-
-
Notifications
You must be signed in to change notification settings - Fork 415
API_C
All functionality in the Memory Process File System is exported in a C/C++ API for use by developers. The header file is named: vmmdll.h
which use vmm.dll
/ vmm.lib
(Windows) or vmm.so
(Linux).
It may also be interesting to look into the more basic API related to read/write physical memory exported by the LeechCore library.
The complete documentation is found in vmmdll.h
. This wiki entry contains an overview of the C/C++ API.
Linux is supported on x64 and ARM64 in addition to Windows x64. Wide-Char *W
versions of API functions are only supported on Windows while UTF-8 *U
versions of API functions are supported on both Linux and Windows.
An example file containing a lot of use cases are found in the file vmmdll_example.c
in the vmmdll_example project in the visual studio solution.
After vmm.dll
is loaded it has to be initialized.
Depending on whether it should be initialized from file, fpga or something else different VMMDLL_Initialize should be called with a different list of string parameters in the first argument. The arguments are the same as given as options when starting The Memory Process File System except for argv[0] which is recommended to set to blank.
BOOL VMMDLL_Initialize(_In_ DWORD argc, _In_ LPSTR argv[]);
BOOL VMMDLL_InitializeEx(_In_ DWORD argc, _In_ LPSTR argv[], _Out_opt_ PPLC_CONFIG_ERRORINFO ppLcErrorInfo);
BOOL VMMDLL_InitializePlugins();
BOOL VMMDLL_Close();
VOID VMMDLL_MemFree(_Frees_ptr_opt_ PVOID pvMem);
BOOL VMMDLL_ConfigGet(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue);
BOOL VMMDLL_ConfigSet(_In_ ULONG64 fOption, _In_ ULONG64 qwValue);
The MemProcFS.exe file is just a wrapper around the API below:
BOOL VMMDLL_VfsListU(
_In_ LPSTR uszPath,
_Inout_ PVMMDLL_VFS_FILELIST2 pFileList
);
BOOL VMMDLL_VfsListW(
_In_ LPWSTR wszPath,
_Inout_ PVMMDLL_VFS_FILELIST2 pFileList
);
NTSTATUS VMMDLL_VfsReadU(
_In_ LPSTR uszFileName,
_Out_writes_to_(cb, *pcbRead) PBYTE pb,
_In_ DWORD cb,
_Out_ PDWORD pcbRead,
_In_ ULONG64 cbOffset
);
NTSTATUS VMMDLL_VfsReadW(
_In_ LPWSTR wszFileName,
_Out_writes_to_(cb, *pcbRead) PBYTE pb,
_In_ DWORD cb,
_Out_ PDWORD pcbRead,
_In_ ULONG64 cbOffset
);
NTSTATUS VMMDLL_VfsWriteU(
_In_ LPSTR uszFileName,
_In_reads_(cb) PBYTE pb,
_In_ DWORD cb,
_Out_ PDWORD pcbWrite,
_In_ ULONG64 cbOffset
);
NTSTATUS VMMDLL_VfsWriteW(
_In_ LPWSTR wszFileName,
_In_reads_(cb) PBYTE pb,
_In_ DWORD cb,
_Out_ PDWORD pcbWrite,
_In_ ULONG64 cbOffset
);
NTSTATUS VMMDLL_UtilVfsReadFile_FromPBYTE(
_In_ PBYTE pbFile,
_In_ ULONG64 cbFile,
_Out_writes_to_(cb, *pcbRead) PBYTE pb,
_In_ DWORD cb,
_Out_ PDWORD pcbRead,
_In_ ULONG64 cbOffset
);
NTSTATUS VMMDLL_UtilVfsReadFile_FromQWORD(
_In_ ULONG64 qwValue,
_Out_writes_to_(cb, *pcbRead) PBYTE pb,
_In_ DWORD cb,
_Out_ PDWORD pcbRead,
_In_ ULONG64 cbOffset,
_In_ BOOL fPrefix
);
NTSTATUS VMMDLL_UtilVfsReadFile_FromDWORD(
_In_ DWORD dwValue,
_Out_writes_to_(cb, *pcbRead) PBYTE pb,
_In_ DWORD cb,
_Out_ PDWORD pcbRead,
_In_ ULONG64 cbOffset,
_In_ BOOL fPrefix
);
NTSTATUS VMMDLL_UtilVfsReadFile_FromBOOL(
_In_ BOOL fValue,
_Out_writes_to_(cb, *pcbRead) PBYTE pb,
_In_ DWORD cb,
_Out_ PDWORD pcbRead,
_In_ ULONG64 cbOffset
);
NTSTATUS VMMDLL_UtilVfsWriteFile_BOOL(
_Inout_ PBOOL pfTarget,
_In_reads_(cb) PBYTE pb,
_In_ DWORD cb,
_Out_ PDWORD pcbWrite,
_In_ ULONG64 cbOffset
);
NTSTATUS VMMDLL_UtilVfsWriteFile_DWORD(
_Inout_ PDWORD pdwTarget,
_In_reads_(cb) PBYTE pb,
_In_ DWORD cb,
_Out_ PDWORD pcbWrite,
_In_ ULONG64 cbOffset,
_In_ DWORD dwMinAllow
);
Read and write both physical and virtual memory via the functions listed below. In most instances it's possible to specify (DWORD)-1
instead of the process pid to read physical memory instead of process virtual memory.
DWORD VMMDLL_MemReadScatter(
_In_ DWORD dwPID,
_Inout_ PPMEM_SCATTER ppMEMs,
_In_ DWORD cpMEMs,
_In_ DWORD flags
);
BOOL VMMDLL_MemReadPage(
_In_ DWORD dwPID,
_In_ ULONG64 qwA,
_Inout_bytecount_(4096) PBYTE pbPage
);
BOOL VMMDLL_MemRead(
_In_ DWORD dwPID,
_In_ ULONG64 qwA,
_Out_writes_(cb) PBYTE pb,
_In_ DWORD cb
);
BOOL VMMDLL_MemReadEx(
_In_ DWORD dwPID,
_In_ ULONG64 qwA,
_Out_writes_(cb) PBYTE pb,
_In_ DWORD cb,
_Out_opt_ PDWORD pcbReadOpt,
_In_ ULONG64 flags
);
BOOL VMMDLL_MemPrefetchPages(
_In_ DWORD dwPID,
_In_reads_(cPrefetchAddresses) PULONG64 pPrefetchAddresses,
_In_ DWORD cPrefetchAddresses
);
BOOL VMMDLL_MemWrite(
_In_ DWORD dwPID,
_In_ ULONG64 qwA,
_In_reads_(cb) PBYTE pb,
_In_ DWORD cb
);
BOOL VMMDLL_MemVirt2Phys(
_In_ DWORD dwPID,
_In_ ULONG64 qwVA,
_Out_ PULONG64 pqwPA
);
Read physical and virtual memory in an efficient way using the Scatter API using the functions listed below. In most instances it's possible to specify (DWORD)-1
instead of the process pid to read physical memory instead of process virtual memory.
Flow is as follows:
- Call VMMDLL_Scatter_Initialize to initialize handle.
- Populate memory ranges with multiple calls to VMMDLL_Scatter_Prepare and/or VMMDLL_Scatter_PrepareEx functions. The memory buffer given to VMMDLL_Scatter_PrepareEx will be populated with contents in step (3).
- Retrieve the memory by calling VMMDLL_Scatter_ExecuteRead function.
- If VMMDLL_Scatter_Prepare was used (i.e. not VMMDLL_Scatter_PrepareEx) then retrieve the memory read in (3).
- Clear the handle for reuse by calling VMMDLL_Scatter_Clear alternatively close the handle to free resources with VMMDLL_Scatter_CloseHandle.
VMMDLL_SCATTER_HANDLE VMMDLL_Scatter_Initialize(
_In_ DWORD dwPID,
_In_ DWORD flags
);
BOOL VMMDLL_Scatter_Prepare(
_In_ VMMDLL_SCATTER_HANDLE hS,
_In_ QWORD va,
_In_ DWORD cb
);
BOOL VMMDLL_Scatter_PrepareEx(
_In_ VMMDLL_SCATTER_HANDLE hS,
_In_ QWORD va,
_In_ DWORD cb,
_Out_writes_opt_(cb) PBYTE pb,
_Out_opt_ PDWORD pcbRead
);
BOOL VMMDLL_Scatter_ExecuteRead(
_In_ VMMDLL_SCATTER_HANDLE hS
);
BOOL VMMDLL_Scatter_Read(
_In_ VMMDLL_SCATTER_HANDLE hS,
_In_ QWORD va,
_In_ DWORD cb,
_Out_writes_opt_(cb) PBYTE pb,
_Out_opt_ PDWORD pcbRead
);
BOOL VMMDLL_Scatter_Clear(
_In_ VMMDLL_SCATTER_HANDLE hS,
_In_ DWORD dwPID,
_In_ DWORD flags
);
VOID VMMDLL_Scatter_CloseHandle(
_In_opt_ _Post_ptr_invalid_ VMMDLL_SCATTER_HANDLE hS
);
Functionality related to processes running on the target system are exposed in via the functions below:
BOOL VMMDLL_PidGetFromName(
_In_ LPSTR szProcName,
_Out_ PDWORD pdwPID
);
BOOL VMMDLL_PidList(
_Out_writes_opt_(*pcPIDs) PDWORD pPIDs,
_Inout_ PULONG64 pcPIDs
);
BOOL VMMDLL_PidGetFromName(
_In_ LPSTR szProcName,
_Out_ PDWORD pdwPID
);
BOOL VMMDLL_PidList(
_Out_writes_opt_(*pcPIDs) PDWORD pPIDs,
_Inout_ PULONG64 pcPIDs
);
BOOL VMMDLL_ProcessGetInformation(
_In_ DWORD dwPID,
_Inout_opt_ PVMMDLL_PROCESS_INFORMATION pProcessInformation,
_In_ PSIZE_T pcbProcessInformation
);
LPSTR VMMDLL_ProcessGetInformationString(
_In_ DWORD dwPID,
_In_ DWORD fOptionString
);
ULONG64 VMMDLL_ProcessGetProcAddressU(
_In_ DWORD dwPID,
_In_ LPSTR uszModuleName,
_In_ LPSTR szFunctionName
);
ULONG64 VMMDLL_ProcessGetProcAddressW(
_In_ DWORD dwPID,
_In_ LPWSTR wszModuleName,
_In_ LPSTR szFunctionName
);
ULONG64 VMMDLL_ProcessGetModuleBaseU(
_In_ DWORD dwPID,
_In_ LPSTR uszModuleName
);
ULONG64 VMMDLL_ProcessGetModuleBaseW(
_In_ DWORD dwPID,
_In_ LPWSTR wszModuleName
);
BOOL VMMDLL_Map_GetPteU(
_In_ DWORD dwPID,
_Out_writes_bytes_opt_(*pcbPteMap) PVMMDLL_MAP_PTE pPteMap,
_Inout_ PDWORD pcbPteMap,
_In_ BOOL fIdentifyModules
);
BOOL VMMDLL_Map_GetPteW(
_In_ DWORD dwPID,
_Out_writes_bytes_opt_(*pcbPteMap) PVMMDLL_MAP_PTE pPteMap,
_Inout_ PDWORD pcbPteMap,
_In_ BOOL fIdentifyModules
);
BOOL VMMDLL_Map_GetVadU(
_In_ DWORD dwPID,
_Out_writes_bytes_opt_(*pcbVadMap) PVMMDLL_MAP_VAD pVadMap,
_Inout_ PDWORD pcbVadMap,
_In_ BOOL fIdentifyModules
);
BOOL VMMDLL_Map_GetVadW(
_In_ DWORD dwPID,
_Out_writes_bytes_opt_(*pcbVadMap) PVMMDLL_MAP_VAD pVadMap,
_Inout_ PDWORD pcbVadMap,
_In_ BOOL fIdentifyModules
);
BOOL VMMDLL_Map_GetVadEx(
_In_ DWORD dwPID,
_Out_writes_bytes_opt_(*pcbVadExMap) PVMMDLL_MAP_VADEX pVadExMap,
_Inout_ PDWORD pcbVadExMap,
_In_ DWORD oPage,
_In_ DWORD cPage
);
BOOL VMMDLL_Map_GetModuleU(
_In_ DWORD dwPID,
_Out_writes_bytes_opt_(*pcbModuleMap) PVMMDLL_MAP_MODULE pModuleMap,
_Inout_ PDWORD pcbModuleMap
);
BOOL VMMDLL_Map_GetModuleW(
_In_ DWORD dwPID,
_Out_writes_bytes_opt_(*pcbModuleMap) PVMMDLL_MAP_MODULE pModuleMap,
_Inout_ PDWORD pcbModuleMap
);
BOOL VMMDLL_Map_GetModuleFromNameU(
_In_ DWORD dwPID,
_In_ LPSTR uszModuleName,
_Out_writes_bytes_opt_(*pcbModuleMapEntry) PVMMDLL_MAP_MODULEENTRY pModuleMapEntry,
_Inout_opt_ PDWORD pcbModuleMapEntry
);
BOOL VMMDLL_Map_GetModuleFromNameW(
_In_ DWORD dwPID,
_In_ LPWSTR wszModuleName,
_Out_writes_bytes_opt_(*pcbModuleMapEntry) PVMMDLL_MAP_MODULEENTRY pModuleMapEntry,
_Inout_opt_ PDWORD pcbModuleMapEntry
);
BOOL VMMDLL_Map_GetUnloadedModuleU(
_In_ DWORD dwPID,
_Out_writes_bytes_opt_(*pcbUnloadedModuleMap) PVMMDLL_MAP_UNLOADEDMODULE pUnloadedModuleMap,
_Inout_ PDWORD pcbUnloadedModuleMap
);
BOOL VMMDLL_Map_GetUnloadedModuleW(
_In_ DWORD dwPID,
_Out_writes_bytes_opt_(*pcbUnloadedModuleMap) PVMMDLL_MAP_UNLOADEDMODULE pUnloadedModuleMap,
_Inout_ PDWORD pcbUnloadedModuleMap
);
BOOL VMMDLL_Map_GetEATU(
_In_ DWORD dwPID,
_In_ LPSTR uszModuleName,
_Out_writes_bytes_opt_(*pcbEatMap) PVMMDLL_MAP_EAT pEatMap,
_Inout_ PDWORD pcbEatMap
);
BOOL VMMDLL_Map_GetEATW(
_In_ DWORD dwPID,
_In_ LPWSTR wszModuleName,
_Out_writes_bytes_opt_(*pcbEatMap) PVMMDLL_MAP_EAT pEatMap,
_Inout_ PDWORD pcbEatMap
);
BOOL VMMDLL_Map_GetIATU(
_In_ DWORD dwPID,
_In_ LPSTR uszModuleName,
_Out_writes_bytes_opt_(*pcbIatMap) PVMMDLL_MAP_IAT pIatMap,
_Inout_ PDWORD pcbIatMap
);
BOOL VMMDLL_Map_GetIATW(
_In_ DWORD dwPID,
_In_ LPWSTR wszModuleName,
_Out_writes_bytes_opt_(*pcbIatMap) PVMMDLL_MAP_IAT pIatMap,
_Inout_ PDWORD pcbIatMap
);
BOOL VMMDLL_Map_GetHeap(
_In_ DWORD dwPID,
_Out_writes_bytes_opt_(*pcbHeapMap) PVMMDLL_MAP_HEAP pHeapMap,
_Inout_ PDWORD pcbHeapMap
);
BOOL VMMDLL_Map_GetThread(
_In_ DWORD dwPID,
_Out_writes_bytes_opt_(*pcbThreadMap) PVMMDLL_MAP_THREAD pThreadMap,
_Inout_ PDWORD pcbThreadMap
);
BOOL VMMDLL_Map_GetHandleU(
_In_ DWORD dwPID,
_Out_writes_bytes_opt_(*pcbHandleMap) PVMMDLL_MAP_HANDLE pHandleMap,
_Inout_ PDWORD pcbHandleMap
);
BOOL VMMDLL_Map_GetHandleW(
_In_ DWORD dwPID,
_Out_writes_bytes_opt_(*pcbHandleMap) PVMMDLL_MAP_HANDLE pHandleMap,
_Inout_ PDWORD pcbHandleMap
);
BOOL VMMDLL_ProcessGetDirectoriesU(
_In_ DWORD dwPID,
_In_ LPSTR uszModule,
_Out_writes_(16) PIMAGE_DATA_DIRECTORY pData,
_In_ DWORD cData,
_Out_ PDWORD pcData
);
BOOL VMMDLL_ProcessGetDirectoriesW(
_In_ DWORD dwPID,
_In_ LPWSTR wszModule,
_Out_writes_(16) PIMAGE_DATA_DIRECTORY pData,
_In_ DWORD cData,
_Out_ PDWORD pcData
);
BOOL VMMDLL_ProcessGetSectionsU(
_In_ DWORD dwPID,
_In_ LPSTR uszModule,
_Out_opt_ PIMAGE_SECTION_HEADER pData,
_In_ DWORD cData,
_Out_ PDWORD pcData
);
BOOL VMMDLL_ProcessGetSectionsW(
_In_ DWORD dwPID,
_In_ LPWSTR wszModule,
_Out_opt_ PIMAGE_SECTION_HEADER pData,
_In_ DWORD cData,
_Out_ PDWORD pcData
);
BOOL VMMDLL_WinGetThunkInfoIATU(
_In_ DWORD dwPID,
_In_ LPSTR uszModuleName,
_In_ LPSTR szImportModuleName,
_In_ LPSTR szImportFunctionName,
_Out_ PVMMDLL_WIN_THUNKINFO_IAT pThunkInfoIAT
);
BOOL VMMDLL_WinGetThunkInfoIATW(
_In_ DWORD dwPID,
_In_ LPWSTR wszModuleName,
_In_ LPSTR szImportModuleName,
_In_ LPSTR szImportFunctionName,
_Out_ PVMMDLL_WIN_THUNKINFO_IAT pThunkInfoIAT
);
The registry API supports enumerating registry hives and the reading/writing of their memory space. Reading and writing individual registry keys are not supported at the moment.
BOOL VMMDLL_WinReg_HiveList(
_Out_writes_(cHives) PVMMDLL_REGISTRY_HIVE_INFORMATION pHives,
_In_ DWORD cHives,
_Out_ PDWORD pcHives
);
BOOL VMMDLL_WinReg_HiveReadEx(
_In_ ULONG64 vaCMHive,
_In_ DWORD ra,
_Out_ PBYTE pb,
_In_ DWORD cb,
_Out_opt_ PDWORD pcbReadOpt,
_In_ ULONG64 flags
);
BOOL VMMDLL_WinReg_HiveWrite(
_In_ ULONG64 vaCMHive,
_In_ DWORD ra,
_In_ PBYTE pb,
_In_ DWORD cb
);
BOOL VMMDLL_WinReg_EnumKeyExU(
_In_ LPSTR uszFullPathKey,
_In_ DWORD dwIndex,
_Out_writes_opt_(*lpcchName) LPSTR lpName,
_Inout_ LPDWORD lpcchName,
_Out_opt_ PFILETIME lpftLastWriteTime
);
BOOL VMMDLL_WinReg_EnumKeyExW(
_In_ LPWSTR wszFullPathKey,
_In_ DWORD dwIndex,
_Out_writes_opt_(*lpcchName) LPWSTR lpName,
_Inout_ LPDWORD lpcchName,
_Out_opt_ PFILETIME lpftLastWriteTime
);
BOOL VMMDLL_WinReg_EnumValueU(
_In_ LPSTR uszFullPathKey,
_In_ DWORD dwIndex,
_Out_writes_opt_(*lpcchValueName) LPSTR lpValueName,
_Inout_ LPDWORD lpcchValueName,
_Out_opt_ LPDWORD lpType,
_Out_writes_opt_(*lpcbData) LPBYTE lpData,
_Inout_opt_ LPDWORD lpcbData
);
BOOL VMMDLL_WinReg_EnumValueW(
_In_ LPWSTR wszFullPathKey,
_In_ DWORD dwIndex,
_Out_writes_opt_(*lpcchValueName) LPWSTR lpValueName,
_Inout_ LPDWORD lpcchValueName,
_Out_opt_ LPDWORD lpType,
_Out_writes_opt_(*lpcbData) LPBYTE lpData,
_Inout_opt_ LPDWORD lpcbData
);
BOOL VMMDLL_WinReg_QueryValueExU(
_In_ LPSTR uszFullPathKeyValue,
_Out_opt_ LPDWORD lpType,
_Out_writes_opt_(*lpcbData) LPBYTE lpData,
_When_(lpData == NULL, _Out_opt_) _When_(lpData != NULL, _Inout_opt_) LPDWORD lpcbData
);
BOOL VMMDLL_WinReg_QueryValueExW(
_In_ LPWSTR wszFullPathKeyValue,
_Out_opt_ LPDWORD lpType,
_Out_writes_opt_(*lpcbData) LPBYTE lpData,
_When_(lpData == NULL, _Out_opt_) _When_(lpData != NULL, _Inout_opt_) LPDWORD lpcbData
);
Limited functionality for debugging symbols retrieved from the Microsoft symbol server.
BOOL VMMDLL_PdbLoad(
_In_ DWORD dwPID,
_In_ ULONG64 vaModuleBase,
_Out_writes_(MAX_PATH) LPSTR szModuleName
);
BOOL VMMDLL_PdbSymbolName(
_In_ LPSTR szModule,
_In_ QWORD cbSymbolAddressOrOffset,
_Out_writes_(MAX_PATH) LPSTR szSymbolName,
_Out_opt_ PDWORD pdwSymbolDisplacement
);
BOOL VMMDLL_PdbSymbolAddress(
_In_ LPSTR szModule,
_In_ LPSTR szSymbolName,
_Out_ PULONG64 pvaSymbolAddress
);
BOOL VMMDLL_PdbTypeSize(
_In_ LPSTR szModule,
_In_ LPSTR szTypeName,
_Out_ PDWORD pcbTypeSize
);
BOOL VMMDLL_PdbTypeChildOffset(
_In_ LPSTR szModule,
_In_ LPSTR szTypeName,
_In_ LPWSTR wszTypeChildName,
_Out_ PDWORD pcbTypeChildOffset
);
BOOL VMMDLL_Map_GetPfn(
_In_ DWORD pPfns[],
_In_ DWORD cPfns,
_Out_writes_bytes_opt_(*pcbPfnMap) PVMMDLL_MAP_PFN pPfnMap,
_Inout_ PDWORD pcbPfnMap
);
BOOL VMMDLL_Map_GetPool(
_Out_writes_bytes_opt_(*pcbPoolMap) PVMMDLL_MAP_POOL pPoolMap,
_Inout_ PDWORD pcbPoolMap
);
BOOL VMMDLL_Map_GetPhysMem(
_Out_writes_bytes_opt_(*pcbPhysMemMap) PVMMDLL_MAP_PHYSMEM pPhysMemMap,
_Inout_ PDWORD pcbPhysMemMap
);
BOOL VMMDLL_Map_GetNetU(
_Out_writes_bytes_opt_(*pcbNetMap) PVMMDLL_MAP_NET pNetMap,
_Inout_ PDWORD pcbNetMap
);
BOOL VMMDLL_Map_GetNetW(
_Out_writes_bytes_opt_(*pcbNetMap) PVMMDLL_MAP_NET pNetMap,
_Inout_ PDWORD pcbNetMap
);
BOOL VMMDLL_Map_GetUsersU(
_Out_writes_bytes_opt_(*pcbUserMap) PVMMDLL_MAP_USER pUserMap,
_Inout_ PDWORD pcbUserMap
);
BOOL VMMDLL_Map_GetUsersW(
_Out_writes_bytes_opt_(*pcbUserMap) PVMMDLL_MAP_USER pUserMap,
_Inout_ PDWORD pcbUserMap
);
BOOL VMMDLL_Map_GetServicesU(
_Out_writes_bytes_opt_(*pcbServiceMap) PVMMDLL_MAP_SERVICE pServiceMap,
_Inout_ PDWORD pcbServiceMap
);
BOOL VMMDLL_Map_GetServicesW(
_Out_writes_bytes_opt_(*pcbServiceMap) PVMMDLL_MAP_SERVICE pServiceMap,
_Inout_ PDWORD pcbServiceMap
);
BOOL VMMDLL_UtilFillHexAscii(
_In_reads_opt_(cb) PBYTE pb,
_In_ DWORD cb,
_In_ DWORD cbInitialOffset,
_Out_writes_opt_(*pcsz) LPSTR sz,
_Inout_ PDWORD pcsz
);
Sponsor PCILeech and MemProcFS:
PCILeech and MemProcFS is free and open source!
I put a lot of time and energy into PCILeech and MemProcFS and related research to make this happen. Some aspects of the projects relate to hardware and I put quite some money into my projects and related research. If you think PCILeech and/or MemProcFS are awesome tools and/or if you had a use for them it's now possible to contribute by becoming a sponsor!
If you like what I've created with PCIleech and MemProcFS with regards to DMA, Memory Analysis and Memory Forensics and would like to give something back to support future development please consider becoming a sponsor at: https://github.com/sponsors/ufrisk
Thank You 💖