?? offset.txt
字號(hào):
不要看反匯編代碼,把注意力放到機(jī)器碼上 非常羅嗦,高手就不要看折磨自己了,不過不知道有沒有錯(cuò),歡迎指出來(lái)
其實(shí)我也剛明白--
dwVar dd ?
call @F
@@:
pop ebx
sub ebx,offset @B
mov eax,[ebx + offset dwVar]
翻譯成機(jī)器碼就是:
:00401000 00000000 BYTE 4 DUP(0)
:00401004 E800000000 call 00401009 call @F
:00401009 5B pop ebx
:0040100A 81EB09104000 sub ebx, 00401009 sub ebx,offset @B
:00401010 8B8300104000 mov eax, dword ptr [ebx+00401000] mov eax,[ebx + offset dwVar]
重點(diǎn)在理解 相對(duì)地址(相對(duì)跳轉(zhuǎn),變) 和 絕對(duì)地址(絕對(duì)跳轉(zhuǎn),全局變量,不變),難點(diǎn)(我覺得)在這句迷惑人的反匯編代碼 call 00401009
不要看反匯編代碼,把注意力放到機(jī)器碼上
把call @F(call 00401009) 這句的機(jī)器碼 E800000000 和最后兩行的機(jī)器碼對(duì)比著看(81EB09104000、8B8300104000)
看出來(lái)了嗎?81EB和8B83后面的09104000和00104000也就是00401009和00401000這兩個(gè)是絕對(duì)地址(注意反過來(lái)了,低地址對(duì)低位),因?yàn)槿肿兞坑玫木褪墙^對(duì)地址。一旦編譯好了,不管這段“數(shù)據(jù)+代碼”移到那里,這兩個(gè)地址都不會(huì)變,都指向00401009和00401000,因?yàn)檫@是絕對(duì)地址,因?yàn)闄C(jī)器碼不會(huì)變。雖然這時(shí)候全局變量(數(shù)據(jù))已經(jīng)從這移走了,現(xiàn)在在這里的有可能是被插入進(jìn)程自己的數(shù)據(jù)。
再看機(jī)器碼E800000000后面是00000000,而不是00401009,這說(shuō)明什么? 對(duì)了:這不是一個(gè)絕對(duì)地址而是一個(gè)相對(duì)地址,不是直接跳到00401009,而是跳到當(dāng)前指令地址+偏移00000000處的地址,也就是當(dāng)前指令地址。
跟上面的兩條指令一樣,也移動(dòng)這句代碼,比如移到00801000,機(jī)器碼不會(huì)變還是E800000000,但這時(shí)它的反匯編代碼會(huì)顯示成call 00801009,移動(dòng)一千次,反匯編代碼變一千次。所以這句反匯編代碼迷惑人的地方就在于實(shí)際上代碼會(huì)變,但代碼的反匯編表現(xiàn)形式——call 00401009——給人一種不變的錯(cuò)覺(比如和這行比 sub ebx, 00401009,這里的00401009就是絕對(duì)地址),總認(rèn)為它不管移到哪都跳到00401009,這里不明白再往下看就等著崩潰吧。不知道你卡哪了,反正我就郁悶在這了,所以說(shuō)基礎(chǔ)知識(shí)掌握不好會(huì)讓你學(xué)的很郁悶。
回過頭再看上面最后兩行的反匯編代碼,結(jié)果是沒變,還是sub ebx, 00401009 和 mov eax, dword ptr [ebx+00401000]。
好了,call @F =j(luò)mp @F + push @F(沒錯(cuò)吧)
pop ebx 把 @F(就是變的值)放到 ebx
sub ebx,offset @B 用變的值-不變的得到差值(offset @B 得到的也是絕對(duì)地址)
mov eax,[ebx + offset dwVar] 差值+不變的=變的也就是正確的,然后把后面所有的全局變量都加上
00801009-00401009=00400000,全局變量都加上400000就ok了
如果整個(gè)“數(shù)據(jù)+代碼”移到00602000,于是00602009-00401009=00201000,那就加201000
再看下面老羅寫的應(yīng)該就能明白了吧 ——
自定位技術(shù)其實(shí)很簡(jiǎn)單,觀察下面這段代碼:
dwVar dd ?
call @F
@@:
pop ebx
sub ebx,offset @B
mov eax,[ebx + offset dwVar]
翻譯成機(jī)器碼就是:
:00401000 00000000 BYTE 4 DUP(0)
:00401004 E800000000 call 00401009
:00401009 5B pop ebx
:0040100A 81EB09104000 sub ebx, 00401009
:00401010 8B8300104000 mov eax, dword ptr [ebx+00401000]
這段代碼不存在重定位的問題,分析如下。
call指令會(huì)將返回地址壓入到堆棧中,當(dāng)整段代碼在沒有移動(dòng)的情況下執(zhí)行的時(shí)候時(shí),call @F指令執(zhí)行后堆棧中的返回地址就是@@標(biāo)號(hào)的地址00401009h,下一句pop指令將返回地址彈出到ebx中,再接下來(lái)ebx減去00401009h,現(xiàn)在ebx等于0,所以mov eax,[ebx + offset dwVar]指令就等于mov eax,dwVar指令。
當(dāng)整段代碼被移動(dòng)到其他地方時(shí)(假設(shè)被移到00801000處執(zhí)行),@@標(biāo)號(hào)現(xiàn)在對(duì)應(yīng)的地址是00801009h,變量dwVar的地址對(duì)應(yīng)00801000h,當(dāng)call指令執(zhí)行后,壓入到堆棧的地址是00801009h,pop到ebx中的就是這個(gè)數(shù)值,經(jīng)過sub ebx,00401009指令以后,ebx等于00400000h,現(xiàn)在mov eax,dword ptr [ebx+00401000]指令就相當(dāng)于mov eax,[00801000],而00801000這個(gè)地址剛好等于dwVar現(xiàn)在所處的位置,所以,雖然代碼被移動(dòng)了位置,mov eax,dwVar指令還是訪問了正確的地方。
call/pop/sub這3個(gè)指令組合的用途就是計(jì)算出代碼當(dāng)前的位置和設(shè)計(jì)時(shí)位置的偏移值之差,只要用這個(gè)差值去修正包含絕對(duì)地址的指令,如訪問全局變量的指令,就能夠保證修正后的地址是正確的,這就解決了重定位的問題。
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -