• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            soNiliCs

            Game! Game! Game!
            隨筆 - 2, 文章 - 2, 評(píng)論 - 0, 引用 - 0
            數(shù)據(jù)加載中……

            崩潰分析用到的一些匯編語言技巧

            常用寄存器

            寄存器
            名稱
            常見用途(未完)
            eax
            累加器(Accumulator) 函數(shù)返回值
            ebx 基址寄存器(Base) 可作為存儲(chǔ)指針來使用
            ecx
            計(jì)數(shù)器(Counter)
            在循環(huán)和字符串操作時(shí),用來控制循環(huán)次數(shù)
            __thiscall中傳遞this指針
            edx
            數(shù)據(jù)寄存器(Data)

            esp
            堆棧指針寄存器(Stack)

            ebp
            基地址指針寄存器(Base)

            esi
            源地址寄存器(Source Index)

            edi
            目的地址寄存器(Destination)


            常用匯編指令

            push 把一個(gè)32位的操作數(shù)壓入堆棧,這個(gè)操作會(huì)導(dǎo)致esp減4.
            pop 與push相反,esp加4,一個(gè)數(shù)據(jù)出棧
            call 調(diào)用函數(shù)。將下一條指令的地址壓棧,然后跳轉(zhuǎn)到所調(diào)用函數(shù)的開始處,本質(zhì)相當(dāng)于push+jump
            ret 與call相對(duì)應(yīng),跳轉(zhuǎn)到棧頂數(shù)據(jù)所指的地址,本質(zhì)相當(dāng)于pop+jump。對(duì)于_cdecl 調(diào)用的函數(shù),通常會(huì)在ret之后進(jìn)行exp-[n],用于清理調(diào)用參數(shù)堆棧
            xor 異或,常用于清零操作,例如: xor eax eax
            lea 取得地址(第二個(gè)參數(shù))后放入前面的寄存器中。
            stosw 將eax中的數(shù)據(jù)傳送給edi,之后edi+4。常與rep一起使用,用于初始化內(nèi)存段
            rep 當(dāng)eax>0時(shí),重復(fù)后面的指令
            jp,jl,jge 根據(jù)eax中值與0的關(guān)系跳轉(zhuǎn)
            cmp 比較指令,將結(jié)果放入eax中,往往是jp,jl,jge之類跳轉(zhuǎn)指令的執(zhí)行條件


            函數(shù)調(diào)用規(guī)則

            調(diào)用方式
            簡(jiǎn)要說明
            堆棧清理 參數(shù)傳遞規(guī)則
            _cdecl C 編譯器的默認(rèn)調(diào)用規(guī)則 Caller
            從右到左
            _stdcall 又稱為WINAPI Callee
            從右到左
            __thiscall C++成員函數(shù)調(diào)用方式
            Callee  this放入ecx,其他從右到左
            __fastcall

            Callee
            前兩個(gè)等于或者小于DWORD大小的參數(shù)放入ecx和edx,其他參數(shù)從右到左

             _cdecl調(diào)用通常的asm代碼:

            被調(diào)用方:
            1.保存ebp。ebp總是用來保存這個(gè)函數(shù)執(zhí)行之前的esp值。執(zhí)行完畢之后,我們用ebp回復(fù)esp;同時(shí),調(diào)用此函數(shù)的上層函數(shù)也用ebp做同樣的事情。
            2.保存esp到ebp中。

            ;保存ebp,并把esp放入ebp中,此時(shí)ebp與esp都為這次函數(shù)調(diào)用的棧頂
            push ebp
            mov  ebp,esp


            3.在堆棧中預(yù)留一個(gè)區(qū)域用于保存局部變量。方法是將esp減少一個(gè)數(shù)值,這樣就等于壓入了一堆變量。要恢復(fù)的時(shí)候直接把esp回復(fù)成ebp保存的數(shù)據(jù)就可以了。
            4.保存ebx、esi、edi到堆棧中,函數(shù)調(diào)用完成后恢復(fù)。

            ;把esp往下移動(dòng)一個(gè)范圍,等于在堆棧中預(yù)留一片新的空間來保存局部變量
            sub  esp,010h
            push ebx
            push esi
            push edi


            5.(debug版)把局部變量全部初始化為0xcccccccch.

            ;將保存局部變量的區(qū)域全部初始化為0xcccccccch
            lea  edi,[ebp
            -010h]
            mov  ecx,33h
            mov  eax,0xcccccccch
            rep  stos dword ptr [edi]


            6.然后執(zhí)行函數(shù)的具體邏輯。傳入?yún)?shù)的獲取為:ebp+4為函數(shù)的返回地址;ebp+8為第一個(gè)參數(shù),ebp+12為第二個(gè)參數(shù),以此類推。

            7.回復(fù)ebx、esi、edi、esp、ebp,最后返回。如果有返回值,在返回之前將保存在eax中,供調(diào)用方式用。

            pop  edi ;恢復(fù)edi、esi、ebx
            pop  esi
            pop  ebx
            mov  esp, ebp ;恢復(fù)原來的ebp和esp
            pop  ebp
            ret


            調(diào)用方:

            mov  eax,dword ptr [b]
            push eax
            move ecx,dword ptr [a]
            push ecx
            call myfunction
            add  esp,
            8              ;回復(fù)堆棧

             

            常見的基礎(chǔ)代碼結(jié)構(gòu)

            for循環(huán)

                for(int i = 0; i < 20++i )
            0040B93E  mov         dword ptr [i],
            0 
            0040B945  jmp         wmain
            +30h (40B950h) 
            0040B947  mov         eax,dword ptr [i] 
            0040B94A  add         eax,
            1 
            0040B94D  mov         dword ptr [i],eax 
            0040B950  cmp         dword ptr [i],14h 
            0040B954  jge         wmain
            +38h (40B958h) 
                {

                }
            0040B956  jmp         wmain
            +27h (40B947h) 

            可以看到主循環(huán)主要由這么幾條指令來實(shí)現(xiàn):mov進(jìn)行初始化;jmp跳過修改循環(huán)變量的代碼;cmp實(shí)現(xiàn)跳轉(zhuǎn)判斷;jge根據(jù)條件跳轉(zhuǎn)。用jmp回到修改循環(huán)變量的代碼進(jìn)行下一次循環(huán)。大體結(jié)構(gòu)如下:
                mov  <循環(huán)變量>,<初始值>     ;給循環(huán)變量賦值
                jmp  A                     ;跳到第一次循環(huán)處
            A:     (改動(dòng)循環(huán)變量)            ;修改循環(huán)變量
                
            B:  cmp  
            <循環(huán)變量>,<限制變量>   ;檢查循環(huán)變量
                jge  跳出循環(huán)
                (循環(huán)體)
                
                jmp  A                     ;跳回修改循環(huán)變量


            do循環(huán)

                int i = 0;
            0040B93E  mov         dword ptr [i],
            0 
                
            do 
                {
                    
            ++i;
            0040B945  mov         eax,dword ptr [i] 
            0040B948  add         eax,
            1 
            0040B94B  mov         dword ptr [i],eax 
                } 
            while (i<10);
            0040B94E  cmp         dword ptr [i],0Ah 
            0040B952  jl          wmain
            +25h (40B945h) 

            上面的do循環(huán)就是用一個(gè)簡(jiǎn)單的條件比較指令跳轉(zhuǎn)回去:
            cmp  <循環(huán)變量><限制變量>
            jl   
            <循環(huán)開始>


            while循環(huán)

            int i = 0;
            0040B93E  mov         dword ptr [i],
            0 
                
            while (i<10)
            0040B945  cmp         dword ptr [i],0Ah 
            0040B949  jge         wmain
            +36h (40B956h) 
                {
                    
            ++i;
            0040B94B  mov         eax,dword ptr [i] 
            0040B94E  add         eax,
            1 
            0040B951  mov         dword ptr [i],eax 
                }
            0040B954  jmp         wmain
            +25h (40B945h) 

            while要復(fù)雜一些,因?yàn)閣ile除了開始的時(shí)候判斷循環(huán)條件之外,后面還要有一條無條件跳轉(zhuǎn)指令:
            A:  cmp  <循環(huán)變量>,<限制變量>
                jge  B
                (循環(huán)體)
                
                jmp  A 
            B:  (跳出循環(huán))


            if-else判斷分支

            int i = 0;
            0040B93E  mov         dword ptr [i],
            0 
                
            int j = 0;
            0040B945  mov         dword ptr [j],
            0 
                
            if ( i < 10 )
            0040B94C  cmp         dword ptr [i],0Ah 
            0040B950  jge         wmain
            +3Bh (40B95Bh) 
                {
                    j 
            = 10;
            0040B952  mov         dword ptr [j],0Ah 
            0040B959  jmp         wmain
            +51h (40B971h) 
                }
                
            else if (i < 20 )
            0040B95B  cmp         dword ptr [i],14h 
            0040B95F  jge         wmain
            +4Ah (40B96Ah) 
                {
                    j 
            = 20;
            0040B961  mov         dword ptr [j],14h 
                }
                
            else
            0040B968  jmp         wmain
            +51h (40B971h) 
                {
                    j 
            = 30;
            0040B96A  mov         dword ptr [j],1Eh 
                }
                
            return 0;
            0040B971  xor         eax,eax 
            if 判斷都是使用cmp加上條件跳轉(zhuǎn)指令。
            cmp <條件>
            jle 
            <下一個(gè)分支>
            所以開始的反匯編為:
                if ( i < 10 )
            0040B94C  cmp         dword ptr [i],0Ah     ;判斷點(diǎn)
            0040B950  jge         wmain
            +3Bh (40B95Bh)     ;跳轉(zhuǎn)到下一個(gè)else if
            else if和else的特點(diǎn)是,在開始的地方都有一條無條件跳轉(zhuǎn)指令,跳轉(zhuǎn)到判斷結(jié)束處,阻止前面的分支執(zhí)行結(jié)束后,直接進(jìn)入這個(gè)分支的可能,這個(gè)分支執(zhí)行的唯一條件為前面的判斷不滿足。
            else則在jmp之后直接執(zhí)行操作,而else if則開始重復(fù)if之后的操作,用cmp比較,然后用條件質(zhì)量進(jìn)行跳轉(zhuǎn)。
            0040B959  jmp         wmain+51h (40B971h)     ;跳轉(zhuǎn)到判斷塊外
                }
                
            else if (i < 20 )
            0040B95B  cmp         dword ptr [i],14h     
            0040B95F  jge         wmain
            +4Ah (40B96Ah)     ;比較,條件跳轉(zhuǎn),目標(biāo)為下一個(gè)分支
                {
                    j 
            = 20;
            0040B961  mov         dword ptr [j],14h 
                }


            switch-case 判斷分支

            switch的特點(diǎn)是有多個(gè)判斷。因?yàn)閟witch顯然不會(huì)判斷大于小于,所以都是je,分別跳轉(zhuǎn)到每個(gè)case處,最有一個(gè)是無條件跳轉(zhuǎn),直接跳到default處。
            對(duì)于break,會(huì)增加一個(gè)無條件跳轉(zhuǎn)語句,跳轉(zhuǎn)至結(jié)尾

            int i = 0;
            0040B93E  mov         dword ptr [i],
            0 
                
            int j = 0;
            0040B945  mov         dword ptr [j],
            0 
                
            switch (i)
            0040B94C  mov         eax,dword ptr [i] 
            0040B94F  mov         dword ptr [ebp
            -0DCh],eax 
            0040B955  cmp         dword ptr [ebp
            -0DCh],0     
            0040B95C  je          wmain
            +49h (40B969h)         ;判斷case 1
            0040B95E  cmp         dword ptr [ebp
            -0DCh],1 
            0040B965  je          wmain
            +52h (40B972h)         ;判斷case 2
            0040B967  jmp         wmain
            +59h (40B979h)         ;跳轉(zhuǎn)到default
                
            {
                
            case 0:
                    j 
            = 0;
            0040B969  mov         dword ptr [j],
            0 
                    
            break;                                    ;跳轉(zhuǎn)到結(jié)束
            0040B970  jmp         wmain
            +60h (40B980h) 
                
            case 1:
                    j 
            = 1;
            0040B972  mov         dword ptr [j],
            1 
                
            default:
                    j 
            = 3;
            0040B979  mov         dword ptr [j],
            3 
                }


                
            return 0;
            0040B980  xor         eax,eax 
            所以如果看到有多個(gè)連續(xù)的
            cmp
            je

            標(biāo)志著可能是swith語句


            訪問結(jié)構(gòu)體數(shù)組成員

            對(duì)于以下代碼:

            struct A 
            {
                
            int a;
                
            int b;
                
            int c;
            }
            ;

            int wmain(int argc, wchar_t* argv[])
            {
                A    ar[
            3];
                
            for (int i=0;i<3;++i)
                
            {
                    ar[i].a    
            = 0;
                    ar[i].b    
            = 0;
                    ar[i].c    
            = 0;
                }


                
            return 0;
            }

            for循環(huán)中所對(duì)應(yīng)的匯編為

              ar[i].a = 0;
            0040B956  mov      eax,dword ptr [i]  ;訪問第i個(gè)數(shù)據(jù)
            0040B959  imul     eax,eax,0Ch    ;0ch為結(jié)構(gòu)體的大小,這里得到訪問第i個(gè)機(jī)構(gòu)體的地址偏移
            0040B95C  mov      dword ptr ar[eax],0  ;取得第i個(gè)結(jié)構(gòu)體的第一個(gè)元素地址
              ar[i].b = 0;
            0040B964  mov      eax,dword ptr [i]
            0040B967  imul     eax,eax,0Ch
            0040B96A  mov      dword ptr [ebp+eax-24h],0
              ar[i].c = 0;
            0040B972  mov      eax,dword ptr [i]
            0040B975  imul     eax,eax,0Ch
            0040B978  mov      dword ptr [ebp+eax-20h],0

            對(duì)于結(jié)構(gòu)體數(shù)組的訪問有個(gè)很明顯的特征:使用imul取得某個(gè)數(shù)組元素的地址偏移,然后在加上所要訪問結(jié)構(gòu)體成員的地址偏移。同時(shí),大多數(shù)情況下結(jié)構(gòu)的的大小都是在編譯期決定的,imul的最后一個(gè)參數(shù)會(huì)是個(gè)常量。


            閱讀匯編代碼的一些技巧

            1.將指令分類:

                首先F(function)類指令:是函數(shù)調(diào)用相關(guān)代碼,這些代碼用于函數(shù)或者作為一個(gè)函數(shù)數(shù)被調(diào)用。幾乎凡是堆棧操作(備份集陳啟或者壓入?yún)?shù))可全部歸入此類。此外還有call指令、堆棧恢復(fù)。
                然后C(control)類指令    :設(shè)計(jì)判斷和跳轉(zhuǎn)指令,以及對(duì)循環(huán)變量操作的指令。這些代碼用于循環(huán)、判斷語句。
                剩余D(data)類指令:數(shù)據(jù)處理指令,應(yīng)該不包含函數(shù)調(diào)用,多半不含有堆操作,也不會(huì)含有跳轉(zhuǎn)。
            2.翻譯D類指令。
            3.表達(dá)式的合并與控制流程的結(jié)合。


            Reference:

            學(xué) Win32 匯編[29] - 串指令: MOVS*、CMPS*、SCAS*、LODS*、REP、REPE、REPNE 等

            《天書夜讀-從匯編語言到Windows內(nèi)核編程》

             

             

             


            posted on 2011-01-07 20:19 sonilics 閱讀(917) 評(píng)論(0)  編輯 收藏 引用 所屬分類: Debugging

            亚洲av成人无码久久精品| 久久99精品久久久久久不卡| 久久精品国产精品亚洲人人| 国产精品久久久久久搜索| 色综合久久久久久久久五月| 久久久久亚洲av综合波多野结衣 | 精品乱码久久久久久夜夜嗨| 国产一区二区三区久久精品| 国产精品久久久久久福利漫画| 久久国产精品成人影院| 国产成人久久AV免费| 精品国产VA久久久久久久冰| 久久精品午夜一区二区福利| 久久精品www人人爽人人| 精品九九久久国内精品| 狠狠精品干练久久久无码中文字幕| 中文精品久久久久国产网址| 国产精品久久久久一区二区三区| 久久精品国产精品亚洲人人| 青青草原综合久久大伊人导航| 久久只有这精品99| 久久夜色精品国产网站| 国产精品免费看久久久香蕉| 久久久久香蕉视频| 亚洲国产精品18久久久久久| 久久99精品国产一区二区三区| 久久国产精品无码网站| 久久精品人人做人人爽电影| 精品九九久久国内精品| 亚洲欧洲精品成人久久曰影片| 久久婷婷五月综合国产尤物app| 久久香蕉一级毛片| 香蕉99久久国产综合精品宅男自 | 国产一区二区精品久久| 亚洲人成无码网站久久99热国产 | 久久亚洲av无码精品浪潮| 久久精品国产AV一区二区三区| 精品国产福利久久久| 久久青青色综合| 久久精品国产精品亜洲毛片| 亚洲AV乱码久久精品蜜桃|