某 PB 9.0 程序**奶站管理系统 v3.06 关键点爆破分析
在爆破前,先学习一下看雪高手的注册分析:
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_itemUSING 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
integer i2
integer ii
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_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_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_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
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 编辑 ] 强。。。应加精华。。。。
/:good 不错,值得我们菜鸟多学习 能反编译的就别爆破了。 偶还看不懂这种语言呼呼 凑热闹看看争取能好好学好!!!/:014 看得头晕啊~~~~~~~~~~~~ /:010 就需要这么精典的例子学习,非常好,超赞一个
页:
[1]