虽然作者已经把算法公开了,但也不是不能分析一下。
首先是把程序跑起来,然后搜关键字,抵达验证函数附近:
00409754 | 55 | push ebp | ;; 按钮处理事件?
00409755 | 8BEC | mov ebp, esp |
00409757 | 81EC 1C000000 | sub esp, 1C |
0040975D | 837D 08 0D | cmp dword ptr ss:[ebp+8], D | D:'\r'
00409761 | 0F85 52010000 | jne keygenme.4098B9 |
00409767 | 833D 20005202 00 | cmp dword ptr ds:[2520020], 0 |
0040976E | 0F85 43000000 | jne keygenme.4097B7 |
00409774 | BB 06000000 | mov ebx, 6 |
00409779 | E8 CEFFFFFF | call keygenme.40974C |
0040977E | 68 01030080 | push 80000301 |
00409783 | 6A 00 | push 0 |
00409785 | 68 00000000 | push 0 |
0040978A | 68 04000080 | push 80000004 |
0040978F | 6A 00 | push 0 |
00409791 | 68 CB904000 | push keygenme.4090CB | 4090CB:"硬盘特征字尚未被取出"
00409796 | 68 04000000 | push 4 |
0040979B | BB 00030000 | mov ebx, 300 |
004097A0 | E8 E9030000 | call keygenme.409B8E |
004097A5 | 83C4 34 | add esp, 34 |
004097A8 | B8 00000000 | mov eax, 0 |
004097AD | BB 01000000 | mov ebx, 1 |
004097B2 | E9 04010000 | jmp keygenme.4098BB |
004097B7 | FF35 20005202 | push dword ptr ds:[2520020] | push 机器码
004097BD | E8 FF000000 | call keygenme.4098C1 | call 计算注册码
004097C2 | 8945 FC | mov dword ptr ss:[ebp-4], eax | 储存真码 (_4)
004097C5 | 6A FF | push FFFFFFFF |
004097C7 | 6A 08 | push 8 |
004097C9 | 68 1E000116 | push 1601001E |
004097CE | 68 01000152 | push 52010001 |
004097D3 | E8 BC030000 | call keygenme.409B94 | 取编辑框内容 [假码]
004097D8 | 83C4 10 | add esp, 10 |
004097DB | 8945 F8 | mov dword ptr ss:[ebp-8], eax | ebp-8 = str_code
004097DE | 68 04000080 | push 80000004 |
004097E3 | 6A 00 | push 0 |
004097E5 | 8B45 F8 | mov eax, dword ptr ss:[ebp-8] |
004097E8 | 85C0 | test eax, eax |
004097EA | 75 05 | jne keygenme.4097F1 |
004097EC | B8 E0904000 | mov eax, keygenme.4090E0 |
004097F1 | 50 | push eax |
004097F2 | 68 01000000 | push 1 |
004097F7 | BB 64010000 | mov ebx, 164 | 整数转双精度
004097FC | E8 8D030000 | call keygenme.409B8E | 易语言支持库 CALL
00409801 | 83C4 10 | add esp, 10 |
00409804 | 8945 F0 | mov dword ptr ss:[ebp-10], eax |
00409807 | 8955 F4 | mov dword ptr ss:[ebp-C], edx |
0040980A | 8B5D F8 | mov ebx, dword ptr ss:[ebp-8] |
0040980D | 85DB | test ebx, ebx |
0040980F | 74 09 | je keygenme.40981A |
00409811 | 53 | push ebx |
00409812 | E8 71030000 | call keygenme.409B88 | 释放内存
00409817 | 83C4 04 | add esp, 4 |
0040981A | DB45 FC | fild st(0), dword ptr ss:[ebp-4] | 加载真码,转双精度,然后写出到 ebp-18
0040981D | DD5D E8 | fstp qword ptr ss:[ebp-18], st(0) |
00409820 | DD45 E8 | fld st(0), qword ptr ss:[ebp-18] | 读入真码
00409823 | DC65 F0 | fsub st(0), qword ptr ss:[ebp-10] | 读入假码 (计算“真码 - 假码”)
00409826 | D9E4 | ftst |
00409828 | DFE0 | fnstsw ax |
0040982A | F6C4 01 | test ah, 1 |
0040982D | 74 02 | je keygenme.409831 | 取绝对值
0040982F | D9E0 | fchs |
00409831 | DC1D E1904000 | fcomp st(0), qword ptr ds:[4090E1] | => 1e-07
00409837 | DFE0 | fnstsw ax |
00409839 | F6C4 41 | test ah, 41 | 易语言允许误差,检测是否为零
0040983C | 0F85 43000000 | jne keygenme.409885 |
00409842 | BB 06000000 | mov ebx, 6 |
00409847 | E8 00FFFFFF | call keygenme.40974C |
0040984C | 68 01030080 | push 80000301 |
00409851 | 6A 00 | push 0 |
00409853 | 68 00000000 | push 0 |
00409858 | 68 04000080 | push 80000004 |
0040985D | 6A 00 | push 0 |
0040985F | 68 E9904000 | push keygenme.4090E9 | “注册码无效…”
00409864 | 68 04000000 | push 4 |
00409869 | BB 00030000 | mov ebx, 300 |
0040986E | E8 1B030000 | call keygenme.409B8E |
00409873 | 83C4 34 | add esp, 34 |
00409876 | B8 00000000 | mov eax, 0 |
0040987B | BB 01000000 | mov ebx, 1 |
00409880 | E9 36000000 | jmp keygenme.4098BB |
00409885 | BB 06000000 | mov ebx, 6 |
0040988A | E8 BDFEFFFF | call keygenme.40974C |
0040988F | 68 01030080 | push 80000301 |
00409894 | 6A 00 | push 0 |
00409896 | 68 00000000 | push 0 |
0040989B | 68 04000080 | push 80000004 |
004098A0 | 6A 00 | push 0 |
004098A2 | 68 45914000 | push keygenme.409145 | 409145:"谢谢您的注册!您现在可以继续使用本软件!"
004098A7 | 68 04000000 | push 4 |
004098AC | BB 00030000 | mov ebx, 300 |
004098B1 | E8 D8020000 | call keygenme.409B8E |
004098B6 | 83C4 34 | add esp, 34 |
004098B9 | 33DB | xor ebx, ebx |
004098BB | 8BE5 | mov esp, ebp |
004098BD | 5D | pop ebp |
004098BE | C2 0400 | ret 4 |
稍微调试过后,发现真码由 004098C1 这个函数提供,进去看看:
004098C1 | 55 | push ebp |
004098C2 | 8BEC | mov ebp, esp |
004098C4 | 81EC 0C000000 | sub esp, C |
004098CA | 68 01030080 | push 80000301 |
004098CF | 6A 00 | push 0 |
004098D1 | 68 13E35E04 | push 45EE313 | 第二个参数 固定值 0x45EE313
004098D6 | 68 01030080 | push 80000301 |
004098DB | 6A 00 | push 0 |
004098DD | FF75 08 | push dword ptr ss:[ebp+8] | 参数 - 机器码
004098E0 | 68 02000000 | push 2 | 两个参数
004098E5 | BB CC000000 | mov ebx, CC | 函数_XOR
004098EA | E8 9F020000 | call keygenme.409B8E | 易语言函数调用跳转
004098EF | 83C4 1C | add esp, 1C |
004098F2 | 8945 FC | mov dword ptr ss:[ebp-4], eax | 存放到 _4
004098F5 | 68 01030080 | push 80000301 |
004098FA | 6A 00 | push 0 |
004098FC | 68 16E35E04 | push 45EE316 | 固定值 0x45EE316
00409901 | 68 01030080 | push 80000301 |
00409906 | 6A 00 | push 0 |
00409908 | FF75 FC | push dword ptr ss:[ebp-4] | _4 变量
0040990B | 68 02000000 | push 2 |
00409910 | BB CC000000 | mov ebx, CC | 再 XOR
00409915 | E8 74020000 | call keygenme.409B8E |
0040991A | 83C4 1C | add esp, 1C |
0040991D | 8945 F8 | mov dword ptr ss:[ebp-8], eax | _8 <- 结果
00409920 | 68 01030080 | push 80000301 |
00409925 | 6A 00 | push 0 |
00409927 | 68 40E35E04 | push 45EE340 | 固定值 0x45EE340
0040992C | 68 01030080 | push 80000301 |
00409931 | 6A 00 | push 0 |
00409933 | FF75 F8 | push dword ptr ss:[ebp-8] | _8 变量
00409936 | 68 02000000 | push 2 |
0040993B | BB CC000000 | mov ebx, CC | 还是 xor
00409940 | E8 49020000 | call keygenme.409B8E |
00409945 | 83C4 1C | add esp, 1C |
00409948 | E9 00000000 | jmp keygenme.40994D |
0040994D | 8BE5 | mov esp, ebp |
0040994F | 5D | pop ebp |
00409950 | C2 0400 | ret 4 |
连续 XOR 三次。由于 (A XOR B) XOR C
等价于 A XOR (B XOR C)
,简化后其实就是 [机器码] XOR 0x45EE345
。
界面上的机器码是十进制表示形式,所以也不需要进行什么转换了。
算法注册机感觉就没必要写了,解析十进制然后一次 XOR,最后将数字转换为十进制的文本即可。