diff --git a/MemProcFS/vfs.c b/MemProcFS/vfs.c
index 6bd89cb..13eb9fc 100644
--- a/MemProcFS/vfs.c
+++ b/MemProcFS/vfs.c
@@ -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();
}
diff --git a/MemProcFS/vmmdll.h b/MemProcFS/vmmdll.h
index 623a09b..bfa1172 100644
--- a/MemProcFS/vmmdll.h
+++ b/MemProcFS/vmmdll.h
@@ -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
}
diff --git a/README.md b/README.md
index 055958e..39c5108 100644
--- a/README.md
+++ b/README.md
@@ -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.
diff --git a/files/MemProcFS.exe b/files/MemProcFS.exe
index d3d3974..5c6c9f0 100644
Binary files a/files/MemProcFS.exe and b/files/MemProcFS.exe differ
diff --git a/files/plugins/m_vmemd.dll b/files/plugins/m_vmemd.dll
index 2d484e8..0c0d215 100644
Binary files a/files/plugins/m_vmemd.dll and b/files/plugins/m_vmemd.dll differ
diff --git a/files/plugins/pym_procstruct/pym_procstruct.py b/files/plugins/pym_procstruct/pym_procstruct.py
index 1c7d48b..2f4b284 100644
--- a/files/plugins/pym_procstruct/pym_procstruct.py
+++ b/files/plugins/pym_procstruct/pym_procstruct.py
@@ -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
diff --git a/files/vmm.dll b/files/vmm.dll
index 7a5e5f1..9ade46f 100644
Binary files a/files/vmm.dll and b/files/vmm.dll differ
diff --git a/files/vmm.lib b/files/vmm.lib
index 92fa149..9ad5dd8 100644
Binary files a/files/vmm.lib and b/files/vmm.lib differ
diff --git a/files/vmmdll.h b/files/vmmdll.h
index 623a09b..bfa1172 100644
--- a/files/vmmdll.h
+++ b/files/vmmdll.h
@@ -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
}
diff --git a/files/vmmpy.py b/files/vmmpy.py
index dd9777e..594a4d6 100644
--- a/files/vmmpy.py
+++ b/files/vmmpy.py
@@ -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 = {}
diff --git a/files/vmmpyc.pyd b/files/vmmpyc.pyd
index 1e4377e..2a1e903 100644
Binary files a/files/vmmpyc.pyd and b/files/vmmpyc.pyd differ
diff --git a/files/vmmpycplugin.dll b/files/vmmpycplugin.dll
index 97948f0..b332312 100644
Binary files a/files/vmmpycplugin.dll and b/files/vmmpycplugin.dll differ
diff --git a/files/vmmpyplugin.py b/files/vmmpyplugin.py
index 29b713b..3c080b0 100644
--- a/files/vmmpyplugin.py
+++ b/files/vmmpyplugin.py
@@ -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 + "'")
diff --git a/m_vmemd/m_vmemd.c b/m_vmemd/m_vmemd.c
index 45cae82..b46a0ef 100644
--- a/m_vmemd/m_vmemd.c
+++ b/m_vmemd/m_vmemd.c
@@ -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.
}
diff --git a/m_vmemd/vmmdll.h b/m_vmemd/vmmdll.h
index 623a09b..bfa1172 100644
--- a/m_vmemd/vmmdll.h
+++ b/m_vmemd/vmmdll.h
@@ -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
}
diff --git a/vmm/device.c b/vmm/device.c
index c349e12..0784834 100644
--- a/vmm/device.c
+++ b/vmm/device.c
@@ -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;
}
diff --git a/vmm/device.h b/vmm/device.h
index 7d39f86..070f4d7 100644
--- a/vmm/device.h
+++ b/vmm/device.h
@@ -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__ */
diff --git a/vmm/devicepcileechdll.c b/vmm/devicepcileechdll.c
index 99e413e..babf137 100644
--- a/vmm/devicepcileechdll.c
+++ b/vmm/devicepcileechdll.c
@@ -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);
}
diff --git a/vmm/m_ldrmodules.c b/vmm/m_ldrmodules.c
index bbebaf8..2ed70fd 100644
--- a/vmm/m_ldrmodules.c
+++ b/vmm/m_ldrmodules.c
@@ -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);
}
diff --git a/vmm/m_status.c b/vmm/m_status.c
index cb36b50..fab008b 100644
--- a/vmm/m_status.c
+++ b/vmm/m_status.c
@@ -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);
}
diff --git a/vmm/m_virt2phys.c b/vmm/m_virt2phys.c
index 43d5ca1..15bf0ea 100644
--- a/vmm/m_virt2phys.c
+++ b/vmm/m_virt2phys.c
@@ -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);
}
diff --git a/vmm/vmmx64.c b/vmm/mm_x64.c
similarity index 56%
rename from vmm/vmmx64.c
rename to vmm/mm_x64.c
index 97b69c4..2cf6032 100644
--- a/vmm/vmmx64.c
+++ b/vmm/mm_x64.c
@@ -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;
}
diff --git a/vmm/vmmx64.h b/vmm/mm_x64.h
similarity index 65%
rename from vmm/vmmx64.h
rename to vmm/mm_x64.h
index 899c606..09b1ac1 100644
--- a/vmm/vmmx64.h
+++ b/vmm/mm_x64.h
@@ -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__ */
diff --git a/vmm/mm_x86.c b/vmm/mm_x86.c
new file mode 100644
index 0000000..0af452d
--- /dev/null
+++ b/vmm/mm_x86.c
@@ -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;
+}
diff --git a/vmm/mm_x86.h b/vmm/mm_x86.h
new file mode 100644
index 0000000..fdbeeaa
--- /dev/null
+++ b/vmm/mm_x86.h
@@ -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__ */
diff --git a/vmm/mm_x86pae.c b/vmm/mm_x86pae.c
new file mode 100644
index 0000000..5045e17
--- /dev/null
+++ b/vmm/mm_x86pae.c
@@ -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;
+}
diff --git a/vmm/mm_x86pae.h b/vmm/mm_x86pae.h
new file mode 100644
index 0000000..a75946e
--- /dev/null
+++ b/vmm/mm_x86pae.h
@@ -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__ */
diff --git a/vmm/pe.c b/vmm/pe.c
new file mode 100644
index 0000000..1fb9699
--- /dev/null
+++ b/vmm/pe.c
@@ -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;
+}
diff --git a/vmm/pe.h b/vmm/pe.h
new file mode 100644
index 0000000..6f254f8
--- /dev/null
+++ b/vmm/pe.h
@@ -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__ */
diff --git a/vmm/pluginmanager.c b/vmm/pluginmanager.c
index b592dde..af1f82e 100644
--- a/vmm/pluginmanager.c
+++ b/vmm/pluginmanager.c
@@ -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;
}
diff --git a/vmm/util.c b/vmm/util.c
index 145846b..0d34fb4 100644
--- a/vmm/util.c
+++ b/vmm/util.c
@@ -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);
diff --git a/vmm/util.h b/vmm/util.h
index 213c4f9..923aff7 100644
--- a/vmm/util.h
+++ b/vmm/util.h
@@ -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.
diff --git a/vmm/vmm.c b/vmm/vmm.c
index 1532be7..03ba8f9 100644
--- a/vmm/vmm.c
+++ b/vmm/vmm.c
@@ -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();
diff --git a/vmm/vmm.h b/vmm/vmm.h
index 4f94466..93e8fb3 100644
--- a/vmm/vmm.h
+++ b/vmm/vmm.h
@@ -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:
diff --git a/vmm/vmm.vcxproj b/vmm/vmm.vcxproj
index 81cb61b..d59be08 100644
--- a/vmm/vmm.vcxproj
+++ b/vmm/vmm.vcxproj
@@ -99,35 +99,44 @@
+
+
+
+
+
-
-
+
+
+
+
+
+
-
-
+
+
diff --git a/vmm/vmm.vcxproj.filters b/vmm/vmm.vcxproj.filters
index 83ee28d..7939595 100644
--- a/vmm/vmm.vcxproj.filters
+++ b/vmm/vmm.vcxproj.filters
@@ -59,13 +59,28 @@
Header Files
-
- Header Files
-
Header Files
-
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
Header Files
@@ -106,13 +121,25 @@
Source Files
-
- Source Files
-
Source Files
-
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
Source Files
diff --git a/vmm/vmmdll.c b/vmm/vmmdll.c
index b524fb5..65e9854 100644
--- a/vmm/vmmdll.c
+++ b/vmm/vmmdll.c
@@ -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);
}
diff --git a/vmm/vmmdll.h b/vmm/vmmdll.h
index 623a09b..bfa1172 100644
--- a/vmm/vmmdll.h
+++ b/vmm/vmmdll.h
@@ -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
}
diff --git a/vmm/vmmproc.c b/vmm/vmmproc.c
index 9a593a0..20d9d4e 100644
--- a/vmm/vmmproc.c
+++ b/vmm/vmmproc.c
@@ -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;
}
diff --git a/vmm/vmmproc.h b/vmm/vmmproc.h
index 2ed1f55..48acf6f 100644
--- a/vmm/vmmproc.h
+++ b/vmm/vmmproc.h
@@ -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.
diff --git a/vmm/vmmproc_windows.h b/vmm/vmmproc_windows.h
deleted file mode 100644
index 56ff08e..0000000
--- a/vmm/vmmproc_windows.h
+++ /dev/null
@@ -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__ */
diff --git a/vmm/vmmvfs.c b/vmm/vmmvfs.c
index a1e89ec..2f57534 100644
--- a/vmm/vmmvfs.c
+++ b/vmm/vmmvfs.c
@@ -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);
diff --git a/vmm/vmmproc_windows.c b/vmm/vmmwin.c
similarity index 50%
rename from vmm/vmmproc_windows.c
rename to vmm/vmmwin.c
index fb95c10..e55b699 100644
--- a/vmm/vmmproc_windows.c
+++ b/vmm/vmmwin.c
@@ -1,13 +1,15 @@
-// vmmproc_windows.h : implementation related to operating system and process
+// vmmwin.c : implementation related to operating system and process
// parsing of virtual memory. Windows related features only.
//
// (c) Ulf Frisk, 2018
// Author: Ulf Frisk, pcileech@frizk.net
//
-#include "vmmproc_windows.h"
+#include "vmmwin.h"
+#include "vmmproc.h"
#include "device.h"
#include "util.h"
+#include "pe.h"
#include
// ----------------------------------------------------------------------------
@@ -15,7 +17,7 @@
// GENERAL FUNCTIONALITY
// ----------------------------------------------------------------------------
-PIMAGE_NT_HEADERS VmmProcWindows_GetVerifyHeaderPE(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModule, _Inout_ PBYTE pbModuleHeader, _Out_ PBOOL pfHdr32)
+PIMAGE_NT_HEADERS VmmWin_GetVerifyHeaderPE(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModule, _Inout_ PBYTE pbModuleHeader, _Out_ PBOOL pfHdr32)
{
PIMAGE_DOS_HEADER dosHeader;
PIMAGE_NT_HEADERS ntHeader;
@@ -38,22 +40,26 @@ PIMAGE_NT_HEADERS VmmProcWindows_GetVerifyHeaderPE(_In_ PVMM_PROCESS pProcess, _
// IMPORT/EXPORT DIRECTORY PARSING
// ----------------------------------------------------------------------------
-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)
+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)
{
- BYTE pbModuleHeader[0x1000];
+ BYTE pbModuleHeader[0x1000] = { 0 };
PIMAGE_NT_HEADERS64 ntHeader64;
- PIMAGE_NT_HEADERS32 ntHeader32;
BOOL fHdr32;
- DWORD i;
+ DWORD i, cSections, cSectionsOpt;
PIMAGE_SECTION_HEADER pSectionBase;
if(pcbDisplayBuffer) { *pcbDisplayBuffer = 0; }
- if(!(ntHeader64 = VmmProcWindows_GetVerifyHeaderPE(pProcess, pModule->BaseAddress, pbModuleHeader, &fHdr32))) { return; }
- ntHeader32 = (PIMAGE_NT_HEADERS32)ntHeader64;
+ if(pcSectionsOpt) {
+ cSectionsOpt = *pcSectionsOpt;
+ *pcSectionsOpt = 0;
+ }
+ if(!(ntHeader64 = VmmWin_GetVerifyHeaderPE(pProcess, pModule->BaseAddress, pbModuleHeader, &fHdr32))) { return; }
pSectionBase = fHdr32 ?
- (PIMAGE_SECTION_HEADER)((QWORD)ntHeader32 + sizeof(IMAGE_NT_HEADERS32)) :
+ (PIMAGE_SECTION_HEADER)((QWORD)ntHeader64 + sizeof(IMAGE_NT_HEADERS32)) :
(PIMAGE_SECTION_HEADER)((QWORD)ntHeader64 + 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, ntHeader64->FileHeader.NumberOfSections); // FileHeader are the same in both 32/64-bit versions of struct
if(pbDisplayBufferOpt) {
- for(i = 0; i < (DWORD)min(32, ntHeader64->FileHeader.NumberOfSections); i++) {
+ for(i = 0; i < cSections; i++) {
// 52 byte per line (indluding newline)
*pcbDisplayBuffer += snprintf(
pbDisplayBufferOpt + *pcbDisplayBuffer,
@@ -70,32 +76,32 @@ VOID VmmProcWindows_PE_SECTION_DisplayBuffer(_In_ PVMM_PROCESS pProcess, _In_ PV
);
}
}
- if(pSectionsOpt) {
- memcpy(pSectionsOpt, pSectionBase, ntHeader64->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER));
+ if(pSectionsOpt && pcSectionsOpt && cSectionsOpt) {
+ *pcSectionsOpt = min(cSectionsOpt, ntHeader64->FileHeader.NumberOfSections);
+ memcpy(pSectionsOpt, pSectionBase, *pcSectionsOpt * sizeof(IMAGE_SECTION_HEADER));
}
}
-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)
+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)
{
- LPCSTR DIRECTORIES[16] = { "EXPORT", "IMPORT", "RESOURCE", "EXCEPTION", "SECURITY", "BASERELOC", "DEBUG", "ARCHITECTURE", "GLOBALPTR", "TLS", "LOAD_CONFIG", "BOUND_IMPORT", "IAT", "DELAY_IMPORT", "COM_DESCRIPTOR", "RESERVED" };
- BYTE i, pbModuleHeader[0x1000];
+ BYTE i, pbModuleHeader[0x1000] = { 0 };
PIMAGE_NT_HEADERS64 ntHeader64;
PIMAGE_NT_HEADERS32 ntHeader32;
PIMAGE_DATA_DIRECTORY pDataDirectoryBase;
BOOL fHdr32;
if(pcbDisplayBuffer) { *pcbDisplayBuffer = 0; }
- if(!(ntHeader64 = VmmProcWindows_GetVerifyHeaderPE(pProcess, pModule->BaseAddress, pbModuleHeader, &fHdr32))) { return; }
+ if(!(ntHeader64 = VmmWin_GetVerifyHeaderPE(pProcess, pModule->BaseAddress, pbModuleHeader, &fHdr32))) { return; }
ntHeader32 = (PIMAGE_NT_HEADERS32)ntHeader64;
pDataDirectoryBase = fHdr32 ? ntHeader32->OptionalHeader.DataDirectory : ntHeader64->OptionalHeader.DataDirectory;
if(pbDisplayBufferOpt) {
for(i = 0; i < 16; i++) {
- if(pbDisplayBufferOpt) {
+ if(pbDisplayBufferOpt && pcbDisplayBuffer) {
*pcbDisplayBuffer += snprintf(
pbDisplayBufferOpt + *pcbDisplayBuffer,
cbDisplayBufferMax - *pcbDisplayBuffer,
"%x %-16.16s %016llx %08x %08x\n",
i,
- DIRECTORIES[i],
+ PE_DATA_DIRECTORIES[i],
pModule->BaseAddress + pDataDirectoryBase[i].VirtualAddress,
pDataDirectoryBase[i].VirtualAddress,
pDataDirectoryBase[i].Size
@@ -109,22 +115,21 @@ VOID VmmProcWindows_PE_DIRECTORY_DisplayBuffer(_In_ PVMM_PROCESS pProcess, _In_
}
-VOID VmmProcWindows_PE_LoadEAT_DisplayBuffer(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_MODULEMAP_ENTRY pModule, _Out_ PVMMPROC_WINDOWS_EAT_ENTRY pEATs, _Inout_ PDWORD pcEATs)
+VOID VmmWin_PE_LoadEAT_DisplayBuffer(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_MODULEMAP_ENTRY pModule, _Out_ PVMMPROC_WINDOWS_EAT_ENTRY pEATs, _Inout_ PDWORD pcEATs)
{
- BYTE pbModuleHeader[0x1000];
+ BYTE pbModuleHeader[0x1000] = { 0 };
PIMAGE_NT_HEADERS64 ntHeader64;
PIMAGE_NT_HEADERS32 ntHeader32;
QWORD oExportDirectory, cbExportDirectory;
PBYTE pbExportDirectory = NULL;
PIMAGE_EXPORT_DIRECTORY pExportDirectory;
- QWORD oNameOrdinal, ooName, oName, oFunction;
- WORD wOrdinalFnIdx;
+ QWORD i, oNameOrdinal, ooName, oName, oFunction, wOrdinalFnIdx;
DWORD vaFunctionOffset;
BOOL fHdr32;
- DWORD i, cEATs = *pcEATs;
+ DWORD cEATs = *pcEATs;
*pcEATs = 0;
// load both 32/64 bit ntHeader (only one will be valid)
- if(!(ntHeader64 = VmmProcWindows_GetVerifyHeaderPE(pProcess, pModule->BaseAddress, pbModuleHeader, &fHdr32))) { goto cleanup; }
+ if(!(ntHeader64 = VmmWin_GetVerifyHeaderPE(pProcess, pModule->BaseAddress, pbModuleHeader, &fHdr32))) { goto cleanup; }
ntHeader32 = (PIMAGE_NT_HEADERS32)ntHeader64;
// Load Export Address Table (EAT)
oExportDirectory = fHdr32 ?
@@ -157,24 +162,24 @@ VOID VmmProcWindows_PE_LoadEAT_DisplayBuffer(_Inout_ PVMM_PROCESS pProcess, _Ino
pEATs[i].vaFunction = pModule->BaseAddress + vaFunctionOffset;
strncpy_s(pEATs[i].szFunction, 40, (LPSTR)(pbExportDirectory - oExportDirectory + oName), _TRUNCATE);
}
- *pcEATs = i;
+ *pcEATs = (DWORD)i;
cleanup:
LocalFree(pbExportDirectory);
}
-VOID VmmProcWindows_PE_LoadIAT_DisplayBuffer(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_MODULEMAP_ENTRY pModule, _Out_ PVMMPROC_WINDOWS_IAT_ENTRY pIATs, _Inout_ PDWORD pcIATs)
+VOID VmmWin_PE_LoadIAT_DisplayBuffer(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_MODULEMAP_ENTRY pModule, _Out_ PVMMWIN_IAT_ENTRY pIATs, _Inout_ PDWORD pcIATs)
{
- BYTE pbModuleHeader[0x1000];
+ BYTE pbModuleHeader[0x1000] = { 0 };
PIMAGE_NT_HEADERS64 ntHeader64;
PIMAGE_NT_HEADERS32 ntHeader32;
- QWORD oImportDirectory;
+ QWORD i, oImportDirectory;
PIMAGE_IMPORT_DESCRIPTOR pIID;
PQWORD pIAT64, pHNA64;
PDWORD pIAT32, pHNA32;
PBYTE pbModule;
DWORD cbModule, cbRead;
BOOL fHdr32, fFnName;
- DWORD c, i, j, cIATs = *pcIATs;
+ DWORD c, j, cIATs = *pcIATs;
*pcIATs = 0;
// Load the module
if(pModule->SizeOfImage > 0x01000000) { return; }
@@ -183,7 +188,7 @@ VOID VmmProcWindows_PE_LoadIAT_DisplayBuffer(_Inout_ PVMM_PROCESS pProcess, _Ino
VmmReadEx(pProcess, pModule->BaseAddress, pbModule, cbModule, &cbRead, 0);
if(cbRead <= 0x2000) { goto cleanup; }
// load both 32/64 bit ntHeader (only one will be valid)
- if(!(ntHeader64 = VmmProcWindows_GetVerifyHeaderPE(pProcess, pModule->BaseAddress, pbModuleHeader, &fHdr32))) { goto cleanup; }
+ if(!(ntHeader64 = VmmWin_GetVerifyHeaderPE(pProcess, pModule->BaseAddress, pbModuleHeader, &fHdr32))) { goto cleanup; }
ntHeader32 = (PIMAGE_NT_HEADERS32)ntHeader64;
oImportDirectory = fHdr32 ?
ntHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress :
@@ -241,78 +246,23 @@ cleanup:
LocalFree(pbModule);
}
-WORD VmmProcWindows_PE_GetNumberOfSection(_In_ PVMM_PROCESS pProcess, _Inout_ PVMM_MODULEMAP_ENTRY pModule, _In_opt_ PIMAGE_NT_HEADERS pbModuleHeaderOpt, _In_opt_ BOOL fHdr32)
+VOID VmmWin_PE_SetSizeSectionIATEAT_DisplayBuffer(_In_ PVMM_PROCESS pProcess, _Inout_ PVMM_MODULEMAP_ENTRY pModule)
{
- BYTE pbModuleHeader[0x1000];
- PIMAGE_NT_HEADERS64 pNtHeader64;
- PIMAGE_NT_HEADERS32 pNtHeader32;
- // load both 32/64 bit ntHeader unless already supplied in parameter (only one of 32/64 bit hdr will be valid)
- if(!(pNtHeader64 = pbModuleHeaderOpt ? pbModuleHeaderOpt : VmmProcWindows_GetVerifyHeaderPE(pProcess, pModule->BaseAddress, pbModuleHeader, &fHdr32))) { return 0; }
- pNtHeader32 = (PIMAGE_NT_HEADERS32)pNtHeader64;
- // retrieve number of sections
- return fHdr32 ? pNtHeader32->FileHeader.NumberOfSections : pNtHeader64->FileHeader.NumberOfSections;
-}
-
-DWORD VmmProcWindows_PE_GetNumberOfIAT(_In_ PVMM_PROCESS pProcess, _Inout_ PVMM_MODULEMAP_ENTRY pModule, _In_opt_ PIMAGE_NT_HEADERS pbModuleHeaderOpt, _In_opt_ BOOL fHdr32)
-{
- BYTE pbModuleHeader[0x1000];
- PIMAGE_NT_HEADERS64 pNtHeader64;
- PIMAGE_NT_HEADERS32 pNtHeader32;
- DWORD cbImportDirectory, cbImportAddressTable, cIatEntries, cModules;
- // load both 32/64 bit ntHeader unless already supplied in parameter (only one of 32/64 bit hdr will be valid)
- if(!(pNtHeader64 = pbModuleHeaderOpt ? pbModuleHeaderOpt : VmmProcWindows_GetVerifyHeaderPE(pProcess, pModule->BaseAddress, pbModuleHeader, &fHdr32))) { return 0; }
- pNtHeader32 = (PIMAGE_NT_HEADERS32)pNtHeader64;
- // Calculate the number of functions in the import address table (IAT).
- // Number of functions = # IAT entries - # Imported modules
- cbImportDirectory = fHdr32 ?
- pNtHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size :
- pNtHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
- cbImportAddressTable = fHdr32 ?
- pNtHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size :
- pNtHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size;
- cIatEntries = cbImportAddressTable / (fHdr32 ? sizeof(DWORD) : sizeof(QWORD));
- cModules = cbImportDirectory / sizeof(IMAGE_IMPORT_DESCRIPTOR);
- return cIatEntries - cModules;
-}
-
-DWORD VmmProcWindows_PE_GetNumberOfEAT(_In_ PVMM_PROCESS pProcess, _Inout_ PVMM_MODULEMAP_ENTRY pModule, _In_opt_ PIMAGE_NT_HEADERS pbModuleHeaderOpt, _In_opt_ BOOL fHdr32)
-{
- BYTE pbModuleHeader[0x1000];
- PIMAGE_NT_HEADERS64 pNtHeader64;
- PIMAGE_NT_HEADERS32 pNtHeader32;
- 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)
- if(!(pNtHeader64 = pbModuleHeaderOpt ? pbModuleHeaderOpt : VmmProcWindows_GetVerifyHeaderPE(pProcess, pModule->BaseAddress, pbModuleHeader, &fHdr32))) { return 0; }
- pNtHeader32 = (PIMAGE_NT_HEADERS32)pNtHeader64;
- // Calculate the number of functions in the export address table (EAT).
- va = fHdr32 ?
- pNtHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress :
- pNtHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
- vaExportDirectory = va ? pModule->BaseAddress + va : 0;
- if(vaExportDirectory && VmmRead(pProcess, vaExportDirectory, (PBYTE)&hdrExportDirectory, sizeof(IMAGE_EXPORT_DIRECTORY)) && (hdrExportDirectory.NumberOfNames < 0x00010000)) {
- return hdrExportDirectory.NumberOfNames;
- }
- return 0;
-}
-
-VOID VmmProcWindows_PE_SetSizeSectionIATEAT_DisplayBuffer(_In_ PVMM_PROCESS pProcess, _Inout_ PVMM_MODULEMAP_ENTRY pModule)
-{
- BYTE pbModuleHeader[0x1000];
+ BYTE pbModuleHeader[0x1000] = { 0 };
PIMAGE_NT_HEADERS64 pNtHeaders64;
BOOL fHdr32;
// check if function is required
if(pModule->fLoadedEAT && pModule->fLoadedIAT) { return; }
// load both 32/64 bit ntHeader (only one will be valid)
- if(!(pNtHeaders64 = VmmProcWindows_GetVerifyHeaderPE(pProcess, pModule->BaseAddress, pbModuleHeader, &fHdr32))) { return; }
+ if(!(pNtHeaders64 = VmmWin_GetVerifyHeaderPE(pProcess, pModule->BaseAddress, pbModuleHeader, &fHdr32))) { return; }
// calculate display buffer size of: SECTIONS, EAT, IAT
- pModule->cbDisplayBufferSections = VmmProcWindows_PE_GetNumberOfSection(pProcess, pModule, pNtHeaders64, fHdr32) * 52; // each display buffer human readable line == 52 bytes.
+ pModule->cbDisplayBufferSections = PE_SectionGetNumberOfEx(pProcess, pModule->BaseAddress, pbModuleHeader) * 52; // each display buffer human readable line == 52 bytes.
if(!pModule->fLoadedEAT) {
- pModule->cbDisplayBufferEAT = VmmProcWindows_PE_GetNumberOfEAT(pProcess, pModule, pNtHeaders64, fHdr32) * 64; // each display buffer human readable line == 64 bytes.
+ pModule->cbDisplayBufferEAT = PE_EatGetNumberOfEx(pProcess, pModule->BaseAddress, pbModuleHeader) * 64; // each display buffer human readable line == 64 bytes.
pModule->fLoadedEAT = TRUE;
}
if(!pModule->fLoadedIAT) {
- pModule->cbDisplayBufferIAT = VmmProcWindows_PE_GetNumberOfIAT(pProcess, pModule, pNtHeaders64, fHdr32) * 128; // each display buffer human readable line == 128 bytes.
+ pModule->cbDisplayBufferIAT = PE_IatGetNumberOfEx(pProcess, pModule->BaseAddress, pbModuleHeader) * 128; // each display buffer human readable line == 128 bytes.
pModule->fLoadedIAT = TRUE;
}
}
@@ -339,11 +289,9 @@ typedef struct _VMMPROC_LDR_DATA_TABLE_ENTRY {
ULONG TimeDateStamp;
} VMMPROC_LDR_DATA_TABLE_ENTRY, *PVMMPROC_LDR_DATA_TABLE_ENTRY;
-QWORD VmmProcWindows_GetProcAddress(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModule, _In_ LPSTR lpProcName);
-
-VOID VmmProcWindows_ScanLdrModules64(_In_ PVMM_PROCESS pProcess, _Inout_ PVMM_MODULEMAP_ENTRY pModules, _Inout_ PDWORD pcModules, _In_ DWORD cModulesMax, _Out_ PBOOL fWow64)
+VOID VmmWin_ScanLdrModules64(_In_ PVMM_PROCESS pProcess, _Inout_ PVMM_MODULEMAP_ENTRY pModules, _Inout_ PDWORD pcModules, _In_ DWORD cModulesMax, _Out_ PBOOL fWow64)
{
- QWORD vaPsLoadedModuleList, vaModuleLdrFirst, vaModuleLdr = 0;
+ QWORD vaModuleLdrFirst, vaModuleLdr = 0;
BYTE pbPEB[sizeof(PEB)], pbPEBLdrData[sizeof(PEB_LDR_DATA)], pbLdrModule[sizeof(VMMPROC_LDR_DATA_TABLE_ENTRY)];
PPEB pPEB = (PPEB)pbPEB;
PPEB_LDR_DATA pPEBLdrData = (PPEB_LDR_DATA)pbPEBLdrData;
@@ -358,11 +306,18 @@ VOID VmmProcWindows_ScanLdrModules64(_In_ PVMM_PROCESS pProcess, _Inout_ PVMM_MO
vaModuleLdr = vaModuleLdrFirst = (QWORD)pPEBLdrData->InMemoryOrderModuleList.Flink - 0x10; // InLoadOrderModuleList == InMemoryOrderModuleList - 0x10
} else {
// Kernel mode process -> walk PsLoadedModuleList to enumerate drivers / .sys and .dlls.
- vaPsLoadedModuleList = VmmProcWindows_GetProcAddress(pProcess, ctxVmm->kernelinfo.vaBase, "PsLoadedModuleList");
- if(!vaPsLoadedModuleList) { return; }
- if(!VmmRead(pProcess, vaPsLoadedModuleList, (PBYTE)&vaModuleLdrFirst, sizeof(QWORD)) || !vaModuleLdrFirst) { return; }
- if(!VmmRead(pProcess, vaPsLoadedModuleList, pbPEBLdrData, sizeof(PEB_LDR_DATA))) { return; }
+ if(!ctxVmm->kernel.vaPsLoadedModuleList) { return; }
+ if(!VmmRead(pProcess, ctxVmm->kernel.vaPsLoadedModuleList, (PBYTE)&vaModuleLdrFirst, sizeof(QWORD)) || !vaModuleLdrFirst) { return; }
+ if(!VmmRead(pProcess, ctxVmm->kernel.vaPsLoadedModuleList, pbPEBLdrData, sizeof(PEB_LDR_DATA))) { return; }
vaModuleLdr = vaModuleLdrFirst;
+ // If vaPsLoadedModuleList was applied from KDBG (pre-win10) 'ntoskrnl.exe' pointer will
+ // go to 2nd entry in list and 'ntoskrnl.exe' will be missed unless Blink is followed first.
+ if(ctxVmm->kernel.vaKDBG) {
+ if(!VmmRead(pProcess, vaModuleLdr, pbLdrModule, sizeof(VMMPROC_LDR_DATA_TABLE_ENTRY))) { return; }
+ if((ctxVmm->kernel.vaBase != (QWORD)pLdrModule->BaseAddress) && (QWORD)pLdrModule->InLoadOrderModuleList.Blink) {
+ vaModuleLdrFirst = vaModuleLdr = (QWORD)pLdrModule->InLoadOrderModuleList.Blink;
+ }
+ }
}
do {
if(!VmmRead(pProcess, vaModuleLdr, pbLdrModule, sizeof(VMMPROC_LDR_DATA_TABLE_ENTRY))) { break; }
@@ -374,7 +329,7 @@ VOID VmmProcWindows_ScanLdrModules64(_In_ PVMM_PROCESS pProcess, _Inout_ PVMM_MO
if(!pLdrModule->BaseDllName.Length) { break; }
if(!VmmReadString_Unicode2Ansi(pProcess, (QWORD)pLdrModule->BaseDllName.Buffer, pModule->szName, min(31, pLdrModule->BaseDllName.Length))) { break; }
*fWow64 = pProcess->fUserOnly && (*fWow64 || !memcmp(pModule->szName, "wow64.dll", 10));
- vmmprintfvv("vmmproc.c!VmmProcWindows_ScanLdrModules: %016llx %016llx %016llx %08x %i %s\n", vaModuleLdr, pModule->BaseAddress, pModule->EntryPoint, pModule->SizeOfImage, (pModule->fWoW64 ? 1 : 0), pModule->szName);
+ vmmprintfvv("vmmwin.c!VmmWin_ScanLdrModules: %016llx %016llx %016llx %08x %i %s\n", vaModuleLdr, pModule->BaseAddress, pModule->EntryPoint, pModule->SizeOfImage, (pModule->fWoW64 ? 1 : 0), pModule->szName);
vaModuleLdr = (QWORD)pLdrModule->InLoadOrderModuleList.Flink;
*pcModules = *pcModules + 1;
} while((vaModuleLdr != vaModuleLdrFirst) && (*pcModules < cModulesMax));
@@ -418,7 +373,7 @@ typedef struct _PEB32 {
} PEB32, *PPEB32;
_Success_(return)
-BOOL VmmProcWindows_ScanLdrModules32(_In_ PVMM_PROCESS pProcess, _Inout_ PVMM_MODULEMAP_ENTRY pModules, _Inout_ PDWORD pcModules, _In_ DWORD cModulesMax)
+BOOL VmmWin_ScanLdrModules32(_In_ PVMM_PROCESS pProcess, _Inout_ PVMM_MODULEMAP_ENTRY pModules, _Inout_ PDWORD pcModules, _In_ DWORD cModulesMax)
{
DWORD vaModuleLdrFirst32, vaModuleLdr32 = 0;
BYTE pbPEB32[sizeof(PEB32)], pbPEBLdrData32[sizeof(PEB_LDR_DATA32)], pbLdrModule32[sizeof(LDR_MODULE32)];
@@ -426,10 +381,28 @@ BOOL VmmProcWindows_ScanLdrModules32(_In_ PVMM_PROCESS pProcess, _Inout_ PVMM_MO
PPEB_LDR_DATA32 pPEBLdrData32 = (PPEB_LDR_DATA32)pbPEBLdrData32;
PLDR_MODULE32 pLdrModule32 = (PLDR_MODULE32)pbLdrModule32;
PVMM_MODULEMAP_ENTRY pModule;
- if(!pProcess->os.win.vaPEB) { return FALSE; }
- if(!VmmRead(pProcess, pProcess->os.win.vaPEB32, pbPEB32, sizeof(PEB32))) { return FALSE; }
- if(!VmmRead(pProcess, (DWORD)pPEB32->Ldr, pbPEBLdrData32, sizeof(PEB_LDR_DATA32))) { return FALSE; }
- vaModuleLdr32 = vaModuleLdrFirst32 = (DWORD)pPEBLdrData32->InMemoryOrderModuleList.Flink - 0x08; // InLoadOrderModuleList == InMemoryOrderModuleList - 0x08
+ if(pProcess->fUserOnly) {
+ if(!pProcess->os.win.vaPEB) { return FALSE; }
+ if(!VmmRead(pProcess, pProcess->os.win.vaPEB32, pbPEB32, sizeof(PEB32))) { return FALSE; }
+ if(!VmmRead(pProcess, (DWORD)pPEB32->Ldr, pbPEBLdrData32, sizeof(PEB_LDR_DATA32))) { return FALSE; }
+ vaModuleLdr32 = vaModuleLdrFirst32 = (DWORD)pPEBLdrData32->InMemoryOrderModuleList.Flink - 0x08; // InLoadOrderModuleList == InMemoryOrderModuleList - 0x08
+ } else if(ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X86) {
+ // Kernel mode process -> walk PsLoadedModuleList to enumerate drivers / .sys and .dlls.
+ if(!ctxVmm->kernel.vaPsLoadedModuleList) { return FALSE; }
+ if(!VmmRead(pProcess, ctxVmm->kernel.vaPsLoadedModuleList, (PBYTE)&vaModuleLdrFirst32, sizeof(DWORD)) || !vaModuleLdrFirst32) { return FALSE; }
+ if(!VmmRead(pProcess, ctxVmm->kernel.vaPsLoadedModuleList, pbPEBLdrData32, sizeof(PEB_LDR_DATA32))) { return FALSE; }
+ vaModuleLdr32 = vaModuleLdrFirst32;
+ // If vaPsLoadedModuleList was applied from KDBG (pre-win10) 'ntoskrnl.exe' pointer will
+ // go to 2nd entry in list and 'ntoskrnl.exe' will be missed unless Blink is followed first.
+ if(ctxVmm->kernel.vaKDBG) {
+ if(!VmmRead(pProcess, vaModuleLdr32, pbLdrModule32, sizeof(LDR_MODULE32))) { return FALSE; }
+ if((ctxVmm->kernel.vaBase != (DWORD)pLdrModule32->BaseAddress) && (DWORD)pLdrModule32->InLoadOrderModuleList.Blink) {
+ vaModuleLdrFirst32 = vaModuleLdr32 = (DWORD)pLdrModule32->InLoadOrderModuleList.Blink;
+ }
+ }
+ } else {
+ return FALSE;
+ }
do {
if(!VmmRead(pProcess, vaModuleLdr32, pbLdrModule32, sizeof(LDR_MODULE32))) { break; }
pModule = pModules + *pcModules;
@@ -439,19 +412,21 @@ BOOL VmmProcWindows_ScanLdrModules32(_In_ PVMM_PROCESS pProcess, _Inout_ PVMM_MO
pModule->fWoW64 = TRUE;
if(!pLdrModule32->BaseDllName.Length) { break; }
if(!VmmReadString_Unicode2Ansi(pProcess, (QWORD)pLdrModule32->BaseDllName.Buffer, pModule->szName, min(31, pLdrModule32->BaseDllName.Length))) { break; }
- vmmprintfvv("vmmproc.c!VmmProcWindows_ScanLdrModules32: %08x %08x %08x %08x %s\n", vaModuleLdr32, (DWORD)pModule->BaseAddress, (DWORD)pModule->EntryPoint, pModule->SizeOfImage, pModule->szName);
+ vmmprintfvv("vmmwin.c!VmmWin_ScanLdrModules32: %08x %08x %08x %08x %s\n", vaModuleLdr32, (DWORD)pModule->BaseAddress, (DWORD)pModule->EntryPoint, pModule->SizeOfImage, pModule->szName);
vaModuleLdr32 = (QWORD)pLdrModule32->InLoadOrderModuleList.Flink;
*pcModules = *pcModules + 1;
} while((vaModuleLdr32 != vaModuleLdrFirst32) && (*pcModules < cModulesMax));
return TRUE;
}
-VOID VmmProcWindows_InitializeLdrModules(_In_ PVMM_PROCESS pProcess)
+#define VMMPROCWINDOWS_MAX_MODULES 512
+
+VOID VmmWin_InitializeLdrModules(_In_ PVMM_PROCESS pProcess)
{
PVMM_MODULEMAP_ENTRY pModules, pModule;
PBYTE pbResult;
DWORD i, o, cModules;
- BOOL result, fWow64;
+ BOOL result, fWow64 = FALSE;
// clear out any previous data
LocalFree(pProcess->os.win.pbLdrModulesDisplayCache);
pProcess->os.win.pbLdrModulesDisplayCache = NULL;
@@ -461,47 +436,77 @@ VOID VmmProcWindows_InitializeLdrModules(_In_ PVMM_PROCESS pProcess)
pModules = (PVMM_MODULEMAP_ENTRY)LocalAlloc(LMEM_ZEROINIT, 512 * sizeof(VMM_MODULEMAP_ENTRY));
if(!pModules) { goto fail; }
cModules = 0;
- VmmProcWindows_ScanLdrModules64(pProcess, pModules, &cModules, 512, &fWow64);
- if((cModules > 0) && (!pModules[cModules - 1].BaseAddress)) { cModules--; }
- if(fWow64) {
- pProcess->os.win.vaPEB32 = (DWORD)pProcess->os.win.vaPEB - 0x1000;
- result = VmmProcWindows_ScanLdrModules32(pProcess, pModules, &cModules, 512);
- if(!result) {
- pProcess->os.win.vaPEB32 = (DWORD)pProcess->os.win.vaPEB + 0x1000;
- result = VmmProcWindows_ScanLdrModules32(pProcess, pModules, &cModules, 512);
+ if(ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X64) {
+ VmmWin_ScanLdrModules64(pProcess, pModules, &cModules, VMMPROCWINDOWS_MAX_MODULES, &fWow64);
+ if((cModules > 0) && (!pModules[cModules - 1].BaseAddress)) { cModules--; }
+ if(fWow64) {
+ pProcess->os.win.vaPEB32 = (DWORD)pProcess->os.win.vaPEB - 0x1000;
+ result = VmmWin_ScanLdrModules32(pProcess, pModules, &cModules, VMMPROCWINDOWS_MAX_MODULES);
+ if(!result) {
+ pProcess->os.win.vaPEB32 = (DWORD)pProcess->os.win.vaPEB + 0x1000;
+ result = VmmWin_ScanLdrModules32(pProcess, pModules, &cModules, VMMPROCWINDOWS_MAX_MODULES);
+ }
+ if(!result) {
+ pProcess->os.win.vaPEB32 = 0;
+ }
}
- if(!result) {
- pProcess->os.win.vaPEB32 = 0;
+ if((cModules > 0) && (!pModules[cModules - 1].BaseAddress)) { cModules--; }
+ if(!cModules) { goto fail; }
+ // generate display cache
+ pProcess->os.win.vaENTRY = pModules[0].EntryPoint;
+ pbResult = pProcess->os.win.pbLdrModulesDisplayCache = (PBYTE)LocalAlloc(LMEM_ZEROINIT, 89ULL * cModules);
+ if(!pbResult) { goto fail; }
+ for(i = 0, o = 0; i < cModules; i++) {
+ pModule = pModules + i;
+ if(!pModule->BaseAddress) { continue; }
+ o += snprintf(
+ pbResult + o,
+ 89,
+ "%04x %8x %016llx-%016llx %s %s\n",
+ i,
+ pModule->SizeOfImage >> 12,
+ pModule->BaseAddress,
+ pModule->BaseAddress + pModule->SizeOfImage - 1,
+ pModule->fWoW64 ? "32" : " ",
+ pModule->szName
+ );
}
+ pProcess->os.win.fWow64 = fWow64;
+ // update memory map with names
+ for(i = 0; i < cModules; i++) {
+ pModule = pModules + i;
+ VmmMapTag(pProcess, pModule->BaseAddress, pModule->BaseAddress + pModule->SizeOfImage, pModule->szName, NULL, FALSE);
+ }
+ pProcess->os.win.cbLdrModulesDisplayCache = o;
+ } else if(ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X86) {
+ pProcess->os.win.vaPEB32 = (DWORD)pProcess->os.win.vaPEB;
+ VmmWin_ScanLdrModules32(pProcess, pModules, &cModules, VMMPROCWINDOWS_MAX_MODULES);
+ if((cModules > 0) && (!pModules[cModules - 1].BaseAddress)) { cModules--; }
+ // generate display cache
+ pProcess->os.win.vaENTRY = pModules[0].EntryPoint;
+ pbResult = pProcess->os.win.pbLdrModulesDisplayCache = (PBYTE)LocalAlloc(LMEM_ZEROINIT, 70ULL * cModules);
+ if(!pbResult) { goto fail; }
+ for(i = 0, o = 0; i < cModules; i++) {
+ pModule = pModules + i;
+ if(!pModule->BaseAddress) { continue; }
+ o += snprintf(
+ pbResult + o,
+ 70,
+ "%04x %8x %08x-%08x %s\n",
+ i,
+ pModule->SizeOfImage >> 12,
+ (DWORD)pModule->BaseAddress,
+ (DWORD)(pModule->BaseAddress + pModule->SizeOfImage - 1),
+ pModule->szName
+ );
+ }
+ // update memory map with names
+ for(i = 0; i < cModules; i++) {
+ pModule = pModules + i;
+ VmmMapTag(pProcess, pModule->BaseAddress, pModule->BaseAddress + pModule->SizeOfImage, pModule->szName, NULL, FALSE);
+ }
+ pProcess->os.win.cbLdrModulesDisplayCache = o;
}
- if((cModules > 0) && (!pModules[cModules - 1].BaseAddress)) { cModules--; }
- if(!cModules) { goto fail; }
- // generate display cache
- pProcess->os.win.vaENTRY = pModules[0].EntryPoint;
- pbResult = pProcess->os.win.pbLdrModulesDisplayCache = (PBYTE)LocalAlloc(LMEM_ZEROINIT, 89 * cModules);
- if(!pbResult) { goto fail; }
- for(i = 0, o = 0; i < cModules; i++) {
- pModule = pModules + i;
- if(!pModule->BaseAddress) { continue; }
- o += snprintf(
- pbResult + o,
- 89,
- "%04x %8x %016llx-%016llx %s %s\n",
- i,
- pModule->SizeOfImage >> 12,
- pModule->BaseAddress,
- pModule->BaseAddress + pModule->SizeOfImage - 1,
- pModule->fWoW64 ? "32" : " ",
- pModule->szName
- );
- }
- pProcess->os.win.fWow64 = fWow64;
- // update memory map with names
- for(i = 0; i < cModules; i++) {
- pModule = pModules + i;
- VmmMapTag(pProcess, pModule->BaseAddress, pModule->BaseAddress + pModule->SizeOfImage, pModule->szName, NULL, pModule->fWoW64);
- }
- pProcess->os.win.cbLdrModulesDisplayCache = o;
// copy modules map into Process struct
pProcess->pModuleMap = (PVMM_MODULEMAP_ENTRY)LocalAlloc(0, cModules * sizeof(VMM_MODULEMAP_ENTRY));
if(!pProcess->pModuleMap) { goto fail; }
@@ -515,163 +520,11 @@ fail:
// WINDOWS SPECIFIC PROCESS RELATED FUNCTIONALITY BELOW:
// ----------------------------------------------------------------------------
-/*
-* 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 16MB
-* will be scanned back.
-*/
-QWORD VmmProcWindows_FindNtoskrnl(_In_ PVMM_PROCESS pSystemProcess, _In_ QWORD vaKernelEntry)
-{
- PBYTE pb;
- QWORD vaBase, oPage, o, vaNtosBase = 0;
- BOOL fINITKDBG, fPOOLCODE;
- DWORD cbRead;
- pb = LocalAlloc(0, 0x200000);
- if(!pb) { goto cleanup; }
- // Scan back in 2MB chunks a time, (ntoskrnl.exe is loaded in 2MB pages).
- for(vaBase = vaKernelEntry & ~0x1fffff; vaBase + 0x02000000 > vaKernelEntry; 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(oPage = 0; oPage < 0x200000; oPage += 0x1000) {
- if(*(PWORD)(pb + oPage) == 0x5a4d) { // MZ header
- fINITKDBG = FALSE;
- fPOOLCODE = FALSE;
- for(o = 0; o < 0x1000; o += 8) {
- if(*(PQWORD)(pb + oPage + o) == 0x4742444B54494E49) { // INITKDBG
- fINITKDBG = TRUE;
- }
- if(*(PQWORD)(pb + oPage + o) == 0x45444F434C4F4F50) { // POOLCODE
- fPOOLCODE = TRUE;
- }
- if(fINITKDBG && fPOOLCODE) {
- vaNtosBase = vaBase + oPage;
- goto cleanup;
- }
- }
- }
- }
- }
-cleanup:
- LocalFree(pb);
- return vaNtosBase;
-}
-
-/*
-* Perform GetProcAddress given a PE header.
-* NB! very messy code due to lots of sanity checks on untrusted data.
-*/
-QWORD VmmProcWindows_GetProcAddress(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModule, _In_ LPSTR lpProcName)
-{
- BYTE pbModuleHeader[0x1000];
- 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 fHdr32;
- if(!(ntHeader64 = VmmProcWindows_GetVerifyHeaderPE(pProcess, vaModule, pbModuleHeader, &fHdr32))) { goto cleanup; }
- if(fHdr32) { // 32-bit PE
- ntHeader32 = (PIMAGE_NT_HEADERS32)ntHeader64;
- vaExportDirectory = vaModule + ntHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
- cbExportDirectory = ntHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
- } else { // 64-bit PE
- vaExportDirectory = vaModule + 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 == vaModule) || (vaExportDirectory > vaModule + 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 = vaModule + exp->AddressOfNames;
- vaNameOrdinals = vaModule + exp->AddressOfNameOrdinals;
- vaRVAAddrFunctions = vaModule + 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 - vaModule);
- 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)(vaModule + pdwRVAAddrFunctions[pwNameOrdinals[i]]);
- LocalFree(pbExportDirectory);
- return vaFnPtr;
- }
- }
-cleanup:
- LocalFree(pbExportDirectory);
- return 0;
-}
-
-/*
-* Retrieve PE module name given a PE header.
-* Function handles both 64-bit and 32-bit PE images.
-* NB! very messy code due to lots of sanity checks on untrusted data.
-*/
-_Success_(return)
-BOOL VmmProcWindows_GetModuleName(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModule, _Out_ CHAR pbModuleName[MAX_PATH], _Out_ PDWORD pdwSize, _In_opt_ PBYTE pbPageMZHeaderPreCacheOpt, _In_ BOOL fDummyPENameOnExportDirectoryFail)
-{
- PIMAGE_NT_HEADERS64 ntHeader64;
- PIMAGE_NT_HEADERS32 ntHeader32;
- PIMAGE_EXPORT_DIRECTORY exp;
- QWORD vaExportDirectory;
- DWORD cbImageSize, cbExportDirectory;
- BYTE pbModuleHeader[0x1000], pbExportDirectory[sizeof(IMAGE_EXPORT_DIRECTORY)];
- BOOL fHdr32;
- if(pbPageMZHeaderPreCacheOpt) {
- memcpy(pbModuleHeader, pbPageMZHeaderPreCacheOpt, 0x1000);
- ntHeader64 = VmmProcWindows_GetVerifyHeaderPE(pProcess, 0, pbModuleHeader, &fHdr32);
- } else {
- ntHeader64 = VmmProcWindows_GetVerifyHeaderPE(pProcess, vaModule, pbModuleHeader, &fHdr32);
- }
- if(!ntHeader64) { return FALSE; }
- if(!fHdr32) { // 64-bit PE
- *pdwSize = ntHeader64->OptionalHeader.SizeOfImage;
- vaExportDirectory = vaModule + 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)ntHeader64;
- *pdwSize = ntHeader32->OptionalHeader.SizeOfImage;
- vaExportDirectory = vaModule + 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 == vaModule) || (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; }
- pbModuleName[MAX_PATH - 1] = 0;
- if(!VmmRead(pProcess, vaModule + exp->Name, pbModuleName, MAX_PATH - 1)) { goto fail; }
- return TRUE;
-fail:
- if(fDummyPENameOnExportDirectoryFail) {
- memcpy(pbModuleName, "UNKNOWN", 8);
- return TRUE;
- }
- return FALSE;
-}
-
/*
* Load module proc names into memory map list if possible.
* NB! this function parallelize reads of MZ header candidates to speed things up.
*/
-VOID VmmProcWindows_ScanHeaderPE(_In_ PVMM_PROCESS pProcess)
+VOID VmmWin_ScanHeaderPE(_In_ PVMM_PROCESS pProcess)
{
typedef struct tdMAP {
MEM_IO_SCATTER_HEADER dma;
@@ -702,6 +555,7 @@ VOID VmmProcWindows_ScanHeaderPE(_In_ PVMM_PROCESS pProcess)
pMap = pMaps + cDMAs;
pMap->mme = pProcess->pMemMap + i;
pMap->dma.cbMax = 0x1000;
+ pMap->dma.version = MEM_IO_SCATTER_HEADER_VERSION;
pMap->dma.qwA = pProcess->pMemMap[i].AddrBase;
pMap->dma.pb = pMap->pb;
ppDMAs[cDMAs] = &pMap->dma;
@@ -714,7 +568,7 @@ VOID VmmProcWindows_ScanHeaderPE(_In_ PVMM_PROCESS pProcess)
for(i = 0; i < cDMAs; i++) {
if(pMaps[i].dma.cb == 0x1000) {
pMap = pMaps + i;
- result = VmmProcWindows_GetModuleName(pProcess, pMap->mme->AddrBase, szBuffer, &cbImageSize, pMap->pb, TRUE);
+ result = PE_GetModuleNameEx(pProcess, pMap->mme->AddrBase, TRUE, pMap->pb, szBuffer, &cbImageSize);
if(result && (cbImageSize < 0x01000000)) {
VmmMapTag(pProcess, pMap->mme->AddrBase, pMap->mme->AddrBase + cbImageSize, szBuffer, NULL, FALSE);
}
@@ -723,32 +577,37 @@ VOID VmmProcWindows_ScanHeaderPE(_In_ PVMM_PROCESS pProcess)
LocalFree(pbBuffer);
}
+// ----------------------------------------------------------------------------
+// WINDOWS EPROCESS WALKING FUNCTIONALITY FOR 64/32 BIT BELOW:
+// ----------------------------------------------------------------------------
+
#define VMMPROC_EPROCESS_MAX_SIZE 0x500
/*
* Very ugly hack that tries to locate some offsets required withn the EPROCESS struct.
*/
_Success_(return)
-BOOL VmmProcWindows_OffsetLocatorEPROCESS(_In_ PVMM_PROCESS pSystemProcess,
- _Out_ PDWORD pdwoState, _Out_ PDWORD pdwoPML4, _Out_ PDWORD pdwoName, _Out_ PDWORD pdwoPID,
- _Out_ PDWORD pdwoFLink, _Out_ PDWORD pdwoPEB, _Out_ PDWORD dwoPML4_User)
+BOOL VmmWin_OffsetLocatorEPROCESS64(_In_ PVMM_PROCESS pSystemProcess,
+ _Out_ PDWORD pdwoState, _Out_ PDWORD pdwoDTB, _Out_ PDWORD pdwoName, _Out_ PDWORD pdwoPID,
+ _Out_ PDWORD pdwoFLink, _Out_ PDWORD pdwoPEB, _Out_ PDWORD dwoDTB_User)
{
BOOL f;
DWORD i;
QWORD va1, vaPEB, paPEB;
- BYTE pb0[VMMPROC_EPROCESS_MAX_SIZE], pb1[VMMPROC_EPROCESS_MAX_SIZE], pbPage[0x1000], pbZero[0x800];
- QWORD paMax, paPML4_0, paPML4_1;
- if(!VmmRead(pSystemProcess, pSystemProcess->os.win.vaEPROCESS, pb0, 0x500)) { return FALSE; }
+ BYTE pb0[VMMPROC_EPROCESS_MAX_SIZE], pb1[VMMPROC_EPROCESS_MAX_SIZE], pbPage[0x1000];
+ BYTE pbZero[0x800];
+ QWORD paMax, paDTB_0, paDTB_1;
+ if(!VmmRead(pSystemProcess, pSystemProcess->os.win.vaEPROCESS, pb0, VMMPROC_EPROCESS_MAX_SIZE)) { return FALSE; }
if(ctxMain->cfg.fVerboseExtra) {
- vmmprintf("vmmproc.c!VmmProcWindows_OffsetLocatorEPROCESS: %016llx %016llx\n", pSystemProcess->paPML4, pSystemProcess->os.win.vaEPROCESS);
+ vmmprintf("vmmwin.c!OffsetLocatorEPROCESS64: %016llx %016llx\n", pSystemProcess->paDTB, pSystemProcess->os.win.vaEPROCESS);
Util_PrintHexAscii(pb0, VMMPROC_EPROCESS_MAX_SIZE, 0);
}
// find offset State (static for now)
if(*(PDWORD)(pb0 + 0x04)) { return FALSE; }
*pdwoState = 0x04;
// find offset PML4 (static for now)
- if(pSystemProcess->paPML4 != (0xfffffffffffff000 & *(PQWORD)(pb0 + 0x28))) { return FALSE; }
- *pdwoPML4 = 0x28;
+ if(pSystemProcess->paDTB != (0xfffffffffffff000 & *(PQWORD)(pb0 + 0x28))) { return FALSE; }
+ *pdwoDTB = 0x28;
// find offset for Name
for(i = 0, f = FALSE; i < VMMPROC_EPROCESS_MAX_SIZE - 8; i += 8) {
if(*(PQWORD)(pb0 + i) == 0x00006D6574737953) {
@@ -767,9 +626,9 @@ BOOL VmmProcWindows_OffsetLocatorEPROCESS(_In_ PVMM_PROCESS pSystemProcess,
f = VmmRead(pSystemProcess, va1, pb1, VMMPROC_EPROCESS_MAX_SIZE);
if(!f) { continue; }
f = FALSE;
- if((*(PQWORD)(pb1 + *pdwoName) != 0x6578652e73736d73) && // smss.exe
- (*(PQWORD)(pb1 + *pdwoName) != 0x7972747369676552) && // Registry
- (*(PQWORD)(pb1 + *pdwoName) != 0x5320657275636553)) // Secure System
+ if((*(PQWORD)(pb1 + *pdwoName) != 0x6578652e73736d73) && // smss.exe
+ (*(PQWORD)(pb1 + *pdwoName) != 0x7972747369676552) && // Registry
+ (*(PQWORD)(pb1 + *pdwoName) != 0x5320657275636553)) // Secure System
{
continue;
}
@@ -784,8 +643,8 @@ BOOL VmmProcWindows_OffsetLocatorEPROCESS(_In_ PVMM_PROCESS pSystemProcess,
}
if(!f) { return FALSE; }
// skip over "processes" without PEB
- while((*(PQWORD)(pb1 + *pdwoName) == 0x5320657275636553) || // Secure System
- (*(PQWORD)(pb1 + *pdwoName) == 0x7972747369676552)) // Registry
+ while((*(PQWORD)(pb1 + *pdwoName) == 0x5320657275636553) || // Secure System
+ (*(PQWORD)(pb1 + *pdwoName) == 0x7972747369676552)) // Registry
{
va1 = *(PQWORD)(pb1 + *pdwoFLink) - *pdwoFLink;
f = VmmRead(pSystemProcess, va1, pb1, VMMPROC_EPROCESS_MAX_SIZE);
@@ -799,10 +658,9 @@ BOOL VmmProcWindows_OffsetLocatorEPROCESS(_In_ PVMM_PROCESS pSystemProcess,
for(i = 0x300, f = FALSE; i < 0x480; i += 8) {
if(*(PQWORD)(pb0 + i)) { continue; }
vaPEB = *(PQWORD)(pb1 + i);
- if(!vaPEB || (*(PQWORD)(pb1 + i) & 0xffff800000000fff)) { continue; }
+ if(!vaPEB || (vaPEB & 0xffff800000000fff)) { continue; }
// Verify potential PEB
- if(!VmmReadPhysicalPage(*(PQWORD)(pb1 + *pdwoPML4), pbPage)) { continue; }
- if(!VmmVirt2PhysEx(TRUE, vaPEB, -1, pbPage, &paPEB)) { continue; }
+ if(!VmmVirt2PhysEx(*(PQWORD)(pb1 + *pdwoDTB), TRUE, vaPEB, &paPEB)) { continue; }
if(!VmmReadPhysicalPage(paPEB, pbPage)) { continue; }
if(*(PWORD)pbPage == 0x5a4d) { continue; } // MZ header -> likely entry point or something not PEB ...
*pdwoPEB = i;
@@ -813,24 +671,25 @@ BOOL VmmProcWindows_OffsetLocatorEPROCESS(_In_ PVMM_PROCESS pSystemProcess,
// find "optional" offset for user cr3/pml4 (post meltdown only)
// System have an entry pointing to a shadow PML4 which has empty user part
// smss.exe do not have an entry since it's running as admin ...
- *dwoPML4_User = 0;
+ *dwoDTB_User = 0;
ZeroMemory(pbZero, 0x800);
paMax = ctxMain->cfg.paAddrMax;
- for(i = *pdwoPML4 + 8; i < VMMPROC_EPROCESS_MAX_SIZE - 8; i += 8) {
- paPML4_0 = *(PQWORD)(pb0 + i); // EPROCESS entry item of System
- paPML4_1 = *(PQWORD)(pb1 + i); // EPROCESS entry item of smss.exe
- f = (paPML4_1 != 0);
- f = f || (paPML4_0 == 0);
- f = f || (paPML4_0 & 0xfff);
- f = f || (paPML4_0 >= paMax);
- f = f || !VmmReadPhysicalPage(paPML4_0, pbPage);
+ for(i = *pdwoDTB + 8; i < VMMPROC_EPROCESS_MAX_SIZE - 8; i += 8) {
+ paDTB_0 = *(PQWORD)(pb0 + i); // EPROCESS entry item of System
+ paDTB_1 = *(PQWORD)(pb1 + i); // EPROCESS entry item of smss.exe
+ f = (paDTB_1 != 0);
+ f = f || (paDTB_0 == 0);
+ f = f || (paDTB_0 & 0xfff);
+ f = f || (paDTB_0 >= paMax);
+ f = f || !VmmReadPhysicalPage(paDTB_0, pbPage);
f = f || memcmp(pbPage, pbZero, 0x800);
- f = f || !VmmTlbPageTableVerify(pbPage, paPML4_0, TRUE);
+ f = f || !VmmTlbPageTableVerify(pbPage, paDTB_0, TRUE);
if(!f) {
- *dwoPML4_User = i;
+ *dwoDTB_User = i;
break;
}
}
+ vmmprintfvv("vmmwin.c!64_OffsetLocatorEPROCESS: PID: %x STATE: %x DTB: %x DTB_User: %x NAME: %x PEB: %x FLink: %x\n", *pdwoPID, *pdwoState, *pdwoDTB, *dwoDTB_User, *pdwoName, *pdwoPEB, *pdwoFLink);
return TRUE;
}
@@ -841,29 +700,31 @@ BOOL VmmProcWindows_OffsetLocatorEPROCESS(_In_ PVMM_PROCESS pSystemProcess,
* -- pSystemProcess
* -- return
*/
-BOOL VmmProcWindows_EnumerateEPROCESS(_In_ PVMM_PROCESS pSystemProcess)
+BOOL VmmWin_EnumerateEPROCESS64(_In_ PVMM_PROCESS pSystemProcess)
{
- DWORD dwoState, dwoPML4, dwoPML4_User, dwoName, dwoPID, dwoFLink, dwoPEB, dwoMax;
- PQWORD pqwPML4, pqwPML4_User, pqwFLink, pqwPEB;
+ DWORD dwoState, dwoDTB, dwoDTB_User, dwoName, dwoPID, dwoFLink, dwoPEB, dwoMax;
+ PQWORD pqwDTB, pqwDTB_User, pqwFLink, pqwPEB;
PDWORD pdwState, pdwPID;
LPSTR szName;
BYTE pb[VMMPROC_EPROCESS_MAX_SIZE];
BOOL result, fSystem, fKernel;
PVMM_PROCESS pVmmProcess;
- QWORD vaSystemEPROCESS, vaEPROCESS, cPID = 0;
+ QWORD vaSystemEPROCESS, vaEPROCESS, cPID = 0, cNewProcessCollision = 0;
+ BOOL fShowTerminated;
+ fShowTerminated = ctxVmm->flags & VMM_FLAG_PROCESS_SHOW_TERMINATED;
// retrieve offsets
vaSystemEPROCESS = pSystemProcess->os.win.vaEPROCESS;
- result = VmmProcWindows_OffsetLocatorEPROCESS(pSystemProcess, &dwoState, &dwoPML4, &dwoName, &dwoPID, &dwoFLink, &dwoPEB, &dwoPML4_User);
+ result = VmmWin_OffsetLocatorEPROCESS64(pSystemProcess, &dwoState, &dwoDTB, &dwoName, &dwoPID, &dwoFLink, &dwoPEB, &dwoDTB_User);
if(!result) {
vmmprintf("VmmProc: Unable to locate EPROCESS offsets.\n");
return FALSE;
}
- vmmprintfvv("vmmproc.c!VmmProcWindows_EnumerateEPROCESS: %016llx %016llx\n", pSystemProcess->paPML4, vaSystemEPROCESS);
- dwoMax = min(VMMPROC_EPROCESS_MAX_SIZE, 16 + max(max(dwoState, dwoPID), max(max(dwoPML4, dwoFLink), max(dwoName, dwoPEB))));
+ vmmprintfvv("vmmwin.c!EnumerateEPROCESS64: %016llx %016llx\n", pSystemProcess->paDTB, vaSystemEPROCESS);
+ dwoMax = min(VMMPROC_EPROCESS_MAX_SIZE, 16 + max(max(dwoState, dwoPID), max(max(dwoDTB, dwoFLink), max(dwoName, dwoPEB))));
pdwState = (PDWORD)(pb + dwoState);
pdwPID = (PDWORD)(pb + dwoPID);
- pqwPML4 = (PQWORD)(pb + dwoPML4);
- pqwPML4_User = (PQWORD)(pb + dwoPML4_User);
+ pqwDTB = (PQWORD)(pb + dwoDTB);
+ pqwDTB_User = (PQWORD)(pb + dwoDTB_User);
pqwFLink = (PQWORD)(pb + dwoFLink);
szName = (LPSTR)(pb + dwoName);
pqwPEB = (PQWORD)(pb + dwoPEB);
@@ -877,30 +738,36 @@ BOOL VmmProcWindows_EnumerateEPROCESS(_In_ PVMM_PROCESS pSystemProcess)
// NB! Windows/Dokany does not support full 64-bit sizes on files, hence
// the max value 0x0001000000000000 for kernel space. Top 16-bits (ffff)
// are sign extended anyway so this should be fine if user skips them.
- if(*pqwPML4 && *(PQWORD)szName) {
+ if(*pqwDTB && *(PQWORD)szName && (fShowTerminated || !*pdwState)) {
pVmmProcess = VmmProcessCreateEntry(
*pdwPID,
*pdwState,
- ~0xfff & *pqwPML4,
- dwoPML4_User ? (~0xfff & *pqwPML4_User) : 0,
+ ~0xfff & *pqwDTB,
+ dwoDTB_User ? (~0xfff & *pqwDTB_User) : 0,
szName,
!fKernel,
fSystem);
+ if(!pVmmProcess) {
+ vmmprintfv("VMM: WARNING: PID '%i' already exists.\n", *pdwPID);
+ if(++cNewProcessCollision >= 8) {
+ break;
+ }
+ }
} else {
pVmmProcess = NULL;
}
if(pVmmProcess) {
pVmmProcess->os.win.vaEPROCESS = vaEPROCESS;
pVmmProcess->os.win.vaPEB = *pqwPEB;
- vmmprintfvv("vmmproc.c!VmmProcWindows_EnumerateEPROCESS: %016llx %016llx %016llx %08x %s\n",
- pVmmProcess->paPML4,
+ vmmprintfvv("vmmwin.c!EnumerateEPROCESS64: %016llx %016llx %016llx %08x %s\n",
+ pVmmProcess->paDTB,
pVmmProcess->os.win.vaEPROCESS,
pVmmProcess->os.win.vaPEB,
pVmmProcess->dwPID,
pVmmProcess->szName);
} else {
szName[14] = 0; // in case of bad string data ...
- vmmprintfv("VMM: Skipping process due to parsing error.\n PML4: %016llx PID: %i STATE: %i EPROCESS: %016llx NAME: %s\n", ~0xfff & *pqwPML4, *pdwPID, *pdwState, vaEPROCESS, szName);
+ vmmprintfv("VMM: Skipping process - parse error or terminated state.\n PML4: %016llx PID: %i STATE: %i EPROCESS: %016llx NAME: %s\n", ~0xfff & *pqwDTB, *pdwPID, *pdwState, vaEPROCESS, szName);
}
vaEPROCESS = *pqwFLink - dwoFLink;
if(vaEPROCESS == vaSystemEPROCESS) {
@@ -909,7 +776,7 @@ BOOL VmmProcWindows_EnumerateEPROCESS(_In_ PVMM_PROCESS pSystemProcess)
if(!VmmRead(pSystemProcess, vaEPROCESS, pb, dwoMax)) {
break;
}
- if(*pqwPML4 & 0xffffff0000000000) {
+ if(*pqwDTB & 0xffffff0000000000) {
break;
}
if(0xffff000000000000 != (0xffff000000000003 & *pqwFLink)) {
@@ -920,101 +787,220 @@ BOOL VmmProcWindows_EnumerateEPROCESS(_In_ PVMM_PROCESS pSystemProcess)
return (cPID > 10);
}
-// ----------------------------------------------------------------------------
-// WINDOWS SPECIFIC IMAGE IDENTIFYING BELOW
-// ----------------------------------------------------------------------------
-
/*
-* 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 the PML4 and ntoskrnl.ese KernelEntry point are returned.
-* NB! KernelEntry != Kernel Base
+* Very ugly hack that tries to locate some offsets required withn the EPROCESS struct.
*/
_Success_(return)
-BOOL VmmProcWindows_FindValidateLowStub(_Out_ PQWORD ppaPML4, _Out_ PQWORD pvaKernelEntry)
+BOOL VmmWin_OffsetLocatorEPROCESS32(_In_ PVMM_PROCESS pSystemProcess,
+ _Out_ PDWORD pdwoState, _Out_ PDWORD pdwoDTB, _Out_ PDWORD pdwoName, _Out_ PDWORD pdwoPID,
+ _Out_ PDWORD pdwoFLink, _Out_ PDWORD pdwoPEB, _Out_ PDWORD dwoDTB_User)
{
- PBYTE pbLowStub;
- DWORD o;
- if(!(pbLowStub = LocalAlloc(LMEM_ZEROINIT, 0x100000))) { return FALSE; }
- DeviceReadMEMEx(0, pbLowStub, 0x100000, NULL);
- o = 0;
- while(o < 0x100000) {
- o += 0x1000;
- if(0x00000001000600E9 != (0xffffffffffff00ff & *(PQWORD)(pbLowStub + o + 0x000))) { continue; } // START BYTES
- if(0xfffff80000000000 != (0xfffff80000000000 & *(PQWORD)(pbLowStub + o + 0x070))) { continue; } // KERNEL ENTRY
- if(0xffffff0000000fff & *(PQWORD)(pbLowStub + o + 0x0a0)) { continue; } // PML4
- *ppaPML4 = *(PQWORD)(pbLowStub + o + 0x0a0);
- *pvaKernelEntry = *(PQWORD)(pbLowStub + o + 0x070);
- LocalFree(pbLowStub);
- return TRUE;
+ BOOL f;
+ DWORD i;
+ DWORD va1, vaPEB;
+ QWORD paPEB;
+ BYTE pb0[VMMPROC_EPROCESS_MAX_SIZE], pb1[VMMPROC_EPROCESS_MAX_SIZE], pbPage[0x1000];
+ //BYTE pbZero[0x800];
+ //QWORD paMax, paDTB_0, paDTB_1;
+ if(!VmmRead(pSystemProcess, pSystemProcess->os.win.vaEPROCESS, pb0, VMMPROC_EPROCESS_MAX_SIZE)) { return FALSE; }
+ if(ctxMain->cfg.fVerboseExtra) {
+ vmmprintf("vmmwin.c!32_OffsetLocatorEPROCESS: %016llx %016llx\n", pSystemProcess->paDTB, pSystemProcess->os.win.vaEPROCESS);
+ Util_PrintHexAscii(pb0, VMMPROC_EPROCESS_MAX_SIZE, 0);
}
- LocalFree(pbLowStub);
- return FALSE;
-}
-
-/*
-* Try initialize the VMM from scratch with new WINDOWS support.
-*/
-BOOL VmmProcWindows_TryInitialize(_In_opt_ QWORD paPML4Opt, _In_opt_ QWORD vaKernelBaseOpt)
-{
- BOOL result;
- PVMM_PROCESS pSystemProcess;
- QWORD paPML4, vaKernelEntry, vaKernelBase, vaPsInitialSystemProcess, vaSystemEPROCESS;
- // Fetch Directory Base (PML4) and Kernel Entry (if optional hints not supplied)
- if(!paPML4Opt || !vaKernelBaseOpt) {
- result = VmmProcWindows_FindValidateLowStub(&paPML4, &vaKernelEntry);
- if(!result) {
- vmmprintfv("VmmProc: Initialization Failed. Bad data #1.\n");
- return FALSE;
- }
- vaKernelBase = 0;
- } else {
- paPML4 = paPML4Opt;
- vaKernelBase = vaKernelBaseOpt; // not entry here, but at least inside kernel ...
- }
- // Spider PML4 to speed things up
- VmmTlbSpider(paPML4, FALSE);
- // Pre-initialize System PID (required by VMM)
- pSystemProcess = VmmProcessCreateEntry(4, 0, paPML4, 0, "System", FALSE, TRUE);
- VmmProcessCreateFinish();
- if(!pSystemProcess) {
- vmmprintfv("VmmProc: Initialization Failed. #4.\n");
- return FALSE;
- }
- // Locate Kernel Base (if required)
- if(!vaKernelBase) {
- vaKernelBase = VmmProcWindows_FindNtoskrnl(pSystemProcess, vaKernelEntry);
- if(!vaKernelBase) {
- vmmprintfv("VmmProc: Initialization Failed. Unable to locate kernel #5\n");
- vmmprintfvv("VmmProc: PML4: 0x%016llx PTR: %016llx\n", pSystemProcess->paPML4, vaKernelEntry);
- return FALSE;
+ // find offset State (static for now)
+ if(*(PDWORD)(pb0 + 0x04)) { return FALSE; }
+ *pdwoState = 0x04;
+ // find offset PML4 (static for now)
+ //if(pSystemProcess->paDTB != (0xfffff000 & *(PDWORD)(pb0 + 0x18))) { return FALSE; }
+ *pdwoDTB = 0x18;
+ // find offset for Name
+ for(i = 0, f = FALSE; i < VMMPROC_EPROCESS_MAX_SIZE - 4; i += 4) {
+ if(*(PQWORD)(pb0 + i) == 0x00006D6574737953) {
+ *pdwoName = i;
+ f = TRUE;
+ break;
}
}
- vmmprintfvv("VmmProc: INFO: Kernel Base located at %016llx.\n", vaKernelBase);
- // Locate System EPROCESS
- vaPsInitialSystemProcess = VmmProcWindows_GetProcAddress(pSystemProcess, vaKernelBase, "PsInitialSystemProcess");
- result = VmmRead(pSystemProcess, vaPsInitialSystemProcess, (PBYTE)&vaSystemEPROCESS, 8);
- if(!result) {
- vmmprintfv("VmmProc: Initialization Failed. Unable to locate EPROCESS. #6\n");
- return FALSE;
+ if(!f) { return FALSE; }
+ // find offset for PID, FLink, BLink (assumed to be following eachother)
+ for(i = 0, f = FALSE; i < VMMPROC_EPROCESS_MAX_SIZE - 4; i += 4) {
+ if(*(PDWORD)(pb0 + i) == 4) {
+ // PID = correct, this is a candidate
+ if(0x80000000 != (0x80000003 & *(PDWORD)(pb0 + i + 4))) { continue; } // FLink not valid kernel pointer
+ va1 = *(PDWORD)(pb0 + i + 4) - i - 4;
+ f = VmmRead(pSystemProcess, va1, pb1, VMMPROC_EPROCESS_MAX_SIZE);
+ if(!f) { continue; }
+ f = FALSE;
+ if((*(PQWORD)(pb1 + *pdwoName) != 0x6578652e73736d73) && // smss.exe
+ (*(PQWORD)(pb1 + *pdwoName) != 0x7972747369676552) && // Registry
+ (*(PQWORD)(pb1 + *pdwoName) != 0x5320657275636553)) // Secure System
+ {
+ continue;
+ }
+ if((*(PDWORD)(pb1 + i + 8) - i - 4) != pSystemProcess->os.win.vaEPROCESS) {
+ continue;
+ }
+ *pdwoPID = i;
+ *pdwoFLink = i + 4;
+ f = TRUE;
+ break;
+ }
}
- pSystemProcess->os.win.vaEPROCESS = vaSystemEPROCESS;
- vmmprintfvv("VmmProc: INFO: PsInitialSystemProcess located at %016llx.\n", vaPsInitialSystemProcess);
- vmmprintfvv("VmmProc: INFO: EPROCESS located at %016llx.\n", vaSystemEPROCESS);
- // Enumerate processes
- result = VmmProcWindows_EnumerateEPROCESS(pSystemProcess);
- if(!result) {
- vmmprintfv("VmmProc: Initialization Failed. Unable to walk EPROCESS. #7\n");
- return FALSE;
+ if(!f) { return FALSE; }
+ // skip over "processes" without PEB
+ while((*(PQWORD)(pb1 + *pdwoName) == 0x5320657275636553) || // Secure System
+ (*(PQWORD)(pb1 + *pdwoName) == 0x7972747369676552)) // Registry
+ {
+ va1 = *(PDWORD)(pb1 + *pdwoFLink) - *pdwoFLink;
+ f = VmmRead(pSystemProcess, va1, pb1, VMMPROC_EPROCESS_MAX_SIZE);
+ if(!f) { return FALSE; }
}
- ctxVmm->fTargetSystem = VMM_TARGET_WINDOWS_X64;
- ctxVmm->kernelinfo.vaBase = vaKernelBase;
- ctxVmm->kernelinfo.paDTB = paPML4;
+ if(ctxMain->cfg.fVerboseExtra) {
+ vmmprintf("---------------------------------------------------------------------------\n");
+ Util_PrintHexAscii(pb1, VMMPROC_EPROCESS_MAX_SIZE, 0);
+ }
+ // find offset for PEB (in EPROCESS)
+ for(i = 0x100, f = FALSE; i < 0x240; i += 4) {
+ if(*(PDWORD)(pb0 + i)) { continue; }
+ vaPEB = *(PDWORD)(pb1 + i);
+ if(!vaPEB || (vaPEB & 0x80000fff)) { continue; }
+ // Verify potential PEB
+ if(!VmmVirt2PhysEx(*(PDWORD)(pb1 + *pdwoDTB), TRUE, vaPEB, &paPEB)) { continue; }
+ if(!VmmReadPhysicalPage(paPEB, pbPage)) { continue; }
+ if(*(PWORD)pbPage == 0x5a4d) { continue; } // MZ header -> likely entry point or something not PEB ...
+ *pdwoPEB = i;
+ f = TRUE;
+ break;
+ }
+ if(!f) { return FALSE; }
+ // find "optional" offset for user cr3/pml4 (post meltdown only)
+ // System have an entry pointing to a shadow PML4 which has empty user part
+ // smss.exe do not have an entry since it's running as admin ...
+ *dwoDTB_User = 0;
+ /*
+ ZeroMemory(pbZero, 0x800);
+ paMax = ctxMain->cfg.paAddrMax;
+ for(i = *pdwoDTB + 4; i < VMMPROC_EPROCESS_MAX_SIZE - 4; i += 4) {
+ paDTB_0 = *(PDWORD)(pb0 + i); // EPROCESS entry item of System
+ paDTB_1 = *(PDWORD)(pb1 + i); // EPROCESS entry item of smss.exe
+ f = (paDTB_1 != 0);
+ f = f || (paDTB_0 == 0);
+ f = f || (paDTB_0 & 0x1f);
+ f = f || (paDTB_0 >= paMax);
+ f = f || !VmmReadPhysicalPage(paDTB_0, pbPage);
+ f = f || memcmp(pbPage, pbZero, 0x800);
+ f = f || !VmmTlbPageTableVerify(pbPage, paDTB_0, TRUE);
+ if(!f) {
+ *dwoDTB_User = i;
+ break;
+ }
+ }
+ */
+ vmmprintfvv("vmmwin.c!32_OffsetLocatorEPROCESS: PID: %x STATE: %x DTB: %x DTB_User: %x NAME: %x PEB: %x FLink: %x\n", *pdwoPID, *pdwoState, *pdwoDTB, *dwoDTB_User, *pdwoName, *pdwoPEB, *pdwoFLink);
return TRUE;
}
-VOID VmmProcWindows_InitializeModuleNames(_In_ PVMM_PROCESS pProcess)
+BOOL VmmWin_EnumerateEPROCESS32(_In_ PVMM_PROCESS pSystemProcess)
{
- VmmProcWindows_InitializeLdrModules(pProcess);
- VmmProcWindows_ScanHeaderPE(pProcess);
+ DWORD dwoState, dwoDTB, dwoDTB_User, dwoName, dwoPID, dwoFLink, dwoPEB, dwoMax;
+ PDWORD pdwDTB, pdwDTB_User, pdwFLink, pdwPEB;
+ PDWORD pdwState, pdwPID;
+ LPSTR szName;
+ BYTE pb[VMMPROC_EPROCESS_MAX_SIZE];
+ BOOL result, fSystem, fKernel;
+ PVMM_PROCESS pVmmProcess;
+ DWORD vaSystemEPROCESS, vaEPROCESS, cPID = 0, cNewProcessCollision = 0;
+ BOOL fShowTerminated;
+ fShowTerminated = ctxVmm->flags & VMM_FLAG_PROCESS_SHOW_TERMINATED;
+ // retrieve offsets
+ vaSystemEPROCESS = (DWORD)pSystemProcess->os.win.vaEPROCESS;
+ result = VmmWin_OffsetLocatorEPROCESS32(pSystemProcess, &dwoState, &dwoDTB, &dwoName, &dwoPID, &dwoFLink, &dwoPEB, &dwoDTB_User);
+ if(!result) {
+ vmmprintf("VmmProc: Unable to locate EPROCESS offsets.\n");
+ return FALSE;
+ }
+ vmmprintfvv("vmmwin.c!EnumerateEPROCESS32: %016llx %08x\n", pSystemProcess->paDTB, vaSystemEPROCESS);
+ dwoMax = min(VMMPROC_EPROCESS_MAX_SIZE, 16 + max(max(dwoState, dwoPID), max(max(dwoDTB, dwoFLink), max(dwoName, dwoPEB))));
+ pdwState = (PDWORD)(pb + dwoState);
+ pdwPID = (PDWORD)(pb + dwoPID);
+ pdwDTB = (PDWORD)(pb + dwoDTB);
+ pdwDTB_User = (PDWORD)(pb + dwoDTB_User);
+ pdwFLink = (PDWORD)(pb + dwoFLink);
+ szName = (LPSTR)(pb + dwoName);
+ pdwPEB = (PDWORD)(pb + dwoPEB);
+ // SCAN!
+ if(!VmmRead(pSystemProcess, vaSystemEPROCESS, pb, dwoMax)) { return FALSE; }
+ vaEPROCESS = vaSystemEPROCESS;
+ while(TRUE) {
+ cPID++;
+ fSystem = (*pdwPID == 4);
+ fKernel = fSystem || ((*pdwState == 0) && (*pdwPEB == 0));
+ // NB! Windows/Dokany does not support full 64-bit sizes on files, hence
+ // the max value 0x0001000000000000 for kernel space. Top 16-bits (ffff)
+ // are sign extended anyway so this should be fine if user skips them.
+ if(*pdwDTB && *(PQWORD)szName && (fShowTerminated || !*pdwState)) {
+ pVmmProcess = VmmProcessCreateEntry(
+ *pdwPID,
+ *pdwState,
+ *pdwDTB & 0xffffffe0,
+ dwoDTB_User ? (~0xfff & *pdwDTB_User) : 0,
+ szName,
+ !fKernel,
+ fSystem);
+ } else {
+ pVmmProcess = NULL;
+ }
+ if(pVmmProcess) {
+ pVmmProcess->os.win.vaEPROCESS = vaEPROCESS;
+ pVmmProcess->os.win.vaPEB = *pdwPEB;
+ vmmprintfvv("vmmwin.c!EnumerateEPROCESS32: %016llx %08x %08x %08x %s\n",
+ pVmmProcess->paDTB,
+ (DWORD)pVmmProcess->os.win.vaEPROCESS,
+ (DWORD)pVmmProcess->os.win.vaPEB,
+ pVmmProcess->dwPID,
+ pVmmProcess->szName);
+ if(!pVmmProcess) {
+ vmmprintfv("VMM: WARNING: PID '%i' already exists.\n", *pdwPID);
+ if(++cNewProcessCollision >= 8) {
+ break;
+ }
+ }
+ } else {
+ szName[14] = 0; // in case of bad string data ...
+ vmmprintfv("VMM: Skipping process - parse error or terminated state.\n PDPT: %08x PID: %i STATE: %i EPROCESS: %08x NAME: %s\n", ~0xfff & *pdwDTB, *pdwPID, *pdwState, vaEPROCESS, szName);
+ }
+ vaEPROCESS = *pdwFLink - dwoFLink;
+ if(vaEPROCESS == vaSystemEPROCESS) {
+ break;
+ }
+ if(!VmmRead(pSystemProcess, vaEPROCESS, pb, dwoMax)) {
+ break;
+ }
+ if(*pdwDTB & 0x1f) {
+ break;
+ }
+ if(0x80000000 != (0x80000003 & *pdwFLink)) {
+ break;
+ }
+ }
+ VmmProcessCreateFinish();
+ return (cPID > 10);
+}
+
+BOOL VmmWin_EnumerateEPROCESS(_In_ PVMM_PROCESS pSystemProcess)
+{
+ switch(ctxVmm->tpMemoryModel) {
+ case VMM_MEMORYMODEL_X64:
+ return VmmWin_EnumerateEPROCESS64(pSystemProcess);
+ case VMM_MEMORYMODEL_X86:
+ case VMM_MEMORYMODEL_X86PAE:
+ return VmmWin_EnumerateEPROCESS32(pSystemProcess);
+ }
+ return FALSE;
+}
+
+VOID VmmWin_InitializeModuleNames(_In_ PVMM_PROCESS pProcess)
+{
+ VmmWin_InitializeLdrModules(pProcess);
+ VmmWin_ScanHeaderPE(pProcess);
}
diff --git a/vmm/vmmwin.h b/vmm/vmmwin.h
new file mode 100644
index 0000000..c99f917
--- /dev/null
+++ b/vmm/vmmwin.h
@@ -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__ */
diff --git a/vmm/vmmwininit.c b/vmm/vmmwininit.c
new file mode 100644
index 0000000..0afeb98
--- /dev/null
+++ b/vmm/vmmwininit.c
@@ -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;
+}
diff --git a/vmm/vmmwininit.h b/vmm/vmmwininit.h
new file mode 100644
index 0000000..4641388
--- /dev/null
+++ b/vmm/vmmwininit.h
@@ -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__ */
diff --git a/vmm_example/vmmdll.h b/vmm_example/vmmdll.h
index 623a09b..bfa1172 100644
--- a/vmm_example/vmmdll.h
+++ b/vmm_example/vmmdll.h
@@ -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
}
diff --git a/vmm_example/vmmdll_example.c b/vmm_example/vmmdll_example.c
index 1f7458f..185690a 100644
--- a/vmm_example/vmmdll_example.c
+++ b/vmm_example/vmmdll_example.c
@@ -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");
diff --git a/vmmpyc/vmmdll.h b/vmmpyc/vmmdll.h
index 623a09b..bfa1172 100644
--- a/vmmpyc/vmmdll.h
+++ b/vmmpyc/vmmdll.h
@@ -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
}
diff --git a/vmmpyc/vmmpyc.c b/vmmpyc/vmmpyc.c
index a64a7e0..2f8f4d9 100644
--- a/vmmpyc/vmmpyc.c
+++ b/vmmpyc/vmmpyc.c
@@ -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;
}
diff --git a/vmmpycplugin/vmmdll.h b/vmmpycplugin/vmmdll.h
index 623a09b..bfa1172 100644
--- a/vmmpycplugin/vmmdll.h
+++ b/vmmpycplugin/vmmdll.h
@@ -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
}
diff --git a/vmmpycplugin/vmmpycplugin.c b/vmmpycplugin/vmmpycplugin.c
index 3d85489..f0e1adf 100644
--- a/vmmpycplugin/vmmpycplugin.c
+++ b/vmmpycplugin/vmmpycplugin.c
@@ -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.