Assembly 从反编译的ASM获取信息

Assembly 从反编译的ASM获取信息,assembly,reverse-engineering,calling-convention,ghidra,Assembly,Reverse Engineering,Calling Convention,Ghidra,我愿意在一个小3D游戏上修改相机坐标。我已经找到了三个函数,每个轴一个。 我们叫他们CameraX,CameraY和CameraZ。当我发现我遗漏了一些东西时,我只和第一个一起工作 以下是从Ghidra获得的ASM说明: ************************************************************* *

我愿意在一个小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 以下是完整的ASM代码: 下面是Ghidra生成的伪代码:

所以我猜我错了:我认为引起这个问题的不是线路,而是这条线路:00478C3D89 46 1c MOV dword ptr[ESI+0x1c],x 但仍然是我的x值导致了它

我不明白的是为什么:x是一个int 32位,而程序正试图将其作为dword 32位存储在[ESI+0x1c]中。有可能程序无法解析x的位置/内容吗?就像我在没有参数的情况下调用函数一样

顺便问一下,这个问题:-为什么我们发明了这么多呼叫约定?例如,为什么我们不都使用_cdecl?为什么有些人使用从右到左的方式,而另一些人从左到右阅读?有什么区别吗?
还没有回答,真的让我很感兴趣,如果你有解释,我很乐意听听!

这看起来像是在使用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清除是另一个选项