WindowsAPI编程核心技术-进线程监控
进线程枚举
进程枚举:
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
| #include <ntifs.h> NTKERNELAPI UCHAR* PsGetProcessImageFileName(IN PEPROCESS Process); NTKERNELAPI HANDLE PsGetProcessInheritedFromUniqueProcessId(IN PEPROCESS Process);
PEPROCESS LookupProcess(HANDLE Pid){ PEPROCESS eprocess = NULL; NTSTATUS Status = STATUS_UNSUCCESSFUL; Status = PsLookupProcessByProcessId(Pid, &eprocess); if (NT_SUCCESS(Status)) return eprocess; return NULL; } VOID EnumProcess(){ PEPROCESS eproc = NULL; for (int temp = 0; temp < 100000; temp += 4){ eproc = LookupProcess((HANDLE)temp); if (eproc != NULL){ DbgPrint("进程名: %s --> 进程PID = %d --> 父进程PPID = %d\r\n",PsGetProcessImageFileName(eproc),PsGetProcessId(eproc), PsGetProcessInheritedFromUniqueProcessId(eproc)); ObDereferenceObject(eproc); } } } VOID UnDriver(PDRIVER_OBJECT driver){ } NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath){ EnumProcess(); Driver->DriverUnload = UnDriver; return STATUS_SUCCESS; }
|
线程枚举:
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
| #include <ntddk.h> #include <windef.h>
NTKERNELAPI UCHAR* PsGetProcessImageFileName(IN PEPROCESS Process); NTKERNELAPI NTSTATUS PsLookupProcessByProcessId(HANDLE Id, PEPROCESS *Process); NTKERNELAPI NTSTATUS PsLookupThreadByThreadId(HANDLE Id, PETHREAD *Thread); NTKERNELAPI PEPROCESS IoThreadToProcess(PETHREAD Thread);
PEPROCESS LookupProcess(HANDLE Pid){ PEPROCESS eprocess = NULL; if (NT_SUCCESS(PsLookupProcessByProcessId(Pid, &eprocess))) return eprocess; else return NULL; }
PETHREAD LookupThread(HANDLE Tid){ PETHREAD ethread; if (NT_SUCCESS(PsLookupThreadByThreadId(Tid, ðread))) return ethread; else return NULL; }
VOID EnumThread(PEPROCESS Process){ ULONG i = 0, c = 0; PETHREAD ethrd = NULL; PEPROCESS eproc = NULL; for (i = 4; i<262144; i = i + 4){ ethrd = LookupThread((HANDLE)i); if (ethrd != NULL){ eproc = IoThreadToProcess(ethrd); if (eproc == Process) DbgPrint("线程: ETHREAD=%p TID=%ld\n",ethrd,(ULONG)PsGetThreadId(ethrd)); ObDereferenceObject(ethrd); } } }
VOID MyEnumThread(char *ProcessName){ ULONG i = 0; PEPROCESS eproc = NULL; for (i = 4; i<100000000; i = i + 4){ eproc = LookupProcess((HANDLE)i); if (eproc != NULL){ ObDereferenceObject(eproc); if (strstr(PsGetProcessImageFileName(eproc), ProcessName) != NULL) EnumThread(eproc); } } } VOID DriverUnload(IN PDRIVER_OBJECT DriverObject){} NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath){ MyEnumThread("calc.exe"); DriverObject->DriverUnload = DriverUnload; return STATUS_SUCCESS; }
|
枚举进程模块,DLL模块记录在PEB的LDR链表中,LDR是个双向链表。
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
| #include <ntddk.h> #include <windef.h>
typedef struct _KAPC_STATE{ LIST_ENTRY ApcListHead[2]; PKPROCESS Process; UCHAR KernelApcInProgress; UCHAR KernelApcPending; UCHAR UserApcPending; } KAPC_STATE, *PKAPC_STATE; typedef struct _LDR_DATA_TABLE_ENTRY{ LIST_ENTRY64 InLoadOrderLinks; LIST_ENTRY64 InMemoryOrderLinks; LIST_ENTRY64 InInitializationOrderLinks; PVOID DllBase; PVOID EntryPoint; ULONG SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; ULONG Flags; USHORT LoadCount; USHORT TlsIndex; PVOID SectionPointer; ULONG CheckSum; PVOID LoadedImports; PVOID EntryPointActivationContext; PVOID PatchInformation; LIST_ENTRY64 ForwarderLinks; LIST_ENTRY64 ServiceTagLinks; LIST_ENTRY64 StaticLinks; PVOID ContextInformation; ULONG64 OriginalBase; LARGE_INTEGER LoadTime; } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; ULONG64 LdrInPebOffset = 0x018; ULONG64 ModListInPebOffset = 0x010;
NTKERNELAPI UCHAR* PsGetProcessImageFileName(IN PEPROCESS Process); NTKERNELAPI PPEB PsGetProcessPeb(PEPROCESS Process); NTKERNELAPI HANDLE PsGetProcessInheritedFromUniqueProcessId(IN PEPROCESS Process);
PEPROCESS LookupProcess(HANDLE Pid){ PEPROCESS eprocess = NULL; if (NT_SUCCESS(PsLookupProcessByProcessId(Pid, &eprocess))) return eprocess; else return NULL; }
VOID EnumModule(PEPROCESS Process){ SIZE_T Peb = 0; SIZE_T Ldr = 0; PLIST_ENTRY ModListHead = 0; PLIST_ENTRY Module = 0; ANSI_STRING AnsiString; KAPC_STATE ks; if (!MmIsAddressValid(Process)) return; Peb = (SIZE_T)PsGetProcessPeb(Process); if (!Peb) return; KeStackAttachProcess(Process, &ks); __try{ Ldr = Peb + (SIZE_T)LdrInPebOffset; ProbeForRead((CONST PVOID)Ldr, 8, 8); ModListHead = (PLIST_ENTRY)(*(PULONG64)Ldr + ModListInPebOffset); ProbeForRead((CONST PVOID)ModListHead, 8, 8); Module = ModListHead->Flink; while (ModListHead != Module){ DbgPrint("模块基址=%p 大小=%ld 路径=%wZ\n",(PVOID)(((PLDR_DATA_TABLE_ENTRY)Module)->DllBase),(ULONG)(((PLDR_DATA_TABLE_ENTRY)Module)->SizeOfImage),&(((PLDR_DATA_TABLE_ENTRY)Module)->FullDllName)); Module = Module->Flink; ProbeForRead((CONST PVOID)Module, 80, 8); } } __except (EXCEPTION_EXECUTE_HANDLER){;} KeUnstackDetachProcess(&ks); }
VOID MyEnumModule(char *ProcessName){ ULONG i = 0; PEPROCESS eproc = NULL; for (i = 4; i<100000000; i = i + 4){ eproc = LookupProcess((HANDLE)i); if (eproc != NULL){ ObDereferenceObject(eproc); if (strstr(PsGetProcessImageFileName(eproc), ProcessName) != NULL) EnumModule(eproc); } } } VOID DriverUnload(IN PDRIVER_OBJECT DriverObject){} NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath){ MyEnumModule("calc.exe"); DriverObject->DriverUnload = DriverUnload; return STATUS_SUCCESS; }
|
枚举SYS文件:
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
| #include <ntddk.h> #include <wdm.h> typedef struct _LDR_DATA_TABLE_ENTRY { LIST_ENTRY InLoadOrderLinks; LIST_ENTRY InMemoryOrderLinks; LIST_ENTRY InInitializationOrderLinks; PVOID DllBase; PVOID EntryPoint; ULONG SizeOfImages; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; ULONG Flags; USHORT LoadCount; USHORT TlsIndex; union { LIST_ENTRY HashLinks; struct { PVOID SectionPointer; ULONG CheckSum; }; }; union { struct { ULONG TimeDateStamp; }; struct { PVOID LoadedImports; }; }; }LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; VOID DriverUnload(IN PDRIVER_OBJECT DriverObject){} NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath){ ULONG count = 0; NTSTATUS Status; DriverObject->DriverUnload = DriverUnload; PLDR_DATA_TABLE_ENTRY pLdr = NULL; PLIST_ENTRY pListEntry = NULL; PLDR_DATA_TABLE_ENTRY pModule = NULL; PLIST_ENTRY pCurrentListEntry = NULL; pLdr = (PLDR_DATA_TABLE_ENTRY)DriverObject->DriverSection; pListEntry = pLdr->InLoadOrderLinks.Flink; pCurrentListEntry = pListEntry->Flink; while (pCurrentListEntry != pListEntry){ pModule = CONTAINING_RECORD(pCurrentListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); if (pModule->BaseDllName.Buffer != 0) DbgPrint("基址:%p ---> 偏移:%p ---> 结束地址:%p---> 模块名:%wZ \r\n",pModule->DllBase, pModule->SizeOfImages - (LONGLONG)pModule->DllBase,(LONGLONG)pModule->DllBase + pModule->SizeOfImages,pModule->BaseDllName); pCurrentListEntry = pCurrentListEntry->Flink; } DriverObject->DriverUnload = DriverUnload; return STATUS_SUCCESS; }
|
进线程对象监控
ObRegisterCallbacks
原型如下:
1 2 3 4 5 6 7 8
| NTSTATUS ObRegisterCallbacks( [in] POB_CALLBACK_REGISTRATION CallbackRegistration, [out] PVOID *RegistrationHandle ); OB_PREOP_CALLBACK_STATUS MyLySharkComObjectCallBack( PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION OperationInformation );
|
ObRegisterCallbacks
基础用法如下:
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
| #include <ntddk.h> #include <ntstrsafe.h> PVOID Globle_Object_Handle; OB_PREOP_CALLBACK_STATUS MyObjectCallBack(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION OperationInformation){ return STATUS_SUCCESS; } VOID UnDriver(PDRIVER_OBJECT driver){ ObUnRegisterCallbacks(Globle_Object_Handle); } NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath){ OB_OPERATION_REGISTRATION Base; OB_CALLBACK_REGISTRATION CallbackReg; CallbackReg.RegistrationContext = NULL; CallbackReg.Version = OB_FLT_REGISTRATION_VERSION; CallbackReg.OperationRegistration = &Base; CallbackReg.OperationRegistrationCount = 1; RtlUnicodeStringInit(&CallbackReg.Altitude, L"600000"); Base.ObjectType = PsProcessType; Base.Operations = OB_OPERATION_HANDLE_CREATE; Base.PreOperation = MyObjectCallBack; Base.PostOperation = NULL; if (ObRegisterCallbacks(&CallbackReg, &Globle_Object_Handle)) DbgPrint("回调注册成功..."); Driver->DriverUnload = UnDriver; return STATUS_SUCCESS; }
|
例如禁止计算器弹出:
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
| #include <ntddk.h> #include <wdm.h> #include <ntstrsafe.h> #define PROCESS_TERMINATE 1 PVOID Globle_Object_Handle; NTKERNELAPI UCHAR * PsGetProcessImageFileName(__in PEPROCESS Process); char* GetProcessImageNameByProcessID(ULONG ulProcessID){ NTSTATUS Status; PEPROCESS EProcess = NULL; Status = PsLookupProcessByProcessId((HANDLE)ulProcessID, &EProcess); if (!NT_SUCCESS(Status)) return FALSE; ObDereferenceObject(EProcess); return (char*)PsGetProcessImageFileName(EProcess); } OB_PREOP_CALLBACK_STATUS MyObjectCallBack(PVOID RegistrationContext,POB_PRE_OPERATION_INFORMATION Operation){ char ProcName[256] = { 0 }; HANDLE pid = PsGetProcessId((PEPROCESS)Operation->Object); strcpy(ProcName, GetProcessImageNameByProcessID((ULONG)pid)); if (strstr(ProcName, "win32calc.exe")) if (Operation->Operation == OB_OPERATION_HANDLE_CREATE) if ((Operation->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_TERMINATE) ==PROCESS_TERMINATE){ DbgPrint("你想结束进程?"); Operation->Parameters->CreateHandleInformation.DesiredAccess = ~THREAD_TERMINATE; return STATUS_UNSUCCESSFUL; } return STATUS_SUCCESS; } VOID UnDriver(PDRIVER_OBJECT driver){ ObUnRegisterCallbacks(Globle_Object_Handle); } NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath){ NTSTATUS obst = 0; OB_CALLBACK_REGISTRATION obReg; OB_OPERATION_REGISTRATION opReg; memset(&obReg, 0, sizeof(obReg)); obReg.Version = ObGetFilterVersion(); obReg.OperationRegistrationCount = 1; obReg.RegistrationContext = NULL; RtlInitUnicodeString(&obReg.Altitude, L"321125"); obReg.OperationRegistration = &opReg; memset(&opReg, 0, sizeof(opReg)); opReg.ObjectType = PsProcessType; opReg.Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE; opReg.PreOperation = (POB_PRE_OPERATION_CALLBACK)&MyObjectCallBack; obst = ObRegisterCallbacks(&obReg, &Globle_Object_Handle); Driver->DriverUnload = UnDriver; return STATUS_SUCCESS; }
|
拦截线程的回调函数写法:
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
| OB_PREOP_CALLBACK_STATUS MyThreadObjectCallBack(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION pOperationInformation) { PEPROCESS ep; PETHREAD et; HANDLE pid; if (pOperationInformation->ObjectType != *PsThreadType) return OB_PREOP_SUCCESS; et = (PETHREAD)pOperationInformation->Object; ep = IoThreadToProcess(et); pid = PsGetProcessId(ep); UNREFERENCED_PARAMETER(RegistrationContext); if (CheckProcess(ep)) { if (pOperationInformation->Operation == OB_OPERATION_HANDLE_CREATE) { pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess = 0; if ((pOperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & THREAD_TERMINATE2) == THREAD_TERMINATE2) { DbgPrint("拦截aaaaaa.exe进程内 %d 线程创建 \n", PsGetThreadId(et)); pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~THREAD_TERMINATE2; } } if (pOperationInformation->Operation == OB_OPERATION_HANDLE_DUPLICATE) { pOperationInformation->Parameters->DuplicateHandleInformation.DesiredAccess = 0; if ((pOperationInformation->Parameters->DuplicateHandleInformation.OriginalDesiredAccess & THREAD_TERMINATE2) == THREAD_TERMINATE2) pOperationInformation->Parameters->DuplicateHandleInformation.DesiredAccess &= ~THREAD_TERMINATE2; } } return OB_PREOP_SUCCESS; }
|
进程创建监控
因为x64下没法HOOK,微软搞了一套接口。
PsSetCreateProcessNotifyRoutineEx
设置进程回调监控创建与退出,控制是否允许进程创建。
1 2 3 4
| NTSTATUS PsSetCreateProcessNotifyRoutineEx( _In_ PCREATE_PROCESS_NOTIFY_ROUTINE_EX NotifyRoutine, _In_ BOOLEAN Remove )
|
PS_CREATE_NOTIFY_INFO
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| typedef struct _PS_CREATE_NOTIFY_INFO { _In_ SIZE_T Size; union { _In_ ULONG Flags; struct { _In_ ULONG FileOpenNameAvailable : 1; _In_ ULONG IsSubsystemProcess : 1; _In_ ULONG Reserved : 30; }; }; _In_ HANDLE ParentProcessId; _In_ CLIENT_ID CreatingThreadId; _Inout_ struct _FILE_OBJECT *FileObject; _In_ PCUNICODE_STRING ImageFileName; _In_opt_ PCUNICODE_STRING CommandLine; _Inout_ NTSTATUS CreationStatus; } PS_CREATE_NOTIFY_INFO, *PPS_CREATE_NOTIFY_INFO;
|
破解内核函数强制完整性签名限制
例如PsSetCreateProcessNotifyRoutineEx
、ObRegisterCallbacks
等函数要求程序强制完整性校验,否则调用失败。
首先要在编译时启用驱动签名强制签名属性。在/integritycheck链接器标志设置IMAGE_OPTIONAL_HEADER中DllCharacteristics字段为IMAGE_DLLCHARACTERISTICS_INTEGRITY属性。
内核通过MmVerifyCallbackFunction
验证限制函数调用是否合法,但它只是验证了DriverObejct->DriverSection->Flags
是否包含0x20,所以破解方法就异或0x20就行了。其中LDR_DATA_TABLE_ENTRY在x86和x64下有差异:
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
| BOOLEAN BypassCheckSign(PDRIVER_OBJECT pDriverObject) { #ifdef _WIN64 typedef struct _KLDR_DATA_TABLE_ENTRY { LIST_ENTRY listEntry; ULONG64 __Undefined1; ULONG64 __Undefined2; ULONG64 __Undefined3; ULONG64 NonPagedDebugInfo; ULONG64 DllBase; ULONG64 EntryPoint; ULONG SizeOfImage; UNICODE_STRING path; UNICODE_STRING name; ULONG Flags; USHORT LoadCount; USHORT __Undefined5; ULONG64 __Undefined6; ULONG CheckSum; ULONG __padding1; ULONG TimeDateStamp; ULONG __padding2; } KLDR_DATA_TABLE_ENTRY, * PKLDR_DATA_TABLE_ENTRY; #else typedef struct _KLDR_DATA_TABLE_ENTRY { LIST_ENTRY listEntry; ULONG unknown1; ULONG unknown2; ULONG unknown3; ULONG unknown4; ULONG unknown5; ULONG unknown6; ULONG unknown7; UNICODE_STRING path; UNICODE_STRING name; ULONG Flags; } KLDR_DATA_TABLE_ENTRY, * PKLDR_DATA_TABLE_ENTRY; #endif PKLDR_DATA_TABLE_ENTRY pLdrData = (PKLDR_DATA_TABLE_ENTRY)pDriverObject->DriverSection; pLdrData->Flags = pLdrData->Flags | 0x20; return TRUE; };
|
例子
设置进程监控回调函数:
1 2 3 4 5 6 7
| NTSTATUS SetProcessNotifyRoutine(VOID) { NTSTATUS status = PsSetCreateProcessNotifyRoutineEx((PCREATE_PROCESS_NOTIFY_ROUTINE_EX)ProcessNotifyExRoutine, FALSE); if (!NT_SUCCESS(status)) ShowError("PsSetCreateProcessNotifyRoutineEx", status); return status; };
|
回调函数原型:
1 2 3 4 5
| VOID ProcessNotifyExRoutine ( _In_ HANDLE ParentId, _In_ HANDLE ProcessId, _Inout_opt_ PPS_CREATE_NOTIFY_INFO CreateInfo )
|
进程创建回调函数的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| VOID ProcessNotifyExRoutine(PEPROCESS pEProcess, HANDLE hProcessId, PPS_CREATE_NOTIFY_INFO CreateInfo) { if (NULL == CreateInfo) return; PCHAR pszImageFileName = PsGetProcessImageFileName(pEProcess); DbgPrint("[%s][%d][%wZ]\n", pszImageFileName, hProcessId, CreateInfo->ImageFileName); if (0 == _stricmp(pszImageFileName, "520.exe")) { CreateInfo->CreationStatus = STATUS_UNSUCCESSFUL; DbgPrint("[禁止创建]\n"); }; return; };
|
源代码
Driver.h:
1 2 3 4 5 6
| #ifndef _DRIVER_H_ #define _DRIVER_H_ #include <ntddk.h> VOID DriverUnload(PDRIVER_OBJECT pDriverObject); NTSTATUS DriverDefaultHandle(PDEVICE_OBJECT pDevObj, PIRP pIrp); #endif
|
NotifyRoutine.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| #ifndef _NOTIFY_ROUTINE_H_ #define _NOTIFY_ROUTINE_H_ #include <ntddk.h>
PCHAR PsGetProcessImageFileName(PEPROCESS pEProcess);
BOOLEAN BypassCheckSign(PDRIVER_OBJECT pDriverObject);
NTSTATUS SetProcessNotifyRoutine();
NTSTATUS RemoveProcessNotifyRoutine();
VOID ProcessNotifyExRoutine(PEPROCESS pEProcess, HANDLE hProcessId, PPS_CREATE_NOTIFY_INFO CreateInfo); #endif
|
Driver.c:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| #include "Driver.h" #include "NotifyRoutine.h" NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath){ NTSTATUS status = STATUS_SUCCESS; pDriverObject->DriverUnload = DriverUnload; for (ULONG i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) pDriverObject->MajorFunction[i] = DriverDefaultHandle; BypassCheckSign(pDriverObject); SetProcessNotifyRoutine(); return status; } VOID DriverUnload(PDRIVER_OBJECT pDriverObject){ RemoveProcessNotifyRoutine(); } NTSTATUS DriverDefaultHandle(PDEVICE_OBJECT pDevObj, PIRP pIrp){ NTSTATUS status = STATUS_SUCCESS; pIrp->IoStatus.Status = status; pIrp->IoStatus.Information = 0; IoCompleteRequest(pIrp, IO_NO_INCREMENT); return status; }
|
NotifyRoutine.c:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| #include "NotifyRoutine.h" VOID ShowError(PCHAR pszText, NTSTATUS ntStatus){ DbgPrint("%s Error[0x%X]\n", pszText, ntStatus); }
BOOLEAN BypassCheckSign(PDRIVER_OBJECT pDriverObject){ #ifdef _WIN64 typedef struct _KLDR_DATA_TABLE_ENTRY { LIST_ENTRY listEntry; ULONG64 __Undefined1; ULONG64 __Undefined2; ULONG64 __Undefined3; ULONG64 NonPagedDebugInfo; ULONG64 DllBase; ULONG64 EntryPoint; ULONG SizeOfImage; UNICODE_STRING path; UNICODE_STRING name; ULONG Flags; USHORT LoadCount; USHORT __Undefined5; ULONG64 __Undefined6; ULONG CheckSum; ULONG __padding1; ULONG TimeDateStamp; ULONG __padding2; } KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY; #else typedef struct _KLDR_DATA_TABLE_ENTRY { LIST_ENTRY listEntry; ULONG unknown1; ULONG unknown2; ULONG unknown3; ULONG unknown4; ULONG unknown5; ULONG unknown6; ULONG unknown7; UNICODE_STRING path; UNICODE_STRING name; ULONG Flags; } KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY; #endif PKLDR_DATA_TABLE_ENTRY pLdrData = (PKLDR_DATA_TABLE_ENTRY)pDriverObject->DriverSection; pLdrData->Flags = pLdrData->Flags | 0x20; return TRUE; }
NTSTATUS SetProcessNotifyRoutine(){ NTSTATUS status = PsSetCreateProcessNotifyRoutineEx((PCREATE_PROCESS_NOTIFY_ROUTINE_EX)ProcessNotifyExRoutine, FALSE); if (!NT_SUCCESS(status)) ShowError("PsSetCreateProcessNotifyRoutineEx", status); return status; }
NTSTATUS RemoveProcessNotifyRoutine(){ NTSTATUS status = PsSetCreateProcessNotifyRoutineEx((PCREATE_PROCESS_NOTIFY_ROUTINE_EX)ProcessNotifyExRoutine, TRUE); if (!NT_SUCCESS(status)) ShowError("PsSetCreateProcessNotifyRoutineEx", status); return status; }
VOID ProcessNotifyExRoutine(PEPROCESS pEProcess, HANDLE hProcessId, PPS_CREATE_NOTIFY_INFO CreateInfo){ if (NULL == CreateInfo) return; PCHAR pszImageFileName = PsGetProcessImageFileName(pEProcess); DbgPrint("[%s][%d][%wZ]\n", pszImageFileName, hProcessId, CreateInfo->ImageFileName); if (0 == _stricmp(pszImageFileName, "520.exe")){ CreateInfo->CreationStatus = STATUS_UNSUCCESSFUL; DbgPrint("[禁止创建]\n"); } }
|
线程创建监控
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #include <ntddk.h> NTKERNELAPI PCHAR PsGetProcessImageFileName(PEPROCESS Process); NTKERNELAPI NTSTATUS PsLookupProcessByProcessId(HANDLE ProcessId, PEPROCESS *Process); VOID MyCreateThreadNotify(HANDLE ProcessId, HANDLE ThreadId, BOOLEAN Create){ PEPROCESS eprocess = NULL; PsLookupProcessByProcessId(ProcessId, &eprocess); if (Create) DbgPrint("线程TID: %1d --> 所属进程名: %s --> 进程PID: %1d \n", ThreadId,PsGetProcessImageFileName(eprocess), PsGetProcessId(eprocess)); else DbgPrint("%s 线程已退出...", ThreadId); } VOID UnDriver(PDRIVER_OBJECT driver){ PsRemoveCreateThreadNotifyRoutine(MyCreateThreadNotify); } NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath){ NTSTATUS status; status = PsSetCreateThreadNotifyRoutine(MyCreateThreadNotify); DbgPrint("PsSetCreateThreadNotifyRoutine: %x", status); Driver->DriverUnload = UnDriver; return STATUS_SUCCESS; }
|
反进程创建监控
基本原理
系统设置的进程创建回调函数会存储在PspCreateProcessNotifyRoutine
的PVOID类型数组里,这里面存储着系统里所有用PsSetCreateProcessNotifyRoutine
函数设置的进程创建回调函数的加密地址。这个数组没有导出不能直接获取,需要逆向PspSetCreateProcessNotifyRoutine
函数:
1 2 3
| nt!PspSetCreateProcessNotifyRoutine+0x4C: 33 FF xor edi,edi 4C 8D 3D FB 0B DF FF lea r15, [nt!PspCreateProcessNotifyRoutine]
|
定位PspCreateProcessNotifyRoutine
数组地址的方法是特征码,每个系统都不一样:
|
Windows 7 |
Windows 8.1 |
Windows 10 |
x86 |
C7450C |
B8 |
BB |
x64 |
4C8D35 |
4C8D3D |
4C8D3D |
但PspSetCreateProcessNotifyRoutine
也不是导出函数,需要逆向PsSetCreateProcessNotifyRoutine
函数:
1 2 3
| nt!PsSetCreateProcessNotifyRoutine: 45 33 C0 xor r8d, r8d E9 E8 FD FF FF jmp nt!PspSetCreateprocessNotifyRoutine
|
定位PspSetCreateProcessNotifyRoutine
函数地址的方法也是特征码,每个系统也不一样:
|
Windows 7 |
Windows 8.1 |
Windows 10 |
x86 |
E8 |
E8 |
E8 |
x64 |
E9 |
E9 |
E9 |
于是获取PspCreateProcessNotifyRoutine
数组实现代码:
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
| PVOID SearchPspCreateProcessNotifyRoutine(PUCHAR pFirstSpecialData, ULONG ulFirstSpecialDataSize, PUCHAR pSecondSpecialData, ULONG ulSecondSpecialDataSize) { UNICODE_STRING ustrFuncName; PVOID pAddress = NULL; LONG lOffset = 0; PVOID pPsSetCteateProcessNotifyRoutine = NULL; PVOID pPspSetCreateProcessNotifyRoutineAddress = NULL; PVOID pPspCreateProcessNotifyRoutineAddress = NULL; RtlInitUnicodeString(&ustrFuncName, L"PsSetCreateProcessNotifyRoutine"); pPsSetCteateProcessNotifyRoutine = MmGetSystemRoutineAddress(&ustrFuncName); if (NULL == pPsSetCteateProcessNotifyRoutine) { ShowError("MmGetSystemRoutineAddress", 0); return pPspCreateProcessNotifyRoutineAddress; }; pAddress = SearchMemory(pPsSetCteateProcessNotifyRoutine, (PVOID)((PUCHAR)pPsSetCteateProcessNotifyRoutine + 0xFF), pFirstSpecialData, ulFirstSpecialDataSize); if (NULL == pAddress) { ShowError("SearchMemory1", 0); return pPspCreateProcessNotifyRoutineAddress; }; lOffset = *(PLONG)pAddress; pPspSetCreateProcessNotifyRoutineAddress = (PVOID)((PUCHAR)pAddress + sizeof(LONG) + lOffset); pAddress = SearchMemory(pPspSetCreateProcessNotifyRoutineAddress, (PVOID)((PUCHAR)pPspSetCreateProcessNotifyRoutineAddress + 0xFF), pSecondSpecialData, ulSecondSpecialDataSize); if (NULL == pAddress) { ShowError("SearchMemory2", 0); return pPspCreateProcessNotifyRoutineAddress; }; #ifdef _WIN64 lOffset = *(PLONG)pAddress; pPspCreateProcessNotifyRoutineAddress = (PVOID)((PUCHAR)pAddress + sizeof(LONG) + lOffset); #else pPspCreateProcessNotifyRoutineAddress = *(PVOID*)pAddress; #endif return pPspCreateProcessNotifyRoutineAddress; };
|
数组PspCreateProcessNotifyRoutine
是加密的,还需要解密。x86和x64加密方法不同。x86下来说,该数组是个4字节无符号类型数组,数组大小最大为8,每个值与运算0xFFFFFFF8再加4即为解密;x64下来说,该数组是个8字节无符号类型数组,数组大小最大为64,每个值与运算0xFFFFFFFFFFFFFFF8即为解密:
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
| BOOLEAN EnumNotifyRoutine(VOID) { ULONG i = 0; PVOID pPspCreateProcessNotifyRoutineAddress = NULL; PVOID pNotifyRoutineAddress = NULL; pPspCreateProcessNotifyRoutineAddress = GetPspCreateProcessNotifyRoutine(); if (NULL == pPspCreateProcessNotifyRoutineAddress) { DbgPrint("GetPspCreateProcessNotifyRoutine Error!\n"); return FALSE; }; DbgPrint("pPspCreateProcessNotifyRoutineAddress=0x%p\n", pPspCreateProcessNotifyRoutineAddress); #ifdef _WIN64 for (i = 0; i < 64; i++) { pNotifyRoutineAddress = *(PVOID*)((PUCHAR)pPspCreateProcessNotifyRoutineAddress + sizeof(PVOID) * i); pNotifyRoutineAddress = (PVOID)((ULONG64)pNotifyRoutineAddress & 0xfffffffffffffff8); if (MmIsAddressValid(pNotifyRoutineAddress)) { pNotifyRoutineAddress = *(PVOID*)pNotifyRoutineAddress; DbgPrint("[%d]ullNotifyRoutine=0x%p\n", i, pNotifyRoutineAddress); }; }; #else for (i = 0; i < 8; i++) { pNotifyRoutineAddress = *(PVOID*)((PUCHAR)pPspCreateProcessNotifyRoutineAddress + sizeof(PVOID) * i); pNotifyRoutineAddress = (PVOID)((ULONG)pNotifyRoutineAddress & 0xfffffff8); if (MmIsAddressValid(pNotifyRoutineAddress)) { pNotifyRoutineAddress = *(PVOID*)((PUCHAR)pNotifyRoutineAddress + 4); DbgPrint("[%d]ullNotifyRoutine=0x%p\n", i, pNotifyRoutineAddress); }; }; #endif return TRUE; };
|
为了删除进程创建回调函数,有3种方法:
- 函数
PsSetCreateProcessNotifyRoutine
也能删除回调函数,传入回调函数地址和删除标志TRUE即可。
- 修改
PspCreateProcessNotifyRoutine
数组中数据,指向自定义空回调函数地址。
- 修改回调函数内存数据前几字节,直接写入RET。
这里就用第一种最方便了:
1 2 3 4 5 6 7
| NTSTATUS RemoveNotifyRoutine(PVOID pNotifyRoutineAddress) { NTSTATUS status = PsSetCreateProcessNotifyRoutine((PCREATE_PROCESS_NOTIFY_ROUTINE)pNotifyRoutineAddress, TRUE); if (!NT_SUCCESS(status)) ShowError("PsSetCreateProcessNotifyRoutine", status); return status; };
|
源代码
Driver.h:
1 2 3 4 5 6
| #ifndef _DRIVER_H_ #define _DRIVER_H_ #include <ntddk.h> VOID DriverUnload(PDRIVER_OBJECT pDriverObject); NTSTATUS DriverDefaultHandle(PDEVICE_OBJECT pDevObj, PIRP pIrp); #endif
|
EnumRemove.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| #ifndef _ENUM_REMOVE_H_ #define _ENUM_REMOVE_H_ #include <ntddk.h>
BOOLEAN EnumNotifyRoutine();
NTSTATUS RemoveNotifyRoutine(PVOID pNotifyRoutineAddress);
PVOID GetPspCreateProcessNotifyRoutine();
PVOID SearchPspCreateProcessNotifyRoutine(PUCHAR pFirstSpecialData, ULONG ulFirstSpecialDataSize, PUCHAR pSecondSpecialData, ULONG ulSecondSpecialDataSize);
PVOID SearchMemory(PVOID pStartAddress, PVOID pEndAddress, PUCHAR pMemoryData, ULONG ulMemoryDataSize); #endif
|
Driver.c:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| #include "EnumRemove.h" #include "Driver.h" NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath){ NTSTATUS status = STATUS_SUCCESS; pDriverObject->DriverUnload = DriverUnload; for (ULONG i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) pDriverObject->MajorFunction[i] = DriverDefaultHandle; EnumNotifyRoutine(); return status; } VOID DriverUnload(PDRIVER_OBJECT pDriverObject){ } NTSTATUS DriverDefaultHandle(PDEVICE_OBJECT pDevObj, PIRP pIrp){ NTSTATUS status = STATUS_SUCCESS; pIrp->IoStatus.Status = status; pIrp->IoStatus.Information = 0; IoCompleteRequest(pIrp, IO_NO_INCREMENT); return status; }
|
EnumRemove.c:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
| #include "EnumRemove.h" VOID ShowError(PCHAR lpszText, NTSTATUS ntStatus){ DbgPrint("%s Error[0x%X]\n", lpszText, ntStatus); }
BOOLEAN EnumNotifyRoutine(){ ULONG i = 0; PVOID pPspCreateProcessNotifyRoutineAddress = NULL; PVOID pNotifyRoutineAddress = NULL; pPspCreateProcessNotifyRoutineAddress = GetPspCreateProcessNotifyRoutine(); if (NULL == pPspCreateProcessNotifyRoutineAddress){ DbgPrint("GetPspCreateProcessNotifyRoutine Error!\n"); return FALSE; } DbgPrint("pPspCreateProcessNotifyRoutineAddress=0x%p\n", pPspCreateProcessNotifyRoutineAddress); #ifdef _WIN64 for (i = 0; i < 64; i++){ pNotifyRoutineAddress = *(PVOID *)((PUCHAR)pPspCreateProcessNotifyRoutineAddress + sizeof(PVOID) * i); pNotifyRoutineAddress = (PVOID)((ULONG64)pNotifyRoutineAddress & 0xfffffffffffffff8); if (MmIsAddressValid(pNotifyRoutineAddress)){ pNotifyRoutineAddress = *(PVOID *)pNotifyRoutineAddress; DbgPrint("[%d]ullNotifyRoutine=0x%p\n", i, pNotifyRoutineAddress); } } #else for (i = 0; i < 8; i++){ pNotifyRoutineAddress = *(PVOID *)((PUCHAR)pPspCreateProcessNotifyRoutineAddress + sizeof(PVOID) * i); pNotifyRoutineAddress = (PVOID)((ULONG)pNotifyRoutineAddress & 0xfffffff8); if (MmIsAddressValid(pNotifyRoutineAddress)){ pNotifyRoutineAddress = *(PVOID *)((PUCHAR)pNotifyRoutineAddress + 4); DbgPrint("[%d]ullNotifyRoutine=0x%p\n", i, pNotifyRoutineAddress); } } #endif return TRUE; }
NTSTATUS RemoveNotifyRoutine(PVOID pNotifyRoutineAddress){ NTSTATUS status = PsSetCreateProcessNotifyRoutine((PCREATE_PROCESS_NOTIFY_ROUTINE)pNotifyRoutineAddress, TRUE); if (!NT_SUCCESS(status)) ShowError("PsSetCreateProcessNotifyRoutine", status); return status; }
PVOID GetPspCreateProcessNotifyRoutine(){ PVOID pPspCreateProcessNotifyRoutineAddress = NULL; RTL_OSVERSIONINFOW osInfo = { 0 }; UCHAR pFirstSpecialData[50] = { 0 }; ULONG ulFirstSpecialDataSize = 0; UCHAR pSecondSpecialData[50] = { 0 }; ULONG ulSecondSpecialDataSize = 0; RtlGetVersion(&osInfo); if (6 == osInfo.dwMajorVersion){ if (1 == osInfo.dwMinorVersion){ #ifdef _WIN64 pFirstSpecialData[0] = 0xE9; ulFirstSpecialDataSize = 1; pSecondSpecialData[0] = 0x4C; pSecondSpecialData[1] = 0x8D; pSecondSpecialData[2] = 0x35; ulSecondSpecialDataSize = 3; #else pFirstSpecialData[0] = 0xE8; ulFirstSpecialDataSize = 1; pSecondSpecialData[0] = 0xC7; pSecondSpecialData[1] = 0x45; pSecondSpecialData[2] = 0x0C; ulSecondSpecialDataSize = 3; #endif } else if (2 == osInfo.dwMinorVersion){ #ifdef _WIN64 #else #endif } else if (3 == osInfo.dwMinorVersion){ #ifdef _WIN64 pFirstSpecialData[0] = 0xE9; ulFirstSpecialDataSize = 1; pSecondSpecialData[0] = 0x4C; pSecondSpecialData[1] = 0x8D; pSecondSpecialData[2] = 0x3D; ulSecondSpecialDataSize = 3; #else pFirstSpecialData[0] = 0xE8; ulFirstSpecialDataSize = 1; pSecondSpecialData[0] = 0xB8; ulSecondSpecialDataSize = 1; #endif } } else if (10 == osInfo.dwMajorVersion){ #ifdef _WIN64 pFirstSpecialData[0] = 0xE9; ulFirstSpecialDataSize = 1; pSecondSpecialData[0] = 0x4C; pSecondSpecialData[1] = 0x8D; pSecondSpecialData[2] = 0x3D; ulSecondSpecialDataSize = 3; #else pFirstSpecialData[0] = 0xE8; ulFirstSpecialDataSize = 1; pSecondSpecialData[0] = 0xBB; ulSecondSpecialDataSize = 1; #endif } pPspCreateProcessNotifyRoutineAddress = SearchPspCreateProcessNotifyRoutine(pFirstSpecialData, ulFirstSpecialDataSize, pSecondSpecialData, ulSecondSpecialDataSize); return pPspCreateProcessNotifyRoutineAddress; }
PVOID SearchPspCreateProcessNotifyRoutine(PUCHAR pFirstSpecialData, ULONG ulFirstSpecialDataSize, PUCHAR pSecondSpecialData, ULONG ulSecondSpecialDataSize){ UNICODE_STRING ustrFuncName; PVOID pAddress = NULL; LONG lOffset = 0; PVOID pPsSetCteateProcessNotifyRoutine = NULL; PVOID pPspSetCreateProcessNotifyRoutineAddress = NULL; PVOID pPspCreateProcessNotifyRoutineAddress = NULL; RtlInitUnicodeString(&ustrFuncName, L"PsSetCreateProcessNotifyRoutine"); pPsSetCteateProcessNotifyRoutine = MmGetSystemRoutineAddress(&ustrFuncName); if (NULL == pPsSetCteateProcessNotifyRoutine){ ShowError("MmGetSystemRoutineAddress", 0); return pPspCreateProcessNotifyRoutineAddress; } pAddress = SearchMemory(pPsSetCteateProcessNotifyRoutine, (PVOID)((PUCHAR)pPsSetCteateProcessNotifyRoutine + 0xFF), pFirstSpecialData, ulFirstSpecialDataSize); if (NULL == pAddress){ ShowError("SearchMemory1", 0); return pPspCreateProcessNotifyRoutineAddress; } lOffset = *(PLONG)pAddress; pPspSetCreateProcessNotifyRoutineAddress = (PVOID)((PUCHAR)pAddress + sizeof(LONG) + lOffset); pAddress = SearchMemory(pPspSetCreateProcessNotifyRoutineAddress, (PVOID)((PUCHAR)pPspSetCreateProcessNotifyRoutineAddress + 0xFF), pSecondSpecialData, ulSecondSpecialDataSize); if (NULL == pAddress){ ShowError("SearchMemory2", 0); return pPspCreateProcessNotifyRoutineAddress; } #ifdef _WIN64 lOffset = *(PLONG)pAddress; pPspCreateProcessNotifyRoutineAddress = (PVOID)((PUCHAR)pAddress + sizeof(LONG) + lOffset); #else pPspCreateProcessNotifyRoutineAddress = *(PVOID *)pAddress; #endif return pPspCreateProcessNotifyRoutineAddress; }
PVOID SearchMemory(PVOID pStartAddress, PVOID pEndAddress, PUCHAR pMemoryData, ULONG ulMemoryDataSize){ PVOID pAddress = NULL; PUCHAR i = NULL; ULONG m = 0; for (i = (PUCHAR)pStartAddress; i < (PUCHAR)pEndAddress; i++){ for (m = 0; m < ulMemoryDataSize; m++) if (*(PUCHAR)(i + m) != pMemoryData[m]) break; if (m >= ulMemoryDataSize){ pAddress = (PVOID)(i + ulMemoryDataSize); break; } } return pAddress; }
|
反线程创建监控
基本原理
系统线程创建回调函数设置用PsSetCreateThreadNotifyRoutine
函数,这个上面没讲但跟进程操作差不多。
线程创建回调函数地址数组叫PspCreateThreadNotifyRoutine
,该数组地址通过PsSetCreateThreadNotifyRoutine
获取:
1 2 3 4 5 6 7 8 9 10 11
| ;Windows 8.1 x86下: nt!PsSetCreateThreadNotifyRoutine+0x16: 53 push ebx 57 push edi BB C8 64 01 81 mov ebx, offset nt!PspCreateThreadNofityRoutine 33 FF xor edir, edi
;Windows 8.1 x64下: nt!PsSetCreateThreadNotifyRoutine+0x1F: 48 8D 0D E6 FE DB FF lea rcx, [nt!PspCreateThreadNotifyRoutine] 45 33 C0 xor r8d, r8d
|
在Windows 7、Windows 8、Windows 8.1等中,函数PsSetCreateThreadNotifyRoutine
是导出的,x86下可直接定位该数组地址,x64下可直接获取该数组偏移并计算出数组地址。
但Windows 10 x64下函数PsSetCreateThreadNotifyRoutine
先调用了函数PspSetCreateThreadNotifyRoutine
:
1 2 3 4 5 6 7
| nt!PsSetCreateThreadNotifyRoutine: 33 D2 xor edx, edx E9 05 01 00 00 jmp nt!PspSetCreateThreadNotifyRoutine
nt!PspSetCreateThreadNotifyRoutine+0x2D: 48 8D 0D 74 0B DF FF lea rcx, [nt!PspCreateThreadNotifyRoutine] 45 33 C0 xor r8d, r8d
|
但是PspSetCreateThreadNotifyRoutine
函数没导出,所以这个函数得特征码扫描,然后数组地址获取方法同Windows 10前操作系统方法。
数组特征码:
|
Windows 7 |
Windows 8.1 |
Windows 10 |
x86 |
BE |
BB |
E8/BF |
x64 |
488D0D |
488D0D |
E9/488D0D |
根据特征码获取数组具体实现代码:
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
| PVOID SearchPspCreateThreadNotifyRoutine(PUCHAR pFirstSpecialData, ULONG ulFirstSpecialDataSize, PUCHAR pSecondSpecialData, ULONG ulSecondSpecialDataSize) { UNICODE_STRING ustrFuncName; PVOID pAddress = NULL; LONG lOffset = 0; PVOID pPsSetCreateThreadNotifyRoutine = NULL; PVOID pPspSetCreateThreadNotifyRoutineAddress = NULL; PVOID pPspCreateThreadNotifyRoutineAddress = NULL; RtlInitUnicodeString(&ustrFuncName, L"PsSetCreateThreadNotifyRoutine"); pPsSetCreateThreadNotifyRoutine = MmGetSystemRoutineAddress(&ustrFuncName); if (NULL == pPsSetCreateThreadNotifyRoutine) { ShowError("MmGetSystemRoutineAddress", 0); return pPspCreateThreadNotifyRoutineAddress; }; pAddress = SearchMemory(pPsSetCreateThreadNotifyRoutine, (PVOID)((PUCHAR)pPsSetCreateThreadNotifyRoutine + 0xFF), pFirstSpecialData, ulFirstSpecialDataSize); if (NULL == pAddress) { ShowError("SearchMemory1", 0); return pPspCreateThreadNotifyRoutineAddress; }; if (0 == ulSecondSpecialDataSize) { #ifdef _WIN64 lOffset = *(PLONG)pAddress; pPspCreateThreadNotifyRoutineAddress = (PVOID)((PUCHAR)pAddress + sizeof(LONG) + lOffset); #else pPspCreateThreadNotifyRoutineAddress = *(PVOID*)pAddress; #endif return pPspCreateThreadNotifyRoutineAddress; }; lOffset = *(PLONG)pAddress; pPspSetCreateThreadNotifyRoutineAddress = (PVOID)((PUCHAR)pAddress + sizeof(LONG) + lOffset); pAddress = SearchMemory(pPspSetCreateThreadNotifyRoutineAddress, (PVOID)((PUCHAR)pPspSetCreateThreadNotifyRoutineAddress + 0xFF), pSecondSpecialData, ulSecondSpecialDataSize); if (NULL == pAddress) { ShowError("SearchMemory2", 0); return pPspCreateThreadNotifyRoutineAddress; }; #ifdef _WIN64 lOffset = *(PLONG)pAddress; pPspCreateThreadNotifyRoutineAddress = (PVOID)((PUCHAR)pAddress + sizeof(LONG) + lOffset); #else pPspCreateThreadNotifyRoutineAddress = *(PVOID*)pAddress; #endif return pPspCreateThreadNotifyRoutineAddress; };
|
别忘了数组还需要解密,解密方法同进程:
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
| BOOLEAN EnumNotifyRoutine(VOID) { ULONG i = 0; PVOID pPspCreateThreadNotifyRoutineAddress = NULL; PVOID pNotifyRoutineAddress = NULL; pPspCreateThreadNotifyRoutineAddress = GetPspCreateThreadNotifyRoutine(); if (NULL == pPspCreateThreadNotifyRoutineAddress) { DbgPrint("GetPspCreateThreadNotifyRoutine Error!\n"); return FALSE; }; DbgPrint("pPspCreateThreadNotifyRoutineAddress=0x%p\n", pPspCreateThreadNotifyRoutineAddress); #ifdef _WIN64 for (i = 0; i < 64; i++) { pNotifyRoutineAddress = *(PVOID*)((PUCHAR)pPspCreateThreadNotifyRoutineAddress + sizeof(PVOID) * i); pNotifyRoutineAddress = (PVOID)((ULONG64)pNotifyRoutineAddress & 0xfffffffffffffff8); if (MmIsAddressValid(pNotifyRoutineAddress)) { pNotifyRoutineAddress = *(PVOID*)pNotifyRoutineAddress; DbgPrint("[%d]ullNotifyRoutine=0x%p\n", i, pNotifyRoutineAddress); }; }; #else for (i = 0; i < 8; i++) { pNotifyRoutineAddress = *(PVOID*)((PUCHAR)pPspCreateThreadNotifyRoutineAddress + sizeof(PVOID) * i); pNotifyRoutineAddress = (PVOID)((ULONG)pNotifyRoutineAddress & 0xfffffff8); if (MmIsAddressValid(pNotifyRoutineAddress)) { pNotifyRoutineAddress = *(PVOID*)((PUCHAR)pNotifyRoutineAddress + 4); DbgPrint("[%d]ullNotifyRoutine=0x%p\n", i, pNotifyRoutineAddress); }; }; #endif return TRUE; };
|
删除线程创建回调函数的方法依然同进程:
1 2 3 4 5 6 7
| NTSTATUS RemoveNotifyRoutine(PVOID pNotifyRoutineAddress) { NTSTATUS status = PsRemoveCreateThreadNotifyRoutine((PCREATE_THREAD_NOTIFY_ROUTINE)pNotifyRoutineAddress); if (!NT_SUCCESS(status)) ShowError("PsRemoveCreateThreadNotifyRoutine", status); return status; };
|
源代码
Driver.h:
1 2 3 4 5 6
| #ifndef _DRIVER_H_ #define _DRIVER_H_ #include <ntddk.h> VOID DriverUnload(PDRIVER_OBJECT pDriverObject); NTSTATUS DriverDefaultHandle(PDEVICE_OBJECT pDevObj, PIRP pIrp); #endif
|
EnumRemove.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| #ifndef _ENUM_REMOVE_H_ #define _ENUM_REMOVE_H_ #include <ntddk.h>
BOOLEAN EnumNotifyRoutine();
NTSTATUS RemoveNotifyRoutine(PVOID pNotifyRoutineAddress);
PVOID GetPspCreateThreadNotifyRoutine();
PVOID SearchPspCreateThreadNotifyRoutine(PUCHAR pFirstSpecialData, ULONG ulFirstSpecialDataSize, PUCHAR pSecondSpecialData, ULONG ulSecondSpecialDataSize);
PVOID SearchMemory(PVOID pStartAddress, PVOID pEndAddress, PUCHAR pMemoryData, ULONG ulMemoryDataSize); #endif
|
Driver.c:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #include "EnumRemove.h" #include "Driver.h" NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath){ NTSTATUS status = STATUS_SUCCESS; pDriverObject->DriverUnload = DriverUnload; for (ULONG i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) pDriverObject->MajorFunction[i] = DriverDefaultHandle; EnumNotifyRoutine(); return status; } VOID DriverUnload(PDRIVER_OBJECT pDriverObject){ } NTSTATUS DriverDefaultHandle(PDEVICE_OBJECT pDevObj, PIRP pIrp){ NTSTATUS status = STATUS_SUCCESS; pIrp->IoStatus.Status = status; pIrp->IoStatus.Information = 0; IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return status; }
|
EnumRemove.c:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
| #include "EnumRemove.h" VOID ShowError(PCHAR lpszText, NTSTATUS ntStatus){ DbgPrint("%s Error[0x%X]\n", lpszText, ntStatus); }
BOOLEAN EnumNotifyRoutine(){ ULONG i = 0; PVOID pPspCreateThreadNotifyRoutineAddress = NULL; PVOID pNotifyRoutineAddress = NULL; pPspCreateThreadNotifyRoutineAddress = GetPspCreateThreadNotifyRoutine(); if (NULL == pPspCreateThreadNotifyRoutineAddress){ DbgPrint("GetPspCreateThreadNotifyRoutine Error!\n"); return FALSE; } DbgPrint("pPspCreateThreadNotifyRoutineAddress=0x%p\n", pPspCreateThreadNotifyRoutineAddress); #ifdef _WIN64 for (i = 0; i < 64; i++){ pNotifyRoutineAddress = *(PVOID *)((PUCHAR)pPspCreateThreadNotifyRoutineAddress + sizeof(PVOID) * i); pNotifyRoutineAddress = (PVOID)((ULONG64)pNotifyRoutineAddress & 0xfffffffffffffff8); if (MmIsAddressValid(pNotifyRoutineAddress)){ pNotifyRoutineAddress = *(PVOID *)pNotifyRoutineAddress; DbgPrint("[%d]ullNotifyRoutine=0x%p\n", i, pNotifyRoutineAddress); } } #else for (i = 0; i < 8; i++){ pNotifyRoutineAddress = *(PVOID *)((PUCHAR)pPspCreateThreadNotifyRoutineAddress + sizeof(PVOID) * i); pNotifyRoutineAddress = (PVOID)((ULONG)pNotifyRoutineAddress & 0xfffffff8); if (MmIsAddressValid(pNotifyRoutineAddress)){ pNotifyRoutineAddress = *(PVOID *)((PUCHAR)pNotifyRoutineAddress + 4); DbgPrint("[%d]ullNotifyRoutine=0x%p\n", i, pNotifyRoutineAddress); } } #endif return TRUE; }
NTSTATUS RemoveNotifyRoutine(PVOID pNotifyRoutineAddress){ NTSTATUS status = PsRemoveCreateThreadNotifyRoutine((PCREATE_THREAD_NOTIFY_ROUTINE)pNotifyRoutineAddress); if (!NT_SUCCESS(status)) ShowError("PsRemoveCreateThreadNotifyRoutine", status); return status; }
PVOID GetPspCreateThreadNotifyRoutine(){ PVOID pPspCreateThreadNotifyRoutineAddress = NULL; RTL_OSVERSIONINFOW osInfo = { 0 }; UCHAR pFirstSpecialData[50] = { 0 }; ULONG ulFirstSpecialDataSize = 0; UCHAR pSecondSpecialData[50] = { 0 }; ULONG ulSecondSpecialDataSize = 0; RtlGetVersion(&osInfo); if (6 == osInfo.dwMajorVersion){ if (1 == osInfo.dwMinorVersion){ #ifdef _WIN64 pFirstSpecialData[0] = 0x48; pFirstSpecialData[1] = 0x8D; pFirstSpecialData[2] = 0x0D; ulFirstSpecialDataSize = 3; #else pFirstSpecialData[0] = 0xBE; ulFirstSpecialDataSize = 1; #endif } else if (2 == osInfo.dwMinorVersion){ #ifdef _WIN64 #else #endif } else if (3 == osInfo.dwMinorVersion){ #ifdef _WIN64 pFirstSpecialData[0] = 0x48; pFirstSpecialData[1] = 0x8D; pFirstSpecialData[2] = 0x0D; ulFirstSpecialDataSize = 3; #else pFirstSpecialData[0] = 0xBB; ulFirstSpecialDataSize = 1; #endif } } else if (10 == osInfo.dwMajorVersion){ #ifdef _WIN64 pFirstSpecialData[0] = 0xE9; ulFirstSpecialDataSize = 1; pSecondSpecialData[0] = 0x48; pSecondSpecialData[1] = 0x8D; pSecondSpecialData[2] = 0x0D; ulSecondSpecialDataSize = 3; #else pFirstSpecialData[0] = 0xE8; ulFirstSpecialDataSize = 1; pSecondSpecialData[0] = 0xBF; ulSecondSpecialDataSize = 1; #endif } pPspCreateThreadNotifyRoutineAddress = SearchPspCreateThreadNotifyRoutine(pFirstSpecialData, ulFirstSpecialDataSize, pSecondSpecialData, ulSecondSpecialDataSize); return pPspCreateThreadNotifyRoutineAddress; }
PVOID SearchPspCreateThreadNotifyRoutine(PUCHAR pFirstSpecialData, ULONG ulFirstSpecialDataSize, PUCHAR pSecondSpecialData, ULONG ulSecondSpecialDataSize){ UNICODE_STRING ustrFuncName; PVOID pAddress = NULL; LONG lOffset = 0; PVOID pPsSetCreateThreadNotifyRoutine = NULL; PVOID pPspSetCreateThreadNotifyRoutineAddress = NULL; PVOID pPspCreateThreadNotifyRoutineAddress = NULL; RtlInitUnicodeString(&ustrFuncName, L"PsSetCreateThreadNotifyRoutine"); pPsSetCreateThreadNotifyRoutine = MmGetSystemRoutineAddress(&ustrFuncName); if (NULL == pPsSetCreateThreadNotifyRoutine){ ShowError("MmGetSystemRoutineAddress", 0); return pPspCreateThreadNotifyRoutineAddress; } pAddress = SearchMemory(pPsSetCreateThreadNotifyRoutine, (PVOID)((PUCHAR)pPsSetCreateThreadNotifyRoutine + 0xFF), pFirstSpecialData, ulFirstSpecialDataSize); if (NULL == pAddress){ ShowError("SearchMemory1", 0); return pPspCreateThreadNotifyRoutineAddress; } if (0 == ulSecondSpecialDataSize){ #ifdef _WIN64 lOffset = *(PLONG)pAddress; pPspCreateThreadNotifyRoutineAddress = (PVOID)((PUCHAR)pAddress + sizeof(LONG) + lOffset); #else pPspCreateThreadNotifyRoutineAddress = *(PVOID *)pAddress; #endif return pPspCreateThreadNotifyRoutineAddress; } lOffset = *(PLONG)pAddress; pPspSetCreateThreadNotifyRoutineAddress = (PVOID)((PUCHAR)pAddress + sizeof(LONG) + lOffset); pAddress = SearchMemory(pPspSetCreateThreadNotifyRoutineAddress, (PVOID)((PUCHAR)pPspSetCreateThreadNotifyRoutineAddress + 0xFF), pSecondSpecialData, ulSecondSpecialDataSize); if (NULL == pAddress){ ShowError("SearchMemory2", 0); return pPspCreateThreadNotifyRoutineAddress; } #ifdef _WIN64 lOffset = *(PLONG)pAddress; pPspCreateThreadNotifyRoutineAddress = (PVOID)((PUCHAR)pAddress + sizeof(LONG) + lOffset); #else pPspCreateThreadNotifyRoutineAddress = *(PVOID *)pAddress; #endif return pPspCreateThreadNotifyRoutineAddress; }
PVOID SearchMemory(PVOID pStartAddress, PVOID pEndAddress, PUCHAR pMemoryData, ULONG ulMemoryDataSize){ PVOID pAddress = NULL; PUCHAR i = NULL; ULONG m = 0; for (i = (PUCHAR)pStartAddress; i < (PUCHAR)pEndAddress; i++){ for (m = 0; m < ulMemoryDataSize; m++) if (*(PUCHAR)(i + m) != pMemoryData[m]) break; if (m >= ulMemoryDataSize){ pAddress = (PVOID)(i + ulMemoryDataSize); break; } } return pAddress; }
|
进程模块加载监控
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
| #include <ntddk.h> #include <ntimage.h> PVOID GetDriverEntryByImageBase(PVOID ImageBase){ PIMAGE_DOS_HEADER pDOSHeader; PIMAGE_NT_HEADERS64 pNTHeader; PVOID pEntryPoint; pDOSHeader = (PIMAGE_DOS_HEADER)ImageBase; pNTHeader = (PIMAGE_NT_HEADERS64)((ULONG64)ImageBase + pDOSHeader->e_lfanew); pEntryPoint = (PVOID)((ULONG64)ImageBase + pNTHeader->OptionalHeader.AddressOfEntryPoint); return pEntryPoint; } VOID MyLoadImageNotifyRoutine(PUNICODE_STRING FullImageName,HANDLE ProcessId,PIMAGE_INFO ImageInfo){ PVOID pDrvEntry; if (FullImageName != NULL && MmIsAddressValid(FullImageName)) if (ProcessId == 0){ pDrvEntry = GetDriverEntryByImageBase(ImageInfo->ImageBase); DbgPrint("模块名称:%wZ --> 装载基址:%p --> 镜像长度: %d", FullImageName, pDrvEntry,ImageInfo->ImageSize); } } VOID UnDriver(PDRIVER_OBJECT driver){ PsRemoveLoadImageNotifyRoutine((PLOAD_IMAGE_NOTIFY_ROUTINE)MyLoadImageNotifyRoutine); } NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath){ PsSetLoadImageNotifyRoutine((PLOAD_IMAGE_NOTIFY_ROUTINE)MyLoadImageNotifyRoutine); Driver->DriverUnload = UnDriver; return STATUS_SUCCESS; }
|
改一下可查找指定模块:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| VOID UnicodeToChar(PUNICODE_STRING dst, char *src){ ANSI_STRING string; RtlUnicodeStringToAnsiString(&string, dst, TRUE); strcpy(src, string.Buffer); RtlFreeAnsiString(&string); } VOID MyLoadImageNotifyRoutine(PUNICODE_STRING FullImageName,HANDLE ModuleStyle,PIMAGE_INFO ImageInfo){ PVOID pDrvEntry; char szFullImageName[256] = { 0 }; if (FullImageName != NULL && MmIsAddressValid(FullImageName)) if (ModuleStyle == 0){ pDrvEntry = GetDriverEntryByImageBase(ImageInfo->ImageBase); UnicodeToChar(FullImageName, szFullImageName); if (strstr(_strlwr(szFullImageName), "hook.sys")) DbgPrint("准备拦截SYS内核模块:%s", _strlwr(szFullImageName)); } }
|
为了屏蔽某SYS模块,可在驱动头部写入ret返回指令,以屏蔽加载特定驱动文件。
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
| #include <ntddk.h> #include <intrin.h> #include <ntimage.h> PVOID GetDriverEntryByImageBase(PVOID ImageBase){ PIMAGE_DOS_HEADER pDOSHeader; PIMAGE_NT_HEADERS64 pNTHeader; PVOID pEntryPoint; pDOSHeader = (PIMAGE_DOS_HEADER)ImageBase; pNTHeader = (PIMAGE_NT_HEADERS64)((ULONG64)ImageBase + pDOSHeader->e_lfanew); pEntryPoint = (PVOID)((ULONG64)ImageBase + pNTHeader->OptionalHeader.AddressOfEntryPoint); return pEntryPoint; } VOID UnicodeToChar(PUNICODE_STRING dst, char *src){ ANSI_STRING string; RtlUnicodeStringToAnsiString(&string, dst, TRUE); strcpy(src, string.Buffer); RtlFreeAnsiString(&string); }
KIRQL WPOFFx64() { KIRQL irql = KeRaiseIrqlToDpcLevel(); UINT64 cr0 = __readcr0(); cr0 &= 0xfffffffffffeffff; _disable(); __writecr0(cr0); return irql; } void WPONx64(KIRQL irql){ UINT64 cr0 = __readcr0(); cr0 |= 0x10000; _enable(); __writecr0(cr0); KeLowerIrql(irql); } BOOLEAN DenyLoadDriver(PVOID DriverEntry){ UCHAR fuck[] = "\xB8\x22\x00\x00\xC0\xC3"; KIRQL kirql;
if (DriverEntry == NULL) return FALSE; kirql = WPOFFx64(); memcpy(DriverEntry, fuck,sizeof(fuck) / sizeof(fuck[0])); WPONx64(kirql); return TRUE; } VOID MyLoadImageNotifyRoutine(PUNICODE_STRING FullImageName, HANDLE ModuleStyle, PIMAGE_INFO ImageInfo){ PVOID pDrvEntry; char szFullImageName[256] = { 0 }; if (FullImageName != NULL && MmIsAddressValid(FullImageName)) if (ModuleStyle == 0) { pDrvEntry = GetDriverEntryByImageBase(ImageInfo->ImageBase); UnicodeToChar(FullImageName, szFullImageName); if (strstr(_strlwr(szFullImageName), "hook.sys")){ DbgPrint("拦截SYS内核模块:%s", szFullImageName); DenyLoadDriver(pDrvEntry); } } } VOID UnDriver(PDRIVER_OBJECT driver){ PsRemoveLoadImageNotifyRoutine((PLOAD_IMAGE_NOTIFY_ROUTINE)MyLoadImageNotifyRoutine); } NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath){ PsSetLoadImageNotifyRoutine((PLOAD_IMAGE_NOTIFY_ROUTINE)MyLoadImageNotifyRoutine); Driver->DriverUnload = UnDriver; return STATUS_SUCCESS; }
|
另一种写法,拦截DLL:
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
| char *UnicodeToLongString(PUNICODE_STRING uString){ ANSI_STRING asStr; char *Buffer = NULL;; RtlUnicodeStringToAnsiString(&asStr, uString, TRUE); Buffer = ExAllocatePoolWithTag(NonPagedPool, uString->MaximumLength * sizeof(wchar_t), 0); if (Buffer == NULL) return NULL; RtlCopyMemory(Buffer, asStr.Buffer, asStr.Length); return Buffer; } VOID MyLoadImageNotifyRoutine(PUNICODE_STRING FullImageName, HANDLE ModuleStyle, PIMAGE_INFO ImageInfo){ PVOID pDrvEntry; char *PareString = NULL; if (MmIsAddressValid(FullImageName)) if (ModuleStyle != 0){ PareString = UnicodeToLongString(FullImageName); if (PareString != NULL) if (strstr(PareString, "hook.dll")){ pDrvEntry = GetDriverEntryByImageBase(ImageInfo->ImageBase); if (pDrvEntry != NULL) DenyLoadDriver(pDrvEntry); } } }
|