CppUtils/PML/PMLEXT.h

448 lines
14 KiB
C
Raw Permalink Normal View History

2025-06-05 10:06:43 +08:00
#pragma once
#include <Windows.h>
#include "PML/PML.h"
#define ClearFlag(cr3) ((ULONG64)cr3 & 0x000FFFFFFFFFF000)
#define NUM_1G 0x40000000
#define NUM_2M 0x200000
#define ENTRY_SIZE 0x8
#define PAGE_SIZE 0x1000
#define ROUND_DOWN(a,b) ((ULONG64)(a) & ~((ULONG64)(b) - 1))
#define ROUND_UP(a,b) (((ULONG64)(a) + ((ULONG64)(b) - 1)) & ~((ULONG64)(b) - 1))
typedef struct _MMPDPTE
{
struct /* bitfield */
{
/* 0x0000 */ unsigned __int64 Valid : 1; /* bit position: 0 */
/* 0x0000 */ unsigned __int64 Dirty1 : 1; /* bit position: 1 */
/* 0x0000 */ unsigned __int64 Owner : 1; /* bit position: 2 */
/* 0x0000 */ unsigned __int64 WriteThrough : 1; /* bit position: 3 */
/* 0x0000 */ unsigned __int64 CacheDisable : 1; /* bit position: 4 */
/* 0x0000 */ unsigned __int64 Accessed : 1; /* bit position: 5 */
/* 0x0000 */ unsigned __int64 Dirty : 1; /* bit position: 6 */
/* 0x0000 */ unsigned __int64 LargePage : 1; /* bit position: 7 */
/* 0x0000 */ unsigned __int64 Global : 1; /* bit position: 8 */
/* 0x0000 */ unsigned __int64 CopyOnWrite : 1; /* bit position: 9 */
/* 0x0000 */ unsigned __int64 Unused : 1; /* bit position: 10 */
/* 0x0000 */ unsigned __int64 Write : 1; /* bit position: 11 */
/* 0x0000 */ unsigned __int64 reserved0 : 18; /* bit position: 12 */
/* 0x0000 */ unsigned __int64 PageFrameNumber : 18; /* bit position: 30 */
/* 0x0000 */ unsigned __int64 reserved1 : 4; /* bit position: 48 */
/* 0x0000 */ unsigned __int64 SoftwareWsIndex : 11; /* bit position: 52 */
/* 0x0000 */ unsigned __int64 NoExecute : 1; /* bit position: 63 */
}; /* bitfield */
} MMPDPTE, * PMMPDPTE; /* size: 0x0008 */
typedef struct _MMPDE
{
struct /* bitfield */
{
/* 0x0000 */ unsigned __int64 Valid : 1; /* bit position: 0 */
/* 0x0000 */ unsigned __int64 Dirty1 : 1; /* bit position: 1 */
/* 0x0000 */ unsigned __int64 Owner : 1; /* bit position: 2 */
/* 0x0000 */ unsigned __int64 WriteThrough : 1; /* bit position: 3 */
/* 0x0000 */ unsigned __int64 CacheDisable : 1; /* bit position: 4 */
/* 0x0000 */ unsigned __int64 Accessed : 1; /* bit position: 5 */
/* 0x0000 */ unsigned __int64 Dirty : 1; /* bit position: 6 */
/* 0x0000 */ unsigned __int64 LargePage : 1; /* bit position: 7 */
/* 0x0000 */ unsigned __int64 Global : 1; /* bit position: 8 */
/* 0x0000 */ unsigned __int64 CopyOnWrite : 1; /* bit position: 9 */
/* 0x0000 */ unsigned __int64 Unused : 1; /* bit position: 10 */
/* 0x0000 */ unsigned __int64 Write : 1; /* bit position: 11 */
/* 0x0000 */ unsigned __int64 reserved0 : 9; /* bit position: 12 */
/* 0x0000 */ unsigned __int64 PageFrameNumber : 27; /* bit position: 21 */
/* 0x0000 */ unsigned __int64 reserved1 : 4; /* bit position: 48 */
/* 0x0000 */ unsigned __int64 SoftwareWsIndex : 11; /* bit position: 52 */
/* 0x0000 */ unsigned __int64 NoExecute : 1; /* bit position: 63 */
}; /* bitfield */
} MMPDE, * PMMPDE; /* size: 0x0008 */
typedef struct _MMPTE
{
struct /* bitfield */
{
/* 0x0000 */ unsigned __int64 Valid : 1; /* bit position: 0 */
/* 0x0000 */ unsigned __int64 Dirty1 : 1; /* bit position: 1 */
/* 0x0000 */ unsigned __int64 Owner : 1; /* bit position: 2 */
/* 0x0000 */ unsigned __int64 WriteThrough : 1; /* bit position: 3 */
/* 0x0000 */ unsigned __int64 CacheDisable : 1; /* bit position: 4 */
/* 0x0000 */ unsigned __int64 Accessed : 1; /* bit position: 5 */
/* 0x0000 */ unsigned __int64 Dirty : 1; /* bit position: 6 */
/* 0x0000 */ unsigned __int64 LargePage : 1; /* bit position: 7 */
/* 0x0000 */ unsigned __int64 Global : 1; /* bit position: 8 */
/* 0x0000 */ unsigned __int64 CopyOnWrite : 1; /* bit position: 9 */
/* 0x0000 */ unsigned __int64 Unused : 1; /* bit position: 10 */
/* 0x0000 */ unsigned __int64 Write : 1; /* bit position: 11 */
/* 0x0000 */ unsigned __int64 PageFrameNumber : 36; /* bit position: 12 */
/* 0x0000 */ unsigned __int64 reserved1 : 4; /* bit position: 48 */
/* 0x0000 */ unsigned __int64 SoftwareWsIndex : 11; /* bit position: 52 */
/* 0x0000 */ unsigned __int64 NoExecute : 1; /* bit position: 63 */
}; /* bitfield */
} MMPTE, * PMMPTE; /* size: 0x0008 */
typedef struct _MMVA
{
struct /* bitfield */
{
/* 0x0000 */ unsigned __int64 Offset : 12;
/* 0x0000 */ unsigned __int64 PT : 9;
/* 0x0000 */ unsigned __int64 PDT : 9;
/* 0x0000 */ unsigned __int64 PDPT : 9;
/* 0x0000 */ unsigned __int64 PML4T : 9;
/* 0x0000 */ unsigned __int64 Partition : 16; //User:0x0000 System:0xFFFF
}; /* bitfield */
} MMVA, * PMMVA; /* size: 0x0008 */
typedef struct _MMVA_PDPTE_LARGE
{
struct /* bitfield */
{
/* 0x0000 */ unsigned __int64 Offset : 30;
/* 0x0000 */ unsigned __int64 PDPT : 9;
/* 0x0000 */ unsigned __int64 PML4T : 9;
/* 0x0000 */ unsigned __int64 Partition : 16; //User:0x0000 System:0xFFFF
}; /* bitfield */
} MMVA_PDPTE_LARGE, * PMMVA_PDPTE_LARGE; /* size: 0x0008 */
typedef struct _MMVA_PDE_LARGE
{
struct /* bitfield */
{
/* 0x0000 */ unsigned __int64 Offset : 21;
/* 0x0000 */ unsigned __int64 PDT : 9;
/* 0x0000 */ unsigned __int64 PDPT : 9;
/* 0x0000 */ unsigned __int64 PML4T : 9;
/* 0x0000 */ unsigned __int64 Partition : 16; //User:0x0000 System:0xFFFF
}; /* bitfield */
} MMVA_PDE_LARGE, * PMMVA_PDE_LARGE; /* size: 0x0008 */
static MAP_INFO MapedInfo{};
static PVOID KeGetSpecificAddressPhysicalByCR3(ULONG64 CR3, PVOID pVirtual)
{
PMMVA pAddressInfo = (PMMVA)&pVirtual;
PVOID pPML4T = (PVOID)ClearFlag(CR3);
PMMPTE pPML4E = NULL;
PVOID pPDPT = NULL;
PMMPTE pPDPTE = NULL;
PVOID pPDT = NULL;
PMMPTE pPDE = NULL;
PVOID pPT = NULL;
PMMPTE pPTE = NULL;
PVOID pPhysicalBase = NULL;
PVOID pPhysical = NULL;
PVOID pPhysicalR3 = NULL;
pPML4E = (PMMPTE)((ULONG64)pPML4T + (pAddressInfo->PML4T * ENTRY_SIZE) + MapedInfo.MapedAddress);
if (!pPML4E->Valid)
return NULL;
pPDPT = (PVOID)ClearFlag(*(PULONG64)pPML4E);
pPDPTE = (PMMPTE)((ULONG64)pPDPT + pAddressInfo->PDPT * ENTRY_SIZE + MapedInfo.MapedAddress);
if (!pPDPTE->Valid)
return NULL;
if (pPDPTE->LargePage)
goto Lable_PDPTE_LargePage;
pPDT = (PVOID)ClearFlag(*(PULONG64)pPDPTE);
pPDE = (PMMPTE)((ULONG64)pPDT + pAddressInfo->PDT * ENTRY_SIZE + MapedInfo.MapedAddress);
if (!pPDE->Valid)
return NULL;
if (pPDE->LargePage)
goto Lable_PDE_LargePage;
pPT = (PVOID)ClearFlag(*(PULONG64)pPDE);
pPTE = (PMMPTE)((ULONG64)pPT + pAddressInfo->PT * ENTRY_SIZE + MapedInfo.MapedAddress);
if (!pPTE->Valid)
return NULL;
pPhysicalBase = (PVOID)ClearFlag(*(PULONG64)pPTE);
pPhysical = (PVOID)((ULONG64)pPhysicalBase + pAddressInfo->Offset);
pPhysicalR3 = (PVOID)((ULONG64)pPhysical + MapedInfo.MapedAddress);
return pPhysicalR3;
Lable_PDPTE_LargePage:
pPhysicalBase = (PVOID)(((PMMPDPTE)pPDPTE)->PageFrameNumber * NUM_1G);
pPhysical = (PVOID)((ULONG64)pPhysicalBase + ((PMMVA_PDPTE_LARGE)pAddressInfo)->Offset);
pPhysicalR3 = (PVOID)((ULONG64)pPhysical + MapedInfo.MapedAddress);
return pPhysicalR3;
Lable_PDE_LargePage:
pPhysicalBase = (PVOID)(((PMMPDE)pPDE)->PageFrameNumber * NUM_2M);
pPhysical = (PVOID)((ULONG64)pPhysicalBase + ((PMMVA_PDE_LARGE)pAddressInfo)->Offset);
pPhysicalR3 = (PVOID)((ULONG64)pPhysical + MapedInfo.MapedAddress);
return pPhysicalR3;
}
static PVOID KAGetSpecificAddressPhysical(ULONG64 TargetProcessCr3,PVOID pVirtual)
{
PMMVA pAddressInfo = (PMMVA)&pVirtual;
PVOID pPML4T = (PVOID)ClearFlag(TargetProcessCr3);
PMMPTE pPML4E = NULL;
PVOID pPDPT = NULL;
PMMPTE pPDPTE = NULL;
PVOID pPDT = NULL;
PMMPTE pPDE = NULL;
PVOID pPT = NULL;
PMMPTE pPTE = NULL;
PVOID pPhysicalBase = NULL;
PVOID pPhysical = NULL;
PVOID pPhysicalR3 = NULL;
pPML4E = (PMMPTE)((ULONG64)pPML4T + pAddressInfo->PML4T * ENTRY_SIZE + MapedInfo.MapedAddress);
if (!pPML4E->Valid)
return NULL;
pPDPT = (PVOID)ClearFlag(*(PULONG64)pPML4E);
pPDPTE = (PMMPTE)((ULONG64)pPDPT + pAddressInfo->PDPT * ENTRY_SIZE + MapedInfo.MapedAddress);
if (!pPDPTE->Valid)
return NULL;
if (pPDPTE->LargePage)
goto Lable_PDPTE_LargePage;
pPDT = (PVOID)ClearFlag(*(PULONG64)pPDPTE);
pPDE = (PMMPTE)((ULONG64)pPDT + pAddressInfo->PDT * ENTRY_SIZE + MapedInfo.MapedAddress);
if (!pPDE->Valid)
return NULL;
if (pPDE->LargePage)
goto Lable_PDE_LargePage;
pPT = (PVOID)ClearFlag(*(PULONG64)pPDE);
pPTE = (PMMPTE)((ULONG64)pPT + pAddressInfo->PT * ENTRY_SIZE + MapedInfo.MapedAddress);
if (!pPTE->Valid)
return NULL;
pPhysicalBase = (PVOID)ClearFlag(*(PULONG64)pPTE);
pPhysical = (PVOID)((ULONG64)pPhysicalBase + pAddressInfo->Offset);
pPhysicalR3 = (PVOID)((ULONG64)pPhysical + MapedInfo.MapedAddress);
return pPhysicalR3;
Lable_PDPTE_LargePage:
pPhysicalBase = (PVOID)(((PMMPDPTE)pPDPTE)->PageFrameNumber * NUM_1G);
pPhysical = (PVOID)((ULONG64)pPhysicalBase + ((PMMVA_PDPTE_LARGE)pAddressInfo)->Offset);
pPhysicalR3 = (PVOID)((ULONG64)pPhysical + MapedInfo.MapedAddress);
return pPhysicalR3;
Lable_PDE_LargePage:
pPhysicalBase = (PVOID)(((PMMPDE)pPDE)->PageFrameNumber * NUM_2M);
pPhysical = (PVOID)((ULONG64)pPhysicalBase + ((PMMVA_PDE_LARGE)pAddressInfo)->Offset);
pPhysicalR3 = (PVOID)((ULONG64)pPhysical + MapedInfo.MapedAddress);
return pPhysicalR3;
}
static BOOL KeReadPhysicalAddress(ULONG64 Cr3, ULONG64 Address, PVOID Buffer, SIZE_T Size)
{
ULONG64 pCurr = (ULONG64)Address;
ULONG64 pEnd = (ULONG64)Address + Size;
ULONG64 pMappedPA = 0;
SIZE_T CurrSize = 0;
SIZE_T BytesCopied = 0;
while (ROUND_DOWN(pCurr, PAGE_SIZE) < pEnd)
{
if (ROUND_DOWN(pCurr, PAGE_SIZE) + PAGE_SIZE < pEnd)
{
CurrSize = PAGE_SIZE - (SIZE_T)pCurr % PAGE_SIZE;
}
else
{
CurrSize = pEnd - pCurr;
}
pMappedPA = (ULONG64)KeGetSpecificAddressPhysicalByCR3(Cr3, (PVOID)pCurr);
if (!pMappedPA)
{
return FALSE;
}
if (!IsBadReadPtr((PUCHAR)pMappedPA, CurrSize))
{
memcpy((PUCHAR)Buffer + BytesCopied, (PUCHAR)pMappedPA, CurrSize);
}
else
{
return FALSE;
}
BytesCopied += CurrSize;
pCurr = ROUND_DOWN(pCurr, PAGE_SIZE) + PAGE_SIZE;
}
return TRUE;
}
static BOOL KeWritePhysicalAddress(ULONG64 Cr3, ULONG64 Address, PVOID Buffer, SIZE_T Size)
{
ULONG64 pCurr = (ULONG64)Address;
ULONG64 pEnd = (ULONG64)Address + Size;
ULONG64 pMappedPA = 0;
SIZE_T CurrSize = 0;
SIZE_T BytesCopied = 0;
while (ROUND_DOWN(pCurr, PAGE_SIZE) < pEnd)
{
if (ROUND_DOWN(pCurr, PAGE_SIZE) + PAGE_SIZE < pEnd)
{
CurrSize = PAGE_SIZE - (SIZE_T)pCurr % PAGE_SIZE;
}
else
{
CurrSize = pEnd - pCurr;
}
pMappedPA = (ULONG64)KeGetSpecificAddressPhysicalByCR3(Cr3, (PVOID)pCurr);
if (!pMappedPA)
{
return FALSE;
}
if (!IsBadReadPtr((PUCHAR)pMappedPA, CurrSize))
{
memcpy((PUCHAR)pMappedPA, (PUCHAR)Buffer + BytesCopied, CurrSize);
}
else
{
return FALSE;
}
BytesCopied += CurrSize;
pCurr = ROUND_DOWN(pCurr, PAGE_SIZE) + PAGE_SIZE;
}
return TRUE;
}
static PVOID DecodeTableOne(ULONG64 BaseAddr, INT index1, INT index2, HANDLE dwmpid)
{
INT i_id = 0;
for (INT i = 0; i < 256; i++)
{
i_id = i * 4 + 1024 * index1 + 512 * index2 * 1024;
if ((HANDLE)i_id == dwmpid)
{
return (PVOID)((ULONG64)BaseAddr + i * 0x10);
}
}
return NULL;
}
static PVOID DecodeTableTwo(ULONG64 BaseAddr, INT index2, HANDLE pid)
{
ULONG64 ul_baseAddr_1 = 0;
PVOID TableTwo = NULL;
for (SIZE_T i = 0; i < 512; i++)
{
KeReadPhysicalAddress(MapedInfo.SystemCr3, (BaseAddr + i * 8), &ul_baseAddr_1, sizeof(ULONG64));
TableTwo = DecodeTableOne(ul_baseAddr_1, i, index2, pid);
if (TableTwo != NULL)
{
return TableTwo;
}
}
return NULL;
}
static PVOID DecodeTableThree(ULONG64 BaseAddr, HANDLE pid)
{
PVOID TableThree = NULL;
ULONG64 ul_baseAddr_2 = 0;
for (INT i = 0; i < 512; i++)
{
KeReadPhysicalAddress(MapedInfo.SystemCr3, (BaseAddr + i * 8), &ul_baseAddr_2, sizeof(ULONG64));
TableThree = DecodeTableTwo(ul_baseAddr_2, i, pid);
if (TableThree != NULL)
{
return TableThree;
}
}
return NULL;
}
static PVOID GetObjectAddrInHandleTable(IN PVOID pHandleTable, IN HANDLE Index)
{
PVOID PspAddr = NULL;
ULONG64 TableCode = NULL;
KeReadPhysicalAddress(MapedInfo.SystemCr3, ((ULONG64)pHandleTable + 0x8), &TableCode, sizeof(ULONG64));
INT List = TableCode & 3;
ULONG64 BaseAddr = TableCode & (~3);
if (List == 0)
{
PspAddr = DecodeTableOne(BaseAddr, 0, 0, Index);
return PspAddr;
}
else if (List == 1)
{
PspAddr = DecodeTableTwo(BaseAddr, 0, Index);
return PspAddr;
}
else if (List == 2)
{
PspAddr = DecodeTableThree(BaseAddr, Index);
return PspAddr;
}
else
{
return NULL;
}
}
static ULONG64 KeGetProcessSectionBase(HANDLE Pid)
{
ULONG64 TargetProcessCr3 = NULL;
ULONG64 TargetEprocess = NULL;
ULONG64 TargetSectionBase = NULL;
ULONG64 ObjectAddress = (ULONG64)GetObjectAddrInHandleTable((PVOID)MapedInfo.PspCidTable, Pid);
KeReadPhysicalAddress(MapedInfo.SystemCr3, ObjectAddress, &TargetEprocess, sizeof(ULONG64));
TargetEprocess = (TargetEprocess >> 16) | 0xFFFF000000000000;
KeReadPhysicalAddress(MapedInfo.SystemCr3, (TargetEprocess + 0x28), &TargetProcessCr3, sizeof(ULONG64));
KeReadPhysicalAddress(MapedInfo.SystemCr3, (TargetEprocess + MapedInfo.SectionBaseAddressOffset), &TargetSectionBase, sizeof(ULONG64));
return TargetSectionBase;
}
static ULONG64 KeGetProcessCr3(HANDLE Pid)
{
ULONG64 TargetProcessCr3 = NULL;
ULONG64 TargetEprocess = NULL;
ULONG64 TargetSectionBase = NULL;
ULONG64 ObjectAddress = (ULONG64)GetObjectAddrInHandleTable((PVOID)MapedInfo.PspCidTable, Pid);
KeReadPhysicalAddress(MapedInfo.SystemCr3, ObjectAddress, &TargetEprocess, sizeof(ULONG64));
TargetEprocess = (TargetEprocess >> 16) | 0xFFFF000000000000;
KeReadPhysicalAddress(MapedInfo.SystemCr3, (TargetEprocess + 0x28), &TargetProcessCr3, sizeof(ULONG64));
return TargetProcessCr3;
}
static PEPROCESS KeGetEProcess(HANDLE Pid)
{
ULONG64 TargetEprocess = NULL;
ULONG64 TargetSectionBase = NULL;
ULONG64 ObjectAddress = (ULONG64)GetObjectAddrInHandleTable((PVOID)MapedInfo.PspCidTable, Pid);
if (!ObjectAddress) return NULL;
KeReadPhysicalAddress(MapedInfo.SystemCr3, ObjectAddress, &TargetEprocess, sizeof(ULONG64));
if (!TargetEprocess) return NULL;
TargetEprocess = (TargetEprocess >> 16) | 0xFFFF000000000000;
return (PEPROCESS)KeGetSpecificAddressPhysicalByCR3(MapedInfo.SystemCr3, (PVOID)TargetEprocess);
}
template<typename T>
static T KeReadChain(ULONG64 Cr3, ULONG64 Address, std::initializer_list<ULONG64> offsets)
{
T result = T();
ULONG64 pCurr = Address;
for (auto offset : offsets)
{
if (!KeReadPhysicalAddress(Cr3, pCurr + offset, &pCurr, sizeof(ULONG64)))
return result;
}
KeReadPhysicalAddress(Cr3, pCurr, &result, sizeof(T));
return result;
}