【编程技术- 全文精华在最后一句】此文章归类为:编程技术。
0. 前言
最近由于工作的需要,需要枚举消息钩子,总所周知的事是,很多ark工具都是有的, 那就选择直接逆向。本文选作了 openark 的驱动代码研究,openark 属于早期部分开源,后期不在开源。但是由于驱动没vmp保护 ,约等于源码么。 废话不多说直接开搞。
首先,直接进入openark的 内核模式,选择内核标签,进入gui管理的 消息钩子 ,然后使用 x64dbg 挂钩 ,对 deviceiocontrol 下断点,顺便把 参数打印出来。 最后如图:

其中这个暂停条件是 rdx== 0xa3632640 ,rdx 是 iocontrolcode ,我当时通过设置暂停条件为0 打印控制码 然后试出来的。
拿到这个控制码直接 就去驱动分析了, 三环没啥东西可看了。
1. 驱动模块逆向
进去直接分析消息通信相关,很标准的通信啊。直接干。

直接找到枚举消息钩子的功能函数的入口(这个里面的其他函数 对应这个gui管理的其他的功能,但是我懒得分析了,只看自己想要看的代码):

进来发现,很多未定义的东西啊(通过上下文可知 ,可能是win32k相关东西),到现在有两种思路 ,一种是直接vmware+VirtualKD-Redux 调试驱动,直接看他这些变量 到底是干什么的。还有一种思路是通过xref猜测他这个变量,其实也不用专门去调试。因为根据 ida 的交叉引用我们 一眼就能看出他是什么东西来了。

就这么标准的写法 模块名,具体的变量/函数 ,最后一个是我们引用查看的,闭着眼 猜是地址了。还原相关的变量名称,就和逆向没多大关系了。
3. 关键变量的一些说明
通过泄露的源码和网上的公开信息,我们可以知道,gSharedInfo 是windows图形显示中很关键的一个内核变量,其中 gSharedInfo+8的位置存放的是aheList数组, 数组成员类型为_HANDLEENTRY,以及HANDLE_TYPE,tagHOOK等。
主要参考了看雪的帖子 https://bbs.kanxue.com/thread-261767.htm
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | 15063 之前的
typedef struct _HANDLEENTRY
{
PVOID phead;
PVOID pOwner;
UCHAR bType;
UCHAR bFlags;
USHORT wUniq;
} HANDLEENTRY, * PHANDLEENTRY;
15063 之后的
typedef struct _HANDLEENTRY
{
PVOID Unknown1;
PVOID UniqueThreadId;
PVOID Unknown2;
UCHAR bType;
UCHAR bFlags;
USHORT wUniq;
} HANDLEENTRY, * PHANDLEENTRY;
enum HANDLE_TYPE {
TYPE_FREE = 0 ,
TYPE_WINDOW = 1 ,
TYPE_MENU = 2 ,
TYPE_CURSOR = 3 ,
TYPE_SETWINDOWPOS = 4 ,
TYPE_HOOK = 5 ,
TYPE_CLIPDATA = 6 ,
TYPE_CALLPROC = 7 ,
TYPE_ACCELTABLE = 8 ,
TYPE_DDEACCESS = 9 ,
TYPE_DDECONV = 10 ,
TYPE_DDEXACT = 11 ,
TYPE_MONITOR = 12 ,
TYPE_KBDLAYOUT = 13 ,
TYPE_KBDFILE = 14 ,
TYPE_WINEVENTHOOK = 15 ,
TYPE_TIMER = 16 ,
TYPE_INPUTCONTEXT = 17 ,
TYPE_HIDDATA = 18 ,
TYPE_DEVICEINFO = 19 ,
TYPE_TOUCHINPUT = 20 ,
TYPE_GESTUREINFO = 21 ,
TYPE_CTYPES = 22 ,
TYPE_GENERIC = 255
};
typedef struct _THRDESKHEAD
{
PVOID h;
ULONG cLockObj;
PVOID pti;
PVOID rpdesk;
PVOID pSelf;
}
typedef struct _tagHOOK
{
_THRDESKHEAD head; / / 0x0
PVOID phkNext; / / 0x28
LONG iHook; / / 0x30
ULONG64 offPfn; / / 0x38
LONG flags; / / 0x40
LONG ihmod; / / 0x44
PVOID rpdesk; / / 0x50
} tagHOOK, * PtagHOOK;
|
真伪未辨 ,直接引用,酌情使用。
4. ida伪代码的阅读与还原
还是说一句,由于代码没有任何保护 , 所以只要把相应的变量符合重新命名,基本上就是源码了,这小节就是个人阅读时候的一些还原思路和对代码的理解,其实使用ai直接还原我感觉效果更好。
首先搞一个基础的检测 主要是看遍历所需的内核变量能否读,主要是针对 gsharedinfo变量来 还有 gSharedInfo+8 也就是 aheList,其中kprobe_read就是判断能不能读

上述检测通过之后 ,判断有没有要遍历的数量,如果有,则开始搞,没有的话就返回

主要说一下, 这个取 HANDLEENTRY ,win10 15063之前和 之后结构体是不同的,所以要对系统版本进行判断,取 htype 成员和 wuniq成员是为了下面的判断,所以需要做处理, 其中 htype 的类型是 HANDLE_TYPE ,这里面我们要遍历的是hook类型的,直接使用TYPE_HOOK = 5来过滤遍历我们想要的。
这里面调用了 HMValidateHandle 函数 来获取 taghook 类型的返回值,该返回值 存储了我们需要的信息

HMValidateHandle 函数原型为
1 | PtagHOOK (*fn_HMValidateHandle)( HANDLE Handle, HANDLE_TYPE hType)
|
其中第一个变量是我们根据句柄生成规则 生成的, 第二个是 HANDLE_TYPE ,因为我们要获取的是 HOOK类型的,所以填对应的5 ,对得到的返回值类型进行判断,如果返回不为NULL继续下一步的遍历
- 这段代码就是就是对 返回值的解析,还有解析信息的返回,至于返回三环的数据格式我就不说了,因为不是我们关心的重点

根据第三小节 我们得知了 PtagHOOK 长什么样子 ,ida截图我感觉 已经说明了挺多东西了。 主要包括以下几个,
1 2 3 4 | PtagHOOK - >flags,(标志位)
PtagHOOK - >iHook,(钩子类型) ,
PtagHOOK - >offpfn (函数地址偏移) / / win10以下的版本是从ahmodLibLoaded获取的。
PtagHOOK - >ihmod(模块索引) ,其中如果ihmod = - 1 的时候,说明 offpfn 是绝对值,否则话是模块内相对偏移
|
- 取模块名称 ,其实就是调用了get_moudle_info_by_Messagehook这个函数, 第三个参数是函数模块的路径 ,第四个参数 ,hook函数的偏移

该函数内部有两个分支功能,一个分支是处理 大于等于win10系统的,一个是小于win10的,大于win10 的主要是调用了 win32kbase!UserGetAtomNameFromAtomTable 函数来获取模块信息, 小于win10的是取函数偏移地址。
- 最后信息展示以及对应的字段说明

能看到 界面展示的 有8个字段, 我们这边一一对应找一下
句柄 : 通过count | ((USHORT)wUniq << 16) 生成
类型: pobject_ret->iHook;// 钩子类型
flag: pobject_ret->flags;// flags
函数地址: 两种情况,一种是 ihmod = -1 直接获取pobject_ret->offPfn
另外一种是 ihmod != -1 等于 moudulebase+ pobject_ret->offPfn
模块名: 通过函数UserGetAtomNameFromAtomTable和句柄 UserLibmgmtAtomTableHandle 获取模块名
pid : 看代码,不想说了,基操
tid : 看代码,不想说了,基操
进程路径: 都拿到pid了, 这个还要问?
5 . 总结
没啥总结,就是逆向别人的驱动,然后结合网上的资料,对ida的伪代码进行还原。
用正经话说就是,主要展示了一个逆向的思路过程,如何在碰到一个需要的功能,并且没有接触过这些知识的的情况下,通过逆向现有的产品功能,获取所需信息的过程。
用大佬说的话就是ida得了mvp,我是抄袭狗。
更多【编程技术- 全文精华在最后一句】相关视频教程:www.yxfzedu.com