【文章标题】:键盘记录器 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组注册码,呵呵。欢迎大家一起来讨论!
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)