根据Chaos-Rootkit项目来掌握进程隐藏
2023-5-12 02:14:0 Author: xz.aliyun.com(查看原文) 阅读量:17 收藏

前置了解:
测试调试环境:Window 10
Chaos-Rootkis,该项目是基于x64内核模块下的rootkit。它的功能是可以有效的隐藏进程且进行提权操作。
我们知道进程对象是有一个 _EPROCESS结构 其中包含了很多结构体比如访问令牌,句柄等信息。
其技术实现之一的关键点就是在 _EPROCESS中的ActiveProcessLinks,它是一个指向LIST_ENTRY结构体的指针


(不同Windows 版本的 前面的偏移量也不一样,所以使用项目的时候也需要对应修改)
双向链表有一个特殊的点就是它含有两个指针地址,一个可以指向前驱节点一个是指向后驱节点。


而 _LIST_ENTRY就是一个双向链表结构
通过windbg 调试也可以确定_LIST_ENTRY是一个双向循环链表,它的表项结构有两个成员分别是Flink和Blink,类型都是_list_entry指针


这其中的 Flink 和 Blink 其实就相当于上述双链表图中的 previous指针和next指针
官方话术:微软官方文档提供的结构体和两个指针所代表的作用

typedef struct _LIST_ENTRY {
  struct _LIST_ENTRY *Flink;
  struct _LIST_ENTRY *Blink;
} LIST_ENTRY, *PLIST_ENTRY, PRLIST_ENTRY;
对于作为列表条目的LIST_ENTRY结构体Flink成员指向列表中的下一个条目,如果列表中没有下一个条目,则指向列表头。
对于作为列表头的LIST_ENTRY结构体Flink成员指向列表中的第一个条目,如果列表为空,则指向LIST_ENTRY结构体本身
对于作为列表条目的LIST_ENTRY结构体Blink成员指向列表中的前一个条目,如果列表中没有前一个条目,则指向列表头。
对于作为列表头的LIST_ENTRY结构体Blink成员指向列表中的最后一个条目,如果列表为空,则指向LIST_ENTRY结构体本身

如果在进程中 用 Flink 和 Blink 来描述指向的话如下图

ProcessA ProcessB ProcessC ProcessD 分别就是四个节点Node,它们都有两个指针Flink,Blink(也就是上述双链表中的Previous 和Next)
在官方话术中,我们知道Flink指向的是下一个entry那么它就是next,Blink指向的是前一个entry 它就是Previous
在上述图我们可以知道Previous 指向都是上一个节点,所以在进程中 Blink 指向的就是上一个进程
所以进程B的Blink指针指向的就是进程A,进程C的Blink指针指向的就是进程B,以此类推
Flink是指向下一个进程,所以进程B的Flink 指向进程C,进程C的Flink指向的就是进程D 以此类推
而表头(也就是Process A ) Blink指针 它的前一个就指回ProcessD 实现闭环(这一点在官方描述中也有提到)

原理学习:
现在我们了解了 双链表的操作,也了解了在windows的 _EPROCESS中的结构体_LIST_ENTRY,也学会了这个结构体的指针在进程里的指向。
那么如果我们要隐藏我们的进程,其实就是修改相邻进程节点的Flink和Blink指针,让这两个指针相互指向对方。这样的话当内核遍历双链表结构的时候,就找不到我们隐藏的进程了。因为该指向下一个节点的指针指向了前一个节点 而该指向上一个节点的指针则指向了下一个节点了。
其实具体的意思就是,如果我们隐藏的是进程B
上述的分析中我们可以知道 指向进程B有关的节点有 进程A的Flink指针 因为它是指向下一个节点的指针
还有进程C的Blink指针,因为它是指向前一个节点的。所以我们只需要修改这两个指针的指向即可,如下图。


来看一下隐藏部分的实现代码,首先就是拿到要隐藏进程的 EPROCESS 结构的引用指针
plist = (PLIST_ENTRY)((char *)process + 0x448); 这里的偏移不同windows版本偏移值是不一样的要注意
然后就是比较关键的对Flink , Blink 判断和移动,还有一点比较关键就是最后记得将进程plist的相应指针设置为NULL,不然关闭进程的时候PspDeleteProcess 会释放资源,不置空的话它就在结构中找不到我们的进程会导致BOSD!


这一步还是跟着调试走一下更好理解,代码中也是做了替换,在调试中
首先我们找到要隐藏的进程 这里的notepad ,查看其ActiveProcessLinks的偏移 是 0x448
而后边两个指针的地址是0xffff898a86d9c4c8 - 0xffff898a86e064c8


0xffff898a86e144c8 Flink 0xffff898a86e084c8 Blink
还记得这两个指针指向的是什么嘛,我们来计算一下(5a8,是ImageFileName 的偏移)这样就得到了这两个指针指向的前后两个进程,也验证了前边的说法。

然后分别拿到这两个进程的地址


然后我们还需要分别获取 PROCESS ffff898a86e08080 --> UserOOBEBroker.exe 进程的 blink flink地址
PROCESS ffff898a85f560c0 -->svchost.exe 进程的 blink flink地址 如下图所示


这样获取到了之后,就按照我们上述图中所示,将两个指向互相指向,这样系统正常来找我们的进程是根据这两个指针,但是现在被我们修改成相互指向了,在任务管理器中就找不到我们的进程了。

注意修改的时候,指针地址所指向的前后顺序千万不要搞混了! 哪一个指向前边哪一个指向后边不能错
效果如图


可以看到可视化的进程显示界面,我已经打开了记事本进程但是并没有出现在任务管理器界面里。
这个项目可以帮助更好的理解可利用隐藏进程的原来和手法,但是还是推荐调试而不是直接使用工具,所以通过调试来演示这样更容易理解这两个指针所指向的操作。
这里的项目里提权就简单提一嘴,因为手法很常见:
此项目还可以进行权限提升,其实就利用驱动获得了系统token,然后将其替换成当前进程的token从而让当前进程拥有system 权限,这一块看一下代码实现即可。主要内容在ring3_app.cpp里,使用了DeviceIoControl来与驱动进行通信,主要是利用了驱动来完成的,项目里也有inf文件


通过在驱动程序从用户模式应用程序接收到PID之后,它使用它来获取指向目标进程的_EPROCESS结构的指针。然后,驱动程序访问_EPROCESS结构的Token成员以获得指向进程令牌的指针,并用系统令牌替换它,从而有效地将进程的安全上下文更改为系统的安全上下文从而来完成提权操作。

引用:
https://github.com/ZeroMemoryEx/Chaos-Rootkit


文章来源: https://xz.aliyun.com/t/12518
如有侵权请联系:admin#unsafe.sh