这篇文章比较特殊,是一篇穿插答疑文章,由于刚好在前一篇教程《驱动开发:内核枚举PspCidTable句柄表》
整理了枚举句柄表的知识点,正好这个知识点能解决一个问题,事情是这样的有一个粉丝求助了一个问题,想要枚举出驱动中活动的线程信息,此功能我并没有尝试过当时也只是说了一个大致思路,今天想具体聊一聊这个话题,也想聊一聊自己对粉丝们的想法。
首先因为我的人生经历比较特殊,我经历过无法求知的困境,深知一个人在没有任何人指点的情况下去研究技术是多么的折磨人,所以在某些情况下只要你关注了我,我也会尽自己最大可能去帮助大家,即便是当时没有解决这个问题我也会记下来,只要能被解决我一定会第一时间告诉粉丝,但也希望大家不要遇到困难关注我,解决困难取消关注,这样我觉得很不地道。
好了步入正题,这个枚举驱动内的线程我们无法用传统的API去枚举,原因很简单你拿不到进程的EPROCESS
结构,或者说他这个驱动程序本身就是系统的一部分根本就没有进程ID的概念,由于我一直没有尝试这个需求,所以当时对粉丝说的是通过PEB来拿到,但这个方法其实关键就在于,以我目前的知识储备无法拿到驱动的EPROCESS
结构。
然后干脆就直接枚举出整个系统所有的进程与线程信息,例如上一篇文章中提到的枚举句柄表,打开ARK工具找到所需查询的线程,会发现他有一个ETHREAD
结构。
我们直接在枚举列表中查询以下看看,你会发现所有句柄表线程中是存在这个ETHREAD
结构。
但是这个是全局的,无法得到它属于哪个驱动模块,这就很尴尬了。
你或许灵机一动,我直接得到ETHREAD
信息,从里面找EPROCESS
,再从里面找进程名,但跟到最后你会发现它显示的是SYSTEM
进程,如果继续往下就是内核了,小丑竟是你自己。
这里只能用笨办法,首先线程ETHREAD
地址是0xFFFF9C02B2DCC540
抹掉最后三位0xFFFF9C02B2DCC000
。
然后看看驱动列表中的0xFFFF9C02B2DCC060
同样抹掉最后三位是0xFFFF9C02B2DCC000
,这两个地址相差不大甚至说就是一摸一样。
我不知道别人的ARK工具是怎么实现的,但是我目前能想到的办法只能是这一种笨办法,两者作比较相差在一个误差以内就说明是进程内的子线程。
这样我们首先枚举的是驱动完整信息,然后在和线程作比较,从而判断或者说归档,将某一些子线程归类到某个驱动程序上面,代码我就不写了,再写也是重复的东西,前面的文章中都有代码,自己拼凑一下就可以实现的功能。
新增一个方法,通过IoThreadToProcess
将线程句柄转换为进程EPROCES,并附加后提取出所属驱动。
if (PsLookupThreadByThreadId(i_id, &p_ethread) == STATUS_SUCCESS)
{
//DbgPrint("线程TID: %d | ID: %d | 内存地址: %p | 对象: %p \n", i_id, i, BaseAddr + i * 0x10, ul_decode);
// 通过线程THread得到进程PID
NTKERNELAPI PEPROCESS IoThreadToProcess(PETHREAD Thread);
NTKERNELAPI char* PsGetProcessImageFileName(PEPROCESS Process);
PEPROCESS ep;
PETHREAD et;
HANDLE pid;
ep = IoThreadToProcess(p_ethread);
pid = PsGetProcessId(ep);
DbgPrint("%d \n", pid);
}