标 题: 【原创】pb程序调试初探 作 者: lzqgj 时 间: 2007-05-10,22:48:15 链 接: http://bbs./showthread.php?t=44277 软件名称:职称英语学习帮手(综合类) 破解工具:OD,shudepb,pbkill,winhex 破解目的:自用 最近要考职称英语,下载了个职称英语的软件来学习。 未注册的版本只能阅读每个部分第一篇,可惜我的银子不够,只好拿它开刀。 打开程序目录,顿时傻眼:PB程序。关于PB程序的调试可以说网上几乎还没有,可见非常困难。 没有反编译工具几乎是不可能完成的任务。而即使是反编译出来,如果编程功力不够,也很难看出注册方法和写注册机。 而爆破关键跳转目前在网上我还没有搜到跳转的机器码是什么。 调试过程的那个辛苦啊,我只想说:破解=运气+毅力。真的,运气可能是第一位的。 先找工具反编译。试了pbkill,只得到一堆if...else...end if之类的,一句代码也没有出来(可能是pbkill试用版吧?) 在网上又搜到另一个反编译工具shudepb,使用确实很好,支持全局搜索,大大方便找关键代码。 全局搜索提示:"对不起,你尚未注册,只能阅读每一部分的第一篇文章!欢迎注册!",找到以下代码: //Has been Shielded. index = PARENT.ddlb_text.finditem(PARENT.ddlb_text.text,1) index ++ IF index > 1 AND gb_register = FALSE THEN //3 PARENT.ddlb_text.text = PARENT.is_etitle messagebox("提示","对不起,你尚未注册,只能阅读每一部分的第一篇文章!欢迎注册!") THIS.setfocus() RETURN END IF //3 ls_text = PARENT.ddlb_text.text(index) IF ls_text = "" THEN //10 index -- PARENT.ddlb_text.text = PARENT.ddlb_text.text(index) RETURN END IF //10 PARENT.ddlb_text.text = PARENT.ddlb_text.text(index) PARENT.ddlb_text.triggerevent(selectionchanged!) RETURN 这个就是点击“下篇”按钮时的过程,判断是否大于第一题和是否未注册,两者条件都满足时跳出NAG。 gb_register是个全局变量,是否注册的标志。再次搜索gb_register可以找到很多赋值语句,说明程序多处进行校验。 注册过程就不贴了,感觉还是比较复杂,我没看明白,只好想到用爆破的方法。于是艰苦的调试过程开始了。 众所周知,PB程序类似于VB的pcode,是解释执行的,调试时在pbvm80.dll中转, 与pcode又有很大不同,你几乎找不到程序在什么地方进行比较,什么地方根据比较结果进行跳转(至少没有人公开过)。 用OD载入程序,运行,点“下篇”弹出NAG,回到OD,F12暂停,Alt+F9运行,回到程序点确定,程序中断, 不断F8单步执行(按住不放好了),最终发现程序在下面一段反复执行: 10CEEB52 MOV ECX,DWORD PTR SS:[EBP-20] 10CEEB55 XOR EAX,EAX 10CEEB57 ADD ECX,EDX 10CEEB59 MOV AX,WORD PTR DS:[ECX] 10CEEB5C LEA EAX,DWORD PTR DS:[EAX+EAX*2] 10CEEB5F SHL EAX,2 10CEEB62 MOV EBX,DWORD PTR DS:[EAX+10DF2B84] 10CEEB68 LEA EDX,DWORD PTR DS:[EDX+EBX*2+2] 10CEEB6C MOV DWORD PTR DS:[ESI+14],EDX 10CEEB6F MOV EDX,DWORD PTR SS:[EBP-24] 10CEEB72 PUSH EDX 10CEEB73 LEA EDX,DWORD PTR SS:[EBP-E8] 10CEEB79 PUSH EDX 10CEEB7A PUSH EDI 10CEEB7B PUSH ECX 10CEEB7C PUSH ESI 10CEEB7D CALL DWORD PTR DS:[EAX+10DF2B80] --->关键,程序解释入口 10CEEB83 MOV DWORD PTR SS:[EBP-4],EAX 10CEEB86 MOV EAX,DWORD PTR DS:[EDI+24C] 10CEEB8C ADD ESP,14 10CEEB8F TEST EAX,EAX 10CEEB91 JE SHORT PBVM80.10CEEBAA 10CEEB93 PUSH EDI 10CEEB94 MOV DWORD PTR SS:[EBP-4],1 10CEEB9B CALL PBVM80.10CEE640 10CEEBA0 ADD ESP,4 10CEEBA3 MOV DWORD PTR SS:[EBP-18],EAX 10CEEBA6 TEST EAX,EAX 10CEEBA8 JE SHORT PBVM80.10CEEBBF 10CEEBAA MOV EAX,DWORD PTR DS:[ESI+38] 10CEEBAD TEST EAX,EAX 10CEEBAF JE SHORT PBVM80.10CEEBB8 10CEEBB1 MOV DWORD PTR SS:[EBP-4],0 10CEEBB8 MOV EAX,DWORD PTR DS:[ESI+18] 10CEEBBB TEST EAX,EAX 10CEEBBD JE SHORT PBVM80.10CEEB41 根据对pcode的了解,猜测10CEEB7D CALL DWORD PTR DS:[EAX+10DF2B80]即是程序解释的入口。 不断跟踪发现解释原理是这样的:根据EAX值的不同,程序call到不同位置执行不同任务, 如读取程序的代码,然后解释执行程序等。 猜测当EAX=2AC或0C或18时,会读取原程序代码,等于其它一些数值时会执行原程序。 不能直接在10CEEB7D处下断,因为一返回程序就会中断。 于是对“下篇”按钮下WM_lbuttonup消息断点,点击后中断,返回OD,在10CEEB7D处下断,F9运行。 当EAX不等于2AC或0C或18时跟F7进去看看。经过n次(未统计,估计>200), 终于在EAX=93C时找到了需要的代码,跟进去程序为: 10D967B0 MOV ECX,DWORD PTR SS:[ESP+C] 10D967B4 PUSH EBX 10D967B5 PUSH ESI 10D967B6 PUSH EDI 10D967B7 MOV ESI,DWORD PTR DS:[ECX+10E] 10D967BD XOR EBX,EBX 10D967BF LEA EDX,DWORD PTR DS:[ESI-38] 10D967C2 MOV DWORD PTR DS:[ECX+10E],EDX 10D967C8 >MOV EDI,DWORD PTR DS:[ESI-1C] 10D967CB MOV EAX,DWORD PTR DS:[EDX] 10D967CD CMP EAX,EDI --->对应index > 1的比较 10D967CF MOV EAX,1 10D967D4 SETG BL --->对应index > 1的比较 10D967D7 MOV WORD PTR DS:[EDX],BX 10D967DA MOV BL,BYTE PTR DS:[EDX+4] 10D967DD TEST AL,BL 10D967DF JNZ SHORT PBVM80.10D967EA 10D967E1 TEST BYTE PTR DS:[ESI-18],AL 10D967E4 JNZ SHORT PBVM80.10D967EA 10D967E6 XOR EDX,EDX 10D967E8 JMP SHORT PBVM80.10D967EC 10D967EA MOV EDX,EAX 10D967EC MOV ESI,DWORD PTR DS:[ECX+10E] 10D967F2 OR DH,5 10D967F5 POP EDI 10D967F6 MOV WORD PTR DS:[ESI+4],DX 10D967FA MOV EDX,DWORD PTR DS:[ECX+10E] 10D96800 POP ESI 10D96801 POP EBX 10D96802 MOV WORD PTR DS:[EDX+6],7 10D96808 MOV EDX,DWORD PTR DS:[ECX+10E] 10D9680E MOV WORD PTR DS:[EDX+1A],0 10D96814 MOV EDX,DWORD PTR DS:[ECX+10E] 10D9681A ADD EDX,1C 10D9681D MOV DWORD PTR DS:[ECX+10E],EDX 10D96823 RETN 继续跟踪,当EAX=804时,跟进得到如下代码: 10D95580 MOV ECX,DWORD PTR SS:[ESP+C] 10D95584 PUSH EBX 10D95585 PUSH ESI 10D95586 XOR EBX,EBX 10D95588 MOV ESI,DWORD PTR DS:[ECX+10E] 10D9558E LEA EDX,DWORD PTR DS:[ESI-38] 10D95591 MOV DWORD PTR DS:[ECX+10E],EDX 10D95597 MOV AX,WORD PTR DS:[EDX] 10D9559A >CMP AX,WORD PTR DS:[ESI-1C] --->对应gb_register = FALSE的比较 10D9559E MOV EAX,1 10D955A3 SETE BL --->对应gb_register = FALSE的比较 10D955A6 MOV WORD PTR DS:[EDX],BX 10D955A9 MOV BL,BYTE PTR DS:[EDX+4] 10D955AC TEST AL,BL 10D955AE JNZ SHORT PBVM80.10D955B9 10D955B0 TEST BYTE PTR DS:[ESI-18],AL 10D955B3 JNZ SHORT PBVM80.10D955B9 10D955B5 XOR EDX,EDX 10D955B7 JMP SHORT PBVM80.10D955BB 10D955B9 MOV EDX,EAX 10D955BB MOV ESI,DWORD PTR DS:[ECX+10E] 10D955C1 OR DH,5 10D955C4 MOV WORD PTR DS:[ESI+4],DX 10D955C8 MOV EDX,DWORD PTR DS:[ECX+10E] 10D955CE POP ESI 10D955CF POP EBX 10D955D0 MOV WORD PTR DS:[EDX+6],7 10D955D6 MOV EDX,DWORD PTR DS:[ECX+10E] 10D955DC MOV WORD PTR DS:[EDX+1A],0 10D955E2 MOV EDX,DWORD PTR DS:[ECX+10E] 10D955E8 ADD EDX,1C 10D955EB MOV DWORD PTR DS:[ECX+10E],EDX 10D955F1 RETN 找到比较代码还是不能爆破的,因为这些代码是在pbvm80.dll中,程序的正确运行是需要它的。 还要找到原程序的代码并修改。这个可没有现成经验。 我的修改思路是将index > 1改成index > 99999(随便你修改),(gb_register是变量,不容易修改的) 在10D967C8 >MOV EDI,DWORD PTR DS:[ESI-1C]处观察ESI-1C的值为A09420,对A09420下硬件写入断点, 运行时会中断很多次,在最后中断在10D9559A >CMP AX,WORD PTR DS:[ESI-1C]的前一次看, 得到程序读入1F30658处的值(即0),在数据窗口中显示为: 01000000390001000300F40931000100000039000100010006,用Winhex打开程序,搜索, 找到地址:0013AC27处,修改0100为FFFF,保存。 再次运行程序,点下篇,没有NAG了吧? 实际程序还没有爆破完全,但是功能限制已经取消了。 小结一下: 10CEEB7D CALL DWORD PTR DS:[EAX+10DF2B80] 是PB程序解释入口,EAX值不同代表不同功能 我猜测EAX=93C时比较是否大于,EAX=804时比较逻辑值是否相等。 其它的值代表的含义希望大家继续跟踪贴出来分享。 调试程序好累,写文章更累。真的需要很好地耐心。休息一下,明天继续爆破注册。那个稍微容易点。 |
|