前往Shuct.Net首页

Shudepb PB反编译专家长时间以来,为业内同类软件事实上的唯一选择.细节,彰显专业.态度,决定品质.

关于PBKILLER的搜索

如何从PB写的程序中提取注册算法,写出注册机 [文字模式] - 看雪安全论坛 看雪安全论坛 > Windows > 『软件调试逆向』 > 如何从PB写的程序中提取注册算法,写出注册机 PDA 查看完整版本 : 如何从PB写的程序中提取注册算法,写出注册机 lei_z_r2006-04-09, 00:54:18如何从PB写的程序中提取注册算法,写出注册机 目标软件:机动车驾驶员模拟考试系统 加密方式:机器码+注册码,未注册有功能限制 作  者: 雷电(lzrlzr) 破解时间:2006-04-08 解密工具:PBKILLER Powerbuild10 破解说明:主要是说明如何去分析PB程序,并找出注册算法,Powerbuild的编程方法就不提了吧。   太忙,好久没写了,把此文送给我的朋友。   朋友发来一个程序:机动车驾驶员模拟考试系统,说让我试试,在安装时就发现安装进度上提示正在安装PB*.dll,我想肯定是个 Powerbuild写的程序。安装完以后,在安装目录中发现有PBVM80.DLL,确认了这个程序是用PB8.0写的软件。   软件一启动主程序jdriver.exe,就会弹出一个要求注册的窗口,窗口的标题是:软件注册,上面有两个按钮,一个是:注册确认 ,一个是:继续试用。随意输入一个注册码,就会提示当前注册码错误。   于是打开PBKILLER(感谢PBKILLER的作者kivens,写出这个超强的反编译PB程序的工具,作者好象也在论坛中),对软件的安装目 录中的主程序和 dll 进行反编译,最后发现在private.dll 中有一个窗体w_registe,这个窗体的propertier(属性)中有 string title = "软件注册" 在窗体的controls(控制)中有几个按钮, 按钮cb_1 的属性是: string text = "注册确认" 按钮cb_2 的属性是: string text = "继续试用" 那么从这个可以判断出w_registe窗体就是软件启动时的注册界面,按钮cb_1就是注册确认。那么在按钮cb_1的events(事件) 中可以找到clicked事件,事件中的代码如下(为了减少长度,我删掉了代码中的注释): integer li_row string ls_reg if tag <> "" then return end if parent.sle_2.text = upper(trim(parent.sle_2.text)) if parent.sle_2.text = "" then msg("注册码不能为空,请重新输入!") parent.sle_2.setfocus() return end if SELECT count ( *) FROM 系统设置表 WHERE 编号 =0 using sqlca; if li_row = 1 then update 系统设置表 SET 机器码 =' ' , 注册码 =' ' WHERE 编号 =0 using sqlca; else DELETE FROM 系统设置表 WHERE 编号 =0 using sqlca; INSERT INTO 系统设置表 ( 编号 , 机器码 , 注册码 , 启用时间 , 剩余次数 ) VALUES ( 0 , ' ' , ' ' , getdate ( ) , 0 ) using sqlca; end if if sqlca.sqlcode <> 0 then rollback using sqlca; msg("保存注册码到系统中失败,请重启后再次注册!") return end if commit using sqlca; if not gnv_app.of_reged() then              ;如果返回值不为真时,注册不成功 msg("当前注册码错误,如果您申请注册码使用的是“" + iff (parent.rb_2.checked,parent.rb_1.text,parent.rb_2.text) + "”,请先选中“" + iff (parent.rb_2.checked,parent.rb_1.text,parent.rb_2.text) + "”再注册确认!") parent.sle_2.setfocus() return end if msg("感谢您对我们软件的注册使用。~n" + "您无私的帮助将是我们发展的最大动力!~n" + "为使您的注册立即生效,系统将退出 并请重新运行!") parent.cb_2.tag = "T" close(parent) halt close return 这段代码比较容易读懂,注册成功的关键就是gnv_app.of_reged(),这个过程反回值为真时,注册就会成功。 于是我继续反编译找,在jdriver.dll的nvo_app的function中找到如下代码of_reged () returns boolean string ls_code string ls_reg string ls_cpu string ls_disk SELECT 注册码 FROM 系统设置表 WHERE 编号 =0 ORDER BY 编号 ASC using sqlca; if isnull(ls_reg) then ls_reg = "" end if ls_reg = trim(ls_reg) ls_cpu = trim(of_reg_disk()) ls_disk = trim(of_reg_cpu()) if ls_cpu = "" and ls_disk = "" then msg("读取系统硬件序列号出错,可能原因如下:~n~n" + "1. 安装目录中文件 GetCpu.DLL 丢失或错误;~n" + "2. 安装 目录中文件 Md5.DLL 丢失或错误;~n" + "3. 本系统在当前操作系统中不能读取硬件数据;~n" + "4. 本机CPU序列号非法(此原因 需更换CPU);~n" + "5. 本机硬盘序列号非法(此原因需更换硬盘);~n" + "6. 其它原因......;") return false end if gnv_info.reg_code_registe = ls_reg if ls_reg <> "" and upper(ls_reg) = upper(of_reg_arithmetic(ls_disk)) then gnv_info.reg_code_machine = ls_disk return true end if if ls_reg <> "" and upper(ls_reg) = upper(of_reg_arithmetic(ls_cpu)) then gnv_info.reg_code_machine = ls_cpu return true end if gnv_info.reg_code_machine = ls_disk + "," + ls_cpu return false 从这个过程中可能看到,注册成功的关键条件就是 upper(ls_reg) = upper(of_reg_arithmetic(ls_disk)) 或者是 upper(ls_reg) = upper(of_reg_arithmetic(ls_cpu)) 这也就是作者设计的,注册码可以和本机的cpu绑定,也可以和本机的硬盘号绑定。 呵呵,继续找,在jdriver.dll的nvo_app的function中找到如下代码: of_reg_arithmetic (string as_code) returns string char lc_key1[] char lc_key2[] char lc_base_char integer li_key1 integer li_key2 integer li_key string ls_base string ls_usercode integer li_len integer li_loop integer li_tmp integer li_right_mod integer li_strlen if as_code = "" then return as_code end if ls_base = gnv_info.basestr li_len = 50 if len(as_code) < 50 then li_len = len(as_code) end if for li_loop = 1 to li_len lc_key1[li_loop] = mid(as_code,li_loop,1) li_key1 += asc(lc_key1[li_loop]) next for li_loop = 1 to li_len step 2 lc_key2[li_loop] = mid(as_code,li_loop,1) li_key2 += asc(lc_key2[li_loop]) next li_key = li_key1 + li_key2 + 50 li_strlen = 25 if gnv_info.ib_project then li_strlen = 13 end if for li_loop = 1 to li_strlen li_len = len(ls_base) li_tmp = mod(li_key,li_len) li_tmp = li_tmp + li_right_mod if li_tmp > li_len then li_tmp = mod(li_tmp,li_len) end if if li_tmp = 0 then li_tmp = 1 end if lc_base_char = char(mid(ls_base,li_tmp,1)) ls_usercode = ls_usercode + string(lc_base_char) li_right_mod = li_tmp ls_base = left(ls_base,li_tmp - 1) + right(ls_base,li_len - li_tmp) next return f_public_replaceall(upper(ls_usercode),"O","0")    ;把字母“O”,全部用数字“0”代替 呵呵,OK,这就是根据机器码生成注册码的字符串变换算法了,用这个就可以写出注册机了。 算法总结:   这个程序根据机器的cpu,硬盘号,经过变换得到机器码(机器码的生成算法可以在of_reg_cpu () ,of_reg_disk ()中得到 ,就是把机器的cpuid或硬盘id分成两部分,分别进行md5变换,再组合成机器码。),根据机码变换得到注册码,再和输入的注册码 字符串进行比较,如果相同就注册成功。作者在验证注册码是否正确时使用的注册算法是正向算法,不需要写出逆算法就可以写出注 册机。作者在算法中设计的比较人性化的一点就是注册码中不使用字母“O”,全部用数字“0”代替。 到此,在 pb中新建一个工程,增加一个窗体,写出注册机,我用的是Powerbuild10(pb我用的也不熟,只会作注册机,呵)。 (算法中用到的f_public_replaceall()定义如下, f_public_replaceall (string as_string1,string as_string2,string as_string3) returns string 存在于OBJECT.dll中) 最后,就此程序加密方法的改进,给作者一点建议(呵呵,不好意思啊): 1、程序中不要包含注册机生成器窗体部分(private.dll 中有一个窗体w_register,就是作者的注册码生成器的窗体,更要命的是包 含完整的注册码生成算法,和我写的注册机代码几乎是一样的,呵呵) 2、取机器 cpuid和硬盘id时,最好放到一个比较好的程序中,最好包含在程序中,不要使用单独的dll文件(我想作者可能是使用了 别人提供的标准函数),这种dll自身就不安全,可以对dll进行修改,让它在所有的机器上生成一模一样的机器码,只需注册一套, 就可以达到复制分发的目的。 3、注册算法的使用要合理,尽理使用一些非对称的加密算法,注册码的生成算法和校验算法不要同时出现在发布的程序中,这样很难 逆出加密算法。  最后,请大家支持国产软件,如果经济条件可以,对软件有需要,还是可以注册一下。 附作者的注册机生成算法(我的就不写出来了,和这个差不多): parent.sle_2.text = trim(parent.sle_2.text) if tag = "" then parent.cb_1.triggerevent(clicked!) return end if parent.mle_1.text = "" if len(parent.sle_2.text) <> 13 then msg("机器码长度必须为13位!") return end if parent.sle_2.text = f_public_replaceall(parent.sle_2.text,"O","0") parent.sle_3.text = upper(gnv_app.of_reg_arithmetic(parent.sle_2.text)) if gnv_info.ib_project then return end if parent.mle_1.text = "尊敬的客户,您好:~r~n" + "感谢你注册软件《" + gnv_info.soft_name_cn + "》成功!~r~n" + "你 的机器码:" + parent.sle_2.text + "~r~n" + "您的注册码:" + parent.sle_3.text + "~r~n" + "注册时间:" + string (today(),"YYYY年MM月DD日") + "~r~n~r~n" + "希望本软件能为你的驾车增添更多的乐趣!~r~n~r~n" + "软件升级与题库更新请 访问:" + gnv_info.comp_http + "~r~n" + "如有软件疑问请发邮件到:" + gnv_info.comp_mail + "~r~n" + "再次感谢你对 本软件的支持,祝你顺利过关!~r~n" + " 劲维科技~r~n" + " " + string (today(),"yyyy-mm-dd") return 魔女2006-04-09, 09:30:43哈哈哈哈,今天坐到沙发了.哈哈哈哈 魔女2006-04-09, 09:37:50:): :(: :o: :D: ;): :p: :cool: :rolleyes: :mad: lzq19732006-04-09, 09:39:06高,好文 keygen2006-06-25, 16:57:51利害,可惜我看不懂 machine2006-08-15, 14:45:51哈哈,这个软件我也破了一次,不过注册机是用VFP写的,我只会用VFP程序!! backuper2006-08-15, 15:19:56顶一下 ,, !! 老大 好崇拜 二毛2006-08-16, 19:15:13不是汇编的不看:D: 皮蛋瘦肉2006-08-17, 10:04:18学习中~~ 今天搞定了一个软件 keymake的内存注册机也做出来了 高兴就到这里来看看 没有想到有学了不少的东西 tebie2006-08-17, 18:22:19可惜就是很少人用PB做出一些很有价值的软件... wch20042006-08-18, 08:57:09这个软件算法简单,很容易破解,如果算法设计难点,不容易破的,如果作者用混淆器将PB文件加密了,那个PBKILL就无法看到上面的代码了。 zhizhengfu2006-09-13, 11:03:33高手,学习中, caiweb2006-09-13, 14:21:45注册的时候代码如下: 略了一些次要的东西。 reg_rand1 = mid(trim(parent.sle_1.text),2,1) reg_temp1 = trim(f_conversion(trim(mid(trim(parent.sle_1.text),3,100)),reg_rand1,"2")) reg_rand2 = mid(trim(parent.sle_1.text),1,1) reg_temp2 = f_conversion(trim(reg_temp1),reg_rand2,"2") if trim(f_hdd_id()) <> trim(reg_temp2) then messagebox("提示信息","您的注册码错误!") return end if update "register" SET "enregister" =' ' , "register" =' ' , "save_id" =' ' WHERE "register"."serno" =1 using sqlca; /* SQL Parameters List 0-> :parent.sle_djm.text 1-> :parent.sle_1.text 2-> :parent.sle_id.text */ if sqlca.sqlcode = 0 then commit using sqlca; w_main.triggerevent(open!) m_right_mouse.m_20.enabled = true messagebox("提示信息","注册码成功! 请重新启动本软件!") parent.cb_2.triggerevent(clicked!) close(w_main) else rollback using sqlca; messagebox("提示信息","无法注册!!!~n错误代码:" + string(sqlca.sqlcode) + "~n错误内容:" + sqlca.sqlerrtext) return end if 其中,f_conversion()涵数已知,f_hdd_id()已知就是id号,登记码已知,如何反算出注册码? jinhf2006-09-14, 11:29:158月份考驾照,碰见过这个软件,偶已经搞定,所以楼主的文章我不用全看就知道怎么搞的.不过还是谢谢楼主的共享精神,由于我比较忙,当时注册后没写下任何破文,楼主正好代劳了,谢谢 jinhf2006-09-14, 11:31:14最初由 caiweb 发布 注册的时候代码如下: 略了一些次要的东西。 reg_rand1 = mid(trim(parent.sle_1.text),2,1) reg_temp1 = trim(f_conversion(trim(mid(trim(parent.sle_1.text),3,100)),reg_rand1,"2")) reg_rand2 = mid(trim(parent.sle_1.text),1,1) ........ 可以看看我的一个破文,见我的博客http://21jhf.52blog.net 或许对你有所帮助 vBulletin&reg; v3.8.7,Copyright &copy;2000-2014,vBulletin Solutions Inc.