适合对象:想进阶的菜鸟,初次接触算法的同志。
使用工具:ollydbg,vc++(编写注册机)
个人觉得算法分析有2个难点
1.定位-那里是关键算法
2.算法的复杂程度
对于第1点,我们发现F8走过0059A1B9的call之后出现了注册码,而此前没有看到,故推测此call为
关键算法call。这样就定位了。
对于第2点就要慢慢看代码了。
暴破Word文档资料管理系统比较简单,这里节省篇幅就不说了(话外:如果你还不会暴破,请跳过这篇文章)
废话少说了,直接开始分析代码:
0059A199 |. 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4] ; eax指向输入的注册码
0059A19C |. 50 PUSH EAX ; 保存指向注册码的指针
0059A19D |. 8D55 F4 LEA EDX,DWORD PTR SS:[EBP-C]
0059A1A0 |. A1 A06F5A00 MOV EAX,DWORD PTR DS:[5A6FA0]
0059A1A5 |. 8B00 MOV EAX,DWORD PTR DS:[EAX]
0059A1A7 |. E8 FC0B0000 CALL DMS.0059ADA8 ; 取机器码
0059A1AC |. 8B55 F4 MOV EDX,DWORD PTR SS:[EBP-C] ; edx指向机器码
0059A1AF |. 8D4D F8 LEA ECX,DWORD PTR SS:[EBP-8]
0059A1B2 |. A1 A06F5A00 MOV EAX,DWORD PTR DS:[5A6FA0]
0059A1B7 |. 8B00 MOV EAX,DWORD PTR DS:[EAX]
0059A1B9 |. E8 B20C0000 CALL DMS.0059AE70 ; 产生注册码,随后进入分析
0059A1BE |. 8B55 F8 MOV EDX,DWORD PTR SS:[EBP-8]
0059A1C1 |. 58 POP EAX
0059A1C2 |. E8 A5ABE6FF CALL DMS.00404D6C ; 关键比较call
0059A1C7 |. 0F85 B1000000 JNZ DMS.0059A27E ; 跳到注册码出错处理部分!
进入0059A1B9处的CALL DMS.0059AE70
0059AE91 |. BB 9F860100 MOV EBX,1869F ; 注意这里MOV EBX,1869F, 1869F是固定的
0059AE96 |. 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4]
0059AE99 |. E8 829DE6FF CALL DMS.00404C20 ; 返回注册码长度
0059AE9E |. 85C0 TEST EAX,EAX ; 嘿嘿,没有输入 ?
0059AEA0 |. 7E 19 JLE SHORT DMS.0059AEBB ; 跳就牺牲了
0059AEA2 |. BA 01000000 MOV EDX,1 ; 初始化
0059AEA7 |> 8B4D FC /MOV ECX,DWORD PTR SS:[EBP-4] ; ecx指向机器码
0059AEAA |. 0FB64C11 FF |MOVZX ECX,BYTE PTR DS:[ECX+EDX-1] ; 取一位机器码的asc码
0059AEAF |. 03D9 |ADD EBX,ECX ; 逐位加上机器码的asc码
0059AEB1 |. 81C3 06020000 |ADD EBX,206 ; 求和(加上0x206),结果保存在EBX
0059AEB7 |. 42 |INC EDX ; 指向下一位
0059AEB8 |. 48 |DEC EAX ; 长度减1,即循环次数减1
0059AEB9 |.^ 75 EC \JNZ SHORT DMS.0059AEA7 ; 还没有完?继续循环
0059AEBB |> 8BD6 MOV EDX,ESI
0059AEBD |. 8BC3 MOV EAX,EBX ; 保存结果
以下我是用c++写的注册机,仅供研究之用,请勿非法传播,研究完,请删除。
请支持共享软件。
//Word文档资料管理系统 注册机
//vc++ 6.0, windows xp sp2编译通过
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
int main()
{
char code[20];
cout << "please input the code: ";
cin >> code;
int sum = 0x1869f; //对应程序的 MOV EBX,1869F
int length = strlen(code); //对应程序的 CALL 00404C20 ;返回注册码长度
for (int i = 0; i < length; i++)
{
sum += code[i]; //对应 ADD EBX,ECX
sum += 0x206; //对应 ADD EBX,206
// sum = sum + code[i] + 0x206; //可以直接用这局代替
}
/*上面的 for 循环对应如下的代码:请初学者仔细分析
MOV EDX,1
MOV ECX,DWORD PTR SS:[EBP-4] ; ecx指向机器码
MOVZX ECX,BYTE PTR DS:[ECX+EDX-1] ; 取一位机器码的asc码
ADD EBX,ECX ; 逐位加上机器码的asc码
ADD EBX,206 ; 求和,结果保存在EBX
INC EDX ; 指向下一位机器码
DEC EAX ; 长度减 1即循环次数减 1
JNZ SHORT DMS.0059AEA7 ; 不为 0 继续循环
*/
// MOV EDX,ESI
// MOV EAX,EBX ;结果保存到EAX,一般是函数的返回值
cout << endl;
cout << "The register code is: " << sum << endl;
system(" pause ");
return 0;
}
运行注册机,输入机器码,看看计算结果吧(图1):103410
输入103410看看,注册成功(图2)
程序将运行次数和注册码写入注册表,有兴趣请自行跟踪,部分代码如下:
0059A207 |> BA E4A25900 MOV EDX,DMS.0059A2E4 ; ASCII "SOFTWARE\wjsh"
0059A20C |. 8BC3 MOV EAX,EBX
0059A20E |. E8 019FEAFF CALL DMS.00444114
0059A213 |. B1 01 MOV CL,1
0059A215 |. BA E4A25900 MOV EDX,DMS.0059A2E4 ; ASCII "SOFTWARE\wjsh"
0059A21A |. 8BC3 MOV EAX,EBX
0059A21C |. E8 CF9FEAFF CALL DMS.004441F0
0059A221 |. B9 C3FFFFFF MOV ECX,-3D
0059A226 |. BA FCA25900 MOV EDX,DMS.0059A2FC ; ASCII "run_times"
0059A22B |. 8BC3 MOV EAX,EBX
0059A22D |. E8 B6A3EAFF CALL DMS.004445E8
0059A232 |> 8D55 F0 LEA EDX,DWORD PTR SS:[EBP-10]
0059A235 |. 8B86 04030000 MOV EAX,DWORD PTR DS:[ESI+304]
0059A23B |. E8 C445ECFF CALL DMS.0045E804
0059A240 |. 8B4D F0 MOV ECX,DWORD PTR SS:[EBP-10]
0059A243 |. BA 10A35900 MOV EDX,DMS.0059A310 ; ASCII "regist_code"
0059A248 |. 8BC3 MOV EAX,EBX
0059A24A |. E8 F5A2EAFF CALL DMS.00444544
0059A24F |. 8BC3 MOV EAX,EBX
0059A251 |. E8 2A9EEAFF CALL DMS.00444080
0059A256 |. 8BC3 MOV EAX,EBX
0059A258 |. E8 0F98E6FF CALL DMS.00403A6C
0059A25D |. B8 24A35900 MOV EAX,DMS.0059A324
0059A262 |. E8 3D0CEAFF CALL DMS.0043AEA4 ; 提示出错了
打开注册表对应位置可以找到找到(图3):
[HKEY_LOCAL_MACHINE\SOFTWARE\wjsh]
"run_times"=dword:ffffffc7
"regist_code"="103410"
文章比较短,请我等菜鸟自己练习。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)