这是我的第一篇破文,其实在前两天我也发过一篇关于Poweriso软件的破文,写好之后忘保存了,在一恢复数据就剩一点了(希望怎么能改善一下)。。此破解程序为国外最强下载器IDM(本人小白,除此破解。如遇大神,还望指点!)
此软件破解难度不高适合新手,下面我们就开始分析吧!
工具:吾爱破解OD,PEID
我们先用PEID打开程序查看其基本信息,发现此程序为32位,无壳,
然后我们就直接用OD打开程序,结果发现在OD中一运行程序,程序就脱离OD单独运行了。(请大神指点!)
之后我就试了试用OD去附加此程序并运行,成功!
我们点击注册并随便填写注册信息和序列号。
然后我们点击确定后弹出注册失败的信息!
因为其程序要判断序列号的对错就要从文本控件处获得用户输入的序列号信息(API函数为GetWindowTextA或GetWindowTextW),我们不知道具体是哪个函数就在OD中按Ctry+B搜索两个函数都进行下段点。
然后在点击注册窗口的确定按钮,然后发现程序停在GetWindowTextA处!
我们发现注册窗口有4个文本控件,其应该是调用四次GetWindowTextA函数,
所以我们就继续按F5运行直到程序第四次停在此处,则为序列号的GetWindowTextA
其调用完GetWindowTextA获得用户输入的序列号后需要判断序列号输入的是否正确,所以我们需要运行到用户区看看序列号分析算法
我们在OD中按ALT+f9使程序回到用户区,然后我们需要F8单步往下运行寻找序列号分析算法。
代码刚返回到用户区就发现一处判断!然后我们发现此处对eax即调用GetWindowTextA函数后的返回值eax,
if(eax == 0)就弹出用户名失败的窗口,所以名字,姓氏, 电子邮件,序列号这些注册信息都不能为空。
在继续F8往下分析,又发现了判断调转指令
[Asm] 纯文本查看 复制代码
00529C8C |> \8DBD 7CFFFFFF lea edi,[local.33] ;[b] 计算序列号长度,(Local.33为序列号的地址)[/b]00529C92 |. 83C9 FF or ecx,0xFFFFFFFF00529C95 |. 33C0 xor eax,eax00529C97 |. F2:AE repne scas byte ptr es:[edi]00529C99 |. F7D1 not ecx00529C9B |. 49 dec ecx00529C9C |. 75 11 jnz XIDMan.00529CAF ; [b] if ( len(序列号) == 0 ) 弹出序列号错误的窗口[/b]00529C9E |. 8B0D 38407000 mov ecx,dword ptr ds:[0x704038]00529CA4 |. 50 push eax00529CA5 |. 68 9CF06C00 push IDMan.006CF09C ; Internet Download Manager00529CAA |.^ E9 F0FEFFFF jmp IDMan.00529B9F ;此跳转会去执行弹出序列号错误窗口的代码
我们接着F8往下分析,其会计算序列号的长度并和0x17(23)比较,
如果序列号长度小于23其会发生跳转,因为我们输入的序列号长度小于23所以我们F8跟进运行到跳转处,
发现其会执行执行跳转到弹出序列号失败窗口的代码。(所以正确的序列号长度应为23)
我们运行程序重新输入长度为23的序列号("KKKKKKKKKKKKKKKKKKKKKKK"),点击确定后
再F8运行到此此处后我们接着向下分析。
然后我们又发现了关键判断处,
al = ss : [ebp - 0x11]
test al,al
如果al不等于0其就会弹出序列号错误的窗口,所以ss : [ebp - 0x11]中的数据应该为0
我们往上分析,并且注意能改变ss : [ebp - 0x11] 数据的代码。(看怎样能保持此数据为0)
我们发现第一处改变ss : [ebp - 0x11]数据的代码,
然后我们在此处下断点后行程序使程序停在此处并对其进行分析
ss : [ebp - 0x11] 被初始化为0,然后分别拿[ebp - 0x7f],[ebp - 0x79],[ebp - 0x73]的数据给‘-’比较,
如果有一个数据不等于‘-’就让ss:[ebp - 0x11] = 1;(那么就会弹出序列号错误的窗口),所以这几个数据都得为 ‘-’
ebp -7f 等于0xBF47A1,我们在数据窗口中搜索查看其数据。
我们发现此缓冲区的数据为kkkkkkkkkkkkkkkk这不是我们输入的序列号吗!
我们对比了此缓冲区中的数据后发现,[ebp - 0x7f],[ebp - 0x79],[ebp - 0x73]分被为我们输入的序列号的第6, 12,18个字符
因为这个数据得等于‘-’ ,意思是我们输入的序列号得为kkkkk-kkkkk-kkkkk-kkkkk的形式。
所以我们运行程序重新输入序列号:“KKKKK-KKKKK-KKKKK-KKKKK”后F8运行到此处后接着往下分析。
其接着调用了IDMan.0060EEE0函数后,我们发现数据窗口中的我们输入的序列号的前五个字符被复制到缓冲区00BF47D0中
紧接着我们发现其又调用了三次IDMan.0060EEE0函数分别把我们输入的序列号的除了 ‘-’字符外所有的字符五个一组
复制到指定内存中,并以0结尾。
00529D29 |. 6A 05 push 0x5
00529D2B |. 8D55 B0 lea edx,[local.20]
00529D2E |. 51 push ecx
00529D2F |. 52 push edx
00529D30 |. E8 AB510E00 call IDMan.0060EEE0 ; 将序列号的前5个字符存到缓冲区edx中
00529D35 |. 8D45 82 lea eax,dword ptr ss:[ebp-0x7E]
00529D38 |. 6A 05 push 0x5
00529D3A |. 8D4D C4 lea ecx,[local.15]
00529D3D |. 50 push eax
00529D3E |. 51 push ecx
00529D3F |. E8 9C510E00 call IDMan.0060EEE0 ; 将序列号的7- 11个字符复制到缓冲区edx中
00529D44 |. 8D55 88 lea edx,[local.30]
00529D47 |. 6A 05 push 0x5
00529D49 |. 8D45 E0 lea eax,[local.8]
00529D4C |. 52 push edx
00529D4D |. 50 push eax
00529D4E |. E8 8D510E00 call IDMan.0060EEE0 ; 将序列号的13- 17个字符复制到缓冲区edx中
00529D53 |. 8D4D 8E lea ecx,dword ptr ss:[ebp-0x72]
00529D56 |. 6A 05 push 0x5
00529D58 |. 8D55 E8 lea edx,[local.6]
00529D5B |. 51 push ecx
00529D5C |. 52 push edx
00529D5D |. E8 7E510E00 call IDMan.0060EEE0 ; 将序列号的19- 23个字符复制到缓冲区edx中
00529D62 |. 33FF xor edi,edi
00529D64 |. 83C4 30 add esp,0x30
00529D67 |. C645 B5 00 mov byte ptr ss:[ebp-0x4B],0x0 ; 将其每一块字符都以0结尾
00529D6B |. C645 C9 00 mov byte ptr ss:[ebp-0x37],0x0
00529D6F |. C645 E5 00 mov byte ptr ss:[ebp-0x1B],0x0
00529D73 |. C645 ED 00 mov byte ptr ss:[ebp-0x13],0x0
其复制过后的查看数据窗口中的数据可以看到其在内存中的位置:
接着往下分析发现四处代码分别对这四处字符进行操作,并且有可能改变ss : [ebp - 0x11]中的数据,
第一处为:
其判断我们输入的序列号的第一组五个字符中是否含有缓冲区[0x7034dc]中36个字符中没有的字符,
如果有则ss:[ebp - 0x11]为1(将会弹出序列号错误的窗口)。并且其会根据此算法计算出一个值存在[local.12]中
第二处,第三处,第四处的代码的算法逻辑和此第一处一样,只不过第二处,第三处,第四处计算出的值分别存在[local.10], ebx, edi中
所以我们得知要想让ss:[ebp - 0x11]的值不为1,我们输入的序列号中的字符都应该是
0x7034dc地址处大小为36的数组中有的字符。
我们在数据窗口中查看0x7034dc地址处的数据为: 26个大写的英语字母和0-9的数字
意思是我们的序列号只能是这些字符组成的。
我们接着往下F8分析!又发现了可能会改变ss:[ebp - 0x11]数据的代码
此代码时分被用刚刚的四处算法逻辑所产生的值(即[local.12], [local.10], ebx, edi)分别除以0x2b,0x17,0x11, 0x35
其产生的余数必须都为0才能使ss:[ebp - 0x11]处的数据不为1
只有上述条件都满足了才能使ss:[ebp - 0x11]为0,编写程序得出一个能满足以上条件的序列号
为:52F2G-XPVV4-0WTJ3-A2TCU
然后我们重新运行并输入此序列号,F8来到此处后继续往下运行发现弹出注册成功窗口。
打开程序点击关于发现程序已经注册成功!
下面我写的注册机比较low,运行一次生成一个序列号
#include <iostream>
#include <time.h>
using namespace std;
int main()
{
char str[36] = { '2', 'Y', 'O', 'P', 'B', '3', 'A',
'Q', 'C', 'V', 'U', 'X', 'M', 'N',
'R', 'S', '9', '7', 'W', 'E', '0',
'I', 'Z', 'D', '4', 'K', 'L', 'F',
'G', 'H', 'J', '8', '1', '6', '5', 'T'};
int eax = 0;
int ecx = 0xFFFFFFFF;
int esi = 0;
int edi = 0;
int a[4];
char dl[21];
char* str1 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
srand((unsigned int) time(0));
while(1)
{
for(int x = 0; x < 20; x++)
dl[x] = str1[rand() % 36];
for(int ii = 0; ii <= 3; ii++)
{
esi = 0;
edi = 0;
for(int i = ii*5; i <= ii* 5 + 4; i++)
{
eax = 0;
ecx = 0xffffffff;
while(1)
{
if(eax < 36)
{
if( str[eax] == dl)
{
ecx = eax;
if(ecx != 0xffffffff)
{
eax = edi * 9;
ecx = ecx + edi;
esi++;
edi = ecx + eax * 4;
a[ii] = edi;
break;
}
}
eax++;
}
else if(eax >= 36)
if(ecx != 0xffffffff)
{
eax = edi * 9;
ecx = ecx + edi;
esi++;
edi = ecx + eax * 4;
a[ii] = edi;
break;
}
}
}
}
if(0 == a[0] % 0x2B && 0 == a[1] % 0x17 && 0 == a[2] % 0x11 && 0 == a[3] % 0x35)
break;
}
for(int i = 0; i <= 19; i++)
cout<<dl;
cout<<endl;
return 0;
}