Получить информацию от декомпилированного ASM - PullRequest
1 голос
/ 13 марта 2020

Я хочу изменить координаты камеры в маленькой 3D-игре. Мне удалось найти три функции, по одной для каждой оси. Давайте назовем их CameraX, CameraY и CameraZ. Я работал только с первым, когда обнаружил, что что-то упустил.

Вот инструкции ASM, полученные от Гидры:

                             *************************************************************
                             *                           FUNCTION                         
                             *************************************************************
                             undefined1  __register  CameraX (undefined2  x)
             undefined1        AL:1           <RETURN>
             undefined2        AX:2           x
             undefined1        Stack[-0x14]   local_14                                XREF[8]:     00478abe (*) , 
                                                                                                   00478aca (*) , 
                                                                                                   00478b44 (*) , 
                                                                                                   00478b53 (*) , 
                                                                                                   00478bb3 (*) , 
                                                                                                   00478bbf (*) , 
                                                                                                   00478c1d (*) , 
                                                                                                   00478c29 (*)   
             undefined4        Stack[-0x18]   local_18                                XREF[4]:     00478ae8 (R) , 
                                                                                                   00478b6e (R) , 
                                                                                                   00478bdd (R) , 
                                                                                                   00478c47 (R)   
             undefined4        Stack[-0x1c]   local_1c                                XREF[4]:     00478ae1 (R) , 
                                                                                                   00478b67 (R) , 
                                                                                                   00478bd6 (R) , 
                                                                                                   00478c40 (R)   
             undefined4        Stack[-0x20]   local_20                                XREF[8]:     00478ace (*) , 
                                                                                                   00478ada (R) , 
                                                                                                   00478b57 (*) , 
                                                                                                   00478b60 (R) , 
                                                                                                   00478bc3 (*) , 
                                                                                                   00478bcf (R) , 
                                                                                                   00478c2d (*) , 
                                                                                                   00478c39 (R)   
             undefined8        Stack[-0x28]   local_28                                XREF[4,2]:   004789ec (*) , 
                                                                                                   004789f5 (*) , 
                                                                                                   00478b06 (*) , 
                                                                                                   00478b0f (*) , 
                                                                                                   004789f1 (W) , 
                                                                                                   00478b0b (W)   
             undefined4        Stack[-0x2c]   local_2c                                XREF[1]:     00478b40 (*)   
                             CameraX                                         XREF[1]:     FUN_0047a280:0047a291 (c)   
        004789e0 53              PUSH       EBX
        004789e1 56              PUSH       ESI
        004789e2 83  c4  e0       ADD        ESP ,-0x20
        004789e5 8b  f0           MOV        ESI ,x
        004789e7 e8  68  9b       CALL       FUN_00462554                                     undefined FUN_00462554()
                 fe  ff
        004789ec 89  04  24       MOV        dword ptr [ESP ]=> local_28 ,x
        004789ef 33  c0           XOR        x,x
        004789f1 89  44  24       MOV        dword ptr [ESP  + local_28 +0x4 ],x
                 04
        004789f5 df  2c  24       FILD       qword ptr [ESP ]=> local_28
        004789f8 dc  66  08       FSUB       qword ptr [ESI  + 0x8 ]
        004789fb d9  1d  18       FSTP       dword ptr [DAT_00871218 ]                        = ??
                 12  87  00


...
...
...


        00478c4e 8b  c3          MOV        x,EBX
        00478c50 83  c4  20      ADD        ESP ,0x20
        00478c53 5e              POP        ESI
        00478c54 5b              POP        EBX
        00478c55 c3              RET

Я знаю, что:
- Мой исполняемый файл 32-битный, сделанный в Delphi.
- x - это новое значение оси X.

Моя цель - использовать эту функцию с внедренной dll. Я пришел к этому:

typedef int (__stdcall *_CameraX)(int x);
_CameraX CameraX = (_CameraX)0x04789E0;

Но ни в коем случае, у меня "нарушение доступа" на линии 004789fb FSTP dword ptr [DAT_00871218]. Это первое использование значения х. Поэтому я думаю, что это неправильный тип.

Вот что я понял:
- Так как исходная программа написана на Delphi, __ pascal помнил соглашение о вызовах. Поскольку это устарело в Visual Studio, я использую __stdcall. Я предполагаю, что, поскольку есть только один аргумент *, это не будет иметь никакого значения.
- x всегда было большим числом. Я бы выбрал долго, если бы он не был в 32 битах.
- Я действительно не знаю тип возвращаемого значения. Я выбрал int, потому что вызывающая функция делает test al, al сразу после вызова.

*: Гидра говорит мне, что есть только один аргумент, но если бы я слушал себя, то было бы 2:

        004789e0 53              PUSH       EBX
        004789e1 56              PUSH       ESI
...
...
        00478c53 5e              POP        ESI
        00478c54 5b              POP        EBX
        00478c55 c3              RET

Итак, вот мои вопросы:
- Есть ли на самом деле только один аргумент?
- Какое соглашение о вызовах следует использовать, если правильным является __ pascal, так как оно непригодно для Visual Студия? (Если существует более одного аргумента)
- Как получить возвращаемое значение?
- Почему мы "изобрели" так много соглашений о вызовах? Почему бы нам всем не использовать __cdecl, например? Почему некоторые используют справа налево, когда другие читают слева направо? Есть ли какие-либо различия?

Я почти уверен, что некоторые сведения отсутствуют, будет ли полезен псевдокод, сгенерированный Гидрой?

Редактировать:

int CameraX(int x)

{
  undefined4 *puVar1;
  uint uVar2;
  undefined4 unaff_EBX;
  int iVar3;
  float10 in_ST0;
  undefined4 local_20;
  undefined4 local_1c;
  undefined4 local_18;
  undefined local_14 [12];

  uVar2 = FUN_00462554();
  DAT_00871218 = (float)(ulonglong)uVar2 - (float)*(double *)(x + 8);
    iVar3 = CONCAT31((int3)((uint)unaff_EBX >> 8),1);
  if (*(float *)(x + 0x6c) < DAT_00871218) {
  // ...

Редактировать 2:

Вот полный код ASM: https://pastebin.com/UiGGEju1, а вот псевдокод, сгенерированный Гидрой: https://pastebin.com/1Fc48k1g

, так что, думаю, я был неправильно: это была не та строка, о которой я думал, которая вызывала эту проблему, а вот эта: 00478c3d 89 46 1c MOV dword ptr [ESI + 0x1c],x, но это все-таки мое значение x, которое вызывает ее.

Что я не понимаю, так это «почему»: x - это целое число (32 бита), и программа пытается сохранить его как двойное слово (32 бита) в [ESI + 0x1c]. Возможно ли, что программа не может решить, где / что такое х? (например, если бы я вызывал функцию без аргументов)

Кстати, вопрос: «- Почему мы« изобрели »так много соглашений о вызовах? Почему мы все не используем, например, __cdecl? Почему некоторые используют справа налево, когда другие читают слева направо? Есть ли различия? " мне не ответили и действительно заинтриговали, если у вас есть объяснение, я был бы рад выслушать его!

1 Ответ

3 голосов
/ 13 марта 2020

Похоже, что используется регистр Borland для вызова соглашения (также известного как Borland fastcall):

  • Требуется EAX, EDX затем ECX в качестве первых трех параметров соответственно;
  • 4-й и более аргументы go в стеке;
  • Вызываемый объект должен сохранить EBX, ESI , EDI и EBP регистры;
  • EAX используется в качестве метода возврата для 32-разрядных целых чисел;
  • ... и некоторых других правил, которые не применяются здесь.

Вы можете видеть, как ваша функция сохраняет регистры EBX и ESI, а также не использует EDI и EBP. Он также использует EAX в качестве первого параметра x и возвращает результат также в EAX, в соответствии с соглашением.

В современной Visual Studio нет эквивалентного соглашения о вызовах для Borland fastcall. Вы, вероятно, будете полагаться на использование встроенной сборки в качестве обходного пути при вызове этой функции Delphi.

Этот обходной путь, вероятно, будет работать с использованием временного указателя функции Microsoft fastcall, так как он также использует регистры для первых параметров, за исключением EAX, который мы должны будем передать, используя встроенную сборку, что-то вроде (не уверен в синтаксисе кода, трактуйте его как псевдокод):

typedef void (__fastcall *_CameraX)();
_CameraX CameraXTemp = (_CameraX)0x04789E0;

int CameraX(int x) {
    int ret;
    __asm mov eax, x
    CameraXTemp();
    __asm mov ret, eax
    return ret;
}

Обратите внимание, что если этот метод работает вам нужно будет инвертировать следующие два параметра (для функций с 2 ​​или 3 аргументами), потому что Microsoft fastcall ожидает ECX, а затем EDX в этом порядке. Для 4 или более аргументов я предполагаю, что потребуется некоторая работа со стеком.

Другой подход заключается в использовании функции naked , я предполагаю, что это будет выглядеть примерно так:

__declspec(naked) int __stdcall CameraX(int x)
{
    __asm
   {
       mov  eax, [esp + 4] // x
       push ebx
       mov  ebx, 0x04789E0
       call ebx
       pop  ebx
       ret  4 // 1 argument in this __stdcall function (1 * 4)
   }
}

В будущем, если вы используете этот метод с другой функцией с более чем одним аргументом, вам нужно будет использовать RET n, где n равно number of arguments * 4. Для 3-х и более аргументов вам также нужно положить sh аргументов в стек, как в предыдущем методе.

...