Version 2.1

This commit is contained in:
Ulf Frisk
2019-02-28 11:23:04 +01:00
parent 78ba5a2936
commit 89106b78fb
36 changed files with 1366 additions and 282 deletions

View File

@@ -137,3 +137,9 @@ v2.0
* Support for Microsoft Crash Dumps - such as created by default by [Comae DumpIt](https://www.comae.com).
* Hyper-V save files.
* Remote capture via remotely installed LeechService.
v2.1
* New APIs:
* IAT/EAT hook functionality.
* Limited Windows 10 MemCompression support.
* Bug fixes.

Binary file not shown.

View File

@@ -111,7 +111,7 @@
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, pcileech@frizk.net
//
// Header Version: 1.0.2
// Header Version: 1.1.0
//
#ifndef __LEECHCORE_H__
#define __LEECHCORE_H__
@@ -229,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
*/

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -4,7 +4,7 @@
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, pcileech@frizk.net
//
// Header Version: 2.0
// Header Version: 2.1
//
#include <windows.h>
@@ -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: <file>, 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
@@ -289,7 +291,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 +324,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 +541,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
);
//-----------------------------------------------------------------------------

View File

@@ -9,7 +9,7 @@
#
# https://github.com/ufrisk/
#
# (c) Ulf Frisk, 2018
# (c) Ulf Frisk, 2018-2019
# Author: Ulf Frisk, pcileech@frizk.net
#
@@ -56,7 +56,7 @@ def VmmPy_Close():
N/A
Example:
VmmPy_Close() --> True
VmmPy_Close()
"""
VMMPYC_Close()
@@ -485,6 +485,58 @@ def VmmPy_VfsWrite(path_file, bytes_data, offset = 0):
VmmPy_VfsWrite(path_file, bytes_data, offset)
#------------------------------------------------------------------------------
# VmmPy WINDOWS ONLY FUNCTIONALITY BELOW:
#------------------------------------------------------------------------------
def VmmPy_WinGetThunkInfoEAT(pid, module_name, exported_function):
"""Retrieve information about a single export address table (EAT) entry. This may be useful for hooking.
Keyword arguments:
pid -- int: the process identifier (pid) when reading process virtual memory.
module_name -- str: name of the module to retrieve.
exported_function -- str: name of the exported function to retrieve.
return -- dict: information about the EAT entry.
Example:
VmmPy_WinGetThunkInfoEAT(4, 'ntoskrnl.exe', 'KeGetCurrentIrql') --> {'vaFunction': 18446735288139539584, 'valueThunk': 1479808, 'vaNameFunction': 18446735288147899428, 'vaThunk': 18446735288147849312}
"""
return VMMPYC_WinGetThunkInfoEAT(pid, module_name, exported_function)
def VmmPy_WinGetThunkInfoIAT(pid, module_name, imported_module_name, imported_module_function):
"""Retrieve information about a single import address table (IAT) entry. This may be useful for hooking.
Keyword arguments:
pid -- int: the process identifier (pid) when reading process virtual memory.
module_name -- str: name of the module to retrieve.
imported_module_name -- str: name of the imported module to retrieve.
imported_module_function -- str: name of the imported function to retrieve.
return -- dict: information about the IAT entry.
Example:
VmmPy_WinGetThunkInfoIAT(4, 'ntoskrnl.exe', 'hal.dll', 'HalSendNMI') --> {'32': False, 'vaFunction': 18446735288149190896, 'vaNameFunction': 18446735288143568050, 'vaNameModule': 18446735288143568362, 'vaThunk': 18446735288143561136}
"""
return VMMPYC_WinGetThunkInfoIAT(pid, module_name, imported_module_name, imported_module_function)
def VmmPy_WinDecompressPage(va_compressed, len_compressed = 0):
"""Decompress a page stored in the MemCompression process in Windows 10.
Keyword arguments:
va_compressed -- int: the virtual address inside 'MemCompression' where the compressed buffer starts.
len_compressed -- int: optional length of the compressed buffer (leave out for auto-detect).
return -- dict: containing decompressed data and size of compressed buffer.
Example:
VmmPy_WinDecompressPage(0x00000210bfb40000) --> {'c': 456, 'b': b'...'}
"""
return VMMPYC_WinMemCompression_DecompressPage(va_compressed, len_compressed)
#------------------------------------------------------------------------------
# VmmPy UTIL FUNCTIONALITY BELOW:
#------------------------------------------------------------------------------

Binary file not shown.

View File

@@ -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://<non_default_path_to_file_winpmem_x64.sys>
// PMEM (use att_winpmem_64.sys in directory of executable)
// PMEM://<non_default_path_to_file_winpmem_64.sys>
//
// 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

View File

@@ -35,7 +35,7 @@ typedef struct tdOBLDRMODULES_CACHE_ENTRY {
*/
POBLDRMODULES_CACHE_ENTRY LdrModule_GetEAT(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ PVMM_MODULEMAP_ENTRY pModule)
{
DWORD i, o, cEATs;
DWORD i, o, cEATs = 0;
PVMMPROC_WINDOWS_EAT_ENTRY pEATs = NULL;
POBLDRMODULES_CACHE_ENTRY pObCacheEntry = NULL;
PVMM_PROCESS pProcess = (PVMM_PROCESS)ctx->pProcess;
@@ -47,10 +47,9 @@ POBLDRMODULES_CACHE_ENTRY LdrModule_GetEAT(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_
VmmOb_DECREF(pObCacheEntry);
pObCacheEntry = NULL;
// 2: retrieve exported functions
cEATs = LDRMODULES_MAX_IATEAT;
pEATs = LocalAlloc(0, LDRMODULES_MAX_IATEAT * sizeof(VMMPROC_WINDOWS_EAT_ENTRY));
if(!pEATs) { goto fail; }
VmmWin_PE_LoadEAT_DisplayBuffer(ctx->pProcess, pModule, pEATs, &cEATs);
VmmWin_PE_LoadEAT_DisplayBuffer(ctx->pProcess, pModule, pEATs, LDRMODULES_MAX_IATEAT, &cEATs);
if(!cEATs) { goto fail; }
// 3: fill "display buffer"
pObCacheEntry = VmmOb_Alloc('EA', LMEM_ZEROINIT, sizeof(OBLDRMODULES_CACHE_ENTRY) + (QWORD)cEATs * 64 + 1, NULL, NULL);
@@ -87,7 +86,7 @@ fail:
*/
POBLDRMODULES_CACHE_ENTRY LdrModule_GetIAT(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ PVMM_MODULEMAP_ENTRY pModule)
{
DWORD i, o, cIATs;
DWORD i, o, cIATs = 0;
PVMMWIN_IAT_ENTRY pIATs = NULL;
POBLDRMODULES_CACHE_ENTRY pObCacheEntry = NULL;
PVMM_PROCESS pProcess = (PVMM_PROCESS)ctx->pProcess;
@@ -99,10 +98,9 @@ POBLDRMODULES_CACHE_ENTRY LdrModule_GetIAT(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_
VmmOb_DECREF(pObCacheEntry);
pObCacheEntry = NULL;
// 2: retrieve exported functions
cIATs = LDRMODULES_MAX_IATEAT;
pIATs = LocalAlloc(0, LDRMODULES_MAX_IATEAT * sizeof(VMMWIN_IAT_ENTRY));
if(!pIATs) { goto fail; }
VmmWin_PE_LoadIAT_DisplayBuffer(ctx->pProcess, pModule, pIATs, &cIATs);
VmmWin_PE_LoadIAT_DisplayBuffer(ctx->pProcess, pModule, pIATs, LDRMODULES_MAX_IATEAT, &cIATs);
if(!cIATs) { goto fail; }
// 3: fill "display buffer"
pObCacheEntry = VmmOb_Alloc('IA', LMEM_ZEROINIT, sizeof(OBLDRMODULES_CACHE_ENTRY) + (QWORD)cIATs * 128 + 1, NULL, NULL);

54
vmm/mm_x64_winpaged.c Normal file
View File

@@ -0,0 +1,54 @@
// mm_x64_winpaged.c : implementation related to the x64 windows paging subsystem
// (including paged out virtual/compressed virtual memory).
//
// (c) Ulf Frisk, 2019
// Author: Ulf Frisk, pcileech@frizk.net
//
#include "mm_x64_winpaged.h"
#define COMPRESS_ALGORITHM_INVALID 0
#define COMPRESS_ALGORITHM_NULL 1
#define COMPRESS_ALGORITHM_MSZIP 2
#define COMPRESS_ALGORITHM_XPRESS 3
#define COMPRESS_ALGORITHM_XPRESS_HUFF 4
#define COMPRESS_ALGORITHM_LZMS 5
#define COMPRESS_ALGORITHM_MAX 6
#define COMPRESS_RAW (1 << 29)
_Success_(return)
BOOL MmX64WinPaged_MemCompression_DecompressPage(_In_ QWORD vaCompressedData, _In_opt_ DWORD cbCompressedData, _Out_writes_(4096) PBYTE pbDecompressedPage, _Out_opt_ PDWORD pcbCompressedData)
{
BOOL result = FALSE;
DWORD i, cbReadCompressedData = 0, cbDecompressed = 0;
BYTE pbCompressed[0x1000] = { 0 };
PVMM_PROCESS pObProcess = NULL;
if(pcbCompressedData) { *pcbCompressedData = 0; }
if(!ctxVmm->fn.RtlDecompressBuffer) { return FALSE; }
if(cbCompressedData > 0x1000) { return FALSE; }
if(!ctxVmm->kernel.dwPidMemCompression) { return FALSE; }
if(!(pObProcess = VmmProcessGet(ctxVmm->kernel.dwPidMemCompression))) { return FALSE; }
// buffer size specified - use value!
if(cbCompressedData) {
result =
VmmRead(pObProcess, vaCompressedData, pbCompressed, cbCompressedData) &&
(VMM_STATUS_SUCCESS == ctxVmm->fn.RtlDecompressBuffer(COMPRESS_ALGORITHM_XPRESS, pbDecompressedPage, 0x1000, pbCompressed, cbCompressedData, &cbDecompressed)) &&
(cbDecompressed == 0x1000);
VmmOb_DECREF(pObProcess); pObProcess = NULL;
if(pcbCompressedData) { *pcbCompressedData = cbCompressedData; }
return result;
}
// buffer not specified - try auto-detect!
VmmReadEx(pObProcess, vaCompressedData, pbCompressed, 0x1000, &cbReadCompressedData, VMM_FLAG_ZEROPAD_ON_FAIL);
VmmOb_DECREF(pObProcess); pObProcess = NULL;
if(cbReadCompressedData < 0x10) { return FALSE; }
for(i = 0x10; i < 0x1000; i++) {
result =
(VMM_STATUS_SUCCESS == ctxVmm->fn.RtlDecompressBuffer(COMPRESS_ALGORITHM_XPRESS, pbDecompressedPage, 0x1000, pbCompressed, i, &cbDecompressed)) &&
(cbDecompressed == 0x1000);
if(result) {
if(pcbCompressedData) { *pcbCompressedData = i; }
return TRUE;
}
}
return FALSE;
}

26
vmm/mm_x64_winpaged.h Normal file
View File

@@ -0,0 +1,26 @@
// mm_x64_winpaged.h : definitions related to the x64 windows paging subsystem
// (including paged out virtual/compressed virtual memory).
//
// (c) Ulf Frisk, 2019
// Author: Ulf Frisk, pcileech@frizk.net
//
#ifndef __MM_X64_WINPAGED_H__
#define __MM_X64_WINPAGED_H__
#include "vmm.h"
/*
* 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.
* -- pbDecompressedPage
* -- return
*/
_Success_(return)
BOOL MmX64WinPaged_MemCompression_DecompressPage(
_In_ QWORD vaCompressedData,
_In_opt_ DWORD cbCompressedData,
_Out_writes_(4096) PBYTE pbDecompressedPage,
_Out_opt_ PDWORD pcbCompressedData
);
#endif /* __MM_X64_WINPAGED_H__ */

121
vmm/pe.c
View File

@@ -5,8 +5,8 @@
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, pcileech@frizk.net
//
#include "vmm.h"
#include "pe.h"
PIMAGE_NT_HEADERS PE_HeaderGetVerify(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _Inout_ PBYTE pbModuleHeader, _Out_opt_ PBOOL pfHdr32)
{
@@ -40,7 +40,102 @@ QWORD PE_GetSize(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase)
return cbSize;
}
QWORD PE_GetProcAddress(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ LPSTR lpProcName)
_Success_(return)
BOOL PE_GetThunkInfoIAT(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ LPSTR szImportModuleName, _In_ LPSTR szImportProcName, _Out_ PPE_THUNKINFO_IAT pThunkInfoIAT)
{
BYTE pbModuleHeader[0x1000] = { 0 };
PIMAGE_NT_HEADERS64 ntHeader64;
PIMAGE_NT_HEADERS32 ntHeader32;
QWORD i, oImportDirectory;
PIMAGE_IMPORT_DESCRIPTOR pIID;
PQWORD pIAT64, pHNA64;
PDWORD pIAT32, pHNA32;
DWORD cbModule, cbRead;
PBYTE pbModule = NULL;
BOOL f32, fFnName;
DWORD c, j;
LPSTR szNameFunction, szNameModule;
// load both 32/64 bit ntHeader (only one will be valid)
if(!(ntHeader64 = PE_HeaderGetVerify(pProcess, vaModuleBase, pbModuleHeader, &f32))) { goto fail; }
ntHeader32 = (PIMAGE_NT_HEADERS32)ntHeader64;
cbModule = f32 ?
ntHeader32->OptionalHeader.SizeOfImage :
ntHeader64->OptionalHeader.SizeOfImage;
if(cbModule > 0x02000000) { goto fail; }
oImportDirectory = f32 ?
ntHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress :
ntHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
if(!oImportDirectory || (oImportDirectory >= cbModule)) { goto fail; }
if(!(pbModule = LocalAlloc(LMEM_ZEROINIT, cbModule))) { goto fail; }
VmmReadEx(pProcess, vaModuleBase, pbModule, cbModule, &cbRead, VMM_FLAG_ZEROPAD_ON_FAIL);
if(cbRead <= 0x2000) { goto fail; }
// Walk imported modules / functions
pIID = (PIMAGE_IMPORT_DESCRIPTOR)(pbModule + oImportDirectory);
i = 0, c = 0;
while((oImportDirectory + (i + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR) < cbModule) && pIID[i].FirstThunk) {
if(pIID[i].Name > cbModule - 64) { i++; continue; }
if(f32) {
// 32-bit PE
j = 0;
pIAT32 = (PDWORD)(pbModule + pIID[i].FirstThunk);
pHNA32 = (PDWORD)(pbModule + pIID[i].OriginalFirstThunk);
while(TRUE) {
if((QWORD)(pIAT32 + j) + sizeof(DWORD) - (QWORD)pbModule > cbModule) { break; }
if((QWORD)(pHNA32 + j) + sizeof(DWORD) - (QWORD)pbModule > cbModule) { break; }
if(!pIAT32[j]) { break; }
if(!pHNA32[j]) { break; }
fFnName = (pHNA32[j] < cbModule - 40);
szNameFunction = (LPSTR)(pbModule + pHNA32[j] + 2);
szNameModule = (LPSTR)(pbModule + pIID[i].Name);
if(fFnName && !strcmp(szNameFunction, szImportProcName) && !_stricmp(szNameModule, szImportModuleName)) {
pThunkInfoIAT->fValid = TRUE;
pThunkInfoIAT->f32 = TRUE;
pThunkInfoIAT->vaThunk = vaModuleBase + pIID[i].FirstThunk + sizeof(DWORD) * j;
pThunkInfoIAT->vaFunction = pIAT32[j];
pThunkInfoIAT->vaNameFunction = vaModuleBase + pHNA32[j] + 2;
pThunkInfoIAT->vaNameModule = vaModuleBase + pIID[i].Name;
LocalFree(pbModule);
return TRUE;
}
c++;
j++;
}
} else {
// 64-bit PE
j = 0;
pIAT64 = (PQWORD)(pbModule + pIID[i].FirstThunk);
pHNA64 = (PQWORD)(pbModule + pIID[i].OriginalFirstThunk);
while(TRUE) {
if((QWORD)(pIAT64 + j) + sizeof(QWORD) - (QWORD)pbModule > cbModule) { break; }
if((QWORD)(pHNA64 + j) + sizeof(QWORD) - (QWORD)pbModule > cbModule) { break; }
if(!pIAT64[j]) { break; }
if(!pHNA64[j]) { break; }
fFnName = (pHNA64[j] < cbModule - 40);
szNameFunction = (LPSTR)(pbModule + pHNA64[j] + 2);
szNameModule = (LPSTR)(pbModule + pIID[i].Name);
if(fFnName && !strcmp(szNameFunction, szImportProcName) && !_stricmp(szNameModule, szImportModuleName)) {
pThunkInfoIAT->fValid = TRUE;
pThunkInfoIAT->f32 = FALSE;
pThunkInfoIAT->vaThunk = vaModuleBase + pIID[i].FirstThunk + sizeof(QWORD) * j;
pThunkInfoIAT->vaFunction = pIAT64[j];
pThunkInfoIAT->vaNameFunction = vaModuleBase + pHNA64[j] + 2;
pThunkInfoIAT->vaNameModule = vaModuleBase + pIID[i].Name;
LocalFree(pbModule);
return TRUE;
}
c++;
j++;
}
}
i++;
}
fail:
LocalFree(pbModule);
return FALSE;
}
_Success_(return)
BOOL PE_GetThunkInfoEAT(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ LPSTR szProcName, _Out_ PPE_THUNKINFO_EAT pThunkInfoEAT)
{
BYTE pbModuleHeader[0x1000] = { 0 };
PIMAGE_NT_HEADERS32 ntHeader32;
@@ -49,7 +144,6 @@ QWORD PE_GetProcAddress(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In
PWORD pwNameOrdinals;
DWORD i, cbProcName, cbExportDirectoryOffset, cbRead = 0;
LPSTR sz;
QWORD vaFnPtr;
QWORD vaExportDirectory;
DWORD cbExportDirectory;
PBYTE pbExportDirectory = NULL;
@@ -76,7 +170,7 @@ QWORD PE_GetProcAddress(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In
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;
cbProcName = (DWORD)strnlen_s(szProcName, MAX_PATH) + 1;
cbExportDirectoryOffset = (DWORD)(vaExportDirectory - vaModuleBase);
pdwRVAAddrNames = (PDWORD)(pbExportDirectory + exp->AddressOfNames - cbExportDirectoryOffset);
pwNameOrdinals = (PWORD)(pbExportDirectory + exp->AddressOfNameOrdinals - cbExportDirectoryOffset);
@@ -84,16 +178,27 @@ QWORD PE_GetProcAddress(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In
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(0 == memcmp(sz, szProcName, cbProcName)) {
if(pwNameOrdinals[i] >= exp->NumberOfFunctions) { goto cleanup; }
vaFnPtr = (QWORD)(vaModuleBase + pdwRVAAddrFunctions[pwNameOrdinals[i]]);
pThunkInfoEAT->fValid = TRUE;
pThunkInfoEAT->vaFunction = (QWORD)(vaModuleBase + pdwRVAAddrFunctions[pwNameOrdinals[i]]);
pThunkInfoEAT->valueThunk = pdwRVAAddrFunctions[pwNameOrdinals[i]];
pThunkInfoEAT->vaThunk = vaExportDirectory + exp->AddressOfFunctions - cbExportDirectoryOffset + sizeof(DWORD) * pwNameOrdinals[i];
pThunkInfoEAT->vaNameFunction = vaExportDirectory + pdwRVAAddrNames[i] - cbExportDirectoryOffset;
LocalFree(pbExportDirectory);
return vaFnPtr;
return TRUE;
}
}
cleanup:
LocalFree(pbExportDirectory);
return 0;
return FALSE;
}
QWORD PE_GetProcAddress(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ LPSTR lpProcName)
{
PE_THUNKINFO_EAT oThunkInfoEAT = { 0 };
PE_GetThunkInfoEAT(pProcess, vaModuleBase, lpProcName, &oThunkInfoEAT);
return oThunkInfoEAT.vaFunction;
}
WORD PE_SectionGetNumberOfEx(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt)

View File

@@ -15,6 +15,23 @@
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" };
typedef struct tdPE_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.
} PE_THUNKINFO_IAT, *PPE_THUNKINFO_IAT;
typedef struct tdPE_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).
} PE_THUNKINFO_EAT, *PPE_THUNKINFO_EAT;
/*
* Retrieve the size of the module given its base.
* -- pProcess
@@ -32,6 +49,31 @@ QWORD PE_GetSize(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase);
*/
QWORD PE_GetProcAddress(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ LPSTR lpProcName);
/*
* Lookup the virtual address of an exported function or symbol in the module supplied
* among with additional information returned in the pThunkInfoEAT struct.
* -- pProcess
* -- vaModuleBase = PE module base address.
* -- szProcName
* -- pThunkInfoEAT
* -- return
*/
_Success_(return)
BOOL PE_GetThunkInfoEAT(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ LPSTR szProcName, _Out_ PPE_THUNKINFO_EAT pThunkInfoEAT);
/*
* Retrieve an import address table (IAT) entry for a specific function.
* This may be useful for IAT patching functionality.
* -- pProcess
* -- vaModuleBase
* -- szImportModuleName
* -- szImportProcName
* -- pThunkInfoIAT
* -- return
*/
_Success_(return)
BOOL PE_GetThunkInfoIAT(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ LPSTR szImportModuleName, _In_ LPSTR szImportProcName, _Out_ PPE_THUNKINFO_IAT pThunkInfoIAT);
/*
* Retrieve the module name and optionally the module size.
* -- pProcess

View File

@@ -12,47 +12,34 @@
VOID _PageStatPrintMemMap(_Inout_ PPAGE_STATISTICS ps)
{
BOOL fIsLinePrinted = FALSE;
QWORD i, qwAddrBase, qwAddrEnd;
QWORD i, qwAddrEnd;
if(!ps->i.fIsFirstPrintCompleted) {
vmmprintf(" Memory Map: \n START END #PAGES \n");
printf(" Memory Map: \n START END #PAGES \n");
}
if(!ps->i.MemMapIdx && !ps->i.MemMap[0]) {
vmmprintf(" \n \n");
if(!ps->i.MemMapIdx) {
printf(" \n \n");
return;
}
if(ps->i.MemMapPrintCommitIdx >= PAGE_STATISTICS_MEM_MAP_MAX_ENTRY - 4) {
vmmprintf(" Maximum number of memory map entries reached. \n \n");
if(ps->i.MemMapIdx >= PAGE_STATISTICS_MEM_MAP_MAX_ENTRY - 2) {
printf(" Maximum number of memory map entries reached. \n \n");
return;
}
qwAddrBase = ps->i.qwAddrBase + ps->i.MemMapPrintCommitPages * 0x1000;
for(i = ps->i.MemMapPrintCommitIdx; i < PAGE_STATISTICS_MEM_MAP_MAX_ENTRY; i++) {
if(!ps->i.MemMap[i] && i == 0) {
continue;
}
if(!ps->i.MemMap[i] || (i == PAGE_STATISTICS_MEM_MAP_MAX_ENTRY - 1)) {
for(i = max(1, ps->i.MemMapPrintIdx); i <= ps->i.MemMapIdx; i++) {
if(!ps->i.MemMap[i].cPages) {
break;
}
qwAddrEnd = qwAddrBase + 0x1000 * (QWORD)ps->i.MemMap[i];
if((i % 2) == 0) {
fIsLinePrinted = TRUE;
vmmprintf(
" %016llx - %016llx %08x \n",
qwAddrBase,
qwAddrEnd - 1,
ps->i.MemMap[i]);
if(i >= ps->i.MemMapPrintCommitIdx + 2) {
ps->i.MemMapPrintCommitPages += ps->i.MemMap[ps->i.MemMapPrintCommitIdx++];
ps->i.MemMapPrintCommitPages += ps->i.MemMap[ps->i.MemMapPrintCommitIdx++];
}
}
qwAddrBase = qwAddrEnd;
qwAddrEnd = ps->i.MemMap[i].qwAddrBase + ((QWORD)ps->i.MemMap[i].cPages << 12);
printf(
" %016llx - %016llx %08x \n",
ps->i.MemMap[i].qwAddrBase,
qwAddrEnd - 1,
ps->i.MemMap[i].cPages);
}
if(!fIsLinePrinted) { // print extra line for formatting reasons.
vmmprintf(" (No memory successfully read yet) \n");
ps->i.MemMapPrintIdx = ps->i.MemMapIdx;
if(!ps->i.MemMap[1].cPages) { // print extra line for formatting reasons.
printf(" (No memory successfully read yet) \n");
}
vmmprintf(" \n");
printf(" \n");
}
VOID _PageStatShowUpdate(_Inout_ PPAGE_STATISTICS ps)
@@ -135,55 +122,54 @@ VOID _PageStatThreadLoop(_In_ PPAGE_STATISTICS ps)
ExitThread(0);
}
VOID PageStatClose(_Inout_ PPAGE_STATISTICS ps)
VOID PageStatClose(_In_opt_ PPAGE_STATISTICS *ppPageStat)
{
BOOL status;
DWORD dwExitCode;
ps->i.fUpdate = TRUE;
ps->i.fThreadExit = TRUE;
while((status = GetExitCodeThread(ps->i.hThread, &dwExitCode)) && STILL_ACTIVE == dwExitCode) {
if(!ppPageStat || !*ppPageStat) { return; }
(*ppPageStat)->i.fUpdate = TRUE;
(*ppPageStat)->i.fThreadExit = TRUE;
while((status = GetExitCodeThread((*ppPageStat)->i.hThread, &dwExitCode)) && STILL_ACTIVE == dwExitCode) {
SwitchToThread();
}
if(!status) {
Sleep(200);
}
LocalFree(*ppPageStat);
*ppPageStat = NULL;
}
VOID PageStatInitialize(_Inout_ PPAGE_STATISTICS ps, _In_ QWORD qwAddrBase, _In_ QWORD qwAddrMax, _In_ LPSTR szAction, _In_ BOOL fKMD, _In_ BOOL fMemMap)
_Success_(return)
BOOL PageStatInitialize(_Out_ PPAGE_STATISTICS *ppPageStat, _In_ QWORD qwAddrBase, _In_ QWORD qwAddrMax, _In_ LPSTR szAction, _In_ BOOL fKMD, _In_ BOOL fMemMap)
{
memset(ps, 0, sizeof(PAGE_STATISTICS));
PPAGE_STATISTICS ps;
ps = *ppPageStat = LocalAlloc(LMEM_ZEROINIT, sizeof(PAGE_STATISTICS));
if(!ps) { return FALSE; }
ps->qwAddr = qwAddrBase;
ps->cPageTotal = (qwAddrMax - qwAddrBase + 1) / 4096;
ps->szAction = szAction;
ps->fKMD = fKMD;
ps->i.fMemMap = fMemMap;
ps->i.qwAddrBase = qwAddrBase;
ps->i.qwTickCountStart = GetTickCount64();
ps->i.hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)_PageStatThreadLoop, ps, 0, NULL);
return TRUE;
}
VOID PageStatUpdate(_Inout_opt_ PPAGE_STATISTICS ps, _In_ QWORD qwAddr, _In_ QWORD cPageSuccessAdd, _In_ QWORD cPageFailAdd)
VOID PageStatUpdate(_In_opt_ PPAGE_STATISTICS pPageStat, _In_ QWORD qwAddr, _In_ QWORD cPageSuccessAdd, _In_ QWORD cPageFailAdd)
{
if(!ps) { return; }
ps->qwAddr = qwAddr;
ps->cPageSuccess += cPageSuccessAdd;
ps->cPageFail += cPageFailAdd;
// add to memory map, even == success, odd = fail.
if(ps->i.MemMapIdx < PAGE_STATISTICS_MEM_MAP_MAX_ENTRY - 2) {
if(cPageSuccessAdd) {
if(ps->i.MemMapIdx % 2 == 1) {
ps->i.MemMapIdx++;
}
ps->i.MemMap[ps->i.MemMapIdx] += (DWORD)cPageSuccessAdd;
}
if(cPageFailAdd) {
if(ps->i.MemMapIdx % 2 == 0) {
ps->i.MemMapIdx++;
}
ps->i.MemMap[ps->i.MemMapIdx] += (DWORD)cPageFailAdd;
if(!pPageStat) { return; }
pPageStat->qwAddr = qwAddr;
pPageStat->cPageSuccess += cPageSuccessAdd;
pPageStat->cPageFail += cPageFailAdd;
// add to memory map
if(cPageSuccessAdd && (pPageStat->i.MemMapIdx < PAGE_STATISTICS_MEM_MAP_MAX_ENTRY - 1)) {
if(!pPageStat->i.MemMapIdx || (qwAddr - (cPageSuccessAdd << 12)) != (pPageStat->i.MemMap[pPageStat->i.MemMapIdx].qwAddrBase + ((QWORD)pPageStat->i.MemMap[pPageStat->i.MemMapIdx].cPages << 12))) {
pPageStat->i.MemMapIdx++;
pPageStat->i.MemMap[pPageStat->i.MemMapIdx].qwAddrBase = qwAddr - (cPageSuccessAdd << 12);
}
pPageStat->i.MemMap[pPageStat->i.MemMapIdx].cPages += (DWORD)cPageSuccessAdd;
}
ps->i.fUpdate = TRUE;
pPageStat->i.fUpdate = TRUE;
}
// ----------------------------------------------------------------------------
@@ -199,6 +185,7 @@ const LPSTR NAMES_VMM_STATISTICS_CALL[] = {
"VMMDLL_MemReadEx",
"VMMDLL_MemWrite",
"VMMDLL_MemVirt2Phys",
"VMMDLL_MemPrefetchPages",
"VMMDLL_PidList",
"VMMDLL_PidGetFromName",
"VMMDLL_ProcessGetInformation",
@@ -210,6 +197,11 @@ const LPSTR NAMES_VMM_STATISTICS_CALL[] = {
"VMMDLL_ProcessGetSections",
"VMMDLL_ProcessGetEAT",
"VMMDLL_ProcessGetIAT",
"VMMDLL_ProcessGetProcAddress",
"VMMDLL_ProcessGetModuleBase",
"VMMDLL_WinGetThunkEAT",
"VMMDLL_WinGetThunkIAT",
"VMMDLL_WinMemCompression_DecompressPage",
"PluginManager_List",
"PluginManager_Read",
"PluginManager_Write",
@@ -268,17 +260,17 @@ VOID Statistics_CallToString(_In_opt_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcb)
LEECHCORE_STATISTICS LeechCoreStatistics = { 0 };
DWORD cbLeechCoreStatistics = sizeof(LEECHCORE_STATISTICS);
if(!pb) {
*pcb = 71 * (STATISTICS_ID_MAX + LEECHCORE_STATISTICS_ID_MAX + 6);
*pcb = 79 * (STATISTICS_ID_MAX + LEECHCORE_STATISTICS_ID_MAX + 6);
return;
}
QueryPerformanceFrequency((PLARGE_INTEGER)&qwFreq);
o += snprintf(
pb + o,
cb - o,
"FUNCTION CALL STATISTICS: \n" \
"VALUES IN DECIMAL, TIME IN MICROSECONDS uS, STATISTICS = %s \n" \
"FUNCTION CALL NAME CALLS TIME AVG TIME TOTAL\n" \
"======================================================================\n",
"FUNCTION CALL STATISTICS: \n" \
"VALUES IN DECIMAL, TIME IN MICROSECONDS uS, STATISTICS = %s \n" \
"FUNCTION CALL NAME CALLS TIME AVG TIME TOTAL\n" \
"==============================================================================\n",
ctxMain->pvStatistics ? "ENABLED " : "DISABLED"
);
// statistics
@@ -290,7 +282,7 @@ VOID Statistics_CallToString(_In_opt_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcb)
o += snprintf(
pb + o,
cb - o,
"%-32.32s %8i %8i %16lli\n",
"%-40.40s %8i %8i %16lli\n",
NAMES_VMM_STATISTICS_CALL[i],
(DWORD)pStat->c,
(DWORD)(uS / pStat->c),
@@ -302,7 +294,7 @@ VOID Statistics_CallToString(_In_opt_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcb)
o += snprintf(
pb + o,
cb - o,
"%-32.32s %8i %8i %16lli\n",
"%-40.40s %8i %8i %16lli\n",
NAMES_VMM_STATISTICS_CALL[i],
0, 0, 0ULL);
}
@@ -315,7 +307,7 @@ VOID Statistics_CallToString(_In_opt_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcb)
o += snprintf(
pb + o,
cb - o,
"%-32.32s %8i %8i %16lli\n",
"%-40.40s %8i %8i %16lli\n",
LEECHCORE_STATISTICS_NAME[i],
(DWORD)LeechCoreStatistics.Call[i].c,
(DWORD)(uS / LeechCoreStatistics.Call[i].c),
@@ -325,11 +317,11 @@ VOID Statistics_CallToString(_In_opt_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcb)
o += snprintf(
pb + o,
cb - o,
"%-32.32s %8i %8i %16lli\n",
"%-40.40s %8i %8i %16lli\n",
LEECHCORE_STATISTICS_NAME[i],
0, 0, 0ULL);
}
}
}
*pcb = o;
*pcb = o - 1;
}

View File

@@ -7,7 +7,7 @@
#define __STATISTICS_H__
#include "vmm.h"
#define PAGE_STATISTICS_MEM_MAP_MAX_ENTRY 4096
#define PAGE_STATISTICS_MEM_MAP_MAX_ENTRY 2048
typedef struct tdPageStatistics {
QWORD qwAddr;
@@ -24,70 +24,80 @@ typedef struct tdPageStatistics {
HANDLE hThread;
WORD wConsoleCursorPosition;
QWORD qwTickCountStart;
QWORD qwAddrBase;
QWORD MemMapIdx;
QWORD MemMapPrintCommitIdx;
QWORD MemMapPrintCommitPages;
DWORD MemMap[PAGE_STATISTICS_MEM_MAP_MAX_ENTRY];
QWORD MemMapPrintIdx;
struct {
QWORD qwAddrBase;
DWORD cPages;
} MemMap[PAGE_STATISTICS_MEM_MAP_MAX_ENTRY];
} i;
} PAGE_STATISTICS, *PPAGE_STATISTICS;
/*
* Initialize the page statistics. This will also start displaying the page statistics
* on the screen asynchronously. PageStatClose must be called to stop this.
* -- ps = ptr to the PAGE_STATISTICS struct to initialize.
* -- ps = ptr to NULL pPageStat PageStatInitialize will initialize. Must be free'd with PageStatClose.
* -- qwAddrBase = the base address that the statistics will be based upon.
* -- qwAddrMax = the maximum address.
* -- szAction = the text shown as action.
* -- fKMD = is KMD mode.
* -- fPageMap = display read memory map when PageStatClose is called.
* -- return
*/
VOID PageStatInitialize(_Inout_ PPAGE_STATISTICS ps, _In_ QWORD qwAddrBase, _In_ QWORD qwAddrMax, _In_ LPSTR szAction, _In_ BOOL fKMD, _In_ BOOL fMemMap);
_Success_(return)
BOOL PageStatInitialize(_Out_ PPAGE_STATISTICS *ppPageStat, _In_ QWORD qwAddrBase, _In_ QWORD qwAddrMax, _In_ LPSTR szAction, _In_ BOOL fKMD, _In_ BOOL fMemMap);
/*
* Do one last update of the on-screen page statistics, display the read memory map if
* previously set in PageStatInitialize and stop the on-screen updates.
* -- ps = ptr to the PAGE_STATISTICS struct to stop using.
* -- pPageStat = ptr to the PPAGE_STATISTICS struct to close and free.
*/
VOID PageStatClose(_Inout_ PPAGE_STATISTICS ps);
VOID PageStatClose(_In_opt_ PPAGE_STATISTICS *ppPageStat);
/*
* Update the page statistics with the current address and with successfully and failed
* pages. Should not be called before PageStatInitialize and not after PageStatClose.
* This function must be used if the memory map should be shown; otherwise it's possible
* to alter the PPAGE_STATISTICS struct members directly.
* -- ps = pointer to page statistics struct (optional).
* -- pPageStat = pointer to page statistics struct.
* -- qwAddr = new address (after completed operation).
* -- cPageSuccessAdd = number of successfully read pages.
* -- cPageFailAdd = number of pages that failed.
*/
VOID PageStatUpdate(_Inout_opt_ PPAGE_STATISTICS ps, _In_ QWORD qwAddr, _In_ QWORD cPageSuccessAdd, _In_ QWORD cPageFailAdd);
VOID PageStatUpdate(_In_opt_ PPAGE_STATISTICS pPageStat, _In_ QWORD qwAddr, _In_ QWORD cPageSuccessAdd, _In_ QWORD cPageFailAdd);
#define STATISTICS_ID_INITIALIZE 0x00
#define STATISTICS_ID_VMMDLL_VfsList 0x01
#define STATISTICS_ID_VMMDLL_VfsRead 0x02
#define STATISTICS_ID_VMMDLL_VfsWrite 0x03
#define STATISTICS_ID_VMMDLL_VfsInitializePlugins 0x04
#define STATISTICS_ID_VMMDLL_MemReadEx 0x05
#define STATISTICS_ID_VMMDLL_MemWrite 0x06
#define STATISTICS_ID_VMMDLL_MemVirt2Phys 0x07
#define STATISTICS_ID_VMMDLL_PidList 0x08
#define STATISTICS_ID_VMMDLL_PidGetFromName 0x09
#define STATISTICS_ID_VMMDLL_ProcessGetInformation 0x0a
#define STATISTICS_ID_VMMDLL_ProcessGetMemoryMap 0x0b
#define STATISTICS_ID_VMMDLL_ProcessGetMemoryMapEntry 0x0c
#define STATISTICS_ID_VMMDLL_ProcessGetModuleMap 0x0d
#define STATISTICS_ID_VMMDLL_ProcessGetModuleFromName 0x0e
#define STATISTICS_ID_VMMDLL_ProcessGetDirectories 0x0f
#define STATISTICS_ID_VMMDLL_ProcessGetSections 0x10
#define STATISTICS_ID_VMMDLL_ProcessGetEAT 0x11
#define STATISTICS_ID_VMMDLL_ProcessGetIAT 0x12
#define STATISTICS_ID_PluginManager_List 0x13
#define STATISTICS_ID_PluginManager_Read 0x14
#define STATISTICS_ID_PluginManager_Write 0x15
#define STATISTICS_ID_PluginManager_Notify 0x16
#define STATISTICS_ID_MAX 0x16
#define STATISTICS_ID_NOLOG 0xffffffff
// NB! also update statistics.c!NAMES_VMM_STATISTICS_CALL
#define STATISTICS_ID_INITIALIZE 0x00
#define STATISTICS_ID_VMMDLL_VfsList 0x01
#define STATISTICS_ID_VMMDLL_VfsRead 0x02
#define STATISTICS_ID_VMMDLL_VfsWrite 0x03
#define STATISTICS_ID_VMMDLL_VfsInitializePlugins 0x04
#define STATISTICS_ID_VMMDLL_MemReadEx 0x05
#define STATISTICS_ID_VMMDLL_MemWrite 0x06
#define STATISTICS_ID_VMMDLL_MemVirt2Phys 0x07
#define STATISTICS_ID_VMMDLL_MemPrefetchPages 0x08
#define STATISTICS_ID_VMMDLL_PidList 0x09
#define STATISTICS_ID_VMMDLL_PidGetFromName 0x0a
#define STATISTICS_ID_VMMDLL_ProcessGetInformation 0x0b
#define STATISTICS_ID_VMMDLL_ProcessGetMemoryMap 0x0c
#define STATISTICS_ID_VMMDLL_ProcessGetMemoryMapEntry 0x0d
#define STATISTICS_ID_VMMDLL_ProcessGetModuleMap 0x0e
#define STATISTICS_ID_VMMDLL_ProcessGetModuleFromName 0x0f
#define STATISTICS_ID_VMMDLL_ProcessGetDirectories 0x10
#define STATISTICS_ID_VMMDLL_ProcessGetSections 0x11
#define STATISTICS_ID_VMMDLL_ProcessGetEAT 0x12
#define STATISTICS_ID_VMMDLL_ProcessGetIAT 0x13
#define STATISTICS_ID_VMMDLL_ProcessGetProcAddress 0x14
#define STATISTICS_ID_VMMDLL_ProcessGetModuleBase 0x15
#define STATISTICS_ID_VMMDLL_WinGetThunkEAT 0x16
#define STATISTICS_ID_VMMDLL_WinGetThunkIAT 0x17
#define STATISTICS_ID_VMMDLL_WinMemCompression_DecompressPage 0x18
#define STATISTICS_ID_PluginManager_List 0x19
#define STATISTICS_ID_PluginManager_Read 0x1a
#define STATISTICS_ID_PluginManager_Write 0x1b
#define STATISTICS_ID_PluginManager_Notify 0x1c
#define STATISTICS_ID_MAX 0x1c
#define STATISTICS_ID_NOLOG 0xffffffff
VOID Statistics_CallSetEnabled(_In_ BOOL fEnabled);
BOOL Statistics_CallGetEnabled();

View File

@@ -2,7 +2,7 @@
#define STRINGIZE(s) STRINGIZE2(s)
#define VERSION_MAJOR 2
#define VERSION_MINOR 0
#define VERSION_MINOR 1
#define VERSION_REVISION 0
#define VERSION_BUILD 0

View File

@@ -610,7 +610,7 @@ VOID VmmCache2Initialize(_In_ WORD wTblTag)
* -- pProcess
* -- pObPrefetchAddresses
*/
VOID VmmCachePrefetch(_In_ PVMM_PROCESS pProcess, _In_opt_ PVMMOB_DATASET pObPrefetchAddresses)
VOID VmmCachePrefetchPages(_In_opt_ PVMM_PROCESS pProcess, _In_opt_ PVMMOB_DATASET pObPrefetchAddresses)
{
QWORD va;
DWORD i, c = 0;
@@ -624,7 +624,11 @@ VOID VmmCachePrefetch(_In_ PVMM_PROCESS pProcess, _In_opt_ PVMMOB_DATASET pObPre
c++;
}
}
VmmReadScatterVirtual(pProcess, ppMEMs, c, 0);
if(pProcess) {
VmmReadScatterVirtual(pProcess, ppMEMs, c, 0);
} else {
VmmReadScatterPhysical(ppMEMs, c, 0);
}
LocalFree(ppMEMs);
}
@@ -860,6 +864,7 @@ PVMM_PROCESS VmmProcessCreateEntry(_In_ BOOL fTotalRefresh, _In_ DWORD dwPID, _I
if(!pProcess) { goto fail; }
InitializeCriticalSectionAndSpinCount(&pProcess->LockUpdate, 4096);
memcpy(pProcess->szName, szName, 16);
pProcess->szName[15] = 0;
pProcess->dwPID = dwPID;
pProcess->dwState = dwState;
pProcess->paDTB = paDTB;
@@ -1350,7 +1355,7 @@ BOOL VmmReadString_Unicode2Ansi(_In_ PVMM_PROCESS pProcess, _In_ QWORD qwVA, _Ou
BOOL result;
WCHAR wsz[0x1000];
if(cch) { sz[0] = 0; }
if(!cch || cch > 0x1000) { return FALSE; }
if((cch < 2) || (cch > 0x1000)) { return FALSE; }
result = VmmRead(pProcess, qwVA, (PBYTE)wsz, cch << 1);
if(!result) { return FALSE; }
for(i = 0; i < cch - 1; i++) {
@@ -1394,6 +1399,15 @@ VOID VmmInitializeMemoryModel(_In_ VMM_MEMORYMODEL_TP tp)
}
}
VOID VmmInitializeFunctions()
{
HMODULE hNtDll = NULL;
if((hNtDll = LoadLibraryA("ntdll.dll"))) {
ctxVmm->fn.RtlDecompressBuffer = (VMMFN_RtlDecompressBuffer*)GetProcAddress(hNtDll, "RtlDecompressBuffer");
FreeLibrary(hNtDll);
}
}
BOOL VmmInitialize()
{
// 1: allocate & initialize
@@ -1411,6 +1425,7 @@ BOOL VmmInitialize()
// 5: OTHER INIT:
VmmObContainer_Initialize(&ctxVmm->ObCEPROCESSCachePrefetch, NULL);
InitializeCriticalSection(&ctxVmm->MasterLock);
VmmInitializeFunctions();
return TRUE;
fail:
VmmClose();

View File

@@ -299,8 +299,24 @@ typedef struct tdVMM_KERNELINFO {
QWORD vaEntry;
QWORD vaPsLoadedModuleList;
QWORD vaKDBG;
DWORD dwPidMemCompression;
} VMM_KERNELINFO;
typedef NTSTATUS VMMFN_RtlDecompressBuffer(
USHORT CompressionFormat,
PUCHAR UncompressedBuffer,
ULONG UncompressedBufferSize,
PUCHAR CompressedBuffer,
ULONG CompressedBufferSize,
PULONG FinalUncompressedSize
);
typedef struct tdVMM_DYNAMIC_LOAD_FUNCTIONS {
// functions below may be loaded on startup
// NB! null checks are required before use!
VMMFN_RtlDecompressBuffer *RtlDecompressBuffer; // ntdll.dll!RtlDecompressBuffer
} VMM_DYNAMIC_LOAD_FUNCTIONS;
typedef struct tdVMM_CONTEXT {
CRITICAL_SECTION MasterLock;
VMMOBCONTAINER PROC; // contains VMM_PROCESS_TABLE
@@ -320,6 +336,7 @@ typedef struct tdVMM_CONTEXT {
} ThreadProcCache;
VMM_STATISTICS stat;
VMM_KERNELINFO kernel;
VMM_DYNAMIC_LOAD_FUNCTIONS fn;
PVOID pVmmVfsModuleList;
VMMOBCONTAINER ObCEPROCESSCachePrefetch;
VMM_CACHE_TABLE PHYS;
@@ -763,7 +780,7 @@ VOID VmmCacheInvalidate(_In_ QWORD pa);
* -- pProcess
* -- pObPrefetchAddresses
*/
VOID VmmCachePrefetch(_In_ PVMM_PROCESS pProcess, _In_opt_ PVMMOB_DATASET pObPrefetchAddresses);
VOID VmmCachePrefetchPages(_In_opt_ PVMM_PROCESS pProcess, _In_opt_ PVMMOB_DATASET pObPrefetchAddresses);
/*
* Initialize the memory model specified and discard any previous memory models

View File

@@ -116,6 +116,7 @@ copy $(ProjectDir)\vmmdll.h $(SolutionDir)\files\ /y</Command>
<ItemGroup>
<ClInclude Include="leechcore.h" />
<ClInclude Include="mm_x64.h" />
<ClInclude Include="mm_x64_winpaged.h" />
<ClInclude Include="mm_x86.h" />
<ClInclude Include="mm_x86pae.h" />
<ClInclude Include="m_status.h" />
@@ -136,6 +137,7 @@ copy $(ProjectDir)\vmmdll.h $(SolutionDir)\files\ /y</Command>
</ItemGroup>
<ItemGroup>
<ClCompile Include="mm_x64.c" />
<ClCompile Include="mm_x64_winpaged.c" />
<ClCompile Include="mm_x86.c" />
<ClCompile Include="mm_x86pae.c" />
<ClCompile Include="m_status.c" />

View File

@@ -75,6 +75,9 @@
<ClInclude Include="version.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="mm_x64_winpaged.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="vmmdll.c">
@@ -125,6 +128,9 @@
<ClCompile Include="vmmwininit.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="mm_x64_winpaged.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="vmmdll.def">

View File

@@ -15,6 +15,7 @@
#include "vmmproc.h"
#include "vmmwin.h"
#include "vmmvfs.h"
#include "mm_x64_winpaged.h"
// ----------------------------------------------------------------------------
// Synchronization macro below. The VMM isn't thread safe so it's important to
@@ -22,7 +23,7 @@
// with internal VMM housekeeping functionality.
// ----------------------------------------------------------------------------
#define CALL_SYNCHRONIZED_IMPLEMENTATION_VMM(id, fn) { \
#define CALL_SYNCHRONIZED_IMPLEMENTATION_VMM(id, fn) { \
QWORD tm; \
BOOL result; \
if(!ctxVmm) { return FALSE; } \
@@ -34,16 +35,16 @@
return result; \
}
#define CALL_SYNCHRONIZED_IMPLEMENTATION_VMM_NTSTATUS(id, fn) { \
QWORD tm; \
NTSTATUS nt; \
if(!ctxVmm) { return ((NTSTATUS)0xC0000001L); } /* UNSUCCESSFUL */ \
tm = Statistics_CallStart(); \
VmmLockAcquire(); \
nt = fn; \
VmmLockRelease(); \
Statistics_CallEnd(id, tm); \
return nt; \
#define CALL_SYNCHRONIZED_IMPLEMENTATION_VMM_RETURN(id, RetTp, RetValFail, fn) { \
QWORD tm; \
RetTp retVal; \
if(!ctxVmm) { return ((RetTp)RetValFail); } /* UNSUCCESSFUL */ \
tm = Statistics_CallStart(); \
VmmLockAcquire(); \
retVal = fn; \
VmmLockRelease(); \
Statistics_CallEnd(id, tm); \
return retVal; \
}
//-----------------------------------------------------------------------------
@@ -172,8 +173,8 @@ VOID VmmDll_PrintHelp()
" Valid options: <memory_dump_file>, PMEM, FPGA, TOTALMELTDOWN \n" \
" --- \n" \
" <memory_dump_file> = memory dump file name optionally including path.\n" \
" PMEM = use rekall winpmem 'winpmem_x64.sys' to aquire live memory. \n" \
" PMEM://c:\\path\\to\\winpmem_x64.sys = path to rekall winpmem driver.\n" \
" PMEM = use winpmem 'winpmem_64.sys' to acquire live memory. \n" \
" PMEM://c:\\path\\to\\winpmem_64.sys = path to winpmem driver. \n" \
" --- \n" \
" Below acquisition devices require pcileech.dll and are not built-in: \n" \
" TOTALMELTDOWN = use CVE-2018-1038 (vulnerable windows 7 only) \n" \
@@ -430,15 +431,19 @@ BOOL VMMDLL_VfsList(_In_ LPCWSTR wcsPath, _Inout_ PVMMDLL_VFS_FILELIST pFileList
NTSTATUS VMMDLL_VfsRead(_In_ LPCWSTR wcsFileName, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset)
{
CALL_SYNCHRONIZED_IMPLEMENTATION_VMM_NTSTATUS(
CALL_SYNCHRONIZED_IMPLEMENTATION_VMM_RETURN(
STATISTICS_ID_VMMDLL_VfsRead,
NTSTATUS,
VMMDLL_STATUS_UNSUCCESSFUL,
VmmVfs_Read(wcsFileName, pb, cb, pcbRead, cbOffset))
}
NTSTATUS VMMDLL_VfsWrite(_In_ LPCWSTR wcsFileName, _In_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset)
{
CALL_SYNCHRONIZED_IMPLEMENTATION_VMM_NTSTATUS(
CALL_SYNCHRONIZED_IMPLEMENTATION_VMM_RETURN(
STATISTICS_ID_VMMDLL_VfsWrite,
NTSTATUS,
VMMDLL_STATUS_UNSUCCESSFUL,
VmmVfs_Write(wcsFileName, pb, cb, pcbWrite, cbOffset))
}
@@ -551,6 +556,38 @@ BOOL VMMDLL_MemReadPage(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Inout_bytecount_(4
return VMMDLL_MemReadEx(dwPID, qwVA, pbPage, 4096, &dwRead, 0) && (dwRead == 4096);
}
_Success_(return)
BOOL VMMDLL_MemPrefetchPages_Impl(_In_ DWORD dwPID, _In_reads_(cPrefetchAddresses) PULONG64 pPrefetchAddresses, _In_ DWORD cPrefetchAddresses)
{
DWORD i;
BOOL result = FALSE;
PVMM_PROCESS pObProcess = NULL;
PVMMOB_DATASET pObPrefetchAddresses = NULL;
if(dwPID != (DWORD)-1) {
pObProcess = VmmProcessGet(dwPID);
if(!pObProcess) { goto fail; }
}
pObPrefetchAddresses = VmmObDataSet_Alloc(TRUE);
if(!pObPrefetchAddresses) { goto fail; }
for(i = 0; i < cPrefetchAddresses; i++) {
VmmObDataSet_Put(pObPrefetchAddresses, pPrefetchAddresses[i] & ~0xfff);
}
VmmCachePrefetchPages(pObProcess, pObPrefetchAddresses);
result = TRUE;
fail:
VmmOb_DECREF(pObPrefetchAddresses);
VmmOb_DECREF(pObProcess);
return result;
}
_Success_(return)
BOOL VMMDLL_MemPrefetchPages(_In_ DWORD dwPID, _In_reads_(cPrefetchAddresses) PULONG64 pPrefetchAddresses, _In_ DWORD cPrefetchAddresses)
{
CALL_SYNCHRONIZED_IMPLEMENTATION_VMM(
STATISTICS_ID_VMMDLL_MemPrefetchPages,
VMMDLL_MemPrefetchPages_Impl(dwPID, pPrefetchAddresses, cPrefetchAddresses))
}
_Success_(return)
BOOL VMMDLL_MemWrite_Impl(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _In_ PBYTE pb, _In_ DWORD cb)
{
@@ -873,7 +910,7 @@ BOOL VMMDLL_ProcessGet_Directories_Sections_IAT_EAT_Impl(
i = PE_EatGetNumberOf(pObProcess, pModule->BaseAddress);
if(!pEAT) { *pcData = i; goto success; }
if(cData < i) { goto fail; }
VmmWin_PE_LoadEAT_DisplayBuffer(pObProcess, pModule, (PVMMPROC_WINDOWS_EAT_ENTRY)pEAT, &cData);
VmmWin_PE_LoadEAT_DisplayBuffer(pObProcess, pModule, (PVMMPROC_WINDOWS_EAT_ENTRY)pEAT, cData, &cData);
*pcData = cData;
goto success;
}
@@ -882,7 +919,7 @@ BOOL VMMDLL_ProcessGet_Directories_Sections_IAT_EAT_Impl(
i = PE_IatGetNumberOf(pObProcess, pModule->BaseAddress);
if(!pIAT) { *pcData = i; goto success; }
if(cData < i) { goto fail; }
VmmWin_PE_LoadIAT_DisplayBuffer(pObProcess, pModule, (PVMMWIN_IAT_ENTRY)pIAT, &cData);
VmmWin_PE_LoadIAT_DisplayBuffer(pObProcess, pModule, (PVMMWIN_IAT_ENTRY)pIAT, cData, &cData);
*pcData = cData;
goto success;
}
@@ -928,6 +965,107 @@ BOOL VMMDLL_ProcessGetIAT(_In_ DWORD dwPID, _In_ LPSTR szModule, _Out_opt_ PVMMD
VMMDLL_ProcessGet_Directories_Sections_IAT_EAT_Impl(dwPID, szModule, cData, pcData, NULL, NULL, NULL, pData, FALSE, FALSE, FALSE, TRUE))
}
ULONG64 VMMDLL_ProcessGetProcAddress_Impl(_In_ DWORD dwPID, _In_ LPSTR szModuleName, _In_ LPSTR szFunctionName)
{
QWORD vaFn = 0;
VMMDLL_MODULEMAP_ENTRY oModuleEntry = { 0 };
PVMM_PROCESS pObProcess = NULL;
pObProcess = VmmProcessGet(dwPID);
if(!pObProcess) { return 0; }
if(VMMDLL_ProcessGetModuleFromName_Impl(dwPID, szModuleName, &oModuleEntry)) {
vaFn = PE_GetProcAddress(pObProcess, oModuleEntry.BaseAddress, szFunctionName);
}
VmmOb_DECREF(pObProcess);
return vaFn;
}
ULONG64 VMMDLL_ProcessGetProcAddress(_In_ DWORD dwPID, _In_ LPSTR szModuleName, _In_ LPSTR szFunctionName)
{
CALL_SYNCHRONIZED_IMPLEMENTATION_VMM_RETURN(
STATISTICS_ID_VMMDLL_ProcessGetIAT,
ULONG64,
0,
VMMDLL_ProcessGetProcAddress_Impl(dwPID, szModuleName, szFunctionName))
}
ULONG64 VMMDLL_ProcessGetModuleBase_Impl(_In_ DWORD dwPID, _In_ LPSTR szModuleName)
{
QWORD vaModuleBase = 0;
VMMDLL_MODULEMAP_ENTRY oModuleEntry = { 0 };
PVMM_PROCESS pObProcess = NULL;
pObProcess = VmmProcessGet(dwPID);
if(!pObProcess) { return 0; }
if(VMMDLL_ProcessGetModuleFromName_Impl(dwPID, szModuleName, &oModuleEntry)) {
vaModuleBase = oModuleEntry.BaseAddress;
}
VmmOb_DECREF(pObProcess);
return vaModuleBase;
}
ULONG64 VMMDLL_ProcessGetModuleBase(_In_ DWORD dwPID, _In_ LPSTR szModuleName)
{
CALL_SYNCHRONIZED_IMPLEMENTATION_VMM_RETURN(
STATISTICS_ID_VMMDLL_ProcessGetModuleBase,
ULONG64,
0,
VMMDLL_ProcessGetModuleBase_Impl(dwPID, szModuleName))
}
_Success_(return)
BOOL VMMDLL_WinGetThunkInfoEAT_Impl(_In_ DWORD dwPID, _In_ LPSTR szModuleName, _In_ LPSTR szExportFunctionName, _Out_ PVMMDLL_WIN_THUNKINFO_EAT pThunkInfoEAT)
{
BOOL result;
VMMDLL_MODULEMAP_ENTRY oModuleEntry = { 0 };
PVMM_PROCESS pObProcess = NULL;
pObProcess = VmmProcessGet(dwPID);
if(!pObProcess) { return 0; }
if(VMMDLL_ProcessGetModuleFromName_Impl(dwPID, szModuleName, &oModuleEntry)) {
result = PE_GetThunkInfoEAT(pObProcess, oModuleEntry.BaseAddress, szExportFunctionName, (PPE_THUNKINFO_EAT)pThunkInfoEAT);
}
VmmOb_DECREF(pObProcess);
return result;
}
_Success_(return)
BOOL VMMDLL_WinGetThunkInfoEAT(_In_ DWORD dwPID, _In_ LPSTR szModuleName, _In_ LPSTR szExportFunctionName, _Out_ PVMMDLL_WIN_THUNKINFO_EAT pThunkInfoEAT)
{
CALL_SYNCHRONIZED_IMPLEMENTATION_VMM(
STATISTICS_ID_VMMDLL_WinGetThunkEAT,
VMMDLL_WinGetThunkInfoEAT_Impl(dwPID, szModuleName, szExportFunctionName, pThunkInfoEAT))
}
_Success_(return)
BOOL VMMDLL_WinGetThunkInfoIAT_Impl(_In_ DWORD dwPID, _In_ LPSTR szModuleName, _In_ LPSTR szImportModuleName, _In_ LPSTR szImportFunctionName, _Out_ PVMMDLL_WIN_THUNKINFO_IAT pThunkInfoIAT)
{
BOOL result = FALSE;
VMMDLL_MODULEMAP_ENTRY oModuleEntry = { 0 };
PVMM_PROCESS pObProcess = NULL;
if(sizeof(VMMDLL_WIN_THUNKINFO_IAT) != sizeof(PE_THUNKINFO_IAT)) { return FALSE; }
pObProcess = VmmProcessGet(dwPID);
if(!pObProcess) { return 0; }
if(VMMDLL_ProcessGetModuleFromName_Impl(dwPID, szModuleName, &oModuleEntry)) {
result = PE_GetThunkInfoIAT(pObProcess, oModuleEntry.BaseAddress, szImportModuleName, szImportFunctionName, (PPE_THUNKINFO_IAT)pThunkInfoIAT);
}
VmmOb_DECREF(pObProcess);
return result;
}
_Success_(return)
BOOL VMMDLL_WinGetThunkInfoIAT(_In_ DWORD dwPID, _In_ LPSTR szModuleName, _In_ LPSTR szImportModuleName, _In_ LPSTR szImportFunctionName, _Out_ PVMMDLL_WIN_THUNKINFO_IAT pThunkInfoIAT)
{
CALL_SYNCHRONIZED_IMPLEMENTATION_VMM(
STATISTICS_ID_VMMDLL_WinGetThunkIAT,
VMMDLL_WinGetThunkInfoIAT_Impl(dwPID, szModuleName, szImportModuleName, szImportFunctionName, pThunkInfoIAT))
}
_Success_(return)
BOOL VMMDLL_WinMemCompression_DecompressPage(_In_ ULONG64 vaCompressedData, _In_opt_ DWORD cbCompressedData, _Out_writes_(4096) PBYTE pbDecompressedPage, _Out_opt_ PDWORD pcbCompressedData)
{
CALL_SYNCHRONIZED_IMPLEMENTATION_VMM(
STATISTICS_ID_VMMDLL_WinMemCompression_DecompressPage,
MmX64WinPaged_MemCompression_DecompressPage(vaCompressedData, cbCompressedData, pbDecompressedPage, pcbCompressedData))
}
_Success_(return)
BOOL VMMDLL_UtilFillHexAscii(_In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset, _Inout_opt_ LPSTR sz, _Out_ PDWORD pcsz)
{

View File

@@ -23,6 +23,7 @@ EXPORTS
VMMDLL_MemReadPage
VMMDLL_MemRead
VMMDLL_MemReadEx
VMMDLL_MemPrefetchPages
VMMDLL_MemWrite
VMMDLL_MemVirt2Phys
@@ -38,5 +39,11 @@ EXPORTS
VMMDLL_ProcessGetSections
VMMDLL_ProcessGetEAT
VMMDLL_ProcessGetIAT
VMMDLL_ProcessGetProcAddress
VMMDLL_ProcessGetModuleBase
VMMDLL_WinGetThunkInfoIAT
VMMDLL_WinGetThunkInfoEAT
VMMDLL_WinMemCompression_DecompressPage
VMMDLL_UtilFillHexAscii

View File

@@ -4,7 +4,7 @@
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, pcileech@frizk.net
//
// Header Version: 2.0
// Header Version: 2.1
//
#include <windows.h>
@@ -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: <file>, 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
@@ -289,7 +291,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 +324,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 +541,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
);
//-----------------------------------------------------------------------------

View File

@@ -230,11 +230,9 @@ BOOL VmmProcPHYS_ScanForKernel(_Out_ PQWORD ppaPML4, _In_ QWORD paBase, _In_ QWO
LEECHCORE_PAGESTAT_MINIMAL PageStatMinimal;
BOOL result;
// initialize / allocate memory
pbBuffer8M = LocalAlloc(0, 0x800000);
pPageStat = (PPAGE_STATISTICS)LocalAlloc(LMEM_ZEROINIT, sizeof(PAGE_STATISTICS));
if(!pbBuffer8M || !pPageStat) { goto fail; }
paCurrent = paBase;
PageStatInitialize(pPageStat, paCurrent, paMax, szDescription, FALSE, FALSE);
if(!(pbBuffer8M = LocalAlloc(0, 0x800000))) { goto fail; }
if(!PageStatInitialize(&pPageStat, paCurrent, paMax, szDescription, FALSE, FALSE)) { goto fail; }
PageStatMinimal.h = (HANDLE)pPageStat;
PageStatMinimal.pfnPageStatUpdate = PageStatUpdate;
// loop kmd-find
@@ -247,8 +245,7 @@ BOOL VmmProcPHYS_ScanForKernel(_Out_ PQWORD ppaPML4, _In_ QWORD paBase, _In_ QWO
result = VmmProcPHYS_VerifyWindowsEPROCESS(pbBuffer8M, 0x00800000, o + i, ppaPML4);
if(result) {
pPageStat->szAction = "Windows System PageDirectoryBase/PML4 located";
PageStatClose(pPageStat);
LocalFree(pPageStat);
PageStatClose(&pPageStat);
LocalFree(pbBuffer8M);
return TRUE;
}
@@ -257,8 +254,7 @@ BOOL VmmProcPHYS_ScanForKernel(_Out_ PQWORD ppaPML4, _In_ QWORD paBase, _In_ QWO
}
}
fail:
if(pPageStat) { PageStatClose(pPageStat); }
LocalFree(pPageStat);
PageStatClose(&pPageStat);
LocalFree(pbBuffer8M);
*ppaPML4 = 0;
return FALSE;

View File

@@ -126,8 +126,8 @@ VOID VmmWin_PE_DIRECTORY_DisplayBuffer(
}
}
VOID VmmWin_PE_LoadEAT_DisplayBuffer(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_MODULEMAP_ENTRY pModule, _Out_writes_opt_(*pcEATs) PVMMPROC_WINDOWS_EAT_ENTRY pEATs, _Inout_ PDWORD pcEATs)
_Success_(return)
BOOL VmmWin_PE_LoadEAT_DisplayBuffer(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MODULEMAP_ENTRY pModule, _Out_writes_opt_(cEATs) PVMMPROC_WINDOWS_EAT_ENTRY pEATs, _In_ DWORD cEATs, _Out_ PDWORD pcEATs)
{
BYTE pbModuleHeader[0x1000] = { 0 };
PIMAGE_NT_HEADERS64 ntHeader64;
@@ -138,10 +138,9 @@ VOID VmmWin_PE_LoadEAT_DisplayBuffer(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM
QWORD i, oNameOrdinal, ooName, oName, oFunction, wOrdinalFnIdx;
DWORD vaFunctionOffset;
BOOL fHdr32;
DWORD cEATs = *pcEATs;
*pcEATs = 0;
// load both 32/64 bit ntHeader (only one will be valid)
if(!(ntHeader64 = VmmWin_GetVerifyHeaderPE(pProcess, pModule->BaseAddress, pbModuleHeader, &fHdr32))) { goto cleanup; }
if(!(ntHeader64 = VmmWin_GetVerifyHeaderPE(pProcess, pModule->BaseAddress, pbModuleHeader, &fHdr32))) { goto fail; }
ntHeader32 = (PIMAGE_NT_HEADERS32)ntHeader64;
// Load Export Address Table (EAT)
oExportDirectory = fHdr32 ?
@@ -150,9 +149,9 @@ VOID VmmWin_PE_LoadEAT_DisplayBuffer(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM
cbExportDirectory = fHdr32 ?
ntHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size :
ntHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
if(!oExportDirectory || !cbExportDirectory || cbExportDirectory > 0x01000000) { goto cleanup; }
if(!(pbExportDirectory = LocalAlloc(0, cbExportDirectory))) { goto cleanup; }
if(!VmmRead(pProcess, pModule->BaseAddress + oExportDirectory, pbExportDirectory, (DWORD)cbExportDirectory)) { goto cleanup; }
if(!oExportDirectory || !cbExportDirectory || cbExportDirectory > 0x01000000) { goto fail; }
if(!(pbExportDirectory = LocalAlloc(0, cbExportDirectory))) { goto fail; }
if(!VmmRead(pProcess, pModule->BaseAddress + oExportDirectory, pbExportDirectory, (DWORD)cbExportDirectory)) { goto fail; }
// Walk exported functions
pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)pbExportDirectory;
for(i = 0; i < pExportDirectory->NumberOfNames && i < cEATs; i++) {
@@ -175,11 +174,14 @@ VOID VmmWin_PE_LoadEAT_DisplayBuffer(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM
strncpy_s(pEATs[i].szFunction, 40, (LPSTR)(pbExportDirectory - oExportDirectory + oName), _TRUNCATE);
}
*pcEATs = (DWORD)i;
cleanup:
LocalFree(pbExportDirectory);
return TRUE;
fail:
LocalFree(pbExportDirectory);
return FALSE;
}
VOID VmmWin_PE_LoadIAT_DisplayBuffer(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_MODULEMAP_ENTRY pModule, _Out_writes_(*pcIATs) PVMMWIN_IAT_ENTRY pIATs, _Inout_ PDWORD pcIATs)
VOID VmmWin_PE_LoadIAT_DisplayBuffer(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MODULEMAP_ENTRY pModule, _Out_writes_(*pcIATs) PVMMWIN_IAT_ENTRY pIATs, _In_ DWORD cIATs, _Out_ PDWORD pcIATs)
{
BYTE pbModuleHeader[0x1000] = { 0 };
PIMAGE_NT_HEADERS64 ntHeader64;
@@ -191,7 +193,7 @@ VOID VmmWin_PE_LoadIAT_DisplayBuffer(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM
PBYTE pbModule;
DWORD cbModule, cbRead;
BOOL fHdr32, fFnName;
DWORD c, j, cIATs = *pcIATs;
DWORD c, j;
*pcIATs = 0;
// Load the module
if(pModule->SizeOfImage > 0x02000000) { return; }
@@ -325,7 +327,7 @@ VOID VmmWin_ScanLdrModules64(_In_ PVMM_PROCESS pProcess, _Inout_ PVMM_MODULEMAP_
DWORD iModuleLdr;
// prefetch existing addresses (if any) & allocate new vaModuleLdr DataSet
pObDataSet_vaModuleLdr = VmmObContainer_GetOb(&pProcess->pObProcessPersistent->ObCLdrModulesCachePrefetch64);
VmmCachePrefetch(pProcess, pObDataSet_vaModuleLdr);
VmmCachePrefetchPages(pProcess, pObDataSet_vaModuleLdr);
VmmOb_DECREF(pObDataSet_vaModuleLdr);
pObDataSet_vaModuleLdr = VmmObDataSet_Alloc(TRUE);
if(!pObDataSet_vaModuleLdr) { goto fail; }
@@ -453,7 +455,7 @@ BOOL VmmWin_ScanLdrModules32(_In_ PVMM_PROCESS pProcess, _Inout_ PVMM_MODULEMAP_
DWORD iModuleLdr;
// prefetch existing addresses (if any) & allocate new vaModuleLdr DataSet
pObDataSet_vaModuleLdr = VmmObContainer_GetOb(&pProcess->pObProcessPersistent->ObCLdrModulesCachePrefetch32);
VmmCachePrefetch(pProcess, pObDataSet_vaModuleLdr);
VmmCachePrefetchPages(pProcess, pObDataSet_vaModuleLdr);
VmmOb_DECREF(pObDataSet_vaModuleLdr);
pObDataSet_vaModuleLdr = VmmObDataSet_Alloc(TRUE);
if(!pObDataSet_vaModuleLdr) { goto fail; }
@@ -955,15 +957,15 @@ VOID VmmWin_OffsetLocatorEPROCESS64(_In_ PVMM_PROCESS pSystemProcess)
// find offset for PEB (in EPROCESS)
for(i = 0x300, f = FALSE; i < 0x480; i += 8) {
if(*(PQWORD)(pb0 + i)) { continue; }
vaPEB = *(PQWORD)(pb1 + i);
if(!vaPEB || (vaPEB & 0xffff800000000fff)) { continue; }
// Verify potential PEB
if(!VmmVirt2PhysEx(*(PQWORD)(pb1 + pOffsetEPROCESS->DTB), TRUE, vaPEB, &paPEB)) { continue; }
if(!VmmReadPhysicalPage(paPEB, pbPage)) { continue; }
if(*(PWORD)pbPage == 0x5a4d) { continue; } // MZ header -> likely entry point or something not PEB ...
pOffsetEPROCESS->PEB = i;
f = TRUE;
break;
vaPEB = *(PQWORD)(pb1 + i);
if(!vaPEB || (vaPEB & 0xffff800000000fff)) { continue; }
// Verify potential PEB
if(!VmmVirt2PhysEx(*(PQWORD)(pb1 + pOffsetEPROCESS->DTB), TRUE, vaPEB, &paPEB)) { continue; }
if(!VmmReadPhysicalPage(paPEB, pbPage)) { continue; }
if(*(PWORD)pbPage == 0x5a4d) { continue; } // MZ header -> likely entry point or something not PEB ...
pOffsetEPROCESS->PEB = i;
f = TRUE;
break;
}
if(!f) { return; }
// find "optional" offset for user cr3/pml4 (post meltdown only)
@@ -1016,7 +1018,7 @@ BOOL VmmWin_EnumerateEPROCESS64(_In_ PVMM_PROCESS pSystemProcess, _In_ BOOL fTot
PVMM_PROCESS pObProcess = NULL;
QWORD vaSystemEPROCESS, vaEPROCESS, cNewProcessCollision = 0;
DWORD iProc = 0;
BOOL fShowTerminated;
BOOL fShowTerminated, fUser;
PVMM_WIN_EPROCESS_OFFSET pOffsetEPROCESS = &ctxVmm->kernel.OffsetEPROCESS;
PVMMOB_DATASET pObSetAddressEPROCESS = NULL;
fShowTerminated = ctxVmm->flags & VMM_FLAG_PROCESS_SHOW_TERMINATED;
@@ -1040,7 +1042,7 @@ BOOL VmmWin_EnumerateEPROCESS64(_In_ PVMM_PROCESS pSystemProcess, _In_ BOOL fTot
pqwPEB = (PQWORD)(pb + pOffsetEPROCESS->PEB);
// prefetch pages into cache (if any)
pObSetAddressEPROCESS = VmmObContainer_GetOb(&ctxVmm->ObCEPROCESSCachePrefetch);
VmmCachePrefetch(pSystemProcess, pObSetAddressEPROCESS);
VmmCachePrefetchPages(pSystemProcess, pObSetAddressEPROCESS);
VmmOb_DECREF(pObSetAddressEPROCESS);
// initialize address set
if(!(pObSetAddressEPROCESS = VmmObDataSet_Alloc(TRUE))) { return FALSE; }
@@ -1054,6 +1056,9 @@ BOOL VmmWin_EnumerateEPROCESS64(_In_ PVMM_PROCESS pSystemProcess, _In_ BOOL fTot
VmmOb_DECREF(pObProcess);
pObProcess = NULL;
if(*pqwDTB && *(PQWORD)szName && (fShowTerminated || !*pdwState)) {
fUser =
!((*pdwPID == 4) || ((*pdwState == 0) && (*pqwPEB == 0))) ||
(*(PQWORD)(szName + 0x00) == 0x72706d6f436d654d) && (*(PDWORD)(szName + 0x08) == 0x69737365); // MemCompression "process"
pObProcess = VmmProcessCreateEntry(
fTotalRefresh,
*pdwPID,
@@ -1061,7 +1066,7 @@ BOOL VmmWin_EnumerateEPROCESS64(_In_ PVMM_PROCESS pSystemProcess, _In_ BOOL fTot
~0xfff & *pqwDTB,
pOffsetEPROCESS->DTB_User ? (~0xfff & *pqwDTB_User) : 0,
szName,
!((*pdwPID == 4) || ((*pdwState == 0) && (*pqwPEB == 0))));
fUser);
if(!pObProcess) {
vmmprintfv("VMM: WARNING: PID '%i' already exists.\n", *pdwPID);
if(++cNewProcessCollision >= 8) {
@@ -1233,7 +1238,7 @@ BOOL VmmWin_EnumerateEPROCESS32(_In_ PVMM_PROCESS pSystemProcess, _In_ BOOL fTot
PVMM_PROCESS pObProcess = NULL;
DWORD vaSystemEPROCESS, vaEPROCESS, cPID = 0, cNewProcessCollision = 0;
DWORD iProc = 0;
BOOL fShowTerminated;
BOOL fShowTerminated, fUser;
PVMM_WIN_EPROCESS_OFFSET pOffsetEPROCESS = &ctxVmm->kernel.OffsetEPROCESS;
PVMMOB_DATASET pObSetAddressEPROCESS = NULL;
fShowTerminated = ctxVmm->flags & VMM_FLAG_PROCESS_SHOW_TERMINATED;
@@ -1257,7 +1262,7 @@ BOOL VmmWin_EnumerateEPROCESS32(_In_ PVMM_PROCESS pSystemProcess, _In_ BOOL fTot
pdwPEB = (PDWORD)(pb + pOffsetEPROCESS->PEB);
// prefetch pages into cache (if any)
pObSetAddressEPROCESS = VmmObContainer_GetOb(&ctxVmm->ObCEPROCESSCachePrefetch);
VmmCachePrefetch(pSystemProcess, pObSetAddressEPROCESS);
VmmCachePrefetchPages(pSystemProcess, pObSetAddressEPROCESS);
VmmOb_DECREF(pObSetAddressEPROCESS);
// initialize address set
if(!(pObSetAddressEPROCESS = VmmObDataSet_Alloc(TRUE))) { return FALSE; }
@@ -1272,6 +1277,9 @@ BOOL VmmWin_EnumerateEPROCESS32(_In_ PVMM_PROCESS pSystemProcess, _In_ BOOL fTot
VmmOb_DECREF(pObProcess);
pObProcess = NULL;
if(*pdwDTB && *(PQWORD)szName && (fShowTerminated || !*pdwState)) {
fUser =
!((*pdwPID == 4) || ((*pdwState == 0) && (*pdwPEB == 0))) ||
((*(PQWORD)(szName + 0x00) == 0x72706d6f436d654d) && (*(PDWORD)(szName + 0x08) == 0x69737365)); // MemCompression "process"
pObProcess = VmmProcessCreateEntry(
fTotalRefresh,
*pdwPID,
@@ -1279,7 +1287,7 @@ BOOL VmmWin_EnumerateEPROCESS32(_In_ PVMM_PROCESS pSystemProcess, _In_ BOOL fTot
*pdwDTB & 0xffffffe0,
pOffsetEPROCESS->DTB_User ? (~0xfff & *pdwDTB_User) : 0,
szName,
!((*pdwPID == 4) || ((*pdwState == 0) && (*pdwPEB == 0))));
fUser);
}
if(pObProcess) {
pObProcess->os.win.vaEPROCESS = vaEPROCESS;

View File

@@ -36,9 +36,12 @@ VOID VmmWin_PE_SetSizeSectionIATEAT_DisplayBuffer(_In_ PVMM_PROCESS pProcess, _I
* -- pProcess
* -- pModule
* -- pEATs
* -- pcEATs = number max items of pEATs on entry, number of actual items of pEATs on exit
* -- cEATs
* -- pcEATs = number of actual items of pEATs written.
* -- return
*/
VOID VmmWin_PE_LoadEAT_DisplayBuffer(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_MODULEMAP_ENTRY pModule, _Out_writes_opt_(*pcEATs) PVMMPROC_WINDOWS_EAT_ENTRY pEATs, _Inout_ PDWORD pcEATs);
_Success_(return)
BOOL VmmWin_PE_LoadEAT_DisplayBuffer(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MODULEMAP_ENTRY pModule, _Out_writes_opt_(cEATs) PVMMPROC_WINDOWS_EAT_ENTRY pEATs, _In_ DWORD cEATs, _Out_ PDWORD pcEATs);
/*
* Walk the import address table (IAT) from a given pProcess and store it in the
@@ -46,9 +49,10 @@ VOID VmmWin_PE_LoadEAT_DisplayBuffer(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM
* -- pProcess
* -- pModule
* -- pIATs
* -- pcIATs = number max items of pIATs on entry, number of actual items of pIATs on exit
* -- cIATs
* -- pcIATs = number of actual items of pIATs on exit
*/
VOID VmmWin_PE_LoadIAT_DisplayBuffer(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_MODULEMAP_ENTRY pModule, _Out_writes_(*pcIATs) PVMMWIN_IAT_ENTRY pIATs, _Inout_ PDWORD pcIATs);
VOID VmmWin_PE_LoadIAT_DisplayBuffer(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MODULEMAP_ENTRY pModule, _Out_writes_(*pcIATs) PVMMWIN_IAT_ENTRY pIATs, _In_ DWORD cIATs, _Out_ PDWORD pcIATs);
/*
* Fill the pbDisplayBuffer with a human readable version of the data directories.

View File

@@ -456,7 +456,7 @@ fail:
*/
BOOL VmmWinInit_TryInitialize(_In_opt_ QWORD paDTBOpt)
{
PVMM_PROCESS pObSystemProcess = NULL;
PVMM_PROCESS pObSystemProcess = NULL, pObProcess = NULL;
QWORD vaPsInitialSystemProcess, vaSystemEPROCESS;
// Fetch Directory Base (DTB (PML4)) and initialize Memory Model.
if(paDTBOpt) {
@@ -503,6 +503,14 @@ BOOL VmmWinInit_TryInitialize(_In_opt_ QWORD paDTBOpt)
// Optionally fetch PsLoadedModuleList / KDBG
VmmWinInit_FindPsLoadedModuleListKDBG(pObSystemProcess);
VmmOb_DECREF(pObSystemProcess);
// Optionally retrieve PID of MemCompression process
while((pObProcess = VmmProcessGetNext(pObProcess))) {
if(memcmp("MemCompression", pObProcess->szName, 15)) { continue; }
ctxVmm->kernel.dwPidMemCompression = pObProcess->dwPID;
VmmOb_DECREF(pObProcess);
pObProcess = NULL;
break;
}
return TRUE;
fail:
VmmInitializeMemoryModel(VMM_MEMORYMODEL_NA); // clean memory model

View File

@@ -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://<non_default_path_to_file_winpmem_x64.sys>
// PMEM (use att_winpmem_64.sys in directory of executable)
// PMEM://<non_default_path_to_file_winpmem_64.sys>
//
// 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

View File

@@ -4,7 +4,7 @@
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, pcileech@frizk.net
//
// Header Version: 2.0
// Header Version: 2.1
//
#include <windows.h>
@@ -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: <file>, 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
@@ -289,7 +291,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 +324,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 +541,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
);
//-----------------------------------------------------------------------------

View File

@@ -64,6 +64,8 @@ int main(_In_ int argc, _In_ char* argv[])
BOOL result;
NTSTATUS nt;
DWORD i, dwPID;
DWORD dw = 0;
QWORD va;
BYTE pbPage1[0x1000], pbPage2[0x1000];
#ifdef _INITIALIZE_FROM_FILE
@@ -86,12 +88,12 @@ int main(_In_ int argc, _In_ char* argv[])
printf("------------------------------------------------------------\n");
printf("#01: Initialize from TotalMeltdown: \n");
ShowKeyPress();
printf("CALL: VMMDLL_InitializeTotalMeltdown\n");
result = VMMDLL_InitializeTotalMeltdown();
printf("CALL: VMMDLL_Initialize\n");
result = result = VMMDLL_Initialize(3, (LPSTR[]) { "", "-device", "totalmeltdown" });
if(result) {
printf("SUCCESS: VMMDLL_InitializeTotalMeltdown\n");
printf("SUCCESS: VMMDLL_Initialize\n");
} else {
printf("FAIL: VMMDLL_InitializeTotalMeltdown\n");
printf("FAIL: VMMDLL_Initialize\n");
return 1;
}
#endif /* _INITIALIZE_FROM_TOTALMELTDOWN */
@@ -101,12 +103,12 @@ int main(_In_ int argc, _In_ char* argv[])
printf("------------------------------------------------------------\n");
printf("#01: Initialize from FPGA: \n");
ShowKeyPress();
printf("CALL: VMMDLL_InitializeFPGA\n");
result = VMMDLL_InitializeFPGA(NULL, NULL);
printf("CALL: VMMDLL_Initialize\n");
result = VMMDLL_Initialize(3, (LPSTR[]) { "", "-device", "fpga" });
if(result) {
printf("SUCCESS: VMMDLL_InitializeFPGA\n");
printf("SUCCESS: VMMDLL_Initialize\n");
} else {
printf("FAIL: VMMDLL_InitializeFPGA\n");
printf("FAIL: VMMDLL_Initialize\n");
return 1;
}
// Retrieve the ID of the FPPA (SP605/PCIeScreamer/AC701 ...) and the bitstream version
@@ -572,6 +574,78 @@ int main(_In_ int argc, _In_ char* argv[])
}
// Get base virtual address of ntoskrnl.exe
printf("------------------------------------------------------------\n");
printf("#17: get ntoskrnl.exe base virtual address \n");
ShowKeyPress();
printf("CALL: VMMDLL_ProcessGetModuleBase\n");
va = VMMDLL_ProcessGetModuleBase(4, "ntoskrnl.exe");
if(va) {
printf("SUCCESS: VMMDLL_ProcessGetModuleBase\n");
printf(" %s = %016llx\n", "ntoskrnl.exe", va);
} else {
printf("FAIL: VMMDLL_ProcessGetModuleBase\n");
return 1;
}
// GetProcAddress from ntoskrnl.exe
printf("------------------------------------------------------------\n");
printf("#18: get proc address for ntoskrnl.exe!KeGetCurrentIrql \n");
ShowKeyPress();
printf("CALL: VMMDLL_ProcessGetProcAddress\n");
va = VMMDLL_ProcessGetProcAddress(4, "ntoskrnl.exe", "KeGetCurrentIrql");
if(va) {
printf("SUCCESS: VMMDLL_ProcessGetProcAddress\n");
printf(" %s!%s = %016llx\n", "ntoskrnl.exe", "KeGetCurrentIrql", va);
} else {
printf("FAIL: VMMDLL_ProcessGetProcAddress\n");
return 1;
}
// Get EAT Thunk from ntoskrnl.exe!KeGetCurrentIrql
printf("------------------------------------------------------------\n");
printf("#19: Address of EAT thunk for ntoskrnl.exe!KeGetCurrentIrql \n");
ShowKeyPress();
VMMDLL_WIN_THUNKINFO_EAT oThunkInfoEAT;
ZeroMemory(&oThunkInfoEAT, sizeof(VMMDLL_WIN_THUNKINFO_EAT));
printf("CALL: VMMDLL_WinGetThunkInfoEAT\n");
result = VMMDLL_WinGetThunkInfoEAT(4, "ntoskrnl.exe", "KeGetCurrentIrql", &oThunkInfoEAT);
if(result) {
printf("SUCCESS: VMMDLL_WinGetThunkInfoEAT\n");
printf(" vaFunction: %016llx\n", oThunkInfoEAT.vaFunction);
printf(" vaThunk: %016llx\n", oThunkInfoEAT.vaThunk);
printf(" valueThunk: %08x\n", oThunkInfoEAT.valueThunk);
printf(" vaNameFunc: %016llx\n", oThunkInfoEAT.vaNameFunction);
} else {
printf("FAIL: VMMDLL_WinGetThunkInfoEAT\n");
return 1;
}
// Get IAT Thunk ntoskrnl.exe -> hal.dll!HalSendNMI
printf("------------------------------------------------------------\n");
printf("#20: Address of IAT thunk for hal.dll!HalSendNMI in ntoskrnl\n");
ShowKeyPress();
VMMDLL_WIN_THUNKINFO_IAT oThunkInfoIAT;
ZeroMemory(&oThunkInfoIAT, sizeof(VMMDLL_WIN_THUNKINFO_IAT));
printf("CALL: VMMDLL_WinGetThunkInfoIAT\n");
result = VMMDLL_WinGetThunkInfoIAT(4, "ntoskrnl.Exe", "hal.Dll", "HalSendNMI", &oThunkInfoIAT);
if(result) {
printf("SUCCESS: VMMDLL_WinGetThunkInfoIAT\n");
printf(" vaFunction: %016llx\n", oThunkInfoIAT.vaFunction);
printf(" vaThunk: %016llx\n", oThunkInfoIAT.vaThunk);
printf(" vaNameFunction: %016llx\n", oThunkInfoIAT.vaNameFunction);
printf(" vaNameModule: %016llx\n", oThunkInfoIAT.vaNameModule);
}
else {
printf("FAIL: VMMDLL_WinGetThunkInfoEAT\n");
return 1;
}
// Finish everything and exit!
printf("------------------------------------------------------------\n");
printf("#99: FINISHED EXAMPLES! \n");

View File

@@ -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://<non_default_path_to_file_winpmem_x64.sys>
// PMEM (use att_winpmem_64.sys in directory of executable)
// PMEM://<non_default_path_to_file_winpmem_64.sys>
//
// 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

View File

@@ -2,7 +2,7 @@
#define STRINGIZE(s) STRINGIZE2(s)
#define VERSION_MAJOR 2
#define VERSION_MINOR 0
#define VERSION_MINOR 1
#define VERSION_REVISION 0
#define VERSION_BUILD 0

View File

@@ -4,7 +4,7 @@
// (c) Ulf Frisk, 2018-2019
// Author: Ulf Frisk, pcileech@frizk.net
//
// Header Version: 2.0
// Header Version: 2.1
//
#include <windows.h>
@@ -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: <file>, 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
@@ -289,7 +291,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 +324,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 +541,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
);
//-----------------------------------------------------------------------------

View File

@@ -48,6 +48,16 @@ VMMPYC_Initialize(PyObject *self, PyObject *args)
return Py_BuildValue("s", NULL); // None returned on success.
}
// () -> None
static PyObject*
VMMPYC_Close(PyObject *self, PyObject *args)
{
Py_BEGIN_ALLOW_THREADS;
VMMDLL_Close();
Py_END_ALLOW_THREADS;
return Py_BuildValue("s", NULL); // None returned on success.
}
//-----------------------------------------------------------------------------
@@ -63,9 +73,9 @@ VMMPYC_ConfigGet(PyObject *self, PyObject *args)
BOOL result;
ULONG64 fOption, qwValue = 0;
if(!PyArg_ParseTuple(args, "K", &fOption)) { return NULL; }
Py_BEGIN_ALLOW_THREADS
Py_BEGIN_ALLOW_THREADS;
result = VMMDLL_ConfigGet(fOption, &qwValue);
Py_END_ALLOW_THREADS
Py_END_ALLOW_THREADS;
if(!result) { return PyErr_Format(PyExc_RuntimeError, "VMMPYC_ConfigGet: Unable to retrieve config value for setting."); }
return PyLong_FromUnsignedLongLong(qwValue);
}
@@ -77,9 +87,9 @@ VMMPYC_ConfigSet(PyObject *self, PyObject *args)
BOOL result;
ULONG64 fOption, qwValue = 0;
if(!PyArg_ParseTuple(args, "KK", &fOption, &qwValue)) { return NULL; }
Py_BEGIN_ALLOW_THREADS
Py_BEGIN_ALLOW_THREADS;
result = VMMDLL_ConfigSet(fOption, qwValue);
Py_END_ALLOW_THREADS
Py_END_ALLOW_THREADS;
if(!result) { return PyErr_Format(PyExc_RuntimeError, "VMMPYC_ConfigSet: Unable to set config value for setting."); }
return Py_BuildValue("s", NULL); // None returned on success.
}
@@ -139,9 +149,9 @@ VMMPYC_MemReadScatter(PyObject *self, PyObject *args)
}
Py_DECREF(pyListSrc);
// call c-dll for vmm
Py_BEGIN_ALLOW_THREADS
Py_BEGIN_ALLOW_THREADS;
result = VMMDLL_MemReadScatter(dwPID, ppMEMs, cMEMs, flags);
Py_END_ALLOW_THREADS
Py_END_ALLOW_THREADS;
if(!result) {
LocalFree(pb);
return PyErr_Format(PyExc_RuntimeError, "VMMPYC_MemReadScatter: Failed.");
@@ -177,9 +187,9 @@ VMMPYC_MemRead(PyObject *self, PyObject *args)
if(cb > 0x01000000) { return PyErr_Format(PyExc_RuntimeError, "VMMPYC_MemRead: Read larger than maxium supported (0x01000000) bytes requested."); }
pb = LocalAlloc(0, cb);
if(!pb) { return PyErr_NoMemory(); }
Py_BEGIN_ALLOW_THREADS
Py_BEGIN_ALLOW_THREADS;
result = VMMDLL_MemReadEx(dwPID, qwA, pb, cb, &cbRead, flags);
Py_END_ALLOW_THREADS
Py_END_ALLOW_THREADS;
if(!result) {
LocalFree(pb);
return PyErr_Format(PyExc_RuntimeError, "VMMPYC_MemRead: Failed.");
@@ -213,10 +223,10 @@ VMMPYC_MemWrite(PyObject *self, PyObject *args)
}
iResult = PyBuffer_ToContiguous(pb, &pyBuffer, cb, 'C');
PyBuffer_Release(&pyBuffer);
Py_BEGIN_ALLOW_THREADS
Py_BEGIN_ALLOW_THREADS;
result = (iResult == 0) && VMMDLL_MemWrite(dwPID, va, pb, (DWORD)cb);
LocalFree(pb);
Py_END_ALLOW_THREADS
Py_END_ALLOW_THREADS;
if(!result) { return PyErr_Format(PyExc_RuntimeError, "VMMPYC_MemWrite: Failed."); }
return Py_BuildValue("s", NULL); // None returned on success.
}
@@ -229,9 +239,9 @@ VMMPYC_MemVirt2Phys(PyObject *self, PyObject *args)
DWORD dwPID;
ULONG64 va, pa;
if(!PyArg_ParseTuple(args, "kK", &dwPID, &va)) { return NULL; }
Py_BEGIN_ALLOW_THREADS
Py_BEGIN_ALLOW_THREADS;
result = VMMDLL_MemVirt2Phys(dwPID, va, &pa);
Py_END_ALLOW_THREADS
Py_END_ALLOW_THREADS;
if(!result) { return PyErr_Format(PyExc_RuntimeError, "VMMPYC_MemVirt2Phys: Failed."); }
return PyLong_FromUnsignedLongLong(pa);
}
@@ -248,13 +258,13 @@ VMMPYC_ProcessGetMemoryMap(PyObject *self, PyObject *args)
CHAR sz[5];
if(!PyArg_ParseTuple(args, "k|p", &dwPID, &fIdentifyModules)) { return NULL; }
if(!(pyList = PyList_New(0))) { return PyErr_NoMemory(); }
Py_BEGIN_ALLOW_THREADS
Py_BEGIN_ALLOW_THREADS;
result =
VMMDLL_ProcessGetMemoryMap(dwPID, NULL, &cMemMapEntries, fIdentifyModules) &&
cMemMapEntries &&
(pMemMapEntries = LocalAlloc(0, cMemMapEntries * sizeof(VMMDLL_MEMMAP_ENTRY))) &&
VMMDLL_ProcessGetMemoryMap(dwPID, pMemMapEntries, &cMemMapEntries, fIdentifyModules);
Py_END_ALLOW_THREADS
Py_END_ALLOW_THREADS;
if(!result) {
Py_DECREF(pyList);
LocalFree(pMemMapEntries);
@@ -294,9 +304,9 @@ VMMPYC_ProcessGetMemoryMapEntry(PyObject *self, PyObject *args)
CHAR sz[5];
if(!PyArg_ParseTuple(args, "kK|p", &dwPID, &va, &fIdentifyModules)) { return NULL; }
if(!(pyDict = PyDict_New())) { return PyErr_NoMemory(); }
Py_BEGIN_ALLOW_THREADS
Py_BEGIN_ALLOW_THREADS;
result = VMMDLL_ProcessGetMemoryMapEntry(dwPID, &e, va, fIdentifyModules);
Py_END_ALLOW_THREADS
Py_END_ALLOW_THREADS;
if(!result) {
Py_DECREF(pyDict);
return PyErr_Format(PyExc_RuntimeError, "VMMDLL_ProcessGetMemoryMapEntry: Failed.");
@@ -327,13 +337,13 @@ VMMPYC_ProcessGetModuleMap(PyObject *self, PyObject *args)
PVMMDLL_MODULEMAP_ENTRY pe, pModuleEntries = NULL;
if(!PyArg_ParseTuple(args, "k", &dwPID)) { return NULL; }
if(!(pyList = PyList_New(0))) { return PyErr_NoMemory(); }
Py_BEGIN_ALLOW_THREADS
Py_BEGIN_ALLOW_THREADS;
result =
VMMDLL_ProcessGetModuleMap(dwPID, NULL, &cModuleEntries) &&
cModuleEntries &&
(pModuleEntries = LocalAlloc(0, cModuleEntries * sizeof(VMMDLL_MODULEMAP_ENTRY))) &&
VMMDLL_ProcessGetModuleMap(dwPID, pModuleEntries, &cModuleEntries);
Py_END_ALLOW_THREADS
Py_END_ALLOW_THREADS;
if(!result) {
Py_DECREF(pyList);
LocalFree(pModuleEntries);
@@ -365,10 +375,10 @@ VMMPYC_ProcessGetModuleFromName(PyObject *self, PyObject *args)
VMMDLL_MODULEMAP_ENTRY e;
if(!PyArg_ParseTuple(args, "ks", &dwPID, &szModuleName)) { return NULL; }
if(!(pyDict = PyDict_New())) { return PyErr_NoMemory(); }
Py_BEGIN_ALLOW_THREADS
Py_BEGIN_ALLOW_THREADS;
ZeroMemory(&e, sizeof(VMMDLL_MODULEMAP_ENTRY));
result = VMMDLL_ProcessGetModuleFromName(dwPID, szModuleName, &e);
Py_END_ALLOW_THREADS
Py_END_ALLOW_THREADS;
if(!result) {
Py_DECREF(pyDict);
return PyErr_Format(PyExc_RuntimeError, "VMMPYC_ProcessGetModuleFromName: Failed.");
@@ -389,9 +399,9 @@ VMMPYC_PidGetFromName(PyObject *self, PyObject *args)
DWORD dwPID;
LPSTR szProcessName;
if(!PyArg_ParseTuple(args, "s", &szProcessName)) { return NULL; }
Py_BEGIN_ALLOW_THREADS
Py_BEGIN_ALLOW_THREADS;
result = VMMDLL_PidGetFromName(szProcessName, &dwPID);
Py_END_ALLOW_THREADS
Py_END_ALLOW_THREADS;
if(!result) { return PyErr_Format(PyExc_RuntimeError, "VMMPYC_PidGetFromName: Failed."); }
return PyLong_FromLong(dwPID);
}
@@ -405,12 +415,12 @@ VMMPYC_PidList(PyObject *self, PyObject *args)
ULONG64 cPIDs = 0;
DWORD i, *pPIDs = NULL;
if(!(pyList = PyList_New(0))) { return PyErr_NoMemory(); }
Py_BEGIN_ALLOW_THREADS
Py_BEGIN_ALLOW_THREADS;
result =
VMMDLL_PidList(NULL, &cPIDs) &&
(pPIDs = LocalAlloc(LMEM_ZEROINIT, cPIDs * sizeof(DWORD))) &&
VMMDLL_PidList(pPIDs, &cPIDs);
Py_END_ALLOW_THREADS
Py_END_ALLOW_THREADS;
if(!result) {
Py_DECREF(pyList);
LocalFree(pPIDs);
@@ -434,12 +444,12 @@ VMMPYC_ProcessGetInformation(PyObject *self, PyObject *args)
SIZE_T cbInfo = sizeof(VMMDLL_PROCESS_INFORMATION);
if(!PyArg_ParseTuple(args, "k", &dwPID)) { return NULL; }
if(!(pyDict = PyDict_New())) { return PyErr_NoMemory(); }
Py_BEGIN_ALLOW_THREADS
Py_BEGIN_ALLOW_THREADS;
ZeroMemory(&info, sizeof(VMMDLL_PROCESS_INFORMATION));
info.magic = VMMDLL_PROCESS_INFORMATION_MAGIC;
info.wVersion = VMMDLL_PROCESS_INFORMATION_VERSION;
result = VMMDLL_ProcessGetInformation(dwPID, &info, &cbInfo);
Py_END_ALLOW_THREADS
Py_END_ALLOW_THREADS;
if(!result) {
Py_DECREF(pyDict);
return PyErr_Format(PyExc_RuntimeError, "VMMPYC_ProcessGetInformation: Failed.");
@@ -481,11 +491,11 @@ VMMPYC_ProcessGetDirectories(PyObject *self, PyObject *args)
LPCSTR DIRECTORIES[16] = { "EXPORT", "IMPORT", "RESOURCE", "EXCEPTION", "SECURITY", "BASERELOC", "DEBUG", "ARCHITECTURE", "GLOBALPTR", "TLS", "LOAD_CONFIG", "BOUND_IMPORT", "IAT", "DELAY_IMPORT", "COM_DESCRIPTOR", "RESERVED" };
if(!PyArg_ParseTuple(args, "ks", &dwPID, &szModule)) { return NULL; }
if(!(pyList = PyList_New(0))) { return PyErr_NoMemory(); }
Py_BEGIN_ALLOW_THREADS
Py_BEGIN_ALLOW_THREADS;
result =
(pDirectories = LocalAlloc(0, 16 * sizeof(IMAGE_DATA_DIRECTORY))) &&
VMMDLL_ProcessGetDirectories(dwPID, szModule, pDirectories, 16, &cDirectories);
Py_END_ALLOW_THREADS
Py_END_ALLOW_THREADS;
if(!result) {
Py_DECREF(pyList);
LocalFree(pDirectories);
@@ -518,13 +528,13 @@ VMMPYC_ProcessGetSections(PyObject *self, PyObject *args)
szName[8] = 0;
if(!PyArg_ParseTuple(args, "ks", &dwPID, &szModule)) { return NULL; }
if(!(pyList = PyList_New(0))) { return PyErr_NoMemory(); }
Py_BEGIN_ALLOW_THREADS
Py_BEGIN_ALLOW_THREADS;
result =
VMMDLL_ProcessGetSections(dwPID, szModule, NULL, 0, &cSections) &&
cSections &&
(pSections = LocalAlloc(0, cSections * sizeof(IMAGE_SECTION_HEADER))) &&
VMMDLL_ProcessGetSections(dwPID, szModule, pSections, cSections, &cSections);
Py_END_ALLOW_THREADS
Py_END_ALLOW_THREADS;
if(!result) {
Py_DECREF(pyList);
LocalFree(pSections);
@@ -564,13 +574,13 @@ VMMPYC_ProcessGetEAT(PyObject *self, PyObject *args)
LPSTR szModule;
if(!PyArg_ParseTuple(args, "ks", &dwPID, &szModule)) { return NULL; }
if(!(pyList = PyList_New(0))) { return PyErr_NoMemory(); }
Py_BEGIN_ALLOW_THREADS
Py_BEGIN_ALLOW_THREADS;
result =
VMMDLL_ProcessGetEAT(dwPID, szModule, NULL, 0, &cEATs) &&
cEATs &&
(pEATs = LocalAlloc(0, cEATs * sizeof(VMMDLL_EAT_ENTRY))) &&
VMMDLL_ProcessGetEAT(dwPID, szModule, pEATs, cEATs, &cEATs);
Py_END_ALLOW_THREADS
Py_END_ALLOW_THREADS;
if(!result) {
Py_DECREF(pyList);
LocalFree(pEATs);
@@ -601,13 +611,13 @@ VMMPYC_ProcessGetIAT(PyObject *self, PyObject *args)
LPSTR szModule;
if(!PyArg_ParseTuple(args, "ks", &dwPID, &szModule)) { return NULL; }
if(!(pyList = PyList_New(0))) { return PyErr_NoMemory(); }
Py_BEGIN_ALLOW_THREADS
Py_BEGIN_ALLOW_THREADS;
result =
VMMDLL_ProcessGetIAT(dwPID, szModule, NULL, 0, &cIATs) &&
cIATs &&
(pIATs = LocalAlloc(0, cIATs * sizeof(VMMDLL_IAT_ENTRY))) &&
VMMDLL_ProcessGetIAT(dwPID, szModule, pIATs, cIATs, &cIATs);
Py_END_ALLOW_THREADS
Py_END_ALLOW_THREADS;
if(!result) {
Py_DECREF(pyList);
LocalFree(pIATs);
@@ -650,7 +660,7 @@ VMMPYC_UtilFillHexAscii(PyObject *self, PyObject *args)
}
iResult = PyBuffer_ToContiguous(pb, &pyBuffer, cb, 'C');
PyBuffer_Release(&pyBuffer);
Py_BEGIN_ALLOW_THREADS
Py_BEGIN_ALLOW_THREADS;
result =
(iResult == 0) &&
VMMDLL_UtilFillHexAscii(pb, cb, cbInitialOffset, NULL, &csz) &&
@@ -658,8 +668,8 @@ VMMPYC_UtilFillHexAscii(PyObject *self, PyObject *args)
(sz = (LPSTR)LocalAlloc(0, csz)) &&
VMMDLL_UtilFillHexAscii(pb, cb, cbInitialOffset, sz, &csz);
LocalFree(pb);
Py_END_ALLOW_THREADS
if(!result || !sz) {
Py_END_ALLOW_THREADS;
if(!result || !sz) {
LocalFree(sz);
return PyErr_Format(PyExc_RuntimeError, "VMMPYC_UtilFillHexAscii: Failed.");
}
@@ -690,9 +700,9 @@ VMMPYC_VfsRead(PyObject *self, PyObject *args)
}
pb = LocalAlloc(0, cb);
if(!pb) { return PyErr_NoMemory(); }
Py_BEGIN_ALLOW_THREADS
Py_BEGIN_ALLOW_THREADS;
nt = VMMDLL_VfsRead(wszFileName, pb, cb, &cbRead, cbOffset);
Py_END_ALLOW_THREADS
Py_END_ALLOW_THREADS;
if(nt != VMMDLL_STATUS_SUCCESS) {
LocalFree(pb);
return PyErr_Format(PyExc_RuntimeError, "VMMPYC_VfsRead: Failed.");
@@ -734,14 +744,124 @@ VMMPYC_VfsWrite(PyObject *self, PyObject *args)
}
iResult = PyBuffer_ToContiguous(pb, &pyBuffer, cb, 'C');
PyBuffer_Release(&pyBuffer);
Py_BEGIN_ALLOW_THREADS
Py_BEGIN_ALLOW_THREADS;
result = (iResult == 0) && (VMMDLL_STATUS_SUCCESS == VMMDLL_VfsWrite(wszFileName, pb, cb, &cbWritten, cbOffset));
LocalFree(pb);
Py_END_ALLOW_THREADS
Py_END_ALLOW_THREADS;
if(!result) { return PyErr_Format(PyExc_RuntimeError, "VMMPYC_VfsWrite: Failed."); }
return Py_BuildValue("s", NULL); // None returned on success.
}
// (DWORD, STR, STR) -> ULONG64
static PyObject*
VMMPYC_ProcessGetProcAddress(PyObject *self, PyObject *args)
{
ULONG64 va;
DWORD dwPID;
LPSTR szModuleName, szProcName;
if(!PyArg_ParseTuple(args, "kss", &dwPID, &szModuleName, &szProcName)) { return NULL; }
Py_BEGIN_ALLOW_THREADS;
va = VMMDLL_ProcessGetProcAddress(dwPID, szModuleName, szProcName);
Py_END_ALLOW_THREADS;
return va ?
PyLong_FromUnsignedLongLong(va) :
PyErr_Format(PyExc_RuntimeError, "VMMPYC_ProcessGetProcAddress: Failed.");
}
// (DWORD, STR) -> ULONG64
static PyObject*
VMMPYC_ProcessGetModuleBase(PyObject *self, PyObject *args)
{
ULONG64 va;
DWORD dwPID;
LPSTR szModuleName;
if(!PyArg_ParseTuple(args, "ks", &dwPID, &szModuleName)) { return NULL; }
Py_BEGIN_ALLOW_THREADS;
va = VMMDLL_ProcessGetModuleBase(dwPID, szModuleName);
Py_END_ALLOW_THREADS;
return va ?
PyLong_FromUnsignedLongLong(va) :
PyErr_Format(PyExc_RuntimeError, "VMMPYC_ProcessGetModuleBase: Failed.");
}
// (DWORD, STR, STR) -> {...}
static PyObject*
VMMPYC_WinGetThunkInfoEAT(PyObject *self, PyObject *args)
{
PyObject *pyDict;
BOOL result;
DWORD dwPID;
VMMDLL_WIN_THUNKINFO_EAT oThunkInfoEAT = { 0 };
LPSTR szModuleName, szExportFunctionName;
if(!PyArg_ParseTuple(args, "kss", &dwPID, &szModuleName, &szExportFunctionName)) { return NULL; }
Py_BEGIN_ALLOW_THREADS;
result = VMMDLL_WinGetThunkInfoEAT(dwPID, szModuleName, szExportFunctionName, &oThunkInfoEAT);
Py_END_ALLOW_THREADS;
if(!result || !oThunkInfoEAT.fValid) {
return PyErr_Format(PyExc_RuntimeError, "VMMPYC_WinGetThunkInfoEAT: Failed.");
}
pyDict = PyDict_New();
if(pyDict) {
PyDict_SetItemString(pyDict, "vaFunction", PyLong_FromUnsignedLongLong(oThunkInfoEAT.vaFunction));
PyDict_SetItemString(pyDict, "valueThunk", PyLong_FromUnsignedLong(oThunkInfoEAT.valueThunk));
PyDict_SetItemString(pyDict, "vaNameFunction", PyLong_FromUnsignedLongLong(oThunkInfoEAT.vaNameFunction));
PyDict_SetItemString(pyDict, "vaThunk", PyLong_FromUnsignedLongLong(oThunkInfoEAT.vaThunk));
}
return pyDict;
}
// (DWORD, STR, STR, STR) -> {...}
static PyObject*
VMMPYC_WinGetThunkInfoIAT(PyObject *self, PyObject *args)
{
PyObject *pyDict;
BOOL result;
DWORD dwPID;
VMMDLL_WIN_THUNKINFO_IAT oThunkInfoIAT = { 0 };
LPSTR szModuleName, szImportModuleName, szImportFunctionName;
if(!PyArg_ParseTuple(args, "ksss", &dwPID, &szModuleName, &szImportModuleName, &szImportFunctionName)) { return NULL; }
Py_BEGIN_ALLOW_THREADS;
result = VMMDLL_WinGetThunkInfoIAT(dwPID, szModuleName, szImportModuleName, szImportFunctionName, &oThunkInfoIAT);
Py_END_ALLOW_THREADS;
if(!result || !oThunkInfoIAT.fValid) {
return PyErr_Format(PyExc_RuntimeError, "VMMPYC_WinGetThunkInfoEAT: Failed.");
}
pyDict = PyDict_New();
if(pyDict) {
PyDict_SetItemString(pyDict, "32", PyBool_FromLong(oThunkInfoIAT.f32 ? 1 : 0));
PyDict_SetItemString(pyDict, "vaFunction", PyLong_FromUnsignedLongLong(oThunkInfoIAT.vaFunction));
PyDict_SetItemString(pyDict, "vaNameFunction", PyLong_FromUnsignedLongLong(oThunkInfoIAT.vaNameFunction));
PyDict_SetItemString(pyDict, "vaNameModule", PyLong_FromUnsignedLongLong(oThunkInfoIAT.vaNameModule));
PyDict_SetItemString(pyDict, "vaThunk", PyLong_FromUnsignedLongLong(oThunkInfoIAT.vaThunk));
}
return pyDict;
}
// (ULONG64, DWORD) -> {b: PBYTE, c: DWORD}
static PyObject*
VMMPYC_WinMemCompression_DecompressPage(PyObject *self, PyObject *args)
{
PyObject *pyDict;
BOOL result;
DWORD cb, cbCompressed;
ULONG64 va;
BYTE pbDecompressed[0x1000] = { 0 };
if(!PyArg_ParseTuple(args, "Kk", &va, &cb)) { return NULL; }
Py_BEGIN_ALLOW_THREADS;
result = VMMDLL_WinMemCompression_DecompressPage(va, cb, pbDecompressed, &cbCompressed);
Py_END_ALLOW_THREADS;
if(!result) {
return PyErr_Format(PyExc_RuntimeError, "VMMPYC_WinMemCompression_DecompressPage: Failed.");
}
pyDict = PyDict_New();
if(pyDict) {
PyDict_SetItemString(pyDict, "c", PyLong_FromUnsignedLong(cbCompressed));
PyDict_SetItemString(pyDict, "b", PyBytes_FromStringAndSize(pbDecompressed, 0x1000));
}
return pyDict;
}
typedef struct tdVMMPYC_VFSLIST {
struct tdVMMPYC_VFSLIST *FLink;
@@ -788,20 +908,20 @@ VMMPYC_VfsList(PyObject *self, PyObject *args)
PVMMPYC_VFSLIST pE = NULL, pE_Next;
if(!PyArg_ParseTuple(args, "s", &szPath)) { return NULL; }
if(!(pyDict = PyDict_New())) { return PyErr_NoMemory(); }
Py_BEGIN_ALLOW_THREADS
Py_BEGIN_ALLOW_THREADS;
{ // char* -> wchar*
for(i = 0; i < MAX_PATH - 1; i++) {
wszPath[i] = szPath[i];
if(0 == szPath[i]) { break; }
}
wszPath[MAX_PATH - 1] = 0;
wszPath[MAX_PATH - 1] = 0;
}
hFileList.h = &pE;
hFileList.pfnAddFile = VMMPYC_VfsList_AddFile;
hFileList.pfnAddDirectory = VMMPYC_VfsList_AddDirectory;
result = VMMDLL_VfsList(wszPath, &hFileList);
pE = *(PVMMPYC_VFSLIST*)hFileList.h;
Py_END_ALLOW_THREADS
Py_END_ALLOW_THREADS;
while(pE) {
if((PyDict_Attr = PyDict_New())) {
PyDict_SetItemString(PyDict_Attr, "f_isdir", PyBool_FromLong(pE->fIsDir ? 1 : 0));
@@ -825,6 +945,7 @@ VMMPYC_VfsList(PyObject *self, PyObject *args)
static PyMethodDef VMMPYC_EmbMethods[] = {
{"VMMPYC_Initialize", VMMPYC_Initialize, METH_VARARGS, "Initialize the VMM"},
{"VMMPYC_Close", VMMPYC_Close, METH_VARARGS, "Try close the VMM"},
{"VMMPYC_ConfigGet", VMMPYC_ConfigGet, METH_VARARGS, "Get a device specific option value."},
{"VMMPYC_ConfigSet", VMMPYC_ConfigSet, METH_VARARGS, "Set a device specific option value."},
{"VMMPYC_MemReadScatter", VMMPYC_MemReadScatter, METH_VARARGS, "Read multiple 4kB page sized and aligned chunks of memory given as an address list."},
@@ -842,9 +963,14 @@ static PyMethodDef VMMPYC_EmbMethods[] = {
{"VMMPYC_ProcessGetSections", VMMPYC_ProcessGetSections, METH_VARARGS, "Retrieve the sections for a specific process and module."},
{"VMMPYC_ProcessGetEAT", VMMPYC_ProcessGetEAT, METH_VARARGS, "Retrieve the export address table (EAT) for a specific process and module."},
{"VMMPYC_ProcessGetIAT", VMMPYC_ProcessGetIAT, METH_VARARGS, "Retrieve the import address table (IAT) for a specific process and module."},
{"VMMPYC_ProcessGetProcAddress", VMMPYC_ProcessGetProcAddress, METH_VARARGS, "Retrieve the proc address of a given module!function."},
{"VMMPYC_ProcessGetModuleBase", VMMPYC_ProcessGetModuleBase, METH_VARARGS, "Retrieve the module base address given a module."},
{"VMMPYC_WinGetThunkInfoEAT", VMMPYC_WinGetThunkInfoEAT, METH_VARARGS, "Retrieve information about the export address table (EAT) thunk. (useful for patching)."},
{"VMMPYC_WinGetThunkInfoIAT", VMMPYC_WinGetThunkInfoIAT, METH_VARARGS, "Retrieve information about the import address table (IAT) thunk. (useful for patching)."},
{"VMMPYC_VfsRead", VMMPYC_VfsRead, METH_VARARGS, "Read from a file in the virtual file system."},
{"VMMPYC_VfsWrite", VMMPYC_VfsWrite, METH_VARARGS, "Write to a file in the virtual file system."},
{"VMMPYC_VfsList", VMMPYC_VfsList, METH_VARARGS, "List files and folder for a specific directory in the Virutal File System."},
{"VMMPYC_WinMemCompression_DecompressPage", VMMPYC_WinMemCompression_DecompressPage, METH_VARARGS, "Decompress compressed memory in the MemCompression process (if any)."},
{"VMMPYC_UtilFillHexAscii", VMMPYC_UtilFillHexAscii, METH_VARARGS, "Convert a bytes object into a human readable 'memory dump' style type of string."},
{NULL, NULL, 0, NULL}
};