【驱动】4-内核下遍历系统当前进程

概述:内核模式下遍历系统当前进程,以及链表的基本使用

相关接口

进程相关

相关知识点

PID

PID 一定是4的整数倍

为什么 PID 一定是4的整数倍

Windows进程的PID(Process ID)是4的倍数的原因与Windows内核中句柄分配机制有关。以下是详细的解释:

  1. 句柄分配机制:在Windows NT内核的操作系统中,进程ID(PID)和线程ID(TID)实际上是基于全局的句柄表PspCidTable生成的,这个表也被称为CID句柄表(Client ID handle table)。这个句柄表中的每个项都包含了进程或线程的对象地址。

  2. 句柄值与索引:在Windows中,句柄值是用来检索句柄表的一个“伪索引”。由于句柄值的低2位被用作标志位,因此它们对于作为句柄表索引本身没有意义。这意味着句柄值实际上是4的倍数,因为每4个字节对应一个句柄索引值。

  3. 内核句柄重用:分配内核句柄的相同代码也用于分配进程和线程ID。由于内核句柄是4的倍数,因此进程和线程ID也是如此。这是一个实现细节,因此不应编写依赖于这个规律的代码。

  4. 结构定义:在Windows内核中,句柄类型是由EXHANDLE结构定义的,其中包含一个ULONG值,用于存储索引。由于低2位被用作标志位,所以有效的索引从第3位开始,这就是为什么句柄值(以及由此产生的PID和TID)是4的倍数的原因。

  5. 历史和兼容性:这个机制在Windows的多个版本中一直保持不变,主要是因为底层代码难以改变。即使在最新的Windows版本中,这个规律依然存在。

总结来说,Windows进程PID是4的倍数是由于内核中句柄分配机制的设计,特别是与句柄值的位结构和内核句柄重用代码有关。这是一个实现细节,不应该依赖于应用程序开发中。

完整代码

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#include <ntifs.h>
#include <windef.h>

extern PVOID PsGetProcessPeb(_In_ PEPROCESS Process); // 函数返回给定进程的进程环境块(Process Environment Block,PEB)的指针
NTKERNELAPI NTSTATUS PsLookupProcessByProcessId(HANDLE ProcessId, PEPROCESS* Process); // 此函数通过给定的进程 ID 查找对应的进程,并将进程的 EPROCESS 结构指针存储在提供的指针变量中。
extern NTKERNELAPI PVOID PsGetProcessWow64Process(_In_ PEPROCESS Process); // 此函数返回给定进程的 Wow64 进程环境的指针。Wow64 进程环境是用于在 64 位 Windows 上运行 32 位应用程序的兼容性层。
extern NTKERNELAPI UCHAR* PsGetProcessImageFileName(IN PEPROCESS Process); // 此函数返回给定进程的映像文件名,即执行该进程的可执行文件的名称。
extern NTKERNELAPI HANDLE PsGetProcessInheritedFromUniqueProcessId(IN PEPROCESS Process); // 此函数返回给定进程所继承的唯一进程 ID,即父进程ID。

typedef struct
{
DWORD Pid;
UCHAR ProcessName[2048];
DWORD Handle;
LIST_ENTRY ListEntry;
} ProcessList;

// 根据进程ID返回进程EPROCESS结构体失败返回NULL
PEPROCESS LookupProcess(HANDLE Pid)
{
PEPROCESS eprocess = NULL;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
Status = PsLookupProcessByProcessId(Pid, &eprocess);
if (NT_SUCCESS(Status))
{
return eprocess;
}
return NULL;
}

// 内核链表操作
BOOLEAN GetAllProcess()
{
PEPROCESS eproc = NULL;
LIST_ENTRY linkListHead;

// 初始化链表头部
InitializeListHead(&linkListHead);
ProcessList* pData = NULL;

for (int temp = 0; temp < 100000; temp += 4) // pid 一定是4的整数倍
{
eproc = LookupProcess((HANDLE)temp);
if (eproc != NULL)
{
STRING nowProcessnameString = { 0 };
RtlInitString(&nowProcessnameString, PsGetProcessImageFileName(eproc));

// 分配内核堆空间
pData = (ProcessList*)ExAllocatePool(PagedPool, sizeof(ProcessList));
RtlZeroMemory(pData, sizeof(ProcessList));

// 设置变量
pData->Pid = (DWORD)PsGetProcessId(eproc);
RtlCopyMemory(pData->ProcessName, PsGetProcessImageFileName(eproc), strlen(PsGetProcessImageFileName(eproc)));
pData->Handle = (DWORD)PsGetProcessInheritedFromUniqueProcessId(eproc);

// 插入元素
InsertTailList(&linkListHead, &pData->ListEntry);
ObDereferenceObject(eproc); // 内核对象引用计数+1
}
}

// 输出链表内的数据
while (!IsListEmpty(&linkListHead))
{
LIST_ENTRY* pEntry = RemoveHeadList(&linkListHead);
pData = CONTAINING_RECORD(pEntry, ProcessList, ListEntry);

DbgPrint("Pid[%d], ProcessName[%s], Handle[0x%x] \n", pData->Pid, pData->ProcessName, pData->Handle);
ExFreePool(pData);
}
return TRUE;
}

// 绕过签名检查
BOOLEAN BypassCheckSign(PDRIVER_OBJECT pDriverObject)
{
#ifdef _WIN64
typedef struct _KLDR_DATA_TABLE_ENTRY
{
LIST_ENTRY listEntry;
ULONG64 __Undefined1;
ULONG64 __Undefined2;
ULONG64 __Undefined3;
ULONG64 NonPagedDebugInfo;
ULONG64 DllBase;
ULONG64 EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING path;
UNICODE_STRING name;
ULONG Flags;
USHORT LoadCount;
USHORT __Undefined5;
ULONG64 __Undefined6;
ULONG CheckSum;
ULONG __padding1;
ULONG TimeDateStamp;
ULONG __padding2;
} KLDR_DATA_TABLE_ENTRY, * PKLDR_DATA_TABLE_ENTRY;
#else
typedef struct _KLDR_DATA_TABLE_ENTRY
{
LIST_ENTRY listEntry;
ULONG unknown1;
ULONG unknown2;
ULONG unknown3;
ULONG unknown4;
ULONG unknown5;
ULONG unknown6;
ULONG unknown7;
UNICODE_STRING path;
UNICODE_STRING name;
ULONG Flags;
} KLDR_DATA_TABLE_ENTRY, * PKLDR_DATA_TABLE_ENTRY;
#endif

PKLDR_DATA_TABLE_ENTRY pLdrData = (PKLDR_DATA_TABLE_ENTRY)pDriverObject->DriverSection;
pLdrData->Flags = pLdrData->Flags | 0x20;

return TRUE;
}



// 卸载驱动
void UnloadDriver(PDRIVER_OBJECT driver)
{
DbgPrint("Uninstall Driver Is Ok \n");
}

// 驱动入口地址
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{

if (BypassCheckSign(Driver))
DbgPrint("Bypass Sign Success.");


DbgPrint("Driver loaded. \n");

GetAllProcess();

Driver->DriverUnload = UnloadDriver;
return STATUS_SUCCESS;

}

【驱动】4-内核下遍历系统当前进程
https://hodlyounger.github.io/2024/11/29/A_OS/Windows/驱动/windows驱动开发教程/【驱动】4-内核下遍历系统当前进程/
作者
mingming
发布于
2024年11月29日
许可协议