通过设置killtimer关键字函数断点进行寻找突破口
断点设置完成之后,开始运行软件,直到运行到我们想看到的输入注册码窗口,后输入错误的注册码,进行测试
输入完成之后OD上显示断点的位置如下:
004DC19D > \83F8 03 cmp eax,0x3
004DC1A0 . 75 1E jnz short DVDMenuS.004DC1C0
004DC1A2 . 8B57 1C mov edx,dword ptr ds:[edi+0x1C] ; Case 3 of switch 004DBDA4
004DC1A5 . 50 push eax ; /TimerID = 0x3
004DC1A6 . 52 push edx ; |hWnd = 00080D4C ('DVD Menu Studio - [Untitled]',class='Afx:400000:8:10003:0:1560cb3')
004DC1A7 . FF15 B4575E00 call dword ptr ds:[<&USER32.KillTimer>] ; \KillTimer
004DC1AD . 6A 00 push 0x0
004DC1AF . 6A 00 push 0x0
004DC1B1 . 68 5C666400 push DVDMenuS.0064665C ; ASCII "The registration code seems to be not valid.\nPlease check if you didn't made any mistake."
004DC1B6 . E8 919D0D00 call DVDMenuS.005B5F4C
004DC1BB . E9 B7000000 jmp DVDMenuS.004DC277
004DC1C0 > 83F8 04 cmp eax,0x4
004DC1C3 . 75 1E jnz short DVDMenuS.004DC1E3
004DC1C5 . 50 push eax ; /TimerID = 0x3; Case 4 of switch 004DBDA4
004DC1C6 . 8B47 1C mov eax,dword ptr ds:[edi+0x1C] ; |
004DC1C9 . 50 push eax ; |hWnd = 00000003
004DC1CA . FF15 B4575E00 call dword ptr ds:[<&USER32.KillTimer>] ; \KillTimer
004DC1D0 . 6A 00 push 0x0
004DC1D2 . 6A 00 push 0x0
004DC1D4 . 68 FC656400 push DVDMenuS.006465FC ; ASCII "Thank you for your support!\nPlease Exit the Software and start it again to validate the code."
004DC1D9 . E8 6E9D0D00 call DVDMenuS.005B5F4C
004DC1DE . E9 94000000 jmp DVDMenuS.004DC277
004DC1E3 > 83F8 05 cmp eax,0x5
004DC1E6 . 75 15 jnz short DVDMenuS.004DC1FD
此时发现注册成功的标志位置:
004DC1D4 . 68 FC656400 push DVDMenuS.006465FC ; ASCII "Thank you for your support!\nPlease Exit the Software and start it again to validate the code."
那通过观察上下汇编指令,可知要让其在等于4的时候成立,做到jnz指令不跳转从而实现破解成功。
这是主体实现破解成功思路。
通过分析,我门要找其根源,那么我们就跟进下去,从比较条件为3的时候向上跟踪。
004DC19D > \83F8 03 cmp eax,0x3
从此处开始, 发现其跳转来自eax=00000003
跳转来自 004DC04C
通过操作跳转如下:
004DC049 > \83F8 02 cmp eax,0x2
004DC04C . 0F85 4B010000 jnz DVDMenuS.004DC19D
再根据其条件不等于2 查看跳转来自的地址进行回溯跟踪。
004DC049 > \83F8 02 cmp eax,0x2
eax=00000003
跳转来自 004DBE01
跳转到下面
004DBDFE > \83F8 07 cmp eax,0x7
004DBE01 . 0F85 42020000 jnz DVDMenuS.004DC049
同上
004DBDFE > \83F8 07 cmp eax,0x7
eax=00000003
跳转来自 004DBDA9
跳转如下:
004DBDA4 . 83F8 01 cmp eax,0x1 ; Switch (cases 1..B)
004DBDA7 . 8BF9 mov edi,ecx
004DBDA9 . 75 53 jnz short DVDMenuS.004DBDFE
004DBDAB . 50 push eax ; /TimerID = 0x3; Case 1 of switch 004DBDA4
此时发现跳转到程序的开头入口点
使用的是switch 语句结构进行跳转,跳转条件从1-B
在程序的开头设置断点,重新跑程序,查看程序运行过程的eax的值这么发送变化的。
观察可知,程序通过switch循环,进行判断,当输入错误的注册码时,eax=3,那么程序运行到这个位置和3进行比较相等,那么就跳转,
执行到错误提示的位置如下:
004DC1D4 . 68 FC656400 push DVDMenuS.006465FC ; ASCII "Thank you for your support!\nPlease Exit the Software and start it again to validate the code."
那么此处突破口的关键位置如下:
004DBD9E . 8B45 08 mov eax,dword ptr ss:[ebp+0x8]
004DBDA1 . 53 push ebx ; DVDMenuS.004DBD80
004DBDA2 . 56 push esi
004DBDA3 . 57 push edi
004DBDA4 . 83F8 01 cmp eax,0x1 ; Switch (cases 1..B)
上述理论上通过更改 004DBD9E . 8B45 08 mov eax,dword ptr ss:[ebp+0x8] 为 mov eax, 4
便可得到破解的目的,但通过测试发现,如果这样修改第一个会导致增加后源程序多了两个字节的数据,这样就会导致堆栈不对称平衡,
从而影响整个程序运行,或者运行不正常,那么我们就不能这样修改,所以此处要用到经典的破解手法就是内联补丁。
内联补丁:表示就是通过找到程序中没有实际代码指令的位置,添加要破解的指令,通过互相跳转来实现不影响程序运行的目的实现最终的破解。
制作内联补丁(内嵌补丁)
005E47C0 00 db 00
005E47C1 00 db 00
005E47C2 00 db 00
005E47C3 00 db 00
005E47C4 00 db 00
005E47C5 00 db 00
005E47C6 00 db 00
005E47C7 00 db 00
005E47C8 00 db 00
005E47C9 00 db 00
005E47CA 00 db 00
005E47CB 00 db 00
005E47CC 00 db 00
005E47CD 00 db 00
005E47CE 00 db 00
005E47CF 00 db 00
005E47D0 00 db 00
005E47D1 00 db 00
005E47D2 00 db 00
类似找到上面没有编写汇编指令的代码处,在内嵌补丁的过程中 尽量不要在刚开始的位置进行内嵌,要尽量空出几行进行,
那么从地址 005E47D0 开始
根据下面的关键代码位置进行更改
004DBD9E > . 8B45 08 mov eax,dword ptr ss:[ebp+0x8]
004DBDA1 . 53 push ebx ; DVDMenuS.004DBD80
004DBDA2 . 56 push esi
004DBDA3 . 57 push edi
更改如下:
005E47D0 > B8 04000000 mov eax,0x4
005E47D5 53 push ebx ; DVDMenuS.004DBD80
005E47D6 56 push esi
005E47D7 00 db 00
然后到 地址 004DBD9E 处将其更改为 jmp 005E47D0
让程序运行到此处跳转至我们设置好的内嵌补丁
然后在地址 005E47D7 添加jmp 004DBDA3 让其跳转至正常程序的下面代码执行后面的流程,如下:
004DBD9E > /E9 2D8A1000 jmp <DVDMenuS.添加内嵌补丁的开头位置>
004DBDA3 . |57 push edi
上面操作 导致一个死循环,还没有完全破解。
所以通过整体观察,发现switch在跳转到B的时候,就会跳出循环,最终将其改为如下:
005E47D0 B8 0B000000 mov eax,0xB
005E47D5 . 53 push ebx
005E47D6 . 56 push esi
005E47D7 .^ E9 C775EFFF jmp DVDMenuS.004DBDA3
将005E47D0 B8 0B000000 mov eax,0xB 改为等于B 就跳出循环,成功破解。
005ABE4D $ B8 442D5E00 mov eax,DVDMenuS.005E2D44
004DC0D1 . E8 77FD0C00 call DVDMenuS.005ABE4D
执行完整个程序,堆栈的调用过程
调用堆栈: 主线程
地址 堆栈 函数过程 / 参数 调用来自 结构
0018FA60 758C7C1D user32.758C78C2 user32.758C7C18 0018FA7C
0018FA80 005B044F user32.GetMessageA DVDMenuS.005B0449 0018FA7C
0018FA84 00662858 pMsg = DVDMenuS.00662858
0018FA88 00000000 hWnd = NULL
0018FA8C 00000000 MsgFilterMin = 0x0
0018FA90 00000000 MsgFilterMax = 0x0
0018FA9C 005AF0A2 包含DVDMenuS.005B044F DVDMenuS.005AF09F
0018FAC0 005ABF2E DVDMenuS.005AEFC8 DVDMenuS.005ABF29
0018FAFC 004DC0D6 ? DVDMenuS.005ABE4D DVDMenuS.004DC0D1
我们查找的话,也要查找最后的那个调用来自, 要从这里找,找到调用nag窗口的来源地址,然后双击,进入
当找到这个关键的地址,就要在这个关键位置的上下文的开始下个断点进行跟进
另一种方法,牛逼而且简单,待强化
将004DBDC5 /75 1F jnz short DVDMenuS.004DBDE6
修改为nop保存即可。