Change name to lpus

This commit is contained in:
2020-06-11 17:16:40 +07:00
parent 7e009b6bfe
commit 533666baab
16 changed files with 1840 additions and 2525 deletions

603
lpus/Driver.cpp Normal file
View File

@ -0,0 +1,603 @@
#include <ntddk.h>
#include <wdf.h>
#include <ntdef.h>
#include <ntstrsafe.h>
#include "Driver.h"
#include "sioctl.h"
// #include "simplewsk.h"
extern "C" DRIVER_INITIALIZE DriverEntry;
extern "C" DRIVER_UNLOAD UnloadRoutine;
extern "C" DRIVER_DISPATCH DriverCreateClose;
extern "C" DRIVER_DISPATCH DriverControl;
// extern "C" PDBGKD_GET_VERSION64 FindKdVersionBlock(void);
#define NT_DEVICE_NAME L"\\Device\\poolscanner"
#define DOS_DEVICE_NAME L"\\DosDevices\\poolscanner"
#define F_DbgPrint(...) \
DbgPrint("[NAK] :: ");\
DbgPrint(__VA_ARGS__);
#define POOL_HEADER_SIZE 0x10 // windows 10
#define CHUNK_SIZE 16 // 64 bit
// #define PAGE_SIZE 4096 // 4KB
// some globals
PVOID ntosbase;
PVOID systemEprocess;
PVOID processHead;
// offset to get from PDB file
ULONG64 eprocessNameOffset = 0;
ULONG64 eprocessLinkOffset = 0;
ULONG64 listBLinkOffset = 0;
ULONG64 processHeadOffset = 0;
ULONG64 miStateOffset = 0;
ULONG64 hardwareOffset = 0;
ULONG64 systemNodeOffset = 0;
ULONG64 firstVaOffset = 0;
ULONG64 lastVaOffset = 0;
ULONG64 largePageTableOffset = 0;
ULONG64 largePageSizeOffset = 0;
ULONG64 poolChunkSize = 0;
NTSTATUS
DriverCreateClose(PDEVICE_OBJECT /* DriverObject */, PIRP Irp) {
PAGED_CODE();
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS
DriverControl(PDEVICE_OBJECT /* DriverObject */, PIRP Irp) {
PIO_STACK_LOCATION irpSp;
NTSTATUS ntStatus = STATUS_SUCCESS;
// ULONG inBufLength;
// ULONG outBufLength;
ULONG controlCode;
// PCHAR inBuf;
// PCHAR outBuf;
PINPUT_DATA inputData = nullptr;
POUTPUT_DATA outputData = nullptr;
POFFSET_VALUE offsetValues = nullptr;
PDEREF_ADDR derefAddr = nullptr;
PSCAN_RANGE scanRange = nullptr;
PHIDE_PROCESS processHide = nullptr;
PAGED_CODE();
irpSp = IoGetCurrentIrpStackLocation(Irp);
/*
* struct {
* ULONG OutputBufferLength;
* ULONG POINTER_ALIGNMENT InputBufferLength;
* ULONG POINTER_ALIGNMENT IoControlCode;
* PVOID Type3InputBuffer;
* } DeviceIoControl;
**/
controlCode = irpSp->Parameters.DeviceIoControl.IoControlCode;
switch (controlCode) {
case IOCTL_SETUP_OFFSETS:
DbgPrint("[NAK] :: [ ] Setup offsets\n");
inputData = (PINPUT_DATA)(Irp->AssociatedIrp.SystemBuffer);
offsetValues = &(inputData->offsetValues);
eprocessNameOffset = offsetValues->eprocessNameOffset;
eprocessLinkOffset = offsetValues->eprocessLinkOffset;
listBLinkOffset = offsetValues->listBLinkOffset;
processHeadOffset = offsetValues->processHeadOffset;
miStateOffset = offsetValues->miStateOffset;
hardwareOffset = offsetValues->hardwareOffset;
systemNodeOffset = offsetValues->systemNodeOffset;
firstVaOffset = offsetValues->firstVaOffset;
lastVaOffset = offsetValues->lastVaOffset;
largePageTableOffset = offsetValues->largePageTableOffset;
largePageSizeOffset = offsetValues->largePageSizeOffset;
poolChunkSize = offsetValues->poolChunkSize;
setup();
break;
case GET_KERNEL_BASE:
DbgPrint("[NAK] :: [ ] Get kernel base\n");
outputData = (POUTPUT_DATA)MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority | MdlMappingNoExecute);
// TODO: check for safety outputData address null
outputData->ulong64Value = (ULONG64)ntosbase;
Irp->IoStatus.Information = sizeof(ULONG64);
break;
case SCAN_PS_ACTIVE_HEAD:
DbgPrint("[NAK] :: [ ] Scan ps active head\n");
scan_ps_active_head();
break;
case SCAN_POOL:
DbgPrint("[NAK] :: [ ] Scan pool\n");
inputData = (PINPUT_DATA)(Irp->AssociatedIrp.SystemBuffer);
scanRange = &(inputData->scanRange);
DbgPrint("[NAK] :: Range: %llx - %llx", scanRange->start, scanRange->end);
scanNormalPool(scanRange->start, scanRange->end);
break;
case SCAN_POOL_REMOTE:
inputData = (PINPUT_DATA)(Irp->AssociatedIrp.SystemBuffer);
outputData = (POUTPUT_DATA)MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority | MdlMappingNoExecute);
scanRange = &(inputData->scanRange);
DbgPrint("[NAK] :: Range: %llx - %llx", scanRange->start, scanRange->end);
(outputData->poolChunk).addr = (ULONG64)scanRemote(scanRange->start, scanRange->end, scanRange->tag);
DbgPrint("[NAK] :: Found: %llx", (outputData->poolChunk).addr);
break;
case DEREFERENCE_ADDRESS:
// DbgPrint("[NAK] :: [ ] Deref address\n");
inputData = (PINPUT_DATA)(Irp->AssociatedIrp.SystemBuffer);
derefAddr = &(inputData->derefAddr);
outputData = (POUTPUT_DATA)MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority | MdlMappingNoExecute);
// DbgPrint("[NAK] :: [ ] Deref %llu bytes from %llx\n", derefAddr->size, derefAddr->addr);
RtlCopyBytes((PVOID)outputData, (PVOID)derefAddr->addr, (SIZE_T)derefAddr->size);
break;
case HIDE_PROCESS_BY_NAME:
DbgPrint("[NAK] :: [ ] Hide process\n");
inputData = (PINPUT_DATA)(Irp->AssociatedIrp.SystemBuffer);
processHide = &(inputData->processHide);
DbgPrint("[NAK] :: [ ] Hide process name: [%15s]; size: %llu\n", processHide->name, processHide->size);
hideProcess(processHide->name, processHide->size);
break;
default:
break;
}
Irp->IoStatus.Status = ntStatus;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return ntStatus;
}
NTSTATUS
DriverEntry(
_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_STRING /* RegistryPath */
) {
DbgPrint("[NAK] :: [ ] Hello from Kernel, setup a few things\n");
NTSTATUS returnStatus = STATUS_SUCCESS;
UNICODE_STRING ntUnicodeString;
UNICODE_STRING ntWin32NameString;
PDEVICE_OBJECT deviceObject = nullptr;
PAGED_CODE();
RtlInitUnicodeString(&ntUnicodeString, NT_DEVICE_NAME);
returnStatus = IoCreateDevice(
DriverObject, // Our Driver Object
0, // We don't use a device extension
&ntUnicodeString, // Device name "\Device\poolscanner"
FILE_DEVICE_UNKNOWN, // Device type
FILE_DEVICE_SECURE_OPEN, // Device characteristics
FALSE, // Not an exclusive device
&deviceObject); // Returned ptr to Device Object
if (!NT_SUCCESS(returnStatus)) {
DbgPrint(("[NAK] :: [-] Couldn't create the device object\n"));
return returnStatus;
}
DriverObject->DriverUnload = UnloadRoutine;
DriverObject->MajorFunction[IRP_MJ_CREATE] = DriverCreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DriverCreateClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DriverControl;
RtlInitUnicodeString(&ntWin32NameString, DOS_DEVICE_NAME);
returnStatus = IoCreateSymbolicLink(&ntWin32NameString, &ntUnicodeString);
if (!NT_SUCCESS(returnStatus)) {
DbgPrint("[NAK] :: [-] Couldn't create symbolic link for driver\n");
IoDeleteDevice(deviceObject);
}
systemEprocess = IoGetCurrentProcess();
DbgPrint("[NAK] :: [+] Setup completed, waiting for command on DeviceIo\n");
return returnStatus;
}
VOID
setup() {
PAGED_CODE();
// TODO: Exception?????
PVOID eprocess = systemEprocess;
DbgPrint("[NAK] :: [ ] System eprocess : 0x%p, [%15s]\n",
eprocess, (char*)((ULONG64)eprocess + eprocessNameOffset));
processHead = (PVOID)(*(ULONG64*)((ULONG64)eprocess + eprocessLinkOffset + listBLinkOffset));
DbgPrint("[NAK] :: [ ] PsActiveProcessHead : 0x%p\n", processHead);
ntosbase = (PVOID)((ULONG64)processHead - processHeadOffset);
DbgPrint("[NAK] :: [ ] ntoskrnl.exe : 0x%p\n", ntosbase);
// TODO: Check if ntosbase is a PE, and the name is ntoskrnl.exe
// https://stackoverflow.com/a/4316804
// https://stackoverflow.com/a/47898643
// https://github.com/Reetus/RazorRE/blob/42f441093bd85443b39fcff5d2a02069b524b114/Crypt/Misc.cpp#L63
// if (ntosbase->e_magic == IMAGE_DOS_SIGNATURE) {
// DbgPrint("[NAK] :: [ ] DOS Signature (MZ) Matched \n");
// const PIMAGE_NT_HEADERS32 peHeader = (PIMAGE_NT_HEADERS32) ((unsigned char*)ntosbase+ntosbase->e_lfanew);
// if(peHeader->Signature == IMAGE_NT_SIGNATURE) {
// DbgPrint("[NAK] :: [ ] PE Signature (PE) Matched \n");
// // yeah we really got ntoskrnl.exe base
// }
// }
}
VOID
scan_ps_active_head() {
PVOID eprocess = (PVOID)((ULONG64)processHead - eprocessLinkOffset);
DbgPrint("[NAK] :: [ ] Scan the PsActiveProcessHead linked-list\n");
while (*(ULONG64*)((ULONG64)eprocess + eprocessLinkOffset) != (ULONG64)processHead) {
eprocess = (PVOID)(*(ULONG64*)((ULONG64)eprocess + eprocessLinkOffset) - eprocessLinkOffset);
DbgPrint("[NAK] :: [ ] eprocess : 0x%p, [%15s]\n",
eprocess, (char*)((ULONG64)eprocess + eprocessNameOffset));
}
}
VOID
hideProcess(CHAR* name, ULONG64 size) {
PVOID eprocess = (PVOID)((ULONG64)processHead - eprocessLinkOffset);
while (*(ULONG64*)((ULONG64)eprocess + eprocessLinkOffset) != (ULONG64)processHead) {
PVOID next_eprocess = (PVOID)(*(ULONG64*)((ULONG64)eprocess + eprocessLinkOffset) - eprocessLinkOffset);
char* processName = (char*)((ULONG64)eprocess + eprocessNameOffset);
int i = 0;
for (; i < size; i++) {
if (processName[i] != name[i]) break;
}
if (i != size) {
eprocess = next_eprocess;
continue;
}
// found process with name
PVOID next_eprocess_link = (PVOID)(*(ULONG64*)((ULONG64)eprocess + eprocessLinkOffset));
PVOID prev_eprocess_link = (PVOID)(*(ULONG64*)((ULONG64)eprocess + eprocessLinkOffset + listBLinkOffset));
// set current to 0
// *(ULONG64*)((ULONG64)eprocess + eprocessLinkOffset) = 0;
// *(ULONG64*)((ULONG64)eprocess + eprocessLinkOffset + listBLinkOffset) = 0;
*(ULONG64*)((ULONG64)next_eprocess_link + listBLinkOffset) = (ULONG64)prev_eprocess_link;
*(ULONG64*)prev_eprocess_link = (ULONG64)next_eprocess_link;
eprocess = next_eprocess;
}
}
NTSTATUS
routine() {
PAGED_CODE();
NTSTATUS returnStatus = STATUS_SUCCESS;
OSVERSIONINFOW windowsVersionInfo;
RtlGetVersion(&windowsVersionInfo);
DbgPrint("[NAK] :: [ ] Windows version : %lu.%lu.%lu\n",
windowsVersionInfo.dwMajorVersion, windowsVersionInfo.dwMinorVersion, windowsVersionInfo.dwBuildNumber);
if (windowsVersionInfo.dwMajorVersion != 10) {
DbgPrint("[NAK] :: [-] Windows version outside 10 is not supported yet!");
return returnStatus;
}
// https://en.wikipedia.org/wiki/Windows_10_version_history
VERSION_BY_POOL windowsVersionByPool = WINDOWS_NOT_SUPPORTED;
// TODO: Move this to front-end for portable update
// TODO: automatically get from parsed PDB file
if (windowsVersionInfo.dwBuildNumber == 17134 || windowsVersionInfo.dwBuildNumber == 17763) {
DbgPrint("[NAK] :: [ ] Detected windows : 2018\n");
windowsVersionByPool = WINDOWS_2018;
}
else if (windowsVersionInfo.dwBuildNumber == 18362 || windowsVersionInfo.dwBuildNumber == 18363) {
DbgPrint("[NAK] :: [ ] Detected windows : 2019\n");
windowsVersionByPool = WINDOWS_2019;
}
else if (windowsVersionInfo.dwBuildNumber == 19041) {
DbgPrint("[NAK] :: [ ] Detected windows : 2020\n");
windowsVersionByPool = WINDOWS_2020;
}
else if (windowsVersionInfo.dwBuildNumber >= 19536) {
DbgPrint("[NAK] :: [ ] Detected windows : 2020 Fast Ring\n");
windowsVersionByPool = WINDOWS_2020_FASTRING;
// eprocessNameOffset = 0x5a8;
// eprocessLinkOffset = 0x448;
// listBLinkOffset = 0x8;
// processHeadOffset = 0xc1f960;
// miStateOffset = 0xc4f040;
// hardwareOffset = 0x1580;
// systemNodeOffset = 0x20;
// firstVaOffset = 0x60;
// lastVaOffset = 0x68;
// largePageTableOffset = 0xc1a740;
// largePageSizeOffset = 0xc1a738;
}
if (windowsVersionByPool == WINDOWS_NOT_SUPPORTED) {
DbgPrint("[NAK] :: [-] Windows 10 with this build number is not supported yet!");
return returnStatus;
}
/**
* Try to find `MmNonPagedPoolStart` and `MmNonPagedPoolEnd`
*
* https://web.archive.org/web/20061110120809/http://www.rootkit.com/newsread.php?newsid=153
* KPCR->KdVersionBlock->Debugger Data List Entry->Flink
*
* This technique is old and cannot be used in Windows 10, Windows 7/8 may fail too,
* After research, the result is summary into this README
* https://github.com/nganhkhoa/pdb_for_nonpagedpool
*
* Basically, find ntoskrnl.exe module address (kernel base) in memory and use offsets parsed from PDB file,
* Finding the kernel base by shellcode is not usable in Windows 2020 Insider Preview,
* I use IoGetCurrentProcess and traverse the ActiveProcessLinks linked list,
* Luckily, the process returned by IoGetCurrentProcess is System (the first process), so the BLINK is nt!PsActiveProcessHead
* With offset of nt!PsActiveProcessHead parsed from PDB file, we can get the kernel base by subtracting.
*
* Then offset to find NonPagedPool{First,Last}Va
*
* In Windows 10, we must use nt!MiState and look into Hardware->NodeInfo,
* there is a slightly different layout/offset to each version of Windows by year?
* 2015 -> 2016 -> 2018 -> 2019 -> 2020 all have a slight (or big) different
*
**/
/**
* In Windows 10 Insider Preview Feb 2020, the global debug is MiState, try this in windbg and see
* `x nt!MiState` to get address of MiState
* `dt _MI_SYSTEM_INFORMATION` to get offset to Hardware
* `dt _MI_HARDWARE_STATE` to get offset to SystemNodeNonPagedPool
* with those offset, use the following command to list the NonPagedPool{First,Last}Va
* `dt (_MI_SYSTEM_NODE_NONPAGED_POOL*) (<nt!MiState> + <HARDWHARE_OFFSET> + <NODE_INFO_OFFSET>)`
* Sample output
*
* +0x000 DynamicBitMapNonPagedPool : _MI_DYNAMIC_BITMAP
* +0x048 CachedNonPagedPoolCount : 0
* +0x050 NonPagedPoolSpinLock : 0
* +0x058 CachedNonPagedPool : (null)
* +0x060 NonPagedPoolFirstVa : 0xffffe580`00000000 Void
* +0x068 NonPagedPoolLastVa : 0xfffff580`00000000 Void
* +0x070 SystemNodeInformation : 0xffffe58f`9283b050 _MI_SYSTEM_NODE_INFORMATION
*
* The big page pool is denoted by two variables `PoolBigPageTable.Va` and `PoolBigPageTableSize`
* It seems that this big page is inside NonPagedPool range
*
* PoolBigPageTable is an array with PoolBigPageTableSize elements, where
* each elements has:
* Va -> Address of the allocation
* Key -> Pool tag
* NumberOfBytes -> Size
*
**/
PVOID miState = (PVOID)((ULONG64)ntosbase + miStateOffset);
DbgPrint("[NAK] :: [ ] nt!MiState : 0x%p\n", miState);
PVOID systemNonPageInfo = nullptr;
ULONG64 nonPagedPoolStart = 0;
ULONG64 nonPagedPoolEnd = 0;
PVOID largePageTableArray = 0;
ULONG64 largePageTableSize = 0;
largePageTableArray = (PVOID)((ULONG64)ntosbase + largePageTableOffset);
largePageTableSize = *(ULONG64*)((ULONG64)ntosbase + largePageSizeOffset);
// TODO: Move this to front-end for portable update
// use defined formula by windows build number to get those two values
switch (windowsVersionByPool) {
case WINDOWS_2020_FASTRING:
systemNonPageInfo = (PVOID)*(ULONG64*)((ULONG64)miState + hardwareOffset + systemNodeOffset);
DbgPrint("[NAK] :: [ ] &systemNonPageInfo : 0x%p\n", systemNonPageInfo);
DbgPrint("[NAK] :: [ ] &NonPagedPoolFirstVa : 0x%p\n", (ULONG64*)((ULONG64)systemNonPageInfo + firstVaOffset));
DbgPrint("[NAK] :: [ ] &NonPagedPoolLastVa : 0x%p\n", (ULONG64*)((ULONG64)systemNonPageInfo + lastVaOffset));
nonPagedPoolStart = *(ULONG64*)((ULONG64)systemNonPageInfo + firstVaOffset);
nonPagedPoolEnd = *(ULONG64*)((ULONG64)systemNonPageInfo + lastVaOffset);
break;
default:
break;
}
DbgPrint("[NAK] :: [+] nonPagedPoolStart : 0x%llx\n", nonPagedPoolStart);
DbgPrint("[NAK] :: [+] nonPagedPoolEnd : 0x%llx\n", nonPagedPoolEnd);
DbgPrint("[NAK] :: [+] large page address : 0x%p\n", largePageTableArray);
DbgPrint("[NAK] :: [+] large page size : 0x%llx\n", largePageTableSize);
// scanNormalPool(nonPagedPoolStart, nonPagedPoolEnd);
// scanLargePool(largePageTableArray, largePageTableSize);
return returnStatus;
}
VOID
UnloadRoutine(_In_ PDRIVER_OBJECT DriverObject) {
PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject;
UNICODE_STRING uniWin32NameString;
PAGED_CODE();
RtlInitUnicodeString(&uniWin32NameString, DOS_DEVICE_NAME);
IoDeleteSymbolicLink(&uniWin32NameString);
if (deviceObject != nullptr) {
IoDeleteDevice(deviceObject);
}
DbgPrint("[NAK] :: [+] Goodbye from Kernel\n");
}
VOID
toPoolHeader(PPOOL_HEADER p, PVOID chunkAddr) {
p->addr = chunkAddr;
p->prevBlockSize = *(USHORT*)((ULONG64) chunkAddr + 0x0) & 0xff;
p->poolIndex = *(USHORT*)((ULONG64) chunkAddr + 0x0) >> 8;
p->blockSize = *(USHORT*)((ULONG64) chunkAddr + 0x2) & 0xff;
p->poolType = *(USHORT*)((ULONG64) chunkAddr + 0x2) >> 8;
p->tag = *(ULONG*)((ULONG64) chunkAddr + 0x4);
}
VOID
tryNextChunk(PPOOL_HEADER p) {
toPoolHeader(p, (PVOID)((ULONG64)p->addr + CHUNK_SIZE));
}
bool
validTag(PPOOL_HEADER p) {
// I know the compiler will optimize for me, so meeh :)
const char a = (char)(p->tag & 0xff);
const char b = (char)((p->tag & 0xff00) >> 8);
const char c = (char)((p->tag & 0xff0000) >> 16);
const char d = (char)(p->tag >> 24);
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-exallocatepoolwithtag
// > Each ASCII character in the tag must be a value in the range 0x20 (space) to 0x7E (tilde)
if (!(a >= 0x20 && a <= 0x7e) ||
!(b >= 0x20 && b <= 0x7e) ||
!(c >= 0x20 && c <= 0x7e) ||
!(d >= 0x20 && d <= 0x7e))
return false;
return true;
}
bool
validPool(PPOOL_HEADER p) {
// https://subs.emis.de/LNI/Proceedings/Proceedings97/GI-Proceedings-97-9.pdf
// long long int offsetInPage = (long long int)p->addr % PAGE_SIZE; // OffsetInPage = addr % pagesize
// (offsetInPage % CHUNK_SIZE == 0) && // rule 1
// (p->blockSize > 0) && // rule 2
// (p->blockSize * CHUNK_SIZE + offsetInPage == PAGE_SIZE) && // rule 3
// (p->prevBlockSize * CHUNK_SIZE <= offsetInPage) // rule 5
if ((p->blockSize * CHUNK_SIZE) < 0xb00 + 0x10 || // eprocess size + pool_header size
// p->poolType % 2 != 0 || // pool tag must be even number aka nonpaged
p->poolType != 2 // force to search for nonpaged pool only aka poolType == 2
)
return false;
return true;
}
VOID
printChunkInfo(PPOOL_HEADER p) {
DbgPrint("[NAK] :: [+] ==== PoolStart 0x%p ====\n", p->addr);
DbgPrint("[NAK] :: [|] \tPreviousSize : 0x%x\n", p->prevBlockSize);
DbgPrint("[NAK] :: [|] \tPoolIndex : 0x%x\n", p->poolIndex);
DbgPrint("[NAK] :: [|] \tBlockSize : 0x%x\n", p->blockSize * CHUNK_SIZE);
DbgPrint("[NAK] :: [|] \tPoolType : 0x%x\n", p->poolType);
DbgPrint("[NAK] :: [|] \tPoolTag : 0x%lx [%4s]\n", p->tag, p->tag);
DbgPrint("[NAK] :: [+] ==== PoolEnd 0x%p ====\n", p->addr);
}
VOID
scanNormalPool(ULONG64 nonPagedPoolStart, ULONG64 nonPagedPoolEnd) {
DbgPrint("[NAK] :: [+] Scanning\n");
/*
* The name nonpaged pool is quite misunderstanding,
* the correct definition of a nonpaged pool is a pool which remains on the nonpaged region
* nonpaged region is a range of address inside the kernel virtual address that has
* a correspoding page in the physical memory (RAM)
*
* Which is, if there is a **valid** page in nonpaged pool, there is a correspoding page in RAM
* The OS will allocate a page in this nonpaged region with a page in RAM when a new page
* is requested to be nonpaged and there is no space left in current allocated nonpaged region.
*
* That is, if the address lies in the nonpaged region but is not allocated yet to have a
* backed paged on RAM, then a bug check will occur. The name is `PAGE FAULT IN NONPAGED AREA`
*
**/
POOL_HEADER p;
PVOID eprocess = nullptr;
char eprocess_name[16] = {0}; // eprocess name is 15 bytes + 1 null
PVOID currentAddr = (PVOID)(nonPagedPoolStart);
while (true) {
if ((ULONG64)currentAddr >= nonPagedPoolEnd)
break;
/*
* BOOLEAN MmIsAddressValid(PVOID)
*
* Warning We do not recommend using this function.
*
* If no page fault would occur from reading or writing at the given virtual address,
* MmIsAddressValid returns TRUE.
*
* Even if MmIsAddressValid returns TRUE, accessing the address can cause page faults
* unless the memory has been locked down or the address **is a valid nonpaged pool address**.
*
* Well, we got a nonpaged pool address, so it is good
*
**/
if (!MmIsAddressValid(currentAddr)) {
// Because a chunk pool reside on a page, so we check on page alignment
currentAddr = (PVOID)((ULONG64)currentAddr + PAGE_SIZE);
continue;
}
// TODO: perform scan in one page, use BlockSize/PreviousBlockSize
toPoolHeader(&p, (PVOID)currentAddr);
currentAddr = (PVOID)((ULONG64)currentAddr + poolChunkSize);
if (p.tag == 0) continue;
if (!validTag(&p)) continue;
if (!validPool(&p)) continue;
if (p.tag != 'Proc' && p.tag != 'corP')
continue;
// TODO: Parse data as _EPROCESS
// The first Proc found seems to be the System _EPROCESS
// The offset of system's chunk to _EPROCESS is 0x40, size is ...
// but offset of other processes' chunk to _EPROCESS is 0x80, size is 0xe00
// TODO: search for CreateTime, this field must be in range [system startup time; now]
// this is resolved in frontend
printChunkInfo(&p);
if (p.blockSize * CHUNK_SIZE == 0xf00) {
eprocess = (PVOID)((ULONG64)p.addr + 0x40);
} else if (p.blockSize * CHUNK_SIZE == 0xd80) {
eprocess = (PVOID)((ULONG64)p.addr + 0x70);
} else if (p.blockSize * CHUNK_SIZE == 0xe00) {
eprocess = (PVOID)((ULONG64)p.addr + 0x80);
} else {
DbgPrint("[NAK] :: [ ] This is not a valid eprocess, maybe\n");
continue;
}
RtlStringCbCopyNA(eprocess_name, 16, (char*)((ULONG64)eprocess + eprocessNameOffset), 15);
DbgPrint("[NAK] :: [ ] eprocess offset 0x80 : 0x%p, [%s]\n", eprocess, eprocess_name);
}
DbgPrint("[NAK] :: [+] Finish scanning");
}
VOID
scanLargePool(PVOID /* largePageTableArray */, ULONG64 /* largePageTableSize */) {
DbgPrint("[NAK] :: [-] Scan large pool not supported yet");
}
PVOID
scanRemote(ULONG64 startAddress, ULONG64 endAddress, ULONG tag) {
POOL_HEADER p;
PVOID currentAddr = (PVOID)startAddress;
while (true) {
if ((ULONG64)currentAddr >= endAddress)
break;
if (!MmIsAddressValid(currentAddr)) {
currentAddr = (PVOID)((ULONG64)currentAddr + PAGE_SIZE);
continue;
}
toPoolHeader(&p, (PVOID)currentAddr);
currentAddr = (PVOID)((ULONG64)currentAddr + poolChunkSize);
if (p.tag == 0) continue;
if (!validTag(&p)) continue;
// if (!validPool(&p)) continue;
if (p.tag != tag)
continue;
return p.addr;
}
return (PVOID)endAddress;
}

54
lpus/Driver.h Normal file
View File

@ -0,0 +1,54 @@
#ifndef _DRIVER_H
#define _DRIVER_H
typedef struct _POOL_HEADER {
PVOID addr;
USHORT prevBlockSize;
USHORT poolIndex;
USHORT blockSize;
USHORT poolType;
ULONG tag;
} POOL_HEADER, *PPOOL_HEADER;
enum VERSION_BY_POOL {
WINDOWS_2018,
WINDOWS_2019,
WINDOWS_2020,
WINDOWS_2020_FASTRING,
WINDOWS_NOT_SUPPORTED
};
VOID
setup();
VOID
scan_ps_active_head();
VOID
toPoolHeader(PPOOL_HEADER p, PVOID chunkAddr);
VOID
tryNextChunk(PPOOL_HEADER p);
bool
validTag(PPOOL_HEADER p);
bool
validPool(PPOOL_HEADER p);
VOID
printChunkInfo(PPOOL_HEADER p);
VOID
scanNormalPool(ULONG64 nonPagedPoolStart, ULONG64 nonPagedPoolEnd);
VOID
scanLargePool(PVOID largePageTableArray, ULONG64 largePageTableSize);
PVOID
scanRemote(ULONG64 startAddress, ULONG64 endAddress, ULONG tag);
VOID
hideProcess(CHAR* name, ULONG64 size);
#endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 KiB

133
lpus/kernel-shellcode.cpp Normal file
View File

@ -0,0 +1,133 @@
#include <wdm.h>
__declspec(dllexport)
__declspec(noinline)
void*
GetNtoskrnlBaseAddress()
{
//
// From Windows Internals part 1, chapter 2:
//
// "The kernel uses a data structure called the processor control region, or KPCR, to store
// processor-specific data. The KPCR contains basic information such as the processor's interrupt
// dispatch table(IDT), task - state segment(TSS), and global descriptor table(GDT). It also includes the
// interrupt controller state, which it shares with other modules, such as the ACPI driver and the HAL. To
// provide easy access to the KPCR, the kernel stores a pointer to it in the fs register on 32-bit Windows
// and in the gs register on an x64 Windows system."
//
//
// Let's view the address of KPCR of the current processor:
//
// 1: kd> dg gs
// P Si Gr Pr Lo
// Sel Base Limit Type l ze an es ng Flags
// ---- ---------------- - ---------------- - ---------- - -- -- -- -- --------
// 002B ffffd001`1972e000 00000000`ffffffff Data RW Ac 3 Bg Pg P Nl 00000cf3
//
// We only care about one field in KPCR which is IdtBase (it has been always at the offset 0x38):
//
// 1: kd> dt nt!_KPCR 0xffffd001`1972e000
// + 0x000 NtTib : _NT_TIB
// + 0x000 GdtBase : 0xffffd001`1973b8c0 _KGDTENTRY64
// + 0x008 TssBase : 0xffffd001`19734b40 _KTSS64
// + 0x010 UserRsp : 0x000000c0`87cffc18
// + 0x018 Self : 0xffffd001`1972e000 _KPCR
// + 0x020 CurrentPrcb : 0xffffd001`1972e180 _KPRCB
// + 0x028 LockArray : 0xffffd001`1972e7f0 _KSPIN_LOCK_QUEUE
// + 0x030 Used_Self : 0x000000c0`86875000 Void
// + 0x038 IdtBase : 0xffffd001`1973b930 _KIDTENTRY64 <- pointer to the IDT array
// ...
//
// The field is a pointer to an array of interrupt service routines in the following format:
//
// 1: kd> dt nt!_KIDTENTRY64
// +0x000 OffsetLow : Uint2B
// +0x002 Selector : Uint2B
// +0x004 IstIndex : Pos 0, 3 Bits --+
// +0x004 Reserved0 : Pos 3, 5 Bits |
// +0x004 Type : Pos 8, 5 Bits |
// +0x004 Dpl : Pos 13, 2 Bits |-> the interrupt service routine as a bitfield
// +0x004 Present : Pos 15, 1 Bit |
// +0x006 OffsetMiddle : Uint2B |
// +0x008 OffsetHigh : Uint4B --+
// +0x00c Reserved1 : Uint4B
// +0x000 Alignment : Uint8B
//
//
// These interrupt service routines are functions defined within the address space of ntoskrnl.exe. We will
// use this fact for searching for the base address of ntoskrnl.exe.
//
// Ensure that the structure is aligned on 1 byte boundary.
#pragma pack(push, 1)
typedef struct
{
UCHAR Padding[4];
PVOID InterruptServiceRoutine;
} IDT_ENTRY;
#pragma pack(pop)
// Find the address of IdtBase using gs register.
const auto idt_base = reinterpret_cast<IDT_ENTRY *>(__readgsqword(0x38));
// Find the address of the first (or any) interrupt service routine.
const auto first_isr_address = idt_base[0].InterruptServiceRoutine;
// Align the address on page boundary.
auto page_within_ntoskrnl = reinterpret_cast<uintptr_t>(first_isr_address) & ~static_cast<uintptr_t>(0xfff);
// Traverse pages backward until we find the PE signature (MZ) of ntoskrnl.exe in the beginning of some page.
while (*reinterpret_cast<const USHORT *>(page_within_ntoskrnl) != 0x5a4d)
{
page_within_ntoskrnl -= 0x1000;
}
// Now we have the base address of ntoskrnl.exe
return reinterpret_cast<void*>(page_within_ntoskrnl);
}
VOID
DriverUnload(PDRIVER_OBJECT driver_object)
{
UNREFERENCED_PARAMETER(driver_object);
}
EXTERN_C
NTSTATUS
DriverEntry(PDRIVER_OBJECT driver_object, PUNICODE_STRING registry_path)
{
UNREFERENCED_PARAMETER(registry_path);
driver_object->DriverUnload = DriverUnload;
// 0 : 65 48 8b 04 25 38 00 mov rax, QWORD PTR gs : 0x38
// 7 : 00 00
// 9 : b9 4d 5a 00 00 mov ecx, 0x5a4d
// e : 48 8b 40 04 mov rax, QWORD PTR[rax + 0x4]
// 12: 48 25 00 f0 ff ff and rax, 0xfffffffffffff000
// 18: eb 06 jmp 0x20
// 1a: 48 2d 00 10 00 00 sub rax, 0x1000
// 20: 66 39 08 cmp WORD PTR[rax], cx
// 23: 75 f5 jne 0x1a
// 25: c3 ret
static const UCHAR shellcode[] = {
0x65, 0x48, 0x8B, 0x04, 0x25, 0x38, 0x00, 0x00, 0x00, 0xB9, 0x4D, 0x5A, 0x00, 0x00, 0x48, 0x8B,
0x40, 0x04, 0x48, 0x25, 0x00, 0xF0, 0xFF, 0xFF, 0xEB, 0x06, 0x48, 0x2D, 0x00, 0x10, 0x00, 0x00,
0x66, 0x39, 0x08, 0x75, 0xF5, 0xC3
};
const auto ntoskrnl_base_address = GetNtoskrnlBaseAddress();
const auto pool = ExAllocatePoolWithTag(NonPagedPoolExecute, sizeof(shellcode), 'KMSL');
if (pool != nullptr)
{
RtlCopyMemory(pool, shellcode, sizeof(shellcode));
const auto get_ntoskrnl_base_address = reinterpret_cast<void *(*)()>(pool);
ASSERT(get_ntoskrnl_base_address() == ntoskrnl_base_address);
ExFreePoolWithTag(pool, 'KMSL');
}
return STATUS_SUCCESS;
}

11
lpus/kpcr.asm Normal file
View File

@ -0,0 +1,11 @@
PUBLIC FindKdVersionBlock
.code _text
FindKdVersionBlock PROC PUBLIC
mov rax, gs:[108h]
ret
FindKdVersionBlock ENDP
END

86
lpus/lpus.inf Normal file
View File

@ -0,0 +1,86 @@
;
; lpus.inf
;
[Version]
Signature="$WINDOWS NT$"
Class=Sample ; TODO: edit Class
ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} ; TODO: edit ClassGuid
Provider=%ManufacturerName%
CatalogFile=lpus.cat
DriverVer= ; TODO: set DriverVer in stampinf property pages
[DestinationDirs]
DefaultDestDir = 12
lpus_Device_CoInstaller_CopyFiles = 11
; ================= Class section =====================
[ClassInstall32]
Addreg=SampleClassReg
[SampleClassReg]
HKR,,,0,%ClassName%
HKR,,Icon,,-5
[SourceDisksNames]
1 = %DiskName%,,,""
[SourceDisksFiles]
lpus.sys = 1,,
WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll=1 ; make sure the number matches with SourceDisksNames
;*****************************************
; Install Section
;*****************************************
[Manufacturer]
%ManufacturerName%=Standard,NT$ARCH$
[Standard.NT$ARCH$]
%lpus.DeviceDesc%=lpus_Device, Root\lpus ; TODO: edit hw-id
[lpus_Device.NT]
CopyFiles=Drivers_Dir
[Drivers_Dir]
lpus.sys
;-------------- Service installation
[lpus_Device.NT.Services]
AddService = lpus,%SPSVCINST_ASSOCSERVICE%, lpus_Service_Inst
; -------------- lpus driver install sections
[lpus_Service_Inst]
DisplayName = %lpus.SVCDESC%
ServiceType = 1 ; SERVICE_KERNEL_DRIVER
StartType = 3 ; SERVICE_DEMAND_START
ErrorControl = 1 ; SERVICE_ERROR_NORMAL
ServiceBinary = %12%\lpus.sys
;
;--- lpus_Device Coinstaller installation ------
;
[lpus_Device.NT.CoInstallers]
AddReg=lpus_Device_CoInstaller_AddReg
CopyFiles=lpus_Device_CoInstaller_CopyFiles
[lpus_Device_CoInstaller_AddReg]
HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller"
[lpus_Device_CoInstaller_CopyFiles]
WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll
[lpus_Device.NT.Wdf]
KmdfService = lpus, lpus_wdfsect
[lpus_wdfsect]
KmdfLibraryVersion = $KMDFVERSION$
[Strings]
SPSVCINST_ASSOCSERVICE= 0x00000002
ManufacturerName="<Your manufacturer name>" ;TODO: Replace with your manufacturer name
ClassName="Samples" ; TODO: edit ClassName
DiskName = "lpus Installation Disk"
lpus.DeviceDesc = "lpus Device"
lpus.SVCDESC = "lpus Service"

168
lpus/lpus.vcxproj Normal file
View File

@ -0,0 +1,168 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM">
<Configuration>Debug</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM">
<Configuration>Release</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{905D3C7D-3EAD-4977-975E-B1FFD3E6FBE4}</ProjectGuid>
<TemplateGuid>{1bc93793-694f-48fe-9372-81e2b05556fd}</TemplateGuid>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<MinimumVisualStudioVersion>12.0</MinimumVisualStudioVersion>
<Configuration>Debug</Configuration>
<Platform Condition="'$(Platform)' == ''">Win32</Platform>
<RootNamespace>lpus</RootNamespace>
<ProjectName>lpus</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<TargetVersion>Windows10</TargetVersion>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
<ConfigurationType>Driver</ConfigurationType>
<DriverType>KMDF</DriverType>
<DriverTargetPlatform>Universal</DriverTargetPlatform>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<TargetVersion>Windows10</TargetVersion>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
<ConfigurationType>Driver</ConfigurationType>
<DriverType>KMDF</DriverType>
<DriverTargetPlatform>Universal</DriverTargetPlatform>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<TargetVersion>Windows10</TargetVersion>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
<ConfigurationType>Driver</ConfigurationType>
<DriverType>KMDF</DriverType>
<DriverTargetPlatform>Universal</DriverTargetPlatform>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<TargetVersion>Windows10</TargetVersion>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
<ConfigurationType>Driver</ConfigurationType>
<DriverType>KMDF</DriverType>
<DriverTargetPlatform>Universal</DriverTargetPlatform>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
<TargetVersion>Windows10</TargetVersion>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
<ConfigurationType>Driver</ConfigurationType>
<DriverType>KMDF</DriverType>
<DriverTargetPlatform>Universal</DriverTargetPlatform>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
<TargetVersion>Windows10</TargetVersion>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
<ConfigurationType>Driver</ConfigurationType>
<DriverType>KMDF</DriverType>
<DriverTargetPlatform>Universal</DriverTargetPlatform>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
<TargetVersion>Windows10</TargetVersion>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
<ConfigurationType>Driver</ConfigurationType>
<DriverType>KMDF</DriverType>
<DriverTargetPlatform>Universal</DriverTargetPlatform>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
<TargetVersion>Windows10</TargetVersion>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
<ConfigurationType>Driver</ConfigurationType>
<DriverType>KMDF</DriverType>
<DriverTargetPlatform>Universal</DriverTargetPlatform>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
<Inf2CatUseLocalTime>true</Inf2CatUseLocalTime>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Link>
<AdditionalDependencies>$(DDK_LIB_PATH)\netio.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<Inf Include="lpus.inf" />
</ItemGroup>
<ItemGroup>
<FilesToPackage Include="$(TargetPath)" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="Driver.cpp" />
<ClCompile Include="simplewsk.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Driver.h" />
<ClInclude Include="simplewsk.h" />
<ClInclude Include="sioctl.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

45
lpus/lpus.vcxproj.filters Normal file
View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Driver Files">
<UniqueIdentifier>{8E41214B-6785-4CFE-B992-037D68949A14}</UniqueIdentifier>
<Extensions>inf;inv;inx;mof;mc;</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<Inf Include="lpus.inf">
<Filter>Driver Files</Filter>
</Inf>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Driver.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="simplewsk.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="sioctl.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Driver.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="simplewsk.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

53
lpus/note.md Normal file
View File

@ -0,0 +1,53 @@
Scanning the memory is not working well, we go with Pool tag quick scanning
[address in kernel space](https://www.codemachine.com/article_x64kvas.html)
find `MmNonPagedPoolStart` and `MmNonPagedPoolEnd` values in kernel variable.
These two variables located inside `KdDebuggerDataBlock` of type `_KDDEBUGGER_DATA64`. `KdDebuggerDataBlock` can be found somewhere in `KdVersionBlock`. `KdVersionBlock` is a member of `KPCR`. `KPCR` pointer can be get through `gs:[0x0]`
> Unfortunately this method stopped working in recent versions of Windows. Recently the KdVersionBlock member is always 0 and does not link to the kernel debugger block.
[kdbg.c](https://raw.githubusercontent.com/libvmi/libvmi/master/libvmi/os/windows/kdbg.c)
[KPCR at gs:[0x0]](https://sizzop.github.io/2016/07/07/kernel-hacking-with-hevd-part-3.html)
[finding kdbg](http://scudette.blogspot.com/2012/11/finding-kernel-debugger-block.html)
[finding kernel variables](http://moyix.blogspot.com/2008/04/finding-kernel-global-variables-in.html)
[get kernel shellcode](https://github.com/FuzzySecurity/PSKernel-Primitives/blob/master/Get-KernelShellCode.ps1)
[www.rootkit.com artifacts](https://github.com/fdiskyou/www.rootkit.com)
- GetVarXP.pdf
[ghidra on fs/gs and kdbg](https://github.com/NationalSecurityAgency/ghidra/issues/1339)
[big ram kdbg](https://laserkittens.com/big-ram-kernel-debugger-data-block/)
[](blackstormsecurity.com/docs/NO_HAT_2019.pdf)
> KPCR -> KdVersionBlock -> `_DBGKD_GET_VERSION64` -> `LIST_ENTRY _KDDEBUGGER_DATA64` (`GetDebuggerData()`) -> `_KDDEBUGGER_DATA64 KdDebuggerDataBlock` -> kernel variables
> `_KPCR gs:[0]` -> `_DBGKD_GET_VERSION64 KdVersionBlock` -> `PLIST_ENTRY DebuggerDataList` -> `PLIST_ENTRY Flink` -> `Debugger block`
This only works with windows x86, x64 Windows KdVersionBlock is always null.
[KdVersionBlock](https://web.archive.org/web/20061110120809/http://www.rootkit.com/newsread.php?newsid=153)
```
_DBGKD_GET_VERSION64* KdVersionBlock;
__asm {
mov eax, gs:[0x108]
mov KdVersionBlock, eax
}
PLIST_ENTRY dbglist = KdVersionBlock->DebuggerDataList;
DebuggerBlock dbgBlock = (DebuggerBlock)*(dbglist->Flink);
```
`AuxKlibQueryModuleInformation` to get all `PsActiveProcessModules`
[Sample](https://correy.webs.com/articles/computer/c/AuxKlibQueryModuleInformation.C.txt)

209
lpus/peformat.h Normal file
View File

@ -0,0 +1,209 @@
// Copyright Ric Vieler, 2006
// Support header for hookManager.c
// Contains required PE file format data structures used by GetFunctionAddress()
#ifndef _PE_FORMAT_HEADER_
#define _PE_FORMAT_HEADER_
typedef unsigned short WORD;
typedef unsigned long DWORD;
typedef long LONG;
typedef unsigned char BYTE;
typedef unsigned long ULONG;
typedef unsigned short USHORT;
typedef unsigned char UCHAR;
typedef unsigned __int64 ULONGLONG;
//
// Image Format
//
#define IMAGE_DOS_SIGNATURE 0x5A4D // MZ
#define IMAGE_NT_SIGNATURE 0x00004550 // PE00
typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header
WORD e_magic; // Magic number
WORD e_cblp; // Bytes on last page of file
WORD e_cp; // Pages in file
WORD e_crlc; // Relocations
WORD e_cparhdr; // Size of header in paragraphs
WORD e_minalloc; // Minimum extra paragraphs needed
WORD e_maxalloc; // Maximum extra paragraphs needed
WORD e_ss; // Initial (relative) SS value
WORD e_sp; // Initial SP value
WORD e_csum; // Checksum
WORD e_ip; // Initial IP value
WORD e_cs; // Initial (relative) CS value
WORD e_lfarlc; // File address of relocation table
WORD e_ovno; // Overlay number
WORD e_res[4]; // Reserved words
WORD e_oemid; // OEM identifier (for e_oeminfo)
WORD e_oeminfo; // OEM information; e_oemid specific
WORD e_res2[10]; // Reserved words
LONG e_lfanew; // File address of new exe header
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
//
// File header format.
//
typedef struct _IMAGE_FILE_HEADER {
WORD Machine;
WORD NumberOfSections;
DWORD TimeDateStamp;
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader;
WORD Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
//
// Directory format.
//
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
//
// Optional header format.
//
typedef struct _IMAGE_OPTIONAL_HEADER {
//
// Standard fields.
//
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
DWORD BaseOfData;
//
// NT additional fields.
//
DWORD ImageBase;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
DWORD SizeOfStackReserve;
DWORD SizeOfStackCommit;
DWORD SizeOfHeapReserve;
DWORD SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER;
typedef struct _IMAGE_OPTIONAL_HEADER64 {
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
ULONGLONG ImageBase;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
ULONGLONG SizeOfStackReserve;
ULONGLONG SizeOfStackCommit;
ULONGLONG SizeOfHeapReserve;
ULONGLONG SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;
typedef struct _IMAGE_NT_HEADERS {
ULONG Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
typedef struct _IMAGE_NT_HEADER64 {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER64 OptionalHeader;
} IMAGE_NT_HEADER64, *PIMAGE_NT_HEADER64;
#define IMAGE_SIZEOF_SHORT_NAME 8
typedef struct _IMAGE_SECTION_HEADER {
UCHAR Name[IMAGE_SIZEOF_SHORT_NAME];
union {
ULONG PhysicalAddress;
ULONG VirtualSize;
} Misc;
ULONG VirtualAddress;
ULONG SizeOfRawData;
ULONG PointerToRawData;
ULONG PointerToRelocations;
ULONG PointerToLinenumbers;
USHORT NumberOfRelocations;
USHORT NumberOfLinenumbers;
ULONG Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
//
// Export Format
//
typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD Name;
DWORD Base;
DWORD NumberOfFunctions;
DWORD NumberOfNames;
DWORD AddressOfFunctions; // RVA from base of image
DWORD AddressOfNames; // RVA from base of image
DWORD AddressOfNameOrdinals; // RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
// Directory Entries
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory
#endif

479
lpus/simplewsk.c Normal file
View File

@ -0,0 +1,479 @@
/*++
Module Name:
simplewsk.c
Abstract:
Wrapper library for WSK functions
Author:
MaD, 12-May-2009
--*/
#include "simplewsk.h"
static WSK_REGISTRATION g_WskRegistration;
static WSK_PROVIDER_NPI g_WskProvider;
static WSK_CLIENT_DISPATCH g_WskDispatch = {MAKE_WSK_VERSION(1, 0), 0, NULL};
enum { DEINITIALIZED, DEINITIALIZING, INITIALIZING, INITIALIZED };
static LONG g_SocketsState = DEINITIALIZED;
static NTSTATUS NTAPI CompletionRoutine(__in PDEVICE_OBJECT DeviceObject,
__in PIRP Irp,
__in PKEVENT CompletionEvent) {
ASSERT(CompletionEvent);
UNREFERENCED_PARAMETER(Irp);
UNREFERENCED_PARAMETER(DeviceObject);
KeSetEvent(CompletionEvent, IO_NO_INCREMENT, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
static NTSTATUS InitWskData(__out PIRP* pIrp, __out PKEVENT CompletionEvent) {
ASSERT(pIrp);
ASSERT(CompletionEvent);
*pIrp = IoAllocateIrp(1, FALSE);
if (!*pIrp) {
KdPrint(("InitWskData(): IoAllocateIrp() failed\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
KeInitializeEvent(CompletionEvent, SynchronizationEvent, FALSE);
IoSetCompletionRoutine(*pIrp, CompletionRoutine, CompletionEvent, TRUE, TRUE,
TRUE);
return STATUS_SUCCESS;
}
static NTSTATUS InitWskBuffer(__in PVOID Buffer, __in ULONG BufferSize,
__out PWSK_BUF WskBuffer) {
NTSTATUS Status = STATUS_SUCCESS;
ASSERT(Buffer);
ASSERT(BufferSize);
ASSERT(WskBuffer);
WskBuffer->Offset = 0;
WskBuffer->Length = BufferSize;
WskBuffer->Mdl = IoAllocateMdl(Buffer, BufferSize, FALSE, FALSE, NULL);
if (!WskBuffer->Mdl) {
KdPrint(("InitWskBuffer(): IoAllocateMdl() failed\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
__try {
MmProbeAndLockPages(WskBuffer->Mdl, KernelMode, IoWriteAccess);
} __except (EXCEPTION_EXECUTE_HANDLER) {
KdPrint(("InitWskBuffer(): MmProbeAndLockPages(%p) failed\n", Buffer));
IoFreeMdl(WskBuffer->Mdl);
Status = STATUS_ACCESS_VIOLATION;
}
return Status;
}
static VOID FreeWskBuffer(__in PWSK_BUF WskBuffer) {
ASSERT(WskBuffer);
MmUnlockPages(WskBuffer->Mdl);
IoFreeMdl(WskBuffer->Mdl);
}
//
// Library initialization routine
//
NTSTATUS NTAPI WSKStartup() {
WSK_CLIENT_NPI WskClient = {0};
NTSTATUS Status = STATUS_UNSUCCESSFUL;
if (InterlockedCompareExchange(&g_SocketsState, INITIALIZING,
DEINITIALIZED) != DEINITIALIZED)
return STATUS_ALREADY_REGISTERED;
WskClient.ClientContext = NULL;
WskClient.Dispatch = &g_WskDispatch;
Status = WskRegister(&WskClient, &g_WskRegistration);
if (!NT_SUCCESS(Status)) {
KdPrint(("WskRegister() failed with status 0x%08X\n", Status));
InterlockedExchange(&g_SocketsState, DEINITIALIZED);
return Status;
}
Status =
WskCaptureProviderNPI(&g_WskRegistration, WSK_NO_WAIT, &g_WskProvider);
if (!NT_SUCCESS(Status)) {
KdPrint(("WskCaptureProviderNPI() failed with status 0x%08X\n", Status));
WskDeregister(&g_WskRegistration);
InterlockedExchange(&g_SocketsState, DEINITIALIZED);
return Status;
}
InterlockedExchange(&g_SocketsState, INITIALIZED);
return STATUS_SUCCESS;
}
//
// Library deinitialization routine
//
VOID NTAPI WSKCleanup() {
if (InterlockedCompareExchange(&g_SocketsState, INITIALIZED,
DEINITIALIZING) != INITIALIZED)
return;
WskReleaseProviderNPI(&g_WskRegistration);
WskDeregister(&g_WskRegistration);
InterlockedExchange(&g_SocketsState, DEINITIALIZED);
}
PWSK_SOCKET
NTAPI
CreateSocket(__in ADDRESS_FAMILY AddressFamily, __in USHORT SocketType,
__in ULONG Protocol, __in ULONG Flags) {
KEVENT CompletionEvent = {0};
PIRP Irp = NULL;
PWSK_SOCKET WskSocket = NULL;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
if (g_SocketsState != INITIALIZED) return NULL;
Status = InitWskData(&Irp, &CompletionEvent);
if (!NT_SUCCESS(Status)) {
KdPrint(
("CreateSocket(): InitWskData() failed with status 0x%08X\n", Status));
return NULL;
}
Status = g_WskProvider.Dispatch->WskSocket(
g_WskProvider.Client, AddressFamily, SocketType, Protocol, Flags, NULL,
NULL, NULL, NULL, NULL, Irp);
if (Status == STATUS_PENDING) {
KeWaitForSingleObject(&CompletionEvent, Executive, KernelMode, FALSE, NULL);
Status = Irp->IoStatus.Status;
}
WskSocket =
NT_SUCCESS(Status) ? (PWSK_SOCKET)Irp->IoStatus.Information : NULL;
IoFreeIrp(Irp);
return (PWSK_SOCKET)WskSocket;
}
NTSTATUS
NTAPI
CloseSocket(__in PWSK_SOCKET WskSocket) {
KEVENT CompletionEvent = {0};
PIRP Irp = NULL;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
if (g_SocketsState != INITIALIZED || !WskSocket)
return STATUS_INVALID_PARAMETER;
Status = InitWskData(&Irp, &CompletionEvent);
if (!NT_SUCCESS(Status)) {
KdPrint(
("CloseSocket(): InitWskData() failed with status 0x%08X\n", Status));
return Status;
}
Status = ((PWSK_PROVIDER_BASIC_DISPATCH)WskSocket->Dispatch)
->WskCloseSocket(WskSocket, Irp);
if (Status == STATUS_PENDING) {
KeWaitForSingleObject(&CompletionEvent, Executive, KernelMode, FALSE, NULL);
Status = Irp->IoStatus.Status;
}
IoFreeIrp(Irp);
return Status;
}
NTSTATUS
NTAPI
Connect(__in PWSK_SOCKET WskSocket, __in PSOCKADDR RemoteAddress) {
KEVENT CompletionEvent = {0};
PIRP Irp = NULL;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
if (g_SocketsState != INITIALIZED || !WskSocket || !RemoteAddress)
return STATUS_INVALID_PARAMETER;
Status = InitWskData(&Irp, &CompletionEvent);
if (!NT_SUCCESS(Status)) {
KdPrint(("Connect(): InitWskData() failed with status 0x%08X\n", Status));
return Status;
}
Status = ((PWSK_PROVIDER_CONNECTION_DISPATCH)WskSocket->Dispatch)
->WskConnect(WskSocket, RemoteAddress, 0, Irp);
if (Status == STATUS_PENDING) {
KeWaitForSingleObject(&CompletionEvent, Executive, KernelMode, FALSE, NULL);
Status = Irp->IoStatus.Status;
}
IoFreeIrp(Irp);
return Status;
}
PWSK_SOCKET
NTAPI
SocketConnect(__in USHORT SocketType, __in ULONG Protocol,
__in PSOCKADDR RemoteAddress, __in PSOCKADDR LocalAddress) {
KEVENT CompletionEvent = {0};
PIRP Irp = NULL;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
PWSK_SOCKET WskSocket = NULL;
if (g_SocketsState != INITIALIZED || !RemoteAddress || !LocalAddress)
return NULL;
Status = InitWskData(&Irp, &CompletionEvent);
if (!NT_SUCCESS(Status)) {
KdPrint(("InitWskData() failed with status 0x%08X\n", Status));
return NULL;
}
Status = g_WskProvider.Dispatch->WskSocketConnect(
g_WskProvider.Client, SocketType, Protocol, LocalAddress, RemoteAddress,
0, NULL, NULL, NULL, NULL, NULL, Irp);
if (Status == STATUS_PENDING) {
KeWaitForSingleObject(&CompletionEvent, Executive, KernelMode, FALSE, NULL);
Status = Irp->IoStatus.Status;
}
WskSocket =
NT_SUCCESS(Status) ? (PWSK_SOCKET)Irp->IoStatus.Information : NULL;
IoFreeIrp(Irp);
return WskSocket;
}
LONG NTAPI Send(__in PWSK_SOCKET WskSocket, __in PVOID Buffer,
__in ULONG BufferSize, __in ULONG Flags) {
KEVENT CompletionEvent = {0};
PIRP Irp = NULL;
WSK_BUF WskBuffer = {0};
LONG BytesSent = SOCKET_ERROR;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
if (g_SocketsState != INITIALIZED || !WskSocket || !Buffer || !BufferSize)
return SOCKET_ERROR;
Status = InitWskBuffer(Buffer, BufferSize, &WskBuffer);
if (!NT_SUCCESS(Status)) {
KdPrint(("Send(): InitWskData() failed with status 0x%08X\n", Status));
return SOCKET_ERROR;
}
Status = InitWskData(&Irp, &CompletionEvent);
if (!NT_SUCCESS(Status)) {
KdPrint(("Send(): InitWskData() failed with status 0x%08X\n", Status));
FreeWskBuffer(&WskBuffer);
return SOCKET_ERROR;
}
Status = ((PWSK_PROVIDER_CONNECTION_DISPATCH)WskSocket->Dispatch)
->WskSend(WskSocket, &WskBuffer, Flags, Irp);
if (Status == STATUS_PENDING) {
KeWaitForSingleObject(&CompletionEvent, Executive, KernelMode, FALSE, NULL);
Status = Irp->IoStatus.Status;
}
BytesSent =
NT_SUCCESS(Status) ? (LONG)Irp->IoStatus.Information : SOCKET_ERROR;
IoFreeIrp(Irp);
FreeWskBuffer(&WskBuffer);
return BytesSent;
}
LONG NTAPI SendTo(__in PWSK_SOCKET WskSocket, __in PVOID Buffer,
__in ULONG BufferSize, __in_opt PSOCKADDR RemoteAddress) {
KEVENT CompletionEvent = {0};
PIRP Irp = NULL;
WSK_BUF WskBuffer = {0};
LONG BytesSent = SOCKET_ERROR;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
if (g_SocketsState != INITIALIZED || !WskSocket || !Buffer || !BufferSize)
return SOCKET_ERROR;
Status = InitWskBuffer(Buffer, BufferSize, &WskBuffer);
if (!NT_SUCCESS(Status)) {
KdPrint(("SendTo(): InitWskData() failed with status 0x%08X\n", Status));
return SOCKET_ERROR;
}
Status = InitWskData(&Irp, &CompletionEvent);
if (!NT_SUCCESS(Status)) {
KdPrint(("SendTo(): InitWskData() failed with status 0x%08X\n", Status));
FreeWskBuffer(&WskBuffer);
return SOCKET_ERROR;
}
Status =
((PWSK_PROVIDER_DATAGRAM_DISPATCH)WskSocket->Dispatch)
->WskSendTo(WskSocket, &WskBuffer, 0, RemoteAddress, 0, NULL, Irp);
if (Status == STATUS_PENDING) {
KeWaitForSingleObject(&CompletionEvent, Executive, KernelMode, FALSE, NULL);
Status = Irp->IoStatus.Status;
}
BytesSent =
NT_SUCCESS(Status) ? (LONG)Irp->IoStatus.Information : SOCKET_ERROR;
IoFreeIrp(Irp);
FreeWskBuffer(&WskBuffer);
return BytesSent;
}
LONG NTAPI Receive(__in PWSK_SOCKET WskSocket, __out PVOID Buffer,
__in ULONG BufferSize, __in ULONG Flags) {
KEVENT CompletionEvent = {0};
PIRP Irp = NULL;
WSK_BUF WskBuffer = {0};
LONG BytesReceived = SOCKET_ERROR;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
if (g_SocketsState != INITIALIZED || !WskSocket || !Buffer || !BufferSize)
return SOCKET_ERROR;
Status = InitWskBuffer(Buffer, BufferSize, &WskBuffer);
if (!NT_SUCCESS(Status)) {
KdPrint(("Receive(): InitWskData() failed with status 0x%08X\n", Status));
return SOCKET_ERROR;
}
Status = InitWskData(&Irp, &CompletionEvent);
if (!NT_SUCCESS(Status)) {
KdPrint(("Receive(): InitWskData() failed with status 0x%08X\n", Status));
FreeWskBuffer(&WskBuffer);
return SOCKET_ERROR;
}
Status = ((PWSK_PROVIDER_CONNECTION_DISPATCH)WskSocket->Dispatch)
->WskReceive(WskSocket, &WskBuffer, Flags, Irp);
if (Status == STATUS_PENDING) {
KeWaitForSingleObject(&CompletionEvent, Executive, KernelMode, FALSE, NULL);
Status = Irp->IoStatus.Status;
}
BytesReceived =
NT_SUCCESS(Status) ? (LONG)Irp->IoStatus.Information : SOCKET_ERROR;
IoFreeIrp(Irp);
FreeWskBuffer(&WskBuffer);
return BytesReceived;
}
LONG NTAPI ReceiveFrom(__in PWSK_SOCKET WskSocket, __out PVOID Buffer,
__in ULONG BufferSize, __out_opt PSOCKADDR RemoteAddress,
__out_opt PULONG ControlFlags) {
KEVENT CompletionEvent = {0};
PIRP Irp = NULL;
WSK_BUF WskBuffer = {0};
LONG BytesReceived = SOCKET_ERROR;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
if (g_SocketsState != INITIALIZED || !WskSocket || !Buffer || !BufferSize)
return SOCKET_ERROR;
Status = InitWskBuffer(Buffer, BufferSize, &WskBuffer);
if (!NT_SUCCESS(Status)) {
KdPrint(
("ReceiveFrom(): InitWskData() failed with status 0x%08X\n", Status));
return SOCKET_ERROR;
}
Status = InitWskData(&Irp, &CompletionEvent);
if (!NT_SUCCESS(Status)) {
KdPrint(
("ReceiveFrom(): InitWskData() failed with status 0x%08X\n", Status));
FreeWskBuffer(&WskBuffer);
return SOCKET_ERROR;
}
Status = ((PWSK_PROVIDER_DATAGRAM_DISPATCH)WskSocket->Dispatch)
->WskReceiveFrom(WskSocket, &WskBuffer, 0, RemoteAddress, 0,
NULL, ControlFlags, Irp);
if (Status == STATUS_PENDING) {
KeWaitForSingleObject(&CompletionEvent, Executive, KernelMode, FALSE, NULL);
Status = Irp->IoStatus.Status;
}
BytesReceived =
NT_SUCCESS(Status) ? (LONG)Irp->IoStatus.Information : SOCKET_ERROR;
IoFreeIrp(Irp);
FreeWskBuffer(&WskBuffer);
return BytesReceived;
}
NTSTATUS
NTAPI
Bind(__in PWSK_SOCKET WskSocket, __in PSOCKADDR LocalAddress) {
KEVENT CompletionEvent = {0};
PIRP Irp = NULL;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
if (g_SocketsState != INITIALIZED || !WskSocket || !LocalAddress)
return STATUS_INVALID_PARAMETER;
Status = InitWskData(&Irp, &CompletionEvent);
if (!NT_SUCCESS(Status)) {
KdPrint(("Bind(): InitWskData() failed with status 0x%08X\n", Status));
return Status;
}
Status = ((PWSK_PROVIDER_CONNECTION_DISPATCH)WskSocket->Dispatch)
->WskBind(WskSocket, LocalAddress, 0, Irp);
if (Status == STATUS_PENDING) {
KeWaitForSingleObject(&CompletionEvent, Executive, KernelMode, FALSE, NULL);
Status = Irp->IoStatus.Status;
}
IoFreeIrp(Irp);
return Status;
}
PWSK_SOCKET
NTAPI
Accept(__in PWSK_SOCKET WskSocket, __out_opt PSOCKADDR LocalAddress,
__out_opt PSOCKADDR RemoteAddress) {
KEVENT CompletionEvent = {0};
PIRP Irp = NULL;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
PWSK_SOCKET AcceptedSocket = NULL;
if (g_SocketsState != INITIALIZED || !WskSocket) return NULL;
Status = InitWskData(&Irp, &CompletionEvent);
if (!NT_SUCCESS(Status)) {
KdPrint(("Accept(): InitWskData() failed with status 0x%08X\n", Status));
return NULL;
}
Status = ((PWSK_PROVIDER_LISTEN_DISPATCH)WskSocket->Dispatch)
->WskAccept(WskSocket, 0, NULL, NULL, LocalAddress,
RemoteAddress, Irp);
if (Status == STATUS_PENDING) {
KeWaitForSingleObject(&CompletionEvent, Executive, KernelMode, FALSE, NULL);
Status = Irp->IoStatus.Status;
}
AcceptedSocket =
NT_SUCCESS(Status) ? (PWSK_SOCKET)Irp->IoStatus.Information : NULL;
IoFreeIrp(Irp);
return AcceptedSocket;
}

55
lpus/simplewsk.h Normal file
View File

@ -0,0 +1,55 @@
#pragma warning(push)
#pragma warning(disable : 4201) // nameless struct/union
#pragma warning(disable : 4214) // bit field types other than int
#pragma once
#include <ntddk.h>
#include <wsk.h>
#pragma warning(pop)
#define SOCKET_ERROR -1
NTSTATUS NTAPI WSKStartup();
VOID NTAPI WSKCleanup();
PWSK_SOCKET
NTAPI
CreateSocket(__in ADDRESS_FAMILY AddressFamily, __in USHORT SocketType,
__in ULONG Protocol, __in ULONG Flags);
NTSTATUS
NTAPI
CloseSocket(__in PWSK_SOCKET WskSocket);
NTSTATUS
NTAPI
Connect(__in PWSK_SOCKET WskSocket, __in PSOCKADDR RemoteAddress);
PWSK_SOCKET
NTAPI
SocketConnect(__in USHORT SocketType, __in ULONG Protocol,
__in PSOCKADDR RemoteAddress, __in PSOCKADDR LocalAddress);
LONG NTAPI Send(__in PWSK_SOCKET WskSocket, __in PVOID Buffer,
__in ULONG BufferSize, __in ULONG Flags);
LONG NTAPI SendTo(__in PWSK_SOCKET WskSocket, __in PVOID Buffer,
__in ULONG BufferSize, __in_opt PSOCKADDR RemoteAddress);
LONG NTAPI Receive(__in PWSK_SOCKET WskSocket, __out PVOID Buffer,
__in ULONG BufferSize, __in ULONG Flags);
LONG NTAPI ReceiveFrom(__in PWSK_SOCKET WskSocket, __out PVOID Buffer,
__in ULONG BufferSize, __out_opt PSOCKADDR RemoteAddress,
__out_opt PULONG ControlFlags);
NTSTATUS
NTAPI
Bind(__in PWSK_SOCKET WskSocket, __in PSOCKADDR LocalAddress);
PWSK_SOCKET
NTAPI
Accept(__in PWSK_SOCKET WskSocket, __out_opt PSOCKADDR LocalAddress,
__out_opt PSOCKADDR RemoteAddress);

103
lpus/sioctl.h Normal file
View File

@ -0,0 +1,103 @@
/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
SIOCTL.H
Abstract:
Defines the IOCTL codes that will be used by this driver. The IOCTL code
contains a command identifier, plus other information about the device,
the type of access with which the file must have been opened,
and the type of buffering.
Environment:
Kernel mode only.
--*/
#ifndef _IOCTL_PROTOCOL_H
#define _IOCTL_PROTOCOL_H
// Device type
#define SIOCTL_TYPE 40000 // 32768 to 65535
// The IOCTL function codes from 0x800 to 0xFFF are for customer use.
#define IOCTL_SETUP_OFFSETS \
CTL_CODE(SIOCTL_TYPE, 0x900, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
#define GET_KERNEL_BASE \
CTL_CODE(SIOCTL_TYPE, 0x901, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
#define SCAN_PS_ACTIVE_HEAD \
CTL_CODE(SIOCTL_TYPE, 0x902, METHOD_NEITHER, FILE_ANY_ACCESS)
#define SCAN_POOL \
CTL_CODE(SIOCTL_TYPE, 0x903, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
#define SCAN_POOL_REMOTE \
CTL_CODE(SIOCTL_TYPE, 0x904, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
#define DEREFERENCE_ADDRESS \
CTL_CODE(SIOCTL_TYPE, 0xA00, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
#define HIDE_PROCESS_BY_NAME \
CTL_CODE(SIOCTL_TYPE, 0xA01, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
#define DRIVER_FUNC_INSTALL 0x01
#define DRIVER_FUNC_REMOVE 0x02
#define DRIVER_NAME "poolscanner"
typedef struct _OFFSET_VALUE {
ULONG64 eprocessNameOffset;
ULONG64 eprocessLinkOffset;
ULONG64 listBLinkOffset;
ULONG64 processHeadOffset;
ULONG64 miStateOffset;
ULONG64 hardwareOffset;
ULONG64 systemNodeOffset;
ULONG64 firstVaOffset;
ULONG64 lastVaOffset;
ULONG64 largePageTableOffset;
ULONG64 largePageSizeOffset;
ULONG64 poolChunkSize;
} OFFSET_VALUES, *POFFSET_VALUE;
typedef struct _DEREF_ADDR {
ULONG64 addr;
ULONG64 size; // bytes
} DEREF_ADDR, *PDEREF_ADDR;
typedef struct _SCAN_RANGE {
ULONG64 start;
ULONG64 end;
ULONG tag;
} SCAN_RANGE, *PSCAN_RANGE;
typedef struct _HIDE_PROCESS {
CHAR name[15];
ULONG64 size;
} HIDE_PROCESS, *PHIDE_PROCESS;
typedef union _INPUT_DATA {
OFFSET_VALUES offsetValues;
DEREF_ADDR derefAddr;
SCAN_RANGE scanRange;
HIDE_PROCESS processHide;
} INPUT_DATA, *PINPUT_DATA;
typedef struct _POOL_CHUNK {
ULONG64 addr;
} POOL_CHUNK, *PPOOL_CHUNK;
typedef union _OUTPUT_DATA {
ULONG64 ulong64Value; // for gereral addresses, value fit in 64 bit
POOL_CHUNK poolChunk;
} OUTPUT_DATA, *POUTPUT_DATA;
#endif