好友
阅读权限 30
听众
最后登录 1970-1-1
本帖最后由 pk8900 于 2017-12-17 11:44 编辑
今天,继续研究 了【适合破解 新手的160个crackme练手】,本文内容为第48个CrackMe: DueList.3.exe ,论坛没有关于这个CrackMe的帖子,于是写了这篇帖子,分享一下我的分析过程及 注册机 编写方法,总体来说写注册机比分析过程更难一些(因为我的编程水平不咋的)。
【crackme简介】
下载地址: http://pan.baidu.com/share/link?shareid=541269&uk=4146939145
MASM32 / TASM32编写,无壳,是一个 选择框式 验证方式,打开有两排选择框,一排9个,共十八个,有Check按钮和Close按钮。
分析工具:X64dbg, PE Explorer 注册机编写:VS2013
【crackme截图】
【算法分析过程】
这个难度不太大,按星级估计算是1星的吧,点击Check按钮,有提示文字:"Your registration info is invalid... Please support shareware authors by buying software!",有字符串,从这里入手直接有效。通过搜索字符串,定位到程序关键代码位置:
[Asm] 纯文本查看 复制代码
00401127 | 0F BE 8E FE 20 40 00 | movsx ecx, byte ptr ds:[esi+0x4020FE] | 0x4020FE地址18个字节值为18个复选框对应的值
0040112E | 83 F9 4D | cmp ecx, 0x4D | 4D:'M' 最后一个复选框之后的值,用来检测结束
00401131 | 74 2F | je duelis.401162 |
00401133 | 89 0D 5E 21 40 00 | mov dword ptr ds:[0x40215E], ecx | [0x0040215E] 保存当前字节值
00401139 | 51 | push ecx | int nIDButton
0040113A | FF 75 08 | push dword ptr ss:[ebp+0x8] | HANDLE hDlg
0040113D | E8 D0 01 00 00 | call <duelis.IsDlgButtonChecked> | IsDlgButtonChecked 复选框状态
00401142 | 46 | inc esi |
00401143 | 83 F8 00 | cmp eax, 0x0 | 判断复选框状态
00401146 | 74 DF | je duelis.401127 | 未选中 下一个
00401148 | A1 5E 21 40 00 | mov eax, dword ptr ds:[0x40215E] | EAX=当前复选框的值
0040114D | 0F BE 8E FE 20 40 00 | movsx ecx, byte ptr ds:[esi+0x4020FE] | ECX下一个复选框的值
00401154 | 0F AF C1 | imul eax, ecx | EAX*ECX
00401157 | 0F AF C6 | imul eax, esi | EAX*计数器N
0040115A | 01 05 62 21 40 00 | add dword ptr ds:[0x402162], eax | 结果累加至402162
00401160 | EB C5 | jmp duelis.401127 |
00401162 | A1 62 21 40 00 | mov eax, dword ptr ds:[0x402162] |
00401167 | 6B C0 4D | imul eax, eax, 0x4D | 402162值*0x4D
0040116A | 3D 66 54 F3 00 | cmp eax, 0xF35466 | 与:0xF35466比较,相同则成功
0040116F | 75 20 | jne duelis.401191 |
00401171 | 68 00 20 00 00 | push 0x2000 |
00401176 | 68 01 20 40 00 | push duelis.402001 | 402001:"Duelist's Crackme #3"
0040117B | 68 17 20 40 00 | push duelis.402017 | 402017:"Congratulations! Please send a screenshot of your solution to [url=mailto:duelist@beer.com]duelist@beer.com[/url]!"
00401180 | 6A 00 | push 0x0 |
00401182 | E8 55 01 00 00 | call <duelis.MessageBoxA> |
00401187 | B8 01 00 00 00 | mov eax, 0x1 |
0040118C | E9 69 FF FF FF | jmp duelis.4010FA |
00401191 | 68 00 20 00 00 | push 0x2000 |
00401196 | 68 01 20 40 00 | push duelis.402001 | 402001:"Duelist's Crackme #3"
0040119B | 68 68 20 40 00 | push duelis.402068 | 402068:"Your registration info is invalid... Please support shareware authors by buying software!"
004011A0 | 6A 00 | push 0x0 |
004011A2 | E8 35 01 00 00 | call <duelis.MessageBoxA> |
004011A7 | B8 00 00 00 00 | mov eax, 0x0 |
004011AC | E9 49 FF FF FF | jmp duelis.4010FA |
代码很简短,经过跟踪分析,注册的算法为:
程序的18个复选框,分别对应内存中18个连续的字节值(实际上是复选框的ID),后面还有一个为4D:'M',用来累加计算和判断循环结束,依次为:{
0x16, 0x49, 0x5E, 0x15, 0x27, 0x26, 0x21, 0x25, 0x1D, 0x59, 0x53, 0x37, 0x31, 0x48, 0x5D, 0x0C, 0x61, 0x52, 0x4D};,从第一个复选框开始,[0x0040215E] 保存当前字节值,若选中,则用当前字节值*下一个字节值再*当位位置,乘积累加至402162,若没选中,继续下一个。最后的累加值402162*0x4D后与0xF35466比较,相同则成功。
程序右边标签提示:"You should use a resource editor!",意思是你需要一个资源修改器,我最开始没有明白为什么需要,在注册机写完以后,验证却没通过时,才明白,界面上的复选框并不和内存中那串复选框ID中 相对应,确实需要一个工具来查看复选框的ID,我使用的是PE Explorer,查看过程看下图:
【注册机编写过程】
算法过程很简单,但注册机不太好写,这应该算是一个组合的问题,反推最终比较结果:0xF35466除0x4D=0x328FE,接下来分别计算每个复选框对应的累加值即check[n]*check[n+1]*n,接下来的组合情况,我用了递归方法来穷举可能的组合。
C++代码如下:
[C++] 纯文本查看 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include <vector>
using namespace std;
void print(vector<int> &tmp) //打印验证成功的结果
{
int y = 0;
for (vector<int>::iterator x = tmp.begin(); x < tmp.end(); x++)
{
if (y == 9)
{
cout << endl;
y = 0;
}
y++;
cout << *x << " ";
}
cout<< endl << "-------------------------------------------------------" << endl;
}
void calc(const vector<int> v, vector<int> base, int x_begin, int x_end, long src_value)
{
vector<int> tmp(base);
long end_v = src_value;
for (int x = x_begin; x < x_end; x++)
{
for (int y = 0; y <= 1; y++)
{
tmp[x] = y;
if (y==1)
end_v = end_v - v[x];
if (end_v == 0)
{
print(tmp); //打印成功结果
break;
}
if (end_v < 0)
break;
if (end_v > 0 && x+1<x_end)
calc(v, tmp, x + 1, x_end, end_v); //进行递归循环
}
}
}
int main()
{
//代码运行中的控件值顺序
int Check_value[] = {0x16, 0x49, 0x5E, 0x15, 0x27, 0x26, 0x21, 0x25, 0x1D, 0x59, 0x53, 0x37, 0x31, 0x48, 0x5D, 0x0C,0x61, 0x52, 0x4D};
//代码运行中的控件值顺序
int value_D[] = {0x16, 0x49, 0x5E, 0x15, 0x27, 0x26, 0x21, 0x25, 0x1D, 0x59, 0x53, 0x37, 0x31, 0x48, 0x5D, 0x0C,0x61, 0x52, 0x4D};
//界面上的控件位置
int value_J[] = {97,73,94,22,37,38,33,89,83,21,55,49,72,93,12,82,39,29, 0x4D };
vector<int> check(18,0);
long end_value = 0x328FE; //最终比较值
for (int x = 0; x < 18; x++)
{ //计算出每个复选框对应的值
Check_value[x] *= Check_value[x + 1];
Check_value[x] *= (x + 1);
}
vector <int> v_value(18,0);
for (int x = 0; x < 18; x++) //按实际位置 重新排序控件值
for (int y = 0; y < 18; y++)
{
if (value_J[x] == value_D[y])
v_value[x] = Check_value[y];
}
calc(v_value, check, 0, 18, end_value);
cout << "calc is over!" << endl;
system("pause");
}
最后附上成功通过的截图:
欢迎大家回贴交流。
免费评分
查看全部评分