好友
阅读权限30
听众
最后登录1970-1-1
|
本帖最后由 pk8900 于 2017-6-22 01:15 编辑
【程序说明】160个Crackme之011-Andrénalin.4,VB 5.0,无壳。
【下载地址:】http://pan.baidu.com/share/link?shareid=541269&uk=4146939145
最近几天学C++学的头晕转向,于是继续进行160个Crackme系列,这个Andrénalin的系列Crackme还真是不好弄,前面几个研究完收获不小,尤其是自己仿写了些代码,反汇编研究,下面就这个Andrénalin.4,给大家详细介绍一下我的分析过程和心得。
Crackme界面如下 :
一些数字键,*、#,<-(退格键),点任意数字键钮,上方文本框中显示字符,同时退格键亮起。右侧有"UNREGISTRIERT"字样,输入正确字符串后,会显示"REGISTRIERT"字样。搜索程序字符串资源,会发现有很多的字串及"REGISTRIERT"
这说明程序采用的是Native Code编码方式,VB编写的应用程序有两种编译方式,一种是Native code方式,另一种是P-code方式,P-code方式程序是搜索不到字符串的。因为P-code方式程序的字节码是运行的时候由msvbvm50.dll和msvbvm60.dll解释执行,所以调试的时候往往会断在msvbvm50.dll和msvbvm60.dll的领空。这个程序爆破起来很容易,因为"REGISTRIERT"字样到处都是,修改之前的跳转,就能达到目的,而我要研究的是程序的算法,所以要进行跟踪,顺着"REGISTRIERT"上找,跟了半天,大致的明白了一点程序的验证流程,但一想到字符串搜索里那若干的REGISTRIERT"和长字符串,就有种不安的感觉,会不会掉到作者挖的坑里了。还是用VB Decompiler Pro反编译看看吧,随便说一下,VB程序反编译,对于分析破解VB程序非常重要,因为VB程序用OD分析,如果代码长,你跟踪变量都会跟丢了。
反编译程序果然发现很多信息:
程序只有一个窗体,但有4个Timer控件,每个控件的周期为1毫秒,而所有的验证代码都在Timer事件中。每个事件中有15段代码,内容大至雷同。
通过对其中一段代码进行分析:
loc_00406CAD: For var_24 = 1 To Len(var_44) Step 1 循环读取字符输入字符
loc_00406CBF:
loc_00406CC1: If var_F8 = 0 Then GoTo loc_00406DF0 若当前为0跳到验证部分
loc_00406CDB: var_50 = CStr(Left(var_44, 1)) ;取左第一个字母
loc_00406D2D: var_304 = Asc(Mid$(CStr(var_44), CLng(var_24), 1)) 取当前字母ASC值
loc_00406D72: var_8C = Hex$((var_30C + var_CC)) 加上一个数后(经后来分析是一个基数,由输入的数左取固定位转10进制数值得来 变量: var_CC)转为十六进制字符串,
loc_00406D9C: var_34 = var_34 & Hex$((var_30C + var_CC)) 累加字符串至变量
以上为大至分析结果,还看不出具体算法,于是用调试器跟踪,因为是时间事件,所以先取消所有断点,输好字符后,再至代码处下断,就会立即断下来。
X32dbg中分析流程:【注:反编译中的var_CC,就是调试器跟踪中的EBP-CC堆栈地址,可以锁定堆栈,把堆栈切换成+??或-??的EBP偏移,方便观察变量的值。】
[Asm] 纯文本查看 复制代码 00406EDC | 85 C0 | test eax,eax | 循环控制
00406EDE | 0F 84 29 01 00 00 | je 40700D |
00406EE4 | 8D 4D BC | lea ecx,dword ptr ss:[ebp-44] | ebp-44是输入的字符串,字符串实际为ebp-3c
00406EE7 | 6A 02 | push 2 | 2个
00406EE9 | 8D 55 8C | lea edx,dword ptr ss:[ebp-74] | ebp-74 结果返回地址,字符:ebp-6c
00406EEC | 51 | push ecx |
00406EED | 52 | push edx |
00406EEE | FF D3 | call ebx | msvbvm60.rtcLeftCharVar
00406EF0 | 8D 45 8C | lea eax,dword ptr ss:[ebp-74] | 返回的两个字符
00406EF3 | 8D 4D B0 | lea ecx,dword ptr ss:[ebp-50] | 结果保存地址
00406EF6 | 50 | push eax |
00406EF7 | 51 | push ecx |
00406EF8 | FF D6 | call esi | var_50 = CStr(Left(var_44, 2))
00406EFA | 50 | push eax |
00406EFB | FF 15 D8 10 40 00 | call dword ptr ds:[<&rtcR8ValFromBstr>] | 字符串转换成浮点数:st0中
00406F01 | DD 9D 34 FF FF FF | fstp qword ptr ss:[ebp-CC] | 数值传给变量ebp-cc *64位*
00406F07 | 8D 55 9C | lea edx,dword ptr ss:[ebp-64] |
00406F0A | 8D 45 DC | lea eax,dword ptr ss:[ebp-24] |
00406F0D | 52 | push edx |
00406F0E | 50 | push eax |
00406F0F | C7 45 A4 01 00 00 00 | mov dword ptr ss:[ebp-5C],1 |
00406F16 | C7 45 9C 02 00 00 00 | mov dword ptr ss:[ebp-64],2 |
00406F1D | FF 15 AC 10 40 00 | call dword ptr ds:[<&_vbaI4Var>] |
00406F23 | 8D 4D BC | lea ecx,dword ptr ss:[ebp-44] |
00406F26 | 50 | push eax |
00406F27 | 8D 55 B8 | lea edx,dword ptr ss:[ebp-48] |
00406F2A | 51 | push ecx |
00406F2B | 52 | push edx |
00406F2C | FF D6 | call esi |
00406F2E | 50 | push eax |
00406F2F | FF 15 4C 10 40 00 | call dword ptr ds:[<&rtcMidCharBstr>] | 循环取字符从1开始
00406F35 | 8B D0 | mov edx,eax |
00406F37 | 8D 4D B4 | lea ecx,dword ptr ss:[ebp-4C] |
00406F3A | FF 15 BC 10 40 00 | call dword ptr ds:[<&_vbaStrMove>] |
00406F40 | 50 | push eax |
00406F41 | FF 15 20 10 40 00 | call dword ptr ds:[<&rtcAnsiValueBstr>] | ASCLL值
00406F47 | 0F BF C0 | movsx eax,ax | 存入变量ebp-310中
00406F4A | 89 85 F0 FC FF FF | mov dword ptr ss:[ebp-310],eax | var_310 = Asc(Mid$(CStr(var_44), CLng(var_24), 1))
00406F50 | 8D 8D 7C FF FF FF | lea ecx,dword ptr ss:[ebp-84] |
00406F56 | DB 85 F0 FC FF FF | fild dword ptr ss:[ebp-310] | 入栈 st0
00406F5C | 51 | push ecx |
00406F5D | C7 85 7C FF FF FF 05 | mov dword ptr ss:[ebp-84],5 |
00406F67 | DD 9D E8 FC FF FF | fstp qword ptr ss:[ebp-318] | 转化精度,给变量EBP-318
00406F6D | DD 85 E8 FC FF FF | fld qword ptr ss:[ebp-318] |
00406F73 | DC 85 34 FF FF FF | fadd qword ptr ss:[ebp-CC] | 加ebp-cc 前面转化来的数值
00406F79 | DD 5D 84 | fstp qword ptr ss:[ebp-7C] | 存入ebp-7c
00406F7C | DF E0 | fnstsw ax | 以下为较验运算,是否出错。
00406F7E | A8 0D | test al,D |
00406F80 | 0F 85 D6 1D 00 00 | jne 408D5C |
00406F86 | FF 15 94 10 40 00 | call dword ptr ds:[<&rtcHexBstrFromVar>] | 十六进制转字符:给变量ebp-8c
00406F8C | 89 85 74 FF FF FF | mov dword ptr ss:[ebp-8C],eax | var_8C = Hex$((var_318 + var_CC))
00406F92 | 8D 55 CC | lea edx,dword ptr ss:[ebp-34] | 十六进制转的字符串
00406F95 | 8D 85 6C FF FF FF | lea eax,dword ptr ss:[ebp-94] |
00406F9B | 52 | push edx |
00406F9C | 8D 8D 5C FF FF FF | lea ecx,dword ptr ss:[ebp-A4] | 累加连接的字符串
00406FA2 | 50 | push eax |
00406FA3 | 51 | push ecx |
00406FA4 | C7 85 6C FF FF FF 08 | mov dword ptr ss:[ebp-94],8 |
00406FAE | FF 15 84 10 40 00 | call dword ptr ds:[<&_vbaVarCat>] | 连接字符串
00406FB4 | 8B D0 | mov edx,eax |
00406FB6 | 8D 4D CC | lea ecx,dword ptr ss:[ebp-34] |
00406FB9 | FF D7 | call edi |
00406FBB | 8D 55 B0 | lea edx,dword ptr ss:[ebp-50] |
00406FBE | 8D 45 B4 | lea eax,dword ptr ss:[ebp-4C] |
00406FC1 | 52 | push edx |
00406FC2 | 8D 4D B8 | lea ecx,dword ptr ss:[ebp-48] |
00406FC5 | 50 | push eax |
00406FC6 | 51 | push ecx |
00406FC7 | 6A 03 | push 3 |
00406FC9 | FF 15 9C 10 40 00 | call dword ptr ds:[<&_vbaFreeStrList>] |
00406FCF | 8D 95 6C FF FF FF | lea edx,dword ptr ss:[ebp-94] |
00406FD5 | 8D 85 7C FF FF FF | lea eax,dword ptr ss:[ebp-84] |
00406FDB | 52 | push edx |
00406FDC | 8D 4D 8C | lea ecx,dword ptr ss:[ebp-74] |
00406FDF | 50 | push eax |
00406FE0 | 8D 55 9C | lea edx,dword ptr ss:[ebp-64] |
00406FE3 | 51 | push ecx |
00406FE4 | 52 | push edx |
00406FE5 | 6A 04 | push 4 |
00406FE7 | FF 15 14 10 40 00 | call dword ptr ds:[<&_vbaFreeVarList>] |
00406FED | 83 C4 24 | add esp,24 |
00406FF0 | 8D 85 E8 FE FF FF | lea eax,dword ptr ss:[ebp-118] |
00406FF6 | 50 | push eax |
00406FF7 | 8D 8D F8 FE FF FF | lea ecx,dword ptr ss:[ebp-108] |
00406FFD | 8D 55 DC | lea edx,dword ptr ss:[ebp-24] |
00407000 | 51 | push ecx |
00407001 | 52 | push edx |
00407002 | FF 15 C8 10 40 00 | call dword ptr ds:[<&_vbaVarForNext>] |
00407008 | E9 CF FE FF FF | jmp 406EDC |
0040700D | 8D 45 CC | lea eax,dword ptr ss:[ebp-34] |
00407010 | 8D 8D 4C FF FF FF | lea ecx,dword ptr ss:[ebp-B4] |
00407016 | 50 | push eax |
00407017 | 51 | push ecx |
00407018 | C7 85 54 FF FF FF E8 | mov dword ptr ss:[ebp-AC],401EE8 | 401EE8:L"0817E747D7A7D7C7F82836D74747A7F7E7G7C7D826D817E7B7C"
00407022 | C7 85 4C FF FF FF 08 | mov dword ptr ss:[ebp-B4],8008 |
0040702C | FF 15 5C 10 40 00 | call dword ptr ds:[<&_vbaVarTstEq>] | 比较字符串,进行验证
通过OD的跟踪分析,已明子软件的算法,具体算法为:从左取用户输入的字符串N位(1-8位),转为十进制数值。用的就是VB中的Val函数,转字符转 10进度数字,*、#则中断,如:VAL(“789”)--- 789 ;VAL(“078*#89”)---- 78 这个值是基数,加上第一个字符的ASC值,两值之和,转为16进制字符,依此类推:第2个字符ASC 加78,转十六进制字符追加后面,直到输入的全部字符,就会得到一个长的十六进制字符串,这里没弄明白的是最前面的字符“0”,在vbaVarCat调用中没发现读取,但在生成后最前加了一个“0”字符,面只有第一次才加。
知道了算法,接下来就是研究做个注册机,分析了一下程序里的字符串,只有这一组:
2 (左取字符为2个)0817E747D7A7D7C7F82836D74747A7F7E7B7C7D826D817E7B7C
全是由十六进制字符,于是用刚学一半的C++试着编了一个算法:
[C++] 纯文本查看 复制代码 #include <iostream>
#include <sstream>
using namespace std;
string kb="0123456789*#";
int kb_dec[]={48,49,50,51,52,53,54,55,56,57,42,35};
int kb_hex[]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
string hexlist="0123456789ABCDEF";
int key_num=2;
string key="0817E747D7A7D7C7F82836D74747A7F7E7B7C7D826D817E7B7C";
int hexstr_to_dec(const string s) //转16进制两位字符到十进制数
{
int a,b;
a=hexlist.find(s[0]);
b=hexlist.find(s[1]);
return a*16+b;
}
void main()
{
int key_value;
int base_value;
string psword;
char p;
string key_str=key.substr(1,2); //取Key的二、三位
key_value=hexstr_to_dec(key_str);
for(int x=1;x<=9;x++) //确定公共值base_value
{
for(int y=0;y<=9;y++)
{
if (y+x*10+kb_dec[x]==key_value)
{
base_value=x*10+y;
break;
}
}
}
cout<<"公共值:"<<base_value<<endl;
for(int x=1;x<key.length();x+=2) /*计算 注册码 部分*/
{
key_str=key.substr(x,2);
key_value=hexstr_to_dec(key_str);
p=(char)(key_value-base_value);
psword=psword+p;
}
cout<<"password:"<<psword<<endl;
system("pause");
至此分析完成,我还用C++写了一个更长的程序,不用穷举的方法计算取1-8位时验证计算,因为刚学的原因,程序最终还是不完善,程序乱的没法贴上来。
【想法】:VB Decompiler分析得不错,可惜没写过OD或X64DBG的插件,等有时间找点资料学一学,把VB Decompiler分析内容加到调试器里,分析起来就方便多了。 |
免费评分
-
查看全部评分
|