首先拖进ida发现并没有vm虚拟化核心代码呵呵(不知道是不是WHQL的原因),然后我们来看这个神笔的DriverEntry,很明显是非常标准的入口函数并没有啥东西,然后传递了DriverObj给下一层函数,同时这个Driver Entry的返回值也是来自这个sub_14034C000的结果的。


那么就跟进去!


我勒个豆呀,果然不简单,好像使用了导入表指针加密(为什么不是lazyimport是因为导入表还是有函数的),稍微增加了一点静态分析难度,然后稍微花了时间,发现这个是一个初始化驱动功能的函数,他干了这些事情:
· 初始化字符串
· 打开对象路径
· 调 KdDisableDebugger
· 注册进程回调
· 注册线程回调
· 注册镜像加载回调
· 注册 ObRegisterCallbacks
· 注册 minifilter
· 创建 FltCreateCommunicationPort 通信端口
· 启动过滤器

通过上面我们可以看到,驱动调用了FltCreateCommunicationPort进行通讯,让我们仔细看这部分驱动初始化代码就可以看到非常明显的 \PacDomain 端口名,由于前面提过的导入表指针加密导致我们无法直接看到函数名,只能看到 off_140104xxx + 0x3EF98FDBAFBD88A7 这种形式,看起来很烦,但是把真实目标算出来以后,off_1401045E8 + 0x3EF98FDBAFBD88A7 就是 RtlInitUnicodeString。然后在 0x14034C66F 这里能看到:
RtlInitUnicodeString(&xxx, L"\\PacDomain")


后面它又在栈上填了一坨 OBJECT_ATTRIBUTES,再到 0x14034C7E7 调下图的FltCreateCommunicationPort进行初始化,我们前面看到的 \PacDomain 端口名就藏在这个OBJECT_ATTRIBUTES结构里的ObjectName,完整调用解密后是这样的:
FltCreateCommunicationPort(qword_1403449C0,&qword_1403449C8,&ObjectAttributes,0,sub_14034F126,sub_14034F0EA,sub_14034F0CF,...),这个调用就很简单了,用户态那边会有一个服务连进来。连接的时候走 sub_14034F126,断开的时候走 sub_14034F0EA,消息处理入口是 sub_14034F0CF。
整个sub_14034F126 会记当前线程 ID,还会把 IoGetCurrentProcess() 之类的信息存到 xmmword_1403449D0。这个感觉像是校验还是啥别的不重要,然后断开时 sub_14034F0EA 会关 client port,然后把这个全局状态清掉。


但是你以为 sub_14034F0CF 就是真正的消息处理入口了吗?!错错错!点击去就会发现这个sub_14034F0CF 其实是个跳板函数!经过计算可以得到真正的消息处理入口是sub_14005B5DB!




想要建立通讯,驱动会对端口客户端进行 8 字节挑战校验,校验点在连接回调 sub_14034F126,它要求 FltCreateCommunicationPort 的 ConnectionContext 参数必须正好是 8 字节。其完整流程为:
·sub_14034F126 先保存传入的 ConnectionContext 指针和 ClientPort。
·检查 SizeOfContext == 8,不等于 8 直接拒绝连接。
[内核课程]《Windows内核攻防实战》!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。
最后于 16小时前
被Rw0terX编辑
,原因: