20

[原创]第5题算法分析

lelfei 2017-6-10 11:58 803

破解工具:ODIDAPython

 

WinXP虚拟机中直接用OD载入CrackMe.exe,查看字符串参考,有明显提示“驱动释放失败,\n请在xp平台中重新运行crackme”,有驱动。

先不管驱动,继续往下跟,在00401593    call    00401AA0处加载驱动,加载成功后在004015CA   call    dword ptr [<&KERNEL32.DeleteFileA>]删除驱动文件,在004015D4    call    00402250里间隔100ms建立5004022A0的进程,进程作用是每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,进行2MD5计算,取结果的(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

 

 

我的电脑CPU4核的,把key分别设置为:

key="abcdefghijklmnopqrstuvwxyz0123456789"

key="9876543210zyxwvutsrqponmlkjihgfedcba"

key="stuvwxyz0123456789abcdefghijklmnopqr"

key="rqponmlkjihgfedcba9876543210zyxwvuts"

开四个进程同时跑,意为分别从最前面、最后面、中间向后、中间向前开始穷举。

大约40分钟,第2个进程跑出结果了:“6891us”,倒序即为注册码:“su1986”。




快讯:[看雪招聘]十八年来,看雪平台输出了大量安全人才,影响三代安全人才!

最新回复 (0)
返回