C反彙編例項(詳細註解版)(一)

2021-05-23 17:07:45 字數 4285 閱讀 4911

呵,好久沒寫

csdn

文章了,來湊個熱鬧。最近我閱讀了楚狂人

,wowocock

寫的《天書夜讀》試讀本,對

c反彙編感觸頗深,書中有一例演算法反彙編,其對彙編的閱讀確實富有挑戰,而該書中也未詳解,在此,我謹將此例詳細分析如下,幫助大家更好理解

c反彙編**,若有任何錯誤,請大家批評指正!

該例的要求是求兩個

3x3矩陣的乘積,其

c源**如下:

int myfunction(int a[3][3], int b[3][3], int c[3][3])

return 0;

}相當簡單吧?呵呵,那麼希望你看過了下面的反彙編**後,還能這樣樂觀。

如下的反彙編**,據原書作者,在

vc2003

,debug

模式下得到,同時我在

vc2008pro

下得到彙編**完全相同,可以通用,但此處引用原書中的**。

00411a3e mov dword ptr [i],0

00411a45 jmp myfunction+30h (411a50h)

00411a47 mov eax,dword ptr [i]

00411a4a add eax,1

00411a4d mov dword ptr [i],eax

00411a50 cmp dword ptr [i],3

00411a54 jge myfunction+0aeh (411aceh)

00411a56 mov dword ptr [j],0

00411a5d jmp myfunction+48h (411a68h)

00411a5f mov eax,dword ptr [j]

00411a62 add eax,1

00411a65 mov dword ptr [j],eax

00411a68 cmp dword ptr [j],3

00411a6c jge myfunction+0a9h (411ac9h)

00411a6e mov eax,dword ptr [i]

00411a71 imul eax,eax,0ch

00411a74 mov ecx,dword ptr [a]

00411a77 mov edx,dword ptr [j]

00411a7a mov esi,dword ptr [b]

00411a7d mov eax,dword ptr [ecx+eax]

00411a80 imul eax,dword ptr [esi+edx*4]

00411a84 mov ecx,dword ptr [i]

00411a87 imul ecx,ecx,0ch

00411a8a mov edx,dword ptr [a]

00411a8d mov esi,dword ptr [j]

00411a90 mov edi,dword ptr [b]

00411a93 mov ecx,dword ptr [edx+ecx+4]

00411a97 imul ecx,dword ptr [edi+esi*4+0ch]

00411a9c add eax,ecx

00411a9e mov edx,dword ptr [i]

00411aa1 imul edx,edx,0ch

00411aa4 mov ecx,dword ptr [a]

00411aa7 mov esi,dword ptr [j]

00411aaa mov edi,dword ptr [b]

00411aad mov edx,dword ptr [ecx+edx+8]

00411ab1 imul edx,dword ptr [edi+esi*4+18h]

00411ab6 add eax,edx

00411ab8 mov ecx,dword ptr [i]

00411abb imul ecx,ecx,0ch

00411abe add ecx,dword ptr [c]

00411ac1 mov edx,dword ptr [j]

00411ac4 mov dword ptr [ecx+edx*4],eax

00411ac7 jmp myfunction+3fh (411a5fh)

00411ac9 jmp myfunction+27h (411a47h)

暈了?呵呵,如果你第一遍看就可以完全讀通,那我只好對您orz了= =,希望你們這些天才別來砸我場子啊^_^

首先先簡單提一下,c語言中多維陣列的儲存方式。其儲存的規則是,列優先於行,也就是:若有a[3][3],則順序是a[0][0], a[0][1], a[0][2], a[1][0], a[1][1], a[1][2],a[2][0], a[2][1], a[2][2]。其實所謂的多維陣列這樣高階語言才有的資料結構,在底層實現中,無非就是一片連續分配的一維記憶體空間而已,大家千萬別看得太過神秘了。

接著要提一下c語言中指標在彙編實現時的情況。彙編可以說把高階語言中幾乎所有現象的本質都暴露了出來。現觀察一下以下情況:對於int a[3][3]定義的多維陣列變數a,a本身表示的是該矩陣首行的位址,而a[0](或者*a)是首行首列元素的位址,兩者是不同的指標型別,然而很容易知道在位址數值上兩者是相等的,我們引申開來,比如我們要訪問a[m][n],我們還可以寫作*(*(a + m) + n),但由上段所述,實際上就是把a所含的位址再往後移m * 3 * 4(int佔4個位元組) + n * 4個位元組(此注:a + m不是a所在處後移m個位元組!可以把a理解為int[3]這種型別的指標,所以加了m,其實是加了12* m個bytes)就是所要訪問的記憶體,換句話說任何多維陣列總可以用乙個一維普通指標(比如使用指標型別強制轉換)完全訪問到,儘管在高階語言中這樣的做法是非常不明智且危險的。但彙編卻正是這麼做的!比如我們有c語句:a[i][j] = 2;,用c還可以寫作*(*(a + i) + j) = 2,而用彙編則可能是這樣,

mov eax, dword ptr [i] ;

把i的值讀入eax

imul eax, eax, 0ch ;

把eax乘以12,因為一行有三個int,3 * 4 = 12

lea ecx, a[eax] ;

相當於將a所含的位址與eax相加後存入ecx

mov edx, dword ptr [j] ;

把j的值讀入edx

mov dword ptr [ecx + edx * 4], 2 ; ecx + edx

就是a[i][j]的位址

我們嘗試省略暫存器的中間步驟、並逐式代入的話,就直接可以推出這個式子:

movdword ptr [a + i * 12 + j * 4], 2

;這個式子和上述的完全一致。

最後提到的就是c中for語句的彙編實現。

for (init; condition; expr)

loop-body

大家都應當很清楚,執行的順序是:先init初始化迴圈變數,接著判斷condition,若滿足則執行迴圈體(loop-body),再執行expr,判斷條件是否滿足,滿足則執行loop-body……彙編**是非常機械地對應著上述過程,例:

for (i = 0; i < 5; ++i)

loop-body

則相應彙編**:

; 初始化**

mov dword ptr [i], 0

jmp(*); 無條件跳轉到(*)所在**,這裡不列出具體的**位址了

; 這段就是expr,類似用乙個中間變數(只不過這裡是暫存器)的辦法來給i加一

(#)mov eax, dword ptr [i]

add eax, 1

mov dword ptr [i], eax ;

這段則是判斷條件,condition

(*)cmp dword ptr [i], 5 ;

比較i和5

jge(**); jge

表示jump to(**)when i is greater than or equal to 5,大於等於5

; 跳轉,(**)指向的是for迴圈後面接著的**,也就是跳出迴圈

; 以下段省略,是迴圈體loop-body…

jmp(#);

無條件跳轉到expr,並進而判斷條件

; 以下是for迴圈以外的**

(**)

C反彙編例項(詳細註解版)(三)

上次我分析了一下,debug 模式下反彙編後的演算法部分 天才的您可能覺得不算糟,想再搞點花樣,那麼本文就能滿足你的需求。天書夜讀上其實還貼出來了 release 模式下的 它經過 vc編譯器 o2的優化,我初次看到反彙編 時,還真汗了一把。不過定下心來細細品位還是可以看懂的,儘管正如原書所說,連語...

C反彙編例項(詳細註解版)(三)

上次我分析了一下,debug 模式下反彙編後的演算法部分 天才的您可能覺得不算糟,想再搞點花樣,那麼本文就能滿足你的需求。天書夜讀上其實還貼出來了 release 模式下的 它經過 vc編譯器 o2的優化,我初次看到反彙編 時,還真汗了一把。不過定下心來細細品位還是可以看懂的,儘管正如原書所說,連語...

C反彙編例項(詳細註解版)(二)

那麼有了上述三方面的基礎,我們就可以來逐一解讀那段 傳奇 的彙編 了。初始化i 00411a3e mov dword ptr i 0 跳轉至條件判斷 00411a45 jmp myfunction 30h 411a50h 迴圈表示式,對i每輪加1 00411a47 mov eax,dword ptr...