【文章标题】:键盘记录器 V7.0 注册算法分析和注册机编写
【文章作者】: drcool
【作者主页】: 无
【软件名称】: monitor.exe V7.0
【下载地址】: 自己搜索下载
【加壳方式】: UPX
【保护方式】: 注册码验证,矩阵加密
【编写语言】: VC
【使用工具】: OD
【操作平台】: WINXP
【软件介绍】: 键盘记录
【作者声明】: 本文仅供研究学习,本人对因这篇文章而导致的一切后果,不承担任何法律责任。本文中的不足之处请各位多多指教
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
--------------------------------------------------------------------------------
【详细过程】
这是一个键盘记录软件,未注册版本每一分钟会弹出一个注册提示框。PEID检查是UPX的壳,脱壳之后加载,发现与注册相关的代码如下:
00402E8B   FF50 18          CALL DWORD PTR DS:[EAX+18]
00402E8E   84C0             TEST AL,AL          //想爆破的朋友可以修改这里,但这次我们讲的如何做注册机呵呵
00402E90   6A 00            PUSH 0
00402E92   75 13            JNZ SHORT monitor.00402EA7
00402E94   68 98384300      PUSH monitor.00433898                              ; ASCII "Warning"
00402E99   68 84384300      PUSH monitor.00433884
00402E9E   8BCD             MOV ECX,EBP
00402EA0   E8 5EB30100      CALL monitor.0041E203
00402EA5   EB 3C            JMP SHORT monitor.00402EE3
00402EA7   68 78384300      PUSH monitor.00433878                              ; ASCII "Infomation"
00402EAC   68 6C384300      PUSH monitor.0043386C
00402EB1   8BCD             MOV ECX,EBP
00402EB3   E8 4BB30100      CALL monitor.0041E203
00402EB8   8B0F             MOV ECX,DWORD PTR DS:[EDI]
00402EBA   68 5C384300      PUSH monitor.0043385C                              ; ASCII "keyboardlog.ini"
00402EBF   57               PUSH EDI
00402EC0   FF51 10          CALL DWORD PTR DS:[ECX+10]
00402EC3   8B4424 10        MOV EAX,DWORD PTR SS:[ESP+10]
00402EC7   8B17             MOV EDX,DWORD PTR DS:[EDI]
00402EC9   50               PUSH EAX
00402ECA   68 50384300      PUSH monitor.00433850                              ; ASCII "UserName"
00402ECF   57               PUSH EDI
00402ED0   FF52 1C          CALL DWORD PTR DS:[EDX+1C]
00402ED3   8B5424 0C        MOV EDX,DWORD PTR SS:[ESP+C]
00402ED7   8B0F             MOV ECX,DWORD PTR DS:[EDI]
00402ED9   52               PUSH EDX
00402EDA   68 44384300      PUSH monitor.00433844                              ; ASCII "UserCode"
00402EDF   57               PUSH EDI
00402EE0   FF51 1C          CALL DWORD PTR DS:[ECX+1C]
00402EE3   8B07             MOV EAX,DWORD PTR DS:[EDI]
00402EE5   57               PUSH EDI
00402EE6   FF50 04          CALL DWORD PTR DS:[EAX+4]
00402EE9   8D4C24 0C        LEA ECX,DWORD PTR SS:[ESP+C]
00402EED   C64424 1C 00     MOV BYTE PTR SS:[ESP+1C],0
00402EF2   E8 80CE0100      CALL monitor.0041FD77
00402EF7   8D4C24 10        LEA ECX,DWORD PTR SS:[ESP+10]
00402EFB   C74424 1C FFFFFF>MOV DWORD PTR SS:[ESP+1C],-1
00402F03   E8 6FCE0100      CALL monitor.0041FD77
00402F08   8BCD             MOV ECX,EBP
00402F0A   E8 5F970100      CALL monitor.0041C66E
00402F0F   8B4C24 14        MOV ECX,DWORD PTR SS:[ESP+14]
00402F13   5F               POP EDI
00402F14   5E               POP ESI
00402F15   5D               POP EBP
00402F16   64:890D 00000000 MOV DWORD PTR FS:[0],ECX
00402F1D   83C4 14          ADD ESP,14
00402F20   C3               RETN

这里就是上面那个CALL DWORD PTR DS:[EAX+18]:
00403E70   83EC 0C          SUB ESP,0C
00403E73   53               PUSH EBX
00403E74   8B5C24 14        MOV EBX,DWORD PTR SS:[ESP+14]
00403E78   55               PUSH EBP
00403E79   8BE9             MOV EBP,ECX
00403E7B   56               PUSH ESI
00403E7C   57               PUSH EDI
00403E7D   8B45 10          MOV EAX,DWORD PTR SS:[EBP+10]
00403E80   85C0             TEST EAX,EAX
00403E82   74 19            JE SHORT monitor.00403E9D
00403E84   8B08             MOV ECX,DWORD PTR DS:[EAX]
00403E86   85C9             TEST ECX,ECX
00403E88   74 13            JE SHORT monitor.00403E9D
00403E8A   3B0B             CMP ECX,DWORD PTR DS:[EBX]
00403E8C   75 0A            JNZ SHORT monitor.00403E98
00403E8E   8B48 04          MOV ECX,DWORD PTR DS:[EAX+4]
00403E91   8B53 04          MOV EDX,DWORD PTR DS:[EBX+4]
00403E94   3BCA             CMP ECX,EDX
00403E96   74 2B            JE SHORT monitor.00403EC3
00403E98   83C0 08          ADD EAX,8
00403E9B  ^75 E7            JNZ SHORT monitor.00403E84
00403E9D   66:8B03          MOV AX,WORD PTR DS:[EBX]
00403EA0   8B55 00          MOV EDX,DWORD PTR SS:[EBP]
00403EA3   8D4C24 10        LEA ECX,DWORD PTR SS:[ESP+10]
00403EA7   50               PUSH EAX
00403EA8   51               PUSH ECX
00403EA9   68 58844300      PUSH monitor.00438458                              ; ASCII "drcool" //注册名
00403EAE   55               PUSH EBP
00403EAF   FF52 18          CALL DWORD PTR DS:[EDX+18]           //这是第一关
00403EB2   B9 03000000      MOV ECX,3
00403EB7   8BFB             MOV EDI,EBX
00403EB9   8D7424 10        LEA ESI,DWORD PTR SS:[ESP+10]
00403EBD   33D2             XOR EDX,EDX
00403EBF   F3:A7            REPE CMPS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
00403EC1   74 0C            JE SHORT monitor.00403ECF         //这里必须相等才行
00403EC3   5F               POP EDI
00403EC4   5E               POP ESI
00403EC5   5D               POP EBP
00403EC6   32C0             XOR AL,AL
00403EC8   5B               POP EBX
00403EC9   83C4 0C          ADD ESP,0C
00403ECC   C2 0400          RETN 4
00403ECF   8B45 00          MOV EAX,DWORD PTR SS:[EBP]
00403ED2   53               PUSH EBX
00403ED3   55               PUSH EBP
00403ED4   FF50 1C          CALL DWORD PTR DS:[EAX+1C]     //这是第二关
00403ED7   53               PUSH EBX
00403ED8   8BCD             MOV ECX,EBP
00403EDA   E8 21000000      CALL monitor.00403F00
00403EDF   B9 03000000      MOV ECX,3
00403EE4   8D7B 0C          LEA EDI,DWORD PTR DS:[EBX+C]
00403EE7   8BF3             MOV ESI,EBX
00403EE9   33D2             XOR EDX,EDX
00403EEB   66:F3:A7         REPE CMPS WORD PTR ES:[EDI],WORD PTR DS:[ESI]  必须相等
00403EEE   5F               POP EDI
00403EEF   5E               POP ESI
00403EF0   5D               POP EBP
00403EF1   5B               POP EBX
00403EF2   0F94C0           SETE AL
00403EF5   83C4 0C          ADD ESP,0C
00403EF8   C2 0400          RETN 4

第一关的代码:
00403C40   83EC 20          SUB ESP,20
00403C43   8B4C24 2C        MOV ECX,DWORD PTR SS:[ESP+2C]
00403C47   33C0             XOR EAX,EAX
00403C49   57               PUSH EDI
00403C4A   8B7C24 2C        MOV EDI,DWORD PTR SS:[ESP+2C]
00403C4E   8901             MOV DWORD PTR DS:[ECX],EAX
00403C50   8941 04          MOV DWORD PTR DS:[ECX+4],EAX
00403C53   8941 08          MOV DWORD PTR DS:[ECX+8],EAX
00403C56   83C9 FF          OR ECX,FFFFFFFF
00403C59   F2:AE            REPNE SCAS BYTE PTR ES:[EDI]
00403C5B   F7D1             NOT ECX
00403C5D   49               DEC ECX
00403C5E   894C24 08        MOV DWORD PTR SS:[ESP+8],ECX
00403C62   0F84 8D000000    JE monitor.00403CF5
00403C68   53               PUSH EBX
00403C69   55               PUSH EBP
00403C6A   56               PUSH ESI
00403C6B   B9 06000000      MOV ECX,6
00403C70   BE 1C394300      MOV ESI,monitor.0043391C                           ; ASCII "Mythusoft_Computing_Inc"
00403C75   8D7C24 18        LEA EDI,DWORD PTR SS:[ESP+18]
00403C79   F3:A5            REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
00403C7B   8D7C24 18        LEA EDI,DWORD PTR SS:[ESP+18]
00403C7F   83C9 FF          OR ECX,FFFFFFFF
00403C82   F2:AE            REPNE SCAS BYTE PTR ES:[EDI]
00403C84   F7D1             NOT ECX
00403C86   49               DEC ECX
00403C87   33FF             XOR EDI,EDI
00403C89   8BE9             MOV EBP,ECX
00403C8B   66:8B4C24 40     MOV CX,WORD PTR SS:[ESP+40]
00403C90   33F6             XOR ESI,ESI
00403C92   33D2             XOR EDX,EDX
00403C94   66:C1E9 08       SHR CX,8
00403C98   C74424 10 FF0000>MOV DWORD PTR SS:[ESP+10],0FF
00403CA0   8B4424 38        MOV EAX,DWORD PTR SS:[ESP+38]
00403CA4   47               INC EDI
00403CA5   8A5C07 FF        MOV BL,BYTE PTR DS:[EDI+EAX-1]
00403CA9   8B4424 14        MOV EAX,DWORD PTR SS:[ESP+14]
00403CAD   3BF8             CMP EDI,EAX
00403CAF   7C 02            JL SHORT monitor.00403CB3
00403CB1   33FF             XOR EDI,EDI
00403CB3   8A4424 40        MOV AL,BYTE PTR SS:[ESP+40]
00403CB7   32C3             XOR AL,BL
00403CB9   8A5C34 18        MOV BL,BYTE PTR SS:[ESP+ESI+18]
00403CBD   04 23            ADD AL,23
00403CBF   32C3             XOR AL,BL
00403CC1   46               INC ESI
00403CC2   3BF5             CMP ESI,EBP
00403CC4   7C 02            JL SHORT monitor.00403CC8
00403CC6   33F6             XOR ESI,ESI
00403CC8   8AD9             MOV BL,CL
00403CCA   02D8             ADD BL,AL
00403CCC   8B4424 3C        MOV EAX,DWORD PTR SS:[ESP+3C]
00403CD0   301C02           XOR BYTE PTR DS:[EDX+EAX],BL
00403CD3   42               INC EDX
00403CD4   83FA 0C          CMP EDX,0C
00403CD7   7C 02            JL SHORT monitor.00403CDB
00403CD9   33D2             XOR EDX,EDX
00403CDB   8B4424 10        MOV EAX,DWORD PTR SS:[ESP+10]
00403CDF   48               DEC EAX
00403CE0   894424 10        MOV DWORD PTR SS:[ESP+10],EAX
00403CE4  ^75 BA            JNZ SHORT monitor.00403CA0
00403CE6   8B5424 3C        MOV EDX,DWORD PTR SS:[ESP+3C]
00403CEA   66:8B4C24 40     MOV CX,WORD PTR SS:[ESP+40]
00403CEF   5E               POP ESI
00403CF0   5D               POP EBP
00403CF1   66:890A          MOV WORD PTR DS:[EDX],CX
00403CF4   5B               POP EBX
00403CF5   5F               POP EDI
00403CF6   83C4 20          ADD ESP,20
00403CF9   C2 1000          RETN 10
第一关的代码比较简单,我们用C语言来描述这个过程:
//key 的1,2字节是可以自己选定的,后面的10字节将由下面的程序产生
//name[]是注册名,data1="Mythusoft_Computing_Inc";共23字节
void test(unsigned char *key)
{
  int i,j=0,k=0,t=0;
  
  for(i=0;i<255;i++)
  {
      out[t]^=(((key[0]^name[j])+0x23)^data1[k])+key[1];
    t=(t+1)%12;
    j=(j+1)%NAME_LEN;
    k=(k+1)%23;
  }
   out[0]=key[0];
   out[1]=key[1];

}
比如我们取key[0]=0x12,key[1]=0x34,则最后产生的12字节就是12343fda2f2e0700feceea3a,这12字节就是注册码的前12字节,下面还有后12字节要计算。

第二关的代码:
00404240   83EC 10          SUB ESP,10
00404243   56               PUSH ESI
00404244   E8 E7F8FFFF      CALL monitor.00403B30
00404249   8BF0             MOV ESI,EAX
0040424B   85F6             TEST ESI,ESI
0040424D   74 6A            JE SHORT monitor.004042B9
0040424F   8B06             MOV EAX,DWORD PTR DS:[ESI]
00404251   8D4C24 04        LEA ECX,DWORD PTR SS:[ESP+4]
00404255   57               PUSH EDI
00404256   51               PUSH ECX
00404257   56               PUSH ESI
00404258   FF50 10          CALL DWORD PTR DS:[EAX+10]
0040425B   8B16             MOV EDX,DWORD PTR DS:[ESI]
0040425D   8D4424 08        LEA EAX,DWORD PTR SS:[ESP+8]
00404261   8B7C24 20        MOV EDI,DWORD PTR SS:[ESP+20]
00404265   50               PUSH EAX
00404266   57               PUSH EDI
00404267   56               PUSH ESI
00404268   FF52 14          CALL DWORD PTR DS:[EDX+14]
0040426B   8B0E             MOV ECX,DWORD PTR DS:[ESI]
0040426D   8D5424 08        LEA EDX,DWORD PTR SS:[ESP+8]
00404271   8D47 04          LEA EAX,DWORD PTR DS:[EDI+4]
00404274   52               PUSH EDX
00404275   50               PUSH EAX
00404276   56               PUSH ESI
00404277   FF51 14          CALL DWORD PTR DS:[ECX+14]
0040427A   8B0E             MOV ECX,DWORD PTR DS:[ESI]
0040427C   8D5424 08        LEA EDX,DWORD PTR SS:[ESP+8]
00404280   8D47 08          LEA EAX,DWORD PTR DS:[EDI+8]
00404283   52               PUSH EDX
00404284   50               PUSH EAX
00404285   56               PUSH ESI
00404286   FF51 14          CALL DWORD PTR DS:[ECX+14]
00404289   8B0E             MOV ECX,DWORD PTR DS:[ESI]
0040428B   56               PUSH ESI
0040428C   FF51 04          CALL DWORD PTR DS:[ECX+4]
//上面这一连串调用看起来很复杂,跟进去看,貌似MD5运算,其实我告诉你,这是障眼法,都是唬人的。
//上面所做的一切运算都与注册无关,目的就是要把分析者搞晕。
//下面才是真正的开始。
0040428F   68 383A4300      PUSH monitor.00433A38
00404294   8D57 0C          LEA EDX,DWORD PTR DS:[EDI+C]
00404297   68 38394300      PUSH monitor.00433938
0040429C   52               PUSH EDX
0040429D   E8 BEFEFFFF      CALL monitor.00404160
004042A2   68 383C4300      PUSH monitor.00433C38
004042A7   83C7 10          ADD EDI,10
004042AA   68 383B4300      PUSH monitor.00433B38
004042AF   57               PUSH EDI
004042B0   E8 ABFEFFFF      CALL monitor.00404160
004042B5   83C4 18          ADD ESP,18
004042B8   5F               POP EDI
004042B9   5E               POP ESI
004042BA   83C4 10          ADD ESP,10
004042BD   C2 0800          RETN 8
下面的代码是上面代码会用到的,是不是很眼熟?但是我告诉你,这是唬人的,呵呵。
004042C0   8B4424 08        MOV EAX,DWORD PTR SS:[ESP+8]
004042C4   C700 01234567    MOV DWORD PTR DS:[EAX],67452301
004042CA   C740 04 89ABCDEF MOV DWORD PTR DS:[EAX+4],EFCDAB89
004042D1   C740 08 FEDCBA98 MOV DWORD PTR DS:[EAX+8],98BADCFE
004042D8   C740 0C 76543210 MOV DWORD PTR DS:[EAX+C],10325476
004042DF   C2 0800          RETN 8

从上面的代码可以看出,CALL monitor.00404160很关键,我们跟进去看看:
00404160   83EC 08          SUB ESP,8
00404163   53               PUSH EBX
00404164   55               PUSH EBP
00404165   8B6C24 18        MOV EBP,DWORD PTR SS:[ESP+18]
00404169   56               PUSH ESI
0040416A   8B7424 18        MOV ESI,DWORD PTR SS:[ESP+18]
0040416E   33C0             XOR EAX,EAX
00404170   57               PUSH EDI
00404171   894424 1C        MOV DWORD PTR SS:[ESP+1C],EAX
00404175   894424 10        MOV DWORD PTR SS:[ESP+10],EAX
00404179   C74424 14 200000>MOV DWORD PTR SS:[ESP+14],20
00404181   8B3E             MOV EDI,DWORD PTR DS:[ESI]
00404183   8B45 00          MOV EAX,DWORD PTR SS:[EBP]
00404186   8B4C24 24        MOV ECX,DWORD PTR SS:[ESP+24]
0040418A   23F8             AND EDI,EAX
0040418C   8B46 04          MOV EAX,DWORD PTR DS:[ESI+4]
0040418F   2301             AND EAX,DWORD PTR DS:[ECX]
00404191   50               PUSH EAX
00404192   E8 A9FFFFFF      CALL monitor.00404140
00404197   57               PUSH EDI
00404198   8AD8             MOV BL,AL
0040419A   E8 A1FFFFFF      CALL monitor.00404140
0040419F   8B5424 24        MOV EDX,DWORD PTR SS:[ESP+24]
004041A3   8B4C24 2C        MOV ECX,DWORD PTR SS:[ESP+2C]
004041A7   33D8             XOR EBX,EAX
004041A9   83C4 08          ADD ESP,8
004041AC   83E3 01          AND EBX,1
004041AF   8D0412           LEA EAX,DWORD PTR DS:[EDX+EDX]
004041B2   33D8             XOR EBX,EAX
004041B4   8B4424 14        MOV EAX,DWORD PTR SS:[ESP+14]
004041B8   83C5 04          ADD EBP,4
004041BB   83C1 04          ADD ECX,4
004041BE   48               DEC EAX
004041BF   895C24 1C        MOV DWORD PTR SS:[ESP+1C],EBX
004041C3   894C24 24        MOV DWORD PTR SS:[ESP+24],ECX
004041C7   894424 14        MOV DWORD PTR SS:[ESP+14],EAX
004041CB  ^75 B4            JNZ SHORT monitor.00404181
004041CD   C74424 20 200000>MOV DWORD PTR SS:[ESP+20],20
004041D5   8B3E             MOV EDI,DWORD PTR DS:[ESI]
004041D7   8B45 00          MOV EAX,DWORD PTR SS:[EBP]
004041DA   8B4C24 24        MOV ECX,DWORD PTR SS:[ESP+24]
004041DE   23F8             AND EDI,EAX
004041E0   8B46 04          MOV EAX,DWORD PTR DS:[ESI+4]
004041E3   2301             AND EAX,DWORD PTR DS:[ECX]
004041E5   50               PUSH EAX
004041E6   E8 55FFFFFF      CALL monitor.00404140
004041EB   57               PUSH EDI
004041EC   8AD8             MOV BL,AL
004041EE   E8 4DFFFFFF      CALL monitor.00404140
004041F3   8B5424 18        MOV EDX,DWORD PTR SS:[ESP+18]
004041F7   8B4C24 2C        MOV ECX,DWORD PTR SS:[ESP+2C]
004041FB   33D8             XOR EBX,EAX
004041FD   83C4 08          ADD ESP,8
00404200   83E3 01          AND EBX,1
00404203   8D0412           LEA EAX,DWORD PTR DS:[EDX+EDX]
00404206   33D8             XOR EBX,EAX
00404208   8B4424 20        MOV EAX,DWORD PTR SS:[ESP+20]
0040420C   83C5 04          ADD EBP,4
0040420F   83C1 04          ADD ECX,4
00404212   48               DEC EAX
00404213   895C24 10        MOV DWORD PTR SS:[ESP+10],EBX
00404217   894C24 24        MOV DWORD PTR SS:[ESP+24],ECX
0040421B   894424 20        MOV DWORD PTR SS:[ESP+20],EAX
0040421F  ^75 B4            JNZ SHORT monitor.004041D5
00404221   8B4C24 1C        MOV ECX,DWORD PTR SS:[ESP+1C]
00404225   8BD3             MOV EDX,EBX
00404227   890E             MOV DWORD PTR DS:[ESI],ECX
00404229   8956 04          MOV DWORD PTR DS:[ESI+4],EDX
0040422C   5F               POP EDI
0040422D   5E               POP ESI
0040422E   5D               POP EBP
0040422F   5B               POP EBX
00404230   83C4 08          ADD ESP,8
00404233   C3               RETN

其中CALL monitor.00404140的代码的C语言描述如下:
 ecx是入口参数
 while(ecx)
    {
      edx=ecx-1; al++;
      ecx&=edx;
    }
返回值是al.我们把这个函数记为FF。
理解这个函数的作用是很重要的哦!
好了,我们来具体看看00404160 在干什么:
从代码来分析我们可以看出,本质上是两个循环,每个循环所做的工作在逻辑上是一样的,每个循环都是迭代32次,
每迭代一次得到1bit,依次由高到低存放在一个临时变量里。那么当函数返回时,就得到两个新的32比特数据。那么在
每轮迭代里又做了什么呢?
设我们的注册码是:unsigned long Key[6];在上面我们已经得到了Key[0],Key[1],Key[2]. 下面就是对剩下的3个DWORD进行检测了。
第一次调用00404160时:
通过两个表,unsigned long Table_1[64],Table_2[64].
unsigned long tmp=0,tmp1=0; //设这是我们用来缓存结果的
for(i=0;i<32;i++)
{
  a0=FF(Key[3]&Table_1[i]);   //FF函数就是上面的monitor.00404140
  a1=FF(Key[4]&Table_2[i]);
  tmp=(tmp<<1)|((a0^al)&1 );
}
for(i=32;i<64;i++)
{
  a0=FF(Key[3]&Table_1[i]);   //FF函数就是上面的monitor.00404140
  a1=FF(Key[4]&Table_2[i]);
  tmp1=(tmp1<<1)|((a0^al)&1 );
}
大家可以自己跟踪一下,看是不是这样的。好了,当循环结束时:Key[3]=tmp, Key[4]=tmp1;

当第二次调用00404160时:
表被替换成了两个新的表,同时进行运算的变成了Key[4]和Key[5],运算完成后Key[4]和Key[5]也分别被计算结果所替换。
下面就是验证了:
我们以字节来表示我们的注册码:unsigned char *code=Key;则
unsigned char add_table[12]={0x41,0x5e,0x88,0x34,0xca,0xe9,0xd2,0x03, 0xca,0x80,0x89,0x3e};
for(i=12;i<24;i++)
if(code[i-12]!=code[i]+add_table[i-12]) 则否决注册码。
如果12字节全部通过,则接收注册码。
也就是说,以12343fda2f2e0700feceea3a为例,我们调用两次00404160后出来的结果必须是:0xd1,0xd6,0xb7,0xa6,0x65,0x45,0x35,0xfd,0x34,0x4e,0x61,0xfc
好了,问题的关键就是上面两个循环迭代到底在干什么!这要我们首先要搞清楚函数FF在做什么。
那么我来告诉你,它完成的工作实际是:计数输入参数的二进制展开中1的个数!只要搞清楚了这一点,整个问题都解决了。
(a0^al)&1,实际上是(Key[3]&Table_1[i]的1的个数的奇偶性) ^( Key[4]&Table_2[i]的1的个数的奇偶性)。
更进一步,Key[3]&Table_1[i]的1的个数的奇偶性可以用一个什么数学关系来描述呢?
我们注意到Key[3]和Table_1[i]都是32比特的数,那么把它们都看作32比特长的01向量,则
Key[3]&Table_1[i]的1的个数的奇偶性=Key[3]点积 Table_1[i],也就是向量的点积。
注意到Key[3]和Table_1的32个数都进行了点积,Key[4]和Table_2和32个数进行了点积,它们点积的结果进行了异或。
那么我们把Table_1的32个32比特数全部看成01向量,则它们组成了一个32×32的矩阵设为TA1,同样对Table_2我们也又TA2;
则整个循环过程我们可以用如下数学式子来表示:
TA1×Key[3]+ TA2×Key[4]=tmp;       (1)   
这里的Key[3]和Key[4]都看成32比特长的列向量,+是指向量的异或,也就是二元域上的向量加法。
同样对下面一个循环我们也可以有:
TA3×Key[3]+ TA4×Key[4]=tmp1;      (2)
然后再下一轮调用中我们有:
TA5×tmp1+ TA6×Key[5]=tmp2;       (3)   
以及:
TA7×tmp1+ TA8×Key[5]=tmp3;       (4)
最终的结果就是tmp, tmp2, tmp3,这12字节。   
现在摆在我们面前的问题是:我们已经知道了tmp, tmp2, tmp3,要求Key[3],Key[4],Key[5].
那么思路很简单,首先联立(3),(4),把tmp1和Key[5]解出来,这是一个简单的线性方程组,只不过所有的运算都在二元域上完成,我们
所需要做的就是利用矩阵的运算来解整个方程。然后再联立(1),(2)把Key[3],Key[4]解出来。
这里需要注意的是:
我们必须要把Table_1等相关运算数转换成矩阵,把32比特数转换成向量,为了求解方程,我们还要能够求二元域上矩阵的逆,其实
这都很简单,和普通的矩阵求逆还要容易,因为只有0,1两种元素,消元很简单,但要注意的是,方程中的矩阵并都是可逆的,我们要
选择那些可逆的矩阵入手来开始消元。
同时还要注意,运算的方式,我们注意到运算结果比特是依次从高位到低位进行存放的,我们在运算中要注意这一点,为了方便,最好转换
成矩阵时,就按照整个方式来转换,即最高比特放在数组的第0个单元,这样计算时,最高位就自动放在了对应的位置上。不过,只要搞清楚了
运算方式,怎么做都是一样的。
好了,为了大家学习方便我把几个数组给大家:
unsigned long Table_1[64]={
0x0BCFEF35,    0x179FDE6B,    0xC5E7E798,    0x5E7F79AC,
0xBCFEF359,    0xF9FDC6B7,    0x73FBAD6A,    0x2F3FBCD6,
0xE7F75AD5,    0x4FEE95AF,    0x9FDD2B5E,    0xFF74CD76,
0xBFBA76B9,    0x7EE9BAE8,    0xFDD375D1,    0xF74D974E,
0x7BA6CBA7,    0x6E9B0E99,    0xDD361D32,    0x3A6C1A60,
0x74D834C0,    0xE9B06981,    0x5360F306,    0xA6C1E60C,
0xCD83EC1D,    0x1B07F83F,    0x360FF07E,    0x6C1FE0FD,
0xD83FC1FA,    0x307FA3F0,    0x60FF47E1,    0xC1FE8FC2,
0x03FD3F80,    0x0FF4FE02,    0x07FA7F01,    0x1FE9FC04,
0x3FD3F808,    0x7FA7F010,    0x7E9FE047,    0xFD3FC08E,
0xFF4FE021,    0xF4FF4232,    0x7A7FA119,    0xD3FD48C3,
0x27FAB183,    0x4FF56306,    0x9FEAC60D,    0x69FEA461,
0xBFD5AC1E,    0xFFAB7839,    0x7F56D076,    0xFEADA0ED,
0x7D5B61DE,    0xFAB6C3BC,    0x756DA77D,    0xEADB4EFA,
0x2DB58F80,    0x5B6B1F00,    0xB6D63E01,    0x55B6BDF1,
0xAB6D7BE3,    0xD6DAD7C2,    0x5B589808,    0xEDAC5C06,
};
unsigned long Table_2[64]={
0x9B4D1349,    0x369A2692,    0xCDA689A4,    0xDA689A48,
0xB4D13490,    0x69A26921,    0xD344D243,    0x6D344D24,
0xA689A486,    0x4D13490D,    0x9A26921A,    0x689A486B,
0x344D2435,    0xD13490D7,    0xA26921AE,    0x89A486BA,
0x44D2435D,    0x13490D75,    0x26921AEA,    0x4D2435D5,
0x9A486BAA,    0x3490D754,    0x6921AEA9,    0xD2435D52,
0xA486BAA5,    0x490D754B,    0x921AEA96,    0x2435D52C,
0x486BAA58,    0x90D754B1,    0x21AEA962,    0x435D52C4,
0x86BAA589,    0x1AEA9624,    0x0D754B12,    0x35D52C48,
0x6BAA5890,    0xD754B120,    0x5D52C481,    0xBAA58902,
0xAEA96240,    0xEA96240A,    0x754B1205,    0xAA58902A,
0x54B12055,    0xA96240AA,    0x52C48154,    0xD52C4815,
0xA58902A9,    0x4B120553,    0x96240AA7,    0x2C48154E,
0x58902A9D,    0xB120553A,    0x6240AA75,    0xC48154EA,
0x48154EAB,    0x902A9D56,    0x20553AAC,    0x8902A9D5,
0x120553AA,    0x240AA755,    0x8154EAB3,    0x40AA7559
};

unsigned long Table_3[64]={
0xAE10E7F5,    0x7087FFB6,    0xE10FFF6D,    0x421FDEDF,
0x843FBDBF,    0xDC21EFEF,    0x3843FFDB,    0x887F5B7B,
0x90FE96F3,    0x07F45782,    0x0FE8AF04,    0xA1FD0DE3,
0xC3FA3BC3,    0xFE8AF04F,    0x7D15C09B,    0x7F457827,
0x1FD15E09,    0x3FA2BC13,    0xFA2B8136,    0x74572268,
0x15CA5A45,    0xC5728693,    0x515CA9A5,    0xA2B9534B,
0x0AE52D22,    0xE8AE44D0,    0xDCA5845F,    0x394B28BB,
0x72965177,    0x2B94B48B,    0x57296916,    0xAE52D22D,
0xE52CA2EF,    0x4A5965DB,    0x94B2CBB7,    0xA965B76A,
0x2596BDA5,    0x4B2D7B4A,    0x965AF695,    0xACB5CD2F,
0xD96BBA5B,    0x32D754B3,    0xD2CB4ED0,    0x65AEA967,
0xCB5D52CE,    0x2D750B30,    0x16BA8598,    0x5AEA1660,
0xB5D42CC0,    0x5750D30E,    0xAEA1A61D,    0xDD436C3E,
0x3A86F879,    0x750DF0F2,    0xEA1BE1E5,    0x5437E3CF,
0xEBA87985,    0x21BF7E74,    0x437EFCE8,    0xA86FC79E,
0xD0DFAF38,    0x86FDF9D1,    0x8DFBD3A7,    0x9BF7874A,
};

unsigned long Table_4[64]={
0xDFCF8EDF,    0xFE7C76FE,    0xFCF8EDFC,    0xF9F1DBF9,
0xF3E3B7F2,    0xBF9F1DBF,    0x7F3E3B7F,    0xE7C76FE5,
0xCF8EDFCB,    0x7C76FE5F,    0xF8EDFCBE,    0x9F1DBF97,
0x3E3B7F2F,    0x8EDFCBE0,    0x1DBF97C1,    0xC76FE5F0,
0xF1DBF97C,    0xE3B7F2F8,    0x3B7F2F82,    0x76FE5F05,
0xBF97C156,    0x6FE5F055,    0xDBF97C15,    0xB7F2F82A,
0xDFCBE0AB,    0xEDFCBE0A,    0xF97C1561,    0xF2F82AC3,
0xE5F05586,    0x7F2F82AC,    0xFE5F0558,    0xFCBE0AB0,
0xCBE0AB0C,    0x97C15619,    0x2F82AC32,    0x5F055865,
0x7C156197,    0xF82AC32E,    0xF055865C,    0xE0AB0CB9,
0xC1561973,    0x82AC32E7,    0xBE0AB0CB,    0x055865CE,
0x0AB0CB9C,    0x2AC32E72,    0x15619739,    0x55865CE4,
0xAB0CB9C8,    0xAC32E723,    0x5865CE46,    0xB0CB9C8D,
0x6197391B,    0xC32E7236,    0x865CE46C,    0x0CB9C8D9,
0x56197391,    0x65CE46CB,    0xCB9C8D96,    0x197391B2,
0x32E72365,    0x97391B2C,    0x2E723659,    0x5CE46CB3,
};
每个数组转换成两个矩阵,分别应用在两个不同的循环迭代中。这些数据,都可以从程序中找出来的。
请大家自己熟悉编写如下几个函数:矩阵转换,向量转换,矩阵求逆,矩阵(向量)乘法.
有了上面几个函数的支撑之后,编写出注册机轻而易举!其实上面的函数实现起来也很简单。
好了,全部讲完了,由于论坛不准发注册机,我就不贴代码了,但是为了大家学习练习方便,我这里给出一组正确的注册对:
注册名:drcool
注册码:12343fda2f2e0700feceea3a8adacbf912e1fb94db27d3ad
终于写完了,最后总结一下,程序作者的注册算法还是很有新意的,首先用假的运算来迷惑混淆破解者,然后再利用两道关卡来验证
注册码,而第二关的算法实际上就是古典的代数矩阵加密算法的变形而已。同时我们也注意到,其实所有的24字节注册码,全部是由
前面的两字节来生成的,由此我们可以知道,一个注册名可以对应至多2^16组注册码,呵呵。欢迎大家一起来讨论!