mirror of
https://github.com/ufrisk/MemProcFS.git
synced 2026-05-07 22:06:17 +08:00
1855 lines
82 KiB
C
1855 lines
82 KiB
C
// vmmdll_example.c - MemProcFS C/C++ VMM API usage examples
|
|
//
|
|
// Note that this is not a complete list of the VMM API.
|
|
// For the complete list please consult the vmmdll.h header file.
|
|
//
|
|
// Note about Windows/Linux differences:
|
|
// - Path to the file to be analyzed
|
|
// - Not all functionality is yet implemented on Linux - primarily debug symbol
|
|
// and forensic functionality is missing. Future support is planned.
|
|
// Please see the guide at https://github.com/ufrisk/MemProcFS/wiki for info.
|
|
// - Windows have access to both UTF-8 *U functions as well as Wide-Char *W
|
|
// functions whilst linux in general should use UTF-8 functions only. This
|
|
// example use UTF-8 functions throughout to have the best compatibility.
|
|
//
|
|
// (c) Ulf Frisk, 2018-2026
|
|
// Author: Ulf Frisk, pcileech@frizk.net
|
|
//
|
|
|
|
#ifdef _WIN32
|
|
|
|
#include <Windows.h>
|
|
#include <stdio.h>
|
|
#include <conio.h>
|
|
#include <leechcore.h>
|
|
#include <vmmdll.h>
|
|
#pragma comment(lib, "leechcore")
|
|
#pragma comment(lib, "vmm")
|
|
|
|
#endif /* _WIN32 */
|
|
#if defined(LINUX) || defined(MACOS)
|
|
|
|
#include <leechcore.h>
|
|
#include <vmmdll.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#define TRUE 1
|
|
#define FALSE 0
|
|
#define LMEM_ZEROINIT 0x0040
|
|
#define _getch() (getchar())
|
|
#define ZeroMemory(pb, cb) (memset(pb, 0, cb))
|
|
#define Sleep(dwMilliseconds) (usleep(1000*dwMilliseconds))
|
|
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
|
#define IMAGE_SCN_MEM_EXECUTE 0x20000000
|
|
#define IMAGE_SCN_MEM_READ 0x40000000
|
|
#define IMAGE_SCN_MEM_WRITE 0x80000000
|
|
|
|
HANDLE LocalAlloc(DWORD uFlags, SIZE_T uBytes)
|
|
{
|
|
HANDLE h = malloc(uBytes);
|
|
if(h && (uFlags & LMEM_ZEROINIT)) {
|
|
memset(h, 0, uBytes);
|
|
}
|
|
return h;
|
|
}
|
|
|
|
VOID LocalFree(HANDLE hMem)
|
|
{
|
|
free(hMem);
|
|
}
|
|
|
|
#endif /* LINUX || MACOS */
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Initialize from type of device, FILE or FPGA.
|
|
// Ensure only one is active below at one single time!
|
|
// INITIALIZE_FROM_FILE contains file name to a raw memory dump.
|
|
// ----------------------------------------------------------------------------
|
|
#define _INITIALIZE_FROM_FILE "Z:\\x64\\WIN10-X64-1909-18363-1.core"
|
|
//#define _INITIALIZE_FROM_FILE "/mnt/c/Dumps/WIN7-x64-SP1-1.pmem"
|
|
//#define _INITIALIZE_FROM_FPGA
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Utility functions below:
|
|
// ----------------------------------------------------------------------------
|
|
|
|
VOID ShowKeyPress()
|
|
{
|
|
printf("PRESS ANY KEY TO CONTINUE ...\n");
|
|
Sleep(250);
|
|
_getch();
|
|
}
|
|
|
|
VOID PrintHexAscii(_In_ PBYTE pb, _In_ DWORD cb)
|
|
{
|
|
LPSTR sz;
|
|
DWORD szMax = 0;
|
|
VMMDLL_UtilFillHexAscii(pb, cb, 0, NULL, &szMax);
|
|
if(!(sz = LocalAlloc(0, szMax))) { return; }
|
|
VMMDLL_UtilFillHexAscii(pb, cb, 0, sz, &szMax);
|
|
printf("%s", sz);
|
|
LocalFree(sz);
|
|
}
|
|
|
|
VOID CallbackList_AddFile(_Inout_ HANDLE h, _In_ LPCSTR uszName, _In_ ULONG64 cb, _In_opt_ PVMMDLL_VFS_FILELIST_EXINFO pExInfo)
|
|
{
|
|
if(uszName) {
|
|
printf(" FILE: '%s'\tSize: %lli\n", uszName, cb);
|
|
}
|
|
}
|
|
|
|
VOID CallbackList_AddDirectory(_Inout_ HANDLE h, _In_ LPCSTR uszName, _In_opt_ PVMMDLL_VFS_FILELIST_EXINFO pExInfo)
|
|
{
|
|
if(uszName) {
|
|
printf(" DIR: '%s'\n", uszName);
|
|
}
|
|
}
|
|
|
|
VOID VadMap_Protection(_In_ PVMMDLL_MAP_VADENTRY pVad, _Out_writes_(6) LPSTR sz)
|
|
{
|
|
BYTE vh = (BYTE)pVad->Protection >> 3;
|
|
BYTE vl = (BYTE)pVad->Protection & 7;
|
|
sz[0] = pVad->fPrivateMemory ? 'p' : '-'; // PRIVATE MEMORY
|
|
sz[1] = (vh & 2) ? ((vh & 1) ? 'm' : 'g') : ((vh & 1) ? 'n' : '-'); // -/NO_CACHE/GUARD/WRITECOMBINE
|
|
sz[2] = ((vl == 1) || (vl == 3) || (vl == 4) || (vl == 6)) ? 'r' : '-'; // COPY ON WRITE
|
|
sz[3] = (vl & 4) ? 'w' : '-'; // WRITE
|
|
sz[4] = (vl & 2) ? 'x' : '-'; // EXECUTE
|
|
sz[5] = ((vl == 5) || (vl == 7)) ? 'c' : '-'; // COPY ON WRITE
|
|
if(sz[1] != '-' && sz[2] == '-' && sz[3] == '-' && sz[4] == '-' && sz[5] == '-') { sz[1] = '-'; }
|
|
}
|
|
|
|
LPSTR VadMap_Type(_In_ PVMMDLL_MAP_VADENTRY pVad)
|
|
{
|
|
if(pVad->fImage) {
|
|
return "Image";
|
|
} else if(pVad->fFile) {
|
|
return "File ";
|
|
} else if(pVad->fHeap) {
|
|
return "Heap ";
|
|
} else if(pVad->fStack) {
|
|
return "Stack";
|
|
} else if(pVad->fTeb) {
|
|
return "Teb ";
|
|
} else if(pVad->fPageFile) {
|
|
return "Pf ";
|
|
} else {
|
|
return " ";
|
|
}
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Callback functions (YARA SEARCH) functionality below:
|
|
// ----------------------------------------------------------------------------
|
|
|
|
BOOL CallbackSearchYaraMatch(_In_ PVOID pvContext, _In_ PVMMYARA_RULE_MATCH pRuleMatch, _In_reads_bytes_(cbBuffer) PBYTE pbBuffer, _In_ SIZE_T cbBuffer)
|
|
{
|
|
PVMMDLL_YARA_CONFIG ctx = (PVMMDLL_YARA_CONFIG)pvContext; // We pass the PVMMDLL_YARA_CONFIG into the user-set context pointer (ctx->pvUserPtrOpt)
|
|
// This is done so we'll get the base address of the buffer being scanned.
|
|
// if one wish to use another user-context the field ctx->pvUserPtrOpt2 may be used.
|
|
if(pRuleMatch->dwVersion != VMMYARA_RULE_MATCH_VERSION) { return FALSE; }
|
|
if((pRuleMatch->cStrings > 0) && (pRuleMatch->Strings[0].cMatch > 0)) { // ensure at least one string match exists - only print the address of the first occurence.
|
|
printf(" rule: %s address: %llx string: %s\n", pRuleMatch->szRuleIdentifier, ctx->vaCurrent + pRuleMatch->Strings[0].cbMatchOffset[0], pRuleMatch->Strings[0].szString);
|
|
}
|
|
return TRUE; // TRUE = continue search, FALSE = abort search
|
|
}
|
|
|
|
/*
|
|
* Optional filter callback. Tell whether a memory region should be scanned or not.
|
|
* User-mode applications predominantely use vad entries, whilst kernel use pte entries.
|
|
* -- ctx = Pointer to the VMMDLL_YARA_CONFIG structure.
|
|
* -- pePte = Pointer to the VMMDLL_MAP_PTEENTRY structure. NULL if not available.
|
|
* -- peVad = Pointer to the VMMDLL_MAP_VADENTRY structure. NULL if not available.
|
|
* -- return = TRUE to scan the memory region, FALSE to skip it.
|
|
*/
|
|
BOOL CallbackSearchYaraFilter(_In_ PVMMDLL_YARA_CONFIG ctx, _In_opt_ PVMMDLL_MAP_PTEENTRY pePte, _In_opt_ PVMMDLL_MAP_VADENTRY peVad)
|
|
{
|
|
if(ctx->dwVersion != VMMDLL_YARA_CONFIG_VERSION) { return FALSE; }
|
|
// only scan VAD-backed image memory regions since we're scanning for PE headers.
|
|
// this may miss out on PE headers in other memory regions commonly used by malware.
|
|
return peVad && peVad->fImage;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Callback functions (MEM CALLBACK) functionality below:
|
|
// ----------------------------------------------------------------------------
|
|
|
|
VOID CallbackMemCallback_PhysicalReadPost(_In_opt_ PVOID ctxUser, _In_ DWORD dwPID, _In_ DWORD cpMEMs, _In_ PPMEM_SCATTER ppMEMs)
|
|
{
|
|
DWORD i;
|
|
PMEM_SCATTER pMEM;
|
|
for(i = 0; i < cpMEMs; i++) {
|
|
pMEM = ppMEMs[i];
|
|
if(pMEM->f && (pMEM->qwA == 0x1000) && (pMEM->cb >= 0x10)) {
|
|
// Successful physical memory read at address 0x1000.
|
|
// This is simplified since read may start mid-range if
|
|
// non-page-aligned MEMs are used.
|
|
memcpy(pMEM->pb, (PBYTE)"0123456789ABCDEF", 0x10);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Main entry point which contains various sample code how to use MemProcFS DLL.
|
|
// Please walk though for different API usage examples. To select device ensure
|
|
// one device type only is uncommented in the #defines above.
|
|
// ---
|
|
// Since v5 MemProcFS supports memory analysis targets at the same time. The
|
|
// VMM_HANDLE (hVMM) which the initialization function return upon success is
|
|
// to be used in all subsequent API calls.
|
|
// ----------------------------------------------------------------------------
|
|
int main(_In_ int argc, _In_ char* argv[])
|
|
{
|
|
VMM_HANDLE hVMM = NULL;
|
|
BOOL result;
|
|
NTSTATUS nt;
|
|
DWORD i, j, cbRead, dwPID;
|
|
DWORD cch = 0, dw = 0;
|
|
QWORD va;
|
|
BYTE pbPage1[0x1000], pbPage2[0x1000];
|
|
CHAR usz[MAX_PATH];
|
|
|
|
#ifdef _INITIALIZE_FROM_FILE
|
|
// Initialize PCILeech DLL with a memory dump file.
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Initialize from file: \n");
|
|
ShowKeyPress();
|
|
printf("CALL: VMMDLL_InitializeFile\n");
|
|
hVMM = VMMDLL_Initialize(3, (LPCSTR[]) { "", "-device", _INITIALIZE_FROM_FILE });
|
|
if(hVMM) {
|
|
printf("SUCCESS: VMMDLL_InitializeFile\n");
|
|
} else {
|
|
printf("FAIL: VMMDLL_InitializeFile\n");
|
|
return 1;
|
|
}
|
|
#endif /* _INITIALIZE_FROM_FILE */
|
|
|
|
#ifdef _INITIALIZE_FROM_FPGA
|
|
// Initialize VMM DLL from a linked PCILeech with a FPGA hardware device
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Initialize from FPGA: \n");
|
|
ShowKeyPress();
|
|
printf("CALL: VMMDLL_Initialize\n");
|
|
hVMM = VMMDLL_Initialize(3, (LPSTR[]) { "", "-device", "fpga" });
|
|
if(hVMM) {
|
|
printf("SUCCESS: VMMDLL_Initialize\n");
|
|
} else {
|
|
printf("FAIL: VMMDLL_Initialize\n");
|
|
return 1;
|
|
}
|
|
// Retrieve the ID of the FPPA (SP605/PCIeScreamer/AC701 ...) and the bitstream version
|
|
ULONG64 qwID, qwVersionMajor, qwVersionMinor;
|
|
ShowKeyPress();
|
|
printf("CALL: VMMDLL_ConfigGet\n");
|
|
result =
|
|
VMMDLL_ConfigGet(hVMM, LC_OPT_FPGA_FPGA_ID, &qwID) &&
|
|
VMMDLL_ConfigGet(hVMM, LC_OPT_FPGA_VERSION_MAJOR, &qwVersionMajor) &&
|
|
VMMDLL_ConfigGet(hVMM, LC_OPT_FPGA_VERSION_MINOR, &qwVersionMinor);
|
|
if(result) {
|
|
printf("SUCCESS: VMMDLL_ConfigGet\n");
|
|
printf(" ID = %lli\n", qwID);
|
|
printf(" VERSION = %lli.%lli\n", qwVersionMajor, qwVersionMinor);
|
|
} else {
|
|
printf("FAIL: VMMDLL_ConfigGet\n");
|
|
return 1;
|
|
}
|
|
// Set PCIe config space status register flags auto-clear [master abort].
|
|
// This requires bitstream version 4.7 or above. By default the flags are
|
|
// reset evry ms. If timing are to be changed it's possible to write a new
|
|
// timing value to PCILeech PCIe register at address: 0x054 (DWORD-value,
|
|
// tickcount of multiples of 62.5MHz ticks).
|
|
if((qwVersionMajor >= 4) && ((qwVersionMajor >= 5) || (qwVersionMinor >= 7)))
|
|
{
|
|
HANDLE hLC;
|
|
LC_CONFIG LcConfig = {
|
|
.dwVersion = LC_CONFIG_VERSION,
|
|
.szDevice = "existing"
|
|
};
|
|
// fetch already existing leechcore handle.
|
|
hLC = LcCreate(&LcConfig);
|
|
if(hLC) {
|
|
// enable auto-clear of status register [master abort].
|
|
LcCommand(hLC, LC_CMD_FPGA_CFGREGPCIE_MARKWR | 0x002, 4, (BYTE[4]) { 0x10, 0x00, 0x10, 0x00 }, NULL, NULL);
|
|
printf("SUCCESS: LcCommand: STATUS REGISTER AUTO-CLEAR\n");
|
|
// close leechcore handle.
|
|
LcClose(hLC);
|
|
}
|
|
}
|
|
#endif /* _INITIALIZE_FROM_FPGA */
|
|
|
|
|
|
// Read physical memory at physical address 0x1000 and display the first
|
|
// 0x100 bytes on-screen.
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Read from physical memory (0x1000 bytes @ 0x1000). \n");
|
|
ShowKeyPress();
|
|
printf("CALL: VMMDLL_MemRead\n");
|
|
result = VMMDLL_MemRead(hVMM, -1, 0x1000, pbPage1, 0x1000);
|
|
if(result) {
|
|
printf("SUCCESS: VMMDLL_MemRead\n");
|
|
PrintHexAscii(pbPage1, 0x100);
|
|
} else {
|
|
printf("FAIL: VMMDLL_MemRead\n");
|
|
return 1;
|
|
}
|
|
|
|
|
|
// Write physical memory at physical address 0x1000 and display the first
|
|
// 0x100 bytes on-screen - afterwards. Maybe result of write is in there?
|
|
// (only if device is capable of writes and target system accepts writes)
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Try write to physical memory at address 0x1000. \n");
|
|
printf(" NB! Write capable device is required for success! \n");
|
|
printf(" (1) Read existing data from physical memory. \n");
|
|
printf(" (2) Try write to physical memory at 0x1000. \n");
|
|
printf(" Bytes written: 11112222333344445555666677778888 \n");
|
|
printf(" (3) Read resulting data from physical memory. \n");
|
|
ShowKeyPress();
|
|
printf("CALL: VMMDLL_MemRead - BEFORE WRITE\n");
|
|
result = VMMDLL_MemRead(hVMM, -1, 0x1000, pbPage1, 0x1000);
|
|
if(result) {
|
|
printf("SUCCESS: VMMDLL_MemRead - BEFORE WRITE\n");
|
|
PrintHexAscii(pbPage1, 0x100);
|
|
} else {
|
|
printf("FAIL: VMMDLL_MemRead - BEFORE WRITE\n");
|
|
return 1;
|
|
}
|
|
printf("CALL: VMMDLL_MemWrite\n");
|
|
DWORD cbWriteDataPhysical = 0x20;
|
|
BYTE pbWriteDataPhysical[0x20] = {
|
|
0x11, 0x11, 0x11, 0x11, 0x22, 0x22, 0x22, 0x22,
|
|
0x33, 0x33, 0x33, 0x33, 0x44, 0x44, 0x44, 0x44,
|
|
0x55, 0x55, 0x55, 0x55, 0x66, 0x66, 0x66, 0x66,
|
|
0x77, 0x77, 0x77, 0x77, 0x88, 0x88, 0x88, 0x88,
|
|
};
|
|
VMMDLL_MemWrite(hVMM, -1, 0x1000, pbWriteDataPhysical, cbWriteDataPhysical);
|
|
printf("CALL: VMMDLL_MemRead - AFTER WRITE\n");
|
|
result = VMMDLL_MemRead(hVMM, -1, 0x1000, pbPage1, 0x1000);
|
|
if(result) {
|
|
printf("SUCCESS: VMMDLL_MemRead - AFTER WRITE\n");
|
|
PrintHexAscii(pbPage1, 0x100);
|
|
} else {
|
|
printf("FAIL: VMMDLL_MemRead - AFTER WRITE\n");
|
|
return 1;
|
|
}
|
|
|
|
|
|
// Retrieve PID of explorer.exe
|
|
// NB! if multiple explorer.exe exists only one will be returned by this
|
|
// specific function call. Please see .h file for additional information
|
|
// about how to retrieve the complete list of PIDs in the system by using
|
|
// the function PCILeech_VmmProcessListPIDs instead.
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Get PID from the first 'explorer.exe' process found. \n");
|
|
ShowKeyPress();
|
|
printf("CALL: VMMDLL_PidGetFromName\n");
|
|
result = VMMDLL_PidGetFromName(hVMM, "explorer.exe", &dwPID);
|
|
if(result) {
|
|
printf("SUCCESS: VMMDLL_PidGetFromName\n");
|
|
printf(" PID = %i\n", dwPID);
|
|
} else {
|
|
printf("FAIL: VMMDLL_PidGetFromName\n");
|
|
return 1;
|
|
}
|
|
|
|
|
|
// Retrieve additional process information such as: name of the process,
|
|
// PML4 (PageDirectoryBase) PML4-USER (if exists) and Process State.
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Get Process Information from 'explorer.exe'. \n");
|
|
ShowKeyPress();
|
|
VMMDLL_PROCESS_INFORMATION ProcessInformation;
|
|
SIZE_T cbProcessInformation = sizeof(VMMDLL_PROCESS_INFORMATION);
|
|
ZeroMemory(&ProcessInformation, sizeof(VMMDLL_PROCESS_INFORMATION));
|
|
ProcessInformation.magic = VMMDLL_PROCESS_INFORMATION_MAGIC;
|
|
ProcessInformation.wVersion = VMMDLL_PROCESS_INFORMATION_VERSION;
|
|
printf("CALL: VMMDLL_ProcessGetInformation\n");
|
|
result = VMMDLL_ProcessGetInformation(hVMM, dwPID, &ProcessInformation, &cbProcessInformation);
|
|
if(result) {
|
|
printf("SUCCESS: VMMDLL_ProcessGetInformation\n");
|
|
printf(" Name = %s\n", ProcessInformation.szName);
|
|
printf(" PageDirectoryBase = 0x%016llx\n", ProcessInformation.paDTB);
|
|
printf(" PageDirectoryBaseUser = 0x%016llx\n", ProcessInformation.paDTB_UserOpt);
|
|
printf(" ProcessState = 0x%08x\n", ProcessInformation.dwState);
|
|
printf(" PID = 0x%08x\n", ProcessInformation.dwPID);
|
|
printf(" ParentPID = 0x%08x\n", ProcessInformation.dwPPID);
|
|
} else {
|
|
printf("FAIL: VMMDLL_ProcessGetInformation\n");
|
|
return 1;
|
|
}
|
|
|
|
|
|
// Retrieve process information such as: name of the process, PML4 (DTB),
|
|
// PML4-USER (if exists) and Process State from _all_ processes.
|
|
// Active processes will have ProcessState = 0.
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Get Process Information from ALL PROCESSES. \n");
|
|
ShowKeyPress();
|
|
DWORD cProcessInformation = 0;
|
|
PVMMDLL_PROCESS_INFORMATION pProcessInformationEntry, pProcessInformationAll = NULL;
|
|
printf("CALL: VMMDLL_ProcessGetInformationAll\n");
|
|
result = VMMDLL_ProcessGetInformationAll(hVMM, &pProcessInformationAll, &cProcessInformation);
|
|
if(result) {
|
|
// print results upon success:
|
|
printf("SUCCESS: VMMDLL_ProcessGetInformationAll\n");
|
|
for(i = 0; i < cProcessInformation; i++) {
|
|
pProcessInformationEntry = &pProcessInformationAll[i];
|
|
printf(" --------------------------------------\n");
|
|
printf(" Name = %s\n", pProcessInformationEntry->szName);
|
|
printf(" LongName = %s\n", pProcessInformationEntry->szNameLong);
|
|
printf(" PageDirectoryBase = 0x%016llx\n", pProcessInformationEntry->paDTB);
|
|
printf(" PageDirectoryBaseUser = 0x%016llx\n", pProcessInformationEntry->paDTB_UserOpt);
|
|
printf(" ProcessState = 0x%08x\n", pProcessInformationEntry->dwState);
|
|
printf(" PID = 0x%08x\n", pProcessInformationEntry->dwPID);
|
|
printf(" ParentPID = 0x%08x\n", pProcessInformationEntry->dwPPID);
|
|
}
|
|
// free function allocated memory:
|
|
VMMDLL_MemFree(pProcessInformationAll);
|
|
} else {
|
|
printf("FAIL: VMMDLL_ProcessGetInformationAll\n");
|
|
return 1;
|
|
}
|
|
|
|
|
|
// Retrieve the memory map from the page table. This function also tries to
|
|
// make additional parsing to identify modules and tag the memory map with
|
|
// them. This is done by multiple methods internally and may sometimes be
|
|
// more resilient against anti-reversing techniques that may be employed in
|
|
// some processes.
|
|
//
|
|
// Note! VMMDLL_Map_GetPte() comes in two variants. The Wide-Char version
|
|
// VMMDLL_Map_GetPteW() is only available on Windows whilst the UTF-8
|
|
// VMMDLL_Map_GetPteU() version is available on Linux and Windows.
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Get PTE Memory Map of 'explorer.exe'. \n");
|
|
ShowKeyPress();
|
|
PVMMDLL_MAP_PTE pPteMap = NULL;
|
|
PVMMDLL_MAP_PTEENTRY pPteMapEntry;
|
|
printf("CALL: VMMDLL_Map_GetPteU\n");
|
|
result = VMMDLL_Map_GetPteU(hVMM, dwPID, TRUE, &pPteMap);
|
|
if(!result) {
|
|
printf("FAIL: VMMDLL_Map_GetPteU\n");
|
|
return 1;
|
|
}
|
|
if(pPteMap->dwVersion != VMMDLL_MAP_PTE_VERSION) {
|
|
printf("FAIL: VMMDLL_Map_GetPteU - BAD VERSION\n");
|
|
VMMDLL_MemFree(pPteMap); pPteMap = NULL;
|
|
return 1;
|
|
}
|
|
{
|
|
printf("SUCCESS: VMMDLL_Map_GetPteU\n");
|
|
printf(" # #PAGES ADRESS_RANGE SRWX\n");
|
|
printf(" ====================================================\n");
|
|
for(i = 0; i < pPteMap->cMap; i++) {
|
|
pPteMapEntry = &pPteMap->pMap[i];
|
|
printf(
|
|
" %04x %8x %016llx-%016llx %sr%s%s%s%s\n",
|
|
i,
|
|
(DWORD)pPteMapEntry->cPages,
|
|
pPteMapEntry->vaBase,
|
|
pPteMapEntry->vaBase + (pPteMapEntry->cPages << 12) - 1,
|
|
pPteMapEntry->fPage & VMMDLL_MEMMAP_FLAG_PAGE_NS ? "-" : "s",
|
|
pPteMapEntry->fPage & VMMDLL_MEMMAP_FLAG_PAGE_W ? "w" : "-",
|
|
pPteMapEntry->fPage & VMMDLL_MEMMAP_FLAG_PAGE_NX ? "-" : "x",
|
|
pPteMapEntry->fWoW64 ? " 32 " : " ",
|
|
pPteMapEntry->uszText
|
|
);
|
|
}
|
|
VMMDLL_MemFree(pPteMap); pPteMap = NULL;
|
|
}
|
|
|
|
|
|
// Retrieve the memory map from the virtual address descriptors (VAD). This
|
|
// function also makes additional parsing to identify modules and tag the
|
|
// memory map with them.
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Get VAD Memory Map of 'explorer.exe'. \n");
|
|
ShowKeyPress();
|
|
CHAR szVadProtection[7] = { 0 };
|
|
PVMMDLL_MAP_VAD pVadMap = NULL;
|
|
PVMMDLL_MAP_VADENTRY pVadMapEntry;
|
|
printf("CALL: VMMDLL_Map_GetVadU\n");
|
|
result = VMMDLL_Map_GetVadU(hVMM, dwPID, TRUE, &pVadMap);
|
|
if(!result) {
|
|
printf("FAIL: VMMDLL_Map_GetVadU\n");
|
|
return 1;
|
|
}
|
|
if(pVadMap->dwVersion != VMMDLL_MAP_VAD_VERSION) {
|
|
printf("FAIL: VMMDLL_Map_GetVadU - BAD VERSION\n");
|
|
VMMDLL_MemFree(pVadMap); pVadMap = NULL;
|
|
return 1;
|
|
}
|
|
{
|
|
printf("SUCCESS: VMMDLL_Map_GetVadU\n");
|
|
printf(" # ADRESS_RANGE KERNEL_ADDR TYPE PROT INFO \n");
|
|
printf(" ============================================================================\n");
|
|
for(i = 0; i < pVadMap->cMap; i++) {
|
|
pVadMapEntry = &pVadMap->pMap[i];
|
|
VadMap_Protection(pVadMapEntry, szVadProtection);
|
|
printf(
|
|
" %04x %016llx-%016llx [%016llx] %s %s %s\n",
|
|
i,
|
|
pVadMapEntry->vaStart,
|
|
pVadMapEntry->vaEnd,
|
|
pVadMapEntry->vaVad,
|
|
VadMap_Type(pVadMapEntry),
|
|
szVadProtection,
|
|
pVadMapEntry->uszText
|
|
);
|
|
}
|
|
VMMDLL_MemFree(pVadMap); pVadMap = NULL;
|
|
}
|
|
|
|
|
|
// Retrieve the list of loaded DLLs from the process. Please note that this
|
|
// list is retrieved by parsing in-process memory structures such as the
|
|
// process environment block (PEB) which may be partly destroyed in some
|
|
// processes due to obfuscation and anti-reversing. If that is the case the
|
|
// memory map may use alternative parsing techniques to list DLLs.
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Get Module Map of 'explorer.exe'. \n");
|
|
ShowKeyPress();
|
|
PVMMDLL_MAP_MODULE pModuleMap = NULL;
|
|
printf("CALL: VMMDLL_Map_GetModuleU\n");
|
|
result = VMMDLL_Map_GetModuleU(hVMM, dwPID, &pModuleMap, 0);
|
|
if(!result) {
|
|
printf("FAIL: VMMDLL_Map_GetModuleU #1\n");
|
|
return 1;
|
|
}
|
|
if(pModuleMap->dwVersion != VMMDLL_MAP_MODULE_VERSION) {
|
|
printf("FAIL: VMMDLL_Map_GetModuleU - BAD VERSION\n");
|
|
VMMDLL_MemFree(pModuleMap); pModuleMap = NULL;
|
|
return 1;
|
|
}
|
|
{
|
|
printf("SUCCESS: VMMDLL_Map_GetModuleU\n");
|
|
printf(" MODULE_NAME BASE SIZE ENTRY PATH\n");
|
|
printf(" ==========================================================================================\n");
|
|
for(i = 0; i < pModuleMap->cMap; i++) {
|
|
printf(
|
|
" %-40.40s %s %016llx %08x %016llx %s\n",
|
|
pModuleMap->pMap[i].uszText,
|
|
pModuleMap->pMap[i].fWoW64 ? "32" : " ",
|
|
pModuleMap->pMap[i].vaBase,
|
|
pModuleMap->pMap[i].cbImageSize,
|
|
pModuleMap->pMap[i].vaEntry,
|
|
pModuleMap->pMap[i].uszFullName
|
|
);
|
|
}
|
|
VMMDLL_MemFree(pModuleMap); pModuleMap = NULL;
|
|
}
|
|
|
|
|
|
// Retrieve the list of loaded DLLs from the process and also include debug
|
|
// and versioning information. Extended information such as debug/versioning
|
|
// information is not included by default (included with flags) and require
|
|
// extra performance to fetch.
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Get Module Map with DEBUG & VERSION info of 'explorer.exe'.\n");
|
|
ShowKeyPress();
|
|
PVMMDLL_MAP_MODULE pModuleExMap = NULL;
|
|
printf("CALL: VMMDLL_Map_GetModuleU\n");
|
|
result = VMMDLL_Map_GetModuleU(hVMM, dwPID, &pModuleExMap, VMMDLL_MODULE_FLAG_DEBUGINFO | VMMDLL_MODULE_FLAG_VERSIONINFO);
|
|
if(!result) {
|
|
printf("FAIL: VMMDLL_Map_GetModuleU #1\n");
|
|
return 1;
|
|
}
|
|
if(pModuleExMap->dwVersion != VMMDLL_MAP_MODULE_VERSION) {
|
|
printf("FAIL: VMMDLL_Map_GetModuleU - BAD VERSION\n");
|
|
VMMDLL_MemFree(pModuleExMap); pModuleExMap = NULL;
|
|
return 1;
|
|
}
|
|
{
|
|
printf("SUCCESS: VMMDLL_Map_GetModuleU\n");
|
|
printf(" MODULE_NAME PDB-PATH CompanyName FileDescription InternalName\n");
|
|
printf(" ================================================================================================================================================================\n");
|
|
for(i = 0; i < pModuleExMap->cMap; i++) {
|
|
printf(
|
|
" %-40.40s %-32.32s %-32.32s %-32.32s %s\n",
|
|
pModuleExMap->pMap[i].uszText,
|
|
pModuleExMap->pMap[i].pExDebugInfo->uszPdbFilename,
|
|
pModuleExMap->pMap[i].pExVersionInfo->uszCompanyName,
|
|
pModuleExMap->pMap[i].pExVersionInfo->uszFileDescription,
|
|
pModuleExMap->pMap[i].pExVersionInfo->uszInternalName
|
|
);
|
|
}
|
|
VMMDLL_MemFree(pModuleExMap); pModuleExMap = NULL;
|
|
}
|
|
|
|
|
|
// Retrieve the list of unloaded DLLs from the process. Please note that
|
|
// Windows only keeps references of the most recent 50-64 entries.
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Get Unloaded Module Map of 'explorer.exe'. \n");
|
|
ShowKeyPress();
|
|
PVMMDLL_MAP_UNLOADEDMODULE pUnloadedMap = NULL;
|
|
printf("CALL: VMMDLL_Map_GetUnloadedModuleU\n");
|
|
result = VMMDLL_Map_GetUnloadedModuleU(hVMM, dwPID, &pUnloadedMap);
|
|
if(!result) {
|
|
printf("FAIL: VMMDLL_Map_GetUnloadedModuleU\n");
|
|
return 1;
|
|
}
|
|
if(pUnloadedMap->dwVersion != VMMDLL_MAP_UNLOADEDMODULE_VERSION) {
|
|
printf("FAIL: VMMDLL_Map_GetUnloadedModuleU - BAD VERSION\n");
|
|
VMMDLL_MemFree(pUnloadedMap); pUnloadedMap = NULL;
|
|
return 1;
|
|
}
|
|
{
|
|
printf("SUCCESS: VMMDLL_Map_GetUnloadedModuleU\n");
|
|
printf(" MODULE_NAME BASE SIZE\n");
|
|
printf(" =================================================================\n");
|
|
for(i = 0; i < pUnloadedMap->cMap; i++) {
|
|
printf(
|
|
" %-40.40s %s %016llx %08x\n",
|
|
pUnloadedMap->pMap[i].uszText,
|
|
pUnloadedMap->pMap[i].fWoW64 ? "32" : " ",
|
|
pUnloadedMap->pMap[i].vaBase,
|
|
pUnloadedMap->pMap[i].cbImageSize
|
|
);
|
|
}
|
|
VMMDLL_MemFree(pUnloadedMap); pUnloadedMap = NULL;
|
|
}
|
|
|
|
|
|
// Retrieve the module of explorer.exe by its name. Note it is also possible
|
|
// to retrieve it by retrieving the complete module map (list) and iterate
|
|
// over it. But if the name of the module is known this is more convenient.
|
|
// This required that the PEB and LDR list in-process haven't been tampered
|
|
// with ...
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Get module by name 'explorer.exe' in 'explorer.exe'. \n");
|
|
ShowKeyPress();
|
|
printf("CALL: VMMDLL_Map_GetModuleFromNameU\n");
|
|
PVMMDLL_MAP_MODULEENTRY pModuleEntryExplorer;
|
|
result = VMMDLL_Map_GetModuleFromNameU(hVMM, dwPID, "explorer.exe", &pModuleEntryExplorer, 0);
|
|
if(result) {
|
|
printf("SUCCESS: VMMDLL_Map_GetModuleFromNameU\n");
|
|
printf(" MODULE_NAME BASE SIZE ENTRY\n");
|
|
printf(" ======================================================================================\n");
|
|
printf(
|
|
" %-40.40s %i %016llx %08x %016llx\n",
|
|
"explorer.exe",
|
|
pModuleEntryExplorer->fWoW64 ? 32 : 64,
|
|
pModuleEntryExplorer->vaBase,
|
|
pModuleEntryExplorer->cbImageSize,
|
|
pModuleEntryExplorer->vaEntry
|
|
);
|
|
} else {
|
|
printf("FAIL: VMMDLL_Map_GetModuleFromNameU\n");
|
|
VMMDLL_MemFree(pModuleEntryExplorer); pModuleEntryExplorer = NULL;
|
|
return 1;
|
|
}
|
|
|
|
|
|
// THREADS: Retrieve thread information about threads in the explorer.exe
|
|
// process and display on the screen.
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Get Thread Information of 'explorer.exe'. \n");
|
|
ShowKeyPress();
|
|
PVMMDLL_MAP_THREAD pThreadMap = NULL;
|
|
PVMMDLL_MAP_THREADENTRY pThreadMapEntry;
|
|
printf("CALL: VMMDLL_Map_GetThread\n");
|
|
result = VMMDLL_Map_GetThread(hVMM, dwPID, &pThreadMap);
|
|
if(!result) {
|
|
printf("FAIL: VMMDLL_Map_GetThread\n");
|
|
return 1;
|
|
}
|
|
if(pThreadMap->dwVersion != VMMDLL_MAP_THREAD_VERSION) {
|
|
printf("FAIL: VMMDLL_Map_GetThread - BAD VERSION\n");
|
|
VMMDLL_MemFree(pThreadMap); pThreadMap = NULL;
|
|
return 1;
|
|
}
|
|
{
|
|
printf("SUCCESS: VMMDLL_Map_GetThread\n");
|
|
printf(" # TID PID ADDR_TEB ADDR_ETHREAD ADDR_START INSTRUCTION_PTR STACK[BASE:TOP]:PTR\n");
|
|
printf(" ==============================================================================================================\n");
|
|
for(i = 0; i < pThreadMap->cMap; i++) {
|
|
pThreadMapEntry = &pThreadMap->pMap[i];
|
|
printf(
|
|
" %04x %8x %8x %016llx %016llx %016llx [%016llx->%016llx]:%016llx %016llx\n",
|
|
i,
|
|
pThreadMapEntry->dwTID,
|
|
pThreadMapEntry->dwPID,
|
|
pThreadMapEntry->vaTeb,
|
|
pThreadMapEntry->vaETHREAD,
|
|
pThreadMapEntry->vaStartAddress,
|
|
pThreadMapEntry->vaStackBaseUser,
|
|
pThreadMapEntry->vaStackLimitUser,
|
|
pThreadMapEntry->vaRSP,
|
|
pThreadMapEntry->vaRIP
|
|
);
|
|
}
|
|
VMMDLL_MemFree(pThreadMap); pThreadMap = NULL;
|
|
}
|
|
|
|
|
|
// THREAD CALLSTACK: Retrieve callstack information for the threads in the
|
|
// 'smss.exe' process and display on the screen.
|
|
DWORD dwPID_SMSS = 0;
|
|
PVMMDLL_MAP_THREAD pThreadMap_SMSS = NULL;
|
|
PVMMDLL_MAP_THREADENTRY pThreadMapEntry_SMSS;
|
|
PVMMDLL_MAP_THREAD_CALLSTACK pThreadCallstack = NULL;
|
|
PVMMDLL_MAP_THREAD_CALLSTACKENTRY pThreadCallstackEntry = NULL;
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Get Thread Callstack Information of 'smss.exe' threads. \n");
|
|
ShowKeyPress();
|
|
VMMDLL_PidGetFromName(hVMM, "smss.exe", &dwPID_SMSS);
|
|
VMMDLL_Map_GetThread(hVMM, dwPID_SMSS, &pThreadMap_SMSS);
|
|
if(!dwPID_SMSS || !pThreadMap_SMSS) {
|
|
printf("FAIL: VMMDLL_PidGetFromName//VMMDLL_Map_GetThread\n");
|
|
return 1;
|
|
}
|
|
for(i = 0; i < pThreadMap_SMSS->cMap; i++) {
|
|
pThreadMapEntry_SMSS = &pThreadMap_SMSS->pMap[i];
|
|
printf("CALL: VMMDLL_Map_GetThread_CallstackU\n");
|
|
result = VMMDLL_Map_GetThread_CallstackU(hVMM, dwPID_SMSS, pThreadMapEntry_SMSS->dwTID, 0, &pThreadCallstack);
|
|
if(!result) {
|
|
printf("FAIL: VMMDLL_Map_GetThread_CallstackU\n");
|
|
return 1;
|
|
}
|
|
printf("SUCCESS: VMMDLL_Map_GetThread_CallstackU\n");
|
|
printf("%s", pThreadCallstack->uszText);
|
|
printf("-------------\n");
|
|
for(j = 0; j < pThreadCallstack->cMap; j++) {
|
|
pThreadCallstackEntry = &pThreadCallstack->pMap[j];
|
|
printf("%02x: %016llx %016llx :: %s!%s+%x\n", pThreadCallstackEntry->i, pThreadCallstackEntry->vaRSP, pThreadCallstackEntry->vaRetAddr, pThreadCallstackEntry->uszModule, pThreadCallstackEntry->uszFunction, pThreadCallstackEntry->cbDisplacement);
|
|
}
|
|
printf("------------------------------------------------------------\n");
|
|
VMMDLL_MemFree(pThreadCallstack); pThreadCallstack = NULL;
|
|
}
|
|
VMMDLL_MemFree(pThreadMap_SMSS); pThreadMap_SMSS = NULL;
|
|
|
|
|
|
// HANDLES: Retrieve handle information about handles in the explorer.exe
|
|
// process and display on the screen.
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Get Handle Information of 'explorer.exe'. \n");
|
|
ShowKeyPress();
|
|
PVMMDLL_MAP_HANDLE pHandleMap = NULL;
|
|
PVMMDLL_MAP_HANDLEENTRY pHandleMapEntry;
|
|
printf("CALL: VMMDLL_Map_GetHandleU\n");
|
|
result = VMMDLL_Map_GetHandleU(hVMM, dwPID, &pHandleMap);
|
|
if(!result) {
|
|
printf("FAIL: VMMDLL_Map_GetHandleU\n");
|
|
return 1;
|
|
}
|
|
if(pHandleMap->dwVersion != VMMDLL_MAP_HANDLE_VERSION) {
|
|
printf("FAIL: VMMDLL_Map_GetHandleU - BAD VERSION\n");
|
|
VMMDLL_MemFree(pHandleMap); pHandleMap = NULL;
|
|
return 1;
|
|
}
|
|
{
|
|
printf("SUCCESS: VMMDLL_Map_GetHandleU\n");
|
|
printf(" # HANDLE PID ADDR_OBJECT ACCESS TYPE DESCRIPTION\n");
|
|
printf(" ===========================================================================\n");
|
|
for(i = 0; i < pHandleMap->cMap; i++) {
|
|
pHandleMapEntry = &pHandleMap->pMap[i];
|
|
printf(
|
|
" %04x %8x %8x %016llx %6x %-16s %s\n",
|
|
i,
|
|
pHandleMapEntry->dwHandle,
|
|
pHandleMapEntry->dwPID,
|
|
pHandleMapEntry->vaObject,
|
|
pHandleMapEntry->dwGrantedAccess,
|
|
pHandleMapEntry->uszType,
|
|
pHandleMapEntry->uszText
|
|
);
|
|
}
|
|
VMMDLL_MemFree(pHandleMap); pHandleMap = NULL;
|
|
}
|
|
|
|
|
|
// HEAPS: Retrieve heap information about handles in the explorer.exe
|
|
// process and display on the screen.
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Get Heap Information of 'explorer.exe'. \n");
|
|
ShowKeyPress();
|
|
PVMMDLL_MAP_HEAP pHeapMap = NULL;
|
|
PVMMDLL_MAP_HEAPENTRY pHeapMapEntry;
|
|
printf("CALL: VMMDLL_Map_GetHeap\n");
|
|
result = VMMDLL_Map_GetHeap(hVMM, dwPID, &pHeapMap);
|
|
if(!result) {
|
|
printf("FAIL: VMMDLL_Map_GetHeap\n");
|
|
return 1;
|
|
}
|
|
if(pHeapMap->dwVersion != VMMDLL_MAP_HEAP_VERSION) {
|
|
printf("FAIL: VMMDLL_Map_GetHeap - BAD VERSION\n");
|
|
VMMDLL_MemFree(pHeapMap); pHeapMap = NULL;
|
|
return 1;
|
|
}
|
|
{
|
|
printf("SUCCESS: VMMDLL_Map_GetHeap\n");
|
|
printf(" # PID ADDR_HEAP HEAP# TYPE\n");
|
|
printf(" ======================================\n");
|
|
for(i = 0; i < pHeapMap->cMap; i++) {
|
|
pHeapMapEntry = &pHeapMap->pMap[i];
|
|
printf(
|
|
" %04x%7i %016llx %3i %2i %s\n",
|
|
pHeapMapEntry->iHeap,
|
|
dwPID,
|
|
pHeapMapEntry->va,
|
|
pHeapMapEntry->dwHeapNum,
|
|
pHeapMapEntry->tp,
|
|
pHeapMapEntry->f32 ? "32" : ""
|
|
);
|
|
}
|
|
VMMDLL_MemFree(pHeapMap); pHeapMap = NULL;
|
|
}
|
|
|
|
|
|
// BINARY SEARCH WITH WILDCARD BITMASK for process PE header signatures.
|
|
// The search is performed at offset 0x0 in each 4096-byte memory page.
|
|
// Only search virtual memory above 4GB. For more information see vmmdll.h.
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Binary Search for PE header signatures in 'explorer.exe'. \n");
|
|
ShowKeyPress();
|
|
// Initialize search context and add one search term. Up to 16 search terms
|
|
// are possible to use at the same time for more efficient searches.
|
|
// In addition to the listed configuration it's possible to use callback
|
|
// functions for both which ranges should be scanned and for search results.
|
|
// Also additional properties for max address and more exists.
|
|
VMMDLL_MEM_SEARCH_CONTEXT_SEARCHENTRY SearchEntry3[3] = { 0 }; // an array which may hold up to 3 search terms (max).
|
|
VMMDLL_MEM_SEARCH_CONTEXT ctxSearch = { 0 };
|
|
ctxSearch.dwVersion = VMMDLL_MEM_SEARCH_VERSION; // required struct version.
|
|
ctxSearch.pSearch = SearchEntry3; // required pointer to search terms.
|
|
if(ctxSearch.cSearch < 3) {
|
|
ctxSearch.pSearch[ctxSearch.cSearch].cb = 4; // required number of bytes to search, max 32.
|
|
memcpy(ctxSearch.pSearch[ctxSearch.cSearch].pb,
|
|
(BYTE[4]) {
|
|
0x4d, 0x5a, 0x90, 0x00
|
|
}, 4); // required bytes to search for, max 32.
|
|
memcpy(ctxSearch.pSearch[ctxSearch.cSearch].pbSkipMask,
|
|
(BYTE[4]) {
|
|
0x00, 0x00, 0xff, 0x00
|
|
}, 4); // optional bitwise wildcard mask, here the 3rd byte is completely optional.
|
|
ctxSearch.pSearch[ctxSearch.cSearch].cbAlign = 0x1000; // optional alignment, i.e. search every X bytes,
|
|
// here we search in beginning of pages only.
|
|
// other common values are 0/1 (default) - full search
|
|
// and 8 - search every 8 bytes for 64-bit pointers.
|
|
ctxSearch.cSearch++;
|
|
}
|
|
ctxSearch.ReadFlags = VMMDLL_FLAG_NOCACHE; // optional read flags are possible to use.
|
|
ctxSearch.vaMin = 0x100000000; // optional start searching at 4GB in virtual memory
|
|
// perform the actual search:
|
|
printf("CALL: VMMDLL_MemSearch\n");
|
|
DWORD cvaSearchResult = 0;
|
|
PQWORD pvaSearchResult = NULL;
|
|
result = VMMDLL_MemSearch(hVMM, dwPID, &ctxSearch, &pvaSearchResult, &cvaSearchResult);
|
|
if(result) {
|
|
printf("SUCCESS: VMMDLL_MemSearch\n");
|
|
printf(" Number of search results: %u\n", cvaSearchResult);
|
|
printf(" ");
|
|
for(i = 0; i < cvaSearchResult; i++) {
|
|
printf(" 0x%016llx", pvaSearchResult[i]);
|
|
}
|
|
printf("\n");
|
|
VMMDLL_MemFree(pvaSearchResult); // free any function-allocated memory containing results.
|
|
} else {
|
|
printf("FAIL: VMMDLL_MemSearch\n");
|
|
VMMDLL_MemFree(pvaSearchResult); // free any function-allocated memory containing results.
|
|
return 1;
|
|
}
|
|
|
|
|
|
// YARA SEARCH for process PE header signatures.
|
|
// NB! YARA SEARCH REQUIRES 'vmmyara.dll'/'vmmyara.so' to be present in the vmm directory.
|
|
// The search is performed at offset 0x0in each scanned memory region (VAD or PTE).
|
|
// Only search virtual memory above 4GB. For more information see vmmdll.h.
|
|
// The search will return a maximum number of 32 results.
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# YARA Search for PE header signatures in 'explorer.exe'. \n");
|
|
ShowKeyPress();
|
|
VMMDLL_YARA_CONFIG ctxYara = { 0 };
|
|
ctxYara.dwVersion = VMMDLL_YARA_CONFIG_VERSION; // required struct version.
|
|
// YARA rules: Yara rules may be in the form of any number of strings as
|
|
// given in the below example.
|
|
// Yara rules may also be given in the form of one (1) file (including path)
|
|
// containing one or more YARA rules or index rules.
|
|
LPSTR szYaraRule1 = " rule mz_header { strings: $mz = \"MZ\" condition: $mz at 0 } ";
|
|
LPSTR szYaraRules[] = { szYaraRule1 };
|
|
ctxYara.pszRules = szYaraRules; // required YARA rules array.
|
|
ctxYara.cRules = 1; // required number of YARA rules.
|
|
ctxYara.pvUserPtrOpt = &ctxYara; // optional user pointer passed to callback functions
|
|
// here ctxYara is passed since we need to read the base address of the memory region.
|
|
// any other user-defined pointer may be set in ctxYara.pvUserPtrOpt2
|
|
ctxYara.cMaxResult = 16; // optional max number of results to return.
|
|
ctxYara.ReadFlags = VMMDLL_FLAG_NOCACHE; // optional read flags are possible to use.
|
|
ctxYara.vaMin = 0x100000000; // optional start searching at 4GB in virtual memory
|
|
ctxYara.pfnFilterOptCB = CallbackSearchYaraFilter; // optional callback function for filtering which memory ranges to scan.
|
|
ctxYara.pfnScanMemoryCB = CallbackSearchYaraMatch; // optional callback function for handling search results
|
|
// perform the actual search:
|
|
// Note that the the two last arguments works the same as in the VMMDLL_MemSearch() function.
|
|
// These are not used in this example though since a callback is used instead (it's possible to use both or just one of them).
|
|
printf("CALL: VMMDLL_YaraSearch\n");
|
|
result = VMMDLL_YaraSearch(hVMM, dwPID, &ctxYara, NULL, NULL);
|
|
if(result) {
|
|
printf("SUCCESS: VMMDLL_YaraSearch\n");
|
|
printf(" Number of search results: %u\n", ctxYara.cResult);
|
|
} else {
|
|
printf("FAIL: VMMDLL_YaraSearch\n");
|
|
// YARA search will fail if 'vmmyara.dll'/'vmmyara.so' is not present in the vmm directory.
|
|
}
|
|
|
|
|
|
// Write virtual memory at PE header of Explorer.EXE and display the first
|
|
// 0x80 bytes on-screen - afterwards. Maybe result of write is in there?
|
|
// (only if device is capable of writes and target system accepts writes)
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Try write to virtual memory of Explorer.EXE PE header \n");
|
|
printf(" NB! Write capable device is required for success! \n");
|
|
printf(" (1) Read existing data from virtual memory. \n");
|
|
printf(" (2) Try write to virtual memory at PE header. \n");
|
|
printf(" (3) Read resulting data from virtual memory. \n");
|
|
ShowKeyPress();
|
|
printf("CALL: VMMDLL_MemRead - BEFORE WRITE\n");
|
|
result = VMMDLL_MemRead(hVMM, dwPID, pModuleEntryExplorer->vaBase, pbPage1, 0x1000);
|
|
if(result) {
|
|
printf("SUCCESS: VMMDLL_MemRead - BEFORE WRITE\n");
|
|
PrintHexAscii(pbPage1, 0x80);
|
|
} else {
|
|
printf("FAIL: VMMDLL_MemRead - BEFORE WRITE\n");
|
|
return 1;
|
|
}
|
|
printf("CALL: VMMDLL_MemWrite\n");
|
|
DWORD cbWriteDataVirtual = 0x1c;
|
|
BYTE pbWriteDataVirtual[0x1c] = {
|
|
0x61, 0x6d, 0x20, 0x69, 0x73, 0x20, 0x6d, 0x6f,
|
|
0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x62,
|
|
0x79, 0x20, 0x4d, 0x65, 0x6d, 0x50, 0x72, 0x6f,
|
|
0x63, 0x46, 0x53, 0x00,
|
|
};
|
|
VMMDLL_MemWrite(hVMM, dwPID, pModuleEntryExplorer->vaBase + 0x58, pbWriteDataVirtual, cbWriteDataVirtual);
|
|
printf("CALL: VMMDLL_MemRead - AFTER WRITE\n");
|
|
result = VMMDLL_MemRead(hVMM, dwPID, pModuleEntryExplorer->vaBase, pbPage1, 0x1000);
|
|
if(result) {
|
|
printf("SUCCESS: VMMDLL_MemRead - AFTER WRITE\n");
|
|
PrintHexAscii(pbPage1, 0x80);
|
|
} else {
|
|
printf("FAIL: VMMDLL_MemRead - AFTER WRITE\n");
|
|
return 1;
|
|
}
|
|
|
|
|
|
// Retrieve the module of kernel32.dll by its name. Note it is also possible
|
|
// to retrieve it by retrieving the complete module map (list) and iterate
|
|
// over it. But if the name of the module is known this is more convenient.
|
|
// This required that the PEB and LDR list in-process haven't been tampered
|
|
// with ...
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Get by name 'kernel32.dll' in 'explorer.exe'. \n");
|
|
ShowKeyPress();
|
|
printf("CALL: VMMDLL_Map_GetModuleFromNameU\n");
|
|
PVMMDLL_MAP_MODULEENTRY pModuleEntryKernel32;
|
|
result = VMMDLL_Map_GetModuleFromNameU(hVMM, dwPID, "kernel32.dll", &pModuleEntryKernel32, 0);
|
|
if(result) {
|
|
printf("SUCCESS: VMMDLL_Map_GetModuleFromNameU\n");
|
|
printf(" MODULE_NAME BASE SIZE ENTRY\n");
|
|
printf(" ======================================================================================\n");
|
|
printf(
|
|
" %-40.40s %i %016llx %08x %016llx\n",
|
|
"kernel32.dll",
|
|
pModuleEntryKernel32->fWoW64 ? 32 : 64,
|
|
pModuleEntryKernel32->vaBase,
|
|
pModuleEntryKernel32->cbImageSize,
|
|
pModuleEntryKernel32->vaEntry
|
|
);
|
|
} else {
|
|
printf("FAIL: VMMDLL_Map_GetModuleFromNameU\n");
|
|
VMMDLL_MemFree(pModuleEntryKernel32); pModuleEntryKernel32 = NULL;
|
|
return 1;
|
|
}
|
|
|
|
|
|
// Retrieve the memory at the base of kernel32.dll previously fetched and
|
|
// display the first 0x200 bytes of it. This read is fetched from the cache
|
|
// by default (if possible). If reads should be forced from the DMA device
|
|
// please specify the flag: VMM_FLAG_NOCACHE
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Read 0x200 bytes of 'kernel32.dll' in 'explorer.exe'. \n");
|
|
ShowKeyPress();
|
|
DWORD cRead;
|
|
printf("CALL: VMMDLL_MemReadEx\n");
|
|
result = VMMDLL_MemReadEx(hVMM, dwPID, pModuleEntryKernel32->vaBase, pbPage2, 0x1000, &cRead, 0); // standard cached read
|
|
//result = VMMDLL_MemReadEx(dwPID, ModuleEntryKernel32.vaBase, pbPage2, 0x1000, &cRead, VMMDLL_FLAG_NOCACHE); // uncached read
|
|
if(result) {
|
|
printf("SUCCESS: VMMDLL_MemReadEx\n");
|
|
PrintHexAscii(pbPage2, min(cRead, 0x200));
|
|
} else {
|
|
printf("FAIL: VMMDLL_MemReadEx\n");
|
|
return 1;
|
|
}
|
|
|
|
|
|
// List the sections from the module of kernel32.dll.
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# List sections of 'kernel32.dll' in 'explorer.exe'. \n");
|
|
ShowKeyPress();
|
|
printf("CALL: VMMDLL_ProcessGetSectionsU #1\n");
|
|
DWORD cSections;
|
|
PIMAGE_SECTION_HEADER pSectionHeaders;
|
|
result = VMMDLL_ProcessGetSectionsU(hVMM, dwPID, "kernel32.dll", NULL, 0, &cSections);
|
|
if(result) {
|
|
printf("SUCCESS: VMMDLL_ProcessGetSectionsU #1\n");
|
|
printf(" Count = %i\n", cSections);
|
|
} else {
|
|
printf("FAIL: VMMDLL_ProcessGetSectionsU #1\n");
|
|
return 1;
|
|
}
|
|
pSectionHeaders = (PIMAGE_SECTION_HEADER)LocalAlloc(LMEM_ZEROINIT, cSections * sizeof(IMAGE_SECTION_HEADER));
|
|
if(!pSectionHeaders) {
|
|
printf("FAIL: OutOfMemory\n");
|
|
return 1;
|
|
}
|
|
printf("CALL: VMMDLL_ProcessGetSectionsU #2\n");
|
|
result = VMMDLL_ProcessGetSectionsU(hVMM, dwPID, "kernel32.dll", pSectionHeaders, cSections, &cSections);
|
|
if(result) {
|
|
printf("SUCCESS: VMMDLL_ProcessGetSectionsU #2\n");
|
|
printf(" # NAME OFFSET SIZE RWX\n");
|
|
printf(" =================================\n");
|
|
for(i = 0; i < cSections; i++) {
|
|
printf(
|
|
" %02x %-8.8s %08x %08x %c%c%c\n",
|
|
i,
|
|
pSectionHeaders[i].Name,
|
|
pSectionHeaders[i].VirtualAddress,
|
|
pSectionHeaders[i].Misc.VirtualSize,
|
|
(pSectionHeaders[i].Characteristics & IMAGE_SCN_MEM_READ) ? 'r' : '-',
|
|
(pSectionHeaders[i].Characteristics & IMAGE_SCN_MEM_WRITE) ? 'w' : '-',
|
|
(pSectionHeaders[i].Characteristics & IMAGE_SCN_MEM_EXECUTE) ? 'x' : '-'
|
|
);
|
|
}
|
|
} else {
|
|
printf("FAIL: VMMDLL_ProcessGetSectionsU #2\n");
|
|
return 1;
|
|
}
|
|
|
|
|
|
// Scatter Read memory from each of the sections of kernel32.dll in explorer.exe
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# 0x20 bytes of each 'kernel32.dll' section. \n");
|
|
ShowKeyPress();
|
|
PPMEM_SCATTER ppMEMs = NULL;
|
|
// Allocate empty scatter entries and populate them with the virtual addresses of
|
|
// the sections to read. If one wish to have a more efficient way of doing things
|
|
// without lots of copying of memory it's possible to initialize the ppMEMs array
|
|
// manually and set each individual MEM_SCATTER result byte buffer to point into
|
|
// own pre-allocated data buffer or use one of the other LcAllocScatterX() fns.
|
|
printf("CALL: LcAllocScatter1 #1\n");
|
|
if(LcAllocScatter1(cSections, &ppMEMs)) {
|
|
printf("SUCCESS: LcAllocScatter1 #1\n");
|
|
} else {
|
|
printf("FAIL: LcAllocScatter1 #1\n");
|
|
return 1;
|
|
}
|
|
for(i = 0; i < cSections; i++) {
|
|
// populate the virtual address of each scatter entry with the address to read
|
|
// (sections are assumed to be page-aligned in virtual memory.
|
|
ppMEMs[i]->qwA = pModuleEntryKernel32->vaBase + pSectionHeaders[i].VirtualAddress;
|
|
}
|
|
// Scatter Read - read all scatter entries in one efficient go. In this
|
|
// example the internal VMM cache is not to be used, and virtual memory
|
|
// is not to be used. One can skip the flags to get default behaviour -
|
|
// that is use cache and paging, and keep buffer byte data as-is on fail.
|
|
printf("CALL: VMMDLL_MemReadScatter #1\n");
|
|
if(VMMDLL_MemReadScatter(hVMM, dwPID, ppMEMs, cSections, VMMDLL_FLAG_NOCACHE | VMMDLL_FLAG_ZEROPAD_ON_FAIL | VMMDLL_FLAG_NOPAGING)) {
|
|
printf("SUCCESS: VMMDLL_MemReadScatter #1\n");
|
|
} else {
|
|
printf("FAIL: VMMDLL_MemReadScatter #1\n");
|
|
return 1;
|
|
}
|
|
// print result
|
|
for(i = 0; i < cSections; i++) {
|
|
printf("--------------\n %s\n", pSectionHeaders[i].Name);
|
|
if(ppMEMs[i]->f) {
|
|
PrintHexAscii(ppMEMs[i]->pb, 0x40);
|
|
} else {
|
|
printf("[read failed]\n");
|
|
}
|
|
}
|
|
// free previosly allocated ppMEMs;
|
|
LcMemFree(ppMEMs);
|
|
|
|
|
|
// Retrieve and display the data directories of kernel32.dll. The number of
|
|
// data directories in a PE is always 16 - so this can be used to simplify
|
|
// calling the functionality somewhat.
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# List directories of 'kernel32.dll' in 'explorer.exe'. \n");
|
|
ShowKeyPress();
|
|
LPCSTR DIRECTORIES[16] = { "EXPORT", "IMPORT", "RESOURCE", "EXCEPTION", "SECURITY", "BASERELOC", "DEBUG", "ARCHITECTURE", "GLOBALPTR", "TLS", "LOAD_CONFIG", "BOUND_IMPORT", "IAT", "DELAY_IMPORT", "COM_DESCRIPTOR", "RESERVED" };
|
|
IMAGE_DATA_DIRECTORY pDirectories[16];
|
|
printf("CALL: VMMDLL_ProcessGetDirectoriesU\n");
|
|
result = VMMDLL_ProcessGetDirectoriesU(hVMM, dwPID, "kernel32.dll", pDirectories);
|
|
if(result) {
|
|
printf("SUCCESS: PCIleech_VmmProcess_GetDirectories\n");
|
|
printf(" # NAME OFFSET SIZE\n");
|
|
printf(" =====================================\n");
|
|
for(i = 0; i < 16; i++) {
|
|
printf(
|
|
" %02x %-16.16s %08x %08x\n",
|
|
i,
|
|
DIRECTORIES[i],
|
|
pDirectories[i].VirtualAddress,
|
|
pDirectories[i].Size
|
|
);
|
|
}
|
|
} else {
|
|
printf("FAIL: VMMDLL_ProcessGetDirectoriesU\n");
|
|
return 1;
|
|
}
|
|
|
|
|
|
// Retrieve the export address table (EAT) of kernel32.dll
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# exports of 'kernel32.dll' in 'explorer.exe'. \n");
|
|
ShowKeyPress();
|
|
PVMMDLL_MAP_EAT pEatMap = NULL;
|
|
PVMMDLL_MAP_EATENTRY pEatMapEntry;
|
|
printf("CALL: VMMDLL_Map_GetEATU\n");
|
|
result = VMMDLL_Map_GetEATU(hVMM, dwPID, "kernel32.dll", &pEatMap);
|
|
if(!result) {
|
|
printf("FAIL: VMMDLL_Map_GetEATU\n");
|
|
return 1;
|
|
}
|
|
if(pEatMap->dwVersion != VMMDLL_MAP_EAT_VERSION) {
|
|
printf("FAIL: VMMDLL_Map_GetEATU - BAD VERSION\n");
|
|
VMMDLL_MemFree(pEatMap); pEatMap = NULL;
|
|
return 1;
|
|
}
|
|
{
|
|
printf("SUCCESS: VMMDLL_Map_GetEATU\n");
|
|
printf(" # ORDINAL ADDRESS NAME ->ForwardedFunction\n");
|
|
printf(" =================================================\n");
|
|
for(i = 0; i < pEatMap->cMap; i++) {
|
|
pEatMapEntry = pEatMap->pMap + i;
|
|
printf(
|
|
" %04x %4x %12llx %s ->%s\n",
|
|
i,
|
|
pEatMapEntry->dwOrdinal,
|
|
pEatMapEntry->vaFunction,
|
|
pEatMapEntry->uszFunction,
|
|
pEatMapEntry->uszForwardedFunction
|
|
);
|
|
}
|
|
VMMDLL_MemFree(pEatMap); pEatMap = NULL;
|
|
}
|
|
|
|
|
|
// Retrieve the import address table (IAT) of kernel32.dll
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# imports of 'kernel32.dll' in 'explorer.exe'. \n");
|
|
ShowKeyPress();
|
|
DWORD cbIatMap = 0;
|
|
PVMMDLL_MAP_IAT pIatMap = NULL;
|
|
PVMMDLL_MAP_IATENTRY pIatMapEntry;
|
|
printf("CALL: VMMDLL_Map_GetIATU\n");
|
|
result = VMMDLL_Map_GetIATU(hVMM, dwPID, "kernel32.dll", &pIatMap);
|
|
if(!result) {
|
|
printf("FAIL: VMMDLL_Map_GetIATU\n");
|
|
return 1;
|
|
}
|
|
if(pIatMap->dwVersion != VMMDLL_MAP_IAT_VERSION) {
|
|
printf("FAIL: VMMDLL_Map_GetIATU - BAD VERSION\n");
|
|
VMMDLL_MemFree(pIatMap); pIatMap = NULL;
|
|
return 1;
|
|
}
|
|
{
|
|
printf("SUCCESS: VMMDLL_Map_GetIATU\n");
|
|
printf(" # VIRTUAL_ADDRESS MODULE!NAME\n");
|
|
printf(" ===================================\n");
|
|
for(i = 0; i < pIatMap->cMap; i++) {
|
|
pIatMapEntry = pIatMap->pMap + i;
|
|
printf(
|
|
" %04x %016llx %s!%s\n",
|
|
i,
|
|
pIatMapEntry->vaFunction,
|
|
pIatMapEntry->uszModule,
|
|
pIatMapEntry->uszFunction
|
|
);
|
|
}
|
|
VMMDLL_MemFree(pIatMap); pIatMap = NULL;
|
|
}
|
|
|
|
|
|
// Initialize the plugin manager for the Vfs functionality to work.
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Initialize Plugin Manager functionality as is required \n");
|
|
printf(" by virtual file system (vfs) functionality. \n");
|
|
ShowKeyPress();
|
|
printf("CALL: VMMDLL_InitializePlugins\n");
|
|
result = VMMDLL_InitializePlugins(hVMM);
|
|
if(result) {
|
|
printf("SUCCESS: VMMDLL_InitializePlugins\n");
|
|
} else {
|
|
printf("FAIL: VMMDLL_InitializePlugins\n");
|
|
return 1;
|
|
}
|
|
|
|
|
|
// The Memory Process File System exists virtually in the form of a virtual
|
|
// file system even if it may not be mounted at a mount point or drive.
|
|
// It is possible to call the functions 'List', 'Read' and 'Write' by using
|
|
// the API.
|
|
// Virtual File System: 'List'.
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Call the file system 'List' function on the root dir. \n");
|
|
ShowKeyPress();
|
|
VMMDLL_VFS_FILELIST2 VfsFileList;
|
|
VfsFileList.dwVersion = VMMDLL_VFS_FILELIST_VERSION;
|
|
VfsFileList.h = 0; // your handle passed to the callback functions (not used in example).
|
|
VfsFileList.pfnAddDirectory = CallbackList_AddDirectory;
|
|
VfsFileList.pfnAddFile = CallbackList_AddFile;
|
|
printf("CALL: VMMDLL_VfsListU\n");
|
|
result = VMMDLL_VfsListU(hVMM, "\\", &VfsFileList);
|
|
if(result) {
|
|
printf("SUCCESS: VMMDLL_VfsListU\n");
|
|
} else {
|
|
printf("FAIL: VMMDLL_VfsListU\n");
|
|
return 1;
|
|
}
|
|
|
|
|
|
// Virtual File System: 'Read' of 0x100 bytes from the offset 0x1000
|
|
// in the physical memory by reading the /pmem physical memory file.
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Call the file system 'Read' function on memory.pmem. \n");
|
|
ShowKeyPress();
|
|
printf("CALL: VMMDLL_VfsReadU\n");
|
|
nt = VMMDLL_VfsReadU(hVMM, "\\memory.pmem", pbPage1, 0x100, &i, 0x1000);
|
|
if(nt == VMMDLL_STATUS_SUCCESS) {
|
|
printf("SUCCESS: VMMDLL_VfsReadU\n");
|
|
PrintHexAscii(pbPage1, i);
|
|
} else {
|
|
printf("FAIL: VMMDLL_VfsReadU\n");
|
|
return 1;
|
|
}
|
|
|
|
|
|
// Virtual File System: 'Read' statistics from the .status module/plugin.
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Call file system 'Read' on conf\\statistics.txt \n");
|
|
ShowKeyPress();
|
|
printf("CALL: VMMDLL_VfsReadU\n");
|
|
ZeroMemory(pbPage1, 0x1000);
|
|
nt = VMMDLL_VfsReadU(hVMM, "\\conf\\statistics.txt", pbPage1, 0xfff, &i, 0);
|
|
if(nt == VMMDLL_STATUS_SUCCESS) {
|
|
printf("SUCCESS: VMMDLL_VfsReadU\n");
|
|
printf("%s", (LPSTR)pbPage1);
|
|
} else {
|
|
printf("FAIL: VMMDLL_VfsReadU\n");
|
|
return 1;
|
|
}
|
|
|
|
|
|
// Get base virtual address of ntoskrnl.exe
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Get ntoskrnl.exe base virtual address \n");
|
|
ShowKeyPress();
|
|
printf("CALL: VMMDLL_ProcessGetModuleBaseU\n");
|
|
va = VMMDLL_ProcessGetModuleBaseU(hVMM, 4, "ntoskrnl.exe");
|
|
if(va) {
|
|
printf("SUCCESS: VMMDLL_ProcessGetModuleBaseU\n");
|
|
printf(" %s = %016llx\n", "ntoskrnl.exe", va);
|
|
} else {
|
|
printf("FAIL: VMMDLL_ProcessGetModuleBaseU\n");
|
|
return 1;
|
|
}
|
|
|
|
|
|
// GetProcAddress from ntoskrnl.exe
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Get proc address for ntoskrnl.exe!KeGetCurrentIrql \n");
|
|
ShowKeyPress();
|
|
printf("CALL: VMMDLL_ProcessGetProcAddressU\n");
|
|
va = VMMDLL_ProcessGetProcAddressU(hVMM, 4, "ntoskrnl.exe", "KeGetCurrentIrql");
|
|
if(va) {
|
|
printf("SUCCESS: VMMDLL_ProcessGetProcAddressU\n");
|
|
printf(" %s!%s = %016llx\n", "ntoskrnl.exe", "KeGetCurrentIrql", va);
|
|
} else {
|
|
printf("FAIL: VMMDLL_ProcessGetProcAddressU\n");
|
|
return 1;
|
|
}
|
|
|
|
|
|
// Get IAT Thunk ntoskrnl.exe -> hal.dll!HalSendNMI
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# 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_WinGetThunkInfoIATU\n");
|
|
result = VMMDLL_WinGetThunkInfoIATU(hVMM, 4, "ntoskrnl.Exe", "hal.Dll", "HalSendNMI", &oThunkInfoIAT);
|
|
if(result) {
|
|
printf("SUCCESS: VMMDLL_WinGetThunkInfoIATU\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_WinGetThunkInfoIATU\n");
|
|
return 1;
|
|
}
|
|
|
|
|
|
// List Windows registry hives
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# List Windows Registry Hives. \n");
|
|
ShowKeyPress();
|
|
DWORD cWinRegHives;
|
|
PVMMDLL_REGISTRY_HIVE_INFORMATION pWinRegHives = NULL;
|
|
printf("CALL: VMMDLL_WinReg_HiveList\n");
|
|
result = VMMDLL_WinReg_HiveList(hVMM, NULL, 0, &cWinRegHives);
|
|
if(!result || !cWinRegHives) {
|
|
printf("FAIL: VMMDLL_WinReg_HiveList #1 - Get # Hives.\n");
|
|
return 1;
|
|
}
|
|
pWinRegHives = LocalAlloc(LMEM_ZEROINIT, cWinRegHives * sizeof(VMMDLL_REGISTRY_HIVE_INFORMATION));
|
|
if(!pWinRegHives) {
|
|
printf("FAIL: OutOfMemory\n");
|
|
return 1;
|
|
}
|
|
result = VMMDLL_WinReg_HiveList(hVMM, pWinRegHives, cWinRegHives, &cWinRegHives);
|
|
if(result && cWinRegHives) {
|
|
printf("SUCCESS: VMMDLL_WinReg_HiveList\n");
|
|
for(i = 0; i < cWinRegHives; i++) {
|
|
printf(" %s\n", pWinRegHives[i].uszName);
|
|
}
|
|
} else {
|
|
printf("FAIL: VMMDLL_WinReg_HiveList #2\n");
|
|
return 1;
|
|
}
|
|
|
|
|
|
// Read 0x100 bytes from offset 0x1000 from the 1st located registry hive memory space
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Read 0x100 bytes from offset 0x1000 of registry hive \n");
|
|
ShowKeyPress();
|
|
printf("CALL: VMMDLL_WinReg_HiveReadEx\n");
|
|
result = VMMDLL_WinReg_HiveReadEx(hVMM, pWinRegHives[0].vaCMHIVE, 0x1000, pbPage1, 0x100, NULL, 0);
|
|
if(result) {
|
|
printf("SUCCESS: VMMDLL_WinReg_HiveReadEx\n");
|
|
PrintHexAscii(pbPage1, 0x100);
|
|
} else {
|
|
printf("FAIL: VMMDLL_WinReg_HiveReadEx\n");
|
|
return 1;
|
|
}
|
|
|
|
|
|
// Enumerate keys under HKLM\SOFTWARE
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Registry: Enumerate keys under 'HKLM\\SOFTWARE' \n");
|
|
printf("------------------------------------------------------------\n");
|
|
ShowKeyPress();
|
|
i = 0;
|
|
while(TRUE) {
|
|
cch = sizeof(usz);
|
|
result = VMMDLL_WinReg_EnumKeyExU(hVMM, "HKLM\\SOFTWARE", i, usz, &cch, NULL);
|
|
if(!result) { break; }
|
|
printf("%2i RegKey='%s'\n", i, usz);
|
|
i++;
|
|
}
|
|
|
|
|
|
// Enumerate values under HKLM\SOFTWARE
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Registry: Enumerate values under--------------------------\n");
|
|
printf(" 'HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run'\n");
|
|
printf("------------------------------------------------------------\n");
|
|
ShowKeyPress();
|
|
i = 0;
|
|
while(TRUE) {
|
|
cch = sizeof(usz);
|
|
result = VMMDLL_WinReg_EnumValueU(hVMM, "HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", i, usz, &cch, NULL, NULL, NULL);
|
|
if(!result) { break; }
|
|
printf("%2i RegValue='%s'\n", i, usz);
|
|
i++;
|
|
}
|
|
|
|
|
|
// Query individual registry values under HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\ProgramFilesDir
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Registry: Query a single registry value-------------------\n");
|
|
printf(" 'HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\ProgramFilesDir'\n");
|
|
printf(" Registry stores most string values in UTF-16 LE, WCHAR. \n");
|
|
printf("------------------------------------------------------------\n");
|
|
ShowKeyPress();
|
|
dw = 0;
|
|
cch = sizeof(pbPage1) - 4;
|
|
ZeroMemory(pbPage1, sizeof(pbPage1));
|
|
result = VMMDLL_WinReg_QueryValueExU(hVMM, "HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\ProgramFilesDir", &dw, pbPage1, &cch);
|
|
if(!result) {
|
|
printf("FAIL: VMMDLL_WinReg_QueryValueExU\n");
|
|
return 1;
|
|
} else {
|
|
printf("SUCCESS: VMMDLL_WinReg_QueryValueExU\n");
|
|
printf(" Value='%S' ByteSize=%i Type=%i\n", (LPWSTR)pbPage1, cch, dw);
|
|
}
|
|
|
|
|
|
// Retrieve Physical Memory Map
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Retrieve Physical Memory Map \n");
|
|
ShowKeyPress();
|
|
PVMMDLL_MAP_PHYSMEM pPhysMemMap = NULL;
|
|
printf("CALL: VMMDLL_Map_GetPhysMem\n");
|
|
result = VMMDLL_Map_GetPhysMem(hVMM, &pPhysMemMap);
|
|
if(!result) {
|
|
printf("FAIL: VMMDLL_Map_GetPhysMem #1 - Get # Hives.\n");
|
|
return 1;
|
|
}
|
|
if(pPhysMemMap->dwVersion != VMMDLL_MAP_PHYSMEM_VERSION) {
|
|
printf("FAIL: VMMDLL_Map_GetPhysMem - BAD VERSION\n");
|
|
VMMDLL_MemFree(pPhysMemMap); pPhysMemMap = NULL;
|
|
return 1;
|
|
}
|
|
{
|
|
printf("SUCCESS: VMMDLL_Map_GetPhysMem\n");
|
|
for(i = 0; i < pPhysMemMap->cMap; i++) {
|
|
printf("%04i %12llx - %12llx\n", i, pPhysMemMap->pMap[i].pa, pPhysMemMap->pMap[i].pa + pPhysMemMap->pMap[i].cb - 1);
|
|
}
|
|
VMMDLL_MemFree(pPhysMemMap); pPhysMemMap = NULL;
|
|
}
|
|
|
|
|
|
// Retrieve Page Frame Number (PFN) information for pages located at
|
|
// physical addresses 0x00001000, 0x00677000, 0x27000000, 0x18000000
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Retrieve PAGE FRAME NUMBERS (PFNs) \n");
|
|
ShowKeyPress();
|
|
DWORD cbPfnMap = 0, cPfns, dwPfns[] = { 1, 0x677, 0x27000, 0x18000 };
|
|
PVMMDLL_MAP_PFN pPfnMap = NULL;
|
|
PVMMDLL_MAP_PFNENTRY pPfnEntry;
|
|
cPfns = sizeof(dwPfns) / sizeof(DWORD);
|
|
printf("CALL: VMMDLL_Map_GetPfn #1\n");
|
|
result = VMMDLL_Map_GetPfn(hVMM, dwPfns, cPfns, NULL, &cbPfnMap);
|
|
if(!result) {
|
|
printf("FAIL: VMMDLL_Map_GetPfn #1\n");
|
|
return 1;
|
|
}
|
|
pPfnMap = LocalAlloc(LMEM_ZEROINIT, cbPfnMap);
|
|
if(!pPfnMap) {
|
|
printf("FAIL: OutOfMemory\n");
|
|
return 1;
|
|
}
|
|
result = VMMDLL_Map_GetPfn(hVMM, dwPfns, cPfns, pPfnMap, &cbPfnMap);
|
|
if(!result) {
|
|
printf("FAIL: VMMDLL_Map_GetPfn #2\n");
|
|
return 1;
|
|
}
|
|
if(pPfnMap->dwVersion != VMMDLL_MAP_PFN_VERSION) {
|
|
printf("FAIL: VMMDLL_Map_GetPfn - BAD VERSION\n");
|
|
return 1;
|
|
}
|
|
{
|
|
printf("SUCCESS: VMMDLL_Map_GetPfn\n");
|
|
printf("# PFN# TYPE TYPEEX VA\n");
|
|
for(i = 0; i < pPfnMap->cMap; i++) {
|
|
pPfnEntry = pPfnMap->pMap + i;
|
|
printf(
|
|
"%i%8i %-10s %-10s %16llx\n",
|
|
i,
|
|
pPfnEntry->dwPfn,
|
|
VMMDLL_PFN_TYPE_TEXT[pPfnEntry->PageLocation],
|
|
VMMDLL_PFN_TYPEEXTENDED_TEXT[pPfnEntry->tpExtended],
|
|
pPfnEntry->vaPte
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
// Retrieve services from the service control manager (SCM) and display
|
|
// select information about the services.
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Retrieve SERVICES \n");
|
|
ShowKeyPress();
|
|
PVMMDLL_MAP_SERVICE pServiceMap = NULL;
|
|
PVMMDLL_MAP_SERVICEENTRY pServiceEntry;
|
|
printf("CALL: VMMDLL_Map_GetServicesU\n");
|
|
result = VMMDLL_Map_GetServicesU(hVMM, &pServiceMap);
|
|
if(!result) {
|
|
printf("FAIL: VMMDLL_Map_GetServicesU #1\n");
|
|
return 1;
|
|
}
|
|
if(pServiceMap->dwVersion != VMMDLL_MAP_SERVICE_VERSION) {
|
|
printf("FAIL: VMMDLL_Map_GetServicesU - BAD VERSION\n");
|
|
VMMDLL_MemFree(pServiceMap); pServiceMap = NULL;
|
|
return 1;
|
|
}
|
|
{
|
|
printf("SUCCESS: VMMDLL_Map_GetServicesU\n");
|
|
printf("# PID VA-OBJ STATE NAME PATH [USER]\n");
|
|
for(i = 0; i < pServiceMap->cMap; i++) {
|
|
pServiceEntry = pServiceMap->pMap + i;
|
|
printf(
|
|
"%02i%7i %12llx %02i %-32s %s [%s]\n",
|
|
pServiceEntry->dwOrdinal,
|
|
pServiceEntry->dwPID,
|
|
pServiceEntry->vaObj,
|
|
pServiceEntry->ServiceStatus.dwCurrentState,
|
|
pServiceEntry->uszServiceName,
|
|
pServiceEntry->uszPath,
|
|
pServiceEntry->uszUserAcct
|
|
);
|
|
}
|
|
VMMDLL_MemFree(pServiceMap); pServiceMap = NULL;
|
|
}
|
|
|
|
|
|
// Retrieve Pool Tag Map
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Retrieve Pool Tag Map \n");
|
|
ShowKeyPress();
|
|
DWORD iPoolTagEntry = 0, iPoolEntry = 0;
|
|
PVMMDLL_MAP_POOL pPoolMap = NULL;
|
|
PVMMDLL_MAP_POOLENTRY pPoolEntry;
|
|
PVMMDLL_MAP_POOLENTRYTAG pPoolTag;
|
|
printf("CALL: VMMDLL_Map_GetPool\n");
|
|
result = VMMDLL_Map_GetPool(hVMM, &pPoolMap, VMMDLL_POOLMAP_FLAG_ALL);
|
|
if(!result) {
|
|
printf("FAIL: VMMDLL_Map_GetPool.\n");
|
|
return 1;
|
|
}
|
|
if(pPoolMap->dwVersion != VMMDLL_MAP_POOL_VERSION) {
|
|
printf("FAIL: VMMDLL_Map_GetPool - BAD VERSION\n");
|
|
VMMDLL_MemFree(pPoolMap); pPoolMap = NULL;
|
|
return 1;
|
|
}
|
|
if(result) {
|
|
// print all pool tag addresses consisting of TcpE - TCP Endpoint
|
|
// NB! The retrieval of the pool tag consiting of the first TcpE
|
|
// entry is very inefficient (scanning approach) for simplicity.
|
|
// For better performance a BTREE approach in the by-tag sorted
|
|
// tag table would be better.
|
|
printf("Scanning for 'TcpE' tag...\n");
|
|
for(iPoolTagEntry = 0; iPoolTagEntry < pPoolMap->cTag; iPoolTagEntry++) {
|
|
if(pPoolMap->pTag[iPoolTagEntry].dwTag == 0x45706354) { // 0x45706354 == EpcT (TcpE in reverse)
|
|
pPoolTag = &pPoolMap->pTag[iPoolTagEntry];
|
|
for(i = 0; i < pPoolTag->cEntry; i++) {
|
|
iPoolEntry = pPoolMap->piTag2Map[pPoolTag->iTag2Map + i];
|
|
pPoolEntry = &pPoolMap->pMap[iPoolEntry];
|
|
printf("Pool Entry TcpE va = %llx size = %4x\n", pPoolEntry->va, pPoolEntry->cb);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
printf("SUCCESS: VMMDLL_Map_GetPool\n");
|
|
}
|
|
VMMDLL_MemFree(pPoolMap); pPoolMap = NULL;
|
|
|
|
|
|
// Retrieve virtual machine information and read VM memory.
|
|
// NB! MemProcFS must have been initialized with either of below options:
|
|
// -forensic [1-4] -vm -vm-basic -vm-nested
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Retrieve Virtual Machine Map \n");
|
|
ShowKeyPress();
|
|
DWORD iVirtualMachineEntry = 0;
|
|
PVMMDLL_MAP_VM pVirtualMachineMap = NULL;
|
|
PVMMDLL_MAP_VMENTRY pVirtualMachineEntry;
|
|
printf("CALL: VMMDLL_Map_GetVMU\n");
|
|
result = VMMDLL_Map_GetVMU(hVMM, &pVirtualMachineMap);
|
|
if(result) {
|
|
// print all VM names:
|
|
for(iVirtualMachineEntry = 0; iVirtualMachineEntry < pVirtualMachineMap->cMap; iVirtualMachineEntry++) {
|
|
pVirtualMachineEntry = pVirtualMachineMap->pMap + iVirtualMachineEntry;
|
|
printf("VM: %02i %02x %6i %s\n",
|
|
iVirtualMachineEntry,
|
|
pVirtualMachineEntry->dwPartitionID,
|
|
pVirtualMachineEntry->dwVersionBuild,
|
|
pVirtualMachineEntry->uszName
|
|
);
|
|
}
|
|
VMMDLL_MemFree(pVirtualMachineMap); pVirtualMachineMap = NULL;
|
|
} else {
|
|
printf("FAIL: VMMDLL_Map_GetVMU.\n");
|
|
}
|
|
|
|
|
|
// Read virtual memory from multiple locations in one efficient sweep
|
|
// using the VMMDLL_Scatter_* API functions.
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Read Scatter from 3+1 addresses in one efficient go. \n");
|
|
ShowKeyPress();
|
|
VMMDLL_SCATTER_HANDLE hS = NULL;
|
|
QWORD vaNt, vaHal, vaCi, vaBeep;
|
|
BYTE pbNt[0x400];
|
|
DWORD cbNt = 0, cbCi = 0;
|
|
vaNt = VMMDLL_ProcessGetModuleBaseU(hVMM, 4, "ntoskrnl.exe");
|
|
vaHal = VMMDLL_ProcessGetModuleBaseU(hVMM, 4, "hal.dll");
|
|
vaCi = VMMDLL_ProcessGetModuleBaseU(hVMM, 4, "CI.DLL");
|
|
vaBeep = VMMDLL_ProcessGetModuleBaseU(hVMM, 4, "beep.sys");
|
|
// EX.1: CREATE SCATTER HANDLE
|
|
printf("CALL: VMMDLL_Scatter_Initialize\n");
|
|
hS = VMMDLL_Scatter_Initialize(hVMM, 4, VMMDLL_FLAG_NOCACHE | VMMDLL_FLAG_NOPAGING_IO);
|
|
if(hS) {
|
|
printf("SUCCESS: VMMDLL_Scatter_Initialize\n");
|
|
} else {
|
|
printf("FAIL: VMMDLL_Scatter_Initialize\n");
|
|
return 1;
|
|
}
|
|
// EX.2: PREPARE / REGISTER MEMORY RANGES TO READ
|
|
printf("CALL: VMMDLL_Scatter_Prepare\n");
|
|
result = VMMDLL_Scatter_PrepareEx(hS, vaNt, 0x400, pbNt, &cbNt);
|
|
printf("%s: VMMDLL_Scatter_PrepareEx\n", (result ? "SUCCESS" : "FAIL"));
|
|
result = VMMDLL_Scatter_Prepare(hS, vaHal, 0x400);
|
|
printf("%s: VMMDLL_Scatter_Prepare\n", (result ? "SUCCESS" : "FAIL"));
|
|
result = VMMDLL_Scatter_Prepare(hS, vaCi, 0x2000);
|
|
printf("%s: VMMDLL_Scatter_Prepare\n", (result ? "SUCCESS" : "FAIL"));
|
|
result = VMMDLL_Scatter_Prepare(hS, vaBeep + 0xff0, 0x3000);
|
|
printf("%s: VMMDLL_Scatter_Prepare\n", (result ? "SUCCESS" : "FAIL"));
|
|
// EX.3: READ MEMORY FROM BACKEND IN AN EFFICIENT SWEEP
|
|
printf("CALL: VMMDLL_Scatter_ExecuteRead\n");
|
|
result = VMMDLL_Scatter_ExecuteRead(hS);
|
|
if(result) {
|
|
printf("SUCCESS: VMMDLL_Scatter_ExecuteRead\n");
|
|
} else {
|
|
printf("FAIL: VMMDLL_Scatter_ExecuteRead\n");
|
|
return 1;
|
|
}
|
|
// EX.4: Nt which was provided as a buffer to VMMDLL_Scatter_PrepareEx call
|
|
// should now be populated!
|
|
if(cbNt) {
|
|
printf("NTOSKRNL.EXE HEADER READ VIA VMMDLL_Scatter_PrepareEx / VMMDLL_Scatter_ExecuteRead:\n");
|
|
PrintHexAscii(pbNt, cbNt);
|
|
}
|
|
// EX.5: try read memory from other ranges as well.
|
|
printf("CALL: VMMDLL_Scatter_Read\n");
|
|
result = VMMDLL_Scatter_Read(hS, vaCi, 0x400, pbPage1, &cbCi);
|
|
if(result) {
|
|
printf("SUCCESS: VMMDLL_Scatter_Read\n");
|
|
PrintHexAscii(pbPage1, cbCi);
|
|
} else {
|
|
printf("FAIL: VMMDLL_Scatter_Read\n");
|
|
}
|
|
// EX.5: Close and clean-up
|
|
printf("CALL: VMMDLL_Scatter_CloseHandle\n");
|
|
VMMDLL_Scatter_CloseHandle(hS);
|
|
hS = NULL;
|
|
|
|
|
|
// Log a message using the MemProcFS logging system. This is most
|
|
// used by C/C++ plugins which should use the module id (MID) which
|
|
// is supplied in the PVMMDLL_PLUGIN_CONTEXT supplied to the functions.
|
|
// ---
|
|
// It's also possible for the main application to make use of logging
|
|
// by supplying the pseudo module id VMMDLL_MID_MAIN
|
|
// ---
|
|
// NB! MemProcFS must be initialized with -printf flag or -loglevel 3
|
|
// for logging to display on-screen. it's also possible to enable
|
|
// printf logging by setting option
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Log a message using the MemProcFS logging system. \n");
|
|
ShowKeyPress();
|
|
printf("CALL: VMMDLL_ConfigSet - printf enable\n");
|
|
VMMDLL_ConfigSet(hVMM, VMMDLL_OPT_CORE_PRINTF_ENABLE, 1);
|
|
printf("SUCCESS: VMMDLL_ConfigSet - printf enable\n");
|
|
printf("CALL: VMMDLL_Log\n");
|
|
VMMDLL_Log(
|
|
hVMM,
|
|
VMMDLL_MID_MAIN,
|
|
VMMDLL_LOGLEVEL_WARNING,
|
|
"%i fake warning message from %s!", 1, "vmmdll_example");
|
|
printf("SUCCESS: VMMDLL_Log\n");
|
|
|
|
|
|
// Read the file /misc/procinfo/dtb.txt containing the DTBs of processes
|
|
// in the target system. This virtual file takes a short while to render
|
|
// after first access.
|
|
// To make use of the virtual file system it's necessary to enable the
|
|
// MemProcFS plugins first. This API call is only required once.
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Access /misc/procinfo/dtb.txt \n");
|
|
ShowKeyPress();
|
|
VMMDLL_InitializePlugins(hVMM);
|
|
printf("CALL: VMMDLL_VfsRead\n");
|
|
ZeroMemory(pbPage1, sizeof(pbPage1));
|
|
BOOL fResultDTB = FALSE;
|
|
while(TRUE) {
|
|
nt = VMMDLL_VfsReadU(hVMM, "\\misc\\procinfo\\progress_percent.txt", pbPage1, 3, &cbRead, 0);
|
|
if(nt == VMMDLL_STATUS_SUCCESS) {
|
|
printf("SUCCESS: VMMDLL_VfsRead: %s\n", (LPSTR)pbPage1);
|
|
if(!strcmp((LPSTR)pbPage1, "100")) {
|
|
// success - progress is at 100% - read the file.
|
|
PBYTE pb1M = LocalAlloc(LMEM_ZEROINIT, 0x00100000);
|
|
if(pb1M) {
|
|
nt = VMMDLL_VfsReadU(hVMM, "\\misc\\procinfo\\dtb.txt", pb1M, 0x00100000, &cbRead, 0);
|
|
if(nt == VMMDLL_STATUS_SUCCESS) {
|
|
printf("SUCCESS: VMMDLL_VfsRead:\n%s\n", (LPSTR)pb1M);
|
|
} else {
|
|
printf("FAIL: VMMDLL_VfsRead\n");
|
|
return 1;
|
|
}
|
|
LocalFree(pb1M); pb1M = NULL;
|
|
}
|
|
break;
|
|
}
|
|
Sleep(100);
|
|
} else {
|
|
printf("FAIL: VMMDLL_VfsRead\n");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
// Use a Memory Callback function to alter the MemProcFS view of underlying
|
|
// physical memory. This can be useful to implement alternative views of
|
|
// memory and/or for debugging and logging purposes.
|
|
// It's possible to register a callback function which will be called every
|
|
// time a physical memory read or write is performed.
|
|
// It also works for any process internal virtual memory read or write.
|
|
// For this example to work we'll read uncached memory since a cache hit
|
|
// would prevent the need for a 2nd physical memory read.
|
|
{
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Demonstrate memory callback functionality: \n");
|
|
printf(" (1) Read existing data from physical memory at 0x1000 \n");
|
|
printf(" (2) Register a callback function: \n");
|
|
printf(" (3) Read existing data from physical memory at 0x1000 \n");
|
|
printf(" (4) Unregister the callback function: \n");
|
|
ShowKeyPress();
|
|
printf("CALL: VMMDLL_MemRead - BEFORE CALLBACK\n");
|
|
result = VMMDLL_MemReadEx(hVMM, -1, 0x1000, pbPage1, 0x1000, NULL, VMMDLL_FLAG_NOCACHE);
|
|
if(result) {
|
|
printf("SUCCESS: VMMDLL_MemRead - BEFORE CALLBACK\n");
|
|
PrintHexAscii(pbPage1, 0x80);
|
|
} else {
|
|
printf("FAIL: VMMDLL_MemRead - BEFORE CALLBACK\n");
|
|
return 1;
|
|
}
|
|
printf("CALL: VMMDLL_MemCallback (Register)\n");
|
|
VMMDLL_MemCallback(hVMM, VMMDLL_MEM_CALLBACK_READ_PHYSICAL_POST, NULL, CallbackMemCallback_PhysicalReadPost);
|
|
printf("CALL: VMMDLL_MemRead - AFTER CALLBACK\n");
|
|
result = VMMDLL_MemReadEx(hVMM, -1, 0x1000, pbPage1, 0x1000, NULL, VMMDLL_FLAG_NOCACHE);
|
|
if(result) {
|
|
printf("SUCCESS: VMMDLL_MemRead - AFTER CALLBACK\n");
|
|
PrintHexAscii(pbPage1, 0x80);
|
|
} else {
|
|
printf("FAIL: VMMDLL_MemRead - AFTER CALLBACK\n");
|
|
return 1;
|
|
}
|
|
printf("CALL: VMMDLL_MemCallback (Unregister)\n");
|
|
VMMDLL_MemCallback(hVMM, VMMDLL_MEM_CALLBACK_READ_PHYSICAL_POST, NULL, NULL);
|
|
}
|
|
|
|
|
|
|
|
|
|
// PDB/Symbol functionality: Get the module name of a loaded PDB file.
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# PDB: Get the PDB file path of kernel32.dll \n");
|
|
ShowKeyPress();
|
|
printf("CALL: VMMDLL_Map_GetModuleFromNameU\n");
|
|
PVMMDLL_MAP_MODULEENTRY pPdbModuleEntryNtdll;
|
|
result = VMMDLL_Map_GetModuleFromNameU(hVMM, dwPID, "ntdll.dll", &pPdbModuleEntryNtdll, 0);
|
|
if(!result) {
|
|
printf("FAIL: VMMDLL_Map_GetModuleFromNameU\n");
|
|
return 1;
|
|
}
|
|
printf("CALL: VMMDLL_PdbLoad\n");
|
|
CHAR szPdbModuleName_NtDll[MAX_PATH] = { 0 };
|
|
result = VMMDLL_PdbLoad(hVMM, dwPID, pPdbModuleEntryNtdll->vaBase, szPdbModuleName_NtDll);
|
|
if(!result) {
|
|
printf("FAIL: VMMDLL_PdbLoad\n");
|
|
return 1;
|
|
}
|
|
printf("SUCCESS: VMMDLL_PdbLoad [%s]\n", szPdbModuleName_NtDll);
|
|
|
|
|
|
// PDB/Symbol functionality: Get the address of the symbol/function 'ntdll!LdrLoadDll'
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# PDB: Get symbol address of ntdll.dll!LdrLoadDll \n");
|
|
ShowKeyPress();
|
|
printf("CALL: VMMDLL_PdbSymbolAddress\n");
|
|
QWORD vaPdbSymbolAddress_LdrLoadDll = 0;
|
|
result = VMMDLL_PdbSymbolAddress(hVMM, szPdbModuleName_NtDll, "LdrLoadDll", &vaPdbSymbolAddress_LdrLoadDll);
|
|
if(!result) {
|
|
printf("FAIL: VMMDLL_PdbSymbolAddress\n");
|
|
return 1;
|
|
}
|
|
printf("SUCCESS: VMMDLL_PdbSymbolAddress [%llx]\n", vaPdbSymbolAddress_LdrLoadDll);
|
|
|
|
|
|
// PDB/Symbol functionality: Get the symbol (exactly/near) of the address of the function 'LdrLoadDll'
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# PDB: Get symbol name exactly/near(+0) address \n");
|
|
ShowKeyPress();
|
|
printf("CALL: VMMDLL_PdbSymbolName\n");
|
|
DWORD dwPdbSymbolDisplacement1 = 0;
|
|
result = VMMDLL_PdbSymbolName(hVMM, szPdbModuleName_NtDll, vaPdbSymbolAddress_LdrLoadDll, usz, &dwPdbSymbolDisplacement1);
|
|
if(!result) {
|
|
printf("FAIL: VMMDLL_PdbSymbolName\n");
|
|
return 1;
|
|
}
|
|
printf("SUCCESS: VMMDLL_PdbSymbolName name:[%s] displacement:[%x]\n", usz, dwPdbSymbolDisplacement1);
|
|
|
|
|
|
// PDB/Symbol functionality: Get the symbol (exactly/near) of the address of the function 'LdrLoadDll'
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# PDB: Get symbol name near(+10) address \n");
|
|
ShowKeyPress();
|
|
printf("CALL: VMMDLL_PdbSymbolName\n");
|
|
DWORD dwPdbSymbolDisplacement2 = 0;
|
|
result = VMMDLL_PdbSymbolName(hVMM, szPdbModuleName_NtDll, vaPdbSymbolAddress_LdrLoadDll + 0x10, usz, &dwPdbSymbolDisplacement2);
|
|
if(!result) {
|
|
printf("FAIL: VMMDLL_PdbSymbolName\n");
|
|
return 1;
|
|
}
|
|
printf("SUCCESS: VMMDLL_PdbSymbolName name:[%s] displacement:[%x]\n", usz, dwPdbSymbolDisplacement2);
|
|
|
|
|
|
// PDB/Symbol functionality: Get type size of the kernel structure '_EPROCESS'
|
|
// The kernel is a special 'module' which is loaded by the name of 'nt', i.e.
|
|
// no previous call to 'VMMDLL_PdbLoad()' is required.
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# PDB: Get type size of _EPROCESS \n");
|
|
ShowKeyPress();
|
|
printf("CALL: VMMDLL_PdbTypeSize\n");
|
|
DWORD dwPdbTypeSize = 0;
|
|
result = VMMDLL_PdbTypeSize(hVMM, "nt", "_EPROCESS", &dwPdbTypeSize);
|
|
if(!result) {
|
|
printf("FAIL: VMMDLL_PdbTypeSize\n");
|
|
return 1;
|
|
}
|
|
printf("SUCCESS: VMMDLL_PdbTypeSize name:[_EPROCESS] type_size:[%x]\n", dwPdbTypeSize);
|
|
|
|
|
|
// PDB/Symbol functionality: Get type offset of the _EPROCESS.Token child member.
|
|
// The kernel is a special 'module' which is loaded by the name of 'nt', i.e.
|
|
// no previous call to 'VMMDLL_PdbLoad()' is required.
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# PDB: Get type child offset of _EPROCESS.Token \n");
|
|
ShowKeyPress();
|
|
printf("CALL: VMMDLL_PdbTypeChildOffset\n");
|
|
DWORD dwPdbTypeChildOffset = 0;
|
|
result = VMMDLL_PdbTypeChildOffset(hVMM, "nt", "_EPROCESS", "Token", &dwPdbTypeChildOffset);
|
|
if(!result) {
|
|
printf("FAIL: VMMDLL_PdbTypeChildOffset\n");
|
|
return 1;
|
|
}
|
|
printf("SUCCESS: VMMDLL_PdbTypeChildOffset name:[_EPROCESS.Token] child_offset:[%x]\n", dwPdbTypeChildOffset);
|
|
|
|
|
|
|
|
|
|
// Close the VMM_HANDLE and clean up native resources.
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# Close the VMM_HANDLE (hVMM) to clean up native resources. \n");
|
|
ShowKeyPress();
|
|
VMMDLL_MemFree(pModuleEntryKernel32); pModuleEntryKernel32 = NULL;
|
|
VMMDLL_MemFree(pModuleEntryExplorer); pModuleEntryExplorer = NULL;
|
|
printf("CALL: VMMDLL_Close #1\n");
|
|
VMMDLL_Close(hVMM);
|
|
|
|
|
|
// Finish everything and exit!
|
|
printf("------------------------------------------------------------\n");
|
|
printf("# FINISHED EXAMPLES! \n");
|
|
ShowKeyPress();
|
|
printf("FINISHED TEST CASES - EXITING!\n");
|
|
return 0;
|
|
}
|