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

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

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

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

就这么标准的写法 模块名,具体的变量/函数 ,最后一个是我们引用查看的,闭着眼 猜是地址了。还原相关的变量名称,就和逆向没多大关系了。
通过泄露的源码和网上的公开信息,我们可以知道,gSharedInfo 是windows图形显示中很关键的一个内核变量,其中 gSharedInfo+8的位置存放的是aheList数组, 数组成员类型为_HANDLEENTRY,以及HANDLE_TYPE,tagHOOK等。
主要参考了看雪的帖子 https://bbs.kanxue.com/thread-261767.htm
真伪未辨 ,直接引用,酌情使用。
还是说一句,由于代码没有任何保护 , 所以只要把相应的变量符合重新命名,基本上就是源码了,这小节就是个人阅读时候的一些还原思路和对代码的理解,其实使用ai直接还原我感觉效果更好。
首先搞一个基础的检测 主要是看遍历所需的内核变量能否读,主要是针对 gsharedinfo变量来 还有 gSharedInfo+8 也就是 aheList,其中kprobe_read就是判断能不能读

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

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

HMValidateHandle 函数原型为
其中第一个变量是我们根据句柄生成规则 生成的, 第二个是 HANDLE_TYPE ,因为我们要获取的是 HOOK类型的,所以填对应的5 ,对得到的返回值类型进行判断,如果返回不为NULL继续下一步的遍历
句柄 : 通过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了, 这个还要问?
没啥总结,就是逆向别人的驱动,然后结合网上的资料,对ida的伪代码进行还原。
用正经话说就是,主要展示了一个逆向的思路过程,如何在碰到一个需要的功能,并且没有接触过这些知识的的情况下,通过逆向现有的产品功能,获取所需信息的过程。
用大佬说的话就是ida得了mvp,我是抄袭狗。
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;
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
,
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课