diff --git a/files/vmmpycplugin.dll b/files/vmmpycplugin.dll index 4953de0..036470e 100644 Binary files a/files/vmmpycplugin.dll and b/files/vmmpycplugin.dll differ diff --git a/vmmpycplugin/leechcore.h b/vmmpycplugin/leechcore.h index a2da3e6..46af16a 100644 --- a/vmmpycplugin/leechcore.h +++ b/vmmpycplugin/leechcore.h @@ -68,13 +68,14 @@ // placed in same directory as the executable file. // // PMEM : load the rekall winpmem driver into the kernel and connect to it -// to acquire memory. The driver file 'winpmem_x64.sys' is found in -// the Rekall directory after most recent version has been installed. -// Copy 'winpmem_x64.sys' to the directory of leechcore.dll and run -// executable as elevated admin using syntax below: +// to acquire memory. The signed driver `.sys` file may be found at: +// https://github.com/Velocidex/c-aff4/tree/master/tools/pmem/resources/winpmem +// Download the driver file `att_winpmem_64.sys` and copy it to the +// directory of leechcore.dll and run executable as elevated admin +// using syntax below: // Syntax: -// PMEM (use winpmem_x64.sys in directory of executable) -// PMEM:// +// PMEM (use att_winpmem_64.sys in directory of executable) +// PMEM:// // // TOTALMELTDOWN : read/write - requires a Windows 7 system vulnerable to the // "Total Meltdown" vulnerability - CVE-2018-1038. @@ -110,7 +111,7 @@ // (c) Ulf Frisk, 2018-2019 // Author: Ulf Frisk, pcileech@frizk.net // -// Header Version: 1.0 +// Header Version: 1.1.0 // #ifndef __LEECHCORE_H__ #define __LEECHCORE_H__ @@ -151,6 +152,7 @@ typedef long long unsigned int QWORD, *PQWORD, ULONG64, *PULONG64; #define _Printf_format_string_ #define _Inout_updates_bytes_(x) #define _In_reads_(cbDataIn) +#define _Out_writes_opt_(x) #define _Success_(return) #endif /* LINUX */ @@ -227,7 +229,10 @@ typedef struct tdLEECHCORE_PAGESTAT_MINIMAL { } LEECHCORE_PAGESTAT_MINIMAL, *PLEECHCORE_PAGESTAT_MINIMAL; /* -* Open a connection to the target device. +* Open a connection to the target device. The LeechCore initialization may fail +* if the underlying device cannot be opened or if the LeechCore is already +* initialized. If already initialized please connect with device EXISTING or +* call LeechCore_Close() before opening a new device. * -- pInformation * -- result */ @@ -455,9 +460,9 @@ DLLEXPORT BOOL LeechCore_CommandData( _In_ ULONG64 fOption, _In_reads_(cbDataIn) PBYTE pbDataIn, _In_ DWORD cbDataIn, - _Out_writes_(cbDataOut) PBYTE pbDataOut, + _Out_writes_opt_(cbDataOut) PBYTE pbDataOut, _In_ DWORD cbDataOut, - _Out_ PDWORD pcbDataOut + _Out_opt_ PDWORD pcbDataOut ); #ifdef __cplusplus diff --git a/vmmpycplugin/version.h b/vmmpycplugin/version.h index 0c049c3..997bede 100644 --- a/vmmpycplugin/version.h +++ b/vmmpycplugin/version.h @@ -2,8 +2,8 @@ #define STRINGIZE(s) STRINGIZE2(s) #define VERSION_MAJOR 2 -#define VERSION_MINOR 0 -#define VERSION_REVISION 0 +#define VERSION_MINOR 2 +#define VERSION_REVISION 1 #define VERSION_BUILD 0 #define VER_FILE_DESCRIPTION_STR "The Memory Process File System : Python Plugin Manager" diff --git a/vmmpycplugin/vmmdll.h b/vmmpycplugin/vmmdll.h index 353159a..6b1e71b 100644 --- a/vmmpycplugin/vmmdll.h +++ b/vmmpycplugin/vmmdll.h @@ -4,7 +4,7 @@ // (c) Ulf Frisk, 2018-2019 // Author: Ulf Frisk, pcileech@frizk.net // -// Header Version: 2.0 +// Header Version: 2.2 // #include @@ -26,13 +26,15 @@ extern "C" { * about the parameters please see github wiki for Memory Process File System * and LeechCore. THIS IS THE PREFERED WAY OF INITIALIZING VMM.DLL * Important parameters are: -* -vdll = show printf style outputs) +* -printf = show printf style outputs) * -v -vv -vvv = extra verbosity levels) * -device = device as on format for LeechCore - please see leechcore.h or * Github documentation for additional information. Some values * are: , fpga, usb3380, hvsavedstate, totalmeltdown, pmem * -remote = remote LeechCore instance - please see leechcore.h or Github * documentation for additional information. +* -norefresh = disable background refreshes (even if backing memory is +* volatile memory). * -- argc * -- argv * -- return = success/fail @@ -48,6 +50,17 @@ BOOL VMMDLL_Initialize(_In_ DWORD argc, _In_ LPSTR argv[]); _Success_(return) BOOL VMMDLL_Close(); +/* +* Perform a force refresh of all internal caches including: +* - process listings +* - memory cache +* - page table cache +* WARNING: function may take some time to execute! +* -- dwReserved = reserved future use - must be zero +* -- return = sucess/fail +*/ +_Success_(return) +BOOL VMMDLL_Refresh(_In_ DWORD dwReserved); //----------------------------------------------------------------------------- @@ -289,7 +302,7 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO { * -- ppMEMs = array of scatter read headers. * -- cpMEMs = count of ppDMAs. * -- pcpDMAsRead = optional count of number of successfully read ppDMAs. -* -- flags = optional flags as given by VMM_FLAG_* +* -- flags = optional flags as given by VMMDLL_FLAG_* * -- return = the number of successfully read items. */ DWORD VMMDLL_MemReadScatter(_In_ DWORD dwPID, _Inout_ PPMEM_IO_SCATTER_HEADER ppMEMs, _In_ DWORD cpMEMs, _In_ DWORD flags); @@ -322,13 +335,25 @@ BOOL VMMDLL_MemRead(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DW * -- pb * -- cb * -- pcbRead -* -- flags = flags as in VMM_FLAG_* +* -- flags = flags as in VMMDLL_FLAG_* * -- return = success/fail. NB! reads may report as success even if 0 bytes are * read - it's recommended to verify pcbReadOpt parameter. */ _Success_(return) BOOL VMMDLL_MemReadEx(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ ULONG64 flags); +/* +* Prefetch a number of addresses (specified in the pA array) into the memory +* cache. This function is to be used to batch larger known reads into local +* cache before making multiple smaller reads - which will then happen from +* the cache. Function exists for performance reasons. +* -- dwPID = PID of target process, (DWORD)-1 for physical memory. +* -- pPrefetchAddresses = array of addresses to read into cache. +* -- cPrefetchAddresses +*/ +_Success_(return) +BOOL VMMDLL_MemPrefetchPages(_In_ DWORD dwPID, _In_reads_(cPrefetchAddresses) PULONG64 pPrefetchAddresses, _In_ DWORD cPrefetchAddresses); + /* * Write a contigious arbitrary amount of memory. Please note some virtual memory * such as pages of executables (such as DLLs) may be shared between different @@ -527,6 +552,87 @@ BOOL VMMDLL_ProcessGetEAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_opt_ PVMMD _Success_(return) BOOL VMMDLL_ProcessGetIAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_opt_ PVMMDLL_IAT_ENTRY pData, _In_ DWORD cData, _Out_ PDWORD pcData); +/* +* Retrieve the virtual address of a given function inside a process/module. +* -- dwPID +* -- szModuleName +* -- szFunctionName +* -- return = virtual address of function, zero on fail. +*/ +ULONG64 VMMDLL_ProcessGetProcAddress(_In_ DWORD dwPID, _In_ LPSTR szModuleName, _In_ LPSTR szFunctionName); + +/* +* Retrieve the base address of a given module. +* -- dwPID +* -- szModuleName +* -- return = virtual address of module base, zero on fail. +*/ +ULONG64 VMMDLL_ProcessGetModuleBase(_In_ DWORD dwPID, _In_ LPSTR szModuleName); + + + +//----------------------------------------------------------------------------- +// WINDOWS SPECIFIC UTILITY FUNCTIONS BELOW: +//----------------------------------------------------------------------------- + +typedef struct tdVMMDLL_WIN_THUNKINFO_IAT { + BOOL fValid; + BOOL f32; // if TRUE fn is a 32-bit/4-byte entry, otherwise 64-bit/8-byte entry. + ULONG64 vaThunk; // address of import address table 'thunk'. + ULONG64 vaFunction; // value if import address table 'thunk' == address of imported function. + ULONG64 vaNameModule; // address of name string for imported module. + ULONG64 vaNameFunction; // address of name string for imported function. +} VMMDLL_WIN_THUNKINFO_IAT, *PVMMDLL_WIN_THUNKINFO_IAT; + +typedef struct tdVMMDLL_WIN_THUNKINFO_EAT { + BOOL fValid; + DWORD valueThunk; // value of export address table 'thunk'. + ULONG64 vaThunk; // address of import address table 'thunk'. + ULONG64 vaNameFunction; // address of name string for exported function. + ULONG64 vaFunction; // address of exported function (module base + value parameter). +} VMMDLL_WIN_THUNKINFO_EAT, *PVMMDLL_WIN_THUNKINFO_EAT; + +/* +* Retrieve information about the import address table IAT thunk for an imported +* function. This includes the virtual address of the IAT thunk which is useful +* for hooking. +* -- dwPID +* -- szModuleName +* -- szImportModuleName +* -- szImportFunctionName +* -- pThunkIAT +* -- return +*/ +_Success_(return) +BOOL VMMDLL_WinGetThunkInfoIAT(_In_ DWORD dwPID, _In_ LPSTR szModuleName, _In_ LPSTR szImportModuleName, _In_ LPSTR szImportFunctionName, _Out_ PVMMDLL_WIN_THUNKINFO_IAT pThunkInfoIAT); + +/* +* Retrieve information about the export address table EAT thunk for an exported +* function. This includes the virtual address of the EAT thunk which is useful +* for hooking. +* -- dwPID +* -- szModuleName +* -- pThunkEAT +* -- return +*/ +_Success_(return) +BOOL VMMDLL_WinGetThunkInfoEAT(_In_ DWORD dwPID, _In_ LPSTR szModuleName, _In_ LPSTR szExportFunctionName, _Out_ PVMMDLL_WIN_THUNKINFO_EAT pThunkInfoEAT); + +/* +* Decompress compressed memory page stored in the MemCompression process. +* -- vaCompressedData = virtual address in 'MemCompression' to decompress. +* -- cbCompressedData = length of compressed data in 'MemCompression' to decompress (or zero for auto-detect). +* -- pbDecompressedPage +* -- pcbCompressedData = optional ptr to receive length of compressed buffer. +* -- return +*/ +_Success_(return) +BOOL VMMDLL_WinMemCompression_DecompressPage( + _In_ ULONG64 vaCompressedData, + _In_opt_ DWORD cbCompressedData, + _Out_writes_(4096) PBYTE pbDecompressedPage, + _Out_opt_ PDWORD pcbCompressedData +); //----------------------------------------------------------------------------- diff --git a/vmmpycplugin/vmmpycplugin.c b/vmmpycplugin/vmmpycplugin.c index b90542b..a65dbb1 100644 --- a/vmmpycplugin/vmmpycplugin.c +++ b/vmmpycplugin/vmmpycplugin.c @@ -279,7 +279,7 @@ VOID VmmPyPlugin_UpdateVerbosity() } } -#define PYTHON_PATH_MAX 4*MAX_PATH +#define PYTHON_PATH_MAX 7*MAX_PATH #define PYTHON_PATH_DELIMITER L";" BOOL VmmPyPlugin_PythonInitialize(_In_ HMODULE hDllPython) { @@ -299,14 +299,26 @@ BOOL VmmPyPlugin_PythonInitialize(_In_ HMODULE hDllPython) wcscat_s(wszPathPython, PYTHON_PATH_MAX, PYTHON_PATH_DELIMITER); wcscat_s(wszPathPython, PYTHON_PATH_MAX, wszPathBasePython); wcscat_s(wszPathPython, PYTHON_PATH_MAX, L"python36.zip"); - // 2.3: python lib + // 2.3: python dlls + wcscat_s(wszPathPython, PYTHON_PATH_MAX, PYTHON_PATH_DELIMITER); + wcscat_s(wszPathPython, PYTHON_PATH_MAX, wszPathBasePython); + wcscat_s(wszPathPython, PYTHON_PATH_MAX, L"DLLs\\"); + // 2.4: python lib wcscat_s(wszPathPython, PYTHON_PATH_MAX, PYTHON_PATH_DELIMITER); wcscat_s(wszPathPython, PYTHON_PATH_MAX, wszPathBasePython); wcscat_s(wszPathPython, PYTHON_PATH_MAX, L"Lib\\"); - // 2.4: .exe location of this process + // 2.5: python lib\site-packages (python pip) + wcscat_s(wszPathPython, PYTHON_PATH_MAX, PYTHON_PATH_DELIMITER); + wcscat_s(wszPathPython, PYTHON_PATH_MAX, wszPathBasePython); + wcscat_s(wszPathPython, PYTHON_PATH_MAX, L"Lib\\site-packages\\"); + // 2.6: .exe location of this process wcscat_s(wszPathPython, PYTHON_PATH_MAX, PYTHON_PATH_DELIMITER); wcscat_s(wszPathPython, PYTHON_PATH_MAX, wszPathBaseExe); - // 3: Initialize Embedded Python. + // 2.7: pylib relative to this process + wcscat_s(wszPathPython, PYTHON_PATH_MAX, PYTHON_PATH_DELIMITER); + wcscat_s(wszPathPython, PYTHON_PATH_MAX, wszPathBaseExe); + wcscat_s(wszPathPython, PYTHON_PATH_MAX, L"pylib\\"); + // 3: Initialize (Embedded) Python. Py_SetProgramName(L"VmmPyPluginManager"); Py_SetPath(wszPathPython); if(ctxPY2C->fVerboseExtra) { @@ -314,6 +326,7 @@ BOOL VmmPyPlugin_PythonInitialize(_In_ HMODULE hDllPython) } PY2C_InitializeModuleVMMPYCC(); Py_Initialize(); + PyEval_InitThreads(); // 4: Import VmmPyPlugin library/file to start the python part of the plugin manager. pName = PyUnicode_DecodeFSDefault("vmmpyplugin"); if(!pName) { goto fail; } @@ -322,6 +335,7 @@ BOOL VmmPyPlugin_PythonInitialize(_In_ HMODULE hDllPython) // 5: Cleanups Py_DECREF(pName); Py_DECREF(pModule); + PyEval_ReleaseLock(); return TRUE; fail: if(pName) { Py_DECREF(pName); }