crochet de noyau x64

X64 Kernel Hook



Le système x64 fournit des API pour nous aider à accrocher, principalement les trois fonctions suivantes

PsSetCreateProcessNotifyRoutineEx, La fonction de cette fonction est Vous avertira lorsque le processus est créé.



PsSetCreateThreadNotifyRoutine, La fonction de cette fonction est Vous serez averti lorsque le fil est créé.



PsSetLoadImageNotifyRoutine, La fonction de cette fonction est Vous serez averti lorsque le module sera chargé.



Callback function prototype VOID CreateProcessNotifyEx( __inout PEPROCESS Process, //The EPROCESS of the process will be provided to you. __in HANDLE ProcessId, //The process ID will be provided to you. __in_opt PPS_CREATE_NOTIFY_INFO CreateInfo //Additional information of process information will be provided to you. Note that the parameter is operable. That is to say, it may be NULL ) NTSTATUS PsSetCreateThreadNotifyRoutine( IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine //Callback function address. When the thread is created, but your callback is not yet run, it will be called. ) NTSTATUS PsSetLoadImageNotifyRoutine( IN PLOAD_IMAGE_NOTIFY_ROUTINE NotifyRoutine )

Les codes de rappel de processus et de thread sont les suivants:

#include NTKERNELAPI PCHAR PsGetProcessImageFileName(PEPROCESS Process) NTKERNELAPI NTSTATUS PsLookupProcessByProcessId(HANDLE ProcessId, PEPROCESS *Process) /*typedef struct _PS_CREATE_NOTIFY_INFO { SIZE_T Size union { ULONG Flags struct { ULONG FileOpenNameAvailable :1 ULONG Reserved :31 } } HANDLE ParentProcessId CLIENT_ID CreatingThreadId struct _FILE_OBJECT *FileObject PCUNICODE_STRING ImageFileName PCUNICODE_STRING CommandLine NTSTATUS CreationStatus } PS_CREATE_NOTIFY_INFO, *PPS_CREATE_NOTIFY_INFO*/ /*VOID MyCreateProcessNotifyEx //Monitor only ( __inout PEPROCESS Process, __in HANDLE ProcessId, __in_opt PPS_CREATE_NOTIFY_INFO CreateInfo ) { if(CreateInfo==NULL) DbgPrint('[monitor_create_process_x64] Process exit: %s',PsGetProcessImageFileName(Process)) else DbgPrint('[monitor_create_process_x64] Process create: %wZ',CreateInfo->CommandLine) }*/ PCHAR GetProcessNameByProcessId(HANDLE ProcessId) { NTSTATUS st = STATUS_UNSUCCESSFUL PEPROCESS ProcessObj = NULL PCHAR string = NULL st = PsLookupProcessByProcessId(ProcessId, &ProcessObj) if (NT_SUCCESS(st)) { string = PsGetProcessImageFileName(ProcessObj) ObfDereferenceObject(ProcessObj) } return string } VOID MyCreateProcessNotifyEx ( __inout PEPROCESS Process, __in HANDLE ProcessId, __in_opt PPS_CREATE_NOTIFY_INFO CreateInfo ) { char procName[16] = { 0 } if (CreateInfo != NULL) //Process creation event { DbgPrint('[monitor_create_process_x64][%ld]%s create process: %wZ', CreateInfo->ParentProcessId, GetProcessNameByProcessId(CreateInfo->ParentProcessId), CreateInfo->ImageFileName) strcpy(procName, PsGetProcessImageFileName(Process)) DbgPrint('The name of the created process is: %p/n', procName) if (!_stricmp(procName, 'calc.exe')) { DbgPrint('Prohibit the creation of calculator process!') CreateInfo->CreationStatus = STATUS_UNSUCCESSFUL //Prohibit the creation process } } else { DbgPrint('[monitor_create_process_x64] Process exit: %s', PsGetProcessImageFileName(Process)) } } VOID MyCreateThreadNotify ( IN HANDLE ProcessId, IN HANDLE ThreadId, IN BOOLEAN Create ) { if (Create) DbgPrint('[monitor_create_process_x64]Thread creation! PID=%ldTID=%ld', ProcessId, ThreadId) else DbgPrint('[monitor_create_process_x64] Thread exits! PID=%ldTID=%ld', ProcessId, ThreadId) PEPROCESS Process = NULL PETHREAD Thread = NULL UCHAR *pszImageName = NULL NTSTATUS status UCHAR *pWin32Address = NULL status = PsLookupProcessByProcessId(ProcessId, &Process)//1. Get EPROCESS by process ID if (!NT_SUCCESS(status)) return status = PsLookupThreadByThreadId(ThreadId, &Thread)//2. Get ETHREAD by thread ID pszImageName = PsGetProcessImageFileName(Process)//3. Get the process name through EPROCESS if (Create) { //dprintf('[Hello] Create Thread pid=%d tid=%d ImageName=%s ', ProcessId, ThreadId, pszImageName) if (strstr(pszImageName, 'calc') != NULL) //4. Determine whether the process name is a calculator { //KdBreakPoint() //Modify the callback function code pWin32Address = *(UCHAR**)((UCHAR*)Thread + 0x410) //5. If yes, find the callback function address. Change to C3 //KeAttachProcess() if (MmIsAddressValid(pWin32Address)) { KdBreakPoint() //*pWin32Address = 0xC3 //Modify to C3, but note that whether you modify the memory protection attribute needs to be removed. However, in 64-bit, inline assembly is not allowed. But you can write binary to change. Or assembly Generate obj, drive to use //Here directly change to C3 manually. } //KeUnstackDetachProcess() } } else //dprintf('[Hello] Exit Thread pid=%d tid=%d ', ProcessId, ThreadId) if (Process) ObDereferenceObject(Process) //Reference count-- if (Thread) ObDereferenceObject(Thread) } VOID Monitor() { // set create process/thread notify NTSTATUS st = PsSetCreateProcessNotifyRoutineEx((PCREATE_PROCESS_NOTIFY_ROUTINE_EX)MyCreateProcessNotifyEx, FALSE) if (!NT_SUCCESS(st)) { DbgPrint('PsSetCreateProcessNotifyRoutineEx return false') } st = PsSetCreateThreadNotifyRoutine(MyCreateThreadNotify) if (!NT_SUCCESS(st)) { DbgPrint('PsSetCreateThreadNotifyRoutine return false') } } // Uninstall the driver, you must remove the callback, otherwise blue screen VOID RemoveMonitor() { //remove create process/thread notify PsSetCreateProcessNotifyRoutineEx((PCREATE_PROCESS_NOTIFY_ROUTINE_EX)MyCreateProcessNotifyEx, TRUE) PsRemoveCreateThreadNotifyRoutine(MyCreateThreadNotify) }

La fonction de rappel de chargement du module est la suivante

#include #include VOID UnicodeToChar(PUNICODE_STRING dst, char *src) { ANSI_STRING string RtlUnicodeStringToAnsiString(&string, dst, TRUE) strcpy(src, string.Buffer) RtlFreeAnsiString(&string) } PVOID GetDriverEntryByImageBase(PVOID pImageBase) { PIMAGE_DOS_HEADER pDOSHeader PIMAGE_NT_HEADERS64 pNTHeader PVOID pEntryPoint pDOSHeader = (PIMAGE_DOS_HEADER)pImageBase pNTHeader = (PIMAGE_NT_HEADERS64)((ULONG64)pImageBase + pDOSHeader->e_lfanew) return (PVOID)((ULONG64)pImageBase + pNTHeader->OptionalHeader.AddressOfEntryPoint) } BOOLEAN VxkCopyMemory(PVOID pDestination, PVOID pSourceAddress, SIZE_T SizeOfCopy) { PMDL pMdl = NULL PVOID pSafeAddress = NULL pMdl = IoAllocateMdl(pSourceAddress, (ULONG)SizeOfCopy, FALSE, FALSE, NULL) if (!pMdl) return FALSE __try { MmProbeAndLockPages(pMdl, KernelMode, IoReadAccess) } __except (EXCEPTION_EXECUTE_HANDLER) { IoFreeMdl(pMdl) return FALSE } pSafeAddress = MmGetSystemAddressForMdlSafe(pMdl, NormalPagePriority) if (!pSafeAddress) return FALSE RtlCopyMemory(pDestination, pSafeAddress, SizeOfCopy) MmUnlockPages(pMdl) IoFreeMdl(pMdl) return TRUE } VOID DenyLoadDriver(PVOID DriverEntry) { // 'Access denied' machine code // mov eax, c0000022h // ret // Machine code bit xB8x22x00x00xC0xC3 UCHAR fuck[] = 'xB8x22x00x00xC0xC3' VxkCopyMemory(DriverEntry, fuck, sizeof(fuck)) } VOID LoadImageNotifyRoutine( _In_ PUNICODE_STRING FullImageName, _In_ HANDLE ProcessId, // pid into which image is being mapped _In_ PIMAGE_INFO ImageInfo ) { PVOID pDrvEntry char szFullImageName[260] = { 0 } if (FullImageName != NULL && MmIsAddressValid(FullImageName)) { //KdPrint(('processid = %lld', ProcessId)) // According to the second parameter of the callback function LoadImageNotifyRoutine, if the PID is 0, it means that the driver is loaded, if the PID bit is non-zero, it means that the DLL is loaded. if (0 == ProcessId) { pDrvEntry = GetDriverEntryByImageBase(ImageInfo->ImageBase) UnicodeToChar(FullImageName, szFullImageName) KdPrint(('The currently loaded module is: %wZ', FullImageName)) // The function of strlwr function is to convert the S parameter in the string to lower case. if (strstr(szFullImageName, 'Win7_x64_SSDT_Hook.sys')) { DenyLoadDriver(pDrvEntry) } } } } VOID MonitorLoadModule() { NTSTATUS nt = PsSetLoadImageNotifyRoutine((PLOAD_IMAGE_NOTIFY_ROUTINE)LoadImageNotifyRoutine) if (!NT_SUCCESS(nt)) { KdPrint(('call PsSetLoadImageNotifyRoutine failed')) } } VOID RemoveMonitorLoadModule() { PsRemoveLoadImageNotifyRoutine((PLOAD_IMAGE_NOTIFY_ROUTINE)LoadImageNotifyRoutine) }