飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 7201|回复: 6

[原创] 某 PB 9.0 程序**奶站管理系统 v3.06 关键点爆破分析

[复制链接]

该用户从未签到

发表于 2008-4-24 08:54:35 | 显示全部楼层 |阅读模式

在爆破前,先学习一下看雪高手的注册分析:
http://bbs.pediy.com/showthread.php?t=63449

||||||||||||||||||||||||||||||||||||以下为转帖部分||||||||||||||||||||||||||||||||||||||||||
PBKiller V2.5.18 反编译后查找到关键点:
********************************************************************************************
dlbmain.pdb/w_dl_frame/Events/open()  //机器码的计算过程
call super::open;
string s_dept  //注册单位名
string s_zz  //初始字符串
string s_mcode  //机器码
string s_nowsn  //输入的注册码
string s_cpuid  //cpu特征信息字串

n_cst_pie_security n_sec
string s_file
title = gnv_app.is_apptitle
s_zz = "139"
if gnv_app.of_getoptionvalue("DWMC",s_dept) <> 0 then  //从数据库读取注册单位名称到s_dept
  gnv_app.of_setregister("1")
else
  gnv_app.is_dwmc = s_dept
end if
s_zz = s_zz + "536dinglisoft"  //计算机器码的初始化字串"139536dinglisoft"
s_cpuid = string(getcpuid())  //调用"pbdlsec.dll"的输出函数getcpuid()获取CPU特征信息,转成字符串
n_sec = create n_cst_pie_security
s_mcode = n_sec.of_unitestring(s_zz,s_dept,s_cpuid)  //连接初始字串,单位名称,CPU特征字串
s_mcode = n_sec.of_pwd2number(s_mcode)  //转换为机器码
gnv_app.is_machinecode = s_mcode  //赋值给gnv_app.is_machinecode
destroy(n_sec)
gnv_app.of_getoptionvalue("REG",s_nowsn)  //获取输入的注册码
gnv_app.is_temp = s_nowsn      //赋值给gnv_app.is_temp
略......
return
********************************************************************************************
********************************************************************************************
dlbmain.pdb/w_dl_frame/Events/pfc_postopen()  //注册码的计算过程
string s_serial
boolean b_tt = false
string s_date
string s_today
string s_end
string s_value
string s_day
n_cst_pie_security n_sec
datastore ds_table
string s_dbver
略......
n_sec = create n_cst_pie_security
s_serial = n_sec.of_pwdtrans(gnv_app.is_machinecode,3,44.4,5)  //转化机器码
s_serial = n_sec.of_tablee(s_serial)  //查表变换
ds_table = create datastore
ds_table.dataobject = "d_sys_pwdtable"  //秘文明文对照表
destroy(ds_table)
if gnv_app.is_temp = n_sec.of_pwd2number(s_serial) then  //若输入的注册码与计算出的注册码相等则置b_tt = true
  b_tt = true
end if
destroy(n_sec)
略......
if b_tt then
  gnv_app.of_setregister("2")  //若b_tt = true,则设置注册成功标志为2
end if          //注册成功标志为0表示未注册,在试用期内
choose case gnv_app.of_getregister(true)//注册成功标志为1表示未注册,过了试用期
  case "2"
  case else
    gnv_app.is_dwmc = gnv_app.is_dllogo
end choose
gnv_app.of_getoptionvalue("DBVER",s_dbver)
if s_dbver < "3.05" then
  messagebox("提示","数据库结构没有升级! 请打开【辅助工具】窗口进行升级!")
end if
********************************************************************************************
用 ShuDePB 1.8320 DEMO 打开 dlmilk.exe 文件,自动加载相关 pdb 文件,展开所有项,
然后全局查找调用的相关函数(只查找标签),快速定位:
--------------------------------------------------------------------------------------------
Public Function long getcpuid () LIBRARY "pbdlsec.dll"
//反汇编getcpuid ()发现:实际是调用Intel Pentium以上级CPU内置的一个指令CPUID(486级及以下的CPU不支持)
//返回edx的特征信息
Exported fn(): getcpuid - Ord:0001h
......
:0040BD34 53                      push ebx
:0040BD35 57                      push edi
:0040BD36 89C7                    mov edi, eax
:0040BD38 B801000000              mov eax, 00000001  //eax置1
:0040BD3D 0FA2                    cpuid  //返回EAX=CPU的级别,型号及步进;EBX=CPU扩展信息;ECX保留;EDX=CPU特征信息
:0040BD3F AB                      stosd
:0040BD40 89D8                    mov eax, ebx
:0040BD42 AB                      stosd
:0040BD43 89C8                    mov eax, ecx
:0040BD45 AB                      stosd
:0040BD46 89D0                    mov eax, edx
:0040BD48 AB                      stosd
:0040BD49 5F                      pop edi
:0040BD4A 5B                      pop ebx
:0040BD4B C3                      ret
--------------------------------------------------------------------------------------------
//Public function of_getoptionvalue (string as_item,ref string as_value) returns integer //SQL查询
SELECT "sys_option"."opvalue" INTO :as_value FROM "sys_option" WHERE "sys_option"."opno" =:as_item  USING sqlca;
RETURN sqlca.sqlcode
--------------------------------------------------------------------------------------------
//Public function of_unitestring (string as_1,string as_2,string as_3) returns string
string s_return
integer i
integer i1[20]
integer i2[20]
integer ii[20]
as_1 = THIS.of_limitlen(as_1,20)  //调整as_1为20位
as_2 = THIS.of_limitlen(as_2 + as_3,20)  //调整as_2+as_3为20位,赋值给as_2
FOR i = 1 TO 20 //2  //1到20位
  i1 = asc(mid(as_1,i,1))
  i2 = asc(mid(as_2,i,1))
  ii = i1 + i2  //相加as_1和as_2对应位置字符的ASCii码值
NEXT //2
s_return = ""
FOR i = 1 TO 20 //8
  s_return = s_return + char(ii)  //加过后的ASCii码值组合为字串
NEXT //8
s_return = THIS.of_pwdtrans(s_return)  //变换字串
s_return = THIS.of_limitlen(s_return,20)//调整为20位
RETURN s_return
--------------------------------------------------------------------------------------------
//Public function of_limitlen (string as_string,integer ai_len) returns string
IF len(as_string) = 0 THEN RETURN ""  //如果为空返回空字串
DO //2
  as_string = as_string + as_string  //自身相加
LOOP UNTIL len(as_string) >= ai_len //2  直到字串长度大于等于20
RETURN left(as_string,ai_len)  //返回字串的前20位
--------------------------------------------------------------------------------------------
//Public function of_pwdtrans (string as_pass) returns string
integer i
integer l_len
integer l
long l_count
string ss[]
integer ascii[]
integer asend[]
IF (isnull(as_pass) OR as_pass = "") THEN RETURN as_pass //为空则返回空
as_pass = lower(as_pass)  //大写转小写
l_len = len(as_pass)
FOR i = 1 TO l_len //3
  ss = mid(as_pass,i,1)
  ascii = asc(ss)
  l_count = l_count + ascii  //累加各位字符的ASCii值
NEXT //3
l_count = int(l_count / 1.3 + 23.6)  //累加ASCii值和/1.3+23.6后取整
as_pass = ""
FOR i = 1 TO l_len //10  //变换各位字符为48(数字0)-90(大写字母Z)之间的字符
  l = l_len - i + 1
  asend = ascii + ascii[l] + l_count + i * 3 //asend(i)=asend(i)+asend(20-i+1)+l_count+i*3
  IF asend < 48 THEN asend = asend + 48  //若asend(i)小于48,则加48
  DO UNTIL asend >= 48 AND asend <= 90 //14
    asend = asend - 90 + 47    //循环减43直到在48-90之间
    IF asend <= 0 THEN asend = 48  //若asend(i)小于等于0,则等于48
  LOOP //14
  ss = char(asend)
  as_pass = as_pass + ss
NEXT //10
RETURN as_pass
--------------------------------------------------------------------------------------------
//Public function of_pwd2number (string as_pass) returns string //转成数字
integer i
integer l_len
integer l
long l_count
string ss[]
integer ascii[]
integer asend[]
IF (isnull(as_pass) OR as_pass = "") THEN RETURN as_pass //为空则返回空
as_pass = lower(as_pass)  //大写转小写
l_len = len(as_pass)
FOR i = 1 TO l_len //3
  ss = mid(as_pass,i,1)
  ascii = asc(ss)
  l_count = l_count + ascii  //累加各位字符的ASCii值
NEXT //3
l_count = int(l_count / 1.3 + 23.6)  //累加ASCii值和/1.3+23.6后取整
as_pass = ""
FOR i = 1 TO l_len //10  //变换各位字符为48(数字0)-57(数字9)之间的字符
  l = l_len - i + 1
  asend = ascii + ascii[l] + l_count + i * 3 //asend(i)=asend(i)+asend(20-i+1)+l_count+i*3
  IF asend < 48 THEN asend = asend + 48  //若asend(i)小于48,则加48
  DO UNTIL asend >= 48 AND asend <= 57 //14
    asend = asend - 57 + 47    //循环减10直到在48-57之间
    IF asend <= 0 THEN asend = 48  //若asend(i)小于等于0,则等于48
  LOOP //14
  ss = char(asend)
  as_pass = as_pass + ss
NEXT //10
RETURN as_pass
--------------------------------------------------------------------------------------------
//Public function of_setregister (string as_reg) returns (none)
THIS.is_registered = as_reg //注册标志位=2为注册成功,0代表未注册在试用,1代表未注册过了试用期
--------------------------------------------------------------------------------------------
//Public function of_pwdtrans (string as_pass,dec a,dec b,integer c) returns string
integer i
integer l_len
integer l
long l_count
string ss[]
integer ascii[]
integer asend[]
IF (isnull(as_pass) OR as_pass = "") THEN RETURN as_pass //为空则返回空
as_pass = lower(as_pass)  //大写转小写
l_len = len(as_pass)
FOR i = 1 TO l_len //3
  ss = mid(as_pass,i,1)
  ascii = asc(ss)
  l_count = l_count + ascii  //累加各位字符的ASCii值
NEXT //3
l_count = int(l_count / a + b)    //累加ASCii值和/a+b后取整
as_pass = ""
FOR i = 1 TO l_len //10  //变换各位字符为48(数字0)-90(大写字母Z)之间的字符
  l = l_len - i + 1
  asend = ascii + ascii[l] + l_count + i * c //asend(i)=asend(i)+asend(20-i+1)+l_count+i*c
  IF asend < 48 THEN asend = asend + 48
  DO UNTIL asend >= 48 AND asend <= 90 //14
    asend = asend - 90 + 47    //循环减43直到在48-90之间
    IF asend <= 0 THEN asend = 48  //若asend(i)小于等于0,则等于48
  LOOP //14
  ss = char(asend)
  as_pass = as_pass + ss
NEXT //10
RETURN as_pass
--------------------------------------------------------------------------------------------
//Public function of_tablee (string as_pwd) returns string
integer i
integer i_length
integer i_rc
long l_rowcount
string s_return
string s_bit
datastore ds_table
i_length = len(as_pwd)
IF i_length = 0 THEN RETURN as_pwd
ds_table = CREATE datastore
ds_table.dataobject = "d_sys_pwdtable"
l_rowcount = ds_table.rowcount()
s_return = ""
FOR i = 1 TO i_length //6
  s_bit = mid(as_pwd,i,1)    //取单个字符
  i_rc = ds_table.find("a='" + s_bit + "'",1,l_rowcount)  //查找
  IF i_rc > 0 THEN //19
    s_return = s_return + ds_table.object.b[i_rc]
    CONTINUE
  END IF //19
  s_return = s_return + s_bit
NEXT //6
DESTROY ds_table
RETURN s_return
--------------------------------------------------------------------------------------------
密码表"d_sys_pwdtable"在dlapp.pbd中。
用ShuDePB1.8320DEMO打开dlapp.pbd,选定DataWindow,将其保存为dlapp_dw.pbl文件。
在PBKiller V2.5.18中打开dlapp_dw.pbl,察看"d_sys_pwdtable":
release 9;
datawindow ( units=0 timer_interval=0 color=16777215 processing=1 print.documentname=""  print.orientation=0 print.margin.left=110 print.margin.right=110 print.margin.top=96 print.margin.bottom=96 print.paper.size=0 print.paper.source=0 grid.lines=0 selected.mouse=yes)
header(height=76 color="536870912" )
summary(height=0 color="536870912" )
footer(height=0 color="536870912" )
detail(height=84 color="536870912" )
table(column=(type=char(1) updatewhereclause=yes name=a dbname="a"  )   //表分"a"和"b"两列,每列一个字符
column=(type=char(1) updatewhereclause=yes name=b dbname="b"  )    //"a"列按字母排序
sort="a A")
text(name=a_t band=header 略... height="60" width="224" text="明文" )  //"a"列标题="明文"
text(name=b_t band=header 略... height="60" width="219" text="密文" )  //"b"列标题="密文"
column(name=a band=detail id=1 x="9" y="8" 略... tabsequence=10 )
column(name=b band=detail id=2 x="242" y="8" 略... tabsequence=20 )
htmltable(border="1" cellPadding="0" cellSpacing="0" generateCSS="no" noWrap="yes" )
htmlgen()
export.xml(metadatatype=0 savemetadata=0 )
import.xml()
export.pdf(method=0)
data  //重要!数据码表!按表的格式读入表中("0","3","1","6","2","2","3","5","4","7","5","1","6","0","7","9","8","4","9","8","A","Q","B","q","C","A","D","a","E","Z","F","z","G","W","H","w","I","S","J","s","K","X","L","x","M","E","N","e","O","D","P","d","Q","C","R","c","S","R","T","r","U","F","V","f","W","V","X","v","Y","P","Z","p","a","L","b","l","c","O","d","o","e","I","f","i","g","K","h","k","i","U","j","u","k","Y","l","y","m","T","n","t","o","G","p","g","q","H","r","h","s","J","t","j","u","B","v","b","w","N","x","n","y","M","z","m",)
--------------------------------------------------------------------------------------------
原作者的这个注册算法有个Bug,当注册的单位名称大于等于20个字符或10个汉字时,机器码/注册码将与cpuid信息无关。
也就是说这组注册名称/注册码可以适用于任何机器。
||||||||||||||||||||||||||||||||||||以上为转帖部分||||||||||||||||||||||||||||||||||||||||||


||||||||||||||||||||||||||||||||||||以下为原创部分||||||||||||||||||||||||||||||||||||||||||
实际上,该程序注册码的计算过程存在一个明显的弱点,即“若b_tt = true,则设置注册成功标志为2”,显然只要修改代码中的“boolean b_tt = false”为“boolean b_tt = true”,即可实现免注册。
********************************************************************************************
dlbmain.pdb/w_dl_frame/Events/pfc_postopen()  //注册码的计算过程
string s_serial
boolean b_tt = false

... ... 略去n行
if b_tt then
  gnv_app.of_setregister("2")  //若b_tt = true,则设置注册成功标志为2
end if          //注册成功标志为0表示未注册,在试用期内
********************************************************************************************
使用 16 进制编辑器打开 dlbmain.pdb,查找字符串 b_tt,在位置 6920h 处可以看到查找结果,往下几行,在位置 69B4h 到 69C7h 对 b_tt 进行了数据类型定义和初始赋值 FF FF 00 00 11 00 00 00 00 00 00 00 00 05 07 00 00 00 00 00,即 boolean b_tt = false,只要将其改成 FF FF 00 00 11 00 00 00 01 00 00 00 00 05 07 00 00 00 00 00,即 boolean b_tt = true,这样的话 b_tt 就恒为真,就大功告成,成为注册版本。仅仅修改了一个字节。
熟悉 PB 编程的应该都知道怎样去修改 16 进制代码,11 00 00 00 代表变量位置(或变量代号),01 00 00 00 代表变量初始值,00 05 07 00 代表数据类型,不过我不懂 PB 编程,不知道对不对。
||||||||||||||||||||||||||||||||||||以上为原创部分||||||||||||||||||||||||||||||||||||||||||


[ 本帖最后由 donpps 于 2008-4-24 08:58 编辑 ]
Snap2.gif

评分

参与人数 1飘云币 +20 收起 理由
tianxj + 20 感谢您发布的原创作品!

查看全部评分

PYG19周年生日快乐!
  • TA的每日心情
    擦汗
    2017-9-28 11:05
  • 签到天数: 3 天

    [LV.2]偶尔看看I

    发表于 2008-4-24 17:18:58 | 显示全部楼层
    强。。。应加精华。。。。

    /:good
    PYG19周年生日快乐!

    该用户从未签到

    发表于 2008-4-25 19:12:26 | 显示全部楼层
    不错,值得我们菜鸟多学习
    PYG19周年生日快乐!
  • TA的每日心情
    无聊
    2016-1-18 13:29
  • 签到天数: 1 天

    [LV.1]初来乍到

    发表于 2008-4-26 23:42:12 | 显示全部楼层
    能反编译的  就别爆破了。
    PYG19周年生日快乐!

    该用户从未签到

    发表于 2008-4-27 19:01:42 | 显示全部楼层
    偶还看不懂这种语言  呼呼   凑热闹看看  争取能好好学好!!!/:014
    PYG19周年生日快乐!

    该用户从未签到

    发表于 2008-5-1 23:29:04 | 显示全部楼层
    看得头晕啊~~~~~~~~~~~~
    PYG19周年生日快乐!
  • TA的每日心情
    开心
    2021-10-11 20:54
  • 签到天数: 1 天

    [LV.1]初来乍到

    发表于 2010-4-4 11:24:05 | 显示全部楼层
    /:010 就需要这么精典的例子学习,非常好,超赞一个
    PYG19周年生日快乐!
    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

    快速回复 返回顶部 返回列表