caterpilla 发表于 2006-9-4 08:31:58

直销业绩考核系统算法分析-PB程序

【文章标题】: 直销业绩考核系统算法分析
【文章作者】: 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//关键部分
string tser
string ls_disk
string ls_disk1
char tmpchr
char tmpchr1
integer i
integer j

ls_disk = f_getdisk()//获取硬盘序列号
ls_disk1 = ""
//下面的ALPHA为明密文转换表,两列相互转化,互为加解密。
alpha = "A"
alpha = "B"
alpha = "C"
alpha = "D"
alpha = "E"
alpha = "F"
alpha = "G"
alpha = "H"
alpha = "I"
alpha = "J"
alpha = "K"
alpha = "L"
alpha = "M"
alpha = "N"
alpha = "O"
alpha = "P"
alpha = "Q"
alpha = "R"
alpha = "S"
alpha = "T"
alpha = "U"
alpha = "V"
alpha = "W"
alpha = "X"
alpha = "Y"
alpha = "Z"
alpha = "0"
alpha = "1"
alpha = "2"
alpha = "3"
alpha = "4"
alpha = "5"
alpha = "6"
alpha = "7"
alpha = "8"
alpha = "9"
alpha = "Z"
alpha = "X"
alpha = "C"
alpha = "V"
alpha = "B"
alpha = "9"
alpha = "M"
alpha = ","
alpha = "."
alpha = "/"
alpha = "7"
alpha = ";"
alpha = "L"
alpha = "8"
alpha = "J"
alpha = "H"
alpha = "6"
alpha = "F"
alpha = "D"
alpha = "S"
alpha = "1"
alpha = "P"
alpha = "O"
alpha = "I"
alpha = "U"
alpha = "Y"
alpha = "E"
alpha = "Q"
alpha = "R"
alpha = "T"
alpha = "W"
alpha = "A"
alpha = "G"
alpha = "]"
alpha = "K"
alpha = "N"
tser = ""
//对从注册表中读出的注册码进行解密
for i = 1 to 16
        tmpchr = mid(reg_code,i,1)

        for j = 1 to 36

                if tmpchr = alpha then//查表,变换,第2列变为第1列,若是想作注册机,需要在此处进行逆运算,1列变2列。
                        tmpchr1 = alpha
                        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
string alser
integer i
integer ss

alser = ""
alpha = "A"
alpha = "B"
alpha = "C"
alpha = "D"
alpha = "E"
alpha = "F"
alpha = "G"
alpha = "H"
alpha = "I"
alpha = "J"
alpha = "K"
alpha = "L"
alpha = "M"
alpha = "N"
alpha = "O"
alpha = "P"
alpha = "Q"
alpha = "R"
alpha = "S"
alpha = "T"
alpha = "U"
alpha = "V"
alpha = "W"
alpha = "X"
alpha = "Y"
alpha = "Z"
alpha = "0"
alpha = "1"
alpha = "2"
alpha = "3"
alpha = "4"
alpha = "5"
alpha = "6"
alpha = "7"
alpha = "8"
alpha = "9"
randomize(0)

for i = 1 to 8
        ss = rand(36)
        alser = alser + alpha
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
string tser
string alser
char tmpchr
char tmpchr1
integer i
integer j
integer strlen

alpha = "A"
alpha = "B"
alpha = "C"
alpha = "D"
alpha = "E"
alpha = "F"
alpha = "G"
alpha = "H"
alpha = "I"
alpha = "J"
alpha = "K"
alpha = "L"
alpha = "M"
alpha = "N"
alpha = "O"
alpha = "P"
alpha = "Q"
alpha = "R"
alpha = "S"
alpha = "T"
alpha = "U"
alpha = "V"
alpha = "W"
alpha = "X"
alpha = "Y"
alpha = "Z"
alpha = "0"
alpha = "1"
alpha = "2"
alpha = "3"
alpha = "4"
alpha = "5"
alpha = "6"
alpha = "7"
alpha = "8"
alpha = "9"
alpha = "Z"
alpha = "X"
alpha = "C"
alpha = "V"
alpha = "B"
alpha = "9"
alpha = "M"
alpha = ","
alpha = "."
alpha = "/"
alpha = "7"
alpha = ";"
alpha = "L"
alpha = "8"
alpha = "J"
alpha = "H"
alpha = "6"
alpha = "F"
alpha = "D"
alpha = "S"
alpha = "1"
alpha = "P"
alpha = "O"
alpha = "I"
alpha = "U"
alpha = "Y"
alpha = "E"
alpha = "Q"
alpha = "R"
alpha = "T"
alpha = "W"
alpha = "A"
alpha = "G"
alpha = "]"
alpha = "K"
alpha = "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 then
                        tmpchr1 = alpha
                        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 of char;
    i, j: integer;
    len: integer;
    enstr: array 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 := 'A';
    alpha := 'B';
    alpha := 'C';
    alpha := 'D';
    alpha := 'E';
    alpha := 'F';
    alpha := 'G';
    alpha := 'H';
    alpha := 'I';
    alpha := 'J';
    alpha := 'K';
    alpha := 'L';
    alpha := 'M';
    alpha := 'N';
    alpha := 'O';
    alpha := 'P';
    alpha := 'Q';
    alpha := 'R';
    alpha := 'S';
    alpha := 'T';
    alpha := 'U';
    alpha := 'V';
    alpha := 'W';
    alpha := 'X';
    alpha := 'Y';
    alpha := 'Z';
    alpha := '0';
    alpha := '1';
    alpha := '2';
    alpha := '3';
    alpha := '4';
    alpha := '5';
    alpha := '6';
    alpha := '7';
    alpha := '8';
    alpha := '9';
    alpha := 'Z';
    alpha := 'X';
    alpha := 'C';
    alpha := 'V';
    alpha := 'B';
    alpha := '9';
    alpha := 'M';
    alpha := ',';
    alpha := '.';
    alpha := '/';
    alpha := '7';
    alpha := ';';
    alpha := 'L';
    alpha := '8';
    alpha := 'J';
    alpha := 'H';
    alpha := '6';
    alpha := 'F';
    alpha := 'D';
    alpha := 'S';
    alpha := '1';
    alpha := 'P';
    alpha := 'O';
    alpha := 'I';
    alpha := 'U';
    alpha := 'Y';
    alpha := 'E';
    alpha := 'Q';
    alpha := 'R';
    alpha := 'T';
    alpha := 'W';
    alpha := 'A';
    alpha := 'G';
    alpha := ']';
    alpha := 'N';
    alpha := '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 = str then
          begin
            enstr := alpha;
            break;
          end;
      end;
      inc(j);
      end
      else
      begin
      enstr := 'A';
      end;

    end;
    edit1.Text:=enstr;
end;

end.




--------------------------------------------------------------------------------
【经验总结】
这次破解主要在笨鸟我先飞兄弟的基础上做的,他把PBKILLER反编译后的代码给了我,我只是阅读了PB的源码,PB脚本与
BASIC语法类似,兄弟们如果破PB,可以参照BASIC语法来阅读源码。

PBKILLER真的很强,反编译出来的代码可读性很好,呵呵。

--------------------------------------------------------------------------------
【版权声明】: 请保持文章完整及作者信息。

                                                       2006年09月04 8:30:32

[ 本帖最后由 caterpilla 于 2006-9-4 10:17 编辑 ]

ZHOU2X 发表于 2006-9-4 11:18:39

学习!!支持!!!!

cha23 发表于 2006-9-4 13:18:29

强!!!!!!

寒湖鹤影 发表于 2006-9-4 14:41:13

看不懂,下来慢慢学

bfqyygy 发表于 2006-9-4 14:58:46

简直是神话。看不懂。。。这么有技术性的文章。得好好收藏!

xingbing 发表于 2006-9-4 17:22:22

PB方面的教程太少了。

caterpilla 发表于 2006-9-5 19:06:41

原帖由 xingbing 于 2006-9-4 17:22 发表
PB方面的教程太少了。
PB擅长数据库方面的开发,适合做管理系统。

笨鸟我先飞 发表于 2006-9-6 08:45:28

惊涛兄软件可能在检测注册码的时候还有个地方,我们现在知道他对注册码的奇数位-->转换表-->转换后的八位与硬件码做对比,可是如果我们在偶数位那里随便填入除A或者别的(未测试)数字软件则提示注册错误

caterpilla 发表于 2006-9-6 09:21:29

原帖由 笨鸟我先飞 于 2006-9-6 08:45 发表
惊涛兄软件可能在检测注册码的时候还有个地方,我们现在知道他对注册码的奇数位-->转换表-->转换后的八位与硬件码做对比,可是如果我们在偶数位那里随便填入除A或者别的(未测试)数字软件则提示注册错误
我试过一些别的字母,在注册机生成后,把偶数位改成其它的字母,当时没提示错误。有没有可能是注册表垃圾信息造成的问题。
页: [1]
查看完整版本: 直销业绩考核系统算法分析-PB程序