| 文章來源: http://www.hacklong.com 原文作者: E言E行駭客龍脈 前言: 寫這篇文章出於個人興趣,要先聲明的是本人能力是非常有限!其中參考了許多文章!由於無法提供更多的資訊教程,所以文章題目才叫做"給新手引路 之 濃縮彙編基礎"。主要講的是破解中所要的一些彙編知識,方便新手們理解,我將用比較通俗的語言講述!希望大家別說我"低級" - -b 寫此文的理由: 1、出於興趣 2、助於自己學習鞏固,利於新手注: 本文並不教如何編寫組譯工具,只想引新手們進Crack大門,一些遲遲無法Crack成功的人也就是這個原因了! 最好是能拋磚引玉了,勾起新手們學習彙編的興趣! 重要一點是:不懂彙編是完全沒辦法搞Crack的,希望大家帶著這點來學習! ----------------------------------------------------------------------------------------------- 1.0 關於組合語言組合語言是創造出來代替原始的只能由處理器理解的二進位代碼的,也就是在OD中常見的機器碼!用機器碼來寫程式,可以想象其難度吧,所以組合語言就出現了,彙編代碼是直接描述處理器可以執行的代碼,也就是在OD中最常見的反組譯碼代碼了!(當然,有點不一樣),而組合語言是和cpu相關的,和機器語言是一一對應的! 2.0 關於cpu CPU的任務就是執行存放在儲存空間裡的指令序列。為此,除要完成算術邏輯操作外,還需要擔負CPU和儲存空間以及I/O之間的資料傳送任務。早期的CPU晶片只包括運算器和控制器兩大部分。到了近幾年,為了使儲存空間速度能更好地與運算器的速度相匹配,又在晶片中引入了高速緩衝儲存空間(知道為什麼P4比P4賽揚貴那麼多了吧?)。看主要的組件: 1.算術邏輯組件ALU(arithmetic logic unit)用來進行算術和邏輯運算。這部分與我們的關係不太大,我們沒必要管它。 2.控制邏輯。同樣與我們的關係不大。 3.工作寄存器。意識了吧,寄存器呀!喂,,寄存器呀!~ 3.0 寄存器所要瞭解的是8個32位的寄存器,分別是eax,ebx,ecx,edx,esp,ebp,edi,esi eax-edx這四個是通用寄存器,雖然各個都有各自的用途,不過你可以用它們來做任何事!是32位的,自然有低位和高位,我們又可以通過ax,bx,cx,dx來訪問其低十六位,但高十六位是無法訪問的!比如eax=12345678h,那麼低十六位ax=5678h!而十六位的自然也有低位和高位,不過高八位是可以訪問的,如ax可以分為ah和al,看字面就知道,ah(high)高八位,al就為低八位了!前面的例子,ax=5678h,那麼ah=56h,al=78h!這四個寄存器主要是用來暫放計算結果或什麼什麼的! esp-esi這四個主要是定址時用來存放位移或指標,所以,也就稱為指標寄存器或變址寄存器了~如在OD中看到的[eax],其實eax中存放的是一個記憶體位址,而實際要訪問的是那個記憶體位址裡的內容! esp(堆棧指標寄存器): 很重要的一個概論,堆棧有著先進後出的特點,就好像有一個圓柱形的筒子,該直徑剛好是一個乒乓球的直徑,所以最先放進去的球當然會最後出來.而esp呢,永遠是指著最頂的那個球的,也就是永遠都指向棧頂!在od中也很常見了,比如push和pop就是對棧的操作,push把一個資料壓入棧中,也就是把一個球放進去,再去調用push時就再放進一個,而esp則指向第二個放進去的那個球了!使用pop呢就從棧中彈出一個資料,前面說了,堆棧有著先進後出的特點,所以用pop呢就從最後放進去的那個球先出了(除非你破壞筒子(破壞堆棧?那是不可能的,程式馬上死給你看))!而esp還是指向棧頂! 取個代碼例子: (1) mov ecx, 100<---------100傳入ecx (2) mov eax, 200<---------200傳入eax (3) push eax <------------ecx先進了 (4) push ecx<-------------再來是eax (5) pop ebx<--------------從棧頂取出一個,也是最後進去的那一個,結果存到ebx (6) pop ecx<--------------從棧頂取出一個,也就是剛剛先進去的那個了,結果存到ecx 最後ebx=200,ecx=100 到了win32的平台下,api大家都知道了吧!api的參數都是靠堆棧來傳遞的,比如說一個FindWindow,在C裡我這樣調用 ->::FindWindow(NULL,"a")->而反組譯碼之後在系統底層反組譯碼代碼就象這個樣子: push xxxxxxxx->xxxxxxxx為"a"的記憶體位址 push yyyyyyyy->yyyyyyyy為空白中止字串的指標 call zzzzzzzz->調用FindWindow 而在call裡面先使用pop彈出先前壓入棧的參數再使用 ebp(基址指標寄存器): 它稱為基址指標寄存器,它們都可以與堆棧段寄存器SS(堆棧段)聯用來確定堆棧中的某一儲存單元的地址,ESP用來指示段頂的位移地址,而EBP可作為堆棧區中的一個基地址以便訪問堆棧中的資訊。 ESI(源變址寄存器)和EDI(目的變址寄存器)一般與資料區段寄存器DS聯用,用來確定資料區段中某一儲存單元的地址。這兩個變址寄存器有自動增量和自動減量的功能,可以很方便地用於變址。 還有兩個專用寄存器,分別是eip和flags flags: 這個是標誌寄存器了,存放條件標誌碼、控制標誌和系統標誌的寄存器!在od中也見很多了,比如zf(零標誌),用cmp比較時,把兩個運算元相減,為0就置zf為1,否則zf為0。而jnz就是看zf是否為0,為0就跳!這樣說起來似乎更亂了,建議大家去記那些大於就跳,小於就跳的,比較簡單(jnz就是不相等就跳)``哦呵呵!!至於其它標誌,這裡不再闡述了,可以去參看彙編速查! cmp eax,ebx<-比較eax和ebx,兩個相減,為0的話zf就為一,否則zf為0 jnz xxxxxxx<-判斷zf是否為0,為0就跳到xxxxxxx處,也就是所謂的不相等就跳 eip(指令指標寄存器): 這個很好理解,根據od來說,載入一個程式後,比如代碼像這樣: 0043C412 >/$ 55 push ebp <-載入後停在這,看寄存器視窗eip這時為43c412 0043C413 |. 8BEC mov ebp, esp <-f8運行一步之後,eip為43c413 0043C415 |. 6A FF push -1 <-eip為43c415 0043C417 |. 68 C8B64800 push 0048B6C8 <-eip為43c417 有人會說"原來eip是指示當前執行到代碼處的地址的!" ,這不對!!因為f8運行還沒通過那條代碼,所以還不算已經執行了,沒錯,eip指向的就是下一條將要執行的指令的指標! 段寄存器: cs程式碼片段,ds資料區段,ss堆棧段,es附加段在Win32編程中段的概念已經不重要了!而在Crack時你總不會是在調是dos時代的程式吧!-! 4.0 常用彙編指令 mov ax,cx <-很常用了,把cx的值送入ax中,cx值保持不變 cmp eax,ecx<-很常見了吧,比較eax和ecx,置標誌位!方法前面說過了 xor eax,eax<-看這個,eax與自己異或,是清零的操作! lea eax,str<-並不傳送資料,只傳送該資料的地址,將str字串的地址傳到eax push eax <-進棧操作,前面說過了,eax進棧 pop ebx <-出棧操作,前面也說了,彈出位於棧頂的資料存入ebx ADD 加法指令 格式:ADD DST,SRC 執行的操作:(DST)<-(SRC)+(DST) SUB 減法指令 格式:SUB DST,SRC 執行的操作:(DST)<-(DST)-(SRC) MUL 無符號乘法指令 格式: MUL SRC 執行的操作:位元組操作(AX)<-(AL)*(SRC);字操作(DX,AX)<-(AX)*(SRC);雙字操作:(EDX,EAX)<- (EAX)*(SRC) DIV 無符號除法指令 格式:DIV SRC 執行的操作:位元組操作:16們被除數在AX中,8位除數為源運算元,結果的8位商在AL中,8位餘數在AH中 。表示為: (AL)<-(AX)/(SRC)的商,(AH)<-(AX)/(SRC)的餘數。字操作:32位被除數在DX,AX中。其中DX為高位字,16位除數為源運算元,結果的16 位商 在AX中,16位餘數在DX中。表示為:(AX)<-(DX,AX)/(SRC)的商,(DX)<-(DX,AX)/(SRC)的餘數。 nop <- 無操作,去掉指令用的吧!去掉一個跳轉,讓程式直接往下走,就到註冊成功處啦(扯遠了````) call <- 調用子程式或函數用的 關於跳轉指令,可以查看彙編速查手冊,彆強迫自己把所有的都一下記住,浪費精力,不懂時再查一下,久了就記住了! 5.0 進階語言程式的彙編淺解析組合語言要和硬體直接打交道,寫病毒是方便點啦!!而在進階語言中,如C中我們要面向的是問題的解決,對於硬體資源操作,編譯器搞定了!在這裡稍微講一下進階語言中與反組譯碼代碼相應的一些地方: 1、定義變數 int a; 一個變數其實是存放在一個記憶體位址裡,如果對a進行賦值"a=10",在反組譯碼中就有可能表現為: mov word ptr[007e58c2],A 像這個樣子,而a所對應的記憶體位址就是0x007e58c2了,當然是亂寫的一個地址而已,系統怎樣分配?(天知道...) 2、比如一個數組 char str[]="hello"; 佔用了6個位元組,最後一個是以0結尾的空位元組,數組名可以當做數組的指標!str[0]='h',str[0]相應一個變數地址,比如為[0040e123],那麼[0040e124]就為'e',[0040e125]就為'l'....了` 3、指標 char *p; 指標也是一個變數,所以它也對應一個記憶體位址!但訪問時應該是訪問其指向的記憶體位址的內容,而不是這個指標變數的內容,其內容只是一個地址而已!假如該指標變數地址為007e1000,那麼語句p=a,這句在進階語言裡是讓指標p指向a這個記憶體單元!p裡的內容是a的地址,*p實際上是a的內容了!而反組譯碼有可能表現成這樣: mov [007e1000],007e2000<-假如007e2000為變數a的地址,那麼就是把a的地址傳到007e1000這個內容裡了! 4、函數調用 sub(a,b); 假如sub是自訂的一個減法函數,作用為參數一減去參數二,上面語句為在C中調中時傳遞參數!前面有說過了,Win32平台下函數調用的參數是通過堆棧來傳遞的,那麼反組譯碼就是: (假如a=2,b=1) mov eax,2 mov ebx,1 push eax push ebx call 取地址(sub) ....... ----------------------------------------------------------------------------------------------- 好了,最後感謝大家能看完這篇了了草草的東西,我也回顧了不少知識!在本人能力範圍內的事不知道對新手們有沒有協助,還有一點要提醒各位新手,如果真想學好Crack學通Crack這門知識的話,不完全瞭解彙編是不行的!所以在看了我這篇之後如果能激起你學彙編的信心是最好的!要不等到Crack遇到什麼問題時才再想回過頭學彙編,那很難!~ |