-
-
继续逆向之旅――几天以前在本版物色好的一个Crackme
-
发表于: 2006-8-11 18:35 5779
-
可惜不幸沉溺于游戏,没有及时把它搞出来
下载地址:http://bbs.pediy.com/showthread.php?threadid=29982
使用工具:
反编译工具:IDA,Resource Hacker
程序开发包:MASM32
这是一个“正宗”的窗口程序,不象以往的大多数Crackme只是一个对话框,这里有着从注册窗口类到
建立消息循环的完整过程。有个特点就是该程序只允许运行一个实例,在初始化的时候有用FindWindow检
测是否存在基于自身类名的窗口运行,若已有一个这样的窗口,就不会继续建立第二个窗口。
创建窗口使用的CreateWindowEx中的两个参数nWidth和nHeight,乍一看令人费解。这两个参数的意义
是指定窗口的大小,以像素为单位,但是现在它们的值都是8000h,而整个屏幕的大小通常也不过是
400h * 300h,怎么显示得下这么大的窗口?并且这个数值也不是CW_USEDEFAULT,CW_USEDEFAULT的值是
80000000h呀!另一方面,实际执行一下程序会发现,窗口实际上还是比较小的,既没有显示一个大到荒唐
的窗口,也不是指定CW_USEDEFAULT的效果。那么这究竟是怎么回事?原来,在建立窗口的WM_CREATE消息
之前先要处理WM_GETMINMAXINFO消息,而窗口过程中对这个消息的处理方式是把窗口的MinTrackSize和
MaxTrackSize(这两个词不知道怎么翻译,意思就是通过拖动边框使得窗口所能达到的最小和最大尺寸)
都设置为280 * 160,正是由于这里设置了正确的数值,窗口在显示的时候才能是合理的大小。在源程序里
我把这两个参数换成了它们本来应该是的数值,虽然这并没有实质性的改进,起码看着直观点吧!
而在UpdateWindow后面这句InvalidateRect就更令人困惑了:它的第一个参数是dword ptr [ebp+8],
这明显是引用子程序参数的方法,但这是位于主程序中,何来的参数?如果把主程序看成Windows系统调用
的一个子程序,那也勉强可以解释过去,问题是当前的[ebp+8]是什么数值呢?用调试器跟踪会发现它的值
是401000h之类的数值,并不是哪个窗口的句柄。事实上这一句调用是否必要都成很大问题,前面不是已经
有UpdateWindow了吗?在源程序里我姑且保留这一句,但是把它注释掉了。
接下来进入消息循环,我们将注意力转移到窗口过程上,这个程序中的窗口过程大致可以分为三块:
主窗口的,“注册”对话框的和“关于”对话框的回调过程。在主窗口的“Help”菜单中选择其中的两项
可以分别弹出后面两个对话框。主窗口中的消息分支可以简单归纳为:WM_COMMAND――根据具体内容做进
一步处理;WM_GETMINMAXINFO――设置固定的窗口大小(哪怕最大化了也还是那么大);WM_CREATE或
WM_SIZE――忽略;WM_DESTROY――PostQuitMessage;其他――DefWindowProc。至于WM_L(R)BUTTONDOWN
只要不设计相应分支的代码,一般也是没事发生,可不予考虑。
“注册”对话框只负责取得用户名和序列号等信息,它通过DialogBoxParam向主调程序返回一个值表
示取得注册信息是否成功,如果取用户名失败或用户名是空串,则返回失败,主调程序就不会继续验证注
册信息,也就没事发生。此外,从程序中看来,在“注册”对话框中每点击一次,整个对话框都会被刷新
一遍,当计算机的运行比较“卡”的时候,可以明显的看到有闪烁。
“关于”对话框十分简单,这里就略过不提了。
注册信息的验证还是在主窗口的WM_COMMAND消息分支里完成的,其中sub_40137E这个过程的作用是检
查用户名的各字符,如果有小于'A'的则判为非法,对大于或等于'Z'的那些则减20h,处理完毕以后再调用
sub_4013C2计算用户名的各字符和,这个和与5678h异或后存入eax;然后取得序列号字符串并且各字符减
去'0'后,第一个字符乘以10后加上第二个字符,这个和再乘以10,再加上第三个字符……如此重复一直到
加完最后一个字符,最后的和与1234h异或后存入edi,然后注册成功与否,则看eax是否等于edi。
从算法的描述上看,作者的意图极有可能是:要将用户名中的小写字母转化为大写字母后再计算字符
串和;并且打算把序列号看成一个十进制整数。但是由于编写程序时粗心大意或者别的原因,导致算法上
存在缺陷,以至于不能实现其初衷。譬如,假如输入的用户名是"PEDIZ"(故意写成Z是为了演示算法的逻
辑问题),本来大写字母应该不变,但是实际上'Z'却要减掉20h――注意到sub_40137E中与'Z'比较后用的
指令是jnb而不是ja――这样字符串的和应该是:
'P'+'E'+'D'+'I'+'Z'-20h = 15Ch
这个值与1234h xor 5678h――也就是444Ch――异或的结果是4510h,转换成十进制是17680。当然我们用
17680作为序列号输入也可以注册成功,但我们现在打算把17680看成“16千15百18十”――注意:“看成
十进制整数”是没错,可没有说每个数码都只能在0到9之间!想象一下旧式七珠大算盘上某一位的所有算
珠都靠梁的情况――那么:
16 + '0' = '@'
15 + '0' = '?'
18 + '0' = 'B'
换言之,"@?B0"也是正确的序列号!只要符合要求,对于同一个用户名,还可以构造出许多不同的稀奇古
怪的序列号。由于这只是算法的欠严谨,而不是矛盾,我没有去修正它。
上传内容:1.asm 源码
1.rc 资源脚本
Icon_1.ico 图标
Bitmap_1.bmp 位图资源
====================以下是代码==================
; enum Control_IDs
ICO_MAIN = 100
ID_MENUEXIT = 101
ID_MENUREG = 102
ID_MENUABOUT = 103
EDT_NAME = 1000
EDT_SERIAL = 1001
ID_CHECK = 1002
ID_CANCEL = 1003
public start
start proc near
push NULL ; lpModuleName
call GetModuleHandleA
mov ds:hInstance, eax
push NULL ; lpWindowName
push offset szMyClass ; "No need to disasm the code!"
call FindWindowA
or eax, eax ; 只允许运行一个实例
jz short loc_40101D
retn
loc_40101D: ; CODE XREF: start+1Aj
mov ds:stMyWndClass.style, CS_VREDRAW or CS_HREDRAW or CS_GLOBALCLASS
mov ds:stMyWndClass.lpfnWndProc, offset _ProcWinMain
mov ds:stMyWndClass.cbClsExtra, 0
mov ds:stMyWndClass.cbWndExtra, 0
mov eax, ds:hInstance
mov ds:stMyWndClass.hInstance, eax
push ICO_MAIN ; lpIconName
push eax ; hInstance
call LoadIconA
mov ds:stMyWndClass.hIcon, eax
push IDC_ARROW ; lpCursorName
push NULL ; hInstance
call LoadCursorA
mov ds:stMyWndClass.hCursor, eax
mov ds:stMyWndClass.hbrBackground, COLOR_MENU + 1
mov ds:stMyWndClass.lpszMenuName, offset szIdMenu ; "MENU"
mov ds:stMyWndClass.lpszClassName, offset szMyClass ; "No need to disasm the code!"
push offset stMyWndClass ; lpWndClass
call RegisterClassA
push NULL ; lpParam
push ds:hInstance ; hInstance
push NULL ; hMenu
push NULL ; hWndParent
push 8000h ; nHeight
push 8000h ; nWidth
push 6Eh ; Y
push 0B4h ; X
push WS_OVERLAPPEDWINDOW ; dwStyle
push offset szNameWinMain ; "CrackMe v1.0"
push offset szMyClass ; "No need to disasm the code!"
push WS_EX_LEFT ; dwExStyle
call CreateWindowExA
mov ds:hWinMain, eax
push SW_SHOWNORMAL ; nCmdShow
push ds:hWinMain ; hWnd
call ShowWindow
push ds:hWinMain ; hWnd
call UpdateWindow
push TRUE ; bErase
push NULL ; lpRect
push dword ptr [ebp+8] ; hWnd
; (401000)
call InvalidateRect
loc_4010F1: ; CODE XREF: start+11Bj
push 0 ; wMsgFilterMax
push 0 ; wMsgFilterMin
push NULL ; hWnd
push offset stMsg ; lpMsg
call GetMessageA
cmp ax, 0
jz short loc_40111D
push offset stMsg ; lpMsg
call TranslateMessage
push offset stMsg ; lpMsg
call DispatchMessageA
jmp short loc_4010F1
loc_40111D: ; CODE XREF: start+105j
push ds:stMsg.wParam ; uExitCode
call ExitProcess
start endp
; Exported entry 1. WndProc
; int __stdcall ProcWinMain(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
public _ProcWinMain
_ProcWinMain proc near ; DATA XREF: start+27o
hWnd = dword ptr 8
uMsg = dword ptr 0Ch
wParam = dword ptr 10h
lParam = dword ptr 14h
enter 0, 0
push esi
push edi
push ebx
cmp [ebp+uMsg], WM_DESTROY
jz short loc_401193
cmp [ebp+uMsg], WM_RBUTTONDOWN
jz short loc_4011A3
nop
nop
nop
nop
cmp [ebp+uMsg], WM_SIZE
jz short loc_4011A5
cmp [ebp+uMsg], WM_CREATE
jz short loc_401176
cmp [ebp+uMsg], WM_LBUTTONDOWN
jz short loc_4011A1
cmp [ebp+uMsg], WM_GETMINMAXINFO
jz short loc_4011AC
cmp [ebp+uMsg], WM_COMMAND
jz short loc_4011D2
nop
nop
nop
nop
jmp short loc_401180
jmp short loc_4011E6
loc_401176: ; CODE XREF: _ProcWinMain+24j
mov eax, 0
jmp short loc_4011E6
loc_401180: ; CODE XREF: _ProcWinMain+42j
push [ebp+lParam] ; lParam
push [ebp+wParam] ; wParam
push [ebp+uMsg] ; Msg
push [ebp+hWnd] ; hWnd
call DefWindowProcA
jmp short loc_4011E6
loc_401193: ; CODE XREF: _ProcWinMain+Bj
; _ProcWinMain+B4j
push 0 ; nExitCode
call PostQuitMessage
mov eax, 0
jmp short loc_4011E6
loc_4011A1: ; CODE XREF: _ProcWinMain+2Dj
jmp short loc_4011E6
loc_4011A3: ; CODE XREF: _ProcWinMain+14j
jmp short loc_4011E6
loc_4011A5: ; CODE XREF: _ProcWinMain+1Ej
mov eax, 0
jmp short loc_4011E6
loc_4011AC: ; CODE XREF: _ProcWinMain+33j
mov ebx, [ebp+lParam]
mov [ebx+MINMAXINFO.ptMinTrackSize.x], 118h
mov [ebx+MINMAXINFO.ptMinTrackSize.y], 0A0h
mov [ebx+MINMAXINFO.ptMaxTrackSize.x], 118h
mov [ebx+MINMAXINFO.ptMaxTrackSize.y], 0A0h
mov eax, 0
jmp short loc_4011E6
loc_4011D2: ; CODE XREF: _ProcWinMain+3Cj
cmp [ebp+wParam], ID_MENUABOUT
jz short loc_4011ED
cmp [ebp+wParam], ID_MENUEXIT
jz short loc_401193
cmp [ebp+wParam], ID_MENUREG
jz short loc_401209
jmp short $+2
loc_4011E6: ; CODE XREF: _ProcWinMain+49j
; _ProcWinMain+53j _ProcWinMain+69j
; _ProcWinMain+77j
; _ProcWinMain:loc_4011A1j
; _ProcWinMain:loc_4011A3j
; _ProcWinMain+82j _ProcWinMain+A8j
; _ProcWinMain+DFj _ProcWinMain+FEj
; _ProcWinMain+122j _ProcWinMain+129j
pop ebx
pop edi
pop esi
leave
retn 10h
loc_4011ED: ; CODE XREF: _ProcWinMain+AEj
push 0 ; dwInitParam
push offset _ProcDlgAbout ; lpDialogFunc
push [ebp+hWnd] ; hWndParent
push offset TemplateName ; "DLG_ABOUT"
push ds:hInstance ; hInstance
call DialogBoxParamA
jmp short loc_4011E6
loc_401209: ; CODE XREF: _ProcWinMain+BAj
push 0 ; dwInitParam
push offset _ProcDlgReg ; lpDialogFunc
push [ebp+hWnd] ; hWndParent
push offset aDlg_regis ; "DLG_REGIS"
push ds:hInstance ; hInstance
call DialogBoxParamA
cmp eax, 0
jz short loc_4011E6
push offset szUserName
call sub_40137E
push eax
push offset szSerial
call sub_4013D8
add esp, 4
pop eax
cmp eax, ebx
jz short loc_40124C
call sub_401362
jmp short loc_4011E6
loc_40124C: ; CODE XREF: _ProcWinMain+11Bj
call sub_40134D
jmp short loc_4011E6
_ProcWinMain endp
; BOOL __stdcall ProcDlgReg(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
_ProcDlgReg proc near ; DATA XREF: _ProcWinMain+E3o
hWnd = dword ptr 8
uMsg = dword ptr 0Ch
wParam = dword ptr 10h
lParam = dword ptr 14h
enter 0, 0
push ebx
push esi
push edi
cmp [ebp+uMsg], WM_INITDIALOG
jz short loc_401297
cmp [ebp+uMsg], WM_COMMAND
jz short loc_4012A1
cmp [ebp+uMsg], WM_CLOSE
jz loc_4012F7
cmp [ebp+uMsg], WM_LBUTTONDOWN
jz short loc_40128B
mov eax, 0
loc_401284: ; CODE XREF: _ProcDlgReg+4Cj
; _ProcDlgReg+A2j _ProcDlgReg+B2j
pop edi
pop esi
pop ebx
leave
retn 10h
loc_40128B: ; CODE XREF: _ProcDlgReg+2Aj
push TRUE ; bErase
push NULL ; lpRect
push [ebp+hWnd] ; hWnd
call InvalidateRect
loc_401297: ; CODE XREF: _ProcDlgReg+Ej
push [ebp+hWnd] ; hWnd
call SetFocus
jmp short loc_401284
loc_4012A1: ; CODE XREF: _ProcDlgReg+17j
; _ProcDlgReg+80j
xor eax, eax
cmp [ebp+wParam], ID_CANCEL
jz short loc_4012F7
cmp [ebp+wParam], ID_CHECK
jnz short loc_4012F0
push 0Bh ; nMaxCount
push offset szUserName ; lpString
push EDT_NAME ; nIDDlgItem
push [ebp+hWnd] ; hDlg
call GetDlgItemTextA
cmp eax, 1
mov [ebp+wParam], ID_CANCEL
jb short loc_4012A1
push 0Bh ; nMaxCount
push offset szSerial ; lpString
push EDT_SERIAL ; nIDDlgItem
push [ebp+hWnd] ; hDlg
call GetDlgItemTextA
mov eax, 1
jmp short loc_4012F7
loc_4012F0: ; CODE XREF: _ProcDlgReg+60j
mov eax, 0
jmp short loc_401284
loc_4012F7: ; CODE XREF: _ProcDlgReg+1Dj
; _ProcDlgReg+57j _ProcDlgReg+9Bj
push eax ; nResult
push [ebp+hWnd] ; hDlg
call EndDialog
mov eax, TRUE
jmp loc_401284
_ProcDlgReg endp
; BOOL __stdcall ProcDlgAbout(HWND hDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)
_ProcDlgAbout proc near ; DATA XREF: _ProcWinMain+C7o
hDlg = dword ptr 8
uMsg = dword ptr 0Ch
wParam = dword ptr 10h
lParam = dword ptr 14h
enter 0, 0
push ebx
push esi
push edi
cmp [ebp+uMsg], WM_COMMAND
jz short loc_40132C
cmp [ebp+uMsg], WM_CLOSE
jz short loc_401335
mov eax, 0
loc_401325: ; CODE XREF: _ProcDlgAbout+3Aj
; _ProcDlgAbout+41j
pop edi
pop esi
pop ebx
leave
retn 10h
loc_40132C: ; CODE XREF: _ProcDlgAbout+Ej
cmp [ebp+wParam], 3F2h
jnz short loc_401346
loc_401335: ; CODE XREF: _ProcDlgAbout+14j
push 0 ; nResult
push [ebp+hDlg] ; hDlg
call EndDialog
mov eax, 1
jmp short loc_401325
loc_401346: ; CODE XREF: _ProcDlgAbout+29j
mov eax, 0
jmp short loc_401325
_ProcDlgAbout endp
sub_40134D proc near ; CODE XREF: _ProcWinMain:loc_40124Cp
push MB_ICONWARNING ; uType
push offset szCapRegSucc ; "Good work!"
push offset szTxtRegSucc ; "Great work, mate!\rNow try the next Crac"...
push dword ptr [ebp+8] ; hWnd
call MessageBoxA
retn
sub_40134D endp
sub_401362 proc near ; CODE XREF: _ProcWinMain+11Dp
push MB_OK ; uType
call MessageBeep
push MB_ICONWARNING ; uType
push offset aNoLuck ; "No luck!"
push offset aNoLuckThereMat ; "No luck there, mate!"
push dword ptr [ebp+8] ; hWnd
call MessageBoxA
retn
sub_401362 endp
sub_40137E proc near ; CODE XREF: _ProcWinMain+105p
arg_0 = dword ptr 4
mov esi, [esp+arg_0]
push esi
loc_401383: ; CODE XREF: sub_40137E+14j
; sub_40137E+1Cj
mov al, [esi]
test al, al
jz short loc_40139C ; 到达串尾
cmp al, 'A'
jb short loc_4013AC
cmp al, 'Z'
jnb short loc_401394
inc esi
jmp short loc_401383
loc_401394: ; CODE XREF: sub_40137E+11j
call sub_4013D2
inc esi
jmp short loc_401383
loc_40139C: ; CODE XREF: sub_40137E+9j
pop esi
call sub_4013C2
xor edi, 5678h
mov eax, edi
jmp short locret_4013C1
loc_4013AC: ; CODE XREF: sub_40137E+Dj
pop esi
push MB_ICONWARNING ; uType
push offset aNoLuck ; "No luck!"
push offset aNoLuckThereMat ; "No luck there, mate!"
push dword ptr [ebp+8] ; hWnd
call MessageBoxA
locret_4013C1: ; CODE XREF: sub_40137E+2Cj
retn
sub_40137E endp
sub_4013C2 proc near ; CODE XREF: sub_40137E+1Fp
xor edi, edi
xor ebx, ebx
loc_4013C6: ; CODE XREF: sub_4013C2+Dj
mov bl, [esi]
test bl, bl
jz short locret_4013D1
add edi, ebx
inc esi
jmp short loc_4013C6
locret_4013D1: ; CODE XREF: sub_4013C2+8j
retn
sub_4013C2 endp
sub_4013D2 proc near ; CODE XREF: sub_40137E:loc_401394p
sub al, 20h
mov [esi], al
retn
sub_4013D2 endp
sub_4013D8 proc near ; CODE XREF: _ProcWinMain+110p
arg_0 = dword ptr 4
xor eax, eax
xor edi, edi
xor ebx, ebx
mov esi, [esp+arg_0]
loc_4013E2: ; CODE XREF: sub_4013D8+1Bj
mov al, 0Ah
mov bl, [esi]
test bl, bl
jz short loc_4013F5
sub bl, '0'
imul edi, eax
add edi, ebx
inc esi
jmp short loc_4013E2
loc_4013F5: ; CODE XREF: sub_4013D8+10j
xor edi, 1234h
mov ebx, edi
retn
sub_4013D8 endp
; HWND hWinMain
hWinMain dd 0 ; DATA XREF: start+C8w start+CFr
; start+DAr
; struct tagMSG stMsg
stMsg tagMSG <0> ; DATA XREF: start+F7o start+107o
; start+111o start:loc_40111Dr
; WNDCLASSA stMyWndClass
stMyWndClass WNDCLASSA <0> ; DATA XREF: start:loc_40101Dw
; start+8Bo start+27w start+31w
; start+3Bw
; HINSTANCE hInstance
hInstance dd 0 ; DATA XREF: start+7w start+45r
; start+97r _ProcWinMain+D4r
; _ProcWinMain+F0r
aTryToCrackMe db 'Try to crack me!',0
; char szNameWinMain[]
szNameWinMain db 'CrackMe v1.0',0 ; DATA XREF: start+B7o
; char szMyClass[]
szMyClass db 'No need to disasm the code!',0 ; DATA XREF: start+Eo
; start+81o start+BCo
szIdMenu db 'MENU',0 ; DATA XREF: start+77o
; char aDlg_regis[]
aDlg_regis db 'DLG_REGIS',0 ; DATA XREF: _ProcWinMain+EBo
; char TemplateName[]
TemplateName db 'DLG_ABOUT',0 ; DATA XREF: _ProcWinMain+CFo
; char szCapRegSucc[]
szCapRegSucc db 'Good work!',0 ; DATA XREF: sub_40134D+2o
; char szTxtRegSucc[]
szTxtRegSucc db 'Great work, mate!',0Dh,'Now try the next CrackMe!',0
; DATA XREF: sub_40134D+7o
; char aNoLuck[]
aNoLuck db 'No luck!',0 ; DATA XREF: sub_401362+9o
; sub_40137E+31o
; char aNoLuckThereMat[]
aNoLuckThereMat db 'No luck there, mate!',0 ; DATA XREF: sub_401362+Eo
; sub_40137E+36o
; char szSerial[]
szSerial db 10h dup(0) ; DATA XREF: _ProcWinMain+10Bo
; _ProcDlgReg+84o
; char szUserName[]
szUserName db 72h dup(0) ; DATA XREF: _ProcWinMain+100o
; _ProcDlgReg+64o
align 1000h
DATA ends
end start
====================以上是代码==================
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!