首页
社区
课程
招聘
[原创]pb程序调试初探
2007-5-10 22:48 42879

[原创]pb程序调试初探

2007-5-10 22:48
42879
软件名称:职称英语学习帮手(综合类)
破解工具: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时比较逻辑值是否相等。
其它的值代表的含义希望大家继续跟踪贴出来分享。

调试程序好累,写文章更累。真的需要很好地耐心。休息一下,明天继续爆破注册。那个稍微容易点。

[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

收藏
点赞7
打赏
分享
最新回复 (46)
雪    币: 276
活跃值: (281)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
lzqgj 6 2007-5-11 08:32
2
0
今天讲一下爆破注册这个程序。
反编译显示程序调用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程序的破解不再是难题。
雪    币: 200
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
founder 2007-5-11 11:09
3
0
学习了,多谢!
雪    币: 276
活跃值: (281)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
lzqgj 6 2007-5-13 08:08
4
0
再次跟踪发现: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程序都用这个比较字符串。
雪    币: 482
活跃值: (263)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
Tee8088 2 2007-5-13 10:48
5
0
我这两天也在弄PB的东西,

PBkiller的作者Kevins哪位兄弟联系的到呀。
雪    币: 716
活跃值: (162)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
elance 6 2007-5-13 10:51
6
0
PB的,这个得学习下
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
pizigao 2007-5-14 08:31
7
0
PB的东西还是蛮头大的~
雪    币: 203
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
rensd 2007-5-24 12:56
8
0
试着照楼主所写的破解了一下,消息断点不知道怎么下,所以没有完成破解。我用了你说的第二种爆破方式,修改了一个字节,爆破成功,感谢楼主,帮我省了100多块钱,呵呵。
雪    币: 158
活跃值: (43)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
modi 2007-5-24 19:56
9
0
好少有爆破的,学习..
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xyu 2007-5-25 14:01
10
0
楼主,请问可以提供下那个shudepb软件的下载网址吗,我下了个demo版本没有什么用处哦
雪    币: 276
活跃值: (281)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
lzqgj 6 2007-5-25 20:47
11
0
我的也是Demo版的,好像没有太多限制,反正反出来能找到想要的信息就行了。
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xyu 2007-5-26 22:29
12
0
看来也只能是移花接木了,去把代码放pb的工程里面去试试!
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ssw 2007-5-27 17:12
13
0
新手,不太懂!
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ssw 2007-5-27 17:41
14
0
楼主能否给职称英语2007理工类的爆破写出来一下,我搞了一天没搞出来,谢谢了!
雪    币: 276
活跃值: (281)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
lzqgj 6 2007-5-28 14:54
15
0
这一系列的软件方法应该是一样的吧?你再试试?
如果pb程序调用外部dll判断是否注册的,一般修改返回值即可,
否则pb程序的jz和jnz的代码到底是什么都不知道,所以如果在pb中爆破修改跳转不方便,我的思路是修改比较的地方,如:
cmp (ifreged)=1
jz reged      一般改成jmp或jnz
改成
cmp (ifreged)=0
jz reged
如此只要在程序中找到那个1的标志所在改成0 就可以。
雪    币: 158
活跃值: (31)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wudiweiwei 2007-5-28 23:44
16
0
pb关键指令
>c5
<d1
<>b5
=a5
<=e9
>=dd
or 22
and 21
not 23
ture 01
false 00
return 39
雪    币: 276
活跃值: (281)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
lzqgj 6 2007-5-29 08:06
17
0
太好了,谢谢!找这个很久了!
雪    币: 199
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
donpps 2007-5-29 10:09
18
0
补充一点:
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的作者能发表一两篇这方面的文章就好。
雪    币: 199
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
donpps 2007-5-29 10:23
19
0
转贴,来源不清楚:

+--------------------------------------------------------------+
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...
雪    币: 199
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
donpps 2007-5-29 10:27
20
0
虽然 shudepb DEMO 效果好一点,并在不断的更新,但是同一个程序每次导出的文件都会有不同,大家注意啦。
雪    币: 89
活跃值: (151)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
sjclch 2007-5-29 15:03
21
0
shudepb是下载的都是DOME版
雪    币: 0
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
kenshu 2007-5-29 20:12
22
0
靠,这都给你发现了......
(我叫阿SHU)

------------------------------------------------------

顺便回楼主


缪赞了.惭愧.


那个是给POWERSHIELD(它是前辈ljcc的作品,当年DEPB可是唯一的PB反编译器啊)混淆过的.并不是因为PBKILLER试用版的原因.

你看代码最前面写着"//Has been Shielded."
雪    币: 276
活跃值: (281)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
lzqgj 6 2007-5-30 07:41
23
0
看来多讨论一下pb程序还是有好处的,发现这么多东西,不然就只能靠反编译然后写注册机一条路了,对我等编程不行的人来说真的好难。

顺便说一下,理工类的破解方法用爆破sapiyy.dll的返回值的方法是一样的。我直接用破好的综合类的文件覆盖就行了。
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ssw 2007-6-4 17:54
24
0
楼主能否将爆破的文件发给我下,新手难搞阿!655750@sina.com,或者ssw1213@qq.com 谢谢你啦!!!!!!
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ranus 2007-6-15 21:31
25
0
老大,如何在OD中查看sapiyy.dll的函数名称?还有如何在gethdserial函数上下断?我弄了两星期了,还是弄不明白,能否说详细一些?谢谢!!!要不把sapiyy.dll发给我吧,mail:huxizh@tom.com
游客
登录 | 注册 方可回帖
返回