32位匯編第一講x86和8086的區別,以及OllyDbg調試器的使用


 

 

             32位匯編第一講x86和8086的區別,以及OllyDbg調試器的使用

一丶32位(x86也稱為80386)與8086(16位)匯編的區別

1.寄存器的改變

  AX 變為 EAX  可以這樣想,16位通用寄存器前邊都加個E開頭

例如:

  

EAX  EBX ECX EDX ESI EDI ESP EBP    ;八個寄存器
EIP EFLAGES                         ;特殊寄存器
CS ES SS DS GS FS            ;其中GS FS是新增加的寄存器,這些段寄存器,並不是4個字節(32位的)還是以前16位的

注意在32位下沒有分段的概念的,因為尋址能力是 0- FFFFFFFF  ,在當時的inter認為當初的4G已經很厲害了,那是后最好的內存才1G,放到現在看

我們感覺4G不夠用了,但也是近幾年才開始用的8G

有分區的概念,比如我們16位匯編中,給代碼分段的時候,順便分了一下區,分區是為了更好的管理代碼的編寫

2.地址有20根總線變為32根總線(也就是4G)

3.寄存器的數量沒有做改變

2.32位寄存器和16位寄存器的兼容

EAX 的低16位變為AX了,所以兼容的16位,其余的寄存器同理

32位中的段寄存器不是我們能操作的了,給操作系統使用,所以有了權限一說

在16位中,我們可以直接操作段寄存器分段,或者尋址,而這樣很不安全,萬一你分段的時候,正好在操作系統的代碼區,那么你可以修改代碼,那么操作系統就崩潰了

所以為了系統的穩定,操作系統不讓使用段寄存器了,而這些段寄存器操作系統都記錄了一些表的信息

二丶編寫32位中的匯編代碼

1.介紹

  在編寫32位匯編的時候,介紹一下編譯器和連接器,以前我們使用的匯編編譯器是可以編譯32位匯編的,但是連接器是不能連接32位匯編程序

所以link連接器需要改為32位的,如果有安裝過vc++6.0 那么是可以找到它的連接器的,我們使用它的連接器即可.

2.分區概念

  上面說了,操作系統不讓我們使用段寄存器,那么我們可以去分區,分為 常量區  全局數據區  代碼區 (沒有棧區,棧區由編譯器維護,編譯器分配)

首先介紹一下偽指令的用法(偽指令在16位匯編最后一講都講了,那么這節課就要調用偽指令去編寫匯編代碼了,還會增加偽指令去講解)

1.偽指令

      ①.model偽指令的使用

memorymodel: 表示你要設置的內存模式 這里我們設置平坦模式(表示內存是連續的,因為不能分段了)平坦模式 FLAT

[,langtype]調用約定: 如果這里寫了調用約定,那么以后我們使用 函數的偽指令(PROC)的時候,就不用指明調用約定

了而且win32可以調用操作系統API,而調用API的時候,這些API的調用約定,也是你這里給指定的

用法例子:

  

.386   ;這里表示我們要寫386的程序(也就是32位)匯編程序,指明一下,這個不是偽指令
.model FLAT,stdcall ;內存設置為平坦模式,默認調用約定stdcall

  ②偽指令PROTO(函數聲明)

函數聲明的偽指令,這個主要是針對我們自己寫的函數,如果調用的時候,函數正好在下面(他會從上面找,找不到報錯)所以聲明一下告訴它存在即可

例子:

  

;使用偽指令聲明
My_ADD PROTO n1:dword,n2:dword

;調用
invoke My_Add ,1,2  ;函數實現在下面,如果不寫聲明告訴存在,就會調用出錯
My_ADD PROC n1:dword,n2:dword ;定義了一個函數,參數是n1,n2,指明的大小是DWORD(4個字節的),這里沒有寫調用約定,上面寫了默認的調用約定了

My_ADD endp  ;函數定義的結束標志

  ③偽指令 option(選項的偽指令)

這個偽指令主要是增加額外選項,比如上面我們調用函數,匯編不區分大小寫,你這樣寫是可以調用的,但是為了

不必要的麻煩,我們加上一個選項,也就是大小寫敏感,也就是區分大小寫,這樣我們調用系統API的時候就不用怕出錯了

使用例子:

  

option casemap:none  ;使用大小寫敏感的選項

   ④定義常量去的偽指令(.const)

上面說了,內存有了保護模式,分為了 可讀可寫可執行,如果是常量去,那么只能讀,不能寫,不能執行

語法:

  

這個比較簡單了

使用例子:

  

.const ;定義常量區
    g_szTitle db "Hello"  ;在常量區中定義常量字符串

   ⑤數據區的定義(.data)

數據區,專門定義數據使用的,是可讀可寫的

語法:

它分為兩種,一種是初始化的數據區,一種是未初始化的數據區

初始化數據區的寫法:

  

.data ;定義數據區
      ....;你自己的數據 

未初始化的數據區寫法

.data ?;加?號表示未初始化
    g_szData dw ? ;數據的申請必須是? 也就是未初始化的

兩者的區別

  初始化的數據,不過你定義數據的時候,是否給? 都會寫的EXE(PE文件中)

  未初始化的數據, 定義數據的時候只能給? 不在PE文件中保存

  ⑥代碼區的偽指令(.code)

定義執行的代碼區

語法:

例子:

  

.code
START:     ;代碼開始執行的標號

end START; end表示文件結束START表示要從START開始執行代碼

 

  ⑦多文件編譯ASM(#include 后綴名.inc)

我們有時候會想,代碼不可能一個文件寫完,比如多個文件聯合編譯,所以就有了.inc文件

一般我們定義數據區,或者定義的宏都放在.inc的文件中

然后ASM文件使用include xxxx.inc 包含你自己的.inc文件即可

3.一段完整的win32匯編代碼框架

上面的偽指令已經講完了,這里寫一段完整的匯編代碼

.386                                ;定義為386的匯編程序
.model FLAT,stdcall                ;內存為平坦模式,默認調用約定stdcall
option casemap:none             ;增加選項,區分大小寫

.const                              ;定義常量區(這些應該放到.inc文件中這里不妨了,放的話就是拷貝過去,然后這個文件引用即可)

    g_szTitle db "Title",0        ;win32字符串結尾都是0結尾了
    g_szMsg  db "Hello 51asm.com",0

.data                               ;定義數據區
 
.code                               ;定義代碼區
START:
    .....                ;你的核心代碼
end START

三丶編譯連接Win32匯編程序

在32位中,編譯匯編程序和連接匯編程序就有點不同了

1.編譯:

在CMD中輸入

ml /c  /coff 文件名.asm

 上面說過,我們在32位下,有了PE文件格式(exe文件),而PE文件格式是 COFF格式,也稱作為PE

編譯幫助:

表示我們要編譯為一個PE的obj格式

編譯我們的代碼

然后出現這個,表示編譯成功,看下obj文件

如果我們不加,就會編譯成了16位的了,而連接的時候就會找16位的連接器,就會出錯,顯示找不到入口點的

錯誤

2.連接

連接的時候,不能在使用16位的連接器了,這里可以使用VC自帶的link,沒有沒有關系,我會在每天的資料中上傳所用的工具

連接選項(對我們有用的)

這個對我們有用,因為在32系統下,有了窗口的概念的,表示你要連接成什么程序,控制台的還是窗口的

假設我們要連接為一個控制台的程序

link /subsystem:console 文件名.obj  ;連接成一個控制台的程序

代碼沒有出錯,則正常顯示

 四丶寫一個窗口版本探彈消息的程序,並用OllyDbg去分析

1.編寫窗口程序

我們基於上面的32位程序的框架,寫一個簡單版本的信息框,彈出一個消息,把我們常量區的數據彈出來

並用OlleyDbg去分析

首先查一下MessageBox的用法

我們知道了,第一個參數是窗口句柄,沒有我們可以給NULL 而NULL 在匯編中沒有,我們就用宏定義 (EQU)

第二個參數是一個0結尾字符串的首地址,那么在匯編中可以通過 offset偽指令,把常量區的地址給它

第三個參數一樣

第四個參數是顯示彈框的按鈕風格,我們一般使用MB_OK,而MB_OK 是0,匯編中也沒有,所以我們定義一下

匯編代碼例子:

.386
.model FLAT,stdcall  ;設置內存為平坦模式,默認調用約定STDCALL
option casemap:none     ;區分大小寫

NULL EQU 0      ;定義NULL
MB_OK EQU 0     ;定義為0
MessageBoxA PROTO hWnd:DWORD, :DWORD,:DWORD,:DWORD    ;函數聲明,聲明為有4個參數,默認調用約定是Stdcall
.const
    g_szTitle db "Title",0
    g_szMsg   db  "Hello www.w1x8.com ",0

.data

.code
START:
    
    invoke MessageBoxA,NULL, offset g_szMsg,offset g_szTitle,MB_OK;調用API
end START

這里使用的是MessageBoxA,因為操作系統分為寬字節和Ascii碼版本

這里編譯的時候命令還是上面的那個命令,(ml /c /coff 文件名.obj)

連接的時候不一樣了

連接的時候我們需要鏈接為Windows窗口程序,而且最重要的一點就是MessageBoxA的實現代碼在User32.lib中,所以也要一並的加入進來

link /subsystem:windows 文件名.obj  user32.lib ;注意,user32.lib放到匯編程序所在的目錄下

看下編譯出來的程序

2.使用OllyDbg分析

把我們的exe放到OllyDbg中分析

這里先說下常用的快捷鍵

F2      : 設置/取消斷點
F3      : 加載文件
F4      : 運行到選中的位置
F5      : 縮小/還原窗口
F7      : 單步步入
F8      : 單步步過
F9      : 運行程序
F10     : 彈出右鍵菜單
F12     : 使正在執行的程序暫停
CTRL+F2 : 重新載入文件
CTRL+F8 : 以指令為單位逐條自動執行
CTRL+F9 : 執行到當前函數的return處
CTRL+F11: 跟蹤進入
CTRL+F12: 跟蹤跳過
CTRL+G  : 跳到某地址處
CTRL+B  : 查找二進制字串
CTRL+N  : 查看當前模塊中的名稱
CTRL+K  : 查看調用樹
CTRL+E  : 編輯選中行的二進制數據
CTRL+減 : 轉到上一個函數過程處
CTRL+加 : 轉到下一個函數過程處
ALT+F2  : 關閉已加載的文件
ALT+F9  : 執行到到用戶空間代碼
ALT+B   : 查看斷點
ALT+E   : 查看已加載的可執行模塊
ALT+Q   : 關閉並退出OD調試器
分號    : 加注釋
冒號    : 加標簽
空格    : 激活/禁用斷點;匯編選中行
-/+     : 回/前看執行過的指令
今天我們用到的是 F7  F8 Ctrl + F2的指令
載入我們的EXE文件

可以看到我們的匯編代碼都在這里,我們F8單步執行,找到第一個Call,也就是MessageBoxA,F8走到Call的地方

F7進入

然后看下,他也是一樣壓棧ebp,出棧ebp,然后看下棧區,

看下EBP的位置(這里的EBP是執指向棧頂的,因為我們 mov ebp,esp了)

然后棧的格式和我們前邊講的是一樣的

棧的當前結構:

 

保存棧底的值(ebp)

返回地址  

參數一

參數二

參數三

參數四

3.使用OD把我們的標題修改了成輸出的消息,把以前的標題,修改為輸出的消息(有點繞,就是兩個互換輸出)

思路:

  我們把壓棧的順序修改一下

雙擊,把當前的壓棧的順序修改一下

push 1.00402008  修改為: push 1.0040200E
push 1.0040200E  修改為: push 1.00402008

 

然后選擇這兩行,右鍵 -> 復制到可執行文件 然后選擇 選擇所有復制(相當於修改后的EXE)

最后彈出了個新的,我們點擊保存文件即可

修改后的EXE

五丶關於PE文件的那點事

 

 上面說了我們的信息會保存在exe文件中(也就是PE)我們用WinHex(16進制編輯器)查看一下

1.32位執行的開始

我們的EXE在這里上面的位置,都是為了兼容16位的,而真正的32位程序是從PE這里開始執行的,

上面的某些字段保存了PE所在的偏移,比如PE所在的位置是C8,那么上面的字段就會有C8保存,因為軟件已啟動

會根據這個偏移尋找PE文件的位置,這里C8位置在3C的位置

那么就代表我們不改變這個值,其余的隨便修改,那么不影響32位程序的使用,我們修改一下

修改后還是能運行的

 

這個匯編程序會崩潰,原因是我們沒有寫退出,比如16位匯編中的退出是 

mov ah,4c00h
int 21h

這里就不寫了

2.32匯編中簡單的Dll劫持和API HOOK(思想)

注入方法很多,這里有個簡單的,比如我們上面調用了一個MessageBoxA

他是在Lib中尋找dll的路徑,以及MessageBoxA在那個Dll中

我們使用的這個Dll是動態的Dll,里面記錄了Dll所在的路徑,以及導出函數

而我們匯編中剛在這樣用則是把user32.lib中當前調用的MessageBoxA所在的Dll路徑,以及Dll導出函數的信息

連接到EXE文件中

所以說EXE文件中也會保存Dll的信息

我們使用WinHex查找一下EXE中是否有MessageBoxA

CTRL + F 查找,輸入字符串

找到了所在的位置,我們把USER32.DLL改下名

 

 

 

可以看到,他找不到AAER32.dll,如果厲害的自己可以寫一個AAER32.DLL,(當然細節很多,這里只是簡單的思想)

我們就可以把DLL劫持了

比如我們把前邊的函數名字修改了,那么如果你厲害,可以寫個相同函數,就形成了APIHOOK

 

課堂資料下載地址:

 當前第一課課程資料: 鏈接:http://pan.baidu.com/s/1geLWBzP 密碼:2ko2

當前32位匯編所有課程資料:  鏈接:http://pan.baidu.com/s/1geC3iNL 密碼:0hpc


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM