【破文标题】东凌ADSL密码终结者2005 注册算法追解
【对 象】初入门的新手
【下载地址】见附件【破解工具】OD
【保护方式】序号
【任 务】找出算法
【破文作者】noNumber
【组 织】没有
【破解声明】只是感兴趣,没其他目的
【破解过程】 ---------------------------------------------------------------------------------------------
上面这些是自己写的吗? 论坛格式要求吗? 我看别人都这样写。。
第一次写破文,失误之处请原谅。。
终于有帐号了~~~黯然泪下。。。
小弟接触破解半个多月,以前搞过免杀,学过编程,学习破解还算轻松,虽然到各论坛找了一些Cheak Me来玩,但大多数都
只做到爆破,一直做不到完美破解————写出一个像样的注册机,要不是太难,要不是一些算法太简单不想写……
正好近几天同学无聊下了一个 东凌ADSL密码终结者2005破解版,内置注册机,作者叫QIQI,还是用VB写的注册机……
于是心想2005年的东西正好拿来练手。。2005年的东西应该比较简单。。OK。兴趣来了。开始 先运行程序,大致看下,点击“输入注册码”,出现注册窗口以及我的机器码:680689520
随意输入111 点击注册,提示 “请填入有效的注册码”。。于是又随意多输入了几个111。幸运的提示“注册码已保存,请重新启动程序验证注册是否有效”。。后来OD中发现注册码必须是16位字符。
原来是重起验证的。信息保存在哪呢? 注册表? 文件? 经过监视发现输入注册码后程序目录下会生成一个licence.dat
用记事本打开一看,果然是刚才输入的16个“1”。。好的,既然是读文件取注册码的,那么通常只要在OD里断CreatFile,ReadFile(EX)就行了。。 载入OD发现入口点代码开始就PUSHAD。。接一个CALL 极可能加壳了,PEID显示为ASPack 2.12 压缩壳脱掉后无法运行,检查一番后确定脱壳文件没问题,难道是自效验? 朋友就发彪了,他打开两个OD,一个载入脱壳后的文件,一个载入原文件并到达OEP。。。然后一边一个F8。慢慢的比较,发现了一个跳转的不同,修改,脱壳后的程序成功运行= =。汗 设置好断点后F9让程序跑起来,并注意堆栈窗口, 第一次可疑的地方:
0012FEFC 00409343 /CALL 到 CreateFileA 来自 Unpacked.0040933E
0012FF00 00A22438 |FileName = "E:\Cheak\over\东凌ADSL密码终结者破解版\Unpacked1.ExE"
0012FF04 80000000 |Access = GENERIC_READ
0012FF08 00000003 |ShareMode = FILE_SHARE_READ|FILE_SHARE_WRITE
0012FF0C 00000000 |pSecurity = NULL
0012FF10 00000003 |Mode = OPEN_EXISTING
0012FF14 00000080 |Attributes = NORMAL
0012FF18 00000000 \hTemplateFile = NULL 打开自己吗。。估计是刚才的自效验吧,这里不多管。继续。 经过N次F9后看到:
0012FCC0 00409343 /CALL 到 CreateFileA 来自 Unpacked.0040933E
0012FCC4 036AA8D8 |FileName = "E:\Cheak\over\东凌ADSL密码终结者破解版\licence.dat"
0012FCC8 80000000 |Access = GENERIC_READ
0012FCCC 00000003 |ShareMode = FILE_SHARE_READ|FILE_SHARE_WRITE
0012FCD0 00000000 |pSecurity = NULL
0012FCD4 00000003 |Mode = OPEN_EXISTING
0012FCD8 00000080 |Attributes = NORMAL
0012FCDC 00000000 \hTemplateFile = NULL 打开licence.dat了。。那么关键点应该在附近了,继续F9
经过一次看到:
0012FCD4 0040938D /CALL 到 ReadFile 来自 Unpacked.00409388
0012FCD8 000001E8 |hFile = 000001E8 (window)
0012FCDC 036AA920 |Buffer = 036AA920
0012FCE0 00000010 |BytesToRead = 10 (16.)
0012FCE4 0012FCEC |pBytesRead = 0012FCEC
0012FCE8 00000000 \pOverlapped = NULL 读文件了,没错的话这个读文件就是在取输入的注册码了。。。清除断点后ALT+F9执行到返回
/*40938D*/ test eax,eax -来到这里
/*40938F*/ jnz XUnpacked.00409398
/*409391*/ mov dword ptr ss:[esp],-0x1
/*409398*/ mov eax,dword ptr ss:[esp]
/*40939B*/ pop edx
/*40939C*/ pop edi
/*40939D*/ pop esi
/*40939E*/ pop ebx
/*40939F*/ retn -好嘛,刚来就返回 F8出去这个CALL,看到的代码同样离RETN很近,继续返回调用。。直到发现进入一个CALL前的寄存器数据非常可疑后才停下 /*4ED593*/ call Unpacked.00420874 //刚才读文件的CALL
/*4ED598*/ mov eax,dword ptr ss:[ebp-0x1C] //出来后EAX指向 一串字符的地址
/*4ED59B*/ mov edx,dword ptr ss:[ebp-0xC]
/*4ED59E*/ mov edx,dword ptr ds:[edx+0x4] //EDX指项我输入的注册码
/*4ED5A1*/ call Unpacked.00404738 //这里很有可能就是比较了
/*4ED5A6*/ sete byte ptr ss:[ebp-0x1] //条件设置
看到EAX指向的字符串 “da9c052177b5cd68”。及其可能为真码,于是到了桌面复制了一个原程序,输入这个码,重起程序,估计得没错,这就是真码,(明码比较就是好哇),到这里,已经可以爆破或者出内存补丁了,不过那不是目的,所以将代码往上拉,因为上面很有可能是得出真码的代码。。一直拉到看到如下代码
/*4ED44D*/ pop ebx
/*4ED44E*/ retn
/*4ED44F*/ nop
/*4ED450*/ push ebp //一般程序的CALL入口,在此下断
/*4ED451*/ mov ebp,esp
/*4ED453*/ mov ecx,0x8
/*4ED458*/ push 0x0
/*4ED45A*/ push 0x0
/*4ED45C*/ dec ecx
/*4ED45D*/ jnz XUnpacked.004ED458 //开辟堆栈空间
/*4ED45F*/ push ebx
/*4ED460*/ mov ebx,eax
/*4ED462*/ xor eax,eax
/*4ED464*/ push ebp
/*4ED465*/ push Unpacked.004ED5F7
/*4ED46A*/ push dword ptr fs:[eax]
/*4ED46D*/ mov dword ptr fs:[eax],esp
/*4ED470*/ lea edx,dword ptr ss:[ebp-0x24]
/*4ED473*/ mov eax,dword ptr ds:[0x4F11E4]
/*4ED478*/ mov eax,dword ptr ds:[eax]
/*4ED47A*/ call Unpacked.0048413C
/*4ED47F*/ mov eax,dword ptr ss:[ebp-0x24]
/*4ED482*/ lea edx,dword ptr ss:[ebp-0x20]
/*4ED485*/ call Unpacked.00409504
/*4ED48A*/ lea eax,dword ptr ss:[ebp-0x20]
/*4ED48D*/ mov edx,Unpacked.004ED610 //licence.dat (OD显示的字符串,看到这个更可疑了)
看来这里是一个CALL啊,在CALL头下断后,重载程序并运行,断下。 F8走起
遇到了第一个CALL,F7进去发现一些获取模块句柄类的函数,估计是初始化一些东西,不管
来到第二个CALL,进去没发现什么。凭估计是一些字符串组合类的运算。。。
第三第四个CALL同样没发现什么,直到F8到以下代码。 /*4ED4AC*/ lea edx,dword ptr ss:[ebp-0x34] //密文1保存的地址
/*4ED4AF*/ mov eax,Unpacked.004ED624 //iloveyanyan 作者设置的字符串。
/*4ED4B4*/ call Unpacked.004A11C0 //获得密文1 数值固定
/*4ED4B9*/ lea eax,dword ptr ss:[ebp-0x34]
/*4ED4BC*/ lea edx,dword ptr ss:[ebp-0x10]
/*4ED4BF*/ call Unpacked.004A1234 //密文1转字符串
/*4ED4C4*/ mov eax,ebx
/*4ED4C6*/ call Unpacked.004ED250 //检索盘符信息
/*4ED4CB*/ xor edx,edx
/*4ED4CD*/ push edx
/*4ED4CE*/ push eax
/*4ED4CF*/ lea eax,dword ptr ss:[ebp-0x38]
/*4ED4D2*/ call Unpacked.00409058 //获得机器码 接下来的部分要认真了, 来看上面这段代码的第一个CALL作者先将一个固定的字符串地址给DAX,并将结果写入EDX。然后把EDX的值转换为字符串 如HEXTOSTR 至于EDX的结果是如何得的,先大致说一下。因为密文1是固定的,并且接下来的“密文2”会详细说。。。。。
为什么说密文1固定呢。作者先把字符串格式存入一个40H大小的数据块(在此称这块数据为X),在字符串后面跟一个80H。然后在数据块尾部前8字节添加字符串位数x8的数值。
然后定义一个10H大小的数据,这个数据是固定的(在此称这块数据为Y) 01 23 45 67 89 AB CD EF FE DC BA 89 76 54 32 10
这两个数据块又进入一个关键CALL,运算后的结果与Y数据块相加,便得到了密文1。。所以密文1是固定的 接下来获得机器码。在此不关心 获得密文1和机器码后:
/*4ED4D7*/ mov eax,dword ptr ss:[ebp-0x38] //机器码偏移进入EAX
/*4ED4DA*/ lea edx,dword ptr ss:[ebp-0x34] //密文1数值偏移存入EDX 这里只是保存地址,不参与运算
/*4ED4DD*/ call Unpacked.004A11C0 //获得密文2
/*4ED4E2*/ lea eax,dword ptr ss:[ebp-0x34]
/*4ED4E5*/ lea edx,dword ptr ss:[ebp-0x14]
/*4ED4E8*/ call Unpacked.004A1234 //密文2转字符串
F7进入获得密文2的CALL看到: /*4A11C0*/ push ebp
/*4A11C1*/ mov ebp,esp
/*4A11C3*/ add esp,-0x5C
/*4A11C6*/ push ebx
/*4A11C7*/ mov ebx,edx
/*4A11C9*/ mov dword ptr ss:[ebp-0x4],eax
/*4A11CC*/ mov eax,dword ptr ss:[ebp-0x4]
/*4A11CF*/ call Unpacked.004047DC
/*4A11D4*/ xor eax,eax
/*4A11D6*/ push ebp
/*4A11D7*/ push Unpacked.004A1226
/*4A11DC*/ push dword ptr fs:[eax]
/*4A11DF*/ mov dword ptr fs:[eax],esp
/*4A11E2*/ lea eax,dword ptr ss:[ebp-0x5C] //取Y的地址
/*4A11E5*/ call Unpacked.004A1098 //数据存入Y,固定
/*4A11EA*/ mov eax,dword ptr ss:[ebp-0x4] //EAX指向机器码
/*4A11ED*/ call Unpacked.004045EC //获得EAX指向字符串位数
/*4A11F2*/ push eax
/*4A11F3*/ mov eax,dword ptr ss:[ebp-0x4]
/*4A11F6*/ call Unpacked.004047EC //判断EAX是否是0
/*4A11FB*/ mov edx,eax
/*4A11FD*/ lea eax,dword ptr ss:[ebp-0x5C] //取Y的地址
/*4A1200*/ pop ecx
/*4A1201*/ call Unpacked.004A10CC //上面的位数乘8 并保存在某个地方,这里称它为J
/*4A1206*/ mov edx,ebx
/*4A1208*/ lea eax,dword ptr ss:[ebp-0x5C]
/*4A120B*/ call Unpacked.004A114C //计算过程
/*4A1210*/ xor eax,eax F7跟进计算过程,将J存入 X尾部前8字节,在X开始的字符串尾部添加 80H
然后F8到
/*4A1193*/ mov edx,esp
/*4A1195*/ mov eax,ebx
/*4A1197*/ mov ecx,0x8
/*4A119C*/ call Unpacked.004A10CC //Y变形 核心 在此称为核心CALL 终于到了核心了,先用超高级语言描述一下这里 Y中HEX每4个字节为一组。。 然后取其中一组i(先取第一组) 和 i+2 和 i+1 及两个立即数加X首地址4字节进入子CALL1号 改变组X的值
再取i=i-1 和 i+2和 i+1 及两个立即数加X偏移 + 4 x(重复次数) 的4字节进入子CALL1号 改变组X的值 (重复15次,)
后续进入子CALL2号及3号还有4号各重复不等次 变形后的各组数据加上原各组数据为密文2 这算法超长啊…………累死跟的人了,所以后来写注册机时就不仔细跟立即数的值和子CALL的功能了,直接把代码扣下贴到MASM里了。CALL的地址为004A10CC。。有兴趣可以去看看…… 终于到了真码计算了。同样进入上面获得密文2的CALL。只是参数和次数不一样罢了。
Y是固定的 01 23 45 67 89 AB CD EF FE DC BA 89 76 54 32 10
X为上面的 密文2转换为字符串的值+密文1转换为字符串的值。
进入核心CALL。 计算后 再次进入核心CALL
Y为上次核心CALL计算后的值
X为密文2跟一个80H 块尾(00 03 00 00 00 00 00 00 固定)
这次计算后结果就为真码了
然后在转成字符串就OK。。 最后感叹下追算法真费时间。。。
附件里包含注册机汇编源码 用7Z解压
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
上传的附件: