Я хочу изменить координаты камеры в маленькой 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? Почему некоторые используют справа налево, когда другие читают слева направо? Есть ли различия? " мне не ответили и действительно заинтриговали, если у вас есть объяснение, я был бы рад выслушать его!