参考
书:《加密与解密》
视频:小甲鱼 解密系列 视频
示例程序下载地址:http://pan.baidu.com/s/1hqBrJWo
方法一:内嵌补丁
加载程序,按F9运行,点击Enter Reg.Code 输入name,key等,先不要按OK ,到OD中 按Ctrl+N打开输入输出表,搜索KillTimer,设置断点。再点击注册窗口的OK,我们可以看见:
(也可以通搜索注册失败时弹出窗口中的“The registration code seems to be not valid” 来找到下面代码)
004DC19D > \83F8 03 cmp eax, 3 004DC1A0 . 75 1E jnz short 004DC1C0 004DC1A2 . 8B57 1C mov edx, dword ptr [edi+1C] ; Case 3 of switch 004DBDA4 004DC1A5 . 50 push eax ; /TimerID 004DC1A6 . 52 push edx ; |hWnd 004DC1A7 . FF15 B4575E00 call dword ptr [<&USER32.KillTimer>] ; \KillTimer 004DC1AD . 6A 00 push 0 004DC1AF . 6A 00 push 0 004DC1B1 . 68 5C666400 push 0064665C ; ASCII "The registration code seems to be not valid.",LF,"Please check if you didn't made any mistake." 004DC1B6 . E8 919D0D00 call 005B5F4C 004DC1BB . E9 B7000000 jmp 004DC277 004DC1C0 > 83F8 04 cmp eax, 4 004DC1C3 . 75 1E jnz short 004DC1E3 004DC1C5 . 50 push eax ; /TimerID; Case 4 of switch 004DBDA4 004DC1C6 . 8B47 1C mov eax, dword ptr [edi+1C] ; | 004DC1C9 . 50 push eax ; |hWnd 004DC1CA . FF15 B4575E00 call dword ptr [<&USER32.KillTimer>] ; \KillTimer 004DC1D0 . 6A 00 push 0 004DC1D2 . 6A 00 push 0 004DC1D4 . 68 FC656400 push 006465FC ; ASCII "Thank you for your support!",LF,"Please Exit the Software and start it again to validate the code." 004DC1D9 . E8 6E9D0D00 call 005B5F4C 004DC1DE . E9 94000000 jmp 004DC277 004DC1E3 > 83F8 05 cmp eax, 5 004DC1E6 . 75 15 jnz short 004DC1FD 004DC1E8 . 8B4F 1C mov ecx, dword ptr [edi+1C] ; Case 5 of switch 004DBDA4 004DC1EB . 50 push eax ; /TimerID 004DC1EC . 51 push ecx ; |hWnd 004DC1ED . FF15 B4575E00 call dword ptr [<&USER32.KillTimer>] ; \KillTimer 004DC1F3 . 6A FF push -1 ; /ExitCode = FFFFFFFF 004DC1F5 . FF15 D0545E00 call dword ptr [<&KERNEL32.ExitProces>; \ExitProcess 004DC1FB . EB 7A jmp short 004DC277 004DC1FD > 83F8 06 cmp eax, 6 004DC200 . 75 0D jnz short 004DC20F 004DC202 . 8B57 1C mov edx, dword ptr [edi+1C] ; Case 6 of switch 004DBDA4 004DC205 . 50 push eax ; /TimerID 004DC206 . 52 push edx ; |hWnd 004DC207 . FF15 B4575E00 call dword ptr [<&USER32.KillTimer>] ; \KillTimer 004DC20D . EB 68 jmp short 004DC277 004DC20F > 83F8 0A cmp eax, 0A 004DC212 . 75 2D jnz short 004DC241 004DC214 . 50 push eax ; /TimerID; Case A of switch 004DBDA4 004DC215 . 8B47 1C mov eax, dword ptr [edi+1C] ; | 004DC218 . 50 push eax ; |hWnd 004DC219 . FF15 B4575E00 call dword ptr [<&USER32.KillTimer>] ; \KillTimer 004DC21F . 8B17 mov edx, dword ptr [edi] 004DC221 . 8BCF mov ecx, edi 004DC223 . FF92 C0000000 call dword ptr [edx+C0] 004DC229 . 85C0 test eax, eax 004DC22B . 74 4A je short 004DC277 004DC22D . 8BC8 mov ecx, eax 004DC22F . E8 772D0E00 call 005BEFAB 004DC234 . 85C0 test eax, eax 004DC236 . 74 3F je short 004DC277 004DC238 . 8BC8 mov ecx, eax 004DC23A . E8 F13EFEFF call 004C0130 004DC23F . EB 36 jmp short 004DC277 004DC241 > 83F8 0B cmp eax, 0B 004DC244 . 75 31 jnz short 004DC277 004DC246 . 50 push eax ; /TimerID; Case B of switch 004DBDA4 004DC247 . 8B47 1C mov eax, dword ptr [edi+1C] ; | 004DC24A . 50 push eax ; |hWnd 004DC24B . FF15 B4575E00 call dword ptr [<&USER32.KillTimer>] ; \KillTimer 004DC251 . E8 F3570E00 call 005C1A49 004DC256 . 8B40 04 mov eax, dword ptr [eax+4] 004DC259 . 6A 00 push 0 004DC25B . 68 B03C6400 push 00643CB0 ; ASCII "ResetToolbars" 004DC260 . 68 1CF16300 push 0063F11C ; ASCII "Settings" 004DC265 . 8BC8 mov ecx, eax 004DC267 . E8 255C0E00 call 005C1E91 004DC26C . 85C0 test eax, eax 004DC26E . 74 07 je short 004DC277 004DC270 . 8BCF mov ecx, edi 004DC272 . E8 99190000 call 004DDC10 004DC277 > 8BCF mov ecx, edi ; Default case of switch 004DBDA4 004DC279 . E8 51040D00 call 005AC6CF 004DC27E . 8B4D F4 mov ecx, dword ptr [ebp-C] 004DC281 . 5F pop edi 004DC282 . 5E pop esi 004DC283 . 5B pop ebx 004DC284 . 64:890D 00000>mov dword ptr fs:[0], ecx 004DC28B . 8BE5 mov esp, ebp 004DC28D . 5D pop ebp 004DC28E . C2 0400 retn 4
这些代码其实是 swith,现在代码eax为3,正要运行case 3 处的代码。观察每个case,可以发现 case 4 中的"Thank you for your support!",我们可以知道可能case 4 就是注册成功。我们就要想办法把swith 3 改成 swith 4。
我们先前看看,看看swith开始的代码
004DBD80 . 55 push ebp 004DBD81 . 8BEC mov ebp, esp 004DBD83 . 6A FF push -1 004DBD85 . 68 17B85D00 push 005DB817 ; SE 处理程序安装 004DBD8A . 64:A1 0000000>mov eax, dword ptr fs:[0] 004DBD90 . 50 push eax 004DBD91 . 64:8925 00000>mov dword ptr fs:[0], esp 004DBD98 . 81EC 68010000 sub esp, 168 004DBD9E . 8B45 08 mov eax, dword ptr [ebp+8] 004DBDA1 . 53 push ebx 004DBDA2 . 56 push esi 004DBDA3 . 57 push edi 004DBDA4 . 83F8 01 cmp eax, 1 ; Switch (cases 1..B) 004DBDA7 . 8BF9 mov edi, ecx 004DBDA9 . 75 53 jnz short 004DBDFE 004DBDAB . 50 push eax ; /TimerID; Case 1 of switch 004DBDA4 004DBDAC . 8B47 1C mov eax, dword ptr [edi+1C] ; | 004DBDAF . 50 push eax ; |hWnd 004DBDB0 . FF15 B4575E00 call dword ptr [<&USER32.KillTimer>] ; \KillTimer 004DBDB6 . E8 8E5C0E00 call 005C1A49
在004DBD80 下断点,删除前面KillTimer设置的断点,重新运行程序。多按几次F9(下断点处的地方,在程序界面产生前就调用了,所以多按几次F9),可以看到程序的界面,打开注册窗口,输入信息,点击OK,发现程序断在前面下断点的地方。
按F8单步运行, 可以发现 mov eax, dword ptr [ebp+8] ,就是设置swith中eax的值。可以尝试把它改成mov eax ,4,但是我们可以发现原来的代码占用3个字节,改后的代码占用5个字节,后面的代码push ebx, push esi被覆盖了。
这时我们可以用内嵌补丁,先把mov eax, dword ptr [ebp+8]改成jmp xxx到空白的代码处,再在空白的代码处写上要执行的代码,再跳回来。
这里我们可以把mov eax, dword ptr [ebp+8] 改成jmp 005E47CC
再在005E47CC 写上下面的代码
005E47CB 00 db 00 005E47CC B8 04000000 mov eax, 4 005E47D1 . 53 push ebx 005E47D2 . 56 push esi 005E47D3 .^ E9 CB75EFFF jmp 004DBDA3 005E47D8 00 db 00
复制到可执行程序,正常运行程序,可以发现,程序打开时一直弹出"Thank you for your support!"的窗口。调试改后的程序,我们可以发现原来程序一直在循环的执行swith,因为我们改成了switch 4,所以一直弹出"Thank you for your support!"的窗口。其实这个程序只是因为过期后前面有一个让我们输入key的nag窗口而不可以使用,我们只要让这个nag窗口不出现就可以了。我们可以让他switc 0B,0b既不会弹出“The registration code seems
to be not valid” 窗口,也不会弹出"Thank you for your support!"的窗口。把 mov eax, 4 改成 mov eax, 0b 复制到可执行程序,再正常运行程序,可以发现程序可以正常运行。
方法二: 查看调用堆栈
此程序,因为产生了一个不可以跳过的nag窗口而不能使用,可以通过改变跳转,使程序不执行nag窗口的代码,来破解。
查找产生nag窗口的代码
重新加载程序,删掉前面设置的断点,按F9运行程序,看到nag窗口出现时,暂停程序,按 alt+K 查看堆栈调用,
图片1
点击最下面的 ”调用来自“。查看代码(点击 函数过程 是看函数的具体代码,点击 调用来自 是看call)
在这个call上下断点,重新运行程序,
图片2
可以发现真是这个call产生了nag窗口。
查找这段代码的开头(即找push ebp)
图片3
在push ebp 下断点重新运行程序,按F9运行,来到断点处。
按F8单步运行,变按边注意跳转,改变寄存器 ,使程序跳过call 005ABE4D。
可以发现只要使 jnz short 004DBDE6 不跳转即可以实现跳过call 005ABE4D。