Windows内核态开发笔记

news2024/12/23 13:28:53

文章目录

    • r3/r0通信
    • x64 HOOK
    • 回调监控
    • 进程强杀
    • minifilter
    • ObRegisterCallbacks
    • WFP
    • 后记

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,找出要实际要访问的物理内存地址。
而当进程访问的虚拟地址在页表中查不到时,系统会产生一个缺页异常,进入系统内核空间分配物理内存、更新进程页表,最后再返回用户空间,恢复进程的运行。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1973067.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Reader

FileInputStream和FileOutputStream其实还叫字节输入流和字节输出流。关于输入和输出这2个总是有点模糊。 以内存为基准&#xff0c;InputStream是文件流向内存&#xff0c;就是从文件中读取数据&#xff0c;又称为输入流。 OutputStream是从内存中流向文件&#xff0c;就是向…

使用s3cmd 2.x 与 Cyberduck 管理在 DigitalOcean Spaces 对象存储中的数据

有很多用户在使用 DigitalOcean Spaces 对象存储的过程中&#xff0c;还没有找到一个合适的数据管理工具。其实目前有很多开源工具都可以使用&#xff0c;比如 s3cmd、Cyberduck、rclone、transmit5。Cyberduck 提供了直观的图形用户界面&#xff0c;而 s3cmd 2.x 则擅长于批处…

怎么搭建AI带货直播间生成虚拟主播?

随着电商直播带货的热潮不断升温&#xff0c;虚拟主播逐渐崭露头角&#xff0c;成为电商直播领域的新宠&#xff0c;相较于真人主播&#xff0c;虚拟主播具备无档期风险、人设稳定可控、24小时不间断直播等显著优势。 本文将深入探讨如何搭建一个AI带货直播间&#xff0c;并详…

最新小猫咪PHP加密系统源码V1.4_本地API接口_带后台

简介&#xff1a; 最新小猫咪PHP加密系统源码V1.4_完全本地化加密API接口_带后台 小猫咪PHP加密系统历时半年&#xff0c;它再一次迎来更新&#xff0c;更新加密算法&#xff08;这应该是最后一次更新加密算法了&#xff0c;以后主要更新都在框架功能上面了&#xff09;&…

在WordPress上启用reCAPTCHA的指南

随着网络安全问题的日益严重&#xff0c;网站管理员必须采取措施保护自己的网站免受恶意攻击。对于WordPress用户来说&#xff0c;可以通过启用谷歌的reCAPTCHA功能来增强网站的安全性。本文将介绍两种在WordPress上启用reCAPTCHA的方法&#xff1a;使用插件和手动添加代码。 一…

Git基础:使用指南

Git是一个开源的分布式版本控制系统&#xff0c;可以有效、高速地处理从很小到非常大的项目版本管理。分布式相比于集中式的最大区别在于开发者可以提交到本地&#xff0c;每个开发者通过克隆&#xff0c;在本地机器上拷贝一个完整的Git仓库。 一、版本管理 1.1 创建版本库 版…

大模型的架构参数是指定义模型基本结构和组成的各种参数,这些参数对模型的性能、训练效率和泛化能力具有重要影响。以下是对大模型架构参数的详细介绍

大模型架构参数 大模型的架构参数是指定义模型基本结构和组成的各种参数&#xff0c;这些参数对模型的性能、训练效率和泛化能力具有重要影响。以下是对大模型架构参数的详细介绍&#xff1a; 一、基本结构和组成 层数&#xff1a;模型的层数是指模型中全连接网络或特定结构…

vue3直播视频流easy-player

vue3直播视频流easy-player <script src"/easyPlayer/EasyPlayer-element.min.js"></script> easyPlayer文件下载地址 https://download.csdn.net/download/weixin_42120669/89605739 <template><div class"container"><div …

Vue进阶之Vue无代码可视化项目(九)

Vue无代码可视化项目—补充内容 背景介绍、方案设计Canvas Table创建一个新的vue项目普通表格的效果Canvas上手Canvas画表格-画基本表格CanvasTable处理事件系统CanvasTable表格滚动Vue组件封装思想拖拽组件 —smooth-dndDndDemo1.vueDndContainer.jsCanvasTable封装CanvasTabl…

LDR6020 iPad皮套一体式键盘充电方案解析

在移动办公与学习的浪潮中&#xff0c;iPad凭借其强大的性能与便携性&#xff0c;成为了越来越多人的首选设备。然而&#xff0c;随着工作与学习任务的日益复杂&#xff0c;单一的触控操作已难以满足高效、精准的需求。因此&#xff0c;搭配一款优秀的键盘成为了提升iPad使用体…

月木学途开发 3.1搭建CentOS虚拟机

安装CentOS 下载地址 &#xff1a;https://mirrors.aliyun.com/centos-vault/?spma2c6h.13651104.0.0.5f6612b2O7Cy9G 选择7.6.1810——isos——x86_64——CentOS-7-x86_64-DVD-1810.iso 安装 VMWare虚拟机 下载 下载地址&#xff1a;https://www.vmware.com/products/desktop…

分享c语言中一些实用的函数2

目录 一.头文件 1.sqrt()函数 2.sin&#xff0c;cos&#xff0c;tan函数 附加:宏定义π 3.exp函数 4.fabs函数 5.fmax函数 6.floor函数 7.log函数 附加&#xff1a;求一个数是几为数(运用floor函数和log函数) 8.pow函数 二.头文件 1.abs函数 附加: 一.头文件<…

详解HTTP协议版本(HTTP/1.0、1.1、2.0、3.0区别)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐&#xff1a;「storm…

数据采集器

目录 1. 采集Redis 2. 采集MySQL 3. 采集容器 1. 采集Redis 出口商和集成 |普罗 米修斯 (prometheus.io) 发布 奥利弗006/redis_exporter (github.com) 在目标机器上安装redis 上传redis采集器包redis_exporter-v1.53.0.linux-amd64.tar.gz [rootharbor opt]# tar -xf …

web3 solana

网址&#xff1a;HACKQUEST 学习初衷&#xff1a; 1.web3概念较为小众&#xff0c;相比于web2&#xff0c;机会较多 2.有机会remote work&#xff0c;带着笔记本到处浪&#xff0c;听着就不错 3.面对越来越卷的国内&#xff0c;有机会并有能力拥抱国外job&#xff0c;感觉是…

安卓车载多屏互动副屏底部有黑线条NavigationBar分析

背景&#xff1a; 在学习了马哥的wms和多屏互动课程后&#xff0c;大家普遍都可以跟着做出如下图效果的多屏互动&#xff1a; 其实初略来看这个成果已经完成一个多屏互动项目大部分功能&#xff0c;但是其实还是有一些bug的存在&#xff0c;今天我们就来分析一下多屏互动相关的…

FPGA实现SDI视频接收转USB3.0传输,GS2971+FT601方案,提供4套工程源码和QT上位机源码

目录 1、前言工程概述免责声明 2、相关方案推荐本博已有的 SDI 编解码方案本博已有的FPGA驱动USB通信方案FPGA基于GS2971的SDI视频解码方案FPGA基于FT601的USB3.0视频传输方案 3、详细设计方案设计原理框图SDI 相机GS2971-SDI解码芯片解读BT1120转RGB888图像缓存FT601-USB3.0芯…

计算机毕业设计选题推荐-校内跑腿业务系统-Java/Python项目实战

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

深入理解操作系统--绪论

文章目录 概述操作系统的基本概念多用户系统用户和组进程 小结 概述 最近在读操作系统&#xff0c;发现一些新的概念。写出来&#xff0c;让自己印象更深&#xff0c;希望也帮助一些不懂的朋友&#xff1b;但愿有所帮助吧。 操作系统的基本概念 计算机都包含操作系统的基本程…

自动化测试的回归策略!

在快速迭代的软件开发过程中&#xff0c;确保软件质量的稳定性和可靠性是每一个开发团队都面临的重要挑战。其中&#xff0c;回归测试作为验证软件变更后是否仍然满足原有需求的重要手段&#xff0c;其重要性不言而喻。而自动化测试的回归策略&#xff0c;正是为了应对这一挑战…