Version 1.2

This commit is contained in:
ufrisk
2018-12-05 13:49:54 +01:00
parent 4350b74492
commit 3cc2a92c30
52 changed files with 3514 additions and 1314 deletions

View File

@@ -30,7 +30,6 @@ typedef struct tdVFS_FILELIST {
} VFS_FILELIST, *PVFS_FILELIST;
BOOL VfsListVmmDirectory(_In_ LPWSTR wszDirectoryName);
VOID Vfs_UtilSplitPathFile(_Out_ WCHAR wszPath[MAX_PATH], _Out_ LPWSTR *pwcsFile, _In_ LPCWSTR wcsFileName);
//-------------------------------------------------------------------------------
// FILELIST FUNCTIONALITY BELOW:
@@ -151,6 +150,7 @@ PWIN32_FIND_DATAW VfsFileList_FindSingle(_In_ PVFS_FILELIST pFileList, _In_ LPWS
// (caching is used to cache vmmproc directory listings for performance reasons)
//-------------------------------------------------------------------------------
_Success_(return)
BOOL VfsCacheDirectory_GetSingle2(_In_ LPWSTR wszPath, _In_ LPWSTR wszFile, _Out_ PWIN32_FIND_DATAW pFindData, _Out_ PBOOL pIsDirectoryExisting)
{
QWORD i, qwCurrentTickCount;
@@ -247,7 +247,7 @@ BOOL VfsListVmmDirectory(_In_ LPWSTR wszDirectoryName)
return TRUE;
}
VOID Vfs_UtilSplitPathFile(_Out_ WCHAR wszPath[MAX_PATH], _Out_ LPWSTR *pwcsFile, _In_ LPCWSTR wcsFileName)
VOID Vfs_UtilSplitPathFile(_Out_writes_(MAX_PATH) PWCHAR wszPath, _Out_ LPWSTR *pwcsFile, _In_ LPCWSTR wcsFileName)
{
DWORD i, iSplitFilePath = 0;
wcsncpy_s(wszPath, MAX_PATH, wcsFileName, _TRUNCATE);
@@ -395,10 +395,8 @@ VOID VfsClose()
VfsCacheDirectory_Close();
DeleteCriticalSection(&ctxVfs->CacheDirectoryLock);
}
if(ctxVfs) {
LocalFree(ctxVfs);
ctxVfs = NULL;
}
LocalFree(ctxVfs);
ctxVfs = NULL;
}
VOID VfsInitializeAndMount(_In_ CHAR chMountPoint, _In_ PVMMDLL_FUNCTIONS pVmmDll)
@@ -417,8 +415,13 @@ VOID VfsInitializeAndMount(_In_ CHAR chMountPoint, _In_ PVMMDLL_FUNCTIONS pVmmDl
pVmmDll->ConfigGet(VMMDLL_OPT_CONFIG_VMM_VERSION_REVISION, &qwVersionRevision);
// allocate
hModuleDokan = LoadLibraryExA("dokan1.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
if(!hModuleDokan) {
printf("MOUNT: Failed. The required DOKANY file system library is not installed. \n");
printf("Please download from : https://github.com/dokan-dev/dokany/releases/latest\n");
goto fail;
}
fnDokanMain = (int(*)(PDOKAN_OPTIONS, PDOKAN_OPERATIONS))GetProcAddress(hModuleDokan, "DokanMain");
if(!hModuleDokan || !fnDokanMain) {
if(!fnDokanMain) {
printf("MOUNT: Failed. The required DOKANY file system library is not installed. \n");
printf("Please download from : https://github.com/dokan-dev/dokany/releases/latest\n");
goto fail;
@@ -462,7 +465,7 @@ VOID VfsInitializeAndMount(_In_ CHAR chMountPoint, _In_ PVMMDLL_FUNCTIONS pVmmDl
"a convenient process file system for analysis purposes. \n" \
" - File system is read-only when dump files are used. \n" \
" - File system is read-write when FPGA hardware acquisition devices are used. \n" \
" - Full support exists for x64 Windows operating systems. \n" \
" - Full support exists for Windows XP to Windows 10 (x86 and x64). \n" \
" - Limited support for other x64 operating systems. \n" \
" - Memory Process File System: https://github.com/ufrisk/MemProcFS \n" \
" - File system by: Ulf Frisk - pcileech@frizk.net - https://frizk.net \n" \
@@ -476,7 +479,7 @@ VOID VfsInitializeAndMount(_In_ CHAR chMountPoint, _In_ PVMMDLL_FUNCTIONS pVmmDl
printf("MOUNT: Failed. Status Code: %i\n", status);
fail:
if(hModuleDokan) { FreeLibrary(hModuleDokan); }
if(pDokanOptions) { LocalFree(pDokanOptions); }
if(pDokanOperations) { LocalFree(pDokanOperations); }
LocalFree(pDokanOptions);
LocalFree(pDokanOperations);
VfsClose();
}

View File

@@ -23,6 +23,7 @@ extern "C" {
* Call other VMMDLL_Intialize functions to initialize VMM.DLL and the memory
* process file system.
*/
_Success_(return)
BOOL VMMDLL_InitializeReserved(_In_ DWORD argc, _In_ LPSTR argv[]);
/*
@@ -37,6 +38,7 @@ BOOL VMMDLL_InitializeReserved(_In_ DWORD argc, _In_ LPSTR argv[]);
* as hex string. NB! this is usally not required. Example: "0x1ab000".
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeFile(_In_ LPSTR szFileName, _In_opt_ LPSTR szPageTableBaseOpt);
/*
@@ -52,6 +54,7 @@ BOOL VMMDLL_InitializeFile(_In_ LPSTR szFileName, _In_opt_ LPSTR szPageTableBase
* as hex string. NB! this is usally not required. Example: "0x1ab000".
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeFPGA(_In_opt_ LPSTR szMaxPhysicalAddressOpt, _In_opt_ LPSTR szPageTableBaseOpt);
/*
@@ -60,6 +63,7 @@ BOOL VMMDLL_InitializeFPGA(_In_opt_ LPSTR szMaxPhysicalAddressOpt, _In_opt_ LPST
* initialized in read/write mode upon success.
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeTotalMeltdown();
/*
@@ -67,6 +71,7 @@ BOOL VMMDLL_InitializeTotalMeltdown();
* including plugins, linked PCILeech.DLL and other memory resources.
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_Close();
@@ -103,7 +108,8 @@ BOOL VMMDLL_Close();
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA_TLP 0x80000004 // RW
#define VMMDLL_OPT_CORE_MAX_NATIVE_ADDRESS 0x80000005 // R
#define VMMDLL_OPT_CORE_MAX_NATIVE_IOSIZE 0x80000006 // R
#define VMMDLL_OPT_CORE_TARGET_SYSTEM 0x80000007 // R
#define VMMDLL_OPT_CORE_SYSTEM 0x80000007 // R
#define VMMDLL_OPT_CORE_MEMORYMODEL 0x80000008 // R
#define VMMDLL_OPT_CONFIG_IS_REFRESH_ENABLED 0x40000001 // R - 1/0
#define VMMDLL_OPT_CONFIG_TICK_PERIOD 0x40000002 // RW - base tick period in ms
@@ -116,6 +122,22 @@ BOOL VMMDLL_Close();
#define VMMDLL_OPT_CONFIG_VMM_VERSION_REVISION 0x40000009 // R
#define VMMDLL_OPT_CONFIG_STATISTICS_FUNCTIONCALL 0x4000000A // RW - enable function call statistics (.status/statistics_fncall file)
static const LPSTR VMMDLL_MEMORYMODEL_TOSTRING[4] = { "N/A", "X86", "X86PAE", "X64" };
typedef enum tdVMMDLL_MEMORYMODEL_TP {
VMMDLL_MEMORYMODEL_NA = 0,
VMMDLL_MEMORYMODEL_X86 = 1,
VMMDLL_MEMORYMODEL_X86PAE = 2,
VMMDLL_MEMORYMODEL_X64 = 3
} VMMDLL_MEMORYMODEL_TP;
typedef enum tdVMMDLL_SYSTEM_TP {
VMMDLL_SYSTEM_UNKNOWN_X64 = 1,
VMMDLL_SYSTEM_WINDOWS_X64 = 2,
VMMDLL_SYSTEM_UNKNOWN_X86 = 3,
VMMDLL_SYSTEM_WINDOWS_X86 = 4
} VMMDLL_SYSTEM_TP;
/*
* Set a device specific option value. Please see defines VMMDLL_OPT_* for infor-
* mation about valid option values. Please note that option values may overlap
@@ -124,6 +146,7 @@ BOOL VMMDLL_Close();
* -- pqwValue = pointer to ULONG64 to receive option value.
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ConfigGet(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue);
/*
@@ -134,6 +157,7 @@ BOOL VMMDLL_ConfigGet(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue);
* -- qwValue
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ConfigSet(_In_ ULONG64 fOption, _In_ ULONG64 qwValue);
@@ -171,6 +195,7 @@ typedef struct tdVMMDLL_VFS_FILELIST {
* -- pFileList
* -- return
*/
_Success_(return)
BOOL VMMDLL_VfsList(_In_ LPCWSTR wcsPath, _Inout_ PVMMDLL_VFS_FILELIST pFileList);
/*
@@ -227,12 +252,13 @@ NTSTATUS VMMDLL_UtilVfsWriteFile_DWORD(_Inout_ PDWORD pdwTarget, _In_ LPVOID pb,
* will be unloaded on a general close of the vmm dll.
* -- return
*/
_Success_(return)
BOOL VMMDLL_VfsInitializePlugins();
#define VMMDLL_PLUGIN_CONTEXT_MAGIC 0xc0ffee663df9301c
#define VMMDLL_PLUGIN_CONTEXT_VERSION 1
#define VMMDLL_PLUGIN_REGINFO_MAGIC 0xc0ffee663df9301d
#define VMMDLL_PLUGIN_REGINFO_VERSION 1
#define VMMDLL_PLUGIN_REGINFO_VERSION 2
#define VMMDLL_PLUGIN_EVENT_VERBOSITYCHANGE 0x01
@@ -254,7 +280,8 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
ULONG64 magic;
WORD wVersion;
WORD wSize;
DWORD fTargetSystem;
VMMDLL_MEMORYMODEL_TP tpMemoryModel;
VMMDLL_SYSTEM_TP tpSystem;
HMODULE hDLL;
HMODULE hReservedDll; // not for general use (only used for python).
BOOL(*pfnPluginManager_Register)(struct tdVMMDLL_PLUGIN_REGINFO *pPluginRegInfo);
@@ -272,7 +299,7 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
// function plugin registration info to be filled out by the plugin below:
struct {
BOOL(*pfnList)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList);
NTSTATUS(*pfnRead)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset);
NTSTATUS(*pfnRead)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset);
NTSTATUS(*pfnWrite)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset);
VOID(*pfnNotify)(_Inout_opt_ PHANDLE phModulePrivate, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent);
VOID(*pfnCloseHandleModule)(_Inout_opt_ PHANDLE phModulePrivate);
@@ -296,8 +323,7 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
#define VMMDLL_FLAG_NOCACHE 0x0001 // do not use the data cache (force reading from memory acquisition device)
#define VMMDLL_FLAG_ZEROPAD_ON_FAIL 0x0002 // zero pad failed physical memory reads and report success if read within range of physical memory.
#define VMMDLL_TARGET_UNKNOWN_X64 0x0001
#define VMMDLL_TARGET_WINDOWS_X64 0x0002
#define VMMDLL_MEM_IO_SCATTER_HEADER_VERSION 2
typedef struct tdVMMDLL_MEM_IO_SCATTER_HEADER {
ULONG64 qwA; // base address (DWORD boundry).
@@ -306,6 +332,10 @@ typedef struct tdVMMDLL_MEM_IO_SCATTER_HEADER {
PBYTE pb; // ptr to 0x1000 sized buffer to receive read bytes.
PVOID pvReserved1; // reserved for use by caller.
PVOID pvReserved2; // reserved for use by caller.
WORD version; // version of struct
WORD Future1; // reserved for future use.
DWORD Future2; // reserved for future use.
ULONG64 qwDeviceA; // device-physical address (used by device layer).
struct {
PVOID pvReserved1;
PVOID pvReserved2;
@@ -335,6 +365,7 @@ DWORD VMMDLL_MemReadScatter(_In_ DWORD dwPID, _Inout_ PPVMMDLL_MEM_IO_SCATTER_HE
* -- pbPage
* -- return = success/fail (depending if all requested bytes are read or not).
*/
_Success_(return)
BOOL VMMDLL_MemReadPage(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_bytecount_(4096) PBYTE pbPage);
/*
@@ -345,6 +376,7 @@ BOOL VMMDLL_MemReadPage(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_bytecount_(4
* -- cb
* -- return = success/fail (depending if all requested bytes are read or not).
*/
_Success_(return)
BOOL VMMDLL_MemRead(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DWORD cb);
/*
@@ -358,7 +390,8 @@ BOOL VMMDLL_MemRead(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DW
* -- return = success/fail. NB! reads may report as success even if 0 bytes are
* read - it's recommended to verify pcbReadOpt parameter.
*/
BOOL VMMDLL_MemReadEx(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ ULONG64 flags);
_Success_(return)
BOOL VMMDLL_MemReadEx(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ ULONG64 flags);
/*
* Write a contigious arbitrary amount of memory. Please note some virtual memory
@@ -373,7 +406,8 @@ BOOL VMMDLL_MemReadEx(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_ PBYTE pb, _In
* -- cb
* -- return = TRUE on success, FALSE on partial or zero write.
*/
BOOL VMMDLL_MemWrite(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DWORD cb);
_Success_(return)
BOOL VMMDLL_MemWrite(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _In_ PBYTE pb, _In_ DWORD cb);
/*
* Translate a virtual address to a physical address by walking the page tables
@@ -383,6 +417,7 @@ BOOL VMMDLL_MemWrite(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ D
* -- pqwPA
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_MemVirt2Phys(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PULONG64 pqwPA);
@@ -401,6 +436,7 @@ BOOL VMMDLL_MemVirt2Phys(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PULONG64 pqw
* -- pdwPID = pointer that will receive PID on success.
* -- return
*/
_Success_(return)
BOOL VMMDLL_PidGetFromName(_In_ LPSTR szProcName, _Out_ PDWORD pdwPID);
/*
@@ -409,7 +445,8 @@ BOOL VMMDLL_PidGetFromName(_In_ LPSTR szProcName, _Out_ PDWORD pdwPID);
* -- pcPIDs = size of (in number of DWORDs) pPIDs array on entry, number of PIDs in system on exit.
* -- return = success/fail.
*/
BOOL VMMDLL_PidList(_Out_ PDWORD pPIDs, _Inout_ PULONG64 pcPIDs);
_Success_(return)
BOOL VMMDLL_PidList(_Out_opt_ PDWORD pPIDs, _Inout_ PULONG64 pcPIDs);
// flags to check for existence in the fPage field of PCILEECH_VMM_MEMMAP_ENTRY
#define VMMDLL_MEMMAP_FLAG_PAGE_W 0x0000000000000002
@@ -437,6 +474,7 @@ typedef struct tdVMMDLL_MEMMAP_ENTRY {
* -- fIdentifyModules = try identify modules as well (= slower)
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ProcessGetMemoryMap(_In_ DWORD dwPID, _Out_opt_ PVMMDLL_MEMMAP_ENTRY pMemMapEntries, _Inout_ PULONG64 pcMemMapEntries, _In_ BOOL fIdentifyModules);
/*
@@ -448,6 +486,7 @@ BOOL VMMDLL_ProcessGetMemoryMap(_In_ DWORD dwPID, _Out_opt_ PVMMDLL_MEMMAP_ENTRY
* -- fIdentifyModules = try identify modules as well (= slower)
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ProcessGetMemoryMapEntry(_In_ DWORD dwPID, _Out_ PVMMDLL_MEMMAP_ENTRY pMemMapEntry, _In_ ULONG64 va, _In_ BOOL fIdentifyModules);
typedef struct tdVMMDLL_MODULEMAP_ENTRY {
@@ -469,7 +508,8 @@ typedef struct tdVMMDLL_MODULEMAP_ENTRY {
* -- pcModuleEntries = pointer to number of memory map entries.
* -- return = success/fail.
*/
BOOL VMMDLL_ProcessGetModuleMap(_In_ DWORD dwPID, _Out_ PVMMDLL_MODULEMAP_ENTRY pModuleEntries, _Inout_ PULONG64 pcModuleEntries);
_Success_(return)
BOOL VMMDLL_ProcessGetModuleMap(_In_ DWORD dwPID, _Out_opt_ PVMMDLL_MODULEMAP_ENTRY pModuleEntries, _Inout_ PULONG64 pcModuleEntries);
/*
* Retrieve a module (.exe or .dll or similar) given a module name.
@@ -478,29 +518,31 @@ BOOL VMMDLL_ProcessGetModuleMap(_In_ DWORD dwPID, _Out_ PVMMDLL_MODULEMAP_ENTRY
* -- pModuleEntry
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ProcessGetModuleFromName(_In_ DWORD dwPID, _In_ LPSTR szModuleName, _Out_ PVMMDLL_MODULEMAP_ENTRY pModuleEntry);
#define VMMDLL_PROCESS_INFORMATION_MAGIC 0xc0ffee663df9301d
#define VMMDLL_PROCESS_INFORMATION_VERSION 1
#define VMMDLL_PROCESS_INFORMATION_MAGIC 0xc0ffee663df9301e
#define VMMDLL_PROCESS_INFORMATION_VERSION 2
typedef struct tdVMMDLL_PROCESS_INFORMATION {
ULONG64 magic;
WORD wVersion;
WORD wSize;
DWORD fTargetSystem; // as given by VMMDLL_TARGET_*
BOOL fUserOnly; // only user mode pages listed
VMMDLL_MEMORYMODEL_TP tpMemoryModel; // as given by VMMDLL_MEMORYMODEL_* enum
VMMDLL_SYSTEM_TP tpSystem; // as given by VMMDLL_SYSTEM_* enum
BOOL fUserOnly; // only user mode pages listed
DWORD dwPID;
DWORD dwState;
CHAR szName[16];
ULONG64 paPML4;
ULONG64 paPML4_UserOpt; // may not exist
ULONG64 paDTB;
ULONG64 paDTB_UserOpt; // may not exist
union {
struct {
ULONG64 vaEPROCESS;
ULONG64 vaPEB;
ULONG64 vaENTRY;
BOOL fWow64;
DWORD vaPEB32; // WoW64 only
DWORD vaPEB32; // WoW64 only
} win;
} os;
} VMMDLL_PROCESS_INFORMATION, *PVMMDLL_PROCESS_INFORMATION;
@@ -513,6 +555,7 @@ typedef struct tdVMMDLL_PROCESS_INFORMATION {
* -- pcbProcessInformation = size of pProcessInfo (in bytes) on entry and exit
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ProcessGetInformation(_In_ DWORD dwPID, _Inout_opt_ PVMMDLL_PROCESS_INFORMATION pProcessInformation, _In_ PSIZE_T pcbProcessInformation);
typedef struct tdVMMDLL_EAT_ENTRY {
@@ -539,10 +582,14 @@ typedef struct tdVMMDLL_IAT_ENTRY {
* -- pcData
* -- return = success/fail.
*/
BOOL VMMDLL_ProcessGetDirectories(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PIMAGE_DATA_DIRECTORY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
BOOL VMMDLL_ProcessGetSections(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PIMAGE_SECTION_HEADER pData, _In_ DWORD cData, _Out_ PDWORD pcData);
BOOL VMMDLL_ProcessGetEAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PVMMDLL_EAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
BOOL VMMDLL_ProcessGetIAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PVMMDLL_IAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
_Success_(return)
BOOL VMMDLL_ProcessGetDirectories(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_writes_(16) PIMAGE_DATA_DIRECTORY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
_Success_(return)
BOOL VMMDLL_ProcessGetSections(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_opt_ PIMAGE_SECTION_HEADER pData, _In_ DWORD cData, _Out_ PDWORD pcData);
_Success_(return)
BOOL VMMDLL_ProcessGetEAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_opt_ PVMMDLL_EAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
_Success_(return)
BOOL VMMDLL_ProcessGetIAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_opt_ PVMMDLL_IAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
@@ -558,7 +605,8 @@ BOOL VMMDLL_ProcessGetIAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PVMMDLL_I
* -- sz = buffer to fill, NULL to retrieve size in pcsz parameter.
* -- pcsz = ptr to size of buffer on entry, size of characters on exit.
*/
BOOL VMMDLL_UtilFillHexAscii(_In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset, _Inout_ LPSTR sz, _Inout_ PDWORD pcsz);
_Success_(return)
BOOL VMMDLL_UtilFillHexAscii(_In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset, _Inout_opt_ LPSTR sz, _Out_ PDWORD pcsz);
#ifdef __cplusplus
}

View File

@@ -77,11 +77,12 @@ Detailed build instructions may be found in the [Wiki](https://github.com/ufrisk
Current Limitations & Future Development:
=========================================
The Memory Process File System is currently limited to analyzing Windows x64 memory dumps (other x64 dumps in a very limited way). Also, the Memory Process File System currently does not run on Linux.
The Memory Process File System is currently limited to analyzing Windows (32-bit and 64-bit XP to 10) memory dumps (other x64 dumps in a very limited way). Also, the Memory Process File System currently does not run on Linux.
Please find some ideas for possible future expansions of the memory process file system listed below. This is a list of ideas - not a list of features that will be implemented. Even though some items are put as prioritized there is no guarantee that they will be implemented in a timely fashion.
### Prioritized items:
- Support for Microsoft crash dump format (full memory dump / DumpIt).
- More/new plugins.
- Linux support - .so files for easy and convenient Linux API access from both C/C++ and Python.
- Additional core functionality (exported functions in .DLL). Please request in Issues section if ideas exist.
@@ -91,7 +92,7 @@ Please find some ideas for possible future expansions of the memory process file
- Multithreading support in main library.
- Linux support in mounted FUSE file system.
- Support for analyzing x64 Linux, macOS and UEFI memory dumps.
- Support for non-x64 memory models (such as x86 32-bit).
- ~~Support for non-x64 memory models (such as x86 32-bit).~~
- Hash lookup of executable memory pages in DB.
Links:
@@ -107,4 +108,11 @@ v1.0
* Initial Release.
v1.1
* Loaded kernel drivers in System process 'modules' sub-directory.
* Loaded kernel drivers in System process 'modules' sub-directory (Windows 10).
v1.2
* Support for 32-bit Windows - XP to 10.
* Support for 32-bit memory models (x86 and PAE).
* Improved auto-identification of memory model and Windows.
* Loaded kernel drivers in System process 'modules' sub-directory (all Windows versions).
* PE (exe/dll/sys) Sections and Data Directories as files in 'modules' sub-directory.

Binary file not shown.

Binary file not shown.

View File

@@ -140,7 +140,7 @@ def IsProcessPeb6432(pid):
if(procinfo['state'] != 0):
result = False, False
else:
result = procinfo['va-peb'] > 0, procinfo['va-peb32'] > 0
result = procinfo['va-peb'] > 0, ('va-peb32' in procinfo and procinfo['va-peb32'] > 0)
procstruct_cache_proc_wow64[pid] = result
return result
@@ -185,11 +185,11 @@ def Close():
def Initialize(os_target):
# Check that the operating system is 64-bit Windows. If it's not then raise
# an exception to terminate loading of this module.
if os_target != VMMPY_TARGET_WINDOWS_X64:
raise RuntimeError("Only x64 Windows is supported by the pym_procstruct module.")
def Initialize(target_system, target_memorymodel):
# Check that the operating system is 32-bit or 64-bit Windows. If it's not
# then raise an exception to terminate loading of this module.
if target_system != VMMPY_SYSTEM_WINDOWS_X64 and target_system != VMMPY_SYSTEM_WINDOWS_X86:
raise RuntimeError("Only Windows is supported by the pym_procstruct module.")
# Calculate the size of the 'eprocess_size_hex' global variable. This is
# only done once - at module instantiation to speed up the list operation.
global procstruct_eprocess_size_hex

Binary file not shown.

Binary file not shown.

View File

@@ -23,6 +23,7 @@ extern "C" {
* Call other VMMDLL_Intialize functions to initialize VMM.DLL and the memory
* process file system.
*/
_Success_(return)
BOOL VMMDLL_InitializeReserved(_In_ DWORD argc, _In_ LPSTR argv[]);
/*
@@ -37,6 +38,7 @@ BOOL VMMDLL_InitializeReserved(_In_ DWORD argc, _In_ LPSTR argv[]);
* as hex string. NB! this is usally not required. Example: "0x1ab000".
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeFile(_In_ LPSTR szFileName, _In_opt_ LPSTR szPageTableBaseOpt);
/*
@@ -52,6 +54,7 @@ BOOL VMMDLL_InitializeFile(_In_ LPSTR szFileName, _In_opt_ LPSTR szPageTableBase
* as hex string. NB! this is usally not required. Example: "0x1ab000".
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeFPGA(_In_opt_ LPSTR szMaxPhysicalAddressOpt, _In_opt_ LPSTR szPageTableBaseOpt);
/*
@@ -60,6 +63,7 @@ BOOL VMMDLL_InitializeFPGA(_In_opt_ LPSTR szMaxPhysicalAddressOpt, _In_opt_ LPST
* initialized in read/write mode upon success.
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeTotalMeltdown();
/*
@@ -67,6 +71,7 @@ BOOL VMMDLL_InitializeTotalMeltdown();
* including plugins, linked PCILeech.DLL and other memory resources.
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_Close();
@@ -103,7 +108,8 @@ BOOL VMMDLL_Close();
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA_TLP 0x80000004 // RW
#define VMMDLL_OPT_CORE_MAX_NATIVE_ADDRESS 0x80000005 // R
#define VMMDLL_OPT_CORE_MAX_NATIVE_IOSIZE 0x80000006 // R
#define VMMDLL_OPT_CORE_TARGET_SYSTEM 0x80000007 // R
#define VMMDLL_OPT_CORE_SYSTEM 0x80000007 // R
#define VMMDLL_OPT_CORE_MEMORYMODEL 0x80000008 // R
#define VMMDLL_OPT_CONFIG_IS_REFRESH_ENABLED 0x40000001 // R - 1/0
#define VMMDLL_OPT_CONFIG_TICK_PERIOD 0x40000002 // RW - base tick period in ms
@@ -116,6 +122,22 @@ BOOL VMMDLL_Close();
#define VMMDLL_OPT_CONFIG_VMM_VERSION_REVISION 0x40000009 // R
#define VMMDLL_OPT_CONFIG_STATISTICS_FUNCTIONCALL 0x4000000A // RW - enable function call statistics (.status/statistics_fncall file)
static const LPSTR VMMDLL_MEMORYMODEL_TOSTRING[4] = { "N/A", "X86", "X86PAE", "X64" };
typedef enum tdVMMDLL_MEMORYMODEL_TP {
VMMDLL_MEMORYMODEL_NA = 0,
VMMDLL_MEMORYMODEL_X86 = 1,
VMMDLL_MEMORYMODEL_X86PAE = 2,
VMMDLL_MEMORYMODEL_X64 = 3
} VMMDLL_MEMORYMODEL_TP;
typedef enum tdVMMDLL_SYSTEM_TP {
VMMDLL_SYSTEM_UNKNOWN_X64 = 1,
VMMDLL_SYSTEM_WINDOWS_X64 = 2,
VMMDLL_SYSTEM_UNKNOWN_X86 = 3,
VMMDLL_SYSTEM_WINDOWS_X86 = 4
} VMMDLL_SYSTEM_TP;
/*
* Set a device specific option value. Please see defines VMMDLL_OPT_* for infor-
* mation about valid option values. Please note that option values may overlap
@@ -124,6 +146,7 @@ BOOL VMMDLL_Close();
* -- pqwValue = pointer to ULONG64 to receive option value.
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ConfigGet(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue);
/*
@@ -134,6 +157,7 @@ BOOL VMMDLL_ConfigGet(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue);
* -- qwValue
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ConfigSet(_In_ ULONG64 fOption, _In_ ULONG64 qwValue);
@@ -171,6 +195,7 @@ typedef struct tdVMMDLL_VFS_FILELIST {
* -- pFileList
* -- return
*/
_Success_(return)
BOOL VMMDLL_VfsList(_In_ LPCWSTR wcsPath, _Inout_ PVMMDLL_VFS_FILELIST pFileList);
/*
@@ -227,12 +252,13 @@ NTSTATUS VMMDLL_UtilVfsWriteFile_DWORD(_Inout_ PDWORD pdwTarget, _In_ LPVOID pb,
* will be unloaded on a general close of the vmm dll.
* -- return
*/
_Success_(return)
BOOL VMMDLL_VfsInitializePlugins();
#define VMMDLL_PLUGIN_CONTEXT_MAGIC 0xc0ffee663df9301c
#define VMMDLL_PLUGIN_CONTEXT_VERSION 1
#define VMMDLL_PLUGIN_REGINFO_MAGIC 0xc0ffee663df9301d
#define VMMDLL_PLUGIN_REGINFO_VERSION 1
#define VMMDLL_PLUGIN_REGINFO_VERSION 2
#define VMMDLL_PLUGIN_EVENT_VERBOSITYCHANGE 0x01
@@ -254,7 +280,8 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
ULONG64 magic;
WORD wVersion;
WORD wSize;
DWORD fTargetSystem;
VMMDLL_MEMORYMODEL_TP tpMemoryModel;
VMMDLL_SYSTEM_TP tpSystem;
HMODULE hDLL;
HMODULE hReservedDll; // not for general use (only used for python).
BOOL(*pfnPluginManager_Register)(struct tdVMMDLL_PLUGIN_REGINFO *pPluginRegInfo);
@@ -272,7 +299,7 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
// function plugin registration info to be filled out by the plugin below:
struct {
BOOL(*pfnList)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList);
NTSTATUS(*pfnRead)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset);
NTSTATUS(*pfnRead)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset);
NTSTATUS(*pfnWrite)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset);
VOID(*pfnNotify)(_Inout_opt_ PHANDLE phModulePrivate, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent);
VOID(*pfnCloseHandleModule)(_Inout_opt_ PHANDLE phModulePrivate);
@@ -296,8 +323,7 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
#define VMMDLL_FLAG_NOCACHE 0x0001 // do not use the data cache (force reading from memory acquisition device)
#define VMMDLL_FLAG_ZEROPAD_ON_FAIL 0x0002 // zero pad failed physical memory reads and report success if read within range of physical memory.
#define VMMDLL_TARGET_UNKNOWN_X64 0x0001
#define VMMDLL_TARGET_WINDOWS_X64 0x0002
#define VMMDLL_MEM_IO_SCATTER_HEADER_VERSION 2
typedef struct tdVMMDLL_MEM_IO_SCATTER_HEADER {
ULONG64 qwA; // base address (DWORD boundry).
@@ -306,6 +332,10 @@ typedef struct tdVMMDLL_MEM_IO_SCATTER_HEADER {
PBYTE pb; // ptr to 0x1000 sized buffer to receive read bytes.
PVOID pvReserved1; // reserved for use by caller.
PVOID pvReserved2; // reserved for use by caller.
WORD version; // version of struct
WORD Future1; // reserved for future use.
DWORD Future2; // reserved for future use.
ULONG64 qwDeviceA; // device-physical address (used by device layer).
struct {
PVOID pvReserved1;
PVOID pvReserved2;
@@ -335,6 +365,7 @@ DWORD VMMDLL_MemReadScatter(_In_ DWORD dwPID, _Inout_ PPVMMDLL_MEM_IO_SCATTER_HE
* -- pbPage
* -- return = success/fail (depending if all requested bytes are read or not).
*/
_Success_(return)
BOOL VMMDLL_MemReadPage(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_bytecount_(4096) PBYTE pbPage);
/*
@@ -345,6 +376,7 @@ BOOL VMMDLL_MemReadPage(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_bytecount_(4
* -- cb
* -- return = success/fail (depending if all requested bytes are read or not).
*/
_Success_(return)
BOOL VMMDLL_MemRead(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DWORD cb);
/*
@@ -358,7 +390,8 @@ BOOL VMMDLL_MemRead(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DW
* -- return = success/fail. NB! reads may report as success even if 0 bytes are
* read - it's recommended to verify pcbReadOpt parameter.
*/
BOOL VMMDLL_MemReadEx(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ ULONG64 flags);
_Success_(return)
BOOL VMMDLL_MemReadEx(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ ULONG64 flags);
/*
* Write a contigious arbitrary amount of memory. Please note some virtual memory
@@ -373,7 +406,8 @@ BOOL VMMDLL_MemReadEx(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_ PBYTE pb, _In
* -- cb
* -- return = TRUE on success, FALSE on partial or zero write.
*/
BOOL VMMDLL_MemWrite(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DWORD cb);
_Success_(return)
BOOL VMMDLL_MemWrite(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _In_ PBYTE pb, _In_ DWORD cb);
/*
* Translate a virtual address to a physical address by walking the page tables
@@ -383,6 +417,7 @@ BOOL VMMDLL_MemWrite(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ D
* -- pqwPA
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_MemVirt2Phys(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PULONG64 pqwPA);
@@ -401,6 +436,7 @@ BOOL VMMDLL_MemVirt2Phys(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PULONG64 pqw
* -- pdwPID = pointer that will receive PID on success.
* -- return
*/
_Success_(return)
BOOL VMMDLL_PidGetFromName(_In_ LPSTR szProcName, _Out_ PDWORD pdwPID);
/*
@@ -409,7 +445,8 @@ BOOL VMMDLL_PidGetFromName(_In_ LPSTR szProcName, _Out_ PDWORD pdwPID);
* -- pcPIDs = size of (in number of DWORDs) pPIDs array on entry, number of PIDs in system on exit.
* -- return = success/fail.
*/
BOOL VMMDLL_PidList(_Out_ PDWORD pPIDs, _Inout_ PULONG64 pcPIDs);
_Success_(return)
BOOL VMMDLL_PidList(_Out_opt_ PDWORD pPIDs, _Inout_ PULONG64 pcPIDs);
// flags to check for existence in the fPage field of PCILEECH_VMM_MEMMAP_ENTRY
#define VMMDLL_MEMMAP_FLAG_PAGE_W 0x0000000000000002
@@ -437,6 +474,7 @@ typedef struct tdVMMDLL_MEMMAP_ENTRY {
* -- fIdentifyModules = try identify modules as well (= slower)
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ProcessGetMemoryMap(_In_ DWORD dwPID, _Out_opt_ PVMMDLL_MEMMAP_ENTRY pMemMapEntries, _Inout_ PULONG64 pcMemMapEntries, _In_ BOOL fIdentifyModules);
/*
@@ -448,6 +486,7 @@ BOOL VMMDLL_ProcessGetMemoryMap(_In_ DWORD dwPID, _Out_opt_ PVMMDLL_MEMMAP_ENTRY
* -- fIdentifyModules = try identify modules as well (= slower)
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ProcessGetMemoryMapEntry(_In_ DWORD dwPID, _Out_ PVMMDLL_MEMMAP_ENTRY pMemMapEntry, _In_ ULONG64 va, _In_ BOOL fIdentifyModules);
typedef struct tdVMMDLL_MODULEMAP_ENTRY {
@@ -469,7 +508,8 @@ typedef struct tdVMMDLL_MODULEMAP_ENTRY {
* -- pcModuleEntries = pointer to number of memory map entries.
* -- return = success/fail.
*/
BOOL VMMDLL_ProcessGetModuleMap(_In_ DWORD dwPID, _Out_ PVMMDLL_MODULEMAP_ENTRY pModuleEntries, _Inout_ PULONG64 pcModuleEntries);
_Success_(return)
BOOL VMMDLL_ProcessGetModuleMap(_In_ DWORD dwPID, _Out_opt_ PVMMDLL_MODULEMAP_ENTRY pModuleEntries, _Inout_ PULONG64 pcModuleEntries);
/*
* Retrieve a module (.exe or .dll or similar) given a module name.
@@ -478,29 +518,31 @@ BOOL VMMDLL_ProcessGetModuleMap(_In_ DWORD dwPID, _Out_ PVMMDLL_MODULEMAP_ENTRY
* -- pModuleEntry
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ProcessGetModuleFromName(_In_ DWORD dwPID, _In_ LPSTR szModuleName, _Out_ PVMMDLL_MODULEMAP_ENTRY pModuleEntry);
#define VMMDLL_PROCESS_INFORMATION_MAGIC 0xc0ffee663df9301d
#define VMMDLL_PROCESS_INFORMATION_VERSION 1
#define VMMDLL_PROCESS_INFORMATION_MAGIC 0xc0ffee663df9301e
#define VMMDLL_PROCESS_INFORMATION_VERSION 2
typedef struct tdVMMDLL_PROCESS_INFORMATION {
ULONG64 magic;
WORD wVersion;
WORD wSize;
DWORD fTargetSystem; // as given by VMMDLL_TARGET_*
BOOL fUserOnly; // only user mode pages listed
VMMDLL_MEMORYMODEL_TP tpMemoryModel; // as given by VMMDLL_MEMORYMODEL_* enum
VMMDLL_SYSTEM_TP tpSystem; // as given by VMMDLL_SYSTEM_* enum
BOOL fUserOnly; // only user mode pages listed
DWORD dwPID;
DWORD dwState;
CHAR szName[16];
ULONG64 paPML4;
ULONG64 paPML4_UserOpt; // may not exist
ULONG64 paDTB;
ULONG64 paDTB_UserOpt; // may not exist
union {
struct {
ULONG64 vaEPROCESS;
ULONG64 vaPEB;
ULONG64 vaENTRY;
BOOL fWow64;
DWORD vaPEB32; // WoW64 only
DWORD vaPEB32; // WoW64 only
} win;
} os;
} VMMDLL_PROCESS_INFORMATION, *PVMMDLL_PROCESS_INFORMATION;
@@ -513,6 +555,7 @@ typedef struct tdVMMDLL_PROCESS_INFORMATION {
* -- pcbProcessInformation = size of pProcessInfo (in bytes) on entry and exit
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ProcessGetInformation(_In_ DWORD dwPID, _Inout_opt_ PVMMDLL_PROCESS_INFORMATION pProcessInformation, _In_ PSIZE_T pcbProcessInformation);
typedef struct tdVMMDLL_EAT_ENTRY {
@@ -539,10 +582,14 @@ typedef struct tdVMMDLL_IAT_ENTRY {
* -- pcData
* -- return = success/fail.
*/
BOOL VMMDLL_ProcessGetDirectories(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PIMAGE_DATA_DIRECTORY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
BOOL VMMDLL_ProcessGetSections(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PIMAGE_SECTION_HEADER pData, _In_ DWORD cData, _Out_ PDWORD pcData);
BOOL VMMDLL_ProcessGetEAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PVMMDLL_EAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
BOOL VMMDLL_ProcessGetIAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PVMMDLL_IAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
_Success_(return)
BOOL VMMDLL_ProcessGetDirectories(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_writes_(16) PIMAGE_DATA_DIRECTORY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
_Success_(return)
BOOL VMMDLL_ProcessGetSections(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_opt_ PIMAGE_SECTION_HEADER pData, _In_ DWORD cData, _Out_ PDWORD pcData);
_Success_(return)
BOOL VMMDLL_ProcessGetEAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_opt_ PVMMDLL_EAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
_Success_(return)
BOOL VMMDLL_ProcessGetIAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_opt_ PVMMDLL_IAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
@@ -558,7 +605,8 @@ BOOL VMMDLL_ProcessGetIAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PVMMDLL_I
* -- sz = buffer to fill, NULL to retrieve size in pcsz parameter.
* -- pcsz = ptr to size of buffer on entry, size of characters on exit.
*/
BOOL VMMDLL_UtilFillHexAscii(_In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset, _Inout_ LPSTR sz, _Inout_ PDWORD pcsz);
_Success_(return)
BOOL VMMDLL_UtilFillHexAscii(_In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset, _Inout_opt_ LPSTR sz, _Out_ PDWORD pcsz);
#ifdef __cplusplus
}

View File

@@ -27,10 +27,19 @@ VMMPY_STATUS_UNSUCCESSFUL = 0xC0000001
VMMPY_STATUS_END_OF_FILE = 0xC0000011
VMMPY_STATUS_FILE_INVALID = 0xC0000098
# TARGET SYSTEM values - used to determine if a plugin is supported or not for
# SYSTEM values - used to determine if a plugin is supported or not for
# the current system that is being analyzed.
VMMPY_TARGET_UNKNOWN_X64 = 0x0001
VMMPY_TARGET_WINDOWS_X64 = 0x0002
VMMPY_SYSTEM_UNKNOWN_X64 = 0x0001
VMMPY_SYSTEM_WINDOWS_X64 = 0x0002
VMMPY_SYSTEM_UNKNOWN_X86 = 0x0003
VMMPY_SYSTEM_WINDOWS_X86 = 0x0004
# MEMORYMODEL values - used to determine if a plugin is supported or not
# for a specific memory model.
VMMPY_MEMORYMODEL_NA = 0x0000
VMMPY_MEMORYMODEL_X86 = 0x0001
VMMPY_MEMORYMODEL_X86PAE = 0x0002
VMMPY_MEMORYMODEL_X64 = 0x0003
# EVENT values - received by the notify callback function for specific events
# occuring in the native plugin manager / vmm / memory process file system.
@@ -154,7 +163,8 @@ VMMPY_OPT_CORE_VERBOSE_EXTRA = 0x80000003 # RW
VMMPY_OPT_CORE_VERBOSE_EXTRA_TLP = 0x80000004 # RW
VMMPY_OPT_CORE_MAX_NATIVE_ADDRESS = 0x80000005 # R
VMMPY_OPT_CORE_MAX_NATIVE_IOSIZE = 0x80000006 # R
VMMPY_OPT_CORE_TARGET_SYSTEM = 0x80000007 # R
VMMPY_OPT_CORE_SYSTEM = 0x80000007 # R
VMMPY_OPT_CORE_MEMORYMODEL = 0x80000008 # R
VMMPY_OPT_CONFIG_IS_REFRESH_ENABLED = 0x40000001 # R - 1/0
VMMPY_OPT_CONFIG_TICK_PERIOD = 0x40000002 # RW - base tick period in ms
@@ -383,7 +393,7 @@ def VmmPy_ProcessGetInformation(pid):
return -- dict: of process information.
Example:
VmmPy_ProcessGetInformation(332) --> {'pid': 8796, 'pa-pml4': 5798625280, 'pa-pml4-user': 6237978624, 'state': 0, 'target': 2, 'usermode': True, 'name': 'cmd.exe', 'wow64': False, 'va-entry': 140700131683072, 'va-eprocess': 18446635809067693440, 'va-peb': 708313505792, 'va-peb32': 0}
VmmPy_ProcessGetInformation(332) --> {'pid': 8796, 'pa-dtb': 5798625280, 'pa-dtb-user': 6237978624, 'state': 0, 'tp-system': 2, 'usermode': True, 'name': 'cmd.exe', 'wow64': False, 'va-entry': 140700131683072, 'va-eprocess': 18446635809067693440, 'va-peb': 708313505792, 'va-peb32': 0}
"""
return VMMPYC_ProcessGetInformation(pid)
@@ -396,7 +406,7 @@ def VmmPy_ProcessListInformation():
return -- dict: dict of process information with pid as key.
Example:
VmmPy_ProcessListInformation() --> {4: {...}, ..., 322: {'pid': 8796, 'pa-pml4': 5798625280, 'pa-pml4-user': 6237978624, 'state': 0, 'target': 2, 'usermode': True, 'name': 'cmd.exe', 'wow64': False, 'va-entry': 140700131683072, 'va-eprocess': 18446635809067693440, 'va-peb': 708313505792, 'va-peb32': 0}
VmmPy_ProcessListInformation() --> {4: {...}, ..., 322: {'pid': 8796, 'pa-dtb': 5798625280, 'pa-dtb-user': 6237978624, 'state': 0, 'tp-system': 2, 'usermode': True, 'name': 'cmd.exe', 'wow64': False, 'va-entry': 140700131683072, 'va-eprocess': 18446635809067693440, 'va-peb': 708313505792, 'va-peb32': 0}
"""
pids = VmmPy_PidList()
result = {}

Binary file not shown.

Binary file not shown.

View File

@@ -69,11 +69,13 @@ def VmmPyPlugin_InternalInitialize():
global VmmPyPlugin_IsInitialized
global VmmPyPlugin_RootDirectoryRoot
global VmmPyPlugin_RootDirectoryProcess
global VmmPyPlugin_OsTarget
global VmmPyPlugin_TargetSystem
global VmmPyPlugin_TargetMemoryModel
VmmPyPlugin_IsInitialized = True
VmmPyPlugin_RootDirectoryRoot = {}
VmmPyPlugin_RootDirectoryProcess = {}
VmmPyPlugin_OsTarget = VmmPy_ConfigGet(VMMPY_OPT_CORE_TARGET_SYSTEM)
VmmPyPlugin_TargetSystem = VmmPy_ConfigGet(VMMPY_OPT_CORE_SYSTEM)
VmmPyPlugin_TargetMemoryModel = VmmPy_ConfigGet(VMMPY_OPT_CORE_MEMORYMODEL)
VmmPyPlugin_InternalSetVerbosity();
VmmPyPlugin_InternalInitializePlugins()
VMMPYCC_CallbackRegister(
@@ -102,7 +104,7 @@ def VmmPyPlugin_InternalInitializePlugins():
for e in plugin_names:
try:
module = importlib.import_module(e)
module.Initialize(VmmPyPlugin_OsTarget)
module.Initialize(VmmPyPlugin_TargetSystem, VmmPyPlugin_TargetMemoryModel)
VmmPyPlugin_PluginModules.append(module)
if VmmPyPlugin_fPrintV:
print("VmmPyPlugin: Loaded '" + e + "'")

View File

@@ -10,7 +10,7 @@
ULONG64 VMemD_GetBaseFromFileName(LPSTR sz)
{
if((strlen(sz) < 18) || (sz[0] != '0') || (sz[1] != 'x')) { return (ULONG64)-1; }
if((strlen(sz) < 15) || (sz[0] != '0') || (sz[1] != 'x')) { return (ULONG64)-1; }
return strtoull(sz, NULL, 16);
}
@@ -100,13 +100,23 @@ BOOL VMemD_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList)
return FALSE;
}
for(i = 0; i < cEntries; i++) {
sprintf_s(
szBufferFileName,
MAX_PATH - 1,
"0x%016llx%s%s.vmem",
pMemMap[i].AddrBase,
pMemMap[i].szTag[0] ? "-" : "",
pMemMap[i].szTag[0] ? pMemMap[i].szTag : "");
if(32 == (ULONG64)*ctx->phModulePrivate) {
sprintf_s(
szBufferFileName,
MAX_PATH - 1,
"0x%08x%s%s.vmem",
(DWORD)pMemMap[i].AddrBase,
pMemMap[i].szTag[0] ? "-" : "",
pMemMap[i].szTag[0] ? pMemMap[i].szTag : "");
} else {
sprintf_s(
szBufferFileName,
MAX_PATH - 1,
"0x%016llx%s%s.vmem",
pMemMap[i].AddrBase,
pMemMap[i].szTag[0] ? "-" : "",
pMemMap[i].szTag[0] ? pMemMap[i].szTag : "");
}
VMMDLL_VfsList_AddFile(pFileList, szBufferFileName, (pMemMap[i].cPages << 12));
}
LocalFree(pMemMap);
@@ -125,11 +135,15 @@ BOOL VMemD_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList)
__declspec(dllexport)
VOID InitializeVmmPlugin(_In_ PVMMDLL_PLUGIN_REGINFO pRegInfo)
{
if(0 == (pRegInfo->fTargetSystem & (VMMDLL_TARGET_UNKNOWN_X64 | VMMDLL_TARGET_WINDOWS_X64))) { return; }
if((pRegInfo->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRegInfo->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; }
// Ensure that the plugin support the memory model that is used. The plugin
// currently supports the 64-bit x64 and 32-bit x86 and x86-pae memory models.
if(!((pRegInfo->tpMemoryModel == VMMDLL_MEMORYMODEL_X64) || (pRegInfo->tpMemoryModel == VMMDLL_MEMORYMODEL_X86) || (pRegInfo->tpMemoryModel == VMMDLL_MEMORYMODEL_X86PAE))) { return; }
strcpy_s(pRegInfo->reg_info.szModuleName, 32, "vmemd"); // module name - 'vmemd'.
pRegInfo->reg_info.fProcessModule = TRUE; // module shows in process directory.
pRegInfo->reg_fn.pfnList = VMemD_List; // List function supported.
pRegInfo->reg_fn.pfnRead = VMemD_Read; // Read function supported.
pRegInfo->reg_fn.pfnWrite = VMemD_Write; // Write function supported.
pRegInfo->reg_info.hModulePrivate = (HANDLE)(ULONG64)((pRegInfo->tpMemoryModel == VMMDLL_MEMORYMODEL_X64) ? 64 : 32); // use handle for "bitness".
pRegInfo->pfnPluginManager_Register(pRegInfo); // Register with the plugin maanger.
}

View File

@@ -23,6 +23,7 @@ extern "C" {
* Call other VMMDLL_Intialize functions to initialize VMM.DLL and the memory
* process file system.
*/
_Success_(return)
BOOL VMMDLL_InitializeReserved(_In_ DWORD argc, _In_ LPSTR argv[]);
/*
@@ -37,6 +38,7 @@ BOOL VMMDLL_InitializeReserved(_In_ DWORD argc, _In_ LPSTR argv[]);
* as hex string. NB! this is usally not required. Example: "0x1ab000".
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeFile(_In_ LPSTR szFileName, _In_opt_ LPSTR szPageTableBaseOpt);
/*
@@ -52,6 +54,7 @@ BOOL VMMDLL_InitializeFile(_In_ LPSTR szFileName, _In_opt_ LPSTR szPageTableBase
* as hex string. NB! this is usally not required. Example: "0x1ab000".
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeFPGA(_In_opt_ LPSTR szMaxPhysicalAddressOpt, _In_opt_ LPSTR szPageTableBaseOpt);
/*
@@ -60,6 +63,7 @@ BOOL VMMDLL_InitializeFPGA(_In_opt_ LPSTR szMaxPhysicalAddressOpt, _In_opt_ LPST
* initialized in read/write mode upon success.
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeTotalMeltdown();
/*
@@ -67,6 +71,7 @@ BOOL VMMDLL_InitializeTotalMeltdown();
* including plugins, linked PCILeech.DLL and other memory resources.
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_Close();
@@ -103,7 +108,8 @@ BOOL VMMDLL_Close();
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA_TLP 0x80000004 // RW
#define VMMDLL_OPT_CORE_MAX_NATIVE_ADDRESS 0x80000005 // R
#define VMMDLL_OPT_CORE_MAX_NATIVE_IOSIZE 0x80000006 // R
#define VMMDLL_OPT_CORE_TARGET_SYSTEM 0x80000007 // R
#define VMMDLL_OPT_CORE_SYSTEM 0x80000007 // R
#define VMMDLL_OPT_CORE_MEMORYMODEL 0x80000008 // R
#define VMMDLL_OPT_CONFIG_IS_REFRESH_ENABLED 0x40000001 // R - 1/0
#define VMMDLL_OPT_CONFIG_TICK_PERIOD 0x40000002 // RW - base tick period in ms
@@ -116,6 +122,22 @@ BOOL VMMDLL_Close();
#define VMMDLL_OPT_CONFIG_VMM_VERSION_REVISION 0x40000009 // R
#define VMMDLL_OPT_CONFIG_STATISTICS_FUNCTIONCALL 0x4000000A // RW - enable function call statistics (.status/statistics_fncall file)
static const LPSTR VMMDLL_MEMORYMODEL_TOSTRING[4] = { "N/A", "X86", "X86PAE", "X64" };
typedef enum tdVMMDLL_MEMORYMODEL_TP {
VMMDLL_MEMORYMODEL_NA = 0,
VMMDLL_MEMORYMODEL_X86 = 1,
VMMDLL_MEMORYMODEL_X86PAE = 2,
VMMDLL_MEMORYMODEL_X64 = 3
} VMMDLL_MEMORYMODEL_TP;
typedef enum tdVMMDLL_SYSTEM_TP {
VMMDLL_SYSTEM_UNKNOWN_X64 = 1,
VMMDLL_SYSTEM_WINDOWS_X64 = 2,
VMMDLL_SYSTEM_UNKNOWN_X86 = 3,
VMMDLL_SYSTEM_WINDOWS_X86 = 4
} VMMDLL_SYSTEM_TP;
/*
* Set a device specific option value. Please see defines VMMDLL_OPT_* for infor-
* mation about valid option values. Please note that option values may overlap
@@ -124,6 +146,7 @@ BOOL VMMDLL_Close();
* -- pqwValue = pointer to ULONG64 to receive option value.
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ConfigGet(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue);
/*
@@ -134,6 +157,7 @@ BOOL VMMDLL_ConfigGet(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue);
* -- qwValue
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ConfigSet(_In_ ULONG64 fOption, _In_ ULONG64 qwValue);
@@ -171,6 +195,7 @@ typedef struct tdVMMDLL_VFS_FILELIST {
* -- pFileList
* -- return
*/
_Success_(return)
BOOL VMMDLL_VfsList(_In_ LPCWSTR wcsPath, _Inout_ PVMMDLL_VFS_FILELIST pFileList);
/*
@@ -227,12 +252,13 @@ NTSTATUS VMMDLL_UtilVfsWriteFile_DWORD(_Inout_ PDWORD pdwTarget, _In_ LPVOID pb,
* will be unloaded on a general close of the vmm dll.
* -- return
*/
_Success_(return)
BOOL VMMDLL_VfsInitializePlugins();
#define VMMDLL_PLUGIN_CONTEXT_MAGIC 0xc0ffee663df9301c
#define VMMDLL_PLUGIN_CONTEXT_VERSION 1
#define VMMDLL_PLUGIN_REGINFO_MAGIC 0xc0ffee663df9301d
#define VMMDLL_PLUGIN_REGINFO_VERSION 1
#define VMMDLL_PLUGIN_REGINFO_VERSION 2
#define VMMDLL_PLUGIN_EVENT_VERBOSITYCHANGE 0x01
@@ -254,7 +280,8 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
ULONG64 magic;
WORD wVersion;
WORD wSize;
DWORD fTargetSystem;
VMMDLL_MEMORYMODEL_TP tpMemoryModel;
VMMDLL_SYSTEM_TP tpSystem;
HMODULE hDLL;
HMODULE hReservedDll; // not for general use (only used for python).
BOOL(*pfnPluginManager_Register)(struct tdVMMDLL_PLUGIN_REGINFO *pPluginRegInfo);
@@ -272,7 +299,7 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
// function plugin registration info to be filled out by the plugin below:
struct {
BOOL(*pfnList)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList);
NTSTATUS(*pfnRead)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset);
NTSTATUS(*pfnRead)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset);
NTSTATUS(*pfnWrite)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset);
VOID(*pfnNotify)(_Inout_opt_ PHANDLE phModulePrivate, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent);
VOID(*pfnCloseHandleModule)(_Inout_opt_ PHANDLE phModulePrivate);
@@ -296,8 +323,7 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
#define VMMDLL_FLAG_NOCACHE 0x0001 // do not use the data cache (force reading from memory acquisition device)
#define VMMDLL_FLAG_ZEROPAD_ON_FAIL 0x0002 // zero pad failed physical memory reads and report success if read within range of physical memory.
#define VMMDLL_TARGET_UNKNOWN_X64 0x0001
#define VMMDLL_TARGET_WINDOWS_X64 0x0002
#define VMMDLL_MEM_IO_SCATTER_HEADER_VERSION 2
typedef struct tdVMMDLL_MEM_IO_SCATTER_HEADER {
ULONG64 qwA; // base address (DWORD boundry).
@@ -306,6 +332,10 @@ typedef struct tdVMMDLL_MEM_IO_SCATTER_HEADER {
PBYTE pb; // ptr to 0x1000 sized buffer to receive read bytes.
PVOID pvReserved1; // reserved for use by caller.
PVOID pvReserved2; // reserved for use by caller.
WORD version; // version of struct
WORD Future1; // reserved for future use.
DWORD Future2; // reserved for future use.
ULONG64 qwDeviceA; // device-physical address (used by device layer).
struct {
PVOID pvReserved1;
PVOID pvReserved2;
@@ -335,6 +365,7 @@ DWORD VMMDLL_MemReadScatter(_In_ DWORD dwPID, _Inout_ PPVMMDLL_MEM_IO_SCATTER_HE
* -- pbPage
* -- return = success/fail (depending if all requested bytes are read or not).
*/
_Success_(return)
BOOL VMMDLL_MemReadPage(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_bytecount_(4096) PBYTE pbPage);
/*
@@ -345,6 +376,7 @@ BOOL VMMDLL_MemReadPage(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_bytecount_(4
* -- cb
* -- return = success/fail (depending if all requested bytes are read or not).
*/
_Success_(return)
BOOL VMMDLL_MemRead(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DWORD cb);
/*
@@ -358,7 +390,8 @@ BOOL VMMDLL_MemRead(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DW
* -- return = success/fail. NB! reads may report as success even if 0 bytes are
* read - it's recommended to verify pcbReadOpt parameter.
*/
BOOL VMMDLL_MemReadEx(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ ULONG64 flags);
_Success_(return)
BOOL VMMDLL_MemReadEx(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ ULONG64 flags);
/*
* Write a contigious arbitrary amount of memory. Please note some virtual memory
@@ -373,7 +406,8 @@ BOOL VMMDLL_MemReadEx(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_ PBYTE pb, _In
* -- cb
* -- return = TRUE on success, FALSE on partial or zero write.
*/
BOOL VMMDLL_MemWrite(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DWORD cb);
_Success_(return)
BOOL VMMDLL_MemWrite(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _In_ PBYTE pb, _In_ DWORD cb);
/*
* Translate a virtual address to a physical address by walking the page tables
@@ -383,6 +417,7 @@ BOOL VMMDLL_MemWrite(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ D
* -- pqwPA
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_MemVirt2Phys(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PULONG64 pqwPA);
@@ -401,6 +436,7 @@ BOOL VMMDLL_MemVirt2Phys(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PULONG64 pqw
* -- pdwPID = pointer that will receive PID on success.
* -- return
*/
_Success_(return)
BOOL VMMDLL_PidGetFromName(_In_ LPSTR szProcName, _Out_ PDWORD pdwPID);
/*
@@ -409,7 +445,8 @@ BOOL VMMDLL_PidGetFromName(_In_ LPSTR szProcName, _Out_ PDWORD pdwPID);
* -- pcPIDs = size of (in number of DWORDs) pPIDs array on entry, number of PIDs in system on exit.
* -- return = success/fail.
*/
BOOL VMMDLL_PidList(_Out_ PDWORD pPIDs, _Inout_ PULONG64 pcPIDs);
_Success_(return)
BOOL VMMDLL_PidList(_Out_opt_ PDWORD pPIDs, _Inout_ PULONG64 pcPIDs);
// flags to check for existence in the fPage field of PCILEECH_VMM_MEMMAP_ENTRY
#define VMMDLL_MEMMAP_FLAG_PAGE_W 0x0000000000000002
@@ -437,6 +474,7 @@ typedef struct tdVMMDLL_MEMMAP_ENTRY {
* -- fIdentifyModules = try identify modules as well (= slower)
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ProcessGetMemoryMap(_In_ DWORD dwPID, _Out_opt_ PVMMDLL_MEMMAP_ENTRY pMemMapEntries, _Inout_ PULONG64 pcMemMapEntries, _In_ BOOL fIdentifyModules);
/*
@@ -448,6 +486,7 @@ BOOL VMMDLL_ProcessGetMemoryMap(_In_ DWORD dwPID, _Out_opt_ PVMMDLL_MEMMAP_ENTRY
* -- fIdentifyModules = try identify modules as well (= slower)
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ProcessGetMemoryMapEntry(_In_ DWORD dwPID, _Out_ PVMMDLL_MEMMAP_ENTRY pMemMapEntry, _In_ ULONG64 va, _In_ BOOL fIdentifyModules);
typedef struct tdVMMDLL_MODULEMAP_ENTRY {
@@ -469,7 +508,8 @@ typedef struct tdVMMDLL_MODULEMAP_ENTRY {
* -- pcModuleEntries = pointer to number of memory map entries.
* -- return = success/fail.
*/
BOOL VMMDLL_ProcessGetModuleMap(_In_ DWORD dwPID, _Out_ PVMMDLL_MODULEMAP_ENTRY pModuleEntries, _Inout_ PULONG64 pcModuleEntries);
_Success_(return)
BOOL VMMDLL_ProcessGetModuleMap(_In_ DWORD dwPID, _Out_opt_ PVMMDLL_MODULEMAP_ENTRY pModuleEntries, _Inout_ PULONG64 pcModuleEntries);
/*
* Retrieve a module (.exe or .dll or similar) given a module name.
@@ -478,29 +518,31 @@ BOOL VMMDLL_ProcessGetModuleMap(_In_ DWORD dwPID, _Out_ PVMMDLL_MODULEMAP_ENTRY
* -- pModuleEntry
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ProcessGetModuleFromName(_In_ DWORD dwPID, _In_ LPSTR szModuleName, _Out_ PVMMDLL_MODULEMAP_ENTRY pModuleEntry);
#define VMMDLL_PROCESS_INFORMATION_MAGIC 0xc0ffee663df9301d
#define VMMDLL_PROCESS_INFORMATION_VERSION 1
#define VMMDLL_PROCESS_INFORMATION_MAGIC 0xc0ffee663df9301e
#define VMMDLL_PROCESS_INFORMATION_VERSION 2
typedef struct tdVMMDLL_PROCESS_INFORMATION {
ULONG64 magic;
WORD wVersion;
WORD wSize;
DWORD fTargetSystem; // as given by VMMDLL_TARGET_*
BOOL fUserOnly; // only user mode pages listed
VMMDLL_MEMORYMODEL_TP tpMemoryModel; // as given by VMMDLL_MEMORYMODEL_* enum
VMMDLL_SYSTEM_TP tpSystem; // as given by VMMDLL_SYSTEM_* enum
BOOL fUserOnly; // only user mode pages listed
DWORD dwPID;
DWORD dwState;
CHAR szName[16];
ULONG64 paPML4;
ULONG64 paPML4_UserOpt; // may not exist
ULONG64 paDTB;
ULONG64 paDTB_UserOpt; // may not exist
union {
struct {
ULONG64 vaEPROCESS;
ULONG64 vaPEB;
ULONG64 vaENTRY;
BOOL fWow64;
DWORD vaPEB32; // WoW64 only
DWORD vaPEB32; // WoW64 only
} win;
} os;
} VMMDLL_PROCESS_INFORMATION, *PVMMDLL_PROCESS_INFORMATION;
@@ -513,6 +555,7 @@ typedef struct tdVMMDLL_PROCESS_INFORMATION {
* -- pcbProcessInformation = size of pProcessInfo (in bytes) on entry and exit
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ProcessGetInformation(_In_ DWORD dwPID, _Inout_opt_ PVMMDLL_PROCESS_INFORMATION pProcessInformation, _In_ PSIZE_T pcbProcessInformation);
typedef struct tdVMMDLL_EAT_ENTRY {
@@ -539,10 +582,14 @@ typedef struct tdVMMDLL_IAT_ENTRY {
* -- pcData
* -- return = success/fail.
*/
BOOL VMMDLL_ProcessGetDirectories(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PIMAGE_DATA_DIRECTORY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
BOOL VMMDLL_ProcessGetSections(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PIMAGE_SECTION_HEADER pData, _In_ DWORD cData, _Out_ PDWORD pcData);
BOOL VMMDLL_ProcessGetEAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PVMMDLL_EAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
BOOL VMMDLL_ProcessGetIAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PVMMDLL_IAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
_Success_(return)
BOOL VMMDLL_ProcessGetDirectories(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_writes_(16) PIMAGE_DATA_DIRECTORY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
_Success_(return)
BOOL VMMDLL_ProcessGetSections(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_opt_ PIMAGE_SECTION_HEADER pData, _In_ DWORD cData, _Out_ PDWORD pcData);
_Success_(return)
BOOL VMMDLL_ProcessGetEAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_opt_ PVMMDLL_EAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
_Success_(return)
BOOL VMMDLL_ProcessGetIAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_opt_ PVMMDLL_IAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
@@ -558,7 +605,8 @@ BOOL VMMDLL_ProcessGetIAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PVMMDLL_I
* -- sz = buffer to fill, NULL to retrieve size in pcsz parameter.
* -- pcsz = ptr to size of buffer on entry, size of characters on exit.
*/
BOOL VMMDLL_UtilFillHexAscii(_In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset, _Inout_ LPSTR sz, _Inout_ PDWORD pcsz);
_Success_(return)
BOOL VMMDLL_UtilFillHexAscii(_In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset, _Inout_opt_ LPSTR sz, _Out_ PDWORD pcsz);
#ifdef __cplusplus
}

View File

@@ -90,11 +90,13 @@ BOOL DeviceOpen()
return result;
}
_Success_(return)
BOOL DeviceGetOption(_In_ QWORD fOption, _Out_ PQWORD pqwValue)
{
return ctxMain->dev.pfnGetOption && ctxMain->dev.pfnGetOption(fOption, pqwValue);
}
_Success_(return)
BOOL DeviceSetOption(_In_ QWORD fOption, _In_ QWORD qwValue)
{
return ctxMain->dev.pfnSetOption && ctxMain->dev.pfnSetOption(fOption, qwValue);
@@ -122,7 +124,7 @@ DWORD DeviceReadMEMEx_DoWork_Scatter(_In_ QWORD qwAddr, _Out_ PBYTE pb, _In_ DWO
PageStatUpdate(pPageStat, pDMAs[i].qwA + 0x1000, 1, 0);
} else {
PageStatUpdate(pPageStat, pDMAs[i].qwA + 0x1000, 0, 1);
ZeroMemory(pDMAs[i].pb, 0x1000);
ZeroMemory(pDMAs[i].pb, pDMAs[i].cbMax);
}
}
LocalFree(pbBuffer);
@@ -148,17 +150,17 @@ DWORD DeviceReadMEMEx_DoWork(_In_ QWORD qwAddr, _Out_ PBYTE pb, _In_ DWORD cb, _
return cbSuccess;
}
DWORD DeviceReadMEMEx(_In_ QWORD qwAddr, _Out_ PBYTE pb, _In_ DWORD cb, _Inout_opt_ PPAGE_STATISTICS pPageStat)
DWORD DeviceReadMEMEx(_In_ QWORD qwAddr, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _Inout_opt_ PPAGE_STATISTICS pPageStat)
{
BYTE pbWorkaround[4096];
DWORD cbDataRead;
// read memory (with strange workaround for 1-page reads...)
if(cb != 0x1000) {
if(cb > 0x1000) {
cbDataRead = DeviceReadMEMEx_DoWork(qwAddr, pb, cb, pPageStat, (DWORD)ctxMain->dev.qwMaxSizeMemIo);
} else {
// why is this working ??? if not here console is screwed up... (threading issue?)
cbDataRead = DeviceReadMEMEx_DoWork(qwAddr, pbWorkaround, 0x1000, pPageStat, (DWORD)ctxMain->dev.qwMaxSizeMemIo);
memcpy(pb, pbWorkaround, 0x1000);
memcpy(pb, pbWorkaround, cb);
}
return cbDataRead;
}

View File

@@ -40,7 +40,7 @@ VOID DeviceReadScatterMEM(_Inout_ PPMEM_IO_SCATTER_HEADER ppMEMs, _In_ DWORD cpM
* -- pPageStat = optional page statistics
* -- return = the number of bytes successfully read.
*/
DWORD DeviceReadMEMEx(_In_ QWORD qwAddr, _Out_ PBYTE pb, _In_ DWORD cb, _Inout_opt_ PPAGE_STATISTICS pPageStat);
DWORD DeviceReadMEMEx(_In_ QWORD qwAddr, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _Inout_opt_ PPAGE_STATISTICS pPageStat);
/*
* Write data to the target system using DMA.
@@ -58,6 +58,7 @@ BOOL DeviceWriteMEM(_In_ QWORD qwAddr, _In_ PBYTE pb, _In_ DWORD cb);
* -- pqwValue = pointer to QWORD to receive option value.
* -- return
*/
_Success_(return)
BOOL DeviceGetOption(_In_ QWORD fOption, _Out_ PQWORD pqwValue);
/*
@@ -67,6 +68,7 @@ BOOL DeviceGetOption(_In_ QWORD fOption, _Out_ PQWORD pqwValue);
* -- qwValue
* -- return
*/
_Success_(return)
BOOL DeviceSetOption(_In_ QWORD fOption, _In_ QWORD qwValue);
#endif /* __DEVICE_H__ */

View File

@@ -31,7 +31,10 @@ VOID DevicePCILeechDll_ReadScatterMEM(_Inout_ PPMEM_IO_SCATTER_HEADER ppMEMs, _I
{
DWORD cMEMsRead;
PDEVICE_CONTEXT_PCILEECH_DLL ctxDll = (PDEVICE_CONTEXT_PCILEECH_DLL)ctxMain->dev.hDevice;
if(!ctxDll) { return; }
if(!ctxDll) {
if(pcMEMsRead) { *pcMEMsRead = 0; }
return;
}
cMEMsRead = ctxDll->PCILeech_DeviceReadScatterMEM(ppMEMs, cpMEMs);
if(pcMEMsRead) {
*pcMEMsRead = cMEMsRead;
@@ -41,7 +44,7 @@ VOID DevicePCILeechDll_ReadScatterMEM(_Inout_ PPMEM_IO_SCATTER_HEADER ppMEMs, _I
BOOL DevicePCILeechDll_GetOption(_In_ QWORD fOption, _Out_ PQWORD pqwValue)
{
PDEVICE_CONTEXT_PCILEECH_DLL ctxDll = (PDEVICE_CONTEXT_PCILEECH_DLL)ctxMain->dev.hDevice;
if(!ctxDll) { return FALSE; }
if(!ctxDll) { *pqwValue = 0; return FALSE; }
return ctxDll->PCIleech_DeviceConfigGet(fOption, pqwValue);
}

View File

@@ -6,9 +6,10 @@
#include "m_ldrmodules.h"
#include "pluginmanager.h"
#include "vmm.h"
#include "vmmproc_windows.h"
#include "vmmwin.h"
#include "vmmvfs.h"
#include "util.h"
#include "pe.h"
#define LDRMODULES_CACHE_TP_EAT 1
#define LDRMODULES_CACHE_TP_IAT 2
@@ -82,7 +83,7 @@ PLDRMODULES_CACHE_ENTRY LdrModule_GetEAT(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ P
cEATs = LDRMODULES_MAX_IATEAT;
pEATs = LocalAlloc(0, LDRMODULES_MAX_IATEAT * sizeof(VMMPROC_WINDOWS_EAT_ENTRY));
if(!pEATs) { goto fail; }
VmmProcWindows_PE_LoadEAT_DisplayBuffer(ctx->pProcess, pModule, pEATs, &cEATs);
VmmWin_PE_LoadEAT_DisplayBuffer(ctx->pProcess, pModule, pEATs, &cEATs);
if(!cEATs) { goto fail; }
// 3: fill "display buffer"
pCacheEntry->cb = cEATs * 64 + 1;
@@ -109,16 +110,16 @@ fail:
PLDRMODULES_CACHE_ENTRY LdrModule_GetIAT(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ PVMM_MODULEMAP_ENTRY pModule)
{
DWORD i, o, cIATs;
PVMMPROC_WINDOWS_IAT_ENTRY pIATs = NULL;
PVMMWIN_IAT_ENTRY pIATs = NULL;
PLDRMODULES_CACHE_ENTRY pCacheEntry;
// 1: retrieve cache
pCacheEntry = LdrModule_GetCacheEntry(ctx, pModule->szName, LDRMODULES_CACHE_TP_IAT);
if(pCacheEntry->pb) { return pCacheEntry; }
// 2: retrieve exported functions
cIATs = LDRMODULES_MAX_IATEAT;
pIATs = LocalAlloc(0, LDRMODULES_MAX_IATEAT * sizeof(VMMPROC_WINDOWS_IAT_ENTRY));
pIATs = LocalAlloc(0, LDRMODULES_MAX_IATEAT * sizeof(VMMWIN_IAT_ENTRY));
if(!pIATs) { goto fail; }
VmmProcWindows_PE_LoadIAT_DisplayBuffer(ctx->pProcess, pModule, pIATs, &cIATs);
VmmWin_PE_LoadIAT_DisplayBuffer(ctx->pProcess, pModule, pIATs, &cIATs);
if(!cIATs) { goto fail; }
// 3: fill "display buffer"
pCacheEntry->cb = cIATs * 128 + 1;
@@ -143,6 +144,112 @@ fail:
return NULL;
}
/*
* Helper write function - Write to a virtual memory backed "file".
*/
VOID LdrModules_Write_MemFile(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaMem, _In_ QWORD cbMem, _In_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset)
{
if(cbMem <= cbOffset) { *pcbWrite = 0; return; }
*pcbWrite = (DWORD)min(cb, cbMem - cbOffset);
VmmWrite(pProcess, vaMem + cbOffset, pb, *pcbWrite);
}
/*
* Helper write function - Write to the requested data directory file.
*/
VOID LdrModules_Write_DirectoriesD(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MODULEMAP_ENTRY pModule, _In_ LPSTR szDirectory, _In_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset)
{
DWORD i;
IMAGE_DATA_DIRECTORY pDataDirectories[16];
*pcbWrite = 0;
for(i = 0; i < 16; i++) {
if(!strcmp(szDirectory, PE_DATA_DIRECTORIES[i])) {
VmmWin_PE_DIRECTORY_DisplayBuffer(pProcess, pModule, NULL, 0, NULL, pDataDirectories);
LdrModules_Write_MemFile(pProcess, pModule->BaseAddress + pDataDirectories[i].VirtualAddress, pDataDirectories[i].Size, pb, cb, pcbWrite, cbOffset);
}
}
}
/*
* Helper write function - Write to the requested section header file.
*/
VOID LdrModules_Write_SectionsD(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MODULEMAP_ENTRY pModule, _In_ LPSTR szSection, _In_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset)
{
IMAGE_SECTION_HEADER SectionHeader;
if(!PE_SectionGetFromName(pProcess, pModule->BaseAddress, szSection, &SectionHeader)) { *pcbWrite = 0; return; }
LdrModules_Write_MemFile(pProcess, pModule->BaseAddress + SectionHeader.VirtualAddress, SectionHeader.Misc.VirtualSize, pb, cb, pcbWrite, cbOffset);
}
/*
* Write : function as specified by the module manager. The module manager will
* call into this callback function whenever a write shall occur from a "file".
* -- ctx
* -- pb
* -- cb
* -- pcbWrite
* -- cbOffset
* -- return
*/
NTSTATUS LdrModules_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset)
{
DWORD i;
CHAR _szBuf[MAX_PATH] = { 0 };
LPSTR szPath1, szPath2;
PVMM_PROCESS pProcess = (PVMM_PROCESS)ctx->pProcess;
*pcbWrite = 0;
Util_PathSplit2(ctx->szPath, _szBuf, &szPath1, &szPath2);
if(szPath1[0] && szPath2[0]) {
for(i = 0; i < pProcess->cModuleMap; i++) {
if(0 == strncmp(szPath1, pProcess->pModuleMap[i].szName, MAX_PATH)) {
if(!_strnicmp(szPath2, "sectionsd\\", 10)) {
LdrModules_Write_SectionsD(pProcess, pProcess->pModuleMap + i, szPath2 + 10, pb, cb, pcbWrite, cbOffset);
}
if(!_strnicmp(szPath2, "directoriesd\\", 13)) {
LdrModules_Write_DirectoriesD(pProcess, pProcess->pModuleMap + i, szPath2 + 13, pb, cb, pcbWrite, cbOffset);
}
break;
}
}
}
return VMM_STATUS_SUCCESS;
}
/*
* Helper read function - Read a virtual memory backed "file".
*/
NTSTATUS LdrModules_Read_MemFile(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaMem, _In_ QWORD cbMem, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset)
{
if(cbMem <= cbOffset) { return VMM_STATUS_END_OF_FILE; }
VmmReadEx(pProcess, vaMem + cbOffset, pb, (DWORD)min(cb, cbMem - cbOffset), pcbRead, 0);
return *pcbRead ? VMMDLL_STATUS_SUCCESS : VMMDLL_STATUS_END_OF_FILE;
}
/*
* Helper read function - Read the requested data directory file.
*/
NTSTATUS LdrModules_Read_DirectoriesD(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MODULEMAP_ENTRY pModule, _In_ LPSTR szDirectory, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset)
{
DWORD i;
IMAGE_DATA_DIRECTORY pDataDirectories[16];
for(i = 0; i < 16; i++) {
if(!strcmp(szDirectory, PE_DATA_DIRECTORIES[i])) {
VmmWin_PE_DIRECTORY_DisplayBuffer(pProcess, pModule, NULL, 0, NULL, pDataDirectories);
return LdrModules_Read_MemFile(pProcess, pModule->BaseAddress + pDataDirectories[i].VirtualAddress, pDataDirectories[i].Size, pb, cb, pcbRead, cbOffset);
}
}
return VMMDLL_STATUS_FILE_INVALID;
}
/*
* Helper read function - Read the requested section header file.
*/
NTSTATUS LdrModules_Read_SectionsD(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MODULEMAP_ENTRY pModule, _In_ LPSTR szSection, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset)
{
IMAGE_SECTION_HEADER SectionHeader;
if(!PE_SectionGetFromName(pProcess, pModule->BaseAddress, szSection, &SectionHeader)) { return VMMDLL_STATUS_FILE_INVALID; }
return LdrModules_Read_MemFile(pProcess, pModule->BaseAddress + SectionHeader.VirtualAddress, SectionHeader.Misc.VirtualSize, pb, cb, pcbRead, cbOffset);
}
/*
* Read : function as specified by the module manager. The module manager will
* call into this callback function whenever a read shall occur from a "file".
@@ -162,6 +269,7 @@ NTSTATUS LdrModules_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_
PLDRMODULES_CACHE_ENTRY pCacheEntry;
PVMM_PROCESS pProcess = (PVMM_PROCESS)ctx->pProcess;
Util_PathSplit2(ctx->szPath, _szBuf, &szPath1, &szPath2);
*pcbRead = 0;
if(szPath1[0] && szPath2[0]) {
for(i = 0; i < pProcess->cModuleMap; i++) {
if(0 == strncmp(szPath1, pProcess->pModuleMap[i].szName, MAX_PATH)) {
@@ -175,7 +283,7 @@ NTSTATUS LdrModules_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_
return Util_VfsReadFile_FromDWORD(pProcess->pModuleMap[i].SizeOfImage, pb, cb, pcbRead, cbOffset, FALSE);
}
if(!_stricmp(szPath2, "directories")) {
VmmProcWindows_PE_DIRECTORY_DisplayBuffer(ctx->pProcess, pProcess->pModuleMap + i, pbBuffer, 0x400, &cbBuffer, NULL);
VmmWin_PE_DIRECTORY_DisplayBuffer(ctx->pProcess, pProcess->pModuleMap + i, pbBuffer, 0x400, &cbBuffer, NULL);
return Util_VfsReadFile_FromPBYTE(pbBuffer, cbBuffer, pb, cb, pcbRead, cbOffset);
}
if(!_stricmp(szPath2, "export")) {
@@ -189,9 +297,15 @@ NTSTATUS LdrModules_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_
return Util_VfsReadFile_FromPBYTE(pCacheEntry->pb, pCacheEntry->cb, pb, cb, pcbRead, cbOffset);
}
if(!_stricmp(szPath2, "sections")) {
VmmProcWindows_PE_SECTION_DisplayBuffer(ctx->pProcess, pProcess->pModuleMap + i, pbBuffer, 0x800, &cbBuffer, NULL);
VmmWin_PE_SECTION_DisplayBuffer(ctx->pProcess, pProcess->pModuleMap + i, pbBuffer, 0x800, &cbBuffer, NULL, NULL);
return Util_VfsReadFile_FromPBYTE(pbBuffer, cbBuffer, pb, cb, pcbRead, cbOffset);
}
if(!_strnicmp(szPath2, "sectionsd\\", 10)) {
return LdrModules_Read_SectionsD(pProcess, pProcess->pModuleMap + i, szPath2 + 10, pb, cb, pcbRead, cbOffset);
}
if(!_strnicmp(szPath2, "directoriesd\\", 13)) {
return LdrModules_Read_DirectoriesD(pProcess, pProcess->pModuleMap + i, szPath2 + 13, pb, cb, pcbRead, cbOffset);
}
return VMMDLL_STATUS_FILE_INVALID;
}
}
@@ -209,9 +323,12 @@ NTSTATUS LdrModules_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_
*/
BOOL LdrModules_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList)
{
DWORD i;
DWORD c, i;
CHAR _szBuf[MAX_PATH] = { 0 };
LPSTR szPath1, szPath2;
PVMM_MODULEMAP_ENTRY pModule = NULL;
PIMAGE_SECTION_HEADER pSections = NULL;
IMAGE_DATA_DIRECTORY pDataDirectories[16];
PVMM_PROCESS pProcess = (PVMM_PROCESS)ctx->pProcess;
// modules root directory -> add directory per DLL
if(!ctx->szPath[0]) {
@@ -222,21 +339,47 @@ BOOL LdrModules_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList)
}
// individual module directory -> list files
Util_PathSplit2(ctx->szPath, _szBuf, &szPath1, &szPath2);
if(!szPath2[0]) {
for(i = 0; i < pProcess->cModuleMap; i++) {
if(0 == strncmp(szPath1, pProcess->pModuleMap[i].szName, MAX_PATH)) {
VmmProcWindows_PE_SetSizeSectionIATEAT_DisplayBuffer(ctx->pProcess, pProcess->pModuleMap + i);
VMMDLL_VfsList_AddFile(pFileList, "base", 16);
VMMDLL_VfsList_AddFile(pFileList, "entry", 16);
VMMDLL_VfsList_AddFile(pFileList, "size", 8);
VMMDLL_VfsList_AddFile(pFileList, "directories", 864);
VMMDLL_VfsList_AddFile(pFileList, "export", pProcess->pModuleMap[i].cbDisplayBufferEAT);
VMMDLL_VfsList_AddFile(pFileList, "import", pProcess->pModuleMap[i].cbDisplayBufferIAT);
VMMDLL_VfsList_AddFile(pFileList, "sections", pProcess->pModuleMap[i].cbDisplayBufferSections);
return TRUE;
}
for(i = 0; i < pProcess->cModuleMap; i++) {
if(0 == strncmp(szPath1, pProcess->pModuleMap[i].szName, 32)) {
pModule = pProcess->pModuleMap + i;
break;
}
return FALSE;
}
if(!pModule) { return FALSE; }
// module-specific 'root' directory
if(!szPath2[0]) {
VmmWin_PE_SetSizeSectionIATEAT_DisplayBuffer(ctx->pProcess, pProcess->pModuleMap + i);
VMMDLL_VfsList_AddFile(pFileList, "base", 16);
VMMDLL_VfsList_AddFile(pFileList, "entry", 16);
VMMDLL_VfsList_AddFile(pFileList, "size", 8);
VMMDLL_VfsList_AddFile(pFileList, "directories", 864);
VMMDLL_VfsList_AddFile(pFileList, "export", pProcess->pModuleMap[i].cbDisplayBufferEAT);
VMMDLL_VfsList_AddFile(pFileList, "import", pProcess->pModuleMap[i].cbDisplayBufferIAT);
VMMDLL_VfsList_AddFile(pFileList, "sections", pProcess->pModuleMap[i].cbDisplayBufferSections);
VMMDLL_VfsList_AddDirectory(pFileList, "sectionsd");
VMMDLL_VfsList_AddDirectory(pFileList, "directoriesd");
return TRUE;
}
// module-specific 'sectiond' directory
if(szPath2[0] && !strcmp(szPath2, "sectionsd")) {
_szBuf[8] = 0;
c = PE_SectionGetNumberOf(pProcess, pModule->BaseAddress);
if(!(pSections = LocalAlloc(0, c * sizeof(IMAGE_SECTION_HEADER)))) { return FALSE; }
VmmWin_PE_SECTION_DisplayBuffer(pProcess, pModule, NULL, 0, NULL, &c, pSections);
for(i = 0; i < c; i++) {
*(PQWORD)_szBuf = *(PQWORD)pSections[i].Name;
VMMDLL_VfsList_AddFile(pFileList, _szBuf, pSections[i].Misc.VirtualSize);
}
LocalFree(pSections);
return TRUE;
}
// module-specific 'directoriesd' directory
if(szPath2[0] && !strcmp(szPath2, "directoriesd")) {
VmmWin_PE_DIRECTORY_DisplayBuffer(pProcess, pModule, NULL, 0, NULL, pDataDirectories);
for(i = 0; i < 16; i++) {
VMMDLL_VfsList_AddFile(pFileList, (LPSTR)PE_DATA_DIRECTORIES[i], pDataDirectories[i].Size);
}
return TRUE;
}
return FALSE;
}
@@ -249,17 +392,19 @@ BOOL LdrModules_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList)
* operating system or architecture is unsupported.
* -- pPluginRegInfo
*/
VOID M_LdrModules_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo)
VOID M_LdrModules_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI)
{
PLDRMODULES_CACHE_ENTRY pCache;
if(0 == (pPluginRegInfo->fTargetSystem & VMM_TARGET_WINDOWS_X64)) { return; }
if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; }
if((pRI->tpSystem != VMM_SYSTEM_WINDOWS_X64) && (pRI->tpSystem != VMM_SYSTEM_WINDOWS_X86)) { return; }
pCache = LocalAlloc(LMEM_ZEROINIT, LDRMODULES_NUM_CACHE * sizeof(LDRMODULES_CACHE_ENTRY));
if(!pCache) { return; }
strcpy_s(pPluginRegInfo->reg_info.szModuleName, 32, "modules"); // module name
pPluginRegInfo->reg_info.fProcessModule = TRUE; // module shows in process directory
pPluginRegInfo->reg_info.hModulePrivate = pCache; // module private handle (for cache)
pPluginRegInfo->reg_fn.pfnList = LdrModules_List; // List function supported
pPluginRegInfo->reg_fn.pfnRead = LdrModules_Read; // Read function supported
pPluginRegInfo->reg_fn.pfnCloseHandleModule = LdrModule_CloseHandleModule; // Close module private handle supported
pPluginRegInfo->pfnPluginManager_Register(pPluginRegInfo);
strcpy_s(pRI->reg_info.szModuleName, 32, "modules"); // module name
pRI->reg_info.fProcessModule = TRUE; // module shows in process directory
pRI->reg_info.hModulePrivate = pCache; // module private handle (for cache)
pRI->reg_fn.pfnList = LdrModules_List; // List function supported
pRI->reg_fn.pfnRead = LdrModules_Read; // Read function supported
pRI->reg_fn.pfnWrite = LdrModules_Write; // Write function supported
pRI->reg_fn.pfnCloseHandleModule = LdrModule_CloseHandleModule; // Close module private handle supported
pRI->pfnPluginManager_Register(pRI);
}

View File

@@ -20,6 +20,7 @@
#include "pluginmanager.h"
#include "util.h"
#include "vmm.h"
#include "vmmproc.h"
#include "vmmvfs.h"
#include "statistics.h"
@@ -49,6 +50,9 @@ NTSTATUS MStatus_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ DWO
}
// "ROOT"
if(!pProcess) {
if(!_stricmp(ctx->szPath, "config_process_show_terminated")) {
return Util_VfsReadFile_FromBOOL(ctxVmm->flags & VMM_FLAG_PROCESS_SHOW_TERMINATED, pb, cb, pcbRead, cbOffset);
}
if(!_stricmp(ctx->szPath, "config_cache_enable")) {
return Util_VfsReadFile_FromBOOL(!(ctxVmm->flags & VMM_FLAG_NOCACHE), pb, cb, pcbRead, cbOffset);
}
@@ -162,6 +166,16 @@ NTSTATUS MStatus_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ LPVOID pb, _In_ DWO
}
// "ROOT"
if(!pProcess) {
if(!_stricmp(ctx->szPath, "config_process_show_terminated")) {
nt = Util_VfsWriteFile_BOOL(&fEnable, pb, cb, pcbWrite, cbOffset);
if(nt == VMMDLL_STATUS_SUCCESS) {
ctxVmm->flags &= ~VMM_FLAG_PROCESS_SHOW_TERMINATED;
ctxVmm->flags |= fEnable ? VMM_FLAG_PROCESS_SHOW_TERMINATED : 0;
VmmProc_Refresh(FALSE, TRUE);
}
return nt;
}
if(!_stricmp(ctx->szPath, "config_cache_enable")) {
nt = Util_VfsWriteFile_BOOL(&fEnable, pb, cb, pcbWrite, cbOffset);
if(nt == VMMDLL_STATUS_SUCCESS) {
@@ -241,6 +255,7 @@ BOOL MStatus_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList)
VMMDLL_VfsList_AddFile(pFileList, "config_printf_v", 1);
VMMDLL_VfsList_AddFile(pFileList, "config_printf_vv", 1);
VMMDLL_VfsList_AddFile(pFileList, "config_printf_vvv", 1);
VMMDLL_VfsList_AddFile(pFileList, "config_process_show_terminated", 1);
VMMDLL_VfsList_AddFile(pFileList, "native_max_address", 16);
VMMDLL_VfsList_AddFile(pFileList, "native_max_iosize", 16);
Statistics_CallToString(NULL, 0, &cbCallStatistics);
@@ -261,14 +276,15 @@ BOOL MStatus_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList)
* operating system or architecture is unsupported.
* -- pPluginRegInfo
*/
VOID M_Status_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo)
VOID M_Status_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI)
{
if(0 == (pPluginRegInfo->fTargetSystem & (VMM_TARGET_UNKNOWN_X64 | VMM_TARGET_WINDOWS_X64))) { return; }
strcpy_s(pPluginRegInfo->reg_info.szModuleName, 32, ".status"); // module name
pPluginRegInfo->reg_info.fRootModule = TRUE; // module shows in root directory
pPluginRegInfo->reg_info.fProcessModule = TRUE; // module shows in process directory
pPluginRegInfo->reg_fn.pfnList = MStatus_List; // List function supported
pPluginRegInfo->reg_fn.pfnRead = MStatus_Read; // Read function supported
pPluginRegInfo->reg_fn.pfnWrite = MStatus_Write; // Write function supported
pPluginRegInfo->pfnPluginManager_Register(pPluginRegInfo);
if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; }
// .status module is always valid - no check against pPluginRegInfo->tpMemoryModel, tpSystem
strcpy_s(pRI->reg_info.szModuleName, 32, ".status"); // module name
pRI->reg_info.fRootModule = TRUE; // module shows in root directory
pRI->reg_info.fProcessModule = TRUE; // module shows in process directory
pRI->reg_fn.pfnList = MStatus_List; // List function supported
pRI->reg_fn.pfnRead = MStatus_Read; // Read function supported
pRI->reg_fn.pfnWrite = MStatus_Write; // Write function supported
pRI->pfnPluginManager_Register(pRI);
}

View File

@@ -19,7 +19,7 @@
* -- pDummy
* -- return
*/
PVMM_VIRT2PHYS_INFORMATION Virt2Phys_GetContext(_Inout_opt_ PHANDLE phProcessPrivate, _Inout_opt_ PVMM_VIRT2PHYS_INFORMATION pDummy)
PVMM_VIRT2PHYS_INFORMATION Virt2Phys_GetContext(_Inout_ PHANDLE phProcessPrivate, _Out_opt_ PVMM_VIRT2PHYS_INFORMATION pDummy)
{
if(*phProcessPrivate) {
return (PVMM_VIRT2PHYS_INFORMATION)*phProcessPrivate;
@@ -51,26 +51,64 @@ NTSTATUS Virt2Phys_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ D
VMM_VIRT2PHYS_INFORMATION Virt2PhysInfo_Dummy, *pVirt2PhysInfo;
pVirt2PhysInfo = Virt2Phys_GetContext(ctx->phProcessPrivate, &Virt2PhysInfo_Dummy);
if(!_stricmp(ctx->szPath, "virt")) {
return Util_VfsReadFile_FromQWORD(pVirt2PhysInfo->va, pb, cb, pcbRead, cbOffset, FALSE);
switch(ctxVmm->tpMemoryModel) {
case VMM_MEMORYMODEL_X64:
return Util_VfsReadFile_FromQWORD(pVirt2PhysInfo->va, pb, cb, pcbRead, cbOffset, FALSE);
break;
case VMM_MEMORYMODEL_X86:
case VMM_MEMORYMODEL_X86PAE:
return Util_VfsReadFile_FromDWORD((DWORD)pVirt2PhysInfo->va, pb, cb, pcbRead, cbOffset, FALSE);
break;
}
}
if(!_stricmp(ctx->szPath, "phys")) {
return Util_VfsReadFile_FromQWORD(pVirt2PhysInfo->x64.pas[0], pb, cb, pcbRead, cbOffset, FALSE);
return Util_VfsReadFile_FromQWORD(pVirt2PhysInfo->pas[0], pb, cb, pcbRead, cbOffset, FALSE);
}
if(!_stricmp(ctx->szPath, "map")) {
cbBuffer = snprintf(
pbBuffer,
0x1000,
"PML4 %016llx +%03x %016llx\n" \
"PDPT %016llx +%03x %016llx\n" \
"PD %016llx +%03x %016llx\n" \
"PT %016llx +%03x %016llx\n" \
"PAGE %016llx\n",
pVirt2PhysInfo->x64.pas[4], pVirt2PhysInfo->x64.iPTEs[4] << 3, pVirt2PhysInfo->x64.PTEs[4],
pVirt2PhysInfo->x64.pas[3], pVirt2PhysInfo->x64.iPTEs[3] << 3, pVirt2PhysInfo->x64.PTEs[3],
pVirt2PhysInfo->x64.pas[2], pVirt2PhysInfo->x64.iPTEs[2] << 3, pVirt2PhysInfo->x64.PTEs[2],
pVirt2PhysInfo->x64.pas[1], pVirt2PhysInfo->x64.iPTEs[1] << 3, pVirt2PhysInfo->x64.PTEs[1],
pVirt2PhysInfo->x64.pas[0]
);
switch(ctxVmm->tpMemoryModel) {
case VMM_MEMORYMODEL_X64:
cbBuffer = snprintf(
pbBuffer,
0x1000,
"PML4 %016llx +%03x %016llx\n" \
"PDPT %016llx +%03x %016llx\n" \
"PD %016llx +%03x %016llx\n" \
"PT %016llx +%03x %016llx\n" \
"PAGE %016llx\n",
pVirt2PhysInfo->pas[4], pVirt2PhysInfo->iPTEs[4] << 3, pVirt2PhysInfo->PTEs[4],
pVirt2PhysInfo->pas[3], pVirt2PhysInfo->iPTEs[3] << 3, pVirt2PhysInfo->PTEs[3],
pVirt2PhysInfo->pas[2], pVirt2PhysInfo->iPTEs[2] << 3, pVirt2PhysInfo->PTEs[2],
pVirt2PhysInfo->pas[1], pVirt2PhysInfo->iPTEs[1] << 3, pVirt2PhysInfo->PTEs[1],
pVirt2PhysInfo->pas[0]
);
break;
case VMM_MEMORYMODEL_X86PAE:
cbBuffer = snprintf(
pbBuffer,
0x1000,
"PDPT %016llx +%03x %016llx\n" \
"PD %016llx +%03x %016llx\n" \
"PT %016llx +%03x %016llx\n" \
"PAGE %016llx\n",
pVirt2PhysInfo->pas[3], pVirt2PhysInfo->iPTEs[3] << 3, pVirt2PhysInfo->PTEs[3],
pVirt2PhysInfo->pas[2], pVirt2PhysInfo->iPTEs[2] << 3, pVirt2PhysInfo->PTEs[2],
pVirt2PhysInfo->pas[1], pVirt2PhysInfo->iPTEs[1] << 3, pVirt2PhysInfo->PTEs[1],
pVirt2PhysInfo->pas[0]
);
break;
case VMM_MEMORYMODEL_X86:
cbBuffer = snprintf(
pbBuffer,
0x1000,
"PD %016llx +%03x %08x\n" \
"PT %016llx +%03x %08x\n" \
"PAGE %016llx\n",
pVirt2PhysInfo->pas[2], pVirt2PhysInfo->iPTEs[2] << 2, (DWORD)pVirt2PhysInfo->PTEs[2],
pVirt2PhysInfo->pas[1], pVirt2PhysInfo->iPTEs[1] << 2, (DWORD)pVirt2PhysInfo->PTEs[1],
pVirt2PhysInfo->pas[0]
);
break;
}
return Util_VfsReadFile_FromPBYTE(pbBuffer, cbBuffer, pb, cb, pcbRead, cbOffset);
}
// "page table" or data page
@@ -78,13 +116,15 @@ NTSTATUS Virt2Phys_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ D
if(!_stricmp(ctx->szPath, "pt_pdpt")) { iPML = 3; }
if(!_stricmp(ctx->szPath, "pt_pd")) { iPML = 2; }
if(!_stricmp(ctx->szPath, "pt_pt")) { iPML = 1; }
if((ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X86) && (iPML > 2)) { return VMMDLL_STATUS_FILE_INVALID; }
if((ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X86PAE) && (iPML > 3)) { return VMMDLL_STATUS_FILE_INVALID; }
ZeroMemory(pbBuffer, 0x1000);
pbSourceData = pbBuffer;
if(iPML && (pVirt2PhysInfo->x64.pas[iPML] & ~0xfff)) {
pbSourceData = VmmTlbGetPageTable(pVirt2PhysInfo->x64.pas[iPML] & ~0xfff, FALSE);
if(iPML && (pVirt2PhysInfo->pas[iPML] & ~0xfff)) {
pbSourceData = VmmTlbGetPageTable(pVirt2PhysInfo->pas[iPML] & ~0xfff, FALSE);
}
if(!_stricmp(ctx->szPath, "page") && (pVirt2PhysInfo->x64.pas[0] & ~0xfff)) {
VmmReadPhysicalPage(pVirt2PhysInfo->x64.pas[0] & ~0xfff, pbBuffer);
if(!_stricmp(ctx->szPath, "page") && (pVirt2PhysInfo->pas[0] & ~0xfff)) {
VmmReadPhysicalPage(pVirt2PhysInfo->pas[0] & ~0xfff, pbBuffer);
}
if(iPML || !_stricmp(ctx->szPath, "page")) {
return Util_VfsReadFile_FromPBYTE(pbSourceData, 0x1000, pb, cb, pcbRead, cbOffset);
@@ -107,7 +147,8 @@ NTSTATUS Virt2Phys_WriteVA(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ LPVOID pb, _In_
PVMM_PROCESS pProcess = (PVMM_PROCESS)ctx->pProcess;
BYTE pbBuffer[17];
PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo;
if(cbOffset < 16) {
VMM_MEMORYMODEL_TP tp = ctxVmm->tpMemoryModel;
if((tp == VMM_MEMORYMODEL_X64) && (cbOffset < 16)) {
pVirt2PhysInfo = Virt2Phys_GetContext(ctx->phProcessPrivate, NULL);
*pcbWrite = cb;
snprintf(pbBuffer, 17, "%016llx", pVirt2PhysInfo->va);
@@ -116,6 +157,15 @@ NTSTATUS Virt2Phys_WriteVA(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ LPVOID pb, _In_
pbBuffer[16] = 0;
pVirt2PhysInfo->va = strtoull(pbBuffer, NULL, 16);
VmmVirt2PhysGetInformation(pProcess, pVirt2PhysInfo);
} else if ((tp == VMM_MEMORYMODEL_X86) || (tp == VMM_MEMORYMODEL_X86PAE)) {
pVirt2PhysInfo = Virt2Phys_GetContext(ctx->phProcessPrivate, NULL);
*pcbWrite = cb;
snprintf(pbBuffer, 9, "%08x", (DWORD)pVirt2PhysInfo->va);
cb = (DWORD)min(8 - cbOffset, cb);
memcpy(pbBuffer + cbOffset, pb, cb);
pbBuffer[8] = 0;
pVirt2PhysInfo->va = strtoul(pbBuffer, NULL, 16);
VmmVirt2PhysGetInformation(pProcess, pVirt2PhysInfo);
} else {
*pcbWrite = 0;
}
@@ -147,10 +197,10 @@ NTSTATUS Virt2Phys_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ LPVOID pb, _In_ D
if(!_stricmp(ctx->szPath, "pt_pt")) { i = 1; }
if(!_stricmp(ctx->szPath, "page")) { i = 0; }
if(i > 4) { return VMMDLL_STATUS_FILE_INVALID; }
if(pVirt2PhysInfo->x64.pas[i] < 0x1000) { return VMMDLL_STATUS_FILE_INVALID; }
if(pVirt2PhysInfo->pas[i] < 0x1000) { return VMMDLL_STATUS_FILE_INVALID; }
if(cbOffset > 0x1000) { return VMMDLL_STATUS_END_OF_FILE; }
*pcbWrite = (DWORD)min(cb, 0x1000 - cbOffset);
VmmWritePhysical(pVirt2PhysInfo->x64.pas[i] + cbOffset, pb, *pcbWrite);
VmmWritePhysical(pVirt2PhysInfo->pas[i] + cbOffset, pb, *pcbWrite);
return *pcbWrite ? VMMDLL_STATUS_SUCCESS : VMMDLL_STATUS_END_OF_FILE;
}
@@ -169,14 +219,35 @@ BOOL Virt2Phys_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList)
// not root directory == error for this module.
return FALSE;
}
VMMDLL_VfsList_AddFile(pFileList, "virt", 16);
VMMDLL_VfsList_AddFile(pFileList, "phys", 16);
VMMDLL_VfsList_AddFile(pFileList, "map", 198);
VMMDLL_VfsList_AddFile(pFileList, "page", 0x1000);
VMMDLL_VfsList_AddFile(pFileList, "pt_pml4", 0x1000);
VMMDLL_VfsList_AddFile(pFileList, "pt_pdpt", 0x1000);
VMMDLL_VfsList_AddFile(pFileList, "pt_pd", 0x1000);
VMMDLL_VfsList_AddFile(pFileList, "pt_pt", 0x1000);
switch(ctxVmm->tpMemoryModel) {
case VMM_MEMORYMODEL_X64:
VMMDLL_VfsList_AddFile(pFileList, "virt", 16);
VMMDLL_VfsList_AddFile(pFileList, "phys", 16);
VMMDLL_VfsList_AddFile(pFileList, "map", 198);
VMMDLL_VfsList_AddFile(pFileList, "pt_pml4", 0x1000);
VMMDLL_VfsList_AddFile(pFileList, "pt_pdpt", 0x1000);
VMMDLL_VfsList_AddFile(pFileList, "pt_pd", 0x1000);
VMMDLL_VfsList_AddFile(pFileList, "pt_pt", 0x1000);
VMMDLL_VfsList_AddFile(pFileList, "page", 0x1000);
break;
case VMM_MEMORYMODEL_X86PAE:
VMMDLL_VfsList_AddFile(pFileList, "virt", 8);
VMMDLL_VfsList_AddFile(pFileList, "phys", 16);
VMMDLL_VfsList_AddFile(pFileList, "map", 154);
VMMDLL_VfsList_AddFile(pFileList, "pt_pdpt", 0x1000);
VMMDLL_VfsList_AddFile(pFileList, "pt_pd", 0x1000);
VMMDLL_VfsList_AddFile(pFileList, "pt_pt", 0x1000);
VMMDLL_VfsList_AddFile(pFileList, "page", 0x1000);
break;
case VMM_MEMORYMODEL_X86:
VMMDLL_VfsList_AddFile(pFileList, "virt", 8);
VMMDLL_VfsList_AddFile(pFileList, "phys", 16);
VMMDLL_VfsList_AddFile(pFileList, "map", 94);
VMMDLL_VfsList_AddFile(pFileList, "pt_pd", 0x1000);
VMMDLL_VfsList_AddFile(pFileList, "pt_pt", 0x1000);
VMMDLL_VfsList_AddFile(pFileList, "page", 0x1000);
break;
}
return TRUE;
}
@@ -192,6 +263,7 @@ BOOL Virt2Phys_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList)
VOID Virt2Phys_CloseHandleProcess(_In_opt_ PHANDLE phModulePrivate, _Inout_ PHANDLE phProcessPrivate)
{
LocalFree(*phProcessPrivate);
*phProcessPrivate = 0;
}
/*
@@ -202,14 +274,15 @@ VOID Virt2Phys_CloseHandleProcess(_In_opt_ PHANDLE phModulePrivate, _Inout_ PHAN
* operating system or architecture is unsupported.
* -- pPluginRegInfo
*/
VOID M_Virt2Phys_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo)
VOID M_Virt2Phys_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI)
{
if(0 == (pPluginRegInfo->fTargetSystem & (VMM_TARGET_UNKNOWN_X64 | VMM_TARGET_WINDOWS_X64))) { return; }
strcpy_s(pPluginRegInfo->reg_info.szModuleName, 32, "virt2phys"); // module name
pPluginRegInfo->reg_info.fProcessModule = TRUE; // module shows in process directory
pPluginRegInfo->reg_fn.pfnList = Virt2Phys_List; // List function supported
pPluginRegInfo->reg_fn.pfnRead = Virt2Phys_Read; // Read function supported
pPluginRegInfo->reg_fn.pfnWrite = Virt2Phys_Write; // Write function supported
pPluginRegInfo->reg_fn.pfnCloseHandleProcess = Virt2Phys_CloseHandleProcess; // Close process module private handle supported
pPluginRegInfo->pfnPluginManager_Register(pPluginRegInfo);
if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; }
if(!((pRI->tpMemoryModel == VMM_MEMORYMODEL_X64) || (pRI->tpMemoryModel == VMM_MEMORYMODEL_X86) || (pRI->tpMemoryModel == VMM_MEMORYMODEL_X86PAE))) { return; }
strcpy_s(pRI->reg_info.szModuleName, 32, "virt2phys"); // module name
pRI->reg_info.fProcessModule = TRUE; // module shows in process directory
pRI->reg_fn.pfnList = Virt2Phys_List; // List function supported
pRI->reg_fn.pfnRead = Virt2Phys_Read; // Read function supported
pRI->reg_fn.pfnWrite = Virt2Phys_Write; // Write function supported
pRI->reg_fn.pfnCloseHandleProcess = Virt2Phys_CloseHandleProcess; // Close process module private handle supported
pRI->pfnPluginManager_Register(pRI);
}

View File

@@ -1,4 +1,4 @@
// vmmx64.c : implementation of the x64 / IA32e / long-mode paging / memory model.
// mm_x64.c : implementation of the x64 / IA32e / long-mode paging / memory model.
//
// (c) Ulf Frisk, 2018
// Author: Ulf Frisk, pcileech@frizk.net
@@ -10,7 +10,7 @@
* Tries to verify that a loaded page table is correct. If just a bit strange
* bytes/ptes supplied in pb will be altered to look better.
*/
BOOL VmmX64_TlbPageTableVerify(_Inout_ PBYTE pb, _In_ QWORD pa, _In_ BOOL fSelfRefReq)
BOOL MmX64_TlbPageTableVerify(_Inout_ PBYTE pb, _In_ QWORD pa, _In_ BOOL fSelfRefReq)
{
DWORD i;
QWORD *ptes, c = 0, pte;
@@ -46,50 +46,50 @@ BOOL VmmX64_TlbPageTableVerify(_Inout_ PBYTE pb, _In_ QWORD pa, _In_ BOOL fSelfR
return TRUE;
}
#define VMMX64_TLB_SIZE_STAGEBUF 0x200
#define MMX64_TLB_SIZE_STAGEBUF 0x200
typedef struct tdVMMX64_TLB_SPIDER_STAGE_INTERNAL {
typedef struct tdMMX64_TLB_SPIDER_STAGE_INTERNAL {
QWORD c;
PMEM_IO_SCATTER_HEADER ppDMAs[VMMX64_TLB_SIZE_STAGEBUF];
PVMM_CACHE_ENTRY ppEntrys[VMMX64_TLB_SIZE_STAGEBUF];
} VMMX64_TLB_SPIDER_STAGE_INTERNAL, *PVMMX64_TLB_SPIDER_STAGE_INTERNAL;
PMEM_IO_SCATTER_HEADER ppDMAs[MMX64_TLB_SIZE_STAGEBUF];
PVMM_CACHE_ENTRY ppEntrys[MMX64_TLB_SIZE_STAGEBUF];
} MMX64_TLB_SPIDER_STAGE_INTERNAL, *PMMX64_TLB_SPIDER_STAGE_INTERNAL;
VOID VmmX64_TlbSpider_ReadToCache(PVMMX64_TLB_SPIDER_STAGE_INTERNAL pTlbSpiderStage)
VOID MmX64_TlbSpider_ReadToCache(PMMX64_TLB_SPIDER_STAGE_INTERNAL pTlbSpiderStage)
{
QWORD i;
DeviceReadScatterMEM(pTlbSpiderStage->ppDMAs, (DWORD)pTlbSpiderStage->c, NULL);
for(i = 0; i < pTlbSpiderStage->c; i++) {
VmmX64_TlbPageTableVerify(pTlbSpiderStage->ppEntrys[i]->h.pb, pTlbSpiderStage->ppEntrys[i]->h.qwA, FALSE);
MmX64_TlbPageTableVerify(pTlbSpiderStage->ppEntrys[i]->h.pb, pTlbSpiderStage->ppEntrys[i]->h.qwA, FALSE);
VmmCachePut(ctxVmm->ptTLB, pTlbSpiderStage->ppEntrys[i]);
}
pTlbSpiderStage->c = 0;
}
BOOL VmmX64_TlbSpider_Stage(_In_ QWORD qwPA, _In_ QWORD qwPML, _In_ BOOL fUserOnly, PVMMX64_TLB_SPIDER_STAGE_INTERNAL pTlbSpiderStage)
BOOL MmX64_TlbSpider_Stage(_In_ QWORD pa, _In_ BYTE iPML, _In_ BOOL fUserOnly, PMMX64_TLB_SPIDER_STAGE_INTERNAL pTlbSpiderStage)
{
BOOL fSpiderComplete = TRUE;
PMEM_IO_SCATTER_HEADER pt;
QWORD i, pe;
// 1: retrieve from cache, add to staging if not found
pt = VmmCacheGet(ctxVmm->ptTLB, qwPA);
pt = VmmCacheGet(ctxVmm->ptTLB, pa);
if(!pt) {
pTlbSpiderStage->ppEntrys[pTlbSpiderStage->c] = VmmCacheReserve(ctxVmm->ptTLB);
pTlbSpiderStage->ppDMAs[pTlbSpiderStage->c] = &pTlbSpiderStage->ppEntrys[pTlbSpiderStage->c]->h;
pTlbSpiderStage->ppDMAs[pTlbSpiderStage->c]->qwA = qwPA;
pTlbSpiderStage->ppDMAs[pTlbSpiderStage->c]->qwA = pa;
pTlbSpiderStage->c++;
if(pTlbSpiderStage->c == VMMX64_TLB_SIZE_STAGEBUF) {
VmmX64_TlbSpider_ReadToCache(pTlbSpiderStage);
if(pTlbSpiderStage->c == MMX64_TLB_SIZE_STAGEBUF) {
MmX64_TlbSpider_ReadToCache(pTlbSpiderStage);
}
return FALSE;
}
// 2: walk trough all entries for PML4, PDPT, PD
if(qwPML == 1) { return TRUE; }
if(iPML == 1) { return TRUE; }
for(i = 0; i < 0x1000; i += 8) {
pe = *(PQWORD)(pt->pb + i);
if(!(pe & 0x01)) { continue; } // not valid
if(pe & 0x80) { continue; } // not valid ptr to (PDPT || PD || PT)
if(fUserOnly && !(pe & 0x04)) { continue; } // supervisor page when fUserOnly -> not valid
fSpiderComplete = VmmX64_TlbSpider_Stage(pe & 0x0000fffffffff000, qwPML - 1, fUserOnly, pTlbSpiderStage) && fSpiderComplete;
fSpiderComplete = MmX64_TlbSpider_Stage(pe & 0x0000fffffffff000, iPML - 1, fUserOnly, pTlbSpiderStage) && fSpiderComplete;
}
return fSpiderComplete;
}
@@ -98,23 +98,20 @@ BOOL VmmX64_TlbSpider_Stage(_In_ QWORD qwPA, _In_ QWORD qwPML, _In_ BOOL fUserOn
* Iterate over PML4, PTPT, PD (3 times in total) to first stage uncached pages
* and then commit them to the cache.
*/
VOID VmmX64_TlbSpider(_In_ QWORD paDTB, _In_ BOOL fUserOnly)
VOID MmX64_TlbSpider(_In_ QWORD paDTB, _In_ BOOL fUserOnly)
{
BOOL result;
QWORD i = 0;
PVMMX64_TLB_SPIDER_STAGE_INTERNAL pTlbSpiderStage;
if(!(pTlbSpiderStage = (PVMMX64_TLB_SPIDER_STAGE_INTERNAL)LocalAlloc(LMEM_ZEROINIT, sizeof(VMMX64_TLB_SPIDER_STAGE_INTERNAL)))) { return; }
while(TRUE) {
i++;
result = VmmX64_TlbSpider_Stage(paDTB, 4, fUserOnly, pTlbSpiderStage);
DWORD i = 0;
BOOL result = FALSE;
PMMX64_TLB_SPIDER_STAGE_INTERNAL pTlbSpiderStage;
if(!(pTlbSpiderStage = (PMMX64_TLB_SPIDER_STAGE_INTERNAL)LocalAlloc(LMEM_ZEROINIT, sizeof(MMX64_TLB_SPIDER_STAGE_INTERNAL)))) { return; }
while(!result && (i < 3)) {
result = MmX64_TlbSpider_Stage(paDTB, 4, fUserOnly, pTlbSpiderStage);
if(pTlbSpiderStage->c) {
VmmX64_TlbSpider_ReadToCache(pTlbSpiderStage);
}
if(result || (i == 3)) {
LocalFree(pTlbSpiderStage);
return;
MmX64_TlbSpider_ReadToCache(pTlbSpiderStage);
}
i++;
}
LocalFree(pTlbSpiderStage);
}
/*
@@ -126,7 +123,7 @@ VOID VmmX64_TlbSpider(_In_ QWORD paDTB, _In_ BOOL fUserOnly)
* -- szTag
* -- wszTag
*/
VOID VmmX64_MapTag(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaBase, _In_ QWORD vaLimit, _In_opt_ LPSTR szTag, _In_opt_ LPWSTR wszTag, _In_opt_ BOOL fWoW64)
VOID MmX64_MapTag(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaBase, _In_ QWORD vaLimit, _In_opt_ LPSTR szTag, _In_opt_ LPWSTR wszTag, _In_opt_ BOOL fWoW64)
{
PVMM_MEMMAP_ENTRY pMap;
QWORD i, lvl, cMap;
@@ -166,7 +163,7 @@ VOID VmmX64_MapTag(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaBase, _In_ QWORD vaL
}
}
VOID VmmX64_MapDisplayBufferGenerate(_In_ PVMM_PROCESS pProcess)
VOID MmX64_MapDisplayBufferGenerate(_In_ PVMM_PROCESS pProcess)
{
DWORD i, o = 0;
PBYTE pbBuffer;
@@ -200,7 +197,7 @@ fail:
LocalFree(pbBuffer);
}
PVMM_MEMMAP_ENTRY VmmX64_MapGetEntry(_In_ PVMM_PROCESS pProcess, _In_ QWORD va)
PVMM_MEMMAP_ENTRY MmX64_MapGetEntry(_In_ PVMM_PROCESS pProcess, _In_ QWORD va)
{
QWORD i, ce;
PVMM_MEMMAP_ENTRY pe;
@@ -215,12 +212,12 @@ PVMM_MEMMAP_ENTRY VmmX64_MapGetEntry(_In_ PVMM_PROCESS pProcess, _In_ QWORD va)
return NULL;
}
const QWORD VMMX64_PAGETABLEMAP_PML_REGION_SIZE[5] = { 0, 12, 21, 30, 39 };
const QWORD MMX64_PAGETABLEMAP_PML_REGION_SIZE[5] = { 0, 12, 21, 30, 39 };
VOID VmmX64_MapInitialize_Index(_In_ PVMM_PROCESS pProcess, _In_ QWORD qwVABase, _In_ QWORD qwPML, _In_ QWORD PTEs[512], _In_ BOOL fSupervisorPML, _In_ QWORD paMax)
VOID MmX64_MapInitialize_Index(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaBase, _In_ BYTE iPML, _In_ QWORD PTEs[512], _In_ BOOL fSupervisorPML, _In_ QWORD paMax)
{
PBYTE pbNextPageTable;
QWORD i, pte, qwVA, qwNextVA, qwNextPA = 0;
QWORD i, pte, va;
BOOL fUserOnly, fNextSupervisorPML;
QWORD cMemMap = pProcess->cMemMap;
PVMM_MEMMAP_ENTRY pMemMap = pProcess->pMemMap;
@@ -229,41 +226,38 @@ VOID VmmX64_MapInitialize_Index(_In_ PVMM_PROCESS pProcess, _In_ QWORD qwVABase,
for(i = 0; i < 512; i++) {
pte = PTEs[i];
if(!(pte & 0x01)) { continue; }
qwNextPA = pte & 0x0000fffffffff000;
if(qwNextPA > paMax) { continue; }
if((pte & 0x0000fffffffff000) > paMax) { continue; }
if(fSupervisorPML) { pte = pte & 0xfffffffffffffffb; }
if(fUserOnly && !(pte & 0x04)) { continue; }
qwVA = qwVABase + (i << VMMX64_PAGETABLEMAP_PML_REGION_SIZE[qwPML]);
va = vaBase + (i << MMX64_PAGETABLEMAP_PML_REGION_SIZE[iPML]);
// maps page
if((qwPML == 1) || (pte & 0x80) /* PS */) {
if(qwPML == 4) { continue; } // not supported - PML4 cannot map page directly
if((iPML == 1) || (pte & 0x80) /* PS */) {
if(iPML == 4) { continue; } // not supported - PML4 cannot map page directly
if((cMemMap == 0) ||
(pMemMapEntry->fPage != (pte & VMM_MEMMAP_FLAG_PAGE_MASK)) ||
(qwVA != pMemMapEntry->AddrBase + (pMemMapEntry->cPages << 12))) {
(va != pMemMapEntry->AddrBase + (pMemMapEntry->cPages << 12))) {
if(cMemMap + 1 >= VMM_MEMMAP_ENTRIES_MAX) { return; }
pMemMapEntry = pProcess->pMemMap + cMemMap;
pMemMapEntry->AddrBase = qwVA;
pMemMapEntry->AddrBase = va;
pMemMapEntry->fPage = pte & VMM_MEMMAP_FLAG_PAGE_MASK;
pMemMapEntry->cPages = 1ULL << (VMMX64_PAGETABLEMAP_PML_REGION_SIZE[qwPML] - 12);
pMemMapEntry->cPages = 1ULL << (MMX64_PAGETABLEMAP_PML_REGION_SIZE[iPML] - 12);
pProcess->cMemMap++;
cMemMap++;
continue;
}
pMemMapEntry->cPages += 1ULL << (VMMX64_PAGETABLEMAP_PML_REGION_SIZE[qwPML] - 12);
pMemMapEntry->cPages += 1ULL << (MMX64_PAGETABLEMAP_PML_REGION_SIZE[iPML] - 12);
continue;
}
// maps page table (PDPT, PD, PT)
qwNextVA = qwVA;
pbNextPageTable = VmmTlbGetPageTable(qwNextPA, FALSE);
if(!pbNextPageTable) { continue; }
fNextSupervisorPML = !(pte & 0x04);
VmmX64_MapInitialize_Index(pProcess, qwNextVA, qwPML - 1, (PQWORD)pbNextPageTable, fNextSupervisorPML, paMax);
if(!(pbNextPageTable = VmmTlbGetPageTable(pte & 0x0000fffffffff000, FALSE))) { continue; }
MmX64_MapInitialize_Index(pProcess, va, iPML - 1, (PQWORD)pbNextPageTable, fNextSupervisorPML, paMax);
cMemMap = pProcess->cMemMap;
pMemMapEntry = pProcess->pMemMap + cMemMap - 1;
}
}
VOID VmmX64_MapInitialize(_In_ PVMM_PROCESS pProcess)
VOID MmX64_MapInitialize(_In_ PVMM_PROCESS pProcess)
{
QWORD i, cMemMap;
PBYTE pbPML4;
@@ -274,9 +268,9 @@ VOID VmmX64_MapInitialize(_In_ PVMM_PROCESS pProcess)
pProcess->cMemMap = 0;
pProcess->pMemMap = (PVMM_MEMMAP_ENTRY)LocalAlloc(LMEM_ZEROINIT, VMM_MEMMAP_ENTRIES_MAX * sizeof(VMM_MEMMAP_ENTRY));
if(!pProcess->pMemMap) { return; }
pbPML4 = VmmTlbGetPageTable(pProcess->paPML4, FALSE);
pbPML4 = VmmTlbGetPageTable(pProcess->paDTB, FALSE);
if(!pbPML4) { return; }
VmmX64_MapInitialize_Index(pProcess, 0, 4, (PQWORD)pbPML4, FALSE, ctxMain->cfg.paAddrMax);
MmX64_MapInitialize_Index(pProcess, 0, 4, (PQWORD)pbPML4, FALSE, ctxMain->cfg.paAddrMax);
cMemMap = pProcess->cMemMap;
for(i = 0; i < cMemMap; i++) { // fixup sign extension for kernel addresses
if(pProcess->pMemMap[i].AddrBase & 0x0000800000000000) {
@@ -286,95 +280,87 @@ VOID VmmX64_MapInitialize(_In_ PVMM_PROCESS pProcess)
}
_Success_(return)
BOOL VmmX64_Virt2PhysEx(_In_ BOOL fUserOnly, _In_ QWORD va, _In_ BYTE iPML, _In_reads_(4096) PBYTE pbPTEs, _Out_ PQWORD ppa)
BOOL MmX64_Virt2Phys(_In_ QWORD paPT, _In_ BOOL fUserOnly, _In_ BYTE iPML, _In_ QWORD va, _Out_ PQWORD ppa)
{
QWORD pte, i, qwMask;
PBYTE pbNextPageTable;
PBYTE pbPTEs;
if(iPML == (BYTE)-1) { iPML = 4; }
i = 0x1ff & (va >> VMMX64_PAGETABLEMAP_PML_REGION_SIZE[iPML]);
if(!(pbPTEs = VmmTlbGetPageTable(paPT & 0x0000fffffffff000, FALSE))) { return FALSE; }
i = 0x1ff & (va >> MMX64_PAGETABLEMAP_PML_REGION_SIZE[iPML]);
pte = ((PQWORD)pbPTEs)[i];
if(!(pte & 0x01)) { return FALSE; } // NOT VALID
if(fUserOnly && !(pte & 0x04)) { return FALSE; } // SUPERVISOR PAGE & USER MODE REQ
if(pte & 0x000f000000000000) { return FALSE; } // RESERVED
if((iPML == 1) || (pte & 0x80) /* PS */) {
if(iPML == 4) { return FALSE; } // NO SUPPORT IN PML4
qwMask = 0xffffffffffffffff << VMMX64_PAGETABLEMAP_PML_REGION_SIZE[iPML];
*ppa = pte & 0x0000fffffffff000 & qwMask; // MASK AWAY BITS FOR 4kB/2MB/1GB PAGES
if(iPML == 4) { return FALSE; } // NO SUPPORT IN PML4
qwMask = 0xffffffffffffffff << MMX64_PAGETABLEMAP_PML_REGION_SIZE[iPML];
*ppa = pte & 0x0000fffffffff000 & qwMask; // MASK AWAY BITS FOR 4kB/2MB/1GB PAGES
qwMask = qwMask ^ 0xffffffffffffffff;
*ppa = *ppa | (qwMask & va); // FILL LOWER ADDRESS BITS
*ppa = *ppa | (qwMask & va); // FILL LOWER ADDRESS BITS
return TRUE;
}
pbNextPageTable = VmmTlbGetPageTable(pte & 0x0000fffffffff000, FALSE);
if(!pbNextPageTable) { return FALSE; }
return VmmX64_Virt2PhysEx(fUserOnly, va, iPML - 1, pbNextPageTable, ppa);
return MmX64_Virt2Phys(pte, fUserOnly, iPML - 1, va, ppa);
}
_Success_(return)
BOOL VmmX64_Virt2Phys(_In_ PVMM_PROCESS pProcess, _In_ QWORD va, _Out_ PQWORD ppa)
{
PBYTE pbPML4 = VmmTlbGetPageTable(pProcess->paPML4, FALSE);
if(!pbPML4) { return FALSE; }
*ppa = 0;
return VmmX64_Virt2PhysEx(pProcess->fUserOnly, va, 4, pbPML4, ppa);
}
VOID VmmX64_Virt2PhysGetInformation_DoWork(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo, _In_ BYTE iPML, _In_ QWORD PTEs[512])
VOID MmX64_Virt2PhysGetInformation_DoWork(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo, _In_ BYTE iPML, _In_ QWORD PTEs[512])
{
QWORD pte, i, qwMask;
PBYTE pbNextPageTable;
i = 0x1ff & (pVirt2PhysInfo->va >> VMMX64_PAGETABLEMAP_PML_REGION_SIZE[iPML]);
i = 0x1ff & (pVirt2PhysInfo->va >> MMX64_PAGETABLEMAP_PML_REGION_SIZE[iPML]);
pte = PTEs[i];
pVirt2PhysInfo->x64.iPTEs[iPML] = (WORD)i;
pVirt2PhysInfo->x64.PTEs[iPML] = pte;
pVirt2PhysInfo->iPTEs[iPML] = (WORD)i;
pVirt2PhysInfo->PTEs[iPML] = pte;
if(!(pte & 0x01)) { return; } // NOT VALID
if(pProcess->fUserOnly && !(pte & 0x04)) { return; } // SUPERVISOR PAGE & USER MODE REQ
if(pte & 0x000f000000000000) { return; } // RESERVED
if((iPML == 1) || (pte & 0x80) /* PS */) {
if(iPML == 4) { return; } // NO SUPPORT IN PML4
qwMask = 0xffffffffffffffff << VMMX64_PAGETABLEMAP_PML_REGION_SIZE[iPML];
pVirt2PhysInfo->x64.pas[0] = pte & 0x0000fffffffff000 & qwMask; // MASK AWAY BITS FOR 4kB/2MB/1GB PAGES
qwMask = 0xffffffffffffffff << MMX64_PAGETABLEMAP_PML_REGION_SIZE[iPML];
pVirt2PhysInfo->pas[0] = pte & 0x0000fffffffff000 & qwMask; // MASK AWAY BITS FOR 4kB/2MB/1GB PAGES
qwMask = qwMask ^ 0xffffffffffffffff;
pVirt2PhysInfo->x64.pas[0] = pVirt2PhysInfo->x64.pas[0] | (qwMask & pVirt2PhysInfo->va); // FILL LOWER ADDRESS BITS
pVirt2PhysInfo->pas[0] = pVirt2PhysInfo->pas[0] | (qwMask & pVirt2PhysInfo->va); // FILL LOWER ADDRESS BITS
return;
}
if(!(pbNextPageTable = VmmTlbGetPageTable(pte & 0x0000fffffffff000, FALSE))) { return; }
pVirt2PhysInfo->x64.pas[iPML - 1] = pte & 0x0000fffffffff000;
VmmX64_Virt2PhysGetInformation_DoWork(pProcess, pVirt2PhysInfo, iPML - 1, (PQWORD)pbNextPageTable);
pVirt2PhysInfo->pas[iPML - 1] = pte & 0x0000fffffffff000;
MmX64_Virt2PhysGetInformation_DoWork(pProcess, pVirt2PhysInfo, iPML - 1, (PQWORD)pbNextPageTable);
}
VOID VmmX64_Virt2PhysGetInformation(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo)
VOID MmX64_Virt2PhysGetInformation(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo)
{
QWORD va;
PBYTE pbPML4;
va = pVirt2PhysInfo->va;
ZeroMemory(pVirt2PhysInfo, sizeof(VMM_VIRT2PHYS_INFORMATION));
pVirt2PhysInfo->tpMemoryModel = X64;
pVirt2PhysInfo->tpMemoryModel = VMM_MEMORYMODEL_X64;
pVirt2PhysInfo->va = va;
pVirt2PhysInfo->x64.pas[4] = pProcess->paPML4;
if(!(pbPML4 = VmmTlbGetPageTable(pProcess->paPML4, FALSE))) { return; }
VmmX64_Virt2PhysGetInformation_DoWork(pProcess, pVirt2PhysInfo, 4, (PQWORD)pbPML4);
pVirt2PhysInfo->pas[4] = pProcess->paDTB;
if(!(pbPML4 = VmmTlbGetPageTable(pProcess->paDTB, FALSE))) { return; }
MmX64_Virt2PhysGetInformation_DoWork(pProcess, pVirt2PhysInfo, 4, (PQWORD)pbPML4);
}
VOID VmmX64_Close()
VOID MmX64_Close()
{
ZeroMemory(&ctxVmm->MemoryModel, sizeof(VMM_MEMORYMODEL));
ctxVmm->f32 = FALSE;
ctxVmm->tpMemoryModel = VMM_MEMORYMODEL_NA;
ZeroMemory(&ctxVmm->fnMemoryModel, sizeof(VMM_MEMORYMODEL_FUNCTIONS));
}
VOID VmmX64_Initialize()
VOID MmX64_Initialize()
{
if(ctxVmm->MemoryModel.pfnClose) {
ctxVmm->MemoryModel.pfnClose();
if(ctxVmm->fnMemoryModel.pfnClose) {
ctxVmm->fnMemoryModel.pfnClose();
}
ctxVmm->MemoryModel.pfnInitialize = VmmX64_Initialize;
ctxVmm->MemoryModel.pfnClose = VmmX64_Close;
ctxVmm->MemoryModel.pfnVirt2Phys = VmmX64_Virt2Phys;
ctxVmm->MemoryModel.pfnVirt2PhysEx = VmmX64_Virt2PhysEx;
ctxVmm->MemoryModel.pfnVirt2PhysGetInformation = VmmX64_Virt2PhysGetInformation;
ctxVmm->MemoryModel.pfnMapInitialize = VmmX64_MapInitialize;
ctxVmm->MemoryModel.pfnMapTag = VmmX64_MapTag;
ctxVmm->MemoryModel.pfnMapGetEntry = VmmX64_MapGetEntry;
ctxVmm->MemoryModel.pfnMapDisplayBufferGenerate = VmmX64_MapDisplayBufferGenerate;
ctxVmm->MemoryModel.pfnTlbSpider = VmmX64_TlbSpider;
ctxVmm->MemoryModel.pfnTlbPageTableVerify = VmmX64_TlbPageTableVerify;
ctxVmm->MemoryModel.tp = X64;
ctxVmm->fnMemoryModel.pfnInitialize = MmX64_Initialize;
ctxVmm->fnMemoryModel.pfnClose = MmX64_Close;
ctxVmm->fnMemoryModel.pfnVirt2Phys = MmX64_Virt2Phys;
ctxVmm->fnMemoryModel.pfnVirt2PhysGetInformation = MmX64_Virt2PhysGetInformation;
ctxVmm->fnMemoryModel.pfnMapInitialize = MmX64_MapInitialize;
ctxVmm->fnMemoryModel.pfnMapTag = MmX64_MapTag;
ctxVmm->fnMemoryModel.pfnMapGetEntry = MmX64_MapGetEntry;
ctxVmm->fnMemoryModel.pfnMapDisplayBufferGenerate = MmX64_MapDisplayBufferGenerate;
ctxVmm->fnMemoryModel.pfnTlbSpider = MmX64_TlbSpider;
ctxVmm->fnMemoryModel.pfnTlbPageTableVerify = MmX64_TlbPageTableVerify;
ctxVmm->tpMemoryModel = VMM_MEMORYMODEL_X64;
ctxVmm->f32 = FALSE;
}

View File

@@ -1,10 +1,10 @@
// vmmx64.h : definitions related to the x64 / IA32e / long-mode paging / memory model.
// mm_x64.h : definitions related to the x64 / IA32e / long-mode paging / memory model.
//
// (c) Ulf Frisk, 2018
// Author: Ulf Frisk, pcileech@frizk.net
//
#ifndef __VMMX64_H__
#define __VMMX64_H__
#ifndef __MM_X64_H__
#define __MM_X64_H__
#include "vmm.h"
/*
@@ -12,6 +12,6 @@
* If a previous memory model exists that memory model is first closed before
* the new X64 memory model is initialized.
*/
VOID VmmX64_Initialize();
VOID MmX64_Initialize();
#endif /* __VMMX64_H__ */
#endif /* __MM_X64_H__ */

303
vmm/mm_x86.c Normal file
View File

@@ -0,0 +1,303 @@
// mm_x86.c : implementation of the x86 32-bit protected mode memory model.
//
// (c) Ulf Frisk, 2018
// Author: Ulf Frisk, pcileech@frizk.net
//
#include "device.h"
#include "vmm.h"
/*
* Tries to verify that a loaded page table is correct. If just a bit strange
* bytes/ptes supplied in pb will be altered to look better.
*/
BOOL MmX86_TlbPageTableVerify(_Inout_ PBYTE pb, _In_ QWORD pa, _In_ BOOL fSelfRefReq)
{
return TRUE;
}
#define VMMX64_TLB_SIZE_STAGEBUF 0x400
typedef struct tdMMX86_TLB_SPIDER_STAGE_INTERNAL {
QWORD c;
PMEM_IO_SCATTER_HEADER ppDMAs[VMMX64_TLB_SIZE_STAGEBUF];
PVMM_CACHE_ENTRY ppEntrys[VMMX64_TLB_SIZE_STAGEBUF];
} MMX86_TLB_SPIDER_STAGE_INTERNAL, *PMMX86_TLB_SPIDER_STAGE_INTERNAL;
VOID MmX86_TlbSpider_ReadToCache(PMMX86_TLB_SPIDER_STAGE_INTERNAL pTlbSpiderStage)
{
QWORD i;
DeviceReadScatterMEM(pTlbSpiderStage->ppDMAs, (DWORD)pTlbSpiderStage->c, NULL);
for(i = 0; i < pTlbSpiderStage->c; i++) {
MmX86_TlbPageTableVerify(pTlbSpiderStage->ppEntrys[i]->h.pb, pTlbSpiderStage->ppEntrys[i]->h.qwA, FALSE);
VmmCachePut(ctxVmm->ptTLB, pTlbSpiderStage->ppEntrys[i]);
}
pTlbSpiderStage->c = 0;
}
/*
* Iterate over the PD to retrieve uncached PT pages and then commit them to the cache.
*/
VOID MmX86_TlbSpider(_In_ QWORD paDTB, _In_ BOOL fUserOnly)
{
PBYTE pbPD;
DWORD i, pte;
PMEM_IO_SCATTER_HEADER pt;
PMMX86_TLB_SPIDER_STAGE_INTERNAL pTlbSpiderStage;
if(!(pTlbSpiderStage = (PMMX86_TLB_SPIDER_STAGE_INTERNAL)LocalAlloc(LMEM_ZEROINIT, sizeof(MMX86_TLB_SPIDER_STAGE_INTERNAL)))) { return; }
pbPD = VmmTlbGetPageTable(paDTB & 0xfffff000, FALSE);
for(i = 0; i < 0x1000; i += 8) {
pte = *(PDWORD)(pbPD + i);
if(!(pte & 0x01)) { continue; } // not valid
if(pte & 0x80) { continue; } // not valid ptr to PT
if(fUserOnly && !(pte & 0x04)) { continue; } // supervisor page when fUserOnly -> not valid
pt = VmmCacheGet(ctxVmm->ptTLB, pte & 0xfffff000);
if(!pt) {
pTlbSpiderStage->ppEntrys[pTlbSpiderStage->c] = VmmCacheReserve(ctxVmm->ptTLB);
pTlbSpiderStage->ppDMAs[pTlbSpiderStage->c] = &pTlbSpiderStage->ppEntrys[pTlbSpiderStage->c]->h;
pTlbSpiderStage->ppDMAs[pTlbSpiderStage->c]->qwA = pte & 0xfffff000;
pTlbSpiderStage->c++;
}
}
MmX86_TlbSpider_ReadToCache(pTlbSpiderStage);
LocalFree(pTlbSpiderStage);
}
/*
* Map a tag into the sorted memory map in O(log2) operations. Supply only one
* of szTag or wszTag.
* -- pProcess
* -- vaBase
* -- vaLimit = limit == vaBase + size (== top address in range +1)
* -- szTag
* -- wszTag
*/
VOID MmX86_MapTag(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaBase, _In_ QWORD vaLimit, _In_opt_ LPSTR szTag, _In_opt_ LPWSTR wszTag, _In_opt_ BOOL fWoW64)
{
PVMM_MEMMAP_ENTRY pMap;
QWORD i, lvl, cMap;
if((vaBase > 0xffffffff) || (vaLimit > 0xffffffff)) { return; }
pMap = pProcess->pMemMap;
cMap = pProcess->cMemMap;
if(!pMap || !cMap) { return; }
// 1: locate base
lvl = 1;
i = cMap >> lvl;
while(TRUE) {
lvl++;
if((cMap >> lvl) == 0) {
break;
}
if(pMap[i].AddrBase > vaBase) {
i -= (cMap >> lvl);
} else {
i += (cMap >> lvl);
}
}
// 2: scan back if needed
while(i && (pMap[i].AddrBase > vaBase)) {
i--;
}
// 3: fill in tag
while((i < cMap) && (pMap[i].AddrBase + (pMap[i].cPages << 12) <= vaLimit)) {
if(pMap[i].AddrBase >= vaBase) {
if(wszTag) {
snprintf(pMap[i].szTag, 31, "%S", wszTag);
}
if(szTag) {
snprintf(pMap[i].szTag, 31, "%s", szTag);
}
}
i++;
}
}
VOID MmX86_MapDisplayBufferGenerate(_In_ PVMM_PROCESS pProcess)
{
DWORD i, o = 0;
PBYTE pbBuffer;
if(!pProcess->cMemMap || !pProcess->pMemMap) { return; }
pProcess->cbMemMapDisplayCache = 0;
LocalFree(pProcess->pbMemMapDisplayCache);
pProcess->pbMemMapDisplayCache = NULL;
pbBuffer = LocalAlloc(LMEM_ZEROINIT, 70 * pProcess->cMemMap);
if(!pbBuffer) { return; }
for(i = 0; i < pProcess->cMemMap; i++) {
o += snprintf(
pbBuffer + o,
70,
"%04x %8x %08x-%08x %sr%sx %s\n",
i,
(DWORD)pProcess->pMemMap[i].cPages,
(DWORD)pProcess->pMemMap[i].AddrBase,
(DWORD)(pProcess->pMemMap[i].AddrBase + (pProcess->pMemMap[i].cPages << 12) - 1),
pProcess->pMemMap[i].fPage & VMM_MEMMAP_FLAG_PAGE_NS ? "-" : "s",
pProcess->pMemMap[i].fPage & VMM_MEMMAP_FLAG_PAGE_W ? "w" : "-",
pProcess->pMemMap[i].szTag
);
}
pProcess->pbMemMapDisplayCache = LocalAlloc(0, o);
if(!pProcess->pbMemMapDisplayCache) { goto fail; }
memcpy(pProcess->pbMemMapDisplayCache, pbBuffer, o);
pProcess->cbMemMapDisplayCache = o;
fail:
LocalFree(pbBuffer);
}
PVMM_MEMMAP_ENTRY MmX86_MapGetEntry(_In_ PVMM_PROCESS pProcess, _In_ QWORD va)
{
QWORD i, ce;
PVMM_MEMMAP_ENTRY pe;
if(!pProcess->pMemMap) { return NULL; }
ce = pProcess->cMemMap;
for(i = 0; i < ce; i++) {
pe = pProcess->pMemMap + i;
if((pe->AddrBase >= va) && (va <= pe->AddrBase + (pe->cPages << 12))) {
return pe;
}
}
return NULL;
}
const QWORD MMX86_PAGETABLEMAP_PML_REGION_SIZE[3] = { 0, 12, 22 };
VOID MmX86_MapInitialize_Index(_In_ PVMM_PROCESS pProcess, _In_ DWORD vaBase, _In_ BYTE iPML, _In_ DWORD PTEs[1024], _In_ BOOL fSupervisorPML, _In_ QWORD paMax)
{
PBYTE pbNextPageTable;
DWORD i, va, pte;
BOOL fUserOnly, fNextSupervisorPML;
QWORD cMemMap = pProcess->cMemMap;
PVMM_MEMMAP_ENTRY pMemMap = pProcess->pMemMap;
PVMM_MEMMAP_ENTRY pMemMapEntry = pMemMap + cMemMap - 1;
fUserOnly = pProcess->fUserOnly;
for(i = 0; i < 1024; i++) {
pte = PTEs[i];
if(!(pte & 0x01)) { continue; }
if((pte & 0xfffff000) > paMax) { continue; }
if(fSupervisorPML) { pte = pte & 0xfffffffb; }
if(fUserOnly && !(pte & 0x04)) { continue; }
va = vaBase + (i << MMX86_PAGETABLEMAP_PML_REGION_SIZE[iPML]);
if((iPML == 1) || (pte & 0x80) /* PS */) {
if((cMemMap == 0) ||
(pMemMapEntry->fPage != (pte & VMM_MEMMAP_FLAG_PAGE_MASK)) ||
(va != pMemMapEntry->AddrBase + (pMemMapEntry->cPages << 12))) {
if(cMemMap + 1 >= VMM_MEMMAP_ENTRIES_MAX) { return; }
pMemMapEntry = pProcess->pMemMap + cMemMap;
pMemMapEntry->AddrBase = va;
pMemMapEntry->fPage = pte & VMM_MEMMAP_FLAG_PAGE_MASK;
pMemMapEntry->cPages = 1ULL << (MMX86_PAGETABLEMAP_PML_REGION_SIZE[iPML] - 12);
pProcess->cMemMap++;
cMemMap++;
continue;
}
pMemMapEntry->cPages += 1ULL << (MMX86_PAGETABLEMAP_PML_REGION_SIZE[iPML] - 12);
continue;
}
// maps page table
fNextSupervisorPML = !(pte & 0x04);
if(!(pbNextPageTable = VmmTlbGetPageTable(pte & 0xfffff000, FALSE))) { continue; }
MmX86_MapInitialize_Index(pProcess, va, 1, (PDWORD)pbNextPageTable, fNextSupervisorPML, paMax);
cMemMap = pProcess->cMemMap;
pMemMapEntry = pProcess->pMemMap + cMemMap - 1;
}
}
VOID MmX86_MapInitialize(_In_ PVMM_PROCESS pProcess)
{
PBYTE pbPD;
pProcess->cbMemMapDisplayCache = 0;
LocalFree(pProcess->pbMemMapDisplayCache);
pProcess->pbMemMapDisplayCache = NULL;
LocalFree(pProcess->pMemMap);
pProcess->cMemMap = 0;
pProcess->pMemMap = (PVMM_MEMMAP_ENTRY)LocalAlloc(LMEM_ZEROINIT, VMM_MEMMAP_ENTRIES_MAX * sizeof(VMM_MEMMAP_ENTRY));
if(!pProcess->pMemMap) { return; }
if(!(pbPD = VmmTlbGetPageTable(pProcess->paDTB & 0xfffff000, FALSE))) { return; }
MmX86_MapInitialize_Index(pProcess, 0, 2, (PDWORD)pbPD, FALSE, ctxMain->cfg.paAddrMax);
}
_Success_(return)
BOOL MmX86_Virt2Phys(_In_ QWORD paPT, _In_ BOOL fUserOnly, _In_ BYTE iPML, _In_ QWORD va, _Out_ PQWORD ppa)
{
DWORD pte, i;
PBYTE pbPTEs;
if(va > 0xffffffff) { return FALSE; }
if(paPT > 0xffffffff) { return FALSE; }
if(iPML == (BYTE)-1) { iPML = 2; }
if(!(pbPTEs = VmmTlbGetPageTable(paPT & 0xfffff000, FALSE))) { return FALSE; }
i = 0x3ff & (va >> MMX86_PAGETABLEMAP_PML_REGION_SIZE[iPML]);
pte = ((PDWORD)pbPTEs)[i];
if(!(pte & 0x01)) { return FALSE; } // NOT VALID
if(fUserOnly && !(pte & 0x04)) { return FALSE; } // SUPERVISOR PAGE & USER MODE REQ
if((iPML == 2) && !(pte & 0x80) /* PS */) {
return MmX86_Virt2Phys(pte, fUserOnly, 1, va, ppa);
}
if(iPML == 1) { // 4kB PAGE
*ppa = pte & 0xfffff000;
return TRUE;
}
// 4MB PAGE
if(pte & 0x003e0000) { return FALSE; } // RESERVED
*ppa = (((QWORD)(pte & 0x0001e000)) << (32 - 13)) + (pte & 0xffc00000) + (va & 0x003ff000);
return TRUE;
}
VOID MmX86_Virt2PhysGetInformation_DoWork(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo, _In_ BYTE iPML, _In_ QWORD paPT)
{
PDWORD PTEs;
DWORD pte, i;
if(!(PTEs = (PDWORD)VmmTlbGetPageTable(paPT, FALSE))) { return; }
i = 0x3ff & (pVirt2PhysInfo->va >> MMX86_PAGETABLEMAP_PML_REGION_SIZE[iPML]);
pte = PTEs[i];
pVirt2PhysInfo->pas[iPML] = paPT;
pVirt2PhysInfo->iPTEs[iPML] = (WORD)i;
pVirt2PhysInfo->PTEs[iPML] = pte;
if(!(pte & 0x01)) { return; } // NOT VALID
if(pProcess->fUserOnly && !(pte & 0x04)) { return; } // SUPERVISOR PAGE & USER MODE REQ
if(iPML == 1) { // 4kB page
pVirt2PhysInfo->pas[0] = pte & 0xfffff000;
return;
}
if(pte & 0x80) { // 4MB page
if(pte & 0x003e0000) { return; } // RESERVED
pVirt2PhysInfo->pas[0] = (pte & 0xffc00000) + (((QWORD)(pte & 0x0001e000)) << (32 - 13));
return;
}
MmX86_Virt2PhysGetInformation_DoWork(pProcess, pVirt2PhysInfo, 1, pte & 0xffff000); // PDE
}
VOID MmX86_Virt2PhysGetInformation(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo)
{
QWORD va;
if(pVirt2PhysInfo->va > 0xffffffff) { return; }
va = pVirt2PhysInfo->va;
ZeroMemory(pVirt2PhysInfo, sizeof(VMM_VIRT2PHYS_INFORMATION));
pVirt2PhysInfo->tpMemoryModel = VMM_MEMORYMODEL_X86;
pVirt2PhysInfo->va = va;
MmX86_Virt2PhysGetInformation_DoWork(pProcess, pVirt2PhysInfo, 2, pProcess->paDTB & 0xfffff000);
}
VOID MmX86_Close()
{
ctxVmm->f32 = FALSE;
ctxVmm->tpMemoryModel = VMM_MEMORYMODEL_NA;
ZeroMemory(&ctxVmm->fnMemoryModel, sizeof(VMM_MEMORYMODEL_FUNCTIONS));
}
VOID MmX86_Initialize()
{
if(ctxVmm->fnMemoryModel.pfnClose) {
ctxVmm->fnMemoryModel.pfnClose();
}
ctxVmm->fnMemoryModel.pfnInitialize = MmX86_Initialize;
ctxVmm->fnMemoryModel.pfnClose = MmX86_Close;
ctxVmm->fnMemoryModel.pfnVirt2Phys = MmX86_Virt2Phys;
ctxVmm->fnMemoryModel.pfnVirt2PhysGetInformation = MmX86_Virt2PhysGetInformation;
ctxVmm->fnMemoryModel.pfnMapInitialize = MmX86_MapInitialize;
ctxVmm->fnMemoryModel.pfnMapTag = MmX86_MapTag;
ctxVmm->fnMemoryModel.pfnMapGetEntry = MmX86_MapGetEntry;
ctxVmm->fnMemoryModel.pfnMapDisplayBufferGenerate = MmX86_MapDisplayBufferGenerate;
ctxVmm->fnMemoryModel.pfnTlbSpider = MmX86_TlbSpider;
ctxVmm->fnMemoryModel.pfnTlbPageTableVerify = MmX86_TlbPageTableVerify;
ctxVmm->tpMemoryModel = VMM_MEMORYMODEL_X86;
ctxVmm->f32 = TRUE;
}

17
vmm/mm_x86.h Normal file
View File

@@ -0,0 +1,17 @@
// mm_x86.h : definitions related to the x86 32-bit protected mode memory model.
//
// (c) Ulf Frisk, 2018
// Author: Ulf Frisk, pcileech@frizk.net
//
#ifndef __MM_X86_H__
#define __MM_X86_H__
#include "vmm.h"
/*
* Initialize the X86 32-bit protected mode memory model.
* If a previous memory model exists that memory model is first closed before
* the new X86 memory model is initialized.
*/
VOID MmX86_Initialize();
#endif /* __MM_X86_H__ */

371
vmm/mm_x86pae.c Normal file
View File

@@ -0,0 +1,371 @@
// mm_x86pae.c : implementation of the x86 PAE (Physical Address Extension) 32-bit protected mode memory model.
//
// (c) Ulf Frisk, 2018
// Author: Ulf Frisk, pcileech@frizk.net
//
#include "device.h"
#include "vmm.h"
/*
* Tries to verify that a loaded page table is correct. If just a bit strange
* bytes/ptes supplied in pb will be altered to look better.
*/
BOOL MmX86PAE_TlbPageTableVerify(_Inout_ PBYTE pb, _In_ QWORD pa, _In_ BOOL fSelfRefReq)
{
return TRUE;
}
#define VMMX64_TLB_SIZE_STAGEBUF 0x200
typedef struct tdMMX86PAE_TLB_SPIDER_STAGE_INTERNAL {
QWORD c;
PMEM_IO_SCATTER_HEADER ppDMAs[VMMX64_TLB_SIZE_STAGEBUF];
PVMM_CACHE_ENTRY ppEntrys[VMMX64_TLB_SIZE_STAGEBUF];
} MMX86PAE_TLB_SPIDER_STAGE_INTERNAL, *PMMX86PAE_TLB_SPIDER_STAGE_INTERNAL;
VOID MmX86PAE_TlbSpider_ReadToCache(PMMX86PAE_TLB_SPIDER_STAGE_INTERNAL pTlbSpiderStage)
{
QWORD i;
DeviceReadScatterMEM(pTlbSpiderStage->ppDMAs, (DWORD)pTlbSpiderStage->c, NULL);
for(i = 0; i < pTlbSpiderStage->c; i++) {
MmX86PAE_TlbPageTableVerify(pTlbSpiderStage->ppEntrys[i]->h.pb, pTlbSpiderStage->ppEntrys[i]->h.qwA, FALSE);
VmmCachePut(ctxVmm->ptTLB, pTlbSpiderStage->ppEntrys[i]);
}
pTlbSpiderStage->c = 0;
}
BOOL MmX86PAE_TlbSpider_PD_PT(_In_ QWORD pa, _In_ BYTE iPML, _In_ BOOL fUserOnly, PMMX86PAE_TLB_SPIDER_STAGE_INTERNAL pTlbSpiderStage)
{
BOOL fSpiderComplete = TRUE;
PMEM_IO_SCATTER_HEADER pt;
QWORD i, pte;
// 1: retrieve from cache, add to staging if not found
pt = VmmCacheGet(ctxVmm->ptTLB, pa);
if(!pt) {
pTlbSpiderStage->ppEntrys[pTlbSpiderStage->c] = VmmCacheReserve(ctxVmm->ptTLB);
pTlbSpiderStage->ppDMAs[pTlbSpiderStage->c] = &pTlbSpiderStage->ppEntrys[pTlbSpiderStage->c]->h;
pTlbSpiderStage->ppDMAs[pTlbSpiderStage->c]->qwA = pa;
pTlbSpiderStage->c++;
if(pTlbSpiderStage->c == VMMX64_TLB_SIZE_STAGEBUF) {
MmX86PAE_TlbSpider_ReadToCache(pTlbSpiderStage);
}
return FALSE;
}
if(iPML == 1) { return TRUE; }
// 2: walk trough all entries for PD
for(i = 0; i < 0x1000; i += 8) {
pte = *(PQWORD)(pt->pb + i);
if(!(pte & 0x01)) { continue; } // not valid
if(pte & 0x80) { continue; } // not valid ptr to PT
if(fUserOnly && !(pte & 0x04)) { continue; } // supervisor page when fUserOnly -> not valid
fSpiderComplete = MmX86PAE_TlbSpider_PD_PT(pte & 0x0000fffffffff000, 1, fUserOnly, pTlbSpiderStage) && fSpiderComplete;
}
return fSpiderComplete;
}
BOOL MmX86PAE_TlbSpider_PDPT(_In_ QWORD paDTB, _In_ BOOL fUserOnly, PMMX86PAE_TLB_SPIDER_STAGE_INTERNAL pTlbSpiderStage)
{
BOOL fSpiderComplete = TRUE;
QWORD i, pte;
PBYTE pbPDPT;
// 1: retrieve PDPT
pbPDPT = VmmTlbGetPageTable(paDTB & 0xfffff000, FALSE);
if(!pbPDPT) { return FALSE; }
pbPDPT += paDTB & 0xfe0;
// 2: walk through all four (4) PDPTEs
for(i = 0; i < 0x20; i += 8) {
pte = *(PQWORD)(pbPDPT + i);
if(!(pte & 0x01)) { continue; } // not valid
if(pte & 0xffff0000000001e6) { continue; } // RESERVED BITS IN PDPTE
fSpiderComplete = MmX86PAE_TlbSpider_PD_PT(pte & 0x0000fffffffff000, 2, fUserOnly, pTlbSpiderStage) && fSpiderComplete;
}
return fSpiderComplete;
}
/*
* Iterate over PTPT, PD (3 times in total) to first stage uncached pages
* and then commit them to the cache.
*/
VOID MmX86PAE_TlbSpider(_In_ QWORD paDTB, _In_ BOOL fUserOnly)
{
DWORD i = 0;
BOOL result = FALSE;
PMMX86PAE_TLB_SPIDER_STAGE_INTERNAL pTlbSpiderStage;
if(!(pTlbSpiderStage = (PMMX86PAE_TLB_SPIDER_STAGE_INTERNAL)LocalAlloc(LMEM_ZEROINIT, sizeof(MMX86PAE_TLB_SPIDER_STAGE_INTERNAL)))) { return; }
while(!result && (i < 3)) {
result = MmX86PAE_TlbSpider_PDPT(paDTB, fUserOnly, pTlbSpiderStage);
if(pTlbSpiderStage->c) {
MmX86PAE_TlbSpider_ReadToCache(pTlbSpiderStage);
}
i++;
}
LocalFree(pTlbSpiderStage);
}
/*
* Map a tag into the sorted memory map in O(log2) operations. Supply only one
* of szTag or wszTag.
* -- pProcess
* -- vaBase
* -- vaLimit = limit == vaBase + size (== top address in range +1)
* -- szTag
* -- wszTag
*/
VOID MmX86PAE_MapTag(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaBase, _In_ QWORD vaLimit, _In_opt_ LPSTR szTag, _In_opt_ LPWSTR wszTag, _In_opt_ BOOL fWoW64)
{
PVMM_MEMMAP_ENTRY pMap;
QWORD i, lvl, cMap;
if((vaBase > 0xffffffff) || (vaLimit > 0xffffffff)) { return; }
pMap = pProcess->pMemMap;
cMap = pProcess->cMemMap;
if(!pMap || !cMap) { return; }
// 1: locate base
lvl = 1;
i = cMap >> lvl;
while(TRUE) {
lvl++;
if((cMap >> lvl) == 0) {
break;
}
if(pMap[i].AddrBase > vaBase) {
i -= (cMap >> lvl);
} else {
i += (cMap >> lvl);
}
}
// 2: scan back if needed
while(i && (pMap[i].AddrBase > vaBase)) {
i--;
}
// 3: fill in tag
while((i < cMap) && (pMap[i].AddrBase + (pMap[i].cPages << 12) <= vaLimit)) {
if(pMap[i].AddrBase >= vaBase) {
if(wszTag) {
snprintf(pMap[i].szTag, 31, "%S", wszTag);
}
if(szTag) {
snprintf(pMap[i].szTag, 31, "%s", szTag);
}
}
i++;
}
}
VOID MmX86PAE_MapDisplayBufferGenerate(_In_ PVMM_PROCESS pProcess)
{
DWORD i, o = 0;
PBYTE pbBuffer;
if(!pProcess->cMemMap || !pProcess->pMemMap) { return; }
pProcess->cbMemMapDisplayCache = 0;
LocalFree(pProcess->pbMemMapDisplayCache);
pProcess->pbMemMapDisplayCache = NULL;
pbBuffer = LocalAlloc(LMEM_ZEROINIT, 70 * pProcess->cMemMap);
if(!pbBuffer) { return; }
for(i = 0; i < pProcess->cMemMap; i++) {
o += snprintf(
pbBuffer + o,
70,
"%04x %8x %08x-%08x %sr%s%s %s\n",
i,
(DWORD)pProcess->pMemMap[i].cPages,
(DWORD)pProcess->pMemMap[i].AddrBase,
(DWORD)(pProcess->pMemMap[i].AddrBase + (pProcess->pMemMap[i].cPages << 12) - 1),
pProcess->pMemMap[i].fPage & VMM_MEMMAP_FLAG_PAGE_NS ? "-" : "s",
pProcess->pMemMap[i].fPage & VMM_MEMMAP_FLAG_PAGE_W ? "w" : "-",
pProcess->pMemMap[i].fPage & VMM_MEMMAP_FLAG_PAGE_NX ? "-" : "x",
pProcess->pMemMap[i].szTag
);
}
pProcess->pbMemMapDisplayCache = LocalAlloc(0, o);
if(!pProcess->pbMemMapDisplayCache) { goto fail; }
memcpy(pProcess->pbMemMapDisplayCache, pbBuffer, o);
pProcess->cbMemMapDisplayCache = o;
fail:
LocalFree(pbBuffer);
}
PVMM_MEMMAP_ENTRY MmX86PAE_MapGetEntry(_In_ PVMM_PROCESS pProcess, _In_ QWORD va)
{
QWORD i, ce;
PVMM_MEMMAP_ENTRY pe;
if(!pProcess->pMemMap) { return NULL; }
ce = pProcess->cMemMap;
for(i = 0; i < ce; i++) {
pe = pProcess->pMemMap + i;
if((pe->AddrBase >= va) && (va <= pe->AddrBase + (pe->cPages << 12))) {
return pe;
}
}
return NULL;
}
const QWORD MMX86PAE_PAGETABLEMAP_PML_REGION_SIZE[4] = { 0, 12, 21, 30 };
VOID MmX86PAE_MapInitialize_Index(_In_ PVMM_PROCESS pProcess, _In_ DWORD vaBase, _In_ BYTE iPML, _In_ QWORD PTEs[512], _In_ BOOL fSupervisorPML, _In_ QWORD paMax)
{
PBYTE pbNextPageTable;
DWORD i, va;
QWORD pte;
BOOL fUserOnly, fNextSupervisorPML;
QWORD cMemMap = pProcess->cMemMap;
PVMM_MEMMAP_ENTRY pMemMap = pProcess->pMemMap;
PVMM_MEMMAP_ENTRY pMemMapEntry = pMemMap + cMemMap - 1;
fUserOnly = pProcess->fUserOnly;
for(i = 0; i < 512; i++) {
if((iPML == 3) && (i > 3)) { break; } // MAX 4 ENTRIES IN PDPT
pte = PTEs[i];
if(!(pte & 0x01)) { continue; }
if((pte & 0x0000fffffffff000) > paMax) { continue; }
if(iPML == 3) {
// PDPT: (iPML = 3)
if(pte & 0xffff0000000001e6) { continue; } // RESERVED BITS IN PDPTE
va = i * 0x40000000;
} else {
// PT or PD: (iPML = 1..2)
if(fSupervisorPML) { pte = pte & 0xfffffffffffffffb; }
if(fUserOnly && !(pte & 0x04)) { continue; }
va = vaBase + (i << MMX86PAE_PAGETABLEMAP_PML_REGION_SIZE[iPML]);
// maps page
if((iPML == 1) || (pte & 0x80) /* PS */) {
if((cMemMap == 0) ||
(pMemMapEntry->fPage != (pte & VMM_MEMMAP_FLAG_PAGE_MASK)) ||
(va != pMemMapEntry->AddrBase + (pMemMapEntry->cPages << 12))) {
if(cMemMap + 1 >= VMM_MEMMAP_ENTRIES_MAX) { return; }
pMemMapEntry = pProcess->pMemMap + cMemMap;
pMemMapEntry->AddrBase = va;
pMemMapEntry->fPage = pte & VMM_MEMMAP_FLAG_PAGE_MASK;
pMemMapEntry->cPages = 1ULL << (MMX86PAE_PAGETABLEMAP_PML_REGION_SIZE[iPML] - 12);
pProcess->cMemMap++;
cMemMap++;
continue;
}
pMemMapEntry->cPages += 1ULL << (MMX86PAE_PAGETABLEMAP_PML_REGION_SIZE[iPML] - 12);
continue;
}
}
// maps page table (PD, PT)
fNextSupervisorPML = (iPML != 3) && !(pte & 0x04);
if(!(pbNextPageTable = VmmTlbGetPageTable(pte & 0x0000fffffffff000, FALSE))) { continue; }
MmX86PAE_MapInitialize_Index(pProcess, va, iPML - 1, (PQWORD)pbNextPageTable, fNextSupervisorPML, paMax);
cMemMap = pProcess->cMemMap;
pMemMapEntry = pProcess->pMemMap + cMemMap - 1;
}
}
VOID MmX86PAE_MapInitialize(_In_ PVMM_PROCESS pProcess)
{
PBYTE pbPDPT;
pProcess->cbMemMapDisplayCache = 0;
LocalFree(pProcess->pbMemMapDisplayCache);
pProcess->pbMemMapDisplayCache = NULL;
LocalFree(pProcess->pMemMap);
pProcess->cMemMap = 0;
pProcess->pMemMap = (PVMM_MEMMAP_ENTRY)LocalAlloc(LMEM_ZEROINIT, VMM_MEMMAP_ENTRIES_MAX * sizeof(VMM_MEMMAP_ENTRY));
if(!pProcess->pMemMap) { return; }
if(!(pbPDPT = VmmTlbGetPageTable(pProcess->paDTB & 0xfffff000, FALSE))) { return; }
pbPDPT += pProcess->paDTB & 0xfe0; // ADJUST PDPT TO 32-BYTE BOUNDARY
MmX86PAE_MapInitialize_Index(pProcess, 0, 3, (PQWORD)pbPDPT, FALSE, ctxMain->cfg.paAddrMax);
}
_Success_(return)
BOOL MmX86PAE_Virt2Phys(_In_ QWORD paPT, _In_ BOOL fUserOnly, _In_ BYTE iPML, _In_ QWORD va, _Out_ PQWORD ppa)
{
QWORD pte, i, qwMask;
PBYTE pbPTEs;
if(va > 0xffffffff) { return FALSE; }
if(iPML == (BYTE)-1) { iPML = 3; }
if(!(pbPTEs = VmmTlbGetPageTable(paPT & 0x0000fffffffff000, FALSE))) { return FALSE; }
i = 0x1ff & (va >> MMX86PAE_PAGETABLEMAP_PML_REGION_SIZE[iPML]);
if(iPML == 3) {
// PDPT
if(i > 3) { return FALSE; } // MAX 4 ENTRIES IN PDPT
pbPTEs += paPT & 0xfe0; // ADJUST PDPT TO 32-BYTE BOUNDARY
pte = ((PQWORD)pbPTEs)[i];
if(!(pte & 0x01)) { return FALSE; } // NOT VALID
if(pte & 0xffff0000000001e6) { return FALSE; } // RESERVED BITS IN PDPTE
return MmX86PAE_Virt2Phys(pte, fUserOnly, 2, va, ppa);
}
// PT or PD
pte = ((PQWORD)pbPTEs)[i];
if(!(pte & 0x01)) { return FALSE; } // NOT VALID
if(fUserOnly && !(pte & 0x04)) { return FALSE; } // SUPERVISOR PAGE & USER MODE REQ
if(pte & 0x000f000000000000) { return FALSE; } // RESERVED
if((iPML == 1) || (pte & 0x80) /* PS */) {
qwMask = 0xffffffffffffffff << MMX86PAE_PAGETABLEMAP_PML_REGION_SIZE[iPML];
*ppa = pte & 0x0000fffffffff000 & qwMask; // MASK AWAY BITS FOR 4kB/2MB/1GB PAGES
qwMask = qwMask ^ 0xffffffffffffffff;
*ppa = *ppa | (qwMask & va); // FILL LOWER ADDRESS BITS
return TRUE;
}
return MmX86PAE_Virt2Phys(pte, fUserOnly, 1, va, ppa);
}
VOID MmX86PAE_Virt2PhysGetInformation_DoWork(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo, _In_ BYTE iPML, _In_ QWORD PTEs[512])
{
QWORD pte, i, qwMask;
PBYTE pbNextPageTable;
i = 0x1ff & (pVirt2PhysInfo->va >> MMX86PAE_PAGETABLEMAP_PML_REGION_SIZE[iPML]);
if((iPML == 3) && (i > 3)) { return; } // MAX 4 ENTRIES IN PDPT
pte = PTEs[i];
pVirt2PhysInfo->iPTEs[iPML] = (WORD)i;
pVirt2PhysInfo->PTEs[iPML] = pte;
if(!(pte & 0x01)) { return; } // NOT VALID
if(iPML == 3) {
// PDPT: (iPML = 3)
if(pte & 0xffff0000000001e6) { return; } // RESERVED BITS IN PDPTE
} else {
// PT or PD: (iPML = 1..2)
if(pProcess->fUserOnly && !(pte & 0x04)) { return; } // SUPERVISOR PAGE & USER MODE REQ
if(pte & 0x000f000000000000) { return; } // RESERVED
if((iPML == 1) || (pte & 0x80) /* PS */) {
qwMask = 0xffffffffffffffff << MMX86PAE_PAGETABLEMAP_PML_REGION_SIZE[iPML];
pVirt2PhysInfo->pas[0] = pte & 0x0000fffffffff000 & qwMask; // MASK AWAY BITS FOR 4kB/2MB PAGES
qwMask = qwMask ^ 0xffffffffffffffff;
pVirt2PhysInfo->pas[0] = pVirt2PhysInfo->pas[0] | (qwMask & pVirt2PhysInfo->va); // FILL LOWER ADDRESS BITS
return;
}
}
if(!(pbNextPageTable = VmmTlbGetPageTable(pte & 0x0000fffffffff000, FALSE))) { return; }
pVirt2PhysInfo->pas[iPML - 1] = pte & 0x0000fffffffff000;
MmX86PAE_Virt2PhysGetInformation_DoWork(pProcess, pVirt2PhysInfo, iPML - 1, (PQWORD)pbNextPageTable);
}
VOID MmX86PAE_Virt2PhysGetInformation(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo)
{
QWORD va;
PBYTE pbPDPT;
if(pVirt2PhysInfo->va > 0xffffffff) { return; }
va = pVirt2PhysInfo->va;
ZeroMemory(pVirt2PhysInfo, sizeof(VMM_VIRT2PHYS_INFORMATION));
pVirt2PhysInfo->tpMemoryModel = VMM_MEMORYMODEL_X86PAE;
pVirt2PhysInfo->va = va;
pVirt2PhysInfo->pas[3] = pProcess->paDTB;
if(!(pbPDPT = VmmTlbGetPageTable(pProcess->paDTB & 0xfffff000, FALSE))) { return; }
MmX86PAE_Virt2PhysGetInformation_DoWork(pProcess, pVirt2PhysInfo, 3, (PQWORD)(pbPDPT + (pProcess->paDTB & 0xfe0)));
}
VOID MmX86PAE_Close()
{
ctxVmm->f32 = FALSE;
ctxVmm->tpMemoryModel = VMM_MEMORYMODEL_NA;
ZeroMemory(&ctxVmm->fnMemoryModel, sizeof(VMM_MEMORYMODEL_FUNCTIONS));
}
VOID MmX86PAE_Initialize()
{
if(ctxVmm->fnMemoryModel.pfnClose) {
ctxVmm->fnMemoryModel.pfnClose();
}
ctxVmm->fnMemoryModel.pfnInitialize = MmX86PAE_Initialize;
ctxVmm->fnMemoryModel.pfnClose = MmX86PAE_Close;
ctxVmm->fnMemoryModel.pfnVirt2Phys = MmX86PAE_Virt2Phys;
ctxVmm->fnMemoryModel.pfnVirt2PhysGetInformation = MmX86PAE_Virt2PhysGetInformation;
ctxVmm->fnMemoryModel.pfnMapInitialize = MmX86PAE_MapInitialize;
ctxVmm->fnMemoryModel.pfnMapTag = MmX86PAE_MapTag;
ctxVmm->fnMemoryModel.pfnMapGetEntry = MmX86PAE_MapGetEntry;
ctxVmm->fnMemoryModel.pfnMapDisplayBufferGenerate = MmX86PAE_MapDisplayBufferGenerate;
ctxVmm->fnMemoryModel.pfnTlbSpider = MmX86PAE_TlbSpider;
ctxVmm->fnMemoryModel.pfnTlbPageTableVerify = MmX86PAE_TlbPageTableVerify;
ctxVmm->tpMemoryModel = VMM_MEMORYMODEL_X86PAE;
ctxVmm->f32 = TRUE;
}

17
vmm/mm_x86pae.h Normal file
View File

@@ -0,0 +1,17 @@
// mm_x86pae.h : definitions related to the x86 PAE (Physical Address Extension) 32-bit protected mode memory model.
//
// (c) Ulf Frisk, 2018
// Author: Ulf Frisk, pcileech@frizk.net
//
#ifndef __MM_X86PAE_H__
#define __MM_X86PAE_H__
#include "vmm.h"
/*
* Initialize the X86 PAE 32-bit protected mode memory model.
* If a previous memory model exists that memory model is first closed before
* the new X86 PAE memory model is initialized.
*/
VOID MmX86PAE_Initialize();
#endif /* __MM_X86PAE_H__ */

221
vmm/pe.c Normal file
View File

@@ -0,0 +1,221 @@
// pe.c : implementation related to parsing of portable executable (PE) images
// in virtual address space. This may mostly (but not exclusively) be
// used by Windows functionality.
//
// (c) Ulf Frisk, 2018
// Author: Ulf Frisk, pcileech@frizk.net
//
#include "vmm.h"
PIMAGE_NT_HEADERS PE_HeaderGetVerify(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _Inout_ PBYTE pbModuleHeader, _Out_opt_ PBOOL pfHdr32)
{
PIMAGE_DOS_HEADER dosHeader;
PIMAGE_NT_HEADERS ntHeader;
if(pfHdr32) { *pfHdr32 = FALSE; }
if(vaModuleBase) {
if(!VmmReadPage(pProcess, vaModuleBase, pbModuleHeader)) { return NULL; }
}
dosHeader = (PIMAGE_DOS_HEADER)pbModuleHeader; // dos header.
if(!dosHeader || dosHeader->e_magic != IMAGE_DOS_SIGNATURE) { return NULL; }
if(dosHeader->e_lfanew > 0x800) { return NULL; }
ntHeader = (PIMAGE_NT_HEADERS)(pbModuleHeader + dosHeader->e_lfanew); // nt header
if(!ntHeader || ntHeader->Signature != IMAGE_NT_SIGNATURE) { return NULL; }
if((ntHeader->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) && (ntHeader->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)) { return NULL; }
if(pfHdr32) { *pfHdr32 = (ntHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC); }
return ntHeader;
}
QWORD PE_GetSize(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase)
{
BYTE pbHeader[0x1000] = { 0 };
PIMAGE_NT_HEADERS ntHeader;
DWORD cbSize;
BOOL f32;
ntHeader = PE_HeaderGetVerify(pProcess, vaModuleBase, pbHeader, &f32);
cbSize = f32 ?
((PIMAGE_NT_HEADERS32)ntHeader)->OptionalHeader.SizeOfImage :
((PIMAGE_NT_HEADERS64)ntHeader)->OptionalHeader.SizeOfImage;
if(cbSize > 0x02000000) { cbSize = 0; }
return cbSize;
}
QWORD PE_GetProcAddress(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ LPSTR lpProcName)
{
BYTE pbModuleHeader[0x1000] = { 0 };
PIMAGE_NT_HEADERS32 ntHeader32;
PIMAGE_NT_HEADERS64 ntHeader64;
PDWORD pdwRVAAddrNames, pdwRVAAddrFunctions;
PWORD pwNameOrdinals;
DWORD i, cbProcName, cbExportDirectoryOffset;
LPSTR sz;
QWORD vaFnPtr;
QWORD vaExportDirectory;
DWORD cbExportDirectory;
PBYTE pbExportDirectory = NULL;
QWORD vaRVAAddrNames, vaNameOrdinals, vaRVAAddrFunctions;
BOOL f32;
if(!(ntHeader64 = PE_HeaderGetVerify(pProcess, vaModuleBase, pbModuleHeader, &f32))) { goto cleanup; }
if(f32) { // 32-bit PE
ntHeader32 = (PIMAGE_NT_HEADERS32)ntHeader64;
vaExportDirectory = vaModuleBase + ntHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
cbExportDirectory = ntHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
} else { // 64-bit PE
vaExportDirectory = vaModuleBase + ntHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
cbExportDirectory = ntHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
}
if((cbExportDirectory < sizeof(IMAGE_EXPORT_DIRECTORY)) || (cbExportDirectory > 0x01000000) || (vaExportDirectory == vaModuleBase) || (vaExportDirectory > vaModuleBase + 0x80000000)) { goto cleanup; }
if(!(pbExportDirectory = LocalAlloc(0, cbExportDirectory))) { goto cleanup; }
if(!VmmRead(pProcess, vaExportDirectory, pbExportDirectory, cbExportDirectory)) { goto cleanup; }
PIMAGE_EXPORT_DIRECTORY exp = (PIMAGE_EXPORT_DIRECTORY)pbExportDirectory;
if(!exp || !exp->NumberOfNames || !exp->AddressOfNames) { goto cleanup; }
vaRVAAddrNames = vaModuleBase + exp->AddressOfNames;
vaNameOrdinals = vaModuleBase + exp->AddressOfNameOrdinals;
vaRVAAddrFunctions = vaModuleBase + exp->AddressOfFunctions;
if((vaRVAAddrNames < vaExportDirectory) || (vaRVAAddrNames > vaExportDirectory + cbExportDirectory - exp->NumberOfNames * sizeof(DWORD))) { goto cleanup; }
if((vaNameOrdinals < vaExportDirectory) || (vaNameOrdinals > vaExportDirectory + cbExportDirectory - exp->NumberOfNames * sizeof(WORD))) { goto cleanup; }
if((vaRVAAddrFunctions < vaExportDirectory) || (vaRVAAddrFunctions > vaExportDirectory + cbExportDirectory - exp->NumberOfNames * sizeof(DWORD))) { goto cleanup; }
cbProcName = (DWORD)strnlen_s(lpProcName, MAX_PATH) + 1;
cbExportDirectoryOffset = (DWORD)(vaExportDirectory - vaModuleBase);
pdwRVAAddrNames = (PDWORD)(pbExportDirectory + exp->AddressOfNames - cbExportDirectoryOffset);
pwNameOrdinals = (PWORD)(pbExportDirectory + exp->AddressOfNameOrdinals - cbExportDirectoryOffset);
pdwRVAAddrFunctions = (PDWORD)(pbExportDirectory + exp->AddressOfFunctions - cbExportDirectoryOffset);
for(i = 0; i < exp->NumberOfNames; i++) {
if(pdwRVAAddrNames[i] - cbExportDirectoryOffset + cbProcName > cbExportDirectory) { continue; }
sz = (LPSTR)(pbExportDirectory + pdwRVAAddrNames[i] - cbExportDirectoryOffset);
if(0 == memcmp(sz, lpProcName, cbProcName)) {
if(pwNameOrdinals[i] >= exp->NumberOfFunctions) { goto cleanup; }
vaFnPtr = (QWORD)(vaModuleBase + pdwRVAAddrFunctions[pwNameOrdinals[i]]);
LocalFree(pbExportDirectory);
return vaFnPtr;
}
}
cleanup:
LocalFree(pbExportDirectory);
return 0;
}
WORD PE_SectionGetNumberOfEx(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt)
{
BOOL f32;
BYTE pbModuleHeader[0x1000] = { 0 };
WORD cSections;
PIMAGE_NT_HEADERS ntHeader;
// load nt header either by using optionally supplied module header or by fetching from memory.
ntHeader = pbModuleHeaderOpt ? PE_HeaderGetVerify(pProcess, 0, pbModuleHeaderOpt, &f32) : PE_HeaderGetVerify(pProcess, vaModuleBase, pbModuleHeader, &f32);
if(!ntHeader) { return 0; }
cSections = f32 ? ((PIMAGE_NT_HEADERS32)ntHeader)->FileHeader.NumberOfSections : ((PIMAGE_NT_HEADERS64)ntHeader)->FileHeader.NumberOfSections;
if(cSections > 0x40) { return 0; }
return cSections;
}
_Success_(return)
BOOL PE_SectionGetFromName(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ LPSTR szSectionName, _Out_ PIMAGE_SECTION_HEADER pSection)
{
BOOL f32;
BYTE pbModuleHeader[0x1000] = { 0 };
PIMAGE_NT_HEADERS ntHeader;
PIMAGE_SECTION_HEADER pSectionBase;
DWORD i, cSections;
if(!(ntHeader = PE_HeaderGetVerify(pProcess, vaModuleBase, pbModuleHeader, &f32))) { return FALSE; }
pSectionBase = f32 ?
(PIMAGE_SECTION_HEADER)((QWORD)ntHeader + sizeof(IMAGE_NT_HEADERS32)) :
(PIMAGE_SECTION_HEADER)((QWORD)ntHeader + sizeof(IMAGE_NT_HEADERS64));
cSections = (DWORD)(((QWORD)pbModuleHeader + 0x1000 - (QWORD)pSectionBase) / sizeof(IMAGE_SECTION_HEADER)); // max section headers possible in 0x1000 module header buffer
cSections = (DWORD)min(cSections, ntHeader->FileHeader.NumberOfSections); // FileHeader is the same in both 32/64-bit versions of struct
for(i = 0; i < cSections; i++) {
if(!strncmp((pSectionBase + i)->Name, szSectionName, 8)) {
memcpy(pSection, pSectionBase + i, sizeof(IMAGE_SECTION_HEADER));
return TRUE;
}
}
return FALSE;
}
DWORD PE_IatGetNumberOfEx(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt)
{
BOOL f32;
BYTE pbModuleHeader[0x1000] = { 0 };
PIMAGE_NT_HEADERS ntHeader;
DWORD cbImportDirectory, cbImportAddressTable, cIatEntries, cModules;
// load nt header either by using optionally supplied module header or by fetching from memory.
ntHeader = pbModuleHeaderOpt ? PE_HeaderGetVerify(pProcess, 0, pbModuleHeaderOpt, &f32) : PE_HeaderGetVerify(pProcess, vaModuleBase, pbModuleHeader, &f32);
if(!ntHeader) { return 0; }
// Calculate the number of functions in the import address table (IAT).
// Number of functions = # IAT entries - # Imported modules
cbImportDirectory = f32 ?
((PIMAGE_NT_HEADERS32)ntHeader)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size :
((PIMAGE_NT_HEADERS64)ntHeader)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
cbImportAddressTable = f32 ?
((PIMAGE_NT_HEADERS32)ntHeader)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size :
((PIMAGE_NT_HEADERS64)ntHeader)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size;
cIatEntries = cbImportAddressTable / (f32 ? sizeof(DWORD) : sizeof(QWORD));
cModules = cbImportDirectory / sizeof(IMAGE_IMPORT_DESCRIPTOR);
return cIatEntries - cModules;
}
DWORD PE_EatGetNumberOfEx(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt)
{
BOOL f32;
BYTE pbModuleHeader[0x1000] = { 0 };
PIMAGE_NT_HEADERS ntHeader;
QWORD va, vaExportDirectory;
IMAGE_EXPORT_DIRECTORY hdrExportDirectory;
// load both 32/64 bit ntHeader unless already supplied in parameter (only one of 32/64 bit hdr will be valid)
// load nt header either by using optionally supplied module header or by fetching from memory.
ntHeader = pbModuleHeaderOpt ? PE_HeaderGetVerify(pProcess, 0, pbModuleHeaderOpt, &f32) : PE_HeaderGetVerify(pProcess, vaModuleBase, pbModuleHeader, &f32);
if(!ntHeader) { return 0; }
// Calculate the number of functions in the export address table (EAT).
va = f32 ?
((PIMAGE_NT_HEADERS32)ntHeader)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress :
((PIMAGE_NT_HEADERS64)ntHeader)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
vaExportDirectory = va ? vaModuleBase + va : 0;
if(vaExportDirectory && VmmRead(pProcess, vaExportDirectory, (PBYTE)&hdrExportDirectory, sizeof(IMAGE_EXPORT_DIRECTORY)) && (hdrExportDirectory.NumberOfNames < 0x00010000)) {
return hdrExportDirectory.NumberOfNames;
}
return 0;
}
_Success_(return)
BOOL PE_GetModuleNameEx(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ BOOL fOnFailDummyName, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt, _Out_writes_(MAX_PATH) PCHAR szModuleName, _Out_opt_ PDWORD pdwSize)
{
BOOL f32;
BYTE pbModuleHeader[0x1000] = { 0 };
PIMAGE_NT_HEADERS ntHeader;
PIMAGE_NT_HEADERS64 ntHeader64;
PIMAGE_NT_HEADERS32 ntHeader32;
PIMAGE_EXPORT_DIRECTORY exp;
QWORD vaExportDirectory;
DWORD cbImageSize, cbExportDirectory;
BYTE pbExportDirectory[sizeof(IMAGE_EXPORT_DIRECTORY)];
// load both 32/64 bit ntHeader unless already supplied in parameter (only one of 32/64 bit hdr will be valid)
// load nt header either by using optionally supplied module header or by fetching from memory.
ntHeader = pbModuleHeaderOpt ? PE_HeaderGetVerify(pProcess, 0, pbModuleHeaderOpt, &f32) : PE_HeaderGetVerify(pProcess, vaModuleBase, pbModuleHeader, &f32);
if(!ntHeader) { return FALSE; }
if(!f32) { // 64-bit PE
ntHeader64 = (PIMAGE_NT_HEADERS64)ntHeader;
if(pdwSize) { *pdwSize = ntHeader64->OptionalHeader.SizeOfImage; }
vaExportDirectory = vaModuleBase + ntHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
cbExportDirectory = ntHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
cbImageSize = ntHeader64->OptionalHeader.SizeOfImage;
} else { // 32-bit PE
ntHeader32 = (PIMAGE_NT_HEADERS32)ntHeader;
if(pdwSize) { *pdwSize = ntHeader32->OptionalHeader.SizeOfImage; }
vaExportDirectory = vaModuleBase + ntHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
cbExportDirectory = ntHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
cbImageSize = ntHeader32->OptionalHeader.SizeOfImage;
}
if((cbExportDirectory < sizeof(IMAGE_EXPORT_DIRECTORY)) || (vaExportDirectory == vaModuleBase) || (cbExportDirectory > cbImageSize)) { goto fail; }
if(!VmmRead(pProcess, vaExportDirectory, pbExportDirectory, sizeof(IMAGE_EXPORT_DIRECTORY))) { goto fail; }
exp = (PIMAGE_EXPORT_DIRECTORY)pbExportDirectory;
if(!exp || !exp->Name || exp->Name > cbImageSize) { goto fail; }
szModuleName[MAX_PATH - 1] = 0;
if(!VmmRead(pProcess, vaModuleBase + exp->Name, szModuleName, MAX_PATH - 1)) { goto fail; }
return TRUE;
fail:
if(fOnFailDummyName) {
memcpy(szModuleName, "UNKNOWN", 8);
return TRUE;
}
return FALSE;
}

102
vmm/pe.h Normal file
View File

@@ -0,0 +1,102 @@
// pe.h : definitions related to parsing of portable executable (PE) images in
// virtual address space. This may mostly (but not exclusively) be used
// by Windows functionality.
//
// (c) Ulf Frisk, 2018
// Author: Ulf Frisk, pcileech@frizk.net
//
#ifndef __PE_H__
#define __PE_H__
#include "vmm.h"
static const LPCSTR PE_DATA_DIRECTORIES[16] = { "EXPORT", "IMPORT", "RESOURCE", "EXCEPTION", "SECURITY", "BASERELOC", "DEBUG", "ARCHITECTURE", "GLOBALPTR", "TLS", "LOAD_CONFIG", "BOUND_IMPORT", "IAT", "DELAY_IMPORT", "COM_DESCRIPTOR", "RESERVED" };
/*
* Retrieve the size of the module given its base.
* -- pProcess
* -- vaModuleBase = PE module base address.
* -- return = success: size of module. fail: 0.
*/
QWORD PE_GetSize(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase);
/*
* Lookup the virtual address of an exported function or symbol in the module supplied.
* Similar to Windows 'GetProcAddress'.
* -- pProcess
* -- vaModuleBase = PE module base address.
* -- return = success: virtual address of function / symbol. fail: 0.
*/
QWORD PE_GetProcAddress(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ LPSTR lpProcName);
/*
* Retrieve the module name and optionally the module size.
* -- pProcess
* -- vaModuleBase
* -- fOnFailDummyName
* -- pbModuleHeaderOpt
* -- szModuleName
* -- pdwSize
* -- return
*/
_Success_(return)
BOOL PE_GetModuleNameEx(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ BOOL fOnFailDummyName, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt, _Out_writes_(MAX_PATH) PCHAR szModuleName, _Out_opt_ PDWORD pdwSize);
_Success_(return)
inline BOOL PE_GetModuleName(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _Out_writes_(MAX_PATH) PCHAR szModuleName)
{
return PE_GetModuleNameEx(pProcess, vaModuleBase, FALSE, NULL, szModuleName, NULL);
}
/*
* Retrieve the number of sections in the module given by either the module base
* virtual address or a pre-retrieved pbModuleHeader of size 0x1000.
* -- pProcess
* -- vaModuleBase = PE module base address (unless pbModuleHeaderOpt is specified)
* -- pbModuleHeaderOpt = Optional buffer containing module header (MZ) page.
* -- return = success: number of sections. fail: 0.
*/
WORD PE_SectionGetNumberOfEx(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt);
inline WORD PE_SectionGetNumberOf(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase)
{
return PE_SectionGetNumberOfEx(pProcess, vaModuleBase, NULL);
}
/*
* Retrieve a single section header given its name.
* -- pProcess
* -- vaModuleBase
* -- szSectionName
* -- pSection
* -- return
*/
_Success_(return)
BOOL PE_SectionGetFromName(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ LPSTR szSectionName, _Out_ PIMAGE_SECTION_HEADER pSection);
/*
* Retrieve the number of export address table (EAT) entries - i.e. the number
* of functions that the module is exporting.
* -- pProcess
* -- vaModuleBase = PE module base address (unless pbModuleHeaderOpt is specified)
* -- pbModuleHaderOpt = Optional buffer containing module header (MZ) page.
* -- return = success: number of entries. fail: 0.
*/
DWORD PE_EatGetNumberOfEx(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt);
inline DWORD PE_EatGetNumberOf(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase)
{
return PE_EatGetNumberOfEx(pProcess, vaModuleBase, NULL);
}
/*
* Retrieve the number of import address table (IAT) entries - i.e. the number
* of functions that the module is importing.
* -- pProcess
* -- vaModuleBase = PE module base address (unless pbModuleHeaderOpt is specified)
* -- pbModuleHaderOpt = Optional buffer containing module header (MZ) page.
* -- return = success: number of entries. fail: 0.
*/
DWORD PE_IatGetNumberOfEx(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt);
inline DWORD PE_IatGetNumberOf(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase)
{
return PE_IatGetNumberOfEx(pProcess, vaModuleBase, NULL);
}
#endif /* __PE_H__ */

View File

@@ -77,7 +77,7 @@ PHANDLE PluginManager_ProcCacheGet(_Inout_ PPLUGIN_LISTENTRY pModule, _In_ DWORD
return NULL;
}
VOID PluginManager_ContextInitialize(_Inout_ PVMMDLL_PLUGIN_CONTEXT ctx, PPLUGIN_LISTENTRY pModule, _In_opt_ PVMM_PROCESS pProcess, _In_ LPSTR szPath, _In_ BOOL fDll)
VOID PluginManager_ContextInitialize(_Out_ PVMMDLL_PLUGIN_CONTEXT ctx, PPLUGIN_LISTENTRY pModule, _In_opt_ PVMM_PROCESS pProcess, _In_ LPSTR szPath, _In_ BOOL fDll)
{
ctx->magic = VMMDLL_PLUGIN_CONTEXT_MAGIC;
ctx->wVersion = VMMDLL_PLUGIN_CONTEXT_VERSION;
@@ -289,14 +289,15 @@ VOID PluginManager_Close()
}
}
VOID PluginManager_Initialize_RegInfoInit(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI, _In_opt_ HMODULE hDLL)
VOID PluginManager_Initialize_RegInfoInit(_Out_ PVMMDLL_PLUGIN_REGINFO pRI, _In_opt_ HMODULE hDLL)
{
ZeroMemory(pRI, sizeof(VMMDLL_PLUGIN_REGINFO));
pRI->magic = VMMDLL_PLUGIN_REGINFO_MAGIC;
pRI->wVersion = VMMDLL_PLUGIN_REGINFO_VERSION;
pRI->wSize = sizeof(VMMDLL_PLUGIN_REGINFO);
pRI->hDLL = hDLL;
pRI->fTargetSystem = ctxVmm->fTargetSystem;
pRI->tpMemoryModel = ctxVmm->tpMemoryModel;
pRI->tpSystem = ctxVmm->tpSystem;
pRI->pfnPluginManager_Register = PluginManager_Register;
}

View File

@@ -16,7 +16,13 @@ QWORD Util_GetNumeric(_In_ LPSTR sz)
#define Util_2HexChar(x) (((((x) & 0xf) <= 9) ? '0' : ('a' - 10)) + ((x) & 0xf))
BOOL Util_FillHexAscii(_In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset, _Inout_opt_ LPSTR sz, _Inout_ PDWORD pcsz)
#define UTIL_PRINTASCII \
"................................ !\"#$%&'()*+,-./0123456789:;<=>?" \
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz`{|}~" \
"................................................................" \
"................................................................" \
BOOL Util_FillHexAscii(_In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset, _Inout_opt_ LPSTR sz, _Out_ PDWORD pcsz)
{
DWORD i, j, o = 0, szMax, iMod;
// checks
@@ -59,7 +65,7 @@ BOOL Util_FillHexAscii(_In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset,
if(j >= cb) {
sz[o++] = ' ';
} else {
sz[o++] = (isprint(pb[j]) ? (CHAR)pb[j] : '.');
sz[o++] = UTIL_PRINTASCII[pb[j]];
}
}
sz[o++] = '\n';
@@ -84,7 +90,7 @@ VOID Util_PrintHexAscii(_In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset
LocalFree(sz);
}
VOID Util_PathSplit2(_In_ LPSTR sz, _Inout_ CHAR _szBuf[MAX_PATH], _Out_ LPSTR *psz1, _Out_ LPSTR *psz2)
VOID Util_PathSplit2(_In_ LPSTR sz, _Out_writes_(MAX_PATH) PCHAR _szBuf, _Out_ LPSTR *psz1, _Out_ LPSTR *psz2)
{
DWORD i;
strcpy_s(_szBuf, MAX_PATH, sz);
@@ -102,7 +108,7 @@ VOID Util_PathSplit2(_In_ LPSTR sz, _Inout_ CHAR _szBuf[MAX_PATH], _Out_ LPSTR *
}
}
VOID Util_PathSplit2_WCHAR(_In_ LPWSTR wsz, _Inout_ CHAR _szBuf[MAX_PATH], _Out_ LPSTR *psz1, _Out_ LPSTR *psz2)
VOID Util_PathSplit2_WCHAR(_In_ LPWSTR wsz, _Out_writes_(MAX_PATH) PCHAR _szBuf, _Out_ LPSTR *psz1, _Out_ LPSTR *psz2)
{
DWORD i;
for(i = 0; i < MAX_PATH; i++) {
@@ -124,7 +130,7 @@ VOID Util_PathSplit2_WCHAR(_In_ LPWSTR wsz, _Inout_ CHAR _szBuf[MAX_PATH], _Out_
}
}
VOID Util_GetPathDll(_Out_ CHAR szPath[MAX_PATH], _In_opt_ HMODULE hModule)
VOID Util_GetPathDll(_Out_writes_(MAX_PATH) PCHAR szPath, _In_opt_ HMODULE hModule)
{
SIZE_T i;
GetModuleFileNameA(hModule, szPath, MAX_PATH - 4);

View File

@@ -32,7 +32,7 @@ VOID Util_PrintHexAscii(_In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset
* -- sz = buffer to fill, NULL to retrieve size in pcsz parameter.
* -- pcsz = ptr to size of buffer on entry, size of characters on exit.
*/
BOOL Util_FillHexAscii(_In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset, _Inout_opt_ LPSTR sz, _Inout_ PDWORD pcsz);
BOOL Util_FillHexAscii(_In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset, _Inout_opt_ LPSTR sz, _Out_ PDWORD pcsz);
/*
* Split a "path" string into two at the first '\' character. If no 2nd string
@@ -42,7 +42,7 @@ BOOL Util_FillHexAscii(_In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset,
* -- psz1
* -- psz2
*/
VOID Util_PathSplit2(_In_ LPSTR sz, _Inout_ CHAR _szBuf[MAX_PATH], _Out_ LPSTR *psz1, _Out_ LPSTR *psz2);
VOID Util_PathSplit2(_In_ LPSTR sz, _Out_writes_(MAX_PATH) PCHAR _szBuf, _Out_ LPSTR *psz1, _Out_ LPSTR *psz2);
/*
* Split a "path" string into two at the first '\' character. If no 2nd string
@@ -52,14 +52,14 @@ VOID Util_PathSplit2(_In_ LPSTR sz, _Inout_ CHAR _szBuf[MAX_PATH], _Out_ LPSTR *
* -- psz1
* -- psz2
*/
VOID Util_PathSplit2_WCHAR(_In_ LPWSTR wsz, _Inout_ CHAR _szBuf[MAX_PATH], _Out_ LPSTR *psz1, _Out_ LPSTR *psz2);
VOID Util_PathSplit2_WCHAR(_In_ LPWSTR wsz, _Out_writes_(MAX_PATH) PCHAR _szBuf, _Out_ LPSTR *psz1, _Out_ LPSTR *psz2);
/*
* Return the path of the specified hModule (DLL) - ending with a backslash, or current Executable.
* -- szPath
* -- hModule = Optional, HMODULE handle for path to DLL, NULL for path to EXE.
*/
VOID Util_GetPathDll(_Out_ CHAR szPath[MAX_PATH], _In_opt_ HMODULE hModule);
VOID Util_GetPathDll(_Out_writes_(MAX_PATH) PCHAR szPath, _In_opt_ HMODULE hModule);
/*
* Utility functions for read/write towards different underlying data representations.

View File

@@ -5,7 +5,9 @@
//
#include "vmm.h"
#include "vmmx64.h"
#include "mm_x86.h"
#include "mm_x86pae.h"
#include "mm_x64.h"
#include "vmmproc.h"
#include "pluginmanager.h"
#include "device.h"
@@ -242,20 +244,24 @@ PVMM_PROCESS VmmProcessGet(_In_ DWORD dwPID)
return VmmProcessGetEx(ctxVmm->ptPROC, dwPID);
}
PVMM_PROCESS VmmProcessCreateEntry(_In_ DWORD dwPID, _In_ DWORD dwState, _In_ QWORD paPML4, _In_ QWORD paPML4_UserOpt, _In_ CHAR szName[16], _In_ BOOL fUserOnly, _In_ BOOL fSpiderPageTableDone)
PVMM_PROCESS VmmProcessCreateEntry(_In_ DWORD dwPID, _In_ DWORD dwState, _In_ QWORD paDTB, _In_ QWORD paDTB_UserOpt, _In_ CHAR szName[16], _In_ BOOL fUserOnly, _In_ BOOL fSpiderPageTableDone)
{
QWORD i, iStart, cEmpty = 0, cValid = 0;
PVMM_PROCESS pNewProcess;
PBYTE pbPML4;
PBYTE pbDTB;
// 1: Sanity check PML4
pbPML4 = VmmTlbGetPageTable(paPML4, FALSE);
if(!pbPML4) { return NULL; }
if(!VmmTlbPageTableVerify(pbPML4, paPML4, (ctxVmm->fTargetSystem & VMM_TARGET_WINDOWS_X64))) { return NULL; }
pbDTB = VmmTlbGetPageTable(paDTB, FALSE);
if(!pbDTB) { return NULL; }
if(!VmmTlbPageTableVerify(pbDTB, paDTB, (ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X64))) { return NULL; }
// 2: Allocate new PID table (if not already existing)
if(ctxVmm->ptPROC->ptNew == NULL) {
if(!(ctxVmm->ptPROC->ptNew = LocalAlloc(LMEM_ZEROINIT, sizeof(VMM_PROCESS_TABLE)))) { return NULL; }
}
// 3: Prepare existing item, or create new item, for new PID
// 3: Sanity check - process to create not already in 'new' table.
if(VmmProcessGetEx(ctxVmm->ptPROC->ptNew, dwPID)) {
return NULL;
}
// 4: Prepare existing item, or create new item, for new PID
pNewProcess = VmmProcessGetEx(ctxVmm->ptPROC, dwPID);
if(!pNewProcess) {
if(!(pNewProcess = LocalAlloc(LMEM_ZEROINIT, sizeof(VMM_PROCESS)))) { return NULL; }
@@ -263,12 +269,12 @@ PVMM_PROCESS VmmProcessCreateEntry(_In_ DWORD dwPID, _In_ DWORD dwState, _In_ QW
memcpy(pNewProcess->szName, szName, 16);
pNewProcess->dwPID = dwPID;
pNewProcess->dwState = dwState;
pNewProcess->paPML4 = paPML4;
pNewProcess->paPML4_UserOpt = paPML4_UserOpt;
pNewProcess->paDTB = paDTB;
pNewProcess->paDTB_UserOpt = paDTB_UserOpt;
pNewProcess->fUserOnly = fUserOnly;
pNewProcess->fSpiderPageTableDone = pNewProcess->fSpiderPageTableDone || fSpiderPageTableDone;
pNewProcess->_i_fMigrated = TRUE;
// 4: Install new PID
// 5: Install new PID
i = iStart = dwPID % VMM_PROCESSTABLE_ENTRIES_MAX;
while(TRUE) {
if(!ctxVmm->ptPROC->ptNew->M[i]) {
@@ -339,7 +345,7 @@ VOID VmmProcessCreateFinish()
}
}
VOID VmmProcessListPIDs(_Out_ PDWORD pPIDs, _Inout_ PSIZE_T pcPIDs)
VOID VmmProcessListPIDs(_Out_opt_ PDWORD pPIDs, _Inout_ PSIZE_T pcPIDs)
{
DWORD i = 0;
WORD iProcess;
@@ -413,7 +419,7 @@ VOID VmmWriteScatterPhysical(_Inout_ PPMEM_IO_SCATTER_HEADER ppDMAsPhys, _In_ DW
}
}
BOOL VmmWritePhysical(_In_ QWORD pa, _Out_ PBYTE pb, _In_ DWORD cb)
BOOL VmmWritePhysical(_In_ QWORD pa, _In_ PBYTE pb, _In_ DWORD cb)
{
QWORD paPage;
// 1: invalidate any physical pages from cache
@@ -573,8 +579,8 @@ VOID VmmClose()
}
}
VmmProcessCloseTable(ctxVmm->ptPROC, TRUE);
if(ctxVmm->MemoryModel.pfnClose) {
ctxVmm->MemoryModel.pfnClose();
if(ctxVmm->fnMemoryModel.pfnClose) {
ctxVmm->fnMemoryModel.pfnClose();
}
VmmCacheClose(ctxVmm->ptTLB);
VmmCacheClose(ctxVmm->ptPHYS);
@@ -583,7 +589,7 @@ VOID VmmClose()
ctxVmm = NULL;
}
VOID VmmWriteEx(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwVA, _Out_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbWrite)
VOID VmmWriteEx(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwVA, _In_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbWrite)
{
DWORD i = 0, oVA = 0, cbWrite = 0, cbP, cDMAs;
PBYTE pbBuffer;
@@ -598,6 +604,7 @@ VOID VmmWriteEx(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwVA, _Out_ PBYTE pb,
// prepare pages
while(oVA < cb) {
ppDMAs[i] = &pDMAs[i];
pDMAs[i].version = MEM_IO_SCATTER_HEADER_VERSION;
pDMAs[i].qwA = qwVA + oVA;
cbP = 0x1000 - ((qwVA + oVA) & 0xfff);
cbP = min(cbP, cb - oVA);
@@ -621,14 +628,14 @@ VOID VmmWriteEx(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwVA, _Out_ PBYTE pb,
LocalFree(pbBuffer);
}
BOOL VmmWrite(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwVA, _Out_ PBYTE pb, _In_ DWORD cb)
BOOL VmmWrite(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwVA, _In_ PBYTE pb, _In_ DWORD cb)
{
DWORD cbWrite;
VmmWriteEx(pProcess, qwVA, pb, cb, &cbWrite);
return (cbWrite == cb);
}
VOID VmmReadEx(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwVA, _Inout_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ QWORD flags)
VOID VmmReadEx(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwVA, _Out_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ QWORD flags)
{
DWORD cbP, cDMAs, cbRead = 0;
PBYTE pbBuffer;
@@ -645,6 +652,7 @@ VOID VmmReadEx(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwVA, _Inout_ PBYTE pb
// prepare "middle" pages
for(i = 0; i < cDMAs; i++) {
ppDMAs[i] = &pDMAs[i];
pDMAs[i].version = MEM_IO_SCATTER_HEADER_VERSION;
pDMAs[i].qwA = qwVA - oVA + (i << 12);
pDMAs[i].cbMax = 0x1000;
pDMAs[i].pb = pb - oVA + (i << 12);
@@ -691,18 +699,21 @@ VOID VmmReadEx(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwVA, _Inout_ PBYTE pb
LocalFree(pbBuffer);
}
BOOL VmmReadString_Unicode2Ansi(_In_ PVMM_PROCESS pProcess, _In_ QWORD qwVA, _Out_ LPSTR sz, _In_ DWORD cch)
_Success_(return)
BOOL VmmReadString_Unicode2Ansi(_In_ PVMM_PROCESS pProcess, _In_ QWORD qwVA, _Out_writes_(cch) LPSTR sz, _In_ DWORD cch)
{
DWORD i = 0;
BOOL result;
WCHAR wsz[0x1000];
if(cch > 0x1000) { return FALSE; }
if(cch) { sz[0] = 0; }
if(!cch || cch > 0x1000) { return FALSE; }
result = VmmRead(pProcess, qwVA, (PBYTE)wsz, cch << 1);
if(!result) { return FALSE; }
for(i = 0; i < cch; i++) {
sz[i] = ((WORD)wsz[i] <= 0xff) ? (CHAR)wsz[i] : '?';
for(i = 0; i < cch - 1; i++) {
sz[i] = (CHAR)(((WORD)wsz[i] <= 0xff) ? wsz[i] : '?');
if(sz[i] == 0) { return TRUE; }
}
sz[cch - 1] = 0;
return TRUE;
}
@@ -720,6 +731,25 @@ BOOL VmmReadPage(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _Inout_bytecoun
return cb == 0x1000;
}
VOID VmmInitializeMemoryModel(_In_ VMM_MEMORYMODEL_TP tp)
{
switch(tp) {
case VMM_MEMORYMODEL_X64:
MmX64_Initialize();
break;
case VMM_MEMORYMODEL_X86PAE:
MmX86PAE_Initialize();
break;
case VMM_MEMORYMODEL_X86:
MmX86_Initialize();
break;
default:
if(ctxVmm->fnMemoryModel.pfnClose) {
ctxVmm->fnMemoryModel.pfnClose();
}
}
}
BOOL VmmInitialize()
{
// 1: allocate & initialize
@@ -738,8 +768,6 @@ BOOL VmmInitialize()
// 5: OTHER INIT:
ctxVmm->fReadOnly = (ctxMain->dev.tp == VMM_DEVICE_FILE);
InitializeCriticalSection(&ctxVmm->MasterLock);
// 6: MEMORY MODEL INIT: (x64)
VmmX64_Initialize();
return TRUE;
fail:
VmmClose();

174
vmm/vmm.h
View File

@@ -10,6 +10,8 @@
typedef unsigned __int64 QWORD, *PQWORD;
#define MEM_IO_SCATTER_HEADER_VERSION 2
typedef struct tdMEM_IO_SCATTER_HEADER {
ULONG64 qwA; // base address (DWORD boundry).
DWORD cbMax; // bytes to read (DWORD boundry, max 0x1000); pbResult must have room for this.
@@ -17,6 +19,10 @@ typedef struct tdMEM_IO_SCATTER_HEADER {
PBYTE pb; // ptr to 0x1000 sized buffer to receive read bytes.
PVOID pvReserved1; // reserved for use by caller.
PVOID pvReserved2; // reserved for use by caller.
WORD version; // version of struct
WORD Future1; // reserved for future use.
DWORD Future2; // reserved for future use.
ULONG64 qwDeviceA; // device-physical address (used by device layer).
struct {
PVOID pvReserved1;
PVOID pvReserved2;
@@ -49,14 +55,28 @@ typedef struct tdMEM_IO_SCATTER_HEADER {
#define VMM_FLAG_NOCACHE 0x0001 // do not use the data cache (force reading from memory acquisition device)
#define VMM_FLAG_ZEROPAD_ON_FAIL 0x0002 // zero pad failed physical memory reads and report success if read within range of physical memory.
#define VMM_TARGET_UNKNOWN_X64 0x0001
#define VMM_TARGET_WINDOWS_X64 0x0002
#define VMM_FLAG_PROCESS_SHOW_TERMINATED 0x0004 // show terminated processes in the process list (if they can be found).
#define VMM_VERSION_MAJOR 1
#define VMM_VERSION_MINOR 1
#define VMM_VERSION_MINOR 2
#define VMM_VERSION_REVISION 0
static const LPSTR VMM_MEMORYMODEL_TOSTRING[4] = { "N/A", "X86", "X86PAE", "X64" };
typedef enum tdVMM_MEMORYMODEL_TP {
VMM_MEMORYMODEL_NA = 0,
VMM_MEMORYMODEL_X86 = 1,
VMM_MEMORYMODEL_X86PAE = 2,
VMM_MEMORYMODEL_X64 = 3
} VMM_MEMORYMODEL_TP;
typedef enum tdVMM_SYSTEM_TP {
VMM_SYSTEM_UNKNOWN_X64 = 1,
VMM_SYSTEM_WINDOWS_X64 = 2,
VMM_SYSTEM_UNKNOWN_X86 = 3,
VMM_SYSTEM_WINDOWS_X86 = 4
} VMM_SYSTEM_TP;
typedef struct tdVMM_MEMMAP_ENTRY {
QWORD AddrBase;
QWORD cPages;
@@ -82,8 +102,8 @@ typedef struct tdVMM_MODULEMAP_ENTRY {
typedef struct tdVMM_PROCESS {
DWORD dwPID;
DWORD dwState; // state of process, 0 = running
QWORD paPML4;
QWORD paPML4_UserOpt;
QWORD paDTB;
QWORD paDTB_UserOpt;
CHAR szName[16];
BOOL _i_fMigrated;
BOOL fUserOnly;
@@ -142,29 +162,18 @@ typedef struct tdVMM_CACHE_TABLE {
PVMM_CACHE_ENTRY S;
} VMM_CACHE_TABLE, *PVMM_CACHE_TABLE;
typedef enum tdVMM_MEMORYMODEL_TP {
NA = 0,
X64 = 1
} tdVMM_MEMORYMODEL_TP;
typedef struct tdVMM_VIRT2PHYS_INFORMATION {
tdVMM_MEMORYMODEL_TP tpMemoryModel;
VMM_MEMORYMODEL_TP tpMemoryModel;
QWORD va;
union {
struct {
QWORD pas[5]; // physical addresses of pagetable[PML]/page[0]
QWORD PTEs[5]; // PTEs[PML]
WORD iPTEs[5]; // Index of PTE in page table
} x64;
};
QWORD pas[5]; // physical addresses of pagetable[PML]/page[0]
QWORD PTEs[5]; // PTEs[PML]
WORD iPTEs[5]; // Index of PTE in page table
} VMM_VIRT2PHYS_INFORMATION, *PVMM_VIRT2PHYS_INFORMATION;
typedef struct tdVMM_MEMORYMODEL {
tdVMM_MEMORYMODEL_TP tp;
typedef struct tdVMM_MEMORYMODEL_FUNCTIONS {
VOID(*pfnInitialize)();
VOID(*pfnClose)();
BOOL(*pfnVirt2Phys)(_In_ PVMM_PROCESS pProcess, _In_ QWORD va, _Out_ PQWORD ppa);
BOOL(*pfnVirt2PhysEx)(_In_ BOOL fUserOnly, _In_ QWORD va, _In_ BYTE iPML, _In_reads_(4096) PBYTE pbPTEs, _Out_ PQWORD ppa);
BOOL(*pfnVirt2Phys)(_In_ QWORD paDTB, _In_ BOOL fUserOnly, _In_ BYTE iPML, _In_ QWORD va, _Out_ PQWORD ppa);
VOID(*pfnVirt2PhysGetInformation)(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo);
VOID(*pfnMapInitialize)(_In_ PVMM_PROCESS pProcess);
VOID(*pfnMapTag)(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaBase, _In_ QWORD vaLimit, _In_opt_ LPSTR szTag, _In_opt_ LPWSTR wszTag, _In_opt_ BOOL fWoW64);
@@ -172,7 +181,7 @@ typedef struct tdVMM_MEMORYMODEL {
VOID(*pfnMapDisplayBufferGenerate)(_In_ PVMM_PROCESS pProcess);
VOID(*pfnTlbSpider)(_In_ QWORD paDTB, _In_ BOOL fUserOnly);
BOOL(*pfnTlbPageTableVerify)(_Inout_ PBYTE pb, _In_ QWORD pa, _In_ BOOL fSelfRefReq);
} VMM_MEMORYMODEL;
} VMM_MEMORYMODEL_FUNCTIONS;
// ----------------------------------------------------------------------------
// VMM general constants and struct definitions below:
@@ -192,17 +201,17 @@ typedef struct tdVmmConfig {
BOOL fVerboseExtraTlp;
} VMMCONFIG, *PVMMCONFIG;
typedef enum tdMPFS_DEVICE_TYPE {
typedef enum tdVMM_DEVICE_TYPE {
VMM_DEVICE_NA,
VMM_DEVICE_FILE,
VMM_DEVICE_PCILEECH_DLL,
} MPFS_DEVICE_TYPE;
} VMM_DEVICE_TYPE;
typedef struct tdVmmDeviceConfig {
HANDLE hDevice;
QWORD paAddrMaxNative;
QWORD qwMaxSizeMemIo;
MPFS_DEVICE_TYPE tp;
VMM_DEVICE_TYPE tp;
VOID(*pfnReadScatterMEM)(_Inout_ PPMEM_IO_SCATTER_HEADER ppDMAs, _In_ DWORD cpDMAs, _Out_opt_ PDWORD pcpDMAsRead);
BOOL(*pfnWriteMEM)(_In_ QWORD qwAddr, _In_ PBYTE pb, _In_ DWORD cb);
VOID(*pfnClose)();
@@ -224,16 +233,27 @@ typedef struct tdVMM_STATISTICS {
QWORD cRefreshProcessFull;
} VMM_STATISTICS, *PVMM_STATISTICS;
typedef struct tdVMM_KERNELINFO {
QWORD paDTB;
QWORD vaBase;
QWORD cbSize;
// optional non-required values below
QWORD vaEntry;
QWORD vaPsLoadedModuleList;
QWORD vaKDBG;
} VMM_KERNELINFO;
typedef struct tdVMM_CONTEXT {
CRITICAL_SECTION MasterLock;
PVMM_PROCESS_TABLE ptPROC;
PVMM_CACHE_TABLE ptTLB;
PVMM_CACHE_TABLE ptPHYS;
BOOL fReadOnly;
VMM_MEMORYMODEL MemoryModel;
// os specific below:
DWORD fTargetSystem;
DWORD flags;
VMM_MEMORYMODEL_FUNCTIONS fnMemoryModel;
VMM_MEMORYMODEL_TP tpMemoryModel;
BOOL f32;
VMM_SYSTEM_TP tpSystem;
DWORD flags; // VMM_FLAG_*
struct {
BOOL fEnabled;
HANDLE hThread;
@@ -244,11 +264,8 @@ typedef struct tdVMM_CONTEXT {
DWORD cTick_ProcTotal;
} ThreadProcCache;
VMM_STATISTICS stat;
VMM_KERNELINFO kernel;
PVOID pVmmVfsModuleList;
struct {
QWORD paDTB;
QWORD vaBase;
} kernelinfo;
} VMM_CONTEXT, *PVMM_CONTEXT;
typedef struct tdVMM_MAIN_CONTEXT {
@@ -301,7 +318,7 @@ VOID VmmLockRelease();
* -- cb
* -- return = TRUE on success, FALSE on partial or zero write.
*/
BOOL VmmWrite(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwVA, _Out_ PBYTE pb, _In_ DWORD cb);
BOOL VmmWrite(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwVA, _In_ PBYTE pb, _In_ DWORD cb);
/*
* Write physical memory and clear any VMM caches that may contain data.
@@ -310,19 +327,20 @@ BOOL VmmWrite(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwVA, _Out_ PBYTE pb, _
* -- cb
* -- return
*/
BOOL VmmWritePhysical(_In_ QWORD pa, _Out_ PBYTE pb, _In_ DWORD cb);
BOOL VmmWritePhysical(_In_ QWORD pa, _In_ PBYTE pb, _In_ DWORD cb);
/*
* Read a virtually contigious arbitrary amount of memory containing cch number of
* unicode characters and convert them into ansi characters. Characters > 0xff are
* converted into '?'.
* converted into '?'. The result is guaranteed to be zero-terminated.
* -- pProcess
* -- qwVA
* -- sz
* -- cch
* -- return
*/
BOOL VmmReadString_Unicode2Ansi(_In_ PVMM_PROCESS pProcess, _In_ QWORD qwVA, _Out_ LPSTR sz, _In_ DWORD cch);
_Success_(return)
BOOL VmmReadString_Unicode2Ansi(_In_ PVMM_PROCESS pProcess, _In_ QWORD qwVA, _Out_writes_(cch) LPSTR sz, _In_ DWORD cch);
/*
* Read a contigious arbitrary amount of memory, virtual or physical.
@@ -348,7 +366,7 @@ BOOL VmmRead(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _Out_ PBYTE pb, _In
* -- pcbRead
* -- flags = flags as in VMM_FLAG_*
*/
VOID VmmReadEx(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _Inout_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ QWORD flags);
VOID VmmReadEx(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _Out_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ QWORD flags);
/*
* Read a single 4096-byte page of memory, virtual or physical.
@@ -394,6 +412,21 @@ BOOL VmmReadPhysicalPage(_In_ QWORD qwPA, _Inout_bytecount_(4096) PBYTE pbPage);
*/
PBYTE VmmTlbGetPageTable(_In_ QWORD pa, _In_ BOOL fCacheOnly);
/*
* Translate a virtual address to a physical address by walking the page tables.
* -- paDTB
* -- fUserOnly
* -- va
* -- ppa
* -- return
*/
_Success_(return)
inline BOOL VmmVirt2PhysEx(_In_ QWORD paDTB, _In_ BOOL fUserOnly, _In_ QWORD va, _Out_ PQWORD ppa)
{
if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_NA) { return FALSE; }
return ctxVmm->fnMemoryModel.pfnVirt2Phys(paDTB, fUserOnly, -1, va, ppa);
}
/*
* Translate a virtual address to a physical address by walking the page tables.
* -- pProcess
@@ -404,25 +437,8 @@ PBYTE VmmTlbGetPageTable(_In_ QWORD pa, _In_ BOOL fCacheOnly);
_Success_(return)
inline BOOL VmmVirt2Phys(_In_ PVMM_PROCESS pProcess, _In_ QWORD va, _Out_ PQWORD ppa)
{
if(ctxVmm->MemoryModel.tp == NA) { return FALSE; }
return ctxVmm->MemoryModel.pfnVirt2Phys(pProcess, va, ppa);
}
/*
* Translate a virtual address to a physical address given some extra parameters as
* as compared to the standard recommended function VmmVirt2Phys.
* -- fUserOnly
* -- va
* -- iPML = index of page table (-1 = topmost) (Example: PML4 = 4, PDPT = 3 .. in X64).
* -- PTEs
* -- ppa
* -- return
*/
_Success_(return)
inline BOOL VmmVirt2PhysEx(_In_ BOOL fUserOnly, _In_ QWORD va, _In_ BYTE iPML, _In_reads_(4096) PBYTE pbPTEs, _Out_ PQWORD ppa)
{
if(ctxVmm->MemoryModel.tp == NA) { return FALSE; }
return ctxVmm->MemoryModel.pfnVirt2PhysEx(fUserOnly, va, iPML, pbPTEs, ppa);
if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_NA) { return FALSE; }
return ctxVmm->fnMemoryModel.pfnVirt2Phys(pProcess->paDTB, pProcess->fUserOnly, -1, va, ppa);
}
/*
@@ -435,8 +451,8 @@ inline BOOL VmmVirt2PhysEx(_In_ BOOL fUserOnly, _In_ QWORD va, _In_ BYTE iPML, _
*/
inline VOID VmmTlbSpider(_In_ QWORD paDTB, _In_ BOOL fUserOnly)
{
if(ctxVmm->MemoryModel.tp == NA) { return; }
ctxVmm->MemoryModel.pfnTlbSpider(paDTB, fUserOnly);
if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_NA) { return; }
ctxVmm->fnMemoryModel.pfnTlbSpider(paDTB, fUserOnly);
}
/*
@@ -447,8 +463,8 @@ inline VOID VmmTlbSpider(_In_ QWORD paDTB, _In_ BOOL fUserOnly)
*/
inline BOOL VmmTlbPageTableVerify(_Inout_ PBYTE pb, _In_ QWORD pa, _In_ BOOL fSelfRefReq)
{
if(ctxVmm->MemoryModel.tp == NA) { return FALSE; }
return ctxVmm->MemoryModel.pfnTlbPageTableVerify(pb, pa, fSelfRefReq);
if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_NA) { return FALSE; }
return ctxVmm->fnMemoryModel.pfnTlbPageTableVerify(pb, pa, fSelfRefReq);
}
/*
@@ -460,8 +476,8 @@ inline BOOL VmmTlbPageTableVerify(_Inout_ PBYTE pb, _In_ QWORD pa, _In_ BOOL fSe
*/
inline VOID VmmVirt2PhysGetInformation(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo)
{
if(ctxVmm->MemoryModel.tp == NA) { return; }
ctxVmm->MemoryModel.pfnVirt2PhysGetInformation(pProcess, pVirt2PhysInfo);
if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_NA) { return; }
ctxVmm->fnMemoryModel.pfnVirt2PhysGetInformation(pProcess, pVirt2PhysInfo);
}
/*
@@ -471,8 +487,8 @@ inline VOID VmmVirt2PhysGetInformation(_Inout_ PVMM_PROCESS pProcess, _Inout_ PV
*/
inline VOID VmmMapInitialize(_In_ PVMM_PROCESS pProcess)
{
if(ctxVmm->MemoryModel.tp == NA) { return; }
ctxVmm->MemoryModel.pfnMapInitialize(pProcess);
if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_NA) { return; }
ctxVmm->fnMemoryModel.pfnMapInitialize(pProcess);
}
/*
@@ -487,8 +503,8 @@ inline VOID VmmMapInitialize(_In_ PVMM_PROCESS pProcess)
*/
inline VOID VmmMapTag(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaBase, _In_ QWORD vaLimit, _In_opt_ LPSTR szTag, _In_opt_ LPWSTR wszTag, _In_opt_ BOOL fWoW64)
{
if(ctxVmm->MemoryModel.tp == NA) { return; }
ctxVmm->MemoryModel.pfnMapTag(pProcess, vaBase, vaLimit, szTag, wszTag, fWoW64);
if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_NA) { return; }
ctxVmm->fnMemoryModel.pfnMapTag(pProcess, vaBase, vaLimit, szTag, wszTag, fWoW64);
}
/*
@@ -499,8 +515,8 @@ inline VOID VmmMapTag(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaBase, _In_ QWORD
*/
inline PVMM_MEMMAP_ENTRY VmmMapGetEntry(_In_ PVMM_PROCESS pProcess, _In_ QWORD va)
{
if(ctxVmm->MemoryModel.tp == NA) { return NULL; }
return ctxVmm->MemoryModel.pfnMapGetEntry(pProcess, va);
if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_NA) { return NULL; }
return ctxVmm->fnMemoryModel.pfnMapGetEntry(pProcess, va);
}
/*
@@ -511,11 +527,10 @@ inline PVMM_MEMMAP_ENTRY VmmMapGetEntry(_In_ PVMM_PROCESS pProcess, _In_ QWORD v
*/
inline VOID VmmMapDisplayBufferGenerate(_In_ PVMM_PROCESS pProcess)
{
if(ctxVmm->MemoryModel.tp == NA) { return; }
ctxVmm->MemoryModel.pfnMapDisplayBufferGenerate(pProcess);
if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_NA) { return; }
ctxVmm->fnMemoryModel.pfnMapDisplayBufferGenerate(pProcess);
}
/*
* Create or re-create the entire process table. This will clean the complete and
* all existing processes will be cleared.
@@ -535,7 +550,7 @@ PVMM_PROCESS VmmProcessGet(_In_ DWORD dwPID);
* structure and won't become visible to the "Process" functions until after the
* VmmProcessCreateFinish have been called.
*/
PVMM_PROCESS VmmProcessCreateEntry(_In_ DWORD dwPID, _In_ DWORD dwState, _In_ QWORD paPML4, _In_ QWORD paPML4_UserOpt, _In_ CHAR szName[16], _In_ BOOL fUserOnly, _In_ BOOL fSpiderPageTableDone);
PVMM_PROCESS VmmProcessCreateEntry(_In_ DWORD dwPID, _In_ DWORD dwState, _In_ QWORD paDTB, _In_ QWORD paDTB_UserOpt, _In_ CHAR szName[16], _In_ BOOL fUserOnly, _In_ BOOL fSpiderPageTableDone);
/*
* Activate the pending, not yet active, processes added by VmmProcessCreateEntry.
@@ -548,7 +563,7 @@ VOID VmmProcessCreateFinish();
* -- pPIDs = user allocated DWORD array to receive result, or NULL.
* -- pcPIDs = ptr to number of DWORDs in pPIDs on entry - number of PIDs in system on exit.
*/
VOID VmmProcessListPIDs(_Out_ PDWORD pPIDs, _Inout_ PSIZE_T pcPIDs);
VOID VmmProcessListPIDs(_Out_opt_ PDWORD pPIDs, _Inout_ PSIZE_T pcPIDs);
/*
* Clear the specified cache from all entries.
@@ -563,6 +578,13 @@ VOID VmmCacheClear( _In_ BOOL fTLB, _In_ BOOL fPHYS);
*/
VOID VmmCacheInvalidate( _In_ QWORD pa);
/*
* Initialize the memory model specified and discard any previous memory models
* that may be in action.
* -- tp
*/
VOID VmmInitializeMemoryModel(_In_ VMM_MEMORYMODEL_TP tp);
/*
* Initialize a new VMM context. This must always be done before calling any
* other VMM functions. An alternative way to do this is to call the function:

View File

@@ -99,35 +99,44 @@
<ClInclude Include="device.h" />
<ClInclude Include="devicefile.h" />
<ClInclude Include="devicepcileechdll.h" />
<ClInclude Include="mm_x64.h" />
<ClInclude Include="mm_x86.h" />
<ClInclude Include="mm_x86pae.h" />
<ClInclude Include="m_ldrmodules.h" />
<ClInclude Include="m_status.h" />
<ClInclude Include="m_virt2phys.h" />
<ClInclude Include="pcileech_dll.h" />
<ClInclude Include="pe.h" />
<ClInclude Include="pluginmanager.h" />
<ClInclude Include="statistics.h" />
<ClInclude Include="util.h" />
<ClInclude Include="vmm.h" />
<ClInclude Include="vmmdll.h" />
<ClInclude Include="vmmproc.h" />
<ClInclude Include="vmmproc_windows.h" />
<ClInclude Include="vmmvfs.h" />
<ClInclude Include="vmmx64.h" />
<ClInclude Include="vmmwin.h" />
<ClInclude Include="vmmwininit.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="device.c" />
<ClCompile Include="devicefile.c" />
<ClCompile Include="devicepcileechdll.c" />
<ClCompile Include="mm_x64.c" />
<ClCompile Include="mm_x86.c" />
<ClCompile Include="mm_x86pae.c" />
<ClCompile Include="m_ldrmodules.c" />
<ClCompile Include="m_status.c" />
<ClCompile Include="m_virt2phys.c" />
<ClCompile Include="pe.c" />
<ClCompile Include="pluginmanager.c" />
<ClCompile Include="statistics.c" />
<ClCompile Include="util.c" />
<ClCompile Include="vmm.c" />
<ClCompile Include="vmmdll.c" />
<ClCompile Include="vmmproc.c" />
<ClCompile Include="vmmproc_windows.c" />
<ClCompile Include="vmmvfs.c" />
<ClCompile Include="vmmx64.c" />
<ClCompile Include="vmmwin.c" />
<ClCompile Include="vmmwininit.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View File

@@ -59,13 +59,28 @@
<ClInclude Include="vmmproc.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vmmproc_windows.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vmmvfs.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vmmx64.h">
<ClInclude Include="mm_x64.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="mm_x86.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="mm_x86pae.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="pe.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vmmdll.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vmmwin.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vmmwininit.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
@@ -106,13 +121,25 @@
<ClCompile Include="vmmproc.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vmmproc_windows.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vmmvfs.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vmmx64.c">
<ClCompile Include="mm_x64.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="mm_x86.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="mm_x86pae.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="pe.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vmmwin.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vmmwininit.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>

View File

@@ -9,9 +9,10 @@
#include "device.h"
#include "pluginmanager.h"
#include "util.h"
#include "pe.h"
#include "vmm.h"
#include "vmmproc.h"
#include "vmmproc_windows.h"
#include "vmmwin.h"
#include "vmmvfs.h"
// ----------------------------------------------------------------------------
@@ -48,6 +49,7 @@
// INITIALIZATION FUNCTIONALITY BELOW:
//-----------------------------------------------------------------------------
_Success_(return)
BOOL VmmDll_ConfigIntialize(_In_ DWORD argc, _In_ char* argv[])
{
char* argv2[3];
@@ -142,7 +144,7 @@ VOID VmmDll_PrintHelp()
" The recommended way to use the Memory Process File System is to specify the \n" \
" memory acquisition device in the -device option and possibly more options. \n" \
" Example 1: MemProcFS.exe -device c:\\temp\\memdump-win10x64.pmem \n" \
" Example 2: MemProcFS.exe -device c:\\temp\\memdump-win10x64.pmem -v -vv \n" \
" Example 2: MemProcFS.exe -device c:\\temp\\memdump-winXPx86.pmem -v -vv \n" \
" Example 3: MemProcFS.exe -device FPGA \n" \
" The Memory Process File System may also be started the memory dump file name \n" \
" as the only option. This allows to make file extensions associated so that \n" \
@@ -191,6 +193,7 @@ VOID VmmDll_FreeContext()
}
}
_Success_(return)
BOOL VMMDLL_InitializeReserved(_In_ DWORD argc, _In_ LPSTR argv[])
{
ctxMain = LocalAlloc(LMEM_ZEROINIT, sizeof(VMM_MAIN_CONTEXT));
@@ -223,21 +226,25 @@ BOOL VMMDLL_InitializeReserved(_In_ DWORD argc, _In_ LPSTR argv[])
return TRUE;
}
_Success_(return)
BOOL VMMDLL_InitializeFile(_In_ LPSTR szFileName, _In_opt_ LPSTR szPageTableBaseOpt)
{
return VMMDLL_InitializeReserved(5, (LPSTR[]) { "", "-device", szFileName, "-cr3", (szPageTableBaseOpt ? szPageTableBaseOpt : "0") });
}
_Success_(return)
BOOL VMMDLL_InitializeFPGA(_In_opt_ LPSTR szMaxPhysicalAddressOpt, _In_opt_ LPSTR szPageTableBaseOpt)
{
return VMMDLL_InitializeReserved(7, (LPSTR[]) { "", "-device", "fpga", "-cr3", (szPageTableBaseOpt ? szPageTableBaseOpt : "0", "-max", szMaxPhysicalAddressOpt) });
}
_Success_(return)
BOOL VMMDLL_InitializeTotalMeltdown()
{
return VMMDLL_InitializeReserved(3, (LPSTR[]) { "", "-device", "totalmeltdown" });
}
_Success_(return)
BOOL VMMDLL_Close()
{
VmmDll_FreeContext();
@@ -248,6 +255,7 @@ BOOL VMMDLL_Close()
// CONFIGURATION SETTINGS BELOW:
//-----------------------------------------------------------------------------
_Success_(return)
BOOL VMMDLL_ConfigGet_VmmCore(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue)
{
switch(fOption) {
@@ -278,6 +286,7 @@ BOOL VMMDLL_ConfigGet_VmmCore(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue)
return TRUE;
}
_Success_(return)
BOOL VMMDLL_ConfigGet(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue)
{
if(!pqwValue) { return FALSE; }
@@ -319,8 +328,11 @@ BOOL VMMDLL_ConfigGet(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue)
case VMMDLL_OPT_CORE_MAX_NATIVE_IOSIZE:
*pqwValue = ctxMain->dev.qwMaxSizeMemIo;
return TRUE;
case VMMDLL_OPT_CORE_TARGET_SYSTEM:
*pqwValue = ctxVmm->fTargetSystem;
case VMMDLL_OPT_CORE_SYSTEM:
*pqwValue = ctxVmm->tpSystem;
return TRUE;
case VMMDLL_OPT_CORE_MEMORYMODEL:
*pqwValue = ctxVmm->tpMemoryModel;
return TRUE;
default:
return FALSE;
@@ -330,6 +342,7 @@ BOOL VMMDLL_ConfigGet(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue)
return DeviceGetOption(fOption, pqwValue);
}
_Success_(return)
BOOL VMMDLL_ConfigSet_VmmCore(_In_ ULONG64 fOption, _In_ ULONG64 qwValue)
{
switch(fOption) {
@@ -357,6 +370,7 @@ BOOL VMMDLL_ConfigSet_VmmCore(_In_ ULONG64 fOption, _In_ ULONG64 qwValue)
return TRUE;
}
_Success_(return)
BOOL VMMDLL_ConfigSet(_In_ ULONG64 fOption, _In_ ULONG64 qwValue)
{
if(!ctxVmm) { return FALSE; }
@@ -404,6 +418,7 @@ BOOL VMMDLL_ConfigSet(_In_ ULONG64 fOption, _In_ ULONG64 qwValue)
// VFS - VIRTUAL FILE SYSTEM FUNCTIONALITY BELOW:
//-----------------------------------------------------------------------------
_Success_(return)
BOOL VMMDLL_VfsList(_In_ LPCWSTR wcsPath, _Inout_ PVMMDLL_VFS_FILELIST pFileList)
{
CALL_SYNCHRONIZED_IMPLEMENTATION_VMM(
@@ -461,6 +476,7 @@ NTSTATUS VMMDLL_UtilVfsWriteFile_DWORD(_Inout_ PDWORD pdwTarget, _In_ LPVOID pb,
// PLUGIN MANAGER FUNCTIONALITY BELOW:
//-----------------------------------------------------------------------------
_Success_(return)
BOOL VMMDLL_VfsInitializePlugins()
{
CALL_SYNCHRONIZED_IMPLEMENTATION_VMM(
@@ -497,7 +513,8 @@ DWORD VMMDLL_MemReadScatter(_In_ DWORD dwPID, _Inout_ PPVMMDLL_MEM_IO_SCATTER_HE
return cMEMs;
}
BOOL VMMDLL_MemReadEx_Impl(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ ULONG64 flags)
_Success_(return)
BOOL VMMDLL_MemReadEx_Impl(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ ULONG64 flags)
{
PVMM_PROCESS pProcess = NULL;
if(dwPID != -1) {
@@ -508,26 +525,30 @@ BOOL VMMDLL_MemReadEx_Impl(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_ PBYTE pb
return TRUE;
}
BOOL VMMDLL_MemReadEx(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ ULONG64 flags)
_Success_(return)
BOOL VMMDLL_MemReadEx(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ ULONG64 flags)
{
CALL_SYNCHRONIZED_IMPLEMENTATION_VMM(
STATISTICS_ID_VMMDLL_MemReadEx,
VMMDLL_MemReadEx_Impl(dwPID, qwVA, pb, cb, pcbReadOpt, flags))
}
_Success_(return)
BOOL VMMDLL_MemRead(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DWORD cb)
{
DWORD dwRead;
return VMMDLL_MemReadEx(dwPID, qwVA, pb, cb, &dwRead, 0) && (dwRead == cb);
}
_Success_(return)
BOOL VMMDLL_MemReadPage(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_bytecount_(4096) PBYTE pbPage)
{
DWORD dwRead;
return VMMDLL_MemReadEx(dwPID, qwVA, pbPage, 4096, &dwRead, 0) && (dwRead == 4096);
}
BOOL VMMDLL_MemWrite_Impl(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DWORD cb)
_Success_(return)
BOOL VMMDLL_MemWrite_Impl(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _In_ PBYTE pb, _In_ DWORD cb)
{
PVMM_PROCESS pProcess = NULL;
if(dwPID != -1) {
@@ -537,13 +558,15 @@ BOOL VMMDLL_MemWrite_Impl(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _
return VmmWrite(pProcess, qwVA, pb, cb);
}
BOOL VMMDLL_MemWrite(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DWORD cb)
_Success_(return)
BOOL VMMDLL_MemWrite(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _In_ PBYTE pb, _In_ DWORD cb)
{
CALL_SYNCHRONIZED_IMPLEMENTATION_VMM(
STATISTICS_ID_VMMDLL_MemWrite,
VMMDLL_MemWrite_Impl(dwPID, qwVA, pb, cb))
}
_Success_(return)
BOOL VMMDLL_MemVirt2Phys_Impl(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PULONG64 pqwPA)
{
PVMM_PROCESS pProcess = VmmProcessGet(dwPID);
@@ -551,6 +574,7 @@ BOOL VMMDLL_MemVirt2Phys_Impl(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PULONG6
return VmmVirt2Phys(pProcess, qwVA, pqwPA);
}
_Success_(return)
BOOL VMMDLL_MemVirt2Phys(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PULONG64 pqwPA)
{
CALL_SYNCHRONIZED_IMPLEMENTATION_VMM(
@@ -562,13 +586,14 @@ BOOL VMMDLL_MemVirt2Phys(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PULONG64 pqw
// VMM PROCESS FUNCTIONALITY BELOW:
//-----------------------------------------------------------------------------
BOOL VMMDLL_ProcessGetMemoryMap_Impl(_In_ DWORD dwPID, _Out_ PVMMDLL_MEMMAP_ENTRY pMemMapEntries, _Inout_ PULONG64 pcMemMapEntries, _In_ BOOL fIdentifyModules)
_Success_(return)
BOOL VMMDLL_ProcessGetMemoryMap_Impl(_In_ DWORD dwPID, _Out_opt_ PVMMDLL_MEMMAP_ENTRY pMemMapEntries, _Inout_ PULONG64 pcMemMapEntries, _In_ BOOL fIdentifyModules)
{
PVMM_PROCESS pProcess = VmmProcessGet(dwPID);
if(!pProcess) { return FALSE; }
if(!pProcess->pMemMap || !pProcess->cMemMap) {
if(!pProcess->fSpiderPageTableDone) {
VmmTlbSpider(pProcess->paPML4, pProcess->fUserOnly);
VmmTlbSpider(pProcess->paDTB, pProcess->fUserOnly);
pProcess->fSpiderPageTableDone = TRUE;
}
VmmMapInitialize(pProcess);
@@ -586,6 +611,7 @@ BOOL VMMDLL_ProcessGetMemoryMap_Impl(_In_ DWORD dwPID, _Out_ PVMMDLL_MEMMAP_ENTR
return TRUE;
}
_Success_(return)
BOOL VMMDLL_ProcessGetMemoryMap(_In_ DWORD dwPID, _Out_opt_ PVMMDLL_MEMMAP_ENTRY pMemMapEntries, _Inout_ PULONG64 pcMemMapEntries, _In_ BOOL fIdentifyModules)
{
CALL_SYNCHRONIZED_IMPLEMENTATION_VMM(
@@ -593,6 +619,7 @@ BOOL VMMDLL_ProcessGetMemoryMap(_In_ DWORD dwPID, _Out_opt_ PVMMDLL_MEMMAP_ENTRY
VMMDLL_ProcessGetMemoryMap_Impl(dwPID, pMemMapEntries, pcMemMapEntries, fIdentifyModules))
}
_Success_(return)
BOOL VMMDLL_ProcessGetMemoryMapEntry_Impl(_In_ DWORD dwPID, _Out_ PVMMDLL_MEMMAP_ENTRY pMemMapEntry, _In_ ULONG64 va, _In_ BOOL fIdentifyModules)
{
PVMM_PROCESS pProcess = VmmProcessGet(dwPID);
@@ -611,6 +638,7 @@ BOOL VMMDLL_ProcessGetMemoryMapEntry_Impl(_In_ DWORD dwPID, _Out_ PVMMDLL_MEMMAP
return TRUE;
}
_Success_(return)
BOOL VMMDLL_ProcessGetMemoryMapEntry(_In_ DWORD dwPID, _Out_ PVMMDLL_MEMMAP_ENTRY pMemMapEntry, _In_ ULONG64 va, _In_ BOOL fIdentifyModules)
{
CALL_SYNCHRONIZED_IMPLEMENTATION_VMM(
@@ -618,7 +646,8 @@ BOOL VMMDLL_ProcessGetMemoryMapEntry(_In_ DWORD dwPID, _Out_ PVMMDLL_MEMMAP_ENTR
VMMDLL_ProcessGetMemoryMapEntry_Impl(dwPID, pMemMapEntry, va, fIdentifyModules))
}
BOOL VMMDLL_ProcessGetModuleMap_Impl(_In_ DWORD dwPID, _Out_ PVMMDLL_MODULEMAP_ENTRY pModuleEntries, _Inout_ PULONG64 pcModuleEntries)
_Success_(return)
BOOL VMMDLL_ProcessGetModuleMap_Impl(_In_ DWORD dwPID, _Out_opt_ PVMMDLL_MODULEMAP_ENTRY pModuleEntries, _Inout_ PULONG64 pcModuleEntries)
{
ULONG64 i;
PVMM_PROCESS pProcess = VmmProcessGet(dwPID);
@@ -626,7 +655,7 @@ BOOL VMMDLL_ProcessGetModuleMap_Impl(_In_ DWORD dwPID, _Out_ PVMMDLL_MODULEMAP_E
if(!pcModuleEntries) { return FALSE; }
if(!pProcess->pModuleMap || !pProcess->cModuleMap) {
if(!pProcess->fSpiderPageTableDone) {
VmmTlbSpider(pProcess->paPML4, pProcess->fUserOnly);
VmmTlbSpider(pProcess->paDTB, pProcess->fUserOnly);
pProcess->fSpiderPageTableDone = TRUE;
}
VmmProc_InitializeModuleNames(pProcess);
@@ -643,17 +672,19 @@ BOOL VMMDLL_ProcessGetModuleMap_Impl(_In_ DWORD dwPID, _Out_ PVMMDLL_MODULEMAP_E
return TRUE;
}
BOOL VMMDLL_ProcessGetModuleMap(_In_ DWORD dwPID, _Out_ PVMMDLL_MODULEMAP_ENTRY pModuleEntries, _Inout_ PULONG64 pcModuleEntries)
_Success_(return)
BOOL VMMDLL_ProcessGetModuleMap(_In_ DWORD dwPID, _Out_opt_ PVMMDLL_MODULEMAP_ENTRY pModuleEntries, _Inout_ PULONG64 pcModuleEntries)
{
CALL_SYNCHRONIZED_IMPLEMENTATION_VMM(
STATISTICS_ID_VMMDLL_ProcessGetModuleMap,
VMMDLL_ProcessGetModuleMap_Impl(dwPID, pModuleEntries, pcModuleEntries))
}
_Success_(return)
BOOL VMMDLL_ProcessGetModuleFromName_Impl(_In_ DWORD dwPID, _In_ LPSTR szModuleName, _Out_ PVMMDLL_MODULEMAP_ENTRY pModuleEntry)
{
BOOL result;
ULONG64 i, cModuleEntries;
ULONG64 i, cModuleEntries = 0;
PVMMDLL_MODULEMAP_ENTRY pModuleEntries = NULL;
result = VMMDLL_ProcessGetModuleMap_Impl(dwPID, NULL, &cModuleEntries);
if(!result || !cModuleEntries) { return FALSE; }
@@ -673,6 +704,7 @@ BOOL VMMDLL_ProcessGetModuleFromName_Impl(_In_ DWORD dwPID, _In_ LPSTR szModuleN
return FALSE;
}
_Success_(return)
BOOL VMMDLL_ProcessGetModuleFromName(_In_ DWORD dwPID, _In_ LPSTR szModuleName, _Out_ PVMMDLL_MODULEMAP_ENTRY pModuleEntry)
{
CALL_SYNCHRONIZED_IMPLEMENTATION_VMM(
@@ -680,19 +712,22 @@ BOOL VMMDLL_ProcessGetModuleFromName(_In_ DWORD dwPID, _In_ LPSTR szModuleName,
VMMDLL_ProcessGetModuleFromName_Impl(dwPID, szModuleName, pModuleEntry))
}
BOOL VMMDLL_PidList_Impl(_Out_ PDWORD pPIDs, _Inout_ PULONG64 pcPIDs)
_Success_(return)
BOOL VMMDLL_PidList_Impl(_Out_opt_ PDWORD pPIDs, _Inout_ PULONG64 pcPIDs)
{
VmmProcessListPIDs(pPIDs, pcPIDs);
return TRUE;
}
BOOL VMMDLL_PidList(_Out_ PDWORD pPIDs, _Inout_ PULONG64 pcPIDs)
_Success_(return)
BOOL VMMDLL_PidList(_Out_opt_ PDWORD pPIDs, _Inout_ PULONG64 pcPIDs)
{
CALL_SYNCHRONIZED_IMPLEMENTATION_VMM(
STATISTICS_ID_VMMDLL_PidList,
VMMDLL_PidList_Impl(pPIDs, pcPIDs))
}
_Success_(return)
BOOL VMMDLL_PidGetFromName_Impl(_In_ LPSTR szProcName, _Out_ PDWORD pdwPID)
{
DWORD i, pdwPIDs[1024];
@@ -710,6 +745,7 @@ BOOL VMMDLL_PidGetFromName_Impl(_In_ LPSTR szProcName, _Out_ PDWORD pdwPID)
return FALSE;
}
_Success_(return)
BOOL VMMDLL_PidGetFromName(_In_ LPSTR szProcName, _Out_ PDWORD pdwPID)
{
CALL_SYNCHRONIZED_IMPLEMENTATION_VMM(
@@ -717,6 +753,7 @@ BOOL VMMDLL_PidGetFromName(_In_ LPSTR szProcName, _Out_ PDWORD pdwPID)
VMMDLL_PidGetFromName_Impl(szProcName, pdwPID))
}
_Success_(return)
BOOL VMMDLL_ProcessGetInformation_Impl(_In_ DWORD dwPID, _Inout_opt_ PVMMDLL_PROCESS_INFORMATION pInfo, _In_ PSIZE_T pcbProcessInfo)
{
PVMM_PROCESS pProcess;
@@ -733,25 +770,33 @@ BOOL VMMDLL_ProcessGetInformation_Impl(_In_ DWORD dwPID, _Inout_opt_ PVMMDLL_PRO
// set general parameters
pInfo->wVersion = VMMDLL_PROCESS_INFORMATION_VERSION;
pInfo->wSize = sizeof(VMMDLL_PROCESS_INFORMATION);
pInfo->fTargetSystem = VMMDLL_TARGET_UNKNOWN_X64;
pInfo->tpMemoryModel = ctxVmm->tpMemoryModel;
pInfo->tpSystem = ctxVmm->tpSystem;
pInfo->fUserOnly = pProcess->fUserOnly;
pInfo->dwPID = dwPID;
pInfo->dwState = pProcess->dwState;
pInfo->paPML4 = pProcess->paPML4;
pInfo->paPML4_UserOpt = pProcess->paPML4_UserOpt;
pInfo->paDTB = pProcess->paDTB;
pInfo->paDTB_UserOpt = pProcess->paDTB_UserOpt;
memcpy(pInfo->szName, pProcess->szName, sizeof(pInfo->szName));
// set windows specific parameters
if(ctxVmm->fTargetSystem == VMM_TARGET_WINDOWS_X64) {
pInfo->fTargetSystem = VMMDLL_TARGET_WINDOWS_X64;
pInfo->os.win.fWow64 = pProcess->os.win.fWow64;
pInfo->os.win.vaENTRY = pProcess->os.win.vaENTRY;
pInfo->os.win.vaEPROCESS = pProcess->os.win.vaEPROCESS;
pInfo->os.win.vaPEB = pProcess->os.win.vaPEB;
pInfo->os.win.vaPEB32 = pProcess->os.win.vaPEB32;
// set operating system specific parameters
switch(ctxVmm->tpSystem) {
case VMM_SYSTEM_WINDOWS_X64:
pInfo->os.win.fWow64 = pProcess->os.win.fWow64;
pInfo->os.win.vaENTRY = pProcess->os.win.vaENTRY;
pInfo->os.win.vaEPROCESS = pProcess->os.win.vaEPROCESS;
pInfo->os.win.vaPEB = pProcess->os.win.vaPEB;
pInfo->os.win.vaPEB32 = pProcess->os.win.vaPEB32;
break;
case VMM_SYSTEM_WINDOWS_X86:
pInfo->os.win.vaENTRY = pProcess->os.win.vaENTRY;
pInfo->os.win.vaEPROCESS = pProcess->os.win.vaEPROCESS;
pInfo->os.win.vaPEB = pProcess->os.win.vaPEB;
break;
}
return TRUE;
}
_Success_(return)
BOOL VMMDLL_ProcessGetInformation(_In_ DWORD dwPID, _Inout_opt_ PVMMDLL_PROCESS_INFORMATION pProcessInformation, _In_ PSIZE_T pcbProcessInformation)
{
CALL_SYNCHRONIZED_IMPLEMENTATION_VMM(
@@ -759,12 +804,13 @@ BOOL VMMDLL_ProcessGetInformation(_In_ DWORD dwPID, _Inout_opt_ PVMMDLL_PROCESS_
VMMDLL_ProcessGetInformation_Impl(dwPID, pProcessInformation, pcbProcessInformation))
}
_Success_(return)
BOOL VMMDLL_ProcessGet_Directories_Sections_IAT_EAT_Impl(
_In_ DWORD dwPID,
_In_ LPSTR szModule,
_In_ DWORD cData,
_Out_ PDWORD pcData,
_Out_opt_ PIMAGE_DATA_DIRECTORY pDataDirectory,
_Out_writes_opt_(16) PIMAGE_DATA_DIRECTORY pDataDirectory,
_Out_opt_ PIMAGE_SECTION_HEADER pSections,
_Out_opt_ PVMMDLL_EAT_ENTRY pEAT,
_Out_opt_ PVOID pIAT,
@@ -781,7 +827,7 @@ BOOL VMMDLL_ProcessGet_Directories_Sections_IAT_EAT_Impl(
// genereate module map (if required)
if(!pProcess->pModuleMap || !pProcess->cModuleMap) {
if(!pProcess->fSpiderPageTableDone) {
VmmTlbSpider(pProcess->paPML4, pProcess->fUserOnly);
VmmTlbSpider(pProcess->paDTB, pProcess->fUserOnly);
pProcess->fSpiderPageTableDone = TRUE;
}
VmmProc_InitializeModuleNames(pProcess);
@@ -798,69 +844,74 @@ BOOL VMMDLL_ProcessGet_Directories_Sections_IAT_EAT_Impl(
if(fDataDirectory) {
if(!pDataDirectory) { *pcData = 16; return TRUE; }
if(cData < 16) { return FALSE; }
VmmProcWindows_PE_DIRECTORY_DisplayBuffer(pProcess, pModule, NULL, 0, NULL, pDataDirectory);
VmmWin_PE_DIRECTORY_DisplayBuffer(pProcess, pModule, NULL, 0, NULL, pDataDirectory);
*pcData = 16;
return TRUE;
}
// sections
if(fSections) {
i = VmmProcWindows_PE_GetNumberOfSection(pProcess, pModule, NULL, FALSE);
i = PE_SectionGetNumberOf(pProcess, pModule->BaseAddress);
if(!pSections) { *pcData = i; return TRUE; }
if(cData < i) { return FALSE; }
VmmProcWindows_PE_SECTION_DisplayBuffer(pProcess, pModule, NULL, 0, NULL, pSections);
*pcData = i;
VmmWin_PE_SECTION_DisplayBuffer(pProcess, pModule, NULL, 0, NULL, &cData, pSections);
*pcData = cData;
return TRUE;
}
// export address table (EAT)
if(fEAT) {
i = VmmProcWindows_PE_GetNumberOfEAT(pProcess, pModule, NULL, FALSE);
i = PE_EatGetNumberOf(pProcess, pModule->BaseAddress);
if(!pEAT) { *pcData = i; return TRUE; }
if(cData < i) { return FALSE; }
VmmProcWindows_PE_LoadEAT_DisplayBuffer(pProcess, pModule, (PVMMPROC_WINDOWS_EAT_ENTRY)pEAT, &cData);
VmmWin_PE_LoadEAT_DisplayBuffer(pProcess, pModule, (PVMMPROC_WINDOWS_EAT_ENTRY)pEAT, &cData);
*pcData = cData;
return TRUE;
}
// import address table (IAT)
if(fIAT) {
i = VmmProcWindows_PE_GetNumberOfIAT(pProcess, pModule, NULL, FALSE);
i = PE_IatGetNumberOf(pProcess, pModule->BaseAddress);
if(!pIAT) { *pcData = i; return TRUE; }
if(cData < i) { return FALSE; }
VmmProcWindows_PE_LoadIAT_DisplayBuffer(pProcess, pModule, (PVMMPROC_WINDOWS_IAT_ENTRY)pIAT, &cData);
VmmWin_PE_LoadIAT_DisplayBuffer(pProcess, pModule, (PVMMWIN_IAT_ENTRY)pIAT, &cData);
*pcData = cData;
return TRUE;
}
return FALSE;
}
BOOL VMMDLL_ProcessGetDirectories(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PIMAGE_DATA_DIRECTORY pData, _In_ DWORD cData, _Out_ PDWORD pcData)
_Success_(return)
BOOL VMMDLL_ProcessGetDirectories(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_writes_(16) PIMAGE_DATA_DIRECTORY pData, _In_ DWORD cData, _Out_ PDWORD pcData)
{
CALL_SYNCHRONIZED_IMPLEMENTATION_VMM(
STATISTICS_ID_VMMDLL_ProcessGetDirectories,
VMMDLL_ProcessGet_Directories_Sections_IAT_EAT_Impl(dwPID, szModule, cData, pcData, pData, NULL, NULL, NULL, TRUE, FALSE, FALSE, FALSE))
}
BOOL VMMDLL_ProcessGetSections(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PIMAGE_SECTION_HEADER pData, _In_ DWORD cData, _Out_ PDWORD pcData)
_Success_(return)
BOOL VMMDLL_ProcessGetSections(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_opt_ PIMAGE_SECTION_HEADER pData, _In_ DWORD cData, _Out_ PDWORD pcData)
{
CALL_SYNCHRONIZED_IMPLEMENTATION_VMM(
STATISTICS_ID_VMMDLL_ProcessGetSections,
VMMDLL_ProcessGet_Directories_Sections_IAT_EAT_Impl(dwPID, szModule, cData, pcData, NULL, pData, NULL, NULL, FALSE, TRUE, FALSE, FALSE))
}
BOOL VMMDLL_ProcessGetEAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PVMMDLL_EAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData)
_Success_(return)
BOOL VMMDLL_ProcessGetEAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_opt_ PVMMDLL_EAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData)
{
CALL_SYNCHRONIZED_IMPLEMENTATION_VMM(
STATISTICS_ID_VMMDLL_ProcessGetEAT,
VMMDLL_ProcessGet_Directories_Sections_IAT_EAT_Impl(dwPID, szModule, cData, pcData, NULL, NULL, pData, NULL, FALSE, FALSE, TRUE, FALSE))
}
BOOL VMMDLL_ProcessGetIAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PVMMDLL_IAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData)
_Success_(return)
BOOL VMMDLL_ProcessGetIAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_opt_ PVMMDLL_IAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData)
{
CALL_SYNCHRONIZED_IMPLEMENTATION_VMM(
STATISTICS_ID_VMMDLL_ProcessGetIAT,
VMMDLL_ProcessGet_Directories_Sections_IAT_EAT_Impl(dwPID, szModule, cData, pcData, NULL, NULL, NULL, pData, FALSE, FALSE, FALSE, TRUE))
}
BOOL VMMDLL_UtilFillHexAscii(_In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset, _Inout_ LPSTR sz, _Inout_ PDWORD pcsz)
_Success_(return)
BOOL VMMDLL_UtilFillHexAscii(_In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset, _Inout_opt_ LPSTR sz, _Out_ PDWORD pcsz)
{
return Util_FillHexAscii(pb, cb, cbInitialOffset, sz, pcsz);
}

View File

@@ -23,6 +23,7 @@ extern "C" {
* Call other VMMDLL_Intialize functions to initialize VMM.DLL and the memory
* process file system.
*/
_Success_(return)
BOOL VMMDLL_InitializeReserved(_In_ DWORD argc, _In_ LPSTR argv[]);
/*
@@ -37,6 +38,7 @@ BOOL VMMDLL_InitializeReserved(_In_ DWORD argc, _In_ LPSTR argv[]);
* as hex string. NB! this is usally not required. Example: "0x1ab000".
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeFile(_In_ LPSTR szFileName, _In_opt_ LPSTR szPageTableBaseOpt);
/*
@@ -52,6 +54,7 @@ BOOL VMMDLL_InitializeFile(_In_ LPSTR szFileName, _In_opt_ LPSTR szPageTableBase
* as hex string. NB! this is usally not required. Example: "0x1ab000".
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeFPGA(_In_opt_ LPSTR szMaxPhysicalAddressOpt, _In_opt_ LPSTR szPageTableBaseOpt);
/*
@@ -60,6 +63,7 @@ BOOL VMMDLL_InitializeFPGA(_In_opt_ LPSTR szMaxPhysicalAddressOpt, _In_opt_ LPST
* initialized in read/write mode upon success.
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeTotalMeltdown();
/*
@@ -67,6 +71,7 @@ BOOL VMMDLL_InitializeTotalMeltdown();
* including plugins, linked PCILeech.DLL and other memory resources.
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_Close();
@@ -103,7 +108,8 @@ BOOL VMMDLL_Close();
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA_TLP 0x80000004 // RW
#define VMMDLL_OPT_CORE_MAX_NATIVE_ADDRESS 0x80000005 // R
#define VMMDLL_OPT_CORE_MAX_NATIVE_IOSIZE 0x80000006 // R
#define VMMDLL_OPT_CORE_TARGET_SYSTEM 0x80000007 // R
#define VMMDLL_OPT_CORE_SYSTEM 0x80000007 // R
#define VMMDLL_OPT_CORE_MEMORYMODEL 0x80000008 // R
#define VMMDLL_OPT_CONFIG_IS_REFRESH_ENABLED 0x40000001 // R - 1/0
#define VMMDLL_OPT_CONFIG_TICK_PERIOD 0x40000002 // RW - base tick period in ms
@@ -116,6 +122,22 @@ BOOL VMMDLL_Close();
#define VMMDLL_OPT_CONFIG_VMM_VERSION_REVISION 0x40000009 // R
#define VMMDLL_OPT_CONFIG_STATISTICS_FUNCTIONCALL 0x4000000A // RW - enable function call statistics (.status/statistics_fncall file)
static const LPSTR VMMDLL_MEMORYMODEL_TOSTRING[4] = { "N/A", "X86", "X86PAE", "X64" };
typedef enum tdVMMDLL_MEMORYMODEL_TP {
VMMDLL_MEMORYMODEL_NA = 0,
VMMDLL_MEMORYMODEL_X86 = 1,
VMMDLL_MEMORYMODEL_X86PAE = 2,
VMMDLL_MEMORYMODEL_X64 = 3
} VMMDLL_MEMORYMODEL_TP;
typedef enum tdVMMDLL_SYSTEM_TP {
VMMDLL_SYSTEM_UNKNOWN_X64 = 1,
VMMDLL_SYSTEM_WINDOWS_X64 = 2,
VMMDLL_SYSTEM_UNKNOWN_X86 = 3,
VMMDLL_SYSTEM_WINDOWS_X86 = 4
} VMMDLL_SYSTEM_TP;
/*
* Set a device specific option value. Please see defines VMMDLL_OPT_* for infor-
* mation about valid option values. Please note that option values may overlap
@@ -124,6 +146,7 @@ BOOL VMMDLL_Close();
* -- pqwValue = pointer to ULONG64 to receive option value.
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ConfigGet(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue);
/*
@@ -134,6 +157,7 @@ BOOL VMMDLL_ConfigGet(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue);
* -- qwValue
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ConfigSet(_In_ ULONG64 fOption, _In_ ULONG64 qwValue);
@@ -171,6 +195,7 @@ typedef struct tdVMMDLL_VFS_FILELIST {
* -- pFileList
* -- return
*/
_Success_(return)
BOOL VMMDLL_VfsList(_In_ LPCWSTR wcsPath, _Inout_ PVMMDLL_VFS_FILELIST pFileList);
/*
@@ -227,12 +252,13 @@ NTSTATUS VMMDLL_UtilVfsWriteFile_DWORD(_Inout_ PDWORD pdwTarget, _In_ LPVOID pb,
* will be unloaded on a general close of the vmm dll.
* -- return
*/
_Success_(return)
BOOL VMMDLL_VfsInitializePlugins();
#define VMMDLL_PLUGIN_CONTEXT_MAGIC 0xc0ffee663df9301c
#define VMMDLL_PLUGIN_CONTEXT_VERSION 1
#define VMMDLL_PLUGIN_REGINFO_MAGIC 0xc0ffee663df9301d
#define VMMDLL_PLUGIN_REGINFO_VERSION 1
#define VMMDLL_PLUGIN_REGINFO_VERSION 2
#define VMMDLL_PLUGIN_EVENT_VERBOSITYCHANGE 0x01
@@ -254,7 +280,8 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
ULONG64 magic;
WORD wVersion;
WORD wSize;
DWORD fTargetSystem;
VMMDLL_MEMORYMODEL_TP tpMemoryModel;
VMMDLL_SYSTEM_TP tpSystem;
HMODULE hDLL;
HMODULE hReservedDll; // not for general use (only used for python).
BOOL(*pfnPluginManager_Register)(struct tdVMMDLL_PLUGIN_REGINFO *pPluginRegInfo);
@@ -272,7 +299,7 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
// function plugin registration info to be filled out by the plugin below:
struct {
BOOL(*pfnList)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList);
NTSTATUS(*pfnRead)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset);
NTSTATUS(*pfnRead)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset);
NTSTATUS(*pfnWrite)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset);
VOID(*pfnNotify)(_Inout_opt_ PHANDLE phModulePrivate, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent);
VOID(*pfnCloseHandleModule)(_Inout_opt_ PHANDLE phModulePrivate);
@@ -296,8 +323,7 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
#define VMMDLL_FLAG_NOCACHE 0x0001 // do not use the data cache (force reading from memory acquisition device)
#define VMMDLL_FLAG_ZEROPAD_ON_FAIL 0x0002 // zero pad failed physical memory reads and report success if read within range of physical memory.
#define VMMDLL_TARGET_UNKNOWN_X64 0x0001
#define VMMDLL_TARGET_WINDOWS_X64 0x0002
#define VMMDLL_MEM_IO_SCATTER_HEADER_VERSION 2
typedef struct tdVMMDLL_MEM_IO_SCATTER_HEADER {
ULONG64 qwA; // base address (DWORD boundry).
@@ -306,6 +332,10 @@ typedef struct tdVMMDLL_MEM_IO_SCATTER_HEADER {
PBYTE pb; // ptr to 0x1000 sized buffer to receive read bytes.
PVOID pvReserved1; // reserved for use by caller.
PVOID pvReserved2; // reserved for use by caller.
WORD version; // version of struct
WORD Future1; // reserved for future use.
DWORD Future2; // reserved for future use.
ULONG64 qwDeviceA; // device-physical address (used by device layer).
struct {
PVOID pvReserved1;
PVOID pvReserved2;
@@ -335,6 +365,7 @@ DWORD VMMDLL_MemReadScatter(_In_ DWORD dwPID, _Inout_ PPVMMDLL_MEM_IO_SCATTER_HE
* -- pbPage
* -- return = success/fail (depending if all requested bytes are read or not).
*/
_Success_(return)
BOOL VMMDLL_MemReadPage(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_bytecount_(4096) PBYTE pbPage);
/*
@@ -345,6 +376,7 @@ BOOL VMMDLL_MemReadPage(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_bytecount_(4
* -- cb
* -- return = success/fail (depending if all requested bytes are read or not).
*/
_Success_(return)
BOOL VMMDLL_MemRead(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DWORD cb);
/*
@@ -358,7 +390,8 @@ BOOL VMMDLL_MemRead(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DW
* -- return = success/fail. NB! reads may report as success even if 0 bytes are
* read - it's recommended to verify pcbReadOpt parameter.
*/
BOOL VMMDLL_MemReadEx(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ ULONG64 flags);
_Success_(return)
BOOL VMMDLL_MemReadEx(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ ULONG64 flags);
/*
* Write a contigious arbitrary amount of memory. Please note some virtual memory
@@ -373,7 +406,8 @@ BOOL VMMDLL_MemReadEx(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_ PBYTE pb, _In
* -- cb
* -- return = TRUE on success, FALSE on partial or zero write.
*/
BOOL VMMDLL_MemWrite(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DWORD cb);
_Success_(return)
BOOL VMMDLL_MemWrite(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _In_ PBYTE pb, _In_ DWORD cb);
/*
* Translate a virtual address to a physical address by walking the page tables
@@ -383,6 +417,7 @@ BOOL VMMDLL_MemWrite(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ D
* -- pqwPA
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_MemVirt2Phys(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PULONG64 pqwPA);
@@ -401,6 +436,7 @@ BOOL VMMDLL_MemVirt2Phys(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PULONG64 pqw
* -- pdwPID = pointer that will receive PID on success.
* -- return
*/
_Success_(return)
BOOL VMMDLL_PidGetFromName(_In_ LPSTR szProcName, _Out_ PDWORD pdwPID);
/*
@@ -409,7 +445,8 @@ BOOL VMMDLL_PidGetFromName(_In_ LPSTR szProcName, _Out_ PDWORD pdwPID);
* -- pcPIDs = size of (in number of DWORDs) pPIDs array on entry, number of PIDs in system on exit.
* -- return = success/fail.
*/
BOOL VMMDLL_PidList(_Out_ PDWORD pPIDs, _Inout_ PULONG64 pcPIDs);
_Success_(return)
BOOL VMMDLL_PidList(_Out_opt_ PDWORD pPIDs, _Inout_ PULONG64 pcPIDs);
// flags to check for existence in the fPage field of PCILEECH_VMM_MEMMAP_ENTRY
#define VMMDLL_MEMMAP_FLAG_PAGE_W 0x0000000000000002
@@ -437,6 +474,7 @@ typedef struct tdVMMDLL_MEMMAP_ENTRY {
* -- fIdentifyModules = try identify modules as well (= slower)
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ProcessGetMemoryMap(_In_ DWORD dwPID, _Out_opt_ PVMMDLL_MEMMAP_ENTRY pMemMapEntries, _Inout_ PULONG64 pcMemMapEntries, _In_ BOOL fIdentifyModules);
/*
@@ -448,6 +486,7 @@ BOOL VMMDLL_ProcessGetMemoryMap(_In_ DWORD dwPID, _Out_opt_ PVMMDLL_MEMMAP_ENTRY
* -- fIdentifyModules = try identify modules as well (= slower)
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ProcessGetMemoryMapEntry(_In_ DWORD dwPID, _Out_ PVMMDLL_MEMMAP_ENTRY pMemMapEntry, _In_ ULONG64 va, _In_ BOOL fIdentifyModules);
typedef struct tdVMMDLL_MODULEMAP_ENTRY {
@@ -469,7 +508,8 @@ typedef struct tdVMMDLL_MODULEMAP_ENTRY {
* -- pcModuleEntries = pointer to number of memory map entries.
* -- return = success/fail.
*/
BOOL VMMDLL_ProcessGetModuleMap(_In_ DWORD dwPID, _Out_ PVMMDLL_MODULEMAP_ENTRY pModuleEntries, _Inout_ PULONG64 pcModuleEntries);
_Success_(return)
BOOL VMMDLL_ProcessGetModuleMap(_In_ DWORD dwPID, _Out_opt_ PVMMDLL_MODULEMAP_ENTRY pModuleEntries, _Inout_ PULONG64 pcModuleEntries);
/*
* Retrieve a module (.exe or .dll or similar) given a module name.
@@ -478,29 +518,31 @@ BOOL VMMDLL_ProcessGetModuleMap(_In_ DWORD dwPID, _Out_ PVMMDLL_MODULEMAP_ENTRY
* -- pModuleEntry
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ProcessGetModuleFromName(_In_ DWORD dwPID, _In_ LPSTR szModuleName, _Out_ PVMMDLL_MODULEMAP_ENTRY pModuleEntry);
#define VMMDLL_PROCESS_INFORMATION_MAGIC 0xc0ffee663df9301d
#define VMMDLL_PROCESS_INFORMATION_VERSION 1
#define VMMDLL_PROCESS_INFORMATION_MAGIC 0xc0ffee663df9301e
#define VMMDLL_PROCESS_INFORMATION_VERSION 2
typedef struct tdVMMDLL_PROCESS_INFORMATION {
ULONG64 magic;
WORD wVersion;
WORD wSize;
DWORD fTargetSystem; // as given by VMMDLL_TARGET_*
BOOL fUserOnly; // only user mode pages listed
VMMDLL_MEMORYMODEL_TP tpMemoryModel; // as given by VMMDLL_MEMORYMODEL_* enum
VMMDLL_SYSTEM_TP tpSystem; // as given by VMMDLL_SYSTEM_* enum
BOOL fUserOnly; // only user mode pages listed
DWORD dwPID;
DWORD dwState;
CHAR szName[16];
ULONG64 paPML4;
ULONG64 paPML4_UserOpt; // may not exist
ULONG64 paDTB;
ULONG64 paDTB_UserOpt; // may not exist
union {
struct {
ULONG64 vaEPROCESS;
ULONG64 vaPEB;
ULONG64 vaENTRY;
BOOL fWow64;
DWORD vaPEB32; // WoW64 only
DWORD vaPEB32; // WoW64 only
} win;
} os;
} VMMDLL_PROCESS_INFORMATION, *PVMMDLL_PROCESS_INFORMATION;
@@ -513,6 +555,7 @@ typedef struct tdVMMDLL_PROCESS_INFORMATION {
* -- pcbProcessInformation = size of pProcessInfo (in bytes) on entry and exit
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ProcessGetInformation(_In_ DWORD dwPID, _Inout_opt_ PVMMDLL_PROCESS_INFORMATION pProcessInformation, _In_ PSIZE_T pcbProcessInformation);
typedef struct tdVMMDLL_EAT_ENTRY {
@@ -539,10 +582,14 @@ typedef struct tdVMMDLL_IAT_ENTRY {
* -- pcData
* -- return = success/fail.
*/
BOOL VMMDLL_ProcessGetDirectories(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PIMAGE_DATA_DIRECTORY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
BOOL VMMDLL_ProcessGetSections(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PIMAGE_SECTION_HEADER pData, _In_ DWORD cData, _Out_ PDWORD pcData);
BOOL VMMDLL_ProcessGetEAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PVMMDLL_EAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
BOOL VMMDLL_ProcessGetIAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PVMMDLL_IAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
_Success_(return)
BOOL VMMDLL_ProcessGetDirectories(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_writes_(16) PIMAGE_DATA_DIRECTORY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
_Success_(return)
BOOL VMMDLL_ProcessGetSections(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_opt_ PIMAGE_SECTION_HEADER pData, _In_ DWORD cData, _Out_ PDWORD pcData);
_Success_(return)
BOOL VMMDLL_ProcessGetEAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_opt_ PVMMDLL_EAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
_Success_(return)
BOOL VMMDLL_ProcessGetIAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_opt_ PVMMDLL_IAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
@@ -558,7 +605,8 @@ BOOL VMMDLL_ProcessGetIAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PVMMDLL_I
* -- sz = buffer to fill, NULL to retrieve size in pcsz parameter.
* -- pcsz = ptr to size of buffer on entry, size of characters on exit.
*/
BOOL VMMDLL_UtilFillHexAscii(_In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset, _Inout_ LPSTR sz, _Inout_ PDWORD pcsz);
_Success_(return)
BOOL VMMDLL_UtilFillHexAscii(_In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset, _Inout_opt_ LPSTR sz, _Out_ PDWORD pcsz);
#ifdef __cplusplus
}

View File

@@ -5,7 +5,8 @@
//
#include "vmmproc.h"
#include "vmmproc_windows.h"
#include "vmmwin.h"
#include "vmmwininit.h"
#include "device.h"
#include "statistics.h"
#include "util.h"
@@ -14,128 +15,66 @@
// GENERIC PROCESS RELATED FUNCTIONALITY BELOW:
// ----------------------------------------------------------------------------
/*
* see VmmProcPHYS_ScanWindowsKernel_LargePages for more information!
* Scan a page table hierarchy between virtual addresses between vaMin and vaMax
* for the first occurence of large 2MB pages. This is usually the ntoskrnl.exe
* if the OS is Windows. Ntoskrnl.exe is loaded between the virtual addresses:
* 0xFFFFF80000000000-0xFFFFF803FFFFFFFF
* -- ctxVmm,
* -- paTable = set to: physical address of PML4
* -- vaBase = set to 0
* -- vaMin = 0xFFFFF80000000000 (if windows kernel)
* -- vaMax = 0xFFFFF803FFFFFFFF (if windows kernel)
* -- cPML = set to 4
* -- pvaBase
* -- pcbSize
*/
VOID VmmProcPHYS_ScanWindowsKernel_LargePages_PageTableWalk(_In_ QWORD paTable, _In_ QWORD vaBase, _In_ QWORD vaMin, _In_ QWORD vaMax, _In_ BYTE cPML, _Inout_ PQWORD pvaBase, _Inout_ PQWORD pcbSize)
{
const QWORD PML_REGION_SIZE[5] = { 0, 12, 21, 30, 39 };
QWORD i, pte, *ptes, vaCurrent, vaSizeRegion;
ptes = (PQWORD)VmmTlbGetPageTable(paTable, FALSE);
if(!ptes) { return; }
if(cPML == 4) {
*pvaBase = 0;
*pcbSize = 0;
if(!VmmTlbPageTableVerify((PBYTE)ptes, paTable, TRUE)) { return; }
vaBase = 0;
}
for(i = 0; i < 512; i++) {
// address in range
vaSizeRegion = 1ULL << PML_REGION_SIZE[cPML];
vaCurrent = vaBase + (i << PML_REGION_SIZE[cPML]);
vaCurrent |= (vaCurrent & 0x0000800000000000) ? 0xffff000000000000 : 0; // sign extend
if(*pvaBase && (vaCurrent >(*pvaBase + *pcbSize))) { return; }
if(vaCurrent < vaMin) { continue; }
if(vaCurrent > vaMax) { return; }
// check PTEs
pte = ptes[i];
if(!(pte & 0x01)) { continue; } // NOT VALID
if(cPML == 2) {
if(!(pte & 0x80)) { continue; }
if(!*pvaBase) { *pvaBase = vaCurrent; }
*pcbSize += 0x200000;
continue;
} else {
if(pte & 0x80) { continue; } // PS = 1
VmmProcPHYS_ScanWindowsKernel_LargePages_PageTableWalk(pte & 0x0000fffffffff000, vaCurrent, vaMin, vaMax, cPML - 1, pvaBase, pcbSize);
}
}
}
/*
* Sometimes the PageDirectoryBase (PML4) is known, but the kernel location may
* be unknown. This functions walks the page table in the area in which ntoskrnl
* is loaded (0xFFFFF80000000000-0xFFFFF803FFFFFFFF) looking for 2MB large pages
* If an area in 2MB pages are found it is scanned for the ntoskrnl.exe base.
* -- paPML4
* -- return = virtual address of ntoskrnl.exe base if successful, otherwise 0.
*/
QWORD VmmProcPHYS_ScanWindowsKernel_LargePages(_In_ QWORD paPML4)
{
PBYTE pbBuffer;
QWORD p, o, vaCurrentMin, vaBase, cbSize;
PVMM_PROCESS pSystemProcess = NULL;
BOOL fINITKDBG, fPOOLCODE;
vaCurrentMin = 0xFFFFF80000000000; // base of windows kernel possible location
while(TRUE) {
VmmProcPHYS_ScanWindowsKernel_LargePages_PageTableWalk(paPML4, 0, vaCurrentMin, 0xFFFFF803FFFFFFFF, 4, &vaBase, &cbSize);
if(!vaBase) { return 0; }
vaCurrentMin = vaBase + cbSize;
if(cbSize <= 0x00400000) { continue; } // too small
if(cbSize >= 0x01000000) { continue; } // too big
if(!pSystemProcess) {
pSystemProcess = VmmProcessCreateEntry(4, 0, paPML4, 0, "System", FALSE, FALSE);
if(!pSystemProcess) { return 0; }
VmmProcessCreateFinish();
}
// try locate ntoskrnl.exe base inside suggested area
pbBuffer = (PBYTE)LocalAlloc(0, cbSize);
if(!pbBuffer) { return 0; }
VmmReadEx(pSystemProcess, vaBase, pbBuffer, (DWORD)cbSize, NULL, 0);
for(p = 0; p < cbSize; p += 0x1000) {
if(*(PWORD)(pbBuffer + p) != 0x5a4d) { continue; }
// check if module header contains INITKDBG and POOLCODE
fINITKDBG = FALSE;
fPOOLCODE = FALSE;
for(o = 0; o < 0x1000; o += 8) {
if(*(PQWORD)(pbBuffer + p + o) == 0x4742444B54494E49) { // INITKDBG
fINITKDBG = TRUE;
}
if(*(PQWORD)(pbBuffer + p + o) == 0x45444F434C4F4F50) { // POOLCODE
fPOOLCODE = TRUE;
}
if(fINITKDBG && fPOOLCODE) {
LocalFree(pbBuffer);
return vaBase + p;
}
}
}
LocalFree(pbBuffer);
}
}
// ----------------------------------------------------------------------------
// GENERIC PROCESS RELATED FUNCTIONALITY BELOW:
// ----------------------------------------------------------------------------
/*
* Try initialize from user supplied CR3/PML4 supplied in parameter at startup.
* -- ctx
* -- return
*/
BOOL VmmProcUserCR3TryInitialize()
BOOL VmmProcUserCR3TryInitialize64()
{
PVMM_PROCESS pProcess;
VmmInitializeMemoryModel(VMM_MEMORYMODEL_X64);
pProcess = VmmProcessCreateEntry(0, 0, ctxMain->cfg.paCR3, 0, "unknown_process", FALSE, TRUE);
VmmProcessCreateFinish();
if(!pProcess) {
vmmprintfv("VmmProc: FAIL: Initialization of Process failed from user-defined CR3 %016llx. #4.\n", ctxMain->cfg.paCR3);
vmmprintfv("VmmProc: FAIL: Initialization of Process failed from user-defined CR3 %016llx.\n", ctxMain->cfg.paCR3);
VmmInitializeMemoryModel(VMM_MEMORYMODEL_NA);
return FALSE;
}
VmmTlbSpider(pProcess->paPML4, FALSE);
ctxVmm->fTargetSystem = VMM_TARGET_UNKNOWN_X64;
VmmTlbSpider(pProcess->paDTB, FALSE);
ctxVmm->tpSystem = VMM_SYSTEM_UNKNOWN_X64;
ctxVmm->kernel.paDTB = ctxMain->cfg.paCR3;
return TRUE;
}
BOOL VmmProc_Refresh(_In_ BOOL fProcessList, _In_ BOOL fProcessFull)
{
PVMM_PROCESS pSystemProcess;
QWORD paSystemPML4, vaSystemEPROCESS;
if(fProcessList) {
ctxVmm->stat.cRefreshProcessPartial++;
// Windows OS
if((ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X64) || (ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X86)) {
pSystemProcess = VmmProcessGet(4);
if(pSystemProcess) {
VmmWin_EnumerateEPROCESS(pSystemProcess);
vmmprintfvv("VmmProc: vmmproc.c!VmmProcCacheUpdaterThread FlushProcessList\n");
}
}
}
if(fProcessFull) {
ctxVmm->stat.cRefreshProcessFull++;
// Windows OS
if((ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X64) || (ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X86)) {
pSystemProcess = VmmProcessGet(4);
if(pSystemProcess) {
paSystemPML4 = pSystemProcess->paDTB;
vaSystemEPROCESS = pSystemProcess->os.win.vaEPROCESS;
// spider TLB and set up initial system process and enumerate EPROCESS
VmmTlbSpider(paSystemPML4, FALSE);
pSystemProcess = VmmProcessCreateEntry(4, 0, paSystemPML4, 0, "System", FALSE, TRUE);
if(!pSystemProcess) { return FALSE; }
pSystemProcess->os.win.vaEPROCESS = vaSystemEPROCESS;
VmmWin_EnumerateEPROCESS(pSystemProcess);
vmmprintfvv("vmmproc.c!VmmProc_Refresh FlushProcessListAndBuffers\n");
}
}
// Single user-defined X64 process
if(ctxVmm->tpSystem == VMM_SYSTEM_UNKNOWN_X64) {
VmmProcessCreateTable();
VmmProcUserCR3TryInitialize64();
}
}
return TRUE;
}
@@ -149,8 +88,6 @@ DWORD VmmProcCacheUpdaterThread()
{
QWORD i = 0;
BOOL fPHYS, fTLB, fProcList, fProcTotal;
PVMM_PROCESS pSystemProcess;
QWORD paSystemPML4, vaSystemEPROCESS;
vmmprintfv("VmmProc: Start periodic cache flushing.\n");
ctxVmm->ThreadProcCache.cMs_TickPeriod = VMMPROC_UPDATERTHREAD_PERIOD;
ctxVmm->ThreadProcCache.cTick_Phys = VMMPROC_UPDATERTHREAD_PHYSCACHE;
@@ -173,44 +110,16 @@ DWORD VmmProcCacheUpdaterThread()
}
// refresh proc list
if(fProcList) {
ctxVmm->stat.cRefreshProcessPartial++;
// Windows OS
if(ctxVmm->fTargetSystem & VMM_TARGET_WINDOWS_X64) {
pSystemProcess = VmmProcessGet(4);
if(pSystemProcess) {
VmmProcWindows_EnumerateEPROCESS(pSystemProcess);
vmmprintfvv("VmmProc: vmmproc.c!VmmProcCacheUpdaterThread FlushProcessList\n");
}
}
VmmProc_Refresh(TRUE, FALSE);
}
// total refresh of entire proc cache
if(fProcTotal) {
ctxVmm->stat.cRefreshProcessFull++;
// Windows OS
if(ctxVmm->fTargetSystem & VMM_TARGET_WINDOWS_X64) {
pSystemProcess = VmmProcessGet(4);
if(pSystemProcess) {
paSystemPML4 = pSystemProcess->paPML4;
vaSystemEPROCESS = pSystemProcess->os.win.vaEPROCESS;
// spider TLB and set up initial system process and enumerate EPROCESS
VmmTlbSpider(paSystemPML4, FALSE);
pSystemProcess = VmmProcessCreateEntry(4, 0, paSystemPML4, 0, "System", FALSE, TRUE);
if(!pSystemProcess) {
vmmprintf("VmmProc: Failed to refresh memory process file system - aborting.\n");
VmmProcessCreateFinish();
ctxVmm->ThreadProcCache.fEnabled = FALSE;
LeaveCriticalSection(&ctxVmm->MasterLock);
goto fail;
}
pSystemProcess->os.win.vaEPROCESS = vaSystemEPROCESS;
VmmProcWindows_EnumerateEPROCESS(pSystemProcess);
vmmprintfvv("VmmProc: vmmproc.c!VmmProcCacheUpdaterThread FlushProcessListAndBuffers\n");
}
}
// Single user-defined X64 process
if(ctxVmm->fTargetSystem & VMM_TARGET_UNKNOWN_X64) {
VmmProcessCreateTable();
VmmProcUserCR3TryInitialize(ctxVmm);
if(!VmmProc_Refresh(FALSE, TRUE)) {
vmmprintf("VmmProc: Failed to refresh memory process file system - aborting.\n");
VmmProcessCreateFinish();
ctxVmm->ThreadProcCache.fEnabled = FALSE;
LeaveCriticalSection(&ctxVmm->MasterLock);
goto fail;
}
}
LeaveCriticalSection(&ctxVmm->MasterLock);
@@ -223,47 +132,27 @@ fail:
VOID VmmProc_InitializeModuleNames(_In_ PVMM_PROCESS pProcess)
{
if(ctxVmm->fTargetSystem & VMM_TARGET_WINDOWS_X64) {
VmmProcWindows_InitializeModuleNames(pProcess);
if((ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X64) || (ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X86)) {
VmmWin_InitializeModuleNames(pProcess);
}
}
BOOL VmmProcInitialize()
{
BOOL result;
QWORD vaKernelBase;
BOOL result = FALSE;
if(!VmmInitialize()) { return FALSE; }
// user supplied a CR3 - use it!
if(ctxMain->cfg.paCR3) {
// if VmmProcPHYS_ScanWindowsKernel_LargePages returns a value this is a
// Windows system - initialize it, otherwise initialize the generic x64
// single process more basic mode.
result = FALSE;
vaKernelBase = VmmProcPHYS_ScanWindowsKernel_LargePages(ctxMain->cfg.paCR3);
if(vaKernelBase) {
result = VmmProcWindows_TryInitialize(ctxMain->cfg.paCR3, vaKernelBase);
}
if(!vaKernelBase) {
result = VmmProcUserCR3TryInitialize(ctxVmm);
if(!result) {
VmmInitialize(); // re-initialize VMM to clear state
}
}
if(!result) {
result = VmmProcUserCR3TryInitialize(ctxVmm);
}
} else {
// no page directory was found, so try initialize it by looking if the
// "low stub" exists on a Windows sytem and use it. Otherwise fail.
result = VmmProcWindows_TryInitialize(0, 0);
// 1: try initialize 'windows' with an optionally supplied CR3
result = VmmWinInit_TryInitialize(ctxMain->cfg.paCR3);
if(!result) {
result = ctxMain->cfg.paCR3 && VmmProcUserCR3TryInitialize64();
if(!result) {
vmmprintf(
"VmmProc: Unable to auto-identify operating system for PROC file system mount. \n" \
" Please specify PageDirectoryBase (CR3/PML4) in the -cr3 option if value\n" \
" Please specify PageDirectoryBase (DTB/CR3) in the -cr3 option if value \n" \
" is known. If unknown it may be recoverable with command 'identify'. \n");
}
}
// set up cache mainenance in the form of a separate worker thread in case
// set up cache maintenance in the form of a separate worker thread in case
// the backend is a writeable device (FPGA). File devices are read-only so
// far so full caching is enabled since they are considered to be read-only.
if(result && !ctxVmm->fReadOnly) {
@@ -308,34 +197,38 @@ _Success_(return)
BOOL VmmProcPHYS_ScanForKernel(_Out_ PQWORD ppaPML4, _In_ QWORD paBase, _In_ QWORD paMax, _In_ LPSTR szDescription)
{
QWORD o, i, paCurrent;
PAGE_STATISTICS pageStat;
PBYTE pbBuffer8M;
PBYTE pbBuffer8M = NULL;
PPAGE_STATISTICS pPageStat = NULL;
BOOL result;
// initialize / allocate memory
if(!(pbBuffer8M = LocalAlloc(0, 0x800000))) { return FALSE; }
ZeroMemory(&pageStat, sizeof(PAGE_STATISTICS));
pbBuffer8M = LocalAlloc(0, 0x800000);
pPageStat = (PPAGE_STATISTICS)LocalAlloc(LMEM_ZEROINIT, sizeof(PAGE_STATISTICS));
if(!pbBuffer8M || !pPageStat) { goto fail; }
paCurrent = paBase;
PageStatInitialize(&pageStat, paCurrent, paMax, szDescription, FALSE, FALSE);
PageStatInitialize(pPageStat, paCurrent, paMax, szDescription, FALSE, FALSE);
// loop kmd-find
for(; paCurrent < paMax; paCurrent += 0x00800000) {
if(!DeviceReadMEMEx(paCurrent, pbBuffer8M, 0x00800000, &pageStat)) { continue; }
if(!DeviceReadMEMEx(paCurrent, pbBuffer8M, 0x00800000, pPageStat)) { continue; }
for(o = 0; o < 0x00800000; o += 0x1000) {
// Scan for windows EPROCESS (to get DirectoryBase/PML4)
for(i = 0; i < 0x1000; i += 8) {
if(*(PQWORD)(pbBuffer8M + o + i) == 0x00006D6574737953) {
result = VmmProcPHYS_VerifyWindowsEPROCESS(pbBuffer8M, 0x00800000, o + i, ppaPML4);
if(result) {
pageStat.szAction = "Windows System PageDirectoryBase/PML4 located";
pPageStat->szAction = "Windows System PageDirectoryBase/PML4 located";
PageStatClose(pPageStat);
LocalFree(pPageStat);
LocalFree(pbBuffer8M);
PageStatClose(&pageStat);
return TRUE;
}
}
}
}
}
fail:
if(pPageStat) { PageStatClose(pPageStat); }
LocalFree(pPageStat);
LocalFree(pbBuffer8M);
PageStatClose(&pageStat);
*ppaPML4 = 0;
return FALSE;
}

View File

@@ -7,6 +7,14 @@
#define __VMMPROC_H__
#include "vmm.h"
/*
* Force a refresh of the process list.
* -- fProcessList = partial refresh of processes should be done.
* -- fProcessFull = full refresh of processes should be done.
* -- return
*/
BOOL VmmProc_Refresh(_In_ BOOL fProcessList, _In_ BOOL fProcessFull);
/*
* Load operating system dependant module names, such as parsed from PE or ELF
* into the proper display caches, and also into the memory map.

View File

@@ -1,116 +0,0 @@
// vmmproc_windows.h : definitions related to windows operating system and processes.
// parsing of virtual memory. Windows related features only.
//
// (c) Ulf Frisk, 2018
// Author: Ulf Frisk, pcileech@frizk.net
//
#ifndef __VMMPROC_WINDOWS_H__
#define __VMMPROC_WINDOWS_H__
#include "vmm.h"
typedef struct tdVMMPROC_WINDOWS_EAT_ENTRY {
QWORD vaFunction;
DWORD vaFunctionOffset;
CHAR szFunction[40];
} VMMPROC_WINDOWS_EAT_ENTRY, *PVMMPROC_WINDOWS_EAT_ENTRY;
typedef struct tdVMMPROC_WINDOWS_IAT_ENTRY {
ULONG64 vaFunction;
CHAR szFunction[40];
CHAR szModule[64];
} VMMPROC_WINDOWS_IAT_ENTRY, *PVMMPROC_WINDOWS_IAT_ENTRY;
/*
* Load the size of the required display buffer for sections, imports and export
* into the pModule struct. The size is a direct consequence of the number of
* functions since fixed line sizes are used for all these types. Loading is
* done in a recource efficient way to minimize I/O as much as possible.
* -- pProcess
* -- pModule
*/
VOID VmmProcWindows_PE_SetSizeSectionIATEAT_DisplayBuffer(_In_ PVMM_PROCESS pProcess, _Inout_ PVMM_MODULEMAP_ENTRY pModule);
/*
* Walk the export address table (EAT) from a given pProcess and store it in the
* in the caller supplied pEATs/pcEATs structures.
* -- pProcess
* -- pModule
* -- pEATs
* -- pcEATs = number max items of pEATs on entry, number of actual items of pEATs on exit
*/
VOID VmmProcWindows_PE_LoadEAT_DisplayBuffer(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_MODULEMAP_ENTRY pModule, _Out_ PVMMPROC_WINDOWS_EAT_ENTRY pEATs, _Inout_ PDWORD pcEATs);
/*
* Walk the import address table (IAT) from a given pProcess and store it in the
* in the caller supplied pIATs/pcIATs structures.
* -- pProcess
* -- pModule
* -- pIATs
* -- pcIATs = number max items of pIATs on entry, number of actual items of pIATs on exit
*/
VOID VmmProcWindows_PE_LoadIAT_DisplayBuffer(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_MODULEMAP_ENTRY pModule, _Out_ PVMMPROC_WINDOWS_IAT_ENTRY pIATs, _Inout_ PDWORD pcIATs);
/*
* Fill the pbDisplayBuffer with a human readable version of the data directories.
* This is guaranteed to be exactly 864 bytes (excluding NULL terminator).
* Alternatively copy the 16 data directories into pDataDirectoryOpt.
* -- pProcess
* -- pModule
* -- pbDisplayBufferOpt
* -- cbDisplayBufferMax
* -- pcbDisplayBuffer
* -- pDataDirectoryOpt
*/
VOID VmmProcWindows_PE_DIRECTORY_DisplayBuffer(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MODULEMAP_ENTRY pModule, _Out_opt_ PBYTE pbDisplayBufferOpt, _In_ DWORD cbDisplayBufferMax, _Out_ PDWORD pcbDisplayBuffer, _Out_opt_ PIMAGE_DATA_DIRECTORY pDataDirectoryOpt);
/*
* Fill the pbDisplayBuffer with a human readable version of the PE sections.
* Alternatively copy the sections into the pSectionsOpt buffer.
* -- pProcess
* -- pModule
* -- pbDisplayBufferOpt
* -- cbDisplayBufferMax
* -- pcbDisplayBuffer
* -- pSectionsOpt
*/
VOID VmmProcWindows_PE_SECTION_DisplayBuffer(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MODULEMAP_ENTRY pModule, _Out_opt_ PBYTE pbDisplayBufferOpt, _In_ DWORD cbDisplayBufferMax, _Out_ PDWORD pcbDisplayBuffer, _Out_opt_ PIMAGE_SECTION_HEADER pSectionsOpt);
/*
* Retrieve the number of: sections, EAT entries or IAT entries depending on the
* function that is called.
* -- pProcess
* -- pModule
* -- pbModuleHeaderOpt = optional PIMAGE_NT_HEADERS structure (either 32 or 64-bit)
* -- fHdr32 = specified whether pbModuleHeaderOpt is a 32-bit or 64-bit header.
* -- return = the number of entries
*/
WORD VmmProcWindows_PE_GetNumberOfSection(_In_ PVMM_PROCESS pProcess, _Inout_ PVMM_MODULEMAP_ENTRY pModule, _In_opt_ PIMAGE_NT_HEADERS pbModuleHeaderOpt, _In_opt_ BOOL fHdr32);
DWORD VmmProcWindows_PE_GetNumberOfEAT(_In_ PVMM_PROCESS pProcess, _Inout_ PVMM_MODULEMAP_ENTRY pModule, _In_opt_ PIMAGE_NT_HEADERS pbModuleHeaderOpt, _In_opt_ BOOL fHdr32);
DWORD VmmProcWindows_PE_GetNumberOfIAT(_In_ PVMM_PROCESS pProcess, _Inout_ PVMM_MODULEMAP_ENTRY pModule, _In_opt_ PIMAGE_NT_HEADERS pbModuleHeaderOpt, _In_opt_ BOOL fHdr32);
/*
* Initialize the module names into the ctxVMM. This is performed by a PEB/Ldr
* scan of in-process memory structures. This may be unreliable of process is
* obfuscated.
* -- pProcess
*/
VOID VmmProcWindows_InitializeModuleNames(_In_ PVMM_PROCESS pProcess);
/*
* Try walk the EPROCESS list in the Windows kernel to enumerate processes into
* the VMM/PROC file system.
* NB! This may be done to refresh an existing PID cache hence migration code.
* -- pSystemProcess
* -- return
*/
BOOL VmmProcWindows_EnumerateEPROCESS(_In_ PVMM_PROCESS pSystemProcess);
/*
* Try initialize the VMM from scratch with new WINDOWS support.
* -- paPML4Opt
* -- vaKernelBaseOpt
* -- return
*/
BOOL VmmProcWindows_TryInitialize(_In_opt_ QWORD paPML4Opt, _In_opt_ QWORD vaKernelBaseOpt);
#endif /* __VMMPROC_WINDOWS_H__ */

View File

@@ -7,7 +7,7 @@
#include "vmmdll.h"
#include "pluginmanager.h"
#include "vmmproc.h"
#include "vmmproc_windows.h"
#include "vmmwin.h"
#include "util.h"
typedef struct tdVMMVFS_PATH {
@@ -19,7 +19,7 @@ typedef struct tdVMMVFS_PATH {
LPSTR szPath2;
} VMMVFS_PATH, *PVMMVFS_PATH;
BOOL VmmVfs_UtilVmmGetPidDirFile(_In_ LPCWSTR wcsFileName, _Inout_ PVMMVFS_PATH pPath)
BOOL VmmVfs_UtilVmmGetPidDirFile(_In_ LPCWSTR wcsFileName, _Out_ PVMMVFS_PATH pPath)
{
DWORD i = 0, iPID, iPath1 = 0, iPath2 = 0;
// 1: convert to ascii string
@@ -78,6 +78,10 @@ NTSTATUS VmmVfsReadFileProcess(_In_ PVMMVFS_PATH pPath, _Out_ LPVOID pb, _In_ DW
if(!pProcess) { return VMM_STATUS_FILE_INVALID; }
// read memory from "vmem" file
if(!_stricmp(pPath->szPath1, "vmem")) {
if((ctxVmm->tpMemoryModel != VMM_MEMORYMODEL_X64) && (cbOffset + cb >= 0x100000000)) {
if(cbOffset >= 0x100000000) { return VMM_STATUS_END_OF_FILE; }
cb = (DWORD)(0x100000000 - cbOffset);
}
VmmReadEx(pProcess, cbOffset, pb, cb, NULL, 0);
*pcbRead = cb;
return VMM_STATUS_SUCCESS;
@@ -93,11 +97,19 @@ NTSTATUS VmmVfsReadFileProcess(_In_ PVMMVFS_PATH pPath, _Out_ LPVOID pb, _In_ DW
return Util_VfsReadFile_FromPBYTE(pProcess->pbMemMapDisplayCache, pProcess->cbMemMapDisplayCache, pb, cb, pcbRead, cbOffset);
}
// read genereal numeric values from files, pml4, pid, name, virt
if(!_stricmp(pPath->szPath1, "pml4")) {
return Util_VfsReadFile_FromQWORD(pProcess->paPML4, pb, cb, pcbRead, cbOffset, FALSE);
if(!_stricmp(pPath->szPath1, "dtb")) {
if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X64) {
return Util_VfsReadFile_FromQWORD(pProcess->paDTB, pb, cb, pcbRead, cbOffset, FALSE);
} else if((ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X86) || (ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X86PAE)) {
return Util_VfsReadFile_FromDWORD((DWORD)pProcess->paDTB, pb, cb, pcbRead, cbOffset, FALSE);
}
}
if(!_stricmp(pPath->szPath1, "pml4-user")) {
return Util_VfsReadFile_FromQWORD(pProcess->paPML4_UserOpt, pb, cb, pcbRead, cbOffset, FALSE);
if(!_stricmp(pPath->szPath1, "dtb-user")) {
if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X64) {
return Util_VfsReadFile_FromQWORD(pProcess->paDTB_UserOpt, pb, cb, pcbRead, cbOffset, FALSE);
} else if((ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X86) || (ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X86PAE)) {
return Util_VfsReadFile_FromDWORD((DWORD)pProcess->paDTB_UserOpt, pb, cb, pcbRead, cbOffset, FALSE);
}
}
if(!_stricmp(pPath->szPath1, "pid")) {
cbBuffer = snprintf(pbBuffer, 32, "%i", pProcess->dwPID);
@@ -108,7 +120,7 @@ NTSTATUS VmmVfsReadFileProcess(_In_ PVMMVFS_PATH pPath, _Out_ LPVOID pb, _In_ DW
return Util_VfsReadFile_FromPBYTE(pbBuffer, cbBuffer, pb, cb, pcbRead, cbOffset);
}
// windows specific reads below:
if(ctxVmm->fTargetSystem & VMM_TARGET_WINDOWS_X64) {
if(ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X64) {
if(!_stricmp(pPath->szPath1, "win-eprocess")) {
return Util_VfsReadFile_FromQWORD(pProcess->os.win.vaEPROCESS, pb, cb, pcbRead, cbOffset, FALSE);
}
@@ -125,6 +137,20 @@ NTSTATUS VmmVfsReadFileProcess(_In_ PVMMVFS_PATH pPath, _Out_ LPVOID pb, _In_ DW
return Util_VfsReadFile_FromDWORD(pProcess->os.win.vaPEB32, pb, cb, pcbRead, cbOffset, FALSE);
}
}
if(ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X86) {
if(!_stricmp(pPath->szPath1, "win-eprocess")) {
return Util_VfsReadFile_FromDWORD((DWORD)pProcess->os.win.vaEPROCESS, pb, cb, pcbRead, cbOffset, FALSE);
}
if(!_stricmp(pPath->szPath1, "win-entry")) {
return Util_VfsReadFile_FromDWORD((DWORD)pProcess->os.win.vaENTRY, pb, cb, pcbRead, cbOffset, FALSE);
}
if(!_stricmp(pPath->szPath1, "win-peb")) {
return Util_VfsReadFile_FromDWORD((DWORD)pProcess->os.win.vaPEB, pb, cb, pcbRead, cbOffset, FALSE);
}
if(!_stricmp(pPath->szPath1, "win-modules") && pProcess->os.win.pbLdrModulesDisplayCache) {
return Util_VfsReadFile_FromPBYTE(pProcess->os.win.pbLdrModulesDisplayCache, pProcess->os.win.cbLdrModulesDisplayCache, pb, cb, pcbRead, cbOffset);
}
}
// no hit - call down the loadable modules chain for potential hits
return PluginManager_Read(pProcess, pPath->szPath1, pPath->szPath2, pb, cb, pcbRead, cbOffset);
}
@@ -174,7 +200,7 @@ NTSTATUS VmmVfsWriteFileProcess(_In_ PVMMVFS_PATH pPath, _In_ LPVOID pb, _In_ DW
return VMM_STATUS_SUCCESS;
}
// windows specific writes below:
if(ctxVmm->fTargetSystem & VMM_TARGET_WINDOWS_X64) {
if((ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X64) || (ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X86)) {
fFound =
!_stricmp(pPath->szPath1, "win-eprocess") ||
!_stricmp(pPath->szPath1, "win-peb") ||
@@ -227,13 +253,15 @@ NTSTATUS VmmVfs_Write(LPCWSTR wcsFileName, _In_ LPVOID pb, _In_ DWORD cb, _Out_
VOID VmmVfsListFiles_OsSpecific(_In_ PVMM_PROCESS pProcess, _Inout_ PHANDLE pFileList)
{
// WINDOWS
if(ctxVmm->fTargetSystem & VMM_TARGET_WINDOWS_X64) {
if(ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X64) {
VMMDLL_VfsList_AddFile(pFileList, "win-eprocess", 16);
if(pProcess->os.win.vaENTRY) {
VMMDLL_VfsList_AddFile(pFileList, "win-entry", 16);
}
// 64-bit PEB and modules
VMMDLL_VfsList_AddFile(pFileList, "win-peb", 16);
if(pProcess->os.win.vaPEB) {
VMMDLL_VfsList_AddFile(pFileList, "win-peb", 16);
}
if(pProcess->os.win.cbLdrModulesDisplayCache) {
VMMDLL_VfsList_AddFile(pFileList, "win-modules", pProcess->os.win.cbLdrModulesDisplayCache);
}
@@ -242,6 +270,19 @@ VOID VmmVfsListFiles_OsSpecific(_In_ PVMM_PROCESS pProcess, _Inout_ PHANDLE pFil
VMMDLL_VfsList_AddFile(pFileList, "win-peb32", 8);
}
}
if(ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X86) {
VMMDLL_VfsList_AddFile(pFileList, "win-eprocess", 8);
if(pProcess->os.win.vaENTRY) {
VMMDLL_VfsList_AddFile(pFileList, "win-entry", 8);
}
// PEB and modules
if(pProcess->os.win.vaPEB) {
VMMDLL_VfsList_AddFile(pFileList, "win-peb", 8);
}
if(pProcess->os.win.cbLdrModulesDisplayCache) {
VMMDLL_VfsList_AddFile(pFileList, "win-modules", pProcess->os.win.cbLdrModulesDisplayCache);
}
}
}
_Success_(return)
@@ -291,10 +332,14 @@ BOOL VmmVfsListFilesProcess(_In_ PVMMVFS_PATH pPath, _Inout_ PHANDLE pFileList)
VMMDLL_VfsList_AddFile(pFileList, "map", pProcess->cbMemMapDisplayCache);
VMMDLL_VfsList_AddFile(pFileList, "name", 16);
VMMDLL_VfsList_AddFile(pFileList, "pid", 10);
VMMDLL_VfsList_AddFile(pFileList, "pml4", 16);
VMMDLL_VfsList_AddFile(pFileList, "vmem", 0x0001000000000000);
if(pProcess->paPML4_UserOpt) {
VMMDLL_VfsList_AddFile(pFileList, "pml4-user", 16);
if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X64) {
VMMDLL_VfsList_AddFile(pFileList, "vmem", 0x0001000000000000);
VMMDLL_VfsList_AddFile(pFileList, "dtb", 16);
if(pProcess->paDTB_UserOpt) { VMMDLL_VfsList_AddFile(pFileList, "dtb-user", 16); }
} else if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X86 || ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X86PAE) {
VMMDLL_VfsList_AddFile(pFileList, "vmem", 0x100000000);
VMMDLL_VfsList_AddFile(pFileList, "dtb", 8);
if(pProcess->paDTB_UserOpt) { VMMDLL_VfsList_AddFile(pFileList, "dtb-user", 8); }
}
VmmVfsListFiles_OsSpecific(pProcess, pFileList);
PluginManager_ListAll(pProcess, pFileList);

File diff suppressed because it is too large Load Diff

96
vmm/vmmwin.h Normal file
View File

@@ -0,0 +1,96 @@
// vmmwin.h : definitions related to windows operating system and processes.
// parsing of virtual memory. Windows related features only.
//
// (c) Ulf Frisk, 2018
// Author: Ulf Frisk, pcileech@frizk.net
//
#ifndef __VMMWIN_H__
#define __VMMWIN_H__
#include "vmm.h"
typedef struct tdVMMWIN_EAT_ENTRY {
QWORD vaFunction;
DWORD vaFunctionOffset;
CHAR szFunction[40];
} VMMPROC_WINDOWS_EAT_ENTRY, *PVMMPROC_WINDOWS_EAT_ENTRY;
typedef struct tdVMMWIN_IAT_ENTRY {
ULONG64 vaFunction;
CHAR szFunction[40];
CHAR szModule[64];
} VMMWIN_IAT_ENTRY, *PVMMWIN_IAT_ENTRY;
/*
* Load the size of the required display buffer for sections, imports and export
* into the pModule struct. The size is a direct consequence of the number of
* functions since fixed line sizes are used for all these types. Loading is
* done in a recource efficient way to minimize I/O as much as possible.
* -- pProcess
* -- pModule
*/
VOID VmmWin_PE_SetSizeSectionIATEAT_DisplayBuffer(_In_ PVMM_PROCESS pProcess, _Inout_ PVMM_MODULEMAP_ENTRY pModule);
/*
* Walk the export address table (EAT) from a given pProcess and store it in the
* in the caller supplied pEATs/pcEATs structures.
* -- pProcess
* -- pModule
* -- pEATs
* -- pcEATs = number max items of pEATs on entry, number of actual items of pEATs on exit
*/
VOID VmmWin_PE_LoadEAT_DisplayBuffer(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_MODULEMAP_ENTRY pModule, _Out_ PVMMPROC_WINDOWS_EAT_ENTRY pEATs, _Inout_ PDWORD pcEATs);
/*
* Walk the import address table (IAT) from a given pProcess and store it in the
* in the caller supplied pIATs/pcIATs structures.
* -- pProcess
* -- pModule
* -- pIATs
* -- pcIATs = number max items of pIATs on entry, number of actual items of pIATs on exit
*/
VOID VmmWin_PE_LoadIAT_DisplayBuffer(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_MODULEMAP_ENTRY pModule, _Out_ PVMMWIN_IAT_ENTRY pIATs, _Inout_ PDWORD pcIATs);
/*
* Fill the pbDisplayBuffer with a human readable version of the data directories.
* This is guaranteed to be exactly 864 bytes (excluding NULL terminator).
* Alternatively copy the 16 data directories into pDataDirectoryOpt.
* -- pProcess
* -- pModule
* -- pbDisplayBufferOpt
* -- cbDisplayBufferMax
* -- pcbDisplayBuffer
* -- pDataDirectoryOpt
*/
VOID VmmWin_PE_DIRECTORY_DisplayBuffer(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MODULEMAP_ENTRY pModule, _Out_opt_ PBYTE pbDisplayBufferOpt, _In_ DWORD cbDisplayBufferMax, _Out_opt_ PDWORD pcbDisplayBuffer, _Out_writes_opt_(16) PIMAGE_DATA_DIRECTORY pDataDirectoryOpt);
/*
* Fill the pbDisplayBuffer with a human readable version of the PE sections.
* Alternatively copy the sections into the pSectionsOpt buffer.
* -- pProcess
* -- pModule
* -- pbDisplayBufferOpt
* -- cbDisplayBufferMax
* -- pcbDisplayBuffer
* -- pcSectionsOpt = size of buffer pSectionsOpt on entry, # returned entries on exit
* -- pSectionsOpt
*/
VOID VmmWin_PE_SECTION_DisplayBuffer(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MODULEMAP_ENTRY pModule, _Out_opt_ PBYTE pbDisplayBufferOpt, _In_ DWORD cbDisplayBufferMax, _Out_opt_ PDWORD pcbDisplayBuffer, _Inout_opt_ PDWORD pcSectionsOpt, _Out_opt_ PIMAGE_SECTION_HEADER pSectionsOpt);
/*
* Initialize the module names into the ctxVMM. This is performed by a PEB/Ldr
* scan of in-process memory structures. This may be unreliable of process is
* obfuscated.
* -- pProcess
*/
VOID VmmWin_InitializeModuleNames(_In_ PVMM_PROCESS pProcess);
/*
* Try walk the EPROCESS list in the Windows kernel to enumerate processes into
* the VMM/PROC file system.
* NB! This may be done to refresh an existing PID cache hence migration code.
* -- pSystemProcess
* -- return
*/
BOOL VmmWin_EnumerateEPROCESS(_In_ PVMM_PROCESS pSystemProcess);
#endif /* __VMMWIN_H__ */

484
vmm/vmmwininit.c Normal file
View File

@@ -0,0 +1,484 @@
// vmmwininit.c : implementation of detection mechanisms for Windows operating
// systems. Contains functions for detecting DTB and Memory Model
// as well as the Windows kernel base and core functionality.
//
// (c) Ulf Frisk, 2018
// Author: Ulf Frisk, pcileech@frizk.net
//
#include "vmm.h"
#include "vmmwin.h"
#include "device.h"
#include "pe.h"
#include "util.h"
/*
* Scan a page table hierarchy between virtual addresses between vaMin and vaMax
* for the first occurence of large 2MB pages. This is usually 'ntoskrnl.exe' if
* the OS is Windows. 'ntoskrnl.exe' is loaded between the virtual addresses:
* 0xFFFFF80000000000-0xFFFFF803FFFFFFFF
* -- paTable = set to: physical address of PML4
* -- vaBase = set to 0
* -- vaMin = 0xFFFFF80000000000 (if windows kernel)
* -- vaMax = 0xFFFFF803FFFFFFFF (if windows kernel)
* -- cPML = set to 4
* -- pvaBase
* -- pcbSize
*/
VOID VmmWinInit_FindNtosScan64_LargePageWalk(_In_ QWORD paTable, _In_ QWORD vaBase, _In_ QWORD vaMin, _In_ QWORD vaMax, _In_ BYTE iPML, _Inout_ PQWORD pvaBase, _Inout_ PQWORD pcbSize)
{
const QWORD PML_REGION_SIZE[5] = { 0, 12, 21, 30, 39 };
QWORD i, pte, *ptes, vaCurrent, vaSizeRegion;
ptes = (PQWORD)VmmTlbGetPageTable(paTable, FALSE);
if(!ptes) { return; }
if(iPML == 4) {
*pvaBase = 0;
*pcbSize = 0;
if(!VmmTlbPageTableVerify((PBYTE)ptes, paTable, TRUE)) { return; }
vaBase = 0;
}
for(i = 0; i < 512; i++) {
// address in range
vaSizeRegion = 1ULL << PML_REGION_SIZE[iPML];
vaCurrent = vaBase + (i << PML_REGION_SIZE[iPML]);
vaCurrent |= (vaCurrent & 0x0000800000000000) ? 0xffff000000000000 : 0; // sign extend
if(*pvaBase && (vaCurrent > (*pvaBase + *pcbSize))) { return; }
if(vaCurrent < vaMin) { continue; }
if(vaCurrent > vaMax) { return; }
// check PTEs
pte = ptes[i];
if(!(pte & 0x01)) { continue; } // NOT VALID
if(iPML == 2) {
if(!(pte & 0x80)) { continue; }
if(!*pvaBase) { *pvaBase = vaCurrent; }
*pcbSize += 0x200000;
continue;
} else {
if(pte & 0x80) { continue; } // PS = 1
VmmWinInit_FindNtosScan64_LargePageWalk(pte & 0x0000fffffffff000, vaCurrent, vaMin, vaMax, iPML - 1, pvaBase, pcbSize);
}
}
}
/*
* Sometimes the PageDirectoryBase (PML4) is known, but the kernel location may
* be unknown. This functions walks the page table in the area in which ntoskrnl
* is loaded (0xFFFFF80000000000-0xFFFFF803FFFFFFFF) looking for 2MB large pages
* If an area in 2MB pages are found it is scanned for the ntoskrnl.exe base.
* -- pSystemProcess
* -- return = virtual address of ntoskrnl.exe base if successful, otherwise 0.
*/
QWORD VmmWinInit_FindNtosScan64(PVMM_PROCESS pSystemProcess)
{
PBYTE pb;
QWORD p, o, vaCurrentMin, vaBase, cbSize;
CHAR szModuleName[MAX_PATH] = { 0 };
vaCurrentMin = 0xFFFFF80000000000;
while(TRUE) {
vaBase = 0;
cbSize = 0;
VmmWinInit_FindNtosScan64_LargePageWalk(pSystemProcess->paDTB, 0, vaCurrentMin, 0xFFFFF803FFFFFFFF, 4, &vaBase, &cbSize);
if(!vaBase) { return 0; }
vaCurrentMin = vaBase + cbSize;
if(cbSize >= 0x01000000) { continue; } // too big
if(cbSize <= 0x00400000) { continue; } // too small
// try locate ntoskrnl.exe base inside suggested area
if(!(pb = (PBYTE)LocalAlloc(0, cbSize))) { return 0; }
VmmReadEx(pSystemProcess, vaBase, pb, (DWORD)cbSize, NULL, 0);
for(p = 0; p < cbSize; p += 0x1000) {
// check for (1) MZ header, (2) POOLCODE section, (3) ntoskrnl.exe module name
if(*(PWORD)(pb + p) != 0x5a4d) { continue; } // MZ header
for(o = 0; o < 0x1000; o += 8) {
if(*(PQWORD)(pb + p + o) == 0x45444F434C4F4F50) { // POOLCODE
PE_GetModuleNameEx(pSystemProcess, vaBase + p, FALSE, pb + p, szModuleName, NULL);
if(!_stricmp(szModuleName, "ntoskrnl.exe")) {
LocalFree(pb);
return vaBase + p;
}
}
}
}
LocalFree(pb);
}
return 0;
}
/*
* Locate the virtual base address of 'ntoskrnl.exe' given any address inside
* the kernel. Localization will be done by a scan-back method. A maximum of
* 32MB will be scanned back.
* -- pSystemProcess
* -- return = virtual address of ntoskrnl.exe base if successful, otherwise 0
*/
QWORD VmmWinInit_FindNtosScanHint64(_In_ PVMM_PROCESS pSystemProcess)
{
PBYTE pb;
QWORD vaBase, o, p, vaNtosBase = 0;
DWORD cbRead;
QWORD vaHint = ctxVmm->kernel.vaEntry;
CHAR szModuleName[MAX_PATH] = { 0 };
pb = LocalAlloc(0, 0x00200000);
if(!pb) { goto cleanup; }
// Scan back in 2MB chunks a time, (ntoskrnl.exe is loaded in 2MB pages).
for(vaBase = vaHint & ~0x1fffff; vaBase + 0x02000000 > vaHint; vaBase -= 0x200000) {
VmmReadEx(pSystemProcess, vaBase, pb, 0x200000, &cbRead, 0);
// only fail here if all virtual memory in read fails. reason is that kernel is
// properly mapped in memory (with NX MZ header in separate page) with empty
// space before next valid kernel pages when running Virtualization Based Security.
if(!cbRead) { goto cleanup; }
for(p = 0; p < 0x200000; p += 0x1000) {
// check for (1) MZ header, (2) POOLCODE section, (3) ntoskrnl.exe module name
if(*(PWORD)(pb + p) != 0x5a4d) { continue; } // MZ header
for(o = 0; o < 0x1000; o += 8) {
if(*(PQWORD)(pb + p + o) == 0x45444F434C4F4F50) { // POOLCODE
PE_GetModuleNameEx(pSystemProcess, vaBase + p, FALSE, pb + p, szModuleName, NULL);
if(!_stricmp(szModuleName, "ntoskrnl.exe")) {
LocalFree(pb);
return vaBase + p;
}
}
}
}
}
cleanup:
LocalFree(pb);
return vaNtosBase;
}
/*
* scans the relatively limited memory space 0x80000000-0x83ffffff for the base
* of 'ntoskrnl.exe'. NB! this is a very non-optimized way of doing things and
* should be improved upon to increase startup performance - but 64MB is not a
* huge amount of memory and it's only scanned at startup ...
* -- pSystemProcess
* -- return = virtual address of ntoskrnl.exe base if successful, otherwise 0.
*/
DWORD VmmWinInit_FindNtosScan32(_In_ PVMM_PROCESS pSystemProcess)
{
DWORD o, p;
PBYTE pb;
CHAR szModuleName[MAX_PATH] = { 0 };
if(!(pb = LocalAlloc(LMEM_ZEROINIT, 0x04000000))) { return 0; }
for(p = 0; p < 0x04000000; p += 0x1000) {
// read 8MB chunks when required.
if(0 == p % 0x00800000) {
VmmReadEx(pSystemProcess, 0x80000000ULL + p, pb + p, 0x00800000, NULL, 0);
}
// check for (1) MZ header, (2) POOLCODE section, (3) ntoskrnl.exe module name
if(*(PWORD)(pb + p) != 0x5a4d) { continue; } // MZ header
for(o = 0; o < 0x1000; o += 8) {
if(*(PQWORD)(pb + p + o) == 0x45444F434C4F4F50) { // POOLCODE
PE_GetModuleNameEx(pSystemProcess, 0x80000000ULL + p, FALSE, pb + p, szModuleName, NULL);
if(!_stricmp(szModuleName, "ntoskrnl.exe")) {
LocalFree(pb);
return 0x80000000 + p;
}
}
}
}
LocalFree(pb);
return 0;
}
/*
* Scan for the 'ntoskrnl.exe' by using the DTB and memory model information
* from the ctxVmm.
* -- ppSystemProcess = ptr to receive pSystemProcess upon success.
* -- return
*/
BOOL VmmWinInit_FindNtosScan(_Out_ PVMM_PROCESS *ppSystemProcess)
{
QWORD vaKernelBase = 0, cbKernelSize;
PVMM_PROCESS pSystemProcess;
*ppSystemProcess = NULL;
// 1: Pre-initialize System PID (required by VMM)
pSystemProcess = VmmProcessCreateEntry(4, 0, ctxVmm->kernel.paDTB, 0, "System", FALSE, TRUE);
if(!pSystemProcess) { return FALSE; }
VmmProcessCreateFinish();
// 2: Spider DTB to speed things up.
VmmTlbSpider(ctxVmm->kernel.paDTB, FALSE);
// 3: Find the base of 'ntoskrnl.exe'
if(VMM_MEMORYMODEL_X64 == ctxVmm->tpMemoryModel) {
if(ctxVmm->kernel.vaEntry) {
vaKernelBase = VmmWinInit_FindNtosScanHint64(pSystemProcess);
}
if(!vaKernelBase) {
vaKernelBase = VmmWinInit_FindNtosScan64(pSystemProcess);
}
} else {
vaKernelBase = VmmWinInit_FindNtosScan32(pSystemProcess);
}
if(!vaKernelBase) { return FALSE; }
cbKernelSize = PE_GetSize(pSystemProcess, vaKernelBase);
if(!cbKernelSize) { return FALSE; }
*ppSystemProcess = pSystemProcess;
ctxVmm->kernel.vaBase = vaKernelBase;
ctxVmm->kernel.cbSize = cbKernelSize;
return TRUE;
}
/*
* Check if a page looks like the Windows Kernel x86 Directory Table Base (DTB)
* in the 32-bit mode - i.e. the PD of the System process.
* 1: self-referential entry exists at offset 0xC00
* 2: PDE[0] is a user-mode PDE pointing to a PT.
* 3: a minimum number of supervisor-mode PDEs must exist.
*/
_Success_(return)
BOOL VmmWinInit_DTB_FindValidate_X86(_In_ QWORD pa, _In_reads_(0x1000) PBYTE pbPage)
{
DWORD c, i;
if((*(PDWORD)(pbPage + 0xc00) & 0xfffff003) != pa + 0x03) { return FALSE; } // self-referential entry exists
if(*pbPage != 0x67) { return FALSE; } // user-mode page table exists at 1st PTE (index 0)
for(c = 0, i = 0x800; i < 0x1000; i += 4) { // minimum number of supervisor entries above 0x800
if((*(pbPage + i) == 0x63) || (*(pbPage + i) == 0xe3)) { c++; }
if(c > 16) { return TRUE; }
}
return FALSE;
}
/*
* Check if a page looks like the Windows Kernel x86 Directory Table Base (DTB)
* in the 32-bit PAE memory mode - i.e. the PDPT of the System process.
* Also please note that this may not be the actual PDPT used by the kernel -
* it may very well rather be the PDPT probably set up by WinLoad and then the
* 'System' process uses another. But it works for auto-detect!
* 1: (4) valid PDPT entries with consecutive physical addresses of the PDPT.
* 2: all zeroes for the rest of the page.
*/
_Success_(return)
BOOL VmmWinInit_DTB_FindValidate_X86PAE(_In_ QWORD pa, _In_reads_(0x1000) PBYTE pbPage)
{
for(QWORD i = 0; i < 0x1000; i += 8) {
if((i < 0x20) && ((*(PQWORD)(pbPage + i) != pa + (i << 9) + 0x1001))) {
return FALSE;
} else if((i >= 0x20) && *(PQWORD)(pbPage + i)) {
return FALSE;
}
}
return TRUE;
}
_Success_(return)
BOOL VmmWinInit_DTB_FindValidate_X64(_In_ QWORD pa, _In_reads_(0x1000) PBYTE pbPage)
{
DWORD c, i;
BOOL fSelfRef = FALSE;
QWORD pte, paMax;
paMax = ctxMain->cfg.paAddrMax;
// check for user-mode page table with PDPT below max physical address and not NX.
pte = *(PQWORD)pbPage;
if(((pte & 0x8000000000000087) != 0x07) || ((pte & 0x0000fffffffff000) > paMax)) { return FALSE; }
for(c = 0, i = 0x800; i < 0x1000; i += 8) { // minimum number of supervisor entries above 0x800
pte = *(PQWORD)(pbPage + i);
// check for user-mode page table with PDPT below max physical address and not NX.
if(((pte & 0x8000ff0000000087) == 0x03) && ((pte & 0x0000fffffffff000) > paMax)) { c++; }
// check for self-referential entry
if((*(PQWORD)(pbPage + i) & 0x8000fffffffff083) == pa + 0x03) { fSelfRef = TRUE; }
}
return fSelfRef && (c >= 6);
}
/*
* Find and validate the low stub (loaded <1MB if exists). The low stub almost
* always exists on real hardware. It may be missing on virtual machines though.
* Upon success both the PML4 and 'ntoskrnl.exe' KernelEntry point are located.
* The PML4 is stored as the ctxVmm->kernel.paDTB and the KernelEntry is stored
* as ctxVmm->kernel.vaHintOpt
*/
BOOL VmmWinInit_DTB_FindValidate_X64_LowStub(_In_ PBYTE pbLowStub1M)
{
DWORD o = 0;
while(o < 0x100000) {
o += 0x1000;
if(0x00000001000600E9 != (0xffffffffffff00ff & *(PQWORD)(pbLowStub1M + o + 0x000))) { continue; } // START BYTES
if(0xfffff80000000000 != (0xfffff80000000003 & *(PQWORD)(pbLowStub1M + o + 0x070))) { continue; } // KERNEL ENTRY
if(0xffffff0000000fff & *(PQWORD)(pbLowStub1M + o + 0x0a0)) { continue; } // PML4
ctxVmm->kernel.vaEntry = *(PQWORD)(pbLowStub1M + o + 0x070);
ctxVmm->kernel.paDTB = *(PQWORD)(pbLowStub1M + o + 0x0a0);
return TRUE;
}
return FALSE;
}
/*
* Tries to locate the Directory Table Base and the Memory Model by using various
* detection and scanning functions. Upon success memory model and kernel DTB is
* returned in the ctxVmm context.
-- return
*/
_Success_(return)
BOOL VmmWinInit_DTB_FindValidate()
{
DWORD pa;
QWORD paDTB = 0;
PBYTE pb16M;
if(!(pb16M = LocalAlloc(LMEM_ZEROINIT, 0x01000000))) { return FALSE; }
// 1: try locate DTB via X64 low stub in lower 1MB
DeviceReadMEMEx(0, pb16M, 0x00100000, NULL);
if(VmmWinInit_DTB_FindValidate_X64_LowStub(pb16M)) {
VmmInitializeMemoryModel(VMM_MEMORYMODEL_X64);
paDTB = ctxVmm->kernel.paDTB;
}
// 2: try locate DTB by scanning in lower 16MB
// X64
if(!paDTB) {
for(pa = 0; pa < 0x01000000; pa += 0x1000) {
if(pa == 0x00100000) {
DeviceReadMEMEx(0x00100000, pb16M + 0x00100000, 0x00f00000, NULL);
}
if(VmmWinInit_DTB_FindValidate_X64(pa, pb16M + pa)) {
VmmInitializeMemoryModel(VMM_MEMORYMODEL_X64);
paDTB = pa;
break;
}
}
}
// X86-PAE
if(!paDTB) {
for(pa = 0; pa < 0x01000000; pa += 0x1000) {
if(VmmWinInit_DTB_FindValidate_X86PAE(pa, pb16M + pa)) {
VmmInitializeMemoryModel(VMM_MEMORYMODEL_X86PAE);
paDTB = pa;
break;
}
}
}
// X86
if(!paDTB) {
for(pa = 0; pa < 0x01000000; pa += 0x1000) {
if(VmmWinInit_DTB_FindValidate_X86(pa, pb16M + pa)) {
VmmInitializeMemoryModel(VMM_MEMORYMODEL_X86);
paDTB = pa;
break;
}
}
}
LocalFree(pb16M);
if(!paDTB) { return FALSE; }
ctxVmm->kernel.paDTB = paDTB;
return TRUE;
}
/*
* Validate a DTB supplied by the user. The memory model will be detected and
* the result will be stored in the ctxVmm context upon success.
* -- paDTB
* -- return
*/
BOOL VmmWinInit_DTB_Validate(QWORD paDTB)
{
BYTE pb[0x1000];
DeviceReadMEMEx(0, pb, 0x1000, NULL);
if(VmmWinInit_DTB_FindValidate_X64(paDTB, pb)) {
VmmInitializeMemoryModel(VMM_MEMORYMODEL_X64);
ctxVmm->kernel.paDTB = paDTB;
return TRUE;
}
if(VmmWinInit_DTB_FindValidate_X86PAE(paDTB, pb)) {
VmmInitializeMemoryModel(VMM_MEMORYMODEL_X86PAE);
ctxVmm->kernel.paDTB = paDTB;
return TRUE;
}
if(VmmWinInit_DTB_FindValidate_X86(paDTB, pb)) {
VmmInitializeMemoryModel(VMM_MEMORYMODEL_X86);
ctxVmm->kernel.paDTB = paDTB;
return TRUE;
}
return FALSE;
}
BOOL VmmWinInit_FindPsLoadedModuleListKDBG(_In_ PVMM_PROCESS pSystemProcess)
{
PBYTE pbData = NULL, pbKDBG;
IMAGE_SECTION_HEADER SectionHeader;
DWORD o;
QWORD va;
// 1: Try locate 'PsLoadedModuleList' by exported kernel symbol. If this is
// possible it's most probably Windows 10 and KDBG will be encrypted so
// no need to continue looking for it.
ctxVmm->kernel.vaPsLoadedModuleList = PE_GetProcAddress(pSystemProcess, ctxVmm->kernel.vaBase, "PsLoadedModuleList");
if(ctxVmm->kernel.vaPsLoadedModuleList) { return TRUE; }
// 2: Try locate 'KDBG' by looking in 'ntoskrnl.exe' '.text' section. This
// is the normal way of finding it on 64-bit Windows below Windows 10.
// This also works on 32-bit Windows versions - so use this method for
// simplicity rather than using a separate 32-bit method.
if(!ctxVmm->kernel.vaKDBG) {
if(!PE_SectionGetFromName(pSystemProcess, ctxVmm->kernel.vaBase, ".data", &SectionHeader)) { goto fail; }
if((SectionHeader.Misc.VirtualSize > 0x00100000) || (SectionHeader.VirtualAddress > 0x01000000)) { goto fail; }
if(!(pbData = LocalAlloc(LMEM_ZEROINIT, SectionHeader.Misc.VirtualSize))) { goto fail; }
VmmReadEx(pSystemProcess, ctxVmm->kernel.vaBase + SectionHeader.VirtualAddress, pbData, SectionHeader.Misc.VirtualSize, NULL, 0);
for(o = 16; o <= SectionHeader.Misc.VirtualSize - 0x290; o += 4) {
if(*(PDWORD)(pbData + o) == 0x4742444b) { // KDBG tag
pbKDBG = pbData + o - 16;
if(ctxVmm->kernel.vaBase != *(PQWORD)(pbKDBG + 0x18)) { continue; }
// fetch PsLoadedModuleList
va = *(PQWORD)(pbKDBG + 0x48);
if((va < ctxVmm->kernel.vaBase) || (va > ctxVmm->kernel.vaBase + ctxVmm->kernel.cbSize)) { goto fail; }
if(!VmmRead(pSystemProcess, va, (PBYTE)&ctxVmm->kernel.vaPsLoadedModuleList, ctxVmm->f32 ? 4 : 8)) { goto fail; }
// finish!
ctxVmm->kernel.vaKDBG = ctxVmm->kernel.vaBase + SectionHeader.VirtualAddress + o - 16;
LocalFree(pbData);
return TRUE;
}
}
}
fail:
LocalFree(pbData);
return FALSE;
}
/*
* Try initialize the VMM from scratch with new WINDOWS support.
* -- paDTBOpt
* -- return
*/
BOOL VmmWinInit_TryInitialize(_In_opt_ QWORD paDTBOpt)
{
PVMM_PROCESS pSystemProcess = NULL;
QWORD vaPsInitialSystemProcess, vaSystemEPROCESS;
// Fetch Directory Base (DTB (PML4)) and initialize Memory Model.
if(paDTBOpt) {
if(!VmmWinInit_DTB_Validate(paDTBOpt)) {
vmmprintfv("VmmWinInit_TryInitialize: Initialization Failed. Unable to verify user-supplied DTB. #1\n");
goto fail;
}
} else {
if(!VmmWinInit_DTB_FindValidate()) {
vmmprintfv("VmmWinInit_TryInitialize: Initialization Failed. Unable to locate valid DTB. #2\n");
goto fail;
}
}
vmmprintfvv("VmmWinInit_TryInitialize: INFO: DTB located at: %016llx. MemoryModel: %s\n", ctxVmm->kernel.paDTB, VMM_MEMORYMODEL_TOSTRING[ctxVmm->tpMemoryModel]);
// Fetch 'ntoskrnl.exe' base address
if(!VmmWinInit_FindNtosScan(&pSystemProcess)) {
vmmprintfv("VmmWinInit_TryInitialize: Initialization Failed. Unable to locate ntoskrnl.exe. #3\n");
goto fail;
}
vmmprintfvv("VmmWinInit_TryInitialize: INFO: NTOS located at: %016llx.\n", ctxVmm->kernel.vaBase);
// Locate System EPROCESS
vaPsInitialSystemProcess = PE_GetProcAddress(pSystemProcess, ctxVmm->kernel.vaBase, "PsInitialSystemProcess");
if(!VmmRead(pSystemProcess, vaPsInitialSystemProcess, (PBYTE)&vaSystemEPROCESS, 8)) {
vmmprintfv("VmmWinInit_TryInitialize: Initialization Failed. Unable to locate EPROCESS. #4\n");
goto fail;
}
if((VMM_MEMORYMODEL_X86 == ctxVmm->tpMemoryModel) || (VMM_MEMORYMODEL_X86PAE == ctxVmm->tpMemoryModel)) {
vaSystemEPROCESS &= 0xffffffff;
}
pSystemProcess->os.win.vaEPROCESS = vaSystemEPROCESS;
vmmprintfvv("VmmWinInit_TryInitialize: INFO: PsInitialSystemProcess located at %016llx.\n", vaPsInitialSystemProcess);
vmmprintfvv("VmmWinInit_TryInitialize: INFO: EPROCESS located at %016llx.\n", vaSystemEPROCESS);
// Enumerate processes
if(!VmmWin_EnumerateEPROCESS(pSystemProcess)) {
vmmprintfv("VmmWinInit: Initialization Failed. Unable to walk EPROCESS. #5\n");
goto fail;
}
ctxVmm->tpSystem = (VMM_MEMORYMODEL_X64 == ctxVmm->tpMemoryModel) ? VMM_SYSTEM_WINDOWS_X64 : VMM_SYSTEM_WINDOWS_X86;
// Optionally fetch PsLoadedModuleList / KDBG
VmmWinInit_FindPsLoadedModuleListKDBG(pSystemProcess);
return TRUE;
fail:
VmmInitializeMemoryModel(VMM_MEMORYMODEL_NA); // clean memory model
ZeroMemory(&ctxVmm->kernel, sizeof(VMM_KERNELINFO));
return FALSE;
}

21
vmm/vmmwininit.h Normal file
View File

@@ -0,0 +1,21 @@
// vmmwininit.h : declarations of detection mechanisms for Windows operating
// systems. Contains functions for detecting DTB and Memory Model
// as well as the Windows kernel base and core functionality.
//
// (c) Ulf Frisk, 2018
// Author: Ulf Frisk, pcileech@frizk.net
//
#ifndef __VMMWININIT_H__
#define __VMMWININIT_H__
#include "vmm.h"
/*
* Try initialize the VMM from scratch with new WINDOWS support.
* -- paDTB
* -- return
*/
_Success_(return)
BOOL VmmWinInit_TryInitialize(_In_opt_ QWORD paDTB);
#endif /* __VMMWININIT_H__ */

View File

@@ -23,6 +23,7 @@ extern "C" {
* Call other VMMDLL_Intialize functions to initialize VMM.DLL and the memory
* process file system.
*/
_Success_(return)
BOOL VMMDLL_InitializeReserved(_In_ DWORD argc, _In_ LPSTR argv[]);
/*
@@ -37,6 +38,7 @@ BOOL VMMDLL_InitializeReserved(_In_ DWORD argc, _In_ LPSTR argv[]);
* as hex string. NB! this is usally not required. Example: "0x1ab000".
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeFile(_In_ LPSTR szFileName, _In_opt_ LPSTR szPageTableBaseOpt);
/*
@@ -52,6 +54,7 @@ BOOL VMMDLL_InitializeFile(_In_ LPSTR szFileName, _In_opt_ LPSTR szPageTableBase
* as hex string. NB! this is usally not required. Example: "0x1ab000".
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeFPGA(_In_opt_ LPSTR szMaxPhysicalAddressOpt, _In_opt_ LPSTR szPageTableBaseOpt);
/*
@@ -60,6 +63,7 @@ BOOL VMMDLL_InitializeFPGA(_In_opt_ LPSTR szMaxPhysicalAddressOpt, _In_opt_ LPST
* initialized in read/write mode upon success.
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeTotalMeltdown();
/*
@@ -67,6 +71,7 @@ BOOL VMMDLL_InitializeTotalMeltdown();
* including plugins, linked PCILeech.DLL and other memory resources.
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_Close();
@@ -103,7 +108,8 @@ BOOL VMMDLL_Close();
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA_TLP 0x80000004 // RW
#define VMMDLL_OPT_CORE_MAX_NATIVE_ADDRESS 0x80000005 // R
#define VMMDLL_OPT_CORE_MAX_NATIVE_IOSIZE 0x80000006 // R
#define VMMDLL_OPT_CORE_TARGET_SYSTEM 0x80000007 // R
#define VMMDLL_OPT_CORE_SYSTEM 0x80000007 // R
#define VMMDLL_OPT_CORE_MEMORYMODEL 0x80000008 // R
#define VMMDLL_OPT_CONFIG_IS_REFRESH_ENABLED 0x40000001 // R - 1/0
#define VMMDLL_OPT_CONFIG_TICK_PERIOD 0x40000002 // RW - base tick period in ms
@@ -116,6 +122,22 @@ BOOL VMMDLL_Close();
#define VMMDLL_OPT_CONFIG_VMM_VERSION_REVISION 0x40000009 // R
#define VMMDLL_OPT_CONFIG_STATISTICS_FUNCTIONCALL 0x4000000A // RW - enable function call statistics (.status/statistics_fncall file)
static const LPSTR VMMDLL_MEMORYMODEL_TOSTRING[4] = { "N/A", "X86", "X86PAE", "X64" };
typedef enum tdVMMDLL_MEMORYMODEL_TP {
VMMDLL_MEMORYMODEL_NA = 0,
VMMDLL_MEMORYMODEL_X86 = 1,
VMMDLL_MEMORYMODEL_X86PAE = 2,
VMMDLL_MEMORYMODEL_X64 = 3
} VMMDLL_MEMORYMODEL_TP;
typedef enum tdVMMDLL_SYSTEM_TP {
VMMDLL_SYSTEM_UNKNOWN_X64 = 1,
VMMDLL_SYSTEM_WINDOWS_X64 = 2,
VMMDLL_SYSTEM_UNKNOWN_X86 = 3,
VMMDLL_SYSTEM_WINDOWS_X86 = 4
} VMMDLL_SYSTEM_TP;
/*
* Set a device specific option value. Please see defines VMMDLL_OPT_* for infor-
* mation about valid option values. Please note that option values may overlap
@@ -124,6 +146,7 @@ BOOL VMMDLL_Close();
* -- pqwValue = pointer to ULONG64 to receive option value.
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ConfigGet(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue);
/*
@@ -134,6 +157,7 @@ BOOL VMMDLL_ConfigGet(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue);
* -- qwValue
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ConfigSet(_In_ ULONG64 fOption, _In_ ULONG64 qwValue);
@@ -171,6 +195,7 @@ typedef struct tdVMMDLL_VFS_FILELIST {
* -- pFileList
* -- return
*/
_Success_(return)
BOOL VMMDLL_VfsList(_In_ LPCWSTR wcsPath, _Inout_ PVMMDLL_VFS_FILELIST pFileList);
/*
@@ -227,12 +252,13 @@ NTSTATUS VMMDLL_UtilVfsWriteFile_DWORD(_Inout_ PDWORD pdwTarget, _In_ LPVOID pb,
* will be unloaded on a general close of the vmm dll.
* -- return
*/
_Success_(return)
BOOL VMMDLL_VfsInitializePlugins();
#define VMMDLL_PLUGIN_CONTEXT_MAGIC 0xc0ffee663df9301c
#define VMMDLL_PLUGIN_CONTEXT_VERSION 1
#define VMMDLL_PLUGIN_REGINFO_MAGIC 0xc0ffee663df9301d
#define VMMDLL_PLUGIN_REGINFO_VERSION 1
#define VMMDLL_PLUGIN_REGINFO_VERSION 2
#define VMMDLL_PLUGIN_EVENT_VERBOSITYCHANGE 0x01
@@ -254,7 +280,8 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
ULONG64 magic;
WORD wVersion;
WORD wSize;
DWORD fTargetSystem;
VMMDLL_MEMORYMODEL_TP tpMemoryModel;
VMMDLL_SYSTEM_TP tpSystem;
HMODULE hDLL;
HMODULE hReservedDll; // not for general use (only used for python).
BOOL(*pfnPluginManager_Register)(struct tdVMMDLL_PLUGIN_REGINFO *pPluginRegInfo);
@@ -272,7 +299,7 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
// function plugin registration info to be filled out by the plugin below:
struct {
BOOL(*pfnList)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList);
NTSTATUS(*pfnRead)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset);
NTSTATUS(*pfnRead)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset);
NTSTATUS(*pfnWrite)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset);
VOID(*pfnNotify)(_Inout_opt_ PHANDLE phModulePrivate, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent);
VOID(*pfnCloseHandleModule)(_Inout_opt_ PHANDLE phModulePrivate);
@@ -296,8 +323,7 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
#define VMMDLL_FLAG_NOCACHE 0x0001 // do not use the data cache (force reading from memory acquisition device)
#define VMMDLL_FLAG_ZEROPAD_ON_FAIL 0x0002 // zero pad failed physical memory reads and report success if read within range of physical memory.
#define VMMDLL_TARGET_UNKNOWN_X64 0x0001
#define VMMDLL_TARGET_WINDOWS_X64 0x0002
#define VMMDLL_MEM_IO_SCATTER_HEADER_VERSION 2
typedef struct tdVMMDLL_MEM_IO_SCATTER_HEADER {
ULONG64 qwA; // base address (DWORD boundry).
@@ -306,6 +332,10 @@ typedef struct tdVMMDLL_MEM_IO_SCATTER_HEADER {
PBYTE pb; // ptr to 0x1000 sized buffer to receive read bytes.
PVOID pvReserved1; // reserved for use by caller.
PVOID pvReserved2; // reserved for use by caller.
WORD version; // version of struct
WORD Future1; // reserved for future use.
DWORD Future2; // reserved for future use.
ULONG64 qwDeviceA; // device-physical address (used by device layer).
struct {
PVOID pvReserved1;
PVOID pvReserved2;
@@ -335,6 +365,7 @@ DWORD VMMDLL_MemReadScatter(_In_ DWORD dwPID, _Inout_ PPVMMDLL_MEM_IO_SCATTER_HE
* -- pbPage
* -- return = success/fail (depending if all requested bytes are read or not).
*/
_Success_(return)
BOOL VMMDLL_MemReadPage(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_bytecount_(4096) PBYTE pbPage);
/*
@@ -345,6 +376,7 @@ BOOL VMMDLL_MemReadPage(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_bytecount_(4
* -- cb
* -- return = success/fail (depending if all requested bytes are read or not).
*/
_Success_(return)
BOOL VMMDLL_MemRead(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DWORD cb);
/*
@@ -358,7 +390,8 @@ BOOL VMMDLL_MemRead(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DW
* -- return = success/fail. NB! reads may report as success even if 0 bytes are
* read - it's recommended to verify pcbReadOpt parameter.
*/
BOOL VMMDLL_MemReadEx(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ ULONG64 flags);
_Success_(return)
BOOL VMMDLL_MemReadEx(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ ULONG64 flags);
/*
* Write a contigious arbitrary amount of memory. Please note some virtual memory
@@ -373,7 +406,8 @@ BOOL VMMDLL_MemReadEx(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_ PBYTE pb, _In
* -- cb
* -- return = TRUE on success, FALSE on partial or zero write.
*/
BOOL VMMDLL_MemWrite(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DWORD cb);
_Success_(return)
BOOL VMMDLL_MemWrite(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _In_ PBYTE pb, _In_ DWORD cb);
/*
* Translate a virtual address to a physical address by walking the page tables
@@ -383,6 +417,7 @@ BOOL VMMDLL_MemWrite(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ D
* -- pqwPA
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_MemVirt2Phys(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PULONG64 pqwPA);
@@ -401,6 +436,7 @@ BOOL VMMDLL_MemVirt2Phys(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PULONG64 pqw
* -- pdwPID = pointer that will receive PID on success.
* -- return
*/
_Success_(return)
BOOL VMMDLL_PidGetFromName(_In_ LPSTR szProcName, _Out_ PDWORD pdwPID);
/*
@@ -409,7 +445,8 @@ BOOL VMMDLL_PidGetFromName(_In_ LPSTR szProcName, _Out_ PDWORD pdwPID);
* -- pcPIDs = size of (in number of DWORDs) pPIDs array on entry, number of PIDs in system on exit.
* -- return = success/fail.
*/
BOOL VMMDLL_PidList(_Out_ PDWORD pPIDs, _Inout_ PULONG64 pcPIDs);
_Success_(return)
BOOL VMMDLL_PidList(_Out_opt_ PDWORD pPIDs, _Inout_ PULONG64 pcPIDs);
// flags to check for existence in the fPage field of PCILEECH_VMM_MEMMAP_ENTRY
#define VMMDLL_MEMMAP_FLAG_PAGE_W 0x0000000000000002
@@ -437,6 +474,7 @@ typedef struct tdVMMDLL_MEMMAP_ENTRY {
* -- fIdentifyModules = try identify modules as well (= slower)
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ProcessGetMemoryMap(_In_ DWORD dwPID, _Out_opt_ PVMMDLL_MEMMAP_ENTRY pMemMapEntries, _Inout_ PULONG64 pcMemMapEntries, _In_ BOOL fIdentifyModules);
/*
@@ -448,6 +486,7 @@ BOOL VMMDLL_ProcessGetMemoryMap(_In_ DWORD dwPID, _Out_opt_ PVMMDLL_MEMMAP_ENTRY
* -- fIdentifyModules = try identify modules as well (= slower)
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ProcessGetMemoryMapEntry(_In_ DWORD dwPID, _Out_ PVMMDLL_MEMMAP_ENTRY pMemMapEntry, _In_ ULONG64 va, _In_ BOOL fIdentifyModules);
typedef struct tdVMMDLL_MODULEMAP_ENTRY {
@@ -469,7 +508,8 @@ typedef struct tdVMMDLL_MODULEMAP_ENTRY {
* -- pcModuleEntries = pointer to number of memory map entries.
* -- return = success/fail.
*/
BOOL VMMDLL_ProcessGetModuleMap(_In_ DWORD dwPID, _Out_ PVMMDLL_MODULEMAP_ENTRY pModuleEntries, _Inout_ PULONG64 pcModuleEntries);
_Success_(return)
BOOL VMMDLL_ProcessGetModuleMap(_In_ DWORD dwPID, _Out_opt_ PVMMDLL_MODULEMAP_ENTRY pModuleEntries, _Inout_ PULONG64 pcModuleEntries);
/*
* Retrieve a module (.exe or .dll or similar) given a module name.
@@ -478,29 +518,31 @@ BOOL VMMDLL_ProcessGetModuleMap(_In_ DWORD dwPID, _Out_ PVMMDLL_MODULEMAP_ENTRY
* -- pModuleEntry
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ProcessGetModuleFromName(_In_ DWORD dwPID, _In_ LPSTR szModuleName, _Out_ PVMMDLL_MODULEMAP_ENTRY pModuleEntry);
#define VMMDLL_PROCESS_INFORMATION_MAGIC 0xc0ffee663df9301d
#define VMMDLL_PROCESS_INFORMATION_VERSION 1
#define VMMDLL_PROCESS_INFORMATION_MAGIC 0xc0ffee663df9301e
#define VMMDLL_PROCESS_INFORMATION_VERSION 2
typedef struct tdVMMDLL_PROCESS_INFORMATION {
ULONG64 magic;
WORD wVersion;
WORD wSize;
DWORD fTargetSystem; // as given by VMMDLL_TARGET_*
BOOL fUserOnly; // only user mode pages listed
VMMDLL_MEMORYMODEL_TP tpMemoryModel; // as given by VMMDLL_MEMORYMODEL_* enum
VMMDLL_SYSTEM_TP tpSystem; // as given by VMMDLL_SYSTEM_* enum
BOOL fUserOnly; // only user mode pages listed
DWORD dwPID;
DWORD dwState;
CHAR szName[16];
ULONG64 paPML4;
ULONG64 paPML4_UserOpt; // may not exist
ULONG64 paDTB;
ULONG64 paDTB_UserOpt; // may not exist
union {
struct {
ULONG64 vaEPROCESS;
ULONG64 vaPEB;
ULONG64 vaENTRY;
BOOL fWow64;
DWORD vaPEB32; // WoW64 only
DWORD vaPEB32; // WoW64 only
} win;
} os;
} VMMDLL_PROCESS_INFORMATION, *PVMMDLL_PROCESS_INFORMATION;
@@ -513,6 +555,7 @@ typedef struct tdVMMDLL_PROCESS_INFORMATION {
* -- pcbProcessInformation = size of pProcessInfo (in bytes) on entry and exit
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ProcessGetInformation(_In_ DWORD dwPID, _Inout_opt_ PVMMDLL_PROCESS_INFORMATION pProcessInformation, _In_ PSIZE_T pcbProcessInformation);
typedef struct tdVMMDLL_EAT_ENTRY {
@@ -539,10 +582,14 @@ typedef struct tdVMMDLL_IAT_ENTRY {
* -- pcData
* -- return = success/fail.
*/
BOOL VMMDLL_ProcessGetDirectories(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PIMAGE_DATA_DIRECTORY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
BOOL VMMDLL_ProcessGetSections(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PIMAGE_SECTION_HEADER pData, _In_ DWORD cData, _Out_ PDWORD pcData);
BOOL VMMDLL_ProcessGetEAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PVMMDLL_EAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
BOOL VMMDLL_ProcessGetIAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PVMMDLL_IAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
_Success_(return)
BOOL VMMDLL_ProcessGetDirectories(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_writes_(16) PIMAGE_DATA_DIRECTORY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
_Success_(return)
BOOL VMMDLL_ProcessGetSections(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_opt_ PIMAGE_SECTION_HEADER pData, _In_ DWORD cData, _Out_ PDWORD pcData);
_Success_(return)
BOOL VMMDLL_ProcessGetEAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_opt_ PVMMDLL_EAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
_Success_(return)
BOOL VMMDLL_ProcessGetIAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_opt_ PVMMDLL_IAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
@@ -558,7 +605,8 @@ BOOL VMMDLL_ProcessGetIAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PVMMDLL_I
* -- sz = buffer to fill, NULL to retrieve size in pcsz parameter.
* -- pcsz = ptr to size of buffer on entry, size of characters on exit.
*/
BOOL VMMDLL_UtilFillHexAscii(_In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset, _Inout_ LPSTR sz, _Inout_ PDWORD pcsz);
_Success_(return)
BOOL VMMDLL_UtilFillHexAscii(_In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset, _Inout_opt_ LPSTR sz, _Out_ PDWORD pcsz);
#ifdef __cplusplus
}

View File

@@ -194,8 +194,8 @@ int main(_In_ int argc, _In_ char* argv[])
if(result) {
printf("SUCCESS: VMMDLL_ProcessGetInformation\n");
printf(" Name = %s\n", ProcessInformation.szName);
printf(" PageDirectoryBase = 0x%016llx\n", ProcessInformation.paPML4);
printf(" PageDirectoryBaseUser = 0x%016llx\n", ProcessInformation.paPML4_UserOpt);
printf(" PageDirectoryBase = 0x%016llx\n", ProcessInformation.paDTB);
printf(" PageDirectoryBaseUser = 0x%016llx\n", ProcessInformation.paDTB_UserOpt);
printf(" ProcessState = 0x%08x\n", ProcessInformation.dwState);
} else {
printf("FAIL: VMMDLL_ProcessGetInformation\n");

View File

@@ -23,6 +23,7 @@ extern "C" {
* Call other VMMDLL_Intialize functions to initialize VMM.DLL and the memory
* process file system.
*/
_Success_(return)
BOOL VMMDLL_InitializeReserved(_In_ DWORD argc, _In_ LPSTR argv[]);
/*
@@ -37,6 +38,7 @@ BOOL VMMDLL_InitializeReserved(_In_ DWORD argc, _In_ LPSTR argv[]);
* as hex string. NB! this is usally not required. Example: "0x1ab000".
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeFile(_In_ LPSTR szFileName, _In_opt_ LPSTR szPageTableBaseOpt);
/*
@@ -52,6 +54,7 @@ BOOL VMMDLL_InitializeFile(_In_ LPSTR szFileName, _In_opt_ LPSTR szPageTableBase
* as hex string. NB! this is usally not required. Example: "0x1ab000".
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeFPGA(_In_opt_ LPSTR szMaxPhysicalAddressOpt, _In_opt_ LPSTR szPageTableBaseOpt);
/*
@@ -60,6 +63,7 @@ BOOL VMMDLL_InitializeFPGA(_In_opt_ LPSTR szMaxPhysicalAddressOpt, _In_opt_ LPST
* initialized in read/write mode upon success.
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeTotalMeltdown();
/*
@@ -67,6 +71,7 @@ BOOL VMMDLL_InitializeTotalMeltdown();
* including plugins, linked PCILeech.DLL and other memory resources.
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_Close();
@@ -103,7 +108,8 @@ BOOL VMMDLL_Close();
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA_TLP 0x80000004 // RW
#define VMMDLL_OPT_CORE_MAX_NATIVE_ADDRESS 0x80000005 // R
#define VMMDLL_OPT_CORE_MAX_NATIVE_IOSIZE 0x80000006 // R
#define VMMDLL_OPT_CORE_TARGET_SYSTEM 0x80000007 // R
#define VMMDLL_OPT_CORE_SYSTEM 0x80000007 // R
#define VMMDLL_OPT_CORE_MEMORYMODEL 0x80000008 // R
#define VMMDLL_OPT_CONFIG_IS_REFRESH_ENABLED 0x40000001 // R - 1/0
#define VMMDLL_OPT_CONFIG_TICK_PERIOD 0x40000002 // RW - base tick period in ms
@@ -116,6 +122,22 @@ BOOL VMMDLL_Close();
#define VMMDLL_OPT_CONFIG_VMM_VERSION_REVISION 0x40000009 // R
#define VMMDLL_OPT_CONFIG_STATISTICS_FUNCTIONCALL 0x4000000A // RW - enable function call statistics (.status/statistics_fncall file)
static const LPSTR VMMDLL_MEMORYMODEL_TOSTRING[4] = { "N/A", "X86", "X86PAE", "X64" };
typedef enum tdVMMDLL_MEMORYMODEL_TP {
VMMDLL_MEMORYMODEL_NA = 0,
VMMDLL_MEMORYMODEL_X86 = 1,
VMMDLL_MEMORYMODEL_X86PAE = 2,
VMMDLL_MEMORYMODEL_X64 = 3
} VMMDLL_MEMORYMODEL_TP;
typedef enum tdVMMDLL_SYSTEM_TP {
VMMDLL_SYSTEM_UNKNOWN_X64 = 1,
VMMDLL_SYSTEM_WINDOWS_X64 = 2,
VMMDLL_SYSTEM_UNKNOWN_X86 = 3,
VMMDLL_SYSTEM_WINDOWS_X86 = 4
} VMMDLL_SYSTEM_TP;
/*
* Set a device specific option value. Please see defines VMMDLL_OPT_* for infor-
* mation about valid option values. Please note that option values may overlap
@@ -124,6 +146,7 @@ BOOL VMMDLL_Close();
* -- pqwValue = pointer to ULONG64 to receive option value.
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ConfigGet(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue);
/*
@@ -134,6 +157,7 @@ BOOL VMMDLL_ConfigGet(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue);
* -- qwValue
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ConfigSet(_In_ ULONG64 fOption, _In_ ULONG64 qwValue);
@@ -171,6 +195,7 @@ typedef struct tdVMMDLL_VFS_FILELIST {
* -- pFileList
* -- return
*/
_Success_(return)
BOOL VMMDLL_VfsList(_In_ LPCWSTR wcsPath, _Inout_ PVMMDLL_VFS_FILELIST pFileList);
/*
@@ -227,12 +252,13 @@ NTSTATUS VMMDLL_UtilVfsWriteFile_DWORD(_Inout_ PDWORD pdwTarget, _In_ LPVOID pb,
* will be unloaded on a general close of the vmm dll.
* -- return
*/
_Success_(return)
BOOL VMMDLL_VfsInitializePlugins();
#define VMMDLL_PLUGIN_CONTEXT_MAGIC 0xc0ffee663df9301c
#define VMMDLL_PLUGIN_CONTEXT_VERSION 1
#define VMMDLL_PLUGIN_REGINFO_MAGIC 0xc0ffee663df9301d
#define VMMDLL_PLUGIN_REGINFO_VERSION 1
#define VMMDLL_PLUGIN_REGINFO_VERSION 2
#define VMMDLL_PLUGIN_EVENT_VERBOSITYCHANGE 0x01
@@ -254,7 +280,8 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
ULONG64 magic;
WORD wVersion;
WORD wSize;
DWORD fTargetSystem;
VMMDLL_MEMORYMODEL_TP tpMemoryModel;
VMMDLL_SYSTEM_TP tpSystem;
HMODULE hDLL;
HMODULE hReservedDll; // not for general use (only used for python).
BOOL(*pfnPluginManager_Register)(struct tdVMMDLL_PLUGIN_REGINFO *pPluginRegInfo);
@@ -272,7 +299,7 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
// function plugin registration info to be filled out by the plugin below:
struct {
BOOL(*pfnList)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList);
NTSTATUS(*pfnRead)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset);
NTSTATUS(*pfnRead)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset);
NTSTATUS(*pfnWrite)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset);
VOID(*pfnNotify)(_Inout_opt_ PHANDLE phModulePrivate, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent);
VOID(*pfnCloseHandleModule)(_Inout_opt_ PHANDLE phModulePrivate);
@@ -296,8 +323,7 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
#define VMMDLL_FLAG_NOCACHE 0x0001 // do not use the data cache (force reading from memory acquisition device)
#define VMMDLL_FLAG_ZEROPAD_ON_FAIL 0x0002 // zero pad failed physical memory reads and report success if read within range of physical memory.
#define VMMDLL_TARGET_UNKNOWN_X64 0x0001
#define VMMDLL_TARGET_WINDOWS_X64 0x0002
#define VMMDLL_MEM_IO_SCATTER_HEADER_VERSION 2
typedef struct tdVMMDLL_MEM_IO_SCATTER_HEADER {
ULONG64 qwA; // base address (DWORD boundry).
@@ -306,6 +332,10 @@ typedef struct tdVMMDLL_MEM_IO_SCATTER_HEADER {
PBYTE pb; // ptr to 0x1000 sized buffer to receive read bytes.
PVOID pvReserved1; // reserved for use by caller.
PVOID pvReserved2; // reserved for use by caller.
WORD version; // version of struct
WORD Future1; // reserved for future use.
DWORD Future2; // reserved for future use.
ULONG64 qwDeviceA; // device-physical address (used by device layer).
struct {
PVOID pvReserved1;
PVOID pvReserved2;
@@ -335,6 +365,7 @@ DWORD VMMDLL_MemReadScatter(_In_ DWORD dwPID, _Inout_ PPVMMDLL_MEM_IO_SCATTER_HE
* -- pbPage
* -- return = success/fail (depending if all requested bytes are read or not).
*/
_Success_(return)
BOOL VMMDLL_MemReadPage(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_bytecount_(4096) PBYTE pbPage);
/*
@@ -345,6 +376,7 @@ BOOL VMMDLL_MemReadPage(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_bytecount_(4
* -- cb
* -- return = success/fail (depending if all requested bytes are read or not).
*/
_Success_(return)
BOOL VMMDLL_MemRead(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DWORD cb);
/*
@@ -358,7 +390,8 @@ BOOL VMMDLL_MemRead(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DW
* -- return = success/fail. NB! reads may report as success even if 0 bytes are
* read - it's recommended to verify pcbReadOpt parameter.
*/
BOOL VMMDLL_MemReadEx(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ ULONG64 flags);
_Success_(return)
BOOL VMMDLL_MemReadEx(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ ULONG64 flags);
/*
* Write a contigious arbitrary amount of memory. Please note some virtual memory
@@ -373,7 +406,8 @@ BOOL VMMDLL_MemReadEx(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_ PBYTE pb, _In
* -- cb
* -- return = TRUE on success, FALSE on partial or zero write.
*/
BOOL VMMDLL_MemWrite(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DWORD cb);
_Success_(return)
BOOL VMMDLL_MemWrite(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _In_ PBYTE pb, _In_ DWORD cb);
/*
* Translate a virtual address to a physical address by walking the page tables
@@ -383,6 +417,7 @@ BOOL VMMDLL_MemWrite(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ D
* -- pqwPA
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_MemVirt2Phys(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PULONG64 pqwPA);
@@ -401,6 +436,7 @@ BOOL VMMDLL_MemVirt2Phys(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PULONG64 pqw
* -- pdwPID = pointer that will receive PID on success.
* -- return
*/
_Success_(return)
BOOL VMMDLL_PidGetFromName(_In_ LPSTR szProcName, _Out_ PDWORD pdwPID);
/*
@@ -409,7 +445,8 @@ BOOL VMMDLL_PidGetFromName(_In_ LPSTR szProcName, _Out_ PDWORD pdwPID);
* -- pcPIDs = size of (in number of DWORDs) pPIDs array on entry, number of PIDs in system on exit.
* -- return = success/fail.
*/
BOOL VMMDLL_PidList(_Out_ PDWORD pPIDs, _Inout_ PULONG64 pcPIDs);
_Success_(return)
BOOL VMMDLL_PidList(_Out_opt_ PDWORD pPIDs, _Inout_ PULONG64 pcPIDs);
// flags to check for existence in the fPage field of PCILEECH_VMM_MEMMAP_ENTRY
#define VMMDLL_MEMMAP_FLAG_PAGE_W 0x0000000000000002
@@ -437,6 +474,7 @@ typedef struct tdVMMDLL_MEMMAP_ENTRY {
* -- fIdentifyModules = try identify modules as well (= slower)
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ProcessGetMemoryMap(_In_ DWORD dwPID, _Out_opt_ PVMMDLL_MEMMAP_ENTRY pMemMapEntries, _Inout_ PULONG64 pcMemMapEntries, _In_ BOOL fIdentifyModules);
/*
@@ -448,6 +486,7 @@ BOOL VMMDLL_ProcessGetMemoryMap(_In_ DWORD dwPID, _Out_opt_ PVMMDLL_MEMMAP_ENTRY
* -- fIdentifyModules = try identify modules as well (= slower)
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ProcessGetMemoryMapEntry(_In_ DWORD dwPID, _Out_ PVMMDLL_MEMMAP_ENTRY pMemMapEntry, _In_ ULONG64 va, _In_ BOOL fIdentifyModules);
typedef struct tdVMMDLL_MODULEMAP_ENTRY {
@@ -469,7 +508,8 @@ typedef struct tdVMMDLL_MODULEMAP_ENTRY {
* -- pcModuleEntries = pointer to number of memory map entries.
* -- return = success/fail.
*/
BOOL VMMDLL_ProcessGetModuleMap(_In_ DWORD dwPID, _Out_ PVMMDLL_MODULEMAP_ENTRY pModuleEntries, _Inout_ PULONG64 pcModuleEntries);
_Success_(return)
BOOL VMMDLL_ProcessGetModuleMap(_In_ DWORD dwPID, _Out_opt_ PVMMDLL_MODULEMAP_ENTRY pModuleEntries, _Inout_ PULONG64 pcModuleEntries);
/*
* Retrieve a module (.exe or .dll or similar) given a module name.
@@ -478,29 +518,31 @@ BOOL VMMDLL_ProcessGetModuleMap(_In_ DWORD dwPID, _Out_ PVMMDLL_MODULEMAP_ENTRY
* -- pModuleEntry
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ProcessGetModuleFromName(_In_ DWORD dwPID, _In_ LPSTR szModuleName, _Out_ PVMMDLL_MODULEMAP_ENTRY pModuleEntry);
#define VMMDLL_PROCESS_INFORMATION_MAGIC 0xc0ffee663df9301d
#define VMMDLL_PROCESS_INFORMATION_VERSION 1
#define VMMDLL_PROCESS_INFORMATION_MAGIC 0xc0ffee663df9301e
#define VMMDLL_PROCESS_INFORMATION_VERSION 2
typedef struct tdVMMDLL_PROCESS_INFORMATION {
ULONG64 magic;
WORD wVersion;
WORD wSize;
DWORD fTargetSystem; // as given by VMMDLL_TARGET_*
BOOL fUserOnly; // only user mode pages listed
VMMDLL_MEMORYMODEL_TP tpMemoryModel; // as given by VMMDLL_MEMORYMODEL_* enum
VMMDLL_SYSTEM_TP tpSystem; // as given by VMMDLL_SYSTEM_* enum
BOOL fUserOnly; // only user mode pages listed
DWORD dwPID;
DWORD dwState;
CHAR szName[16];
ULONG64 paPML4;
ULONG64 paPML4_UserOpt; // may not exist
ULONG64 paDTB;
ULONG64 paDTB_UserOpt; // may not exist
union {
struct {
ULONG64 vaEPROCESS;
ULONG64 vaPEB;
ULONG64 vaENTRY;
BOOL fWow64;
DWORD vaPEB32; // WoW64 only
DWORD vaPEB32; // WoW64 only
} win;
} os;
} VMMDLL_PROCESS_INFORMATION, *PVMMDLL_PROCESS_INFORMATION;
@@ -513,6 +555,7 @@ typedef struct tdVMMDLL_PROCESS_INFORMATION {
* -- pcbProcessInformation = size of pProcessInfo (in bytes) on entry and exit
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ProcessGetInformation(_In_ DWORD dwPID, _Inout_opt_ PVMMDLL_PROCESS_INFORMATION pProcessInformation, _In_ PSIZE_T pcbProcessInformation);
typedef struct tdVMMDLL_EAT_ENTRY {
@@ -539,10 +582,14 @@ typedef struct tdVMMDLL_IAT_ENTRY {
* -- pcData
* -- return = success/fail.
*/
BOOL VMMDLL_ProcessGetDirectories(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PIMAGE_DATA_DIRECTORY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
BOOL VMMDLL_ProcessGetSections(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PIMAGE_SECTION_HEADER pData, _In_ DWORD cData, _Out_ PDWORD pcData);
BOOL VMMDLL_ProcessGetEAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PVMMDLL_EAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
BOOL VMMDLL_ProcessGetIAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PVMMDLL_IAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
_Success_(return)
BOOL VMMDLL_ProcessGetDirectories(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_writes_(16) PIMAGE_DATA_DIRECTORY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
_Success_(return)
BOOL VMMDLL_ProcessGetSections(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_opt_ PIMAGE_SECTION_HEADER pData, _In_ DWORD cData, _Out_ PDWORD pcData);
_Success_(return)
BOOL VMMDLL_ProcessGetEAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_opt_ PVMMDLL_EAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
_Success_(return)
BOOL VMMDLL_ProcessGetIAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_opt_ PVMMDLL_IAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
@@ -558,7 +605,8 @@ BOOL VMMDLL_ProcessGetIAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PVMMDLL_I
* -- sz = buffer to fill, NULL to retrieve size in pcsz parameter.
* -- pcsz = ptr to size of buffer on entry, size of characters on exit.
*/
BOOL VMMDLL_UtilFillHexAscii(_In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset, _Inout_ LPSTR sz, _Inout_ PDWORD pcsz);
_Success_(return)
BOOL VMMDLL_UtilFillHexAscii(_In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset, _Inout_opt_ LPSTR sz, _Out_ PDWORD pcsz);
#ifdef __cplusplus
}

View File

@@ -96,8 +96,8 @@ VMMPYC_MemReadScatter(PyObject *self, PyObject *args)
{
PyObject *pyListSrc, *pyListItemSrc, *pyListDst, *pyDict;
BOOL result;
DWORD dwPID, cMEMs, i, flags = 0;
ULONG64 qwA;
DWORD dwPID, cMEMs, flags = 0;
ULONG64 i, qwA;
PVMMDLL_MEM_IO_SCATTER_HEADER pMEM, pMEMs;
PPVMMDLL_MEM_IO_SCATTER_HEADER ppMEMs;
PBYTE pb, pbDataBuffer;
@@ -243,7 +243,7 @@ VMMPYC_ProcessGetMemoryMap(PyObject *self, PyObject *args)
PyObject *pyList, *pyDict;
BOOL result, fIdentifyModules;
DWORD dwPID, i;
ULONG64 cMemMapEntries;
ULONG64 cMemMapEntries = 0;
PVMMDLL_MEMMAP_ENTRY pe, pMemMapEntries = NULL;
CHAR sz[5];
if(!PyArg_ParseTuple(args, "k|p", &dwPID, &fIdentifyModules)) { return NULL; }
@@ -323,7 +323,7 @@ VMMPYC_ProcessGetModuleMap(PyObject *self, PyObject *args)
PyObject *pyList, *pyDict;
BOOL result;
DWORD dwPID;
ULONG64 i, cModuleEntries;
ULONG64 i, cModuleEntries = 0;
PVMMDLL_MODULEMAP_ENTRY pe, pModuleEntries = NULL;
if(!PyArg_ParseTuple(args, "k", &dwPID)) { return NULL; }
if(!(pyList = PyList_New(0))) { return PyErr_NoMemory(); }
@@ -402,7 +402,7 @@ VMMPYC_PidList(PyObject *self, PyObject *args)
{
PyObject *pyList;
BOOL result;
ULONG64 cPIDs;
ULONG64 cPIDs = 0;
DWORD i, *pPIDs = NULL;
if(!(pyList = PyList_New(0))) { return PyErr_NoMemory(); }
Py_BEGIN_ALLOW_THREADS
@@ -445,18 +445,26 @@ VMMPYC_ProcessGetInformation(PyObject *self, PyObject *args)
return PyErr_Format(PyExc_RuntimeError, "VMMPYC_ProcessGetInformation: Failed.");
}
PyDict_SetItemString(pyDict, "pid", PyLong_FromUnsignedLong(info.dwPID));
PyDict_SetItemString(pyDict, "pa-pml4", PyLong_FromUnsignedLongLong(info.paPML4));
PyDict_SetItemString(pyDict, "pa-pml4-user", PyLong_FromUnsignedLongLong(info.paPML4_UserOpt));
PyDict_SetItemString(pyDict, "pa-dtb", PyLong_FromUnsignedLongLong(info.paDTB));
PyDict_SetItemString(pyDict, "pa-dtb-user", PyLong_FromUnsignedLongLong(info.paDTB_UserOpt));
PyDict_SetItemString(pyDict, "state", PyLong_FromUnsignedLong(info.dwState));
PyDict_SetItemString(pyDict, "target", PyLong_FromUnsignedLong(info.fTargetSystem));
PyDict_SetItemString(pyDict, "tp-memorymodel", PyLong_FromUnsignedLong(info.tpMemoryModel));
PyDict_SetItemString(pyDict, "tp-system", PyLong_FromUnsignedLong(info.tpSystem));
PyDict_SetItemString(pyDict, "usermode", PyBool_FromLong(info.fUserOnly));
PyDict_SetItemString(pyDict, "name", PyUnicode_FromString(info.szName));
if(info.fTargetSystem == VMMDLL_TARGET_WINDOWS_X64) {
PyDict_SetItemString(pyDict, "wow64", PyBool_FromLong((long)info.os.win.fWow64));
PyDict_SetItemString(pyDict, "va-entry", PyLong_FromUnsignedLongLong(info.os.win.vaENTRY));
PyDict_SetItemString(pyDict, "va-eprocess", PyLong_FromUnsignedLongLong(info.os.win.vaEPROCESS));
PyDict_SetItemString(pyDict, "va-peb", PyLong_FromUnsignedLongLong(info.os.win.vaPEB));
PyDict_SetItemString(pyDict, "va-peb32", PyLong_FromUnsignedLongLong(info.os.win.vaPEB32));
switch(info.tpSystem) {
case VMMDLL_SYSTEM_WINDOWS_X64:
PyDict_SetItemString(pyDict, "wow64", PyBool_FromLong((long)info.os.win.fWow64));
PyDict_SetItemString(pyDict, "va-entry", PyLong_FromUnsignedLongLong(info.os.win.vaENTRY));
PyDict_SetItemString(pyDict, "va-eprocess", PyLong_FromUnsignedLongLong(info.os.win.vaEPROCESS));
PyDict_SetItemString(pyDict, "va-peb", PyLong_FromUnsignedLongLong(info.os.win.vaPEB));
PyDict_SetItemString(pyDict, "va-peb32", PyLong_FromUnsignedLongLong(info.os.win.vaPEB32));
break;
case VMMDLL_SYSTEM_WINDOWS_X86:
PyDict_SetItemString(pyDict, "va-entry", PyLong_FromUnsignedLongLong(info.os.win.vaENTRY));
PyDict_SetItemString(pyDict, "va-eprocess", PyLong_FromUnsignedLongLong(info.os.win.vaEPROCESS));
PyDict_SetItemString(pyDict, "va-peb", PyLong_FromUnsignedLongLong(info.os.win.vaPEB));
break;
}
return pyDict;
}

View File

@@ -23,6 +23,7 @@ extern "C" {
* Call other VMMDLL_Intialize functions to initialize VMM.DLL and the memory
* process file system.
*/
_Success_(return)
BOOL VMMDLL_InitializeReserved(_In_ DWORD argc, _In_ LPSTR argv[]);
/*
@@ -37,6 +38,7 @@ BOOL VMMDLL_InitializeReserved(_In_ DWORD argc, _In_ LPSTR argv[]);
* as hex string. NB! this is usally not required. Example: "0x1ab000".
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeFile(_In_ LPSTR szFileName, _In_opt_ LPSTR szPageTableBaseOpt);
/*
@@ -52,6 +54,7 @@ BOOL VMMDLL_InitializeFile(_In_ LPSTR szFileName, _In_opt_ LPSTR szPageTableBase
* as hex string. NB! this is usally not required. Example: "0x1ab000".
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeFPGA(_In_opt_ LPSTR szMaxPhysicalAddressOpt, _In_opt_ LPSTR szPageTableBaseOpt);
/*
@@ -60,6 +63,7 @@ BOOL VMMDLL_InitializeFPGA(_In_opt_ LPSTR szMaxPhysicalAddressOpt, _In_opt_ LPST
* initialized in read/write mode upon success.
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_InitializeTotalMeltdown();
/*
@@ -67,6 +71,7 @@ BOOL VMMDLL_InitializeTotalMeltdown();
* including plugins, linked PCILeech.DLL and other memory resources.
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_Close();
@@ -103,7 +108,8 @@ BOOL VMMDLL_Close();
#define VMMDLL_OPT_CORE_VERBOSE_EXTRA_TLP 0x80000004 // RW
#define VMMDLL_OPT_CORE_MAX_NATIVE_ADDRESS 0x80000005 // R
#define VMMDLL_OPT_CORE_MAX_NATIVE_IOSIZE 0x80000006 // R
#define VMMDLL_OPT_CORE_TARGET_SYSTEM 0x80000007 // R
#define VMMDLL_OPT_CORE_SYSTEM 0x80000007 // R
#define VMMDLL_OPT_CORE_MEMORYMODEL 0x80000008 // R
#define VMMDLL_OPT_CONFIG_IS_REFRESH_ENABLED 0x40000001 // R - 1/0
#define VMMDLL_OPT_CONFIG_TICK_PERIOD 0x40000002 // RW - base tick period in ms
@@ -116,6 +122,22 @@ BOOL VMMDLL_Close();
#define VMMDLL_OPT_CONFIG_VMM_VERSION_REVISION 0x40000009 // R
#define VMMDLL_OPT_CONFIG_STATISTICS_FUNCTIONCALL 0x4000000A // RW - enable function call statistics (.status/statistics_fncall file)
static const LPSTR VMMDLL_MEMORYMODEL_TOSTRING[4] = { "N/A", "X86", "X86PAE", "X64" };
typedef enum tdVMMDLL_MEMORYMODEL_TP {
VMMDLL_MEMORYMODEL_NA = 0,
VMMDLL_MEMORYMODEL_X86 = 1,
VMMDLL_MEMORYMODEL_X86PAE = 2,
VMMDLL_MEMORYMODEL_X64 = 3
} VMMDLL_MEMORYMODEL_TP;
typedef enum tdVMMDLL_SYSTEM_TP {
VMMDLL_SYSTEM_UNKNOWN_X64 = 1,
VMMDLL_SYSTEM_WINDOWS_X64 = 2,
VMMDLL_SYSTEM_UNKNOWN_X86 = 3,
VMMDLL_SYSTEM_WINDOWS_X86 = 4
} VMMDLL_SYSTEM_TP;
/*
* Set a device specific option value. Please see defines VMMDLL_OPT_* for infor-
* mation about valid option values. Please note that option values may overlap
@@ -124,6 +146,7 @@ BOOL VMMDLL_Close();
* -- pqwValue = pointer to ULONG64 to receive option value.
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ConfigGet(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue);
/*
@@ -134,6 +157,7 @@ BOOL VMMDLL_ConfigGet(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue);
* -- qwValue
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ConfigSet(_In_ ULONG64 fOption, _In_ ULONG64 qwValue);
@@ -171,6 +195,7 @@ typedef struct tdVMMDLL_VFS_FILELIST {
* -- pFileList
* -- return
*/
_Success_(return)
BOOL VMMDLL_VfsList(_In_ LPCWSTR wcsPath, _Inout_ PVMMDLL_VFS_FILELIST pFileList);
/*
@@ -227,12 +252,13 @@ NTSTATUS VMMDLL_UtilVfsWriteFile_DWORD(_Inout_ PDWORD pdwTarget, _In_ LPVOID pb,
* will be unloaded on a general close of the vmm dll.
* -- return
*/
_Success_(return)
BOOL VMMDLL_VfsInitializePlugins();
#define VMMDLL_PLUGIN_CONTEXT_MAGIC 0xc0ffee663df9301c
#define VMMDLL_PLUGIN_CONTEXT_VERSION 1
#define VMMDLL_PLUGIN_REGINFO_MAGIC 0xc0ffee663df9301d
#define VMMDLL_PLUGIN_REGINFO_VERSION 1
#define VMMDLL_PLUGIN_REGINFO_VERSION 2
#define VMMDLL_PLUGIN_EVENT_VERBOSITYCHANGE 0x01
@@ -254,7 +280,8 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
ULONG64 magic;
WORD wVersion;
WORD wSize;
DWORD fTargetSystem;
VMMDLL_MEMORYMODEL_TP tpMemoryModel;
VMMDLL_SYSTEM_TP tpSystem;
HMODULE hDLL;
HMODULE hReservedDll; // not for general use (only used for python).
BOOL(*pfnPluginManager_Register)(struct tdVMMDLL_PLUGIN_REGINFO *pPluginRegInfo);
@@ -272,7 +299,7 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
// function plugin registration info to be filled out by the plugin below:
struct {
BOOL(*pfnList)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList);
NTSTATUS(*pfnRead)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset);
NTSTATUS(*pfnRead)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset);
NTSTATUS(*pfnWrite)(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset);
VOID(*pfnNotify)(_Inout_opt_ PHANDLE phModulePrivate, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent);
VOID(*pfnCloseHandleModule)(_Inout_opt_ PHANDLE phModulePrivate);
@@ -296,8 +323,7 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO {
#define VMMDLL_FLAG_NOCACHE 0x0001 // do not use the data cache (force reading from memory acquisition device)
#define VMMDLL_FLAG_ZEROPAD_ON_FAIL 0x0002 // zero pad failed physical memory reads and report success if read within range of physical memory.
#define VMMDLL_TARGET_UNKNOWN_X64 0x0001
#define VMMDLL_TARGET_WINDOWS_X64 0x0002
#define VMMDLL_MEM_IO_SCATTER_HEADER_VERSION 2
typedef struct tdVMMDLL_MEM_IO_SCATTER_HEADER {
ULONG64 qwA; // base address (DWORD boundry).
@@ -306,6 +332,10 @@ typedef struct tdVMMDLL_MEM_IO_SCATTER_HEADER {
PBYTE pb; // ptr to 0x1000 sized buffer to receive read bytes.
PVOID pvReserved1; // reserved for use by caller.
PVOID pvReserved2; // reserved for use by caller.
WORD version; // version of struct
WORD Future1; // reserved for future use.
DWORD Future2; // reserved for future use.
ULONG64 qwDeviceA; // device-physical address (used by device layer).
struct {
PVOID pvReserved1;
PVOID pvReserved2;
@@ -335,6 +365,7 @@ DWORD VMMDLL_MemReadScatter(_In_ DWORD dwPID, _Inout_ PPVMMDLL_MEM_IO_SCATTER_HE
* -- pbPage
* -- return = success/fail (depending if all requested bytes are read or not).
*/
_Success_(return)
BOOL VMMDLL_MemReadPage(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_bytecount_(4096) PBYTE pbPage);
/*
@@ -345,6 +376,7 @@ BOOL VMMDLL_MemReadPage(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_bytecount_(4
* -- cb
* -- return = success/fail (depending if all requested bytes are read or not).
*/
_Success_(return)
BOOL VMMDLL_MemRead(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DWORD cb);
/*
@@ -358,7 +390,8 @@ BOOL VMMDLL_MemRead(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DW
* -- return = success/fail. NB! reads may report as success even if 0 bytes are
* read - it's recommended to verify pcbReadOpt parameter.
*/
BOOL VMMDLL_MemReadEx(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ ULONG64 flags);
_Success_(return)
BOOL VMMDLL_MemReadEx(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ ULONG64 flags);
/*
* Write a contigious arbitrary amount of memory. Please note some virtual memory
@@ -373,7 +406,8 @@ BOOL VMMDLL_MemReadEx(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_ PBYTE pb, _In
* -- cb
* -- return = TRUE on success, FALSE on partial or zero write.
*/
BOOL VMMDLL_MemWrite(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DWORD cb);
_Success_(return)
BOOL VMMDLL_MemWrite(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _In_ PBYTE pb, _In_ DWORD cb);
/*
* Translate a virtual address to a physical address by walking the page tables
@@ -383,6 +417,7 @@ BOOL VMMDLL_MemWrite(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ D
* -- pqwPA
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_MemVirt2Phys(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PULONG64 pqwPA);
@@ -401,6 +436,7 @@ BOOL VMMDLL_MemVirt2Phys(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PULONG64 pqw
* -- pdwPID = pointer that will receive PID on success.
* -- return
*/
_Success_(return)
BOOL VMMDLL_PidGetFromName(_In_ LPSTR szProcName, _Out_ PDWORD pdwPID);
/*
@@ -409,7 +445,8 @@ BOOL VMMDLL_PidGetFromName(_In_ LPSTR szProcName, _Out_ PDWORD pdwPID);
* -- pcPIDs = size of (in number of DWORDs) pPIDs array on entry, number of PIDs in system on exit.
* -- return = success/fail.
*/
BOOL VMMDLL_PidList(_Out_ PDWORD pPIDs, _Inout_ PULONG64 pcPIDs);
_Success_(return)
BOOL VMMDLL_PidList(_Out_opt_ PDWORD pPIDs, _Inout_ PULONG64 pcPIDs);
// flags to check for existence in the fPage field of PCILEECH_VMM_MEMMAP_ENTRY
#define VMMDLL_MEMMAP_FLAG_PAGE_W 0x0000000000000002
@@ -437,6 +474,7 @@ typedef struct tdVMMDLL_MEMMAP_ENTRY {
* -- fIdentifyModules = try identify modules as well (= slower)
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ProcessGetMemoryMap(_In_ DWORD dwPID, _Out_opt_ PVMMDLL_MEMMAP_ENTRY pMemMapEntries, _Inout_ PULONG64 pcMemMapEntries, _In_ BOOL fIdentifyModules);
/*
@@ -448,6 +486,7 @@ BOOL VMMDLL_ProcessGetMemoryMap(_In_ DWORD dwPID, _Out_opt_ PVMMDLL_MEMMAP_ENTRY
* -- fIdentifyModules = try identify modules as well (= slower)
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ProcessGetMemoryMapEntry(_In_ DWORD dwPID, _Out_ PVMMDLL_MEMMAP_ENTRY pMemMapEntry, _In_ ULONG64 va, _In_ BOOL fIdentifyModules);
typedef struct tdVMMDLL_MODULEMAP_ENTRY {
@@ -469,7 +508,8 @@ typedef struct tdVMMDLL_MODULEMAP_ENTRY {
* -- pcModuleEntries = pointer to number of memory map entries.
* -- return = success/fail.
*/
BOOL VMMDLL_ProcessGetModuleMap(_In_ DWORD dwPID, _Out_ PVMMDLL_MODULEMAP_ENTRY pModuleEntries, _Inout_ PULONG64 pcModuleEntries);
_Success_(return)
BOOL VMMDLL_ProcessGetModuleMap(_In_ DWORD dwPID, _Out_opt_ PVMMDLL_MODULEMAP_ENTRY pModuleEntries, _Inout_ PULONG64 pcModuleEntries);
/*
* Retrieve a module (.exe or .dll or similar) given a module name.
@@ -478,29 +518,31 @@ BOOL VMMDLL_ProcessGetModuleMap(_In_ DWORD dwPID, _Out_ PVMMDLL_MODULEMAP_ENTRY
* -- pModuleEntry
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ProcessGetModuleFromName(_In_ DWORD dwPID, _In_ LPSTR szModuleName, _Out_ PVMMDLL_MODULEMAP_ENTRY pModuleEntry);
#define VMMDLL_PROCESS_INFORMATION_MAGIC 0xc0ffee663df9301d
#define VMMDLL_PROCESS_INFORMATION_VERSION 1
#define VMMDLL_PROCESS_INFORMATION_MAGIC 0xc0ffee663df9301e
#define VMMDLL_PROCESS_INFORMATION_VERSION 2
typedef struct tdVMMDLL_PROCESS_INFORMATION {
ULONG64 magic;
WORD wVersion;
WORD wSize;
DWORD fTargetSystem; // as given by VMMDLL_TARGET_*
BOOL fUserOnly; // only user mode pages listed
VMMDLL_MEMORYMODEL_TP tpMemoryModel; // as given by VMMDLL_MEMORYMODEL_* enum
VMMDLL_SYSTEM_TP tpSystem; // as given by VMMDLL_SYSTEM_* enum
BOOL fUserOnly; // only user mode pages listed
DWORD dwPID;
DWORD dwState;
CHAR szName[16];
ULONG64 paPML4;
ULONG64 paPML4_UserOpt; // may not exist
ULONG64 paDTB;
ULONG64 paDTB_UserOpt; // may not exist
union {
struct {
ULONG64 vaEPROCESS;
ULONG64 vaPEB;
ULONG64 vaENTRY;
BOOL fWow64;
DWORD vaPEB32; // WoW64 only
DWORD vaPEB32; // WoW64 only
} win;
} os;
} VMMDLL_PROCESS_INFORMATION, *PVMMDLL_PROCESS_INFORMATION;
@@ -513,6 +555,7 @@ typedef struct tdVMMDLL_PROCESS_INFORMATION {
* -- pcbProcessInformation = size of pProcessInfo (in bytes) on entry and exit
* -- return = success/fail.
*/
_Success_(return)
BOOL VMMDLL_ProcessGetInformation(_In_ DWORD dwPID, _Inout_opt_ PVMMDLL_PROCESS_INFORMATION pProcessInformation, _In_ PSIZE_T pcbProcessInformation);
typedef struct tdVMMDLL_EAT_ENTRY {
@@ -539,10 +582,14 @@ typedef struct tdVMMDLL_IAT_ENTRY {
* -- pcData
* -- return = success/fail.
*/
BOOL VMMDLL_ProcessGetDirectories(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PIMAGE_DATA_DIRECTORY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
BOOL VMMDLL_ProcessGetSections(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PIMAGE_SECTION_HEADER pData, _In_ DWORD cData, _Out_ PDWORD pcData);
BOOL VMMDLL_ProcessGetEAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PVMMDLL_EAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
BOOL VMMDLL_ProcessGetIAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PVMMDLL_IAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
_Success_(return)
BOOL VMMDLL_ProcessGetDirectories(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_writes_(16) PIMAGE_DATA_DIRECTORY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
_Success_(return)
BOOL VMMDLL_ProcessGetSections(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_opt_ PIMAGE_SECTION_HEADER pData, _In_ DWORD cData, _Out_ PDWORD pcData);
_Success_(return)
BOOL VMMDLL_ProcessGetEAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_opt_ PVMMDLL_EAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
_Success_(return)
BOOL VMMDLL_ProcessGetIAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_opt_ PVMMDLL_IAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData);
@@ -558,7 +605,8 @@ BOOL VMMDLL_ProcessGetIAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_ PVMMDLL_I
* -- sz = buffer to fill, NULL to retrieve size in pcsz parameter.
* -- pcsz = ptr to size of buffer on entry, size of characters on exit.
*/
BOOL VMMDLL_UtilFillHexAscii(_In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset, _Inout_ LPSTR sz, _Inout_ PDWORD pcsz);
_Success_(return)
BOOL VMMDLL_UtilFillHexAscii(_In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset, _Inout_opt_ LPSTR sz, _Out_ PDWORD pcsz);
#ifdef __cplusplus
}

View File

@@ -56,7 +56,7 @@ PY2C_CallbackRegister(PyObject *self, PyObject *args)
return Py_BuildValue("s", NULL); // None returned on success.
}
BOOL PY2C_Util_TranslatePathDelimiter(_Inout_ CHAR dst[MAX_PATH], LPSTR src)
BOOL PY2C_Util_TranslatePathDelimiter(_Out_writes_(MAX_PATH) PCHAR dst, LPSTR src)
{
DWORD i;
for(i = 0; i < MAX_PATH; i++) {
@@ -248,7 +248,7 @@ void PY2C_InitializeModuleVMMPYCC()
// CORE NATIVE MODULE FUNCTIONALITY BELOW:
//-----------------------------------------------------------------------------
VOID Util_GetPathDll(_Out_ WCHAR wszPath[MAX_PATH], _In_opt_ HMODULE hModule)
VOID Util_GetPathDll(_Out_writes_(MAX_PATH) PWCHAR wszPath, _In_opt_ HMODULE hModule)
{
SIZE_T i;
GetModuleFileNameW(hModule, wszPath, MAX_PATH - 4);
@@ -348,7 +348,7 @@ VOID PYTHON_Close(_Inout_ PHANDLE phModulePrivate)
__declspec(dllexport)
VOID InitializeVmmPlugin(_In_ PVMMDLL_PLUGIN_REGINFO pRegInfo)
{
if(0 == (pRegInfo->fTargetSystem & (VMMDLL_TARGET_UNKNOWN_X64 | VMMDLL_TARGET_WINDOWS_X64))) { return; }
if((pRegInfo->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRegInfo->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; }
if(VmmPyPlugin_PythonInitialize(pRegInfo->hReservedDll)) {
strcpy_s(pRegInfo->reg_info.szModuleName, 32, "py"); // module name - 'py'.
pRegInfo->reg_info.fRootModule = TRUE; // module shows in root directory.