逆向工程实验
逆向工程實驗
- 1、PE頭及導入表應用
- 2、PE導出表分析及應用
- 3、應用軟件破解
- 4、殼應用
1、PE頭及導入表應用
1、PE可執行文件分析
1.1開發一個源程序 HelloWorld .asm,顯示hello world。
2、調試軟件OllyDBG
問題 2.1、利用OD軟件調試PE文件。
從OD反匯編的結果分析,invoke MessageBox,NULL,offset szText,NULL,MB_OK分解成哪幾個指令?
答:
PUSH 0
PUSH 0
PUSH OFFSET 00403000
PUSH 0
CALL <JMP.&user32.MessageBoxA>
問題 2.2:怎么理解E8 08000000?
答:E8調試CALL指令,E8后跟著偏移地址,高位先讀:0000 0008,CALL指令把它的下一條指令壓棧,00401010 + 00000008 = 00401018
問題 2.3:F7單步步入和F8單步步過 有什么不同?
答:單步步入遇到子程序時,會跳轉到子程序內部執行;單步步過遇到子程序時,將該調用當成一條指令執行,并不進入子程序內部。
2.2、修改EXE文件字節碼
將messagebox的 HelloWorld 修改成 GoodNight,顯示結果。
答:
問題 2.4:修改是從文件偏移的什么地方開始的(FOA和VA、RVA分別的多少)?
答:FOA的800偏移
基址:00400000
RVA的3000偏移
VA:00403000
3、調試軟件W32DASM
利用W32DASM查看HelloWorld.EXE的輸出。
問題3.1:該函數用到哪幾個DLL,分別用到哪幾個函數?
答:兩個DLL:user32.dll、kernel32.dll
兩個函數:MessageBoxA、ExitProcess
4、FlexHex 或 Winhex
熟悉十六進制編輯軟件的使用。
問題4.1:如何初步判斷一個文件是PE文件?
答:用Winhex打開文件,從文件頭4D 5A(MZ)開始跳轉3C,讀取到數據0000 00B0,再次跳轉到0000 00B0,若該地址為50 45 即為PE文件
5、利用PEditor查看Hellworld,讀出其ImageBase的值,并畫出節表(截圖)。
問題5.1:畫出節表。
答:ImageBase:0x00400000
問題5.2:某變量的FOA為410H,試分析其位于哪一節(給出分析過程。)?該變量的RVA為多少(給出計算過程)?
答:位于.text:410H 410H<600H
RVA的1010偏移:1000H + 410H -400H = 1010H
6、如何判斷一個文件是否是PE文件?
答:用Winhex打開文件,從文件頭4D 5A(MZ)開始跳轉3C,讀取到數據0000 00B0,再次跳轉到0000 00B0,若該地址為50 45 即為PE文件
7、查閱資料,簡述病毒獲取Kernel32模塊基地址的重要性。
答:一般初始化PE文件的時候,ntdll.dll, kernel32.dll是隨進程以及線程初始化時候加載的。所以即使程序中我們不引入任何輸入表結構,這兩個DLL在我們程序進程以及線程初始化時也必須加載。獲得kernel32.dll的基地址后,就可以獲得LoadLibray函數來繼續加載其他的動態鏈接庫,然后再通過我們的GetProcAdress函數來獲得相應需要的api函數地址,這樣也就做到了可移植性的要求。
8、導入表結構分析。
問題8.1:利用PEditor打開firstwindow.exe,分析該PE的導入表。該PE文件描述導入表的數據目錄項的偏移是多少?導入表的VA和大小分別是多少?該EXE用到多少個DLL文件。驗證與PEditor中查看到的是否一致?
答:導入表的數據目錄項的偏移是:80H
導入表的VA和大小分別是:00402084,50H(RVA:2084.FOA:684)
EXE用到3個DLL文件:
問題8.2:理解PE文件的雙橋結構,特別是從靜態到動態橋2發生的變化。下圖為導入表描述符的數據結構。僅填寫與Winresult.DLL相關的信息(靜態、動態兩個圖)
2、PE導出表分析及應用
問題1、利用Winhex查看Winresult.DLL 并分析其提供函數的名字及對應入口地址。畫出導出表結構圖。
答:
從PE文件頭跳轉78可以的找到該文件的RVA = 2140h
由下圖可知,2140在2000-3000之間,所以原始偏移 = 800h
即FOA = (2140h-2000h) + 800h = 940h
在WinHex跳轉到940h可以找到:
根據上圖畫出導出表:
問題2、pedtior打開本機的kernel32.DLL,其導出表RVA?導出表大小?找到無導入表情況下需要的兩個函數的名稱及其入口地址。
答:
導出表RVA:00 09 2D 30
導出表大小:00 00 DC 14H = 56340
LoadLibray()函數來繼續加載其他的動態鏈接庫,
GetProcAdress()函數來獲得相應需要的api函數地址,
這樣也就做到了可移植性的要求。
LoadLibray:
GetProcAddress:
問題3、實現兩種方式的導出函數覆蓋-1
修改winResult.dll導出結構中的函數入口地址,達到firstwindow.EXE以動畫方式打開的效果。描述你所做的工作。
答:
交換FadeInOpen和AnimateOpen函數的入口地址
問題4、實現兩種方式的導出函數覆蓋-2
覆蓋fadeinopen函數的指令代碼:使得運行firstwindow.EXE程序時會彈出messagebox。如下圖所示:
步驟:
FadeInOpen函數的FOA = (1282h-1000h) + 400h = 682h
可以找到:
修改文件:
用OD打開其他導入的文件查看messageboxA的地址:
通過messagebox找到函數入口地址:77 47 36 70
根據《WinPE權威指南》來完成修改:
其中,將EA 07 D5 77 替換成自己的函數入口地址77 47 36 70:
保存后運行:
3、應用軟件破解
1、U盤監控器注冊破解
U 盤監控器需要注冊才能使用全部功能,我們的任務是使得輸入任何注冊碼均能注冊成功 。通常在注冊時,程序會讀取注冊碼,然后對注冊碼進行判 斷: 正確則顯示注冊成功,轉到正常的程序運行狀態:錯誤則顯示注冊失敗 ,轉到未注冊運行狀態。
1.1、運行軟件,獲得與破解有關的信息;
打開USB監控器獲取注冊失敗關鍵詞:
1.2、尋找注冊失敗字符串地址;
用WinHex打開USB監控器查找到注冊失敗
獲取到文件偏移地址:0x81A79
基址:0x00400000
0x0481A79 = 0x00400000 + 文件偏移地址
即字符串地址常量:0x00481A79
1.3、使用 OD 獲取引用該字符串的指令在內存中的地址;
在OD打開USB監控器查看該字符串地址常量
獲取內存地址:00405D2D
1.4、使用W32DASM獲得判斷語句的位置;
用W32Dasm打開USB監控器,查找到00405D2D
往上找找到一個函數:
可以找到:
JG在匯編語言意思為跳轉,與之相反的指令為JL
5、使用OD修改指令字節碼。
打開OD查找到JG指令:
右鍵這條指令(Assemble)進行修改修改:
可以看到修改后的信息:
保存文件,并打開修改后的文件進行注冊:
破解原理:
2、Free Internet Window Washer注冊破解
2.1、運行安裝軟件FIWWSetup2.9.exe,找到安裝文件夾
2.2、查殼:使用PEID工具檢驗是否加殼;
可以看到沒有加殼
2.3、注冊,發現報錯字符串
2.4、輸入錯誤注冊碼,調試跟蹤,發現注冊判斷代碼位置
打開WLan_Chinese.ini查找到RES_Registration_Error:
2.5、使用OD修改指令字節碼
用OD打開Clearpch.exe,查找RES_Registration_Error:
在這個函數的頭部下斷點來進行調試,根據OD中函數頭部的提示,函數頭部在004D3874處,按F2下斷點,然后進行動態調試
按F9運行程序,程序運行后繼續用假注冊碼進行注冊:
按F8進行單步調試,每一次按F8后注意如下圖,出現假注冊碼“44”時停止調試:
返回去可以找到注冊算法的位置,并雙擊其進行修改:
改后保存好,放到安裝目錄文件夾里(必須),即可注冊成功:
4、殼應用
1.加殼
2、模擬殼的工作
初始PE文件的 RVA 與 FOA 相同,使得模擬的時候可以省去各種地址轉換的問題。本節的模擬工作將會在該文件上進行模擬。以下分析、處理基于EnPE.exe文件。
① 對原始可執行文件RawPE.exe的代碼節進行加密,得到EnPE.exe(已完成);
密碼算法:異或;密鑰0XCC,與原始可執行文件RawPE.exe比較,分析加密了幾個字節?
答:兩個字節
1、可以看到兩個文件的入口點都是00001000
2、用WinHex打開文件后跳轉到1000,對比加密前后的信息,可以知道加密了兩個字節
加密前:
加密后:
② 增加節(已完成);與原始可執行文件RawPE.exe比較,增加了幾個節,該節大小是多少?
答:增加了一個節,大小為1000H
前:
后:
③ 修改代碼節的屬性與程序的入口點;
知識點:節的屬性問題
關于文件屬性:
標志(屬性塊)常用特征值對照如下所示:
[00000020h] :包含可執行代碼;a
[00000040h]:該塊包含已初始化的數據;b
[00000080h]:該塊包含未初始化的數據;c
[20000000h]:該塊可執行;d
[40000000h]:該塊可讀;e
[80000000h]:該塊可寫;f
代碼節的屬性一般為60000020H,也就是可執行、可讀和"節中包含代碼"(a+d+e);
數據節的屬性 一般為C0000040H,也就是可讀、可寫和"包含已初始化數據"(b+e+f);
而常量節(對應源代碼中的.const段)的屬性為40000040H,也就是可讀 和 “包含已初始化數據”;
那么為了達到加殼后能正常運行,EnPE.exe的.text節的屬性是什么?
答:
能正常運行的標志(屬性塊)常用特征值必須包含:a,d,e,f
所以EnPE.exe入口點應修改為E0000020h = 20h+20000000h+40000000h+80000000h
知識點:入口點
為了達到加殼后能正常運行,EnPE.exe入口點應改為什么?
答:
修改程序入口點:00004000h
④ 在增加的節中寫入解密代碼。
答:可以看到此時文件入口點為00404000h
① pushad
在可執行程序裝載入內存后,操作系統對進程進行了一系列的初始化工作,寄存器都有一些初始值,在解密的過程中會改變寄存器的值,為了保證解密后寄存器的值與可執行程序剛裝載入內存時相同,因此先使用 pushad 指令對各個寄存器進行保存。
② mov esi,00401000
將值 00401000 賦給 ESI 寄存器,也就是將 ESI 指向地址 00401000 處。地址 00401000是原來 EasyPack.exe 程序的入口點,也就是原來程序代碼開始的位置處。
③ mov ecx,2
ECX 寄存器有一個特殊的用途,就是用于循環時的計數。在前面對代碼節進行異或加密時一共加密了 0x02 字節,因此在解密時也需要循環對 0x02 字節進行解密。
④ xor byte ptr [esi], 0cc
從 ESI 指向的地址中取出一個字節,與 CC 進行異或運算后再保存至 ESI 指向的地址中。這句就是解密的指令。
⑤ inc esi
將 ESI 的地址向后移動一個字節,主要是改變 ESI 寄存指向的地址,因為在解密的時候是逐字節進行解密的。
⑥ loop 0040400B
loop 指令會首先將 ECX 寄存器的值減一,然后判斷 ECX 寄存器的值是否大于 0。如果ECX 寄存器的值大于 0,則跳轉到 loop 指令后跟隨的地址處;如果 ECX 寄存器不大于 0,則執行 loop 指令后的指令。在該段程序中,ECX 寄存器的值為 0x02,因此會循環 0x02 次,也就是逐字節解密需要解密 0x02 次。
⑦ popad
在執行完解密代碼后,將各寄存器的值恢復為原來的值。pushad 指令和 popad 指令是成對出現的,用于保存和恢復寄存器環境。
⑧ mov eax,00401000
將地址 00401000 地址賦值給 EAX 寄存器。請記住,地址 00401000 是原來 EasyPack.exe程序的入口點,通常在加殼前的入口點被稱為原始入口點,即 OEP。在脫殼時,很關鍵的一點就是尋找 OEP。
⑨ jmp eax
EAX 寄存器中保存了 00401000,也就是保存了 OEP 的地址。jmp eax 就是跳回到原來的入口點繼續執行。
在OD中修改代碼:
在PE中修改.屬性:
測試結果:
總結
- 上一篇: 杨辉三角 Python(利用嵌套列表)
- 下一篇: 计算机网络模拟校园,计算机网络实验——模