• 标 题:时间到了 v1.5 简单注册算法分析 + 注册机源代码(tc2) (9千字)
  • 作 者:炎之川
  • 时 间:2003-4-12 15:16:28
  • 链 接:http://bbs.pediy.com

时间到了 v1.5 简单注册算法分析 + 注册机源代码(tc2)

破解目标:时间到了 1.5
官方主页:无
软件简介:本软件可以安排X分钟后“显示一段信息”、“执行某个文件”、“锁定屏幕”、“关闭Windows”、“循环锁屏”其中一个且只有一个任务。但在非Win9x操作系统下取消了有关锁屏的功能(即是说在非Win9x系统下不能使用上述的全部功能).“循环锁屏(隔时锁屏)”只向注册用户开放,除此没有限制。注:在Windows 2000/xp/NT可以使用,但封印了部分功能。
下载地址:http://count.skycn.com/softdown.php?id=11656&url=http://on165-down.skycn.net/down/sjdl.rar

使用工具:FI 2.50、CASPr 1.10、W32Dasm、Ollydbg 1.09b 汉化版

作者:炎之川[BCG]
时间:2003.4.12
主页:http://skipli.yeah.net/

声明: 此文仅用于学习及交流,若要转载请保持文章完整。

这个软件是昨天在 fixdown 的国产软件破解更新里面看到的,只有一个注册码,所以就随便下载了一个,开始时发现其中用了一些浮点指令,本来有些怕,不过把注册流程跟了一遍才发现那是哄人的……

用 Fileinfo 2.50 征测,得知软件是用 ASPack 1.082 加的壳,真是很古老的版本啊~用 CASPr 轻松脱掉壳。

使用 W32Dasm 分析,可以找到注册成功、失败等提示信息,稍作分析后用 OD 装入程序,在 48CCF8 处下断点,然后 Ctrl+F2 重新载入程序,F9 运行,输入注册名及假注册码并点击“验证”:
Name: lovefire
Serial: 787878
注意注册名必须为8位,这是软件提示你的。

浮点指令的解释参考自看雪大哥的 Crack Tutorial 2001


0048CCF8  /. 55            PUSH EBP  //断在这里
0048CCF9  |. 8BEC          MOV EBP,ESP
0048CCFB  |. 33C9          XOR ECX,ECX
0048CCFD  |. 51            PUSH ECX
0048CCFE  |. 51            PUSH ECX
0048CCFF  |. 51            PUSH ECX
0048CD00  |. 51            PUSH ECX
0048CD01  |. 51            PUSH ECX
0048CD02  |. 51            PUSH ECX
0048CD03  |. 51            PUSH ECX
0048CD04  |. 51            PUSH ECX
0048CD05  |. 53            PUSH EBX
0048CD06  |. 56            PUSH ESI
0048CD07  |. 57            PUSH EDI
0048CD08  |. 8BF0          MOV ESI,EAX
0048CD0A  |. 33C0          XOR EAX,EAX
0048CD0C  |. 55            PUSH EBP
0048CD0D  |. 68 58CE4800    PUSH un.0048CE58
0048CD12  |. 64:FF30        PUSH DWORD PTR FS:[EAX]
0048CD15  |. 64:8920        MOV DWORD PTR FS:[EAX],ESP
0048CD18  |. 8D55 F4        LEA EDX,DWORD PTR SS:[EBP-C]
0048CD1B  |. 8B86 00040000  MOV EAX,DWORD PTR DS:[ESI+400]
0048CD21  |. E8 B205FAFF    CALL un.0042D2D8
0048CD26  |. 8B45 F4        MOV EAX,DWORD PTR SS:[EBP-C]  //用户名送eaxDWOR
0048CD29  |. E8 0670F7FF    CALL un.00403D34  //这个call取得用户名的长度
0048CD2E  |. 83F8 08        CMP EAX,8  //比较输入的用户名是否等于8?
0048CD31  |. 74 21          JE SHORT un.0048CD54  //等于则跳转到下面的注册码计算部分
0048CD33  |. 6A 40          PUSH 40
0048CD35  |. 68 68CE4800    PUSH un.0048CE68
0048CD3A  |. 68 70CE4800    PUSH un.0048CE70
0048CD3F  |. A1 E4384900    MOV EAX,DWORD PTR DS:[4938E4]
0048CD44  |. E8 C366FAFF    CALL un.0043340C
0048CD49  |. 50            PUSH EAX                                ; |hOwner
0048CD4A  |. E8 159DF7FF    CALL <JMP.&user32.MessageBoxA>          ; \MessageBoxA  //不等于8,则弹出提示“注册标识符长度不足!”
0048CD4F  |. E9 D9000000    JMP un.0048CE2D
0048CD54  |> 8D55 F0        LEA EDX,DWORD PTR SS:[EBP-10]
0048CD57  |. 8B86 00040000  MOV EAX,DWORD PTR DS:[ESI+400]
0048CD5D  |. E8 7605FAFF    CALL un.0042D2D8  //再次取用户名
0048CD62  |. 8B45 F0        MOV EAX,DWORD PTR SS:[EBP-10]  //用户名送eax
0048CD65  |. E8 CA6FF7FF    CALL un.00403D34  //用户名长度
0048CD6A  |. 8BD8          MOV EBX,EAX  //长度送ebx
0048CD6C  |. 85DB          TEST EBX,EBX  //比较ebx是否为0
0048CD6E  |. 7C 32          JL SHORT un.0048CDA2  //小于则跳过循环,直接失败(这里验证注册名是否有输入?)
0048CD70  |. 43            INC EBX  //ebx是用户名长度,ebx+1=9 作计数器
0048CD71  |. 33FF          XOR EDI,EDI  //edi清零

0048CD73  |> 8D55 EC        /LEA EDX,DWORD PTR SS:[EBP-14]
0048CD76  |. 8B86 00040000  |MOV EAX,DWORD PTR DS:[ESI+400]
0048CD7C  |. E8 5705FAFF    |CALL un.0042D2D8  //再次取用户名
0048CD81  |. 8B45 EC        |MOV EAX,DWORD PTR SS:[EBP-14  //用户名送eax
0048CD84  |. 0FB64438 FF    |MOVZX EAX,BYTE PTR DS:[EAX+EDI-1]  //逐位取用户名
//由于上面将ebx计数器+1,所以第一次循环时[EAX+EDI-1]的值为0,什么也取不到
0048CD89  |. 69C0 43020000  |IMUL EAX,EAX,243  /eax=eax*243,注意第一次循环时eax=0,第二次循环开始,eax为注册名的ASCII值
0048CD8F  |. 05 89000000    |ADD EAX,89  //eax=eax+89
0048CD94  |. 8945 E8        |MOV DWORD PTR SS:[EBP-18],EAX  //得出的eax值放入堆栈SS
0048CD97  |. DB45 E8        |FILD DWORD PTR SS:[EBP-18]  //浮点指令!装入整数到st(0)
0048CD9A  |. DD5D F8        |FSTP QWORD PTR SS:[EBP-8]  //dest <- st(0),即将目的操作数(dest)放入 [EBP-8]
0048CD9D  |. 9B            |WAIT
0048CD9E  |. 47            |INC EDI  //edi+1
0048CD9F  |. 4B            |DEC EBX  //ebx-1
0048CDA0  |.^75 D1          \JNZ SHORT un.0048CD73  //没有取完就跳回去继续

第一次循环,取得的eax值为0,所以 eax=eax*243+89=0*243+89=89,st(0)=137.00000000000000000
第二次循环,取得的eax值为6C(即“l”),所以 eax=eax*243+89=6C*243+89=F4CD,st(0)=62669.000000000000000
…………
第九次循环,取得的eax值为65(即“e”),所以 eax=eax*243+89=65*243+89=E4F8,st(0)=58616.00000000000000000

结果这个循环的真实作用就是:
(注册名最后一个字符ASCII值)*243+89
所以只有最后一次的计算有效,前面的计算均无实际用途。

0048CDA2  |> 8D55 E4        LEA EDX,DWORD PTR SS:[EBP-1C]
0048CDA5  |. 8B86 04040000  MOV EAX,DWORD PTR DS:[ESI+404]
0048CDAB  |. E8 2805FAFF    CALL un.0042D2D8  //取假码
0048CDB0  |. 8B45 E4        MOV EAX,DWORD PTR SS:[EBP-1C]  //假码放入eax
0048CDB3  |. 50            PUSH EAX  //假码入栈
0048CDB4  |. DD45 F8        FLD QWORD PTR SS:[EBP-8]  //又一个浮点指令,作用是装入实数到st(0),此时 [EBP-8] 中放的数据就是上面最后一次循环得出的值
0048CDB7  |. 83C4 F4        ADD ESP,-0C
0048CDBA  |. DB3C24        FSTP TBYTE PTR SS:[ESP]                  ; |  dest <- st(0),即将目的操作数(dest)放入 [ESP]
0048CDBD  |. 9B            WAIT                                    ; |
0048CDBE  |. 8D45 E0        LEA EAX,DWORD PTR SS:[EBP-20]            ; |
0048CDC1  |. E8 AEBEF7FF    CALL un.00408C74                        ; \  //得出实数部分,即真实注册码,放在[EBP-20]中
0048CDC6  |. 8B55 E0        MOV EDX,DWORD PTR SS:[EBP-20]  //真码送edx
0048CDC9  |. 58            POP EAX  //假码出栈
0048CDCA  |. E8 7570F7FF    CALL un.00403E44  //比较真假注册码
0048CDCF  |. 75 40          JNZ SHORT un.0048CE11  //不同则注册失败
0048CDD1  |. 6A 40          PUSH 40
0048CDD3  |. 68 88CE4800    PUSH un.0048CE88
0048CDD8  |. 68 94CE4800    PUSH un.0048CE94
0048CDDD  |. A1 E4384900    MOV EAX,DWORD PTR DS:[4938E4]
0048CDE2  |. E8 2566FAFF    CALL un.0043340C
0048CDE7  |. 50            PUSH EAX                                ; |hOwner
0048CDE8  |. E8 779CF7FF    CALL <JMP.&user32.MessageBoxA>          ; \MessageBoxA  //这里弹出注册失败的MessageBox

归根到底,虽然软件用了一些浮点指令,但根本没有用到小数部分的计算,全部都是实数部分的计算。

算法总结:
(注册名的最后一个字符的ASCII值)*243+89,结果转换为10进制就是注册码。

注册信息保存在系统目录下的 vsde.dll 文件中,这其实是一个ini文件,注册后内容如下:
[set]
vnt=1
left=320
top=171
finished=1
reg=1  //注册后增加此行

至此,时间到了 v1.5 注册算法分完成,由于是国产软件,所以不提供可用的注册码。

----------------------------------------------------------
注册机源代码(TC 2.0)

以下是注册机源代码,TC 中似乎不能进行浮点计算,但软件的算法部分的浮点指令并不是计算指令,只是数据传递和对常量的操作指令,且只用到了实数部分,并没有用小数,所以姑且按普通的整型写一下注册机,想来应该不会有什么大问题吧^_^

另外由于水平非常有限,写的代码可能比较一般……^_^


/* KeyGen by 炎之川[BCG],2003.4.12 */

/* KeyGen by 炎之川[BCG],2003.4.12,修正于 2003.4.13 */
/* 感谢 wscn 兄的指点 */

#include <stdio.h>
#include <string.h>
main()
{
        char name[80];
        int name_len,i;
        unsigned long int sn1;
        unsigned long int sn2=0;
        clrscr();
        printf("    _/_/_/      _/_/_/    _/_/_/\n  _/    _/  _/        _/\n  _/_/_/    _/        _/  _/_/\n _/    _/  _/        _/    _/\n_/_/_/      _/_/_/    _/_/_/\n\n -= shijiandaole 1.5 KeyGen by lovefire[BCG] =-\n\n\nPlease enter your name: ");
        gets(name);
        name_len=strlen(name);
        if (name_len>7 && name_len<9)
        {
                for (i=0;i<name_len;i++)
                {
                        sn2=name[i]*0x243+0x89;
                }
                printf("\nok, try this serial: %u\n",sn2);
                printf("\n\nNOTE: serial only for test!");
                printf("\nIf you like it, buy it to support the soft's author!");
        }
                else
                {
                        printf("\nReg Name MUST have 8 char. ;)\n");
                }
        printf("\n\nhave fun^^\nwelcome to http://skipli.yeah.net/");
        getch();
}


----------------------------------------------------------

炎之川
属于中国破解组织BCG(Beginner's Cracking Group)

    _/_/_/      _/_/_/    _/_/_/
  _/    _/  _/        _/
  _/_/_/    _/        _/  _/_/
_/    _/  _/        _/    _/
_/_/_/      _/_/_/    _/_/_/