【文章标题】: 直销业绩考核系统算法分析
【文章作者】: caterpilla(惊涛)
【软件名称】: 直销业绩考核系统
【下载地址】: 自己搜索下载
【编写语言】: POWERBUILDER
【使用工具】: UE,PBKILLER,OD
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
这个软件笨鸟我先飞兄弟已经爆破过了,而且应用PBKILLER反编译了软件的源码,他把软件和反编译的代码给了我,我只是在阅读源码后,整理了一下算法,没有深入测试。
从源码开始看起了,呵呵,先贴几个关键的。
1、在系统启动时,应用程序调用检测是否注册的用户对象,判断是否注册、过期、调整过爱期、以及是否手工改过注册等。
global type dotnew from application
。。。。。。。。。
integer rt_chk_value
user_reg myreg
event open;ulong l_handle
ulong lu_class
string ls_name
rt_chk_value = myreg.f_check_reg()
if rt_chk_value = -100 then
messagebox("提示","系统时间有误!")
halt close
end if
if rt_chk_value = -200 then
messagebox("提示","注册码有误!")
halt close
end if
if rt_chk_value = -300 then
messagebox("提示","试用期到,请注册!电话:13336268237 网址:www.zcrj.net")
open(w_wrcode)
return
end if
if rt_chk_value = -400 then
messagebox("提示","系统破坏,请联系开发商!")
return
end if
下面的代码就是USER_REG用户对象,承担检测注册任务。
global type user_reg from n_cst_numerical autoinstantiate
end type
global user_reg user_reg
forward prototypes
public function integer f_check_reg ()//检测是否过期、爱期调整、注册,内部调用f_checkregcode
public function integer f_checkregcode (string reg_code)//关键的检查注册码的部分
public function string f_encode (string source_str)//对注册表信息加密的部分
public function string f_genpuzzle ()
public function string f_genser ()
public function string f_getdisk ()//获取硬盘序列号,与注册码生成有关
public function string f_redreg (string xsxt_key)//读注册表
public function integer f_setreg (string str_num,string str_info)//写注册表
public function string f_swap1 (string str_input)
public function string uf_patchstr (string userstr,integer userlen)
end prototypes
这里面其它的函数都是起迷惑作用的,呵呵。。。。。。。。。。。。。
public function integer f_check_reg ();string ls_right
string ls_wrong
ulong l_handle
ulong lu_class
string ls_name
string ls_disk
string ls_ser
string ls_flag
string ls_day
string ls_num
string ls_ltime
string ls_regflag
string ls_regcode
date ld_d1
date ld_td
integer tsh
integer tshch
integer check_result
ls_right = f_encode(f_redreg("0"))
ls_wrong = f_encode(f_redreg("1"))
if ((ls_right <> "wright") or (ls_wrong <> "wrong")) then//检测软件是否被破坏,手工改过注册表
return -400
end if
ls_regflag = f_redreg("3") //错误标记
if ls_regflag = "err" then
ls_flag = f_encode("90")
ls_day = f_encode("30")
ls_disk = f_encode(f_getdisk())
f_setreg("2",f_encode(f_genser()))
f_setreg("3",ls_flag)
f_setreg("4",f_encode("f7657lo"))
f_setreg("5",ls_day)
f_setreg("6",f_encode("fj;[57lo"))
f_setreg("7",f_encode(string(today())))
f_setreg("8",f_encode("fj57lo"))
return 100
end if
ls_ser = f_encode(f_redreg("2"))
ls_flag = f_encode(f_redreg("3")) //注册表中在HKEY_CURRENT_USER\Software\xsxt\xsxt_3下存放是否注册的标志
ls_day = f_encode(f_redreg("5"))
ls_ltime = f_encode(f_redreg("7"))
ls_regcode = f_encode(f_redreg("9"))
ld_d1 = date(ls_ltime)
ld_td = today()
tsh = daysafter(ld_d1,ld_td) //安装爱期与当前爱期比较
if tsh < 0 then
return -100落后 //若小,说明改过爱期
end if
if ls_flag = "89" then //89这个标记,代表已经注册,继续检测注册码是否合法
check_result = f_checkregcode(ls_regcode)//调用f_checkregcode检查注册码合法性
if check_result = 0 then
return 200 //注册
else
return -200 //注册码不合法
end if
else
tshch = integer(ls_day) - tsh//代表已过期
if tshch <= 0 then
f_setreg("5","00")
f_setreg("7",f_encode(string(today())))
return -300
else
ls_day = f_encode(uf_patchstr(string(tshch),2))
f_setreg("5",ls_day)
f_setreg("7",f_encode(string(today())))
return 300
end if
end if
end function
public function integer f_checkregcode (string reg_code);char alpha[36,2]//关键部分
string tser
string ls_disk
string ls_disk1
char tmpchr
char tmpchr1
integer i
integer j
ls_disk = f_getdisk()//获取硬盘序列号
ls_disk1 = ""
//下面的ALPHA为明密文转换表,两列相互转化,互为加解密。
alpha[1,1] = "A"
alpha[2,1] = "B"
alpha[3,1] = "C"
alpha[4,1] = "D"
alpha[5,1] = "E"
alpha[6,1] = "F"
alpha[7,1] = "G"
alpha[8,1] = "H"
alpha[9,1] = "I"
alpha[10,1] = "J"
alpha[11,1] = "K"
alpha[12,1] = "L"
alpha[13,1] = "M"
alpha[14,1] = "N"
alpha[15,1] = "O"
alpha[16,1] = "P"
alpha[17,1] = "Q"
alpha[18,1] = "R"
alpha[19,1] = "S"
alpha[20,1] = "T"
alpha[21,1] = "U"
alpha[22,1] = "V"
alpha[23,1] = "W"
alpha[24,1] = "X"
alpha[25,1] = "Y"
alpha[26,1] = "Z"
alpha[27,1] = "0"
alpha[28,1] = "1"
alpha[29,1] = "2"
alpha[30,1] = "3"
alpha[31,1] = "4"
alpha[32,1] = "5"
alpha[33,1] = "6"
alpha[34,1] = "7"
alpha[35,1] = "8"
alpha[36,1] = "9"
alpha[2,2] = "Z"
alpha[1,2] = "X"
alpha[4,2] = "C"
alpha[3,2] = "V"
alpha[6,2] = "B"
alpha[5,2] = "9"
alpha[8,2] = "M"
alpha[7,2] = ","
alpha[10,2] = "."
alpha[9,2] = "/"
alpha[12,2] = "7"
alpha[11,2] = ";"
alpha[14,2] = "L"
alpha[13,2] = "8"
alpha[16,2] = "J"
alpha[15,2] = "H"
alpha[18,2] = "6"
alpha[17,2] = "F"
alpha[20,2] = "D"
alpha[19,2] = "S"
alpha[22,2] = "1"
alpha[21,2] = "P"
alpha[24,2] = "O"
alpha[23,2] = "I"
alpha[26,2] = "U"
alpha[25,2] = "Y"
alpha[28,2] = "E"
alpha[27,2] = "Q"
alpha[30,2] = "R"
alpha[29,2] = "T"
alpha[32,2] = "W"
alpha[31,2] = "A"
alpha[34,2] = "G"
alpha[33,2] = "]"
alpha[36,2] = "K"
alpha[35,2] = "N"
tser = ""
//对从注册表中读出的注册码进行解密
for i = 1 to 16
tmpchr = mid(reg_code,i,1)
for j = 1 to 36
if tmpchr = alpha[j,2] then//查表,变换,第2列变为第1列,若是想作注册机,需要在此处进行逆运算,1列变2列。
tmpchr1 = alpha[j,1]
tser = tser + tmpchr1
end if
next
next
ls_disk1 = ""
for i = 1 to 15 step 2//取变换后的注册码的奇数位字符拼接成串
ls_disk1 = ls_disk1 + mid(tser,i,1)
next
if ls_disk1 <> ls_disk then//与硬盘序列号比较
return -1
else
return 0//相等,注册成功
end if
end function
public function string f_encode (string source_str);ulong lu_ll
char lc_char
string ls_rt_str
integer i
integer li_char
for i = 1 to len(trim(source_str))
lc_char = mid(source_str,i,1)
li_char = asc(lc_char)
lu_ll = of_bitwisexor(li_char,100)
ls_rt_str = ls_rt_str + char(lu_ll)
next
return ls_rt_str
end function
public function string f_genpuzzle ();string alpha[36]
string alser
integer i
integer ss
alser = ""
alpha[1] = "A"
alpha[2] = "B"
alpha[3] = "C"
alpha[4] = "D"
alpha[5] = "E"
alpha[6] = "F"
alpha[7] = "G"
alpha[8] = "H"
alpha[9] = "I"
alpha[10] = "J"
alpha[11] = "K"
alpha[12] = "L"
alpha[13] = "M"
alpha[14] = "N"
alpha[15] = "O"
alpha[16] = "P"
alpha[17] = "Q"
alpha[18] = "R"
alpha[19] = "S"
alpha[20] = "T"
alpha[21] = "U"
alpha[22] = "V"
alpha[23] = "W"
alpha[24] = "X"
alpha[25] = "Y"
alpha[26] = "Z"
alpha[27] = "0"
alpha[28] = "1"
alpha[29] = "2"
alpha[30] = "3"
alpha[31] = "4"
alpha[32] = "5"
alpha[33] = "6"
alpha[34] = "7"
alpha[35] = "8"
alpha[36] = "9"
randomize(0)
for i = 1 to 8
ss = rand(36)
alser = alser + alpha[ss]
next
return alser
end function
public function string f_genser ();string alser
string tser
char tmpchr
char tmpchr1
integer i
integer j
string ls_mhser
alser = f_getdisk()
alser = f_swap1(alser)
ls_mhser = f_genpuzzle()
ls_mhser = f_swap1(ls_mhser)
tser = left(ls_mhser,4) + left(alser,4) + right(ls_mhser,4) + right(alser,4)
return tser
end function
public function string f_getdisk ();long retval
string sdrv
string str
string str2
string ls_retval
long a
long b
ulong ll_retval
n_cst_numerical ln_1
string ls_format = "0000"
integer li_len
sdrv = "C:\"
str = space(256)
str2 = space(256)
ll_retval = getvolumeinformationa(sdrv,str,256,retval,a,b,str2,256) //调用API,获取硬盘序列号
ls_retval = ln_1.of_hex(retval)//转换为16进制串
if len(ls_retval) > 4 then
li_len = len(ls_retval) - 4
ls_retval = upper(left(ls_format,4 - li_len) + left(ls_retval,li_len) + right(ls_retval,4))//若不足8位,在串前补0
end if
return ls_retval
end function
public function string f_redreg (string xsxt_key);string ls_value
string ls_path
integer li_flag
ls_path = "HKEY_CURRENT_USER\Software\xsxt\xsxt_" + xsxt_key
li_flag = registryget(ls_path,xsxt_key,regstring!,ls_value)
if li_flag = 1 then
return ls_value
else
return "err"
end if
end function
public function integer f_setreg (string str_num,string str_info);string ls_path
integer li_flag
ls_path = "HKEY_CURRENT_USER\Software\xsxt\xsxt_" + str_num
li_flag = registryset(ls_path,str_num,regstring!,str_info)
if li_flag = 1 then
return 0
else
return -1
end if
end function
public function string f_swap1 (string str_input);char alpha[36,2]
string tser
string alser
char tmpchr
char tmpchr1
integer i
integer j
integer strlen
alpha[1,1] = "A"
alpha[2,1] = "B"
alpha[3,1] = "C"
alpha[4,1] = "D"
alpha[5,1] = "E"
alpha[6,1] = "F"
alpha[7,1] = "G"
alpha[8,1] = "H"
alpha[9,1] = "I"
alpha[10,1] = "J"
alpha[11,1] = "K"
alpha[12,1] = "L"
alpha[13,1] = "M"
alpha[14,1] = "N"
alpha[15,1] = "O"
alpha[16,1] = "P"
alpha[17,1] = "Q"
alpha[18,1] = "R"
alpha[19,1] = "S"
alpha[20,1] = "T"
alpha[21,1] = "U"
alpha[22,1] = "V"
alpha[23,1] = "W"
alpha[24,1] = "X"
alpha[25,1] = "Y"
alpha[26,1] = "Z"
alpha[27,1] = "0"
alpha[28,1] = "1"
alpha[29,1] = "2"
alpha[30,1] = "3"
alpha[31,1] = "4"
alpha[32,1] = "5"
alpha[33,1] = "6"
alpha[34,1] = "7"
alpha[35,1] = "8"
alpha[36,1] = "9"
alpha[1,2] = "Z"
alpha[2,2] = "X"
alpha[3,2] = "C"
alpha[4,2] = "V"
alpha[5,2] = "B"
alpha[6,2] = "9"
alpha[7,2] = "M"
alpha[8,2] = ","
alpha[9,2] = "."
alpha[10,2] = "/"
alpha[11,2] = "7"
alpha[12,2] = ";"
alpha[13,2] = "L"
alpha[14,2] = "8"
alpha[15,2] = "J"
alpha[16,2] = "H"
alpha[17,2] = "6"
alpha[18,2] = "F"
alpha[19,2] = "D"
alpha[20,2] = "S"
alpha[21,2] = "1"
alpha[22,2] = "P"
alpha[23,2] = "O"
alpha[24,2] = "I"
alpha[25,2] = "U"
alpha[26,2] = "Y"
alpha[27,2] = "E"
alpha[28,2] = "Q"
alpha[29,2] = "R"
alpha[30,2] = "T"
alpha[31,2] = "W"
alpha[32,2] = "A"
alpha[33,2] = "G"
alpha[34,2] = "]"
alpha[35,2] = "K"
alpha[36,2] = "N"
tser = ""
alser = trim(str_input)
strlen = len(alser)
for i = 1 to strlen
tmpchr = mid(alser,i,1)
for j = 1 to 36
if tmpchr = alpha[j,1] then
tmpchr1 = alpha[j,2]
tser = tser + tmpchr1
end if
next
next
return tser
end function
public function string uf_patchstr (string userstr,integer userlen);integer i
integer strlen
userstr = trim(userstr)
if len(userstr) > userlen then
messagebox("错误","长度错误,无法转换")
return "error"
end if
strlen = userlen - len(userstr)
for i = 1 to strlen
userstr = "0" + userstr
next
return userstr
end function
on user_reg.create
call super::create;
end on
on user_reg.destroy
call super::destroy;
end on
在上面的代码中,关键部分作为注释,现总结一下:
对注册起作用的是f_checkregcode和f_getdisk。
注册码算法为:
1、注册码为16位长度的串,为大写。
2、取出硬盘序列号后,若为8位16进制串,则不变,否则在前补0,拼成8位串。
3、对所得的硬盘序列号串,按f_checkregcode中的明密文转换表,进行变换,变换的结果,分别记入注册表串的奇数位,即1,3,5,7,9,11,13,15的位置。
4、注册码偶数位的字符任意,只要是明密文表中能找到可以了。我在注册机中指定为‘A’。
注册机源码:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Strutils;
type
TForm1 = class(TForm)
Edit1: TEdit;
Label1: TLabel;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
var
serialnumber: integer;
comlen: DWORD;
flag: DWORD;
str: AnsiString;
alpha: array[1..36, 1..2] of char;
i, j: integer;
len: integer;
enstr: array[1..16] of char;
begin
GetVolumeInformation(Pchar('c:'), nil, MAX_PATH + 1, @serialnumber, comlen, flag, nil, MAX_PATH + 1);
str := inttohex(serialnumber, 4);
len := length(str);
if (len > 4) then
begin
len := len - 4;
// ls_retval = upper(left(ls_format,4 - li_len) + left(ls_retval,li_len) + right(ls_retval,4))
str := leftstr('0000', 4 - len) + leftstr(str, len) + rightstr(str, 4);
end;
str:=UpperCase(str);
Label1.Caption:=str;
alpha[1][1] := 'A';
alpha[2][1] := 'B';
alpha[3][1] := 'C';
alpha[4][1] := 'D';
alpha[5][1] := 'E';
alpha[6][1] := 'F';
alpha[7][1] := 'G';
alpha[8][1] := 'H';
alpha[9][1] := 'I';
alpha[10][1] := 'J';
alpha[11][1] := 'K';
alpha[12][1] := 'L';
alpha[13][1] := 'M';
alpha[14][1] := 'N';
alpha[15][1] := 'O';
alpha[16][1] := 'P';
alpha[17][1] := 'Q';
alpha[18][1] := 'R';
alpha[19][1] := 'S';
alpha[20][1] := 'T';
alpha[21][1] := 'U';
alpha[22][1] := 'V';
alpha[23][1] := 'W';
alpha[24][1] := 'X';
alpha[25][1] := 'Y';
alpha[26][1] := 'Z';
alpha[27][1] := '0';
alpha[28][1] := '1';
alpha[29][1] := '2';
alpha[30][1] := '3';
alpha[31][1] := '4';
alpha[32][1] := '5';
alpha[33][1] := '6';
alpha[34][1] := '7';
alpha[35][1] := '8';
alpha[36][1] := '9';
alpha[2][2] := 'Z';
alpha[1][2] := 'X';
alpha[4][2] := 'C';
alpha[3][2] := 'V';
alpha[6][2] := 'B';
alpha[5][2] := '9';
alpha[8][2] := 'M';
alpha[7][2] := ',';
alpha[10][2] := '.';
alpha[9][2] := '/';
alpha[12][2] := '7';
alpha[11][2] := ';';
alpha[14][2] := 'L';
alpha[13][2] := '8';
alpha[16][2] := 'J';
alpha[15][2] := 'H';
alpha[18][2] := '6';
alpha[17][2] := 'F';
alpha[20][2] := 'D';
alpha[19][2] := 'S';
alpha[22][2] := '1';
alpha[21][2] := 'P';
alpha[24][2] := 'O';
alpha[23][2] := 'I';
alpha[26][2] := 'U';
alpha[25][2] := 'Y';
alpha[28][2] := 'E';
alpha[27][2] := 'Q';
alpha[30][2] := 'R';
alpha[29][2] := 'T';
alpha[32][2] := 'W';
alpha[31][2] := 'A';
alpha[34][2] := 'G';
alpha[33][2] := ']';
alpha[35][2] := 'N';
alpha[36][2] := 'K';
j := 1;
for i := 1 to 16 do
begin
if i mod 2 <> 0 then
begin
for len := 1 to 36 do
begin
if alpha[len][1] = str[j] then
begin
enstr[i] := alpha[len][2];
break;
end;
end;
inc(j);
end
else
begin
enstr[i] := 'A';
end;
end;
edit1.Text:=enstr;
end;
end.
--------------------------------------------------------------------------------
【经验总结】
这次破解主要在笨鸟我先飞兄弟的基础上做的,他把PBKILLER反编译后的代码给了我,我只是阅读了PB的源码,PB脚本与
BASIC语法类似,兄弟们如果破PB,可以参照BASIC语法来阅读源码。
PBKILLER真的很强,反编译出来的代码可读性很好,呵呵。
--------------------------------------------------------------------------------
【版权声明】: 请保持文章完整及作者信息。
2006年09月04 8:30:32