基本知識
加殼程序
- 1、殼是什么?
- 加殼是可執行程序資源壓縮,是保護文件的常用手段。加殼過的程序可以直接運行,但是不能查看源代碼,要經過脫殼才可以查看源代碼。
- 2、加殼的原理是什么?殼是怎么運作的?
- 加殼是利用特殊的算法,對EXE、DLL文件里的資源進行壓縮、加密。類似WINZIP 的效果,只不過這個壓縮之后的文件,可以獨立運行,解壓過程完全隱蔽,都在內存中完成。它們附加在原程序上通過Windows加載器載入內存后,先於原始程序執行,得到控制權,執行過程中對原始程序進行解密、還原,還原完成后再把控制權交還給原始程序,執行原來的代碼部分。加上外殼后,原始程序代碼在磁盤文件中一般是以加密后的形式存在的,只在執行時在內存中還原,這樣就可以比較有效地防止破解者對程序文件的非法修改,同時也可以防止程序被靜態反編譯。
- 簡單來說,殼可以完成代碼的壓縮和實時解壓執行,加殼程序可以正常執行,但是看不到原來的代碼,反編譯的時候看不懂。
- 3、殼的分類
- 殼的類型通常分為壓縮殼和加密殼兩類。
- 壓縮殼的特點是減小軟件體積大小,加密保護不是重點。
- 加密殼種類比較多,不同的殼側重點不同,一些殼單純保護程序,另一些殼提供額外的功能,如提供注冊機制、使用次數、時間限制等。
脫殼
- 1、對特定的殼可以用專門的脫殼軟件進行脫殼。
- 2、也可以手動脫殼
OD
反匯編工具OD=OllyDebug,OllyDbg 是一種具有可視化界面的 32 位匯編-分析調試器。它的特別之處在於可以在沒有源代碼時解決問題,並且可以處理其它編譯器無法解決的難題。
手動脫殼的基本思路
- 1、用軟件查殼,可用PEID或者ExeinfoPE查殼。
- 2、用進行OD動態反匯編,找到程序真正的入口。
- 3、用OD插件或者loadPE脫殼。
OEP
- OEP:(Original Entry Point),程序的入口點。軟件加殼一般隱藏了程序真實的OEP(或者用了假的OEP), 我們需要尋找程序真正的OEP,才可以完成脫殼。
一般加殼程序在使用Ollydbg等動態調試工具時,會停在殼的預處理塊。即處在對於程序原始代碼塊的解壓或解密操作之前,在運行完程序自脫殼模塊后,會停留在程序加殼之前的OEP位置,此時是dump程序的最佳時期。脫殼時在真實OEP處下int3斷點,就可以捕捉到程序代碼段完全恢復的狀態。因此,尋找加殼程序的正確OEP,也成了手動脫殼時的第一要務。
OPE的基本特征
VC6
-
區段特征
-
入口特征
-
EBP為基指針(Base Pointer)寄存器,用它可直接存取堆棧中的數據;
-
ESP為堆棧指針(Stack Pointer)寄存器,用它只可訪問棧頂。
-
push ebp;保存ebp內容以便調用完后恢復;此時esp <- esp - 4
-
mov ebp esp; 保存調用前棧頂地址以便調用完后恢復,用ebp來保存當前esp。
VS2008和VS2013
-
入口特征
-
第一行是call XXXX
-
第二行是 jmp XXXX
-
call里面是push ebp mov ebp esp
常見語言的入口點:
VB:
004012D4 > 68 54474000 push QQ個性網.00404754
004012D9 E8 F0FFFFFF call <jmp.&MSVBVM60.#100>
004012DE 0000 add byte ptr ds:[eax],al
004012E0 0000 add byte ptr ds:[eax],al
004012E2 0000 add byte ptr ds:[eax],al
004012E4 3000 xor byte ptr ds:[eax],al
004012E6 0000 add byte ptr ds:[eax],al
004012E8 48 dec eax
delphi:
004A5C54 > 55 push ebp
004A5C55 8BEC mov ebp,esp
004A5C57 83C4 F0 add esp,-10
004A5C5A B8 EC594A00 mov eax,openpro.004A59EC
BC++:
00401678 > /EB 10 jmp short btengine.0040168A
0040167A |66:623A bound di,dword ptr ds:[edx]
0040167D |43 inc ebx
0040167E |2B2B sub ebp,dword ptr ds:[ebx]
00401680 |48 dec eax
00401681 |4F dec edi
00401682 |4F dec edi
00401683 |4B dec ebx
00401684 |90 nop
00401685 -|E9 98005400 jmp 00941722
0040168A \A1 8B005400 mov eax,dword ptr ds:[54008B]
0040168F C1E0 02 shl eax,2
00401692 A3 8F005400 mov dword ptr ds:[54008F],eax
00401697 52 push edx
00401698 6A 00 push 0
0040169A E8 99D01300 call <jmp.&KERNEL32.GetModuleHandleA>
0040169F 8BD0 mov edx,eax
VC++:
0040A41E > 55 push ebp
0040A41F 8BEC mov ebp,esp
0040A421 6A FF push -1
0040A423 68 C8CB4000 push 跑跑排行.0040CBC8
0040A428 68 A4A54000 push <jmp.&MSVCRT._except_handler3>
0040A42D 64:A1 00000000 mov eax,dword ptr fs:[0]
0040A433 50 push eax
0040A434 64:8925 0000000>mov dword ptr fs:[0],esp
0040A43B 83EC 68 sub esp,68
0040A43E 53 push ebx
0040A43F 56 push esi
0040A440 57 push edi
MASM(匯編):
004035C9 > 6A 00 push 0
004035CB E8 A20A0000 call <jmp.&kernel32.GetModuleHandleA>
004035D0 A3 5B704000 mov dword ptr ds:[40705B],eax
004035D5 68 80000000 push 80
004035DA 68 2C754000 push 11.0040752C
004035DF FF35 5B704000 push dword ptr ds:[40705B]
004035E5 E8 820A0000 call <jmp.&kernel32.GetModuleFileNameA>
004035EA E8 87070000 call 11.00403D76
004035EF 6A 00 push 0
004035F1 68 0B364000 push 11.0040360B
004035F6 6A 00 push 0
004035F8 6A 64 push 64
004035FA FF35 5B704000 push dword ptr ds:[40705B]
手動脫殼方法
-
方法1:單步跟蹤
-
方法2:ESP定律法
-
方法3:2次內存鏡像法
-
方法4:一步直達法
常用匯編
1.MOV 傳送字或字節.
2.MOVSX 先符號擴展,再傳送.
3.MOVZX 先零擴展,再傳送.
4.PUSH 把字壓入堆棧.
5.POP 把字彈出堆棧.
6.PUSHA 把AX,CX,DX,BX,SP,BP,SI,DI依次壓入堆棧.
7.POPA 把DI,SI,BP,SP,BX,DX,CX,AX依次彈出堆棧.
8.JMP 無條件轉移指令
9.CALL 過程調用
10.RET/RETF過程返回.
11.2>條件轉移指令 (短轉移,-128到+127的距離內)
( 當且僅當(SF XOR OF)=1時,OP1<OP2 )
12.JA/JNBE 不小於或不等於時轉移.
13.JAE/JNB 大於或等於轉移.
14.JB/JNAE 小於轉移.
15.JBE/JNA 小於或等於轉移.
以上四條,測試無符號整數運算的結果(標志C和Z).
16.JG/JNLE 大於轉移.
17.JGE/JNL 大於或等於轉移.
18.JL/JNGE 小於轉移.
19.JLE/JNG 小於或等於轉移.
以上四條,測試帶符號整數運算的結果(標志S,O和Z).
20.JE/JZ 等於轉移.
21.JNE/JNZ 不等於時轉移.
22.JC 有進位時轉移.
23.JNC 無進位時轉移.
24JNO 不溢出時轉移.
25.JNP/JPO 奇偶性為奇數時轉移.
26.JNS 符號位為 "0" 時轉移.
27.JO 溢出轉移.
28.JP/JPE 奇偶性為偶數時轉移.
29.JS 符號位為 "1" 時轉移.
30.3>循環控制指令(短轉移)
31.LOOP CX不為零時循環.
32.LOOPE/LOOPZ CX不為零且標志Z=1時循環.
33.LOOPNE/LOOPNZ CX不為零且標志Z=0時循環.
34.JCXZ CX為零時轉移.
35.JECXZ ECX為零時轉移.
寄存器相關知識
-
EAX : 是"累加器"(accumulator), 它是很多加法乘法指令的缺省寄存器。
-
ECX : 是計數器(counter), 是重復(REP)前綴指令和LOOP指令的內定計數器。
-
EDX : 總是被用來放整數除法產生的余數。
-
EBX : 是"基地址"(base)寄存器, 在內存尋址時存放基地址。
-
ESP : 專門用作堆棧指針,被形象地稱為棧頂指針,堆棧的頂部是地址小的區域,壓入堆棧的數據越多,ESP也就越來越小。在32位平台上,ESP每次減少4字節。
-
EBP : 是"基址指針"(BASE POINTER), 它最經常被用作高級語言函數調用的"框架指針"(frame pointer).
push ebp ;保存當前ebp
mov ebp,esp ;EBP設為當前堆棧指針
sub esp, xxx ;預留xxx字節給函數臨時變量.
-
ESI/EDI:分別叫做"源/目標索引寄存器"(source/destination index),因為在很多字符串操作指令中, DS:ESI指向源串,而ES:EDI指向目標串.
-
EIP: 寄存器存放下一個CPU指令存放的內存地址,當CPU執行完當前的指令后,從EIP寄存器中讀取下一條指令的內存地址,然后繼續執行。
-
ES:附加段寄存器
-
CS:代碼段寄存器
-
SS:堆棧段寄存器
-
DS:數據段寄存器
-
FS:標志段寄存器
-
GS:全局寄存器