我来说说我的破法吧:
(1)OD载入Crackme。
(2)F9运行后,点击窗口菜单(W图标)刷新,在OK按钮上选择“在ClassProc上设消息断点”。断消息201,左键Up。
(3)随机输入注册码,点确定按钮。
(4)这时,会断在User32领空。
(5)“调试/打开或清除Run跟踪”。设置Run跟踪条件为EIP范围位于:401000~404000之间(M图标中程序的.text节范围内,意思是一旦执行到程序领空就停止执行,这样,停止的地址,就是当前点击按钮后程序最近执行的地址)。
(6)“调试/跟踪步入”。会停在程序领空F2断点之
004024FB 3935 14464000 cmp dword ptr [404614], esi
(7)F8到此函数返回(记得清除user32中的消息断点),应该就到了算注册码的函数了:
004011E0 |. 8D4424 04 lea eax, dword ptr [esp+4]
(8)这个函数不长,跑一遍就知道该F7跟入下面的地方进行分析了:
0040120C |. E8 A9FEFFFF call 004010BA
(9)跟入的函数:
004010BA $ 53 push ebx
004010BB . 31C0 xor eax, eax
004010BD . 50 push eax
004010BE . 50 push eax
004010BF . 8B5424 10 mov edx, dword ptr [esp+10]
004010C3 . 8D0C24 lea ecx, dword ptr [esp]
004010C6 . E8 350F0000 call 00402000
004010CB . C74424 04 010>mov dword ptr [esp+4], 1
004010D3 > B8 10000000 mov eax, 10
004010D8 . 3B4424 04 cmp eax, dword ptr [esp+4]
004010DC . 7C 6E jl short 0040114C
004010DE . A1 28464000 mov eax, dword ptr [404628]
004010E3 . 50 push eax
004010E4 . 50 push eax
004010E5 . 68 01000000 push 1
004010EA . FF7424 10 push dword ptr [esp+10]
004010EE . FF7424 10 push dword ptr [esp+10]
004010F2 . E8 590F0000 call 00402050
004010F7 . FF05 28464000 inc dword ptr [404628]
004010FD . A1 28464000 mov eax, dword ptr [404628]
00401102 . 50 push eax
00401103 . 50 push eax
00401104 . 8B5C24 10 mov ebx, dword ptr [esp+10]
00401108 . 83C3 3E add ebx, 3E
0040110B . 53 push ebx
0040110C . E8 1F0F0000 call 00402030
00401111 . 5A pop edx
00401112 . 59 pop ecx
00401113 . 890D 28464000 mov dword ptr [404628], ecx
00401119 . 030D 94404000 add ecx, dword ptr [404094]
0040111F . 0315 94404000 add edx, dword ptr [404094]
00401125 . E8 D6160000 call 00402800
0040112A . 75 1A jnz short 00401146
0040112C . 68 00000000 push 0
00401131 . 68 80404000 push 00404080
00401136 . 68 51404000 push 00404051
0040113B . E8 C10F0000 call 00402101
00401140 . EB 0A jmp short 0040114C
00401142 . 31C0 xor eax, eax
00401144 . EB 6C jmp short 004011B2
00401146 > FF4424 04 inc dword ptr [esp+4]
0040114A .^ 71 87 jno short 004010D3
0040114C > FF3424 push dword ptr [esp]
0040114F . E8 7C0F0000 call 004020D0
00401154 . 89C3 mov ebx, eax
00401156 . 83FB 10 cmp ebx, 10
00401159 . 75 55 jnz short 004011B0
0040115B . FF3424 push dword ptr [esp]
0040115E . 8B15 00464000 mov edx, dword ptr [404600]
00401164 . 59 pop ecx
00401165 . E8 96160000 call 00402800
0040116A . 74 44 je short 004011B0
0040116C . FF35 28464000 push dword ptr [404628]
00401172 . 68 00000000 push 0
00401177 . FF35 28464000 push dword ptr [404628]
0040117D . BA 29404000 mov edx, 00404029 ; ASCII "过关密码是:"
00401182 . E8 99150000 call 00402720
00401187 . 8B5424 0C mov edx, dword ptr [esp+C]
0040118B . E8 90150000 call 00402720
00401190 . FF05 28464000 inc dword ptr [404628]
00401196 . 68 56404000 push 00404056
0040119B . 8B15 94404000 mov edx, dword ptr [404094]
004011A1 . 015424 04 add dword ptr [esp+4], edx
004011A5 . E8 570F0000 call 00402101
004011AA . 8F05 28464000 pop dword ptr [404628]
004011B0 > 31C0 xor eax, eax
004011B2 > FF3424 push dword ptr [esp]
004011B5 . E8 76160000 call 00402830
004011BA . 83C4 08 add esp, 8
004011BD . 5B pop ebx
004011BE . C2 0400 retn 4
(10)分析函数功能。参数输入,结果输出,这就是函数。参数大部分是通过寄存器和栈传入(跟调用规则有关,这个是标准的stdcall调用方式,参数push入栈,子函数负责栈平衡),返回值要么eax要么在入栈参数的指针中,要么在全局变量中。分析一个函数,只要注意入栈的指针参数,eax返回值就可以了,如果两者都没有变化,跟进去看看有没有改写什么全局变量,在数据窗口中监视函数执行前后其变化就可以分析出个大概了。
这部分就是最考验耐心的地方了……
我跟了很久(我智商低)发现:
00402050这个函数的作用我通过改变输入参数发现,它的大致作用是从制定字符串的指定位置提取指定长度的子串。结果保存在全局变量* [404094]处:
004010DE . A1 28464000 mov eax, dword ptr [404628]
004010E3 . 50 push eax
004010E4 . 50 push eax
004010E5 . 68 01000000 push 1
004010EA . FF7424 10 push dword ptr [esp+10]
004010EE . FF7424 10 push dword ptr [esp+10]
004010F2 . E8 590F0000 call 00402050
紧接着的部分:
00401104 . 8B5C24 10 mov ebx, dword ptr [esp+10]
00401108 . 83C3 3E add ebx, 3E
0040110B . 53 push ebx
0040110C . E8 1F0F0000 call 00402030
的作用是取真正的注册码。
再下面的就是比较二者是否相等。
00401111 . 5A pop edx
00401112 . 59 pop ecx
00401113 . 890D 28464000 mov dword ptr [404628], ecx
00401119 . 030D 94404000 add ecx, dword ptr [404094]
0040111F . 0315 94404000 add edx, dword ptr [404094]
00401125 . E8 D6160000 call 00402800
0040112A . 75 1A jnz short 00401146
数据窗口中监视:(我随机输入的注册码:1234567890abcdef)
(手工改变比较结果)
第一次:
008F06A0 31 00 3F 00 35 36 37 38 39 30 61 62 63 64 65 66 1.?.567890abcdef
第二次:
008F06A0 32 00 40 00 35 36 37 38 39 30 61 62 63 64 65 66 2.@.567890abcdef
第三次:
008F06A0 33 00 41 00 35 36 37 38 39 30 61 62 63 64 65 66 3.A.567890abcdef
……
很显然真正的注册码就是?@A.......,当然如果分析出了00402030函数的作用,也不同这样循环者提取。
讲点心得,多多交流。