From ebe459d8f98636e94afe1b6525560c1a61114530 Mon Sep 17 00:00:00 2001 From: Toni Uhlig Date: Sun, 7 Jul 2019 01:35:05 +0200 Subject: project structure refactoring --- KMemDriver/Driver.c | 1030 ----------------------------- KMemDriver/KMemDriver.c | 1030 +++++++++++++++++++++++++++++ KMemDriver/KMemDriver.vcxproj | 4 +- KMemDriver/KMemDriver.vcxproj.filters | 12 +- MemDriverLib/MemDriverLib.cpp | 324 +++++++++ MemDriverLib/MemDriverLib.vcxproj | 4 +- MemDriverLib/MemDriverLib.vcxproj.filters | 4 +- MemDriverWeb/MemDriverWeb.cpp | 2 + MemDriverWeb/MemDriverWeb.vcxproj | 8 +- include/Driver.h | 131 ---- include/KInterface.h | 2 +- include/KMemDriver.h | 134 ++++ 12 files changed, 1510 insertions(+), 1175 deletions(-) delete mode 100644 KMemDriver/Driver.c create mode 100644 KMemDriver/KMemDriver.c delete mode 100644 include/Driver.h create mode 100644 include/KMemDriver.h diff --git a/KMemDriver/Driver.c b/KMemDriver/Driver.c deleted file mode 100644 index c85188c..0000000 --- a/KMemDriver/Driver.c +++ /dev/null @@ -1,1030 +0,0 @@ -#include "Driver.h" -#include "Imports.h" -#include "Native.h" - -#include -#include - -#define CHEAT_EXE L"kmem" - -#ifdef _DEBUG_ -#define KDBG(fmt, ...) DbgPrint("KMemDriver[%01d]: " fmt, KeGetCurrentIrql(), __VA_ARGS__) -#else -#define KDBG(fmt, ...) -#endif - -#ifndef _DEBUG_ -#define FNZERO_MARKER() \ - do { \ - volatile UINT32 marker = 0xDEADC0DE;\ - UNREFERENCED_PARAMETER(marker); \ - } while (0) -#define FNZERO_FN(fn_start) \ - do { fn_zero_text((PVOID)fn_start); } while (0) -#define FNZERO(fn_start) \ - FNZERO_MARKER(); \ - FNZERO_FN(fn_start) -#else -#define FNZERO_MARKER() -#define FNZERO_FN(fn_start) -#define FNZERO(fn_start) -#endif - -#define WAIT_OBJECT_0 ((STATUS_WAIT_0 ) + 0 ) - -DRIVER_INITIALIZE DriverEntry; -#pragma alloc_text(INIT, DriverEntry) -void OnImageLoad( - PUNICODE_STRING FullImageName, - HANDLE ProcessId, - PIMAGE_INFO ImageInfo -); -#pragma alloc_text(PAGE, OnImageLoad) - -NTSTATUS WaitForControlProcess(OUT PEPROCESS *ppEProcess); -NTSTATUS VerifyControlProcess(IN PEPROCESS pEProcess); -NTSTATUS InitSharedMemory(IN PEPROCESS pEProcess); -NTSTATUS WaitForHandshake( - IN PEPROCESS pEProcess, - OUT HANDLE *pKEvent, OUT HANDLE *pUEvent -); -NTSTATUS OpenEventReference( - IN PEPROCESS pEProcess, - IN KAPC_STATE *pKAPCState, IN HANDLE hEvent, - OUT PKEVENT *pPKEvent -); -NTSTATUS UpdatePPEPIfRequired( - IN HANDLE wantedPID, - IN HANDLE lastPID, OUT HANDLE *lastPROC, - OUT PEPROCESS *lastPEP -); -NTSTATUS GetPages( - IN PEPROCESS Process, - OUT MEMORY_BASIC_INFORMATION *mbiArr, - IN SIZE_T mbiArrLen, OUT SIZE_T *mbiUsed, - IN PVOID start_addr -); -NTSTATUS GetModules( - IN PEPROCESS pEProcess, - OUT PMODULE_DATA pmod, IN OUT SIZE_T *psiz, - IN SIZE_T start_index -); -NTSTATUS KeReadVirtualMemory( - IN PEPROCESS pEProcess, - IN PVOID SourceAddress, - IN PVOID TargetAddress, IN PSIZE_T Size -); -NTSTATUS KeWriteVirtualMemory( - IN PEPROCESS pEProcess, - IN PVOID SourceAddress, - IN PVOID TargetAddress, - IN PSIZE_T Size -); -NTSTATUS KeProtectVirtualMemory( - IN HANDLE hProcess, - IN PVOID addr, IN SIZE_T siz, - IN ULONG new_prot, OUT ULONG *old_prot -); -NTSTATUS KeRestoreProtectVirtualMemory( - IN HANDLE hProcess, - IN PVOID addr, IN SIZE_T siz, - IN ULONG old_prot -); -NTSTATUS GetDriverObject( - IN OUT PDRIVER_OBJECT *lpObj, - IN WCHAR* DriverDirName -); -NTSTATUS KRThread(IN PVOID pArg); -TABLE_SEARCH_RESULT VADFindNodeOrParent( - IN PMM_AVL_TABLE Table, - IN ULONG_PTR StartingVpn, - OUT PMMADDRESS_NODE *NodeOrParent -); -NTSTATUS VADFind( - IN PEPROCESS pProcess, - IN ULONG_PTR address, - OUT PMMVAD_SHORT* pResult -); -NTSTATUS VADProtect( - IN PEPROCESS pProcess, - IN ULONG_PTR address, - IN ULONG prot -); - -#pragma alloc_text(PAGE, WaitForControlProcess) -#pragma alloc_text(PAGE, VerifyControlProcess) -#pragma alloc_text(PAGE, InitSharedMemory) -#pragma alloc_text(PAGE, WaitForHandshake) -#pragma alloc_text(PAGE, OpenEventReference) -#pragma alloc_text(PAGE, UpdatePPEPIfRequired) -#pragma alloc_text(PAGE, GetPages) -#pragma alloc_text(PAGE, GetModules) -#pragma alloc_text(PAGE, KeReadVirtualMemory) -#pragma alloc_text(PAGE, KeWriteVirtualMemory) -#pragma alloc_text(PAGE, KeProtectVirtualMemory) -#pragma alloc_text(PAGE, KeRestoreProtectVirtualMemory) -#pragma alloc_text(PAGE, GetDriverObject) -#pragma alloc_text(PAGE, KRThread) -#pragma alloc_text(PAGE, VADFindNodeOrParent) -#pragma alloc_text(PAGE, VADFind) -#pragma alloc_text(PAGE, VADProtect) - -static void fn_zero_text(PVOID fn_start); -static HANDLE ctrlPID; -static PVOID imageBase; - -static PVOID mmapedBase = NULL; -static INT hijacked = 0; -static PDRIVER_OBJECT hijackedDriver = NULL; -static DRIVER_OBJECT hijackedDriverOriginal; - - -NTSTATUS DriverEntry( - _In_ DRIVER_OBJECT *DriverObject, - _In_ PUNICODE_STRING RegistryPath -) -{ - NTSTATUS status; - HANDLE hThread = NULL; - CLIENT_ID clientID = { 0 }; - OBJECT_ATTRIBUTES obAttr = { 0 }; - - UNREFERENCED_PARAMETER(DriverObject); - UNREFERENCED_PARAMETER(RegistryPath); - - KDBG("Driver Loaded\n"); - if (!DriverObject && RegistryPath) { - /* assume that we are manual mapped by PastDSE */ - mmapedBase = RegistryPath; - KDBG("Manual mapped image base: 0x%p\n", mmapedBase); - } - InitializeObjectAttributes(&obAttr, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); - status = PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS, &obAttr, NULL, &clientID, &KRThread, NULL); - if (!NT_SUCCESS(status)) - { - KDBG("Failed to create worker thread. Status: 0x%X\n", status); - return status; - } - - FNZERO(DriverEntry); - return status; -} - -void OnImageLoad( - PUNICODE_STRING FullImageName, - HANDLE ProcessId, - PIMAGE_INFO ImageInfo -) -{ - UNREFERENCED_PARAMETER(ImageInfo); -#if 0 - KDBG("ProcessID: 0x%X\n", ProcessId); - KDBG("FullImage: %wZ\n", FullImageName); -#endif - if (wcsstr(FullImageName->Buffer, CHEAT_EXE)) { - ctrlPID = ProcessId; - imageBase = ImageInfo->ImageBase; - KDBG("Found Target !!!\n"); - } -} - -NTSTATUS WaitForControlProcess(OUT PEPROCESS *ppEProcess) -{ - NTSTATUS status; - - if (!ppEProcess) - return STATUS_INVALID_ADDRESS; - - imageBase = NULL; - ctrlPID = NULL; - - status = PsSetLoadImageNotifyRoutine(OnImageLoad); - if (!NT_SUCCESS(status)) { - KDBG("PsSetLoadImageNotifyRoutine failed with 0x%X\n", status); - return status; - } - - while (!ctrlPID) { - LARGE_INTEGER wait = { .QuadPart = -1000000 }; - KeDelayExecutionThread(KernelMode, TRUE, &wait); - } - - status = PsRemoveLoadImageNotifyRoutine(OnImageLoad); - if (!NT_SUCCESS(status)) { - KDBG("PsRemoveLoadImageNotifyRoutine failed with 0x%X\n", status); - return status; - } - - status = PsLookupProcessByProcessId(ctrlPID, ppEProcess); - if (!NT_SUCCESS(status)) { - KDBG("PsLookupProcessByProcessId failed with 0x%X\n", status); - return status; - } - - KDBG("Got Ctrl Process PID: 0x%X (%d)\n", - ctrlPID, ctrlPID); - - return STATUS_SUCCESS; -} - -NTSTATUS VerifyControlProcess(IN PEPROCESS pEProcess) -{ - NTSTATUS status; - UCHAR pefile[4] = { 0 }; - SIZE_T pesiz = sizeof pefile; - - status = KeReadVirtualMemory(pEProcess, - imageBase, pefile, &pesiz); - if (!NT_SUCCESS(status) || pesiz != sizeof pefile) { - KDBG("KeReadVirtualMemory failed with 0x%X\n", status); - return status; - } - if (pefile[0] != 0x4D || pefile[1] != 0x5A || - pefile[2] != 0x90 || pefile[3] != 0x00) - { - KDBG("Invalid PE file\n"); - return status; - } - - return status; -} - -NTSTATUS InitSharedMemory(IN PEPROCESS pEProcess) -{ - NTSTATUS status = STATUS_UNSUCCESSFUL; - SIZE_T maxWaits = 20; - - KDBG("Init Shmem ..\n"); - while (--maxWaits) { - UCHAR buf[4] = { 0 }; - SIZE_T bufsiz = sizeof buf; - LARGE_INTEGER wait = { .QuadPart = -5000000 }; - status = KeReadVirtualMemory(pEProcess, - (PVOID)SHMEM_ADDR, buf, &bufsiz); - if (NT_SUCCESS(status) && bufsiz == sizeof buf) - break; - KDBG("Waiting until 0x%X alloc'd by user space app ..\n", SHMEM_ADDR); - KeDelayExecutionThread(KernelMode, TRUE, &wait); - } - - return status; -} - -NTSTATUS WaitForHandshake( - IN PEPROCESS pEProcess, - OUT HANDLE *pKEvent, OUT HANDLE *pUEvent -) -{ - NTSTATUS status = STATUS_UNSUCCESSFUL; - SIZE_T maxWaits = 20; - - KDBG("Wait for Handshake ..\n"); - while (--maxWaits) { - KERNEL_HANDSHAKE hnds; - SIZE_T siz = sizeof hnds; - LARGE_INTEGER wait = { .QuadPart = -5000000 }; - status = KeReadVirtualMemory(pEProcess, (PVOID)SHMEM_ADDR, &hnds, &siz); - if (NT_SUCCESS(status) && siz == sizeof hnds && - hnds.kevent) - { - if (validateRequest(&hnds) != MEM_HANDSHAKE) { - KDBG("Invalid Handshake received: 0x%X\n", hnds.hdr.magic); - return STATUS_INVALID_CONNECTION; - } - *pKEvent = hnds.kevent; - *pUEvent = hnds.uevent; - KDBG("Got Event Handle 0x%X (Kernel) and 0x%X (User)\n", - *pKEvent, *pUEvent); - break; - } - KDBG("Waiting for handshake at 0x%X ..\n", SHMEM_ADDR); - KeDelayExecutionThread(KernelMode, TRUE, &wait); - } - - return status; -} - -NTSTATUS OpenEventReference( - IN PEPROCESS pEProcess, - IN KAPC_STATE *pKAPCState, IN HANDLE hEvent, - OUT PKEVENT *pPKEvent -) -{ - NTSTATUS status; - - KeStackAttachProcess((PRKPROCESS)pEProcess, pKAPCState); - status = ObReferenceObjectByHandle( - hEvent, SYNCHRONIZE | EVENT_MODIFY_STATE, - *ExEventObjectType, UserMode, pPKEvent, NULL - ); - KeUnstackDetachProcess(pKAPCState); - if (!NT_SUCCESS(status)) - KDBG("ObReferenceObjectByHandle for Handle 0x%X failed with 0x%X\n", - hEvent, status); - - return status; -} - -NTSTATUS KRThread(IN PVOID pArg) -{ - NTSTATUS status; - INT reinit; - HANDLE kevent, uevent; - PEPROCESS ctrlPEP; - KAPC_STATE apcstate; - PKEVENT pk_kevent, pk_uevent; - - UNREFERENCED_PARAMETER(pArg); - - do { - reinit = 0; - ctrlPEP = NULL; - pk_kevent = pk_uevent = NULL; - - KeLowerIrql(0); - KDBG("Init ..\n"); - { - ULONG_PTR low, high; - IoGetStackLimits(&low, &high); - KDBG("Stack limits (high/low/total/remaining): 0x%p/0x%p/0x%X/0x%X\n", - low, high, high - low, IoGetRemainingStackSize()); - } - - if (mmapedBase && !hijackedDriver && - NT_SUCCESS(GetDriverObject(&hijackedDriver, L"\\Driver\\ahcache"))) - { - if (hijackedDriver) { -#ifdef _DEBUG_ - KDBG("Got DriverObject at 0x%p\n", hijackedDriver); - PKLDR_DATA_TABLE_ENTRY drv_section = hijackedDriver->DriverSection; - KDBG("PDrvObj: base -> 0x%p , name -> '%wZ' , flags -> 0x%X\n", - drv_section->DllBase, drv_section->BaseDllName, drv_section->Flags); -#endif - /* !!! EXPERIMENTAL !!! */ -#if 0 - hijacked = 1; - /* the following lines are known to cause a bugcheck */ - hijackedDriverOriginal = *hijackedDriver; - hijackedDriver->DriverStart = mmapedBase; - //hijackedDriver->DriverSection = (PVOID)((ULONG_PTR)mmapedBase + 100); -#endif -#if 0 - /* the following lines are known to not work with ahcache driver */ - hijackedDriver->DriverInit = (PDRIVER_INITIALIZE)DriverEntry; - hijackedDriver->DriverStartIo = NULL; - hijackedDriver->DriverUnload = NULL; - SIZE_T funcs = sizeof hijackedDriver->MajorFunction / sizeof hijackedDriver->MajorFunction[0]; - for (SIZE_T i = 0; i < funcs; ++i) { - hijackedDriver->MajorFunction[i] = NULL; - } -#endif - } - } - - status = WaitForControlProcess(&ctrlPEP); - if (!NT_SUCCESS(status)) - goto finish; - - if (hijackedDriver && hijacked) { - *hijackedDriver = hijackedDriverOriginal; - } - - status = VerifyControlProcess(ctrlPEP); - if (!NT_SUCCESS(status)) - goto finish_ctrlpep; - - status = InitSharedMemory(ctrlPEP); - if (!NT_SUCCESS(status)) - goto finish_ctrlpep; - - status = WaitForHandshake(ctrlPEP, - &kevent, &uevent); - if (!NT_SUCCESS(status)) - goto finish_ctrlpep; - - status = OpenEventReference(ctrlPEP, - &apcstate, kevent, &pk_kevent); - if (!NT_SUCCESS(status)) - goto finish_ctrlpep; - - status = OpenEventReference(ctrlPEP, - &apcstate, uevent, &pk_uevent); - if (!NT_SUCCESS(status)) - goto finish_kevent; - - KeClearEvent(pk_kevent); - KeClearEvent(pk_uevent); - - PVOID shm_buf = MmAllocateNonCachedMemory(SHMEM_SIZE); - if (!shm_buf) { - KDBG("MmAllocateNonCachedMemory with size 0x%X failed\n", SHMEM_SIZE); - goto nomem; - } - - reinit = 1; - KeSetEvent(pk_uevent, FILE_DEVICE_MOUSE, TRUE); - HANDLE lastPID = NULL, lastPROC = NULL; - PEPROCESS lastPEP = NULL; - INT running = 1; - SIZE_T maxWaits = 20; - do { - LARGE_INTEGER wait = { .QuadPart = -10000000 }; - status = KeWaitForSingleObject(pk_kevent, Executive, UserMode, FALSE, &wait); - if (NT_SUCCESS(status) && status == WAIT_OBJECT_0) { - maxWaits = 20; - /* parse memory request */ - SIZE_T siz = SHMEM_SIZE; - status = KeReadVirtualMemory(ctrlPEP, (PVOID)SHMEM_ADDR, shm_buf, &siz); - - if (NT_SUCCESS(status) && siz == SHMEM_SIZE) { - switch (validateRequest(shm_buf)) - { - case MEM_HANDSHAKE: - KDBG("Invalid Request MEM_HANDSHAKE\n"); - break; - case MEM_PING: { - PKERNEL_PING ping = (PKERNEL_PING)shm_buf; - KDBG("Got a PING with rng 0x%X, sending PONG !\n", - ping->rnd_user); - ping->rnd_kern = ping->rnd_user; - siz = sizeof *ping; - KeWriteVirtualMemory(ctrlPEP, ping, (PVOID)SHMEM_ADDR, &siz); - break; - } - case MEM_PAGES: { - PKERNEL_PAGE pages = (PKERNEL_PAGE)shm_buf; - KDBG("Got a PAGES request for process 0x%X start at address 0x%p\n", - pages->ProcessId, pages->StartAddress); - if (!NT_SUCCESS(UpdatePPEPIfRequired(pages->ProcessId, - lastPID, &lastPROC, &lastPEP))) - { - running = 0; - break; - } - siz = (SHMEM_SIZE - sizeof *pages + sizeof pages->pages_start) - / sizeof pages->pages_start; - pages->StatusRes = GetPages(lastPEP, &pages->pages_start, siz, - &pages->pages, pages->StartAddress); - siz = (sizeof *pages - sizeof pages->pages_start) + - sizeof pages->pages_start * pages->pages; - KeWriteVirtualMemory(ctrlPEP, pages, (PVOID)SHMEM_ADDR, &siz); - break; - } - case MEM_MODULES: { - PKERNEL_MODULES mods = (PKERNEL_MODULES)shm_buf; - KDBG("Got a MODULES request for process 0x%X start at index 0x%X\n", - mods->ProcessId, mods->StartIndex); - if (!NT_SUCCESS(UpdatePPEPIfRequired(mods->ProcessId, - lastPID, &lastPROC, &lastPEP))) - { - running = 0; - break; - } - siz = (SHMEM_SIZE - sizeof *mods + sizeof mods->modules_start) - / sizeof mods->modules_start; - PMODULE_DATA entries = &mods->modules_start; - KDBG("GetModules max entries: %u\n", siz); - KeStackAttachProcess((PRKPROCESS)lastPEP, &apcstate); - mods->StatusRes = GetModules(lastPEP, entries, &siz, mods->StartIndex); - KeUnstackDetachProcess(&apcstate); - mods->modules = siz; - siz = (sizeof *mods - sizeof mods->modules_start) + - sizeof mods->modules_start * mods->modules; - KeWriteVirtualMemory(ctrlPEP, mods, (PVOID)SHMEM_ADDR, &siz); - break; - } - case MEM_RPM: { - PKERNEL_READ_REQUEST rr = (PKERNEL_READ_REQUEST)shm_buf; - KDBG("Got a RPM to process 0x%X, address 0x%p with size 0x%lX\n", - rr->ProcessId, rr->Address, rr->SizeReq); - if (!NT_SUCCESS(UpdatePPEPIfRequired(rr->ProcessId, - lastPID, &lastPROC, &lastPEP))) - { - running = 0; - break; - } - if (rr->SizeReq > SHMEM_SIZE - sizeof *rr) { - siz = SHMEM_SIZE - sizeof *rr; - } - else { - siz = rr->SizeReq; - } - ULONG new_prot = PAGE_EXECUTE_READWRITE, old_prot = 0; - KeProtectVirtualMemory(lastPROC, rr->Address, rr->SizeReq, new_prot, &old_prot); - KDBG("RPM to 0x%p size 0x%X bytes (protection before/after: 0x%X/0x%X)\n", - rr->Address, rr->SizeReq, old_prot, new_prot); - rr->StatusRes = KeReadVirtualMemory(lastPEP, (PVOID)rr->Address, - (PVOID)((ULONG_PTR)shm_buf + sizeof *rr), &siz); - KeRestoreProtectVirtualMemory(lastPROC, rr->Address, rr->SizeReq, old_prot); - if (NT_SUCCESS(rr->StatusRes)) { - rr->SizeRes = siz; - siz += sizeof *rr; - } - else { - rr->SizeRes = 0; - siz = sizeof *rr; - } - KeWriteVirtualMemory(ctrlPEP, rr, (PVOID)SHMEM_ADDR, &siz); - break; - } - case MEM_WPM: { - PKERNEL_WRITE_REQUEST wr = (PKERNEL_WRITE_REQUEST)shm_buf; - KDBG("Got a WPM to process 0x%X, address 0x%p with size 0x%lX\n", - wr->ProcessId, wr->Address, wr->SizeReq); - if (!NT_SUCCESS(UpdatePPEPIfRequired(wr->ProcessId, - lastPID, &lastPROC, &lastPEP))) - { - running = 0; - break; - } - if (wr->SizeReq > SHMEM_SIZE - sizeof *wr) { - siz = SHMEM_SIZE - sizeof *wr; - } - else { - siz = wr->SizeReq; - } - ULONG new_prot = PAGE_EXECUTE_READWRITE, old_prot = 0; - KeProtectVirtualMemory(lastPEP, wr->Address, wr->SizeReq, new_prot, &old_prot); - KDBG("WPM to 0x%p size 0x%X bytes (protection before/after: 0x%X/0x%X)\n", - wr->Address, wr->SizeReq, old_prot, new_prot); - wr->StatusRes = KeWriteVirtualMemory(lastPEP, (PVOID)((ULONG_PTR)shm_buf + sizeof *wr), - (PVOID)wr->Address, &siz); - KeRestoreProtectVirtualMemory(lastPROC, wr->Address, wr->SizeReq, old_prot); - if (NT_SUCCESS(wr->StatusRes)) { - wr->SizeRes = siz; - siz += sizeof *wr; - } - else { - wr->SizeRes = 0; - siz = sizeof *wr; - } - KeWriteVirtualMemory(ctrlPEP, wr, (PVOID)SHMEM_ADDR, &siz); - break; - } - case MEM_EXIT: - KDBG("Gracefully exiting ..\n"); - KeClearEvent(pk_kevent); - KeClearEvent(pk_uevent); - running = 0; - reinit = 0; - break; - default: - KDBG("Invalid Request\n"); - running = 0; - reinit = 0; - break; - } - } - - if (KeSetEvent(pk_uevent, FILE_DEVICE_MOUSE, TRUE)) { - KDBG("Previous signal state wasn't consumed!?\n"); - } - } - else { - if (!maxWaits--) { - KDBG("No activity, abort ..\n"); - running = 0; - } - } - } while (running); - KeSetEvent(pk_uevent, FILE_DEVICE_MOUSE, TRUE); - - if (lastPEP) - ObDereferenceObject(lastPEP); - if (lastPROC) - ZwClose(lastPROC); - MmFreeNonCachedMemory(shm_buf, SHMEM_SIZE); - nomem: - ObDereferenceObject(pk_uevent); - finish_kevent: - ObDereferenceObject(pk_kevent); - finish_ctrlpep: - ObDereferenceObject(ctrlPEP); - finish: - if (reinit) { - LARGE_INTEGER wait = { .QuadPart = -50000000 }; - KeDelayExecutionThread(KernelMode, TRUE, &wait); - } - } while (reinit); - - KDBG("Terminating ..\n"); - PsTerminateSystemThread(status); - return status; -} - -NTSTATUS UpdatePPEPIfRequired( - IN HANDLE wantedPID, - IN HANDLE lastPID, OUT HANDLE *lastPROC, - OUT PEPROCESS *lastPEP -) -{ - NTSTATUS status = STATUS_SUCCESS; - - if (wantedPID != lastPID) { - if (lastPID) { - ObDereferenceObject(*lastPEP); - *lastPEP = NULL; - ZwClose(*lastPROC); - *lastPROC = NULL; - } - status = PsLookupProcessByProcessId(wantedPID, lastPEP); - if (!NT_SUCCESS(status)) { - KDBG("PsLookupProcessByProcessId failed with 0x%X\n", status); - } - else { - status = ObOpenObjectByPointer(*lastPEP, - OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, GENERIC_ALL, - *PsProcessType, KernelMode, lastPROC - ); - if (!NT_SUCCESS(status)) { - KDBG("ObOpenObjectByPointer failed with 0x%X\n", status); - } - else { - PEPROCESS pep = *lastPEP; - PVOID base = NULL; - SIZE_T size = ADDRESS_AND_SIZE_TO_SPAN_PAGES(base, 4096); - PKAPC_STATE apc = MmAllocateNonCachedMemory(sizeof(*apc)); - KeStackAttachProcess((PRKPROCESS)pep, apc); - status = ZwAllocateVirtualMemory(ZwCurrentProcess(), &base, 0, &size, MEM_COMMIT, PAGE_READWRITE); - if (!NT_SUCCESS(status)) { - KDBG("ZwAllocateVirtualMemory failed with 0x%X\n", status); - } - else { - *(UINT64 *)base = 0x4141414142424242; - } - KeUnstackDetachProcess(apc); - KDBG("VAD Test Alloc.: 0x%p (status: 0x%X)\n", base, status); - PMMVAD_SHORT mmvad; - status = VADFind(pep, (ULONG_PTR)base, &mmvad); - KDBG("VAD Test.......: 0x%p (status: 0x%X)\n", mmvad->StartingVpn, status); - KeStackAttachProcess((PRKPROCESS)pep, apc); - if (*(UINT64 *)base != 0x4141414142424242) { - KDBG("VAD Test failed: 0x%p != 0x%p\n", 0x4141414142424242, base); - } - ZwFreeVirtualMemory(ZwCurrentProcess(), &base, &size, MEM_RELEASE); - KeUnstackDetachProcess(apc); - MmFreeNonCachedMemory(apc, sizeof(*apc)); -#if 0 - PMM_AVL_TABLE avltable = (PMM_AVL_TABLE)((ULONG_PTR *)pep + VAD_TREE_1803); - KDBG("VAD-ROOT.....: 0x%p\n", GET_VAD_ROOT(avltable)); - KDBG("NODE-HINT....: 0x%p\n", avltable->NodeHint); - KDBG("NMBR-OF-ELEMs: %d\n", avltable->NumberGenericTableElements); - KDBG("FLAGS........: 0x%p\n", *((UINT32 *)pep + 0x304)); - KDBG("VSIZE........: %d\n", *((UINT64 *)pep + 0x338)); - KDBG("IMAGEFILENAME: %.*s\n", 15, ((const char *)pep + 0x450)); -#endif - } - } - } - return status; -} - -NTSTATUS GetPages( - IN PEPROCESS Process, - OUT MEMORY_BASIC_INFORMATION *mbiArr, - IN SIZE_T mbiArrLen, OUT SIZE_T *mbiUsed, - IN PVOID start_addr -) -{ - NTSTATUS status; - HANDLE procHandle; - SIZE_T i, mbiLength, mbiReturn; - ULONG_PTR baseAddr = (ULONG_PTR)start_addr; - - status = ObOpenObjectByPointer(Process, - OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, GENERIC_ALL, - *PsProcessType, KernelMode, &procHandle - ); - if (!NT_SUCCESS(status)) { - KDBG("ObOpenObjectByPointer failed with 0x%X\n", status); - return status; - } - - KDBG("ZwQueryVirtualMemory max entries: %u\n", mbiArrLen); - *mbiUsed = 0; - do { - mbiReturn = 0; - status = ZwQueryVirtualMemory(procHandle, (PVOID)baseAddr, - MemoryBasicInformation, mbiArr, sizeof *mbiArr * mbiArrLen, &mbiReturn); - mbiLength = mbiReturn / sizeof *mbiArr; - if (!NT_SUCCESS(status)) { - if (status == STATUS_INVALID_PARAMETER) - status = STATUS_SUCCESS; - else - KDBG("ZwQueryVirtualMemory failed with 0x%X\n", status); - break; - } - else { - for (i = 0; i < mbiLength; ++i) - KDBG("Page #%03u: base -> 0x%p, prot -> 0x%02X, size -> 0x%X\n", - (*mbiUsed) + i, (*(mbiArr + i)).BaseAddress, (*(mbiArr + i)).Protect, - (*(mbiArr + i)).RegionSize); - } - baseAddr += (SIZE_T)(mbiArr + mbiLength - 1)->RegionSize; - *mbiUsed += mbiLength; - mbiArr += mbiLength; - } while (*mbiUsed < mbiArrLen && mbiReturn > 0); - - ZwClose(procHandle); - return status; -} - -NTSTATUS GetModules( - IN PEPROCESS Process, - OUT PMODULE_DATA pmod, IN OUT SIZE_T *psiz, - IN SIZE_T start_index -) -{ - SIZE_T used = 0, index = 0; - INT waitCount = 0; - - PPEB peb = PsGetProcessPeb(Process); - if (!peb) { - KDBG("PsGetProcessPeb failed"); - return STATUS_UNSUCCESSFUL; - } - - PPEB_LDR_DATA ldr = peb->Ldr; - - if (!ldr) { - KDBG("peb->Ldr is invalid"); - return STATUS_UNSUCCESSFUL; - } - - if (!ldr->Initialized) { - while (!ldr->Initialized && waitCount++ < 4) { - LARGE_INTEGER wait = { .QuadPart = -2500 }; - KeDelayExecutionThread(KernelMode, TRUE, &wait); - } - - if (!ldr->Initialized) { - KDBG("ldr->Initialized is 0"); - return STATUS_UNSUCCESSFUL; - } - } - - for (PLIST_ENTRY listEntry = (PLIST_ENTRY)ldr->InLoadOrderModuleList.Flink; - listEntry != &ldr->InLoadOrderModuleList && used < *psiz; - listEntry = (PLIST_ENTRY)listEntry->Flink, ++pmod, ++index) { - if (index < start_index) - continue; - used++; - - PLDR_DATA_TABLE_ENTRY ldrEntry = CONTAINING_RECORD(listEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); - ANSI_STRING name; - if (NT_SUCCESS(RtlUnicodeStringToAnsiString(&name, &ldrEntry->BaseDllName, sizeof pmod->BaseDllName))) { - RtlCopyMemory(pmod->BaseDllName, name.Buffer, - (name.Length > sizeof pmod->BaseDllName ? - sizeof pmod->BaseDllName : name.Length) - ); - } - pmod->DllBase = ldrEntry->DllBase; - pmod->SizeOfImage = ldrEntry->SizeOfImage; - KDBG("DLL #%02lu: base -> 0x%p, size -> 0x%06X, name -> '%s'\n", used, - pmod->DllBase, pmod->SizeOfImage, pmod->BaseDllName); - } - - *psiz = used; - return STATUS_SUCCESS; -} - -NTSTATUS KeReadVirtualMemory( - IN PEPROCESS Process, IN PVOID SourceAddress, - IN PVOID TargetAddress, IN PSIZE_T Size -) -{ - NTSTATUS status; - SIZE_T Bytes = 0; - - status = MmCopyVirtualMemory(Process, SourceAddress, PsGetCurrentProcess(), - TargetAddress, *Size, KernelMode, &Bytes); - if (NT_SUCCESS(status)) - { - *Size = Bytes; - return STATUS_SUCCESS; - } - else { - return status; - } -} - -NTSTATUS KeWriteVirtualMemory( - IN PEPROCESS Process, IN PVOID SourceAddress, - IN PVOID TargetAddress, IN PSIZE_T Size -) -{ - NTSTATUS status; - SIZE_T Bytes = 0; - - status = MmCopyVirtualMemory(PsGetCurrentProcess(), SourceAddress, Process, - TargetAddress, *Size, KernelMode, &Bytes); - if (NT_SUCCESS(status)) - { - *Size = Bytes; - return STATUS_SUCCESS; - } - else { - return status; - } -} - -NTSTATUS KeProtectVirtualMemory( - IN HANDLE hProcess, IN PVOID addr, - IN SIZE_T siz, IN ULONG new_prot, - OUT ULONG *old_prot -) -{ - NTSTATUS status; - PVOID prot_addr = addr; - SIZE_T prot_size = siz; - ULONG prot = 0; - - status = ZwProtectVirtualMemory(hProcess, &prot_addr, - &prot_size, new_prot, &prot); - if (NT_SUCCESS(status)) { - *old_prot = prot; - } - return status; -} - -NTSTATUS KeRestoreProtectVirtualMemory(IN HANDLE hProcess, - IN PVOID addr, IN SIZE_T siz, - IN ULONG old_prot) -{ - NTSTATUS status; - PVOID prot_addr = addr; - SIZE_T prot_size = siz; - ULONG prot = 0; - - status = ZwProtectVirtualMemory(hProcess, &prot_addr, - &prot_size, old_prot, &prot); - return status; -} - -static void fn_zero_text(PVOID fn_start) -{ - SIZE_T i; - UINT32 marker = 0xDEADC0DE; - PUCHAR fnbuf = (PUCHAR)fn_start; - - KDBG("Fn: %p\n", fn_start); - for (i = 0; i < 0x1000; ++i && fnbuf++) { - if (*(UINT32 *)fnbuf == marker) { - KDBG("Marker: 0x%X\n", i); - RtlSecureZeroMemory(fn_start, i + 4); - } - } -} - -NTSTATUS GetDriverObject( - IN OUT PDRIVER_OBJECT *lpObj, - IN WCHAR* DriverDirName -) -{ - NTSTATUS status = STATUS_SUCCESS; - PDRIVER_OBJECT pBeepObj = NULL; - UNICODE_STRING DevName = { 0 }; - - if (!MmIsAddressValid(lpObj)) - return STATUS_INVALID_ADDRESS; - - RtlInitUnicodeString(&DevName, DriverDirName); - - status = ObReferenceObjectByName(&DevName, OBJ_CASE_INSENSITIVE, NULL, 0, *IoDriverObjectType, KernelMode, NULL, &pBeepObj); - - if (NT_SUCCESS(status)) - *lpObj = pBeepObj; - else - { - *lpObj = NULL; - } - - return status; -} - -TABLE_SEARCH_RESULT -VADFindNodeOrParent( - IN PMM_AVL_TABLE Table, - IN ULONG_PTR StartingVpn, - OUT PMMADDRESS_NODE *NodeOrParent -) -{ - PMMADDRESS_NODE Child; - PMMADDRESS_NODE NodeToExamine; - PMMVAD_SHORT VpnCompare; - ULONG_PTR startVpn; - ULONG_PTR endVpn; - - if (Table->NumberGenericTableElements == 0) { - return TableEmptyTree; - } - - NodeToExamine = (PMMADDRESS_NODE)GET_VAD_ROOT(Table); - - for (;;) { - - VpnCompare = (PMMVAD_SHORT)NodeToExamine; - startVpn = VpnCompare->StartingVpn; - endVpn = VpnCompare->EndingVpn; - - startVpn |= (ULONG_PTR)VpnCompare->StartingVpnHigh << 32; - endVpn |= (ULONG_PTR)VpnCompare->EndingVpnHigh << 32; - - KDBG("Examining Node 0x%p with start VA 0x%p and end VA 0x%p\n", VpnCompare, startVpn, endVpn); - - // - // Compare the buffer with the key in the tree element. - // - - if (StartingVpn < startVpn) { - - Child = NodeToExamine->LeftChild; - - if (Child != NULL) { - NodeToExamine = Child; - } - else { - - // - // Node is not in the tree. Set the output - // parameter to point to what would be its - // parent and return which child it would be. - // - - *NodeOrParent = NodeToExamine; - return TableInsertAsLeft; - } - } - else if (StartingVpn <= endVpn) { - - // - // This is the node. - // - - *NodeOrParent = NodeToExamine; - return TableFoundNode; - } - else { - - Child = NodeToExamine->RightChild; - - if (Child != NULL) { - NodeToExamine = Child; - } - else { - - // - // Node is not in the tree. Set the output - // parameter to point to what would be its - // parent and return which child it would be. - // - - *NodeOrParent = NodeToExamine; - return TableInsertAsRight; - } - } - } -} - -NTSTATUS VADFind( - IN PEPROCESS pProcess, - IN ULONG_PTR address, - OUT PMMVAD_SHORT* pResult -) -{ - NTSTATUS status = STATUS_SUCCESS; - ULONG_PTR vpnStart = address >> PAGE_SHIFT; - PMM_AVL_TABLE pTable = (PMM_AVL_TABLE)((PUCHAR)pProcess + VAD_TREE_1803); - PMM_AVL_NODE pNode = GET_VAD_ROOT(pTable); - - if (pProcess == NULL || pResult == NULL) - return STATUS_INVALID_PARAMETER; - - // Search VAD - if (VADFindNodeOrParent(pTable, vpnStart, &pNode) == TableFoundNode) - { - *pResult = (PMMVAD_SHORT)pNode; - } - else - { - KDBG("%s: VAD entry for address 0x%p not found\n", __FUNCTION__, address); - status = STATUS_NOT_FOUND; - } - - return status; -} - -NTSTATUS VADProtect( - IN PEPROCESS pProcess, - IN ULONG_PTR address, IN ULONG prot -) -{ - NTSTATUS status = STATUS_SUCCESS; - PMMVAD_SHORT pVadShort = NULL; - - status = VADFind(pProcess, address, &pVadShort); - if (NT_SUCCESS(status)) - pVadShort->u.VadFlags.Protection = prot; - - return status; -} \ No newline at end of file diff --git a/KMemDriver/KMemDriver.c b/KMemDriver/KMemDriver.c new file mode 100644 index 0000000..45d2a51 --- /dev/null +++ b/KMemDriver/KMemDriver.c @@ -0,0 +1,1030 @@ +#include "KMemDriver.h" +#include "Imports.h" +#include "Native.h" + +#include +#include + +#define CHEAT_EXE L"kmem" + +#ifdef _DEBUG_ +#define KDBG(fmt, ...) DbgPrint("KMemDriver[%01d]: " fmt, KeGetCurrentIrql(), __VA_ARGS__) +#else +#define KDBG(fmt, ...) +#endif + +#ifndef _DEBUG_ +#define FNZERO_MARKER() \ + do { \ + volatile UINT32 marker = 0xDEADC0DE;\ + UNREFERENCED_PARAMETER(marker); \ + } while (0) +#define FNZERO_FN(fn_start) \ + do { fn_zero_text((PVOID)fn_start); } while (0) +#define FNZERO(fn_start) \ + FNZERO_MARKER(); \ + FNZERO_FN(fn_start) +#else +#define FNZERO_MARKER() +#define FNZERO_FN(fn_start) +#define FNZERO(fn_start) +#endif + +#define WAIT_OBJECT_0 ((STATUS_WAIT_0 ) + 0 ) + +DRIVER_INITIALIZE DriverEntry; +#pragma alloc_text(INIT, DriverEntry) +void OnImageLoad( + PUNICODE_STRING FullImageName, + HANDLE ProcessId, + PIMAGE_INFO ImageInfo +); +#pragma alloc_text(PAGE, OnImageLoad) + +NTSTATUS WaitForControlProcess(OUT PEPROCESS *ppEProcess); +NTSTATUS VerifyControlProcess(IN PEPROCESS pEProcess); +NTSTATUS InitSharedMemory(IN PEPROCESS pEProcess); +NTSTATUS WaitForHandshake( + IN PEPROCESS pEProcess, + OUT HANDLE *pKEvent, OUT HANDLE *pUEvent +); +NTSTATUS OpenEventReference( + IN PEPROCESS pEProcess, + IN KAPC_STATE *pKAPCState, IN HANDLE hEvent, + OUT PKEVENT *pPKEvent +); +NTSTATUS UpdatePPEPIfRequired( + IN HANDLE wantedPID, + IN HANDLE lastPID, OUT HANDLE *lastPROC, + OUT PEPROCESS *lastPEP +); +NTSTATUS GetPages( + IN PEPROCESS Process, + OUT MEMORY_BASIC_INFORMATION *mbiArr, + IN SIZE_T mbiArrLen, OUT SIZE_T *mbiUsed, + IN PVOID start_addr +); +NTSTATUS GetModules( + IN PEPROCESS pEProcess, + OUT PMODULE_DATA pmod, IN OUT SIZE_T *psiz, + IN SIZE_T start_index +); +NTSTATUS KeReadVirtualMemory( + IN PEPROCESS pEProcess, + IN PVOID SourceAddress, + IN PVOID TargetAddress, IN PSIZE_T Size +); +NTSTATUS KeWriteVirtualMemory( + IN PEPROCESS pEProcess, + IN PVOID SourceAddress, + IN PVOID TargetAddress, + IN PSIZE_T Size +); +NTSTATUS KeProtectVirtualMemory( + IN HANDLE hProcess, + IN PVOID addr, IN SIZE_T siz, + IN ULONG new_prot, OUT ULONG *old_prot +); +NTSTATUS KeRestoreProtectVirtualMemory( + IN HANDLE hProcess, + IN PVOID addr, IN SIZE_T siz, + IN ULONG old_prot +); +NTSTATUS GetDriverObject( + IN OUT PDRIVER_OBJECT *lpObj, + IN WCHAR* DriverDirName +); +NTSTATUS KRThread(IN PVOID pArg); +TABLE_SEARCH_RESULT VADFindNodeOrParent( + IN PMM_AVL_TABLE Table, + IN ULONG_PTR StartingVpn, + OUT PMMADDRESS_NODE *NodeOrParent +); +NTSTATUS VADFind( + IN PEPROCESS pProcess, + IN ULONG_PTR address, + OUT PMMVAD_SHORT* pResult +); +NTSTATUS VADProtect( + IN PEPROCESS pProcess, + IN ULONG_PTR address, + IN ULONG prot +); + +#pragma alloc_text(PAGE, WaitForControlProcess) +#pragma alloc_text(PAGE, VerifyControlProcess) +#pragma alloc_text(PAGE, InitSharedMemory) +#pragma alloc_text(PAGE, WaitForHandshake) +#pragma alloc_text(PAGE, OpenEventReference) +#pragma alloc_text(PAGE, UpdatePPEPIfRequired) +#pragma alloc_text(PAGE, GetPages) +#pragma alloc_text(PAGE, GetModules) +#pragma alloc_text(PAGE, KeReadVirtualMemory) +#pragma alloc_text(PAGE, KeWriteVirtualMemory) +#pragma alloc_text(PAGE, KeProtectVirtualMemory) +#pragma alloc_text(PAGE, KeRestoreProtectVirtualMemory) +#pragma alloc_text(PAGE, GetDriverObject) +#pragma alloc_text(PAGE, KRThread) +#pragma alloc_text(PAGE, VADFindNodeOrParent) +#pragma alloc_text(PAGE, VADFind) +#pragma alloc_text(PAGE, VADProtect) + +static void fn_zero_text(PVOID fn_start); +static HANDLE ctrlPID; +static PVOID imageBase; + +static PVOID mmapedBase = NULL; +static INT hijacked = 0; +static PDRIVER_OBJECT hijackedDriver = NULL; +static DRIVER_OBJECT hijackedDriverOriginal; + + +NTSTATUS DriverEntry( + _In_ DRIVER_OBJECT *DriverObject, + _In_ PUNICODE_STRING RegistryPath +) +{ + NTSTATUS status; + HANDLE hThread = NULL; + CLIENT_ID clientID = { 0 }; + OBJECT_ATTRIBUTES obAttr = { 0 }; + + UNREFERENCED_PARAMETER(DriverObject); + UNREFERENCED_PARAMETER(RegistryPath); + + KDBG("Driver Loaded\n"); + if (!DriverObject && RegistryPath) { + /* assume that we are manual mapped by PastDSE */ + mmapedBase = RegistryPath; + KDBG("Manual mapped image base: 0x%p\n", mmapedBase); + } + InitializeObjectAttributes(&obAttr, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); + status = PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS, &obAttr, NULL, &clientID, &KRThread, NULL); + if (!NT_SUCCESS(status)) + { + KDBG("Failed to create worker thread. Status: 0x%X\n", status); + return status; + } + + FNZERO(DriverEntry); + return status; +} + +void OnImageLoad( + PUNICODE_STRING FullImageName, + HANDLE ProcessId, + PIMAGE_INFO ImageInfo +) +{ + UNREFERENCED_PARAMETER(ImageInfo); +#if 0 + KDBG("ProcessID: 0x%X\n", ProcessId); + KDBG("FullImage: %wZ\n", FullImageName); +#endif + if (wcsstr(FullImageName->Buffer, CHEAT_EXE)) { + ctrlPID = ProcessId; + imageBase = ImageInfo->ImageBase; + KDBG("Found Target !!!\n"); + } +} + +NTSTATUS WaitForControlProcess(OUT PEPROCESS *ppEProcess) +{ + NTSTATUS status; + + if (!ppEProcess) + return STATUS_INVALID_ADDRESS; + + imageBase = NULL; + ctrlPID = NULL; + + status = PsSetLoadImageNotifyRoutine(OnImageLoad); + if (!NT_SUCCESS(status)) { + KDBG("PsSetLoadImageNotifyRoutine failed with 0x%X\n", status); + return status; + } + + while (!ctrlPID) { + LARGE_INTEGER wait = { .QuadPart = -1000000 }; + KeDelayExecutionThread(KernelMode, TRUE, &wait); + } + + status = PsRemoveLoadImageNotifyRoutine(OnImageLoad); + if (!NT_SUCCESS(status)) { + KDBG("PsRemoveLoadImageNotifyRoutine failed with 0x%X\n", status); + return status; + } + + status = PsLookupProcessByProcessId(ctrlPID, ppEProcess); + if (!NT_SUCCESS(status)) { + KDBG("PsLookupProcessByProcessId failed with 0x%X\n", status); + return status; + } + + KDBG("Got Ctrl Process PID: 0x%X (%d)\n", + ctrlPID, ctrlPID); + + return STATUS_SUCCESS; +} + +NTSTATUS VerifyControlProcess(IN PEPROCESS pEProcess) +{ + NTSTATUS status; + UCHAR pefile[4] = { 0 }; + SIZE_T pesiz = sizeof pefile; + + status = KeReadVirtualMemory(pEProcess, + imageBase, pefile, &pesiz); + if (!NT_SUCCESS(status) || pesiz != sizeof pefile) { + KDBG("KeReadVirtualMemory failed with 0x%X\n", status); + return status; + } + if (pefile[0] != 0x4D || pefile[1] != 0x5A || + pefile[2] != 0x90 || pefile[3] != 0x00) + { + KDBG("Invalid PE file\n"); + return status; + } + + return status; +} + +NTSTATUS InitSharedMemory(IN PEPROCESS pEProcess) +{ + NTSTATUS status = STATUS_UNSUCCESSFUL; + SIZE_T maxWaits = 20; + + KDBG("Init Shmem ..\n"); + while (--maxWaits) { + UCHAR buf[4] = { 0 }; + SIZE_T bufsiz = sizeof buf; + LARGE_INTEGER wait = { .QuadPart = -5000000 }; + status = KeReadVirtualMemory(pEProcess, + (PVOID)SHMEM_ADDR, buf, &bufsiz); + if (NT_SUCCESS(status) && bufsiz == sizeof buf) + break; + KDBG("Waiting until 0x%X alloc'd by user space app ..\n", SHMEM_ADDR); + KeDelayExecutionThread(KernelMode, TRUE, &wait); + } + + return status; +} + +NTSTATUS WaitForHandshake( + IN PEPROCESS pEProcess, + OUT HANDLE *pKEvent, OUT HANDLE *pUEvent +) +{ + NTSTATUS status = STATUS_UNSUCCESSFUL; + SIZE_T maxWaits = 20; + + KDBG("Wait for Handshake ..\n"); + while (--maxWaits) { + KERNEL_HANDSHAKE hnds; + SIZE_T siz = sizeof hnds; + LARGE_INTEGER wait = { .QuadPart = -5000000 }; + status = KeReadVirtualMemory(pEProcess, (PVOID)SHMEM_ADDR, &hnds, &siz); + if (NT_SUCCESS(status) && siz == sizeof hnds && + hnds.kevent) + { + if (validateRequest(&hnds) != MEM_HANDSHAKE) { + KDBG("Invalid Handshake received: 0x%X\n", hnds.hdr.magic); + return STATUS_INVALID_CONNECTION; + } + *pKEvent = hnds.kevent; + *pUEvent = hnds.uevent; + KDBG("Got Event Handle 0x%X (Kernel) and 0x%X (User)\n", + *pKEvent, *pUEvent); + break; + } + KDBG("Waiting for handshake at 0x%X ..\n", SHMEM_ADDR); + KeDelayExecutionThread(KernelMode, TRUE, &wait); + } + + return status; +} + +NTSTATUS OpenEventReference( + IN PEPROCESS pEProcess, + IN KAPC_STATE *pKAPCState, IN HANDLE hEvent, + OUT PKEVENT *pPKEvent +) +{ + NTSTATUS status; + + KeStackAttachProcess((PRKPROCESS)pEProcess, pKAPCState); + status = ObReferenceObjectByHandle( + hEvent, SYNCHRONIZE | EVENT_MODIFY_STATE, + *ExEventObjectType, UserMode, pPKEvent, NULL + ); + KeUnstackDetachProcess(pKAPCState); + if (!NT_SUCCESS(status)) + KDBG("ObReferenceObjectByHandle for Handle 0x%X failed with 0x%X\n", + hEvent, status); + + return status; +} + +NTSTATUS KRThread(IN PVOID pArg) +{ + NTSTATUS status; + INT reinit; + HANDLE kevent, uevent; + PEPROCESS ctrlPEP; + KAPC_STATE apcstate; + PKEVENT pk_kevent, pk_uevent; + + UNREFERENCED_PARAMETER(pArg); + + do { + reinit = 0; + ctrlPEP = NULL; + pk_kevent = pk_uevent = NULL; + + KeLowerIrql(0); + KDBG("Init ..\n"); + { + ULONG_PTR low, high; + IoGetStackLimits(&low, &high); + KDBG("Stack limits (high/low/total/remaining): 0x%p/0x%p/0x%X/0x%X\n", + low, high, high - low, IoGetRemainingStackSize()); + } + + if (mmapedBase && !hijackedDriver && + NT_SUCCESS(GetDriverObject(&hijackedDriver, L"\\Driver\\ahcache"))) + { + if (hijackedDriver) { +#ifdef _DEBUG_ + KDBG("Got DriverObject at 0x%p\n", hijackedDriver); + PKLDR_DATA_TABLE_ENTRY drv_section = hijackedDriver->DriverSection; + KDBG("PDrvObj: base -> 0x%p , name -> '%wZ' , flags -> 0x%X\n", + drv_section->DllBase, drv_section->BaseDllName, drv_section->Flags); +#endif + /* !!! EXPERIMENTAL !!! */ +#if 0 + hijacked = 1; + /* the following lines are known to cause a bugcheck */ + hijackedDriverOriginal = *hijackedDriver; + hijackedDriver->DriverStart = mmapedBase; + //hijackedDriver->DriverSection = (PVOID)((ULONG_PTR)mmapedBase + 100); +#endif +#if 0 + /* the following lines are known to not work with ahcache driver */ + hijackedDriver->DriverInit = (PDRIVER_INITIALIZE)DriverEntry; + hijackedDriver->DriverStartIo = NULL; + hijackedDriver->DriverUnload = NULL; + SIZE_T funcs = sizeof hijackedDriver->MajorFunction / sizeof hijackedDriver->MajorFunction[0]; + for (SIZE_T i = 0; i < funcs; ++i) { + hijackedDriver->MajorFunction[i] = NULL; + } +#endif + } + } + + status = WaitForControlProcess(&ctrlPEP); + if (!NT_SUCCESS(status)) + goto finish; + + if (hijackedDriver && hijacked) { + *hijackedDriver = hijackedDriverOriginal; + } + + status = VerifyControlProcess(ctrlPEP); + if (!NT_SUCCESS(status)) + goto finish_ctrlpep; + + status = InitSharedMemory(ctrlPEP); + if (!NT_SUCCESS(status)) + goto finish_ctrlpep; + + status = WaitForHandshake(ctrlPEP, + &kevent, &uevent); + if (!NT_SUCCESS(status)) + goto finish_ctrlpep; + + status = OpenEventReference(ctrlPEP, + &apcstate, kevent, &pk_kevent); + if (!NT_SUCCESS(status)) + goto finish_ctrlpep; + + status = OpenEventReference(ctrlPEP, + &apcstate, uevent, &pk_uevent); + if (!NT_SUCCESS(status)) + goto finish_kevent; + + KeClearEvent(pk_kevent); + KeClearEvent(pk_uevent); + + PVOID shm_buf = MmAllocateNonCachedMemory(SHMEM_SIZE); + if (!shm_buf) { + KDBG("MmAllocateNonCachedMemory with size 0x%X failed\n", SHMEM_SIZE); + goto nomem; + } + + reinit = 1; + KeSetEvent(pk_uevent, FILE_DEVICE_MOUSE, TRUE); + HANDLE lastPID = NULL, lastPROC = NULL; + PEPROCESS lastPEP = NULL; + INT running = 1; + SIZE_T maxWaits = 20; + do { + LARGE_INTEGER wait = { .QuadPart = -10000000 }; + status = KeWaitForSingleObject(pk_kevent, Executive, UserMode, FALSE, &wait); + if (NT_SUCCESS(status) && status == WAIT_OBJECT_0) { + maxWaits = 20; + /* parse memory request */ + SIZE_T siz = SHMEM_SIZE; + status = KeReadVirtualMemory(ctrlPEP, (PVOID)SHMEM_ADDR, shm_buf, &siz); + + if (NT_SUCCESS(status) && siz == SHMEM_SIZE) { + switch (validateRequest(shm_buf)) + { + case MEM_HANDSHAKE: + KDBG("Invalid Request MEM_HANDSHAKE\n"); + break; + case MEM_PING: { + PKERNEL_PING ping = (PKERNEL_PING)shm_buf; + KDBG("Got a PING with rng 0x%X, sending PONG !\n", + ping->rnd_user); + ping->rnd_kern = ping->rnd_user; + siz = sizeof *ping; + KeWriteVirtualMemory(ctrlPEP, ping, (PVOID)SHMEM_ADDR, &siz); + break; + } + case MEM_PAGES: { + PKERNEL_PAGE pages = (PKERNEL_PAGE)shm_buf; + KDBG("Got a PAGES request for process 0x%X start at address 0x%p\n", + pages->ProcessId, pages->StartAddress); + if (!NT_SUCCESS(UpdatePPEPIfRequired(pages->ProcessId, + lastPID, &lastPROC, &lastPEP))) + { + running = 0; + break; + } + siz = (SHMEM_SIZE - sizeof *pages + sizeof pages->pages_start) + / sizeof pages->pages_start; + pages->StatusRes = GetPages(lastPEP, &pages->pages_start, siz, + &pages->pages, pages->StartAddress); + siz = (sizeof *pages - sizeof pages->pages_start) + + sizeof pages->pages_start * pages->pages; + KeWriteVirtualMemory(ctrlPEP, pages, (PVOID)SHMEM_ADDR, &siz); + break; + } + case MEM_MODULES: { + PKERNEL_MODULES mods = (PKERNEL_MODULES)shm_buf; + KDBG("Got a MODULES request for process 0x%X start at index 0x%X\n", + mods->ProcessId, mods->StartIndex); + if (!NT_SUCCESS(UpdatePPEPIfRequired(mods->ProcessId, + lastPID, &lastPROC, &lastPEP))) + { + running = 0; + break; + } + siz = (SHMEM_SIZE - sizeof *mods + sizeof mods->modules_start) + / sizeof mods->modules_start; + PMODULE_DATA entries = &mods->modules_start; + KDBG("GetModules max entries: %u\n", siz); + KeStackAttachProcess((PRKPROCESS)lastPEP, &apcstate); + mods->StatusRes = GetModules(lastPEP, entries, &siz, mods->StartIndex); + KeUnstackDetachProcess(&apcstate); + mods->modules = siz; + siz = (sizeof *mods - sizeof mods->modules_start) + + sizeof mods->modules_start * mods->modules; + KeWriteVirtualMemory(ctrlPEP, mods, (PVOID)SHMEM_ADDR, &siz); + break; + } + case MEM_RPM: { + PKERNEL_READ_REQUEST rr = (PKERNEL_READ_REQUEST)shm_buf; + KDBG("Got a RPM to process 0x%X, address 0x%p with size 0x%lX\n", + rr->ProcessId, rr->Address, rr->SizeReq); + if (!NT_SUCCESS(UpdatePPEPIfRequired(rr->ProcessId, + lastPID, &lastPROC, &lastPEP))) + { + running = 0; + break; + } + if (rr->SizeReq > SHMEM_SIZE - sizeof *rr) { + siz = SHMEM_SIZE - sizeof *rr; + } + else { + siz = rr->SizeReq; + } + ULONG new_prot = PAGE_EXECUTE_READWRITE, old_prot = 0; + KeProtectVirtualMemory(lastPROC, rr->Address, rr->SizeReq, new_prot, &old_prot); + KDBG("RPM to 0x%p size 0x%X bytes (protection before/after: 0x%X/0x%X)\n", + rr->Address, rr->SizeReq, old_prot, new_prot); + rr->StatusRes = KeReadVirtualMemory(lastPEP, (PVOID)rr->Address, + (PVOID)((ULONG_PTR)shm_buf + sizeof *rr), &siz); + KeRestoreProtectVirtualMemory(lastPROC, rr->Address, rr->SizeReq, old_prot); + if (NT_SUCCESS(rr->StatusRes)) { + rr->SizeRes = siz; + siz += sizeof *rr; + } + else { + rr->SizeRes = 0; + siz = sizeof *rr; + } + KeWriteVirtualMemory(ctrlPEP, rr, (PVOID)SHMEM_ADDR, &siz); + break; + } + case MEM_WPM: { + PKERNEL_WRITE_REQUEST wr = (PKERNEL_WRITE_REQUEST)shm_buf; + KDBG("Got a WPM to process 0x%X, address 0x%p with size 0x%lX\n", + wr->ProcessId, wr->Address, wr->SizeReq); + if (!NT_SUCCESS(UpdatePPEPIfRequired(wr->ProcessId, + lastPID, &lastPROC, &lastPEP))) + { + running = 0; + break; + } + if (wr->SizeReq > SHMEM_SIZE - sizeof *wr) { + siz = SHMEM_SIZE - sizeof *wr; + } + else { + siz = wr->SizeReq; + } + ULONG new_prot = PAGE_EXECUTE_READWRITE, old_prot = 0; + KeProtectVirtualMemory(lastPEP, wr->Address, wr->SizeReq, new_prot, &old_prot); + KDBG("WPM to 0x%p size 0x%X bytes (protection before/after: 0x%X/0x%X)\n", + wr->Address, wr->SizeReq, old_prot, new_prot); + wr->StatusRes = KeWriteVirtualMemory(lastPEP, (PVOID)((ULONG_PTR)shm_buf + sizeof *wr), + (PVOID)wr->Address, &siz); + KeRestoreProtectVirtualMemory(lastPROC, wr->Address, wr->SizeReq, old_prot); + if (NT_SUCCESS(wr->StatusRes)) { + wr->SizeRes = siz; + siz += sizeof *wr; + } + else { + wr->SizeRes = 0; + siz = sizeof *wr; + } + KeWriteVirtualMemory(ctrlPEP, wr, (PVOID)SHMEM_ADDR, &siz); + break; + } + case MEM_EXIT: + KDBG("Gracefully exiting ..\n"); + KeClearEvent(pk_kevent); + KeClearEvent(pk_uevent); + running = 0; + reinit = 0; + break; + default: + KDBG("Invalid Request\n"); + running = 0; + reinit = 0; + break; + } + } + + if (KeSetEvent(pk_uevent, FILE_DEVICE_MOUSE, TRUE)) { + KDBG("Previous signal state wasn't consumed!?\n"); + } + } + else { + if (!maxWaits--) { + KDBG("No activity, abort ..\n"); + running = 0; + } + } + } while (running); + KeSetEvent(pk_uevent, FILE_DEVICE_MOUSE, TRUE); + + if (lastPEP) + ObDereferenceObject(lastPEP); + if (lastPROC) + ZwClose(lastPROC); + MmFreeNonCachedMemory(shm_buf, SHMEM_SIZE); + nomem: + ObDereferenceObject(pk_uevent); + finish_kevent: + ObDereferenceObject(pk_kevent); + finish_ctrlpep: + ObDereferenceObject(ctrlPEP); + finish: + if (reinit) { + LARGE_INTEGER wait = { .QuadPart = -50000000 }; + KeDelayExecutionThread(KernelMode, TRUE, &wait); + } + } while (reinit); + + KDBG("Terminating ..\n"); + PsTerminateSystemThread(status); + return status; +} + +NTSTATUS UpdatePPEPIfRequired( + IN HANDLE wantedPID, + IN HANDLE lastPID, OUT HANDLE *lastPROC, + OUT PEPROCESS *lastPEP +) +{ + NTSTATUS status = STATUS_SUCCESS; + + if (wantedPID != lastPID) { + if (lastPID) { + ObDereferenceObject(*lastPEP); + *lastPEP = NULL; + ZwClose(*lastPROC); + *lastPROC = NULL; + } + status = PsLookupProcessByProcessId(wantedPID, lastPEP); + if (!NT_SUCCESS(status)) { + KDBG("PsLookupProcessByProcessId failed with 0x%X\n", status); + } + else { + status = ObOpenObjectByPointer(*lastPEP, + OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, GENERIC_ALL, + *PsProcessType, KernelMode, lastPROC + ); + if (!NT_SUCCESS(status)) { + KDBG("ObOpenObjectByPointer failed with 0x%X\n", status); + } + else { + PEPROCESS pep = *lastPEP; + PVOID base = NULL; + SIZE_T size = ADDRESS_AND_SIZE_TO_SPAN_PAGES(base, 4096); + PKAPC_STATE apc = MmAllocateNonCachedMemory(sizeof(*apc)); + KeStackAttachProcess((PRKPROCESS)pep, apc); + status = ZwAllocateVirtualMemory(ZwCurrentProcess(), &base, 0, &size, MEM_COMMIT, PAGE_READWRITE); + if (!NT_SUCCESS(status)) { + KDBG("ZwAllocateVirtualMemory failed with 0x%X\n", status); + } + else { + *(UINT64 *)base = 0x4141414142424242; + } + KeUnstackDetachProcess(apc); + KDBG("VAD Test Alloc.: 0x%p (status: 0x%X)\n", base, status); + PMMVAD_SHORT mmvad; + status = VADFind(pep, (ULONG_PTR)base, &mmvad); + KDBG("VAD Test.......: 0x%p (status: 0x%X)\n", mmvad->StartingVpn, status); + KeStackAttachProcess((PRKPROCESS)pep, apc); + if (*(UINT64 *)base != 0x4141414142424242) { + KDBG("VAD Test failed: 0x%p != 0x%p\n", 0x4141414142424242, base); + } + ZwFreeVirtualMemory(ZwCurrentProcess(), &base, &size, MEM_RELEASE); + KeUnstackDetachProcess(apc); + MmFreeNonCachedMemory(apc, sizeof(*apc)); +#if 0 + PMM_AVL_TABLE avltable = (PMM_AVL_TABLE)((ULONG_PTR *)pep + VAD_TREE_1803); + KDBG("VAD-ROOT.....: 0x%p\n", GET_VAD_ROOT(avltable)); + KDBG("NODE-HINT....: 0x%p\n", avltable->NodeHint); + KDBG("NMBR-OF-ELEMs: %d\n", avltable->NumberGenericTableElements); + KDBG("FLAGS........: 0x%p\n", *((UINT32 *)pep + 0x304)); + KDBG("VSIZE........: %d\n", *((UINT64 *)pep + 0x338)); + KDBG("IMAGEFILENAME: %.*s\n", 15, ((const char *)pep + 0x450)); +#endif + } + } + } + return status; +} + +NTSTATUS GetPages( + IN PEPROCESS Process, + OUT MEMORY_BASIC_INFORMATION *mbiArr, + IN SIZE_T mbiArrLen, OUT SIZE_T *mbiUsed, + IN PVOID start_addr +) +{ + NTSTATUS status; + HANDLE procHandle; + SIZE_T i, mbiLength, mbiReturn; + ULONG_PTR baseAddr = (ULONG_PTR)start_addr; + + status = ObOpenObjectByPointer(Process, + OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, GENERIC_ALL, + *PsProcessType, KernelMode, &procHandle + ); + if (!NT_SUCCESS(status)) { + KDBG("ObOpenObjectByPointer failed with 0x%X\n", status); + return status; + } + + KDBG("ZwQueryVirtualMemory max entries: %u\n", mbiArrLen); + *mbiUsed = 0; + do { + mbiReturn = 0; + status = ZwQueryVirtualMemory(procHandle, (PVOID)baseAddr, + MemoryBasicInformation, mbiArr, sizeof *mbiArr * mbiArrLen, &mbiReturn); + mbiLength = mbiReturn / sizeof *mbiArr; + if (!NT_SUCCESS(status)) { + if (status == STATUS_INVALID_PARAMETER) + status = STATUS_SUCCESS; + else + KDBG("ZwQueryVirtualMemory failed with 0x%X\n", status); + break; + } + else { + for (i = 0; i < mbiLength; ++i) + KDBG("Page #%03u: base -> 0x%p, prot -> 0x%02X, size -> 0x%X\n", + (*mbiUsed) + i, (*(mbiArr + i)).BaseAddress, (*(mbiArr + i)).Protect, + (*(mbiArr + i)).RegionSize); + } + baseAddr += (SIZE_T)(mbiArr + mbiLength - 1)->RegionSize; + *mbiUsed += mbiLength; + mbiArr += mbiLength; + } while (*mbiUsed < mbiArrLen && mbiReturn > 0); + + ZwClose(procHandle); + return status; +} + +NTSTATUS GetModules( + IN PEPROCESS Process, + OUT PMODULE_DATA pmod, IN OUT SIZE_T *psiz, + IN SIZE_T start_index +) +{ + SIZE_T used = 0, index = 0; + INT waitCount = 0; + + PPEB peb = PsGetProcessPeb(Process); + if (!peb) { + KDBG("PsGetProcessPeb failed"); + return STATUS_UNSUCCESSFUL; + } + + PPEB_LDR_DATA ldr = peb->Ldr; + + if (!ldr) { + KDBG("peb->Ldr is invalid"); + return STATUS_UNSUCCESSFUL; + } + + if (!ldr->Initialized) { + while (!ldr->Initialized && waitCount++ < 4) { + LARGE_INTEGER wait = { .QuadPart = -2500 }; + KeDelayExecutionThread(KernelMode, TRUE, &wait); + } + + if (!ldr->Initialized) { + KDBG("ldr->Initialized is 0"); + return STATUS_UNSUCCESSFUL; + } + } + + for (PLIST_ENTRY listEntry = (PLIST_ENTRY)ldr->InLoadOrderModuleList.Flink; + listEntry != &ldr->InLoadOrderModuleList && used < *psiz; + listEntry = (PLIST_ENTRY)listEntry->Flink, ++pmod, ++index) { + if (index < start_index) + continue; + used++; + + PLDR_DATA_TABLE_ENTRY ldrEntry = CONTAINING_RECORD(listEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); + ANSI_STRING name; + if (NT_SUCCESS(RtlUnicodeStringToAnsiString(&name, &ldrEntry->BaseDllName, sizeof pmod->BaseDllName))) { + RtlCopyMemory(pmod->BaseDllName, name.Buffer, + (name.Length > sizeof pmod->BaseDllName ? + sizeof pmod->BaseDllName : name.Length) + ); + } + pmod->DllBase = ldrEntry->DllBase; + pmod->SizeOfImage = ldrEntry->SizeOfImage; + KDBG("DLL #%02lu: base -> 0x%p, size -> 0x%06X, name -> '%s'\n", used, + pmod->DllBase, pmod->SizeOfImage, pmod->BaseDllName); + } + + *psiz = used; + return STATUS_SUCCESS; +} + +NTSTATUS KeReadVirtualMemory( + IN PEPROCESS Process, IN PVOID SourceAddress, + IN PVOID TargetAddress, IN PSIZE_T Size +) +{ + NTSTATUS status; + SIZE_T Bytes = 0; + + status = MmCopyVirtualMemory(Process, SourceAddress, PsGetCurrentProcess(), + TargetAddress, *Size, KernelMode, &Bytes); + if (NT_SUCCESS(status)) + { + *Size = Bytes; + return STATUS_SUCCESS; + } + else { + return status; + } +} + +NTSTATUS KeWriteVirtualMemory( + IN PEPROCESS Process, IN PVOID SourceAddress, + IN PVOID TargetAddress, IN PSIZE_T Size +) +{ + NTSTATUS status; + SIZE_T Bytes = 0; + + status = MmCopyVirtualMemory(PsGetCurrentProcess(), SourceAddress, Process, + TargetAddress, *Size, KernelMode, &Bytes); + if (NT_SUCCESS(status)) + { + *Size = Bytes; + return STATUS_SUCCESS; + } + else { + return status; + } +} + +NTSTATUS KeProtectVirtualMemory( + IN HANDLE hProcess, IN PVOID addr, + IN SIZE_T siz, IN ULONG new_prot, + OUT ULONG *old_prot +) +{ + NTSTATUS status; + PVOID prot_addr = addr; + SIZE_T prot_size = siz; + ULONG prot = 0; + + status = ZwProtectVirtualMemory(hProcess, &prot_addr, + &prot_size, new_prot, &prot); + if (NT_SUCCESS(status)) { + *old_prot = prot; + } + return status; +} + +NTSTATUS KeRestoreProtectVirtualMemory(IN HANDLE hProcess, + IN PVOID addr, IN SIZE_T siz, + IN ULONG old_prot) +{ + NTSTATUS status; + PVOID prot_addr = addr; + SIZE_T prot_size = siz; + ULONG prot = 0; + + status = ZwProtectVirtualMemory(hProcess, &prot_addr, + &prot_size, old_prot, &prot); + return status; +} + +static void fn_zero_text(PVOID fn_start) +{ + SIZE_T i; + UINT32 marker = 0xDEADC0DE; + PUCHAR fnbuf = (PUCHAR)fn_start; + + KDBG("Fn: %p\n", fn_start); + for (i = 0; i < 0x1000; ++i && fnbuf++) { + if (*(UINT32 *)fnbuf == marker) { + KDBG("Marker: 0x%X\n", i); + RtlSecureZeroMemory(fn_start, i + 4); + } + } +} + +NTSTATUS GetDriverObject( + IN OUT PDRIVER_OBJECT *lpObj, + IN WCHAR* DriverDirName +) +{ + NTSTATUS status = STATUS_SUCCESS; + PDRIVER_OBJECT pBeepObj = NULL; + UNICODE_STRING DevName = { 0 }; + + if (!MmIsAddressValid(lpObj)) + return STATUS_INVALID_ADDRESS; + + RtlInitUnicodeString(&DevName, DriverDirName); + + status = ObReferenceObjectByName(&DevName, OBJ_CASE_INSENSITIVE, NULL, 0, *IoDriverObjectType, KernelMode, NULL, &pBeepObj); + + if (NT_SUCCESS(status)) + *lpObj = pBeepObj; + else + { + *lpObj = NULL; + } + + return status; +} + +TABLE_SEARCH_RESULT +VADFindNodeOrParent( + IN PMM_AVL_TABLE Table, + IN ULONG_PTR StartingVpn, + OUT PMMADDRESS_NODE *NodeOrParent +) +{ + PMMADDRESS_NODE Child; + PMMADDRESS_NODE NodeToExamine; + PMMVAD_SHORT VpnCompare; + ULONG_PTR startVpn; + ULONG_PTR endVpn; + + if (Table->NumberGenericTableElements == 0) { + return TableEmptyTree; + } + + NodeToExamine = (PMMADDRESS_NODE)GET_VAD_ROOT(Table); + + for (;;) { + + VpnCompare = (PMMVAD_SHORT)NodeToExamine; + startVpn = VpnCompare->StartingVpn; + endVpn = VpnCompare->EndingVpn; + + startVpn |= (ULONG_PTR)VpnCompare->StartingVpnHigh << 32; + endVpn |= (ULONG_PTR)VpnCompare->EndingVpnHigh << 32; + + KDBG("Examining Node 0x%p with start VA 0x%p and end VA 0x%p\n", VpnCompare, startVpn, endVpn); + + // + // Compare the buffer with the key in the tree element. + // + + if (StartingVpn < startVpn) { + + Child = NodeToExamine->LeftChild; + + if (Child != NULL) { + NodeToExamine = Child; + } + else { + + // + // Node is not in the tree. Set the output + // parameter to point to what would be its + // parent and return which child it would be. + // + + *NodeOrParent = NodeToExamine; + return TableInsertAsLeft; + } + } + else if (StartingVpn <= endVpn) { + + // + // This is the node. + // + + *NodeOrParent = NodeToExamine; + return TableFoundNode; + } + else { + + Child = NodeToExamine->RightChild; + + if (Child != NULL) { + NodeToExamine = Child; + } + else { + + // + // Node is not in the tree. Set the output + // parameter to point to what would be its + // parent and return which child it would be. + // + + *NodeOrParent = NodeToExamine; + return TableInsertAsRight; + } + } + } +} + +NTSTATUS VADFind( + IN PEPROCESS pProcess, + IN ULONG_PTR address, + OUT PMMVAD_SHORT* pResult +) +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG_PTR vpnStart = address >> PAGE_SHIFT; + PMM_AVL_TABLE pTable = (PMM_AVL_TABLE)((PUCHAR)pProcess + VAD_TREE_1803); + PMM_AVL_NODE pNode = GET_VAD_ROOT(pTable); + + if (pProcess == NULL || pResult == NULL) + return STATUS_INVALID_PARAMETER; + + // Search VAD + if (VADFindNodeOrParent(pTable, vpnStart, &pNode) == TableFoundNode) + { + *pResult = (PMMVAD_SHORT)pNode; + } + else + { + KDBG("%s: VAD entry for address 0x%p not found\n", __FUNCTION__, address); + status = STATUS_NOT_FOUND; + } + + return status; +} + +NTSTATUS VADProtect( + IN PEPROCESS pProcess, + IN ULONG_PTR address, IN ULONG prot +) +{ + NTSTATUS status = STATUS_SUCCESS; + PMMVAD_SHORT pVadShort = NULL; + + status = VADFind(pProcess, address, &pVadShort); + if (NT_SUCCESS(status)) + pVadShort->u.VadFlags.Protection = prot; + + return status; +} \ No newline at end of file diff --git a/KMemDriver/KMemDriver.vcxproj b/KMemDriver/KMemDriver.vcxproj index 1c84ef0..898b55d 100644 --- a/KMemDriver/KMemDriver.vcxproj +++ b/KMemDriver/KMemDriver.vcxproj @@ -172,10 +172,10 @@ - + - + diff --git a/KMemDriver/KMemDriver.vcxproj.filters b/KMemDriver/KMemDriver.vcxproj.filters index 99f5bcc..218ceac 100644 --- a/KMemDriver/KMemDriver.vcxproj.filters +++ b/KMemDriver/KMemDriver.vcxproj.filters @@ -10,11 +10,6 @@ h;hpp;hxx;hm;inl;inc;xsd - - - Source Files - - Header Files @@ -22,8 +17,13 @@ Header Files - + Header Files + + + Source Files + + \ No newline at end of file diff --git a/MemDriverLib/MemDriverLib.cpp b/MemDriverLib/MemDriverLib.cpp index e91f2eb..38c038d 100644 --- a/MemDriverLib/MemDriverLib.cpp +++ b/MemDriverLib/MemDriverLib.cpp @@ -3,4 +3,328 @@ #include "stdafx.h" +#include "KInterface.h" +#include "KMemDriver.h" +#include +#include +#include + + +KInterface::KInterface() +{ +} + +bool KInterface::Init() +{ + std::srand((unsigned int)std::time(nullptr)); + m_shmem = VirtualAlloc((PVOID)SHMEM_ADDR, SHMEM_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + m_kevent = CreateEvent(NULL, FALSE, FALSE, NULL); + m_uevent = CreateEvent(NULL, FALSE, FALSE, NULL); + return m_shmem && m_kevent != INVALID_HANDLE_VALUE && m_uevent != INVALID_HANDLE_VALUE; +} + +bool KInterface::Handshake() +{ + PKERNEL_HANDSHAKE hnds = (PKERNEL_HANDSHAKE)getBuffer(); + hnds->kevent = m_kevent; + hnds->uevent = m_uevent; + m_last_ntstatus = INVALID_NTSTATUS; + return SendRecvWait(MEM_HANDSHAKE) == SRR_SIGNALED; +} + +bool KInterface::Ping() +{ + SendRecvReturn srr; + PKERNEL_PING ping = (PKERNEL_PING)getBuffer(); + m_last_ping_value = ping->rnd_user = (std::rand() << 16) | std::rand(); + std::srand(m_last_ping_value); + m_last_ntstatus = INVALID_NTSTATUS; + srr = SendRecvWait(MEM_PING); + if (ping->rnd_kern != getLastPingValue()) + return false; + return srr == SRR_SIGNALED; +} + +bool KInterface::Pages(HANDLE targetPID, + std::vector& dest, + PVOID start_address) +{ + PKERNEL_PAGE pages = (PKERNEL_PAGE)getBuffer(); + const ULONGLONG max_pages = (SHMEM_SIZE - sizeof *pages + + sizeof pages->pages_start) / sizeof pages->pages_start; + SendRecvReturn srr; + bool success = false; + + do { + m_last_ntstatus = INVALID_NTSTATUS; + pages->pages = 0; + pages->ProcessId = targetPID; + pages->StartAddress = start_address; + srr = SendRecvWait(MEM_PAGES); + if (srr == SRR_SIGNALED) { + m_last_ntstatus = pages->StatusRes; + if (validateRespone(getBuffer()) == MEM_PAGES && + !pages->StatusRes && + pages->pages * sizeof(pages->pages_start) <= SHMEM_SIZE) + { + for (SIZE_T i = 0; i < pages->pages; ++i) { + dest.push_back((&pages->pages_start)[i]); + start_address = (PVOID) + ((ULONG_PTR)((&pages->pages_start)[i].BaseAddress) + + (&pages->pages_start)[i].RegionSize); + } + success = true; + } + else { + success = false; + break; + } + } + } while (srr == SRR_SIGNALED && pages->pages == max_pages && pages->pages); + return success && srr == SRR_SIGNALED;; +} + +bool KInterface::Modules(HANDLE targetPID, + std::vector& dest) +{ + PKERNEL_MODULES mods = (PKERNEL_MODULES)getBuffer(); + SIZE_T start_index = 0; + const ULONGLONG max_mods = (SHMEM_SIZE - sizeof *mods + + sizeof mods->modules_start) / sizeof mods->modules_start; + SendRecvReturn srr; + bool success = false; + + do { + m_last_ntstatus = INVALID_NTSTATUS; + mods->modules = 0; + mods->ProcessId = targetPID; + mods->StartIndex = start_index; + srr = SendRecvWait(MEM_MODULES); + if (srr == SRR_SIGNALED) { + m_last_ntstatus = mods->StatusRes; + if (validateRespone(getBuffer()) == MEM_MODULES && + !mods->StatusRes && + mods->modules * sizeof(mods->modules_start) <= SHMEM_SIZE) + { + for (SIZE_T i = 0; i < mods->modules; ++i) { + dest.push_back((&mods->modules_start)[i]); + start_index++; + } + success = true; + } + else { + success = false; + break; + } + } + } while (srr == SRR_SIGNALED && mods->modules == max_mods && mods->modules); + return success && srr == SRR_SIGNALED; +} + +bool KInterface::Exit() +{ + m_last_ntstatus = INVALID_NTSTATUS; + return SendRecvWait(MEM_EXIT, INFINITE) == SRR_SIGNALED; +} + +bool KInterface::RPM(HANDLE targetPID, PVOID address, BYTE *buf, SIZE_T size, + PKERNEL_READ_REQUEST result) +{ + PKERNEL_READ_REQUEST rr = (PKERNEL_READ_REQUEST)getBuffer(); + m_last_ntstatus = INVALID_NTSTATUS; + if (size > SHMEM_SIZE - sizeof *rr) + return false; + rr->ProcessId = targetPID; + rr->Address = address; + rr->SizeReq = size; + rr->SizeRes = (SIZE_T)-1; + rr->StatusRes = (NTSTATUS)-1; + if (SendRecvWait(MEM_RPM) == SRR_SIGNALED) { + m_last_ntstatus = rr->StatusRes; + if (rr->StatusRes || + rr->SizeRes != size) + { + std::stringstream err_str; + err_str << "Call RPM(0x" << std::hex << address + << "," << std::dec << size + << ") failed with 0x" + << std::hex << rr->StatusRes + << " (Size Req/Res: " + << std::dec << rr->SizeReq << "/" << (SSIZE_T)rr->SizeRes + << ")"; + throw std::runtime_error(err_str.str()); + } + memcpy(buf, (BYTE *)rr + sizeof *rr, size); + if (result) + *result = *rr; + return true; + } + return false; +} + +bool KInterface::WPM(HANDLE targetPID, PVOID address, BYTE *buf, SIZE_T size, + PKERNEL_WRITE_REQUEST result) +{ + PKERNEL_WRITE_REQUEST wr = (PKERNEL_WRITE_REQUEST)getBuffer(); + m_last_ntstatus = INVALID_NTSTATUS; + if (size > SHMEM_SIZE - sizeof *wr) + return false; + wr->ProcessId = targetPID; + wr->Address = address; + wr->SizeReq = size; + wr->SizeRes = (SIZE_T)-1; + wr->StatusRes = (NTSTATUS)-1; + memcpy((BYTE *)wr + sizeof *wr, buf, size); + if (SendRecvWait(MEM_WPM) == SRR_SIGNALED) { + m_last_ntstatus = wr->StatusRes; + if (wr->StatusRes || + wr->SizeRes != size) + { + std::stringstream err_str; + err_str << "Call WPM(0x" << std::hex << address + << "," << std::dec << size + << ") failed with 0x" + << std::hex << wr->StatusRes + << " (Size Req/Res: " + << std::dec << wr->SizeReq << "/" << (SSIZE_T)wr->SizeRes + << ")"; + throw std::runtime_error(err_str.str()); + } + if (result) + *result = *wr; + return true; + } + return false; +} + +PVOID KInterface::getBuffer() { + if (!m_shmem) + throw std::runtime_error("Call Init() before.."); + return m_shmem; +} + +HANDLE KInterface::getKHandle() { + if (!m_kevent) + throw std::runtime_error("Call Init() before.."); + return m_kevent; +} + +HANDLE KInterface::getUHandle() { + if (!m_uevent) + throw std::runtime_error("Call Init() before.."); + return m_uevent; +} + +UINT32 KInterface::getLastPingValue() { + return m_last_ping_value; +} + +UINT32 KInterface::getLastNtStatus() { + return m_last_ntstatus; +} + +SendRecvReturn KInterface::SendRecvWait(UINT32 type, DWORD timeout) +{ + prepareRequest(getBuffer(), type); + if (!SetEvent(m_kevent)) + return SRR_ERR_KEVENT; + return RecvWait(timeout); +} + +SendRecvReturn KInterface::RecvWait(DWORD timeout) +{ + switch (WaitForSingleObject(m_uevent, timeout)) { + case WAIT_OBJECT_0: + return validateRespone(getBuffer()) != INVALID_REQUEST ? SRR_SIGNALED : SRR_ERR_HEADER; + case WAIT_TIMEOUT: + return SRR_TIMEOUT; + } + return SRR_ERR_UEVENT; +} + +SSIZE_T KScan::KScanSimple(HANDLE targetPID, PVOID start_address, SIZE_T max_scansize, + PVOID scanbuf, SIZE_T scanbuf_size) +{ + ULONG_PTR max_addr; + ULONG_PTR cur_addr = (ULONG_PTR)start_address; + BYTE tmp_rpmbuf[SHMEM_SIZE]; + SIZE_T scan_index, processed, real_size, diff_size; + std::vector mbis; + KERNEL_READ_REQUEST rr = { 0 }; + + if (max_scansize < scanbuf_size) + return -1; + if (!KInterface::getInstance().Pages(targetPID, mbis, start_address)) + return -1; + + diff_size = (ULONG_PTR)start_address - (ULONG_PTR)mbis.at(0).BaseAddress; + real_size = (mbis.at(0).RegionSize - diff_size > max_scansize ? + max_scansize : (ULONG_PTR)mbis.at(0).RegionSize - diff_size); + max_addr = (ULONG_PTR)start_address + real_size; + + while (cur_addr < max_addr) { + if (!KInterface::getInstance().RPM(targetPID, (PVOID)cur_addr, + tmp_rpmbuf, (sizeof tmp_rpmbuf > real_size ? real_size : sizeof tmp_rpmbuf), &rr)) + { + break; + } + + if (rr.StatusRes || rr.SizeRes < scanbuf_size) + break; + + for (processed = 0, scan_index = 0; processed < rr.SizeRes; ++processed) { + if (tmp_rpmbuf[processed] != *((BYTE*)scanbuf + scan_index)) { + scan_index = 0; + } + else { + scan_index++; + if (scan_index == scanbuf_size) { + return cur_addr + processed - scanbuf_size + 1; + } + } + } + cur_addr += processed; + real_size -= processed; + } + return -1; +} + +SSIZE_T KScan::KBinDiffSimple(HANDLE targetPID, PVOID start_address, + BYTE *curbuf, BYTE *oldbuf, SIZE_T siz, std::vector> *diffs) +{ + SSIZE_T scanned, diff_start; + SIZE_T diff_size; + KERNEL_READ_REQUEST rr = { 0 }; + + if (!KInterface::getInstance().RPM(targetPID, start_address, + curbuf, siz, &rr)) + { + scanned = -1; + } + else scanned = rr.SizeRes; + + if (scanned > 0) { + diffs->clear(); + diff_start = -1; + diff_size = 0; + for (SIZE_T i = 0; i < (SIZE_T)scanned; ++i) { + if (curbuf[i] != oldbuf[i]) { + if (diff_start < 0) + diff_start = i; + diff_size++; + } + else if (diff_start >= 0) { + diffs->push_back(std::pair + (diff_start, diff_size)); + diff_start = -1; + diff_size = 0; + } + } + memcpy(oldbuf, curbuf, scanned); + if ((SIZE_T)scanned < siz) + memset(oldbuf + scanned, 0, siz - scanned); + } + + return scanned; +} \ No newline at end of file diff --git a/MemDriverLib/MemDriverLib.vcxproj b/MemDriverLib/MemDriverLib.vcxproj index 939ae83..7289ecb 100644 --- a/MemDriverLib/MemDriverLib.vcxproj +++ b/MemDriverLib/MemDriverLib.vcxproj @@ -90,6 +90,7 @@ true _DEBUG;MEMDRIVERLIB_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true + $(SolutionDir)/include;%(AdditionalIncludeDirectories) Windows @@ -139,6 +140,7 @@ true NDEBUG;MEMDRIVERLIB_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true + $(SolutionDir)/include;%(AdditionalIncludeDirectories) Windows @@ -149,7 +151,7 @@ - + diff --git a/MemDriverLib/MemDriverLib.vcxproj.filters b/MemDriverLib/MemDriverLib.vcxproj.filters index b674adc..12267f1 100644 --- a/MemDriverLib/MemDriverLib.vcxproj.filters +++ b/MemDriverLib/MemDriverLib.vcxproj.filters @@ -21,10 +21,10 @@ Header Files - + Header Files - + Header Files diff --git a/MemDriverWeb/MemDriverWeb.cpp b/MemDriverWeb/MemDriverWeb.cpp index 5e9dfc5..2622d87 100644 --- a/MemDriverWeb/MemDriverWeb.cpp +++ b/MemDriverWeb/MemDriverWeb.cpp @@ -1,6 +1,7 @@ #include "pch.h" #include #include +#include #include "www.h" #include "minitmpl.h" @@ -27,6 +28,7 @@ static std::string& template_test_cb(std::string &out) int main() { + KInterface &ki = KInterface::getInstance(); httplib::Server httpServer; TemplateString::registerTemplateCallback("<% CONTENT %>", template_test_cb); diff --git a/MemDriverWeb/MemDriverWeb.vcxproj b/MemDriverWeb/MemDriverWeb.vcxproj index a545fd4..e005901 100644 --- a/MemDriverWeb/MemDriverWeb.vcxproj +++ b/MemDriverWeb/MemDriverWeb.vcxproj @@ -93,11 +93,13 @@ _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true pch.h + $(SolutionDir)/include;%(AdditionalIncludeDirectories) Console true - $(VCToolsInstallDir)lib\x64;%(AdditionalLibraryDirectories) + $(VCToolsInstallDir)lib\x64;$(OutputPath);%(AdditionalLibraryDirectories) + MemDriverLib.lib;%(AdditionalDependencies) @@ -145,13 +147,15 @@ NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true pch.h + $(SolutionDir)/include;%(AdditionalIncludeDirectories) Console true true true - $(VCToolsInstallDir)lib\x64;%(AdditionalLibraryDirectories) + $(VCToolsInstallDir)lib\x64;$(OutputPath);%(AdditionalLibraryDirectories) + MemDriverLib.lib;%(AdditionalDependencies) diff --git a/include/Driver.h b/include/Driver.h deleted file mode 100644 index 6a41fe2..0000000 --- a/include/Driver.h +++ /dev/null @@ -1,131 +0,0 @@ -#pragma once - -#ifdef KERNEL_MODULE -#include "Native.h" -#else -#include -#endif - -#define HDR_MAGIC 0xDEADC0DE -#define SHMEM_ADDR 0x60000000 -#define SHMEM_SIZE 8192*8*2 -#define INVALID_REQUEST (UINT32)-1 - -#define MEM_HANDSHAKE 0x800 -#define MEM_PING 0x801 -#define MEM_MODULES 0x802 -#define MEM_PAGES 0x803 -#define MEM_RPM 0x804 -#define MEM_WPM 0x805 -#define MEM_EXIT 0x806 - -typedef struct _KERNEL_HEADER -{ - UINT32 magic; - UINT32 type; -} KERNEL_HEADER, *PKERNEL_HEADER; - -typedef struct _KERNEL_HANDSHAKE -{ - KERNEL_HEADER hdr; - HANDLE kevent; - HANDLE uevent; -} KERNEL_HANDSHAKE, *PKERNEL_HANDSHAKE; - -typedef struct _KERNEL_PING -{ - KERNEL_HEADER hdr; - UINT32 rnd_user; - UINT32 rnd_kern; -} KERNEL_PING, *PKERNEL_PING; - -typedef struct _KERNEL_PAGE -{ - KERNEL_HEADER hdr; - HANDLE ProcessId; - PVOID StartAddress; - - NTSTATUS StatusRes; - SIZE_T pages; - MEMORY_BASIC_INFORMATION pages_start; -} KERNEL_PAGE, *PKERNEL_PAGE; - -typedef struct _MODULE_DATA -{ - PVOID DllBase; - ULONG SizeOfImage; - CHAR BaseDllName[64]; -} MODULE_DATA, *PMODULE_DATA; - -typedef struct _KERNEL_MODULES -{ - KERNEL_HEADER hdr; - HANDLE ProcessId; - SIZE_T StartIndex; - - NTSTATUS StatusRes; - SIZE_T modules; - MODULE_DATA modules_start; -} KERNEL_MODULES, *PKERNEL_MODULES; - -typedef struct _KERNEL_EXIT -{ - KERNEL_HEADER hdr; -} KERNEL_EXIT, *PKERNEL_EXIT; - -typedef struct _KERNEL_READ_REQUEST -{ - KERNEL_HEADER hdr; - HANDLE ProcessId; - PVOID Address; - SIZE_T SizeReq; - - NTSTATUS StatusRes; - SIZE_T SizeRes; -} KERNEL_READ_REQUEST, *PKERNEL_READ_REQUEST; - -typedef struct _KERNEL_WRITE_REQUEST -{ - KERNEL_HEADER hdr; - HANDLE ProcessId; - PVOID Address; - SIZE_T SizeReq; - - NTSTATUS StatusRes; - SIZE_T SizeRes; -} KERNEL_WRITE_REQUEST, *PKERNEL_WRITE_REQUEST; - - -#ifndef KERNEL_MODULE -static inline VOID prepareRequest(PVOID buf, UINT32 type) -{ - PKERNEL_HEADER hdr = (PKERNEL_HEADER)buf; - hdr->magic = HDR_MAGIC; - hdr->type = type; -} -#endif - -static inline UINT32 -#ifndef KERNEL_MODULE -validateRespone -#else -validateRequest -#endif -(PVOID buf) -{ - PKERNEL_HEADER hdr = (PKERNEL_HEADER)buf; - if (hdr->magic != HDR_MAGIC) - return INVALID_REQUEST; - switch (hdr->type) { - case MEM_HANDSHAKE: - case MEM_PING: - case MEM_PAGES: - case MEM_MODULES: - case MEM_RPM: - case MEM_WPM: - case MEM_EXIT: - return hdr->type; - default: - return INVALID_REQUEST; - } -} \ No newline at end of file diff --git a/include/KInterface.h b/include/KInterface.h index a8a7ee2..7f485a6 100644 --- a/include/KInterface.h +++ b/include/KInterface.h @@ -1,6 +1,6 @@ #pragma once -#include "Driver.h" +#include "KMemDriver.h" #include #include diff --git a/include/KMemDriver.h b/include/KMemDriver.h new file mode 100644 index 0000000..c6bd734 --- /dev/null +++ b/include/KMemDriver.h @@ -0,0 +1,134 @@ +#pragma once + +#ifdef KERNEL_MODULE +#include "Native.h" +#else +#include +#ifndef NTSTATUS +typedef _Return_type_success_(return >= 0) LONG NTSTATUS; +#endif +#endif + +#define HDR_MAGIC 0xDEADC0DE +#define SHMEM_ADDR 0x60000000 +#define SHMEM_SIZE 8192*8*2 +#define INVALID_REQUEST (UINT32)-1 + +#define MEM_HANDSHAKE 0x800 +#define MEM_PING 0x801 +#define MEM_MODULES 0x802 +#define MEM_PAGES 0x803 +#define MEM_RPM 0x804 +#define MEM_WPM 0x805 +#define MEM_EXIT 0x806 + +typedef struct _KERNEL_HEADER +{ + UINT32 magic; + UINT32 type; +} KERNEL_HEADER, *PKERNEL_HEADER; + +typedef struct _KERNEL_HANDSHAKE +{ + KERNEL_HEADER hdr; + HANDLE kevent; + HANDLE uevent; +} KERNEL_HANDSHAKE, *PKERNEL_HANDSHAKE; + +typedef struct _KERNEL_PING +{ + KERNEL_HEADER hdr; + UINT32 rnd_user; + UINT32 rnd_kern; +} KERNEL_PING, *PKERNEL_PING; + +typedef struct _KERNEL_PAGE +{ + KERNEL_HEADER hdr; + HANDLE ProcessId; + PVOID StartAddress; + + NTSTATUS StatusRes; + SIZE_T pages; + MEMORY_BASIC_INFORMATION pages_start; +} KERNEL_PAGE, *PKERNEL_PAGE; + +typedef struct _MODULE_DATA +{ + PVOID DllBase; + ULONG SizeOfImage; + CHAR BaseDllName[64]; +} MODULE_DATA, *PMODULE_DATA; + +typedef struct _KERNEL_MODULES +{ + KERNEL_HEADER hdr; + HANDLE ProcessId; + SIZE_T StartIndex; + + NTSTATUS StatusRes; + SIZE_T modules; + MODULE_DATA modules_start; +} KERNEL_MODULES, *PKERNEL_MODULES; + +typedef struct _KERNEL_EXIT +{ + KERNEL_HEADER hdr; +} KERNEL_EXIT, *PKERNEL_EXIT; + +typedef struct _KERNEL_READ_REQUEST +{ + KERNEL_HEADER hdr; + HANDLE ProcessId; + PVOID Address; + SIZE_T SizeReq; + + NTSTATUS StatusRes; + SIZE_T SizeRes; +} KERNEL_READ_REQUEST, *PKERNEL_READ_REQUEST; + +typedef struct _KERNEL_WRITE_REQUEST +{ + KERNEL_HEADER hdr; + HANDLE ProcessId; + PVOID Address; + SIZE_T SizeReq; + + NTSTATUS StatusRes; + SIZE_T SizeRes; +} KERNEL_WRITE_REQUEST, *PKERNEL_WRITE_REQUEST; + + +#ifndef KERNEL_MODULE +static inline VOID prepareRequest(PVOID buf, UINT32 type) +{ + PKERNEL_HEADER hdr = (PKERNEL_HEADER)buf; + hdr->magic = HDR_MAGIC; + hdr->type = type; +} +#endif + +static inline UINT32 +#ifndef KERNEL_MODULE +validateRespone +#else +validateRequest +#endif +(PVOID buf) +{ + PKERNEL_HEADER hdr = (PKERNEL_HEADER)buf; + if (hdr->magic != HDR_MAGIC) + return INVALID_REQUEST; + switch (hdr->type) { + case MEM_HANDSHAKE: + case MEM_PING: + case MEM_PAGES: + case MEM_MODULES: + case MEM_RPM: + case MEM_WPM: + case MEM_EXIT: + return hdr->type; + default: + return INVALID_REQUEST; + } +} \ No newline at end of file -- cgit v1.2.3