新手破解练习Crackme160之091 - crueme
-
去NAG
程序一运行就有个密钥文件验证提示框, 我们可以先跳过~, OD载入程序一眼就看到了文件读取并弹框的代码, 前面这些代码看, 并没有对文件进行校验, 所以我们可以直接创建一个CRUEME.DAT的空文件, 也可以将00401065处的jnz改为jmp, 达到跳过提示框的操作~
-
暴力破解
搜索关键字"False password - Try again" 定位到 004012DE, 将push 0x402254 改为 push 0x402236 失败的字符串改成成功的字符串, 保存搞定~
-
正常破解
在004012DE上面看到了004012BE处 user32.GetDlgItemTextA, 下个断点, 看来下一行就是关键算法了, 进入方法
1). 判断是不是8位, 不是的话, 置空8位并返回失败(eax=0)
2). 我们输入8位abc12345来验证,
3). 每一位循环与0x50异或, 得123abcde
4). 再将结果每一位循环加上循环变量(倒序), 得999fffff
5). 结果再每2位异或得005F0000(开)
6). 得到的4位再分别两位异或结果再异或得到最后一位((00^5F) ^ (00^00))=5F
7). 结果如果是0则返回失败
8). 取出第4).步得到的结果999fffff, 循环异或6).步的结果5F, 得fff99999
9). fff99999 与固定串 "???罾... 异或得 D軺???...
10). 与固定串 籇3酞U"?? 对比, 如果不相等失败退出, 相等则成功退出
退出算法方法, 来到004012C7关键跳, 进入成功分支后又马上进入到失败分支了~ 这个有点懵了, 这是不是说明显上面的算法是没用的?
看着好像没办法了~ 从头再看一下代码, 发现有个方法到处都是, 它就是 call dword ptr ds:[0x402364] , 我们进入这个方法看下(对应行上按Enter键即可进入方法), 方法入口下个断点,
重新按check按钮, 看是否会进这个方法, 果然 还是有进来~ 看到这个方法后面有非常多的系统方法的调用~ 看来这个方法是一个公共方法, 单步跟踪每次进入这个方法与退出这个方法回到的地方, 最终可以知道按验证按钮后, 第一个调用这个方法的系统方法是<jmp.&USER32.SendDlgItemMessageA>, 返回到00401239, 这行又是一个方法call 00401B73, 我们进入方法看下, 看到是一堆的加减乘除运算, 嗯~ 还有0xFF * 0xFF次的循环(65025次), 代码如下:
00401B73 . 33FF xor edi,edi
00401B75 . 33F6 xor esi,esi
00401B77 . 85C0 test eax,eax
00401B79 . 0F84 0F010000 je crueme.00401C8E
00401B7F . A3 72214000 mov dword ptr ds:[0x402172],eax
00401B84 . BB 1D214000 mov ebx,crueme.0040211D ; 输入串
00401B89 > B9 FF000000 mov ecx,0xFF ; 第一层循环
00401B8E > 8B03 mov eax,dword ptr ds:[ebx] ; 第二层循环
00401B90 . 05 87D61200 add eax,0x12D687
00401B95 . 0343 08 add eax,dword ptr ds:[ebx+0x8]
00401B98 . 2D 672B0000 sub eax,0x2B67
00401B9D . 33D2 xor edx,edx
00401B9F . F725 72214000 mul dword ptr ds:[0x402172]
00401BA5 . 8B53 04 mov edx,dword ptr ds:[ebx+0x4]
00401BA8 . 81C2 EAF48F04 add edx,0x48FF4EA
00401BAE . 33C2 xor eax,edx
00401BB0 . 8B53 08 mov edx,dword ptr ds:[ebx+0x8]
00401BB3 . 81EA 015CBC00 sub edx,0xBC5C01
00401BB9 . 2B13 sub edx,dword ptr ds:[ebx]
00401BBB . 81C2 672B0000 add edx,0x2B67
00401BC1 . 33C2 xor eax,edx
00401BC3 . 0D E2599302 or eax,0x29359E2
00401BC8 . 03F8 add edi,eax
00401BCA . 233D 62214000 and edi,dword ptr ds:[0x402162]
00401BD0 . 8B03 mov eax,dword ptr ds:[ebx]
00401BD2 . 2D 87D61200 sub eax,0x12D687
00401BD7 . 2B43 08 sub eax,dword ptr ds:[ebx+0x8]
00401BDA . 05 CE560000 add eax,0x56CE
00401BDF . 33D2 xor edx,edx
00401BE1 . F735 72214000 div dword ptr ds:[0x402172]
00401BE7 . 8B53 04 mov edx,dword ptr ds:[ebx+0x4]
00401BEA . 81EA EAF48F04 sub edx,0x48FF4EA
00401BF0 . 33C2 xor eax,edx
00401BF2 . 8B53 08 mov edx,dword ptr ds:[ebx+0x8]
00401BF5 . 81C2 015CBC00 add edx,0xBC5C01
00401BFB . 0313 add edx,dword ptr ds:[ebx]
00401BFD . 81EA CE560000 sub edx,0x56CE
00401C03 . 33C2 xor eax,edx
00401C05 . 25 E2599302 and eax,0x29359E2
00401C0A . 03F0 add esi,eax
00401C0C . 0B35 66214000 or esi,dword ptr ds:[0x402166]
00401C12 . E2 02 loopd short crueme.00401C16
00401C14 . EB 05 jmp short crueme.00401C1B
00401C16 >^ E9 73FFFFFF jmp crueme.00401B8E
00401C1B > 81C7 11090000 add edi,0x911
00401C21 . 81EE 11090000 sub esi,0x911
00401C27 . FE0D 33214000 dec byte ptr ds:[0x402133]
00401C2D . 803D 33214000>cmp byte ptr ds:[0x402133],0x0
00401C34 .^ 0F85 4FFFFFFF jnz crueme.00401B89
00401C3A . C605 33214000>mov byte ptr ds:[0x402133],0xFF
00401C41 . BB 1D214000 mov ebx,crueme.0040211D ; 输入串
00401C46 . B9 0E000000 mov ecx,0xE
00401C4B > C603 00 mov byte ptr ds:[ebx],0x0
00401C4E . 43 inc ebx ; crueme.0040211D
00401C4F .^ E2 FA loopd short crueme.00401C4B
00401C51 . 81C7 AFE3FDEF add edi,0xEFFDE3AF
00401C57 . 75 35 jnz short crueme.00401C8E
00401C59 . 81C6 238D94A4 add esi,0xA4948D23
00401C5F . 75 2D jnz short crueme.00401C8E
00401C61 . BE 2C224000 mov esi,crueme.0040222C ; for input
00401C66 . 83C6 0A add esi,0xA
00401C69 . BF 6F224000 mov edi,crueme.0040226F ; ASCII "Correct password - Good work!"
00401C6E . B9 1D000000 mov ecx,0x1D
00401C73 . F3:A4 rep movs byte ptr es:[edi],byte ptr ds:[esi]
00401C75 . 68 6F224000 push crueme.0040226F ; ASCII "Correct password - Good work!"
00401C7A . 68 F2030000 push 0x3F2
00401C7F . FF75 08 push dword ptr ss:[ebp+0x8]
00401C82 . B0 15 mov al,0x15
00401C84 . FF15 64234000 call dword ptr ds:[0x402364] ; crueme.00401493
00401C8A . 33C0 xor eax,eax
00401C8C . EB 05 jmp short crueme.00401C93
00401C8E > B8 01000000 mov eax,0x1
00401C93 > C3 retn
好家伙~ 这个肯定没办法逆运算了吧? 单步跟踪也没办法了, 这得跟踪到猴年马月去, 写个程序来暴破, 看是否能写出来, 代码中有几处是取注册码的4位, 8位的, 所以我们为了方便, 规定注册码为4位, 8位 或 12位, 先试下4位的, 看能否有答案,
接下来开始写代码, 分别对 1). 纯数字 2). 纯字母 3).字母+数字 4). 纯符号 5).符号+数字 6). 符号+字母 7).符号+数字+字母 来写暴破代码
经验证, 纯数字与纯字母, 纯符号都没有找到符合条件的, 符号+数字与没有,
符号+小写字母找到了很多, 例:
时间: 6.756秒, 注册码为: "*q`
时间: 6.757秒, 注册码为: "*q@
时间: 6.761秒, 注册码为: "*q (注意后面一个是空格)
时间: 21.779秒, 注册码为: "j"?
时间: 21.830秒, 注册码为: "j@*
时间: 21.835秒, 注册码为: "j@j
时间: 22.163秒, 注册码为: "jh}
时间: 22.248秒, 注册码为: "jp`
时间: 22.249秒, 注册码为: "jp@
时间: 22.254秒, 注册码为: "jp (注意后面一个是空格)
符号+大写字母找到了很多, 例:
时间: 6.597秒, 注册码为: "*A*
时间: 6.603秒, 注册码为: "*AJ
时间: 17.248秒, 注册码为: "B#?
时间: 17.672秒, 注册码为: "BS}
符号+大小写字母一起的也找到了很多(与上面去重后), 例: (没等全跑完, 后面时间太长了)
时间: 14.459秒, 注册码为: "*Aj
时间: 47.063秒, 注册码为: "j@J
符号+数字+字母(从上面测试可知这几个符号("*@}?#`)容易成功, 所以把它们放最前面去加快查找速度), 找到特别多, 例:
时间: 49.384秒, 注册码为: "2s@
时间: 49.385秒, 注册码为: "2s`
时间: 49.390秒, 注册码为: "2s (注意后面一个是空格)
时间: 49.560秒, 注册码为: "2C*
时间: 49.569秒, 注册码为: "2Cj
时间: 49.574秒, 注册码为: "2CJ
时间: 75.615秒, 注册码为: "j8*
时间: 75.624秒, 注册码为: "j8j
时间: 75.629秒, 注册码为: "j8J
得到正确的注册码后,验证成功~ 提示框也显示了"Correct password - Good work!", 程序就不会进入到上面那段没用的算法中了, 看关键代码,如下:
00401239 . E8 35090000 call crueme.00401B73 ;真正算法
0040123E . 50 push eax ;将验证结果存起来了,下面这段代码是没用了,作者用来迷惑我们的,看起来也像是算法
0040123F ? BF 01000000 mov edi,0x1
00401244 . E8 FD080000 call crueme.00401B46
00401249 . B9 08000000 mov ecx,0x8
0040124E . BF 85214000 mov edi,crueme.00402185
00401253 . BE 34214000 mov esi,crueme.00402134
00401258 > 8A07 mov al,byte ptr ds:[edi]
0040125A . 8A1E mov bl,byte ptr ds:[esi]
0040125C . 32C3 xor al,bl
0040125E . D0C0 rol al,1
00401260 . 8806 mov byte ptr ds:[esi],al
00401262 . 47 inc edi
00401263 . 46 inc esi
00401264 .^ E2 F2 loopd short crueme.00401258
00401266 . 58 pop eax ; crueme.0040123E 直到这里又把上面的存的结果取出来了
00401267 . 85C0 test eax,eax
00401269 . 0F84 84000000 je crueme.004012F3 ; 这边才是真正的关键跳, 失败就会进入最前面那段没用的假算法去
到此就算正常破解完成了, 4位以上的就不玩了, 4位都需要那么久时间才能暴破出来, 再长就没办法等了~
这里是暴破代码: keygen.c
#include <stdio.h>
#include <string.h>
#include <time.h>
int chk(char data[5]);
int genPassword(int index, int len, char * testPassword);
int main(int argc, char** argv) {
clock_t s = clock(), e;
char *data = "\"@*`?#~!$%^&()-+{}|:;'<>,./\\ abcdefghijklmnopqrstuvwxyz"; // "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; //"0123456789"; //这里的符号只验证的键盘上有的符号, 其它特殊符号就没考虑了
char rlt[5] = {0};
int ret = 1, len = strlen(data);
for(int i=0; i<len; i++){
rlt[0] = data[i];
for(int j=0; j<len; j++){
rlt[1] = data[j];
for(int k=0; k<len; k++){
rlt[2] = data[k];
for(int l=0; l<len; l++){
rlt[3] = data[l];
ret = chk(rlt);
//if(ret == 0) goto end; //只找一个
if(ret == 0){ //找所有
e = clock();
double t = ((double)(e - s)) / CLOCKS_PER_SEC;
printf("时间: %.3f秒, 注册码为: %s\n", t, rlt);
}
}
}
}
}
//genPassword(0, 4, rlt); //递归,300多秒才能出结果 "*A*
/*end:
if(ret == 0) printf("时间: %.5f秒, 注册码为: %s", t, rlt);
else */
e = clock();
double t = ((double)(e - s)) / CLOCKS_PER_SEC;
printf("时间: %.3f秒, 结束~", t);
getchar();getchar();
return 0;
}
int genPassword(int index, int len, char * testPassword){ //递归写法 从大佬那边复制来的
int ret = 1;
if(index == len){
//printf("%s,", testPassword);
ret = chk(testPassword);
if(ret == 0){
printf("注册码为: %s\n", testPassword);
return 0;
}
return 1;
}
for(int i=0x20; i<0x7F; i++) { //字符区域
testPassword[index] = (char)i;
ret = genPassword(index+1, len, testPassword);
if(ret == 0){
return 0;
}
}
return 1;
}
int chk(char* data){
long long eax = 0, edx = 0, edi = 0, esi = 0, tmp1 = 0, tmp2 = 0;
long d4 = 0;
for(int i=3; i>=0; i--){
d4 = d4 << 8;
d4 |= data[i];
}
eax = d4;
eax += 0x12D687;
eax += 0; //因为4位,所以8位后的4位地址是0
eax -= 0x2B67;
edx = 0;
eax *= 4; //长度是4位
edx = 0; //取4位后的4位,也是0
edx += 0x48FF4EA;
eax ^= edx;
edx = 0; //取8位后的4位地址 0
edx -= 0xBC5C01;
edx -= d4;
edx += 0x2B67;
eax ^= edx;
eax |= 0x29359E2;
tmp1 = eax;
eax = d4;
eax -= 0x12D687;
eax -= 0; //8位后0
eax += 0x56CE;
edx = 0;
edx = eax % 4;
eax /= 4; //长度4
edx = 0; //4位后0
edx -= 0x48FF4EA;
eax ^= edx;
edx = 0; //8位后0
edx += 0xBC5C01;
edx += d4;
edx -= 0x56CE;
eax ^= edx;
eax &= 0x29359E2;
tmp2 = eax;
for(int i=0; i<0xFF; i++){
for(int j=0; j<0xFF; j++){
edi += tmp1;
edi &= 0x15263748;
esi += tmp2;
esi |= 0x596A7B8C;
}
edi += 0x911;
esi -= 0x911;
}
edi += 0xEFFDE3AF;
esi += 0xA4948D23;
edi &= 0xFFFFFFFF;
esi &= 0xFFFFFFFF;
if(edi > 0 || esi > 0) return 1;
return 0;
}
1~160每个破解过程,在吾爱破解论坛都有高手破解过了,也有整理好现成的, 我这边主要就是自己动手操作的过程,与他们的不太一样
附上高手们的连接: 点击前往查看
使用的工具连接(工具有点多有点大,可以先下OD,其它的后面慢慢下) 点击前往下载
新人入门教程"玩玩破解,写给新人看" 点击前往查看
我就是从这里开始的,对我这样的小白感觉超级友好~
下面是我的OD的界面布局,我觉得这4个是最常用的界面,其它的我基本上没用到~


浙公网安备 33010602011771号