Windows内核态开发笔记

r3/r0通信

用户态

#include <Windows.h>
#include <stdio.h>

#define SENDSTR CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
void main() {
    HANDLE device = CreateFileW(L"\\\\.\\cc", GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);

    if (device == INVALID_HANDLE_VALUE) {
        printf("获取驱动句柄失败! 错误:%d\n", GetLastError());
        getchar();
        return;
    }
    const char* msg = "hello cccccccccc";
    char response[256] = { 0 };
    DWORD size = 0;
    DWORD bytesReturned = 0;
    if (!DeviceIoControl(device, SENDSTR, (LPVOID)msg, strlen(msg) + 1, response, sizeof(response), &bytesReturned, 0)) {
        printf("发送消息失败! 错误:%d\n", GetLastError());
    }
    else {
        printf("发送消息成功! 输出缓冲区大小:%d\n", bytesReturned);
        printf("从内核收到的回复: %s\n", response);
    }
    getchar();
    CloseHandle(device);
}

内核态

#include "ntddk.h"
#define SYMBOLLINK L"\\??\\cc"
//生成一个自己设备控制请求功能号 0-7ff 被微软保留,只能用比这大的
#define SENDSTR CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
PDEVICE_OBJECT dev = NULL; //控制设备
VOID DriverUnload(PDRIVER_OBJECT DriverObject)
{
	if (DriverObject != NULL)
	{
		UNICODE_STRING SymbolName;//符号链接
		RtlInitUnicodeString(&SymbolName, SYMBOLLINK);
		IoDeleteSymbolicLink(&SymbolName);//删除符号链接
		if (dev != NULL)
		{
			IoDeleteDevice(dev);
		}
		DbgPrint("删除设备和符号链接成功");
	}
}
NTSTATUS CreateDevice(PDRIVER_OBJECT DriverObject) {
	NTSTATUS Status;  //返回状态
	UNICODE_STRING DeviceName; //设备名称
	UNICODE_STRING SymbolName;//符号链接
	RtlInitUnicodeString(&DeviceName, L"\\Device\\cc");
	Status = IoCreateDevice(
		DriverObject,
		0,
		&DeviceName,
		FILE_DEVICE_UNKNOWN,
		0,
		TRUE, //是否是独占设备,安全软件一般都是独占,由某个进程打开着永不关闭
		&dev
	);
	do
	{
		if (!NT_SUCCESS(Status)) {
			if (Status == STATUS_OBJECT_NAME_COLLISION)
			{
				DbgPrint("设备名称冲突");
			}
			DbgPrint("创建失败");
			break;
		}
		//初始化符号链接  设备名称应用程序是不可见的,因此驱动要暴露一个符号链接给应用层
		RtlInitUnicodeString(&SymbolName, SYMBOLLINK);
		Status = IoCreateSymbolicLink(&SymbolName, &DeviceName);
		if (!NT_SUCCESS(Status)) { //不等于0
			IoDeleteDevice(dev); //删除设备
			DbgPrint("删除设备成功");
			break;
		}
		else {
			DbgPrint("创建符号链接成功");
		}
	} while (FALSE);//仅执行一次的经典写法,为内核态的跳出格式
	return Status;
}
NTSTATUS fDispatch(PDEVICE_OBJECT pdev, PIRP irp) {
	UNREFERENCED_PARAMETER(pdev);
	NTSTATUS Status = STATUS_SUCCESS;  //返回状态
	ULONG len = 0;
	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(irp);
	ULONG inBufferLength = stack->Parameters.DeviceIoControl.InputBufferLength;
	ULONG outBufferLength = stack->Parameters.DeviceIoControl.OutputBufferLength;
	PVOID inBuffer = (PCHAR)irp->AssociatedIrp.SystemBuffer;
	if (stack->MajorFunction == IRP_MJ_DEVICE_CONTROL)
	{
		//处理DeviceIoControl
		switch (stack->Parameters.DeviceIoControl.IoControlCode)
		{
		case SENDSTR:
			if (inBufferLength > 0 && inBuffer != NULL) {
				DbgPrint("Received message from user: %s\n",(char*) inBuffer);
				char response[10] = "coleak";
				ULONG responseLength = (ULONG)strlen(response) + 1;
				if (outBufferLength >= responseLength) {
					RtlZeroMemory(inBuffer, outBufferLength);
					RtlCopyMemory(inBuffer, response, responseLength);
					len = responseLength;
				}
				else {
					Status = STATUS_BUFFER_TOO_SMALL;
					irp->IoStatus.Information = 0;
				}
				break;
			}
		default:
			//到这里的请求都是不接受的请求,返回参数错误
			Status = STATUS_INVALID_PARAMETER;
			break;
		}
	}
	irp->IoStatus.Information = len;
	irp->IoStatus.Status = Status;
	IoCompleteRequest(irp, IO_NO_INCREMENT);
	return  Status;
}

NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING  RegistryPath)
{
	//KdBreakPoint(); 

	if (RegistryPath != NULL)
	{
		DbgPrint("[%ws]所在注册表位置:%wZ\n", __FUNCTIONW__, RegistryPath);
	}
	if (DriverObject != NULL)
	{
		DbgPrint("[%ws]驱动对象地址:%p\n", __FUNCTIONW__, DriverObject);

		//创建控制设备
		CreateDevice(DriverObject);

		//设置分发函数
		for (ULONG i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
		{
			DriverObject->MajorFunction[i] = fDispatch;
		}
		DriverObject->DriverUnload = DriverUnload;
		DbgPrint("驱动加载成功");
	}
	return STATUS_SUCCESS;
}

浅记

  • CreateFileW的dwFlagsAndAttributes为FILE_ATTRIBUTE_SYSTEM,该文件是操作系统的一部分或由操作系统独占使用

  • DeviceIoControl设置功能号和r0进行通信,r0应该设置对应的的功能号以便判断IoControlCode后处理该请求

  • 用户态的链接符号格式为\\\\.\\链接名,内核态链接符号格式为\\??\\链接名

  • UNREFERENCED_PARAMETER可以忽略参数未使用的报错

  • METHOD_BUFFERED通信中内核的输入和输出缓冲区均为irp->AssociatedIrp.SystemBuffer

x64 HOOK

windbg调试下结构

cmd下:bcdedit -debug on
.sympath srv*C:\symbols\microsoft*https://msdl.microsoft.com/download/symbols
.reload
rdmsr C0000082
u fffff807`6502b800	(nt!KiSystemCall64)
u...
找到如下
nt!KiSystemServiceRepeat:
fffff807`6502bb64 4c8d15555d9d00  lea     r10,[nt!KeServiceDescriptorTable (fffff807`65a018c0)]
fffff807`6502bb6b 4c8d1d8e258f00  lea     r11,[nt!KeServiceDescriptorTableShadow (fffff807`6591e100)]
特征码:4c8d15
这里的fffff807`65a018c0=fffff807`6502bb6b+9d5d55

接下来找sysnumber
u zwopenprocess
nt!ZwOpenProcess+0x14:
fffff800`72c13414 b826000000      mov     eax,26h
fffff800`72c13419 e962830100      jmp     nt!KiServiceInternal (fffff800`72c2b780)
这里的26h也就是表中的38
dd KeServiceDescriptorTable
fffff800`736018c0  728cfb80 fffff800 00000000 00000000
fffff800`736018d0  000001e6 00000000 728d031c fffff800
这里主要找四个字节的偏移量ServiceTableBase

内核态

#include "ntddk.h"
#include<intrin.h>
#include "c.h"
PVOID oldfun = NULL;
ULONG funoffset = 0;
typedef NTSTATUS(*pNtOpenProcess)(
	_Out_ PHANDLE ProcessHandle,
	_In_ ACCESS_MASK DesiredAccess,
	_In_ POBJECT_ATTRIBUTES ObjectAttributes,
	_In_opt_ PCLIENT_ID ClientId
	);
KIRQL WPOFFx64()
{
	KIRQL irql = KeRaiseIrqlToDpcLevel();
	UINT64 cr0 = __readcr0();
	cr0 &= 0xfffffffffffeffff;
	__writecr0(cr0);
	_disable();
	return irql;
}
void WPONx64(KIRQL irql)
{
	UINT64 cr0 = __readcr0();
	cr0 |= 0x10000;
	_enable();
	__writecr0(cr0);
	KeLowerIrql(irql);
}
typedef struct _SERVICE_DESCRIPTOR_TABLE
{
	PVOID ServiceTableBase;
	PVOID ServiceCounterTableBase;
	ULONGLONG  NumberOfService;//SSDT表中服务函数的总数
	PVOID ParamTableBase;
} SSDTEntry, * PSSDTEntry;
NTSTATUS myNtOpenProcess(
	_Out_ PHANDLE ProcessHandle,
	_In_ ACCESS_MASK DesiredAccess,
	_In_ POBJECT_ATTRIBUTES ObjectAttributes,
	_In_opt_ PCLIENT_ID ClientId
) {
	DbgPrint("打开了一个进程:ClientId---%ld", ClientId->UniqueProcess);
	return ((pNtOpenProcess)oldfun)(ProcessHandle, DesiredAccess, ObjectAttributes, ClientId);
}
ULONGLONG Get_SSDT_Base()
{
	PUCHAR Base = (PUCHAR)__readmsr(0xC0000082);      // 读取C0000082寄存器
	PUCHAR Address = Base + 0x500;                    // 相加偏移
	PUCHAR i = NULL;
	UCHAR b1 = 0, b2 = 0, b3 = 0;                     // 保存特征码
	ULONG templong = 0;
	ULONGLONG addr = 0;                               // 最后获取到的地址
	for (i = Base; i < Address; i++)
	{
		if (MmIsAddressValid(i) && MmIsAddressValid(i + 1) && MmIsAddressValid(i + 2))
		{
			b1 = *i; b2 = *(i + 1); b3 = *(i + 2);
			if (b1 == 0x4c && b2 == 0x8d && b3 == 0x15)   // 判断是否=4c8d15
			{
				memcpy(&templong, i + 3, 4);              // 在i+3位置拷贝,拷贝4字节
				addr = (ULONGLONG)templong + (ULONGLONG)i + 7;
				return addr;
			}
		}
	}
	return addr;
}
VOID unhook() {
	PSSDTEntry ssdt = (PSSDTEntry)Get_SSDT_Base();
	PULONG stb = (PULONG)(ssdt->ServiceTableBase);
	KIRQL irql = WPOFFx64();//关保护
	stb[38] = funoffset;
	WPONx64(irql);
	DbgPrint("unhook");
}
ULONGLONG GetSSDTFunction(ULONG Index)
{
	PSSDTEntry ssdt = (PSSDTEntry)Get_SSDT_Base();
	PULONG stb = (PULONG)(ssdt->ServiceTableBase);
	LONG qwTemp = stb[Index];
	qwTemp = qwTemp >> 4;
	return (ULONGLONG)stb + (ULONGLONG)qwTemp;
}
ULONG getOffset(ULONGLONG addrFunction)
{
	PSSDTEntry ssdt = (PSSDTEntry)Get_SSDT_Base();
	PULONG stb = (PULONG)(ssdt->ServiceTableBase);
	LONG tmp = (LONG)(addrFunction - (ULONGLONG)stb);
	tmp = tmp << 4;
	return tmp;
}
VOID initKeBugCheckEx()
{
	/*
	  48 B8 xxxx    mov rax,XXXh;
	  FF E0      jmp rax
	*/
	UCHAR jmpCode[] = "\x48\xB8\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xE0";
	ULONGLONG proxyFunction = (ULONGLONG)myNtOpenProcess;  //自己的NtOpenProess
	memcpy(jmpCode + 2, &proxyFunction, 8);
	KIRQL irql = WPOFFx64();//关保护
	memcpy((void*)KeBugCheckEx, jmpCode, 12);
	WPONx64(irql);
}
VOID hookSSDT()
{
	oldfun = (PVOID)GetSSDTFunction(38);
	initKeBugCheckEx();

	PSSDTEntry ssdt = (PSSDTEntry)Get_SSDT_Base();
	PULONG stb = (PULONG)(ssdt->ServiceTableBase);
	funoffset = stb[38];

	KIRQL irql = WPOFFx64();//关保护
	stb[38] = getOffset((ULONGLONG)KeBugCheckEx);
	WPONx64(irql);
	DbgPrint("SSDT hooked");
}

VOID DriverUnload(PDRIVER_OBJECT DriverObject)
{
	UNREFERENCED_PARAMETER(DriverObject);
	unhook();
	DbgPrint("DriverUnload");
}
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING  RegistryPath)
{
	DbgPrint("DriverEntry");
	UNREFERENCED_PARAMETER(RegistryPath);
	DriverObject->DriverUnload = DriverUnload;
	hookSSDT();
	return STATUS_SUCCESS;
}

浅记

  • 通过修改cr0寄存器的WP位来关闭写保护,并提高IRQL到DPC级别
  • 通过读取MSR寄存器0xC0000082,并向下查找特征码4c 8d 15以定位SSDT的基地址
  • ServiceTableBase+偏移量(stb[Index])可以和获取函数的地址
  • 构造jmpCode修改KeBugCheckEx前12位进行jmp到我们的函数
  • 函数地址-ServiceTableBase然后左移四位即可获取偏移量

回调监控

进程通知

#include "ntddk.h"
NTKERNELAPI UCHAR* PsGetProcessImageFileName( PEPROCESS Process);
VOID PcreateProcessNotifyRoutineEx(
	PEPROCESS Process,
	HANDLE ProcessId,
	PPS_CREATE_NOTIFY_INFO CreateInfo //进程创建相关的信息
) {
	//为Null表示是进程结束的通知
	if (CreateInfo == NULL)
	{
		DbgPrint("进程结束id:%d 通知例程的当前线程ID:%d \n----------",(LONG) ProcessId, (LONG)PsGetCurrentThreadId());
		return;
	}
	/*
	进程创建通知
	*/
	//获取进程的信息
	PCUNICODE_STRING ImageFileName = CreateInfo->ImageFileName;//进程名称
	HANDLE parentprocessid = CreateInfo->CreatingThreadId.UniqueProcess;//父进程id
	HANDLE parentthreadid = CreateInfo->CreatingThreadId.UniqueThread;//父进程线程id

	DbgPrint("通知例程的当前线程ID:%d 创建进程id:%d  父进程id:%d  父进程线程id:%d  进程名称:%wZ\n----------",
		(LONG)PsGetCurrentThreadId(),
		(LONG)ProcessId,
		(LONG)parentprocessid,
		(LONG)parentthreadid,
		ImageFileName
	);

	//在这里可以对进程进行监控,例如对指定进程禁止创建
	PUCHAR imageName = PsGetProcessImageFileName(Process);

	if (strcmp((const char*)imageName, "aaa.exe") == 0)
	{
		CreateInfo->CreationStatus = STATUS_ACCESS_DENIED;//拒绝操作
		DbgPrint("拦截了你创建进程:%wZ", imageName);
	}
}
VOID DriverUnload(PDRIVER_OBJECT DriverObject)
{
	UNREFERENCED_PARAMETER(DriverObject);
	PsSetCreateProcessNotifyRoutineEx(PcreateProcessNotifyRoutineEx, TRUE);
	DbgPrint("驱动卸载完成----------");

}
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING  RegistryPath)
{
	UNREFERENCED_PARAMETER(RegistryPath);
	PsSetCreateProcessNotifyRoutineEx(PcreateProcessNotifyRoutineEx, FALSE);
	DbgPrint("驱动加载完成----------");
	DriverObject->DriverUnload = DriverUnload;
	return STATUS_SUCCESS;
}

浅记

  • PsSetCreateProcessNotifyRoutineEx对进程创建前进行回调,获得新进程handle、pid和CreateInfo
  • PsGetProcessImageFileName可以通过进程句柄获取进程的主模块路径,已导出需要声明

模块加载通知拦截

#include <ntifs.h>//PsLookupProcessByProcessId
#include "ntddk.h"
#include <ntimage.h>//pe格式解析需要
#include "c.h"
NTSTATUS MmUnmapViewOfSection(PEPROCESS Process, PVOID BaseAddr);

typedef struct DATA {

	HANDLE processid;
	PVOID image;
} data, * pdata;

void loadImageNotifyRoutine(
	PUNICODE_STRING FullImageName,
	HANDLE ProcessId,
	PIMAGE_INFO ImageInfo //模块在内存中的加载基址
) {
	DbgPrint("PID:[%d]	FullImageName:[%wZ]	size:[%d]	Base:[%p]----------", (LONG)ProcessId, FullImageName, ImageInfo->ImageSize, ImageInfo->ImageBase);
	//把模块路径转成普通的字符串便于操作
	CHAR name[1024] = { 0 };
	ANSI_STRING temp;
	RtlUnicodeStringToAnsiString(&temp, FullImageName, TRUE);
	RtlCopyMemory(name, temp.Buffer, temp.Length);
	RtlFreeAnsiString(&temp);
	HANDLE thread = NULL;
	//ProcessId = 0表示是驱动模块
	if (ProcessId != 0)//dll或exe
	{
		//要卸载DLL必须要等到进程里的所有模块加载完毕之后,采用办法多线程延时等待
		if (strstr(name, "aaa.dll") != NULL)
		{
			pdata mydata = ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(data),'a');
			//pdata mydata = ExAllocatePool(NonPagedPool, sizeof(data)); //堆里面分配内存
			mydata->image = ImageInfo->ImageBase;
			mydata->processid = ProcessId;
			//避免死锁,创建多线程延迟1秒然后卸载
			PsCreateSystemThread(&thread, 0, NULL, NtCurrentProcess(), NULL, threadProc, mydata);
			DbgPrint("拦截了你的DLL:%s", name);
		}
	}
	else//驱动
	{
		if (strstr(name, "aaa.sys") != NULL)
		{
			disableDriver(ImageInfo->ImageBase);
			DbgPrint("拦截了你的驱动:%s", name);
		}
	}
}

//拒绝加载驱动
VOID disableDriver(PVOID pImageBase) {
	UCHAR code[6] = { 0xB8, 0x22, 0x00, 0x00, 0xC0, 0xC3 };//STATUS_ACCESS_DENIED mov eax,0xc0000022 ret

	//根据基址找到入口地址DriverEntry
	PIMAGE_DOS_HEADER dosheader = pImageBase;
	PIMAGE_NT_HEADERS ntheads = (PIMAGE_NT_HEADERS)((PUCHAR)dosheader + dosheader->e_lfanew);
	PVOID pDriverEntry = (PVOID)((PUCHAR)dosheader + ntheads->OptionalHeader.AddressOfEntryPoint);//基地址加上偏移找到入口

	/*修改前6个字节*/
	PMDL pmdl = MmCreateMdl(NULL, pDriverEntry, 6);
	MmBuildMdlForNonPagedPool(pmdl);

	PVOID addr = MmMapLockedPages(pmdl, KernelMode);
	RtlCopyMemory(addr, code, 6);
	MmUnmapLockedPages(addr, pmdl);
	IoFreeMdl(pmdl);
}

VOID threadProc(PVOID data) {
	pdata mydata = (pdata)data;
	LARGE_INTEGER time = { 0 };
	time.QuadPart = -10 * 1000 * 1000;//1秒
	KeDelayExecutionThread(KernelMode, FALSE, &time);//睡眠
	unDLL(mydata->processid, mydata->image);
	ExFreePool(mydata);
}

//调用 MmUnmapViewOfSection卸载 
VOID unDLL(HANDLE processid, PVOID image) {
	PEPROCESS pEprocess = NULL;
	PsLookupProcessByProcessId(processid, &pEprocess);
	MmUnmapViewOfSection(pEprocess, image); //强力卸载
}

VOID DriverUnload(PDRIVER_OBJECT DriverObject)
{
	PsRemoveLoadImageNotifyRoutine(loadImageNotifyRoutine);
	DbgPrint("驱动卸载完成----------");

}
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING  RegistryPath)
{
	PsSetLoadImageNotifyRoutine(loadImageNotifyRoutine);
	DbgPrint("驱动加载完成----------");
	DriverObject->DriverUnload = DriverUnload;
	return STATUS_SUCCESS;	
}

浅记

  • RtlAnsiStringToUnicodeString的AllocateDestinationString选项分配了内存,需要用rtlFreeAnsiString释放
  • PsLookupProcessByProcessId接受pid返回PEPROCESS ,MmUnmapViewOfSection(需要声明)接受PEPROCESS 和dllbase强行取消加载的dll,测试中发现容易不稳定导致进程直接结束
  • KeDelayExecutionThread完成sleep操作,负数为相对时间,单位为100纳秒
  • ExAllocatePool2分配的内存必须ExFreePool去释放
  • 拒绝驱动加载即在对方驱动DriverEntry返回STATUS_ACCESS_DENIED,即mov eax,0xc0000022; ret
  • MmCreateMdl本质是申请一个非分页内存。然后初始化为MDL, MmBuildMdlForNonPagedPool更新 MDL 对物理内存的描述,MmMapLockedPages映射到一个内核地址,MmUnmapLockedPages先解除锁定,IoFreeMdl然后再释放
  • MDL 是用来建立一块虚拟地址空间与物理页面之间的映射,当我们要对一块内核内存进行修改的时候,我们先为这块内存创建 MDL,那么就会建立一块新的虚拟内存空间,与将要修改内存对应的物理空间相映射。也就是说,同一块物理空间,映射了两块不同的虚拟内存地址。我们可以通过这两个虚拟内存地址,来操作这块物理内存,这便是 MDL 修改内存的实现思路

进程强杀

查找特征码

.sympath srv*C:\symbols\microsoft*https://msdl.microsoft.com/download/symbols
.reload
u PsTerminateSystemThread

nt!PsTerminateSystemThread:
fffff803`525a5290 4883ec28        sub     rsp,28h
fffff803`525a5294 8bd1            mov     edx,ecx
fffff803`525a5296 65488b0c2588010000 mov   rcx,qword ptr gs:[188h]
fffff803`525a529f f7417400040000  test    dword ptr [rcx+74h],400h
fffff803`525a52a6 0f84d6df1400    je      nt!PsTerminateSystemThread+0x14dff2 (fffff803`526f3282)
fffff803`525a52ac 41b001          mov     r8b,1
fffff803`525a52af e8ecb1fcff      call    nt!PspTerminateThreadByPointer (fffff803`525704a0)
fffff803`525a52b4 4883c428        add     rsp,28h

fffff803525704a0-fffff803525a52b4=FFFF FFFF FFFC B1EC,这里即fffcb1ec
#include <ntifs.h>
#include "ntddk.h"
#include "c.h"

typedef NTSTATUS(_fastcall* PSPTERMINATETHREADBYPOINTER)(PETHREAD Thread, NTSTATUS Exitstatus, BOOLEAN DirectTerminate);

VOID DriverUnload(PDRIVER_OBJECT DriverObject)
{
	DriverObject = DriverObject;//消除未引用警告
	DbgPrint("驱动卸载完成----------");

}
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING  RegistryPath)
{
	RegistryPath = RegistryPath;
	DbgPrint("驱动加载完成----------");
	KillProcess((HANDLE)3408);
	DriverObject->DriverUnload = DriverUnload;
	return STATUS_SUCCESS;
}

//从PsTerminateSystemThread里面找到PsTerminateThreadByPointer

PVOID getPsTerminateThreadByPointer() {
	UCHAR code = 0xe8;
	UNICODE_STRING FUNname;
	PVOID offset = NULL;
	RtlInitUnicodeString(&FUNname, L"PsTerminateSystemThread");

	//找到PsTerminateSystemThread地址
	PVOID pPsTerminateSystemThread = MmGetSystemRoutineAddress(&FUNname);
	if (pPsTerminateSystemThread == NULL)
	{
		DbgPrint("pPsTerminateSystemThread找不到----------");
		return 0;
	}

	//扫描内存找到PsTerminateThreadByPointer地址
	for (PUCHAR i = (PUCHAR)pPsTerminateSystemThread; i < ((PUCHAR)pPsTerminateSystemThread + 0xFF); i++)
	{
		//判断符合特征码地址
		if (*i == code)
		{
			offset = (PVOID)(i + 1);
			break;
		}
	}
	if (offset == NULL)
	{
		DbgPrint("OFFSET找不到----------");
		return 0;
	}
	//获取偏移计算地址
	LONG loffset = *(PLONG)offset;//取出偏移
	PVOID PsTerminateThreadByPointerAddress = (PVOID)((PUCHAR)offset + 4 + loffset);
	return PsTerminateThreadByPointerAddress;
}

//强杀进程
NTSTATUS KillProcess(HANDLE pid) {
	NTSTATUS status = STATUS_SUCCESS;
	PEPROCESS pEprocess = NULL;
	PEPROCESS ThreadProcess = NULL;
	PETHREAD pEthread = NULL;
	//获取PsTerminateThreadByPointer地址
	PVOID PsTerminateThreadByPointerAddress = getPsTerminateThreadByPointer();

	//获取结束进程的EPROCESS
	status = PsLookupProcessByProcessId(pid, &pEprocess);
	if (!NT_SUCCESS(status))
	{
		DbgPrint("PsLookupProcessByProcessId GG----------");
		return status;
	}
	//遍历所有线程,并结束指定进程的所有线程
	ULONG i = 0;
	for (i = 4; i < 0x80000; i += 4)
	{
		status = PsLookupThreadByThreadId((HANDLE)i, &pEthread);
		if (NT_SUCCESS(status))
		{
			//获取线程所属的进程的EPROCESS
			ThreadProcess = PsGetThreadProcess(pEthread);

			if (pEprocess == ThreadProcess)
			{
				((PSPTERMINATETHREADBYPOINTER)PsTerminateThreadByPointerAddress)(pEthread, 0, 1);
				DbgPrint(" thread:【%d】----------", i);

			}
			//lookup打开的必须释放掉
			ObDereferenceObject(pEthread);
		}

	}
	ObDereferenceObject(pEprocess);

	return status;
}
  • 根据特征码扫描内存,获取 PspTerminateThreadByPointer 函数地址
  • 调用 PsLookupProcessByProcessId 函数,根据将要结束进程 ID 获取对应的进程结构对象 EPROCESS
  • 遍历所有的线程 ID,并调用 PsLookupThreadByThreadId 函数根据线程 ID 获取对应的线程结构 ETHREAD
  • 调用函数 PsGetThreadProcess 获取线程结构 ETHREAD 对应的进程结构 EPROCESS
  • 通过判断该进程是不是我们指定要结束的进程,若是则调用PspTerminateThreadByPointer 函数结束线程;否则,继续遍历下一个线程 ID
  • 查杀指定进程的所有线程,所有线程被结束之后,进程也随之结束
  • 这里地址用PUCHAR计算进行位数对齐

minifilter

在vs2022中minifilter框架被移除,需要自己构建项目框架

https://github.com/microsoft/Windows-driver-samples/tree/main/filesys/miniFilter
https://blog.csdn.net/lyshark_csdn/article/details/134738527

需要手动在链接器-输入-依赖项中添加fltMgr.lib

代码框架:

#include <fltKernel.h>
#include <dontuse.h>
#include <suppress.h>
PFLT_FILTER gFilterHandle;

DRIVER_INITIALIZE DriverEntry;
NTSTATUS
DriverEntry(
    _In_ PDRIVER_OBJECT DriverObject,
    _In_ PUNICODE_STRING RegistryPath
);

NTSTATUS
PtInstanceSetup(
    _In_ PCFLT_RELATED_OBJECTS FltObjects,
    _In_ FLT_INSTANCE_SETUP_FLAGS Flags,
    _In_ DEVICE_TYPE VolumeDeviceType,
    _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType
);

VOID
PtInstanceTeardownStart(
    _In_ PCFLT_RELATED_OBJECTS FltObjects,
    _In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags
);

VOID
PtInstanceTeardownComplete(
    _In_ PCFLT_RELATED_OBJECTS FltObjects,
    _In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags
);

NTSTATUS
PtUnload(
    _In_ FLT_FILTER_UNLOAD_FLAGS Flags
);

NTSTATUS
PtInstanceQueryTeardown(
    _In_ PCFLT_RELATED_OBJECTS FltObjects,
    _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags
);

FLT_PREOP_CALLBACK_STATUS
PtPreOperationPassThrough(
    _Inout_ PFLT_CALLBACK_DATA Data,
    _In_ PCFLT_RELATED_OBJECTS FltObjects,
    _Flt_CompletionContext_Outptr_ PVOID* CompletionContext
);

FLT_POSTOP_CALLBACK_STATUS
PtPostOperationPassThrough(
    _Inout_ PFLT_CALLBACK_DATA Data,
    _In_ PCFLT_RELATED_OBJECTS FltObjects,
    _In_opt_ PVOID CompletionContext,
    _In_ FLT_POST_OPERATION_FLAGS Flags
);

// 回调函数集
CONST FLT_OPERATION_REGISTRATION Callbacks[] =
{
    // 创建时触发 PreOperation(之前回调函数) / PostOperation(之后回调函数)
    { IRP_MJ_CREATE, 0, PtPreOperationPassThrough, PtPostOperationPassThrough },
    // 读取时触发
    { IRP_MJ_READ, 0, PtPreOperationPassThrough, PtPostOperationPassThrough },
    // 写入触发
    { IRP_MJ_WRITE, 0, PtPreOperationPassThrough, PtPostOperationPassThrough },
    // 设置时触发
    { IRP_MJ_SET_INFORMATION, 0, PtPreOperationPassThrough, PtPostOperationPassThrough },
    // 结束标志
    { IRP_MJ_OPERATION_END }
};

//
//  This defines what we want to filter with FltMgr
//
CONST FLT_REGISTRATION FilterRegistration = {

    sizeof(FLT_REGISTRATION),         //  Size
    FLT_REGISTRATION_VERSION,           //  Version
    0,                                  //  Flags
    NULL,                               //  Context
    Callbacks,                          //  Operation callbacks
    PtUnload,                           //  MiniFilterUnload
    PtInstanceSetup,                    //  InstanceSetup
    PtInstanceQueryTeardown,            //  InstanceQueryTeardown
    PtInstanceTeardownStart,            //  InstanceTeardownStart
    PtInstanceTeardownComplete,         //  InstanceTeardownComplete
    NULL,                               //  GenerateFileName
    NULL,                            //  GenerateDestinationFileName
    NULL                                //  NormalizeNameComponent
};

// 当实例被安装时触发
NTSTATUS
PtInstanceSetup(
    _In_ PCFLT_RELATED_OBJECTS FltObjects,
    _In_ FLT_INSTANCE_SETUP_FLAGS Flags,
    _In_ DEVICE_TYPE VolumeDeviceType,
    _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType
)
{
    DbgPrint("PassThrough!PtInstanceSetup: Entered\n");
    return STATUS_SUCCESS;
}

// 当实例被销毁时触发
NTSTATUS
PtInstanceQueryTeardown(
    _In_ PCFLT_RELATED_OBJECTS FltObjects,
    _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags
)
{
    DbgPrint("PassThrough!PtInstanceQueryTeardown: Entered\n");
    return STATUS_SUCCESS;
}

// 实例解除绑定时触发
VOID
PtInstanceTeardownStart(
    _In_ PCFLT_RELATED_OBJECTS FltObjects,
    _In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags
)
{
    DbgPrint("PassThrough!PtInstanceTeardownStart: Entered\n");
}

// 实例解绑完成时触发
VOID
PtInstanceTeardownComplete(
    _In_ PCFLT_RELATED_OBJECTS FltObjects,
    _In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags
)
{
    DbgPrint("PassThrough!PtInstanceTeardownComplete: Entered\n");
}


/*************************************************************************
    MiniFilter initialization and unload routines.
*************************************************************************/

NTSTATUS
DriverEntry(
    _In_ PDRIVER_OBJECT DriverObject,
    _In_ PUNICODE_STRING RegistryPath
)
{
    NTSTATUS status;
    DbgPrint("PassThrough!DriverEntry: Entered\n");
    status = FltRegisterFilter(DriverObject,
        &FilterRegistration,
        &gFilterHandle);
    if (NT_SUCCESS(status)) {
        status = FltStartFiltering(gFilterHandle);
        if (!NT_SUCCESS(status)) {
            FltUnregisterFilter(gFilterHandle);
            DbgPrint("[过滤器] 取消注册.. \n");
        }
        DbgPrint("[过滤器] 开启监控.. \n");
    }
    return status;
}

NTSTATUS
PtUnload(
    _In_ FLT_FILTER_UNLOAD_FLAGS Flags
)
{
    DbgPrint("PassThrough!PtUnload: Entered\n");
    FltUnregisterFilter(gFilterHandle);
    return STATUS_SUCCESS;
}

/*************************************************************************
    MiniFilter callback routines.
*************************************************************************/
FLT_PREOP_CALLBACK_STATUS
PtPreOperationPassThrough(
    _Inout_ PFLT_CALLBACK_DATA Data,
    _In_ PCFLT_RELATED_OBJECTS FltObjects,
    _Flt_CompletionContext_Outptr_ PVOID* CompletionContext
)
{
    NTSTATUS status;
    // 获取文件路径

    UCHAR MajorFunction = Data->Iopb->MajorFunction;
    PFLT_FILE_NAME_INFORMATION lpNameInfo = NULL;

    // 得到文件名相关信息
    status = FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &lpNameInfo);
    if (NT_SUCCESS(status))
    {
        status = FltParseFileNameInformation(lpNameInfo);
        if (NT_SUCCESS(status))
        {
            // 创建
            if (IRP_MJ_CREATE == MajorFunction)
            {
                DbgPrint("[创建文件时] %wZ", &lpNameInfo->Name);
                // 拒绝创建
                // STATUS_INSUFFICIENT_RESOURCES                 提示不是有效的资源
                // STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY  静默拒绝
                // STATUS_ACCESS_DENIED                          提示访问拒绝
                // return STATUS_ACCESS_DENIED;
                // return FLT_PREOP_COMPLETE;
            }
            // 读取
            else if (IRP_MJ_READ == MajorFunction)
            {
                DbgPrint("[读取文件] %wZ", &lpNameInfo->Name);
                // return FLT_PREOP_COMPLETE;
            }
            // 文件写入
            else if (IRP_MJ_WRITE == MajorFunction)
            {
                DbgPrint("[写入文件] %wZ", &lpNameInfo->Name);
                // return FLT_PREOP_COMPLETE;
            }
            // 修改文件信息
            else if (IRP_MJ_SET_INFORMATION == MajorFunction)
            {
                DbgPrint("[修改文件] %wZ", &lpNameInfo->Name);
                // return FLT_PREOP_COMPLETE;
            }
        }
        FltReleaseFileNameInformation(lpNameInfo);
    }
    return FLT_PREOP_SUCCESS_WITH_CALLBACK;
}

FLT_POSTOP_CALLBACK_STATUS
PtPostOperationPassThrough(
    _Inout_ PFLT_CALLBACK_DATA Data,
    _In_ PCFLT_RELATED_OBJECTS FltObjects,
    _In_opt_ PVOID CompletionContext,
    _In_ FLT_POST_OPERATION_FLAGS Flags
)
{
    return FLT_POSTOP_FINISHED_PROCESSING;
}

FltReleaseFileNameInformation需要放到FltGetFileNameInformation返回成功的逻辑里,否则会计数减失败从而造成蓝屏

注意:

Post-operation callback routines are called in an arbitrary thread context, at IRQL <= DISPATCH_LEVEL. Because this callback routine can be called at IRQL DISPATCH_LEVEL, it is subject to the following constraints:

  • It cannot safely call any kernel-mode routine that must run at a lower IRQL.
  • Any data structures used in this routine must be allocated from nonpaged pool.
  • It cannot be made pageable.
  • It cannot acquire resources, mutexes, or fast mutexes. However, it can acquire spin locks.
  • It cannot get, set, or delete contexts, but it can release contexts.

由于inf第三方没有签名,所以用c++进行手动加载添加注册表和服务

#include<windows.h>
#include <winsvc.h>
#include <winioctl.h>
#include <iostream>
BOOL InstallDriver(const char* lpszDriverName, const char* lpszDriverPath, const char* lpszAltitude);
BOOL StartDriver(const char* lpszDriverName);
BOOL StopDriver(const char* lpszDriverName);
BOOL DeleteDriver(const char* lpszDriverName);
BOOL InstallDriver(const char* lpszDriverName, const char* lpszDriverPath, const char* lpszAltitude)
{
    char    szTempStr[MAX_PATH];
    HKEY    hKey;
    DWORD    dwData;
    char    szDriverImagePath[MAX_PATH];
    if (NULL == lpszDriverName || NULL == lpszDriverPath)
    {
        return FALSE;
    }
    //得到完整的驱动路径
    GetFullPathNameA(lpszDriverPath, MAX_PATH, szDriverImagePath, NULL);

    SC_HANDLE hServiceMgr = NULL;// SCM管理器的句柄
    SC_HANDLE hService = NULL;// NT驱动程序的服务句柄

    //打开服务控制管理器
    hServiceMgr = OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if (hServiceMgr == NULL)
    {
        // OpenSCManager失败
        CloseServiceHandle(hServiceMgr);
        return FALSE;
    }

    // OpenSCManager成功  

    //创建驱动所对应的服务
    hService = CreateServiceA(hServiceMgr,
        lpszDriverName,             // 驱动程序的在注册表中的名字
        lpszDriverName,             // 注册表驱动程序的DisplayName 值
        SERVICE_ALL_ACCESS,         // 加载驱动程序的访问权限
        SERVICE_FILE_SYSTEM_DRIVER, // 表示加载的服务是文件系统驱动程序
        SERVICE_DEMAND_START,       // 注册表驱动程序的Start 值
        SERVICE_ERROR_IGNORE,       // 注册表驱动程序的ErrorControl 值
        szDriverImagePath,          // 注册表驱动程序的ImagePath 值
        "FSFilter Activity Monitor",// 注册表驱动程序的Group 值
        NULL,
        "FltMgr",                   // 注册表驱动程序的DependOnService 值
        NULL,
        NULL);

    if (hService == NULL)
    {
        if (GetLastError() == ERROR_SERVICE_EXISTS)
        {
            //服务创建失败,是由于服务已经创立过
            CloseServiceHandle(hService);       // 服务句柄
            CloseServiceHandle(hServiceMgr);    // SCM句柄
            printf("already create");
            return TRUE;
        }
        else
        {
            CloseServiceHandle(hService);       // 服务句柄
            CloseServiceHandle(hServiceMgr);    // SCM句柄
            return FALSE;
        }
    }
    CloseServiceHandle(hService);       // 服务句柄
    CloseServiceHandle(hServiceMgr);    // SCM句柄

    //-------------------------------------------------------------------------------------------------------
    // SYSTEM\\CurrentControlSet\\Services\\DriverName\\Instances子健下的键值项 
    //-------------------------------------------------------------------------------------------------------
    strcpy_s(szTempStr, "SYSTEM\\CurrentControlSet\\Services\\");
    strcat_s(szTempStr, lpszDriverName);
    strcat_s(szTempStr, "\\Instances");
    if (RegCreateKeyExA(HKEY_LOCAL_MACHINE, szTempStr, 0, NULL, TRUE, KEY_ALL_ACCESS, NULL, &hKey, (LPDWORD)&dwData) != ERROR_SUCCESS)
    {
        return FALSE;
    }
    // 注册表驱动程序的DefaultInstance 值 
    strcpy_s(szTempStr, lpszDriverName);
    strcat_s(szTempStr, " Instance");
    if (RegSetValueExA(hKey, "DefaultInstance", 0, REG_SZ, (CONST BYTE*)szTempStr, (DWORD)strlen(szTempStr)) != ERROR_SUCCESS)
    {
        return FALSE;
    }
    RegFlushKey(hKey);//刷新注册表
    RegCloseKey(hKey);
    //-------------------------------------------------------------------------------------------------------

    //-------------------------------------------------------------------------------------------------------
    // SYSTEM\\CurrentControlSet\\Services\\DriverName\\Instances\\DriverName Instance子健下的键值项 
    //-------------------------------------------------------------------------------------------------------
    strcpy_s(szTempStr, "SYSTEM\\CurrentControlSet\\Services\\");
    strcat_s(szTempStr, lpszDriverName);
    strcat_s(szTempStr, "\\Instances\\");
    strcat_s(szTempStr, lpszDriverName);
    strcat_s(szTempStr, " Instance");
    if (RegCreateKeyExA(HKEY_LOCAL_MACHINE, szTempStr, 0, NULL,TRUE, KEY_ALL_ACCESS, NULL, &hKey, (LPDWORD)&dwData) != ERROR_SUCCESS)
    {
        return FALSE;
    }
    // 注册表驱动程序的Altitude 值
    strcpy_s(szTempStr, lpszAltitude);
    if (RegSetValueExA(hKey, "Altitude", 0, REG_SZ, (CONST BYTE*)szTempStr, (DWORD)strlen(szTempStr)) != ERROR_SUCCESS)
    {
        return FALSE;
    }
    // 注册表驱动程序的Flags 值
    dwData = 0x0;
    if (RegSetValueExA(hKey, "Flags", 0, REG_DWORD, (CONST BYTE*) & dwData, sizeof(DWORD)) != ERROR_SUCCESS)
    {
        return FALSE;
    }
    RegFlushKey(hKey);//刷新注册表
    RegCloseKey(hKey);
    //-------------------------------------------------------------------------------------------------------
    printf("succ");
    return TRUE;
}

BOOL StartDriver(const char* lpszDriverName)
{
    SC_HANDLE        schManager;
    SC_HANDLE        schService;
    SERVICE_STATUS    svcStatus;

    if (NULL == lpszDriverName)
    {
        return FALSE;
    }

    schManager = OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if (NULL == schManager)
    {
        printf("11");
        CloseServiceHandle(schManager);
        return FALSE;
    }
    schService = OpenServiceA(schManager, lpszDriverName, SERVICE_ALL_ACCESS);
    if (NULL == schService)
    {
        CloseServiceHandle(schService);
        CloseServiceHandle(schManager);
        printf("22");

        return FALSE;
    }

    if (!StartServiceA(schService, 0, NULL))
    {
        CloseServiceHandle(schService);
        CloseServiceHandle(schManager);
        if (GetLastError() == ERROR_SERVICE_ALREADY_RUNNING)
        {
            printf("33");

            // 服务已经开启
            return TRUE;
        }
        printf("44");

        return FALSE;
    }

    CloseServiceHandle(schService);
    CloseServiceHandle(schManager);
    printf("55");

    return TRUE;
}

BOOL StopDriver(const char* lpszDriverName)
{
    SC_HANDLE        schManager;
    SC_HANDLE        schService;
    SERVICE_STATUS    svcStatus;
    bool            bStopped = false;

    schManager = OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if (NULL == schManager)
    {
        return FALSE;
    }
    schService = OpenServiceA(schManager, lpszDriverName, SERVICE_ALL_ACCESS);
    if (NULL == schService)
    {
        CloseServiceHandle(schManager);
        return FALSE;
    }
    if (!ControlService(schService, SERVICE_CONTROL_STOP, &svcStatus) && (svcStatus.dwCurrentState != SERVICE_STOPPED))
    {
        CloseServiceHandle(schService);
        CloseServiceHandle(schManager);
        return FALSE;
    }

    CloseServiceHandle(schService);
    CloseServiceHandle(schManager);

    return TRUE;
}

BOOL DeleteDriver(const char* lpszDriverName)
{
    SC_HANDLE        schManager;
    SC_HANDLE        schService;
    SERVICE_STATUS    svcStatus;

    schManager = OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if (NULL == schManager)
    {
        return FALSE;
    }
    schService = OpenServiceA(schManager, lpszDriverName, SERVICE_ALL_ACCESS);
    if (NULL == schService)
    {
        CloseServiceHandle(schManager);
        return FALSE;
    }
    ControlService(schService, SERVICE_CONTROL_STOP, &svcStatus);
    if (!DeleteService(schService))
    {
        CloseServiceHandle(schService);
        CloseServiceHandle(schManager);
        return FALSE;
    }
    CloseServiceHandle(schService);
    CloseServiceHandle(schManager);

    return TRUE;
}
int main(int argc, char* argv[])
{
    while (1)
    {
        char str[20] = "\0";
        printf("请输入命令: ");
        gets_s(str);
        if (strcmp(str, "1") == 0)
        {
            if(StartDriver("minifilter"))
            printf("[*] 启动驱动 \n");
            
        }
        if (strcmp(str, "2") == 0)
        {
            printf("[-] 关闭驱动 \n");
            StopDriver("minifilter");
        }
        if (strcmp(str, "3") == 0)
        {
            printf("[-] 卸载驱动 \n");
            DeleteDriver("minifilter");
        }
        if (strcmp(str, "0") == 0)
        {
            if (!InstallDriver("minifilter", ".\\mini.sys", "225000"))
            {
                printf("InstallDriver failed");
                return 0;
            }
        }
    }
    return 0;
}

minifilter框架使用端口通信

FltCreateCommunicationPort
FltCloseCommunicationPort
通过回调函数的InputBuffer接受用户态的消息并通过OutputBuffer回复

用户态通过FilterConnectCommunicationPort和FilterSendMessage通信

ObRegisterCallbacks

主要对下面三种方式进行过滤

  • 句柄的打开
  • 句柄的复制
  • 句柄的继承

微软提供了一个ObRegisterCallbacks函数可实现对对象回调的注册,这个函数可以监控获取进程句柄对象、线程句柄对象、桌面句柄对象

#include <ntifs.h>
#include "ntddk.h"

HANDLE g_obProcessHandle;
PUCHAR PsGetProcessImageFileName(PEPROCESS pEProcess);
OB_PREOP_CALLBACK_STATUS ProcessPreCall(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION pObPreOperationInfo);
NTSTATUS SetProcessCallbacks();
BOOLEAN IsProtectProcess(PEPROCESS pEProcess);
VOID DriverUnload(PDRIVER_OBJECT pDriverObject);
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath);
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath)
{
	pRegPath = pRegPath;
	DbgPrint("驱动加载\n");

	NTSTATUS status;
	pDriverObject->DriverUnload = DriverUnload;

	// 设置进程回调函数
	status=SetProcessCallbacks();
	return status;
}

VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
	pDriverObject = pDriverObject;
	// 删除进程回调函数
	if (NULL != g_obProcessHandle)
	{
		ObUnRegisterCallbacks(g_obProcessHandle);
	}
	DbgPrint("驱动卸载\n");
}

// 设置进程回调函数
NTSTATUS SetProcessCallbacks()
{
	NTSTATUS status = STATUS_SUCCESS;
	OB_CALLBACK_REGISTRATION obCallbackReg = { 0 };
	OB_OPERATION_REGISTRATION obOperationReg = { 0 };

	// 设置 OB_CALLBACK_REGISTRATION
	obCallbackReg.Version = OB_FLT_REGISTRATION_VERSION;//设置回调版本
	obCallbackReg.OperationRegistrationCount = 1;//回调函数数量
	obCallbackReg.RegistrationContext = NULL;
	RtlInitUnicodeString(&obCallbackReg.Altitude, L"321000");
	obCallbackReg.OperationRegistration = &obOperationReg;
	obOperationReg.ObjectType = PsProcessType;
	//设置过滤操作
	obOperationReg.Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;

	obOperationReg.PreOperation = (POB_PRE_OPERATION_CALLBACK)(&ProcessPreCall);
	obOperationReg.PostOperation = NULL;

	// 注册回调函数
	status = ObRegisterCallbacks(&obCallbackReg, &g_obProcessHandle);
	if (!NT_SUCCESS(status))
	{
		DbgPrint("ObRegisterCallbacks注册失败\n", status);
		return status;
	}
	return status;
}

// 进程回调函数
OB_PREOP_CALLBACK_STATUS ProcessPreCall(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION pObPreOperationInfo)
{
	RegistrationContext = RegistrationContext;
	PEPROCESS pEProcess = NULL;
	pEProcess = (PEPROCESS)pObPreOperationInfo->Object;
	if (IsProtectProcess(pEProcess))
	{
		if (OB_OPERATION_HANDLE_CREATE == pObPreOperationInfo->Operation)
		{
			pObPreOperationInfo->Parameters->CreateHandleInformation.DesiredAccess = 0;
		}
		else if (OB_OPERATION_HANDLE_DUPLICATE == pObPreOperationInfo->Operation)
		{
			pObPreOperationInfo->Parameters->DuplicateHandleInformation.DesiredAccess = 0;
		}
	}
	return OB_PREOP_SUCCESS;
}
BOOLEAN IsProtectProcess(PEPROCESS pEProcess)
{
	PUCHAR pProcessName = PsGetProcessImageFileName(pEProcess);
	if (NULL != pProcessName)
	{
		if (0 == _stricmp((const char*)pProcessName,"cc.exe"))
		{
			DbgPrint("cc被保护了");
			return TRUE;
		}
		DbgPrint("ProcessName=%s\n", pProcessName);
	}
	return FALSE;
}

WFP

在这里插入图片描述

reference

https://v3ded.github.io/redteam/red-team-tactics-writing-windows-kernel-drivers-for-advanced-persistence-part-2
https://www.cnblogs.com/LyShark/p/17134954.html

逻辑梳理

WfpInit:
IoCreateDevice->FwpmEngineOpen->FwpsCalloutRegister->FwpmCalloutAdd->FwpmSubLayerAdd->FwpmFilterAdd
在FwpsCalloutRegister中指定CalloutFilter和CalloutNotify
CalloutFilter:
layerData->NET_BUFFER_LIST->NET_BUFFER_LIST_FIRST_NB->NdisGetDataBuffer
WfpCleanup:
FwpmSubLayerDeleteByKey,FwpmFilterDeleteById,FwpmCalloutDeleteById

icmp header

Type	Code	Checksum  Rest of header
8		8		16		  32
一共64位,即8字节

ULONG  icmpLength = firstFragment->DataLength;
UINT32 dataLength = icmpLength - 8;
UINT32 payloadLength = dataLength - 4 - 1; //passwd:4,flag:1

发现std:c++20新语法hhh

    ExampleStruct example = {
        .id = 1,
        .name = "Example",
        .value = 10.5f
    };

icmp协议传输也是很方便,为了隐蔽还可以加密处理

在这里插入图片描述

补充一下显式事务

FwpmTransactionBegin、FwpmTransactionCommit、FwpmTransactionAbort
FwpmTransactionBegin 用于开始一个事务。在事务开始之后,对 WFP 对象的所有更改将被暂存,直到事务被提交或中止。
FwpmTransactionCommit 用于提交当前事务,应用所有暂存的更改。
FwpmTransactionAbort 用于中止当前事务,丢弃所有暂存的更改

再补充一下权限操作

actionType:一个FWP_ACTION_TYPE值,该值指定要根据标注驱动程序的分类Fn 标注函数确定的建议操作。 标注驱动程序将此变量设置为以下值之一:
FWP_ACTION_BLOCK
阻止传输或接收数据。
FWP_ACTION_CONTINUE
将阻止或允许数据传输或接收的决定传递给筛选器引擎中的下一个筛选器。
FWP_ACTION_NONE
不对数据执行任何操作。
FWP_ACTION_NONE_NO_MATCH
不对数据执行任何操作,因为它与枚举的筛选器数据类型不匹配。
FWP_ACTION_PERMIT
允许传输或接收数据。

否定三连:
		classifyOut->actionType = FWP_ACTION_BLOCK;
		classifyOut->rights = classifyOut->rights & (~FWPS_RIGHT_ACTION_WRITE);
		classifyOut->flags = classifyOut->flags | FWPS_CLASSIFY_OUT_FLAG_ABSORB;

后记

输出格式控制

符号格式说明符类型
%c, %lcANSI字符char
%C, %wc宽字符wchar_t
%d, %i十进制有符号整数int
%D十进制__int64__int64
%L十六进制的LARGE_INTEGERLARGE_INTEGER
%s, %lsNULL终止的ANSI字符串char*
%S, %wsNULL终止的宽字符串wchar_t*
%ZANSI_STRING字符串ANSI_STRING
%wZUNICODE_STRING字符串UNICODE_STRING
%u十进制的ULONGULONG
%x小写字符十六进制的ULONGULONG
%X大写字符十六进制的ULONGULONG
%p指针Pointer 32/64位

api开头含义

Nt:NewTechnology WindowsNT系统

Ke:Kernel core / Ki:Kernel interfacce 内核接口

Cm:Configuration Manager 系统配置管理

Ex:Executive 执行相关

Hal:Hardware Abstraction Layer 硬件抽象层

Io:I/O Manager 输入/输出管理

Mm:Memory Manager 内存管理

Ob:Object Manager 对象管理

Po:Power Manager 电源管理

Tm:Transaction Manager 事务管理

Ps:Process Manager 进程管理

Se:Security 安全管理

Fs:File System 文件系统

PnP:Plug-and-Play 即插即用

Rtl:Runtime Library 运行时程序库

WDM:Windows Driver Model 驱动模式

DMA:Direct Memory Access 直接存储器访问

DPCs:Deferred Procedure Calls 延迟过程调用

ISRs:Interrupt Service Routines 中断服务例程

常识浅记

内存

我们程序所使用的内存地址叫做虚拟内存地址(Virtual Memory Address)
实际存在硬件里面的空间地址叫物理内存地址(Physical Memory Address)
操作系统引入了虚拟内存,进程持有的虚拟地址会通过 CPU 芯片中的内存管理单元(MMU)的映射关系,来转换变成物理地址,然后再通过物理地址访问内存

内存分段:
内存碎片的问题共有两处地方:
外部内存碎片,也就是产生了多个不连续的小物理内存,导致新的程序无法被装载;
内部内存碎片,程序所有的内存都被装载到了物理内存,但是这个程序有部分的内存可能并不是很常使用,这也会导致内存的浪费;
为了解决内存分段的内存碎片和内存交换效率低的问题,就出现了内存分页。

内存分页:
页表实际上存储在 CPU 的内存管理单元 (MMU) 中,于是 CPU 就可以直接通过 MMU,找出要实际要访问的物理内存地址。
而当进程访问的虚拟地址在页表中查不到时,系统会产生一个缺页异常,进入系统内核空间分配物理内存、更新进程页表,最后再返回用户空间,恢复进程的运行。

IRQL级别控制

Windows NT把内核模式地址空间分成分页内存池和非分页内存池。(用户模式地址空间总是分页的) 必须驻留的代码和数据放在非分页池;不必常驻的代码和数据放在分页池中。非分页内容的空间是很小的,所以一般的东西都会放入分页内存中。执行在高于或等于DISPATCH_LEVEL级上的代码必须存在于非分页内存中

在写驱动的时候,经常要调用ExAllocatePoolWithTag函数分配内存,其中第一个参数可以是如下:
NonPagedPool:从非分页内存池中分配内存
PagedPool:从分页内存池中分配内存
即:分页内存是低中断级别的例程可以访问的,而非分页内存则是各个中断级别的例程都可以使用的(区别在于:分页内为存虚拟内存在,物理上未必总是能得到)

在windows驱动开发中,常见的有以下几类中断优先级:
PASSIVE_LEVEL(0):
IRQL优先级最低的中断等级,用户模式执行在这个中断级,可以访问分页内存。这个等级的中断只能被其他高优先级的中断所中断,而不能中断其他中断

APC_LEVEL(1):
IRQL为APC级别的中断会被屏蔽,可以访问分页内存。当有APC发生时,处理器提升到APC级别,这样,就屏蔽掉其它APC,为了和APC执行一些同步,驱动程序可以手动提升到这个级别,如果提升到这个级别,APC就不能调用。在这个级别,APC被禁止了,导致禁止一些I/O完成APC, 所以有一些API不能调用。

DISPATCH_LEVEL(2):
这个级别,DISPATCH_LEVEL 和APC_LEVEL 中断被屏蔽,剩余拦不住的中断还有这些:设备、时钟、电源错误。StartIO、AdapterControl、IoTimer、Cancel等例程会要求屏蔽DISPATCH_LEVEL级中断。从这里开始只能使用非分页的内存

DIRQL (Device IRQL 3-26)
IRQL<=26的中断都被屏蔽。大于该等级的拦不住,例如:clock、电源错误。InterruptService、SynchCritSection例程需要屏蔽这个等级的中断。

APC_LEVEL 和 PASSIVE_LEVEL 之间的唯一区别是,在 APC_LEVEL 执行的进程无法获得 APC 中断。但两个 IRQL暗含线程上下文,两者都意味着代码可以使用分页内存。在内核模式下,可以通过内核函数 KeGetCurrentIrql(),来获得当前的中断等级。可以通过调用KeLowerIrql与KeRaiseIrql来降低和升级等级。可以先提升IRQL,然后恢复(下降)到原有IRQL;不能单独调用KeLowerIrql来降低IRQL;调用了KeRaiseIrql后必须调用KeLowerIrql恢复原有IRQL。

PAGED_CODE

PAGED_CODE 宏确保调用方线程在足够低的允许分页的 IRQL 上运行。
如果 IRQL >APC_LEVEL,PAGED_CODE 宏会导致系统出现 ASSERT。PAGED_CODE 宏仅检查位于驱动程序代码执行宏的位置的 IRQL。
和内存交换效率低的问题,就出现了内存分页。

内存分页:
页表实际上存储在 CPU 的内存管理单元 (MMU) 中,于是 CPU 就可以直接通过 MMU,找出要实际要访问的物理内存地址。
而当进程访问的虚拟地址在页表中查不到时,系统会产生一个缺页异常,进入系统内核空间分配物理内存、更新进程页表,最后再返回用户空间,恢复进程的运行。
  • 25
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

coleak

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值