好友
阅读权限35
听众
最后登录1970-1-1
|
楼主|
solly
发表于 2019-12-27 17:59
三、算法逆向和注册机实现
本帖最后由 solly 于 2020-1-9 01:07 编辑
(注:跟贴顺序有时会变化,这是第三部分,如果顺序显示不对,可先看第二部分再看这一部分)
前面两部分,对加密进行了分析,这部分对注册算法进行逆向分析。因为加密共有5个过程,其中4个比较简单,很容易逆向出来,这4个就不详説了。
现在看看,最关键的一段加密,其代码如下所示:
[Asm] 纯文本查看 复制代码 786139A0 51 push ecx
786139A1 0FB64E 03 movzx ecx, byte ptr [esi+3]
786139A5 0FB646 02 movzx eax, byte ptr [esi+2]
786139A9 0FB656 01 movzx edx, byte ptr [esi+1]
786139AD C1E1 08 shl ecx, 8
786139B0 0BC8 or ecx, eax
786139B2 0FB606 movzx eax, byte ptr [esi]
786139B5 C1E1 08 shl ecx, 8
786139B8 0BCA or ecx, edx
786139BA 0FB656 06 movzx edx, byte ptr [esi+6]
786139BE C1E1 08 shl ecx, 8
786139C1 0BC8 or ecx, eax ; ecx == sn_part1
786139C3 0FB646 07 movzx eax, byte ptr [esi+7]
786139C7 C1E0 08 shl eax, 8
786139CA 0BC2 or eax, edx
786139CC 0FB656 05 movzx edx, byte ptr [esi+5]
786139D0 C1E0 08 shl eax, 8
786139D3 0BC2 or eax, edx
786139D5 0FB656 04 movzx edx, byte ptr [esi+4]
786139D9 53 push ebx
786139DA 55 push ebp
786139DB C1E0 08 shl eax, 8
786139DE 57 push edi
786139DF 0BC2 or eax, edx ; eax == sn_part2
786139E1 BF 20000000 mov edi, 20 ; int n = 0x20;
786139E6 BA 2037EFC6 mov edx, C6EF3720 ; key = 0xC6EF3720
786139EB 4F dec edi ; n--
786139EC 897C24 0C mov dword ptr [esp+C], edi ; n
786139F0 8BD9 mov ebx, ecx ; sn11 = sn_part1;
786139F2 335C24 1C xor ebx, dword ptr [esp+1C] ; sn11 = sn_part1 ^ key3;
786139F6 8BF9 mov edi, ecx ; sn12 = sn_part1;
786139F8 035C24 20 add ebx, dword ptr [esp+20] ; sn11 = sn11 + key4;
786139FC C1EF 05 shr edi, 5 ; sn12 >>= 5;
786139FF 33FA xor edi, edx ; sn12 ^= key;
78613A01 03DF add ebx, edi ; sn11 += sn12;
78613A03 8BE9 mov ebp, ecx ; sn13 = sn_part1;
78613A05 C1E5 04 shl ebp, 4 ; sn13 <<= 4;
78613A08 03EB add ebp, ebx ; sn13 += sn11;
78613A0A 2BC5 sub eax, ebp ; sn_part2 -= sn13;
78613A0C 8BD8 mov ebx, eax
78613A0E 335C24 14 xor ebx, dword ptr [esp+14] ; sn11 = sn_part2 ^ key1;
78613A12 8BF8 mov edi, eax ; sn12 = sn_part2;
78613A14 035C24 18 add ebx, dword ptr [esp+18] ; sn11 = sn11 + key2;
78613A18 C1EF 05 shr edi, 5 ; sn12 >>= 5;
78613A1B 33FA xor edi, edx ; sn12 ^= key;
78613A1D 8BE8 mov ebp, eax ; sn13 = sn_part2;
78613A1F 03DF add ebx, edi ; sn11 += sn12;
78613A21 8B7C24 0C mov edi, dword ptr [esp+C] ; n
78613A25 C1E5 04 shl ebp, 4 ; sn13 <<= 4;
78613A28 03EB add ebp, ebx ; sn13 += sn11;
78613A2A 2BCD sub ecx, ebp ; sn_part1 -= sn13;
78613A2C 81C2 4786C861 add edx, 61C88647 ; key += 0x61C88647;
78613A32 85FF test edi, edi
78613A34 ^ 77 B5 ja short 786139EB ; 循环执行32次
78613A36 33FF xor edi, edi ; 0
78613A38 0BC7 or eax, edi ; sn_part2 = 0x4C22825B
78613A3A 33D2 xor edx, edx ; 0
78613A3C 0BD1 or edx, ecx ; sn_part1 = 0x4F16BACE
78613A3E 8BCA mov ecx, edx ; sn_part1 = 0x4F16BACE
78613A40 8BF8 mov edi, eax ; sn_part2 = 0x4C22825B
78613A42 0FACF9 08 shrd ecx, edi, 8 ; save to sn_int, edi最低8bits移到ecx的最高8bits
78613A46 884E 01 mov byte ptr [esi+1], cl ; save
78613A49 C1EF 08 shr edi, 8
78613A4C 8BCA mov ecx, edx
78613A4E 8BF8 mov edi, eax
78613A50 0FACF9 10 shrd ecx, edi, 10
78613A54 884E 02 mov byte ptr [esi+2], cl ; save
78613A57 8816 mov byte ptr [esi], dl ; save
78613A59 8BC8 mov ecx, eax
78613A5B 0FACCA 18 shrd edx, ecx, 18
78613A5F C1E9 18 shr ecx, 18
78613A62 8856 03 mov byte ptr [esi+3], dl ; save
78613A65 8BD0 mov edx, eax
78613A67 C1EF 10 shr edi, 10
78613A6A 8BC8 mov ecx, eax
78613A6C 5F pop edi
78613A6D 8856 04 mov byte ptr [esi+4], dl ; save
78613A70 C1E9 08 shr ecx, 8
78613A73 C1EA 10 shr edx, 10
78613A76 C1E8 18 shr eax, 18
78613A79 5D pop ebp
78613A7A 884E 05 mov byte ptr [esi+5], cl ; save
78613A7D 8856 06 mov byte ptr [esi+6], dl ; save
78613A80 8846 07 mov byte ptr [esi+7], al ; save
78613A83 5B pop ebx
78613A84 59 pop ecx
78613A85 C3 retn
先转换成 C 代码:
[C++] 纯文本查看 复制代码 //// Keys0 = {0xA4DFD9AD, 0x9AA2B19E, 0xC08F9A86, 0x9BA4B66A}
long getKey0Check(ULONG key1, ULONG key2, ULONG key3, ULONG key4, char * sn_int) {
ULONG sn11, sn12, sn13;
//// 取注册码
ULONG sn_part1 = (ULONG)(*(ULONG *)&sn_int[0]);
ULONG sn_part2 = (ULONG)(*(ULONG *)&sn_int[4]);
ULONG key = 0xC6EF3720;
for(int i=0; i<32; i++) {
sn11 = sn_part1 ^ key3;
sn11 += key4;
sn12 = sn_part1 >> 5;
sn12 ^= key;
sn11 += sn12;
sn13 = sn_part1 << 4;
sn13 += sn11;
sn_part2 -= sn13;
/////
sn11 = sn_part2 ^ key1;
sn11 += key2;
sn12 = sn_part2 >> 5;
sn12 ^= key;
sn11 += sn12;
sn13 = sn_part2 << 4;
sn13 += sn11;
sn_part1 -= sn13;
key += 0x61C88647;
}
//// sn_part1= 0x4F16BACE, sn_part2 = 4C22825B, key = 0x00000000
*(ULONG *)&sn_int[0] = sn_part1;
*(ULONG *)&sn_int[4] = sn_part2;
printSN(6);
return 0;
}
对代码进行优化一下,如下所示:
[C++] 纯文本查看 复制代码 //// Keys0 = {0xA4DFD9AD, 0x9AA2B19E, 0xC08F9A86, 0x9BA4B66A}
long getKey0Check(ULONG key1, ULONG key2, ULONG key3, ULONG key4, char * sn_int) {
ULONG sn11, sn12, sn13;
//// 取注册码
ULONG sn_part1 = (ULONG)(*(ULONG *)&sn_int[0]);
ULONG sn_part2 = (ULONG)(*(ULONG *)&sn_int[4]);
ULONG key = 0xC6EF3720;
for(int i=0; i<32; i++) {
sn11 = (sn_part1 ^ key3) + key4;
sn12 = (sn_part1 >> 5) ^ key;
sn13 = (sn_part1 << 4);
sn_part2 -= (sn11 + sn12 + sn13);
/////
sn11 = (sn_part2 ^ key1) + key2;
sn12 = (sn_part2 >> 5) ^ key;
sn13 = (sn_part2 << 4);
sn_part1 -= (sn11 + sn12 + sn13);
key += 0x61C88647;
}
*(ULONG *)&sn_int[0] = sn_part1;
*(ULONG *)&sn_int[4] = sn_part2;
printSN(3);
return 0;
}
可以看到,是用一个64位密码(两组32位),再加另一个32位key(计算的密码,每轮都不一样)(其实是IV),分别对一段SN(32位数据)加密,同时,SN两段数据还交叉进行加密。
一眼也看不出是什么加密方法,上网查资料,看看哪个算法有32轮加密,直到看到一个 DES 加密的框图,如下所示:
可以看到,这里也会将64位明文,分成两个32位交叉加密,是不是很象前面的加密代码,不过 DES 一般只进行 16 轮加密,而这里用了 32 轮,比标准的多一倍,并且也没有对明文和密文进行置换,因此,对 DES 加密过程也进行了简化。
因此,可以看成是对标准 DES 算法的一种变形,那解密算法自然也是 DES 解密算法的变形,经过对标准 DES 算法的基本了解和查阅了一些资料,终于逆向出解密算法如下:
[Asm] 纯文本查看 复制代码 //// step2_2() like DES_Decrypt()
int step2_2(ULONG key1, ULONG key2, ULONG key3, ULONG key4, char * sn_int) {
ULONG sn11, sn12, sn13;
//// 取注册码
ULONG sn_part1 = (ULONG)(*(ULONG *)&sn_int[0]);
ULONG sn_part2 = (ULONG)(*(ULONG *)&sn_int[4]);
ULONG IV = 0x00000000; //init IV
for(int i=0; i<32; i++) {
IV -= 0x61C88647;
/////
sn11 = (sn_part2 ^ key1) + key2;
sn12 = (sn_part2 >> 5) ^ IV;
sn13 = (sn_part2 << 4);
sn_part1 += (sn11 + sn12 + sn13);
/////
sn11 = (sn_part1 ^ key3) + key4;
sn12 = (sn_part1 >> 5) ^ IV;
sn13 = (sn_part1 << 4);
sn_part2 += (sn11 + sn12 + sn13);
}
*(ULONG *)&sn_int[0] = sn_part1;
*(ULONG *)&sn_int[4] = sn_part2;
//printSN(3);
return 0;
}
与加密算法很相似,只是顺序反过来,包括那个计算的密码也是顺序反过来。
完整的注册机代码如下,包括了注册码的加密过程(从输入的假码到完成加密)和逆向解密过程(在加密后的假码中的将正确的用户名CRC值替换原值,并解密返回到可用的注册码SN 0),便于了解SN在加密、解密过程的变化:
[C++] 纯文本查看 复制代码 #include <iostream>
#include "crc_table.h"
typedef unsigned char UCHAR;
typedef unsigned short UWORD;
typedef unsigned long ULONG;
typedef unsigned long long UINT64;
/*
// Video Joiner
UCHAR KEY0[] = {0xC6, 0x99};
UCHAR KEY1[] = {0xB2, 0xB5, 0xA9, 0xB7, 0x97, 0xA3, 0xD0, 0xE6,
0x9D, 0x8B, 0xA1, 0xD2, 0x63, 0xB7, 0x96, 0xDD};
char KEY2[] = "Q2JmTzS8fIKsNQBI8itv01Yir6Is4846";
char KEY3[] = "ncYEVD34az43";
*/
/*
// Video Splitter
UCHAR KEY0[] = {0x6A, 0xA2};
UCHAR KEY1[] = {0x99, 0xA8, 0x9B, 0x8E, 0x89, 0xD8, 0x7E, 0x93,
0x9E, 0xC0, 0xE1, 0x78, 0x8E, 0x7D, 0xA8, 0xC9};
char KEY2[] = "0HCw296HPiAWxg9v5lGQ4rA13Ejg52I8";
char KEY3[] = "Q7H4I53CngYt";
*/
/*
/// Video Converter
UCHAR KEY0[] = {0x68, 0x8B};
UCHAR KEY1[] = {0x96, 0xD4, 0x67, 0xAE, 0x8E, 0x82, 0x7A, 0xAB,
0x84, 0xDD, 0xBC, 0xEB, 0x90, 0x75, 0xCA, 0x6C};
char KEY2[] = "11s8hYyw9QW74U1Gw5893241o65rncsW";
char KEY3[] = "841a036f5vDr";
*/
///*
/// Audio Converter
UCHAR KEY0[] = {0xBD, 0x88};
UCHAR KEY1[] = {0xAD, 0xD9, 0xDF, 0xA4, 0x9E, 0xB1, 0xA2, 0x9A,
0x86, 0x9A, 0x8F, 0xC0, 0x6A, 0xB6, 0xA4, 0x9B};
char KEY2[] = "W9K85WVnk9BlCqM8f43rSwZ6T3748b44";
char KEY3[] = "7Kb3xboI268I";
//*/
//unsigned long KEY4=0;
//unsigned long KEY5=0;
//unsigned long KEY6=0;
void printSN(int theTimes);
long getCRC(char * buff);
unsigned short getSNCheck(char * sn_char);
long getKeyCheck1(char * key, char * sn_int);
long getKeyCheck2(unsigned long key, char * keyStr);
long getKey2Check1(char * key, char * sn_int);
long getKey2Check2(unsigned long key, char * sn_int);
long getKey0Check(ULONG key1, ULONG key2, ULONG key3, ULONG key4, char * sn_int);
long getSNCheck2(char * sn_int);
long getNameCheck(char * name);
int keyTransform1(char * keyStr, ULONG * key_trans);
//// application algorithm
int getAlgorithm(char * name);
//// calculate serial number
int getSN(char * name);
//// test sn: 11111111-22222222-33333333-44444444-55555555-66666666-7777
char sn_char_test[] = {0x11, 0x11, 0x11, 0x11,
0x22, 0x22, 0x22, 0x22,
0x33, 0x33, 0x33, 0x33,
0x44, 0x44, 0x44, 0x44,
0x55, 0x55, 0x55, 0x55,
0x66, 0x66, 0x66, 0x66,
0x77, 0x77}; ////check
//char sn_char_test[] = {0x52, 0x52, 0x52, 0x52,
// 0x52, 0x52, 0x52, 0x52,
// 0x52, 0x52, 0x52, 0x52,
// 0x52, 0x52, 0x52, 0x52,
// 0x52, 0x52, 0x52, 0x52,
// 0x52, 0x52, 0x52, 0x52,
// 0x52, 0x52}; ////check
int main(int argc, char** argv) {
char name[] = "solly"; /// modify name here
//char name[] = "52pojie.cn"; /// modify name here
printf("User Name: %s\n", name);
///// calculate
printf("\n============================ start calculate =============================\n");
////
int a = getAlgorithm(name);
//// get successfal flag value
printf("\n============================ show check value ============================\n");
long name_check = getNameCheck(name);
printf("Name check: 0x%08X\n", name_check);
UWORD key = (UWORD) name_check;
UWORD sn_key = * (UWORD *)&sn_char_test[18]; /// sn_int[19]sn_int[18]
printf("key valid flag: 0x%04X, key calculated flag: 0x%04X\n", key, sn_key);
///// reverse
printf("\n======================== start reverse calculate =========================\n");
////
int b = getSN(name);
return 0;
}
void printSN(int theTimes) {
int n = 26;
printf("SN %d: ", theTimes);
for(int i=0; i<n; i++) {
if((i>0) && (i % 4 == 0)) {
printf("-");
}
printf("%02X", (unsigned char)sn_char_test[ i ]);
}
printf("\n");
}
//// registration algorithm
int getAlgorithm(char * name) {
////
printSN(0); /// 显示注册码
////
long nameCRC = getCRC(name);
///printf("Name check: 0x%08X\n", nameCRC);
long organCRC = getCRC(NULL); //// 目前没有用到,为空
short snCHK = getSNCheck(sn_char_test);
unsigned short sn_check = (short)(nameCRC + organCRC) ^ snCHK;
///printf(" SN CHECK: 0x%04X\n", sn_check);
sn_char_test[24] = (unsigned char)(sn_check);
sn_char_test[25] = (unsigned char)(sn_check>>8);
//// 下面进行注册码处理
printSN(1); /// 显示注册码
long keyCheck = getKeyCheck1(KEY2, sn_char_test);
printSN(2); /// 显示注册码
getKey2Check1(KEY3, sn_char_test);
//printSN(3); /// 显示注册码
////
long sn_check2 = getSNCheck2(sn_char_test);
printSN(5); /// 显示注册码
return 0;
}
long getCRC(char * buff) {
long crc = 0;
if(buff == NULL) {
return 0;
}
while(*buff != '\0') {
crc ^= crc_table[(unsigned int)((*buff) ^ (unsigned char)crc)];
buff++;
}
return crc;
}
unsigned short getSNCheck(char * sn_char) {
unsigned char ch_even = 0;
unsigned char ch_odd = 0;
unsigned short sn_check = 0;
if(sn_char == NULL) {
return 0;
}
for(int i=0; i<24; i++) {
if(i % 2) {
ch_odd += sn_char[ i ];
} else {
ch_even ^= sn_char[ i ];
}
}
sn_check = (ch_even<<8) + ch_odd;
sn_check ^= ((UWORD)KEY3[1]<<8) + (UWORD)KEY3[0];
return sn_check;
}
/// Key1: "W9K85WVnk9BlCqM8f43rSwZ6T3748b44"
/// return:
/// chk1: 0xE88F784B
/// chk2: 0x7319B02E
long getKeyCheck2(unsigned long key, char * keyStr) {
unsigned char ch = 0;
unsigned long ch1 = 0;
unsigned long ch2 = key;
do {
ch = (unsigned char)(* keyStr);
ch1 = ((unsigned long)ch << 8);
ch2 ^= ch1;
unsigned short i = 0;
do {
ch1 = (unsigned char)i ^ ch2;
ch1 += 0x7034616B; //// "ka4k"
ch2 = (unsigned char)ch1;
ch2 &= 0x1F;
if(ch2 != 0) {
ch1 = (ch1 >> ch2) + (ch1<<(32-ch2)); /// ROR
}
ch2 = ch1 ^ 0x8372A5A7;
i--; //i += 0xFFFF;
} while(i);
keyStr ++;
} while(ch);
return ch2;
}
/// 将SN的6段分别与6个常量进行xor操作
/// Key: "W9K85WVnk9BlCqM8f43rSwZ6T3748b44"
long getKeyCheck1(char * key, char * sn_int) {
unsigned long ch1 = 0;
unsigned long chk = 0;
/// chk1 and chk1 calculated from Key: "W9K85WVnk9BlCqM8f43rSwZ6T3748b44"
//unsigned long chk1[] = {0xE88F784B, 0x20E57D8E, 0xA522A5A6, 0x2C245DBC, 0x712E29E9, 0xB2BAF74F};
//unsigned long chk2[] = {0x7319B02E, 0x42D2836B, 0x7936349F, 0xD9930AE9, 0x2872B191, 0x5EE814F3};
unsigned long chk2[6];
keyTransform1(key, chk2);
//// 以整数方式存取
unsigned long * sn = (unsigned long *)&sn_int[0];
for(int i=0; i<6; i++) {
sn[ i ] = sn[ i ] ^ chk2[ i ];
}
return 0;//chk1;
}
long getKey2Check1(char * key, char * sn_int) {
unsigned long ch = 0;
unsigned long ch1 = 0;
unsigned long ch2 = 0;
unsigned long ch3 = 0;
unsigned long ch4 = 0;
unsigned long ch5 = 0;
unsigned long ch6 = 0;
//// 由key2组合成两个整数
// //// 两整数相加
//// char key2[] = "7Kb3xboI268I"; //// 0x33624B37, 0x496F6278, 0x49383632
// ch1 = 0x496F6278; // (7-6-5-4)
// ch3 = 0x49383632; // (11-10-9-8)
ch1 = *(ULONG *)&KEY3[4]; // (7-6-5-4)
ch3 = *(ULONG *)&KEY3[8]; // (11-10-9-8)
ch = ch1 + ch3; //// ch = 0x92A798AA
long check2 = getKey2Check2(ch, sn_int);
printSN(3);
//// 由 key0 组合成 4 个整数
//unsigned long key0[] = {0xA4DFD9AD, 0x9AA2B19E, 0xC08F9A86, 0x9BA4B66A};
// ch4 = 0x9BA4B66A; //(17-16-15-14)
// ch3 = 0xC08F9A86; //(13-12-11-10)
// ch2 = 0x9AA2B19E; //(9-8-7-6)
// ch1 = 0xA4DFD9AD; //(5-4-3-2)
ch4 = *(ULONG *)&KEY1[12]; //(17-16-15-14)
ch3 = *(ULONG *)&KEY1[8]; //(13-12-11-10)
ch2 = *(ULONG *)&KEY1[4]; //(9-8-7-6)
ch1 = *(ULONG *)&KEY1[0]; //(5-4-3-2)
//// 每次同时处理两段SN
unsigned long long * sn_llu = (unsigned long long *)(& sn_int[0]);
for(int i=0; i<3; i++) {
getKey0Check(ch1, ch2, ch3, ch4, (char *)(& sn_llu[ i ]));
}
printSN(4);
return 0;
}
ULONG htonl(ULONG l) {
ULONG tmp = l;
ULONG nl = (UCHAR)tmp;
nl <<= 8;
nl += (UCHAR)(tmp >> 8);
nl <<= 8;
nl += (UCHAR)(tmp >> 16);
nl <<= 8;
nl += (UCHAR)(tmp >> 24);
return nl;
}
////
// ch1 = 0x496F6278; // key2[](7-6-5-4)
// ch2 = 0x49383632; // key2[](11-10-9-8)
// key = ch1 + ch2; //// ch = 0x92A798AA
long getKey2Check2(unsigned long key, char * sn_int) {
unsigned short key0 = 0;
unsigned short key1 = 0;
unsigned long key2 = 0;
unsigned long key3 = 0;
unsigned long ch = 0;
unsigned long sn_part = 0;
int n = 6;
unsigned long sn_origin = 0;
unsigned long sn_new = 0;
unsigned long sn_tmp = 0;
////printf(" key: 0x%08X\n", key);
//unsigned char * sn_ptr = (unsigned char *)&sn_int[2];
ULONG * sn = (ULONG *)(& sn_int[0]);
for(int i=0; i<n; i++) {
key -= 0x76BDEFDB;
//// key 字节顺序置换
key = htonl(key); //// 调整字节顺序
//printf("new key: 0x%08X\n", key);
//// 将SN每部分4字节组合成一个整数
sn_part = sn[ i ];
sn_tmp = sn_part; //// save temp
//printf("sn_Part1: 0x%08X\n", sn_part);
//// 计算
sn_part -= key;
sn_part ^= sn_origin;
//printf("sn_Part2: 0x%08X\n", sn_part);
//// 保存
sn[ i ] = sn_part;
//sn_ptr += 4; ///// SN 下一段
//n--;
sn_origin = sn_tmp; /// SN 上一段的值,作为下一段的异常参数
}// while(n>0);
return 0;
}
//// Keys0 = {0xA4DFD9AD, 0x9AA2B19E, 0xC08F9A86, 0x9BA4B66A}
long getKey0Check(ULONG key1, ULONG key2, ULONG key3, ULONG key4, char * sn_int) {
ULONG sn11, sn12, sn13;
//// 取注册码
ULONG sn_part1 = (ULONG)(*(ULONG *)&sn_int[0]);
ULONG sn_part2 = (ULONG)(*(ULONG *)&sn_int[4]);
ULONG key = 0xC6EF3720;
/* 32 个 key: key[ i ] = key[i-1] + 0x61C88647
0xC6EF3720, 0x28B7BD67, 0x8A8043AE, 0xEC48C9F5,
0x4E11503C, 0xAFD9D683, 0x11A25CCA, 0x736AE311,
0xD5336958, 0x36FBEF9F, 0x98C475E6, 0xFA8CFC2D,
0x5C558274, 0xBE1E08BB, 0x1FE68F02, 0x81AF1549,
0xE3779B90, 0x454021D7, 0xA708A81E, 0x08D12E65,
0x6A99B4AC, 0xCC623AF3, 0x2E2AC13A, 0x8FF34781,
0xF1BBCDC8, 0x5384540F, 0xB54CDA56, 0x1715609D,
0x78DDE6E4, 0xDAA66D2B, 0x3C6EF372, 0x9E3779B9//, 0x00000000
*/
//printf("key: 0x%08X, sn1: 0x%08X, sn2: 0x%08X\n", key, sn_part1, sn_part2);
//printf("key0key: \n");
for(int i=0; i<32; i++) {
sn11 = sn_part1 ^ key3;
sn11 += key4;
sn12 = sn_part1 >> 5;
sn12 ^= key;
sn11 += sn12;
sn13 = sn_part1 << 4;
sn13 += sn11;
sn_part2 -= sn13;
/////
sn11 = sn_part2 ^ key1;
sn11 += key2;
sn12 = sn_part2 >> 5;
sn12 ^= key;
sn11 += sn12;
sn13 = sn_part2 << 4;
sn13 += sn11;
sn_part1 -= sn13;
key += 0x61C88647;
//printf("key: 0x%08X, sn1: 0x%08X, sn2: 0x%08X\n", key, sn_part1, sn_part2);
}
//printf("\nkey0key: 0x%08X\n", key); /// 最后 key == 0x00000000
//// sn_part1= 0x4F16BACE, sn_part2 = 0x4C22825B, key = 0x00000000
*(ULONG *)&sn_int[0] = sn_part1;
*(ULONG *)&sn_int[4] = sn_part2;
//printSN(3);
return 0;
}
long getSNCheck2(char * sn_int) {
char low = sn_int[22]; /// 0x4D
char up = sn_int[23]; /// 0x5F
//printf("up = 0x%02X, low = 0x%02X\n", up, low);
for(int i=0; i<22; i++) {
sn_int[ i ] = (sn_int[ i ] - up) ^ low;
}
return 0;//(up<<8) + low;
}
long getNameCheck(char * name) {
ULONG check = 0;
while(*name != '\0') {
check = check ^ crc_table[(UCHAR)check ^ (UCHAR)(* name)];
name ++;
}
return check;
}
/////
/*
SN CRC: 0x894D
SN 0: 11111111 22222222 33333333 44444444 55555555 66666666 7777
SN 1: 11111111 22222222 33333333 44444444 55555555 66666666 4D89
SN 2: 3FA10862 49A1F060 AC07054A AD4ED79D C4E4277D 95728E38 4D89
SN 3: CEBA164F 5B82224C AB6AFAAC 0A1589E4 E1190CCD 2407D7E7 4D89
SN 3: CEBA164F 5B82224C 4B43745D 754702AF E1190CCD 2407D7E7 4D89
SN 3: CEBA164F 5B82224C 4B43745D 754702AF F3D8A75B FE0A4D5F 4D89
SN 3: CEBA164F 5B82224C 4B43745D 754702AF F3D8A75B FE0A4D5F 4D89
SN 4: 2216FABD B16E8EA0 A1A958B3 5BA5EE1D D93405B1 D2E64D5F 4D89
Name check: 0x9B64C2B0
key ok: 0xC2B0, key_act: 0xB105
*/
//// ==================== start reverse ===========================
//// ready
int step0(char * name, char * sn_int) {
ULONG name_check = (ULONG)getNameCheck(name);
//// update name_check to valid value
* (UWORD *)&sn_int[18] = (UWORD)name_check; /// sn_int[19]sn_int[18]
return name_check;
}
int step1(char * sn_int) {
char low = sn_int[22]; /// 0x4D
char hi = sn_int[23]; /// 0x5F
for(int i=0; i<22; i++) {
sn_int[ i ] = (sn_int[ i ] ^ low) + hi;
}
return 0;
}
// ch1 = 0x496F6278; // key2[](7-6-5-4)
// ch2 = 0x49383632; // key2[](11-10-9-8)
// key = ch1 + ch2; //// ch = 0x92A798AA
// like RC4_Decrypt
int step2_1(ULONG key, char * sn_int) {
ULONG * sn = (ULONG *)(& sn_int[0]);
ULONG sn_origin = 0;
for(int i=0; i<6; i++) {
key -= 0x76BDEFDB;
//// key 字节顺序置换
key = htonl(key); //// 调整字节顺序
//// descrypt
sn[ i ] = (sn[ i ] ^ sn_origin) + key;
sn_origin = sn[ i ]; /// SN 上一段的值,作为下一段的异常参数
}
return 0;
}
//// step2_2() like DES_Decrypt()
int step2_2(ULONG key1, ULONG key2, ULONG key3, ULONG key4, char * sn_int) {
ULONG sn11, sn12, sn13;
//// 取注册码
ULONG sn_part1 = (ULONG)(*(ULONG *)&sn_int[0]);
ULONG sn_part2 = (ULONG)(*(ULONG *)&sn_int[4]);
ULONG IV = 0x00000000; //init IV
for(int i=0; i<32; i++) {
IV -= 0x61C88647;
/////
sn11 = (sn_part2 ^ key1) + key2;
sn12 = (sn_part2 >> 5) ^ IV;
sn13 = (sn_part2 << 4);
sn_part1 += (sn11 + sn12 + sn13);
/////
sn11 = (sn_part1 ^ key3) + key4;
sn12 = (sn_part1 >> 5) ^ IV;
sn13 = (sn_part1 << 4);
sn_part2 += (sn11 + sn12 + sn13);
}
*(ULONG *)&sn_int[0] = sn_part1;
*(ULONG *)&sn_int[4] = sn_part2;
//printSN(3);
return 0;
}
///
int step2(char * sn_int) {
// ULONG key4 = 0x9BA4B66A; //(17-16-15-14)
// ULONG key3 = 0xC08F9A86; //(13-12-11-10)
// ULONG key2 = 0x9AA2B19E; //(9-8-7-6)
// ULONG key1 = 0xA4DFD9AD; //(5-4-3-2)
ULONG key4 = * (ULONG *)&KEY1[12];
ULONG key3 = * (ULONG *)&KEY1[8];
ULONG key2 = * (ULONG *)&KEY1[4];
ULONG key1 = * (ULONG *)&KEY1[0];
//// 64 bits data from sn
UINT64 * sn_llu = (UINT64 *)(& sn_int[0]);
for(int i=0; i<3; i++) {
step2_2(key1, key2, key3, key4, (char *)(& sn_llu[ i ]));
}
printSN(3);
//// char key2[] = "7Kb3xboI268I"; //// 0x33624B37, 0x496F6278, 0x49383632
// ULONG key5 = 0x496F6278; // (7-6-5-4)
// ULONG key6 = 0x49383632; // (11-10-9-8)
ULONG key5 = * (ULONG *)&KEY3[4]; // (7-6-5-4)
ULONG key6 = * (ULONG *)&KEY3[8]; // (11-10-9-8)
ULONG key = key5 + key6; //// key = 0x92A798AA
long check2 = step2_1(key, sn_int);
printSN(2);
return 0;
}
//// 1: 0xE88F784B, 2: 0x7319B02E
int keyTransform2(ULONG key, char * keyStr) {
unsigned char ch = 0;
unsigned long ch1 = 0;
unsigned long ch2 = key;
do {
ch = (unsigned char)(* keyStr);
ch1 = ((unsigned long)ch << 8);
ch2 ^= ch1;
unsigned short i = 0;
do {
ch1 = (unsigned char)i ^ ch2;
ch1 += 0x7034616B;
ch2 = (unsigned char)ch1;
ch2 &= 0x1F;
if(ch2 != 0) {
ch1 = (ch1 >> ch2) + (ch1<<(32-ch2)); /// ROR
}
ch2 = ch1 ^ 0x8372A5A7;
i--; //i += 0xFFFF;
} while(i);
keyStr ++;
} while(ch);
return ch2;
}
//// KeyStr: "W9K85WVnk9BlCqM8f43rSwZ6T3748b44"
int keyTransform1(char * keyStr, ULONG * key_trans) {
const ULONG k = 0x41363233;
if((keyStr == NULL) || (key_trans == NULL)) {
return -1;
}
ULONG ch1 = (ULONG)keyStr[0];
ULONG ch2 = (ULONG)keyStr[0];
ch1 ^= k;
ULONG chk1 = keyTransform2(ch1, keyStr); //// key 变换
//printf("Key trans chk1: 0x%08X\n", chk1);
///
ch2 = (ch2<<8) ^ chk1;
ULONG chk2 = keyTransform2(ch2, keyStr); //// key 变换
//printf("Key trans chk2: 0x%08X\n", chk2);
for(int i=0; i<6; i++) {
key_trans[i] = chk2;
//printf("Key trans %d: 0x%08X\n", i, key_trans[i]);
ULONG n1 = chk2 & 0x1F;
if(n1 != 0) {
chk1 = (chk1<<n1) + (chk1>>(32-n1)); /// ROL
}
ULONG n2 = ((chk1 >> 8) & 0x1F);
chk2 = chk1 ^ chk2;
if(n2 != 0) {
chk2 = (chk2 >> n2) + (chk2 << (32-n2)); /// ROR
}
chk1 += chk2;
////
}
return chk2;
}
/// 将SN的6段分别与6个常量进行xor操作
/// Key: "W9K85WVnk9BlCqM8f43rSwZ6T3748b44"
int step3(char * key, char * sn_int) {
/// key transformed from: "W9K85WVnk9BlCqM8f43rSwZ6T3748b44"
//ULONG key1[] = {0xE88F784B, 0x20E57D8E, 0xA522A5A6, 0x2C245DBC, 0x712E29E9, 0xB2BAF74F};
ULONG key_trans[6];// = {0x7319B02E, 0x42D2836B, 0x7936349F, 0xD9930AE9, 0x2872B191, 0x5EE814F3};
keyTransform1(key, key_trans);
//// 以整数方式存取
ULONG * sn = (ULONG *)&sn_int[0];
for(int i=0; i<6; i++) {
sn[ i ] = sn[ i ] ^ key_trans[ i ];
}
return 0;//chk1;
}
int step4(char * name, char * sn_int) {
long nameCRC = getCRC(name);
long organCRC = getCRC(NULL); //// 目前没有用到,为空
short snCHK = getSNCheck(sn_char_test);
UWORD sn_check = (short)(nameCRC + organCRC) ^ snCHK;
//// update sn_check to valid value
* (UWORD *)&sn_int[24] = sn_check; /// sn_int[25]sn_int[24]
return sn_check;
}
int getSN(char * name) {
step0(name, sn_char_test);
printSN(5);
step1(sn_char_test);
printSN(4);
step2(sn_char_test); /// it has two steps
//printSN(2);
step3(KEY2, sn_char_test);
printSN(1);
step4(name, sn_char_test);
//// final sn is valid
printSN(0);
return 0;
}
另外,CRC 查表数据头文件:crc_table.h 如下:
[C++] 纯文本查看 复制代码 //// crc计算的查表数据
#ifndef __crc_table_h__
#define __crc_table_h__
long crc_table[] = {
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D};
#endif
计算结果如下:
[Shell] 纯文本查看 复制代码 User Name: solly
============================ start calculate =============================
SN 0: 11111111-22222222-33333333-44444444-55555555-66666666-7777
SN 1: 11111111-22222222-33333333-44444444-55555555-66666666-4D89
SN 2: 3FA10862-49A1F060-AC07054A-AD4ED79D-C4E4277D-95728E38-4D89
SN 3: 24B85F92-CE17FE7D-AB6AFAAC-0A1589E4-E1190CCD-2407D7E7-4D89
SN 4: CEBA164F-5B82224C-4B43745D-754702AF-F3D8A75B-FE0A4D5F-4D89
SN 5: 2216FABD-B16E8EA0-A1A958B3-5BA5EE1D-D93405B1-D2E64D5F-4D89
============================ show check value ============================
Name check: 0x9B64C2B0
key valid flag: 0xC2B0, key calculated flag: 0xB105
======================== start reverse calculate =========================
SN 5: 2216FABD-B16E8EA0-A1A958B3-5BA5EE1D-D934B0C2-D2E64D5F-4D89
SN 4: CEBA164F-5B82224C-4B43745D-754702AF-F3D85CEE-FE0A4D5F-4D89
SN 3: 24B85F92-CE17FE7D-AB6AFAAC-0A1589E4-BB21717E-494633AD-4D89
SN 2: 3FA10862-49A1F060-AC07054A-AD4ED79D-8EFCF20F-7C495F40-4D89
SN 1: 11111111-22222222-33333333-44444444-1F4D8027-8F5DB71E-4D89
SN 0: 11111111-22222222-33333333-44444444-1F4D8027-8F5DB71E-C42E
--------------------------------
Process exited after 0.1549 seconds with return value 0
请按任意键继续. . .
再来一个:
[Shell] 纯文本查看 复制代码 User Name: 52pojie.cn
============================ start calculate =============================
SN 0: 52525252-52525252-52525252-52525252-52525252-52525252-5252
SN 1: 52525252-52525252-52525252-52525252-52525252-52525252-BDB9
SN 2: 7CE24B21-39D18010-CD66642B-BB58C18B-C3E3207A-A146BA0C-BDB9
SN 3: 61F9A251-9D04CDEE-3AFAEABD-797A12B7-F00E15C6-2F543C15-BDB9
SN 4: B0A54A27-886F3D22-2E38ED99-1AD46F14-FE96EECF-B184EE74-BDB9
SN 5: D2DF385D-FA152740-542A97CB-488E154E-64CC94B5-D3FEEE74-BDB9
============================ show check value ============================
Name check: 0x4FDFF252
key valid flag: 0xF252, key calculated flag: 0xB594
======================== start reverse calculate =========================
SN 5: D2DF385D-FA152740-542A97CB-488E154E-64CC52F2-D3FEEE74-BDB9
SN 4: B0A54A27-886F3D22-2E38ED99-1AD46F14-FE963090-B184EE74-BDB9
SN 3: 61F9A251-9D04CDEE-3AFAEABD-797A12B7-FBD3B937-99CCFAE2-BDB9
SN 2: 7CE24B21-39D18010-CD66642B-BB58C18B-B818C5E8-D662DDA7-BDB9
SN 1: 52525252-52525252-52525252-52525252-29A9B7C0-257635F9-BDB9
SN 0: 52525252-52525252-52525252-52525252-29A9B7C0-257635F9-0D37
--------------------------------
Process exited after 0.1664 seconds with return value 0
请按任意键继续. . .
上面两个例子最后输出的 SN 0 就是正确的注册码了。
可以看到,注册码的前4段没什么用,只影响最后的 CRC 校验值。
分析完毕!!!!
|
免费评分
-
查看全部评分
|