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
Сообщений: 533
Регистрация: 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,355
Регистрация: 4-February 08
Пользователь №: 3
Спасибо сказали: 311 раз(а)



Это слегка не так работает.
%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
Сообщений: 533
Регистрация: 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,355
Регистрация: 4-February 08
Пользователь №: 3
Спасибо сказали: 311 раз(а)



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
Сообщений: 533
Регистрация: 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,355
Регистрация: 4-February 08
Пользователь №: 3
Спасибо сказали: 311 раз(а)



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,355
Регистрация: 4-February 08
Пользователь №: 3
Спасибо сказали: 311 раз(а)



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

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,355
Регистрация: 4-February 08
Пользователь №: 3
Спасибо сказали: 311 раз(а)



Обсуждали когда-то давно в этой теме код и я такой спрашиваю:
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
Сообщений: 533
Регистрация: 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,355
Регистрация: 4-February 08
Пользователь №: 3
Спасибо сказали: 311 раз(а)



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

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
Сообщений: 533
Регистрация: 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,355
Регистрация: 4-February 08
Пользователь №: 3
Спасибо сказали: 311 раз(а)



Ковырял я недавно ресурсы одной игры, а они зашифрованы.
Вот код расшифровки:
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,355
Регистрация: 4-February 08
Пользователь №: 3
Спасибо сказали: 311 раз(а)



Оказывается 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
Сообщений: 533
Регистрация: 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,355
Регистрация: 4-February 08
Пользователь №: 3
Спасибо сказали: 311 раз(а)



Это-то понятно. Но я никогда до этого не видел, чтобы альфа была последим битом - обычно он первый.
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,355
Регистрация: 4-February 08
Пользователь №: 3
Спасибо сказали: 311 раз(а)



Спросили меня как-то о том, как я пишу код.
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

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

 



Упрощённая версия Сейчас: 17th June 2024 - 10:08