Joe1sn's Cabin

【RootKit】Chaos-Rootkit解读-1 进程隐藏

去年学了点kernel开发,实战太少了,看看别人的代码怎么写的

项目地址:https://github.com/ZeroMemoryEx/Chaos-Rootkit

进程隐藏

测试环境:

image-20250430073259244

连接到rookit

image-20250430074025149

使用效果:

image-20250430074124118

image-20250430074144155

原理剖析

Driver.c/processIoctlRequest中处理这个功能的ioctl

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
NTSTATUS processIoctlRequest(
DEVICE_OBJECT* DeviceObject,
IRP* Irp
)
{
PIO_STACK_LOCATION pstack = IoGetCurrentIrpStackLocation(Irp);

int pstatus = 0;
int inputInt = 0;

__try
{
// if system offsets not supported / disable features
// that require the use of offsets to avoid crash
if (pstack->Parameters.DeviceIoControl.IoControlCode >= HIDE_PROC && \
pstack->Parameters.DeviceIoControl.IoControlCode <= UNPROTECT_ALL_PROCESSES && xHooklist.check_off)
{
pstatus = ERROR_UNSUPPORTED_OFFSET;
__leave;
}
switch (pstack->Parameters.DeviceIoControl.IoControlCode)
{
case HIDE_PROC:
{
if (pstack->Parameters.DeviceIoControl.InputBufferLength < sizeof(int))
{
pstatus = STATUS_BUFFER_TOO_SMALL;
break;
}
RtlCopyMemory(&inputInt, Irp->AssociatedIrp.SystemBuffer, sizeof(inputInt));

pstatus = HideProcess(inputInt);

DbgPrint("Received input value: %d\n", inputInt);
break;
}
//...
}
}

核心功能函数HideProcess

首先通过PsLookupProcessByProcessId找到EPROCESS

image-20250430074718524

然后就是找到activelist双向链表,然后将当前eprocess从双向链表中摘除

image-20250430074828264

关于eprocess的双向链表activelist你可以回顾前文:【Win Pwn】HEVD-内核栈溢出(下)

这里简单提及:

在刚才的EPROCESS中,有一段记录的是程序的链表:ActiveProcessLinks,而且windows会生成一段独特的标识来标记每一个程序:UniqueProcessId,在这段 双向 链表上每段程序都可以被找到,因为可以向前和向后查找。

image-20240119193844612

image-20240119193859162

image-20240119194420366

调试

这里我新建了一个cmd.exe,进程pid为:4648(0x1228)

image-20250430080321276

image-20250430080433357

此时他的flink和blink为

image-20250430080607648

image-20250430081947836

hide_process

之后使用rootkit

image-20250430082442539

开发

双向链表删除作为数据结构基础部分没啥好说的,值得一提的是这里的锁设计

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
DWORD
HideProcess(
int pid
)
{
//...
BOOLEAN lockAcquired = FALSE;

__try
{
__try
{
//...
ExAcquirePushLockExclusive(&pLock);
lockAcquired = TRUE;
//...
}
//...
}
__finally
{
//...
if (lockAcquired)
ExReleasePushLockExclusive(&pLock);
}
return (status);
}

在os运行时,内核可能会对这块链表进行修改,当我们修改时在这里添加一个锁可以有效地避免条件竞争导致出现的未定义行为

防护

image-20250430083050562

其实可以这样想,在任务管理器中我们已经看不到了这个进程,那么为什么在windbg中依然能够通过PID找到该进程呢?