IPB

Добро пожаловать, гость ( Вход | Регистрация )

9 Страниц V « < 7 8 9  
Reply to this topicStart new topic
> Delphi, Asm, C, WinAPI, PHP, ..., FAQ
Siberian GRemlin
Jul 2 2020, 18:29
Сообщение #161


Advanced Member
***

Группа: CTPAX-X
Сообщений: 537
Регистрация: 4-February 08
Пользователь №: 2
Спасибо сказали: 221 раз(а)



В игре выводится количество денег с разделением порядков запятыми. В ЕХЕ упоминается формат вывода
CODE
%0lld
CODE
%03lld
Как я понимаю, это оно. Есть ли формат вывода с разделением порядков пробелами?

Нужно, чтобы было 1,234,567, а стало 1 234 567.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
-=CHE@TER=-
Jul 2 2020, 19:03
Сообщение #162


Walter Sullivan
***

Группа: Root Admin
Сообщений: 1,360
Регистрация: 4-February 08
Пользователь №: 3
Спасибо сказали: 313 раз(а)



Это слегка не так работает.
%d - вывести digit
%ld - вывести long digit (для архитектур, где размер int больше long, например int 16, а long 32)
%lld - вывести long long digit (как правило int 64)

%0lld - тоже самое что и %lld (символ один и не указан размер)
%03lld - тоже самое, что %03d (выравнять тремя нулями слева, если число меньше), но для int64

CODE
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

int main(void) {
ULARGE_INTEGER x;
  x.QuadPart = 1;
  printf("%0lld\n", x.QuadPart); // будет просто 1
  printf("%03lld\n", x.QuadPart); // будет 001
  return(0);
}

В сях нет стандартных функций для разделения тысяч, чтобы из 1234567 сделать 1,234,567 или 1 234 567. Боюсь тебе придётся вручную искать код который это делает. Попробуй поискать по работе со строками и символом 0x2C (запятая). Ставлю на то, что как раз твои строки и работают с числами - смотри где они используются.
"%03lld" нужно чтобы у тебя числа менее тысячи добивались нулями: 3007 => 3,007, а не 3,7.
"%0lld" - это остаток в левой части, в примере 3007 - это будет тройка, т.к. её добивать нулями не нужно.


Спасибо сказали:
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
Siberian GRemlin
Feb 17 2021, 13:57
Сообщение #163


Advanced Member
***

Группа: CTPAX-X
Сообщений: 537
Регистрация: 4-February 08
Пользователь №: 2
Спасибо сказали: 221 раз(а)



Нашёл. Число выводится несколькими строками, затем склеивается со вставкой запятой в одну строку и выводится на экран. Почему-то я сначала думал, что это стандартная процедура вывода, и поленился сразу в IDA поискать.

Помню, что десятичный разделитель можно было выводить и запятой, и точкой. Но после школы я этим никогда не пользовался.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
-=CHE@TER=-
Feb 17 2021, 18:27
Сообщение #164


Walter Sullivan
***

Группа: Root Admin
Сообщений: 1,360
Регистрация: 4-February 08
Пользователь №: 3
Спасибо сказали: 313 раз(а)



QUOTE(Siberian GRemlin @ Feb 17 2021, 13:57) *
Помню, что десятичный разделитель можно было выводить и запятой, и точкой. Но после школы я этим никогда не пользовался.
В Delphi есть глобальная переменная DecimalSeparator, которой можно присвоить '.' или ',' в зависимости от того что тебе в качестве разделителя нужно. Если не ошибаюсь, это влияет на функции типа StrToFloat(), FloatToStr() и прочие. В сях, конечно, ничего подобного нет.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
Siberian GRemlin
Feb 26 2021, 05:30
Сообщение #165


Advanced Member
***

Группа: CTPAX-X
Сообщений: 537
Регистрация: 4-February 08
Пользователь №: 2
Спасибо сказали: 221 раз(а)



Рано я радовался. Хоть я и заменил удачно запятую на пробел, и в игре это стало отображаться, но оказалось, что игра в основной части вылетает, так как эта переменная с запятой, видимо, используется не только там.

Кто-нибудь может глянуть код на асме функции склейки этих «%03lld» с запятой и убрать из неё прибавление запятой?

Игра Win64. Работу оплачу.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
-=CHE@TER=-
Feb 26 2021, 11:23
Сообщение #166


Walter Sullivan
***

Группа: Root Admin
Сообщений: 1,360
Регистрация: 4-February 08
Пользователь №: 3
Спасибо сказали: 313 раз(а)



QUOTE(Siberian GRemlin @ Feb 26 2021, 05:30) *
Рано я радовался. Хоть я и заменил удачно запятую на пробел, и в игре это стало отображаться, но оказалось, что игра в основной части вылетает, так как эта переменная с запятой, видимо, используется не только там.

Кто-нибудь может глянуть код на асме функции склейки этих «%03lld» с запятой и убрать из неё прибавление запятой?

Игра Win64. Работу оплачу.
Вышли мне на почту исполняемый файл игры, я его могу в статике посмотреть. И ещё приложи к нему:
fc /b old.exe new.exe >file.txt
Чтобы было понятно что ты там и где менял (меня интересует только место где ты пробел на запятую заменил).
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
-=CHE@TER=-
Apr 2 2022, 14:13
Сообщение #167


Walter Sullivan
***

Группа: Root Admin
Сообщений: 1,360
Регистрация: 4-February 08
Пользователь №: 3
Спасибо сказали: 313 раз(а)



Про ограничение у имён файлов.
Мы все прекрасно знаем, что есть программы, которые не работают с русскими или не английскими буквами. На самом деле ограничений гораздо больше, если программа написана не очень хорошо. Ниже будет приведён список из множества тех, с которыми можно так или иначе столкнуться.

1) Программы работающие корректно только с английскими буквами в пути и именах файлов.
Вернее сказать, работают они корректно только с цифрами "0".."9", английскими буквами "A..Z" (маленькими и большими) и символом подчерк "_". Ещё можно использовать минус-тире "-", тильду "~" и много чего ещё, но не стоит, потому что, как минимум, с тире есть проблемы из-за того что некоторые не особо умные программы, сами парсят командную строку, причём криво, и видя где-то "-" считают что это начало ключа командной строки. Что до не английских букв (русских, немецких и других языков) - так у них в ANSI кодировке код символа более 127, что такие программы считают за мусорные и обрубают строку по первому такому символу.

2) Программы работающие корректно только с именами без пробелов (подмножество предыдущих).
Аналогичная предыдущей ситуация, когда кривой парсер командной строки считает пробел как разделитель аргументов. Поэтому исключайте из пути пробелы в имени каталогов и файлов.

3) Программы Windows работающие с ограничением в MAX_PATH (260) символов.
Причём, я не помню, вроде бы, MAX_PATH - это включая завершающий ноль, так что, на самом деле, есть только 259 символов. Суть такова: если путь до программы или каталога более MAX_PATH символов, то программа может либо вылететь с ошибкой, либо не запуститься вообще. Чтобы было понятно в чём проблема - большинство функций Windows работающих с файлами и каталогами, типа получения полного пути текущего каталога, принимают два аргумента: буфер и его размер в символах. Можно сделать путь длиннее MAX_PATH, но тогда нужно сперва вызывать функцию чтобы узнать сколько символов нужно, затем выделять память, ещё раз вызывать чтобы уже прочитать в буфер, а после использования этот буфер удалить, чтобы память не текла. Поэтому в 95% случаев (а то и в 99%) разработчики создают на стеке статический буфер в MAX_PATH символов и его используют. При этом некоторые функции, типа GetModuleFileName() (см. документацию в MSDN и пометки о её работе в Windows XP и более младших системах) даже не возвращают нужного размера буфера, так что их приходится вызывать увеличивая размер буфера "на глаз", пока не останется неиспользуемое место в конце.

4) Программы для DOS запущенные в Windows XP / Me / 98 - ограничение в 64 символа.
Аналогичная предыдущей ситуация. В 64 символа, вроде бы, входит также и нулевой, так что есть только 63 для пути с именем файла. Тут, правда, всё во много раз хуже из-за того, что в функциях DOS передавался только буфер, без его размера. При этом Windows пишет туда путь даже если он более 64 символов, что, как правило, приводит к разрушению стека и вылету программы с фатальной ошибкой.

5) Ограничение на имя каталога и файла для DOS в 8.3 (8 символов на имя, точка и ещё 3 на расширение).
Иными словами такой путь:
C:\Program Files\My Files\New File List.txt
Превратится во что-то типа такого для DOS приложения:
C:\PROGRA~1\MYFILE~1\NEWFIL~1.TXT
А если сделать, например, вот такой путь:
C:\PROGRAMS\MY_FILES\FILELIST.NEW
То он будет одинаковай при его указании как в DOS, так и в Windows и проблем не создаст.
А ещё обратите внимание, что в DOS используются только заглавные английские буквы в именах файлов, а также там почему-то, в отличие от Windows, дополнительно запрещены символы "[" и "]" в имени.

Большинство из описанных выше проблем решаются вот таким простым пакетным файлом "RUNSHORT.BAT":
CODE
@echo off
subst Z: .
Z:
program.exe
subst Z: /d

Виртуальный диск Z: можно заменить на любой другой, как и имя запускаемой программы "program.exe". Обратите внимание, что при создании виртуального диска (первый subst) в конце стоит точка - указатель на текущий каталог (откуда был запущен .BAT файл). Для использования нужно положить "RUNSHORT.BAT" в каталог программы рядом с "program.exe" и запустить.

И последнее - не забывайте, что русское (в общем случае не английское или с произвольными символами) имя пользователя в системе тоже может вызвать проблемы (ссылка), т.к. оно входит в часть пути до временного каталога %TEMP% и %TMP%.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
-=CHE@TER=-
Oct 1 2022, 16:13
Сообщение #168


Walter Sullivan
***

Группа: Root Admin
Сообщений: 1,360
Регистрация: 4-February 08
Пользователь №: 3
Спасибо сказали: 313 раз(а)



Обсуждали когда-то давно в этой теме код и я такой спрашиваю:
QUOTE(-=CHE@TER=- @ Jul 10 2007, 12:51) *
3) MUTEX обязательно должен называться '851137EC-3D96-4EA6-817B-30969CCF477B' или можно своё имя сунуть?..
На что мне отвечают:
QUOTE(Xplorer @ Jul 10 2007, 13:54) *
Можно и своё.
Но никто не объяснил, почему это хитровыделанное имя лучше.
Дело в том, что GUID - это всегда уникальное имя.
Если, конечно, оно не написано абы как, а создано специальной программой, по специальному алгоритму.
У кого стоит Microsoft Visual Studio 6 (1998), то там в утилитах нужная программа точно есть - называется "Create GUID":
C:\Program Files\Microsoft Visual Studio\Common\Tools\GUIDGEN.EXE
Кому лень искать и ставить, то есть аналоги в Интернете (первое что вышло в Google за запросу "create unique guid online"):
- https://www.guidgen.com/ - утверждается, что делает это также, как и Microsoft
- https://www.guidgenerator.com/
Наверное именно поэтому в том же Far Manager последних версий (в смысле, в версии 3.x точно, может и в 2.x - не проверял) для идентификации плагинов, а также других вещей (типа диалоговых окон) используются именно GUID'ы.
Кому интересно к чему приводит попытка назвать что-то простым именем: Two bugs for the price of one.
В статье, правда, всё несколько проще, т.к. имя для CreateEvent() можно, вообще, не задавать (указать как NULL), если планируется работать только внутри одного процесса и есть другие способы (помимо имени) для передачи дескриптора между разными частями программы.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
Siberian GRemlin
Aug 6 2023, 11:17
Сообщение #169


Advanced Member
***

Группа: CTPAX-X
Сообщений: 537
Регистрация: 4-February 08
Пользователь №: 2
Спасибо сказали: 221 раз(а)



Привет.
Кто-нибудь знает, в каком виде нужно пихать буфер в Zcrc32? https://github.com/ashumkin/delphi-zlib/tree/master
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
-=CHE@TER=-
Aug 6 2023, 17:40
Сообщение #170


Walter Sullivan
***

Группа: Root Admin
Сообщений: 1,360
Регистрация: 4-February 08
Пользователь №: 3
Спасибо сказали: 313 раз(а)



А с чем там проблема?

P.S. Извини, что на почту не отвечал - очень не до того было.

CODE
{ test.dpr }
uses ZLibEx, SysUtils;
{$APPTYPE CONSOLE}
var
  fl: File;
   p: pointer;
   x: longint;
   s: AnsiString;
begin
  AssignFile(fl, 'test.dpr');
  Reset(fl, 1);
  x:=FileSize(fl);
  GetMem(p, x);
  BlockRead(fl, p^, x);
  s:='test';
  WriteLn(
    'D87F7E0C = ',
     IntToHex(
       ZCrc32(0, s[1], Length(s)),
     8)
  );
  WriteLn(
    '???????? = ',
    IntToHex(
      ZCrc32(0, p^, x),
    8)
  );
  FreeMem(p, x);
  CloseFile(fl);
end.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
Siberian GRemlin
Aug 7 2023, 06:34
Сообщение #171


Advanced Member
***

Группа: CTPAX-X
Сообщений: 537
Регистрация: 4-February 08
Пользователь №: 2
Спасибо сказали: 221 раз(а)



Я как всегда поторопился. Вчера хотел прогу дописать, голова уже не варила. А с утра увидел, что забыл уже ненужную строчку удалить.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
-=CHE@TER=-
Aug 9 2023, 09:01
Сообщение #172


Walter Sullivan
***

Группа: Root Admin
Сообщений: 1,360
Регистрация: 4-February 08
Пользователь №: 3
Спасибо сказали: 313 раз(а)



Ковырял я недавно ресурсы одной игры, а они зашифрованы.
Вот код расшифровки:
CODE
mov ecx, _data; pointer to the data buffer
mov esi, _size; size of the data buffer
@uncrypt:
mov al, [ecx]
mov dl, al
not dl
xor dl, al
and dl, 55h
not al
xor dl, al
mov [ecx], dl
inc ecx
dec esi
jnz @uncrypt

Что можно переписать так (внутренняя часть цикла - расшифровка байта):
CODE
// C
uint8_t data; // BYTE data;
...
data = (((~data) ^ data) & 0x55) ^ (~data);

// Pascal
var data: byte;
...
data := (((not data) xor data) and $55) xor (not data);

И я бы так и оставил, но чем больше я смотрел на это выражение, тем больше у меня возникало ощущение, что я смотрю на какую-то фигню.
А давайте распишем логические операции (напомню, что мы работаем в пределах байта):
Операция "not data" для байта эквивалентна "data xor 0xFF", отсюда:
(not data) xor data => (data xor 0xFF) xor data => data xor 0xFF xor data
Так как "data xor data" это ноль, то получаем "0 xor 0xFF", что даёт просто 0xFF и далее:
0xFF and 0x55 - так и останется 0x55 из чего получается:
0x55 xor (not data)
Опять заменяем "not data" на "data xor 0xFF":
0x55 xor data xor 0xFF
0xFF xor 0x55 = 0xAA
Итого всё выражение:
CODE
data := (((not data) xor data) and $55) xor (not data); // Pascal

Сворачивается просто до:
CODE
data := data xor 0xAA; // Pascal

Кстати, если выражение:
CODE
data = (((~data) ^ data) & 0x55) ^ (~data); // C

Скомпилировать компилятором GCC (версия 3.2 за 2002-08-17) с оптимизацией по размеру, то он в ассемблерном коде всё и свернёт до "data ^= 0xAA".
Игра была написана на Microsoft Visual C++ 5.0 (1999) под Windows. Может быть, конечно, тот VC5 ещё не умел оптимизировать такие выражение или не был включён режим оптимизации (он замедляет компиляцию, а в те времена компьютеры были не шибко быстрые) при сборке финального исполняемого файла.

Но в любом случае, это не отменяет того факта, что тот кто писал этот код не понимал как работает битовая логика и что вся эта замудрённая дурь вырождается тупо в константу. Иными словами, можно было легко по'xor'ить ресурсы игры байтом от 0x00 до 0xFF и сохранить в отдельные файлы (например, DATA.###, где ### - номер байта, которым xor'илось), после чего просмотреть их (всего-то 256 штук) и найти расшифрованный.

Что-то похожее я прочитал в 2011 году на одном зарубежном сайте, правда про другую игру:
QUOTE
2009/06/02 / exvcpak
I kept looking at the scramble algorithm trying to figure out why it does several operations that result in constant values ... finally I concluded that whoever wrote the code is just an idiot.
© asmodean's reverse engineering page

До кучи напомню про это: Command & Conquer: Red Alert [Hidden Easter Egg] - там аж целый главный погром-мист и разработчик, ООП, абстракция на абстракции сидит и абстракцией погоняет, а основ и базы даже не языка программирования, а обычной работы с данными, не знает и не понимает.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
-=CHE@TER=-
Aug 14 2023, 18:28
Сообщение #173


Walter Sullivan
***

Группа: Root Admin
Сообщений: 1,360
Регистрация: 4-February 08
Пользователь №: 3
Спасибо сказали: 313 раз(а)



Оказывается 16-ти битные (два байта) изображения могут быть не только в форматах:
RGB_565 (RRRRRGGG GGGBBBBB)
или:
RGBA_4444 (RRRRGGGG BBBBAAAA)
но и в совсем уж наркоманском (пришлось документацию на поддерживаемые Android форматы искать):
RGBA_5551 (RRRRRGGG GGBBBBBA)
Когда при декодировании в формате RGB_565 красный стоит как надо, но идёт слишком много синего и он очень резко обрываясь переходит в зелёный на границах, где должен быть плавный переход - знайте, что, на самом деле, это RGBA_5551.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
Siberian GRemlin
Aug 22 2023, 11:16
Сообщение #174


Advanced Member
***

Группа: CTPAX-X
Сообщений: 537
Регистрация: 4-February 08
Пользователь №: 2
Спасибо сказали: 221 раз(а)



QUOTE(-=CHE@TER=- @ Aug 15 2023, 01:28) *
RGBA_5551 (RRRRRGGG GGBBBBBA)
У «Dune 2000» тоже было 15 бит на цвет и 1 бит на альфу.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
-=CHE@TER=-
Aug 22 2023, 15:25
Сообщение #175


Walter Sullivan
***

Группа: Root Admin
Сообщений: 1,360
Регистрация: 4-February 08
Пользователь №: 3
Спасибо сказали: 313 раз(а)



Это-то понятно. Но я никогда до этого не видел, чтобы альфа была последим битом - обычно он первый.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
-=CHE@TER=-
Dec 16 2023, 09:35
Сообщение #176


Walter Sullivan
***

Группа: Root Admin
Сообщений: 1,360
Регистрация: 4-February 08
Пользователь №: 3
Спасибо сказали: 313 раз(а)



Спросили меня как-то о том, как я пишу код.
CODE
// example 1
if (condition) {
  code();
}

// example 2
if (condition)
{
  code();
}

Я ответил, что первый вариант. Объясняю почему на конкретном примере забытой или случайно поставленной не там ";" в коде.
CODE
// example 1
if (argc != 2) {;
  return(1);
}

// example 2
if (argc != 2);
{
  return(1);
}

Первому примеру люто пофиг, а вот второй пример из-за не там оставленной ";" вырождается в:
CODE
if (argc != 2) {}
return(1);

Иными словами код условия начинает выполняться всегда независимо от значения условия.

Такая же штука и в Delphi:
CODE
Program Test;
{$APPTYPE CONSOLE}
Begin
  If (ParamCount = 1) Then; // note ";" here
  Begin
    WriteLn('two');
  End;
  WriteLn('one');
End.

Я теперь понимаю, почему в своих программах товарищ jTommy писал вот так:
CODE
if (condition) then begin
  code();
end;

В отличие от C выглядит не очень из-за того что тут слова begin-end, да ещё и с разным количеством букв, вместо фигурных скобок, зато поставленная в конце строки ";" ни на что не повлияет (можете проверить).
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
Siberian GRemlin
Aug 11 2024, 04:44
Сообщение #177


Advanced Member
***

Группа: CTPAX-X
Сообщений: 537
Регистрация: 4-February 08
Пользователь №: 2
Спасибо сказали: 221 раз(а)



QUOTE(-=CHE@TER=- @ Dec 16 2023, 16:35) *
Я теперь понимаю, почему в своих программах товарищ jTommy писал вот так:
CODE
if (condition) then begin
  code();
end;

В отличие от C выглядит не очень из-за того что тут слова begin-end, да ещё и с разным количеством букв, вместо фигурных скобок, зато поставленная в конце строки ";" ни на что не повлияет (можете проверить).

Я тоже всегда так писал, ибо при такой структуре чётко видно, где блок начинается, а где заканчивается.

P. S. Никогда не понимал, зачем ты в коде каждое слово пишешь с большой буквы.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
-=CHE@TER=-
Aug 11 2024, 13:16
Сообщение #178


Walter Sullivan
***

Группа: Root Admin
Сообщений: 1,360
Регистрация: 4-February 08
Пользователь №: 3
Спасибо сказали: 313 раз(а)



QUOTE(Siberian GRemlin @ Aug 11 2024, 04:44) *
P. S. Никогда не понимал, зачем ты в коде каждое слово пишешь с большой буквы.
CamelCase потому что. Несколько раздражает читать функции типа "gethostbyname", которые именно что так объявлены (в сях, например, все имена функций регистрозависимые), поэтому ты долго смотришь на них, пытаясь понять что это за слова и где заканчивается одно и начинается другое, чтобы разбить на отдельные слова и понять по имени что функция делает. Можно ещё подчерки использовать get_some_value - но такое мне не очень нравится, ибо символ подчерка увеличивает на один знак строку с именем, а при достаточно длинном имени это разносит в ширину строку, она смотрится громоздко и занимает много места в коде программы.
Частным случаем, кстати говоря, является lowerCamelCase - когда заглавные все буквы, кроме первой, так что имена состоящие из одного слова так с маленькой букви и пишутся, но много-много-много лет назад, когда я только начинал программировать, я о такой штуке не знал, сам не додумался, а сейчас уже привычка. Плюс я точно также могу тебя спросить, зачем ты пишешь предложения с большой буквы? (*улыбается*) Программа - это тоже, в каком-то смысле, текст.
В общем, все люди со своими особенностями.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

9 Страниц V « < 7 8 9
Reply to this topicStart new topic
43 чел. читают эту тему (гостей: 43, скрытых пользователей: 0)
Пользователей: 0 -

 



Упрощённая версия Сейчас: 9th September 2024 - 15:36