AX 變爲 EAX 能夠這樣想,16位通用寄存器前邊都加個E開頭c++
例如:編程
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,放到如今看windows
咱們感受4G不夠用了,但也是近幾年纔開始用的8G安全
有分區的概念,好比咱們16位彙編中,給代碼分段的時候,順便分了一下區,分區是爲了更好的管理代碼的編寫框架
EAX 的低16位變爲AX了,因此兼容的16位,其他的寄存器同理編輯器
32位中的段寄存器不是咱們能操做的了,給操做系統使用,因此有了權限一說函數
在16位中,咱們能夠直接操做段寄存器分段,或者尋址,而這樣很不安全,萬一你分段的時候,正好在操做系統的代碼區,那麼你能夠修改代碼,那麼操做系統就崩潰了工具
因此爲了系統的穩定,操做系統不讓使用段寄存器了,而這些段寄存器操做系統都記錄了一些表的信息spa
在編寫32位彙編的時候,介紹一下編譯器和鏈接器,之前咱們使用的彙編編譯器是能夠編譯32位彙編的,可是鏈接器是不能鏈接32位彙編程序操作系統
因此link鏈接器須要改成32位的,若是有安裝過vc++6.0 那麼是能夠找到它的鏈接器的,咱們使用它的鏈接器便可.
上面說了,操做系統不讓咱們使用段寄存器,那麼咱們能夠去分區,分爲 常量區 全局數據區 代碼區 (沒有棧區,棧區由編譯器維護,編譯器分配)
首先介紹一下僞指令的用法(僞指令在16位彙編最後一講都講了,那麼這節課就要調用僞指令去編寫彙編代碼了,還會增長僞指令去講解)
memorymodel: 表示你要設置的內存模式 這裏咱們設置平坦模式(表示內存是連續的,由於不能分段了)平坦模式 FLAT
[,langtype]調用約定: 若是這裏寫了調用約定,那麼之後咱們使用 函數的僞指令(PROC)的時候,就不用指明調用約定
了並且win32能夠調用操做系統API,而調用API的時候,這些API的調用約定,也是你這裏給指定的
用法例子:
.386 ;這裏表示咱們要寫386的程序(也就是32位)彙編程序,指明一下,這個不是僞指令 .model FLAT,stdcall ;內存設置爲平坦模式,默認調用約定stdcall
函數聲明的僞指令,這個主要是針對咱們本身寫的函數,若是調用的時候,函數正好在下面(他會從上面找,找不到報錯)因此聲明一下告訴它存在便可
例子:
;使用僞指令聲明 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 ;函數定義的結束標誌
這個僞指令主要是增長額外選項,好比上面咱們調用函數,彙編不區分大小寫,你這樣寫是能夠調用的,可是爲了
沒必要要的麻煩,咱們加上一個選項,也就是大小寫敏感,也就是區分大小寫,這樣咱們調用系統API的時候就不用怕出錯了
使用例子:
option casemap:none ;使用大小寫敏感的選項
上面說了,內存有了保護模式,分爲了 可讀可寫可執行,若是是常量去,那麼只能讀,不能寫,不能執行
語法:
這個比較簡單了
使用例子:
.const ;定義常量區 g_szTitle db "Hello" ;在常量區中定義常量字符串
數據區,專門定義數據使用的,是可讀可寫的
語法:
它分爲兩種,一種是初始化的數據區,一種是未初始化的數據區
初始化數據區的寫法:
.data ;定義數據區 ....;你本身的數據
未初始化的數據區寫法
.data ?;加?號表示未初始化 g_szData dw ? ;數據的申請必須是? 也就是未初始化的
二者的區別
初始化的數據,不過你定義數據的時候,是否給? 都會寫的EXE(PE文件中)
未初始化的數據, 定義數據的時候只能給? 不在PE文件中保存
定義執行的代碼區
語法:
例子:
.code START: ;代碼開始執行的標號 end START; end表示文件結束START表示要從START開始執行代碼
咱們有時候會想,代碼不可能一個文件寫完,好比多個文件聯合編譯,因此就有了.inc文件
通常咱們定義數據區,或者定義的宏都放在.inc的文件中
而後ASM文件使用include xxxx.inc 包含你本身的.inc文件便可
上面的僞指令已經講完了,這裏寫一段完整的彙編代碼
.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
在32位中,編譯彙編程序和鏈接彙編程序就有點不一樣了
在CMD中輸入
ml /c /coff 文件名.asm
上面說過,咱們在32位下,有了PE文件格式(exe文件),而PE文件格式是 COFF格式,也稱做爲PE
編譯幫助:
表示咱們要編譯爲一個PE的obj格式
編譯咱們的代碼
而後出現這個,表示編譯成功,看下obj文件
若是咱們不加,就會編譯成了16位的了,而鏈接的時候就會找16位的鏈接器,就會出錯,顯示找不到入口點的
錯誤
鏈接的時候,不能在使用16位的鏈接器了,這裏可使用VC自帶的link,沒有沒有關係,我會在天天的資料中上傳所用的工具
鏈接選項(對咱們有用的)
這個對咱們有用,由於在32系統下,有了窗口的概念的,表示你要鏈接成什麼程序,控制檯的仍是窗口的
假設咱們要鏈接爲一個控制檯的程序
link /subsystem:console 文件名.obj ;鏈接成一個控制檯的程序
代碼沒有出錯,則正常顯示
咱們基於上面的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放到彙編程序所在的目錄下
看下編譯出來的程序
把咱們的exe放到OllyDbg中分析
這裏先說下經常使用的快捷鍵
能夠看到咱們的彙編代碼都在這裏,咱們F8單步執行,找到第一個Call,也就是MessageBoxA,F8走到Call的地方
F7進入
而後看下,他也是同樣壓棧ebp,出棧ebp,而後看下棧區,
看下EBP的位置(這裏的EBP是執指向棧頂的,由於咱們 mov ebp,esp了)
而後棧的格式和咱們前邊講的是同樣的
棧的當前結構:
保存棧底的值(ebp)
返回地址
參數一
參數二
參數三
參數四
思路:
咱們把壓棧的順序修改一下
雙擊,把當前的壓棧的順序修改一下
push 1.00402008 修改成: push 1.0040200E push 1.0040200E 修改成: push 1.00402008
而後選擇這兩行,右鍵 -> 複製到可執行文件 而後選擇 選擇全部複製(至關於修改後的EXE)
最後彈出了個新的,咱們點擊保存文件便可
修改後的EXE
上面說了咱們的信息會保存在exe文件中(也就是PE)咱們用WinHex(16進制編輯器)查看一下
咱們的EXE在這裏上面的位置,都是爲了兼容16位的,而真正的32位程序是從PE這裏開始執行的,
上面的某些字段保存了PE所在的偏移,好比PE所在的位置是C8,那麼上面的字段就會有C8保存,由於軟件已啓動
會根據這個偏移尋找PE文件的位置,這裏C8位置在3C的位置
那麼就表明咱們不改變這個值,其他的隨便修改,那麼不影響32位程序的使用,咱們修改一下
修改後仍是能運行的
這個彙編程序會崩潰,緣由是咱們沒有寫退出,好比16位彙編中的退出是
mov ah,4c00h int 21h
這裏就不寫了
注入方法不少,這裏有個簡單的,好比咱們上面調用了一個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