前往Shuct.Net首页

Shudepb PB反编译专家长时间以来,为业内同类软件事实上的唯一选择.细节,彰显专业.态度,决定品质.

关于PBKILLER的搜索

【原创】pb程序调试初探 [文字模式] - 看雪安全论坛 看雪安全论坛 > Windows > 『软件调试逆向』 > 【原创】pb程序调试初探 PDA 查看完整版本 : 【原创】pb程序调试初探 lzqgj2007-05-10, 22:48:15软件名称:职称英语学习帮手(综合类) 破解工具: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时比较逻辑值是否相等。 其它的值代表的含义希望大家继续跟踪贴出来分享。 调试程序好累,写文章更累。真的需要很好地耐心。休息一下,明天继续爆破注册。那个稍微容易点。 lzqgj2007-05-11, 08:32:13今天讲一下爆破注册这个程序。 反编译显示程序调用sapiyy.dll、RegClient.dll进行注册。在OD中查看sapiyy.dll的函数名称,发现很多与注册有关的函数: 名称位于 sapiyy 地址 名称 注释 01ADA1AC RegClient.CheckRegister 01AD2860 DoCheckRegister 检查是否注册 01AD22C0 _DoCheckRegister2@16 01AD2DC0 DoRegister 01AD2CF0 DoUnRegister 01ADA1B8 RegClient.GetErrorString 01AD1780 gethdserial 获取硬件ID 01AD1A80 getsourestring1024 01AD1D40 getsourestring128 01AD1BE0 getsourestring256 01AD1920 getsourestring512 好像是加密注册码的逆向处理 01ADA1B4 RegClient.GetTokenString 01ADA17C MSVCRT._mbscmp 01ADA1A8 RegClient.Register 01AD17D0 secstring 注册码处理函数 01ADA1B0 RegClient.UnRegister 在gethdserial函数上下断,F9运行,中断后F12返回,程序回到这里(在pbvm80.dll中): 10BBB5E3 POP ESI 10BBB5E4 POP EDI 10BBB5E5 CALL DWORD PTR SS:[EBP+8] 10BBB5E8 CMP ESP,DWORD PTR SS:[EBP-8] --->停在这 10BBB5EB JE SHORT PBVM80.10BBB5F7 明显10BBB5E5 CALL DWORD PTR SS:[EBP+8] 这句就是调用函数。下断,F9运行。 发现它会call到不同地址。原来这就是pb程序调用外部函数的入口。 如果想跟踪注册算法,在这里下断应该可以得到一些信息,因为程序调用外部函数处理注册码的。 但是我对追注册码实在没有信心,我只想找到爆破的地方。 如果程序调用外部函数判断是否注册并返回bool值,那我们修改返回值不就OK? 下断后继续运行,每次中断看看Call的外部函数名称,觉得是判断注册的就跟进去,如果是处理注册码的就继续运行。 终于在一次下断后来到DoCheckRegister函数。跟进去看: 01AD2860 >SUB ESP,1C4 01AD2866 PUSH ESI 01AD2867 PUSH EDI 01AD2868 MOV EDI,DWORD PTR SS:[ESP+1D8] 省略部分代码 01AD28D8 PUSH EAX 01AD28D9 PUSH ECX 01AD28DA PUSH sapiyy.01ADDC30 01AD28DF PUSH sapiyy.01ADDC30 01AD28E4 PUSH sapiyy.01ADC3BC ; ASCII "I0qOWoaJ584Lz/CUMSi3qN4anWMV6Zox" 01AD28E9 PUSH sapiyy.01ADC398 ; ASCII "gX93+hAOo1HQnq1enogxlpL2kp0gUgF7" 01AD28EE PUSH EDX 01AD28EF PUSH sapiyy.01ADC294 ; ASCII "smskb" 01AD28F4 CALL <JMP.&RegClient.CheckRegister> 01AD28F9 CMP EAX,9 01AD28FC JNZ SHORT sapiyy.01AD290B 01AD28FE POP EDI 01AD28FF XOR EAX,EAX 01AD2901 POP ESI 01AD2902 ADD ESP,1C4 01AD2908 RETN 10 省略部分代码 01AD295E PUSH EAX 01AD295F PUSH ECX 01AD2960 PUSH sapiyy.01ADDC30 01AD2965 PUSH sapiyy.01ADDC30 01AD296A PUSH sapiyy.01ADC3BC ; ASCII "I0qOWoaJ584Lz/CUMSi3qN4anWMV6Zox" 01AD296F PUSH sapiyy.01ADC398 ; ASCII "gX93+hAOo1HQnq1enogxlpL2kp0gUgF7" 01AD2974 PUSH EDX 01AD2975 PUSH sapiyy.01ADC294 ; ASCII "smskb" 01AD297A CALL <JMP.&RegClient.CheckRegister> 01AD297F MOV EDX,EAX 01AD2981 CMP EDX,ESI 01AD2983 JE SHORT sapiyy.01AD29EF 01AD2985 CMP EDX,1F 01AD2988 JE sapiyy.01AD2CD9 01AD298E CMP EDX,25 01AD2991 JE sapiyy.01AD2CD9 01AD2997 CMP EDX,26 01AD299A JE sapiyy.01AD2CD9 01AD29A0 CMP EDX,27 01AD29A3 JE sapiyy.01AD2CD9 01AD29A9 CMP EDX,28 01AD29AC JE sapiyy.01AD2CD9 01AD29B2 CMP EDX,29 01AD29B5 JE sapiyy.01AD2CD9 01AD29BB CMP EDX,2A 01AD29BE JE sapiyy.01AD2CD9 01AD29C4 MOV ECX,20 01AD29C9 XOR EAX,EAX 01AD29CB LEA EDI,DWORD PTR SS:[ESP+C8] 01AD29D2 REP STOS DWORD PTR ES:[EDI] 01AD29D4 LEA EAX,DWORD PTR SS:[ESP+C8] 01AD29DB PUSH EAX 01AD29DC PUSH EDX 01AD29DD CALL <JMP.&RegClient.GetErrorString> 01AD29E2 POP EDI 01AD29E3 XOR EAX,EAX 01AD29E5 POP ESI 01AD29E6 ADD ESP,1C4 01AD29EC RETN 10 看到的那一串古怪字符明显与注册码有关。看ret前几个代码,发现: 01AD29DD CALL <JMP.&RegClient.GetErrorString> 01AD29E2 POP EDI 01AD29E3 XOR EAX,EAX 应该是注册不成功的置0标志位。修改EAX为1,运行,程序不再有注册提示,按钮变成了“注销注册”。成功! 小结: pb程序本身调试是很困难的,但是如果调用外部程序注册调试起来将会轻松得多,因为调用地址是固定的, 只要在调用处下断,可以清楚看到用到哪些函数进行运算注册。 写这篇文章没有其它目的,纯粹是为了方便自己记忆,没有太多技术上的东西,pb与vb pcode相似,但不同之处有太多,难度大很多。 一段代码执行起来跟踪要很久,下面这三行就花了我将近1个小时才找关键,真的需要运气。 index = PARENT.ddlb_text.finditem(PARENT.ddlb_text.text,1) index ++ IF index > 1 AND gb_register = FALSE THEN //3 pb程序没有直接读取原程序,而是将原程序的代码先复制到临时地址,然后不断读取临时地址并执行。 所以调试时找到临时地址还是不够的,还要找到原程序的地址才能爆破,很多机器码如jz、jnz等我也不知道是什么。 毕竟网上有关pb的调试太少了,各位老大可能都是直接反编译写出注册机的。我没有这个本事,只有寻求爆破了。 真的希望各位同仁能多写些pb调试的文章,把经验放给大家共享,让pb程序的破解不再是难题。 founder2007-05-11, 11:09:33学习了,多谢! lzqgj2007-05-13, 08:08:01再次跟踪发现:pb调用os_callc函数来执行外部函数。 10CDD898 CALL PBVM80.os_callc 对pb了解太少,今天才发现原来pb也有类似于vb一样的Native和Pcode的两种编译方式。 Pcode是在dll里打转的,Native还是在主程序中运行,调用pb的函数来进行运算,这种方式的程序破解难度小很多。 比如今天调试的某机动车模拟考试软件,用了类似Vb的Native方式的编译。几个主要代码如下: 004AAD27 CALL <JMP.&PBVM80.#2384> 跟进: 0071C09E JMP DWORD PTR DS:[<&PBVM80.#2384>] ; PBvm80.ob_invoke_static 调用原程序的子过程,一般F8过去,但往往也会跳过注册算法。开始跟进去就在这里就跟丢了,以为进到dll里出不来了。 004AAE63 CALL <JMP.&PBVM80.#2611> 跟进: 0071BFF0 JMP DWORD PTR DS:[<&PBVM80.#2611>] ; PBvm80.ot_ansi_strcmp 比较函数,再次跟进 发现调用msvcrt.dll 的 _mbscmp函数进行比较,几乎pb程序都用这个比较字符串。 Tee80882007-05-13, 10:48:59我这两天也在弄PB的东西, PBKILLER的作者Kevins哪位兄弟联系的到呀。 elance2007-05-13, 10:51:33PB的,这个得学习下 pizigao2007-05-14, 08:31:35PB的东西还是蛮头大的~ rensd2007-05-24, 12:56:44试着照楼主所写的破解了一下,消息断点不知道怎么下,所以没有完成破解。我用了你说的第二种爆破方式,修改了一个字节,爆破成功,感谢楼主,帮我省了100多块钱,呵呵。 modi2007-05-24, 19:56:18好少有爆破的,学习.. xyu2007-05-25, 14:01:32再次跟踪发现:pb调用os_callc函数来执行外部函数。 10CDD898 CALL PBVM80.os_callc 对pb了解太少,今天才发现原来pb也有类似于vb一样的Native和Pcode的两种编译方式。 Pcode是在dll里打转的,Native还是在主程序中运行,调用pb的... 楼主,请问可以提供下那个shudepb软件的下载网址吗,我下了个demo版本没有什么用处哦:confused: lzqgj2007-05-25, 20:47:25楼主,请问可以提供下那个shudepb软件的下载网址吗,我下了个demo版本没有什么用处哦:confused: 我的也是Demo版的,好像没有太多限制,反正反出来能找到想要的信息就行了。 xyu2007-05-26, 22:29:48看来也只能是移花接木了,去把代码放pb的工程里面去试试! ssw2007-05-27, 17:12:34新手,不太懂! ssw2007-05-27, 17:41:27楼主能否给职称英语2007理工类的爆破写出来一下,我搞了一天没搞出来,谢谢了! lzqgj2007-05-28, 14:54:43楼主能否给职称英语2007理工类的爆破写出来一下,我搞了一天没搞出来,谢谢了! 这一系列的软件方法应该是一样的吧?你再试试? 如果pb程序调用外部dll判断是否注册的,一般修改返回值即可, 否则pb程序的jz和jnz的代码到底是什么都不知道,所以如果在pb中爆破修改跳转不方便,我的思路是修改比较的地方,如: cmp (ifreged)=1 jz reged 一般改成jmp或jnz 改成 cmp (ifreged)=0 jz reged 如此只要在程序中找到那个1的标志所在改成0 就可以。 wudiweiwei2007-05-28, 23:44:40pb关键指令 >c5 <d1 <>b5 =a5 <=e9 >=dd or 22 and 21 not 23 ture 01 false 00 return 39 lzqgj2007-05-29, 08:06:22pb关键指令 >c5 <d1 <>b5 =a5 <=e9 >=dd or 22 and 21 not 23 ture 01 false 00 return 39 太好了,谢谢!找这个很久了! donpps2007-05-29, 10:09:27补充一点: return ture 39 00 01 (从01到FF都可) return false 39 00 00 return 1 (0-255) 30 00 01 (从00到FF) 实际上会因为比较对象的不同、句式的不同代码会有变化,实践中的一些例子: ------------------------------------------ 00077b50h: 00 00 00 1B 00 01 00 1B 00 02 00 CA 00 00 00 00 ; ...........?... if ls_fxrq > ls_jzrq then beep(1) messagebox("错误号(007)","已过数据服务期(咨询电话:010-88578174,88578175)!",stopsign!) return true else return false end if 00077b50h: 00 00 00 1B 00 01 00 1B 00 01 00 BF 00 00 00 00 ; ...........?... if ls_fxrq <> ls_fxrq then beep(1) messagebox("错误号(007)","已过数据服务期(咨询电话:010-88578174,88578175)!",stopsign!) return true else return false end if -------------------------------- 00075bc0h: 40 BD 01 12 01 02 00 00 00 38 01 02 00 D6 00 01 ; @?......8...?. if ls_jzrq < string(today(),"yyyy.mm.dd") then messagebox("提示","你已经超过使用期限,请尽快缴服务费!") return else run("smart.exe") end if return 00075bc0h: 40 BD 01 12 01 02 00 00 00 38 01 02 00 AE 00 01 ; @?......8...?. if ls_jzrq = string(today(),"yyyy.mm.dd") then messagebox("提示","你已经超过使用期限,请尽快缴服务费!") return else run("smart.exe") end if return // D6 < ; CA > ; BF <> ;AE = ; ---------------------------------------- 0006fe30h: 00 38 01 02 00 31 00 1E 00 00 00 E9 00 02 00 D6 ; .8...1.....?.. if daysafter(today(),date(ls_jzrq)) <= 30 then ls_temp = string(daysafter(today(),date(ls_jzrq))) dw_1.modify("t_1.visible='1'") dw_1.modify("t_1.text='您还有" + ls_temp + "天的使用时间,请尽快升级!'") end if 0006fe30h: 00 38 01 02 00 31 00 00 00 00 00 A5 00 02 00 D6 ; .8...1.....?.. if daysafter(today(),date(ls_jzrq)) = 0 then ls_temp = string(daysafter(today(),date(ls_jzrq))) dw_1.modify("t_1.visible='1'") dw_1.modify("t_1.text='您还有" + ls_temp + "天的使用时间,请尽快升级!'") end if // D1 <; C5 > ; B5 <> ; A5 = ; ---------------------------------------- 00015a69h: 00 1B 00 01 00 A3 01 00 00 38 00 08 00 00 00 AA ; .....?..8.....? 00015a79h: 00 00 00 01 00 1B 00 01 00 92 01 22 00 02 00 7C ; .........?"...| 00015a89h: 00 1A 01 01 00 38 00 09 00 00 00 30 01 01 00 85 ; .....8.....0...? 00015a99h: 00 00 00 1B 00 00 00 A3 01 00 00 38 00 08 00 00 ; .......?..8.... 00015aa9h: 00 AA 00 00 00 01 00 1B 00 00 00 92 01 22 00 02 ; .?........?".. 00015ab9h: 00 AE 00 1A 01 00 00 38 00 0C 00 00 00 30 01 01 ; .?....8.....0.. 00015ac9h: 00 85 00 00 ; .?. ls_hardid = trim(hdserialnumread()) ls_cpuid = trim(string(getcpuid())) if ((trim(ls_hardid) = "") or (isnull(ls_hardid))) then ls_hardid = "H8" end if if ((trim(ls_cpuid) = "") or (isnull(ls_cpuid))) then ls_cpuid = "C8" end if ls_xlh = f_xlh_sub1(f_replace(upper(ls_hardid)),f_replace(upper(ls_cpuid))) return trim(ls_xlh) 00015a69h: 00 1B 00 01 00 A3 01 00 00 38 00 08 00 00 00 BC ; .....?..8.....? 00015a79h: 00 00 00 01 00 1B 00 01 00 92 01 22 00 02 00 7C ; .........?"...| 00015a89h: 00 1A 01 01 00 38 00 09 00 00 00 30 01 01 00 85 ; .....8.....0...? 00015a99h: 00 00 00 1B 00 00 00 A3 01 00 00 38 00 08 00 00 ; .......?..8.... 00015aa9h: 00 BC 00 00 00 01 00 1B 00 00 00 92 01 22 00 02 ; .?........?".. 00015ab9h: 00 AE 00 1A 01 00 00 38 00 0C 00 00 00 30 01 01 ; .?....8.....0.. 00015ac9h: 00 85 00 00 ; .?. ls_hardid = trim(hdserialnumread()) ls_cpuid = trim(string(getcpuid())) if ((trim(ls_hardid) <> "") or (isnull(ls_hardid))) then ls_hardid = "H8" end if if ((trim(ls_cpuid) <> "") or (isnull(ls_cpuid))) then ls_cpuid = "C8" end if ls_xlh = f_xlh_sub1(f_replace(upper(ls_hardid)),f_replace(upper(ls_cpuid))) return trim(ls_xlh) ---------------------------------------- 以上都是没有进行伪代码混淆的结果。 而楼主 LZQQJ 所提到的软件并不一定符合以上规律。如所言版本只需修改3100010000为3100FFFFFF即可,而另一版本(理工)虽然伪代码一样,但二进制代码则不同。 如果,PBKILLER的作者能发表一两篇这方面的文章就好。 donpps2007-05-29, 10:23:31转贴,来源不清楚: +--------------------------------------------------------------+ I PBL File Format I +--------------------------------------------------------------+ Dear PB Fans out there, these are the results of the analysis I did, written down as a short ASCII text description (valid thru PB5-11). With this knowledge you can write your own LibraryDirectory or Export Function for PowerBuilder PBL/PBD/DLL/EXE files. Think about the possibility; including files via PBR assignment and extracting them during runtime. That is a nice gimmick. Most of the terms used are the results and presumptions of my analysis. Regards Arnd Schmidt March 2005 arnd.schmidt@dwox.com +--------------------------------------------------------------+ I PBL File Format I +--------------------------------------------------------------+ Rules and facts: 1.) A PBL is always made out of blocks of 512 Bytes, except the Node Block, that has a size of 6 blocks, meaning 3072 Bytes. 2.) There is always one Header (HDR*), followed by a free/used blocks bitmap (FRE*). Then (after 1024 Byte) follows the first 'NOD*' block. Theoretically this first 'NOD*' block might(!) point to a parent node, but I have never seen that. 3.) Object Data (and SCC Informations - pre PB8) are always stored in single forward linked/chained 'DAT*'-Blocks. 4.) A PBD is a PBL. 5.) DLL and EXE files have a 'TRL*' at the end of the file. This is pointing to the one and only 'HDR*'-Block. +--------------------------------------------------------------+ I Library Header Block (512 Byte) I +-----------+------------+-------------------------------------+ I Pos. I Type I Information I +-----------+------------+-------------------------------------+ I 1 - 4 I Char(4) I 'HDR*' I I 5 - 18 I String I 'PowerBuilder' + 0x00 + 0x00 I I 19 - 22 I Char(4) I PBL Format Version? (0400/0500/0600)I I 23 - 26 I Long I Creation/Optimization Datetime I I 29 - ff I String I Library Comment I I 285 - 288 I Long I Offset of first SCC data block I I 289 - 292 I Long I Size (Net size of SCC data) I +-----------+------------+-------------------------------------+ +--------------------------------------------------------------+ I Library Header Block - Unicode (1024 Byte) I +-----------+------------+-------------------------------------+ I Pos. I Type I Information I +-----------+------------+-------------------------------------+ I 1 - 4 I Char(4) I 'HDR*' I I 5 - 32 I StringW I 'PowerBuilder' + 0x00 + 0x00 I I 33 - 40 I CharW(4) I PBL Format Version? (0400/0500/0600)I I 41 - 44 I Long I Creation/Optimization Datetime I I 45 - ff I StringW I Library Comment I +-----------+------------+-------------------------------------+ +--------------------------------------------------------------+ I Bitmap Block (512 Byte) I +-----------+------------+-------------------------------------+ I Pos. I Type I Information I +-----------+------------+-------------------------------------+ I 1 - 4 I Char(4) I 'FRE*' I I 5 - 8 I Long I Offset of next block or 0 I I 9 - 512 I Bit(504) I Bitmap, each Bit represents a block I +-----------+------------+-------------------------------------+ (512 - 8) * 8 = 4032 Blocks are referenced +--------------------------------------------------------------+ I Node Block (3072 Byte) I +-----------+------------+-------------------------------------+ I Pos. I Type I Information I +-----------+------------+-------------------------------------+ I 1 - 4 I Char(4) I 'NOD*' I I 5 - 8 I Long I Offset of next (left ) block or 0 I I 9 - 12 I Long I Offset of parent block or 0 I I 13 - 16 I Long I Offset of next (right) block or 0 I I 21 - 22 I Integer I Count of entries in that node I I 33 - ff I Chunks I 'ENT*'-Chunks I +-----------+------------+-------------------------------------+ +--------------------------------------------------------------+ I Entry Chunk (Variable Length) I +-----------+------------+-------------------------------------+ I Pos. I Type I Information I +-----------+------------+-------------------------------------+ I 1 - 4 I Char(4) I 'ENT*' I I 5 - 8 I Char(4) I PBL version? (0400/0500/0600) I I 9 - 12 I Long I Offset of first data block I I 13 - 16 I Long I Objectsize (Net size of data) I I 17 - 20 I Long I Unix datetime I I 21 - 22 I Integer I Length of comment I I 23 - 24 I Integer I Length of objectname I I 25 - ff I String I Objectname I +-----------+------------+-------------------------------------+ +--------------------------------------------------------------+ I Entry Chunk - Unicode (Variable Length) I +-----------+------------+-------------------------------------+ I Pos. I Type I Information I +-----------+------------+-------------------------------------+ I 1 - 4 I Char(4) I 'ENT*' I I 5 - 12 I CharW(4) I PBL version? (0400/0500/0600) I I 13 - 16 I Long I Offset of first data block I I 17 - 20 I Long I Objectsize (Net size of data) I I 21 - 24 I Long I Unix datetime I I 25 - 26 I Integer I Length of comment I I 27 - 28 I Integer I Length of objectname I I 29 - ff I StringW I Objectname I +-----------+------------+-------------------------------------+ +--------------------------------------------------------------+ I Data Block (512 Byte) I +-----------+------------+-------------------------------------+ I Pos. I Type I Information I +-----------+------------+-------------------------------------+ I 1 - 4 I Char(4) I 'DAT*' I I 5 - 8 I Long I Offset of next data block or 0 I I 9 - 10 I Integer I Length of data in block I I 11 - XXX I Blob{} I Data (maximum Length is 502 I +-----------+------------+-------------------------------------+ +--------------------------------------------------------------+ I Trailer Block (in DLL/EXE) always last block (512 Byte) I +-----------+------------+-------------------------------------+ I Pos. I Type I Information I +-----------+------------+-------------------------------------+ I 1 - 4 I Char(4) I 'TRL*' I I 5 - 8 I Long I Offset of Library Header ('HDR*') I +-----------+------------+-------------------------------------+ +--------------------------------------------------------------+ I SCC DATA I I Structure of status information chunks I I in DAT*-blocks (Variable Length) I +---------+----------------------------------------------------I I Type I Information I +---------+----------------------------------------------------I I String I Libraryname (the opposite!) I I String I Objectname I I String I Developername I I Char(1) I Flag I +---------+----------------------------------------------------I +--------------------------------------------------------------+ I PB6/7 Status Flags I +------+------+------------------------------------------------+ I Icon I Flag I Meaning I +------+------+------------------------------------------------+ I I r I Object is registered I I I d I Object is Checked Out (locked) I I I s I Object (Working Copy) to be checked in I I I u I Unknown?! After an Error occurred. I I I I (Checked out by user <Unknown> I I I I Could be set to 'r' with an Hex-Editor.) I +------+------+------------------------------------------------+ DateTimes are stored in Long format in Unix representation. Timezone is always GMT (+/- 0:00), so the datetime has to be converted to LocalDateTime via LocalTimeZone conversation. In the compiled object data blocks, there are at least 2 more datetimes, starting at byte 23 and the other one at 27! Looks like these are the modification and regeneration date... donpps2007-05-29, 10:27:28虽然 shudepb DEMO 效果好一点,并在不断的更新,但是同一个程序每次导出的文件都会有不同,大家注意啦。 sjclch2007-05-29, 15:03:26shudepb是下载的都是DOME版 kenshu2007-05-29, 20:12:18虽然 shudepb DEMO 效果好一点,并在不断的更新,但是同一个程序每次导出的文件都会有不同,大家注意啦。 靠,这都给你发现了...... (我叫阿SHU) ------------------------------------------------------ 顺便回楼主 在网上又搜到另一个反编译工具shudepb,使用确实很好,支持全局搜索,大大方便找关键代码。 缪赞了.惭愧. 先找工具反编译。试了pbkill,只得到一堆if...else...end if之类的,一句代码也没有出来(可能是pbkill试用版吧?) 那个是给POWERSHIELD(它是前辈ljcc的作品,当年DEPB可是唯一的PB反编译器啊)混淆过的.并不是因为PBKILLER试用版的原因. 你看代码最前面写着"//Has been Shielded." lzqgj2007-05-30, 07:41:35看来多讨论一下pb程序还是有好处的,发现这么多东西,不然就只能靠反编译然后写注册机一条路了,对我等编程不行的人来说真的好难。 顺便说一下,理工类的破解方法用爆破sapiyy.dll的返回值的方法是一样的。我直接用破好的综合类的文件覆盖就行了。 ssw2007-06-04, 17:54:45楼主能否将爆破的文件发给我下,新手难搞阿!655750@sina.com,或者ssw1213@qq.com 谢谢你啦!!!!!! ranus2007-06-15, 21:31:04:o: 老大,如何在OD中查看sapiyy.dll的函数名称?还有如何在gethdserial函数上下断?我弄了两星期了,还是弄不明白,能否说详细一些?谢谢!!!要不把sapiyy.dll发给我吧,mail:huxizh@tom.com lzqgj2007-06-15, 21:53:55:o: 老大,如何在OD中查看sapiyy.dll的函数名称?还有如何在gethdserial函数上下断?我弄了两星期了,还是弄不明白,能否说详细一些?谢谢!!!要不把sapiyy.dll发给我吧,mail:huxizh@tom.com 先查看模块,然后在sapiyy.dll模块上右键→查看名称。就可以找到了 或当程序运行在sapiyy.dll领空时在代码上右键→查看当前模块名称,也可以找到 ranus2007-06-15, 23:11:48已经看到了,谢谢!!! ranus2007-06-16, 20:26:32:o:&nbsp;看到的那一串古怪字符明显与注册码有关。看ret前几个代码,发现: 01AD29DD&nbsp;&nbsp;CALL&nbsp;<JMP.&RegClient.GetErrorString> 01AD29E2&nbsp;&nbsp;POP&nbsp;EDI 01AD29E3&nbsp;&nbsp;XOR&nbsp;EAX,EAX 应该是注册不成功的置0标志位。修改EAX为1,运行,程序不再有注册提示,按钮变成了“注销注册”。成功! 老大,是将XOR&nbsp;EAX,EAX这行的EAX改为1吗?我改了,什么还不行啊?按F8光标到这行后,先在寄存器窗口改EAX的值,然后再按F9,是这样吗?谢谢!!! lzqgj2007-06-16, 22:03:15:o:&nbsp;老大,是将XOR&nbsp;EAX,EAX这行的EAX改为1吗?我改了,什么还不行啊?按F8光标到这行后,先在寄存器窗口改EAX的值,然后再按F9,是这样吗?谢谢!!! 具体位置记不清了,不过好像有两处,有一个是运行不到的。在附近找找看,应该还有一个。 ranus2007-06-17, 10:31:02具体位置记不清了,不过好像有两处,有一个是运行不到的。在附近找找看,应该还有一个。 01AD29BE JE sapiyy.01AD2CD9 01AD29C4 MOV ECX,20 01AD29C9 XOR EAX,EAX 01AD29CB LEA EDI,DWORD PTR SS:[ESP+C8] 01AD29D2 REP STOS DWORD PTR ES:[EDI] 01AD29C9 XOR EAX,EAX 我把这里的EAX改了也不行,应该是我保存方法不对。修改后应如何保存?我是修改后点右键→复制到可执行文件→选择,弹出一个窗口,再在该窗口点右键→保存文件。但是弹出了一个文件未更改的对话框。 lzqgj2007-06-18, 00:14:2001AD29C9 XOR EAX,EAX 我把这里的EAX改了也不行,应该是我保存方法不对。修改后应如何保存?我是修改后点右键→复制到可执行文件→选择,弹出一个窗口,再在该窗口点右键→保存文件。但是弹出了一个文件未更改的对话框。 不是改eax的值,那样只是这次程序运行有效。 应改代码xor eax,eax 为mov al,1 ranus2007-06-18, 18:11:25不是改eax的值,那样只是这次程序运行有效。 应改代码xor eax,eax 为mov al,1 已成功爆破,谢谢了,你真是神人!! QHXCJ2007-06-24, 01:05:28根据楼主的分析我也成功,以下是我两台机子的更改地址(2.93版) 020E29E3 33C0 XOR EAX,EAX 020F2FE9 33C0 XOR EAX,EAX 01CF29E3 33C0 XOR EAX,EAX 01CF2FE9 33C0 XOR EAX,EAX 做了个内存补丁,地址不一样就不能用于其它机子,不过可用于系列软件的破解。 pizigao2007-07-27, 09:47:32PB的东西还是比较难搞的!不过学习一下很好~ eaglefox2007-08-09, 22:47:17shudepb,这个软件破解版本很少。 tshihong2007-08-26, 09:15:40我是职称英语学习帮手的作者,请删除相关破解信息!! tshihong2007-08-26, 09:15:52我是职称英语学习帮手的作者,请删除相关破解信息!! zyhxhw2007-11-02, 22:07:54好文章,学习了! 蓝领2008-02-03, 18:08:06我照你的讲解已经成功实现破解,但是好像不能复制到可执行文件 提示“在可执行文件中无法定位数据”,应该怎么处理?请赐教,多谢 我破的是2008年的 lzqgj2008-02-03, 22:04:26呵呵,2007年的好像就已经有变化了,加了壳,有文件校验。08年的没有用过。 lovebj2008-02-03, 23:56:17我有一贴破PB的(第一贴)(以前的) http://bbs.pediy.com/showthread.php?p=153117#post153117 坛主没有加精,现在只有潜水了。 我也用了不少工具。如PBKILLER ,Hex Workshop. 不给加精没有信心了。不过破解还是学。 我原贴注册码都给我用OD给调试出来了。 舵手2008-02-04, 08:48:37楼上的, 你的http://bbs.pediy.com/showthread.php?p=153117#post153117 还真没看出来你是用OD调试的。 lovebj2008-02-04, 21:50:34我原贴注册码都给我用OD给调试出来了。 我说的是最近。 playx2008-02-09, 22:16:42今年考职称,想找一本,楼上的能发一份吗? 兰雪儿2008-04-11, 00:09:50“真的希望各位同仁能多写些pb调试的文章,把经验放给大家共享,让pb程序的破解不再是难题。” leiyihui2008-04-12, 13:00:25很强大,学习, nadis2008-07-27, 08:35:00这几天刚好在破一小软,看也没看是啥写的,调试的时候看到调用pbvm8.0, 不过我不知道有反编译工具这回事... 对照这jump table 把函数给看了。..... 有个比较的函数 看下jump table就知道了 我没记下编号 vBulletin&reg; v3.8.7,Copyright &copy;2000-2014,vBulletin Solutions Inc.