ReverseMe 不完美分析过程
lnn1123/2006.3
为了响应老大的号召http://bbs.pediy.com//showthread.php?s=&threadid=22990去下了个ReverseMe玩玩
下玩东西,先看说明
You must insert a MenuItem called "Detour" into the menu of the
ReverseMe. When clicking this MenuItem, it should call a function inside
a Dll that you will have to code yourself. This function should show the
RunDialog-box (like the one in the Windows "Start"-menu.... Hint: call by
Ordinal in Shell32.dll). When executed, the RunDialog should show the Icon
of the ReverseMe. You MUST do this by pushing the handle of the Icon to the
call of your function inside your DLL. The OK-button of the RunDialog must
be disabled when the RunDialog opens (and enabled when entering something in
the editbox of the dialog). Afterwards the code-execution will have to
return
to the ReverseMe without exiting the program.
要你添加一个菜单,完成一点功能.那我就不客气了用ResHacker添加一个菜单
CAPTRESREMEMENU MENU
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
{
POPUP "&CaptREsMenu"
{
MENUITEM "&About", 1
MENUITEM SEPARATOR
MENUITEM "Detour", 3 //自己添加的,注意后面的资源ID不能重复
MENUITEM "E&xit", 2
}
}
保存运行看看,出来就是给你一个下马威,异常,OD调试跟踪到下面代码处异常
00401070 |. 68 70454000 PUSH CaptRERe.00404570 ; /FileName = ""
00401075 |. E8 8C010000 CALL <JMP.&KERNEL32.LoadLibraryA> ; \LoadLibraryA
0040107A |. 68 78454000 PUSH CaptRERe.00404578 ; /ProcNameOrOrdinal = ""
0040107F |. 50 PUSH EAX ; |hModule
00401080 |. E8 7B010000 CALL <JMP.&KERNEL32.GetProcAddress> ; \GetProcAddress
00401085 |. 6A 00 PUSH 0
00401087 |. 68 1E454000 PUSH CaptRERe.0040451E
0040108C |. 6A 00 PUSH 0
0040108E |. FFD0 CALL EAX //就是这个竟然call 0了,肯定异常了
看代码00401070处加载dll时就出错拉,push CaptRERe.00404570这句应该指向dll名字符,这里竟然是0,后面看看代码
加载dll后作者也没有检测是否加载成功就直接用函数名(函数名竟然也指向空字符)得到函数地址了,分析一下估计是
ResHacker在添加资源菜单的时候把原来文件某些地方的东西给弄没有了,并且很可能是00404570(offset:1170),00404578(offset:1178)处的字
符被清0了,对比原文件用Hex Workshop 到1170处发现果然被ResHacker修改后的文件1170初是00,而原文件是有字符的,这个好办,把原文件1104
处大小为80字节的内容复制到目标文件相同地址处(记得是覆盖),这样保存后运行正常.
看说明用写一个dll 执行菜单Detour功能,还要弄一个运行框的东西出来.
思路是这样的:
利用窗口子类化处理Detour的执行,在Detour执行的时候用dll弄一个对话框出来,并且完成相应功能
看说明要你点Detour的时候出来一个运行框,可以选择一个文件并且运行它,这些都是在dll里面来完成的,这个先放一放,要用dll中的函数先要
把原程序来改一改,因为dll中的输出函数有一个参数是调用dll的进程的窗口句饼,所以定位CreateWindowExA到这里 004010E6 |. 8945 B0 MOV DWORD PTR SS:[EBP-50],EAX
004010E9 |. 6A 01 PUSH 1 ; /ShowState = SW_SHOWNORMAL//就修改这里跳到我的代码处
004010EB |. FF75 B0 PUSH DWORD PTR SS:[EBP-50] ; |hWnd
004010EE |. E8 EF000000 CALL <JMP.&USER32.ShowWindow> ; \ShowWindow
004010F3 |. FF75 B0 PUSH DWORD PTR SS:[EBP-50] ; /hWnd
004010F6 |. E8 ED000000 CALL <JMP.&USER32.UpdateWindow> ; \UpdateWindow
004010FB |> 6A 00 PUSH 0 ; /MsgFilterMax = 0 修改后的代码:
004010E6 . 8945 B0 MOV DWORD PTR SS:[EBP-50],EAX ;保存窗口句饼
004010E9 . E9 3D010000 JMP 4.0040122B ;跳到我的代码处
004010EE 90 NOP
004010EF 90 NOP
004010F0 90 NOP
004010F1 90 NOP
004010F2 90 NOP
004010F3 > FF75 B0 PUSH DWORD PTR SS:[EBP-50] ; /hWnd
004010F6 . E8 ED000000 CALL <JMP.&USER32.UpdateWindow> ; \UpdateWindow
004010FB > 6A 00 PUSH 0 ; /MsgFilterMax = 0
004010FD . 6A 00 PUSH 0 ; |MsgFilterMin = 0
004010FF . 6A 00 PUSH 0 ; |hWnd = NULL
00401101 . 8D45 B4 LEA EAX,DWORD PTR SS:[EBP-4C] ; |
00401104 . 50 PUSH EAX ; |pMsg
00401105 . E8 BA000000 CALL <JMP.&USER32.GetMessageA> ; \GetMessageA
0040110A . 0BC0 OR EAX,EAX
0040110C . 74 0B JE SHORT 4.00401119
0040110E . 8D45 B4 LEA EAX,DWORD PTR SS:[EBP-4C]
00401111 . 50 PUSH EAX ; /pMsg
00401112 . E8 A7000000 CALL <JMP.&USER32.DispatchMessageA> ; \DispatchMessageA
00401117 .^EB E2 JMP SHORT 4.004010FB
00401119 > 8B45 BC MOV EAX,DWORD PTR SS:[EBP-44]
0040111C . C9 LEAVE
0040111D . C2 1000 RETN 10
00401120 /. 55 PUSH EBP
00401121 |. 8BEC MOV EBP,ESP
00401123 |. 837D 0C 02 CMP DWORD PTR SS:[EBP+C],2
00401127 |. 75 09 JNZ SHORT 4.00401132
00401129 |. 6A 00 PUSH 0 ; /ExitCode = 0
0040112B |. E8 A6000000 CALL <JMP.&USER32.PostQuitMessage> ; \PostQuitMessage
00401130 |. EB 79 JMP SHORT 4.004011AB
00401132 |> 817D 0C 110100>CMP DWORD PTR SS:[EBP+C],111
00401139 |. 75 5B JNZ SHORT 4.00401196
0040113B |. 8B45 10 MOV EAX,DWORD PTR SS:[EBP+10]
0040113E |. 66:83F8 01 CMP AX,1
00401142 |. 75 2B JNZ SHORT 4.0040116F
00401144 |. 68 70454000 PUSH 4.00404570 ; /FileName = "Shell32"
00401149 |. E8 B8000000 CALL <JMP.&KERNEL32.LoadLibraryA> ; \LoadLibraryA
0040114E |. 68 64454000 PUSH 4.00404564 ; /ProcNameOrOrdinal = "ShellAboutA"
00401153 |. 50 PUSH EAX ; |hModule
00401154 |. E8 A7000000 CALL <JMP.&KERNEL32.GetProcAddress> ; \GetProcAddress
00401159 |. FF35 90304000 PUSH DWORD PTR DS:[403090]
0040115F |. 68 5A454000 PUSH 4.0040455A ; ASCII "By CaptRE"
00401164 |. 68 11454000 PUSH 4.00404511 ; ASCII "CaptREsReMe1"
00401169 |. 6A 00 PUSH 0
0040116B |. FFD0 CALL EAX
0040116D |. EB 3C JMP SHORT 4.004011AB
0040116F |> 66:83F8 02 CMP AX,2
00401173 |. 75 36 JNZ SHORT 4.004011AB
00401175 |. 6A 24 PUSH 24 ; /Style = MB_YESNO|MB_ICONQUESTION|MB_APPLMODAL
00401177 |. 68 11454000 PUSH 4.00404511 ; |Title = "CaptREsReMe1"
0040117C |. 68 3E454000 PUSH 4.0040453E ; |Text = "Do you really want to exit?"
00401181 |. 6A 00 PUSH 0 ; |hOwner = NULL
00401183 |. E8 48000000 CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA
00401188 |. 83F8 06 CMP EAX,6
0040118B |. 75 07 JNZ SHORT 4.00401194
0040118D |. 6A 00 PUSH 0 ; /ExitCode = 0
0040118F |. E8 5A000000 CALL <JMP.&KERNEL32.ExitProcess> ; \ExitProcess
00401194 |> EB 15 JMP SHORT 4.004011AB
00401196 |> FF75 14 PUSH DWORD PTR SS:[EBP+14] ; /lParam
00401199 |. FF75 10 PUSH DWORD PTR SS:[EBP+10] ; |wParam
0040119C |. FF75 0C PUSH DWORD PTR SS:[EBP+C] ; |Message
0040119F |. FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
004011A2 |. E8 11000000 CALL <JMP.&USER32.DefWindowProcA> ; \DefWindowProcA
004011A7 |. C9 LEAVE
004011A8 |. C2 1000 RETN 10
004011AB |> 33C0 XOR EAX,EAX
004011AD |. C9 LEAVE
004011AE \. C2 1000 RETN 10
004011B1 CC INT3
004011B2 $-FF25 38204000 JMP DWORD PTR DS:[<&USER32.CreateWindowE>; USER32.CreateWindowExA
004011B8 $-FF25 28204000 JMP DWORD PTR DS:[<&USER32.DefWindowProc>; USER32.DefWindowProcA
004011BE $-FF25 30204000 JMP DWORD PTR DS:[<&USER32.DispatchMessa>; USER32.DispatchMessageA
004011C4 $-FF25 2C204000 JMP DWORD PTR DS:[<&USER32.GetMessageA>] ; USER32.GetMessageA
004011CA $-FF25 24204000 JMP DWORD PTR DS:[<&USER32.LoadCursorA>] ; USER32.LoadCursorA
004011D0 $-FF25 1C204000 JMP DWORD PTR DS:[<&USER32.MessageBoxA>] ; USER32.MessageBoxA
004011D6 $-FF25 18204000 JMP DWORD PTR DS:[<&USER32.PostQuitMessa>; USER32.PostQuitMessage
004011DC $-FF25 34204000 JMP DWORD PTR DS:[<&USER32.RegisterClass>; USER32.RegisterClassExA
004011E2 .-FF25 3C204000 JMP DWORD PTR DS:[<&USER32.ShowWindow>] ; USER32.ShowWindow
004011E8 $-FF25 20204000 JMP DWORD PTR DS:[<&USER32.UpdateWindow>>; USER32.UpdateWindow
004011EE .-FF25 10204000 JMP DWORD PTR DS:[<&KERNEL32.ExitProcess>; kernel32.ExitProcess
004011F4 $-FF25 0C204000 JMP DWORD PTR DS:[<&KERNEL32.GetCommandL>; kernel32.GetCommandLineA
004011FA $-FF25 08204000 JMP DWORD PTR DS:[<&KERNEL32.GetModuleHa>; kernel32.GetModuleHandleA
00401200 $-FF25 04204000 JMP DWORD PTR DS:[<&KERNEL32.GetProcAddr>; kernel32.GetProcAddress
00401206 $-FF25 00204000 JMP DWORD PTR DS:[<&KERNEL32.LoadLibrary>; kernel32.LoadLibraryA
0040120C 00 DB 00
0040120D 00 DB 00
0040120E 00 DB 00
0040120F 00 DB 00
00401210 00 DB 00
00401211 00 DB 00
00401212 00 DB 00
00401213 00 DB 00
00401214 00 DB 00
00401215 00 DB 00
00401216 00 DB 00
00401217 . 6C 6F 61 64 2E>ASCII "load.dll",0 ; dll名
00401220 00 DB 00
00401221 . 62 62 62 00 ASCII "bbb",0 ; 要调用的函数名
00401225 00 DB 00
00401226 00 DB 00
00401227 00 DB 00
00401228 00 DB 00
00401229 00 DB 00
0040122A 00 DB 00
0040122B > 60 PUSHAD ; 保护环境
0040122C . 68 17124000 PUSH 4.00401217 ; /FileName = "load.dll"
00401231 . FF15 00204000 CALL DWORD PTR DS:[<&KERNEL32.LoadLibrar>; \LoadLibraryA
00401237 . 85C0 TEST EAX,EAX ; 加载是否成功
00401239 . 74 15 JE SHORT 4.00401250
0040123B . 68 21124000 PUSH 4.00401221 ; /ProcNameOrOrdinal = "bbb"
00401240 . 50 PUSH EAX ; |hModule
00401241 . FF15 04204000 CALL DWORD PTR DS:[<&KERNEL32.GetProcAdd>; \GetProcAddress
00401247 . 85C0 TEST EAX,EAX ; 得到了函数地址?
00401249 . 74 05 JE SHORT 4.00401250 ; 没得到跳
0040124B . FF75 B0 PUSH DWORD PTR SS:[EBP-50] ; 窗口句饼
0040124E . FFD0 CALL EAX ; 子类化函数
00401250 > 61 POPAD
00401251 . 6A 01 PUSH 1 ; /ShowState = SW_SHOWNORMAL
00401253 . FF75 B0 PUSH DWORD PTR SS:[EBP-50] ; |hWnd
00401256 . FF15 3C204000 CALL DWORD PTR DS:[<&USER32.ShowWindow>] ; \ShowWindow ;这里是修补原来被NOP了的函数
0040125C . 68 F3104000 PUSH 4.004010F3
00401261 . C3 RETN ; RET used as a jump to 004010F3
下面就是写dll了,代码如下:
; code:lnn1123
; Date:2006.3
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.586
Option CaseMap: None
.Model Flat, StdCall
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\gdi32.inc
include \masm32\include\masm32.inc
include \masm32\include\comdlg32.inc
include \masm32\include\Comctl32.inc
include \masm32\include\shell32.inc
;\\\\\\\\\\\\ lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\gdi32.lib
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\comdlg32.lib
includelib \masm32\lib\Comctl32.lib
includelib \masm32\lib\shell32.lib
IDD_DLG1 equ 1000
IDC_EDT1 equ 1002
IDC_Open equ 1001
IDC_oK equ 1003
IDC_eXit equ 1004
Detour equ 3
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data?
szFileName db MAX_PATH dup (?)
hInstance DWORD ?
Old_Window_Main_Proc DWORD ?
EIDC_oK DWORD ?
hWinMain dd ?
.const
open db "open",0
szExtPe db 'PE Files',0,'*.exe;*.dll;*.scr;*.fon;*.drv',0
db 'All Files(*.*)',0,'*.*',0,0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
DialogProc proto :DWORD,:DWORD,:DWORD,:DWORD
Window_Main_Proc proto :DWORD,:DWORD,:DWORD,:DWORD
bbb proto :DWORD
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; dll 的入口函数
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DllEntry proc _hInstance,_dwReason,_dwReserved
mov eax,TRUE
ret
DllEntry Endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 对话框消息处理过程
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DialogProc proc hDlg :HWND, uMsg :UINT, wParam :WPARAM, lParam :LPARAM
mov eax,uMsg
.if eax == WM_CLOSE
invoke EndDialog,hDlg,NULL
.elseif eax == WM_INITDIALOG
push hDlg
pop hWinMain
invoke GetDlgItem, hDlg, IDC_oK
mov EIDC_oK,eax
.elseif eax == WM_COMMAND
mov eax,wParam
.if ax == IDC_Open
call _OpenFile
invoke EnableWindow,EIDC_oK,TRUE
.elseif ax == IDC_oK
invoke ShellExecute,hDlg,offset open,offset szFileName,NULL,NULL,SW_SHOW ;运行打开的程序
.elseif ax==IDC_eXit
invoke EndDialog,hDlg,NULL
.endif
.else
mov eax,FALSE
ret
.endif
mov eax,TRUE
ret
DialogProc endp
_OpenFile proc
local @stOF:OPENFILENAME
local @hFile,@dwFileSize,@hMapFile,@lpMemory
invoke RtlZeroMemory,addr @stOF,sizeof @stOF
mov @stOF.lStructSize,sizeof @stOF
push hWinMain
pop @stOF.hwndOwner
mov @stOF.lpstrFilter,offset szExtPe ;填写结构体字段
mov @stOF.lpstrFile,offset szFileName ;TOO
mov @stOF.nMaxFile,MAX_PATH ;TOO
mov @stOF.Flags,OFN_PATHMUSTEXIST or OFN_FILEMUSTEXIST ;TOO
invoke GetOpenFileName,addr @stOF ;打开文件
.if ! eax
jmp @F
.endif
invoke SetDlgItemText,hWinMain,IDC_EDT1,OFFSET szFileName ;设置 edit编辑框文本为打开的文件名
invoke CreateFile,addr szFileName,GENERIC_READ,FILE_SHARE_READ or \
FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,NULL
.if eax != INVALID_HANDLE_VALUE ;文件打开错误?
mov @hFile,eax
invoke CloseHandle,@hFile
.endif
@@:
ret
_OpenFile endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 下面的这个子程序还是用dummy的
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Window_Main_Proc proc hWnd :HWND, uMsg :UINT, wParam :WPARAM, lParam :LPARAM
mov ecx, [uMsg]
cmp ecx, WM_COMMAND
jne @F
mov ebx, [wParam]
shr ebx, 16
cmp bx, BN_CLICKED
je _MAIN_bn_clicked
cmp bx, EN_CHANGE
jne @F
; invoke InvalidateRect, lParam, NULL, TRUE
jmp @F
_MAIN_bn_clicked:
cmp [wParam], Detour
je NewDlg ;按的是 Detour?
jmp @F ;不是就给原来窗口处理过程处理
NewDlg:
invoke DialogBoxParam, 10000000h, IDD_DLG1,hWnd, addr DialogProc, 0;创建一个对话框
xor eax, eax
ret @@:
invoke CallWindowProc, Old_Window_Main_Proc, hWnd, uMsg, wParam, lParam
ret
Window_Main_Proc endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; dll 的导出函数
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
bbb proc aa :HWND
invoke SetWindowLong, aa, GWL_WNDPROC, Window_Main_Proc ;子类化窗口
mov Old_Window_Main_Proc, eax ;保存原来窗口函数入口
ret
bbb ENDP
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
End DllEntry看一下修改后的样子
这样就实现了窗口子类化,完成了相应功能,但是还有一个问题没有弄好
When executed, the RunDialog should show the Icon
of the ReverseMe. You MUST do this by pushing the handle of the Icon to the
call of your function inside your DLL
这个不知道怎么实现,当我把dll 和目标文件放在一起的时候.exe文件的图标也没有了,不知道为什么.
END
lnn1123 2006.3
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
上传的附件: