一个简单ReverseMe的完全分析
这个ReverseMe是<<加密与解密>>第2版P89提到的ReverseMe01.exe, 但是书上并没有给出完全分析, 在本文中给出.
阅读本文之前读者应当熟悉窗口程序的基本结构和基本API函数
为了方便新手阅读, 代码尽量保持良好的可读性, 这样做同时也是因为本文是采用纯静态反汇编分析的方法
文章很菜, 还望各位不吝赐教
一. 工欲善其事, 必先利其器
首先准备好工具, 这里我们需要3样工具, 他们是:
1. Stud_PE或PEiD...............获取欲逆向文件的第一手信息, 包括编写语言, 是否加壳等
2. IDA.........................强大的逆向工程工具, 把它用在单纯的破解上可以说是杀鸡用牛刀了
3. MSDN........................我们是新手, 有不懂的地方它永远是最好的老师
二. 知彼知己, 百战不殆
工具准备好了, 可以正式开始了, 不过在开始之前, 我们要问自己以下几个问题:
1.这个程序行为如何?
运行之, 出现一小窗口, 上有一按钮和一文本框, 按钮上有
"not reversed"
几个字, 单击按钮会弹出对话框
"Ok, for now, mission failed"
.
2.这个程序是否加壳?是何语言编写?该语言编写的程序有什么特点?
Peid显示为无壳, 汇编语言编写, 汇编语言编写的程序反汇编结果基本与源码一致, 可读性很好.
3.这个程序用到了哪些API?各是干什么的?
用Peid查看其输入表, 结果如下, 我一一作简要的解释供参考, 详细解释请查阅Msdn
基本上都是很基本的窗口程序API
USER32.dll
DestroyWindow
ord:141 rva: 00002010
清除一个窗口并导致一个WM_DESTROY消息
GetWindowTextA ord:347 rva: 00002014
获取窗口标题(或者按钮, 文本框)文本
LoadCursorA ord:407 rva: 00002018
装载光标
LoadIconA ord:411 rva: 0000201C
装载图标
MessageBoxA ord:443 rva: 00002020
不用多说了, 大家都知道
PostQuitMessage
ord:477 rva: 00002024
在消息队列里加入一条WM_QUIT消息
DispatchMessageA ord:148 rva: 00002028
向窗口过程分发消息, 窗口程序基本API之一
GetMessageA ord:296 rva: 0000202C
取消息队列消息, 基本函数
SetFocus
ord:555 rva: 00002030
设置窗口焦点
SetWindowTextA ord:601 rva: 00002034
设置窗口文本
ShowWindow
ord:613 rva: 00002038
设置窗口显隐状态
TranslateMessage
ord:637 rva: 0000203C
翻译消息
UpdateWindow
ord:651 rva: 00002040
刷新窗口
DefWindowProcA ord:131 rva: 00002044
消息默认处理函数, 基本函数之一
CreateWindowExA ord:88 rva: 00002048
建立窗口
RegisterClassExA ord:495 rva: 0000204C
注册类
SendMessageA ord:528 rva: 00002050
向窗口过程发送消息, 阻塞型函数
KERNEL32.dll
GetModuleHandleA ord:273 rva: 00002000
获取模块句柄, 基本函数
GetCommandLineA ord:182 rva: 00002004
获取命令行
ExitProcess
ord:117 rva: 00002008
退出进程
三. 实战
下面我们开始逆向之旅
我们目的是完全逆向这个程序, 由于程序很简单, 从入口来分析是合理的
start
proc
near
.text:00401000
push
NULL
; lpModuleName
.text:00401002
call
GetModuleHandleA
.text:00401007
mov
hInstance,
eax
.text:0040100C
call
GetCommandLineA
.text:00401011
push
SW_SHOWDEFAULT
; nCmdShow
.text:00401013
push
lpCmdLine
; lpCmdLine
.text:00401019
push
NULL
; hPrevInstance
.text:0040101B
push
hInstance
; hInstance
.text:00401021
call
WinMain
.text:00401026
push
eax
; uExitCode
.text:00401027
call
ExitProcess
.text:00401027 start
endp
很标准的入口初始化过程: 首先获取本模块句柄, 然后获取命令行指针, 再启动WinMain主函数, 最后ExitProcess退出.
不知大家注意到没, 这个入口过程有一个小错误, 看出来了吗?就是那个lpCmdLine参数不正确, 应当push eax才对
我们看看WinMain里有什么
; int __stdcall WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPCSTR lpCmdLine,int nCmdShow)
.text:0040102C WinMain
proc
near
; CODE XREF: start+21p
.text:0040102C
.text:0040102C hWnd =
dword
ptr
-50h
.text:0040102C stMsg = MSG
ptr
-4Ch
.text:0040102C stWndClassex = WNDCLASSEXA
ptr
-30h
.text:0040102C hInstance =
dword
ptr
8
.text:0040102C hPrevInstance =
dword
ptr
0Ch
.text:0040102C lpCmdLine =
dword
ptr
10h
.text:0040102C nCmdShow =
dword
ptr
14h
.text:0040102C
.text:0040102C
push
ebp
.text:0040102D
mov
ebp
,
esp
.text:0040102F
add
esp
, -50h
.text:00401032
mov
[
ebp
+stWndClassex.cbSize],
SIZEOF
WNDCLASSEX
.text:00401039
mov
[
ebp
+stWndClassex.style], 3
.text:00401040
mov
[
ebp
+stWndClassex.lpfnWndProc],
offset
WndProc
.text:00401047
mov
[
ebp
+stWndClassex.cbClsExtra], 0
.text:0040104E
mov
[
ebp
+stWndClassex.cbWndExtra], 0
.text:00401055
push
[
ebp
+hInstance]
.text:00401058
pop
[
ebp
+stWndClassex.hInstance]
.text:0040105B
mov
[
ebp
+stWndClassex.hbrBackground], 0Fh + 1h
.text:00401062
mov
[
ebp
+stWndClassex.lpszMenuName],
offset
aWhatmenu
; "WhatMenu"
.text:00401069
mov
[
ebp
+stWndClassex.lpszClassName],
offset
ClassName
; "SupremeDickHead"
.text:00401070
push
IDI_APPLICATION
; lpIconName
.text:00401075
push
NULL
; hInstance
.text:00401077
call
LoadIconA
.text:0040107C
mov
[
ebp
+stWndClassex.hIcon],
eax
.text:0040107F
mov
[
ebp
+stWndClassex.hIconSm],
eax
.text:00401082
push
IDC_ARROW
; lpCursorName
.text:00401087
push
NULL
; hInstance
.text:00401089
call
LoadCursorA
.text:0040108E
mov
[
ebp
+stWndClassex.hCursor],
eax
以上一段代码初始化窗口类, 类名为
"SupremeDickHead"
, 窗口程序为WndProc, 由于反汇编代码已经最大程度的整理过了, 所以如果读者熟悉窗口程序的话应该很容易看明白, 我就不作解释了
.text:00401091
lea
eax
, [
ebp
+stWndClassex]
.text:00401094
push
eax
; WNDCLASSEXA *
.text:00401095
call
RegisterClassExA
注册窗口类
.text:0040109A
push
NULL
; lpParam
.text:0040109C
push
[
ebp
+hInstance]
; hInstance
.text:0040109F
push
NULL
; hMenu
.text:004010A1
push
NULL
; hWndParent
.text:004010A3
push
0C8h
; nHeight
.text:004010A8
push
12Ch
; nWidth
.text:004010AD
push
0C8h
; Y
.text:004010B2
push
0C8h
; X
.text:004010B7
push
80C80000h
; dwStyle
.text:004010BC
push
offset
Caption
; "ReverseMe #1"
.text:004010C1
push
offset
ClassName
; "SupremeDickHead"
.text:004010C6
push
0
; dwExStyle
.text:004010C8
call
CreateWindowExA
.text:004010CD
mov
[
ebp
+hWnd],
eax
创建窗口, 窗口标题为
"ReverseMe #1"
, 没有菜单
.text:004010D0
push
SW_SHOWNORMAL
; nCmdShow
.text:004010D2
push
[
ebp
+hWnd]
; hWnd
.text:004010D5
call
ShowWindow
显示窗口
.text:004010DA
push
[
ebp
+hWnd]
; hWnd
.text:004010DD
call
UpdateWindow
.text:004010E2
刷新窗口
.text:004010E2 MessageLoop:
; CODE XREF: WinMain+DBj
.text:004010E2
push
0
; wMsgFilterMax
.text:004010E4
push
0
; wMsgFilterMin
.text:004010E6
push
NULL
; hWnd
.text:004010E8
lea
eax
, [
ebp
+stMsg]
.text:004010EB
push
eax
; lpMsg
.text:004010EC
call
GetMessageA
.text:004010F1
or
eax
,
eax
;收到WM_QUIT消息就退出
.text:004010F3
jz
short Exit
.text:004010F5
lea
eax
, [
ebp
+stMsg]
.text:004010F8
push
eax
; lpMsg
.text:004010F9
call
TranslateMessage
.text:004010FE
lea
eax
, [
ebp
+stMsg]
.text:00401101
push
eax
; lpMsg
.text:00401102
call
DispatchMessageA
.text:00401107
jmp
short MessageLoop
消息循环
.text:00401109
.text:00401109 Exit:
; CODE XREF: WinMain+C7j
.text:00401109
mov
eax
, [
ebp
+stMsg.wParam]
.text:0040110C
leave
.text:0040110D
retn
10h
.text:0040110D WinMain
endp
这个WinMain是非常标准的窗口程序主函数, 很可惜, 没有什么特别之处, 我就不多说了, 如果读者还是不理解原理请参考Windows程序设计相关书籍, 论坛置顶帖有介绍的
重点在WndProc函数处, 下面我们一起来看看这个函数
; int __stdcall WndProc(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam)
.text:00401110 WndProc
proc
near
; DATA XREF: WinMain+14o
.text:00401110
.text:00401110 hWnd =
dword
ptr
8
.text:00401110 Msg =
dword
ptr
0Ch
.text:00401110 wParam =
dword
ptr
10h
.text:00401110 lParam =
dword
ptr
14h
.text:00401110
.text:00401110
push
ebp
.text:00401111
mov
ebp
,
esp
.text:00401113
cmp
[
ebp
+Msg], WM_DESTROY
.text:00401117
jnz
short loc_401125
;if (Msg == WM_DESTROY)
.text:00401119
push
0
; nExitCode
.text:0040111B
call
PostQuitMessage
.text:00401120
jmp
return
如果窗口关闭则发送退出消息使主程序退出消息循环
.text:00401125 loc_401125:
; CODE XREF: WndProc+7j
.text:00401125
cmp
[
ebp
+Msg], WM_CREATE
.text:00401129
jnz
short loc_4011A1
else if (Msg == WM_CREATE)
.text:0040112B
push
0
; lpParam
.text:0040112D
push
hInstance
; hInstance
.text:00401133
push
ID_EDIT
; nControlID
.text:00401135
push
[
ebp
+hWnd]
; hWndParent
.text:00401138
push
19h
; nHeight
.text:0040113A
push
0C8h
; nWidth
.text:0040113F
push
23h
; Y
.text:00401141
push
32h
; X
.text:00401143
push
50800080h
; dwStyle
.text:00401148
push
NULL
; lpWindowName
.text:0040114A
push
offset
aEdit
; "edit"
.text:0040114F
push
WS_EX_CLIENTEDGE
; dwExStyle
.text:00401154
call
CreateWindowExA
.text:00401159
mov
hEdit,
eax
在窗口中创建一个Edit控件
.text:0040115E
push
hEdit
; hWnd
.text:00401164
call
SetFocus
并设置焦点
.text:00401169
push
NULL
; lpParam
.text:0040116B
push
hInstance
; hInstance
.text:00401171
push
ID_BUTTON
; nControlID
.text:00401173
push
[
ebp
+hWnd]
; hWndParent
.text:00401176
push
19h
; nHeight
.text:00401178
push
8Ch
; nWidth
.text:0040117D
push
46h
; Y
.text:0040117F
push
4Bh
; X
.text:00401181
push
50000001h
; dwStyle
.text:00401186
push
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课