乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      VS2008查看匯編代碼

       云將東游 2014-08-13
      了解反匯編的一些小知識對于我們在開發(fā)軟件時進行編程與調試大有好處,下面以VS2008環(huán)境下的VC++簡單介紹一下反匯編的一些小東西!如果有些解釋有問題的地方,希望大家能夠指出。
      1、新建簡單的VC控制臺應用程序(對此熟悉的同學可以略過)
      A、打開Microsoft Visual Studio 2008,選擇主菜單“File”
      B、選擇子菜單“New”下面的“Project”,打開“New Project”對話框。
      C、左邊選擇Visual C++下的win32,右邊選擇Win32 Console Application,然后輸入一個工程名,點擊“OK”即可,在出現的向導中,一切默認,點擊Finish即可。
      D、在出現的編輯區(qū)域內會出現以你設定的工程名命名的CPP文件。內容如下:
            #include "stdafx.h"
            int _tmain(int argc, _TCHAR* argv)
            {
                  return 0;
            }
      2、VS查看匯編代碼
      A、VC處于調試狀態(tài)才能看到匯編指令窗口。因此,可以在 return 0 上設置一個斷點:把光標移到 return 0 那一行上,然后按下F9鍵設置一個斷點。
      B、按下F5鍵進入調試狀態(tài),當程序停在 return 0 這一行上時,打開菜單“Debug”下的“Windows”子菜單,選擇“Disassembly”。這樣,出現一個反匯編的窗口,顯示下面的信息:
      --- d:/my documents/visual studio 2008/projects/casmtest/casmtest/casmtest_main.cpp
      // CAsmTest.cpp : 定義控制臺應用程序的入口點。
      //
      #include "stdafx.h"
      int _tmain(int argc, _TCHAR* argv)
      {
      00411370  push        ebp  
      00411371  mov         ebp,esp
      00411373  sub         esp,0C0h
      00411379  push        ebx  
      0041137A  push        esi  
      0041137B  push        edi  
      0041137C  lea         edi,
      00411382  mov         ecx,30h
      00411387  mov         eax,0CCCCCCCCh
      0041138C  rep stos    dword ptr es:
      return 0;
      0041138E  xor         eax,eax
      }
      00411390  pop         edi  
      00411391  pop         esi  
      00411392  pop         ebx  
      00411393  mov         esp,ebp
      00411395  pop         ebp  
      00411396  ret   
      上面就是系統(tǒng)生成的main函數原型,確切的說是_tmain()的反匯編的相關信息,相信學過匯編語言的肯定就能夠了解它所做的操作了。
      3、簡單了解一下常見的匯編指令
      為了照顧到沒學過匯編程序的同志們,這里簡單介紹一下常見的幾種匯編指令。
      A、add:加法指令,第一個是目標操作數,第二個是源操作數,格式為:目標操作數 = 目標操作數 + 源操作數。
      B、sub:減法指令,格式同 add。
      C、call:調用函數,一般函數的參數放在寄存器中。
      D、ret:跳轉會調用函數的地方。對應于call,返回到對應的call調用的下一條指令,若有返回值,則放入eax中。
      E、push:把一個32位的操作數壓入堆棧中,這個操作在32位機中會使得esp被減4(字節(jié)),esp通常是指向棧頂的(這里要指出的是:學過單片機的同學請注意單片機種的堆棧與Windows下的堆棧是不同的,請參考相應資料),這里頂部是地址小的區(qū)域,那么,壓入堆棧的數據越多,esp也就越來越小。
      F、pop:與push相反,esp每次加4(字節(jié)),一個數據出棧。pop的參數一般是一個寄存器,棧頂的數據被彈出到這個寄存器中。
      一般不會把sub、add這樣的算術指令,以及call、ret這樣的跳轉指令歸入堆棧相關指令中。但是實際上在函數參數傳遞過程中,sub和add最常用來操作堆棧;call和ret對堆棧也有影響。
      G、mov:數據傳送。第一個參數是目的操作數,第二個參數是源操作數,就是把源操作數拷貝到目的一份。
      H、xor:異或指令,這本身是一個邏輯運算指令,但在匯編指令中通常會見到它被用來實現清零功能。用 xor eax,eax這種操作來實現 mov eax,0,可以使速度更快,占用字節(jié)數更少。
      I、lea:取得第二個參數地址后放入到前面的寄存器(第一個參數)中。
      然而lea也同樣可以實現mov的操作,例如:
                                        lea edi,
      方括號表示存儲單元,也就是提取方括號中的數據所指向的內容,然而lea提取內容的地址,這樣就實現了把(ebx-0ch)放入到了edi中,但是mov指令是不支持第二個操作數是一個寄存器減去一個數值的。
      J、stos:串行存儲指令,它實現把eax中的數據放入到edi所指的地址中,同時edi后移4個字節(jié),這里的stos實際上對應的是stosd,其他的還有stosb,stosw分別對應1,2個字節(jié)。
      K、jmp:無條件跳轉指令,對應于大量的條件跳轉指令。
      L、jg:條件跳轉,大于時成立,進行跳轉,通常條件跳轉之前會有一條比較指令(用于設置標志位)。
      M、jl:小于時跳轉。
      N、jge:大于等于時跳轉。
      O、cmp:比較大小指令,結果用來設置標志位。
      4、函數參數傳遞方式
      函數調用規(guī)則指的是調用者和被調用函數間傳遞參數及返回參數的方法,在Windows上,常用的有Pascal方式、WINAPI方式(_stdcall)、C方式(_cdecl)。
      A、_cdecl C調用規(guī)則:
      (a)參數從右到左進入堆棧;
      (b)在函數返回后,調用者要負責清除堆棧,這種調用方式通常會生成較大的可執(zhí)行程序。
      B、_stdcall又稱為WINAPI,調用規(guī)則如下:
      (a)參數從右到左進入堆棧;
      (b)被調用的函數在返回前自行清理堆棧,這種方式生成的代碼比cdecl小。
      C、Pascal調用規(guī)則(主要用于Win16函數庫中,現在基本不用):
      (a)參數從左到右進入堆棧;
      (b)被調用的函數在返回前自行清理堆棧。
      (c)不支持可變參數的函數調用。
      5、VC中訪問無效變量出錯原因
      我們看上面主函數反匯編后的其中一段代碼如下:
      0041137C  lea         edi,
      00411382  mov         ecx,30h
      00411387  mov         eax,0CCCCCCCCh
      0041138C  rep stos    dword ptr es:
      從代碼的表面上看,它是實現把從ebp-0C0h開始的30h個字的空間寫入0CCCCCCCCh。其中eax為四位的數據,這樣可以計算:
                            0C0h = 30h * 4
      也就是把從ebp-0C0h 到ebp之間的空間初始化為0CCCCCCCCh。大家在學習反匯編的過程中會發(fā)現,其實編譯器會根據情況把相應長度的這樣一段作為局部變量的空間,而這里把局部變量區(qū)域全都初始化成0CCCCCCCCh也是有其用意的,做VC編程的工作者,特別是初學者可能不會對0CCCCCCCCh這個常量陌生。0cch實際上是int 3指令的機器碼,這是一個斷點中斷指令(在反編譯出的信息中大家會看到int 3),因為局部變量不可被執(zhí)行,或者如果在沒有初始化的時候進行了訪問,則就會出現訪問失敗錯誤。這個在VC編譯Debug版本中才能看到提示這個錯誤,在Release版本中,會以另外一種錯誤形式體現。下面,我們修改主程序看下new與delete的反匯編的效果(注釋直接加到反匯編的代碼中了)。
      VC生成工程,寫入源代碼如下:
      (1)情況1
      // ASM_Test.cpp : Defines the entry point for the console application.                    (  源代碼1 )
      //
      #include "stdafx.h"
      #include "stdlib.h"
      int _tmain(int argc, _TCHAR* argv)
      {
          int *pTest = new int(3);                //定義一個整型指針,并初始化為 3
          printf( "*pTest = %d/r/n", *pTest );    //調用庫函數printf輸出數據
          delete pTest;                            //刪除這個指針
          return 0;
      }
      這里僅僅看下在new與delete進行空間管理時進行反匯編時可能出現的一些情況,我們把上面源代碼稱為源代碼(1),我們按照前面講解的查看VS下反匯編的方法可以看到對應于上面代碼的反匯編代碼如下:
      --- f:/mysource/asm_test/asm_test/asm_test.cpp ---------------------------------                      ( 反匯編代碼 1)
      // ASM_Test.cpp : Defines the entry point for the console application.
      //
      #include "stdafx.h"
      #include "stdlib.h"
      int _tmain(int argc, _TCHAR* argv)
      {
      ;(1)函數預處理部分
      004113C0  push        ebp  
      004113C1  mov         ebp,esp ;保存堆棧的棧頂位置
      004113C3  sub         esp,0E8h ;要置為0CCCCCCCCh 保留變量空間長度
      004113C9  push        ebx       ;保存寄存器ebx、esi、edi
      004113CA  push        esi  
      004113CB  push        edi  
      004113CC  lea         edi,    ;提出要置為0CCCCCCCCh 的空間起始地址
      004113D2  mov         ecx,3Ah      ;要置為0CCCCCCCCh 的個數,每個占4個字節(jié)
      004113D7  mov         eax,0CCCCCCCCh  ;于是3Ah * 4 = 0E8h
      004113DC  rep stos    dword ptr es:  ;進行置為0CCCCCCCCh操作
      ;(2)定義一個int 型指針,分配空間后,并初始化為 3 ,
          int *pTest = new int(3);                //定義一個整型指針,并初始化為 3
      004113DE  push        4    ;要分配的空間長度,會根據定義的數據類型而不同
      004113E0  call        operator new (411186h)   ;分配空間,并把分配空間的起始地址放入eax中
      004113E5  add         esp,4    ;由于new與delete函數本身沒有對棧進行彈出操作,所以,要編寫者自己處理
      004113E8  mov         dword ptr ,eax  ;比較分配的空間是否為0,如果為0
      004113EE  cmp         dword ptr ,0
      004113F5  je          wmain+51h (411411h)
      004113F7  mov         eax,dword ptr       ;對于分配的地址分配空間進行賦值為:3
      004113FD  mov         dword ptr ,3
      00411403  mov         ecx,dword ptr  
      00411409  mov         dword ptr ,ecx   ;似乎用和作為了中間存儲單元
      0041140F  jmp         wmain+5Bh (41141Bh)
      00411411  mov         dword ptr ,0     ;上面分配空間失敗是的操作
      0041141B  mov         edx,dword ptr  
      00411421  mov         dword ptr ,edx           ;數據最后送入pTest變量中
      ;調用printf函數進行數據輸出
          printf( "*pTest = %d/r/n", *pTest );    //調用庫函數printf輸出數據
      00411424  mov         esi,esp   ;用于調用printf后的Esp檢測,不明白編譯器為什么這樣做
      00411426  mov         eax,dword ptr    ;提取要打印的數據,先是地址,下面一條是提取具體數據
      00411429  mov         ecx,dword ptr  
      0041142B  push        ecx         ;兩個參數入棧
      0041142C  push        offset string "*pTest = %d/r/n" (41573Ch)
      00411431  call        dword ptr       ;調用函數
      00411437  add         esp,8         ;由于庫函數無出棧管理操作,同new與delete,所以要加 8,進行堆棧處理
      0041143A  cmp         esi,esp        ;對堆棧的棧頂進行測試
      0041143C  call        @ILT+325(__RTC_CheckEsp) (41114Ah)
      ;進行指針變量的清理工作
          delete pTest;                            //刪除這個指針
      00411441  mov         eax,dword ptr    ; 中放入的是分配的地址,下面幾條指令轉悠一圈
      00411444  mov         dword ptr ,eax   ;就是要把要清理的地址送入堆棧,然后調用delete函數
      0041144A  mov         ecx,dword ptr  
      00411450  push        ecx  
      00411451  call        operator delete (411091h)
      00411456  add         esp,4     ;對堆棧進行處理,同new與printf函數
      ;函數結束后,進行最終的清理工作
          return 0;
      00411459  xor         eax,eax   ;做相應的清理工作,堆棧中保存的變量送回原寄存器
      }
      0041145B  pop         edi  
      0041145C  pop         esi  
      0041145D  pop         ebx  
      0041145E  add         esp,0E8h       ;進行堆棧的棧頂判斷
      00411464  cmp         ebp,esp
      00411466  call        @ILT+325(__RTC_CheckEsp) (41114Ah)
      0041146B  mov         esp,ebp
      0041146D  pop         ebp  
      0041146E  ret  
      --- No source file -------------------------------------------------------------;后面不再是源代碼
      在列出反匯編程序時把反匯編代碼的上下的分解注釋也列了出來,親手去查看的朋友可能會發(fā)現在這段代碼的之外的其他部分會有大量的int 3匯編中的中斷指令,這個是與上面的所說的0CCCCCCCCh具有一致性,這些區(qū)域是無效區(qū)域,但代碼訪問這些區(qū)域時就會出現非法訪問提示。當然,你應該可以想到,那個提示是可以被屏蔽掉的,你可以把這部分區(qū)域填充上數據或者修改 iint 3 調用的中斷程序。
      從以上反匯編程序,我們可以發(fā)現幾點:
      A、一些內部的庫函數是不會對堆棧進行出棧管理的,所以若要對反匯編程序進行操作時,一點要注意這一點
      B、編譯器會自動的加上一些對棧頂的檢查工作,這個是我們在做VC調試時經常遇到的一個問題,就是堆棧錯誤
      當然以上只是對debug版本下的程序進行反匯編,如果為release 版本,代碼就會進行大量的優(yōu)化,在理解時會有一定的難度,有興趣朋友可以試著反匯編一下,推薦大家有IDA返回工具,感覺挺好用的。

        本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯系方式、誘導購買等信息,謹防詐騙。如發(fā)現有害或侵權內容,請點擊一鍵舉報。
        轉藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多