From 820586763bbf72ecf1466415569f19f3c2adb9fa Mon Sep 17 00:00:00 2001 From: Cool-Y <1072916769@qq.com> Date: Sat, 30 Mar 2019 17:36:25 +0800 Subject: [PATCH] Site updated: 2019-03-30 17:36:19 --- 2019/03/28/逆向工程实验/index.html | 6 +++--- sitemap.xml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/2019/03/28/逆向工程实验/index.html b/2019/03/28/逆向工程实验/index.html index bcda9d6c..7af310e5 100644 --- a/2019/03/28/逆向工程实验/index.html +++ b/2019/03/28/逆向工程实验/index.html @@ -96,7 +96,7 @@ - + @@ -519,7 +519,7 @@
用鼠标选中程序分支点,按空格切换回汇编指令界面
可以看到,这条指令位于PE文件的.text节,并且IDA已经自动将地址转换为运行时的内存地址VA:004010F9
VA:004010F9
处查看那条引起程序分支的关键指令验证函数的返回值存于EAX寄存器中,if语句通过以下两条指令执行
1 | cmp eax,ecx |
分析上图算法,按tab键转换为高级语言1
2
3
4for ( i = 0; i < v6; v12 = v10 )
v10 = (v6 + v12) * lpStringa[i++];
if ( (v12 ^ 0xA9F9FA) == atoi(v15) )
MessageBoxA(hDlg, aTerimaKasihKer, aGoodBoy, 0);
可以看出,生成注册码主要在for循环中完成,之后将生成的注册码与输入相比较,判断是否正确。
所以,只要能弄明白v6,v12,v10,v15的含义,我们就可以轻松的编写注册机。
打开ollybdg,在进入循环之前设下断点,动态调试程序1
2
3
4
5
6
7
8004010CC |> /8B4D 10 |mov ecx,[arg.3] //此时ecx为name
004010CF |. 8B55 0C |mov edx,[arg.2] //edx为0x1908
004010D2 |. 03D3 |add edx,ebx //edx加上name的长度(ebx)
004010D4 |. 0FBE0C08 |movsx ecx,byte ptr ds:[eax+ecx] //ecx=61h
004010D8 |. 0FAFCA |imul ecx,edx //61h(a) * edx
004010DB |. 40 |inc eax //eax加1(初始为0)
004010DC |. 894D 0C |mov [arg.2],ecx
004010DF |. 3BC3 |cmp eax,ebx //循环是否结束
arg.3为输入的name,arg.2初始为0x1908,ebx为name的长度,eax每次循环加1直到等于长度
因此,我们可以对参数的含义进行解释如下1
2
3
4
5
6
7
8
9
10
11v12 = 6408; //0x1908
v10 = 6408; //0x1908
v6 = len(name);
v12 = input_serial;
for ( i = 0; i < v6; i++ ){
v12 = v10;
v10 = (v6 + v12) * lpStringa[i];
}
if ((v12 ^ 0xA9F9FA) == atoi(v15)){
MessageBoxA(hDlg, aTerimaKasihKer, aGoodBoy, 0);
}
可见,v12^0xA9F9FA的结果即是正确的注册码,我们编写一个简单的程序帮助我们生成注册码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <iostream>
#include<stdio.h>
using namespace::std;
int main(){
int v12;
int v10 = 6408; //0x1908
string name;
cout << "请输入name: ";
cin >> name;
int len = name.size();
for(int i = 0; i < len+1; i++ ){
v12 = v10;
v10 = (len + v12) * name[i];
}
cout<<"\n"<<"注册码为: "<<(v12 ^ 0xA9F9FA)<<endl;
return 0;
}
可见,v12^0xA9F9FA的结果即是正确的注册码,我们编写一个简单的程序帮助我们生成注册码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <iostream>
#include<stdio.h>
using namespace::std;
int main(){
int v12;
int v10 = 6408; //0x1908
string name;
cout << "请输入name: ";
cin >> name;
int len = name.size();
for(int i = 0; i < len+1; i++ ){
v12 = v10;
v10 = (len + v12) * name[i];
}
cout<<"\n"<<"注册码为: "<<(v12 ^ 0xA9F9FA)<<endl;
return 0;
}
计算出”testname”的对应注册码
注册成功!
CrackMe1.exe 1641.0 KB
无保护措施:无壳、未加密、无反调试措施
使用OllyDbg对该程序进行调试时,程序会自动退出