Assembly 从反编译的ASM获取信息
我愿意在一个小3D游戏上修改相机坐标。我已经找到了三个函数,每个轴一个。 我们叫他们CameraX,CameraY和CameraZ。当我发现我遗漏了一些东西时,我只和第一个一起工作 以下是从Ghidra获得的ASM说明:Assembly 从反编译的ASM获取信息,assembly,reverse-engineering,calling-convention,ghidra,Assembly,Reverse Engineering,Calling Convention,Ghidra,我愿意在一个小3D游戏上修改相机坐标。我已经找到了三个函数,每个轴一个。 我们叫他们CameraX,CameraY和CameraZ。当我发现我遗漏了一些东西时,我只和第一个一起工作 以下是从Ghidra获得的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
但不可能,我在线路004789fb FSTP dword ptr[DAT_00871218]上遇到访问冲突。这是x值的首次使用。所以我猜这是错误的类型
以下是我的理解:
-由于最初的程序是用Delphi编写的,_pascal调用约定就出现在脑海中。因为它在VisualStudio中已被弃用,所以我使用的是u stdcall。我假设,因为只有一个论点,这不会有任何区别。
-x总是一个很大的数字。如果不是32位,我会选择long。
-我真的不知道返回类型。我选择int是因为调用方函数在调用之后进行了一次测试al,al
*:Ghidra告诉我只有一个论点,但如果我听自己的,会有两个:
004789e0 53 PUSH EBX
004789e1 56 PUSH ESI
...
...
00478c53 5e POP ESI
00478c54 5b POP EBX
00478c55 c3 RET
下面是我的问题:
-真的只有一个论点吗?
-如果正确的调用约定是_pascal,那么应该使用哪个调用约定,因为它在Visual Studio中不可用?如果有不止一个论点
-检索返回值的方法是什么?
-为什么我们发明了这么多电话会议?例如,我们为什么不都使用cdecl呢?为什么有些人从右到左阅读,而有些人从左到右阅读?有什么不同吗
我很确定缺少一些信息,Ghidra生成的伪代码有用吗
编辑:
int CameraXint x
{
未定义4*puVar1;
uint-uVar2;
未定义4未定义EBX;
int iVar3;
浮动10英寸;
未定义4本地_20;
未定义的4本地_1c;
未定义4本地_18;
未定义的局部_14[12];
uVar2=FUN_00462554;
DAT_00871218=浮点数龙长数值2-浮点数*双精度*x+8;
iVar3=CONCAT31int3uintunaff_EBX>>8,1;
如果*float*x+0x6c还没有回答,真的让我很感兴趣,如果你有解释,我很乐意听听!这看起来像是在使用Borland注册呼叫约定,也称为Borland快速呼叫: 它分别以EAX、EDX和ECX作为前三个参数; 第四个及以上参数进入堆栈; 被叫方必须保留EBX、ESI、EDI和EBP寄存器; EAX用作32位整数的返回方法; …还有其他一些不适用的规则。 您可以看到,您的函数保存EBX和ESI寄存器,也不使用EDI或EBP。它还使用EAX作为第一个参数x,并按照约定在EAX中返回结果 在现代Visual Studio中,Borland fastcall没有等效的调用约定。在调用此Delphi函数时,您可能需要使用内联汇编作为一种变通方法 此解决方法可能会使用临时Microsoft fastcall函数指针,因为它还使用寄存器作为第一个参数,EAX除外,我们必须使用内联汇编传递它,例如不确定代码语法,将其视为伪代码: typedef void uu fastcall*u CameraX; _CameraX CameraXTemp=_CameraX0x04789E0; int CameraXint x{ int ret; __asm mov eax,x CameraXTemp; __汽车修理部经理 返回ret; } 请注意,如果此方法有效,则需要为具有2个或3个参数的函数反转接下来的两个参数,因为Microsoft的fastcall希望ECX然后EDX按此顺序进行。对于4个或更多参数,我假设需要一些堆栈工作 另一种方法是使用裸函数,我假设它看起来像这样: __DeclSpec裸体int_uuustdcall CameraXint x { __asm { mov eax,[esp+4]//x 推ebx mov ebx,0x04789E0 呼叫ebx 流行电子束 ret 4//1此u stdcall函数中的参数1*4 } } 出于将来的目的,如果将此方法用于具有多个参数的另一个函数,则需要使用RET n,其中n是参数数*4。对于3个或更多参数,则
'还必须像前一个方法一样将参数推入堆栈。这看起来像是在使用Borland寄存器调用约定(也称为Borland fastcall): 它分别以EAX、EDX和ECX作为前三个参数; 第四个及以上参数进入堆栈; 被叫方必须保留EBX、ESI、EDI和EBP寄存器; EAX用作32位整数的返回方法; …还有其他一些不适用的规则。 您可以看到您的函数保存EBX和ESI寄存器,并且不使用EDI或EBP。它还使用EAX作为第一个参数x,并按照约定在EAX中返回结果 在现代Visual Studio中,Borland fastcall没有等效的调用约定。在调用此Delphi函数时,您可能会依赖于使用内联汇编作为变通方法 此解决方法可能会使用临时Microsoft fastcall函数指针,因为它还使用寄存器作为第一个参数,EAX除外,我们必须使用内联汇编传递它,例如不确定代码语法,将其视为伪代码: typedef void uu fastcall*u CameraX; _CameraX CameraXTemp=_CameraX0x04789E0; int CameraXint x{ int ret; __asm mov eax,x CameraXTemp; __汽车修理部经理 返回ret; } 请注意,如果此方法有效,则需要为具有2个或3个参数的函数反转接下来的两个参数,因为Microsoft的fastcall期望ECX,然后是EDX。对于4个或更多参数,我假设需要一些堆栈工作 另一种方法是使用裸函数,我假设它看起来像这样: __DeclSpec裸体int_uuustdcall CameraXint x { __asm { mov eax,[esp+4]//x 推ebx mov ebx,0x04789E0 呼叫ebx 流行电子束 ret 4//1此u stdcall函数中的参数1*4 } }
出于将来的目的,如果将此方法用于另一个具有多个参数的函数,则需要使用RET n,其中n是参数数*4。对于3个或更多参数,您还必须像前一个方法一样将参数推入堆栈。您不可能在该行出现错误,因为这只是写入全局存储,应该可以工作。代码似乎使用了非标准的调用序列,因为参数是在eax中传递的。这似乎也通过esi传递给了FUN_00462554。为什么你决定这是pascal呼叫会议?interjay:根据Borland Pascal编程语言的调用约定,参数按与cdecl相反的从左到右的顺序推送到堆栈上,被调用方负责将其从堆栈中删除。从,听起来像是,你能告诉我这句话哪一点错了吗?杰斯特:很明显,我在地址004789fb上有一个弹出窗口,上面写着访问违规。我想向您展示这一行的Ghidra伪代码,请参见上述主题的最后一段。您刚才说的pascal调用约定是什么。但这不是此汇编代码使用的调用约定。@Jester:你怎么知道eax已经过时了?你不可能真的在那一行有错误,因为这只是写入全局存储,应该可以工作。代码似乎使用了非标准的调用序列,因为参数是在eax中传递的。这似乎也通过esi传递给了FUN_00462554。为什么你决定这是pascal呼叫会议?interjay:根据Borland Pascal编程语言的调用约定,参数按与cdecl相反的从左到右的顺序推送到堆栈上,被调用方负责将其从堆栈中删除。从,听起来像是,你能告诉我这句话哪一点错了吗?杰斯特:很明显,我在地址004789fb上有一个弹出窗口,上面写着访问违规。我想向您展示这一行的Ghidra伪代码,请参见上述主题的最后一段。您刚才说的pascal调用约定是什么。但这不是此汇编代码使用的调用约定。@Jester:您怎么知道eax已经过时了?谢谢您的帮助!所以我测试了第一种方法:它编译时没有任何问题,但我仍然在模块“…”中的地址00478C3D处遇到访问冲突。写入地址004789FC。这和我已经得到的信息是一样的。请看我的编辑。我试了第二个。我无法使用调用0x04789E0进行编译,因此我尝试通过参数发送地址。它进行编译,但给我的是相同的消息,地址不同,超出范围,因此我做了一些错误的事情。错误行表示它试图写入[ESI+0x1C],即[0x004789E0-0x1C],即0x004789FC 错误表明,ESI以某种方式保留了原始CameraX函数的开始。查看反汇编函数,ESI可追溯到参数x的值,
这意味着您要将函数的地址传递给第一个函数参数本身。这也意味着X EAX可能不是您所认为的那样。它看起来像原始函数上下文中的指针。\u stdcall是一种调用方约定。在register arg函数返回后,需要ret 4从堆栈中清除arg。此外,不幸的是,MSVC内联asm不支持将相对调用组合到绝对目标地址;你需要做一些笨拙的事情,比如把绝对地址放在寄存器中,调用ecx ping@NoxI。在检查了我对x的用途没有错之后,我一直在尝试第一种方法。我仍然没有他的类型,我尝试了int,*int,并发送一个指向不带参数的int函数的函数指针。没有成功。尽管如此,我确信x应该做什么,我已经能够通过作弊引擎检查它。关于如何找到x的类型有什么线索吗?顺便问一下,为什么我们要ret 4而不是ret 1?我们返回字节数了吗?现在stdcall函数被破坏了,因为它在不保存的情况下关闭了EBX。可能在通话中按/弹出它。按0x04789E0/呼叫[esp]并弹出ecx清理是另一个选项,感谢您的帮助!所以我测试了第一种方法:它编译时没有任何问题,但我仍然在模块“…”中的地址00478C3D处遇到访问冲突。写入地址004789FC。这和我已经得到的信息是一样的。请看我的编辑。我试了第二个。我无法使用调用0x04789E0进行编译,因此我尝试通过参数发送地址。它进行编译,但给我的是相同的消息,地址不同,超出范围,因此我做了一些错误的事情。错误行表示它试图写入[ESI+0x1C],即[0x004789E0-0x1C],即0x004789FC 错误表明,ESI以某种方式保留了原始CameraX函数的开始。查看反汇编函数,ESI可追溯到参数x的值,这意味着您将函数的地址传递给第一个函数参数本身。这也意味着X EAX可能不是您所认为的那样。它看起来像原始函数上下文中的指针。\u stdcall是一种调用方约定。在register arg函数返回后,需要ret 4从堆栈中清除arg。此外,不幸的是,MSVC内联asm不支持将相对调用组合到绝对目标地址;你需要做一些笨拙的事情,比如把绝对地址放在寄存器中,调用ecx ping@NoxI。在检查了我对x的用途没有错之后,我一直在尝试第一种方法。我仍然没有他的类型,我尝试了int,*int,并发送一个指向不带参数的int函数的函数指针。没有成功。尽管如此,我确信x应该做什么,我已经能够通过作弊引擎检查它。关于如何找到x的类型有什么线索吗?顺便问一下,为什么我们要ret 4而不是ret 1?我们返回字节数了吗?现在stdcall函数被破坏了,因为它在不保存的情况下关闭了EBX。可能在通话中按/弹出它。按0x04789E0/调用[esp]并弹出ecx清除是另一个选项