-
-
[原创]第5题算法分析
-
2017-6-10 11:58 2816
-
破解工具:OD,IDA,Python
在WinXP虚拟机中直接用OD载入CrackMe.exe,查看字符串参考,有明显提示“驱动释放失败,\n请在xp平台中重新运行crackme”,有驱动。
先不管驱动,继续往下跟,在00401593 call 00401AA0处加载驱动,加载成功后在004015CA call dword ptr [<&KERNEL32.DeleteFileA>]删除驱动文件,在004015D4 call 00402250里间隔100ms建立5个004022A0的进程,进程作用是每3000ms与驱动通信一次。
字符串参考里0042D16C处的字符串"888aeda4ab"看起来很可疑,到该段函数的第一行00401760下断,跳过建立进程代码运行后,输入注册码按回车,果然断下来了。
程序先对输入字符串格式化(试了一下只是大写转小写),然后把字符串逆序,004017C5 cmp dword ptr [ecx-0x8], 0x6检测长度是否为6,检测调试004017D1 call <jmp.&KERNEL32.IsDebuggerPresent>,检测标志位004017DE mov eax, dword ptr [esi+0x64]为0时直接退出,然后在004017FB call 00401D50与驱动交互。
可能是驱动里做了anti-debug,调试到call DeviceIoControl时程序就崩了。
先把程序跑起来然后再附加,设置的断点无效,硬件断点也不好使。
这里卡住了一会,想到一个取巧的办法,调试的程序里跳过驱动加载和进程检测,修改程序检测流程跑到call 00401D50里时停下来,另外再运行一个CrackMe.exe加载驱动,然后再到调试程序里CreateFileA连接驱动,跳过DeviceIoControl驱动通信,直接执行WriteFile传字符串给驱动、ReadFile从驱动读取结果,居然成功了。
看到驱动读取了0x10字节计算结果,转换成0x20字符串,返回主流程后,00401829 call 00401920再次计算转换为0x20字符串,提取(2,0x0A)测试是否为"888aeda4ab"。
整个流程有2个关键算法,一个在驱动里,一个在call 00401920里。
先看call 00401920,输出值像是MD5,找个MD5计算器对驱动处理结果进行MD5计算,果然与call 00401920计算结果一样。
再看驱动计算过程,也像是MD5,直接对输入值进行MD5计算,不正确。看来需要分析驱动了。
在驱动释放完成后先把驱动文件存出来:vmxdrv.sys。只有6K,拖到IDA里分析一下,在sub_108B2处发现了疑似MD5算法的初始化代代码:
int *__stdcall myMd5Init(int *a1)
{
int *result; // eax@1
result = a1;
*a1 = 0;
a1[1] = 0;
a1[2] = 0x67452301;
a1[3] = 0xEFCDAB89;
a1[4] = 0x98BADCFE;
a1[5] = 0x10325476;
return result;
}
查看调用,找到MD5计算过程:
void __stdcall myMd5Calc(char *a1, char *a2)
{
signed int v2; // eax@1
signed int v3; // esi@1
signed int v4; // eax@2
int v5; // [sp+Ch] [bp-6Ch]@6
char v6[16]; // [sp+64h] [bp-14h]@1
v6[0] = 0;
*(_DWORD *)&v6[1] = 0;
*(_DWORD *)&v6[5] = 0;
*(_DWORD *)&v6[9] = 0;
*(_WORD *)&v6[13] = 0;
v6[15] = 0;
v2 = strlen(a1);
v3 = v2;
if ( v2 <= 16 )
{
memcpy(v6, a1, v2);
v4 = 0;
if ( dword_11380 )
++v6[0];
if ( v3 > 0 )
{
do
{
v6[v4] += v4;
++v4;
}
while ( v4 < v3 );
}
myMd5Init(&v5);
myMd5Update(&v5, v6, strlen(v6));
myMd5Final(&v5, a2);
}
}
流程比较清晰,先把输入字符串变换一下,然后就开始MD5计算了。
字符串变换过程为:当dword_11380为非0时字符串第0位加1;字符串每一位加上顺序号。
再查看dword_11380的引用,在sub_1071A里,功能为DeviceIoControl调用0x222004功能时置为1,同时在sub_10486里设置进程信息,估计在这里清除了调试标志导致OD的调试崩掉了。
验证一下MD5算法,输入值为“654321”时,字符串转换结果为“766666”,进行MD5计算,与驱动返回结果相同。
这里算法已经分析完成了。总结一下流程:输入6位字符,转换为小写,逆序排列,按位分别+1 +1 +2 +3 +4 +5,进行2次MD5计算,取结果的(2,0x0A)位,测试是否为"888aeda4ab"。
MD5算法只能穷举了,先试了一下6位纯数字,没跑到结果,只好加上所有小写字符了,Python源码如下:
import hashlib
key="abcdefghijklmnopqrstuvwxyz0123456789"
dest="888aeda4ab"
i=1
done=False
for a in key:
if (done):
break
for b in key:
if (done):
break
for c in key:
if (done):
break
for d in key:
if (done):
break
for e in key:
if (done):
break
for f in key:
if (done):
break
s=chr(ord(a)+1)+chr(ord(b)+1)+chr(ord(c)+2)+chr(ord(d)+3)+chr(ord(e)+4)+chr(ord(f)+5)
i+=1
if ((i%100000)==0):
print("*calc:",a+b+c+d+e+f)
i=1
m=hashlib.md5(s.encode(encoding='utf-8'))
#print(m.hexdigest())
s2=m.hexdigest()
m2=hashlib.md5(s2.encode(encoding='utf-8'))
#print(m2.hexdigest())
s3=m2.hexdigest()
#print(s3[2:12],dest)
if (s3[2:12]==dest):
s=a+b+c+d+e+f
print(s,s2,s3)
done=True
我的电脑CPU是4核的,把key分别设置为:
key="abcdefghijklmnopqrstuvwxyz0123456789"
key="9876543210zyxwvutsrqponmlkjihgfedcba"
key="stuvwxyz0123456789abcdefghijklmnopqr"
key="rqponmlkjihgfedcba9876543210zyxwvuts"
开四个进程同时跑,意为分别从最前面、最后面、中间向后、中间向前开始穷举。
大约40分钟,第2个进程跑出结果了:“6891us”,倒序即为注册码:“su1986”。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课