2012-03-01 183 views
4

我在学习逆向工程,而我被困在这个小东西上。我有这样的代码:如何通过反汇编从C++函数获取“lea”指令?

.text:10003478     mov  eax, HWHandle 
.text:1000347D     lea  ecx, [eax+1829B8h] <------ 
.text:10003483     mov  dword_1000FA64, ecx 
.text:10003489     lea  esi, [eax+166A98h]<------ 
.text:1000348F     lea  edx, [eax+11FE320h] 
.text:10003495     mov  dword_1000FCA0, esi 

,我想知道,它是如何看起来像在C或C++?特别是箭头标出的两条指令。 HWHandle是变量,它保存从GetModuleHandle()函数返回的值。 更有趣的是,一对夫妇低于这个指导线,dword_1000FCA0用作功能:

.text:1000353C     mov  eax, dword_1000FCA0 
.text:10003541     mov  ecx, [eax+0A0h] 
.text:10003547     push offset asc_1000C9E4 ; "\r\n========================\r\n" 
.text:1000354C     call ecx 

这将吸引我的游戏机这个文本。你有什么想法吗,伙计?

+2

我建议你禁用编译器的代码优化,因为它可能会产生一个有时很难理解的机器代码,并且会有大量的简化/重写/重新组织。 – huelbois 2012-03-01 09:50:09

+1

带有禁用优化的OTOH编译器引入了看似不必要的加载和存储到相同的地址,这可能使反汇编难以阅读,因为实际发生的少数相关行之间很少。我更喜欢'-O1'。 – hirschhornsalz 2012-03-01 10:00:44

+0

你在做什么游戏控制台?的Xbox? – 2012-03-01 10:04:36

回答

3

由于HWHandle是模块句柄,这仅仅是一个DLL的基地址,它看起来好象正在加入到这一常数是用于DLL内的功能或静态数据的偏移。代码正在计算这些函数或数据项的地址并将其存储起来以备后用。

由于这通常是动态链接器的工作,所以我不确定此汇编代码是否与实际的C++代码相对应。了解你正在工作的环境会很有帮助 - 因为你指的是游戏控制台,这个Xbox代码是什么?不幸的是,我不知道Xbox上的动态链接是如何工作的,但是看起来好像这可能是这里发生的事情。

dword_1000FCA0的特定情况下,看起来好像这是DLL内跳转表的位置(即基本上是函数指针的列表)。你的第二个代码片段是从这个表中的偏移量0xA获得一个函数指针,然后调用它 - 显然,被调用的函数将字符串输出到屏幕。 (该字符串指针将输出压入堆栈,其通常的x86调用约定)。与此对应的C++代码会是这样的

my_print_function("\r\n========================\r\n"); 

编辑:

如果你想调用DLL中的函数自己,在函数指针获得的典型方法是使用GetProcAddress()

FARPROC func=GetProcAddress(HWHandle, "MyFunction"); 

但是,您发布的代码计算偏移本身,如果你真的想这样做,你可以使用这样的东西:

DWORD func=(DWORD)HWHandle + myOffset; 

myOffset是偏移量要使用 - 当然,你需要有确定这个偏移的一些方法,这样就可以改变每DLL被重新编译时间,所以它不是一个技术,我会建议 - 但它毕竟是你问的,但是。

无论您使用哪种方式获取函数的地址,都需要调用它。为此,您需要声明一个函数指针 - 为此,您需要知道函数的签名(它的参数和返回类型)。例如:

typedef void (*print_func_type)(const char *); 
print_func_type my_func_pointer=(print_func_type)func; 
my_func_pointer("\r\n========================\r\n"); 

请注意 - 如果您得到的函数地址或其签名错误,您的代码可能会崩溃。这种低级工作的乐趣的所有部分。

+0

是的,你的第一段正是我需要听到的,这是真的!我完全必须使用在这个DLL中得出的函数,但现在是个问题 - 我该怎么做? 编辑 这是我的想法:通过添加偏移地址为HWModule我能获得地址,此DLL功能icnluded,对不对?我可以这样做的: http://wklej.org/id/699418/ 然后在我的FUNC变量i将有一个地址FUNC。我将如何使用该字符串参数来调用该函数? – Blood 2012-03-01 13:38:05

+0

非常感谢你:) – Blood 2012-03-01 15:54:40

+0

有关GetProcAddress的() - 我知道这是好,但我不知道什么是函数的名字,但我敢肯定它不会被重新编译。奥基,我写了,我有这样的事情:http://wklej.org/id/699603/应该罚款? – Blood 2012-03-01 17:49:48

0

这真的是编译器和优化相关的,但如果IIRC,lea可以发射只是为了增加....所以lea ecx, [eax+1829B8h]可以理解为ecx = eax + 0x1829B8

1

在C++中,这大约相当于

char* ecx, eax, esi; 
ecx = eax+0x1829B8 // lea ecx, [eax+1829B8h] 
esi = eax+0x166A98 // lea esi, [eax+166A98h] 

假设eax,esi和ecx确实是指向内存位置的指针。当然,lea指令也可以用于简单的算术,事实上它经常被编译器用于添加。与简单的add相比的优势:它最多可以有三个输入操作数和一个不同的目标。

1

例如,foo = &bar->baz与(简化)foo = (char *)bar + offsetof(typeof(*bar), baz)相同,其可以被翻译为lea foo, [bar+offsetofbaz]

2

它看起来像HWHandle是一些结构(一个大结构)的apointer。 lea指令是从结构读取地址(ES),例如:

mov eax, HWHandle 
lea ecx, [eax+1829B8h] 
mov dword_1000FA64, ecx 

是指:从HWHandle + 0x1829B8

  1. 读地址,并把它变成ecx
  2. 将这个地址(从ecx)到一些(全球)变量dword_1000FA64

其余的看起来是相似的。

在C++中,你可以得到它几乎任何地方,你真的无法预测(依赖于编译和优化),例如:

int x; 
int* pX = &X; 

第二行可能会产生lea

又如:

struct s 
{ 
    int x; 
    int y; 
}; 
my_s s; 
int Y = s.y; //here: probably lea <something> , [address(my_s) + 0x4] 

希望有所帮助。

5

LEA不过是一个算术运算:在这种情况下,ECX只是填充EAX +偏移量(非常地址,而不是指向的内容)。如果HWHandle指向一个(非常大的)结构,那么ECX只是其成员之一。

这可能是一个相关的源代码:

extern A* HWHandle;     // mov  eax, HWHandle 
B* ECX = HWHandle->someStructure; // lea  ecx, [eax+1829B8h] 

和后,B的构件中的一个用作函数。

*(ECX->ptrFunction(someArg))  // mov  ecx, [eax+0A0h] 
            // call ecx 
+1

实际上,我们知道什么样的“结构”HWHandle指向 - 它是一个模块句柄,即DLL的基地址。 – 2012-03-01 10:22:43