2012-03-01 187 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