標(biāo) 題: 【原創(chuàng)】內(nèi)聯(lián)匯編 作 者: kflnig 時 間: 2007-02-11,15:27:26 鏈 接: http://bbs./showthread.php?t=39485 有很多人認(rèn)為匯編已經(jīng)失去了用武之地,包括曾經(jīng)的我。我用的是visual c++6.0?,F(xiàn)在我要問你一個問題。 a=10,b=20。你現(xiàn)在要使a和b的值交換。你有什么辦法。這是教科書上說得很多的方法。第一種方法: #include <iostream.h> void main() { int a,b,c; a=10; b=20; c=a; a=b; b=c; cout<<“a=”<<a<<“,b=”<<b; } 輸出當(dāng)然是a=20,b=10 該方法引入了一個新的變量,即多開辟了一個DWORD的空間。現(xiàn)在請你再看我的實(shí)現(xiàn)方法。第二種方法:(把加了下劃線的部分改成如下代碼) _asm { push a push b pop a pop b } 我稍微解釋一下:_asm告訴編譯器,我要使用內(nèi)聯(lián)匯編代碼了。換成__asm也一樣(注意這里有兩根英文半角下劃線,前面的是一條)。上面的那段代碼也等價于 _asm push a _asm push b _asm pop a _asm pop b 看來還是用花括號{}來得方便。 上述,我在c++中使用了內(nèi)聯(lián)匯編,說實(shí)話,這種方法比第一種方法來得差。因?yàn)槲业膬蓚€push就開辟了2個DWORD空間。 有沒有辦法不開辟額外的空間呢?請看第三種實(shí)現(xiàn)方法: _asm { mov eax,a mov ebx,b xchg eax,ebx mov a,eax mov b,ebx } 在聽取下面的朋友的批評之后,上面這段代碼不免有脫了褲子放屁之嫌,應(yīng)改為 _asm { mov eax,a xchg eax,b mov a,eax } 這樣看起來就比較好了。因?yàn)榈谝欢未a執(zhí)行的時候也要先把值移動到寄存器中。 要說內(nèi)聯(lián)匯編最重要的作用就是在寫溢出代碼和注冊機(jī)中。如果你有志于學(xué)這些東西,那么下面的文章你要好好看了??上У氖莾?nèi)聯(lián)匯編不是宏匯編,一些偽指令內(nèi)聯(lián)匯編中是不能用的,比如說 .if .elseif .endif 雖然在很多時候?qū)懘a不方便了,但是勉強(qiáng)還行。 很重要的一點(diǎn):一般來說,在_asm塊開始的時候,你不應(yīng)該假定某個寄存器中包含著值。也就是說所有的寄存器都是可用的。當(dāng)然不指eip,esp,ebp用這些寄存器用得不好你會死得很難看,是cracker都知道這三個寄存器的作用吧!還要注意PUSH,POP配對。這是為了堆棧平衡。 現(xiàn)在基本上我們邁出了學(xué)習(xí)內(nèi)聯(lián)匯編的第一步,也是一大步。剩下的都只是一些細(xì)節(jié)了。 現(xiàn)在我要編寫一個函數(shù)。 int cmpare(int a,int b) { _asm { mov eax,a cmp eax,b jge line1;都是因?yàn)閭沃噶畈荒苡?,否則這里肯定是用.if偽指令更容易看懂。 mov eax,b line1: } } 我寫這個函數(shù)的目的是為了告訴大家整數(shù)在默認(rèn)情況下是采用eax來作為返回值的,還有就是在內(nèi)聯(lián)匯編中推薦用匯編自己的注釋符號“;”,雖然說c++的注釋符號也可以使用。這里我的a=10,b=20。雖然在編譯時c++提示我如圖1 ![]() 圖1 但是真正執(zhí)行cout<<cmpare(10,20)輸出的是20。另外浮點(diǎn)通過st(0)返回值。 sz[1]= 3; _asm { mov eax,sz[1] mov a,eax } cout<<a; 你知道這將會輸出什么嗎?你絕對意想不到,我告訴你,在我這里是63753420。是不是很迷惑。當(dāng)然開始的時候我也很迷糊,咱們先把mov eax,sz[1]改成mov eax,sz[4]然后再編譯,看現(xiàn)在已經(jīng)達(dá)到了我們預(yù)想的情況a=3。至于為什么嗎?原因是:[]是c++和匯編共同包含的操作符,會被編譯成匯編的操作符。而一個int是4字節(jié),所以我們的代碼應(yīng)該是sz[4]而不是sz[1],后面的下標(biāo)實(shí)際上是起著尋址的作用。前面的數(shù)組名sz是起著基地址的作用。如果不好理解你應(yīng)該用OD調(diào)試看看。為了簡便我們的寫法。我覺得我們可以這樣操作數(shù)組: sz[xl*lx]。 lx是我們先前就定義的各種類型常量,xl是序列,即一般的下標(biāo)值。這個類型的常量我們可以用 _asm { mov eax,type sz;sz是數(shù)組或者變量名 mov a,eax } cout<<a; 這樣就可以輸出這種數(shù)據(jù)的每個數(shù)據(jù)所占的大小了,單位是byte。 內(nèi)聯(lián)匯編學(xué)習(xí)的路還很遠(yuǎn),大家要努力學(xué)習(xí)。 學(xué)習(xí)匯編,最常用的東西除了寄存器就是指針了,在匯編中指針的反映就是使用[ address]。 不懂事的程序員往往很容易寫出這樣的代碼: _asm { lea eax,a mov b,[eax] } 這當(dāng)然是錯誤的,這反映為對匯編代碼知識不是很了解。因?yàn)閙ov指令是不可以這樣使用的 mov m32,m32;m32表示32位儲存器。所以只是應(yīng)該改成下面這樣。 _asm { lea eax,a mov ebx,[eax] mov b,ebx } 這樣a的值才順利到達(dá)了變量b這里。下面再舉幾個例子,只是希望對一些匯編代碼不太熟悉的小鳥一些幫助。我們繼續(xù)。 a=0x120; _asm { lea ebx,a movzx eax, byte ptr [ebx] mov b,eax } cout<<b; b等于多少?知道嗎?如果你說的是32,那么你很聰明,匯編學(xué)得還不錯。如果你說的是48,那么你已經(jīng)把整數(shù)變量和字符串混起來了,在ASCII碼表中0的表示就是48。如果你說的是1,那么你應(yīng)該還不懂匯編。 在內(nèi)存中ebx指向的內(nèi)存應(yīng)該是20 01。因?yàn)樗械臇|西在內(nèi)存中都是反向存儲的。在計算機(jī)運(yùn)算的時候就是01 20。在出一道練習(xí)題 在內(nèi)存中20 30 04這個值是多少?答案:04 30 20。 這里我們要特別注意的是在寫注冊機(jī)時,你得先知道,你輸入的值,它是在當(dāng)整數(shù)計算,還是字符串計算。通常它取得到的都是字符串,有些軟件會把字符串轉(zhuǎn)換成整數(shù)。 這么點(diǎn)東西,我學(xué)習(xí)了一天?。M愧,慚愧…… 最后夸獎自己一句,這篇文章真的很好,很難找到這么淺顯易懂的文章?。_^ |
|