最近一直与失败为伍
1.
解决UltraDict之后,想试试商业软件
正好有一款国内著名的ciba软件,虽然有Crack补丁,不过有bug
每次上网之后她就不能用了,要再打一次补丁才可以,估计她会自动连接网络验证激活码
把她更新的网络设置改成代理方式,设置一个不能连接网络的代理地址
想把她困死在代理里,结果还是失败,猜想她是正常连接失败才会通过代理连接,或者相反
好,捆不住你是吧,把你关起来看你还能咋办!
用系统自带的防火墙阻止她的网络连接
或者把她拉到其他防火墙的黑名单里,禁止她一切的网络通信
(这个方法还没有测试,估计100%可行)
回到ciba的分析上,开始对她束手无策
反汇编之后,查看串式参考没有找到任何有用的信息(当时只会这种方法)
之后又看别人Crack其他软件的文章,开始接触OD,学习动态调试(动态调试关键是找准断点)
学会通过函数参考找断点,终于找到ciba的入口了,虽然只是Crack的起点
分析代码,找到关键跳转,修改之后跳到保存注册信息的窗口
再下一步却返回到注册窗口,没有跳进主界面
反复分析代码(当时读懂的代码少之又少,边学边看)
反反复复修改,还是进不去主界面,暴力Crack暂时失败
之后采取跟踪程序,试着能否跟踪出激活码,这个过程非常累
程序在关键call里call了又call,往往跟踪一两个小时就眼花,不知东南西北
关键在于没有抓到最关键的代码,反反复复都是事倍功半,只好暂时放手
分析的过程中注意到一点:
注册ciba先是输入通行证的用户名和密码
再把用户名通过算法转成数字,而密码只是通过简单的移位
字母不变,数字虽然通过算法转变了,但是通过黑盒测试就能够找到转变的规律
用户名和密码变换之后连接成请求码,最后转成激活码
2.
之后转战Ashampoo的刻录软件(下载的网站提供了一个可用的SN)
试用期是10天,一直都没有想到要Crack她的时间限制,因为当时脑海根本没有这个概念
一开始还是老办法,反汇编,查看串式参考,发现不少有用的信息
爆破点很快就找到了,修改关键跳转,输入任意注册码都能成功跳进主界面!
不过马上发现问题,每次启动都要输入注册码,查看注册表,注册码的信息已经创建了
估计有一部分注册相关的代码没有正确执行
或者是软件在启动的时候存在一个判断注册码的机制(这条经过对比分析暂时排除)
当时分析代码还是很困难,暂时没有去管哪些代码没有执行了
紧接着转去跟踪注册码的生成过程,只能说她的过程比ciba稍微容易点
断断续续的跟踪N次,没有跟踪出完整的注册码
不过已经有了大概的了解,进一步分析需要读懂更多的代码
于是返回分析UltraDict的代码,逐渐学习汇编语言
3.
分析UltraDict的结果如下:
* Referenced by a (U)nconditional or (C)onditional Jump at Address: ;假设用户名的每个字符的十进制用X表示
|:00401CA8(C)
|
:00401C33 0FBE7C3420 movsx edi, byte ptr [esp+esi+20] ;根据用户名计算注册码算法开始,edi一直保存用户名的字符
:00401C38 8BC7 mov eax, edi
:00401C3A B90A000000 mov ecx, 0000000A ;0Ah=10
:00401C3F 99 cdq ;edx清零
:00401C40 F7F9 idiv ecx ;X/10,商没有进入下面的计算,edx保存余数,实际上是把X的个位数存入edx
:00401C42 8BCA mov ecx, edx ;X的个位数也存入ecx,这里为后面一个关系ecx的运算做准备
:00401C44 81E201000080 and edx, 80000001 ;edx是奇数则为1,偶数则为0
:00401C4A 7905 jns 00401C51 ;结果为正则跳,因为edx不可能为负,所以必跳
:00401C4C 4A dec edx ;如果edx为负,从这里开始的三行代码是为了防止溢出?
:00401C4D 83CAFE or edx, FFFFFFFE
:00401C50 42 inc edx
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401C4A(C)
|
:00401C51 7516 jne 00401C69 ;edx是奇数就跳,即X是奇数就跳
:00401C53 8BC7 mov eax, edi
:00401C55 B91A000000 mov ecx, 0000001A ;1Ah=26
:00401C5A 99 cdq ;edx清零
:00401C5B F7F9 idiv ecx ;X/26
:00401C5D 80C241 add dl, 41 ;41h=65,X/26的余数+65=注册码的十进制数
:00401C60 88943448010000 mov byte ptr [esp+esi+00000148], dl ;算出的注册码是大写字母,保存在这里
:00401C67 EB2E jmp 00401C97
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401C51(C)
|
:00401C69 8BC1 mov eax, ecx ;ecx保存着X的个位数
:00401C6B BB03000000 mov ebx, 00000003
:00401C70 99 cdq
:00401C71 F7FB idiv ebx ;X的个位数/3
:00401C73 85D2 test edx, edx ;判断是否整除,整除则edx=0
:00401C75 7516 jne 00401C8D ;不整除就跳
:00401C77 8BC7 mov eax, edi
:00401C79 B91A000000 mov ecx, 0000001A
:00401C7E 99 cdq ;edx清零
:00401C7F F7F9 idiv ecx
:00401C81 80C261 add dl, 61 ;61h=97,X/26的余数+97=注册码的十进制数
:00401C84 88943448010000 mov byte ptr [esp+esi+00000148], dl ;算出的注册码是小写字母,保存在这里
:00401C8B EB0A jmp 00401C97
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401C75(C)
|
:00401C8D 80C131 add cl, 31 ;31h=49,X的个位数+49=注册码的十进制数
;个位数最大是9,结果会出现58,不是数字?不会,前面个位数/3排除这个结果
:00401C90 888C3448010000 mov byte ptr [esp+esi+00000148], cl ;算出的注册码是数字,保存在这里
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00401C67(U), :00401C8B(U)
|
:00401C97 8D7C2420 lea edi, dword ptr [esp+20]
:00401C9B 83C9FF or ecx, FFFFFFFF
:00401C9E 33C0 xor eax, eax
:00401CA0 46 inc esi
:00401CA1 F2 repnz
:00401CA2 AE scasb
:00401CA3 F7D1 not ecx
:00401CA5 49 dec ecx
:00401CA6 3BF1 cmp esi, ecx ;esi的值是已经循环的次数,ecx的值是注册码字符串长度
:00401CA8 7289 jb 00401C33 ;算法末尾,不等就跳转,循环次数为注册码字符串长度
:00401CAA 33DB xor ebx, ebx
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401C31(C)
|
:00401CAC 55 push ebp
:00401CAD 8D8C24EC000000 lea ecx, dword ptr [esp+000000EC]
:00401CB4 889C344C010000 mov byte ptr [esp+esi+0000014C], bl
:00401CBB E8F0010000 call 00401EB0
:00401CC0 899C24B4010000 mov dword ptr [esp+000001B4], ebx
:00401CC7 8DB42484000000 lea esi, dword ptr [esp+00000084] ;信息窗口显示输入的注册码的ASCII码
:00401CCE 8D842448010000 lea eax, dword ptr [esp+00000148] ;如果断点设在这里,信息窗口直接显示正确的注册码的ASCII码
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401CF3(C)
|
:00401CD5 8A10 mov dl, byte ptr [eax] ;开始判断输入的注册码与算出来的注册码是否一致
:00401CD7 8ACA mov cl, dl
:00401CD9 3A16 cmp dl, byte ptr [esi]
:00401CDB 751C jne 00401CF9
:00401CDD 3ACB cmp cl, bl
:00401CDF 7414 je 00401CF5
:00401CE1 8A5001 mov dl, byte ptr [eax+01]
:00401CE4 8ACA mov cl, dl
:00401CE6 3A5601 cmp dl, byte ptr [esi+01]
:00401CE9 750E jne 00401CF9
:00401CEB 83C002 add eax, 00000002
:00401CEE 83C602 add esi, 00000002
:00401CF1 3ACB cmp cl, bl
:00401CF3 75E0 jne 00401CD5
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401CDF(C)
|
:00401CF5 33C0 xor eax, eax
:00401CF7 EB05 jmp 00401CFE
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00401CDB(C), :00401CE9(C)
|
:00401CF9 1BC0 sbb eax, eax
:00401CFB 83D8FF sbb eax, FFFFFFFF
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401CF7(U)
|
:00401CFE 3BC3 cmp eax, ebx
:00401D00 0F85DF000000 jne 00401DE5 ;判断之后的关键跳转
:00401D06 6801100000 push 00001001
注册码的算法很简单,里面一个call也没有
刚开始只是想简单地注释一些代码,没想到把算法弄出来了
算法总结如下:
X是偶数: X/26的余数+65=注册码的十进制数
X是奇数,且个位数能被3整除: X/26的余数+97=注册码的十进制数
X是奇数,且个位数不能被3整除: X的个位数+49=注册码的十进制数
C programming Language 是彻底生疏了,翻书+调试,搞半天才把注册机写出来,尽管糟糕,将就用吧,源码如下,错误请指出:
#include <stdio.h>
#include <string.h>
main()
{
char s[40];
int i=0;
int j=0;
printf("Please enter your name:");
gets(s);
i=strlen(s);
j=i;
for(i=0;i<j;i++)
{
if(s[i]%2==0)
s[i]=s[i]%26+65;
else
if(s[i]%10%3==0)
s[i]=s[i]%26+97;
else
s[i]=s[i]%10+49;
}
printf("Your SN is:\n");
for(i=0;i<j;i++)
{
printf("%c",s[i]);
}
printf("\n");
}
测试使用的用户名和注册码如下:
注册名:gardener 注册码:z8KW2G2K
回想第一次Crack就成功了,真是碰上超级好运气!
后面遇到的都是硬骨头啊!
- 标 题:【原创】UltraDict算法总结
- 作 者:karas
- 时 间:2009-06-17 23:48
- 链 接:http://bbs.pediy.com/showthread.php?t=91770