mirror of
https://github.com/ufrisk/MemProcFS-plugins.git
synced 2026-06-04 17:37:28 +08:00
Version 2.1
This commit is contained in:
@@ -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.
@@ -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.
BIN
files/vmm.dll
BIN
files/vmm.dll
Binary file not shown.
BIN
files/vmm.lib
BIN
files/vmm.lib
Binary file not shown.
103
files/vmmdll.h
103
files/vmmdll.h
@@ -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
|
||||
);
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -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:
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
BIN
files/vmmpyc.pyd
BIN
files/vmmpyc.pyd
Binary file not shown.
@@ -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
|
||||
|
||||
@@ -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
54
vmm/mm_x64_winpaged.c
Normal 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
26
vmm/mm_x64_winpaged.h
Normal 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
121
vmm/pe.c
@@ -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)
|
||||
|
||||
42
vmm/pe.h
42
vmm/pe.h
@@ -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
|
||||
|
||||
126
vmm/statistics.c
126
vmm/statistics.c
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
21
vmm/vmm.c
21
vmm/vmm.c
@@ -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();
|
||||
|
||||
19
vmm/vmm.h
19
vmm/vmm.h
@@ -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
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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">
|
||||
|
||||
172
vmm/vmmdll.c
172
vmm/vmmdll.c
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
103
vmm/vmmdll.h
103
vmm/vmmdll.h
@@ -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
|
||||
);
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -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;
|
||||
|
||||
62
vmm/vmmwin.c
62
vmm/vmmwin.c
@@ -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;
|
||||
|
||||
12
vmm/vmmwin.h
12
vmm/vmmwin.h
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
103
vmmpyc/vmmdll.h
103
vmmpyc/vmmdll.h
@@ -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
|
||||
);
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
214
vmmpyc/vmmpyc.c
214
vmmpyc/vmmpyc.c
@@ -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}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user