This page looks best with JavaScript enabled

驱动实现内存读写

 ·  ☕ 4 min read · 👀... views

在一些强对抗环境下,当我们试图在三环下用API去读取别的进程的内存往往会收到诸多限制,比如r3花式hook,r0句柄降权,改进程结构体等等等等,稍微有些保护就可以使得 ReadProcessMemory、WriteProcessMemory 这些API失效,因此需要设计驱动能在r0层读写内存。

这里我的驱动读直接就是KeStackAttachProcess切换内核到要读进程的上下文去把那块内存复制出来;写用的是MDL,MDL的原理这里不过多阐述、百度里资料很多,简单说就是做了一个应用层内存到内核态的一个映射(严格来说是同一块物理内存同时映射到用户态空间和核心态空间)。直接附加和MDL都是较为简单好用的方法,而且基本能过大部分保护了,这里做一个记录

ReadWriteProcess.h

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// ReadWriteProcess.h

#include<ntifs.h>
#include<windef.h>

/* 调试辅助函数 */
#define printfs(x, ...) DbgPrintEx(0, 0, x, __VA_ARGS__)

/* 传递信息的结构 */
typedef struct _UserData
{
	DWORD Pid;							//要读写的进程ID
	DWORD64 Address;				//要读写的地址
	DWORD Size;							//读写长度
	PBYTE Data;								//要读写的数据
}UserData, *PUserData;

Driver.c

  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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
// Driver.c

#include "ReadWriteProcess.h"

// Qfrost_DriverReadWriteProcess
UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\Qfrost_DriverReadWriteProcess");
UNICODE_STRING DeviceLink = RTL_CONSTANT_STRING(L"\\??\\Qfrost_DriverReadWriteProcess");

//读取内存
VOID MdlReadProcessMemory(PUserData Buffer)
{
	//打开目标进程
	PEPROCESS Process = NULL;
	NTSTATUS Status = PsLookupProcessByProcessId((HANDLE)Buffer->Pid, &Process);
	if (!NT_SUCCESS(Status))
	{
		printfs("[Mdl] : Read PsLookupProcessByProcessId函数失败\n");
		return;
	}

	//申请内存空间
	PBYTE Temp = ExAllocatePool(PagedPool, Buffer->Size);
	if (Temp == NULL)
	{
		printfs("[Mdl] : Read ExAllocatePool函数失败\n");
		ObDereferenceObject(Process);
		return;
	}
	else
		memset(Temp, 0, Buffer->Size);

	//附加进程
	KAPC_STATE Stack = { 0 };
	KeStackAttachProcess(Process, &Stack);
	
	__try {
		//检查内存
		ProbeForRead((PVOID)Buffer->Address, Buffer->Size, 1);
		// STATUS_ACCESS_VIOLATION: 内存范围不在该进程地址空间
		// STATUS_DATATYPE_MISALIGNMENT: 地址范围开始未按Alignment粒度对其

		//复制内存
		RtlCopyMemory(Temp, (PVOID)Buffer->Address, Buffer->Size);

	}
	except(EXCEPTION_EXECUTE_HANDLER) {
		printfs("[Mdl] : %X 内存读取失败, 地址不在该进程内存范围内\n", Buffer->Address);
	}
	//结束附加
	KeUnstackDetachProcess(&Stack);
	//解除引用
	ObDereferenceObject(Process);


	//复制到我们的缓冲区
	RtlCopyMemory(Buffer->Data, Temp, Buffer->Size);

	//释放内存
	ExFreePool(Temp);
}

//写入内存
VOID MdlWriteProcessMemory(PUserData Buffer)
{
	// KdBreakPoint();
	//打开目标进程
	PEPROCESS Process = NULL;
	NTSTATUS Status = PsLookupProcessByProcessId((HANDLE)Buffer->Pid, &Process);
	if (!NT_SUCCESS(Status))
	{
		printfs("[Mdl] : Write PsLookupProcessByProcessId函数失败\n");
		return;
	}

	//申请内存空间
	PBYTE Temp = ExAllocatePool(PagedPool, Buffer->Size);
	if (Temp == NULL)
	{
		printfs("[Mdl] : Write ExAllocatePool函数失败\n");
		ObDereferenceObject(Process);
		return;
	}

	// 复制内存数据
	RtlCopyMemory(Temp, Buffer->Data, Buffer->Size);

	//附加进程
	KAPC_STATE Stack = { 0 };
	KeStackAttachProcess(Process, &Stack);

	//检查内存
	__try {
		ProbeForWrite((PVOID)Buffer->Address, Buffer->Size, 1);
	}
	except(EXCEPTION_EXECUTE_HANDLER) {
		printfs("[Mdl] : %X 内存写入失败, 地址不在该进程内存范围内\n", Buffer->Address);
		KeUnstackDetachProcess(&Stack);
		ObDereferenceObject(Process);
		ExFreePool(Temp);
		return;
	}

	
	//申请MDL
	PMDL Mdl = IoAllocateMdl((PVOID)Buffer->Address, Buffer->Size, FALSE, FALSE, NULL);
	if (Mdl == NULL)
	{
		printfs("[Mdl] : IoAllocateMdl函数失败\n");
		ExFreePool(Temp);
		KeUnstackDetachProcess(&Stack);
		ObDereferenceObject(Process);
		return;
	}

	//建设物理页面
	MmBuildMdlForNonPagedPool(Mdl);
	__try {
		//锁定页面
		PBYTE ChangeData = MmMapLockedPages(Mdl, KernelMode);
		//复制内存
		if (ChangeData) RtlCopyMemory(ChangeData, Temp, Buffer->Size);
	}
	except(EXCEPTION_EXECUTE_HANDLER) {
		printfs("[Mdl] : %X 内存写入失败, MmMapLockedPages Error!\n", Buffer->Address);
	}

	//释放数据
	IoFreeMdl(Mdl);
	ExFreePool(Temp);

	KeUnstackDetachProcess(&Stack);
	ObDereferenceObject(Process);
}

//驱动分发函数
NTSTATUS DriverIoctl(PDEVICE_OBJECT Device, PIRP pirp)
{
	//未引用
	UNREFERENCED_PARAMETER(Device);

	//获取堆栈
	PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(pirp);

	//获取控制码
	ULONG Code = Stack->Parameters.DeviceIoControl.IoControlCode;

	if (Stack->MajorFunction == IRP_MJ_DEVICE_CONTROL)
	{
		//获取数据指针
		PUserData Buffer = pirp->AssociatedIrp.SystemBuffer;

		if (Code == Mdl_Read) {
			MdlReadProcessMemory(Buffer); //读取内存
			printfs("[Mdl Read] : PID:%d  地址:%x  大小:%d\n", Buffer->Pid, Buffer->Address, Buffer->Size);
		}
		if (Code == Mdl_Write) {
			MdlWriteProcessMemory(Buffer);//写入内存
			printfs("[Mdl Write] : PID:%d  地址:%x  大小:%d\n", Buffer->Pid, Buffer->Address, Buffer->Size);

		}

		pirp->IoStatus.Information = sizeof(UserData);
	}
	else pirp->IoStatus.Information = 0;

	//完成IO
	pirp->IoStatus.Status = STATUS_SUCCESS;
	IoCompleteRequest(pirp, IO_NO_INCREMENT);

	return STATUS_SUCCESS;
}

//驱动卸载函数
VOID DriverUnload(PDRIVER_OBJECT object)
{
	if (object->DeviceObject)
	{
		IoDeleteSymbolicLink(&DeviceLink);
		IoDeleteDevice(object->DeviceObject);
	}
	printfs("[Mdl] : 驱动卸载成功\n");
}

//驱动入口函数
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
	printfs("[Mdl] : 驱动注册表 -> %wZ\n", RegistryPath);

	//设置卸载函数
	DriverObject->DriverUnload = DriverUnload;

	//创建设备
	PDEVICE_OBJECT Device = NULL;
	NTSTATUS Status = IoCreateDevice(DriverObject, sizeof(DriverObject->DriverExtension), &DeviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &Device);
	if (!NT_SUCCESS(Status))
	{
		printfs("[Mdl] : IoCreateDevice函数失败\n");
		return Status;
	}

	//创建链接
	Status = IoCreateSymbolicLink(&DeviceLink, &DeviceName);
	if (!NT_SUCCESS(Status))
	{
		printfs("[Mdl] : IoCreateSymbolicLink函数失败\n");
		IoDeleteDevice(Device);
		return Status;
	}

	//设置派遣函数
	DriverObject->MajorFunction[IRP_MJ_CREATE] = DriverIoctl;
	DriverObject->MajorFunction[IRP_MJ_CLOSE] = DriverIoctl;
	DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DriverIoctl;

	printfs("[Mdl] : 驱动加载成功\n");
	return STATUS_SUCCESS;
}
Share on

Qfrost
WRITTEN BY
Qfrost
CTFer, Anti-Cheater, LLVM Committer