Windows x64内核
x64内核的回调函数
因为x64再想要去Hook例如各种门,SSDT表之类的重要数据结构变得异常困难
为了在内核模式下提供合法的扩展和拦截机制,微软提供了许多回调函数,这些回调允许驱动开发者在特定事件发生时执行自定义代码,而不必直接修改关键的内核数据结构。
还有一点,如果没有加载数字签名,调用以下API可能会报错,我们需要在编译选项加一些东西:/INTEGRITYCHECK
进程监控
具体代码,用于检测任何进程的创建与卸载
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
| #include "header.h"
VOID CreateProcessNotifyRoutine( _In_ HANDLE ParentId, _In_ HANDLE ProcessId, _In_ BOOLEAN Create ) { ParentId; PEPROCESS Process_ptr = NULL; PsLookupProcessByProcessId(ProcessId, &Process_ptr); if (Process_ptr == NULL) { DbgPrint("获取进程信息失败!\n"); return; }
if (Create) { UCHAR* processName = (UCHAR*)PsGetProcessImageFileName(Process_ptr); DbgPrint("进程%s被创建\n", processName); } else { UCHAR* processName = (UCHAR*)PsGetProcessImageFileName(Process_ptr); DbgPrint("进程%s被卸载\n", processName); } }
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { UNREFERENCED_PARAMETER(RegistryPath); KdPrint(("Create!")); KdBreakPoint(); DriverObject->DriverUnload = DriverUnloadRoutine; NTSTATUS status; PDEVICE_OBJECT DeviceObject = NULL; UNICODE_STRING DeviceName; RtlInitUnicodeString(&DeviceName, L"\\Device\\MyDevice"); status = IoCreateDevice( DriverObject, 0, &DeviceName, FILE_DEVICE_UNKNOWN, 0, FALSE, &DeviceObject );
if (!NT_SUCCESS(status)) { KdPrint(("Failed to create device: %X\n", status)); return status; } KdPrint(("Device created successfully\n"));
UNICODE_STRING symbolicLink = RTL_CONSTANT_STRING(L"\\??\\MyDevice_Link"); status = IoCreateSymbolicLink(&symbolicLink, &DeviceName); if (!NT_SUCCESS(status)) { KdPrint(("Failed to create device: %X\n", status)); return status; } KdPrint(("Device created successfully\n"));
PsSetCreateProcessNotifyRoutine((_In_ PCREATE_PROCESS_NOTIFY_ROUTINE)CreateProcessNotifyRoutine, FALSE);
return STATUS_SUCCESS; }
VOID DriverUnloadRoutine(IN PDRIVER_OBJECT DriverObject) { if (DriverObject->DeviceObject != NULL) { UNICODE_STRING symbolicLink = RTL_CONSTANT_STRING(L"\\??\\MyDevice_Link"); IoDeleteSymbolicLink(&symbolicLink); IoDeleteDevice(DriverObject->DeviceObject); } PsSetCreateProcessNotifyRoutine((_In_ PCREATE_PROCESS_NOTIFY_ROUTINE)CreateProcessNotifyRoutine, TRUE); DbgPrint("Driver unloaded\n"); }
|
如果我们需要阻止一个软件开启,我们可以通过PsSetCreateProcessNotifyRoutineEx
进行拦截
1 2 3 4 5 6 7 8 9 10
| VOID PcreateProcessNotifyRoutineEx( PEPROCESS Process, HANDLE ProcessId, PPS_CREATE_NOTIFY_INFO CreateInfo );
NTSTATUS PsSetCreateProcessNotifyRoutineEx( [in] PCREATE_PROCESS_NOTIFY_ROUTINE_EX NotifyRoutine, [in] BOOLEAN Remove );
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| VOID PcreateProcessNotifyRoutineEx( PEPROCESS Process, HANDLE ProcessId, PPS_CREATE_NOTIFY_INFO CreateInfo ) { Process; ProcessId; CreateInfo; UCHAR* processName = (UCHAR*)PsGetProcessImageFileName(Process); if (!CreateInfo) { KdPrint(("%s被卸载\n", (char*)processName)); } else { if (!strcmp("calc.exe", (char*)processName)) { CreateInfo->CreationStatus = 0xC0000008; } } }
|
提一嘴,PcreateProcessNotifyRoutineEx这里的Process指向一个_EPROCESS结构体,可以通过 !process 0 0
去获取到
我们通过WRK分析一下这个函数PsSetCreateProcessNotifyRoutine
发现如果注册过回调函数,那么将会按照顺序进行调用
而且PG保护是不会保护这玩意的,毕竟这玩意一直在变
如果我们把PsSetCreateProcessNotifyRoutine
里面的数据全抹掉,那么之前注册的回调将会全部失效
例如一些杀毒软件,禁止人为的卸载,就在注册一个回调,禁止我们手动卸载。
这时候我们将这里面的数据全部抹掉,这时候就可以顺利地删除了
- 线程监控
- API:
PsSetCreateThreadNotifyRoutine
- 描述: 注册一个回调函数,当线程创建或终止时,系统会调用此回调函数。这在监控线程生命周期和操作时非常有用。
- 注册表监控
- 文件监控
- 网络监控
- 模块监控
- API:
PsSetLoadImageNotifyRoutine
- 描述: 注册一个回调函数,当模块(包括驱动程序、DLL等)加载到内存中时,系统会调用此回调函数。通过此API可以监控系统中加载的所有模块。
- 开关机监控
对象监控
- API:
ObRegisterCallbacks
- 描述:
ObRegisterCallbacks
允许注册回调函数,监控和控制对特定对象类型(如进程、线程)的访问。通过这种方式,可以在对象创建、引用、销毁时获得通知或修改访问权限。
在WDK(Windows Driver Kit)开发中,ObRegisterCallbacks
函数用于注册回调函数,这些回调函数可以拦截对指定对象类型(如进程或线程)进行访问的请求。通过该函数,你可以设置回调,以便在对象句柄被创建或被重复使用(即使用现有句柄进行操作)时进行过滤和处理。
具体来说,ObRegisterCallbacks
注册的回调可以拦截以下操作:
- 句柄创建(Pre-Operation Callback):在目标对象的句柄创建之前调用,可以检查并修改请求的访问权限,或者拒绝句柄创建。这可以用来阻止某些进程对其他进程的句柄创建请求,限制其访问目标进程或线程的能力。
- 句柄重复使用(Post-Operation Callback):在句柄已经成功创建之后调用,这允许驱动在句柄创建成功后执行额外的操作,例如记录相关信息或进一步修改访问权限。
ObRegisterCallbacks
主要用于访问控制,例如拦截并限制对特定进程或线程对象的访问,常用于安全类驱动或反作弊系统,以防止恶意软件或调试器访问和控制某些系统资源。
这是参考代码 ProcessProtect-main.zip
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
| OB_OPERATION_REGISTRATION obOperationRegistrations[2] = { {0}, {0} }; OB_CALLBACK_REGISTRATION obCallbackRegistration = { 0 }; UNICODE_STRING altitude = { 0 }; PVOID RegistrationHandle = NULL;
NTSTATUS InitObRegistration() { obOperationRegistrations[0].ObjectType = PsProcessType; obOperationRegistrations[0].Operations |= OB_OPERATION_HANDLE_CREATE; obOperationRegistrations[0].Operations |= OB_OPERATION_HANDLE_DUPLICATE; obOperationRegistrations[0].PreOperation = PreOperationCallback;
obOperationRegistrations[1].ObjectType = PsThreadType; obOperationRegistrations[1].Operations |= OB_OPERATION_HANDLE_CREATE; obOperationRegistrations[1].Operations |= OB_OPERATION_HANDLE_DUPLICATE; obOperationRegistrations[1].PreOperation = PreOperationCallback;
RtlInitUnicodeString(&altitude, L"1000");
obCallbackRegistration.Version = ObGetFilterVersion();
obCallbackRegistration.OperationRegistrationCount = 2;
obCallbackRegistration.RegistrationContext = NULL;
obCallbackRegistration.Altitude = altitude;
obCallbackRegistration.OperationRegistration = obOperationRegistrations;
return ObRegisterCallbacks(&obCallbackRegistration, &RegistrationHandle); }
OB_PREOP_CALLBACK_STATUS PreOperationCallback(_In_ PVOID RegistrationContext, _Inout_ POB_PRE_OPERATION_INFORMATION PreInfo) { UNREFERENCED_PARAMETER(RegistrationContext);
PEPROCESS requestingProcess = IoGetCurrentProcess(); UCHAR* requestingProcessName = PsGetProcessImageFileName(requestingProcess);
PEPROCESS process = (PEPROCESS)PreInfo->Object;
if (PreInfo->ObjectType == *PsThreadType) { process = IoThreadToProcess((PETHREAD)PreInfo->Object); } else if (PreInfo->ObjectType == *PsProcessType) { process = (PEPROCESS)PreInfo->Object; } else { return OB_PREOP_SUCCESS; }
PUCHAR processName = PsGetProcessImageFileName(process);
if (_stricmp((char*)processName, "notepad.exe") != 0) { return OB_PREOP_SUCCESS; }
if (PreInfo->Operation == OB_OPERATION_HANDLE_CREATE) { if (!(_strnicmp((char*)requestingProcessName, "cheatengine-x86_64.exe", 6))) { PreInfo->Parameters->CreateHandleInformation.DesiredAccess = 0; } }
if (PreInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE) { if (!(_strnicmp((char*)requestingProcessName, "cheatengine-x86_64.exe", 6))) { PreInfo->Parameters->DuplicateHandleInformation.DesiredAccess = 0; } }
return OB_PREOP_SUCCESS; }
VOID UnInitObRegistration() { if (RegistrationHandle) { ObUnRegisterCallbacks(RegistrationHandle); RegistrationHandle = NULL; } }
|