本帖最后由 pk8900 于 2018-3-10 12:15 编辑
经过半年多的断断续续的研究 【适合破解新手的160个crackme练手】已经进行到第154个,还有几个就要进行完了,今天把这个Crackme的算法分析写一下,因为论坛里没有搜索到详细分析的帖子。
【crackme简介】
下载地址1:https://pan.baidu.com/s/1cySNkj9uENG_ppK80BmjUQ 密码:8d77
MASM32 / TASM32编写,无壳,点击help菜单下Register,是一个Name+Code验证方式,界面两个文本框,OK按钮和Cancel按钮。【初试】在Crackme中输入任意用户名和序列号,点OK按钮,没有反应,估计只能正确时才会有提示。
分析工具:IDA + X64dbg,注册机编写:VS2013
【crackme截图】
【算法分析过程】
X64dbg中载入,搜索字符串,发现:" C00L !! U found a correct Serial ! =)\n\r Tell Me how by e-mail to : Phrozen_q@cyberdude.com ",转到代码位置,发现如下代码:
[Asm] 纯文本查看 复制代码 004012C9 | E8 52 01 00 00 | call <the_q..GetDlgItem> |
004012CE | 68 A9 21 40 00 | push the_q..4021A9 |
004012D3 | 6A 28 | push 0x28 |
004012D5 | 6A 0D | push 0xD |
004012D7 | 50 | push eax |
004012D8 | E8 73 01 00 00 | call <the_q..SendMessageA> |
004012DD | A2 D1 21 40 00 | mov byte ptr ds:[0x4021D1], al |
004012E2 | 3C 00 | cmp al, 0x0 |
004012E4 | 74 67 | je the_q..40134D |
004012E6 | 90 | nop |
004012E7 | 90 | nop |
004012E8 | 90 | nop |
004012E9 | 90 | nop |
004012EA | 3C 08 | cmp al, 0x8 |
004012EC | 73 09 | jae the_q..4012F7 |
004012EE | 90 | nop |
004012EF | 90 | nop |
004012F0 | 90 | nop |
004012F1 | 90 | nop |
004012F2 | E8 5F 00 00 00 | call <the_q..sub_401356> |
004012F7 | 6A 00 | push 0x0 |
004012F9 | 6A 00 | push 0x0 |
004012FB | 6A 66 | push 0x66 |
004012FD | FF 75 08 | push dword ptr ss:[ebp+0x8] |
00401300 | E8 21 01 00 00 | call <the_q..GetDlgItemInt> |
00401305 | A3 D2 21 40 00 | mov dword ptr ds:[0x4021D2], eax |
0040130A | 3C 00 | cmp al, 0x0 |
0040130C | 74 3F | je the_q..40134D |
0040130E | 90 | nop |
0040130F | 90 | nop |
00401310 | 90 | nop |
00401311 | 90 | nop |
00401312 | E8 5E 00 00 00 | call <the_q..sub_401375> |
00401317 | E8 A5 00 00 00 | call <the_q..sub_4013C1> |
0040131C | 85 C0 | test eax, eax |
0040131E | 74 2D | je the_q..40134D |
00401320 | 90 | nop |
00401321 | 90 | nop |
00401322 | 90 | nop |
00401323 | 90 | nop |
00401324 | 6A 00 | push 0x0 |
00401326 | 68 9F 21 40 00 | push the_q..40219F | 40219F:"Correct !"
0040132B | 68 3A 21 40 00 | push the_q..40213A | 40213A:" C00L !! U found a correct Serial ! =)\n\r Tell Me how by e-mail to : [url=mailto:Phrozen_q@cyberdude.com]Phrozen_q@cyberdude.com[/url] "
00401330 | FF 75 08 | push dword ptr ss:[ebp+0x8] |
00401333 | E8 06 01 00 00 | call <the_q..MessageBoxA> |
程序调用:GetDlgItem和SendMessageA获取Name框文本内容,调用GetDlgItemInt获取Code框输入的数值,输入任意Name和Code后,进行跟踪,发现在上段代码中:
一、sub_401356子程序对输入的Name长度小于8的话,则在用户名后追加字符0,1,2......到Name长度为8终止。
二、sub_401375子程序对输入的Name进行加密操作处理,流程为:第一字符累加第8字符,第二字符累加第7字符,第三字符累加第6字符,第4字符累加第5字符,然后用累加完的1-4字符复制到5-8字符,最后将1-8字符分别与"PhroZenQ"字符异或,加密过程完成。
[C++] 纯文本查看 复制代码 void sub_401375( char * yourname)
{
for (int x = 0; x < 4; x++)
{
yourname[x] += yourname[7 - x];
}
for (int x = 4; x < 8; x++)
{
yourname[x] = yourname[x - 4];
}
char * s1 = "PhroZenQ";
for (int x = 0; x < 8; x++)
{
yourname[x] ^= s1[x];
}
}
三、sub_4013C1是验证子程序,验证流程如下图:
通过上图验证流程,进行注册机的反推,将Name值加密后分组,应使P1和P2的值相等,P2的值是由Key1循环右移P1的低8位值得来,也就是说P2的值(Key1循环右移X次后),值等于P1,即P2的低8位值一定是X,否则无法实现P1=P2,通过比较X的值,匹配后再进一步算出Code,如果从00-0FF都匹配不上,则该Name无法成功算出Code。
根据分析结果,注册机实现如下:
[C++] 纯文本查看 复制代码 #include<iostream>
using namespace std;
void sub_401375( char * yourname)//用户名加密处理
{
for (int x = 0; x < 4; x++)
{
yourname[x] += yourname[7 - x];
}
for (int x = 4; x < 8; x++)
{
yourname[x] = yourname[x - 4];
}
char * s1 = "PhroZenQ";
for (int x = 0; x < 8; x++)
{
yourname[x] ^= s1[x];
}
}
long ror(unsigned long a1, int x1)//循环右移x1次
{
unsigned long ret = a1;
long a2 = 0;
for (int x = 0; x < x1; x++)
{
a2 = (ret & 1) << 31;
ret = ((ret & 1) << 31) | (ret >> 1);
}
return ret;
}
long rol(unsigned long a1, int x1)//循环左移x1次
{
unsigned long ret = a1;
for (int x = 0; x < x1; x++)
{
ret = ((ret & 0x80000000) >>31) + (ret << 1);
}
return ret;
}
void main()
{
char * Enter_yourname = new char[260];
memset(Enter_yourname, 0, 260);
cout << "Enter your name:";
gets_s(Enter_yourname, 260);
char s1 = 0x30;
int a;
while (strlen(Enter_yourname) < 8)
{
a = strlen(Enter_yourname);
Enter_yourname[a] = s1;
Enter_yourname[a+1] = 0;
s1++;
}
cout << Enter_yourname << endl;
sub_401375(Enter_yourname);
// cout << "Enter your serial:";//原程序流程部分
unsigned long serial;
//cin >> serial;//原程序流程部分
unsigned long * key1 = (unsigned long *)&Enter_yourname[1];
unsigned long * key2 = (unsigned long *)&Enter_yourname[5];
// unsigned long k1 = rol(serial, Enter_yourname[0] & 0xFF) ^ *key2;//原程序流程部分
// unsigned long k2 = ror(*key1, k1 & 0xff);//原程序流程部分
//cout << hex << uppercase << k1 << " " << k2 << endl;//原程序流程部分
unsigned long tmp=0,tmp1=0;
unsigned long the_key = 0;
for (int x = 0; x <= 255; x++)
{
tmp = ror(*key1, x);
if ((tmp & 0xFF) == x) //判断低8位值是否等于X,若相等则进一步反推,得出CODE值
{
tmp ^= *key2;
the_key = ror(tmp, Enter_yourname[0] & 0xFF);
break;
}
}
if (the_key != 0)
cout << "your serial is:" << the_key << endl;
else
cout << "not found serial!" << endl;
cout<<"auto head...hello!"<<endl;
system("pause");
}
通过注册机测试,并不是所有的name都能得到CODE,能通过的用户名有:PhroZenQ,P......
52pojie,52pojie.cn,O等
提供两组测试:name:52pojie.cn Code:3679130504 name:PhroZenQ Code:3793889001
注册成功截图如下:
程序Name长度有效位数为9位,多余部分不参与加密与验证。
整个分析过程完成,如有不对的地方还请路过的大神指正。
|