C 反彙編揭秘1 乙個簡單的C 程式反彙編解析

2021-05-21 17:51:44 字數 4517 閱讀 9322

本系列主要從彙編角度研究c++語言機制和彙編的對應關係。第一篇自然應該從最簡單的開始。c++的源**如下:

class my_class

void method(int n)

~my_class()

private :

int m_member;

};

int _tmain(int argc, _tchar* argv)

可以直接debug的時候看到assembly**,不過這樣獲得的**注釋比較少。比較理想的方法是利用vc編譯器的乙個選項/fas來生成對應的彙編**。/fas還會在彙編**中加入注釋註明和c++**的對應關係,十分有助於分析。build**便可以在輸出目錄下發現對應的.asm檔案。本文將逐句分析彙編**和c++的對應關係。

首先是winmain:

_text segment

_wmain       proc

push ebp                                  ; 儲存舊的ebp

mov    ebp, esp                             ; ebp儲存當前棧的位置

push -1                                   ; 建立seh(structured exception handler)鏈

; -1表示表頭,沒有prev

push __ehhandler$_wmain                   ; seh異常處理程式的位址

mov    eax, dword ptr fs:0                  ; fs:0指向teb的內容,頭4個位元組是當前seh鏈的位址

push eax                                  ; 儲存起來

sub    esp, d8h                             ; 分配d8h位元組的空間

push ebx

push esi

push edi

lea    edi, dword ptr [ebp-e4h]             ; e4h = d8h + 4 * 3,跳過中間ebx, esi, edi

mov    ecx, 36h                             ; 36h*4h=d8h,也就是用36h個cccccccch填滿剛才分配的d8h位元組空間

mov    eax, cccccccch

rep stosd

mov    eax, dword ptr ___security_cookie   

xor    eax, ebp                 

push eax                                  ; ebp ^ __security_cookie壓棧儲存

lea    eax, dword ptr [ebp-0ch]             ; ebp-0ch是新的seh鏈的結構位址(剛壓入棧中的棧位址)

mov    dword ptr fs:0, eax                  ; 設定到teb中作為當前active的seh鍊錶末尾

到此為止棧的內容是這樣的:

低位址security cookie after xor

edi

esi

ebx

local stack: d8h

old fs:0

__ehhandler$_wmain

ffffffffh

old ebp

高位址main接著後面呼叫my_class的建構函式

lea    ecx, dword ptr [ebp-14h]

call ??0my_class@@qae@xz                  ; 呼叫my_class::my_class, ??my_class@@qae@xz是經過name mangling後的名字

mov    dword ptr [ebp-4], 0                 ; 進入__try塊,在main中有乙個隱式的__try/__except塊

接著呼叫my_class::method

push 10                                   ; 引數入棧

lea    ecx, dword ptr [ebp-14h]             ; 遵循thiscall呼叫協定,ecx存放的是this指標

call ?method@my_class@@qaexh@z            ; 呼叫子程式my_class:method(10)

之後是析構:

mov    dword ptr [ebp-e0h], 0              ; 用來放置返回值

mov    dword ptr [ebp-4], -1                ; 標記try的正常結束

lea    ecx, dword ptr [ebp-14h]             ; a_class的位址作為this存入ecx

call ??1my_class@@qae@xz                  ; my_class::~my_class

mov    eax, dword ptr [ebp-e0h]             ; 返回值按照約定放入eax中

main函式退出**如下:

push edx

mov    ecx, ebp

push eax

lea    edx, dword ptr $ln7@wmain

call @_rtc_checkstackvars@8              ; 檢查棧

pop    eax

pop    edx

mov    ecx, dword ptr [ebp-0ch]             ; 取出之前儲存的舊的fs:0,並恢復

mov    dword ptr fs:0, ecx

pop    ecx

pop    edi

pop    esi

pop    ebx

add    esp, e4h                             ; 退掉分配的d8h + 建立seh鏈所需的0ch位元組

cmp    ebp, esp

call __rtc_checkesp                       ; 檢查esp值,這個時候esp應該和ebp匹配,否則說明出現了棧不平衡的情況,這種情況下呼叫子程式報錯

mov    esp, ebp                             ; 恢復ebp到esp

pop    ebp                                  ; 恢復原來的ebp值

ret    0

_wmain       endp

專門用於seh的子程式。__unwindfunclet$_wmain$0當異常發生的時候被調,負責進行棧展開,主要是呼叫析構函式。__ehhandler$_wmain則是在exception被丟擲的時候呼叫。

text$x       segment

__unwindfunclet$_wmain$0:                        ; 當seh發生的時候會呼叫該函式,析購a_class

lea    ecx, dword ptr [ebp-14h]             ; ecx = [ebp – 14h],也就是a_class的位址

jmp    ??1my_class@@qae@xz                  ; 呼叫my_class::~my_class

__ehhandler$_wmain:

mov    edx, dword ptr [esp+8]              ; esp = 當前的fs:0, [esp + 8] = 之前的seh結構,也就是main中建立的

lea    eax, dword ptr [edx+0ch]             ; edx + 0ch = 當前的ebp,也就是main的ebp,此時不能直接使用ebp因為可能會從任意函式調過來,此時ebp是該函式的ebp,而不是main的ebp

mov    ecx, dword ptr [edx-e0h]             ; 之前存下去的__security_cookie ^ ebp

xor    ecx, eax                             ; 再次和ebp相異或

call @__security_check_cookie@4           ; 此時ecx應該等於__security_cookie,否則說明棧的內容被惡意改動(或者程式設計錯誤)

mov    eax, offset __ehfuncinfo$_wmain

jmp    ___cxxframehandler3

text$x       ends

my_class::my_class建構函式如下。建構函式本質上就是乙個全域性函式,名字是經過打亂的(name mangling),這樣可以和同一class和其他class的同名方法區別開來。不同編譯器有不同規則,因此不必過於深究。

乙個簡單函式的反彙編

void myfunction int a,int b int c a b 1 儲存ebp。ebp總是被我們用來儲存這個函式執行前的esp的值。執行完畢後,我們用ebp恢復esp 同時,呼叫此函式的上層函式也用ebp做同樣的事情。所以先把ebp壓入堆疊,返回之前彈出,避免ebp被我們改動。push ...

乙個簡單的verlig程式 乙個簡單C程式的介紹

我們前面學了c語言的一些理論知識,今天通過乙個簡單的程式先來看一看c語言程式是什麼樣子。然後再對程式中的 進行介紹。這個語句的功能是進行有關的預處理操作。include稱為檔案包含命令,後面尖括號的內容稱為標頭檔案或首檔案。此處指包含stdio.h系統標頭檔案,在下面主函式中使用的printf 函式...

objdump 反彙編乙個函式的指令碼

1 使用system.map檔案查詢函式的起始位址和結束位址 2 使用objdump d 反彙編,然後通過 start address和 stop address引數指定函式區間 3 使用nm n out.elf system.map 命令生成system.map檔案 bin sh routine ...