首页
社区
课程
招聘
[原创]独行孤客CrackMe-第五题的writeup(一路的艰辛)
发表于: 2017-6-11 01:02 3714

[原创]独行孤客CrackMe-第五题的writeup(一路的艰辛)

2017-6-11 01:02
3714

程序的特点:MFC程序,反调试,隐蔽的驱动文件,驱动反调试等。


1 MFC程序的特点

MFC程序使用了大量的深度封装的类,这些类除了结构复杂的特点,还有虚函数。虚函数支持了C++的多态性。在C++内存模型中,如果想访问一个对象的虚函数,需要做两件事,首先判断该对象的类型(找到虚函数表,对象前一个DWORD指向该虚表),然后根据索引访问虚表中的函数。这意味着大量使用虚函数和继承的MFC程序有很多张虚表,每有一个实现了虚函数的类,就可能有一张虚表。在MFC中,对虚函数很少有直接的访问,通常是通过虚表地址加上偏移来计算实际调用地址,很不直观。

幸运的是该MFC程序没有在虚函数上绕弯路,尽管如此,深入分析仍然很困难。


2 隐蔽的驱动文件

MFC仍然是一个win32程序,离不开消息事件的驱动,离不开窗口过程的处理。

使用IDA打开程序,没有受到任何阻挠,来到 0x40C14E处的 call _WinMain@16,有兴趣的可以阅读CWinApp类的源码,CWinApp类封装了win32程序的几个关键函数。

连续跟随调用地址,便会看到几个头疼的虚函数调用。

上面的eax便是虚函数表的地址,仅靠代码是无法知道这些对应什么函数调用。

当程序运行在非xp系统时,提示“请在xp平台中重新运行CrackMe",搜索关键字"xp",然后ctrl+x找到唯一引用,来到sub_4013E0。

快速浏览一下,调用了GetSystemMenu和AppendMenuA(创建系统菜单相关的调用),和SendMessageA(msg=80h,查找得知是让图标与窗口关联的消息),还有PostMessageA(msg=12h,让程序退出的消息)

在程序退出提示框之前有一个call sub_402210,判断是否是符合的xp系统。

如果是xp系统,然后 jnz short loc_4014E9

经过各种字符串的操作后, jnz     short loc_401587

细细分析一下 sub_401AA0

突然意识到创建服务传入的BinaryPathName=...\vmxdrv.sys在哪里,原来在 sub_401F20处创建了一个驱动文件在

.text:00401566               call    sub_401F20 

下一行指令下断点,在该程序当前目录下会找到一个vmxdrv.sys驱动文件。

第一次分析驱动文件,经过查找相关资料,得知访问驱动文件,需要一下几个关键函数 CreateFile,DeviceIoControl,WriteFile,ReadFile。

CreateFile是通过"\\.\vmxdrv"作为文件名访问服务的,DeviceIoControl传入控制码,而WriteFile和ReadFile是从驱动设备写入和读取数据。

找到DeviceIoControl的两个调用 sub_4022A0 和sub_401D50。

简单分析下sub_4022A0,发现该调用只是简单发送一个0x222004H的IoControlCode,调用该过程的父调用恰好位于上述的打开vmxdrv服务之后,而且调用了5次该过程。

接下来分析sub_401D50,经一下分析,得知该过程的作用就是往驱动设备发送输入的字符串,然后读取输出,并将输出的16个字节变成长度为32的HexString。

该过程的caller分析如下


3分析驱动文件

驱动文件的入口是DriverEntry,尽量参考一些驱动资料。

通常在加载驱动结束前有重要的一个MajorFunction。

再来分析 sub_1071A 设备控制处理

然后分析输入处理 sub_1061C

最后分析读取处理

经过以上简单分析,驱动文件的算法如下:

1 接受IoControlCode=222004H后,设置dword_114D8=1,并使DebugPort清零

2 接受输入时,当dword_114D8=1时,先讲字符串与byte{1,1,2,3,4,5}对应相加,然后使用MD5加密,最后设置dword_114DC=1

3 处理读取时,判断dword_114DC=1,如果为1,则输出加密后的16个字节,否则固定输出某些字节

隐藏的dword_114E0,存放IoGetCurrentProcess()返回值,猜测和多线程有关。

而MFC程序的加密算法大致如下:

1 接受6位字符串输入

2 向驱动设备输入该6位字符串

3 读取加密处理后的16个字节,然后转成HexString

4 再次HexString进行MD5加密处理,再次转成HexString

5 讲HexString与"888aeda4ab"比较,似乎有些不对劲,32长度的HexString如何与10长度的比较,肯定还有一些不清楚的地方。


4反调试

1 IsDebuggerPresent 这是一个很常见的反调试。

如果eax=1,则跳到loc_4018C2。

由于这个函数不需要任何参数,所以无需调整堆栈,分别使用5个nop指令和一个xor eax, xor eax替换掉call 和 test指令

2 头疼的DeviceIoControl

当在调试该程序时,运行到222004H设备控制码时便会抛出内核访问异常,程序无法正常调试。

本来想对驱动文件patch,不让DebugPort置零,然后创建服务。但是这会导致驱动校验无法通过。


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 1
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//