Files
2021-05-18 23:23:42 +07:00

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