软件名称:职称英语学习帮手(综合类)
破解工具: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时比较逻辑值是否相等。
其它的值代表的含义希望大家继续跟踪贴出来分享。
调试程序好累,写文章更累。真的需要很好地耐心。休息一下,明天继续爆破注册。那个稍微容易点。
- 标 题: pb程序调试初探
- 作 者:lzqgj
- 时 间:2007-05-10 22:48
- 链 接:http://bbs.pediy.com/showthread.php?t=44277