add simple valid pool chunk check

This commit is contained in:
2020-02-23 03:33:45 +07:00
parent 949507ba16
commit 2eb04827be
3 changed files with 735 additions and 21 deletions

View File

@ -1,6 +1,7 @@
#include <ntddk.h>
#include <wdf.h>
#include <ntdef.h>
#include <ntstrsafe.h>
#include "sioctl.h"
#include "Driver.h"
@ -21,6 +22,19 @@ extern "C" DRIVER_UNLOAD UnloadRoutine;
#define CHUNK_SIZE 16 // 64 bit
// #define PAGE_SIZE 4096 // 4KB
// 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;
NTSTATUS
DriverEntry(
_In_ PDRIVER_OBJECT DriverObject,
@ -69,18 +83,9 @@ DriverEntry(
// https://en.wikipedia.org/wiki/Windows_10_version_history
VERSION_BY_POOL windowsVersionByPool = WINDOWS_NOT_SUPPORTED;
// TODO: automatically get from parsed 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;
// setup offset
// 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;
@ -105,6 +110,8 @@ DriverEntry(
systemNodeOffset = 0x20;
firstVaOffset = 0x60;
lastVaOffset = 0x68;
largePageTableOffset = 0xc17ed8;
largePageSizeOffset = 0xc17ed0;
}
if (windowsVersionByPool == WINDOWS_NOT_SUPPORTED) {
@ -138,12 +145,18 @@ DriverEntry(
// TODO: Exception?????
PVOID eprocess = (PVOID)IoGetCurrentProcess();
DbgPrint("[NAK] :: [ ] eprocess : 0x%p, [%15s]\n", eprocess, (char*)((ULONG64)eprocess + eprocessNameOffset));
DbgPrint("[NAK] :: [ ] System eprocess : 0x%p, [%15s]\n", eprocess, (char*)((ULONG64)eprocess + eprocessNameOffset));
PVOID processHead = (PVOID)(*(ULONG64*)((ULONG64)eprocess + eprocessLinkOffset + listBLinkOffset));
DbgPrint("[NAK] :: [ ] PsActiveProcessHead : 0x%p\n", processHead);
PVOID ntosbase = (PVOID)((ULONG64)processHead - processHeadOffset);
DbgPrint("[NAK] :: [ ] ntoskrnl.exe : 0x%p\n", ntosbase);
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));
}
// TODO: Check if ntosbase is a PE, and the name is ntoskrnl.exe
// https://stackoverflow.com/a/4316804
// https://stackoverflow.com/a/47898643
@ -174,6 +187,15 @@ DriverEntry(
* +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);
@ -182,7 +204,14 @@ DriverEntry(
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:
@ -199,8 +228,11 @@ DriverEntry(
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);
scan(nonPagedPoolStart, nonPagedPoolEnd);
scanNormalPool(nonPagedPoolStart, nonPagedPoolEnd);
scanLargePool(largePageTableArray, largePageTableSize);
return returnStatus;
}
@ -254,13 +286,18 @@ validTag(PPOOL_HEADER p) {
}
bool
checkValidPool(PPOOL_HEADER /* p */) {
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;
}
@ -271,12 +308,12 @@ printChunkInfo(PPOOL_HEADER p) {
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 [%c%c%c%c]\n", p->tag, p->tag, p->tag >> 8, p->tag >> 16, p->tag >> 24);
DbgPrint("[NAK] :: [|] \tPoolTag : 0x%lx [%4s]\n", p->tag, p->tag);
DbgPrint("[NAK] :: [+] ==== PoolEnd 0x%p ====\n", p->addr);
}
VOID
scan(ULONG64 nonPagedPoolStart, ULONG64 nonPagedPoolEnd) {
scanNormalPool(ULONG64 nonPagedPoolStart, ULONG64 nonPagedPoolEnd) {
DbgPrint("[NAK] :: [+] Scanning\n");
/*
@ -295,6 +332,8 @@ scan(ULONG64 nonPagedPoolStart, ULONG64 nonPagedPoolEnd) {
**/
POOL_HEADER p;
PVOID eprocess;
char eprocess_name[16] = {0}; // eprocess name is 15 bytes + 1 null
const ULONG64 headerSize = 0x10;
PVOID currentAddr = (PVOID)(nonPagedPoolStart);
while (true) {
@ -327,6 +366,7 @@ scan(ULONG64 nonPagedPoolStart, ULONG64 nonPagedPoolEnd) {
if (p.tag == 0) continue;
if (!validTag(&p)) continue;
if (!validPool(&p)) continue;
if (p.tag != 'Proc' && p.tag != 'corP')
continue;
@ -334,10 +374,19 @@ scan(ULONG64 nonPagedPoolStart, ULONG64 nonPagedPoolEnd) {
// TODO: Parse data as _EPROCESS
// The first Proc found seems to be the EPROCESS from IoGetCurrentProcess
// But it was offset 0x40
printChunkInfo(&p);
DbgPrint("[NAK] :: [+] HEY EPROCESS POOL CHUNK");
break;
// printChunkInfo(&p);
// eprocess = (PVOID)((ULONG64)p.addr + 0x40);
// RtlStringCbCopyNA(eprocess_name, 16, (char*)((ULONG64)eprocess + eprocessNameOffset), 15);
// DbgPrint("[NAK] :: [ ] eprocess offset 0x40 : 0x%p, [%s]\n", eprocess, eprocess_name);
eprocess = (PVOID)((ULONG64)p.addr + 0x80);
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");
}

View File

@ -28,12 +28,15 @@ bool
validTag(PPOOL_HEADER p);
bool
checkValidPool(PPOOL_HEADER p);
validPool(PPOOL_HEADER p);
VOID
printChunkInfo(PPOOL_HEADER p);
VOID
scan(ULONG64 nonPagedPoolStart, ULONG64 nonPagedPoolEnd);
scanNormalPool(ULONG64 nonPagedPoolStart, ULONG64 nonPagedPoolEnd);
VOID
scanLargePool(PVOID largePageTableArray, ULONG64 largePageTableSize);
#endif