From ba3fb699975ff836f56d24e92c513b372ddbb04e Mon Sep 17 00:00:00 2001 From: ufrisk Date: Thu, 4 Aug 2022 08:34:42 +0200 Subject: [PATCH] Version 5.0 --- README.md | 193 +-- includes/leechcore_device.h | 172 +++ includes/lib32/leechcore.lib | Bin 5360 -> 5360 bytes includes/lib64/leechcore.lib | Bin 5268 -> 5268 bytes includes/lib64/vmm.lib | Bin 25270 -> 25662 bytes includes/vmmdll.h | 532 ++++--- m_vmemd/Makefile | 32 + m_vmemd/m_vmemd.c | 130 +- m_vmemd/oscompatibility.c | 502 ++++++ m_vmemd/oscompatibility.h | 571 +++++++ m_vmemd/version.h | 8 +- memprocfs/memprocfs_dokan.c | 21 +- memprocfs/memprocfs_fuse.c | 55 +- memprocfs/version.h | 8 +- memprocfs/vfslist.c | 1 + vmm/Makefile | 12 +- vmm/charutil.c | 115 ++ vmm/charutil.h | 36 + vmm/fc.c | 729 ++++++--- vmm/fc.h | 112 +- vmm/infodb.c | 183 ++- vmm/infodb.h | 38 +- vmm/m_conf.c | 230 +-- vmm/m_fc_csv.c | 152 ++ vmm/m_fc_handle.c | 80 + vmm/m_fc_json.c | 64 +- vmm/m_fc_module.c | 276 ++-- vmm/m_fc_ntfs.c | 196 ++- vmm/m_fc_proc.c | 117 +- vmm/m_fc_registry.c | 61 +- vmm/m_fc_sys.c | 37 + vmm/m_fc_thread.c | 82 +- vmm/m_fc_timeline.c | 44 +- vmm/m_file_handles_vads.c | 38 +- vmm/m_file_modules.c | 52 +- vmm/m_findevil.c | 94 +- vmm/m_misc_bitlocker.c | 157 +- vmm/m_misc_web.c | 105 +- vmm/m_modules.h | 86 +- vmm/m_phys2virt.c | 92 +- vmm/m_proc_handle.c | 52 +- vmm/m_proc_heap.c | 69 +- vmm/m_proc_ldrmodules.c | 206 ++- vmm/m_proc_memmap.c | 102 +- vmm/m_proc_minidump.c | 106 +- vmm/m_proc_thread.c | 72 +- vmm/m_proc_token.c | 67 +- vmm/m_search.c | 116 +- vmm/m_sys.c | 86 +- vmm/m_sys_cert.c | 100 +- vmm/m_sys_driver.c | 151 +- vmm/m_sys_mem.c | 48 +- vmm/m_sys_net.c | 55 +- vmm/m_sys_obj.c | 60 +- vmm/m_sys_pool.c | 68 +- vmm/m_sys_proc.c | 89 +- vmm/m_sys_svc.c | 123 +- vmm/m_sys_syscall.c | 69 +- vmm/m_sys_task.c | 178 ++- vmm/m_sys_user.c | 58 + vmm/m_vfsfc.c | 24 +- vmm/m_vfsproc.c | 82 +- vmm/m_vfsroot.c | 189 +-- vmm/m_virt2phys.c | 82 +- vmm/m_winreg.c | 124 +- vmm/mm.h | 24 +- vmm/mm_pfn.c | 124 +- vmm/mm_pfn.h | 12 +- vmm/mm_vad.c | 297 ++-- vmm/mm_win.c | 575 +++---- vmm/mm_x64.c | 126 +- vmm/mm_x86.c | 105 +- vmm/mm_x86pae.c | 123 +- vmm/ob/ob.h | 114 +- vmm/ob/ob_cachemap.c | 14 +- vmm/ob/ob_compressed.c | 127 +- vmm/ob/ob_container.c | 4 +- vmm/ob/ob_core.c | 21 +- vmm/ob/ob_counter.c | 7 +- vmm/ob/ob_map.c | 35 +- vmm/ob/ob_memfile.c | 60 +- vmm/ob/ob_set.c | 47 +- vmm/ob/ob_strmap.c | 34 +- vmm/ob/ob_tag.h | 10 + vmm/oscompatibility.c | 18 +- vmm/oscompatibility.h | 48 +- vmm/pdb.c | 515 ++++--- vmm/pdb.h | 69 +- vmm/pe.c | 105 +- vmm/pe.h | 50 +- vmm/pluginmanager.c | 556 ++++--- vmm/pluginmanager.h | 68 +- vmm/statistics.c | 250 +-- vmm/statistics.h | 351 ++--- vmm/sysquery.c | 12 +- vmm/sysquery.h | 6 +- vmm/util.c | 72 +- vmm/util.h | 30 +- vmm/version.h | 8 +- vmm/vmm.c | 1131 +++++++------- vmm/vmm.h | 752 +++++---- vmm/vmm.vcxproj | 7 + vmm/vmm.vcxproj.filters | 21 + vmm/vmmdll.c | 2200 ++++++++++++--------------- vmm/vmmdll.def | 8 +- vmm/vmmdll.h | 532 ++++--- vmm/vmmdll_core.c | 739 +++++++++ vmm/vmmdll_scatter.c | 11 +- vmm/vmmevil.c | 383 +++-- vmm/vmmevil.h | 8 +- vmm/vmmheap.c | 310 ++-- vmm/vmmheap.h | 9 +- vmm/vmmlog.c | 202 ++- vmm/vmmlog.h | 67 +- vmm/vmmnet.c | 338 ++-- vmm/vmmnet.h | 9 +- vmm/vmmproc.c | 218 +-- vmm/vmmproc.h | 13 +- vmm/vmmwin.c | 1223 ++++++++------- vmm/vmmwin.h | 55 +- vmm/vmmwindef.h | 2 + vmm/vmmwininit.c | 731 ++++----- vmm/vmmwininit.h | 8 +- vmm/vmmwinobj.c | 427 +++--- vmm/vmmwinobj.h | 37 +- vmm/vmmwinpool.c | 310 ++-- vmm/vmmwinpool.h | 6 +- vmm/vmmwinreg.c | 445 +++--- vmm/vmmwinreg.h | 77 +- vmm/vmmwinsvc.c | 177 ++- vmm/vmmwinsvc.h | 6 +- vmm/vmmwork.c | 372 +++++ vmm/vmmwork.h | 32 + vmm_example/vmmdll_example.c | 436 +++--- vmmjava/VmmExample.java | 2 +- vmmjava/vmm/internal/VmmImpl.java | 272 ++-- vmmjava/vmm/internal/VmmNative.java | 100 +- vmmpyc/version.h | 8 +- vmmpyc/vmmpyc.c | 12 +- vmmpyc/vmmpyc.h | 57 +- vmmpyc/vmmpyc_kernel.c | 12 +- vmmpyc/vmmpyc_maps.c | 52 +- vmmpyc/vmmpyc_module.c | 32 +- vmmpyc/vmmpyc_modulemaps.c | 44 +- vmmpyc/vmmpyc_pdb.c | 18 +- vmmpyc/vmmpyc_physicalmemory.c | 12 +- vmmpyc/vmmpyc_process.c | 59 +- vmmpyc/vmmpyc_processmaps.c | 75 +- vmmpyc/vmmpyc_reghive.c | 20 +- vmmpyc/vmmpyc_regkey.c | 28 +- vmmpyc/vmmpyc_regmemory.c | 8 +- vmmpyc/vmmpyc_regvalue.c | 14 +- vmmpyc/vmmpyc_scattermemory.c | 6 +- vmmpyc/vmmpyc_vfs.c | 18 +- vmmpyc/vmmpyc_virtualmemory.c | 14 +- vmmpyc/vmmpyc_vmm.c | 79 +- vmmpyc/vmmpycplugin.c | 51 +- vmmsharp/vmm_example.cs | 82 +- vmmsharp/vmmsharp.cs | 1452 ++++++++++-------- 159 files changed, 15182 insertions(+), 10453 deletions(-) create mode 100644 includes/leechcore_device.h create mode 100644 m_vmemd/Makefile create mode 100644 m_vmemd/oscompatibility.c create mode 100644 m_vmemd/oscompatibility.h create mode 100644 vmm/m_fc_csv.c create mode 100644 vmm/m_fc_handle.c create mode 100644 vmm/m_fc_sys.c create mode 100644 vmm/m_sys_user.c create mode 100644 vmm/vmmdll_core.c create mode 100644 vmm/vmmwork.c create mode 100644 vmm/vmmwork.h diff --git a/README.md b/README.md index 783aa5b..758a3b0 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,52 @@ -The Memory Process File System: +MemProcFS: =============================== -The Memory Process File System (MemProcFS) is an easy and convenient way of viewing physical memory as files in a virtual file system. +MemProcFS is an easy and convenient way of viewing physical memory as files in a virtual file system. Easy trivial point and click memory analysis without the need for complicated commandline arguments! Access memory content and artifacts via files in a mounted virtual file system or via a feature rich application library to include in your own projects! -Analyze memory dump files, live memory via DumpIt or WinPMEM, live memory in read-write mode via linked [PCILeech](https://github.com/ufrisk/pcileech/) and [PCILeech-FPGA](https://github.com/ufrisk/pcileech-fpga/) devices! +Analyze memory dump files, live memory via DumpIt or WinPMEM, live memory in read-write mode from virtual machines or from [PCILeech](https://github.com/ufrisk/pcileech/) [FPGA](https://github.com/ufrisk/pcileech-fpga/) hardware devices! -It's even possible to connect to a remote LeechAgent memory acquisition agent over a secured connection - allowing for remote live memory incident response - even over higher latency low band-width connections! Peek into Hyper-V Virtual Machines with [LiveCloudKd](https://github.com/ufrisk/LeechCore/wiki/Device_LiveCloudKd)! +It's even possible to connect to a remote LeechAgent memory acquisition agent over a secured connection - allowing for remote live memory incident response - even over higher latency low band-width connections! Peek into Virtual Machines with [LiveCloudKd](https://github.com/ufrisk/LeechCore/wiki/Device_LiveCloudKd) or [VMWare](https://github.com/ufrisk/LeechCore/wiki/Device_VMWare)! Use your favorite tools to analyze memory - use your favorite hex editors, your python and powershell scripts, WinDbg or your favorite disassemblers and debuggers - all will work trivally with MemProcFS by just reading and writing files!

-Include MemProcFS in your [C/C++](https://github.com/ufrisk/MemProcFS/wiki/API_C), [C#](https://github.com/ufrisk/MemProcFS/wiki/API_CSharp), [Java](https://github.com/ufrisk/MemProcFS/wiki/API_Java) or [Python](https://github.com/ufrisk/MemProcFS/wiki/API_Python) programming projects! Everything in MemProcFS is exposed via an easy-to-use API for use in your own projects! The Plugin friendly architecture allows users to easily extend MemProcFS with native C .DLL plugins or Python .py plugins - providing additional analysis capabilities! -MemProcFS is available on Python pip. Just type `pip install memprocfs` and you're ready to go! Please see the [Python API documentation](https://github.com/ufrisk/MemProcFS/wiki/API_Python) and the [YouTube demo](https://youtu.be/pLFU1lxBNM0) for examples and usage! +Get Started! +============ -Please check out the [project wiki](https://github.com/ufrisk/MemProcFS/wiki) for more in-depth detailed information about the file system itself, its API and its plugin modules! +Check out the excellent quick walkthrough from [13Cubed](https://www.13cubed.com/) to get going! Also check out my older conference talks from Disobey and BlueHat. -Please check out the [LeechCore project](https://github.com/ufrisk/LeechCore) for information about supported memory acquisition methods and remote memory access via the LeechService. +

+ +For additional documentation **please check out the [project wiki](https://github.com/ufrisk/MemProcFS/wiki)** for in-depth detailed information about the file system itself, its API and its plugin modules! For additional information about memory acqusition methods check out the **[LeechCore project](https://github.com/ufrisk/LeechCore/)** or hop into the [#pcileech](https://discord.gg/sEkn3aa) Discord channel! To get going clone the sources in the repository or download the [latest binaries, modules and configuration files](https://github.com/ufrisk/MemProcFS/releases/latest) from the releases section and **check out the [guide](https://github.com/ufrisk/MemProcFS/wiki).** -Fast and easy memory analysis via mounted file system: -====================================================== -No matter if you have no prior knowledge of memory analysis or are an advanced user MemProcFS (and its API) may be useful! Click around the memory objects in the file system -

+ +Installing: +=========== +Get the latest [binaries, modules and configuration files](https://github.com/ufrisk/MemProcFS/releases/latest) from the latest release. Alternatively clone the repository and build from source. + +## Windows +Mounting the file system requires the Dokany file system library to be installed. Please download and install the latest version of Dokany version 2 at: https://github.com/dokan-dev/dokany/releases/latest + +To capture live memory (without PCILeech FPGA hardware) download [DumpIt](https://www.comae.com/) and start MemProcFS via DumpIt /LIVEKD mode. Alternatively, get WinPMEM by downloading the most recent signed [WinPMEM driver](https://github.com/Velocidex/c-aff4/tree/master/tools/pmem/resources/winpmem) and place it alongside MemProcFS - detailed instructions in the [LeechCore Wiki](https://github.com/ufrisk/LeechCore/wiki/Device_WinPMEM). + +PCILeech FPGA will require hardware as well as _FTD3XX.dll_ to be dropped alongside the MemProcFS binaries. Please check out the [LeechCore](https://github.com/ufrisk/LeechCore) project for instructions. + +## Linux +MemProcFS is dependent on packages, please do a `sudo apt-get install libusb-1.0 fuse openssl lz4` before trying out MemProcFS. If building from source please check out the guide about [MemProcFS on Linux](https://github.com/ufrisk/MemProcFS/wiki/_Linux). + + Extensive Python, Java, C# and C/C++ API: =============================== +Include MemProcFS in your [C/C++](https://github.com/ufrisk/MemProcFS/wiki/API_C), [C#](https://github.com/ufrisk/MemProcFS/wiki/API_CSharp), [Java](https://github.com/ufrisk/MemProcFS/wiki/API_Java) or [Python](https://github.com/ufrisk/MemProcFS/wiki/API_Python) programming projects! Everything in MemProcFS is exposed via an easy-to-use API for use in your own projects! The Plugin friendly architecture allows users to easily extend MemProcFS with native C .DLL plugins or Python plugins! + Everything in MemProcFS is exposed as APIs. APIs exist for both C/C++ `vmmdll.h`, C# `vmmsharp.cs`, Java and Python `memprocfs.py`. The file system itself is made available virtually via the API without the need to mount it. SIt is possible to read both virtual process memory as well as physical memory! The example below shows reading 0x20 bytes from physical address 0x1000: ``` >>> import memprocfs @@ -40,25 +56,7 @@ Everything in MemProcFS is exposed as APIs. APIs exist for both C/C++ `vmmdll.h` 0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ ``` -Modular Plugin Architecture: -============================ -Anyone is able to extend MemProcFS with custom plugins! It is as easy as dropping a python file in the correct directory or compiling a tiny C DLL. Existing functionality is already implemented as well documented C and Python plugins! -Installing: -=========== -Get the latest [binaries, modules and configuration files](https://github.com/ufrisk/MemProcFS/releases/latest) from the latest release. Alternatively clone the repository and build from source. - -## Windows -Mounting the file system requires the Dokany file system library to be installed. Please download and install the latest version of Dokany version 2 at: https://github.com/dokan-dev/dokany/releases/latest - -Python support requires Python 3.6 or later. The user may specify the path to the Python installation with the command line parameter `-pythonhome`, alternatively download [Python 3.7 - Windows x86-64 embeddable zip file](https://www.python.org/downloads/windows/) and unzip its contents into the `files/python` folder when using Python modules in the file system. To use the Python API a normal 64-bit Python 3.6 or later installation for Windows is required. - -To capture live memory (without PCILeech FPGA hardware) download [DumpIt](https://www.comae.com/) and start MemProcFS via DumpIt /LIVEKD mode. Alternatively, get WinPMEM by downloading the most recent signed [WinPMEM driver](https://github.com/Velocidex/c-aff4/tree/master/tools/pmem/resources/winpmem) and place it alongside MemProcFS - detailed instructions in the [LeechCore Wiki](https://github.com/ufrisk/LeechCore/wiki/Device_WinPMEM). - -PCILeech FPGA will require hardware as well as _FTD3XX.dll_ to be dropped alongside the MemProcFS binaries. Please check out the [LeechCore](https://github.com/ufrisk/LeechCore) project for instructions. - -## Linux -MemProcFS is dependent on packages, please do a `sudo apt-get install libusb-1.0 fuse openssl lz4` before trying out MemProcFS. If building from source please check out the guide about [MemProcFS on Linux](https://github.com/ufrisk/MemProcFS/wiki/_Linux). Examples: ========= @@ -66,23 +64,16 @@ Start MemProcFS from the command line - possibly by using one of the examples be Or register the memory dump file extension with MemProcFS.exe so that the file system is automatically mounted when double-clicking on a memory dump file! -- mount the memory dump file as /home/pi/mnt/ on Linux:
`./memprocfs -mount /home/pi/linux -device /dumps/win10x64-dump.raw` - mount the memory dump file as default M:
`memprocfs.exe -device c:\temp\win10x64-dump.raw` - mount the memory dump file as default M: with extra verbosity:
`memprocfs.exe -device c:\temp\win10x64-dump.raw -v` -- mount the memory dump file as default M: with extra extra verbosity:
`memprocfs.exe -device c:\temp\win10x64-dump.raw -v -vv` +- mount the memory dump file as default M: and start forensics mode:
`memprocfs.exe -device c:\temp\win10x64-dump.raw -forensic 1` +- mount the memory dump file as /home/pi/mnt/ on Linux:
`./memprocfs -mount /home/pi/linux -device /dumps/win10x64-dump.raw` - mount the memory dump file as S:
`memprocfs.exe -mount s -device c:\temp\win10x64-dump.raw` - mount live target memory, in verbose read-only mode, with DumpIt in /LIVEKD mode:
`DumpIt.exe /LIVEKD /A memprocfs.exe /C "-v"` - mount live target memory, in read-only mode, with WinPMEM driver:
`memprocfs.exe -device pmem` - mount live target memory, in read/write mode, with PCILeech FPGA memory acquisition device:
`memprocfs.exe -device fpga -memmap auto` - mount a memory dump with a corresponding page files:
`memprocfs.exe -device unknown-x64-dump.raw -pagefile0 pagefile.sys -pagefile1 swapfile.sys` -Documentation: -============== -For additional documentation please check out the [project wiki](https://github.com/ufrisk/MemProcFS/wiki) for in-depth detailed information about the file system itself, its API and its plugin modules! For additional information about memory acqusition methods check out the [LeechCore project](https://github.com/ufrisk/LeechCore/) - -Also check out my Microsoft BlueHatIL 2019 talk _Practical Uses for Hardware-assisted Memory Visualization_ and my Disobey 2020 talk _Live Memory Attacks and Forensics_ about MemProcFS. - -

Building: @@ -91,14 +82,20 @@ Building: Detailed build instructions may be found in the [Wiki](https://github.com/ufrisk/MemProcFS/wiki) in the [Building](https://github.com/ufrisk/MemProcFS/wiki/Dev_Building) section. + + License: ======== The project source code is released under: GNU Affero General Public License v3.0. Some bundled dependencies and plugins are released under GPLv3. Some bundled Microsoft redistributable binaries are released under separate licenses. Alternative closed-source licensing may be possible upon request. + + Contributing: ============= PCILeech, MemProcFS and LeechCore are open source but not open contribution. PCILeech, MemProcFS and LeechCore offers a highly flexible plugin architecture that will allow for contributions in the form of plugins. If you wish to make a contribution, other than a plugin, to the core projects please contact me before starting to develop. + + Links: ====== * Twitter: [![Twitter](https://img.shields.io/twitter/follow/UlfFrisk?label=UlfFrisk&style=social)](https://twitter.com/intent/follow?screen_name=UlfFrisk) @@ -110,11 +107,15 @@ Links: * YouTube: https://www.youtube.com/channel/UC2aAi-gjqvKiC7s7Opzv9rg * Blog: http://blog.frizk.net + + Links - Related Projects: ========================= * MemProcFSHunter: https://github.com/memprocfshunt/MemProcFSHunter * MemProcFS-Analyzer: https://github.com/evild3ad/MemProcFS-Analyzer + + Support PCILeech/MemProcFS development: ======================================= PCILeech and MemProcFS is free and open source! @@ -125,7 +126,7 @@ If you like what I've created with PCIleech and MemProcFS with regards to DMA, M To all my sponsors, Thank You 💖 -All sponsorships are welcome, no matter how large or small. I especially wish to thank my **bronze sponsors**: [grandprixgp](https://github.com/grandprixgp). + Changelog: =================== @@ -134,108 +135,9 @@ Changelog: v1.0 * Initial Release. -v1.1-v2.10 +v1.1-v3.10 * Various updates. Please see individual relases for more information. -[v3.0](https://github.com/ufrisk/MemProcFS/releases/tag/v3.0) -* Major release with new features, optimizations and refactorings. -* New virtual memory core for increased speed and memory recovery: - * VAD (virtual address descriptor) support. - * Win10 memory decompression bug-fixes. - * Pagefile support. -* Handles. -* Threads. -* API: new features and updates (module names from ansi to wide string). - -[v3.1](https://github.com/ufrisk/MemProcFS/releases/tag/v3.1) -* Bug fixes and refactorings. -* Code signing of binaries. -* New Features: - * Users. - * Volatile registry keys. - * File recovery via Handles and Vads. - -[v3.2](https://github.com/ufrisk/MemProcFS/releases/tag/v3.2) -* Bug fixes. -* Support for low-memory x64 systems. -* New Features: - * Certificates. - * Physical memory map. - * Per-page physical memory information (PFN database). - * Registry "big data" value type support. - -[v3.3](https://github.com/ufrisk/MemProcFS/releases/tag/v3.3) -* Bug fixes. -* Better write support. -* AMD Ryzen FPGA support. -* Module map: new info - Full .DLL Path. -* Thread map: new info - CPU registers. -* New forensic mode: - * Timelining. - * NTFS MFT parsing. - * SQLITE database generation. -* New Features: - * Minidump .DMP file generation for individual processes. - * Syscalls - nt & win32k. - -[v3.4](https://github.com/ufrisk/MemProcFS/releases/tag/v3.4) -* Bug fixes. -* Support for [LiveCloudKd](https://github.com/ufrisk/LeechCore/wiki/Device_LiveCloudKd). -* Network UDP and TCP listen socket support. -* C# API and examples - located in `vmmsharp` project. - -[v3.5](https://github.com/ufrisk/MemProcFS/releases/tag/v3.5) -* Bug fixes. -* New Features: - * Minidump for live processes. - * Services information. - * Memmap: Verbose VAD with individual page info. - -[v3.6](https://github.com/ufrisk/MemProcFS/releases/tag/v3.6) -* Bug fixes & refactorings. -* NB! Breaking C/C++ API changes (function renames). -* New Features: - * Unloaded modules. - * [FindEvil](https://github.com/ufrisk/MemProcFS/wiki/FS_FindEvil) - find select signs of injections and malware. - -[v3.7](https://github.com/ufrisk/MemProcFS/releases/tag/v3.7) -* Updates & Improvements: - * Registry. - * Services. - * NTFS MFT. -* New Features: - * Time: process-time, boot-time, current-time, timezone. - * Python Light Plugins: print('file system plugins as easy as Python print!') - * Registry Parsing: usb-storage, bluetooth, wallpapers and more in 'py/reg' & 'py/by-user/reg'. - -[v3.8](https://github.com/ufrisk/MemProcFS/releases/tag/v3.8) -* Updates & Improvements: - * Rename 'sysinfo' directory to 'sys'. - * Better os detection (symbol fallback). - * Handles: additional object info. - * Info header in most info-files (enabled by default - possible to disable). -* New Features: - * Windows Kernel Object Manager Objects. - * Additional kernel driver information. - * Detailed Object and Object Header Info. - -[v3.9](https://github.com/ufrisk/MemProcFS/releases/tag/v3.9) -* Bug fixes. -* License Change: GNU Affero General Public License v3.0. -* Updates & Improvements: - * Faster and more robust parsing of physical memory map - * Rename per-process `user` to `token` and add more info. -* New Features: - * New [Python API](https://github.com/ufrisk/MemProcFS/wiki/API_Python) now also available on [Python pip](https://pypi.org/project/memprocfs/). Check out the [YouTube demo](https://youtu.be/pLFU1lxBNM0)! - * `py/reg/net/tcpip_interfaces.txt` - -[v3.10](https://github.com/ufrisk/MemProcFS/releases/tag/v3.10) -* Bug fixes. -* New Features: - * Scheduled Tasks at `/sys/tasks/` - * Forensic mode: JSON info file generation `/forensic/json/` (compatible with Elasticsearch). - - [v4.0](https://github.com/ufrisk/MemProcFS/releases/tag/v4.0) * Linux support (x64 and aarch64). * Separate releases for Windows and Linux. @@ -295,9 +197,10 @@ v1.1-v2.10 * Process integrity levels and full SID list. * [Heap parsing](https://github.com/ufrisk/MemProcFS/wiki/FS_Process_Heaps). * [Web history](https://github.com/ufrisk/MemProcFS/wiki/FS_Web) plugin. + -Latest: -* Bug fixes. -* [Java API](https://github.com/ufrisk/MemProcFS/wiki/API_Java). -* Additional info in [token/sid-all.txt](https://github.com/ufrisk/MemProcFS/wiki/FS_Process_Token). -* ElasticSearch authentication for JSON import added. +[v5.0](https://github.com/ufrisk/MemProcFS/releases/tag/v5.0) +* Major release with new features to support parallel analysis tasks. +* Breaking API changes and major updates. +* Extended forensic analysis capabilties and [CSV file](https://github.com/ufrisk/MemProcFS/wiki/FS_Forensic_CSV) support. +* New [Java API](https://github.com/ufrisk/MemProcFS/wiki/API_Java). diff --git a/includes/leechcore_device.h b/includes/leechcore_device.h new file mode 100644 index 0000000..efa5e40 --- /dev/null +++ b/includes/leechcore_device.h @@ -0,0 +1,172 @@ +// leechcore_device.h : external header file to be used by LeechCore plug-in +// modules implemented as separate libraries. +// +// A LeechCore device plugin module must be placed alongside leechcore.[dll|so] +// and follow the naming convention leechcore_device_xxxx.[dll|so] where xxxx +// is the name of the device. +// +// The DLL load function must not initialize the device itself or do anything +// special that may take time to perform - since the plugin module will always +// be loaded even if not used. +// +// The plugin module must implement and export the open function: +// BOOL LcPluginCreate(_In_ PLC_CONTEXT ctx); +// The LcPluginCreate() function will be called whenever a new instance of the +// device may be created/opened - if only one instance may be open at the same +// time this should be handled by the plugin module itself. +// +// (c) Ulf Frisk, 2020-2022 +// Author: Ulf Frisk, pcileech@frizk.net +// +// Header Version: 2.5 +// + +#ifndef __LEECHCORE_DEVICE_H__ +#define __LEECHCORE_DEVICE_H__ +#include +#include "leechcore.h" + +#ifdef LINUX +#include +#include +#ifndef _LINUX_DEF_CRITICAL_SECTION +#define _LINUX_DEF_CRITICAL_SECTION +typedef struct tdCRITICAL_SECTION { + pthread_mutex_t mutex; + pthread_mutexattr_t mta; +} CRITICAL_SECTION, *LPCRITICAL_SECTION; +#endif /* _LINUX_DEF_CRITICAL_SECTION */ +#endif /* LINUX */ + +#define LC_CONTEXT_VERSION 0xc0e10004 +#define LC_DEVICE_PARAMETER_MAX_ENTRIES 0x10 + +typedef struct tdLC_DEVICE_PARAMETER_ENTRY { + CHAR szName[MAX_PATH]; + CHAR szValue[MAX_PATH]; + QWORD qwValue; +} LC_DEVICE_PARAMETER_ENTRY, *PLC_DEVICE_PARAMETER_ENTRY; + +typedef struct tdLC_CONTEXT LC_CONTEXT, *PLC_CONTEXT; + +typedef struct tdLC_READ_CONTIGIOUS_CONTEXT { + PLC_CONTEXT ctxLC; + HANDLE hEventWakeup; + HANDLE hEventFinish; + HANDLE hThread; + DWORD iRL; + DWORD cMEMs; + PPMEM_SCATTER ppMEMs; + QWORD paBase; + DWORD cbRead; + DWORD cb; + BYTE pb[0]; +} LC_READ_CONTIGIOUS_CONTEXT, *PLC_READ_CONTIGIOUS_CONTEXT; + +#define LC_PRINTF_ENABLE 0 +#define LC_PRINTF_V 1 +#define LC_PRINTF_VV 2 +#define LC_PRINTF_VVV 3 + +typedef struct tdLC_CONTEXT { + DWORD version; // LC_CONTEXT_VERSION + DWORD dwHandleCount; + HANDLE FLink; + union { + CRITICAL_SECTION Lock; + BYTE _PadLinux[48]; + }; + QWORD cReadScatterMEM; + LC_STATISTICS CallStat; + HANDLE hDeviceModule; + BOOL(*pfnCreate)(_Inout_ PLC_CONTEXT ctxLC, _Out_opt_ PPLC_CONFIG_ERRORINFO ppLcCreateErrorInfo); + // Config for use by devices below: + LC_CONFIG Config; + DWORD cDeviceParameter; + LC_DEVICE_PARAMETER_ENTRY pDeviceParameter[LC_DEVICE_PARAMETER_MAX_ENTRIES]; + BOOL fWritable; // deprecated - do not use! + BOOL fPrintf[4]; + HANDLE hDevice; + BOOL fMultiThread; + VOID(*pfnReadScatter)(_In_ PLC_CONTEXT ctxLC, _In_ DWORD cpMEMs, _Inout_ PPMEM_SCATTER ppMEMs); + VOID(*pfnReadContigious)(_Inout_ PLC_READ_CONTIGIOUS_CONTEXT ctxReadContigious); + VOID(*pfnWriteScatter)(_In_ PLC_CONTEXT ctxLC, _In_ DWORD cpMEMs, _Inout_ PPMEM_SCATTER ppMEMs); + BOOL(*pfnWriteContigious)(_In_ PLC_CONTEXT ctxLC, _In_ QWORD pa, _In_ DWORD cb, _In_reads_(cb) PBYTE pb); + BOOL(*pfnGetOption)(_In_ PLC_CONTEXT ctxLC, _In_ QWORD fOption, _Out_ PQWORD pqwValue); + BOOL(*pfnSetOption)(_In_ PLC_CONTEXT ctxLC, _In_ QWORD fOption, _In_ QWORD qwValue); + BOOL(*pfnCommand)(_In_ PLC_CONTEXT ctxLC, _In_ QWORD fOption, _In_ DWORD cbDataIn, _In_reads_opt_(cbDataIn) PBYTE pbDataIn, _Out_opt_ PBYTE *ppbDataOut, _Out_opt_ PDWORD pcbDataOut); + VOID(*pfnClose)(_Inout_ PLC_CONTEXT ctxLC); + struct { + DWORD cThread; + DWORD cbChunkSize; + BOOL fLoadBalance; + } ReadContigious; + // Internal ReadContigious functionality: + struct { + BOOL fActive; + HANDLE hEventFinish[8]; + PLC_READ_CONTIGIOUS_CONTEXT ctx[8]; + } RC; + // MemMap functionality: + DWORD cMemMap; + DWORD cMemMapMax; + PLC_MEMMAP_ENTRY pMemMap; + // Remote functionality: + struct { + BOOL fCompress; + DWORD dwRpcClientId; + } Rpc; +} LC_CONTEXT, *PLC_CONTEXT; + +/* +* Retrieve a device parameter by its name (if exists). +* -- ctxLc +* -- szName +* -- return +*/ +EXPORTED_FUNCTION PLC_DEVICE_PARAMETER_ENTRY LcDeviceParameterGet(_In_ PLC_CONTEXT ctxLC, _In_ LPSTR szName); + +/* +* Retrieve the numeric value of a device parameter (if exists). +* -- ctxLc +* -- szName +* -- return = the numeric value of the device parameter - 0 on fail. +*/ +EXPORTED_FUNCTION QWORD LcDeviceParameterGetNumeric(_In_ PLC_CONTEXT ctxLC, _In_ LPSTR szName); + +#define lcprintf(ctxLC, _Format, ...) { if(ctxLC->fPrintf[0]) { ctxLC->Config.pfn_printf_opt ? ctxLC->Config.pfn_printf_opt(_Format, ##__VA_ARGS__) : printf(_Format, ##__VA_ARGS__); } } +#define lcprintfv(ctxLC, _Format, ...) { if(ctxLC->fPrintf[1]) { lcprintf(ctxLC, _Format, ##__VA_ARGS__); } } +#define lcprintfvv(ctxLC, _Format, ...) { if(ctxLC->fPrintf[2]) { lcprintf(ctxLC, _Format, ##__VA_ARGS__); } } +#define lcprintfvvv(ctxLC, _Format, ...) { if(ctxLC->fPrintf[3]) { lcprintf(ctxLC, _Format, ##__VA_ARGS__); } } +#define lcprintf_fn(ctxLC, _Format, ...) { if(ctxLC->fPrintf[0]) { lcprintf(ctxLC, "%s: "_Format, __func__, ##__VA_ARGS__); } } +#define lcprintfv_fn(ctxLC, _Format, ...) { if(ctxLC->fPrintf[1]) { lcprintf(ctxLC, "%s: "_Format, __func__, ##__VA_ARGS__); } } +#define lcprintfvv_fn(ctxLC, _Format, ...) { if(ctxLC->fPrintf[2]) { lcprintf(ctxLC, "%s: "_Format, __func__, ##__VA_ARGS__); } } +#define lcprintfvvv_fn(ctxLC, _Format, ...) { if(ctxLC->fPrintf[3]) { lcprintf(ctxLC, "%s: "_Format, __func__, ##__VA_ARGS__); } } + +/* +* Check whether the memory map is initialized or not. +* -- ctxLC +* -- return +*/ +EXPORTED_FUNCTION BOOL LcMemMap_IsInitialized(_In_ PLC_CONTEXT ctxLC); + +/* +* Add a memory range to the memory map. +* -- ctxLC +* -- pa +* -- cb +* -- paRemap = remap offset within file (if relevant). +* -- return +*/ +_Success_(return) +EXPORTED_FUNCTION BOOL LcMemMap_AddRange(_In_ PLC_CONTEXT ctxLC, _In_ QWORD pa, _In_ QWORD cb, _In_opt_ QWORD paRemap); + +/* +* Get the max physical address from the memory map. +* -- ctxLC +* -- return +*/ +_Success_(return != 0) +EXPORTED_FUNCTION QWORD LcMemMap_GetMaxAddress(_In_ PLC_CONTEXT ctxLC); + +#endif /* __LEECHCORE_DEVICE_H__ */ diff --git a/includes/lib32/leechcore.lib b/includes/lib32/leechcore.lib index 7b390f27189f9adf8fde0a7a966fd2d2b5e79ae6..0c89bafd8404011032b015c4c8a0cf9ad8ff691f 100644 GIT binary patch delta 114 zcmeyM`9X7o69?z9f9KEhGcqu6Os?gUo_v8@dU7L2DT@L_O4a0F9MMcERhz>(Wf@s# z>TP+ud-6tZ`N=c5GGNl`Tn@?kxdnQeDL~bx+~q7q;hK*pZ{XelQy@LLo`(ZuMkh}? F2LMe?C{+Le delta 114 zcmeyM`9X7o69;FVfZH#AMg|6s$+cY4lP_>fPj2KWWszmrS~~d`M>Nyc(#_$VvW%=} zW-u_~} wMKvbh=i&gexHzRJGjqqX+TB|E=Kf?|E_t9n>B;lC%fYHt5UMuE^O$k~02)mpK>z>% diff --git a/includes/lib64/vmm.lib b/includes/lib64/vmm.lib index 778c34654fe19aeaaa72081d31186cd1af3c0ca6..8c3c921f1d717d27ec707b01c3fcaa3c62818318 100644 GIT binary patch delta 4150 zcmcJR32@Z)6~|v>H_0y>NWyOJlaPd4a*=aG?vUMNcXN?D*@Vpkp%D-jt)h!k9Y6)i zqf}8qMNuh5r_mk`LV$8AAyK&mq##$LT!KK6qu<|ux2U6?>2#)<`Q-iH@jKr8z5g%y z(>Aw_JKbJLcO)gIMJYcmUPQEyDB%WCvW{q65mDMYC+Pu1l9U%++=c|kkxnM)i6rSy zIZ2&Nq|gfq8ZcMk2}n@C)=6WpgQyV!O*u{)P9p#`);no>4|dQT(2Jf|C7CN)f9t z9uk-qxd?*s_l$H`(v2Y=6}L)1ZGFdC7>#u6ET1PrfxQ40v=sGVtI4?(_Cn728{9@@tt|p6jQU z1|FX&_)=a#*GGPjxF;0Nm}Q^-K)bD|y~Cb6bEbWI+fO(6nV(;X4&l9H{5Z4Pm!||x zb0j6*eJ?tQ=tcsOE*UK~j%ZyPQ9wG;iz!66!AK)+dIHf?uuV=S>IDG}L{EUV_0Sv9 z+D$~Kq1R*l9>zhRj`Ab7*DSxIs&Gek${Qld^Qe{L$n>N%q5BkVTD8s!HGQVmrvvc zIXjOW)Q0x#1=rymjEQqW9J=8Z5MO{z!A5k#$V{|z7SV@bmY(QKumuY(gI$I31`APQ z8P>ufiZFhr0*3+1%ZYp;*TWZsag~*5Cs0iydT^2hnPZ@DK>&zqMaH1ohH`=ZsKWYE ze7Il{G7AG4xR$9X-xXX#Ee?h^p4`cUG~`X~q#`wW(XXh3if96v$V^5mp<*&n9_3RG zQ=&%WI@?i--x8Da0-eGh!}fm{-PmOBOoc3C54x~Y{XhR=!!-YIRA0RE*pFO?$d%N=8wY?-MUP}|LLZZ%kgm$+Eq3((L+`9=e#rgOu{<1 zHg=4Q;hMxmjMj|{+$}%AT+WY8u-WcK}GmNqe;B?+~6;Q;lGDDrByr^zxSfl2Jo#E z6Z>ZBVykZT?}~;+^~3yMs9$7b2A8C2#lgzqdqNP67d2JKkENQ#Uvie74THrU7Mrj= zo^*2vG!Mn^PdEh>H3)axkVF2^1Z&fqM0d~r1EJ8o_}A$+K~vw{ zDm4wCf_9?ogPRf1ytzEXE}}QD+a|Sv&;ogXMh0KZ)QOLKF7?P6gLqY@e`iZ3FK*R} zVe6u|M8W7IjmjSYnLtyzRz1LQ?o22j*ZXsXzCyD~SNxfr>_;m0^V9KSy-7V|$(lQH zyeBKP)7O(#S!S_d-iq6C2-0$2R$!;^Kz3vqL}XrnpFE5XM!PV$cixejzYO8(@n-d) z10U=Q{em36>X98gZV2u|f25y-Q1QsvoI;kHly!7Fovxg^&jE>`Mx%Ahb_oof^Qx)WbTK?`S}yeZykjJUD0hQJLNl?6x@~nj6Na z@E>xtnwb9Q&&X-fupf&EMh>acuJ+D;`${+uDfH)^1y$iE*@Xsi z>g`J><-uZkNuf>LUOHUKB@UX7{faC?uf2XC5dLA@USt)030qG^K^x9}MN`Bs&+Q~EBk`kr`VrAoKWT+XnFr@x$Y=5Dj)L<;L*iK@#69C_Q}GHW=FAIoHs@9 zm)$*v&lQ{5Vbq3fIDP4)T=3o>y4&@yL#M$kbT9Pnmc2WcYYaBgb9l!k`6b2kR)f|1 z#MNU5BB3S7?UslTE;bs)?0HGb`4ahMqg7)M9rbAxLXuFSC4s>lQBtZY2;cR+tXeW` zt$_jjY>7!&SI#*lKe2IqyrkWG-l+Sp$UIWy!p9NPQEC*vzQ600d8G2DQoAU+e)Enz zbsCQ`S=B2<&gD3M+#JNKqI~(UCWENkwf0+iWf}aWS;vv)I#vJl`pW~VPW&2uXQdGBa%-c(`ojvDpI*RtM)N?Aq+^4Lm~cSH5o zt#Y*@r!jz6R#teY`yV49l6|j|iMsi49sd{1d zeMiGMyB=>?U4^)^;F})VpjCXh&MG#Q8TU$UBInmz)z=^RW=9M!X$a=-`fBww_3Ayb z?A9nX!C4I!@#&GPTV!o&IkLf@SE=!|wWKO<<=gwbl`pVP@!TFN_*#C7{L>NlQ!! zTVvFm(QMQ#4}ADLX}2o&NM7G;R6W*Hb&3CO4dF#GUL0jLit4)J9(iG{>;`LDfSR{A z;j5_9ifdoZSFUmrJpSB`_+=KSr*~TS4LQf=^5A+fZ+44O(>pQcTbXtnwmcRS%BNe5 zBKNI%CuOvq(_7oU>n|@;-pa|coBHB|czbK9#xJyUpX`t+n6^0}oHHhsitx1KUr5_j JUOZ{ozW_aSRsjG2 delta 3921 zcmcJQd2rN47RO&?ej%Ni9Aq*{Cg%`h3<3d?ko!I+$z*1d$wltTWC#!>8xBQQaRXH> zcu>ODa}`-F4yBewEN~+(lM2oe#X$Wb`H_ry5*;?Y=~Gf@o?XQF04W%JW2N;U1R5f@uS8jFCi=v|%@? zMj{tGU_m3sy0`@^iFMOlM&x1_ENE)$mH)s=H!TT7F4n+G?zm~~Ad*bS=3Kl73+fMf zsDcFzsUEh$g0dtxr3Z;5#+zOELWbQ6=ez%GZqSWdJE_<{`x*j7UnU5f>Qd>V(UQ4MI1qJ71N zR|9{*Otb*B=Mo(O>3Kwf`9w>=CbWMpBASDXyT1U7;v|Nk*P~rrf(yH&gy<|fm*)`O z0Bf^}{9ywzXa$&<0S)ZULK}V6umhQx7!#>r7l0HT?N(4`A=(4(S3$?-f?%Hp@s&ic zfFr0zKJL$wcA{&b&4CO1HiURP76HBxk2z2>oW0cqy@Kc+SZ`$a0@?$}x+9(FAi&3! zyh)HRsYoFo>Y_PRLPj!^g-ldVrBp@*R7iQ0Pg7_rCDAlWrWDGgEJ~*gs-Pk&?xj>p zqg=|S92!jqil!KfqDYFPaTH5q$w{3wgJ#i8noNmQMK-chCDqe(s>NwkQw>d|Ni?1w zrUxmW9-;)AK(k3tVH8546iyN3M{3egAdMk^3ZNj;QZVVLff}im+Njq~?bJlg)ItvG zATN60f6wW^NvZe$kkfyrG>YmimSVHnUNpC7Vdt+-&u?aS%_{BWgOTBUb(ESls$kYf z{qdJ)ix(`P?5jDUoHr(ruScErcD;Gx%L!Uu=dbNMA3e{DubKS%W*bf`9HR(sjgRAR zRKEO1{J<~M;FB;4p9G#95Zbrrp(L+gKO7-_!wGl2`tCoRJz6#M&Wk5FH))%fgD<2c zur@gnE&pi|+?sq_iCeaCXeU26Eru7T%y30aarG`%%{f(cgP)z|9u_C^oju+261!%& zhxVrK;5W;(BIJuFe$wNjdU0QxL(EAjx-Gp2I4a%3=hK7LYctypghLrcD!x2Q%l;W= zG2yX`Uq?byu`|Od&fHyiYAig3KhEe9Rd-L{(8BZPg3M;I;mp08I(Vabb7rfiW~cpF z1Uw%+2tE-Q!f{z9VOe{e*Av6PM(ed<6qYfd?n}i=Rf5*#nQk3cu0By zJUZ8@-u>8=yYcV>k;-=gQ9K-=@JqSn>en2DA4q+SOOIjSJhQUwr-}X1+>;x@i}I}M zuY6y-Aa|v8Md)}C+S7BtaIF*!ZJ#EX$7Wf?&a}-#ay=dYIo~OsZF}>gEM^F63mhWh zvw~A{j!=H8pi?P+`Q1wq98eI#_X=`lI)-&?^A5;#^eC6-idr1=?4_NLR=Iy(ke;UW zwF_6}0^zcz^6GULTExEl>uyOgf)5lrm6u0dxnkh=3w4}dR4<~d8m}AB7scy~W(m_H zBd(G~b3k#Ydi!j@n=##f%JzLf5(Y1kD=O@2YjM}97Jt6eN#H?UtGNgB_$ z1#^rxkn37phb8=HI6jp<>7E`n|FzO8Mw*I0d=P4eOYI5L@c1f=@>2h2-%a4vm0`R+ zD2O*#S;VaiM^4JPEW|~#-c~7It=VuxD%nuFg(hq8xST!5HP6UcHG5ZEm8*HjkHvGh zEsRIT2J+u3Q`xUpE7H1~2FD>b&lS5t>&G{%O`?D1s^e14_ozOcAFJ@}8k2g-((PZ$ zx)mVnf>=GDt}$t{xBTmzj4qUAvuUE)RBKZE+L))L`B;uLB5F5A2G*O@`Ro7U`hb_-^|B;CLR}5X);u3(jpci7VM7{W8{y*!g0m zchm>6;+4FtDT4DSD?FjeB6c6kyDBSR1+`lgYkqf9-d7vnZgPrC1DkKl`&!M;X1lnu z>CAcQ)$m8nb|ts+z_~cKH|uz*w;$VDEb8sA?7b!Duao8Tj^+# zdaF3K)vDI&FWfgEYPu^*3*DQyw3@~4)pI_Vvp4X)R=e;aeZTY?xwFkKp7R;`Ounur zKHBC`-%|}-kzO-q*c+!~tKB5N=zr>;@|aq9qx})_!nm3t>9xX(s z{-U(;C5Mg!9r*QpP~k1;X}_sll|6P(PpvpJsJ|hVb|~Sz(ordNtGxQ9;(*d6ww7GK zCJ(%WZ5^{j$D2Mwvd_u;I=U2nZqU~Twsh!uKy1Tr~m)} diff --git a/includes/vmmdll.h b/includes/vmmdll.h index 2bfce0d..b42dba7 100644 --- a/includes/vmmdll.h +++ b/includes/vmmdll.h @@ -1,13 +1,23 @@ // vmmdll.h : header file to include in projects that use vmm.dll / vmm.so // +// Please also consult the guide at: https://github.com/ufrisk/MemProcFS/wiki +// +// U/W functions +// ============= // Windows may access both UTF-8 *U and Wide-Char *W versions of functions // while Linux may only access UTF-8 versions. Some functionality may also // be degraded or unavailable on Linux. +// +// v5 API +// ====== +// v5 of the API support multiple concurrent parallel analysis tasks. +// To accomodate this significant changes have been done to the API which is +// largely incompatible (but very similar) to the earlier API versions. // // (c) Ulf Frisk, 2018-2022 // Author: Ulf Frisk, pcileech@frizk.net // -// Header Version: 4.9 +// Header Version: 5.0 // #include "leechcore.h" @@ -67,6 +77,8 @@ typedef uint16_t WCHAR, *PWCHAR, *LPWSTR, *LPCWSTR; #endif /* LINUX */ +typedef struct tdVMM_HANDLE *VMM_HANDLE; + //----------------------------------------------------------------------------- @@ -124,21 +136,34 @@ typedef uint16_t WCHAR, *PWCHAR, *LPWSTR, *LPCWSTR; * struct LC_CONFIG_ERRORINFO with extended error information upon * failure. Any memory received should be free'd by caller by * calling LcMemFree(). -* -- return = success/fail +* -- return = VMM_HANDLE on success for usage in subsequent API calls. NULL=fail. */ -EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_Initialize(_In_ DWORD argc, _In_ LPSTR argv[]); +EXPORTED_FUNCTION _Success_(return != NULL) +VMM_HANDLE VMMDLL_Initialize(_In_ DWORD argc, _In_ LPSTR argv[]); -EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_InitializeEx(_In_ DWORD argc, _In_ LPSTR argv[], _Out_opt_ PPLC_CONFIG_ERRORINFO ppLcErrorInfo); +EXPORTED_FUNCTION _Success_(return != NULL) +VMM_HANDLE VMMDLL_InitializeEx(_In_ DWORD argc, _In_ LPSTR argv[], _Out_opt_ PPLC_CONFIG_ERRORINFO ppLcErrorInfo); /* -* Close an initialized instance of VMM.DLL and clean up all allocated resources -* including plugins, linked PCILeech.DLL and other memory resources. -* -- return = success/fail. +* Close an instantiated version of VMM_HANDLE and free up any resources. +* -- hVMM */ -EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_Close(); +EXPORTED_FUNCTION +VOID VMMDLL_Close(_In_opt_ _Post_ptr_invalid_ VMM_HANDLE hVMM); + +/* +* Close all instantiated versions of VMM_HANDLE and free up all resources. +*/ +EXPORTED_FUNCTION +VOID VMMDLL_CloseAll(); + +/* +* Query the size of memory allocated by the VMMDLL. +* -- pvMem +* -- return = number of bytes required to hold memory allocation. +*/ +EXPORTED_FUNCTION _Success_(return != 0) +SIZE_T VMMDLL_MemSize(_In_ PVOID pvMem); /* * Free memory allocated by the VMMDLL. @@ -190,21 +215,13 @@ VOID VMMDLL_MemFree(_Frees_ptr_opt_ PVOID pvMem); #define VMMDLL_OPT_FORENSIC_MODE 0x2000020100000000 // RW - enable/retrieve forensic mode type [0-4]. #define VMMDLL_OPT_REFRESH_ALL 0x2001ffff00000000 // W - refresh all caches -#define VMMDLL_OPT_REFRESH_FREQ_MEM 0x2001000200000000 // W - refresh memory cache (excl. TLB) [partial 33%/call] -#define VMMDLL_OPT_REFRESH_FREQ_TLB 0x2001000400000000 // W - refresh page table (TLB) cache [partial 33%/call] +#define VMMDLL_OPT_REFRESH_FREQ_MEM 0x2001100000000000 // W - refresh memory cache (excl. TLB) [fully] +#define VMMDLL_OPT_REFRESH_FREQ_MEM_PARTIAL 0x2001000200000000 // W - refresh memory cache (excl. TLB) [partial 33%/call] +#define VMMDLL_OPT_REFRESH_FREQ_TLB 0x2001080000000000 // W - refresh page table (TLB) cache [fully] +#define VMMDLL_OPT_REFRESH_FREQ_TLB_PARTIAL 0x2001000400000000 // W - refresh page table (TLB) cache [partial 33%/call] #define VMMDLL_OPT_REFRESH_FREQ_FAST 0x2001040000000000 // W - refresh fast frequency - incl. partial process refresh #define VMMDLL_OPT_REFRESH_FREQ_MEDIUM 0x2001000100000000 // W - refresh medium frequency - incl. full process refresh #define VMMDLL_OPT_REFRESH_FREQ_SLOW 0x2001001000000000 // W - refresh slow frequency. -#define VMMDLL_OPT_REFRESH_PROCESS 0x2001000100000000 // W - DEPRECATED: refresh process listings -#define VMMDLL_OPT_REFRESH_READ 0x2001000200000000 // W - DEPRECATED: refresh physical read cache -#define VMMDLL_OPT_REFRESH_TLB 0x2001000400000000 // W - DEPRECATED: refresh page table (TLB) cache -#define VMMDLL_OPT_REFRESH_PAGING 0x2001000800000000 // W - DEPRECATED: refresh virtual memory 'paging' cache -#define VMMDLL_OPT_REFRESH_REGISTRY 0x2001001000000000 // W - DEPRECATED: -#define VMMDLL_OPT_REFRESH_USER 0x2001002000000000 // W - DEPRECATED: -#define VMMDLL_OPT_REFRESH_PHYSMEMMAP 0x2001004000000000 // W - DEPRECATED: -#define VMMDLL_OPT_REFRESH_PFN 0x2001008000000000 // W - DEPRECATED: -#define VMMDLL_OPT_REFRESH_OBJ 0x2001010000000000 // W - DEPRECATED: -#define VMMDLL_OPT_REFRESH_NET 0x2001020000000000 // W - DEPRECATED: static LPCSTR VMMDLL_MEMORYMODEL_TOSTRING[4] = { "N/A", "X86", "X86PAE", "X64" }; @@ -226,23 +243,25 @@ typedef enum tdVMMDLL_SYSTEM_TP { * Get a device specific option value. Please see defines VMMDLL_OPT_* for infor- * mation about valid option values. Please note that option values may overlap * between different device types with different meanings. +* -- hVMM * -- fOption * -- pqwValue = pointer to ULONG64 to receive option value. * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_ConfigGet(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue); +BOOL VMMDLL_ConfigGet(_In_ VMM_HANDLE hVMM, _In_ ULONG64 fOption, _Out_ PULONG64 pqwValue); /* * Set a device specific option value. Please see defines VMMDLL_OPT_* for infor- * mation about valid option values. Please note that option values may overlap * between different device types with different meanings. +* -- hVMM * -- fOption * -- qwValue * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_ConfigSet(_In_ ULONG64 fOption, _In_ ULONG64 qwValue); +BOOL VMMDLL_ConfigSet(_In_ VMM_HANDLE hVMM, _In_ ULONG64 fOption, _In_ ULONG64 qwValue); @@ -372,25 +391,28 @@ EXPORTED_FUNCTION BOOL VMMDLL_VfsList_IsHandleValid(_In_ HANDLE pFileList); * by callbacks into functions supplied in the pFileList parameter. * If information of an individual file is needed it's neccessary to list all * files in its directory. +* -- hVMM * -- [uw]szPath * -- pFileList * -- return */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_VfsListU(_In_ LPSTR uszPath, _Inout_ PVMMDLL_VFS_FILELIST2 pFileList); -_Success_(return) BOOL VMMDLL_VfsListW(_In_ LPWSTR wszPath, _Inout_ PVMMDLL_VFS_FILELIST2 pFileList); +_Success_(return) BOOL VMMDLL_VfsListU(_In_ VMM_HANDLE hVMM, _In_ LPSTR uszPath, _Inout_ PVMMDLL_VFS_FILELIST2 pFileList); +_Success_(return) BOOL VMMDLL_VfsListW(_In_ VMM_HANDLE hVMM, _In_ LPWSTR wszPath, _Inout_ PVMMDLL_VFS_FILELIST2 pFileList); /* * List a directory of files in MemProcFS and return a VMMDLL_VFS_FILELISTBLOB. * CALLER FREE: VMMDLL_MemFree(return) +* -- hVMM * -- uszPath * -- return */ EXPORTED_FUNCTION -_Success_(return != NULL) PVMMDLL_VFS_FILELISTBLOB VMMDLL_VfsListBlobU(_In_ LPSTR uszPath); +_Success_(return != NULL) PVMMDLL_VFS_FILELISTBLOB VMMDLL_VfsListBlobU(_In_ VMM_HANDLE hVMM, _In_ LPSTR uszPath); /* * Read select parts of a file in MemProcFS. +* -- hVMM * -- [uw]szFileName * -- pb * -- cb @@ -400,11 +422,12 @@ _Success_(return != NULL) PVMMDLL_VFS_FILELISTBLOB VMMDLL_VfsListBlobU(_In_ LPST * */ EXPORTED_FUNCTION -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_VfsReadU(_In_ VMM_HANDLE hVMM, _In_ LPSTR uszFileName, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset); +NTSTATUS VMMDLL_VfsReadW(_In_ VMM_HANDLE hVMM, _In_ LPWSTR wszFileName, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset); /* * Write select parts to a file in MemProcFS. +* -- hVMM * -- [uw]szFileName * -- pb * -- cb @@ -413,8 +436,8 @@ NTSTATUS VMMDLL_VfsReadW(_In_ LPWSTR wszFileName, _Out_writes_to_(cb, *pcbRead) * -- return */ EXPORTED_FUNCTION -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_VfsWriteU(_In_ VMM_HANDLE hVMM, _In_ LPSTR uszFileName, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset); +NTSTATUS VMMDLL_VfsWriteW(_In_ VMM_HANDLE hVMM, _In_ LPWSTR wszFileName, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset); /* * Utility functions for MemProcFS read/write towards different underlying data @@ -438,7 +461,7 @@ EXPORTED_FUNCTION NTSTATUS VMMDLL_UtilVfsWriteFile_DWORD(_Inout_ PDWORD pdwTarge // function. The plugin/module may decide to call pfnPluginManager_Register to // register plugins in the form of different names one or more times. // Example of registration function in a plugin DLL below: -// 'VOID InitializeVmmPlugin(_In_ PVMM_PLUGIN_REGINFO pRegInfo)' +// 'VOID InitializeVmmPlugin(_In_ VMM_HANDLE H, _In_ PVMM_PLUGIN_REGINFO pRegInfo)' //----------------------------------------------------------------------------- /* @@ -446,16 +469,17 @@ EXPORTED_FUNCTION NTSTATUS VMMDLL_UtilVfsWriteFile_DWORD(_Inout_ PDWORD pdwTarge * MemProcFS. Please note that plugins are not loaded by default - they have to * be explicitly loaded by calling this function. They will be unloaded on a * general close of the vmm dll. +* -- hVMM * -- return */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_InitializePlugins(); +BOOL VMMDLL_InitializePlugins(_In_ VMM_HANDLE hVMM); #define VMMDLL_PLUGIN_CONTEXT_MAGIC 0xc0ffee663df9301c #define VMMDLL_PLUGIN_CONTEXT_VERSION 5 #define VMMDLL_PLUGIN_REGINFO_MAGIC 0xc0ffee663df9301d -#define VMMDLL_PLUGIN_REGINFO_VERSION 13 -#define VMMDLL_PLUGIN_FORENSIC_JSONDATA_VERSION 0xc0ee0001 +#define VMMDLL_PLUGIN_REGINFO_VERSION 15 +#define VMMDLL_PLUGIN_FORENSIC_JSONDATA_VERSION 0xc0ee0002 #define VMMDLL_PLUGIN_NOTIFY_VERBOSITYCHANGE 0x01 #define VMMDLL_PLUGIN_NOTIFY_REFRESH_FAST 0x05 // refresh fast event - at partial process refresh. @@ -467,6 +491,7 @@ BOOL VMMDLL_InitializePlugins(); typedef DWORD VMMDLL_MODULE_ID; typedef HANDLE *PVMMDLL_PLUGIN_INTERNAL_CONTEXT; +typedef struct tdVMMDLL_CSV_HANDLE *VMMDLL_CSV_HANDLE; #define VMMDLL_MID_MAIN ((VMMDLL_MODULE_ID)0x80000001) #define VMMDLL_MID_PYTHON ((VMMDLL_MODULE_ID)0x80000002) @@ -486,7 +511,7 @@ typedef struct tdVMMDLL_PLUGIN_CONTEXT { typedef struct tdVMMDLL_PLUGIN_FORENSIC_JSONDATA { DWORD dwVersion; // must equal VMMDLL_PLUGIN_FORENSIC_JSONDATA_VERSION - BOOL fVerbose; + DWORD _FutureUse; LPSTR szjType; // log type/name (json encoded) DWORD i; DWORD dwPID; @@ -504,9 +529,11 @@ typedef struct tdVMMDLL_PLUGIN_FORENSIC_JSONDATA { } VMMDLL_PLUGIN_FORENSIC_JSONDATA, *PVMMDLL_PLUGIN_FORENSIC_JSONDATA; typedef struct tdVMMDLL_PLUGIN_FORENSIC_INGEST_PHYSMEM { - DWORD cMEMs; BOOL fValid; - QWORD paBase; + QWORD pa; + DWORD cb; + PBYTE pb; + DWORD cMEMs; PPMEM_SCATTER ppMEMs; PVMMDLL_MAP_PFN pPfnMap; } VMMDLL_PLUGIN_FORENSIC_INGEST_PHYSMEM, *PVMMDLL_PLUGIN_FORENSIC_INGEST_PHYSMEM; @@ -518,7 +545,7 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO { VMMDLL_MEMORYMODEL_TP tpMemoryModel; VMMDLL_SYSTEM_TP tpSystem; HMODULE hDLL; - BOOL(*pfnPluginManager_Register)(struct tdVMMDLL_PLUGIN_REGINFO *pPluginRegInfo); + BOOL(*pfnPluginManager_Register)(_In_ VMM_HANDLE H, struct tdVMMDLL_PLUGIN_REGINFO *pPluginRegInfo); DWORD _Reserved[32]; // python plugin information - not for general use struct { @@ -542,12 +569,12 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO { } reg_info; // function plugin registration info to be filled out by the plugin below: struct { - BOOL(*pfnList)(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList); - NTSTATUS(*pfnRead)(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset); - NTSTATUS(*pfnWrite)(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset); - VOID(*pfnNotify)(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent); - VOID(*pfnClose)(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP); - BOOL(*pfnVisibleModule)(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP); + BOOL(*pfnList)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList); + NTSTATUS(*pfnRead)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset); + NTSTATUS(*pfnWrite)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset); + VOID(*pfnNotify)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent); + VOID(*pfnClose)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP); + BOOL(*pfnVisibleModule)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP); PVOID pvReserved[10]; } reg_fn; // Optional forensic plugin functionality for forensic (more comprehensive) @@ -557,17 +584,20 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO { // Functions are called in the order of: // pfnInitialize(), pfnIngest*(), pfnTimeline(), pfnLogJSON(), pfnFinalize() struct { - PVOID(*pfnInitialize)(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP); - VOID(*pfnFinalize)(_In_opt_ PVOID ctxfc); + PVOID(*pfnInitialize)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP); + VOID(*pfnFinalize)(_In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc); VOID(*pfnTimeline)( + _In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc, _In_ HANDLE hTimeline, - _In_ VOID(*pfnAddEntry)(_In_ HANDLE hTimeline, _In_ QWORD ft, _In_ DWORD dwAction, _In_ DWORD dwPID, _In_ DWORD dwData32, _In_ QWORD qwData64, _In_ LPSTR uszText), - _In_ VOID(*pfnEntryAddBySql)(_In_ HANDLE hTimeline, _In_ DWORD cEntrySql, _In_ LPSTR *pszEntrySql)); - VOID(*pfnIngestPhysmem)(_In_opt_ PVOID ctxfc, _In_ PVMMDLL_PLUGIN_FORENSIC_INGEST_PHYSMEM pIngestPhysmem); - VOID(*pfnIngestFinalize)(_In_opt_ PVOID ctxfc); - PVOID pvReserved[10]; - VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)); + _In_ VOID(*pfnAddEntry)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ QWORD ft, _In_ DWORD dwAction, _In_ DWORD dwPID, _In_ DWORD dwData32, _In_ QWORD qwData64, _In_ LPSTR uszText), + _In_ VOID(*pfnEntryAddBySql)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ DWORD cEntrySql, _In_ LPSTR *pszEntrySql)); + VOID(*pfnIngestPhysmem)(_In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc, _In_ PVMMDLL_PLUGIN_FORENSIC_INGEST_PHYSMEM pIngestPhysmem); + VOID(*pfnIngestVirtmem)(_In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc, _In_ DWORD dwPID, _In_ QWORD va, _In_ PBYTE pb, _In_ DWORD cb); + VOID(*pfnIngestFinalize)(_In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc); + PVOID pvReserved[8]; + VOID(*pfnLogCSV)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VMMDLL_CSV_HANDLE hCSV); + VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)); } reg_fnfc; // Additional system information - read/only by the plugins. struct { @@ -581,6 +611,29 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO { +//----------------------------------------------------------------------------- +// FORENSIC-MODE SPECIFIC FUNCTIONALITY BELOW: +//----------------------------------------------------------------------------- + +/* +* Append text data to a memory-backed forensics file. +* All text should be UTF-8 encoded. +* -- H +* -- uszFileName +* -- uszFormat +* -- .. +* -- return = number of bytes appended (excluding terminating null). +*/ +EXPORTED_FUNCTION _Success_(return != 0) +SIZE_T VMMDLL_ForensicFileAppend( + _In_ VMM_HANDLE H, + _In_ LPSTR uszFileName, + _In_z_ _Printf_format_string_ LPSTR uszFormat, + ... +); + + + //----------------------------------------------------------------------------- // VMM LOG FUNCTIONALITY BELOW: // It's possible for external code (primarily external plugins) to make use of @@ -600,6 +653,7 @@ typedef enum tdVMMDLL_LOGLEVEL { /* * Log a message using the internal MemProcFS vmm logging system. Log messages * will be displayed/suppressed depending on current logging configuration. +* -- hVMM * -- MID = module id supplied by plugin context PVMMDLL_PLUGIN_CONTEXT or * id given by VMMDLL_MID_*. * -- dwLogLevel @@ -608,6 +662,7 @@ typedef enum tdVMMDLL_LOGLEVEL { */ EXPORTED_FUNCTION VOID VMMDLL_Log( + _In_ VMM_HANDLE hVMM, _In_opt_ VMMDLL_MODULE_ID MID, _In_ VMMDLL_LOGLEVEL dwLogLevel, _In_z_ _Printf_format_string_ LPSTR uszFormat, @@ -617,6 +672,7 @@ VOID VMMDLL_Log( /* * Log a message using the internal MemProcFS vmm logging system. Log messages * will be displayed/suppressed depending on current logging configuration. +* -- hVMM * -- MID = module id supplied by plugin context PVMMDLL_PLUGIN_CONTEXT or * id given by VMMDLL_MID_*. * -- dwLogLevel @@ -625,6 +681,7 @@ VOID VMMDLL_Log( */ EXPORTED_FUNCTION VOID VMMDLL_LogEx( + _In_ VMM_HANDLE hVMM, _In_opt_ VMMDLL_MODULE_ID MID, _In_ VMMDLL_LOGLEVEL dwLogLevel, _In_z_ _Printf_format_string_ LPSTR uszFormat, @@ -663,6 +720,7 @@ VOID VMMDLL_LogEx( * boost will be given if above hardware limit. Max size of each unit of work is * one 4k page (4096 bytes). Reads must not cross 4k page boundaries. Reads must * start at even DWORDs (4-bytes). +* -- hVMM * -- dwPID - PID of target process, (DWORD)-1 to read physical memory. * -- ppMEMs = array of scatter read headers. * -- cpMEMs = count of ppMEMs. @@ -670,33 +728,36 @@ VOID VMMDLL_LogEx( * -- return = the number of successfully read items. */ EXPORTED_FUNCTION -DWORD VMMDLL_MemReadScatter(_In_ DWORD dwPID, _Inout_ PPMEM_SCATTER ppMEMs, _In_ DWORD cpMEMs, _In_ DWORD flags); +DWORD VMMDLL_MemReadScatter(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Inout_ PPMEM_SCATTER ppMEMs, _In_ DWORD cpMEMs, _In_ DWORD flags); /* * Write memory in various non-contigious locations specified by the pointers to * the items in the ppMEMs array. Result for each unit of work will be given * individually. No upper limit of number of items to write Max size of each * unit of work is one 4k page (4096 bytes). Writes must not cross 4k page boundaries. +* -- hVMM * -- dwPID - PID of target process, (DWORD)-1 to write physical memory. * -- ppMEMs = array of scatter read headers. * -- cpMEMs = count of ppMEMs. * -- return = the number of hopefully successfully written items. */ EXPORTED_FUNCTION -DWORD VMMDLL_MemWriteScatter(_In_ DWORD dwPID, _Inout_ PPMEM_SCATTER ppMEMs, _In_ DWORD cpMEMs); +DWORD VMMDLL_MemWriteScatter(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Inout_ PPMEM_SCATTER ppMEMs, _In_ DWORD cpMEMs); /* * Read a single 4096-byte page of memory. +* -- hVMM * -- dwPID - PID of target process, (DWORD)-1 to read physical memory. * -- qwA * -- pbPage * -- return = success/fail (depending if all requested bytes are read or not). */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_MemReadPage(_In_ DWORD dwPID, _In_ ULONG64 qwA, _Inout_bytecount_(4096) PBYTE pbPage); +BOOL VMMDLL_MemReadPage(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ ULONG64 qwA, _Inout_bytecount_(4096) PBYTE pbPage); /* * Read a contigious arbitrary amount of memory. +* -- hVMM * -- dwPID - PID of target process, (DWORD)-1 to read physical memory. * -- qwA * -- pb @@ -704,10 +765,11 @@ BOOL VMMDLL_MemReadPage(_In_ DWORD dwPID, _In_ ULONG64 qwA, _Inout_bytecount_(40 * -- return = success/fail (depending if all requested bytes are read or not). */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_MemRead(_In_ DWORD dwPID, _In_ ULONG64 qwA, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb); +BOOL VMMDLL_MemRead(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ ULONG64 qwA, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb); /* * Read a contigious amount of memory and report the number of bytes read in pcbRead. +* -- hVMM * -- dwPID - PID of target process, (DWORD)-1 to read physical memory. * -- qwA * -- pb @@ -718,19 +780,20 @@ BOOL VMMDLL_MemRead(_In_ DWORD dwPID, _In_ ULONG64 qwA, _Out_writes_(cb) PBYTE p * read - it's recommended to verify pcbReadOpt parameter. */ EXPORTED_FUNCTION _Success_(return) -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_MemReadEx(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ ULONG64 qwA, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ ULONG64 flags); /* * Prefetch a number of addresses (specified in the pA array) into the memory * cache. This function is to be used to batch larger known reads into local * cache before making multiple smaller reads - which will then happen from * the cache. Function exists for performance reasons. +* -- hVMM * -- dwPID = PID of target process, (DWORD)-1 for physical memory. * -- pPrefetchAddresses = array of addresses to read into cache. * -- cPrefetchAddresses */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_MemPrefetchPages(_In_ DWORD dwPID, _In_reads_(cPrefetchAddresses) PULONG64 pPrefetchAddresses, _In_ DWORD cPrefetchAddresses); +BOOL VMMDLL_MemPrefetchPages(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_reads_(cPrefetchAddresses) PULONG64 pPrefetchAddresses, _In_ DWORD cPrefetchAddresses); /* * Write a contigious arbitrary amount of memory. Please note some virtual memory @@ -739,6 +802,7 @@ BOOL VMMDLL_MemPrefetchPages(_In_ DWORD dwPID, _In_reads_(cPrefetchAddresses) PU * in one process is likely to affect kernel32 in the whole system - in all * processes. Heaps and Stacks and other memory are usually safe to write to. * Please take care when writing to memory! +* -- hVMM * -- dwPID = PID of target process, (DWORD)-1 to read physical memory. * -- qwA * -- pb @@ -746,18 +810,19 @@ BOOL VMMDLL_MemPrefetchPages(_In_ DWORD dwPID, _In_reads_(cPrefetchAddresses) PU * -- return = TRUE on success, FALSE on partial or zero write. */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_MemWrite(_In_ DWORD dwPID, _In_ ULONG64 qwA, _In_reads_(cb) PBYTE pb, _In_ DWORD cb); +BOOL VMMDLL_MemWrite(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ ULONG64 qwA, _In_reads_(cb) PBYTE pb, _In_ DWORD cb); /* * Translate a virtual address to a physical address by walking the page tables * of the specified process. +* -- hVMM * -- dwPID * -- qwVA * -- pqwPA * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_MemVirt2Phys(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PULONG64 pqwPA); +BOOL VMMDLL_MemVirt2Phys(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PULONG64 pqwPA); @@ -784,12 +849,13 @@ typedef HANDLE VMMDLL_SCATTER_HANDLE; /* * Initialize a scatter handle which is used to call VMMDLL_Scatter_* functions. * CALLER CLOSE: VMMDLL_Scatter_CloseHandle(return) +* -- hVMM * -- dwPID - PID of target process, (DWORD)-1 to read physical memory. * -- flags = optional flags as given by VMMDLL_FLAG_* * -- return = handle to be used in VMMDLL_Scatter_* functions. */ EXPORTED_FUNCTION _Success_(return != NULL) -VMMDLL_SCATTER_HANDLE VMMDLL_Scatter_Initialize(_In_ DWORD dwPID, _In_ DWORD flags); +VMMDLL_SCATTER_HANDLE VMMDLL_Scatter_Initialize(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ DWORD flags); /* * Prepare (add) a memory range for reading. The memory may after a call to @@ -898,7 +964,7 @@ VOID VMMDLL_Scatter_CloseHandle(_In_opt_ _Post_ptr_invalid_ VMMDLL_SCATTER_HANDL #define VMMDLL_MAP_HEAP_VERSION 4 #define VMMDLL_MAP_HEAPALLOC_VERSION 1 #define VMMDLL_MAP_THREAD_VERSION 4 -#define VMMDLL_MAP_HANDLE_VERSION 2 +#define VMMDLL_MAP_HANDLE_VERSION 3 #define VMMDLL_MAP_POOL_VERSION 2 #define VMMDLL_MAP_NET_VERSION 3 #define VMMDLL_MAP_PHYSMEM_VERSION 2 @@ -1139,7 +1205,7 @@ typedef struct tdVMMDLL_MAP_HANDLEENTRY { DWORD _FutureUse2; DWORD dwPID; DWORD dwPoolTag; - DWORD _FutureUse[5]; + DWORD _FutureUse[7]; union { LPSTR uszType; LPWSTR wszType; QWORD _Pad1; }; // U/W dependant } VMMDLL_MAP_HANDLEENTRY, *PVMMDLL_MAP_HANDLEENTRY; @@ -1392,173 +1458,165 @@ typedef struct tdVMMDLL_MAP_SERVICE { } VMMDLL_MAP_SERVICE, *PVMMDLL_MAP_SERVICE; /* -* Retrieve the memory map entries based on hardware page tables (PTE) for the -* process. If pPteMap is set to NULL the number of bytes required will be -* returned in parameter pcbPteMap. +* Retrieve the memory map entries based on hardware page tables (PTEs) for the process. * Entries returned are sorted on VMMDLL_MAP_PTEENTRY.va +* CALLER FREE: VMMDLL_MemFree(*ppVadMap) +* -- hVMM * -- dwPID -* -- pPteMap = buffer of minimum byte length *pcbPteMap or NULL. -* -- pcbPteMap = pointer to byte count of pPteMap buffer. * -- fIdentifyModules = try identify modules as well (= slower) +* -- ppPteMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetPteU(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbPteMap) PVMMDLL_MAP_PTE pPteMap, _Inout_ PDWORD pcbPteMap, _In_ BOOL fIdentifyModules); -_Success_(return) BOOL VMMDLL_Map_GetPteW(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbPteMap) PVMMDLL_MAP_PTE pPteMap, _Inout_ PDWORD pcbPteMap, _In_ BOOL fIdentifyModules); +_Success_(return) BOOL VMMDLL_Map_GetPteU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ BOOL fIdentifyModules, _Out_ PVMMDLL_MAP_PTE *ppPteMap); +_Success_(return) BOOL VMMDLL_Map_GetPteW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ BOOL fIdentifyModules, _Out_ PVMMDLL_MAP_PTE *ppPteMap); /* -* Retrieve memory map entries based on virtual address descriptor (VAD) for -* the process. If pVadMap is set to NULL the number of bytes required -* will be returned in parameter pcbVadMap. +* Retrieve memory map entries based on virtual address descriptor (VAD) for the process. * Entries returned are sorted on VMMDLL_MAP_VADENTRY.vaStart +* CALLER FREE: VMMDLL_MemFree(*ppVadMap) +* -- hVMM * -- dwPID -* -- pVadMap = buffer of minimum byte length *pcbVadMap or NULL. -* -- pcbVadMap = pointer to byte count of pVadMap buffer. * -- fIdentifyModules = try identify modules as well (= slower) +* -- ppVadMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetVadU(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbVadMap) PVMMDLL_MAP_VAD pVadMap, _Inout_ PDWORD pcbVadMap, _In_ BOOL fIdentifyModules); -_Success_(return) BOOL VMMDLL_Map_GetVadW(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbVadMap) PVMMDLL_MAP_VAD pVadMap, _Inout_ PDWORD pcbVadMap, _In_ BOOL fIdentifyModules); +_Success_(return) BOOL VMMDLL_Map_GetVadU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ BOOL fIdentifyModules, _Out_ PVMMDLL_MAP_VAD *ppVadMap); +_Success_(return) BOOL VMMDLL_Map_GetVadW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ BOOL fIdentifyModules, _Out_ PVMMDLL_MAP_VAD *ppVadMap); /* -* Retrieve extended memory map information about a select sub-set of the memory -* map. If pVadExMap is set to NULL the number of bytes required will be -* returned in the parameter pcbVadExMap. -* -- dwPID -* -- pVadExMap = buffer of minimum byte length *pcbVadExMap or NULL. -* -- pcbVadExMap = pointer to byte count of pVadExMap buffer. +* Retrieve extended memory map information about a sub-set of the memory map. +* CALLER FREE: VMMDLL_MemFree(*ppVadExMap) +* -- hVMM * -- oPage = offset in number of pages from process start. * -- cPage = number of pages to process from oPages base. +* -- ppVadExMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) -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_GetVadEx(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ DWORD oPage, _In_ DWORD cPage, _Out_ PVMMDLL_MAP_VADEX *ppVadExMap); /* -* Retrieve the modules (.dlls) for the specified process. If pModuleMap is set -* to NULL the number of bytes required will be returned in parameter pcbModuleMap. +* Retrieve the modules (.dlls) for the specified process. +* CALLER FREE: VMMDLL_MemFree(*ppModuleMap) +* -- hVMM * -- dwPID -* -- pModuleMap = buffer of minimum byte length *pcbModuleMap or NULL. -* -- pcbModuleMap = pointer to byte count of pModuleMap buffer. +* -- ppModuleMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetModuleU(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbModuleMap) PVMMDLL_MAP_MODULE pModuleMap, _Inout_ PDWORD pcbModuleMap); -_Success_(return) BOOL VMMDLL_Map_GetModuleW(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbModuleMap) PVMMDLL_MAP_MODULE pModuleMap, _Inout_ PDWORD pcbModuleMap); +_Success_(return) BOOL VMMDLL_Map_GetModuleU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_MODULE *ppModuleMap); +_Success_(return) BOOL VMMDLL_Map_GetModuleW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_MODULE *ppModuleMap); /* * Retrieve a module (.dll) entry given a process and module name. -* If pModuleMapEntry is set to NULL the number of bytes required -* will be returned in parameter pcbModuleMapEntry. -* If pcbModuleMapEntry is set to NULL the pModuleMapEntry is assumed to be of -* size sizeof(VMMDLL_MAP_MODULEENTRY) and data without names will be copied. +* CALLER FREE: VMMDLL_MemFree(*ppModuleMapEntry) +* -- hVMM * -- dwPID * -- [uw]szModuleName = module name (or ""/NULL for 1st module entry). -* -- pModuleMapEntry = buffer of minimum byte length *pcbModuleMapEntry or NULL. -* -- pcbModuleMapEntry = pointer to byte count of pModuleMapEntry buffer or NULL. +* -- ppModuleMapEntry = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetModuleFromNameU(_In_ DWORD dwPID, _In_opt_ LPSTR uszModuleName, _Out_writes_bytes_opt_(*pcbModuleMapEntry) PVMMDLL_MAP_MODULEENTRY pModuleMapEntry, _Inout_opt_ PDWORD pcbModuleMapEntry); -_Success_(return) BOOL VMMDLL_Map_GetModuleFromNameW(_In_ DWORD dwPID, _In_opt_ LPWSTR wszModuleName, _Out_writes_bytes_opt_(*pcbModuleMapEntry) PVMMDLL_MAP_MODULEENTRY pModuleMapEntry, _Inout_opt_ PDWORD pcbModuleMapEntry); +_Success_(return) BOOL VMMDLL_Map_GetModuleFromNameU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_opt_ LPSTR uszModuleName, _Out_ PVMMDLL_MAP_MODULEENTRY *ppModuleMapEntry); +_Success_(return) BOOL VMMDLL_Map_GetModuleFromNameW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_opt_ LPWSTR wszModuleName, _Out_ PVMMDLL_MAP_MODULEENTRY *ppModuleMapEntry); /* -* Retrieve the unloaded modules (.dll/.sys) for the specified process. If -* pUnloadedModuleMap is set to NULL the number of bytes required will be -* returned in parameter pcbUnloadedModuleMap. +* Retrieve the unloaded modules (.dll/.sys) for the specified process. +* CALLER FREE: VMMDLL_MemFree(*ppUnloadedModuleMap) +* -- hVMM * -- dwPID -* -- pUnloadedModuleMap = buffer of minimum byte length *pcbUnloadedModuleMap or NULL. -* -- pcbUnloadedModuleMap = pointer to byte count of pUnloadedModuleMap buffer. +* -- ppUnloadedModuleMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetUnloadedModuleU(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbUnloadedModuleMap) PVMMDLL_MAP_UNLOADEDMODULE pUnloadedModuleMap, _Inout_ PDWORD pcbUnloadedModuleMap); -_Success_(return) BOOL VMMDLL_Map_GetUnloadedModuleW(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbUnloadedModuleMap) PVMMDLL_MAP_UNLOADEDMODULE pUnloadedModuleMap, _Inout_ PDWORD pcbUnloadedModuleMap); +_Success_(return) BOOL VMMDLL_Map_GetUnloadedModuleU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_UNLOADEDMODULE *ppUnloadedModuleMap); +_Success_(return) BOOL VMMDLL_Map_GetUnloadedModuleW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_UNLOADEDMODULE *ppUnloadedModuleMap); /* * Retrieve the module exported functions from the export address table (EAT). -* If pEatMap is set to NULL the number of bytes required will be returned in -* parameter pcbEatMap. +* CALLER FREE: VMMDLL_MemFree(*ppEatMap) +* -- hVMM * -- dwPID * -- [uw]szModuleName -* -- pEatMap = buffer of minimum byte length *pcbEatMap or NULL. -* -- pcbEatMap = pointer to byte count of pEatMap buffer. +* -- ppEatMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetEATU(_In_ DWORD dwPID, _In_ LPSTR uszModuleName, _Out_writes_bytes_opt_(*pcbEatMap) PVMMDLL_MAP_EAT pEatMap, _Inout_ PDWORD pcbEatMap); -_Success_(return) BOOL VMMDLL_Map_GetEATW(_In_ DWORD dwPID, _In_ LPWSTR wszModuleName, _Out_writes_bytes_opt_(*pcbEatMap) PVMMDLL_MAP_EAT pEatMap, _Inout_ PDWORD pcbEatMap); +_Success_(return) BOOL VMMDLL_Map_GetEATU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPSTR uszModuleName, _Out_ PVMMDLL_MAP_EAT *ppEatMap); +_Success_(return) BOOL VMMDLL_Map_GetEATW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPWSTR wszModuleName, _Out_ PVMMDLL_MAP_EAT *ppEatMap); /* * Retrieve the module imported functions from the import address table (IAT). -* If pIatMap is set to NULL the number of bytes required will be returned in -* parameter pcbIatMap. +* CALLER FREE: VMMDLL_MemFree(*ppIatMap) +* -- hVMM * -- dwPID * -- [uw]szModuleName -* -- pIatMap = buffer of minimum byte length *pcbIatMap or NULL. -* -- pcbIatMap = pointer to byte count of pIatMap buffer. +* -- ppIatMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetIATU(_In_ DWORD dwPID, _In_ LPSTR uszModuleName, _Out_writes_bytes_opt_(*pcbIatMap) PVMMDLL_MAP_IAT pIatMap, _Inout_ PDWORD pcbIatMap); -_Success_(return) BOOL VMMDLL_Map_GetIATW(_In_ DWORD dwPID, _In_ LPWSTR wszModuleName, _Out_writes_bytes_opt_(*pcbIatMap) PVMMDLL_MAP_IAT pIatMap, _Inout_ PDWORD pcbIatMap); +_Success_(return) BOOL VMMDLL_Map_GetIATU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPSTR uszModuleName, _Out_ PVMMDLL_MAP_IAT *ppIatMap); +_Success_(return) BOOL VMMDLL_Map_GetIATW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPWSTR wszModuleName, _Out_ PVMMDLL_MAP_IAT *ppIatMap); /* * Retrieve the heaps for the specified process. -* CALLER VMMDLL_MemFree: *ppHeapMap +* CALLER FREE: VMMDLL_MemFree(*ppHeapMap) +* -- hVMM * -- dwPID * -- ppHeapMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetHeapEx(_In_ DWORD dwPID, _Out_ PVMMDLL_MAP_HEAP *ppHeapMap); +_Success_(return) BOOL VMMDLL_Map_GetHeap(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_HEAP *ppHeapMap); /* * Retrieve heap allocations for the specified process heap. -* CALLER VMMDLL_MemFree: *ppHeapAllocMap +* CALLER FREE: VMMDLL_MemFree(*ppHeapAllocMap) +* -- hVMM * -- dwPID * -- qwHeapNumOrAddress = number or virtual address of heap to retrieve allocations from. * -- ppHeapAllocMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetHeapAllocEx(_In_ DWORD dwPID, _In_ QWORD qwHeapNumOrAddress, _Out_ PVMMDLL_MAP_HEAPALLOC *ppHeapAllocMap); +_Success_(return) BOOL VMMDLL_Map_GetHeapAlloc(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ QWORD qwHeapNumOrAddress, _Out_ PVMMDLL_MAP_HEAPALLOC *ppHeapAllocMap); /* -* Retrieve the threads for the specified process. If pThreadMap is set to NULL -* the number of bytes required will be returned in parameter pcbThreadMap. +* Retrieve the threads for the specified process. * Entries returned are sorted on VMMDLL_MAP_THREADENTRY.dwTID +* CALLER FREE: VMMDLL_MemFree(*ppThreadMap) +* -- hVMM * -- dwPID -* -- pThreadMap = buffer of minimum byte length *pcbThreadMap or NULL. -* -- pcbThreadMap = pointer to byte count of pThreadMap buffer. +* -- ppThreadMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetThread(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbThreadMap) PVMMDLL_MAP_THREAD pThreadMap, _Inout_ PDWORD pcbThreadMap); +_Success_(return) BOOL VMMDLL_Map_GetThread(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_THREAD *ppThreadMap); /* -* Retrieve the handles for the specified process. If pHandleMap is set to NULL -* the number of bytes required will be returned in parameter pcbHandleMap. +* Retrieve the handles for the specified process. * Entries returned are sorted on VMMDLL_MAP_HANDLEENTRY.dwHandle +* CALLER FREE: VMMDLL_MemFree(*ppHandleMap) +* -- hVMM * -- dwPID -* -- pHandleMap = buffer of minimum byte length *pcbHandleMap or NULL. -* -- pcbHandleMap = pointer to byte count of pHandleMap buffer. +* -- ppHandleMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetHandleU(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbHandleMap) PVMMDLL_MAP_HANDLE pHandleMap, _Inout_ PDWORD pcbHandleMap); -_Success_(return) BOOL VMMDLL_Map_GetHandleW(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbHandleMap) PVMMDLL_MAP_HANDLE pHandleMap, _Inout_ PDWORD pcbHandleMap); +_Success_(return) BOOL VMMDLL_Map_GetHandleU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_HANDLE *ppHandleMap); +_Success_(return) BOOL VMMDLL_Map_GetHandleW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_HANDLE *ppHandleMap); /* -* Retrieve the physical memory ranges from the physical memory map that Windows -* have enumerated. -* -- pPhysMemMap = buffer of minimum byte length *pcbPhysMemMap or NULL. -* -- pcbPhysMemMap = pointer to byte count of pPhysMemMap buffer. +* Retrieve the physical memory ranges from the operating system physical memory map. +* CALLER FREE: VMMDLL_MemFree(*ppPhysMemMap) +* -- hVMM +* -- ppPhysMemMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree() * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetPhysMem(_Out_writes_bytes_opt_(*pcbPhysMemMap) PVMMDLL_MAP_PHYSMEM pPhysMemMap, _Inout_ PDWORD pcbPhysMemMap); +_Success_(return) BOOL VMMDLL_Map_GetPhysMem(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_PHYSMEM *ppPhysMemMap); /* * Retrieve the pool map - consisting of kernel allocated pool entries. @@ -1568,62 +1626,51 @@ _Success_(return) BOOL VMMDLL_Map_GetPhysMem(_Out_writes_bytes_opt_(*pcbPhysMemM * NB! The pool map relies on debug symbols. Please ensure supporting files * symsrv.dll, dbghelp.dll and info.db (found in the binary distribution) * is put alongside vmm.dll. (On Linux the .dll files aren't necessary). -* -- pPoolMap = buffer of minimum byte length *pcbPoolMap or NULL. -* -- pcbPoolMap = pointer to byte count of pPoolMap buffer. -* -- return = success/fail. -*/ -EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetPool(_Out_writes_bytes_opt_(*pcbPoolMap) PVMMDLL_MAP_POOL pPoolMap, _Inout_ PDWORD pcbPoolMap); - -/* -* Retrieve the pool map - consisting of kernel allocated pool entries. -* The pool map pMap is sorted by allocation virtual address. -* The pool map pTag is sorted by pool tag. -* NB! The pool map may contain both false negatives/positives. -* NB! The pool map relies on debug symbols. Please ensure supporting files -* symsrv.dll, dbghelp.dll and info.db (found in the binary distribution) -* is put alongside vmm.dll. (On Linux the .dll files aren't necessary). -* CALLER VMMDLL_MemFree: *ppPoolMap +* CALLER FREE: VMMDLL_MemFree(*ppPoolMap) +* -- hVMM * -- ppPoolMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- flags = VMMDLL_POOLMAP_FLAG* * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetPoolEx(_Out_ PVMMDLL_MAP_POOL* ppPoolMap, _In_ DWORD flags); +_Success_(return) BOOL VMMDLL_Map_GetPool(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_POOL *ppPoolMap, _In_ DWORD flags); /* * Retrieve the network connection map - consisting of active network connections, * listening sockets and other networking functionality. -* -- pNetMap = buffer of minimum byte length *pcbNetMap or NULL. -* -- pcbNetMap = pointer to byte count of pNetMap buffer. +* CALLER FREE: VMMDLL_MemFree(*ppNetMap) +* -- hVMM +* -- ppNetMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetNetU(_Out_writes_bytes_opt_(*pcbNetMap) PVMMDLL_MAP_NET pNetMap, _Inout_ PDWORD pcbNetMap); -_Success_(return) BOOL VMMDLL_Map_GetNetW(_Out_writes_bytes_opt_(*pcbNetMap) PVMMDLL_MAP_NET pNetMap, _Inout_ PDWORD pcbNetMap); +_Success_(return) BOOL VMMDLL_Map_GetNetU(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_NET *ppNetMap); +_Success_(return) BOOL VMMDLL_Map_GetNetW(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_NET *ppNetMap); /* * Retrieve the non well known users that are detected in the target system. * NB! There may be more users in the system than the ones that are detected, * only users with mounted registry hives may currently be detected - this is * the normal behaviour for users with active processes. -* -- pUserMap = buffer of minimum byte length *pcbUserMap or NULL. -* -- pcbUserMap = pointer to byte count of pUserMap buffer. +* CALLER FREE: VMMDLL_MemFree(*ppUserMap) +* -- hVMM +* -- ppUserMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetUsersU(_Out_writes_bytes_opt_(*pcbUserMap) PVMMDLL_MAP_USER pUserMap, _Inout_ PDWORD pcbUserMap); -_Success_(return) BOOL VMMDLL_Map_GetUsersW(_Out_writes_bytes_opt_(*pcbUserMap) PVMMDLL_MAP_USER pUserMap, _Inout_ PDWORD pcbUserMap); +_Success_(return) BOOL VMMDLL_Map_GetUsersU(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_USER *ppUserMap); +_Success_(return) BOOL VMMDLL_Map_GetUsersW(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_USER *ppUserMap); /* * Retrieve the services currently known by the service control manager (SCM). -* -- pServiceMap = buffer of minimum byte length *pcbServiceMap or NULL. -* -- pcbServiceMap = pointer to byte count of pServiceMap buffer. +* CALLER FREE: VMMDLL_MemFree(*ppServiceMap) +* -- hVMM +* -- ppServiceMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetServicesU(_Out_writes_bytes_opt_(*pcbServiceMap) PVMMDLL_MAP_SERVICE pServiceMap, _Inout_ PDWORD pcbServiceMap); -_Success_(return) BOOL VMMDLL_Map_GetServicesW(_Out_writes_bytes_opt_(*pcbServiceMap) PVMMDLL_MAP_SERVICE pServiceMap, _Inout_ PDWORD pcbServiceMap); +_Success_(return) BOOL VMMDLL_Map_GetServicesU(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_SERVICE *ppServiceMap); +_Success_(return) BOOL VMMDLL_Map_GetServicesW(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_SERVICE *ppServiceMap); @@ -1680,6 +1727,7 @@ typedef struct tdVMMDLL_MEM_SEARCH_CONTEXT { * To cancel a search prematurely set the fAbortRequested flag in the context * and wait a short while. * CALLER FREE: VMMDLL_MemFree(*ppva) +* -- hVMM * -- dwPID * -- ctx * -- ppva = pointer to receive addresses found. Free'd with VMMDLL_MemFree(). @@ -1687,7 +1735,13 @@ typedef struct tdVMMDLL_MEM_SEARCH_CONTEXT { * -- return */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_MemSearch(_In_ DWORD dwPID, _Inout_ PVMMDLL_MEM_SEARCH_CONTEXT ctx, _Out_opt_ PQWORD *ppva, _Out_opt_ PDWORD pcva); +BOOL VMMDLL_MemSearch( + _In_ VMM_HANDLE hVMM, + _In_ DWORD dwPID, + _Inout_ PVMMDLL_MEM_SEARCH_CONTEXT ctx, + _Out_opt_ PQWORD *ppva, + _Out_opt_ PDWORD pcva +); @@ -1775,6 +1829,7 @@ typedef struct tdVMMDLL_MAP_PFN { /* * Retrieve information about scattered PFNs. The PFNs are returned in order of * in which they are stored in the pPfns set. +* -- hVMM * -- pPfns * -- cPfns * -- pPfnMap = buffer of minimum byte length *pcbPfnMap or NULL. @@ -1782,7 +1837,13 @@ typedef struct tdVMMDLL_MAP_PFN { * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) -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_GetPfn( + _In_ VMM_HANDLE hVMM, + _In_ DWORD pPfns[], + _In_ DWORD cPfns, + _Out_writes_bytes_opt_(*pcbPfnMap) PVMMDLL_MAP_PFN pPfnMap, + _Inout_ PDWORD pcbPfnMap +); @@ -1796,21 +1857,23 @@ BOOL VMMDLL_Map_GetPfn(_In_ DWORD pPfns[], _In_ DWORD cPfns, _Out_writes_bytes_o * processes with the same name exists only one will be returned. If required to * parse all processes with the same name please iterate over the PID list by * calling VMMDLL_PidList together with VMMDLL_ProcessGetInformation. +* -- hVMM * -- szProcName = process name case insensitive. * -- pdwPID = pointer that will receive PID on success. * -- return */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_PidGetFromName(_In_ LPSTR szProcName, _Out_ PDWORD pdwPID); +BOOL VMMDLL_PidGetFromName(_In_ VMM_HANDLE hVMM, _In_ LPSTR szProcName, _Out_ PDWORD pdwPID); /* * List the PIDs in the system. +* -- hVMM * -- pPIDs = DWORD array of at least number of PIDs in system, or NULL. * -- pcPIDs = size of (in number of DWORDs) pPIDs array on entry, number of PIDs in system on exit. * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_PidList(_Out_writes_opt_(*pcPIDs) PDWORD pPIDs, _Inout_ PULONG64 pcPIDs); +BOOL VMMDLL_PidList(_In_ VMM_HANDLE hVMM, _Out_writes_opt_(*pcPIDs) PDWORD pPIDs, _Inout_ PSIZE_T pcPIDs); #define VMMDLL_PROCESS_INFORMATION_MAGIC 0xc0ffee663df9301e #define VMMDLL_PROCESS_INFORMATION_VERSION 7 @@ -1856,13 +1919,19 @@ typedef struct tdVMMDLL_PROCESS_INFORMATION { /* * Retrieve various process information from a PID. Process information such as * name, page directory bases and the process state may be retrieved. +* -- hVMM * -- dwPID * -- pProcessInformation = if null, size is given in *pcbProcessInfo * -- pcbProcessInformation = size of pProcessInfo (in bytes) on entry and exit * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_ProcessGetInformation(_In_ DWORD dwPID, _Inout_opt_ PVMMDLL_PROCESS_INFORMATION pProcessInformation, _In_ PSIZE_T pcbProcessInformation); +BOOL VMMDLL_ProcessGetInformation( + _In_ VMM_HANDLE hVMM, + _In_ DWORD dwPID, + _Inout_opt_ PVMMDLL_PROCESS_INFORMATION pProcessInformation, + _In_ PSIZE_T pcbProcessInformation +); #define VMMDLL_PROCESS_INFORMATION_OPT_STRING_PATH_KERNEL 1 #define VMMDLL_PROCESS_INFORMATION_OPT_STRING_PATH_USER_IMAGE 2 @@ -1874,18 +1943,20 @@ BOOL VMMDLL_ProcessGetInformation(_In_ DWORD dwPID, _Inout_opt_ PVMMDLL_PROCESS_ * NULL terminated. On failure NULL is returned. * NB! CALLER IS RESPONSIBLE FOR VMMDLL_MemFree return value! * CALLER FREE: VMMDLL_MemFree(return) +* -- hVMM * -- dwPID * -- fOptionString = string value to retrieve as given by VMMDLL_PROCESS_INFORMATION_OPT_STRING_* * -- return - fail: NULL, success: the string - NB! must be VMMDLL_MemFree'd by caller! */ -EXPORTED_FUNCTION -LPSTR VMMDLL_ProcessGetInformationString(_In_ DWORD dwPID, _In_ DWORD fOptionString); +EXPORTED_FUNCTION _Success_(return != NULL) +LPSTR VMMDLL_ProcessGetInformationString(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ DWORD fOptionString); /* * Retrieve information about: Data Directories, Sections, Export Address Table * and Import Address Table (IAT). * If the pData == NULL upon entry the number of entries of the pData array must * have in order to be able to hold the data is returned. +* -- hVMM * -- dwPID * -- [uw]szModule * -- pData @@ -1894,32 +1965,34 @@ LPSTR VMMDLL_ProcessGetInformationString(_In_ DWORD dwPID, _In_ DWORD fOptionStr * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_ProcessGetDirectoriesU(_In_ DWORD dwPID, _In_ LPSTR uszModule, _Out_writes_(16) PIMAGE_DATA_DIRECTORY pData, _In_ DWORD cData, _Out_ PDWORD pcData); -_Success_(return) BOOL VMMDLL_ProcessGetDirectoriesW(_In_ DWORD dwPID, _In_ LPWSTR wszModule, _Out_writes_(16) PIMAGE_DATA_DIRECTORY pData, _In_ DWORD cData, _Out_ PDWORD pcData); +_Success_(return) BOOL VMMDLL_ProcessGetDirectoriesU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPSTR uszModule, _Out_writes_(16) PIMAGE_DATA_DIRECTORY pDataDirectories); +_Success_(return) BOOL VMMDLL_ProcessGetDirectoriesW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPWSTR wszModule, _Out_writes_(16) PIMAGE_DATA_DIRECTORY pDataDirectories); EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_ProcessGetSectionsU(_In_ DWORD dwPID, _In_ LPSTR uszModule, _Out_opt_ PIMAGE_SECTION_HEADER pData, _In_ DWORD cData, _Out_ PDWORD pcData); -_Success_(return) BOOL VMMDLL_ProcessGetSectionsW(_In_ DWORD dwPID, _In_ LPWSTR wszModule, _Out_opt_ PIMAGE_SECTION_HEADER pData, _In_ DWORD cData, _Out_ PDWORD pcData); +_Success_(return) BOOL VMMDLL_ProcessGetSectionsU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPSTR uszModule, _Out_writes_opt_(cSections) PIMAGE_SECTION_HEADER pSections, _In_ DWORD cSections, _Out_ PDWORD pcSections); +_Success_(return) BOOL VMMDLL_ProcessGetSectionsW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPWSTR wszModule, _Out_writes_opt_(cSections) PIMAGE_SECTION_HEADER pSections, _In_ DWORD cSections, _Out_ PDWORD pcSections); /* * Retrieve the virtual address of a given function inside a process/module. +* -- hVMM * -- dwPID * -- [uw]szModuleName * -- szFunctionName * -- return = virtual address of function, zero on fail. */ EXPORTED_FUNCTION -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_ProcessGetProcAddressU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPSTR uszModuleName, _In_ LPSTR szFunctionName); +ULONG64 VMMDLL_ProcessGetProcAddressW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPWSTR wszModuleName, _In_ LPSTR szFunctionName); /* * Retrieve the base address of a given module. +* -- hVMM * -- dwPID * -- [uw]szModuleName * -- return = virtual address of module base, zero on fail. */ EXPORTED_FUNCTION -ULONG64 VMMDLL_ProcessGetModuleBaseU(_In_ DWORD dwPID, _In_ LPSTR uszModuleName); -ULONG64 VMMDLL_ProcessGetModuleBaseW(_In_ DWORD dwPID, _In_ LPWSTR wszModuleName); +ULONG64 VMMDLL_ProcessGetModuleBaseU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPSTR uszModuleName); +ULONG64 VMMDLL_ProcessGetModuleBaseW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPWSTR wszModuleName); @@ -1929,18 +2002,25 @@ ULONG64 VMMDLL_ProcessGetModuleBaseW(_In_ DWORD dwPID, _In_ LPWSTR wszModuleName /* * Load a .pdb symbol file and return its associated module name upon success. +* -- hVMM * -- dwPID * -- vaModuleBase * -- szModuleName = buffer to receive module name upon success. * -- return */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_PdbLoad(_In_ DWORD dwPID, _In_ ULONG64 vaModuleBase, _Out_writes_(MAX_PATH) LPSTR szModuleName); +BOOL VMMDLL_PdbLoad( + _In_ VMM_HANDLE hVMM, + _In_ DWORD dwPID, + _In_ ULONG64 vaModuleBase, + _Out_writes_(MAX_PATH) LPSTR szModuleName +); /* * Retrieve a symbol virtual address given a module name and a symbol name. * NB! not all modules may exist - initially only module "nt" is available. * NB! if multiple modules have the same name the 1st to be added will be used. +* -- hVMM * -- szModule * -- cbSymbolAddressOrOffset = symbol virtual address or symbol offset. * -- szSymbolName = buffer to receive symbol name upon success. @@ -1948,36 +2028,55 @@ BOOL VMMDLL_PdbLoad(_In_ DWORD dwPID, _In_ ULONG64 vaModuleBase, _Out_writes_(MA * -- return */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_PdbSymbolName(_In_ LPSTR szModule, _In_ QWORD cbSymbolAddressOrOffset, _Out_writes_(MAX_PATH) LPSTR szSymbolName, _Out_opt_ PDWORD pdwSymbolDisplacement); +BOOL VMMDLL_PdbSymbolName( + _In_ VMM_HANDLE hVMM, + _In_ LPSTR szModule, + _In_ QWORD cbSymbolAddressOrOffset, + _Out_writes_(MAX_PATH) LPSTR szSymbolName, + _Out_opt_ PDWORD pdwSymbolDisplacement +); /* * Retrieve a symbol virtual address given a module name and a symbol name. * NB! not all modules may exist - initially only module "nt" is available. * NB! if multiple modules have the same name the 1st to be added will be used. +* -- hVMM * -- szModule * -- szSymbolName * -- pvaSymbolAddress * -- return */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_PdbSymbolAddress(_In_ LPSTR szModule, _In_ LPSTR szSymbolName, _Out_ PULONG64 pvaSymbolAddress); +BOOL VMMDLL_PdbSymbolAddress( + _In_ VMM_HANDLE hVMM, + _In_ LPSTR szModule, + _In_ LPSTR szSymbolName, + _Out_ PULONG64 pvaSymbolAddress +); /* * Retrieve a type size given a module name and a type name. * NB! not all modules may exist - initially only module "nt" is available. * NB! if multiple modules have the same name the 1st to be added will be used. +* -- hVMM * -- szModule * -- szTypeName * -- pcbTypeSize * -- return */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_PdbTypeSize(_In_ LPSTR szModule, _In_ LPSTR szTypeName, _Out_ PDWORD pcbTypeSize); +BOOL VMMDLL_PdbTypeSize( + _In_ VMM_HANDLE hVMM, + _In_ LPSTR szModule, + _In_ LPSTR szTypeName, + _Out_ PDWORD pcbTypeSize +); /* * Locate the offset of a type child - typically a sub-item inside a struct. * NB! not all modules may exist - initially only module "nt" is available. * NB! if multiple modules have the same name the 1st to be added will be used. +* -- hVMM * -- szModule * -- uszTypeName * -- uszTypeChildName @@ -1985,7 +2084,13 @@ BOOL VMMDLL_PdbTypeSize(_In_ LPSTR szModule, _In_ LPSTR szTypeName, _Out_ PDWORD * -- return */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_PdbTypeChildOffset(_In_ LPSTR szModule, _In_ LPSTR uszTypeName, _In_ LPSTR uszTypeChildName, _Out_ PDWORD pcbTypeChildOffset); +BOOL VMMDLL_PdbTypeChildOffset( + _In_ VMM_HANDLE hVMM, + _In_ LPSTR szModule, + _In_ LPSTR uszTypeName, + _In_ LPSTR uszTypeChildName, + _Out_ PDWORD pcbTypeChildOffset +); @@ -1994,13 +2099,13 @@ BOOL VMMDLL_PdbTypeChildOffset(_In_ LPSTR szModule, _In_ LPSTR uszTypeName, _In_ //----------------------------------------------------------------------------- #define VMMDLL_REGISTRY_HIVE_INFORMATION_MAGIC 0xc0ffee653df8d01e -#define VMMDLL_REGISTRY_HIVE_INFORMATION_VERSION 3 +#define VMMDLL_REGISTRY_HIVE_INFORMATION_VERSION 4 typedef struct td_VMMDLL_REGISTRY_HIVE_INFORMATION { ULONG64 magic; WORD wVersion; WORD wSize; - BYTE _FutureReserved1[0x14]; + BYTE _FutureReserved1[0x34]; ULONG64 vaCMHIVE; ULONG64 vaHBASE_BLOCK; DWORD cbLength; @@ -2012,18 +2117,25 @@ typedef struct td_VMMDLL_REGISTRY_HIVE_INFORMATION { /* * Retrieve information about the registry hives in the target system. -* -- pHives = buffer of cHives * sizeof(VMMDLL_REGISTRY_HIVE_INFORMATION) to receive information about all hives. NULL to receive # hives in pcHives. +* -- pHives = buffer of cHives * sizeof(VMMDLL_REGISTRY_HIVE_INFORMATION) to + receive info about all hives. NULL to receive # hives in pcHives. * -- cHives * -- pcHives = if pHives == NULL: # total hives. if pHives: # read hives. * -- return */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_WinReg_HiveList(_Out_writes_(cHives) PVMMDLL_REGISTRY_HIVE_INFORMATION pHives, _In_ DWORD cHives, _Out_ PDWORD pcHives); +BOOL VMMDLL_WinReg_HiveList( + _In_ VMM_HANDLE hVMM, + _Out_writes_(cHives) PVMMDLL_REGISTRY_HIVE_INFORMATION pHives, + _In_ DWORD cHives, + _Out_ PDWORD pcHives +); /* * Read a contigious arbitrary amount of registry hive memory and report the * number of bytes read in pcbRead. * NB! Address space does not include regf registry hive file header! +* -- hVMM * -- vaCMHive * -- ra * -- pb @@ -2034,11 +2146,20 @@ BOOL VMMDLL_WinReg_HiveList(_Out_writes_(cHives) PVMMDLL_REGISTRY_HIVE_INFORMATI * read - it's recommended to verify pcbReadOpt parameter. */ EXPORTED_FUNCTION _Success_(return) -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_HiveReadEx( + _In_ VMM_HANDLE hVMM, + _In_ ULONG64 vaCMHive, + _In_ DWORD ra, + _Out_ PBYTE pb, + _In_ DWORD cb, + _Out_opt_ PDWORD pcbReadOpt, + _In_ ULONG64 flags +); /* * Write a virtually contigious arbitrary amount of memory to a registry hive. * NB! Address space does not include regf registry hive file header! +* -- hVMM * -- vaCMHive * -- ra * -- pb @@ -2046,7 +2167,13 @@ BOOL VMMDLL_WinReg_HiveReadEx(_In_ ULONG64 vaCMHive, _In_ DWORD ra, _Out_ PBYTE * -- return = TRUE on success, FALSE on partial or zero write. */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_WinReg_HiveWrite(_In_ ULONG64 vaCMHive, _In_ DWORD ra, _In_ PBYTE pb, _In_ DWORD cb); +BOOL VMMDLL_WinReg_HiveWrite( + _In_ VMM_HANDLE hVMM, + _In_ ULONG64 vaCMHive, + _In_ DWORD ra, + _In_ PBYTE pb, + _In_ DWORD cb +); /* * Enumerate registry sub keys - similar to WINAPI function 'RegEnumKeyExW.' @@ -2056,6 +2183,7 @@ BOOL VMMDLL_WinReg_HiveWrite(_In_ ULONG64 vaCMHive, _In_ DWORD ra, _In_ PBYTE pb * 2) 'HKLM\ORPHAN\SAM\Key\SubKey' (orphan key) * 3) '0x\ROOT\Key\SubKey' * 4) '0x\ORPHAN\Key\SubKey' (orphan key) +* -- hVMM * -- uszFullPathKey * -- dwIndex = sub-key index 0..N (-1 for key). * -- lpName @@ -2065,6 +2193,7 @@ BOOL VMMDLL_WinReg_HiveWrite(_In_ ULONG64 vaCMHive, _In_ DWORD ra, _In_ PBYTE pb */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_WinReg_EnumKeyExU( + _In_ VMM_HANDLE hVMM, _In_ LPSTR uszFullPathKey, _In_ DWORD dwIndex, _Out_writes_opt_(*lpcchName) LPSTR lpName, @@ -2081,6 +2210,7 @@ BOOL VMMDLL_WinReg_EnumKeyExU( * 2) 'HKLM\ORPHAN\SAM\Key\SubKey' (orphan key) * 3) '0x\ROOT\Key\SubKey' * 4) '0x\ORPHAN\Key\SubKey' (orphan key) +* -- hVMM * -- uszFullPathKey * -- dwIndex * -- lpValueName @@ -2092,6 +2222,7 @@ BOOL VMMDLL_WinReg_EnumKeyExU( */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_WinReg_EnumValueU( + _In_ VMM_HANDLE hVMM, _In_ LPSTR uszFullPathKey, _In_ DWORD dwIndex, _Out_writes_opt_(*lpcchValueName) LPSTR lpValueName, @@ -2110,6 +2241,7 @@ BOOL VMMDLL_WinReg_EnumValueU( * 2) 'HKLM\ORPHAN\SAM\Key\SubKey\' (orphan key and default value) * 3) '0x\ROOT\Key\SubKey\Value' * 4) '0x\ORPHAN\Key\SubKey\Value' (orphan key value) +* -- hVMM * -- uszFullPathKeyValue * -- lpType * -- lpData @@ -2118,6 +2250,7 @@ BOOL VMMDLL_WinReg_EnumValueU( */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_WinReg_QueryValueExU( + _In_ VMM_HANDLE hVMM, _In_ LPSTR uszFullPathKeyValue, _Out_opt_ LPDWORD lpType, _Out_writes_opt_(*lpcbData) LPBYTE lpData, @@ -2132,6 +2265,7 @@ BOOL VMMDLL_WinReg_QueryValueExU( * 2) 'HKLM\ORPHAN\SAM\Key\SubKey' (orphan key) * 3) '0x\ROOT\Key\SubKey' * 4) '0x\ORPHAN\Key\SubKey' (orphan key) +* -- hVMM * -- wszFullPathKey * -- dwIndex = sub-key index 0..N (-1 for key). * -- lpName @@ -2141,6 +2275,7 @@ BOOL VMMDLL_WinReg_QueryValueExU( */ _Success_(return) BOOL VMMDLL_WinReg_EnumKeyExW( + _In_ VMM_HANDLE hVMM, _In_ LPWSTR wszFullPathKey, _In_ DWORD dwIndex, _Out_writes_opt_(*lpcchName) LPWSTR lpName, @@ -2157,6 +2292,7 @@ BOOL VMMDLL_WinReg_EnumKeyExW( * 2) 'HKLM\ORPHAN\SAM\Key\SubKey' (orphan key) * 3) '0x\ROOT\Key\SubKey' * 4) '0x\ORPHAN\Key\SubKey' (orphan key) +* -- hVMM * -- wszFullPathKey * -- dwIndex * -- lpValueName @@ -2168,6 +2304,7 @@ BOOL VMMDLL_WinReg_EnumKeyExW( */ _Success_(return) BOOL VMMDLL_WinReg_EnumValueW( + _In_ VMM_HANDLE hVMM, _In_ LPWSTR wszFullPathKey, _In_ DWORD dwIndex, _Out_writes_opt_(*lpcchValueName) LPWSTR lpValueName, @@ -2186,6 +2323,7 @@ BOOL VMMDLL_WinReg_EnumValueW( * 2) 'HKLM\ORPHAN\SAM\Key\SubKey\' (orphan key and default value) * 3) '0x\ROOT\Key\SubKey\Value' * 4) '0x\ORPHAN\Key\SubKey\Value' (orphan key value) +* -- hVMM * -- wszFullPathKeyValue * -- lpType * -- lpData @@ -2194,6 +2332,7 @@ BOOL VMMDLL_WinReg_EnumValueW( */ _Success_(return) BOOL VMMDLL_WinReg_QueryValueExW( + _In_ VMM_HANDLE hVMM, _In_ LPWSTR wszFullPathKeyValue, _Out_opt_ LPDWORD lpType, _Out_writes_opt_(*lpcbData) LPBYTE lpData, @@ -2219,6 +2358,7 @@ typedef struct tdVMMDLL_WIN_THUNKINFO_IAT { * Retrieve information about the import address table IAT thunk for an imported * function. This includes the virtual address of the IAT thunk which is useful * for hooking. +* -- hVMM * -- dwPID * -- [uw]szModuleName * -- szImportModuleName @@ -2227,8 +2367,8 @@ typedef struct tdVMMDLL_WIN_THUNKINFO_IAT { * -- return */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_WinGetThunkInfoIATU(_In_ DWORD dwPID, _In_ LPSTR uszModuleName, _In_ LPSTR szImportModuleName, _In_ LPSTR szImportFunctionName, _Out_ PVMMDLL_WIN_THUNKINFO_IAT pThunkInfoIAT); -_Success_(return) BOOL VMMDLL_WinGetThunkInfoIATW(_In_ DWORD dwPID, _In_ LPWSTR wszModuleName, _In_ LPSTR szImportModuleName, _In_ LPSTR szImportFunctionName, _Out_ PVMMDLL_WIN_THUNKINFO_IAT pThunkInfoIAT); +_Success_(return) BOOL VMMDLL_WinGetThunkInfoIATU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPSTR uszModuleName, _In_ LPSTR szImportModuleName, _In_ LPSTR szImportFunctionName, _Out_ PVMMDLL_WIN_THUNKINFO_IAT pThunkInfoIAT); +_Success_(return) BOOL VMMDLL_WinGetThunkInfoIATW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPWSTR wszModuleName, _In_ LPSTR szImportModuleName, _In_ LPSTR szImportFunctionName, _Out_ PVMMDLL_WIN_THUNKINFO_IAT pThunkInfoIAT); diff --git a/m_vmemd/Makefile b/m_vmemd/Makefile new file mode 100644 index 0000000..a21c98b --- /dev/null +++ b/m_vmemd/Makefile @@ -0,0 +1,32 @@ +# +# NOTE! PACKAGE DEPENDENCY ON LeechCore: +# The build script require leechcore.so built from the leechcore project +# which is found at https://github.com/ufrisk/LeechCore to build. This +# file is assumed to exist in either of the directories: +# . (current), ../files, ../../LeechCore*/files +# +CC=gcc +CFLAGS += -std=c11 -I. -I../includes -D LINUX -D _GNU_SOURCE -shared -fPIC -l:../files/leechcore.so -l:../files/vmm.so -fvisibility=hidden -L. -lm -pthread `pkg-config liblz4 openssl --libs --cflags` +#CFLAGS += -g -O0 -Wextra -Wno-unused-parameter -Wno-cast-function-type +CFLAGS += -fPIE -fPIC -pie -fstack-protector -D_FORTIFY_SOURCE=2 -O1 -Wl,-z,noexecstack +CFLAGS += -Wall -Wno-format-truncation -Wno-enum-compare -Wno-pointer-sign -Wno-multichar -Wno-unused-variable -Wno-unused-value +CFLAGS += -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast +LDFLAGS += -Wl,-rpath,'$$ORIGIN' -g -ldl -shared +DEPS = vmmdll.h +OBJ = m_vmemd.o oscompatibility.o + +%.o: %.c $(DEPS) + $(CC) -c -o $@ $< $(CFLAGS) + +m_vmemd: $(OBJ) + $(CC) -o $@ $^ $(CFLAGS) -o m_vmemd.so $(LDFLAGS) + mv m_vmemd.so ../files/plugins/ + rm -f *.o || true + rm -f */*.o || true + rm -f *.so || true + true + +clean: + rm -f *.o || true + rm -f */*.o || true + rm -f *.so || true diff --git a/m_vmemd/m_vmemd.c b/m_vmemd/m_vmemd.c index bfcba58..bedf5ba 100644 --- a/m_vmemd/m_vmemd.c +++ b/m_vmemd/m_vmemd.c @@ -4,7 +4,7 @@ // (c) Ulf Frisk, 2018-2022 // Author: Ulf Frisk, pcileech@frizk.net // -#include +#include "oscompatibility.h" #include #include @@ -30,24 +30,24 @@ BOOL VMemD_GetBaseAndTypeFromFileName(_In_ LPSTR usz, _Out_ PQWORD pva, _Out_ PB return TRUE; } -VOID VMemD_Util_FileNameU(_Out_writes_(64) LPSTR uszOut, _In_ LPWSTR wsz) +VOID VMemD_Util_FileNameU(_Out_writes_(64) LPSTR uszOut, _In_ LPSTR usz) { WCHAR ch; DWORD i = 0; - while(wsz[i]) { - if(wsz[i] == '\\') { - wsz += i + 1ULL; + while(usz[i]) { + if(usz[i] == '\\') { + usz += i + 1ULL; i = 0; continue; } if(i == 62) { - wsz += 1; + usz += 1; continue; } i++; } i = 0; - while((ch = wsz[i])) { + while((ch = usz[i])) { uszOut[i] = ((ch < 128) && (UTIL_ASCIIFILENAME_ALLOW[ch] == '0')) ? '_' : ch; i++; } @@ -115,20 +115,17 @@ int VMemD_ReadVad_CmpFind(_In_ QWORD vaFind, _In_ PVMMDLL_MAP_VADENTRY pEntry) /* * Read/Write virtual memory inside a memory map entry of PTE-type. */ -NTSTATUS VMemD_ReadWritePte(_In_ DWORD dwPID, _In_ QWORD vaBase, _In_ BOOL fRead, _Out_writes_bytes_(*pcbReadWrite) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbReadWrite, _In_ ULONG64 cbOffset) +NTSTATUS VMemD_ReadWritePte(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ QWORD vaBase, _In_ BOOL fRead, _Out_writes_bytes_(*pcbReadWrite) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbReadWrite, _In_ ULONG64 cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; BOOL result; QWORD cbMax; - DWORD cbPteMap = 0; PVMMDLL_MAP_PTE pPteMap = NULL; PVMMDLL_MAP_PTEENTRY pe = NULL; // read memory from "vmemd" directory file - "pte mapped" *pcbReadWrite = 0; result = - VMMDLL_Map_GetPte(dwPID, NULL, &cbPteMap, FALSE) && - (pPteMap = LocalAlloc(0, cbPteMap)) && - VMMDLL_Map_GetPte(dwPID, pPteMap, &cbPteMap, FALSE) && + VMMDLL_Map_GetPteU(H, dwPID, FALSE, &pPteMap) && (pe = VMemD_Util_qfind((PVOID)vaBase, pPteMap->cMap, pPteMap->pMap, sizeof(VMMDLL_MAP_PTEENTRY), (int(*)(PVOID, PVOID))VMemD_ReadPte_CmpFind)); if(!result) { goto fail; } if(pe->vaBase + (pe->cPages << 12) <= vaBase + cbOffset) { @@ -137,36 +134,32 @@ NTSTATUS VMemD_ReadWritePte(_In_ DWORD dwPID, _In_ QWORD vaBase, _In_ BOOL fRead } cbMax = min((pe->vaBase + (pe->cPages << 12)), (vaBase + cb + cbOffset)) - (vaBase + cbOffset); // min(entry_top_addr, request_top_addr) - request_start_addr if(fRead) { - result = VMMDLL_MemReadEx(dwPID, vaBase + cbOffset, pb, (DWORD)min(cb, cbMax), NULL, VMMDLL_FLAG_ZEROPAD_ON_FAIL); + result = VMMDLL_MemReadEx(H, dwPID, vaBase + cbOffset, pb, (DWORD)min(cb, cbMax), NULL, VMMDLL_FLAG_ZEROPAD_ON_FAIL); *pcbReadWrite = (DWORD)min(cb, cbMax); nt = (result && *pcbReadWrite) ? VMMDLL_STATUS_SUCCESS : VMMDLL_STATUS_END_OF_FILE; } else { - VMMDLL_MemWrite(dwPID, vaBase + cbOffset, pb, (DWORD)min(cb, cbMax)); + VMMDLL_MemWrite(H, dwPID, vaBase + cbOffset, pb, (DWORD)min(cb, cbMax)); *pcbReadWrite = cb; nt = VMMDLL_STATUS_SUCCESS; } fail: - LocalFree(pPteMap); + VMMDLL_MemFree(pPteMap); return nt; } /* * Read/Write virtual memory inside a memory map entry of VAD-type. */ -NTSTATUS VMemD_ReadWriteVad(_In_ DWORD dwPID, _In_ QWORD vaBase, _In_ BOOL fRead, _Out_writes_bytes_(*pcbReadWrite) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbReadWrite, _In_ ULONG64 cbOffset) +NTSTATUS VMemD_ReadWriteVad(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ QWORD vaBase, _In_ BOOL fRead, _Out_writes_bytes_(*pcbReadWrite) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbReadWrite, _In_ ULONG64 cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; BOOL result; QWORD cbMax; - DWORD cbVadMap = 0; PVMMDLL_MAP_VAD pVadMap = NULL; PVMMDLL_MAP_VADENTRY pe = NULL; // read memory from "vmemd" directory file - "pte mapped" *pcbReadWrite = 0; - result = - VMMDLL_Map_GetVad(dwPID, NULL, &cbVadMap, FALSE) && - (pVadMap = LocalAlloc(0, cbVadMap)) && - VMMDLL_Map_GetVad(dwPID, pVadMap, &cbVadMap, FALSE) && + result = VMMDLL_Map_GetVadU(H, dwPID, FALSE, &pVadMap) && (pe = VMemD_Util_qfind((PVOID)vaBase, pVadMap->cMap, pVadMap->pMap, sizeof(VMMDLL_MAP_VADENTRY), (int(*)(PVOID, PVOID))VMemD_ReadVad_CmpFind)); if(!result) { goto fail; } if(pe->vaEnd <= vaBase + cbOffset) { @@ -175,68 +168,71 @@ NTSTATUS VMemD_ReadWriteVad(_In_ DWORD dwPID, _In_ QWORD vaBase, _In_ BOOL fRead } cbMax = min(pe->vaEnd + 1, (vaBase + cb + cbOffset)) - (vaBase + cbOffset); // min(entry_top_addr, request_top_addr) - request_start_addr if(fRead) { - result = VMMDLL_MemReadEx(dwPID, vaBase + cbOffset, pb, (DWORD)min(cb, cbMax), NULL, VMMDLL_FLAG_ZEROPAD_ON_FAIL); + result = VMMDLL_MemReadEx(H, dwPID, vaBase + cbOffset, pb, (DWORD)min(cb, cbMax), NULL, VMMDLL_FLAG_ZEROPAD_ON_FAIL); *pcbReadWrite = (DWORD)min(cb, cbMax); nt = (result && *pcbReadWrite) ? VMMDLL_STATUS_SUCCESS : VMMDLL_STATUS_END_OF_FILE; } else { - VMMDLL_MemWrite(dwPID, vaBase + cbOffset, pb, (DWORD)min(cb, cbMax)); + VMMDLL_MemWrite(H, dwPID, vaBase + cbOffset, pb, (DWORD)min(cb, cbMax)); *pcbReadWrite = cb; nt = VMMDLL_STATUS_SUCCESS; } fail: - LocalFree(pVadMap); + VMMDLL_MemFree(pVadMap); return nt; } /* * Read : function as specified by the module manager. The module manager will * call into this callback function whenever a read shall occur from a "file". -* -- ctx +* -- H +* -- ctxP * -- pb * -- cb * -- pcbRead * -- cbOffset * -- return */ -NTSTATUS VMemD_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset) +NTSTATUS VMemD_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset) { BOOL fVad; QWORD vaBase; - if(!VMemD_GetBaseAndTypeFromFileName(ctx->uszPath, &vaBase, &fVad)) { return VMMDLL_STATUS_FILE_INVALID; } + if(!VMemD_GetBaseAndTypeFromFileName(ctxP->uszPath, &vaBase, &fVad)) { return VMMDLL_STATUS_FILE_INVALID; } return fVad ? - VMemD_ReadWriteVad(ctx->dwPID, vaBase, TRUE, pb, cb, pcbRead, cbOffset) : - VMemD_ReadWritePte(ctx->dwPID, vaBase, TRUE, pb, cb, pcbRead, cbOffset); + VMemD_ReadWriteVad(H, ctxP->dwPID, vaBase, TRUE, pb, cb, pcbRead, cbOffset) : + VMemD_ReadWritePte(H, ctxP->dwPID, vaBase, TRUE, pb, cb, pcbRead, cbOffset); } /* * Write : function as specified by the module manager. The module manager will * call into this callback function whenever a write shall occur from a "file". -* -- ctx +* -- H +* -- ctxP * -- pb * -- cb * -- pcbWrite * -- cbOffset * -- return */ -NTSTATUS VMemD_WritePte(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset) +NTSTATUS VMemD_WritePte(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset) { BOOL fVad; QWORD vaBase; - if(!VMemD_GetBaseAndTypeFromFileName(ctx->uszPath, &vaBase, &fVad)) { return VMMDLL_STATUS_FILE_INVALID; } + if(!VMemD_GetBaseAndTypeFromFileName(ctxP->uszPath, &vaBase, &fVad)) { return VMMDLL_STATUS_FILE_INVALID; } return fVad ? - VMemD_ReadWriteVad(ctx->dwPID, vaBase, FALSE, pb, cb, pcbWrite, cbOffset) : - VMemD_ReadWritePte(ctx->dwPID, vaBase, FALSE, pb, cb, pcbWrite, cbOffset); + VMemD_ReadWriteVad(H, ctxP->dwPID, vaBase, FALSE, pb, cb, pcbWrite, cbOffset) : + VMemD_ReadWritePte(H, ctxP->dwPID, vaBase, FALSE, pb, cb, pcbWrite, cbOffset); } /* * List : function as specified by the module manager. The module manager will * call into this callback function whenever a list directory shall occur from * the given module. -* -- ctx +* -- H +* -- ctxP * -- pFileList * -- return */ -BOOL VMemD_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) +BOOL VMemD_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { BOOL f, fResult = FALSE; DWORD iVad, iPte, cbPteMap = 0, cbVadMap = 0; @@ -244,41 +240,36 @@ BOOL VMemD_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) PVMMDLL_MAP_PTEENTRY pPte = NULL; PVMMDLL_MAP_VAD pVadMap = NULL; PVMMDLL_MAP_VADENTRY pVad = NULL; - WCHAR wszBufferFileName[MAX_PATH] = { 0 }; + CHAR uszBufferFileName[MAX_PATH] = { 0 }; CHAR uszInfo[64] = { 0 }; // Retrieve mandatory memory map based on hardware page tables. - f = VMMDLL_Map_GetPte(ctx->dwPID, NULL, &cbPteMap, TRUE) && - (pPteMap = LocalAlloc(0, cbPteMap)); - f = f && VMMDLL_Map_GetPte(ctx->dwPID, pPteMap, &cbPteMap, TRUE); - if(!f) { goto fail; } + if(!VMMDLL_Map_GetPteU(H, ctxP->dwPID, TRUE, &pPteMap)) { goto fail; } // Retrieve optional memory map based on virtual address descriptors (VADs). - f = VMMDLL_Map_GetVad(ctx->dwPID, NULL, &cbVadMap, TRUE) && - (pVadMap = LocalAlloc(0, cbVadMap)) && - VMMDLL_Map_GetVad(ctx->dwPID, pVadMap, &cbVadMap, TRUE); + f = VMMDLL_Map_GetVadU(H, ctxP->dwPID, TRUE, &pVadMap); // Display VadMap entries in the file system (if any) for(iVad = 0; (f && (iVad < pVadMap->cMap)); iVad++) { pVad = pVadMap->pMap + iVad; - VMemD_Util_FileNameU(uszInfo, pVad->wszText); + VMemD_Util_FileNameU(uszInfo, pVad->uszText); if(g_VMemD_TpMemoryModel == VMMDLL_MEMORYMODEL_X64) { - swprintf_s( - wszBufferFileName, + sprintf_s( + uszBufferFileName, MAX_PATH - 1, - L"0x%016llx%s%S.vvmem", + "0x%016llx%s%s.vvmem", pVad->vaStart, - uszInfo[0] ? L"-" : L"", + uszInfo[0] ? "-" : "", uszInfo ); } else if((g_VMemD_TpMemoryModel == VMMDLL_MEMORYMODEL_X86) || (g_VMemD_TpMemoryModel == VMMDLL_MEMORYMODEL_X86PAE)) { - swprintf_s( - wszBufferFileName, + sprintf_s( + uszBufferFileName, MAX_PATH - 1, - L"0x%08lx%s%S.vvmem", + "0x%08x%s%s.vvmem", (DWORD)pVad->vaStart, - uszInfo[0] ? L"-" : L"", + uszInfo[0] ? "-" : "", uszInfo ); } - VMMDLL_VfsList_AddFileW(pFileList, wszBufferFileName, pVad->vaEnd + 1 - pVad->vaStart, NULL); + VMMDLL_VfsList_AddFile(pFileList, uszBufferFileName, pVad->vaEnd + 1 - pVad->vaStart, NULL); } // Display PteMap entries in the file system unless already part of Vad for(iPte = 0, iVad = 0; iPte < pPteMap->cMap; iPte++) { @@ -287,32 +278,32 @@ BOOL VMemD_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) while((iVad < pVadMap->cMap) && (pVadMap->pMap[iVad].vaEnd < pPte->vaBase) && ++iVad); if((iVad < pVadMap->cMap) && (pVadMap->pMap[iVad].vaStart <= pPte->vaBase) && (pVadMap->pMap[iVad].vaEnd >= pPte->vaBase)) { continue; } } - VMemD_Util_FileNameU(uszInfo, pPte->wszText); + VMemD_Util_FileNameU(uszInfo, pPte->uszText); if(g_VMemD_TpMemoryModel == VMMDLL_MEMORYMODEL_X64) { - swprintf_s( - wszBufferFileName, + sprintf_s( + uszBufferFileName, MAX_PATH - 1, - L"0x%016llx%s%S.vmem", + "0x%016llx%s%s.vmem", pPte->vaBase, - uszInfo[0] ? L"-" : L"", + uszInfo[0] ? "-" : "", uszInfo ); } else if((g_VMemD_TpMemoryModel == VMMDLL_MEMORYMODEL_X86) || (g_VMemD_TpMemoryModel == VMMDLL_MEMORYMODEL_X86PAE)) { - swprintf_s( - wszBufferFileName, + sprintf_s( + uszBufferFileName, MAX_PATH - 1, - L"0x%08lx%s%S.vmem", + "0x%08x%s%s.vmem", (DWORD)pPte->vaBase, - uszInfo[0] ? L"-" : L"", + uszInfo[0] ? "-" : "", uszInfo ); } - VMMDLL_VfsList_AddFileW(pFileList, wszBufferFileName, pPte->cPages << 12, NULL); + VMMDLL_VfsList_AddFile(pFileList, uszBufferFileName, pPte->cPages << 12, NULL); } fResult = TRUE; fail: - LocalFree(pPteMap); - LocalFree(pVadMap); + VMMDLL_MemFree(pPteMap); + VMMDLL_MemFree(pVadMap); return fResult; } @@ -323,10 +314,11 @@ fail: * after the DLL is loaded. The DLL then must fill the appropriate information * into the supplied struct and call the pfnPluginManager_Register function to * register itself with the plugin manager. +* -- H * -- pRegInfo */ -__declspec(dllexport) -VOID InitializeVmmPlugin(_In_ PVMMDLL_PLUGIN_REGINFO pRegInfo) +EXPORTED_FUNCTION +VOID InitializeVmmPlugin(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_REGINFO pRegInfo) { if((pRegInfo->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRegInfo->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } // Ensure that the plugin support the memory model that is used. The plugin @@ -338,5 +330,5 @@ VOID InitializeVmmPlugin(_In_ PVMMDLL_PLUGIN_REGINFO pRegInfo) pRegInfo->reg_fn.pfnList = VMemD_List; // List function supported. pRegInfo->reg_fn.pfnRead = VMemD_Read; // Read function supported. pRegInfo->reg_fn.pfnWrite = VMemD_WritePte; // Write function supported. - pRegInfo->pfnPluginManager_Register(pRegInfo); // Register with the plugin manager. + pRegInfo->pfnPluginManager_Register(H, pRegInfo); // Register with the plugin manager. } diff --git a/m_vmemd/oscompatibility.c b/m_vmemd/oscompatibility.c new file mode 100644 index 0000000..bbcc6f5 --- /dev/null +++ b/m_vmemd/oscompatibility.c @@ -0,0 +1,502 @@ +// oscompatibility.c : VMM Windows/Linux compatibility layer. +// +// (c) Ulf Frisk, 2021-2022 +// Author: Ulf Frisk, pcileech@frizk.net +// +#ifdef LINUX + +#include "oscompatibility.h" +#include +#include +#include +#include +#include +#include +#include +#include + +// ---------------------------------------------------------------------------- +// LocalAlloc/LocalFree BELOW: +// ---------------------------------------------------------------------------- + +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); +} + +// ---------------------------------------------------------------------------- +// LIBRARY FUNCTIONS BELOW: +// ---------------------------------------------------------------------------- + +FARPROC GetProcAddress(HMODULE hModule, LPSTR lpProcName) +{ + return NULL; +} + +HMODULE LoadLibraryA(LPSTR lpFileName) +{ + if(!strcmp(lpFileName, "ntdll.dll")) { + return (HMODULE)0x1000; // FAKE HMODULE + } + return 0; +} + +// ---------------------------------------------------------------------------- +// GENERAL HANDLES BELOW: +// ---------------------------------------------------------------------------- + +#define OSCOMPATIBILITY_HANDLE_INTERNAL 0x35d91cca +#define OSCOMPATIBILITY_HANDLE_TYPE_THREAD 2 +#define OSCOMPATIBILITY_HANDLE_TYPE_EVENT 3 + +typedef struct tdHANDLE_INTERNAL { + DWORD magic; + DWORD type; +} HANDLE_INTERNAL, *PHANDLE_INTERNAL; + +typedef struct tdHANDLE_INTERNAL_THREAD { + DWORD magic; + DWORD type; + pthread_t thread; +} HANDLE_INTERNAL_THREAD, *PHANDLE_INTERNAL_THREAD; + +BOOL CloseHandle(_In_ HANDLE hObject) +{ + PHANDLE_INTERNAL hi = (PHANDLE_INTERNAL)hObject; + if(hi->magic != OSCOMPATIBILITY_HANDLE_INTERNAL) { return FALSE; } + switch(hi->type) { + case OSCOMPATIBILITY_HANDLE_TYPE_THREAD: + break; + case OSCOMPATIBILITY_HANDLE_TYPE_EVENT: + SetEvent(hObject); + break; + default: + break; + } + LocalFree(hi); + return TRUE; +} + +QWORD GetTickCount64() +{ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); + return ts.tv_sec * 1000 + ts.tv_nsec / (1000 * 1000); +} + +BOOL QueryPerformanceFrequency(_Out_ LARGE_INTEGER *lpFrequency) +{ + *lpFrequency = 1000 * 1000; + return TRUE; +} + +BOOL QueryPerformanceCounter(_Out_ LARGE_INTEGER *lpPerformanceCount) +{ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); + *lpPerformanceCount = (ts.tv_sec * 1000 * 1000) + (ts.tv_nsec / 1000); // uS resolution + return TRUE; +} + +HANDLE CreateThread( + PVOID lpThreadAttributes, + SIZE_T dwStackSize, + PVOID lpStartAddress, + PVOID lpParameter, + DWORD dwCreationFlags, + PDWORD lpThreadId +) { + PHANDLE_INTERNAL_THREAD ph; + pthread_t thread; + int status; + status = pthread_create(&thread, NULL, lpStartAddress, lpParameter); + if(status) { return NULL;} + ph = malloc(sizeof(HANDLE_INTERNAL_THREAD)); + ph->magic = OSCOMPATIBILITY_HANDLE_INTERNAL; + ph->type = OSCOMPATIBILITY_HANDLE_TYPE_THREAD; + ph->thread = thread; + return (HANDLE)ph; +} + +BOOL GetExitCodeThread(_In_ HANDLE hThread, _Out_ LPDWORD lpExitCode) +{ + PHANDLE_INTERNAL_THREAD ph = (PHANDLE_INTERNAL_THREAD)hThread; + *lpExitCode = 0; + if((ph->magic != OSCOMPATIBILITY_HANDLE_INTERNAL) || (ph->type != OSCOMPATIBILITY_HANDLE_TYPE_THREAD)) { return FALSE; } + return 0 == pthread_join(ph->thread, NULL); +} + +VOID GetLocalTime(LPSYSTEMTIME lpSystemTime) +{ + time_t curtime; + struct tm t = { 0 }; + curtime = time(NULL); + localtime_r(&curtime, &t); + lpSystemTime->wYear = t.tm_year; + lpSystemTime->wMonth = t.tm_mon; + lpSystemTime->wDayOfWeek = t.tm_wday; + lpSystemTime->wDay = t.tm_mday; + lpSystemTime->wHour = t.tm_hour; + lpSystemTime->wMinute = t.tm_min; + lpSystemTime->wSecond = t.tm_sec; + lpSystemTime->wMilliseconds = 0; +} + +VOID GetSystemTimeAsFileTime(PFILETIME lpSystemTimeAsFileTime) +{ + *lpSystemTimeAsFileTime = (time(NULL) * 10000000) + 116444736000000000; +} + +HANDLE FindFirstFileA(LPSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData) +{ + DWORD i; + DIR *hDir; + CHAR szDirName[MAX_PATH] = { 0 }; + strcpy_s(lpFindFileData->__cExtension, 5, lpFileName + strlen(lpFileName) - 3); + strcpy_s(szDirName, MAX_PATH - 1, lpFileName); + for(i = strlen(szDirName) - 1; i > 0; i--) { + if(szDirName[i] == '/') { + szDirName[i] = 0; + break; + } + } + hDir = opendir(szDirName); + if(!hDir) { return NULL; } + return FindNextFileA((HANDLE)hDir, lpFindFileData) ? (HANDLE)hDir : INVALID_HANDLE_VALUE; +} + +BOOL FindNextFileA(HANDLE hFindFile, LPWIN32_FIND_DATAA lpFindFileData) +{ + DIR *hDir = (DIR*)hFindFile; + struct dirent *dir; + char* sz; + if(!hDir) { return FALSE; } + while ((dir = readdir(hDir)) != NULL) { + sz = dir->d_name; + if((strlen(sz) > 3) && !strcasecmp(sz + strlen(sz) - 3, lpFindFileData->__cExtension)) { + strcpy_s(lpFindFileData->cFileName, MAX_PATH, sz); + return TRUE; + } + } + closedir(hDir); + return FALSE; +} + +DWORD InterlockedAdd(DWORD *Addend, DWORD Value) +{ + return __sync_add_and_fetch(Addend, Value); +} + +BOOL FileTimeToSystemTime(_In_ PFILETIME lpFileTime, _Out_ PSYSTEMTIME pSystemTime) +{ + time_t tm = 0; + struct tm t = { 0 }; + if(*lpFileTime >= 116444736000000000ULL) { + tm = (*lpFileTime - 116444736000000000ULL) / 10000000ULL; + } + gmtime_r(&tm, &t); + pSystemTime->wYear = 1900 + t.tm_year; + pSystemTime->wMonth = 1 + t.tm_mon; + pSystemTime->wDayOfWeek = t.tm_wday; + pSystemTime->wDay = t.tm_mday; + pSystemTime->wHour = t.tm_hour; + pSystemTime->wMinute = t.tm_min; + pSystemTime->wSecond = t.tm_sec; + pSystemTime->wMilliseconds = (*lpFileTime / 10000) % 1000; + return TRUE; +} + +// ---------------------------------------------------------------------------- +// CRITICAL_SECTION functionality below: +// ---------------------------------------------------------------------------- + +VOID InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection) +{ + memset(lpCriticalSection, 0, sizeof(CRITICAL_SECTION)); + pthread_mutexattr_init(&lpCriticalSection->mta); + pthread_mutexattr_settype(&lpCriticalSection->mta, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&lpCriticalSection->mutex, &lpCriticalSection->mta); +} + +BOOL InitializeCriticalSectionAndSpinCount(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount) +{ + InitializeCriticalSection(lpCriticalSection); + return TRUE; +} + +VOID DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection) +{ + pthread_mutex_destroy(&lpCriticalSection->mutex); + memset(lpCriticalSection, 0, sizeof(CRITICAL_SECTION)); +} + +VOID EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection) +{ + pthread_mutex_lock(&lpCriticalSection->mutex); +} + +VOID LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection) +{ + pthread_mutex_unlock(&lpCriticalSection->mutex); +} + + + +// ---------------------------------------------------------------------------- +// SRWLock functionality below: +// ---------------------------------------------------------------------------- + +static int futex(uint32_t *uaddr, int futex_op, uint32_t val, const struct timespec *timeout, uint32_t *uaddr2, uint32_t val3) +{ + return syscall(SYS_futex, uaddr, futex_op, val, timeout, uaddr2, val3); +} + +VOID InitializeSRWLock(PSRWLOCK SRWLock) +{ + ZeroMemory(SRWLock, sizeof(SRWLOCK)); +} + +BOOL AcquireSRWLockExclusive_Try(_Inout_ PSRWLOCK SRWLock) +{ + DWORD dwZero = 0; + __sync_fetch_and_add_4(&SRWLock->c, 1); + if(atomic_compare_exchange_strong(&SRWLock->xchg, &dwZero, 1)) { + return TRUE; + } + __sync_sub_and_fetch_4(&SRWLock->c, 1); + return FALSE; +} + +VOID AcquireSRWLockExclusive(_Inout_ PSRWLOCK SRWLock) +{ + DWORD dwZero; + __sync_fetch_and_add_4(&SRWLock->c, 1); + while(TRUE) { + dwZero = 0; + if(atomic_compare_exchange_strong(&SRWLock->xchg, &dwZero, 1)) { + return; + } + futex(&SRWLock->xchg, FUTEX_WAIT, 1, NULL, NULL, 0); + } +} + +_Success_(return) +BOOL AcquireSRWLockExclusive_Timeout(_Inout_ PSRWLOCK SRWLock, _In_ DWORD dwMilliseconds) +{ + DWORD dwZero; + struct timespec ts; + __sync_fetch_and_add_4(&SRWLock->c, 1); + while(TRUE) { + dwZero = 0; + if(atomic_compare_exchange_strong(&SRWLock->xchg, &dwZero, 1)) { + return TRUE; + } + if((dwMilliseconds != 0) && (dwMilliseconds != 0xffffffff)) { + ts.tv_sec = dwMilliseconds / 1000; + ts.tv_nsec = (dwMilliseconds % 1000) * 1000 * 1000; + if((-1 == futex(&SRWLock->xchg, FUTEX_WAIT, 1, &ts, NULL, 0)) && (errno != EAGAIN)) { + __sync_sub_and_fetch_4(&SRWLock->c, 1); + return FALSE; + } + } else { + if((-1 == futex(&SRWLock->xchg, FUTEX_WAIT, 1, NULL, NULL, 0)) && (errno != EAGAIN)) { + __sync_sub_and_fetch_4(&SRWLock->c, 1); + return FALSE; + } + } + } +} + +VOID ReleaseSRWLockExclusive(_Inout_ PSRWLOCK SRWLock) +{ + DWORD dwOne = 1; + if(atomic_compare_exchange_strong(&SRWLock->xchg, &dwOne, 0)) { + if(__sync_sub_and_fetch_4(&SRWLock->c, 1)) { + futex(&SRWLock->xchg, FUTEX_WAKE, 1, NULL, NULL, 0); + } + } +} + +// ---------------------------------------------------------------------------- +// EVENT functionality below: +// ---------------------------------------------------------------------------- + +typedef struct tdHANDLE_INTERNAL_EVENT2 { + DWORD magic; + DWORD type; + BOOL fEventManualReset; + SRWLOCK SRWLock; +} HANDLE_INTERNAL_EVENT2, *PHANDLE_INTERNAL_EVENT2; + +// function is limited and not thread-safe, but use case in leechcore is single-threaded +DWORD WaitForSingleObject(_In_ HANDLE hHandle, _In_ DWORD dwMilliseconds) +{ + PHANDLE_INTERNAL_EVENT2 ph = (PHANDLE_INTERNAL_EVENT2)hHandle; + BOOL fResult; + if((ph->magic != OSCOMPATIBILITY_HANDLE_INTERNAL) || (ph->type != OSCOMPATIBILITY_HANDLE_TYPE_EVENT)) { return 0xffffffff; } + if(!AcquireSRWLockExclusive_Timeout(&ph->SRWLock, dwMilliseconds)) { + return 0xffffffff; // timeout + } + if(ph->fEventManualReset) { + ReleaseSRWLockExclusive(&ph->SRWLock); + } + return 0; +} + +DWORD WaitForMultipleObjectsAll(_In_ DWORD nCount, HANDLE *lpHandles, _In_ DWORD dwMilliseconds) +{ + DWORD i; + BOOL fAll = FALSE; + PHANDLE_INTERNAL_EVENT2 ph; + // 1: verify handle validity + for(i = 0; i < nCount; i++) { + ph = *(PHANDLE_INTERNAL_EVENT2 *)(lpHandles + i); + if((ph->magic != OSCOMPATIBILITY_HANDLE_INTERNAL) || (ph->type != OSCOMPATIBILITY_HANDLE_TYPE_EVENT)) { + return 0xffffffff; + } + } + // 2: wait for all objects + while(!fAll) { + fAll = TRUE; + for(i = 0; i < nCount; i++) { + ph = *(PHANDLE_INTERNAL_EVENT2 *)(lpHandles + i); + if(!AcquireSRWLockExclusive_Try(&ph->SRWLock)) { + if(!AcquireSRWLockExclusive_Timeout(&ph->SRWLock, dwMilliseconds)) { + return 0xffffffff; // timeout + } + fAll = FALSE; + } + ReleaseSRWLockExclusive(&ph->SRWLock); + } + } + return 0; +} + +DWORD WaitForMultipleObjectsSingle(_In_ DWORD nCount, HANDLE *lpHandles, _In_ DWORD dwMilliseconds) +{ + DWORD i; + PHANDLE_INTERNAL_EVENT2 ph; + // 1: verify handle validity + for(i = 0; i < nCount; i++) { + ph = *(PHANDLE_INTERNAL_EVENT2*)(lpHandles + i); + if((ph->magic != OSCOMPATIBILITY_HANDLE_INTERNAL) || (ph->type != OSCOMPATIBILITY_HANDLE_TYPE_EVENT)) { + return 0xffffffff; + } + } + // 2: try find single available object - or else sleep and try again + while(TRUE) { + for(i = 0; i < nCount; i++) { + ph = *(PHANDLE_INTERNAL_EVENT2*)(lpHandles + i); + if(AcquireSRWLockExclusive_Try(&ph->SRWLock)) { + if(ph->fEventManualReset) { + ReleaseSRWLockExclusive(&ph->SRWLock); + } + return i; + } + } + Sleep(5); + } +} + +DWORD WaitForMultipleObjects(_In_ DWORD nCount, HANDLE *lpHandles, _In_ BOOL bWaitAll, _In_ DWORD dwMilliseconds) +{ + return bWaitAll ? + WaitForMultipleObjectsAll(nCount, lpHandles, dwMilliseconds) : + WaitForMultipleObjectsSingle(nCount, lpHandles, dwMilliseconds); + +} + +BOOL SetEvent(_In_ HANDLE hEventIngestPhys) +{ + PHANDLE_INTERNAL_EVENT2 ph = (PHANDLE_INTERNAL_EVENT2)hEventIngestPhys; + if((ph->magic != OSCOMPATIBILITY_HANDLE_INTERNAL) || (ph->type != OSCOMPATIBILITY_HANDLE_TYPE_EVENT)) { return FALSE; } + ReleaseSRWLockExclusive(&ph->SRWLock); + return TRUE; +} + +BOOL ResetEvent(_In_ HANDLE hEventIngestPhys) +{ + PHANDLE_INTERNAL_EVENT2 ph = (PHANDLE_INTERNAL_EVENT2)hEventIngestPhys; + if((ph->magic != OSCOMPATIBILITY_HANDLE_INTERNAL) || (ph->type != OSCOMPATIBILITY_HANDLE_TYPE_EVENT)) { return FALSE; } + return AcquireSRWLockExclusive_Try(&ph->SRWLock); +} + +HANDLE CreateEvent(_In_opt_ PVOID lpEventAttributes, _In_ BOOL bManualReset, _In_ BOOL bInitialState, _In_opt_ PVOID lpName) +{ + PHANDLE_INTERNAL_EVENT2 ph; + ph = malloc(sizeof(HANDLE_INTERNAL_EVENT2)); + ZeroMemory(ph, sizeof(HANDLE_INTERNAL_EVENT2)); + ph->magic = OSCOMPATIBILITY_HANDLE_INTERNAL; + ph->type = OSCOMPATIBILITY_HANDLE_TYPE_EVENT; + ph->fEventManualReset = bManualReset; + if(bInitialState) { + SetEvent((HANDLE)ph); + } else { + ResetEvent((HANDLE)ph); + } + return (HANDLE)ph; +} + +// ---------------------------------------------------------------------------- +// SLIST functionality below: +// ---------------------------------------------------------------------------- + +VOID InitializeSListHead(PSLIST_HEADER ListHead) +{ + ZeroMemory(ListHead, sizeof(SLIST_HEADER)); +} + +USHORT QueryDepthSList(PSLIST_HEADER ListHead) +{ + return ListHead->c; +} + +PSLIST_ENTRY InterlockedPopEntrySList(_Inout_ PSLIST_HEADER ListHead) +{ + PSLIST_ENTRY e = NULL; + AcquireSRWLockExclusive(&ListHead->LockSRW); + if(ListHead->c) { + ListHead->c--; + if((e = ListHead->Next)) { + ListHead->Next = ListHead->Next->Next; + e->Next = NULL; + } + } + ReleaseSRWLockExclusive(&ListHead->LockSRW); + return e; +} + + +PSLIST_ENTRY InterlockedPushEntrySList(_Inout_ PSLIST_HEADER ListHead, _Inout_ PSLIST_ENTRY ListEntry) +{ + PSLIST_ENTRY e = NULL; + AcquireSRWLockExclusive(&ListHead->LockSRW); + ListHead->c++; + e = ListHead->Next; + ListEntry->Next = e; + ListHead->Next = ListEntry; + ReleaseSRWLockExclusive(&ListHead->LockSRW); + return e; +} + +// ---------------------------------------------------------------------------- +// VARIOUS FUNCTIONALITY BELOW: +// ---------------------------------------------------------------------------- + +errno_t tmpnam_s(char *_Buffer, ssize_t _Size) +{ + if(_Size < 32) { return -1; } + snprintf(_Buffer, _Size, "/tmp/vmm-%x%x", (uint32_t)((uint64_t)_Buffer >> 12), rand()); + return 0; +} + +#endif /* LINUX */ diff --git a/m_vmemd/oscompatibility.h b/m_vmemd/oscompatibility.h new file mode 100644 index 0000000..efe85c8 --- /dev/null +++ b/m_vmemd/oscompatibility.h @@ -0,0 +1,571 @@ +// oscompatibility.h : VMM Windows/Linux compatibility layer. +// +// (c) Ulf Frisk, 2021-2022 +// Author: Ulf Frisk, pcileech@frizk.net +// +#ifndef __OSCOMPATIBILITY_H__ +#define __OSCOMPATIBILITY_H__ +#include +#include "vmmdll.h" + +#ifdef _WIN32 + +#include +#include +#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) +#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L) +#define STATUS_END_OF_FILE ((NTSTATUS)0xC0000011L) +#define STATUS_FILE_INVALID ((NTSTATUS)0xC0000098L) +#define STATUS_FILE_SYSTEM_LIMITATION ((NTSTATUS)0xC0000427L) +typedef unsigned __int64 QWORD, *PQWORD; + +#endif /* _WIN32 */ +#ifdef LINUX +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LC_LIBRARY_FILETYPE ".so" + +typedef void VOID, *PVOID, *LPVOID; +typedef void *HANDLE, **PHANDLE, *HMODULE, *FARPROC; +typedef uint32_t BOOL, *PBOOL; +typedef uint8_t BYTE, *PBYTE, *LPBYTE; +typedef uint8_t UCHAR, *PUCHAR; +typedef char CHAR, *PCHAR, *PSTR, *LPSTR; +typedef int16_t SHORT, *PSHORT; +typedef int32_t UINT, LONG; +typedef int64_t LONGLONG; +typedef uint16_t WORD, *PWORD, USHORT, *PUSHORT; +typedef uint16_t WCHAR, *PWCHAR, *LPWSTR, *LPCWSTR; +typedef uint32_t DWORD, *PDWORD, *LPDWORD, NTSTATUS, ULONG, *PULONG, ULONG32; +typedef long long unsigned int QWORD, *PQWORD, ULONG64, *PULONG64, ULONG_PTR; +typedef uint64_t DWORD64, *PDWORD64, LARGE_INTEGER, *PLARGE_INTEGER, ULONGLONG, FILETIME, *PFILETIME; +typedef size_t SIZE_T, *PSIZE_T; +typedef struct _M128A { ULONGLONG Low; LONGLONG High; } M128A, *PM128A; +typedef void *OVERLAPPED, *LPOVERLAPPED; +typedef struct tdEXCEPTION_RECORD32 { CHAR sz[80]; } EXCEPTION_RECORD32; +typedef struct tdEXCEPTION_RECORD64 { CHAR sz[152]; } EXCEPTION_RECORD64; +typedef struct tdSID { BYTE pb[12]; } SID, *PSID; +typedef DWORD(*PTHREAD_START_ROUTINE)(PVOID); +typedef DWORD(*LPTHREAD_START_ROUTINE)(PVOID); +typedef int(*_CoreCrtNonSecureSearchSortCompareFunction)(void const *, void const *); +#define WINAPI +#define errno_t int +#define CONST const +#define TRUE 1 +#define FALSE 0 +#define MAX_PATH 260 +#define LMEM_ZEROINIT 0x0040 +#define INVALID_HANDLE_VALUE ((HANDLE)-1) +#define STD_INPUT_HANDLE ((DWORD)-10) +#define STD_OUTPUT_HANDLE ((DWORD)-11) +#define GENERIC_WRITE (0x40000000L) +#define GENERIC_READ (0x80000000L) +#define FILE_SHARE_READ (0x00000001L) +#define CREATE_NEW (0x00000001L) +#define OPEN_EXISTING (0x00000003L) +#define FILE_ATTRIBUTE_NORMAL (0x00000080L) +#define STILL_ACTIVE (0x00000103L) +#define CRYPT_STRING_HEX_ANY (0x00000008L) +#define CRYPT_STRING_HEXASCIIADDR (0x00000008L) +#define STILL_ACTIVE (0x00000103L) +#define INVALID_FILE_SIZE (0xffffffffL) +#define _TRUNCATE ((SIZE_T)-1LL) +#define HEAP_ZERO_MEMORY 0x00000008 +#define CONSOLE_SCREEN_BUFFER_INFO PVOID // TODO: remove this dummy +#define SOCKET int +#define INVALID_SOCKET -1 +#define SOCKET_ERROR -1 +#define WSAEWOULDBLOCK 10035L +#define WAIT_OBJECT_0 (0x00000000UL) +#define INFINITE (0xFFFFFFFFUL) +#define MAXIMUM_WAIT_OBJECTS 64 +#define SID_MAX_SUB_AUTHORITIES (15) +#define SECURITY_MAX_SID_SIZE (sizeof(SID) - sizeof(DWORD) + (SID_MAX_SUB_AUTHORITIES * sizeof(DWORD))) +#define CP_ACP 0 +#define CP_UTF8 65001 +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 +#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) +#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L) +#define STATUS_END_OF_FILE ((NTSTATUS)0xC0000011L) +#define STATUS_FILE_INVALID ((NTSTATUS)0xC0000098L) +#define STATUS_FILE_SYSTEM_LIMITATION ((NTSTATUS)0xC0000427L) + +//----------------------------------------------------------------------------- +// SAL DEFINES BELOW: +//----------------------------------------------------------------------------- +#define _In_ +#define _In_z_ +#define _Out_ +#define _Inout_ +#define _Inout_opt_ +#define _In_opt_ +#define _In_opt_z_ +#define _Out_opt_ +#define _Check_return_opt_ +#define _Frees_ptr_opt_ +#define _Post_ptr_invalid_ +#define _Printf_format_string_ +#define _In_reads_(x) +#define _In_reads_opt_(x) +#define _Out_writes_(x) +#define __bcount(x) +#define _Inout_bytecount_(x) +#define _Inout_count_(x) +#define _Inout_updates_(x) +#define _Inout_updates_opt_(x) +#define _Inout_updates_bytes_(x) +#define _Out_writes_bytes_(x) +#define _Out_writes_bytes_opt_(x) +#define _Out_writes_opt_(x) +#define _Out_writes_to_(x,y) +#define _Out_writes_z_(x) +#define _Maybenull_ +#define _Success_(x) +#define _When_(x,y) +#define _Writable_bytes_(x) + +#define UNREFERENCED_PARAMETER(x) + +#define max(a, b) (((a) > (b)) ? (a) : (b)) +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#define _byteswap_ushort(v) (bswap_16(v)) +#define _byteswap_ulong(v) (bswap_32(v)) +#define _byteswap_uint64(v) (bswap_64(v)) +#ifndef _rotr +#define _rotr(v,c) ((((DWORD)v) >> ((DWORD)c) | (DWORD)((DWORD)v) << (32 - (DWORD)c))) +#endif /* _rotr */ +#define _rotr16(v,c) ((((WORD)v) >> ((WORD)c) | (WORD)((WORD)v) << (16 - (WORD)c))) +#define _rotr64(v,c) ((((QWORD)v) >> ((QWORD)c) | (QWORD)((QWORD)v) << (64 - (QWORD)c))) +#define _rotl64(v,c) ((QWORD)(((QWORD)v) << ((QWORD)c)) | (((QWORD)v) >> (64 - (QWORD)c))) +#define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0])) +#define sprintf_s(s, maxcount, ...) (snprintf(s, maxcount, __VA_ARGS__)) +#define strnlen_s(s, maxcount) (strnlen(s, maxcount)) +#define strcpy_s(dst, len, src) (strncpy(dst, src, len)) +#define strncpy_s(dst, len, src, srclen) (strncpy(dst, src, min((QWORD)(max(1, len)) - 1, (QWORD)(srclen)))) +#define strncat_s(dst, dstlen, src, srclen) (strncat(dst, src, min((((strlen(dst) + 1 >= (size_t)(dstlen)) || ((size_t)(dstlen) == 0)) ? 0 : ((size_t)(dstlen) - strlen(dst) - 1)), (size_t)(srclen)))) +#define strcat_s(dst, dstlen, src) (strncat_s(dst, dstlen, src, _TRUNCATE)) +#define _vsnprintf_s(dst, len, cnt, fmt, a) (vsnprintf(dst, min((QWORD)(len), (QWORD)(cnt)), fmt, a)) +#define _stricmp(s1, s2) (strcasecmp(s1, s2)) +#define _strnicmp(s1, s2, maxcount) (strncasecmp(s1, s2, maxcount)) +#define strtok_s(s, d, c) (strtok_r(s, d, c)) +#define _snprintf_s(s,l,c,...) (snprintf(s,min((QWORD)(l), (QWORD)(c)),__VA_ARGS__)) +#define sscanf_s(s, f, ...) (sscanf(s, f, __VA_ARGS__)) +#define SwitchToThread() (sched_yield()) +#define ExitThread(dwExitCode) (pthread_exit(dwExitCode)) +#define ExitProcess(c) (exit(c ? EXIT_SUCCESS : EXIT_FAILURE)) +#define Sleep(dwMilliseconds) (usleep(1000*dwMilliseconds)) +#define _fsopen(szFile, szMode, dwAttr) fopen(szFile, szMode) +#define fopen_s(ppFile, szFile, szAttr) ((*ppFile = fopen64(szFile, szAttr)) ? 0 : 1) +#define ZeroMemory(pb, cb) (memset(pb, 0, cb)) +#define _ftelli64(f) (ftello64(f)) +#define _fseeki64(f, o, w) (fseeko64(f, o, w)) +#define _chsize_s(fd, cb) (ftruncate64(fd, cb)) +#define _fileno(f) (fileno(f)) +#define InterlockedAdd64(p, v) (__sync_add_and_fetch(p, v)) +#define InterlockedIncrement64(p) (__sync_add_and_fetch(p, 1)) +#define InterlockedIncrement(p) (__sync_add_and_fetch_4(p, 1)) +#define InterlockedDecrement(p) (__sync_sub_and_fetch_4(p, 1)) +#define GetCurrentProcess() ((HANDLE)-1) +#define InetNtopA inet_ntop +#define closesocket(s) close(s) +#define FreeLibrary(h) +#define GetModuleHandleA(s) NULL +#define HeapAlloc(hHeap, dwFlags, dwBytes) malloc(dwBytes) + +HMODULE LoadLibraryA(LPSTR lpFileName); +FARPROC GetProcAddress(HMODULE hModule, LPSTR lpProcName); + +// CRITICAL SECTION +#ifndef _LINUX_DEF_CRITICAL_SECTION +#define _LINUX_DEF_CRITICAL_SECTION +typedef struct tdCRITICAL_SECTION { + pthread_mutex_t mutex; + pthread_mutexattr_t mta; +} CRITICAL_SECTION, *LPCRITICAL_SECTION; +#endif /* _LINUX_DEF_CRITICAL_SECTION */ +BOOL InitializeCriticalSectionAndSpinCount(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount); +VOID InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection); +VOID DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection); +VOID EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection); +VOID LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection); + +typedef struct _SYSTEMTIME { + WORD wYear; + WORD wMonth; + WORD wDayOfWeek; + WORD wDay; + WORD wHour; + WORD wMinute; + WORD wSecond; + WORD wMilliseconds; +} SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME; + +typedef struct _WIN32_FIND_DATAA { + CHAR __cExtension[5]; + CHAR cFileName[MAX_PATH]; +} WIN32_FIND_DATAA, *PWIN32_FIND_DATAA, *LPWIN32_FIND_DATAA; + +HANDLE FindFirstFileA(LPSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData); +BOOL FindNextFileA(HANDLE hFindFile, LPWIN32_FIND_DATAA lpFindFileData); +HANDLE LocalAlloc(DWORD uFlags, SIZE_T uBytes); +VOID LocalFree(HANDLE hMem); +QWORD GetTickCount64(); +BOOL QueryPerformanceFrequency(_Out_ LARGE_INTEGER *lpFrequency); +BOOL QueryPerformanceCounter(_Out_ LARGE_INTEGER *lpPerformanceCount); +VOID GetLocalTime(LPSYSTEMTIME lpSystemTime); +DWORD InterlockedAdd(DWORD *Addend, DWORD Value); +BOOL GetExitCodeThread(_In_ HANDLE hThread, _Out_ LPDWORD lpExitCode); +BOOL FileTimeToSystemTime(_In_ PFILETIME lpFileTime, _Out_ PSYSTEMTIME lpSystemTime); +VOID GetSystemTimeAsFileTime(PFILETIME lpSystemTimeAsFileTime); +errno_t tmpnam_s(char *_Buffer, ssize_t _Size); + +HANDLE CreateThread( + PVOID lpThreadAttributes, + SIZE_T dwStackSize, + PVOID lpStartAddress, + PVOID lpParameter, + DWORD dwCreationFlags, + PDWORD lpThreadId +); + +BOOL CloseHandle(_In_ HANDLE hObject); +BOOL ResetEvent(_In_ HANDLE hEventIngestPhys); +BOOL SetEvent(_In_ HANDLE hEventIngestPhys); +HANDLE CreateEvent(_In_opt_ PVOID lpEventAttributes, _In_ BOOL bManualReset, _In_ BOOL bInitialState, _In_opt_ PVOID lpName); +DWORD WaitForMultipleObjects(_In_ DWORD nCount, HANDLE *lpHandles, _In_ BOOL bWaitAll, _In_ DWORD dwMilliseconds); +DWORD WaitForSingleObject(_In_ HANDLE hHandle, _In_ DWORD dwMilliseconds); + +// for some unexplainable reasons the gcc on -O2 will optimize out functionality +// and destroy the proper workings on some functions due to an unexplainable +// reason disable optimization on a function level resolves the issues ... +#define LINUX_NO_OPTIMIZE __attribute__((optimize("O0"))) + +#define CONTAINING_RECORD(address, type, field) ((type *)( \ + (PCHAR)(address) - \ + (ULONG_PTR)(&((type *)0)->field))) + +typedef struct _IMAGE_DEBUG_DIRECTORY { + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD Type; + DWORD SizeOfData; + DWORD AddressOfRawData; + DWORD PointerToRawData; +} IMAGE_DEBUG_DIRECTORY, *PIMAGE_DEBUG_DIRECTORY; + +#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 +#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 +#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 +#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 +#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 +#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 +#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 +#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 +#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 +#define IMAGE_DIRECTORY_ENTRY_TLS 9 +#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 +#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 +#define IMAGE_DIRECTORY_ENTRY_IAT 12 +#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 +#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 + +#define IMAGE_DOS_SIGNATURE 0x5A4D +#define IMAGE_NT_SIGNATURE 0x00004550 +#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b +#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b +#define IMAGE_DEBUG_TYPE_CODEVIEW 2 + +typedef struct _IMAGE_DOS_HEADER { + WORD e_magic; + WORD e_cblp; + WORD e_cp; + WORD e_crlc; + WORD e_cparhdr; + WORD e_minalloc; + WORD e_maxalloc; + WORD e_ss; + WORD e_sp; + WORD e_csum; + WORD e_ip; + WORD e_cs; + WORD e_lfarlc; + WORD e_ovno; + WORD e_res[4]; + WORD e_oemid; + WORD e_oeminfo; + WORD e_res2[10]; + LONG e_lfanew; +} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; + +typedef struct _IMAGE_FILE_HEADER { + WORD Machine; + WORD NumberOfSections; + DWORD TimeDateStamp; + DWORD PointerToSymbolTable; + DWORD NumberOfSymbols; + WORD SizeOfOptionalHeader; + WORD Characteristics; +} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; + +typedef struct _IMAGE_OPTIONAL_HEADER { + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + DWORD BaseOfData; + DWORD ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + DWORD SizeOfStackReserve; + DWORD SizeOfStackCommit; + DWORD SizeOfHeapReserve; + DWORD SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; + +typedef struct _IMAGE_OPTIONAL_HEADER64 { + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + ULONGLONG ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + ULONGLONG SizeOfStackReserve; + ULONGLONG SizeOfStackCommit; + ULONGLONG SizeOfHeapReserve; + ULONGLONG SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64; + +typedef struct _IMAGE_NT_HEADERS64 { + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER64 OptionalHeader; +} IMAGE_NT_HEADERS, IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS64; + +typedef struct _IMAGE_NT_HEADERS { + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER32 OptionalHeader; +} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32; + +typedef struct _IMAGE_EXPORT_DIRECTORY { + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD Name; + DWORD Base; + DWORD NumberOfFunctions; + DWORD NumberOfNames; + DWORD AddressOfFunctions; + DWORD AddressOfNames; + DWORD AddressOfNameOrdinals; +} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; + +typedef struct _IMAGE_IMPORT_DESCRIPTOR { + union { + DWORD Characteristics; + DWORD OriginalFirstThunk; + }; + DWORD TimeDateStamp; + DWORD ForwarderChain; + DWORD Name; + DWORD FirstThunk; +} IMAGE_IMPORT_DESCRIPTOR, *PIMAGE_IMPORT_DESCRIPTOR; + +#define REG_NONE ( 0ul ) +#define REG_SZ ( 1ul ) +#define REG_EXPAND_SZ ( 2ul ) +#define REG_BINARY ( 3ul ) +#define REG_DWORD ( 4ul ) +#define REG_DWORD_LITTLE_ENDIAN ( 4ul ) +#define REG_DWORD_BIG_ENDIAN ( 5ul ) +#define REG_LINK ( 6ul ) +#define REG_MULTI_SZ ( 7ul ) +#define REG_RESOURCE_LIST ( 8ul ) +#define REG_FULL_RESOURCE_DESCRIPTOR ( 9ul ) +#define REG_RESOURCE_REQUIREMENTS_LIST ( 10ul ) +#define REG_QWORD ( 11ul ) +#define REG_QWORD_LITTLE_ENDIAN ( 11ul ) + +typedef enum _SID_NAME_USE { + SidTypeUser = 1, + SidTypeGroup, + SidTypeDomain, + SidTypeAlias, + SidTypeWellKnownGroup, + SidTypeDeletedAccount, + SidTypeInvalid, + SidTypeUnknown, + SidTypeComputer, + SidTypeLabel, + SidTypeLogonSession +} SID_NAME_USE, *PSID_NAME_USE; + +typedef struct _LIST_ENTRY { + struct _LIST_ENTRY *Flink; + struct _LIST_ENTRY *Blink; +} LIST_ENTRY, *PLIST_ENTRY; + +typedef struct LIST_ENTRY32 { + DWORD Flink; + DWORD Blink; +} LIST_ENTRY32; +typedef LIST_ENTRY32 *PLIST_ENTRY32; + +typedef struct LIST_ENTRY64 { + ULONGLONG Flink; + ULONGLONG Blink; +} LIST_ENTRY64; +typedef LIST_ENTRY64 *PLIST_ENTRY64; + + + + + + + + +#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 +#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 +#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 +#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 +#define IMAGE_SCN_MEM_SHARED 0x10000000 +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 +#define IMAGE_SCN_MEM_READ 0x40000000 +#define IMAGE_SCN_MEM_WRITE 0x80000000 + +#define SERVICE_KERNEL_DRIVER 0x00000001 +#define SERVICE_FILE_SYSTEM_DRIVER 0x00000002 +#define SERVICE_ADAPTER 0x00000004 +#define SERVICE_RECOGNIZER_DRIVER 0x00000008 +#define SERVICE_DRIVER (SERVICE_KERNEL_DRIVER | \ + SERVICE_FILE_SYSTEM_DRIVER | \ + SERVICE_RECOGNIZER_DRIVER) +#define SERVICE_WIN32_OWN_PROCESS 0x00000010 +#define SERVICE_WIN32_SHARE_PROCESS 0x00000020 +#define SERVICE_WIN32 (SERVICE_WIN32_OWN_PROCESS | \ + SERVICE_WIN32_SHARE_PROCESS) +#define SERVICE_USER_SERVICE 0x00000040 +#define SERVICE_USERSERVICE_INSTANCE 0x00000080 +#define SERVICE_USER_SHARE_PROCESS (SERVICE_USER_SERVICE | \ + SERVICE_WIN32_SHARE_PROCESS) +#define SERVICE_USER_OWN_PROCESS (SERVICE_USER_SERVICE | \ + SERVICE_WIN32_OWN_PROCESS) +#define SERVICE_INTERACTIVE_PROCESS 0x00000100 +#define SERVICE_PKG_SERVICE 0x00000200 +#define SERVICE_TYPE_ALL (SERVICE_WIN32 | \ + SERVICE_ADAPTER | \ + SERVICE_DRIVER | \ + SERVICE_INTERACTIVE_PROCESS | \ + SERVICE_USER_SERVICE | \ + SERVICE_USERSERVICE_INSTANCE | \ + SERVICE_PKG_SERVICE) + + + + + + + + + + +// SRWLOCK +typedef struct tdSRWLOCK { + uint32_t xchg; + int c; +} SRWLOCK, *PSRWLOCK; +VOID InitializeSRWLock(PSRWLOCK SRWLock); +VOID AcquireSRWLockExclusive(_Inout_ PSRWLOCK SRWLock); +VOID ReleaseSRWLockExclusive(_Inout_ PSRWLOCK SRWLock); +#define AcquireSRWLockShared AcquireSRWLockExclusive +#define ReleaseSRWLockShared ReleaseSRWLockExclusive +#define SRWLOCK_INIT { 0 } + + + + + + + +typedef struct _SLIST_ENTRY { + struct _SLIST_ENTRY *Next; +} SLIST_ENTRY, *PSLIST_ENTRY; + +typedef struct _SLIST_HEADER { + PSLIST_ENTRY Next; + SRWLOCK LockSRW; + USHORT c; +} SLIST_HEADER, *PSLIST_HEADER; + +VOID InitializeSListHead(PSLIST_HEADER ListHead); +USHORT QueryDepthSList(PSLIST_HEADER ListHead); +PSLIST_ENTRY InterlockedPopEntrySList(_Inout_ PSLIST_HEADER ListHead); +PSLIST_ENTRY InterlockedPushEntrySList(_Inout_ PSLIST_HEADER ListHead, _Inout_ PSLIST_ENTRY ListEntry); + +#endif /* LINUX */ + + + +#endif /* __OSCOMPATIBILITY_H__ */ diff --git a/m_vmemd/version.h b/m_vmemd/version.h index 1ca559c..caa4943 100644 --- a/m_vmemd/version.h +++ b/m_vmemd/version.h @@ -1,10 +1,10 @@ #define STRINGIZE2(s) #s #define STRINGIZE(s) STRINGIZE2(s) -#define VERSION_MAJOR 4 -#define VERSION_MINOR 9 -#define VERSION_REVISION 3 -#define VERSION_BUILD 72 +#define VERSION_MAJOR 5 +#define VERSION_MINOR 0 +#define VERSION_REVISION 0 +#define VERSION_BUILD 73 #define VER_FILE_DESCRIPTION_STR "MemProcFS : Plugin vmemd" #define VER_FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_BUILD diff --git a/memprocfs/memprocfs_dokan.c b/memprocfs/memprocfs_dokan.c index 4b2e1f4..6aa57ad 100644 --- a/memprocfs/memprocfs_dokan.c +++ b/memprocfs/memprocfs_dokan.c @@ -35,6 +35,7 @@ typedef struct tdVMMVFS_CONFIG { PVMMVFS_CONFIG ctxVfs; HANDLE g_hLC_RemoteFS; +VMM_HANDLE g_hVMM; CHAR g_VfsMountPoint = 'M'; @@ -62,7 +63,7 @@ _Success_(return) BOOL MemProcFS_VfsListU(_In_ LPSTR uszPath, _Inout_ PVMMDLL_VF PVMMDLL_VFS_FILELISTBLOB pVfsList; PVMMDLL_VFS_FILELISTBLOB_ENTRY pe; if(!g_hLC_RemoteFS) { - return VMMDLL_VfsListU(uszPath, pFileList); + return VMMDLL_VfsListU(g_hVMM, uszPath, pFileList); } ZeroMemory(&Req, sizeof(LC_CMD_AGENT_VFS_REQ)); Req.dwVersion = LC_CMD_AGENT_VFS_REQ_VERSION; @@ -99,7 +100,7 @@ NTSTATUS MemProcFS_VfsReadW(_In_ LPWSTR wszFileName, _Out_writes_to_(cb, *pcbRea LC_CMD_AGENT_VFS_REQ Req; PLC_CMD_AGENT_VFS_RSP pRsp = NULL; if(!g_hLC_RemoteFS) { - return VMMDLL_VfsReadW(wszFileName, pb, cb, pcbRead, cbOffset); + return VMMDLL_VfsReadW(g_hVMM, wszFileName, pb, cb, pcbRead, cbOffset); } // Remote MemProcFS below: ZeroMemory(&Req, sizeof(LC_CMD_AGENT_VFS_REQ)); @@ -132,7 +133,7 @@ NTSTATUS MemProcFS_VfsWriteW(_In_ LPWSTR wszFileName, _In_reads_(cb) PBYTE pb, _ PLC_CMD_AGENT_VFS_REQ pReq = NULL; PLC_CMD_AGENT_VFS_RSP pRsp = NULL; if(!g_hLC_RemoteFS) { - return VMMDLL_VfsWriteW(wszFileName, pb, cb, pcbWrite, cbOffset); + return VMMDLL_VfsWriteW(g_hVMM, wszFileName, pb, cb, pcbWrite, cbOffset); } // Remote MemProcFS below: *pcbWrite = 0; @@ -170,7 +171,7 @@ BOOL MemProcFS_ConfigGet(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue) PLC_CMD_AGENT_VFS_RSP pRsp = NULL; *pqwValue = 0; if(!g_hLC_RemoteFS) { - return VMMDLL_ConfigGet(fOption, pqwValue); + return VMMDLL_ConfigGet(g_hVMM, fOption, pqwValue); } // Remote MemProcFS below: Req.dwVersion = LC_CMD_AGENT_VFS_REQ_VERSION; @@ -199,7 +200,7 @@ BOOL MemProcFS_ConfigSet(_In_ ULONG64 fOption, _In_ ULONG64 qwValue) BOOL fResult; PLC_CMD_AGENT_VFS_REQ pReq = NULL; if(!g_hLC_RemoteFS) { - return VMMDLL_ConfigSet(fOption, qwValue); + return VMMDLL_ConfigSet(g_hVMM, fOption, qwValue); } // Remote MemProcFS below: if(!(pReq = LocalAlloc(LMEM_ZEROINIT, sizeof(LC_CMD_AGENT_VFS_REQ) + sizeof(QWORD)))) { return FALSE; } @@ -539,7 +540,7 @@ DWORD WINAPI MemProcFsCtrlHandler_TryShutdownThread(PVOID pv) LcClose(g_hLC_RemoteFS); g_hLC_RemoteFS = NULL; } else { - VMMDLL_Close(); + VMMDLL_Close(g_hVMM); } } __except(EXCEPTION_EXECUTE_HANDLER) { ; } return 1; @@ -654,13 +655,13 @@ int main(_In_ int argc, _In_ char* argv[]) if(argc > 2) { szArgs[argc++] = "-userinteract"; } - result = VMMDLL_Initialize(argc, szArgs); - if(!result) { + g_hVMM = VMMDLL_Initialize(argc, szArgs); + if(!g_hVMM) { // any error message will already be shown by the InitializeReserved function. return 1; } - VMMDLL_ConfigSet(VMMDLL_OPT_CONFIG_STATISTICS_FUNCTIONCALL, 1); - result = VMMDLL_InitializePlugins(); + VMMDLL_ConfigSet(g_hVMM, VMMDLL_OPT_CONFIG_STATISTICS_FUNCTIONCALL, 1); + result = VMMDLL_InitializePlugins(g_hVMM); if(!result) { printf("MemProcFS: Error file system plugins in vmm.dll!\n"); return 1; diff --git a/memprocfs/memprocfs_fuse.c b/memprocfs/memprocfs_fuse.c index f0470b1..794ff6d 100644 --- a/memprocfs/memprocfs_fuse.c +++ b/memprocfs/memprocfs_fuse.c @@ -12,6 +12,8 @@ #define FUSE_USE_VERSION 30 #include +VMM_HANDLE g_hVMM = NULL; + //----------------------------------------------------------------------------- // FUSE FILE SYSTEM FUNCTIONALITY BELOW: //----------------------------------------------------------------------------- @@ -88,7 +90,7 @@ static int vfs_read(const char *uszPath, char *buffer, size_t size, off_t offset if(c == '/') { uszPathCopy[i - 1] = '\\'; } } // 2: read - nt = VMMDLL_VfsReadU((LPSTR)uszPathCopy, (PBYTE)buffer, size, &readlength, offset); + nt = VMMDLL_VfsReadU(g_hVMM, (LPSTR)uszPathCopy, (PBYTE)buffer, size, &readlength, offset); return ((nt == VMMDLL_STATUS_SUCCESS) || (nt == VMMDLL_STATUS_END_OF_FILE)) ? (int)readlength : 0; } @@ -109,7 +111,7 @@ static int vfs_write(const char *uszPath, const char *buffer, size_t size, off_t if(c == '/') { uszPathCopy[i - 1] = '\\'; } } // 2: write - nt = VMMDLL_VfsWriteU((LPSTR)uszPathCopy, (PBYTE)buffer, size, &writelength, offset); + nt = VMMDLL_VfsWriteU(g_hVMM, (LPSTR)uszPathCopy, (PBYTE)buffer, size, &writelength, offset); return ((nt == VMMDLL_STATUS_SUCCESS) || (nt == VMMDLL_STATUS_END_OF_FILE)) ? (int)size : 0; } @@ -128,6 +130,27 @@ int vfs_initialize_and_mount_displayinfo(int argc, char *argv[]) +//----------------------------------------------------------------------------- +// LOCAL/REMOTE WRAPPER FUNCTIONS BELOW: +//----------------------------------------------------------------------------- + +/* +* WRAPPER FUNCTION AROUND LOCAL/REMOTE VMMDLL_VfsListU +* List a directory of files in MemProcFS. Directories and files will be listed +* by callbacks into functions supplied in the pFileList parameter. +* If information of an individual file is needed it's neccessary to list all +* files in its directory. +* -- uszPath +* -- pFileList +* -- return +*/ +_Success_(return) BOOL MemProcFS_VfsListU(_In_ LPSTR uszPath, _Inout_ PVMMDLL_VFS_FILELIST2 pFileList) +{ + return VMMDLL_VfsListU(g_hVMM, uszPath, pFileList); +} + + + //----------------------------------------------------------------------------- // GENERAL INITIALIZATION FUNCTIONALITY BELOW: //----------------------------------------------------------------------------- @@ -161,15 +184,15 @@ VOID Vfs_InitializeAndMount_DisplayInfo(_In_ LPSTR uszMountPoint) ULONG64 qwVersionWinMajor = 0, qwVersionWinMinor = 0, qwVersionWinBuild = 0; ULONG64 qwUniqueSystemId = 0, iMemoryModel; // get vmm.dll versions - VMMDLL_ConfigGet(VMMDLL_OPT_CONFIG_VMM_VERSION_MAJOR, &qwVersionVmmMajor); - VMMDLL_ConfigGet(VMMDLL_OPT_CONFIG_VMM_VERSION_MINOR, &qwVersionVmmMinor); - VMMDLL_ConfigGet(VMMDLL_OPT_CONFIG_VMM_VERSION_REVISION, &qwVersionVmmRevision); + VMMDLL_ConfigGet(g_hVMM, VMMDLL_OPT_CONFIG_VMM_VERSION_MAJOR, &qwVersionVmmMajor); + VMMDLL_ConfigGet(g_hVMM, VMMDLL_OPT_CONFIG_VMM_VERSION_MINOR, &qwVersionVmmMinor); + VMMDLL_ConfigGet(g_hVMM, VMMDLL_OPT_CONFIG_VMM_VERSION_REVISION, &qwVersionVmmRevision); // get operating system versions - VMMDLL_ConfigGet(VMMDLL_OPT_CORE_MEMORYMODEL, &iMemoryModel); - VMMDLL_ConfigGet(VMMDLL_OPT_WIN_VERSION_MAJOR, &qwVersionWinMajor); - VMMDLL_ConfigGet(VMMDLL_OPT_WIN_VERSION_MINOR, &qwVersionWinMinor); - VMMDLL_ConfigGet(VMMDLL_OPT_WIN_VERSION_BUILD, &qwVersionWinBuild); - VMMDLL_ConfigGet(VMMDLL_OPT_WIN_SYSTEM_UNIQUE_ID, &qwUniqueSystemId); + VMMDLL_ConfigGet(g_hVMM, VMMDLL_OPT_CORE_MEMORYMODEL, &iMemoryModel); + VMMDLL_ConfigGet(g_hVMM, VMMDLL_OPT_WIN_VERSION_MAJOR, &qwVersionWinMajor); + VMMDLL_ConfigGet(g_hVMM, VMMDLL_OPT_WIN_VERSION_MINOR, &qwVersionWinMinor); + VMMDLL_ConfigGet(g_hVMM, VMMDLL_OPT_WIN_VERSION_BUILD, &qwVersionWinBuild); + VMMDLL_ConfigGet(g_hVMM, VMMDLL_OPT_WIN_SYSTEM_UNIQUE_ID, &qwUniqueSystemId); printf("\n" \ "=============== MemProcFS - THE MEMORY PROCESS FILE SYSTEM ===============\n" \ " - Author: Ulf Frisk - pcileech@frizk.net \n" \ @@ -208,7 +231,6 @@ int main(_In_ int argc, _In_ char* argv[]) { // MAIN FUNCTION PROPER BELOW: int i; - BOOL result; LPSTR szMountPoint = NULL, *szArgs = NULL; GetMountPoint(argc, argv, &szMountPoint); if(!szMountPoint || (szMountPoint[0] != '/')) { @@ -223,18 +245,17 @@ int main(_In_ int argc, _In_ char* argv[]) szArgs[i] = argv[i]; } szArgs[0] = "-printf"; - result = VMMDLL_Initialize(argc, szArgs); - if(!result) { + g_hVMM = VMMDLL_Initialize(argc, szArgs); + if(!g_hVMM) { // any error message will already be shown by the InitializeReserved function. return 1; } - VMMDLL_ConfigSet(VMMDLL_OPT_CONFIG_STATISTICS_FUNCTIONCALL, 1); - result = VMMDLL_InitializePlugins(); - if(!result) { + VMMDLL_ConfigSet(g_hVMM, VMMDLL_OPT_CONFIG_STATISTICS_FUNCTIONCALL, 1); + if(!VMMDLL_InitializePlugins(g_hVMM)) { printf("MemProcFS: Error file system plugins in vmm.dll!\n"); return 1; } - VfsList_Initialize(VMMDLL_VfsListU, 500, 128, FALSE); + VfsList_Initialize(MemProcFS_VfsListU, 500, 128, FALSE); Vfs_InitializeAndMount_DisplayInfo(szMountPoint); // hand over control to FUSE. LPSTR szArgListFuse[] = { argv[0], szMountPoint, "-f" }; diff --git a/memprocfs/version.h b/memprocfs/version.h index 6ca48d5..86ba8b9 100644 --- a/memprocfs/version.h +++ b/memprocfs/version.h @@ -1,10 +1,10 @@ #define STRINGIZE2(s) #s #define STRINGIZE(s) STRINGIZE2(s) -#define VERSION_MAJOR 4 -#define VERSION_MINOR 9 -#define VERSION_REVISION 3 -#define VERSION_BUILD 72 +#define VERSION_MAJOR 5 +#define VERSION_MINOR 0 +#define VERSION_REVISION 0 +#define VERSION_BUILD 73 #define VER_FILE_DESCRIPTION_STR "MemProcFS" #define VER_FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_BUILD diff --git a/memprocfs/vfslist.c b/memprocfs/vfslist.c index 56a2abb..5044c24 100644 --- a/memprocfs/vfslist.c +++ b/memprocfs/vfslist.c @@ -363,3 +363,4 @@ BOOL VfsList_Initialize(_In_ VFS_LIST_U_PFN pfnVfsListU, _In_ DWORD dwCacheValid #endif /* _WIN32 */ return TRUE; } + diff --git a/vmm/Makefile b/vmm/Makefile index 7cb5f65..06a53e9 100644 --- a/vmm/Makefile +++ b/vmm/Makefile @@ -13,22 +13,24 @@ CFLAGS += -Wall -Wno-format-truncation -Wno-enum-compare -Wno-pointer-sign -Wno CFLAGS += -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast LDFLAGS += -Wl,-rpath,'$$ORIGIN' -g -ldl -shared DEPS = vmmdll.h -OBJ = oscompatibility.o charutil.o util.o pe.o vmmdll.o vmmdll_scatter.o \ +OBJ = oscompatibility.o charutil.o util.o pe.o vmmdll.o vmmdll_core.o vmmdll_scatter.o \ vmm.o mm_x64.o mm_x86.o mm_x86pae.o mm_pfn.o mm_vad.o mm_win.o fc.o \ pluginmanager.o pdb.o infodb.o sqlite/sqlite3.o \ ob/ob_cachemap.o ob/ob_compressed.o ob/ob_container.o ob/ob_core.o \ ob/ob_counter.o ob/ob_map.o ob/ob_memfile.o ob/ob_set.o ob/ob_strmap.o \ statistics.o sysquery.o vmmevil.o vmmheap.o vmmlog.o vmmnet.o \ vmmproc.o vmmwininit.o vmmwin.o vmmwinobj.o vmmwinpool.o vmmwinreg.o \ - vmmwinsvc.o \ + vmmwinsvc.o vmmwork.o \ m_vfsfc.o m_vfsproc.o m_vfsroot.o m_conf.o m_winreg.o \ - m_fc_json.o m_fc_module.o m_fc_ntfs.o m_fc_proc.o m_fc_registry.o \ - m_fc_thread.o m_fc_timeline.o m_file_handles_vads.o m_file_modules.o \ + m_fc_csv.o m_fc_handle.o m_fc_json.o m_fc_module.o m_fc_ntfs.o \ + m_fc_proc.o m_fc_registry.o m_fc_sys.o m_fc_thread.o m_fc_timeline.o \ + m_file_handles_vads.o m_file_modules.o \ m_findevil.o m_misc_bitlocker.o m_misc_web.o m_phys2virt.o \ m_proc_handle.o m_proc_heap.o m_proc_ldrmodules.o m_proc_memmap.o \ m_proc_minidump.o m_proc_thread.o m_search.o \ m_sys.o m_sys_driver.o m_sys_mem.o m_sys_net.o m_sys_obj.o \ - m_sys_pool.c m_sys_proc.o m_sys_svc.o m_sys_task.o m_virt2phys.o + m_sys_pool.c m_sys_proc.o m_sys_svc.o m_sys_task.o m_sys_user.o \ + m_virt2phys.o %.o: %.c $(DEPS) $(CC) -c -o $@ $< $(CFLAGS) diff --git a/vmm/charutil.c b/vmm/charutil.c index abb67f5..e5c6b75 100644 --- a/vmm/charutil.c +++ b/vmm/charutil.c @@ -699,6 +699,104 @@ fail: return FALSE; } +/* +* Convert UTF-8 string into a CSV compatible string. +* If source string contain either comma(,) space( ) doublequote(") it will be +* treated as a CSV string and be put into double quotes at start/end. +* Function support usz == pbBuffer - usz will then become overwritten. +* CALLER LOCALFREE (if *pvsz != pbBuffer): *pvsz +* -- usz = the string to convert. +* -- cch = -1 for null-terminated string; or max number of chars (excl. null). +* -- pbBuffer = optional buffer to place the result in. +* -- cbBuffer +* -- pvsz = if set to null: function calculate length only and return TRUE. + result utf-8 string, either as (*pvsz == pbBuffer) or LocalAlloc'ed +* buffer that caller is responsible for free. +* -- pcbv = byte length (including terminating null) of utf-8 string. +* -- flags = CHARUTIL_FLAG_NONE, CHARUTIL_FLAG_ALLOC or CHARUTIL_FLAG_TRUNCATE +* -- return +*/ +_Success_(return) +BOOL CharUtil_UtoCSV(_In_opt_ LPSTR usz, _In_ DWORD cch, _Maybenull_ _Writable_bytes_(cbBuffer) PBYTE pbBuffer, _In_ DWORD cbBuffer, _Out_opt_ LPSTR *pvsz, _Out_opt_ PDWORD pcbv, _In_ DWORD flags) +{ + UCHAR c; + LPSTR vsz; + DWORD iu, iv, n, cbu = 0, cbv = 0; + BOOL fCSV = FALSE; + BOOL fTruncate = flags & CHARUTIL_FLAG_TRUNCATE; + if(pcbv) { *pcbv = 0; } + if(pvsz) { *pvsz = NULL; } + if(!usz) { usz = ""; } + if(cch > CHARUTIL_CONVERT_MAXSIZE) { cch = CHARUTIL_CONVERT_MAXSIZE; } + // 1: utf-8 byte-length: + if(fTruncate && (!cbBuffer || (flags & CHARUTIL_FLAG_ALLOC))) { goto fail; } + while((cbu < cch) && (c = usz[cbu])) { + if(c & 0x80) { + // utf-8 char: + n = 0; + if((c & 0xe0) == 0xc0) { n = 2; } + if((c & 0xf0) == 0xe0) { n = 3; } + if((c & 0xf8) == 0xf0) { n = 4; } + if(!n) { goto fail; } // invalid char-encoding + if(cbu + n > cch) { break; } + if(fTruncate && (cbv + n >= cbBuffer)) { break; } + if((n > 1) && ((usz[cbu + 1] & 0xc0) != 0x80)) { goto fail; } // invalid char-encoding + if((n > 2) && ((usz[cbu + 2] & 0xc0) != 0x80)) { goto fail; } // invalid char-encoding + if((n > 3) && ((usz[cbu + 3] & 0xc0) != 0x80)) { goto fail; } // invalid char-encoding + cbu += n; + cbv += n; + } else if(c == '"' || c == ' ' || c == ',') { + n = (c == '"') ? 2 : 1; + if(!fCSV) { n += 2; } + if(fTruncate && (cbv + n >= cbBuffer)) { break; } + fCSV = TRUE; + cbu += 1; + cbv += n; + } else { + if(fTruncate && (cbv + 1 >= cbBuffer)) { break; } + cbu += 1; + cbv += 1; + } + } + cbu++; + cbv++; + if(pcbv) { *pcbv = cbv; } + // 2: return on length-request or alloc-fail + if(!pvsz) { + if(!(flags & CHARUTIL_FLAG_STR_BUFONLY)) { return TRUE; } // success: length request + if(flags & CHARUTIL_FLAG_ALLOC) { return FALSE; } + } + if(!(flags & CHARUTIL_FLAG_ALLOC) && (!pbBuffer || (cbBuffer < cbv))) { goto fail; } // fail: insufficient buffer space + vsz = (pbBuffer && (cbBuffer >= cbv)) ? pbBuffer : LocalAlloc(0, cbv); + if(!vsz) { goto fail; } // fail: failed buffer space allocation + // 3: populate with CSV UTF-8 string + iu = cbu - 2; iv = cbv - 2; + if(fCSV) { vsz[iv--] = '"'; } + while(iv < 0x7fffffff) { + if(!iv && fCSV) { + vsz[0] = '"'; + break; + } + c = usz[iu--]; + if(c == '"') { + vsz[iv--] = '"'; + } + if(c < 0x20) { + c = '?'; + } + vsz[iv--] = c; + } + vsz[cbv - 1] = 0; + if(pvsz) { *pvsz = vsz; } + return TRUE; +fail: + if(!(flags ^ CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR) && pbBuffer && cbBuffer) { + if(pvsz) { *pvsz = (LPSTR)pbBuffer; } + if(pcbv) { *pcbv = 1; } + pbBuffer[0] = 0; + } + return FALSE; +} @@ -1181,6 +1279,23 @@ BOOL CharUtil_StrEndsWith(_In_opt_ LPSTR usz, _In_opt_ LPSTR uszEndsWith, _In_ B (0 == strcmp(usz + cch - cchEndsWith, uszEndsWith)); } +/* +* Checks if a string starts with a certain substring. +* -- usz +* -- uszStartsWith +* -- fCaseInsensitive +* -- return +*/ +BOOL CharUtil_StrStartsWith(_In_opt_ LPSTR usz, _In_opt_ LPSTR uszStartsWith, _In_ BOOL fCaseInsensitive) +{ + if(!usz || !uszStartsWith) { return FALSE; } + if(fCaseInsensitive) { + return (0 == _strnicmp(usz, uszStartsWith, strlen(uszStartsWith))); + } else { + return (0 == strncmp(usz, uszStartsWith, strlen(uszStartsWith))); + } +} + /* * Compare a wide-char string to a utf-8 string. * NB! only the first 2*MAX_PATH characters are compared. diff --git a/vmm/charutil.h b/vmm/charutil.h index 860c943..a7932a7 100644 --- a/vmm/charutil.h +++ b/vmm/charutil.h @@ -160,6 +160,33 @@ BOOL CharUtil_WtoJ( _In_ DWORD flags ); +/* +* Convert UTF-8 string into a CSV compatible string. +* If source string contain either comma(,) space( ) doublequote(") it will be +* treated as a CSV string and be put into double quotes at start/end. +* Function support usz == pbBuffer - usz will then become overwritten. +* CALLER LOCALFREE (if *pvsz != pbBuffer): *pvsz +* -- usz = the string to convert. +* -- cch = -1 for null-terminated string; or max number of chars (excl. null). +* -- pbBuffer = optional buffer to place the result in. +* -- cbBuffer +* -- pvsz = if set to null: function calculate length only and return TRUE. + result utf-8 string, either as (*pvsz == pbBuffer) or LocalAlloc'ed +* buffer that caller is responsible for free. +* -- pcbv = byte length (including terminating null) of utf-8 string. +* -- flags = CHARUTIL_FLAG_NONE, CHARUTIL_FLAG_ALLOC or CHARUTIL_FLAG_TRUNCATE +* -- return +*/ +_Success_(return) +BOOL CharUtil_UtoCSV( + _In_opt_ LPSTR usz, + _In_ DWORD cch, + _Maybenull_ _Writable_bytes_(cbBuffer) PBYTE pbBuffer, + _In_ DWORD cbBuffer, + _Out_opt_ LPSTR *pvsz, + _Out_opt_ PDWORD pcbv, + _In_ DWORD flags); + /* * Hash a string quickly using the ROT13 algorithm either to a 64-bit or 32-bit number. * -- sz/usz/wsz = the string to hash @@ -299,6 +326,15 @@ LPSTR CharUtil_PathSplitLastEx(_In_ LPSTR usz, _Out_writes_(cbuPath) LPSTR uszPa */ BOOL CharUtil_StrEndsWith(_In_opt_ LPSTR usz, _In_opt_ LPSTR uszEndsWith, _In_ BOOL fCaseInsensitive); +/* +* Checks if a string starts with a certain substring. +* -- usz +* -- uszStartsWith +* -- fCaseInsensitive +* -- return +*/ +BOOL CharUtil_StrStartsWith(_In_opt_ LPSTR usz, _In_opt_ LPSTR uszStartsWith, _In_ BOOL fCaseInsensitive); + /* * Compare a wide-char string to a utf-8 string. * NB! only the first 2*MAX_PATH characters are compared. diff --git a/vmm/fc.c b/vmm/fc.c index 38d5c1e..51a8d50 100644 --- a/vmm/fc.c +++ b/vmm/fc.c @@ -27,15 +27,7 @@ static LPSTR FC_SQL_SCHEMA_STR = "DROP TABLE IF EXISTS str; " \ - "CREATE TABLE str ( id INTEGER PRIMARY KEY, cbu INT, cbj INT, sz TEXT ); "; - - - -// ---------------------------------------------------------------------------- -// FC global variable below: -// ---------------------------------------------------------------------------- - -PFC_CONTEXT ctxFc = NULL; + "CREATE TABLE str ( id INTEGER PRIMARY KEY, cbu INT, cbj INT, cbv INT, sz TEXT ); "; @@ -45,39 +37,42 @@ PFC_CONTEXT ctxFc = NULL; /* * Retrieve an SQLITE database handle. The retrieved handle must be -* returned with Fc_SqlReserveReturn(). +* returned with Fc_SqlReserveReturn(H, ). +* -- H * -- return = an SQLITE handle, or NULL on error. */ _Success_(return != NULL) -sqlite3* Fc_SqlReserve() +sqlite3* Fc_SqlReserve(_In_ VMM_HANDLE H) { DWORD iWaitNum = 0; - if(ctxFc->db.fSingleThread) { - WaitForSingleObject(ctxFc->db.hEvent[0], INFINITE); + if(H->fAbort) { return NULL; } + if(H->fc->db.fSingleThread) { + WaitForSingleObject(H->fc->db.hEventIngestPhys[0], INFINITE); } else { - iWaitNum = WaitForMultipleObjects(FC_SQL_POOL_CONNECTION_NUM, ctxFc->db.hEvent, FALSE, INFINITE) - WAIT_OBJECT_0; + iWaitNum = WaitForMultipleObjects(FC_SQL_POOL_CONNECTION_NUM, H->fc->db.hEventIngestPhys, FALSE, INFINITE) - WAIT_OBJECT_0; } if(iWaitNum >= FC_SQL_POOL_CONNECTION_NUM) { - VmmLog(MID_FORENSIC, LOGLEVEL_CRITICAL, "FATAL DATABASE ERROR: WaitForMultipleObjects ERROR: 0x%08x\n", (DWORD)(iWaitNum + WAIT_OBJECT_0)); + VmmLog(H, MID_FORENSIC, LOGLEVEL_CRITICAL, "FATAL DATABASE ERROR: WaitForMultipleObjects ERROR: 0x%08x", (DWORD)(iWaitNum + WAIT_OBJECT_0)); return NULL; } - return ctxFc->db.hSql[iWaitNum]; + return H->fc->db.hSql[iWaitNum]; } /* * Return a SQLITE database handle previously retrieved with Fc_SqlReserve() * so that other threads may use it. +* -- H * -- hSql = the SQLITE database handle. * -- return = always NULL. */ _Success_(return != NULL) -sqlite3* Fc_SqlReserveReturn(_In_opt_ sqlite3 *hSql) +sqlite3* Fc_SqlReserveReturn(_In_ VMM_HANDLE H, _In_opt_ sqlite3 *hSql) { DWORD i; if(!hSql) { return NULL; } for(i = 0; i < FC_SQL_POOL_CONNECTION_NUM; i++) { - if(ctxFc->db.hSql[i] == hSql) { - SetEvent(ctxFc->db.hEvent[i]); + if(H->fc->db.hSql[i] == hSql) { + SetEvent(H->fc->db.hEventIngestPhys[i]); break; } } @@ -86,17 +81,18 @@ sqlite3* Fc_SqlReserveReturn(_In_opt_ sqlite3 *hSql) /* * Execute a single SQLITE database SQL query and return the SQLITE result code. +* -- H * -- szSql * -- return = sqlite return code. */ _Success_(return == SQLITE_OK) -int Fc_SqlExec(_In_ LPSTR szSql) +int Fc_SqlExec(_In_ VMM_HANDLE H, _In_ LPSTR szSql) { int rc = SQLITE_ERROR; - sqlite3 *hSql = Fc_SqlReserve(); + sqlite3 *hSql = Fc_SqlReserve(H); if(hSql) { rc = sqlite3_exec(hSql, szSql, NULL, NULL, NULL); - Fc_SqlReserveReturn(hSql); + Fc_SqlReserveReturn(H, hSql); } return rc; } @@ -105,6 +101,7 @@ int Fc_SqlExec(_In_ LPSTR szSql) * Execute a single SQLITE database SQL query and return all results as numeric * 64-bit results in an array that must have capacity to hold all values. * result and the SQLITE result code. +* -- H * -- szSql * -- cQueryValue = nummber of numeric query arguments- * -- pqwQueryValues = array of 64-bit query arguments- @@ -114,11 +111,11 @@ int Fc_SqlExec(_In_ LPSTR szSql) * -- return = sqlite return code. */ _Success_(return == SQLITE_OK) -int Fc_SqlQueryN(_In_ LPSTR szSql, _In_ DWORD cQueryValues, _In_reads_(cQueryValues) PQWORD pqwQueryValues, _In_ DWORD cResultValues, _Out_writes_(cResultValues) PQWORD pqwResultValues, _Out_opt_ PDWORD pcResultValues) +int Fc_SqlQueryN(_In_ VMM_HANDLE H, _In_ LPSTR szSql, _In_ DWORD cQueryValues, _In_reads_(cQueryValues) PQWORD pqwQueryValues, _In_ DWORD cResultValues, _Out_writes_(cResultValues) PQWORD pqwResultValues, _Out_opt_ PDWORD pcResultValues) { int rc = SQLITE_ERROR; DWORD i, iMax; - sqlite3 *hSql = Fc_SqlReserve(); + sqlite3 *hSql = Fc_SqlReserve(H); sqlite3_stmt *hStmt = NULL; if(hSql) { rc = sqlite3_prepare_v2(hSql, szSql, -1, &hStmt, 0); @@ -143,24 +140,27 @@ int Fc_SqlQueryN(_In_ LPSTR szSql, _In_ DWORD cQueryValues, _In_reads_(cQueryVal } fail: sqlite3_finalize(hStmt); - Fc_SqlReserveReturn(hSql); + Fc_SqlReserveReturn(H, hSql); if(pcResultValues) { *pcResultValues = 0; } return rc; } _Success_(return) -BOOL Fc_SqlInsertStr(_In_ sqlite3_stmt *hStmt, _In_ LPSTR usz, _Out_ PFCSQL_INSERTSTRTABLE pThis) +BOOL Fc_SqlInsertStr(_In_ VMM_HANDLE H, _In_ sqlite3_stmt *hStmt, _In_ LPSTR usz, _Out_ PFCSQL_INSERTSTRTABLE pThis) { if(!CharUtil_UtoU(usz, -1, NULL, 0, NULL, &pThis->cbu, 0)) { return FALSE; } pThis->cbu--; // don't count null terminator. - CharUtil_UtoJ(usz, -1, NULL, 0, NULL, &pThis->cbj, 0); // # of bytes to represent JSON string (incl. null-terminator) + CharUtil_UtoJ(usz, -1, NULL, 0, NULL, &pThis->cbj, 0); // # of bytes to represent JSON string (incl. null-terminator) if(pThis->cbj) { pThis->cbj--; } - pThis->id = InterlockedIncrement64(&ctxFc->db.qwIdStr); + CharUtil_UtoCSV(usz, -1, NULL, 0, NULL, &pThis->cbv, 0); // # of bytes to represent CSV string (incl. null-terminator) + if(pThis->cbv) { pThis->cbv--; } + pThis->id = InterlockedIncrement64(&H->fc->db.qwIdStr); sqlite3_reset(hStmt); sqlite3_bind_int64(hStmt, 1, pThis->id); sqlite3_bind_int(hStmt, 2, pThis->cbu); sqlite3_bind_int(hStmt, 3, pThis->cbj); - sqlite3_bind_text(hStmt, 4, usz, -1, NULL); + sqlite3_bind_int(hStmt, 4, pThis->cbv); + sqlite3_bind_text(hStmt, 5, usz, -1, NULL); sqlite3_step(hStmt); return TRUE; } @@ -194,6 +194,101 @@ int Fc_SqlBindMultiInt64(_In_ sqlite3_stmt *hStmt, _In_ DWORD iFirstBind, _In_ D +//----------------------------------------------------------------------------- +// FC FILE FUNCTIONALITY BELOW: +//----------------------------------------------------------------------------- + +typedef struct tdVMMDLL_CSV_HANDLE { + DWORD o; + BYTE pb[0x00100000]; +} *VMMDLL_CSV_HANDLE; + +VOID FcCsv_Reset(_In_ VMMDLL_CSV_HANDLE h) +{ + if(h) { h->o = 0; } +} + +LPSTR FcCsv_FileTime(_In_ VMMDLL_CSV_HANDLE h, _In_ QWORD ft) +{ + DWORD o; + if(h && (sizeof(h->pb) - h->o > 22)) { + o = h->o; + Util_FileTime2CSV(ft, h->pb + o); + h->o += 22; + return h->pb + o; + } + return ""; +} + +LPSTR FcCsv_String(_In_ VMMDLL_CSV_HANDLE h, _In_opt_ LPSTR usz) +{ + DWORD o, cbv = 0; + if(!usz || !CharUtil_UtoCSV(usz, -1, NULL, 0, NULL, &cbv, 0)) { return ""; } + if(h && (sizeof(h->pb) - h->o > cbv)) { + o = h->o; + if(!CharUtil_UtoCSV(usz, -1, h->pb + o, sizeof(h->pb) - h->o, NULL, &cbv, CHARUTIL_FLAG_STR_BUFONLY)) { return ""; } + h->o += cbv; + return h->pb + o; + } + return ""; +} + +VOID FcFile_CleanupCB(_In_ PVOID pOb) +{ + Ob_DECREF(((PFCOB_FILE)pOb)->pmf); +} + +/* +* Append text data to a memory-backed forensics file. +* All text should be UTF-8 encoded. +* -- H +* -- uszFileName +* -- uszFormat +* -- .. +* -- return = the number of bytes appended (excluding terminating null). +*/ +_Success_(return != 0) +SIZE_T FcFileAppend(_In_ VMM_HANDLE H, _In_ LPSTR uszFileName, _In_z_ _Printf_format_string_ LPSTR uszFormat, ...) +{ + SIZE_T ret; + va_list arglist; + va_start(arglist, uszFormat); + ret = FcFileAppendEx(H, uszFileName, uszFormat, arglist); + va_end(arglist); + return ret; +} + +/* +* Append text data to a memory-backed forensics file. +* All text should be UTF-8 encoded. +* -- H +* -- uszFileName +* -- uszFormat +* -- arglist +* -- return = the number of bytes appended (excluding terminating null). +*/ +_Success_(return != 0) +SIZE_T FcFileAppendEx(_In_ VMM_HANDLE H, _In_ LPSTR uszFileName, _In_z_ _Printf_format_string_ LPSTR uszFormat, _In_ va_list arglist) +{ + SIZE_T ret = 0; + PFCOB_FILE pObFcFile = NULL; + QWORD qwFileNameHash = CharUtil_Hash64U(uszFileName, TRUE); + if(!H->fc || !H->fc->fInitStart || H->fc->fInitFinish) { goto fail; } + if(!(pObFcFile = ObMap_GetByKey(H->fc->FileCSV.pm, qwFileNameHash))) { + // add/allocate new file: + if(!(pObFcFile = Ob_AllocEx(H, OB_TAG_FORENSIC_FILE, LMEM_ZEROINIT, sizeof(FCOB_FILE), FcFile_CleanupCB, NULL))) { goto fail; } + if(!CharUtil_UtoU(uszFileName, -1, (PBYTE)pObFcFile->uszName, _countof(pObFcFile->uszName), NULL, NULL, CHARUTIL_FLAG_STR_BUFONLY)) { goto fail; } + if(!(pObFcFile->pmf = ObMemFile_New(H, H->vmm.pObCacheMapObCompressedShared))) { goto fail; } + if(!ObMap_Push(H->fc->FileCSV.pm, qwFileNameHash, pObFcFile)) { goto fail; } + } + ret = ObMemFile_AppendStringEx(pObFcFile->pmf, uszFormat, arglist); +fail: + Ob_DECREF(pObFcFile); + return ret; +} + + + // ---------------------------------------------------------------------------- // TIMELINING FUNCTIONALITY BELOW: // ---------------------------------------------------------------------------- @@ -214,12 +309,12 @@ typedef struct tdFCTIMELINE_PLUGIN_CONTEXT { * -- qwValue * -- wszText */ -VOID FcTimeline_Callback_PluginEntryAdd(_In_ HANDLE hTimeline, _In_ QWORD ft, _In_ DWORD dwAction, _In_ DWORD dwPID, _In_ DWORD dwData32, _In_ QWORD qwData64, _In_ LPSTR uszText) +VOID FcTimeline_Callback_PluginEntryAdd(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ QWORD ft, _In_ DWORD dwAction, _In_ DWORD dwPID, _In_ DWORD dwData32, _In_ QWORD qwData64, _In_ LPSTR uszText) { PFCTIMELINE_PLUGIN_CONTEXT ctx = (PFCTIMELINE_PLUGIN_CONTEXT)hTimeline; FCSQL_INSERTSTRTABLE SqlStrInsert; // build and insert string data into 'str' table. - if(!Fc_SqlInsertStr(ctx->hStmtStr, uszText, &SqlStrInsert)) { return; } + if(!Fc_SqlInsertStr(H, ctx->hStmtStr, uszText, &SqlStrInsert)) { return; } // insert into 'timeline_data' table. sqlite3_reset(ctx->hStmt); Fc_SqlBindMultiInt64(ctx->hStmt, 1, 7, @@ -240,7 +335,7 @@ VOID FcTimeline_Callback_PluginEntryAdd(_In_ HANDLE hTimeline, _In_ QWORD ft, _I * -- cEntrySql * -- pszEntrySql */ -VOID FcTimeline_Callback_PluginEntryAddBySQL(_In_ HANDLE hTimeline, _In_ DWORD cEntrySql, _In_ LPSTR *pszEntrySql) +VOID FcTimeline_Callback_PluginEntryAddBySQL(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ DWORD cEntrySql, _In_ LPSTR *pszEntrySql) { int rc; DWORD i; @@ -251,7 +346,7 @@ VOID FcTimeline_Callback_PluginEntryAddBySQL(_In_ HANDLE hTimeline, _In_ DWORD c snprintf(szSql, sizeof(szSql), "INSERT INTO timeline_data(tp, id_str, ft, ac, pid, data32, data64) SELECT %i, %s;", ctx->dwId, pszEntrySql[i]); rc = sqlite3_exec(ctx->hSql, szSql, NULL, NULL, NULL); if(rc != SQLITE_OK) { - VmmLog(MID_FORENSIC, LOGLEVEL_DEBUG, "BAD SQL CODE=0x%x SQL=%s\n", rc, szSql); + VmmLog(H, MID_FORENSIC, LOGLEVEL_DEBUG, "BAD SQL CODE=0x%x SQL=%s\n", rc, szSql); } } } @@ -260,13 +355,14 @@ VOID FcTimeline_Callback_PluginEntryAddBySQL(_In_ HANDLE hTimeline, _In_ DWORD c * Callback function to close an existing timeline plugin module handle. * -- hTimeline */ -VOID FcTimeline_Callback_PluginClose(_In_ HANDLE hTimeline) +VOID FcTimeline_Callback_PluginClose(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline) { PFCTIMELINE_PLUGIN_CONTEXT ctxPlugin = (PFCTIMELINE_PLUGIN_CONTEXT)hTimeline; sqlite3_exec(ctxPlugin->hSql, "COMMIT TRANSACTION", NULL, NULL, NULL); sqlite3_finalize(ctxPlugin->hStmtStr); sqlite3_finalize(ctxPlugin->hStmt); - Fc_SqlReserveReturn(ctxPlugin->hSql); + Fc_SqlReserveReturn(H, ctxPlugin->hSql); + LocalFree(ctxPlugin); } /* @@ -275,31 +371,31 @@ VOID FcTimeline_Callback_PluginClose(_In_ HANDLE hTimeline) * -- szFileUTF8 = utf-8 file name (if exists) * -- return = handle, should be closed with callback function. */ -HANDLE FcTimeline_Callback_PluginRegister(_In_reads_(6) LPSTR sNameShort, _In_reads_(32) LPSTR szFileUTF8) +HANDLE FcTimeline_Callback_PluginRegister(_In_ VMM_HANDLE H, _In_reads_(6) LPSTR sNameShort, _In_reads_(32) LPSTR szFileUTF8) { QWORD v; sqlite3 *hSql = NULL; sqlite3_stmt *hStmt = NULL; PFCTIMELINE_PLUGIN_CONTEXT ctxPlugin = NULL; - if(!(hSql = Fc_SqlReserve())) { goto fail; } - if(SQLITE_OK != sqlite3_prepare_v2(hSql, "INSERT INTO timeline_info (short_name, file_name_u, file_name_j) VALUES (?, ?, '');", -1, &hStmt, 0)) { goto fail; } + if(!(hSql = Fc_SqlReserve(H))) { goto fail; } + if(SQLITE_OK != sqlite3_prepare_v2(hSql, "INSERT INTO timeline_info (short_name, file_name) VALUES (?, ?);", -1, &hStmt, 0)) { goto fail; } if(SQLITE_OK != sqlite3_bind_text(hStmt, 1, sNameShort, 6, NULL)) { goto fail; } if(SQLITE_OK != sqlite3_bind_text(hStmt, 2, szFileUTF8, -1, NULL)) { goto fail; } if(SQLITE_DONE != sqlite3_step(hStmt)) { goto fail; } - hSql = Fc_SqlReserveReturn(hSql); - Fc_SqlQueryN("SELECT MAX(id) FROM timeline_info;", 0, NULL, 1, &v, NULL); + hSql = Fc_SqlReserveReturn(H, hSql); + Fc_SqlQueryN(H, "SELECT MAX(id) FROM timeline_info;", 0, NULL, 1, &v, NULL); if(!(ctxPlugin = LocalAlloc(LMEM_ZEROINIT, sizeof(FCTIMELINE_PLUGIN_CONTEXT)))) { goto fail; } ctxPlugin->dwId = (DWORD)v; - ctxPlugin->hSql = Fc_SqlReserve(); + ctxPlugin->hSql = Fc_SqlReserve(H); sqlite3_prepare_v2(ctxPlugin->hSql, "INSERT INTO timeline_data (id_str, tp, ft, ac, pid, data32, data64) VALUES (?, ?, ?, ?, ?, ?, ?);", -1, &ctxPlugin->hStmt, NULL); - sqlite3_prepare_v2(ctxPlugin->hSql, "INSERT INTO str (id, cbu, cbj, sz) VALUES (?, ?, ?, ?);", -1, &ctxPlugin->hStmtStr, NULL); + sqlite3_prepare_v2(ctxPlugin->hSql, szFC_SQL_STR_INSERT, -1, &ctxPlugin->hStmtStr, NULL); sqlite3_exec(ctxPlugin->hSql, "BEGIN TRANSACTION", NULL, NULL, NULL); fail: sqlite3_finalize(hStmt); if(ctxPlugin) { return (HANDLE)ctxPlugin; } - Fc_SqlReserveReturn(hSql); + Fc_SqlReserveReturn(H, hSql); return NULL; } @@ -307,10 +403,11 @@ fail: * Initialize the timelining functionality. Before the timelining functionality * is initialized processes, threads, registry and ntfs must be initialized. * Initialization may take some time. +* -- H * -- return */ _Success_(return) -BOOL FcTimeline_Initialize() +BOOL FcTimeline_Initialize(_In_ VMM_HANDLE H) { BOOL fResult = FALSE; int rc; @@ -322,82 +419,94 @@ BOOL FcTimeline_Initialize() LPSTR szTIMELINE_SQL1[] = { // populate timeline_info with basic information: "DROP TABLE IF EXISTS timeline_info;", - "CREATE TABLE timeline_info (id INTEGER PRIMARY KEY, short_name TEXT, file_name_u TEXT, file_name_j TEXT, file_size_u INTEGER DEFAULT 0, file_size_j INTEGER DEFAULT 0);", - "INSERT INTO timeline_info VALUES(0, '' , 'timeline_all.txt', 'timeline_all.json', 0, 0); ", + "CREATE TABLE timeline_info (id INTEGER PRIMARY KEY, short_name TEXT, file_name TEXT, file_size_u INTEGER DEFAULT 0, file_size_j INTEGER DEFAULT 0, file_size_v INTEGER DEFAULT 0);", + "INSERT INTO timeline_info VALUES(0, '', 'timeline_all', 0, 0, 0);", // populate timeline_data temporary table - with basic data. "DROP TABLE IF EXISTS timeline_data;", "CREATE TABLE timeline_data ( id INTEGER PRIMARY KEY AUTOINCREMENT, id_str INTEGER, tp INT, ft INTEGER, ac INT, pid INT, data32 INT, data64 INTEGER );" }; for(i = 0; i < sizeof(szTIMELINE_SQL1) / sizeof(LPCSTR); i++) { - if(SQLITE_OK != (rc = Fc_SqlExec(szTIMELINE_SQL1[i]))) { - VmmLog(MID_FORENSIC, LOGLEVEL_WARNING, "FAIL INITIALIZE TIMELINE WITH SQLITE ERROR CODE %i, QUERY: %s\n", rc, szTIMELINE_SQL1[i]); + if(SQLITE_OK != (rc = Fc_SqlExec(H, szTIMELINE_SQL1[i]))) { + VmmLog(H, MID_FORENSIC, LOGLEVEL_WARNING, "FAIL INITIALIZE TIMELINE WITH SQLITE ERROR CODE %i, QUERY: %s", rc, szTIMELINE_SQL1[i]); goto fail; } } // populate timeline_data temporary table - with plugins. - PluginManager_FcTimeline(FcTimeline_Callback_PluginRegister, FcTimeline_Callback_PluginClose, FcTimeline_Callback_PluginEntryAdd, FcTimeline_Callback_PluginEntryAddBySQL); + PluginManager_FcTimeline(H, FcTimeline_Callback_PluginRegister, FcTimeline_Callback_PluginClose, FcTimeline_Callback_PluginEntryAdd, FcTimeline_Callback_PluginEntryAddBySQL); LPSTR szTIMELINE_SQL2[] = { // populate main timeline table: "DROP TABLE IF EXISTS timeline;", "DROP VIEW IF EXISTS v_timeline;", - "CREATE TABLE timeline ( id INTEGER PRIMARY KEY AUTOINCREMENT, tp INT, tp_id INTEGER, id_str INTEGER, ft INTEGER, ac INT, pid INT, data32 INT, data64 INTEGER, oln_u INTEGER, oln_j INTEGER, oln_utp INTEGER );" + "CREATE TABLE timeline ( id INTEGER PRIMARY KEY AUTOINCREMENT, tp INT, tp_id INTEGER, id_str INTEGER, ft INTEGER, ac INT, pid INT, data32 INT, data64 INTEGER, oln_u INTEGER, oln_j INTEGER, oln_v INTEGER, oln_utp INTEGER, oln_vtp INTEGER );", "CREATE VIEW v_timeline AS SELECT * FROM timeline, str WHERE timeline.id_str = str.id;", "CREATE UNIQUE INDEX idx_timeline_tpid ON timeline(tp, tp_id);", "CREATE UNIQUE INDEX idx_timeline_oln_u ON timeline(oln_u);", - "CREATE UNIQUE INDEX idx_timeline_oln_j ON timeline(oln_j);" + "CREATE UNIQUE INDEX idx_timeline_oln_j ON timeline(oln_j);", + "CREATE UNIQUE INDEX idx_timeline_oln_v ON timeline(oln_v);", "CREATE UNIQUE INDEX idx_timeline_oln_utp ON timeline(tp, oln_utp);", - "INSERT INTO timeline (tp, tp_id, id_str, ft, ac, pid, data32, data64, oln_u, oln_j, oln_utp) SELECT td.tp, (SUM(1) OVER (PARTITION BY td.tp ORDER BY td.ft DESC, td.id)), td.id_str, td.ft, td.ac, td.pid, td.data32, td.data64, (SUM(str.cbu+"STRINGIZE(FC_LINELENGTH_TIMELINE_UTF8)") OVER (ORDER BY td.ft DESC, td.id) - str.cbu-"STRINGIZE(FC_LINELENGTH_TIMELINE_UTF8)"), (SUM(str.cbj+"STRINGIZE(FC_LINELENGTH_TIMELINE_JSON)") OVER (ORDER BY td.ft DESC, td.id) - str.cbj-"STRINGIZE(FC_LINELENGTH_TIMELINE_JSON)"), (SUM(str.cbu+"STRINGIZE(FC_LINELENGTH_TIMELINE_UTF8)") OVER (PARTITION BY td.tp ORDER BY td.ft DESC, td.id) - str.cbu-"STRINGIZE(FC_LINELENGTH_TIMELINE_UTF8)") FROM timeline_data td, str WHERE str.id = td.id_str ORDER BY td.ft DESC, td.id;", + "CREATE UNIQUE INDEX idx_timeline_oln_vtp ON timeline(tp, oln_vtp);", + "INSERT INTO timeline (tp, tp_id, id_str, ft, ac, pid, data32, data64, oln_u, oln_j, oln_v, oln_utp, oln_vtp) SELECT td.tp, (SUM(1) OVER (PARTITION BY td.tp ORDER BY td.ft DESC, td.id)), td.id_str, td.ft, td.ac, td.pid, td.data32, td.data64, (SUM(str.cbu+"STRINGIZE(FC_LINELENGTH_TIMELINE_UTF8)") OVER (ORDER BY td.ft DESC, td.id) - str.cbu-"STRINGIZE(FC_LINELENGTH_TIMELINE_UTF8)"), (SUM(str.cbj+"STRINGIZE(FC_LINELENGTH_TIMELINE_JSON)") OVER (ORDER BY td.ft DESC, td.id) - str.cbj-"STRINGIZE(FC_LINELENGTH_TIMELINE_JSON)"), (SUM(str.cbv+"STRINGIZE(FC_LINELENGTH_TIMELINE_CSV)") OVER (ORDER BY td.ft DESC, td.id) - str.cbv-"STRINGIZE(FC_LINELENGTH_TIMELINE_CSV)"), (SUM(str.cbu+"STRINGIZE(FC_LINELENGTH_TIMELINE_UTF8)") OVER (PARTITION BY td.tp ORDER BY td.ft DESC, td.id) - str.cbu-"STRINGIZE(FC_LINELENGTH_TIMELINE_UTF8)"), (SUM(str.cbv+"STRINGIZE(FC_LINELENGTH_TIMELINE_CSV)") OVER (PARTITION BY td.tp ORDER BY td.ft DESC, td.id) - str.cbv-"STRINGIZE(FC_LINELENGTH_TIMELINE_CSV)") FROM timeline_data td, str WHERE str.id = td.id_str ORDER BY td.ft DESC, td.id;", "DROP TABLE timeline_data;" - // update timeline_info with sizes for 'all' file (utf8 and json). + // update timeline_info with sizes for 'all' file (utf8, json, csv). "UPDATE timeline_info SET file_size_u = (SELECT oln_u+cbu+"STRINGIZE(FC_LINELENGTH_TIMELINE_UTF8)" AS cbu_tot FROM v_timeline WHERE id = (SELECT MAX(id) FROM v_timeline)) WHERE id = 0;", "UPDATE timeline_info SET file_size_j = (SELECT oln_j+cbj+"STRINGIZE(FC_LINELENGTH_TIMELINE_JSON)" AS cbj_tot FROM v_timeline WHERE id = (SELECT MAX(id) FROM v_timeline)) WHERE id = 0;", + "UPDATE timeline_info SET file_size_v = (SELECT oln_v+cbv+"STRINGIZE(FC_LINELENGTH_TIMELINE_CSV)" AS cbv_tot FROM v_timeline WHERE id = (SELECT MAX(id) FROM v_timeline)) WHERE id = 0;", }; for(i = 0; i < sizeof(szTIMELINE_SQL2) / sizeof(LPCSTR); i++) { - if(SQLITE_OK != (rc = Fc_SqlExec(szTIMELINE_SQL2[i]))) { - VmmLog(MID_FORENSIC, LOGLEVEL_WARNING, "FAIL INITIALIZE TIMELINE WITH SQLITE ERROR CODE %i, QUERY: %s\n", rc, szTIMELINE_SQL2[i]); + if(SQLITE_OK != (rc = Fc_SqlExec(H, szTIMELINE_SQL2[i]))) { + VmmLog(H, MID_FORENSIC, LOGLEVEL_WARNING, "FAIL INITIALIZE TIMELINE WITH SQLITE ERROR CODE %i, QUERY: %s", rc, szTIMELINE_SQL2[i]); goto fail; } } // update progress percent counter. - ctxFc->cProgressPercent = 80; - // update timeline_info with sizes for individual types for utf-8 only. - LPSTR szTIMELINE_SQL_TIMELINE_UPD_UTF8 = - "UPDATE timeline_info SET file_size_u = IFNULL((SELECT oln_utp+cbu+"STRINGIZE(FC_LINELENGTH_TIMELINE_UTF8)" FROM v_timeline WHERE tp = ? AND tp_id = (SELECT MAX(tp_id) FROM v_timeline WHERE tp = ?)), 0) WHERE id = ?;"; - Fc_SqlQueryN("SELECT MAX(id) FROM timeline_info;", 0, NULL, 1, &v, NULL); - ctxFc->Timeline.cTp = (DWORD)v + 1; - for(k = 1; k < ctxFc->Timeline.cTp; k++) { - if(SQLITE_DONE != (rc = Fc_SqlQueryN(szTIMELINE_SQL_TIMELINE_UPD_UTF8, 3, (QWORD[]) { k, k, k }, 0, NULL, NULL))) { - VmmLog(MID_FORENSIC, LOGLEVEL_WARNING, "FAIL INITIALIZE TIMELINE WITH SQLITE ERROR CODE %i, QUERY: %s\n", rc, szTIMELINE_SQL_TIMELINE_UPD_UTF8); - goto fail; + H->fc->cProgressPercent = 80; + // update timeline_info with sizes for individual types for utf-8 and csv only. + LPSTR szTIMELINE_SQL_TIMELINE_UPD[2] = { + "UPDATE timeline_info SET file_size_u = IFNULL((SELECT oln_utp+cbu+"STRINGIZE(FC_LINELENGTH_TIMELINE_UTF8)" FROM v_timeline WHERE tp = ? AND tp_id = (SELECT MAX(tp_id) FROM v_timeline WHERE tp = ?)), 0) WHERE id = ?;", + "UPDATE timeline_info SET file_size_v = IFNULL((SELECT oln_vtp+cbv+"STRINGIZE(FC_LINELENGTH_TIMELINE_CSV)" FROM v_timeline WHERE tp = ? AND tp_id = (SELECT MAX(tp_id) FROM v_timeline WHERE tp = ?)), 0) WHERE id = ?;", + }; + Fc_SqlQueryN(H, "SELECT MAX(id) FROM timeline_info;", 0, NULL, 1, &v, NULL); + H->fc->Timeline.cTp = (DWORD)v + 1; + for(k = 1; k < H->fc->Timeline.cTp; k++) { + for(i = 0; i < sizeof(szTIMELINE_SQL_TIMELINE_UPD) / sizeof(LPSTR); i++) { + if(SQLITE_DONE != (rc = Fc_SqlQueryN(H, szTIMELINE_SQL_TIMELINE_UPD[i], 3, (QWORD[]) { k, k, k }, 0, NULL, NULL))) { + VmmLog(H, MID_FORENSIC, LOGLEVEL_WARNING, "FAIL INITIALIZE TIMELINE WITH SQLITE ERROR CODE %i, QUERY: %s", rc, szTIMELINE_SQL_TIMELINE_UPD[i]); + goto fail; + } } } // populate timeline info struct - if(!(ctxFc->Timeline.pInfo = LocalAlloc(LMEM_ZEROINIT, (ctxFc->Timeline.cTp) * sizeof(FC_TIMELINE_INFO)))) { goto fail; } - if(!(hSql = Fc_SqlReserve())) { goto fail; } - if(SQLITE_OK != sqlite3_prepare_v2(hSql, "SELECT * FROM timeline_info", -1, &hStmt, 0)) { goto fail; } - for(i = 0; i < ctxFc->Timeline.cTp; i++) { - pi = ctxFc->Timeline.pInfo + i; + if(!(H->fc->Timeline.pInfo = LocalAlloc(LMEM_ZEROINIT, (H->fc->Timeline.cTp) * sizeof(FC_TIMELINE_INFO)))) { goto fail; } + if(!(hSql = Fc_SqlReserve(H))) { goto fail; } + if(SQLITE_OK != sqlite3_prepare_v2(hSql, "SELECT id, short_name, file_name, file_size_u, file_size_j, file_size_v FROM timeline_info", -1, &hStmt, 0)) { goto fail; } + for(i = 0; i < H->fc->Timeline.cTp; i++) { + pi = H->fc->Timeline.pInfo + i; if(SQLITE_ROW != sqlite3_step(hStmt)) { goto fail; } pi->dwId = sqlite3_column_int(hStmt, 0); pi->szNameShort[0] = 0; strncpy_s(pi->szNameShort, _countof(pi->szNameShort), sqlite3_column_text(hStmt, 1), _TRUNCATE); pi->szNameShort[_countof(pi->szNameShort) - 1] = 0; - strncpy_s(pi->uszNameFile, _countof(pi->uszNameFile), sqlite3_column_text(hStmt, 2), _TRUNCATE); - pi->dwFileSizeUTF8 = sqlite3_column_int(hStmt, 4); - pi->dwFileSizeJSON = sqlite3_column_int(hStmt, 5); + strncpy_s(pi->uszNameFileTXT, _countof(pi->uszNameFileTXT), sqlite3_column_text(hStmt, 2), _TRUNCATE); + strncpy_s(pi->uszNameFileCSV, _countof(pi->uszNameFileCSV), pi->uszNameFileTXT, _TRUNCATE); + strncat_s(pi->uszNameFileTXT, _countof(pi->uszNameFileTXT), ".txt", _TRUNCATE); + strncat_s(pi->uszNameFileCSV, _countof(pi->uszNameFileCSV), ".csv", _TRUNCATE); + pi->dwFileSizeUTF8 = sqlite3_column_int(hStmt, 3); + pi->dwFileSizeJSON = sqlite3_column_int(hStmt, 4); + pi->dwFileSizeCSV = sqlite3_column_int(hStmt, 5); } fResult = TRUE; fail: sqlite3_finalize(hStmt); - Fc_SqlReserveReturn(hSql); + Fc_SqlReserveReturn(H, hSql); return fResult; } -#define FCTIMELINE_SQL_SELECT_FIELDS_ALL " cbu, sz, id, ft, tp, ac, pid, data32, data64, oln_u, oln_j " -#define FCTIMELINE_SQL_SELECT_FIELDS_TP " cbu, sz, tp_id, ft, tp, ac, pid, data32, data64, oln_utp, 0 " +#define FCTIMELINE_SQL_SELECT_FIELDS_ALL " cbu, sz, id, ft, tp, ac, pid, data32, data64, oln_u, oln_j, oln_v , cbv" +#define FCTIMELINE_SQL_SELECT_FIELDS_TP " cbu, sz, tp_id, ft, tp, ac, pid, data32, data64, oln_utp, 0, oln_vtp, cbv" /* * Internal function to create a PFCOB_MAP_TIMELINE map from given sql queries. +* -- H * -- szSqlCount * -- szSqlSelect * -- cQueryValues @@ -406,7 +515,7 @@ fail: * -- return */ _Success_(return) -BOOL FcTimelineMap_CreateInternal(_In_ LPSTR szSqlCount, _In_ LPSTR szSqlSelect, _In_ DWORD cQueryValues, _In_reads_(cQueryValues) PQWORD pqwQueryValues, _Out_ PFCOB_MAP_TIMELINE *ppObNtfsMap) +BOOL FcTimelineMap_CreateInternal(_In_ VMM_HANDLE H, _In_ LPSTR szSqlCount, _In_ LPSTR szSqlSelect, _In_ DWORD cQueryValues, _In_reads_(cQueryValues) PQWORD pqwQueryValues, _Out_ PFCOB_MAP_TIMELINE *ppObNtfsMap) { int rc; QWORD pqwResult[2]; @@ -416,17 +525,17 @@ BOOL FcTimelineMap_CreateInternal(_In_ LPSTR szSqlCount, _In_ LPSTR szSqlSelect, PFC_MAP_TIMELINEENTRY pe; sqlite3 *hSql = NULL; sqlite3_stmt *hStmt = NULL; - rc = Fc_SqlQueryN(szSqlCount, cQueryValues, pqwQueryValues, 2, pqwResult, NULL); + rc = Fc_SqlQueryN(H, szSqlCount, cQueryValues, pqwQueryValues, 2, pqwResult, NULL); if((rc != SQLITE_OK) || (pqwResult[0] > 0x00010000) || (pqwResult[1] > 0x01000000)) { goto fail; } cchMultiText = (DWORD)(1 + 2 * pqwResult[0] + pqwResult[1]); - pObTimelineMap = Ob_Alloc('Mtml', LMEM_ZEROINIT, (SIZE_T)(sizeof(FCOB_MAP_TIMELINE) + pqwResult[0] * sizeof(FC_MAP_TIMELINEENTRY) + cchMultiText), NULL, NULL); + pObTimelineMap = Ob_AllocEx(H, OB_TAG_MOD_FCTIMELINE, LMEM_ZEROINIT, (SIZE_T)(sizeof(FCOB_MAP_TIMELINE) + pqwResult[0] * sizeof(FC_MAP_TIMELINEENTRY) + cchMultiText), NULL, NULL); if(!pObTimelineMap) { goto fail; } pObTimelineMap->uszMultiText = (LPSTR)((PBYTE)pObTimelineMap + sizeof(FCOB_MAP_TIMELINE) + pqwResult[0] * sizeof(FC_MAP_TIMELINEENTRY)); pObTimelineMap->cbuMultiText = cchMultiText; pObTimelineMap->cMap = (DWORD)pqwResult[0]; cchMultiText--; szuMultiText = pObTimelineMap->uszMultiText + 1; - if(!(hSql = Fc_SqlReserve())) { goto fail; } + if(!(hSql = Fc_SqlReserve(H))) { goto fail; } rc = sqlite3_prepare_v2(hSql, szSqlSelect, -1, &hStmt, 0); if(rc != SQLITE_OK) { goto fail; } for(i = 0; i < cQueryValues; i++) { @@ -454,17 +563,20 @@ BOOL FcTimelineMap_CreateInternal(_In_ LPSTR szSqlCount, _In_ LPSTR szSqlSelect, pe->data64 = sqlite3_column_int64(hStmt, 8); pe->cuszOffset = sqlite3_column_int64(hStmt, 9); pe->cjszOffset = sqlite3_column_int64(hStmt, 10); + pe->cvszOffset = sqlite3_column_int64(hStmt, 11); + pe->cvszText = sqlite3_column_int(hStmt, 12); } Ob_INCREF(pObTimelineMap); fail: sqlite3_finalize(hStmt); - Fc_SqlReserveReturn(hSql); + Fc_SqlReserveReturn(H, hSql); *ppObNtfsMap = Ob_DECREF(pObTimelineMap); return (*ppObNtfsMap != NULL); } /* * Retrieve a timeline map object consisting of timeline data. +* -- H * -- dwTimelineType = the timeline type, 0 for all. * -- qwId = the minimum timeline id of the entries to retrieve. * -- cId = the number of timeline entries to retrieve. @@ -472,7 +584,7 @@ fail: * -- return */ _Success_(return) -BOOL FcTimelineMap_GetFromIdRange(_In_ DWORD dwTimelineType, _In_ QWORD qwId, _In_ QWORD cId, _Out_ PFCOB_MAP_TIMELINE * ppObTimelineMap) +BOOL FcTimelineMap_GetFromIdRange(_In_ VMM_HANDLE H, _In_ DWORD dwTimelineType, _In_ QWORD qwId, _In_ QWORD cId, _Out_ PFCOB_MAP_TIMELINE *ppObTimelineMap) { QWORD v[] = { qwId, qwId + cId, dwTimelineType }; DWORD iSQL = dwTimelineType ? 2 : 0; @@ -482,29 +594,43 @@ BOOL FcTimelineMap_GetFromIdRange(_In_ DWORD dwTimelineType, _In_ QWORD qwId, _I "SELECT COUNT(*), SUM(cbu) FROM v_timeline WHERE tp_id >= ? AND tp_id < ? AND tp = ?", "SELECT "FCTIMELINE_SQL_SELECT_FIELDS_TP" FROM v_timeline WHERE tp_id >= ? AND tp_id < ? AND tp = ? ORDER BY tp_id" }; - return FcTimelineMap_CreateInternal(szSQL[iSQL], szSQL[iSQL + 1], (dwTimelineType ? 3 : 2), v, ppObTimelineMap); + return FcTimelineMap_CreateInternal(H, szSQL[iSQL], szSQL[iSQL + 1], (dwTimelineType ? 3 : 2), v, ppObTimelineMap); } /* * Retrieve the minimum timeline id that exists within a byte range inside a * timeline file of a specific type. -* -- dwTimelineType = the timeline type, 0 for all - has no meaning in json mode. -* -- fJSON = is JSON type, otherwise UTF8 type. +* -- H +* -- dwTimelineType = the timeline type, 0 for all. +* -- tpFormat = FC_FORMAT_TYPE_UTF8, FC_FORMAT_TYPE_JSON or FC_FORMAT_TYPE_CSV. * -- qwFilePos = the file position. * -- pqwId = pointer to receive the result id. * -- return */ _Success_(return) -BOOL FcTimeline_GetIdFromPosition(_In_ DWORD dwTimelineType, _In_ BOOL fJSON, _In_ QWORD qwFilePos, _Out_ PQWORD pqwId) +BOOL FcTimeline_GetIdFromPosition(_In_ VMM_HANDLE H, _In_ DWORD dwTimelineType, _In_ FC_FORMAT_TYPE tpFormat, _In_ QWORD qwFilePos, _Out_ PQWORD pqwId) { - QWORD v[] = { max(2048, qwFilePos) - 2048, qwFilePos, dwTimelineType }; - DWORD iSQL = fJSON ? 1 : ((dwTimelineType ? 2 : 0)); - LPSTR szSQL[3] = { - "SELECT MAX(id) FROM timeline WHERE oln_u >= ? AND oln_u <= ?", - "SELECT MAX(id) FROM timeline WHERE oln_j >= ? AND oln_j <= ?", - "SELECT MAX(tp_id) FROM timeline WHERE oln_utp >= ? AND oln_utp <= ? AND tp = ?" - }; - return (SQLITE_OK == Fc_SqlQueryN(szSQL[iSQL], (dwTimelineType ? 3 : 2), v, 1, pqwId, NULL)); + QWORD v[] = { max(4096, qwFilePos) - 4096, qwFilePos, dwTimelineType }; + if(dwTimelineType) { + switch(tpFormat) { + case FC_FORMAT_TYPE_UTF8: + return (SQLITE_OK == Fc_SqlQueryN(H, "SELECT MAX(tp_id) FROM timeline WHERE oln_utp >= ? AND oln_utp <= ? AND tp = ?", 3, v, 1, pqwId, NULL)); + case FC_FORMAT_TYPE_JSON: + return FALSE; + case FC_FORMAT_TYPE_CSV: + return (SQLITE_OK == Fc_SqlQueryN(H, "SELECT MAX(tp_id) FROM timeline WHERE oln_vtp >= ? AND oln_vtp <= ? AND tp = ?", 3, v, 1, pqwId, NULL)); + } + } else { + switch(tpFormat) { + case FC_FORMAT_TYPE_UTF8: + return (SQLITE_OK == Fc_SqlQueryN(H, "SELECT MAX(id) FROM timeline WHERE oln_u >= ? AND oln_u <= ?", 2, v, 1, pqwId, NULL)); + case FC_FORMAT_TYPE_JSON: + return (SQLITE_OK == Fc_SqlQueryN(H, "SELECT MAX(id) FROM timeline WHERE oln_j >= ? AND oln_j <= ?", 2, v, 1, pqwId, NULL)); + case FC_FORMAT_TYPE_CSV: + return (SQLITE_OK == Fc_SqlQueryN(H, "SELECT MAX(id) FROM timeline WHERE oln_v >= ? AND oln_v <= ?", 2, v, 1, pqwId, NULL)); + } + } + return FALSE; } @@ -516,35 +642,36 @@ BOOL FcTimeline_GetIdFromPosition(_In_ DWORD dwTimelineType, _In_ BOOL fJSON, _I // ---------------------------------------------------------------------------- typedef struct tdFC_SCANPHYSMEM_CONTEXT { - HANDLE hEvent; + HANDLE hEventIngestPhys; VMMDLL_PLUGIN_FORENSIC_INGEST_PHYSMEM e; } FC_SCANPHYSMEM_CONTEXT, *PFC_SCANPHYSMEM_CONTEXT; -VOID FcScanPhysmem_ThreadProc(_Inout_ PVMMDLL_PLUGIN_FORENSIC_INGEST_PHYSMEM ctx) +VOID FcScanPhysmem_ThreadProc(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_INGEST_PHYSMEM ctx) { DWORD dwPfnBase, cbPfnMap; QWORD i, pa; BOOL fValidMEMs, fValidAddr; PDWORD pPfns = NULL; PVMMDLL_MAP_PFNENTRY pePfn; + if(H->fAbort) { return; } ctx->fValid = FALSE; // 1: fetch and setup PFN map by calling VMMDLL API // (somewhat ugly to call external api, but it provides required data). - if(!ctxVmm->Work.fEnabled) { goto fail; } - dwPfnBase = (DWORD)(ctx->paBase >> 12); + if(H->fAbort) { goto fail; } + dwPfnBase = (DWORD)(ctx->pa >> 12); if(!(pPfns = LocalAlloc(0, FC_PHYSMEM_NUM_CHUNKS * sizeof(DWORD)))) { goto fail; } for(i = 0; i < FC_PHYSMEM_NUM_CHUNKS; i++) { pPfns[i] = dwPfnBase + (DWORD)i; } cbPfnMap = sizeof(VMMDLL_MAP_PFN) + FC_PHYSMEM_NUM_CHUNKS * sizeof(VMMDLL_MAP_PFNENTRY); - if(!VMMDLL_Map_GetPfn(pPfns, FC_PHYSMEM_NUM_CHUNKS, ctx->pPfnMap, &cbPfnMap)) { goto fail; } + if(!VMMDLL_Map_GetPfn(H, pPfns, FC_PHYSMEM_NUM_CHUNKS, ctx->pPfnMap, &cbPfnMap)) { goto fail; } if(ctx->pPfnMap->cMap < FC_PHYSMEM_NUM_CHUNKS) { goto fail; } // 2: set up MEMs - if(!ctxVmm->Work.fEnabled) { goto fail; } + if(H->fAbort) { goto fail; } for(i = 0, fValidMEMs = FALSE; i < FC_PHYSMEM_NUM_CHUNKS; i++) { - pa = ctx->paBase + (i << 12); - fValidAddr = (pa <= ctxMain->dev.paMax); + pa = ctx->pa + (i << 12); + fValidAddr = (pa <= H->dev.paMax); if(fValidAddr) { pePfn = &ctx->pPfnMap->pMap[i]; fValidAddr = @@ -561,7 +688,8 @@ VOID FcScanPhysmem_ThreadProc(_Inout_ PVMMDLL_PLUGIN_FORENSIC_INGEST_PHYSMEM ctx } // 3: read physical memory if(fValidMEMs) { - VmmReadScatterPhysical(ctx->ppMEMs, FC_PHYSMEM_NUM_CHUNKS, VMM_FLAG_NOCACHEPUT); + ZeroMemory(ctx->pb, FC_PHYSMEM_NUM_CHUNKS << 12); + VmmReadScatterPhysical(H, ctx->ppMEMs, FC_PHYSMEM_NUM_CHUNKS, VMM_FLAG_NOCACHEPUT); } ctx->fValid = TRUE; fail: @@ -573,8 +701,9 @@ fail: * with one thread calling only. The function allocates two 16MB chunks and will * begin to loop-read physical memory into chunks (in separate thread) and call * the plugin manager for processing by forensic consumer plugins. +* -- H */ -VOID FcScanPhysmem() +VOID FcScanPhysmem(_In_ VMM_HANDLE H) { QWORD i, iChunk = 0, paBase; FC_SCANPHYSMEM_CONTEXT ctx2[2] = { 0 }; @@ -582,63 +711,176 @@ VOID FcScanPhysmem() // 1: initialize two 16MB physical memory scan chunks for(i = 0; i < 2; i++) { ctx = ctx2 + i; - if(!(ctx->hEvent = CreateEvent(NULL, TRUE, TRUE, NULL))) { goto fail; } - if(!LcAllocScatter1(FC_PHYSMEM_NUM_CHUNKS, &ctx->e.ppMEMs)) { goto fail; } - if(!(ctx->e.pPfnMap = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMDLL_MAP_PFN) + FC_PHYSMEM_NUM_CHUNKS * sizeof(VMMDLL_MAP_PFNENTRY)))) { goto fail; } ctx->e.cMEMs = FC_PHYSMEM_NUM_CHUNKS; + ctx->e.cb = ctx->e.cMEMs * 0x1000; + if(!(ctx->hEventIngestPhys = CreateEvent(NULL, TRUE, TRUE, NULL))) { goto fail; } + if(!(ctx->e.pPfnMap = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMDLL_MAP_PFN) + FC_PHYSMEM_NUM_CHUNKS * sizeof(VMMDLL_MAP_PFNENTRY)))) { goto fail; } + if(!(ctx->e.pb = LocalAlloc(LMEM_ZEROINIT, ctx->e.cb))) { goto fail; } + if(!LcAllocScatter2(ctx->e.cb, ctx->e.pb, ctx->e.cMEMs, &ctx->e.ppMEMs)) { goto fail; } } // 2: main physical memory scan loop - for(paBase = 0; paBase < ctxMain->dev.paMax; paBase += 0x1000 * FC_PHYSMEM_NUM_CHUNKS) { + for(paBase = 0; paBase < H->dev.paMax; paBase += 0x1000 * FC_PHYSMEM_NUM_CHUNKS) { iChunk++; - if(!ctxVmm->Work.fEnabled) { goto fail; } - VmmLog(MID_FORENSIC, LOGLEVEL_DEBUG, "PhysicalAddress=%016llx\n", paBase); + if(H->fAbort) { goto fail; } + VmmLog(H, MID_FORENSIC, LOGLEVEL_6_TRACE, "PhysicalAddress=%016llx", paBase); // 2.1: fetch new physical data in separate thread: ctx = ctx2 + (iChunk % 2); - ctx->e.paBase = paBase; - ResetEvent(ctx->hEvent); - VmmWork((LPTHREAD_START_ROUTINE)FcScanPhysmem_ThreadProc, &ctx->e, ctx->hEvent); + ctx->e.pa = paBase; + VmmWork_Void(H, (PVMM_WORK_START_ROUTINE_PVOID_PFN)FcScanPhysmem_ThreadProc, &ctx->e, ctx->hEventIngestPhys, VMMWORK_FLAG_PRIO_LOW); // 2.2: process previously scheduled work item (unless first): if(paBase == 0) { continue; } ctx = ctx2 + ((iChunk - 1) % 2); - WaitForSingleObject(ctx->hEvent, INFINITE); - if(!ctxVmm->Work.fEnabled) { goto fail; } + WaitForSingleObject(ctx->hEventIngestPhys, INFINITE); + if(H->fAbort) { goto fail; } if(ctx->e.fValid) { - PluginManager_FcIngestPhysmem(&ctx->e); + PluginManager_FcIngestPhysmem(H, &ctx->e); } - ctxFc->cProgressPercent = 10 + (BYTE)((50 * paBase) / ctxMain->dev.paMax); + H->fc->cProgressPercent = 10 + (BYTE)((40 * paBase) / H->dev.paMax); } // 2.3: process last read chunk if(iChunk) { ctx = ctx2 + ((iChunk - 1) % 2); - WaitForSingleObject(ctx->hEvent, INFINITE); - if(!ctxVmm->Work.fEnabled) { goto fail; } + WaitForSingleObject(ctx->hEventIngestPhys, INFINITE); + if(H->fAbort) { goto fail; } if(ctx->e.fValid) { - PluginManager_FcIngestPhysmem(&ctx->e); + PluginManager_FcIngestPhysmem(H, &ctx->e); } } fail: for(i = 0; i < 2; i++) { ctx = ctx2 + i; - if(ctx->hEvent) { - WaitForSingleObject(ctx->hEvent, INFINITE); + if(ctx->hEventIngestPhys) { + WaitForSingleObject(ctx->hEventIngestPhys, INFINITE); + CloseHandle(ctx->hEventIngestPhys); } - if(ctx->hEvent) { CloseHandle(ctx->hEvent); } LcMemFree(ctx->e.ppMEMs); LocalFree(ctx->e.pPfnMap); + LocalFree(ctx->e.pb); } } +// ---------------------------------------------------------------------------- +// VIRTUAL MEMORY SCAN FUNCTIONALITY BELOW: +// Virtual memory is scanned and analyzed in parallel per-process via plugins +// though the plugin manager. +// User mode processes are supported and are based on VAD enumeration. +// A special case for the kernel exists which is based on PTE scannint. +// ---------------------------------------------------------------------------- + +/* +* Entry point for the virtual memory scanning of the kernel address space (pid 4). +* Scanning takes place by walking ranges recovered from PTEs. +* Reads will be packetized in chunks of max 16MBs. +*/ +VOID FcScanVirtmemKernel_ThreadProc(_In_ VMM_HANDLE H, _In_ QWORD qwNotUsed) +{ + return; // not yet activated (no active consumer module yet). + /* + PBYTE pb = NULL; + QWORD va = 0, vaMax; + DWORD iPTE = 0, cb, cbRead, cbPTE; + PVMM_MAP_PTEENTRY pePTE; + PVMMOB_MAP_PTE pObPTE = NULL; + PVMM_PROCESS pObSystemProcess = NULL; + if(H->fAbort) { goto fail; } + if(!(pb = LocalAlloc(0, 0x01000000))) { goto fail; } + if(!(pObSystemProcess = VmmProcessGet(H, 4))) { goto fail; } + if(!VmmMap_GetPte(H, pObSystemProcess, &pObPTE, FALSE)) { goto fail; } + while(iPTE < pObPTE->cMap) { + pePTE = pObPTE->pMap + iPTE; + cbPTE = (DWORD)(pePTE->cPages << 12); + if(cbPTE > 0x40000000) { iPTE++; continue; } // don't process 1GB+ PTE entries + va = max(va, pePTE->vaBase); + vaMax = pePTE->vaBase + cbPTE; + // merge following PTEs (if adjacent and not too large) + iPTE++; + while(iPTE < pObPTE->cMap) { + pePTE = pObPTE->pMap + iPTE; + cbPTE = (DWORD)(pePTE->cPages << 12); + if(vaMax != pePTE->vaBase) { break; } // don't merge non-adjacent PTEs. + if(cbPTE > 0x40000000) { break; } // don't process 1GB+ PTE entries + if(vaMax - va + cbPTE > 0x40000000) { break; } // don't merge if chunk becomes 1GB+ + // merge adjacent PTEs + vaMax += cbPTE; + iPTE++; + } + // read and send onwards to plugin manager virtual memory ingest. + while(va < vaMax) { + if(H->fAbort) { goto fail; } + cb = min(0x01000000, (DWORD)(vaMax - va)); + VmmReadEx(H, pObSystemProcess, va, pb, cb, &cbRead, VMM_FLAG_ZEROPAD_ON_FAIL); + PluginManager_FcIngestVirtmem(H, pObSystemProcess, va, pb, cb); + va += cb; + } + } +fail: + Ob_DECREF(pObPTE); + Ob_DECREF(pObSystemProcess); + LocalFree(pb); + */ +} + +/* +* Only scan user-mode processes in the per-process virtual memory ingest. +*/ +BOOL FcScanVirtmem_ProcessCriteriaCB(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ PVOID ctx) +{ + return (pProcess->dwState == 0) && (pProcess->fUserOnly || !strcmp(pProcess->szName, "csrss.exe")); +} + +/* +* Entry point for per-process virtual memory scanning. +* The process scanning technique is based on scanning the VADs. +* To avoid worker thread depletion only a few processes should be scanned in parallel. +*/ +VOID FcScanVirtmem_ProcessCB(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ PVOID ctx) +{ + PBYTE pb = NULL; + QWORD va = 0, vaMax; + DWORD iVAD = 0, cb, cbRead; + PVMM_MAP_VADENTRY peVAD; + PVMMOB_MAP_VAD pObVAD = NULL; + if(H->fAbort) { goto fail; } + if(!(pb = LocalAlloc(0, 0x01000000))) { goto fail; } + if(!VmmMap_GetVad(H, pProcess, &pObVAD, VMM_VADMAP_TP_CORE)) { goto fail; } + for(iVAD = 0; iVAD < pObVAD->cMap; iVAD++) { + peVAD = pObVAD->pMap + iVAD; + if(peVAD->vaEnd - peVAD->vaStart > 0x40000000) { continue; } // don't process 1GB+ entries + va = max(va, peVAD->vaStart); + vaMax = peVAD->vaEnd + 1; + // read and send onwards to plugin manager virtual memory ingest. + while(va < vaMax) { + if(H->fAbort) { goto fail; } + cb = min(0x01000000, (DWORD)(vaMax - va)); + VmmReadEx(H, pProcess, va, pb, cb, &cbRead, VMM_FLAG_ZEROPAD_ON_FAIL); + PluginManager_FcIngestVirtmem(H, pProcess, va, pb, cb); + va += cb; + } + } +fail: + Ob_DECREF(pObVAD); + LocalFree(pb); +} + +VOID FcScanVirtmem_ThreadProc(_In_ VMM_HANDLE H, _In_ QWORD qwNotUsed) +{ + return; // not yet activated (no active consumer module yet). + //VmmWork_ProcessActionForeachParallel_Void(H, 6, NULL, FcScanVirtmem_ProcessCriteriaCB, FcScanVirtmem_ProcessCB); +} + + // ---------------------------------------------------------------------------- // GENERAL JSON DATA LOG BELOW: // ---------------------------------------------------------------------------- /* * Callback function to add a json log line to 'general.json' +* -- H * -- pDataJSON */ -VOID FcJson_Callback_EntryAdd(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pDataJSON) +VOID FcJson_Callback_EntryAdd(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pDataJSON) { LPSTR szj; DWORD i; @@ -658,6 +900,7 @@ VOID FcJson_Callback_EntryAdd(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pDataJSON) CHAR szjPidProcName[64]; } *PBUFFER; PBUFFER buf = (PBUFFER)pDataJSON->_Reserved; + if(H->fAbort) { return; } if(pDataJSON->dwVersion != VMMDLL_PLUGIN_FORENSIC_JSONDATA_VERSION) { return; } // general/base: { @@ -666,7 +909,7 @@ VOID FcJson_Callback_EntryAdd(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pDataJSON) buf->cchHdrType = snprintf(buf->szjHdrType, sizeof(buf->szjHdrType), "{\"class\":\"GEN\",\"ver\":\"%i.%i\",\"sys\":\"%s\",\"type\":\"%s\"", VERSION_MAJOR, VERSION_MINOR, - ctxVmm->szSystemUniqueTag, + H->vmm.szSystemUniqueTag, pDataJSON->szjType ); } @@ -676,7 +919,7 @@ VOID FcJson_Callback_EntryAdd(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pDataJSON) if(pDataJSON->dwPID) { if(buf->dwPID != pDataJSON->dwPID) { buf->dwPID = pDataJSON->dwPID; - if((pObProcess = VmmProcessGetEx(NULL, pDataJSON->dwPID, VMM_FLAG_PROCESS_SHOW_TERMINATED))) { + if((pObProcess = VmmProcessGetEx(H, NULL, pDataJSON->dwPID, VMM_FLAG_PROCESS_SHOW_TERMINATED))) { CharUtil_UtoJ(pObProcess->pObPersistent->uszNameLong, -1, buf->szjProcName, sizeof(buf->szjProcName), &szj, NULL, CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR); buf->cchPidProcName = snprintf(buf->szjPidProcName, sizeof(buf->szjPidProcName), ",\"pid\":%i,\"proc\":\"%s\"", pDataJSON->dwPID, buf->szjProcName); Ob_DECREF_NULL(&pObProcess); @@ -726,11 +969,7 @@ VOID FcJson_Callback_EntryAdd(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pDataJSON) // commit to json file: if(sizeof(buf->szln) - o > 3) { memcpy(buf->szln + o, "}\n", 3); - if(pDataJSON->fVerbose) { - ObMemFile_AppendString(ctxFc->FileJSON.pGenVerbose, buf->szln); - } else { - ObMemFile_AppendString(ctxFc->FileJSON.pGen, buf->szln); - } + ObMemFile_AppendString(H->fc->FileJSON.pGen, buf->szln); } } @@ -743,93 +982,162 @@ VOID FcJson_Callback_EntryAdd(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pDataJSON) /* * The core asynchronous forensic initialization function. */ -VOID FcInitialize_ThreadProc(_In_ PVOID pvContext) +VOID FcInitialize_ThreadProc(_In_ VMM_HANDLE H, _In_ QWORD qwNotUsed) { + BOOL fResult = FALSE; + VMMDLL_CSV_HANDLE hCSV = NULL; PVMMOB_MAP_EVIL pObEvilMap = NULL; - HANDLE hEventAsyncLogJSON = 0; - QWORD tmStart = Statistics_CallStart(); - if(SQLITE_OK != Fc_SqlExec(FC_SQL_SCHEMA_STR)) { goto fail; } - if(!ctxVmm->Work.fEnabled) { goto fail; } - if(!(hEventAsyncLogJSON = CreateEvent(NULL, TRUE, FALSE, NULL))) { goto fail; } - PluginManager_Notify(VMMDLL_PLUGIN_NOTIFY_FORENSIC_INIT, NULL, 0); - VmmMap_GetEvil(NULL, &pObEvilMap); // start findevil (in 'async' mode) + HANDLE hEventAsyncLogCSV = 0, hEventAsyncLogJSON = 0, hEventAsyncIngestVirtmem = 0, hEventAsyncIngestVirtmemKernel = 0; + QWORD tmStart = Statistics_CallStart(H); + QWORD tcStart = GetTickCount64(); + VmmLog(H, MID_FORENSIC, LOGLEVEL_4_VERBOSE, "INIT START"); + if(SQLITE_OK != Fc_SqlExec(H, FC_SQL_SCHEMA_STR)) { goto fail; } + if(H->fAbort) { goto fail; } + if(!(hCSV = LocalAlloc(LMEM_ZEROINIT, sizeof(struct tdVMMDLL_CSV_HANDLE)))) { goto fail; } + if(!(hEventAsyncLogCSV = CreateEvent(NULL, TRUE, TRUE, NULL))) { goto fail; } + if(!(hEventAsyncLogJSON = CreateEvent(NULL, TRUE, TRUE, NULL))) { goto fail; } + if(!(hEventAsyncIngestVirtmem = CreateEvent(NULL, TRUE, TRUE, NULL))) { goto fail; } + if(!(hEventAsyncIngestVirtmemKernel = CreateEvent(NULL, TRUE, TRUE, NULL))) { goto fail; } + PluginManager_Notify(H, VMMDLL_PLUGIN_NOTIFY_FORENSIC_INIT, NULL, 0); + VmmMap_GetEvil(H, NULL, &pObEvilMap); // start findevil (in 'async' mode) Ob_DECREF_NULL(&pObEvilMap); - PluginManager_FcInitialize(); // 0-10% - ctxFc->cProgressPercent = 10; - if(!ctxVmm->Work.fEnabled) { goto fail; } - VmmWork( - (LPTHREAD_START_ROUTINE)PluginManager_FcLogJSON, - FcJson_Callback_EntryAdd, - hEventAsyncLogJSON - ); // parallel async init of json log - FcScanPhysmem(); // 11-60% - ctxFc->cProgressPercent = 60; - if(!ctxVmm->Work.fEnabled) { goto fail; } - PluginManager_FcIngestFinalize(); // 61-70% - ctxFc->cProgressPercent = 70; - if(!ctxVmm->Work.fEnabled) { goto fail; } - FcTimeline_Initialize(); // 71-90% - ctxFc->cProgressPercent = 90; - if(!ctxVmm->Work.fEnabled) { goto fail; } + PluginManager_FcInitialize(H); // 0-10% + H->fc->cProgressPercent = 10; + if(H->fAbort) { goto fail; } + // parallel async init of: scan virtual per-process/kernel address space & init of json log + VmmWork_Void(H, (PVMM_WORK_START_ROUTINE_PVOID_PFN)PluginManager_FcLogCSV, hCSV, hEventAsyncLogCSV, VMMWORK_FLAG_PRIO_LOW); + VmmWork_Void(H, (PVMM_WORK_START_ROUTINE_PVOID_PFN)PluginManager_FcLogJSON, FcJson_Callback_EntryAdd, hEventAsyncLogJSON, VMMWORK_FLAG_PRIO_LOW); + VmmWork_Value(H, FcScanVirtmemKernel_ThreadProc, 0, hEventAsyncIngestVirtmemKernel, VMMWORK_FLAG_PRIO_LOW); + VmmWork_Value(H, FcScanVirtmem_ThreadProc, 0, hEventAsyncIngestVirtmem, VMMWORK_FLAG_PRIO_LOW); + FcScanPhysmem(H); // 11-50% + H->fc->cProgressPercent = 50; + VmmLog(H, MID_FORENSIC, LOGLEVEL_5_DEBUG, "INIT %i%% time=%llis", H->fc->cProgressPercent, ((GetTickCount64() - tcStart) / 1000)); + if(H->fAbort) { goto fail; } + WaitForSingleObject(hEventAsyncIngestVirtmem, INFINITE); // 51-60% + WaitForSingleObject(hEventAsyncIngestVirtmemKernel, INFINITE); + H->fc->cProgressPercent = 60; + VmmLog(H, MID_FORENSIC, LOGLEVEL_5_DEBUG, "INIT %i%% time=%llis", H->fc->cProgressPercent, ((GetTickCount64() - tcStart) / 1000)); + if(H->fAbort) { goto fail; } + PluginManager_FcIngestFinalize(H); // 61-70% + H->fc->cProgressPercent = 70; + VmmLog(H, MID_FORENSIC, LOGLEVEL_5_DEBUG, "INIT %i%% time=%llis", H->fc->cProgressPercent, ((GetTickCount64() - tcStart) / 1000)); + if(H->fAbort) { goto fail; } + FcTimeline_Initialize(H); // 71-90% + H->fc->cProgressPercent = 90; + VmmLog(H, MID_FORENSIC, LOGLEVEL_5_DEBUG, "INIT %i%% time=%llis", H->fc->cProgressPercent, ((GetTickCount64() - tcStart) / 1000)); + if(H->fAbort) { goto fail; } + WaitForSingleObject(hEventAsyncLogCSV, INFINITE); WaitForSingleObject(hEventAsyncLogJSON, INFINITE); - PluginManager_FcFinalize(); // 91-100% - ctxFc->cProgressPercent = 100; - ctxFc->db.fSingleThread = FALSE; - ctxFc->fInitFinish = TRUE; - PluginManager_Notify(VMMDLL_PLUGIN_NOTIFY_FORENSIC_INIT, NULL, 100); - PluginManager_Notify(VMMDLL_PLUGIN_NOTIFY_FORENSIC_INIT_COMPLETE, NULL, 0); - Statistics_CallEnd(STATISTICS_ID_FORENSIC_FcInitialize, tmStart); + PluginManager_FcFinalize(H); // 91-100% + H->fc->cProgressPercent = 100; + H->fc->db.fSingleThread = FALSE; + H->fc->fInitFinish = TRUE; + if(H->fAbort) { goto fail; } + PluginManager_Notify(H, VMMDLL_PLUGIN_NOTIFY_FORENSIC_INIT, NULL, 100); + PluginManager_Notify(H, VMMDLL_PLUGIN_NOTIFY_FORENSIC_INIT_COMPLETE, NULL, 0); + Statistics_CallEnd(H, STATISTICS_ID_FORENSIC_FcInitialize, tmStart); + fResult = TRUE; fail: - if(hEventAsyncLogJSON) { CloseHandle(hEventAsyncLogJSON); } - if(ctxFc->cProgressPercent != 100) { - ctxFc->cProgressPercent = 0; + // finalize required even on error (including on H->fAbort) to clean up. + PluginManager_FcFinalize(H); + if(hEventAsyncLogCSV) { + WaitForSingleObject(hEventAsyncLogCSV, INFINITE); + CloseHandle(hEventAsyncLogCSV); + } + if(hEventAsyncLogJSON) { + WaitForSingleObject(hEventAsyncLogJSON, INFINITE); + CloseHandle(hEventAsyncLogJSON); + } + if(hEventAsyncIngestVirtmem) { + WaitForSingleObject(hEventAsyncIngestVirtmem, INFINITE); + CloseHandle(hEventAsyncIngestVirtmem); + } + if(hEventAsyncIngestVirtmemKernel) { + WaitForSingleObject(hEventAsyncIngestVirtmemKernel, INFINITE); + CloseHandle(hEventAsyncIngestVirtmemKernel); + } + if(H->fc->cProgressPercent != 100) { + H->fc->cProgressPercent = 0; + } + LocalFree(hCSV); + VmmLog(H, MID_FORENSIC, LOGLEVEL_4_VERBOSE, "INIT %s : time=%llis", (fResult ? "COMPLETED" : "FAIL"), ((GetTickCount64() - tcStart) / 1000)); +} + +/* +* Interrupt forensic sub-system sql queries (to allow for smooth termination) +* Cleanup will still have to be done by FcClose() once threads are shutdown. +* -- H +*/ +VOID FcInterrupt(_In_ VMM_HANDLE H) +{ + DWORD i; + if(H->fc) { + EnterCriticalSection(&H->fc->Lock); + for(i = 0; i < FC_SQL_POOL_CONNECTION_NUM; i++) { + sqlite3_interrupt(H->fc->db.hSql[i]); + } + LeaveCriticalSection(&H->fc->Lock); } } /* * Close the forensic sub-system. +* This should be done after threading has been shut down. +* -- H */ -VOID FcClose() +VOID FcClose(_In_ VMM_HANDLE H) { + PFC_CONTEXT ctxFc = H->fc; DWORD i; if(!ctxFc) { return; } EnterCriticalSection(&ctxFc->Lock); + // 1: interrupt any ongoing database queries. for(i = 0; i < FC_SQL_POOL_CONNECTION_NUM; i++) { - if(ctxFc->db.hEvent[i]) { - WaitForSingleObject(ctxFc->db.hEvent[i], INFINITE); - CloseHandle(ctxFc->db.hEvent[i]); - ctxFc->db.hEvent[i] = NULL; - } - if(ctxFc->db.hSql[i]) { sqlite3_close(ctxFc->db.hSql[i]); } + sqlite3_interrupt(ctxFc->db.hSql[i]); } + // 2: wait for query completion (to close handles). + for(i = 0; i < FC_SQL_POOL_CONNECTION_NUM; i++) { + if(ctxFc->db.hEventIngestPhys[i]) { + WaitForSingleObject(ctxFc->db.hEventIngestPhys[i], INFINITE); + CloseHandle(ctxFc->db.hEventIngestPhys[i]); + ctxFc->db.hEventIngestPhys[i] = NULL; + } + if(ctxFc->db.hSql[i]) { + sqlite3_close_v2(ctxFc->db.hSql[i]); + } + } + // clean up + H->fc = NULL; if(ctxFc->db.tp == FC_DATABASE_TYPE_TEMPFILE_CLOSE) { Util_DeleteFileU(ctxFc->db.uszDatabasePath); } Ob_DECREF_NULL(&ctxFc->FileJSON.pGen); - Ob_DECREF_NULL(&ctxFc->FileJSON.pGenVerbose); Ob_DECREF_NULL(&ctxFc->FileJSON.pReg); + Ob_DECREF_NULL(&ctxFc->FileCSV.pm); LocalFree(ctxFc->Timeline.pInfo); LeaveCriticalSection(&ctxFc->Lock); DeleteCriticalSection(&ctxFc->Lock); + LocalFree(ctxFc); } /* * Helper function to set the path of the database file. -* The different paths are saved to the global ctxFc. +* The different paths are saved to the H->fc context. +* -- H * -- dwDatabaseType = database type as specified by: FC_DATABASE_TYPE_* * -- return */ _Success_(return) -BOOL FcInitialize_SetPath(_In_ DWORD dwDatabaseType) +BOOL FcInitialize_SetPath(_In_ VMM_HANDLE H, _In_ DWORD dwDatabaseType) { + static LONG dwInMemoryDBCounter = 0; // global increasing counter to allow for multiple in-memory dbs. DWORD i, cch; CHAR uszTemp[MAX_PATH]; WCHAR wszTemp[MAX_PATH], wszTempShort[MAX_PATH]; SYSTEMTIME st; if(dwDatabaseType == FC_DATABASE_TYPE_MEMORY) { - ctxFc->db.tp = FC_DATABASE_TYPE_MEMORY; - strcpy_s(ctxFc->db.szuDatabase, _countof(ctxFc->db.szuDatabase), "file:///memorydb?mode=memory"); - return TRUE; + H->fc->db.tp = FC_DATABASE_TYPE_MEMORY; + return _snprintf_s(H->fc->db.szuDatabase, _countof(H->fc->db.szuDatabase), _TRUNCATE, "file:///memorydb%i?mode=memory", InterlockedIncrement(&dwInMemoryDBCounter)) > 0; } #ifdef _WIN32 cch = GetTempPathW(_countof(wszTempShort), wszTempShort); @@ -859,13 +1167,13 @@ BOOL FcInitialize_SetPath(_In_ DWORD dwDatabaseType) } // check length, copy into ctxFc and finish if(strlen(uszTemp) > MAX_PATH - 10) { return FALSE; } - strncpy_s(ctxFc->db.uszDatabasePath, _countof(ctxFc->db.uszDatabasePath), uszTemp, _TRUNCATE); + strncpy_s(H->fc->db.uszDatabasePath, _countof(H->fc->db.uszDatabasePath), uszTemp, _TRUNCATE); for(i = 0; i < MAX_PATH; i++) { if(uszTemp[i] == '\\') { uszTemp[i] = '/'; } } - strcpy_s(ctxFc->db.szuDatabase, _countof(ctxFc->db.szuDatabase), "file:///"); - strncpy_s(ctxFc->db.szuDatabase + 8, _countof(ctxFc->db.szuDatabase) - 8, uszTemp, _TRUNCATE); - ctxFc->db.tp = dwDatabaseType; + strcpy_s(H->fc->db.szuDatabase, _countof(H->fc->db.szuDatabase), "file:///"); + strncpy_s(H->fc->db.szuDatabase + 8, _countof(H->fc->db.szuDatabase) - 8, uszTemp, _TRUNCATE); + H->fc->db.tp = dwDatabaseType; return TRUE; } @@ -873,62 +1181,65 @@ BOOL FcInitialize_SetPath(_In_ DWORD dwDatabaseType) * Core non-threaded forensic initialization function. Allocates and sets up the * database and kicks off an asynchronous initialization thread for the rest of * the forensic activities. +* -- H * -- dwDatabaseType * -- fForceReInit * -- return */ _Success_(return) -BOOL FcInitialize_Impl(_In_ DWORD dwDatabaseType, _In_ BOOL fForceReInit) +BOOL FcInitialize_Impl(_In_ VMM_HANDLE H, _In_ DWORD dwDatabaseType, _In_ BOOL fForceReInit) { DWORD i; - if(ctxMain->dev.fVolatile) { - VmmLog(MID_FORENSIC, LOGLEVEL_WARNING, "FORENSIC mode on volatile memory is not recommended due to memory drift/smear.\n"); - } if(!dwDatabaseType || (dwDatabaseType > FC_DATABASE_TYPE_MAX)) { return FALSE; } - if(ctxFc && !fForceReInit) { return FALSE; } - ctxMain->cfg.tpForensicMode = dwDatabaseType; - PDB_Initialize_WaitComplete(); + if(H->fc && !fForceReInit) { return FALSE; } + if(H->dev.fVolatile) { + VmmLog(H, MID_FORENSIC, LOGLEVEL_WARNING, "FORENSIC mode on volatile memory is not recommended due to memory drift/smear."); + } + H->cfg.tpForensicMode = dwDatabaseType; + PDB_Initialize_WaitComplete(H); + if(H->fAbort) { goto fail; } // 1: ALLOCATE AND INITIALIZE. - if(ctxFc) { FcClose(); } - if(!(ctxFc = (PFC_CONTEXT)LocalAlloc(LMEM_ZEROINIT, sizeof(FC_CONTEXT)))) { goto fail; } - InitializeCriticalSection(&ctxFc->Lock); - if(!(ctxFc->FileJSON.pGen = ObMemFile_New())) { goto fail; } - if(!(ctxFc->FileJSON.pGenVerbose = ObMemFile_New())) { goto fail; } - if(!(ctxFc->FileJSON.pReg = ObMemFile_New())) { goto fail; } + if(H->fc) { FcClose(H); } + if(!(H->fc = (PFC_CONTEXT)LocalAlloc(LMEM_ZEROINIT, sizeof(FC_CONTEXT)))) { goto fail; } + InitializeCriticalSection(&H->fc->Lock); + if(!(H->fc->FileJSON.pGen = ObMemFile_New(H, H->vmm.pObCacheMapObCompressedShared))) { goto fail; } + if(!(H->fc->FileJSON.pReg = ObMemFile_New(H, H->vmm.pObCacheMapObCompressedShared))) { goto fail; } + if(!(H->fc->FileCSV.pm = ObMap_New(H, OB_MAP_FLAGS_OBJECT_OB))) { goto fail; } // 2: SQLITE INIT: if(SQLITE_CONFIG_MULTITHREAD != sqlite3_threadsafe()) { - VmmLog(MID_FORENSIC, LOGLEVEL_CRITICAL, "WRONG SQLITE THREADING MODE - TERMINATING!\n"); + VmmLog(H, MID_FORENSIC, LOGLEVEL_CRITICAL, "WRONG SQLITE THREADING MODE - TERMINATING!"); ExitProcess(0); } - if(!FcInitialize_SetPath(dwDatabaseType)) { - VmmLog(MID_FORENSIC, LOGLEVEL_WARNING, "Unable to set Sqlite path.\n"); + if(!FcInitialize_SetPath(H, dwDatabaseType)) { + VmmLog(H, MID_FORENSIC, LOGLEVEL_WARNING, "Unable to set Sqlite path."); goto fail; } - ctxFc->db.fSingleThread = TRUE; // single thread during INSERT-bound init phase + H->fc->db.fSingleThread = TRUE; // single thread during INSERT-bound init phase for(i = 0; i < FC_SQL_POOL_CONNECTION_NUM; i++) { - if(!(ctxFc->db.hEvent[i] = CreateEvent(NULL, FALSE, TRUE, NULL))) { goto fail; } - if(SQLITE_OK != sqlite3_open_v2(ctxFc->db.szuDatabase, &ctxFc->db.hSql[i], SQLITE_OPEN_URI | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_SHAREDCACHE | SQLITE_OPEN_NOMUTEX, NULL)) { goto fail; } + if(!(H->fc->db.hEventIngestPhys[i] = CreateEvent(NULL, FALSE, TRUE, NULL))) { goto fail; } + if(SQLITE_OK != sqlite3_open_v2(H->fc->db.szuDatabase, &H->fc->db.hSql[i], SQLITE_OPEN_URI | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_SHAREDCACHE | SQLITE_OPEN_NOMUTEX, NULL)) { goto fail; } } - VmmWork((LPTHREAD_START_ROUTINE)FcInitialize_ThreadProc, NULL, 0); - ctxFc->fInitStart = TRUE; + VmmWork_Value(H, FcInitialize_ThreadProc, 0, 0, VMMWORK_FLAG_PRIO_LOW); + H->fc->fInitStart = TRUE; return TRUE; fail: - FcClose(); + FcClose(H); return FALSE; } /* * Initialize (or re-initialize) the forensic sub-system. +* -- H * -- dwDatabaseType = database type as specified by: FC_DATABASE_TYPE_* * -- fForceReInit * -- return */ _Success_(return) -BOOL FcInitialize(_In_ DWORD dwDatabaseType, _In_ BOOL fForceReInit) +BOOL FcInitialize(_In_ VMM_HANDLE H, _In_ DWORD dwDatabaseType, _In_ BOOL fForceReInit) { BOOL fResult; - EnterCriticalSection(&ctxVmm->LockMaster); - fResult = FcInitialize_Impl(dwDatabaseType, FALSE); - LeaveCriticalSection(&ctxVmm->LockMaster); + EnterCriticalSection(&H->vmm.LockMaster); + fResult = FcInitialize_Impl(H, dwDatabaseType, FALSE); + LeaveCriticalSection(&H->vmm.LockMaster); return fResult; } diff --git a/vmm/fc.h b/vmm/fc.h index 0cb0aeb..be04acc 100644 --- a/vmm/fc.h +++ b/vmm/fc.h @@ -25,17 +25,26 @@ typedef struct tdFCSQL_INSERTSTRTABLE { QWORD id; DWORD cbu; // UTF-8 byte count (excl. NULL) - DWORD cbj; // JSON byte count (excl. NULL) + DWORD cbj; // JSON byte count (excl. NULL) + DWORD cbv; // CSV byte count (excl. NULL) } FCSQL_INSERTSTRTABLE, *PFCSQL_INSERTSTRTABLE; typedef struct tdFC_TIMELINE_INFO { DWORD dwId; DWORD dwFileSizeUTF8; DWORD dwFileSizeJSON; + DWORD dwFileSizeCSV; CHAR szNameShort[7]; // 6 chars + NULL - CHAR uszNameFile[32]; + CHAR uszNameFileTXT[32]; + CHAR uszNameFileCSV[32]; } FC_TIMELINE_INFO, *PFC_TIMELINE_INFO; +typedef struct tdFCOB_FILE { + OB ObHdr; + CHAR uszName[MAX_PATH]; + POB_MEMFILE pmf; +} FCOB_FILE, *PFCOB_FILE; + typedef struct tdFC_CONTEXT { BOOL fInitStart; BOOL fInitFinish; @@ -46,7 +55,7 @@ typedef struct tdFC_CONTEXT { CHAR uszDatabasePath[MAX_PATH]; // database filsystem path CHAR szuDatabase[MAX_PATH]; // Sqlite3 database path in UTF-8 BOOL fSingleThread; // enforce single-thread access (used during insert-bound init phase) - HANDLE hEvent[FC_SQL_POOL_CONNECTION_NUM]; + HANDLE hEventIngestPhys[FC_SQL_POOL_CONNECTION_NUM]; sqlite3 *hSql[FC_SQL_POOL_CONNECTION_NUM]; QWORD qwIdStr; } db; @@ -56,20 +65,16 @@ typedef struct tdFC_CONTEXT { } Timeline; struct { POB_MEMFILE pGen; - POB_MEMFILE pGenVerbose; POB_MEMFILE pReg; } FileJSON; + struct { + POB_MAP pm; // map of PFCOB_FILE + } FileCSV; } FC_CONTEXT, *PFC_CONTEXT; #define FC_JSONDATA_INIT_PIDTYPE(pd, pid, tp) { ZeroMemory(pd, sizeof(VMMDLL_PLUGIN_FORENSIC_JSONDATA)); pd->dwVersion = VMMDLL_PLUGIN_FORENSIC_JSONDATA_VERSION; pd->dwPID = pid; pd->szjType = tp; } - - -// ---------------------------------------------------------------------------- -// FC global variable below: -// ---------------------------------------------------------------------------- - -extern PFC_CONTEXT ctxFc; +static const LPSTR szFC_SQL_STR_INSERT = "INSERT INTO str (id, cbu, cbj, cbv, sz) VALUES (?, ?, ?, ?, ?);"; @@ -85,17 +90,27 @@ extern PFC_CONTEXT ctxFc; /* * Initialize (or re-initialize) the forensic sub-system. +* -- H * -- dwDatabaseType = database type as specified by: FC_DATABASE_TYPE_* * -- fForceReInit * -- return */ _Success_(return) -BOOL FcInitialize(_In_ DWORD dwDatabaseType, _In_ BOOL fForceReInit); +BOOL FcInitialize(_In_ VMM_HANDLE H, _In_ DWORD dwDatabaseType, _In_ BOOL fForceReInit); + +/* +* Interrupt forensic sub-system sql queries (to allow for smooth termination) +* Cleanup will still have to be done by FcClose() once threads are shutdown. +* -- H +*/ +VOID FcInterrupt(_In_ VMM_HANDLE H); /* * Close the forensic sub-system. +* This should be done after threading has been shut down. +* -- H */ -VOID FcClose(); +VOID FcClose(_In_ VMM_HANDLE H); @@ -105,33 +120,37 @@ VOID FcClose(); /* * Retrieve an SQLITE database handle. The retrieved handle must be -* returned with Fc_SqlReserveReturn(). +* returned with Fc_SqlReserveReturn(H, ). +* -- H * -- return = an SQLITE handle, or NULL on error. */ _Success_(return != NULL) -sqlite3* Fc_SqlReserve(); +sqlite3* Fc_SqlReserve(_In_ VMM_HANDLE H); /* * Return a SQLITE database handle previously retrieved with Fc_SqlReserve() * so that other threads may use it. +* -- H * -- hSql = the SQLITE database handle. * -- return = always NULL. */ _Success_(return != NULL) -sqlite3* Fc_SqlReserveReturn(_In_opt_ sqlite3 *hSql); +sqlite3* Fc_SqlReserveReturn(_In_ VMM_HANDLE H, _In_opt_ sqlite3 *hSql); /* * Execute a single SQLITE database SQL query and return the SQLITE result code. +* -- H * -- szSql * -- return = sqlite return code. */ _Success_(return == SQLITE_OK) -int Fc_SqlExec(_In_ LPSTR szSql); +int Fc_SqlExec(_In_ VMM_HANDLE H, _In_ LPSTR szSql); /* * Execute a single SQLITE database SQL query and return all results as numeric * 64-bit results in an array that must have capacity to hold all values. * result and the SQLITE result code. +* -- H * -- szSql * -- cQueryValue = nummber of numeric query arguments- * -- pqwQueryValues = array of 64-bit query arguments- @@ -142,6 +161,7 @@ int Fc_SqlExec(_In_ LPSTR szSql); */ _Success_(return == SQLITE_OK) int Fc_SqlQueryN( + _In_ VMM_HANDLE H, _In_ LPSTR szSql, _In_ DWORD cQueryValues, _In_reads_(cQueryValues) PQWORD pqwQueryValues, @@ -154,6 +174,7 @@ int Fc_SqlQueryN( * Helper function to insert a string into the database 'str' table. * Wide-Char string must not exceed 2048 characters. Only one of utf-8 * and wide-char string is inserted (preferential treatment to utf-8). +* -- H * -- hStmt * -- usz = utf-8 string to be inserted * -- pThis @@ -161,6 +182,7 @@ int Fc_SqlQueryN( */ _Success_(return) BOOL Fc_SqlInsertStr( + _In_ VMM_HANDLE H, _In_ sqlite3_stmt *hStmt, _In_ LPSTR usz, _Out_ PFCSQL_INSERTSTRTABLE pThis @@ -186,12 +208,50 @@ int Fc_SqlBindMultiInt64( +//----------------------------------------------------------------------------- +// FC FILE FUNCTIONALITY BELOW: +//----------------------------------------------------------------------------- + +/* +* Append text data to a memory-backed forensics file. +* All text should be UTF-8 encoded. +* -- H +* -- uszFileName +* -- uszFormat +* -- .. +* -- return = the number of bytes appended (excluding terminating null). +*/ +_Success_(return != 0) +SIZE_T FcFileAppend(_In_ VMM_HANDLE H, _In_ LPSTR uszFileName, _In_z_ _Printf_format_string_ LPSTR uszFormat, ...); + +/* +* Append text data to a memory-backed forensics file. +* All text should be UTF-8 encoded. +* -- H +* -- uszFileName +* -- uszFormat +* -- arglist +* -- return = the number of bytes appended (excluding terminating null). +*/ +_Success_(return != 0) +SIZE_T FcFileAppendEx(_In_ VMM_HANDLE H, _In_ LPSTR uszFileName, _In_z_ _Printf_format_string_ LPSTR uszFormat, _In_ va_list arglist); + +/* +* Helper functions to ease CSV string conversions destined for FcFileAppend(). +*/ +VOID FcCsv_Reset(_In_ VMMDLL_CSV_HANDLE h); +LPSTR FcCsv_String(_In_ VMMDLL_CSV_HANDLE h, _In_opt_ LPSTR usz); +LPSTR FcCsv_FileTime(_In_ VMMDLL_CSV_HANDLE h, _In_ QWORD ft); + + + // ---------------------------------------------------------------------------- // FC TIMELINING FUNCTIONALITY BELOW: // ---------------------------------------------------------------------------- #define FC_LINELENGTH_TIMELINE_UTF8 74 #define FC_LINELENGTH_TIMELINE_JSON 170 +#define FC_LINELENGTH_TIMELINE_CSV 75 #define FC_TIMELINE_ACTION_NONE 0 #define FC_TIMELINE_ACTION_CREATE 1 @@ -204,7 +264,7 @@ static LPCSTR FC_TIMELINE_ACTION_STR[FC_TIMELINE_ACTION_MAX + 1] = { "---", "CRE", "MOD", - "RD ", + "RD", "DEL", }; @@ -218,6 +278,8 @@ typedef struct tdFC_MAP_TIMELINEENTRY { QWORD data64; QWORD cuszOffset; // offset to start of "line" in bytes (utf-8) QWORD cjszOffset; // offset to start of "line" in bytes (json) + QWORD cvszOffset; // offset to start of "line" in bytes (csv) + DWORD cvszText; // CSV BYTE count not including terminating null DWORD cuszText; // UTF-8 BYTE count not including terminating null LPSTR uszText; // UTF-8 LPSTR pointed into FCOB_MAP_TIMELINE.uszMultiText } FC_MAP_TIMELINEENTRY, *PFC_MAP_TIMELINEENTRY; @@ -230,8 +292,15 @@ typedef struct tdFCOB_MAP_TIMELINE { FC_MAP_TIMELINEENTRY pMap[]; // map entries. } FCOB_MAP_TIMELINE, *PFCOB_MAP_TIMELINE; +typedef enum tdFC_FORMAT_TYPE { + FC_FORMAT_TYPE_UTF8 = 0, + FC_FORMAT_TYPE_JSON = 1, + FC_FORMAT_TYPE_CSV = 2, +} FC_FORMAT_TYPE; + /* * Retrieve a timeline map object consisting of timeline data. +* -- H * -- dwTimelineType = the timeline type, 0 for all. * -- qwId = the minimum timeline id of the entries to retrieve. * -- cId = the number of timeline entries to retrieve. @@ -240,6 +309,7 @@ typedef struct tdFCOB_MAP_TIMELINE { */ _Success_(return) BOOL FcTimelineMap_GetFromIdRange( + _In_ VMM_HANDLE H, _In_ DWORD dwTimelineType, _In_ QWORD qwId, _In_ QWORD cId, @@ -249,16 +319,18 @@ BOOL FcTimelineMap_GetFromIdRange( /* * Retrieve the minimum timeline id that exists within a byte range inside a * timeline file of a specific type. +* -- H * -- dwTimelineType = the timeline type, 0 for all. -* -- fJSON = is JSON type, otherwise UTF8 type. +* -- tpFormat = FC_FORMAT_TYPE_UTF8, FC_FORMAT_TYPE_JSON or FC_FORMAT_TYPE_CSV. * -- qwFilePos = the file position. * -- pqwId = pointer to receive the result id. * -- return */ _Success_(return) BOOL FcTimeline_GetIdFromPosition( + _In_ VMM_HANDLE H, _In_ DWORD dwTimelineType, - _In_ BOOL fJSON, + _In_ FC_FORMAT_TYPE tpFormat, _In_ QWORD qwFilePos, _Out_ PQWORD pqwId ); diff --git a/vmm/infodb.c b/vmm/infodb.c index 2b6e5c8..12e70e6 100644 --- a/vmm/infodb.c +++ b/vmm/infodb.c @@ -16,7 +16,7 @@ typedef struct tdOB_INFODB_CONTEXT { DWORD dwPdbId_NT; DWORD dwPdbId_TcpIp; BOOL fPdbId_TcpIp_TryComplete; - HANDLE hEvent[INFODB_SQL_POOL_CONNECTION_NUM]; + HANDLE hEventIngestPhys[INFODB_SQL_POOL_CONNECTION_NUM]; sqlite3 *hSql[INFODB_SQL_POOL_CONNECTION_NUM]; } OB_INFODB_CONTEXT, *POB_INFODB_CONTEXT; @@ -27,17 +27,18 @@ typedef struct tdOB_INFODB_CONTEXT { /* * Retrieve an SQLITE database handle. The retrieved handle must be -* returned with Fc_SqlReserveReturn(). +* returned with Fc_SqlReserveReturn(H, ). +* -- H * -- ctx * -- return = an SQLITE handle, or NULL on error. */ _Success_(return != NULL) -sqlite3 *InfoDB_SqlReserve(_In_ POB_INFODB_CONTEXT ctx) +sqlite3 *InfoDB_SqlReserve(_In_ VMM_HANDLE H, _In_ POB_INFODB_CONTEXT ctx) { DWORD iWaitNum = 0; - iWaitNum = WaitForMultipleObjects(INFODB_SQL_POOL_CONNECTION_NUM, ctx->hEvent, FALSE, INFINITE) - WAIT_OBJECT_0; + iWaitNum = WaitForMultipleObjects(INFODB_SQL_POOL_CONNECTION_NUM, ctx->hEventIngestPhys, FALSE, INFINITE) - WAIT_OBJECT_0; if(iWaitNum >= INFODB_SQL_POOL_CONNECTION_NUM) { - VmmLog(MID_INFODB, LOGLEVEL_CRITICAL, "DATABASE ERROR: WaitForMultipleObjects ERROR: 0x%08x", (DWORD)(iWaitNum + WAIT_OBJECT_0)); + VmmLog(H, MID_INFODB, LOGLEVEL_CRITICAL, "DATABASE ERROR: WaitForMultipleObjects ERROR: 0x%08x", (DWORD)(iWaitNum + WAIT_OBJECT_0)); return NULL; } return ctx->hSql[iWaitNum]; @@ -57,7 +58,7 @@ sqlite3 *InfoDB_SqlReserveReturn(_In_opt_ POB_INFODB_CONTEXT ctx, _In_opt_ sqlit if(!ctx || !hSql) { return NULL; } for(i = 0; i < INFODB_SQL_POOL_CONNECTION_NUM; i++) { if(ctx->hSql[i] == hSql) { - SetEvent(ctx->hEvent[i]); + SetEvent(ctx->hEventIngestPhys[i]); break; } } @@ -66,15 +67,16 @@ sqlite3 *InfoDB_SqlReserveReturn(_In_opt_ POB_INFODB_CONTEXT ctx, _In_opt_ sqlit /* * Execute a single SQLITE database SQL query and return the SQLITE result code. +* -- H * -- ctx * -- szSql * -- return = sqlite return code. */ _Success_(return == SQLITE_OK) -int InfoDB_SqlExec(_In_ POB_INFODB_CONTEXT ctx, _In_ LPSTR szSql) +int InfoDB_SqlExec(_In_ VMM_HANDLE H, _In_ POB_INFODB_CONTEXT ctx, _In_ LPSTR szSql) { int rc = SQLITE_ERROR; - sqlite3 *hSql = InfoDB_SqlReserve(ctx); + sqlite3 *hSql = InfoDB_SqlReserve(H, ctx); if(hSql) { rc = sqlite3_exec(hSql, szSql, NULL, NULL, NULL); InfoDB_SqlReserveReturn(ctx, hSql); @@ -86,6 +88,7 @@ int InfoDB_SqlExec(_In_ POB_INFODB_CONTEXT ctx, _In_ LPSTR szSql) * Execute a single SQLITE database SQL query and return all results as numeric * 64-bit results in an array that must have capacity to hold all values. * result and the SQLITE result code. +* -- H * -- ctx * -- szSql * -- cQueryValue = nummber of numeric query arguments- @@ -96,11 +99,11 @@ int InfoDB_SqlExec(_In_ POB_INFODB_CONTEXT ctx, _In_ LPSTR szSql) * -- return = sqlite return code. */ _Success_(return == SQLITE_OK) -int InfoDB_SqlQueryN(_In_ POB_INFODB_CONTEXT ctx, _In_ LPSTR szSql, _In_ DWORD cQueryValues, _In_reads_(cQueryValues) PQWORD pqwQueryValues, _In_ DWORD cResultValues, _Out_writes_(cResultValues) PQWORD pqwResultValues, _Out_opt_ PDWORD pcResultValues) +int InfoDB_SqlQueryN(_In_ VMM_HANDLE H, _In_ POB_INFODB_CONTEXT ctx, _In_ LPSTR szSql, _In_ DWORD cQueryValues, _In_reads_(cQueryValues) PQWORD pqwQueryValues, _In_ DWORD cResultValues, _Out_writes_(cResultValues) PQWORD pqwResultValues, _Out_opt_ PDWORD pcResultValues) { int rc = SQLITE_ERROR; DWORD i, iMax; - sqlite3 *hSql = InfoDB_SqlReserve(ctx); + sqlite3 *hSql = InfoDB_SqlReserve(H, ctx); sqlite3_stmt *hStmt = NULL; if(hSql) { rc = sqlite3_prepare_v2(hSql, szSql, -1, &hStmt, 0); @@ -136,7 +139,7 @@ fail: // GENERAL INTERNAL FUNCTIONALITY BELOW: // ---------------------------------------------------------------------------- -DWORD InfoDB_GetPdbId(_In_ POB_INFODB_CONTEXT ctx, _In_ QWORD vaModuleBase) +DWORD InfoDB_GetPdbId(_In_ VMM_HANDLE H, _In_ POB_INFODB_CONTEXT ctx, _In_ QWORD vaModuleBase) { PVMM_PROCESS pObSystemProcess = NULL; PE_CODEVIEW_INFO CodeViewInfo = { 0 }; @@ -145,9 +148,9 @@ DWORD InfoDB_GetPdbId(_In_ POB_INFODB_CONTEXT ctx, _In_ QWORD vaModuleBase) CHAR szAgeGUID[0x40] = { 0 }; int rc; sqlite3_stmt *hStmt = NULL; - sqlite3 *hSql = InfoDB_SqlReserve(ctx); - if(!(pObSystemProcess = VmmProcessGet(4))) { goto fail; } - if(!PE_GetCodeViewInfo(pObSystemProcess, vaModuleBase, NULL, &CodeViewInfo)) { goto fail; } + sqlite3 *hSql = InfoDB_SqlReserve(H, ctx); + if(!(pObSystemProcess = VmmProcessGet(H, 4))) { goto fail; } + if(!PE_GetCodeViewInfo(H, pObSystemProcess, vaModuleBase, NULL, &CodeViewInfo)) { goto fail; } qwEndGUID = *(PQWORD)(CodeViewInfo.CodeView.Guid + 8); _snprintf_s(szAgeGUID, sizeof(szAgeGUID), _TRUNCATE, "%08X%04X%04X%016llX%X", *(PDWORD)(CodeViewInfo.CodeView.Guid + 0), @@ -155,7 +158,7 @@ DWORD InfoDB_GetPdbId(_In_ POB_INFODB_CONTEXT ctx, _In_ QWORD vaModuleBase) *(PWORD)(CodeViewInfo.CodeView.Guid + 6), (QWORD)_byteswap_uint64(qwEndGUID), CodeViewInfo.CodeView.Age); - VmmLog(MID_INFODB, LOGLEVEL_TRACE, "AGEGUID=%s va=0x%llx", szAgeGUID, vaModuleBase); + VmmLog(H, MID_INFODB, LOGLEVEL_TRACE, "AGEGUID=%s va=0x%llx", szAgeGUID, vaModuleBase); rc = sqlite3_prepare_v2(hSql, "SELECT id FROM pdb WHERE guidage = ?", -1, &hStmt, 0); if(rc != SQLITE_OK) { goto fail; } sqlite3_bind_text(hStmt, 1, szAgeGUID, -1, NULL); @@ -163,25 +166,25 @@ DWORD InfoDB_GetPdbId(_In_ POB_INFODB_CONTEXT ctx, _In_ QWORD vaModuleBase) if(rc != SQLITE_ROW) { goto fail; } dwPdbId = (DWORD)sqlite3_column_int(hStmt, 0); fail: - VmmLog(MID_INFODB, LOGLEVEL_VERBOSE, "INIT: %s: va=0x%llx", (dwPdbId ? "SUCCESS" : "FAIL"), vaModuleBase); + VmmLog(H, MID_INFODB, LOGLEVEL_VERBOSE, "INIT: %s: va=0x%llx", (dwPdbId ? "SUCCESS" : "FAIL"), vaModuleBase); sqlite3_finalize(hStmt); InfoDB_SqlReserveReturn(ctx, hSql); Ob_DECREF(pObSystemProcess); return dwPdbId; } -DWORD InfoDB_EnsureTcpIp(_In_ POB_INFODB_CONTEXT ctx) +DWORD InfoDB_EnsureTcpIp(_In_ VMM_HANDLE H, _In_ POB_INFODB_CONTEXT ctx) { PVMMOB_MAP_MODULE pObModuleMap = NULL; PVMM_MAP_MODULEENTRY peModuleTcpip; if(!ctx->fPdbId_TcpIp_TryComplete) { - EnterCriticalSection(&ctxVmm->LockMaster); - if(!ctx->fPdbId_TcpIp_TryComplete && VmmMap_GetModuleEntryEx(NULL, 4, "tcpip.sys", &pObModuleMap, &peModuleTcpip)) { - ctx->dwPdbId_TcpIp = InfoDB_GetPdbId(ctx, peModuleTcpip->vaBase); + EnterCriticalSection(&H->vmm.LockMaster); + if(!ctx->fPdbId_TcpIp_TryComplete && VmmMap_GetModuleEntryEx(H, NULL, 4, "tcpip.sys", &pObModuleMap, &peModuleTcpip)) { + ctx->dwPdbId_TcpIp = InfoDB_GetPdbId(H, ctx, peModuleTcpip->vaBase); ctx->fPdbId_TcpIp_TryComplete = TRUE; Ob_DECREF_NULL(&pObModuleMap); } - LeaveCriticalSection(&ctxVmm->LockMaster); + LeaveCriticalSection(&H->vmm.LockMaster); } return ctx->dwPdbId_TcpIp; } @@ -194,17 +197,18 @@ DWORD InfoDB_EnsureTcpIp(_In_ POB_INFODB_CONTEXT ctx) /* * Check if a certificate is well know against the database. +* -- H * -- qwThumbprintEndSHA1 = QWORD representation of the last 64 bits of the SHA-1 certificate thumbprint. * -- return */ _Success_(return) -BOOL InfoDB_CertIsWellKnown(_In_ QWORD qwThumbprintEndSHA1) +BOOL InfoDB_CertIsWellKnown(_In_ VMM_HANDLE H, _In_ QWORD qwThumbprintEndSHA1) { QWORD qwResult = 0; POB_INFODB_CONTEXT pObCtx = NULL; qwThumbprintEndSHA1 = qwThumbprintEndSHA1 & 0x7fffffffffffffff; - if(!(pObCtx = ObContainer_GetOb(ctxVmm->pObCInfoDB)) || !pObCtx->dwPdbId_NT) { goto fail; } - InfoDB_SqlQueryN(pObCtx, "SELECT count(*) FROM cert WHERE hash = ?", 1, &qwThumbprintEndSHA1, 1, &qwResult, NULL); + if(!(pObCtx = ObContainer_GetOb(H->vmm.pObCInfoDB)) || !pObCtx->dwPdbId_NT) { goto fail; } + InfoDB_SqlQueryN(H, pObCtx, "SELECT count(*) FROM cert WHERE hash = ?", 1, &qwThumbprintEndSHA1, 1, &qwResult, NULL); fail: Ob_DECREF(pObCtx); return (1 == qwResult); @@ -213,40 +217,42 @@ fail: /* * Query the InfoDB for the offset of a symbol. * Currently only szModule values of 'nt', 'ntoskrnl', 'tcpip' is supported. +* -- H * -- szModule * -- szSymbolName * -- pdwSymbolOffset * -- return */ _Success_(return) -BOOL InfoDB_SymbolOffset(_In_ LPSTR szModule, _In_ LPSTR szSymbolName, _Out_ PDWORD pdwSymbolOffset) +BOOL InfoDB_SymbolOffset(_In_ VMM_HANDLE H, _In_ LPSTR szModule, _In_ LPSTR szSymbolName, _Out_ PDWORD pdwSymbolOffset) { BOOL fResult = FALSE; POB_INFODB_CONTEXT pObCtx = NULL; QWORD qwHash, qwResult = 0, qwPdbId = 0; *pdwSymbolOffset = 0; - if(!(pObCtx = ObContainer_GetOb(ctxVmm->pObCInfoDB))) { goto fail; } + if(!(pObCtx = ObContainer_GetOb(H->vmm.pObCInfoDB))) { goto fail; } if(!strcmp(szModule, "nt") || !strcmp(szModule, "ntoskrnl")) { qwPdbId = pObCtx->dwPdbId_NT; } else if(!strcmp(szModule, "tcpip")) { - qwPdbId = InfoDB_EnsureTcpIp(pObCtx); + qwPdbId = InfoDB_EnsureTcpIp(H, pObCtx); } if(!qwPdbId) { goto fail; } qwHash = CharUtil_Hash32A(szSymbolName, FALSE) + (qwPdbId << 32); - if(SQLITE_OK == InfoDB_SqlQueryN(pObCtx, "SELECT data FROM symbol_offset WHERE hash = ?", 1, &qwHash, 1, &qwResult, NULL)) { + if(SQLITE_OK == InfoDB_SqlQueryN(H, pObCtx, "SELECT data FROM symbol_offset WHERE hash = ?", 1, &qwHash, 1, &qwResult, NULL)) { *pdwSymbolOffset = (DWORD)qwResult; fResult = TRUE; } fail: Ob_DECREF(pObCtx); if(!fResult) { - VmmLog(MID_INFODB, LOGLEVEL_TRACE, "Missing SymbolOffset: %s", szSymbolName); + VmmLog(H, MID_INFODB, LOGLEVEL_TRACE, "Missing SymbolOffset: %s", szSymbolName); } return fResult; } /* * Read memory at the symbol offset. +* -- H * -- szModule * -- vaModuleBase * -- szSymbolName @@ -256,15 +262,16 @@ fail: * -- return */ _Success_(return) -BOOL InfoDB_SymbolPBYTE(_In_ LPSTR szModule, _In_ QWORD vaModuleBase, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb) +BOOL InfoDB_SymbolPBYTE(_In_ VMM_HANDLE H, _In_ LPSTR szModule, _In_ QWORD vaModuleBase, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb) { DWORD dwSymbolOffset = 0; - if(!InfoDB_SymbolOffset(szModule, szSymbolName, &dwSymbolOffset)) { return FALSE; } - return VmmRead(pProcess, vaModuleBase + dwSymbolOffset, pb, cb); + if(!InfoDB_SymbolOffset(H, szModule, szSymbolName, &dwSymbolOffset)) { return FALSE; } + return VmmRead(H, pProcess, vaModuleBase + dwSymbolOffset, pb, cb); } /* * Read memory pointed to at the symbol offset. +* -- H * -- szModule * -- vaModuleBase * -- szSymbolName @@ -273,13 +280,14 @@ BOOL InfoDB_SymbolPBYTE(_In_ LPSTR szModule, _In_ QWORD vaModuleBase, _In_ LPSTR * -- return */ _Success_(return) -BOOL InfoDB_GetSymbolQWORD(_In_ LPSTR szModule, _In_ QWORD vaModuleBase, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PQWORD pqw) +BOOL InfoDB_GetSymbolQWORD(_In_ VMM_HANDLE H, _In_ LPSTR szModule, _In_ QWORD vaModuleBase, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PQWORD pqw) { - return InfoDB_SymbolPBYTE(szModule, vaModuleBase, szSymbolName, pProcess, (PBYTE)pqw, sizeof(QWORD)); + return InfoDB_SymbolPBYTE(H, szModule, vaModuleBase, szSymbolName, pProcess, (PBYTE)pqw, sizeof(QWORD)); } /* * Read memory pointed to at the symbol offset. +* -- H * -- szModule * -- vaModuleBase * -- szSymbolName @@ -288,13 +296,14 @@ BOOL InfoDB_GetSymbolQWORD(_In_ LPSTR szModule, _In_ QWORD vaModuleBase, _In_ LP * -- return */ _Success_(return) -BOOL InfoDB_SymbolDWORD(_In_ LPSTR szModule, _In_ QWORD vaModuleBase, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PDWORD pdw) +BOOL InfoDB_SymbolDWORD(_In_ VMM_HANDLE H, _In_ LPSTR szModule, _In_ QWORD vaModuleBase, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PDWORD pdw) { - return InfoDB_SymbolPBYTE(szModule, vaModuleBase, szSymbolName, pProcess, (PBYTE)pdw, sizeof(DWORD)); + return InfoDB_SymbolPBYTE(H, szModule, vaModuleBase, szSymbolName, pProcess, (PBYTE)pdw, sizeof(DWORD)); } /* * Read memory pointed to at the symbol offset. +* -- H * -- szModule * -- vaModuleBase * -- szSymbolName @@ -303,30 +312,31 @@ BOOL InfoDB_SymbolDWORD(_In_ LPSTR szModule, _In_ QWORD vaModuleBase, _In_ LPSTR * -- return */ _Success_(return) -BOOL InfoDB_SymbolPTR(_In_ LPSTR szModule, _In_ QWORD vaModuleBase, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PVOID pv) +BOOL InfoDB_SymbolPTR(_In_ VMM_HANDLE H, _In_ LPSTR szModule, _In_ QWORD vaModuleBase, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PVOID pv) { - return InfoDB_SymbolPBYTE(szModule, vaModuleBase, szSymbolName, pProcess, (PBYTE)pv, (ctxVmm->f32 ? sizeof(DWORD) : sizeof(QWORD))); + return InfoDB_SymbolPBYTE(H, szModule, vaModuleBase, szSymbolName, pProcess, (PBYTE)pv, (H->vmm.f32 ? sizeof(DWORD) : sizeof(QWORD))); } /* * Query the InfoDB for a static size populated in the static_type_size table. +* -- H * -- szModule * -- szTypeName * -- pdwTypeSize * -- return */ _Success_(return) -BOOL InfoDB_TypeSize_Static(_In_ LPSTR szModule, _In_ LPSTR szTypeName, _Out_ PDWORD pdwTypeSize) +BOOL InfoDB_TypeSize_Static(_In_ VMM_HANDLE H, _In_ LPSTR szModule, _In_ LPSTR szTypeName, _Out_ PDWORD pdwTypeSize) { int r, rc = SQLITE_ERROR; sqlite3_stmt *hStmt = NULL; sqlite3 *hSql = NULL; POB_INFODB_CONTEXT pObCtx = NULL; - DWORD dwArch = ctxVmm->f32 ? 32 : 64; + DWORD dwArch = H->vmm.f32 ? 32 : 64; *pdwTypeSize = 0; - if(!(pObCtx = ObContainer_GetOb(ctxVmm->pObCInfoDB))) { goto fail; } - hSql = InfoDB_SqlReserve(pObCtx); - if(!ctxVmm->f32 && (szModule[0] == 'w')) { + if(!(pObCtx = ObContainer_GetOb(H->vmm.pObCInfoDB))) { goto fail; } + hSql = InfoDB_SqlReserve(H, pObCtx); + if(!H->vmm.f32 && (szModule[0] == 'w')) { // wow64 modules start with 'w' (wntdll == 32-bit ntdll on a 64-bit system) -> use the 32-bit offset instead. szModule = szModule + 1; dwArch = 32; @@ -337,7 +347,7 @@ BOOL InfoDB_TypeSize_Static(_In_ LPSTR szModule, _In_ LPSTR szTypeName, _Out_ PD sqlite3_bind_text(hStmt, 1, szModule, -1, NULL); sqlite3_bind_text(hStmt, 2, szTypeName, -1, NULL); sqlite3_bind_int(hStmt, 3, dwArch); - sqlite3_bind_int(hStmt, 4, ctxVmm->kernel.dwVersionBuild); + sqlite3_bind_int(hStmt, 4, H->vmm.kernel.dwVersionBuild); rc = sqlite3_step(hStmt); if(rc != SQLITE_ROW) { goto fail; } r = sqlite3_column_int(hStmt, 0); @@ -352,39 +362,40 @@ fail: if(rc == SQLITE_OK) { return TRUE; } - VmmLog(MID_INFODB, LOGLEVEL_TRACE, "Missing TypeSize(Static): %s!%s", szModule, szTypeName); + VmmLog(H, MID_INFODB, LOGLEVEL_TRACE, "Missing TypeSize(Static): %s!%s", szModule, szTypeName); return FALSE; } /* * Query the InfoDB for the size of a type. * Support for 'nt', 'tcpip'. +* -- H * -- szModule * -- szTypeName * -- pdwTypeSize * -- return */ _Success_(return) -BOOL InfoDB_TypeSize_Dynamic(_In_ LPSTR szModule, _In_ LPSTR szTypeName, _Out_ PDWORD pdwTypeSize) +BOOL InfoDB_TypeSize_Dynamic(_In_ VMM_HANDLE H, _In_ LPSTR szModule, _In_ LPSTR szTypeName, _Out_ PDWORD pdwTypeSize) { DWORD dwPdbId = 0; QWORD qwHash, qwResult = 0; POB_INFODB_CONTEXT pObCtx = NULL; - if(!(pObCtx = ObContainer_GetOb(ctxVmm->pObCInfoDB))) { goto fail; } + if(!(pObCtx = ObContainer_GetOb(H->vmm.pObCInfoDB))) { goto fail; } if(!strcmp(szModule, "nt") || !strcmp(szModule, "ntoskrnl")) { dwPdbId = pObCtx->dwPdbId_NT; } else if(!strcmp(szModule, "tcpip")) { - dwPdbId = InfoDB_EnsureTcpIp(pObCtx); + dwPdbId = InfoDB_EnsureTcpIp(H, pObCtx); } if(!dwPdbId) { goto fail; } qwHash = CharUtil_Hash32A(szTypeName, FALSE) + ((QWORD)dwPdbId << 32); - if(SQLITE_OK == InfoDB_SqlQueryN(pObCtx, "SELECT data FROM type_size WHERE hash = ?", 1, &qwHash, 1, &qwResult, NULL)) { + if(SQLITE_OK == InfoDB_SqlQueryN(H, pObCtx, "SELECT data FROM type_size WHERE hash = ?", 1, &qwHash, 1, &qwResult, NULL)) { *pdwTypeSize = (DWORD)qwResult; Ob_DECREF(pObCtx); return TRUE; } fail: - VmmLog(MID_INFODB, LOGLEVEL_TRACE, "Missing TypeSize(Dynamic): %s!%s", szModule, szTypeName); + VmmLog(H, MID_INFODB, LOGLEVEL_TRACE, "Missing TypeSize(Dynamic): %s!%s", szModule, szTypeName); Ob_DECREF(pObCtx); return FALSE; } @@ -392,6 +403,7 @@ fail: /* * Query the InfoDB for the static offset of a child inside a type - often inside a struct. * Support for nt/ntoskrnl/tcpip. +* -- H * -- szModule * -- szTypeName * -- uszTypeChildName @@ -399,17 +411,17 @@ fail: * -- return */ _Success_(return) -BOOL InfoDB_TypeChildOffset_Static(_In_ LPSTR szModule, _In_ LPSTR szTypeName, _In_ LPSTR uszTypeChildName, _Out_ PDWORD pdwTypeOffset) +BOOL InfoDB_TypeChildOffset_Static(_In_ VMM_HANDLE H, _In_ LPSTR szModule, _In_ LPSTR szTypeName, _In_ LPSTR uszTypeChildName, _Out_ PDWORD pdwTypeOffset) { int r, rc = SQLITE_ERROR; sqlite3_stmt *hStmt = NULL; sqlite3 *hSql = NULL; POB_INFODB_CONTEXT pObCtx = NULL; - DWORD dwArch = ctxVmm->f32 ? 32 : 64; + DWORD dwArch = H->vmm.f32 ? 32 : 64; *pdwTypeOffset = 0; - if(!(pObCtx = ObContainer_GetOb(ctxVmm->pObCInfoDB))) { goto fail; } - hSql = InfoDB_SqlReserve(pObCtx); - if(!ctxVmm->f32 && (szModule[0] == 'w')) { + if(!(pObCtx = ObContainer_GetOb(H->vmm.pObCInfoDB))) { goto fail; } + hSql = InfoDB_SqlReserve(H, pObCtx); + if(!H->vmm.f32 && (szModule[0] == 'w')) { // wow64 modules start with 'w' (wntdll == 32-bit ntdll on a 64-bit system) -> use the 32-bit offset instead. szModule = szModule + 1; dwArch = 32; @@ -421,7 +433,7 @@ BOOL InfoDB_TypeChildOffset_Static(_In_ LPSTR szModule, _In_ LPSTR szTypeName, _ rc = sqlite3_bind_text(hStmt, 2, szTypeName, -1, NULL); rc = sqlite3_bind_text(hStmt, 3, uszTypeChildName, -1, NULL); rc = sqlite3_bind_int(hStmt, 4, dwArch); - rc = sqlite3_bind_int(hStmt, 5, ctxVmm->kernel.dwVersionBuild); + rc = sqlite3_bind_int(hStmt, 5, H->vmm.kernel.dwVersionBuild); rc = sqlite3_step(hStmt); if(rc != SQLITE_ROW) { goto fail; } r = sqlite3_column_int(hStmt, 0); @@ -436,13 +448,14 @@ fail: if(rc == SQLITE_OK) { return TRUE; } - VmmLog(MID_INFODB, LOGLEVEL_TRACE, "Missing TypeChildOffset(Static): %s.%s", szTypeName, uszTypeChildName); + VmmLog(H, MID_INFODB, LOGLEVEL_TRACE, "Missing TypeChildOffset(Static): %s.%s", szTypeName, uszTypeChildName); return FALSE; } /* * Query the InfoDB for the offset of a child inside a type - often inside a struct. * Support for nt/ntoskrnl/tcpip. +* -- H * -- szModule * -- szTypeName * -- uszTypeChildName @@ -450,42 +463,43 @@ fail: * -- return */ _Success_(return) -BOOL InfoDB_TypeChildOffset_Dynamic(_In_ LPSTR szModule, _In_ LPSTR szTypeName, _In_ LPSTR uszTypeChildName, _Out_ PDWORD pdwTypeOffset) +BOOL InfoDB_TypeChildOffset_Dynamic(_In_ VMM_HANDLE H, _In_ LPSTR szModule, _In_ LPSTR szTypeName, _In_ LPSTR uszTypeChildName, _Out_ PDWORD pdwTypeOffset) { DWORD dwPdbId = 0; POB_INFODB_CONTEXT pObCtx = NULL; QWORD qwHash, qwHash1, qwHash2, qwResult = 0; - if(!(pObCtx = ObContainer_GetOb(ctxVmm->pObCInfoDB))) { goto fail; } + if(!(pObCtx = ObContainer_GetOb(H->vmm.pObCInfoDB))) { goto fail; } if(!strcmp(szModule, "nt") || !strcmp(szModule, "ntoskrnl")) { dwPdbId = pObCtx->dwPdbId_NT; } else if(!strcmp(szModule, "tcpip")) { - dwPdbId = InfoDB_EnsureTcpIp(pObCtx); + dwPdbId = InfoDB_EnsureTcpIp(H, pObCtx); } if(!dwPdbId) { goto fail; } qwHash1 = CharUtil_Hash32A(szTypeName, FALSE); qwHash2 = CharUtil_Hash32U(uszTypeChildName, FALSE); qwHash = ((qwHash2 << 32) + qwHash1 + dwPdbId + ((QWORD)dwPdbId << 32)) & 0x7fffffffffffffff; - if(SQLITE_OK == InfoDB_SqlQueryN(pObCtx, "SELECT data FROM type_child WHERE hash = ?", 1, &qwHash, 1, &qwResult, NULL)) { + if(SQLITE_OK == InfoDB_SqlQueryN(H, pObCtx, "SELECT data FROM type_child WHERE hash = ?", 1, &qwHash, 1, &qwResult, NULL)) { *pdwTypeOffset = (DWORD)qwResult; Ob_DECREF(pObCtx); return TRUE; } fail: - VmmLog(MID_INFODB, LOGLEVEL_TRACE, "Missing TypeChildOffset(Dynamic): %s.%s", szTypeName, uszTypeChildName); + VmmLog(H, MID_INFODB, LOGLEVEL_TRACE, "Missing TypeChildOffset(Dynamic): %s.%s", szTypeName, uszTypeChildName); Ob_DECREF(pObCtx); return FALSE; } /* * Return whether the InfoDB symbols are ok or not. +* -- H * -- pfNtos * -- pfTcpIp */ -VOID InfoDB_IsValidSymbols(_Out_opt_ PBOOL pfNtos, _Out_opt_ PBOOL pfTcpIp) +VOID InfoDB_IsValidSymbols(_In_ VMM_HANDLE H, _Out_opt_ PBOOL pfNtos, _Out_opt_ PBOOL pfTcpIp) { BOOL fNtos = FALSE, fTcpIp = FALSE; POB_INFODB_CONTEXT pObCtx = NULL; - if((pObCtx = ObContainer_GetOb(ctxVmm->pObCInfoDB))) { + if((pObCtx = ObContainer_GetOb(H->vmm.pObCInfoDB))) { fNtos = pObCtx->dwPdbId_NT ? TRUE : FALSE; fTcpIp = pObCtx->dwPdbId_TcpIp ? TRUE : FALSE; } @@ -497,11 +511,12 @@ VOID InfoDB_IsValidSymbols(_Out_opt_ PBOOL pfNtos, _Out_opt_ PBOOL pfTcpIp) /* * Return if the InfoDB have been successfully initialized. * Will return fail on no-init or failure to init (missing info.db file). +* -- H * -- return; */ -BOOL InfoDB_IsInitialized() +BOOL InfoDB_IsInitialized(_In_ VMM_HANDLE H) { - return ObContainer_Exists(ctxVmm->pObCInfoDB); + return ObContainer_Exists(H->vmm.pObCInfoDB); } /* @@ -511,36 +526,36 @@ VOID InfoDB_Context_CleanupCB(POB_INFODB_CONTEXT pOb) { DWORD i; for(i = 0; i < INFODB_SQL_POOL_CONNECTION_NUM; i++) { - if(pOb->hEvent[i]) { - WaitForSingleObject(pOb->hEvent[i], INFINITE); - CloseHandle(pOb->hEvent[i]); - pOb->hEvent[i] = NULL; + if(pOb->hEventIngestPhys[i]) { + WaitForSingleObject(pOb->hEventIngestPhys[i], INFINITE); + CloseHandle(pOb->hEventIngestPhys[i]); + pOb->hEventIngestPhys[i] = NULL; } if(pOb->hSql[i]) { sqlite3_close(pOb->hSql[i]); } } } -VOID InfoDB_Initialize_DoWork() +VOID InfoDB_Initialize_DoWork(_In_ VMM_HANDLE H) { DWORD i; POB_INFODB_CONTEXT pObCtx = NULL; CHAR szDbPathFile[MAX_PATH] = { 0 }; // 1: INIT - if(!(pObCtx = Ob_Alloc(OB_TAG_INFODB_CTX, LMEM_ZEROINIT, sizeof(OB_INFODB_CONTEXT), (OB_CLEANUP_CB)InfoDB_Context_CleanupCB, NULL))) { goto fail; } + if(!(pObCtx = Ob_AllocEx(H, OB_TAG_INFODB_CTX, LMEM_ZEROINIT, sizeof(OB_INFODB_CONTEXT), (OB_CLEANUP_CB)InfoDB_Context_CleanupCB, NULL))) { goto fail; } // 2: SQLITE INIT: Util_GetPathLib(szDbPathFile); strncat_s(szDbPathFile, sizeof(szDbPathFile), "info.db", _TRUNCATE); if(SQLITE_CONFIG_MULTITHREAD != sqlite3_threadsafe()) { - VmmLog(MID_INFODB, LOGLEVEL_CRITICAL, "WRONG SQLITE THREADING MODE - TERMINATING!"); + VmmLog(H, MID_INFODB, LOGLEVEL_CRITICAL, "WRONG SQLITE THREADING MODE - TERMINATING!"); ExitProcess(0); } for(i = 0; i < INFODB_SQL_POOL_CONNECTION_NUM; i++) { - if(!(pObCtx->hEvent[i] = CreateEvent(NULL, FALSE, TRUE, NULL))) { goto fail; } + if(!(pObCtx->hEventIngestPhys[i] = CreateEvent(NULL, FALSE, TRUE, NULL))) { goto fail; } if(SQLITE_OK != sqlite3_open_v2(szDbPathFile, &pObCtx->hSql[i], SQLITE_OPEN_URI | SQLITE_OPEN_READONLY | SQLITE_OPEN_SHAREDCACHE | SQLITE_OPEN_NOMUTEX, NULL)) { goto fail; } } // 3: QUERY CURRENT 'NTOSKRNL.EXE' IMAGE - pObCtx->dwPdbId_NT = InfoDB_GetPdbId(pObCtx, ctxVmm->kernel.vaBase); - ObContainer_SetOb(ctxVmm->pObCInfoDB, pObCtx); + pObCtx->dwPdbId_NT = InfoDB_GetPdbId(H, pObCtx, H->vmm.kernel.vaBase); + ObContainer_SetOb(H->vmm.pObCInfoDB, pObCtx); fail: Ob_DECREF(pObCtx); } @@ -548,16 +563,16 @@ fail: /* * Initialize the InfoDB (if possible): */ -VOID InfoDB_Initialize() +VOID InfoDB_Initialize(_In_ VMM_HANDLE H) { - if(ObContainer_Exists(ctxVmm->pObCInfoDB)) { return; } - if(ctxMain->cfg.fDisableInfoDB) { - VmmLog(MID_INFODB, LOGLEVEL_INFO, "Info database disabled by user"); + if(ObContainer_Exists(H->vmm.pObCInfoDB)) { return; } + if(H->cfg.fDisableInfoDB) { + VmmLog(H, MID_INFODB, LOGLEVEL_INFO, "Info database disabled by user"); return; } - EnterCriticalSection(&ctxVmm->LockMaster); - if(!ObContainer_Exists(ctxVmm->pObCInfoDB)) { - InfoDB_Initialize_DoWork(); + EnterCriticalSection(&H->vmm.LockMaster); + if(!ObContainer_Exists(H->vmm.pObCInfoDB)) { + InfoDB_Initialize_DoWork(H); } - LeaveCriticalSection(&ctxVmm->LockMaster); + LeaveCriticalSection(&H->vmm.LockMaster); } diff --git a/vmm/infodb.h b/vmm/infodb.h index 8582644..a45c0f5 100644 --- a/vmm/infodb.h +++ b/vmm/infodb.h @@ -9,25 +9,28 @@ /* * Check if a certificate is well know against the database. +* -- H * -- qwThumbprintEndSHA1 = QWORD representation of the last 64 bits of the SHA-1 certificate thumbprint. * -- return */ _Success_(return) -BOOL InfoDB_CertIsWellKnown(_In_ QWORD qwThumbprintEndSHA1); +BOOL InfoDB_CertIsWellKnown(_In_ VMM_HANDLE H, _In_ QWORD qwThumbprintEndSHA1); /* * Query the InfoDB for the offset of a symbol. * Currently only szModule values of 'nt', 'ntoskrnl', 'tcpip' is supported. +* -- H * -- szModule * -- szSymbolName * -- pdwSymbolOffset * -- return */ _Success_(return) -BOOL InfoDB_SymbolOffset(_In_ LPSTR szModule, _In_ LPSTR szSymbolName, _Out_ PDWORD pdwSymbolOffset); +BOOL InfoDB_SymbolOffset(_In_ VMM_HANDLE H, _In_ LPSTR szModule, _In_ LPSTR szSymbolName, _Out_ PDWORD pdwSymbolOffset); /* * Read memory pointed to at the symbol offset. +* -- H * -- szModule * -- vaModuleBase * -- szSymbolName @@ -36,10 +39,11 @@ BOOL InfoDB_SymbolOffset(_In_ LPSTR szModule, _In_ LPSTR szSymbolName, _Out_ PDW * -- return */ _Success_(return) -BOOL InfoDB_GetSymbolQWORD(_In_ LPSTR szModule, _In_ QWORD vaModuleBase, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PQWORD pqw); +BOOL InfoDB_GetSymbolQWORD(_In_ VMM_HANDLE H, _In_ LPSTR szModule, _In_ QWORD vaModuleBase, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PQWORD pqw); /* * Read memory pointed to at the symbol offset. +* -- H * -- szModule * -- vaModuleBase * -- szSymbolName @@ -48,10 +52,11 @@ BOOL InfoDB_GetSymbolQWORD(_In_ LPSTR szModule, _In_ QWORD vaModuleBase, _In_ LP * -- return */ _Success_(return) -BOOL InfoDB_SymbolDWORD(_In_ LPSTR szModule, _In_ QWORD vaModuleBase, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PDWORD pdw); +BOOL InfoDB_SymbolDWORD(_In_ VMM_HANDLE H, _In_ LPSTR szModule, _In_ QWORD vaModuleBase, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PDWORD pdw); /* * Read memory pointed to at the symbol offset. +* -- H * -- szModule * -- vaModuleBase * -- szSymbolName @@ -60,32 +65,35 @@ BOOL InfoDB_SymbolDWORD(_In_ LPSTR szModule, _In_ QWORD vaModuleBase, _In_ LPSTR * -- return */ _Success_(return) -BOOL InfoDB_SymbolPTR(_In_ LPSTR szModule, _In_ QWORD vaModuleBase, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PVOID pv); +BOOL InfoDB_SymbolPTR(_In_ VMM_HANDLE H, _In_ LPSTR szModule, _In_ QWORD vaModuleBase, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PVOID pv); /* * Query the InfoDB for a static size populated in the static_type_size table. +* -- H * -- szModule * -- szTypeName * -- pdwTypeSize * -- return */ _Success_(return) -BOOL InfoDB_TypeSize_Static(_In_ LPSTR szModule, _In_ LPSTR szTypeName, _Out_ PDWORD pdwTypeSize); +BOOL InfoDB_TypeSize_Static(_In_ VMM_HANDLE H, _In_ LPSTR szModule, _In_ LPSTR szTypeName, _Out_ PDWORD pdwTypeSize); /* * Query the InfoDB for the size of a type. * Currently only szModule values of 'nt' or 'ntoskrnl' is supported. * Support for nt/ntoskrnl/tcpip. +* -- H * -- szModule * -- szTypeName * -- pdwTypeSize * -- return */ _Success_(return) -BOOL InfoDB_TypeSize_Dynamic(_In_ LPSTR szModule, _In_ LPSTR szTypeName, _Out_ PDWORD pdwTypeSize); +BOOL InfoDB_TypeSize_Dynamic(_In_ VMM_HANDLE H, _In_ LPSTR szModule, _In_ LPSTR szTypeName, _Out_ PDWORD pdwTypeSize); /* * Query the InfoDB for the static offset of a child inside a type - often inside a struct. +* -- H * -- szModule * -- szTypeName * -- uszTypeChildName @@ -93,11 +101,12 @@ BOOL InfoDB_TypeSize_Dynamic(_In_ LPSTR szModule, _In_ LPSTR szTypeName, _Out_ P * -- return */ _Success_(return) -BOOL InfoDB_TypeChildOffset_Static(_In_ LPSTR szModule, _In_ LPSTR szTypeName, _In_ LPSTR uszTypeChildName, _Out_ PDWORD pdwTypeOffset); +BOOL InfoDB_TypeChildOffset_Static(_In_ VMM_HANDLE H, _In_ LPSTR szModule, _In_ LPSTR szTypeName, _In_ LPSTR uszTypeChildName, _Out_ PDWORD pdwTypeOffset); /* * Query the InfoDB for the offset of a child inside a type - often inside a struct. * Support for nt/ntoskrnl/tcpip. +* -- H * -- szModule * -- szTypeName * -- uszTypeChildName @@ -105,25 +114,28 @@ BOOL InfoDB_TypeChildOffset_Static(_In_ LPSTR szModule, _In_ LPSTR szTypeName, _ * -- return */ _Success_(return) -BOOL InfoDB_TypeChildOffset_Dynamic(_In_ LPSTR szModule, _In_ LPSTR szTypeName, _In_ LPSTR uszTypeChildName, _Out_ PDWORD pdwTypeOffset); +BOOL InfoDB_TypeChildOffset_Dynamic(_In_ VMM_HANDLE H, _In_ LPSTR szModule, _In_ LPSTR szTypeName, _In_ LPSTR uszTypeChildName, _Out_ PDWORD pdwTypeOffset); /* * Return whether the InfoDB symbols are ok or not. +* -- H * -- pfNtos * -- pfTcpIp */ -VOID InfoDB_IsValidSymbols(_Out_opt_ PBOOL pfNtos, _Out_opt_ PBOOL pfTcpIp); +VOID InfoDB_IsValidSymbols(_In_ VMM_HANDLE H, _Out_opt_ PBOOL pfNtos, _Out_opt_ PBOOL pfTcpIp); /* * Return if the InfoDB have been successfully initialized. * Will return fail on no-init or failure to init (missing info.db file). -* -- return; +* -- H +* -- return */ -BOOL InfoDB_IsInitialized(); +BOOL InfoDB_IsInitialized(_In_ VMM_HANDLE H); /* * Initialize the InfoDB (if possible): +* -- H */ -VOID InfoDB_Initialize(); +VOID InfoDB_Initialize(_In_ VMM_HANDLE H); #endif /* __INFODB_H__ */ diff --git a/vmm/m_conf.c b/vmm/m_conf.c index b85131e..720f1ec 100644 --- a/vmm/m_conf.c +++ b/vmm/m_conf.c @@ -25,14 +25,15 @@ /* * Read : function as specified by the module manager. The module manager will * call into this callback function whenever a read shall occur from a "file". -* -- ctx +* -- H +* -- ctxP * -- pb * -- cb * -- pcbRead * -- cbOffset * -- return */ -NTSTATUS MConf_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MConf_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { DWORD cchBuffer; CHAR szBuffer[0x800]; @@ -40,42 +41,42 @@ NTSTATUS MConf_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbRea LPSTR szCallStatistics = NULL; QWORD cPageReadTotal, cPageFailTotal; NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; - if(!_stricmp(ctx->uszPath, "config_process_show_terminated.txt")) { - return Util_VfsReadFile_FromBOOL(ctxVmm->flags & VMM_FLAG_PROCESS_SHOW_TERMINATED, pb, cb, pcbRead, cbOffset); + if(!_stricmp(ctxP->uszPath, "config_process_show_terminated.txt")) { + return Util_VfsReadFile_FromBOOL(H->vmm.flags & VMM_FLAG_PROCESS_SHOW_TERMINATED, pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "config_cache_enable.txt")) { - return Util_VfsReadFile_FromBOOL(!(ctxVmm->flags & VMM_FLAG_NOCACHE), pb, cb, pcbRead, cbOffset); + if(!_stricmp(ctxP->uszPath, "config_cache_enable.txt")) { + return Util_VfsReadFile_FromBOOL(!(H->vmm.flags & VMM_FLAG_NOCACHE), pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "config_paging_enable.txt")) { - return Util_VfsReadFile_FromBOOL(!(ctxVmm->flags & VMM_FLAG_NOPAGING), pb, cb, pcbRead, cbOffset); + if(!_stricmp(ctxP->uszPath, "config_paging_enable.txt")) { + return Util_VfsReadFile_FromBOOL(!(H->vmm.flags & VMM_FLAG_NOPAGING), pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "config_statistics_fncall.txt")) { - return Util_VfsReadFile_FromBOOL(Statistics_CallGetEnabled(), pb, cb, pcbRead, cbOffset); + if(!_stricmp(ctxP->uszPath, "config_statistics_fncall.txt")) { + return Util_VfsReadFile_FromBOOL(Statistics_CallGetEnabled(H), pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "config_refresh_enable.txt")) { - return Util_VfsReadFile_FromBOOL(ctxVmm->ThreadProcCache.fEnabled, pb, cb, pcbRead, cbOffset); + if(!_stricmp(ctxP->uszPath, "config_refresh_enable.txt")) { + return Util_VfsReadFile_FromBOOL(H->vmm.ThreadProcCache.fEnabled, pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "config_refresh_tick_period_ms.txt")) { - return Util_VfsReadFile_FromDWORD(ctxVmm->ThreadProcCache.cMs_TickPeriod, pb, cb, pcbRead, cbOffset, FALSE); + if(!_stricmp(ctxP->uszPath, "config_refresh_tick_period_ms.txt")) { + return Util_VfsReadFile_FromDWORD(H->vmm.ThreadProcCache.cMs_TickPeriod, pb, cb, pcbRead, cbOffset, FALSE); } - if(!_stricmp(ctx->uszPath, "config_refresh_read.txt")) { - return Util_VfsReadFile_FromDWORD(ctxVmm->ThreadProcCache.cTick_MEM, pb, cb, pcbRead, cbOffset, FALSE); + if(!_stricmp(ctxP->uszPath, "config_refresh_read.txt")) { + return Util_VfsReadFile_FromDWORD(H->vmm.ThreadProcCache.cTick_MEM, pb, cb, pcbRead, cbOffset, FALSE); } - if(!_stricmp(ctx->uszPath, "config_refresh_tlb.txt")) { - return Util_VfsReadFile_FromDWORD(ctxVmm->ThreadProcCache.cTick_TLB, pb, cb, pcbRead, cbOffset, FALSE); + if(!_stricmp(ctxP->uszPath, "config_refresh_tlb.txt")) { + return Util_VfsReadFile_FromDWORD(H->vmm.ThreadProcCache.cTick_TLB, pb, cb, pcbRead, cbOffset, FALSE); } - if(!_stricmp(ctx->uszPath, "config_refresh_proc_partial.txt")) { - return Util_VfsReadFile_FromDWORD(ctxVmm->ThreadProcCache.cTick_Fast, pb, cb, pcbRead, cbOffset, FALSE); + if(!_stricmp(ctxP->uszPath, "config_refresh_proc_partial.txt")) { + return Util_VfsReadFile_FromDWORD(H->vmm.ThreadProcCache.cTick_Fast, pb, cb, pcbRead, cbOffset, FALSE); } - if(!_stricmp(ctx->uszPath, "config_refresh_proc_total.txt")) { - return Util_VfsReadFile_FromDWORD(ctxVmm->ThreadProcCache.cTick_Medium, pb, cb, pcbRead, cbOffset, FALSE); + if(!_stricmp(ctxP->uszPath, "config_refresh_proc_total.txt")) { + return Util_VfsReadFile_FromDWORD(H->vmm.ThreadProcCache.cTick_Medium, pb, cb, pcbRead, cbOffset, FALSE); } - if(!_stricmp(ctx->uszPath, "config_refresh_registry.txt")) { - return Util_VfsReadFile_FromDWORD(ctxVmm->ThreadProcCache.cTick_Slow, pb, cb, pcbRead, cbOffset, FALSE); + if(!_stricmp(ctxP->uszPath, "config_refresh_registry.txt")) { + return Util_VfsReadFile_FromDWORD(H->vmm.ThreadProcCache.cTick_Slow, pb, cb, pcbRead, cbOffset, FALSE); } - if(!_stricmp(ctx->uszPath, "statistics.txt")) { - cPageReadTotal = ctxVmm->stat.page.cPrototype + ctxVmm->stat.page.cTransition + ctxVmm->stat.page.cDemandZero + ctxVmm->stat.page.cVAD + ctxVmm->stat.page.cCacheHit + ctxVmm->stat.page.cPageFile + ctxVmm->stat.page.cCompressed; - cPageFailTotal = ctxVmm->stat.page.cFailCacheHit + ctxVmm->stat.page.cFailVAD + ctxVmm->stat.page.cFailPageFile + ctxVmm->stat.page.cFailCompressed + ctxVmm->stat.page.cFail; + if(!_stricmp(ctxP->uszPath, "statistics.txt")) { + cPageReadTotal = H->vmm.stat.page.cPrototype + H->vmm.stat.page.cTransition + H->vmm.stat.page.cDemandZero + H->vmm.stat.page.cVAD + H->vmm.stat.page.cCacheHit + H->vmm.stat.page.cPageFile + H->vmm.stat.page.cCompressed; + cPageFailTotal = H->vmm.stat.page.cFailCacheHit + H->vmm.stat.page.cFailVAD + H->vmm.stat.page.cFailPageFile + H->vmm.stat.page.cFailCompressed + H->vmm.stat.page.cFail; cchBuffer = snprintf(szBuffer, 0x800, "VMM STATISTICS (4kB PAGES / COUNTS - HEXADECIMAL)\n" \ "===================================================\n" \ @@ -106,60 +107,60 @@ NTSTATUS MConf_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbRea "TLB MEMORY REFRESH: %16llx\n" \ "PROCESS PARTIAL REFRESH: %16llx\n" \ "PROCESS FULL REFRESH: %16llx\n", - ctxVmm->stat.cPhysCacheHit, ctxVmm->stat.cPhysReadSuccess, ctxVmm->stat.cPhysReadFail, ctxVmm->stat.cPhysWrite, - cPageReadTotal, ctxVmm->stat.page.cPrototype, ctxVmm->stat.page.cTransition, ctxVmm->stat.page.cDemandZero, ctxVmm->stat.page.cVAD, ctxVmm->stat.page.cCacheHit, ctxVmm->stat.page.cPageFile, ctxVmm->stat.page.cCompressed, - cPageFailTotal, ctxVmm->stat.page.cFailCacheHit, ctxVmm->stat.page.cFailVAD, ctxVmm->stat.page.cFailPageFile, ctxVmm->stat.page.cFailCompressed, - ctxVmm->stat.cTlbCacheHit, ctxVmm->stat.cTlbReadSuccess, ctxVmm->stat.cTlbReadFail, - ctxVmm->stat.cPhysRefreshCache, ctxVmm->stat.cTlbRefreshCache, ctxVmm->stat.cProcessRefreshPartial, ctxVmm->stat.cProcessRefreshFull + H->vmm.stat.cPhysCacheHit, H->vmm.stat.cPhysReadSuccess, H->vmm.stat.cPhysReadFail, H->vmm.stat.cPhysWrite, + cPageReadTotal, H->vmm.stat.page.cPrototype, H->vmm.stat.page.cTransition, H->vmm.stat.page.cDemandZero, H->vmm.stat.page.cVAD, H->vmm.stat.page.cCacheHit, H->vmm.stat.page.cPageFile, H->vmm.stat.page.cCompressed, + cPageFailTotal, H->vmm.stat.page.cFailCacheHit, H->vmm.stat.page.cFailVAD, H->vmm.stat.page.cFailPageFile, H->vmm.stat.page.cFailCompressed, + H->vmm.stat.cTlbCacheHit, H->vmm.stat.cTlbReadSuccess, H->vmm.stat.cTlbReadFail, + H->vmm.stat.cPhysRefreshCache, H->vmm.stat.cTlbRefreshCache, H->vmm.stat.cProcessRefreshPartial, H->vmm.stat.cProcessRefreshFull ); return Util_VfsReadFile_FromPBYTE(szBuffer, cchBuffer, pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "statistics_fncall.txt")) { - if(Statistics_CallToString(&szCallStatistics, &cbCallStatistics)) { + if(!_stricmp(ctxP->uszPath, "statistics_fncall.txt")) { + if(Statistics_CallToString(H, &szCallStatistics, &cbCallStatistics)) { nt = Util_VfsReadFile_FromPBYTE(szCallStatistics, cbCallStatistics, pb, cb, pcbRead, cbOffset); LocalFree(szCallStatistics); } return nt; } - if(!_stricmp(ctx->uszPath, "config_fileinfoheader_enable.txt")) { - return Util_VfsReadFile_FromBOOL(ctxMain->cfg.fFileInfoHeader, pb, cb, pcbRead, cbOffset); + if(!_stricmp(ctxP->uszPath, "config_fileinfoheader_enable.txt")) { + return Util_VfsReadFile_FromBOOL(H->cfg.fFileInfoHeader, pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "config_printf_enable.txt")) { - return Util_VfsReadFile_FromBOOL(ctxMain->cfg.fVerboseDll, pb, cb, pcbRead, cbOffset); + if(!_stricmp(ctxP->uszPath, "config_printf_enable.txt")) { + return Util_VfsReadFile_FromBOOL(H->cfg.fVerboseDll, pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "config_printf_v.txt")) { - return Util_VfsReadFile_FromBOOL(ctxMain->cfg.fVerbose, pb, cb, pcbRead, cbOffset); + if(!_stricmp(ctxP->uszPath, "config_printf_v.txt")) { + return Util_VfsReadFile_FromBOOL(H->cfg.fVerbose, pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "config_printf_vv.txt")) { - return Util_VfsReadFile_FromBOOL(ctxMain->cfg.fVerboseExtra, pb, cb, pcbRead, cbOffset); + if(!_stricmp(ctxP->uszPath, "config_printf_vv.txt")) { + return Util_VfsReadFile_FromBOOL(H->cfg.fVerboseExtra, pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "config_printf_vvv.txt")) { - return Util_VfsReadFile_FromBOOL(ctxMain->cfg.fVerboseExtraTlp, pb, cb, pcbRead, cbOffset); + if(!_stricmp(ctxP->uszPath, "config_printf_vvv.txt")) { + return Util_VfsReadFile_FromBOOL(H->cfg.fVerboseExtraTlp, pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "native_max_address.txt")) { - return Util_VfsReadFile_FromQWORD(ctxMain->dev.paMax, pb, cb, pcbRead, cbOffset, FALSE); + if(!_stricmp(ctxP->uszPath, "native_max_address.txt")) { + return Util_VfsReadFile_FromQWORD(H->dev.paMax, pb, cb, pcbRead, cbOffset, FALSE); } - if(!_strnicmp(ctx->uszPath, "config_symbol.txt", 13)) { - if(!_stricmp(ctx->uszPath, "config_symbol_enable.txt")) { - return Util_VfsReadFile_FromBOOL(ctxMain->pdb.fEnable, pb, cb, pcbRead, cbOffset); + if(!_strnicmp(ctxP->uszPath, "config_symbol.txt", 13)) { + if(!_stricmp(ctxP->uszPath, "config_symbol_enable.txt")) { + return Util_VfsReadFile_FromBOOL(H->pdb.fEnable, pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "config_symbolcache.txt")) { - return Util_VfsReadFile_FromPBYTE(ctxMain->pdb.szLocal, strlen(ctxMain->pdb.szLocal), pb, cb, pcbRead, cbOffset); + if(!_stricmp(ctxP->uszPath, "config_symbolcache.txt")) { + return Util_VfsReadFile_FromPBYTE(H->pdb.szLocal, strlen(H->pdb.szLocal), pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "config_symbolserver.txt")) { - return Util_VfsReadFile_FromPBYTE(ctxMain->pdb.szServer, strlen(ctxMain->pdb.szServer), pb, cb, pcbRead, cbOffset); + if(!_stricmp(ctxP->uszPath, "config_symbolserver.txt")) { + return Util_VfsReadFile_FromPBYTE(H->pdb.szServer, strlen(H->pdb.szServer), pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "config_symbolserver_enable.txt")) { - return Util_VfsReadFile_FromBOOL(ctxMain->pdb.fServerEnable, pb, cb, pcbRead, cbOffset); + if(!_stricmp(ctxP->uszPath, "config_symbolserver_enable.txt")) { + return Util_VfsReadFile_FromBOOL(H->pdb.fServerEnable, pb, cb, pcbRead, cbOffset); } } return VMMDLL_STATUS_FILE_INVALID; } -NTSTATUS MConf_Write_NotifyVerbosityChange(_In_ NTSTATUS nt) +NTSTATUS MConf_Write_NotifyVerbosityChange(_In_ VMM_HANDLE H, _In_ NTSTATUS nt) { if(nt == VMMDLL_STATUS_SUCCESS) { - PluginManager_Notify(VMMDLL_PLUGIN_NOTIFY_VERBOSITYCHANGE, NULL, 0); + PluginManager_Notify(H, VMMDLL_PLUGIN_NOTIFY_VERBOSITYCHANGE, NULL, 0); } return nt; } @@ -167,101 +168,102 @@ NTSTATUS MConf_Write_NotifyVerbosityChange(_In_ NTSTATUS nt) /* * Write : function as specified by the module manager. The module manager will * call into this callback function whenever a write shall occur from a "file". -* -- ctx +* -- H +* -- ctxP * -- pb * -- cb * -- pcbWrite * -- cbOffset * -- return */ -NTSTATUS MConf_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) +NTSTATUS MConf_Write(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) { NTSTATUS nt; BOOL fEnable = FALSE; - if(!_stricmp(ctx->uszPath, "config_process_show_terminated.txt")) { + if(!_stricmp(ctxP->uszPath, "config_process_show_terminated.txt")) { nt = Util_VfsWriteFile_BOOL(&fEnable, pb, cb, pcbWrite, cbOffset); if(nt == VMMDLL_STATUS_SUCCESS) { - ctxVmm->flags &= ~VMM_FLAG_PROCESS_SHOW_TERMINATED; - ctxVmm->flags |= fEnable ? VMM_FLAG_PROCESS_SHOW_TERMINATED : 0; + H->vmm.flags &= ~VMM_FLAG_PROCESS_SHOW_TERMINATED; + H->vmm.flags |= fEnable ? VMM_FLAG_PROCESS_SHOW_TERMINATED : 0; } return nt; } - if(!_stricmp(ctx->uszPath, "config_cache_enable.txt")) { + if(!_stricmp(ctxP->uszPath, "config_cache_enable.txt")) { nt = Util_VfsWriteFile_BOOL(&fEnable, pb, cb, pcbWrite, cbOffset); if(nt == VMMDLL_STATUS_SUCCESS) { - ctxVmm->flags &= ~VMM_FLAG_NOCACHE; - ctxVmm->flags |= fEnable ? 0 : VMM_FLAG_NOCACHE; + H->vmm.flags &= ~VMM_FLAG_NOCACHE; + H->vmm.flags |= fEnable ? 0 : VMM_FLAG_NOCACHE; } return nt; } - if(!_stricmp(ctx->uszPath, "config_paging_enable.txt")) { + if(!_stricmp(ctxP->uszPath, "config_paging_enable.txt")) { nt = Util_VfsWriteFile_BOOL(&fEnable, pb, cb, pcbWrite, cbOffset); if(nt == VMMDLL_STATUS_SUCCESS) { - ctxVmm->flags &= ~VMM_FLAG_NOPAGING; - ctxVmm->flags |= fEnable ? 0 : VMM_FLAG_NOPAGING; + H->vmm.flags &= ~VMM_FLAG_NOPAGING; + H->vmm.flags |= fEnable ? 0 : VMM_FLAG_NOPAGING; } return nt; } - if(!_stricmp(ctx->uszPath, "config_statistics_fncall.txt")) { + if(!_stricmp(ctxP->uszPath, "config_statistics_fncall.txt")) { nt = Util_VfsWriteFile_BOOL(&fEnable, pb, cb, pcbWrite, cbOffset); if(nt == VMMDLL_STATUS_SUCCESS) { - Statistics_CallSetEnabled(fEnable); + Statistics_CallSetEnabled(H, fEnable); } return nt; } - if(!_stricmp(ctx->uszPath, "config_refresh_tick_period_ms.txt")) { - return Util_VfsWriteFile_DWORD(&ctxVmm->ThreadProcCache.cMs_TickPeriod, pb, cb, pcbWrite, cbOffset, 50, 0); + if(!_stricmp(ctxP->uszPath, "config_refresh_tick_period_ms.txt")) { + return Util_VfsWriteFile_DWORD(&H->vmm.ThreadProcCache.cMs_TickPeriod, pb, cb, pcbWrite, cbOffset, 50, 0); } - if(!_stricmp(ctx->uszPath, "config_refresh_read.txt")) { - return Util_VfsWriteFile_DWORD(&ctxVmm->ThreadProcCache.cTick_MEM, pb, cb, pcbWrite, cbOffset, 1, 0); + if(!_stricmp(ctxP->uszPath, "config_refresh_read.txt")) { + return Util_VfsWriteFile_DWORD(&H->vmm.ThreadProcCache.cTick_MEM, pb, cb, pcbWrite, cbOffset, 1, 0); } - if(!_stricmp(ctx->uszPath, "config_refresh_tlb.txt")) { - return Util_VfsWriteFile_DWORD(&ctxVmm->ThreadProcCache.cTick_TLB, pb, cb, pcbWrite, cbOffset, 1, 0); + if(!_stricmp(ctxP->uszPath, "config_refresh_tlb.txt")) { + return Util_VfsWriteFile_DWORD(&H->vmm.ThreadProcCache.cTick_TLB, pb, cb, pcbWrite, cbOffset, 1, 0); } - if(!_stricmp(ctx->uszPath, "config_refresh_proc_partial.txt")) { - return Util_VfsWriteFile_DWORD(&ctxVmm->ThreadProcCache.cTick_Fast, pb, cb, pcbWrite, cbOffset, 1, 0); + if(!_stricmp(ctxP->uszPath, "config_refresh_proc_partial.txt")) { + return Util_VfsWriteFile_DWORD(&H->vmm.ThreadProcCache.cTick_Fast, pb, cb, pcbWrite, cbOffset, 1, 0); } - if(!_stricmp(ctx->uszPath, "config_refresh_proc_total.txt")) { - return Util_VfsWriteFile_DWORD(&ctxVmm->ThreadProcCache.cTick_Medium, pb, cb, pcbWrite, cbOffset, 1, 0); + if(!_stricmp(ctxP->uszPath, "config_refresh_proc_total.txt")) { + return Util_VfsWriteFile_DWORD(&H->vmm.ThreadProcCache.cTick_Medium, pb, cb, pcbWrite, cbOffset, 1, 0); } - if(!_stricmp(ctx->uszPath, "config_refresh_registry.txt")) { - VmmWinReg_Refresh(); - return Util_VfsWriteFile_DWORD(&ctxVmm->ThreadProcCache.cTick_Slow, pb, cb, pcbWrite, cbOffset, 1, 0); + if(!_stricmp(ctxP->uszPath, "config_refresh_registry.txt")) { + VmmWinReg_Refresh(H); + return Util_VfsWriteFile_DWORD(&H->vmm.ThreadProcCache.cTick_Slow, pb, cb, pcbWrite, cbOffset, 1, 0); } - if(!_stricmp(ctx->uszPath, "config_fileinfoheader_enable.txt")) { - Util_VfsWriteFile_BOOL(&ctxMain->cfg.fFileInfoHeader, pb, cb, pcbWrite, cbOffset); + if(!_stricmp(ctxP->uszPath, "config_fileinfoheader_enable.txt")) { + Util_VfsWriteFile_BOOL(&H->cfg.fFileInfoHeader, pb, cb, pcbWrite, cbOffset); } - if(!_stricmp(ctx->uszPath, "config_printf_enable.txt")) { + if(!_stricmp(ctxP->uszPath, "config_printf_enable.txt")) { return MConf_Write_NotifyVerbosityChange( - Util_VfsWriteFile_BOOL(&ctxMain->cfg.fVerboseDll, pb, cb, pcbWrite, cbOffset)); + H, Util_VfsWriteFile_BOOL(&H->cfg.fVerboseDll, pb, cb, pcbWrite, cbOffset)); } - if(!_stricmp(ctx->uszPath, "config_printf_v.txt")) { + if(!_stricmp(ctxP->uszPath, "config_printf_v.txt")) { return MConf_Write_NotifyVerbosityChange( - Util_VfsWriteFile_BOOL(&ctxMain->cfg.fVerbose, pb, cb, pcbWrite, cbOffset)); + H, Util_VfsWriteFile_BOOL(&H->cfg.fVerbose, pb, cb, pcbWrite, cbOffset)); } - if(!_stricmp(ctx->uszPath, "config_printf_vv.txt")) { + if(!_stricmp(ctxP->uszPath, "config_printf_vv.txt")) { return MConf_Write_NotifyVerbosityChange( - Util_VfsWriteFile_BOOL(&ctxMain->cfg.fVerboseExtra, pb, cb, pcbWrite, cbOffset)); + H, Util_VfsWriteFile_BOOL(&H->cfg.fVerboseExtra, pb, cb, pcbWrite, cbOffset)); } - if(!_stricmp(ctx->uszPath, "config_printf_vvv.txt")) { + if(!_stricmp(ctxP->uszPath, "config_printf_vvv.txt")) { return MConf_Write_NotifyVerbosityChange( - Util_VfsWriteFile_BOOL(&ctxMain->cfg.fVerboseExtraTlp, pb, cb, pcbWrite, cbOffset)); + H, Util_VfsWriteFile_BOOL(&H->cfg.fVerboseExtraTlp, pb, cb, pcbWrite, cbOffset)); } - if(!_strnicmp(ctx->uszPath, "config_symbol.txt", 13)) { + if(!_strnicmp(ctxP->uszPath, "config_symbol.txt", 13)) { nt = VMMDLL_STATUS_FILE_INVALID; - if(!_stricmp(ctx->uszPath, "config_symbol_enable.txt")) { - nt = Util_VfsWriteFile_DWORD(&ctxMain->pdb.fEnable, pb, cb, pcbWrite, cbOffset, 1, 0); + if(!_stricmp(ctxP->uszPath, "config_symbol_enable.txt")) { + nt = Util_VfsWriteFile_DWORD(&H->pdb.fEnable, pb, cb, pcbWrite, cbOffset, 1, 0); } - if(!_stricmp(ctx->uszPath, "config_symbolcache.txt")) { - nt = Util_VfsWriteFile_PBYTE(ctxMain->pdb.szLocal, _countof(ctxMain->pdb.szLocal) - 1, pb, cb, pcbWrite, cbOffset, TRUE); + if(!_stricmp(ctxP->uszPath, "config_symbolcache.txt")) { + nt = Util_VfsWriteFile_PBYTE(H->pdb.szLocal, _countof(H->pdb.szLocal) - 1, pb, cb, pcbWrite, cbOffset, TRUE); } - if(!_stricmp(ctx->uszPath, "config_symbolserver.txt")) { - nt = Util_VfsWriteFile_PBYTE(ctxMain->pdb.szServer, _countof(ctxMain->pdb.szServer) - 1, pb, cb, pcbWrite, cbOffset, TRUE); + if(!_stricmp(ctxP->uszPath, "config_symbolserver.txt")) { + nt = Util_VfsWriteFile_PBYTE(H->pdb.szServer, _countof(H->pdb.szServer) - 1, pb, cb, pcbWrite, cbOffset, TRUE); } - if(!_stricmp(ctx->uszPath, "config_symbolserver_enable.txt")) { - nt = Util_VfsWriteFile_DWORD(&ctxMain->pdb.fServerEnable, pb, cb, pcbWrite, cbOffset, 1, 0); + if(!_stricmp(ctxP->uszPath, "config_symbolserver_enable.txt")) { + nt = Util_VfsWriteFile_DWORD(&H->pdb.fServerEnable, pb, cb, pcbWrite, cbOffset, 1, 0); } - PDB_ConfigChange(); + PDB_ConfigChange(H); return nt; } return VMMDLL_STATUS_FILE_INVALID; @@ -271,18 +273,19 @@ NTSTATUS MConf_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_reads_(cb) PBYTE pb, _ * List : function as specified by the module manager. The module manager will * call into this callback function whenever a list directory shall occur from * the given module. -* -- ctx +* -- H +* -- ctxP * -- pFileList * -- return */ -BOOL MConf_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) +BOOL MConf_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { DWORD cbCallStatistics = 0; // not module root directory -> fail! - if(ctx->uszPath[0]) { return FALSE; } + if(ctxP->uszPath[0]) { return FALSE; } // "root" view - if(!ctx->pProcess) { - Statistics_CallToString(NULL, &cbCallStatistics); + if(!ctxP->pProcess) { + Statistics_CallToString(H, NULL, &cbCallStatistics); VMMDLL_VfsList_AddFile(pFileList, "config_fileinfoheader_enable.txt", 1, NULL); VMMDLL_VfsList_AddFile(pFileList, "config_cache_enable.txt", 1, NULL); VMMDLL_VfsList_AddFile(pFileList, "config_paging_enable.txt", 1, NULL); @@ -295,8 +298,8 @@ BOOL MConf_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) VMMDLL_VfsList_AddFile(pFileList, "config_refresh_proc_total.txt", 8, NULL); VMMDLL_VfsList_AddFile(pFileList, "config_refresh_registry.txt", 8, NULL); VMMDLL_VfsList_AddFile(pFileList, "config_symbol_enable.txt", 1, NULL); - VMMDLL_VfsList_AddFile(pFileList, "config_symbolcache.txt", strlen(ctxMain->pdb.szLocal), NULL); - VMMDLL_VfsList_AddFile(pFileList, "config_symbolserver.txt", strlen(ctxMain->pdb.szServer), NULL); + VMMDLL_VfsList_AddFile(pFileList, "config_symbolcache.txt", strlen(H->pdb.szLocal), NULL); + VMMDLL_VfsList_AddFile(pFileList, "config_symbolserver.txt", strlen(H->pdb.szServer), NULL); VMMDLL_VfsList_AddFile(pFileList, "config_symbolserver_enable.txt", 1, NULL); VMMDLL_VfsList_AddFile(pFileList, "statistics.txt", 1103, NULL); VMMDLL_VfsList_AddFile(pFileList, "config_printf_enable.txt", 1, NULL); @@ -316,9 +319,10 @@ BOOL MConf_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) * shall call the supplied pfnPluginManager_Register function. * NB! the module does not have to register itself - for example if the target * operating system or architecture is unsupported. -* -- pPluginRegInfo +* -- H +* -- pRI */ -VOID M_Conf_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_Conf_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } // .status module is always valid - no check against pPluginRegInfo->tpMemoryModel, tpSystem @@ -327,5 +331,5 @@ VOID M_Conf_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) pRI->reg_fn.pfnList = MConf_List; // List function supported pRI->reg_fn.pfnRead = MConf_Read; // Read function supported pRI->reg_fn.pfnWrite = MConf_Write; // Write function supported - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_fc_csv.c b/vmm/m_fc_csv.c new file mode 100644 index 0000000..5af9558 --- /dev/null +++ b/vmm/m_fc_csv.c @@ -0,0 +1,152 @@ +// m_fc_csv.c : implementation of csv file functionality (general & timelining) +// +// REQUIRE: FORENSIC SUB-SYSTEM INIT: TIMELINE +// +// (c) Ulf Frisk, 2022 +// Author: Ulf Frisk, pcileech@frizk.net +// + +#include "fc.h" +#include "vmm.h" +#include "pluginmanager.h" +#include "charutil.h" +#include "util.h" + +#define MFCCSV_TIMELINE_LINEHEADER "Time,Type,Action,PID,Value32,Value64,Text\n" + +/* +* Read the csv version of the timeline info files. +*/ +NTSTATUS M_FcCSV_ReadTimeline2(_In_ VMM_HANDLE H, _In_ DWORD dwTimelineType, _Out_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +{ + NTSTATUS nt = VMMDLL_STATUS_END_OF_FILE; + PFC_MAP_TIMELINEENTRY pe; + PFCOB_MAP_TIMELINE pObMap = NULL; + QWORD i, o, cch, qwIdBase, qwIdTop, cId, cszuBuffer, cbOffsetBuffer; + LPSTR szuBuffer = NULL; + DWORD cbv, dwEntryType, dwEntryAction; + CHAR szTime[22]; + if(!FcTimeline_GetIdFromPosition(H, dwTimelineType, FC_FORMAT_TYPE_CSV, cbOffset, &qwIdBase)) { goto fail; } + if(!FcTimeline_GetIdFromPosition(H, dwTimelineType, FC_FORMAT_TYPE_CSV, cbOffset + cb, &qwIdTop)) { goto fail; } + cId = min(cb / FC_LINELENGTH_TIMELINE_CSV, qwIdTop - qwIdBase) + 1; + if(!FcTimelineMap_GetFromIdRange(H, dwTimelineType, qwIdBase, cId, &pObMap) || !pObMap->cMap) { goto fail; } + cbOffsetBuffer = pObMap->pMap[0].cvszOffset; + if((cbOffsetBuffer > cbOffset) || (cbOffset - cbOffsetBuffer > 0x10000)) { goto fail; } + cszuBuffer = 0x01000000; + if(!(szuBuffer = LocalAlloc(0, (SIZE_T)cszuBuffer))) { goto fail; } + for(i = 0, o = 0; (i < pObMap->cMap) && (o < cszuBuffer - 0x1000); i++) { + pe = pObMap->pMap + i; + Util_FileTime2CSV(pe->ft, szTime); + dwEntryType = (pe->tp < H->fc->Timeline.cTp) ? pe->tp : 0; + dwEntryAction = (pe->ac <= FC_TIMELINE_ACTION_MAX) ? pe->ac : FC_TIMELINE_ACTION_NONE; + cch = snprintf( + szuBuffer + o, + (SIZE_T)(cszuBuffer - o), + "%s,%s,%s,%u,0x%x,0x%llx,", + szTime, + H->fc->Timeline.pInfo[dwEntryType].szNameShort, + FC_TIMELINE_ACTION_STR[dwEntryAction], + pe->pid, + pe->data32, + pe->data64 + ); + o += cch; + CharUtil_UtoCSV(pe->uszText, -1, szuBuffer + o, min((DWORD)(pe->cvszText + 1), (DWORD)(cszuBuffer - o)), NULL, &cbv, CHARUTIL_FLAG_STR_BUFONLY); + o += cbv - 1; + o += snprintf( + szuBuffer + o, + (SIZE_T)(cszuBuffer - o), + ",%*s\n", + (DWORD)(FC_LINELENGTH_TIMELINE_CSV - cch - 2), + "" + ); + } + nt = Util_VfsReadFile_FromPBYTE(szuBuffer, o, pb, cb, pcbRead, cbOffset - cbOffsetBuffer); +fail: + LocalFree(szuBuffer); + Ob_DECREF(pObMap); + return nt; +} + +/* +* Read the csv version of the timeline info files. +*/ +NTSTATUS M_FcCSV_ReadTimeline(_In_ VMM_HANDLE H, _In_ DWORD dwTimelineType, _Out_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +{ + NTSTATUS nt; + DWORD cbHdr = 0, cbRead = 0; + if(cbOffset < VMM_STRLEN(MFCCSV_TIMELINE_LINEHEADER)) { + nt = Util_VfsReadFile_FromPBYTE((PBYTE)MFCCSV_TIMELINE_LINEHEADER, VMM_STRLEN(MFCCSV_TIMELINE_LINEHEADER), pb, cb, pcbRead, cbOffset); + cbHdr = *pcbRead; + if(cbHdr && (cb > cbHdr)) { + M_FcCSV_ReadTimeline2(H, dwTimelineType, pb + cbHdr, cb - cbHdr, &cbRead, 0); + *pcbRead = cbHdr + cbRead; + } + return nt; + } + return M_FcCSV_ReadTimeline2(H, dwTimelineType, pb, cb, pcbRead, cbOffset - VMM_STRLEN(MFCCSV_TIMELINE_LINEHEADER)); +} + +NTSTATUS M_FcCSV_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +{ + DWORD i; + NTSTATUS nt; + QWORD qwFileHash; + PFC_TIMELINE_INFO pi; + PFCOB_FILE pObFile = NULL; + // 1: timeline + for(i = 0; i < H->fc->Timeline.cTp; i++) { + pi = H->fc->Timeline.pInfo + i; + if(!_stricmp(ctxP->uszPath, pi->uszNameFileCSV)) { + return M_FcCSV_ReadTimeline(H, pi->dwId, pb, cb, pcbRead, cbOffset); + } + } + // 2: memory backed files: + qwFileHash = CharUtil_Hash64U(ctxP->uszPath, TRUE); + if((pObFile = ObMap_GetByKey(H->fc->FileCSV.pm, qwFileHash))) { + nt = ObMemFile_ReadFile(pObFile->pmf, pb, cb, pcbRead, cbOffset); + Ob_DECREF(pObFile); + return nt; + } + return VMMDLL_STATUS_FILE_INVALID; +} + +BOOL M_FcCSV_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) +{ + QWORD i; + PFC_TIMELINE_INFO pi; + PFCOB_FILE pObFile = NULL; + if(ctxP->uszPath[0]) { return FALSE; } + // 1: timeline + for(i = 0; i < H->fc->Timeline.cTp; i++) { + pi = H->fc->Timeline.pInfo + i; + if(pi->uszNameFileTXT[0]) { + VMMDLL_VfsList_AddFile(pFileList, pi->uszNameFileCSV, VMM_STRLEN(MFCCSV_TIMELINE_LINEHEADER) + pi->dwFileSizeCSV, NULL); + } + } + // 2: memory backed files: + while((pObFile = ObMap_GetNext(H->fc->FileCSV.pm, pObFile))) { + VMMDLL_VfsList_AddFile(pFileList, pObFile->uszName, ObMemFile_Size(pObFile->pmf), NULL); + } + return TRUE; +} + +VOID M_FcCSV_Notify(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent) +{ + if(fEvent == VMMDLL_PLUGIN_NOTIFY_FORENSIC_INIT_COMPLETE) { + PluginManager_SetVisibility(H, TRUE, "\\forensic\\csv", TRUE); + } +} + +VOID M_FcCSV_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +{ + if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } + if((pRI->tpSystem != VMM_SYSTEM_WINDOWS_X64) && (pRI->tpSystem != VMM_SYSTEM_WINDOWS_X86)) { return; } + strcpy_s(pRI->reg_info.uszPathName, 128, "\\forensic\\csv"); // module name + pRI->reg_info.fRootModule = TRUE; // module shows in root directory + pRI->reg_info.fRootModuleHidden = TRUE; // module hidden by default + pRI->reg_fn.pfnList = M_FcCSV_List; // List function supported + pRI->reg_fn.pfnRead = M_FcCSV_Read; // Read function supported + pRI->reg_fn.pfnNotify = M_FcCSV_Notify; // Notify function supported + pRI->pfnPluginManager_Register(H, pRI); +} diff --git a/vmm/m_fc_handle.c b/vmm/m_fc_handle.c new file mode 100644 index 0000000..9ba36b8 --- /dev/null +++ b/vmm/m_fc_handle.c @@ -0,0 +1,80 @@ +// m_fc_handle.c : handle forensic module. +// +// REQUIRE: FORENSIC SUB-SYSTEM INIT. +// +// NB! module generate forensic data only - no file system presence! +// +// (c) Ulf Frisk,2022 +// Author: Ulf Frisk, pcileech@frizk.net +// + +#include "fc.h" +#include "vmm.h" +#include "vmmwin.h" +#include "pluginmanager.h" +#include "util.h" + +static LPSTR MFCHANDLE_CSV_HANDLE = "PID,Handle,Object,Access,Type,Tag,HandleCount,Device,Description\n"; + +PVOID MFcHandle_FcInitialize(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP) +{ + FcFileAppend(H, "handles.csv", MFCHANDLE_CSV_HANDLE); + return NULL; +} + +VOID MFcHandle_FcLogCSV(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VMMDLL_CSV_HANDLE hCSV) +{ + PVMM_PROCESS pProcess = ctxP->pProcess; + PVMMOB_MAP_HANDLE pObHandleMap = NULL; + PVMM_MAP_HANDLEENTRY pe; + PVMMWIN_OBJECT_TYPE pOT; + CHAR szType[32] = { 0 }; + CHAR szPoolTag[5] = { 0 }; + CHAR uszBufferDevName[MAX_PATH] = { 0 }; + DWORD i; + if(pProcess && VmmMap_GetHandle(H, pProcess, &pObHandleMap, TRUE)) { + for(i = 0; i < pObHandleMap->cMap; i++) { + pe = pObHandleMap->pMap + i; + // type&pool tag: + *(PDWORD)szPoolTag = pe->dwPoolTag; + if((pOT = VmmWin_ObjectTypeGet(H, (BYTE)pe->iType))) { + snprintf(szType, _countof(szType), "%s", pOT->usz); + szType[16] = 0; + } else { + *(PDWORD)szType = pe->dwPoolTag; + szType[4] = 0; + } + // device object name: + uszBufferDevName[0] = 0; + if(pe->_InfoFile.dwoName) { + strncpy_s(uszBufferDevName, sizeof(uszBufferDevName), pe->uszText + 1, pe->_InfoFile.dwoName - 1); + } + // csv file append: + FcCsv_Reset(hCSV); + FcFileAppend(H, "handles.csv", "%i,0x%x,0x%llx,%x,%s,%s,0x%llx,%s,%s\n", + pProcess->dwPID, + pe->dwHandle, + pe->vaObject, + pe->dwGrantedAccess, + FcCsv_String(hCSV, szType), + FcCsv_String(hCSV, szPoolTag), + pe->qwHandleCount, + FcCsv_String(hCSV, uszBufferDevName), + FcCsv_String(hCSV, pe->uszText + pe->_InfoFile.dwoName) + ); + } + } + Ob_DECREF(pObHandleMap); +} + +VOID M_FcHandle_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +{ + if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } + if((pRI->tpSystem != VMM_SYSTEM_WINDOWS_X64) && (pRI->tpSystem != VMM_SYSTEM_WINDOWS_X86)) { return; } + strcpy_s(pRI->reg_info.uszPathName, 128, "\\forensic\\hidden\\handles"); // module name + pRI->reg_info.fRootModule = TRUE; // module shows in root directory + pRI->reg_info.fRootModuleHidden = TRUE; // module hidden by default + pRI->reg_fnfc.pfnInitialize = MFcHandle_FcInitialize; // Forensic initialize function supported + pRI->reg_fnfc.pfnLogCSV = MFcHandle_FcLogCSV; // CSV log function supported + pRI->pfnPluginManager_Register(H, pRI); +} diff --git a/vmm/m_fc_json.c b/vmm/m_fc_json.c index 461d635..922c4eb 100644 --- a/vmm/m_fc_json.c +++ b/vmm/m_fc_json.c @@ -17,8 +17,9 @@ /* * Read the json version of the timeline info files. */ -NTSTATUS M_FcJSON_TimelineReadInfo(_Out_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS M_FcJSON_TimelineReadInfo(_In_ VMM_HANDLE H, _Out_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { + PFC_CONTEXT ctxFc = H->fc; NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; PFC_MAP_TIMELINEENTRY pe; PFCOB_MAP_TIMELINE pObMap = NULL; @@ -27,10 +28,10 @@ NTSTATUS M_FcJSON_TimelineReadInfo(_Out_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD p LPSTR szj, szuBuffer = NULL; DWORD dwEntryType, dwEntryAction; CHAR szTime[21]; - if(!FcTimeline_GetIdFromPosition(0, TRUE, cbOffset, &qwIdBase)) { goto fail; } - if(!FcTimeline_GetIdFromPosition(0, TRUE, cbOffset + cb, &qwIdTop)) { goto fail; } + if(!FcTimeline_GetIdFromPosition(H, 0, FC_FORMAT_TYPE_JSON, cbOffset, &qwIdBase)) { goto fail; } + if(!FcTimeline_GetIdFromPosition(H, 0, FC_FORMAT_TYPE_JSON, cbOffset + cb, &qwIdTop)) { goto fail; } cId = min(cb / FC_LINELENGTH_TIMELINE_JSON, qwIdTop - qwIdBase) + 1; - if(!FcTimelineMap_GetFromIdRange(0, qwIdBase, cId, &pObMap) || !pObMap->cMap) { goto fail; } + if(!FcTimelineMap_GetFromIdRange(H, 0, qwIdBase, cId, &pObMap) || !pObMap->cMap) { goto fail; } cbOffsetBuffer = pObMap->pMap[0].cjszOffset; if((cbOffsetBuffer > cbOffset) || (cbOffset - cbOffsetBuffer > 0x10000)) { goto fail; } cszuBuffer = 0x01000000; @@ -43,9 +44,9 @@ NTSTATUS M_FcJSON_TimelineReadInfo(_Out_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD p o += cbln = snprintf( szuBuffer + o, cszuBuffer - o, - "{\"class\":\"TL\",\"ver\":\"%i.%i\",\"sys\":\"%s\",\"date\":\"%s\",\"type\":\"%s\",\"action\":\"%s\",\"pid\":%u,\"num\":%u,\"hex\":\"%llx\",\"desc\":\"", + "{\"class\":\"TL\",\"ver\":\"%i.%i\",\"sys\":\"%s\",\"date\":\"%s\",\"type\":\"%-3s\",\"action\":\"%s\",\"pid\":%u,\"num\":%u,\"hex\":\"%llx\",\"desc\":\"", VERSION_MAJOR, VERSION_MINOR, - ctxVmm->szSystemUniqueTag, + H->vmm.szSystemUniqueTag, szTime, ctxFc->Timeline.pInfo[dwEntryType].szNameShort, FC_TIMELINE_ACTION_STR[dwEntryAction], @@ -64,73 +65,60 @@ fail: return nt; } -NTSTATUS M_FcJSON_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS M_FcJSON_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { + PFC_CONTEXT ctxFc = H->fc; NTSTATUS nt = STATUS_END_OF_FILE; DWORD cbRead = 0; QWORD cbGen = ObMemFile_Size(ctxFc->FileJSON.pGen); #ifdef _WIN32 - if(!_stricmp(ctx->uszPath, "elastic_import.ps1")) { - return Util_VfsReadFile_FromResource(L"RCFILE_FC_JSON_ELASTIC_IMPORT", pb, cb, pcbRead, cbOffset); + if(!_stricmp(ctxP->uszPath, "elastic_import.ps1")) { + return Util_VfsReadFile_FromResource(H, L"RCFILE_FC_JSON_ELASTIC_IMPORT", pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "elastic_import_unauth.ps1")) { - return Util_VfsReadFile_FromResource(L"RCFILE_FC_JSON_ELASTIC_IMPORT_UNAUTH", pb, cb, pcbRead, cbOffset); + if(!_stricmp(ctxP->uszPath, "elastic_import_unauth.ps1")) { + return Util_VfsReadFile_FromResource(H, L"RCFILE_FC_JSON_ELASTIC_IMPORT_UNAUTH", pb, cb, pcbRead, cbOffset); } #endif /* _WIN32 */ - if(!_stricmp(ctx->uszPath, "general.json")) { + if(!_stricmp(ctxP->uszPath, "general.json")) { return ObMemFile_ReadFile(ctxFc->FileJSON.pGen, pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "general-v.json")) { - *pcbRead = 0; - if(cbOffset < cbGen) { - nt = ObMemFile_ReadFile(ctxFc->FileJSON.pGen, pb, cb, &cbRead, cbOffset); - pb += cbRead; - cb -= cbRead; - cbOffset += cbRead; - } - if(cb && (cbOffset >= cbGen)) { - nt = ObMemFile_ReadFile(ctxFc->FileJSON.pGenVerbose, pb, cb, pcbRead, cbOffset - cbGen); - } - *pcbRead += cbRead; - return nt; - } - if(!_stricmp(ctx->uszPath, "registry.json")) { + if(!_stricmp(ctxP->uszPath, "registry.json")) { return ObMemFile_ReadFile(ctxFc->FileJSON.pReg, pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "timeline.json")) { - return M_FcJSON_TimelineReadInfo(pb, cb, pcbRead, cbOffset); + if(!_stricmp(ctxP->uszPath, "timeline.json")) { + return M_FcJSON_TimelineReadInfo(H, pb, cb, pcbRead, cbOffset); } return VMMDLL_STATUS_FILE_INVALID; } -BOOL M_FcJSON_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) +BOOL M_FcJSON_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { + PFC_CONTEXT ctxFc = H->fc; PFC_TIMELINE_INFO pi = ctxFc->Timeline.pInfo + 0; - if(ctx->uszPath[0]) { return FALSE; } + if(ctxP->uszPath[0] || !pi) { return FALSE; } #ifdef _WIN32 DWORD cbElasticPs1; - if((cbElasticPs1 = Util_ResourceSize(L"RCFILE_FC_JSON_ELASTIC_IMPORT"))) { + if((cbElasticPs1 = Util_ResourceSize(H, L"RCFILE_FC_JSON_ELASTIC_IMPORT"))) { VMMDLL_VfsList_AddFile(pFileList, "elastic_import.ps1", cbElasticPs1, NULL); } - if((cbElasticPs1 = Util_ResourceSize(L"RCFILE_FC_JSON_ELASTIC_IMPORT_UNAUTH"))) { + if((cbElasticPs1 = Util_ResourceSize(H, L"RCFILE_FC_JSON_ELASTIC_IMPORT_UNAUTH"))) { VMMDLL_VfsList_AddFile(pFileList, "elastic_import_unauth.ps1", cbElasticPs1, NULL); } #endif /* _WIN32 */ VMMDLL_VfsList_AddFile(pFileList, "general.json", ObMemFile_Size(ctxFc->FileJSON.pGen), NULL); - VMMDLL_VfsList_AddFile(pFileList, "general-v.json", ObMemFile_Size(ctxFc->FileJSON.pGen) + ObMemFile_Size(ctxFc->FileJSON.pGenVerbose), NULL); VMMDLL_VfsList_AddFile(pFileList, "registry.json", ObMemFile_Size(ctxFc->FileJSON.pReg), NULL); VMMDLL_VfsList_AddFile(pFileList, "timeline.json", pi->dwFileSizeJSON, NULL); return TRUE; } -VOID M_FcJSON_Notify(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent) +VOID M_FcJSON_Notify(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent) { if(fEvent == VMMDLL_PLUGIN_NOTIFY_FORENSIC_INIT_COMPLETE) { - PluginManager_SetVisibility(TRUE, "\\forensic\\json", TRUE); + PluginManager_SetVisibility(H, TRUE, "\\forensic\\json", TRUE); } } -VOID M_FcJSON_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_FcJSON_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if((pRI->tpSystem != VMM_SYSTEM_WINDOWS_X64) && (pRI->tpSystem != VMM_SYSTEM_WINDOWS_X86)) { return; } @@ -140,5 +128,5 @@ VOID M_FcJSON_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) pRI->reg_fn.pfnList = M_FcJSON_List; // List function supported pRI->reg_fn.pfnRead = M_FcJSON_Read; // Read function supported pRI->reg_fn.pfnNotify = M_FcJSON_Notify; // Notify function supported - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_fc_module.c b/vmm/m_fc_module.c index 3ff1b61..15c1f0d 100644 --- a/vmm/m_fc_module.c +++ b/vmm/m_fc_module.c @@ -12,118 +12,49 @@ #include "vmm.h" #include "pe.h" #include "pluginmanager.h" +#include "charutil.h" #include "util.h" -VOID MFcModule_LogEAT(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd, _In_ VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData), _In_ PVMM_PROCESS pProcess, PVMM_MAP_MODULEENTRY peM) -{ - PVMMOB_MAP_EAT pObEatMap = NULL; - PVMM_MAP_EATENTRY pe; - DWORD i; - if(VmmMap_GetEAT(pProcess, peM, &pObEatMap)) { - for(i = 0; i < pObEatMap->cMap; i++) { - pe = pObEatMap->pMap + i; - pd->i = i; - pd->va[0] = pe->vaFunction; - pd->qwNum[1] = pe->dwOrdinal; - pd->qwHex[0] = pe->vaFunction - peM->vaBase; - pd->usz[0] = peM->uszText; - pd->usz[1] = pe->uszFunction; - pfnLogJSON(pd); - } - } - Ob_DECREF(pObEatMap); -} +static LPSTR MFCMODULE_CSV_MODULES = "PID,Name,Wow64,Size,Start,End,#Imports,#Exports,#Sections,Path,KernelPath,PdbPath,PdbAge,PdbHexGUID\n"; +static LPSTR MFCMODULE_CSV_UNLOADEDMODULES = "PID,ModuleName,UnloadTime,Wow64,Size,Start,End\n"; -VOID MFcModule_LogIAT(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd, _In_ VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData), _In_ PVMM_PROCESS pProcess, PVMM_MAP_MODULEENTRY peM) -{ - PVMMOB_MAP_IAT pObIatMap = NULL; - PVMM_MAP_IATENTRY pe; - DWORD i; - CHAR usz[MAX_PATH]; - if(VmmMap_GetIAT(pProcess, peM, &pObIatMap)) { - for(i = 0; i < pObIatMap->cMap; i++) { - pe = pObIatMap->pMap + i; - snprintf(usz, _countof(usz), "%s!%s", pe->uszModule, pe->uszFunction); - pd->i = i; - pd->va[0] = pe->vaFunction; - pd->usz[0] = peM->uszText; - pd->usz[1] = usz; - pfnLogJSON(pd); - } - } - Ob_DECREF(pObIatMap); -} - -VOID MFcModule_LogDirectory(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd, _In_ VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData), _In_ PVMM_PROCESS pProcess, PVMM_MAP_MODULEENTRY peM) -{ - DWORD i; - PIMAGE_DATA_DIRECTORY pe; - IMAGE_DATA_DIRECTORY Directory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; - if(!PE_DirectoryGetAll(pProcess, peM->vaBase, NULL, Directory)) { return; } - for(i = 0; i < 16; i++) { - pe = Directory + i; - if(pe->VirtualAddress) { - pd->va[0] = peM->vaBase + pe->VirtualAddress; - pd->va[1] = pe->VirtualAddress; - pd->qwNum[0] = pe->Size; - pd->usz[0] = (LPSTR)PE_DATA_DIRECTORIES[i]; - pfnLogJSON(pd); - } - } -} - -VOID MFcModule_LogSection(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd, _In_ VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData), _In_ PVMM_PROCESS pProcess, PVMM_MAP_MODULEENTRY peM) -{ - DWORD i, cSections; - CHAR usz[32]; - PIMAGE_SECTION_HEADER pSections = NULL; - PIMAGE_SECTION_HEADER pe; - cSections = PE_SectionGetNumberOf(pProcess, peM->vaBase); - if(!cSections || !(pSections = LocalAlloc(LMEM_ZEROINIT, cSections * sizeof(IMAGE_SECTION_HEADER)))) { return; } - if(PE_SectionGetAll(pProcess, peM->vaBase, cSections, pSections)) { - for(i = 0; i < cSections; i++) { - pe = pSections + i; - pd->i = i; - pd->va[0] = peM->vaBase + pe->VirtualAddress; - pd->qwNum[0] = pe->Misc.VirtualSize; - pd->qwHex[0] = pe->VirtualAddress; - pd->qwHex[1] = pe->Misc.VirtualSize; - pe->Misc.VirtualSize = 0; // effectively null-terminates pe->Name - snprintf(usz, sizeof(usz), "%s %c%c%c", - pe->Name, - (pe->Characteristics & IMAGE_SCN_MEM_READ) ? 'r' : '-', - (pe->Characteristics & IMAGE_SCN_MEM_WRITE) ? 'w' : '-', - (pe->Characteristics & IMAGE_SCN_MEM_EXECUTE) ? 'x' : '-'); - pd->usz[0] = peM->uszText; - pd->usz[1] = usz; - pfnLogJSON(pd); - } - } - LocalFree(pSections); -} - -VOID MFcModule_LogCodeView(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd, _In_ VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData), _In_ PVMM_PROCESS pProcess, PVMM_MAP_MODULEENTRY peM) +_Success_(return) +BOOL MFcModule_GetCodeView(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, PVMM_MAP_MODULEENTRY peM, _Out_writes_(33) LPSTR szGUID, _Out_writes_(MAX_PATH) LPSTR szPdbFileName, _Out_ PDWORD pdwAge) { LPCSTR szHEX_ALPHABET = "0123456789ABCDEF"; - CHAR usz[MAX_PATH], szGuidHEX[33] = { 0 }; - DWORD i, j; BYTE b; + DWORD i, j; PE_CODEVIEW_INFO CodeViewInfo = { 0 }; - if(!PE_GetCodeViewInfo(pProcess, peM->vaBase, NULL, &CodeViewInfo)) { return; } + szGUID[0] = 0; + szPdbFileName[0] = 0; + *pdwAge = 0; + if(!PE_GetCodeViewInfo(H, pProcess, peM->vaBase, NULL, &CodeViewInfo)) { return FALSE; } // guid -> hex for(i = 0, j = 0; i < 16; i++) { b = CodeViewInfo.CodeView.Guid[i]; - szGuidHEX[j++] = szHEX_ALPHABET[b >> 4]; - szGuidHEX[j++] = szHEX_ALPHABET[b & 7]; + szGUID[j++] = szHEX_ALPHABET[b >> 4]; + szGUID[j++] = szHEX_ALPHABET[b & 7]; } - snprintf(usz, sizeof(usz), "AGE=[%i] GUID=[%s] PDB=[%s]", CodeViewInfo.CodeView.Age, szGuidHEX, CodeViewInfo.CodeView.PdbFileName); - pd->qwNum[0] = CodeViewInfo.CodeView.Age; - pd->usz[0] = peM->uszText; - pd->usz[1] = usz; - pfnLogJSON(pd); + szGUID[32] = 0; + strncpy_s(szPdbFileName, MAX_PATH, CodeViewInfo.CodeView.PdbFileName, _TRUNCATE); + *pdwAge = CodeViewInfo.CodeView.Age; + return TRUE; } -VOID MFcModule_LogModule(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd, _In_ VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData), PVMMOB_MAP_MODULE pMap) +VOID MFcModule_LogCodeView(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd, _In_ VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData), _In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_MODULEENTRY peM) +{ + DWORD dwAge; + CHAR usz[MAX_PATH], szGUID[33], szPdbFileName[MAX_PATH]; + if(MFcModule_GetCodeView(H, pProcess, peM, szGUID, szPdbFileName, &dwAge)) { + snprintf(usz, sizeof(usz), "AGE=[%i] GUID=[%s] PDB=[%s]", dwAge, szGUID, szPdbFileName); + pd->qwNum[0] = dwAge; + pd->usz[0] = peM->uszText; + pd->usz[1] = usz; + pfnLogJSON(H, pd); + } +} + +VOID MFcModule_LogModule(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd, _In_ VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData), _In_ PVMMOB_MAP_MODULE pMap) { DWORD i; PVMM_MAP_MODULEENTRY pe; @@ -136,11 +67,11 @@ VOID MFcModule_LogModule(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd, _In_ VOID(*pf pd->va[0] = pe->vaBase; pd->va[1] = pe->vaBase + pe->cbImageSize - 1; pd->usz[0] = pe->uszText; - pfnLogJSON(pd); + pfnLogJSON(H, pd); } } -VOID MFcModule_LogUnloadedModule(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd, _In_ VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData), PVMMOB_MAP_UNLOADEDMODULE pMap) +VOID MFcModule_LogUnloadedModule(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd, _In_ VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData), PVMMOB_MAP_UNLOADEDMODULE pMap) { DWORD i; PVMM_MAP_UNLOADEDMODULEENTRY pe; @@ -153,11 +84,11 @@ VOID MFcModule_LogUnloadedModule(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd, _In_ pd->va[0] = pe->vaBase; pd->va[1] = pe->vaBase + pe->cbImageSize - 1; pd->usz[0] = pe->uszText; - pfnLogJSON(pd); + pfnLogJSON(H, pd); } } -VOID MFcModule_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) +VOID MFcModule_FcLogJSON(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) { PVMM_PROCESS pProcess = ctxP->pProcess; PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd; @@ -168,60 +99,137 @@ VOID MFcModule_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON if(!pProcess || !(pd = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMDLL_PLUGIN_FORENSIC_JSONDATA)))) { return; } // loaded modules: FC_JSONDATA_INIT_PIDTYPE(pd, pProcess->dwPID, "module"); - if(VmmMap_GetModule(pProcess, &pObModuleMap)) { - MFcModule_LogModule(pd, pfnLogJSON, pObModuleMap); + if(VmmMap_GetModule(H, pProcess, &pObModuleMap)) { + if(H->fAbort) { goto fail; } + MFcModule_LogModule(H, pd, pfnLogJSON, pObModuleMap); } // unloaded modules: FC_JSONDATA_INIT_PIDTYPE(pd, pProcess->dwPID, "unloadedmodule"); - if(VmmMap_GetUnloadedModule(pProcess, &pObUnloadedModuleMap)) { - MFcModule_LogUnloadedModule(pd, pfnLogJSON, pObUnloadedModuleMap); + if(VmmMap_GetUnloadedModule(H, pProcess, &pObUnloadedModuleMap)) { + if(H->fAbort) { goto fail; } + MFcModule_LogUnloadedModule(H, pd, pfnLogJSON, pObUnloadedModuleMap); } // pdb debug info / codeview: FC_JSONDATA_INIT_PIDTYPE(pd, pProcess->dwPID, "codeview"); for(i = 0; i < pObModuleMap->cMap; i++) { + if(H->fAbort) { goto fail; } peM = pObModuleMap->pMap + i; - MFcModule_LogCodeView(pd, pfnLogJSON, pProcess, peM); - } - // data directories: - FC_JSONDATA_INIT_PIDTYPE(pd, pProcess->dwPID, "datadir"); pd->fVerbose = TRUE; - for(i = 0; i < pObModuleMap->cMap; i++) { - peM = pObModuleMap->pMap + i; - MFcModule_LogDirectory(pd, pfnLogJSON, pProcess, peM); - } - // sections: - FC_JSONDATA_INIT_PIDTYPE(pd, pProcess->dwPID, "section"); pd->fVerbose = TRUE; - for(i = 0; i < pObModuleMap->cMap; i++) { - peM = pObModuleMap->pMap + i; - MFcModule_LogSection(pd, pfnLogJSON, pProcess, peM); - } - // imports: - FC_JSONDATA_INIT_PIDTYPE(pd, pProcess->dwPID, "import"); pd->fVerbose = TRUE; - for(i = 0; i < pObModuleMap->cMap; i++) { - peM = pObModuleMap->pMap + i; - MFcModule_LogIAT(pd, pfnLogJSON, pProcess, peM); - } - // exports: - FC_JSONDATA_INIT_PIDTYPE(pd, pProcess->dwPID, "export"); pd->fVerbose = TRUE; - for(i = 0; i < pObModuleMap->cMap; i++) { - peM = pObModuleMap->pMap + i; - MFcModule_LogEAT(pd, pfnLogJSON, pProcess, peM); + MFcModule_LogCodeView(H, pd, pfnLogJSON, pProcess, peM); } +fail: Ob_DECREF(pObModuleMap); Ob_DECREF(pObUnloadedModuleMap); LocalFree(pd); } +VOID MFcModule_LogModuleCSV(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ VMMDLL_CSV_HANDLE hCSV, _In_ PVMMOB_MAP_MODULE pMap) +{ + BOOL fSuppressDriver; + DWORD i; + PVMM_MAP_MODULEENTRY pe; + DWORD dwAge; + CHAR szGUID[33], szPdbFileName[MAX_PATH]; + PVMM_MAP_VADENTRY peVad = NULL; + PVMMOB_MAP_VAD pObVadMap = NULL; + VmmMap_GetVad(H, pProcess, &pObVadMap, VMM_VADMAP_TP_FULL); + fSuppressDriver = !_stricmp(pProcess->szName, "csrss.exe") || !_stricmp(pProcess->szName, "Registry"); + for(i = 0; i < pMap->cMap; i++) { + pe = pMap->pMap + i; + if(fSuppressDriver && CharUtil_StrEndsWith(pe->uszText, ".sys", FALSE)) { continue; } + if(!MFcModule_GetCodeView(H, pProcess, pe, szGUID, szPdbFileName, &dwAge)) { + dwAge = 0; + szGUID[0] = 0; + szPdbFileName[0] = 0; + } + peVad = VmmMap_GetVadEntry(H, pObVadMap, pe->vaBase); + //"PID,Name,Wow64,Size,Start,End,#Imports,#Exports,#Sections,Path,KernelPath,PdbPath,PdbAge,PdbHexGUID" + FcCsv_Reset(hCSV); + FcFileAppend(H, "modules.csv", "%i,%s,%i,0x%x,0x%llx,0x%llx,%i,%i,%i,%s,%s,%s,%i,%s\n", + pProcess->dwPID, + FcCsv_String(hCSV, pe->uszText), + pe->fWoW64 ? 1 : 0, + pe->cbImageSize, + pe->vaBase, + pe->vaBase + pe->cbImageSize - 1, + pe->cIAT, + pe->cEAT, + pe->cSection, + FcCsv_String(hCSV, pe->uszFullName), + peVad ? FcCsv_String(hCSV, peVad->uszText) : "", + FcCsv_String(hCSV, szPdbFileName), + dwAge, + FcCsv_String(hCSV, szGUID) + ); + } + Ob_DECREF(pObVadMap); +} + +VOID MFcModule_LogUnloadedModuleCSV(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ VMMDLL_CSV_HANDLE hCSV, _In_ PVMMOB_MAP_UNLOADEDMODULE pMap) +{ + DWORD i; + CHAR vszTimeUnload[24]; + PVMM_MAP_UNLOADEDMODULEENTRY pe; + for(i = 0; i < pMap->cMap; i++) { + pe = pMap->pMap + i; + Util_FileTime2CSV(pe->ftUnload, vszTimeUnload); + //"PID,ModuleName,UnloadTime,Wow64,Size,Start,End" + FcCsv_Reset(hCSV); + FcFileAppend(H, "unloaded_modules.csv", "%i,%s,%s,%i,0x%x,0x%llx,0x%llx\n", + pProcess->dwPID, + FcCsv_String(hCSV, pe->uszText), + vszTimeUnload, + pe->fWoW64 ? 1 : 0, + pe->cbImageSize, + pe->vaBase, + pe->vaBase + pe->cbImageSize - 1 + ); + } +} + +VOID MFcModule_FcLogCSV(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VMMDLL_CSV_HANDLE hCSV) +{ + PVMM_PROCESS pProcess = ctxP->pProcess; + PVMMOB_MAP_UNLOADEDMODULE pObUnloadedModuleMap = NULL; + PVMMOB_MAP_MODULE pObModuleMap = NULL; + if(!pProcess) { return; } + // loaded modules: + if(VmmMap_GetModule(H, pProcess, &pObModuleMap)) { + if(H->fAbort) { goto fail; } + MFcModule_LogModuleCSV(H, pProcess, hCSV, pObModuleMap); + } + // unloaded modules: + if(VmmMap_GetUnloadedModule(H, pProcess, &pObUnloadedModuleMap)) { + if(H->fAbort) { goto fail; } + if(_stricmp(pProcess->szName, "csrss.exe") && _stricmp(pProcess->szName, "Registry")) { + MFcModule_LogUnloadedModuleCSV(H, pProcess, hCSV, pObUnloadedModuleMap); + } + } +fail: + Ob_DECREF(pObModuleMap); + Ob_DECREF(pObUnloadedModuleMap); +} + +PVOID MFcModule_FcInitialize(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP) +{ + FcFileAppend(H, "modules.csv", MFCMODULE_CSV_MODULES); + FcFileAppend(H, "unloaded_modules.csv", MFCMODULE_CSV_UNLOADEDMODULES); + return NULL; +} + /* * Plugin initialization / registration function called by the plugin manager. +* -- H * -- pRI */ -VOID M_FcModule_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_FcModule_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if((pRI->tpSystem != VMM_SYSTEM_WINDOWS_X64) && (pRI->tpSystem != VMM_SYSTEM_WINDOWS_X86)) { return; } strcpy_s(pRI->reg_info.uszPathName, 128, "\\forensic\\hidden\\module"); // module name pRI->reg_info.fRootModule = TRUE; // module shows in root directory pRI->reg_info.fRootModuleHidden = TRUE; // module hidden by default + pRI->reg_fnfc.pfnInitialize = MFcModule_FcInitialize; // Forensic initialize supported + pRI->reg_fnfc.pfnLogCSV = MFcModule_FcLogCSV; // CSV log function supported pRI->reg_fnfc.pfnLogJSON = MFcModule_FcLogJSON; // JSON log function supported - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_fc_ntfs.c b/vmm/m_fc_ntfs.c index 26e3dcc..17f0316 100644 --- a/vmm/m_fc_ntfs.c +++ b/vmm/m_fc_ntfs.c @@ -261,20 +261,30 @@ VOID FcNtfs_Close(_Frees_ptr_opt_ PFCNTFS_SETUP_CONTEXT ctx) } } +/* +* Finalize the NTFS setup/initialization phase. Close/Clear any allocated contexts. +* -- H +* -- ctxfc +*/ +VOID FcNtfs_Finalize(_In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc) +{ + FcNtfs_Close((PFCNTFS_SETUP_CONTEXT)ctxfc); +} + /* * Initialize a new empty PFCNTFS_SETUP_CONTEXT. * -- return = the initialized context, or NULL on fail. */ -PVOID FcNtfs_Initialize(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) +PVOID FcNtfs_Initialize(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP) { PFCNTFS_SETUP_CONTEXT ctx; - Fc_SqlExec(FC_SQL_SCHEMA_NTFS); + Fc_SqlExec(H, FC_SQL_SCHEMA_NTFS); if(!(ctx = LocalAlloc(LMEM_ZEROINIT, sizeof(FCNTFS_SETUP_CONTEXT)))) { goto fail; } - if(!(ctx->pmDuplicate = ObMap_New(OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } - if(!(ctx->psRoot = ObSet_New())) { goto fail; } - if(!(ctx->psDirFile = ObSet_New())) { goto fail; } - if(!(ctx->pmDir = ObMap_New(0))) { goto fail; } - if(!(ctx->psOrphan = ObSet_New())) { goto fail; } + if(!(ctx->pmDuplicate = ObMap_New(H, OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } + if(!(ctx->psRoot = ObSet_New(H))) { goto fail; } + if(!(ctx->psDirFile = ObSet_New(H))) { goto fail; } + if(!(ctx->pmDir = ObMap_New(H, 0))) { goto fail; } + if(!(ctx->psOrphan = ObSet_New(H))) { goto fail; } return ctx; fail: FcNtfs_Close(ctx); @@ -283,12 +293,13 @@ fail: /* * Try add a single MFT entry to the NTFS MFT dataset. +* -- H * -- ctx * -- qwPhysicalAddress * -- qwVirtualAddress * -- pb */ -VOID FcNtfs_IngestMftEntry(_In_ PFCNTFS_SETUP_CONTEXT ctx, _In_ QWORD qwPhysicalAddress, _In_opt_ QWORD qwVirtualAddress, _In_reads_(0x400) PBYTE pb) +VOID FcNtfs_IngestMftEntry(_In_ VMM_HANDLE H, _In_ PFCNTFS_SETUP_CONTEXT ctx, _In_ QWORD qwPhysicalAddress, _In_opt_ QWORD qwVirtualAddress, _In_reads_(0x400) PBYTE pb) { QWORD qwHashDuplicateCheck; DWORD oA, cbData = 0, cbuName; @@ -332,7 +343,10 @@ VOID FcNtfs_IngestMftEntry(_In_ PFCNTFS_SETUP_CONTEXT ctx, _In_ QWORD qwPhysical if(!pfn->NameLength) { return; } if(!CharUtil_WtoU(pfn->Name, pfn->NameLength, NULL, 0, NULL, &cbuName, 0)) { return; } if(!(pNtfs = LocalAlloc(LMEM_ZEROINIT, sizeof(FCNTFS) + cbuName))) { return; } - if(!CharUtil_WtoU(pfn->Name, pfn->NameLength, pNtfs->uszName, cbuName, NULL, &cbuName, CHARUTIL_FLAG_STR_BUFONLY)) { return; } + if(!CharUtil_WtoU(pfn->Name, pfn->NameLength, pNtfs->uszName, cbuName, NULL, &cbuName, CHARUTIL_FLAG_STR_BUFONLY)) { + LocalFree(pNtfs); + return; + } pNtfs->pa = qwPhysicalAddress; pNtfs->va = qwVirtualAddress; pNtfs->ftCreate = psi->TimeCreate; @@ -366,7 +380,7 @@ VOID FcNtfs_IngestMftEntry(_In_ PFCNTFS_SETUP_CONTEXT ctx, _In_ QWORD qwPhysical ObSet_Push(ctx->psDirFile, (QWORD)pNtfs); } // Debug output: - VmmLog(MID_FORENSIC, LOGLEVEL_DEBUG, " %08x:%04x %12llx %8lli : %c : %s \n", + VmmLog(H, MID_FORENSIC, LOGLEVEL_6_TRACE, " %08x:%04x %12llx %8lli : %c : %s", pNtfs->Setup.dwParentRecordNumber, pNtfs->Setup.wParentSeqenceNumber, pNtfs->pa, @@ -382,7 +396,7 @@ VOID FcNtfs_IngestMftEntry(_In_ PFCNTFS_SETUP_CONTEXT ctx, _In_ QWORD qwPhysical * -- pa * -- pbPage */ -VOID FcNtfs_IngestMftPage(_In_ PFCNTFS_SETUP_CONTEXT ctx, _In_ QWORD pa, _In_reads_(0x1000) PBYTE pbPage) +VOID FcNtfs_IngestMftPage(_In_ VMM_HANDLE H, _In_ PFCNTFS_SETUP_CONTEXT ctx, _In_ QWORD pa, _In_reads_(0x1000) PBYTE pbPage) { QWORD i, va = 0; PNTFS_FILE_RECORD pr; @@ -393,7 +407,7 @@ VOID FcNtfs_IngestMftPage(_In_ PFCNTFS_SETUP_CONTEXT ctx, _In_ QWORD pa, _In_rea if((pr->UpdateSequenceArrayOffset > 0x100) || (pr->UpdateSequenceArraySize > 0x100)) { continue; } if(pr->BaseFileRecordSegment.SegmentNumber) { continue; } if(pr->FirstAttributeOffset > 0x300) { continue; } - FcNtfs_IngestMftEntry(ctx, pa + i, (va ? va + i : 0), pbPage + i); + FcNtfs_IngestMftEntry(H, ctx, pa + i, (va ? va + i : 0), pbPage + i); } } @@ -404,13 +418,13 @@ VOID FcNtfs_IngestMftPage(_In_ PFCNTFS_SETUP_CONTEXT ctx, _In_ QWORD pa, _In_rea * -- pc * -- return = MAP or NULL if no candidate pages found. */ -POB_MAP FcNtfs_IngestGetValidAddrMap(_In_ PVMMDLL_PLUGIN_FORENSIC_INGEST_PHYSMEM pc) +POB_MAP FcNtfs_IngestGetValidAddrMap(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_INGEST_PHYSMEM pc) { BOOL fPfnValidForMft; DWORD i; POB_MAP pmObAddr; PVMMDLL_MAP_PFNENTRY pePfn; - if(!(pmObAddr = ObMap_New(0))) { return NULL; } + if(!(pmObAddr = ObMap_New(H, 0))) { return NULL; } for(i = 0; i < 0x1000; i++) { if((pc->ppMEMs[i]->qwA != (QWORD)-1) && pc->ppMEMs[i]->f && (pc->ppMEMs[i]->cb == 0x1000) && (*(PDWORD)pc->ppMEMs[i]->pb == 'ELIF')) { pePfn = (pc->pPfnMap && (i < pc->pPfnMap->cMap)) ? (pc->pPfnMap->pMap + i) : NULL; @@ -435,18 +449,19 @@ POB_MAP FcNtfs_IngestGetValidAddrMap(_In_ PVMMDLL_PLUGIN_FORENSIC_INGEST_PHYSMEM /* * Analyze a POB_FC_SCANPHYSMEM_CHUNK 16MB memory chunk for MFT file candidates * and add any found to the internal data sets. +* -- H * -- ctxfc * -- pIngestPhysmem */ -VOID FcNtfs_Ingest(_In_opt_ PVOID ctxfc, _In_ PVMMDLL_PLUGIN_FORENSIC_INGEST_PHYSMEM pIngestPhysmem) +VOID FcNtfs_IngestPhysmem(_In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc, _In_ PVMMDLL_PLUGIN_FORENSIC_INGEST_PHYSMEM pIngestPhysmem) { QWORD pa; PBYTE pb; POB_MAP pmObAddr = NULL; PFCNTFS_SETUP_CONTEXT ctx = (PFCNTFS_SETUP_CONTEXT)ctxfc; - if(ctx && (pmObAddr = FcNtfs_IngestGetValidAddrMap(pIngestPhysmem))) { + if(ctx && (pmObAddr = FcNtfs_IngestGetValidAddrMap(H, pIngestPhysmem))) { while((pb = ObMap_PopWithKey(pmObAddr, &pa))) { - FcNtfs_IngestMftPage(ctx, pa, pb); + FcNtfs_IngestMftPage(H, ctx, pa, pb); } } Ob_DECREF(pmObAddr); @@ -551,10 +566,11 @@ PFCNTFS FcNtfs_FinalizeCreateSynthenticDir(_In_ PFCNTFS_SETUP_CONTEXT ctx, _In_ /* * Merge orphan entries and return the global root +* -- H * -- ctx * -- return = the global root, or null if fail */ -PFCNTFS FcNtfs_FinalizeMerge2(_In_ PFCNTFS_SETUP_CONTEXT ctx) +PFCNTFS FcNtfs_FinalizeMerge2(_In_ VMM_HANDLE H, _In_ PFCNTFS_SETUP_CONTEXT ctx) { PFCNTFS pe, pRootOrphan, pRootGlobal = NULL; PDWORD pdwRecordNumberArray = NULL; @@ -609,11 +625,11 @@ fail: /* * Add a file system entry to the database. */ -VOID FcNtfs_Finalize_DatabaseAdd(_In_ PFCNTFS_FINALIZE_CONTEXT ctx, _In_ PFCNTFS pe, _In_ LPSTR uszPathName) +VOID FcNtfs_Finalize_DatabaseAdd(_In_ VMM_HANDLE H, _In_ PFCNTFS_FINALIZE_CONTEXT ctx, _In_ PFCNTFS pe, _In_ LPSTR uszPathName) { QWORD id = pe->iMap; FCSQL_INSERTSTRTABLE SqlStrInsert = { 0 }; - if(!Fc_SqlInsertStr(ctx->st_str, uszPathName + 1, &SqlStrInsert)) { return; } + if(!Fc_SqlInsertStr(H, ctx->st_str, uszPathName + 1, &SqlStrInsert)) { return; } sqlite3_reset(ctx->st); sqlite3_bind_int64(ctx->st, 1, id); sqlite3_bind_int64(ctx->st, 2, pe->pParent ? pe->pParent->iMap : (QWORD)-1); @@ -637,7 +653,7 @@ VOID FcNtfs_Finalize_DatabaseAdd(_In_ PFCNTFS_FINALIZE_CONTEXT ctx, _In_ PFCNTFS ctx->cbJsonTotal += SqlStrInsert.cbj; } -DWORD FcNtfs_FinalizeFinish(_In_ PFCNTFS_FINALIZE_CONTEXT ctx, _In_ POB_SET psHashPath, _In_ PFCNTFS peNtfs, _In_ DWORD iMap, _In_ BYTE iDirDepth, _In_reads_(2048) LPSTR uszPath, _In_ DWORD cuszPath) +DWORD FcNtfs_FinalizeFinish(_In_ VMM_HANDLE H, _In_ PFCNTFS_FINALIZE_CONTEXT ctx, _In_ POB_SET psHashPath, _In_ PFCNTFS peNtfs, _In_ DWORD iMap, _In_ BYTE iDirDepth, _In_reads_(2048) LPSTR uszPath, _In_ DWORD cuszPath) { DWORD dwHashName, cuszName; QWORD qwHashTotal; @@ -659,8 +675,8 @@ DWORD FcNtfs_FinalizeFinish(_In_ PFCNTFS_FINALIZE_CONTEXT ctx, _In_ POB_SET psHa peNtfs->qwHashThis = qwHashTotal; peNtfs->iDirDepth = iDirDepth; peNtfs->iMap = iMap++; - FcNtfs_Finalize_DatabaseAdd(ctx, peNtfs, uszPath); - iMap = FcNtfs_FinalizeFinish(ctx, psHashPath, peNtfs->pChild, iMap, iDirDepth + 1, uszPath, cuszPath + cuszName + 1); + FcNtfs_Finalize_DatabaseAdd(H, ctx, peNtfs, uszPath); + iMap = FcNtfs_FinalizeFinish(H, ctx, psHashPath, peNtfs->pChild, iMap, iDirDepth + 1, uszPath, cuszPath + cuszName + 1); peNtfs = peNtfs->pSibling; } uszPath[cuszPath] = 0; @@ -671,10 +687,10 @@ DWORD FcNtfs_FinalizeFinish(_In_ PFCNTFS_FINALIZE_CONTEXT ctx, _In_ POB_SET psHa * Finalize the NTFS setup/initialization phase. Try to put re-assemble the NTFS * MFT file fragments into some kind of usable file-system approximation using * heuristics and save it to the forensic database. -* -- pvSetupContextNtfs -* -- fScanSuccess +* -- H +* -- ctxfc */ -VOID FcNtfs_Finalize(_In_opt_ PVOID ctxfc) +VOID FcNtfs_IngestFinalize(_In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc) { PFCNTFS_SETUP_CONTEXT ctx = (PFCNTFS_SETUP_CONTEXT)ctxfc; FCNTFS_FINALIZE_CONTEXT ctxFinal = { 0 }; @@ -684,52 +700,53 @@ VOID FcNtfs_Finalize(_In_opt_ PVOID ctxfc) int rc; // initialize general if(!ctx) { goto fail; } - if(!(psObHashPath = ObSet_New())) { goto fail; } + if(!(psObHashPath = ObSet_New(H))) { goto fail; } // merge ingested items and retrieve global root FcNtfs_FinalizeMerge1(ctx); - pNtfsGlobalRoot = FcNtfs_FinalizeMerge2(ctx); + pNtfsGlobalRoot = FcNtfs_FinalizeMerge2(H, ctx); if(!pNtfsGlobalRoot) { goto fail; } // SETUP FINISH: - if(!(ctxFinal.hSql = Fc_SqlReserve())) { goto fail; } + if(!(ctxFinal.hSql = Fc_SqlReserve(H))) { goto fail; } rc = sqlite3_prepare_v2(ctxFinal.hSql, "INSERT INTO ntfs " \ "(id, id_parent, id_str, hash, hash_parent, addr_phys, inode, mft_flags, depth, size_file, size_fileres, time_create, time_modify, time_read, name_seq, oln_u, oln_j) " \ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);" , -1, &ctxFinal.st, NULL); if(rc != SQLITE_OK) { goto fail; } - rc = sqlite3_prepare_v2(ctxFinal.hSql, "INSERT INTO str (id, cbu, cbj, sz) VALUES (?, ?, ?, ?);", -1, &ctxFinal.st_str, NULL); + rc = sqlite3_prepare_v2(ctxFinal.hSql, szFC_SQL_STR_INSERT, -1, &ctxFinal.st_str, NULL); if(rc != SQLITE_OK) { goto fail; } sqlite3_exec(ctxFinal.hSql, "BEGIN TRANSACTION", NULL, NULL, NULL); - DWORD DEBUG_NUM = FcNtfs_FinalizeFinish(&ctxFinal, psObHashPath, pNtfsGlobalRoot, 0, 0, uszPath, 0); + DWORD DEBUG_NUM = FcNtfs_FinalizeFinish(H, &ctxFinal, psObHashPath, pNtfsGlobalRoot, 0, 0, uszPath, 0); sqlite3_exec(ctxFinal.hSql, "COMMIT TRANSACTION", NULL, NULL, NULL); // CLEAN UP: fail: sqlite3_finalize(ctxFinal.st); sqlite3_finalize(ctxFinal.st_str); - Fc_SqlReserveReturn(ctxFinal.hSql); + Fc_SqlReserveReturn(H, ctxFinal.hSql); Ob_DECREF(psObHashPath); - FcNtfs_Close(ctx); } /* * Timeline data by executing a partial SQL query on pre-existing data. +* -- H * -- ctxfc * -- hTimeline * -- pfnAddEntry * -- pfnEntryAddBySql */ VOID FcNtfs_SetupTimeline( + _In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc, _In_ HANDLE hTimeline, - _In_ VOID(*pfnAddEntry)(_In_ HANDLE hTimeline, _In_ QWORD ft, _In_ DWORD dwAction, _In_ DWORD dwPID, _In_ DWORD dwData32, _In_ QWORD qwData64, _In_ LPSTR uszText), - _In_ VOID(*pfnEntryAddBySql)(_In_ HANDLE hTimeline, _In_ DWORD cEntrySql, _In_ LPSTR *pszEntrySql) + _In_ VOID(*pfnAddEntry)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ QWORD ft, _In_ DWORD dwAction, _In_ DWORD dwPID, _In_ DWORD dwData32, _In_ QWORD qwData64, _In_ LPSTR uszText), + _In_ VOID(*pfnEntryAddBySql)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ DWORD cEntrySql, _In_ LPSTR *pszEntrySql) ) { LPSTR pszSql[] = { "id_str, time_create, "STRINGIZE(FC_TIMELINE_ACTION_CREATE)", 0, size_file, addr_phys FROM ntfs WHERE time_create > 0;", "id_str, time_modify, "STRINGIZE(FC_TIMELINE_ACTION_MODIFY)", 0, size_file, addr_phys FROM ntfs WHERE time_modify > 0 AND time_modify != time_create;", "id_str, time_read, "STRINGIZE(FC_TIMELINE_ACTION_READ)" , 0, size_file, addr_phys FROM ntfs WHERE time_read > 0 AND time_read != time_create AND time_read != time_modify;" }; - pfnEntryAddBySql(hTimeline, sizeof(pszSql) / sizeof(LPSTR), pszSql); + pfnEntryAddBySql(H, hTimeline, sizeof(pszSql) / sizeof(LPSTR), pszSql); } @@ -771,6 +788,7 @@ typedef struct tdFCOB_MAP_NTFS { /* * Retrieve the MFT resident data (i.e. read file contents that fit into the MFT). +* -- H * -- pNtfsEntry * -- pbData * -- cbData @@ -778,13 +796,13 @@ typedef struct tdFCOB_MAP_NTFS { * -- return */ _Success_(return) -BOOL FcNtfs_GetMftResidentData(_In_ PFC_MAP_NTFSENTRY pNtfsEntry, _Out_writes_opt_(cbData) PBYTE pbData, _In_ DWORD cbData, _Out_opt_ PDWORD pcbDataRead) +BOOL FcNtfs_GetMftResidentData(_In_ VMM_HANDLE H, _In_ PFC_MAP_NTFSENTRY pNtfsEntry, _Out_writes_opt_(cbData) PBYTE pbData, _In_ DWORD cbData, _Out_opt_ PDWORD pcbDataRead) { DWORD oA; PNTFS_ATTR pa; PNTFS_FILE_RECORD pr; BYTE pbMftEntry[0x400]; - if(!VmmRead(NULL, pNtfsEntry->pa, pbMftEntry, 0x400)) { return FALSE; } + if(!VmmRead(H, NULL, pNtfsEntry->pa, pbMftEntry, 0x400)) { return FALSE; } pr = (PNTFS_FILE_RECORD)pbMftEntry; // Check MFT record number is within the correct location inside the page. if((((pNtfsEntry->pa >> 10) & 0x3) != (0x3 & pr->MftRecordNumber)) || (pr->MftRecordNumber == 0)) { return FALSE; } @@ -811,7 +829,7 @@ BOOL FcNtfs_GetMftResidentData(_In_ PFC_MAP_NTFSENTRY pNtfsEntry, _Out_writes_op #define FCNTFS_SQL_SELECT_FIELDS " sz, id, id_parent, addr_phys, inode, mft_flags, depth, name_seq, time_create, time_modify, time_read, size_file, size_fileres, oln_u, oln_j " _Success_(return) -BOOL FcNtfsMap_CreateInternal(_In_ LPSTR szSqlCount, _In_ LPSTR szSqlSelect, _In_ DWORD cQueryValues, _In_reads_(cQueryValues) PQWORD pqwQueryValues, _Out_ PFCOB_MAP_NTFS *ppObNtfsMap) +BOOL FcNtfsMap_CreateInternal(_In_ VMM_HANDLE H, _In_ LPSTR szSqlCount, _In_ LPSTR szSqlSelect, _In_ DWORD cQueryValues, _In_reads_(cQueryValues) PQWORD pqwQueryValues, _Out_ PFCOB_MAP_NTFS *ppObNtfsMap) { // TODO: CHANGE MAP INTO UTF-8 STRING! int rc; @@ -822,15 +840,15 @@ BOOL FcNtfsMap_CreateInternal(_In_ LPSTR szSqlCount, _In_ LPSTR szSqlSelect, _In PFC_MAP_NTFSENTRY pe; sqlite3 *hSql = NULL; sqlite3_stmt *hStmt = NULL; - rc = Fc_SqlQueryN(szSqlCount, cQueryValues, pqwQueryValues, 2, pqwResult, NULL); + rc = Fc_SqlQueryN(H, szSqlCount, cQueryValues, pqwQueryValues, 2, pqwResult, NULL); if((rc != SQLITE_OK) || (pqwResult[0] > 0x00010000) || (pqwResult[1] > 0x01000000)) { goto fail; } cbuMultiText = (DWORD)(1 + pqwResult[0] + pqwResult[1]); - pObNtfsMap = Ob_Alloc('Mntf', LMEM_ZEROINIT, (SIZE_T)(sizeof(FCOB_MAP_NTFS) + pqwResult[0] * sizeof(FC_MAP_NTFSENTRY) + cbuMultiText), NULL, NULL); + pObNtfsMap = Ob_AllocEx(H, OB_TAG_MOD_FCNTFS_CTX, LMEM_ZEROINIT, (SIZE_T)(sizeof(FCOB_MAP_NTFS) + pqwResult[0] * sizeof(FC_MAP_NTFSENTRY) + cbuMultiText), NULL, NULL); if(!pObNtfsMap) { goto fail; } pObNtfsMap->uszMultiText = (LPSTR)((PBYTE)pObNtfsMap + sizeof(FCOB_MAP_NTFS) + pqwResult[0] * sizeof(FC_MAP_NTFSENTRY)); pObNtfsMap->cbuMultiText = cbuMultiText; pObNtfsMap->cMap = (DWORD)pqwResult[0]; - if(!(hSql = Fc_SqlReserve())) { goto fail; } + if(!(hSql = Fc_SqlReserve(H))) { goto fail; } rc = sqlite3_prepare_v2(hSql, szSqlSelect, -1, &hStmt, 0); if(rc != SQLITE_OK) { goto fail; } for(i = 0; i < cQueryValues; i++) { @@ -867,7 +885,7 @@ BOOL FcNtfsMap_CreateInternal(_In_ LPSTR szSqlCount, _In_ LPSTR szSqlSelect, _In Ob_INCREF(pObNtfsMap); fail: sqlite3_finalize(hStmt); - Fc_SqlReserveReturn(hSql); + Fc_SqlReserveReturn(H, hSql); *ppObNtfsMap = Ob_DECREF(pObNtfsMap); return (*ppObNtfsMap != NULL); } @@ -875,14 +893,16 @@ fail: /* * Retrieve a FCOB_MAP_NTFS map object containing a specific entry given by its * file system hash. +* -- H * -- qwHash * -- ppObNtfsMap * -- return */ _Success_(return) -BOOL FcNtfsMap_GetFromHash(_In_ QWORD qwHash, _Out_ PFCOB_MAP_NTFS * ppObNtfsMap) +BOOL FcNtfsMap_GetFromHash(_In_ VMM_HANDLE H, _In_ QWORD qwHash, _Out_ PFCOB_MAP_NTFS * ppObNtfsMap) { return FcNtfsMap_CreateInternal( + H, "SELECT COUNT(*), SUM(cbu) FROM v_ntfs WHERE hash = ?", "SELECT "FCNTFS_SQL_SELECT_FIELDS" FROM v_ntfs WHERE hash = ?", 1, @@ -894,14 +914,16 @@ BOOL FcNtfsMap_GetFromHash(_In_ QWORD qwHash, _Out_ PFCOB_MAP_NTFS * ppObNtfsMap /* * Retrieve a FCOB_MAP_NTFS map object containing entries which have the same * file system parent given by its parent hash. +* -- H * -- qwHashParent * -- ppObNtfsMap * -- return */ _Success_(return) -BOOL FcNtfsMap_GetFromHashParent(_In_ QWORD qwHashParent, _Out_ PFCOB_MAP_NTFS * ppObNtfsMap) +BOOL FcNtfsMap_GetFromHashParent(_In_ VMM_HANDLE H, _In_ QWORD qwHashParent, _Out_ PFCOB_MAP_NTFS * ppObNtfsMap) { return FcNtfsMap_CreateInternal( + H, "SELECT COUNT(*), SUM(cbu) FROM v_ntfs WHERE hash_parent = ?", "SELECT "FCNTFS_SQL_SELECT_FIELDS" FROM v_ntfs WHERE hash_parent = ?", 1, @@ -912,16 +934,18 @@ BOOL FcNtfsMap_GetFromHashParent(_In_ QWORD qwHashParent, _Out_ PFCOB_MAP_NTFS * /* * Retrieve a FCOB_MAP_NTFS map object containing entries within a range. +* -- H * -- qwId * -- cId * -- ppObNtfsMap * -- return */ _Success_(return) -BOOL FcNtfsMap_GetFromIdRange(_In_ QWORD qwId, _In_ QWORD cId, _Out_ PFCOB_MAP_NTFS * ppObNtfsMap) +BOOL FcNtfsMap_GetFromIdRange(_In_ VMM_HANDLE H, _In_ QWORD qwId, _In_ QWORD cId, _Out_ PFCOB_MAP_NTFS * ppObNtfsMap) { QWORD v[] = { qwId, qwId + cId }; return FcNtfsMap_CreateInternal( + H, "SELECT COUNT(*), SUM(cbu) FROM v_ntfs WHERE id >= ? AND id < ?", "SELECT "FCNTFS_SQL_SELECT_FIELDS" FROM v_ntfs WHERE id >= ? AND id < ? ORDER BY id", 2, @@ -932,17 +956,18 @@ BOOL FcNtfsMap_GetFromIdRange(_In_ QWORD qwId, _In_ QWORD cId, _Out_ PFCOB_MAP_N /* * Retieve the file size of the ntfs information file either in JSON or UTF8. +* -- H * -- pcRecords = number of entries/lines/records. * -- pcbUTF8 = UTF8 text file size. * -- pcbJSON = JSON file size. * -- return */ _Success_(return) -BOOL FcNtfs_GetFileSize(_Out_opt_ PQWORD pcRecords, _Out_opt_ PQWORD pcbUTF8, _Out_opt_ PQWORD pcbJSON) +BOOL FcNtfs_GetFileSize(_In_ VMM_HANDLE H, _Out_opt_ PQWORD pcRecords, _Out_opt_ PQWORD pcbUTF8, _Out_opt_ PQWORD pcbJSON) { QWORD pqwResult[3]; // query below is convoluted but it's very fast ... - if(SQLITE_OK != Fc_SqlQueryN("SELECT id, oln_u+cbu+"STRINGIZE(M_NTFS_INFO_LINELENGTH_UTF8)" AS cbu_tot, oln_j+cbj+"STRINGIZE(M_NTFS_INFO_LINELENGTH_JSON)" AS cbj_tot FROM v_ntfs WHERE id = (SELECT MAX(id) FROM v_ntfs)", 0, NULL, 3, pqwResult, NULL)) { return FALSE; } + if(SQLITE_OK != Fc_SqlQueryN(H, "SELECT id, oln_u+cbu+"STRINGIZE(M_NTFS_INFO_LINELENGTH_UTF8)" AS cbu_tot, oln_j+cbj+"STRINGIZE(M_NTFS_INFO_LINELENGTH_JSON)" AS cbj_tot FROM v_ntfs WHERE id = (SELECT MAX(id) FROM v_ntfs)", 0, NULL, 3, pqwResult, NULL)) { return FALSE; } if(pcRecords) { *pcRecords = pqwResult[0]; } if(pcbUTF8) { *pcbUTF8 = pqwResult[1]; } if(pcbJSON) { *pcbJSON = pqwResult[1]; } @@ -951,18 +976,19 @@ BOOL FcNtfs_GetFileSize(_Out_opt_ PQWORD pcRecords, _Out_opt_ PQWORD pcbUTF8, _O /* * Retrieve the id associated within the position of the info file. +* -- H * -- qwFilePos * -- fJSON * -- pqwId * -- return */ _Success_(return) -BOOL FcNtfs_GetIdFromPosition(_In_ QWORD qwFilePos, _In_ BOOL fJSON, _Out_ PQWORD pqwId) +BOOL FcNtfs_GetIdFromPosition(_In_ VMM_HANDLE H, _In_ QWORD qwFilePos, _In_ BOOL fJSON, _Out_ PQWORD pqwId) { QWORD v[] = { max(2048, qwFilePos) - 2048, qwFilePos }; return fJSON ? - (SQLITE_OK == Fc_SqlQueryN("SELECT MAX(id) FROM ntfs WHERE oln_j >= ? AND oln_j <= ?", 2, v, 1, pqwId, NULL)) : - (SQLITE_OK == Fc_SqlQueryN("SELECT MAX(id) FROM ntfs WHERE oln_u >= ? AND oln_u <= ?", 2, v, 1, pqwId, NULL)); + (SQLITE_OK == Fc_SqlQueryN(H, "SELECT MAX(id) FROM ntfs WHERE oln_j >= ? AND oln_j <= ?", 2, v, 1, pqwId, NULL)) : + (SQLITE_OK == Fc_SqlQueryN(H, "SELECT MAX(id) FROM ntfs WHERE oln_u >= ? AND oln_u <= ?", 2, v, 1, pqwId, NULL)); } @@ -976,11 +1002,12 @@ BOOL FcNtfs_GetIdFromPosition(_In_ QWORD qwFilePos, _In_ BOOL fJSON, _Out_ PQWOR /* * Retrieve info file for single ntfs entry * NB! CALLER LocalFree: return +* -- H * -- peNtfs * -- pcsz * -- return */ -PBYTE M_FcNtfs_ReadInfoSingle(_In_ PFC_MAP_NTFSENTRY peNtfs, _Out_ PDWORD pcsz) +PBYTE M_FcNtfs_ReadInfoSingle(_In_ VMM_HANDLE H, _In_ PFC_MAP_NTFSENTRY peNtfs, _Out_ PDWORD pcsz) { LPSTR sz = NULL; LPSTR uszTextName; @@ -1000,7 +1027,7 @@ PBYTE M_FcNtfs_ReadInfoSingle(_In_ PFC_MAP_NTFSENTRY peNtfs, _Out_ PDWORD pcsz) PNTFS_FILE_NAME pFN; PNTFS_OBJECT_ID pOID; *pcsz = 0; - if(!VmmRead(NULL, peNtfs->pa, pbr, 0x400)) { goto fail; } + if(!VmmRead(H, NULL, peNtfs->pa, pbr, 0x400)) { goto fail; } if(!(sz = LocalAlloc(0, M_NTFS_READINFOSINGLE_BUFFER))) { goto fail; } pR = (PNTFS_FILE_RECORD)pbr; if(pR->FirstAttributeOffset > 0x300) { goto fail; } @@ -1091,8 +1118,9 @@ PBYTE M_FcNtfs_ReadInfoSingle(_In_ PFC_MAP_NTFSENTRY peNtfs, _Out_ PDWORD pcsz) // $DATA if(pA->Type == NTFS_ATTR_TYPE_DATA) { cszHexAscii = sizeof(szHexAscii) - 2; - Util_FillHexAscii(pbr + oA + pA->AttrOffset, pA->AttrLength, 0, szHexAscii, &cszHexAscii); - csz += snprintf(sz + csz, M_NTFS_READINFOSINGLE_BUFFER - csz, "---\n%s", szHexAscii); + if(Util_FillHexAscii(pbr + oA + pA->AttrOffset, pA->AttrLength, 0, szHexAscii, &cszHexAscii)) { + csz += snprintf(sz + csz, M_NTFS_READINFOSINGLE_BUFFER - csz, "---\n%s", szHexAscii); + } } // $OBJECT_ID if((pA->Type == NTFS_ATTR_TYPE_OBJECT_ID) && (pA->AttrLength >= sizeof(NTFS_OBJECT_ID))) { @@ -1114,7 +1142,7 @@ fail: return sz; } -NTSTATUS M_FcNtfs_ReadInfoAll(_Out_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS M_FcNtfs_ReadInfoAll(_In_ VMM_HANDLE H, _Out_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; PFC_MAP_NTFSENTRY pe; @@ -1122,10 +1150,10 @@ NTSTATUS M_FcNtfs_ReadInfoAll(_Out_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRea QWORD i, o, qwIdBase, qwIdTop, cId, cszuBuffer, cbOffsetBuffer; LPSTR szuBuffer = NULL; CHAR szTimeCreate[24], szTimeModify[24]; - if(!FcNtfs_GetIdFromPosition(cbOffset, FALSE, &qwIdBase)) { goto fail; } - if(!FcNtfs_GetIdFromPosition(cbOffset + cb, FALSE, &qwIdTop)) { goto fail; } + if(!FcNtfs_GetIdFromPosition(H, cbOffset, FALSE, &qwIdBase)) { goto fail; } + if(!FcNtfs_GetIdFromPosition(H, cbOffset + cb, FALSE, &qwIdTop)) { goto fail; } cId = min(cb / M_NTFS_INFO_LINELENGTH_UTF8, qwIdTop - qwIdBase) + 1; - if(!FcNtfsMap_GetFromIdRange(qwIdBase, cId, &pObNtfsMap) || !pObNtfsMap->cMap) { goto fail; } + if(!FcNtfsMap_GetFromIdRange(H, qwIdBase, cId, &pObNtfsMap) || !pObNtfsMap->cMap) { goto fail; } cbOffsetBuffer = pObNtfsMap->pMap[0].cszuOffset; if((cbOffsetBuffer > cbOffset) || (cbOffset - cbOffsetBuffer > 0x10000)) { goto fail; } cszuBuffer = 0x01000000; @@ -1160,6 +1188,7 @@ fail: * Check if the path contains the meta info directory '$_INFO' and also if * it points to a file '\mftinfo.txt' / '\mftdata.mem' / '\mftdata.bin'. * If so strip this info. +* -- H * -- wszPath * -- uszPathStripped * -- pfMeta = path contains '\\$_INFO' @@ -1168,7 +1197,7 @@ fail: * -- pfMem = path ends with '\\mftdata.mem' * -- pfBin = path ends with '\\mftfile.bin' */ -VOID M_FcNtfs_PathStripMftInfo(_In_ LPSTR uszPath, _Out_writes_(MAX_PATH) LPSTR uszPathStripped, _Out_opt_ PBOOL pfMeta, _Out_opt_ PBOOL pfEnd, _Out_opt_ PBOOL pfTxt, _Out_opt_ PBOOL pfMem, _Out_opt_ PBOOL pfBin) +VOID M_FcNtfs_PathStripMftInfo(_In_ VMM_HANDLE H, _In_ LPSTR uszPath, _Out_writes_(MAX_PATH) LPSTR uszPathStripped, _Out_opt_ PBOOL pfMeta, _Out_opt_ PBOOL pfEnd, _Out_opt_ PBOOL pfTxt, _Out_opt_ PBOOL pfMem, _Out_opt_ PBOOL pfBin) { QWORD cch; LPSTR usz; @@ -1196,7 +1225,7 @@ VOID M_FcNtfs_PathStripMftInfo(_In_ LPSTR uszPath, _Out_writes_(MAX_PATH) LPSTR if(pfMeta) { *pfMeta = TRUE; } } -NTSTATUS M_FcNtfs_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS M_FcNtfs_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; PFCOB_MAP_NTFS pObNtfsMap = NULL; @@ -1207,16 +1236,16 @@ NTSTATUS M_FcNtfs_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcb CHAR uszPathStripped[MAX_PATH]; PBYTE pbInfoTxt; DWORD cbInfoTxt; - if(!strcmp(ctx->uszPath, "ntfs_files.txt")) { - return M_FcNtfs_ReadInfoAll(pb, cb, pcbRead, cbOffset); + if(!strcmp(ctxP->uszPath, "ntfs_files.txt")) { + return M_FcNtfs_ReadInfoAll(H, pb, cb, pcbRead, cbOffset); } - M_FcNtfs_PathStripMftInfo(ctx->uszPath, uszPathStripped, &fMeta, NULL, &fMetaTxt, &fMetaMem, &fMetaBin); + M_FcNtfs_PathStripMftInfo(H, ctxP->uszPath, uszPathStripped, &fMeta, NULL, &fMetaTxt, &fMetaMem, &fMetaBin); qwHashPath = CharUtil_HashPathFsU(uszPathStripped); - if(FcNtfsMap_GetFromHash(qwHashPath, &pObNtfsMap) && pObNtfsMap->cMap) { + if(FcNtfsMap_GetFromHash(H, qwHashPath, &pObNtfsMap) && pObNtfsMap->cMap) { peNtfs = pObNtfsMap->pMap + 0; if(!fMeta || fMetaBin) { if(peNtfs->qwFileSize && (peNtfs->dwFileSizeResident == peNtfs->qwFileSize) && (peNtfs->qwFileSize < 0x400)) { - if(FcNtfs_GetMftResidentData(peNtfs, pbNtfsRecordMax, peNtfs->dwFileSizeResident, NULL)) { + if(FcNtfs_GetMftResidentData(H, peNtfs, pbNtfsRecordMax, peNtfs->dwFileSizeResident, NULL)) { nt = Util_VfsReadFile_FromPBYTE(pbNtfsRecordMax, peNtfs->dwFileSizeResident, pb, cb, pcbRead, cbOffset); } } else { @@ -1224,10 +1253,10 @@ NTSTATUS M_FcNtfs_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcb } } if(fMetaMem) { - VmmRead2(NULL, peNtfs->pa, pbNtfsRecordMax, 0x400, VMM_FLAG_ZEROPAD_ON_FAIL); + VmmRead2(H, NULL, peNtfs->pa, pbNtfsRecordMax, 0x400, VMM_FLAG_ZEROPAD_ON_FAIL); nt = Util_VfsReadFile_FromPBYTE(pbNtfsRecordMax, 0x400, pb, cb, pcbRead, cbOffset); } - if(fMetaTxt && (pbInfoTxt = M_FcNtfs_ReadInfoSingle(peNtfs, &cbInfoTxt))) { + if(fMetaTxt && (pbInfoTxt = M_FcNtfs_ReadInfoSingle(H, peNtfs, &cbInfoTxt))) { nt = Util_VfsReadFile_FromPBYTE(pbInfoTxt, cbInfoTxt, pb, cb, pcbRead, cbOffset); LocalFree(pbInfoTxt); } @@ -1236,7 +1265,7 @@ NTSTATUS M_FcNtfs_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcb return nt; } -VOID M_FcNtfs_ListDirectory(_In_ LPSTR uszPath, _Inout_ PHANDLE pFileList) +VOID M_FcNtfs_ListDirectory(_In_ VMM_HANDLE H, _In_ LPSTR uszPath, _Inout_ PHANDLE pFileList) { BOOL fMeta, fEnd, fTxt, fMem, fBin; PBYTE pbInfoTxt; @@ -1248,18 +1277,18 @@ VOID M_FcNtfs_ListDirectory(_In_ LPSTR uszPath, _Inout_ PHANDLE pFileList) LPSTR uszTextName; QWORD qwHashPath; FileExInfo.dwVersion = VMMDLL_VFS_FILELIST_EXINFO_VERSION; - M_FcNtfs_PathStripMftInfo(uszPath, uszNameFix, &fMeta, &fEnd, &fTxt, &fMem, &fBin); + M_FcNtfs_PathStripMftInfo(H, uszPath, uszNameFix, &fMeta, &fEnd, &fTxt, &fMem, &fBin); if(fTxt || fMem || fBin) { return; } qwHashPath = CharUtil_HashPathFsU(uszNameFix); // single mft entry metadata files if(fMeta && !fEnd) { - if(FcNtfsMap_GetFromHash(qwHashPath, &pObNtfsMap) && pObNtfsMap->cMap) { + if(FcNtfsMap_GetFromHash(H, qwHashPath, &pObNtfsMap) && pObNtfsMap->cMap) { pe = pObNtfsMap->pMap; if(pe->pa) { FileExInfo.qwCreationTime = pe->ftCreate; FileExInfo.qwLastWriteTime = pe->ftModify; FileExInfo.qwLastAccessTime = pe->ftRead; - if((pbInfoTxt = M_FcNtfs_ReadInfoSingle(pe, &cbInfoTxt))) { + if((pbInfoTxt = M_FcNtfs_ReadInfoSingle(H, pe, &cbInfoTxt))) { VMMDLL_VfsList_AddFile(pFileList, "mftinfo.txt", cbInfoTxt, &FileExInfo); LocalFree(pbInfoTxt); } @@ -1273,7 +1302,7 @@ VOID M_FcNtfs_ListDirectory(_In_ LPSTR uszPath, _Inout_ PHANDLE pFileList) return; } // ordinary directory or metadata directory - if(!FcNtfsMap_GetFromHashParent(qwHashPath, &pObNtfsMap)) { return; } + if(!FcNtfsMap_GetFromHashParent(H, qwHashPath, &pObNtfsMap)) { return; } if(!fMeta && uszPath[0] && pObNtfsMap->cMap) { VMMDLL_VfsList_AddDirectory(pFileList, "$_INFO", NULL); } @@ -1297,24 +1326,24 @@ VOID M_FcNtfs_ListDirectory(_In_ LPSTR uszPath, _Inout_ PHANDLE pFileList) Ob_DECREF(pObNtfsMap); } -BOOL M_FcNtfs_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) +BOOL M_FcNtfs_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { QWORD cbFileSizeUTF8; - M_FcNtfs_ListDirectory(ctx->uszPath, pFileList); - if(!ctx->uszPath[0] && FcNtfs_GetFileSize(NULL, &cbFileSizeUTF8, NULL)) { + M_FcNtfs_ListDirectory(H, ctxP->uszPath, pFileList); + if(!ctxP->uszPath[0] && FcNtfs_GetFileSize(H, NULL, &cbFileSizeUTF8, NULL)) { VMMDLL_VfsList_AddFile(pFileList, "ntfs_files.txt", cbFileSizeUTF8, NULL); } return TRUE; } -VOID M_FcNtfs_Notify(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent) +VOID M_FcNtfs_Notify(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent) { if(fEvent == VMMDLL_PLUGIN_NOTIFY_FORENSIC_INIT_COMPLETE) { - PluginManager_SetVisibility(TRUE, "\\forensic\\ntfs", TRUE); + PluginManager_SetVisibility(H, TRUE, "\\forensic\\ntfs", TRUE); } } -VOID M_FcNtfs_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_FcNtfs_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if((pRI->tpSystem != VMM_SYSTEM_WINDOWS_X64) && (pRI->tpSystem != VMM_SYSTEM_WINDOWS_X86)) { return; } @@ -1325,10 +1354,11 @@ VOID M_FcNtfs_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) pRI->reg_fn.pfnRead = M_FcNtfs_Read; // Read function supported pRI->reg_fn.pfnNotify = M_FcNtfs_Notify; // Notify function supported pRI->reg_fnfc.pfnInitialize = FcNtfs_Initialize; // Forensic initialize function supported - pRI->reg_fnfc.pfnIngestPhysmem = FcNtfs_Ingest; // Forensic physmem ingest supported - pRI->reg_fnfc.pfnIngestFinalize = FcNtfs_Finalize; // Forensic ingest finalize function supported + pRI->reg_fnfc.pfnFinalize = FcNtfs_Finalize; // Forensic ingest finalize function supported + pRI->reg_fnfc.pfnIngestPhysmem = FcNtfs_IngestPhysmem; // Forensic physmem ingest supported + pRI->reg_fnfc.pfnIngestFinalize = FcNtfs_IngestFinalize; // Forensic ingest finalize function supported pRI->reg_fnfc.pfnTimeline = FcNtfs_SetupTimeline; // Forensic timelining supported memcpy(pRI->reg_info.sTimelineNameShort, "NTFS", 5); - strncpy_s(pRI->reg_info.uszTimelineFile, 32, "timeline_ntfs.txt", _TRUNCATE); - pRI->pfnPluginManager_Register(pRI); + strncpy_s(pRI->reg_info.uszTimelineFile, 32, "timeline_ntfs", _TRUNCATE); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_fc_proc.c b/vmm/m_fc_proc.c index bd5dad0..b62f0c8 100644 --- a/vmm/m_fc_proc.c +++ b/vmm/m_fc_proc.c @@ -14,6 +14,8 @@ #include "pluginmanager.h" #include "util.h" +static LPSTR MFCPROC_CSV_PROCESS = "PID,PPID,State,ShortName,Name,IntegrityLevel,User,CreateTime,ExitTime,Wow64,EPROCESS,PEB,PEB32,DTB,UserDTB,UserPath,KernelPath,CommandLine\n"; + static LPSTR FC_SQL_SCHEMA_PROCESS = "DROP TABLE IF EXISTS process; " \ "CREATE TABLE process(id INTEGER PRIMARY KEY AUTOINCREMENT, id_str_name INTEGER, id_str_path INTEGER, id_str_user INTEGER, id_str_all INTEGER, pid INT, ppid INT, eprocess INTEGER, dtb INTEGER, dtb_user INTEGER, state INTEGER, wow64 INT, peb INTEGER, peb32 INTEGER, time_create INTEGER, time_exit INTEGER); " \ @@ -23,7 +25,7 @@ static LPSTR FC_SQL_SCHEMA_PROCESS = /* * Forensic initialization function called when the forensic sub-system is initializing. */ -PVOID MFcProc_FcInitialize(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) +PVOID MFcProc_FcInitialize(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP) { int rc; BOOL fWellKnownAccount = FALSE; @@ -32,19 +34,22 @@ PVOID MFcProc_FcInitialize(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) sqlite3_stmt *hStmt = NULL, *hStmtStr = NULL; FCSQL_INSERTSTRTABLE SqlStrInsert[4]; CHAR uszUserName[MAX_PATH], uszFullInfo[2048]; - if(SQLITE_OK != Fc_SqlExec(FC_SQL_SCHEMA_PROCESS)) { goto fail; } - if(!(hSql = Fc_SqlReserve())) { goto fail; } + // 1: initialize csv + FcFileAppend(H, "process.csv", MFCPROC_CSV_PROCESS); + // 2: initialize timelining (sql) + if(SQLITE_OK != Fc_SqlExec(H, FC_SQL_SCHEMA_PROCESS)) { goto fail; } + if(!(hSql = Fc_SqlReserve(H))) { goto fail; } if(SQLITE_OK != sqlite3_prepare_v2(hSql, "INSERT INTO process (id_str_name, id_str_path, id_str_user, id_str_all, pid, ppid, eprocess, dtb, dtb_user, state, wow64, peb, peb32, time_create, time_exit) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", -1, &hStmt, NULL)) { goto fail; } - if(SQLITE_OK != sqlite3_prepare_v2(hSql, "INSERT INTO str (id, cbu, cbj, sz) VALUES (?, ?, ?, ?);", -1, &hStmtStr, NULL)) { goto fail; } + if(SQLITE_OK != sqlite3_prepare_v2(hSql, szFC_SQL_STR_INSERT, -1, &hStmtStr, NULL)) { goto fail; } sqlite3_exec(hSql, "BEGIN TRANSACTION", NULL, NULL, NULL); - while((pObProcess = VmmProcessGetNext(pObProcess, VMM_FLAG_PROCESS_TOKEN | VMM_FLAG_PROCESS_SHOW_TERMINATED))) { + while((pObProcess = VmmProcessGetNext(H, pObProcess, VMM_FLAG_PROCESS_TOKEN | VMM_FLAG_PROCESS_SHOW_TERMINATED))) { // build and insert string data into 'str' table. - if(!Fc_SqlInsertStr(hStmtStr, pObProcess->pObPersistent->uszNameLong, &SqlStrInsert[0])) { goto fail_transact; } - if(!Fc_SqlInsertStr(hStmtStr, pObProcess->pObPersistent->uszPathKernel, &SqlStrInsert[1])) { goto fail_transact; } - if(!pObProcess->win.TOKEN.fSidUserValid || !VmmWinUser_GetName(&pObProcess->win.TOKEN.SidUser.SID, uszUserName, MAX_PATH, &fWellKnownAccount)) { uszUserName[0] = 0; } - if(!Fc_SqlInsertStr(hStmtStr, uszUserName, &SqlStrInsert[2])) { goto fail_transact; } + if(!Fc_SqlInsertStr(H, hStmtStr, pObProcess->pObPersistent->uszNameLong, &SqlStrInsert[0])) { goto fail_transact; } + if(!Fc_SqlInsertStr(H, hStmtStr, pObProcess->pObPersistent->uszPathKernel, &SqlStrInsert[1])) { goto fail_transact; } + if(!pObProcess->win.TOKEN.fSidUserValid || !VmmWinUser_GetName(H, &pObProcess->win.TOKEN.SidUser.SID, uszUserName, MAX_PATH, &fWellKnownAccount)) { uszUserName[0] = 0; } + if(!Fc_SqlInsertStr(H, hStmtStr, uszUserName, &SqlStrInsert[2])) { goto fail_transact; } _snprintf_s(uszFullInfo, 2048 - 2, 2048 - 3, "%s [%s%s] %s", pObProcess->pObPersistent->uszNameLong, (fWellKnownAccount ? "*" : ""), uszUserName, pObProcess->pObPersistent->uszPathKernel); - if(!Fc_SqlInsertStr(hStmtStr, uszFullInfo, &SqlStrInsert[3])) { goto fail_transact; } + if(!Fc_SqlInsertStr(H, hStmtStr, uszFullInfo, &SqlStrInsert[3])) { goto fail_transact; } // insert into 'process' table. sqlite3_reset(hStmt); rc = Fc_SqlBindMultiInt64(hStmt, 1, 15, @@ -61,8 +66,8 @@ PVOID MFcProc_FcInitialize(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) (QWORD)(pObProcess->win.fWow64 ? 1 : 0), pObProcess->win.vaPEB, (QWORD)pObProcess->win.vaPEB32, - VmmProcess_GetCreateTimeOpt(pObProcess), - VmmProcess_GetExitTimeOpt(pObProcess) + VmmProcess_GetCreateTimeOpt(H, pObProcess), + VmmProcess_GetExitTimeOpt(H, pObProcess) ); if(SQLITE_OK != rc) { goto fail_transact; } sqlite3_step(hStmt); @@ -72,7 +77,7 @@ fail: Ob_DECREF(pObProcess); sqlite3_finalize(hStmt); sqlite3_finalize(hStmtStr); - Fc_SqlReserveReturn(hSql); + Fc_SqlReserveReturn(H, hSql); return NULL; fail_transact: sqlite3_exec(hSql, "COMMIT TRANSACTION", NULL, NULL, NULL); @@ -81,25 +86,27 @@ fail_transact: /* * Timeline data by executing a partial SQL query on pre-existing data. +* -- H * -- ctxfc * -- hTimeline * -- pfnAddEntry * -- pfnEntryAddBySql */ VOID MFcProc_FcTimeline( + _In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc, _In_ HANDLE hTimeline, - _In_ VOID(*pfnAddEntry)(_In_ HANDLE hTimeline, _In_ QWORD ft, _In_ DWORD dwAction, _In_ DWORD dwPID, _In_ DWORD dwData32, _In_ QWORD qwData64, _In_ LPSTR uszText), - _In_ VOID(*pfnEntryAddBySql)(_In_ HANDLE hTimeline, _In_ DWORD cEntrySql, _In_ LPSTR *pszEntrySql) + _In_ VOID(*pfnAddEntry)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ QWORD ft, _In_ DWORD dwAction, _In_ DWORD dwPID, _In_ DWORD dwData32, _In_ QWORD qwData64, _In_ LPSTR uszText), + _In_ VOID(*pfnEntryAddBySql)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ DWORD cEntrySql, _In_ LPSTR *pszEntrySql) ) { LPSTR pszSql[] = { "id_str_all, time_create, "STRINGIZE(FC_TIMELINE_ACTION_CREATE)", pid, ppid, eprocess FROM process WHERE time_create > 0;", "id_str_all, time_exit, "STRINGIZE(FC_TIMELINE_ACTION_DELETE)", pid, ppid, eprocess FROM process WHERE time_exit > 0;" }; - pfnEntryAddBySql(hTimeline, sizeof(pszSql) / sizeof(LPSTR), pszSql); + pfnEntryAddBySql(H, hTimeline, sizeof(pszSql) / sizeof(LPSTR), pszSql); } -VOID MFcProc_LogHeap(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd, _In_ VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData), _In_ PVMMOB_MAP_HEAP pMap) +VOID MFcProc_LogHeap(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd, _In_ VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData), _In_ PVMMOB_MAP_HEAP pMap) { DWORD i; PVMM_MAP_HEAP_SEGMENTENTRY peR; @@ -109,29 +116,29 @@ VOID MFcProc_LogHeap(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd, _In_ VOID(*pfnLog pd->va[0] = peR->va; pd->va[1] = pMap->pMap[peR->iHeap].va; pd->qwNum[0] = peR->cb; - pfnLogJSON(pd); + pfnLogJSON(H, pd); } } -VOID MFcProc_LogProcess_GetUserName(_In_ PVMM_PROCESS pProcess, _Out_writes_(17) LPSTR uszUserName, _Out_ PBOOL fAccountUser) +VOID MFcProc_LogProcess_GetUserName(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Out_writes_(17) LPSTR uszUserName, _Out_ PBOOL fAccountUser) { BOOL f, fWellKnownAccount = FALSE; uszUserName[0] = 0; f = pProcess->win.TOKEN.fSidUserValid && - VmmWinUser_GetName(&pProcess->win.TOKEN.SidUser.SID, uszUserName, 17, &fWellKnownAccount); + VmmWinUser_GetName(H, &pProcess->win.TOKEN.SidUser.SID, uszUserName, 17, &fWellKnownAccount); *fAccountUser = f && !fWellKnownAccount; } -VOID MFcProc_LogProcess(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd, _In_ VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData), PVMM_PROCESS pProcess) +VOID MFcProc_LogProcess(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd, _In_ VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData), PVMM_PROCESS pProcess) { SIZE_T o; BOOL fStateTerminated, fAccountUser = FALSE; CHAR uszBuffer[1024], szUserName[17], szTimeCRE[24], szTimeEXIT[24]; - PVMMWIN_USER_PROCESS_PARAMETERS pu = VmmWin_UserProcessParameters_Get(pProcess); + PVMMWIN_USER_PROCESS_PARAMETERS pu = VmmWin_UserProcessParameters_Get(H, pProcess); SIZE_T cbu = sizeof(uszBuffer); LPSTR usz = uszBuffer; - if(pu->cbuImagePathName + pu->cbuCommandLine > sizeof(uszBuffer) - 512) { - cbu = pu->cbuImagePathName + pu->cbuCommandLine + 512; + if((SIZE_T)pu->cbuImagePathName + pu->cbuCommandLine > sizeof(uszBuffer) - 512) { + cbu = (SIZE_T)pu->cbuImagePathName + pu->cbuCommandLine + 512; usz = LocalAlloc(0, cbu); if(!usz) { return; } } @@ -142,31 +149,31 @@ VOID MFcProc_LogProcess(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd, _In_ VOID(*pfn pd->qwHex[1] = pProcess->paDTB_UserOpt; pd->usz[0] = pProcess->pObPersistent->uszPathKernel; fStateTerminated = (pProcess->dwState != 0); - MFcProc_LogProcess_GetUserName(pProcess, szUserName, &fAccountUser); - Util_FileTime2String(VmmProcess_GetCreateTimeOpt(pProcess), szTimeCRE); + MFcProc_LogProcess_GetUserName(H, pProcess, szUserName, &fAccountUser); + Util_FileTime2String(VmmProcess_GetCreateTimeOpt(H, pProcess), szTimeCRE); o = _snprintf_s(usz, cbu, _TRUNCATE, "flags:[%s%c%c%c] user:[%s] upath:[%s] cmd:[%s] createtime:[%s]", pProcess->win.fWow64 ? "32" : " ", pProcess->win.EPROCESS.fNoLink ? 'E' : ' ', fStateTerminated ? 'T' : ' ', fAccountUser ? 'U' : ' ', szUserName, - pu->uszImagePathName, - pu->uszCommandLine, + pu->uszImagePathName ? pu->uszImagePathName : "", + pu->uszCommandLine ? pu->uszCommandLine : "", szTimeCRE ); - if(VmmProcess_GetExitTimeOpt(pProcess)) { - Util_FileTime2String(VmmProcess_GetExitTimeOpt(pProcess), szTimeEXIT); + if(VmmProcess_GetExitTimeOpt(H, pProcess)) { + Util_FileTime2String(VmmProcess_GetExitTimeOpt(H, pProcess), szTimeEXIT); o += _snprintf_s(usz + o, cbu - o, _TRUNCATE, " exittime:[%s]", szTimeEXIT); } if(pProcess->win.TOKEN.IntegrityLevel) { o += _snprintf_s(usz + o, cbu - o, _TRUNCATE, " integrity:[%s]", VMM_PROCESS_INTEGRITY_LEVEL_STR[pProcess->win.TOKEN.IntegrityLevel]); } pd->usz[1] = usz; - pfnLogJSON(pd); + pfnLogJSON(H, pd); if(usz != uszBuffer) { LocalFree(usz); } } -VOID MFcProc_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) +VOID MFcProc_FcLogJSON(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) { PVMM_PROCESS pProcess = ctxP->pProcess; PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd; @@ -174,21 +181,54 @@ VOID MFcProc_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)( if(!pProcess || !(pd = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMDLL_PLUGIN_FORENSIC_JSONDATA)))) { return; } // process: FC_JSONDATA_INIT_PIDTYPE(pd, pProcess->dwPID, "process"); - MFcProc_LogProcess(pd, pfnLogJSON, pProcess); + MFcProc_LogProcess(H, pd, pfnLogJSON, pProcess); // heap: FC_JSONDATA_INIT_PIDTYPE(pd, pProcess->dwPID, "heap"); - if(VmmMap_GetHeap(pProcess, &pObHeapMap)) { - MFcProc_LogHeap(pd, pfnLogJSON, pObHeapMap); + if(VmmMap_GetHeap(H, pProcess, &pObHeapMap)) { + MFcProc_LogHeap(H, pd, pfnLogJSON, pObHeapMap); } Ob_DECREF(pObHeapMap); LocalFree(pd); } +VOID MFcProc_FcLogCSV(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VMMDLL_CSV_HANDLE hCSV) +{ + PVMM_PROCESS pProcess = ctxP->pProcess; + PVMMWIN_USER_PROCESS_PARAMETERS pu; + BOOL fAccountUser = FALSE; + CHAR szUserName[17]; + if(!pProcess) { return; } + pu = VmmWin_UserProcessParameters_Get(H, pProcess); + MFcProc_LogProcess_GetUserName(H, pProcess, szUserName, &fAccountUser); + FcCsv_Reset(hCSV); + FcFileAppend(H, "process.csv", "%i,%i,%i,%s,%s,%s,%s,%s,%s,%i,0x%llx,0x%llx,0x%x,0x%llx,0x%llx,%s,%s,%s\n", + pProcess->dwPID, + pProcess->dwPPID, + pProcess->dwState, + FcCsv_String(hCSV, pProcess->szName), + FcCsv_String(hCSV, pProcess->pObPersistent->uszNameLong), + FcCsv_String(hCSV, (LPSTR)VMM_PROCESS_INTEGRITY_LEVEL_STR[pProcess->win.TOKEN.IntegrityLevel]), + FcCsv_String(hCSV, szUserName), + FcCsv_FileTime(hCSV, VmmProcess_GetCreateTimeOpt(H, pProcess)), + FcCsv_FileTime(hCSV, VmmProcess_GetExitTimeOpt(H, pProcess)), + pProcess->win.fWow64 ? 1 : 0, + pProcess->win.EPROCESS.va, + pProcess->win.vaPEB, + pProcess->win.vaPEB32, + pProcess->paDTB, + pProcess->paDTB_UserOpt, + FcCsv_String(hCSV, pu->uszImagePathName), + FcCsv_String(hCSV, pProcess->pObPersistent->uszPathKernel), + FcCsv_String(hCSV, pu->uszCommandLine) + ); +} + /* * Plugin initialization / registration function called by the plugin manager. +* -- H * -- pRI */ -VOID M_FcProc_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_FcProc_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if((pRI->tpSystem != VMM_SYSTEM_WINDOWS_X64) && (pRI->tpSystem != VMM_SYSTEM_WINDOWS_X86)) { return; } @@ -197,8 +237,9 @@ VOID M_FcProc_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) pRI->reg_info.fRootModuleHidden = TRUE; // module hidden by default pRI->reg_fnfc.pfnInitialize = MFcProc_FcInitialize; // Forensic initialize function supported pRI->reg_fnfc.pfnTimeline = MFcProc_FcTimeline; // Forensic timelining supported + pRI->reg_fnfc.pfnLogCSV = MFcProc_FcLogCSV; // CSV log function supported pRI->reg_fnfc.pfnLogJSON = MFcProc_FcLogJSON; // JSON log function supported memcpy(pRI->reg_info.sTimelineNameShort, "PROC", 5); - strncpy_s(pRI->reg_info.uszTimelineFile, 32, "timeline_process.txt", _TRUNCATE); - pRI->pfnPluginManager_Register(pRI); + strncpy_s(pRI->reg_info.uszTimelineFile, 32, "timeline_process", _TRUNCATE); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_fc_registry.c b/vmm/m_fc_registry.c index d796535..ca9133b 100644 --- a/vmm/m_fc_registry.c +++ b/vmm/m_fc_registry.c @@ -37,15 +37,16 @@ static LPCSTR MFCREGISTRY_TYPE_NAMES[] = { "REG_QWORD" }; -VOID MFcRegistry_JsonKeyCB(_Inout_ PVMMWINREG_FORENSIC_CONTEXT ctx, _In_z_ LPSTR uszPathName, _In_ QWORD ftLastWrite) +VOID MFcRegistry_JsonKeyCB(_In_ VMM_HANDLE H, _Inout_ PVMMWINREG_FORENSIC_CONTEXT ctx, _In_z_ LPSTR uszPathName, _In_ QWORD ftLastWrite) { + PFC_CONTEXT ctxFc = H->fc; SIZE_T o = 0; CHAR szKeyLastWrite[21]; // 1: create json 'base/prefix' to re-use with values: o += snprintf(ctx->szjBase, sizeof(ctx->szjBase) - o, "{\"class\":\"REG\",\"ver\":\"%i.%i\",\"sys\":\"%s\",\"key\":\"", VERSION_MAJOR, VERSION_MINOR, - ctxVmm->szSystemUniqueTag + H->vmm.szSystemUniqueTag ); CharUtil_UtoJ(uszPathName, -1, ctx->szjBase + o, (DWORD)(sizeof(ctx->szjBase) - o), NULL, NULL, CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR | CHARUTIL_FLAG_STR_BUFONLY); // 2: write key json line @@ -58,7 +59,7 @@ VOID MFcRegistry_JsonKeyCB(_Inout_ PVMMWINREG_FORENSIC_CONTEXT ctx, _In_z_ LPSTR ObMemFile_AppendString(ctxFc->FileJSON.pReg, ctx->sz); } -VOID MFcRegistry_JsonValueCB(_Inout_ PVMMWINREG_FORENSIC_CONTEXT ctx) +VOID MFcRegistry_JsonValueCB(_In_ VMM_HANDLE H, _Inout_ PVMMWINREG_FORENSIC_CONTEXT ctx) { QWORD i; DWORD cch; @@ -74,7 +75,14 @@ VOID MFcRegistry_JsonValueCB(_Inout_ PVMMWINREG_FORENSIC_CONTEXT ctx) case REG_RESOURCE_REQUIREMENTS_LIST: cch = _countof(ctx->value.sz); Util_FillHexAscii(ctx->value.pb, min(0x100, ctx->value.cb), 0, ctx->value.sz, &cch); - CharUtil_AtoJ(ctx->value.sz, -1, ctx->value.szjValue, sizeof(ctx->value.szjValue), &szj, NULL, CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR); + CharUtil_AtoJ( + ctx->value.sz, + ctx->value.cb, + ctx->value.szjValue, + sizeof(ctx->value.szjValue), + &szj, + NULL, + CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR); break; case REG_DWORD: case REG_DWORD_BIG_ENDIAN: @@ -92,7 +100,14 @@ VOID MFcRegistry_JsonValueCB(_Inout_ PVMMWINREG_FORENSIC_CONTEXT ctx) // fall-through case REG_SZ: case REG_EXPAND_SZ: - CharUtil_WtoJ((LPWSTR)ctx->value.pb, -1, (PBYTE)ctx->value.szjValue, sizeof(ctx->value.szjValue), NULL, NULL, CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR); + CharUtil_WtoJ( + (LPWSTR)ctx->value.pb, + (ctx->value.cb / 2), + (PBYTE)ctx->value.szjValue, + sizeof(ctx->value.szjValue), + &szj, + NULL, + CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR); break; } snprintf(ctx->sz, sizeof(ctx->sz), @@ -103,19 +118,19 @@ VOID MFcRegistry_JsonValueCB(_Inout_ PVMMWINREG_FORENSIC_CONTEXT ctx) ctx->value.info.cbData, ctx->value.szjValue ); - ObMemFile_AppendString(ctxFc->FileJSON.pReg, ctx->sz); + ObMemFile_AppendString(H->fc->FileJSON.pReg, ctx->sz); } /* * Callback for registry key information destined for forensic database. */ -VOID MFcRegistry_KeyCB(_In_ HANDLE hCallback1, _In_ HANDLE hCallback2, _In_ LPSTR uszPathName, _In_ QWORD vaHive, _In_ DWORD dwCell, _In_ DWORD dwCellParent, _In_ QWORD ftLastWrite) +VOID MFcRegistry_KeyCB(_In_ VMM_HANDLE H, _In_ HANDLE hCallback1, _In_ HANDLE hCallback2, _In_ LPSTR uszPathName, _In_ QWORD vaHive, _In_ DWORD dwCell, _In_ DWORD dwCellParent, _In_ QWORD ftLastWrite) { FCSQL_INSERTSTRTABLE SqlStrInsert; sqlite3_stmt *hStmt = (sqlite3_stmt *)hCallback1; sqlite3_stmt *hStmtStr = (sqlite3_stmt *)hCallback2; // build and insert string data into 'str' table. - if(!Fc_SqlInsertStr(hStmtStr, uszPathName, &SqlStrInsert)) { return; } + if(!Fc_SqlInsertStr(H, hStmtStr, uszPathName, &SqlStrInsert)) { return; } // insert into 'process' table. sqlite3_reset(hStmt); Fc_SqlBindMultiInt64(hStmt, 1, 5, @@ -131,52 +146,54 @@ VOID MFcRegistry_KeyCB(_In_ HANDLE hCallback1, _In_ HANDLE hCallback2, _In_ LPST /* * Forensic initialization function called when the forensic sub-system is initializing. */ -PVOID M_FcRegistry_FcInitialize(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) +PVOID M_FcRegistry_FcInitialize(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP) { POB_REGISTRY_HIVE pObHive = NULL; sqlite3 *hSql = NULL; sqlite3_stmt *hStmt = NULL, *hStmtStr = NULL; - if(SQLITE_OK != Fc_SqlExec(FC_SQL_SCHEMA_REGISTRY)) { goto fail; } - if(!(hSql = Fc_SqlReserve())) { goto fail; } + if(SQLITE_OK != Fc_SqlExec(H, FC_SQL_SCHEMA_REGISTRY)) { goto fail; } + if(!(hSql = Fc_SqlReserve(H))) { goto fail; } if(SQLITE_OK != sqlite3_prepare_v2(hSql, "INSERT INTO registry (id_str, hive, cell, cell_parent, time) VALUES (?, ?, ?, ?, ?);", -1, &hStmt, NULL)) { goto fail; } - if(SQLITE_OK != sqlite3_prepare_v2(hSql, "INSERT INTO str (id, cbu, cbj, sz) VALUES (?, ?, ?, ?);", -1, &hStmtStr, NULL)) { goto fail; } + if(SQLITE_OK != sqlite3_prepare_v2(hSql, szFC_SQL_STR_INSERT, -1, &hStmtStr, NULL)) { goto fail; } sqlite3_exec(hSql, "BEGIN TRANSACTION", NULL, NULL, NULL); - while((pObHive = VmmWinReg_HiveGetNext(pObHive))) { - VmmWinReg_ForensicGetAllKeysAndValues(pObHive, hStmt, hStmtStr, MFcRegistry_KeyCB, MFcRegistry_JsonKeyCB, MFcRegistry_JsonValueCB); + while((pObHive = VmmWinReg_HiveGetNext(H, pObHive))) { + VmmWinReg_ForensicGetAllKeysAndValues(H, pObHive, hStmt, hStmtStr, MFcRegistry_KeyCB, MFcRegistry_JsonKeyCB, MFcRegistry_JsonValueCB); } sqlite3_exec(hSql, "COMMIT TRANSACTION", NULL, NULL, NULL); fail: - Ob_DECREF(pObHive); sqlite3_finalize(hStmt); sqlite3_finalize(hStmtStr); - Fc_SqlReserveReturn(hSql); + Fc_SqlReserveReturn(H, hSql); return NULL; } /* * Timeline data by executing a partial SQL query on pre-existing data. +* -- H * -- ctxfc * -- hTimeline * -- pfnAddEntry * -- pfnEntryAddBySql */ VOID M_FcRegistry_FcTimeline( + _In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc, _In_ HANDLE hTimeline, - _In_ VOID(*pfnAddEntry)(_In_ HANDLE hTimeline, _In_ QWORD ft, _In_ DWORD dwAction, _In_ DWORD dwPID, _In_ DWORD dwData32, _In_ QWORD qwData64, _In_ LPSTR uszText), - _In_ VOID(*pfnEntryAddBySql)(_In_ HANDLE hTimeline, _In_ DWORD cEntrySql, _In_ LPSTR *pszEntrySql) + _In_ VOID(*pfnAddEntry)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ QWORD ft, _In_ DWORD dwAction, _In_ DWORD dwPID, _In_ DWORD dwData32, _In_ QWORD qwData64, _In_ LPSTR uszText), + _In_ VOID(*pfnEntryAddBySql)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ DWORD cEntrySql, _In_ LPSTR *pszEntrySql) ) { LPSTR pszSql[] = { "id_str, time, "STRINGIZE(FC_TIMELINE_ACTION_MODIFY)", 0, 0, 0 FROM registry WHERE time > 0;" }; - pfnEntryAddBySql(hTimeline, sizeof(pszSql) / sizeof(LPSTR), pszSql); + pfnEntryAddBySql(H, hTimeline, sizeof(pszSql) / sizeof(LPSTR), pszSql); } /* * Plugin initialization / registration function called by the plugin manager. +* -- H * -- pRI */ -VOID M_FcRegistry_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_FcRegistry_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if((pRI->tpSystem != VMM_SYSTEM_WINDOWS_X64) && (pRI->tpSystem != VMM_SYSTEM_WINDOWS_X86)) { return; } @@ -186,6 +203,6 @@ VOID M_FcRegistry_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) pRI->reg_fnfc.pfnInitialize = M_FcRegistry_FcInitialize; // Forensic initialize function supported pRI->reg_fnfc.pfnTimeline = M_FcRegistry_FcTimeline; // Forensic timelining supported memcpy(pRI->reg_info.sTimelineNameShort, "REG", 4); - strncpy_s(pRI->reg_info.uszTimelineFile, 32, "timeline_registry.txt", _TRUNCATE); - pRI->pfnPluginManager_Register(pRI); + strncpy_s(pRI->reg_info.uszTimelineFile, 32, "timeline_registry", _TRUNCATE); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_fc_sys.c b/vmm/m_fc_sys.c new file mode 100644 index 0000000..7eae0a4 --- /dev/null +++ b/vmm/m_fc_sys.c @@ -0,0 +1,37 @@ +// m_fc_sys.c : general system forensic module. +// +// REQUIRE: FORENSIC SUB-SYSTEM INIT. +// +// NB! module generate forensic data only - no file system presence! +// +// (c) Ulf Frisk,2022 +// Author: Ulf Frisk, pcileech@frizk.net +// + +#include "fc.h" +#include "vmm.h" +#include "vmmwin.h" +#include "pluginmanager.h" +#include "util.h" + +PVOID MFcSys_FcInitialize(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP) +{ + return NULL; +} + +VOID MFcSys_FcLogCSV(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VMMDLL_CSV_HANDLE hCSV) +{ + ; +} + +VOID M_FcSys_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +{ + if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } + if((pRI->tpSystem != VMM_SYSTEM_WINDOWS_X64) && (pRI->tpSystem != VMM_SYSTEM_WINDOWS_X86)) { return; } + strcpy_s(pRI->reg_info.uszPathName, 128, "\\forensic\\hidden\\sys"); // module name + pRI->reg_info.fRootModule = TRUE; // module shows in root directory + pRI->reg_info.fRootModuleHidden = TRUE; // module hidden by default + pRI->reg_fnfc.pfnInitialize = MFcSys_FcInitialize; // Forensic initialize function supported + pRI->reg_fnfc.pfnLogCSV = MFcSys_FcLogCSV; // CSV log function supported + pRI->pfnPluginManager_Register(H, pRI); +} diff --git a/vmm/m_fc_thread.c b/vmm/m_fc_thread.c index a693764..7fc5ff8 100644 --- a/vmm/m_fc_thread.c +++ b/vmm/m_fc_thread.c @@ -14,6 +14,8 @@ #include "util.h" #include "vmmwindef.h" +static LPSTR MFCPROC_CSV_THREAD = "PID,TID,ETHREAD,State,WaitReason,CreateTime,ExitTime,Running,BasePriority,Priority,ExitStatus,StartAddress,IP,SP,TEB,StackBaseUser,StackLimitUser,StackBaseKernel,StackLimitKernel,TrapFrame\n"; + static LPSTR FC_SQL_SCHEMA_THREAD = "DROP TABLE IF EXISTS thread; " \ "CREATE TABLE thread(id INTEGER PRIMARY KEY AUTOINCREMENT, id_str INTEGER, pid INT, tid INT, ethread INTEGER, teb INTEGER, state INT, exitstatus INT, running INT, prio INT, priobase INT, waitreason INT, startaddr INTEGER, stackbase_u INTEGER, stacklimit_u INTEGER, stackbase_k INTEGER, stacklimit_k INTEGER, trapframe INTEGER, sp INTEGER, ip INTEGER, time_create INTEGER, time_exit INTEGER); " \ @@ -23,7 +25,7 @@ static LPSTR FC_SQL_SCHEMA_THREAD = #define MFCTHREAD_GET_STR_STATE(pe) ((pe->bState < (sizeof(_KTHREAD_STATE_STR) / sizeof(LPCSTR))) ? _KTHREAD_STATE_STR[pe->bState] : "Unknown") #define MFCTHREAD_GET_STR_WAIT_REASON(pe) ((pe->bWaitReason < (sizeof(_KWAIT_REASON_STR) / sizeof(LPCSTR))) ? _KWAIT_REASON_STR[pe->bWaitReason] : "Unknown") -VOID M_FcThread_FcInitialize_ThreadProc(_In_ PVMM_PROCESS pProcess, _In_ PVOID pv) +VOID M_FcThread_FcInitialize_ThreadProc(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVOID pv) { int rc; sqlite3 *hSql = NULL; @@ -33,15 +35,15 @@ VOID M_FcThread_FcInitialize_ThreadProc(_In_ PVMM_PROCESS pProcess, _In_ PVOID p PVMM_MAP_THREADENTRY pe; CHAR szStr[MAX_PATH]; FCSQL_INSERTSTRTABLE SqlStrInsert; - if(!VmmMap_GetThread(pProcess, &pObThreadMap)) { goto fail; } - if(!(hSql = Fc_SqlReserve())) { goto fail; } + if(!VmmMap_GetThread(H, pProcess, &pObThreadMap)) { goto fail; } + if(!(hSql = Fc_SqlReserve(H))) { goto fail; } if(SQLITE_OK != sqlite3_prepare_v2(hSql, "INSERT INTO thread (id_str, pid, tid, ethread, teb, state, exitstatus, running, prio, priobase, waitreason, startaddr, stackbase_u, stacklimit_u, stackbase_k, stacklimit_k, trapframe, sp, ip, time_create, time_exit) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", -1, &hStmt, NULL)) { goto fail; } - if(SQLITE_OK != sqlite3_prepare_v2(hSql, "INSERT INTO str (id, cbu, cbj, sz) VALUES (?, ?, ?, ?);", -1, &hStmtStr, NULL)) { goto fail; } + if(SQLITE_OK != sqlite3_prepare_v2(hSql, szFC_SQL_STR_INSERT, -1, &hStmtStr, NULL)) { goto fail; } sqlite3_exec(hSql, "BEGIN TRANSACTION", NULL, NULL, NULL); for(i = 0; i < pObThreadMap->cMap; i++) { pe = pObThreadMap->pMap + i; snprintf(szStr, _countof(szStr), "TID: %i", pe->dwTID); - if(!Fc_SqlInsertStr(hStmtStr, szStr, &SqlStrInsert)) { goto fail_transact; } + if(!Fc_SqlInsertStr(H, hStmtStr, szStr, &SqlStrInsert)) { goto fail_transact; } sqlite3_reset(hStmt); rc = Fc_SqlBindMultiInt64(hStmt, 1, 20, SqlStrInsert.id, @@ -74,7 +76,7 @@ fail_transact: fail: sqlite3_finalize(hStmt); sqlite3_finalize(hStmtStr); - Fc_SqlReserveReturn(hSql); + Fc_SqlReserveReturn(H, hSql); Ob_DECREF(pObThreadMap); return; } @@ -82,34 +84,39 @@ fail: /* * Forensic initialization function called when the forensic sub-system is initializing. */ -PVOID M_FcThread_FcInitialize(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) +PVOID M_FcThread_FcInitialize(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP) { - if(SQLITE_OK != Fc_SqlExec(FC_SQL_SCHEMA_THREAD)) { return NULL; } - VmmProcessActionForeachParallel(NULL, VmmProcessActionForeachParallel_CriteriaActiveOnly, M_FcThread_FcInitialize_ThreadProc); + // 1: initialize csv + FcFileAppend(H, "threads.csv", MFCPROC_CSV_THREAD); + // 2: initialize timelining (sql) + if(SQLITE_OK != Fc_SqlExec(H, FC_SQL_SCHEMA_THREAD)) { return NULL; } + VmmWork_ProcessActionForeachParallel_Void(H, 0, NULL, VmmWork_ProcessActionForeachParallel_CriteriaActiveOnly, M_FcThread_FcInitialize_ThreadProc); return NULL; } /* * Timeline data by executing a partial SQL query on pre-existing data. +* -- H * -- ctxfc * -- hTimeline * -- pfnAddEntry * -- pfnEntryAddBySql */ VOID M_FcThread_FcTimeline( + _In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc, _In_ HANDLE hTimeline, - _In_ VOID(*pfnAddEntry)(_In_ HANDLE hTimeline, _In_ QWORD ft, _In_ DWORD dwAction, _In_ DWORD dwPID, _In_ DWORD dwData32, _In_ QWORD qwData64, _In_ LPSTR uszText), - _In_ VOID(*pfnEntryAddBySql)(_In_ HANDLE hTimeline, _In_ DWORD cEntrySql, _In_ LPSTR *pszEntrySql) + _In_ VOID(*pfnAddEntry)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ QWORD ft, _In_ DWORD dwAction, _In_ DWORD dwPID, _In_ DWORD dwData32, _In_ QWORD qwData64, _In_ LPSTR uszText), + _In_ VOID(*pfnEntryAddBySql)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ DWORD cEntrySql, _In_ LPSTR *pszEntrySql) ) { LPSTR pszSql[] = { "id_str, time_create, "STRINGIZE(FC_TIMELINE_ACTION_CREATE)", pid, tid, ethread FROM thread WHERE time_create > 0;", "id_str, time_exit, "STRINGIZE(FC_TIMELINE_ACTION_DELETE)", pid, tid, ethread FROM thread WHERE time_exit > 0;", }; - pfnEntryAddBySql(hTimeline, sizeof(pszSql) / sizeof(LPSTR), pszSql); + pfnEntryAddBySql(H, hTimeline, sizeof(pszSql) / sizeof(LPSTR), pszSql); } -VOID M_FcThread_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) +VOID M_FcThread_FcLogJSON(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) { PVMM_PROCESS pProcess = ctxP->pProcess; PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd; @@ -122,7 +129,7 @@ VOID M_FcThread_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSO pd->dwVersion = VMMDLL_PLUGIN_FORENSIC_JSONDATA_VERSION; pd->dwPID = pProcess->dwPID; pd->szjType = "thread"; - if(VmmMap_GetThread(pProcess, &pObThreadMap)) { + if(VmmMap_GetThread(H, pProcess, &pObThreadMap)) { for(i = 0; i < pObThreadMap->cMap; i++) { pe = pObThreadMap->pMap + i; Util_FileTime2String(pe->ftCreateTime, szTime); @@ -139,18 +146,56 @@ VOID M_FcThread_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSO pd->va[0] = pe->vaStackBaseUser ? pe->vaStackBaseUser : pe->vaStackBaseKernel; pd->va[1] = pe->vaStackBaseUser ? pe->vaStackLimitUser : pe->vaStackLimitKernel; pd->usz[0] = usz; - pfnLogJSON(pd); + pfnLogJSON(H, pd); } } Ob_DECREF(pObThreadMap); LocalFree(pd); } +VOID M_FcThread_FcLogCSV(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VMMDLL_CSV_HANDLE hCSV) +{ + PVMM_PROCESS pProcess = ctxP->pProcess; + PVMMOB_MAP_THREAD pObThreadMap = NULL; + PVMM_MAP_THREADENTRY pe; + DWORD i; + if(pProcess && VmmMap_GetThread(H, pProcess, &pObThreadMap)) { + for(i = 0; i < pObThreadMap->cMap; i++) { + pe = pObThreadMap->pMap + i; + FcCsv_Reset(hCSV); + FcFileAppend(H, "threads.csv", "%i,%i,%llx,%s,%s,%s,%s,%x,%x,%x,%x,%llx,%llx,%llx,%llx,%llx,%llx,%llx,%llx,%llx\n", + pe->dwPID, + pe->dwTID, + pe->vaETHREAD, + MFCTHREAD_GET_STR_STATE(pe), + MFCTHREAD_GET_STR_WAIT_REASON(pe), + FcCsv_FileTime(hCSV, pe->ftCreateTime), + FcCsv_FileTime(hCSV, pe->ftExitTime), + pe->bRunning, + pe->bBasePriority, + pe->bPriority, + pe->dwExitStatus, + pe->vaStartAddress, + pe->vaRIP, + pe->vaRSP, + pe->vaTeb, + pe->vaStackBaseUser, + pe->vaStackLimitUser, + pe->vaStackBaseKernel, + pe->vaStackLimitKernel, + pe->vaTrapFrame + ); + } + } + Ob_DECREF(pObThreadMap); +} + /* * Plugin initialization / registration function called by the plugin manager. +* -- H * -- pRI */ -VOID M_FcThread_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_FcThread_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if((pRI->tpSystem != VMM_SYSTEM_WINDOWS_X64) && (pRI->tpSystem != VMM_SYSTEM_WINDOWS_X86)) { return; } @@ -159,8 +204,9 @@ VOID M_FcThread_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) pRI->reg_info.fRootModuleHidden = TRUE; // module hidden by default pRI->reg_fnfc.pfnInitialize = M_FcThread_FcInitialize; // Forensic initialize function supported pRI->reg_fnfc.pfnTimeline = M_FcThread_FcTimeline; // Forensic timelining supported + pRI->reg_fnfc.pfnLogCSV = M_FcThread_FcLogCSV; // CSV log function supported pRI->reg_fnfc.pfnLogJSON = M_FcThread_FcLogJSON; // JSON log function supported memcpy(pRI->reg_info.sTimelineNameShort, "THREAD", 6); - strncpy_s(pRI->reg_info.uszTimelineFile, 32, "timeline_thread.txt", _TRUNCATE); - pRI->pfnPluginManager_Register(pRI); + strncpy_s(pRI->reg_info.uszTimelineFile, 32, "timeline_thread", _TRUNCATE); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_fc_timeline.c b/vmm/m_fc_timeline.c index 495cf80..117bac1 100644 --- a/vmm/m_fc_timeline.c +++ b/vmm/m_fc_timeline.c @@ -15,7 +15,7 @@ /* * Read the text version of the timeline info files. */ -NTSTATUS M_FcTimeline_ReadInfo(_In_ DWORD dwTimelineType, _Out_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS M_FcTimeline_ReadInfo(_In_ VMM_HANDLE H, _In_ DWORD dwTimelineType, _Out_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; PFC_MAP_TIMELINEENTRY pe; @@ -24,10 +24,10 @@ NTSTATUS M_FcTimeline_ReadInfo(_In_ DWORD dwTimelineType, _Out_ PBYTE pb, _In_ D LPSTR szuBuffer = NULL; DWORD dwEntryType, dwEntryAction; CHAR szTime[24]; - if(!FcTimeline_GetIdFromPosition(dwTimelineType, FALSE, cbOffset, &qwIdBase)) { goto fail; } - if(!FcTimeline_GetIdFromPosition(dwTimelineType, FALSE, cbOffset + cb, &qwIdTop)) { goto fail; } + if(!FcTimeline_GetIdFromPosition(H, dwTimelineType, FC_FORMAT_TYPE_UTF8, cbOffset, &qwIdBase)) { goto fail; } + if(!FcTimeline_GetIdFromPosition(H, dwTimelineType, FC_FORMAT_TYPE_UTF8, cbOffset + cb, &qwIdTop)) { goto fail; } cId = min(cb / FC_LINELENGTH_TIMELINE_UTF8, qwIdTop - qwIdBase) + 1; - if(!FcTimelineMap_GetFromIdRange(dwTimelineType, qwIdBase, cId, &pObMap) || !pObMap->cMap) { goto fail; } + if(!FcTimelineMap_GetFromIdRange(H, dwTimelineType, qwIdBase, cId, &pObMap) || !pObMap->cMap) { goto fail; } cbOffsetBuffer = pObMap->pMap[0].cuszOffset; if((cbOffsetBuffer > cbOffset) || (cbOffset - cbOffsetBuffer > 0x10000)) { goto fail; } cszuBuffer = 0x01000000; @@ -35,15 +35,15 @@ NTSTATUS M_FcTimeline_ReadInfo(_In_ DWORD dwTimelineType, _Out_ PBYTE pb, _In_ D for(i = 0, o = 0; (i < pObMap->cMap) && (o < cszuBuffer - 0x1000); i++) { pe = pObMap->pMap + i; Util_FileTime2String(pe->ft, szTime); - dwEntryType = (pe->tp < ctxFc->Timeline.cTp) ? pe->tp : 0; + dwEntryType = (pe->tp < H->fc->Timeline.cTp) ? pe->tp : 0; dwEntryAction = (pe->ac <= FC_TIMELINE_ACTION_MAX) ? pe->ac : FC_TIMELINE_ACTION_NONE; o += snprintf( szuBuffer + o, (SIZE_T)(cszuBuffer - o), - "%s %-*s %s%10u%10u %16llx %s\n", + "%s %-*s %-3s%10u%10u %16llx %s\n", szTime, 6, - ctxFc->Timeline.pInfo[dwEntryType].szNameShort, + H->fc->Timeline.pInfo[dwEntryType].szNameShort, FC_TIMELINE_ACTION_STR[dwEntryAction], pe->pid, pe->data32, @@ -58,41 +58,41 @@ fail: return nt; } -NTSTATUS M_FcTimeline_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS M_FcTimeline_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { DWORD i; PFC_TIMELINE_INFO pi; - for(i = 0; i < ctxFc->Timeline.cTp; i++) { - pi = ctxFc->Timeline.pInfo + i; - if(!_stricmp(ctx->uszPath, pi->uszNameFile)) { - return M_FcTimeline_ReadInfo(pi->dwId, pb, cb, pcbRead, cbOffset); + for(i = 0; i < H->fc->Timeline.cTp; i++) { + pi = H->fc->Timeline.pInfo + i; + if(!_stricmp(ctxP->uszPath, pi->uszNameFileTXT)) { + return M_FcTimeline_ReadInfo(H, pi->dwId, pb, cb, pcbRead, cbOffset); } } return VMMDLL_STATUS_FILE_INVALID; } -BOOL M_FcTimeline_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) +BOOL M_FcTimeline_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { QWORD i; PFC_TIMELINE_INFO pi; - if(ctx->uszPath[0]) { return FALSE; } - for(i = 0; i < ctxFc->Timeline.cTp; i++) { - pi = ctxFc->Timeline.pInfo + i; - if(pi->uszNameFile[0]) { - VMMDLL_VfsList_AddFile(pFileList, pi->uszNameFile, pi->dwFileSizeUTF8, NULL); + if(ctxP->uszPath[0]) { return FALSE; } + for(i = 0; i < H->fc->Timeline.cTp; i++) { + pi = H->fc->Timeline.pInfo + i; + if(pi->uszNameFileTXT[0]) { + VMMDLL_VfsList_AddFile(pFileList, pi->uszNameFileTXT, pi->dwFileSizeUTF8, NULL); } } return TRUE; } -VOID M_FcTimeline_Notify(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent) +VOID M_FcTimeline_Notify(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent) { if(fEvent == VMMDLL_PLUGIN_NOTIFY_FORENSIC_INIT_COMPLETE) { - PluginManager_SetVisibility(TRUE, "\\forensic\\timeline", TRUE); + PluginManager_SetVisibility(H, TRUE, "\\forensic\\timeline", TRUE); } } -VOID M_FcTimeline_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_FcTimeline_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if((pRI->tpSystem != VMM_SYSTEM_WINDOWS_X64) && (pRI->tpSystem != VMM_SYSTEM_WINDOWS_X86)) { return; } @@ -102,5 +102,5 @@ VOID M_FcTimeline_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) pRI->reg_fn.pfnList = M_FcTimeline_List; // List function supported pRI->reg_fn.pfnRead = M_FcTimeline_Read; // Read function supported pRI->reg_fn.pfnNotify = M_FcTimeline_Notify; // Notify function supported - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_file_handles_vads.c b/vmm/m_file_handles_vads.c index 1958ac4..6b9888d 100644 --- a/vmm/m_file_handles_vads.c +++ b/vmm/m_file_handles_vads.c @@ -11,49 +11,49 @@ #include "vmmwinobj.h" _Success_(return == 0) -NTSTATUS M_FileHandlesVads_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset, _In_ BOOL fHandles) +NTSTATUS M_FileHandlesVads_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset, _In_ BOOL fHandles) { QWORD va; POB_MAP pmObFiles = NULL; POB_VMMWINOBJ_OBJECT pOb = NULL; *pcbRead = 0; if(!(va = strtoull(ctx->uszPath, NULL, 16))) { return VMMDLL_STATUS_FILE_INVALID; } - if(!(pOb = VmmWinObj_Get(va))) { - VmmWinObjFile_GetByProcess(ctx->pProcess, &pmObFiles, fHandles); + if(!(pOb = VmmWinObj_Get(H, va))) { + VmmWinObjFile_GetByProcess(H, ctx->pProcess, &pmObFiles, fHandles); Ob_DECREF_NULL(&pmObFiles); - pOb = VmmWinObj_Get(va); + pOb = VmmWinObj_Get(H, va); } if(!pOb) { return VMMDLL_STATUS_FILE_INVALID; } if(pOb->tp != VMMWINOBJ_TYPE_FILE) { Ob_DECREF(pOb); return VMMDLL_STATUS_FILE_INVALID; } - *pcbRead = VmmWinObjFile_Read((POB_VMMWINOBJ_FILE)pOb, cbOffset, pb, cb, 0); + *pcbRead = VmmWinObjFile_Read(H, (POB_VMMWINOBJ_FILE)pOb, cbOffset, pb, cb, 0); Ob_DECREF(pOb); return *pcbRead ? VMM_STATUS_SUCCESS : VMM_STATUS_END_OF_FILE; } _Success_(return == 0) -NTSTATUS M_FileHandles_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS M_FileHandles_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { - return M_FileHandlesVads_Read(ctx, pb, cb, pcbRead, cbOffset, TRUE); + return M_FileHandlesVads_Read(H, ctxP, pb, cb, pcbRead, cbOffset, TRUE); } _Success_(return == 0) -NTSTATUS M_FileVads_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS M_FileVads_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { - return M_FileHandlesVads_Read(ctx, pb, cb, pcbRead, cbOffset, FALSE); + return M_FileHandlesVads_Read(H, ctxP, pb, cb, pcbRead, cbOffset, FALSE); } -BOOL M_FileHandlesVads_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList, _In_ BOOL fHandles) +BOOL M_FileHandlesVads_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList, _In_ BOOL fHandles) { POB_MAP pmObFiles; POB_VMMWINOBJ_FILE pObFile; CHAR uszAddressPath[MAX_PATH]; if(ctx->uszPath[0]) { return FALSE; } - if(VmmWinObjFile_GetByProcess(ctx->pProcess, &pmObFiles, fHandles)) { + if(VmmWinObjFile_GetByProcess(H, ctx->pProcess, &pmObFiles, fHandles)) { while((pObFile = ObMap_Pop(pmObFiles))) { - Util_PathPrependVA(uszAddressPath, pObFile->va, ctxVmm->f32, pObFile->uszName); + Util_PathPrependVA(uszAddressPath, pObFile->va, H->vmm.f32, pObFile->uszName); VMMDLL_VfsList_AddFile(pFileList, uszAddressPath, pObFile->cb, NULL); Ob_DECREF(pObFile); } @@ -62,17 +62,17 @@ BOOL M_FileHandlesVads_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFi return TRUE; } -BOOL M_FileHandles_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) +BOOL M_FileHandles_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { - return M_FileHandlesVads_List(ctx, pFileList, TRUE); + return M_FileHandlesVads_List(H, ctxP, pFileList, TRUE); } -BOOL M_FileVads_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) +BOOL M_FileVads_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { - return M_FileHandlesVads_List(ctx, pFileList, FALSE); + return M_FileHandlesVads_List(H, ctxP, pFileList, FALSE); } -VOID M_FileHandlesVads_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_FileHandlesVads_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if(!((pRI->tpSystem == VMM_SYSTEM_WINDOWS_X64) || (pRI->tpSystem == VMM_SYSTEM_WINDOWS_X86))) { return; } @@ -82,12 +82,12 @@ VOID M_FileHandlesVads_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) pRI->reg_info.fProcessModule = TRUE; // module shows in process directory pRI->reg_fn.pfnList = M_FileHandles_List; // List function supported pRI->reg_fn.pfnRead = M_FileHandles_Read; // Read function supported - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); // file vads strcpy_s(pRI->reg_info.uszPathName, 128, "\\files\\vads"); // module name pRI->reg_info.fRootModule = FALSE; // module shows in root directory pRI->reg_info.fProcessModule = TRUE; // module shows in process directory pRI->reg_fn.pfnList = M_FileVads_List; // List function supported pRI->reg_fn.pfnRead = M_FileVads_Read; // Read function supported - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_file_modules.c b/vmm/m_file_modules.c index 4c84c12..d080ea1 100644 --- a/vmm/m_file_modules.c +++ b/vmm/m_file_modules.c @@ -28,7 +28,7 @@ typedef struct tdOBFILEMODULES_MODULECACHE { * -- pFileList * -- return */ -POBFILEMODULES_MODULECACHE M_FileModules_GetModuleCache(_In_ PVMMDLL_PLUGIN_CONTEXT ctx) +POBFILEMODULES_MODULECACHE M_FileModules_GetModuleCache(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctx) { BOOL result = FALSE; DWORD iModule, cVad = 0; @@ -42,26 +42,26 @@ POBFILEMODULES_MODULECACHE M_FileModules_GetModuleCache(_In_ PVMMDLL_PLUGIN_CONT pObCache = ObContainer_GetOb(pProcess->Plugin.pObCPeDumpDirCache); // 2: set up cache (if needed) if(!pObCache) { - if(!VmmMap_GetModule(pProcess, &pObModuleMap)) { goto fail; } - pObCache = Ob_Alloc('MPeD', LMEM_ZEROINIT, sizeof(OBFILEMODULES_MODULECACHE) + ((QWORD)pObModuleMap->cMap + cVad) * sizeof(FILEMODULES_FILENTRY), NULL, NULL); + if(!VmmMap_GetModule(H, pProcess, &pObModuleMap)) { goto fail; } + pObCache = Ob_AllocEx(H, 'MPeD', LMEM_ZEROINIT, sizeof(OBFILEMODULES_MODULECACHE) + ((QWORD)pObModuleMap->cMap + cVad) * sizeof(FILEMODULES_FILENTRY), NULL, NULL); if(!pObCache) { goto fail; } // Load module bases (PE header) memory into cache with one single call. - if(!(pObSet_ModuleBaseAddresses = ObSet_New())) { goto fail; } + if(!(pObSet_ModuleBaseAddresses = ObSet_New(H))) { goto fail; } for(iModule = 0; iModule < pObModuleMap->cMap; iModule++) { ObSet_Push(pObSet_ModuleBaseAddresses, pObModuleMap->pMap[iModule].vaBase); } - VmmCachePrefetchPages(pProcess, pObSet_ModuleBaseAddresses, 0); + VmmCachePrefetchPages(H, pProcess, pObSet_ModuleBaseAddresses, 0); // Build file listing information cache (only from in-cache items). ZeroMemory(pbPage, 0x1000); for(iModule = 0; iModule < pObModuleMap->cMap; iModule++) { - VmmReadEx(pProcess, pObModuleMap->pMap[iModule].vaBase, pbPage, 0x1000, &cbPageRead, VMM_FLAG_FORCECACHE_READ); + VmmReadEx(H, pProcess, pObModuleMap->pMap[iModule].vaBase, pbPage, 0x1000, &cbPageRead, VMM_FLAG_FORCECACHE_READ); if(cbPageRead != 0x1000) { - VmmLog(ctx->MID, LOGLEVEL_DEBUG, "Skipping module: '%s' - paged/invalid?", pObModuleMap->pMap[iModule].uszText); + VmmLog(H, ctx->MID, LOGLEVEL_DEBUG, "Skipping module: '%s' - paged/invalid?", pObModuleMap->pMap[iModule].uszText); continue; } - pObCache->File[pObCache->cFiles].cb = PE_FileRaw_Size(pProcess, pObModuleMap->pMap[iModule].vaBase, pbPage); + pObCache->File[pObCache->cFiles].cb = PE_FileRaw_Size(H, pProcess, pObModuleMap->pMap[iModule].vaBase, pbPage); if(!pObCache->File[pObCache->cFiles].cb) { - VmmLog(ctx->MID, LOGLEVEL_DEBUG, "Skipping module: '%s' - paged/invalid?", pObModuleMap->pMap[iModule].uszText); + VmmLog(H, ctx->MID, LOGLEVEL_DEBUG, "Skipping module: '%s' - paged/invalid?", pObModuleMap->pMap[iModule].uszText); continue; } strncpy_s(pObCache->File[pObCache->cFiles].uszName, MAX_PATH, pObModuleMap->pMap[iModule].uszText, _TRUNCATE); @@ -79,18 +79,19 @@ fail: * List : function as specified by the module manager. The module manager will * call into this callback function whenever a list directory shall occur from * the given module. -* -- ctx +* -- H +* -- ctxP * -- pFileList * -- return */ _Success_(return) -BOOL M_FileModules_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) +BOOL M_FileModules_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { BOOL result = FALSE; DWORD iModule; POBFILEMODULES_MODULECACHE pObCache = NULL; - if(ctx->uszPath[0]) { return FALSE; } - if(!(pObCache = M_FileModules_GetModuleCache(ctx))) { return FALSE; } + if(ctxP->uszPath[0]) { return FALSE; } + if(!(pObCache = M_FileModules_GetModuleCache(H, ctxP))) { return FALSE; } for(iModule = 0; iModule < pObCache->cFiles; iModule++) { VMMDLL_VfsList_AddFile(pFileList, pObCache->File[iModule].uszName, pObCache->File[iModule].cb, NULL); } @@ -101,22 +102,23 @@ BOOL M_FileModules_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileLi /* * Read : function as specified by the module manager. The module manager will * call into this callback function whenever a read shall occur from a "file". -* -- ctx +* -- H +* -- ctxP * -- pb * -- cb * -- pcbRead * -- cbOffset * -- return */ -NTSTATUS M_FileModules_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS M_FileModules_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { BOOL f; PVMM_MAP_MODULEENTRY pModule = NULL; PVMMOB_MAP_MODULE pObModuleMap = NULL; *pcbRead = 0; f = (cbOffset <= 0x02000000) && - VmmMap_GetModuleEntryEx((PVMM_PROCESS)ctx->pProcess, 0, ctx->uszPath, &pObModuleMap, &pModule) && - PE_FileRaw_Read(ctx->pProcess, pModule->vaBase, pb, cb, pcbRead, (DWORD)cbOffset); + VmmMap_GetModuleEntryEx(H, (PVMM_PROCESS)ctxP->pProcess, 0, ctxP->uszPath, &pObModuleMap, &pModule) && + PE_FileRaw_Read(H, ctxP->pProcess, pModule->vaBase, pb, cb, pcbRead, (DWORD)cbOffset); Ob_DECREF_NULL(&pObModuleMap); return f ? VMMDLL_STATUS_SUCCESS : VMMDLL_STATUS_FILE_INVALID; } @@ -129,22 +131,23 @@ NTSTATUS M_FileModules_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, * and are shared between all processes. A write in one process is most likely * to affect all processes with this specific module loaded! * Writing may crash the target system! -* -- ctx +* -- H +* -- ctxP * -- pb * -- cb * -- pcbWrite * -- cbOffset * -- return */ -NTSTATUS M_FileModules_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) +NTSTATUS M_FileModules_Write(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) { BOOL f; PVMM_MAP_MODULEENTRY pModule = NULL; PVMMOB_MAP_MODULE pObModuleMap = NULL; *pcbWrite = 0; f = (cbOffset <= 0x02000000) && - VmmMap_GetModuleEntryEx((PVMM_PROCESS)ctx->pProcess, 0, ctx->uszPath, &pObModuleMap, &pModule) && - PE_FileRaw_Write(ctx->pProcess, pModule->vaBase, pb, cb, pcbWrite, (DWORD)cbOffset); + VmmMap_GetModuleEntryEx(H, (PVMM_PROCESS)ctxP->pProcess, 0, ctxP->uszPath, &pObModuleMap, &pModule) && + PE_FileRaw_Write(H, ctxP->pProcess, pModule->vaBase, pb, cb, pcbWrite, (DWORD)cbOffset); Ob_DECREF_NULL(&pObModuleMap); return f ? VMMDLL_STATUS_SUCCESS : VMMDLL_STATUS_FILE_INVALID; } @@ -155,9 +158,10 @@ NTSTATUS M_FileModules_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_reads_(cb) PBY * shall call the supplied pfnPluginManager_Register function. * NB! the module does not have to register itself - for example if the target * operating system or architecture is unsupported. -* -- pPluginRegInfo +* -- H +* -- pRI */ -VOID M_FileModules_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_FileModules_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if((pRI->tpSystem != VMM_SYSTEM_WINDOWS_X64) && (pRI->tpSystem != VMM_SYSTEM_WINDOWS_X86)) { return; } @@ -166,5 +170,5 @@ VOID M_FileModules_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) pRI->reg_fn.pfnList = M_FileModules_List; // List function supported pRI->reg_fn.pfnRead = M_FileModules_Read; // Read function supported pRI->reg_fn.pfnWrite = M_FileModules_Write; // Write function supported - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_findevil.c b/vmm/m_findevil.c index 73ca405..2d999a8 100644 --- a/vmm/m_findevil.c +++ b/vmm/m_findevil.c @@ -46,13 +46,13 @@ LPCSTR szM_FINDEVIL_README = "--- \n" \ "Find Evil is a work in progress - post github issues for feature requests. \n"; -VOID MFindEvil_Read_FindEvil_LnTpModule(_In_opt_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_EVILENTRY peEvil, _In_ WORD iLine, _Inout_updates_(MFINDEVIL_LINELENGTH_X64) LPSTR usz) +VOID MFindEvil_Read_FindEvil_LnTpModule(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_EVILENTRY peEvil, _In_ WORD iLine, _Inout_updates_(MFINDEVIL_LINELENGTH_X64) LPSTR usz) { DWORD i; PVMMOB_MAP_MODULE pObModuleMap = NULL; LPSTR uszModuleName = NULL; if(!pProcess) { return; } - if(VmmMap_GetModule(pProcess, &pObModuleMap)) { + if(VmmMap_GetModule(H, pProcess, &pObModuleMap)) { for(i = 0; i < pObModuleMap->cMap; i++) { if(pObModuleMap->pMap[i].vaBase == peEvil->va) { uszModuleName = pObModuleMap->pMap[i].uszFullName; @@ -64,7 +64,7 @@ VOID MFindEvil_Read_FindEvil_LnTpModule(_In_opt_ PVMM_PROCESS pProcess, _In_ PVM Ob_DECREF(pObModuleMap); } -VOID MFindEvil_Read_FindEvil_LnTpVadEx(_In_opt_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_EVILENTRY peEvil, _In_ WORD iLine, _Inout_updates_(MFINDEVIL_LINELENGTH_X64) LPSTR usz) +VOID MFindEvil_Read_FindEvil_LnTpVadEx(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_EVILENTRY peEvil, _In_ WORD iLine, _Inout_updates_(MFINDEVIL_LINELENGTH_X64) LPSTR usz) { QWORD qwHwPte; PVMM_MAP_VADENTRY peVad; @@ -74,9 +74,9 @@ VOID MFindEvil_Read_FindEvil_LnTpVadEx(_In_opt_ PVMM_PROCESS pProcess, _In_ PVMM CHAR szProtection[7] = { 0 }; CHAR szPatchOffset[8]; if(!pProcess) { return; } - if(!VmmMap_GetVad(pProcess, &pObVadMap, VMM_VADMAP_TP_FULL)) { goto fail; } - if(!(peVad = VmmMap_GetVadEntry(pObVadMap, peEvil->vaVad))) { goto fail; } - if(!VmmMap_GetVadEx(pProcess, &pObVadEx, VMM_VADMAP_TP_FULL, peVad->cVadExPagesBase + peEvil->oVadEx, 1) || !pObVadEx->cMap) { goto fail; } + if(!VmmMap_GetVad(H, pProcess, &pObVadMap, VMM_VADMAP_TP_FULL)) { goto fail; } + if(!(peVad = VmmMap_GetVadEntry(H, pObVadMap, peEvil->vaVad))) { goto fail; } + if(!VmmMap_GetVadEx(H, pProcess, &pObVadEx, VMM_VADMAP_TP_FULL, peVad->cVadExPagesBase + peEvil->oVadEx, 1) || !pObVadEx->cMap) { goto fail; } pex = pObVadEx->pMap; MmVad_StrProtectionFlags(peVad, szProtection); qwHwPte = (pex->tp == VMM_PTE_TP_HARDWARE) ? pex->pte : 0; @@ -109,25 +109,26 @@ fail: Ob_DECREF(pObVadEx); } -VOID MFindEvil_ReadLineCB(_Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_EVILENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR usz) +VOID MFindEvil_ReadLineCB(_In_ VMM_HANDLE H, _Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_EVILENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR usz) { VMM_EVIL_TP tp; CHAR uszBuffer[MFINDEVIL_LINELENGTH_X64] = { 0 }; - PVMM_PROCESS pObProcess = VmmProcessGet(pe->dwPID); + PVMM_PROCESS pObProcess = VmmProcessGet(H, pe->dwPID); + LPSTR uszText = uszBuffer; switch(pe->tp) { case VMM_EVIL_TP_PE_NA: strncpy_s(uszBuffer, sizeof(uszBuffer), "__internal_error__", _TRUNCATE); break; case VMM_EVIL_TP_PE_INJECTED: case VMM_EVIL_TP_PE_NOTLINKED: - MFindEvil_Read_FindEvil_LnTpModule(pObProcess, pe, (WORD)ie, uszBuffer); + MFindEvil_Read_FindEvil_LnTpModule(H, pObProcess, pe, (WORD)ie, uszBuffer); break; case VMM_EVIL_TP_VAD_PATCHED_PE: case VMM_EVIL_TP_VAD_PRIVATE_RX: case VMM_EVIL_TP_VAD_PRIVATE_RWX: case VMM_EVIL_TP_VAD_NOIMAGE_RX: case VMM_EVIL_TP_VAD_NOIMAGE_RWX: - MFindEvil_Read_FindEvil_LnTpVadEx(pObProcess, pe, (WORD)ie, uszBuffer); + MFindEvil_Read_FindEvil_LnTpVadEx(H, pObProcess, pe, (WORD)ie, uszBuffer); break; case VMM_EVIL_TP_PROC_NOLINK: case VMM_EVIL_TP_PROC_PARENT: @@ -136,27 +137,36 @@ VOID MFindEvil_ReadLineCB(_Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, _In_ D case VMM_EVIL_TP_PEB_BAD_LDR: // no description on these break; + case VMM_EVIL_TP_MAX: + // max value not used -> no description + break; + case VMM_EVIL_TP_DRIVER_PATH: + // evils with descriptive text + if(pe->cbuText && pe->uszText) { + uszText = pe->uszText; + } + break; } tp = min(pe->tp, sizeof(VMM_EVIL_TP_STRING) / sizeof(LPSTR) - 1); if(ctx) { // "fake" file read for json data - CharUtil_UtoJ(uszBuffer, -1, usz, cbLineLength + 1, NULL, NULL, CHARUTIL_FLAG_TRUNCATE | CHARUTIL_FLAG_STR_BUFONLY); + CharUtil_UtoJ(uszText, -1, usz, cbLineLength + 1, NULL, NULL, CHARUTIL_FLAG_TRUNCATE | CHARUTIL_FLAG_STR_BUFONLY); } else { // "ordinary" file read Util_usnprintf_ln(usz, cbLineLength, - "%04x%7i %-15s%12s %016llx %s", + "%04x%7i %-15s%-12s %016llx %s", ie, pe->dwPID, pObProcess ? pObProcess->szName : "_NA", VMM_EVIL_TP_STRING[tp], pe->va, - uszBuffer + uszText ); } Ob_DECREF(pObProcess); } -VOID MFindEvil_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) +VOID MFindEvil_FcLogJSON(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) { PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd; PVMMOB_MAP_EVIL pObEvilMap = NULL; @@ -167,39 +177,39 @@ VOID MFindEvil_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON if(ctxP->pProcess || !(pd = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMDLL_PLUGIN_FORENSIC_JSONDATA)))) { return; } pd->dwVersion = VMMDLL_PLUGIN_FORENSIC_JSONDATA_VERSION; pd->szjType = "evil"; - if(VmmMap_GetEvil(NULL, &pObEvilMap)) { + if(VmmMap_GetEvil(H, NULL, &pObEvilMap)) { for(i = 0; i < pObEvilMap->cMap; i++) { pe = pObEvilMap->pMap + i; tp = min(pe->tp, sizeof(VMM_EVIL_TP_STRING) / sizeof(LPSTR) - 1); - MFindEvil_ReadLineCB((PVOID)TRUE, _countof(usz) - 1, i, pe, usz); + MFindEvil_ReadLineCB(H, (PVOID)TRUE, _countof(usz) - 1, i, pe, usz); // assign: pd->i = i; pd->dwPID = pe->dwPID; pd->va[0] = pe->va; pd->usz[0] = VMM_EVIL_TP_STRING[tp]; pd->usz[1] = usz; - pfnLogJSON(pd); + pfnLogJSON(H, pd); } } Ob_DECREF(pObEvilMap); LocalFree(pd); } -NTSTATUS MFindEvil_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MFindEvil_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt; PVMMOB_MAP_EVIL pObEvilMap = NULL; - PVMM_PROCESS pProcess = (PVMM_PROCESS)ctx->pProcess; - if(!_stricmp(ctx->uszPath, "readme.txt")) { + PVMM_PROCESS pProcess = (PVMM_PROCESS)ctxP->pProcess; + if(!_stricmp(ctxP->uszPath, "readme.txt")) { return Util_VfsReadFile_FromPBYTE((PBYTE)szM_FINDEVIL_README, strlen(szM_FINDEVIL_README), pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "progress_percent.txt")) { - return Util_VfsReadFile_FromNumber(ctxVmm->EvilContext.cProgressPercent, pb, cb, pcbRead, cbOffset); + if(!_stricmp(ctxP->uszPath, "progress_percent.txt")) { + return Util_VfsReadFile_FromNumber(H->vmm.EvilContext.cProgressPercent, pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "findevil.txt")) { - if(VmmMap_GetEvil(pProcess, &pObEvilMap)) { + if(!_stricmp(ctxP->uszPath, "findevil.txt")) { + if(VmmMap_GetEvil(H, pProcess, &pObEvilMap)) { nt = Util_VfsLineFixed_Read( - (UTIL_VFSLINEFIXED_PFN_CB)MFindEvil_ReadLineCB, NULL, MFINDEVIL_LINELENGTH_X64, MFINDEVIL_LINEHEADER, + H, (UTIL_VFSLINEFIXED_PFN_CB)MFindEvil_ReadLineCB, NULL, MFINDEVIL_LINELENGTH_X64, MFINDEVIL_LINEHEADER, pObEvilMap->pMap, pObEvilMap->cMap, sizeof(VMM_MAP_EVILENTRY), pb, cb, pcbRead, cbOffset ); @@ -213,19 +223,19 @@ NTSTATUS MFindEvil_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pc return VMMDLL_STATUS_FILE_INVALID; } -BOOL MFindEvil_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) +BOOL MFindEvil_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { QWORD qwProgress; DWORD cbEvil; PVMMOB_MAP_EVIL pObEvilMap = NULL; - PVMM_PROCESS pProcess = (PVMM_PROCESS)ctx->pProcess; - if(ctx->uszPath[0]) { return FALSE; } - VmmMap_GetEvil(pProcess, &pObEvilMap); - cbEvil = pObEvilMap ? (UTIL_VFSLINEFIXED_LINECOUNT(pObEvilMap->cMap) * MFINDEVIL_LINELENGTH_X64) : 0; + PVMM_PROCESS pProcess = (PVMM_PROCESS)ctxP->pProcess; + if(ctxP->uszPath[0]) { return FALSE; } + VmmMap_GetEvil(H, pProcess, &pObEvilMap); + cbEvil = pObEvilMap ? (UTIL_VFSLINEFIXED_LINECOUNT(H, pObEvilMap->cMap) * MFINDEVIL_LINELENGTH_X64) : 0; VMMDLL_VfsList_AddFile(pFileList, "findevil.txt", cbEvil, NULL); VMMDLL_VfsList_AddFile(pFileList, "readme.txt", strlen(szM_FINDEVIL_README), NULL); - if(!ctx->pProcess) { - qwProgress = ctxVmm->EvilContext.cProgressPercent; + if(!ctxP->pProcess) { + qwProgress = H->vmm.EvilContext.cProgressPercent; qwProgress = (qwProgress == 100) ? 3 : ((qwProgress >= 10) ? 2 : 1); VMMDLL_VfsList_AddFile(pFileList, "progress_percent.txt", qwProgress, NULL); } @@ -233,24 +243,24 @@ BOOL MFindEvil_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) return TRUE; } -VOID MFindEvil_Notify(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent) +VOID MFindEvil_Notify(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent) { if(fEvent == VMMDLL_PLUGIN_NOTIFY_FORENSIC_INIT_COMPLETE) { - PluginManager_SetVisibility(TRUE, "\\forensic\\findevil", TRUE); + PluginManager_SetVisibility(H, TRUE, "\\forensic\\findevil", TRUE); } } -VOID MFindEvil_FcFinalize(_In_opt_ PVOID ctxfc) +VOID MFindEvil_FcFinalize(_In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc) { - VmmEvil_InitializeAll_WaitFinish(); + VmmEvil_InitializeAll_WaitFinish(H); } -BOOL MFindEvil_VisiblePlugin(_In_ PVMMDLL_PLUGIN_CONTEXT ctx) +BOOL MFindEvil_VisiblePlugin(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP) { - return !ctx->pProcess || ((PVMM_PROCESS)ctx->pProcess)->fUserOnly; + return !ctxP->pProcess || ((PVMM_PROCESS)ctxP->pProcess)->fUserOnly; } -VOID M_FindEvil_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_FindEvil_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if(pRI->sysinfo.f32 || (pRI->sysinfo.dwVersionBuild < 9600)) { return; } // only support 64-bit Win8.1+ for now @@ -261,17 +271,17 @@ VOID M_FindEvil_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) strcpy_s(pRI->reg_info.uszPathName, 128, "\\findevil"); pRI->reg_info.fRootModule = FALSE; pRI->reg_info.fProcessModule = TRUE; - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); // register root plugin strcpy_s(pRI->reg_info.uszPathName, 128, "\\misc\\findevil"); pRI->reg_info.fRootModule = TRUE; pRI->reg_info.fProcessModule = FALSE; - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); // register forensic plugin strcpy_s(pRI->reg_info.uszPathName, 128, "\\forensic\\findevil"); pRI->reg_info.fRootModuleHidden = TRUE; pRI->reg_fn.pfnNotify = MFindEvil_Notify; pRI->reg_fnfc.pfnFinalize = MFindEvil_FcFinalize; pRI->reg_fnfc.pfnLogJSON = MFindEvil_FcLogJSON; // JSON log function supported - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_misc_bitlocker.c b/vmm/m_misc_bitlocker.c index 4486cf4..2aa7b55 100644 --- a/vmm/m_misc_bitlocker.c +++ b/vmm/m_misc_bitlocker.c @@ -92,10 +92,10 @@ static LPCSTR szMBDE_MODE_STR[] = { /* * Update a key with display information. -* -- ctx +* -- ctxBDE * -- pk */ -VOID MBDE_ContextKeyUpdate(_In_ PMBDE_CONTEXT ctx, _In_ PMBDE_KEY pk) +VOID MBDE_ContextKeyUpdate(_In_ PMBDE_CONTEXT ctxBDE, _In_ PMBDE_KEY pk) { DWORD o, i = 0; CHAR szKey1[129], szKey2[129]; @@ -115,7 +115,7 @@ VOID MBDE_ContextKeyUpdate(_In_ PMBDE_CONTEXT ctx, _In_ PMBDE_KEY pk) szMBDE_MODE_STR[pk->dwMode], 2 * pk->cbKey, szKey1 ); - if((pk->dwMode == MBDE_MODE_AES128_DIFFUSER) || (pk->dwMode == MBDE_MODE_AES256_DIFFUSER) || ctx->fWin8) { + if((pk->dwMode == MBDE_MODE_AES128_DIFFUSER) || (pk->dwMode == MBDE_MODE_AES256_DIFFUSER) || ctxBDE->fWin8) { snprintf(pk->szTXT + o, _countof(pk->szTXT) - o, "Tweak: %.*s\n", 2 * pk->cbKey, szKey2); } } @@ -123,39 +123,40 @@ VOID MBDE_ContextKeyUpdate(_In_ PMBDE_CONTEXT ctx, _In_ PMBDE_KEY pk) /* * Add a key context. This is usually a recovered bitlocker AES key. * In case of Win8 it may be a partial key if elephant diffuser is used. -* -- ctx +* -- H +* -- ctxBDE * -- peKey * -- pbKeyBlob */ -VOID MBDE_ContextKeyAdd(_In_ PMBDE_CONTEXT ctx, _In_ PMBDE_KEY peKey, _In_ PBYTE pbKeyBlob) +VOID MBDE_ContextKeyAdd(_In_ VMM_HANDLE H, _In_ PMBDE_CONTEXT ctxBDE, _In_ PMBDE_KEY peKey, _In_ PBYTE pbKeyBlob) { PMBDE_KEY pk; if(!(pk = LocalAlloc(0, sizeof(MBDE_KEY) + peKey->cbBlob))) { return; } - if(!ObMap_Push(ctx->pmBDE, peKey->va, pk)) { + if(!ObMap_Push(ctxBDE->pmBDE, peKey->va, pk)) { LocalFree(pk); return; } memcpy(pk, peKey, sizeof(MBDE_KEY)); memcpy(pk->pbBlob, pbKeyBlob, peKey->cbBlob); - MBDE_ContextKeyUpdate(ctx, pk); - VmmLog(ctx->ctxP->MID, LOGLEVEL_TRACE, "Key located at %llx", pk->va); + MBDE_ContextKeyUpdate(ctxBDE, pk); + VmmLog(H, ctxBDE->ctxP->MID, LOGLEVEL_TRACE, "Key located at %llx", pk->va); } /* * Merge any Win8 diffuser keys. In Win8 and early win10 keys are split between * two different key blobs. There is a pointer which ties keys together. Merge * these key blobs into two different versions - one correct and one fail. -* -- ctx +* -- ctxBDE */ -VOID MBDE_Win8_PostProcess(_In_ PMBDE_CONTEXT ctx) +VOID MBDE_Win8_PostProcess(_In_ VMM_HANDLE H, _In_ PMBDE_CONTEXT ctxBDE) { PMBDE_KEY pKey1 = NULL, pKey2; QWORD va1 = 0, va2 = 0; - while((pKey1 = ObMap_GetNext(ctx->pmBDE, pKey1))) { - va1 = VMM_PTR_OFFSET_DUAL(ctxVmm->f32, pKey1->pbBlob, 0x10, 8); + while((pKey1 = ObMap_GetNext(ctxBDE->pmBDE, pKey1))) { + va1 = VMM_PTR_OFFSET_DUAL(H->vmm.f32, pKey1->pbBlob, 0x10, 8); pKey2 = NULL; - while((pKey2 = ObMap_GetNext(ctx->pmBDE, pKey2))) { - va2 = VMM_PTR_OFFSET_DUAL(ctxVmm->f32, pKey2->pbBlob, 0x10, 8); + while((pKey2 = ObMap_GetNext(ctxBDE->pmBDE, pKey2))) { + va2 = VMM_PTR_OFFSET_DUAL(H->vmm.f32, pKey2->pbBlob, 0x10, 8); if((pKey1 == pKey2) || (va1 != va2) || pKey1->fWin8Merge || pKey2->fWin8Merge) { continue; } // pointer match - merge keys in two different ways! if(pKey1->dwMode == MBDE_MODE_AES128) { pKey1->dwMode = MBDE_MODE_AES128_DIFFUSER; } @@ -164,11 +165,11 @@ VOID MBDE_Win8_PostProcess(_In_ PMBDE_CONTEXT ctx) if(pKey2->dwMode == MBDE_MODE_AES256) { pKey2->dwMode = MBDE_MODE_AES256_DIFFUSER; } memcpy(pKey1->pbKey2, pKey2->pbKey1, 32); memcpy(pKey2->pbKey2, pKey1->pbKey1, 32); - MBDE_ContextKeyUpdate(ctx, pKey1); - MBDE_ContextKeyUpdate(ctx, pKey2); + MBDE_ContextKeyUpdate(ctxBDE, pKey1); + MBDE_ContextKeyUpdate(ctxBDE, pKey2); pKey1->fWin8Merge = TRUE; pKey2->fWin8Merge = TRUE; - VmmLog(ctx->ctxP->MID, LOGLEVEL_TRACE, "Keys updated at %llx %llx", pKey1->va, pKey2->va); + VmmLog(H, ctxBDE->ctxP->MID, LOGLEVEL_TRACE, "Keys updated at %llx %llx", pKey1->va, pKey2->va); return; } } @@ -176,18 +177,19 @@ VOID MBDE_Win8_PostProcess(_In_ PMBDE_CONTEXT ctx) /* * Parse a Win10 14393+ bitlocker key. -* -- ctx +* -- H +* -- ctxBDE * -- pe * -- pb */ -VOID MBDE_Win10(_In_ PMBDE_CONTEXT ctx, _In_ PVMM_MAP_POOLENTRY pe, _In_ PBYTE pb) +VOID MBDE_Win10(_In_ VMM_HANDLE H, _In_ PMBDE_CONTEXT ctxBDE, _In_ PVMM_MAP_POOLENTRY pe, _In_ PBYTE pb) { MBDE_KEY e = { 0 }; MBDE_OFFSET o = { 0 }; DWORD i, dw, cbKey, dwMode; - BOOL fWin8 = (ctxVmm->kernel.dwVersionBuild < 14393); + BOOL fWin8 = (H->vmm.kernel.dwVersionBuild < 14393); if(pe->cb > 0x1000) { return; } - if(ctxVmm->f32) { + if(H->vmm.f32) { // 32-bit if(pe->cb < (fWin8 ? 0x268UL : 0x400UL)) { return; } o.o0 = 0x50; o.o1 = 0x54; o.o2 = 0x78; o.o3 = 0x98; @@ -204,7 +206,7 @@ VOID MBDE_Win10(_In_ PMBDE_CONTEXT ctx, _In_ PVMM_MAP_POOLENTRY pe, _In_ PBYTE p // length/signature: dw = *(PDWORD)(pb + i + o.o0); if((dw != 0x10) && (dw != 0x20) && (dw != 0x40)) { - VmmLog(ctx->ctxP->MID, LOGLEVEL_TRACE, "Failed candidate at %llx (signature)", pe->va); + VmmLog(H, ctxBDE->ctxP->MID, LOGLEVEL_TRACE, "Failed candidate at %llx (signature)", pe->va); return; } // mode & length: @@ -228,7 +230,7 @@ VOID MBDE_Win10(_In_ PMBDE_CONTEXT ctx, _In_ PVMM_MAP_POOLENTRY pe, _In_ PBYTE p } } if(!dwMode || (e.dwMode && (e.dwMode != dwMode))) { - VmmLog(ctx->ctxP->MID, LOGLEVEL_TRACE, "Failed candidate at %llx (mode #1)", pe->va); + VmmLog(H, ctxBDE->ctxP->MID, LOGLEVEL_TRACE, "Failed candidate at %llx (mode #1)", pe->va); return; } e.cbKey = cbKey; @@ -237,7 +239,7 @@ VOID MBDE_Win10(_In_ PMBDE_CONTEXT ctx, _In_ PVMM_MAP_POOLENTRY pe, _In_ PBYTE p if(memcmp(e.pbKey1, pbMBDE_ZERO32, 32)) { // pre-existing key - this is a tweak key (diffuser) if((e.dwMode == MBDE_MODE_AES128_XTS) || (e.dwMode == MBDE_MODE_AES256_XTS)) { - VmmLog(ctx->ctxP->MID, LOGLEVEL_TRACE, "Failed candidate at %llx (mode #2)", pe->va); + VmmLog(H, ctxBDE->ctxP->MID, LOGLEVEL_TRACE, "Failed candidate at %llx (mode #2)", pe->va); return; } e.dwMode = (e.cbKey == 16) ? MBDE_MODE_AES128_DIFFUSER : MBDE_MODE_AES256_DIFFUSER; @@ -250,24 +252,25 @@ VOID MBDE_Win10(_In_ PMBDE_CONTEXT ctx, _In_ PVMM_MAP_POOLENTRY pe, _In_ PBYTE p } // finish: if(!memcmp(e.pbKey1, pbMBDE_ZERO32, 32)) { - VmmLog(ctx->ctxP->MID, LOGLEVEL_TRACE, "Failed candidate at %llx (no key found)", pe->va); + VmmLog(H, ctxBDE->ctxP->MID, LOGLEVEL_TRACE, "Failed candidate at %llx (no key found)", pe->va); return; } - MBDE_ContextKeyAdd(ctx, &e, pb); + MBDE_ContextKeyAdd(H, ctxBDE, &e, pb); } /* * Parse a Win7 bitlocker key. -* -- ctx +* -- H +* -- ctxBDE * -- pe * -- pb */ -VOID MBDE_Win7(_In_ PMBDE_CONTEXT ctx, _In_ PVMM_MAP_POOLENTRY pe, _In_ PBYTE pb) +VOID MBDE_Win7(_In_ VMM_HANDLE H, _In_ PMBDE_CONTEXT ctxBDE, _In_ PVMM_MAP_POOLENTRY pe, _In_ PBYTE pb) { MBDE_KEY e = { 0 }; MBDE_OFFSET o = { 0 }; // 1: initialize static offsets - if(ctxVmm->f32) { + if(H->vmm.f32) { if(pe->cb == 0x1f0) { o.o0 = 0x10; o.o1 = 0x18; o.o2 = 0; } if(pe->cb == 0x3c8) { o.o0 = 0x10; o.o1 = 0x18; o.o2 = 0x1f0; } } else { @@ -275,12 +278,12 @@ VOID MBDE_Win7(_In_ PMBDE_CONTEXT ctx, _In_ PVMM_MAP_POOLENTRY pe, _In_ PBYTE pb if(pe->cb == 0x3e0) { o.o0 = 0x1c; o.o1 = 0x20; o.o2 = 0x200; } } if(!o.o0) { - VmmLog(ctx->ctxP->MID, LOGLEVEL_TRACE, "Failed candidate at %llx [%i] (length)", pe->va, pe->cb); + VmmLog(H, ctxBDE->ctxP->MID, LOGLEVEL_TRACE, "Failed candidate at %llx [%i] (length)", pe->va, pe->cb); return; } // 2: parse mode & key if((pb[o.o0] > 0x03) || (pb[o.o0 + 1] != 0x80)) { - VmmLog(ctx->ctxP->MID, LOGLEVEL_TRACE, "Failed candidate at %llx (mode)", pe->va); + VmmLog(H, ctxBDE->ctxP->MID, LOGLEVEL_TRACE, "Failed candidate at %llx (mode)", pe->va); return; } e.va = pe->va; @@ -291,29 +294,30 @@ VOID MBDE_Win7(_In_ PMBDE_CONTEXT ctx, _In_ PVMM_MAP_POOLENTRY pe, _In_ PBYTE pb if((e.dwMode == MBDE_MODE_AES128_DIFFUSER) || (e.dwMode == MBDE_MODE_AES256_DIFFUSER)) { memcpy(e.pbKey2, pb + o.o2, e.cbKey); } - MBDE_ContextKeyAdd(ctx, &e, pb); + MBDE_ContextKeyAdd(H, ctxBDE, &e, pb); } /* * Pool scanner function - locates bitlocker pool tags and send them onwards * for analysis in os-dependent pfnCB callback function. -* -- ctx +* -- H +* -- ctxBDE * -- dwPoolTag * -- pfnCB */ -VOID MBDE_PoolScan(_In_ PMBDE_CONTEXT ctx, _In_ DWORD dwPoolTag, _In_ VOID(*pfnCB)(PMBDE_CONTEXT, PVMM_MAP_POOLENTRY, PBYTE)) +VOID MBDE_PoolScan(_In_ VMM_HANDLE H, _In_ PMBDE_CONTEXT ctxBDE, _In_ DWORD dwPoolTag, _In_ VOID(*pfnCB)(VMM_HANDLE H, PMBDE_CONTEXT, PVMM_MAP_POOLENTRY, PBYTE)) { DWORD i, j; BYTE pb[4096]; PVMM_MAP_POOLENTRY pe; PVMM_MAP_POOLENTRYTAG pTag; - for(i = 0; i < ctx->pPoolMap->cTag; i++) { - pTag = ctx->pPoolMap->pTag + i; + for(i = 0; i < ctxBDE->pPoolMap->cTag; i++) { + pTag = ctxBDE->pPoolMap->pTag + i; if(pTag->dwTag == dwPoolTag) { for(j = 0; j < pTag->cEntry; j++) { - pe = ctx->pPoolMap->pMap + ctx->pPoolMap->piTag2Map[pTag->iTag2Map + j]; - if((pe->cb < sizeof(pb)) && VmmRead(PVMM_PROCESS_SYSTEM, pe->va, pb, pe->cb)) { - pfnCB(ctx, pe, pb); + pe = ctxBDE->pPoolMap->pMap + ctxBDE->pPoolMap->piTag2Map[pTag->iTag2Map + j]; + if((pe->cb < sizeof(pb)) && VmmRead(H, PVMM_PROCESS_SYSTEM, pe->va, pb, pe->cb)) { + pfnCB(H, ctxBDE, pe, pb); } } return; @@ -324,54 +328,57 @@ VOID MBDE_PoolScan(_In_ PMBDE_CONTEXT ctx, _In_ DWORD dwPoolTag, _In_ VOID(*pfnC /* * Build a new context with results. * CALLER DECREF: return +* -- H * -- ctxP * -- return */ -POB_MAP MBDE_ContextFetch_DoWork(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) +POB_MAP MBDE_ContextFetch_DoWork(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP) { - MBDE_CONTEXT ctx = { 0 }; - VmmLog(ctxP->MID, LOGLEVEL_TRACE, "Initialization started"); + MBDE_CONTEXT ctxBDE = { 0 }; + DWORD dwBuild = H->vmm.kernel.dwVersionBuild; + VmmLog(H, ctxP->MID, LOGLEVEL_TRACE, "Initialization started"); // 1: context init - ctx.ctxP = ctxP; - ctx.pmBDE = ObMap_New(OB_MAP_FLAGS_OBJECT_LOCALFREE); - VmmMap_GetPool(&ctx.pPoolMap, TRUE); - if(!ctx.pmBDE || !ctx.pPoolMap) { - VmmLog(ctxP->MID, LOGLEVEL_VERBOSE, "Initialization failed: POOL/OOM"); + ctxBDE.ctxP = ctxP; + ctxBDE.pmBDE = ObMap_New(H, OB_MAP_FLAGS_OBJECT_LOCALFREE); + VmmMap_GetPool(H, &ctxBDE.pPoolMap, TRUE); + if(!ctxBDE.pmBDE || !ctxBDE.pPoolMap) { + VmmLog(H, ctxP->MID, LOGLEVEL_VERBOSE, "Initialization failed: POOL/OOM"); goto fail; } // 2: dispatch - if(ctxVmm->kernel.dwVersionBuild >= 14393) { - MBDE_PoolScan(&ctx, 'enoN', MBDE_Win10); - } else if(ctxVmm->kernel.dwVersionBuild >= 9200) { - ctx.fWin8 = TRUE; - MBDE_PoolScan(&ctx, 'bgnC', MBDE_Win10); - MBDE_Win8_PostProcess(&ctx); - } else if(ctxVmm->kernel.dwVersionBuild >= 7600) { - MBDE_PoolScan(&ctx, 'cEVF', MBDE_Win7); + if(dwBuild >= 14393) { + MBDE_PoolScan(H, &ctxBDE, 'enoN', MBDE_Win10); + } else if(dwBuild >= 9200) { + ctxBDE.fWin8 = TRUE; + MBDE_PoolScan(H, &ctxBDE, 'bgnC', MBDE_Win10); + MBDE_Win8_PostProcess(H, &ctxBDE); + } else if(dwBuild >= 7600) { + MBDE_PoolScan(H, &ctxBDE, 'cEVF', MBDE_Win7); } - VmmLog(ctxP->MID, LOGLEVEL_TRACE, "Initialization completed"); + VmmLog(H, ctxP->MID, LOGLEVEL_TRACE, "Initialization completed"); fail: - Ob_DECREF(ctx.pPoolMap); - return ctx.pmBDE; + Ob_DECREF(ctxBDE.pPoolMap); + return ctxBDE.pmBDE; } /* * Fetch, and if required, build a new context with results. * CALLER DECREF: return +* -- H * -- ctxP * -- return */ -POB_MAP MBDE_ContextFetch(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) +POB_MAP MBDE_ContextFetch(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP) { POB_MAP pmObBDE = ObContainer_GetOb((POB_CONTAINER)ctxP->ctxM); if(!pmObBDE) { - EnterCriticalSection(&ctxVmm->LockPlugin); + EnterCriticalSection(&H->vmm.LockPlugin); pmObBDE = ObContainer_GetOb((POB_CONTAINER)ctxP->ctxM); if(!pmObBDE) { - pmObBDE = MBDE_ContextFetch_DoWork(ctxP); + pmObBDE = MBDE_ContextFetch_DoWork(H, ctxP); ObContainer_SetOb((POB_CONTAINER)ctxP->ctxM, pmObBDE); } - LeaveCriticalSection(&ctxVmm->LockPlugin); + LeaveCriticalSection(&H->vmm.LockPlugin); } return pmObBDE; } @@ -382,7 +389,7 @@ POB_MAP MBDE_ContextFetch(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) // PLUGIN ACCESS FUNCTIONALITY BELOW: // ---------------------------------------------------------------------------- -VOID MBDE_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) +VOID MBDE_FcLogJSON(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) { DWORD i, cKey = 0; PMBDE_KEY pKey = NULL; @@ -390,7 +397,7 @@ VOID MBDE_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In CHAR szDislocker[MAX_PATH]; PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd = NULL; if(ctxP->pProcess) { return; } - if(!(pmObBDE = MBDE_ContextFetch(ctxP))) { goto fail; } + if(!(pmObBDE = MBDE_ContextFetch(H, ctxP))) { goto fail; } if(!(pd = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMDLL_PLUGIN_FORENSIC_JSONDATA)))) { goto fail; } pd->dwVersion = VMMDLL_PLUGIN_FORENSIC_JSONDATA_VERSION; pd->szjType = "bitlocker"; @@ -402,14 +409,14 @@ VOID MBDE_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In pd->vaObj = pKey->va; pd->usz[0] = szMBDE_MODE_STR[pKey->dwMode]; pd->usz[1] = szDislocker; - pfnLogJSON(pd); + pfnLogJSON(H, pd); } fail: Ob_DECREF(pmObBDE); LocalFree(pd); } -NTSTATUS MBDE_ReadInternal(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ POB_MAP pmObBDE, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset) +NTSTATUS MBDE_ReadInternal(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ POB_MAP pmObBDE, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset) { PMBDE_KEY pKey = NULL; if(0 == _stricmp("readme.txt", ctxP->uszPath)) { @@ -429,22 +436,22 @@ NTSTATUS MBDE_ReadInternal(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ POB_MAP pmObBD return VMMDLL_STATUS_FILE_INVALID; } -NTSTATUS MBDE_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset) +NTSTATUS MBDE_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; - POB_MAP pmObBDE = MBDE_ContextFetch(ctxP); + POB_MAP pmObBDE = MBDE_ContextFetch(H, ctxP); *pcbRead = 0; if(pmObBDE) { - nt = MBDE_ReadInternal(ctxP, pmObBDE, pb, cb, pcbRead, cbOffset); + nt = MBDE_ReadInternal(H, ctxP, pmObBDE, pb, cb, pcbRead, cbOffset); } Ob_DECREF(pmObBDE); return nt; } -BOOL MBDE_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) +BOOL MBDE_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { PMBDE_KEY pKey = NULL; - POB_MAP pmObBDE = MBDE_ContextFetch(ctxP); + POB_MAP pmObBDE = MBDE_ContextFetch(H, ctxP); if(!ctxP->uszPath[0]) { VMMDLL_VfsList_AddFile(pFileList, "readme.txt", strlen(szMBDE_README), NULL); while((pKey = ObMap_GetNext(pmObBDE, pKey))) { @@ -457,19 +464,19 @@ BOOL MBDE_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) return TRUE; } -VOID MBDE_Notify(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent) +VOID MBDE_Notify(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent) { if(fEvent == VMMDLL_PLUGIN_NOTIFY_REFRESH_SLOW) { ObContainer_SetOb((POB_CONTAINER)ctxP->ctxM, NULL); } } -VOID MBDE_Close(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) +VOID MBDE_Close(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP) { Ob_DECREF((POB_CONTAINER)ctxP->ctxM); } -VOID M_BDE_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_BDE_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } // the bitlocker plugin is only supported on: 64-bit Windows or 32-bit Windows 10 14393 or later. @@ -483,5 +490,5 @@ VOID M_BDE_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) pRI->reg_fn.pfnNotify = MBDE_Notify; // Notify function supported. pRI->reg_fn.pfnClose = MBDE_Close; // Close function supported. pRI->reg_fnfc.pfnLogJSON = MBDE_FcLogJSON; // JSON log function supported - pRI->pfnPluginManager_Register(pRI); // Register with the plugin manager + pRI->pfnPluginManager_Register(H, pRI); // Register with the plugin manager } diff --git a/vmm/m_misc_web.c b/vmm/m_misc_web.c index 059682e..c768538 100644 --- a/vmm/m_misc_web.c +++ b/vmm/m_misc_web.c @@ -96,7 +96,7 @@ typedef struct tdMWEB_CONTEXT { * -- tpAction * -- szSql */ -VOID FcWeb_AddEntryFromDB(_In_ PMWEB_CONTEXT ctx, VMM_MAP_WEB_TPBROWSER tpBrowser, VMM_MAP_WEB_TPACTION tpAction, _In_ LPSTR szSql) +VOID FcWeb_AddEntryFromDB(_In_ VMM_HANDLE H, _In_ PMWEB_CONTEXT ctx, VMM_MAP_WEB_TPBROWSER tpBrowser, VMM_MAP_WEB_TPACTION tpAction, _In_ LPSTR szSql) { QWORD qwHash; PVMM_MAP_WEBENTRY pe; @@ -145,15 +145,17 @@ VOID FcWeb_AddEntryFromDB(_In_ PMWEB_CONTEXT ctx, VMM_MAP_WEB_TPBROWSER tpBrowse // WEB BROWSER SPECIFIC PARSING below: // ---------------------------------------------------------------------------- -VOID FcWeb_FF_Places(_In_ PMWEB_CONTEXT ctx) +VOID FcWeb_FF_Places(_In_ VMM_HANDLE H, _In_ PMWEB_CONTEXT ctx) { FcWeb_AddEntryFromDB( + H, ctx, VMM_MAP_WEB_TPBROWSER_FIREFOX, VMM_MAP_WEB_TPACTION_BROWSE, "SELECT 0, last_visit_date, url, title from moz_places WHERE last_visit_date > 0" ); FcWeb_AddEntryFromDB( + H, ctx, VMM_MAP_WEB_TPBROWSER_FIREFOX, VMM_MAP_WEB_TPACTION_DOWNLOAD, @@ -161,16 +163,18 @@ VOID FcWeb_FF_Places(_In_ PMWEB_CONTEXT ctx) ); } -VOID FcWeb_Chrome_History(_In_ PMWEB_CONTEXT ctx) +VOID FcWeb_Chrome_History(_In_ VMM_HANDLE H, _In_ PMWEB_CONTEXT ctx) { VMM_MAP_WEB_TPBROWSER tpBrowser = strstr(ctx->pProcess->szName, "chrome") ? VMM_MAP_WEB_TPBROWSER_CHROME : VMM_MAP_WEB_TPBROWSER_MSEDGE; FcWeb_AddEntryFromDB( + H, ctx, tpBrowser, VMM_MAP_WEB_TPACTION_BROWSE, "SELECT v.visit_time, 0, u.url, u.title FROM visits v, urls u WHERE v.url = u.id AND v.visit_time > 0" ); FcWeb_AddEntryFromDB( + H, ctx, tpBrowser, VMM_MAP_WEB_TPACTION_DOWNLOAD, @@ -186,10 +190,11 @@ VOID FcWeb_Chrome_History(_In_ PMWEB_CONTEXT ctx) /* * Dispatch a file for analysis to the appropriate browser tanalysis functions. +* -- H * -- ctx * -- pfnCB = analysis callback function. */ -VOID FcWeb_LoadSqliteDispatch(_In_ PMWEB_CONTEXT ctx, _In_ VOID(*pfnCB)(_In_ PMWEB_CONTEXT ctx)) +VOID FcWeb_LoadSqliteDispatch(_In_ VMM_HANDLE H, _In_ PMWEB_CONTEXT ctx, _In_ VOID(*pfnCB)(_In_ VMM_HANDLE H, _In_ PMWEB_CONTEXT ctx)) { int rc; DWORD cbDB; @@ -199,17 +204,17 @@ VOID FcWeb_LoadSqliteDispatch(_In_ PMWEB_CONTEXT ctx, _In_ VOID(*pfnCB)(_In_ PMW FILE *phFile = NULL; // 1: sanity checks if((ctx->pFile->cb < 0x1000) || (ctx->pFile->cb > 0x04000000)) { goto fail; } - VmmWinObjFile_Read(ctx->pFile, 0, pbTest, sizeof(pbTest) - 1, 0); + VmmWinObjFile_Read(H, ctx->pFile, 0, pbTest, sizeof(pbTest) - 1, 0); if(pbTest != (PBYTE)strstr((LPCSTR)pbTest, "SQLite ")) { goto fail; } // 2: read file handle into memory cbDB = (DWORD)ctx->pFile->cb; if(!(pbDB = LocalAlloc(0, cbDB))) { goto fail; } - cbDB = VmmWinObjFile_Read(ctx->pFile, 0, pbDB, cbDB, 0); + cbDB = VmmWinObjFile_Read(H, ctx->pFile, 0, pbDB, cbDB, 0); // 3: create and write to temp file if(tmpnam_s(szFile, MAX_PATH)) { goto fail; } strncat_s(szFile, _countof(szFile), ".vmmsqlite3.tmp", _TRUNCATE); if(fopen_s(&phFile, szFile, "wb")) { - VmmLog(ctx->MID, LOGLEVEL_DEBUG, "fail open temp file: %s", szFile); + VmmLog(H, ctx->MID, LOGLEVEL_DEBUG, "fail open temp file: %s", szFile); goto fail; } fwrite(pbDB, 1, cbDB, phFile); @@ -219,9 +224,9 @@ VOID FcWeb_LoadSqliteDispatch(_In_ PMWEB_CONTEXT ctx, _In_ VOID(*pfnCB)(_In_ PMW CharUtil_ReplaceAllA(szURI, '\\', '/'); rc = sqlite3_open_v2(szURI, &ctx->hDB, SQLITE_OPEN_URI | SQLITE_OPEN_READONLY | SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_EXCLUSIVE, NULL); if(rc == SQLITE_OK) { - pfnCB(ctx); + pfnCB(H, ctx); } else { - VmmLog(ctx->MID, LOGLEVEL_DEBUG, "fail sqlite3 open: rc=%i db='%s'", rc, ctx->pFile->uszName); + VmmLog(H, ctx->MID, LOGLEVEL_DEBUG, "fail sqlite3 open: rc=%i db='%s'", rc, ctx->pFile->uszName); } fail: sqlite3_close(ctx->hDB); ctx->hDB = NULL; @@ -235,23 +240,24 @@ fail: * -- pProcess * -- ctx */ -VOID MWeb_Initialize_ThreadProc(_In_ PVMM_PROCESS pProcess, _In_ PVOID pvCtxInit) +VOID MWeb_Initialize_ThreadProc(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVOID pvCtxInit) { BOOL fAnalyze; QWORD qwHashFile; POB_MAP pmObFiles; POB_VMMWINOBJ_FILE pObFile; PMWEB_CONTEXT ctx = pvCtxInit; - if(!VmmWinObjFile_GetByProcess(pProcess, &pmObFiles, TRUE)) { return; } - VmmLog(ctx->MID, LOGLEVEL_TRACE, "process: pid=%i", pProcess->dwPID); + if(!VmmWinObjFile_GetByProcess(H, pProcess, &pmObFiles, TRUE)) { return; } + VmmLog(H, ctx->MID, LOGLEVEL_TRACE, "process: pid=%i", pProcess->dwPID); while((pObFile = ObMap_Pop(pmObFiles))) { if(pObFile->fData) { - VmmLog(ctx->MID, LOGLEVEL_TRACE, "handle: pid=%i handle=%s", pProcess->dwPID, pObFile->uszName); + VmmLog(H, ctx->MID, LOGLEVEL_TRACE, "handle: pid=%i handle=%s", pProcess->dwPID, pObFile->uszName); // check if already processed (multiple handles often exists) qwHashFile = pObFile->cb + pProcess->dwPID; qwHashFile = qwHashFile + (qwHashFile << 32) + CharUtil_Hash64U(pObFile->uszName, FALSE); if(!ObSet_Push(ctx->psFileProcessed, qwHashFile)) { // already processed another handle to same file + Ob_DECREF(pObFile); continue; } // lock & prepare: @@ -262,16 +268,16 @@ VOID MWeb_Initialize_ThreadProc(_In_ PVMM_PROCESS pProcess, _In_ PVOID pvCtxInit // dispatch to analysis: fAnalyze = FALSE; if((fAnalyze = !strcmp(pObFile->uszName, "places.sqlite"))) { // firefox 'places.sqlite' - FcWeb_LoadSqliteDispatch(ctx, FcWeb_FF_Places); + FcWeb_LoadSqliteDispatch(H, ctx, FcWeb_FF_Places); } //if((fAnalyze = !strcmp(pObFile->uszName, "cookies.sqlite"))) { // firefox cookies.sqlite // FcWeb_LoadSqliteDispatch(&ctx, FcWeb_FF_Cookies); //} if((fAnalyze = !strcmp(pObFile->uszName, "History"))) { // chrome/edge 'History' - FcWeb_LoadSqliteDispatch(ctx, FcWeb_Chrome_History); + FcWeb_LoadSqliteDispatch(H, ctx, FcWeb_Chrome_History); } if(fAnalyze) { - VmmLog(ctx->MID, LOGLEVEL_DEBUG, "analyze: pid=%i db=%s", pProcess->dwPID, pObFile->uszName); + VmmLog(H, ctx->MID, LOGLEVEL_DEBUG, "analyze: pid=%i db=%s", pProcess->dwPID, pObFile->uszName); } // finish: ctx->pFile = NULL; @@ -284,7 +290,7 @@ VOID MWeb_Initialize_ThreadProc(_In_ PVMM_PROCESS pProcess, _In_ PVOID pvCtxInit Ob_DECREF(pmObFiles); } -BOOL MWeb_CriteriaSupportedBrowserProcess(_In_ PVMM_PROCESS pProcess, _In_opt_ PVOID ctx) +BOOL MWeb_CriteriaSupportedBrowserProcess(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ PVOID ctx) { if(pProcess->dwState != 0) { return FALSE; } return @@ -307,9 +313,10 @@ int MWeb_Initialize_CmpSort(POB_MAP_ENTRY p1, POB_MAP_ENTRY p2) /* * Initialize a new web map in a single-threaded context. +* -- H * -- ctxP */ -VOID MWeb_Initialize_DoWork(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) +VOID MWeb_Initialize_DoWork(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP) { BOOL fResult = FALSE; DWORD i, cMap, cbDataStr, cbData, cbOffset = 0; @@ -318,16 +325,16 @@ VOID MWeb_Initialize_DoWork(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) PVMMOB_MAP_WEB pObMap = NULL; // 1: INIT: ctxInit.MID = ctxP->MID; - if(!(ctxInit.psFileProcessed = ObSet_New())) { goto fail; } - if(!(ctxInit.pm = ObMap_New(OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } - if(!(ctxInit.psm = ObStrMap_New(OB_STRMAP_FLAGS_CASE_SENSITIVE))) { goto fail; } + if(!(ctxInit.psFileProcessed = ObSet_New(H))) { goto fail; } + if(!(ctxInit.pm = ObMap_New(H, OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } + if(!(ctxInit.psm = ObStrMap_New(H, OB_STRMAP_FLAGS_CASE_SENSITIVE))) { goto fail; } // 2: DISPATCH TO ANALYSIS: - VmmProcessActionForeachParallel(&ctxInit, MWeb_CriteriaSupportedBrowserProcess, MWeb_Initialize_ThreadProc); + if(!VmmWork_ProcessActionForeachParallel_Void(H, 0, &ctxInit, MWeb_CriteriaSupportedBrowserProcess, MWeb_Initialize_ThreadProc)) { goto fail; } // 3: CREATE MAP / FINALIZE: if(!ObStrMap_FinalizeBufferU(ctxInit.psm, 0, NULL, &cbDataStr)) { goto fail; } cMap = ObMap_Size(ctxInit.pm); cbData = sizeof(VMMOB_MAP_WEB) + cMap * (sizeof(VMM_MAP_WEBENTRY) + sizeof(DWORD)) + cbDataStr; - if(!(pObMap = Ob_Alloc(OB_TAG_MAP_WEB, LMEM_ZEROINIT, cbData, NULL, NULL))) { goto fail; } + if(!(pObMap = Ob_AllocEx(H, OB_TAG_MAP_WEB, LMEM_ZEROINIT, cbData, NULL, NULL))) { goto fail; } pObMap->cMap = cMap; pObMap->pdwLineOffset = (PDWORD)(pObMap->pMap + pObMap->cMap); pObMap->pbMultiText = (LPSTR)((QWORD)pObMap + cbData - cbDataStr); @@ -347,7 +354,7 @@ fail: Ob_DECREF(ctxInit.pm); Ob_DECREF(ctxInit.psm); Ob_DECREF(ctxInit.psFileProcessed); - if(!fResult && (pObMap = Ob_Alloc(OB_TAG_MAP_WEB, LMEM_ZEROINIT, sizeof(VMMOB_MAP_WEB), NULL, NULL))) { + if(!fResult && (pObMap = Ob_AllocEx(H, OB_TAG_MAP_WEB, LMEM_ZEROINIT, sizeof(VMMOB_MAP_WEB), NULL, NULL))) { pObMap->pdwLineOffset = &pObMap->cMap; ObContainer_SetOb((POB_CONTAINER)ctxP->ctxM, pObMap); Ob_DECREF(pObMap); @@ -357,16 +364,17 @@ fail: /* * Fetch the 'WebMap' object. * CALLER DECREF: return +* -- H * -- ctxP * -- return */ -PVMMOB_MAP_WEB MWeb_GetWebMap(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) +PVMMOB_MAP_WEB MWeb_GetWebMap(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP) { static SRWLOCK LockSRW = SRWLOCK_INIT; PVMMOB_MAP_WEB pOb; if((pOb = ObContainer_GetOb((POB_CONTAINER)ctxP->ctxM))) { return pOb; } AcquireSRWLockExclusive(&LockSRW); - MWeb_Initialize_DoWork(ctxP); + MWeb_Initialize_DoWork(H, ctxP); ReleaseSRWLockExclusive(&LockSRW); return ObContainer_GetOb((POB_CONTAINER)ctxP->ctxM); } @@ -380,7 +388,7 @@ PVMMOB_MAP_WEB MWeb_GetWebMap(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) /* * Generate a single line in the web.txt file. */ -VOID MWeb_ReadLine_CB(_In_ PVMMOB_MAP_WEB pObWebMap, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVOID pv, _Out_writes_(cbLineLength + 1) LPSTR szu8) +VOID MWeb_ReadLine_CB(_In_ VMM_HANDLE H, _In_ PVMMOB_MAP_WEB pObWebMap, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVOID pv, _Out_writes_(cbLineLength + 1) LPSTR szu8) { PVMM_MAP_WEBENTRY pe = pObWebMap->pMap + ie; CHAR szTime[24]; @@ -398,17 +406,17 @@ VOID MWeb_ReadLine_CB(_In_ PVMMOB_MAP_WEB pObWebMap, _In_ DWORD cbLineLength, _I ); } -NTSTATUS MWeb_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MWeb_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; PVMMOB_MAP_WEB pObWebMap = NULL; - if(!(pObWebMap = MWeb_GetWebMap(ctxP))) { goto finish; } + if(!(pObWebMap = MWeb_GetWebMap(H, ctxP))) { goto finish; } if(!_stricmp("readme.txt", ctxP->uszPath)) { return VMMDLL_UtilVfsReadFile_FromPBYTE(szMWEB_README, strlen(szMWEB_README), pb, cb, pcbRead, cbOffset); } if(!_stricmp(ctxP->uszPath, "web.txt")) { nt = Util_VfsLineVariable_Read( - (UTIL_VFSLINEFIXED_PFN_CB)MWeb_ReadLine_CB, pObWebMap, MWEB_LINEHEADER, + H, (UTIL_VFSLINEFIXED_PFN_CB)MWeb_ReadLine_CB, pObWebMap, MWEB_LINEHEADER, pObWebMap->pMap, pObWebMap->cMap, sizeof(VMM_MAP_WEBENTRY), pObWebMap->pdwLineOffset, pb, cb, pcbRead, cbOffset ); @@ -419,13 +427,13 @@ finish: return nt; } -BOOL MWeb_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) +BOOL MWeb_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { PVMMOB_MAP_WEB pObWebMap = NULL; - if(!(pObWebMap = MWeb_GetWebMap(ctxP))) { goto finish; } + if(!(pObWebMap = MWeb_GetWebMap(H, ctxP))) { goto finish; } if(!ctxP->uszPath[0]) { VMMDLL_VfsList_AddFile(pFileList, "readme.txt", strlen(szMWEB_README), NULL); - VMMDLL_VfsList_AddFile(pFileList, "web.txt", UTIL_VFSLINEVARIABLE_BYTECOUNT(pObWebMap->cMap, pObWebMap->pdwLineOffset, MWEB_LINEHEADER), NULL); + VMMDLL_VfsList_AddFile(pFileList, "web.txt", UTIL_VFSLINEVARIABLE_BYTECOUNT(H, pObWebMap->cMap, pObWebMap->pdwLineOffset, MWEB_LINEHEADER), NULL); goto finish; } finish: @@ -433,19 +441,19 @@ finish: return TRUE; } -VOID MWeb_Notify(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent) +VOID MWeb_Notify(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent) { if(fEvent == VMMDLL_PLUGIN_NOTIFY_REFRESH_SLOW) { ObContainer_SetOb((POB_CONTAINER)ctxP->ctxM, NULL); } } -VOID MWeb_Close(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) +VOID MWeb_Close(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP) { Ob_DECREF(ctxP->ctxM); } -VOID MWeb_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) +VOID MWeb_FcLogJSON(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) { DWORD ie; PVMM_MAP_WEBENTRY pe = NULL; @@ -453,7 +461,7 @@ VOID MWeb_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd = NULL; CHAR usz[2048], szTime[24]; if(ctxP->pProcess) { return; } - if(!(pObWebMap = MWeb_GetWebMap(ctxP))) { goto fail; } + if(!(pObWebMap = MWeb_GetWebMap(H, ctxP))) { goto fail; } if(!(pd = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMDLL_PLUGIN_FORENSIC_JSONDATA)))) { goto fail; } pd->dwVersion = VMMDLL_PLUGIN_FORENSIC_JSONDATA_VERSION; pd->szjType = "web"; @@ -469,7 +477,7 @@ VOID MWeb_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In pd->dwPID = pe->dwPID; pd->usz[0] = pe->uszUrl; pd->usz[1] = usz; - pfnLogJSON(pd); + pfnLogJSON(H, pd); } fail: Ob_DECREF(pObWebMap); @@ -477,10 +485,11 @@ fail: } VOID MWeb_FcTimeline( + _In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc, _In_ HANDLE hTimeline, - _In_ VOID(*pfnAddEntry)(_In_ HANDLE hTimeline, _In_ QWORD ft, _In_ DWORD dwAction, _In_ DWORD dwPID, _In_ DWORD dwData32, _In_ QWORD qwData64, _In_ LPSTR uszText), - _In_ VOID(*pfnEntryAddBySql)(_In_ HANDLE hTimeline, _In_ DWORD cEntrySql, _In_ LPSTR *pszEntrySql) + _In_ VOID(*pfnAddEntry)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ QWORD ft, _In_ DWORD dwAction, _In_ DWORD dwPID, _In_ DWORD dwData32, _In_ QWORD qwData64, _In_ LPSTR uszText), + _In_ VOID(*pfnEntryAddBySql)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ DWORD cEntrySql, _In_ LPSTR *pszEntrySql) ) { PVMMOB_MAP_WEB pWebMap = (PVMMOB_MAP_WEB)ctxfc; PVMM_MAP_WEBENTRY pe; @@ -497,26 +506,26 @@ VOID MWeb_FcTimeline( pe->uszInfo); if(cch > 10) { if(pe->ftCreate) { - pfnAddEntry(hTimeline, pe->ftCreate, FC_TIMELINE_ACTION_CREATE, pe->dwPID, 0, 0, usz); + pfnAddEntry(H, hTimeline, pe->ftCreate, FC_TIMELINE_ACTION_CREATE, pe->dwPID, 0, 0, usz); } if(pe->ftAccess && (pe->ftAccess != pe->ftCreate)) { - pfnAddEntry(hTimeline, pe->ftAccess, FC_TIMELINE_ACTION_READ, pe->dwPID, 0, 0, usz); + pfnAddEntry(H, hTimeline, pe->ftAccess, FC_TIMELINE_ACTION_READ, pe->dwPID, 0, 0, usz); } } } } -VOID MWeb_FcFinalize(_In_opt_ PVOID ctxfc) +VOID MWeb_FcFinalize(_In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc) { Ob_DECREF(ctxfc); } -PVOID MWeb_FcInitialize(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) +PVOID MWeb_FcInitialize(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP) { - return MWeb_GetWebMap(ctxP); + return MWeb_GetWebMap(H, ctxP); } -VOID M_MiscWeb_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_MiscWeb_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if((pRI->tpSystem != VMM_SYSTEM_WINDOWS_X64) && (pRI->tpSystem != VMM_SYSTEM_WINDOWS_X86)) { return; } @@ -534,6 +543,6 @@ VOID M_MiscWeb_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) pRI->reg_fnfc.pfnTimeline = MWeb_FcTimeline; // Forensic timelining supported pRI->reg_fnfc.pfnFinalize = MWeb_FcFinalize; // Forensic finalize function supported memcpy(pRI->reg_info.sTimelineNameShort, "WEB", 4); - strncpy_s(pRI->reg_info.uszTimelineFile, 32, "timeline_web.txt", _TRUNCATE); - pRI->pfnPluginManager_Register(pRI); + strncpy_s(pRI->reg_info.uszTimelineFile, 32, "timeline_web", _TRUNCATE); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_modules.h b/vmm/m_modules.h index 0797e9e..0c6b6f5 100644 --- a/vmm/m_modules.h +++ b/vmm/m_modules.h @@ -10,67 +10,71 @@ /* * Initialization function for the build-in virtual file system root folder module. */ -VOID M_VfsRoot_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_VfsRoot_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); /* * Initialization function for the build-in virtual file system process folder module. */ -VOID M_VfsProc_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_VfsProc_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); /* * Initialization function for the build-in virtual file system forensic folder module. */ -VOID M_VfsFc_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_VfsFc_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); /* * Initialization functions for ROOT modules. * NB! modules may in some cases be combined ROOT/FORENSIC/PROCESS modules. */ -VOID M_BDE_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID M_Conf_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID M_FindEvil_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID M_MiscWeb_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID M_Phys2Virt_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID M_Sys_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID M_SysCert_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID M_SysDriver_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID M_SysMem_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID M_SysNet_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID M_SysObj_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID M_SysPool_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID M_SysProc_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID M_SysSvc_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID M_SysSyscall_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID M_SysTask_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID M_Virt2Phys_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID M_WinReg_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_BDE_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_Conf_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_FindEvil_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_MiscWeb_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_Phys2Virt_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_Sys_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_SysCert_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_SysDriver_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_SysMem_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_SysNet_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_SysObj_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_SysPool_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_SysProc_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_SysSvc_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_SysSyscall_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_SysTask_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_SysUser_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_Virt2Phys_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_WinReg_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); /* * Initialization functions for FORENSIC related modules. */ -VOID M_FcJSON_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID M_FcTimeline_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID M_FcModule_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID M_FcNtfs_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID M_FcProc_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID M_FcRegistry_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID M_FcThread_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_FcCSV_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_FcHandle_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_FcJSON_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_FcTimeline_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_FcModule_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_FcNtfs_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_FcProc_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_FcRegistry_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_FcSys_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_FcThread_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); /* * Initialization functions for PROCESS related modules. */ -VOID M_FileHandlesVads_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID M_FileModules_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID M_ProcHandle_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID M_ProcHeap_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID M_ProcLdrModules_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID M_ProcMemMap_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID M_ProcMiniDump_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID M_ProcToken_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID M_ProcThread_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID M_Search_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_FileHandlesVads_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_FileModules_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_ProcHandle_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_ProcHeap_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_ProcLdrModules_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_ProcMemMap_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_ProcMiniDump_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_ProcToken_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_ProcThread_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); +VOID M_Search_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pPluginRegInfo); -VOID(*g_pfnModulesAllInternal[])(_In_ PVMMDLL_PLUGIN_REGINFO pRegInfo) = { +VOID(*g_pfnModulesAllInternal[])(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_REGINFO pRegInfo) = { // core modules M_VfsRoot_Initialize, M_VfsProc_Initialize, @@ -101,14 +105,18 @@ VOID(*g_pfnModulesAllInternal[])(_In_ PVMMDLL_PLUGIN_REGINFO pRegInfo) = { M_SysProc_Initialize, M_SysSvc_Initialize, M_SysTask_Initialize, + M_SysUser_Initialize, M_WinReg_Initialize, // forensic modules + M_FcCSV_Initialize, + M_FcHandle_Initialize, M_FcJSON_Initialize, M_FcTimeline_Initialize, M_FcModule_Initialize, M_FcNtfs_Initialize, M_FcProc_Initialize, M_FcRegistry_Initialize, + M_FcSys_Initialize, M_FcThread_Initialize, #ifdef _WIN32 // windows-only per-process modules diff --git a/vmm/m_phys2virt.c b/vmm/m_phys2virt.c index 3018c79..b999980 100644 --- a/vmm/m_phys2virt.c +++ b/vmm/m_phys2virt.c @@ -31,13 +31,13 @@ typedef struct tdM_PHYS2VIRT_MULTIENTRY_CONTEXT { M_PHYS2VIRT_MULTIENTRY e[0]; } M_PHYS2VIRT_MULTIENTRY_CONTEXT, *PM_PHYS2VIRT_MULTIENTRY_CONTEXT; -VOID Phys2Virt_GetUpdateAll_CallbackAction(_In_ PVMM_PROCESS pProcess, _In_opt_ PVOID ctxIn) +VOID Phys2Virt_GetUpdateAll_CallbackAction(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ PVOID ctxIn) { PM_PHYS2VIRT_MULTIENTRY_CONTEXT ctx = (PM_PHYS2VIRT_MULTIENTRY_CONTEXT)ctxIn; DWORD i, j; PVMMOB_PHYS2VIRT_INFORMATION pObPhys2Virt = NULL; if(!ctx) { return; } - pObPhys2Virt = VmmPhys2VirtGetInformation(pProcess, ctx->pa); + pObPhys2Virt = VmmPhys2VirtGetInformation(H, pProcess, ctx->pa); if(!pObPhys2Virt) { return; } for(j = 0; j < pObPhys2Virt->cvaList; j++) { if(pObPhys2Virt->pvaList[j]) { @@ -55,16 +55,19 @@ VOID Phys2Virt_GetUpdateAll_CallbackAction(_In_ PVMM_PROCESS pProcess, _In_opt_ * CALLER LocalFree: ppMultiEntry */ _Success_(return) -BOOL Phys2Virt_GetUpdateAll(_Out_opt_ PM_PHYS2VIRT_MULTIENTRY_CONTEXT *ppMultiEntry, _Out_opt_ PDWORD pcMultiEntry) +BOOL Phys2Virt_GetUpdateAll(_In_ VMM_HANDLE H, _Out_opt_ PM_PHYS2VIRT_MULTIENTRY_CONTEXT *ppMultiEntry, _Out_opt_ PDWORD pcMultiEntry) { PM_PHYS2VIRT_MULTIENTRY_CONTEXT ctx = NULL; SIZE_T cPIDs = 0; - VmmProcessListPIDs(NULL, &cPIDs, 0); + VmmProcessListPIDs(H, NULL, &cPIDs, 0); ctx = LocalAlloc(LMEM_ZEROINIT, sizeof(M_PHYS2VIRT_MULTIENTRY_CONTEXT) + cPIDs * 4 * sizeof(M_PHYS2VIRT_MULTIENTRY)); if(!ctx) { return FALSE; } - ctx->pa = ctxVmm->paPluginPhys2VirtRoot; + ctx->pa = H->vmm.paPluginPhys2VirtRoot; ctx->cMax = (DWORD)cPIDs * 4; - VmmProcessActionForeachParallel(ctx, VmmProcessActionForeachParallel_CriteriaActiveOnly, Phys2Virt_GetUpdateAll_CallbackAction); + if(!VmmWork_ProcessActionForeachParallel_Void(H, 0, ctx, VmmWork_ProcessActionForeachParallel_CriteriaActiveOnly, Phys2Virt_GetUpdateAll_CallbackAction)) { + LocalFree(ctx); + return FALSE; + } ctx->c = min(ctx->c, ctx->cMax - 1); if(pcMultiEntry) { *pcMultiEntry = ctx->c; } if(ppMultiEntry) { @@ -87,13 +90,13 @@ int Phys2Virt_ReadVirtRoot_CmpSort(PM_PHYS2VIRT_MULTIENTRY a, PM_PHYS2VIRT_MULTI return a->dwPID - b->dwPID; } -NTSTATUS Phys2Virt_ReadVirtRoot(_Out_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS Phys2Virt_ReadVirtRoot(_In_ VMM_HANDLE H, _Out_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; DWORD i, cbBuffer = 0, cbBufferMax; PBYTE pbBuffer = NULL; PM_PHYS2VIRT_MULTIENTRY_CONTEXT ctx = NULL; - if(Phys2Virt_GetUpdateAll(&ctx, NULL)) { + if(Phys2Virt_GetUpdateAll(H, &ctx, NULL)) { cbBufferMax = 24 * ctx->c + 0x10; pbBuffer = LocalAlloc(0, cbBufferMax); if(pbBuffer) { @@ -104,7 +107,7 @@ NTSTATUS Phys2Virt_ReadVirtRoot(_Out_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbR cbBuffer += snprintf( pbBuffer + cbBuffer, cbBufferMax - cbBuffer, - ctxVmm->f32 ? "%6i %08llx\n" : "%6i %016llx\n", + H->vmm.f32 ? "%6i %08llx\n" : "%6i %016llx\n", ctx->e[i].dwPID, ctx->e[i].va ); @@ -119,6 +122,7 @@ NTSTATUS Phys2Virt_ReadVirtRoot(_Out_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbR /* * Read the virtual address file with up to PHYS2VIRT_MAX_NUMBER_ADDRESS entries. +* -- H * -- pProcess * -- pb * -- cb @@ -126,21 +130,21 @@ NTSTATUS Phys2Virt_ReadVirtRoot(_Out_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbR * -- cbOffset * -- return */ -NTSTATUS Phys2Virt_ReadVirtProcess(_In_ PVMM_PROCESS pProcess, _Out_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS Phys2Virt_ReadVirtProcess(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Out_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { DWORD i; DWORD cbBuffer = 0, cbBufferMax = 0x10 + VMM_PHYS2VIRT_INFORMATION_MAX_PROCESS_RESULT * 17; BYTE pbBuffer[0x10 + VMM_PHYS2VIRT_INFORMATION_MAX_PROCESS_RESULT * 17] = { 0 }; PVMMOB_PHYS2VIRT_INFORMATION pObPhys2Virt = NULL; // 1: retrieve / start update of PVMMOB_PHYS2VIRT_INFORMATION in a thread-safe way. - pObPhys2Virt = VmmPhys2VirtGetInformation(pProcess, 0); + pObPhys2Virt = VmmPhys2VirtGetInformation(H, pProcess, 0); // 2: show result if(pObPhys2Virt) { for(i = 0; i < pObPhys2Virt->cvaList; i++) { cbBuffer += snprintf( pbBuffer + cbBuffer, cbBufferMax - cbBuffer, - ctxVmm->f32 ? "%08llx\n" : "%016llx\n", + H->vmm.f32 ? "%08llx\n" : "%016llx\n", pObPhys2Virt->pvaList[i] ); } @@ -152,37 +156,38 @@ NTSTATUS Phys2Virt_ReadVirtProcess(_In_ PVMM_PROCESS pProcess, _Out_ PBYTE pb, _ /* * Read : function as specified by the module manager. The module manager will * call into this callback function whenever a read shall occur from a "file". -* -- ctx +* -- H +* -- ctxP * -- pb * -- cb * -- pcbRead * -- cbOffset * -- return */ -NTSTATUS Phys2Virt_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS Phys2Virt_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt; PVMMOB_PHYS2VIRT_INFORMATION pObPhys2Virt = NULL; - PVMM_PROCESS pProcess = (PVMM_PROCESS)ctx->pProcess; - if(!_stricmp(ctx->uszPath, "readme.txt")) { + PVMM_PROCESS pProcess = (PVMM_PROCESS)ctxP->pProcess; + if(!_stricmp(ctxP->uszPath, "readme.txt")) { return Util_VfsReadFile_FromStrA(szMPHYS2VIRT_README, pb, cb, pcbRead, cbOffset); } if(pProcess) { - if(!_stricmp(ctx->uszPath, "phys.txt")) { - pObPhys2Virt = VmmPhys2VirtGetInformation(pProcess, 0); + if(!_stricmp(ctxP->uszPath, "phys.txt")) { + pObPhys2Virt = VmmPhys2VirtGetInformation(H, pProcess, 0); nt = Util_VfsReadFile_FromQWORD((pObPhys2Virt ? pObPhys2Virt->paTarget : 0), pb, cb, pcbRead, cbOffset, FALSE); Ob_DECREF_NULL(&pObPhys2Virt); return nt; } - if(!_stricmp(ctx->uszPath, "virt.txt")) { - return Phys2Virt_ReadVirtProcess(pProcess, pb, cb, pcbRead, cbOffset); + if(!_stricmp(ctxP->uszPath, "virt.txt")) { + return Phys2Virt_ReadVirtProcess(H, pProcess, pb, cb, pcbRead, cbOffset); } } else { - if(!_stricmp(ctx->uszPath, "phys.txt")) { - return Util_VfsReadFile_FromQWORD(ctxVmm->paPluginPhys2VirtRoot, pb, cb, pcbRead, cbOffset, FALSE); + if(!_stricmp(ctxP->uszPath, "phys.txt")) { + return Util_VfsReadFile_FromQWORD(H->vmm.paPluginPhys2VirtRoot, pb, cb, pcbRead, cbOffset, FALSE); } - if(!_stricmp(ctx->uszPath, "virt.txt")) { - return Phys2Virt_ReadVirtRoot(pb, cb, pcbRead, cbOffset); + if(!_stricmp(ctxP->uszPath, "virt.txt")) { + return Phys2Virt_ReadVirtRoot(H, pb, cb, pcbRead, cbOffset); } } return VMMDLL_STATUS_FILE_INVALID; @@ -191,19 +196,20 @@ NTSTATUS Phys2Virt_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pc /* * Write : function as specified by the module manager. The module manager will * call into this callback function whenever a write shall occur from a "file". -* -- ctx +* -- H +* -- ctxP * -- pb * -- cb * -- pcbWrite * -- cbOffset * -- return */ -NTSTATUS Phys2Virt_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) +NTSTATUS Phys2Virt_Write(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) { BYTE pbBuffer[17]; - PVMM_PROCESS pProcess = (PVMM_PROCESS)ctx->pProcess; + PVMM_PROCESS pProcess = (PVMM_PROCESS)ctxP->pProcess; *pcbWrite = 0; - if(!_stricmp(ctx->uszPath, "phys.txt")) { + if(!_stricmp(ctxP->uszPath, "phys.txt")) { if(cbOffset < 16) { *pcbWrite = cb; memcpy(pbBuffer, "0000000000000000", 16); @@ -211,10 +217,10 @@ NTSTATUS Phys2Virt_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_reads_(cb) PBYTE p memcpy(pbBuffer + cbOffset, pb, cb); pbBuffer[16] = 0; if(pProcess) { - Ob_DECREF(VmmPhys2VirtGetInformation(pProcess, strtoull(pbBuffer, NULL, 16))); + Ob_DECREF(VmmPhys2VirtGetInformation(H, pProcess, strtoull(pbBuffer, NULL, 16))); } else { - ctxVmm->paPluginPhys2VirtRoot = strtoull(pbBuffer, NULL, 16); - Phys2Virt_GetUpdateAll(NULL, NULL); + H->vmm.paPluginPhys2VirtRoot = strtoull(pbBuffer, NULL, 16); + Phys2Virt_GetUpdateAll(H, NULL, NULL); } } return *pcbWrite ? VMMDLL_STATUS_SUCCESS : VMMDLL_STATUS_END_OF_FILE; @@ -226,25 +232,26 @@ NTSTATUS Phys2Virt_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_reads_(cb) PBYTE p * List : function as specified by the module manager. The module manager will * call into this callback function whenever a list directory shall occur from * the given module. -* -- ctx +* -- H +* -- ctxP * -- pFileList * -- return */ -BOOL Phys2Virt_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) +BOOL Phys2Virt_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { DWORD c = 0, cb; PVMMOB_PHYS2VIRT_INFORMATION pObPhys2Virt = NULL; - PVMM_PROCESS pProcess = (PVMM_PROCESS)ctx->pProcess; - if(ctx->uszPath[0]) { return FALSE; } + PVMM_PROCESS pProcess = (PVMM_PROCESS)ctxP->pProcess; + if(ctxP->uszPath[0]) { return FALSE; } if(pProcess) { // process context - pObPhys2Virt = VmmPhys2VirtGetInformation(pProcess, 0); - cb = !pObPhys2Virt ? 0 : pObPhys2Virt->cvaList * (1 + (ctxVmm->f32 ? 8 : 16)); + pObPhys2Virt = VmmPhys2VirtGetInformation(H, pProcess, 0); + cb = !pObPhys2Virt ? 0 : pObPhys2Virt->cvaList * (1 + (H->vmm.f32 ? 8 : 16)); Ob_DECREF(pObPhys2Virt); } else { // root context - Phys2Virt_GetUpdateAll(NULL, &c); - cb = c * (8 + (ctxVmm->f32 ? 8 : 16)); + Phys2Virt_GetUpdateAll(H, NULL, &c); + cb = c * (8 + (H->vmm.f32 ? 8 : 16)); } VMMDLL_VfsList_AddFile(pFileList, "readme.txt", strlen(szMPHYS2VIRT_README), NULL); VMMDLL_VfsList_AddFile(pFileList, "phys.txt", 16, NULL); @@ -258,9 +265,10 @@ BOOL Phys2Virt_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) * shall call the supplied pfnPluginManager_Register function. * NB! the module does not have to register itself - for example if the target * operating system or architecture is unsupported. +* -- H * -- pRI */ -VOID M_Phys2Virt_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_Phys2Virt_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if(!((pRI->tpMemoryModel == VMM_MEMORYMODEL_X64) || (pRI->tpMemoryModel == VMM_MEMORYMODEL_X86) || (pRI->tpMemoryModel == VMM_MEMORYMODEL_X86PAE))) { return; } @@ -271,10 +279,10 @@ VOID M_Phys2Virt_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) strcpy_s(pRI->reg_info.uszPathName, 128, "\\phys2virt"); pRI->reg_info.fRootModule = FALSE; pRI->reg_info.fProcessModule = TRUE; - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); // register root plugin strcpy_s(pRI->reg_info.uszPathName, 128, "\\misc\\phys2virt"); pRI->reg_info.fRootModule = TRUE; pRI->reg_info.fProcessModule = FALSE; - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_proc_handle.c b/vmm/m_proc_handle.c index ca3d0de..248ce4e 100644 --- a/vmm/m_proc_handle.c +++ b/vmm/m_proc_handle.c @@ -13,11 +13,11 @@ #define MHANDLE_LINELENGTH 222ULL #define MHANDLE_LINEHEADER " # PID Handle Object Address Access Type Description" -VOID MHandle_ReadLine_Callback(_Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_HANDLEENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR szu8) +VOID MHandle_ReadLine_CB(_In_ VMM_HANDLE H, _Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_HANDLEENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR szu8) { PVMMWIN_OBJECT_TYPE pOT; CHAR szType[32] = { 0 }; - if((pOT = VmmWin_ObjectTypeGet((BYTE)pe->iType))) { + if((pOT = VmmWin_ObjectTypeGet(H, (BYTE)pe->iType))) { snprintf(szType, _countof(szType), "%s", pOT->usz); szType[16] = 0; } else { @@ -66,7 +66,8 @@ PVMM_MAP_HANDLEENTRY MHandle_HandleFromPath(_In_ LPSTR uszPath, _In_ PVMMOB_MAP_ /* * Read : function as specified by the module manager. The module manager will * call into this callback function whenever a read shall occur from a "file". -* -- ctx +* -- H +* -- ctxP * -- pb * -- cb * -- pcbRead @@ -74,21 +75,21 @@ PVMM_MAP_HANDLEENTRY MHandle_HandleFromPath(_In_ LPSTR uszPath, _In_ PVMMOB_MAP_ * -- return */ _Success_(return == 0) -NTSTATUS MHandle_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MHandle_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; PVMMOB_MAP_HANDLE pObHandleMap = NULL; PVMM_MAP_HANDLEENTRY pe; - if(VmmMap_GetHandle(ctx->pProcess, &pObHandleMap, TRUE)) { - if(!_stricmp(ctx->uszPath, "handles.txt")) { + if(VmmMap_GetHandle(H, ctxP->pProcess, &pObHandleMap, TRUE)) { + if(!_stricmp(ctxP->uszPath, "handles.txt")) { nt = Util_VfsLineFixed_Read( - (UTIL_VFSLINEFIXED_PFN_CB)MHandle_ReadLine_Callback, NULL, MHANDLE_LINELENGTH, MHANDLE_LINEHEADER, + H, (UTIL_VFSLINEFIXED_PFN_CB)MHandle_ReadLine_CB, NULL, MHANDLE_LINELENGTH, MHANDLE_LINEHEADER, pObHandleMap->pMap, pObHandleMap->cMap, sizeof(VMM_MAP_HANDLEENTRY), pb, cb, pcbRead, cbOffset ); } - if((pe = MHandle_HandleFromPath(ctx->uszPath, pObHandleMap))) { - nt = VmmWinObjDisplay_VfsRead(ctx->uszPath, pe->iType, pe->vaObject, pb, cb, pcbRead, cbOffset); + if((pe = MHandle_HandleFromPath(ctxP->uszPath, pObHandleMap))) { + nt = VmmWinObjDisplay_VfsRead(H, ctxP->uszPath, pe->iType, pe->vaObject, pb, cb, pcbRead, cbOffset); } } Ob_DECREF(pObHandleMap); @@ -99,37 +100,38 @@ NTSTATUS MHandle_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbR * List : function as specified by the module manager. The module manager will * call into this callback function whenever a list directory shall occur from * the given module. -* -- ctx +* -- H +* -- ctxP * -- pFileList * -- return */ -BOOL MHandle_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) +BOOL MHandle_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { DWORD i; CHAR usz[MAX_PATH]; PVMMWIN_OBJECT_TYPE ptp; PVMM_MAP_HANDLEENTRY pe; PVMMOB_MAP_HANDLE pObHandleMap = NULL; - if(!ctx->uszPath[0]) { - if(VmmMap_GetHandle(ctx->pProcess, &pObHandleMap, FALSE)) { - VMMDLL_VfsList_AddFile(pFileList, "handles.txt", UTIL_VFSLINEFIXED_LINECOUNT(pObHandleMap->cMap) * MHANDLE_LINELENGTH, NULL); + if(!ctxP->uszPath[0]) { + if(VmmMap_GetHandle(H, ctxP->pProcess, &pObHandleMap, FALSE)) { + VMMDLL_VfsList_AddFile(pFileList, "handles.txt", UTIL_VFSLINEFIXED_LINECOUNT(H, pObHandleMap->cMap) * MHANDLE_LINELENGTH, NULL); VMMDLL_VfsList_AddDirectory(pFileList, "by-id", NULL); } goto finish; } - if(!VmmMap_GetHandle(ctx->pProcess, &pObHandleMap, TRUE)) { return TRUE; } - if(!_stricmp(ctx->uszPath, "by-id")) { + if(!VmmMap_GetHandle(H, ctxP->pProcess, &pObHandleMap, TRUE)) { return TRUE; } + if(!_stricmp(ctxP->uszPath, "by-id")) { for(i = 0; i < pObHandleMap->cMap; i++) { pe = pObHandleMap->pMap + i; - if((ptp = VmmWin_ObjectTypeGet((BYTE)pe->iType)) && ptp->usz) { + if((ptp = VmmWin_ObjectTypeGet(H, (BYTE)pe->iType)) && ptp->usz) { _snprintf_s(usz, MAX_PATH, _TRUNCATE, "%05X-%s", pe->dwHandle, ptp->usz); VMMDLL_VfsList_AddDirectory(pFileList, usz, NULL); } } goto finish; } - if((pe = MHandle_HandleFromPath(ctx->uszPath, pObHandleMap))) { - VmmWinObjDisplay_VfsList(pe->iType, pe->vaObject, pFileList); + if((pe = MHandle_HandleFromPath(ctxP->uszPath, pObHandleMap))) { + VmmWinObjDisplay_VfsList(H, pe->iType, pe->vaObject, pFileList); goto finish; } finish: @@ -140,7 +142,7 @@ finish: /* * Forensic JSON log: */ -VOID MHandle_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) +VOID MHandle_FcLogJSON(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) { PVMM_PROCESS pProcess = ctxP->pProcess; PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd; @@ -153,11 +155,11 @@ VOID MHandle_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)( pd->dwVersion = VMMDLL_PLUGIN_FORENSIC_JSONDATA_VERSION; pd->dwPID = pProcess->dwPID; pd->szjType = "handle"; - if(VmmMap_GetHandle(ctxP->pProcess, &pObHandleMap, TRUE)) { + if(VmmMap_GetHandle(H, ctxP->pProcess, &pObHandleMap, TRUE)) { for(i = 0; i < pObHandleMap->cMap; i++) { pe = pObHandleMap->pMap + i; // get type: - if((pOT = VmmWin_ObjectTypeGet((BYTE)pe->iType))) { + if((pOT = VmmWin_ObjectTypeGet(H, (BYTE)pe->iType))) { snprintf(uszType, _countof(uszType), "%s", pOT->usz); } else { *(PDWORD)szTypePool = pe->dwPoolTag; @@ -171,7 +173,7 @@ VOID MHandle_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)( pd->qwHex[1] = pe->dwGrantedAccess; pd->usz[0] = uszType; pd->usz[1] = pe->uszText; - pfnLogJSON(pd); + pfnLogJSON(H, pd); } } Ob_DECREF(pObHandleMap); @@ -186,7 +188,7 @@ VOID MHandle_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)( * operating system or architecture is unsupported. * -- pPluginRegInfo */ -VOID M_ProcHandle_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_ProcHandle_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if(!((pRI->tpSystem == VMM_SYSTEM_WINDOWS_X64) || (pRI->tpSystem == VMM_SYSTEM_WINDOWS_X86))) { return; } @@ -196,5 +198,5 @@ VOID M_ProcHandle_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) pRI->reg_fn.pfnList = MHandle_List; // List function supported pRI->reg_fn.pfnRead = MHandle_Read; // Read function supported pRI->reg_fnfc.pfnLogJSON = MHandle_FcLogJSON; // JSON log function supported - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_proc_heap.c b/vmm/m_proc_heap.c index 7d29202..03ef355 100644 --- a/vmm/m_proc_heap.c +++ b/vmm/m_proc_heap.c @@ -40,7 +40,7 @@ typedef struct tdMHEAP_CTX { PVMM_PROCESS pProcess; } MHEAP_CTX, *PMHEAP_CTX; -VOID MHeap_HeapReadLineCB(_In_ PMHEAP_CTX ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_HEAPENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR szu8) +VOID MHeap_HeapReadLineCB(_In_ VMM_HANDLE H, _In_ PMHEAP_CTX ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_HEAPENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR szu8) { Util_usnprintf_ln(szu8, cbLineLength, "%04x%7i %4i %016llx %s%s", @@ -49,11 +49,11 @@ VOID MHeap_HeapReadLineCB(_In_ PMHEAP_CTX ctx, _In_ DWORD cbLineLength, _In_ DWO pe->iHeap, pe->va, VMM_HEAP_TP_STR[pe->tp], - (!ctxVmm->f32 && pe->f32) ? " (32)" : "" + (!H->vmm.f32 && pe->f32) ? " (32)" : "" ); } -VOID MHeap_SegmentReadLineCB(_In_ PMHEAP_CTX ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_HEAP_SEGMENTENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR szu8) +VOID MHeap_SegmentReadLineCB(_In_ VMM_HANDLE H, _In_ PMHEAP_CTX ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_HEAP_SEGMENTENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR szu8) { Util_usnprintf_ln(szu8, cbLineLength, "%04x%7i %4i %016llx %s", @@ -65,14 +65,14 @@ VOID MHeap_SegmentReadLineCB(_In_ PMHEAP_CTX ctx, _In_ DWORD cbLineLength, _In_ ); } -VOID MHeap_AllocReadLineCB(_In_ PMHEAP_CTX ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_HEAPALLOCENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR szu8) +VOID MHeap_AllocReadLineCB(_In_ VMM_HANDLE H, _In_ PMHEAP_CTX ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_HEAPALLOCENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR szu8) { BYTE pb16[16] = { 0 }; CHAR szHex[80] = { 0 }; DWORD cbHex; if(ctx->fVerbose) { cbHex = sizeof(szHex); - VmmRead(ctx->pProcess, pe->va, pb16, min(16, pe->cb)); + VmmRead(H, ctx->pProcess, pe->va, pb16, min(16, pe->cb)); Util_FillHexAscii(pb16, 16, 0, szHex, &cbHex); } Util_usnprintf_ln(szu8, cbLineLength, @@ -88,37 +88,38 @@ VOID MHeap_AllocReadLineCB(_In_ PMHEAP_CTX ctx, _In_ DWORD cbLineLength, _In_ DW } _Success_(return) -BOOL MHeap_GetAllocPath(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_ PVMMOB_MAP_HEAPALLOC *ppObHeapAllocMap, _Out_ LPSTR *pszPath) +BOOL MHeap_GetAllocPath(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_ PVMMOB_MAP_HEAPALLOC *ppObHeapAllocMap, _Out_ LPSTR *pszPath) { DWORD dwId = (DWORD)Util_GetNumericA(ctxP->uszPath); if(!dwId && (ctxP->uszPath[0] != '0')) return FALSE; *pszPath = CharUtil_PathSplitNext(ctxP->uszPath); - return VmmMap_GetHeapAlloc(ctxP->pProcess, dwId, ppObHeapAllocMap); + return VmmMap_GetHeapAlloc(H, ctxP->pProcess, dwId, ppObHeapAllocMap); } /* * Write : function as specified by the module manager. The module manager will * call into this callback function whenever a write shall occur from a "file". -* -- ctx +* -- H +* -- ctxP * -- pb * -- cb * -- pcbWrite * -- cbOffset * -- return */ -NTSTATUS MHeap_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) +NTSTATUS MHeap_Write(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) { QWORD va; LPSTR uszPath; PVMM_MAP_HEAPALLOCENTRY peA; PVMMOB_MAP_HEAPALLOC pObHeapAllocMap = NULL; *pcbWrite = 0; - if(!MHeap_GetAllocPath(ctxP, &pObHeapAllocMap, &uszPath)) { goto finish; } + if(!MHeap_GetAllocPath(H, ctxP, &pObHeapAllocMap, &uszPath)) { goto finish; } if(CharUtil_StrEndsWith(uszPath, ".mem", FALSE)) { uszPath = CharUtil_PathSplitLast(uszPath); va = Util_GetNumericA(uszPath); - if(va && (peA = VmmMap_GetHeapAllocEntry(pObHeapAllocMap, va))) { - VmmWriteAsFile(ctxP->pProcess, peA->va, peA->cb, pb, cb, pcbWrite, cbOffset); + if(va && (peA = VmmMap_GetHeapAllocEntry(H, pObHeapAllocMap, va))) { + VmmWriteAsFile(H, ctxP->pProcess, peA->va, peA->cb, pb, cb, pcbWrite, cbOffset); } goto finish; } @@ -129,7 +130,8 @@ finish: /* * Read : function as specified by the module manager. The module manager will * call into this callback function whenever a read shall occur from a "file". -* -- ctx +* -- H +* -- ctxP * -- pb * -- cb * -- pcbRead @@ -137,7 +139,7 @@ finish: * -- return */ _Success_(return == 0) -NTSTATUS MHeap_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MHeap_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; PVMMOB_MAP_HEAP pObHeapMap = NULL; @@ -146,7 +148,7 @@ NTSTATUS MHeap_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRe MHEAP_CTX ctx = { 0 }; LPSTR uszPath; QWORD va; - if(!VmmMap_GetHeap(ctxP->pProcess, &pObHeapMap)) { return VMMDLL_STATUS_FILE_INVALID; } + if(!VmmMap_GetHeap(H, ctxP->pProcess, &pObHeapMap)) { return VMMDLL_STATUS_FILE_INVALID; } ctx.pProcess = (PVMM_PROCESS)ctxP->pProcess; // module root - heap info files if(!_stricmp(ctxP->uszPath, "readme.txt")) { @@ -154,7 +156,7 @@ NTSTATUS MHeap_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRe } if(!_stricmp(ctxP->uszPath, "heaps.txt")) { nt = Util_VfsLineFixed_Read( - (UTIL_VFSLINEFIXED_PFN_CB)MHeap_HeapReadLineCB, &ctx, MHEAP_HEAP_LINELENGTH, MHEAP_HEAP_LINEHEADER, + H, (UTIL_VFSLINEFIXED_PFN_CB)MHeap_HeapReadLineCB, &ctx, MHEAP_HEAP_LINELENGTH, MHEAP_HEAP_LINEHEADER, pObHeapMap->pMap, pObHeapMap->cMap, sizeof(VMM_MAP_HEAPENTRY), pb, cb, pcbRead, cbOffset ); @@ -162,17 +164,17 @@ NTSTATUS MHeap_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRe } if(!_stricmp(ctxP->uszPath, "segments.txt")) { nt = Util_VfsLineFixed_Read( - (UTIL_VFSLINEFIXED_PFN_CB)MHeap_SegmentReadLineCB, &ctx, MHEAP_SEGMENT_LINELENGTH, MHEAP_SEGMENT_LINEHEADER, + H, (UTIL_VFSLINEFIXED_PFN_CB)MHeap_SegmentReadLineCB, &ctx, MHEAP_SEGMENT_LINELENGTH, MHEAP_SEGMENT_LINEHEADER, pObHeapMap->pSegments, pObHeapMap->cSegments, sizeof(VMM_MAP_HEAP_SEGMENTENTRY), pb, cb, pcbRead, cbOffset ); goto finish; } // specific heap - if(!MHeap_GetAllocPath(ctxP, &pObHeapAllocMap, &uszPath)) { goto finish; } + if(!MHeap_GetAllocPath(H, ctxP, &pObHeapAllocMap, &uszPath)) { goto finish; } if(!_stricmp(uszPath, "allocations.txt")) { nt = Util_VfsLineFixed_Read( - (UTIL_VFSLINEFIXED_PFN_CB)MHeap_AllocReadLineCB, &ctx, MHEAP_ALLOC_LINELENGTH, MHEAP_ALLOC_LINEHEADER, + H, (UTIL_VFSLINEFIXED_PFN_CB)MHeap_AllocReadLineCB, &ctx, MHEAP_ALLOC_LINELENGTH, MHEAP_ALLOC_LINEHEADER, pObHeapAllocMap->pMap, pObHeapAllocMap->cMap, sizeof(VMM_MAP_HEAPALLOCENTRY), pb, cb, pcbRead, cbOffset ); @@ -181,7 +183,7 @@ NTSTATUS MHeap_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRe if(!_stricmp(uszPath, "allocations-v.txt")) { ctx.fVerbose = TRUE; nt = Util_VfsLineFixed_Read( - (UTIL_VFSLINEFIXED_PFN_CB)MHeap_AllocReadLineCB, &ctx, MHEAP_ALLOCV_LINELENGTH, MHEAP_ALLOCV_LINEHEADER, + H, (UTIL_VFSLINEFIXED_PFN_CB)MHeap_AllocReadLineCB, &ctx, MHEAP_ALLOCV_LINELENGTH, MHEAP_ALLOCV_LINEHEADER, pObHeapAllocMap->pMap, pObHeapAllocMap->cMap, sizeof(VMM_MAP_HEAPALLOCENTRY), pb, cb, pcbRead, cbOffset ); @@ -190,8 +192,8 @@ NTSTATUS MHeap_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRe if(CharUtil_StrEndsWith(uszPath, ".mem", FALSE)) { uszPath = CharUtil_PathSplitLast(uszPath); va = Util_GetNumericA(uszPath); - if(va && (peA = VmmMap_GetHeapAllocEntry(pObHeapAllocMap, va))) { - nt = Util_VfsReadFile_FromMEM(ctxP->pProcess, va, peA->cb, 0, pb, cb, pcbRead, cbOffset); + if(va && (peA = VmmMap_GetHeapAllocEntry(H, pObHeapAllocMap, va))) { + nt = Util_VfsReadFile_FromMEM(H, ctxP->pProcess, va, peA->cb, 0, pb, cb, pcbRead, cbOffset); } goto finish; } @@ -204,11 +206,12 @@ finish: * List : function as specified by the module manager. The module manager will * call into this callback function whenever a list directory shall occur from * the given module. -* -- ctx +* -- H +* -- ctxP * -- pFileList * -- return */ -BOOL MHeap_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) +BOOL MHeap_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { PVMMOB_MAP_HEAP pObHeapMap = NULL; PVMMOB_MAP_HEAPALLOC pObHeapAllocMap = NULL; @@ -217,8 +220,8 @@ BOOL MHeap_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) CHAR szBuffer[32]; LPSTR uszPath; DWORD i, iBase; - LPSTR szFORMATMEM = ctxVmm->f32 ? "0x%08llx.mem" : "0x%012llx.mem"; - if(!VmmMap_GetHeap(ctxP->pProcess, &pObHeapMap)) { goto finish; } + LPSTR szFORMATMEM = H->vmm.f32 ? "0x%08llx.mem" : "0x%012llx.mem"; + if(!VmmMap_GetHeap(H, ctxP->pProcess, &pObHeapMap)) { goto finish; } // module root - list heap map if(!ctxP->uszPath[0]) { for(i = 0; i < pObHeapMap->cMap; i++) { @@ -227,19 +230,19 @@ BOOL MHeap_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) VMMDLL_VfsList_AddDirectory(pFileList, szBuffer, NULL); } VMMDLL_VfsList_AddFile(pFileList, "readme.txt", strlen(szMHEAP_README), NULL); - VMMDLL_VfsList_AddFile(pFileList, "heaps.txt", UTIL_VFSLINEFIXED_LINECOUNT(pObHeapMap->cMap) * MHEAP_HEAP_LINELENGTH, NULL); - VMMDLL_VfsList_AddFile(pFileList, "segments.txt", UTIL_VFSLINEFIXED_LINECOUNT(pObHeapMap->cSegments) * MHEAP_SEGMENT_LINELENGTH, NULL); + VMMDLL_VfsList_AddFile(pFileList, "heaps.txt", UTIL_VFSLINEFIXED_LINECOUNT(H, pObHeapMap->cMap) * MHEAP_HEAP_LINELENGTH, NULL); + VMMDLL_VfsList_AddFile(pFileList, "segments.txt", UTIL_VFSLINEFIXED_LINECOUNT(H, pObHeapMap->cSegments) * MHEAP_SEGMENT_LINELENGTH, NULL); goto finish; } // specific heap - if(!MHeap_GetAllocPath(ctxP, &pObHeapAllocMap, &uszPath)) { goto finish; } + if(!MHeap_GetAllocPath(H, ctxP, &pObHeapAllocMap, &uszPath)) { goto finish; } if(!uszPath[0]) { for(i = 0; i < pObHeapAllocMap->cMap; i += MHEAP_ALLOC_PER_DIR_MAX) { _snprintf_s(szBuffer, _countof(szBuffer), _TRUNCATE, "0x%x", i); VMMDLL_VfsList_AddDirectory(pFileList, szBuffer, NULL); } - VMMDLL_VfsList_AddFile(pFileList, "allocations.txt", UTIL_VFSLINEFIXED_LINECOUNT(pObHeapAllocMap->cMap) * MHEAP_ALLOC_LINELENGTH, NULL); - VMMDLL_VfsList_AddFile(pFileList, "allocations-v.txt", UTIL_VFSLINEFIXED_LINECOUNT(pObHeapAllocMap->cMap) * MHEAP_ALLOCV_LINELENGTH, NULL); + VMMDLL_VfsList_AddFile(pFileList, "allocations.txt", UTIL_VFSLINEFIXED_LINECOUNT(H, pObHeapAllocMap->cMap) * MHEAP_ALLOC_LINELENGTH, NULL); + VMMDLL_VfsList_AddFile(pFileList, "allocations-v.txt", UTIL_VFSLINEFIXED_LINECOUNT(H, pObHeapAllocMap->cMap) * MHEAP_ALLOCV_LINELENGTH, NULL); goto finish; } iBase = (DWORD)Util_GetNumericA(uszPath); @@ -264,7 +267,7 @@ finish: * operating system or architecture is unsupported. * -- pPluginRegInfo */ -VOID M_ProcHeap_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_ProcHeap_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if(!((pRI->tpSystem == VMM_SYSTEM_WINDOWS_X64) || (pRI->tpSystem == VMM_SYSTEM_WINDOWS_X86))) { return; } @@ -274,5 +277,5 @@ VOID M_ProcHeap_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) pRI->reg_fn.pfnList = MHeap_List; // List function supported pRI->reg_fn.pfnRead = MHeap_Read; // Read function supported pRI->reg_fn.pfnWrite = MHeap_Write; // Write function supported - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_proc_ldrmodules.c b/vmm/m_proc_ldrmodules.c index 431ccaa..39d4eb0 100644 --- a/vmm/m_proc_ldrmodules.c +++ b/vmm/m_proc_ldrmodules.c @@ -15,13 +15,17 @@ #define LDRMODULES_NUM_CACHE 8 #define LDRMODULES_LINELENGTH_X86 107ULL #define LDRMODULES_LINELENGTH_X64 123ULL +#define LDRMODULES_LINELENGTH_X86_VERB (LDRMODULES_LINELENGTH_X86+156ULL) +#define LDRMODULES_LINELENGTH_X64_VERB (LDRMODULES_LINELENGTH_X64+156ULL) #define LDRMODULES_LINELENGTH_DIRECTORIES 54ULL #define LDRMODULES_LINELENGTH_SECTIONS 70ULL #define LDRMODULES_LINELENGTH_EAT 78ULL #define LDRMODULES_LINELENGTH_IAT 128ULL -#define LDRMODULES_LINEHEADER_X86 " # PID Pages Range Start-End Description" -#define LDRMODULES_LINEHEADER_X64 " # PID Pages Range Start-End Description" +#define LDRMODULES_LINEHEADER_X86 " # PID Pages Range Start-End Description" +#define LDRMODULES_LINEHEADER_X64 " # PID Pages Range Start-End Description" +#define LDRMODULES_LINEHEADER_X86_VERB LDRMODULES_LINEHEADER_X86" #Imports #Exports #Sect Path KernelPath" +#define LDRMODULES_LINEHEADER_X64_VERB LDRMODULES_LINEHEADER_X64" #Imports #Exports #Sect Path KernelPath" #define LDRMODULES_MAX_IATEAT 0x10000 @@ -37,7 +41,7 @@ typedef struct tdOBLDRMODULES_CACHE_ENTRY { * Dynamically generate the file \\export.txt */ _Success_(return == 0) -NTSTATUS LdrModules_ReadFile_EAT(_In_ PVMM_PROCESS pProcess, _In_ PVMMOB_MAP_EAT pEatMap, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS LdrModules_ReadFile_EAT(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVMMOB_MAP_EAT pEatMap, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt; LPSTR sz; @@ -71,7 +75,7 @@ NTSTATUS LdrModules_ReadFile_EAT(_In_ PVMM_PROCESS pProcess, _In_ PVMMOB_MAP_EAT * Dynamically generate the file \\import.txt */ _Success_(return == 0) -NTSTATUS LdrModules_ReadFile_IAT(_In_ PVMM_PROCESS pProcess, _In_ PVMMOB_MAP_IAT pIatMap, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS LdrModules_ReadFile_IAT(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVMMOB_MAP_IAT pIatMap, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt; LPSTR sz; @@ -104,13 +108,13 @@ NTSTATUS LdrModules_ReadFile_IAT(_In_ PVMM_PROCESS pProcess, _In_ PVMMOB_MAP_IAT * Dynamically generate the file \\directories */ _Success_(return == 0) -NTSTATUS LdrModules_ReadFile_Directories(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _Out_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS LdrModules_ReadFile_Directories(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _Out_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt; LPSTR sz; QWORD i, o = 0, cbMax, cStart, cEnd, cbLINELENGTH; IMAGE_DATA_DIRECTORY Directory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; - if(!PE_DirectoryGetAll(pProcess, vaModuleBase, NULL, Directory)) { return VMMDLL_STATUS_FILE_INVALID; } + if(!PE_DirectoryGetAll(H, pProcess, vaModuleBase, NULL, Directory)) { return VMMDLL_STATUS_FILE_INVALID; } cbLINELENGTH = LDRMODULES_LINELENGTH_DIRECTORIES; cStart = (DWORD)(cbOffset / cbLINELENGTH); cEnd = (DWORD)min(16 - 1, (cb + cbOffset + cbLINELENGTH - 1) / cbLINELENGTH); @@ -138,14 +142,14 @@ NTSTATUS LdrModules_ReadFile_Directories(_In_ PVMM_PROCESS pProcess, _In_ QWORD * Dynamically generate the file \\sections */ _Success_(return == 0) -NTSTATUS LdrModules_ReadFile_Sections(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _Out_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS LdrModules_ReadFile_Sections(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _Out_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; LPSTR sz; QWORD i, o = 0, cbMax, cStart, cEnd, cbLINELENGTH; DWORD cSections; PIMAGE_SECTION_HEADER pSections = NULL; - cSections = PE_SectionGetNumberOf(pProcess, vaModuleBase); + cSections = PE_SectionGetNumberOf(H, pProcess, vaModuleBase); cbLINELENGTH = LDRMODULES_LINELENGTH_SECTIONS; cStart = (DWORD)(cbOffset / cbLINELENGTH); cEnd = (DWORD)min(cSections - 1, (cb + cbOffset + cbLINELENGTH - 1) / cbLINELENGTH); @@ -153,7 +157,7 @@ NTSTATUS LdrModules_ReadFile_Sections(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaM if(!cSections || (cStart > cSections)) { return VMMDLL_STATUS_END_OF_FILE; } if(!(sz = LocalAlloc(LMEM_ZEROINIT, (SIZE_T)cbMax))) { goto fail; } if(!(pSections = LocalAlloc(LMEM_ZEROINIT, cSections * sizeof(IMAGE_SECTION_HEADER)))) { goto fail; } - if(!PE_SectionGetAll(pProcess, vaModuleBase, cSections, pSections)) { goto fail; } + if(!PE_SectionGetAll(H, pProcess, vaModuleBase, cSections, pSections)) { goto fail; } for(i = cStart; i <= cEnd; i++) { o += Util_usnprintf_ln( sz + o, @@ -181,10 +185,10 @@ fail: /* * Dynamically generate the file \modules.txt. */ -VOID LdrModules_ModuleReadLine_Callback(_In_ PVMM_PROCESS pProcess, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_MODULEENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR usz) +VOID LdrModules_ModuleReadLineCB(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_MODULEENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR usz) { Util_usnprintf_ln(usz, cbLineLength, - ctxVmm->f32 ? "%04x%7i %8x %08x-%08x %s %s" : "%04x%7i %8x %016llx-%016llx %s %s", + H->vmm.f32 ? "%04x%7i %8x %08x-%08x %s %s" : "%04x%7i %8x %016llx-%016llx %s %s", ie, pProcess->dwPID, pe->cbImageSize >> 12, @@ -195,13 +199,42 @@ VOID LdrModules_ModuleReadLine_Callback(_In_ PVMM_PROCESS pProcess, _In_ DWORD c ); } +/* +* Dynamically generate the file \modules-v.txt. +*/ +VOID LdrModules_ModuleVerbReadLineCB(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_MODULEENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR usz) +{ + PVMM_MAP_VADENTRY peVad = NULL; + PVMMOB_MAP_VAD pObVadMap = NULL; + if(VmmMap_GetVad(H, pProcess, &pObVadMap, VMM_VADMAP_TP_FULL)) { + peVad = VmmMap_GetVadEntry(H, pObVadMap, pe->vaBase); + } + Util_usnprintf_ln(usz, cbLineLength, + H->vmm.f32 ? "%04x%7i %8x %08x-%08x %s %s" : "%04x%7i %8x %016llx-%016llx %s %-48s%8i%9i%6i %-72s%s", + ie, + pProcess->dwPID, + pe->cbImageSize >> 12, + pe->vaBase, + pe->vaBase + pe->cbImageSize - 1, + pe->fWoW64 ? "32" : " ", + pe->uszText + pe->cbuText - min(48, pe->cbuText), + pe->cIAT, + pe->cEAT, + pe->cSection, + pe->uszFullName + pe->cbuFullName - min(72, pe->cbuFullName), + (peVad && peVad->uszText) ? peVad->uszText : "" + ); + + Ob_DECREF(pObVadMap); +} + /* * Dynamically generate the file \unloaded_modules.txt. */ -VOID LdrModules_UnloadedReadLine_Callback(_In_ PVMM_PROCESS pProcess, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_UNLOADEDMODULEENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR usz) +VOID LdrModules_UnloadedReadLineCB(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_UNLOADEDMODULEENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR usz) { Util_usnprintf_ln(usz, cbLineLength, - ctxVmm->f32 ? "%04x%7i %8x %08x-%08x %s %s" : "%04x%7i %8x %016llx-%016llx %s %s", + H->vmm.f32 ? "%04x%7i %8x %08x-%08x %s %s" : "%04x%7i %8x %016llx-%016llx %s %s", ie, pProcess->dwPID, pe->cbImageSize >> 12, @@ -215,15 +248,15 @@ VOID LdrModules_UnloadedReadLine_Callback(_In_ PVMM_PROCESS pProcess, _In_ DWORD /* * Helper write function - Write to the requested data directory file. */ -VOID LdrModules_Write_DirectoriesD(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_MODULEENTRY pModule, _In_ LPSTR uszDirectory, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) +VOID LdrModules_Write_DirectoriesD(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_MODULEENTRY pModule, _In_ LPSTR uszDirectory, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) { DWORD i; IMAGE_DATA_DIRECTORY Directory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; *pcbWrite = 0; - if(PE_DirectoryGetAll(pProcess, pModule->vaBase, NULL, Directory)) { + if(PE_DirectoryGetAll(H, pProcess, pModule->vaBase, NULL, Directory)) { for(i = 0; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; i++) { if(!_strnicmp((LPSTR)PE_DATA_DIRECTORIES[i], uszDirectory, 0)) { - VmmWriteAsFile(pProcess, pModule->vaBase + Directory[i].VirtualAddress, Directory[i].Size, pb, cb, pcbWrite, cbOffset); + VmmWriteAsFile(H, pProcess, pModule->vaBase + Directory[i].VirtualAddress, Directory[i].Size, pb, cb, pcbWrite, cbOffset); } } } @@ -232,41 +265,42 @@ VOID LdrModules_Write_DirectoriesD(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_MOD /* * Helper write function - Write to the requested section header file. */ -VOID LdrModules_Write_SectionsD(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_MODULEENTRY pModule, _In_ LPSTR uszSection, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) +VOID LdrModules_Write_SectionsD(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_MODULEENTRY pModule, _In_ LPSTR uszSection, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) { IMAGE_SECTION_HEADER SectionHeader; - if(!PE_SectionGetFromName(pProcess, pModule->vaBase, uszSection, &SectionHeader)) { *pcbWrite = 0; return; } - VmmWriteAsFile(pProcess, pModule->vaBase + SectionHeader.VirtualAddress, SectionHeader.Misc.VirtualSize, pb, cb, pcbWrite, cbOffset); + if(!PE_SectionGetFromName(H, pProcess, pModule->vaBase, uszSection, &SectionHeader)) { *pcbWrite = 0; return; } + VmmWriteAsFile(H, pProcess, pModule->vaBase + SectionHeader.VirtualAddress, SectionHeader.Misc.VirtualSize, pb, cb, pcbWrite, cbOffset); } /* * Write : function as specified by the module manager. The module manager will * call into this callback function whenever a write shall occur from a "file". -* -- ctx +* -- H +* -- ctxP * -- pb * -- cb * -- pcbWrite * -- cbOffset * -- return */ -NTSTATUS LdrModules_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) +NTSTATUS LdrModules_Write(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) { PVMM_MAP_MODULEENTRY pModule = NULL; PVMMOB_MAP_MODULE pObModuleMap = NULL; CHAR uszModuleName[MAX_PATH]; LPSTR uszModuleSubPath; - PVMM_PROCESS pProcess = (PVMM_PROCESS)ctx->pProcess; + PVMM_PROCESS pProcess = (PVMM_PROCESS)ctxP->pProcess; *pcbWrite = 0; - uszModuleSubPath = CharUtil_PathSplitFirst(ctx->uszPath, uszModuleName, sizeof(uszModuleName)); - if(uszModuleName[0] && uszModuleSubPath[0] && VmmMap_GetModuleEntryEx((PVMM_PROCESS)ctx->pProcess, 0, uszModuleName, &pObModuleMap, &pModule)) { + uszModuleSubPath = CharUtil_PathSplitFirst(ctxP->uszPath, uszModuleName, sizeof(uszModuleName)); + if(uszModuleName[0] && uszModuleSubPath[0] && VmmMap_GetModuleEntryEx(H, (PVMM_PROCESS)ctxP->pProcess, 0, uszModuleName, &pObModuleMap, &pModule)) { if(!_stricmp(uszModuleSubPath, "pefile.dll")) { - PE_FileRaw_Write(pProcess, pModule->vaBase, pb, cb, pcbWrite, (DWORD)cbOffset); + PE_FileRaw_Write(H, pProcess, pModule->vaBase, pb, cb, pcbWrite, (DWORD)cbOffset); } if(!_strnicmp(uszModuleSubPath, "sectionsd\\", 10)) { - LdrModules_Write_SectionsD(pProcess, pModule, uszModuleSubPath + 10, pb, cb, pcbWrite, cbOffset); + LdrModules_Write_SectionsD(H, pProcess, pModule, uszModuleSubPath + 10, pb, cb, pcbWrite, cbOffset); } if(!_strnicmp(uszModuleSubPath, "directoriesd\\", 13)) { - LdrModules_Write_DirectoriesD(pProcess, pModule, uszModuleSubPath + 13, pb, cb, pcbWrite, cbOffset); + LdrModules_Write_DirectoriesD(H, pProcess, pModule, uszModuleSubPath + 13, pb, cb, pcbWrite, cbOffset); } } Ob_DECREF(pObModuleMap); @@ -276,14 +310,14 @@ NTSTATUS LdrModules_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_reads_(cb) PBYTE /* * Helper read function - Read the requested data directory file. */ -NTSTATUS LdrModules_Read_DirectoriesD(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_MODULEENTRY pModule, _In_ LPSTR uszDirectory, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS LdrModules_Read_DirectoriesD(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_MODULEENTRY pModule, _In_ LPSTR uszDirectory, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { DWORD i; IMAGE_DATA_DIRECTORY Directory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; - if(PE_DirectoryGetAll(pProcess, pModule->vaBase, NULL, Directory)) { + if(PE_DirectoryGetAll(H, pProcess, pModule->vaBase, NULL, Directory)) { for(i = 0; i < 16; i++) { if(!_stricmp(uszDirectory, PE_DATA_DIRECTORIES[i])) { - return VmmReadAsFile(pProcess, pModule->vaBase + Directory[i].VirtualAddress, Directory[i].Size, pb, cb, pcbRead, cbOffset); + return VmmReadAsFile(H, pProcess, pModule->vaBase + Directory[i].VirtualAddress, Directory[i].Size, pb, cb, pcbRead, cbOffset); } } } @@ -293,14 +327,14 @@ NTSTATUS LdrModules_Read_DirectoriesD(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_ /* * Helper read function - Read the requested section header file. */ -NTSTATUS LdrModules_Read_SectionsD(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_MODULEENTRY pModule, _In_ LPSTR uszSection, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS LdrModules_Read_SectionsD(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_MODULEENTRY pModule, _In_ LPSTR uszSection, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { IMAGE_SECTION_HEADER SectionHeader; - if(!PE_SectionGetFromName(pProcess, pModule->vaBase, uszSection, &SectionHeader)) { return VMMDLL_STATUS_FILE_INVALID; } - return VmmReadAsFile(pProcess, pModule->vaBase + SectionHeader.VirtualAddress, SectionHeader.Misc.VirtualSize, pb, cb, pcbRead, cbOffset); + if(!PE_SectionGetFromName(H, pProcess, pModule->vaBase, uszSection, &SectionHeader)) { return VMMDLL_STATUS_FILE_INVALID; } + return VmmReadAsFile(H, pProcess, pModule->vaBase + SectionHeader.VirtualAddress, SectionHeader.Misc.VirtualSize, pb, cb, pcbRead, cbOffset); } -NTSTATUS LdrModules_Read_ModuleSubFile(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ PVMM_MAP_MODULEENTRY pModule, _In_ LPSTR uszPath, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS LdrModules_Read_ModuleSubFile(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ PVMM_MAP_MODULEENTRY pModule, _In_ LPSTR uszPath, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; PVMMOB_MAP_EAT pObEatMap = NULL; @@ -320,33 +354,33 @@ NTSTATUS LdrModules_Read_ModuleSubFile(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ PVM return Util_VfsReadFile_FromDWORD(pModule->cbImageSize, pb, cb, pcbRead, cbOffset, FALSE); } if(!_stricmp(uszPath, "directories.txt")) { - return LdrModules_ReadFile_Directories(pProcess, pModule->vaBase, pb, cb, pcbRead, cbOffset); + return LdrModules_ReadFile_Directories(H, pProcess, pModule->vaBase, pb, cb, pcbRead, cbOffset); } if(!_stricmp(uszPath, "export.txt")) { - if(VmmMap_GetEAT(pProcess, pModule, &pObEatMap)) { - nt = LdrModules_ReadFile_EAT(pProcess, pObEatMap, pb, cb, pcbRead, cbOffset); + if(VmmMap_GetEAT(H, pProcess, pModule, &pObEatMap)) { + nt = LdrModules_ReadFile_EAT(H, pProcess, pObEatMap, pb, cb, pcbRead, cbOffset); Ob_DECREF(pObEatMap); } return nt; } if(!_stricmp(uszPath, "import.txt")) { - if(VmmMap_GetIAT(pProcess, pModule, &pObIatMap)) { - nt = LdrModules_ReadFile_IAT(pProcess, pObIatMap, pb, cb, pcbRead, cbOffset); + if(VmmMap_GetIAT(H, pProcess, pModule, &pObIatMap)) { + nt = LdrModules_ReadFile_IAT(H, pProcess, pObIatMap, pb, cb, pcbRead, cbOffset); Ob_DECREF(pObIatMap); } return nt; } if(!_stricmp(uszPath, "pefile.dll")) { - return PE_FileRaw_Read(pProcess, pModule->vaBase, pb, cb, pcbRead, (DWORD)cbOffset) ? VMMDLL_STATUS_SUCCESS : VMMDLL_STATUS_FILE_INVALID; + return PE_FileRaw_Read(H, pProcess, pModule->vaBase, pb, cb, pcbRead, (DWORD)cbOffset) ? VMMDLL_STATUS_SUCCESS : VMMDLL_STATUS_FILE_INVALID; } if(!_stricmp(uszPath, "sections.txt")) { - return LdrModules_ReadFile_Sections(pProcess, pModule->vaBase, pb, cb, pcbRead, cbOffset); + return LdrModules_ReadFile_Sections(H, pProcess, pModule->vaBase, pb, cb, pcbRead, cbOffset); } if(!_strnicmp(uszPath, "sectionsd\\", 10)) { - return LdrModules_Read_SectionsD(pProcess, pModule, uszPath + 10, pb, cb, pcbRead, cbOffset); + return LdrModules_Read_SectionsD(H, pProcess, pModule, uszPath + 10, pb, cb, pcbRead, cbOffset); } if(!_strnicmp(uszPath, "directoriesd\\", 13)) { - return LdrModules_Read_DirectoriesD(pProcess, pModule, uszPath + 13, pb, cb, pcbRead, cbOffset); + return LdrModules_Read_DirectoriesD(H, pProcess, pModule, uszPath + 13, pb, cb, pcbRead, cbOffset); } return VMMDLL_STATUS_FILE_INVALID; } @@ -354,14 +388,15 @@ NTSTATUS LdrModules_Read_ModuleSubFile(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ PVM /* * Read : function as specified by the module manager. The module manager will * call into this callback function whenever a read shall occur from a "file". -* -- ctx +* -- H +* -- ctxP * -- pb * -- cb * -- pcbRead * -- cbOffset * -- return */ -NTSTATUS LdrModules_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS LdrModules_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; CHAR uszModuleName[MAX_PATH]; @@ -369,12 +404,12 @@ NTSTATUS LdrModules_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *p PVMM_MAP_MODULEENTRY pModule = NULL; PVMMOB_MAP_MODULE pObModuleMap = NULL; PVMMOB_MAP_UNLOADEDMODULE pObUnloadedModuleMap = NULL; - if(!_stricmp(ctx->uszPath, "modules.txt")) { - if(VmmMap_GetModule((PVMM_PROCESS)ctx->pProcess, &pObModuleMap)) { + if(!_stricmp(ctxP->uszPath, "modules.txt")) { + if(VmmMap_GetModule(H, (PVMM_PROCESS)ctxP->pProcess, &pObModuleMap)) { nt = Util_VfsLineFixed_Read( - (UTIL_VFSLINEFIXED_PFN_CB)LdrModules_ModuleReadLine_Callback, ctx->pProcess, - (ctxVmm->f32 ? LDRMODULES_LINELENGTH_X86 : LDRMODULES_LINELENGTH_X64), - (ctxVmm->f32 ? LDRMODULES_LINEHEADER_X86 : LDRMODULES_LINEHEADER_X64), + H, (UTIL_VFSLINEFIXED_PFN_CB)LdrModules_ModuleReadLineCB, ctxP->pProcess, + (H->vmm.f32 ? LDRMODULES_LINELENGTH_X86 : LDRMODULES_LINELENGTH_X64), + (H->vmm.f32 ? LDRMODULES_LINEHEADER_X86 : LDRMODULES_LINEHEADER_X64), pObModuleMap->pMap, pObModuleMap->cMap, sizeof(VMM_MAP_MODULEENTRY), pb, cb, pcbRead, cbOffset ); @@ -382,12 +417,25 @@ NTSTATUS LdrModules_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *p } return nt; } - if(!_stricmp(ctx->uszPath, "unloaded_modules.txt")) { - if(VmmMap_GetUnloadedModule((PVMM_PROCESS)ctx->pProcess, &pObUnloadedModuleMap)) { + if(!_stricmp(ctxP->uszPath, "modules-v.txt")) { + if(VmmMap_GetModule(H, (PVMM_PROCESS)ctxP->pProcess, &pObModuleMap)) { nt = Util_VfsLineFixed_Read( - (UTIL_VFSLINEFIXED_PFN_CB)LdrModules_UnloadedReadLine_Callback, ctx->pProcess, - (ctxVmm->f32 ? LDRMODULES_LINELENGTH_X86 : LDRMODULES_LINELENGTH_X64), - (ctxVmm->f32 ? LDRMODULES_LINEHEADER_X86 : LDRMODULES_LINEHEADER_X64), + H, (UTIL_VFSLINEFIXED_PFN_CB)LdrModules_ModuleVerbReadLineCB, ctxP->pProcess, + (H->vmm.f32 ? LDRMODULES_LINELENGTH_X86_VERB : LDRMODULES_LINELENGTH_X64_VERB), + (H->vmm.f32 ? LDRMODULES_LINEHEADER_X86_VERB : LDRMODULES_LINEHEADER_X64_VERB), + pObModuleMap->pMap, pObModuleMap->cMap, sizeof(VMM_MAP_MODULEENTRY), + pb, cb, pcbRead, cbOffset + ); + Ob_DECREF(pObModuleMap); + } + return nt; + } + if(!_stricmp(ctxP->uszPath, "unloaded_modules.txt")) { + if(VmmMap_GetUnloadedModule(H, (PVMM_PROCESS)ctxP->pProcess, &pObUnloadedModuleMap)) { + nt = Util_VfsLineFixed_Read( + H, (UTIL_VFSLINEFIXED_PFN_CB)LdrModules_UnloadedReadLineCB, ctxP->pProcess, + (H->vmm.f32 ? LDRMODULES_LINELENGTH_X86 : LDRMODULES_LINELENGTH_X64), + (H->vmm.f32 ? LDRMODULES_LINEHEADER_X86 : LDRMODULES_LINEHEADER_X64), pObUnloadedModuleMap->pMap, pObUnloadedModuleMap->cMap, sizeof(VMM_MAP_UNLOADEDMODULEENTRY), pb, cb, pcbRead, cbOffset ); @@ -395,10 +443,10 @@ NTSTATUS LdrModules_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *p } return nt; } - uszModuleSubPath = CharUtil_PathSplitFirst(ctx->uszPath, uszModuleName, sizeof(uszModuleName)); + uszModuleSubPath = CharUtil_PathSplitFirst(ctxP->uszPath, uszModuleName, sizeof(uszModuleName)); *pcbRead = 0; - if(uszModuleName[0] && uszModuleSubPath[0] && VmmMap_GetModuleEntryEx((PVMM_PROCESS)ctx->pProcess, 0, uszModuleName, &pObModuleMap, &pModule)) { - nt = LdrModules_Read_ModuleSubFile(ctx, pModule, uszModuleSubPath, pb, cb, pcbRead, cbOffset); + if(uszModuleName[0] && uszModuleSubPath[0] && VmmMap_GetModuleEntryEx(H, (PVMM_PROCESS)ctxP->pProcess, 0, uszModuleName, &pObModuleMap, &pModule)) { + nt = LdrModules_Read_ModuleSubFile(H, ctxP, pModule, uszModuleSubPath, pb, cb, pcbRead, cbOffset); Ob_DECREF(pObModuleMap); return nt; } @@ -410,13 +458,14 @@ NTSTATUS LdrModules_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *p * List : function as specified by the module manager. The module manager will * call into this callback function whenever a list directory shall occur from * the given module. -* -- ctx +* -- H +* -- ctxP * -- pFileList * -- return */ -BOOL LdrModules_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) +BOOL LdrModules_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { - DWORD c, i, cbLine; + DWORD c, i, cbLine, cbLineV; CHAR szSectionName[9] = { 0 }; CHAR uszPath1[MAX_PATH]; LPSTR uszPath2; @@ -425,24 +474,26 @@ BOOL LdrModules_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) PIMAGE_SECTION_HEADER pSections = NULL; IMAGE_DATA_DIRECTORY pDataDirectories[16]; PVMMOB_MAP_UNLOADEDMODULE pObUnloadedModuleMap = NULL; - PVMM_PROCESS pProcess = (PVMM_PROCESS)ctx->pProcess; - if(!VmmMap_GetModule(pProcess, &pObModuleMap)) { goto fail; } + PVMM_PROCESS pProcess = (PVMM_PROCESS)ctxP->pProcess; + if(!VmmMap_GetModule(H, pProcess, &pObModuleMap)) { goto fail; } // modules root directory -> add directory per DLL - if(!ctx->uszPath[0]) { + if(!ctxP->uszPath[0]) { for(i = 0; i < pObModuleMap->cMap; i++) { VMMDLL_VfsList_AddDirectory(pFileList, pObModuleMap->pMap[i].uszText, NULL); } - cbLine = ctxVmm->f32 ? LDRMODULES_LINELENGTH_X86 : LDRMODULES_LINELENGTH_X64; - VMMDLL_VfsList_AddFile(pFileList, "modules.txt", UTIL_VFSLINEFIXED_LINECOUNT(pObModuleMap->cMap) * cbLine, NULL); - if(VmmMap_GetUnloadedModule(pProcess, &pObUnloadedModuleMap)) { - VMMDLL_VfsList_AddFile(pFileList, "unloaded_modules.txt", UTIL_VFSLINEFIXED_LINECOUNT(pObUnloadedModuleMap->cMap) * cbLine, NULL); + cbLine = H->vmm.f32 ? LDRMODULES_LINELENGTH_X86 : LDRMODULES_LINELENGTH_X64; + cbLineV = H->vmm.f32 ? LDRMODULES_LINELENGTH_X86_VERB : LDRMODULES_LINELENGTH_X64_VERB; + VMMDLL_VfsList_AddFile(pFileList, "modules.txt", UTIL_VFSLINEFIXED_LINECOUNT(H, pObModuleMap->cMap) * cbLine, NULL); + VMMDLL_VfsList_AddFile(pFileList, "modules-v.txt", UTIL_VFSLINEFIXED_LINECOUNT(H, pObModuleMap->cMap) * cbLineV, NULL); + if(VmmMap_GetUnloadedModule(H, pProcess, &pObUnloadedModuleMap)) { + VMMDLL_VfsList_AddFile(pFileList, "unloaded_modules.txt", UTIL_VFSLINEFIXED_LINECOUNT(H, pObUnloadedModuleMap->cMap) * cbLine, NULL); Ob_DECREF_NULL(&pObUnloadedModuleMap); } goto success; } // individual module directory -> list files - uszPath2 = CharUtil_PathSplitFirst(ctx->uszPath, uszPath1, sizeof(uszPath1)); - if(!(pModule = VmmMap_GetModuleEntry(pObModuleMap, uszPath1))) { goto fail; } + uszPath2 = CharUtil_PathSplitFirst(ctxP->uszPath, uszPath1, sizeof(uszPath1)); + if(!(pModule = VmmMap_GetModuleEntry(H, pObModuleMap, uszPath1))) { goto fail; } // module-specific 'root' directory if(!uszPath2[0]) { VMMDLL_VfsList_AddFile(pFileList, "base.txt", 16, NULL); @@ -460,9 +511,9 @@ BOOL LdrModules_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) } // module-specific 'sectiond' directory if(uszPath2[0] && !_stricmp(uszPath2, "sectionsd")) { - c = PE_SectionGetNumberOf(pProcess, pModule->vaBase); + c = PE_SectionGetNumberOf(H, pProcess, pModule->vaBase); if(!(pSections = LocalAlloc(0, c * sizeof(IMAGE_SECTION_HEADER)))) { goto fail; } - if(!PE_SectionGetAll(pProcess, pModule->vaBase, c, pSections)) { goto fail; } + if(!PE_SectionGetAll(H, pProcess, pModule->vaBase, c, pSections)) { goto fail; } for(i = 0; i < c; i++) { if(pSections[i].Name[0]) { memcpy(szSectionName, pSections[i].Name, 8); @@ -477,7 +528,7 @@ BOOL LdrModules_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) // module-specific 'directoriesd' directory if(uszPath2[0] && !_stricmp(uszPath2, "directoriesd")) { ZeroMemory(pDataDirectories, IMAGE_NUMBEROF_DIRECTORY_ENTRIES * sizeof(IMAGE_DATA_DIRECTORY)); - if(PE_DirectoryGetAll(pProcess, pModule->vaBase, NULL, pDataDirectories)) { + if(PE_DirectoryGetAll(H, pProcess, pModule->vaBase, NULL, pDataDirectories)) { for(i = 0; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; i++) { VMMDLL_VfsList_AddFile(pFileList, (LPSTR)PE_DATA_DIRECTORIES[i], pDataDirectories[i].Size, NULL); } @@ -498,9 +549,10 @@ success: * shall call the supplied pfnPluginManager_Register function. * NB! the module does not have to register itself - for example if the target * operating system or architecture is unsupported. -* -- pPluginRegInfo +* -- H +* -- pRI */ -VOID M_ProcLdrModules_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_ProcLdrModules_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if((pRI->tpSystem != VMM_SYSTEM_WINDOWS_X64) && (pRI->tpSystem != VMM_SYSTEM_WINDOWS_X86)) { return; } @@ -508,8 +560,8 @@ VOID M_ProcLdrModules_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) pRI->reg_info.fProcessModule = TRUE; // module shows in process directory pRI->reg_fn.pfnList = LdrModules_List; // List function supported pRI->reg_fn.pfnRead = LdrModules_Read; // Read function supported - if(ctxMain->dev.fWritable) { + if(H->dev.fWritable) { pRI->reg_fn.pfnWrite = LdrModules_Write; // Write function supported } - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_proc_memmap.c b/vmm/m_proc_memmap.c index 6a21b48..4aa6442 100644 --- a/vmm/m_proc_memmap.c +++ b/vmm/m_proc_memmap.c @@ -21,12 +21,12 @@ #define MEMMAP_VAD_LINEHEADER_X86 " # PID ObjAddr Pages Commit Range Start-End Type FLAGS Description" #define MEMMAP_VAD_LINEHEADER_X64 " # PID Object Address Pages Commit Range Start-End Type FLAGS Description" -VOID MemMap_VadReadLine_Callback(_In_ PVMM_PROCESS pProcess, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_VADENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR usz) +VOID MemMap_VadReadLineCB(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_VADENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR usz) { CHAR szProtection[7] = { 0 }; MmVad_StrProtectionFlags(pe, szProtection); Util_usnprintf_ln(usz, cbLineLength, - (ctxVmm->f32 ? "%04x%7i %08x %8x %8x %i %08x-%08x %s %s %s" : "%04x%7i %016llx %8x %8x %i %016llx-%016llx %s %s %s"), + (H->vmm.f32 ? "%04x%7i %08x %8x %8x %i %08x-%08x %s %s %s" : "%04x%7i %016llx %8x %8x %i %016llx-%016llx %s %s %s"), ie, pProcess->dwPID, pe->vaVad, @@ -42,7 +42,7 @@ VOID MemMap_VadReadLine_Callback(_In_ PVMM_PROCESS pProcess, _In_ DWORD cbLineLe } _Success_(return == 0) -NTSTATUS MemMap_Read_VadExMap2(_In_ PVMM_PROCESS pProcess, _In_ DWORD oVadExPages, _In_ DWORD cVadExPagesMax, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MemMap_Read_VadExMap2(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ DWORD oVadExPages, _In_ DWORD cVadExPagesMax, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt; LPSTR sz; @@ -56,7 +56,7 @@ NTSTATUS MemMap_Read_VadExMap2(_In_ PVMM_PROCESS pProcess, _In_ DWORD oVadExPage cbLINELENGTH = MEMMAP_VADEX_LINELENGTH; iPage = (DWORD)(cbOffset / cbLINELENGTH) + oVadExPages; cPage = (DWORD)min((cb + cbOffset + cbLINELENGTH - 1) / cbLINELENGTH, cVadExPagesMax - (iPage - oVadExPages)); - if(!VmmMap_GetVadEx(pProcess, &pObMap, VMM_VADMAP_TP_FULL, iPage, cPage)) { return VMMDLL_STATUS_FILE_INVALID; } + if(!VmmMap_GetVadEx(H, pProcess, &pObMap, VMM_VADMAP_TP_FULL, iPage, cPage)) { return VMMDLL_STATUS_FILE_INVALID; } cPage = pObMap->cMap; cbMax = 1 + pObMap->cMap * cbLINELENGTH; if(!(sz = LocalAlloc(LMEM_ZEROINIT, (SIZE_T)cbMax))) { Ob_DECREF(pObMap); return VMMDLL_STATUS_FILE_INVALID; } @@ -102,20 +102,20 @@ int MemMap_Read_VadExMap_CmpFind(_In_ QWORD vaBase, _In_ QWORD qwEntry) } _Success_(return == 0) -NTSTATUS MemMap_Read_VadExMap(_In_ PVMM_PROCESS pProcess, _In_ LPSTR uszFile, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MemMap_Read_VadExMap(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ LPSTR uszFile, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; QWORD vaVad; PVMM_MAP_VADENTRY peVad; PVMMOB_MAP_VAD pObVadMap = NULL; if(!_stricmp(uszFile, "_vad-v.txt")) { - return MemMap_Read_VadExMap2(pProcess, 0, 0xffffffff, pb, cb, pcbRead, cbOffset); + return MemMap_Read_VadExMap2(H, pProcess, 0, 0xffffffff, pb, cb, pcbRead, cbOffset); } - if(uszFile[0] == '0' && uszFile[1] == 'x' && VmmMap_GetVad(pProcess, &pObVadMap, VMM_VADMAP_TP_CORE)) { + if(uszFile[0] == '0' && uszFile[1] == 'x' && VmmMap_GetVad(H, pProcess, &pObVadMap, VMM_VADMAP_TP_CORE)) { vaVad = Util_GetNumericA(uszFile); peVad = Util_qfind(vaVad, pObVadMap->cMap, pObVadMap->pMap, sizeof(VMM_MAP_VADENTRY), MemMap_Read_VadExMap_CmpFind); if(peVad) { - nt = MemMap_Read_VadExMap2(pProcess, peVad->cVadExPagesBase, peVad->cVadExPages, pb, cb, pcbRead, cbOffset); + nt = MemMap_Read_VadExMap2(H, pProcess, peVad->cVadExPagesBase, peVad->cVadExPages, pb, cb, pcbRead, cbOffset); } Ob_DECREF_NULL(&pObVadMap); return nt; @@ -123,10 +123,10 @@ NTSTATUS MemMap_Read_VadExMap(_In_ PVMM_PROCESS pProcess, _In_ LPSTR uszFile, _O return nt; } -VOID MemMap_PteReadLine_Callback(_In_ PVMM_PROCESS pProcess, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_PTEENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR szu8) +VOID MemMap_PteReadLine_Callback(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_PTEENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR szu8) { Util_usnprintf_ln(szu8, cbLineLength, - ctxVmm->f32 ? "%04x%7i %8x %08x-%08x %cr%c%c%s%s" : "%04x%7i %8x %016llx-%016llx %cr%c%c%s%s", + H->vmm.f32 ? "%04x%7i %8x %08x-%08x %cr%c%c%s%s" : "%04x%7i %8x %016llx-%016llx %cr%c%c%s%s", ie, pProcess->dwPID, (DWORD)pe->cPages, @@ -143,7 +143,8 @@ VOID MemMap_PteReadLine_Callback(_In_ PVMM_PROCESS pProcess, _In_ DWORD cbLineLe /* * Read : function as specified by the module manager. The module manager will * call into this callback function whenever a read shall occur from a "file". -* -- ctx +* -- H +* -- ctxP * -- pb * -- cb * -- pcbRead @@ -151,43 +152,44 @@ VOID MemMap_PteReadLine_Callback(_In_ PVMM_PROCESS pProcess, _In_ DWORD cbLineLe * -- return */ _Success_(return == 0) -NTSTATUS MemMap_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MemMap_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { + BOOL f32 = H->vmm.f32; NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; LPSTR uszFile; CHAR uszPath1[MAX_PATH]; - PVMMOB_MAP_PTE pObMemMapPte = NULL; - PVMMOB_MAP_VAD pObMemMapVad = NULL; + PVMMOB_MAP_PTE pObPteMap = NULL; + PVMMOB_MAP_VAD pObVadMap = NULL; // read page table memory map. - if(!_stricmp(ctx->uszPath, "pte.txt")) { - if(VmmMap_GetPte(ctx->pProcess, &pObMemMapPte, TRUE)) { + if(!_stricmp(ctxP->uszPath, "pte.txt")) { + if(VmmMap_GetPte(H, ctxP->pProcess, &pObPteMap, TRUE)) { nt = Util_VfsLineFixed_Read( - (UTIL_VFSLINEFIXED_PFN_CB)MemMap_PteReadLine_Callback, ctx->pProcess, - (ctxVmm->f32 ? MEMMAP_PTE_LINELENGTH_X86 : MEMMAP_PTE_LINELENGTH_X64), - (ctxVmm->f32 ? MEMMAP_PTE_LINEHEADER_X86 : MEMMAP_PTE_LINEHEADER_X64), - pObMemMapPte->pMap, pObMemMapPte->cMap, sizeof(VMM_MAP_PTEENTRY), + H, (UTIL_VFSLINEFIXED_PFN_CB)MemMap_PteReadLine_Callback, ctxP->pProcess, + (f32 ? MEMMAP_PTE_LINELENGTH_X86 : MEMMAP_PTE_LINELENGTH_X64), + (f32 ? MEMMAP_PTE_LINEHEADER_X86 : MEMMAP_PTE_LINEHEADER_X64), + pObPteMap->pMap, pObPteMap->cMap, sizeof(VMM_MAP_PTEENTRY), pb, cb, pcbRead, cbOffset ); - Ob_DECREF(pObMemMapPte); + Ob_DECREF_NULL(&pObPteMap); } return nt; } - if(!_stricmp(ctx->uszPath, "vad.txt")) { - if(VmmMap_GetVad(ctx->pProcess, &pObMemMapVad, VMM_VADMAP_TP_FULL)) { + if(!_stricmp(ctxP->uszPath, "vad.txt")) { + if(VmmMap_GetVad(H, ctxP->pProcess, &pObVadMap, VMM_VADMAP_TP_FULL)) { nt = Util_VfsLineFixed_Read( - (UTIL_VFSLINEFIXED_PFN_CB)MemMap_VadReadLine_Callback, ctx->pProcess, - (ctxVmm->f32 ? MEMMAP_VAD_LINELENGTH_X86 : MEMMAP_VAD_LINELENGTH_X64), - (ctxVmm->f32 ? MEMMAP_VAD_LINEHEADER_X86 : MEMMAP_VAD_LINEHEADER_X64), - pObMemMapVad->pMap, pObMemMapVad->cMap, sizeof(VMM_MAP_VADENTRY), + H, (UTIL_VFSLINEFIXED_PFN_CB)MemMap_VadReadLineCB, ctxP->pProcess, + (f32 ? MEMMAP_VAD_LINELENGTH_X86 : MEMMAP_VAD_LINELENGTH_X64), + (f32 ? MEMMAP_VAD_LINEHEADER_X86 : MEMMAP_VAD_LINEHEADER_X64), + pObVadMap->pMap, pObVadMap->cMap, sizeof(VMM_MAP_VADENTRY), pb, cb, pcbRead, cbOffset ); - Ob_DECREF(pObMemMapVad); + Ob_DECREF(pObVadMap); } return nt; } - uszFile = CharUtil_PathSplitFirst(ctx->uszPath, uszPath1, sizeof(uszPath1)); + uszFile = CharUtil_PathSplitFirst(ctxP->uszPath, uszPath1, sizeof(uszPath1)); if(!_stricmp(uszPath1, "vad-v") && uszFile[0]) { - return MemMap_Read_VadExMap(ctx->pProcess, uszFile, pb, cb, pcbRead, cbOffset); + return MemMap_Read_VadExMap(H, ctxP->pProcess, uszFile, pb, cb, pcbRead, cbOffset); } return nt; @@ -197,42 +199,44 @@ NTSTATUS MemMap_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbRe * List : function as specified by the module manager. The module manager will * call into this callback function whenever a list directory shall occur from * the given module. -* -- ctx +* -- H +* -- ctxP * -- pFileList * -- return */ -BOOL MemMap_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) +BOOL MemMap_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { + BOOL f32 = H->vmm.f32; DWORD iVad, cbLine; LPSTR uszFile; CHAR uszPath1[MAX_PATH]; PVMMOB_MAP_PTE pObPteMap = NULL; PVMMOB_MAP_VAD pObVadMap = NULL; - if(!ctx->uszPath[0]) { + if(!ctxP->uszPath[0]) { // list page table memory map. - if(VmmMap_GetPte(ctx->pProcess, &pObPteMap, FALSE)) { - cbLine = ctxVmm->f32 ? MEMMAP_PTE_LINELENGTH_X86 : MEMMAP_PTE_LINELENGTH_X64; - VMMDLL_VfsList_AddFile(pFileList, "pte.txt", UTIL_VFSLINEFIXED_LINECOUNT(pObPteMap->cMap) * cbLine, NULL); + if(VmmMap_GetPte(H, ctxP->pProcess, &pObPteMap, FALSE)) { + cbLine = f32 ? MEMMAP_PTE_LINELENGTH_X86 : MEMMAP_PTE_LINELENGTH_X64; + VMMDLL_VfsList_AddFile(pFileList, "pte.txt", UTIL_VFSLINEFIXED_LINECOUNT(H, pObPteMap->cMap) * cbLine, NULL); Ob_DECREF_NULL(&pObPteMap); } // list vad & and extended vad map directory VMMDLL_VfsList_AddDirectory(pFileList, "vad-v", NULL); - if(VmmMap_GetVad(ctx->pProcess, &pObVadMap, VMM_VADMAP_TP_CORE)) { - cbLine = ctxVmm->f32 ? MEMMAP_VAD_LINELENGTH_X86 : MEMMAP_VAD_LINELENGTH_X64; - VMMDLL_VfsList_AddFile(pFileList, "vad.txt", UTIL_VFSLINEFIXED_LINECOUNT(pObVadMap->cMap) * cbLine, NULL); + if(VmmMap_GetVad(H, ctxP->pProcess, &pObVadMap, VMM_VADMAP_TP_CORE)) { + cbLine = f32 ? MEMMAP_VAD_LINELENGTH_X86 : MEMMAP_VAD_LINELENGTH_X64; + VMMDLL_VfsList_AddFile(pFileList, "vad.txt", UTIL_VFSLINEFIXED_LINECOUNT(H, pObVadMap->cMap) * cbLine, NULL); Ob_DECREF_NULL(&pObVadMap); } return TRUE; } - uszFile = CharUtil_PathSplitFirst(ctx->uszPath, uszPath1, sizeof(uszPath1)); + uszFile = CharUtil_PathSplitFirst(ctxP->uszPath, uszPath1, sizeof(uszPath1)); if(!_stricmp(uszPath1, "vad-v") && !uszFile[0]) { - if(VmmMap_GetVad(ctx->pProcess, &pObVadMap, VMM_VADMAP_TP_FULL)) { + if(VmmMap_GetVad(H, ctxP->pProcess, &pObVadMap, VMM_VADMAP_TP_FULL)) { VMMDLL_VfsList_AddFile(pFileList, "_vad-v.txt", pObVadMap->cPage * MEMMAP_VADEX_LINELENGTH, NULL); for(iVad = 0; iVad < pObVadMap->cMap; iVad++) { sprintf_s( uszPath1, _countof(uszPath1) - 1, - ctxVmm->f32 ? "0x%08llx%s%s.txt" : "0x%016llx%s%s.txt", + f32 ? "0x%08llx%s%s.txt" : "0x%016llx%s%s.txt", pObVadMap->pMap[iVad].vaStart, (pObVadMap->pMap[iVad].uszText && pObVadMap->pMap[iVad].uszText[0]) ? "-" : "", pObVadMap->pMap[iVad].uszText ? CharUtil_PathSplitLast(pObVadMap->pMap[iVad].uszText) : "" @@ -248,7 +252,7 @@ BOOL MemMap_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) /* * Forensic JSON log: */ -VOID MemMap_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) +VOID MemMap_FcLogJSON(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) { PVMM_PROCESS pProcess = ctxP->pProcess; PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd; @@ -265,7 +269,7 @@ VOID MemMap_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_ // 1: PTEs pd->fHex[0] = TRUE; usz[1] = 'r'; usz[6] = ' '; - if(VmmMap_GetPte(pProcess, &pObPteMap, TRUE)) { + if(VmmMap_GetPte(H, pProcess, &pObPteMap, TRUE)) { for(i = 0; i < pObPteMap->cMap; i++) { pep = pObPteMap->pMap + i; usz[0] = pep->fPage & VMM_MEMMAP_PAGE_NS ? '-' : 's'; @@ -278,13 +282,13 @@ VOID MemMap_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_ pd->va[1] = pep->vaBase + (pep->cPages << 12) - 1; pd->usz[0] = usz; pd->usz[1] = pep->uszText; - pfnLogJSON(pd); + pfnLogJSON(H, pd); } } // 2: VADs pd->szjType = "vad"; pd->fHex[1] = TRUE; - if(VmmMap_GetVad(pProcess, &pObVadMap, VMM_VADMAP_TP_FULL)) { + if(VmmMap_GetVad(H, pProcess, &pObVadMap, VMM_VADMAP_TP_FULL)) { for(i = 0; i < pObVadMap->cMap; i++) { pev = pObVadMap->pMap + i; MmVad_StrProtectionFlags(pev, usz); @@ -298,7 +302,7 @@ VOID MemMap_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_ pd->va[1] = pev->vaEnd; pd->usz[0] = (LPSTR)MmVad_StrType(pev); pd->usz[1] = usz; - pfnLogJSON(pd); + pfnLogJSON(H, pd); } } Ob_DECREF(pObVadMap); @@ -314,7 +318,7 @@ VOID MemMap_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_ * operating system or architecture is unsupported. * -- pPluginRegInfo */ -VOID M_ProcMemMap_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_ProcMemMap_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if(!((pRI->tpMemoryModel == VMM_MEMORYMODEL_X64) || (pRI->tpMemoryModel == VMM_MEMORYMODEL_X86) || (pRI->tpMemoryModel == VMM_MEMORYMODEL_X86PAE))) { return; } @@ -324,5 +328,5 @@ VOID M_ProcMemMap_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) pRI->reg_fn.pfnList = MemMap_List; // List function supported pRI->reg_fn.pfnRead = MemMap_Read; // Read function supported pRI->reg_fnfc.pfnLogJSON = MemMap_FcLogJSON; // JSON log function supported - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_proc_minidump.c b/vmm/m_proc_minidump.c index 660f17b..9887963 100644 --- a/vmm/m_proc_minidump.c +++ b/vmm/m_proc_minidump.c @@ -455,11 +455,11 @@ DWORD M_MiniDump_Initialize_AddText(_Inout_ POB_M_MINIDUMP_CONTEXT ctx, _In_ LPS return rva; } -VOID M_MiniDump_Initialize_ThreadList_CpuContext32(_In_ PVMM_PROCESS pSystemProcess, _Inout_ POB_M_MINIDUMP_CONTEXT mdCtx, _In_ PVMM_MAP_THREADENTRY peT, _Inout_ PMINIDUMP_THREAD pmdT) +VOID M_MiniDump_Initialize_ThreadList_CpuContext32(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _Inout_ POB_M_MINIDUMP_CONTEXT mdCtx, _In_ PVMM_MAP_THREADENTRY peT, _Inout_ PMINIDUMP_THREAD pmdT) { CPU_CONTEXT32 ctx = { 0 }; CPU_KTRAP_FRAME32 trap = { 0 }; - VmmReadEx(pSystemProcess, peT->vaTrapFrame, (PBYTE)&trap, sizeof(CPU_KTRAP_FRAME32), NULL, VMM_FLAG_ZEROPAD_ON_FAIL); + VmmReadEx(H, pSystemProcess, peT->vaTrapFrame, (PBYTE)&trap, sizeof(CPU_KTRAP_FRAME32), NULL, VMM_FLAG_ZEROPAD_ON_FAIL); ctx.Dr0 = trap.Dr0; ctx.Dr1 = trap.Dr1; ctx.Dr2 = trap.Dr2; @@ -486,11 +486,11 @@ VOID M_MiniDump_Initialize_ThreadList_CpuContext32(_In_ PVMM_PROCESS pSystemProc pmdT->ThreadContext.Rva = M_MiniDump_Initialize_AddBinary(mdCtx, (PBYTE)&ctx, sizeof(CPU_CONTEXT32)); } -VOID M_MiniDump_Initialize_ThreadList_CpuContext64(_In_ PVMM_PROCESS pSystemProcess, _Inout_ POB_M_MINIDUMP_CONTEXT mdCtx, _In_ PVMM_MAP_THREADENTRY peT, _Inout_ PMINIDUMP_THREAD pmdT) +VOID M_MiniDump_Initialize_ThreadList_CpuContext64(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _Inout_ POB_M_MINIDUMP_CONTEXT mdCtx, _In_ PVMM_MAP_THREADENTRY peT, _Inout_ PMINIDUMP_THREAD pmdT) { CPU_CONTEXT64 ctx = { 0 }; CPU_KTRAP_FRAME64 trap = { 0 }; - VmmReadEx(pSystemProcess, peT->vaTrapFrame, (PBYTE)&trap, sizeof(CPU_KTRAP_FRAME64), NULL, VMM_FLAG_ZEROPAD_ON_FAIL); + VmmReadEx(H, pSystemProcess, peT->vaTrapFrame, (PBYTE)&trap, sizeof(CPU_KTRAP_FRAME64), NULL, VMM_FLAG_ZEROPAD_ON_FAIL); ctx.P1Home = trap.P1Home; ctx.P2Home = trap.P2Home; ctx.P3Home = trap.P3Home; @@ -541,12 +541,13 @@ VOID M_MiniDump_CallbackCleanup_ObMiniDumpContext(POB_M_MINIDUMP_CONTEXT pOb) /* * Create a new minidump context for the given process. * CALLER DECREF: return +* -- H * -- pProcess * -- return */ -POB_M_MINIDUMP_CONTEXT M_MiniDump_Initialize_Internal(_In_ PVMM_PROCESS pProcess) +POB_M_MINIDUMP_CONTEXT M_MiniDump_Initialize_Internal(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess) { - BOOL f, f32 = ctxVmm->f32; + BOOL f, f32 = H->vmm.f32; DWORD i, j, iPte, iVad, iMR, dwCpuMhz, cThreadActive = 0; QWORD qw, vaDiff; PBYTE pbOld = NULL; @@ -572,16 +573,16 @@ POB_M_MINIDUMP_CONTEXT M_MiniDump_Initialize_Internal(_In_ PVMM_PROCESS pProcess PMINIDUMP_MEMORY_INFO pmdMI, pmdMIprev; CHAR szComment[0x80]; // initialization - if(!(psObPrefetch = ObSet_New())) { goto fail; } - if(!(pObSystemProcess = VmmProcessGet(4))) { goto fail; } - if(!VmmMap_GetPte(pProcess, &pObPteMap, FALSE) || !pObPteMap->cMap || (pObPteMap->cMap > 0x4000)) { goto fail; } - if(!VmmMap_GetVad(pProcess, &pObVadMap, VMM_VADMAP_TP_FULL) || !pObVadMap->cMap || (pObVadMap->cMap > 0x1000)) { goto fail; } - if(VmmMap_GetThread(pProcess, &pObThreadMap) && (!pObThreadMap->cMap || (pObThreadMap->cMap > 0x4000))) { // THREAD = allowed to fail (due to dependency on debug symbols). + if(!(psObPrefetch = ObSet_New(H))) { goto fail; } + if(!(pObSystemProcess = VmmProcessGet(H, 4))) { goto fail; } + if(!VmmMap_GetPte(H, pProcess, &pObPteMap, FALSE) || !pObPteMap->cMap || (pObPteMap->cMap > 0x4000)) { goto fail; } + if(!VmmMap_GetVad(H, pProcess, &pObVadMap, VMM_VADMAP_TP_FULL) || !pObVadMap->cMap || (pObVadMap->cMap > 0x1000)) { goto fail; } + if(VmmMap_GetThread(H, pProcess, &pObThreadMap) && (!pObThreadMap->cMap || (pObThreadMap->cMap > 0x4000))) { // THREAD = allowed to fail (due to dependency on debug symbols). Ob_DECREF_NULL(&pObThreadMap); } - if(!VmmMap_GetModule(pProcess, &pObModuleMap) || !pObModuleMap->cMap || (pObModuleMap->cMap > 0x4000)) { goto fail; } - if(!VmmMap_GetUnloadedModule(pProcess, &pObUnloadedModuleMap)) { goto fail; } - if(!(ctx = Ob_Alloc(OB_TAG_MOD_MINIDUMP_CTX, LMEM_ZEROINIT, sizeof(OB_M_MINIDUMP_CONTEXT), (OB_CLEANUP_CB)M_MiniDump_CallbackCleanup_ObMiniDumpContext, NULL))) { goto fail; } + if(!VmmMap_GetModule(H, pProcess, &pObModuleMap) || !pObModuleMap->cMap || (pObModuleMap->cMap > 0x4000)) { goto fail; } + if(!VmmMap_GetUnloadedModule(H, pProcess, &pObUnloadedModuleMap)) { goto fail; } + if(!(ctx = Ob_AllocEx(H, OB_TAG_MOD_MINIDUMP_CTX, LMEM_ZEROINIT, sizeof(OB_M_MINIDUMP_CONTEXT), (OB_CLEANUP_CB)M_MiniDump_CallbackCleanup_ObMiniDumpContext, NULL))) { goto fail; } if(!(ctx->pb = LocalAlloc(LMEM_ZEROINIT, MINIDUMP_BUFFER_INITIAL))) { goto fail; } _snprintf_s( szComment, @@ -657,10 +658,10 @@ POB_M_MINIDUMP_CONTEXT M_MiniDump_Initialize_Internal(_In_ PVMM_PROCESS pProcess ctx->MiscInfoStream.p->SizeOfInfo = sizeof(MINIDUMP_MISC_INFO_3); ctx->MiscInfoStream.p->Flags1 = MINIDUMP_MISC1_PROCESS_ID | MINIDUMP_MISC1_PROCESS_TIMES; ctx->MiscInfoStream.p->ProcessId = pProcess->dwPID; - ctx->MiscInfoStream.p->ProcessCreateTime = (DWORD)((*(PQWORD)(pProcess->win.EPROCESS.pb + ctxVmm->offset.EPROCESS.opt.CreateTime) - 11644473600000 * 10000) / 10000000); - ctx->MiscInfoStream.p->ProcessUserTime = *(PDWORD)(pProcess->win.EPROCESS.pb + ctxVmm->offset.EPROCESS.opt.UserTime); - ctx->MiscInfoStream.p->ProcessKernelTime = *(PDWORD)(pProcess->win.EPROCESS.pb + ctxVmm->offset.EPROCESS.opt.KernelTime); - if(VmmWinReg_ValueQuery2("HKLM\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0\\~MHz", NULL, (PBYTE)&dwCpuMhz, sizeof(DWORD), NULL)) { + ctx->MiscInfoStream.p->ProcessCreateTime = (DWORD)((*(PQWORD)(pProcess->win.EPROCESS.pb + H->vmm.offset.EPROCESS.opt.CreateTime) - 11644473600000 * 10000) / 10000000); + ctx->MiscInfoStream.p->ProcessUserTime = *(PDWORD)(pProcess->win.EPROCESS.pb + H->vmm.offset.EPROCESS.opt.UserTime); + ctx->MiscInfoStream.p->ProcessKernelTime = *(PDWORD)(pProcess->win.EPROCESS.pb + H->vmm.offset.EPROCESS.opt.KernelTime); + if(VmmWinReg_ValueQuery2(H, "HKLM\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0\\~MHz", NULL, (PBYTE)&dwCpuMhz, sizeof(DWORD), NULL)) { ctx->MiscInfoStream.p->Flags1 = ctx->MiscInfoStream.p->Flags1 | MINIDUMP_MISC1_PROCESSOR_POWER_INFO; ctx->MiscInfoStream.p->ProcessorMaxMhz = dwCpuMhz; ctx->MiscInfoStream.p->ProcessorCurrentMhz = dwCpuMhz; @@ -676,11 +677,11 @@ POB_M_MINIDUMP_CONTEXT M_MiniDump_Initialize_Internal(_In_ PVMM_PROCESS pProcess ctx->SystemInfo.p->ProcessorArchitecture = (f32 ? PROCESSOR_ARCHITECTURE_INTEL : PROCESSOR_ARCHITECTURE_AMD64); ctx->SystemInfo.p->ProcessorLevel = 0; ctx->SystemInfo.p->ProcessorRevision = 0x31; - ctx->SystemInfo.p->NumberOfProcessors = (UCHAR)ctxVmm->kernel.opt.cCPUs; + ctx->SystemInfo.p->NumberOfProcessors = (UCHAR)H->vmm.kernel.opt.cCPUs; ctx->SystemInfo.p->ProductType = VER_NT_WORKSTATION; - ctx->SystemInfo.p->MajorVersion = ctxVmm->kernel.dwVersionMajor; - ctx->SystemInfo.p->MinorVersion = ctxVmm->kernel.dwVersionMinor; - ctx->SystemInfo.p->BuildNumber = ctxVmm->kernel.dwVersionBuild; + ctx->SystemInfo.p->MajorVersion = H->vmm.kernel.dwVersionMajor; + ctx->SystemInfo.p->MinorVersion = H->vmm.kernel.dwVersionMinor; + ctx->SystemInfo.p->BuildNumber = H->vmm.kernel.dwVersionBuild; ctx->SystemInfo.p->PlatformId = VER_PLATFORM_WIN32_NT; ctx->SystemInfo.p->CSDVersionRva = M_MiniDump_Initialize_AddText(ctx, szComment); ctx->SystemInfo.p->SuiteMask = 0; @@ -697,7 +698,7 @@ POB_M_MINIDUMP_CONTEXT M_MiniDump_Initialize_Internal(_In_ PVMM_PROCESS pProcess pmdM = &ctx->ModuleList.p->Modules[i]; pmdM->BaseOfImage = peM->vaBase; pmdM->SizeOfImage = peM->cbImageSize; - PE_GetTimeDateStampCheckSum(pProcess, peM->vaBase, &pmdM->TimeDateStamp, &pmdM->CheckSum); + PE_GetTimeDateStampCheckSum(H, pProcess, peM->vaBase, &pmdM->TimeDateStamp, &pmdM->CheckSum); pmdM->ModuleNameRva = M_MiniDump_Initialize_AddText(ctx, peM->uszFullName); //pmdM->VersionInfo. ... // TODO: //pmdM->CvRecord // ADDED LATER @@ -707,11 +708,10 @@ POB_M_MINIDUMP_CONTEXT M_MiniDump_Initialize_Internal(_In_ PVMM_PROCESS pProcess } // populate: MINIDUMP_UNLOADED_MODULE_LIST - if(pObThreadMap) - { - ctx->ThreadInfoList.p1->SizeOfHeader = sizeof(MINIDUMP_UNLOADED_MODULE_LIST); - ctx->ThreadInfoList.p1->SizeOfEntry = sizeof(MINIDUMP_UNLOADED_MODULE); - ctx->ThreadInfoList.p1->NumberOfEntries = pObUnloadedModuleMap->cMap; + if(pObUnloadedModuleMap) { + ctx->UnloadedModuleList.p1->SizeOfHeader = sizeof(MINIDUMP_UNLOADED_MODULE_LIST); + ctx->UnloadedModuleList.p1->SizeOfEntry = sizeof(MINIDUMP_UNLOADED_MODULE); + ctx->UnloadedModuleList.p1->NumberOfEntries = pObUnloadedModuleMap->cMap; for(i = 0; i < pObUnloadedModuleMap->cMap; i++) { peU = &pObUnloadedModuleMap->pMap[i]; pmdU = &ctx->UnloadedModuleList.p2[i]; @@ -721,6 +721,10 @@ POB_M_MINIDUMP_CONTEXT M_MiniDump_Initialize_Internal(_In_ PVMM_PROCESS pProcess pmdU->TimeDateStamp = peU->dwTimeDateStamp; pmdU->ModuleNameRva = M_MiniDump_Initialize_AddText(ctx, peU->uszText); } + } else { + ctx->UnloadedModuleList.p1->SizeOfHeader = sizeof(MINIDUMP_UNLOADED_MODULE_LIST); + ctx->UnloadedModuleList.p1->SizeOfEntry = sizeof(MINIDUMP_UNLOADED_MODULE); + ctx->UnloadedModuleList.p1->NumberOfEntries = 0; } // populate: MINIDUMP_THREAD_INFO_LIST @@ -765,16 +769,16 @@ POB_M_MINIDUMP_CONTEXT M_MiniDump_Initialize_Internal(_In_ PVMM_PROCESS pProcess } } } - VmmCachePrefetchPages3(pObSystemProcess, psObPrefetch, sizeof(CPU_KTRAP_FRAME64), 0); + VmmCachePrefetchPages3(H, pObSystemProcess, psObPrefetch, sizeof(CPU_KTRAP_FRAME64), 0); ObSet_Clear(psObPrefetch); for(i = 0, j = 0; i < pObThreadMap->cMap; i++) { if((peT = &pObThreadMap->pMap[i])->ftExitTime) { continue; } pmdT = &ctx->ThreadList.p->Threads[j++]; if(pmdT->Stack.StartOfMemoryRange) { if(f32) { - M_MiniDump_Initialize_ThreadList_CpuContext32(pObSystemProcess, ctx, peT, pmdT); + M_MiniDump_Initialize_ThreadList_CpuContext32(H, pObSystemProcess, ctx, peT, pmdT); } else { - M_MiniDump_Initialize_ThreadList_CpuContext64(pObSystemProcess, ctx, peT, pmdT); + M_MiniDump_Initialize_ThreadList_CpuContext64(H, pObSystemProcess, ctx, peT, pmdT); } } } @@ -784,20 +788,13 @@ POB_M_MINIDUMP_CONTEXT M_MiniDump_Initialize_Internal(_In_ PVMM_PROCESS pProcess { for(i = 0; i < ctx->ModuleList.p->NumberOfModules; i++) { pmdM = &ctx->ModuleList.p->Modules[i]; - if(PE_GetCodeViewInfo(pProcess, pmdM->BaseOfImage, NULL, &CodeViewInfo)) { + if(PE_GetCodeViewInfo(H, pProcess, pmdM->BaseOfImage, NULL, &CodeViewInfo)) { pmdM->CvRecord.DataSize = CodeViewInfo.SizeCodeView; pmdM->CvRecord.Rva = M_MiniDump_Initialize_AddBinary(ctx, (PBYTE)&CodeViewInfo.CodeView, CodeViewInfo.SizeCodeView); } } } - // populate: MINIDUMP_UNLOADED_MODULE_LIST - { - ctx->UnloadedModuleList.p1->SizeOfHeader = sizeof(MINIDUMP_UNLOADED_MODULE_LIST); - ctx->UnloadedModuleList.p1->SizeOfEntry = sizeof(MINIDUMP_UNLOADED_MODULE); - ctx->UnloadedModuleList.p1->NumberOfEntries = 0; - } - // allocate: MINIDUMP_HANDLE_DATA_STREAM { ctx->HandleDataStream.cb = sizeof(MINIDUMP_HANDLE_DATA_STREAM); @@ -988,7 +985,7 @@ POB_M_MINIDUMP_CONTEXT M_MiniDump_Initialize_Internal(_In_ PVMM_PROCESS pProcess // set update time (used for file time stamp) ctx->qwLastAccessTickCount64 = GetTickCount64(); - if(ctxMain->dev.fVolatile || !(ctx->qwTimeUpdate = VmmProcess_GetCreateTimeOpt(pProcess))) { + if(H->dev.fVolatile || !(ctx->qwTimeUpdate = VmmProcess_GetCreateTimeOpt(H, pProcess))) { GetSystemTimeAsFileTime((PFILETIME)&ctx->qwTimeUpdate); } @@ -1009,10 +1006,11 @@ fail: /* * Retrieve minidump context for the given process. * CALLER DECREF: return +* -- H * -- pProcess * -- return */ -POB_M_MINIDUMP_CONTEXT M_MiniDump_GetContext(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) +POB_M_MINIDUMP_CONTEXT M_MiniDump_GetContext(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP) { POB_M_MINIDUMP_CONTEXT pObCtx = NULL; POB_MAP ctxM = (POB_MAP)ctxP->ctxM; @@ -1020,7 +1018,7 @@ POB_M_MINIDUMP_CONTEXT M_MiniDump_GetContext(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) QWORD qwKey = (QWORD)pProcess->dwPID; if(!pProcess->fUserOnly) { return NULL; } if((pObCtx = ObMap_GetByKey(ctxM, qwKey))) { - if(!ctxMain->dev.fVolatile || pObCtx->qwLastAccessTickCount64 + M_MINIDUMP_DYNAMIC_DUMP_MAX_AGE_MS > GetTickCount64()) { + if(!H->dev.fVolatile || pObCtx->qwLastAccessTickCount64 + M_MINIDUMP_DYNAMIC_DUMP_MAX_AGE_MS > GetTickCount64()) { goto finish; } // ctx is aged out @@ -1029,7 +1027,7 @@ POB_M_MINIDUMP_CONTEXT M_MiniDump_GetContext(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) } EnterCriticalSection(&pProcess->LockPlugin); if(!(pObCtx = ObMap_GetByKey(ctxM, qwKey))) { - if((pObCtx = M_MiniDump_Initialize_Internal(pProcess))) { + if((pObCtx = M_MiniDump_Initialize_Internal(H, pProcess))) { ObMap_Push(ctxM, qwKey, pObCtx); } } @@ -1042,14 +1040,14 @@ finish: } _Success_(return == STATUS_SUCCESS) -NTSTATUS M_MiniDump_ReadMiniDump(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS M_MiniDump_ReadMiniDump(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { DWORD i, cbHead = 0, cbReadMem = 0, dwIntraSize; QWORD cbBase = 0, cbIntraOffset; PMINIDUMP_MEMORY_DESCRIPTOR64 pmd; POB_M_MINIDUMP_CONTEXT pObMiniDump = NULL; PVMM_PROCESS pProcess = (PVMM_PROCESS)ctxP->pProcess; - if(!(pObMiniDump = M_MiniDump_GetContext(ctxP))) { return VMMDLL_STATUS_FILE_INVALID; } + if(!(pObMiniDump = M_MiniDump_GetContext(H, ctxP))) { return VMMDLL_STATUS_FILE_INVALID; } // read minidmump header if(cbOffset < pObMiniDump->cb) { cbHead = min(cb, pObMiniDump->cb - (DWORD)cbOffset); @@ -1070,7 +1068,7 @@ NTSTATUS M_MiniDump_ReadMiniDump(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_t if(cbBase >= cbOffset + cbReadMem + cb) { break; } cbIntraOffset = (cbBase < cbOffset) ? cbOffset - cbBase : 0; dwIntraSize = (DWORD)min(cb, pmd->DataSize - cbIntraOffset); - VmmReadEx(pProcess, pmd->StartOfMemoryRange + cbIntraOffset, pb, dwIntraSize, NULL, VMM_FLAG_ZEROPAD_ON_FAIL); + VmmReadEx(H, pProcess, pmd->StartOfMemoryRange + cbIntraOffset, pb, dwIntraSize, NULL, VMM_FLAG_ZEROPAD_ON_FAIL); cbReadMem += dwIntraSize; pb += dwIntraSize; cb -= dwIntraSize; @@ -1083,24 +1081,24 @@ finish: } _Success_(return == STATUS_SUCCESS) -NTSTATUS M_MiniDump_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS M_MiniDump_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { if(!_stricmp(ctxP->uszPath, "readme.txt")) { return Util_VfsReadFile_FromStrA(szMMINIDUMP_README, pb, cb, pcbRead, cbOffset); } if(!_stricmp(ctxP->uszPath, "minidump.dmp")) { - return M_MiniDump_ReadMiniDump(ctxP, pb, cb, pcbRead, cbOffset); + return M_MiniDump_ReadMiniDump(H, ctxP, pb, cb, pcbRead, cbOffset); } return VMMDLL_STATUS_FILE_INVALID; } -BOOL M_MiniDump_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) +BOOL M_MiniDump_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { VMMDLL_VFS_FILELIST_EXINFO ExInfo = { 0 }; POB_M_MINIDUMP_CONTEXT pObMiniDump = NULL; if(ctxP->uszPath[0]) { return FALSE; } VMMDLL_VfsList_AddFile(pFileList, "readme.txt", strlen(szMMINIDUMP_README), NULL); - if((pObMiniDump = M_MiniDump_GetContext(ctxP))) { + if((pObMiniDump = M_MiniDump_GetContext(H, ctxP))) { ExInfo.dwVersion = VMMDLL_VFS_FILELIST_EXINFO_VERSION; ExInfo.qwCreationTime = ExInfo.qwLastAccessTime = ExInfo.qwLastWriteTime = pObMiniDump->qwTimeUpdate; VMMDLL_VfsList_AddFile(pFileList, "minidump.dmp", pObMiniDump->cb + pObMiniDump->cbMemory, &ExInfo); @@ -1109,7 +1107,7 @@ BOOL M_MiniDump_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList return TRUE; } -VOID M_MiniDump_Close(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) +VOID M_MiniDump_Close(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP) { Ob_DECREF(ctxP->ctxM); } @@ -1122,16 +1120,16 @@ VOID M_MiniDump_Close(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) * operating system or architecture is unsupported. * -- pPluginRegInfo */ -VOID M_ProcMiniDump_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_ProcMiniDump_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if(!((pRI->tpSystem == VMM_SYSTEM_WINDOWS_X64) || (pRI->tpSystem == VMM_SYSTEM_WINDOWS_X86))) { return; } - if(!(pRI->reg_info.ctxM = (PVMMDLL_PLUGIN_INTERNAL_CONTEXT)ObMap_New(OB_MAP_FLAGS_OBJECT_OB))) { return; } // internal module context + if(!(pRI->reg_info.ctxM = (PVMMDLL_PLUGIN_INTERNAL_CONTEXT)ObMap_New(H, OB_MAP_FLAGS_OBJECT_OB))) { return; } // internal module context strcpy_s(pRI->reg_info.uszPathName, 128, "\\minidump"); // module name pRI->reg_info.fRootModule = FALSE; // module shows in root directory pRI->reg_info.fProcessModule = TRUE; // module shows in process directory pRI->reg_fn.pfnList = M_MiniDump_List; // List function supported pRI->reg_fn.pfnRead = M_MiniDump_Read; // Read function supported pRI->reg_fn.pfnClose = M_MiniDump_Close; // Close function supported - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_proc_thread.c b/vmm/m_proc_thread.c index 9f6dca4..76f721b 100644 --- a/vmm/m_proc_thread.c +++ b/vmm/m_proc_thread.c @@ -18,7 +18,7 @@ #define MTHREAD_GET_STR_WAIT_REASON(pe) ((pe->bWaitReason < (sizeof(_KWAIT_REASON_STR) / sizeof(LPCSTR))) ? _KWAIT_REASON_STR[pe->bWaitReason] : "Unknown") _Success_(return == 0) -NTSTATUS MThread_Read_ThreadInfo(_In_ PVMM_MAP_THREADENTRY pe, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MThread_Read_ThreadInfo(_In_ VMM_HANDLE H, _In_ PVMM_MAP_THREADENTRY pe, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { CHAR sz[MTHREAD_INFOFILE_LENGTH + 1]; CHAR szTimeCreate[32] = { 0 }, szTimeExit[32] = { 0 }; @@ -73,7 +73,7 @@ NTSTATUS MThread_Read_ThreadInfo(_In_ PVMM_MAP_THREADENTRY pe, _Out_writes_to_(c return Util_VfsReadFile_FromPBYTE(sz, MTHREAD_INFOFILE_LENGTH, pb, cb, pcbRead, cbOffset); } -VOID MThread_ReadLine_Callback(_Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_THREADENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR szu8) +VOID MThread_ReadLineCB(_In_ VMM_HANDLE H, _Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_THREADENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR szu8) { CHAR szTimeCreate[24], szTimeExit[24]; Util_FileTime2String(pe->ftCreateTime, szTimeCreate); @@ -106,7 +106,8 @@ VOID MThread_ReadLine_Callback(_Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, _ /* * Read : function as specified by the module manager. The module manager will * call into this callback function whenever a read shall occur from a "file". -* -- ctx +* -- H +* -- ctxP * -- pb * -- cb * -- pcbRead @@ -114,7 +115,7 @@ VOID MThread_ReadLine_Callback(_Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, _ * -- return */ _Success_(return == 0) -NTSTATUS MThread_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MThread_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; PVMMOB_MAP_THREAD pObThreadMap = NULL; @@ -122,39 +123,39 @@ NTSTATUS MThread_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbR LPSTR uszSubPath; DWORD dwTID; PVMM_MAP_THREADENTRY pe; - if(!VmmMap_GetThread(ctx->pProcess, &pObThreadMap)) { return VMMDLL_STATUS_FILE_INVALID; } + if(!VmmMap_GetThread(H, ctxP->pProcess, &pObThreadMap)) { return VMMDLL_STATUS_FILE_INVALID; } // module root - thread info file - if(!_stricmp(ctx->uszPath, "threads.txt")) { + if(!_stricmp(ctxP->uszPath, "threads.txt")) { nt = Util_VfsLineFixed_Read( - (UTIL_VFSLINEFIXED_PFN_CB)MThread_ReadLine_Callback, NULL, MTHREAD_LINELENGTH, MTHREAD_LINEHEADER, + H, (UTIL_VFSLINEFIXED_PFN_CB)MThread_ReadLineCB, NULL, MTHREAD_LINELENGTH, MTHREAD_LINEHEADER, pObThreadMap->pMap, pObThreadMap->cMap, sizeof(VMM_MAP_THREADENTRY), pb, cb, pcbRead, cbOffset ); goto finish; } // individual thread file - uszSubPath = CharUtil_PathSplitFirst(ctx->uszPath, uszThreadName, _countof(uszThreadName)); - if(uszSubPath && (dwTID = (DWORD)Util_GetNumericA(ctx->uszPath)) && (pe = VmmMap_GetThreadEntry(pObThreadMap, dwTID))) { + uszSubPath = CharUtil_PathSplitFirst(ctxP->uszPath, uszThreadName, _countof(uszThreadName)); + if(uszSubPath && (dwTID = (DWORD)Util_GetNumericA(ctxP->uszPath)) && (pe = VmmMap_GetThreadEntry(H, pObThreadMap, dwTID))) { if(!_stricmp(uszSubPath, "info.txt")) { - nt = MThread_Read_ThreadInfo(pe, pb, cb, pcbRead, cbOffset); + nt = MThread_Read_ThreadInfo(H, pe, pb, cb, pcbRead, cbOffset); goto finish; } // individual thread files backed by user-mode memory below: if(!_stricmp(uszSubPath, "teb")) { - nt = VmmReadAsFile((PVMM_PROCESS)ctx->pProcess, pe->vaTeb, 0x1000, pb, cb, pcbRead, cbOffset); + nt = VmmReadAsFile(H, (PVMM_PROCESS)ctxP->pProcess, pe->vaTeb, 0x1000, pb, cb, pcbRead, cbOffset); goto finish; } if(!_stricmp(uszSubPath, "stack")) { - nt = VmmReadAsFile((PVMM_PROCESS)ctx->pProcess, pe->vaStackLimitUser, pe->vaStackBaseUser - pe->vaStackLimitUser, pb, cb, pcbRead, cbOffset); + nt = VmmReadAsFile(H, (PVMM_PROCESS)ctxP->pProcess, pe->vaStackLimitUser, pe->vaStackBaseUser - pe->vaStackLimitUser, pb, cb, pcbRead, cbOffset); goto finish; } // individual thread files backed by kernel memory below: if(!_stricmp(uszSubPath, "ethread")) { - nt = VmmReadAsFile(PVMM_PROCESS_SYSTEM, pe->vaETHREAD, ctxVmm->offset.ETHREAD.oMax, pb, cb, pcbRead, cbOffset); + nt = VmmReadAsFile(H, PVMM_PROCESS_SYSTEM, pe->vaETHREAD, H->vmm.offset.ETHREAD.oMax, pb, cb, pcbRead, cbOffset); goto finish; } if(!_stricmp(uszSubPath, "kstack")) { - nt = VmmReadAsFile(PVMM_PROCESS_SYSTEM, pe->vaStackLimitKernel, pe->vaStackBaseKernel - pe->vaStackLimitKernel, pb, cb, pcbRead, cbOffset); + nt = VmmReadAsFile(H, PVMM_PROCESS_SYSTEM, pe->vaStackLimitKernel, pe->vaStackBaseKernel - pe->vaStackLimitKernel, pb, cb, pcbRead, cbOffset); goto finish; } } @@ -166,14 +167,15 @@ finish: /* * Write : function as specified by the module manager. The module manager will * call into this callback function whenever a write shall occur from a "file". -* -- ctx +* -- H +* -- ctxP * -- pb * -- cb * -- pcbWrite * -- cbOffset * -- return */ -NTSTATUS MThread_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) +NTSTATUS MThread_Write(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; PVMMOB_MAP_THREAD pObThreadMap = NULL; @@ -181,26 +183,26 @@ NTSTATUS MThread_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_reads_(cb) PBYTE pb, LPSTR uszSubPath; DWORD dwTID; PVMM_MAP_THREADENTRY pe; - if(!VmmMap_GetThread(ctx->pProcess, &pObThreadMap)) { return VMMDLL_STATUS_FILE_INVALID; } + if(!VmmMap_GetThread(H, ctxP->pProcess, &pObThreadMap)) { return VMMDLL_STATUS_FILE_INVALID; } // individual thread file - uszSubPath = CharUtil_PathSplitFirst(ctx->uszPath, uszThreadName, sizeof(uszThreadName)); - if(uszSubPath && (dwTID = (DWORD)Util_GetNumericA(ctx->uszPath)) && (pe = VmmMap_GetThreadEntry(pObThreadMap, dwTID))) { + uszSubPath = CharUtil_PathSplitFirst(ctxP->uszPath, uszThreadName, sizeof(uszThreadName)); + if(uszSubPath && (dwTID = (DWORD)Util_GetNumericA(ctxP->uszPath)) && (pe = VmmMap_GetThreadEntry(H, pObThreadMap, dwTID))) { // individual thread files backed by user-mode memory below: if(!_stricmp(uszSubPath, "teb")) { - nt = VmmWriteAsFile((PVMM_PROCESS)ctx->pProcess, pe->vaTeb, 0x1000, pb, cb, pcbWrite, cbOffset); + nt = VmmWriteAsFile(H, (PVMM_PROCESS)ctxP->pProcess, pe->vaTeb, 0x1000, pb, cb, pcbWrite, cbOffset); goto finish; } if(!_stricmp(uszSubPath, "stack")) { - nt = VmmWriteAsFile((PVMM_PROCESS)ctx->pProcess, pe->vaStackLimitUser, pe->vaStackBaseUser - pe->vaStackLimitUser, pb, cb, pcbWrite, cbOffset); + nt = VmmWriteAsFile(H, (PVMM_PROCESS)ctxP->pProcess, pe->vaStackLimitUser, pe->vaStackBaseUser - pe->vaStackLimitUser, pb, cb, pcbWrite, cbOffset); goto finish; } // individual thread files backed by kernel memory below: if(!_stricmp(uszSubPath, "ethread")) { - nt = VmmWriteAsFile(PVMM_PROCESS_SYSTEM, pe->vaETHREAD, ctxVmm->offset.ETHREAD.oMax, pb, cb, pcbWrite, cbOffset); + nt = VmmWriteAsFile(H, PVMM_PROCESS_SYSTEM, pe->vaETHREAD, H->vmm.offset.ETHREAD.oMax, pb, cb, pcbWrite, cbOffset); goto finish; } if(!_stricmp(uszSubPath, "kstack")) { - nt = VmmWriteAsFile(PVMM_PROCESS_SYSTEM, pe->vaStackLimitKernel, pe->vaStackBaseKernel - pe->vaStackLimitKernel, pb, cb, pcbWrite, cbOffset); + nt = VmmWriteAsFile(H, PVMM_PROCESS_SYSTEM, pe->vaStackLimitKernel, pe->vaStackBaseKernel - pe->vaStackLimitKernel, pb, cb, pcbWrite, cbOffset); goto finish; } } @@ -228,36 +230,37 @@ VOID MThread_List_TimeStampFile(_In_ PVMM_MAP_THREADENTRY pThreadEntry, _Out_ PV * List : function as specified by the module manager. The module manager will * call into this callback function whenever a list directory shall occur from * the given module. -* -- ctx +* -- H +* -- ctxP * -- pFileList * -- return */ -BOOL MThread_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) +BOOL MThread_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { DWORD i, dwTID, cbStack; CHAR uszBuffer[32] = { 0 }; PVMMOB_MAP_THREAD pObThreadMap = NULL; PVMM_MAP_THREADENTRY pe; VMMDLL_VFS_FILELIST_EXINFO ExInfo = { 0 }; - if(!VmmMap_GetThread(ctx->pProcess, &pObThreadMap)) { goto fail; } + if(!VmmMap_GetThread(H, ctxP->pProcess, &pObThreadMap)) { goto fail; } // module root - list thread map - if(!ctx->uszPath[0]) { + if(!ctxP->uszPath[0]) { for(i = 0; i < pObThreadMap->cMap; i++) { pe = pObThreadMap->pMap + i; MThread_List_TimeStampFile(pe, &ExInfo); _snprintf_s(uszBuffer, _countof(uszBuffer), 32, "%i", pe->dwTID); VMMDLL_VfsList_AddDirectory(pFileList, uszBuffer, &ExInfo); } - VMMDLL_VfsList_AddFile(pFileList, "threads.txt", UTIL_VFSLINEFIXED_LINECOUNT(pObThreadMap->cMap) * MTHREAD_LINELENGTH, NULL); + VMMDLL_VfsList_AddFile(pFileList, "threads.txt", UTIL_VFSLINEFIXED_LINECOUNT(H, pObThreadMap->cMap) * MTHREAD_LINELENGTH, NULL); Ob_DECREF_NULL(&pObThreadMap); return TRUE; } // specific thread - if(!(dwTID = (DWORD)Util_GetNumericA(ctx->uszPath))) { goto fail; } - if(!(pe = VmmMap_GetThreadEntry(pObThreadMap, dwTID))) { goto fail; } + if(!(dwTID = (DWORD)Util_GetNumericA(ctxP->uszPath))) { goto fail; } + if(!(pe = VmmMap_GetThreadEntry(H, pObThreadMap, dwTID))) { goto fail; } MThread_List_TimeStampFile(pe, &ExInfo); VMMDLL_VfsList_AddFile(pFileList, "info.txt", MTHREAD_INFOFILE_LENGTH, &ExInfo); - VMMDLL_VfsList_AddFile(pFileList, "ethread", ctxVmm->offset.ETHREAD.oMax, &ExInfo); + VMMDLL_VfsList_AddFile(pFileList, "ethread", H->vmm.offset.ETHREAD.oMax, &ExInfo); if(pe->vaTeb) { VMMDLL_VfsList_AddFile(pFileList, "teb", 0x1000, &ExInfo); } @@ -280,9 +283,10 @@ fail: * shall call the supplied pfnPluginManager_Register function. * NB! the module does not have to register itself - for example if the target * operating system or architecture is unsupported. -* -- pPluginRegInfo +* -- H +* -- pRI */ -VOID M_ProcThread_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_ProcThread_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if(!((pRI->tpSystem == VMM_SYSTEM_WINDOWS_X64) || (pRI->tpSystem == VMM_SYSTEM_WINDOWS_X86))) { return; } @@ -292,5 +296,5 @@ VOID M_ProcThread_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) pRI->reg_fn.pfnList = MThread_List; // List function supported pRI->reg_fn.pfnRead = MThread_Read; // Read function supported pRI->reg_fn.pfnWrite = MThread_Write; // Write function supported - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_proc_token.c b/vmm/m_proc_token.c index 6c41ada..2a7d53f 100644 --- a/vmm/m_proc_token.c +++ b/vmm/m_proc_token.c @@ -59,12 +59,12 @@ static LPCSTR szTOKEN_NAMES[] = { }; _Success_(return) -BOOL MProcToken_PrivilegeGet(_In_ QWORD vaToken, _Out_ PSEP_TOKEN_PRIVILEGES pSepTokenPrivileges, _Out_ PDWORD cSepTokenPrivileges) +BOOL MProcToken_PrivilegeGet(_In_ VMM_HANDLE H, _In_ QWORD vaToken, _Out_ PSEP_TOKEN_PRIVILEGES pSepTokenPrivileges, _Out_ PDWORD cSepTokenPrivileges) { QWORD v; DWORD i, c = 0; - if(ctxVmm->kernel.dwVersionBuild < 6000) { return FALSE; } // TOKEN PRIVILEGES ONLY IN VISTA+ - if(!VmmRead(PVMM_PROCESS_SYSTEM, vaToken + 0x40, (PBYTE)pSepTokenPrivileges, 0x18)) { return FALSE; } + if(H->vmm.kernel.dwVersionBuild < 6000) { return FALSE; } // TOKEN PRIVILEGES ONLY IN VISTA+ + if(!VmmRead(H, PVMM_PROCESS_SYSTEM, vaToken + 0x40, (PBYTE)pSepTokenPrivileges, 0x18)) { return FALSE; } for(i = 2; i < sizeof(szTOKEN_NAMES) / sizeof(LPCWSTR); i++) { v = pSepTokenPrivileges->Enabled | pSepTokenPrivileges->EnabledByDefault | pSepTokenPrivileges->Present; c += (v >> i) & 1; @@ -73,7 +73,7 @@ BOOL MProcToken_PrivilegeGet(_In_ QWORD vaToken, _Out_ PSEP_TOKEN_PRIVILEGES pSe return TRUE; } -VOID MProcToken_PrivilegeReadLine_Callback(_In_ PVMM_PROCESS pProcess, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PSEP_TOKEN_PRIVILEGES pPriv, _Out_writes_(cbLineLength + 1) LPSTR szu8) +VOID MProcToken_PrivilegeReadLineCB(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PSEP_TOKEN_PRIVILEGES pPriv, _Out_writes_(cbLineLength + 1) LPSTR szu8) { QWORD v; DWORD i, c = ie; @@ -106,7 +106,7 @@ typedef struct tdMPROCTOKEN_ALLSID_CONTEXT { PBYTE pbUserAndGroups; } MPROCTOKEN_ALLSID_CONTEXT, *PMPROCTOKEN_ALLSID_CONTEXT; -VOID MProcToken_AllSidReadLine_Callback(_In_ PMPROCTOKEN_ALLSID_CONTEXT ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVOID pvNotUsed, _Out_writes_(cbLineLength + 1) LPSTR szu8) +VOID MProcToken_AllSidReadLineCB(_In_ VMM_HANDLE H, _In_ PMPROCTOKEN_ALLSID_CONTEXT ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVOID pvNotUsed, _Out_writes_(cbLineLength + 1) LPSTR szu8) { union { SID SID; @@ -118,8 +118,8 @@ VOID MProcToken_AllSidReadLine_Callback(_In_ PMPROCTOKEN_ALLSID_CONTEXT ctx, _In CHAR szNameBuffer[MAX_PATH], szBuffer[MAX_PATH] = { 0 }; DWORD i, cszNameBuffer = _countof(szNameBuffer); DWORD cszBuffer = _countof(szBuffer); - vaSid = VMM_PTR_OFFSET(ctxVmm->f32, ctx->pbUserAndGroups, ie * (ctxVmm->f32 ? 8ULL : 16ULL)); - if(!VmmRead(ctx->pSystemProcess, vaSid, Sid.pb, SECURITY_MAX_SID_SIZE)) { goto fail; } + vaSid = VMM_PTR_OFFSET(H->vmm.f32, ctx->pbUserAndGroups, ie * (H->vmm.f32 ? 8ULL : 16ULL)); + if(!VmmRead(H, ctx->pSystemProcess, vaSid, Sid.pb, SECURITY_MAX_SID_SIZE)) { goto fail; } if(!ConvertSidToStringSidA(&Sid.SID, &szSid)) { goto fail; } // display name from winapi lookup: if(LookupAccountSidA(NULL, &Sid.SID, szNameBuffer, &cszNameBuffer, szBuffer, &cszBuffer, &eUse)) { @@ -164,7 +164,8 @@ fail: /* * Read : function as specified by the module manager. The module manager will * call into this callback function whenever a read shall occur from a "file". -* -- ctx +* -- H +* -- ctxP * -- pb * -- cb * -- pcbRead @@ -172,7 +173,7 @@ fail: * -- return */ _Success_(return == 0) -NTSTATUS MProcToken_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MProcToken_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; CHAR uszBuffer[MAX_PATH + 1]; @@ -181,42 +182,42 @@ NTSTATUS MProcToken_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *p DWORD cSepTokenPrivileges; LPCSTR sz; MPROCTOKEN_ALLSID_CONTEXT ctxAllSid = { 0 }; - if(!(pObProcess = VmmProcessGetEx(NULL, ctx->dwPID, VMM_FLAG_PROCESS_TOKEN))) { goto fail; } + if(!(pObProcess = VmmProcessGetEx(H, NULL, ctxP->dwPID, VMM_FLAG_PROCESS_TOKEN))) { goto fail; } if(!pObProcess->win.TOKEN.fInitialized || !pObProcess->win.TOKEN.fSidUserValid) { goto fail; } - if(!_stricmp(ctx->uszPath, "sid.txt")) { + if(!_stricmp(ctxP->uszPath, "sid.txt")) { nt = Util_VfsReadFile_FromPBYTE( (PBYTE)pObProcess->win.TOKEN.szSID, pObProcess->win.TOKEN.szSID ? strlen(pObProcess->win.TOKEN.szSID) : 0, pb, cb, pcbRead, cbOffset); - } else if(!_stricmp(ctx->uszPath, "sid-all.txt")) { - if(pObProcess->win.TOKEN.dwUserAndGroupCount && VmmReadAlloc(PVMM_PROCESS_SYSTEM, pObProcess->win.TOKEN.vaUserAndGroups, &ctxAllSid.pbUserAndGroups, pObProcess->win.TOKEN.dwUserAndGroupCount * (ctxVmm->f32 ? 8 : 16), 0)) { + } else if(!_stricmp(ctxP->uszPath, "sid-all.txt")) { + if(pObProcess->win.TOKEN.dwUserAndGroupCount && VmmReadAlloc(H, PVMM_PROCESS_SYSTEM, pObProcess->win.TOKEN.vaUserAndGroups, &ctxAllSid.pbUserAndGroups, pObProcess->win.TOKEN.dwUserAndGroupCount * (H->vmm.f32 ? 8 : 16), 0)) { ctxAllSid.pProcess = pObProcess; - ctxAllSid.pSystemProcess = VmmProcessGet(4); - VmmMap_GetUser(&ctxAllSid.pUserMap); + ctxAllSid.pSystemProcess = VmmProcessGet(H, 4); + VmmMap_GetUser(H, &ctxAllSid.pUserMap); nt = Util_VfsLineFixed_Read( - (UTIL_VFSLINEFIXED_PFN_CB)MProcToken_AllSidReadLine_Callback, &ctxAllSid, MPROCTOKEN_ALLSID_LINELENGTH, MPROCTOKEN_ALLSID_LINEHEADER, + H, (UTIL_VFSLINEFIXED_PFN_CB)MProcToken_AllSidReadLineCB, &ctxAllSid, MPROCTOKEN_ALLSID_LINELENGTH, MPROCTOKEN_ALLSID_LINEHEADER, (PVOID)ctxAllSid.pbUserAndGroups /*dummy*/, pObProcess->win.TOKEN.dwUserAndGroupCount, 0, pb, cb, pcbRead, cbOffset ); Ob_DECREF(ctxAllSid.pSystemProcess); Ob_DECREF(ctxAllSid.pUserMap); } - } else if(!_stricmp(ctx->uszPath, "user.txt")) { - VmmWinUser_GetName(&pObProcess->win.TOKEN.SidUser.SID, uszBuffer, MAX_PATH, NULL); + } else if(!_stricmp(ctxP->uszPath, "user.txt")) { + VmmWinUser_GetName(H, &pObProcess->win.TOKEN.SidUser.SID, uszBuffer, MAX_PATH, NULL); nt = Util_VfsReadFile_FromPBYTE(uszBuffer, strlen(uszBuffer), pb, cb, pcbRead, cbOffset); - } else if(!_stricmp(ctx->uszPath, "luid.txt")) { + } else if(!_stricmp(ctxP->uszPath, "luid.txt")) { nt = Util_VfsReadFile_FromQWORD(pObProcess->win.TOKEN.qwLUID, pb, cb, pcbRead, cbOffset, FALSE); - } else if(!_stricmp(ctx->uszPath, "session.txt")) { + } else if(!_stricmp(ctxP->uszPath, "session.txt")) { nt = Util_VfsReadFile_FromDWORD(pObProcess->win.TOKEN.dwSessionId, pb, cb, pcbRead, cbOffset, FALSE); - } else if(!_stricmp(ctx->uszPath, "privileges.txt")) { - if(MProcToken_PrivilegeGet(pObProcess->win.TOKEN.va, &SepTokenPrivileges, &cSepTokenPrivileges)) { + } else if(!_stricmp(ctxP->uszPath, "privileges.txt")) { + if(MProcToken_PrivilegeGet(H, pObProcess->win.TOKEN.va, &SepTokenPrivileges, &cSepTokenPrivileges)) { nt = Util_VfsLineFixed_Read( - (UTIL_VFSLINEFIXED_PFN_CB)MProcToken_PrivilegeReadLine_Callback, pObProcess, MPROCTOKEN_PRIVILEGE_LINELENGTH, MPROCTOKEN_PRIVILEGE_LINEHEADER, + H, (UTIL_VFSLINEFIXED_PFN_CB)MProcToken_PrivilegeReadLineCB, pObProcess, MPROCTOKEN_PRIVILEGE_LINELENGTH, MPROCTOKEN_PRIVILEGE_LINEHEADER, &SepTokenPrivileges, cSepTokenPrivileges, 0, pb, cb, pcbRead, cbOffset ); } - } else if(!_stricmp(ctx->uszPath, "integrity.txt")) { + } else if(!_stricmp(ctxP->uszPath, "integrity.txt")) { sz = VMM_PROCESS_INTEGRITY_LEVEL_STR[pObProcess->win.TOKEN.IntegrityLevel]; nt = Util_VfsReadFile_FromPBYTE((PBYTE)sz, strlen(sz), pb, cb, pcbRead, cbOffset); } @@ -229,30 +230,30 @@ fail: * List : function as specified by the module manager. The module manager will * call into this callback function whenever a list directory shall occur from * the given module. -* -- ctx +* -- ctxP * -- pFileList * -- return */ -BOOL MProcToken_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) +BOOL MProcToken_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { BOOL fResult = FALSE; DWORD cSepTokenPrivileges; CHAR uszBuffer[MAX_PATH + 1] = { 0 }; PVMM_PROCESS pObProcess = NULL; SEP_TOKEN_PRIVILEGES SepTokenPrivileges; - if(!(pObProcess = VmmProcessGetEx(NULL, ctx->dwPID, VMM_FLAG_PROCESS_TOKEN))) { goto fail; } + if(!(pObProcess = VmmProcessGetEx(H, NULL, ctxP->dwPID, VMM_FLAG_PROCESS_TOKEN))) { goto fail; } if(!pObProcess->win.TOKEN.fInitialized || !pObProcess->win.TOKEN.fSidUserValid) { goto fail; } if(pObProcess->win.TOKEN.szSID) { VMMDLL_VfsList_AddFile(pFileList, "sid.txt", strlen(pObProcess->win.TOKEN.szSID), NULL); - VMMDLL_VfsList_AddFile(pFileList, "sid-all.txt", UTIL_VFSLINEFIXED_LINECOUNT(pObProcess->win.TOKEN.dwUserAndGroupCount) * MPROCTOKEN_ALLSID_LINELENGTH, NULL); + VMMDLL_VfsList_AddFile(pFileList, "sid-all.txt", UTIL_VFSLINEFIXED_LINECOUNT(H, pObProcess->win.TOKEN.dwUserAndGroupCount) * MPROCTOKEN_ALLSID_LINELENGTH, NULL); } - if(VmmWinUser_GetName(&pObProcess->win.TOKEN.SidUser.SID, uszBuffer, MAX_PATH, NULL)) { + if(VmmWinUser_GetName(H, &pObProcess->win.TOKEN.SidUser.SID, uszBuffer, MAX_PATH, NULL)) { VMMDLL_VfsList_AddFile(pFileList, "user.txt", strlen(uszBuffer), NULL); } VMMDLL_VfsList_AddFile(pFileList, "luid.txt", 16, NULL); VMMDLL_VfsList_AddFile(pFileList, "session.txt", 8, NULL); - if(MProcToken_PrivilegeGet(pObProcess->win.TOKEN.va, &SepTokenPrivileges, &cSepTokenPrivileges)) { - VMMDLL_VfsList_AddFile(pFileList, "privileges.txt", UTIL_VFSLINEFIXED_LINECOUNT(cSepTokenPrivileges) * MPROCTOKEN_PRIVILEGE_LINELENGTH, NULL); + if(MProcToken_PrivilegeGet(H, pObProcess->win.TOKEN.va, &SepTokenPrivileges, &cSepTokenPrivileges)) { + VMMDLL_VfsList_AddFile(pFileList, "privileges.txt", UTIL_VFSLINEFIXED_LINECOUNT(H, cSepTokenPrivileges) * MPROCTOKEN_PRIVILEGE_LINELENGTH, NULL); } if(pObProcess->win.TOKEN.IntegrityLevel) { VMMDLL_VfsList_AddFile(pFileList, "integrity.txt", strlen(VMM_PROCESS_INTEGRITY_LEVEL_STR[pObProcess->win.TOKEN.IntegrityLevel]), NULL); @@ -271,7 +272,7 @@ fail: * operating system or architecture is unsupported. * -- pPluginRegInfo */ -VOID M_ProcToken_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_ProcToken_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if(!((pRI->tpSystem == VMM_SYSTEM_WINDOWS_X64) || (pRI->tpSystem == VMM_SYSTEM_WINDOWS_X86))) { return; } @@ -280,5 +281,5 @@ VOID M_ProcToken_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) pRI->reg_info.fProcessModule = TRUE; // module shows in process directory pRI->reg_fn.pfnList = MProcToken_List; // List function supported pRI->reg_fn.pfnRead = MProcToken_Read; // Read function supported - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_search.c b/vmm/m_search.c index 9908f85..77627c3 100644 --- a/vmm/m_search.c +++ b/vmm/m_search.c @@ -32,14 +32,14 @@ typedef struct tdMOB_SEARCH_CONTEXT { POB_DATA pObDataResult; } MOB_SEARCH_CONTEXT, *PMOB_SEARCH_CONTEXT; -VOID MSearch_ContextUpdate(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_opt_ PMOB_SEARCH_CONTEXT ctxS) +VOID MSearch_ContextUpdate(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_opt_ PMOB_SEARCH_CONTEXT ctxS) { - EnterCriticalSection(&ctxVmm->LockPlugin); + EnterCriticalSection(&H->vmm.LockPlugin); if(!ctxS || !ObMap_Exists((POB_MAP)ctxP->ctxM, ctxS)) { Ob_DECREF(ObMap_RemoveByKey((POB_MAP)ctxP->ctxM, ctxP->dwPID)); if(ctxS) { ObMap_Push((POB_MAP)ctxP->ctxM, ctxP->dwPID, ctxS); } } - LeaveCriticalSection(&ctxVmm->LockPlugin); + LeaveCriticalSection(&H->vmm.LockPlugin); } VOID MSearch_ContextCleanup1_CB(PVOID pOb) @@ -55,27 +55,27 @@ VOID MSearch_ContextCleanup_CB(PVOID pOb) /* * CALLER DECREF: return */ -PMOB_SEARCH_CONTEXT MSearch_ContextGet(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) +PMOB_SEARCH_CONTEXT MSearch_ContextGet(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP) { PMOB_SEARCH_CONTEXT pObCtx = NULL; - EnterCriticalSection(&ctxVmm->LockPlugin); + EnterCriticalSection(&H->vmm.LockPlugin); pObCtx = ObMap_GetByKey((POB_MAP)ctxP->ctxM, ctxP->dwPID); - LeaveCriticalSection(&ctxVmm->LockPlugin); - if(!pObCtx && (pObCtx = Ob_Alloc(OB_TAG_MOD_SEARCH_CTX, LMEM_ZEROINIT, sizeof(MOB_SEARCH_CONTEXT), MSearch_ContextCleanup_CB, MSearch_ContextCleanup1_CB))) { + LeaveCriticalSection(&H->vmm.LockPlugin); + if(!pObCtx && (pObCtx = Ob_AllocEx(H, OB_TAG_MOD_SEARCH_CTX, LMEM_ZEROINIT, sizeof(MOB_SEARCH_CONTEXT), MSearch_ContextCleanup_CB, MSearch_ContextCleanup1_CB))) { pObCtx->sctx.cSearch = 1; pObCtx->sctx.search[0].cbAlign = 1; if(ctxP->pProcess) { // virtual memory search in process address space pObCtx->dwPID = ((PVMM_PROCESS)ctxP->pProcess)->dwPID; if(((PVMM_PROCESS)ctxP->pProcess)->fUserOnly) { - pObCtx->sctx.vaMax = ctxVmm->f32 ? 0x7fffffff : 0x7fffffffffff; + pObCtx->sctx.vaMax = H->vmm.f32 ? 0x7fffffff : 0x7fffffffffff; } else { - pObCtx->sctx.vaMax = ctxVmm->f32 ? 0xffffffff : 0xffffffffffffffff; + pObCtx->sctx.vaMax = H->vmm.f32 ? 0xffffffff : 0xffffffffffffffff; } } else { // physical memory search pObCtx->dwPID = 0; - pObCtx->sctx.vaMax = ctxMain->dev.paMax - 1; + pObCtx->sctx.vaMax = H->dev.paMax - 1; } } return pObCtx; @@ -84,32 +84,31 @@ PMOB_SEARCH_CONTEXT MSearch_ContextGet(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) /* * Perform the memory search in an async worker thread */ -DWORD WINAPI MSearch_PerformSeach_ThreadProc(_In_ PMOB_SEARCH_CONTEXT ctxS) +VOID MSearch_PerformSeach_ThreadProc(_In_ VMM_HANDLE H, _In_ PMOB_SEARCH_CONTEXT ctxS) { PVMM_PROCESS pObProcess = NULL; if(!ctxS->dwPID) { - VmmSearch(NULL, &ctxS->sctx, &ctxS->pObDataResult); - } else if((pObProcess = VmmProcessGet(ctxS->dwPID))) { - VmmSearch(pObProcess, &ctxS->sctx, &ctxS->pObDataResult); + VmmSearch(H, NULL, &ctxS->sctx, &ctxS->pObDataResult); + } else if((pObProcess = VmmProcessGet(H, ctxS->dwPID))) { + VmmSearch(H, pObProcess, &ctxS->sctx, &ctxS->pObDataResult); } ctxS->fCompleted = TRUE; ctxS->fActive = FALSE; - Ob_DECREF(ctxS); Ob_DECREF(pObProcess); - return 0; } /* * Write : function as specified by the module manager. The module manager will * call into this callback function whenever a write shall occur from a "file". -* -- ctx +* -- H +* -- ctxP * -- pb * -- cb * -- pcbWrite * -- cbOffset * -- return */ -NTSTATUS MSearch_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) +NTSTATUS MSearch_Write(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) { NTSTATUS nt = VMMDLL_STATUS_SUCCESS; PMOB_SEARCH_CONTEXT pObCtx = NULL; @@ -118,14 +117,14 @@ NTSTATUS MSearch_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_reads_(cb) PBYTE pb QWORD qw; BYTE pbSearchBuffer[32]; *pcbWrite = cb; - if(!(pObCtx = MSearch_ContextGet(ctxP))) { return VMMDLL_STATUS_FILE_INVALID; } + if(!(pObCtx = MSearch_ContextGet(H, ctxP))) { return VMMDLL_STATUS_FILE_INVALID; } if(!_stricmp(ctxP->uszPath, "reset.txt")) { fReset = FALSE; nt = Util_VfsWriteFile_BOOL(&fReset, pb, cb, pcbWrite, cbOffset); if(fReset) { // removal via context update will clear up objects and also // cancel / abort any running tasks via the object refcount. - MSearch_ContextUpdate(ctxP, NULL); + MSearch_ContextUpdate(H, ctxP, NULL); } } if(!pObCtx->fActive && !pObCtx->fCompleted) { @@ -135,40 +134,40 @@ NTSTATUS MSearch_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_reads_(cb) PBYTE pb if((dw != pObCtx->sctx.search[0].cbAlign) && (0 == (dw & (dw - 1)))) { if(dw == 0) { dw = 1; } // update (if ok) within critical section - EnterCriticalSection(&ctxVmm->LockPlugin); + EnterCriticalSection(&H->vmm.LockPlugin); if(!pObCtx->fActive && !pObCtx->fCompleted) { pObCtx->sctx.search[0].cbAlign = dw; - MSearch_ContextUpdate(ctxP, pObCtx); + MSearch_ContextUpdate(H, ctxP, pObCtx); } - LeaveCriticalSection(&ctxVmm->LockPlugin); + LeaveCriticalSection(&H->vmm.LockPlugin); } } if(!_stricmp(ctxP->uszPath, "addr-max.txt")) { qw = pObCtx->sctx.vaMax; - nt = Util_VfsWriteFile_QWORD(&qw, pb, cb, pcbWrite, cbOffset + (ctxVmm->f32 ? 8 : 0), 1, 0); + nt = Util_VfsWriteFile_QWORD(&qw, pb, cb, pcbWrite, cbOffset + (H->vmm.f32 ? 8 : 0), 1, 0); qw = (qw - 1) | 0xfff; if((qw != pObCtx->sctx.vaMax)) { // update (if ok) within critical section - EnterCriticalSection(&ctxVmm->LockPlugin); + EnterCriticalSection(&H->vmm.LockPlugin); if(!pObCtx->fActive && !pObCtx->fCompleted) { pObCtx->sctx.vaMax = qw; - MSearch_ContextUpdate(ctxP, pObCtx); + MSearch_ContextUpdate(H, ctxP, pObCtx); } - LeaveCriticalSection(&ctxVmm->LockPlugin); + LeaveCriticalSection(&H->vmm.LockPlugin); } } if(!_stricmp(ctxP->uszPath, "addr-min.txt")) { qw = pObCtx->sctx.vaMin; - nt = Util_VfsWriteFile_QWORD(&qw, pb, cb, pcbWrite, cbOffset + (ctxVmm->f32 ? 8 : 0), 0, 0); + nt = Util_VfsWriteFile_QWORD(&qw, pb, cb, pcbWrite, cbOffset + (H->vmm.f32 ? 8 : 0), 0, 0); qw = qw & ~0xfff; if((qw != pObCtx->sctx.vaMin)) { // update (if ok) within critical section - EnterCriticalSection(&ctxVmm->LockPlugin); + EnterCriticalSection(&H->vmm.LockPlugin); if(!pObCtx->fActive && !pObCtx->fCompleted) { pObCtx->sctx.vaMin = qw; - MSearch_ContextUpdate(ctxP, pObCtx); + MSearch_ContextUpdate(H, ctxP, pObCtx); } - LeaveCriticalSection(&ctxVmm->LockPlugin); + LeaveCriticalSection(&H->vmm.LockPlugin); } } if(!_stricmp(ctxP->uszPath, "search-skip-bitmask.txt")) { @@ -176,13 +175,13 @@ NTSTATUS MSearch_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_reads_(cb) PBYTE pb nt = Util_VfsWriteFile_HEXASCII(pbSearchBuffer, 32, pb, cb, pcbWrite, cbOffset); if(*pcbWrite) { // update (if ok) within critical section - EnterCriticalSection(&ctxVmm->LockPlugin); + EnterCriticalSection(&H->vmm.LockPlugin); if(!pObCtx->fActive && !pObCtx->fCompleted) { pObCtx->sctx.search[0].cb = max(pObCtx->sctx.search[0].cb, (*pcbWrite + 1) >> 1); memcpy(pObCtx->sctx.search[0].pbSkipMask, pbSearchBuffer, 32); - MSearch_ContextUpdate(ctxP, pObCtx); + MSearch_ContextUpdate(H, ctxP, pObCtx); } - LeaveCriticalSection(&ctxVmm->LockPlugin); + LeaveCriticalSection(&H->vmm.LockPlugin); } } if(!_stricmp(ctxP->uszPath, "search.txt")) { @@ -190,19 +189,19 @@ NTSTATUS MSearch_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_reads_(cb) PBYTE pb nt = Util_VfsWriteFile_HEXASCII(pbSearchBuffer, 32, pb, cb, pcbWrite, cbOffset); if(*pcbWrite) { // update (if ok) within critical section - EnterCriticalSection(&ctxVmm->LockPlugin); + EnterCriticalSection(&H->vmm.LockPlugin); if(!pObCtx->fActive && !pObCtx->fCompleted) { pObCtx->sctx.search[0].cb = (*pcbWrite + 1) >> 1; memcpy(pObCtx->sctx.search[0].pb, pbSearchBuffer, 32); - MSearch_ContextUpdate(ctxP, pObCtx); + MSearch_ContextUpdate(H, ctxP, pObCtx); // start search by queuing the search onto a work item // in a separate thread. also increase refcount since // worker thread is responsible for its own DECREF. pObCtx->sctx.fAbortRequested = FALSE; pObCtx->fActive = TRUE; - VmmWork((LPTHREAD_START_ROUTINE)MSearch_PerformSeach_ThreadProc, Ob_INCREF(pObCtx), NULL); + VmmWork_Ob(H, (PVMM_WORK_START_ROUTINE_OB_PFN)MSearch_PerformSeach_ThreadProc, (POB)pObCtx, NULL, VMMWORK_FLAG_PRIO_NORMAL); } - LeaveCriticalSection(&ctxVmm->LockPlugin); + LeaveCriticalSection(&H->vmm.LockPlugin); } } } @@ -249,34 +248,35 @@ NTSTATUS MSearch_ReadStatus(_In_ PMOB_SEARCH_CONTEXT ctxS, _Out_writes_to_(cb, * } } -VOID MSearch_ReadLine_CB(_Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PQWORD pe, _Out_writes_(cbLineLength + 1) LPSTR szu8) +VOID MSearch_ReadLine_CB(_In_ VMM_HANDLE H, _Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PQWORD pe, _Out_writes_(cbLineLength + 1) LPSTR szu8) { - Util_usnprintf_ln(szu8, cbLineLength, ctxVmm->f32 ? "%08x" : "%016llx", *pe); + Util_usnprintf_ln(szu8, cbLineLength, H->vmm.f32 ? "%08x" : "%016llx", *pe); } /* * Read : function as specified by the module manager. The module manager will * call into this callback function whenever a read shall occur from a "file". -* -- ctx +* -- H +* -- ctxP * -- pb * -- cb * -- pcbRead * -- cbOffset * -- return */ -NTSTATUS MSearch_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MSearch_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; PMOB_SEARCH_CONTEXT pObCtx = NULL; - if(!(pObCtx = MSearch_ContextGet(ctxP))) { return VMMDLL_STATUS_FILE_INVALID; } + if(!(pObCtx = MSearch_ContextGet(H, ctxP))) { return VMMDLL_STATUS_FILE_INVALID; } if(!_stricmp(ctxP->uszPath, "readme.txt")) { nt = Util_VfsReadFile_FromStrA(szSEARCH_README, pb, cb, pcbRead, cbOffset); } else if(!_stricmp(ctxP->uszPath, "addr-max.txt")) { - nt = ctxVmm->f32 ? + nt = H->vmm.f32 ? Util_VfsReadFile_FromDWORD((DWORD)pObCtx->sctx.vaMax, pb, cb, pcbRead, cbOffset, FALSE) : Util_VfsReadFile_FromQWORD((QWORD)pObCtx->sctx.vaMax, pb, cb, pcbRead, cbOffset, FALSE); } else if(!_stricmp(ctxP->uszPath, "addr-min.txt")) { - nt = ctxVmm->f32 ? + nt = H->vmm.f32 ? Util_VfsReadFile_FromDWORD((DWORD)pObCtx->sctx.vaMin, pb, cb, pcbRead, cbOffset, FALSE) : Util_VfsReadFile_FromQWORD((QWORD)pObCtx->sctx.vaMin, pb, cb, pcbRead, cbOffset, FALSE); } else if(!_stricmp(ctxP->uszPath, "align.txt")) { @@ -287,7 +287,7 @@ NTSTATUS MSearch_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcb nt = VMMDLL_STATUS_END_OF_FILE; if(pObCtx->pObDataResult) { nt = Util_VfsLineFixed_Read( - (UTIL_VFSLINEFIXED_PFN_CB)MSearch_ReadLine_CB, NULL, ctxVmm->f32 ? 9 : 17, NULL, + H, (UTIL_VFSLINEFIXED_PFN_CB)MSearch_ReadLine_CB, NULL, H->vmm.f32 ? 9 : 17, NULL, pObCtx->pObDataResult->pqw, pObCtx->pObDataResult->ObHdr.cbData / sizeof(QWORD), sizeof(QWORD), pb, cb, pcbRead, cbOffset ); @@ -307,22 +307,23 @@ NTSTATUS MSearch_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcb * List : function as specified by the module manager. The module manager will * call into this callback function whenever a list directory shall occur from * the given module. -* -- ctx +* -- H +* -- ctxP * -- pFileList * -- return */ -BOOL MSearch_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) +BOOL MSearch_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { DWORD cbResult = 0; PMOB_SEARCH_CONTEXT pObCtx = NULL; if(ctxP->uszPath[0]) { return FALSE; } - if(!(pObCtx = MSearch_ContextGet(ctxP))) { return FALSE; } - VMMDLL_VfsList_AddFile(pFileList, "addr-max.txt", ctxVmm->f32 ? 8 : 16, NULL); - VMMDLL_VfsList_AddFile(pFileList, "addr-min.txt", ctxVmm->f32 ? 8 : 16, NULL); + if(!(pObCtx = MSearch_ContextGet(H, ctxP))) { return FALSE; } + VMMDLL_VfsList_AddFile(pFileList, "addr-max.txt", H->vmm.f32 ? 8 : 16, NULL); + VMMDLL_VfsList_AddFile(pFileList, "addr-min.txt", H->vmm.f32 ? 8 : 16, NULL); VMMDLL_VfsList_AddFile(pFileList, "align.txt", 3, NULL); VMMDLL_VfsList_AddFile(pFileList, "readme.txt", strlen(szSEARCH_README), NULL); VMMDLL_VfsList_AddFile(pFileList, "reset.txt", 1, NULL); - cbResult = pObCtx->pObDataResult ? ((ctxVmm->f32 ? 9ULL : 17ULL) * pObCtx->pObDataResult->ObHdr.cbData / sizeof(QWORD)) : 0; + cbResult = pObCtx->pObDataResult ? ((H->vmm.f32 ? 9ULL : 17ULL) * pObCtx->pObDataResult->ObHdr.cbData / sizeof(QWORD)) : 0; VMMDLL_VfsList_AddFile(pFileList, "result.txt", cbResult, NULL); VMMDLL_VfsList_AddFile(pFileList, "search.txt", pObCtx->sctx.search[0].cb * 2ULL, NULL); VMMDLL_VfsList_AddFile(pFileList, "search-skip-bitmask.txt", pObCtx->sctx.search[0].cb * 2ULL, NULL); @@ -333,7 +334,7 @@ BOOL MSearch_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) return TRUE; } -VOID MSearch_Close(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) +VOID MSearch_Close(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP) { Ob_DECREF(ctxP->ctxM); } @@ -344,12 +345,13 @@ VOID MSearch_Close(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) * shall call the supplied pfnPluginManager_Register function. * NB! the module does not have to register itself - for example if the target * operating system or architecture is unsupported. +* -- H * -- pRI */ -VOID M_Search_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_Search_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } - if(!(pRI->reg_info.ctxM = (PVMMDLL_PLUGIN_INTERNAL_CONTEXT)ObMap_New(OB_MAP_FLAGS_OBJECT_OB))) { return; } + if(!(pRI->reg_info.ctxM = (PVMMDLL_PLUGIN_INTERNAL_CONTEXT)ObMap_New(H, OB_MAP_FLAGS_OBJECT_OB))) { return; } pRI->reg_fn.pfnList = MSearch_List; // List function supported pRI->reg_fn.pfnRead = MSearch_Read; // Read function supported pRI->reg_fn.pfnWrite = MSearch_Write; // Write function supported @@ -357,11 +359,11 @@ VOID M_Search_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) strcpy_s(pRI->reg_info.uszPathName, 128, "\\search"); pRI->reg_info.fRootModule = FALSE; pRI->reg_info.fProcessModule = TRUE; - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); // register root plugin (physical memory search) pRI->reg_fn.pfnClose = MSearch_Close; // Close function supported (but should only be called once on unload so put it here...) strcpy_s(pRI->reg_info.uszPathName, 128, "\\misc\\search"); pRI->reg_info.fRootModule = TRUE; pRI->reg_info.fProcessModule = FALSE; - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_sys.c b/vmm/m_sys.c index f0767ea..4bc411c 100644 --- a/vmm/m_sys.c +++ b/vmm/m_sys.c @@ -13,12 +13,12 @@ #include "util.h" #include "charutil.h" -VOID MSys_QueryTimeZone(_Out_writes_(49) LPSTR uszTimeZone, _In_ BOOL fLine) +VOID MSys_QueryTimeZone(_In_ VMM_HANDLE H, _Out_writes_(49) LPSTR uszTimeZone, _In_ BOOL fLine) { int iTimeZoneActiveBias = 0; CHAR uszTimeZoneName[0x20] = { 0 }; uszTimeZone[0] = 0; - if(SysQuery_TimeZone(uszTimeZoneName, &iTimeZoneActiveBias)) { + if(SysQuery_TimeZone(H, uszTimeZoneName, &iTimeZoneActiveBias)) { if(iTimeZoneActiveBias % 60) { if(fLine) { Util_usnprintf_ln(uszTimeZone, 48, "%s [UTC%+i]", uszTimeZoneName, -iTimeZoneActiveBias); @@ -39,66 +39,66 @@ VOID MSys_QueryTimeZone(_Out_writes_(49) LPSTR uszTimeZone, _In_ BOOL fLine) uszTimeZone[48] = 0; } -NTSTATUS MSys_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MSys_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { DWORD cbBuffer, cbData; BYTE pbBuffer[0x42] = { 0 }; BYTE pbRegData[0x42] = { 0 }; CHAR szTimeZone[64] = { 0 }; // version.txt - if(!_stricmp(ctx->uszPath, "version.txt")) { - cbBuffer = snprintf(pbBuffer, sizeof(pbBuffer), "%i.%i.%i", ctxVmm->kernel.dwVersionMajor, ctxVmm->kernel.dwVersionMinor, ctxVmm->kernel.dwVersionBuild); + if(!_stricmp(ctxP->uszPath, "version.txt")) { + cbBuffer = snprintf(pbBuffer, sizeof(pbBuffer), "%i.%i.%i", H->vmm.kernel.dwVersionMajor, H->vmm.kernel.dwVersionMinor, H->vmm.kernel.dwVersionBuild); return Util_VfsReadFile_FromPBYTE(pbBuffer, cbBuffer, pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "version-major.txt")) { - return Util_VfsReadFile_FromNumber(ctxVmm->kernel.dwVersionMajor, pb, cb, pcbRead, cbOffset); + if(!_stricmp(ctxP->uszPath, "version-major.txt")) { + return Util_VfsReadFile_FromNumber(H->vmm.kernel.dwVersionMajor, pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "version-minor.txt")) { - return Util_VfsReadFile_FromNumber(ctxVmm->kernel.dwVersionMinor, pb, cb, pcbRead, cbOffset); + if(!_stricmp(ctxP->uszPath, "version-minor.txt")) { + return Util_VfsReadFile_FromNumber(H->vmm.kernel.dwVersionMinor, pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "version-build.txt")) { - return Util_VfsReadFile_FromNumber(ctxVmm->kernel.dwVersionBuild, pb, cb, pcbRead, cbOffset); + if(!_stricmp(ctxP->uszPath, "version-build.txt")) { + return Util_VfsReadFile_FromNumber(H->vmm.kernel.dwVersionBuild, pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "unique-tag.txt")) { - return Util_VfsReadFile_FromPBYTE(ctxVmm->szSystemUniqueTag, strlen(ctxVmm->szSystemUniqueTag), pb, cb, pcbRead, cbOffset); + if(!_stricmp(ctxP->uszPath, "unique-tag.txt")) { + return Util_VfsReadFile_FromPBYTE(H->vmm.szSystemUniqueTag, strlen(H->vmm.szSystemUniqueTag), pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "architecture.txt")) { + if(!_stricmp(ctxP->uszPath, "architecture.txt")) { return Util_VfsReadFile_FromPBYTE( - VMM_MEMORYMODEL_TOSTRING[ctxVmm->tpMemoryModel], - strlen(VMM_MEMORYMODEL_TOSTRING[ctxVmm->tpMemoryModel]), + VMM_MEMORYMODEL_TOSTRING[H->vmm.tpMemoryModel], + strlen(VMM_MEMORYMODEL_TOSTRING[H->vmm.tpMemoryModel]), pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "computername.txt")) { - VmmWinReg_ValueQuery2("HKLM\\SYSTEM\\ControlSet001\\Control\\ComputerName\\ComputerName\\ComputerName", NULL, pbRegData, sizeof(pbRegData) - 2, &cbData); + if(!_stricmp(ctxP->uszPath, "computername.txt")) { + VmmWinReg_ValueQuery2(H, "HKLM\\SYSTEM\\ControlSet001\\Control\\ComputerName\\ComputerName\\ComputerName", NULL, pbRegData, sizeof(pbRegData) - 2, &cbData); CharUtil_WtoU((LPWSTR)pbRegData, cbData << 1, pbBuffer, sizeof(pbBuffer), NULL, NULL, CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR | CHARUTIL_FLAG_STR_BUFONLY); return Util_VfsReadFile_FromPBYTE(pbBuffer, 32, pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "time-boot.txt")) { - return Util_VfsReadFile_FromFILETIME(ctxVmm->kernel.opt.ftBootTime, pb, cb, pcbRead, cbOffset); + if(!_stricmp(ctxP->uszPath, "time-boot.txt")) { + return Util_VfsReadFile_FromFILETIME(H->vmm.kernel.opt.ftBootTime, pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "time-current.txt")) { - return Util_VfsReadFile_FromFILETIME(SysQuery_TimeCurrent(), pb, cb, pcbRead, cbOffset); + if(!_stricmp(ctxP->uszPath, "time-current.txt")) { + return Util_VfsReadFile_FromFILETIME(SysQuery_TimeCurrent(H), pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "timezone.txt")) { - MSys_QueryTimeZone(szTimeZone, TRUE); + if(!_stricmp(ctxP->uszPath, "timezone.txt")) { + MSys_QueryTimeZone(H, szTimeZone, TRUE); return Util_VfsReadFile_FromPBYTE(szTimeZone, 48, pb, cb, pcbRead, cbOffset); } return VMMDLL_STATUS_FILE_INVALID; } -BOOL MSys_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) +BOOL MSys_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { DWORD cchMajor, cchMinor, cchBuild; - if(ctx->uszPath[0]) { return FALSE; } - cchMajor = Util_GetNumDigits(ctxVmm->kernel.dwVersionMajor); - cchMinor = Util_GetNumDigits(ctxVmm->kernel.dwVersionMinor); - cchBuild = Util_GetNumDigits(ctxVmm->kernel.dwVersionBuild); + if(ctxP->uszPath[0]) { return FALSE; } + cchMajor = Util_GetNumDigits(H->vmm.kernel.dwVersionMajor); + cchMinor = Util_GetNumDigits(H->vmm.kernel.dwVersionMinor); + cchBuild = Util_GetNumDigits(H->vmm.kernel.dwVersionBuild); VMMDLL_VfsList_AddFile(pFileList, "version.txt", 2ULL + cchMajor + cchMinor + cchBuild, NULL); VMMDLL_VfsList_AddFile(pFileList, "version-major.txt", cchMajor, NULL); VMMDLL_VfsList_AddFile(pFileList, "version-minor.txt", cchMinor, NULL); VMMDLL_VfsList_AddFile(pFileList, "version-build.txt", cchBuild, NULL); - VMMDLL_VfsList_AddFile(pFileList, "unique-tag.txt", strlen(ctxVmm->szSystemUniqueTag), NULL); - VMMDLL_VfsList_AddFile(pFileList, "architecture.txt", strlen(VMM_MEMORYMODEL_TOSTRING[ctxVmm->tpMemoryModel]), NULL); + VMMDLL_VfsList_AddFile(pFileList, "unique-tag.txt", strlen(H->vmm.szSystemUniqueTag), NULL); + VMMDLL_VfsList_AddFile(pFileList, "architecture.txt", strlen(VMM_MEMORYMODEL_TOSTRING[H->vmm.tpMemoryModel]), NULL); VMMDLL_VfsList_AddFile(pFileList, "computername.txt", 32, NULL); VMMDLL_VfsList_AddFile(pFileList, "time-boot.txt", 24, NULL); VMMDLL_VfsList_AddFile(pFileList, "time-current.txt", 24, NULL); @@ -106,32 +106,32 @@ BOOL MSys_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) return TRUE; } -VOID MSys_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) +VOID MSys_FcLogJSON(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) { PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd; CHAR usz[MAX_PATH], szTimeBoot[24], szTimeCurrent[24], szTimeZone[64]; BYTE pbComputerName[0x42] = { 0 }; if(ctxP->pProcess || !(pd = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMDLL_PLUGIN_FORENSIC_JSONDATA)))) { return; } - Util_FileTime2String(ctxVmm->kernel.opt.ftBootTime, szTimeBoot); - Util_FileTime2String(SysQuery_TimeCurrent(), szTimeCurrent); - MSys_QueryTimeZone(szTimeZone, FALSE); - VmmWinReg_ValueQuery2("HKLM\\SYSTEM\\ControlSet001\\Control\\ComputerName\\ComputerName\\ComputerName", NULL, pbComputerName, sizeof(pbComputerName) - 2, NULL); + Util_FileTime2String(H->vmm.kernel.opt.ftBootTime, szTimeBoot); + Util_FileTime2String(SysQuery_TimeCurrent(H), szTimeCurrent); + MSys_QueryTimeZone(H, szTimeZone, FALSE); + VmmWinReg_ValueQuery2(H, "HKLM\\SYSTEM\\ControlSet001\\Control\\ComputerName\\ComputerName\\ComputerName", NULL, pbComputerName, sizeof(pbComputerName) - 2, NULL); snprintf(usz, sizeof(usz), "architecture:[%s] version:[%i.%i.%i] time-boot:[%s] time-current:[%s], timezone:[%s]", - VMM_MEMORYMODEL_TOSTRING[ctxVmm->tpMemoryModel], - ctxVmm->kernel.dwVersionMajor, ctxVmm->kernel.dwVersionMinor, ctxVmm->kernel.dwVersionBuild, + VMM_MEMORYMODEL_TOSTRING[H->vmm.tpMemoryModel], + H->vmm.kernel.dwVersionMajor, H->vmm.kernel.dwVersionMinor, H->vmm.kernel.dwVersionBuild, szTimeBoot, szTimeCurrent, szTimeZone ); pd->dwVersion = VMMDLL_PLUGIN_FORENSIC_JSONDATA_VERSION; pd->szjType = "systeminformation"; - pd->vaObj = ctxVmm->kernel.vaBase; - pd->va[0] = ctxVmm->kernel.opt.KDBG.va; + pd->vaObj = H->vmm.kernel.vaBase; + pd->va[0] = H->vmm.kernel.opt.KDBG.va; pd->wsz[0] = (LPCWSTR)pbComputerName; pd->usz[1] = usz; - pfnLogJSON(pd); + pfnLogJSON(H, pd); LocalFree(pd); } -VOID M_Sys_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_Sys_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if((pRI->tpSystem != VMM_SYSTEM_WINDOWS_X64) && (pRI->tpSystem != VMM_SYSTEM_WINDOWS_X86)) { return; } @@ -140,5 +140,5 @@ VOID M_Sys_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) pRI->reg_fn.pfnList = MSys_List; // List function supported pRI->reg_fn.pfnRead = MSys_Read; // Read function supported pRI->reg_fnfc.pfnLogJSON = MSys_FcLogJSON; // JSON log function supported - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_sys_cert.c b/vmm/m_sys_cert.c index bc09826..d7e9b7d 100644 --- a/vmm/m_sys_cert.c +++ b/vmm/m_sys_cert.c @@ -37,7 +37,7 @@ VOID MSysCert_CallbackCleanup(PMSYSCERT_OB_ENTRY pOb) LocalFree(pOb->uszSubjectCN); } -VOID MSysCert_GetContext_UserAddSingleCert(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY pkStore, _In_ POB_REGISTRY_KEY pkCert, _In_opt_ PVMM_MAP_USERENTRY pUser, _Inout_ POB_MAP pmCtx) +VOID MSysCert_GetContext_UserAddSingleCert(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY pkStore, _In_ POB_REGISTRY_KEY pkCert, _In_opt_ PVMM_MAP_USERENTRY pUser, _Inout_ POB_MAP pmCtx) { DWORD o, cb, cch; BYTE pb[0x1800]; @@ -48,10 +48,10 @@ VOID MSysCert_GetContext_UserAddSingleCert(_In_ POB_REGISTRY_HIVE pHive, _In_ PO VMM_REGISTRY_VALUE_INFO ValueInfo = { 0 }; VMM_REGISTRY_KEY_INFO KeyCertInfo = { 0 }; VMM_REGISTRY_KEY_INFO KeyStoreInfo = { 0 }; - if(!(pObValue = VmmWinReg_KeyValueGetByName(pHive, pkCert, "Blob"))) { + if(!(pObValue = VmmWinReg_KeyValueGetByName(H, pHive, pkCert, "Blob"))) { goto fail; } - if(!VmmWinReg_ValueQuery4(pHive, pObValue, NULL, pb, sizeof(pb), &cb) || (cb < 0x20)) { + if(!VmmWinReg_ValueQuery4(H, pHive, pObValue, NULL, pb, sizeof(pb), &cb) || (cb < 0x20)) { goto fail; } VmmWinReg_KeyInfo(pHive, pkCert, &KeyCertInfo); @@ -72,7 +72,7 @@ VOID MSysCert_GetContext_UserAddSingleCert(_In_ POB_REGISTRY_HIVE pHive, _In_ PO if(!(pCertContext = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, pb + o, cb + 10))) { goto fail; } - if(!(pObResult = Ob_Alloc('Pcer', LMEM_ZEROINIT, sizeof(MSYSCERT_OB_ENTRY), MSysCert_CallbackCleanup, NULL))) { + if(!(pObResult = Ob_AllocEx(H, OB_TAG_MOD_CERTIFICATES, LMEM_ZEROINIT, sizeof(MSYSCERT_OB_ENTRY), MSysCert_CallbackCleanup, NULL))) { goto fail; } // Subject CN @@ -103,21 +103,21 @@ fail: Ob_DECREF(pObValue); } -VOID MSysCert_GetContext_UserAddCerts(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY pKeySystemCertificates, _In_opt_ PVMM_MAP_USERENTRY pUserEntry, _Inout_ POB_MAP pmCtx) +VOID MSysCert_GetContext_UserAddCerts(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY pKeySystemCertificates, _In_opt_ PVMM_MAP_USERENTRY pUserEntry, _Inout_ POB_MAP pmCtx) { POB_REGISTRY_KEY pkObCertStore = NULL, pkObCertStoreCerts = NULL, pkObCert = NULL; POB_MAP pmkObCertStores = NULL, pmObCerts = NULL; - if(!(pmkObCertStores = VmmWinReg_KeyList(pHive, pKeySystemCertificates))) { return; } + if(!(pmkObCertStores = VmmWinReg_KeyList(H, pHive, pKeySystemCertificates))) { return; } while((pkObCertStore = ObMap_GetNext(pmkObCertStores, pkObCertStore))) { - pkObCertStoreCerts = VmmWinReg_KeyGetByChildName(pHive, pkObCertStore, "Certificates"); - if(!pkObCertStoreCerts) { continue; } - if((pmObCerts = VmmWinReg_KeyList(pHive, pkObCertStoreCerts))) { - while((pkObCert = ObMap_GetNext(pmObCerts, pkObCert))) { - MSysCert_GetContext_UserAddSingleCert(pHive, pkObCertStore, pkObCert, pUserEntry, pmCtx); + if((pkObCertStoreCerts = VmmWinReg_KeyGetByChildName(H, pHive, pkObCertStore, "Certificates"))) { + if((pmObCerts = VmmWinReg_KeyList(H, pHive, pkObCertStoreCerts))) { + while((pkObCert = ObMap_GetNext(pmObCerts, pkObCert))) { + MSysCert_GetContext_UserAddSingleCert(H, pHive, pkObCertStore, pkObCert, pUserEntry, pmCtx); + } + Ob_DECREF_NULL(&pmObCerts); } - Ob_DECREF_NULL(&pmObCerts); + Ob_DECREF_NULL(&pkObCertStoreCerts); } - Ob_DECREF_NULL(&pkObCertStoreCerts); } Ob_DECREF_NULL(&pmkObCertStores); } @@ -128,7 +128,7 @@ VOID MSysCert_GetContext_UserAddCerts(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REG * -- return */ _Success_(return != NULL) -POB_MAP MSysCert_GetContext(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) +POB_MAP MSysCert_GetContext(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP) { LPSTR uszCertStoresUSER[] = { "ROOT\\Software\\Microsoft\\SystemCertificates", "ROOT\\Software\\Policies\\Microsoft\\SystemCertificates" }; LPSTR uszCertStoresSYSTEM[] = { "HKLM\\SOFTWARE\\Microsoft\\SystemCertificates", "HKLM\\SOFTWARE\\Policies\\Microsoft\\SystemCertificates" }; @@ -139,24 +139,24 @@ POB_MAP MSysCert_GetContext(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) POB_REGISTRY_HIVE pObHive = NULL; POB_CONTAINER ctxM = (POB_CONTAINER)ctxP->ctxM; if((pObCtx = ObContainer_GetOb(ctxM))) { return pObCtx; } - EnterCriticalSection(&ctxVmm->LockUpdateModule); + EnterCriticalSection(&H->vmm.LockUpdateModule); if((pObCtx = ObContainer_GetOb(ctxM))) { goto finish; } - if(!(pObCtx = ObMap_New(OB_MAP_FLAGS_OBJECT_OB))) { goto finish; } + if(!(pObCtx = ObMap_New(H, OB_MAP_FLAGS_OBJECT_OB))) { goto finish; } // Retrieve system (local machine) certificates: for(i = 0; i < sizeof(uszCertStoresSYSTEM) / sizeof(LPSTR); i++) { - if(VmmWinReg_KeyHiveGetByFullPath(uszCertStoresSYSTEM[i], &pObHive, &pObKey)) { - MSysCert_GetContext_UserAddCerts(pObHive, pObKey, NULL, pObCtx); + if(VmmWinReg_KeyHiveGetByFullPath(H, uszCertStoresSYSTEM[i], &pObHive, &pObKey)) { + MSysCert_GetContext_UserAddCerts(H, pObHive, pObKey, NULL, pObCtx); Ob_DECREF_NULL(&pObKey); Ob_DECREF_NULL(&pObHive); } } // Retrieve user certificates: - if(VmmMap_GetUser(&pObUserMap)) { + if(VmmMap_GetUser(H, &pObUserMap)) { for(iMap = 0; iMap < pObUserMap->cMap; iMap++) { - if((pObHive = VmmWinReg_HiveGetByAddress(pObUserMap->pMap[iMap].vaRegHive))) { + if((pObHive = VmmWinReg_HiveGetByAddress(H, pObUserMap->pMap[iMap].vaRegHive))) { for(i = 0; i < sizeof(uszCertStoresUSER) / sizeof(LPSTR); i++) { - if((pObKey = VmmWinReg_KeyGetByPath(pObHive, uszCertStoresUSER[i]))) { - MSysCert_GetContext_UserAddCerts(pObHive, pObKey, pObUserMap->pMap + iMap, pObCtx); + if((pObKey = VmmWinReg_KeyGetByPath(H, pObHive, uszCertStoresUSER[i]))) { + MSysCert_GetContext_UserAddCerts(H, pObHive, pObKey, pObUserMap->pMap + iMap, pObCtx); Ob_DECREF_NULL(&pObKey); } } @@ -167,11 +167,11 @@ POB_MAP MSysCert_GetContext(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) } ObContainer_SetOb(ctxM, pObCtx); finish: - LeaveCriticalSection(&ctxVmm->LockUpdateModule); + LeaveCriticalSection(&H->vmm.LockUpdateModule); return pObCtx; } -NTSTATUS MSysCert_Read_Cert(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MSysCert_Read_Cert(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; BYTE pbCertBuffer[0x1800]; @@ -185,11 +185,11 @@ NTSTATUS MSysCert_Read_Cert(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb if(!(cch = strlen(ctxP->uszPath)) || (cch < 20)) { goto fail; } if(_stricmp(ctxP->uszPath + cch - 4, ".cer")) { goto fail; } if(!(qwIdMapKey = strtoull(ctxP->uszPath + cch - 20, NULL, 16))) { goto fail; } - if(!(pmOb = MSysCert_GetContext(ctxP))) { goto fail; } + if(!(pmOb = MSysCert_GetContext(H, ctxP))) { goto fail; } if(!(pObEntry = ObMap_GetByKey(pmOb, qwIdMapKey))) { goto fail; } - if(!(pObHive = VmmWinReg_HiveGetByAddress(pObEntry->vaHive))) { goto fail; } - if(!(pObValue = VmmWinReg_KeyValueGetByOffset(pObHive, pObEntry->oRegCellValue))) { goto fail; } - if(!VmmWinReg_ValueQuery4(pObHive, pObValue, NULL, pbCertBuffer, sizeof(pbCertBuffer), &cbCertBuffer)) { goto fail; } + if(!(pObHive = VmmWinReg_HiveGetByAddress(H, pObEntry->vaHive))) { goto fail; } + if(!(pObValue = VmmWinReg_KeyValueGetByOffset(H, pObHive, pObEntry->oRegCellValue))) { goto fail; } + if(!VmmWinReg_ValueQuery4(H, pObHive, pObValue, NULL, pbCertBuffer, sizeof(pbCertBuffer), &cbCertBuffer)) { goto fail; } if(cb < pObEntry->oRegBlob) { goto fail; } cbCertBuffer = min(pObEntry->cbCert, cbCertBuffer - pObEntry->oRegBlob); nt = Util_VfsReadFile_FromPBYTE(pbCertBuffer + pObEntry->oRegBlob, cbCertBuffer, pb, cb, pcbRead, cbOffset); @@ -201,7 +201,7 @@ fail: return nt; } -VOID MSysCert_Read_InfoFile_GetUserName(_In_ PVMMOB_MAP_USER pUserMap, _In_ DWORD dwHashSid, _Out_writes_(17) LPSTR uszUserName) +VOID MSysCert_Read_InfoFile_GetUserName(_In_ VMM_HANDLE H, _In_ PVMMOB_MAP_USER pUserMap, _In_ DWORD dwHashSid, _Out_writes_(17) LPSTR uszUserName) { DWORD i; if(0 == dwHashSid) { @@ -217,7 +217,7 @@ VOID MSysCert_Read_InfoFile_GetUserName(_In_ PVMMOB_MAP_USER pUserMap, _In_ DWOR uszUserName[0] = 0; } -NTSTATUS MSysCert_Read_InfoFile2(_In_ POB_MAP pmCertificates, _In_ PVMMOB_MAP_USER pUserMap, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MSysCert_Read_InfoFile2(_In_ VMM_HANDLE H, _In_ POB_MAP pmCertificates, _In_ PVMMOB_MAP_USER pUserMap, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; LPSTR sz; @@ -234,8 +234,8 @@ NTSTATUS MSysCert_Read_InfoFile2(_In_ POB_MAP pmCertificates, _In_ PVMMOB_MAP_US if(!(sz = LocalAlloc(LMEM_ZEROINIT, (SIZE_T)cbMax))) { return VMMDLL_STATUS_FILE_INVALID; } for(i = cStart; i <= cEnd; i++) { peOb = ObMap_GetByIndex(pmCertificates, (DWORD)i); - fWellKnown = InfoDB_CertIsWellKnown(peOb->qwIdMapKey); - MSysCert_Read_InfoFile_GetUserName(pUserMap, peOb->dwHashUserSID, szUserName); + fWellKnown = InfoDB_CertIsWellKnown(H, peOb->qwIdMapKey); + MSysCert_Read_InfoFile_GetUserName(H, pUserMap, peOb->dwHashUserSID, szUserName); o += Util_usnprintf_ln( sz + o, cbLINELENGTH, @@ -248,20 +248,21 @@ NTSTATUS MSysCert_Read_InfoFile2(_In_ POB_MAP pmCertificates, _In_ PVMMOB_MAP_US (fWellKnown ? ' ' : '*'), peOb->uszIdHash ); + Ob_DECREF_NULL(&peOb); } nt = Util_VfsReadFile_FromPBYTE(sz, cbMax - 1, pb, cb, pcbRead, cbOffset - cStart * cbLINELENGTH); LocalFree(sz); return nt; } -NTSTATUS MSysCert_Read_InfoFile(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MSysCert_Read_InfoFile(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; POB_MAP pmObCtx = NULL; PVMMOB_MAP_USER pObUserMap = NULL; - if(!VmmMap_GetUser(&pObUserMap)) { goto fail; } - if(!(pmObCtx = MSysCert_GetContext(ctxP))) { goto fail; } - nt = MSysCert_Read_InfoFile2(pmObCtx, pObUserMap, pb, cb, pcbRead, cbOffset); + if(!VmmMap_GetUser(H, &pObUserMap)) { goto fail; } + if(!(pmObCtx = MSysCert_GetContext(H, ctxP))) { goto fail; } + nt = MSysCert_Read_InfoFile2(H, pmObCtx, pObUserMap, pb, cb, pcbRead, cbOffset); fail: Ob_DECREF(pmObCtx); Ob_DECREF(pObUserMap); @@ -269,20 +270,20 @@ fail: } -NTSTATUS MSysCert_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MSysCert_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { - return _stricmp(ctxP->uszPath, "certificates.txt") ? MSysCert_Read_Cert(ctxP, pb, cb, pcbRead, cbOffset) : MSysCert_Read_InfoFile(ctxP, pb, cb, pcbRead, cbOffset); + return _stricmp(ctxP->uszPath, "certificates.txt") ? MSysCert_Read_Cert(H, ctxP, pb, cb, pcbRead, cbOffset) : MSysCert_Read_InfoFile(H, ctxP, pb, cb, pcbRead, cbOffset); } -BOOL MSysCert_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) +BOOL MSysCert_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { DWORD i, dwHashUserSID = 0; CHAR usz[MAX_PATH]; POB_MAP pmObCtx = NULL; PVMMOB_MAP_USER pObUserMap = NULL; PMSYSCERT_OB_ENTRY pObEntry = NULL; - if(!VmmMap_GetUser(&pObUserMap)) { goto fail; } - if(!(pmObCtx = MSysCert_GetContext(ctxP))) { goto fail; } + if(!VmmMap_GetUser(H, &pObUserMap)) { goto fail; } + if(!(pmObCtx = MSysCert_GetContext(H, ctxP))) { goto fail; } if(!ctxP->uszPath[0]) { // ROOT VMMDLL_VfsList_AddFile(pFileList, "certificates.txt", ObMap_Size(pmObCtx) * MSYSCERT_LINE_LENGTH, NULL); @@ -314,7 +315,7 @@ fail: return TRUE; } -VOID MSysCert_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) +VOID MSysCert_FcLogJSON(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) { PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd; POB_MAP pmObCerts = NULL; @@ -324,14 +325,14 @@ VOID MSysCert_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON) if(ctxP->pProcess || !(pd = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMDLL_PLUGIN_FORENSIC_JSONDATA)))) { return; } pd->dwVersion = VMMDLL_PLUGIN_FORENSIC_JSONDATA_VERSION; pd->szjType = "certificate"; - if((pmObCerts = MSysCert_GetContext(ctxP))) { + if((pmObCerts = MSysCert_GetContext(H, ctxP))) { for(i = 0, iMax = ObMap_Size(pmObCerts); i < iMax; i++) { if((peOb = ObMap_GetByIndex(pmObCerts, (DWORD)i))) { snprintf(usz, _countof(usz), "store:[%s] thumbprint:[%s] issuer:[%s]", peOb->uszStore, peOb->uszIdHash, peOb->uszIssuerCN); pd->i = i; pd->usz[0] = peOb->uszSubjectCN; pd->usz[1] = usz; - pfnLogJSON(pd); + pfnLogJSON(H, pd); Ob_DECREF_NULL(&peOb); } } @@ -340,7 +341,7 @@ VOID MSysCert_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON) LocalFree(pd); } -VOID MSysCert_Notify(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent) +VOID MSysCert_Notify(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent) { POB_CONTAINER ctxM = (POB_CONTAINER)ctxP->ctxM; if(fEvent == VMMDLL_PLUGIN_NOTIFY_REFRESH_SLOW) { @@ -348,13 +349,12 @@ VOID MSysCert_Notify(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ DWORD fEvent, _In_op } } -VOID MSysCert_Close(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) +VOID MSysCert_Close(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP) { - POB_CONTAINER ctxM = (POB_CONTAINER)ctxP->ctxM; - Ob_DECREF(ctxM); + Ob_DECREF((POB_CONTAINER)ctxP->ctxM); } -VOID M_SysCert_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_SysCert_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if((pRI->tpSystem != VMM_SYSTEM_WINDOWS_X64) && (pRI->tpSystem != VMM_SYSTEM_WINDOWS_X86)) { return; } @@ -366,5 +366,5 @@ VOID M_SysCert_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) pRI->reg_fn.pfnClose = MSysCert_Close; // Close function supported pRI->reg_fn.pfnNotify = MSysCert_Notify; // Notify function supported pRI->reg_fnfc.pfnLogJSON = MSysCert_FcLogJSON; // JSON log function supported - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_sys_driver.c b/vmm/m_sys_driver.c index 3577475..0400364 100644 --- a/vmm/m_sys_driver.c +++ b/vmm/m_sys_driver.c @@ -7,15 +7,18 @@ // Author: Ulf Frisk, pcileech@frizk.net // #include "vmm.h" +#include "fc.h" #include "charutil.h" #include "util.h" #include "pluginmanager.h" #include "vmmwinobj.h" #include "vmmwindef.h" -#define MSYSDRIVER_DRV_LINELENGTH 128ULL +static LPSTR MSYSDRIVER_CSV_DRIVERS = "Name,ObjectAddress,Size,Start,End,ServiceKey,DriverName,DriverPath\n"; + +#define MSYSDRIVER_DRV_LINELENGTH 256ULL #define MSYSDRIVER_IRP_LINELENGTH 88ULL -#define MSYSDRIVER_DRV_LINEHEADER " # Object Address Driver Size Drv Range: Start-End Service Key Driver Name" +#define MSYSDRIVER_DRV_LINEHEADER " # Object Address Driver Size Drv Range: Start-End Service Key Driver Name Driver Path" #define MSYSDRIVER_IRP_LINEHEADER " # Driver # IRP_MJ_* Address Target Module" #define MSYSDRIVER_IRP_STR (LPCSTR[]){ \ @@ -67,7 +70,7 @@ int MSysDriver_PteCmpFind(_In_ QWORD va, _In_ QWORD qwEntry) /* * Line callback function to print a single driver/irp line. */ -VOID MSysDriver_IrpReadLine_Callback(_In_ PMSYSDRIVER_IRP_CONTEXT ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVOID pv, _Out_writes_(cbLineLength + 1) LPSTR usz) +VOID MSysDriver_IrpReadLineCB(_In_ VMM_HANDLE H, _In_ PMSYSDRIVER_IRP_CONTEXT ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVOID pv, _Out_writes_(cbLineLength + 1) LPSTR usz) { PVMM_MAP_PTEENTRY pePte; PVMM_MAP_KDRIVERENTRY pe; @@ -78,7 +81,7 @@ VOID MSysDriver_IrpReadLine_Callback(_In_ PMSYSDRIVER_IRP_CONTEXT ctx, _In_ DWOR iIrp = ie % 28; pe = ctx->pDrvMap->pMap + iDrv; vaIrp = pe->MajorFunction[iIrp]; - if(vaIrp == ctxVmm->kernel.opt.vaIopInvalidDeviceRequest) { + if(vaIrp == H->vmm.kernel.opt.vaIopInvalidDeviceRequest) { uszTxt = "---"; } else if((vaIrp >= pe->vaStart) && (vaIrp < pe->vaStart + pe->cbDriverSize)) { uszTxt = pe->uszName; @@ -96,10 +99,12 @@ VOID MSysDriver_IrpReadLine_Callback(_In_ PMSYSDRIVER_IRP_CONTEXT ctx, _In_ DWOR ); } -VOID MSysDriver_DrvReadLine_Callback(_Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_KDRIVERENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR usz) +VOID MSysDriver_DrvReadLineCB(_In_ VMM_HANDLE H, _In_ POB_MAP pmModuleByVA, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_KDRIVERENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR usz) { + PVMMOB_MAP_MODULE pObModuleMap = NULL; + PVMM_MAP_MODULEENTRY peModule = ObMap_GetByKey(pmModuleByVA, pe->vaStart); Util_usnprintf_ln(usz, cbLineLength, - "%04x %16llx %-16.16s %8llx %16llx-%16llx %-16.16s %s", + "%04x %16llx %-16.16s %8llx %16llx-%16llx %-16.16s %-32.32s %s", ie, pe->va, pe->uszName, @@ -107,7 +112,8 @@ VOID MSysDriver_DrvReadLine_Callback(_Inout_opt_ PVOID ctx, _In_ DWORD cbLineLen pe->vaStart, pe->cbDriverSize ? (pe->vaStart + pe->cbDriverSize - 1) : pe->vaStart, pe->uszServiceKeyName, - pe->uszPath + pe->uszPath, + (peModule && peModule->uszFullName) ? peModule->uszFullName : "" ); } @@ -129,77 +135,111 @@ BOOL MSysDriver_EntryFromPath(_In_ LPSTR uszPath, _In_ PVMMOB_MAP_KDRIVER pDrvMa return FALSE; } -NTSTATUS MSysDriver_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MSysDriver_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; - PVMM_MAP_KDRIVERENTRY pe; + PVMM_MAP_KDRIVERENTRY peDriver; PVMMOB_MAP_PTE pObPteMap = NULL; PVMMOB_MAP_KDRIVER pObDrvMap = NULL; PVMM_PROCESS pObSystemProcess = NULL; MSYSDRIVER_IRP_CONTEXT IrpCtx = { 0 }; - if(!VmmMap_GetKDriver(&pObDrvMap)) { goto cleanup; } - if(!_stricmp(ctx->uszPath, "drivers.txt")) { + PVMMOB_MAP_MODULE pObModuleMap = NULL; + POB_MAP pmObModuleByVA = NULL; + CHAR uszBuffer[MAX_PATH]; + LPSTR uszPath; + if(!VmmMap_GetKDriver(H, &pObDrvMap)) { goto cleanup; } + if(!(pObSystemProcess = VmmProcessGet(H, 4))) { goto cleanup; } + if(!_stricmp(ctxP->uszPath, "drivers.txt")) { + if(VmmMap_GetModule(H, pObSystemProcess, &pObModuleMap)) { + VmmMap_GetModuleEntryEx3(H, pObModuleMap, &pmObModuleByVA); + } nt = Util_VfsLineFixed_Read( - (UTIL_VFSLINEFIXED_PFN_CB)MSysDriver_DrvReadLine_Callback, NULL, MSYSDRIVER_DRV_LINELENGTH, MSYSDRIVER_DRV_LINEHEADER, + H, (UTIL_VFSLINEFIXED_PFN_CB)MSysDriver_DrvReadLineCB, pmObModuleByVA, MSYSDRIVER_DRV_LINELENGTH, MSYSDRIVER_DRV_LINEHEADER, pObDrvMap->pMap, pObDrvMap->cMap, sizeof(VMM_MAP_KDRIVERENTRY), pb, cb, pcbRead, cbOffset ); goto cleanup; } - if(!_stricmp(ctx->uszPath, "driver_irp.txt")) { - if(!(pObSystemProcess = VmmProcessGet(4))) { goto cleanup; } - if(!VmmMap_GetPte(pObSystemProcess, &pObPteMap, TRUE)) { goto cleanup; } + if(!_stricmp(ctxP->uszPath, "driver_irp.txt")) { + if(!VmmMap_GetPte(H, pObSystemProcess, &pObPteMap, TRUE)) { goto cleanup; } IrpCtx.pDrvMap = pObDrvMap; IrpCtx.pPteMap = pObPteMap; nt = Util_VfsLineFixed_Read( - (UTIL_VFSLINEFIXED_PFN_CB)MSysDriver_IrpReadLine_Callback, &IrpCtx, MSYSDRIVER_IRP_LINELENGTH, MSYSDRIVER_IRP_LINEHEADER, + H, (UTIL_VFSLINEFIXED_PFN_CB)MSysDriver_IrpReadLineCB, &IrpCtx, MSYSDRIVER_IRP_LINELENGTH, MSYSDRIVER_IRP_LINEHEADER, pObDrvMap->pMap, pObDrvMap->cMap * 28ULL, 0, pb, cb, pcbRead, cbOffset ); goto cleanup; } - if(!_strnicmp("by-name\\", ctx->uszPath, 8)) { - if(MSysDriver_EntryFromPath(ctx->uszPath, pObDrvMap, &pe, NULL)) { - nt = VmmWinObjDisplay_VfsRead(ctx->uszPath, ctxVmm->ObjectTypeTable.tpDriver, pe->va, pb, cb, pcbRead, cbOffset); - goto cleanup; + if(!_strnicmp("by-name\\", ctxP->uszPath, 8)) { + if(MSysDriver_EntryFromPath(ctxP->uszPath, pObDrvMap, &peDriver, NULL)) { + uszPath = CharUtil_PathSplitNext(ctxP->uszPath); + uszPath = CharUtil_PathSplitNext(uszPath); + if(strstr(uszPath, "\\")) { + // module directory + _snprintf_s(uszBuffer, _countof(uszBuffer), _TRUNCATE, "modules\\%s", uszPath); + nt = PluginManager_Read(H, pObSystemProcess, uszBuffer, pb, cb, pcbRead, cbOffset); + } else { + // driver object directory + nt = VmmWinObjDisplay_VfsRead(H, ctxP->uszPath, H->vmm.ObjectTypeTable.tpDriver, peDriver->va, pb, cb, pcbRead, cbOffset); + } } + goto cleanup; } cleanup: Ob_DECREF(pObDrvMap); Ob_DECREF(pObPteMap); + Ob_DECREF(pObModuleMap); + Ob_DECREF(pmObModuleByVA); Ob_DECREF(pObSystemProcess); return nt; } -BOOL MSysDriver_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) +BOOL MSysDriver_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { DWORD i; + CHAR uszBuffer[MAX_PATH]; LPSTR uszPath; - PVMM_MAP_KDRIVERENTRY pe; + PVMM_MAP_KDRIVERENTRY peDriver; PVMMOB_MAP_KDRIVER pObDrvMap = NULL; - if(!VmmMap_GetKDriver(&pObDrvMap)) { goto finish; } - if(!ctx->uszPath[0]) { + PVMM_MAP_MODULEENTRY peModule; + PVMMOB_MAP_MODULE pObModuleMap = NULL; + PVMM_PROCESS pObSystemProcess = NULL; + if(!VmmMap_GetKDriver(H, &pObDrvMap)) { goto finish; } + if(!ctxP->uszPath[0]) { VMMDLL_VfsList_AddDirectory(pFileList, "by-name", NULL); - VMMDLL_VfsList_AddFile(pFileList, "drivers.txt", UTIL_VFSLINEFIXED_LINECOUNT(pObDrvMap->cMap) * MSYSDRIVER_DRV_LINELENGTH, NULL); - VMMDLL_VfsList_AddFile(pFileList, "driver_irp.txt", UTIL_VFSLINEFIXED_LINECOUNT(pObDrvMap->cMap * 28ULL) * MSYSDRIVER_IRP_LINELENGTH, NULL); + VMMDLL_VfsList_AddFile(pFileList, "drivers.txt", UTIL_VFSLINEFIXED_LINECOUNT(H, pObDrvMap->cMap) * MSYSDRIVER_DRV_LINELENGTH, NULL); + VMMDLL_VfsList_AddFile(pFileList, "driver_irp.txt", UTIL_VFSLINEFIXED_LINECOUNT(H, pObDrvMap->cMap * 28ULL) * MSYSDRIVER_IRP_LINELENGTH, NULL); goto finish; } - if(!_stricmp(ctx->uszPath, "by-name")) { + if(!_stricmp(ctxP->uszPath, "by-name")) { for(i = 0; i < pObDrvMap->cMap; i++) { VMMDLL_VfsList_AddDirectory(pFileList, pObDrvMap->pMap[i].uszName, NULL); } goto finish; } - if(MSysDriver_EntryFromPath(ctx->uszPath, pObDrvMap, &pe, &uszPath) && uszPath[0]) { - VmmWinObjDisplay_VfsList(ctxVmm->ObjectTypeTable.tpDriver, pe->va, pFileList); + if(MSysDriver_EntryFromPath(ctxP->uszPath, pObDrvMap, &peDriver, &uszPath) && uszPath[0] && (pObSystemProcess = VmmProcessGet(H, 4))) { + uszPath = CharUtil_PathSplitNext(uszPath); + if(0 == uszPath[0]) { + VmmWinObjDisplay_VfsList(H, H->vmm.ObjectTypeTable.tpDriver, peDriver->va, pFileList); + if(VmmMap_GetModule(H, pObSystemProcess, &pObModuleMap) && (peModule = VmmMap_GetModuleEntryEx2(H, pObModuleMap, peDriver->vaStart))) { + VMMDLL_VfsList_AddDirectory(pFileList, peModule->uszText, NULL); + } + } else { + // forward link to module: + _snprintf_s(uszBuffer, _countof(uszBuffer), _TRUNCATE, "modules\\%s\\", uszPath); + PluginManager_List(H, pObSystemProcess, uszBuffer, pFileList); + } goto finish; } finish: Ob_DECREF(pObDrvMap); + Ob_DECREF(pObModuleMap); + Ob_DECREF(pObSystemProcess); return TRUE; } -VOID MSysDriver_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) +VOID MSysDriver_FcLogJSON(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) { PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd; PVMMOB_MAP_KDRIVER pObDrvMap = NULL; @@ -209,7 +249,7 @@ VOID MSysDriver_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSO if(ctxP->pProcess || !(pd = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMDLL_PLUGIN_FORENSIC_JSONDATA)))) { return; } pd->dwVersion = VMMDLL_PLUGIN_FORENSIC_JSONDATA_VERSION; pd->szjType = "driver"; - if(VmmMap_GetKDriver(&pObDrvMap)) { + if(VmmMap_GetKDriver(H, &pObDrvMap)) { for(i = 0; i < pObDrvMap->cMap; i++) { pe = pObDrvMap->pMap + i; pd->i = i; @@ -220,14 +260,55 @@ VOID MSysDriver_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSO pd->usz[0] = pe->uszName; snprintf(usz, sizeof(usz), "svc:[%s] path:[%s]", pe->uszServiceKeyName, pe->uszPath); pd->usz[1] = usz; - pfnLogJSON(pd); + pfnLogJSON(H, pd); } } Ob_DECREF(pObDrvMap); LocalFree(pd); } -VOID M_SysDriver_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +PVOID MSysDriver_FcInitialize(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP) +{ + FcFileAppend(H, "drivers.csv", MSYSDRIVER_CSV_DRIVERS); + return NULL; +} + +VOID MSysDriver_FcLogCSV(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VMMDLL_CSV_HANDLE hCSV) +{ + PVMM_PROCESS pSystemProcess = (PVMM_PROCESS)ctxP->pProcess; + PVMM_MAP_KDRIVERENTRY pe; + PVMMOB_MAP_KDRIVER pObDriverMap = NULL; + PVMMOB_MAP_MODULE pObModuleMap = NULL; + PVMM_MAP_MODULEENTRY peModule; + POB_MAP pmObModuleByVA = NULL; + DWORD i; + if(!pSystemProcess || (pSystemProcess->dwPID != 4)) { return; } + if(!VmmMap_GetKDriver(H, &pObDriverMap)) { return; } + if(VmmMap_GetModule(H, pSystemProcess, &pObModuleMap)) { + VmmMap_GetModuleEntryEx3(H, pObModuleMap, &pmObModuleByVA); + } + for(i = 0; i < pObDriverMap->cMap; i++) { + pe = pObDriverMap->pMap + i; + peModule = (PVMM_MAP_MODULEENTRY)ObMap_GetByKey(pmObModuleByVA, pe->vaStart); + //"Name,ObjectAddress,Size,Start,End,ServiceKey,DriverName,DriverPath" + FcCsv_Reset(hCSV); + FcFileAppend(H, "drivers.csv", "%s,0x%llx,0x%llx,0x%llx,0x%llx,%s,%s,%s\n", + FcCsv_String(hCSV, pe->uszName), + pe->va, + pe->cbDriverSize, + pe->vaStart, + pe->cbDriverSize ? (pe->vaStart + pe->cbDriverSize - 1) : pe->vaStart, + FcCsv_String(hCSV, pe->uszServiceKeyName), + FcCsv_String(hCSV, pe->uszPath), + (peModule && peModule->uszFullName) ? FcCsv_String(hCSV, peModule->uszFullName) : "" + ); + } + Ob_DECREF(pObDriverMap); + Ob_DECREF(pObModuleMap); + Ob_DECREF(pmObModuleByVA); +} + +VOID M_SysDriver_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if((pRI->tpSystem != VMM_SYSTEM_WINDOWS_X64) && (pRI->tpSystem != VMM_SYSTEM_WINDOWS_X86)) { return; } @@ -236,6 +317,8 @@ VOID M_SysDriver_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) pRI->reg_info.fRootModule = TRUE; // module shows in root directory pRI->reg_fn.pfnList = MSysDriver_List; // List function supported pRI->reg_fn.pfnRead = MSysDriver_Read; // Read function supported + pRI->reg_fnfc.pfnInitialize = MSysDriver_FcInitialize; // Forensic initialize function supported + pRI->reg_fnfc.pfnLogCSV = MSysDriver_FcLogCSV; // CSV log function supported pRI->reg_fnfc.pfnLogJSON = MSysDriver_FcLogJSON; // JSON log function supported - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_sys_mem.c b/vmm/m_sys_mem.c index 835b7fa..2bfefc7 100644 --- a/vmm/m_sys_mem.c +++ b/vmm/m_sys_mem.c @@ -14,7 +14,7 @@ #define MSYSMEM_PHYSMEMMAP_LINELENGTH 33ULL #define MSYSMEM_PHYSMEMMAP_LINEHEADER " # Base Top" -VOID MSysMem_PhysMemReadLine_Callback(_Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_PHYSMEMENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR usz) +VOID MSysMem_PhysMemReadLineCB(_In_ VMM_HANDLE H, _Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_PHYSMEMENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR usz) { Util_usnprintf_ln(usz, cbLineLength, "%04x %12llx - %12llx", @@ -25,7 +25,7 @@ VOID MSysMem_PhysMemReadLine_Callback(_Inout_opt_ PVOID ctx, _In_ DWORD cbLineLe } _Success_(return == 0) -NTSTATUS MSysMem_Read_PfnMap(_Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MSysMem_Read_PfnMap(_In_ VMM_HANDLE H, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt; LPSTR sz; @@ -35,13 +35,13 @@ NTSTATUS MSysMem_Read_PfnMap(_Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD CHAR szType[MAX_PATH] = { 0 }; DWORD tp, cPfnTotal, cPfnStart, cPfnEnd; BOOL fModified, fPrototype; - cPfnTotal = (DWORD)(ctxMain->dev.paMax >> 12); + cPfnTotal = (DWORD)(H->dev.paMax >> 12); cbLINELENGTH = MSYSMEM_PFNMAP_LINELENGTH; cPfnStart = (DWORD)(cbOffset / cbLINELENGTH); cPfnEnd = (DWORD)min(cPfnTotal - 1, (cb + cbOffset + cbLINELENGTH - 1) / cbLINELENGTH); cbMax = 1 + (1ULL + cPfnEnd - cPfnStart) * cbLINELENGTH; if(cPfnStart >= cPfnTotal) { return VMMDLL_STATUS_END_OF_FILE; } - if(!MmPfn_Map_GetPfn(cPfnStart, cPfnEnd - cPfnStart + 1, &pObPfnMap, TRUE)) { return VMMDLL_STATUS_FILE_INVALID; } + if(!MmPfn_Map_GetPfn(H, cPfnStart, cPfnEnd - cPfnStart + 1, &pObPfnMap, TRUE)) { return VMMDLL_STATUS_FILE_INVALID; } if(!(sz = LocalAlloc(LMEM_ZEROINIT, (SIZE_T)cbMax))) { Ob_DECREF(pObPfnMap); return VMMDLL_STATUS_FILE_INVALID; @@ -71,48 +71,48 @@ NTSTATUS MSysMem_Read_PfnMap(_Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD return nt; } -NTSTATUS MSysMem_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MSysMem_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; PVMMOB_MAP_PHYSMEM pObPhysMemMap = NULL; - if(!_stricmp(ctx->uszPath, "physmemmap.txt") && VmmMap_GetPhysMem(&pObPhysMemMap)) { + if(!_stricmp(ctxP->uszPath, "physmemmap.txt") && VmmMap_GetPhysMem(H, &pObPhysMemMap)) { nt = Util_VfsLineFixed_Read( - (UTIL_VFSLINEFIXED_PFN_CB)MSysMem_PhysMemReadLine_Callback, NULL, MSYSMEM_PHYSMEMMAP_LINELENGTH, MSYSMEM_PHYSMEMMAP_LINEHEADER, + H, (UTIL_VFSLINEFIXED_PFN_CB)MSysMem_PhysMemReadLineCB, NULL, MSYSMEM_PHYSMEMMAP_LINELENGTH, MSYSMEM_PHYSMEMMAP_LINEHEADER, pObPhysMemMap->pMap, pObPhysMemMap->cMap, sizeof(VMM_MAP_PHYSMEMENTRY), pb, cb, pcbRead, cbOffset ); Ob_DECREF_NULL(&pObPhysMemMap); } - if(!_stricmp(ctx->uszPath, "pfndb.txt")) { - nt = MSysMem_Read_PfnMap(pb, cb, pcbRead, cbOffset); + if(!_stricmp(ctxP->uszPath, "pfndb.txt")) { + nt = MSysMem_Read_PfnMap(H, pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "pfnaddr.txt")) { - nt = ctxVmm->f32 ? - Util_VfsReadFile_FromDWORD((DWORD)ctxVmm->kernel.opt.vaPfnDatabase, pb, cb, pcbRead, cbOffset, FALSE) : - Util_VfsReadFile_FromQWORD((QWORD)ctxVmm->kernel.opt.vaPfnDatabase, pb, cb, pcbRead, cbOffset, FALSE); + if(!_stricmp(ctxP->uszPath, "pfnaddr.txt")) { + nt = H->vmm.f32 ? + Util_VfsReadFile_FromDWORD((DWORD)H->vmm.kernel.opt.vaPfnDatabase, pb, cb, pcbRead, cbOffset, FALSE) : + Util_VfsReadFile_FromQWORD((QWORD)H->vmm.kernel.opt.vaPfnDatabase, pb, cb, pcbRead, cbOffset, FALSE); } return nt; } -BOOL MSysMem_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) +BOOL MSysMem_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { DWORD cPfn, cPhys; PVMMOB_MAP_PHYSMEM pObPhysMemMap = NULL; // PFN database: - if(ctxVmm->kernel.opt.vaPfnDatabase) { - cPfn = (DWORD)(ctxMain->dev.paMax >> 12); + if(H->vmm.kernel.opt.vaPfnDatabase) { + cPfn = (DWORD)(H->dev.paMax >> 12); VMMDLL_VfsList_AddFile(pFileList, "pfndb.txt", cPfn * MSYSMEM_PFNMAP_LINELENGTH, NULL); - VMMDLL_VfsList_AddFile(pFileList, "pfnaddr.txt", ctxVmm->f32 ? 8 : 16, NULL); + VMMDLL_VfsList_AddFile(pFileList, "pfnaddr.txt", H->vmm.f32 ? 8 : 16, NULL); } // Physical Memory Map: - VmmMap_GetPhysMem(&pObPhysMemMap); + VmmMap_GetPhysMem(H, &pObPhysMemMap); cPhys = pObPhysMemMap ? pObPhysMemMap->cMap : 0; - VMMDLL_VfsList_AddFile(pFileList, "physmemmap.txt", UTIL_VFSLINEFIXED_LINECOUNT(cPhys) * MSYSMEM_PHYSMEMMAP_LINELENGTH, NULL); + VMMDLL_VfsList_AddFile(pFileList, "physmemmap.txt", UTIL_VFSLINEFIXED_LINECOUNT(H, cPhys) * MSYSMEM_PHYSMEMMAP_LINELENGTH, NULL); Ob_DECREF(pObPhysMemMap); return TRUE; } -VOID MSysMem_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) +VOID MSysMem_FcLogJSON(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) { PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd; PVMMOB_MAP_PHYSMEM pObPhysMemMap = NULL; @@ -121,21 +121,21 @@ VOID MSysMem_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)( if(ctxP->pProcess || !(pd = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMDLL_PLUGIN_FORENSIC_JSONDATA)))) { return; } pd->dwVersion = VMMDLL_PLUGIN_FORENSIC_JSONDATA_VERSION; pd->szjType = "memorymap"; - if(VmmMap_GetPhysMem(&pObPhysMemMap)) { + if(VmmMap_GetPhysMem(H, &pObPhysMemMap)) { for(i = 0; i < pObPhysMemMap->cMap; i++) { pe = pObPhysMemMap->pMap + i; pd->i = i; pd->va[0] = pe->pa; pd->va[1] = pe->pa + pe->cb - 1; pd->qwNum[0] = pe->cb; - pfnLogJSON(pd); + pfnLogJSON(H, pd); } } Ob_DECREF(pObPhysMemMap); LocalFree(pd); } -VOID M_SysMem_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_SysMem_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if((pRI->tpSystem != VMM_SYSTEM_WINDOWS_X64) && (pRI->tpSystem != VMM_SYSTEM_WINDOWS_X86)) { return; } @@ -144,5 +144,5 @@ VOID M_SysMem_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) pRI->reg_fn.pfnList = MSysMem_List; // List function supported pRI->reg_fn.pfnRead = MSysMem_Read; // Read function supported pRI->reg_fnfc.pfnLogJSON = MSysMem_FcLogJSON; // JSON log function supported - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_sys_net.c b/vmm/m_sys_net.c index 61bf104..4708f84 100644 --- a/vmm/m_sys_net.c +++ b/vmm/m_sys_net.c @@ -33,9 +33,9 @@ LPCSTR szMSYSNET_README = -VOID MSysNet_ReadLine_Callback(_Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_NETENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR szu8) +VOID MSysNet_ReadLineCB(_In_ VMM_HANDLE H, _Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_NETENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR szu8) { - PVMM_PROCESS pObProcess = VmmProcessGet(pe->dwPID); + PVMM_PROCESS pObProcess = VmmProcessGet(H, pe->dwPID); Util_usnprintf_ln(szu8, cbLineLength, "%04x%7i %s %s", ie, @@ -46,10 +46,10 @@ VOID MSysNet_ReadLine_Callback(_Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, _ Ob_DECREF(pObProcess); } -VOID MSysNet_ReadLineVerbose_Callback(_Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_NETENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR szu8) +VOID MSysNet_ReadLineVerboseCB(_In_ VMM_HANDLE H, _Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_NETENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR szu8) { CHAR szTime[24]; - PVMM_PROCESS pObProcess = VmmProcessGet(pe->dwPID); + PVMM_PROCESS pObProcess = VmmProcessGet(H, pe->dwPID); Util_FileTime2String(pe->ftTime, szTime); Util_usnprintf_ln(szu8, cbLineLength, "%04x%7i %s %-20s %s %016llx %s", @@ -64,24 +64,24 @@ VOID MSysNet_ReadLineVerbose_Callback(_Inout_opt_ PVOID ctx, _In_ DWORD cbLineLe Ob_DECREF(pObProcess); } -NTSTATUS MSysNet_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MSysNet_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; PVMMOB_MAP_NET pObNetMap; - if(!_stricmp(ctx->uszPath, "readme.txt")) { + if(!_stricmp(ctxP->uszPath, "readme.txt")) { return Util_VfsReadFile_FromStrA(szMSYSNET_README, pb, cb, pcbRead, cbOffset); } - if(VmmMap_GetNet(&pObNetMap)) { - if(!_stricmp(ctx->uszPath, "netstat.txt")) { + if(VmmMap_GetNet(H, &pObNetMap)) { + if(!_stricmp(ctxP->uszPath, "netstat.txt")) { nt = Util_VfsLineFixed_Read( - (UTIL_VFSLINEFIXED_PFN_CB)MSysNet_ReadLine_Callback, NULL, MSYSNET_LINELENGTH, MSYSNET_LINEHEADER, + H, (UTIL_VFSLINEFIXED_PFN_CB)MSysNet_ReadLineCB, NULL, MSYSNET_LINELENGTH, MSYSNET_LINEHEADER, pObNetMap->pMap, pObNetMap->cMap, sizeof(VMM_MAP_NETENTRY), pb, cb, pcbRead, cbOffset ); } - if(!_stricmp(ctx->uszPath, "netstat-v.txt")) { + if(!_stricmp(ctxP->uszPath, "netstat-v.txt")) { nt = Util_VfsLineFixed_Read( - (UTIL_VFSLINEFIXED_PFN_CB)MSysNet_ReadLineVerbose_Callback, NULL, MSYSNET_LINELENGTH_VERBOSE, MSYSNET_LINEHEADER_VERBOSE, + H, (UTIL_VFSLINEFIXED_PFN_CB)MSysNet_ReadLineVerboseCB, NULL, MSYSNET_LINELENGTH_VERBOSE, MSYSNET_LINEHEADER_VERBOSE, pObNetMap->pMap, pObNetMap->cMap, sizeof(VMM_MAP_NETENTRY), pb, cb, pcbRead, cbOffset ); @@ -91,40 +91,41 @@ NTSTATUS MSysNet_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbR return nt; } -BOOL MSysNet_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) +BOOL MSysNet_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { PVMMOB_MAP_NET pObNetMap; - if(ctx->uszPath[0]) { return FALSE; } + if(ctxP->uszPath[0]) { return FALSE; } VMMDLL_VfsList_AddFile(pFileList, "readme.txt", strlen(szMSYSNET_README), NULL); - if(VmmMap_GetNet(&pObNetMap)) { - VMMDLL_VfsList_AddFile(pFileList, "netstat.txt", UTIL_VFSLINEFIXED_LINECOUNT(pObNetMap->cMap) * MSYSNET_LINELENGTH, NULL); - VMMDLL_VfsList_AddFile(pFileList, "netstat-v.txt", UTIL_VFSLINEFIXED_LINECOUNT(pObNetMap->cMap) * MSYSNET_LINELENGTH_VERBOSE, NULL); + if(VmmMap_GetNet(H, &pObNetMap)) { + VMMDLL_VfsList_AddFile(pFileList, "netstat.txt", UTIL_VFSLINEFIXED_LINECOUNT(H, pObNetMap->cMap) * MSYSNET_LINELENGTH, NULL); + VMMDLL_VfsList_AddFile(pFileList, "netstat-v.txt", UTIL_VFSLINEFIXED_LINECOUNT(H, pObNetMap->cMap) * MSYSNET_LINELENGTH_VERBOSE, NULL); Ob_DECREF(pObNetMap); } return TRUE; } VOID MSysNet_Timeline( + _In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc, _In_ HANDLE hTimeline, - _In_ VOID(*pfnAddEntry)(_In_ HANDLE hTimeline, _In_ QWORD ft, _In_ DWORD dwAction, _In_ DWORD dwPID, _In_ DWORD dwData32, _In_ QWORD qwData64, _In_ LPSTR uszText), - _In_ VOID(*pfnEntryAddBySql)(_In_ HANDLE hTimeline, _In_ DWORD cEntrySql, _In_ LPSTR *pszEntrySql) + _In_ VOID(*pfnAddEntry)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ QWORD ft, _In_ DWORD dwAction, _In_ DWORD dwPID, _In_ DWORD dwData32, _In_ QWORD qwData64, _In_ LPSTR uszText), + _In_ VOID(*pfnEntryAddBySql)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ DWORD cEntrySql, _In_ LPSTR *pszEntrySql) ) { DWORD i; PVMM_MAP_NETENTRY pe; PVMMOB_MAP_NET pObNetMap; - if(VmmMap_GetNet(&pObNetMap)) { + if(VmmMap_GetNet(H, &pObNetMap)) { for(i = 0; i < pObNetMap->cMap; i++) { pe = pObNetMap->pMap + i; if(pe->ftTime && pe->uszText[0]) { - pfnAddEntry(hTimeline, pe->ftTime, FC_TIMELINE_ACTION_CREATE, pe->dwPID, 0, pe->vaObj, pe->uszText); + pfnAddEntry(H, hTimeline, pe->ftTime, FC_TIMELINE_ACTION_CREATE, pe->dwPID, 0, pe->vaObj, pe->uszText); } } Ob_DECREF(pObNetMap); } } -VOID MSysNet_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) +VOID MSysNet_FcLogJSON(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) { PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd; PVMMOB_MAP_NET pObNetMap = NULL; @@ -135,11 +136,11 @@ VOID MSysNet_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)( if(ctxP->pProcess || !(pd = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMDLL_PLUGIN_FORENSIC_JSONDATA)))) { return; } pd->dwVersion = VMMDLL_PLUGIN_FORENSIC_JSONDATA_VERSION; pd->szjType = "net"; - if(VmmMap_GetNet(&pObNetMap)) { + if(VmmMap_GetNet(H, &pObNetMap)) { for(i = 0; i < pObNetMap->cMap; i++) { pe = pObNetMap->pMap + i; szu[0] = 0; - if((pObProcess = VmmProcessGet(pe->dwPID))) { + if((pObProcess = VmmProcessGet(H, pe->dwPID))) { Util_FileTime2String(pe->ftTime, szTime); snprintf(szu, _countof(szu), "proc:[%s] time:[%s] path:[%s]", pObProcess ? pObProcess->pObPersistent->uszNameLong : "", @@ -152,14 +153,14 @@ VOID MSysNet_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)( pd->vaObj = pe->vaObj; pd->usz[0] = pe->uszText; pd->usz[1] = szu; - pfnLogJSON(pd); + pfnLogJSON(H, pd); } } Ob_DECREF(pObNetMap); LocalFree(pd); } -VOID M_SysNet_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_SysNet_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if((pRI->tpSystem != VMM_SYSTEM_WINDOWS_X64) && (pRI->tpSystem != VMM_SYSTEM_WINDOWS_X86)) { return; } @@ -170,6 +171,6 @@ VOID M_SysNet_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) pRI->reg_fnfc.pfnTimeline = MSysNet_Timeline; // Timeline supported pRI->reg_fnfc.pfnLogJSON = MSysNet_FcLogJSON; // JSON log function supported memcpy(pRI->reg_info.sTimelineNameShort, "Net", 4); - strncpy_s(pRI->reg_info.uszTimelineFile, 32, "timeline_net.txt", _TRUNCATE); - pRI->pfnPluginManager_Register(pRI); + strncpy_s(pRI->reg_info.uszTimelineFile, 32, "timeline_net", _TRUNCATE); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_sys_obj.c b/vmm/m_sys_obj.c index 5e34bc5..ec9ba8e 100644 --- a/vmm/m_sys_obj.c +++ b/vmm/m_sys_obj.c @@ -76,7 +76,7 @@ VOID MSysObj_GetFullPath(_In_ PVMM_MAP_OBJECTENTRY pe, _Out_writes_(MAX_PATH) LP } } -VOID MSysObj_ReadLine_Callback(_Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_OBJECTENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR usz) +VOID MSysObj_ReadLineCB(_In_ VMM_HANDLE H, _Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_OBJECTENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR usz) { CHAR uszPath[MAX_PATH]; MSysObj_GetFullPath(pe, uszPath); @@ -92,26 +92,26 @@ VOID MSysObj_ReadLine_Callback(_Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, _ ); } -NTSTATUS MSysObj_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MSysObj_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; PVMMOB_MAP_OBJECT pObObjMap = NULL; PVMM_MAP_OBJECTENTRY pe; BOOL fMeta, fEnd, fTxt, fMem; - if(!VmmMap_GetObject(&pObObjMap)) { goto finish; } - if(!_stricmp(ctx->uszPath, "objects.txt")) { + if(!VmmMap_GetObject(H, &pObObjMap)) { goto finish; } + if(!_stricmp(ctxP->uszPath, "objects.txt")) { nt = Util_VfsLineFixed_Read( - (UTIL_VFSLINEFIXED_PFN_CB)MSysObj_ReadLine_Callback, NULL, MSYSOBJ_LINELENGTH, MSYSOBJ_LINEHEADER, + H, (UTIL_VFSLINEFIXED_PFN_CB)MSysObj_ReadLineCB, NULL, MSYSOBJ_LINELENGTH, MSYSOBJ_LINEHEADER, pObObjMap->pMap, pObObjMap->cMap, sizeof(VMM_MAP_OBJECTENTRY), pb, cb, pcbRead, cbOffset ); goto finish; } - if(MSysObj_Path2Entry(pObObjMap, ctx->uszPath, &pe, &fMeta, &fEnd, &fTxt, &fMem)) { + if(MSysObj_Path2Entry(pObObjMap, ctxP->uszPath, &pe, &fMeta, &fEnd, &fTxt, &fMem)) { if(fMeta) { - nt = VmmWinObjDisplay_VfsRead(ctx->uszPath, pe->pType->iType, pe->va, pb, cb, pcbRead, cbOffset); + nt = VmmWinObjDisplay_VfsRead(H, ctxP->uszPath, pe->pType->iType, pe->va, pb, cb, pcbRead, cbOffset); } else { - nt = Util_VfsReadFile_FromMEM(PVMM_PROCESS_SYSTEM, pe->va, pe->pType->cb, VMM_FLAG_ZEROPAD_ON_FAIL, pb, cb, pcbRead, cbOffset); + nt = Util_VfsReadFile_FromMEM(H, PVMM_PROCESS_SYSTEM, pe->va, pe->pType->cb, VMM_FLAG_ZEROPAD_ON_FAIL, pb, cb, pcbRead, cbOffset); } } finish: @@ -119,13 +119,13 @@ finish: return nt; } -VOID MSysObj_ListDirectory(_In_ PVMMOB_MAP_OBJECT pObjMap, _In_ LPSTR uszPath, _Inout_ PHANDLE pFileList) +VOID MSysObj_ListDirectory(_In_ VMM_HANDLE H, _In_ PVMMOB_MAP_OBJECT pObjMap, _In_ LPSTR uszPath, _Inout_ PHANDLE pFileList) { PVMM_MAP_OBJECTENTRY pe; BOOL fMeta, fEnd, fTxt, fMem; if(!MSysObj_Path2Entry(pObjMap, uszPath, &pe, &fMeta, &fEnd, &fTxt, &fMem)) { return; } if(fMeta && !fEnd) { - VmmWinObjDisplay_VfsList(pe->pType->iType, pe->va, pFileList); + VmmWinObjDisplay_VfsList(H, pe->pType->iType, pe->va, pFileList); return; } pe = pe->pChild; @@ -143,17 +143,17 @@ VOID MSysObj_ListDirectory(_In_ PVMMOB_MAP_OBJECT pObjMap, _In_ LPSTR uszPath, _ } } -BOOL MSysObj_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) +BOOL MSysObj_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { PVMMOB_MAP_OBJECT pObObjMap = NULL; - if(!VmmMap_GetObject(&pObObjMap)) { goto finish; } - if(!ctx->uszPath[0]) { + if(!VmmMap_GetObject(H, &pObObjMap)) { goto finish; } + if(!ctxP->uszPath[0]) { VMMDLL_VfsList_AddDirectory(pFileList, "ROOT", NULL); - VMMDLL_VfsList_AddFile(pFileList, "objects.txt", UTIL_VFSLINEFIXED_LINECOUNT(pObObjMap->cMap) * MSYSOBJ_LINELENGTH, NULL); + VMMDLL_VfsList_AddFile(pFileList, "objects.txt", UTIL_VFSLINEFIXED_LINECOUNT(H, pObObjMap->cMap) * MSYSOBJ_LINELENGTH, NULL); goto finish; } - if(!_strnicmp(ctx->uszPath, "ROOT", 4)) { - MSysObj_ListDirectory(pObObjMap, ctx->uszPath, pFileList); + if(!_strnicmp(ctxP->uszPath, "ROOT", 4)) { + MSysObj_ListDirectory(H, pObObjMap, ctxP->uszPath, pFileList); goto finish; } finish: @@ -162,29 +162,31 @@ finish: } VOID MSysObj_Timeline( + _In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc, _In_ HANDLE hTimeline, - _In_ VOID(*pfnAddEntry)(_In_ HANDLE hTimeline, _In_ QWORD ft, _In_ DWORD dwAction, _In_ DWORD dwPID, _In_ DWORD dwData32, _In_ QWORD qwData64, _In_ LPSTR uszText), - _In_ VOID(*pfnEntryAddBySql)(_In_ HANDLE hTimeline, _In_ DWORD cEntrySql, _In_ LPSTR *pszEntrySql) + _In_ VOID(*pfnAddEntry)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ QWORD ft, _In_ DWORD dwAction, _In_ DWORD dwPID, _In_ DWORD dwData32, _In_ QWORD qwData64, _In_ LPSTR uszText), + _In_ VOID(*pfnEntryAddBySql)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ DWORD cEntrySql, _In_ LPSTR *pszEntrySql) ) { DWORD i, cType, iTypeBase; CHAR uszPath[MAX_PATH]; PVMM_MAP_OBJECTENTRY pe; - PVMMOB_MAP_OBJECT pObObjMap; - if(VmmMap_GetObject(&pObObjMap)) { - cType = pObObjMap->cType[ctxVmm->ObjectTypeTable.tpSymbolicLink]; - iTypeBase = pObObjMap->iTypeSortBase[ctxVmm->ObjectTypeTable.tpSymbolicLink]; + PVMMOB_MAP_OBJECT pObObjMap = NULL; + if(VmmMap_GetObject(H, &pObObjMap)) { + cType = pObObjMap->cType[H->vmm.ObjectTypeTable.tpSymbolicLink]; + iTypeBase = pObObjMap->iTypeSortBase[H->vmm.ObjectTypeTable.tpSymbolicLink]; for(i = 0; i < cType; i++) { pe = &pObObjMap->pMap[iTypeBase + i]; if(pe->ExtInfo.ft) { MSysObj_GetFullPath(pe, uszPath); - pfnAddEntry(hTimeline, pe->ExtInfo.ft, FC_TIMELINE_ACTION_CREATE, 0, 0, pe->va, uszPath); + pfnAddEntry(H, hTimeline, pe->ExtInfo.ft, FC_TIMELINE_ACTION_CREATE, 0, 0, pe->va, uszPath); } } + Ob_DECREF(pObObjMap); } } -VOID MSysObj_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) +VOID MSysObj_FcLogJSON(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) { PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd; PVMMOB_MAP_OBJECT pObObjMap = NULL; @@ -195,7 +197,7 @@ VOID MSysObj_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)( if(ctxP->pProcess || !(pd = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMDLL_PLUGIN_FORENSIC_JSONDATA)))) { return; } pd->dwVersion = VMMDLL_PLUGIN_FORENSIC_JSONDATA_VERSION; pd->szjType = "kobj"; - if(VmmMap_GetObject(&pObObjMap)) { + if(VmmMap_GetObject(H, &pObObjMap)) { for(i = 0; i < pObObjMap->cMap; i++) { pe = pObObjMap->pMap + i; MSysObj_GetFullPath(pe, uszPath); @@ -208,14 +210,14 @@ VOID MSysObj_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)( pd->vaObj = pe->va; pd->usz[0] = pe->pType->usz; pd->usz[1] = usz; - pfnLogJSON(pd); + pfnLogJSON(H, pd); } } Ob_DECREF(pObObjMap); LocalFree(pd); } -VOID M_SysObj_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_SysObj_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if((pRI->tpSystem != VMM_SYSTEM_WINDOWS_X64) && (pRI->tpSystem != VMM_SYSTEM_WINDOWS_X86)) { return; } @@ -227,6 +229,6 @@ VOID M_SysObj_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) pRI->reg_fnfc.pfnTimeline = MSysObj_Timeline; // Timeline supported pRI->reg_fnfc.pfnLogJSON = MSysObj_FcLogJSON; // JSON log function supported memcpy(pRI->reg_info.sTimelineNameShort, "KObj", 5); - strncpy_s(pRI->reg_info.uszTimelineFile, 32, "timeline_kernelobject.txt", _TRUNCATE); - pRI->pfnPluginManager_Register(pRI); + strncpy_s(pRI->reg_info.uszTimelineFile, 32, "timeline_kernelobject", _TRUNCATE); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_sys_pool.c b/vmm/m_sys_pool.c index 66a640b..6f9fa99 100644 --- a/vmm/m_sys_pool.c +++ b/vmm/m_sys_pool.c @@ -31,7 +31,7 @@ LPCSTR szMSYSPOOL_README = #define MSYSPOOL_LINELENGTH 58ULL #define MSYSPOOL_LINEHEADER " # Tag A Address Size Type Pool" -VOID MSysPool_ReadLine_Callback(_Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_POOLENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR usz) +VOID MSysPool_ReadLineCB(_In_ VMM_HANDLE H, _Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_POOLENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR usz) { union { CHAR sz[5]; DWORD dw; } uTag; uTag.dw = pe->dwTag; @@ -57,7 +57,7 @@ typedef struct tdMSYSPOOL_MAP_CONTEXT { PVMM_MAP_POOLENTRYTAG pePoolTag; } MSYSPOOL_MAP_CONTEXT, *PMSYSPOOL_MAP_CONTEXT; -PVOID MSysPool_ReadLineGetEntry_Callback(_In_ PVOID ctxMap, _In_ DWORD iMap) +PVOID MSysPool_ReadLineGetEntryCB(_In_ VMM_HANDLE H, _In_ PVOID ctxMap, _In_ DWORD iMap) { PMSYSPOOL_MAP_CONTEXT ctx = (PMSYSPOOL_MAP_CONTEXT)ctxMap; if(iMap < ctx->pePoolTag->cEntry) { @@ -66,10 +66,10 @@ PVOID MSysPool_ReadLineGetEntry_Callback(_In_ PVOID ctxMap, _In_ DWORD iMap) return NULL; } -NTSTATUS MSysPool_ReadSingle(_In_ LPSTR uszPathFile, _In_ PVMM_MAP_POOLENTRY pe, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MSysPool_ReadSingle(_In_ VMM_HANDLE H, _In_ LPSTR uszPathFile, _In_ PVMM_MAP_POOLENTRY pe, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { if(CharUtil_StrEndsWith(uszPathFile, "pool-address.txt", TRUE)) { - if(ctxVmm->f32) { + if(H->vmm.f32) { return Util_VfsReadFile_FromDWORD((DWORD)pe->va, pb, cb, pcbRead, cbOffset, FALSE); } else { return Util_VfsReadFile_FromQWORD(pe->va, pb, cb, pcbRead, cbOffset, FALSE); @@ -79,12 +79,12 @@ NTSTATUS MSysPool_ReadSingle(_In_ LPSTR uszPathFile, _In_ PVMM_MAP_POOLENTRY pe, return Util_VfsReadFile_FromPBYTE((PBYTE)pe->szTag, 4, pb, cb, pcbRead, cbOffset); } if(CharUtil_StrEndsWith(uszPathFile, "pool-data.mem", TRUE)) { - return Util_VfsReadFile_FromMEM(PVMM_PROCESS_SYSTEM, pe->va, pe->cb, VMM_FLAG_ZEROPAD_ON_FAIL, pb, cb, pcbRead, cbOffset); + return Util_VfsReadFile_FromMEM(H, PVMM_PROCESS_SYSTEM, pe->va, pe->cb, VMM_FLAG_ZEROPAD_ON_FAIL, pb, cb, pcbRead, cbOffset); } return VMMDLL_STATUS_FILE_INVALID; } -NTSTATUS MSysPool_Read2(_In_ LPSTR uszPath, _In_ PVMMOB_MAP_POOL pmPool, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MSysPool_Read2(_In_ VMM_HANDLE H, _In_ LPSTR uszPath, _In_ PVMMOB_MAP_POOL pmPool, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { DWORD iEntry, iTag, dwTag = (DWORD)-1; QWORD vaEntry; @@ -94,7 +94,7 @@ NTSTATUS MSysPool_Read2(_In_ LPSTR uszPath, _In_ PVMMOB_MAP_POOL pmPool, _Out_wr // general allocations file if(!_stricmp(uszPath, "allocations.txt")) { return Util_VfsLineFixed_Read( - (UTIL_VFSLINEFIXED_PFN_CB)MSysPool_ReadLine_Callback, NULL, MSYSPOOL_LINELENGTH, MSYSPOOL_LINEHEADER, + H, (UTIL_VFSLINEFIXED_PFN_CB)MSysPool_ReadLineCB, NULL, MSYSPOOL_LINELENGTH, MSYSPOOL_LINEHEADER, pmPool->pMap, pmPool->cMap, sizeof(VMM_MAP_POOLENTRY), pb, cb, pcbRead, cbOffset ); @@ -102,12 +102,12 @@ NTSTATUS MSysPool_Read2(_In_ LPSTR uszPath, _In_ PVMMOB_MAP_POOL pmPool, _Out_wr // by-tag allocations file if(CharUtil_StrEndsWith(uszPath, "allocations.txt", TRUE)) { Util_VfsHelper_GetIdDir(uszPath, TRUE, &dwTag, NULL); - if(!VmmMap_GetPoolTag(pmPool, dwTag, &iTag)) { return VMMDLL_STATUS_FILE_INVALID; } + if(!VmmMap_GetPoolTag(H, pmPool, dwTag, &iTag)) { return VMMDLL_STATUS_FILE_INVALID; } ctxMap.pmPool = pmPool; ctxMap.pePoolTag = pmPool->pTag + iTag; return Util_VfsLineFixedMapCustom_Read( - (UTIL_VFSLINEFIXED_PFN_CB)MSysPool_ReadLine_Callback, NULL, MSYSPOOL_LINELENGTH, MSYSPOOL_LINEHEADER, - &ctxMap, pmPool->pTag[iTag].cEntry, MSysPool_ReadLineGetEntry_Callback, + H, (UTIL_VFSLINEFIXED_PFN_CB)MSysPool_ReadLineCB, NULL, MSYSPOOL_LINELENGTH, MSYSPOOL_LINEHEADER, + &ctxMap, pmPool->pTag[iTag].cEntry, MSysPool_ReadLineGetEntryCB, pb, cb, pcbRead, cbOffset ); } @@ -116,38 +116,38 @@ NTSTATUS MSysPool_Read2(_In_ LPSTR uszPath, _In_ PVMMOB_MAP_POOL pmPool, _Out_wr uszPath = CharUtil_PathSplitNext(uszPath); uszPath = CharUtil_PathSplitFirst(uszPath, usz, _countof(usz)); vaEntry = strtoull(usz, NULL, 16); - if(!uszPath[0] || !VmmMap_GetPoolEntry(pmPool, vaEntry, &iEntry)) { return VMMDLL_STATUS_FILE_INVALID; } - return MSysPool_ReadSingle(uszPath, pmPool->pMap + iEntry, pb, cb, pcbRead, cbOffset); + if(!uszPath[0] || !VmmMap_GetPoolEntry(H, pmPool, vaEntry, &iEntry)) { return VMMDLL_STATUS_FILE_INVALID; } + return MSysPool_ReadSingle(H, uszPath, pmPool->pMap + iEntry, pb, cb, pcbRead, cbOffset); } -NTSTATUS MSysPool_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MSysPool_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; PVMMOB_MAP_POOL pmObPool = NULL; - if(!_stricmp(ctx->uszPath, "readme.txt")) { + if(!_stricmp(ctxP->uszPath, "readme.txt")) { return Util_VfsReadFile_FromStrA(szMSYSPOOL_README, pb, cb, pcbRead, cbOffset); } // all pool directory - if(!_strnicmp(ctx->uszPath, "all", 3) && VmmMap_GetPool(&pmObPool, TRUE)) { - nt = MSysPool_Read2(ctx->uszPath + 3, pmObPool, pb, cb, pcbRead, cbOffset); + if(!_strnicmp(ctxP->uszPath, "all", 3) && VmmMap_GetPool(H, &pmObPool, TRUE)) { + nt = MSysPool_Read2(H, ctxP->uszPath + 3, pmObPool, pb, cb, pcbRead, cbOffset); } // big pool directory - if(!_strnicmp(ctx->uszPath, "big", 3) && VmmMap_GetPool(&pmObPool, FALSE)) { - nt = MSysPool_Read2(ctx->uszPath + 3, pmObPool, pb, cb, pcbRead, cbOffset); + if(!_strnicmp(ctxP->uszPath, "big", 3) && VmmMap_GetPool(H, &pmObPool, FALSE)) { + nt = MSysPool_Read2(H, ctxP->uszPath + 3, pmObPool, pb, cb, pcbRead, cbOffset); } Ob_DECREF(pmObPool); return nt; } -BOOL MSysPool_ListSingle(_In_ PVMM_MAP_POOLENTRY pe, _Inout_ PHANDLE pFileList) +BOOL MSysPool_ListSingle(_In_ VMM_HANDLE H, _In_ PVMM_MAP_POOLENTRY pe, _Inout_ PHANDLE pFileList) { VMMDLL_VfsList_AddFile(pFileList, "pool-tag.txt", 4, NULL); - VMMDLL_VfsList_AddFile(pFileList, "pool-address.txt", ctxVmm->f32 ? 8 : 16, NULL); + VMMDLL_VfsList_AddFile(pFileList, "pool-address.txt", H->vmm.f32 ? 8 : 16, NULL); VMMDLL_VfsList_AddFile(pFileList, "pool-data.mem", pe->cb, NULL); return TRUE; } -BOOL MSysPool_List2(_In_ LPSTR uszPath, _In_ PVMMOB_MAP_POOL pmPool, _Inout_ PHANDLE pFileList) +BOOL MSysPool_List2(_In_ VMM_HANDLE H, _In_ LPSTR uszPath, _In_ PVMMOB_MAP_POOL pmPool, _Inout_ PHANDLE pFileList) { QWORD vaEntry; DWORD i, iEntry, iTag, iTagEntry, dwTag = (DWORD)-1; @@ -158,7 +158,7 @@ BOOL MSysPool_List2(_In_ LPSTR uszPath, _In_ PVMMOB_MAP_POOL pmPool, _Inout_ PHA // root directory if(!uszPath[0]) { VMMDLL_VfsList_AddDirectory(pFileList, "by-tag", NULL); - VMMDLL_VfsList_AddFile(pFileList, "allocations.txt", UTIL_VFSLINEFIXED_LINECOUNT(pmPool->cMap) * MSYSPOOL_LINELENGTH, NULL); + VMMDLL_VfsList_AddFile(pFileList, "allocations.txt", UTIL_VFSLINEFIXED_LINECOUNT(H, pmPool->cMap) * MSYSPOOL_LINELENGTH, NULL); return TRUE; } // by tag @@ -179,49 +179,49 @@ BOOL MSysPool_List2(_In_ LPSTR uszPath, _In_ PVMMOB_MAP_POOL pmPool, _Inout_ PHA if(!uszSubPath) { return FALSE; } // sub-path-dir if(!uszSubPath[0]) { - if(!VmmMap_GetPoolTag(pmPool, dwTag, &iTag)) { return FALSE; } + if(!VmmMap_GetPoolTag(H, pmPool, dwTag, &iTag)) { return FALSE; } pePoolTag = pmPool->pTag + iTag; for(iTagEntry = 0; iTagEntry < pePoolTag->cEntry; iTagEntry++) { iEntry = pmPool->piTag2Map[pePoolTag->iTag2Map + iTagEntry]; _snprintf_s(usz, MAX_PATH, _TRUNCATE, "%llx", pmPool->pMap[iEntry].va); VMMDLL_VfsList_AddDirectory(pFileList, usz, NULL); } - VMMDLL_VfsList_AddFile(pFileList, "allocations.txt", UTIL_VFSLINEFIXED_LINECOUNT(pmPool->pTag[iTag].cEntry) * MSYSPOOL_LINELENGTH, NULL); + VMMDLL_VfsList_AddFile(pFileList, "allocations.txt", UTIL_VFSLINEFIXED_LINECOUNT(H, pmPool->pTag[iTag].cEntry) * MSYSPOOL_LINELENGTH, NULL); return TRUE; } // single uszSubPath = CharUtil_PathSplitFirst(uszSubPath, usz, _countof(usz)); vaEntry = strtoull(usz, NULL, 16); - if(uszSubPath[0] || !VmmMap_GetPoolEntry(pmPool, vaEntry, &iEntry)) { return FALSE; } - return MSysPool_ListSingle(pmPool->pMap + iEntry, pFileList); + if(uszSubPath[0] || !VmmMap_GetPoolEntry(H, pmPool, vaEntry, &iEntry)) { return FALSE; } + return MSysPool_ListSingle(H, pmPool->pMap + iEntry, pFileList); } return FALSE; } -BOOL MSysPool_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) +BOOL MSysPool_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { BOOL fResult = FALSE; PVMMOB_MAP_POOL pmObPool = NULL; // root directory - if(!ctx->uszPath[0]) { + if(!ctxP->uszPath[0]) { VMMDLL_VfsList_AddDirectory(pFileList, "all", NULL); VMMDLL_VfsList_AddDirectory(pFileList, "big", NULL); VMMDLL_VfsList_AddFile(pFileList, "readme.txt", strlen(szMSYSPOOL_README), NULL); return TRUE; } // all pool directory - if(!_strnicmp(ctx->uszPath, "all", 3) && VmmMap_GetPool(&pmObPool, TRUE)) { - fResult = MSysPool_List2(ctx->uszPath + 3, pmObPool, pFileList); + if(!_strnicmp(ctxP->uszPath, "all", 3) && VmmMap_GetPool(H, &pmObPool, TRUE)) { + fResult = MSysPool_List2(H, ctxP->uszPath + 3, pmObPool, pFileList); } // big pool directory - if(!_strnicmp(ctx->uszPath, "big", 3) && VmmMap_GetPool(&pmObPool, FALSE)) { - fResult = MSysPool_List2(ctx->uszPath + 3, pmObPool, pFileList); + if(!_strnicmp(ctxP->uszPath, "big", 3) && VmmMap_GetPool(H, &pmObPool, FALSE)) { + fResult = MSysPool_List2(H, ctxP->uszPath + 3, pmObPool, pFileList); } Ob_DECREF(pmObPool); return fResult; } -VOID M_SysPool_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_SysPool_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if((pRI->tpSystem != VMM_SYSTEM_WINDOWS_X64) && (pRI->tpSystem != VMM_SYSTEM_WINDOWS_X86)) { return; } @@ -229,5 +229,5 @@ VOID M_SysPool_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) pRI->reg_info.fRootModule = TRUE; // module shows in root directory pRI->reg_fn.pfnList = MSysPool_List; // List function supported pRI->reg_fn.pfnRead = MSysPool_Read; // Read function supported - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_sys_proc.c b/vmm/m_sys_proc.c index 3fd96cf..a212cb6 100644 --- a/vmm/m_sys_proc.c +++ b/vmm/m_sys_proc.c @@ -18,9 +18,9 @@ // efficient, but the file is not read often so it should be OK. // ---------------------------------------------------------------------------- -#define MSYSPROC_TREE_LINE_LENGTH 112 -#define MSYSPROC_TREE_LINE_LENGTH_VERBOSE_BASE 64 -#define MSYSPROC_TREE_LINE_LENGTH_VERBOSE_HEADER 97 +#define MSYSPROC_TREE_LINE_LENGTH 115 +#define MSYSPROC_TREE_LINE_LENGTH_VERBOSE_BASE 67 +#define MSYSPROC_TREE_LINE_LENGTH_VERBOSE_HEADER 100 const LPSTR szMSYSPROC_WHITELIST_WINDOWS_PATHS_AND_BINARIES[] = { "\\Windows\\System32\\", @@ -53,25 +53,25 @@ BOOL MSysProc_Tree_ExistsUnprocessed(PMSYSPROC_TREE_ENTRY pPidList, DWORD cPidLi return FALSE; } -VOID MSysProc_Tree_ProcessItems_GetUserName(_In_ PVMM_PROCESS pProcess, _Out_writes_(17) LPSTR uszUserName, _Out_ PBOOL fAccountUser) +VOID MSysProc_Tree_ProcessItems_GetUserName(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Out_writes_(17) LPSTR uszUserName, _Out_ PBOOL fAccountUser) { BOOL f, fWellKnownAccount = FALSE; uszUserName[0] = 0; f = pProcess->win.TOKEN.fSidUserValid && - VmmWinUser_GetName(&pProcess->win.TOKEN.SidUser.SID, uszUserName, 17, &fWellKnownAccount); + VmmWinUser_GetName(H, &pProcess->win.TOKEN.SidUser.SID, uszUserName, 17, &fWellKnownAccount); *fAccountUser = f && !fWellKnownAccount; } -DWORD MSysProc_Tree_ProcessItems(_In_ PMSYSPROC_TREE_ENTRY pProcessEntry, _In_ PMSYSPROC_TREE_ENTRY pList, _In_ DWORD cList, _In_ PBYTE pb, _In_ DWORD cb, _In_ BYTE iLevel, _In_ BOOL fVerbose) +DWORD MSysProc_Tree_ProcessItems(_In_ VMM_HANDLE H, _In_ PMSYSPROC_TREE_ENTRY pProcessEntry, _In_ PMSYSPROC_TREE_ENTRY pList, _In_ DWORD cList, _In_ PBYTE pb, _In_ DWORD cb, _In_ BYTE iLevel, _In_ BOOL fVerbose) { - LPCSTR szINDENT[] = { "-", "--", "---", "----", "-----", "------", "-------", "--------", "--------+" }; + LPCSTR szINDENT[] = { "-", "--", "---", "----", "-----", "------", "-------", "--------", "---------", "----------", "-----------", "----------+" }; CHAR szUserName[17], szTimeCRE[24], szTimeEXIT[24]; DWORD i, o = 0; BOOL fWinNativeProc, fStateTerminated, fAccountUser = FALSE; BOOL fPPID, fTime; PVMMWIN_USER_PROCESS_PARAMETERS pu; if((cb > 0x01000000) || (cb < 0x00040000)) { - VmmLog(MID_PE, LOGLEVEL_WARNING, "BUFFER MAY BE TOO SMALL - SHOULD NOT HAPPEN! %i", cb); + VmmLog(H, MID_PE, LOGLEVEL_WARNING, "BUFFER MAY BE TOO SMALL - SHOULD NOT HAPPEN! %i", cb); return 0; } fStateTerminated = (pProcessEntry->pObProcess->dwState != 0); @@ -79,18 +79,18 @@ DWORD MSysProc_Tree_ProcessItems(_In_ PMSYSPROC_TREE_ENTRY pProcessEntry, _In_ P for(i = 0; !fWinNativeProc && (i < (sizeof(szMSYSPROC_WHITELIST_WINDOWS_PATHS_AND_BINARIES) / sizeof(LPSTR))); i++) { fWinNativeProc = (NULL != strstr(pProcessEntry->pObProcess->pObPersistent->uszPathKernel, szMSYSPROC_WHITELIST_WINDOWS_PATHS_AND_BINARIES[i])); } - MSysProc_Tree_ProcessItems_GetUserName(pProcessEntry->pObProcess, szUserName, &fAccountUser); - Util_FileTime2String(VmmProcess_GetCreateTimeOpt(pProcessEntry->pObProcess), szTimeCRE); - Util_FileTime2String(VmmProcess_GetExitTimeOpt(pProcessEntry->pObProcess), szTimeEXIT); + MSysProc_Tree_ProcessItems_GetUserName(H, pProcessEntry->pObProcess, szUserName, &fAccountUser); + Util_FileTime2String(VmmProcess_GetCreateTimeOpt(H, pProcessEntry->pObProcess), szTimeCRE); + Util_FileTime2String(VmmProcess_GetExitTimeOpt(H, pProcessEntry->pObProcess), szTimeEXIT); if(!fVerbose) { // normal non-verbose file: 'proc.txt' o = snprintf( pb, cb, "%s %-15s%*s%6i %6i %s%c%c%c%c %-16s %s %s\n", - szINDENT[min(8, iLevel)], + szINDENT[min(11, iLevel)], pProcessEntry->pObProcess->szName, - 8 - min(7, iLevel), + (int)(11 - min(10, iLevel)), "", pProcessEntry->dwPID, pProcessEntry->dwPPID, @@ -109,9 +109,9 @@ DWORD MSysProc_Tree_ProcessItems(_In_ PMSYSPROC_TREE_ENTRY pProcessEntry, _In_ P pb, cb, "%s %-15s%*s%6i %6i %s%c%c%c%c %-16s %s\n", - szINDENT[min(8, iLevel)], + szINDENT[min(11, iLevel)], pProcessEntry->pObProcess->szName, - 8 - min(7, iLevel), + (int)(11 - min(10, iLevel)), "", pProcessEntry->dwPID, pProcessEntry->dwPPID, @@ -123,18 +123,18 @@ DWORD MSysProc_Tree_ProcessItems(_In_ PMSYSPROC_TREE_ENTRY pProcessEntry, _In_ P szUserName, pProcessEntry->pObProcess->pObPersistent->uszPathKernel ); - pu = VmmWin_UserProcessParameters_Get(pProcessEntry->pObProcess); + pu = VmmWin_UserProcessParameters_Get(H, pProcessEntry->pObProcess); if(pu->cbuImagePathName > 1) { - o += snprintf(pb + o, cb - o, "%63s%s\n", "", pu->uszImagePathName); + o += snprintf(pb + o, cb - o, "%66s%s\n", "", pu->uszImagePathName); } if(pu->cbuCommandLine > 1) { - o += snprintf(pb + o, cb - o, "%63s%s\n", "", pu->uszCommandLine); + o += snprintf(pb + o, cb - o, "%66s%s\n", "", pu->uszCommandLine); } if(szTimeCRE[0] != ' ') { - o += snprintf(pb + o, cb - o, "%63s%s -> %s\n", "", szTimeCRE, szTimeEXIT); + o += snprintf(pb + o, cb - o, "%66s%s -> %s\n", "", szTimeCRE, szTimeEXIT); } if(pProcessEntry->pObProcess->win.TOKEN.IntegrityLevel) { - o += snprintf(pb + o, cb - o, "%63s%s\n", "", VMM_PROCESS_INTEGRITY_LEVEL_STR[pProcessEntry->pObProcess->win.TOKEN.IntegrityLevel]); + o += snprintf(pb + o, cb - o, "%66s%s\n", "", VMM_PROCESS_INTEGRITY_LEVEL_STR[pProcessEntry->pObProcess->win.TOKEN.IntegrityLevel]); } o += snprintf(pb + o, cb - o, "\n"); } @@ -146,7 +146,7 @@ DWORD MSysProc_Tree_ProcessItems(_In_ PMSYSPROC_TREE_ENTRY pProcessEntry, _In_ P fPPID = (pList[i].dwPPID == pProcessEntry->dwPID); fTime = !pList[i].ftCreate || !pProcessEntry->ftCreate || (pProcessEntry->ftCreate < pList[i].ftCreate) || (pList[i].dwPPID == 4); if(fPPID && fTime) { - o += MSysProc_Tree_ProcessItems(pList + i, pList, cList, pb + o, cb - o, iLevel + 1, fVerbose); + o += MSysProc_Tree_ProcessItems(H, pList + i, pList, cList, pb + o, cb - o, iLevel + 1, fVerbose); } } return o; @@ -161,7 +161,7 @@ int MSysProc_Tree_CmpSort(PMSYSPROC_TREE_ENTRY a, PMSYSPROC_TREE_ENTRY b) } _Success_(return) -BOOL MSysProc_Tree(_In_ BOOL fVerbose, _Out_ PBYTE *ppb, _Out_ PDWORD pcb) +BOOL MSysProc_Tree(_In_ VMM_HANDLE H, _In_ BOOL fVerbose, _Out_ PBYTE *ppb, _Out_ PDWORD pcb) { BOOL fResult = FALSE; PVMM_PROCESS pObProcess = NULL; @@ -171,14 +171,14 @@ BOOL MSysProc_Tree(_In_ BOOL fVerbose, _Out_ PBYTE *ppb, _Out_ PDWORD pcb) PBYTE pb; DWORD cb = 0x00100000, o = 0; // 1MB should be enough to hold any process list ... // 1: retrieve process information into "pid list" - VmmProcessListPIDs(NULL, &cPidList, VMM_FLAG_PROCESS_SHOW_TERMINATED); + VmmProcessListPIDs(H, NULL, &cPidList, VMM_FLAG_PROCESS_SHOW_TERMINATED); if(!cPidList) { return FALSE; } if(!(pPidList = LocalAlloc(LMEM_ZEROINIT, cPidList * sizeof(MSYSPROC_TREE_ENTRY)))) { return FALSE; } - while((iPidList < cPidList) && (pObProcess = VmmProcessGetNext(pObProcess, VMM_FLAG_PROCESS_SHOW_TERMINATED | VMM_FLAG_PROCESS_TOKEN))) { + while((iPidList < cPidList) && (pObProcess = VmmProcessGetNext(H, pObProcess, VMM_FLAG_PROCESS_SHOW_TERMINATED | VMM_FLAG_PROCESS_TOKEN))) { pPidEntry = pPidList + iPidList; pPidEntry->dwPID = pObProcess->dwPID; pPidEntry->dwPPID = pObProcess->dwPPID; - pPidEntry->ftCreate = VmmProcess_GetCreateTimeOpt(pObProcess); + pPidEntry->ftCreate = VmmProcess_GetCreateTimeOpt(H, pObProcess); pPidEntry->pObProcess = (PVMM_PROCESS)Ob_INCREF(pObProcess); // INCREF process object and assign to array iPidList++; } @@ -189,21 +189,21 @@ BOOL MSysProc_Tree(_In_ BOOL fVerbose, _Out_ PBYTE *ppb, _Out_ PDWORD pcb) // 3: iterate over top level items - processes with no parent qsort(pPidList, cPidList, sizeof(MSYSPROC_TREE_ENTRY), (int(*)(const void *, const void *))MSysProc_Tree_CmpSort); o = snprintf(pb, cb, fVerbose ? - " Process Pid Parent Flag User Path / Command / Time / Integrity\n------------------------------------------------------------------------------------------------\n" : - " Process Pid Parent Flag User Create Time Exit Time \n---------------------------------------------------------------------------------------------------------------\n"); + " Process Pid Parent Flag User Path / Command / Time / Integrity\n---------------------------------------------------------------------------------------------------\n" : + " Process Pid Parent Flag User Create Time Exit Time \n------------------------------------------------------------------------------------------------------------------\n"); // 3.1 process items for(i = 0; i < cPidList; i++) { pPidEntry = pPidList + i; if(pPidEntry->fProcessed) { continue; } if(MSysProc_Tree_ExistsUnprocessed(pPidList, (DWORD)cPidList, pPidEntry->dwPPID)) { continue; } - o += MSysProc_Tree_ProcessItems(pPidEntry, pPidList, (DWORD)cPidList, pb + o, cb - o, 0, fVerbose); + o += MSysProc_Tree_ProcessItems(H, pPidEntry, pPidList, (DWORD)cPidList, pb + o, cb - o, 0, fVerbose); } // 3.2 process remaining items (in case of PPID-loop which ideally should not happen) // the remaining items are processed without regards for order. for(i = 0; i < cPidList; i++) { pPidEntry = pPidList + i; if(pPidEntry->fProcessed) { continue; } - o += MSysProc_Tree_ProcessItems(pPidEntry, pPidList, (DWORD)cPidList, pb + o, cb - o, 0, fVerbose); + o += MSysProc_Tree_ProcessItems(H, pPidEntry, pPidList, (DWORD)cPidList, pb + o, cb - o, 0, fVerbose); } // 4: finish! *ppb = pb; @@ -217,10 +217,10 @@ BOOL MSysProc_Tree(_In_ BOOL fVerbose, _Out_ PBYTE *ppb, _Out_ PDWORD pcb) return fResult; } -VOID MSysProc_ListTree_ProcessUserParams_CallbackAction(_In_ PVMM_PROCESS pProcess, _In_ PVOID ctx) +VOID MSysProc_ListTree_ProcessUserParams_CallbackAction(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVOID ctx) { PDWORD pcTotalBytes = (PDWORD)ctx; - PVMMWIN_USER_PROCESS_PARAMETERS pu = VmmWin_UserProcessParameters_Get(pProcess); + PVMMWIN_USER_PROCESS_PARAMETERS pu = VmmWin_UserProcessParameters_Get(H, pProcess); DWORD c = MSYSPROC_TREE_LINE_LENGTH_VERBOSE_BASE + pProcess->pObPersistent->cuszPathKernel + 1; if(pu->cbuImagePathName > 1) { c += MSYSPROC_TREE_LINE_LENGTH_VERBOSE_BASE + pu->cbuImagePathName - 1; @@ -228,7 +228,7 @@ VOID MSysProc_ListTree_ProcessUserParams_CallbackAction(_In_ PVMM_PROCESS pProce if(pu->cbuCommandLine > 1) { c += MSYSPROC_TREE_LINE_LENGTH_VERBOSE_BASE + pu->cbuCommandLine - 1; } - if(VmmProcess_GetCreateTimeOpt(pProcess)) { + if(VmmProcess_GetCreateTimeOpt(H, pProcess)) { c += MSYSPROC_TREE_LINE_LENGTH_VERBOSE_BASE + 23 + 4 + 23; } if(pProcess->win.TOKEN.IntegrityLevel) { @@ -237,19 +237,19 @@ VOID MSysProc_ListTree_ProcessUserParams_CallbackAction(_In_ PVMM_PROCESS pProce InterlockedAdd(pcTotalBytes, c); } -NTSTATUS MSysProc_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MSysProc_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt; DWORD cbFile = 0; PBYTE pbFile = NULL; - if(!_stricmp(ctx->uszPath, "proc.txt")) { - MSysProc_Tree(FALSE, &pbFile, &cbFile); + if(!_stricmp(ctxP->uszPath, "proc.txt")) { + MSysProc_Tree(H, FALSE, &pbFile, &cbFile); nt = Util_VfsReadFile_FromPBYTE(pbFile, cbFile, pb, cb, pcbRead, cbOffset); LocalFree(pbFile); return nt; } - if(!_stricmp(ctx->uszPath, "proc-v.txt")) { - MSysProc_Tree(TRUE, &pbFile, &cbFile); + if(!_stricmp(ctxP->uszPath, "proc-v.txt")) { + MSysProc_Tree(H, TRUE, &pbFile, &cbFile); nt = Util_VfsReadFile_FromPBYTE(pbFile, cbFile, pb, cb, pcbRead, cbOffset); LocalFree(pbFile); return nt; @@ -257,23 +257,24 @@ NTSTATUS MSysProc_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcb return VMMDLL_STATUS_FILE_INVALID; } -BOOL MSysProc_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) +BOOL MSysProc_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { SIZE_T cProcess = 0; DWORD cbProcTree = 0; - if(ctx->uszPath[0]) { return FALSE; } - VmmProcessListPIDs(NULL, &cProcess, VMM_FLAG_PROCESS_SHOW_TERMINATED); + if(ctxP->uszPath[0]) { return FALSE; } + VmmProcessListPIDs(H, NULL, &cProcess, VMM_FLAG_PROCESS_SHOW_TERMINATED); if(cProcess) { cbProcTree = (DWORD)(cProcess + 2) * MSYSPROC_TREE_LINE_LENGTH; VMMDLL_VfsList_AddFile(pFileList, "proc.txt", cbProcTree, NULL); cbProcTree = MSYSPROC_TREE_LINE_LENGTH_VERBOSE_HEADER * 2; - VmmProcessActionForeachParallel(&cbProcTree, NULL, MSysProc_ListTree_ProcessUserParams_CallbackAction); - VMMDLL_VfsList_AddFile(pFileList, "proc-v.txt", cbProcTree, NULL); + if(VmmWork_ProcessActionForeachParallel_Void(H, 0, &cbProcTree, NULL, MSysProc_ListTree_ProcessUserParams_CallbackAction)) { + VMMDLL_VfsList_AddFile(pFileList, "proc-v.txt", cbProcTree, NULL); + } } return TRUE; } -VOID M_SysProc_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_SysProc_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if((pRI->tpSystem != VMM_SYSTEM_WINDOWS_X64) && (pRI->tpSystem != VMM_SYSTEM_WINDOWS_X86)) { return; } @@ -281,5 +282,5 @@ VOID M_SysProc_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) pRI->reg_info.fRootModule = TRUE; // module shows in root directory pRI->reg_fn.pfnList = MSysProc_List; // List function supported pRI->reg_fn.pfnRead = MSysProc_Read; // Read function supported - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_sys_svc.c b/vmm/m_sys_svc.c index 2500738..b1f7670 100644 --- a/vmm/m_sys_svc.c +++ b/vmm/m_sys_svc.c @@ -11,6 +11,8 @@ #include "fc.h" #include "pluginmanager.h" +static LPSTR MSYSSVC_CSV_SERVICES = "PID,Ordinal,ServiceName,DisplayName,User,StartType,State,Type1,Type2,ObjectAddress,ImagePath,DriverpathOrCmdline\n"; + #define MSYSSVC_LINELENGTH 288ULL #define MSYSSVC_LINEHEADER " # PID Start Type State Type Type Obj Address Name / Display Name User Image Path Object Name / Command Line" @@ -54,6 +56,36 @@ VOID MSysSvc_GetSvcTypeLong(_In_ PVMM_MAP_SERVICEENTRY pe, _Out_writes_(MAX_PATH } } +VOID MSysSvc_GetSvcTypeShort2(_In_ PVMM_MAP_SERVICEENTRY pe, _Out_ LPCSTR *psz1, _Out_ LPCSTR *psz2) +{ + DWORD tp = pe->ServiceStatus.dwServiceType; + if(tp & SERVICE_KERNEL_DRIVER) { + *psz1 = "Driver"; *psz2 = "KERNEL_DRIVER"; + return; + } else if(tp & SERVICE_FILE_SYSTEM_DRIVER) { + *psz1 = "Driver"; *psz2 = "FILE_SYSTEM_DRIVER"; + return; + } else if(tp & SERVICE_ADAPTER) { + *psz1 = "Driver"; *psz2 = "ADAPTER"; + return; + } else if(tp & SERVICE_RECOGNIZER_DRIVER) { + *psz1 = "Driver"; *psz2 = "RECOGNIZER_DRIVER"; + return; + } else if((tp & SERVICE_WIN32_OWN_PROCESS) && (tp & SERVICE_WIN32_SHARE_PROCESS)) { + *psz1 = "Process"; *psz2 = "OWN|SHR"; + return; + } else if(tp & SERVICE_WIN32_OWN_PROCESS) { + *psz1 = "Process"; *psz2 = "OWN"; + return; + } else if(tp & SERVICE_WIN32_SHARE_PROCESS) { + *psz1 = "Process"; *psz2 = "SHR"; + return; + } else { + *psz1 = ""; *psz2 = ""; + return; + } +} + LPSTR MSysSvc_GetSvcTypeShort(_In_ PVMM_MAP_SERVICEENTRY pe) { DWORD tp = pe->ServiceStatus.dwServiceType; @@ -105,7 +137,7 @@ LPSTR MSysSvc_GetSvcState(_In_ PVMM_MAP_SERVICEENTRY pe, _In_ BOOL fLong) return szSVC_STATE[min(8, pe->ServiceStatus.dwCurrentState)][fLong ? 1 : 0]; } -VOID MSysSvc_ReadLine_Callback(_Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_SERVICEENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR szu8) +VOID MSysSvc_ReadLineCB(_In_ VMM_HANDLE H, _Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_SERVICEENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR szu8) { CHAR uszSvcName[MAX_PATH + 1]; uszSvcName[0] = '\0'; @@ -141,7 +173,7 @@ DWORD MSysSvc_InfoFromEntry(_In_ PVMM_MAP_SERVICEENTRY pe, _Out_writes_(cbu) LPS "Service Name: %s\n" \ "Display Name: %s\n" \ "Record Address: 0x%012llx\n" \ - "Service Type: %s (0x%x)\n" \ + "Start Type: %s (0x%x)\n" \ "Service State: %s (0x%x)\n" \ "Service Type: %s (0x%x)\n" \ "Process ID (PID): %i\n" \ @@ -170,7 +202,7 @@ int MSysSvc_InfoFromPath_Filter(_In_ QWORD pvFind, _In_ QWORD qwEntry) return (DWORD)pvFind - pvEntry->dwOrdinal; } -NTSTATUS MSysSvc_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MSysSvc_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; PVMMOB_MAP_SERVICE pObSvcMap = NULL; @@ -180,16 +212,16 @@ NTSTATUS MSysSvc_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbR DWORD i, cbInfoFile, dwSvcId; CHAR usz[MAX_PATH]; CHAR szu8InfoFile[0x1000]; - if(!VmmMap_GetService(&pObSvcMap)) { goto finish; } - if(!_stricmp(ctx->uszPath, "services.txt")) { + if(!VmmMap_GetService(H, &pObSvcMap)) { goto finish; } + if(!_stricmp(ctxP->uszPath, "services.txt")) { nt = Util_VfsLineFixed_Read( - (UTIL_VFSLINEFIXED_PFN_CB)MSysSvc_ReadLine_Callback, NULL, MSYSSVC_LINELENGTH, MSYSSVC_LINEHEADER, + H, (UTIL_VFSLINEFIXED_PFN_CB)MSysSvc_ReadLineCB, NULL, MSYSSVC_LINELENGTH, MSYSSVC_LINEHEADER, pObSvcMap->pMap, pObSvcMap->cMap, sizeof(VMM_MAP_SERVICEENTRY), pb, cb, pcbRead, cbOffset ); goto finish; } - if(Util_VfsHelper_GetIdDir(ctx->uszPath, FALSE, &dwSvcId, &uszSvcSubPath)) { + if(Util_VfsHelper_GetIdDir(ctxP->uszPath, FALSE, &dwSvcId, &uszSvcSubPath)) { qwSvcId = dwSvcId; pe = Util_qfind(qwSvcId, pObSvcMap->cMap, pObSvcMap->pMap, sizeof(VMM_MAP_SERVICEENTRY), MSysSvc_InfoFromPath_Filter); if(pe) { @@ -201,7 +233,7 @@ NTSTATUS MSysSvc_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbR if(!_strnicmp("registry", uszSvcSubPath, 8)) { i = (uszSvcSubPath[8] == '\\') ? 9 : 8; _snprintf_s(usz, MAX_PATH, _TRUNCATE, "registry\\HKLM\\SYSTEM\\ControlSet001\\Services\\%s\\%s", pe->uszServiceName, uszSvcSubPath + i); - return PluginManager_Read(NULL, usz, pb, cb, pcbRead, cbOffset); + return PluginManager_Read(H, NULL, usz, pb, cb, pcbRead, cbOffset); } } } @@ -210,7 +242,7 @@ finish: return nt; } -BOOL MSysSvc_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) +BOOL MSysSvc_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { QWORD qwSvcId; DWORD i, cbInfoFile, dwSvcId; @@ -219,28 +251,28 @@ BOOL MSysSvc_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) PVMM_MAP_SERVICEENTRY pe; CHAR usz[MAX_PATH]; CHAR szu8InfoFile[0x1000]; - if(!VmmMap_GetService(&pObSvcMap)) { goto finish; } - if(0 == ctx->uszPath[0]) { + if(!VmmMap_GetService(H, &pObSvcMap)) { goto finish; } + if(0 == ctxP->uszPath[0]) { VMMDLL_VfsList_AddDirectory(pFileList, "by-id", NULL); VMMDLL_VfsList_AddDirectory(pFileList, "by-name", NULL); - VMMDLL_VfsList_AddFile(pFileList, "services.txt", UTIL_VFSLINEFIXED_LINECOUNT(pObSvcMap->cMap) * MSYSSVC_LINELENGTH, NULL); + VMMDLL_VfsList_AddFile(pFileList, "services.txt", UTIL_VFSLINEFIXED_LINECOUNT(H, pObSvcMap->cMap) * MSYSSVC_LINELENGTH, NULL); goto finish; } - if(!_stricmp(ctx->uszPath, "by-id")) { + if(!_stricmp(ctxP->uszPath, "by-id")) { for(i = 0; i < pObSvcMap->cMap; i++) { _snprintf_s(usz, 5, _TRUNCATE, "%i", pObSvcMap->pMap[i].dwOrdinal); VMMDLL_VfsList_AddDirectory(pFileList, usz, NULL); } goto finish; } - if(!_stricmp(ctx->uszPath, "by-name")) { + if(!_stricmp(ctxP->uszPath, "by-name")) { for(i = 0; i < pObSvcMap->cMap; i++) { - _snprintf_s(usz, MAX_PATH, _TRUNCATE, "%s-%i", pObSvcMap->pMap[i].uszServiceName, pObSvcMap->pMap[i].dwOrdinal); + _snprintf_s(usz, _countof(usz), _TRUNCATE, "%s-%i", pObSvcMap->pMap[i].uszServiceName, pObSvcMap->pMap[i].dwOrdinal); VMMDLL_VfsList_AddDirectory(pFileList, usz, NULL); } goto finish; } - if(Util_VfsHelper_GetIdDir(ctx->uszPath, FALSE, &dwSvcId, &uszSvcSubPath)) { + if(Util_VfsHelper_GetIdDir(ctxP->uszPath, FALSE, &dwSvcId, &uszSvcSubPath)) { qwSvcId = dwSvcId; pe = Util_qfind(qwSvcId, pObSvcMap->cMap, pObSvcMap->pMap, sizeof(VMM_MAP_SERVICEENTRY), MSysSvc_InfoFromPath_Filter); if(pe) { @@ -252,8 +284,8 @@ BOOL MSysSvc_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) } if(!_strnicmp(uszSvcSubPath, "registry", 8)) { i = (uszSvcSubPath[8] == '\\') ? 9 : 8; - _snprintf_s(usz, MAX_PATH, _TRUNCATE, "registry\\HKLM\\SYSTEM\\ControlSet001\\Services\\%s\\%s", pe->uszServiceName, uszSvcSubPath + i); - PluginManager_List(NULL, usz, pFileList); + _snprintf_s(usz, _countof(usz), _TRUNCATE, "registry\\HKLM\\SYSTEM\\ControlSet001\\Services\\%s\\%s", pe->uszServiceName, uszSvcSubPath + i); + PluginManager_List(H, NULL, usz, pFileList); goto finish; } } @@ -266,7 +298,7 @@ finish: /* * Forensic JSON log: */ -VOID MSysSvc_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) +VOID MSysSvc_FcLogJSON(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) { PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd; PVMMOB_MAP_SERVICE pObSvcMap = NULL; @@ -276,7 +308,7 @@ VOID MSysSvc_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)( if(ctxP->pProcess || !(pd = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMDLL_PLUGIN_FORENSIC_JSONDATA)))) { return; } pd->dwVersion = VMMDLL_PLUGIN_FORENSIC_JSONDATA_VERSION; pd->szjType = "service"; - if(VmmMap_GetService(&pObSvcMap)) { + if(VmmMap_GetService(H, &pObSvcMap)) { for(i = 0; i < pObSvcMap->cMap; i++) { pe = pObSvcMap->pMap + i; pd->i = i; @@ -293,14 +325,57 @@ VOID MSysSvc_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)( (pe->uszPath[0] ? pe->uszPath : "---")); pd->usz[0] = usz[0]; pd->usz[1] = usz[1]; - pfnLogJSON(pd); + pfnLogJSON(H, pd); } } Ob_DECREF(pObSvcMap); LocalFree(pd); } -VOID M_SysSvc_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +PVOID MSysSvc_FcInitialize(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP) +{ + FcFileAppend(H, "services.csv", MSYSSVC_CSV_SERVICES); + return NULL; +} + +VOID MSysSvc_FcLogCSV(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VMMDLL_CSV_HANDLE hCSV) +{ + CHAR uszSvcName[MAX_PATH], uszSvcDisplayName[MAX_PATH]; + CHAR szSvcType[MAX_PATH]; + PVMMOB_MAP_SERVICE pObSvcMap = NULL; + PVMM_MAP_SERVICEENTRY pe; + LPSTR szTp1, szTp2; + DWORD i; + if((ctxP->dwPID == 4) && VmmMap_GetService(H, &pObSvcMap)) { + for(i = 0; i < pObSvcMap->cMap; i++) { + pe = pObSvcMap->pMap + i; + uszSvcName[0] = '\0'; + uszSvcDisplayName[0] = '\0'; + strncpy_s(uszSvcName, MAX_PATH, pe->uszServiceName, _TRUNCATE); + strncpy_s(uszSvcDisplayName, MAX_PATH, pe->uszDisplayName, _TRUNCATE); + MSysSvc_GetSvcTypeLong(pe, szSvcType); + MSysSvc_GetSvcTypeShort2(pe, &szTp1, &szTp2); + //"PID,Ordinal,ServiceName,DisplayName,User,StartType,State,Type1,Type2,ObjectAddress,ImagePath,DriverpathOrCmdline" + FcCsv_Reset(hCSV); + FcFileAppend(H, "services.csv", "%i,%i,%s,%s,%s,%s,%s,%s,%s,0x%llx,%s,%s\n", + pe->dwPID, + pe->dwOrdinal, + FcCsv_String(hCSV, uszSvcName), + FcCsv_String(hCSV, uszSvcDisplayName), + FcCsv_String(hCSV, pe->uszUserAcct), + MSysSvc_GetSvcStartType(pe, TRUE), + MSysSvc_GetSvcState(pe, TRUE), + szTp1, + szTp2, + pe->vaObj, + FcCsv_String(hCSV, pe->uszImagePath), + FcCsv_String(hCSV, pe->uszPath) + ); + } + } +} + +VOID M_SysSvc_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if((pRI->tpSystem != VMM_SYSTEM_WINDOWS_X64) && (pRI->tpSystem != VMM_SYSTEM_WINDOWS_X86)) { return; } @@ -308,6 +383,8 @@ VOID M_SysSvc_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) pRI->reg_info.fRootModule = TRUE; // module shows in root directory pRI->reg_fn.pfnList = MSysSvc_List; // List function supported pRI->reg_fn.pfnRead = MSysSvc_Read; // Read function supported + pRI->reg_fnfc.pfnInitialize = MSysSvc_FcInitialize; // Forensic initialize supported + pRI->reg_fnfc.pfnLogCSV = MSysSvc_FcLogCSV; // CSV log function supported pRI->reg_fnfc.pfnLogJSON = MSysSvc_FcLogJSON; // JSON log function supported - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_sys_syscall.c b/vmm/m_sys_syscall.c index 20874a5..4c4bec6 100644 --- a/vmm/m_sys_syscall.c +++ b/vmm/m_sys_syscall.c @@ -42,12 +42,13 @@ typedef struct tdMSYSCALL_CONTEXT { * Retrieve csrss.exe process. It's a specially treated process with both * user/kernel space mapped for win32k reasons. * CALLER DECREF: return +* -- H * -- return */ -PVMM_PROCESS MSyscall_GetProcessCsrss() +PVMM_PROCESS MSyscall_GetProcessCsrss(_In_ VMM_HANDLE H) { PVMM_PROCESS pObProcess = NULL; - while((pObProcess = VmmProcessGetNext(pObProcess, 0))) { + while((pObProcess = VmmProcessGetNext(H, pObProcess, 0))) { if(!strcmp(pObProcess->szName, "csrss.exe")) { return pObProcess; } @@ -55,9 +56,9 @@ PVMM_PROCESS MSyscall_GetProcessCsrss() return NULL; } -VOID MSyscall_Initialize_BuildText(PMSYSCALL_CONTEXT ctxM, PVMM_PROCESS pProcess, DWORD iTable, PDB_HANDLE hPDB, QWORD vaBase) +VOID MSyscall_Initialize_BuildText(_In_ VMM_HANDLE H, PMSYSCALL_CONTEXT ctxM, PVMM_PROCESS pProcess, DWORD iTable, PDB_HANDLE hPDB, QWORD vaBase) { - BOOL f, f32 = ctxVmm->f32; + BOOL f, f32 = H->vmm.f32; DWORD i, c, dwSymbolDisplacement, oBuffer = 0, cbBuffer; PBYTE pbBuffer = NULL; PDWORD pdwTable = NULL; @@ -66,43 +67,43 @@ VOID MSyscall_Initialize_BuildText(PMSYSCALL_CONTEXT ctxM, PVMM_PROCESS pProcess c = f32 ? ctxM->ServiceDescriptorTable32[iTable].NumberOfServices : (DWORD)ctxM->ServiceDescriptorTable64[iTable].NumberOfServices; vaServiceTableBase = f32 ? ctxM->ServiceDescriptorTable32[iTable].ServiceTableBase : ctxM->ServiceDescriptorTable64[iTable].ServiceTableBase; if(!(pdwTable = LocalAlloc(0, c * sizeof(DWORD)))) { goto fail; } - if(!VmmRead(pProcess, vaServiceTableBase, (PBYTE)pdwTable, c * sizeof(DWORD))) { goto fail; } + if(!VmmRead(H, pProcess, vaServiceTableBase, (PBYTE)pdwTable, c * sizeof(DWORD))) { goto fail; } cbBuffer = c * (64 + MAX_PATH); if(!(pbBuffer = LocalAlloc(0, cbBuffer))) { goto fail; } for(i = 0; i < c; i++) { va = 0; f = pdwTable[i] && (va = f32 ? pdwTable[i] : vaServiceTableBase + (((LONG)pdwTable[i]) >> 4)) && - PDB_GetSymbolFromOffset(hPDB, (DWORD)(va - vaBase), szSymbolName, &dwSymbolDisplacement) && + PDB_GetSymbolFromOffset(H, hPDB, (DWORD)(va - vaBase), szSymbolName, &dwSymbolDisplacement) && (dwSymbolDisplacement == 0); oBuffer += f ? snprintf(pbBuffer + oBuffer, cbBuffer - oBuffer, "%04x %08x +%06x %llx %s %s\n", (i + 0x1000 * iTable), pdwTable[i], (DWORD)(va - vaBase), va, (iTable == 2 ? "win32k" : "nt "), szSymbolName) : snprintf(pbBuffer + oBuffer, cbBuffer - oBuffer, "%04x %08x +%06x %*llx %s %s\n", (i + 0x1000 * iTable), pdwTable[i], 0, (f32 ? 8 : 16), va, (iTable == 2 ? "win32k" : "nt "), "---"); } - ctxM->pCompressedData[iTable] = ObCompressed_NewFromByte(pbBuffer, oBuffer); + ctxM->pCompressedData[iTable] = ObCompressed_NewFromByte(H, H->vmm.pObCacheMapObCompressedShared, pbBuffer, oBuffer); fail: LocalFree(pbBuffer); LocalFree(pdwTable); } -VOID MSyscall_Initialize(PMSYSCALL_CONTEXT ctxM) +VOID MSyscall_Initialize(_In_ VMM_HANDLE H, PMSYSCALL_CONTEXT ctxM) { - BOOL f, f32 = ctxVmm->f32; + BOOL f, f32 = H->vmm.f32; DWORD i, cbRead; PDB_HANDLE hPdbWin32k; PVMM_MAP_MODULEENTRY peModuleWin32k; PVMMOB_MAP_MODULE pObModuleMap = NULL; PE_CODEVIEW_INFO CVInfoWin32k = { 0 }; PVMM_PROCESS pObProcessCsrss = NULL, pObSystemProcess = NULL; - if(!(pObSystemProcess = VmmProcessGet(4))) { goto fail; } + if(!(pObSystemProcess = VmmProcessGet(H, 4))) { goto fail; } // retrieve nt!KeServiceDescriptorTable & nt!KeServiceDescriptorTableShadow - if(!PDB_GetSymbolAddress(PDB_HANDLE_KERNEL, "KeServiceDescriptorTable", &ctxM->vaKeServiceDescriptorTable)) { goto fail; } - if(!PDB_GetSymbolAddress(PDB_HANDLE_KERNEL, "KeServiceDescriptorTableShadow", &ctxM->vaKeServiceDescriptorTableShadow)) { goto fail; } - if(!VMM_KADDR_8_16(ctxM->vaKeServiceDescriptorTable)) { goto fail; } - if(!VMM_KADDR_8_16(ctxM->vaKeServiceDescriptorTableShadow)) { goto fail; } + if(!PDB_GetSymbolAddress(H, PDB_HANDLE_KERNEL, "KeServiceDescriptorTable", &ctxM->vaKeServiceDescriptorTable)) { goto fail; } + if(!PDB_GetSymbolAddress(H, PDB_HANDLE_KERNEL, "KeServiceDescriptorTableShadow", &ctxM->vaKeServiceDescriptorTableShadow)) { goto fail; } + if(!VMM_KADDR_8_16(f32, ctxM->vaKeServiceDescriptorTable)) { goto fail; } + if(!VMM_KADDR_8_16(f32, ctxM->vaKeServiceDescriptorTableShadow)) { goto fail; } cbRead = (f32 ? sizeof(KSERVICE_DESCRIPTOR_TABLE32) : sizeof(KSERVICE_DESCRIPTOR_TABLE64)); - if(!VmmRead(pObSystemProcess, ctxM->vaKeServiceDescriptorTable, ctxM->pbServiceDescriptorTable, cbRead)) { goto fail; } // Table - if(!VmmRead(pObSystemProcess, ctxM->vaKeServiceDescriptorTableShadow, ctxM->pbServiceDescriptorTable + cbRead, 2 * cbRead)) { goto fail; } // TableShadow + if(!VmmRead(H, pObSystemProcess, ctxM->vaKeServiceDescriptorTable, ctxM->pbServiceDescriptorTable, cbRead)) { goto fail; } // Table + if(!VmmRead(H, pObSystemProcess, ctxM->vaKeServiceDescriptorTableShadow, ctxM->pbServiceDescriptorTable + cbRead, 2 * cbRead)) { goto fail; } // TableShadow // validate nt!KeServiceDescriptorTable / nt!KeServiceDescriptorTableShadow for(i = 0; i < 3; i++) { if(f32) { @@ -122,15 +123,15 @@ VOID MSyscall_Initialize(PMSYSCALL_CONTEXT ctxM) } } // fetch win32k infos - if(!(pObProcessCsrss = MSyscall_GetProcessCsrss())) { goto fail_win32k; } - if(!VmmMap_GetModuleEntryEx(pObSystemProcess, 0, "win32k.sys", &pObModuleMap, &peModuleWin32k)) { goto fail_win32k; } - if(!(hPdbWin32k = PDB_GetHandleFromModuleAddress(pObProcessCsrss, peModuleWin32k->vaBase))) { goto fail_win32k; } + if(!(pObProcessCsrss = MSyscall_GetProcessCsrss(H))) { goto fail_win32k; } + if(!VmmMap_GetModuleEntryEx(H, pObSystemProcess, 0, "win32k.sys", &pObModuleMap, &peModuleWin32k)) { goto fail_win32k; } + if(!(hPdbWin32k = PDB_GetHandleFromModuleAddress(H, pObProcessCsrss, peModuleWin32k->vaBase))) { goto fail_win32k; } // build text files in-memory (win32k) - MSyscall_Initialize_BuildText(ctxM, pObProcessCsrss, 2, hPdbWin32k, peModuleWin32k->vaBase); + MSyscall_Initialize_BuildText(H, ctxM, pObProcessCsrss, 2, hPdbWin32k, peModuleWin32k->vaBase); fail_win32k: // build text files in-memory (nt) - MSyscall_Initialize_BuildText(ctxM, pObSystemProcess, 0, PDB_HANDLE_KERNEL, ctxVmm->kernel.vaBase); - MSyscall_Initialize_BuildText(ctxM, pObSystemProcess, 1, PDB_HANDLE_KERNEL, ctxVmm->kernel.vaBase); + MSyscall_Initialize_BuildText(H, ctxM, pObSystemProcess, 0, PDB_HANDLE_KERNEL, H->vmm.kernel.vaBase); + MSyscall_Initialize_BuildText(H, ctxM, pObSystemProcess, 1, PDB_HANDLE_KERNEL, H->vmm.kernel.vaBase); fail: Ob_DECREF(pObModuleMap); Ob_DECREF(pObSystemProcess); @@ -138,22 +139,22 @@ fail: ctxM->fInit = TRUE; } -PMSYSCALL_CONTEXT MSyscall_GetContext(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) +PMSYSCALL_CONTEXT MSyscall_GetContext(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP) { PMSYSCALL_CONTEXT ctxM = (PMSYSCALL_CONTEXT)ctxP->ctxM; if(ctxM->fInit) { return ctxM; } - EnterCriticalSection(&ctxVmm->LockPlugin); + EnterCriticalSection(&H->vmm.LockPlugin); if(ctxM->fInit) { goto finish; } - PDB_Initialize_WaitComplete(); - MSyscall_Initialize(ctxM); + PDB_Initialize_WaitComplete(H); + MSyscall_Initialize(H, ctxM); finish: - LeaveCriticalSection(&ctxVmm->LockPlugin); + LeaveCriticalSection(&H->vmm.LockPlugin); return ctxM; } -NTSTATUS MSyscall_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MSyscall_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { - PMSYSCALL_CONTEXT ctxM = MSyscall_GetContext(ctxP); + PMSYSCALL_CONTEXT ctxM = MSyscall_GetContext(H, ctxP); if(!_stricmp(ctxP->uszPath, "syscall_nt.txt")) { return Util_VfsReadFile_FromObCompressed(ctxM->pCompressedData[0], pb, cb, pcbRead, cbOffset); } @@ -166,9 +167,9 @@ NTSTATUS MSyscall_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pc return VMMDLL_STATUS_FILE_INVALID; } -BOOL MSyscall_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) +BOOL MSyscall_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { - PMSYSCALL_CONTEXT ctxM = MSyscall_GetContext(ctxP); + PMSYSCALL_CONTEXT ctxM = MSyscall_GetContext(H, ctxP); if(ctxP->uszPath[0]) { return FALSE; } VMMDLL_VfsList_AddFile(pFileList, "syscall_nt.txt", ObCompress_Size(ctxM->pCompressedData[0]), NULL); VMMDLL_VfsList_AddFile(pFileList, "syscall_nt_shadow.txt", ObCompress_Size(ctxM->pCompressedData[1]), NULL); @@ -176,7 +177,7 @@ BOOL MSyscall_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) return TRUE; } -VOID MSyscall_Close(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) +VOID MSyscall_Close(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP) { PMSYSCALL_CONTEXT ctxM = (PMSYSCALL_CONTEXT)ctxP->ctxM; Ob_DECREF(ctxM->pCompressedData[0]); @@ -185,7 +186,7 @@ VOID MSyscall_Close(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) LocalFree(ctxM); } -VOID M_SysSyscall_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_SysSyscall_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if((pRI->tpSystem != VMM_SYSTEM_WINDOWS_X64) && (pRI->tpSystem != VMM_SYSTEM_WINDOWS_X86)) { return; } @@ -195,5 +196,5 @@ VOID M_SysSyscall_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) pRI->reg_fn.pfnList = MSyscall_List; // List function supported pRI->reg_fn.pfnRead = MSyscall_Read; // Read function supported pRI->reg_fn.pfnClose = MSyscall_Close; // Close function supported - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_sys_task.c b/vmm/m_sys_task.c index f09dd54..69f97fa 100644 --- a/vmm/m_sys_task.c +++ b/vmm/m_sys_task.c @@ -16,6 +16,8 @@ #include "fc.h" #include "pluginmanager.h" +static LPSTR MSYSTASK_CSV_TASKS = "GUID,TaskName,TaskPath,User,TimeMostRecent,CommandLine,Parameters,TimeReg,TimeCreate,TimeLastRun,TimeCompleted\n"; + #define MSYSTASK_LINELENGTH 256ULL #define MSYSTASK_LINEHEADER " # Task GUID Task Name Time (Most Recent) User Command Line :: Parameters" @@ -99,20 +101,20 @@ QWORD VmmSysTask_Util_HashGUID(_In_reads_opt_(39) LPSTR szGUID) * Populate a task with information such as action and additional time stamps. * The data is retrieved from the task 'TackCache\Tasks\{GUID}' key values. */ -VOID VmmSysTask_Initialize_AddInfo(_In_ PVMM_TASK_SETUP_CONTEXT ctx, _In_ POB_REGISTRY_KEY pKey, _In_ PVMM_MAP_TASKENTRY pTask) +VOID VmmSysTask_Initialize_AddInfo(_In_ VMM_HANDLE H, _In_ PVMM_TASK_SETUP_CONTEXT ctx, _In_ POB_REGISTRY_KEY pKey, _In_ PVMM_MAP_TASKENTRY pTask) { DWORD dw, dwVer, cb, o; BYTE pb[0x800]; WCHAR wsz[MAX_PATH + 1]; // time stamps from 'DynamicInfo' value: ZeroMemory(pb, 0x24); - if(VmmWinReg_ValueQuery5(ctx->pHive, pKey, "DynamicInfo", NULL, pb, sizeof(pb), NULL)) { + if(VmmWinReg_ValueQuery5(H, ctx->pHive, pKey, "DynamicInfo", NULL, pb, sizeof(pb), NULL)) { if(pb[0x0b] == 0x01) { pTask->ftCreate = *(PQWORD)(pb + 0x04); } if(pb[0x13] == 0x01) { pTask->ftLastRun = *(PQWORD)(pb + 0x0c); } if(pb[0x23] == 0x01) { pTask->ftLastCompleted = *(PQWORD)(pb + 0x1c); } } // user, command, parameters from 'Actions' value: - if(VmmWinReg_ValueQuery5(ctx->pHive, pKey, "Actions", NULL, pb, sizeof(pb), &cb)) { + if(VmmWinReg_ValueQuery5(H, ctx->pHive, pKey, "Actions", NULL, pb, sizeof(pb), &cb)) { dwVer = *(PWORD)pb; if(!cb || (cb < 0x1c) || !dwVer || dwVer > 3) { return; } // [user] @@ -160,6 +162,7 @@ VOID VmmSysTask_Initialize_AddTask_FullPath(_In_ PVMM_TASK_SETUP_CONTEXT ctx, _I * Create or retrieve a single task in the initialization phase. */ PVMM_MAP_TASKENTRY VmmSysTask_Initialize_AddTask( + _In_ VMM_HANDLE H, _In_ PVMM_TASK_SETUP_CONTEXT ctx, _In_ QWORD ftRegLastWrite, _In_ LPSTR uszName, @@ -209,7 +212,7 @@ PVMM_MAP_TASKENTRY VmmSysTask_Initialize_AddTask( return pTask; } -VOID VmmSysTask_Initialize_Tree(_In_ PVMM_TASK_SETUP_CONTEXT ctx, _In_ POB_REGISTRY_KEY pKey, _In_ BOOL fTopLevel, _In_opt_ PVMM_MAP_TASKENTRY pParentTask) +VOID VmmSysTask_Initialize_Tree(_In_ VMM_HANDLE H, _In_ PVMM_TASK_SETUP_CONTEXT ctx, _In_ POB_REGISTRY_KEY pKey, _In_ BOOL fTopLevel, _In_opt_ PVMM_MAP_TASKENTRY pParentTask) { LPSTR uszGUID; BYTE pbBuffer[80], pbRegGUID[80]; @@ -221,14 +224,14 @@ VOID VmmSysTask_Initialize_Tree(_In_ PVMM_TASK_SETUP_CONTEXT ctx, _In_ POB_REGIS // 1: fetch current task entry/directory. if(!fTopLevel) { VmmWinReg_KeyInfo(ctx->pHive, pKey, &KeyInfo); - if(!VmmWinReg_ValueQuery5(ctx->pHive, pKey, "Id", &dwKeyValueTp, pbRegGUID, sizeof(pbRegGUID) - 2, NULL)) { return; } + if(!VmmWinReg_ValueQuery5(H, ctx->pHive, pKey, "Id", &dwKeyValueTp, pbRegGUID, sizeof(pbRegGUID) - 2, NULL)) { return; } if(!CharUtil_WtoU((LPWSTR)pbRegGUID, -1, pbBuffer, sizeof(pbBuffer), &uszGUID, NULL, 0)) { return; } - if(!(pTask = VmmSysTask_Initialize_AddTask(ctx, KeyInfo.ftLastWrite, KeyInfo.uszName, uszGUID, pParentTask))) { return; } + if(!(pTask = VmmSysTask_Initialize_AddTask(H, ctx, KeyInfo.ftLastWrite, KeyInfo.uszName, uszGUID, pParentTask))) { return; } } // 2: iterate over sub-directories - if((pmObKeyList = VmmWinReg_KeyList(ctx->pHive, pKey))) { + if((pmObKeyList = VmmWinReg_KeyList(H, ctx->pHive, pKey))) { while((pObSubKey = ObMap_Pop(pmObKeyList))) { - VmmSysTask_Initialize_Tree(ctx, pObSubKey, FALSE, pTask); + VmmSysTask_Initialize_Tree(H, ctx, pObSubKey, FALSE, pTask); Ob_DECREF(pObSubKey); } Ob_DECREF_NULL(&pmObKeyList); @@ -241,7 +244,7 @@ VOID VmmSysTask_Initialize_Tree(_In_ PVMM_TASK_SETUP_CONTEXT ctx, _In_ POB_REGIS * but if data have been corrupted this adds to robustness by having a 2nd * way to retrieve data. */ -PVMM_MAP_TASKENTRY VmmSysTask_Initialize_GetTaskByPath(_In_ PVMM_TASK_SETUP_CONTEXT ctx, _In_ LPSTR uszPath, _In_opt_ PVMM_REGISTRY_KEY_INFO pKeyInfo) +PVMM_MAP_TASKENTRY VmmSysTask_Initialize_GetTaskByPath(_In_ VMM_HANDLE H, _In_ PVMM_TASK_SETUP_CONTEXT ctx, _In_ LPSTR uszPath, _In_opt_ PVMM_REGISTRY_KEY_INFO pKeyInfo) { QWORD qwHash; LPSTR uszNewName; @@ -252,13 +255,13 @@ PVMM_MAP_TASKENTRY VmmSysTask_Initialize_GetTaskByPath(_In_ PVMM_TASK_SETUP_CONT // get level -1 if(!(uszNewName = CharUtil_PathSplitLastEx(uszPath, uszNewPath, sizeof(uszNewPath)))) { return NULL; } if((uszNewPath[0] != 0) && (uszNewPath[1] != 0)) { - pTaskParent = VmmSysTask_Initialize_GetTaskByPath(ctx, uszNewPath, NULL); + pTaskParent = VmmSysTask_Initialize_GetTaskByPath(H, ctx, uszNewPath, NULL); if(!pTaskParent) { return NULL; } } - return VmmSysTask_Initialize_AddTask(ctx, (pKeyInfo ? pKeyInfo->ftLastWrite : 0), uszNewName, (pKeyInfo ? pKeyInfo->uszName : NULL), pTaskParent); + return VmmSysTask_Initialize_AddTask(H, ctx, (pKeyInfo ? pKeyInfo->ftLastWrite : 0), uszNewName, (pKeyInfo ? pKeyInfo->uszName : NULL), pTaskParent); } -VOID VmmSysTask_Initialize_AddInfoOrType(_In_ PVMM_TASK_SETUP_CONTEXT ctx, _In_ LPSTR uszKeyPath, _In_ DWORD dwTypeOpt) +VOID VmmSysTask_Initialize_AddInfoOrType(_In_ VMM_HANDLE H, _In_ PVMM_TASK_SETUP_CONTEXT ctx, _In_ LPSTR uszKeyPath, _In_ DWORD dwTypeOpt) { PVMM_MAP_TASKENTRY pTask; POB_MAP pmObKeyList = NULL; @@ -266,16 +269,16 @@ VOID VmmSysTask_Initialize_AddInfoOrType(_In_ PVMM_TASK_SETUP_CONTEXT ctx, _In_ VMM_REGISTRY_KEY_INFO KeyInfo = { 0 }; BYTE pbBufferPath[2 * MAX_PATH], pbBuffer[MAX_PATH]; LPSTR uszPath; - if((pObKey = VmmWinReg_KeyGetByPath(ctx->pHive, uszKeyPath)) && (pmObKeyList = VmmWinReg_KeyList(ctx->pHive, pObKey))) { + if((pObKey = VmmWinReg_KeyGetByPath(H, ctx->pHive, uszKeyPath)) && (pmObKeyList = VmmWinReg_KeyList(H, ctx->pHive, pObKey))) { while((pObSubKey = ObMap_Pop(pmObKeyList))) { VmmWinReg_KeyInfo(ctx->pHive, pObSubKey, &KeyInfo); pTask = ObMap_GetByKey(ctx->pmTask, VmmSysTask_Util_HashGUID(KeyInfo.uszName)); if(!pTask && !dwTypeOpt) { // code path should only be triggered on corrupt (due to paging or intentionally manipulated) task cache ZeroMemory(pbBufferPath, sizeof(pbBufferPath)); - if(VmmWinReg_ValueQuery5(ctx->pHive, pObSubKey, "Path", NULL, pbBufferPath, sizeof(pbBufferPath) - 2, NULL)) { + if(VmmWinReg_ValueQuery5(H, ctx->pHive, pObSubKey, "Path", NULL, pbBufferPath, sizeof(pbBufferPath) - 2, NULL)) { if(CharUtil_WtoU((LPWSTR)pbBufferPath, -1, pbBuffer, sizeof(pbBuffer), &uszPath, NULL, CHARUTIL_FLAG_TRUNCATE)) { - pTask = VmmSysTask_Initialize_GetTaskByPath(ctx, uszPath, &KeyInfo); + pTask = VmmSysTask_Initialize_GetTaskByPath(H, ctx, uszPath, &KeyInfo); } } } @@ -283,7 +286,7 @@ VOID VmmSysTask_Initialize_AddInfoOrType(_In_ PVMM_TASK_SETUP_CONTEXT ctx, _In_ if(dwTypeOpt) { pTask->tp = pTask->tp | dwTypeOpt; } else { - VmmSysTask_Initialize_AddInfo(ctx, pObSubKey, pTask); + VmmSysTask_Initialize_AddInfo(H, ctx, pObSubKey, pTask); } } Ob_DECREF(pObSubKey); @@ -303,7 +306,7 @@ VOID VmmSysTask_CallbackCleanup_ObObjectMap(PVMMOB_MAP_TASK pOb) LocalFree(pOb->pbMultiText); } -VOID VmmSysTask_Initialize_DoWork(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) +VOID VmmSysTask_Initialize_DoWork(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP) { BOOL fResult = FALSE; DWORD cAll, cTask, cbData, cbo, i, iTask; @@ -312,26 +315,26 @@ VOID VmmSysTask_Initialize_DoWork(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) POB_REGISTRY_KEY pObKey = NULL; VMM_TASK_SETUP_CONTEXT ctxInit = { 0 }; // 1: INIT: - if(!(ctxInit.pmAll = ObMap_New(OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } - if(!(ctxInit.pmDir = ObMap_New(OB_MAP_FLAGS_OBJECT_VOID))) { goto fail; } - if(!(ctxInit.pmTask = ObMap_New(OB_MAP_FLAGS_OBJECT_VOID))) { goto fail; } - if(!(ctxInit.psm = ObStrMap_New(OB_STRMAP_FLAGS_CASE_INSENSITIVE | OB_STRMAP_FLAGS_STR_ASSIGN_TEMPORARY))) { goto fail; } + if(!(ctxInit.pmAll = ObMap_New(H, OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } + if(!(ctxInit.pmDir = ObMap_New(H, OB_MAP_FLAGS_OBJECT_VOID))) { goto fail; } + if(!(ctxInit.pmTask = ObMap_New(H, OB_MAP_FLAGS_OBJECT_VOID))) { goto fail; } + if(!(ctxInit.psm = ObStrMap_New(H, OB_STRMAP_FLAGS_CASE_INSENSITIVE | OB_STRMAP_FLAGS_STR_ASSIGN_TEMPORARY))) { goto fail; } // 2: ITERATE OVER 'TaskCache\Tree': - if(!VmmWinReg_KeyHiveGetByFullPath(TASKREGROOT "Tree", &ctxInit.pHive, &pObKey)) { goto fail; } - VmmSysTask_Initialize_Tree(&ctxInit, pObKey, TRUE, NULL); + if(!VmmWinReg_KeyHiveGetByFullPath(H, TASKREGROOT "Tree", &ctxInit.pHive, &pObKey)) { goto fail; } + VmmSysTask_Initialize_Tree(H, &ctxInit, pObKey, TRUE, NULL); // 3: ADD TASK ADDITIONAL INFO: - VmmSysTask_Initialize_AddInfoOrType(&ctxInit, TASKREGROOT_LOCALHIVE "Tasks", 0); + VmmSysTask_Initialize_AddInfoOrType(H, &ctxInit, TASKREGROOT_LOCALHIVE "Tasks", 0); // 4: ADD TASK TYPE: - VmmSysTask_Initialize_AddInfoOrType(&ctxInit, TASKREGROOT_LOCALHIVE "Boot", VMM_MAP_TASKENTRY_TP_BOOT); - VmmSysTask_Initialize_AddInfoOrType(&ctxInit, TASKREGROOT_LOCALHIVE "Logon", VMM_MAP_TASKENTRY_TP_LOGON); - VmmSysTask_Initialize_AddInfoOrType(&ctxInit, TASKREGROOT_LOCALHIVE "Maintenance", VMM_MAP_TASKENTRY_TP_MAINTENANCE); - VmmSysTask_Initialize_AddInfoOrType(&ctxInit, TASKREGROOT_LOCALHIVE "Plain", VMM_MAP_TASKENTRY_TP_PLAIN); + VmmSysTask_Initialize_AddInfoOrType(H, &ctxInit, TASKREGROOT_LOCALHIVE "Boot", VMM_MAP_TASKENTRY_TP_BOOT); + VmmSysTask_Initialize_AddInfoOrType(H, &ctxInit, TASKREGROOT_LOCALHIVE "Logon", VMM_MAP_TASKENTRY_TP_LOGON); + VmmSysTask_Initialize_AddInfoOrType(H, &ctxInit, TASKREGROOT_LOCALHIVE "Maintenance", VMM_MAP_TASKENTRY_TP_MAINTENANCE); + VmmSysTask_Initialize_AddInfoOrType(H, &ctxInit, TASKREGROOT_LOCALHIVE "Plain", VMM_MAP_TASKENTRY_TP_PLAIN); // 5: CREATE MAP / FINALIZE: cAll = ObMap_Size(ctxInit.pmAll); cTask = ObMap_Size(ctxInit.pmTask); if(cAll > 0xffff) { goto fail; } cbData = sizeof(VMMOB_MAP_TASK) + cAll * sizeof(VMM_MAP_TASKENTRY) + ((SIZE_T)cAll + cTask + cTask) * sizeof(QWORD); - pObMap = Ob_Alloc(OB_TAG_MAP_TASK, LMEM_ZEROINIT, cbData, (OB_CLEANUP_CB)VmmSysTask_CallbackCleanup_ObObjectMap, NULL); + pObMap = Ob_AllocEx(H, OB_TAG_MAP_TASK, LMEM_ZEROINIT, cbData, (OB_CLEANUP_CB)VmmSysTask_CallbackCleanup_ObObjectMap, NULL); if(!pObMap) { goto fail; } cbo = sizeof(VMMOB_MAP_TASK) + cAll * sizeof(VMM_MAP_TASKENTRY); pObMap->pqwByHashName = (PQWORD)((PBYTE)pObMap + cbo); cbo += cAll * sizeof(QWORD); @@ -369,7 +372,7 @@ VOID VmmSysTask_Initialize_DoWork(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) fail: Ob_DECREF(pObMap); Ob_DECREF(pObKey); - if(!fResult && (pObMap = Ob_Alloc(OB_TAG_MAP_TASK, LMEM_ZEROINIT, sizeof(VMMOB_MAP_TASK), NULL, NULL))) { + if(!fResult && (pObMap = Ob_AllocEx(H, OB_TAG_MAP_TASK, LMEM_ZEROINIT, sizeof(VMMOB_MAP_TASK), NULL, NULL))) { ObContainer_SetOb((POB_CONTAINER)ctxP->ctxM, pObMap); Ob_DECREF(pObMap); } @@ -386,13 +389,13 @@ fail: * -- ctxP * -- return */ -PVMMOB_MAP_TASK VmmSysTask_GetTaskMap(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) +PVMMOB_MAP_TASK VmmSysTask_GetTaskMap(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP) { PVMMOB_MAP_TASK pOb; if((pOb = ObContainer_GetOb((POB_CONTAINER)ctxP->ctxM))) { return pOb; } - EnterCriticalSection(&ctxVmm->LockPlugin); - VmmSysTask_Initialize_DoWork(ctxP); - LeaveCriticalSection(&ctxVmm->LockPlugin); + EnterCriticalSection(&H->vmm.LockPlugin); + VmmSysTask_Initialize_DoWork(H, ctxP); + LeaveCriticalSection(&H->vmm.LockPlugin); return ObContainer_GetOb((POB_CONTAINER)ctxP->ctxM); } @@ -421,7 +424,7 @@ PVMM_MAP_TASKENTRY VmmSysTask_GetTaskByHash(_In_ PVMMOB_MAP_TASK pObTaskMap, _In /* * Generate the file 'taskinfo.txt' in each individual task: */ -DWORD MSysTask_InfoFromEntry(_In_ PVMM_MAP_TASKENTRY pe, _Out_writes_(cbu) LPSTR usz, _In_ DWORD cbu) +DWORD MSysTask_InfoFromEntry(_In_ VMM_HANDLE H, _In_ PVMM_MAP_TASKENTRY pe, _Out_writes_(cbu) LPSTR usz, _In_ DWORD cbu) { CHAR szTimeRegWR[24], szTimeCreate[24], szTimeLastRun[24], szTimeCompleted[24]; Util_FileTime2String(pe->ftRegLastWrite, szTimeRegWR); @@ -455,18 +458,18 @@ DWORD MSysTask_InfoFromEntry(_In_ PVMM_MAP_TASKENTRY pe, _Out_writes_(cbu) LPSTR /* * Read a 'single entry' file - the 'taskinfo.txt' a registry sub-folder file. */ -NTSTATUS MSysTask_ReadSingleEntry(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset, _In_ PVMM_MAP_TASKENTRY pTask, _In_ LPSTR uszPath) +NTSTATUS MSysTask_ReadSingleEntry(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset, _In_ PVMM_MAP_TASKENTRY pTask, _In_ LPSTR uszPath) { DWORD cbInfoFile; CHAR usz[MAX_PATH]; CHAR szu8InfoFile[0x1000]; if(!_stricmp("taskinfo.txt", uszPath)) { - cbInfoFile = MSysTask_InfoFromEntry(pTask, szu8InfoFile, sizeof(szu8InfoFile)); + cbInfoFile = MSysTask_InfoFromEntry(H, pTask, szu8InfoFile, sizeof(szu8InfoFile)); return Util_VfsReadFile_FromPBYTE((PBYTE)szu8InfoFile, cbInfoFile, pb, cb, pcbRead, cbOffset); } if(!_strnicmp("registry", uszPath, 8)) { _snprintf_s(usz, MAX_PATH, _TRUNCATE, "registry\\HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Schedule\\TaskCache\\Tasks\\%s\\%s", pTask->uszGUID, uszPath + (uszPath[8] ? 9 : 8)); - return PluginManager_Read(NULL, usz, pb, cb, pcbRead, cbOffset); + return PluginManager_Read(H, NULL, usz, pb, cb, pcbRead, cbOffset); } return VMMDLL_STATUS_FILE_INVALID; } @@ -474,7 +477,7 @@ NTSTATUS MSysTask_ReadSingleEntry(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_ /* * Generate a single line in the tasks.txt file. */ -VOID MSysTask_ReadLine_CB(_In_ PVMMOB_MAP_TASK pObTaskMap, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVOID pv, _Out_writes_(cbLineLength + 1) LPSTR szu8) +VOID MSysTask_ReadLine_CB(_In_ VMM_HANDLE H, _In_ PVMMOB_MAP_TASK pObTaskMap, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVOID pv, _Out_writes_(cbLineLength + 1) LPSTR szu8) { PVMM_MAP_TASKENTRY pe = pObTaskMap->pMap + pObTaskMap->pqwByTaskName[ie]; CHAR szTime[24]; @@ -492,7 +495,7 @@ VOID MSysTask_ReadLine_CB(_In_ PVMMOB_MAP_TASK pObTaskMap, _In_ DWORD cbLineLeng ); } -NTSTATUS MSysTask_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MSysTask_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; PVMMOB_MAP_TASK pObTaskMap = NULL; @@ -500,10 +503,10 @@ NTSTATUS MSysTask_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pc LPSTR uszSubPath; QWORD qwHash; PVMM_MAP_TASKENTRY pe; - if(!(pObTaskMap = VmmSysTask_GetTaskMap(ctxP))) { goto finish; } + if(!(pObTaskMap = VmmSysTask_GetTaskMap(H, ctxP))) { goto finish; } if(!_stricmp(ctxP->uszPath, "tasks.txt")) { nt = Util_VfsLineFixed_Read( - (UTIL_VFSLINEFIXED_PFN_CB)MSysTask_ReadLine_CB, pObTaskMap, MSYSTASK_LINELENGTH, MSYSTASK_LINEHEADER, + H, (UTIL_VFSLINEFIXED_PFN_CB)MSysTask_ReadLine_CB, pObTaskMap, MSYSTASK_LINELENGTH, MSYSTASK_LINEHEADER, pObTaskMap->pMap, pObTaskMap->cTask, sizeof(VMM_MAP_TASKENTRY), pb, cb, pcbRead, cbOffset ); @@ -518,7 +521,7 @@ NTSTATUS MSysTask_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pc qwHash = CharUtil_HashNameFsU(uszGUID, 0); pe = VmmSysTask_GetTaskByHash(pObTaskMap, pObTaskMap->pqwByHashName, pObTaskMap->cMap, qwHash); } - nt = MSysTask_ReadSingleEntry(ctxP,pb, cb, pcbRead, cbOffset, pe, uszSubPath); + nt = MSysTask_ReadSingleEntry(H, ctxP, pb, cb, pcbRead, cbOffset, pe, uszSubPath); goto finish; } finish: @@ -529,37 +532,37 @@ finish: /* * List a single entry directory - i.e. the directory as such or the registry sub-directory. */ -VOID MSysTask_ListSingleEntry(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList, _In_ PVMM_MAP_TASKENTRY pTask, _In_ LPSTR uszPath) +VOID MSysTask_ListSingleEntry(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList, _In_ PVMM_MAP_TASKENTRY pTask, _In_ LPSTR uszPath) { DWORD cbInfoFile; CHAR usz[MAX_PATH]; CHAR szu8InfoFile[0x1000]; if(!pTask) { return; } if(!uszPath[0]) { - cbInfoFile = MSysTask_InfoFromEntry(pTask, szu8InfoFile, sizeof(szu8InfoFile)); + cbInfoFile = MSysTask_InfoFromEntry(H, pTask, szu8InfoFile, sizeof(szu8InfoFile)); VMMDLL_VfsList_AddFile(pFileList, "taskinfo.txt", cbInfoFile, NULL); VMMDLL_VfsList_AddDirectory(pFileList, "registry", NULL); return; } if(!_strnicmp(uszPath, "registry", 8)) { _snprintf_s(usz, MAX_PATH, _TRUNCATE, "registry\\HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Schedule\\TaskCache\\Tasks\\%s\\%s", pTask->uszGUID, uszPath + (uszPath[8] ? 9 : 8)); - PluginManager_List(NULL, usz, pFileList); + PluginManager_List(H, NULL, usz, pFileList); return; } } -BOOL MSysTask_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) +BOOL MSysTask_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { QWORD i, qwHash; CHAR uszGUID[MAX_PATH]; LPSTR uszSubPath; PVMM_MAP_TASKENTRY pe; PVMMOB_MAP_TASK pObTaskMap = NULL; - if(!(pObTaskMap = VmmSysTask_GetTaskMap(ctxP))) { goto finish; } + if(!(pObTaskMap = VmmSysTask_GetTaskMap(H, ctxP))) { goto finish; } if(!ctxP->uszPath[0]) { VMMDLL_VfsList_AddDirectory(pFileList, "by-guid", NULL); VMMDLL_VfsList_AddDirectory(pFileList, "by-name", NULL); - VMMDLL_VfsList_AddFile(pFileList, "tasks.txt", UTIL_VFSLINEFIXED_LINECOUNT(pObTaskMap->cTask) * MSYSTASK_LINELENGTH, NULL); + VMMDLL_VfsList_AddFile(pFileList, "tasks.txt", UTIL_VFSLINEFIXED_LINECOUNT(H, pObTaskMap->cTask) * MSYSTASK_LINELENGTH, NULL); goto finish; } if(!_stricmp("by-guid", ctxP->uszPath)) { @@ -585,7 +588,7 @@ BOOL MSysTask_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) qwHash = CharUtil_HashNameFsU(uszGUID, 0); pe = VmmSysTask_GetTaskByHash(pObTaskMap, pObTaskMap->pqwByHashName, pObTaskMap->cMap, qwHash); } - MSysTask_ListSingleEntry(ctxP, pFileList, pe, uszSubPath); + MSysTask_ListSingleEntry(H, ctxP, pFileList, pe, uszSubPath); goto finish; } finish: @@ -596,19 +599,21 @@ finish: /* * Forensic Timeline: Retrieve ObTaskMap into ctxfc. */ -PVOID MSysTask_FcInitialize(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) +PVOID MSysTask_FcInitialize(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP) { - return VmmSysTask_GetTaskMap(ctxP); + FcFileAppend(H, "tasks.csv", MSYSTASK_CSV_TASKS); + return VmmSysTask_GetTaskMap(H, ctxP); } /* * Forensic Timeline: Populate timeline information: */ VOID MSysTask_FcTimeline( + _In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc, _In_ HANDLE hTimeline, - _In_ VOID(*pfnAddEntry)(_In_ HANDLE hTimeline, _In_ QWORD ft, _In_ DWORD dwAction, _In_ DWORD dwPID, _In_ DWORD dwData32, _In_ QWORD dwData64, _In_ LPSTR uszText), - _In_ VOID(*pfnEntryAddBySql)(_In_ HANDLE hTimeline, _In_ DWORD cEntrySql, _In_ LPSTR *pszEntrySql) + _In_ VOID(*pfnAddEntry)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ QWORD ft, _In_ DWORD dwAction, _In_ DWORD dwPID, _In_ DWORD dwData32, _In_ QWORD dwData64, _In_ LPSTR uszText), + _In_ VOID(*pfnEntryAddBySql)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ DWORD cEntrySql, _In_ LPSTR *pszEntrySql) ) { PVMMOB_MAP_TASK pObTaskMap = ctxfc; PVMM_MAP_TASKENTRY pe; @@ -618,10 +623,10 @@ VOID MSysTask_FcTimeline( for(i = 0; i < pObTaskMap->cTask; i++) { pe = pObTaskMap->pMap + pObTaskMap->pqwByTaskName[i]; _snprintf_s(usz, MAX_PATH, _TRUNCATE, "%s - [%s :: %s] (%s)", pe->uszName, pe->uszActionCommand, pe->uszActionParameters, pe->uszActionUser); - if(pe->ftRegLastWrite) { pfnAddEntry(hTimeline, pe->ftRegLastWrite, FC_TIMELINE_ACTION_MODIFY, 0, 0, 0, usz); } - if(pe->ftCreate) { pfnAddEntry(hTimeline, pe->ftCreate, FC_TIMELINE_ACTION_CREATE, 0, 0, 0, usz); } - if(pe->ftLastRun) { pfnAddEntry(hTimeline, pe->ftLastRun, FC_TIMELINE_ACTION_READ, 0, 0, 0, usz); } - if(pe->ftLastCompleted) { pfnAddEntry(hTimeline, pe->ftLastCompleted, FC_TIMELINE_ACTION_DELETE, 0, 0, 0, usz); } + if(pe->ftRegLastWrite) { pfnAddEntry(H, hTimeline, pe->ftRegLastWrite, FC_TIMELINE_ACTION_MODIFY, 0, 0, 0, usz); } + if(pe->ftCreate) { pfnAddEntry(H, hTimeline, pe->ftCreate, FC_TIMELINE_ACTION_CREATE, 0, 0, 0, usz); } + if(pe->ftLastRun) { pfnAddEntry(H, hTimeline, pe->ftLastRun, FC_TIMELINE_ACTION_READ, 0, 0, 0, usz); } + if(pe->ftLastCompleted) { pfnAddEntry(H, hTimeline, pe->ftLastCompleted, FC_TIMELINE_ACTION_DELETE, 0, 0, 0, usz); } } } } @@ -629,7 +634,7 @@ VOID MSysTask_FcTimeline( /* * Forensic JSON log: */ -VOID MSysTask_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) +VOID MSysTask_FcLogJSON(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) { PVMMDLL_PLUGIN_FORENSIC_JSONDATA pd; PVMMOB_MAP_TASK pObTaskMap = NULL; @@ -639,14 +644,14 @@ VOID MSysTask_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON) if(ctxP->pProcess || !(pd = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMDLL_PLUGIN_FORENSIC_JSONDATA)))) { return; } pd->dwVersion = VMMDLL_PLUGIN_FORENSIC_JSONDATA_VERSION; pd->szjType = "shtask"; - if((pObTaskMap = VmmSysTask_GetTaskMap(ctxP))) { + if((pObTaskMap = VmmSysTask_GetTaskMap(H, ctxP))) { for(i = 0; i < pObTaskMap->cMap; i++) { pe = pObTaskMap->pMap + i; pd->i = i; snprintf(uzj, _countof(uzj), "user:[%s] cmd:[%s] param:[%s]", pe->uszActionUser, pe->uszActionCommand, pe->uszActionParameters); pd->usz[0] = pe->uszPath; pd->usz[1] = uzj; - pfnLogJSON(pd); + pfnLogJSON(H, pd); } } Ob_DECREF(pObTaskMap); @@ -656,24 +661,60 @@ VOID MSysTask_FcLogJSON(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON) /* * Forensic Timeline: Free ObTaskMap from FcInitialize(). */ -VOID MSysTask_FcFinalize(_In_opt_ PVOID ctxfc) +VOID MSysTask_FcFinalize(_In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc) { Ob_DECREF(ctxfc); } -VOID MSysTask_Notify(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent) +VOID MSysTask_FcLogCSV(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VMMDLL_CSV_HANDLE hCSV) +{ + DWORD i; + QWORD ftRecent; + CHAR vszTimeRecent[24], vszTimeRegWR[24], vszTimeCreate[24], vszTimeLastRun[24], vszTimeCompleted[24]; + PVMMOB_MAP_TASK pObTaskMap = NULL; + PVMM_MAP_TASKENTRY pe; + if((ctxP->dwPID == 4) && (pObTaskMap = VmmSysTask_GetTaskMap(H, ctxP))) { + for(i = 0; i < pObTaskMap->cMap; i++) { + pe = pObTaskMap->pMap + i; + ftRecent = max(max(pe->ftCreate, pe->ftLastCompleted), max(pe->ftLastRun, pe->ftRegLastWrite)); + if(!ftRecent) { continue; } + Util_FileTime2CSV(ftRecent, vszTimeRecent); + Util_FileTime2CSV(pe->ftRegLastWrite, vszTimeRegWR); + Util_FileTime2CSV(pe->ftCreate, vszTimeCreate); + Util_FileTime2CSV(pe->ftLastRun, vszTimeLastRun); + Util_FileTime2CSV(pe->ftLastCompleted, vszTimeCompleted); + //"GUID,TaskName,TaskPath,User,TimeMostRecent,CommandLine,Parameters,TimeReg,TimeCreate,TimeLastRun,TimeCompleted" + FcCsv_Reset(hCSV); + FcFileAppend(H, "tasks.csv", "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n", + FcCsv_String(hCSV, pe->uszGUID), + FcCsv_String(hCSV, pe->uszName), + FcCsv_String(hCSV, pe->uszPath), + FcCsv_String(hCSV, pe->uszActionUser), + vszTimeRecent, + FcCsv_String(hCSV, pe->uszActionCommand), + FcCsv_String(hCSV, pe->uszActionParameters), + vszTimeRegWR, + vszTimeCreate, + vszTimeLastRun, + vszTimeCompleted + ); + } + } +} + +VOID MSysTask_Notify(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent) { if(fEvent == VMMDLL_PLUGIN_NOTIFY_REFRESH_SLOW) { ObContainer_SetOb((POB_CONTAINER)ctxP->ctxM, NULL); } } -VOID MSysTask_Close(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP) +VOID MSysTask_Close(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP) { Ob_DECREF(ctxP->ctxM); } -VOID M_SysTask_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_SysTask_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if((pRI->tpSystem != VMM_SYSTEM_WINDOWS_X64) && (pRI->tpSystem != VMM_SYSTEM_WINDOWS_X86)) { return; } @@ -687,11 +728,12 @@ VOID M_SysTask_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) pRI->reg_fn.pfnNotify = MSysTask_Notify; pRI->reg_fn.pfnClose = MSysTask_Close; pRI->reg_fnfc.pfnLogJSON = MSysTask_FcLogJSON; - // timelining support: + // timelining & csv support: pRI->reg_fnfc.pfnInitialize = MSysTask_FcInitialize; + pRI->reg_fnfc.pfnLogCSV = MSysTask_FcLogCSV; pRI->reg_fnfc.pfnTimeline = MSysTask_FcTimeline; pRI->reg_fnfc.pfnFinalize = MSysTask_FcFinalize; memcpy(pRI->reg_info.sTimelineNameShort, "ShTask", 6); - strncpy_s(pRI->reg_info.uszTimelineFile, 32, "timeline_task.txt", _TRUNCATE); - pRI->pfnPluginManager_Register(pRI); + strncpy_s(pRI->reg_info.uszTimelineFile, 32, "timeline_task", _TRUNCATE); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_sys_user.c b/vmm/m_sys_user.c new file mode 100644 index 0000000..ebb88fa --- /dev/null +++ b/vmm/m_sys_user.c @@ -0,0 +1,58 @@ +// m_sys_user.c : implementation related to the sys/users built-in module. +// +// The '/sys/users' module is responsible for displaying the users of the system. +// +// (c) Ulf Frisk, 2022 +// Author: Ulf Frisk, pcileech@frizk.net +// +#include "pluginmanager.h" +#include "util.h" + +#define MSYSUSER_LINELENGTH 120ULL +#define MSYSUSER_LINEHEADER " # Username SID" + +VOID MSysUser_ReadLineCB(_In_ VMM_HANDLE H, _Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_USERENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR usz) +{ + Util_usnprintf_ln(usz, cbLineLength, + "%04x %-32s %s", + ie, + pe->uszText, + pe->szSID ? pe->szSID : "***" + ); +} + +NTSTATUS MSysUser_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +{ + NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; + PVMMOB_MAP_USER pObUserMap = NULL; + if(VmmMap_GetUser(H, &pObUserMap)) { + nt = Util_VfsLineFixed_Read( + H, (UTIL_VFSLINEFIXED_PFN_CB)MSysUser_ReadLineCB, NULL, MSYSUSER_LINELENGTH, MSYSUSER_LINEHEADER, + pObUserMap->pMap, pObUserMap->cMap, sizeof(VMM_MAP_USERENTRY), + pb, cb, pcbRead, cbOffset + ); + } + Ob_DECREF(pObUserMap); + return nt; +} + +BOOL MSysUser_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) +{ + PVMMOB_MAP_USER pObUserMap = NULL; + if(VmmMap_GetUser(H, &pObUserMap)) { + VMMDLL_VfsList_AddFile(pFileList, "users.txt", UTIL_VFSLINEFIXED_LINECOUNT(H, pObUserMap->cMap) * MSYSUSER_LINELENGTH, NULL); + } + Ob_DECREF(pObUserMap); + return TRUE; +} + +VOID M_SysUser_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +{ + if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } + if((pRI->tpSystem != VMM_SYSTEM_WINDOWS_X64) && (pRI->tpSystem != VMM_SYSTEM_WINDOWS_X86)) { return; } + strcpy_s(pRI->reg_info.uszPathName, 128, "\\sys\\users"); // module name + pRI->reg_info.fRootModule = TRUE; // module shows in root directory + pRI->reg_fn.pfnList = MSysUser_List; // List function supported + pRI->reg_fn.pfnRead = MSysUser_Read; // Read function supported + pRI->pfnPluginManager_Register(H, pRI); +} diff --git a/vmm/m_vfsfc.c b/vmm/m_vfsfc.c index dd5249e..6f95ef6 100644 --- a/vmm/m_vfsfc.c +++ b/vmm/m_vfsfc.c @@ -45,20 +45,21 @@ LPCSTR szMFC_README = "For additional information about MemProcFS forensics check out the guide at:\n" \ "https://github.com/ufrisk/MemProcFS/wiki \n"; -NTSTATUS M_VfsFc_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS M_VfsFc_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { + PFC_CONTEXT ctxFc = H->fc; BYTE btp; - if(!_stricmp(ctx->uszPath, "readme.txt")) { + if(!_stricmp(ctxP->uszPath, "readme.txt")) { return Util_VfsReadFile_FromStrA(szMFC_README, pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "progress_percent.txt")) { + if(!_stricmp(ctxP->uszPath, "progress_percent.txt")) { return Util_VfsReadFile_FromNumber(ctxFc ? ctxFc->cProgressPercent : 0, pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "forensic_enable.txt")) { + if(!_stricmp(ctxP->uszPath, "forensic_enable.txt")) { btp = '0' + (ctxFc ? (BYTE)ctxFc->db.tp : 0); return Util_VfsReadFile_FromPBYTE(&btp, 1, pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "database.txt")) { + if(!_stricmp(ctxP->uszPath, "database.txt")) { if(ctxFc) { return Util_VfsReadFile_FromPBYTE(ctxFc->db.uszDatabasePath, strlen(ctxFc->db.uszDatabasePath), pb, cb, pcbRead, cbOffset); } else { @@ -68,20 +69,21 @@ NTSTATUS M_VfsFc_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbR return VMMDLL_STATUS_FILE_INVALID; } -NTSTATUS M_VfsFc_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) +NTSTATUS M_VfsFc_Write(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) { DWORD dwDatabaseType = 0; NTSTATUS nt; - if(!_stricmp(ctx->uszPath, "forensic_enable.txt")) { + if(!_stricmp(ctxP->uszPath, "forensic_enable.txt")) { nt = Util_VfsWriteFile_09(&dwDatabaseType, pb, cb, pcbWrite, cbOffset); - FcInitialize(dwDatabaseType, FALSE); + FcInitialize(H, dwDatabaseType, FALSE); return nt; } return VMMDLL_STATUS_FILE_INVALID; } -BOOL M_VfsFc_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) +BOOL M_VfsFc_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { + PFC_CONTEXT ctxFc = H->fc; QWORD qwProgress; qwProgress = ctxFc ? ctxFc->cProgressPercent : 0; qwProgress = (qwProgress == 100) ? 3 : ((qwProgress >= 10) ? 2 : 1); @@ -92,7 +94,7 @@ BOOL M_VfsFc_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) return TRUE; } -VOID M_VfsFc_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_VfsFc_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if((pRI->tpSystem != VMM_SYSTEM_WINDOWS_X64) && (pRI->tpSystem != VMM_SYSTEM_WINDOWS_X86)) { return; } @@ -101,5 +103,5 @@ VOID M_VfsFc_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) pRI->reg_fn.pfnList = M_VfsFc_List; // List function supported pRI->reg_fn.pfnRead = M_VfsFc_Read; // Read function supported pRI->reg_fn.pfnWrite = M_VfsFc_Write; // Read function supported - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_vfsproc.c b/vmm/m_vfsproc.c index 1c08ff6..fcccaff 100644 --- a/vmm/m_vfsproc.c +++ b/vmm/m_vfsproc.c @@ -10,37 +10,40 @@ /* * Read process root file. -* -- ctx +* -- H +* -- ctxP * -- pb * -- cb * -- pcbRead * -- cbOffset * -- return */ -NTSTATUS MVfsProc_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MVfsProc_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { + VMM_MEMORYMODEL_TP tpMemoryModel = H->vmm.tpMemoryModel; + VMM_SYSTEM_TP tpSystem = H->vmm.tpSystem; QWORD cbMemSize; BYTE pbBuffer[0x800] = { 0 }; - LPSTR uszPath = ctx->uszPath; - PVMM_PROCESS pProcess = ctx->pProcess; - PVMMWIN_USER_PROCESS_PARAMETERS pUserProcessParams = VmmWin_UserProcessParameters_Get(pProcess); // don't free + LPSTR uszPath = ctxP->uszPath; + PVMM_PROCESS pProcess = ctxP->pProcess; + PVMMWIN_USER_PROCESS_PARAMETERS pUserProcessParams = VmmWin_UserProcessParameters_Get(H, pProcess); // don't free // read memory from "memory.vmem" file if(!_stricmp(uszPath, "memory.vmem")) { - cbMemSize = (ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X64) ? 1ULL << 48 : 1ULL << 32; - return VmmReadAsFile(pProcess, 0, cbMemSize, pb, cb, pcbRead, cbOffset); + cbMemSize = (tpMemoryModel == VMM_MEMORYMODEL_X64) ? 1ULL << 48 : 1ULL << 32; + return VmmReadAsFile(H, pProcess, 0, cbMemSize, pb, cb, pcbRead, cbOffset); } // read genereal numeric values from files, pml4, pid, name, virt if(!_stricmp(uszPath, "dtb.txt")) { - if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X64) { + if(tpMemoryModel == VMM_MEMORYMODEL_X64) { return Util_VfsReadFile_FromQWORD(pProcess->paDTB, pb, cb, pcbRead, cbOffset, FALSE); - } else if((ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X86) || (ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X86PAE)) { + } else if((tpMemoryModel == VMM_MEMORYMODEL_X86) || (tpMemoryModel == VMM_MEMORYMODEL_X86PAE)) { return Util_VfsReadFile_FromDWORD((DWORD)pProcess->paDTB, pb, cb, pcbRead, cbOffset, FALSE); } } if(!_stricmp(uszPath, "dtb-user.txt")) { - if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X64) { + if(tpMemoryModel == VMM_MEMORYMODEL_X64) { return Util_VfsReadFile_FromQWORD(pProcess->paDTB_UserOpt, pb, cb, pcbRead, cbOffset, FALSE); - } else if((ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X86) || (ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X86PAE)) { + } else if((tpMemoryModel == VMM_MEMORYMODEL_X86) || (tpMemoryModel == VMM_MEMORYMODEL_X86PAE)) { return Util_VfsReadFile_FromDWORD((DWORD)pProcess->paDTB_UserOpt, pb, cb, pcbRead, cbOffset, FALSE); } } @@ -57,13 +60,13 @@ NTSTATUS MVfsProc_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcb return Util_VfsReadFile_usnprintf_ln(pb, cb, pcbRead, cbOffset, 16, "%s", pProcess->szName); } if(!_stricmp(uszPath, "time-create.txt")) { - return Util_VfsReadFile_FromFILETIME(VmmProcess_GetCreateTimeOpt(pProcess), pb, cb, pcbRead, cbOffset); + return Util_VfsReadFile_FromFILETIME(VmmProcess_GetCreateTimeOpt(H, pProcess), pb, cb, pcbRead, cbOffset); } if(!_stricmp(uszPath, "time-exit.txt")) { - return Util_VfsReadFile_FromFILETIME(VmmProcess_GetExitTimeOpt(pProcess), pb, cb, pcbRead, cbOffset); + return Util_VfsReadFile_FromFILETIME(VmmProcess_GetExitTimeOpt(H, pProcess), pb, cb, pcbRead, cbOffset); } // windows specific reads below: - if((ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X64) || (ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X86)) { + if((tpSystem == VMM_SYSTEM_WINDOWS_X64) || (tpSystem == VMM_SYSTEM_WINDOWS_X86)) { if(!_stricmp(uszPath, "name-long.txt")) { return Util_VfsReadFile_FromPBYTE(pProcess->pObPersistent->uszNameLong, pProcess->pObPersistent->cuszNameLong, pb, cb, pcbRead, cbOffset); } @@ -80,7 +83,7 @@ NTSTATUS MVfsProc_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcb return Util_VfsReadFile_FromPBYTE(pUserProcessParams->uszWindowTitle, max(1, pUserProcessParams->cbuWindowTitle) - 1, pb, cb, pcbRead, cbOffset); } } - if(ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X64) { + if(tpSystem == VMM_SYSTEM_WINDOWS_X64) { if(!_stricmp(uszPath, "win-eprocess.txt")) { return Util_VfsReadFile_FromQWORD(pProcess->win.EPROCESS.va, pb, cb, pcbRead, cbOffset, FALSE); } @@ -91,7 +94,7 @@ NTSTATUS MVfsProc_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcb return Util_VfsReadFile_FromDWORD(pProcess->win.vaPEB32, pb, cb, pcbRead, cbOffset, FALSE); } } - if(ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X86) { + if(H->vmm.tpSystem == VMM_SYSTEM_WINDOWS_X86) { if(!_stricmp(uszPath, "win-eprocess.txt")) { return Util_VfsReadFile_FromDWORD((DWORD)pProcess->win.EPROCESS.va, pb, cb, pcbRead, cbOffset, FALSE); } @@ -104,19 +107,20 @@ NTSTATUS MVfsProc_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcb /* * Write process root file. -* -- ctx +* -- H +* -- ctxP * -- pb * -- cb * -- pcbWrite * -- cbOffset * -- return */ -NTSTATUS MVfsProc_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) +NTSTATUS MVfsProc_Write(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) { BOOL fFound; QWORD cbMemSize; - LPSTR uszPath = ctx->uszPath; - PVMM_PROCESS pProcess = ctx->pProcess; + LPSTR uszPath = ctxP->uszPath; + PVMM_PROCESS pProcess = ctxP->pProcess; // read only files - report zero bytes written fFound = !_stricmp(uszPath, "dtb.txt") || @@ -137,17 +141,17 @@ NTSTATUS MVfsProc_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_reads_(cb) PBYTE pb } // write memory to "memory.vmem" file if(!_stricmp(uszPath, "memory.vmem")) { - cbMemSize = (ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X64) ? 1ULL << 48 : 1ULL << 32; - return VmmWriteAsFile(pProcess, 0, cbMemSize, pb, cb, pcbWrite, cbOffset); + cbMemSize = (H->vmm.tpMemoryModel == VMM_MEMORYMODEL_X64) ? 1ULL << 48 : 1ULL << 32; + return VmmWriteAsFile(H, pProcess, 0, cbMemSize, pb, cb, pcbWrite, cbOffset); } return VMM_STATUS_FILE_INVALID; } -VOID MVfsProc_List_OsSpecific(_In_ PVMM_PROCESS pProcess, _In_ PVMMDLL_VFS_FILELIST_EXINFO pExInfo, _Inout_ PHANDLE pFileList) +VOID MVfsProc_List_OsSpecific(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVMMDLL_VFS_FILELIST_EXINFO pExInfo, _Inout_ PHANDLE pFileList) { - PVMMWIN_USER_PROCESS_PARAMETERS pUserProcessParams = VmmWin_UserProcessParameters_Get(pProcess); // don't free + PVMMWIN_USER_PROCESS_PARAMETERS pUserProcessParams = VmmWin_UserProcessParameters_Get(H, pProcess); // don't free // WINDOWS - 32 & 64-bit - if((ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X64) || (ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X86)) { + if((H->vmm.tpSystem == VMM_SYSTEM_WINDOWS_X64) || (H->vmm.tpSystem == VMM_SYSTEM_WINDOWS_X86)) { VMMDLL_VfsList_AddFile(pFileList, "name-long.txt", pProcess->pObPersistent->cuszNameLong, pExInfo); VMMDLL_VfsList_AddFile(pFileList, "win-path.txt", pProcess->pObPersistent->cuszPathKernel, pExInfo); if(pUserProcessParams->uszCommandLine) { @@ -165,7 +169,7 @@ VOID MVfsProc_List_OsSpecific(_In_ PVMM_PROCESS pProcess, _In_ PVMMDLL_VFS_FILEL } } // WINDOWS - 64-bit specific - if(ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X64) { + if(H->vmm.tpSystem == VMM_SYSTEM_WINDOWS_X64) { VMMDLL_VfsList_AddFile(pFileList, "win-eprocess.txt", 16, pExInfo); // 64-bit PEB and modules if(pProcess->win.vaPEB) { @@ -177,7 +181,7 @@ VOID MVfsProc_List_OsSpecific(_In_ PVMM_PROCESS pProcess, _In_ PVMMDLL_VFS_FILEL } } // WINDOWS 32-bit specific - if(ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X86) { + if(H->vmm.tpSystem == VMM_SYSTEM_WINDOWS_X86) { VMMDLL_VfsList_AddFile(pFileList, "win-eprocess.txt", 8, pExInfo); // PEB if(pProcess->win.vaPEB) { @@ -188,45 +192,47 @@ VOID MVfsProc_List_OsSpecific(_In_ PVMM_PROCESS pProcess, _In_ PVMMDLL_VFS_FILEL /* * List process root file. -* -- ctx +* -- H +* -- ctxP * -- pFileList * -- return */ -BOOL MVfsProc_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) +BOOL MVfsProc_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { - PVMM_PROCESS pProcess = ctx->pProcess; + PVMM_PROCESS pProcess = ctxP->pProcess; VMMDLL_VFS_FILELIST_EXINFO ExInfo = { 0 }; - Util_VfsTimeStampFile(pProcess, &ExInfo); + Util_VfsTimeStampFile(H, pProcess, &ExInfo); // populate process directory - list standard files and subdirectories - if(!ctx->uszPath[0]) { + if(!ctxP->uszPath[0]) { VMMDLL_VfsList_AddFile(pFileList, "name.txt", 16, &ExInfo); VMMDLL_VfsList_AddFile(pFileList, "pid.txt", 11, &ExInfo); VMMDLL_VfsList_AddFile(pFileList, "ppid.txt", 11, &ExInfo); VMMDLL_VfsList_AddFile(pFileList, "state.txt", 11, &ExInfo); - if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X64) { + if(H->vmm.tpMemoryModel == VMM_MEMORYMODEL_X64) { VMMDLL_VfsList_AddFile(pFileList, "memory.vmem", 0x0001000000000000, &ExInfo); VMMDLL_VfsList_AddFile(pFileList, "dtb.txt", 16, &ExInfo); if(pProcess->paDTB_UserOpt) { VMMDLL_VfsList_AddFile(pFileList, "dtb-user.txt", 16, &ExInfo); } - } else if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X86 || ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X86PAE) { + } else if(H->vmm.tpMemoryModel == VMM_MEMORYMODEL_X86 || H->vmm.tpMemoryModel == VMM_MEMORYMODEL_X86PAE) { VMMDLL_VfsList_AddFile(pFileList, "memory.vmem", 0x100000000, &ExInfo); VMMDLL_VfsList_AddFile(pFileList, "dtb.txt", 8, &ExInfo); if(pProcess->paDTB_UserOpt) { VMMDLL_VfsList_AddFile(pFileList, "dtb-user.txt", 8, &ExInfo); } } - MVfsProc_List_OsSpecific(pProcess, &ExInfo, pFileList); + MVfsProc_List_OsSpecific(H, pProcess, &ExInfo, pFileList); } return TRUE; } /* * Initialize the process root plugin. -* -- pPluginRegInfo +* -- H +* -- pRI */ -VOID M_VfsProc_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_VfsProc_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { strcpy_s(pRI->reg_info.uszPathName, 128, "\\"); // module name pRI->reg_info.fProcessModule = TRUE; // process module pRI->reg_fn.pfnList = MVfsProc_List; // List function supported pRI->reg_fn.pfnRead = MVfsProc_Read; // Read function supported pRI->reg_fn.pfnWrite = MVfsProc_Write; // Write function supported - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_vfsroot.c b/vmm/m_vfsroot.c index 6b1f2ab..b577dc1 100644 --- a/vmm/m_vfsroot.c +++ b/vmm/m_vfsroot.c @@ -55,20 +55,20 @@ typedef struct tdOB_VMMVFS_DUMP_CONTEXT { * -- pSystemProcess * -- ctx */ -VOID MVfsRoot_EnsureProcessorContext0(_In_ PVMM_PROCESS pSystemProcess, _In_ POB_VMMVFS_DUMP_CONTEXT ctx) +VOID MVfsRoot_EnsureProcessorContext0(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ POB_VMMVFS_DUMP_CONTEXT ctx) { BOOL f; QWORD va, vaContextKPRCB; - if(ctxVmm->f32) { return; } + if(H->vmm.f32) { return; } f = (va = *(PQWORD)(ctx->KDBG.pb + KDBG64_KiProcessorBlock)) && VMM_KADDR64_16(va) && - VmmRead(pSystemProcess, va, (PBYTE)&va, sizeof(QWORD)) && + VmmRead(H, pSystemProcess, va, (PBYTE)&va, sizeof(QWORD)) && VMM_KADDR64_16(va) && (va = va + *(PWORD)(ctx->KDBG.pb + KDBG64_ContextKPRCB)) && - VmmRead(pSystemProcess, va, (PBYTE)&vaContextKPRCB, sizeof(QWORD)) && + VmmRead(H, pSystemProcess, va, (PBYTE)&vaContextKPRCB, sizeof(QWORD)) && VMM_KADDR64_16(vaContextKPRCB); if(f) { - if(VmmVirt2Phys(pSystemProcess, vaContextKPRCB + 0x038, &ctx->KiInitialPCR_Context.pa)) { + if(VmmVirt2Phys(H, pSystemProcess, vaContextKPRCB + 0x038, &ctx->KiInitialPCR_Context.pa)) { ctx->KiInitialPCR_Context.cb = 0x10; *(PWORD)(ctx->KiInitialPCR_Context.pb + 0x00) = 0x10; // SegCs *(PWORD)(ctx->KiInitialPCR_Context.pb + 0x02) = 0x2b; // SegDs @@ -84,22 +84,23 @@ VOID MVfsRoot_EnsureProcessorContext0(_In_ PVMM_PROCESS pSystemProcess, _In_ POB } } -VOID MVfsRoot_KdbgDecryptRun(_Inout_ PQWORD pqw) +VOID MVfsRoot_KdbgDecryptRun(_In_ VMM_HANDLE H, _Inout_ PQWORD pqw) { - QWORD v = *pqw ^ ctxVmm->kernel.opt.KDBG.qwKiWaitNever; - v = _rotl64(v, (UCHAR)ctxVmm->kernel.opt.KDBG.qwKiWaitNever); - v = v ^ ctxVmm->kernel.opt.KDBG.vaKdpDataBlockEncoded; + QWORD v = *pqw ^ H->vmm.kernel.opt.KDBG.qwKiWaitNever; + v = _rotl64(v, (UCHAR)H->vmm.kernel.opt.KDBG.qwKiWaitNever); + v = v ^ H->vmm.kernel.opt.KDBG.vaKdpDataBlockEncoded; v = _byteswap_uint64(v); - *pqw = v ^ ctxVmm->kernel.opt.KDBG.qwKiWaitAlways; + *pqw = v ^ H->vmm.kernel.opt.KDBG.qwKiWaitAlways; } /* * Load KDBG (KDebuggerDataBlock) and optionally (if required) decrypt it. * Decryption most often needs to be done on x64 Win8+. +* -- H * -- pSystemProcess * -- ctx */ -VOID MVfsRoot_KdbgLoadAndDecrypt(_In_ PVMM_PROCESS pSystemProcess, _In_ POB_VMMVFS_DUMP_CONTEXT ctx) +VOID MVfsRoot_KdbgLoadAndDecrypt(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ POB_VMMVFS_DUMP_CONTEXT ctx) { DWORD i; union { @@ -109,25 +110,25 @@ VOID MVfsRoot_KdbgLoadAndDecrypt(_In_ PVMM_PROCESS pSystemProcess, _In_ POB_VMMV DWORD cb; }; } hdr; - if(ctxVmm->f32 || !ctxVmm->kernel.opt.KDBG.va) { return; } - if(!VmmVirt2Phys(pSystemProcess, ctxVmm->kernel.opt.KDBG.va, &ctx->KDBG.pa)) { return; } - if(!VmmRead(pSystemProcess, ctxVmm->kernel.opt.KDBG.va + 0x10, (PBYTE)&hdr.qw, sizeof(QWORD))) { return; } + if(H->vmm.f32 || !H->vmm.kernel.opt.KDBG.va) { return; } + if(!VmmVirt2Phys(H, pSystemProcess, H->vmm.kernel.opt.KDBG.va, &ctx->KDBG.pa)) { return; } + if(!VmmRead(H, pSystemProcess, H->vmm.kernel.opt.KDBG.va + 0x10, (PBYTE)&hdr.qw, sizeof(QWORD))) { return; } if(hdr.magic == 0x4742444b) { // load decrypted and return - if((hdr.cb > sizeof(ctx->KDBG.pb)) || !VmmRead(pSystemProcess, ctxVmm->kernel.opt.KDBG.va, ctx->KDBG.pb, hdr.cb)) { return; } - if(!VmmVirt2Phys(pSystemProcess, ctxVmm->kernel.opt.KDBG.va, &ctx->KDBG.pa)) { return; } + if((hdr.cb > sizeof(ctx->KDBG.pb)) || !VmmRead(H, pSystemProcess, H->vmm.kernel.opt.KDBG.va, ctx->KDBG.pb, hdr.cb)) { return; } + if(!VmmVirt2Phys(H, pSystemProcess, H->vmm.kernel.opt.KDBG.va, &ctx->KDBG.pa)) { return; } ctx->KDBG.cb = hdr.cb; ctx->KDBG.fEncrypted = FALSE; return; } // encrypted - try decrypt - if(!ctxVmm->kernel.opt.KDBG.vaKdpDataBlockEncoded || !ctxVmm->kernel.opt.KDBG.qwKiWaitAlways || !ctxVmm->kernel.opt.KDBG.qwKiWaitNever) { return; } - if(!VmmVirt2Phys(pSystemProcess, ctxVmm->kernel.opt.KDBG.vaKdpDataBlockEncoded, &ctx->KDBG.paKdpDataBlockEncoded)) { return; } - MVfsRoot_KdbgDecryptRun(&hdr.qw); + if(!H->vmm.kernel.opt.KDBG.vaKdpDataBlockEncoded || !H->vmm.kernel.opt.KDBG.qwKiWaitAlways || !H->vmm.kernel.opt.KDBG.qwKiWaitNever) { return; } + if(!VmmVirt2Phys(H, pSystemProcess, H->vmm.kernel.opt.KDBG.vaKdpDataBlockEncoded, &ctx->KDBG.paKdpDataBlockEncoded)) { return; } + MVfsRoot_KdbgDecryptRun(H, &hdr.qw); if((hdr.magic != 0x4742444b) || (hdr.cb > sizeof(ctx->KDBG.pb)) || (hdr.cb & 0x07)) { return; } - if(!VmmRead(pSystemProcess, ctxVmm->kernel.opt.KDBG.va, ctx->KDBG.pb, hdr.cb)) { return; } + if(!VmmRead(H, pSystemProcess, H->vmm.kernel.opt.KDBG.va, ctx->KDBG.pb, hdr.cb)) { return; } for(i = 0; i < hdr.cb; i += 8) { - MVfsRoot_KdbgDecryptRun((PQWORD)(ctx->KDBG.pb + i)); + MVfsRoot_KdbgDecryptRun(H, (PQWORD)(ctx->KDBG.pb + i)); } ctx->KDBG.cb = hdr.cb; // set physical memory overlay struct for decrypted KDBG @@ -140,48 +141,48 @@ VOID MVfsRoot_KdbgLoadAndDecrypt(_In_ PVMM_PROCESS pSystemProcess, _In_ POB_VMMV ctx->KDBG.fEncrypted = TRUE; } -VOID MVfsRoot_InitializeDumpContext_SetMemory(_In_ POB_VMMVFS_DUMP_CONTEXT ctx) +VOID MVfsRoot_InitializeDumpContext_SetMemory(_In_ VMM_HANDLE H, _In_ POB_VMMVFS_DUMP_CONTEXT ctx) { _PPHYSICAL_MEMORY_DESCRIPTOR32 pMd32 = (_PPHYSICAL_MEMORY_DESCRIPTOR32)(ctx->Hdr.pb + 0x064); _PPHYSICAL_MEMORY_DESCRIPTOR64 pMd64 = (_PPHYSICAL_MEMORY_DESCRIPTOR64)(ctx->Hdr.pb + 0x088); - if(ctxVmm->f32) { + if(H->vmm.f32) { pMd32->NumberOfRuns = 1; - pMd32->NumberOfPages = (DWORD)(ctxMain->dev.paMax / 0x1000); + pMd32->NumberOfPages = (DWORD)(H->dev.paMax / 0x1000); pMd32->Run[0].BasePage = 0; - pMd32->Run[0].PageCount = (DWORD)(ctxMain->dev.paMax / 0x1000); + pMd32->Run[0].PageCount = (DWORD)(H->dev.paMax / 0x1000); } else { pMd64->Reserved1 = 0; pMd64->Reserved2 = 0; pMd64->NumberOfRuns = 1; - pMd64->NumberOfPages = (DWORD)(ctxMain->dev.paMax / 0x1000); + pMd64->NumberOfPages = (DWORD)(H->dev.paMax / 0x1000); pMd64->Run[0].BasePage = 0; - pMd64->Run[0].PageCount = ctxMain->dev.paMax / 0x1000; + pMd64->Run[0].PageCount = H->dev.paMax / 0x1000; } } -VOID MVfsRoot_InitializeDumpContext64(_In_ PVMM_PROCESS pSystemProcess, _In_ POB_VMMVFS_DUMP_CONTEXT ctx) +VOID MVfsRoot_InitializeDumpContext64(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ POB_VMMVFS_DUMP_CONTEXT ctx) { PBYTE pb = ctx->Hdr.pb; QWORD ftMin, ftMax; - ftMin = ctxVmm->kernel.opt.ftBootTime; - ftMax = SysQuery_TimeCurrent(); + ftMin = H->vmm.kernel.opt.ftBootTime; + ftMax = SysQuery_TimeCurrent(H); *(PDWORD)(pb + 0x000) = 0x45474150; // Signature #1 *(PDWORD)(pb + 0x004) = 0x34365544; // Signature #2 *(PDWORD)(pb + 0x008) = 0x0000000F; // DumpVersion - *(PDWORD)(pb + 0x00c) = ctxVmm->kernel.dwVersionBuild; // BuildNo - *(PQWORD)(pb + 0x010) = ctxVmm->kernel.paDTB; - *(PQWORD)(pb + 0x018) = ctxVmm->kernel.opt.vaPfnDatabase; - *(PQWORD)(pb + 0x020) = ctxVmm->kernel.opt.vaPsLoadedModuleListExp; + *(PDWORD)(pb + 0x00c) = H->vmm.kernel.dwVersionBuild; // BuildNo + *(PQWORD)(pb + 0x010) = H->vmm.kernel.paDTB; + *(PQWORD)(pb + 0x018) = H->vmm.kernel.opt.vaPfnDatabase; + *(PQWORD)(pb + 0x020) = H->vmm.kernel.opt.vaPsLoadedModuleListExp; *(PQWORD)(pb + 0x028) = pSystemProcess->win.EPROCESS.va; *(PDWORD)(pb + 0x030) = 0x8664; // MachineImageType = AMD64 - *(PDWORD)(pb + 0x034) = max(1, ctxVmm->kernel.opt.cCPUs); + *(PDWORD)(pb + 0x034) = max(1, H->vmm.kernel.opt.cCPUs); *(PDWORD)(pb + 0x038) = 0xDEADDEAD; // BugCheckCode *(PQWORD)(pb + 0x040) = 1; // BugCheck1 *(PQWORD)(pb + 0x048) = 2; // BugCheck2 *(PQWORD)(pb + 0x050) = 3; // BugCheck3 *(PQWORD)(pb + 0x058) = 4; // BugCheck4 - *(PQWORD)(pb + 0x080) = ctxVmm->kernel.opt.KDBG.va; // KDBG - MVfsRoot_InitializeDumpContext_SetMemory(ctx); + *(PQWORD)(pb + 0x080) = H->vmm.kernel.opt.KDBG.va; // KDBG + MVfsRoot_InitializeDumpContext_SetMemory(H, ctx); ZeroMemory(pb + 0x348, 3000); // ContextRecord *(PWORD)(pb + 0x348 + 0x038) = 0x10; // SegCs *(PWORD)(pb + 0x348 + 0x03a) = 0x2b; // SegDs @@ -189,7 +190,7 @@ VOID MVfsRoot_InitializeDumpContext64(_In_ PVMM_PROCESS pSystemProcess, _In_ POB *(PWORD)(pb + 0x348 + 0x03e) = 0x53; // SegFs *(PWORD)(pb + 0x348 + 0x040) = 0x2b; // SegGs *(PWORD)(pb + 0x348 + 0x042) = 0x00; // SegSs - *(PQWORD)(pb + 0x348 + 0x098) = ctxVmm->kernel.vaBase; // Rsp + *(PQWORD)(pb + 0x348 + 0x098) = H->vmm.kernel.vaBase; // Rsp ZeroMemory(pb + 0xf00, 152); // ExceptionRecord ZeroMemory(pb + 0xfb0, 128); // Comment snprintf( @@ -201,7 +202,7 @@ VOID MVfsRoot_InitializeDumpContext64(_In_ PVMM_PROCESS pSystemProcess, _In_ POB VERSION_REVISION, VERSION_BUILD); *(PDWORD)(pb + 0xf98) = 1; - *(PQWORD)(pb + 0xfa0) = 0x2000 + ctxMain->dev.paMax; + *(PQWORD)(pb + 0xfa0) = 0x2000 + H->dev.paMax; *(PQWORD)(pb + 0xfa8) = ftMax; *(PQWORD)(pb + 0x1030) = ftMax - ftMin; *(PDWORD)(pb + 0x1038) = 0; @@ -211,31 +212,31 @@ VOID MVfsRoot_InitializeDumpContext64(_In_ PVMM_PROCESS pSystemProcess, _In_ POB ctx->fInitialized = TRUE; } -VOID MVfsRoot_InitializeDumpContext32(PVMM_PROCESS pSystemProcess, POB_VMMVFS_DUMP_CONTEXT ctx) +VOID MVfsRoot_InitializeDumpContext32(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, POB_VMMVFS_DUMP_CONTEXT ctx) { PBYTE pb = ctx->Hdr.pb; //PDUMP_HEADER32 pd = &ctx->Hdr._32; QWORD ftMin, ftMax; - ftMin = ctxVmm->kernel.opt.ftBootTime; - ftMax = SysQuery_TimeCurrent(); + ftMin = H->vmm.kernel.opt.ftBootTime; + ftMax = SysQuery_TimeCurrent(H); *(PDWORD)(pb + 0x000) = 0x45474150; // Signature #1 *(PDWORD)(pb + 0x004) = 0x504d5544; // Signature #2 *(PDWORD)(pb + 0x008) = 0x0000000F; // DumpVersion - *(PDWORD)(pb + 0x00c) = ctxVmm->kernel.dwVersionBuild; // BuildNo - *(PDWORD)(pb + 0x010) = (DWORD)ctxVmm->kernel.paDTB; - *(PDWORD)(pb + 0x014) = (DWORD)ctxVmm->kernel.opt.vaPfnDatabase; - *(PDWORD)(pb + 0x018) = (DWORD)ctxVmm->kernel.opt.vaPsLoadedModuleListExp; + *(PDWORD)(pb + 0x00c) = H->vmm.kernel.dwVersionBuild; // BuildNo + *(PDWORD)(pb + 0x010) = (DWORD)H->vmm.kernel.paDTB; + *(PDWORD)(pb + 0x014) = (DWORD)H->vmm.kernel.opt.vaPfnDatabase; + *(PDWORD)(pb + 0x018) = (DWORD)H->vmm.kernel.opt.vaPsLoadedModuleListExp; *(PDWORD)(pb + 0x01c) = (DWORD)pSystemProcess->win.EPROCESS.va; *(PDWORD)(pb + 0x020) = 0x014c; // MachineImageType = I386 - *(PDWORD)(pb + 0x024) = max(1, ctxVmm->kernel.opt.cCPUs); + *(PDWORD)(pb + 0x024) = max(1, H->vmm.kernel.opt.cCPUs); *(PDWORD)(pb + 0x028) = 0xDEADDEAD; // BugCheckCode *(PDWORD)(pb + 0x02c) = 1; // BugCheck1 *(PDWORD)(pb + 0x030) = 2; // BugCheck2 *(PDWORD)(pb + 0x034) = 3; // BugCheck3 *(PDWORD)(pb + 0x038) = 4; // BugCheck4 - *(PBYTE)(pb + 0x05c) = (ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X86PAE) ? 1 : 0; // PAE or NOT. - *(PDWORD)(pb + 0x060) = (DWORD)ctxVmm->kernel.opt.KDBG.va; // KDBG - MVfsRoot_InitializeDumpContext_SetMemory(ctx); + *(PBYTE)(pb + 0x05c) = (H->vmm.tpMemoryModel == VMM_MEMORYMODEL_X86PAE) ? 1 : 0; // PAE or NOT. + *(PDWORD)(pb + 0x060) = (DWORD)H->vmm.kernel.opt.KDBG.va; // KDBG + MVfsRoot_InitializeDumpContext_SetMemory(H, ctx); ZeroMemory(pb + 0x320, 1200); // ContextRecord ZeroMemory(pb + 0x7d0, 80); // ExceptionRecord ZeroMemory(pb + 0x820, 128); // Comment @@ -248,7 +249,7 @@ VOID MVfsRoot_InitializeDumpContext32(PVMM_PROCESS pSystemProcess, POB_VMMVFS_DU VERSION_REVISION, VERSION_BUILD); *(PDWORD)(pb + 0xf88) = 1; - *(PQWORD)(pb + 0xfa0) = 0x2000 + ctxMain->dev.paMax; + *(PQWORD)(pb + 0xfa0) = 0x2000 + H->dev.paMax; *(PQWORD)(pb + 0xfc0) = ftMax; *(PQWORD)(pb + 0xfb8) = ftMax - ftMin; *(PDWORD)(pb + 0xf8c) = 0; @@ -258,7 +259,7 @@ VOID MVfsRoot_InitializeDumpContext32(PVMM_PROCESS pSystemProcess, POB_VMMVFS_DU ctx->fInitialized = TRUE; } -VOID MVfsRoot_InitializeDumpContext(POB_VMMVFS_DUMP_CONTEXT ctx) +VOID MVfsRoot_InitializeDumpContext(_In_ VMM_HANDLE H, POB_VMMVFS_DUMP_CONTEXT ctx) { PVMM_PROCESS pObSystemProcess = NULL; DWORD cbDumpHeader; @@ -267,12 +268,12 @@ VOID MVfsRoot_InitializeDumpContext(POB_VMMVFS_DUMP_CONTEXT ctx) // The crash dump header is simply copied verbatim - except mem regions. // Crash dump headers are always assumed to be correct and the dump files // are assumed to have a decrypted KDBG block. - ctx->cbHdr = ctxVmm->f32 ? 0x1000 : 0x2000; - if(LcCommand(ctxMain->hLC, LC_CMD_FILE_DUMPHEADER_GET, 0, NULL, &pbDumpHeader, &cbDumpHeader)) { + ctx->cbHdr = H->vmm.f32 ? 0x1000 : 0x2000; + if(LcCommand(H->hLC, LC_CMD_FILE_DUMPHEADER_GET, 0, NULL, &pbDumpHeader, &cbDumpHeader)) { if(cbDumpHeader == ctx->cbHdr) { memcpy(ctx->Hdr.pb, pbDumpHeader, ctx->cbHdr); LocalFree(pbDumpHeader); - MVfsRoot_InitializeDumpContext_SetMemory(ctx); + MVfsRoot_InitializeDumpContext_SetMemory(H, ctx); ctx->fInitialized = TRUE; return; } @@ -280,16 +281,16 @@ VOID MVfsRoot_InitializeDumpContext(POB_VMMVFS_DUMP_CONTEXT ctx) } // 2: Load optional required values in a best-effort way and decrypt KDBG // if necessary and possible. - if(!(pObSystemProcess = VmmProcessGet(4))) { return; } - VmmWinInit_TryInitializeKernelOptionalValues(); - MVfsRoot_KdbgLoadAndDecrypt(pObSystemProcess, ctx); - MVfsRoot_EnsureProcessorContext0(pObSystemProcess, ctx); + if(!(pObSystemProcess = VmmProcessGet(H, 4))) { return; } + VmmWinInit_TryInitializeKernelOptionalValues(H); + MVfsRoot_KdbgLoadAndDecrypt(H, pObSystemProcess, ctx); + MVfsRoot_EnsureProcessorContext0(H, pObSystemProcess, ctx); // 3: Initialize dump headers memset(ctx->Hdr.pb, 'X', ctx->cbHdr); - if(ctxVmm->f32) { - MVfsRoot_InitializeDumpContext32(pObSystemProcess, ctx); + if(H->vmm.f32) { + MVfsRoot_InitializeDumpContext32(H, pObSystemProcess, ctx); } else { - MVfsRoot_InitializeDumpContext64(pObSystemProcess, ctx); + MVfsRoot_InitializeDumpContext64(H, pObSystemProcess, ctx); } Ob_DECREF(pObSystemProcess); } @@ -302,28 +303,29 @@ VOID MVfsRoot_CallbackCleanup_ObVmmVfsDumpContext(POB_VMMVFS_DUMP_CONTEXT pOb) /* * Retrieve the module context object. * CALLER DECREF: return +* -- H * -- return */ -POB_VMMVFS_DUMP_CONTEXT MVfsRoot_GetDumpContext() +POB_VMMVFS_DUMP_CONTEXT MVfsRoot_GetDumpContext(_In_ VMM_HANDLE H) { POB_VMMVFS_DUMP_CONTEXT ctx; // 1: fetch context or create initial context if required - if(!(ctx = (POB_VMMVFS_DUMP_CONTEXT)Ob_INCREF(ctxVmm->pObVfsDumpContext))) { - EnterCriticalSection(&ctxVmm->LockMaster); - if(!(ctx = (POB_VMMVFS_DUMP_CONTEXT)Ob_INCREF(ctxVmm->pObVfsDumpContext))) { - ctx = (POB_VMMVFS_DUMP_CONTEXT)Ob_Alloc(OB_TAG_VMMVFS_DUMPCONTEXT, LMEM_ZEROINIT, sizeof(OB_VMMVFS_DUMP_CONTEXT), NULL, NULL); + if(!(ctx = (POB_VMMVFS_DUMP_CONTEXT)Ob_INCREF(H->vmm.pObVfsDumpContext))) { + EnterCriticalSection(&H->vmm.LockMaster); + if(!(ctx = (POB_VMMVFS_DUMP_CONTEXT)Ob_INCREF(H->vmm.pObVfsDumpContext))) { + ctx = (POB_VMMVFS_DUMP_CONTEXT)Ob_AllocEx(H, OB_TAG_VMMVFS_DUMPCONTEXT, LMEM_ZEROINIT, sizeof(OB_VMMVFS_DUMP_CONTEXT), NULL, NULL); if(ctx) { InitializeCriticalSection(&ctx->Lock); - ctxVmm->pObVfsDumpContext = Ob_INCREF(ctx); + H->vmm.pObVfsDumpContext = Ob_INCREF(ctx); } } - LeaveCriticalSection(&ctxVmm->LockMaster); + LeaveCriticalSection(&H->vmm.LockMaster); } // 2: initialize context (if required) if(ctx && !ctx->fInitialized) { EnterCriticalSection(&ctx->Lock); if(!ctx->fInitialized) { - MVfsRoot_InitializeDumpContext(ctx); + MVfsRoot_InitializeDumpContext(H, ctx); } LeaveCriticalSection(&ctx->Lock); } @@ -332,14 +334,15 @@ POB_VMMVFS_DUMP_CONTEXT MVfsRoot_GetDumpContext() /* * Read from memory dump files in the virtual file system root. -* -- ctx +* -- H +* -- ctxP * -- pb * -- cb * -- pcbRead * -- cbOffset * -- return */ -NTSTATUS MVfsRoot_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MVfsRoot_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt = VMM_STATUS_FILE_INVALID; POB_VMMVFS_DUMP_CONTEXT pObDumpCtx = NULL; @@ -347,12 +350,12 @@ NTSTATUS MVfsRoot_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcb DWORD io, cbHead = 0, cbReadMem = 0; DWORD cbOverlayOffset, cbOverlay; QWORD cbOverlayAdjust; - if(!_stricmp(ctx->uszPath, "memory.pmem")) { - VmmReadEx(NULL, cbOffset, pb, cb, pcbRead, VMM_FLAG_ZEROPAD_ON_FAIL); + if(!_stricmp(ctxP->uszPath, "memory.pmem")) { + VmmReadEx(H, NULL, cbOffset, pb, cb, pcbRead, VMM_FLAG_ZEROPAD_ON_FAIL); return VMM_STATUS_SUCCESS; } - if(!_stricmp(ctx->uszPath, "memory.dmp")) { - if(!(pObDumpCtx = MVfsRoot_GetDumpContext())) { goto finish; } + if(!_stricmp(ctxP->uszPath, "memory.dmp")) { + if(!(pObDumpCtx = MVfsRoot_GetDumpContext(H))) { goto finish; } // read dump header if(cbOffset < pObDumpCtx->cbHdr) { cbHead = min(cb, pObDumpCtx->cbHdr - (DWORD)cbOffset); @@ -368,7 +371,7 @@ NTSTATUS MVfsRoot_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcb } cbOffset -= pObDumpCtx->cbHdr; // read memory - VmmReadEx(NULL, cbOffset, pb, cb, &cbReadMem, VMM_FLAG_ZEROPAD_ON_FAIL); + VmmReadEx(H, NULL, cbOffset, pb, cb, &cbReadMem, VMM_FLAG_ZEROPAD_ON_FAIL); if(pcbRead) { *pcbRead = cbHead + cbReadMem; } // overlay decrypted KDBG, KdpDataBlockEncoded (if encrypted) and ProcessorContext0 for(io = 0; io < sizeof(pObDumpCtx->OVERLAY) / sizeof(VMMVFS_DUMP_CONTEXT_OVERLAY); io++) { @@ -399,25 +402,26 @@ finish: * write-capable backend device/driver. Also the crash dump header in microsoft * crash dumps aren't writable. This write function does not account for any * overlayed memory - such as decrypted KDBG. -* -- ctx +* -- H +* -- ctxP * -- pb * -- cb * -- pcbWrite * -- cbOffset * -- return */ -NTSTATUS MVfsRoot_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) +NTSTATUS MVfsRoot_Write(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) { BOOL fResult; DWORD cbHeaderSize; - if(!_stricmp(ctx->uszPath, "memory.pmem")) { + if(!_stricmp(ctxP->uszPath, "memory.pmem")) { *pcbWrite = cb; - fResult = VmmWrite(NULL, cbOffset, pb, cb); + fResult = VmmWrite(H, NULL, cbOffset, pb, cb); return fResult ? VMM_STATUS_SUCCESS : VMM_STATUS_FILE_SYSTEM_LIMITATION; } - if(!_stricmp(ctx->uszPath, "memory.dmp")) { + if(!_stricmp(ctxP->uszPath, "memory.dmp")) { *pcbWrite = cb; - cbHeaderSize = ctxVmm->f32 ? 0x1000 : 0x2000; + cbHeaderSize = H->vmm.f32 ? 0x1000 : 0x2000; if(cbOffset + cb <= cbHeaderSize) { return VMM_STATUS_SUCCESS; } @@ -426,7 +430,7 @@ NTSTATUS MVfsRoot_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_reads_(cb) PBYTE pb cb -= (DWORD)(cbHeaderSize - cbOffset); cbOffset = cbHeaderSize; } - fResult = VmmWrite(NULL, cbOffset, pb, cb); + fResult = VmmWrite(H, NULL, cbOffset, pb, cb); return fResult ? VMM_STATUS_SUCCESS : VMM_STATUS_FILE_SYSTEM_LIMITATION; } return VMM_STATUS_FILE_INVALID; @@ -440,13 +444,13 @@ NTSTATUS MVfsRoot_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_reads_(cb) PBYTE pb * -- pFileList * -- return */ -BOOL MVfsRoot_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) +BOOL MVfsRoot_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { - if(!ctx->uszPath[0]) { + if(!ctxP->uszPath[0]) { VMMDLL_VfsList_AddDirectory(pFileList, "name", NULL); VMMDLL_VfsList_AddDirectory(pFileList, "pid", NULL); - VMMDLL_VfsList_AddFile(pFileList, "memory.pmem", ctxMain->dev.paMax, NULL); - VMMDLL_VfsList_AddFile(pFileList, "memory.dmp", ctxMain->dev.paMax + (ctxVmm->f32 ? 0x1000 : 0x2000), NULL); + VMMDLL_VfsList_AddFile(pFileList, "memory.pmem", H->dev.paMax, NULL); + VMMDLL_VfsList_AddFile(pFileList, "memory.dmp", H->dev.paMax + (H->vmm.f32 ? 0x1000 : 0x2000), NULL); } return TRUE; } @@ -457,16 +461,17 @@ BOOL MVfsRoot_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) * shall call the supplied pfnPluginManager_Register function. * NB! the module does not have to register itself - for example if the target * operating system or architecture is unsupported. -* -- pPluginRegInfo +* -- H +* -- pRI */ -VOID M_VfsRoot_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_VfsRoot_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { strcpy_s(pRI->reg_info.uszPathName, 128, "\\"); // module name pRI->reg_info.fRootModule = TRUE; // root module pRI->reg_fn.pfnList = MVfsRoot_List; // List function supported pRI->reg_fn.pfnRead = MVfsRoot_Read; // Read function supported - if(ctxMain->dev.fWritable) { + if(H->dev.fWritable) { pRI->reg_fn.pfnWrite = MVfsRoot_Write; // Write function supported } - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_virt2phys.c b/vmm/m_virt2phys.c index efdf9c0..88bd278 100644 --- a/vmm/m_virt2phys.c +++ b/vmm/m_virt2phys.c @@ -22,29 +22,30 @@ LPCSTR szMVIRT2PHYS_README = /* * Read : function as specified by the module manager. The module manager will * call into this callback function whenever a read shall occur from a "file". -* -- ctx +* -- H +* -- ctxP * -- pb * -- cb * -- pcbRead * -- cbOffset * -- return */ -NTSTATUS Virt2Phys_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS Virt2Phys_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { BYTE iPML = 0; DWORD cbBuffer; PBYTE pbSourceData; BYTE pbBuffer[0x1000]; PVMMOB_CACHE_MEM pObPT = NULL; - PVMM_PROCESS pProcess = (PVMM_PROCESS)ctx->pProcess; + PVMM_PROCESS pProcess = (PVMM_PROCESS)ctxP->pProcess; VMM_VIRT2PHYS_INFORMATION Virt2PhysInfo = { 0 }; Virt2PhysInfo.va = pProcess->pObPersistent->Plugin.vaVirt2Phys; - VmmVirt2PhysGetInformation(pProcess, &Virt2PhysInfo); - if(!_stricmp(ctx->uszPath, "readme.txt")) { + VmmVirt2PhysGetInformation(H, pProcess, &Virt2PhysInfo); + if(!_stricmp(ctxP->uszPath, "readme.txt")) { return Util_VfsReadFile_FromStrA(szMVIRT2PHYS_README, pb, cb, pcbRead, cbOffset); } - if(!_stricmp(ctx->uszPath, "virt.txt")) { - switch(ctxVmm->tpMemoryModel) { + if(!_stricmp(ctxP->uszPath, "virt.txt")) { + switch(H->vmm.tpMemoryModel) { case VMM_MEMORYMODEL_X64: return Util_VfsReadFile_FromQWORD(Virt2PhysInfo.va, pb, cb, pcbRead, cbOffset, FALSE); case VMM_MEMORYMODEL_X86: @@ -54,11 +55,11 @@ NTSTATUS Virt2Phys_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pc return VMMDLL_STATUS_FILE_INVALID; } } - if(!_stricmp(ctx->uszPath, "phys.txt")) { + if(!_stricmp(ctxP->uszPath, "phys.txt")) { return Util_VfsReadFile_FromQWORD(Virt2PhysInfo.pas[0], pb, cb, pcbRead, cbOffset, FALSE); } - if(!_stricmp(ctx->uszPath, "map.txt")) { - switch(ctxVmm->tpMemoryModel) { + if(!_stricmp(ctxP->uszPath, "map.txt")) { + switch(H->vmm.tpMemoryModel) { case VMM_MEMORYMODEL_X64: cbBuffer = snprintf( (LPSTR)pbBuffer, @@ -107,26 +108,26 @@ NTSTATUS Virt2Phys_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pc return Util_VfsReadFile_FromPBYTE(pbBuffer, cbBuffer, pb, cb, pcbRead, cbOffset); } // "page table" or data page - if(!_stricmp(ctx->uszPath, "pt_pml4.mem")) { iPML = 4; } - if(!_stricmp(ctx->uszPath, "pt_pdpt.mem")) { iPML = 3; } - if(!_stricmp(ctx->uszPath, "pt_pd.mem")) { iPML = 2; } - if(!_stricmp(ctx->uszPath, "pt_pt.mem")) { iPML = 1; } - if((ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X86) && (iPML > 2)) { return VMMDLL_STATUS_FILE_INVALID; } - if((ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X86PAE) && (iPML > 3)) { return VMMDLL_STATUS_FILE_INVALID; } + if(!_stricmp(ctxP->uszPath, "pt_pml4.mem")) { iPML = 4; } + if(!_stricmp(ctxP->uszPath, "pt_pdpt.mem")) { iPML = 3; } + if(!_stricmp(ctxP->uszPath, "pt_pd.mem")) { iPML = 2; } + if(!_stricmp(ctxP->uszPath, "pt_pt.mem")) { iPML = 1; } + if((H->vmm.tpMemoryModel == VMM_MEMORYMODEL_X86) && (iPML > 2)) { return VMMDLL_STATUS_FILE_INVALID; } + if((H->vmm.tpMemoryModel == VMM_MEMORYMODEL_X86PAE) && (iPML > 3)) { return VMMDLL_STATUS_FILE_INVALID; } ZeroMemory(pbBuffer, 0x1000); pbSourceData = pbBuffer; if(iPML && (Virt2PhysInfo.pas[iPML] & ~0xfff)) { - pObPT = VmmTlbGetPageTable(Virt2PhysInfo.pas[iPML] & ~0xfff, FALSE); + pObPT = VmmTlbGetPageTable(H, Virt2PhysInfo.pas[iPML] & ~0xfff, FALSE); if(pObPT) { memcpy(pbSourceData, pObPT->pb, 0x1000); Ob_DECREF(pObPT); pObPT = NULL; } } - if(!_stricmp(ctx->uszPath, "page.mem") && (Virt2PhysInfo.pas[0] & ~0xfff)) { - VmmReadPage(NULL, Virt2PhysInfo.pas[0] & ~0xfff, pbBuffer); + if(!_stricmp(ctxP->uszPath, "page.mem") && (Virt2PhysInfo.pas[0] & ~0xfff)) { + VmmReadPage(H, NULL, Virt2PhysInfo.pas[0] & ~0xfff, pbBuffer); } - if(iPML || !_stricmp(ctx->uszPath, "page.mem")) { + if(iPML || !_stricmp(ctxP->uszPath, "page.mem")) { return Util_VfsReadFile_FromPBYTE(pbSourceData, 0x1000, pb, cb, pcbRead, cbOffset); } return VMMDLL_STATUS_FILE_INVALID; @@ -135,22 +136,23 @@ NTSTATUS Virt2Phys_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pc /* * Write : function as specified by the module manager. The module manager will * call into this callback function whenever a write shall occur from a "file". -* -- ctx +* -- H +* -- ctxP * -- pb * -- cb * -- pcbWrite * -- cbOffset * -- return */ -NTSTATUS Virt2Phys_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) +NTSTATUS Virt2Phys_Write(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) { DWORD i; - PVMM_PROCESS pProcess = (PVMM_PROCESS)ctx->pProcess; + PVMM_PROCESS pProcess = (PVMM_PROCESS)ctxP->pProcess; VMM_VIRT2PHYS_INFORMATION Virt2PhysInfo = { 0 }; - if(!_stricmp(ctx->uszPath, "virt.txt")) { - if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X64) { + if(!_stricmp(ctxP->uszPath, "virt.txt")) { + if(H->vmm.tpMemoryModel == VMM_MEMORYMODEL_X64) { return Util_VfsWriteFile_QWORD(&pProcess->pObPersistent->Plugin.vaVirt2Phys, pb, cb, pcbWrite, cbOffset, 0, 0); - } else if((ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X86) || (ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X86PAE)) { + } else if((H->vmm.tpMemoryModel == VMM_MEMORYMODEL_X86) || (H->vmm.tpMemoryModel == VMM_MEMORYMODEL_X86PAE)) { return Util_VfsWriteFile_DWORD((PDWORD)&pProcess->pObPersistent->Plugin.vaVirt2Phys, pb, cb, pcbWrite, cbOffset, 0, 0); } else { *pcbWrite = 0; @@ -158,18 +160,18 @@ NTSTATUS Virt2Phys_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_reads_(cb) PBYTE p } } Virt2PhysInfo.va = pProcess->pObPersistent->Plugin.vaVirt2Phys; - VmmVirt2PhysGetInformation(pProcess, &Virt2PhysInfo); + VmmVirt2PhysGetInformation(H, pProcess, &Virt2PhysInfo); i = 0xff; - if(!_stricmp(ctx->uszPath, "pt_pml4.mem")) { i = 4; } - if(!_stricmp(ctx->uszPath, "pt_pdpt.mem")) { i = 3; } - if(!_stricmp(ctx->uszPath, "pt_pd.mem")) { i = 2; } - if(!_stricmp(ctx->uszPath, "pt_pt.mem")) { i = 1; } - if(!_stricmp(ctx->uszPath, "page.mem")) { i = 0; } + if(!_stricmp(ctxP->uszPath, "pt_pml4.mem")) { i = 4; } + if(!_stricmp(ctxP->uszPath, "pt_pdpt.mem")) { i = 3; } + if(!_stricmp(ctxP->uszPath, "pt_pd.mem")) { i = 2; } + if(!_stricmp(ctxP->uszPath, "pt_pt.mem")) { i = 1; } + if(!_stricmp(ctxP->uszPath, "page.mem")) { i = 0; } if(i > 4) { return VMMDLL_STATUS_FILE_INVALID; } if(Virt2PhysInfo.pas[i] < 0x1000) { return VMMDLL_STATUS_FILE_INVALID; } if(cbOffset > 0x1000) { return VMMDLL_STATUS_END_OF_FILE; } *pcbWrite = (DWORD)min(cb, 0x1000 - cbOffset); - VmmWrite(NULL, Virt2PhysInfo.pas[i] + cbOffset, pb, *pcbWrite); + VmmWrite(H, NULL, Virt2PhysInfo.pas[i] + cbOffset, pb, *pcbWrite); return *pcbWrite ? VMMDLL_STATUS_SUCCESS : VMMDLL_STATUS_END_OF_FILE; } @@ -177,18 +179,19 @@ NTSTATUS Virt2Phys_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_reads_(cb) PBYTE p * List : function as specified by the module manager. The module manager will * call into this callback function whenever a list directory shall occur from * the given module. +* -- H * -- ctx * -- pFileList * -- return */ -BOOL Virt2Phys_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) +BOOL Virt2Phys_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { - if(ctx->uszPath[0]) { + if(ctxP->uszPath[0]) { // only list in module root directory. // not root directory == error for this module. return FALSE; } - switch(ctxVmm->tpMemoryModel) { + switch(H->vmm.tpMemoryModel) { case VMM_MEMORYMODEL_X64: VMMDLL_VfsList_AddFile(pFileList, "virt.txt", 16, NULL); VMMDLL_VfsList_AddFile(pFileList, "phys.txt", 16, NULL); @@ -229,9 +232,10 @@ BOOL Virt2Phys_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) * shall call the supplied pfnPluginManager_Register function. * NB! the module does not have to register itself - for example if the target * operating system or architecture is unsupported. -* -- pPluginRegInfo +* -- H +* -- pRI */ -VOID M_Virt2Phys_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_Virt2Phys_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if(!((pRI->tpMemoryModel == VMM_MEMORYMODEL_X64) || (pRI->tpMemoryModel == VMM_MEMORYMODEL_X86) || (pRI->tpMemoryModel == VMM_MEMORYMODEL_X86PAE))) { return; } @@ -240,5 +244,5 @@ VOID M_Virt2Phys_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) pRI->reg_fn.pfnList = Virt2Phys_List; // List function supported pRI->reg_fn.pfnRead = Virt2Phys_Read; // Read function supported pRI->reg_fn.pfnWrite = Virt2Phys_Write; // Write function supported - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/m_winreg.c b/vmm/m_winreg.c index bb49b12..42e646a 100644 --- a/vmm/m_winreg.c +++ b/vmm/m_winreg.c @@ -12,7 +12,7 @@ #define KEY_META_BUFFER_SIZE 0xA000 _Success_(return) -BOOL MWinReg_Read_HiveFile(POB_REGISTRY_HIVE pHive, _Out_writes_(*pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +BOOL MWinReg_Read_HiveFile(_In_ VMM_HANDLE H, POB_REGISTRY_HIVE pHive, _Out_writes_(*pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { DWORD cbReadBaseBlock; BYTE pbBaseBlock[0x1000] = { 0 }; @@ -25,7 +25,7 @@ BOOL MWinReg_Read_HiveFile(POB_REGISTRY_HIVE pHive, _Out_writes_(*pcbRead) PBYTE // Read base block / regf (first 0x1000 bytes). if(cbOffset < 0x1000) { cbReadBaseBlock = (DWORD)min(cb, 0x1000 - cbOffset); - VmmReadEx(PVMM_PROCESS_SYSTEM, pHive->vaHBASE_BLOCK, pbBaseBlock, 0x1000, NULL, VMM_FLAG_ZEROPAD_ON_FAIL); + VmmReadEx(H, PVMM_PROCESS_SYSTEM, pHive->vaHBASE_BLOCK, pbBaseBlock, 0x1000, NULL, VMM_FLAG_ZEROPAD_ON_FAIL); memcpy(pb, pbBaseBlock + cbOffset, cbReadBaseBlock); cbOffset += cbReadBaseBlock; pb += cbReadBaseBlock; @@ -33,24 +33,24 @@ BOOL MWinReg_Read_HiveFile(POB_REGISTRY_HIVE pHive, _Out_writes_(*pcbRead) PBYTE } // read hive memory space if((cbOffset >= 0x1000) && cb) { - VmmWinReg_HiveReadEx(pHive, (DWORD)(cbOffset - 0x1000), pb, cb, NULL, VMM_FLAG_ZEROPAD_ON_FAIL); + VmmWinReg_HiveReadEx(H, pHive, (DWORD)(cbOffset - 0x1000), pb, cb, NULL, VMM_FLAG_ZEROPAD_ON_FAIL); } return TRUE; } _Success_(return) -BOOL MWinReg_Read_HiveMemory(POB_REGISTRY_HIVE pHive, _Out_writes_(*pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +BOOL MWinReg_Read_HiveMemory(_In_ VMM_HANDLE H, POB_REGISTRY_HIVE pHive, _Out_writes_(*pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { if(cbOffset >= 0x100000000) { *pcbRead = 0; return FALSE; } *pcbRead = cb = (DWORD)min(cb, 0x100000000 - cbOffset); - VmmWinReg_HiveReadEx(pHive, (DWORD)cbOffset, pb, cb, NULL, VMM_FLAG_ZEROPAD_ON_FAIL); + VmmWinReg_HiveReadEx(H, pHive, (DWORD)cbOffset, pb, cb, NULL, VMM_FLAG_ZEROPAD_ON_FAIL); return TRUE; } -VOID MWinReg_Write_HiveFile(POB_REGISTRY_HIVE pHive, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) +VOID MWinReg_Write_HiveFile(_In_ VMM_HANDLE H, POB_REGISTRY_HIVE pHive, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) { DWORD cbWriteBaseBlock; *pcbWrite = 0; @@ -62,32 +62,32 @@ VOID MWinReg_Write_HiveFile(POB_REGISTRY_HIVE pHive, _In_reads_(cb) PBYTE pb, _I // Write base block / regf (first 0x1000 bytes). if(cbOffset < 0x1000) { cbWriteBaseBlock = (DWORD)min(cb, 0x1000 - cbOffset); - VmmWrite(PVMM_PROCESS_SYSTEM, (pHive->vaHBASE_BLOCK + (cbOffset & 0xfff)), pb, cbWriteBaseBlock); + VmmWrite(H, PVMM_PROCESS_SYSTEM, (pHive->vaHBASE_BLOCK + (cbOffset & 0xfff)), pb, cbWriteBaseBlock); cbOffset += cbWriteBaseBlock; pb += cbWriteBaseBlock; cb -= cbWriteBaseBlock; } // write hive memory space if((cbOffset >= 0x1000) && cb) { - VmmWinReg_HiveWrite(pHive, (DWORD)(cbOffset - 0x1000), pb, cb); + VmmWinReg_HiveWrite(H, pHive, (DWORD)(cbOffset - 0x1000), pb, cb); } } -VOID MWinReg_Write_HiveMemory(POB_REGISTRY_HIVE pHive, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) +VOID MWinReg_Write_HiveMemory(_In_ VMM_HANDLE H, POB_REGISTRY_HIVE pHive, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) { if(cbOffset >= 0x100000000) { *pcbWrite = 0; return; } cb = (DWORD)min(cb, 0x100000000 - cbOffset); - VmmWinReg_HiveWrite(pHive, (DWORD)cbOffset, pb, cb); + VmmWinReg_HiveWrite(H, pHive, (DWORD)cbOffset, pb, cb); *pcbWrite = cb; } /* * Helper function for MWinReg_Read_KeyValue to calculate the size of hexascii (binary) meta-data */ -DWORD MWinReg_Read_KeyValue_GetHexAscii(_In_ LPSTR szKeyName, _In_ PBYTE pbData, _In_ DWORD cbData, _Out_writes_(KEY_META_BUFFER_SIZE) LPSTR szMeta) +DWORD MWinReg_Read_KeyValue_GetHexAscii(_In_ VMM_HANDLE H, _In_ LPSTR szKeyName, _In_ PBYTE pbData, _In_ DWORD cbData, _Out_writes_(KEY_META_BUFFER_SIZE) LPSTR szMeta) { DWORD i, cszMeta = snprintf(szMeta, KEY_META_BUFFER_SIZE, "%s\n", szKeyName); if(cbData) { @@ -99,7 +99,7 @@ DWORD MWinReg_Read_KeyValue_GetHexAscii(_In_ LPSTR szKeyName, _In_ PBYTE pbData, return cszMeta; } -DWORD MWinReg_Read_KeyValue_GetAscii(_In_ LPSTR szKeyName, _In_ LPWSTR wszData, _In_ DWORD cbData, _Out_writes_(KEY_META_BUFFER_SIZE) LPSTR szMeta) +DWORD MWinReg_Read_KeyValue_GetAscii(_In_ VMM_HANDLE H, _In_ LPSTR szKeyName, _In_ LPWSTR wszData, _In_ DWORD cbData, _Out_writes_(KEY_META_BUFFER_SIZE) LPSTR szMeta) { WCHAR c; DWORD o, cszMeta; @@ -118,7 +118,7 @@ DWORD MWinReg_Read_KeyValue_GetAscii(_In_ LPSTR szKeyName, _In_ LPWSTR wszData, return cszMeta; } -NTSTATUS MWinReg_Read_KeyInfo(POB_REGISTRY_HIVE pHive, _In_ LPSTR uszKeyPath, _In_ BOOL fMeta, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MWinReg_Read_KeyInfo(_In_ VMM_HANDLE H, POB_REGISTRY_HIVE pHive, _In_ LPSTR uszKeyPath, _In_ BOOL fMeta, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; VMM_REGISTRY_KEY_INFO KeyInfo = { 0 }; @@ -126,7 +126,7 @@ NTSTATUS MWinReg_Read_KeyInfo(POB_REGISTRY_HIVE pHive, _In_ LPSTR uszKeyPath, _I PBYTE pbKey = NULL; DWORD cbKey; CHAR szTime[24]; - if(!(pObKey = VmmWinReg_KeyGetByPath(pHive, uszKeyPath))) { goto fail; } + if(!(pObKey = VmmWinReg_KeyGetByPath(H, pHive, uszKeyPath))) { goto fail; } VmmWinReg_KeyInfo(pHive, pObKey, &KeyInfo); if(fMeta) { cbKey = KEY_INFO_META_SIZE + KeyInfo.cbuName; @@ -137,7 +137,7 @@ NTSTATUS MWinReg_Read_KeyInfo(POB_REGISTRY_HIVE pHive, _In_ LPSTR uszKeyPath, _I } else { cbKey = KeyInfo.cbKeyCell; if(!(pbKey = LocalAlloc(LMEM_ZEROINIT, cbKey))) { goto fail; } - VmmWinReg_HiveReadEx(pHive, KeyInfo.raKeyCell, pbKey, cbKey, NULL, VMM_FLAG_ZEROPAD_ON_FAIL); + VmmWinReg_HiveReadEx(H, pHive, KeyInfo.raKeyCell, pbKey, cbKey, NULL, VMM_FLAG_ZEROPAD_ON_FAIL); nt = Util_VfsReadFile_FromPBYTE(pbKey, cbKey, pb, cb, pcbRead, cbOffset); } fail: @@ -146,7 +146,7 @@ fail: return nt; } -NTSTATUS MWinReg_Read_KeyValue(_In_ LPSTR uszPathFull, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MWinReg_Read_KeyValue(_In_ VMM_HANDLE H, _In_ LPSTR uszPathFull, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; POB_REGISTRY_HIVE pObHive = NULL; @@ -155,20 +155,22 @@ NTSTATUS MWinReg_Read_KeyValue(_In_ LPSTR uszPathFull, _Out_writes_to_(cb, *pcbR DWORD cbData, raValue = 0; PBYTE pbData = NULL; LPSTR szMeta = NULL; - if(!VmmWinReg_PathHiveGetByFullPath(uszPathFull, &pObHive, uszSubPath)) { goto finish; } + if(!VmmWinReg_PathHiveGetByFullPath(H, uszPathFull, &pObHive, uszSubPath)) { goto finish; } cuszSubPath = (DWORD)strlen(uszSubPath); // key info file if(CharUtil_StrEndsWith(uszSubPath, "\\(_Key_)", TRUE)) { uszSubPath[cuszSubPath - 8] = 0; - return MWinReg_Read_KeyInfo(pObHive, uszSubPath, FALSE, pb, cb, pcbRead, cbOffset); + nt = MWinReg_Read_KeyInfo(H, pObHive, uszSubPath, FALSE, pb, cb, pcbRead, cbOffset); + goto finish; } if(CharUtil_StrEndsWith(uszSubPath, "\\(_Key_).txt", TRUE)) { uszSubPath[cuszSubPath - 12] = 0; - return MWinReg_Read_KeyInfo(pObHive, uszSubPath, TRUE, pb, cb, pcbRead, cbOffset); + nt = MWinReg_Read_KeyInfo(H, pObHive, uszSubPath, TRUE, pb, cb, pcbRead, cbOffset); + goto finish; } // raw registry value - i.e not metadata if((cuszSubPath < 5) || strcmp(uszSubPath + cuszSubPath - 4, ".txt")) { - nt = VmmWinReg_ValueQuery1(pObHive, uszSubPath, NULL, NULL, pb, cb, pcbRead, cbOffset) ? VMMDLL_STATUS_SUCCESS : VMMDLL_STATUS_END_OF_FILE; + nt = VmmWinReg_ValueQuery1(H, pObHive, uszSubPath, NULL, NULL, pb, cb, pcbRead, cbOffset) ? VMMDLL_STATUS_SUCCESS : VMMDLL_STATUS_END_OF_FILE; goto finish; } // metadata file below: @@ -176,8 +178,8 @@ NTSTATUS MWinReg_Read_KeyValue(_In_ LPSTR uszPathFull, _Out_writes_to_(cb, *pcbR // allocate buffers and read value if(!(szMeta = (LPSTR)LocalAlloc(0, 27 + KEY_META_BUFFER_SIZE))) { goto finish; } if(!(pbData = LocalAlloc(LMEM_ZEROINIT, 2 * KEY_META_BUFFER_SIZE))) { goto finish; } - if(!VmmWinReg_ValueQuery1(pObHive, uszSubPath, &dwType, &raValue, pbData, 2 * KEY_META_BUFFER_SIZE, &cbData, 0)) { - VmmWinReg_ValueQuery1(pObHive, uszSubPath, &dwType, &raValue, NULL, 0, &cbData, 0); + if(!VmmWinReg_ValueQuery1(H, pObHive, uszSubPath, &dwType, &raValue, pbData, 2 * KEY_META_BUFFER_SIZE, &cbData, 0)) { + VmmWinReg_ValueQuery1(H, pObHive, uszSubPath, &dwType, &raValue, NULL, 0, &cbData, 0); } cbData = min(cbData, 2 * KEY_META_BUFFER_SIZE); // write address header and temporarily move szMeta start forward 26 bytes @@ -189,13 +191,13 @@ NTSTATUS MWinReg_Read_KeyValue(_In_ LPSTR uszPathFull, _Out_writes_to_(cb, *pcbR cszMeta = snprintf(szMeta, KEY_META_BUFFER_SIZE, "REG_NONE\n"); break; case REG_SZ: - cszMeta = MWinReg_Read_KeyValue_GetAscii("REG_SZ", (LPWSTR)pbData, cbData, szMeta); + cszMeta = MWinReg_Read_KeyValue_GetAscii(H, "REG_SZ", (LPWSTR)pbData, cbData, szMeta); break; case REG_EXPAND_SZ: - cszMeta = MWinReg_Read_KeyValue_GetAscii("REG_EXPAND_SZ", (LPWSTR)pbData, cbData, szMeta); + cszMeta = MWinReg_Read_KeyValue_GetAscii(H, "REG_EXPAND_SZ", (LPWSTR)pbData, cbData, szMeta); break; case REG_BINARY: - cszMeta = MWinReg_Read_KeyValue_GetHexAscii("REG_BINARY", pbData, cbData, szMeta); + cszMeta = MWinReg_Read_KeyValue_GetHexAscii(H, "REG_BINARY", pbData, cbData, szMeta); break; case REG_DWORD: cszMeta = snprintf(szMeta, KEY_META_BUFFER_SIZE, "REG_DWORD\n%08x\n", *(PDWORD)pbData); @@ -204,7 +206,7 @@ NTSTATUS MWinReg_Read_KeyValue(_In_ LPSTR uszPathFull, _Out_writes_to_(cb, *pcbR cszMeta = snprintf(szMeta, KEY_META_BUFFER_SIZE, "REG_DWORD_BIG_ENDIAN\n%2x%2x%2x%2x\n", pbData[0], pbData[1], pbData[2], pbData[3]); break; case REG_LINK: - cszMeta = MWinReg_Read_KeyValue_GetAscii("REG_LINK", (LPWSTR)pbData, cbData + 2, szMeta); + cszMeta = MWinReg_Read_KeyValue_GetAscii(H, "REG_LINK", (LPWSTR)pbData, cbData + 2, szMeta); break; case REG_MULTI_SZ: for(i = 0; (cbData >= 6) && (i < cbData - 4); i += 2) { // replace NULL WCHAR between strings with newline @@ -212,22 +214,22 @@ NTSTATUS MWinReg_Read_KeyValue(_In_ LPSTR uszPathFull, _Out_writes_to_(cb, *pcbR *(LPWSTR)(pbData + i) = '\n'; } } - cszMeta = MWinReg_Read_KeyValue_GetAscii("REG_MULTI_SZ", (LPWSTR)pbData, (cbData < 2 ? 0 : cbData - 2), szMeta); + cszMeta = MWinReg_Read_KeyValue_GetAscii(H, "REG_MULTI_SZ", (LPWSTR)pbData, (cbData < 2 ? 0 : cbData - 2), szMeta); break; case REG_RESOURCE_LIST: - cszMeta = MWinReg_Read_KeyValue_GetHexAscii("REG_RESOURCE_LIST", pbData, cbData, szMeta); + cszMeta = MWinReg_Read_KeyValue_GetHexAscii(H, "REG_RESOURCE_LIST", pbData, cbData, szMeta); break; case REG_FULL_RESOURCE_DESCRIPTOR: - cszMeta = MWinReg_Read_KeyValue_GetHexAscii("REG_FULL_RESOURCE_DESCRIPTOR", pbData, cbData, szMeta); + cszMeta = MWinReg_Read_KeyValue_GetHexAscii(H, "REG_FULL_RESOURCE_DESCRIPTOR", pbData, cbData, szMeta); break; case REG_RESOURCE_REQUIREMENTS_LIST: - cszMeta = MWinReg_Read_KeyValue_GetHexAscii("REG_RESOURCE_REQUIREMENTS_LIST", pbData, cbData, szMeta); + cszMeta = MWinReg_Read_KeyValue_GetHexAscii(H, "REG_RESOURCE_REQUIREMENTS_LIST", pbData, cbData, szMeta); break; case REG_QWORD: cszMeta = snprintf(szMeta, KEY_META_BUFFER_SIZE, "REG_QWORD\n%016llx\n", *(PQWORD)pbData); break; default: - cszMeta = MWinReg_Read_KeyValue_GetHexAscii("REG_UNKNOWN", pbData, cbData, szMeta); + cszMeta = MWinReg_Read_KeyValue_GetHexAscii(H, "REG_UNKNOWN", pbData, cbData, szMeta); break; } // move back address header @@ -242,51 +244,51 @@ finish: return nt; } -NTSTATUS MWinReg_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS MWinReg_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { BOOL fResult; POB_REGISTRY_HIVE pObHive = NULL; CHAR uszTopPath[64]; LPSTR uszSubPath; *pcbRead = 0; - uszSubPath = CharUtil_PathSplitFirst(ctx->uszPath, uszTopPath, sizeof(uszTopPath)); + uszSubPath = CharUtil_PathSplitFirst(ctxP->uszPath, uszTopPath, sizeof(uszTopPath)); if(!_stricmp(uszTopPath, "hive_files")) { - pObHive = VmmWinReg_HiveGetByAddress(Util_GetNumericA(uszSubPath)); + pObHive = VmmWinReg_HiveGetByAddress(H, Util_GetNumericA(uszSubPath)); if(!pObHive) { return VMMDLL_STATUS_FILE_INVALID; } - fResult = MWinReg_Read_HiveFile(pObHive, pb, cb, pcbRead, cbOffset); + fResult = MWinReg_Read_HiveFile(H, pObHive, pb, cb, pcbRead, cbOffset); Ob_DECREF(pObHive); return fResult ? VMMDLL_STATUS_SUCCESS : VMMDLL_STATUS_END_OF_FILE; } if(!_stricmp(uszTopPath, "hive_memory")) { - pObHive = VmmWinReg_HiveGetByAddress(Util_GetNumericA(uszSubPath)); + pObHive = VmmWinReg_HiveGetByAddress(H, Util_GetNumericA(uszSubPath)); if(!pObHive) { return VMMDLL_STATUS_FILE_INVALID; } - fResult = MWinReg_Read_HiveMemory(pObHive, pb, cb, pcbRead, cbOffset); + fResult = MWinReg_Read_HiveMemory(H, pObHive, pb, cb, pcbRead, cbOffset); Ob_DECREF(pObHive); return fResult ? VMMDLL_STATUS_SUCCESS : VMMDLL_STATUS_END_OF_FILE; } if(!_stricmp(uszTopPath, "by-hive") || !_stricmp(uszTopPath, "HKLM") || !_stricmp(uszTopPath, "HKU")) { - return MWinReg_Read_KeyValue(ctx->uszPath, pb, cb, pcbRead, cbOffset); + return MWinReg_Read_KeyValue(H, ctxP->uszPath, pb, cb, pcbRead, cbOffset); } return VMMDLL_STATUS_FILE_INVALID; } -NTSTATUS MWinReg_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) +NTSTATUS MWinReg_Write(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) { POB_REGISTRY_HIVE pObHive = NULL; CHAR uszTopPath[64]; LPSTR uszSubPath; - uszSubPath = CharUtil_PathSplitFirst(ctx->uszPath, uszTopPath, sizeof(uszTopPath)); + uszSubPath = CharUtil_PathSplitFirst(ctxP->uszPath, uszTopPath, sizeof(uszTopPath)); if(!_stricmp(uszTopPath, "hive_files")) { - pObHive = VmmWinReg_HiveGetByAddress(Util_GetNumericA(uszSubPath)); + pObHive = VmmWinReg_HiveGetByAddress(H, Util_GetNumericA(uszSubPath)); if(!pObHive) { return VMMDLL_STATUS_FILE_INVALID; } - MWinReg_Write_HiveFile(pObHive, pb, cb, pcbWrite, cbOffset); + MWinReg_Write_HiveFile(H, pObHive, pb, cb, pcbWrite, cbOffset); Ob_DECREF(pObHive); return VMMDLL_STATUS_SUCCESS; } if(!_stricmp(uszTopPath, "hive_memory")) { - pObHive = VmmWinReg_HiveGetByAddress(Util_GetNumericA(uszSubPath)); + pObHive = VmmWinReg_HiveGetByAddress(H, Util_GetNumericA(uszSubPath)); if(!pObHive) { return VMMDLL_STATUS_FILE_INVALID; } - MWinReg_Write_HiveMemory(pObHive, pb, cb, pcbWrite, cbOffset); + MWinReg_Write_HiveMemory(H, pObHive, pb, cb, pcbWrite, cbOffset); Ob_DECREF(pObHive); return VMMDLL_STATUS_SUCCESS; } @@ -331,7 +333,7 @@ DWORD MWinReg_List_MWinReg_List_KeyAndValueMetaSize(_In_ PVMM_REGISTRY_VALUE_INF } } -VOID MWinReg_List_KeyAndValue(_Inout_ PHANDLE pFileList, _In_ POB_REGISTRY_HIVE pHive, _In_ LPSTR uszPath) +VOID MWinReg_List_KeyAndValue(_In_ VMM_HANDLE H, _Inout_ PHANDLE pFileList, _In_ POB_REGISTRY_HIVE pHive, _In_ LPSTR uszPath) { CHAR uszNameMeta[MAX_PATH]; POB_MAP pmObSubkeys, pmObValues = NULL; @@ -341,7 +343,7 @@ VOID MWinReg_List_KeyAndValue(_Inout_ PHANDLE pFileList, _In_ POB_REGISTRY_HIVE VMM_REGISTRY_VALUE_INFO ValueInfo; VMMDLL_VFS_FILELIST_EXINFO FileExInfo = { 0 }; FileExInfo.dwVersion = VMMDLL_VFS_FILELIST_EXINFO_VERSION; - if(uszPath[0] && !(pObKey = VmmWinReg_KeyGetByPath(pHive, uszPath))) { return; } + if(uszPath[0] && !(pObKey = VmmWinReg_KeyGetByPath(H, pHive, uszPath))) { return; } // list key info if(pObKey && _stricmp(uszPath, "ORPHAN\\") && _stricmp(uszPath, "ORPHAN")) { VmmWinReg_KeyInfo(pHive, pObKey, &KeyInfo); @@ -351,7 +353,7 @@ VOID MWinReg_List_KeyAndValue(_Inout_ PHANDLE pFileList, _In_ POB_REGISTRY_HIVE VMMDLL_VfsList_AddFile(pFileList, "(_Key_).txt", KEY_INFO_META_SIZE + KeyInfo.cbuName, &FileExInfo); } // list sub-keys - if((pmObSubkeys = VmmWinReg_KeyList(pHive, pObKey))) { + if((pmObSubkeys = VmmWinReg_KeyList(H, pHive, pObKey))) { while((pObSubkey = ObMap_GetNext(pmObSubkeys, pObSubkey))) { VmmWinReg_KeyInfo(pHive, pObSubkey, &KeyInfo); FileExInfo.fCompressed = !KeyInfo.fActive; @@ -360,7 +362,7 @@ VOID MWinReg_List_KeyAndValue(_Inout_ PHANDLE pFileList, _In_ POB_REGISTRY_HIVE } } // list values - if(pObKey && (pmObValues = VmmWinReg_KeyValueList(pHive, pObKey))) { + if(pObKey && (pmObValues = VmmWinReg_KeyValueList(H, pHive, pObKey))) { VmmWinReg_KeyInfo(pHive, pObKey, &KeyInfo); FileExInfo.fCompressed = !KeyInfo.fActive; FileExInfo.qwLastWriteTime = KeyInfo.ftLastWrite; @@ -377,7 +379,7 @@ VOID MWinReg_List_KeyAndValue(_Inout_ PHANDLE pFileList, _In_ POB_REGISTRY_HIVE Ob_DECREF(pObKey); } -BOOL MWinReg_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) +BOOL MWinReg_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) { DWORD i; CHAR uszNameHive[MAX_PATH]; @@ -395,14 +397,14 @@ BOOL MWinReg_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) return TRUE; } if(!_stricmp(uszPath, "hive_files")) { - while((pObHive = VmmWinReg_HiveGetNext(pObHive))) { + while((pObHive = VmmWinReg_HiveGetNext(H, pObHive))) { _snprintf_s(uszNameHive, _countof(uszNameHive), _TRUNCATE, "%s.reghive", pObHive->uszName); VMMDLL_VfsList_AddFile(pFileList, uszNameHive, pObHive->cbLength + 0x1000ULL, NULL); } return TRUE; } if(!_stricmp(uszPath, "hive_memory")) { - while((pObHive = VmmWinReg_HiveGetNext(pObHive))) { + while((pObHive = VmmWinReg_HiveGetNext(H, pObHive))) { _snprintf_s(uszNameHive, _countof(uszNameHive), _TRUNCATE, "%s.hivemem", pObHive->uszName); VMMDLL_VfsList_AddFile(pFileList, uszNameHive, 0x100000000, NULL); } @@ -411,15 +413,15 @@ BOOL MWinReg_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) if(!_strnicmp(uszPath, "by-hive", 7)) { // list hives if(!_stricmp(uszPath, "by-hive")) { - while((pObHive = VmmWinReg_HiveGetNext(pObHive))) { + while((pObHive = VmmWinReg_HiveGetNext(H, pObHive))) { _snprintf_s(uszNameHive, _countof(uszNameHive), _TRUNCATE, "%s", pObHive->uszName); VMMDLL_VfsList_AddDirectory(pFileList, uszNameHive, NULL); } return TRUE; } // list hive contents - if(VmmWinReg_PathHiveGetByFullPath(uszPath, &pObHive, uszPathHive)) { - MWinReg_List_KeyAndValue(pFileList, pObHive, uszPathHive); + if(VmmWinReg_PathHiveGetByFullPath(H, uszPath, &pObHive, uszPathHive)) { + MWinReg_List_KeyAndValue(H, pFileList, pObHive, uszPathHive); Ob_DECREF_NULL(&pObHive); return TRUE; } @@ -443,8 +445,8 @@ BOOL MWinReg_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) return TRUE; } // list hive contents - if(VmmWinReg_PathHiveGetByFullPath(uszPath, &pObHive, uszPathHive)) { - MWinReg_List_KeyAndValue(pFileList, pObHive, uszPathHive); + if(VmmWinReg_PathHiveGetByFullPath(H, uszPath, &pObHive, uszPathHive)) { + MWinReg_List_KeyAndValue(H, pFileList, pObHive, uszPathHive); Ob_DECREF_NULL(&pObHive); return TRUE; } @@ -455,7 +457,7 @@ BOOL MWinReg_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) FileExInfo.fCompressed = TRUE; } if(!_stricmp(uszPath, "HKU") || !_stricmp(uszPath, "HKU\\ORPHAN")) { - if(VmmMap_GetUser(&pObUserMap)) { + if(VmmMap_GetUser(H, &pObUserMap)) { for(i = 0; i < pObUserMap->cMap; i++) { if(pObUserMap->pMap[i].vaRegHive) { VMMDLL_VfsList_AddDirectory(pFileList, pObUserMap->pMap[i].uszText, &FileExInfo); @@ -473,8 +475,8 @@ BOOL MWinReg_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) return TRUE; } // list hive contents - if(VmmWinReg_PathHiveGetByFullPath(uszPath, &pObHive, uszPathHive)) { - MWinReg_List_KeyAndValue(pFileList, pObHive, uszPathHive); + if(VmmWinReg_PathHiveGetByFullPath(H, uszPath, &pObHive, uszPathHive)) { + MWinReg_List_KeyAndValue(H, pFileList, pObHive, uszPathHive); Ob_DECREF_NULL(&pObHive); return TRUE; } @@ -483,7 +485,7 @@ BOOL MWinReg_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) return FALSE; } -VOID M_WinReg_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) +VOID M_WinReg_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI) { if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } if((pRI->tpSystem != VMM_SYSTEM_WINDOWS_X64) && (pRI->tpSystem != VMM_SYSTEM_WINDOWS_X86)) { return; } @@ -492,5 +494,5 @@ VOID M_WinReg_Initialize(_Inout_ PVMMDLL_PLUGIN_REGINFO pRI) pRI->reg_fn.pfnList = MWinReg_List; // List function supported pRI->reg_fn.pfnRead = MWinReg_Read; // Read function supported pRI->reg_fn.pfnWrite = MWinReg_Write; // Write function supported - pRI->pfnPluginManager_Register(pRI); + pRI->pfnPluginManager_Register(H, pRI); } diff --git a/vmm/mm.h b/vmm/mm.h index 40d2a96..633b1db 100644 --- a/vmm/mm.h +++ b/vmm/mm.h @@ -11,56 +11,63 @@ * Initialize the X86 32-bit protected mode memory model. * If a previous memory model exists that memory model is first closed before * the new X86 memory model is initialized. +* -- H */ -VOID MmX86_Initialize(); +VOID MmX86_Initialize(_In_ VMM_HANDLE H); /* * Initialize the X86 PAE 32-bit protected mode memory model. * If a previous memory model exists that memory model is first closed before * the new X86 PAE memory model is initialized. +* -- H */ -VOID MmX86PAE_Initialize(); +VOID MmX86PAE_Initialize(_In_ VMM_HANDLE H); /* * Initialize the X64 / IA32e / Long-Mode paging / memory model. * If a previous memory model exists that memory model is first closed before * the new X64 memory model is initialized. +* -- H */ -VOID MmX64_Initialize(); +VOID MmX64_Initialize(_In_ VMM_HANDLE H); /* * Initialize the paging sub-system for Windows in a limited or full fashion. * In full mode Win10 memory decompression will be initialized. +* -- H * -- fModeFull */ -VOID MmWin_PagingInitialize(_In_ BOOL fModeFull); +VOID MmWin_PagingInitialize(_In_ VMM_HANDLE H, _In_ BOOL fModeFull); /* * Close / Shutdown the paging subsystem. This function should not be called * when there is an active thread executing inside the sub-system - ideally * it should only be called on shutdown. +* -- H */ -VOID MmWin_PagingClose(); +VOID MmWin_PagingClose(_In_ VMM_HANDLE H); /* * Initialize / Ensure that a VAD map is initialized for the specific process. +* -- H * -- pProcess * -- tp = VMM_VADMAP_TP_* * -- fVmmRead = VMM_FLAGS_* flags. * -- return */ _Success_(return) -BOOL MmVad_MapInitialize(_In_ PVMM_PROCESS pProcess, _In_ VMM_VADMAP_TP tp, _In_ QWORD fVmmRead); +BOOL MmVad_MapInitialize(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ VMM_VADMAP_TP tp, _In_ QWORD fVmmRead); /* * Try to read a prototype page table entry (PTE). +* -- H * -- pProcess * -- va * -- pfInRange * -- fVmmRead = VMM_FLAGS_* flags. * -- return = prototype pte or zero on fail. */ -QWORD MmVad_PrototypePte(_In_ PVMM_PROCESS pProcess, _In_ QWORD va, _Out_opt_ PBOOL pfInRange, _In_ QWORD fVmmRead); +QWORD MmVad_PrototypePte(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD va, _Out_opt_ PBOOL pfInRange, _In_ QWORD fVmmRead); /* * Interprete VAD protection flags into string p[mgn]rwxc. @@ -88,6 +95,7 @@ CHAR MmVadEx_StrType(_In_ VMM_PTE_TP tp); * Initialize / Retrieve an extended VAD map with info about individual pages in * the ranges pecified by the iPage and cPage variables. * CALLER DECREF: return +* -- H * -- pProcess * -- tpVmmVadMap = VMM_VADMAP_TP_* * -- iPage = index of range start in vad map. @@ -95,6 +103,6 @@ CHAR MmVadEx_StrType(_In_ VMM_PTE_TP tp); * -- return */ _Success_(return != NULL) -PVMMOB_MAP_VADEX MmVadEx_MapInitialize(_In_ PVMM_PROCESS pProcess, _In_ VMM_VADMAP_TP tpVmmVadMap, _In_ DWORD iPage, _In_ DWORD cPage); +PVMMOB_MAP_VADEX MmVadEx_MapInitialize(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ VMM_VADMAP_TP tpVmmVadMap, _In_ DWORD iPage, _In_ DWORD cPage); #endif /* __MM_H__ */ diff --git a/vmm/mm_pfn.c b/vmm/mm_pfn.c index 1028e82..aaee504 100644 --- a/vmm/mm_pfn.c +++ b/vmm/mm_pfn.c @@ -33,57 +33,60 @@ VOID MmPfn_CallbackCleanup_ObContext(POB_MMPFN_CONTEXT ctx) DeleteCriticalSection(&ctx->Lock); } -VOID MmPfn_Refresh() +VOID MmPfn_Refresh(_In_ VMM_HANDLE H) { - POB_MMPFN_CONTEXT ctx = (POB_MMPFN_CONTEXT)ctxVmm->pObPfnContext; + POB_MMPFN_CONTEXT ctx = (POB_MMPFN_CONTEXT)H->vmm.pObPfnContext; if(!ctx) { return; } ObContainer_SetOb(ctx->pObCProcTableDTB, NULL); } -VOID MmPfn_Initialize(_In_ PVMM_PROCESS pSystemProcess) +VOID MmPfn_Initialize(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess) { BOOL f; POB_MMPFN_CONTEXT ctx; - if(!(ctx = Ob_Alloc(OB_TAG_PFN_CONTEXT, LMEM_ZEROINIT, sizeof(OB_MMPFN_CONTEXT), (OB_CLEANUP_CB)MmPfn_CallbackCleanup_ObContext, NULL))) { return; } + if(!(ctx = Ob_AllocEx(H, OB_TAG_PFN_CONTEXT, LMEM_ZEROINIT, sizeof(OB_MMPFN_CONTEXT), (OB_CLEANUP_CB)MmPfn_CallbackCleanup_ObContext, NULL))) { return; } InitializeCriticalSection(&ctx->Lock); f = (ctx->pObCProcTableDTB = ObContainer_New()) && - PDB_GetSymbolPTR(PDB_HANDLE_KERNEL, "MmPfnDatabase", pSystemProcess, &ctx->vaPfnDatabase) && - PDB_GetTypeSizeShort(PDB_HANDLE_KERNEL, "_MMPFN", &ctx->_MMPFN.cb) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_MMPFN", "OriginalPte", &ctx->_MMPFN.oOriginalPte) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_MMPFN", "PteAddress", &ctx->_MMPFN.oPteAddress) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_MMPFN", "u2", &ctx->_MMPFN.ou2) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_MMPFN", "u3", &ctx->_MMPFN.ou3) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_MMPFN", "u4", &ctx->_MMPFN.ou4) && - (ctx->iPfnMax = (DWORD)(ctxMain->dev.paMax >> 12)) && - (ctxVmm->pObPfnContext = Ob_INCREF(ctx)); + PDB_GetSymbolPTR(H, PDB_HANDLE_KERNEL, "MmPfnDatabase", pSystemProcess, &ctx->vaPfnDatabase) && + PDB_GetTypeSizeShort(H, PDB_HANDLE_KERNEL, "_MMPFN", &ctx->_MMPFN.cb) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_MMPFN", "OriginalPte", &ctx->_MMPFN.oOriginalPte) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_MMPFN", "PteAddress", &ctx->_MMPFN.oPteAddress) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_MMPFN", "u2", &ctx->_MMPFN.ou2) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_MMPFN", "u3", &ctx->_MMPFN.ou3) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_MMPFN", "u4", &ctx->_MMPFN.ou4) && + (ctx->iPfnMax = (DWORD)(H->dev.paMax >> 12)); + if(f) { + H->vmm.pObPfnContext = Ob_INCREF(ctx); + } Ob_DECREF(ctx); } /* * Create a new process data table sorted on DTB PFN. * CALLER DECREF: return +* -- H * -- ctx * -- return */ -POB_DATA MmPfn_ProcDTB_Create(_In_ POB_MMPFN_CONTEXT ctx) +POB_DATA MmPfn_ProcDTB_Create(_In_ VMM_HANDLE H, _In_ POB_MMPFN_CONTEXT ctx) { SIZE_T i, cPIDs = 0, cEntries; POB_DATA pObData = NULL; PVMM_PROCESS pObProcess = NULL; PVMMOB_CACHE_MEM pObPDPT = NULL; QWORD j, qwPte; - VmmProcessListPIDs(NULL, &cPIDs, 0); - cEntries = cPIDs * ((ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X86PAE) ? 4 : 1); - if(!(pObData = Ob_Alloc(OB_TAG_PFN_PROC_TABLE, LMEM_ZEROINIT, sizeof(OB) + cEntries * sizeof(QWORD), NULL, NULL))) { return NULL; } - VmmProcessListPIDs(pObData->pdw, &cPIDs, 0); + VmmProcessListPIDs(H, NULL, &cPIDs, 0); + cEntries = cPIDs * ((H->vmm.tpMemoryModel == VMM_MEMORYMODEL_X86PAE) ? 4 : 1); + if(!(pObData = Ob_AllocEx(H, OB_TAG_PFN_PROC_TABLE, LMEM_ZEROINIT, sizeof(OB) + cEntries * sizeof(QWORD), NULL, NULL))) { return NULL; } + VmmProcessListPIDs(H, pObData->pdw, &cPIDs, 0); for(i = 0; i < cPIDs; i++) { - if((pObProcess = VmmProcessGet(pObData->pdw[cPIDs - i - 1]))) { - if((ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X64) || (ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X86)) { + if((pObProcess = VmmProcessGet(H, pObData->pdw[cPIDs - i - 1]))) { + if((H->vmm.tpMemoryModel == VMM_MEMORYMODEL_X64) || (H->vmm.tpMemoryModel == VMM_MEMORYMODEL_X86)) { if(pObProcess->fUserOnly) { pObData->pqw[cPIDs - i - 1] = pObProcess->dwPID | (pObProcess->paDTB << 20); } - } else if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X86PAE) { - if((pObPDPT = VmmTlbGetPageTable(pObProcess->paDTB & ~0xfff, FALSE))) { + } else if(H->vmm.tpMemoryModel == VMM_MEMORYMODEL_X86PAE) { + if((pObPDPT = VmmTlbGetPageTable(H, pObProcess->paDTB & ~0xfff, FALSE))) { for(j = 0; j < 4; j++) { if((qwPte = pObPDPT->pqw[((pObProcess->paDTB & 0xfff) >> 3) + j])) { pObData->pqw[(cPIDs - i - 1) * 4 + j] = pObProcess->dwPID | ((qwPte & 0x00000ffffffff000) << 20) | (j << 30); @@ -111,10 +114,11 @@ int MmPfn_GetPidFromDTB_qfind(_In_ QWORD pvFind, _In_ QWORD pvEntry) /* * Retrieve a process PID given a prcess DTB. +* -- H * -- ctx * -- return */ -DWORD MmPfn_GetPidFromDTB(_In_ POB_MMPFN_CONTEXT ctx, _In_ PVMM_PROCESS pSystemProcess, _In_ QWORD qwPfnDTB) +DWORD MmPfn_GetPidFromDTB(_In_ VMM_HANDLE H, _In_ POB_MMPFN_CONTEXT ctx, _In_ PVMM_PROCESS pSystemProcess, _In_ QWORD qwPfnDTB) { DWORD dwPID; PVOID pvFind; @@ -123,7 +127,7 @@ DWORD MmPfn_GetPidFromDTB(_In_ POB_MMPFN_CONTEXT ctx, _In_ PVMM_PROCESS pSystemP if(!(pObData = ObContainer_GetOb(ctx->pObCProcTableDTB))) { EnterCriticalSection(&ctx->Lock); if(!(pObData = ObContainer_GetOb(ctx->pObCProcTableDTB))) { - pObData = MmPfn_ProcDTB_Create(ctx); + pObData = MmPfn_ProcDTB_Create(H, ctx); } LeaveCriticalSection(&ctx->Lock); } @@ -134,7 +138,7 @@ DWORD MmPfn_GetPidFromDTB(_In_ POB_MMPFN_CONTEXT ctx, _In_ PVMM_PROCESS pSystemP return dwPID; } -VOID MmPfn_Map_GetPfn_GetVaX64(_In_ POB_MMPFN_CONTEXT ctx, _In_ PVMM_PROCESS pSystemProcess, _In_ POB_SET psPte, _In_ POB_SET psPrefetch, _In_ BYTE iPML) +VOID MmPfn_Map_GetPfn_GetVaX64(_In_ VMM_HANDLE H, _In_ POB_MMPFN_CONTEXT ctx, _In_ PVMM_PROCESS pSystemProcess, _In_ POB_SET psPte, _In_ POB_SET psPrefetch, _In_ BYTE iPML) { BOOL f; BYTE tp, pbPfn[0x30]; @@ -142,12 +146,12 @@ VOID MmPfn_Map_GetPfn_GetVaX64(_In_ POB_MMPFN_CONTEXT ctx, _In_ PVMM_PROCESS pSy DWORD i, c, iPfnNext, cbRead; QWORD pa; PVMMOB_CACHE_MEM pObPD = NULL; - VmmCachePrefetchPages(pSystemProcess, psPrefetch, 0); + VmmCachePrefetchPages(H, pSystemProcess, psPrefetch, 0); ObSet_Clear(psPrefetch); for(i = 0, c = ObSet_Size(psPte); i < c; i++) { pe = (PMMPFN_MAP_ENTRY)ObSet_Get(psPte, i); if(!pe || !pe->AddressInfo.va) { continue; } - VmmReadEx(pSystemProcess, MMPFN_PFN_TO_VA(ctx, pe->AddressInfo.dwPfnPte[iPML]), pbPfn, ctx->_MMPFN.cb, &cbRead, 0); + VmmReadEx(H, pSystemProcess, MMPFN_PFN_TO_VA(ctx, pe->AddressInfo.dwPfnPte[iPML]), pbPfn, ctx->_MMPFN.cb, &cbRead, 0); f = cbRead && (tp = (pbPfn[ctx->_MMPFN.ou3 + 2] & 0x7)) && // "PageLocation" ((tp == MmPfnTypeActive) || (pe->PageLocation == MmPfnTypeStandby) || (tp == MmPfnTypeModified) || (tp == MmPfnTypeModifiedNoWrite)) && @@ -161,11 +165,11 @@ VOID MmPfn_Map_GetPfn_GetVaX64(_In_ POB_MMPFN_CONTEXT ctx, _In_ PVMM_PROCESS pSy pe->AddressInfo.va = pe->AddressInfo.va | 0xffff000000000000; } if(pe->AddressInfo.va) { - pe->AddressInfo.dwPid = MmPfn_GetPidFromDTB(ctx, pSystemProcess, (QWORD)pe->AddressInfo.dwPfnPte[4]); + pe->AddressInfo.dwPid = MmPfn_GetPidFromDTB(H, ctx, pSystemProcess, (QWORD)pe->AddressInfo.dwPfnPte[4]); if(pe->AddressInfo.dwPid && (pe->AddressInfo.dwPid != 4)) { pe->tpExtended = MmPfnExType_ProcessPrivate; } - if(!pe->AddressInfo.dwPid && (!VmmVirt2Phys(pSystemProcess, pe->AddressInfo.va, &pa) || (pe->dwPfn != pa >> 12))) { + if(!pe->AddressInfo.dwPid && (!VmmVirt2Phys(H, pSystemProcess, pe->AddressInfo.va, &pa) || (pe->dwPfn != pa >> 12))) { pe->AddressInfo.va = 0; } if(pe->AddressInfo.va && (pe->AddressInfo.dwPfnPte[3] == pe->AddressInfo.dwPfnPte[4])) { @@ -180,24 +184,24 @@ VOID MmPfn_Map_GetPfn_GetVaX64(_In_ POB_MMPFN_CONTEXT ctx, _In_ PVMM_PROCESS pSy } } if(iPML < 3) { - MmPfn_Map_GetPfn_GetVaX64(ctx, pSystemProcess, psPte, psPrefetch, iPML + 1); + MmPfn_Map_GetPfn_GetVaX64(H, ctx, pSystemProcess, psPte, psPrefetch, iPML + 1); } } -VOID MmPfn_Map_GetPfn_GetVaX86PAE(_In_ POB_MMPFN_CONTEXT ctx, _In_ PVMM_PROCESS pSystemProcess, _In_ POB_SET psPte, _In_ POB_SET psPrefetch, _In_ BYTE iPML) +VOID MmPfn_Map_GetPfn_GetVaX86PAE(_In_ VMM_HANDLE H, _In_ POB_MMPFN_CONTEXT ctx, _In_ PVMM_PROCESS pSystemProcess, _In_ POB_SET psPte, _In_ POB_SET psPrefetch, _In_ BYTE iPML) { BOOL f; BYTE tp, pbPfn[0x30]; PMMPFN_MAP_ENTRY pe; QWORD pa; DWORD i, c, iPfnNext, cbRead, dwPidEx, iPfn, dwPid; - VmmCachePrefetchPages(pSystemProcess, psPrefetch, 0); + VmmCachePrefetchPages(H, pSystemProcess, psPrefetch, 0); ObSet_Clear(psPrefetch); for(i = 0, c = ObSet_Size(psPte); i < c; i++) { pe = (PMMPFN_MAP_ENTRY)ObSet_Get(psPte, i); if(!pe || !pe->AddressInfo.va) { continue; } if(iPML == 2) { - dwPidEx = MmPfn_GetPidFromDTB(ctx, pSystemProcess, (QWORD)pe->AddressInfo.dwPfnPte[2]); + dwPidEx = MmPfn_GetPidFromDTB(H, ctx, pSystemProcess, (QWORD)pe->AddressInfo.dwPfnPte[2]); dwPid = dwPidEx & 0x3fffffff; iPfn = dwPidEx >> 30; if(dwPid && (dwPid != 4) && (iPfn < 2)) { @@ -206,13 +210,13 @@ VOID MmPfn_Map_GetPfn_GetVaX86PAE(_In_ POB_MMPFN_CONTEXT ctx, _In_ PVMM_PROCESS pe->AddressInfo.va = (pe->AddressInfo.va & ~0xfff) + ((QWORD)iPfn << 30); } else { pe->AddressInfo.va = (pe->AddressInfo.va & ~0xfff) + ((QWORD)iPfn << 30); - if(!VmmVirt2Phys(pSystemProcess, pe->AddressInfo.va, &pa) || (pe->dwPfn != pa >> 12)) { + if(!VmmVirt2Phys(H, pSystemProcess, pe->AddressInfo.va, &pa) || (pe->dwPfn != pa >> 12)) { pe->AddressInfo.va = 0; } } continue; } - VmmReadEx(pSystemProcess, MMPFN_PFN_TO_VA(ctx, pe->AddressInfo.dwPfnPte[iPML]), pbPfn, ctx->_MMPFN.cb, &cbRead, 0); + VmmReadEx(H, pSystemProcess, MMPFN_PFN_TO_VA(ctx, pe->AddressInfo.dwPfnPte[iPML]), pbPfn, ctx->_MMPFN.cb, &cbRead, 0); f = cbRead && (tp = (pbPfn[ctx->_MMPFN.ou3 + 2] & 0x7)) && // "PageLocation" ((tp == MmPfnTypeActive) || (pe->PageLocation == MmPfnTypeStandby) || (tp == MmPfnTypeModified) || (tp == MmPfnTypeModifiedNoWrite)) && @@ -226,11 +230,11 @@ VOID MmPfn_Map_GetPfn_GetVaX86PAE(_In_ POB_MMPFN_CONTEXT ctx, _In_ PVMM_PROCESS } } if(iPML < 2) { - MmPfn_Map_GetPfn_GetVaX86PAE(ctx, pSystemProcess, psPte, psPrefetch, iPML + 1); + MmPfn_Map_GetPfn_GetVaX86PAE(H, ctx, pSystemProcess, psPte, psPrefetch, iPML + 1); } } -VOID MmPfn_Map_GetPfn_GetVaX86(_In_ POB_MMPFN_CONTEXT ctx, _In_ PVMM_PROCESS pSystemProcess, _In_ POB_SET psPte, _In_ POB_SET psPrefetch) +VOID MmPfn_Map_GetPfn_GetVaX86(_In_ VMM_HANDLE H, _In_ POB_MMPFN_CONTEXT ctx, _In_ PVMM_PROCESS pSystemProcess, _In_ POB_SET psPte, _In_ POB_SET psPrefetch) { BOOL f; BYTE tp, pbPfn[0x30]; @@ -238,13 +242,13 @@ VOID MmPfn_Map_GetPfn_GetVaX86(_In_ POB_MMPFN_CONTEXT ctx, _In_ PVMM_PROCESS pSy DWORD i, c, iPfnNext, cbRead, dwPID, dwPte; QWORD pa; PVMMOB_CACHE_MEM pObPD = NULL; - VmmCachePrefetchPages(pSystemProcess, psPrefetch, 0); + VmmCachePrefetchPages(H, pSystemProcess, psPrefetch, 0); ObSet_Clear(psPrefetch); for(i = 0, c = ObSet_Size(psPte); i < c; i++) { pe = (PMMPFN_MAP_ENTRY)ObSet_Get(psPte, i); if(!pe) { continue; } pe->AddressInfo.va = 0; - VmmReadEx(pSystemProcess, MMPFN_PFN_TO_VA(ctx, pe->AddressInfo.dwPfnPte[1]), pbPfn, ctx->_MMPFN.cb, &cbRead, 0); + VmmReadEx(H, pSystemProcess, MMPFN_PFN_TO_VA(ctx, pe->AddressInfo.dwPfnPte[1]), pbPfn, ctx->_MMPFN.cb, &cbRead, 0); f = cbRead && (tp = (pbPfn[ctx->_MMPFN.ou3 + 2] & 0x7)) && // "PageLocation" ((tp == MmPfnTypeActive) || (pe->PageLocation == MmPfnTypeStandby) || (tp == MmPfnTypeModified) || (tp == MmPfnTypeModifiedNoWrite)) && @@ -252,13 +256,13 @@ VOID MmPfn_Map_GetPfn_GetVaX86(_In_ POB_MMPFN_CONTEXT ctx, _In_ PVMM_PROCESS pSy (iPfnNext <= ctx->iPfnMax) && (pe->AddressInfo.dwPfnPte[2] = iPfnNext); if(!f) { continue; } pe->AddressInfo.va += ((QWORD)(*(PDWORD)(pbPfn + ctx->_MMPFN.oPteAddress) & 0xffc) << 20) + ((pe->vaPte & 0xffc) << 10); - dwPID = MmPfn_GetPidFromDTB(ctx, pSystemProcess, (QWORD)pe->AddressInfo.dwPfnPte[2]); + dwPID = MmPfn_GetPidFromDTB(H, ctx, pSystemProcess, (QWORD)pe->AddressInfo.dwPfnPte[2]); if(dwPID && (dwPID != 4)) { pe->AddressInfo.dwPid = dwPID; pe->tpExtended = MmPfnExType_ProcessPrivate; } else { if(pe->AddressInfo.dwPfnPte[1] == pe->AddressInfo.dwPfnPte[2]) { - if((pObPD = VmmTlbGetPageTable((QWORD)pe->AddressInfo.dwPfnPte[2] << 12, FALSE))) { + if((pObPD = VmmTlbGetPageTable(H, (QWORD)pe->AddressInfo.dwPfnPte[2] << 12, FALSE))) { dwPte = pObPD->pdw[pe->AddressInfo.va >> 22]; Ob_DECREF_NULL(&pObPD); if(dwPte & 0x01) { @@ -268,7 +272,7 @@ VOID MmPfn_Map_GetPfn_GetVaX86(_In_ POB_MMPFN_CONTEXT ctx, _In_ PVMM_PROCESS pSy } } } - if(!VmmVirt2Phys(pSystemProcess, pe->AddressInfo.va, &pa) || (pe->dwPfn != pa >> 12)) { + if(!VmmVirt2Phys(H, pSystemProcess, pe->AddressInfo.va, &pa) || (pe->dwPfn != pa >> 12)) { pe->AddressInfo.va = 0; } } @@ -276,10 +280,10 @@ VOID MmPfn_Map_GetPfn_GetVaX86(_In_ POB_MMPFN_CONTEXT ctx, _In_ PVMM_PROCESS pSy } _Success_(return) -BOOL MmPfn_Map_GetPfnScatter(_In_ POB_SET psPfn, _Out_ PMMPFNOB_MAP *ppObPfnMap, _In_ BOOL fExtended) +BOOL MmPfn_Map_GetPfnScatter(_In_ VMM_HANDLE H, _In_ POB_SET psPfn, _Out_ PMMPFNOB_MAP *ppObPfnMap, _In_ BOOL fExtended) { - POB_MMPFN_CONTEXT ctx = (POB_MMPFN_CONTEXT)ctxVmm->pObPfnContext; - BOOL f32 = ctxVmm->f32; + POB_MMPFN_CONTEXT ctx = (POB_MMPFN_CONTEXT)H->vmm.pObPfnContext; + BOOL f32 = H->vmm.f32; BYTE pbPfn[0x30] = { 0 }; PVMM_PROCESS pObSystemProcess = NULL; PMMPFNOB_MAP pObPfnMap = NULL; @@ -290,10 +294,10 @@ BOOL MmPfn_Map_GetPfnScatter(_In_ POB_SET psPfn, _Out_ PMMPFNOB_MAP *ppObPfnMap, if(!ctx) { goto fail; } // initialization if(!(cPfn = ObSet_Size(psPfn))) { goto fail; } - if(!(pObSystemProcess = VmmProcessGet(4))) { goto fail; } - if(!(psObEnrichAddress = ObSet_New())) { goto fail; } - if(!(psObPrefetch = ObSet_New())) { goto fail; } - if(!(pObPfnMap = Ob_Alloc(OB_TAG_MAP_PFN, LMEM_ZEROINIT, sizeof(MMPFNOB_MAP) + cPfn * sizeof(MMPFN_MAP_ENTRY), NULL, NULL))) { goto fail; } + if(!(pObSystemProcess = VmmProcessGet(H, 4))) { goto fail; } + if(!(psObEnrichAddress = ObSet_New(H))) { goto fail; } + if(!(psObPrefetch = ObSet_New(H))) { goto fail; } + if(!(pObPfnMap = Ob_AllocEx(H, OB_TAG_MAP_PFN, LMEM_ZEROINIT, sizeof(MMPFNOB_MAP) + cPfn * sizeof(MMPFN_MAP_ENTRY), NULL, NULL))) { goto fail; } pObPfnMap->cMap = cPfn; // translate pfn# to pfn va and prefetch for(i = 0; i < cPfn; i++) { @@ -301,13 +305,13 @@ BOOL MmPfn_Map_GetPfnScatter(_In_ POB_SET psPfn, _Out_ PMMPFNOB_MAP *ppObPfnMap, pe->dwPfn = (DWORD)ObSet_Get(psPfn, i); ObSet_Push_PageAlign(psObPrefetch, MMPFN_PFN_TO_VA(ctx, pe->dwPfn), ctx->_MMPFN.cb); } - VmmCachePrefetchPages(pObSystemProcess, psObPrefetch, 0); + VmmCachePrefetchPages(H, pObSystemProcess, psObPrefetch, 0); ObSet_Clear(psObPrefetch); // iterate and fetch pfns for(i = 0; i < cPfn; i++) { pe = pObPfnMap->pMap + i; if(pe->dwPfn > ctx->iPfnMax) { continue; } - VmmReadEx(pObSystemProcess, MMPFN_PFN_TO_VA(ctx, pe->dwPfn), pbPfn, ctx->_MMPFN.cb, &cbRead, 0); + VmmReadEx(H, pObSystemProcess, MMPFN_PFN_TO_VA(ctx, pe->dwPfn), pbPfn, ctx->_MMPFN.cb, &cbRead, 0); if(!cbRead) { continue; } pe->_u3 = *(PDWORD)(pbPfn + ctx->_MMPFN.ou3); qw = *(PQWORD)(pbPfn + ctx->_MMPFN.ou4); @@ -343,12 +347,12 @@ BOOL MmPfn_Map_GetPfnScatter(_In_ POB_SET psPfn, _Out_ PMMPFNOB_MAP *ppObPfnMap, } // encrich result with virtual addresses and additional info if(ObSet_Size(psObEnrichAddress)) { - if(ctxVmm->tpMemoryModel == VMMDLL_MEMORYMODEL_X64) { - MmPfn_Map_GetPfn_GetVaX64(ctx, pObSystemProcess, psObEnrichAddress, psObPrefetch, 1); - } else if(ctxVmm->tpMemoryModel == VMMDLL_MEMORYMODEL_X86PAE) { - MmPfn_Map_GetPfn_GetVaX86PAE(ctx, pObSystemProcess, psObEnrichAddress, psObPrefetch, 1); - } else if(ctxVmm->tpMemoryModel == VMMDLL_MEMORYMODEL_X86) { - MmPfn_Map_GetPfn_GetVaX86(ctx, pObSystemProcess, psObEnrichAddress, psObPrefetch); + if(H->vmm.tpMemoryModel == VMMDLL_MEMORYMODEL_X64) { + MmPfn_Map_GetPfn_GetVaX64(H, ctx, pObSystemProcess, psObEnrichAddress, psObPrefetch, 1); + } else if(H->vmm.tpMemoryModel == VMMDLL_MEMORYMODEL_X86PAE) { + MmPfn_Map_GetPfn_GetVaX86PAE(H, ctx, pObSystemProcess, psObEnrichAddress, psObPrefetch, 1); + } else if(H->vmm.tpMemoryModel == VMMDLL_MEMORYMODEL_X86) { + MmPfn_Map_GetPfn_GetVaX86(H, ctx, pObSystemProcess, psObEnrichAddress, psObPrefetch); } } // fall through to cleanup @@ -362,16 +366,16 @@ fail: } _Success_(return) -BOOL MmPfn_Map_GetPfn(_In_ DWORD dwPfnStart, _In_ DWORD cPfn, _Out_ PMMPFNOB_MAP *ppObPfnMap, _In_ BOOL fExtended) +BOOL MmPfn_Map_GetPfn(_In_ VMM_HANDLE H, _In_ DWORD dwPfnStart, _In_ DWORD cPfn, _Out_ PMMPFNOB_MAP *ppObPfnMap, _In_ BOOL fExtended) { BOOL fResult; POB_SET psObPfn; QWORD iPfn, iPfnEnd; - if(!(psObPfn = ObSet_New())) { return FALSE; } + if(!(psObPfn = ObSet_New(H))) { return FALSE; } for(iPfn = dwPfnStart, iPfnEnd = (QWORD)dwPfnStart + cPfn; iPfn < iPfnEnd; iPfn++) { ObSet_Push(psObPfn, 0x8000000000000000 | iPfn); } - fResult = MmPfn_Map_GetPfnScatter(psObPfn, ppObPfnMap, fExtended); + fResult = MmPfn_Map_GetPfnScatter(H, psObPfn, ppObPfnMap, fExtended); Ob_DECREF(psObPfn); return fResult; } diff --git a/vmm/mm_pfn.h b/vmm/mm_pfn.h index 6e850bc..8dbe3ad 100644 --- a/vmm/mm_pfn.h +++ b/vmm/mm_pfn.h @@ -84,19 +84,22 @@ typedef struct tdMMPFNOB_MAP { /* * Initialize the PFN (page frame number) subsystem. +* -- H * -- pSystemProcess */ -VOID MmPfn_Initialize(_In_ PVMM_PROCESS pSystemProcess); +VOID MmPfn_Initialize(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess); /* * Refresh the PFN (page frame number) subsystem. * This should be performed after each process list refresh. +* -- H */ -VOID MmPfn_Refresh(); +VOID MmPfn_Refresh(_In_ VMM_HANDLE H); /* * Retrieve information about a sequential number of PFNs. * CALLER DECREF: pObPfnMap +* -- H * -- dwPfnStart = starting PFN. PFN = physical address / 0x1000. * -- cPfn * -- ppObPfnMap @@ -104,13 +107,14 @@ VOID MmPfn_Refresh(); * -- return */ _Success_(return) -BOOL MmPfn_Map_GetPfn(_In_ DWORD dwPfnStart, _In_ DWORD cPfn, _Out_ PMMPFNOB_MAP *ppObPfnMap, _In_ BOOL fExtended); +BOOL MmPfn_Map_GetPfn(_In_ VMM_HANDLE H, _In_ DWORD dwPfnStart, _In_ DWORD cPfn, _Out_ PMMPFNOB_MAP *ppObPfnMap, _In_ BOOL fExtended); /* * Retrieve information about scattered PFNs. The PFNs are returned in order of * in which they are stored in the psPfn set. * NB! POB_SET does not support ZERO, for PFN zero use 0x8000000000000000. * CALLER DECREF: pObPfnMap +* -- H * -- psPfn = Set of PFNs. PFN = physical address / 0x1000. * -- cPfn * -- ppObPfnMap @@ -118,6 +122,6 @@ BOOL MmPfn_Map_GetPfn(_In_ DWORD dwPfnStart, _In_ DWORD cPfn, _Out_ PMMPFNOB_MAP * -- return */ _Success_(return) -BOOL MmPfn_Map_GetPfnScatter(_In_ POB_SET psPfn, _Out_ PMMPFNOB_MAP *ppObPfnMap, _In_ BOOL fExtended); +BOOL MmPfn_Map_GetPfnScatter(_In_ VMM_HANDLE H, _In_ POB_SET psPfn, _Out_ PMMPFNOB_MAP *ppObPfnMap, _In_ BOOL fExtended); #endif /* __MM_PFN_H__ */ diff --git a/vmm/mm_vad.c b/vmm/mm_vad.c index 1f09fb8..b20d3d6 100644 --- a/vmm/mm_vad.c +++ b/vmm/mm_vad.c @@ -14,7 +14,7 @@ #define MMVAD_POOLTAG_VADL 'Vadl' #define MMVAD_POOLTAG_VADM 'Vadm' -#define MMVAD_PTESIZE ((ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X86) ? 4 : 8) +#define MMVAD_PTESIZE ((H->vmm.tpMemoryModel == VMM_MEMORYMODEL_X86) ? 4 : 8) #define MMVAD_MAXVADS_THRESHOLD 0x10000 #define MMVADEX_MAXVADPAGES_THRESHOLD 0x10000 @@ -476,11 +476,11 @@ BOOL MmVad_Spider_PoolTagAny(_In_ DWORD dwPoolTag, _In_ DWORD cPoolTag, ...) return FALSE; } -PVMM_MAP_VADENTRY MmVad_Spider_MMVAD32_XP(_In_ PVMM_PROCESS pSystemProcess, _In_ QWORD va, _In_ PVMMOB_MAP_VAD pmVad, _In_ POB_SET psAll, _In_ POB_SET psTry1, _In_opt_ POB_SET psTry2, _In_ QWORD fVmmRead, _In_ DWORD dwReserved) +PVMM_MAP_VADENTRY MmVad_Spider_MMVAD32_XP(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ QWORD va, _In_ PVMMOB_MAP_VAD pmVad, _In_ POB_SET psAll, _In_ POB_SET psTry1, _In_opt_ POB_SET psTry2, _In_ QWORD fVmmRead, _In_ DWORD dwReserved) { _MMVAD32_XP v = { 0 }; PVMM_MAP_VADENTRY e; - if(!VmmRead2(pSystemProcess, va, (PBYTE)&v, sizeof(_MMVAD32_XP), fVmmRead | VMM_FLAG_FORCECACHE_READ)) { + if(!VmmRead2(H, pSystemProcess, va, (PBYTE)&v, sizeof(_MMVAD32_XP), fVmmRead | VMM_FLAG_FORCECACHE_READ)) { ObSet_Push(psTry2, va); return NULL; } @@ -489,12 +489,10 @@ PVMM_MAP_VADENTRY MmVad_Spider_MMVAD32_XP(_In_ PVMM_PROCESS pSystemProcess, _In_ } // short vad e = &pmVad->pMap[pmVad->cMap++]; - if(VMM_KADDR32_8(v.LeftChild)) { - ObSet_Push(psAll, v.LeftChild - 8); + if(VMM_KADDR32_8(v.LeftChild) && ObSet_Push(psAll, v.LeftChild - 8)) { ObSet_Push(psTry1, v.LeftChild - 8); } - if(VMM_KADDR32_8(v.RightChild)) { - ObSet_Push(psAll, v.RightChild - 8); + if(VMM_KADDR32_8(v.RightChild) && ObSet_Push(psAll, v.RightChild - 8)) { ObSet_Push(psTry1, v.RightChild - 8); } e->vaStart = (QWORD)v.StartingVpn << 12; @@ -515,11 +513,11 @@ PVMM_MAP_VADENTRY MmVad_Spider_MMVAD32_XP(_In_ PVMM_PROCESS pSystemProcess, _In_ return e; } -PVMM_MAP_VADENTRY MmVad_Spider_MMVAD32_7(_In_ PVMM_PROCESS pSystemProcess, _In_ QWORD va, _In_ PVMMOB_MAP_VAD pmVad, _In_ POB_SET psAll, _In_ POB_SET psTry1, _In_opt_ POB_SET psTry2, _In_ QWORD fVmmRead, _In_ DWORD dwReserved) +PVMM_MAP_VADENTRY MmVad_Spider_MMVAD32_7(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ QWORD va, _In_ PVMMOB_MAP_VAD pmVad, _In_ POB_SET psAll, _In_ POB_SET psTry1, _In_opt_ POB_SET psTry2, _In_ QWORD fVmmRead, _In_ DWORD dwReserved) { _MMVAD32_7 v = { 0 }; PVMM_MAP_VADENTRY e; - if(!VmmRead2(pSystemProcess, va, (PBYTE)&v, sizeof(_MMVAD32_7), fVmmRead | VMM_FLAG_FORCECACHE_READ)) { + if(!VmmRead2(H, pSystemProcess, va, (PBYTE)&v, sizeof(_MMVAD32_7), fVmmRead | VMM_FLAG_FORCECACHE_READ)) { ObSet_Push(psTry2, va); return NULL; } @@ -528,12 +526,10 @@ PVMM_MAP_VADENTRY MmVad_Spider_MMVAD32_7(_In_ PVMM_PROCESS pSystemProcess, _In_ } // short vad e = &pmVad->pMap[pmVad->cMap++]; - if(VMM_KADDR32_8(v.LeftChild)) { - ObSet_Push(psAll, v.LeftChild - 8); + if(VMM_KADDR32_8(v.LeftChild) && ObSet_Push(psAll, v.LeftChild - 8)) { ObSet_Push(psTry1, v.LeftChild - 8); } - if(VMM_KADDR32_8(v.RightChild)) { - ObSet_Push(psAll, v.RightChild - 8); + if(VMM_KADDR32_8(v.RightChild) && ObSet_Push(psAll, v.RightChild - 8)) { ObSet_Push(psTry1, v.RightChild - 8); } e->vaStart = (QWORD)v.StartingVpn << 12; @@ -553,11 +549,11 @@ PVMM_MAP_VADENTRY MmVad_Spider_MMVAD32_7(_In_ PVMM_PROCESS pSystemProcess, _In_ return e; } -PVMM_MAP_VADENTRY MmVad_Spider_MMVAD64_7(_In_ PVMM_PROCESS pSystemProcess, _In_ QWORD va, _In_ PVMMOB_MAP_VAD pmVad, _In_ POB_SET psAll, _In_ POB_SET psTry1, _In_opt_ POB_SET psTry2, _In_ QWORD fVmmRead, _In_ DWORD dwReserved) +PVMM_MAP_VADENTRY MmVad_Spider_MMVAD64_7(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ QWORD va, _In_ PVMMOB_MAP_VAD pmVad, _In_ POB_SET psAll, _In_ POB_SET psTry1, _In_opt_ POB_SET psTry2, _In_ QWORD fVmmRead, _In_ DWORD dwReserved) { _MMVAD64_7 v = { 0 }; PVMM_MAP_VADENTRY e; - if(!VmmRead2(pSystemProcess, va, (PBYTE)&v, sizeof(_MMVAD64_7), fVmmRead | VMM_FLAG_FORCECACHE_READ)) { + if(!VmmRead2(H, pSystemProcess, va, (PBYTE)&v, sizeof(_MMVAD64_7), fVmmRead | VMM_FLAG_FORCECACHE_READ)) { ObSet_Push(psTry2, va); return NULL; } @@ -566,12 +562,10 @@ PVMM_MAP_VADENTRY MmVad_Spider_MMVAD64_7(_In_ PVMM_PROCESS pSystemProcess, _In_ } // short vad e = &pmVad->pMap[pmVad->cMap++]; - if(VMM_KADDR64_16(v.LeftChild)) { - ObSet_Push(psAll, v.LeftChild - 0x10); + if(VMM_KADDR64_16(v.LeftChild) && ObSet_Push(psAll, v.LeftChild - 0x10)) { ObSet_Push(psTry1, v.LeftChild - 0x10); } - if(VMM_KADDR64_16(v.RightChild)) { - ObSet_Push(psAll, v.RightChild - 0x10); + if(VMM_KADDR64_16(v.RightChild) && ObSet_Push(psAll, v.RightChild - 0x10)) { ObSet_Push(psTry1, v.RightChild - 0x10); } e->vaStart = (QWORD)v.StartingVpn << 12; @@ -591,11 +585,11 @@ PVMM_MAP_VADENTRY MmVad_Spider_MMVAD64_7(_In_ PVMM_PROCESS pSystemProcess, _In_ return e; } -PVMM_MAP_VADENTRY MmVad_Spider_MMVAD32_80(_In_ PVMM_PROCESS pSystemProcess, _In_ QWORD va, _In_ PVMMOB_MAP_VAD pmVad, _In_ POB_SET psAll, _In_ POB_SET psTry1, _In_opt_ POB_SET psTry2, _In_ QWORD fVmmRead, _In_ DWORD dwReserved) +PVMM_MAP_VADENTRY MmVad_Spider_MMVAD32_80(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ QWORD va, _In_ PVMMOB_MAP_VAD pmVad, _In_ POB_SET psAll, _In_ POB_SET psTry1, _In_opt_ POB_SET psTry2, _In_ QWORD fVmmRead, _In_ DWORD dwReserved) { _MMVAD32_80 v = { 0 }; PVMM_MAP_VADENTRY e; - if(!VmmRead2(pSystemProcess, va, (PBYTE)&v, sizeof(_MMVAD32_80), fVmmRead | VMM_FLAG_FORCECACHE_READ)) { + if(!VmmRead2(H, pSystemProcess, va, (PBYTE)&v, sizeof(_MMVAD32_80), fVmmRead | VMM_FLAG_FORCECACHE_READ)) { ObSet_Push(psTry2, va); return NULL; } @@ -604,12 +598,10 @@ PVMM_MAP_VADENTRY MmVad_Spider_MMVAD32_80(_In_ PVMM_PROCESS pSystemProcess, _In_ } // short vad e = &pmVad->pMap[pmVad->cMap++]; - if(VMM_KADDR64_16(v.LeftChild)) { - ObSet_Push(psAll, v.LeftChild - 8); + if(VMM_KADDR64_16(v.LeftChild) && ObSet_Push(psAll, v.LeftChild - 8)) { ObSet_Push(psTry1, v.LeftChild - 8); } - if(VMM_KADDR64_16(v.RightChild)) { - ObSet_Push(psAll, v.RightChild - 8); + if(VMM_KADDR64_16(v.RightChild) && ObSet_Push(psAll, v.RightChild - 8)) { ObSet_Push(psTry1, v.RightChild - 8); } e->vaStart = (QWORD)v.StartingVpn << 12; @@ -630,11 +622,11 @@ PVMM_MAP_VADENTRY MmVad_Spider_MMVAD32_80(_In_ PVMM_PROCESS pSystemProcess, _In_ return e; } -PVMM_MAP_VADENTRY MmVad_Spider_MMVAD64_80(_In_ PVMM_PROCESS pSystemProcess, _In_ QWORD va, _In_ PVMMOB_MAP_VAD pmVad, _In_ POB_SET psAll, _In_ POB_SET psTry1, _In_opt_ POB_SET psTry2, _In_ QWORD fVmmRead, _In_ DWORD dwReserved) +PVMM_MAP_VADENTRY MmVad_Spider_MMVAD64_80(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ QWORD va, _In_ PVMMOB_MAP_VAD pmVad, _In_ POB_SET psAll, _In_ POB_SET psTry1, _In_opt_ POB_SET psTry2, _In_ QWORD fVmmRead, _In_ DWORD dwReserved) { _MMVAD64_80 v = { 0 }; PVMM_MAP_VADENTRY e; - if(!VmmRead2(pSystemProcess, va, (PBYTE)&v, sizeof(_MMVAD64_80), fVmmRead | VMM_FLAG_FORCECACHE_READ)) { + if(!VmmRead2(H, pSystemProcess, va, (PBYTE)&v, sizeof(_MMVAD64_80), fVmmRead | VMM_FLAG_FORCECACHE_READ)) { ObSet_Push(psTry2, va); return NULL; } @@ -643,12 +635,10 @@ PVMM_MAP_VADENTRY MmVad_Spider_MMVAD64_80(_In_ PVMM_PROCESS pSystemProcess, _In_ } // short vad e = &pmVad->pMap[pmVad->cMap++]; - if(VMM_KADDR64_16(v.LeftChild)) { - ObSet_Push(psAll, v.LeftChild - 0x10); + if(VMM_KADDR64_16(v.LeftChild) && ObSet_Push(psAll, v.LeftChild - 0x10)) { ObSet_Push(psTry1, v.LeftChild - 0x10); } - if(VMM_KADDR64_16(v.RightChild)) { - ObSet_Push(psAll, v.RightChild - 0x10); + if(VMM_KADDR64_16(v.RightChild) && ObSet_Push(psAll, v.RightChild - 0x10)) { ObSet_Push(psTry1, v.RightChild - 0x10); } e->vaStart = (QWORD)v.StartingVpn << 12; @@ -669,11 +659,11 @@ PVMM_MAP_VADENTRY MmVad_Spider_MMVAD64_80(_In_ PVMM_PROCESS pSystemProcess, _In_ return e; } -PVMM_MAP_VADENTRY MmVad_Spider_MMVAD32_10(_In_ PVMM_PROCESS pSystemProcess, _In_ QWORD va, _In_ PVMMOB_MAP_VAD pmVad, _In_ POB_SET psAll, _In_ POB_SET psTry1, _In_opt_ POB_SET psTry2, _In_ QWORD fVmmRead, _In_ DWORD dwFlagsBitMask) +PVMM_MAP_VADENTRY MmVad_Spider_MMVAD32_10(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ QWORD va, _In_ PVMMOB_MAP_VAD pmVad, _In_ POB_SET psAll, _In_ POB_SET psTry1, _In_opt_ POB_SET psTry2, _In_ QWORD fVmmRead, _In_ DWORD dwFlagsBitMask) { _MMVAD32_10 v = { 0 }; PVMM_MAP_VADENTRY e; - if(!VmmRead2(pSystemProcess, va, (PBYTE)&v, sizeof(_MMVAD32_10), fVmmRead | VMM_FLAG_FORCECACHE_READ)) { + if(!VmmRead2(H, pSystemProcess, va, (PBYTE)&v, sizeof(_MMVAD32_10), fVmmRead | VMM_FLAG_FORCECACHE_READ)) { ObSet_Push(psTry2, va); return NULL; } @@ -682,12 +672,10 @@ PVMM_MAP_VADENTRY MmVad_Spider_MMVAD32_10(_In_ PVMM_PROCESS pSystemProcess, _In_ } // short vad e = &pmVad->pMap[pmVad->cMap++]; - if(VMM_KADDR32_8(v.Children[0])) { - ObSet_Push(psAll, v.Children[0] - 8); + if(VMM_KADDR32_8(v.Children[0]) && ObSet_Push(psAll, v.Children[0] - 8)) { ObSet_Push(psTry1, v.Children[0] - 8); } - if(VMM_KADDR32_8(v.Children[1])) { - ObSet_Push(psAll, v.Children[1] - 8); + if(VMM_KADDR32_8(v.Children[1]) && ObSet_Push(psAll, v.Children[1] - 8)) { ObSet_Push(psTry1, v.Children[1] - 8); } e->vaStart = (QWORD)v.StartingVpn << 12; @@ -708,11 +696,11 @@ PVMM_MAP_VADENTRY MmVad_Spider_MMVAD32_10(_In_ PVMM_PROCESS pSystemProcess, _In_ return e; } -PVMM_MAP_VADENTRY MmVad_Spider_MMVAD64_10(_In_ PVMM_PROCESS pSystemProcess, _In_ QWORD va, _In_ PVMMOB_MAP_VAD pmVad, _In_ POB_SET psAll, _In_ POB_SET psTry1, _In_opt_ POB_SET psTry2, _In_ QWORD fVmmRead, _In_ DWORD dwFlagsBitMask) +PVMM_MAP_VADENTRY MmVad_Spider_MMVAD64_10(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ QWORD va, _In_ PVMMOB_MAP_VAD pmVad, _In_ POB_SET psAll, _In_ POB_SET psTry1, _In_opt_ POB_SET psTry2, _In_ QWORD fVmmRead, _In_ DWORD dwFlagsBitMask) { _MMVAD64_10 v = { 0 }; PVMM_MAP_VADENTRY e; - if(!VmmRead2(pSystemProcess, va, (PBYTE)&v, sizeof(_MMVAD64_10), fVmmRead | VMM_FLAG_FORCECACHE_READ)) { + if(!VmmRead2(H, pSystemProcess, va, (PBYTE)&v, sizeof(_MMVAD64_10), fVmmRead | VMM_FLAG_FORCECACHE_READ)) { ObSet_Push(psTry2, va); return NULL; } @@ -721,12 +709,10 @@ PVMM_MAP_VADENTRY MmVad_Spider_MMVAD64_10(_In_ PVMM_PROCESS pSystemProcess, _In_ } // short vad e = &pmVad->pMap[pmVad->cMap++]; - if(VMM_KADDR64_16(v.Children[0])) { - ObSet_Push(psAll, v.Children[0] - 0x10); + if(VMM_KADDR64_16(v.Children[0]) && ObSet_Push(psAll, v.Children[0] - 0x10)) { ObSet_Push(psTry1, v.Children[0] - 0x10); } - if(VMM_KADDR64_16(v.Children[1])) { - ObSet_Push(psAll, v.Children[1] - 0x10); + if(VMM_KADDR64_16(v.Children[1]) && ObSet_Push(psAll, v.Children[1] - 0x10)) { ObSet_Push(psTry1, v.Children[1] - 0x10); } e->vaStart = ((QWORD)v.StartingVpnHigh << (32 + 12)) | ((QWORD)v.StartingVpn << 12); @@ -747,89 +733,96 @@ PVMM_MAP_VADENTRY MmVad_Spider_MMVAD64_10(_In_ PVMM_PROCESS pSystemProcess, _In_ return e; } -VOID MmVad_Spider_DoWork(_In_ PVMM_PROCESS pSystemProcess, _In_ PVMM_PROCESS pProcess, _In_ QWORD fVmmRead) +VOID MmVad_Spider_DoWork(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ PVMM_PROCESS pProcess, _In_ QWORD fVmmRead) { - BOOL f; - QWORD i, va; + BOOL f, f32 = H->vmm.f32; + DWORD dwVersionBuild = H->vmm.kernel.dwVersionBuild; + QWORD i, va, fVmmReadSpider; DWORD cMax, cVads, dwFlagsBitMask = 0; PVMM_MAP_VADENTRY eVad; PVMMOB_MAP_VAD pmObVad = NULL, pmObVadTemp; POB_SET psObAll = NULL, psObTry1 = NULL, psObTry2 = NULL, psObPrefetch = NULL; - PVMM_MAP_VADENTRY(*pfnMmVad_Spider)(PVMM_PROCESS, QWORD, PVMMOB_MAP_VAD, POB_SET, POB_SET, POB_SET, QWORD, DWORD); - if(!(ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X64 || ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X86)) { goto fail; } + PVMM_MAP_VADENTRY(*pfnMmVad_Spider)(VMM_HANDLE, PVMM_PROCESS, QWORD, PVMMOB_MAP_VAD, POB_SET, POB_SET, POB_SET, QWORD, DWORD); + if(!(H->vmm.tpSystem == VMM_SYSTEM_WINDOWS_X64 || H->vmm.tpSystem == VMM_SYSTEM_WINDOWS_X86)) { goto fail; } // 1: retrieve # of VAD entries and sanity check. - if(ctxVmm->kernel.dwVersionBuild >= 9600) { + if(dwVersionBuild >= 9600) { // Win8.1 and later -> fetch # of RtlBalancedNode from EPROCESS. - cVads = (DWORD)VMM_EPROCESS_PTR(pProcess, ctxVmm->offset.EPROCESS.VadRoot + (ctxVmm->f32 ? 8 : 0x10)); - } else if(ctxVmm->kernel.dwVersionBuild >= 6000) { + cVads = (DWORD)VMM_EPROCESS_PTR(f32, pProcess, H->vmm.offset.EPROCESS.VadRoot + (f32 ? 8 : 0x10)); + } else if(dwVersionBuild >= 6000) { // WinVista::Win8.0 -> fetch # of AvlNode from EPROCESS. - i = (ctxVmm->kernel.dwVersionBuild < 9200) ? (ctxVmm->f32 ? 0x14 : 0x28) : (ctxVmm->f32 ? 0x1c : 0x18); - cVads = ((DWORD)VMM_EPROCESS_PTR(pProcess, ctxVmm->offset.EPROCESS.VadRoot + i) >> 8); + i = (dwVersionBuild < 9200) ? (f32 ? 0x14 : 0x28) : (f32 ? 0x1c : 0x18); + cVads = ((DWORD)VMM_EPROCESS_PTR(f32, pProcess, H->vmm.offset.EPROCESS.VadRoot + i) >> 8); } else { // WinXP cVads = (DWORD)VMM_EPROCESS_DWORD(pProcess, 0x240); } if(cVads > MMVAD_MAXVADS_THRESHOLD) { - VmmLog(MID_VMM, LOGLEVEL_VERBOSE, "BAD #VAD VALUE- PID: %i #VAD: %x\n", pProcess->dwPID, cVads); + VmmLog(H, MID_VMM, LOGLEVEL_VERBOSE, "BAD #VAD VALUE- PID: %i #VAD: %x", pProcess->dwPID, cVads); cVads = MMVAD_MAXVADS_THRESHOLD; } // 2: allocate and retrieve objects required for processing - if(!(pmObVad = Ob_Alloc(OB_TAG_MAP_VAD, LMEM_ZEROINIT, sizeof(VMMOB_MAP_VAD) + cVads * sizeof(VMM_MAP_VADENTRY), MmVad_MemMapVad_CloseObCallback, NULL))) { goto fail; } + if(!(pmObVad = Ob_AllocEx(H, OB_TAG_MAP_VAD, LMEM_ZEROINIT, sizeof(VMMOB_MAP_VAD) + cVads * sizeof(VMM_MAP_VADENTRY), MmVad_MemMapVad_CloseObCallback, NULL))) { goto fail; } if((cVads == 0) && (pProcess->dwPID != 4)) { // No VADs - VmmLog(MID_VMM, LOGLEVEL_VERBOSE, "NO VAD FOR PROCESS - PID: %i STATE: %i NAME: %s\n", pProcess->dwPID, pProcess->dwState, pProcess->szName); + VmmLog(H, MID_VMM, LOGLEVEL_VERBOSE, "NO VAD FOR PROCESS - PID: %i STATE: %i NAME: %s", pProcess->dwPID, pProcess->dwState, pProcess->szName); pProcess->Map.pObVad = Ob_INCREF(pmObVad); goto fail; } cMax = cVads; - if(!(psObAll = ObSet_New())) { goto fail; } - if(!(psObTry1 = ObSet_New())) { goto fail; } - if(!(psObTry2 = ObSet_New())) { goto fail; } + if(!(psObAll = ObSet_New(H))) { goto fail; } + if(!(psObTry1 = ObSet_New(H))) { goto fail; } + if(!(psObTry2 = ObSet_New(H))) { goto fail; } // 3: retrieve initial VAD node entry - f = ((ctxVmm->kernel.dwVersionBuild >= 6000) && (ctxVmm->kernel.dwVersionBuild < 9600)); // AvlTree (Vista::Win8.0 + f = ((dwVersionBuild >= 6000) && (dwVersionBuild < 9600)); // AvlTree (Vista::Win8.0 for(i = (f ? 1 : 0); i < (f ? 4 : 1); i++) { - va = VMM_EPROCESS_PTR(pProcess, ctxVmm->offset.EPROCESS.VadRoot + i * (ctxVmm->f32 ? 4 : 8)); - if(ctxVmm->f32 && !VMM_KADDR32_8(va)) { continue; } - if(!ctxVmm->f32 && !VMM_KADDR64_16(va)) { continue; } - va -= ctxVmm->f32 ? 8 : 0x10; + va = VMM_EPROCESS_PTR(f32, pProcess, H->vmm.offset.EPROCESS.VadRoot + i * (f32 ? 4 : 8)); + if(f32 && !VMM_KADDR32_8(va)) { continue; } + if(!f32 && !VMM_KADDR64_16(va)) { continue; } + va -= f32 ? 8 : 0x10; ObSet_Push(psObAll, va); ObSet_Push(psObTry2, va); } if(!ObSet_Size(psObTry2)) { goto fail; } - if(ctxVmm->kernel.dwVersionBuild >= 9600) { + if(dwVersionBuild >= 9600) { // Win8.1 and later - pfnMmVad_Spider = ctxVmm->f32 ? MmVad_Spider_MMVAD32_10 : MmVad_Spider_MMVAD64_10; - if(ctxVmm->kernel.dwVersionBuild >= 20348) { // bitmask offset for empty:PrivateMemory:Protection:VadType + pfnMmVad_Spider = f32 ? MmVad_Spider_MMVAD32_10 : MmVad_Spider_MMVAD64_10; + if(dwVersionBuild >= 20348) { // bitmask offset for empty:PrivateMemory:Protection:VadType dwFlagsBitMask = 0x00150704; - } else if(ctxVmm->kernel.dwVersionBuild >= 18362) { + } else if(dwVersionBuild >= 18362) { dwFlagsBitMask = 0x00140704; - } else if(ctxVmm->kernel.dwVersionBuild >= 17134) { + } else if(dwVersionBuild >= 17134) { dwFlagsBitMask = 0x000e0300; } else { dwFlagsBitMask = 0x000f0300; } - } else if(ctxVmm->kernel.dwVersionBuild >= 9200) { + } else if(dwVersionBuild >= 9200) { // Win8.0 - pfnMmVad_Spider = ctxVmm->f32 ? MmVad_Spider_MMVAD32_80 : MmVad_Spider_MMVAD64_80; - } else if(ctxVmm->kernel.dwVersionBuild >= 6000) { + pfnMmVad_Spider = f32 ? MmVad_Spider_MMVAD32_80 : MmVad_Spider_MMVAD64_80; + } else if(dwVersionBuild >= 6000) { // WinVista :: Win7 - pfnMmVad_Spider = ctxVmm->f32 ? MmVad_Spider_MMVAD32_7 : MmVad_Spider_MMVAD64_7; + pfnMmVad_Spider = f32 ? MmVad_Spider_MMVAD32_7 : MmVad_Spider_MMVAD64_7; } else { // WinXP pfnMmVad_Spider = MmVad_Spider_MMVAD32_XP; } // 4: cache: prefetch previous addresses if((psObPrefetch = ObContainer_GetOb(pProcess->pObPersistent->pObCMapVadPrefetch))) { - VmmCachePrefetchPages3(pSystemProcess, psObPrefetch, sizeof(_MMVAD64_10), fVmmRead); + VmmCachePrefetchPages3(H, pSystemProcess, psObPrefetch, sizeof(_MMVAD64_10), fVmmRead); Ob_DECREF_NULL(&psObPrefetch); } - // 5: spider vad tree in an efficient way (minimize non-cached reads) + // 5: Spider VAD tree in an efficient way (minimize non-cached reads). + // NB! Read flags are altered to temporarily disregard no-cache flag. + // It's done to avoid extreme amounts of reads on larger VAD trees. + fVmmReadSpider = fVmmRead; + if(fVmmReadSpider & VMM_FLAG_NOCACHE) { + fVmmReadSpider = (fVmmReadSpider & ~VMM_FLAG_NOCACHE) | VMM_FLAG_CACHE_RECENT_ONLY; + } while((pmObVad->cMap < cMax) && ObSet_Size(psObTry2)) { // fetch vad entries 2nd attempt - VmmCachePrefetchPages3(pSystemProcess, psObTry2, sizeof(_MMVAD64_10), fVmmRead); + VmmCachePrefetchPages3(H, pSystemProcess, psObTry2, sizeof(_MMVAD64_10), fVmmReadSpider); while((pmObVad->cMap < cMax) && (va = ObSet_Pop(psObTry2))) { - if((eVad = pfnMmVad_Spider(pSystemProcess, va, pmObVad, psObAll, psObTry1, NULL, fVmmRead, dwFlagsBitMask))) { + if((eVad = pfnMmVad_Spider(H, pSystemProcess, va, pmObVad, psObAll, psObTry1, NULL, fVmmReadSpider, dwFlagsBitMask))) { if(eVad->CommitCharge > ((eVad->vaEnd + 1 - eVad->vaStart) >> 12)) { eVad->CommitCharge = 0; } - eVad->vaVad = va + (ctxVmm->f32 ? 8 : 0x10); + eVad->vaVad = va + (f32 ? 8 : 0x10); eVad->cbuText = 1; eVad->uszText = ""; if(eVad->cbPrototypePte > 0x01000000) { eVad->cbPrototypePte = MMVAD_PTESIZE * (DWORD)((0x1000 + eVad->vaEnd - eVad->vaStart) >> 12); } @@ -837,9 +830,9 @@ VOID MmVad_Spider_DoWork(_In_ PVMM_PROCESS pSystemProcess, _In_ PVMM_PROCESS pPr } // fetch vad entries 1st attempt while((pmObVad->cMap < cMax) && (va = ObSet_Pop(psObTry1))) { - if((eVad = pfnMmVad_Spider(pSystemProcess, va, pmObVad, psObAll, psObTry1, psObTry2, fVmmRead, dwFlagsBitMask))) { + if((eVad = pfnMmVad_Spider(H, pSystemProcess, va, pmObVad, psObAll, psObTry1, psObTry2, fVmmReadSpider, dwFlagsBitMask))) { if(eVad->CommitCharge > ((eVad->vaEnd + 1 - eVad->vaStart) >> 12)) { eVad->CommitCharge = 0; } - eVad->vaVad = va + (ctxVmm->f32 ? 8 : 0x10); + eVad->vaVad = va + (f32 ? 8 : 0x10); eVad->cbuText = 1; eVad->uszText = ""; if(eVad->cbPrototypePte > 0x01000000) { eVad->cbPrototypePte = MMVAD_PTESIZE * (DWORD)((0x1000 + eVad->vaEnd - eVad->vaStart) >> 12); } @@ -855,7 +848,7 @@ VOID MmVad_Spider_DoWork(_In_ PVMM_PROCESS pSystemProcess, _In_ PVMM_PROCESS pPr // 8: shrink oversized result object (if sufficiently too large) if(pmObVad->cMap + 0x10 < cMax) { pmObVadTemp = pmObVad; - if(!(pmObVad = Ob_Alloc(OB_TAG_MAP_VAD, 0, sizeof(VMMOB_MAP_VAD) + pmObVadTemp->cMap * sizeof(VMM_MAP_VADENTRY), MmVad_MemMapVad_CloseObCallback, NULL))) { goto fail; } + if(!(pmObVad = Ob_AllocEx(H, OB_TAG_MAP_VAD, 0, sizeof(VMMOB_MAP_VAD) + pmObVadTemp->cMap * sizeof(VMM_MAP_VADENTRY), MmVad_MemMapVad_CloseObCallback, NULL))) { goto fail; } memcpy(((POB_DATA)pmObVad)->pb, ((POB_DATA)pmObVadTemp)->pb, pmObVad->ObHdr.cbData); Ob_DECREF_NULL(&pmObVadTemp); } @@ -872,14 +865,16 @@ fail: * pProcess->pObMemMapVad->wszText which will be allocated by the function * and must be free'd upon cleanup of pObMemMapVad. * NB! MUST BE CALLED IN THREAD-SAFE WAY AND MUST NOT HAVE A PREVIOUS BUFFER! +* -- H * -- pSystemProcess * -- pProcess * -- tp = VMM_VADMAP_TP_* * -- fVmmRead */ -VOID MmVad_ExtendedInfoFetch(_In_ PVMM_PROCESS pSystemProcess, _In_ PVMM_PROCESS pProcess, _In_ VMM_VADMAP_TP tp, _In_ QWORD fVmmRead) +VOID MmVad_ExtendedInfoFetch(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ PVMM_PROCESS pProcess, _In_ VMM_VADMAP_TP tp, _In_ QWORD fVmmRead) { - BOOL f, f32 = ctxVmm->f32, fSharedCacheMap = FALSE; + BOOL f, fSharedCacheMap = FALSE, f32 = H->vmm.f32; + DWORD dwVersionBuild = H->vmm.kernel.dwVersionBuild; WORD oControlArea_FilePointer; DWORD cMax, cVads = 0; BYTE pbBuffer[0x60]; @@ -893,13 +888,13 @@ VOID MmVad_ExtendedInfoFetch(_In_ PVMM_PROCESS pSystemProcess, _In_ PVMM_PROCESS POB_STRMAP psmOb = NULL; pVadMap = pProcess->Map.pObVad; if(tp == VMM_VADMAP_TP_FULL) { - if(!(psmOb = ObStrMap_New(0))) { goto cleanup; } + if(!(psmOb = ObStrMap_New(H, 0))) { goto cleanup; } } // count max potential vads and allocate. { for(i = 0, cMax = pVadMap->cMap; i < cMax; i++) { va = pVadMap->pMap[i].vaSubsection; - if(VMM_KADDR_4_8(va)) { + if(VMM_KADDR_4_8(f32, va)) { cVads++; } } @@ -910,41 +905,41 @@ VOID MmVad_ExtendedInfoFetch(_In_ PVMM_PROCESS pSystemProcess, _In_ PVMM_PROCESS { for(i = 0, j = 0, cMax = pVadMap->cMap; (i < cMax) && (j < cVads); i++) { va = pVadMap->pMap[i].vaSubsection; - if(VMM_KADDR_4_8(va)) { + if(VMM_KADDR_4_8(f32, va)) { ppeVads[j] = pVadMap->pMap + i; pva[j++] = va; } } } // fetch subsection -> pointer to control area (1st address ptr in subsection) - if((ctxVmm->kernel.dwVersionBuild >= 6000)) { // Not WinXP (ControlArea already in map subsection field). - VmmCachePrefetchPages4(pSystemProcess, cVads, pva, 8, fVmmRead); + if((dwVersionBuild >= 6000)) { // Not WinXP (ControlArea already in map subsection field). + VmmCachePrefetchPages4(H, pSystemProcess, cVads, pva, 8, fVmmRead); for(i = 0, va = 0; i < cVads; i++) { f = pva[i] && - VmmRead2(pSystemProcess, pva[i], (PBYTE)&va, f32 ? 4 : 8, fVmmRead | VMM_FLAG_FORCECACHE_READ) && - VMM_KADDR_8_16(va); + VmmRead2(H, pSystemProcess, pva[i], (PBYTE)&va, f32 ? 4 : 8, fVmmRead | VMM_FLAG_FORCECACHE_READ) && + VMM_KADDR_8_16(f32, va); pva[i] = f ? (va - 0x10) : 0; } } // fetch _CONTROL_AREA -> pointer to _FILE_OBJECT { - VmmCachePrefetchPages4(pSystemProcess, cVads, pva, 0x50, fVmmRead); + VmmCachePrefetchPages4(H, pSystemProcess, cVads, pva, 0x50, fVmmRead); oControlArea_FilePointer = f32 ? - ((ctxVmm->kernel.dwVersionBuild <= 7601) ? 0x24 : 0x20) : // 32-bit win7sp1- or win8.0+ - ((ctxVmm->kernel.dwVersionBuild <= 6000) ? 0x30 : 0x40); // 64-bit vistasp0- or vistasp1+ + ((dwVersionBuild <= 7601) ? 0x24 : 0x20) : // 32-bit win7sp1- or win8.0+ + ((dwVersionBuild <= 6000) ? 0x30 : 0x40); // 64-bit vistasp0- or vistasp1+ for(i = 0; i < cVads; i++) { // pointer to _FILE_OBJECT f = pva[i] && - VmmRead2(pSystemProcess, pva[i], pbBuffer, sizeof(pbBuffer), fVmmRead | VMM_FLAG_FORCECACHE_READ) && - (VMM_POOLTAG_PREPENDED(pbBuffer, 0x10, 'MmCa') || VMM_POOLTAG_PREPENDED(pbBuffer, 0x10, 'MmCi')) && + VmmRead2(H, pSystemProcess, pva[i], pbBuffer, sizeof(pbBuffer), fVmmRead | VMM_FLAG_FORCECACHE_READ) && + (VMM_POOLTAG_PREPENDED(f32, pbBuffer, 0x10, 'MmCa') || VMM_POOLTAG_PREPENDED(f32, pbBuffer, 0x10, 'MmCi')) && (va = VMM_PTR_OFFSET_EX_FAST_REF(f32, pbBuffer + 0x10, oControlArea_FilePointer)) && - VMM_KADDR_8_16(va); - if(pva[i] && !f && VMM_POOLTAG_PREPENDED(pbBuffer, 0x10, 'MmCa')) { ppeVads[i]->fPageFile = 1; } - if(f && VMM_POOLTAG_PREPENDED(pbBuffer, 0x10, 'MmCa')) { + VMM_KADDR_8_16(f32, va); + if(pva[i] && !f && VMM_POOLTAG_PREPENDED(f32, pbBuffer, 0x10, 'MmCa')) { ppeVads[i]->fPageFile = 1; } + if(f && VMM_POOLTAG_PREPENDED(f32, pbBuffer, 0x10, 'MmCa')) { ppeVads[i]->fFile = 1; ppeVads[i]->vaFileObject = va; } - if(f && VMM_POOLTAG_PREPENDED(pbBuffer, 0x10, 'MmCi')) { + if(f && VMM_POOLTAG_PREPENDED(f32, pbBuffer, 0x10, 'MmCi')) { ppeVads[i]->fImage = 1; ppeVads[i]->vaFileObject = va; } @@ -955,7 +950,7 @@ VOID MmVad_ExtendedInfoFetch(_In_ PVMM_PROCESS pSystemProcess, _In_ PVMM_PROCESS } } // [ page count set ] - if(!pVadMap->cPage && VmmMap_GetPte(pProcess, &pObPteMap, FALSE)) { + if(!pVadMap->cPage && VmmMap_GetPte(H, pProcess, &pObPteMap, FALSE)) { for(i = 0, cMax = pVadMap->cMap; i < cMax; i++) { peVad = &pVadMap->pMap[i]; peVad->cVadExPagesBase = pVadMap->cPage; @@ -973,9 +968,9 @@ VOID MmVad_ExtendedInfoFetch(_In_ PVMM_PROCESS pSystemProcess, _In_ PVMM_PROCESS goto cleanup; } // [ heap map parse ] - if(VmmMap_GetHeap(pProcess, &pObHeapMap)) { + if(VmmMap_GetHeap(H, pProcess, &pObHeapMap)) { for(i = 0; i < pObHeapMap->cSegments; i++) { - if((peVad = VmmMap_GetVadEntry(pVadMap, pObHeapMap->pSegments[i].va))) { + if((peVad = VmmMap_GetVadEntry(H, pVadMap, pObHeapMap->pSegments[i].va))) { peVad->fHeap = 1; peVad->HeapNum = pObHeapMap->pSegments[i].iHeap; if(peVad->cbuText < 2) { @@ -985,15 +980,15 @@ VOID MmVad_ExtendedInfoFetch(_In_ PVMM_PROCESS pSystemProcess, _In_ PVMM_PROCESS } } // [ thread map parse ] - if(VmmMap_GetThread(pProcess, &pObThreadMap)) { + if(VmmMap_GetThread(H, pProcess, &pObThreadMap)) { for(i = 0; i < pObThreadMap->cMap; i++) { - if((peVad = VmmMap_GetVadEntry(pVadMap, pObThreadMap->pMap[i].vaTeb))) { + if((peVad = VmmMap_GetVadEntry(H, pVadMap, pObThreadMap->pMap[i].vaTeb))) { peVad->fTeb = TRUE; if(peVad->cbuText < 2) { ObStrMap_PushUU_snprintf_s(psmOb, &peVad->uszText, &peVad->cbuText, "TEB-%04X", (WORD)min(0xffff, pObThreadMap->pMap[i].dwTID)); } } - if((peVad = VmmMap_GetVadEntry(pVadMap, pObThreadMap->pMap[i].vaStackLimitUser))) { + if((peVad = VmmMap_GetVadEntry(H, pVadMap, pObThreadMap->pMap[i].vaStackLimitUser))) { peVad->fStack = TRUE; if(peVad->cbuText < 2) { ObStrMap_PushUU_snprintf_s(psmOb, &peVad->uszText, &peVad->cbuText, "STACK-%04X", (WORD)min(0xffff, pObThreadMap->pMap[i].dwTID)); @@ -1030,7 +1025,7 @@ BOOL MmVad_PrototypePteArray_FetchNew_PoolHdrVerify(_In_ PBYTE pb, _In_ DWORD cb * -- pVad * -- fVmmRead */ -VOID MmVad_PrototypePteArray_FetchNew(_In_ PVMM_PROCESS pSystemProcess, _In_ PVMM_MAP_VADENTRY pVad, _In_ QWORD fVmmRead) +VOID MmVad_PrototypePteArray_FetchNew(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ PVMM_MAP_VADENTRY pVad, _In_ QWORD fVmmRead) { PBYTE pbData; POB_DATA e = NULL; @@ -1043,29 +1038,29 @@ VOID MmVad_PrototypePteArray_FetchNew(_In_ PVMM_PROCESS pSystemProcess, _In_ PVM } // 2: pool header offset (if any) if(pVad->vaPrototypePte & 0xfff) { - if(ctxVmm->kernel.dwVersionBuild >= 9200) { // WIN8.0 and later - cbDataOffsetPoolHdr = ctxVmm->f32 ? 0x04 : 0x0c; + if(H->vmm.kernel.dwVersionBuild >= 9200) { // WIN8.0 and later + cbDataOffsetPoolHdr = H->vmm.f32 ? 0x04 : 0x0c; } else { // WinXP to Win7 - pool header seems to be varying between these zero and these offsets, check for them all... - cbDataOffsetPoolHdr = ctxVmm->f32 ? 0x34 : 0x5c; + cbDataOffsetPoolHdr = H->vmm.f32 ? 0x34 : 0x5c; if((pVad->vaStart & 0xfff) < cbDataOffsetPoolHdr) { cbDataOffsetPoolHdr = 0; } } cbData += cbDataOffsetPoolHdr; } // 3: fetch prototype page table entries if(!(pbData = LocalAlloc(0, cbData))) { return; } - if(VmmRead2(pSystemProcess, pVad->vaPrototypePte - cbDataOffsetPoolHdr, pbData, cbData, fVmmRead)) { + if(VmmRead2(H, pSystemProcess, pVad->vaPrototypePte - cbDataOffsetPoolHdr, pbData, cbData, fVmmRead)) { if(MmVad_PrototypePteArray_FetchNew_PoolHdrVerify(pbData, cbDataOffsetPoolHdr)) { - if((e = Ob_Alloc('MmSt', 0, sizeof(OB) + cbData - cbDataOffsetPoolHdr, NULL, NULL))) { + if((e = Ob_AllocEx(H, OB_TAG_VAD_MEM, 0, sizeof(OB) + cbData - cbDataOffsetPoolHdr, NULL, NULL))) { memcpy(e->pb, pbData + cbDataOffsetPoolHdr, cbData - cbDataOffsetPoolHdr); } } } if(!e) { - e = Ob_Alloc('MmSt', 0, sizeof(OB), NULL, NULL); + e = Ob_AllocEx(H, OB_TAG_VAD_MEM, 0, sizeof(OB), NULL, NULL); } if(e) { - ObMap_Push(ctxVmm->Cache.pmPrototypePte, pVad->vaPrototypePte, e); + ObMap_Push(H->vmm.Cache.pmPrototypePte, pVad->vaPrototypePte, e); Ob_DECREF(e); } LocalFree(pbData); @@ -1080,7 +1075,7 @@ VOID MmVad_PrototypePteArray_FetchNew(_In_ PVMM_PROCESS pSystemProcess, _In_ PVM * -- fVmmRead * -- return */ -POB_DATA MmVad_PrototypePteArray_Get(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_VADENTRY pVad, _In_ QWORD fVmmRead) +POB_DATA MmVad_PrototypePteArray_Get(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_VADENTRY pVad, _In_ QWORD fVmmRead) { QWORD i, va; POB_DATA e = NULL; @@ -1088,39 +1083,39 @@ POB_DATA MmVad_PrototypePteArray_Get(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_V PVMM_PROCESS pObSystemProcess = NULL; PVMMOB_MAP_VAD pVadMap; if(!pVad->vaPrototypePte || !pVad->cbPrototypePte) { return NULL; } - if((e = ObMap_GetByKey(ctxVmm->Cache.pmPrototypePte, pVad->vaPrototypePte))) { return e; } + if((e = ObMap_GetByKey(H->vmm.Cache.pmPrototypePte, pVad->vaPrototypePte))) { return e; } EnterCriticalSection(&pProcess->LockUpdate); - if((e = ObMap_GetByKey(ctxVmm->Cache.pmPrototypePte, pVad->vaPrototypePte))) { + if((e = ObMap_GetByKey(H->vmm.Cache.pmPrototypePte, pVad->vaPrototypePte))) { LeaveCriticalSection(&pProcess->LockUpdate); return e; } - if((pObSystemProcess = VmmProcessGet(4))) { - if(!pProcess->Map.pObVad->fSpiderPrototypePte && pVad->cbPrototypePte < 0x1000 && (psObPrefetch = ObSet_New())) { + if((pObSystemProcess = VmmProcessGet(H, 4))) { + if(!pProcess->Map.pObVad->fSpiderPrototypePte && pVad->cbPrototypePte < 0x1000 && (psObPrefetch = ObSet_New(H))) { pVadMap = pProcess->Map.pObVad; // spider all prototype pte's less than 0x1000 in size into the cache pVadMap->fSpiderPrototypePte = TRUE; for(i = 0; i < pVadMap->cMap; i++) { va = pVadMap->pMap[i].vaPrototypePte; - if(va && (pVadMap->pMap[i].cbPrototypePte < 0x1000) && !ObMap_ExistsKey(ctxVmm->Cache.pmPrototypePte, va)) { + if(va && (pVadMap->pMap[i].cbPrototypePte < 0x1000) && !ObMap_ExistsKey(H->vmm.Cache.pmPrototypePte, va)) { ObSet_Push(psObPrefetch, va); } } - VmmCachePrefetchPages3(pObSystemProcess, psObPrefetch, 0x1000, fVmmRead); + VmmCachePrefetchPages3(H, pObSystemProcess, psObPrefetch, 0x1000, fVmmRead); for(i = 0; i < pVadMap->cMap; i++) { va = pVadMap->pMap[i].vaPrototypePte; - if(va && (pVadMap->pMap[i].cbPrototypePte < 0x1000) && !ObMap_ExistsKey(ctxVmm->Cache.pmPrototypePte, va)) { - MmVad_PrototypePteArray_FetchNew(pObSystemProcess, pVadMap->pMap + i, fVmmRead | VMM_FLAG_FORCECACHE_READ); + if(va && (pVadMap->pMap[i].cbPrototypePte < 0x1000) && !ObMap_ExistsKey(H->vmm.Cache.pmPrototypePte, va)) { + MmVad_PrototypePteArray_FetchNew(H, pObSystemProcess, pVadMap->pMap + i, fVmmRead | VMM_FLAG_FORCECACHE_READ); } } Ob_DECREF(psObPrefetch); } else { // fetch single vad prototypte pte array into the cache - MmVad_PrototypePteArray_FetchNew(pObSystemProcess, pVad, fVmmRead); + MmVad_PrototypePteArray_FetchNew(H, pObSystemProcess, pVad, fVmmRead); } Ob_DECREF(pObSystemProcess); } LeaveCriticalSection(&pProcess->LockUpdate); - return ObMap_GetByKey(ctxVmm->Cache.pmPrototypePte, pVad->vaPrototypePte); + return ObMap_GetByKey(H->vmm.Cache.pmPrototypePte, pVad->vaPrototypePte); } @@ -1131,20 +1126,21 @@ POB_DATA MmVad_PrototypePteArray_Get(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_V /* * Try to read a prototype page table entry (PTE). +* -- H * -- pProcess * -- va * -- pfInRange -* -- fVmmRead = VMM_FLAGS_* flags. +* -- fVmmRead = VMM_FLAG_* flags. * -- return = prototype pte or zero on fail. */ -QWORD MmVad_PrototypePte(_In_ PVMM_PROCESS pProcess, _In_ QWORD va, _Out_opt_ PBOOL pfInRange, _In_ QWORD fVmmRead) +QWORD MmVad_PrototypePte(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD va, _Out_opt_ PBOOL pfInRange, _In_ QWORD fVmmRead) { QWORD iPrototypePte, qwPrototypePte = 0; POB_DATA pObPteArray = NULL; PVMM_MAP_VADENTRY pVad = NULL; - if(MmVad_MapInitialize(pProcess, FALSE, fVmmRead) && (pVad = VmmMap_GetVadEntry(pProcess->Map.pObVad, va)) && (pObPteArray = MmVad_PrototypePteArray_Get(pProcess, pVad, fVmmRead))) { + if(MmVad_MapInitialize(H, pProcess, VMM_VADMAP_TP_CORE, fVmmRead) && (pVad = VmmMap_GetVadEntry(H, pProcess->Map.pObVad, va)) && (pObPteArray = MmVad_PrototypePteArray_Get(H, pProcess, pVad, fVmmRead))) { iPrototypePte = (va - pVad->vaStart) >> 12; - if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X86) { + if(H->vmm.tpMemoryModel == VMM_MEMORYMODEL_X86) { if(pObPteArray->ObHdr.cbData > (iPrototypePte * 4)) { qwPrototypePte = pObPteArray->pdw[iPrototypePte]; } @@ -1160,15 +1156,17 @@ QWORD MmVad_PrototypePte(_In_ PVMM_PROCESS pProcess, _In_ QWORD va, _Out_opt_ PB } _Success_(return) -BOOL MmVad_MapInitialize_Core(_In_ PVMM_PROCESS pProcess, _In_ QWORD fVmmRead) +BOOL MmVad_MapInitialize_Core(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD fVmmRead) { PVMM_PROCESS pObSystemProcess; if(pProcess->Map.pObVad) { return TRUE; } EnterCriticalSection(&pProcess->LockUpdate); - if(!pProcess->Map.pObVad && (pObSystemProcess = VmmProcessGet(4))) { - MmVad_Spider_DoWork(pObSystemProcess, pProcess, (fVmmRead & ~VMM_FLAG_FORCECACHE_READ) | VMM_FLAG_NOVAD); + if(!pProcess->Map.pObVad && (pObSystemProcess = VmmProcessGet(H, 4))) { + if(pProcess->dwState != 1) { // vads does not exist on terminated processes + MmVad_Spider_DoWork(H, pObSystemProcess, pProcess, (fVmmRead & ~VMM_FLAG_FORCECACHE_READ) | VMM_FLAG_NOVAD); + } if(!pProcess->Map.pObVad) { - pProcess->Map.pObVad = Ob_Alloc(OB_TAG_MAP_VAD, LMEM_ZEROINIT, sizeof(VMMOB_MAP_VAD), MmVad_MemMapVad_CloseObCallback, NULL); + pProcess->Map.pObVad = Ob_AllocEx(H, OB_TAG_MAP_VAD, LMEM_ZEROINIT, sizeof(VMMOB_MAP_VAD), MmVad_MemMapVad_CloseObCallback, NULL); } Ob_DECREF(pObSystemProcess); } @@ -1177,7 +1175,7 @@ BOOL MmVad_MapInitialize_Core(_In_ PVMM_PROCESS pProcess, _In_ QWORD fVmmRead) } _Success_(return) -BOOL MmVad_MapInitialize_ExtendedInfo(_In_ PVMM_PROCESS pProcess, _In_ VMM_VADMAP_TP tp, _In_ QWORD fVmmRead) +BOOL MmVad_MapInitialize_ExtendedInfo(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ VMM_VADMAP_TP tp, _In_ QWORD fVmmRead) { PVMM_PROCESS pObSystemProcess; if(tp <= pProcess->Map.pObVad->tp) { return TRUE; } @@ -1186,8 +1184,8 @@ BOOL MmVad_MapInitialize_ExtendedInfo(_In_ PVMM_PROCESS pProcess, _In_ VMM_VADMA } else { EnterCriticalSection(&pProcess->Map.LockUpdateThreadExtendedInfo); } - if((pProcess->Map.pObVad->tp < tp) && (pObSystemProcess = VmmProcessGet(4))) { - MmVad_ExtendedInfoFetch(pObSystemProcess, pProcess, tp, fVmmRead | VMM_FLAG_NOVAD); + if((pProcess->Map.pObVad->tp < tp) && (pObSystemProcess = VmmProcessGet(H, 4))) { + MmVad_ExtendedInfoFetch(H, pObSystemProcess, pProcess, tp, fVmmRead | VMM_FLAG_NOVAD); Ob_DECREF(pObSystemProcess); } if(tp == VMM_VADMAP_TP_PARTIAL) { @@ -1200,17 +1198,18 @@ BOOL MmVad_MapInitialize_ExtendedInfo(_In_ PVMM_PROCESS pProcess, _In_ VMM_VADMA /* * Initialize / Ensure that a VAD map is initialized for the specific process. +* -- H * -- pProcess * -- tp = VMM_VADMAP_TP_* * -- fVmmRead = VMM_FLAGS_* flags. * -- return */ _Success_(return) -BOOL MmVad_MapInitialize(_In_ PVMM_PROCESS pProcess, _In_ VMM_VADMAP_TP tp, _In_ QWORD fVmmRead) +BOOL MmVad_MapInitialize(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ VMM_VADMAP_TP tp, _In_ QWORD fVmmRead) { if(pProcess->Map.pObVad && (tp <= pProcess->Map.pObVad->tp)) { return TRUE; } - VmmTlbSpider(pProcess); - return MmVad_MapInitialize_Core(pProcess, fVmmRead) && ((tp == VMM_VADMAP_TP_CORE) || MmVad_MapInitialize_ExtendedInfo(pProcess, tp, fVmmRead)); + VmmTlbSpider(H, pProcess); + return MmVad_MapInitialize_Core(H, pProcess, fVmmRead) && ((tp == VMM_VADMAP_TP_CORE) || MmVad_MapInitialize_ExtendedInfo(H, pProcess, tp, fVmmRead)); } /* @@ -1281,6 +1280,7 @@ CHAR MmVadEx_StrType(_In_ VMM_PTE_TP tp) //----------------------------------------------------------------------------- VOID MmVadEx_EntryPrefill( + _In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVMMOB_MAP_PTE pPteMap, _In_ PVMM_MAP_VADENTRY peVad, @@ -1288,14 +1288,14 @@ VOID MmVadEx_EntryPrefill( _In_ DWORD oVadEx, // start offset in # entries from vad base _Inout_count_(cVadEx) PVMM_MAP_VADEXENTRY peVadEx ) { - BOOL fX86 = (ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X86); + BOOL fX86 = (H->vmm.tpMemoryModel == VMM_MEMORYMODEL_X86); DWORD cPteFwd, iePte = 0, iPteCurrent = 0; QWORD va, iVad, iVadEx; PVMM_MAP_VADEXENTRY pe; PVMM_MAP_PTEENTRY pePte = NULL; POB_DATA pObProtoPteArray = NULL; if(!peVad->fPrivateMemory && peVad->vaPrototypePte && peVad->cbPrototypePte) { - pObProtoPteArray = MmVad_PrototypePteArray_Get(pProcess, peVad, 0); + pObProtoPteArray = MmVad_PrototypePteArray_Get(H, pProcess, peVad, 0); } if(peVad->fFile || peVad->fImage) { // FILE or IMAGE VAD @@ -1352,7 +1352,7 @@ VOID MmVadEx_EntryPrefill( pe = peVadEx + iVadEx; pe->peVad = peVad; if(pe->proto.pte) { - ctxVmm->fnMemoryModel.pfnPagedRead(pProcess, pe->va, pe->proto.pte, NULL, &pe->proto.pa, &pe->proto.tp, VMM_FLAG_NOVAD); + H->vmm.fnMemoryModel.pfnPagedRead(H, pProcess, pe->va, pe->proto.pte, NULL, &pe->proto.pa, &pe->proto.tp, VMM_FLAG_NOVAD); } } // cleanup @@ -1381,6 +1381,7 @@ int MmVadEx_VadEntryFind_CmpFind(_In_ QWORD iPage, _In_ QWORD qwEntry) * Initialize / Retrieve an extended VAD map with info about individual pages in * the ranges pecified by the iPage and cPage variables. * CALLER DECREF: return +* -- H * -- pProcess * -- tpVmmVadMap = VMM_VADMAP_TP_* * -- iPage = index of range start in vad map. @@ -1388,7 +1389,7 @@ int MmVadEx_VadEntryFind_CmpFind(_In_ QWORD iPage, _In_ QWORD qwEntry) * -- return */ _Success_(return != NULL) -PVMMOB_MAP_VADEX MmVadEx_MapInitialize(_In_ PVMM_PROCESS pProcess, _In_ VMM_VADMAP_TP tpVmmVadMap, _In_ DWORD iPage, _In_ DWORD cPage) +PVMMOB_MAP_VADEX MmVadEx_MapInitialize(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ VMM_VADMAP_TP tpVmmVadMap, _In_ DWORD iPage, _In_ DWORD cPage) { DWORD iVadEx = 0, iPageCurrent, cPageCurrent; POB_DATA pObProtoPteArray = NULL; @@ -1398,11 +1399,11 @@ PVMMOB_MAP_VADEX MmVadEx_MapInitialize(_In_ PVMM_PROCESS pProcess, _In_ VMM_VADM PVMMOB_MAP_VAD pObVad = NULL; PVMMOB_MAP_VADEX pObVadEx = NULL; // 1: fetch vad map and perform santity checks - if(!VmmMap_GetPte(pProcess, &pObPte, FALSE)) { goto fail; } - if(!VmmMap_GetVad(pProcess, &pObVad, min(VMM_VADMAP_TP_PARTIAL, tpVmmVadMap))) { goto fail; } + if(!VmmMap_GetPte(H, pProcess, &pObPte, FALSE)) { goto fail; } + if(!VmmMap_GetVad(H, pProcess, &pObVad, min(VMM_VADMAP_TP_PARTIAL, tpVmmVadMap))) { goto fail; } cPage = min(cPage, pObVad->cPage - iPage); // 2: alloc extended vad map - pObVadEx = Ob_Alloc(OB_TAG_MAP_VADEX, LMEM_ZEROINIT, sizeof(VMMOB_MAP_VADEX) + cPage * sizeof(VMM_MAP_VADEXENTRY), MmVadEx_CloseObCallback, NULL); + pObVadEx = Ob_AllocEx(H, OB_TAG_MAP_VADEX, LMEM_ZEROINIT, sizeof(VMMOB_MAP_VADEX) + cPage * sizeof(VMM_MAP_VADEXENTRY), MmVadEx_CloseObCallback, NULL); if(!pObVadEx) { goto fail; } pObVadEx->pVadMap = Ob_INCREF(pObVad); pObVadEx->cMap = cPage; @@ -1412,14 +1413,14 @@ PVMMOB_MAP_VADEX MmVadEx_MapInitialize(_In_ PVMM_PROCESS pProcess, _In_ VMM_VADM peVad = Util_qfind((QWORD)iPageCurrent, pObVad->cMap, pObVad->pMap, sizeof(VMM_MAP_VADENTRY), MmVadEx_VadEntryFind_CmpFind); if(!peVad) { goto fail; } cPageCurrent = min(iPage + cPage - iPageCurrent, peVad->cVadExPagesBase + peVad->cVadExPages - iPageCurrent); - MmVadEx_EntryPrefill(pProcess, pObPte, peVad, cPageCurrent, iPageCurrent - peVad->cVadExPagesBase, pObVadEx->pMap + iPageCurrent - iPage); + MmVadEx_EntryPrefill(H, pProcess, pObPte, peVad, cPageCurrent, iPageCurrent - peVad->cVadExPagesBase, pObVadEx->pMap + iPageCurrent - iPage); iPageCurrent += cPageCurrent; } // 4: fill page table information with hardware mappings iVadEx = 0; while(iVadEx < pObVadEx->cMap) { if(pObVadEx->pMap[iVadEx].va) { - ctxVmm->fnMemoryModel.pfnVirt2PhysVadEx(pProcess->paDTB, pObVadEx, -1, &iVadEx); + H->vmm.fnMemoryModel.pfnVirt2PhysVadEx(H, pProcess->paDTB, pObVadEx, -1, &iVadEx); } else { iVadEx++; } @@ -1429,7 +1430,7 @@ PVMMOB_MAP_VADEX MmVadEx_MapInitialize(_In_ PVMM_PROCESS pProcess, _In_ VMM_VADM pex = pObVadEx->pMap + iVadEx; if(pex->tp == VMM_PTE_TP_NA) { if(pex->pte && (pex->iPML == 1)) { - ctxVmm->fnMemoryModel.pfnPagedRead(pProcess, pex->va, pex->pte, NULL, &pex->pa, &pex->tp, VMM_FLAG_NOVAD); + H->vmm.fnMemoryModel.pfnPagedRead(H, pProcess, pex->va, pex->pte, NULL, &pex->pa, &pex->tp, VMM_FLAG_NOVAD); } if(!pex->pte || (pex->iPML != 1) || (pex->tp == VMM_PTE_TP_PROTOTYPE)) { pex->tp = VMM_PTE_TP_PROTOTYPE; diff --git a/vmm/mm_win.c b/vmm/mm_win.c index 189c41e..c4098be 100644 --- a/vmm/mm_win.c +++ b/vmm/mm_win.c @@ -14,27 +14,27 @@ #define MM_LOOP_PROTECT_MAX(flags) (((flags >> 16) & 0xff) > 4) #define PTE_SWIZZLE_BIT 0x10 // nt!_MMPTE_SOFTWARE.SwizzleBit -#define PTE_SWIZZLE_MASK (((PMMWIN_CONTEXT)ctxVmm->pMmContext)->MemCompress.dwInvalidPteMask) +#define PTE_SWIZZLE_MASK (H->vmm.pMmContext->MemCompress.dwInvalidPteMask) #define MMWINX86_PTE_IS_HARDWARE(pte) (pte & 0x01) #define MMWINX86_PTE_TRANSITION(pte) (((pte & 0x0c01) == 0x0800) ? ((pte & 0xfffff000) | 0x005) : 0) #define MMWINX86_PTE_PROTOTYPE(pte) (((pte & 0x00000407) == 0x00000400) ? (0x80000000 | ((pte >> 1) & 0x7ffffc00) | ((pte << 1) & 0x3ff)) : 0) -#define MMWINX86_PTE_PAGE_FILE_NUMBER(pte) ((pte >> 1) & 0x0f) +#define MMWINX86_PTE_PAGE_FILE_NUMBER(H, pte) ((pte >> 1) & 0x0f) #define MMWINX86_PTE_PAGE_FILE_OFFSET(pte) (pte >> 12) #define MMWINX86PAE_PTE_IS_HARDWARE(pte) (pte & 0x01) #define MMWINX86PAE_PTE_TRANSITION(pte) (((pte & 0x0c01) == 0x0800) ? ((pte & 0x0000003ffffff000) | 0x005) : 0) #define MMWINX86PAE_PTE_PROTOTYPE(pte) (((pte & 0x8000000700000401) == 0x8000000000000400) ? (pte >> 32) : 0) -#define MMWINX86PAE_PTE_PAGE_FILE_NUMBER(pte) ((pte >> (((ctxVmm->kernel.dwVersionBuild >= 17134) ? 12 : 1))) & 0x0f) +#define MMWINX86PAE_PTE_PAGE_FILE_NUMBER(H, pte) ((pte >> (((H->vmm.kernel.dwVersionBuild >= 17134) ? 12 : 1))) & 0x0f) #define MMWINX86PAE_PTE_PAGE_FILE_OFFSET(pte) ((pte >> 32) ^ (!(pte & PTE_SWIZZLE_BIT) ? PTE_SWIZZLE_MASK : 0)) -#define MMWINX86PAE_PTE_PAGE_KEY_COMPRESSED(pte) (DWORD)(((MMWINX86PAE_PTE_PAGE_FILE_NUMBER(pte) << 0x1c) | MMWINX86PAE_PTE_PAGE_FILE_OFFSET(pte))) +#define MMWINX86PAE_PTE_PAGE_KEY_COMPRESSED(H, pte) (DWORD)(((MMWINX86PAE_PTE_PAGE_FILE_NUMBER(H, pte) << 0x1c) | MMWINX86PAE_PTE_PAGE_FILE_OFFSET(pte))) #define MMWINX64_PTE_IS_HARDWARE(pte) (pte & 0x01) #define MMWINX64_PTE_TRANSITION(pte) (((pte & 0x0c01) == 0x0800) ? ((pte & 0xffffdffffffff000) | 0x005) : 0) #define MMWINX64_PTE_PROTOTYPE(pte) (((pte & 0x8000000000070401) == 0x8000000000000400) ? ((pte >> 16) | 0xffff000000000000) : 0) -#define MMWINX64_PTE_PAGE_FILE_NUMBER(pte) ((pte >> (((ctxVmm->kernel.dwVersionBuild >= 17134) ? 12 : 1))) & 0x0f) +#define MMWINX64_PTE_PAGE_FILE_NUMBER(H, pte) ((pte >> (((H->vmm.kernel.dwVersionBuild >= 17134) ? 12 : 1))) & 0x0f) #define MMWINX64_PTE_PAGE_FILE_OFFSET(pte) ((pte >> 32) ^ (!(pte & PTE_SWIZZLE_BIT) ? PTE_SWIZZLE_MASK : 0)) -#define MMWINX64_PTE_PAGE_KEY_COMPRESSED(pte) (DWORD)(((MMWINX64_PTE_PAGE_FILE_NUMBER(pte) << 0x1c) | MMWINX64_PTE_PAGE_FILE_OFFSET(pte))) +#define MMWINX64_PTE_PAGE_KEY_COMPRESSED(H, pte) (DWORD)(((MMWINX64_PTE_PAGE_FILE_NUMBER(H, pte) << 0x1c) | MMWINX64_PTE_PAGE_FILE_OFFSET(pte))) typedef struct tdMMWIN_MEMCOMPRESS_OFFSET { BOOL _fValid; @@ -114,10 +114,10 @@ typedef struct td_BTREE64 { } _BTREE64, *P_BTREE64; _Success_(return) -BOOL MmWin_BTree32_Search(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaTree, _In_ DWORD dwKey, _Out_ PDWORD pdwValue, _In_ QWORD fVmmRead); +BOOL MmWin_BTree32_Search(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD vaTree, _In_ DWORD dwKey, _Out_ PDWORD pdwValue, _In_ QWORD fVmmRead); _Success_(return) -BOOL MmWin_BTree64_Search(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaTree, _In_ DWORD dwKey, _Out_ PDWORD pdwValue, _In_ QWORD fVmmRead); +BOOL MmWin_BTree64_Search(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD vaTree, _In_ DWORD dwKey, _Out_ PDWORD pdwValue, _In_ QWORD fVmmRead); _Success_(return) BOOL MmWin_BTree32_SearchLeaf(_In_ PVMM_PROCESS pSystemProcess, _In_ P_BTREE32 pT, _In_ DWORD dwKey, _Out_ PDWORD pdwValue, _In_ QWORD fVmmRead) @@ -187,7 +187,7 @@ BOOL MmWin_BTree64_SearchLeaf(_In_ PVMM_PROCESS pSystemProcess, _In_ P_BTREE64 p } _Success_(return) -BOOL MmWin_BTree32_SearchNode(_In_ PVMM_PROCESS pSystemProcess, _In_ P_BTREE32 pT, _In_ DWORD dwKey, _Out_ PDWORD pdwValue, _In_ QWORD fVmmRead) +BOOL MmWin_BTree32_SearchNode(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ P_BTREE32 pT, _In_ DWORD dwKey, _Out_ PDWORD pdwValue, _In_ QWORD fVmmRead) { BOOL fSearchPreFail = FALSE; DWORD i, dwSearchStep, dwSearchIndex = 1; @@ -207,7 +207,7 @@ BOOL MmWin_BTree32_SearchNode(_In_ PVMM_PROCESS pSystemProcess, _In_ P_BTREE32 p } else { vaSubTree = pT->NodeEntries[dwSearchIndex].vaLeaf; } - return MmWin_BTree32_Search(pSystemProcess, vaSubTree, dwKey, pdwValue, MM_LOOP_PROTECT_ADD(fVmmRead)); + return MmWin_BTree32_Search(H, pSystemProcess, vaSubTree, dwKey, pdwValue, MM_LOOP_PROTECT_ADD(fVmmRead)); } else if(pT->NodeEntries[dwSearchIndex].k < dwKey) { if(dwSearchIndex + dwSearchStep < pT->cEntries) { dwSearchIndex += dwSearchStep; @@ -221,7 +221,7 @@ BOOL MmWin_BTree32_SearchNode(_In_ PVMM_PROCESS pSystemProcess, _In_ P_BTREE32 p } _Success_(return) -BOOL MmWin_BTree64_SearchNode(_In_ PVMM_PROCESS pSystemProcess, _In_ P_BTREE64 pT, _In_ DWORD dwKey, _Out_ PDWORD pdwValue, _In_ QWORD fVmmRead) +BOOL MmWin_BTree64_SearchNode(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ P_BTREE64 pT, _In_ DWORD dwKey, _Out_ PDWORD pdwValue, _In_ QWORD fVmmRead) { BOOL fSearchPreFail = FALSE; DWORD i, dwSearchStep, dwSearchIndex = 1, dwSearchCount = 0; @@ -242,7 +242,7 @@ BOOL MmWin_BTree64_SearchNode(_In_ PVMM_PROCESS pSystemProcess, _In_ P_BTREE64 p } else { vaSubTree = pT->NodeEntries[dwSearchIndex].vaLeaf; } - return MmWin_BTree64_Search(pSystemProcess, vaSubTree, dwKey, pdwValue, MM_LOOP_PROTECT_ADD(fVmmRead)); + return MmWin_BTree64_Search(H, pSystemProcess, vaSubTree, dwKey, pdwValue, MM_LOOP_PROTECT_ADD(fVmmRead)); } else if(pT->NodeEntries[dwSearchIndex].k < dwKey) { if(dwSearchIndex + dwSearchStep < pT->cEntries) { dwSearchIndex += dwSearchStep; @@ -256,7 +256,7 @@ BOOL MmWin_BTree64_SearchNode(_In_ PVMM_PROCESS pSystemProcess, _In_ P_BTREE64 p } _Success_(return) -BOOL MmWin_BTree32_Search(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaTree, _In_ DWORD dwKey, _Out_ PDWORD pdwValue, _In_ QWORD fVmmRead) +BOOL MmWin_BTree32_Search(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD vaTree, _In_ DWORD dwKey, _Out_ PDWORD pdwValue, _In_ QWORD fVmmRead) { BOOL f; BYTE pbBuffer[0x1000]; @@ -264,7 +264,7 @@ BOOL MmWin_BTree32_Search(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaTree, _In_ DW // 1: read tree f = !MM_LOOP_PROTECT_MAX(fVmmRead) && VMM_KADDR32_PAGE(vaTree) && - VmmRead2(pProcess, vaTree, pbBuffer, 0x1000, fVmmRead) && + VmmRead2(H, pProcess, vaTree, pbBuffer, 0x1000, fVmmRead) && pT->cEntries; if(!f) { return FALSE; } if(pT->fLeaf) { @@ -274,12 +274,12 @@ BOOL MmWin_BTree32_Search(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaTree, _In_ DW } else { // Node if(pT->cEntries > 0x1ff) { return FALSE; } - return MmWin_BTree32_SearchNode(pProcess, pT, dwKey, pdwValue, fVmmRead); + return MmWin_BTree32_SearchNode(H, pProcess, pT, dwKey, pdwValue, fVmmRead); } } _Success_(return) -BOOL MmWin_BTree64_Search(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaTree, _In_ DWORD dwKey, _Out_ PDWORD pdwValue, _In_ QWORD fVmmRead) +BOOL MmWin_BTree64_Search(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD vaTree, _In_ DWORD dwKey, _Out_ PDWORD pdwValue, _In_ QWORD fVmmRead) { BOOL f; BYTE pbBuffer[0x1000]; @@ -287,7 +287,7 @@ BOOL MmWin_BTree64_Search(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaTree, _In_ DW // 1: read tree f = !MM_LOOP_PROTECT_MAX(fVmmRead) && VMM_KADDR64_PAGE(vaTree) && - VmmRead2(pProcess, vaTree, pbBuffer, 0x1000, fVmmRead) && + VmmRead2(H, pProcess, vaTree, pbBuffer, 0x1000, fVmmRead) && pT->cEntries; if(!f) { return FALSE; } if(pT->fLeaf) { @@ -297,14 +297,14 @@ BOOL MmWin_BTree64_Search(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaTree, _In_ DW } else { // Node if(pT->cEntries > 0xff) { return FALSE; } - return MmWin_BTree64_SearchNode(pProcess, pT, dwKey, pdwValue, fVmmRead); + return MmWin_BTree64_SearchNode(H, pProcess, pT, dwKey, pdwValue, fVmmRead); } } _Success_(return) -BOOL MmWin_BTree_Search(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaTree, _In_ DWORD dwKey, _Out_ PDWORD pdwValue, _In_ QWORD fVmmRead) +BOOL MmWin_BTree_Search(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD vaTree, _In_ DWORD dwKey, _Out_ PDWORD pdwValue, _In_ QWORD fVmmRead) { - return ctxVmm->f32 ? MmWin_BTree32_Search(pProcess, vaTree, dwKey, pdwValue, fVmmRead) : MmWin_BTree64_Search(pProcess, vaTree, dwKey, pdwValue, fVmmRead); + return H->vmm.f32 ? MmWin_BTree32_Search(H, pProcess, vaTree, dwKey, pdwValue, fVmmRead) : MmWin_BTree64_Search(H, pProcess, vaTree, dwKey, pdwValue, fVmmRead); } @@ -314,10 +314,12 @@ BOOL MmWin_BTree_Search(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaTree, _In_ DWOR /* * Initialize offsets in _SMKM_STORE / _ST_STORE / _ST_DATA_MGR +* -- H */ -VOID MmWin_MemCompress_InitializeOffsets32() +VOID MmWin_MemCompress_InitializeOffsets32(_In_ VMM_HANDLE H) { - PMMWIN_MEMCOMPRESS_OFFSET po = &((PMMWIN_CONTEXT)ctxVmm->pMmContext)->MemCompress.O; + DWORD dwVersionBuild = H->vmm.kernel.dwVersionBuild; + PMMWIN_MEMCOMPRESS_OFFSET po = &H->vmm.pMmContext->MemCompress.O; po->SMKM_STORE.PagesTree = 0x38 + 0x0; // static = ok po->SMKM_STORE.ChunkMetaData = 0x38 + 0x6C; // static = ok po->SMKM_STORE.SmkmStore = 0x38 + 0x1C0; // static = ok @@ -326,15 +328,15 @@ VOID MmWin_MemCompress_InitializeOffsets32() po->SMKM_STORE.CompressionAlgorithm = 0x38 + 0x224; // 1709+ po->SMKM_STORE.CompressedRegionPtrArray = 0x1184; // 1709+ po->SMKM_STORE.OwnerProcess = 0x125c; // 2004+ - if(ctxVmm->kernel.dwVersionBuild <= 18363) { // 1709-1909 + if(dwVersionBuild <= 18363) { // 1709-1909 po->SMKM_STORE.OwnerProcess = 0x1254; } - if(ctxVmm->kernel.dwVersionBuild == 15063) { // 1703 + if(dwVersionBuild == 15063) { // 1703 po->SMKM_STORE.CompressionAlgorithm = 0x38 + 0x220; po->SMKM_STORE.CompressedRegionPtrArray = 0x1174; po->SMKM_STORE.OwnerProcess = 0x1244; } - if(ctxVmm->kernel.dwVersionBuild == 14393) { // 1607 + if(dwVersionBuild == 14393) { // 1607 po->SMKM_STORE.CompressionAlgorithm = 0x38 + 0x220; po->SMKM_STORE.CompressedRegionPtrArray = 0x1124; po->SMKM_STORE.OwnerProcess = 0x1204; @@ -344,9 +346,10 @@ VOID MmWin_MemCompress_InitializeOffsets32() po->_fValid = TRUE; } -VOID MmWin_MemCompress_InitializeOffsets64() +VOID MmWin_MemCompress_InitializeOffsets64(_In_ VMM_HANDLE H) { - PMMWIN_MEMCOMPRESS_OFFSET po = &((PMMWIN_CONTEXT)ctxVmm->pMmContext)->MemCompress.O; + DWORD dwVersionBuild = H->vmm.kernel.dwVersionBuild; + PMMWIN_MEMCOMPRESS_OFFSET po = &H->vmm.pMmContext->MemCompress.O; po->SMKM_STORE.PagesTree = 0x50 + 0x0; // static = ok po->SMKM_STORE.ChunkMetaData = 0x50 + 0xC0; // static = ok po->SMKM_STORE.SmkmStore = 0x50 + 0x320; // static = ok @@ -355,15 +358,15 @@ VOID MmWin_MemCompress_InitializeOffsets64() po->SMKM_STORE.CompressionAlgorithm = 0x50 + 0x3E0; // 1709+ po->SMKM_STORE.CompressedRegionPtrArray = 0x1848; // 1709+ po->SMKM_STORE.OwnerProcess = 0x19B8; // 2004+ - if(ctxVmm->kernel.dwVersionBuild <= 18363) { // 1709-1909 + if(dwVersionBuild <= 18363) { // 1709-1909 po->SMKM_STORE.OwnerProcess = 0x19A8; } - if(ctxVmm->kernel.dwVersionBuild == 15063) { // 1703 + if(dwVersionBuild == 15063) { // 1703 po->SMKM_STORE.CompressionAlgorithm = 0x50 + 0x3D0; po->SMKM_STORE.CompressedRegionPtrArray = 0x1828; po->SMKM_STORE.OwnerProcess = 0x1988; } - if(ctxVmm->kernel.dwVersionBuild == 14393) { // 1607 + if(dwVersionBuild == 14393) { // 1607 po->SMKM_STORE.CompressionAlgorithm = 0x50 + 0x3D0; po->SMKM_STORE.CompressedRegionPtrArray = 0x17A8; po->SMKM_STORE.OwnerProcess = 0x1918; @@ -378,7 +381,7 @@ VOID MmWin_MemCompress_InitializeOffsets64() * on debug symbols. * NB! THIS DOES NOT WORK ON MORE RECENT WINDOWS VERSION (SERVER2022/WIN11). */ -VOID MmWin_MemCompress_InitializeVirtualStorePageFileNumber_Old(_Inout_ PMMWIN_CONTEXT ctx, _In_ PVMM_PROCESS pSystemProcess) +VOID MmWin_MemCompress_InitializeVirtualStorePageFileNumber_Old(_In_ VMM_HANDLE H, _Inout_ PMMWIN_CONTEXT ctx, _In_ PVMM_PROCESS pSystemProcess) { BOOL f; BYTE pbMm[0x100] = { 0 }; @@ -389,20 +392,20 @@ VOID MmWin_MemCompress_InitializeVirtualStorePageFileNumber_Old(_Inout_ PMMWIN_C POB_SET pObSet = NULL; ctx->MemCompress.dwPageFileNumber = 2; // 1: SetUp and locate nt!MiSystemPartition/nt!.data - if(!(pObSet = ObSet_New())) { goto finish; } - if(!PE_SectionGetFromName(pSystemProcess, ctxVmm->kernel.vaBase, ".data", &oSectionHeader)) { - VmmLog(MID_VMM, LOGLEVEL_VERBOSE, "VirtualStorePageFileNumber: CANNOT READ ntoskrnl.exe.data SECTION from PE header"); + if(!(pObSet = ObSet_New(H))) { goto finish; } + if(!PE_SectionGetFromName(H, pSystemProcess, H->vmm.kernel.vaBase, ".data", &oSectionHeader)) { + VmmLog(H, MID_VMM, LOGLEVEL_VERBOSE, "VirtualStorePageFileNumber: CANNOT READ ntoskrnl.exe.data SECTION from PE header"); goto finish; } if(oSectionHeader.Misc.VirtualSize > 0x00100000) { goto finish; } - va = ctxVmm->kernel.vaBase + oSectionHeader.VirtualAddress; + va = H->vmm.kernel.vaBase + oSectionHeader.VirtualAddress; cb = oSectionHeader.Misc.VirtualSize; if(!(pb = LocalAlloc(0, cb))) { goto finish; } - if(!VmmRead(pSystemProcess, va, pb, cb)) { - VmmLog(MID_VMM, LOGLEVEL_VERBOSE, "VirtualStorePageFileNumber: CANNOT READ ntoskrnl.exe .data SECTION.\n"); + if(!VmmRead(H, pSystemProcess, va, pb, cb)) { + VmmLog(H, MID_VMM, LOGLEVEL_VERBOSE, "VirtualStorePageFileNumber: CANNOT READ ntoskrnl.exe .data SECTION.\n"); goto finish; } - if(ctxVmm->f32) { + if(H->vmm.f32) { // 32-bit // 2: Search for candidate pointers for(i = 0; i < cb - 0x90; i += 4) { @@ -445,15 +448,15 @@ VOID MmWin_MemCompress_InitializeVirtualStorePageFileNumber_Old(_Inout_ PMMWIN_C oPfNum = 0xcc; } // 3: Verify nt!dt _MMPAGING_FILE by looking at pool header and VirtualStorePagefile bit - VmmCachePrefetchPages(pSystemProcess, pObSet, 0); + VmmCachePrefetchPages(H, pSystemProcess, pObSet, 0); while((va = ObSet_Pop(pObSet))) { - VmmReadEx(pSystemProcess, va - 0x10, pbMm, 0x100, &cbRead, VMM_FLAG_FORCECACHE_READ); + VmmReadEx(H, pSystemProcess, va - 0x10, pbMm, 0x100, &cbRead, VMM_FLAG_FORCECACHE_READ); if((*(PDWORD)(pbMm + oPoolHdr) == ' mM') && (*(PBYTE)(pbMm + 0x10 + oPfNum) & 0x40)) { ctx->MemCompress.dwPageFileNumber = (*(PBYTE)(pbMm + 0x10 + oPfNum) & 0x0f); goto finish; } } - VmmLog(MID_VMM, LOGLEVEL_VERBOSE, "VirtualStorePageFileNumber: WARN! did not find virtual store number - fallback to default"); + VmmLog(H, MID_VMM, LOGLEVEL_VERBOSE, "VirtualStorePageFileNumber: WARN! did not find virtual store number - fallback to default"); finish: LocalFree(pb); Ob_DECREF(pObSet); @@ -473,44 +476,45 @@ finish: * +0x0cc PageFileNumber : Pos 0, 4 Bits * +0x0cc VirtualStorePagefile : Pos 6, 1 Bit * If this function fails it will automatically fallback to default number 2. +* -- H */ -VOID MmWin_MemCompress_InitializeVirtualStorePageFileNumber() +VOID MmWin_MemCompress_InitializeVirtualStorePageFileNumber(_In_ VMM_HANDLE H) { BOOL f; PVMM_PROCESS pObSystemProcess = NULL; QWORD qw, va, vaMiState, iPfNum; DWORD oMiStateHardware, oMiStateHardwareInvalidPteMask; - PMMWIN_CONTEXT ctx = (PMMWIN_CONTEXT)ctxVmm->pMmContext; + PMMWIN_CONTEXT ctx = H->vmm.pMmContext; DWORD oVp, oPagingFile, oPageFileNumber; POB_SET pObSet = NULL; BYTE pb[16 * sizeof(QWORD)], bFlags; // 1: Prepare - if(!(pObSet = ObSet_New())) { goto finish; } - if(!(pObSystemProcess = VmmProcessGet(4))) { goto finish; } + if(!(pObSet = ObSet_New(H))) { goto finish; } + if(!(pObSystemProcess = VmmProcessGet(H, 4))) { goto finish; } // 2: Set InvalidPteMask - if(ctxVmm->kernel.dwVersionBuild >= 15063) { - f = PDB_GetSymbolAddress(PDB_HANDLE_KERNEL, "MiState", &vaMiState) && - PDB_GetTypeChildOffset(PDB_HANDLE_KERNEL, "_MI_SYSTEM_INFORMATION", "Hardware", &oMiStateHardware) && - PDB_GetTypeChildOffset(PDB_HANDLE_KERNEL, "_MI_HARDWARE_STATE", "InvalidPteMask", &oMiStateHardwareInvalidPteMask) && - VmmRead(pObSystemProcess, vaMiState + oMiStateHardware + oMiStateHardwareInvalidPteMask, (PBYTE)&qw, 8); + if(H->vmm.kernel.dwVersionBuild >= 15063) { + f = PDB_GetSymbolAddress(H, PDB_HANDLE_KERNEL, "MiState", &vaMiState) && + PDB_GetTypeChildOffset(H, PDB_HANDLE_KERNEL, "_MI_SYSTEM_INFORMATION", "Hardware", &oMiStateHardware) && + PDB_GetTypeChildOffset(H, PDB_HANDLE_KERNEL, "_MI_HARDWARE_STATE", "InvalidPteMask", &oMiStateHardwareInvalidPteMask) && + VmmRead(H, pObSystemProcess, vaMiState + oMiStateHardware + oMiStateHardwareInvalidPteMask, (PBYTE)&qw, 8); ctx->MemCompress.dwInvalidPteMask = f ? (qw >> 32) : 0x00002000; // if fail: [0x00002000 = most common on Intel] } // 3: fetch virtual store # via pdb symbols - f = PDB_GetSymbolAddress(PDB_HANDLE_KERNEL, "MiSystemPartition", &va) && - PDB_GetTypeChildOffset(PDB_HANDLE_KERNEL, "_MI_PARTITION", "Vp", &oVp) && - PDB_GetTypeChildOffset(PDB_HANDLE_KERNEL, "_MI_VISIBLE_PARTITION", "PagingFile", &oPagingFile) && - PDB_GetTypeChildOffset(PDB_HANDLE_KERNEL, "_MMPAGING_FILE", "PageFileNumber", &oPageFileNumber) && - VmmRead(pObSystemProcess, va + oVp + oPagingFile, pb, 16 * sizeof(QWORD)); + f = PDB_GetSymbolAddress(H, PDB_HANDLE_KERNEL, "MiSystemPartition", &va) && + PDB_GetTypeChildOffset(H, PDB_HANDLE_KERNEL, "_MI_PARTITION", "Vp", &oVp) && + PDB_GetTypeChildOffset(H, PDB_HANDLE_KERNEL, "_MI_VISIBLE_PARTITION", "PagingFile", &oPagingFile) && + PDB_GetTypeChildOffset(H, PDB_HANDLE_KERNEL, "_MMPAGING_FILE", "PageFileNumber", &oPageFileNumber) && + VmmRead(H, pObSystemProcess, va + oVp + oPagingFile, pb, 16 * sizeof(QWORD)); if(!f) { goto fail; } for(iPfNum = 0; iPfNum < 16; iPfNum++) { - va = ctxVmm->f32 ? *(PDWORD)(pb + iPfNum * 4) : *(PQWORD)(pb + iPfNum * 8); - if(VMM_KADDR_8_16(va)) { + va = H->vmm.f32 ? *(PDWORD)(pb + iPfNum * 4) : *(PQWORD)(pb + iPfNum * 8); + if(VMM_KADDR_8_16(H->vmm.f32, va)) { ObSet_Push(pObSet, va + oPageFileNumber); } } - VmmCachePrefetchPages(pObSystemProcess, pObSet, 0); + VmmCachePrefetchPages(H, pObSystemProcess, pObSet, 0); while((va = ObSet_Pop(pObSet))) { - if(VmmRead2(pObSystemProcess, va, &bFlags, 1, VMM_FLAG_FORCECACHE_READ)) { + if(VmmRead2(H, pObSystemProcess, va, &bFlags, 1, VMM_FLAG_FORCECACHE_READ)) { if(bFlags & 0x40) { ctx->MemCompress.dwPageFileNumber = bFlags & 0x0f; goto finish; @@ -518,7 +522,7 @@ VOID MmWin_MemCompress_InitializeVirtualStorePageFileNumber() } } fail: - MmWin_MemCompress_InitializeVirtualStorePageFileNumber_Old(ctx, pObSystemProcess); + MmWin_MemCompress_InitializeVirtualStorePageFileNumber_Old(H, ctx, pObSystemProcess); finish: Ob_DECREF(pObSystemProcess); Ob_DECREF(pObSet); @@ -533,34 +537,34 @@ finish: * +000 = PTR to SMKM_STORE * +018 = PTR to EPROCESS * SMGLOBALS (_SMKM_STORE_MGR)+1C0 = KeyToStoreTree (B_TREE sGlobalTree) -* -- pSystemProcess +* -- H */ -VOID MmWin_MemCompress_Initialize_NoPdb64() +VOID MmWin_MemCompress_Initialize_NoPdb64(_In_ VMM_HANDLE H) { - BOOL f, f32 = ctxVmm->f32; + BOOL f, f32 = H->vmm.f32; BYTE pbPage[0x1000] = { 0 }; DWORD i, dwSmsaPoolHdr = 0, cbRead; QWORD vaSmGlobals, vaSmsa, vaKeyToStoreTree; IMAGE_SECTION_HEADER oSectionHeader; PVMM_PROCESS pObSystemProcess = NULL; POB_SET pObSet = NULL; - PMMWIN_CONTEXT ctx = (PMMWIN_CONTEXT)ctxVmm->pMmContext; - EnterCriticalSection(&ctxVmm->LockMaster); - if(ctx->MemCompress.fInitialized || (ctxVmm->kernel.dwVersionBuild < 14393)) { goto finish; } + PMMWIN_CONTEXT ctx = H->vmm.pMmContext; + EnterCriticalSection(&H->vmm.LockMaster); + if(ctx->MemCompress.fInitialized || (H->vmm.kernel.dwVersionBuild < 14393)) { goto finish; } // 1: Locate SmGlobals candidates in ntoskrnl.exe!CACHEALI section - if(!(pObSystemProcess = VmmProcessGet(4))) { goto finish; } - if(!(pObSet = ObSet_New())) { goto finish; } - if(!PE_SectionGetFromName(pObSystemProcess, ctxVmm->kernel.vaBase, "CACHEALI", &oSectionHeader)) { - VmmLog(MID_VMM, LOGLEVEL_VERBOSE, "MemCompress_Initialize_NoPdb64: CANNOT READ ntoskrnl.exe CACHEALI SECTION from PE header"); + if(!(pObSystemProcess = VmmProcessGet(H, 4))) { goto finish; } + if(!(pObSet = ObSet_New(H))) { goto finish; } + if(!PE_SectionGetFromName(H, pObSystemProcess, H->vmm.kernel.vaBase, "CACHEALI", &oSectionHeader)) { + VmmLog(H, MID_VMM, LOGLEVEL_VERBOSE, "MemCompress_Initialize_NoPdb64: CANNOT READ ntoskrnl.exe CACHEALI SECTION from PE header"); goto finish; } - if(!VmmRead(pObSystemProcess, ctxVmm->kernel.vaBase + oSectionHeader.VirtualAddress, pbPage, 0x1000)) { - VmmLog(MID_VMM, LOGLEVEL_VERBOSE, "MemCompress_Initialize_NoPdb64: CANNOT READ ntoskrnl.exe CACHEALI SECTION"); + if(!VmmRead(H, pObSystemProcess, H->vmm.kernel.vaBase + oSectionHeader.VirtualAddress, pbPage, 0x1000)) { + VmmLog(H, MID_VMM, LOGLEVEL_VERBOSE, "MemCompress_Initialize_NoPdb64: CANNOT READ ntoskrnl.exe CACHEALI SECTION"); goto finish; } // 2: Verify SMGLOBALS / _SMKM_STORE_METADATA (pool hdr: 'smSa') for(i = 0; i < 0x1000 - 0x1c0 - sizeof(QWORD); i += 8) { - vaSmGlobals = ctxVmm->kernel.vaBase + oSectionHeader.VirtualAddress + i; + vaSmGlobals = H->vmm.kernel.vaBase + oSectionHeader.VirtualAddress + i; vaSmsa = *(PQWORD)(pbPage + i); vaKeyToStoreTree = *(PQWORD)(pbPage + i + 0x1c0); f = VMM_KADDR64_PAGE(vaKeyToStoreTree) && @@ -572,59 +576,59 @@ VOID MmWin_MemCompress_Initialize_NoPdb64() } } // 2: Verify SMGLOBALS / _SMKM_STORE_METADATA (pool hdr: 'smSa') - VmmCachePrefetchPages(pObSystemProcess, pObSet, 0); + VmmCachePrefetchPages(H, pObSystemProcess, pObSet, 0); while(ObSet_Size(pObSet)) { vaSmsa = ObSet_Pop(pObSet); vaKeyToStoreTree = ObSet_Pop(pObSet); vaSmGlobals = ObSet_Pop(pObSet); - VmmReadEx(pObSystemProcess, vaSmsa - 12, (PBYTE)&dwSmsaPoolHdr, sizeof(DWORD), &cbRead, VMM_FLAG_FORCECACHE_READ); + VmmReadEx(H, pObSystemProcess, vaSmsa - 12, (PBYTE)&dwSmsaPoolHdr, sizeof(DWORD), &cbRead, VMM_FLAG_FORCECACHE_READ); if(dwSmsaPoolHdr == 'aSms') { - MmWin_MemCompress_InitializeOffsets64(); + MmWin_MemCompress_InitializeOffsets64(H); ctx->MemCompress.fValid = TRUE; ctx->MemCompress.vaSmGlobals = vaSmGlobals; ctx->MemCompress.vaKeyToStoreTree = vaKeyToStoreTree; - VmmLog(MID_VMM, LOGLEVEL_VERBOSE, "Windows 10 Memory Compression Initialize #1 - SmGlobals located at: %16llx Pf: %i", ctx->MemCompress.vaSmGlobals, ctx->MemCompress.dwPageFileNumber); + VmmLog(H, MID_VMM, LOGLEVEL_VERBOSE, "Windows 10 Memory Compression Initialize #1 - SmGlobals located at: %16llx Pf: %i", ctx->MemCompress.vaSmGlobals, ctx->MemCompress.dwPageFileNumber); break; } } finish: - LeaveCriticalSection(&ctxVmm->LockMaster); + LeaveCriticalSection(&H->vmm.LockMaster); ctx->MemCompress.fInitialized = TRUE; Ob_DECREF(pObSystemProcess); Ob_DECREF(pObSet); } -VOID MmWin_MemCompress_Initialize() +VOID MmWin_MemCompress_Initialize(_In_ VMM_HANDLE H) { DWORD vaKeyToStoreTree32; QWORD vaKeyToStoreTree64; PVMM_PROCESS pObSystemProcess = NULL, pObProcess = NULL; - PMMWIN_CONTEXT ctx = (PMMWIN_CONTEXT)ctxVmm->pMmContext; - if(ctxVmm->kernel.dwVersionMajor < 10) { goto fail; } - MmWin_MemCompress_InitializeVirtualStorePageFileNumber(); + PMMWIN_CONTEXT ctx = H->vmm.pMmContext; + if(H->vmm.kernel.dwVersionMajor < 10) { goto fail; } + MmWin_MemCompress_InitializeVirtualStorePageFileNumber(H); // Retrieve MemCompression process PID and vaEPROCESS - while((pObProcess = VmmProcessGetNext(pObProcess, 0))) { + while((pObProcess = VmmProcessGetNext(H, pObProcess, 0))) { if((pObProcess->dwPPID == 4) && !memcmp("MemCompression", pObProcess->szName, 15)) { ctx->MemCompress.dwPid = pObProcess->dwPID; ctx->MemCompress.vaEPROCESS = pObProcess->win.EPROCESS.va; } } // Retrieve SmGlobals address - if(!PDB_GetSymbolAddress(PDB_HANDLE_KERNEL, "SmGlobals", &ctx->MemCompress.vaSmGlobals)) { - if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X64) { - MmWin_MemCompress_Initialize_NoPdb64(); + if(!PDB_GetSymbolAddress(H, PDB_HANDLE_KERNEL, "SmGlobals", &ctx->MemCompress.vaSmGlobals)) { + if(H->vmm.tpMemoryModel == VMM_MEMORYMODEL_X64) { + MmWin_MemCompress_Initialize_NoPdb64(H); } goto fail; } - if(!(pObSystemProcess = VmmProcessGet(4))) { goto fail; } - if(ctxVmm->f32) { - MmWin_MemCompress_InitializeOffsets32(); - if(!VmmRead(pObSystemProcess, ctx->MemCompress.vaSmGlobals + 0x0f4, (PBYTE)&vaKeyToStoreTree32, sizeof(DWORD))) { goto fail; } + if(!(pObSystemProcess = VmmProcessGet(H, 4))) { goto fail; } + if(H->vmm.f32) { + MmWin_MemCompress_InitializeOffsets32(H); + if(!VmmRead(H, pObSystemProcess, ctx->MemCompress.vaSmGlobals + 0x0f4, (PBYTE)&vaKeyToStoreTree32, sizeof(DWORD))) { goto fail; } if(!VMM_KADDR32_PAGE(vaKeyToStoreTree32)) { goto fail; } ctx->MemCompress.vaKeyToStoreTree = vaKeyToStoreTree32; } else { - MmWin_MemCompress_InitializeOffsets64(); - if(!VmmRead(pObSystemProcess, ctx->MemCompress.vaSmGlobals + 0x1c0, (PBYTE)&vaKeyToStoreTree64, sizeof(QWORD))) { goto fail; } + MmWin_MemCompress_InitializeOffsets64(H); + if(!VmmRead(H, pObSystemProcess, ctx->MemCompress.vaSmGlobals + 0x1c0, (PBYTE)&vaKeyToStoreTree64, sizeof(QWORD))) { goto fail; } if(!VMM_KADDR64_PAGE(vaKeyToStoreTree64)) { goto fail; } ctx->MemCompress.vaKeyToStoreTree = vaKeyToStoreTree64; } @@ -711,16 +715,16 @@ typedef struct td_ST_PAGE_RECORD { DWORD NextKey; } _ST_PAGE_RECORD, *P_ST_PAGE_RECORD; -BOOL MmWin_MemCompress_LogError(_In_ PMMWINX64_COMPRESS_CONTEXT ctx, _In_ LPSTR sz) +BOOL MmWin_MemCompress_LogError(_In_ VMM_HANDLE H, _In_ PMMWINX64_COMPRESS_CONTEXT ctx, _In_ LPSTR sz) { - VmmLog(MID_VMM, LOGLEVEL_DEBUG, "MmWin_CompressedPage: FAIL: %s", sz); - VmmLog(MID_VMM, LOGLEVEL_DEBUG, + VmmLog(H, MID_VMM, LOGLEVEL_DEBUG, "MmWin_CompressedPage: FAIL: %s", sz); + VmmLog(H, MID_VMM, LOGLEVEL_DEBUG, " va= %016llx ep= %016llx pgk=%08x ism=%04x vas=%016llx", ctx->e.va, ctx->e.vaEPROCESS, ctx->e.dwPageKey, ctx->e.iSmkm, ctx->e.vaSmkmStore); - VmmLog(MID_VMM, LOGLEVEL_DEBUG, + VmmLog(H, MID_VMM, LOGLEVEL_DEBUG, " pte=%016llx oep=%016llx rgk=%08x pid=%04x vat=%016llx", - ctx->e.PTE, ctx->e.vaOwnerEPROCESS, ctx->e.dwRegionKey, ctx->pProcess->dwPID, ((PMMWIN_CONTEXT)ctxVmm->pMmContext)->MemCompress.vaKeyToStoreTree); - VmmLog(MID_VMM, LOGLEVEL_DEBUG, + ctx->e.PTE, ctx->e.vaOwnerEPROCESS, ctx->e.dwRegionKey, ctx->pProcess->dwPID, H->vmm.pMmContext->MemCompress.vaKeyToStoreTree); + VmmLog(H, MID_VMM, LOGLEVEL_DEBUG, " pte=%016llx oep=%016llx rgk=%08x pid=%04x vat=%016llx", ctx->e.vaPageRecord, ctx->e.vaRegion, ctx->e.cbRegionOffset, ctx->e.cbCompressedData, (ctx->e.vaRegion + ctx->e.cbRegionOffset)); return FALSE; @@ -730,18 +734,19 @@ BOOL MmWin_MemCompress_LogError(_In_ PMMWINX64_COMPRESS_CONTEXT ctx, _In_ LPSTR * Retrieve the index of the 32x32 array in SmGlobals/SMKM_STORE_METADATA which * points to the SmkmStore. The index is retrieved from the KeyToStoreTree BTree * pointed by SmGlobals/SMKM_STORE_METADATA. +* -- H * -- ctx * -- pwSmkmStoreIndex * -- return */ _Success_(return) -BOOL MmWin_MemCompress1_SmkmStoreIndex(_In_ PMMWINX64_COMPRESS_CONTEXT ctx) +BOOL MmWin_MemCompress1_SmkmStoreIndex(_In_ VMM_HANDLE H, _In_ PMMWINX64_COMPRESS_CONTEXT ctx) { DWORD v; - if(!MmWin_BTree_Search(ctx->pSystemProcess, ((PMMWIN_CONTEXT)ctxVmm->pMmContext)->MemCompress.vaKeyToStoreTree, ctx->e.dwPageKey, &v, ctx->fVmmRead)) { - return MmWin_MemCompress_LogError(ctx, "#11 BTreeSearch"); + if(!MmWin_BTree_Search(H, ctx->pSystemProcess, H->vmm.pMmContext->MemCompress.vaKeyToStoreTree, ctx->e.dwPageKey, &v, ctx->fVmmRead)) { + return MmWin_MemCompress_LogError(H, ctx, "#11 BTreeSearch"); } - if(v & 0x01000000) { return MmWin_MemCompress_LogError(ctx, "#12 InvalidValue"); } + if(v & 0x01000000) { return MmWin_MemCompress_LogError(H, ctx, "#12 InvalidValue"); } ctx->e.iSmkm = 0x3ff & v; return TRUE; } @@ -749,38 +754,39 @@ BOOL MmWin_MemCompress1_SmkmStoreIndex(_In_ PMMWINX64_COMPRESS_CONTEXT ctx) /* * Retrieve the virtual address to the SmkmStore and the EPROCESS of the process * by walking the 32x32 array in SmGlobals. +* -- H * -- ctx * -- return */ _Success_(return) -BOOL MmWin_MemCompress2_SmkmStoreMetadata32(_In_ PMMWINX64_COMPRESS_CONTEXT ctx) +BOOL MmWin_MemCompress2_SmkmStoreMetadata32(_In_ VMM_HANDLE H, _In_ PMMWINX64_COMPRESS_CONTEXT ctx) { DWORD va; _SMKM_STORE_METADATA32 MetaData; // 1: 1st level fetch virtual address to 2nd level of 32x32 array - if(!VmmRead2(ctx->pSystemProcess, ((PMMWIN_CONTEXT)ctxVmm->pMmContext)->MemCompress.vaSmGlobals + (ctx->e.iSmkm >> 5) * sizeof(DWORD), (PBYTE)&va, sizeof(DWORD), ctx->fVmmRead)) { return MmWin_MemCompress_LogError(ctx, "#21 Read"); } - if(!VMM_KADDR32_8(va)) { return MmWin_MemCompress_LogError(ctx, "#22 NoKADDR"); } + if(!VmmRead2(H, ctx->pSystemProcess, H->vmm.pMmContext->MemCompress.vaSmGlobals + (ctx->e.iSmkm >> 5) * sizeof(DWORD), (PBYTE)&va, sizeof(DWORD), ctx->fVmmRead)) { return MmWin_MemCompress_LogError(H, ctx, "#21 Read"); } + if(!VMM_KADDR32_8(va)) { return MmWin_MemCompress_LogError(H, ctx, "#22 NoKADDR"); } // 2: 2nd fetch values (_SMKM_STORE_METADATA) from 2nd level of 32x32 array. - if(!VmmRead2(ctx->pSystemProcess, va + (ctx->e.iSmkm & 0x1f) * sizeof(_SMKM_STORE_METADATA32), (PBYTE)&MetaData, sizeof(_SMKM_STORE_METADATA32), ctx->fVmmRead)) { return MmWin_MemCompress_LogError(ctx, "#23 Read"); } - if(MetaData.vaEPROCESS && !VMM_KADDR32_8(MetaData.vaEPROCESS)) { return MmWin_MemCompress_LogError(ctx, "#24 NoKADDR"); } - if(!VMM_KADDR32_PAGE(MetaData.vaSmkmStore)) { return MmWin_MemCompress_LogError(ctx, "#25 NoKADDR"); } + if(!VmmRead2(H, ctx->pSystemProcess, va + (ctx->e.iSmkm & 0x1f) * sizeof(_SMKM_STORE_METADATA32), (PBYTE)&MetaData, sizeof(_SMKM_STORE_METADATA32), ctx->fVmmRead)) { return MmWin_MemCompress_LogError(H, ctx, "#23 Read"); } + if(MetaData.vaEPROCESS && !VMM_KADDR32_8(MetaData.vaEPROCESS)) { return MmWin_MemCompress_LogError(H, ctx, "#24 NoKADDR"); } + if(!VMM_KADDR32_PAGE(MetaData.vaSmkmStore)) { return MmWin_MemCompress_LogError(H, ctx, "#25 NoKADDR"); } ctx->e.vaSmkmStore = MetaData.vaSmkmStore; ctx->e.vaEPROCESS = MetaData.vaEPROCESS; return TRUE; } _Success_(return) -BOOL MmWin_MemCompress2_SmkmStoreMetadata64(_In_ PMMWINX64_COMPRESS_CONTEXT ctx) +BOOL MmWin_MemCompress2_SmkmStoreMetadata64(_In_ VMM_HANDLE H, _In_ PMMWINX64_COMPRESS_CONTEXT ctx) { QWORD va; _SMKM_STORE_METADATA64 MetaData; // 1: 1st level fetch virtual address to 2nd level of 32x32 array - if(!VmmRead2(ctx->pSystemProcess, ((PMMWIN_CONTEXT)ctxVmm->pMmContext)->MemCompress.vaSmGlobals + (ctx->e.iSmkm >> 5) * sizeof(QWORD), (PBYTE)&va, sizeof(QWORD), ctx->fVmmRead)) { return MmWin_MemCompress_LogError(ctx, "#21 Read"); } - if(!VMM_KADDR64_16(va)) { return MmWin_MemCompress_LogError(ctx, "#22 NoKADDR"); } + if(!VmmRead2(H, ctx->pSystemProcess, H->vmm.pMmContext->MemCompress.vaSmGlobals + (ctx->e.iSmkm >> 5) * sizeof(QWORD), (PBYTE)&va, sizeof(QWORD), ctx->fVmmRead)) { return MmWin_MemCompress_LogError(H, ctx, "#21 Read"); } + if(!VMM_KADDR64_16(va)) { return MmWin_MemCompress_LogError(H, ctx, "#22 NoKADDR"); } // 2: 2nd fetch values (_SMKM_STORE_METADATA) from 2nd level of 32x32 array. - if(!VmmRead2(ctx->pSystemProcess, va + (ctx->e.iSmkm & 0x1f) * sizeof(_SMKM_STORE_METADATA64), (PBYTE)&MetaData, sizeof(_SMKM_STORE_METADATA64), ctx->fVmmRead)) { return MmWin_MemCompress_LogError(ctx, "#23 Read"); } - if(MetaData.vaEPROCESS && !VMM_KADDR64_16(MetaData.vaEPROCESS)) { return MmWin_MemCompress_LogError(ctx, "#24 NoKADDR"); } - if(!VMM_KADDR64_PAGE(MetaData.vaSmkmStore)) { return MmWin_MemCompress_LogError(ctx, "#25 NoKADDR"); } + if(!VmmRead2(H, ctx->pSystemProcess, va + (ctx->e.iSmkm & 0x1f) * sizeof(_SMKM_STORE_METADATA64), (PBYTE)&MetaData, sizeof(_SMKM_STORE_METADATA64), ctx->fVmmRead)) { return MmWin_MemCompress_LogError(H, ctx, "#23 Read"); } + if(MetaData.vaEPROCESS && !VMM_KADDR64_16(MetaData.vaEPROCESS)) { return MmWin_MemCompress_LogError(H, ctx, "#24 NoKADDR"); } + if(!VMM_KADDR64_PAGE(MetaData.vaSmkmStore)) { return MmWin_MemCompress_LogError(H, ctx, "#25 NoKADDR"); } ctx->e.vaSmkmStore = MetaData.vaSmkmStore; ctx->e.vaEPROCESS = MetaData.vaEPROCESS; return TRUE; @@ -788,30 +794,31 @@ BOOL MmWin_MemCompress2_SmkmStoreMetadata64(_In_ PMMWINX64_COMPRESS_CONTEXT ctx) /* * Retrieve the SmkmStore and the PageRecord. +* -- H * -- ctx * -- return */ _Success_(return) -BOOL MmWin_MemCompress3_SmkmStoreAndPageRecord32(_In_ PMMWINX64_COMPRESS_CONTEXT ctx) +BOOL MmWin_MemCompress3_SmkmStoreAndPageRecord32(_In_ VMM_HANDLE H, _In_ PMMWINX64_COMPRESS_CONTEXT ctx) { DWORD vaPageRecordArray; DWORD i, dwEncodedMetadata, iChunkPtr = 0, iChunkArray, dwPoolHdr = 0; P_SMHP_CHUNK_METADATA32 pc; - PMMWIN_MEMCOMPRESS_OFFSET po = &((PMMWIN_CONTEXT)ctxVmm->pMmContext)->MemCompress.O; + PMMWIN_MEMCOMPRESS_OFFSET po = &H->vmm.pMmContext->MemCompress.O; // 1: Load SmkmStore - if(!VmmRead2(ctx->pSystemProcess, ctx->e.vaSmkmStore, ctx->e.pbSmkm, sizeof(ctx->e.pbSmkm), ctx->fVmmRead)) { - return MmWin_MemCompress_LogError(ctx, "#31 ReadSmkmStore"); + if(!VmmRead2(H, ctx->pSystemProcess, ctx->e.vaSmkmStore, ctx->e.pbSmkm, sizeof(ctx->e.pbSmkm), ctx->fVmmRead)) { + return MmWin_MemCompress_LogError(H, ctx, "#31 ReadSmkmStore"); } // 2: Validate if(!VMM_KADDR32_8(*(PDWORD)(ctx->e.pbSmkm + po->SMKM_STORE.PagesTree))) { - return MmWin_MemCompress_LogError(ctx, "#32 PagesTreePtrNoKADDR"); + return MmWin_MemCompress_LogError(H, ctx, "#32 PagesTreePtrNoKADDR"); } if(COMPRESS_ALGORITHM_XPRESS != *(PWORD)(ctx->e.pbSmkm + po->SMKM_STORE.CompressionAlgorithm)) { - return MmWin_MemCompress_LogError(ctx, "#33 InvalidCompressionAlgorithm"); + return MmWin_MemCompress_LogError(H, ctx, "#33 InvalidCompressionAlgorithm"); } // 3: Get region key - if(!MmWin_BTree_Search(ctx->pSystemProcess, *(PDWORD)(ctx->e.pbSmkm + po->SMKM_STORE.PagesTree), ctx->e.dwPageKey, &ctx->e.dwRegionKey, ctx->fVmmRead)) { - return MmWin_MemCompress_LogError(ctx, "#34 RegionKeyBTreeSearch"); + if(!MmWin_BTree_Search(H, ctx->pSystemProcess, *(PDWORD)(ctx->e.pbSmkm + po->SMKM_STORE.PagesTree), ctx->e.dwPageKey, &ctx->e.dwRegionKey, ctx->fVmmRead)) { + return MmWin_MemCompress_LogError(H, ctx, "#34 RegionKeyBTreeSearch"); } // 4: Get page record and calculate: // - chunk "encoded metadata" @@ -826,54 +833,55 @@ BOOL MmWin_MemCompress3_SmkmStoreAndPageRecord32(_In_ PMMWINX64_COMPRESS_CONTEXT iChunkArray = (1 << iChunkPtr) ^ dwEncodedMetadata; // 5: Validate and fetch page record address if(iChunkArray > 0x400) { - return MmWin_MemCompress_LogError(ctx, "#35 ChunkArrayTooLarge"); + return MmWin_MemCompress_LogError(H, ctx, "#35 ChunkArrayTooLarge"); } if(!VMM_KADDR32_8(pc->avaChunkPtr[iChunkPtr])) { - return MmWin_MemCompress_LogError(ctx, "#36 ChunkPtrNoKADDR"); + return MmWin_MemCompress_LogError(H, ctx, "#36 ChunkPtrNoKADDR"); } if(pc->avaChunkPtr[iChunkPtr] & 0xfff) { - if(!VmmRead2(ctx->pSystemProcess, pc->avaChunkPtr[iChunkPtr] - 4, (PBYTE)&dwPoolHdr, 4, ctx->fVmmRead) || (dwPoolHdr != 'ABms')) { - return MmWin_MemCompress_LogError(ctx, "#37 ChunkBadPoolHdr"); + if(!VmmRead2(H, ctx->pSystemProcess, pc->avaChunkPtr[iChunkPtr] - 4, (PBYTE)&dwPoolHdr, 4, ctx->fVmmRead) || (dwPoolHdr != 'ABms')) { + return MmWin_MemCompress_LogError(H, ctx, "#37 ChunkBadPoolHdr"); } } - if(!VmmRead2(ctx->pSystemProcess, pc->avaChunkPtr[iChunkPtr] + 0x0cULL * iChunkArray, (PBYTE)&vaPageRecordArray, sizeof(DWORD), ctx->fVmmRead) || !VMM_KADDR32_PAGE(vaPageRecordArray)) { - return MmWin_MemCompress_LogError(ctx, "#38 PageRecordArray"); + if(!VmmRead2(H, ctx->pSystemProcess, pc->avaChunkPtr[iChunkPtr] + 0x0cULL * iChunkArray, (PBYTE)&vaPageRecordArray, sizeof(DWORD), ctx->fVmmRead) || !VMM_KADDR32_PAGE(vaPageRecordArray)) { + return MmWin_MemCompress_LogError(H, ctx, "#38 PageRecordArray"); } ctx->e.vaPageRecord = (DWORD)((QWORD)vaPageRecordArray + pc->dwChunkPageHeaderSize + ((QWORD)pc->dwPageRecordSize * (ctx->e.dwRegionKey & pc->dwPageRecordsPerChunkMask))); // 6: Get owner EPROCESS ctx->e.vaOwnerEPROCESS = *(PDWORD)(ctx->e.pbSmkm + po->SMKM_STORE.OwnerProcess); - if(ctx->e.vaOwnerEPROCESS != ((PMMWIN_CONTEXT)ctxVmm->pMmContext)->MemCompress.vaEPROCESS) { - return MmWin_MemCompress_LogError(ctx, "#39 OwnerEPROCESS"); + if(ctx->e.vaOwnerEPROCESS != H->vmm.pMmContext->MemCompress.vaEPROCESS) { + return MmWin_MemCompress_LogError(H, ctx, "#39 OwnerEPROCESS"); } return TRUE; } /* * Retrieve the SmkmStore and the PageRecord. +* -- H * -- ctx * -- return */ _Success_(return) -BOOL MmWin_MemCompress3_SmkmStoreAndPageRecord64(_In_ PMMWINX64_COMPRESS_CONTEXT ctx) +BOOL MmWin_MemCompress3_SmkmStoreAndPageRecord64(_In_ VMM_HANDLE H, _In_ PMMWINX64_COMPRESS_CONTEXT ctx) { QWORD vaPageRecordArray; DWORD i, dwEncodedMetadata, iChunkPtr = 0, iChunkArray, dwPoolHdr = 0; P_SMHP_CHUNK_METADATA64 pc; - PMMWIN_MEMCOMPRESS_OFFSET po = &((PMMWIN_CONTEXT)ctxVmm->pMmContext)->MemCompress.O; + PMMWIN_MEMCOMPRESS_OFFSET po = &H->vmm.pMmContext->MemCompress.O; // 1: Load SmkmStore - if(!VmmRead2(ctx->pSystemProcess, ctx->e.vaSmkmStore, ctx->e.pbSmkm, sizeof(ctx->e.pbSmkm), ctx->fVmmRead)) { - return MmWin_MemCompress_LogError(ctx, "#31 ReadSmkmStore"); + if(!VmmRead2(H, ctx->pSystemProcess, ctx->e.vaSmkmStore, ctx->e.pbSmkm, sizeof(ctx->e.pbSmkm), ctx->fVmmRead)) { + return MmWin_MemCompress_LogError(H, ctx, "#31 ReadSmkmStore"); } // 2: Validate if(!VMM_KADDR64_16(*(PQWORD)(ctx->e.pbSmkm + po->SMKM_STORE.PagesTree))) { - return MmWin_MemCompress_LogError(ctx, "#32 PagesTreePtrNoKADDR"); + return MmWin_MemCompress_LogError(H, ctx, "#32 PagesTreePtrNoKADDR"); } if(COMPRESS_ALGORITHM_XPRESS != *(PWORD)(ctx->e.pbSmkm + po->SMKM_STORE.CompressionAlgorithm)) { - return MmWin_MemCompress_LogError(ctx, "#33 InvalidCompressionAlgorithm"); + return MmWin_MemCompress_LogError(H, ctx, "#33 InvalidCompressionAlgorithm"); } // 3: Get region key - if(!MmWin_BTree_Search(ctx->pSystemProcess, *(PQWORD)(ctx->e.pbSmkm + po->SMKM_STORE.PagesTree), ctx->e.dwPageKey, &ctx->e.dwRegionKey, ctx->fVmmRead)) { - return MmWin_MemCompress_LogError(ctx, "#34 RegionKeyBTreeSearch"); + if(!MmWin_BTree_Search(H, ctx->pSystemProcess, *(PQWORD)(ctx->e.pbSmkm + po->SMKM_STORE.PagesTree), ctx->e.dwPageKey, &ctx->e.dwRegionKey, ctx->fVmmRead)) { + return MmWin_MemCompress_LogError(H, ctx, "#34 RegionKeyBTreeSearch"); } // 4: Get page record and calculate: // - chunk "encoded metadata" @@ -888,24 +896,24 @@ BOOL MmWin_MemCompress3_SmkmStoreAndPageRecord64(_In_ PMMWINX64_COMPRESS_CONTEXT iChunkArray = (1 << iChunkPtr) ^ dwEncodedMetadata; // 5: Validate and fetch page record address if(iChunkArray > 0x400) { - return MmWin_MemCompress_LogError(ctx, "#35 ChunkArrayTooLarge"); + return MmWin_MemCompress_LogError(H, ctx, "#35 ChunkArrayTooLarge"); } if(!VMM_KADDR64_16(pc->avaChunkPtr[iChunkPtr])) { - return MmWin_MemCompress_LogError(ctx, "#36 ChunkPtrNoKADDR"); + return MmWin_MemCompress_LogError(H, ctx, "#36 ChunkPtrNoKADDR"); } if(pc->avaChunkPtr[iChunkPtr] & 0xfff) { - if(!VmmRead2(ctx->pSystemProcess, pc->avaChunkPtr[iChunkPtr] - 12, (PBYTE)&dwPoolHdr, 4, ctx->fVmmRead) || (dwPoolHdr != 'ABms')) { - return MmWin_MemCompress_LogError(ctx, "#37 ChunkBadPoolHdr"); + if(!VmmRead2(H, ctx->pSystemProcess, pc->avaChunkPtr[iChunkPtr] - 12, (PBYTE)&dwPoolHdr, 4, ctx->fVmmRead) || (dwPoolHdr != 'ABms')) { + return MmWin_MemCompress_LogError(H, ctx, "#37 ChunkBadPoolHdr"); } } - if(!VmmRead2(ctx->pSystemProcess, pc->avaChunkPtr[iChunkPtr] + 0x10ULL * iChunkArray, (PBYTE)&vaPageRecordArray, sizeof(QWORD), ctx->fVmmRead) || !VMM_KADDR64_PAGE(vaPageRecordArray)) { - return MmWin_MemCompress_LogError(ctx, "#38 PageRecordArray"); + if(!VmmRead2(H, ctx->pSystemProcess, pc->avaChunkPtr[iChunkPtr] + 0x10ULL * iChunkArray, (PBYTE)&vaPageRecordArray, sizeof(QWORD), ctx->fVmmRead) || !VMM_KADDR64_PAGE(vaPageRecordArray)) { + return MmWin_MemCompress_LogError(H, ctx, "#38 PageRecordArray"); } ctx->e.vaPageRecord = (QWORD)(vaPageRecordArray + pc->dwChunkPageHeaderSize + ((QWORD)pc->dwPageRecordSize * (ctx->e.dwRegionKey & pc->dwPageRecordsPerChunkMask))); // 6: Get owner EPROCESS ctx->e.vaOwnerEPROCESS = *(PQWORD)(ctx->e.pbSmkm + po->SMKM_STORE.OwnerProcess); - if(ctx->e.vaOwnerEPROCESS != ((PMMWIN_CONTEXT)ctxVmm->pMmContext)->MemCompress.vaEPROCESS) { - return MmWin_MemCompress_LogError(ctx, "#39 OwnerEPROCESS"); + if(ctx->e.vaOwnerEPROCESS != H->vmm.pMmContext->MemCompress.vaEPROCESS) { + return MmWin_MemCompress_LogError(H, ctx, "#39 OwnerEPROCESS"); } return TRUE; } @@ -916,32 +924,32 @@ BOOL MmWin_MemCompress3_SmkmStoreAndPageRecord64(_In_ PMMWINX64_COMPRESS_CONTEXT * -- return */ _Success_(return) -BOOL MmWin_MemCompress4_CompressedRegionData(_In_ PMMWINX64_COMPRESS_CONTEXT ctx) +BOOL MmWin_MemCompress4_CompressedRegionData(_In_ VMM_HANDLE H, _In_ PMMWINX64_COMPRESS_CONTEXT ctx) { QWORD vaRegionPtr = 0; DWORD dwRegionIndexMask, dwRegionIndex; _ST_PAGE_RECORD PageRecord; - PMMWIN_MEMCOMPRESS_OFFSET po = &((PMMWIN_CONTEXT)ctxVmm->pMmContext)->MemCompress.O; + PMMWIN_MEMCOMPRESS_OFFSET po = &H->vmm.pMmContext->MemCompress.O; // 1: Read page record - if(!VmmRead2(ctx->pSystemProcess, ctx->e.vaPageRecord, (PBYTE)&PageRecord, sizeof(PageRecord), ctx->fVmmRead)) { - return MmWin_MemCompress_LogError(ctx, "#41 ReadPageRecord"); + if(!VmmRead2(H, ctx->pSystemProcess, ctx->e.vaPageRecord, (PBYTE)&PageRecord, sizeof(PageRecord), ctx->fVmmRead)) { + return MmWin_MemCompress_LogError(H, ctx, "#41 ReadPageRecord"); } if(PageRecord.Key == 0xffffffff) { // TODO: implement support - return MmWin_MemCompress_LogError(ctx, "#42 InvalidPageRecord"); + return MmWin_MemCompress_LogError(H, ctx, "#42 InvalidPageRecord"); } ctx->e.cbCompressedData = (PageRecord.CompressedSize == 0x1000) ? 0x1000 : PageRecord.CompressedSize & 0xfff; - if(ctxVmm->f32) { + if(H->vmm.f32) { // 2: Get pointer to region (32-bit) dwRegionIndexMask = *(PDWORD)(ctx->e.pbSmkm + po->SMKM_STORE.RegionIndexMask) & 0xff; dwRegionIndex = PageRecord.Key >> dwRegionIndexMask; vaRegionPtr = *(PDWORD)(ctx->e.pbSmkm + po->SMKM_STORE.CompressedRegionPtrArray) + dwRegionIndex * sizeof(DWORD); // 3: Get region and offset (32-bit) - if(!VmmRead2(ctx->pSystemProcess, vaRegionPtr, (PBYTE)&ctx->e.vaRegion, sizeof(DWORD), ctx->fVmmRead)) { - return MmWin_MemCompress_LogError(ctx, "#43 ReadRegionVA"); + if(!VmmRead2(H, ctx->pSystemProcess, vaRegionPtr, (PBYTE)&ctx->e.vaRegion, sizeof(DWORD), ctx->fVmmRead)) { + return MmWin_MemCompress_LogError(H, ctx, "#43 ReadRegionVA"); } if(!ctx->e.vaRegion || (ctx->e.vaRegion & 0x8000ffff)) { - return MmWin_MemCompress_LogError(ctx, "#44 InvalidRegionVA"); + return MmWin_MemCompress_LogError(H, ctx, "#44 InvalidRegionVA"); } } else { // 2: Get pointer to region (64-bit) @@ -949,11 +957,11 @@ BOOL MmWin_MemCompress4_CompressedRegionData(_In_ PMMWINX64_COMPRESS_CONTEXT ctx dwRegionIndex = PageRecord.Key >> dwRegionIndexMask; vaRegionPtr = *(PQWORD)(ctx->e.pbSmkm + po->SMKM_STORE.CompressedRegionPtrArray) + dwRegionIndex * sizeof(QWORD); // 3: Get region and offset (64-bit) - if(!VmmRead2(ctx->pSystemProcess, vaRegionPtr, (PBYTE)&ctx->e.vaRegion, sizeof(QWORD), ctx->fVmmRead)) { - return MmWin_MemCompress_LogError(ctx, "#45 ReadRegionVA"); + if(!VmmRead2(H, ctx->pSystemProcess, vaRegionPtr, (PBYTE)&ctx->e.vaRegion, sizeof(QWORD), ctx->fVmmRead)) { + return MmWin_MemCompress_LogError(H, ctx, "#45 ReadRegionVA"); } if(!ctx->e.vaRegion || (ctx->e.vaRegion & 0xffff80000000ffff)) { - return MmWin_MemCompress_LogError(ctx, "#46 InvalidRegionVA"); + return MmWin_MemCompress_LogError(H, ctx, "#46 InvalidRegionVA"); } } ctx->e.cbRegionOffset = (PageRecord.Key & *(PDWORD)(ctx->e.pbSmkm + po->SMKM_STORE.RegionSizeMask)) << 4; @@ -967,24 +975,24 @@ BOOL MmWin_MemCompress4_CompressedRegionData(_In_ PMMWINX64_COMPRESS_CONTEXT ctx * -- return */ _Success_(return) -BOOL MmWin_MemCompress5_DecompressPage(_In_ PMMWINX64_COMPRESS_CONTEXT ctx, _Out_writes_(4096) PBYTE pbDecompressedPage) +BOOL MmWin_MemCompress5_DecompressPage(_In_ VMM_HANDLE H, _In_ PMMWINX64_COMPRESS_CONTEXT ctx, _Out_writes_(4096) PBYTE pbDecompressedPage) { DWORD cbDecompressed = 0; NTSTATUS nt = VMM_STATUS_UNSUCCESSFUL; // 1: Read compressed data - if(!VmmRead2(ctx->pProcessMemCompress, ctx->e.vaRegion + ctx->e.cbRegionOffset, ctx->e.pbCompressedData, ctx->e.cbCompressedData, ctx->fVmmRead)) { - MmWin_MemCompress_LogError(ctx, "#51 Read"); + if(!VmmRead2(H, ctx->pProcessMemCompress, ctx->e.vaRegion + ctx->e.cbRegionOffset, ctx->e.pbCompressedData, ctx->e.cbCompressedData, ctx->fVmmRead)) { + MmWin_MemCompress_LogError(H, ctx, "#51 Read"); return FALSE; } // 2: Decompress data if(ctx->e.cbCompressedData == 0x1000) { memcpy(pbDecompressedPage, ctx->e.pbCompressedData, 0x1000); } else { - if(ctxVmm->fn.RtlDecompressBufferOpt) { - nt = ctxVmm->fn.RtlDecompressBufferOpt(COMPRESS_ALGORITHM_XPRESS, pbDecompressedPage, 0x1000, ctx->e.pbCompressedData, ctx->e.cbCompressedData, &cbDecompressed); + if(H->vmm.fn.RtlDecompressBufferOpt) { + nt = H->vmm.fn.RtlDecompressBufferOpt(COMPRESS_ALGORITHM_XPRESS, pbDecompressedPage, 0x1000, ctx->e.pbCompressedData, ctx->e.cbCompressedData, &cbDecompressed); } if((nt != VMM_STATUS_SUCCESS) || (cbDecompressed != 0x1000)) { - MmWin_MemCompress_LogError(ctx, "#52 Decompress"); + MmWin_MemCompress_LogError(H, ctx, "#52 Decompress"); return FALSE; } } @@ -993,6 +1001,7 @@ BOOL MmWin_MemCompress5_DecompressPage(_In_ PMMWINX64_COMPRESS_CONTEXT ctx, _Out /* * Decompress a page. +* -- H * -- pProcess * -- va * -- pte @@ -1001,46 +1010,46 @@ BOOL MmWin_MemCompress5_DecompressPage(_In_ PMMWINX64_COMPRESS_CONTEXT ctx, _Out * -- return */ _Success_(return) -BOOL MmWin_MemCompress(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD va, _In_ QWORD pte, _Out_writes_(4096) PBYTE pbPage, _In_ QWORD fVmmRead) +BOOL MmWin_MemCompress(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ QWORD va, _In_ QWORD pte, _Out_writes_(4096) PBYTE pbPage, _In_ QWORD fVmmRead) { BOOL fResult = FALSE; PMMWINX64_COMPRESS_CONTEXT ctx = NULL; PVMM_PROCESS pObSystemProcess = NULL, pObMemCompressProcess = NULL; - QWORD tm = Statistics_CallStart(); + QWORD tm = Statistics_CallStart(H); if(!(ctx = LocalAlloc(LMEM_ZEROINIT, sizeof(MMWINX64_COMPRESS_CONTEXT)))) { goto fail; } ctx->fVmmRead = fVmmRead; ctx->e.va = va; ctx->e.PTE = pte; - if(ctxVmm->f32) { + if(H->vmm.f32) { // 32-bit system - ctx->e.dwPageKey = MMWINX86PAE_PTE_PAGE_KEY_COMPRESSED(pte); + ctx->e.dwPageKey = MMWINX86PAE_PTE_PAGE_KEY_COMPRESSED(H, pte); fResult = (ctx->pProcess = pProcess) && - (ctx->pSystemProcess = pObSystemProcess = VmmProcessGet(4)) && - (ctx->pProcessMemCompress = pObMemCompressProcess = VmmProcessGet(((PMMWIN_CONTEXT)ctxVmm->pMmContext)->MemCompress.dwPid)) && - MmWin_MemCompress1_SmkmStoreIndex(ctx) && - MmWin_MemCompress2_SmkmStoreMetadata32(ctx) && - MmWin_MemCompress3_SmkmStoreAndPageRecord32(ctx) && - MmWin_MemCompress4_CompressedRegionData(ctx) && - MmWin_MemCompress5_DecompressPage(ctx, pbPage); + (ctx->pSystemProcess = pObSystemProcess = VmmProcessGet(H, 4)) && + (ctx->pProcessMemCompress = pObMemCompressProcess = VmmProcessGet(H, H->vmm.pMmContext->MemCompress.dwPid)) && + MmWin_MemCompress1_SmkmStoreIndex(H, ctx) && + MmWin_MemCompress2_SmkmStoreMetadata32(H, ctx) && + MmWin_MemCompress3_SmkmStoreAndPageRecord32(H, ctx) && + MmWin_MemCompress4_CompressedRegionData(H, ctx) && + MmWin_MemCompress5_DecompressPage(H, ctx, pbPage); } else { // 64-bit system - ctx->e.dwPageKey = MMWINX64_PTE_PAGE_KEY_COMPRESSED(pte); + ctx->e.dwPageKey = MMWINX64_PTE_PAGE_KEY_COMPRESSED(H, pte); fResult = (ctx->pProcess = pProcess) && - (ctx->pSystemProcess = pObSystemProcess = VmmProcessGet(4)) && - (ctx->pProcessMemCompress = pObMemCompressProcess = VmmProcessGet(((PMMWIN_CONTEXT)ctxVmm->pMmContext)->MemCompress.dwPid)) && - MmWin_MemCompress1_SmkmStoreIndex(ctx) && - MmWin_MemCompress2_SmkmStoreMetadata64(ctx) && - MmWin_MemCompress3_SmkmStoreAndPageRecord64(ctx) && - MmWin_MemCompress4_CompressedRegionData(ctx) && - MmWin_MemCompress5_DecompressPage(ctx, pbPage); + (ctx->pSystemProcess = pObSystemProcess = VmmProcessGet(H, 4)) && + (ctx->pProcessMemCompress = pObMemCompressProcess = VmmProcessGet(H, H->vmm.pMmContext->MemCompress.dwPid)) && + MmWin_MemCompress1_SmkmStoreIndex(H, ctx) && + MmWin_MemCompress2_SmkmStoreMetadata64(H, ctx) && + MmWin_MemCompress3_SmkmStoreAndPageRecord64(H, ctx) && + MmWin_MemCompress4_CompressedRegionData(H, ctx) && + MmWin_MemCompress5_DecompressPage(H, ctx, pbPage); } fail: LocalFree(ctx); Ob_DECREF(pObSystemProcess); Ob_DECREF(pObMemCompressProcess); - Statistics_CallEnd(STATISTICS_ID_VMM_PagedCompressedMemory, tm); + Statistics_CallEnd(H, STATISTICS_ID_VMM_PagedCompressedMemory, tm); return fResult; } @@ -1050,9 +1059,9 @@ fail: //----------------------------------------------------------------------------- _Success_(return) -BOOL MmWin_PfReadFile(_In_ DWORD dwPfNumber, _In_ DWORD dwPfOffset, _Out_writes_(4096) PBYTE pbPage) +BOOL MmWin_PfReadFile(_In_ VMM_HANDLE H, _In_ DWORD dwPfNumber, _In_ DWORD dwPfOffset, _Out_writes_(4096) PBYTE pbPage) { - PMMWIN_CONTEXT ctx = (PMMWIN_CONTEXT)ctxVmm->pMmContext; + PMMWIN_CONTEXT ctx = H->vmm.pMmContext; DWORD cb = 0; if(!ctx || !ctx->pPageFile[dwPfNumber]) { return FALSE; } EnterCriticalSection(&ctx->Lock); @@ -1064,52 +1073,52 @@ BOOL MmWin_PfReadFile(_In_ DWORD dwPfNumber, _In_ DWORD dwPfOffset, _Out_writes_ } _Success_(return) -BOOL MmWin_PfRead(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD va, _In_ QWORD pte, _In_ QWORD fVmmRead, _In_ DWORD dwPfNumber, _In_ DWORD dwPfOffset, _Out_writes_(4096) PBYTE pbPage) +BOOL MmWin_PfRead(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ QWORD va, _In_ QWORD pte, _In_ QWORD fVmmRead, _In_ DWORD dwPfNumber, _In_ DWORD dwPfOffset, _Out_writes_(4096) PBYTE pbPage) { BOOL fResult; PVMMOB_CACHE_MEM pObCacheEntry; // cached page? - if((pObCacheEntry = VmmCacheGet(VMM_CACHE_TAG_PAGING, pte))) { + if((pObCacheEntry = VmmCacheGet(H, VMM_CACHE_TAG_PAGING, pte))) { memcpy(pbPage, pObCacheEntry->pb, 0x1000); Ob_DECREF(pObCacheEntry); - InterlockedIncrement64(&ctxVmm->stat.page.cCacheHit); + InterlockedIncrement64(&H->vmm.stat.page.cCacheHit); return TRUE; } // cached failed page? - if(ObSet_Exists(ctxVmm->Cache.PAGING_FAILED, pte)) { - InterlockedIncrement64(&ctxVmm->stat.page.cFailCacheHit); + if(ObSet_Exists(H->vmm.Cache.PAGING_FAILED, pte)) { + InterlockedIncrement64(&H->vmm.stat.page.cFailCacheHit); return FALSE; } // check flags: NoPagingIo, ForceCache and santity checks. if(fVmmRead & (VMM_FLAG_NOPAGING_IO | VMM_FLAG_FORCECACHE_READ)) { return FALSE; } - if(!ctxVmm->pMmContext || (dwPfNumber >= 10)) { return FALSE; } + if(!H->vmm.pMmContext || (dwPfNumber >= 10)) { return FALSE; } // dispatch to page file or compressed virtual store - if(((PMMWIN_CONTEXT)ctxVmm->pMmContext)->MemCompress.fValid && (dwPfNumber == ((PMMWIN_CONTEXT)ctxVmm->pMmContext)->MemCompress.dwPageFileNumber)) { - fResult = MmWin_MemCompress(pProcess, va, pte, pbPage, fVmmRead); + if(H->vmm.pMmContext->MemCompress.fValid && (dwPfNumber == H->vmm.pMmContext->MemCompress.dwPageFileNumber)) { + fResult = MmWin_MemCompress(H, pProcess, va, pte, pbPage, fVmmRead); if(fResult) { - InterlockedIncrement64(&ctxVmm->stat.page.cCompressed); + InterlockedIncrement64(&H->vmm.stat.page.cCompressed); } else { - InterlockedIncrement64(&ctxVmm->stat.page.cFailCompressed); + InterlockedIncrement64(&H->vmm.stat.page.cFailCompressed); } } else { - fResult = MmWin_PfReadFile(dwPfNumber, dwPfOffset, pbPage); + fResult = MmWin_PfReadFile(H, dwPfNumber, dwPfOffset, pbPage); if(fResult) { - InterlockedIncrement64(&ctxVmm->stat.page.cPageFile); + InterlockedIncrement64(&H->vmm.stat.page.cPageFile); } else { - InterlockedIncrement64(&ctxVmm->stat.page.cFailPageFile); + InterlockedIncrement64(&H->vmm.stat.page.cFailPageFile); } } // update cache if(fResult) { - if((pObCacheEntry = VmmCacheReserve(VMM_CACHE_TAG_PAGING))) { + if((pObCacheEntry = VmmCacheReserve(H, VMM_CACHE_TAG_PAGING))) { pObCacheEntry->h.f = TRUE; pObCacheEntry->h.qwA = pte; memcpy(pObCacheEntry->pb, pbPage, 0x1000); - VmmCacheReserveReturn(pObCacheEntry); + VmmCacheReserveReturn(H, pObCacheEntry); } return TRUE; } - ObSet_Push(ctxVmm->Cache.PAGING_FAILED, pte); + ObSet_Push(H->vmm.Cache.PAGING_FAILED, pte); return FALSE; } @@ -1120,27 +1129,25 @@ BOOL MmWin_PfRead(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD va, _In_ QWORD pte, /* * Fetch PTE from a prototype PTE. The returned PTE may be zero = fail, hardware or software PTE. +* -- H * -- pte * -- fVmmRead = flags to VmmRead function calls. * -- return */ -DWORD MmWinX86_Prototype(_In_ DWORD pte, _In_ QWORD fVmmRead) +DWORD MmWinX86_Prototype(_In_ VMM_HANDLE H, _In_ DWORD pte, _In_ QWORD fVmmRead) { - PVMM_PROCESS pObSystemProcess; DWORD cbRead, dwPtePage = 0; - if(!(pObSystemProcess = VmmProcessGet(4))) { goto fail; } - VmmReadEx(pObSystemProcess, MMWINX86_PTE_PROTOTYPE(pte), (PBYTE)&dwPtePage, 4, &cbRead, fVmmRead); - if(cbRead != 4) { goto fail; } - if((MMWINX86_PTE_IS_HARDWARE(dwPtePage) && (dwPtePage >= ctxMain->dev.paMax)) || MMWINX86_PTE_PROTOTYPE(dwPtePage)) { - dwPtePage = 0; + VmmReadEx(H, PVMM_PROCESS_SYSTEM, MMWINX86_PTE_PROTOTYPE(pte), (PBYTE)&dwPtePage, 4, &cbRead, fVmmRead); + if(cbRead != 4) { return 0; } + if((MMWINX86_PTE_IS_HARDWARE(dwPtePage) && (dwPtePage >= H->dev.paMax)) || MMWINX86_PTE_PROTOTYPE(dwPtePage)) { + return 0; } -fail: - Ob_DECREF(pObSystemProcess); return dwPtePage; } /* * Read a 'paged' page from virtual memory. +* -- H * -- pProcess * -- va * -- pte @@ -1150,7 +1157,7 @@ fail: * -- return */ _Success_(return) -BOOL MmWinX86_ReadPaged(_In_ PVMM_PROCESS pProcess, _In_opt_ DWORD va, _In_ DWORD pte, _Out_writes_opt_(4096) PBYTE pbPage, _Out_ PQWORD ppa, _Inout_opt_ PVMM_PTE_TP ptp, _In_ QWORD flags) +BOOL MmWinX86_ReadPaged(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ DWORD va, _In_ DWORD pte, _Out_writes_opt_(4096) PBYTE pbPage, _Out_ PQWORD ppa, _Inout_opt_ PVMM_PTE_TP ptp, _In_ QWORD flags) { BOOL f; DWORD dwPfNumber, dwPfOffset; @@ -1165,8 +1172,8 @@ BOOL MmWinX86_ReadPaged(_In_ PVMM_PROCESS pProcess, _In_opt_ DWORD va, _In_ DWOR // prototype page [ nt!_MMPTE_PROTOTYPE ] if(!(flags & VMM_FLAG_NOPAGING_IO) && MMWINX86_PTE_PROTOTYPE(pte)) { if(ptp && !*ptp) { *ptp = VMM_PTE_TP_PROTOTYPE; } - InterlockedIncrement64(&ctxVmm->stat.page.cPrototype); - pte = MmWinX86_Prototype(pte, flags); + InterlockedIncrement64(&H->vmm.stat.page.cPrototype); + pte = MmWinX86_Prototype(H, pte, flags); if(MMWINX86_PTE_IS_HARDWARE(pte)) { *ppa = pte & 0xfffff000; return FALSE; @@ -1177,28 +1184,28 @@ BOOL MmWinX86_ReadPaged(_In_ PVMM_PROCESS pProcess, _In_opt_ DWORD va, _In_ DWOR if(MMWINX86_PTE_TRANSITION(pte)) { if(ptp && !*ptp) { *ptp = VMM_PTE_TP_TRANSITION; } pte = MMWINX86_PTE_TRANSITION(pte); - if((pte & 0xfffff000) < ctxMain->dev.paMax) { + if((pte & 0xfffff000) < H->dev.paMax) { *ppa = pte & 0xfffff000; - InterlockedIncrement64(&ctxVmm->stat.page.cTransition); + InterlockedIncrement64(&H->vmm.stat.page.cTransition); } return FALSE; } - dwPfNumber = MMWINX86_PTE_PAGE_FILE_NUMBER(pte); + dwPfNumber = MMWINX86_PTE_PAGE_FILE_NUMBER(H, pte); dwPfOffset = MMWINX86_PTE_PAGE_FILE_OFFSET(pte); // Potentially VAD-backed virtual memory if(va && !VMM_KADDR32(va) && !(flags & VMM_FLAG_NOVAD) && (!pte || (dwPfOffset == 0x000fffff))) { - pte = (DWORD)MmVad_PrototypePte(pProcess, va, &f, flags); + pte = (DWORD)MmVad_PrototypePte(H, pProcess, va, &f, flags); if(!pte) { - if(f) { InterlockedIncrement64(&ctxVmm->stat.page.cFailVAD); } + if(f) { InterlockedIncrement64(&H->vmm.stat.page.cFailVAD); } return FALSE; } if(ptp && !*ptp) { *ptp = VMM_PTE_TP_PROTOTYPE; } - InterlockedIncrement64(&ctxVmm->stat.page.cVAD); + InterlockedIncrement64(&H->vmm.stat.page.cVAD); if(MMWINX86_PTE_IS_HARDWARE(pte)) { *ppa = pte & 0xfffff000; return FALSE; } - return MmWinX86_ReadPaged(pProcess, va, pte, pbPage, ppa, NULL, flags | VMM_FLAG_NOVAD); + return MmWinX86_ReadPaged(H, pProcess, va, pte, pbPage, ppa, NULL, flags | VMM_FLAG_NOVAD); } if(!pte) { return FALSE; } // demand zero virtual memory [ nt!_MMPTE_SOFTWARE ] @@ -1206,19 +1213,19 @@ BOOL MmWinX86_ReadPaged(_In_ PVMM_PROCESS pProcess, _In_opt_ DWORD va, _In_ DWOR if(ptp && !*ptp) { *ptp = VMM_PTE_TP_DEMANDZERO; } if(pbPage) { ZeroMemory(pbPage, 0x1000); - InterlockedIncrement64(&ctxVmm->stat.page.cDemandZero); + InterlockedIncrement64(&H->vmm.stat.page.cDemandZero); return TRUE; } return FALSE; } // retrive from page file or compressed store if(ptp && !*ptp) { - *ptp = (((PMMWIN_CONTEXT)ctxVmm->pMmContext)->MemCompress.fValid && (dwPfNumber == ((PMMWIN_CONTEXT)ctxVmm->pMmContext)->MemCompress.dwPageFileNumber)) ? + *ptp = (H->vmm.pMmContext->MemCompress.fValid && (dwPfNumber == H->vmm.pMmContext->MemCompress.dwPageFileNumber)) ? VMM_PTE_TP_COMPRESSED : VMM_PTE_TP_PAGEFILE; } - return pbPage ? MmWin_PfRead(pProcess, va, pte, flags, dwPfNumber, dwPfOffset, pbPage) : FALSE; + return pbPage ? MmWin_PfRead(H, pProcess, va, pte, flags, dwPfNumber, dwPfOffset, pbPage) : FALSE; fail: - InterlockedIncrement64(&ctxVmm->stat.page.cFail); + InterlockedIncrement64(&H->vmm.stat.page.cFail); return FALSE; } @@ -1229,28 +1236,26 @@ fail: /* * Fetch PTE from a prototype PTE. The returned PTE may be zero = fail, hardware or software PTE. +* -- H * -- pte * -- fVmmRead = flags to VmmRead function calls. * -- return */ -QWORD MmWinX86PAE_Prototype(_In_ QWORD pte, _In_ QWORD fVmmRead) +QWORD MmWinX86PAE_Prototype(_In_ VMM_HANDLE H, _In_ QWORD pte, _In_ QWORD fVmmRead) { DWORD cbRead; QWORD qwPtePage = 0; - PVMM_PROCESS pObSystemProcess; - if(!(pObSystemProcess = VmmProcessGet(4))) { goto fail; } - VmmReadEx(pObSystemProcess, MMWINX86PAE_PTE_PROTOTYPE(pte), (PBYTE)&qwPtePage, 8, &cbRead, fVmmRead); - if(cbRead != 8) { goto fail; } - if((MMWINX86PAE_PTE_IS_HARDWARE(qwPtePage) && ((qwPtePage & 0x0000003ffffff000) >= ctxMain->dev.paMax)) || MMWINX86PAE_PTE_PROTOTYPE(qwPtePage)) { - qwPtePage = 0; + VmmReadEx(H, PVMM_PROCESS_SYSTEM, MMWINX86PAE_PTE_PROTOTYPE(pte), (PBYTE)&qwPtePage, 8, &cbRead, fVmmRead); + if(cbRead != 8) { return 0; } + if((MMWINX86PAE_PTE_IS_HARDWARE(qwPtePage) && ((qwPtePage & 0x0000003ffffff000) >= H->dev.paMax)) || MMWINX86PAE_PTE_PROTOTYPE(qwPtePage)) { + return 0; } -fail: - Ob_DECREF(pObSystemProcess); return qwPtePage; } /* * Read a 'paged' page from virtual memory. +* -- H * -- pProcess * -- va * -- pte @@ -1260,7 +1265,7 @@ fail: * -- return */ _Success_(return) -BOOL MmWinX86PAE_ReadPaged(_In_ PVMM_PROCESS pProcess, _In_opt_ DWORD va, _In_ QWORD pte, _Out_writes_opt_(4096) PBYTE pbPage, _Out_ PQWORD ppa, _Inout_opt_ PVMM_PTE_TP ptp, _In_ QWORD flags) +BOOL MmWinX86PAE_ReadPaged(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ DWORD va, _In_ QWORD pte, _Out_writes_opt_(4096) PBYTE pbPage, _Out_ PQWORD ppa, _Inout_opt_ PVMM_PTE_TP ptp, _In_ QWORD flags) { BOOL f; DWORD dwPfNumber, dwPfOffset; @@ -1275,8 +1280,8 @@ BOOL MmWinX86PAE_ReadPaged(_In_ PVMM_PROCESS pProcess, _In_opt_ DWORD va, _In_ Q // prototype page [ nt!_MMPTE_PROTOTYPE ] if(!(flags & VMM_FLAG_NOPAGING_IO) && MMWINX86PAE_PTE_PROTOTYPE(pte)) { if(ptp && !*ptp) { *ptp = VMM_PTE_TP_PROTOTYPE; } - InterlockedIncrement64(&ctxVmm->stat.page.cPrototype); - pte = MmWinX86PAE_Prototype(pte, flags); + InterlockedIncrement64(&H->vmm.stat.page.cPrototype); + pte = MmWinX86PAE_Prototype(H, pte, flags); if(MMWINX86PAE_PTE_IS_HARDWARE(pte)) { *ppa = pte & 0x0000003ffffff000; return FALSE; @@ -1287,28 +1292,28 @@ BOOL MmWinX86PAE_ReadPaged(_In_ PVMM_PROCESS pProcess, _In_opt_ DWORD va, _In_ Q if(MMWINX86PAE_PTE_TRANSITION(pte)) { if(ptp && !*ptp) { *ptp = VMM_PTE_TP_TRANSITION; } pte = MMWINX86PAE_PTE_TRANSITION(pte); - if((pte & 0x0000003ffffff000) < ctxMain->dev.paMax) { + if((pte & 0x0000003ffffff000) < H->dev.paMax) { *ppa = pte & 0x0000003ffffff000; - InterlockedIncrement64(&ctxVmm->stat.page.cTransition); + InterlockedIncrement64(&H->vmm.stat.page.cTransition); } return FALSE; } - dwPfNumber = MMWINX86PAE_PTE_PAGE_FILE_NUMBER(pte); + dwPfNumber = MMWINX86PAE_PTE_PAGE_FILE_NUMBER(H, pte); dwPfOffset = MMWINX86PAE_PTE_PAGE_FILE_OFFSET(pte); // Potentially VAD-backed virtual memory if(va && !VMM_KADDR32(va) && !(flags & VMM_FLAG_NOVAD) && (!pte || (dwPfOffset == 0xffffffff))) { - pte = MmVad_PrototypePte(pProcess, va, &f, flags); + pte = MmVad_PrototypePte(H, pProcess, va, &f, flags); if(!pte) { - if(f) { InterlockedIncrement64(&ctxVmm->stat.page.cFailVAD); } + if(f) { InterlockedIncrement64(&H->vmm.stat.page.cFailVAD); } return FALSE; } if(ptp && !*ptp) { *ptp = VMM_PTE_TP_PROTOTYPE; } - InterlockedIncrement64(&ctxVmm->stat.page.cVAD); + InterlockedIncrement64(&H->vmm.stat.page.cVAD); if(MMWINX86PAE_PTE_IS_HARDWARE(pte)) { *ppa = pte & 0x0000003ffffff000; return FALSE; } - return MmWinX86PAE_ReadPaged(pProcess, va, pte, pbPage, ppa, NULL, flags | VMM_FLAG_NOVAD); + return MmWinX86PAE_ReadPaged(H, pProcess, va, pte, pbPage, ppa, NULL, flags | VMM_FLAG_NOVAD); } if(!pte) { return FALSE; } // demand zero virtual memory [ nt!_MMPTE_SOFTWARE ] @@ -1316,19 +1321,19 @@ BOOL MmWinX86PAE_ReadPaged(_In_ PVMM_PROCESS pProcess, _In_opt_ DWORD va, _In_ Q if(ptp && !*ptp) { *ptp = VMM_PTE_TP_DEMANDZERO; } if(pbPage) { ZeroMemory(pbPage, 0x1000); - InterlockedIncrement64(&ctxVmm->stat.page.cDemandZero); + InterlockedIncrement64(&H->vmm.stat.page.cDemandZero); return TRUE; } return FALSE; } // retrive from page file or compressed store if(ptp && !*ptp) { - *ptp = (((PMMWIN_CONTEXT)ctxVmm->pMmContext)->MemCompress.fValid && (dwPfNumber == ((PMMWIN_CONTEXT)ctxVmm->pMmContext)->MemCompress.dwPageFileNumber)) ? + *ptp = (H->vmm.pMmContext->MemCompress.fValid && (dwPfNumber == H->vmm.pMmContext->MemCompress.dwPageFileNumber)) ? VMM_PTE_TP_COMPRESSED : VMM_PTE_TP_PAGEFILE; } - return pbPage ? MmWin_PfRead(pProcess, va, pte, flags, dwPfNumber, dwPfOffset, pbPage) : FALSE; + return pbPage ? MmWin_PfRead(H, pProcess, va, pte, flags, dwPfNumber, dwPfOffset, pbPage) : FALSE; fail: - InterlockedIncrement64(&ctxVmm->stat.page.cFail); + InterlockedIncrement64(&H->vmm.stat.page.cFail); return FALSE; } @@ -1339,28 +1344,26 @@ fail: /* * Fetch PTE from a prototype PTE. The returned PTE may be zero = fail, hardware or software PTE. +* -- H * -- pte * -- fVmmRead = flags to VmmRead function calls. * -- return */ -QWORD MmWinX64_Prototype(_In_ QWORD pte, _In_ QWORD fVmmRead) +QWORD MmWinX64_Prototype(_In_ VMM_HANDLE H, _In_ QWORD pte, _In_ QWORD fVmmRead) { DWORD cbRead; QWORD qwPtePage = 0; - PVMM_PROCESS pObSystemProcess; - if(!(pObSystemProcess = VmmProcessGet(4))) { goto fail; } - VmmReadEx(pObSystemProcess, MMWINX64_PTE_PROTOTYPE(pte), (PBYTE)&qwPtePage, 8, &cbRead, fVmmRead); - if(cbRead != 8) { goto fail; } - if((MMWINX64_PTE_IS_HARDWARE(qwPtePage) && ((qwPtePage & 0x0000fffffffff000) >= ctxMain->dev.paMax)) || MMWINX64_PTE_PROTOTYPE(qwPtePage)) { - qwPtePage = 0; + VmmReadEx(H, PVMM_PROCESS_SYSTEM, MMWINX64_PTE_PROTOTYPE(pte), (PBYTE)&qwPtePage, 8, &cbRead, fVmmRead); + if(cbRead != 8) { return 0; } + if((MMWINX64_PTE_IS_HARDWARE(qwPtePage) && ((qwPtePage & 0x0000fffffffff000) >= H->dev.paMax)) || MMWINX64_PTE_PROTOTYPE(qwPtePage)) { + return 0; } -fail: - Ob_DECREF(pObSystemProcess); return qwPtePage; } /* * Read a 'paged' page from virtual memory. +* -- H * -- pProcess * -- va * -- pte @@ -1371,7 +1374,7 @@ fail: * -- return */ _Success_(return) -BOOL MmWinX64_ReadPaged(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD va, _In_ QWORD pte, _Out_writes_opt_(4096) PBYTE pbPage, _Out_ PQWORD ppa, _Inout_opt_ PVMM_PTE_TP ptp, _In_ QWORD flags) +BOOL MmWinX64_ReadPaged(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ QWORD va, _In_ QWORD pte, _Out_writes_opt_(4096) PBYTE pbPage, _Out_ PQWORD ppa, _Inout_opt_ PVMM_PTE_TP ptp, _In_ QWORD flags) { BOOL f; DWORD dwPfNumber, dwPfOffset; @@ -1386,8 +1389,8 @@ BOOL MmWinX64_ReadPaged(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD va, _In_ QWOR // prototype page if(!(flags & VMM_FLAG_NOPAGING_IO) && MMWINX64_PTE_PROTOTYPE(pte)) { if(ptp && !*ptp) { *ptp = VMM_PTE_TP_PROTOTYPE; } - InterlockedIncrement64(&ctxVmm->stat.page.cPrototype); - pte = MmWinX64_Prototype(pte, flags); + InterlockedIncrement64(&H->vmm.stat.page.cPrototype); + pte = MmWinX64_Prototype(H, pte, flags); if(MMWINX64_PTE_IS_HARDWARE(pte)) { *ppa = pte & 0x0000fffffffff000; return FALSE; @@ -1398,28 +1401,28 @@ BOOL MmWinX64_ReadPaged(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD va, _In_ QWOR if(MMWINX64_PTE_TRANSITION(pte)) { if(ptp && !*ptp) { *ptp = VMM_PTE_TP_TRANSITION; } pte = MMWINX64_PTE_TRANSITION(pte); - if((pte & 0x0000fffffffff000) < ctxMain->dev.paMax) { + if((pte & 0x0000fffffffff000) < H->dev.paMax) { *ppa = pte & 0x0000fffffffff000; - InterlockedIncrement64(&ctxVmm->stat.page.cTransition); + InterlockedIncrement64(&H->vmm.stat.page.cTransition); } return FALSE; } - dwPfNumber = MMWINX64_PTE_PAGE_FILE_NUMBER(pte); + dwPfNumber = MMWINX64_PTE_PAGE_FILE_NUMBER(H, pte); dwPfOffset = MMWINX64_PTE_PAGE_FILE_OFFSET(pte); // Potentially VAD-backed virtual memory if(va && !VMM_KADDR64(va) && !(flags & VMM_FLAG_NOVAD) && (!pte || (dwPfOffset == 0xffffffff))) { - pte = MmVad_PrototypePte(pProcess, va, &f, flags); + pte = MmVad_PrototypePte(H, pProcess, va, &f, flags); if(!pte) { - if(f) { InterlockedIncrement64(&ctxVmm->stat.page.cFailVAD); } + if(f) { InterlockedIncrement64(&H->vmm.stat.page.cFailVAD); } return FALSE; } if(ptp && !*ptp) { *ptp = VMM_PTE_TP_PROTOTYPE; } - InterlockedIncrement64(&ctxVmm->stat.page.cVAD); + InterlockedIncrement64(&H->vmm.stat.page.cVAD); if(MMWINX64_PTE_IS_HARDWARE(pte)) { *ppa = pte & 0x0000fffffffff000; return FALSE; } - return MmWinX64_ReadPaged(pProcess, va, pte, pbPage, ppa, NULL, flags | VMM_FLAG_NOVAD); + return MmWinX64_ReadPaged(H, pProcess, va, pte, pbPage, ppa, NULL, flags | VMM_FLAG_NOVAD); } if(!pte) { return FALSE; } // demand zero virtual memory [ nt!_MMPTE_SOFTWARE ] @@ -1427,19 +1430,19 @@ BOOL MmWinX64_ReadPaged(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD va, _In_ QWOR if(ptp && !*ptp) { *ptp = VMM_PTE_TP_DEMANDZERO; } if(pbPage) { ZeroMemory(pbPage, 0x1000); - InterlockedIncrement64(&ctxVmm->stat.page.cDemandZero); + InterlockedIncrement64(&H->vmm.stat.page.cDemandZero); return TRUE; } return FALSE; } // retrive from page file or compressed store if(ptp && !*ptp) { - *ptp = (((PMMWIN_CONTEXT)ctxVmm->pMmContext)->MemCompress.fValid && (dwPfNumber == ((PMMWIN_CONTEXT)ctxVmm->pMmContext)->MemCompress.dwPageFileNumber)) ? + *ptp = (H->vmm.pMmContext->MemCompress.fValid && (dwPfNumber == H->vmm.pMmContext->MemCompress.dwPageFileNumber)) ? VMM_PTE_TP_COMPRESSED : VMM_PTE_TP_PAGEFILE; } - return pbPage ? MmWin_PfRead(pProcess, va, pte, flags, dwPfNumber, dwPfOffset, pbPage) : FALSE; + return pbPage ? MmWin_PfRead(H, pProcess, va, pte, flags, dwPfNumber, dwPfOffset, pbPage) : FALSE; fail: - InterlockedIncrement64(&ctxVmm->stat.page.cFail); + InterlockedIncrement64(&H->vmm.stat.page.cFail); return FALSE; } @@ -1448,12 +1451,12 @@ fail: // INITIALIZATION FUNCTIONALITY BELOW: //----------------------------------------------------------------------------- -VOID MmWin_PagingClose() +VOID MmWin_PagingClose(_In_ VMM_HANDLE H) { - PMMWIN_CONTEXT ctx = (PMMWIN_CONTEXT)ctxVmm->pMmContext; + PMMWIN_CONTEXT ctx = H->vmm.pMmContext; DWORD i; if(ctx) { - ctxVmm->pMmContext = NULL; + H->vmm.pMmContext = NULL; for(i = 0; i < 10; i++) { if(ctx->pPageFile[i]) { fclose(ctx->pPageFile[i]); @@ -1463,20 +1466,20 @@ VOID MmWin_PagingClose() } } -VOID MmWin_PagingInitialize(_In_ BOOL fModeFull) +VOID MmWin_PagingInitialize(_In_ VMM_HANDLE H, _In_ BOOL fModeFull) { - PMMWIN_CONTEXT ctx = (PMMWIN_CONTEXT)ctxVmm->pMmContext; + PMMWIN_CONTEXT ctx = H->vmm.pMmContext; DWORD i; // 1: Initialize Paging - switch(ctxVmm->tpMemoryModel) { + switch(H->vmm.tpMemoryModel) { case VMM_MEMORYMODEL_X64: - ctxVmm->fnMemoryModel.pfnPagedRead = MmWinX64_ReadPaged; + H->vmm.fnMemoryModel.pfnPagedRead = MmWinX64_ReadPaged; break; case VMM_MEMORYMODEL_X86PAE: - ctxVmm->fnMemoryModel.pfnPagedRead = (BOOL(*)(PVMM_PROCESS, QWORD, QWORD, PBYTE, PQWORD, PVMM_PTE_TP, QWORD))MmWinX86PAE_ReadPaged; + H->vmm.fnMemoryModel.pfnPagedRead = (BOOL(*)(VMM_HANDLE, PVMM_PROCESS, QWORD, QWORD, PBYTE, PQWORD, PVMM_PTE_TP, QWORD))MmWinX86PAE_ReadPaged; break; case VMM_MEMORYMODEL_X86: - ctxVmm->fnMemoryModel.pfnPagedRead = (BOOL(*)(PVMM_PROCESS, QWORD, QWORD, PBYTE, PQWORD, PVMM_PTE_TP, QWORD))MmWinX86_ReadPaged; + H->vmm.fnMemoryModel.pfnPagedRead = (BOOL(*)(VMM_HANDLE, PVMM_PROCESS, QWORD, QWORD, PBYTE, PQWORD, PVMM_PTE_TP, QWORD))MmWinX86_ReadPaged; break; default: return; @@ -1487,17 +1490,17 @@ VOID MmWin_PagingInitialize(_In_ BOOL fModeFull) if(!ctx) { return; } InitializeCriticalSection(&ctx->Lock); for(i = 0; i < 10; i++) { - if(ctxMain->cfg.szPageFile[i][0]) { - if(fopen_s(&ctx->pPageFile[i], ctxMain->cfg.szPageFile[i], "rb")) { - VmmLog(MID_VMM, LOGLEVEL_VERBOSE, "WARNING: CANNOT OPEN PAGE FILE #%i '%s'", i, ctxMain->cfg.szPageFile[i]); + if(H->cfg.szPageFile[i][0]) { + if(fopen_s(&ctx->pPageFile[i], H->cfg.szPageFile[i], "rb")) { + VmmLog(H, MID_VMM, LOGLEVEL_VERBOSE, "WARNING: CANNOT OPEN PAGE FILE #%i '%s'", i, H->cfg.szPageFile[i]); } else { - VmmLog(MID_VMM, LOGLEVEL_DEBUG, "Successfully opened page file #%i '%s'", i, ctxMain->cfg.szPageFile[i]); + VmmLog(H, MID_VMM, LOGLEVEL_DEBUG, "Successfully opened page file #%i '%s'", i, H->cfg.szPageFile[i]); } } } - ctxVmm->pMmContext = ctx; + H->vmm.pMmContext = ctx; } if(!fModeFull) { return; } // 3: Initialize Memory DeCompression - MmWin_MemCompress_Initialize(); + MmWin_MemCompress_Initialize(H); } diff --git a/vmm/mm_x64.c b/vmm/mm_x64.c index f0833f0..296d597 100644 --- a/vmm/mm_x64.c +++ b/vmm/mm_x64.c @@ -7,21 +7,21 @@ #include "vmmproc.h" #define MMX64_MEMMAP_DISPLAYBUFFER_LINE_LENGTH 89 -#define MMX64_PTE_IS_TRANSITION(pte, iPML) ((((pte & 0x0c01) == 0x0800) && (iPML == 1) && ctxVmm && (ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X64)) ? ((pte & 0xffffdffffffff000) | 0x005) : 0) +#define MMX64_PTE_IS_TRANSITION(H, pte, iPML) ((((pte & 0x0c01) == 0x0800) && (iPML == 1) && (H->vmm.tpSystem == VMM_SYSTEM_WINDOWS_X64)) ? ((pte & 0xffffdffffffff000) | 0x005) : 0) #define MMX64_PTE_IS_VALID(pte, iPML) (pte & 0x01) /* * Tries to verify that a loaded page table is correct. If just a bit strange * bytes/ptes supplied in pb will be altered to look better. */ -BOOL MmX64_TlbPageTableVerify(_Inout_ PBYTE pb, _In_ QWORD pa, _In_ BOOL fSelfRefReq) +BOOL MmX64_TlbPageTableVerify(_In_ VMM_HANDLE H, _Inout_ PBYTE pb, _In_ QWORD pa, _In_ BOOL fSelfRefReq) { DWORD i; QWORD *ptes, c = 0, pte, paMax; BOOL fSelfRef = FALSE; if(!pb) { return FALSE; } ptes = (PQWORD)pb; - paMax = max(0xffffffff, ctxMain->dev.paMax); + paMax = max(0xffffffff, H->dev.paMax); for(i = 0; i < 512; i++) { pte = *(ptes + i); if((pte & 0x01) && ((0x000fffffffffffff & pte) > paMax)) { @@ -30,8 +30,10 @@ BOOL MmX64_TlbPageTableVerify(_Inout_ PBYTE pb, _In_ QWORD pa, _In_ BOOL fSelfRe // we clear this faulty entry. If too may bad PTEs are found this // is most probably not a page table - zero it out but let it // remain in cache to prevent performance degrading reloads... - VmmLog(MID_VMM, LOGLEVEL_DEBUG, "BAD_PTE %016llx at PA: %016llx i: %i", *(ptes + i), pa, i); *(ptes + i) = (QWORD)0; + // avoid counting some special cases which may have plenty of entries. + if(((pte & 0x80ffff000000000f) == 0x800000000000000f)) { continue; } + // count as a bad page - if over threshold -> abort! c++; if(c > 16) { break; } } @@ -40,21 +42,18 @@ BOOL MmX64_TlbPageTableVerify(_Inout_ PBYTE pb, _In_ QWORD pa, _In_ BOOL fSelfRe } } if((c > 16) || (fSelfRefReq && !fSelfRef)) { - if(ctxVmm) { - VmmLog(MID_VMM, LOGLEVEL_DEBUG, "BAD_PT_PAGE at PA: %016llx", pa); - } ZeroMemory(pb, 4096); return FALSE; } return TRUE; } -VOID MmX64_TlbSpider_Stage(_In_ QWORD pa, _In_ BYTE iPML, _In_ BOOL fUserOnly, _In_ POB_SET pPageSet) +VOID MmX64_TlbSpider_Stage(_In_ VMM_HANDLE H, _In_ QWORD pa, _In_ BYTE iPML, _In_ BOOL fUserOnly, _In_ POB_SET pPageSet) { QWORD i, pe; PVMMOB_CACHE_MEM ptObMEM = NULL; // 1: retrieve from cache, add to staging if not found - ptObMEM = VmmCacheGet(VMM_CACHE_TAG_TLB, pa); + ptObMEM = VmmCacheGet(H, VMM_CACHE_TAG_TLB, pa); if(!ptObMEM) { ObSet_Push(pPageSet, pa); return; @@ -69,7 +68,7 @@ VOID MmX64_TlbSpider_Stage(_In_ QWORD pa, _In_ BYTE iPML, _In_ BOOL fUserOnly, _ if(!(pe & 0x01)) { continue; } // not valid if(pe & 0x80) { continue; } // not valid ptr to (PDPT || PD || PT) if(fUserOnly && !(pe & 0x04)) { continue; } // supervisor page when fUserOnly -> not valid - MmX64_TlbSpider_Stage(pe & 0x0000fffffffff000, iPML - 1, fUserOnly, pPageSet); + MmX64_TlbSpider_Stage(H, pe & 0x0000fffffffff000, iPML - 1, fUserOnly, pPageSet); } Ob_DECREF(ptObMEM); } @@ -77,17 +76,19 @@ VOID MmX64_TlbSpider_Stage(_In_ QWORD pa, _In_ BYTE iPML, _In_ BOOL fUserOnly, _ /* * Iterate over PML4, PTPT, PD (3 times in total) to first stage uncached pages * and then commit them to the cache. +* -- H +* -- pProcess */ -VOID MmX64_TlbSpider(_In_ PVMM_PROCESS pProcess) +VOID MmX64_TlbSpider(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess) { DWORD i; POB_SET pObPageSet = NULL; if(pProcess->fTlbSpiderDone) { return; } - if(!(pObPageSet = ObSet_New())) { return; } - Ob_DECREF(VmmTlbGetPageTable(pProcess->paDTB, FALSE)); + if(!(pObPageSet = ObSet_New(H))) { return; } + Ob_DECREF(VmmTlbGetPageTable(H, pProcess->paDTB, FALSE)); for(i = 0; i < 3; i++) { - MmX64_TlbSpider_Stage(pProcess->paDTB, 4, pProcess->fUserOnly, pObPageSet); - VmmTlbPrefetch(pObPageSet); + MmX64_TlbSpider_Stage(H, pProcess->paDTB, 4, pProcess->fUserOnly, pObPageSet); + VmmTlbPrefetch(H, pObPageSet); } pProcess->fTlbSpiderDone = TRUE; Ob_DECREF(pObPageSet); @@ -97,14 +98,14 @@ const QWORD MMX64_PAGETABLEMAP_PML_REGION_SIZE[5] = { 0, 12, 21, 30, 39 }; const QWORD MMX64_PAGETABLEMAP_PML_REGION_MASK_PG[5] = { 0, 0x0000fffffffff000, 0x0000ffffffe00000, 0x0000ffffc0000000, 0 }; const QWORD MMX64_PAGETABLEMAP_PML_REGION_MASK_AD[5] = { 0, 0xfff, 0x1fffff, 0x3fffffff, 0 }; -VOID MmX64_MapInitialize_Index(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_PTEENTRY pMemMap, _In_ PDWORD pcMemMap, _In_ QWORD vaBase, _In_ BYTE iPML, _In_ QWORD PTEs[512], _In_ BOOL fSupervisorPML, _In_ QWORD paMax) +VOID MmX64_MapInitialize_Index(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_PTEENTRY pMemMap, _In_ PDWORD pcMemMap, _In_ QWORD vaBase, _In_ BYTE iPML, _In_ QWORD PTEs[512], _In_ BOOL fSupervisorPML, _In_ QWORD paMax) { PVMMOB_CACHE_MEM pObNextPT; QWORD i, pte, va, cPages; BOOL fUserOnly, fNextSupervisorPML, fPagedOut = FALSE; PVMM_MAP_PTEENTRY pMemMapEntry = pMemMap + *pcMemMap - 1; if(!pProcess->fTlbSpiderDone) { - VmmTlbSpider(pProcess); + VmmTlbSpider(H, pProcess); } fUserOnly = pProcess->fUserOnly; for(i = 0; i < 512; i++) { @@ -112,7 +113,7 @@ VOID MmX64_MapInitialize_Index(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_PTEENTR if(!MMX64_PTE_IS_VALID(pte, iPML)) { if(!pte) { continue; } if(iPML != 1) { continue; } - pte = MMX64_PTE_IS_TRANSITION(pte, iPML); + pte = MMX64_PTE_IS_TRANSITION(H, pte, iPML); pte = 0x8000000000000005 | (pte ? (pte & 0x8000fffffffff000 ) : 0); // GUESS READ-ONLY USER PAGE IF NON TRANSITION fPagedOut = TRUE; } else { @@ -153,9 +154,9 @@ VOID MmX64_MapInitialize_Index(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_PTEENTR } // maps page table (PDPT, PD, PT) fNextSupervisorPML = !(pte & 0x04); - pObNextPT = VmmTlbGetPageTable(pte & 0x0000fffffffff000, FALSE); + pObNextPT = VmmTlbGetPageTable(H, pte & 0x0000fffffffff000, FALSE); if(!pObNextPT) { continue; } - MmX64_MapInitialize_Index(pProcess, pMemMap, pcMemMap, va, iPML - 1, pObNextPT->pqw, fNextSupervisorPML, paMax); + MmX64_MapInitialize_Index(H, pProcess, pMemMap, pcMemMap, va, iPML - 1, pObNextPT->pqw, fNextSupervisorPML, paMax); Ob_DECREF(pObNextPT); pMemMapEntry = pMemMap + *pcMemMap - 1; } @@ -167,7 +168,7 @@ VOID MmX64_CallbackCleanup_ObPteMap(PVMMOB_MAP_PTE pOb) } _Success_(return) -BOOL MmX64_PteMapInitialize(_In_ PVMM_PROCESS pProcess) +BOOL MmX64_PteMapInitialize(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess) { QWORD i; DWORD cMemMap = 0; @@ -182,11 +183,11 @@ BOOL MmX64_PteMapInitialize(_In_ PVMM_PROCESS pProcess) return TRUE; } // allocate temporary buffer and walk page tables - pObPML4 = VmmTlbGetPageTable(pProcess->paDTB, FALSE); + pObPML4 = VmmTlbGetPageTable(H, pProcess->paDTB, FALSE); if(pObPML4) { pMemMap = (PVMM_MAP_PTEENTRY)LocalAlloc(LMEM_ZEROINIT, VMM_MEMMAP_ENTRIES_MAX * sizeof(VMM_MAP_PTEENTRY)); if(pMemMap) { - MmX64_MapInitialize_Index(pProcess, pMemMap, &cMemMap, 0, 4, pObPML4->pqw, FALSE, ctxMain->dev.paMax); + MmX64_MapInitialize_Index(H, pProcess, pMemMap, &cMemMap, 0, 4, pObPML4->pqw, FALSE, H->dev.paMax); for(i = 0; i < cMemMap; i++) { // fixup sign extension for kernel addresses if(pMemMap[i].vaBase & 0x0000800000000000) { pMemMap[i].vaBase |= 0xffff000000000000; @@ -196,9 +197,9 @@ BOOL MmX64_PteMapInitialize(_In_ PVMM_PROCESS pProcess) Ob_DECREF(pObPML4); } // allocate VmmOb depending on result - pObMap = Ob_Alloc(OB_TAG_MAP_PTE, 0, sizeof(VMMOB_MAP_PTE) + cMemMap * sizeof(VMM_MAP_PTEENTRY), (OB_CLEANUP_CB)MmX64_CallbackCleanup_ObPteMap, NULL); + pObMap = Ob_AllocEx(H, OB_TAG_MAP_PTE, 0, sizeof(VMMOB_MAP_PTE) + cMemMap * sizeof(VMM_MAP_PTEENTRY), (OB_CLEANUP_CB)MmX64_CallbackCleanup_ObPteMap, NULL); if(!pObMap) { - pProcess->Map.pObPte = Ob_Alloc(OB_TAG_MAP_PTE, LMEM_ZEROINIT, sizeof(VMMOB_MAP_PTE), NULL, NULL); + pProcess->Map.pObPte = Ob_AllocEx(H, OB_TAG_MAP_PTE, LMEM_ZEROINIT, sizeof(VMMOB_MAP_PTE), NULL, NULL); LeaveCriticalSection(&pProcess->LockUpdate); LocalFree(pMemMap); return TRUE; @@ -215,12 +216,12 @@ BOOL MmX64_PteMapInitialize(_In_ PVMM_PROCESS pProcess) } _Success_(return) -BOOL MmX64_Virt2Phys(_In_ QWORD paPT, _In_ BOOL fUserOnly, _In_ BYTE iPML, _In_ QWORD va, _Out_ PQWORD ppa) +BOOL MmX64_Virt2Phys(_In_ VMM_HANDLE H, _In_ QWORD paPT, _In_ BOOL fUserOnly, _In_ BYTE iPML, _In_ QWORD va, _Out_ PQWORD ppa) { QWORD pte, i, qwMask; PVMMOB_CACHE_MEM pObPTEs; if(iPML == (BYTE)-1) { iPML = 4; } - pObPTEs = VmmTlbGetPageTable(paPT & 0x0000fffffffff000, FALSE); + pObPTEs = VmmTlbGetPageTable(H, paPT & 0x0000fffffffff000, FALSE); if(!pObPTEs) { return FALSE; } i = 0x1ff & (va >> MMX64_PAGETABLEMAP_PML_REGION_SIZE[iPML]); pte = pObPTEs->pqw[i]; @@ -239,15 +240,15 @@ BOOL MmX64_Virt2Phys(_In_ QWORD paPT, _In_ BOOL fUserOnly, _In_ BYTE iPML, _In_ *ppa = *ppa | (qwMask & va); // FILL LOWER ADDRESS BITS return TRUE; } - return MmX64_Virt2Phys(pte, fUserOnly, iPML - 1, va, ppa); + return MmX64_Virt2Phys(H, pte, fUserOnly, iPML - 1, va, ppa); } -VOID MmX64_Virt2PhysVadEx(_In_ QWORD paPT, _Inout_ PVMMOB_MAP_VADEX pVadEx, _In_ BYTE iPML, _Inout_ PDWORD piVadEx) +VOID MmX64_Virt2PhysVadEx(_In_ VMM_HANDLE H, _In_ QWORD paPT, _Inout_ PVMMOB_MAP_VADEX pVadEx, _In_ BYTE iPML, _Inout_ PDWORD piVadEx) { QWORD pa, pte, iPte, iVadEx, qwMask; PVMMOB_CACHE_MEM pObPTEs = NULL; if(iPML == (BYTE)-1) { iPML = 4; } - if(!(pObPTEs = VmmTlbGetPageTable(paPT & 0x0000fffffffff000, FALSE))) { + if(!(pObPTEs = VmmTlbGetPageTable(H, paPT & 0x0000fffffffff000, FALSE))) { *piVadEx = *piVadEx + 1; return; } @@ -267,7 +268,7 @@ next_entry: pVadEx->pMap[iVadEx].tp = VMM_PTE_TP_HARDWARE; goto next_check; } - MmX64_Virt2PhysVadEx(pte, pVadEx, iPML - 1, piVadEx); + MmX64_Virt2PhysVadEx(H, pte, pVadEx, iPML - 1, piVadEx); Ob_DECREF(pObPTEs); return; next_check: @@ -278,7 +279,7 @@ next_check: Ob_DECREF(pObPTEs); } -VOID MmX64_Virt2PhysGetInformation_DoWork(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo, _In_ BYTE iPML, _In_ QWORD PTEs[512]) +VOID MmX64_Virt2PhysGetInformation_DoWork(_In_ VMM_HANDLE H, _Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo, _In_ BYTE iPML, _In_ QWORD PTEs[512]) { QWORD pte, i, qwMask; PVMMOB_CACHE_MEM pObNextPT; @@ -297,14 +298,14 @@ VOID MmX64_Virt2PhysGetInformation_DoWork(_Inout_ PVMM_PROCESS pProcess, _Inout_ pVirt2PhysInfo->pas[0] = pVirt2PhysInfo->pas[0] | (qwMask & pVirt2PhysInfo->va); // FILL LOWER ADDRESS BITS return; } - pObNextPT = VmmTlbGetPageTable(pte & 0x0000fffffffff000, FALSE); + pObNextPT = VmmTlbGetPageTable(H, pte & 0x0000fffffffff000, FALSE); if(!pObNextPT) { return; } pVirt2PhysInfo->pas[iPML - 1] = pte & 0x0000fffffffff000; - MmX64_Virt2PhysGetInformation_DoWork(pProcess, pVirt2PhysInfo, iPML - 1, pObNextPT->pqw); + MmX64_Virt2PhysGetInformation_DoWork(H, pProcess, pVirt2PhysInfo, iPML - 1, pObNextPT->pqw); Ob_DECREF(pObNextPT); } -VOID MmX64_Virt2PhysGetInformation(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo) +VOID MmX64_Virt2PhysGetInformation(_In_ VMM_HANDLE H, _Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo) { QWORD va; PVMMOB_CACHE_MEM pObPML4; @@ -313,19 +314,19 @@ VOID MmX64_Virt2PhysGetInformation(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_V pVirt2PhysInfo->tpMemoryModel = VMM_MEMORYMODEL_X64; pVirt2PhysInfo->va = va; pVirt2PhysInfo->pas[4] = pProcess->paDTB; - pObPML4 = VmmTlbGetPageTable(pProcess->paDTB, FALSE); + pObPML4 = VmmTlbGetPageTable(H, pProcess->paDTB, FALSE); if(!pObPML4) { return; } - MmX64_Virt2PhysGetInformation_DoWork(pProcess, pVirt2PhysInfo, 4, pObPML4->pqw); + MmX64_Virt2PhysGetInformation_DoWork(H, pProcess, pVirt2PhysInfo, 4, pObPML4->pqw); Ob_DECREF(pObPML4); } -VOID MmX64_Phys2VirtGetInformation_Index(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaBase, _In_ BYTE iPML, _In_ QWORD PTEs[512], _In_ QWORD paMax, _Inout_ PVMMOB_PHYS2VIRT_INFORMATION pP2V) +VOID MmX64_Phys2VirtGetInformation_Index(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD vaBase, _In_ BYTE iPML, _In_ QWORD PTEs[512], _In_ QWORD paMax, _Inout_ PVMMOB_PHYS2VIRT_INFORMATION pP2V) { BOOL fUserOnly; QWORD i, pte, va; PVMMOB_CACHE_MEM pObNextPT; if(!pProcess->fTlbSpiderDone) { - VmmTlbSpider(pProcess); + VmmTlbSpider(H, pProcess); } fUserOnly = pProcess->fUserOnly; for(i = 0; i < 512; i++) { @@ -346,45 +347,46 @@ VOID MmX64_Phys2VirtGetInformation_Index(_In_ PVMM_PROCESS pProcess, _In_ QWORD } // maps page table (PDPT, PD, PT) if(fUserOnly && !(pte & 0x04)) { continue; } // do not go into supervisor pages if user-only adderss space - pObNextPT = VmmTlbGetPageTable(pte & 0x0000fffffffff000, FALSE); + pObNextPT = VmmTlbGetPageTable(H, pte & 0x0000fffffffff000, FALSE); if(!pObNextPT) { continue; } va = vaBase + (i << MMX64_PAGETABLEMAP_PML_REGION_SIZE[iPML]); - MmX64_Phys2VirtGetInformation_Index(pProcess, va, iPML - 1, pObNextPT->pqw, paMax, pP2V); + MmX64_Phys2VirtGetInformation_Index(H, pProcess, va, iPML - 1, pObNextPT->pqw, paMax, pP2V); Ob_DECREF(pObNextPT); if(pP2V->cvaList == VMM_PHYS2VIRT_INFORMATION_MAX_PROCESS_RESULT) { return; } } } -VOID MmX64_Phys2VirtGetInformation(_In_ PVMM_PROCESS pProcess, _Inout_ PVMMOB_PHYS2VIRT_INFORMATION pP2V) +VOID MmX64_Phys2VirtGetInformation(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Inout_ PVMMOB_PHYS2VIRT_INFORMATION pP2V) { PVMMOB_CACHE_MEM pObPML4; - if((pP2V->cvaList == VMM_PHYS2VIRT_INFORMATION_MAX_PROCESS_RESULT) || (pP2V->paTarget > ctxMain->dev.paMax)) { return; } - pObPML4 = VmmTlbGetPageTable(pProcess->paDTB, FALSE); + if((pP2V->cvaList == VMM_PHYS2VIRT_INFORMATION_MAX_PROCESS_RESULT) || (pP2V->paTarget > H->dev.paMax)) { return; } + pObPML4 = VmmTlbGetPageTable(H, pProcess->paDTB, FALSE); if(!pObPML4) { return; } - MmX64_Phys2VirtGetInformation_Index(pProcess, 0, 4, pObPML4->pqw, ctxMain->dev.paMax, pP2V); + MmX64_Phys2VirtGetInformation_Index(H, pProcess, 0, 4, pObPML4->pqw, H->dev.paMax, pP2V); Ob_DECREF(pObPML4); } -VOID MmX64_Close() +VOID MmX64_Close(_In_ VMM_HANDLE H) { - ctxVmm->f32 = FALSE; - ctxVmm->tpMemoryModel = VMM_MEMORYMODEL_NA; - ZeroMemory(&ctxVmm->fnMemoryModel, sizeof(VMM_MEMORYMODEL_FUNCTIONS)); + H->vmm.f32 = FALSE; + H->vmm.tpMemoryModel = VMM_MEMORYMODEL_NA; + ZeroMemory(&H->vmm.fnMemoryModel, sizeof(VMM_MEMORYMODEL_FUNCTIONS)); } -VOID MmX64_Initialize() +VOID MmX64_Initialize(_In_ VMM_HANDLE H) { - if(ctxVmm->fnMemoryModel.pfnClose) { - ctxVmm->fnMemoryModel.pfnClose(); + PVMM_MEMORYMODEL_FUNCTIONS pfnsMemoryModel = &H->vmm.fnMemoryModel; + if(pfnsMemoryModel->pfnClose) { + pfnsMemoryModel->pfnClose(H); } - ctxVmm->fnMemoryModel.pfnClose = MmX64_Close; - ctxVmm->fnMemoryModel.pfnVirt2Phys = MmX64_Virt2Phys; - ctxVmm->fnMemoryModel.pfnVirt2PhysVadEx = MmX64_Virt2PhysVadEx; - ctxVmm->fnMemoryModel.pfnVirt2PhysGetInformation = MmX64_Virt2PhysGetInformation; - ctxVmm->fnMemoryModel.pfnPhys2VirtGetInformation = MmX64_Phys2VirtGetInformation; - ctxVmm->fnMemoryModel.pfnPteMapInitialize = MmX64_PteMapInitialize; - ctxVmm->fnMemoryModel.pfnTlbSpider = MmX64_TlbSpider; - ctxVmm->fnMemoryModel.pfnTlbPageTableVerify = MmX64_TlbPageTableVerify; - ctxVmm->tpMemoryModel = VMM_MEMORYMODEL_X64; - ctxVmm->f32 = FALSE; + pfnsMemoryModel->pfnClose = MmX64_Close; + pfnsMemoryModel->pfnVirt2Phys = MmX64_Virt2Phys; + pfnsMemoryModel->pfnVirt2PhysVadEx = MmX64_Virt2PhysVadEx; + pfnsMemoryModel->pfnVirt2PhysGetInformation = MmX64_Virt2PhysGetInformation; + pfnsMemoryModel->pfnPhys2VirtGetInformation = MmX64_Phys2VirtGetInformation; + pfnsMemoryModel->pfnPteMapInitialize = MmX64_PteMapInitialize; + pfnsMemoryModel->pfnTlbSpider = MmX64_TlbSpider; + pfnsMemoryModel->pfnTlbPageTableVerify = MmX64_TlbPageTableVerify; + H->vmm.tpMemoryModel = VMM_MEMORYMODEL_X64; + H->vmm.f32 = FALSE; } diff --git a/vmm/mm_x86.c b/vmm/mm_x86.c index 4da4783..731f540 100644 --- a/vmm/mm_x86.c +++ b/vmm/mm_x86.c @@ -7,14 +7,14 @@ #include "vmmproc.h" #define MMX86_MEMMAP_DISPLAYBUFFER_LINE_LENGTH 70 -#define MMX86_PTE_IS_TRANSITION(pte, iPML) ((((pte & 0x0c01) == 0x0800) && (iPML == 1) && ctxVmm && (ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X86)) ? ((pte & 0xfffff000) | 0x005) : 0) +#define MMX86_PTE_IS_TRANSITION(H, pte, iPML) ((((pte & 0x0c01) == 0x0800) && (iPML == 1) && (H->vmm.tpSystem == VMM_SYSTEM_WINDOWS_X86)) ? ((pte & 0xfffff000) | 0x005) : 0) #define MMX86_PTE_IS_VALID(pte, iPML) (pte & 0x01) /* * Tries to verify that a loaded page table is correct. If just a bit strange * bytes/ptes supplied in pb will be altered to look better. */ -BOOL MmX86_TlbPageTableVerify(_Inout_ PBYTE pb, _In_ QWORD pa, _In_ BOOL fSelfRefReq) +BOOL MmX86_TlbPageTableVerify(_In_ VMM_HANDLE H, _Inout_ PBYTE pb, _In_ QWORD pa, _In_ BOOL fSelfRefReq) { return TRUE; } @@ -22,14 +22,14 @@ BOOL MmX86_TlbPageTableVerify(_Inout_ PBYTE pb, _In_ QWORD pa, _In_ BOOL fSelfRe /* * Iterate over the PD to retrieve uncached PT pages and then commit them to the cache. */ -VOID MmX86_TlbSpider(_In_ PVMM_PROCESS pProcess) +VOID MmX86_TlbSpider(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess) { PVMMOB_CACHE_MEM pObPD = NULL; DWORD i, pte; POB_SET pObPageSet = NULL; if(pProcess->fTlbSpiderDone) { return; } - if(!(pObPageSet = ObSet_New())) { return; } - pObPD = VmmTlbGetPageTable(pProcess->paDTB & 0xfffff000, FALSE); + if(!(pObPageSet = ObSet_New(H))) { return; } + pObPD = VmmTlbGetPageTable(H, pProcess->paDTB & 0xfffff000, FALSE); if(!pObPD) { goto fail; } for(i = 0; i < 1024; i++) { pte = pObPD->pdw[i]; @@ -38,7 +38,7 @@ VOID MmX86_TlbSpider(_In_ PVMM_PROCESS pProcess) if(pProcess->fUserOnly && !(pte & 0x04)) { continue; } // supervisor page when fUserOnly -> not valid ObSet_Push(pObPageSet, pte & 0xfffff000); } - VmmTlbPrefetch(pObPageSet); + VmmTlbPrefetch(H, pObPageSet); pProcess->fTlbSpiderDone = TRUE; fail: Ob_DECREF(pObPageSet); @@ -47,7 +47,7 @@ fail: const DWORD MMX86_PAGETABLEMAP_PML_REGION_SIZE[3] = { 0, 12, 22 }; -VOID MmX86_MapInitialize_Index(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_PTEENTRY pMemMap, _In_ PDWORD pcMemMap, _In_ DWORD vaBase, _In_ BYTE iPML, _In_ DWORD PTEs[1024], _In_ BOOL fSupervisorPML, _In_ QWORD paMax) +VOID MmX86_MapInitialize_Index(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_PTEENTRY pMemMap, _In_ PDWORD pcMemMap, _In_ DWORD vaBase, _In_ BYTE iPML, _In_ DWORD PTEs[1024], _In_ BOOL fSupervisorPML, _In_ QWORD paMax) { PVMMOB_CACHE_MEM pObNextPT; DWORD i, va, pte; @@ -60,7 +60,7 @@ VOID MmX86_MapInitialize_Index(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_PTEENTR if(!MMX86_PTE_IS_VALID(pte, iPML)) { if(!pte) { continue; } if(iPML != 1) { continue; } - pte = MMX86_PTE_IS_TRANSITION(pte, iPML); + pte = MMX86_PTE_IS_TRANSITION(H, pte, iPML); pte = 0x00000005 | (pte ? (pte & 0xfffff000) : 0); // GUESS READ-ONLY USER PAGE IF NON TRANSITION fPagedOut = TRUE; } else { @@ -92,9 +92,9 @@ VOID MmX86_MapInitialize_Index(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_PTEENTR } // maps page table fNextSupervisorPML = !(pte & 0x04); - pObNextPT = VmmTlbGetPageTable(pte & 0xfffff000, FALSE); + pObNextPT = VmmTlbGetPageTable(H, pte & 0xfffff000, FALSE); if(!pObNextPT) { continue; } - MmX86_MapInitialize_Index(pProcess, pMemMap, pcMemMap, va, 1, pObNextPT->pdw, fNextSupervisorPML, paMax); + MmX86_MapInitialize_Index(H, pProcess, pMemMap, pcMemMap, va, 1, pObNextPT->pdw, fNextSupervisorPML, paMax); Ob_DECREF(pObNextPT); pMemMapEntry = pMemMap + *pcMemMap - 1; } @@ -106,7 +106,7 @@ VOID MmX86_CallbackCleanup_ObPteMap(PVMMOB_MAP_PTE pOb) } _Success_(return) -BOOL MmX86_PteMapInitialize(_In_ PVMM_PROCESS pProcess) +BOOL MmX86_PteMapInitialize(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess) { PVMMOB_CACHE_MEM pObPD; DWORD cMemMap = 0; @@ -120,19 +120,19 @@ BOOL MmX86_PteMapInitialize(_In_ PVMM_PROCESS pProcess) return TRUE; } // allocate temporary buffer and walk page tables - VmmTlbSpider(pProcess); - pObPD = VmmTlbGetPageTable(pProcess->paDTB & 0xfffff000, FALSE); + VmmTlbSpider(H, pProcess); + pObPD = VmmTlbGetPageTable(H, pProcess->paDTB & 0xfffff000, FALSE); if(pObPD) { pMemMap = (PVMM_MAP_PTEENTRY)LocalAlloc(LMEM_ZEROINIT, VMM_MEMMAP_ENTRIES_MAX * sizeof(VMM_MAP_PTEENTRY)); if(pMemMap) { - MmX86_MapInitialize_Index(pProcess, pMemMap, &cMemMap, 0, 2, pObPD->pdw, FALSE, ctxMain->dev.paMax); + MmX86_MapInitialize_Index(H, pProcess, pMemMap, &cMemMap, 0, 2, pObPD->pdw, FALSE, H->dev.paMax); } Ob_DECREF(pObPD); } // allocate VmmOb depending on result - pObMap = Ob_Alloc(OB_TAG_MAP_PTE, 0, sizeof(VMMOB_MAP_PTE) + cMemMap * sizeof(VMM_MAP_PTEENTRY), (OB_CLEANUP_CB)MmX86_CallbackCleanup_ObPteMap, NULL); + pObMap = Ob_AllocEx(H, OB_TAG_MAP_PTE, 0, sizeof(VMMOB_MAP_PTE) + cMemMap * sizeof(VMM_MAP_PTEENTRY), (OB_CLEANUP_CB)MmX86_CallbackCleanup_ObPteMap, NULL); if(!pObMap) { - pProcess->Map.pObPte = Ob_Alloc(OB_TAG_MAP_PTE, LMEM_ZEROINIT, sizeof(VMMOB_MAP_PTE), NULL, NULL); + pProcess->Map.pObPte = Ob_AllocEx(H, OB_TAG_MAP_PTE, LMEM_ZEROINIT, sizeof(VMMOB_MAP_PTE), NULL, NULL); LeaveCriticalSection(&pProcess->LockUpdate); LocalFree(pMemMap); return TRUE; @@ -149,7 +149,7 @@ BOOL MmX86_PteMapInitialize(_In_ PVMM_PROCESS pProcess) } _Success_(return) -BOOL MmX86_Virt2Phys(_In_ QWORD paPT, _In_ BOOL fUserOnly, _In_ BYTE iPML, _In_ QWORD va, _Out_ PQWORD ppa) +BOOL MmX86_Virt2Phys(_In_ VMM_HANDLE H, _In_ QWORD paPT, _In_ BOOL fUserOnly, _In_ BYTE iPML, _In_ QWORD va, _Out_ PQWORD ppa) { DWORD pte, i; PVMMOB_CACHE_MEM pObPTEs; @@ -157,7 +157,7 @@ BOOL MmX86_Virt2Phys(_In_ QWORD paPT, _In_ BOOL fUserOnly, _In_ BYTE iPML, _In_ if(va > 0xffffffff) { return FALSE; } if(paPT > 0xffffffff) { return FALSE; } if(iPML == (BYTE)-1) { iPML = 2; } - pObPTEs = VmmTlbGetPageTable(paPT & 0xfffff000, FALSE); + pObPTEs = VmmTlbGetPageTable(H, paPT & 0xfffff000, FALSE); if(!pObPTEs) { return FALSE; } i = 0x3ff & (va >> MMX86_PAGETABLEMAP_PML_REGION_SIZE[iPML]); pte = pObPTEs->pdw[i]; @@ -168,7 +168,7 @@ BOOL MmX86_Virt2Phys(_In_ QWORD paPT, _In_ BOOL fUserOnly, _In_ BYTE iPML, _In_ } if(fUserOnly && !(pte & 0x04)) { return FALSE; } // SUPERVISOR PAGE & USER MODE REQ if((iPML == 2) && !(pte & 0x80) /* PS */) { - return MmX86_Virt2Phys(pte, fUserOnly, 1, va, ppa); + return MmX86_Virt2Phys(H, pte, fUserOnly, 1, va, ppa); } if(iPML == 1) { // 4kB PAGE *ppa = pte & 0xfffff000; @@ -180,12 +180,12 @@ BOOL MmX86_Virt2Phys(_In_ QWORD paPT, _In_ BOOL fUserOnly, _In_ BYTE iPML, _In_ return TRUE; } -VOID MmX86_Virt2PhysVadEx(_In_ QWORD paPT, _Inout_ PVMMOB_MAP_VADEX pVadEx, _In_ BYTE iPML, _Inout_ PDWORD piVadEx) +VOID MmX86_Virt2PhysVadEx(_In_ VMM_HANDLE H, _In_ QWORD paPT, _Inout_ PVMMOB_MAP_VADEX pVadEx, _In_ BYTE iPML, _Inout_ PDWORD piVadEx) { DWORD pte, iPte, iVadEx; PVMMOB_CACHE_MEM pObPTEs = NULL; if(iPML == (BYTE)-1) { iPML = 2; } - if((pVadEx->pMap[*piVadEx].va > 0xffffffff) || (paPT > 0xffffffff) || !(pObPTEs = VmmTlbGetPageTable(paPT & 0xfffff000, FALSE))) { + if((pVadEx->pMap[*piVadEx].va > 0xffffffff) || (paPT > 0xffffffff) || !(pObPTEs = VmmTlbGetPageTable(H, paPT & 0xfffff000, FALSE))) { *piVadEx = *piVadEx + 1; return; } @@ -196,7 +196,7 @@ next_entry: if(!MMX86_PTE_IS_VALID(pte, iPML)) { goto next_check; } // NOT VALID if(!(pte & 0x04)) { goto next_check; } // SUPERVISOR PAGE & USER MODE REQ if((iPML == 2) && !(pte & 0x80) /* PS */) { - MmX86_Virt2PhysVadEx(pte, pVadEx, 1, piVadEx); + MmX86_Virt2PhysVadEx(H, pte, pVadEx, 1, piVadEx); Ob_DECREF(pObPTEs); return; } @@ -215,11 +215,11 @@ next_check: Ob_DECREF(pObPTEs); } -VOID MmX86_Virt2PhysGetInformation_DoWork(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo, _In_ BYTE iPML, _In_ QWORD paPT) +VOID MmX86_Virt2PhysGetInformation_DoWork(_In_ VMM_HANDLE H, _Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo, _In_ BYTE iPML, _In_ QWORD paPT) { PVMMOB_CACHE_MEM pObPTEs; DWORD pte, i; - pObPTEs = VmmTlbGetPageTable(paPT, FALSE); + pObPTEs = VmmTlbGetPageTable(H, paPT, FALSE); if(!pObPTEs) { return; } i = 0x3ff & (pVirt2PhysInfo->va >> MMX86_PAGETABLEMAP_PML_REGION_SIZE[iPML]); pte = pObPTEs->pdw[i]; @@ -238,10 +238,10 @@ VOID MmX86_Virt2PhysGetInformation_DoWork(_Inout_ PVMM_PROCESS pProcess, _Inout_ pVirt2PhysInfo->pas[0] = (pte & 0xffc00000) + (((QWORD)(pte & 0x0001e000)) << (32 - 13)); return; } - MmX86_Virt2PhysGetInformation_DoWork(pProcess, pVirt2PhysInfo, 1, pte & 0xfffff000); // PDE + MmX86_Virt2PhysGetInformation_DoWork(H, pProcess, pVirt2PhysInfo, 1, pte & 0xfffff000); // PDE } -VOID MmX86_Virt2PhysGetInformation(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo) +VOID MmX86_Virt2PhysGetInformation(_In_ VMM_HANDLE H, _Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo) { QWORD va; if(pVirt2PhysInfo->va > 0xffffffff) { return; } @@ -249,17 +249,17 @@ VOID MmX86_Virt2PhysGetInformation(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_V ZeroMemory(pVirt2PhysInfo, sizeof(VMM_VIRT2PHYS_INFORMATION)); pVirt2PhysInfo->tpMemoryModel = VMM_MEMORYMODEL_X86; pVirt2PhysInfo->va = va; - MmX86_Virt2PhysGetInformation_DoWork(pProcess, pVirt2PhysInfo, 2, pProcess->paDTB & 0xfffff000); + MmX86_Virt2PhysGetInformation_DoWork(H, pProcess, pVirt2PhysInfo, 2, pProcess->paDTB & 0xfffff000); } -VOID MmX86_Phys2VirtGetInformation_Index(_In_ PVMM_PROCESS pProcess, _In_ DWORD vaBase, _In_ BYTE iPML, _In_ DWORD PTEs[1024], _In_ QWORD paMax, _Inout_ PVMMOB_PHYS2VIRT_INFORMATION pP2V) +VOID MmX86_Phys2VirtGetInformation_Index(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ DWORD vaBase, _In_ BYTE iPML, _In_ DWORD PTEs[1024], _In_ QWORD paMax, _Inout_ PVMMOB_PHYS2VIRT_INFORMATION pP2V) { BOOL fUserOnly; QWORD pa; DWORD i, va, pte; PVMMOB_CACHE_MEM pObNextPT; if(!pProcess->fTlbSpiderDone) { - VmmTlbSpider(pProcess); + VmmTlbSpider(H, pProcess); } fUserOnly = pProcess->fUserOnly; for(i = 0; i < 1024; i++) { @@ -287,44 +287,45 @@ VOID MmX86_Phys2VirtGetInformation_Index(_In_ PVMM_PROCESS pProcess, _In_ DWORD } // maps page table if(fUserOnly && !(pte & 0x04)) { continue; } // do not go into supervisor pages if user-only adderss space - pObNextPT = VmmTlbGetPageTable(pte & 0xfffff000, FALSE); + pObNextPT = VmmTlbGetPageTable(H, pte & 0xfffff000, FALSE); if(!pObNextPT) { continue; } - MmX86_Phys2VirtGetInformation_Index(pProcess, va, 1, pObNextPT->pdw, paMax, pP2V); + MmX86_Phys2VirtGetInformation_Index(H, pProcess, va, 1, pObNextPT->pdw, paMax, pP2V); Ob_DECREF(pObNextPT); if(pP2V->cvaList == VMM_PHYS2VIRT_INFORMATION_MAX_PROCESS_RESULT) { return; } } } -VOID MmX86_Phys2VirtGetInformation(_In_ PVMM_PROCESS pProcess, _Inout_ PVMMOB_PHYS2VIRT_INFORMATION pP2V) +VOID MmX86_Phys2VirtGetInformation(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Inout_ PVMMOB_PHYS2VIRT_INFORMATION pP2V) { PVMMOB_CACHE_MEM pObPD; - if((pP2V->cvaList == VMM_PHYS2VIRT_INFORMATION_MAX_PROCESS_RESULT) || (pP2V->paTarget > ctxMain->dev.paMax)) { return; } - pObPD = VmmTlbGetPageTable(pProcess->paDTB & 0xfffff000, FALSE); + if((pP2V->cvaList == VMM_PHYS2VIRT_INFORMATION_MAX_PROCESS_RESULT) || (pP2V->paTarget > H->dev.paMax)) { return; } + pObPD = VmmTlbGetPageTable(H, pProcess->paDTB & 0xfffff000, FALSE); if(!pObPD) { return; } - MmX86_Phys2VirtGetInformation_Index(pProcess, 0, 2, pObPD->pdw, ctxMain->dev.paMax, pP2V); + MmX86_Phys2VirtGetInformation_Index(H, pProcess, 0, 2, pObPD->pdw, H->dev.paMax, pP2V); Ob_DECREF(pObPD); } -VOID MmX86_Close() +VOID MmX86_Close(_In_ VMM_HANDLE H) { - ctxVmm->f32 = FALSE; - ctxVmm->tpMemoryModel = VMM_MEMORYMODEL_NA; - ZeroMemory(&ctxVmm->fnMemoryModel, sizeof(VMM_MEMORYMODEL_FUNCTIONS)); + H->vmm.f32 = FALSE; + H->vmm.tpMemoryModel = VMM_MEMORYMODEL_NA; + ZeroMemory(&H->vmm.fnMemoryModel, sizeof(VMM_MEMORYMODEL_FUNCTIONS)); } -VOID MmX86_Initialize() +VOID MmX86_Initialize(_In_ VMM_HANDLE H) { - if(ctxVmm->fnMemoryModel.pfnClose) { - ctxVmm->fnMemoryModel.pfnClose(); + PVMM_MEMORYMODEL_FUNCTIONS pfnsMemoryModel = &H->vmm.fnMemoryModel; + if(pfnsMemoryModel->pfnClose) { + pfnsMemoryModel->pfnClose(H); } - ctxVmm->fnMemoryModel.pfnClose = MmX86_Close; - ctxVmm->fnMemoryModel.pfnVirt2Phys = MmX86_Virt2Phys; - ctxVmm->fnMemoryModel.pfnVirt2PhysVadEx = MmX86_Virt2PhysVadEx; - ctxVmm->fnMemoryModel.pfnVirt2PhysGetInformation = MmX86_Virt2PhysGetInformation; - ctxVmm->fnMemoryModel.pfnPhys2VirtGetInformation = MmX86_Phys2VirtGetInformation; - ctxVmm->fnMemoryModel.pfnPteMapInitialize = MmX86_PteMapInitialize; - ctxVmm->fnMemoryModel.pfnTlbSpider = MmX86_TlbSpider; - ctxVmm->fnMemoryModel.pfnTlbPageTableVerify = MmX86_TlbPageTableVerify; - ctxVmm->tpMemoryModel = VMM_MEMORYMODEL_X86; - ctxVmm->f32 = TRUE; + pfnsMemoryModel->pfnClose = MmX86_Close; + pfnsMemoryModel->pfnVirt2Phys = MmX86_Virt2Phys; + pfnsMemoryModel->pfnVirt2PhysVadEx = MmX86_Virt2PhysVadEx; + pfnsMemoryModel->pfnVirt2PhysGetInformation = MmX86_Virt2PhysGetInformation; + pfnsMemoryModel->pfnPhys2VirtGetInformation = MmX86_Phys2VirtGetInformation; + pfnsMemoryModel->pfnPteMapInitialize = MmX86_PteMapInitialize; + pfnsMemoryModel->pfnTlbSpider = MmX86_TlbSpider; + pfnsMemoryModel->pfnTlbPageTableVerify = MmX86_TlbPageTableVerify; + H->vmm.tpMemoryModel = VMM_MEMORYMODEL_X86; + H->vmm.f32 = TRUE; } diff --git a/vmm/mm_x86pae.c b/vmm/mm_x86pae.c index 62d816c..c0c3429 100644 --- a/vmm/mm_x86pae.c +++ b/vmm/mm_x86pae.c @@ -7,24 +7,24 @@ #include "vmmproc.h" #define MMX86PAE_MEMMAP_DISPLAYBUFFER_LINE_LENGTH 70 -#define MMX86PAE_PTE_IS_TRANSITION(pte, iPML) ((((pte & 0x0c01) == 0x0800) && (iPML == 1) && ctxVmm && (ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X86)) ? ((pte & 0xffffdffffffff000) | 0x005) : 0) +#define MMX86PAE_PTE_IS_TRANSITION(H, pte, iPML) ((((pte & 0x0c01) == 0x0800) && (iPML == 1) && (H->vmm.tpSystem == VMM_SYSTEM_WINDOWS_X86)) ? ((pte & 0xffffdffffffff000) | 0x005) : 0) #define MMX86PAE_PTE_IS_VALID(pte, iPML) (pte & 0x01) /* * Tries to verify that a loaded page table is correct. If just a bit strange * bytes/ptes supplied in pb will be altered to look better. */ -BOOL MmX86PAE_TlbPageTableVerify(_Inout_ PBYTE pb, _In_ QWORD pa, _In_ BOOL fSelfRefReq) +BOOL MmX86PAE_TlbPageTableVerify(_In_ VMM_HANDLE H, _Inout_ PBYTE pb, _In_ QWORD pa, _In_ BOOL fSelfRefReq) { return TRUE; } -VOID MmX86PAE_TlbSpider_PD_PT(_In_ QWORD pa, _In_ BYTE iPML, _In_ BOOL fUserOnly, _In_ POB_SET pPageSet) +VOID MmX86PAE_TlbSpider_PD_PT(_In_ VMM_HANDLE H, _In_ QWORD pa, _In_ BYTE iPML, _In_ BOOL fUserOnly, _In_ POB_SET pPageSet) { QWORD i, pte; PVMMOB_CACHE_MEM pObPT = NULL; // 1: retrieve from cache, add to staging if not found - pObPT = VmmCacheGet(VMM_CACHE_TAG_TLB, pa); + pObPT = VmmCacheGet(H, VMM_CACHE_TAG_TLB, pa); if(!pObPT) { ObSet_Push(pPageSet, pa); return; @@ -39,19 +39,19 @@ VOID MmX86PAE_TlbSpider_PD_PT(_In_ QWORD pa, _In_ BYTE iPML, _In_ BOOL fUserOnly if(!(pte & 0x01)) { continue; } // not valid if(pte & 0x80) { continue; } // not valid ptr to PT if(fUserOnly && !(pte & 0x04)) { continue; } // supervisor page when fUserOnly -> not valid - MmX86PAE_TlbSpider_PD_PT(pte & 0x0000fffffffff000, 1, fUserOnly, pPageSet); + MmX86PAE_TlbSpider_PD_PT(H, pte & 0x0000fffffffff000, 1, fUserOnly, pPageSet); } Ob_DECREF(pObPT); } -VOID MmX86PAE_TlbSpider_PDPT(_In_ QWORD paDTB, _In_ BOOL fUserOnly, _In_ POB_SET pPageSet) +VOID MmX86PAE_TlbSpider_PDPT(_In_ VMM_HANDLE H, _In_ QWORD paDTB, _In_ BOOL fUserOnly, _In_ POB_SET pPageSet) { BOOL fSpiderComplete = TRUE; PVMMOB_CACHE_MEM pObPDPT; PBYTE pbPDPT; QWORD i, pte; // 1: retrieve PDPT - pObPDPT = VmmTlbGetPageTable(paDTB & 0xfffff000, FALSE); + pObPDPT = VmmTlbGetPageTable(H, paDTB & 0xfffff000, FALSE); if(!pObPDPT) { return; } pbPDPT = pObPDPT->pb + (paDTB & 0xfe0); // 2: walk through all four (4) PDPTEs @@ -59,7 +59,7 @@ VOID MmX86PAE_TlbSpider_PDPT(_In_ QWORD paDTB, _In_ BOOL fUserOnly, _In_ POB_SET pte = *(PQWORD)(pbPDPT + i); if(!(pte & 0x01)) { continue; } // not valid if(pte & 0xffff0000000001e6) { continue; } // RESERVED BITS IN PDPTE - MmX86PAE_TlbSpider_PD_PT(pte & 0x0000fffffffff000, 2, fUserOnly, pPageSet); + MmX86PAE_TlbSpider_PD_PT(H, pte & 0x0000fffffffff000, 2, fUserOnly, pPageSet); } Ob_DECREF(pObPDPT); } @@ -68,15 +68,15 @@ VOID MmX86PAE_TlbSpider_PDPT(_In_ QWORD paDTB, _In_ BOOL fUserOnly, _In_ POB_SET * Iterate over PTPT, PD (3 times in total) to first stage uncached pages * and then commit them to the cache. */ -VOID MmX86PAE_TlbSpider(_In_ PVMM_PROCESS pProcess) +VOID MmX86PAE_TlbSpider(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess) { DWORD i; POB_SET pObPageSet = NULL; if(pProcess->fTlbSpiderDone) { return; } - if(!(pObPageSet = ObSet_New())) { return; } + if(!(pObPageSet = ObSet_New(H))) { return; } for(i = 0; i < 3; i++) { - MmX86PAE_TlbSpider_PDPT(pProcess->paDTB, pProcess->fUserOnly, pObPageSet); - VmmTlbPrefetch(pObPageSet); + MmX86PAE_TlbSpider_PDPT(H, pProcess->paDTB, pProcess->fUserOnly, pObPageSet); + VmmTlbPrefetch(H, pObPageSet); } pProcess->fTlbSpiderDone = TRUE; Ob_DECREF(pObPageSet); @@ -87,7 +87,7 @@ const DWORD MMX86PAE_PAGETABLEMAP_PML_REGION_MASK_PG[4] = { 0, 0xfffff000, 0xffe const DWORD MMX86PAE_PAGETABLEMAP_PML_REGION_MASK_AD[4] = { 0, 0xfff, 0x1fffff, 0 }; -VOID MmX86PAE_MapInitialize_Index(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_PTEENTRY pMemMap, _In_ PDWORD pcMemMap, _In_ DWORD vaBase, _In_ BYTE iPML, _In_ QWORD PTEs[512], _In_ BOOL fSupervisorPML, _In_ QWORD paMax) +VOID MmX86PAE_MapInitialize_Index(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_PTEENTRY pMemMap, _In_ PDWORD pcMemMap, _In_ DWORD vaBase, _In_ BYTE iPML, _In_ QWORD PTEs[512], _In_ BOOL fSupervisorPML, _In_ QWORD paMax) { PVMMOB_CACHE_MEM pObNextPT; DWORD i, va; @@ -101,7 +101,7 @@ VOID MmX86PAE_MapInitialize_Index(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_PTEE if(!MMX86PAE_PTE_IS_VALID(pte, iPML)) { if(!pte) { continue; } if(iPML != 1) { continue; } - pte = MMX86PAE_PTE_IS_TRANSITION(pte, iPML); + pte = MMX86PAE_PTE_IS_TRANSITION(H, pte, iPML); pte = 0x8000000000000005 | (pte ? (pte & 0x8000fffffffff000) : 0); // GUESS READ-ONLY USER PAGE IF NON TRANSITION fPagedOut = TRUE; } else { @@ -141,9 +141,9 @@ VOID MmX86PAE_MapInitialize_Index(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_PTEE } // maps page table (PD, PT) fNextSupervisorPML = (iPML != 3) && !(pte & 0x04); - pObNextPT = VmmTlbGetPageTable(pte & 0x0000fffffffff000, FALSE); + pObNextPT = VmmTlbGetPageTable(H, pte & 0x0000fffffffff000, FALSE); if(!pObNextPT) { continue; } - MmX86PAE_MapInitialize_Index(pProcess, pMemMap, pcMemMap, va, iPML - 1, pObNextPT->pqw, fNextSupervisorPML, paMax); + MmX86PAE_MapInitialize_Index(H, pProcess, pMemMap, pcMemMap, va, iPML - 1, pObNextPT->pqw, fNextSupervisorPML, paMax); Ob_DECREF(pObNextPT); pMemMapEntry = pMemMap + *pcMemMap - 1; } @@ -155,7 +155,7 @@ VOID MmX86PAE_CallbackCleanup_ObPteMap(PVMMOB_MAP_PTE pOb) } _Success_(return) -BOOL MmX86PAE_PteMapInitialize(_In_ PVMM_PROCESS pProcess) +BOOL MmX86PAE_PteMapInitialize(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess) { DWORD cMemMap = 0; PBYTE pbPDPT; @@ -170,20 +170,20 @@ BOOL MmX86PAE_PteMapInitialize(_In_ PVMM_PROCESS pProcess) return TRUE; } // allocate temporary buffer and walk page tables - VmmTlbSpider(pProcess); - pObPDPT = VmmTlbGetPageTable(pProcess->paDTB & 0xfffff000, FALSE); + VmmTlbSpider(H, pProcess); + pObPDPT = VmmTlbGetPageTable(H, pProcess->paDTB & 0xfffff000, FALSE); if(pObPDPT) { pMemMap = (PVMM_MAP_PTEENTRY)LocalAlloc(LMEM_ZEROINIT, VMM_MEMMAP_ENTRIES_MAX * sizeof(VMM_MAP_PTEENTRY)); if(pMemMap) { pbPDPT = pObPDPT->pb + (pProcess->paDTB & 0xfe0); // ADJUST PDPT TO 32-BYTE BOUNDARY - MmX86PAE_MapInitialize_Index(pProcess, pMemMap, &cMemMap, 0, 3, (PQWORD)pbPDPT, FALSE, ctxMain->dev.paMax); + MmX86PAE_MapInitialize_Index(H, pProcess, pMemMap, &cMemMap, 0, 3, (PQWORD)pbPDPT, FALSE, H->dev.paMax); } Ob_DECREF(pObPDPT); } // allocate VmmOb depending on result - pObMap = Ob_Alloc(OB_TAG_MAP_PTE, 0, sizeof(VMMOB_MAP_PTE) + cMemMap * sizeof(VMM_MAP_PTEENTRY), (OB_CLEANUP_CB)MmX86PAE_CallbackCleanup_ObPteMap, NULL); + pObMap = Ob_AllocEx(H, OB_TAG_MAP_PTE, 0, sizeof(VMMOB_MAP_PTE) + cMemMap * sizeof(VMM_MAP_PTEENTRY), (OB_CLEANUP_CB)MmX86PAE_CallbackCleanup_ObPteMap, NULL); if(!pObMap) { - pProcess->Map.pObPte = Ob_Alloc(OB_TAG_MAP_PTE, LMEM_ZEROINIT, sizeof(VMMOB_MAP_PTE), NULL, NULL); + pProcess->Map.pObPte = Ob_AllocEx(H, OB_TAG_MAP_PTE, LMEM_ZEROINIT, sizeof(VMMOB_MAP_PTE), NULL, NULL); LeaveCriticalSection(&pProcess->LockUpdate); LocalFree(pMemMap); return TRUE; @@ -200,14 +200,14 @@ BOOL MmX86PAE_PteMapInitialize(_In_ PVMM_PROCESS pProcess) } _Success_(return) -BOOL MmX86PAE_Virt2Phys(_In_ QWORD paPT, _In_ BOOL fUserOnly, _In_ BYTE iPML, _In_ QWORD va, _Out_ PQWORD ppa) +BOOL MmX86PAE_Virt2Phys(_In_ VMM_HANDLE H, _In_ QWORD paPT, _In_ BOOL fUserOnly, _In_ BYTE iPML, _In_ QWORD va, _Out_ PQWORD ppa) { PBYTE pbPTEs; QWORD pte, i, qwMask; PVMMOB_CACHE_MEM pObPTEs; if(va > 0xffffffff) { return FALSE; } if(iPML == (BYTE)-1) { iPML = 3; } - pObPTEs = VmmTlbGetPageTable(paPT & 0x0000fffffffff000, FALSE); + pObPTEs = VmmTlbGetPageTable(H, paPT & 0x0000fffffffff000, FALSE); if(!pObPTEs) { return FALSE; } i = 0x1ff & (va >> MMX86PAE_PAGETABLEMAP_PML_REGION_SIZE[iPML]); if(iPML == 3) { @@ -221,7 +221,7 @@ BOOL MmX86PAE_Virt2Phys(_In_ QWORD paPT, _In_ BOOL fUserOnly, _In_ BYTE iPML, _I Ob_DECREF(pObPTEs); if(!(pte & 0x01)) { return FALSE; } // NOT VALID if(pte & 0xffff0000000001e6) { return FALSE; } // RESERVED BITS IN PDPTE - return MmX86PAE_Virt2Phys(pte, fUserOnly, 2, va, ppa); + return MmX86PAE_Virt2Phys(H, pte, fUserOnly, 2, va, ppa); } // PT or PD pte = pObPTEs->pqw[i]; @@ -239,16 +239,16 @@ BOOL MmX86PAE_Virt2Phys(_In_ QWORD paPT, _In_ BOOL fUserOnly, _In_ BYTE iPML, _I *ppa = *ppa | (qwMask & va); // FILL LOWER ADDRESS BITS return TRUE; } - return MmX86PAE_Virt2Phys(pte, fUserOnly, 1, va, ppa); + return MmX86PAE_Virt2Phys(H, pte, fUserOnly, 1, va, ppa); } -VOID MmX86PAE_Virt2PhysVadEx(_In_ QWORD paPT, _Inout_ PVMMOB_MAP_VADEX pVadEx, _In_ BYTE iPML, _Inout_ PDWORD piVadEx) +VOID MmX86PAE_Virt2PhysVadEx(_In_ VMM_HANDLE H, _In_ QWORD paPT, _Inout_ PVMMOB_MAP_VADEX pVadEx, _In_ BYTE iPML, _Inout_ PDWORD piVadEx) { PBYTE pbPTEs; QWORD pa, pte, iPte, iVadEx, qwMask; PVMMOB_CACHE_MEM pObPTEs = NULL; if(iPML == (BYTE)-1) { iPML = 3; } - if((pVadEx->pMap[*piVadEx].va > 0xffffffff) || !(pObPTEs = VmmTlbGetPageTable(paPT & 0x0000fffffffff000, FALSE))) { + if((pVadEx->pMap[*piVadEx].va > 0xffffffff) || !(pObPTEs = VmmTlbGetPageTable(H, paPT & 0x0000fffffffff000, FALSE))) { *piVadEx = *piVadEx + 1; return; } @@ -263,7 +263,7 @@ next_entry: pte = ((PQWORD)pbPTEs)[iPte]; if(!(pte & 0x01)) { goto next_check; } // NOT VALID if(pte & 0xffff0000000001e6) { goto next_check; } // RESERVED BITS IN PDPTE - MmX86PAE_Virt2PhysVadEx(pte, pVadEx, 2, piVadEx); + MmX86PAE_Virt2PhysVadEx(H, pte, pVadEx, 2, piVadEx); Ob_DECREF(pObPTEs); return; } @@ -279,7 +279,7 @@ next_entry: pVadEx->pMap[iVadEx].tp = VMM_PTE_TP_HARDWARE; goto next_check; } - MmX86PAE_Virt2PhysVadEx(pte, pVadEx, 1, piVadEx); + MmX86PAE_Virt2PhysVadEx(H, pte, pVadEx, 1, piVadEx); Ob_DECREF(pObPTEs); return; next_check: @@ -290,7 +290,7 @@ next_check: Ob_DECREF(pObPTEs); } -VOID MmX86PAE_Virt2PhysGetInformation_DoWork(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo, _In_ BYTE iPML, _In_ QWORD PTEs[512]) +VOID MmX86PAE_Virt2PhysGetInformation_DoWork(_In_ VMM_HANDLE H, _Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo, _In_ BYTE iPML, _In_ QWORD PTEs[512]) { QWORD pte, i, qwMask; PVMMOB_CACHE_MEM pObNextPT; @@ -315,14 +315,14 @@ VOID MmX86PAE_Virt2PhysGetInformation_DoWork(_Inout_ PVMM_PROCESS pProcess, _Ino return; } } - pObNextPT = VmmTlbGetPageTable(pte & 0x0000fffffffff000, FALSE); + pObNextPT = VmmTlbGetPageTable(H, pte & 0x0000fffffffff000, FALSE); if(!pObNextPT) { return; } pVirt2PhysInfo->pas[iPML - 1] = pte & 0x0000fffffffff000; - MmX86PAE_Virt2PhysGetInformation_DoWork(pProcess, pVirt2PhysInfo, iPML - 1, pObNextPT->pqw); + MmX86PAE_Virt2PhysGetInformation_DoWork(H, pProcess, pVirt2PhysInfo, iPML - 1, pObNextPT->pqw); Ob_DECREF(pObNextPT); } -VOID MmX86PAE_Virt2PhysGetInformation(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo) +VOID MmX86PAE_Virt2PhysGetInformation(_In_ VMM_HANDLE H, _Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo) { QWORD va; PVMMOB_CACHE_MEM pObPDPT; @@ -332,20 +332,20 @@ VOID MmX86PAE_Virt2PhysGetInformation(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVM pVirt2PhysInfo->tpMemoryModel = VMM_MEMORYMODEL_X86PAE; pVirt2PhysInfo->va = va; pVirt2PhysInfo->pas[3] = pProcess->paDTB; - pObPDPT = VmmTlbGetPageTable(pProcess->paDTB & 0xfffff000, FALSE); + pObPDPT = VmmTlbGetPageTable(H, pProcess->paDTB & 0xfffff000, FALSE); if(!pObPDPT) { return; } - MmX86PAE_Virt2PhysGetInformation_DoWork(pProcess, pVirt2PhysInfo, 3, (PQWORD)(pObPDPT->pb + (pProcess->paDTB & 0xfe0))); + MmX86PAE_Virt2PhysGetInformation_DoWork(H, pProcess, pVirt2PhysInfo, 3, (PQWORD)(pObPDPT->pb + (pProcess->paDTB & 0xfe0))); Ob_DECREF(pObPDPT); } -VOID MmX86PAE_Phys2VirtGetInformation_Index(_In_ PVMM_PROCESS pProcess, _In_ DWORD vaBase, _In_ BYTE iPML, _In_ QWORD PTEs[512], _In_ QWORD paMax, _Inout_ PVMMOB_PHYS2VIRT_INFORMATION pP2V) +VOID MmX86PAE_Phys2VirtGetInformation_Index(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ DWORD vaBase, _In_ BYTE iPML, _In_ QWORD PTEs[512], _In_ QWORD paMax, _Inout_ PVMMOB_PHYS2VIRT_INFORMATION pP2V) { BOOL fUserOnly; QWORD pte; DWORD i, va; PVMMOB_CACHE_MEM pObNextPT; if(!pProcess->fTlbSpiderDone) { - VmmTlbSpider(pProcess); + VmmTlbSpider(H, pProcess); } fUserOnly = pProcess->fUserOnly; for(i = 0; i < 512; i++) { @@ -374,44 +374,45 @@ VOID MmX86PAE_Phys2VirtGetInformation_Index(_In_ PVMM_PROCESS pProcess, _In_ DWO } // maps page table (PD, PT) if((iPML != 3) && fUserOnly && !(pte & 0x04)) { continue; } // do not go into supervisor pages if user-only adderss space - pObNextPT = VmmTlbGetPageTable(pte & 0x0000fffffffff000, FALSE); + pObNextPT = VmmTlbGetPageTable(H, pte & 0x0000fffffffff000, FALSE); if(!pObNextPT) { continue; } - MmX86PAE_Phys2VirtGetInformation_Index(pProcess, va, iPML - 1, pObNextPT->pqw, paMax, pP2V); + MmX86PAE_Phys2VirtGetInformation_Index(H, pProcess, va, iPML - 1, pObNextPT->pqw, paMax, pP2V); Ob_DECREF(pObNextPT); if(pP2V->cvaList == VMM_PHYS2VIRT_INFORMATION_MAX_PROCESS_RESULT) { return; } } } -VOID MmX86PAE_Phys2VirtGetInformation(_In_ PVMM_PROCESS pProcess, _Inout_ PVMMOB_PHYS2VIRT_INFORMATION pP2V) +VOID MmX86PAE_Phys2VirtGetInformation(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Inout_ PVMMOB_PHYS2VIRT_INFORMATION pP2V) { PVMMOB_CACHE_MEM pObPDPT; - if((pP2V->cvaList == VMM_PHYS2VIRT_INFORMATION_MAX_PROCESS_RESULT) || (pP2V->paTarget > ctxMain->dev.paMax)) { return; } - pObPDPT = VmmTlbGetPageTable(pProcess->paDTB & ~0xfff, FALSE); + if((pP2V->cvaList == VMM_PHYS2VIRT_INFORMATION_MAX_PROCESS_RESULT) || (pP2V->paTarget > H->dev.paMax)) { return; } + pObPDPT = VmmTlbGetPageTable(H, pProcess->paDTB & ~0xfff, FALSE); if(!pObPDPT) { return; } - MmX86PAE_Phys2VirtGetInformation_Index(pProcess, 0, 3, (PQWORD)(pObPDPT->pb + (pProcess->paDTB & 0xfe0)), ctxMain->dev.paMax, pP2V); + MmX86PAE_Phys2VirtGetInformation_Index(H, pProcess, 0, 3, (PQWORD)(pObPDPT->pb + (pProcess->paDTB & 0xfe0)), H->dev.paMax, pP2V); Ob_DECREF(pObPDPT); } -VOID MmX86PAE_Close() +VOID MmX86PAE_Close(_In_ VMM_HANDLE H) { - ctxVmm->f32 = FALSE; - ctxVmm->tpMemoryModel = VMM_MEMORYMODEL_NA; - ZeroMemory(&ctxVmm->fnMemoryModel, sizeof(VMM_MEMORYMODEL_FUNCTIONS)); + H->vmm.f32 = FALSE; + H->vmm.tpMemoryModel = VMM_MEMORYMODEL_NA; + ZeroMemory(&H->vmm.fnMemoryModel, sizeof(VMM_MEMORYMODEL_FUNCTIONS)); } -VOID MmX86PAE_Initialize() +VOID MmX86PAE_Initialize(_In_ VMM_HANDLE H) { - if(ctxVmm->fnMemoryModel.pfnClose) { - ctxVmm->fnMemoryModel.pfnClose(); + PVMM_MEMORYMODEL_FUNCTIONS pfnsMemoryModel = &H->vmm.fnMemoryModel; + if(pfnsMemoryModel->pfnClose) { + pfnsMemoryModel->pfnClose(H); } - ctxVmm->fnMemoryModel.pfnClose = MmX86PAE_Close; - ctxVmm->fnMemoryModel.pfnVirt2Phys = MmX86PAE_Virt2Phys; - ctxVmm->fnMemoryModel.pfnVirt2PhysVadEx = MmX86PAE_Virt2PhysVadEx; - ctxVmm->fnMemoryModel.pfnVirt2PhysGetInformation = MmX86PAE_Virt2PhysGetInformation; - ctxVmm->fnMemoryModel.pfnPhys2VirtGetInformation = MmX86PAE_Phys2VirtGetInformation; - ctxVmm->fnMemoryModel.pfnPteMapInitialize = MmX86PAE_PteMapInitialize; - ctxVmm->fnMemoryModel.pfnTlbSpider = MmX86PAE_TlbSpider; - ctxVmm->fnMemoryModel.pfnTlbPageTableVerify = MmX86PAE_TlbPageTableVerify; - ctxVmm->tpMemoryModel = VMM_MEMORYMODEL_X86PAE; - ctxVmm->f32 = TRUE; + pfnsMemoryModel->pfnClose = MmX86PAE_Close; + pfnsMemoryModel->pfnVirt2Phys = MmX86PAE_Virt2Phys; + pfnsMemoryModel->pfnVirt2PhysVadEx = MmX86PAE_Virt2PhysVadEx; + pfnsMemoryModel->pfnVirt2PhysGetInformation = MmX86PAE_Virt2PhysGetInformation; + pfnsMemoryModel->pfnPhys2VirtGetInformation = MmX86PAE_Phys2VirtGetInformation; + pfnsMemoryModel->pfnPteMapInitialize = MmX86PAE_PteMapInitialize; + pfnsMemoryModel->pfnTlbSpider = MmX86PAE_TlbSpider; + pfnsMemoryModel->pfnTlbPageTableVerify = MmX86PAE_TlbPageTableVerify; + H->vmm.tpMemoryModel = VMM_MEMORYMODEL_X86PAE; + H->vmm.f32 = TRUE; } diff --git a/vmm/ob/ob.h b/vmm/ob/ob.h index 01a2053..148f92f 100644 --- a/vmm/ob/ob.h +++ b/vmm/ob/ob.h @@ -15,6 +15,7 @@ typedef unsigned __int64 QWORD, *PQWORD; #define OB_DEBUG #define OB_HEADER_MAGIC 0x0c0efefe +typedef struct tdVMM_HANDLE *VMM_HANDLE; #define OB_TAG_CORE_CONTAINER 'ObCo' #define OB_TAG_CORE_COMPRESSED 'ObCp' @@ -46,9 +47,9 @@ typedef unsigned __int64 QWORD, *PQWORD; typedef struct tdOB { // internal object manager functionality below: (= do not use unless absolutely necessary) - DWORD _magic; // magic value - OB_HEADER_MAGIC + DWORD _magic1; // magic value - OB_HEADER_MAGIC union { - DWORD _tag; // tag - 2 chars, no null terminator + DWORD _tag; // tag - 4 chars, no null terminator CHAR _tagCh[4]; }; union { @@ -59,13 +60,30 @@ typedef struct tdOB { VOID(*_pfnRef_1)(_In_ PVOID pOb); // callback - when object reach refcount 1 (not initial) QWORD _Filler2; }; + DWORD _Filler3[5]; DWORD _count; // reference count // external object manager functionality below: (= ok to use) + union { VMM_HANDLE H; QWORD _Filler4; };// vmm user handle (supplied at alloc) DWORD cbData; // data byte count (excl. OB header) + DWORD _magic2; // magic value - OB_HEADER_MAGIC } OB, *POB; typedef VOID(*OB_CLEANUP_CB)(_In_ PVOID pOb); +/* +* Allocate a new object manager memory object. +* -- H = an optional handle to embed as OB.H in the header. +* -- tag = tag identifying the type of object. +* -- uFlags = flags as given by LocalAlloc. +* -- uBytes = bytes of object (_including_ object headers). +* -- pfnRef_0 = optional callback for cleanup o be called before object is destroyed. +* (if object contains objects which references should be decremented + before destruction of this 'parent' object). +* -- pfnRef_1 = optional callback for when object reach refcount = 1 at DECREF. +* -- return = allocated object on success, with refcount = 1, - NULL on fail. +*/ +PVOID Ob_AllocEx(_In_opt_ VMM_HANDLE H, _In_ DWORD tag, _In_ UINT uFlags, _In_ SIZE_T uBytes, _In_opt_ OB_CLEANUP_CB pfnRef_0, _In_opt_ OB_CLEANUP_CB pfnRef_1); + /* * Allocate a new object manager memory object. * -- tag = tag identifying the type of object. @@ -77,7 +95,10 @@ typedef VOID(*OB_CLEANUP_CB)(_In_ PVOID pOb); * -- pfnRef_1 = optional callback for when object reach refcount = 1 at DECREF. * -- return = allocated object on success, with refcount = 1, - NULL on fail. */ -PVOID Ob_Alloc(_In_ DWORD tag, _In_ UINT uFlags, _In_ SIZE_T uBytes, _In_opt_ OB_CLEANUP_CB pfnRef_0, _In_opt_ OB_CLEANUP_CB pfnRef_1); +inline PVOID Ob_Alloc(_In_ DWORD tag, _In_ UINT uFlags, _In_ SIZE_T uBytes, _In_opt_ OB_CLEANUP_CB pfnRef_0, _In_opt_ OB_CLEANUP_CB pfnRef_1) +{ + return Ob_AllocEx(NULL, tag, uFlags, uBytes, pfnRef_0, pfnRef_1); +} /* * Increase the reference count of a object by one. @@ -136,12 +157,13 @@ typedef struct tdOB_DATA { * to the number of bytes in the data buffer supplied to this function. * May also be created with Ob_Alloc with size: sizeof(OB_HDR) + length of data. * CALLER DECREF: return +* -- H * -- pb * -- cb * -- return */ _Success_(return != NULL) -POB_DATA ObData_New(_In_ PBYTE pb, _In_ DWORD cb); +POB_DATA ObData_New(_In_opt_ VMM_HANDLE H, _In_ PBYTE pb, _In_ DWORD cb); @@ -216,9 +238,10 @@ typedef struct tdOB_SET *POB_SET; * ways to store unique 64-bit (or smaller) numbers as a set. * The ObSet is an object manager object and must be DECREF'ed when required. * CALLER DECREF: return +* -- H * -- return */ -POB_SET ObSet_New(); +POB_SET ObSet_New(_In_opt_ VMM_HANDLE H); /* * Retrieve the number of items in the given ObSet. @@ -367,10 +390,11 @@ typedef struct tdOB_MAP_ENTRY { * to optionally map key values to values, pointers or object manager objects. * The ObMap is an object manager object and must be DECREF'ed when required. * CALLER DECREF: return +* -- H * -- flags = defined by OB_MAP_FLAGS_* * -- return */ -POB_MAP ObMap_New(_In_ QWORD flags); +POB_MAP ObMap_New(_In_opt_ VMM_HANDLE H, _In_ QWORD flags); /* * Retrieve the number of objects in the ObMap. @@ -549,6 +573,8 @@ QWORD ObMap_GetKey(_In_opt_ POB_MAP pm, _In_ PVOID pvObject); */ VOID ObMap_FilterSet_FilterAllKey(_In_ QWORD k, _In_ PVOID v, _Inout_ POB_SET ps); +typedef VOID(*OB_MAP_FILTER_PFN)(_In_ QWORD k, _In_ PVOID v, _Inout_opt_ PVOID ctx); + /* * Filter map objects into a generic context by using a user-supplied filter function. * -- pm @@ -557,25 +583,39 @@ VOID ObMap_FilterSet_FilterAllKey(_In_ QWORD k, _In_ PVOID v, _Inout_ POB_SET ps * -- return */ _Success_(return) -BOOL ObMap_Filter(_In_opt_ POB_MAP pm, _Inout_opt_ PVOID ctx, _In_opt_ VOID(*pfnFilter)(_In_ QWORD k, _In_ PVOID v, _Inout_opt_ PVOID ctx)); +BOOL ObMap_Filter(_In_opt_ POB_MAP pm, _Inout_opt_ PVOID ctx, _In_opt_ OB_MAP_FILTER_PFN pfnFilter); + +typedef VOID(*OB_MAP_FILTERSET_PFN)(_In_ QWORD k, _In_ PVOID v, _Inout_ POB_SET ps); /* * Filter map objects into a POB_SET by using a user-supplied filter function. * CALLER DECREF: return * -- pm -* -- pfnFilter +* -- pfnFilterSet * -- return = POB_SET consisting of values gathered by the pfnFilter function. */ _Success_(return != NULL) -POB_SET ObMap_FilterSet(_In_opt_ POB_MAP pm, _In_opt_ VOID(*pfnFilter)(_In_ QWORD k, _In_ PVOID v, _Inout_ POB_SET ps)); +POB_SET ObMap_FilterSet(_In_opt_ POB_MAP pm, _In_opt_ OB_MAP_FILTERSET_PFN pfnFilterSet); + +/* +* Callback function for pfnFilter in ObMap_RemoveByFilter(). +* -- H +* -- k +* -- v +*/ +typedef BOOL(*OB_MAP_FILTER_REMOVE_PFN_CB)( + _In_opt_ VMM_HANDLE H, + _In_ QWORD k, + _In_ PVOID v +); /* * Remove map objects using a user-supplied filter function. * -- pm -* -- pfnFilter = decision making function: [pfnFilter(k,v)->TRUE(remove)|FALSE(keep)] +* -- pfnFilter = decision making function: [pfnFilter(H,k,v)->TRUE(remove)|FALSE(keep)] * -- return = number of entries removed. */ -DWORD ObMap_RemoveByFilter(_In_opt_ POB_MAP pm, _In_opt_ BOOL(*pfnFilter)(_In_ QWORD k, _In_ PVOID v)); +DWORD ObMap_RemoveByFilter(_In_opt_ POB_MAP pm, _In_opt_ OB_MAP_FILTER_REMOVE_PFN_CB pfnFilter); /* * Sort the ObMap entry index by a sort compare function. @@ -610,11 +650,26 @@ typedef struct tdOB_CACHEMAP *POB_CACHEMAP; #define OB_CACHEMAP_FLAGS_OBJECT_OB 0x01 #define OB_CACHEMAP_FLAGS_OBJECT_LOCALFREE 0x02 +/* +* Callback function for the pfnValidEntry in ObCacheMap_New() +* -- H +* -- qwContext +* -- qwKey +* -- pbObject +*/ +typedef BOOL(*OB_CACHEMAP_VALIDENTRY_PFN_CB)( + _In_opt_ VMM_HANDLE H, + _Inout_ PQWORD qwContext, + _In_ QWORD qwKey, + _In_ PVOID pvObject +); + /* * Create a new cached map. A cached map (ObCacheMap) provides atomic map * operations on cached objects. * The ObCacheMap is an object manager object and must be DECREF'ed when required. * CALLER DECREF: return +* -- H * -- cMaxEntries = max entries in the cache, if more entries are added the * least recently accessed item will be removed from the cache map. * -- pfnValidEntry = validation callback function (if any). @@ -622,8 +677,9 @@ typedef struct tdOB_CACHEMAP *POB_CACHEMAP; * -- return */ POB_CACHEMAP ObCacheMap_New( + _In_opt_ VMM_HANDLE H, _In_ DWORD cMaxEntries, - _In_opt_ BOOL(*pfnValidEntry)(_Inout_ PQWORD qwContext, _In_ QWORD qwKey, _In_ PVOID pvObject), + _In_opt_ OB_CACHEMAP_VALIDENTRY_PFN_CB pfnValidEntry, _In_ QWORD flags ); @@ -932,11 +988,12 @@ BOOL ObStrMap_FinalizeBufferXUW(_In_opt_ POB_STRMAP psm, _In_ DWORD cbMultiStr, * decommissioned by calling any of the ObStrMap_Finalize*() functions. * The ObStrMap is an object manager object and must be DECREF'ed when required. * CALLER DECREF: return +* -- H * -- flags * -- return */ _Success_(return != NULL) -POB_STRMAP ObStrMap_New(_In_ QWORD flags); +POB_STRMAP ObStrMap_New(_In_opt_ VMM_HANDLE H, _In_ QWORD flags); @@ -948,24 +1005,33 @@ POB_STRMAP ObStrMap_New(_In_ QWORD flags); typedef struct tdOB_COMPRESSED *POB_COMPRESSED; +#define OB_COMPRESSED_CACHED_ENTRIES_MAX 0x40 +#define OB_COMPRESSED_CACHED_ENTRIES_MAXSIZE 0x00100000 + /* * Create a new compressed buffer object from a byte buffer. +* It's strongly recommended to supply a global cache map to use. * CALLER DECREF: return +* -- H +* -- pcmg = optional global (per VMM_HANDLE) cache map to use. * -- pb * -- cb * -- return */ _Success_(return != NULL) -POB_COMPRESSED ObCompressed_NewFromByte(_In_reads_(cb) PBYTE pb, _In_ DWORD cb); +POB_COMPRESSED ObCompressed_NewFromByte(_In_opt_ VMM_HANDLE H, _In_opt_ POB_CACHEMAP pcmg, _In_reads_(cb) PBYTE pb, _In_ DWORD cb); /* * Create a new compressed buffer object from a zero terminated string. +* It's strongly recommended to supply a global cache map to use. * CALLER DECREF: return +* -- H +* -- pcmg = optional global (per VMM_HANDLE) cache map to use. * -- sz * -- return */ _Success_(return != NULL) -POB_COMPRESSED ObCompress_NewFromStrA(_In_ LPSTR sz); +POB_COMPRESSED ObCompress_NewFromStrA(_In_opt_ VMM_HANDLE H, _In_opt_ POB_CACHEMAP pcmg, _In_ LPSTR sz); /* * Retrieve the uncompressed size of the compressed data object. @@ -1000,11 +1066,14 @@ typedef struct tdOB_MEMFILE *POB_MEMFILE; /* * Create a new empty memory file. +* It's strongly recommended to supply a global cache map to use. * CALLER DECREF: return +* -- H +* -- pcmg = optional global (per VMM_HANDLE) cache map to use. * -- return */ _Success_(return != NULL) -POB_MEMFILE ObMemFile_New(); +POB_MEMFILE ObMemFile_New(_In_opt_ VMM_HANDLE H, _In_opt_ POB_CACHEMAP pcmg); /* * Retrieve byte count of the ObMemFile. @@ -1032,6 +1101,16 @@ BOOL ObMemFile_Append(_In_opt_ POB_MEMFILE pmf, _In_reads_(cb) PBYTE pb, _In_ QW _Success_(return) BOOL ObMemFile_AppendString(_In_opt_ POB_MEMFILE pmf, _In_opt_z_ LPSTR sz); +/* +* Append a string (ansi or utf-8) to the ObMemFile. +* -- H +* -- uszFormat +* -- arglist +* -- return = the number of bytes appended (excluding terminating null). +*/ +_Success_(return != 0) +SIZE_T ObMemFile_AppendStringEx(_In_opt_ POB_MEMFILE pmf, _In_z_ _Printf_format_string_ LPSTR uszFormat, _In_ va_list arglist); + /* * Read data 'as file' from the ObMemFile. * -- pmf @@ -1071,10 +1150,11 @@ typedef struct tdOB_COUNTER_ENTRY { * Create a new counter. A counter (ObCounter) provides atomic counting operations. * The ObCounter is an object manager object and must be DECREF'ed when required. * CALLER DECREF: return +* -- H * -- flags = defined by OB_COUNTER_FLAGS_* * -- return */ -POB_COUNTER ObCounter_New(_In_ QWORD flags); +POB_COUNTER ObCounter_New(_In_opt_ VMM_HANDLE H, _In_ QWORD flags); /* * Retrieve the number of counted keys the ObCounter. diff --git a/vmm/ob/ob_cachemap.c b/vmm/ob/ob_cachemap.c index d62bdf5..3666b35 100644 --- a/vmm/ob/ob_cachemap.c +++ b/vmm/ob/ob_cachemap.c @@ -15,7 +15,7 @@ // #include "ob.h" -#define OB_CACHEMAP_IS_VALID(p) (p && (p->ObHdr._magic == OB_HEADER_MAGIC) && (p->ObHdr._tag == OB_TAG_CORE_CACHEMAP)) +#define OB_CACHEMAP_IS_VALID(p) (p && (p->ObHdr._magic2 == OB_HEADER_MAGIC) && (p->ObHdr._magic1 == OB_HEADER_MAGIC) && (p->ObHdr._tag == OB_TAG_CORE_CACHEMAP)) #define OB_CACHEMAP_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pcm, RetTp, RetValFail, fn) { \ if(!OB_CACHEMAP_IS_VALID(pcm)) { return RetValFail; } \ @@ -42,10 +42,9 @@ typedef struct tdOB_CACHEMAP { BOOL fObjectsLocalFree; POB_MAP pm; POB_CACHEMAPENTRY AgeListHead; - BOOL(*pfnValidEntry)(_Inout_ PQWORD qwData, _In_ QWORD qwKey, _In_ PVOID pvObject); + OB_CACHEMAP_VALIDENTRY_PFN_CB pfnValidEntry; } OB_CACHEMAP, *POB_CACHEMAP; - _Success_(return) BOOL _ObCacheMap_Clear(_In_ POB_CACHEMAP pcm) { @@ -108,7 +107,7 @@ PVOID _ObCacheMap_GetByKey(_In_ POB_CACHEMAP pcm, _In_ QWORD qwKey) { POB_CACHEMAPENTRY pe; if(!(pe = ObMap_GetByKey(pcm->pm, qwKey))) { return NULL; } - if(pcm->pfnValidEntry && !pcm->pfnValidEntry(&pe->qwContext, qwKey, pe->pvObject)) { + if(pcm->pfnValidEntry && !pcm->pfnValidEntry(pcm->ObHdr.H, &pe->qwContext, qwKey, pe->pvObject)) { // invalid - remove object from map and return NULL _ObCacheMap_RemoveByKey(pcm, qwKey, TRUE); return NULL; @@ -228,25 +227,26 @@ VOID _ObCacheMap_ObCloseCallback(_In_ POB_CACHEMAP pObCacheMap) * operations on cached objects. * The ObCacheMap is an object manager object and must be DECREF'ed when required. * CALLER DECREF: return +* -- H * -- cMaxEntries = max entries in the cache, if more entries are added the * least recently accessed item will be removed from the cache map. * -- pfnValidEntry = optional validation callback function. * -- flags = defined by OB_CACHEMAP_FLAGS_* * -- return */ -POB_CACHEMAP ObCacheMap_New(_In_ DWORD cMaxEntries, _In_opt_ BOOL(*pfnValidEntry)(_Inout_ PQWORD qwContext, _In_ QWORD qwKey, _In_ PVOID pvObject), _In_ QWORD flags) +POB_CACHEMAP ObCacheMap_New(_In_opt_ VMM_HANDLE H, _In_ DWORD cMaxEntries, _In_opt_ OB_CACHEMAP_VALIDENTRY_PFN_CB pfnValidEntry, _In_ QWORD flags) { POB_CACHEMAP pObCacheMap; if(!cMaxEntries) { return NULL; } if((flags & OB_MAP_FLAGS_OBJECT_OB) && (flags & OB_MAP_FLAGS_OBJECT_LOCALFREE)) { return NULL; } - pObCacheMap = Ob_Alloc(OB_TAG_CORE_CACHEMAP, LMEM_ZEROINIT, sizeof(OB_CACHEMAP), (OB_CLEANUP_CB)_ObCacheMap_ObCloseCallback, NULL); + pObCacheMap = Ob_AllocEx(H, OB_TAG_CORE_CACHEMAP, LMEM_ZEROINIT, sizeof(OB_CACHEMAP), (OB_CLEANUP_CB)_ObCacheMap_ObCloseCallback, NULL); if(!pObCacheMap) { return NULL; } InitializeSRWLock(&pObCacheMap->LockSRW); pObCacheMap->cMax = cMaxEntries; pObCacheMap->pfnValidEntry = pfnValidEntry; pObCacheMap->fObjectsOb = (flags & OB_CACHEMAP_FLAGS_OBJECT_OB) ? TRUE : FALSE; pObCacheMap->fObjectsLocalFree = (flags & OB_CACHEMAP_FLAGS_OBJECT_LOCALFREE) ? TRUE : FALSE; - pObCacheMap->pm = ObMap_New(OB_MAP_FLAGS_OBJECT_VOID); + pObCacheMap->pm = ObMap_New(H, OB_MAP_FLAGS_OBJECT_VOID); if(!pObCacheMap->pm) { Ob_DECREF(pObCacheMap); return NULL; diff --git a/vmm/ob/ob_compressed.c b/vmm/ob/ob_compressed.c index ab4c093..60be153 100644 --- a/vmm/ob/ob_compressed.c +++ b/vmm/ob/ob_compressed.c @@ -11,20 +11,28 @@ // #include "ob.h" -#define OB_COMPRESSED_MAX_THREADS 2 -#define OB_COMPRESSED_CACHED_ENTRIES_MAX 0x40 -#define OB_COMPRESSED_CACHED_ENTRIES_MAXSIZE 0x00100000 -#define OB_COMPRESSED_IS_VALID(p) (p && (p->ObHdr._magic == OB_HEADER_MAGIC) && (p->ObHdr._tag == OB_TAG_CORE_COMPRESSED)) +#define OB_COMPRESSED_IS_VALID(p) (p && (p->ObHdr._magic2 == OB_HEADER_MAGIC) && (p->ObHdr._magic1 == OB_HEADER_MAGIC) && (p->ObHdr._tag == OB_TAG_CORE_COMPRESSED)) typedef struct tdOB_COMPRESSED { OB ObHdr; + SRWLOCK LockSRW; QWORD qwCacheKey; DWORD cbUncompressed; DWORD cbCompressed; PBYTE pbCompressed; USHORT usRtlCompressionFormat; + POB_CACHEMAP pcm; } OB_COMPRESSED, *POB_COMPRESSED; +#define OB_COMPRESSED_CALL_SYNCHRONIZED_IMPLEMENTATION_EXCLUSIVE(pm, RetTp, RetValFail, fn) { \ + if(!OB_COMPRESSED_IS_VALID(pm)) { return RetValFail; } \ + RetTp retVal; \ + AcquireSRWLockExclusive(&pm->LockSRW); \ + retVal = fn; \ + ReleaseSRWLockExclusive(&pm->LockSRW); \ + return retVal; \ +} + #ifdef _WIN32 #include @@ -55,14 +63,9 @@ typedef NTSTATUS WINAPI OB_COMPRESSED_RtlDecompressBuffer( PULONG FinalUncompressedSize ); -typedef struct tdOB_COMPRESSED_WORKSPACE { - SRWLOCK LockSRW; - PBYTE pbWorkBuffer; - DWORD cbWorkBuffer; -} OB_COMPRESSED_WORKSPACE; - /* * Internal helper function to compress bytes. +* -- H * -- pb * -- cb * -- ppb @@ -72,14 +75,12 @@ typedef struct tdOB_COMPRESSED_WORKSPACE { * CALLER LocalFree: *ppb */ _Success_(return) -BOOL _ObCompressed_Compress(_In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PBYTE *ppb, _Out_ PDWORD pcb, _Out_ PUSHORT pusRtlCompressionFormat) +BOOL _ObCompressed_Compress(_In_opt_ VMM_HANDLE H, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PBYTE *ppb, _Out_ PDWORD pcb, _Out_ PUSHORT pusRtlCompressionFormat) { BOOL f; NTSTATUS nt; - DWORD cbResult, i; - PBYTE pbResult = NULL, pbBuffer = NULL; - static DWORD iWorkSpace = 0; - static OB_COMPRESSED_WORKSPACE WorkSpace[OB_COMPRESSED_MAX_THREADS] = { 0 }; + DWORD cbResult; + PBYTE pbResult = NULL, pbBuffer = NULL, pbWorkBuffer = NULL; static OB_COMPRESSED_RtlCompressBuffer *pfnRtlCompressBuffer = NULL; static OB_COMPRESSED_RtlGetCompressionWorkSpaceSize *pfnRtlGetCompressionWorkSpaceSize = NULL; static SRWLOCK InitLockSRW = { 0 }; @@ -95,10 +96,6 @@ BOOL _ObCompressed_Compress(_In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PBYTE (hNtDll = LoadLibraryA("ntdll.dll")) && (pfnRtlGetCompressionWorkSpaceSize = (OB_COMPRESSED_RtlGetCompressionWorkSpaceSize *)GetProcAddress(hNtDll, "RtlGetCompressionWorkSpaceSize")) && (0 == pfnRtlGetCompressionWorkSpaceSize(usRtlCompressionFormat, &ulCompressBufferWorkSpaceSize, &ulCompressFragmentWorkSpaceSize)); - for(i = 0; f && (i < OB_COMPRESSED_MAX_THREADS); i++) { - WorkSpace[i].cbWorkBuffer = ulCompressBufferWorkSpaceSize; - WorkSpace[i].pbWorkBuffer = LocalAlloc(0, ulCompressBufferWorkSpaceSize); - } if(f) { pfnRtlCompressBuffer = (OB_COMPRESSED_RtlCompressBuffer *)GetProcAddress(hNtDll, "RtlCompressBuffer"); } @@ -111,10 +108,8 @@ BOOL _ObCompressed_Compress(_In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PBYTE } // 2: compress if(!(pbBuffer = LocalAlloc(0, cb))) { goto fail; } - i = InterlockedIncrement(&iWorkSpace) % OB_COMPRESSED_MAX_THREADS; - AcquireSRWLockExclusive(&WorkSpace[i].LockSRW); - nt = pfnRtlCompressBuffer(usRtlCompressionFormat, pb, cb, pbBuffer, cb, 4096, &cbResult, WorkSpace->pbWorkBuffer); - ReleaseSRWLockExclusive(&WorkSpace[i].LockSRW); + if(!(pbWorkBuffer = LocalAlloc(0, ulCompressBufferWorkSpaceSize))) { goto fail; } + nt = pfnRtlCompressBuffer(usRtlCompressionFormat, pb, cb, pbBuffer, cb, 4096, &cbResult, pbWorkBuffer); if(nt) { goto fail; } if(!(pbResult = LocalAlloc(0, cbResult))) { goto fail; } memcpy(pbResult, pbBuffer, cbResult); @@ -123,6 +118,7 @@ BOOL _ObCompressed_Compress(_In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PBYTE *pusRtlCompressionFormat = usRtlCompressionFormat; fail: LocalFree(pbBuffer); + LocalFree(pbWorkBuffer); return pbResult ? TRUE : FALSE; } @@ -133,26 +129,19 @@ fail: * -- return */ _Success_(return != NULL) -POB_DATA ObCompressed_GetData(_In_opt_ POB_COMPRESSED pdc) +POB_DATA _ObCompressed_GetData(_In_ POB_COMPRESSED pdc) { - // function have a static global cache map shared amongst all instances - // which will cache up to OB_COMPRESSED_CACHED_ENTRIES_MAX decompressed - // entries smaller than OB_COMPRESSED_CACHED_ENTRIES_MAXSIZE. - static POB_CACHEMAP pObCacheMap = NULL; static SRWLOCK InitLockSRW = { 0 }; static OB_COMPRESSED_RtlDecompressBuffer *pfnRtlDecompressBuffer = NULL; HANDLE hNtDll = 0; POB_DATA pObData = NULL; ULONG ulFinalUncompressedSize = 0; - if(!OB_COMPRESSED_IS_VALID(pdc)) { return NULL; } + DWORD status; // 1: ensure compress functionality: if(!pfnRtlDecompressBuffer) { AcquireSRWLockExclusive(&InitLockSRW); if(!pfnRtlDecompressBuffer) { - if(!pObCacheMap) { - pObCacheMap = ObCacheMap_New(OB_COMPRESSED_CACHED_ENTRIES_MAX, NULL, OB_CACHEMAP_FLAGS_OBJECT_OB); - } - if(pObCacheMap && (hNtDll = LoadLibraryA("ntdll.dll"))) { + if((hNtDll = LoadLibraryA("ntdll.dll"))) { pfnRtlDecompressBuffer = (OB_COMPRESSED_RtlDecompressBuffer *)GetProcAddress(hNtDll, "RtlDecompressBuffer"); FreeLibrary(hNtDll); } @@ -161,17 +150,20 @@ POB_DATA ObCompressed_GetData(_In_opt_ POB_COMPRESSED pdc) if(!pfnRtlDecompressBuffer) { return NULL; } } // 2: fetch from cache (if possible): - if(pObCacheMap && (pObData = ObCacheMap_GetByKey(pObCacheMap, pdc->qwCacheKey))) { + if((pObData = ObCacheMap_GetByKey(pdc->pcm, pdc->qwCacheKey))) { return pObData; } // 3: decompress and insert into cache - if(!(pObData = Ob_Alloc(OB_TAG_CORE_DATA, 0, sizeof(OB) + pdc->cbUncompressed, NULL, NULL))) { return NULL; } - if(0 != pfnRtlDecompressBuffer(pdc->usRtlCompressionFormat, pObData->pb, pdc->cbUncompressed, pdc->pbCompressed, pdc->cbCompressed, &ulFinalUncompressedSize)) { + if(!(pObData = Ob_AllocEx(pdc->ObHdr.H, OB_TAG_CORE_DATA, 0, sizeof(OB) + pdc->cbUncompressed, NULL, NULL))) { + return NULL; + } + status = pfnRtlDecompressBuffer(pdc->usRtlCompressionFormat, pObData->pb, pdc->cbUncompressed, pdc->pbCompressed, pdc->cbCompressed, &ulFinalUncompressedSize); + if(status != 0) { Ob_DECREF(pObData); return NULL; } - if(pObData->ObHdr.cbData < OB_COMPRESSED_CACHED_ENTRIES_MAXSIZE) { // only cache objects smaller than threshold - ObCacheMap_Push(pObCacheMap, pdc->qwCacheKey, pObData, 0); + if(pObData->ObHdr.cbData <= OB_COMPRESSED_CACHED_ENTRIES_MAXSIZE) { // only cache objects smaller than threshold + ObCacheMap_Push(pdc->pcm, pdc->qwCacheKey, pObData, 0); } return pObData; } @@ -183,6 +175,7 @@ POB_DATA ObCompressed_GetData(_In_opt_ POB_COMPRESSED pdc) /* * Internal helper function to compress bytes. +* -- H * -- pb * -- cb * -- ppb @@ -192,7 +185,7 @@ POB_DATA ObCompressed_GetData(_In_opt_ POB_COMPRESSED pdc) * CALLER LocalFree: *ppb */ _Success_(return) -BOOL _ObCompressed_Compress(_In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PBYTE * ppb, _Out_ PDWORD pcb, _Out_ PUSHORT pusRtlCompressionFormat) +BOOL _ObCompressed_Compress(_In_opt_ VMM_HANDLE H, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PBYTE * ppb, _Out_ PDWORD pcb, _Out_ PUSHORT pusRtlCompressionFormat) { DWORD cbResult = 0; PBYTE pbResult = NULL, pbBuffer = NULL; @@ -217,42 +210,41 @@ fail: * -- return */ _Success_(return != NULL) -POB_DATA ObCompressed_GetData(_In_opt_ POB_COMPRESSED pdc) +POB_DATA _ObCompressed_GetData(_In_ POB_COMPRESSED pdc) { - // function have a static global cache map shared amongst all instances - // which will cache up to OB_COMPRESSED_CACHED_ENTRIES_MAX decompressed - // entries smaller than OB_COMPRESSED_CACHED_ENTRIES_MAXSIZE. - static POB_CACHEMAP pObCacheMap = NULL; - static SRWLOCK InitLockSRW = { 0 }; POB_DATA pObData = NULL; - if(!OB_COMPRESSED_IS_VALID(pdc)) { return NULL; } // 1: ensure compress functionality: - if(!pObCacheMap) { - AcquireSRWLockExclusive(&InitLockSRW); - if(!pObCacheMap) { - pObCacheMap = ObCacheMap_New(OB_COMPRESSED_CACHED_ENTRIES_MAX, NULL, OB_CACHEMAP_FLAGS_OBJECT_OB); - } - ReleaseSRWLockExclusive(&InitLockSRW); - if(!pObCacheMap) { return NULL; } - } + // NOT REQUIRED ON LINUX // 2: fetch from cache (if possible): - if(pObCacheMap && (pObData = ObCacheMap_GetByKey(pObCacheMap, pdc->qwCacheKey))) { + if((pObData = ObCacheMap_GetByKey(pdc->pcm, pdc->qwCacheKey))) { return pObData; } // 3: decompress and insert into cache - if(!(pObData = Ob_Alloc(OB_TAG_CORE_DATA, 0, sizeof(OB) + pdc->cbUncompressed, NULL, NULL))) { return NULL; } - if(pObData->ObHdr.cbData != LZ4_decompress_safe(pdc->pbCompressed, pObData->pb, pdc->cbCompressed, pdc->cbUncompressed)) { + if(!(pObData = Ob_AllocEx(pdc->ObHdr.H, OB_TAG_CORE_DATA, 0, sizeof(OB) + pdc->cbUncompressed, NULL, NULL))) { return NULL; } + if((int)pObData->ObHdr.cbData != LZ4_decompress_safe(pdc->pbCompressed, pObData->pb, pdc->cbCompressed, pdc->cbUncompressed)) { Ob_DECREF(pObData); return NULL; } if(pObData->ObHdr.cbData < OB_COMPRESSED_CACHED_ENTRIES_MAXSIZE) { // only cache objects smaller than threshold - ObCacheMap_Push(pObCacheMap, pdc->qwCacheKey, pObData, 0); + ObCacheMap_Push(pdc->pcm, pdc->qwCacheKey, pObData, 0); } return pObData; } #endif /* LINUX */ +/* +* Retrieve uncompressed from a compressed data object. +* CALLER DECREF: return +* -- pdc +* -- return +*/ +_Success_(return != NULL) +POB_DATA ObCompressed_GetData(_In_opt_ POB_COMPRESSED pdc) +{ + OB_COMPRESSED_CALL_SYNCHRONIZED_IMPLEMENTATION_EXCLUSIVE(pdc, POB_DATA, NULL, _ObCompressed_GetData(pdc)); +} + /* * Object Map object manager cleanup function to be called when reference * count reaches zero. @@ -261,25 +253,29 @@ POB_DATA ObCompressed_GetData(_In_opt_ POB_COMPRESSED pdc) VOID _ObCompressed_ObCloseCallback(_In_ POB_COMPRESSED pObCompressed) { LocalFree(pObCompressed->pbCompressed); + Ob_DECREF(pObCompressed->pcm); } /* * Create a new compressed buffer object from a byte buffer. +* It's strongly recommended to supply a global cache map to use. * CALLER DECREF: return +* -- H +* -- pcmg = optional global (per VMM_HANDLE) cache map to use. * -- pb * -- cb * -- return */ _Success_(return != NULL) -POB_COMPRESSED ObCompressed_NewFromByte(_In_reads_(cb) PBYTE pb, _In_ DWORD cb) +POB_COMPRESSED ObCompressed_NewFromByte(_In_opt_ VMM_HANDLE H, _In_opt_ POB_CACHEMAP pcmg, _In_reads_(cb) PBYTE pb, _In_ DWORD cb) { POB_COMPRESSED pObC = NULL; - pObC = Ob_Alloc(OB_TAG_CORE_COMPRESSED, 0, sizeof(OB_COMPRESSED), (OB_CLEANUP_CB)_ObCompressed_ObCloseCallback, NULL); + pObC = Ob_AllocEx(H, OB_TAG_CORE_COMPRESSED, LMEM_ZEROINIT, sizeof(OB_COMPRESSED), (OB_CLEANUP_CB)_ObCompressed_ObCloseCallback, NULL); if(!pObC) { return NULL; } - pObC->pbCompressed = NULL; - if(!_ObCompressed_Compress(pb, cb, &pObC->pbCompressed, &pObC->cbCompressed, &pObC->usRtlCompressionFormat)) { goto fail; } + if(!_ObCompressed_Compress(H, pb, cb, &pObC->pbCompressed, &pObC->cbCompressed, &pObC->usRtlCompressionFormat)) { goto fail; } pObC->cbUncompressed = cb; pObC->qwCacheKey = (QWORD)pObC ^ ((QWORD)pObC << 47) ^ (QWORD)pObC->pbCompressed ^ (QWORD)pb ^ ((QWORD)cb << 31); + pObC->pcm = Ob_INCREF(pcmg); Ob_INCREF(pObC); fail: return Ob_DECREF(pObC); @@ -287,16 +283,19 @@ fail: /* * Create a new compressed buffer object from a zero terminated string. +* It's strongly recommended to supply a global cache map to use. * CALLER DECREF: return +* -- H +* -- pcmg = optional global (per VMM_HANDLE) cache map to use. * -- sz * -- return */ _Success_(return != NULL) -POB_COMPRESSED ObCompress_NewFromStrA(_In_ LPSTR sz) +POB_COMPRESSED ObCompress_NewFromStrA(_In_opt_ VMM_HANDLE H, _In_opt_ POB_CACHEMAP pcmg, _In_ LPSTR sz) { SIZE_T csz = strlen(sz); if(csz > 0x01000000) { return NULL; } - return ObCompressed_NewFromByte(sz, (DWORD)csz + 1); + return ObCompressed_NewFromByte(H, pcmg, sz, (DWORD)csz + 1); } /* diff --git a/vmm/ob/ob_container.c b/vmm/ob/ob_container.c index c8da17a..fea3bca 100644 --- a/vmm/ob/ob_container.c +++ b/vmm/ob/ob_container.c @@ -12,7 +12,7 @@ // #include "ob.h" -#define OB_CONTAINER_IS_VALID(p) (p && (p->ObHdr._magic == OB_HEADER_MAGIC) && (p->ObHdr._tag == OB_TAG_CORE_CONTAINER)) +#define OB_CONTAINER_IS_VALID(p) (p && (p->ObHdr._magic2 == OB_HEADER_MAGIC) && (p->ObHdr._magic1 == OB_HEADER_MAGIC) && (p->ObHdr._tag == OB_TAG_CORE_CONTAINER)) /* * Object Container object manager cleanup function to be called when reference @@ -39,7 +39,7 @@ POB_CONTAINER ObContainer_New() POB_CONTAINER pObContainer = Ob_Alloc(OB_TAG_CORE_CONTAINER, LMEM_ZEROINIT, sizeof(OB_CONTAINER), (OB_CLEANUP_CB)ObContainer_ObCloseCallback, NULL); if(!pObContainer) { return NULL; } if(!InitializeCriticalSectionAndSpinCount(&pObContainer->Lock, 4096)) { - LocalFree(pObContainer); + Ob_DECREF(pObContainer); return NULL; } return pObContainer; diff --git a/vmm/ob/ob_core.c b/vmm/ob/ob_core.c index 2fbdac1..e1daa0e 100644 --- a/vmm/ob/ob_core.c +++ b/vmm/ob/ob_core.c @@ -26,6 +26,7 @@ /* * Allocate a new object manager memory object. +* -- H = an optional handle to embed as OB.H in the header. * -- tag = tag of the object to be allocated. * -- uFlags = flags as given by LocalAlloc. * -- uBytes = bytes of object (_including_ object headers). @@ -34,17 +35,19 @@ * -- pfnRef_1 = optional callback for when object reach refcount = 1 (excl. initial). * -- return = allocated object on success, with refcount = 1, - NULL on fail. */ -PVOID Ob_Alloc(_In_ DWORD tag, _In_ UINT uFlags, _In_ SIZE_T uBytes, _In_opt_ VOID(*pfnRef_0)(_In_ PVOID pOb), _In_opt_ VOID(*pfnRef_1)(_In_ PVOID pOb)) +PVOID Ob_AllocEx(_In_opt_ VMM_HANDLE H, _In_ DWORD tag, _In_ UINT uFlags, _In_ SIZE_T uBytes, _In_opt_ OB_CLEANUP_CB pfnRef_0, _In_opt_ OB_CLEANUP_CB pfnRef_1) { POB pOb; if((uBytes > 0x40000000) || (uBytes < sizeof(OB))) { return NULL; } pOb = (POB)LocalAlloc(uFlags, uBytes + OB_DEBUG_FOOTER_SIZE); if(!pOb) { return NULL; } - pOb->_magic = OB_HEADER_MAGIC; + pOb->_magic1 = OB_HEADER_MAGIC; + pOb->_magic2 = OB_HEADER_MAGIC; pOb->_count = 1; pOb->_tag = tag; pOb->_pfnRef_0 = pfnRef_0; pOb->_pfnRef_1 = pfnRef_1; + pOb->H = H; pOb->cbData = (DWORD)uBytes - sizeof(OB); #ifdef OB_DEBUG DWORD i, cb = sizeof(OB) + pOb->cbData; @@ -65,7 +68,7 @@ PVOID Ob_XINCREF(_In_opt_ PVOID pObIn) { POB pOb = (POB)pObIn; if(pOb) { - if(pOb->_magic == OB_HEADER_MAGIC) { + if((pOb->_magic2 == OB_HEADER_MAGIC) && (pOb->_magic1 == OB_HEADER_MAGIC)) { InterlockedIncrement(&pOb->_count); return (POB)pOb; } else { @@ -86,7 +89,7 @@ PVOID Ob_XDECREF(_In_opt_ PVOID pObIn) POB pOb = (POB)pObIn; DWORD c; if(pOb) { - if(pOb->_magic == OB_HEADER_MAGIC) { + if((pOb->_magic2 == OB_HEADER_MAGIC) && (pOb->_magic1 == OB_HEADER_MAGIC)) { c = InterlockedDecrement(&pOb->_count); #ifdef OB_DEBUG DWORD i, cb = sizeof(OB) + pOb->cbData; @@ -99,7 +102,8 @@ PVOID Ob_XDECREF(_In_opt_ PVOID pObIn) #endif /* OB_DEBUG */ if(c == 0) { if(pOb->_pfnRef_0) { pOb->_pfnRef_0(pOb); } - pOb->_magic = 0; + pOb->_magic1 = 0; + pOb->_magic2 = 0; LocalFree(pOb); } else if((c == 1) && pOb->_pfnRef_1) { pOb->_pfnRef_1(pOb); @@ -137,7 +141,7 @@ VOID Ob_XDECREF_NULL(_In_opt_ PVOID *ppOb) BOOL Ob_VALID_TAG(_In_ PVOID pObIn, _In_ DWORD tag) { POB pOb = (POB)pObIn; - return pOb && (pOb->_magic == OB_HEADER_MAGIC) && (pOb->_tag = tag); + return pOb && (pOb->_magic2 == OB_HEADER_MAGIC) && (pOb->_magic1 == OB_HEADER_MAGIC) && (pOb->_tag = tag); } /* @@ -145,15 +149,16 @@ BOOL Ob_VALID_TAG(_In_ PVOID pObIn, _In_ DWORD tag) * to the number of bytes in the data buffer supplied to this function. * May also be created with Ob_Alloc with size: sizeof(OB_HDR) + length of data. * CALLER DECREF: return +* -- H * -- pb * -- cb * -- return */ _Success_(return != NULL) -POB_DATA ObData_New(_In_ PBYTE pb, _In_ DWORD cb) +POB_DATA ObData_New(_In_opt_ VMM_HANDLE H, _In_ PBYTE pb, _In_ DWORD cb) { POB_DATA pObData = NULL; - if((pObData = Ob_Alloc(OB_TAG_CORE_DATA, 0, sizeof(OB) + cb, NULL, NULL))) { + if((pObData = Ob_AllocEx(H, OB_TAG_CORE_DATA, 0, sizeof(OB) + cb, NULL, NULL))) { memcpy(pObData->pb, pb, cb); } return pObData; diff --git a/vmm/ob/ob_counter.c b/vmm/ob/ob_counter.c index bdab83f..462e430 100644 --- a/vmm/ob/ob_counter.c +++ b/vmm/ob/ob_counter.c @@ -12,7 +12,7 @@ #define OB_COUNTER_ENTRIES_DIRECTORY 0x100 #define OB_COUNTER_ENTRIES_TABLE 0x200 #define OB_COUNTER_ENTRIES_STORE 0x100 -#define OB_COUNTER_IS_VALID(p) (p && (p->ObHdr._magic == OB_HEADER_MAGIC) && (p->ObHdr._tag == OB_TAG_CORE_COUNTER)) +#define OB_COUNTER_IS_VALID(p) (p && (p->ObHdr._magic2 == OB_HEADER_MAGIC) && (p->ObHdr._magic1 == OB_HEADER_MAGIC) && (p->ObHdr._tag == OB_TAG_CORE_COUNTER)) #define OB_COUNTER_TABLE_MAX_CAPACITY OB_COUNTER_ENTRIES_DIRECTORY * OB_COUNTER_ENTRIES_TABLE * OB_COUNTER_ENTRIES_STORE #define OB_COUNTER_HASH_FUNCTION(v) (13 * (v + _rotr16((WORD)v, 9) + _rotr((DWORD)v, 17) + _rotr64(v, 31))) @@ -531,13 +531,14 @@ BOOL _ObCounter_Push(_In_ POB_COUNTER pm, _In_ QWORD k, _In_ QWORD v) * Create a new counter. A counter (ObCounter) provides atomic counting operations. * The ObCounter is an object manager object and must be DECREF'ed when required. * CALLER DECREF: return +* -- H * -- flags = defined by OB_COUNTER_FLAGS_* * -- return */ -POB_COUNTER ObCounter_New(_In_ QWORD flags) +POB_COUNTER ObCounter_New(_In_opt_ VMM_HANDLE H, _In_ QWORD flags) { POB_COUNTER pObCounter; - pObCounter = Ob_Alloc(OB_TAG_CORE_COUNTER, LMEM_ZEROINIT, sizeof(OB_COUNTER), (OB_CLEANUP_CB)_ObCounter_ObCloseCallback, NULL); + pObCounter = Ob_AllocEx(H, OB_TAG_CORE_COUNTER, LMEM_ZEROINIT, sizeof(OB_COUNTER), (OB_CLEANUP_CB)_ObCounter_ObCloseCallback, NULL); if(!pObCounter) { return NULL; } InitializeSRWLock(&pObCounter->LockSRW); pObCounter->c = 1; // item zero is reserved - hence the initialization of count to 1 diff --git a/vmm/ob/ob_map.c b/vmm/ob/ob_map.c index 557bea4..a8d9ff0 100644 --- a/vmm/ob/ob_map.c +++ b/vmm/ob/ob_map.c @@ -20,7 +20,7 @@ #define OB_MAP_ENTRIES_DIRECTORY 0x100 #define OB_MAP_ENTRIES_TABLE 0x200 #define OB_MAP_ENTRIES_STORE 0x100 -#define OB_MAP_IS_VALID(p) (p && (p->ObHdr._magic == OB_HEADER_MAGIC) && (p->ObHdr._tag == OB_TAG_CORE_MAP)) +#define OB_MAP_IS_VALID(p) (p && (p->ObHdr._magic2 == OB_HEADER_MAGIC) && (p->ObHdr._magic1 == OB_HEADER_MAGIC) && (p->ObHdr._tag == OB_TAG_CORE_MAP)) #define OB_MAP_TABLE_MAX_CAPACITY OB_MAP_ENTRIES_DIRECTORY * OB_MAP_ENTRIES_TABLE * OB_MAP_ENTRIES_STORE #define OB_MAP_HASH_FUNCTION(v) (13 * (v + _rotr16((WORD)v, 9) + _rotr((DWORD)v, 17) + _rotr64(v, 31))) @@ -283,7 +283,7 @@ QWORD _ObMap_GetKey(_In_ POB_MAP pm, _In_ PVOID pvObject) } _Success_(return) -BOOL _ObMap_Filter(_In_ POB_MAP pm, _Inout_opt_ PVOID ctx, _In_ VOID(*pfnFilter)(_In_ QWORD k, _In_ PVOID v, _Inout_opt_ PVOID ctx)) +BOOL _ObMap_Filter(_In_ POB_MAP pm, _Inout_opt_ PVOID ctx, _In_ OB_MAP_FILTER_PFN pfnFilter) { DWORD iEntry; POB_MAP_ENTRY pEntry; @@ -295,16 +295,16 @@ BOOL _ObMap_Filter(_In_ POB_MAP pm, _Inout_opt_ PVOID ctx, _In_ VOID(*pfnFilter) } _Success_(return != NULL) -POB_SET _ObMap_FilterSet(_In_ POB_MAP pm, _In_opt_ VOID(*pfnFilter)(_In_ QWORD k, _In_ PVOID v, _Inout_ POB_SET ps)) +POB_SET _ObMap_FilterSet(_In_ POB_MAP pm, _In_opt_ OB_MAP_FILTERSET_PFN pfnFilterSet) { DWORD iEntry; POB_MAP_ENTRY pEntry; POB_SET pObSet; - if(!(pObSet = ObSet_New())) { return NULL; } - if(!pfnFilter) { return pObSet; } + if(!(pObSet = ObSet_New(pm->ObHdr.H))) { return NULL; } + if(!pfnFilterSet) { return pObSet; } for(iEntry = 1; iEntry < pm->c; iEntry++) { pEntry = &pm->Directory[OB_MAP_INDEX_DIRECTORY(iEntry)][OB_MAP_INDEX_TABLE(iEntry)][OB_MAP_INDEX_STORE(iEntry)]; - pfnFilter(pEntry->k, pEntry->v, pObSet); + pfnFilterSet(pEntry->k, pEntry->v, pObSet); } return pObSet; } @@ -414,7 +414,7 @@ QWORD ObMap_PeekKey(_In_opt_ POB_MAP pm) * -- return */ _Success_(return) -BOOL ObMap_Filter(_In_opt_ POB_MAP pm, _Inout_opt_ PVOID ctx, _In_opt_ VOID(*pfnFilter)(_In_ QWORD k, _In_ PVOID v, _Inout_opt_ PVOID ctx)) +BOOL ObMap_Filter(_In_opt_ POB_MAP pm, _Inout_opt_ PVOID ctx, _In_opt_ OB_MAP_FILTER_PFN pfnFilter) { if(!pfnFilter) { return FALSE; } OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pm, BOOL, FALSE, _ObMap_Filter(pm, ctx, pfnFilter)); @@ -424,13 +424,13 @@ BOOL ObMap_Filter(_In_opt_ POB_MAP pm, _Inout_opt_ PVOID ctx, _In_opt_ VOID(*pfn * Filter map objects into a POB_SET by using a user-supplied filter function. * CALLER DECREF: return * -- pm -* -- pfnFilter +* -- pfnFilterSet * -- return = POB_SET consisting of values gathered by the pfnFilter function. */ _Success_(return != NULL) -POB_SET ObMap_FilterSet(_In_opt_ POB_MAP pm, _In_opt_ VOID(*pfnFilter)(_In_ QWORD k, _In_ PVOID v, _Inout_ POB_SET ps)) +POB_SET ObMap_FilterSet(_In_opt_ POB_MAP pm, _In_opt_ OB_MAP_FILTERSET_PFN pfnFilterSet) { - OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pm, POB_SET, NULL, _ObMap_FilterSet(pm, pfnFilter)); + OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pm, POB_SET, NULL, _ObMap_FilterSet(pm, pfnFilterSet)); } /* @@ -484,7 +484,7 @@ PVOID _ObMap_RemoveOrRemoveByKey(_In_ POB_MAP pm, _In_ BOOL fValueHash, _In_ QWO return _ObMap_RetrieveAndRemoveByEntryIndex(pm, iEntry, NULL); } -DWORD _ObMap_RemoveByFilter(_In_ POB_MAP pm, _In_opt_ BOOL(*pfnFilter)(_In_ QWORD k, _In_ PVOID v)) +DWORD _ObMap_RemoveByFilter(_In_ POB_MAP pm, _In_opt_ OB_MAP_FILTER_REMOVE_PFN_CB pfnFilter) { DWORD cRemove = 0; DWORD iEntry; @@ -493,7 +493,7 @@ DWORD _ObMap_RemoveByFilter(_In_ POB_MAP pm, _In_opt_ BOOL(*pfnFilter)(_In_ QWOR if(!pfnFilter) { return 0; } for(iEntry = pm->c - 1; iEntry; iEntry--) { pEntry = &pm->Directory[OB_MAP_INDEX_DIRECTORY(iEntry)][OB_MAP_INDEX_TABLE(iEntry)][OB_MAP_INDEX_STORE(iEntry)]; - if(pfnFilter(pEntry->k, pEntry->v)) { + if(pfnFilter(pm->ObHdr.H, pEntry->k, pEntry->v)) { cRemove++; pv = _ObMap_RetrieveAndRemoveByEntryIndex(pm, iEntry, NULL); if(pm->fObjectsOb) { Ob_DECREF(pv); } @@ -556,10 +556,10 @@ PVOID ObMap_RemoveByKey(_In_opt_ POB_MAP pm, _In_ QWORD qwKey) /* * Remove map objects using a user-supplied filter function. * -- pm -* -- pfnFilter = decision making function, TRUE = keep, FALSE = remove. +* -- pfnFilter = decision making function: [pfnFilter(H,k,v)->TRUE(remove)|FALSE(keep)] * -- return = number of entries removed. */ -DWORD ObMap_RemoveByFilter(_In_opt_ POB_MAP pm, _In_opt_ BOOL(*pfnFilter)(_In_ QWORD k, _In_ PVOID v)) +DWORD ObMap_RemoveByFilter(_In_opt_ POB_MAP pm, _In_opt_ OB_MAP_FILTER_REMOVE_PFN_CB pfnFilter) { OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pm, DWORD, 0, _ObMap_RemoveByFilter(pm, pfnFilter)); } @@ -677,7 +677,7 @@ BOOL _ObMap_Push(_In_ POB_MAP pm, _In_ QWORD qwKey, _In_ PVOID pvObject) POB_MAP_ENTRY pe; DWORD iEntry = pm->c; if(!pvObject || _ObMap_Exists(pm, TRUE, (QWORD)pvObject) || _ObMap_Exists(pm, FALSE, qwKey)) { return FALSE; } - if(iEntry == OB_MAP_ENTRIES_DIRECTORY * OB_MAP_ENTRIES_TABLE * OB_MAP_ENTRIES_STORE) { return FALSE; } + if(iEntry == OB_MAP_TABLE_MAX_CAPACITY) { return FALSE; } if(iEntry == pm->cHashGrowThreshold) { if(!_ObMap_Grow(pm)) { return FALSE; @@ -748,14 +748,15 @@ BOOL ObMap_PushCopy(_In_opt_ POB_MAP pm, _In_ QWORD qwKey, _In_ PVOID pvObject, * to optionally map key values to values, pointers or object manager objects. * The ObMap is an object manager object and must be DECREF'ed when required. * CALLER DECREF: return +* -- H * -- flags = defined by OB_MAP_FLAGS_* * -- return */ -POB_MAP ObMap_New(_In_ QWORD flags) +POB_MAP ObMap_New(_In_opt_ VMM_HANDLE H, _In_ QWORD flags) { POB_MAP pObMap; if((flags & OB_MAP_FLAGS_OBJECT_OB) && (flags & OB_MAP_FLAGS_OBJECT_LOCALFREE)) { return NULL; } - pObMap = Ob_Alloc(OB_TAG_CORE_MAP, LMEM_ZEROINIT, sizeof(OB_MAP), (OB_CLEANUP_CB)_ObMap_ObCloseCallback, NULL); + pObMap = Ob_AllocEx(H, OB_TAG_CORE_MAP, LMEM_ZEROINIT, sizeof(OB_MAP), (OB_CLEANUP_CB)_ObMap_ObCloseCallback, NULL); if(!pObMap) { return NULL; } InitializeSRWLock(&pObMap->LockSRW); pObMap->c = 1; // item zero is reserved - hence the initialization of count to 1 diff --git a/vmm/ob/ob_memfile.c b/vmm/ob/ob_memfile.c index 0f7d212..b51c586 100644 --- a/vmm/ob/ob_memfile.c +++ b/vmm/ob/ob_memfile.c @@ -12,6 +12,7 @@ // Author: Ulf Frisk, pcileech@frizk.net // #include "ob.h" +#include #define OB_MEMFILE_ENTRIES_DIRECTORY 0x200 #define OB_MEMFILE_ENTRIES_TABLE 0x200 @@ -21,7 +22,7 @@ #define OB_MEMFILE_INDEX_DIRECTORY(cb) (((cb) >> 25) & 0x1ff) #define OB_MEMFILE_INDEX_TABLE(cb) (((cb) >> 16) & 0x1ff) -#define OB_MEMFILE_IS_VALID(p) (p && (p->ObHdr._magic == OB_HEADER_MAGIC) && (p->ObHdr._tag == OB_TAG_CORE_MEMFILE)) +#define OB_MEMFILE_IS_VALID(p) (p && (p->ObHdr._magic2 == OB_HEADER_MAGIC) && (p->ObHdr._magic1 == OB_HEADER_MAGIC) && (p->ObHdr._tag == OB_TAG_CORE_MEMFILE)) #define NTSTATUS_SUCCESS ((NTSTATUS)0x00000000L) #define NTSTATUS_END_OF_FILE ((NTSTATUS)0xC0000011L) @@ -31,6 +32,7 @@ typedef struct tdOB_MEMFILE { OB ObHdr; SRWLOCK LockSRW; QWORD cb; + POB_CACHEMAP pcm; POB_COMPRESSED* Directory[OB_MEMFILE_ENTRIES_DIRECTORY]; POB_COMPRESSED Table0[OB_MEMFILE_ENTRIES_TABLE]; BYTE pbBuffer[OB_MEMFILE_BUFSIZE]; @@ -68,6 +70,7 @@ VOID _ObMemFile_ObCloseCallback(_In_ POB_MEMFILE pmf) for(i = 1; i < OB_MEMFILE_ENTRIES_DIRECTORY && pmf->Directory[i]; i++) { LocalFree(pmf->Directory[i]); } + Ob_DECREF(pmf->pcm); } _Success_(return == 0) @@ -129,7 +132,7 @@ BOOL _ObMemFile_Compress(_In_ POB_MEMFILE pmf) pmf->Directory[iDirectory] = LocalAlloc(LMEM_ZEROINIT, OB_MEMFILE_ENTRIES_TABLE * sizeof(POB_COMPRESSED)); if(!pmf->Directory[iDirectory]) { goto fail; } } - pmf->Directory[iDirectory][iTable] = ObCompressed_NewFromByte(pmf->pbBuffer, OB_MEMFILE_BUFSIZE); + pmf->Directory[iDirectory][iTable] = ObCompressed_NewFromByte(pmf->ObHdr.H, pmf->pcm, pmf->pbBuffer, OB_MEMFILE_BUFSIZE); if(!pmf->Directory[iDirectory][iTable]) { goto fail; } return TRUE; fail: @@ -160,6 +163,38 @@ BOOL _ObMemFile_Append(_In_ POB_MEMFILE pmf, _In_reads_(cbData) PBYTE pbData, _I return TRUE; } +_Success_(return != 0) +SIZE_T _ObMemFile_AppendStringEx(_In_ POB_MEMFILE pmf, _In_z_ _Printf_format_string_ LPSTR uszFormat, _In_ va_list arglist) +{ + BOOL f = FALSE; + int cch1, cch2; + PBYTE pbBuffer; + QWORD oBuffer, cbCopy, cbData; + va_list arglist_copy; + va_copy(arglist_copy, arglist); + cch1 = _vscprintf(uszFormat, arglist_copy); + if(cch1 <= 0) { return 0; } + cbData = (QWORD)cch1 + 1; + oBuffer = pmf->cb % OB_MEMFILE_BUFSIZE; + cbCopy = min(cbData, OB_MEMFILE_BUFSIZE - oBuffer); + // 1: try efficient direct write into buffer if it fits! + if(cbData == cbCopy) { + cch2 = _vsnprintf_s(pmf->pbBuffer + oBuffer, (SIZE_T)cbCopy, _TRUNCATE, uszFormat, arglist); + if(cch1 != cch2) { return 0; } + pmf->cb += (QWORD)cch2; + return (SIZE_T)cch2; + } + // 2: data too large to fit buffer - allocate and write bytes + if((pbBuffer = LocalAlloc(0, (SIZE_T)cbData))) { + cch2 = _vsnprintf_s(pbBuffer, (SIZE_T)cbData, _TRUNCATE, uszFormat, arglist); + if(cch1 == cch2) { + f = _ObMemFile_Append(pmf, pbBuffer, (QWORD)cch2); + } + LocalFree(pbBuffer); + } + return f ? (SIZE_T)cch2 : 0; +} + /* * Append binary data to the ObMemFile. * -- pmf @@ -186,6 +221,19 @@ BOOL ObMemFile_AppendString(_In_opt_ POB_MEMFILE pmf, _In_opt_z_ LPSTR sz) return ObMemFile_Append(pmf, (PBYTE)sz, strlen(sz)); } +/* +* Append a string (ansi or utf-8) to the ObMemFile. +* -- H +* -- uszFormat +* -- arglist +* -- return = the number of bytes appended (excluding terminating null). +*/ +_Success_(return != 0) +SIZE_T ObMemFile_AppendStringEx(_In_opt_ POB_MEMFILE pmf, _In_z_ _Printf_format_string_ LPSTR uszFormat, _In_ va_list arglist) +{ + OB_MEMFILE_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pmf, SIZE_T, 0, _ObMemFile_AppendStringEx(pmf, uszFormat, arglist)); +} + /* * Retrieve byte count of the ObMemFile. * -- pmf @@ -198,15 +246,19 @@ QWORD ObMemFile_Size(_In_opt_ POB_MEMFILE pmf) /* * Create a new empty memory file. +* It's strongly recommended to supply a global cache map to use. * CALLER DECREF: return +* -- H +* -- pcmg = optional global (per VMM_HANDLE) cache map to use. * -- return */ _Success_(return != NULL) -POB_MEMFILE ObMemFile_New() +POB_MEMFILE ObMemFile_New(_In_opt_ VMM_HANDLE H, _In_opt_ POB_CACHEMAP pcmg) { - POB_MEMFILE pObMemFile = Ob_Alloc(OB_TAG_CORE_MEMFILE, LMEM_ZEROINIT, sizeof(OB_MEMFILE), (OB_CLEANUP_CB)_ObMemFile_ObCloseCallback, NULL); + POB_MEMFILE pObMemFile = Ob_AllocEx(H, OB_TAG_CORE_MEMFILE, LMEM_ZEROINIT, sizeof(OB_MEMFILE), (OB_CLEANUP_CB)_ObMemFile_ObCloseCallback, NULL); if(pObMemFile) { pObMemFile->Directory[0] = pObMemFile->Table0; + pObMemFile->pcm = Ob_INCREF(pcmg); } return pObMemFile; } diff --git a/vmm/ob/ob_set.c b/vmm/ob/ob_set.c index f09b35c..5b95249 100644 --- a/vmm/ob/ob_set.c +++ b/vmm/ob/ob_set.c @@ -18,6 +18,13 @@ #define OB_SET_ENTRIES_DIRECTORY 0x100 #define OB_SET_ENTRIES_TABLE 0x80 #define OB_SET_ENTRIES_STORE 0x200 +#define OB_SET_IS_VALID(p) (p && (p->ObHdr._magic2 == OB_HEADER_MAGIC) && (p->ObHdr._magic1 == OB_HEADER_MAGIC) && (p->ObHdr._tag == OB_TAG_CORE_SET)) +#define OB_SET_TABLE_MAX_CAPACITY OB_SET_ENTRIES_DIRECTORY * OB_SET_ENTRIES_TABLE * OB_SET_ENTRIES_STORE +#define OB_SET_HASH_FUNCTION(v) (13 * (v + _rotr16((WORD)v, 9) + _rotr((DWORD)v, 17) + _rotr64(v, 31))) + +#define OB_SET_INDEX_DIRECTORY(i) ((i >> 16) & (OB_SET_ENTRIES_DIRECTORY - 1)) +#define OB_SET_INDEX_TABLE(i) ((i >> 9) & (OB_SET_ENTRIES_TABLE - 1)) +#define OB_SET_INDEX_STORE(i) (i & (OB_SET_ENTRIES_STORE - 1)) typedef struct tdOB_SET_TABLE_ENTRY { union { @@ -49,10 +56,6 @@ typedef struct tdOB_SET { QWORD pStore00[OB_SET_ENTRIES_STORE]; } OB_SET, *POB_SET; -#define OB_SET_IS_VALID(p) (p && (p->ObHdr._magic == OB_HEADER_MAGIC) && (p->ObHdr._tag == OB_TAG_CORE_SET)) -#define TABLE_MAX_CAPACITY OB_SET_ENTRIES_DIRECTORY * OB_SET_ENTRIES_TABLE * OB_SET_ENTRIES_STORE -#define HASH_FUNCTION(v) (13 * (v + _rotr16((WORD)v, 9) + _rotr((DWORD)v, 17) + _rotr64(v, 31))) - #define OB_SET_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pvs, RetTp, RetValFail, fn) { \ if(!OB_SET_IS_VALID(pvs)) { return RetValFail; } \ RetTp retVal; \ @@ -106,11 +109,13 @@ VOID _ObSet_ObCloseCallback(_In_ POB_SET pObSet) * ways to store unique 64-bit (or smaller) numbers as a set. * The ObSet is an object manager object and must be DECREF'ed when required. * CALLER DECREF: return +* -- H +* -- hHeap * -- return */ -POB_SET ObSet_New() +POB_SET ObSet_New(_In_opt_ VMM_HANDLE H) { - POB_SET pObSet = Ob_Alloc(OB_TAG_CORE_SET, LMEM_ZEROINIT, sizeof(OB_SET), (OB_CLEANUP_CB)_ObSet_ObCloseCallback, NULL); + POB_SET pObSet = Ob_AllocEx(H, OB_TAG_CORE_SET, LMEM_ZEROINIT, sizeof(OB_SET), (OB_CLEANUP_CB)_ObSet_ObCloseCallback, NULL); if(!pObSet) { return NULL; } InitializeSRWLock(&pObSet->LockSRW); pObSet->c = 1; // item zero is reserved - hence the initialization of count to 1 @@ -122,20 +127,20 @@ POB_SET ObSet_New() QWORD _ObSet_GetValueFromIndex(_In_ POB_SET pvs, _In_ DWORD iValue) { - WORD iDirectory = (iValue >> 14) & (OB_SET_ENTRIES_DIRECTORY - 1); - WORD iTable = (iValue >> 9) & (OB_SET_ENTRIES_TABLE - 1); - WORD iValueStore = iValue & (OB_SET_ENTRIES_STORE - 1); + WORD iDirectory = OB_SET_INDEX_DIRECTORY(iValue); + WORD iTable = OB_SET_INDEX_TABLE(iValue); + WORD iValueStore = OB_SET_INDEX_STORE(iValue); if(!iValue || (iValue >= pvs->c)) { return 0; } return pvs->fLargeMode ? - pvs->pDirectory[iDirectory].pTable[iTable].pValues[iValueStore] : + pvs->pDirectory[OB_SET_INDEX_DIRECTORY(iValue)].pTable[iTable].pValues[iValueStore] : pvs->pTable0[iTable].pValues[iValueStore]; } VOID _ObSet_SetValueFromIndex(_In_ POB_SET pvs, _In_ DWORD iValue, _In_ QWORD qwValue) { - WORD iDirectory = (iValue >> 14) & (OB_SET_ENTRIES_DIRECTORY - 1); - WORD iTable = (iValue >> 9) & (OB_SET_ENTRIES_TABLE - 1); - WORD iValueStore = iValue & (OB_SET_ENTRIES_STORE - 1); + WORD iDirectory = OB_SET_INDEX_DIRECTORY(iValue); + WORD iTable = OB_SET_INDEX_TABLE(iValue); + WORD iValueStore = OB_SET_INDEX_STORE(iValue); if(pvs->fLargeMode) { pvs->pDirectory[iDirectory].pTable[iTable].pValues[iValueStore] = qwValue; } else { @@ -163,7 +168,7 @@ VOID _ObSet_InsertHash(_In_ POB_SET pvs, _In_ DWORD iValue) DWORD dwHashMask = pvs->cHashMax - 1; QWORD qwValueToHash = _ObSet_GetValueFromIndex(pvs, iValue); if(!qwValueToHash) { return; } - iHash = HASH_FUNCTION(qwValueToHash) & dwHashMask; + iHash = OB_SET_HASH_FUNCTION(qwValueToHash) & dwHashMask; while(_ObSet_GetIndexFromHash(pvs, iHash)) { iHash = (iHash + 1) & dwHashMask; } @@ -182,7 +187,7 @@ VOID _ObSet_RemoveHash(_In_ POB_SET pvs, _In_ DWORD iHash) iNextHash = (iNextHash + 1) & dwHashMask; iNextEntry = _ObSet_GetIndexFromHash(pvs, iNextHash); if(0 == iNextEntry) { return; } - iNextHashPreferred = HASH_FUNCTION(_ObSet_GetValueFromIndex(pvs, iNextEntry)) & dwHashMask; + iNextHashPreferred = OB_SET_HASH_FUNCTION(_ObSet_GetValueFromIndex(pvs, iNextEntry)) & dwHashMask; if(iNextHash == iNextHashPreferred) { continue; } if(pvs->fLargeMode) { pvs->pHashMapLarge[iNextHash] = 0; @@ -198,7 +203,7 @@ BOOL _ObSet_GetIndexFromValue(_In_ POB_SET pvs, _In_ QWORD v, _Out_opt_ PDWORD p { DWORD dwIndex; DWORD dwHashMask = pvs->cHashMax - 1; - DWORD dwHash = HASH_FUNCTION(v) & dwHashMask; + DWORD dwHash = OB_SET_HASH_FUNCTION(v) & dwHashMask; // scan hash table to find entry while(TRUE) { dwIndex = _ObSet_GetIndexFromHash(pvs, dwHash); @@ -272,7 +277,7 @@ POB_DATA _ObSet_GetAll(_In_ POB_SET pvs) { DWORD iValue; POB_DATA pObData; - if(!(pObData = Ob_Alloc(OB_TAG_CORE_DATA, 0, sizeof(OB) + (pvs->c - 1) * sizeof(QWORD), NULL, NULL))) { return NULL; } + if(!(pObData = Ob_AllocEx(pvs->ObHdr.H, OB_TAG_CORE_DATA, 0, sizeof(OB) + (pvs->c - 1) * sizeof(QWORD), NULL, NULL))) { return NULL; } for(iValue = pvs->c - 1; iValue; iValue--) { pObData->pqw[iValue - 1] = _ObSet_GetValueFromIndex(pvs, iValue); } @@ -403,11 +408,11 @@ BOOL _ObSet_Push(_In_ POB_SET pvs, _In_ QWORD value) { POB_SET_TABLE_ENTRY pTable = NULL; DWORD iValue = pvs->c; - WORD iDirectory = (iValue >> 14) & (OB_SET_ENTRIES_DIRECTORY - 1); - WORD iTable = (iValue >> 9) & (OB_SET_ENTRIES_TABLE - 1); - WORD iValueStore = iValue & (OB_SET_ENTRIES_STORE - 1); + WORD iDirectory = OB_SET_INDEX_DIRECTORY(iValue); + WORD iTable = OB_SET_INDEX_TABLE(iValue); + WORD iValueStore = OB_SET_INDEX_STORE(iValue); if((value == 0) || _ObSet_Exists(pvs, value)) { return FALSE; } - if(iValue == OB_SET_ENTRIES_DIRECTORY * OB_SET_ENTRIES_TABLE * OB_SET_ENTRIES_STORE) { return FALSE; } + if(iValue == OB_SET_TABLE_MAX_CAPACITY) { return FALSE; } if(iValue == pvs->cHashGrowThreshold) { if(!_ObSet_Grow(pvs)) { return FALSE; diff --git a/vmm/ob/ob_strmap.c b/vmm/ob/ob_strmap.c index 19ce9e3..a6d20f1 100644 --- a/vmm/ob/ob_strmap.c +++ b/vmm/ob/ob_strmap.c @@ -23,7 +23,7 @@ #include #define OB_STRMAP_SUBENTRY_SIZE 0x10 -#define OB_STRUMAP_IS_VALID(p) (p && (p->ObHdr._magic == OB_HEADER_MAGIC) && (p->ObHdr._tag == OB_TAG_CORE_STRMAP)) +#define OB_STRUMAP_IS_VALID(p) (p && (p->ObHdr._magic2 == OB_HEADER_MAGIC) && (p->ObHdr._magic1 == OB_HEADER_MAGIC) && (p->ObHdr._tag == OB_TAG_CORE_STRMAP)) typedef struct tdOB_STRMAP_PTRENTRY { union { @@ -451,8 +451,8 @@ VOID _ObStrMap_FinalizeDoWork_UnicodeResolve(_In_ POB_STRMAP psm) BYTE pbBuffer[sizeof(UNICODE_STRING64)]; if(psm->fFinalized) { return; } if(!psm->pUnicodeObjectListHead && !psm->pUnicodeBufferListHead) { return; } - if(!(psObPrefetch = ObSet_New())) { return; } - if(!(pObSystemProcess = VmmProcessGet(4))) { goto fail; } + if(!(psObPrefetch = ObSet_New(psm->ObHdr.H))) { return; } + if(!(pObSystemProcess = VmmProcessGet(psm->ObHdr.H, 4))) { goto fail; } // resolve unicode object pointers: if(psm->pUnicodeObjectListHead) { pu = psm->pUnicodeObjectListHead; @@ -460,10 +460,10 @@ VOID _ObStrMap_FinalizeDoWork_UnicodeResolve(_In_ POB_STRMAP psm) ObSet_Push_PageAlign(psObPrefetch, pu->va, pu->f32 ? sizeof(UNICODE_STRING32) : sizeof(UNICODE_STRING64)); pu = pu->FLink; } - VmmCachePrefetchPages(pObSystemProcess, psObPrefetch, 0); + VmmCachePrefetchPages(psm->ObHdr.H, pObSystemProcess, psObPrefetch, 0); pu = psm->pUnicodeObjectListHead; while(pu) { - if(VmmRead2(pObSystemProcess, pu->va, pbBuffer, pu->f32 ? sizeof(UNICODE_STRING32) : sizeof(UNICODE_STRING64), VMM_FLAG_FORCECACHE_READ)) { + if(VmmRead2(psm->ObHdr.H, pObSystemProcess, pu->va, pbBuffer, pu->f32 ? sizeof(UNICODE_STRING32) : sizeof(UNICODE_STRING64), VMM_FLAG_FORCECACHE_READ)) { f = pu->f32 ? _ObStrMap_Push_UnicodeBuffer(psm, ((PUNICODE_STRING32)pbBuffer)->Length, ((PUNICODE_STRING32)pbBuffer)->Buffer, pu->p.pusz, pu->p.pcbu) : _ObStrMap_Push_UnicodeBuffer(psm, ((PUNICODE_STRING64)pbBuffer)->Length, ((PUNICODE_STRING64)pbBuffer)->Buffer, pu->p.pusz, pu->p.pcbu); @@ -482,11 +482,11 @@ VOID _ObStrMap_FinalizeDoWork_UnicodeResolve(_In_ POB_STRMAP psm) ObSet_Push_PageAlign(psObPrefetch, pu->va, pu->cb); pu = pu->FLink; } - VmmCachePrefetchPages(pObSystemProcess, psObPrefetch, 0); + VmmCachePrefetchPages(psm->ObHdr.H, pObSystemProcess, psObPrefetch, 0); pu = psm->pUnicodeBufferListHead; while(pu) { wsz[0] = 0; - if(VmmRead2(pObSystemProcess, pu->va, (PBYTE)wsz, pu->cb, VMM_FLAG_FORCECACHE_READ)) { + if(VmmRead2(psm->ObHdr.H, pObSystemProcess, pu->va, (PBYTE)wsz, pu->cb, VMM_FLAG_FORCECACHE_READ)) { wsz[pu->cb >> 1] = 0; } _ObStrMap_PushPtr(psm, NULL, NULL, (LPWSTR)wsz, pu->p.pusz, pu->p.pcbu, NULL, NULL); @@ -578,9 +578,16 @@ BOOL _ObStrMap_FinalizeAlloc_DoWork(_In_ POB_STRMAP psm, _Out_ PBYTE *ppbMultiSt f = _ObStrMap_Finalize_FillBuffer(psm, 0, NULL, &cb, fWideChar) && (pb = LocalAlloc(0, cb)) && _ObStrMap_Finalize_FillBuffer(psm, cb, pb, &cb, fWideChar); - *ppbMultiStr = f ? pb : NULL; - *pcbMultiStr = f ? cb : 0; - return f; + if(f) { + *ppbMultiStr = pb; + *pcbMultiStr = cb; + return TRUE; + } else { + LocalFree(pb); + *ppbMultiStr = NULL; + *pcbMultiStr = 0; + return FALSE; + } } _Success_(return) @@ -685,18 +692,19 @@ BOOL ObStrMap_FinalizeBufferXUW(_In_opt_ POB_STRMAP psm, _In_ DWORD cbMultiStr, * decommissioned by calling any of the ObStrMap_Finalize*() functions. * The ObStrMap is an object manager object and must be DECREF'ed when required. * CALLER DECREF: return +* -- H * -- flags * -- return */ _Success_(return != NULL) -POB_STRMAP ObStrMap_New(_In_ QWORD flags) +POB_STRMAP ObStrMap_New(_In_opt_ VMM_HANDLE H, _In_ QWORD flags) { POB_STRMAP pObStrMap = NULL; POB_STRMAP_ENTRY pStrEntry = NULL; if((flags & OB_STRMAP_FLAGS_STR_ASSIGN_TEMPORARY) && (flags & OB_STRMAP_FLAGS_STR_ASSIGN_OFFSET)) { goto fail; } - if(!(pObStrMap = Ob_Alloc(OB_TAG_CORE_STRMAP, LMEM_ZEROINIT, sizeof(OB_STRMAP), (OB_CLEANUP_CB)_ObStrMap_ObCloseCallback, NULL))) { goto fail; } + if(!(pObStrMap = Ob_AllocEx(H, OB_TAG_CORE_STRMAP, LMEM_ZEROINIT, sizeof(OB_STRMAP), (OB_CLEANUP_CB)_ObStrMap_ObCloseCallback, NULL))) { goto fail; } if(!(pStrEntry = LocalAlloc(LMEM_ZEROINIT, sizeof(OB_STRMAP_ENTRY) + 1))) { goto fail; } // "" entry - if(!(pObStrMap->pm = ObMap_New(0))) { goto fail; } + if(!(pObStrMap->pm = ObMap_New(H, 0))) { goto fail; } pObStrMap->fCaseInsensitive = (flags & OB_STRMAP_FLAGS_CASE_INSENSITIVE) ? TRUE : FALSE; pObStrMap->fStrAssignTemporary = (flags & OB_STRMAP_FLAGS_STR_ASSIGN_TEMPORARY) ? TRUE : FALSE; pObStrMap->fStrAssignOffset = (flags & OB_STRMAP_FLAGS_STR_ASSIGN_OFFSET) ? TRUE : FALSE; diff --git a/vmm/ob/ob_tag.h b/vmm/ob/ob_tag.h index ddc46c1..ac50bc9 100644 --- a/vmm/ob/ob_tag.h +++ b/vmm/ob/ob_tag.h @@ -8,6 +8,7 @@ #include "ob.h" +#define OB_TAG_FORENSIC_FILE 'Ffil' #define OB_TAG_INFODB_CTX 'IDBC' #define OB_TAG_MAP_PTE 'Mpte' #define OB_TAG_MAP_VAD 'Mvad' @@ -31,6 +32,9 @@ #define OB_TAG_MAP_EVIL 'Mevl' #define OB_TAG_MAP_TASK 'Mtsk' #define OB_TAG_MAP_WEB 'Mweb' +#define OB_TAG_MOD_CERTIFICATES 'mCer' +#define OB_TAG_MOD_FCNTFS_CTX 'mFnt' +#define OB_TAG_MOD_FCTIMELINE 'mFtl' #define OB_TAG_MOD_MINIDUMP_CTX 'mMDx' #define OB_TAG_MOD_SEARCH_CTX 'mSHx' #define OB_TAG_OBJ_ERROR 'Oerr' @@ -38,15 +42,21 @@ #define OB_TAG_OBJ_DISPLAY 'Odis' #define OB_TAG_PDB_CTX 'PdbC' #define OB_TAG_PDB_ENTRY 'PdbE' +#define OB_TAG_PDB_KERNEL_CONTEXT 'PdbK' #define OB_TAG_PFN_CONTEXT 'PfnC' #define OB_TAG_PFN_PROC_TABLE 'PfnT' #define OB_TAG_REG_HIVE 'Rhve' #define OB_TAG_REG_KEY 'Rkey' #define OB_TAG_REG_KEYVALUE 'Rval' +#define OB_TAG_VAD_MEM 'MmSt' +#define OB_TAG_WORK_PER_PROCESS 'WrkP' +#define OB_TAG_WORK_WORKUNIT 'WrkU' #define OB_TAG_VMM_PROCESS 'Ps__' #define OB_TAG_VMM_PROCESS_CLONE 'PsC_' #define OB_TAG_VMM_PROCESS_PERSISTENT 'PsSt' #define OB_TAG_VMM_PROCESSTABLE 'PsTb' +#define OB_TAG_VMM_VIRT2PHYS 'PsVP' +#define OB_TAB_VMMDLL_EXTERNALMEM 'EXTM' #define OB_TAG_VMMVFS_DUMPCONTEXT 'CDmp' #endif /* __OB_TAG_H__ */ diff --git a/vmm/oscompatibility.c b/vmm/oscompatibility.c index b7bb737..088339a 100644 --- a/vmm/oscompatibility.c +++ b/vmm/oscompatibility.c @@ -81,6 +81,7 @@ BOOL CloseHandle(_In_ HANDLE hObject) if(hi->magic != OSCOMPATIBILITY_HANDLE_INTERNAL) { return FALSE; } switch(hi->type) { case OSCOMPATIBILITY_HANDLE_TYPE_THREAD: + pthread_join(((PHANDLE_INTERNAL_THREAD)hi)->thread, NULL); break; case OSCOMPATIBILITY_HANDLE_TYPE_EVENT: SetEvent(hObject); @@ -127,6 +128,7 @@ HANDLE CreateThread( status = pthread_create(&thread, NULL, lpStartAddress, lpParameter); if(status) { return NULL;} ph = malloc(sizeof(HANDLE_INTERNAL_THREAD)); + if(!ph) { return NULL; } ph->magic = OSCOMPATIBILITY_HANDLE_INTERNAL; ph->type = OSCOMPATIBILITY_HANDLE_TYPE_THREAD; ph->thread = thread; @@ -421,17 +423,17 @@ DWORD WaitForMultipleObjects(_In_ DWORD nCount, HANDLE *lpHandles, _In_ BOOL bWa } -BOOL SetEvent(_In_ HANDLE hEvent) +BOOL SetEvent(_In_ HANDLE hEventIngestPhys) { - PHANDLE_INTERNAL_EVENT2 ph = (PHANDLE_INTERNAL_EVENT2)hEvent; + PHANDLE_INTERNAL_EVENT2 ph = (PHANDLE_INTERNAL_EVENT2)hEventIngestPhys; if((ph->magic != OSCOMPATIBILITY_HANDLE_INTERNAL) || (ph->type != OSCOMPATIBILITY_HANDLE_TYPE_EVENT)) { return FALSE; } ReleaseSRWLockExclusive(&ph->SRWLock); return TRUE; } -BOOL ResetEvent(_In_ HANDLE hEvent) +BOOL ResetEvent(_In_ HANDLE hEventIngestPhys) { - PHANDLE_INTERNAL_EVENT2 ph = (PHANDLE_INTERNAL_EVENT2)hEvent; + PHANDLE_INTERNAL_EVENT2 ph = (PHANDLE_INTERNAL_EVENT2)hEventIngestPhys; if((ph->magic != OSCOMPATIBILITY_HANDLE_INTERNAL) || (ph->type != OSCOMPATIBILITY_HANDLE_TYPE_EVENT)) { return FALSE; } return AcquireSRWLockExclusive_Try(&ph->SRWLock); } @@ -511,4 +513,12 @@ errno_t tmpnam_s(char *_Buffer, ssize_t _Size) return 0; } +int _vscprintf(_In_z_ _Printf_format_string_ char const *const _Format, va_list _ArgList) +{ + char *sz = NULL; + int len = vasprintf(&sz, _Format, _ArgList); + free(sz); + return len; +} + #endif /* LINUX */ diff --git a/vmm/oscompatibility.h b/vmm/oscompatibility.h index 576a449..3455661 100644 --- a/vmm/oscompatibility.h +++ b/vmm/oscompatibility.h @@ -12,6 +12,7 @@ #include #include +#define VMM_LIBRARY_FILETYPE ".dll" #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) #define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L) #define STATUS_END_OF_FILE ((NTSTATUS)0xC0000011L) @@ -43,7 +44,7 @@ typedef unsigned __int64 QWORD, *PQWORD; #include #include -#define LC_LIBRARY_FILETYPE ".so" +#define VMM_LIBRARY_FILETYPE ".so" typedef void VOID, *PVOID, *LPVOID; typedef void *HANDLE, **PHANDLE, *HMODULE, *FARPROC; @@ -90,6 +91,7 @@ typedef int(*_CoreCrtNonSecureSearchSortCompareFunction)(void const *, void cons #define STILL_ACTIVE (0x00000103L) #define INVALID_FILE_SIZE (0xffffffffL) #define _TRUNCATE ((SIZE_T)-1LL) +#define HEAP_ZERO_MEMORY 0x00000008 #define CONSOLE_SCREEN_BUFFER_INFO PVOID // TODO: remove this dummy #define SOCKET int #define INVALID_SOCKET -1 @@ -112,35 +114,37 @@ typedef int(*_CoreCrtNonSecureSearchSortCompareFunction)(void const *, void cons //----------------------------------------------------------------------------- // SAL DEFINES BELOW: //----------------------------------------------------------------------------- -#define _In_ -#define _In_z_ -#define _Out_ -#define _Inout_ -#define _Inout_opt_ -#define _In_opt_ -#define _In_opt_z_ -#define _Out_opt_ #define _Check_return_opt_ #define _Frees_ptr_opt_ -#define _Post_ptr_invalid_ -#define _Printf_format_string_ +#define _In_ +#define _In_count_(x) +#define _In_opt_ +#define _In_opt_z_ #define _In_reads_(x) #define _In_reads_opt_(x) -#define _Out_writes_(x) -#define __bcount(x) +#define _In_z_ +#define _Inout_ #define _Inout_bytecount_(x) #define _Inout_count_(x) +#define _Inout_opt_ #define _Inout_updates_(x) -#define _Inout_updates_opt_(x) #define _Inout_updates_bytes_(x) +#define _Inout_updates_opt_(x) +#define _Maybenull_ +#define _Out_ +#define _Out_opt_ +#define _Out_writes_(x) +#define _Out_writes_bytes_(x) #define _Out_writes_bytes_opt_(x) #define _Out_writes_opt_(x) #define _Out_writes_to_(x,y) #define _Out_writes_z_(x) -#define _Maybenull_ +#define _Post_ptr_invalid_ +#define _Printf_format_string_ #define _Success_(x) #define _When_(x,y) #define _Writable_bytes_(x) +#define __bcount(x) #define UNREFERENCED_PARAMETER(x) @@ -150,7 +154,7 @@ typedef int(*_CoreCrtNonSecureSearchSortCompareFunction)(void const *, void cons #define _byteswap_ulong(v) (bswap_32(v)) #define _byteswap_uint64(v) (bswap_64(v)) #ifndef _rotr -#define _rotr(v,c) ((((DWORD)v) >> ((DWORD)c) | (DWORD)((DWORD)v) << (32 - (DWORD)c))) +#define _rotr(v,c) ((((DWORD)v) >> ((DWORD)c) | (DWORD)((DWORD)v) << (32 - (DWORD)c))) #endif /* _rotr */ #define _rotr16(v,c) ((((WORD)v) >> ((WORD)c) | (WORD)((WORD)v) << (16 - (WORD)c))) #define _rotr64(v,c) ((((QWORD)v) >> ((QWORD)c) | (QWORD)((QWORD)v) << (64 - (QWORD)c))) @@ -159,14 +163,14 @@ typedef int(*_CoreCrtNonSecureSearchSortCompareFunction)(void const *, void cons #define sprintf_s(s, maxcount, ...) (snprintf(s, maxcount, __VA_ARGS__)) #define strnlen_s(s, maxcount) (strnlen(s, maxcount)) #define strcpy_s(dst, len, src) (strncpy(dst, src, len)) -#define strncpy_s(dst, len, src, srclen) (strncpy(dst, src, min((QWORD)(max(1, len)) - 1, (QWORD)(srclen)))) +#define strncpy_s(dst, len, src, srclen) (strncpy(dst, src, min((size_t)(max(1, len)) - 1, (size_t)(srclen)))) #define strncat_s(dst, dstlen, src, srclen) (strncat(dst, src, min((((strlen(dst) + 1 >= (size_t)(dstlen)) || ((size_t)(dstlen) == 0)) ? 0 : ((size_t)(dstlen) - strlen(dst) - 1)), (size_t)(srclen)))) #define strcat_s(dst, dstlen, src) (strncat_s(dst, dstlen, src, _TRUNCATE)) -#define _vsnprintf_s(dst, len, cnt, fmt, a) (vsnprintf(dst, min((QWORD)(len), (QWORD)(cnt)), fmt, a)) +#define _vsnprintf_s(dst, len, cnt, fmt, a) (vsnprintf(dst, min((size_t)(len), (size_t)(cnt)), fmt, a)) #define _stricmp(s1, s2) (strcasecmp(s1, s2)) #define _strnicmp(s1, s2, maxcount) (strncasecmp(s1, s2, maxcount)) #define strtok_s(s, d, c) (strtok_r(s, d, c)) -#define _snprintf_s(s,l,c,...) (snprintf(s,min((QWORD)(l), (QWORD)(c)),__VA_ARGS__)) +#define _snprintf_s(s,l,c,...) (snprintf(s,min((size_t)(l), (size_t)(c)),__VA_ARGS__)) #define sscanf_s(s, f, ...) (sscanf(s, f, __VA_ARGS__)) #define SwitchToThread() (sched_yield()) #define ExitThread(dwExitCode) (pthread_exit(dwExitCode)) @@ -188,6 +192,7 @@ typedef int(*_CoreCrtNonSecureSearchSortCompareFunction)(void const *, void cons #define closesocket(s) close(s) #define FreeLibrary(h) #define GetModuleHandleA(s) NULL +#define HeapAlloc(hHeap, dwFlags, dwBytes) malloc(dwBytes) HMODULE LoadLibraryA(LPSTR lpFileName); FARPROC GetProcAddress(HMODULE hModule, LPSTR lpProcName); @@ -246,11 +251,12 @@ HANDLE CreateThread( ); BOOL CloseHandle(_In_ HANDLE hObject); -BOOL ResetEvent(_In_ HANDLE hEvent); -BOOL SetEvent(_In_ HANDLE hEvent); +BOOL ResetEvent(_In_ HANDLE hEventIngestPhys); +BOOL SetEvent(_In_ HANDLE hEventIngestPhys); HANDLE CreateEvent(_In_opt_ PVOID lpEventAttributes, _In_ BOOL bManualReset, _In_ BOOL bInitialState, _In_opt_ PVOID lpName); DWORD WaitForMultipleObjects(_In_ DWORD nCount, HANDLE *lpHandles, _In_ BOOL bWaitAll, _In_ DWORD dwMilliseconds); DWORD WaitForSingleObject(_In_ HANDLE hHandle, _In_ DWORD dwMilliseconds); +int _vscprintf(_In_z_ _Printf_format_string_ char const *const _Format, va_list _ArgList); // for some unexplainable reasons the gcc on -O2 will optimize out functionality // and destroy the proper workings on some functions due to an unexplainable diff --git a/vmm/pdb.c b/vmm/pdb.c index 7dee65c..70e40ee 100644 --- a/vmm/pdb.c +++ b/vmm/pdb.c @@ -12,36 +12,39 @@ #include "util.h" #include "vmmwindef.h" #include "vmmwininit.h" +#include "ob/ob.h" +#include "ob/ob_tag.h" -VOID PDB_PrintError(_In_ LPSTR szErrorMessage) +VOID PDB_PrintError(_In_ VMM_HANDLE H, _In_ LPSTR szErrorMessage) { BOOL fInfoDB_Ntos; DWORD dwTimeDateStamp = 0; PVMM_PROCESS pObSystemProcess; - InfoDB_IsValidSymbols(&fInfoDB_Ntos, NULL); + InfoDB_IsValidSymbols(H, &fInfoDB_Ntos, NULL); if(fInfoDB_Ntos) { - VmmLog(MID_PDB, LOGLEVEL_WARNING, "Functionality may be limited. Extended debug information disabled"); - VmmLog(MID_PDB, LOGLEVEL_WARNING, "Partial offline fallback symbols in use"); - VmmLog(MID_PDB, LOGLEVEL_WARNING, "%s\n", szErrorMessage); + VmmLog(H, MID_PDB, LOGLEVEL_WARNING, "Functionality may be limited. Extended debug information disabled"); + VmmLog(H, MID_PDB, LOGLEVEL_WARNING, "Partial offline fallback symbols in use"); + VmmLog(H, MID_PDB, LOGLEVEL_WARNING, "%s\n", szErrorMessage); return; } - if(InfoDB_IsInitialized()) { - if((pObSystemProcess = VmmProcessGet(4))) { - PE_GetTimeDateStampCheckSum(pObSystemProcess, ctxVmm->kernel.vaBase, &dwTimeDateStamp, NULL); + if(InfoDB_IsInitialized(H)) { + if((pObSystemProcess = VmmProcessGet(H, 4))) { + PE_GetTimeDateStampCheckSum(H, pObSystemProcess, H->vmm.kernel.vaBase, &dwTimeDateStamp, NULL); Ob_DECREF_NULL(&pObSystemProcess); } - VmmLog(MID_PDB, LOGLEVEL_WARNING, "Functionality may be limited. Extended debug information disabled"); - VmmLog(MID_PDB, LOGLEVEL_WARNING, "Offline symbols unavailable - ID: %08X%X", dwTimeDateStamp, (DWORD)ctxVmm->kernel.cbSize); - VmmLog(MID_PDB, LOGLEVEL_WARNING, "%s\n", szErrorMessage); + VmmLog(H, MID_PDB, LOGLEVEL_WARNING, "Functionality may be limited. Extended debug information disabled"); + VmmLog(H, MID_PDB, LOGLEVEL_WARNING, "Offline symbols unavailable - ID: %08X%X", dwTimeDateStamp, (DWORD)H->vmm.kernel.cbSize); + VmmLog(H, MID_PDB, LOGLEVEL_WARNING, "%s\n", szErrorMessage); } else { - VmmLog(MID_PDB, LOGLEVEL_WARNING, "Functionality may be limited. Extended debug information disabled"); - VmmLog(MID_PDB, LOGLEVEL_WARNING, "Offline symbols unavailable - file 'info.db' not found"); - VmmLog(MID_PDB, LOGLEVEL_WARNING, "%s\n", szErrorMessage); + VmmLog(H, MID_PDB, LOGLEVEL_WARNING, "Functionality may be limited. Extended debug information disabled"); + VmmLog(H, MID_PDB, LOGLEVEL_WARNING, "Offline symbols unavailable - file 'info.db' not found"); + VmmLog(H, MID_PDB, LOGLEVEL_WARNING, "%s\n", szErrorMessage); } } /* * Read memory pointed to at the PDB acquired symbol offset. +* -- H * -- hPDB * -- szSymbolName * -- pProcess @@ -49,13 +52,14 @@ VOID PDB_PrintError(_In_ LPSTR szErrorMessage) * -- return */ _Success_(return) -BOOL PDB_GetSymbolQWORD(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PQWORD pqw) +BOOL PDB_GetSymbolQWORD(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PQWORD pqw) { - return PDB_GetSymbolPBYTE(hPDB, szSymbolName, pProcess, (PBYTE)pqw, sizeof(QWORD)); + return PDB_GetSymbolPBYTE(H, hPDB, szSymbolName, pProcess, (PBYTE)pqw, sizeof(QWORD)); } /* * Read memory pointed to at the PDB acquired symbol offset. +* -- H * -- hPDB * -- szSymbolName * -- pProcess @@ -63,13 +67,14 @@ BOOL PDB_GetSymbolQWORD(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _In_ * -- return */ _Success_(return) -BOOL PDB_GetSymbolDWORD(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PDWORD pdw) +BOOL PDB_GetSymbolDWORD(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PDWORD pdw) { - return PDB_GetSymbolPBYTE(hPDB, szSymbolName, pProcess, (PBYTE)pdw, sizeof(DWORD)); + return PDB_GetSymbolPBYTE(H, hPDB, szSymbolName, pProcess, (PBYTE)pdw, sizeof(DWORD)); } /* * Read memory pointed to at the PDB acquired symbol offset. +* -- H * -- hPDB * -- szSymbolName * -- pProcess @@ -77,13 +82,14 @@ BOOL PDB_GetSymbolDWORD(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _In_ * -- return */ _Success_(return) -BOOL PDB_GetSymbolPTR(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PVOID pv) +BOOL PDB_GetSymbolPTR(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PVOID pv) { - return PDB_GetSymbolPBYTE(hPDB, szSymbolName, pProcess, (PBYTE)pv, (ctxVmm->f32 ? sizeof(DWORD) : sizeof(QWORD))); + return PDB_GetSymbolPBYTE(H, hPDB, szSymbolName, pProcess, (PBYTE)pv, (H->vmm.f32 ? sizeof(DWORD) : sizeof(QWORD))); } /* * Read memory at the PDB acquired symbol offset and virtual address base. +* -- H * -- hPDB * -- vaBase * -- szSymbolName = wildcard symbol name @@ -93,15 +99,16 @@ BOOL PDB_GetSymbolPTR(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _In_ PV * -- return */ _Success_(return) -BOOL PDB_GetSymbolPBYTE2(_In_opt_ PDB_HANDLE hPDB, _In_ QWORD vaBase, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb) +BOOL PDB_GetSymbolPBYTE2(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ QWORD vaBase, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb) { DWORD dwSymbolOffset; - if(!PDB_GetSymbolOffset(hPDB, szSymbolName, &dwSymbolOffset)) { return FALSE; } - return VmmRead(pProcess, vaBase + dwSymbolOffset, pb, cb); + if(!PDB_GetSymbolOffset(H, hPDB, szSymbolName, &dwSymbolOffset)) { return FALSE; } + return VmmRead(H, pProcess, vaBase + dwSymbolOffset, pb, cb); } /* * Read memory pointed to at the PDB acquired symbol offset and virtual address base. +* -- H * -- hPDB * -- vaBase * -- szSymbolName @@ -110,13 +117,14 @@ BOOL PDB_GetSymbolPBYTE2(_In_opt_ PDB_HANDLE hPDB, _In_ QWORD vaBase, _In_ LPSTR * -- return */ _Success_(return) -BOOL PDB_GetSymbolQWORD2(_In_opt_ PDB_HANDLE hPDB, _In_ QWORD vaBase, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PQWORD pqw) +BOOL PDB_GetSymbolQWORD2(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ QWORD vaBase, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PQWORD pqw) { - return PDB_GetSymbolPBYTE2(hPDB, vaBase, szSymbolName, pProcess, (PBYTE)pqw, sizeof(QWORD)); + return PDB_GetSymbolPBYTE2(H, hPDB, vaBase, szSymbolName, pProcess, (PBYTE)pqw, sizeof(QWORD)); } /* * Read memory pointed to at the PDB acquired symbol offset and virtual address base. +* -- H * -- hPDB * -- vaBase * -- szSymbolName @@ -125,13 +133,14 @@ BOOL PDB_GetSymbolQWORD2(_In_opt_ PDB_HANDLE hPDB, _In_ QWORD vaBase, _In_ LPSTR * -- return */ _Success_(return) -BOOL PDB_GetSymbolDWORD2(_In_opt_ PDB_HANDLE hPDB, _In_ QWORD vaBase, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PDWORD pdw) +BOOL PDB_GetSymbolDWORD2(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ QWORD vaBase, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PDWORD pdw) { - return PDB_GetSymbolPBYTE2(hPDB, vaBase, szSymbolName, pProcess, (PBYTE)pdw, sizeof(DWORD)); + return PDB_GetSymbolPBYTE2(H, hPDB, vaBase, szSymbolName, pProcess, (PBYTE)pdw, sizeof(DWORD)); } /* * Read memory pointed to at the PDB acquired symbol offset and virtual address base. +* -- H * -- hPDB * -- vaBase * -- szSymbolName @@ -140,9 +149,9 @@ BOOL PDB_GetSymbolDWORD2(_In_opt_ PDB_HANDLE hPDB, _In_ QWORD vaBase, _In_ LPSTR * -- return */ _Success_(return) -BOOL PDB_GetSymbolPTR2(_In_opt_ PDB_HANDLE hPDB, _In_ QWORD vaBase, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PVOID pv) +BOOL PDB_GetSymbolPTR2(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ QWORD vaBase, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PVOID pv) { - return PDB_GetSymbolPBYTE2(hPDB, vaBase, szSymbolName, pProcess, (PBYTE)pv, (ctxVmm->f32 ? sizeof(DWORD) : sizeof(QWORD))); + return PDB_GetSymbolPBYTE2(H, hPDB, vaBase, szSymbolName, pProcess, (PBYTE)pv, (H->vmm.f32 ? sizeof(DWORD) : sizeof(QWORD))); } /* @@ -165,22 +174,24 @@ LPSTR PDB_ModuleNameFromHandleMagic(_In_ PDB_HANDLE hPDB) /* * Wrapper for Query the InfoDB for the offset of a symbol. * NB! Query must be done with magic PDB handle to succeed. +* -- H * -- hPDB = magic PDB handle. * -- szSymbolName * -- pdwSymbolOffset * -- return */ _Success_(return) -BOOL PDB_InfoDB_SymbolOffset(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _Out_ PDWORD pdwSymbolOffset) +BOOL PDB_InfoDB_SymbolOffset(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _Out_ PDWORD pdwSymbolOffset) { LPSTR szModule = PDB_ModuleNameFromHandleMagic(hPDB); if(!szModule) { return FALSE; } - return InfoDB_SymbolOffset(szModule, szSymbolName, pdwSymbolOffset); + return InfoDB_SymbolOffset(H, szModule, szSymbolName, pdwSymbolOffset); } /* * Wrapper for Query the InfoDB for the size of a type. * NB! Query must be done with magic PDB handle to succeed. +* * -- hPDB = magic PDB handle. * -- szTypeName * -- pdwTypeSize @@ -188,20 +199,21 @@ BOOL PDB_InfoDB_SymbolOffset(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, * -- return */ _Success_(return) -BOOL PDB_InfoDB_TypeSize(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _Out_ PDWORD pdwTypeSize, _In_ BOOL fDynamic) +BOOL PDB_InfoDB_TypeSize(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _Out_ PDWORD pdwTypeSize, _In_ BOOL fDynamic) { LPSTR szModule = PDB_ModuleNameFromHandleMagic(hPDB); if(!szModule) { return FALSE; } if(fDynamic) { - return InfoDB_TypeSize_Dynamic(szModule, szTypeName, pdwTypeSize); + return InfoDB_TypeSize_Dynamic(H, szModule, szTypeName, pdwTypeSize); } else { - return InfoDB_TypeSize_Static(szModule, szTypeName, pdwTypeSize); + return InfoDB_TypeSize_Static(H, szModule, szTypeName, pdwTypeSize); } } /* * Wrapper for Query the InfoDB for the offset of a child inside a type - often inside a struct. * NB! Query must be done with magic PDB handle to succeed. +* -- H * -- hPDB = magic PDB handle. * -- szTypeName * -- uszTypeChildName @@ -210,14 +222,14 @@ BOOL PDB_InfoDB_TypeSize(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _Out_ * -- return */ _Success_(return) -BOOL PDB_InfoDB_TypeChildOffset(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _In_ LPSTR uszTypeChildName, _Out_ PDWORD pdwTypeOffset, _In_ BOOL fDynamic) +BOOL PDB_InfoDB_TypeChildOffset(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _In_ LPSTR uszTypeChildName, _Out_ PDWORD pdwTypeOffset, _In_ BOOL fDynamic) { LPSTR szModule = PDB_ModuleNameFromHandleMagic(hPDB); if(!szModule) { return FALSE; } if(fDynamic) { - return InfoDB_TypeChildOffset_Dynamic(szModule, szTypeName, uszTypeChildName, pdwTypeOffset); + return InfoDB_TypeChildOffset_Dynamic(H, szModule, szTypeName, uszTypeChildName, pdwTypeOffset); } else { - return InfoDB_TypeChildOffset_Static(szModule, szTypeName, uszTypeChildName, pdwTypeOffset); + return InfoDB_TypeChildOffset_Static(H, szModule, szTypeName, uszTypeChildName, pdwTypeOffset); } } @@ -294,11 +306,12 @@ typedef struct tdOB_PDB_CONTEXT { }; } OB_PDB_CONTEXT, *POB_PDB_CONTEXT; -typedef struct tdVMMWIN_PDB_INITIALIZE_KERNEL_PARAMETERS { +typedef struct tdOB_PDB_INITIALIZE_KERNEL_PARAMETERS { + OB ObHdr; PHANDLE phEventThreadStarted; BOOL fPdbInfo; PE_CODEVIEW_INFO PdbInfo; -} VMMWIN_PDB_INITIALIZE_KERNEL_PARAMETERS, *PVMMWIN_PDB_INITIALIZE_KERNEL_PARAMETERS; +} OB_PDB_INITIALIZE_KERNEL_PARAMETERS, *POB_PDB_INITIALIZE_KERNEL_PARAMETERS; QWORD PDB_HashPdb(_In_ LPSTR szPdbName, _In_reads_(16) PBYTE pbPdbGUID, _In_ DWORD dwPdbAge) { @@ -326,29 +339,30 @@ VOID PDB_CallbackCleanup_ObPdbEntry(PPDB_ENTRY pOb) */ VOID PDB_CallbackCleanup_ObPdbContext(POB_PDB_CONTEXT ctx) { - if(ctx->hSym) { - ctx->pfn.SymCleanup(ctx->hSym); - } + if(ctx->hSym) { ctx->pfn.SymCleanup(ctx->hSym); } Ob_DECREF(ctx->pmPdbByHash); Ob_DECREF(ctx->pmPdbByModule); - if(ctx->hModuleDbgHelp) { FreeLibrary(ctx->hModuleDbgHelp); } if(ctx->hModuleSymSrv) { FreeLibrary(ctx->hModuleSymSrv); } + if(ctx->hModuleDbgHelp) { FreeLibrary(ctx->hModuleDbgHelp); } + DeleteCriticalSection(&ctx->Lock); } /* * Retrieve the current PDB context * CALLER DECREF: return +* -- H * -- return */ -POB_PDB_CONTEXT PDB_GetContext() +POB_PDB_CONTEXT PDB_GetContext(_In_ VMM_HANDLE H) { - return Ob_INCREF(ctxVmm->pObPdbContext); + return Ob_INCREF(H->vmm.pObPdbContext); } /* * Add a module to the PDB database and return its handle. * NB! The PDB for the added module won't be loaded until required. +* -- H * -- vaModuleBase * -- cbModuleSize = optional size of the module (required if using GetSymbolFromAddress functionality). * -- szModuleName @@ -357,16 +371,16 @@ POB_PDB_CONTEXT PDB_GetContext() * -- dwPdbAge * -- return = The PDB handle on success (no need to close handle); or zero on fail. */ -PDB_HANDLE PDB_AddModuleEntry(_In_ QWORD vaModuleBase, _In_opt_ DWORD cbModuleSize, _In_ LPSTR szModuleName, _In_ LPSTR szPdbName, _In_reads_(16) PBYTE pbPdbGUID, _In_ DWORD dwPdbAge) +PDB_HANDLE PDB_AddModuleEntry(_In_ VMM_HANDLE H, _In_ QWORD vaModuleBase, _In_opt_ DWORD cbModuleSize, _In_ LPSTR szModuleName, _In_ LPSTR szPdbName, _In_reads_(16) PBYTE pbPdbGUID, _In_ DWORD dwPdbAge) { - POB_PDB_CONTEXT ctxOb = PDB_GetContext(); + POB_PDB_CONTEXT ctxOb = PDB_GetContext(H); PPDB_ENTRY pObPdbEntry; QWORD qwPdbHash = 0; if(!ctxOb) { return 0; } qwPdbHash = PDB_HashPdb(szPdbName, pbPdbGUID, dwPdbAge); EnterCriticalSection(&ctxOb->Lock); if(!ObMap_ExistsKey(ctxOb->pmPdbByHash, qwPdbHash)) { - pObPdbEntry = Ob_Alloc(OB_TAG_PDB_ENTRY, LMEM_ZEROINIT, sizeof(PDB_ENTRY), PDB_CallbackCleanup_ObPdbEntry, NULL); + pObPdbEntry = Ob_AllocEx(H, OB_TAG_PDB_ENTRY, LMEM_ZEROINIT, sizeof(PDB_ENTRY), PDB_CallbackCleanup_ObPdbEntry, NULL); if(!pObPdbEntry) { goto fail; } pObPdbEntry->dwAge = dwPdbAge; pObPdbEntry->qwHash = qwPdbHash; @@ -394,9 +408,9 @@ fail: * -- vaModuleBase * -- return = The PDB handle on success (no need to close handle); or zero on fail. */ -PDB_HANDLE PDB_GetHandleFromModuleAddress(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase) +PDB_HANDLE PDB_GetHandleFromModuleAddress(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase) { - POB_PDB_CONTEXT ctxOb = PDB_GetContext(); + POB_PDB_CONTEXT ctxOb = PDB_GetContext(H); PPDB_ENTRY pObPdbEntry = 0; PE_CODEVIEW_INFO CodeViewInfo = { 0 }; DWORD i, iMax; @@ -417,13 +431,14 @@ PDB_HANDLE PDB_GetHandleFromModuleAddress(_In_ PVMM_PROCESS pProcess, _In_ QWORD } Ob_DECREF_NULL(&ctxOb); // retrieve codeview and add to .pdb database. - if(!(cbModuleSize = PE_GetSize(pProcess, vaModuleBase)) || (cbModuleSize > 0x04000000)) { return 0; } - if(!PE_GetCodeViewInfo(pProcess, vaModuleBase, NULL, &CodeViewInfo)) { return 0; } + if(!(cbModuleSize = PE_GetSize(H, pProcess, vaModuleBase)) || (cbModuleSize > 0x04000000)) { return 0; } + if(!PE_GetCodeViewInfo(H, pProcess, vaModuleBase, NULL, &CodeViewInfo)) { return 0; } strcpy_s(szModuleName, MAX_PATH, CodeViewInfo.CodeView.PdbFileName); if((szPdbText = strstr(szModuleName, ".pdb"))) { szPdbText[0] = 0; } return PDB_AddModuleEntry( + H, vaModuleBase, (DWORD)cbModuleSize, szModuleName, @@ -437,12 +452,13 @@ PDB_HANDLE PDB_GetHandleFromModuleAddress(_In_ PVMM_PROCESS pProcess, _In_ QWORD * Retrieve a PDB handle from an already added module. * NB! If multiple modules exists with the same name the 1st module to be added * is returned. +* -- H * -- szModuleName * -- return = The PDB handle on success (no need to close handle); or zero on fail. */ -PDB_HANDLE PDB_GetHandleFromModuleName(_In_ LPSTR szModuleName) +PDB_HANDLE PDB_GetHandleFromModuleName(_In_ VMM_HANDLE H, _In_ LPSTR szModuleName) { - POB_PDB_CONTEXT ctxOb = PDB_GetContext(); + POB_PDB_CONTEXT ctxOb = PDB_GetContext(H); PPDB_ENTRY pObPdbEntry = NULL; QWORD qwHashPdb = 0; DWORD dwHashModule; @@ -461,13 +477,14 @@ fail: /* * Get a valid PDB handle given an ordinary or magic PDB handle. +* -- H * -- hPDB = ordinary or magic PDB handle. * -- return = ordinary PDB handle (or 0 on fail). */ -PDB_HANDLE PDB_GetHandleFromHandleMagic(_In_ PDB_HANDLE hPDB) +PDB_HANDLE PDB_GetHandleFromHandleMagic(_In_ VMM_HANDLE H, _In_ PDB_HANDLE hPDB) { LPSTR szModule = PDB_ModuleNameFromHandleMagic(hPDB); - return szModule ? PDB_GetHandleFromModuleName(szModule) : hPDB; + return szModule ? PDB_GetHandleFromModuleName(H, szModule) : hPDB; } /* @@ -495,17 +512,18 @@ fail: /* * Ensure that the PDB_HANDLE have its symbols loaded into memory. +* -- H * -- hPDB * -- return */ _Success_(return) -BOOL PDB_LoadEnsure(_In_opt_ PDB_HANDLE hPDB) +BOOL PDB_LoadEnsure(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB) { - POB_PDB_CONTEXT ctxOb = PDB_GetContext(); + POB_PDB_CONTEXT ctxOb = PDB_GetContext(H); PPDB_ENTRY pObPdbEntry = NULL; BOOL fResult = FALSE; if(!ctxOb || ctxOb->fDisabled) { goto fail; } - if(!(hPDB = PDB_GetHandleFromHandleMagic(hPDB))) { goto fail; } + if(!(hPDB = PDB_GetHandleFromHandleMagic(H, hPDB))) { goto fail; } if(!(pObPdbEntry = ObMap_GetByKey(ctxOb->pmPdbByHash, hPDB))) { goto fail; } EnterCriticalSection(&ctxOb->Lock); fResult = PDB_LoadEnsureEx(ctxOb, pObPdbEntry); @@ -518,6 +536,7 @@ fail: /* * Return module information given a PDB handle. +* -- H * -- hPDB * -- szModuleName = buffer to receive module name upon success. * -- pvaModuleBase @@ -525,13 +544,13 @@ fail: * -- return */ _Success_(return) -BOOL PDB_GetModuleInfo(_In_opt_ PDB_HANDLE hPDB, _Out_writes_opt_(MAX_PATH) LPSTR szModuleName, _Out_opt_ PQWORD pvaModuleBase, _Out_opt_ PDWORD pcbModuleSize) +BOOL PDB_GetModuleInfo(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _Out_writes_opt_(MAX_PATH) LPSTR szModuleName, _Out_opt_ PQWORD pvaModuleBase, _Out_opt_ PDWORD pcbModuleSize) { - POB_PDB_CONTEXT ctxOb = PDB_GetContext(); + POB_PDB_CONTEXT ctxOb = PDB_GetContext(H); PPDB_ENTRY pObPdbEntry = NULL; BOOL fResult = FALSE; if(!ctxOb || ctxOb->fDisabled) { goto fail; } - if(!(hPDB = PDB_GetHandleFromHandleMagic(hPDB))) { goto fail; } + if(!(hPDB = PDB_GetHandleFromHandleMagic(H, hPDB))) { goto fail; } if(!(pObPdbEntry = ObMap_GetByKey(ctxOb->pmPdbByHash, hPDB))) { goto fail; } if(szModuleName) { strncpy_s(szModuleName, MAX_PATH, pObPdbEntry->szModuleName, MAX_PATH - 1); @@ -562,25 +581,26 @@ BOOL PDB_GetSymbolOffset_Callback(_In_ PSYMBOL_INFO pSymInfo, _In_ ULONG SymbolS /* * Query the PDB for the offset of a symbol. +* -- H * -- hPDB * -- szSymbolName * -- pdwSymbolOffset * -- return */ _Success_(return) -BOOL PDB_GetSymbolOffset(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _Out_ PDWORD pdwSymbolOffset) +BOOL PDB_GetSymbolOffset(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _Out_ PDWORD pdwSymbolOffset) { - POB_PDB_CONTEXT ctxOb = PDB_GetContext(); + POB_PDB_CONTEXT ctxOb = PDB_GetContext(H); SYMBOL_INFO SymbolInfo = { 0 }; PPDB_ENTRY pObPdbEntry = NULL; *pdwSymbolOffset = 0; - if(PDB_InfoDB_SymbolOffset(hPDB, szSymbolName, pdwSymbolOffset)) { Ob_DECREF(ctxOb); return TRUE; } + if(PDB_InfoDB_SymbolOffset(H, hPDB, szSymbolName, pdwSymbolOffset)) { Ob_DECREF(ctxOb); return TRUE; } if(!ctxOb || ctxOb->fDisabled) { goto fail; } - if(!(hPDB = PDB_GetHandleFromHandleMagic(hPDB))) { goto fail; } + if(!(hPDB = PDB_GetHandleFromHandleMagic(H, hPDB))) { goto fail; } if(!(pObPdbEntry = ObMap_GetByKey(ctxOb->pmPdbByHash, hPDB))) { goto fail; } EnterCriticalSection(&ctxOb->Lock); if(PDB_LoadEnsureEx(ctxOb, pObPdbEntry)) { - if(!ctxVmm->f32) { + if(!H->vmm.f32) { // 64-bit: use faster algo SymbolInfo.SizeOfStruct = sizeof(SYMBOL_INFO); if(ctxOb->pfn.SymGetTypeFromName(ctxOb->hSym, pObPdbEntry->qwLoadAddress, szSymbolName, &SymbolInfo)) { @@ -603,24 +623,25 @@ fail: * Query the PDB for the offset of a symbol and return its virtual address. If * szSymbolName contains wildcard '?*' characters and matches multiple symbols * the virtual address of the 1st symbol is returned. +* -- H * -- hPDB * -- szSymbolName = wildcard symbol name * -- pvaSymbolAddress * -- return */ _Success_(return) -BOOL PDB_GetSymbolAddress(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _Out_ PQWORD pvaSymbolAddress) +BOOL PDB_GetSymbolAddress(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _Out_ PQWORD pvaSymbolAddress) { - POB_PDB_CONTEXT ctxOb = PDB_GetContext(); + POB_PDB_CONTEXT ctxOb = PDB_GetContext(H); PPDB_ENTRY pObPdbEntry = NULL; DWORD cbSymbolOffset; BOOL fResult = FALSE; - if(!PDB_GetSymbolOffset(hPDB, szSymbolName, &cbSymbolOffset)) { goto fail; } + if(!PDB_GetSymbolOffset(H, hPDB, szSymbolName, &cbSymbolOffset)) { goto fail; } if(hPDB == PDB_HANDLE_KERNEL) { - *pvaSymbolAddress = ctxVmm->kernel.vaBase + cbSymbolOffset; + *pvaSymbolAddress = H->vmm.kernel.vaBase + cbSymbolOffset; } else { if(!ctxOb || ctxOb->fDisabled) { goto fail; } - if(!(hPDB = PDB_GetHandleFromHandleMagic(hPDB))) { goto fail; } + if(!(hPDB = PDB_GetHandleFromHandleMagic(H, hPDB))) { goto fail; } if(!(pObPdbEntry = ObMap_GetByKey(ctxOb->pmPdbByHash, hPDB))) { goto fail; } *pvaSymbolAddress = pObPdbEntry->vaModuleBase + cbSymbolOffset; } @@ -634,6 +655,7 @@ fail: /* * Query the PDB for the closest symbol name given an offset from the module * base address. +* -- H * -- hPDB * -- dwSymbolOffset = the offset from the module base to query. * -- szSymbolName = buffer to receive the name of the symbol. @@ -641,15 +663,15 @@ fail: * -- return */ _Success_(return) -BOOL PDB_GetSymbolFromOffset(_In_opt_ PDB_HANDLE hPDB, _In_ DWORD dwSymbolOffset, _Out_writes_opt_(MAX_PATH) LPSTR szSymbolName, _Out_opt_ PDWORD pdwSymbolDisplacement) +BOOL PDB_GetSymbolFromOffset(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ DWORD dwSymbolOffset, _Out_writes_opt_(MAX_PATH) LPSTR szSymbolName, _Out_opt_ PDWORD pdwSymbolDisplacement) { - POB_PDB_CONTEXT ctxOb = PDB_GetContext(); + POB_PDB_CONTEXT ctxOb = PDB_GetContext(H); SYMBOL_INFO_PACKAGE SymbolInfo = { 0 }; QWORD cch, qwDisplacement; PPDB_ENTRY pObPdbEntry = NULL; BOOL fResult = FALSE; if(!ctxOb || ctxOb->fDisabled) { goto fail; } - if(!(hPDB = PDB_GetHandleFromHandleMagic(hPDB))) { goto fail; } + if(!(hPDB = PDB_GetHandleFromHandleMagic(H, hPDB))) { goto fail; } if(!(pObPdbEntry = ObMap_GetByKey(ctxOb->pmPdbByHash, hPDB))) { goto fail; } EnterCriticalSection(&ctxOb->Lock); if(PDB_LoadEnsureEx(ctxOb, pObPdbEntry)) { @@ -678,6 +700,7 @@ fail: * Read memory at the PDB acquired symbol offset. If szSymbolName contains * wildcard '?*' characters and matches multiple symbols the offset of the * 1st symbol is used to read the memory. +* -- H * -- hPDB * -- szSymbolName = wildcard symbol name * -- pProcess @@ -686,23 +709,23 @@ fail: * -- return */ _Success_(return) -BOOL PDB_GetSymbolPBYTE(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb) +BOOL PDB_GetSymbolPBYTE(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb) { - POB_PDB_CONTEXT ctxOb = PDB_GetContext(); + POB_PDB_CONTEXT ctxOb = PDB_GetContext(H); PPDB_ENTRY pObPdbEntry = NULL; DWORD dwSymbolOffset; QWORD va; BOOL fResult = FALSE; - if(!PDB_GetSymbolOffset(hPDB, szSymbolName, &dwSymbolOffset)) { goto fail; } + if(!PDB_GetSymbolOffset(H, hPDB, szSymbolName, &dwSymbolOffset)) { goto fail; } if(hPDB == PDB_HANDLE_KERNEL) { - va = ctxVmm->kernel.vaBase + dwSymbolOffset; + va = H->vmm.kernel.vaBase + dwSymbolOffset; } else { if(!ctxOb || ctxOb->fDisabled) { goto fail; } - if(!(hPDB = PDB_GetHandleFromHandleMagic(hPDB))) { goto fail; } + if(!(hPDB = PDB_GetHandleFromHandleMagic(H, hPDB))) { goto fail; } if(!(pObPdbEntry = ObMap_GetByKey(ctxOb->pmPdbByHash, hPDB))) { goto fail; } va = pObPdbEntry->vaModuleBase + dwSymbolOffset; } - fResult = VmmRead(pProcess, va, pb, cb); + fResult = VmmRead(H, pProcess, va, pb, cb); fail: Ob_DECREF(pObPdbEntry); Ob_DECREF(ctxOb); @@ -712,20 +735,21 @@ fail: /* * Query the PDB for the size of a type. If szTypeName contains wildcard '?*' * characters and matches multiple types the size of the 1st type is returned. +* -- H * -- hPDB * -- szTypeName = wildcard type name * -- pdwTypeSize * -- return */ _Success_(return) -BOOL PDB_GetTypeSize_Internal(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _Out_ PDWORD pdwTypeSize) +BOOL PDB_GetTypeSize_Internal(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _Out_ PDWORD pdwTypeSize) { - POB_PDB_CONTEXT ctxOb = PDB_GetContext(); + POB_PDB_CONTEXT ctxOb = PDB_GetContext(H); SYMBOL_INFO SymbolInfo = { 0 }; PPDB_ENTRY pObPdbEntry = NULL; BOOL fResult = FALSE; if(!ctxOb || ctxOb->fDisabled) { goto fail; } - if(!(hPDB = PDB_GetHandleFromHandleMagic(hPDB))) { goto fail; } + if(!(hPDB = PDB_GetHandleFromHandleMagic(H, hPDB))) { goto fail; } if(!(pObPdbEntry = ObMap_GetByKey(ctxOb->pmPdbByHash, hPDB))) { goto fail; } EnterCriticalSection(&ctxOb->Lock); if(PDB_LoadEnsureEx(ctxOb, pObPdbEntry)) { @@ -743,26 +767,27 @@ fail: /* * Query the PDB for the size of a type. If szTypeName contains wildcard '?*' * characters and matches multiple types the size of the 1st type is returned. +* -- H * -- hPDB * -- szTypeName = wildcard type name * -- pdwTypeSize * -- return */ _Success_(return) -BOOL PDB_GetTypeSize(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _Out_ PDWORD pdwTypeSize) +BOOL PDB_GetTypeSize(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _Out_ PDWORD pdwTypeSize) { // lookup hierarchy (1): InfoDB dynamic (cached pdb), (2): Full PDB, (3): InfoDB static (build# based). return - PDB_InfoDB_TypeSize(hPDB, szTypeName, pdwTypeSize, TRUE) || - PDB_GetTypeSize_Internal(hPDB, szTypeName, pdwTypeSize) || - PDB_InfoDB_TypeSize(hPDB, szTypeName, pdwTypeSize, FALSE); + PDB_InfoDB_TypeSize(H, hPDB, szTypeName, pdwTypeSize, TRUE) || + PDB_GetTypeSize_Internal(H, hPDB, szTypeName, pdwTypeSize) || + PDB_InfoDB_TypeSize(H, hPDB, szTypeName, pdwTypeSize, FALSE); } _Success_(return) -BOOL PDB_GetTypeSizeShort(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _Out_ PWORD pwTypeSize) +BOOL PDB_GetTypeSizeShort(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _Out_ PWORD pwTypeSize) { DWORD dwTypeSize; - if(!PDB_GetTypeSize(hPDB, szTypeName, &dwTypeSize) || (dwTypeSize > 0xffff)) { return FALSE; } + if(!PDB_GetTypeSize(H, hPDB, szTypeName, &dwTypeSize) || (dwTypeSize > 0xffff)) { return FALSE; } if(pwTypeSize) { *pwTypeSize = (WORD)dwTypeSize; } return TRUE; } @@ -781,6 +806,7 @@ BOOL WINAPI PDB_GetTypeChildOffset_Callback(_In_ PSYMBOL_INFO pSymInfo, _In_ ULO * Query the PDB for the offset of a child inside a type - often inside a struct. * If szTypeName contains wildcard '?*' characters and matches multiple types the * first type is queried for children. The child name must match exactly. +* -- H * -- hPDB * -- szTypeName = wildcard type name. * -- uszTypeChildName = exact match of child name. @@ -788,9 +814,9 @@ BOOL WINAPI PDB_GetTypeChildOffset_Callback(_In_ PSYMBOL_INFO pSymInfo, _In_ ULO * -- return */ _Success_(return) -BOOL PDB_GetTypeChildOffset_Internal(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _In_ LPSTR uszTypeChildName, _Out_ PDWORD pdwTypeOffset) +BOOL PDB_GetTypeChildOffset_Internal(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _In_ LPSTR uszTypeChildName, _Out_ PDWORD pdwTypeOffset) { - POB_PDB_CONTEXT ctxOb = PDB_GetContext(); + POB_PDB_CONTEXT ctxOb = PDB_GetContext(H); BOOL fResult = FALSE; LPWSTR wszTypeChildSymName; LPSTR uszTypeChildSymName; @@ -799,7 +825,7 @@ BOOL PDB_GetTypeChildOffset_Internal(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szType DWORD dwTypeId, cTypeChildren, iTypeChild; TI_FINDCHILDREN_PARAMS *pFindChildren = NULL; if(!ctxOb || ctxOb->fDisabled) { goto fail; } - if(!(hPDB = PDB_GetHandleFromHandleMagic(hPDB))) { goto fail; } + if(!(hPDB = PDB_GetHandleFromHandleMagic(H, hPDB))) { goto fail; } if(!(pObPdbEntry = ObMap_GetByKey(ctxOb->pmPdbByHash, hPDB))) { goto fail; } EnterCriticalSection(&ctxOb->Lock); if(!PDB_LoadEnsureEx(ctxOb, pObPdbEntry)) { goto fail_lock; } @@ -832,6 +858,7 @@ fail: * Query the PDB for the offset of a child inside a type - often inside a struct. * If szTypeName contains wildcard '?*' characters and matches multiple types the * first type is queried for children. The child name must match exactly. +* -- H * -- hPDB * -- szTypeName = wildcard type name. * -- uszTypeChildName = exact match of child name. @@ -839,20 +866,20 @@ fail: * -- return */ _Success_(return) -BOOL PDB_GetTypeChildOffset(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _In_ LPSTR uszTypeChildName, _Out_ PDWORD pdwTypeOffset) +BOOL PDB_GetTypeChildOffset(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _In_ LPSTR uszTypeChildName, _Out_ PDWORD pdwTypeOffset) { // lookup hierarchy (1): InfoDB dynamic (cached pdb), (2): Full PDB, (3): InfoDB static (build# based). return - PDB_InfoDB_TypeChildOffset(hPDB, szTypeName, uszTypeChildName, pdwTypeOffset, TRUE) || - PDB_GetTypeChildOffset_Internal(hPDB, szTypeName, uszTypeChildName, pdwTypeOffset) || - PDB_InfoDB_TypeChildOffset(hPDB, szTypeName, uszTypeChildName, pdwTypeOffset, FALSE); + PDB_InfoDB_TypeChildOffset(H, hPDB, szTypeName, uszTypeChildName, pdwTypeOffset, TRUE) || + PDB_GetTypeChildOffset_Internal(H, hPDB, szTypeName, uszTypeChildName, pdwTypeOffset) || + PDB_InfoDB_TypeChildOffset(H, hPDB, szTypeName, uszTypeChildName, pdwTypeOffset, FALSE); } _Success_(return) -BOOL PDB_GetTypeChildOffsetShort(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _In_ LPSTR uszTypeChildName, _Out_ PWORD pwTypeOffset) +BOOL PDB_GetTypeChildOffsetShort(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _In_ LPSTR uszTypeChildName, _Out_ PWORD pwTypeOffset) { DWORD dwTypeOffset; - if(!PDB_GetTypeChildOffset(hPDB, szTypeName, uszTypeChildName, &dwTypeOffset) || (dwTypeOffset > 0xffff)) { return FALSE; } + if(!PDB_GetTypeChildOffset(H, hPDB, szTypeName, uszTypeChildName, &dwTypeOffset) || (dwTypeOffset > 0xffff)) { return FALSE; } if(pwTypeOffset) { *pwTypeOffset = (WORD)dwTypeOffset; } return TRUE; } @@ -866,25 +893,25 @@ BOOL PDB_GetTypeChildOffsetShort(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName /* * Cleanup the PDB sub-system. This should ideally be done on Vmm Close(). */ -VOID PDB_Close() +VOID PDB_Close(_In_ VMM_HANDLE H) { - Ob_DECREF_NULL(&ctxVmm->pObPdbContext); - ctxMain->pdb.fInitialized = FALSE; + Ob_DECREF_NULL(&H->vmm.pObPdbContext); + H->pdb.fInitialized = FALSE; } /* * */ _Success_(return) -BOOL PDB_Initialize_Async_Kernel_ScanForPdbInfo(_In_ PVMM_PROCESS pSystemProcess, _Out_ PPE_CODEVIEW_INFO pCodeViewInfo) +BOOL PDB_Initialize_Async_Kernel_ScanForPdbInfo(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _Out_ PPE_CODEVIEW_INFO pCodeViewInfo) { PBYTE pb = NULL; DWORD i, cbRead; PPE_CODEVIEW pPdb; ZeroMemory(pCodeViewInfo, sizeof(PE_CODEVIEW_INFO)); - if(!ctxVmm->kernel.vaBase) { return FALSE; } + if(!H->vmm.kernel.vaBase) { return FALSE; } if(!(pb = LocalAlloc(0, 0x00800000))) { return FALSE; } - VmmReadEx(pSystemProcess, ctxVmm->kernel.vaBase, pb, 0x00800000, &cbRead, VMM_FLAG_ZEROPAD_ON_FAIL); + VmmReadEx(H, pSystemProcess, H->vmm.kernel.vaBase, pb, 0x00800000, &cbRead, VMM_FLAG_ZEROPAD_ON_FAIL); // 1: search for pdb debug information adn extract offset of PsInitialSystemProcess for(i = 0; i < 0x00800000 - sizeof(PE_CODEVIEW); i += 4) { pPdb = (PPE_CODEVIEW)(pb + i); @@ -905,10 +932,10 @@ BOOL PDB_Initialize_Async_Kernel_ScanForPdbInfo(_In_ PVMM_PROCESS pSystemProcess return FALSE; } -VOID PDB_Initialize_WaitComplete() +VOID PDB_Initialize_WaitComplete(_In_ VMM_HANDLE H) { - POB_PDB_CONTEXT ctxOb = PDB_GetContext(); - if(ctxOb && ctxMain->pdb.fEnable) { + POB_PDB_CONTEXT ctxOb = PDB_GetContext(H); + if(ctxOb && H->pdb.fEnable) { EnterCriticalSection(&ctxOb->Lock); LeaveCriticalSection(&ctxOb->Lock); } @@ -921,172 +948,169 @@ VOID PDB_Initialize_WaitComplete() * Once this initializtion is successfully completed the fDisabled flag will be * removed - allowing other threads to use the PDB subsystem. * If the initialization fails it's assume the PDB system should be disabled. -* -- hEventThreadStart -* -- return +* -- H +* -- */ -DWORD PDB_Initialize_Async_Kernel_ThreadProc(LPVOID lpParameter) +VOID PDB_Initialize_Async_Kernel_ThreadProc(_In_ VMM_HANDLE H, _In_ POB_PDB_INITIALIZE_KERNEL_PARAMETERS pKernelParameters) { - POB_PDB_CONTEXT ctxOb = PDB_GetContext(); - PVMMWIN_PDB_INITIALIZE_KERNEL_PARAMETERS pKernelParameters = (PVMMWIN_PDB_INITIALIZE_KERNEL_PARAMETERS)lpParameter; + POB_PDB_CONTEXT ctxOb = PDB_GetContext(H); DWORD dwReturnStatus = 0; PVMM_PROCESS pObSystemProcess = NULL; PPDB_ENTRY pObKernelEntry = NULL; QWORD qwPdbHash; - if(!ctxOb) { return 0; } + if(!ctxOb) { return; } EnterCriticalSection(&ctxOb->Lock); SetEvent(*pKernelParameters->phEventThreadStarted); - if(!(pObSystemProcess = VmmProcessGet(4))) { goto fail; } + if(!(pObSystemProcess = VmmProcessGet(H, 4))) { goto fail; } pKernelParameters->fPdbInfo = pKernelParameters->fPdbInfo || - PE_GetCodeViewInfo(pObSystemProcess, ctxVmm->kernel.vaBase, NULL, &pKernelParameters->PdbInfo) || - PDB_Initialize_Async_Kernel_ScanForPdbInfo(pObSystemProcess, &pKernelParameters->PdbInfo); + PE_GetCodeViewInfo(H, pObSystemProcess, H->vmm.kernel.vaBase, NULL, &pKernelParameters->PdbInfo) || + PDB_Initialize_Async_Kernel_ScanForPdbInfo(H, pObSystemProcess, &pKernelParameters->PdbInfo); if(!pKernelParameters->fPdbInfo) { - PDB_PrintError("Reason: Unable to locate debugging information in kernel image."); + PDB_PrintError(H, "Reason: Unable to locate debugging information in kernel image."); goto fail; } - qwPdbHash = PDB_AddModuleEntry(ctxVmm->kernel.vaBase, (DWORD)ctxVmm->kernel.cbSize, "ntoskrnl", pKernelParameters->PdbInfo.CodeView.PdbFileName, pKernelParameters->PdbInfo.CodeView.Guid, pKernelParameters->PdbInfo.CodeView.Age); + qwPdbHash = PDB_AddModuleEntry(H, H->vmm.kernel.vaBase, (DWORD)H->vmm.kernel.cbSize, "ntoskrnl", pKernelParameters->PdbInfo.CodeView.PdbFileName, pKernelParameters->PdbInfo.CodeView.Guid, pKernelParameters->PdbInfo.CodeView.Age); pObKernelEntry = ObMap_GetByKey(ctxOb->pmPdbByHash, qwPdbHash); if(!pObKernelEntry) { - PDB_PrintError("Reason: Failed creating initial PDB entry."); + PDB_PrintError(H, "Reason: Failed creating initial PDB entry."); goto fail; } if(!PDB_LoadEnsureEx(ctxOb, pObKernelEntry)) { - PDB_PrintError("Reason: Unable to download kernel symbols to cache from Symbol Server."); + PDB_PrintError(H, "Reason: Unable to download kernel symbols to cache from Symbol Server."); goto fail; } - VmmLog(MID_PDB, LOGLEVEL_DEBUG, "Initialization of debug symbol .pdb functionality completed"); - VmmLog(MID_PDB, LOGLEVEL_DEBUG, "[ %s ]", ctxMain->pdb.szSymbolPath); + VmmLog(H, MID_PDB, LOGLEVEL_DEBUG, "Initialization of debug symbol .pdb functionality completed"); + VmmLog(H, MID_PDB, LOGLEVEL_DEBUG, "[ %s ]", H->pdb.szSymbolPath); ctxOb->fDisabled = FALSE; - dwReturnStatus = 1; // fall-through to fail for cleanup fail: LeaveCriticalSection(&ctxOb->Lock); Ob_DECREF(pObKernelEntry); Ob_DECREF(pObSystemProcess); - LocalFree(pKernelParameters); Ob_DECREF(ctxOb); - return dwReturnStatus; } -VOID PDB_Initialize_InitialValues() +VOID PDB_Initialize_InitialValues(_In_ VMM_HANDLE H) { - HKEY hKey; + HKEY hKey = NULL; DWORD cbData, dwEnableSymbols, dwEnableSymbolServer; // 1: try load values from registry - if(!ctxMain->pdb.fInitialized) { - ctxMain->pdb.fEnable = 1; - ctxMain->pdb.fServerEnable = !ctxMain->cfg.fDisableSymbolServerOnStartup; + if(!H->pdb.fInitialized) { + H->pdb.fEnable = 1; + H->pdb.fServerEnable = !H->cfg.fDisableSymbolServerOnStartup; } - ctxMain->pdb.szLocal[0] = 0; - ctxMain->pdb.szServer[0] = 0; - dwEnableSymbols = ctxMain->pdb.fEnable ? 1 : 0; - dwEnableSymbolServer = ctxMain->pdb.fServerEnable ? 1 : 0; + H->pdb.szLocal[0] = 0; + H->pdb.szServer[0] = 0; + dwEnableSymbols = H->pdb.fEnable ? 1 : 0; + dwEnableSymbolServer = H->pdb.fServerEnable ? 1 : 0; if(ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Software\\UlfFrisk\\MemProcFS", 0, KEY_READ, &hKey)) { - cbData = _countof(ctxMain->pdb.szLocal) - 1; - RegQueryValueExA(hKey, "SymbolCache", NULL, NULL, (PBYTE)ctxMain->pdb.szLocal, &cbData); - if(cbData < 3) { ctxMain->pdb.szLocal[0] = 0; } - cbData = _countof(ctxMain->pdb.szServer) - 1; - RegQueryValueExA(hKey, "SymbolServer", NULL, NULL, (PBYTE)ctxMain->pdb.szServer, &cbData); - if(cbData < 3) { ctxMain->pdb.szServer[0] = 0; } - if(ctxMain->pdb.fEnable) { + cbData = _countof(H->pdb.szLocal) - 1; + RegQueryValueExA(hKey, "SymbolCache", NULL, NULL, (PBYTE)H->pdb.szLocal, &cbData); + if(cbData < 3) { H->pdb.szLocal[0] = 0; } + cbData = _countof(H->pdb.szServer) - 1; + RegQueryValueExA(hKey, "SymbolServer", NULL, NULL, (PBYTE)H->pdb.szServer, &cbData); + if(cbData < 3) { H->pdb.szServer[0] = 0; } + if(H->pdb.fEnable) { cbData = sizeof(DWORD); RegQueryValueExA(hKey, "SymbolEnable", NULL, NULL, (PBYTE)&dwEnableSymbols, &cbData); } - if(ctxMain->pdb.fServerEnable) { + if(H->pdb.fServerEnable) { cbData = sizeof(DWORD); RegQueryValueExA(hKey, "SymbolServerEnable", NULL, NULL, (PBYTE)&dwEnableSymbolServer, &cbData); } - RegCloseKey(hKey); } + if(hKey) { RegCloseKey(hKey); hKey = NULL; } // 2: set default values (if not already loaded from registry) - if(!ctxMain->pdb.szLocal[0]) { - Util_GetPathDll(ctxMain->pdb.szLocal, ctxVmm->hModuleVmmOpt); - strncat_s(ctxMain->pdb.szLocal, _countof(ctxMain->pdb.szLocal), "Symbols", _TRUNCATE); + if(!H->pdb.szLocal[0]) { + Util_GetPathDll(H->pdb.szLocal, H->vmm.hModuleVmmOpt); + strncat_s(H->pdb.szLocal, _countof(H->pdb.szLocal), "Symbols", _TRUNCATE); } - if(!ctxMain->pdb.szServer[0]) { - strncpy_s(ctxMain->pdb.szServer, _countof(ctxMain->pdb.szServer), "https://msdl.microsoft.com/download/symbols", _TRUNCATE); + if(!H->pdb.szServer[0]) { + strncpy_s(H->pdb.szServer, _countof(H->pdb.szServer), "https://msdl.microsoft.com/download/symbols", _TRUNCATE); } // 3: set final values - ctxMain->pdb.fEnable = (dwEnableSymbols == 1); - ctxMain->pdb.fServerEnable = (dwEnableSymbolServer == 1); - strncpy_s(ctxMain->pdb.szSymbolPath, _countof(ctxMain->pdb.szSymbolPath), "srv*", _TRUNCATE); - strncat_s(ctxMain->pdb.szSymbolPath, _countof(ctxMain->pdb.szSymbolPath), ctxMain->pdb.szLocal, _TRUNCATE); - if(ctxMain->pdb.fServerEnable) { - strncat_s(ctxMain->pdb.szSymbolPath, _countof(ctxMain->pdb.szSymbolPath), "*", _TRUNCATE); - strncat_s(ctxMain->pdb.szSymbolPath, _countof(ctxMain->pdb.szSymbolPath), ctxMain->pdb.szServer, _TRUNCATE); + H->pdb.fEnable = (dwEnableSymbols == 1); + H->pdb.fServerEnable = (dwEnableSymbolServer == 1); + strncpy_s(H->pdb.szSymbolPath, _countof(H->pdb.szSymbolPath), "srv*", _TRUNCATE); + strncat_s(H->pdb.szSymbolPath, _countof(H->pdb.szSymbolPath), H->pdb.szLocal, _TRUNCATE); + if(H->pdb.fServerEnable) { + strncat_s(H->pdb.szSymbolPath, _countof(H->pdb.szSymbolPath), "*", _TRUNCATE); + strncat_s(H->pdb.szSymbolPath, _countof(H->pdb.szSymbolPath), H->pdb.szServer, _TRUNCATE); } - ctxMain->pdb.fInitialized = TRUE; + H->pdb.fInitialized = TRUE; } /* * Update the PDB configuration. The PDB syb-system will be reloaded on * configuration changes - which may cause a short interruption for any * caller. +* -- H */ -VOID PDB_ConfigChange() +VOID PDB_ConfigChange(_In_ VMM_HANDLE H) { HKEY hKey; CHAR szLocalPath[MAX_PATH] = { 0 }; - if(ctxMain->cfg.fDisableSymbols) { - VmmLog(MID_PDB, LOGLEVEL_INFO, "Debug symbols disabled by user"); + if(H->cfg.fDisableSymbols) { + VmmLog(H, MID_PDB, LOGLEVEL_INFO, "Debug symbols disabled by user"); return; } // update new values in registry if(ERROR_SUCCESS == RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\UlfFrisk\\MemProcFS", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hKey, NULL)) { - Util_GetPathDll(szLocalPath, ctxVmm->hModuleVmmOpt); - if(strncmp(szLocalPath, ctxMain->pdb.szLocal, strlen(szLocalPath) - 1) && !_access_s(ctxMain->pdb.szLocal, 06)) { - RegSetValueExA(hKey, "SymbolCache", 0, REG_SZ, (PBYTE)ctxMain->pdb.szLocal, (DWORD)strlen(ctxMain->pdb.szLocal)); + Util_GetPathDll(szLocalPath, H->vmm.hModuleVmmOpt); + if(strncmp(szLocalPath, H->pdb.szLocal, strlen(szLocalPath) - 1) && !_access_s(H->pdb.szLocal, 06)) { + RegSetValueExA(hKey, "SymbolCache", 0, REG_SZ, (PBYTE)H->pdb.szLocal, (DWORD)strlen(H->pdb.szLocal)); } else { RegSetValueExA(hKey, "SymbolCache", 0, REG_SZ, (PBYTE)"", 0); } - if((!strncmp("http://", ctxMain->pdb.szServer, 7) || !strncmp("https://", ctxMain->pdb.szServer, 8)) && !strstr(ctxMain->pdb.szServer, "msdl.microsoft.com")) { - RegSetValueExA(hKey, "SymbolServer", 0, REG_SZ, (PBYTE)ctxMain->pdb.szServer, (DWORD)strlen(ctxMain->pdb.szServer)); + if((!strncmp("http://", H->pdb.szServer, 7) || !strncmp("https://", H->pdb.szServer, 8)) && !strstr(H->pdb.szServer, "msdl.microsoft.com")) { + RegSetValueExA(hKey, "SymbolServer", 0, REG_SZ, (PBYTE)H->pdb.szServer, (DWORD)strlen(H->pdb.szServer)); } else { RegSetValueExA(hKey, "SymbolServer", 0, REG_SZ, (PBYTE)"", 0); } RegCloseKey(hKey); } // refresh values and reload! - EnterCriticalSection(&ctxVmm->LockMaster); - PDB_Close(); - PDB_Initialize(NULL, FALSE); - LeaveCriticalSection(&ctxVmm->LockMaster); + EnterCriticalSection(&H->vmm.LockMaster); + PDB_Close(H); + PDB_Initialize(H, NULL, FALSE); + LeaveCriticalSection(&H->vmm.LockMaster); } /* * Initialize the PDB sub-system. This should ideally be done on Vmm Init() */ -VOID PDB_Initialize(_In_opt_ PPE_CODEVIEW_INFO pPdbInfoOpt, _In_ BOOL fInitializeKernelAsync) +VOID PDB_Initialize(_In_ VMM_HANDLE H, _In_opt_ PPE_CODEVIEW_INFO pPdbInfoOpt, _In_ BOOL fInitializeKernelAsync) { HANDLE hEventThreadStarted = 0; POB_PDB_CONTEXT ctx = NULL; DWORD i, dwSymOptions; CHAR szPathSymSrv[MAX_PATH], szPathDbgHelp[MAX_PATH]; - PVMMWIN_PDB_INITIALIZE_KERNEL_PARAMETERS pKernelParameters = NULL; - if(ctxMain->pdb.fInitialized) { return; } - if(ctxMain->cfg.fDisableSymbols) { - VmmLog(MID_PDB, LOGLEVEL_INFO, "Debug symbols disabled by user"); + POB_PDB_INITIALIZE_KERNEL_PARAMETERS pObKernelParameters = NULL; + if(H->pdb.fInitialized) { return; } + if(H->cfg.fDisableSymbols) { + VmmLog(H, MID_PDB, LOGLEVEL_INFO, "Debug symbols disabled by user"); return; } - PDB_Initialize_InitialValues(); - if(!ctxMain->pdb.fEnable) { goto fail; } - if(!(ctx = Ob_Alloc(OB_TAG_PDB_CTX, LMEM_ZEROINIT, sizeof(OB_PDB_CONTEXT), PDB_CallbackCleanup_ObPdbContext, NULL))) { goto fail; } - if(!(ctx->pmPdbByHash = ObMap_New(OB_MAP_FLAGS_OBJECT_OB))) { goto fail; } - if(!(ctx->pmPdbByModule = ObMap_New(OB_MAP_FLAGS_OBJECT_OB))) { goto fail; } + PDB_Initialize_InitialValues(H); + if(!H->pdb.fEnable) { goto fail; } + if(!(ctx = Ob_AllocEx(H, OB_TAG_PDB_CTX, LMEM_ZEROINIT, sizeof(OB_PDB_CONTEXT), PDB_CallbackCleanup_ObPdbContext, NULL))) { goto fail; } + if(!(ctx->pmPdbByHash = ObMap_New(H, OB_MAP_FLAGS_OBJECT_OB))) { goto fail; } + if(!(ctx->pmPdbByModule = ObMap_New(H, OB_MAP_FLAGS_OBJECT_OB))) { goto fail; } // 1: dynamic load of dbghelp.dll and symsrv.dll from directory of vmm.dll - i.e. not from system32 - Util_GetPathDll(szPathSymSrv, ctxVmm->hModuleVmmOpt); - Util_GetPathDll(szPathDbgHelp, ctxVmm->hModuleVmmOpt); + Util_GetPathDll(szPathSymSrv, H->vmm.hModuleVmmOpt); + Util_GetPathDll(szPathDbgHelp, H->vmm.hModuleVmmOpt); strncat_s(szPathSymSrv, MAX_PATH, "symsrv.dll", _TRUNCATE); strncat_s(szPathDbgHelp, MAX_PATH, "dbghelp.dll", _TRUNCATE); ctx->hModuleSymSrv = LoadLibraryA(szPathSymSrv); ctx->hModuleDbgHelp = LoadLibraryA(szPathDbgHelp); if(!ctx->hModuleSymSrv || !ctx->hModuleDbgHelp) { - PDB_PrintError("Reason: Could not load PDB required files - symsrv.dll/dbghelp.dll."); + PDB_PrintError(H, "Reason: Could not load PDB required files - symsrv.dll/dbghelp.dll."); goto fail; } for(i = 0; i < sizeof(VMMWIN_PDB_FUNCTIONS) / sizeof(PVOID); i++) { ctx->vafn[i] = GetProcAddress(ctx->hModuleDbgHelp, szVMMWIN_PDB_FUNCTIONS[i]); if(!ctx->vafn[i]) { - PDB_PrintError("Reason: Could not load function(s) from symsrv.dll/dbghelp.dll."); + PDB_PrintError(H, "Reason: Could not load function(s) from symsrv.dll/dbghelp.dll."); goto fail; } } @@ -1099,37 +1123,38 @@ VOID PDB_Initialize(_In_opt_ PPE_CODEVIEW_INFO pPdbInfoOpt, _In_ BOOL fInitializ dwSymOptions |= SYMOPT_IGNORE_NT_SYMPATH; dwSymOptions |= SYMOPT_UNDNAME; ctx->pfn.SymSetOptions(dwSymOptions); - if(!ctx->pfn.SymInitialize(ctx->hSym, ctxMain->pdb.szSymbolPath, FALSE)) { - PDB_PrintError("Reason: Failed to initialize Symbol Handler / dbghelp.dll."); + if(!ctx->pfn.SymInitialize(ctx->hSym, H->pdb.szSymbolPath, FALSE)) { + PDB_PrintError(H, "Reason: Failed to initialize Symbol Handler / dbghelp.dll."); ctx->hSym = NULL; goto fail; } // success - finish up and load kernel .pdb async (to optimize startup time). // pdb subsystem won't be fully initialized until before the kernel is loaded. if(!(hEventThreadStarted = CreateEvent(NULL, TRUE, FALSE, NULL))) { goto fail; } - if(!(pKernelParameters = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMWIN_PDB_INITIALIZE_KERNEL_PARAMETERS)))) { goto fail; } - pKernelParameters->phEventThreadStarted = &hEventThreadStarted; + if(!(pObKernelParameters = Ob_AllocEx(H, OB_TAG_PDB_KERNEL_CONTEXT, LMEM_ZEROINIT, sizeof(OB_PDB_INITIALIZE_KERNEL_PARAMETERS), NULL, NULL))) { goto fail; } + pObKernelParameters->phEventThreadStarted = &hEventThreadStarted; if(pPdbInfoOpt) { - pKernelParameters->fPdbInfo = TRUE; - memcpy(&pKernelParameters->PdbInfo, pPdbInfoOpt, sizeof(PE_CODEVIEW_INFO)); + pObKernelParameters->fPdbInfo = TRUE; + memcpy(&pObKernelParameters->PdbInfo, pPdbInfoOpt, sizeof(PE_CODEVIEW_INFO)); } InitializeCriticalSection(&ctx->Lock); ctx->qwLoadAddressNext = VMMWIN_PDB_LOAD_ADDRESS_BASE; ctx->fDisabled = TRUE; - ctxVmm->pObPdbContext = (POB)ctx; + H->vmm.pObPdbContext = (POB)ctx; if(fInitializeKernelAsync) { - VmmWork((LPTHREAD_START_ROUTINE)PDB_Initialize_Async_Kernel_ThreadProc, (LPVOID)pKernelParameters, NULL); - WaitForSingleObject(hEventThreadStarted, 500); // wait for async thread initialize thread to start (and acquire PDB lock). + VmmWork_Ob(H, (PVMM_WORK_START_ROUTINE_OB_PFN)PDB_Initialize_Async_Kernel_ThreadProc, (POB)pObKernelParameters, NULL, VMMWORK_FLAG_PRIO_NORMAL); + WaitForSingleObject(hEventThreadStarted, 1000); // wait for async thread initialize thread to start (and acquire PDB lock). } else { - PDB_Initialize_Async_Kernel_ThreadProc(pKernelParameters); // synchronous call + PDB_Initialize_Async_Kernel_ThreadProc(H, pObKernelParameters); // synchronous call } CloseHandle(hEventThreadStarted); + Ob_DECREF(pObKernelParameters); return; fail: if(hEventThreadStarted) { CloseHandle(hEventThreadStarted); } + Ob_DECREF(pObKernelParameters); Ob_DECREF(ctx); - LocalFree(pKernelParameters); - ctxMain->pdb.fEnable = FALSE; + H->pdb.fEnable = FALSE; } @@ -1218,7 +1243,7 @@ LPWSTR PDB_DisplayTypeNt_GetTypeName(_In_ PPDB_DT_INFO pDT, _In_ QWORD cbType) * text buffer in the ctxDT context. This function makes multiple and possible * also recursive lookups against dbghelp.dll. */ -VOID PDB_DisplayTypeNt_DoWork(_Inout_ PPDB_DT_CONTEXT ctxDT, _In_ BYTE iLevel, _In_ DWORD dwTypeIndex, _In_ DWORD dwChildCount, _In_ LPWSTR wszTypeName, _In_opt_ PBYTE pbMEM, _In_ DWORD cbMEM) +VOID PDB_DisplayTypeNt_DoWork(_In_ VMM_HANDLE H, _Inout_ PPDB_DT_CONTEXT ctxDT, _In_ BYTE iLevel, _In_ DWORD dwTypeIndex, _In_ DWORD dwChildCount, _In_ LPWSTR wszTypeName, _In_opt_ PBYTE pbMEM, _In_ DWORD cbMEM) { static const IMAGEHLP_SYMBOL_TYPE_INFO _INFO1_ReqKinds[] = { TI_GET_SYMNAME, @@ -1360,7 +1385,7 @@ VOID PDB_DisplayTypeNt_DoWork(_Inout_ PPDB_DT_CONTEXT ctxDT, _In_ BYTE iLevel, _ ctxDT->csz += _snprintf_s(ctxDT->szu8 + ctxDT->csz, (SIZE_T)(ctxDT->cszMax - ctxDT->csz), _TRUNCATE, "%S\n", ctxDT->wszln); // commit line to result utf-8 result string oln = 0; if(pe->dwChildCount && (iLevel < ctxDT->iLevelMax) && (!pbMEM || (pe->dwOffset + pe->qwLength <= cbMEM))) { - PDB_DisplayTypeNt_DoWork(ctxDT, iLevel + 1, pe->dwTypeIndex, pe->dwChildCount, pe->wszTypeName, (pbMEM ? pbMEM + pe->dwOffset : NULL), (pbMEM ? cbMEM - pe->dwOffset : 0)); + PDB_DisplayTypeNt_DoWork(H, ctxDT, iLevel + 1, pe->dwTypeIndex, pe->dwChildCount, pe->wszTypeName, (pbMEM ? pbMEM + pe->dwOffset : NULL), (pbMEM ? cbMEM - pe->dwOffset : 0)); } } else { wszBuffer[0] = 0; @@ -1393,9 +1418,9 @@ VOID PDB_DisplayTypeNt_DoWork(_Inout_ PPDB_DT_CONTEXT ctxDT, _In_ BYTE iLevel, _ // _UNICODE_STRING special case: if(pbMEM && (dwChildCount == 3) && (i == 2) && wszTypeName && !wcscmp(L"_UNICODE_STRING", wszTypeName)) { cbData = *(PWORD)pbMEM; - vaData = ctxVmm->f32 ? *(PDWORD)(pbMEM + 4) : *(PQWORD)(pbMEM + 8); - if(VMM_KADDR(vaData) && cbData && !(cbData & 1) && (cbData < MAX_PATH * 2)) { - if(VmmRead(PVMM_PROCESS_SYSTEM, vaData, (PBYTE)ctxDT->wszBuffer, (DWORD)cbData)) { + vaData = H->vmm.f32 ? *(PDWORD)(pbMEM + 4) : *(PQWORD)(pbMEM + 8); + if(VMM_KADDR(H->vmm.f32, vaData) && cbData && !(cbData & 1) && (cbData < MAX_PATH * 2)) { + if(VmmRead(H, PVMM_PROCESS_SYSTEM, vaData, (PBYTE)ctxDT->wszBuffer, (DWORD)cbData)) { ctxDT->wszBuffer[cbData >> 1] = 0; oln += _snwprintf_s(ctxDT->wszln + oln, MAX_PATH - oln, _TRUNCATE, L" - %s", ctxDT->wszBuffer); } @@ -1426,6 +1451,7 @@ fail: * a human readable utf-8 string. Caller is responsible for LocalFree(). * Please also note that this function is single-threaded by an internal lock. * CALLER LocalFree: *pszResult +* -- H * -- szTypeName = the name of the type - only types within ntosknl.exe are allowed. * -- cLevelMax = recurse into sub-types to cLevelMax. * -- vaType = optional kernel address in SYSTEM process address space where to @@ -1441,6 +1467,7 @@ fail: */ _Success_(return) BOOL PDB_DisplayTypeNt( + _In_ VMM_HANDLE H, _In_ LPSTR szTypeName, _In_ BYTE cLevelMax, _In_opt_ QWORD vaType, @@ -1450,7 +1477,7 @@ BOOL PDB_DisplayTypeNt( _Out_opt_ PDWORD pcbResult, _Out_opt_ PDWORD pcbType ) { - POB_PDB_CONTEXT ctxOb = PDB_GetContext(); + POB_PDB_CONTEXT ctxOb = PDB_GetContext(H); BOOL fResult = FALSE; PDB_HANDLE hPDB; SYMBOL_INFO_PACKAGE SymbolInfoType = { 0 }; @@ -1467,13 +1494,13 @@ BOOL PDB_DisplayTypeNt( Ob_DECREF(ctxOb); return FALSE; } - hPDB = PDB_GetHandleFromModuleName("ntoskrnl"); + hPDB = PDB_GetHandleFromModuleName(H, "ntoskrnl"); if(!(pObPdbEntry = ObMap_GetByKey(ctxOb->pmPdbByHash, hPDB))) { return FALSE; } EnterCriticalSection(&ctxOb->Lock); if(!PDB_LoadEnsureEx(ctxOb, pObPdbEntry)) { goto fail; } // flag: object header -> type == _OBJECT_HEADER + adjust va type base. if(fObjHeader) { szTypeName = "_OBJECT_HEADER"; } - if(fObjHeader && vaType) { vaType -= ctxVmm->f32 ? sizeof(OBJECT_HEADER32) : sizeof(OBJECT_HEADER64); } + if(fObjHeader && vaType) { vaType -= H->vmm.f32 ? sizeof(OBJECT_HEADER32) : sizeof(OBJECT_HEADER64); } // fetch type data: SymbolInfoType.si.SizeOfStruct = sizeof(SYMBOL_INFO); SymbolInfoType.si.MaxNameLen = MAX_SYM_NAME; @@ -1491,24 +1518,24 @@ BOOL PDB_DisplayTypeNt( ctxDT.szu8[0] = 0; if(!ctxDT.szu8) { goto fail; } // fetch optional type memory (if possible): - if(VMM_KADDR_4_8(vaType) && (SymbolInfoType.si.Size >= 4) && (SymbolInfoType.si.Size < 0x2000)) { + if(VMM_KADDR_4_8(H->vmm.f32, vaType) && (SymbolInfoType.si.Size >= 4) && (SymbolInfoType.si.Size < 0x2000)) { if((pbMEM = LocalAlloc(0, SymbolInfoType.si.Size))) { - if(!VmmRead(PVMM_PROCESS_SYSTEM, vaType, pbMEM, SymbolInfoType.si.Size)) { + if(!VmmRead(H, PVMM_PROCESS_SYSTEM, vaType, pbMEM, SymbolInfoType.si.Size)) { pbMEM = LocalFree(pbMEM); } } } // call worker function: if(pbMEM) { - szFormat = ctxVmm->f32 ? "dt nt!%s 0x%08llX\n" : "dt nt!%s 0x%016llX\n"; + szFormat = H->vmm.f32 ? "dt nt!%s 0x%08llX\n" : "dt nt!%s 0x%016llX\n"; ctxDT.csz += snprintf(ctxDT.szu8 + ctxDT.csz, (SIZE_T)(ctxDT.cszMax - ctxDT.csz), szFormat, SymbolInfoType.si.Name, vaType); } else { ctxDT.csz += snprintf(ctxDT.szu8 + ctxDT.csz, (SIZE_T)(ctxDT.cszMax - ctxDT.csz), "dt nt!%s\n", SymbolInfoType.si.Name); } - PDB_DisplayTypeNt_DoWork(&ctxDT, 0, SymbolInfoType.si.TypeIndex, cTypeChildren, NULL, pbMEM, (pbMEM ? SymbolInfoType.si.Size : 0)); + PDB_DisplayTypeNt_DoWork(H, &ctxDT, 0, SymbolInfoType.si.TypeIndex, cTypeChildren, NULL, pbMEM, (pbMEM ? SymbolInfoType.si.Size : 0)); // append optional hexascii: if(fHexAscii && pbMEM && ctxDT.csz) { - szFormat = ctxVmm->f32 ? "\n---\n\ndb 0x%08llX L%03X\n" : "\n---\n\ndb 0x%016llX L%03X\n"; + szFormat = H->vmm.f32 ? "\n---\n\ndb 0x%08llX L%03X\n" : "\n---\n\ndb 0x%016llX L%03X\n"; ctxDT.csz += snprintf(ctxDT.szu8 + ctxDT.csz, (SIZE_T)(ctxDT.cszMax - ctxDT.csz), szFormat, vaType, SymbolInfoType.si.Size); cbHexAscii = (DWORD)(ctxDT.cszMax - ctxDT.csz); if(Util_FillHexAscii(pbMEM, min(0x2000, SymbolInfoType.si.Size), 0, ctxDT.szu8 + ctxDT.csz, &cbHexAscii)) { @@ -1516,22 +1543,22 @@ BOOL PDB_DisplayTypeNt( } } // flag: object header: special processing: - if(fObjHeader && pbMEM && ctxVmm->offset._OBJECT_HEADER_CREATOR_INFO.cb) { + if(fObjHeader && pbMEM && H->vmm.offset._OBJECT_HEADER_CREATOR_INFO.cb) { for(i = 0; i < 9; i++) { - if(((1 << i) & (ctxVmm->f32 ? ((POBJECT_HEADER32)pbMEM)->InfoMask : ((POBJECT_HEADER64)pbMEM)->InfoMask)) || (i == 8)) { + if(((1 << i) & (H->vmm.f32 ? ((POBJECT_HEADER32)pbMEM)->InfoMask : ((POBJECT_HEADER64)pbMEM)->InfoMask)) || (i == 8)) { switch(i) { - case 0: szSubType = "_OBJECT_HEADER_CREATOR_INFO"; cbSubType = ctxVmm->offset._OBJECT_HEADER_CREATOR_INFO.cb; break; // 0x01 - case 1: szSubType = "_OBJECT_HEADER_NAME_INFO"; cbSubType = ctxVmm->offset._OBJECT_HEADER_NAME_INFO.cb; break; // 0x02 - case 2: szSubType = "_OBJECT_HEADER_HANDLE_INFO"; cbSubType = ctxVmm->offset._OBJECT_HEADER_HANDLE_INFO.cb; break; // 0x04 - case 3: szSubType = "_OBJECT_HEADER_QUOTA_INFO"; cbSubType = ctxVmm->offset._OBJECT_HEADER_QUOTA_INFO.cb; break; // 0x08 - case 4: szSubType = "_OBJECT_HEADER_PROCESS_INFO"; cbSubType = ctxVmm->offset._OBJECT_HEADER_PROCESS_INFO.cb; break; // 0x10 - case 6: szSubType = "_OBJECT_HEADER_AUDIT_INFO"; cbSubType = ctxVmm->offset._OBJECT_HEADER_AUDIT_INFO.cb; break; // 0x40 - case 8: szSubType = "_POOL_HEADER"; cbSubType = ctxVmm->offset._POOL_HEADER.cb; break; // --- + case 0: szSubType = "_OBJECT_HEADER_CREATOR_INFO"; cbSubType = H->vmm.offset._OBJECT_HEADER_CREATOR_INFO.cb; break; // 0x01 + case 1: szSubType = "_OBJECT_HEADER_NAME_INFO"; cbSubType = H->vmm.offset._OBJECT_HEADER_NAME_INFO.cb; break; // 0x02 + case 2: szSubType = "_OBJECT_HEADER_HANDLE_INFO"; cbSubType = H->vmm.offset._OBJECT_HEADER_HANDLE_INFO.cb; break; // 0x04 + case 3: szSubType = "_OBJECT_HEADER_QUOTA_INFO"; cbSubType = H->vmm.offset._OBJECT_HEADER_QUOTA_INFO.cb; break; // 0x08 + case 4: szSubType = "_OBJECT_HEADER_PROCESS_INFO"; cbSubType = H->vmm.offset._OBJECT_HEADER_PROCESS_INFO.cb; break; // 0x10 + case 6: szSubType = "_OBJECT_HEADER_AUDIT_INFO"; cbSubType = H->vmm.offset._OBJECT_HEADER_AUDIT_INFO.cb; break; // 0x40 + case 8: szSubType = "_POOL_HEADER"; cbSubType = H->vmm.offset._POOL_HEADER.cb; break; // --- default: szSubType = NULL; cbSubType = 0; break; } if(!cbSubType || !szSubType) { break; } vaType -= cbSubType; - if(PDB_DisplayTypeNt(szSubType, 2, vaType, fHexAscii, FALSE, &szSubTypeResult, NULL, NULL)) { + if(PDB_DisplayTypeNt(H, szSubType, 2, vaType, fHexAscii, FALSE, &szSubTypeResult, NULL, NULL)) { ctxDT.csz += snprintf(ctxDT.szu8 + ctxDT.csz, (SIZE_T)(ctxDT.cszMax - ctxDT.csz), "\n======\n\n%s", szSubTypeResult); LocalFree(szSubTypeResult); } @@ -1559,65 +1586,65 @@ fail: #include "pdb.h" -VOID PDB_Initialize_WaitComplete() { return; } -VOID PDB_Close() { return; } -VOID PDB_ConfigChange() { return; } -PDB_HANDLE PDB_GetHandleFromModuleAddress(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase) { return 0; } -PDB_HANDLE PDB_GetHandleFromModuleName(_In_ LPSTR szModuleName) { return 0; } -_Success_(return) BOOL PDB_LoadEnsure(_In_opt_ PDB_HANDLE hPDB) { return FALSE; } -_Success_(return) BOOL PDB_GetModuleInfo(_In_opt_ PDB_HANDLE hPDB, _Out_writes_opt_(MAX_PATH) LPSTR szModuleName, _Out_opt_ PQWORD pvaModuleBase, _Out_opt_ PDWORD pcbModuleSize) { return FALSE; } -_Success_(return) BOOL PDB_GetSymbolFromOffset(_In_opt_ PDB_HANDLE hPDB, _In_ DWORD dwSymbolOffset, _Out_writes_opt_(MAX_PATH) LPSTR szSymbolName, _Out_opt_ PDWORD pdwSymbolDisplacement) { return FALSE; } -_Success_(return) BOOL PDB_DisplayTypeNt(_In_ LPSTR szTypeName, _In_ BYTE cLevelMax, _In_opt_ QWORD vaType, _In_ BOOL fHexAscii, _In_ BOOL fObjHeader, _Out_opt_ LPSTR * pszResult, _Out_opt_ PDWORD pcbResult, _Out_opt_ PDWORD pcbType) { return FALSE; } +VOID PDB_Initialize_WaitComplete(_In_ VMM_HANDLE H) { return; } +VOID PDB_Close(_In_ VMM_HANDLE H) { return; } +VOID PDB_ConfigChange(_In_ VMM_HANDLE H) { return; } +PDB_HANDLE PDB_GetHandleFromModuleAddress(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase) { return 0; } +PDB_HANDLE PDB_GetHandleFromModuleName(_In_ VMM_HANDLE H, _In_ LPSTR szModuleName) { return 0; } +_Success_(return) BOOL PDB_LoadEnsure(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB) { return FALSE; } +_Success_(return) BOOL PDB_GetModuleInfo(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _Out_writes_opt_(MAX_PATH) LPSTR szModuleName, _Out_opt_ PQWORD pvaModuleBase, _Out_opt_ PDWORD pcbModuleSize) { return FALSE; } +_Success_(return) BOOL PDB_GetSymbolFromOffset(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ DWORD dwSymbolOffset, _Out_writes_opt_(MAX_PATH) LPSTR szSymbolName, _Out_opt_ PDWORD pdwSymbolDisplacement) { return FALSE; } +_Success_(return) BOOL PDB_DisplayTypeNt(_In_ VMM_HANDLE H, _In_ LPSTR szTypeName, _In_ BYTE cLevelMax, _In_opt_ QWORD vaType, _In_ BOOL fHexAscii, _In_ BOOL fObjHeader, _Out_opt_ LPSTR * pszResult, _Out_opt_ PDWORD pcbResult, _Out_opt_ PDWORD pcbType) { return FALSE; } -VOID PDB_Initialize(_In_opt_ PPE_CODEVIEW_INFO pPdbInfoOpt, _In_ BOOL fInitializeKernelAsync) +VOID PDB_Initialize(_In_ VMM_HANDLE H, _In_opt_ PPE_CODEVIEW_INFO pPdbInfoOpt, _In_ BOOL fInitializeKernelAsync) { - PDB_PrintError("Full symbol support only available on Windows."); + PDB_PrintError(H, "Full symbol support only available on Windows."); return; } -_Success_(return) BOOL PDB_GetSymbolOffset(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _Out_ PDWORD pdwSymbolOffset) +_Success_(return) BOOL PDB_GetSymbolOffset(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _Out_ PDWORD pdwSymbolOffset) { - return PDB_InfoDB_SymbolOffset(hPDB, szSymbolName, pdwSymbolOffset); + return PDB_InfoDB_SymbolOffset(H, hPDB, szSymbolName, pdwSymbolOffset); } -_Success_(return) BOOL PDB_GetTypeSize(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _Out_ PDWORD pdwTypeSize) +_Success_(return) BOOL PDB_GetTypeSize(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _Out_ PDWORD pdwTypeSize) { - return PDB_InfoDB_TypeSize(hPDB, szTypeName, pdwTypeSize, TRUE) || PDB_InfoDB_TypeSize(hPDB, szTypeName, pdwTypeSize, FALSE); + return PDB_InfoDB_TypeSize(H, hPDB, szTypeName, pdwTypeSize, TRUE) || PDB_InfoDB_TypeSize(H, hPDB, szTypeName, pdwTypeSize, FALSE); } -_Success_(return) BOOL PDB_GetTypeChildOffset(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _In_ LPSTR uszTypeChildName, _Out_ PDWORD pdwTypeOffset) +_Success_(return) BOOL PDB_GetTypeChildOffset(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _In_ LPSTR uszTypeChildName, _Out_ PDWORD pdwTypeOffset) { - return PDB_InfoDB_TypeChildOffset(hPDB, szTypeName, uszTypeChildName, pdwTypeOffset, TRUE) || PDB_InfoDB_TypeChildOffset(hPDB, szTypeName, uszTypeChildName, pdwTypeOffset, FALSE); + return PDB_InfoDB_TypeChildOffset(H, hPDB, szTypeName, uszTypeChildName, pdwTypeOffset, TRUE) || PDB_InfoDB_TypeChildOffset(H, hPDB, szTypeName, uszTypeChildName, pdwTypeOffset, FALSE); } -_Success_(return) BOOL PDB_GetSymbolAddress(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _Out_ PQWORD pvaSymbolAddress) +_Success_(return) BOOL PDB_GetSymbolAddress(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _Out_ PQWORD pvaSymbolAddress) { DWORD dwSymbolOffset; *pvaSymbolAddress = 0; - if((hPDB == PDB_HANDLE_KERNEL) && PDB_InfoDB_SymbolOffset(hPDB, szSymbolName, &dwSymbolOffset)) { - *pvaSymbolAddress = ctxVmm->kernel.vaBase + dwSymbolOffset; + if((hPDB == PDB_HANDLE_KERNEL) && PDB_InfoDB_SymbolOffset(H, hPDB, szSymbolName, &dwSymbolOffset)) { + *pvaSymbolAddress = H->vmm.kernel.vaBase + dwSymbolOffset; return TRUE; } return FALSE; } -_Success_(return) BOOL PDB_GetSymbolPBYTE(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb) +_Success_(return) BOOL PDB_GetSymbolPBYTE(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb) { QWORD vaSymbolAddress = 0; - return PDB_GetSymbolAddress(hPDB, szSymbolName, &vaSymbolAddress) && VmmRead(pProcess, vaSymbolAddress, pb, cb); + return PDB_GetSymbolAddress(H, hPDB, szSymbolName, &vaSymbolAddress) && VmmRead(H, pProcess, vaSymbolAddress, pb, cb); } -_Success_(return) BOOL PDB_GetTypeSizeShort(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _Out_ PWORD pwTypeSize) +_Success_(return) BOOL PDB_GetTypeSizeShort(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _Out_ PWORD pwTypeSize) { DWORD dwTypeSize = 0; - if(!PDB_GetTypeSize(hPDB, szTypeName, &dwTypeSize)) { return FALSE; } + if(!PDB_GetTypeSize(H, hPDB, szTypeName, &dwTypeSize)) { return FALSE; } *pwTypeSize = (WORD)dwTypeSize; return TRUE; } -_Success_(return) BOOL PDB_GetTypeChildOffsetShort(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _In_ LPSTR uszTypeChildName, _Out_ PWORD pwTypeOffset) +_Success_(return) BOOL PDB_GetTypeChildOffsetShort(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _In_ LPSTR uszTypeChildName, _Out_ PWORD pwTypeOffset) { DWORD dwTypeOffset = 0; - if(!PDB_GetTypeChildOffset(hPDB, szTypeName, uszTypeChildName, &dwTypeOffset)) { return FALSE; } + if(!PDB_GetTypeChildOffset(H, hPDB, szTypeName, uszTypeChildName, &dwTypeOffset)) { return FALSE; } *pwTypeOffset = (WORD)dwTypeOffset; return TRUE; } diff --git a/vmm/pdb.h b/vmm/pdb.h index 5fe0d5f..62da861 100644 --- a/vmm/pdb.h +++ b/vmm/pdb.h @@ -19,58 +19,66 @@ typedef QWORD PDB_HANDLE; /* * Initialize the PDB sub-system. This should ideally be done on Vmm Init(). +* -- H * -- pPdbInfoOpt * -- fInitializeKernelAsync */ -VOID PDB_Initialize(_In_opt_ PPE_CODEVIEW_INFO pPdbInfoOpt, _In_ BOOL fInitializeKernelAsync); +VOID PDB_Initialize(_In_ VMM_HANDLE H, _In_opt_ PPE_CODEVIEW_INFO pPdbInfoOpt, _In_ BOOL fInitializeKernelAsync); /* * Wait for completion of initialization of the PDB sub-system. +* -- H */ -VOID PDB_Initialize_WaitComplete(); +VOID PDB_Initialize_WaitComplete(_In_ VMM_HANDLE H); /* * Cleanup the PDB sub-system. This should ideally be done on Vmm Close(). +* -- H */ -VOID PDB_Close(); +VOID PDB_Close(_In_ VMM_HANDLE H); /* * Update the PDB configuration. The PDB syb-system will be reloaded on * configuration changes - which may cause a short interruption for any * caller. +* -- H */ -VOID PDB_ConfigChange(); +VOID PDB_ConfigChange(_In_ VMM_HANDLE H); /* * Retrieve a PDB handle given a process and module base address. If the handle * is not found in the database an attempt to automatically add it is performed. * NB! Only one PDB with the same base address may exist regardless of process. * NB! The PDB for the added module won't be loaded until required. +* -- H * -- pProcess * -- vaModuleBase * -- return = The PDB handle on success (no need to close handle); or zero on fail. */ -PDB_HANDLE PDB_GetHandleFromModuleAddress(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase); +PDB_HANDLE PDB_GetHandleFromModuleAddress(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase); /* * Retrieve a PDB handle from an already added module. * NB! If multiple modules exists with the same name the 1st module to be added * is returned. +* -- H * -- szModuleName * -- return = The PDB handle on success (no need to close handle); or zero on fail. */ -PDB_HANDLE PDB_GetHandleFromModuleName(_In_ LPSTR szModuleName); +PDB_HANDLE PDB_GetHandleFromModuleName(_In_ VMM_HANDLE H, _In_ LPSTR szModuleName); /* * Ensure that the PDB_HANDLE have its symbols loaded into memory. +* -- H * -- hPDB * -- return */ _Success_(return) -BOOL PDB_LoadEnsure(_In_opt_ PDB_HANDLE hPDB); +BOOL PDB_LoadEnsure(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB); /* * Return module information given a PDB handle. +* -- H * -- hPDB * -- szModuleName = buffer to receive module name upon success. * -- pvaModuleBase @@ -78,7 +86,7 @@ BOOL PDB_LoadEnsure(_In_opt_ PDB_HANDLE hPDB); * -- return */ _Success_(return) -BOOL PDB_GetModuleInfo(_In_opt_ PDB_HANDLE hPDB, _Out_writes_opt_(MAX_PATH) LPSTR szModuleName, _Out_opt_ PQWORD pvaModuleBase, _Out_opt_ PDWORD pcbModuleSize); +BOOL PDB_GetModuleInfo(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _Out_writes_opt_(MAX_PATH) LPSTR szModuleName, _Out_opt_ PQWORD pvaModuleBase, _Out_opt_ PDWORD pcbModuleSize); @@ -91,27 +99,30 @@ BOOL PDB_GetModuleInfo(_In_opt_ PDB_HANDLE hPDB, _Out_writes_opt_(MAX_PATH) LPST /* * Query the PDB for the offset of a symbol. +* -- H * -- hPDB * -- szSymbolName * -- pdwSymbolOffset * -- return */ _Success_(return) -BOOL PDB_GetSymbolOffset(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _Out_ PDWORD pdwSymbolOffset); +BOOL PDB_GetSymbolOffset(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _Out_ PDWORD pdwSymbolOffset); /* * Query the PDB for the offset of a symbol and return its virtual address. +* -- H * -- hPDB * -- szSymbolName * -- pvaSymbolAddress * -- return */ _Success_(return) -BOOL PDB_GetSymbolAddress(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _Out_ PQWORD pvaSymbolAddress); +BOOL PDB_GetSymbolAddress(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _Out_ PQWORD pvaSymbolAddress); /* * Query the PDB for the closest symbol name given an offset from the module * base address. +* -- H * -- hPDB * -- dwSymbolOffset = the offset from the module base to query. * -- szSymbolName = buffer to receive the name of the symbol. @@ -119,11 +130,12 @@ BOOL PDB_GetSymbolAddress(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _Ou * -- return */ _Success_(return) -BOOL PDB_GetSymbolFromOffset(_In_opt_ PDB_HANDLE hPDB, _In_ DWORD dwSymbolOffset, _Out_writes_opt_(MAX_PATH) LPSTR szSymbolName, _Out_opt_ PDWORD pdwSymbolDisplacement); +BOOL PDB_GetSymbolFromOffset(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ DWORD dwSymbolOffset, _Out_writes_opt_(MAX_PATH) LPSTR szSymbolName, _Out_opt_ PDWORD pdwSymbolDisplacement); /* * Read memory at the PDB acquired symbol offset. * Functions PDB_GetSymbolQWORD and PDB_GetSymbolDWORD behave similarly. +* -- H * -- hPDB * -- szSymbolName * -- pProcess @@ -132,10 +144,11 @@ BOOL PDB_GetSymbolFromOffset(_In_opt_ PDB_HANDLE hPDB, _In_ DWORD dwSymbolOffset * -- return */ _Success_(return) -BOOL PDB_GetSymbolPBYTE(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb); +BOOL PDB_GetSymbolPBYTE(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb); /* * Read memory pointed to at the PDB acquired symbol offset. +* -- H * -- hPDB * -- szSymbolName * -- pProcess @@ -143,10 +156,11 @@ BOOL PDB_GetSymbolPBYTE(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _In_ * -- return */ _Success_(return) -BOOL PDB_GetSymbolQWORD(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PQWORD pqw); +BOOL PDB_GetSymbolQWORD(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PQWORD pqw); /* * Read memory pointed to at the PDB acquired symbol offset. +* -- H * -- hPDB * -- szSymbolName * -- pProcess @@ -154,10 +168,11 @@ BOOL PDB_GetSymbolQWORD(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _In_ * -- return */ _Success_(return) -BOOL PDB_GetSymbolDWORD(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PDWORD pdw); +BOOL PDB_GetSymbolDWORD(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PDWORD pdw); /* * Read memory pointed to at the PDB acquired symbol offset. +* -- H * -- hPDB * -- szSymbolName * -- pProcess @@ -165,10 +180,11 @@ BOOL PDB_GetSymbolDWORD(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _In_ * -- return */ _Success_(return) -BOOL PDB_GetSymbolPTR(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PVOID pv); +BOOL PDB_GetSymbolPTR(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PVOID pv); /* * Read memory at the PDB acquired symbol offset and virtual address base. +* -- H * -- hPDB * -- vaBase * -- szSymbolName = wildcard symbol name @@ -178,10 +194,11 @@ BOOL PDB_GetSymbolPTR(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szSymbolName, _In_ PV * -- return */ _Success_(return) -BOOL PDB_GetSymbolPBYTE2(_In_opt_ PDB_HANDLE hPDB, _In_ QWORD vaBase, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb); +BOOL PDB_GetSymbolPBYTE2(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ QWORD vaBase, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb); /* * Read memory pointed to at the PDB acquired symbol offset and virtual address base. +* -- H * -- hPDB * -- vaBase * -- szSymbolName @@ -190,10 +207,11 @@ BOOL PDB_GetSymbolPBYTE2(_In_opt_ PDB_HANDLE hPDB, _In_ QWORD vaBase, _In_ LPSTR * -- return */ _Success_(return) -BOOL PDB_GetSymbolQWORD2(_In_opt_ PDB_HANDLE hPDB, _In_ QWORD vaBase, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PQWORD pqw); +BOOL PDB_GetSymbolQWORD2(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ QWORD vaBase, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PQWORD pqw); /* * Read memory pointed to at the PDB acquired symbol offset and virtual address base. +* -- H * -- hPDB * -- vaBase * -- szSymbolName @@ -202,10 +220,11 @@ BOOL PDB_GetSymbolQWORD2(_In_opt_ PDB_HANDLE hPDB, _In_ QWORD vaBase, _In_ LPSTR * -- return */ _Success_(return) -BOOL PDB_GetSymbolDWORD2(_In_opt_ PDB_HANDLE hPDB, _In_ QWORD vaBase, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PDWORD pdw); +BOOL PDB_GetSymbolDWORD2(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ QWORD vaBase, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PDWORD pdw); /* * Read memory pointed to at the PDB acquired symbol offset and virtual address base. +* -- H * -- hPDB * -- vaBase * -- szSymbolName @@ -214,7 +233,7 @@ BOOL PDB_GetSymbolDWORD2(_In_opt_ PDB_HANDLE hPDB, _In_ QWORD vaBase, _In_ LPSTR * -- return */ _Success_(return) -BOOL PDB_GetSymbolPTR2(_In_opt_ PDB_HANDLE hPDB, _In_ QWORD vaBase, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PVOID pv); +BOOL PDB_GetSymbolPTR2(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ QWORD vaBase, _In_ LPSTR szSymbolName, _In_ PVMM_PROCESS pProcess, _Out_ PVOID pv); @@ -225,21 +244,23 @@ BOOL PDB_GetSymbolPTR2(_In_opt_ PDB_HANDLE hPDB, _In_ QWORD vaBase, _In_ LPSTR s /* * Query the PDB for the size of a type. If szTypeName contains wildcard '?*' * characters and matches multiple types the size of the 1st type is returned. +* -- H * -- hPDB * -- szTypeName = wildcard type name * -- pdwTypeSize / pwTypeSize * -- return */ _Success_(return) -BOOL PDB_GetTypeSize(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _Out_ PDWORD pdwTypeSize); +BOOL PDB_GetTypeSize(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _Out_ PDWORD pdwTypeSize); _Success_(return) -BOOL PDB_GetTypeSizeShort(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _Out_ PWORD pwTypeSize); +BOOL PDB_GetTypeSizeShort(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _Out_ PWORD pwTypeSize); /* * Query the PDB for the offset of a child inside a type - often inside a struct. * If szTypeName contains wildcard '?*' characters and matches multiple types the * first type is queried for children. The child name must match exactly. +* -- H * -- hPDB * -- szTypeName = wildcard type name. * -- uszTypeChildName = exact match of child name. @@ -247,16 +268,17 @@ BOOL PDB_GetTypeSizeShort(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _Out_ * -- return */ _Success_(return) -BOOL PDB_GetTypeChildOffset(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _In_ LPSTR uszTypeChildName, _Out_ PDWORD pdwTypeOffset); +BOOL PDB_GetTypeChildOffset(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _In_ LPSTR uszTypeChildName, _Out_ PDWORD pdwTypeOffset); _Success_(return) -BOOL PDB_GetTypeChildOffsetShort(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _In_ LPSTR uszTypeChildName, _Out_ PWORD pwTypeOffset); +BOOL PDB_GetTypeChildOffsetShort(_In_ VMM_HANDLE H, _In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName, _In_ LPSTR uszTypeChildName, _Out_ PWORD pwTypeOffset); /* * Fetch the ntoskrnl.exe type information from the PDB symbols and return it in * a human readable utf-8 string. Caller is responsible for LocalFree(). * Please also note that this function is single-threaded by an internal lock. * CALLER LocalFree: *pszResult +* -- H * -- szTypeName = the name of the type - only types within ntosknl.exe are allowed. * -- cLevelMax = recurse into sub-types to cLevelMax. * -- vaType = optional kernel address in SYSTEM process address space where to @@ -272,6 +294,7 @@ BOOL PDB_GetTypeChildOffsetShort(_In_opt_ PDB_HANDLE hPDB, _In_ LPSTR szTypeName */ _Success_(return) BOOL PDB_DisplayTypeNt( + _In_ VMM_HANDLE H, _In_ LPSTR szTypeName, _In_ BYTE cLevelMax, _In_opt_ QWORD vaType, diff --git a/vmm/pe.c b/vmm/pe.c index 88829d4..f2d7317 100644 --- a/vmm/pe.c +++ b/vmm/pe.c @@ -8,13 +8,13 @@ #include "vmm.h" #include "pe.h" -PIMAGE_NT_HEADERS PE_HeaderGetVerify(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _Inout_ PBYTE pbModuleHeader, _Out_opt_ PBOOL pfHdr32) +PIMAGE_NT_HEADERS PE_HeaderGetVerify(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _Inout_ PBYTE pbModuleHeader, _Out_opt_ PBOOL pfHdr32) { PIMAGE_DOS_HEADER dosHeader; PIMAGE_NT_HEADERS ntHeader; if(pfHdr32) { *pfHdr32 = FALSE; } if(vaModuleBase) { - if(!VmmReadPage(pProcess, vaModuleBase, pbModuleHeader)) { return NULL; } + if(!VmmReadPage(H, pProcess, vaModuleBase, pbModuleHeader)) { return NULL; } } dosHeader = (PIMAGE_DOS_HEADER)pbModuleHeader; // dos header. if(!dosHeader || dosHeader->e_magic != IMAGE_DOS_SIGNATURE) { return NULL; } @@ -26,13 +26,13 @@ PIMAGE_NT_HEADERS PE_HeaderGetVerify(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD return ntHeader; } -QWORD PE_GetSize(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase) +QWORD PE_GetSize(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase) { BYTE pbHeader[0x1000] = { 0 }; PIMAGE_NT_HEADERS ntHeader; DWORD cbSize; BOOL f32; - ntHeader = PE_HeaderGetVerify(pProcess, vaModuleBase, pbHeader, &f32); + ntHeader = PE_HeaderGetVerify(H, pProcess, vaModuleBase, pbHeader, &f32); if(!ntHeader) { return 0; } cbSize = f32 ? ((PIMAGE_NT_HEADERS32)ntHeader)->OptionalHeader.SizeOfImage : @@ -42,13 +42,13 @@ QWORD PE_GetSize(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase) } _Success_(return) -BOOL PE_GetTimeDateStampCheckSum(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _Out_opt_ PDWORD pdwTimeDateStamp, _Out_opt_ PDWORD pdwCheckSum) +BOOL PE_GetTimeDateStampCheckSum(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _Out_opt_ PDWORD pdwTimeDateStamp, _Out_opt_ PDWORD pdwCheckSum) { BYTE pbHeader[0x1000] = { 0 }; PIMAGE_NT_HEADERS ntHeader; BOOL f32; DWORD dwTimeDateStamp, dwCheckSum; - ntHeader = PE_HeaderGetVerify(pProcess, vaModuleBase, pbHeader, &f32); + ntHeader = PE_HeaderGetVerify(H, pProcess, vaModuleBase, pbHeader, &f32); if(!ntHeader) { return FALSE; } if(f32) { dwCheckSum = ((PIMAGE_NT_HEADERS32)ntHeader)->OptionalHeader.CheckSum; @@ -63,7 +63,7 @@ BOOL PE_GetTimeDateStampCheckSum(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaMo } _Success_(return) -BOOL PE_GetThunkInfoIAT(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ LPSTR szImportModuleName, _In_ LPSTR szImportProcName, _Out_ PPE_THUNKINFO_IAT pThunkInfoIAT) +BOOL PE_GetThunkInfoIAT(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ LPSTR szImportModuleName, _In_ LPSTR szImportProcName, _Out_ PPE_THUNKINFO_IAT pThunkInfoIAT) { BYTE pbModuleHeader[0x1000] = { 0 }; PIMAGE_NT_HEADERS64 ntHeader64; @@ -78,7 +78,7 @@ BOOL PE_GetThunkInfoIAT(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In DWORD c, j; LPSTR szNameFunction, szNameModule; // load both 32/64 bit ntHeader (only one will be valid) - if(!(ntHeader64 = (PIMAGE_NT_HEADERS64)PE_HeaderGetVerify(pProcess, vaModuleBase, pbModuleHeader, &f32))) { goto fail; } + if(!(ntHeader64 = (PIMAGE_NT_HEADERS64)PE_HeaderGetVerify(H, pProcess, vaModuleBase, pbModuleHeader, &f32))) { goto fail; } ntHeader32 = (PIMAGE_NT_HEADERS32)ntHeader64; cbModule = f32 ? ntHeader32->OptionalHeader.SizeOfImage : @@ -89,7 +89,7 @@ BOOL PE_GetThunkInfoIAT(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In ntHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; if(!oImportDirectory || (oImportDirectory >= cbModule)) { goto fail; } if(!(pbModule = LocalAlloc(LMEM_ZEROINIT, cbModule))) { goto fail; } - VmmReadEx(pProcess, vaModuleBase, pbModule, cbModule, &cbRead, VMM_FLAG_ZEROPAD_ON_FAIL); + VmmReadEx(H, pProcess, vaModuleBase, pbModule, cbModule, &cbRead, VMM_FLAG_ZEROPAD_ON_FAIL); if(cbRead <= 0x2000) { goto fail; } // Walk imported modules / functions pIID = (PIMAGE_IMPORT_DESCRIPTOR)(pbModule + oImportDirectory); @@ -157,7 +157,7 @@ fail: } _Success_(return) -BOOL PE_GetThunkInfoEAT(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ LPSTR szProcName, _Out_ PPE_THUNKINFO_EAT pThunkInfoEAT) +BOOL PE_GetThunkInfoEAT(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ LPSTR szProcName, _Out_ PPE_THUNKINFO_EAT pThunkInfoEAT) { BYTE pbModuleHeader[0x1000] = { 0 }; PIMAGE_NT_HEADERS32 ntHeader32; @@ -171,7 +171,7 @@ BOOL PE_GetThunkInfoEAT(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In PBYTE pbExportDirectory = NULL; QWORD vaRVAAddrNames, vaNameOrdinals, vaRVAAddrFunctions; BOOL f32; - if(!(ntHeader64 = (PIMAGE_NT_HEADERS64)PE_HeaderGetVerify(pProcess, vaModuleBase, pbModuleHeader, &f32))) { goto cleanup; } + if(!(ntHeader64 = (PIMAGE_NT_HEADERS64)PE_HeaderGetVerify(H, pProcess, vaModuleBase, pbModuleHeader, &f32))) { goto cleanup; } if(f32) { // 32-bit PE ntHeader32 = (PIMAGE_NT_HEADERS32)ntHeader64; vaExportDirectory = vaModuleBase + ntHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; @@ -182,7 +182,7 @@ BOOL PE_GetThunkInfoEAT(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In } if((cbExportDirectory < sizeof(IMAGE_EXPORT_DIRECTORY)) || (cbExportDirectory > 0x01000000) || (vaExportDirectory == vaModuleBase) || (vaExportDirectory > vaModuleBase + 0x80000000)) { goto cleanup; } if(!(pbExportDirectory = LocalAlloc(0, cbExportDirectory))) { goto cleanup; } - VmmReadEx(pProcess, vaExportDirectory, pbExportDirectory, cbExportDirectory, &cbRead, VMM_FLAG_ZEROPAD_ON_FAIL); + VmmReadEx(H, pProcess, vaExportDirectory, pbExportDirectory, cbExportDirectory, &cbRead, VMM_FLAG_ZEROPAD_ON_FAIL); if(!cbRead) { goto cleanup; } PIMAGE_EXPORT_DIRECTORY exp = (PIMAGE_EXPORT_DIRECTORY)pbExportDirectory; if(!exp || !exp->NumberOfNames || !exp->AddressOfNames) { goto cleanup; } @@ -216,41 +216,41 @@ cleanup: return FALSE; } -QWORD PE_GetProcAddress(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ LPSTR lpProcName) +QWORD PE_GetProcAddress(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ LPSTR lpProcName) { PE_THUNKINFO_EAT oThunkInfoEAT = { 0 }; - PE_GetThunkInfoEAT(pProcess, vaModuleBase, lpProcName, &oThunkInfoEAT); + PE_GetThunkInfoEAT(H, pProcess, vaModuleBase, lpProcName, &oThunkInfoEAT); return oThunkInfoEAT.vaFunction; } -WORD PE_SectionGetNumberOfEx(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt) +WORD PE_SectionGetNumberOfEx(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt) { BOOL f32; BYTE pbModuleHeader[0x1000] = { 0 }; WORD cSections; PIMAGE_NT_HEADERS ntHeader; // load nt header either by using optionally supplied module header or by fetching from memory. - ntHeader = pbModuleHeaderOpt ? PE_HeaderGetVerify(pProcess, 0, pbModuleHeaderOpt, &f32) : PE_HeaderGetVerify(pProcess, vaModuleBase, pbModuleHeader, &f32); + ntHeader = pbModuleHeaderOpt ? PE_HeaderGetVerify(H, pProcess, 0, pbModuleHeaderOpt, &f32) : PE_HeaderGetVerify(H, pProcess, vaModuleBase, pbModuleHeader, &f32); if(!ntHeader) { return 0; } cSections = f32 ? ((PIMAGE_NT_HEADERS32)ntHeader)->FileHeader.NumberOfSections : ((PIMAGE_NT_HEADERS64)ntHeader)->FileHeader.NumberOfSections; if(cSections > 0x40) { return 0; } return cSections; } -WORD PE_SectionGetNumberOf(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase) +WORD PE_SectionGetNumberOf(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase) { - return PE_SectionGetNumberOfEx(pProcess, vaModuleBase, NULL); + return PE_SectionGetNumberOfEx(H, pProcess, vaModuleBase, NULL); } _Success_(return) -BOOL PE_SectionGetAll(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ DWORD cSections, _Out_writes_(cSections) PIMAGE_SECTION_HEADER pSections) +BOOL PE_SectionGetAll(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ DWORD cSections, _Out_writes_(cSections) PIMAGE_SECTION_HEADER pSections) { BOOL f32; BYTE pbModuleHeader[0x1000] = { 0 }; PIMAGE_NT_HEADERS ntHeader; PIMAGE_SECTION_HEADER pSectionBase; DWORD cSectionsHdr; - if(!(ntHeader = PE_HeaderGetVerify(pProcess, vaModuleBase, pbModuleHeader, &f32))) { return FALSE; } + if(!(ntHeader = PE_HeaderGetVerify(H, pProcess, vaModuleBase, pbModuleHeader, &f32))) { return FALSE; } pSectionBase = f32 ? (PIMAGE_SECTION_HEADER)((QWORD)ntHeader + sizeof(IMAGE_NT_HEADERS32)) : (PIMAGE_SECTION_HEADER)((QWORD)ntHeader + sizeof(IMAGE_NT_HEADERS64)); @@ -262,14 +262,14 @@ BOOL PE_SectionGetAll(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ } _Success_(return) -BOOL PE_SectionGetFromName(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ LPSTR szSectionName, _Out_ PIMAGE_SECTION_HEADER pSection) +BOOL PE_SectionGetFromName(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ LPSTR szSectionName, _Out_ PIMAGE_SECTION_HEADER pSection) { BOOL f32; BYTE pbModuleHeader[0x1000] = { 0 }; PIMAGE_NT_HEADERS ntHeader; PIMAGE_SECTION_HEADER pSectionBase; DWORD i, cSections; - if(!(ntHeader = PE_HeaderGetVerify(pProcess, vaModuleBase, pbModuleHeader, &f32))) { return FALSE; } + if(!(ntHeader = PE_HeaderGetVerify(H, pProcess, vaModuleBase, pbModuleHeader, &f32))) { return FALSE; } pSectionBase = f32 ? (PIMAGE_SECTION_HEADER)((QWORD)ntHeader + sizeof(IMAGE_NT_HEADERS32)) : (PIMAGE_SECTION_HEADER)((QWORD)ntHeader + sizeof(IMAGE_NT_HEADERS64)); @@ -290,14 +290,14 @@ BOOL PE_SectionGetFromName(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, return FALSE; } -DWORD PE_IatGetNumberOfEx(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt) +DWORD PE_IatGetNumberOfEx(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt) { BOOL f32; BYTE pbModuleHeader[0x1000] = { 0 }; PIMAGE_NT_HEADERS ntHeader; DWORD cbImportDirectory, cbImportAddressTable, cIatEntries, cModules; // load nt header either by using optionally supplied module header or by fetching from memory. - ntHeader = pbModuleHeaderOpt ? PE_HeaderGetVerify(pProcess, 0, pbModuleHeaderOpt, &f32) : PE_HeaderGetVerify(pProcess, vaModuleBase, pbModuleHeader, &f32); + ntHeader = pbModuleHeaderOpt ? PE_HeaderGetVerify(H, pProcess, 0, pbModuleHeaderOpt, &f32) : PE_HeaderGetVerify(H, pProcess, vaModuleBase, pbModuleHeader, &f32); if(!ntHeader) { return 0; } // Calculate the number of functions in the import address table (IAT). // Number of functions = # IAT entries - # Imported modules @@ -312,7 +312,7 @@ DWORD PE_IatGetNumberOfEx(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBas return cIatEntries - min(cIatEntries, cModules); } -DWORD PE_EatGetNumberOfEx(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt) +DWORD PE_EatGetNumberOfEx(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt) { BOOL f32; BYTE pbModuleHeader[0x1000] = { 0 }; @@ -321,21 +321,21 @@ DWORD PE_EatGetNumberOfEx(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBas IMAGE_EXPORT_DIRECTORY hdrExportDirectory; // load both 32/64 bit ntHeader unless already supplied in parameter (only one of 32/64 bit hdr will be valid) // load nt header either by using optionally supplied module header or by fetching from memory. - ntHeader = pbModuleHeaderOpt ? PE_HeaderGetVerify(pProcess, 0, pbModuleHeaderOpt, &f32) : PE_HeaderGetVerify(pProcess, vaModuleBase, pbModuleHeader, &f32); + ntHeader = pbModuleHeaderOpt ? PE_HeaderGetVerify(H, pProcess, 0, pbModuleHeaderOpt, &f32) : PE_HeaderGetVerify(H, pProcess, vaModuleBase, pbModuleHeader, &f32); if(!ntHeader) { return 0; } // Calculate the number of functions in the export address table (EAT). va = f32 ? ((PIMAGE_NT_HEADERS32)ntHeader)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress : ((PIMAGE_NT_HEADERS64)ntHeader)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; vaExportDirectory = va ? vaModuleBase + va : 0; - if(vaExportDirectory && VmmRead(pProcess, vaExportDirectory, (PBYTE)&hdrExportDirectory, sizeof(IMAGE_EXPORT_DIRECTORY)) && (hdrExportDirectory.NumberOfFunctions < 0x00010000)) { + if(vaExportDirectory && VmmRead(H, pProcess, vaExportDirectory, (PBYTE)&hdrExportDirectory, sizeof(IMAGE_EXPORT_DIRECTORY)) && (hdrExportDirectory.NumberOfFunctions < 0x00010000)) { return hdrExportDirectory.NumberOfFunctions; } return 0; } _Success_(return) -BOOL PE_GetModuleNameEx(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ BOOL fOnFailDummyName, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt, _Out_writes_(cszModuleName) PCHAR szModuleName, _In_ DWORD cszModuleName, _Out_opt_ PDWORD pdwSize) +BOOL PE_GetModuleNameEx(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ BOOL fOnFailDummyName, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt, _Out_writes_(cszModuleName) PCHAR szModuleName, _In_ DWORD cszModuleName, _Out_opt_ PDWORD pdwSize) { BOOL f32; BYTE pbModuleHeader[0x1000] = { 0 }; @@ -348,7 +348,7 @@ BOOL PE_GetModuleNameEx(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In BYTE pbExportDirectory[sizeof(IMAGE_EXPORT_DIRECTORY)]; // load both 32/64 bit ntHeader unless already supplied in parameter (only one of 32/64 bit hdr will be valid) // load nt header either by using optionally supplied module header or by fetching from memory. - ntHeader = pbModuleHeaderOpt ? PE_HeaderGetVerify(pProcess, 0, pbModuleHeaderOpt, &f32) : PE_HeaderGetVerify(pProcess, vaModuleBase, pbModuleHeader, &f32); + ntHeader = pbModuleHeaderOpt ? PE_HeaderGetVerify(H, pProcess, 0, pbModuleHeaderOpt, &f32) : PE_HeaderGetVerify(H, pProcess, vaModuleBase, pbModuleHeader, &f32); if(!ntHeader) { return FALSE; } if(!f32) { // 64-bit PE ntHeader64 = (PIMAGE_NT_HEADERS64)ntHeader; @@ -364,11 +364,11 @@ BOOL PE_GetModuleNameEx(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In cbImageSize = ntHeader32->OptionalHeader.SizeOfImage; } if((cbExportDirectory < sizeof(IMAGE_EXPORT_DIRECTORY)) || (vaExportDirectory == vaModuleBase) || (cbExportDirectory > cbImageSize)) { goto fail; } - if(!VmmRead(pProcess, vaExportDirectory, pbExportDirectory, sizeof(IMAGE_EXPORT_DIRECTORY))) { goto fail; } + if(!VmmRead(H, pProcess, vaExportDirectory, pbExportDirectory, sizeof(IMAGE_EXPORT_DIRECTORY))) { goto fail; } exp = (PIMAGE_EXPORT_DIRECTORY)pbExportDirectory; if(!exp || !exp->Name || exp->Name > cbImageSize) { goto fail; } szModuleName[cszModuleName - 1] = 0; - if(!VmmRead(pProcess, vaModuleBase + exp->Name, szModuleName, cszModuleName - 1)) { goto fail; } + if(!VmmRead(H, pProcess, vaModuleBase + exp->Name, szModuleName, cszModuleName - 1)) { goto fail; } return TRUE; fail: if(fOnFailDummyName) { @@ -379,19 +379,19 @@ fail: } _Success_(return) -BOOL PE_GetModuleName(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _Out_writes_(cszModuleName) PCHAR szModuleName, _In_ DWORD cszModuleName) +BOOL PE_GetModuleName(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _Out_writes_(cszModuleName) PCHAR szModuleName, _In_ DWORD cszModuleName) { - return PE_GetModuleNameEx(pProcess, vaModuleBase, FALSE, NULL, szModuleName, cszModuleName, NULL); + return PE_GetModuleNameEx(H, pProcess, vaModuleBase, FALSE, NULL, szModuleName, cszModuleName, NULL); } -DWORD PE_DirectoryGetOffset(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt, _In_ DWORD dwDirectory) +DWORD PE_DirectoryGetOffset(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt, _In_ DWORD dwDirectory) { BOOL f32; PIMAGE_NT_HEADERS ntHeader; BYTE pbModuleHeader[0x1000] = { 0 }; // load both 32/64 bit ntHeader unless already supplied in parameter (only one of 32/64 bit hdr will be valid) // load nt header either by using optionally supplied module header or by fetching from memory. - ntHeader = pbModuleHeaderOpt ? PE_HeaderGetVerify(pProcess, 0, pbModuleHeaderOpt, &f32) : PE_HeaderGetVerify(pProcess, vaModuleBase, pbModuleHeader, &f32); + ntHeader = pbModuleHeaderOpt ? PE_HeaderGetVerify(H, pProcess, 0, pbModuleHeaderOpt, &f32) : PE_HeaderGetVerify(H, pProcess, vaModuleBase, pbModuleHeader, &f32); if(!ntHeader) { return 0; } return f32 ? ((PIMAGE_NT_HEADERS32)ntHeader)->OptionalHeader.DataDirectory[dwDirectory].VirtualAddress : @@ -399,14 +399,14 @@ DWORD PE_DirectoryGetOffset(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleB } _Success_(return) -BOOL PE_DirectoryGetAll(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt, _Out_writes_(IMAGE_NUMBEROF_DIRECTORY_ENTRIES) PIMAGE_DATA_DIRECTORY pDirectories) +BOOL PE_DirectoryGetAll(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt, _Out_writes_(IMAGE_NUMBEROF_DIRECTORY_ENTRIES) PIMAGE_DATA_DIRECTORY pDirectories) { BOOL f32; PIMAGE_NT_HEADERS ntHeader; BYTE pbModuleHeader[0x1000] = { 0 }; // load both 32/64 bit ntHeader unless already supplied in parameter (only one of 32/64 bit hdr will be valid) // load nt header either by using optionally supplied module header or by fetching from memory. - ntHeader = pbModuleHeaderOpt ? PE_HeaderGetVerify(pProcess, 0, pbModuleHeaderOpt, &f32) : PE_HeaderGetVerify(pProcess, vaModuleBase, pbModuleHeader, &f32); + ntHeader = pbModuleHeaderOpt ? PE_HeaderGetVerify(H, pProcess, 0, pbModuleHeaderOpt, &f32) : PE_HeaderGetVerify(H, pProcess, vaModuleBase, pbModuleHeader, &f32); if(!ntHeader) { return FALSE; } if(f32) { memcpy(pDirectories, ((PIMAGE_NT_HEADERS32)ntHeader)->OptionalHeader.DataDirectory, IMAGE_NUMBEROF_DIRECTORY_ENTRIES * sizeof(IMAGE_DATA_DIRECTORY)); @@ -417,7 +417,7 @@ BOOL PE_DirectoryGetAll(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, } _Success_(return) -BOOL PE_GetCodeViewInfo(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt, _Out_ PPE_CODEVIEW_INFO pCodeViewInfo) +BOOL PE_GetCodeViewInfo(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt, _Out_ PPE_CODEVIEW_INFO pCodeViewInfo) { BOOL f, f32; BYTE pbModuleHeader[0x1000] = { 0 }; @@ -431,7 +431,7 @@ BOOL PE_GetCodeViewInfo(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, ZeroMemory(pCodeViewInfo, sizeof(PE_CODEVIEW_INFO)); // load both 32/64 bit ntHeader unless already supplied in parameter (only one of 32/64 bit hdr will be valid) // load nt header either by using optionally supplied module header or by fetching from memory. - ntHeader = pbModuleHeaderOpt ? PE_HeaderGetVerify(pProcess, 0, pbModuleHeaderOpt, &f32) : PE_HeaderGetVerify(pProcess, vaModuleBase, pbModuleHeader, &f32); + ntHeader = pbModuleHeaderOpt ? PE_HeaderGetVerify(H, pProcess, 0, pbModuleHeaderOpt, &f32) : PE_HeaderGetVerify(H, pProcess, vaModuleBase, pbModuleHeader, &f32); if(!ntHeader) { return FALSE; } if(!f32) { // 64-bit PE ntHeader64 = (PIMAGE_NT_HEADERS64)ntHeader; @@ -446,7 +446,7 @@ BOOL PE_GetCodeViewInfo(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, } if((cbDebugDirectory < sizeof(IMAGE_DEBUG_DIRECTORY)) || (vaDebugDirectory == vaModuleBase) || (cbDebugDirectory > cbImageSize)) { goto fail; } if(!(pbDebugDirectory = LocalAlloc(0, cbDebugDirectory))) { goto fail; } - if(!VmmRead(pProcess, vaDebugDirectory, pbDebugDirectory, cbDebugDirectory)) { goto fail; } + if(!VmmRead(H, pProcess, vaDebugDirectory, pbDebugDirectory, cbDebugDirectory)) { goto fail; } for(i = 0, iMax = cbDebugDirectory / sizeof(IMAGE_DEBUG_DIRECTORY); i < iMax; i++) { pDebugDirectory = ((PIMAGE_DEBUG_DIRECTORY)pbDebugDirectory) + i; f = !pDebugDirectory->Characteristics && @@ -454,7 +454,7 @@ BOOL PE_GetCodeViewInfo(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, (pDebugDirectory->SizeOfData <= sizeof(PE_CODEVIEW)) && (pDebugDirectory->SizeOfData > 24) && (pDebugDirectory->AddressOfRawData + pDebugDirectory->SizeOfData < cbImageSize) && - VmmRead(pProcess, vaModuleBase + pDebugDirectory->AddressOfRawData, (PBYTE)&pCodeViewInfo->CodeView, pDebugDirectory->SizeOfData) && + VmmRead(H, pProcess, vaModuleBase + pDebugDirectory->AddressOfRawData, (PBYTE)&pCodeViewInfo->CodeView, pDebugDirectory->SizeOfData) && (pCodeViewInfo->CodeView.Signature == 0x53445352) && (pCodeViewInfo->SizeCodeView = pDebugDirectory->SizeOfData); if(f) { @@ -490,6 +490,7 @@ typedef struct tdPE_SECTION_FILEREGIONS_RAW { * Retrieve the 'raw' section file regions from a PE header. The sections are * optionally retrieved between the cbStartOpt and cbSizeOpt address/sizes. * This is useful when reconstructing PE files from in-memory items. +* -- H * -- pProcess * -- vaModuleBase = PE module base address (unless pbModuleHeaderOpt is specified) * -- pbModuleHaderOpt = Optional buffer containing module header (MZ) page. @@ -499,7 +500,7 @@ typedef struct tdPE_SECTION_FILEREGIONS_RAW { * -- return */ _Success_(return) -BOOL PE_FileRaw_FileRegions(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt, _In_ DWORD cbFileRegionStart, _In_ DWORD cbFileRegionSize, _Out_ PPE_SECTION_FILEREGIONS_RAW pRegions) +BOOL PE_FileRaw_FileRegions(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt, _In_ DWORD cbFileRegionStart, _In_ DWORD cbFileRegionSize, _Out_ PPE_SECTION_FILEREGIONS_RAW pRegions) { BOOL f32, fRegionInScope, fRegionInScopeAll; BYTE pbModuleHeader[0x1000] = { 0 }; @@ -512,7 +513,7 @@ BOOL PE_FileRaw_FileRegions(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleB DWORD cbFileSectionStart, cbFileSectionEnd; PIMAGE_SECTION_HEADER pSections, pSection; // 1: load nt header and section base - ntHeader = pbModuleHeaderOpt ? PE_HeaderGetVerify(pProcess, 0, pbModuleHeaderOpt, &f32) : PE_HeaderGetVerify(pProcess, vaModuleBase, pbModuleHeader, &f32); + ntHeader = pbModuleHeaderOpt ? PE_HeaderGetVerify(H, pProcess, 0, pbModuleHeaderOpt, &f32) : PE_HeaderGetVerify(H, pProcess, vaModuleBase, pbModuleHeader, &f32); if(!ntHeader) { return FALSE; } if(f32) { // 32-bit PE ntHeader32 = (PIMAGE_NT_HEADERS32)ntHeader; @@ -560,7 +561,7 @@ BOOL PE_FileRaw_FileRegions(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleB return TRUE; } -DWORD PE_FileRaw_Size(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt) +DWORD PE_FileRaw_Size(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt) { BOOL f32; BYTE pbModuleHeader[0x1000] = { 0 }; @@ -570,7 +571,7 @@ DWORD PE_FileRaw_Size(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _ DWORD cSections, cbModuleFile, iSection; PIMAGE_SECTION_HEADER pSections; // 1: load nt header and section base - ntHeader = pbModuleHeaderOpt ? PE_HeaderGetVerify(pProcess, 0, pbModuleHeaderOpt, &f32) : PE_HeaderGetVerify(pProcess, vaModuleBase, pbModuleHeader, &f32); + ntHeader = pbModuleHeaderOpt ? PE_HeaderGetVerify(H, pProcess, 0, pbModuleHeaderOpt, &f32) : PE_HeaderGetVerify(H, pProcess, vaModuleBase, pbModuleHeader, &f32); if(!ntHeader) { return FALSE; } if(f32) { // 32-bit PE ntHeader32 = (PIMAGE_NT_HEADERS32)ntHeader; @@ -591,14 +592,14 @@ DWORD PE_FileRaw_Size(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _ } _Success_(return) -BOOL PE_FileRaw_Read(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _Out_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ DWORD cbOffset) +BOOL PE_FileRaw_Read(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _Out_ PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ DWORD cbOffset) { BOOL result; DWORD iRegion; PE_SECTION_FILEREGIONS_RAW PERegions; DWORD cbOffsetBuffer, cbRead; *pcbRead = 0; - result = PE_FileRaw_FileRegions(pProcess, vaModuleBase, NULL, cbOffset, cb, &PERegions); + result = PE_FileRaw_FileRegions(H, pProcess, vaModuleBase, NULL, cbOffset, cb, &PERegions); if(!result) { return FALSE; } ZeroMemory(pb, cb); if(cbOffset + cb > PERegions.cbTotalSize) { @@ -611,10 +612,11 @@ BOOL PE_FileRaw_Read(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _Out_ for(iRegion = 0; iRegion < PERegions.cRegions; iRegion++) { cbOffsetBuffer = PERegions.Region[iRegion].cbOffsetFile - cbOffset; if(cbOffsetBuffer + PERegions.Region[iRegion].cb > cb) { - VmmLog(MID_PE, LOGLEVEL_WARNING, "SHOULD NOT HAPPEN! potential buffer overflow avoided reading module at PID=%i BASE=%016llx", pProcess->dwPID, vaModuleBase); + VmmLog(H, MID_PE, LOGLEVEL_WARNING, "SHOULD NOT HAPPEN! potential buffer overflow avoided reading module at PID=%i BASE=%016llx", pProcess->dwPID, vaModuleBase); continue; } VmmReadEx( + H, pProcess, vaModuleBase + PERegions.Region[iRegion].cbOffsetVMem, pb + cbOffsetBuffer, @@ -627,13 +629,13 @@ BOOL PE_FileRaw_Read(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _Out_ } _Success_(return) -BOOL PE_FileRaw_Write(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ DWORD cbOffset) +BOOL PE_FileRaw_Write(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ DWORD cbOffset) { BOOL result; DWORD iRegion, cbOffsetBuffer; PE_SECTION_FILEREGIONS_RAW PERegions; *pcbWrite = 0; - result = PE_FileRaw_FileRegions(pProcess, vaModuleBase, NULL, cbOffset, cb, &PERegions); + result = PE_FileRaw_FileRegions(H, pProcess, vaModuleBase, NULL, cbOffset, cb, &PERegions); if(!result) { return FALSE; } if(cbOffset + cb > PERegions.cbTotalSize) { if(cbOffset >= PERegions.cbTotalSize) { @@ -645,10 +647,11 @@ BOOL PE_FileRaw_Write(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_r for(iRegion = 0; iRegion < PERegions.cRegions; iRegion++) { cbOffsetBuffer = PERegions.Region[iRegion].cbOffsetFile - cbOffset; if(cbOffsetBuffer + PERegions.Region[iRegion].cb > cb) { - VmmLog(MID_PE, LOGLEVEL_WARNING, "SHOULD NOT HAPPEN! potential buffer overflow avoided writing module at PID=%i BASE=%016llx", pProcess->dwPID, vaModuleBase); + VmmLog(H, MID_PE, LOGLEVEL_WARNING, "SHOULD NOT HAPPEN! potential buffer overflow avoided writing module at PID=%i BASE=%016llx", pProcess->dwPID, vaModuleBase); continue; } VmmWrite( + H, pProcess, vaModuleBase + PERegions.Region[iRegion].cbOffsetVMem, pb + cbOffsetBuffer, diff --git a/vmm/pe.h b/vmm/pe.h index d1ac4fb..e409bd9 100644 --- a/vmm/pe.h +++ b/vmm/pe.h @@ -45,17 +45,20 @@ typedef struct tdPE_THUNKINFO_EAT { /* * Retrieve the size of the module given its base. +* -- H * -- pProcess * -- vaModuleBase = PE module base address. * -- return = success: size of module. fail: 0. */ QWORD PE_GetSize( + _In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase ); /* * Retrieve the TimeDateStamp and CheckSum from the PE header. +* -- H * -- pProcess * -- vaModuleBase = PE module base address. * -- pdwTimeDateStamp @@ -64,6 +67,7 @@ QWORD PE_GetSize( */ _Success_(return) BOOL PE_GetTimeDateStampCheckSum( + _In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _Out_opt_ PDWORD pdwTimeDateStamp, @@ -73,11 +77,13 @@ BOOL PE_GetTimeDateStampCheckSum( /* * Lookup the virtual address of an exported function or symbol in the module supplied. * Similar to Windows 'GetProcAddress'. +* -- H * -- pProcess * -- vaModuleBase = PE module base address. * -- return = success: virtual address of function / symbol. fail: 0. */ QWORD PE_GetProcAddress( + _In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ LPSTR lpProcName @@ -86,6 +92,7 @@ QWORD PE_GetProcAddress( /* * Lookup the virtual address of an exported function or symbol in the module supplied * among with additional information returned in the pThunkInfoEAT struct. +* -- H * -- pProcess * -- vaModuleBase = PE module base address. * -- szProcName @@ -94,6 +101,7 @@ QWORD PE_GetProcAddress( */ _Success_(return) BOOL PE_GetThunkInfoEAT( + _In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ LPSTR szProcName, @@ -103,6 +111,7 @@ BOOL PE_GetThunkInfoEAT( /* * Retrieve an import address table (IAT) entry for a specific function. * This may be useful for IAT patching functionality. +* -- H * -- pProcess * -- vaModuleBase * -- szImportModuleName @@ -112,6 +121,7 @@ BOOL PE_GetThunkInfoEAT( */ _Success_(return) BOOL PE_GetThunkInfoIAT( + _In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ LPSTR szImportModuleName, @@ -121,6 +131,7 @@ BOOL PE_GetThunkInfoIAT( /* * Retrieve the module name and optionally the module size. +* -- H * -- pProcess * -- vaModuleBase * -- fOnFailDummyName @@ -131,23 +142,25 @@ BOOL PE_GetThunkInfoIAT( * -- return */ _Success_(return) -BOOL PE_GetModuleNameEx(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ BOOL fOnFailDummyName, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt, _Out_writes_(cszModuleName) PCHAR szModuleName, _In_ DWORD cszModuleName, _Out_opt_ PDWORD pdwSize); +BOOL PE_GetModuleNameEx(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ BOOL fOnFailDummyName, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt, _Out_writes_(cszModuleName) PCHAR szModuleName, _In_ DWORD cszModuleName, _Out_opt_ PDWORD pdwSize); _Success_(return) -BOOL PE_GetModuleName(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _Out_writes_(cszModuleName) PCHAR szModuleName, _In_ DWORD cszModuleName); +BOOL PE_GetModuleName(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _Out_writes_(cszModuleName) PCHAR szModuleName, _In_ DWORD cszModuleName); /* * Retrieve the number of sections in the module given by either the module base * virtual address or a pre-retrieved pbModuleHeader of size 0x1000. +* -- H * -- pProcess * -- vaModuleBase = PE module base address (unless pbModuleHeaderOpt is specified) * -- pbModuleHeaderOpt = Optional buffer containing module header (MZ) page. * -- return = success: number of sections. fail: 0. */ -WORD PE_SectionGetNumberOfEx(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt); -WORD PE_SectionGetNumberOf(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase); +WORD PE_SectionGetNumberOfEx(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt); +WORD PE_SectionGetNumberOf(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase); /* * Retrieve a single section header given its name. +* -- H * -- pProcess * -- vaModuleBase * -- szSectionName @@ -156,6 +169,7 @@ WORD PE_SectionGetNumberOf(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBa */ _Success_(return) BOOL PE_SectionGetFromName( + _In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ LPSTR szSectionName, @@ -164,6 +178,7 @@ BOOL PE_SectionGetFromName( /* * Retrieve all sections. +* -- H * -- pProcess * -- vaModuleBase * -- cSections @@ -172,6 +187,7 @@ BOOL PE_SectionGetFromName( */ _Success_(return) BOOL PE_SectionGetAll( + _In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_ DWORD cSections, @@ -181,33 +197,36 @@ BOOL PE_SectionGetAll( /* * Retrieve the number of export address table (EAT) entries - i.e. the number * of functions that the module is exporting. +* -- H * -- pProcess * -- vaModuleBase = PE module base address (unless pbModuleHeaderOpt is specified) * -- pbModuleHaderOpt = Optional buffer containing module header (MZ) page. * -- return = success: number of entries. fail: 0. */ -DWORD PE_EatGetNumberOfEx(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt); -inline DWORD PE_EatGetNumberOf(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase) +DWORD PE_EatGetNumberOfEx(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt); +inline DWORD PE_EatGetNumberOf(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase) { - return PE_EatGetNumberOfEx(pProcess, vaModuleBase, NULL); + return PE_EatGetNumberOfEx(H, pProcess, vaModuleBase, NULL); } /* * Retrieve the number of import address table (IAT) entries - i.e. the number * of functions that the module is importing. +* -- H * -- pProcess * -- vaModuleBase = PE module base address (unless pbModuleHeaderOpt is specified) * -- pbModuleHaderOpt = Optional buffer containing module header (MZ) page. * -- return = success: number of entries. fail: 0. */ -DWORD PE_IatGetNumberOfEx(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt); -inline DWORD PE_IatGetNumberOf(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase) +DWORD PE_IatGetNumberOfEx(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt); +inline DWORD PE_IatGetNumberOf(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase) { - return PE_IatGetNumberOfEx(pProcess, vaModuleBase, NULL); + return PE_IatGetNumberOfEx(H, pProcess, vaModuleBase, NULL); } /* * Retrieve info about the PE directories. +* -- H * -- pProcess * -- vaModuleBase = PE module base address (unless pbModuleHeaderOpt is specified) * -- pbModuleHeaderOpt = Optional buffer containing module header (MZ) page. @@ -215,6 +234,7 @@ inline DWORD PE_IatGetNumberOf(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModu */ _Success_(return) BOOL PE_DirectoryGetAll( + _In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt, @@ -223,6 +243,7 @@ BOOL PE_DirectoryGetAll( /* * Retrieve the offset of a PE directory - i.e. the VirtualAddress of the directory. +* -- H * -- pProcess * -- vaModuleBase = PE module base address (unless pbModuleHeaderOpt is specified) * -- pbModuleHeaderOpt = Optional buffer containing module header (MZ) page. @@ -230,6 +251,7 @@ BOOL PE_DirectoryGetAll( * -- return = the offset in bytes from PE base or 0 on fail. */ DWORD PE_DirectoryGetOffset( + _In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt, @@ -238,6 +260,7 @@ DWORD PE_DirectoryGetOffset( /* * Retrieve PDB debugging information from a single module. +* -- H * -- pProcess * -- vaModulebase * -- pbModuleHeaderOpt @@ -246,6 +269,7 @@ DWORD PE_DirectoryGetOffset( */ _Success_(return) BOOL PE_GetCodeViewInfo( + _In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt, @@ -255,12 +279,14 @@ BOOL PE_GetCodeViewInfo( /* * Retrieve the raw size of the 'file' estimation that is possible to rebuild * using PE sections from memory. +* -- H * -- pProcess * -- vaModuleBase = PE module base address (unless pbModuleHeaderOpt is specified) * -- pbModuleHaderOpt = Optional buffer containing module header (MZ) page. * -- return = success: size of file. fail: 0. */ DWORD PE_FileRaw_Size( + _In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModuleBase, _In_reads_opt_(0x1000) PBYTE pbModuleHeaderOpt @@ -268,6 +294,7 @@ DWORD PE_FileRaw_Size( /* * Read part of a, from memory, best-effort re-constructed PE file. +* -- H * -- pProcess * -- vaModuleBase = PE module base address. * -- pb @@ -278,6 +305,7 @@ DWORD PE_FileRaw_Size( */ _Success_(return) BOOL PE_FileRaw_Read( + _In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _Out_ PBYTE pb, @@ -290,6 +318,7 @@ BOOL PE_FileRaw_Read( * Write to the underlying pages which supports this re-constructed PE file. * This is normally not recommended and will be very dangerous since it is most * likely to affect all instances - in all processes - of the PE file written to. +* -- H * -- pProcess * -- vaModuleBase = PE module base address. * -- pb @@ -300,6 +329,7 @@ BOOL PE_FileRaw_Read( */ _Success_(return) BOOL PE_FileRaw_Write( + _In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD vaModuleBase, _In_reads_(cb) PBYTE pb, diff --git a/vmm/pluginmanager.c b/vmm/pluginmanager.c index 3c68d56..08538d9 100644 --- a/vmm/pluginmanager.c +++ b/vmm/pluginmanager.c @@ -11,13 +11,14 @@ #include "vmmdll.h" #include "vmmlog.h" #include "m_modules.h" +#include "fc.h" // // This file contains functionality related to keeping track of plugins, both // internal built-in ones and loadable plugins in the form of compliant DLLs. // // The functionality and data structures are at this moment single-threaded in -// this implementation and should be protected by a lock (ctxVmm->LockMaster). +// this implementation and should be protected by a lock (H->vmm.LockMaster). // // Core module calls are: List, Read, Write. // Other module calls are: Notify and Close. @@ -45,25 +46,27 @@ typedef struct tdPLUGIN_ENTRY { BOOL fRootModule; BOOL fProcessModule; PVMMDLL_PLUGIN_INTERNAL_CONTEXT ctxM; - BOOL(*pfnVisibleModule)(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP); - BOOL(*pfnList)(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList); - NTSTATUS(*pfnRead)(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset); - NTSTATUS(*pfnWrite)(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset); - VOID(*pfnNotify)(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent); - VOID(*pfnClose)(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP); + BOOL(*pfnVisibleModule)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP); + BOOL(*pfnList)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList); + NTSTATUS(*pfnRead)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset); + NTSTATUS(*pfnWrite)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset); + VOID(*pfnNotify)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent); + VOID(*pfnClose)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP); struct { PVOID ctxfc; - PHANDLE phEventIngestFinish; - PVOID(*pfnInitialize)(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP); - VOID(*pfnFinalize)(_In_opt_ PVOID ctxfc); + PVOID(*pfnInitialize)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP); + VOID(*pfnFinalize)(_In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc); VOID(*pfnTimeline)( + _In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc, _In_ HANDLE hTimeline, - _In_ VOID(*pfnAddEntry)(_In_ HANDLE hTimeline, _In_ QWORD ft, _In_ DWORD dwAction, _In_ DWORD dwPID, _In_ DWORD dwData32, _In_ QWORD qwData64, _In_ LPSTR uszText), - _In_ VOID(*pfnEntryAddBySql)(_In_ HANDLE hTimeline, _In_ DWORD cEntrySql, _In_ LPSTR *pszEntrySql)); - VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)); - VOID(*pfnIngestPhysmem)(_In_opt_ PVOID ctxfc, _In_ PVMMDLL_PLUGIN_FORENSIC_INGEST_PHYSMEM pIngestPhysmem); - VOID(*pfnIngestFinalize)(_In_opt_ PVOID ctxfc); + _In_ VOID(*pfnAddEntry)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ QWORD ft, _In_ DWORD dwAction, _In_ DWORD dwPID, _In_ DWORD dwData32, _In_ QWORD qwData64, _In_ LPSTR uszText), + _In_ VOID(*pfnEntryAddBySql)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ DWORD cEntrySql, _In_ LPSTR *pszEntrySql)); + VOID(*pfnLogCSV)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, VMMDLL_CSV_HANDLE hCSV); + VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)); + VOID(*pfnIngestPhysmem)(_In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc, _In_ PVMMDLL_PLUGIN_FORENSIC_INGEST_PHYSMEM pIngestPhysmem); + VOID(*pfnIngestVirtmem)(_In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc, _In_ DWORD dwPID, _In_ QWORD va, _In_ PBYTE pb, _In_ DWORD cb); + VOID(*pfnIngestFinalize)(_In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc); struct { PVMMDLL_PLUGIN_FORENSIC_INGEST_PHYSMEM p; } IngestPhysmem; @@ -87,7 +90,7 @@ typedef struct tdPLUGIN_TREE { PPLUGIN_ENTRY pPlugin; } PLUGIN_TREE, *PPLUGIN_TREE; -VOID PluginManager_Initialize_Python(); +VOID PluginManager_Initialize_Python(_In_ VMM_HANDLE H); @@ -162,17 +165,17 @@ finish: *puszSubPath = uszPath; } -VOID PluginManager_SetVisibility(_In_ BOOL fRoot, _In_ LPSTR uszPluginPath, _In_ BOOL fVisible) +VOID PluginManager_SetVisibility(_In_ VMM_HANDLE H, _In_ BOOL fRoot, _In_ LPSTR uszPluginPath, _In_ BOOL fVisible) { LPSTR uszSubPath; PPLUGIN_TREE pTree; if(uszPluginPath[0] == '\\') { uszPluginPath++; } - PluginManager_GetTree((fRoot ? ctxVmm->PluginManager.Root : ctxVmm->PluginManager.Proc), uszPluginPath, &pTree, &uszSubPath); + PluginManager_GetTree((fRoot ? H->vmm.PluginManager.Root : H->vmm.PluginManager.Proc), uszPluginPath, &pTree, &uszSubPath); PluginManager_SetTreeVisibility(pTree, fVisible); } -BOOL PluginManager_ModuleExistsDll(_In_opt_ HMODULE hDLL) { - PPLUGIN_ENTRY pModule = (PPLUGIN_ENTRY)ctxVmm->PluginManager.FLinkAll; +BOOL PluginManager_ModuleExistsDll(_In_ VMM_HANDLE H, _In_opt_ HMODULE hDLL) { + PPLUGIN_ENTRY pModule = (PPLUGIN_ENTRY)H->vmm.PluginManager.FLinkAll; while(pModule) { if(hDLL && (hDLL == pModule->hDLL)) { return TRUE; } pModule = pModule->FLinkAll; @@ -200,18 +203,18 @@ VOID PluginManager_ContextInitialize(_Out_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ PPLU ctx->MID = pModule->MID; } -VOID PluginManager_List(_In_opt_ PVMM_PROCESS pProcess, _In_ LPSTR uszPath, _Inout_ PHANDLE pFileList) +VOID PluginManager_List(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ LPSTR uszPath, _Inout_ PHANDLE pFileList) { DWORD i; BOOL fVisibleProgrammatic, result = TRUE; - QWORD tmStart = Statistics_CallStart(); + QWORD tmStart = Statistics_CallStart(H); VMMDLL_PLUGIN_CONTEXT ctxPlugin; LPSTR uszSubPath; PPLUGIN_TREE pTree; PPLUGIN_ENTRY pPlugin; - pTree = pProcess ? ctxVmm->PluginManager.Proc : ctxVmm->PluginManager.Root; + pTree = pProcess ? H->vmm.PluginManager.Proc : H->vmm.PluginManager.Root; if(!pTree) { return; } - PluginManager_GetTree((pProcess ? ctxVmm->PluginManager.Proc : ctxVmm->PluginManager.Root), uszPath, &pTree, &uszSubPath); + PluginManager_GetTree((pProcess ? H->vmm.PluginManager.Proc : H->vmm.PluginManager.Root), uszPath, &pTree, &uszSubPath); if(pTree->fVisible) { if(pTree->cChild && !uszSubPath[0]) { for(i = 0; i < pTree->cChild; i++) { @@ -219,7 +222,7 @@ VOID PluginManager_List(_In_opt_ PVMM_PROCESS pProcess, _In_ LPSTR uszPath, _Ino fVisibleProgrammatic = pTree->Child[i]->cChild || !pTree->Child[i]->pPlugin || !pTree->Child[i]->pPlugin->pfnVisibleModule; if(!fVisibleProgrammatic) { PluginManager_ContextInitialize(&ctxPlugin, pTree->Child[i]->pPlugin, pProcess, uszSubPath); - fVisibleProgrammatic = pTree->Child[i]->pPlugin->pfnVisibleModule(&ctxPlugin); + fVisibleProgrammatic = pTree->Child[i]->pPlugin->pfnVisibleModule(H, &ctxPlugin); } if(fVisibleProgrammatic) { VMMDLL_VfsList_AddDirectory(pFileList, pTree->Child[i]->uszName, NULL); @@ -229,215 +232,320 @@ VOID PluginManager_List(_In_opt_ PVMM_PROCESS pProcess, _In_ LPSTR uszPath, _Ino } if((pPlugin = pTree->pPlugin) && pPlugin->pfnList) { PluginManager_ContextInitialize(&ctxPlugin, pPlugin, pProcess, uszSubPath); - if(!pPlugin->pfnVisibleModule || pPlugin->pfnVisibleModule(&ctxPlugin)) { - pTree->pPlugin->pfnList(&ctxPlugin, pFileList); + if(!pPlugin->pfnVisibleModule || pPlugin->pfnVisibleModule(H, &ctxPlugin)) { + pTree->pPlugin->pfnList(H, &ctxPlugin, pFileList); } } } - Statistics_CallEnd(STATISTICS_ID_PluginManager_List, tmStart); + Statistics_CallEnd(H, STATISTICS_ID_PluginManager_List, tmStart); } -NTSTATUS PluginManager_Read(_In_opt_ PVMM_PROCESS pProcess, _In_ LPSTR uszPath, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS PluginManager_Read(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ LPSTR uszPath, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { - QWORD tmStart = Statistics_CallStart(); + QWORD tmStart = Statistics_CallStart(H); NTSTATUS nt; VMMDLL_PLUGIN_CONTEXT ctxPlugin; LPSTR uszSubPath; PPLUGIN_TREE pTree; PPLUGIN_ENTRY pPlugin; - pTree = pProcess ? ctxVmm->PluginManager.Proc : ctxVmm->PluginManager.Root; + pTree = pProcess ? H->vmm.PluginManager.Proc : H->vmm.PluginManager.Root; if(!pTree) { return VMMDLL_STATUS_FILE_INVALID; } - PluginManager_GetTree((pProcess ? ctxVmm->PluginManager.Proc : ctxVmm->PluginManager.Root), uszPath, &pTree, &uszSubPath); + PluginManager_GetTree((pProcess ? H->vmm.PluginManager.Proc : H->vmm.PluginManager.Root), uszPath, &pTree, &uszSubPath); if(pTree->fVisible) { if((pPlugin = pTree->pPlugin) && pPlugin->pfnRead) { PluginManager_ContextInitialize(&ctxPlugin, pPlugin, pProcess, uszSubPath); - nt = pPlugin->pfnRead(&ctxPlugin, pb, cb, pcbRead, cbOffset); - Statistics_CallEnd(STATISTICS_ID_PluginManager_Read, tmStart); + nt = pPlugin->pfnRead(H, &ctxPlugin, pb, cb, pcbRead, cbOffset); + Statistics_CallEnd(H, STATISTICS_ID_PluginManager_Read, tmStart); return nt; } } - Statistics_CallEnd(STATISTICS_ID_PluginManager_Read, tmStart); + Statistics_CallEnd(H, STATISTICS_ID_PluginManager_Read, tmStart); return VMMDLL_STATUS_FILE_INVALID; } -NTSTATUS PluginManager_Write(_In_opt_ PVMM_PROCESS pProcess, _In_ LPSTR uszPath, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) +NTSTATUS PluginManager_Write(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ LPSTR uszPath, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) { - QWORD tmStart = Statistics_CallStart(); + QWORD tmStart = Statistics_CallStart(H); NTSTATUS nt; VMMDLL_PLUGIN_CONTEXT ctxPlugin; LPSTR uszSubPath; PPLUGIN_TREE pTree; PPLUGIN_ENTRY pPlugin; - pTree = pProcess ? ctxVmm->PluginManager.Proc : ctxVmm->PluginManager.Root; + pTree = pProcess ? H->vmm.PluginManager.Proc : H->vmm.PluginManager.Root; if(!pTree) { return VMMDLL_STATUS_FILE_INVALID; } - PluginManager_GetTree((pProcess ? ctxVmm->PluginManager.Proc : ctxVmm->PluginManager.Root), uszPath, &pTree, &uszSubPath); + PluginManager_GetTree((pProcess ? H->vmm.PluginManager.Proc : H->vmm.PluginManager.Root), uszPath, &pTree, &uszSubPath); if(pTree->fVisible) { if((pPlugin = pTree->pPlugin) && pPlugin->pfnWrite) { PluginManager_ContextInitialize(&ctxPlugin, pPlugin, pProcess, uszSubPath); - nt = pPlugin->pfnWrite(&ctxPlugin, pb, cb, pcbWrite, cbOffset); - Statistics_CallEnd(STATISTICS_ID_PluginManager_Write, tmStart); + nt = pPlugin->pfnWrite(H, &ctxPlugin, pb, cb, pcbWrite, cbOffset); + Statistics_CallEnd(H, STATISTICS_ID_PluginManager_Write, tmStart); return nt; } } - Statistics_CallEnd(STATISTICS_ID_PluginManager_Write, tmStart); + Statistics_CallEnd(H, STATISTICS_ID_PluginManager_Write, tmStart); return VMMDLL_STATUS_FILE_INVALID; } -BOOL PluginManager_Notify(_In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent) +BOOL PluginManager_Notify(_In_ VMM_HANDLE H, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent) { VMMDLL_PLUGIN_CONTEXT ctxPlugin; - QWORD tmStart = Statistics_CallStart(); - PPLUGIN_ENTRY pPlugin = (PPLUGIN_ENTRY)ctxVmm->PluginManager.FLinkNotify; + QWORD tmStart = Statistics_CallStart(H); + PPLUGIN_ENTRY pPlugin = (PPLUGIN_ENTRY)H->vmm.PluginManager.FLinkNotify; while(pPlugin) { if(pPlugin->pfnNotify) { PluginManager_ContextInitialize(&ctxPlugin, pPlugin, NULL, NULL); - pPlugin->pfnNotify(&ctxPlugin, fEvent, pvEvent, cbEvent); + pPlugin->pfnNotify(H, &ctxPlugin, fEvent, pvEvent, cbEvent); } pPlugin = pPlugin->FLinkNotify; } - Statistics_CallEnd(STATISTICS_ID_PluginManager_Notify, tmStart); + Statistics_CallEnd(H, STATISTICS_ID_PluginManager_Notify, tmStart); return TRUE; } /* * Initialize plugins with forensic mode capabilities. +* -- H */ -VOID PluginManager_FcInitialize() +VOID PluginManager_FcInitialize(_In_ VMM_HANDLE H) { VMMDLL_PLUGIN_CONTEXT ctxPlugin; - QWORD tmStart = Statistics_CallStart(); - PPLUGIN_ENTRY pPlugin = (PPLUGIN_ENTRY)ctxVmm->PluginManager.FLinkForensic; + QWORD tmStart = Statistics_CallStart(H); + PPLUGIN_ENTRY pPlugin = (PPLUGIN_ENTRY)H->vmm.PluginManager.FLinkForensic; while(pPlugin) { if(pPlugin->fc.pfnInitialize) { PluginManager_ContextInitialize(&ctxPlugin, pPlugin, NULL, NULL); - pPlugin->fc.ctxfc = pPlugin->fc.pfnInitialize(&ctxPlugin); + pPlugin->fc.ctxfc = pPlugin->fc.pfnInitialize(H, &ctxPlugin); } pPlugin = pPlugin->FLinkForensic; } - Statistics_CallEnd(STATISTICS_ID_PluginManager_FcInitialize, tmStart); + Statistics_CallEnd(H, STATISTICS_ID_PluginManager_FcInitialize, tmStart); } /* * Finalize plugins with forensic mode capabilities. +* -- H */ -VOID PluginManager_FcFinalize() +VOID PluginManager_FcFinalize(_In_ VMM_HANDLE H) { - QWORD tmStart = Statistics_CallStart(); - PPLUGIN_ENTRY pModule = (PPLUGIN_ENTRY)ctxVmm->PluginManager.FLinkForensic; + QWORD tmStart = Statistics_CallStart(H); + PPLUGIN_ENTRY pModule = (PPLUGIN_ENTRY)H->vmm.PluginManager.FLinkForensic; while(pModule) { if(pModule->fc.pfnFinalize) { - pModule->fc.pfnFinalize(pModule->fc.ctxfc); + pModule->fc.pfnFinalize(H, pModule->fc.ctxfc); + pModule->fc.pfnFinalize = NULL; pModule->fc.ctxfc = NULL; } pModule = pModule->FLinkForensic; } - Statistics_CallEnd(STATISTICS_ID_PluginManager_FcFinalize, tmStart); + Statistics_CallEnd(H, STATISTICS_ID_PluginManager_FcFinalize, tmStart); } /* * Worker thread entry point: * Ingest physical memory into plugins with forensic mode capabilities. -* -- pModule +* -- H +* -- ctx */ -VOID PluginManager_FcIngestPhysmem_ThreadProc(PPLUGIN_ENTRY pModule) +VOID PluginManager_FcIngestPhysmem_ThreadProc(_In_ VMM_HANDLE H, _In_ PVOID ctx) { - pModule->fc.pfnIngestPhysmem(pModule->fc.ctxfc, pModule->fc.IngestPhysmem.p); + PPLUGIN_ENTRY pModule = ctx; + if(H->fAbort) { return; } + pModule->fc.pfnIngestPhysmem(H, pModule->fc.ctxfc, pModule->fc.IngestPhysmem.p); } /* * Ingest physical memory into plugins with forensic mode capabilities. +* -- H * -- pIngestPhysmem */ -VOID PluginManager_FcIngestPhysmem(_In_ PVMMDLL_PLUGIN_FORENSIC_INGEST_PHYSMEM pIngestPhysmem) +VOID PluginManager_FcIngestPhysmem(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_INGEST_PHYSMEM pIngestPhysmem) { - QWORD tmStart = Statistics_CallStart(); - PPLUGIN_ENTRY pModule = (PPLUGIN_ENTRY)ctxVmm->PluginManager.FLinkForensic; + DWORD cWork = 0; + PVOID ctxs[MAXIMUM_WAIT_OBJECTS]; + PVMM_WORK_START_ROUTINE_PVOID_PFN pfns[MAXIMUM_WAIT_OBJECTS]; + QWORD tmStart = Statistics_CallStart(H); + PPLUGIN_ENTRY pModule = (PPLUGIN_ENTRY)H->vmm.PluginManager.FLinkForensic; while(pModule) { if(pModule->fc.pfnIngestPhysmem) { - ResetEvent(pModule->fc.phEventIngestFinish); pModule->fc.IngestPhysmem.p = pIngestPhysmem; - // ingestion will happen in parallel between all plugins, but this - // function will wait for all ingestion to finish before exiting. - VmmWork((LPTHREAD_START_ROUTINE)PluginManager_FcIngestPhysmem_ThreadProc, pModule, pModule->fc.phEventIngestFinish); + ctxs[cWork] = pModule; + pfns[cWork] = PluginManager_FcIngestPhysmem_ThreadProc; + cWork++; + if(cWork >= MAXIMUM_WAIT_OBJECTS) { return; } } pModule = pModule->FLinkForensic; } - WaitForMultipleObjects(ctxVmm->PluginManager.fc.cEvent, ctxVmm->PluginManager.fc.hEvent, TRUE, INFINITE); - Statistics_CallEnd(STATISTICS_ID_PluginManager_FcIngestPhysmem, tmStart); + VmmWorkWaitMultiple2_Void(H, cWork, pfns, ctxs); + Statistics_CallEnd(H, STATISTICS_ID_PluginManager_FcIngestPhysmem, tmStart); +} + +typedef struct tVMMPLUGIN_INGEST_VIRTMEM { + VOID(*pfnIngestVirtmem)(_In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc, _In_ DWORD dwPID, _In_ QWORD va, _In_ PBYTE pb, _In_ DWORD cb); + PVOID ctxfc; + PVMM_PROCESS pProcess; + QWORD va; + DWORD cb; + PBYTE pb; +} VMMPLUGIN_INGEST_VIRTMEM, *PVMMPLUGIN_INGEST_VIRTMEM; + +/* +* Worker thread entry point: +* Ingest virtual memory into plugins with forensic mode capabilities. +* -- H +* -- ctx +*/ +VOID PluginManager_FcIngestVirtmem_ThreadProc(_In_ VMM_HANDLE H, _In_ PVOID ctx) +{ + PVMMPLUGIN_INGEST_VIRTMEM ctxVM = ctx; + if(H->fAbort) { return; } + ctxVM->pfnIngestVirtmem(H, ctxVM->ctxfc, ctxVM->pProcess->dwPID, ctxVM->va, ctxVM->pb, ctxVM->cb); +} + +/* +* Ingest virtual memory into plugins with forensic mode capabilities. +* -- H +* -- pProcess +* -- va +* -- pb +* -- cb +*/ +VOID PluginManager_FcIngestVirtmem(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD va, _In_ PBYTE pb, _In_ DWORD cb) +{ + DWORD cWork = 0; + PVMM_WORK_START_ROUTINE_PVOID_PFN pfns[MAXIMUM_WAIT_OBJECTS]; + VMMPLUGIN_INGEST_VIRTMEM ctxa[MAXIMUM_WAIT_OBJECTS]; + PVMMPLUGIN_INGEST_VIRTMEM ctx, ctxs[MAXIMUM_WAIT_OBJECTS]; + QWORD tmStart = Statistics_CallStart(H); + PPLUGIN_ENTRY pModule = (PPLUGIN_ENTRY)H->vmm.PluginManager.FLinkForensic; + while(pModule) { + if(pModule->fc.pfnIngestVirtmem) { + ctx = ctxa + cWork; + ctx->pfnIngestVirtmem = pModule->fc.pfnIngestVirtmem; + ctx->ctxfc = pModule->fc.ctxfc; + ctx->pProcess = pProcess; + ctx->va = va; + ctx->cb = cb; + ctx->pb = pb; + ctxs[cWork] = ctx; + pfns[cWork] = PluginManager_FcIngestVirtmem_ThreadProc; + cWork++; + if(cWork >= MAXIMUM_WAIT_OBJECTS) { return; } + } + pModule = pModule->FLinkForensic; + } + VmmWorkWaitMultiple2_Void(H, cWork, pfns, (PVOID*)ctxs); + Statistics_CallEnd(H, STATISTICS_ID_PluginManager_FcIngestVirtmem, tmStart); } /* * All ingestion actions are completed. +* -- H */ -VOID PluginManager_FcIngestFinalize() +VOID PluginManager_FcIngestFinalize(_In_ VMM_HANDLE H) { - QWORD tmStart = Statistics_CallStart(); - PPLUGIN_ENTRY pModule = (PPLUGIN_ENTRY)ctxVmm->PluginManager.FLinkForensic; + QWORD tmStart = Statistics_CallStart(H); + PPLUGIN_ENTRY pModule = (PPLUGIN_ENTRY)H->vmm.PluginManager.FLinkForensic; while(pModule) { if(pModule->fc.pfnIngestFinalize) { - pModule->fc.pfnIngestFinalize(pModule->fc.ctxfc); + pModule->fc.pfnIngestFinalize(H, pModule->fc.ctxfc); } pModule = pModule->FLinkForensic; } - Statistics_CallEnd(STATISTICS_ID_PluginManager_FcIngestPhysmem, tmStart); + Statistics_CallEnd(H, STATISTICS_ID_PluginManager_FcIngestPhysmem, tmStart); } /* * Register plugins with timelining capabilities with the timeline manager * and call into each plugin to allow them to add their timelining entries. * NB! This function is meant to be called by the core forensic subsystem only. +* -- H * -- pfnRegister = callback function to register timeline module. * -- pfnClose = function to close the timeline handle. * -- pfnAddEntry = callback function to call to add a timelining entry. +* -- pfnEntryAddBySql = callback function to add timelining entries by sqlite query. */ VOID PluginManager_FcTimeline( - _In_ HANDLE(*pfnRegister)(_In_reads_(6) LPSTR sNameShort, _In_reads_(32) LPSTR szFileUTF8), - _In_ VOID(*pfnClose)(_In_ HANDLE hTimeline), - _In_ VOID(*pfnAddEntry)(_In_ HANDLE hTimeline, _In_ QWORD ft, _In_ DWORD dwAction, _In_ DWORD dwPID, _In_ DWORD dwData32, _In_ QWORD qwData64, _In_ LPSTR uszText), - _In_ VOID(*pfnEntryAddBySql)(_In_ HANDLE hTimeline, _In_ DWORD cEntrySql, _In_ LPSTR *pszEntrySql) + _In_ VMM_HANDLE H, + _In_ HANDLE(*pfnRegister)(_In_ VMM_HANDLE H, _In_reads_(6) LPSTR sNameShort, _In_reads_(32) LPSTR szFileUTF8), + _In_ VOID(*pfnClose)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline), + _In_ VOID(*pfnAddEntry)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ QWORD ft, _In_ DWORD dwAction, _In_ DWORD dwPID, _In_ DWORD dwData32, _In_ QWORD qwData64, _In_ LPSTR uszText), + _In_ VOID(*pfnEntryAddBySql)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ DWORD cEntrySql, _In_ LPSTR *pszEntrySql) ) { HANDLE hTimeline; - QWORD tmStart = Statistics_CallStart(); - PPLUGIN_ENTRY pModule = (PPLUGIN_ENTRY)ctxVmm->PluginManager.FLinkForensic; + QWORD tmStart = Statistics_CallStart(H); + PPLUGIN_ENTRY pModule = (PPLUGIN_ENTRY)H->vmm.PluginManager.FLinkForensic; while(pModule) { if(pModule->fc.pfnTimeline) { - hTimeline = pfnRegister(pModule->fc.Timeline.sNameShort, pModule->fc.Timeline.szFileUTF8); + hTimeline = pfnRegister(H, pModule->fc.Timeline.sNameShort, pModule->fc.Timeline.szFileUTF8); if(hTimeline) { - pModule->fc.pfnTimeline(pModule->fc.ctxfc, hTimeline, pfnAddEntry, pfnEntryAddBySql); - pfnClose(hTimeline); + pModule->fc.pfnTimeline(H, pModule->fc.ctxfc, hTimeline, pfnAddEntry, pfnEntryAddBySql); + pfnClose(H, hTimeline); + hTimeline = NULL; } } pModule = pModule->FLinkForensic; } - Statistics_CallEnd(STATISTICS_ID_PluginManager_FcTimeline, tmStart); + Statistics_CallEnd(H, STATISTICS_ID_PluginManager_FcTimeline, tmStart); +} + +/* +* Call each plugin capable of forensic csv log. Plugins may be process or global. +* NB! This function is meant to be called by the core forensic subsystem only. +* -- H +* -- hCSV +* -- return = 0 (to make function compatible with LPTHREAD_START_ROUTINE). +*/ +DWORD PluginManager_FcLogCSV(_In_ VMM_HANDLE H, _In_ VMMDLL_CSV_HANDLE hCSV) +{ + VMMDLL_PLUGIN_CONTEXT ctxPlugin; + QWORD tmStart = Statistics_CallStart(H); + PPLUGIN_ENTRY pPlugin = (PPLUGIN_ENTRY)H->vmm.PluginManager.FLinkForensic; + PVMM_PROCESS pObProcess = NULL; + while(pPlugin && !H->fAbort) { + if(pPlugin->fc.pfnLogCSV) { + // global plugins: + PluginManager_ContextInitialize(&ctxPlugin, pPlugin, NULL, NULL); + pPlugin->fc.pfnLogCSV(H, &ctxPlugin, hCSV); + // per-process plugins: + while((pObProcess = VmmProcessGetNext(H, pObProcess, VMM_FLAG_PROCESS_SHOW_TERMINATED | VMM_FLAG_PROCESS_TOKEN))) { + PluginManager_ContextInitialize(&ctxPlugin, pPlugin, pObProcess, NULL); + FcCsv_Reset(hCSV); + pPlugin->fc.pfnLogCSV(H, &ctxPlugin, hCSV); + } + } + pPlugin = pPlugin->FLinkForensic; + } + Statistics_CallEnd(H, STATISTICS_ID_PluginManager_FcLogCSV, tmStart); + return 0; } /* * Call each plugin capable of forensic json log. Plugins may be process or global. * NB! This function is meant to be called by the core forensic subsystem only. +* -- H * -- pfnAddEntry = callback function to call to add a json entry. * -- return = 0 (to make function compatible with LPTHREAD_START_ROUTINE). */ -DWORD PluginManager_FcLogJSON(_In_ VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) +DWORD PluginManager_FcLogJSON(_In_ VMM_HANDLE H, _In_ VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)) { VMMDLL_PLUGIN_CONTEXT ctxPlugin; - QWORD tmStart = Statistics_CallStart(); - PPLUGIN_ENTRY pPlugin = (PPLUGIN_ENTRY)ctxVmm->PluginManager.FLinkForensic; + QWORD tmStart = Statistics_CallStart(H); + PPLUGIN_ENTRY pPlugin = (PPLUGIN_ENTRY)H->vmm.PluginManager.FLinkForensic; PVMM_PROCESS pObProcess = NULL; - while(pPlugin && ctxVmm->Work.fEnabled) { + while(pPlugin && !H->fAbort) { if(pPlugin->fc.pfnLogJSON) { // global plugins: PluginManager_ContextInitialize(&ctxPlugin, pPlugin, NULL, NULL); - pPlugin->fc.pfnLogJSON(&ctxPlugin, pfnLogJSON); + pPlugin->fc.pfnLogJSON(H, &ctxPlugin, pfnLogJSON); // per-process plugins: - while((pObProcess = VmmProcessGetNext(pObProcess, 0))) { + while((pObProcess = VmmProcessGetNext(H, pObProcess, VMM_FLAG_PROCESS_SHOW_TERMINATED | VMM_FLAG_PROCESS_TOKEN))) { PluginManager_ContextInitialize(&ctxPlugin, pPlugin, pObProcess, NULL); - pPlugin->fc.pfnLogJSON(&ctxPlugin, pfnLogJSON); + pPlugin->fc.pfnLogJSON(H, &ctxPlugin, pfnLogJSON); } } pPlugin = pPlugin->FLinkForensic; } - Statistics_CallEnd(STATISTICS_ID_PluginManager_FcLogJSON, tmStart); + Statistics_CallEnd(H, STATISTICS_ID_PluginManager_FcLogJSON, tmStart); return 0; } @@ -447,7 +555,7 @@ DWORD PluginManager_FcLogJSON(_In_ VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_FORENSI // MODULES REGISTRATION/CLEANUP FUNCTIONALITY - IMPLEMENTATION BELOW: // ---------------------------------------------------------------------------- -BOOL PluginManager_Register(_In_ PVMMDLL_PLUGIN_REGINFO pRegInfo) +BOOL PluginManager_Register(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_REGINFO pRegInfo) { DWORD iPluginNameStart; LPSTR uszPluginName, uszLogName; @@ -455,19 +563,41 @@ BOOL PluginManager_Register(_In_ PVMMDLL_PLUGIN_REGINFO pRegInfo) PPLUGIN_TREE pPluginTreeEntry; // 1: tests if plugin is valid pRegInfo->reg_info.uszPathName[127] = 0; - if(ctxVmm->PluginManager.fc.cEvent >= _countof(ctxVmm->PluginManager.fc.hEvent)) { return FALSE; } - if(!pRegInfo || (pRegInfo->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRegInfo->wVersion > VMMDLL_PLUGIN_REGINFO_VERSION)) { return FALSE; } - if(!pRegInfo->reg_info.uszPathName[0]) { return FALSE; } + if(!pRegInfo || (pRegInfo->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRegInfo->wVersion > VMMDLL_PLUGIN_REGINFO_VERSION)) { + VmmLog(H, MID_PLUGIN, LOGLEVEL_WARNING, "LOAD_FAIL: invalid plugin magic/version va=%p", pRegInfo); + return FALSE; + } + if(!pRegInfo->reg_info.uszPathName[0]) { + VmmLog(H, MID_PLUGIN, LOGLEVEL_WARNING, "LOAD_FAIL: missing plugin path/name"); + return FALSE; + } uszPluginName = CharUtil_PathSplitLast(pRegInfo->reg_info.uszPathName); if(strlen(uszPluginName) > 31) { return FALSE; } - if(pRegInfo->reg_info.fRootModule && PluginManager_ModuleExists(ctxVmm->PluginManager.Root, pRegInfo->reg_info.uszPathName)) { return FALSE; } - if(pRegInfo->reg_info.fProcessModule && PluginManager_ModuleExists(ctxVmm->PluginManager.Proc, pRegInfo->reg_info.uszPathName)) { return FALSE; } + if(pRegInfo->reg_info.fRootModule && PluginManager_ModuleExists(H->vmm.PluginManager.Root, pRegInfo->reg_info.uszPathName)) { + VmmLog(H, MID_PLUGIN, LOGLEVEL_WARNING, "LOAD_FAIL: root plugin '%s' already exists", uszPluginName); + return FALSE; + } + if(pRegInfo->reg_info.fProcessModule && PluginManager_ModuleExists(H->vmm.PluginManager.Proc, pRegInfo->reg_info.uszPathName)) { + VmmLog(H, MID_PLUGIN, LOGLEVEL_WARNING, "LOAD_FAIL: process plugin '%s' already exists", uszPluginName); + return FALSE; + } + if(!pRegInfo->reg_info.fRootModule && !pRegInfo->reg_info.fProcessModule) { + VmmLog(H, MID_PLUGIN, LOGLEVEL_WARNING, "LOAD_FAIL: plugin '%s' is neither root/process type", uszPluginName); + return FALSE; + } + if(!pRegInfo->reg_fnfc.pfnIngestPhysmem && (H->vmm.PluginManager.cIngestPhysmem >= MAXIMUM_WAIT_OBJECTS)) { + VmmLog(H, MID_PLUGIN, LOGLEVEL_WARNING, "LOAD_FAIL: plugin '%s' would exceed max # IngestPhysmem modules (%i)", uszPluginName, MAXIMUM_WAIT_OBJECTS); + return FALSE; + } + if(!pRegInfo->reg_fnfc.pfnIngestVirtmem && (H->vmm.PluginManager.cIngestVirtmem >= MAXIMUM_WAIT_OBJECTS)) { + VmmLog(H, MID_PLUGIN, LOGLEVEL_WARNING, "LOAD_FAIL: plugin '%s' would exceed max # Ingestvirtmem modules (%i)", uszPluginName, MAXIMUM_WAIT_OBJECTS); + return FALSE; + } + // 2: register plugin pModule = (PPLUGIN_ENTRY)LocalAlloc(LMEM_ZEROINIT, sizeof(PLUGIN_ENTRY)); if(!pModule) { return FALSE; } - if(!pRegInfo->reg_info.fRootModule && !pRegInfo->reg_info.fProcessModule) { return FALSE; } - // 2: register plugin pModule->hDLL = pRegInfo->hDLL; - pModule->MID = InterlockedIncrement(&ctxVmm->PluginManager.dwNextMID); + pModule->MID = InterlockedIncrement(&H->vmm.PluginManager.dwNextMID); strncpy_s(pModule->uszName, 32, uszPluginName, _TRUNCATE); pModule->dwNameHash = CharUtil_HashNameFsU(pModule->uszName, TRUE); pModule->fRootModule = pRegInfo->reg_info.fRootModule; @@ -483,36 +613,36 @@ BOOL PluginManager_Register(_In_ PVMMDLL_PLUGIN_REGINFO pRegInfo) pModule->fc.pfnInitialize = pRegInfo->reg_fnfc.pfnInitialize; pModule->fc.pfnFinalize = pRegInfo->reg_fnfc.pfnFinalize; pModule->fc.pfnTimeline = pRegInfo->reg_fnfc.pfnTimeline; + pModule->fc.pfnLogCSV = pRegInfo->reg_fnfc.pfnLogCSV; pModule->fc.pfnLogJSON = pRegInfo->reg_fnfc.pfnLogJSON; pModule->fc.pfnIngestPhysmem = pRegInfo->reg_fnfc.pfnIngestPhysmem; + pModule->fc.pfnIngestVirtmem = pRegInfo->reg_fnfc.pfnIngestVirtmem; pModule->fc.pfnIngestFinalize = pRegInfo->reg_fnfc.pfnIngestFinalize; memcpy(pModule->fc.Timeline.sNameShort, pRegInfo->reg_info.sTimelineNameShort, _countof(pModule->fc.Timeline.sNameShort)); memcpy(pModule->fc.Timeline.szFileUTF8, pRegInfo->reg_info.uszTimelineFile, _countof(pModule->fc.Timeline.szFileUTF8)); - if(pRegInfo->reg_fnfc.pfnIngestPhysmem) { - ctxVmm->PluginManager.fc.hEvent[ctxVmm->PluginManager.fc.cEvent] = CreateEvent(NULL, TRUE, TRUE, NULL); - pModule->fc.phEventIngestFinish = ctxVmm->PluginManager.fc.hEvent[ctxVmm->PluginManager.fc.cEvent++]; - } - VmmLog(MID_PLUGIN, LOGLEVEL_VERBOSE, "MODULE_LOAD: %s module: '%s'", (pModule->hDLL ? " native " : "built-in"), pRegInfo->reg_info.uszPathName); + VmmLog(H, MID_PLUGIN, LOGLEVEL_VERBOSE, "LOAD: %s module: '%s'", (pModule->hDLL ? " native " : "built-in"), pRegInfo->reg_info.uszPathName); if(pModule->pfnNotify) { - pModule->FLinkNotify = (PPLUGIN_ENTRY)ctxVmm->PluginManager.FLinkNotify; - ctxVmm->PluginManager.FLinkNotify = pModule; + pModule->FLinkNotify = (PPLUGIN_ENTRY)H->vmm.PluginManager.FLinkNotify; + H->vmm.PluginManager.FLinkNotify = pModule; } - if(pModule->fc.pfnInitialize || pModule->fc.pfnFinalize || pModule->fc.pfnTimeline || pModule->fc.pfnLogJSON || pModule->fc.pfnIngestPhysmem || pModule->fc.pfnIngestFinalize) { - pModule->FLinkForensic = (PPLUGIN_ENTRY)ctxVmm->PluginManager.FLinkForensic; - ctxVmm->PluginManager.FLinkForensic = pModule; + if(pModule->fc.pfnInitialize || pModule->fc.pfnFinalize || pModule->fc.pfnTimeline || pModule->fc.pfnLogCSV || pModule->fc.pfnLogJSON || pModule->fc.pfnIngestPhysmem || pModule->fc.pfnIngestVirtmem || pModule->fc.pfnIngestFinalize) { + if(pModule->fc.pfnIngestPhysmem) { H->vmm.PluginManager.cIngestPhysmem++; } + if(pModule->fc.pfnIngestVirtmem) { H->vmm.PluginManager.cIngestVirtmem++; } + pModule->FLinkForensic = (PPLUGIN_ENTRY)H->vmm.PluginManager.FLinkForensic; + H->vmm.PluginManager.FLinkForensic = pModule; } - pModule->FLinkAll = (PPLUGIN_ENTRY)ctxVmm->PluginManager.FLinkAll; - ctxVmm->PluginManager.FLinkAll = pModule; + pModule->FLinkAll = (PPLUGIN_ENTRY)H->vmm.PluginManager.FLinkAll; + H->vmm.PluginManager.FLinkAll = pModule; // 3: register plugin in plugin tree iPluginNameStart = (pRegInfo->reg_info.uszPathName[0] == '\\') ? 1 : 0; if(pModule->fRootModule) { - pPluginTreeEntry = PluginManager_Register_GetCreateTree(ctxVmm->PluginManager.Root, pRegInfo->reg_info.uszPathName + iPluginNameStart, !pRegInfo->reg_info.fRootModuleHidden); + pPluginTreeEntry = PluginManager_Register_GetCreateTree(H->vmm.PluginManager.Root, pRegInfo->reg_info.uszPathName + iPluginNameStart, !pRegInfo->reg_info.fRootModuleHidden); if(pPluginTreeEntry && !pPluginTreeEntry->pPlugin) { pPluginTreeEntry->pPlugin = pModule; } } if(pModule->fProcessModule) { - pPluginTreeEntry = PluginManager_Register_GetCreateTree(ctxVmm->PluginManager.Proc, pRegInfo->reg_info.uszPathName + iPluginNameStart, !pRegInfo->reg_info.fProcessModuleHidden); + pPluginTreeEntry = PluginManager_Register_GetCreateTree(H->vmm.PluginManager.Proc, pRegInfo->reg_info.uszPathName + iPluginNameStart, !pRegInfo->reg_info.fProcessModuleHidden); if(pPluginTreeEntry && !pPluginTreeEntry->pPlugin) { pPluginTreeEntry->pPlugin = pModule; } @@ -525,7 +655,7 @@ BOOL PluginManager_Register(_In_ PVMMDLL_PLUGIN_REGINFO pRegInfo) } else { uszLogName = "root"; } - VmmLog_RegisterModule(pModule->MID, uszLogName, (pModule->hDLL ? TRUE : FALSE)); + VmmLog_RegisterModule(H, pModule->MID, uszLogName, (pModule->hDLL ? TRUE : FALSE)); return TRUE; } @@ -539,53 +669,49 @@ VOID PluginManager_Close_Tree(_In_ PPLUGIN_TREE pTree) LocalFree(pTree); } -VOID PluginManager_Close() +VOID PluginManager_Close(_In_ VMM_HANDLE H) { PPLUGIN_ENTRY pPlugin; VMMDLL_PLUGIN_CONTEXT ctxPlugin; - PPLUGIN_TREE pTreeRoot = ctxVmm->PluginManager.Root, pTreeProc = ctxVmm->PluginManager.Proc; - ctxVmm->PluginManager.Root = NULL; - ctxVmm->PluginManager.Proc = NULL; + PPLUGIN_TREE pTreeRoot = H->vmm.PluginManager.Root, pTreeProc = H->vmm.PluginManager.Proc; + H->vmm.PluginManager.Root = NULL; + H->vmm.PluginManager.Proc = NULL; PluginManager_Close_Tree(pTreeRoot); PluginManager_Close_Tree(pTreeProc); - ctxVmm->PluginManager.FLinkNotify = NULL; - while((pPlugin = (PPLUGIN_ENTRY)ctxVmm->PluginManager.FLinkAll)) { + H->vmm.PluginManager.FLinkNotify = NULL; + while((pPlugin = (PPLUGIN_ENTRY)H->vmm.PluginManager.FLinkAll)) { // 1: Detach current module list entry from list - ctxVmm->PluginManager.FLinkAll = pPlugin->FLinkAll; + H->vmm.PluginManager.FLinkAll = pPlugin->FLinkAll; // 2: Close module callback if(pPlugin->pfnClose) { PluginManager_ContextInitialize(&ctxPlugin, pPlugin, NULL, NULL); - pPlugin->pfnClose(&ctxPlugin); + pPlugin->pfnClose(H, &ctxPlugin); } // 3: FreeLibrary (if last module belonging to specific Library) - if(pPlugin->hDLL && !PluginManager_ModuleExistsDll(pPlugin->hDLL)) { FreeLibrary(pPlugin->hDLL); } + if(pPlugin->hDLL && !PluginManager_ModuleExistsDll(H, pPlugin->hDLL)) { FreeLibrary(pPlugin->hDLL); } // 4: LocalFree this ListEntry LocalFree(pPlugin); } - // 5: Clean up events - while(ctxVmm->PluginManager.fc.cEvent) { - CloseHandle(ctxVmm->PluginManager.fc.hEvent[--ctxVmm->PluginManager.fc.cEvent]); - } } -VOID PluginManager_Initialize_RegInfoInit(_Out_ PVMMDLL_PLUGIN_REGINFO pRI, _In_opt_ HMODULE hDLL) +VOID PluginManager_Initialize_RegInfoInit(_In_ VMM_HANDLE H, _Out_ PVMMDLL_PLUGIN_REGINFO pRI, _In_opt_ HMODULE hDLL) { ZeroMemory(pRI, sizeof(VMMDLL_PLUGIN_REGINFO)); pRI->magic = VMMDLL_PLUGIN_REGINFO_MAGIC; pRI->wVersion = VMMDLL_PLUGIN_REGINFO_VERSION; pRI->wSize = sizeof(VMMDLL_PLUGIN_REGINFO); pRI->hDLL = hDLL; - pRI->tpMemoryModel = ctxVmm->tpMemoryModel; - pRI->tpSystem = ctxVmm->tpSystem; + pRI->tpMemoryModel = H->vmm.tpMemoryModel; + pRI->tpSystem = H->vmm.tpSystem; pRI->pfnPluginManager_Register = PluginManager_Register; - pRI->sysinfo.f32 = ctxVmm->f32; - pRI->sysinfo.dwVersionMajor = ctxVmm->kernel.dwVersionMajor; - pRI->sysinfo.dwVersionMinor = ctxVmm->kernel.dwVersionMinor; - pRI->sysinfo.dwVersionBuild = ctxVmm->kernel.dwVersionBuild; + pRI->sysinfo.f32 = H->vmm.f32; + pRI->sysinfo.dwVersionMajor = H->vmm.kernel.dwVersionMajor; + pRI->sysinfo.dwVersionMinor = H->vmm.kernel.dwVersionMinor; + pRI->sysinfo.dwVersionBuild = H->vmm.kernel.dwVersionBuild; } #ifdef _WIN32 -VOID PluginManager_Initialize_Python() +VOID PluginManager_Initialize_Python(_In_ VMM_HANDLE H) { LPSTR szPYTHON_VERSIONS_SUPPORTED[] = { "python315.dll", "python314.dll", "python313.dll", "python312.dll", "python311.dll", "python310.dll", "python39.dll", "python38.dll", "python37.dll", "python36.dll" }; DWORD cszPYTHON_VERSIONS_SUPPORTED = (sizeof(szPYTHON_VERSIONS_SUPPORTED) / sizeof(LPSTR)); @@ -594,14 +720,14 @@ VOID PluginManager_Initialize_Python() VMMDLL_PLUGIN_REGINFO ri; CHAR szPythonPath[MAX_PATH]; HMODULE hDllPython3X = NULL, hDllPython3 = NULL, hDllPyPlugin = NULL; - VOID(*pfnInitializeVmmPlugin)(_In_ PVMMDLL_PLUGIN_REGINFO pRegInfo); + VOID(*pfnInitializeVmmPlugin)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_REGINFO pRegInfo); // 0: Verify that Python should be enabled - if(ctxMain->cfg.fDisablePython) { return; } + if(H->cfg.fDisablePython) { return; } // 1: Locate Python by trying user-defined path - if(ctxMain->cfg.szPythonPath[0]) { + if(H->cfg.szPythonPath[0]) { for(i = 0; i < cszPYTHON_VERSIONS_SUPPORTED; i++) { ZeroMemory(szPythonPath, MAX_PATH); - strcpy_s(szPythonPath, MAX_PATH, ctxMain->cfg.szPythonPath); + strcpy_s(szPythonPath, MAX_PATH, H->cfg.szPythonPath); strcat_s(szPythonPath, MAX_PATH, "\\"); strcat_s(szPythonPath, MAX_PATH, szPYTHON_VERSIONS_SUPPORTED[i]); hDllPython3X = LoadLibraryExA(szPythonPath, 0, LOAD_WITH_ALTERED_SEARCH_PATH); @@ -609,23 +735,23 @@ VOID PluginManager_Initialize_Python() fBitnessFail = fBitnessFail || (ERROR_BAD_EXE_FORMAT == GetLastError()); } if(!hDllPython3X) { - ZeroMemory(ctxMain->cfg.szPythonPath, MAX_PATH); - VmmLog(MID_PLUGIN, LOGLEVEL_INFO, + ZeroMemory(H->cfg.szPythonPath, MAX_PATH); + VmmLog(H, MID_PLUGIN, LOGLEVEL_INFO, fBitnessFail ? - "PluginManager: Python initialization failed. Unable to load 32-bit Python. 64-bit required." : - "PluginManager: Python initialization failed. Python 3.6 or later not found on user specified path." + "Python initialization failed. Unable to load 32-bit Python. 64-bit required." : + "Python initialization failed. Python 3.6 or later not found on user specified path." ); return; } } // 2: If Python is already loaded - use it! - if(0 == ctxMain->cfg.szPythonPath[0]) { + if(0 == H->cfg.szPythonPath[0]) { for(i = 0; i < cszPYTHON_VERSIONS_SUPPORTED; i++) { if((hDllPython3X = GetModuleHandleA(szPYTHON_VERSIONS_SUPPORTED[i]))) { GetModuleFileNameA(hDllPython3X, szPythonPath, MAX_PATH); hDllPython3X = LoadLibraryA(szPythonPath); if(hDllPython3X) { - Util_GetPathDll(ctxMain->cfg.szPythonPath, hDllPython3X); + Util_GetPathDll(H->cfg.szPythonPath, hDllPython3X); fPythonStandalone = TRUE; break; } @@ -633,7 +759,7 @@ VOID PluginManager_Initialize_Python() } } // 3: Try locate Python by checking the python36 sub-directory relative to the current executable (.exe). - if(0 == ctxMain->cfg.szPythonPath[0]) { + if(0 == H->cfg.szPythonPath[0]) { for(i = 0; i < cszPYTHON_VERSIONS_SUPPORTED; i++) { ZeroMemory(szPythonPath, MAX_PATH); Util_GetPathDll(szPythonPath, NULL); @@ -644,24 +770,24 @@ VOID PluginManager_Initialize_Python() fBitnessFail = fBitnessFail || (ERROR_BAD_EXE_FORMAT == GetLastError()); } if(hDllPython3X) { - Util_GetPathDll(ctxMain->cfg.szPythonPath, NULL); - strcat_s(ctxMain->cfg.szPythonPath, MAX_PATH, "python\\"); + Util_GetPathDll(H->cfg.szPythonPath, NULL); + strcat_s(H->cfg.szPythonPath, MAX_PATH, "python\\"); } } // 4: Try locate Python by loading from the current path. - if(0 == ctxMain->cfg.szPythonPath[0]) { + if(0 == H->cfg.szPythonPath[0]) { for(i = 0; i < cszPYTHON_VERSIONS_SUPPORTED; i++) { hDllPython3X = LoadLibraryA(szPYTHON_VERSIONS_SUPPORTED[i]); if(hDllPython3X) { break; } fBitnessFail = fBitnessFail || (ERROR_BAD_EXE_FORMAT == GetLastError()); } if(hDllPython3X) { - Util_GetPathDll(ctxMain->cfg.szPythonPath, hDllPython3X); + Util_GetPathDll(H->cfg.szPythonPath, hDllPython3X); } } // 5: Python is not found? - if(0 == ctxMain->cfg.szPythonPath[0]) { - VmmLog(MID_PLUGIN, LOGLEVEL_INFO, + if(0 == H->cfg.szPythonPath[0]) { + VmmLog(H, MID_PLUGIN, LOGLEVEL_INFO, fBitnessFail ? "Python initialization failed. Unable to load 32-bit Python. 64-bit required." : "Python initialization failed. Python 3.6 or later not found." @@ -675,24 +801,24 @@ VOID PluginManager_Initialize_Python() // 7: process 'special status' python plugin manager. hDllPyPlugin = LoadLibraryA("vmmpyc.pyd"); if(!hDllPyPlugin) { - VmmLog(MID_PLUGIN, LOGLEVEL_WARNING, "Python plugin manager failed to load."); + VmmLog(H, MID_PLUGIN, LOGLEVEL_WARNING, "Python plugin manager failed to load."); goto fail; } - pfnInitializeVmmPlugin = (VOID(*)(PVMMDLL_PLUGIN_REGINFO))GetProcAddress(hDllPyPlugin, "InitializeVmmPlugin"); + pfnInitializeVmmPlugin = (VOID(*)(VMM_HANDLE, PVMMDLL_PLUGIN_REGINFO))GetProcAddress(hDllPyPlugin, "InitializeVmmPlugin"); if(!pfnInitializeVmmPlugin) { - VmmLog(MID_PLUGIN, LOGLEVEL_WARNING, "Python plugin manager failed to load due to corrupt DLL."); + VmmLog(H, MID_PLUGIN, LOGLEVEL_WARNING, "Python plugin manager failed to load due to corrupt DLL."); goto fail; } - PluginManager_Initialize_RegInfoInit(&ri, hDllPyPlugin); + PluginManager_Initialize_RegInfoInit(H, &ri, hDllPyPlugin); ri.python.fPythonStandalone = fPythonStandalone; ri.python.hReservedDllPython3X = hDllPython3X; ri.python.hReservedDllPython3 = hDllPython3; - pfnInitializeVmmPlugin(&ri); - if(!PluginManager_ModuleExistsDll(hDllPyPlugin)) { - VmmLog(MID_PLUGIN, LOGLEVEL_WARNING, "Python plugin manager failed to load due to internal error."); + pfnInitializeVmmPlugin(H, &ri); + if(!PluginManager_ModuleExistsDll(H, hDllPyPlugin)) { + VmmLog(H, MID_PLUGIN, LOGLEVEL_WARNING, "Python plugin manager failed to load due to internal error."); return; } - VmmLog(MID_PLUGIN, LOGLEVEL_VERBOSE, "PluginManager: Python plugin loaded."); + VmmLog(H, MID_PLUGIN, LOGLEVEL_VERBOSE, "PluginManager: Python plugin loaded."); if(hDllPython3X) { FreeLibrary(hDllPython3X); } return; fail: @@ -701,7 +827,7 @@ fail: if(hDllPython3) { FreeLibrary(hDllPython3); } } -VOID PluginManager_Initialize_ExternalDlls() +VOID PluginManager_Initialize_ExternalDlls(_In_ VMM_HANDLE H) { VMMDLL_PLUGIN_REGINFO ri; CHAR szPath[MAX_PATH]; @@ -709,10 +835,10 @@ VOID PluginManager_Initialize_ExternalDlls() HANDLE hFindFile; WIN32_FIND_DATAA FindData; HMODULE hDLL; - VOID(*pfnInitializeVmmPlugin)(_In_ PVMMDLL_PLUGIN_REGINFO pRegInfo); + VOID(*pfnInitializeVmmPlugin)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_REGINFO pRegInfo); Util_GetPathDll(szPath, NULL); cchPathBase = (DWORD)strnlen(szPath, MAX_PATH - 1); - strcat_s(szPath, MAX_PATH, "plugins\\m_*.dll"); + strcat_s(szPath, MAX_PATH, "plugins\\m_*"VMM_LIBRARY_FILETYPE); hFindFile = FindFirstFileA(szPath, &FindData); if(hFindFile != INVALID_HANDLE_VALUE) { do { @@ -721,59 +847,109 @@ VOID PluginManager_Initialize_ExternalDlls() strcat_s(szPath, MAX_PATH, FindData.cFileName); hDLL = LoadLibraryExA(szPath, 0, 0); if(!hDLL) { - VmmLog(MID_PLUGIN, LOGLEVEL_DEBUG, "FAIL: Load DLL: '%s' - missing dependencies?", FindData.cFileName); + VmmLog(H, MID_PLUGIN, LOGLEVEL_DEBUG, "FAIL: Load DLL: '%s' - missing dependencies?", FindData.cFileName); continue; } - VmmLog(MID_PLUGIN, LOGLEVEL_DEBUG, "Load DLL: '%s'", FindData.cFileName); - pfnInitializeVmmPlugin = (VOID(*)(PVMMDLL_PLUGIN_REGINFO))GetProcAddress(hDLL, "InitializeVmmPlugin"); + VmmLog(H, MID_PLUGIN, LOGLEVEL_DEBUG, "Load DLL: '%s'", FindData.cFileName); + pfnInitializeVmmPlugin = (VOID(*)(VMM_HANDLE, PVMMDLL_PLUGIN_REGINFO))GetProcAddress(hDLL, "InitializeVmmPlugin"); if(!pfnInitializeVmmPlugin) { - VmmLog(MID_PLUGIN, LOGLEVEL_DEBUG, "UnLoad DLL: '%s' - Plugin Entry Point not found", FindData.cFileName); + VmmLog(H, MID_PLUGIN, LOGLEVEL_DEBUG, "Unload DLL: '%s' - Plugin Entry Point not found", FindData.cFileName); FreeLibrary(hDLL); continue; } - PluginManager_Initialize_RegInfoInit(&ri, hDLL); - pfnInitializeVmmPlugin(&ri); - if(!PluginManager_ModuleExistsDll(hDLL)) { - VmmLog(MID_PLUGIN, LOGLEVEL_DEBUG, "UnLoad DLL: '%s' - not registered with plugin manager", FindData.cFileName); + PluginManager_Initialize_RegInfoInit(H, &ri, hDLL); + pfnInitializeVmmPlugin(H, &ri); + if(!PluginManager_ModuleExistsDll(H, hDLL)) { + VmmLog(H, MID_PLUGIN, LOGLEVEL_DEBUG, "Unload DLL: '%s' - not registered with plugin manager", FindData.cFileName); FreeLibrary(hDLL); continue; } } while(FindNextFileA(hFindFile, &FindData)); + FindClose(hFindFile); } } - #endif /* _WIN32 */ + #ifdef LINUX -VOID PluginManager_Initialize_Python() { return; } -VOID PluginManager_Initialize_ExternalDlls() { return; } +VOID PluginManager_Initialize_Python(_In_ VMM_HANDLE H) { return; } + +VOID PluginManager_Initialize_ExternalDlls(_In_ VMM_HANDLE H) +{ + HMODULE hDLL; + VMMDLL_PLUGIN_REGINFO ri; + CHAR szPath[MAX_PATH]; + DWORD cchPathBase; + DIR *dp; + struct dirent *ep; + VOID(*pfnInitializeVmmPlugin)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_REGINFO pRegInfo); + Util_GetPathLib(szPath); + strcat_s(szPath, MAX_PATH, "/plugins/"); + cchPathBase = (DWORD)strnlen(szPath, MAX_PATH - 1); + if(cchPathBase > MAX_PATH - 0x20) { + VmmLog(H, MID_PLUGIN, LOGLEVEL_DEBUG, "FAIL load external modules - path too long"); + return; + } + if(!(dp = opendir(szPath))) { + VmmLog(H, MID_PLUGIN, LOGLEVEL_DEBUG, "FAIL load external modules - plugins directory missing"); + return; + } + if(!dp) { return; } + while((ep = readdir(dp))) { + if(!ep->d_name || (ep->d_name[0] != 'm') || (ep->d_name[1] != '_')) { continue; } + if(!CharUtil_StrEndsWith(ep->d_name, VMM_LIBRARY_FILETYPE, TRUE)) { continue; } + + strcat_s(szPath + cchPathBase, MAX_PATH - cchPathBase, ep->d_name); + hDLL = dlopen(szPath, RTLD_NOW); + if(!hDLL) { + VmmLog(H, MID_PLUGIN, LOGLEVEL_DEBUG, "FAIL load external module '%s' - missing dependencies?", ep->d_name); + continue; + } + + + pfnInitializeVmmPlugin = (VOID(*)(VMM_HANDLE, PVMMDLL_PLUGIN_REGINFO))dlsym(hDLL, "InitializeVmmPlugin"); + if(!pfnInitializeVmmPlugin) { + VmmLog(H, MID_PLUGIN, LOGLEVEL_DEBUG, "FAIL load external module '%s' - plugin entry point not found", ep->d_name); + dlclose(hDLL); + continue; + } + PluginManager_Initialize_RegInfoInit(H, &ri, hDLL); + pfnInitializeVmmPlugin(H, &ri); + if(!PluginManager_ModuleExistsDll(H, hDLL)) { + VmmLog(H, MID_PLUGIN, LOGLEVEL_DEBUG, "FAIL load external module '%s' - not registered with plugin manager", ep->d_name); + dlclose(hDLL); + continue; + } + } + closedir(dp); +} #endif /* LINUX */ -BOOL PluginManager_Initialize() +BOOL PluginManager_Initialize(_In_ VMM_HANDLE H) { DWORD i; VMMDLL_PLUGIN_REGINFO ri; // 1: check if already initialized - if(ctxVmm->PluginManager.FLinkAll) { return FALSE; } - EnterCriticalSection(&ctxVmm->LockMaster); - if(ctxVmm->PluginManager.FLinkAll) { goto fail; } + if(H->vmm.PluginManager.FLinkAll) { return FALSE; } + EnterCriticalSection(&H->vmm.LockMaster); + if(H->vmm.PluginManager.FLinkAll) { goto fail; } // 2: set up root nodes of process plugin tree - ctxVmm->PluginManager.Root = LocalAlloc(LMEM_ZEROINIT, sizeof(PLUGIN_TREE)); - ctxVmm->PluginManager.Proc = LocalAlloc(LMEM_ZEROINIT, sizeof(PLUGIN_TREE)); - if(!ctxVmm->PluginManager.Root || !ctxVmm->PluginManager.Proc) { goto fail; } + H->vmm.PluginManager.Root = LocalAlloc(LMEM_ZEROINIT, sizeof(PLUGIN_TREE)); + H->vmm.PluginManager.Proc = LocalAlloc(LMEM_ZEROINIT, sizeof(PLUGIN_TREE)); + if(!H->vmm.PluginManager.Root || !H->vmm.PluginManager.Proc) { goto fail; } // 3: process built-in modules for(i = 0; i < sizeof(g_pfnModulesAllInternal) / sizeof(PVOID); i++) { - PluginManager_Initialize_RegInfoInit(&ri, NULL); - g_pfnModulesAllInternal[i](&ri); + PluginManager_Initialize_RegInfoInit(H, &ri, NULL); + g_pfnModulesAllInternal[i](H, &ri); } // 4: process dll modules - PluginManager_Initialize_ExternalDlls(); + PluginManager_Initialize_ExternalDlls(H); // 5: process 'special status' python plugin manager. - PluginManager_Initialize_Python(); + PluginManager_Initialize_Python(H); // 6: refresh logging (module specific overrides not yet applied may exist) - VmmLog_LevelRefresh(); - LeaveCriticalSection(&ctxVmm->LockMaster); + VmmLog_LevelRefresh(H); + LeaveCriticalSection(&H->vmm.LockMaster); return TRUE; fail: - LeaveCriticalSection(&ctxVmm->LockMaster); + LeaveCriticalSection(&H->vmm.LockMaster); return FALSE; } diff --git a/vmm/pluginmanager.h b/vmm/pluginmanager.h index fb38fb7..9b0f2d2 100644 --- a/vmm/pluginmanager.h +++ b/vmm/pluginmanager.h @@ -12,35 +12,41 @@ /* * Initialize built-in and external modules. +* -- H +* -- return */ -BOOL PluginManager_Initialize(); +BOOL PluginManager_Initialize(_In_ VMM_HANDLE H); /* * Close built-in and external modules, free their resources and unload loaded * DLLs from memory. +* -- H */ -VOID PluginManager_Close(); +VOID PluginManager_Close(_In_ VMM_HANDLE H); /* * Set/Change the visibility of an already registered plugin. Depending on other * plugins registered in the path parent paths may change as well. +* -- H * -- fRoot = TRUE: root, FALSE: process. * -- uszPluginPath * -- fVisible */ -VOID PluginManager_SetVisibility(_In_ BOOL fRoot, _In_ LPSTR uszPluginPath, _In_ BOOL fVisible); +VOID PluginManager_SetVisibility(_In_ VMM_HANDLE H, _In_ BOOL fRoot, _In_ LPSTR uszPluginPath, _In_ BOOL fVisible); /* * Send a List command down the module chain to the appropriate module. +* -- H * -- pProcess * -- uszPath * -- pFileList * -- return */ -VOID PluginManager_List(_In_opt_ PVMM_PROCESS pProcess, _In_ LPSTR uszPath, _Inout_ PHANDLE pFileList); +VOID PluginManager_List(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ LPSTR uszPath, _Inout_ PHANDLE pFileList); /* * Send a Read command down the module chain to the appropriate module. +* -- H * -- pProcess * -- uszPath * -- pb @@ -49,10 +55,11 @@ VOID PluginManager_List(_In_opt_ PVMM_PROCESS pProcess, _In_ LPSTR uszPath, _Ino * -- cbOffset * -- return */ -NTSTATUS PluginManager_Read(_In_opt_ PVMM_PROCESS pProcess, _In_ LPSTR uszPath, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset); +NTSTATUS PluginManager_Read(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ LPSTR uszPath, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset); /* * Send a Write command down the module chain to the appropriate module. +* -- H * -- pProcess * -- uszPath * -- pb @@ -61,44 +68,60 @@ NTSTATUS PluginManager_Read(_In_opt_ PVMM_PROCESS pProcess, _In_ LPSTR uszPath, * -- cbOffset * -- return */ -NTSTATUS PluginManager_Write(_In_opt_ PVMM_PROCESS pProcess, _In_ LPSTR uszPath, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset); +NTSTATUS PluginManager_Write(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ LPSTR uszPath, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset); /* * Send a notification event to plugins that registered to receive notifications. * Officially supported events are listed in vmmdll.h!VMMDLL_PLUGIN_EVENT_* +* -- H * -- fEvent = the event to send. * -- pvEvent = optional binary object related to the event. * -- cbEvent = length in bytes of pvEvent (if any). * -- return = (always return TRUE). */ -BOOL PluginManager_Notify(_In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent); +BOOL PluginManager_Notify(_In_ VMM_HANDLE H, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent); /* * Initialize plugins with forensic mode capabilities. +* -- H */ -VOID PluginManager_FcInitialize(); +VOID PluginManager_FcInitialize(_In_ VMM_HANDLE H); /* * Finalize plugins with forensic mode capabilities. +* -- H */ -VOID PluginManager_FcFinalize(); +VOID PluginManager_FcFinalize(_In_ VMM_HANDLE H); /* * Ingest physical memory into plugins with forensic mode capabilities. * NB! must only be called in single-threaded context! +* -- H * -- pIngestPhysmem */ -VOID PluginManager_FcIngestPhysmem(_In_ PVMMDLL_PLUGIN_FORENSIC_INGEST_PHYSMEM pIngestPhysmem); +VOID PluginManager_FcIngestPhysmem(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_INGEST_PHYSMEM pIngestPhysmem); /* -* All ingestion actions are completed. +* Ingest virtual memory into plugins with forensic mode capabilities. +* -- H +* -- pProcess +* -- va +* -- pb +* -- cb */ -VOID PluginManager_FcIngestFinalize(); +VOID PluginManager_FcIngestVirtmem(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD va, _In_ PBYTE pb, _In_ DWORD cb); + +/* +* All ingestion actions (physical & virtual) are completed. +* -- H +*/ +VOID PluginManager_FcIngestFinalize(_In_ VMM_HANDLE H); /* * Register plugins with timelining capabilities with the timeline manager * and call into each plugin to allow them to add their timelining entries. * NB! This function is meant to be called by the core forensic subsystem only. +* -- H * -- pfnRegister = callback function to register timeline module. * -- pfnClose = function to close the timeline handle. * -- pfnEntryAdd = callback function to call to add a timelining entry. @@ -107,18 +130,29 @@ VOID PluginManager_FcIngestFinalize(); * id_str, ft, ac, pid, data32, data64 (in order and without SELECT statement). */ VOID PluginManager_FcTimeline( - _In_ HANDLE(*pfnRegister)(_In_reads_(6) LPSTR sNameShort, _In_reads_(32) LPSTR szFileUTF8), - _In_ VOID(*pfnClose)(_In_ HANDLE hTimeline), - _In_ VOID(*pfnEntryAdd)(_In_ HANDLE hTimeline, _In_ QWORD ft, _In_ DWORD dwAction, _In_ DWORD dwPID, _In_ DWORD dwData32, _In_ QWORD qwData64, _In_ LPSTR uszText), - _In_ VOID(*pfnEntryAddBySql)(_In_ HANDLE hTimeline, _In_ DWORD cEntrySql, _In_ LPSTR *pszEntrySql) + _In_ VMM_HANDLE H, + _In_ HANDLE(*pfnRegister)(_In_ VMM_HANDLE H, _In_reads_(6) LPSTR sNameShort, _In_reads_(32) LPSTR szFileUTF8), + _In_ VOID(*pfnClose)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline), + _In_ VOID(*pfnEntryAdd)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ QWORD ft, _In_ DWORD dwAction, _In_ DWORD dwPID, _In_ DWORD dwData32, _In_ QWORD qwData64, _In_ LPSTR uszText), + _In_ VOID(*pfnEntryAddBySql)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ DWORD cEntrySql, _In_ LPSTR *pszEntrySql) ); +/* +* Call each plugin capable of forensic csv log. Plugins may be process or global. +* NB! This function is meant to be called by the core forensic subsystem only. +* -- H +* -- hCSV +* -- return = 0 (to make function compatible with LPTHREAD_START_ROUTINE). +*/ +DWORD PluginManager_FcLogCSV(_In_ VMM_HANDLE H, _In_ VMMDLL_CSV_HANDLE hCSV); + /* * Call each plugin capable of forensic json log. Plugins may be process or global. * NB! This function is meant to be called by the core forensic subsystem only. +* -- H * -- pfnAddEntry = callback function to call to add a json entry. * -- return = 0 (to make function compatible with LPTHREAD_START_ROUTINE). */ -DWORD PluginManager_FcLogJSON(_In_ VOID(*pfnAddEntry)(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)); +DWORD PluginManager_FcLogJSON(_In_ VMM_HANDLE H, _In_ VOID(*pfnAddEntry)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)); #endif /* __PLUGINMANAGER_H__ */ diff --git a/vmm/statistics.c b/vmm/statistics.c index 787e3cc..8a36089 100644 --- a/vmm/statistics.c +++ b/vmm/statistics.c @@ -7,217 +7,52 @@ #include "vmm.h" #include "util.h" -// ---------------------------------------------------------------------------- -// PAGE READ STATISTICAL FUNCTIONALITY BELOW: -// ---------------------------------------------------------------------------- - -VOID _PageStatPrintMemMap(_Inout_ PPAGE_STATISTICS ps) -{ - QWORD i, qwAddrEnd; - if(!ps->i.fIsFirstPrintCompleted) { - printf(" Memory Map: \n START END #PAGES \n"); - } - if(!ps->i.MemMapIdx) { - printf(" \n \n"); - return; - } - if(ps->i.MemMapIdx >= PAGE_STATISTICS_MEM_MAP_MAX_ENTRY - 2) { - printf(" Maximum number of memory map entries reached. \n \n"); - return; - } - for(i = max(1, ps->i.MemMapPrintIdx); i <= ps->i.MemMapIdx; i++) { - if(!ps->i.MemMap[i].cPages) { - break; - } - qwAddrEnd = ps->i.MemMap[i].qwAddrBase + ((QWORD)ps->i.MemMap[i].cPages << 12); - printf( - " %016llx - %016llx %08x \n", - ps->i.MemMap[i].qwAddrBase, - qwAddrEnd - 1, - ps->i.MemMap[i].cPages); - } - ps->i.MemMapPrintIdx = ps->i.MemMapIdx; - if(!ps->i.MemMap[1].cPages) { // print extra line for formatting reasons. - printf(" (No memory successfully read yet) \n"); - } - printf(" \n"); -} - -VOID _PageStatShowUpdate(_Inout_ PPAGE_STATISTICS ps) -{ - if(0 == ps->cPageTotal) { return; } - QWORD qwPercentTotal = ((ps->cPageSuccess + ps->cPageFail) * 100) / ps->cPageTotal; - QWORD qwPercentSuccess = (ps->cPageSuccess * 200 + 1) / (ps->cPageTotal * 2); - QWORD qwPercentFail = (ps->cPageFail * 200 + 1) / (ps->cPageTotal * 2); - QWORD qwTickCountElapsed = GetTickCount64() - ps->i.qwTickCountStart; - QWORD qwSpeed = ((ps->cPageSuccess + ps->cPageFail) * 4) / (1 + (qwTickCountElapsed / 1000)); - HANDLE hConsole; - CONSOLE_SCREEN_BUFFER_INFO consoleInfo; - BOOL isMBs = qwSpeed >= 2048; - if(ps->i.fIsFirstPrintCompleted) { -#ifdef WIN32 - hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - GetConsoleScreenBufferInfo(hConsole, &consoleInfo); - consoleInfo.dwCursorPosition.Y -= ps->i.fMemMap ? 9 : 7; - SetConsoleCursorPosition(hConsole, consoleInfo.dwCursorPosition); -#endif /* WIN32 */ -#if defined(LINUX) || defined(ANDROID) - vmmprintf(ps->i.fMemMap ? "\033[9A" : "\033[7A"); // move cursor up 7/9 positions -#endif /* LINUX || ANDROID */ - } - if(ps->i.fMemMap) { - _PageStatPrintMemMap(ps); - } - if(ps->cPageTotal < 0x0000000fffffffff) { - vmmprintf( - " Current Action: %s \n" \ - " Access Mode: %s \n" \ - " Progress: %llu / %llu (%llu%%) \n" \ - " Speed: %llu %s \n" \ - " Address: 0x%016llX \n" \ - " Pages read: %llu / %llu (%llu%%) \n" \ - " Pages failed: %llu (%llu%%) \n", - ps->szAction, - ps->fKMD ? "KMD (kernel module assisted DMA)" : "Normal ", - (ps->cPageSuccess + ps->cPageFail) / 256, - ps->cPageTotal / 256, - qwPercentTotal, - (isMBs ? qwSpeed >> 10 : qwSpeed), - (isMBs ? "MB/s" : "kB/s"), - ps->qwAddr, - ps->cPageSuccess, - ps->cPageTotal, - qwPercentSuccess, - ps->cPageFail, - qwPercentFail); - } else { - vmmprintf( - " Current Action: %s \n" \ - " Access Mode: %s \n" \ - " Progress: %llu / (unknown) \n" \ - " Speed: %llu %s \n" \ - " Address: 0x%016llX \n" \ - " Pages read: %llu \n" \ - " Pages failed: %llu \n", - ps->szAction, - ps->fKMD ? "KMD (kernel module assisted DMA)" : "Normal ", - (ps->cPageSuccess + ps->cPageFail) / 256, - (isMBs ? qwSpeed >> 10 : qwSpeed), - (isMBs ? "MB/s" : "kB/s"), - ps->qwAddr, - ps->cPageSuccess, - ps->cPageFail); - } - ps->i.fIsFirstPrintCompleted = TRUE; -} - -VOID _PageStatThreadLoop(_In_ PPAGE_STATISTICS ps) -{ - while(!ps->i.fThreadExit) { - Sleep(100); - if(ps->i.fUpdate) { - ps->i.fUpdate = FALSE; - _PageStatShowUpdate(ps); - } - } - ExitThread(0); -} - -VOID PageStatClose(_In_opt_ PPAGE_STATISTICS *ppPageStat) -{ - BOOL status; - DWORD dwExitCode; - PPAGE_STATISTICS ps; - if(!ppPageStat || !*ppPageStat) { return; } - ps = *ppPageStat; - ps->i.fUpdate = TRUE; - ps->i.fThreadExit = TRUE; - while((status = GetExitCodeThread(ps->i.hThread, &dwExitCode)) && STILL_ACTIVE == dwExitCode) { - SwitchToThread(); - } - if(!status) { - Sleep(200); - } - if(ps->i.hThread) { CloseHandle(ps->i.hThread); } - LocalFree(*ppPageStat); - *ppPageStat = NULL; -} - -_Success_(return) -BOOL PageStatInitialize(_Out_ PPAGE_STATISTICS *ppPageStat, _In_ QWORD qwAddrBase, _In_ QWORD qwAddrMax, _In_ LPSTR szAction, _In_ BOOL fKMD, _In_ BOOL fMemMap) -{ - PPAGE_STATISTICS ps; - ps = *ppPageStat = LocalAlloc(LMEM_ZEROINIT, sizeof(PAGE_STATISTICS)); - if(!ps) { return FALSE; } - ps->qwAddr = qwAddrBase; - ps->cPageTotal = (qwAddrMax - qwAddrBase + 1) / 4096; - ps->szAction = szAction; - ps->fKMD = fKMD; - ps->i.fMemMap = fMemMap; - ps->i.qwTickCountStart = GetTickCount64(); - ps->i.hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)_PageStatThreadLoop, ps, 0, NULL); - return TRUE; -} - -VOID PageStatUpdate(_In_opt_ PPAGE_STATISTICS pPageStat, _In_ QWORD qwAddr, _In_ QWORD cPageSuccessAdd, _In_ QWORD cPageFailAdd) -{ - if(!pPageStat) { return; } - pPageStat->qwAddr = qwAddr; - pPageStat->cPageSuccess += cPageSuccessAdd; - pPageStat->cPageFail += cPageFailAdd; - // add to memory map - if(cPageSuccessAdd && (pPageStat->i.MemMapIdx < PAGE_STATISTICS_MEM_MAP_MAX_ENTRY - 1)) { - if(!pPageStat->i.MemMapIdx || (qwAddr - (cPageSuccessAdd << 12)) != (pPageStat->i.MemMap[pPageStat->i.MemMapIdx].qwAddrBase + ((QWORD)pPageStat->i.MemMap[pPageStat->i.MemMapIdx].cPages << 12))) { - pPageStat->i.MemMapIdx++; - pPageStat->i.MemMap[pPageStat->i.MemMapIdx].qwAddrBase = qwAddr - (cPageSuccessAdd << 12); - } - pPageStat->i.MemMap[pPageStat->i.MemMapIdx].cPages += (DWORD)cPageSuccessAdd; - } - pPageStat->i.fUpdate = TRUE; -} - // ---------------------------------------------------------------------------- // FUNCTION CALL STATISTICAL FUNCTIONALITY BELOW: // ---------------------------------------------------------------------------- -typedef struct tdCALLSTAT { +typedef struct tdVMMSTATISTICS_ENTRY { QWORD c; QWORD tm; -} CALLSTAT, *PCALLSTAT; +} VMMSTATISTICS_ENTRY, *PVMMSTATISTICS_ENTRY; -VOID Statistics_CallSetEnabled(_In_ BOOL fEnabled) +typedef struct tdVMMSTATISTICS_CALL_CONTEXT { + VMMSTATISTICS_ENTRY e[STATISTICS_ID_MAX]; +} VMMSTATISTICS_CALL_CONTEXT, *PVMMSTATISTICS_CALL_CONTEXT; + +VOID Statistics_CallSetEnabled(_In_ VMM_HANDLE H, _In_ BOOL fEnabled) { - if(fEnabled && ctxMain->pvStatistics) { return; } - if(!fEnabled && !ctxMain->pvStatistics) { return; } + if(fEnabled && H->statistics_call) { return; } + if(!fEnabled && !H->statistics_call) { return; } if(fEnabled) { - ctxMain->pvStatistics = LocalAlloc(LMEM_ZEROINIT, (STATISTICS_ID_MAX + 1) * sizeof(CALLSTAT)); + H->statistics_call = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMSTATISTICS_CALL_CONTEXT)); } else { - LocalFree(ctxMain->pvStatistics); - ctxMain->pvStatistics = NULL; + LocalFree(H->statistics_call); + H->statistics_call = NULL; } } -BOOL Statistics_CallGetEnabled() +BOOL Statistics_CallGetEnabled(_In_ VMM_HANDLE H) { - return ctxMain->pvStatistics != NULL; + return H->statistics_call != NULL; } -QWORD Statistics_CallStart() +QWORD Statistics_CallStart(_In_ VMM_HANDLE H) { QWORD tmNow; - if(!ctxMain->pvStatistics) { return 0; } + if(!H->statistics_call) { return 0; } QueryPerformanceCounter((PLARGE_INTEGER)&tmNow); return tmNow; } -QWORD Statistics_CallEnd(_In_ DWORD fId, QWORD tmCallStart) +QWORD Statistics_CallEnd(_In_ VMM_HANDLE H, _In_ DWORD fId, QWORD tmCallStart) { QWORD tmNow; - PCALLSTAT pStat; - if(!ctxMain->pvStatistics) { return 0; } - if(fId > STATISTICS_ID_MAX) { return 0; } + PVMMSTATISTICS_ENTRY pStat; + if(!H->statistics_call) { return 0; } + if(fId >= STATISTICS_ID_MAX) { return 0; } if(tmCallStart == 0) { return 0; } - pStat = ((PCALLSTAT)ctxMain->pvStatistics) + fId; + pStat = H->statistics_call->e + fId; InterlockedIncrement64(&pStat->c); QueryPerformanceCounter((PLARGE_INTEGER)&tmNow); InterlockedAdd64(&pStat->tm, tmNow - tmCallStart); @@ -225,23 +60,24 @@ QWORD Statistics_CallEnd(_In_ DWORD fId, QWORD tmCallStart) } #define STATISTICS_CALL_LINELENGTH 79 -#define STATISTICS_CALL_BUFFERSIZE (STATISTICS_CALL_LINELENGTH * (4 + STATISTICS_ID_MAX + 1 + LC_STATISTICS_ID_MAX + 1) + 1) +#define STATISTICS_CALL_BUFFERSIZE (STATISTICS_CALL_LINELENGTH * (4 + STATISTICS_ID_MAX + LC_STATISTICS_ID_MAX + 1) + 1) /* * Retrieve call statistics as a string buffer and size. If psz is not supplied * only retrieve size. * CALLER LocalFree: psz +* -- H * -- psz * -- pcsz * -- return */ _Success_(return) -BOOL Statistics_CallToString(_Out_opt_ LPSTR *psz, _Out_ PDWORD pcsz) +BOOL Statistics_CallToString(_In_ VMM_HANDLE H, _Out_opt_ LPSTR *psz, _Out_ PDWORD pcsz) { LPSTR sz; BOOL result; QWORD i, o = 0, qwFreq, qwCallCount, qwCallTimeAvg_uS, qwCallTimeTotal_uS; - PCALLSTAT pStat; + PVMMSTATISTICS_ENTRY pStat; PLC_STATISTICS pLcStatistics = NULL; *pcsz = STATISTICS_CALL_BUFFERSIZE - 1; if(!psz) { return TRUE; } @@ -249,29 +85,31 @@ BOOL Statistics_CallToString(_Out_opt_ LPSTR *psz, _Out_ PDWORD pcsz) QueryPerformanceFrequency((PLARGE_INTEGER)&qwFreq); // header o += Util_usnprintf_ln(sz + o, STATISTICS_CALL_LINELENGTH, "FUNCTION CALL STATISTICS:"); - o += Util_usnprintf_ln(sz + o, STATISTICS_CALL_LINELENGTH, "VALUES IN DECIMAL, TIME IN MICROSECONDS uS, STATISTICS = %s", ctxMain->pvStatistics ? "ENABLED " : "DISABLED"); + o += Util_usnprintf_ln(sz + o, STATISTICS_CALL_LINELENGTH, "VALUES IN DECIMAL, TIME IN MICROSECONDS uS, STATISTICS = %s", H->statistics_call ? "ENABLED " : "DISABLED"); o += Util_usnprintf_ln(sz + o, STATISTICS_CALL_LINELENGTH, "FUNCTION CALL NAME CALLS TIME AVG TIME TOTAL"); o += Util_usnprintf_ln(sz + o, STATISTICS_CALL_LINELENGTH, "=============================================================================="); // vmm statistics - for(i = 0; i <= STATISTICS_ID_MAX; i++) { - qwCallCount = qwCallTimeAvg_uS = qwCallTimeTotal_uS = 0; - if((pStat = ((PCALLSTAT)ctxMain->pvStatistics) + i) && pStat->c) { - qwCallCount = pStat->c; - qwCallTimeTotal_uS = (pStat->tm * 1000000ULL) / qwFreq; - qwCallTimeAvg_uS = (qwCallTimeTotal_uS / qwCallCount); + if(H->statistics_call) { + for(i = 0; i < STATISTICS_ID_MAX; i++) { + qwCallCount = qwCallTimeAvg_uS = qwCallTimeTotal_uS = 0; + if((pStat = H->statistics_call->e + i) && pStat->c) { + qwCallCount = pStat->c; + qwCallTimeTotal_uS = (pStat->tm * 1000000ULL) / qwFreq; + qwCallTimeAvg_uS = (qwCallTimeTotal_uS / qwCallCount); + } + o += Util_usnprintf_ln( + sz + o, + STATISTICS_CALL_LINELENGTH, + "%-40.40s %9lli %9lli %17lli", + STATISTICS_ID_STR[i], + qwCallCount, + qwCallTimeAvg_uS, + qwCallTimeTotal_uS + ); } - o += Util_usnprintf_ln( - sz + o, - STATISTICS_CALL_LINELENGTH, - "%-40.40s %9lli %9lli %17lli", - STATISTICS_ID_STR[i], - qwCallCount, - qwCallTimeAvg_uS, - qwCallTimeTotal_uS - ); } // leechcore statistics - result = LcCommand(ctxMain->hLC, LC_CMD_STATISTICS_GET, 0, NULL, (PBYTE*)&pLcStatistics, NULL); + result = LcCommand(H->hLC, LC_CMD_STATISTICS_GET, 0, NULL, (PBYTE*)&pLcStatistics, NULL); if(result && (pLcStatistics->dwVersion == LC_STATISTICS_VERSION) && pLcStatistics->qwFreq) { for(i = 0; i <= LC_STATISTICS_ID_MAX; i++) { qwCallCount = qwCallTimeAvg_uS = qwCallTimeTotal_uS = 0; diff --git a/vmm/statistics.h b/vmm/statistics.h index 5601183..1c57a28 100644 --- a/vmm/statistics.h +++ b/vmm/statistics.h @@ -7,220 +7,169 @@ #define __STATISTICS_H__ #include "vmm.h" -#define PAGE_STATISTICS_MEM_MAP_MAX_ENTRY 2048 - -typedef struct tdPageStatistics { - QWORD qwAddr; - QWORD cPageTotal; - QWORD cPageSuccess; - QWORD cPageFail; - BOOL fKMD; - LPSTR szAction; - struct _InternalUseOnly { - BOOL fUpdate; - BOOL fThreadExit; - BOOL fMemMap; - BOOL fIsFirstPrintCompleted; - HANDLE hThread; - WORD wConsoleCursorPosition; - QWORD qwTickCountStart; - QWORD MemMapIdx; - QWORD MemMapPrintIdx; - struct { - QWORD qwAddrBase; - DWORD cPages; - } MemMap[PAGE_STATISTICS_MEM_MAP_MAX_ENTRY]; - } i; -} PAGE_STATISTICS, *PPAGE_STATISTICS; - -/* -* Initialize the page statistics. This will also start displaying the page statistics -* on the screen asynchronously. PageStatClose must be called to stop this. -* -- ps = ptr to NULL pPageStat PageStatInitialize will initialize. Must be free'd with PageStatClose. -* -- qwAddrBase = the base address that the statistics will be based upon. -* -- qwAddrMax = the maximum address. -* -- szAction = the text shown as action. -* -- fKMD = is KMD mode. -* -- fPageMap = display read memory map when PageStatClose is called. -* -- return -*/ -_Success_(return) -BOOL PageStatInitialize(_Out_ PPAGE_STATISTICS *ppPageStat, _In_ QWORD qwAddrBase, _In_ QWORD qwAddrMax, _In_ LPSTR szAction, _In_ BOOL fKMD, _In_ BOOL fMemMap); - -/* -* Do one last update of the on-screen page statistics, display the read memory map if -* previously set in PageStatInitialize and stop the on-screen updates. -* -- pPageStat = ptr to the PPAGE_STATISTICS struct to close and free. -*/ -VOID PageStatClose(_In_opt_ PPAGE_STATISTICS *ppPageStat); - -/* -* Update the page statistics with the current address and with successfully and failed -* pages. Should not be called before PageStatInitialize and not after PageStatClose. -* This function must be used if the memory map should be shown; otherwise it's possible -* to alter the PPAGE_STATISTICS struct members directly. -* -- pPageStat = pointer to page statistics struct. -* -- qwAddr = new address (after completed operation). -* -- cPageSuccessAdd = number of successfully read pages. -* -- cPageFailAdd = number of pages that failed. -*/ -VOID PageStatUpdate(_In_opt_ PPAGE_STATISTICS pPageStat, _In_ QWORD qwAddr, _In_ QWORD cPageSuccessAdd, _In_ QWORD cPageFailAdd); - // NB! also update STATISTICS_ID_STR -#define STATISTICS_ID_INITIALIZE 0x00 -#define STATISTICS_ID_PluginManager_List 0x01 -#define STATISTICS_ID_PluginManager_Read 0x02 -#define STATISTICS_ID_PluginManager_Write 0x03 -#define STATISTICS_ID_PluginManager_Notify 0x04 -#define STATISTICS_ID_PluginManager_FcInitialize 0x05 -#define STATISTICS_ID_PluginManager_FcFinalize 0x06 -#define STATISTICS_ID_PluginManager_FcTimeline 0x07 -#define STATISTICS_ID_PluginManager_FcLogJSON 0x08 -#define STATISTICS_ID_PluginManager_FcIngestPhysmem 0x09 -#define STATISTICS_ID_PluginManager_FcIngestFinalize 0x0a -#define STATISTICS_ID_FORENSIC_FcInitialize 0x0b -#define STATISTICS_ID_VMMDLL_VfsList 0x0c -#define STATISTICS_ID_VMMDLL_VfsListBlob 0x0d -#define STATISTICS_ID_VMMDLL_VfsRead 0x0e -#define STATISTICS_ID_VMMDLL_VfsWrite 0x0f -#define STATISTICS_ID_VMMDLL_InitializePlugins 0x10 -#define STATISTICS_ID_VMMDLL_MemReadEx 0x11 -#define STATISTICS_ID_VMMDLL_MemReadScatter 0x12 -#define STATISTICS_ID_VMMDLL_MemWriteScatter 0x13 -#define STATISTICS_ID_VMMDLL_MemWrite 0x14 -#define STATISTICS_ID_VMMDLL_MemVirt2Phys 0x15 -#define STATISTICS_ID_VMMDLL_MemSearch 0x16 -#define STATISTICS_ID_VMMDLL_MemPrefetchPages 0x17 -#define STATISTICS_ID_VMMDLL_PidList 0x18 -#define STATISTICS_ID_VMMDLL_PidGetFromName 0x19 -#define STATISTICS_ID_VMMDLL_ProcessGetInformation 0x1a -#define STATISTICS_ID_VMMDLL_ProcessGetInformationString 0x1b -#define STATISTICS_ID_VMMDLL_Log 0x1c -#define STATISTICS_ID_VMMDLL_Map_GetPte 0x1d -#define STATISTICS_ID_VMMDLL_Map_GetVad 0x1e -#define STATISTICS_ID_VMMDLL_Map_GetVadEx 0x1f -#define STATISTICS_ID_VMMDLL_Map_GetModule 0x20 -#define STATISTICS_ID_VMMDLL_Map_GetModuleFromName 0x21 -#define STATISTICS_ID_VMMDLL_Map_GetUnloadedModule 0x22 -#define STATISTICS_ID_VMMDLL_Map_GetEAT 0x23 -#define STATISTICS_ID_VMMDLL_Map_GetIAT 0x24 -#define STATISTICS_ID_VMMDLL_Map_GetHeapEx 0x25 -#define STATISTICS_ID_VMMDLL_Map_GetHeapAllocEx 0x26 -#define STATISTICS_ID_VMMDLL_Map_GetThread 0x27 -#define STATISTICS_ID_VMMDLL_Map_GetHandle 0x28 -#define STATISTICS_ID_VMMDLL_Map_GetPhysMem 0x29 -#define STATISTICS_ID_VMMDLL_Map_GetPool 0x2a -#define STATISTICS_ID_VMMDLL_Map_GetPoolEx 0x2b -#define STATISTICS_ID_VMMDLL_Map_GetNet 0x2c -#define STATISTICS_ID_VMMDLL_Map_GetUsers 0x2d -#define STATISTICS_ID_VMMDLL_Map_GetServices 0x2e -#define STATISTICS_ID_VMMDLL_Map_GetPfn 0x2f -#define STATISTICS_ID_VMMDLL_ProcessGetDirectories 0x30 -#define STATISTICS_ID_VMMDLL_ProcessGetSections 0x31 -#define STATISTICS_ID_VMMDLL_ProcessGetProcAddress 0x32 -#define STATISTICS_ID_VMMDLL_ProcessGetModuleBase 0x33 -#define STATISTICS_ID_VMMDLL_WinGetThunkIAT 0x34 -#define STATISTICS_ID_VMMDLL_WinMemCompression_DecompressPage 0x35 -#define STATISTICS_ID_VMMDLL_WinRegHive_List 0x36 -#define STATISTICS_ID_VMMDLL_WinRegHive_ReadEx 0x37 -#define STATISTICS_ID_VMMDLL_WinRegHive_Write 0x38 -#define STATISTICS_ID_VMMDLL_WinReg_EnumKeyExW 0x39 -#define STATISTICS_ID_VMMDLL_WinReg_EnumValueW 0x3a -#define STATISTICS_ID_VMMDLL_WinReg_QueryValueEx 0x3b -#define STATISTICS_ID_VMMDLL_UtilFillHexAscii 0x3c -#define STATISTICS_ID_VMMDLL_PdbLoad 0x3d -#define STATISTICS_ID_VMMDLL_PdbSymbolName 0x3e -#define STATISTICS_ID_VMMDLL_PdbSymbolAddress 0x3f -#define STATISTICS_ID_VMMDLL_PdbTypeSize 0x20 -#define STATISTICS_ID_VMMDLL_PdbTypeChildOffset 0x41 -#define STATISTICS_ID_VMM_PagedCompressedMemory 0x42 -#define STATISTICS_ID_MAX 0x42 -#define STATISTICS_ID_NOLOG 0xffffffff +typedef enum tdSTATISTICS_ID { + STATISTICS_ID_INITIALIZE, + STATISTICS_ID_PluginManager_List, + STATISTICS_ID_PluginManager_Read, + STATISTICS_ID_PluginManager_Write, + STATISTICS_ID_PluginManager_Notify, + STATISTICS_ID_PluginManager_FcInitialize, + STATISTICS_ID_PluginManager_FcFinalize, + STATISTICS_ID_PluginManager_FcTimeline, + STATISTICS_ID_PluginManager_FcLogCSV, + STATISTICS_ID_PluginManager_FcLogJSON, + STATISTICS_ID_PluginManager_FcIngestPhysmem, + STATISTICS_ID_PluginManager_FcIngestVirtmem, + STATISTICS_ID_PluginManager_FcIngestFinalize, + STATISTICS_ID_FORENSIC_FcInitialize, + STATISTICS_ID_VMMDLL_VfsList, + STATISTICS_ID_VMMDLL_VfsListBlob, + STATISTICS_ID_VMMDLL_VfsRead, + STATISTICS_ID_VMMDLL_VfsWrite, + STATISTICS_ID_VMMDLL_ConfigGet, + STATISTICS_ID_VMMDLL_ConfigSet, + STATISTICS_ID_VMMDLL_InitializePlugins, + STATISTICS_ID_VMMDLL_MemReadEx, + STATISTICS_ID_VMMDLL_MemReadScatter, + STATISTICS_ID_VMMDLL_MemWriteScatter, + STATISTICS_ID_VMMDLL_MemWrite, + STATISTICS_ID_VMMDLL_MemVirt2Phys, + STATISTICS_ID_VMMDLL_MemSearch, + STATISTICS_ID_VMMDLL_MemPrefetchPages, + STATISTICS_ID_VMMDLL_PidList, + STATISTICS_ID_VMMDLL_PidGetFromName, + STATISTICS_ID_VMMDLL_ProcessGetInformation, + STATISTICS_ID_VMMDLL_ProcessGetInformationString, + STATISTICS_ID_VMMDLL_Log, + STATISTICS_ID_VMMDLL_Map_GetPte, + STATISTICS_ID_VMMDLL_Map_GetVad, + STATISTICS_ID_VMMDLL_Map_GetVadEx, + STATISTICS_ID_VMMDLL_Map_GetModule, + STATISTICS_ID_VMMDLL_Map_GetModuleFromName, + STATISTICS_ID_VMMDLL_Map_GetUnloadedModule, + STATISTICS_ID_VMMDLL_Map_GetEAT, + STATISTICS_ID_VMMDLL_Map_GetIAT, + STATISTICS_ID_VMMDLL_Map_GetHeapEx, + STATISTICS_ID_VMMDLL_Map_GetHeapAllocEx, + STATISTICS_ID_VMMDLL_Map_GetThread, + STATISTICS_ID_VMMDLL_Map_GetHandle, + STATISTICS_ID_VMMDLL_Map_GetPhysMem, + STATISTICS_ID_VMMDLL_Map_GetPool, + STATISTICS_ID_VMMDLL_Map_GetNet, + STATISTICS_ID_VMMDLL_Map_GetUsers, + STATISTICS_ID_VMMDLL_Map_GetServices, + STATISTICS_ID_VMMDLL_Map_GetPfn, + STATISTICS_ID_VMMDLL_ProcessGetDirectories, + STATISTICS_ID_VMMDLL_ProcessGetSections, + STATISTICS_ID_VMMDLL_ProcessGetProcAddress, + STATISTICS_ID_VMMDLL_ProcessGetModuleBase, + STATISTICS_ID_VMMDLL_WinGetThunkIAT, + STATISTICS_ID_VMMDLL_WinMemCompression_DecompressPage, + STATISTICS_ID_VMMDLL_WinRegHive_List, + STATISTICS_ID_VMMDLL_WinRegHive_ReadEx, + STATISTICS_ID_VMMDLL_WinRegHive_Write, + STATISTICS_ID_VMMDLL_WinReg_EnumKeyExW, + STATISTICS_ID_VMMDLL_WinReg_EnumValueW, + STATISTICS_ID_VMMDLL_WinReg_QueryValueEx, + STATISTICS_ID_VMMDLL_PdbLoad, + STATISTICS_ID_VMMDLL_PdbSymbolName, + STATISTICS_ID_VMMDLL_PdbSymbolAddress, + STATISTICS_ID_VMMDLL_PdbTypeSize, + STATISTICS_ID_VMMDLL_PdbTypeChildOffset, + STATISTICS_ID_VMMDLL_ForensicFileAppend, + STATISTICS_ID_VMM_PagedCompressedMemory, + STATISTICS_ID_MAX +} STATISTICS_ID; -static LPCSTR STATISTICS_ID_STR[] = { - "INITIALIZE", - "PluginManager_List", - "PluginManager_Read", - "PluginManager_Write", - "PluginManager_Notify", - "PluginManager_FcInitialize", - "PluginManager_FcFinalize", - "PluginManager_FcTimeline", - "PluginManager_FcLogJSON", - "PluginManager_IngestPhysmem", - "PluginManager_IngestFinalize", - "FORENSIC_FcInitialize", - "VMMDLL_VfsList", - "VMMDLL_VfsListBlob", - "VMMDLL_VfsRead", - "VMMDLL_VfsWrite", - "VMMDLL_InitializePlugins", - "VMMDLL_MemReadEx", - "VMMDLL_MemReadScatter", - "VMMDLL_MemWriteScatter", - "VMMDLL_MemWrite", - "VMMDLL_MemVirt2Phys", - "VMMDLL_MemSearch", - "VMMDLL_MemPrefetchPages", - "VMMDLL_PidList", - "VMMDLL_PidGetFromName", - "VMMDLL_ProcessGetInformation", - "VMMDLL_ProcessGetInformationString", - "VMMDLL_Map_GetLog", - "VMMDLL_Map_GetPte", - "VMMDLL_Map_GetVad", - "VMMDLL_Map_GetVadEx", - "VMMDLL_Map_GetModule", - "VMMDLL_Map_GetModuleFromName", - "VMMDLL_Map_GetUnloadedModule", - "VMMDLL_Map_GetEAT", - "VMMDLL_Map_GetIAT", - "VMMDLL_Map_GetHeapEx", - "VMMDLL_Map_GetHeapAllocEx", - "VMMDLL_Map_GetThread", - "VMMDLL_Map_GetHandle", - "VMMDLL_Map_GetPhysMem", - "VMMDLL_Map_GetPool", - "VMMDLL_Map_GetPoolEx", - "VMMDLL_Map_GetNet", - "VMMDLL_Map_GetUsers", - "VMMDLL_Map_GetServices", - "VMMDLL_Map_GetPfn", - "VMMDLL_ProcessGetDirectories", - "VMMDLL_ProcessGetSections", - "VMMDLL_ProcessGetProcAddress", - "VMMDLL_ProcessGetModuleBase", - "VMMDLL_WinGetThunkIAT", - "VMMDLL_WinMemCompression_DecompressPage", - "VMMDLL_WinRegHive_List", - "VMMDLL_WinRegHive_ReadEx", - "VMMDLL_WinRegHive_Write", - "VMMDLL_WinReg_EnumKeyExW", - "VMMDLL_WinReg_EnumValueW", - "VMMDLL_WinReg_QueryValueExW", - "VMMDLL_UtilFillHexAscii", - "VMMDLL_PdbLoad", - "VMMDLL_PdbSymbolName", - "VMMDLL_PdbSymbolAddress", - "VMMDLL_PdbTypeSize", - "VMMDLL_PdbTypeChildOffset", - "VMM_PagedCompressedMemory", +static LPCSTR STATISTICS_ID_STR[STATISTICS_ID_MAX] = { + [STATISTICS_ID_INITIALIZE] = "INITIALIZE", + [STATISTICS_ID_PluginManager_List] = "PluginManager_List", + [STATISTICS_ID_PluginManager_Read] = "PluginManager_Read", + [STATISTICS_ID_PluginManager_Write] = "PluginManager_Write", + [STATISTICS_ID_PluginManager_Notify] = "PluginManager_Notify", + [STATISTICS_ID_PluginManager_FcInitialize] = "PluginManager_FcInitialize", + [STATISTICS_ID_PluginManager_FcFinalize] = "PluginManager_FcFinalize", + [STATISTICS_ID_PluginManager_FcTimeline] = "PluginManager_FcTimeline", + [STATISTICS_ID_PluginManager_FcLogCSV] = "PluginManager_FcLogCSV", + [STATISTICS_ID_PluginManager_FcLogJSON] = "PluginManager_FcLogJSON", + [STATISTICS_ID_PluginManager_FcIngestPhysmem] = "PluginManager_FcIngestPhysmem", + [STATISTICS_ID_PluginManager_FcIngestVirtmem] = "PluginManager_FcIngestVirtmem", + [STATISTICS_ID_PluginManager_FcIngestFinalize] = "PluginManager_FcIngestFinalize", + [STATISTICS_ID_FORENSIC_FcInitialize] = "FORENSIC_FcInitialize", + [STATISTICS_ID_VMMDLL_VfsList] = "VMMDLL_VfsList", + [STATISTICS_ID_VMMDLL_VfsListBlob] = "VMMDLL_VfsListBlob", + [STATISTICS_ID_VMMDLL_VfsRead] = "VMMDLL_VfsRead", + [STATISTICS_ID_VMMDLL_VfsWrite] = "VMMDLL_VfsWrite", + [STATISTICS_ID_VMMDLL_ConfigGet] = "VMMDLL_ConfigGet", + [STATISTICS_ID_VMMDLL_ConfigSet] = "VMMDLL_ConfigSet", + [STATISTICS_ID_VMMDLL_InitializePlugins] = "VMMDLL_InitializePlugins", + [STATISTICS_ID_VMMDLL_MemReadEx] = "VMMDLL_MemReadEx", + [STATISTICS_ID_VMMDLL_MemReadScatter] = "VMMDLL_MemReadScatter", + [STATISTICS_ID_VMMDLL_MemWriteScatter] = "VMMDLL_MemWriteScatter", + [STATISTICS_ID_VMMDLL_MemWrite] = "VMMDLL_MemWrite", + [STATISTICS_ID_VMMDLL_MemVirt2Phys] = "VMMDLL_MemVirt2Phys", + [STATISTICS_ID_VMMDLL_MemSearch] = "VMMDLL_MemSearch", + [STATISTICS_ID_VMMDLL_MemPrefetchPages] = "VMMDLL_MemPrefetchPages", + [STATISTICS_ID_VMMDLL_PidList] = "VMMDLL_PidList", + [STATISTICS_ID_VMMDLL_PidGetFromName] = "VMMDLL_PidGetFromName", + [STATISTICS_ID_VMMDLL_ProcessGetInformation] = "VMMDLL_ProcessGetInformation", + [STATISTICS_ID_VMMDLL_ProcessGetInformationString] = "VMMDLL_ProcessGetInformationString", + [STATISTICS_ID_VMMDLL_Log] = "VMMDLL_Log", + [STATISTICS_ID_VMMDLL_Map_GetPte] = "VMMDLL_Map_GetPte", + [STATISTICS_ID_VMMDLL_Map_GetVad] = "VMMDLL_Map_GetVad", + [STATISTICS_ID_VMMDLL_Map_GetVadEx] = "VMMDLL_Map_GetVadEx", + [STATISTICS_ID_VMMDLL_Map_GetModule] = "VMMDLL_Map_GetModule", + [STATISTICS_ID_VMMDLL_Map_GetModuleFromName] = "VMMDLL_Map_GetModuleFromName", + [STATISTICS_ID_VMMDLL_Map_GetUnloadedModule] = "VMMDLL_Map_GetUnloadedModule", + [STATISTICS_ID_VMMDLL_Map_GetEAT] = "VMMDLL_Map_GetEAT", + [STATISTICS_ID_VMMDLL_Map_GetIAT] = "VMMDLL_Map_GetIAT", + [STATISTICS_ID_VMMDLL_Map_GetHeapEx] = "VMMDLL_Map_GetHeapEx", + [STATISTICS_ID_VMMDLL_Map_GetHeapAllocEx] = "VMMDLL_Map_GetHeapAllocEx", + [STATISTICS_ID_VMMDLL_Map_GetThread] = "VMMDLL_Map_GetThread", + [STATISTICS_ID_VMMDLL_Map_GetHandle] = "VMMDLL_Map_GetHandle", + [STATISTICS_ID_VMMDLL_Map_GetPhysMem] = "VMMDLL_Map_GetPhysMem", + [STATISTICS_ID_VMMDLL_Map_GetPool] = "VMMDLL_Map_GetPool", + [STATISTICS_ID_VMMDLL_Map_GetNet] = "VMMDLL_Map_GetNet", + [STATISTICS_ID_VMMDLL_Map_GetUsers] = "VMMDLL_Map_GetUsers", + [STATISTICS_ID_VMMDLL_Map_GetServices] = "VMMDLL_Map_GetServices", + [STATISTICS_ID_VMMDLL_Map_GetPfn] = "VMMDLL_Map_GetPfn", + [STATISTICS_ID_VMMDLL_ProcessGetDirectories] = "VMMDLL_ProcessGetDirectories", + [STATISTICS_ID_VMMDLL_ProcessGetSections] = "VMMDLL_ProcessGetSections", + [STATISTICS_ID_VMMDLL_ProcessGetProcAddress] = "VMMDLL_ProcessGetProcAddress", + [STATISTICS_ID_VMMDLL_ProcessGetModuleBase] = "VMMDLL_ProcessGetModuleBase", + [STATISTICS_ID_VMMDLL_WinGetThunkIAT] = "VMMDLL_WinGetThunkIAT", + [STATISTICS_ID_VMMDLL_WinMemCompression_DecompressPage] = "VMMDLL_WinMemCompression_DecompressPage", + [STATISTICS_ID_VMMDLL_WinRegHive_List] = "VMMDLL_WinRegHive_List", + [STATISTICS_ID_VMMDLL_WinRegHive_ReadEx] = "VMMDLL_WinRegHive_ReadEx", + [STATISTICS_ID_VMMDLL_WinRegHive_Write] = "VMMDLL_WinRegHive_Write", + [STATISTICS_ID_VMMDLL_WinReg_EnumKeyExW] = "VMMDLL_WinReg_EnumKeyExW", + [STATISTICS_ID_VMMDLL_WinReg_EnumValueW] = "VMMDLL_WinReg_EnumValueW", + [STATISTICS_ID_VMMDLL_WinReg_QueryValueEx] = "VMMDLL_WinReg_QueryValueEx", + [STATISTICS_ID_VMMDLL_PdbLoad] = "VMMDLL_PdbLoad", + [STATISTICS_ID_VMMDLL_PdbSymbolName] = "VMMDLL_PdbSymbolName", + [STATISTICS_ID_VMMDLL_PdbSymbolAddress] = "VMMDLL_PdbSymbolAddress", + [STATISTICS_ID_VMMDLL_PdbTypeSize] = "VMMDLL_PdbTypeSize", + [STATISTICS_ID_VMMDLL_PdbTypeChildOffset] = "VMMDLL_PdbTypeChildOffset", + [STATISTICS_ID_VMMDLL_ForensicFileAppend] = "VMMDLL_ForensicFileAppend", + [STATISTICS_ID_VMM_PagedCompressedMemory] = "VMM_PagedCompressedMemory" }; -VOID Statistics_CallSetEnabled(_In_ BOOL fEnabled); -BOOL Statistics_CallGetEnabled(); -QWORD Statistics_CallStart(); -QWORD Statistics_CallEnd(_In_ DWORD fId, QWORD tmCallStart); +VOID Statistics_CallSetEnabled(_In_ VMM_HANDLE H, _In_ BOOL fEnabled); +BOOL Statistics_CallGetEnabled(_In_ VMM_HANDLE H); +QWORD Statistics_CallStart(_In_ VMM_HANDLE H); +QWORD Statistics_CallEnd(_In_ VMM_HANDLE H, _In_ DWORD fId, QWORD tmCallStart); /* * Retrieve call statistics as a string buffer and size. If psz is not supplied * only retrieve size. * CALLER LocalFree: psz +* -- H * -- psz * -- pcsz * -- return */ _Success_(return) -BOOL Statistics_CallToString(_Out_opt_ LPSTR *psz, _Out_ PDWORD pcsz); +BOOL Statistics_CallToString(_In_ VMM_HANDLE H, _Out_opt_ LPSTR *psz, _Out_ PDWORD pcsz); #endif /* __STATISTICS_H__ */ diff --git a/vmm/sysquery.c b/vmm/sysquery.c index 5f30975..e4256b6 100644 --- a/vmm/sysquery.c +++ b/vmm/sysquery.c @@ -9,10 +9,11 @@ /* * Retrieve the current system time as FILETIME. +* -- H * -- return */ _Success_(return != 0) -QWORD SysQuery_TimeCurrent() +QWORD SysQuery_TimeCurrent(_In_ VMM_HANDLE H) { // data is fetched from fixed memory address as defined in wdm.h // this applies even to the most recent windows version ... @@ -20,27 +21,28 @@ QWORD SysQuery_TimeCurrent() // #define KI_USER_SHARED_DATA 0xFFFFF78000000000UI64 // #define SharedSystemTime (KI_USER_SHARED_DATA + 0x14) QWORD ft = 0; - VmmRead(PVMM_PROCESS_SYSTEM, ctxVmm->f32 ? 0xFFDF0014 : 0xFFFFF78000000014, (PBYTE)&ft, sizeof(QWORD)); + VmmRead(H, PVMM_PROCESS_SYSTEM, H->vmm.f32 ? 0xFFDF0014 : 0xFFFFF78000000014, (PBYTE)&ft, sizeof(QWORD)); return ft; } /* * Query the system for current time zone and its bias in minutes against UCT. * NB! individual sessions connected remotely may have other time zones. +* -- H * -- wszTimeZone = full name text representation - ex: 'Eastern Standard Time'. * -- piActiveBias = bias against UCT in minutes - ex: (CET=UCT+1=-60). * -- return */ _Success_(return) -BOOL SysQuery_TimeZone(_Out_writes_opt_(32) LPSTR uszTimeZone, _Out_opt_ int *piActiveBias) +BOOL SysQuery_TimeZone(_In_ VMM_HANDLE H, _Out_writes_opt_(32) LPSTR uszTimeZone, _Out_opt_ int *piActiveBias) { BYTE pbTimeZone[64]; if(uszTimeZone) { - if(!VmmWinReg_ValueQuery2("HKLM\\SYSTEM\\ControlSet001\\Control\\TimeZoneInformation\\TimeZoneKeyName", NULL, pbTimeZone, sizeof(pbTimeZone), NULL)) { return FALSE; } + if(!VmmWinReg_ValueQuery2(H, "HKLM\\SYSTEM\\ControlSet001\\Control\\TimeZoneInformation\\TimeZoneKeyName", NULL, pbTimeZone, sizeof(pbTimeZone), NULL)) { return FALSE; } CharUtil_WtoU((LPWSTR)pbTimeZone, 32, uszTimeZone, 32, NULL, NULL, CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR | CHARUTIL_FLAG_STR_BUFONLY); } if(piActiveBias) { - if(!VmmWinReg_ValueQuery2("HKLM\\SYSTEM\\ControlSet001\\Control\\TimeZoneInformation\\ActiveTimeBias", NULL, (PBYTE)piActiveBias, sizeof(DWORD), NULL)) { return FALSE; } + if(!VmmWinReg_ValueQuery2(H, "HKLM\\SYSTEM\\ControlSet001\\Control\\TimeZoneInformation\\ActiveTimeBias", NULL, (PBYTE)piActiveBias, sizeof(DWORD), NULL)) { return FALSE; } if((*piActiveBias > 24 * 60) && (*piActiveBias < -(24 * 60))) { return FALSE; } } return TRUE; diff --git a/vmm/sysquery.h b/vmm/sysquery.h index 6fb4d1c..f49c8fc 100644 --- a/vmm/sysquery.h +++ b/vmm/sysquery.h @@ -9,19 +9,21 @@ /* * Retrieve the current system time as FILETIME. +* -- H * -- return */ _Success_(return != 0) -QWORD SysQuery_TimeCurrent(); +QWORD SysQuery_TimeCurrent(_In_ VMM_HANDLE H); /* * Query the system for current time zone and its bias in minutes against UCT. * NB! individual sessions connected remotely may have other time zones. +* -- H * -- uszTimeZone = full name text representation - ex: 'Eastern Standard Time'. * -- piActiveBias = bias against UCT in minutes - ex: (CET=UCT+1=-60). * -- return */ _Success_(return) -BOOL SysQuery_TimeZone(_Out_writes_opt_(32) LPSTR uszTimeZone, _Out_opt_ int *piActiveBias); +BOOL SysQuery_TimeZone(_In_ VMM_HANDLE H, _Out_writes_opt_(32) LPSTR uszTimeZone, _Out_opt_ int *piActiveBias); #endif /* __SYSQUERY_H__ */ diff --git a/vmm/util.c b/vmm/util.c index 8af7f37..4e77b5f 100644 --- a/vmm/util.c +++ b/vmm/util.c @@ -110,7 +110,7 @@ size_t Util_usnprintf_ln_impl( // 2: write to buffer csz = _vsnprintf_s(uszBuffer, (SIZE_T)cszLineLength, _TRUNCATE, uszFormat, arglist); if((csz < 0) && (csz != -1)) { csz = 0; } // error & not _TRUNCATE - if(csz < cszLineLength - 1) { + if((QWORD)csz < cszLineLength - 1) { memset(uszBuffer + csz, ' ', (SIZE_T)(cszLineLength - 1 - csz)); } uszBuffer[cszLineLength - 1] = '\n'; @@ -183,7 +183,7 @@ NTSTATUS Util_VfsReadFile_FromStrA(_In_opt_ LPCSTR szFile, _Out_writes_to_(cb, * return Util_VfsReadFile_FromPBYTE((PBYTE)szFile, strlen(szFile), pb, cb, pcbRead, cbOffset); } -NTSTATUS Util_VfsReadFile_FromMEM(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD vaMEM, _In_ QWORD cbMEM, _In_ QWORD flags, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS Util_VfsReadFile_FromMEM(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ QWORD vaMEM, _In_ QWORD cbMEM, _In_ QWORD flags, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt = UTIL_NTSTATUS_END_OF_FILE; PBYTE pbMEM; @@ -191,7 +191,7 @@ NTSTATUS Util_VfsReadFile_FromMEM(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD vaM vaMEM += cbOffset; cbMEM -= cbOffset; if((cbMEM < 0x04000000) && (pbMEM = LocalAlloc(0, (SIZE_T)cbMEM))) { - if(VmmRead2(pProcess, vaMEM, pbMEM, (DWORD)cbMEM, flags)) { + if(VmmRead2(H, pProcess, vaMEM, pbMEM, (DWORD)cbMEM, flags)) { nt = Util_VfsReadFile_FromPBYTE(pbMEM, cbMEM, pb, cb, pcbRead, 0); } LocalFree(pbMEM); @@ -407,12 +407,12 @@ NTSTATUS Util_VfsWriteFile_QWORD(_Inout_ PQWORD pqwTarget, _In_reads_(cb) PBYTE return UTIL_NTSTATUS_SUCCESS; } -VOID Util_VfsTimeStampFile(_In_opt_ PVMM_PROCESS pProcess, _Out_ PVMMDLL_VFS_FILELIST_EXINFO pExInfo) +VOID Util_VfsTimeStampFile(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _Out_ PVMMDLL_VFS_FILELIST_EXINFO pExInfo) { pExInfo->dwVersion = VMMDLL_VFS_FILELIST_EXINFO_VERSION; pExInfo->fCompressed = pProcess && pProcess->dwState; - pExInfo->qwCreationTime = VmmProcess_GetCreateTimeOpt(pProcess); - pExInfo->qwLastWriteTime = (pProcess && pProcess->dwState) ? VmmProcess_GetExitTimeOpt(pProcess) : 0; + pExInfo->qwCreationTime = VmmProcess_GetCreateTimeOpt(H, pProcess); + pExInfo->qwLastWriteTime = (pProcess && pProcess->dwState) ? VmmProcess_GetExitTimeOpt(H, pProcess) : 0; if(!pExInfo->qwLastWriteTime) { pExInfo->qwLastWriteTime = pExInfo->qwCreationTime; } @@ -481,6 +481,24 @@ BOOL Util_FileTime2JSON(_In_ QWORD ft, _Out_writes_(21) LPSTR szTime) return TRUE; } +VOID Util_FileTime2CSV(_In_ QWORD ft, _Out_writes_(22) LPSTR szTime) +{ + SYSTEMTIME SystemTime; + if((ft < 0x0100000000000000) || (ft > 0x0200000000000000)) { + szTime[0] = 0; + return; + } + FileTimeToSystemTime((PFILETIME)&ft, &SystemTime); + sprintf_s(szTime, 22, "\"%04i-%02i-%02i %02i:%02i:%02i\"", + SystemTime.wYear, + SystemTime.wMonth, + SystemTime.wDay, + SystemTime.wHour, + SystemTime.wMinute, + SystemTime.wSecond + ); +} + VOID Util_GuidToString(_In_reads_(16) PBYTE pb, _Out_writes_(37) LPSTR szGUID) { typedef struct tdGUID { @@ -639,6 +657,7 @@ BOOL Util_VfsHelper_GetIdDir(_In_ LPSTR uszPath, _In_ BOOL fHex, _Out_ PDWORD pd /* * VariableLineRead: Read from a file dynamically created from a map/array object * using a callback function to populate individual lines (excluding header). +* -- H = VMM handle. * -- pfnCallback = callback function to populate individual lines. * -- ctx = optional context to 'pfn' callback function. * -- uszHeader = optional header line. @@ -653,6 +672,7 @@ BOOL Util_VfsHelper_GetIdDir(_In_ LPSTR uszPath, _In_ BOOL fHex, _Out_ PDWORD pd * -- return */ NTSTATUS Util_VfsLineVariable_Read( + _In_ VMM_HANDLE H, _In_ UTIL_VFSLINEFIXED_PFN_CB pfnCallback, _Inout_opt_ PVOID ctx, _In_opt_ LPSTR uszHeader, @@ -674,7 +694,7 @@ NTSTATUS Util_VfsLineVariable_Read( PVOID pvMapEntry; *pcbRead = 0; // header parse - if(uszHeader && ctxMain->cfg.fFileInfoHeader && (cbOffset < 0x400)) { + if(uszHeader && H->cfg.fFileInfoHeader && (cbOffset < 0x400)) { cbHeaderLine = uszHeader ? ((DWORD)strlen(uszHeader) + 1) : 0; if(cbOffset < 2ULL * cbHeaderLine) { _snprintf_s(szu, sizeof(szu), _TRUNCATE, "%s\n%.*s\n", uszHeader, cbHeaderLine - 1, UTIL_VFSLINEFIXED_LINEPAD512); @@ -718,7 +738,7 @@ NTSTATUS Util_VfsLineVariable_Read( cbLineLength = pdwLineOffset[ie] - cbLineStartOffset; if((cbOffset == cbLineStartOffset) && (cb > cbLineLength)) { // entry fits into line - pfnCallback(ctx, cbLineLength, ie, pvMapEntry, (LPSTR)pb); + pfnCallback(H, ctx, cbLineLength, ie, pvMapEntry, (LPSTR)pb); pb += cbLineLength; cb -= cbLineLength; cbOffset += cbLineLength; @@ -727,7 +747,7 @@ NTSTATUS Util_VfsLineVariable_Read( } else { // partial line if(cbLineLength + 1ULL > sizeof(szu)) { return UTIL_NTSTATUS_FILE_INVALID; } - pfnCallback(ctx, cbLineLength, ie, pvMapEntry, szu); + pfnCallback(H, ctx, cbLineLength, ie, pvMapEntry, szu); nt = Util_VfsReadFile_FromPBYTE(szu, cbLineLength, pb, cb, &cbRead, cbOffset - cbLineStartOffset); pb += cbRead; cb -= cbRead; @@ -744,6 +764,7 @@ finish: /* * FixedLineRead: Read from a file dynamically created from a map/array object * using a callback function to populate individual lines (excluding header). +* -- H = VMM handle. * -- pfnCallback = callback function to populate individual lines. * -- ctx = optional context to 'pfn' callback function. * -- cbLineLength = line length, including newline, excluding null terminator. @@ -758,6 +779,7 @@ finish: * -- return */ NTSTATUS Util_VfsLineFixed_Read( + _In_ VMM_HANDLE H, _In_ UTIL_VFSLINEFIXED_PFN_CB pfnCallback, _Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, @@ -774,7 +796,7 @@ NTSTATUS Util_VfsLineFixed_Read( NTSTATUS nt; PVOID pvMapEntry; QWORD i, iMapEntry, o = 0, cbMax, cStart, cEnd, cHeader; - cHeader = (uszHeader && ctxMain->cfg.fFileInfoHeader) ? 2 : 0; + cHeader = (uszHeader && H->cfg.fFileInfoHeader) ? 2 : 0; cStart = (DWORD)(cbOffset / cbLineLength); cEnd = (DWORD)min(cHeader + cMap - 1, (cb + cbOffset + cbLineLength - 1) / cbLineLength); cbMax = 1 + (1 + cEnd - cStart) * cbLineLength; @@ -792,7 +814,7 @@ NTSTATUS Util_VfsLineFixed_Read( // line: iMapEntry = i - cHeader; pvMapEntry = (PBYTE)pMap + iMapEntry * cbEntry; - pfnCallback(ctx, cbLineLength, (DWORD)iMapEntry, pvMapEntry, usz + o); + pfnCallback(H, ctx, cbLineLength, (DWORD)iMapEntry, pvMapEntry, usz + o); o += cbLineLength; } nt = Util_VfsReadFile_FromPBYTE(usz, cbMax - 1, pb, cb, pcbRead, cbOffset - cStart * cbLineLength); @@ -804,6 +826,7 @@ NTSTATUS Util_VfsLineFixed_Read( * FixedLineRead: Read from a file dynamically created from a custom generator * callback function using using a callback function to populate individual lines * (excluding header). +* -- H = VMM handle. * -- pfnCallback = callback function to populate individual lines. * -- ctx = optional context to 'pfn' callback function. * -- cbLineLength = line length, including newline, excluding null terminator. @@ -818,6 +841,7 @@ NTSTATUS Util_VfsLineFixed_Read( * -- return */ NTSTATUS Util_VfsLineFixedMapCustom_Read( + _In_ VMM_HANDLE H, _In_ UTIL_VFSLINEFIXED_PFN_CB pfnCallback, _Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, @@ -834,7 +858,7 @@ NTSTATUS Util_VfsLineFixedMapCustom_Read( NTSTATUS nt; PVOID pvMapEntry; QWORD i, iMapEntry, o = 0, cbMax, cStart, cEnd, cHeader; - cHeader = (uszHeader && ctxMain->cfg.fFileInfoHeader) ? 2 : 0; + cHeader = (uszHeader && H->cfg.fFileInfoHeader) ? 2 : 0; cStart = (DWORD)(cbOffset / cbLineLength); cEnd = (DWORD)min(cHeader + cMap - 1, (cb + cbOffset + cbLineLength - 1) / cbLineLength); cbMax = 1 + (1 + cEnd - cStart) * cbLineLength; @@ -851,8 +875,8 @@ NTSTATUS Util_VfsLineFixedMapCustom_Read( } // line: iMapEntry = i - cHeader; - pvMapEntry = pfnMap(ctxMap, (DWORD)iMapEntry); - pfnCallback(ctx, cbLineLength, (DWORD)iMapEntry, pvMapEntry, usz + o); + pvMapEntry = pfnMap(H, ctxMap, (DWORD)iMapEntry); + pfnCallback(H, ctx, cbLineLength, (DWORD)iMapEntry, pvMapEntry, usz + o); o += cbLineLength; } nt = Util_VfsReadFile_FromPBYTE(usz, cbMax - 1, pb, cb, pcbRead, cbOffset - cStart * cbLineLength); @@ -902,23 +926,23 @@ VOID Util_GetPathDll(_Out_writes_(MAX_PATH) PCHAR szPath, _In_opt_ HMODULE hModu } } -DWORD Util_ResourceSize(_In_ LPWSTR wszResourceName) +DWORD Util_ResourceSize(_In_ VMM_HANDLE H, _In_ LPWSTR wszResourceName) { HRSRC hRes; - if(!(hRes = FindResource(ctxVmm->hModuleVmmOpt, wszResourceName, RT_RCDATA))) { return 0; } - return SizeofResource(ctxVmm->hModuleVmmOpt, hRes); + if(!(hRes = FindResource(H->vmm.hModuleVmmOpt, wszResourceName, RT_RCDATA))) { return 0; } + return SizeofResource(H->vmm.hModuleVmmOpt, hRes); } -NTSTATUS Util_VfsReadFile_FromResource(_In_ LPWSTR wszResourceName, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS Util_VfsReadFile_FromResource(_In_ VMM_HANDLE H, _In_ LPWSTR wszResourceName, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { HRSRC hRes; HGLOBAL hResGlobal; DWORD cbRes; PBYTE pbRes; - if(!(hRes = FindResource(ctxVmm->hModuleVmmOpt, wszResourceName, RT_RCDATA))) { goto fail; } - if(!(hResGlobal = LoadResource(ctxVmm->hModuleVmmOpt, hRes))) { goto fail; } + if(!(hRes = FindResource(H->vmm.hModuleVmmOpt, wszResourceName, RT_RCDATA))) { goto fail; } + if(!(hResGlobal = LoadResource(H->vmm.hModuleVmmOpt, hRes))) { goto fail; } if(!(pbRes = (PBYTE)LockResource(hResGlobal))) { goto fail; } - cbRes = SizeofResource(ctxVmm->hModuleVmmOpt, hRes); + cbRes = SizeofResource(H->vmm.hModuleVmmOpt, hRes); return Util_VfsReadFile_FromPBYTE(pbRes, cbRes, pb, cb, pcbRead, cbOffset); fail: return VMMDLL_STATUS_FILE_INVALID; @@ -947,9 +971,9 @@ BOOL Util_HashSHA256(_In_reads_(cbData) PBYTE pbData, _In_ DWORD cbData, _Out_wr if(BCryptFinishHash(hHash, pbHash, 32, 0)) { goto fail; } fResult = TRUE; fail: - if(hAlg) { BCryptCloseAlgorithmProvider(hAlg, 0); } if(hHash) { BCryptDestroyHash(hHash); } LocalFree(pbHashObject); + if(hAlg) { BCryptCloseAlgorithmProvider(hAlg, 0); } return fResult; } @@ -995,6 +1019,6 @@ VOID Util_DeleteFileU(_In_ LPSTR uszPathFile) remove(uszPathFile); } -DWORD Util_ResourceSize(_In_ LPWSTR wszResourceName) { return 0; } -NTSTATUS Util_VfsReadFile_FromResource(_In_ LPWSTR wszResourceName, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { return VMMDLL_STATUS_FILE_INVALID; } +DWORD Util_ResourceSize(_In_ VMM_HANDLE H, _In_ LPWSTR wszResourceName) { return 0; } +NTSTATUS Util_VfsReadFile_FromResource(_In_ VMM_HANDLE H, _In_ LPWSTR wszResourceName, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { return VMMDLL_STATUS_FILE_INVALID; } #endif /* LINUX */ \ No newline at end of file diff --git a/vmm/util.h b/vmm/util.h index 0976f5a..2ca9b10 100644 --- a/vmm/util.h +++ b/vmm/util.h @@ -146,6 +146,14 @@ VOID Util_FileTime2String(_In_ QWORD ft, _Out_writes_(24) LPSTR szTime); */ BOOL Util_FileTime2JSON(_In_ QWORD ft, _Out_writes_(21) LPSTR szTime); +/* +* Convert a FILETIME (ft) into a CSV string. +* -- ft = the FILETIME in UTC time zone. +* -- szTime = time in format '"2020-01-01 23:59:59"' (21 chars). +* -- return +*/ +VOID Util_FileTime2CSV(_In_ QWORD ft, _Out_writes_(22) LPSTR szTime); + /* * Convert a GUID in byte format to a GUID in string format. * -- pbGUID = 16-byte GUID value. @@ -205,7 +213,7 @@ NTSTATUS Util_VfsReadFile_FromZERO(_In_ QWORD cbFile, _Out_writes_to_(cb, *pcbRe NTSTATUS Util_VfsReadFile_FromPBYTE(_In_opt_ PBYTE pbFile, _In_ QWORD cbFile, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset); NTSTATUS Util_VfsReadFile_FromHEXASCII(_In_opt_ PBYTE pbFile, _In_ QWORD cbFile, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset); NTSTATUS Util_VfsReadFile_FromStrA(_In_opt_ LPCSTR szFile, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset); -NTSTATUS Util_VfsReadFile_FromMEM(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD vaMEM, _In_ QWORD cbMEM, _In_ QWORD flags, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset); +NTSTATUS Util_VfsReadFile_FromMEM(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ QWORD vaMEM, _In_ QWORD cbMEM, _In_ QWORD flags, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset); NTSTATUS Util_VfsReadFile_FromObData(_In_opt_ POB_DATA pData, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset); NTSTATUS Util_VfsReadFile_FromObCompressed(_In_opt_ POB_COMPRESSED pdc, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset); NTSTATUS Util_VfsReadFile_FromObCompressedStrA(_In_opt_ POB_COMPRESSED pdc, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset); @@ -214,7 +222,7 @@ NTSTATUS Util_VfsReadFile_FromQWORD(_In_ QWORD qwValue, _Out_writes_to_(cb, *pcb NTSTATUS Util_VfsReadFile_FromDWORD(_In_ DWORD dwValue, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset, _In_ BOOL fPrefix); NTSTATUS Util_VfsReadFile_FromBOOL(_In_ BOOL fValue, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset); NTSTATUS Util_VfsReadFile_FromFILETIME(_In_ QWORD ftValue, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset); -NTSTATUS Util_VfsReadFile_FromResource(_In_ LPWSTR wszResourceName, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset); +NTSTATUS Util_VfsReadFile_FromResource(_In_ VMM_HANDLE H, _In_ LPWSTR wszResourceName, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset); NTSTATUS Util_VfsReadFile_usnprintf_ln(_Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset, _In_ QWORD cszLineLength, _In_z_ _Printf_format_string_ LPSTR uszFormat, ...); NTSTATUS Util_VfsWriteFile_BOOL(_Inout_ PBOOL pfTarget, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset); NTSTATUS Util_VfsWriteFile_09(_Inout_ PDWORD pdwTarget, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset); @@ -222,8 +230,8 @@ NTSTATUS Util_VfsWriteFile_DWORD(_Inout_ PDWORD pdwTarget, _In_reads_(cb) PBYTE NTSTATUS Util_VfsWriteFile_QWORD(_Inout_ PQWORD pqwTarget, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset, _In_ QWORD qwMinAllow, _In_opt_ QWORD qwMaxAllow); NTSTATUS Util_VfsWriteFile_PBYTE(_Inout_ PBYTE pbTarget, _In_ DWORD cbTarget, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset, _In_ BOOL fTerminatingNULL); NTSTATUS Util_VfsWriteFile_HEXASCII(_Inout_ PBYTE pbTarget, _In_ DWORD cbTarget, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset); -DWORD Util_ResourceSize(_In_ LPWSTR wszResourceName); -VOID Util_VfsTimeStampFile(_In_opt_ PVMM_PROCESS pProcess, _Out_ PVMMDLL_VFS_FILELIST_EXINFO pExInfo); +DWORD Util_ResourceSize(_In_ VMM_HANDLE H, _In_ LPWSTR wszResourceName); +VOID Util_VfsTimeStampFile(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _Out_ PVMMDLL_VFS_FILELIST_EXINFO pExInfo); /* * Retrieve PID / ID number from path (in base10). This is commonly used to @@ -237,13 +245,14 @@ VOID Util_VfsTimeStampFile(_In_opt_ PVMM_PROCESS pProcess, _Out_ PVMMDLL_VFS_FIL _Success_(return) BOOL Util_VfsHelper_GetIdDir(_In_ LPSTR uszPath, _In_ BOOL fHex, _Out_ PDWORD pdwID, _Out_opt_ LPSTR *puszSubPath); -#define UTIL_VFSLINEFIXED_LINECOUNT(c) (c + (ctxMain->cfg.fFileInfoHeader ? 2ULL : 0ULL)) -#define UTIL_VFSLINEVARIABLE_BYTECOUNT(c, pdwo, szHdr) ((c ? (pdwo[c - 1]) : 0) + (ctxMain->cfg.fFileInfoHeader ? 2 * strlen(szHdr) + 2 : 0ULL)) +#define UTIL_VFSLINEFIXED_LINECOUNT(H, c) (c + (H->cfg.fFileInfoHeader ? 2ULL : 0ULL)) +#define UTIL_VFSLINEVARIABLE_BYTECOUNT(H, c, pdwo, szHdr) ((c ? (pdwo[c - 1]) : 0) + (H->cfg.fFileInfoHeader ? 2 * strlen(szHdr) + 2 : 0ULL)) /* * FixedLineRead: Callback function to populate a fixed-length line in a * dynamically created file. Line data should be written in utf-8 with the * function: Util_snwprintf_u8ln(). Line data MUST ALWAYS be written! +* -- H = VMM handle. * -- ctx = optional context. * -- cbLineLength = line length including newline, excluding null terminator. * -- ie = line index. @@ -251,6 +260,7 @@ BOOL Util_VfsHelper_GetIdDir(_In_ LPSTR uszPath, _In_ BOOL fHex, _Out_ PDWORD pd * -- szu8 = utf-8 string to write line data into. */ typedef VOID(*UTIL_VFSLINEFIXED_PFN_CB)( + _In_ VMM_HANDLE H, _Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, @@ -261,6 +271,7 @@ typedef VOID(*UTIL_VFSLINEFIXED_PFN_CB)( /* * VariableLineRead: Read from a file dynamically created from a map/array object * using a callback function to populate individual lines (excluding header). +* -- H = VMM handle. * -- pfnCallback = callback function to populate individual lines. * -- ctx = optional context to 'pfn' callback function. * -- uszHeader = optional header line. @@ -275,6 +286,7 @@ typedef VOID(*UTIL_VFSLINEFIXED_PFN_CB)( * -- return */ NTSTATUS Util_VfsLineVariable_Read( + _In_ VMM_HANDLE H, _In_ UTIL_VFSLINEFIXED_PFN_CB pfnCallback, _Inout_opt_ PVOID ctx, _In_opt_ LPSTR uszHeader, @@ -291,6 +303,7 @@ NTSTATUS Util_VfsLineVariable_Read( /* * FixedLineRead: Read from a file dynamically created from a map/array object * using a callback function to populate individual lines (excluding header). +* -- H = VMM handle. * -- pfnCallback = callback function to populate individual lines. * -- ctx = optional context to 'pfn' callback function. * -- cbLineLength = line length, including newline, excluding null terminator. @@ -305,6 +318,7 @@ NTSTATUS Util_VfsLineVariable_Read( * -- return */ NTSTATUS Util_VfsLineFixed_Read( + _In_ VMM_HANDLE H, _In_ UTIL_VFSLINEFIXED_PFN_CB pfnCallback, _Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, @@ -320,10 +334,12 @@ NTSTATUS Util_VfsLineFixed_Read( /* * Util_VfsLineFixedMapCustom_Read: Callback function to retrieve an entry. +* -- H * -- pMap * -- iMap */ typedef PVOID(*UTIL_VFSLINEFIXED_MAP_PFN_CB)( + _In_ VMM_HANDLE H, _In_ PVOID ctxMap, _In_ DWORD iMap ); @@ -332,6 +348,7 @@ typedef PVOID(*UTIL_VFSLINEFIXED_MAP_PFN_CB)( * Util_VfsLineFixedMapCustom_Read: Read from a file dynamically created from a * custom generator callback function using using a callback function to * populate individual lines (excluding header). +* -- H = VMM handle. * -- pfnCallback = callback function to populate individual lines. * -- ctx = optional context to 'pfn' callback function. * -- cbLineLength = line length, including newline, excluding null terminator. @@ -346,6 +363,7 @@ typedef PVOID(*UTIL_VFSLINEFIXED_MAP_PFN_CB)( * -- return */ NTSTATUS Util_VfsLineFixedMapCustom_Read( + _In_ VMM_HANDLE H, _In_ UTIL_VFSLINEFIXED_PFN_CB pfnCallback, _Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, diff --git a/vmm/version.h b/vmm/version.h index c7f7419..2ed8038 100644 --- a/vmm/version.h +++ b/vmm/version.h @@ -1,10 +1,10 @@ #define STRINGIZE2(s) #s #define STRINGIZE(s) STRINGIZE2(s) -#define VERSION_MAJOR 4 -#define VERSION_MINOR 9 -#define VERSION_REVISION 3 -#define VERSION_BUILD 72 +#define VERSION_MAJOR 5 +#define VERSION_MINOR 0 +#define VERSION_REVISION 0 +#define VERSION_BUILD 73 #define VER_FILE_DESCRIPTION_STR "MemProcFS : Core" #define VER_FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_BUILD diff --git a/vmm/vmm.c b/vmm/vmm.c index b40a16e..8fb9caa 100644 --- a/vmm/vmm.c +++ b/vmm/vmm.c @@ -24,15 +24,6 @@ #include #endif /* _WIN32 */ -// ---------------------------------------------------------------------------- -// VMM global variables below: -// ---------------------------------------------------------------------------- - -PVMM_CONTEXT ctxVmm = NULL; -PVMM_MAIN_CONTEXT ctxMain = NULL; - - - // ---------------------------------------------------------------------------- // CACHE FUNCTIONALITY: // PHYSICAL MEMORY CACHING FOR READS AND PAGE TABLES @@ -43,15 +34,18 @@ PVMM_MAIN_CONTEXT ctxMain = NULL; /* * Retrieve cache table from ctxVmm given a specific tag. */ -PVMM_CACHE_TABLE VmmCacheTableGet(_In_ DWORD wTblTag) +PVMM_CACHE_TABLE VmmCacheTableGet(_In_ VMM_HANDLE H, _In_ DWORD wTblTag) { switch(wTblTag) { case VMM_CACHE_TAG_PHYS: - return &ctxVmm->Cache.PHYS; + H->vmm.Cache.PHYS.cMaxMems = VMM_CACHE_REGION_MEMS_PHYS; + return &H->vmm.Cache.PHYS; case VMM_CACHE_TAG_TLB: - return &ctxVmm->Cache.TLB; + H->vmm.Cache.TLB.cMaxMems = VMM_CACHE_REGION_MEMS_TLB; + return &H->vmm.Cache.TLB; case VMM_CACHE_TAG_PAGING: - return &ctxVmm->Cache.PAGING; + H->vmm.Cache.PAGING.cMaxMems = VMM_CACHE_REGION_MEMS_PAGING; + return &H->vmm.Cache.PAGING; default: return NULL; } @@ -61,14 +55,14 @@ PVMM_CACHE_TABLE VmmCacheTableGet(_In_ DWORD wTblTag) * Clear the oldest region of all InUse entries and make it the new active region. * -- wTblTag */ -VOID VmmCacheClearPartial(_In_ DWORD dwTblTag) +VOID VmmCacheClearPartial(_In_ VMM_HANDLE H, _In_ DWORD dwTblTag) { PVMM_CACHE_TABLE t; PVMMOB_CACHE_MEM pOb; PSLIST_ENTRY e; DWORD iR; PVMM_PROCESS pObProcess = NULL; - t = VmmCacheTableGet(dwTblTag); + t = VmmCacheTableGet(H, dwTblTag); if(!t || !t->fActive) { return; } EnterCriticalSection(&t->Lock); iR = (t->iR + (VMM_CACHE_REGIONS - 1)) % VMM_CACHE_REGIONS; @@ -87,7 +81,7 @@ VOID VmmCacheClearPartial(_In_ DWORD dwTblTag) LeaveCriticalSection(&t->Lock); // 2: if tlb cache clear -> update process 'is spider done' flag if(t->fAllActiveRegions && (dwTblTag == VMM_CACHE_TAG_TLB)) { - while((pObProcess = VmmProcessGetNext(pObProcess, 0))) { + while((pObProcess = VmmProcessGetNext(H, pObProcess, 0))) { if(pObProcess->fTlbSpiderDone) { EnterCriticalSection(&pObProcess->LockUpdate); pObProcess->fTlbSpiderDone = FALSE; @@ -101,11 +95,11 @@ VOID VmmCacheClearPartial(_In_ DWORD dwTblTag) * Clear the specified cache from all entries. * -- dwTblTag */ -VOID VmmCacheClear(_In_ DWORD dwTblTag) +VOID VmmCacheClear(_In_ VMM_HANDLE H, _In_ DWORD dwTblTag) { DWORD i; for(i = 0; i < VMM_CACHE_REGIONS; i++) { - VmmCacheClearPartial(dwTblTag); + VmmCacheClearPartial(H, dwTblTag); } } @@ -117,12 +111,12 @@ VOID VmmCacheClear(_In_ DWORD dwTblTag) * -- fCurrentRegionOnly = only retrieve from the currently active cache region. * -- return */ -PVMMOB_CACHE_MEM VmmCacheGetEx(_In_ DWORD dwTblTag, _In_ QWORD qwA, _In_ BOOL fCurrentRegionOnly) +PVMMOB_CACHE_MEM VmmCacheGetEx(_In_ VMM_HANDLE H, _In_ DWORD dwTblTag, _In_ QWORD qwA, _In_ BOOL fCurrentRegionOnly) { PVMM_CACHE_TABLE t; DWORD iB, iR, iRB, iRC; PVMMOB_CACHE_MEM pOb; - t = VmmCacheTableGet(dwTblTag); + t = VmmCacheTableGet(H, dwTblTag); if(!t || !t->fActive) { return NULL; } iB = VMM_CACHE_GET_BUCKET(qwA); iRB = t->iR; @@ -151,27 +145,17 @@ PVMMOB_CACHE_MEM VmmCacheGetEx(_In_ DWORD dwTblTag, _In_ QWORD qwA, _In_ BOOL fC * -- qwA * -- return */ -PVMMOB_CACHE_MEM VmmCacheGet(_In_ DWORD dwTblTag, _In_ QWORD qwA) +PVMMOB_CACHE_MEM VmmCacheGet(_In_ VMM_HANDLE H, _In_ DWORD dwTblTag, _In_ QWORD qwA) { - return VmmCacheGetEx(dwTblTag, qwA, FALSE); -} - -BOOL VmmCacheExists(_In_ DWORD dwTblTag, _In_ QWORD qwA) -{ - BOOL result; - PVMMOB_CACHE_MEM pOb; - pOb = VmmCacheGetEx(dwTblTag, qwA, FALSE); - result = pOb != NULL; - Ob_DECREF(pOb); - return result; + return VmmCacheGetEx(H, dwTblTag, qwA, FALSE); } VOID VmmCache_CallbackRefCount1(PVMMOB_CACHE_MEM pOb) { - PVMM_CACHE_TABLE t; - t = VmmCacheTableGet(((POB)pOb)->_tag); + VMM_HANDLE H = ((POB)pOb)->H; + PVMM_CACHE_TABLE t = VmmCacheTableGet(H, ((POB)pOb)->_tag); if(!t) { - VmmLog(MID_VMM, LOGLEVEL_CRITICAL, "ERROR - SHOULD NOT HAPPEN - INVALID OBJECT TAG %02X", ((POB)pOb)->_tag); + VmmLog(H, MID_VMM, LOGLEVEL_CRITICAL, "ERROR - SHOULD NOT HAPPEN - INVALID OBJECT TAG %02X", ((POB)pOb)->_tag); return; } if(!t->fActive) { return; } @@ -179,18 +163,18 @@ VOID VmmCache_CallbackRefCount1(PVMMOB_CACHE_MEM pOb) InterlockedPushEntrySList(&t->R[pOb->iR].ListHeadEmpty, &pOb->SListEmpty); } -PVMMOB_CACHE_MEM VmmCacheReserve(_In_ DWORD dwTblTag) +PVMMOB_CACHE_MEM VmmCacheReserve(_In_ VMM_HANDLE H, _In_ DWORD dwTblTag) { PVMM_CACHE_TABLE t; PVMMOB_CACHE_MEM pOb; PSLIST_ENTRY e; WORD cLoopProtect = 0; - t = VmmCacheTableGet(dwTblTag); + t = VmmCacheTableGet(H, dwTblTag); if(!t || !t->fActive) { return NULL; } while(!(e = InterlockedPopEntrySList(&t->R[t->iR].ListHeadEmpty))) { - if(QueryDepthSList(&t->R[t->iR].ListHeadTotal) < VMM_CACHE_REGION_MEMS) { + if(QueryDepthSList(&t->R[t->iR].ListHeadTotal) < t->cMaxMems) { // below max threshold -> create new - pOb = Ob_Alloc(t->tag, LMEM_ZEROINIT, sizeof(VMMOB_CACHE_MEM), NULL, (OB_CLEANUP_CB)VmmCache_CallbackRefCount1); + pOb = Ob_AllocEx(H, t->tag, LMEM_ZEROINIT, sizeof(VMMOB_CACHE_MEM), NULL, (OB_CLEANUP_CB)VmmCache_CallbackRefCount1); if(!pOb) { return NULL; } pOb->iR = t->iR; pOb->h.version = MEM_SCATTER_VERSION; @@ -202,9 +186,9 @@ PVMMOB_CACHE_MEM VmmCacheReserve(_In_ DWORD dwTblTag) return pOb; // return fresh object - refcount = 2. } // reclaim existing entries by clearing the oldest cache region. - VmmCacheClearPartial(dwTblTag); + VmmCacheClearPartial(H, dwTblTag); if(++cLoopProtect == VMM_CACHE_REGIONS) { - VmmLog(MID_VMM, LOGLEVEL_WARNING, "SHOULD NOT HAPPEN - CACHE %04X DRAINED OF ENTRIES", dwTblTag); + VmmLog(H, MID_VMM, LOGLEVEL_WARNING, "SHOULD NOT HAPPEN - CACHE %04X DRAINED OF ENTRIES", dwTblTag); Sleep(10); } } @@ -218,15 +202,16 @@ PVMMOB_CACHE_MEM VmmCacheReserve(_In_ DWORD dwTblTag) * Return an entry retrieved with VmmCacheReserve to the cache. * NB! no other items may be returned with this function! * FUNCTION DECREF: pOb +* -- H * -- pOb */ -VOID VmmCacheReserveReturn(_In_opt_ PVMMOB_CACHE_MEM pOb) +VOID VmmCacheReserveReturn(_In_ VMM_HANDLE H, _In_opt_ PVMMOB_CACHE_MEM pOb) { PVMM_CACHE_TABLE t; if(!pOb) { return; } - t = VmmCacheTableGet(((POB)pOb)->_tag); + t = VmmCacheTableGet(H, ((POB)pOb)->_tag); if(!t) { - VmmLog(MID_VMM, LOGLEVEL_CRITICAL, "ERROR - SHOULD NOT HAPPEN - INVALID OBJECT TAG %02X", ((POB)pOb)->_tag); + VmmLog(H, MID_VMM, LOGLEVEL_CRITICAL, "ERROR - SHOULD NOT HAPPEN - INVALID OBJECT TAG %02X", ((POB)pOb)->_tag); return; } if(!t->fActive || !pOb->h.f || (pOb->h.qwA == MEM_SCATTER_ADDR_INVALID)) { @@ -247,13 +232,13 @@ VOID VmmCacheReserveReturn(_In_opt_ PVMMOB_CACHE_MEM pOb) ReleaseSRWLockExclusive(&t->R[pOb->iR].LockSRW); } -VOID VmmCacheClose(_In_ DWORD dwTblTag) +VOID VmmCacheClose(_In_ VMM_HANDLE H, _In_ DWORD dwTblTag) { PVMM_CACHE_TABLE t; PVMMOB_CACHE_MEM pOb; PSLIST_ENTRY e; DWORD iR; - t = VmmCacheTableGet(dwTblTag); + t = VmmCacheTableGet(H, dwTblTag); if(!t || !t->fActive) { return; } t->fActive = FALSE; EnterCriticalSection(&t->Lock); @@ -278,17 +263,32 @@ VOID VmmCacheClose(_In_ DWORD dwTblTag) DeleteCriticalSection(&t->Lock); } -VOID VmmCacheInitialize(_In_ DWORD dwTblTag) +VOID VmmCacheInitialize(_In_ VMM_HANDLE H, _In_ DWORD dwTblTag) { - DWORD iR; + DWORD iR, iMEM; PVMM_CACHE_TABLE t; - t = VmmCacheTableGet(dwTblTag); + PVMMOB_CACHE_MEM pOb; + t = VmmCacheTableGet(H, dwTblTag); if(!t || t->fActive) { return; } for(iR = 0; iR < VMM_CACHE_REGIONS; iR++) { InitializeSRWLock(&t->R[iR].LockSRW); InitializeSListHead(&t->R[iR].ListHeadEmpty); InitializeSListHead(&t->R[iR].ListHeadInUse); InitializeSListHead(&t->R[iR].ListHeadTotal); + if(VMM_CACHE_REGION_MEMS_INITALLOC) { + for(iMEM = 0; iMEM < t->cMaxMems; iMEM++) { + pOb = Ob_AllocEx(H, dwTblTag, LMEM_ZEROINIT, sizeof(VMMOB_CACHE_MEM), NULL, (OB_CLEANUP_CB)VmmCache_CallbackRefCount1); + if(!pOb) { continue; } + pOb->iR = iR; + pOb->h.version = MEM_SCATTER_VERSION; + pOb->h.cb = 0x1000; + pOb->h.pb = pOb->pb; + pOb->h.qwA = MEM_SCATTER_ADDR_INVALID; + Ob_INCREF(pOb); + InterlockedPushEntrySList(&t->R[iR].ListHeadEmpty, &pOb->SListEmpty); + InterlockedPushEntrySList(&t->R[iR].ListHeadTotal, &pOb->SListTotal); + } + } } InitializeCriticalSection(&t->Lock); t->tag = dwTblTag; @@ -298,13 +298,13 @@ VOID VmmCacheInitialize(_In_ DWORD dwTblTag) /* * Invalidate a cache entry (if exists) */ -VOID VmmCacheInvalidate_2(_In_ DWORD dwTblTag, _In_ QWORD qwA) +VOID VmmCacheInvalidate_2(_In_ VMM_HANDLE H, _In_ DWORD dwTblTag, _In_ QWORD qwA) { PVMM_CACHE_TABLE t; PVMMOB_CACHE_MEM pOb; - t = VmmCacheTableGet(dwTblTag); + t = VmmCacheTableGet(H, dwTblTag); if(!t || !t->fActive) { return; } - while((pOb = VmmCacheGet(dwTblTag, qwA))) { + while((pOb = VmmCacheGet(H, dwTblTag, qwA))) { AcquireSRWLockExclusive(&t->R[pOb->iR].LockSRW); // remove from bucket list if(pOb->FLink) { @@ -322,36 +322,36 @@ VOID VmmCacheInvalidate_2(_In_ DWORD dwTblTag, _In_ QWORD qwA) } } -VOID VmmCacheInvalidate(_In_ QWORD pa) +VOID VmmCacheInvalidate(_In_ VMM_HANDLE H, _In_ QWORD pa) { - VmmCacheInvalidate_2(VMM_CACHE_TAG_TLB, pa); - VmmCacheInvalidate_2(VMM_CACHE_TAG_PHYS, pa); + VmmCacheInvalidate_2(H, VMM_CACHE_TAG_TLB, pa); + VmmCacheInvalidate_2(H, VMM_CACHE_TAG_PHYS, pa); } -PVMMOB_CACHE_MEM VmmCacheGet_FromDeviceOnMiss(_In_ DWORD dwTblTag, _In_ DWORD dwTblTagSecondaryOpt, _In_ QWORD qwA) +PVMMOB_CACHE_MEM VmmCacheGet_FromDeviceOnMiss(_In_ VMM_HANDLE H, _In_ DWORD dwTblTag, _In_ DWORD dwTblTagSecondaryOpt, _In_ QWORD qwA) { PVMMOB_CACHE_MEM pObMEM, pObReservedMEM; PMEM_SCATTER pMEM; - pObMEM = VmmCacheGet(dwTblTag, qwA); + pObMEM = VmmCacheGet(H, dwTblTag, qwA); if(pObMEM) { return pObMEM; } - if((pObReservedMEM = VmmCacheReserve(dwTblTag))) { + if((pObReservedMEM = VmmCacheReserve(H, dwTblTag))) { pMEM = &pObReservedMEM->h; pMEM->qwA = qwA; - if(dwTblTagSecondaryOpt && (pObMEM = VmmCacheGet(dwTblTagSecondaryOpt, qwA))) { + if(dwTblTagSecondaryOpt && (pObMEM = VmmCacheGet(H, dwTblTagSecondaryOpt, qwA))) { pMEM->f = TRUE; memcpy(pMEM->pb, pObMEM->pb, 0x1000); Ob_DECREF(pObMEM); pObMEM = NULL; } if(!pMEM->f) { - LcReadScatter(ctxMain->hLC, 1, &pMEM); + LcReadScatter(H->hLC, 1, &pMEM); } if(pMEM->f) { Ob_INCREF(pObReservedMEM); - VmmCacheReserveReturn(pObReservedMEM); + VmmCacheReserveReturn(H, pObReservedMEM); return pObReservedMEM; } - VmmCacheReserveReturn(pObReservedMEM); + VmmCacheReserveReturn(H, pObReservedMEM); } return NULL; } @@ -359,27 +359,28 @@ PVMMOB_CACHE_MEM VmmCacheGet_FromDeviceOnMiss(_In_ DWORD dwTblTag, _In_ DWORD dw /* * Retrieve a page table from a given physical address (if possible). * CALLER DECREF: return +* -- H * -- pa * -- fCacheOnly * -- return = Cache entry on success, NULL on fail. */ -PVMMOB_CACHE_MEM VmmTlbGetPageTable(_In_ QWORD pa, _In_ BOOL fCacheOnly) +PVMMOB_CACHE_MEM VmmTlbGetPageTable(_In_ VMM_HANDLE H, _In_ QWORD pa, _In_ BOOL fCacheOnly) { PVMMOB_CACHE_MEM pObMEM; - pObMEM = VmmCacheGet(VMM_CACHE_TAG_TLB, pa); + pObMEM = VmmCacheGet(H, VMM_CACHE_TAG_TLB, pa); if(pObMEM) { - InterlockedIncrement64(&ctxVmm->stat.cTlbCacheHit); + InterlockedIncrement64(&H->vmm.stat.cTlbCacheHit); return pObMEM; } if(fCacheOnly) { return NULL; } // try retrieve from (1) TLB cache, (2) PHYS cache, (3) device - pObMEM = VmmCacheGet_FromDeviceOnMiss(VMM_CACHE_TAG_TLB, VMM_CACHE_TAG_PHYS, pa); + pObMEM = VmmCacheGet_FromDeviceOnMiss(H, VMM_CACHE_TAG_TLB, VMM_CACHE_TAG_PHYS, pa); if(!pObMEM) { - InterlockedIncrement64(&ctxVmm->stat.cTlbReadFail); + InterlockedIncrement64(&H->vmm.stat.cTlbReadFail); return NULL; } - InterlockedIncrement64(&ctxVmm->stat.cTlbReadSuccess); - if(VmmTlbPageTableVerify(pObMEM->h.pb, pObMEM->h.qwA, FALSE)) { + InterlockedIncrement64(&H->vmm.stat.cTlbReadSuccess); + if(VmmTlbPageTableVerify(H, pObMEM->h.pb, pObMEM->h.qwA, FALSE)) { return pObMEM; } Ob_DECREF(pObMEM); @@ -391,6 +392,7 @@ PVMMOB_CACHE_MEM VmmTlbGetPageTable(_In_ QWORD pa, _In_ BOOL fCacheOnly) * The successfully translated Physical Address (PA) is returned in ppa. * Upon fail the PTE will be returned in ppa (if possible) - which may be used * to further lookup virtual memory in case of PageFile or Win10 MemCompression. +* -- H * -- paDTB * -- fUserOnly * -- va @@ -398,11 +400,11 @@ PVMMOB_CACHE_MEM VmmTlbGetPageTable(_In_ QWORD pa, _In_ BOOL fCacheOnly) * -- return */ _Success_(return) -BOOL VmmVirt2PhysEx(_In_ QWORD paDTB, _In_ BOOL fUserOnly, _In_ QWORD va, _Out_ PQWORD ppa) +BOOL VmmVirt2PhysEx(_In_ VMM_HANDLE H, _In_ QWORD paDTB, _In_ BOOL fUserOnly, _In_ QWORD va, _Out_ PQWORD ppa) { *ppa = 0; - if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_NA) { return FALSE; } - return ctxVmm->fnMemoryModel.pfnVirt2Phys(paDTB, fUserOnly, -1, va, ppa); + if(H->vmm.tpMemoryModel == VMM_MEMORYMODEL_NA) { return FALSE; } + return H->vmm.fnMemoryModel.pfnVirt2Phys(H, paDTB, fUserOnly, -1, va, ppa); } /* @@ -410,50 +412,54 @@ BOOL VmmVirt2PhysEx(_In_ QWORD paDTB, _In_ BOOL fUserOnly, _In_ QWORD va, _Out_ * The successfully translated Physical Address (PA) is returned in ppa. * Upon fail the PTE will be returned in ppa (if possible) - which may be used * to further lookup virtual memory in case of PageFile or Win10 MemCompression. +* -- H * -- pProcess * -- va * -- ppa * -- return */ _Success_(return) -BOOL VmmVirt2Phys(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD va, _Out_ PQWORD ppa) +BOOL VmmVirt2Phys(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ QWORD va, _Out_ PQWORD ppa) { *ppa = 0; - if(!pProcess || (ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_NA)) { return FALSE; } - return ctxVmm->fnMemoryModel.pfnVirt2Phys(pProcess->paDTB, pProcess->fUserOnly, -1, va, ppa); + if(!pProcess || (H->vmm.tpMemoryModel == VMM_MEMORYMODEL_NA)) { return FALSE; } + return H->vmm.fnMemoryModel.pfnVirt2Phys(H, pProcess->paDTB, pProcess->fUserOnly, -1, va, ppa); } /* * Spider the TLB (page table cache) to load all page table pages into the cache. * This is done to speed up various subsequent virtual memory accesses. * NB! pages may fall out of the cache if it's in heavy use or doe to timing. +* -- H * -- pProcess */ -VOID VmmTlbSpider(_In_ PVMM_PROCESS pProcess) +VOID VmmTlbSpider(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess) { - if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_NA) { return; } - ctxVmm->fnMemoryModel.pfnTlbSpider(pProcess); + if(H->vmm.tpMemoryModel == VMM_MEMORYMODEL_NA) { return; } + H->vmm.fnMemoryModel.pfnTlbSpider(H, pProcess); } /* * Try verify that a supplied page table in pb is valid by analyzing it. +* -- H * -- pb = 0x1000 bytes containing the page table page. * -- pa = physical address if the page table page. * -- fSelfRefReq = is a self referential entry required to be in the map? (PML4 for Windows). */ -BOOL VmmTlbPageTableVerify(_Inout_ PBYTE pb, _In_ QWORD pa, _In_ BOOL fSelfRefReq) +BOOL VmmTlbPageTableVerify(_In_ VMM_HANDLE H, _Inout_ PBYTE pb, _In_ QWORD pa, _In_ BOOL fSelfRefReq) { - if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_NA) { return FALSE; } - return ctxVmm->fnMemoryModel.pfnTlbPageTableVerify(pb, pa, fSelfRefReq); + if(H->vmm.tpMemoryModel == VMM_MEMORYMODEL_NA) { return FALSE; } + return H->vmm.fnMemoryModel.pfnTlbPageTableVerify(H, pb, pa, fSelfRefReq); } /* * Prefetch a set of physical addresses contained in pTlbPrefetch into the Tlb. * NB! pTlbPrefetch must not be updated/altered during the function call. +* -- H * -- pProcess * -- pTlbPrefetch = the page table addresses to prefetch (on entry) and empty set on exit. */ -VOID VmmTlbPrefetch(_In_ POB_SET pTlbPrefetch) +VOID VmmTlbPrefetch(_In_ VMM_HANDLE H, _In_ POB_SET pTlbPrefetch) { QWORD pbTlb = 0; DWORD cTlbs, i = 0; @@ -464,16 +470,16 @@ VOID VmmTlbPrefetch(_In_ POB_SET pTlbPrefetch) if(!(ppObMEMs = LocalAlloc(0, cTlbs * sizeof(PVMMOB_CACHE_MEM)))) { goto fail; } while((cTlbs = min(0x2000, ObSet_Size(pTlbPrefetch)))) { // protect cache bleed -> max 0x2000 pages/round for(i = 0; i < cTlbs; i++) { - ppObMEMs[i] = VmmCacheReserve(VMM_CACHE_TAG_TLB); + ppObMEMs[i] = VmmCacheReserve(H, VMM_CACHE_TAG_TLB); ppMEMs[i] = &ppObMEMs[i]->h; ppMEMs[i]->qwA = ObSet_Pop(pTlbPrefetch); } - LcReadScatter(ctxMain->hLC, cTlbs, ppMEMs); + LcReadScatter(H->hLC, cTlbs, ppMEMs); for(i = 0; i < cTlbs; i++) { - if(ppMEMs[i]->f && !VmmTlbPageTableVerify(ppMEMs[i]->pb, ppMEMs[i]->qwA, FALSE)) { + if(ppMEMs[i]->f && !VmmTlbPageTableVerify(H, ppMEMs[i]->pb, ppMEMs[i]->qwA, FALSE)) { ppMEMs[i]->f = FALSE; // "fail" invalid page table read } - VmmCacheReserveReturn(ppObMEMs[i]); + VmmCacheReserveReturn(H, ppObMEMs[i]); } } fail: @@ -486,25 +492,26 @@ fail: * is useful when reading data from somewhat known addresses over higher latency * connections. * NB! pPrefetchPages must not be updated/altered during the function call. +* -- H * -- pProcess * -- pPrefetchPages * -- flags */ -VOID VmmCachePrefetchPages(_In_opt_ PVMM_PROCESS pProcess, _In_opt_ POB_SET pPrefetchPages, _In_ QWORD flags) +VOID VmmCachePrefetchPages(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_opt_ POB_SET pPrefetchPages, _In_ QWORD flags) { QWORD qwA = 0; DWORD cPages, iMEM = 0; PPMEM_SCATTER ppMEMs = NULL; cPages = ObSet_Size(pPrefetchPages); - if(!cPages || (ctxVmm->flags & VMM_FLAG_NOCACHE)) { return; } + if(!cPages || (H->vmm.flags & VMM_FLAG_NOCACHE)) { return; } if(!LcAllocScatter1(cPages, &ppMEMs)) { return; } while((qwA = ObSet_GetNext(pPrefetchPages, qwA))) { ppMEMs[iMEM++]->qwA = qwA & ~0xfff; } if(pProcess) { - VmmReadScatterVirtual(pProcess, ppMEMs, iMEM, flags | VMM_FLAG_CACHE_RECENT_ONLY); + VmmReadScatterVirtual(H, pProcess, ppMEMs, iMEM, flags | VMM_FLAG_CACHE_RECENT_ONLY); } else { - VmmReadScatterPhysical(ppMEMs, iMEM, flags | VMM_FLAG_CACHE_RECENT_ONLY); + VmmReadScatterPhysical(H, ppMEMs, iMEM, flags | VMM_FLAG_CACHE_RECENT_ONLY); } LcMemFree(ppMEMs); } @@ -512,22 +519,23 @@ VOID VmmCachePrefetchPages(_In_opt_ PVMM_PROCESS pProcess, _In_opt_ POB_SET pPre /* * Prefetch a set of addresses. This is useful when reading data from somewhat * known addresses over higher latency connections. +* -- H * -- pProcess * -- cAddresses * -- ... = variable list of total cAddresses of addresses of type QWORD. */ -VOID VmmCachePrefetchPages2(_In_opt_ PVMM_PROCESS pProcess, _In_ DWORD cAddresses, ...) +VOID VmmCachePrefetchPages2(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ DWORD cAddresses, ...) { va_list arguments; POB_SET pObSet = NULL; - if(!cAddresses || !(pObSet = ObSet_New())) { return; } + if(!cAddresses || !(pObSet = ObSet_New(H))) { return; } va_start(arguments, cAddresses); while(cAddresses) { ObSet_Push(pObSet, va_arg(arguments, QWORD) & ~0xfff); cAddresses--; } va_end(arguments); - VmmCachePrefetchPages(pProcess, pObSet, 0); + VmmCachePrefetchPages(H, pProcess, pObSet, 0); Ob_DECREF(pObSet); } @@ -536,51 +544,54 @@ VOID VmmCachePrefetchPages2(_In_opt_ PVMM_PROCESS pProcess, _In_ DWORD cAddresse * the cache by first converting them to page aligned pages. This is used when * reading data from somewhat known addresses over higher latency connections. * NB! pPrefetchPagesNonPageAligned must not be altered during the function call. +* -- H * -- pProcess * -- pPrefetchPagesNonPageAligned * -- cb * -- flags */ -VOID VmmCachePrefetchPages3(_In_opt_ PVMM_PROCESS pProcess, _In_opt_ POB_SET pPrefetchPagesNonPageAligned, _In_ DWORD cb, _In_ QWORD flags) +VOID VmmCachePrefetchPages3(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_opt_ POB_SET pPrefetchPagesNonPageAligned, _In_ DWORD cb, _In_ QWORD flags) { QWORD qwA = 0; POB_SET pObSetAlign; if(!cb || !pPrefetchPagesNonPageAligned) { return; } if(0 == ObSet_Size(pPrefetchPagesNonPageAligned)) { return; } - if(!(pObSetAlign = ObSet_New())) { return; } + if(!(pObSetAlign = ObSet_New(H))) { return; } while((qwA = ObSet_GetNext(pPrefetchPagesNonPageAligned, qwA))) { ObSet_Push_PageAlign(pObSetAlign, qwA, cb); } - VmmCachePrefetchPages(pProcess, pObSetAlign, flags); + VmmCachePrefetchPages(H, pProcess, pObSetAlign, flags); Ob_DECREF(pObSetAlign); } /* * Prefetch an array of optionally non-page aligned addresses. This is useful * when reading data from somewhat known addresses over higher latency connections. +* -- H * -- pProcess * -- cAddresses * -- pqwAddresses = array of addresses to fetch * -- cb * -- flags */ -VOID VmmCachePrefetchPages4(_In_opt_ PVMM_PROCESS pProcess, _In_ DWORD cAddresses, _In_ PQWORD pqwAddresses, _In_ DWORD cb, _In_ QWORD flags) +VOID VmmCachePrefetchPages4(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ DWORD cAddresses, _In_ PQWORD pqwAddresses, _In_ DWORD cb, _In_ QWORD flags) { POB_SET pObSet = NULL; - if(!cAddresses || !(pObSet = ObSet_New())) { return; } + if(!cAddresses || !(pObSet = ObSet_New(H))) { return; } while(cAddresses) { cAddresses--; if(pqwAddresses[cAddresses]) { ObSet_Push_PageAlign(pObSet, pqwAddresses[cAddresses], cb); } } - VmmCachePrefetchPages(pProcess, pObSet, 0); + VmmCachePrefetchPages(H, pProcess, pObSet, 0); Ob_DECREF(pObSet); } /* * Prefetch memory of optionally non-page aligned addresses which are derived * from pmPrefetchObjects by the pfnFilter filter function. +* -- H * -- pProcess * -- pmPrefetch = map of objects. * -- cb @@ -588,11 +599,11 @@ VOID VmmCachePrefetchPages4(_In_opt_ PVMM_PROCESS pProcess, _In_ DWORD cAddresse * -- pfnFilter = filter as required by ObMap_FilterSet function. * -- return = at least one object is found to be prefetched into cache. */ -BOOL VmmCachePrefetchPages5(_In_opt_ PVMM_PROCESS pProcess, _In_opt_ POB_MAP pmPrefetch, _In_ DWORD cb, _In_ QWORD flags, _In_ VOID(*pfnFilter)(_In_ QWORD k, _In_ PVOID v, _Inout_ POB_SET ps)) +BOOL VmmCachePrefetchPages5(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_opt_ POB_MAP pmPrefetch, _In_ DWORD cb, _In_ QWORD flags, _In_ VOID(*pfnFilter)(_In_ QWORD k, _In_ PVOID v, _Inout_ POB_SET ps)) { POB_SET psObCache = ObMap_FilterSet(pmPrefetch, pfnFilter); BOOL fResult = ObSet_Size(psObCache) > 0; - VmmCachePrefetchPages3(pProcess, psObCache, cb, flags); + VmmCachePrefetchPages3(H, pProcess, psObCache, cb, flags); Ob_DECREF(psObCache); return fResult; } @@ -627,14 +638,14 @@ BOOL VmmCachePrefetchPages5(_In_opt_ PVMM_PROCESS pProcess, _In_opt_ POB_MAP pmP // ---------------------------------------------------------------------------- #ifdef _WIN32 -VOID VmmProcess_TokenTryEnsure(_In_ PVMMOB_PROCESS_TABLE pt) +VOID VmmProcess_TokenTryEnsure(_In_ VMM_HANDLE H, _In_ PVMMOB_PROCESS_TABLE pt) { - BOOL f, f32 = ctxVmm->f32; + BOOL f, f32 = H->vmm.f32; DWORD j, i = 0, iM, cbHdr, cb, dwIntegrityLevelIndex; QWORD va, *pva = NULL; BYTE pb[0x1000]; PVMM_PROCESS *ppProcess = NULL, pObSystemProcess = NULL; - PVMM_OFFSET_EPROCESS oep = &ctxVmm->offset.EPROCESS; + PVMM_OFFSET_EPROCESS poe = &H->vmm.offset.EPROCESS; LPSTR szSidIntegrity = NULL; BOOL fSidIntegrity; VMM_PROCESS_INTEGRITY_LEVEL IntegrityLevel; @@ -642,20 +653,20 @@ VOID VmmProcess_TokenTryEnsure(_In_ PVMMOB_PROCESS_TABLE pt) SID SID; BYTE pb[SECURITY_MAX_SID_SIZE]; } SidIntegrity; - f = oep->opt.TOKEN_TokenId && // token offsets/symbols initialized. - (pObSystemProcess = VmmProcessGet(4)) && + f = poe->opt.TOKEN_TokenId && // token offsets/symbols initialized. + (pObSystemProcess = VmmProcessGet(H, 4)) && (pva = LocalAlloc(LMEM_ZEROINIT, pt->c * 2 * sizeof(QWORD))) && (ppProcess = LocalAlloc(LMEM_ZEROINIT, pt->c * sizeof(PVMM_PROCESS))); if(!f) { goto fail; } cbHdr = f32 ? 0x2c : 0x5c; - cb = cbHdr + oep->opt.TOKEN_cb; - if((cb > 0x1000) || !oep->opt.TOKEN_cb) { goto fail; } + cb = cbHdr + poe->opt.TOKEN_cb; + if((cb > 0x1000) || !poe->opt.TOKEN_cb) { goto fail; } // 1: Get Process and Token VA: iM = pt->_iFLink; while(iM && i < pt->c) { if((ppProcess[i] = pt->_M[iM]) && !ppProcess[i]->win.TOKEN.fInitialized) { - va = VMM_PTR_OFFSET(f32, ppProcess[i]->win.EPROCESS.pb, oep->opt.Token) & (f32 ? ~0x7 : ~0xf); - if(VMM_KADDR(va)) { + va = VMM_PTR_OFFSET(f32, ppProcess[i]->win.EPROCESS.pb, poe->opt.Token) & (f32 ? ~0x7 : ~0xf); + if(VMM_KADDR(f32, va)) { ppProcess[i]->win.TOKEN.va = va; pva[i] = va - cbHdr; // adjust for _OBJECT_HEADER and Pool Header } @@ -664,60 +675,60 @@ VOID VmmProcess_TokenTryEnsure(_In_ PVMMOB_PROCESS_TABLE pt) i++; } // 2: Read Token: - VmmCachePrefetchPages4(pObSystemProcess, (DWORD)pt->c, pva, cb, 0); + VmmCachePrefetchPages4(H, pObSystemProcess, (DWORD)pt->c, pva, cb, 0); for(i = 0; i < pt->c; i++) { - if(!pva[i] || !VmmRead2(pObSystemProcess, pva[i], pb, cb, VMM_FLAG_FORCECACHE_READ)) { continue; } + if(!pva[i] || !VmmRead2(H, pObSystemProcess, pva[i], pb, cb, VMM_FLAG_FORCECACHE_READ)) { continue; } // 2.1: fetch TOKEN.UserAndGroups (user id [_SID_AND_ATTRIBUTES]) - pva[i] = VMM_PTR_OFFSET(f32, pb + cbHdr, oep->opt.TOKEN_UserAndGroups); - if(!VMM_KADDR(pva[i])) { pva[i] = 0; continue; } + pva[i] = VMM_PTR_OFFSET(f32, pb + cbHdr, poe->opt.TOKEN_UserAndGroups); + if(!VMM_KADDR(f32, pva[i])) { pva[i] = 0; continue; } ppProcess[i]->win.TOKEN.vaUserAndGroups = pva[i]; // 2.2: fetch various offsets for(j = 0, f = FALSE; !f && (j < cbHdr); j += (f32 ? 0x08 : 0x10)) { f = VMM_POOLTAG_SHORT(*(PDWORD)(pb + j), 'Toke'); } if(!f) { pva[i] = 0; continue; } - ppProcess[i]->win.TOKEN.qwLUID = *(PQWORD)(pb + cbHdr + ctxVmm->offset.EPROCESS.opt.TOKEN_TokenId); - ppProcess[i]->win.TOKEN.dwSessionId = *(PDWORD)(pb + cbHdr + ctxVmm->offset.EPROCESS.opt.TOKEN_SessionId); - if(ctxVmm->offset.EPROCESS.opt.TOKEN_UserAndGroupCount) { - ppProcess[i]->win.TOKEN.dwUserAndGroupCount = *(PDWORD)(pb + cbHdr + ctxVmm->offset.EPROCESS.opt.TOKEN_UserAndGroupCount); + ppProcess[i]->win.TOKEN.qwLUID = *(PQWORD)(pb + cbHdr + poe->opt.TOKEN_TokenId); + ppProcess[i]->win.TOKEN.dwSessionId = *(PDWORD)(pb + cbHdr + poe->opt.TOKEN_SessionId); + if(poe->opt.TOKEN_UserAndGroupCount) { + ppProcess[i]->win.TOKEN.dwUserAndGroupCount = *(PDWORD)(pb + cbHdr + poe->opt.TOKEN_UserAndGroupCount); } - if(ctxVmm->offset.EPROCESS.opt.TOKEN_IntegrityLevelIndex) { - dwIntegrityLevelIndex = *(PDWORD)(pb + cbHdr + ctxVmm->offset.EPROCESS.opt.TOKEN_IntegrityLevelIndex); + if(poe->opt.TOKEN_IntegrityLevelIndex) { + dwIntegrityLevelIndex = *(PDWORD)(pb + cbHdr + poe->opt.TOKEN_IntegrityLevelIndex); if(dwIntegrityLevelIndex > ppProcess[i]->win.TOKEN.dwUserAndGroupCount) { dwIntegrityLevelIndex = 0; } } // 2.3: fetch TOKEN.UserAndGroups+dwIntegrityLevelIndex (integrity level [_SID_AND_ATTRIBUTES]) if(dwIntegrityLevelIndex) { - va = VMM_PTR_OFFSET(f32, pb + cbHdr, oep->opt.TOKEN_UserAndGroups) + dwIntegrityLevelIndex * (f32 ? 8ULL : 16ULL); - if(VMM_KADDR(va)) { pva[pt->c + i] = va; } + va = VMM_PTR_OFFSET(f32, pb + cbHdr, poe->opt.TOKEN_UserAndGroups) + dwIntegrityLevelIndex * (f32 ? 8ULL : 16ULL); + if(VMM_KADDR(f32, va)) { pva[pt->c + i] = va; } } } // 3: Read SID user & integrity ptr: - VmmCachePrefetchPages4(pObSystemProcess, 2 * (DWORD)pt->c, pva, 8, 0); + VmmCachePrefetchPages4(H, pObSystemProcess, 2 * (DWORD)pt->c, pva, 8, 0); for(i = 0; i < pt->c; i++) { // user: - f = pva[i] && VmmRead2(pObSystemProcess, pva[i], pb, 8, VMM_FLAG_FORCECACHE_READ) && + f = pva[i] && VmmRead2(H, pObSystemProcess, pva[i], pb, 8, VMM_FLAG_FORCECACHE_READ) && (va = VMM_PTR_OFFSET(f32, pb, 0)) && - VMM_KADDR(va); + VMM_KADDR(f32, va); pva[i] = f ? va : 0; // integrity: - f = pva[pt->c + i] && VmmRead2(pObSystemProcess, pva[pt->c + i], pb, 8, VMM_FLAG_FORCECACHE_READ) && + f = pva[pt->c + i] && VmmRead2(H, pObSystemProcess, pva[pt->c + i], pb, 8, VMM_FLAG_FORCECACHE_READ) && (va = VMM_PTR_OFFSET(f32, pb, 0)) && - VMM_KADDR(va); + VMM_KADDR(f32, va); pva[pt->c + i] = f ? va : 0; } // 4: Get SID user & integrity: - VmmCachePrefetchPages4(pObSystemProcess, 2 * (DWORD)pt->c, pva, SECURITY_MAX_SID_SIZE, 0); + VmmCachePrefetchPages4(H, pObSystemProcess, 2 * (DWORD)pt->c, pva, SECURITY_MAX_SID_SIZE, 0); for(i = 0; i < pt->c; i++) { if(!ppProcess[i]) { continue; } // user: ppProcess[i]->win.TOKEN.fSidUserValid = (va = pva[i]) && - VmmRead2(pObSystemProcess, va, ppProcess[i]->win.TOKEN.SidUser.pb, SECURITY_MAX_SID_SIZE, VMM_FLAG_FORCECACHE_READ) && + VmmRead2(H, pObSystemProcess, va, ppProcess[i]->win.TOKEN.SidUser.pb, SECURITY_MAX_SID_SIZE, VMM_FLAG_FORCECACHE_READ) && IsValidSid(&ppProcess[i]->win.TOKEN.SidUser.SID); // integrity: fSidIntegrity = (va = pva[pt->c + i]) && - VmmRead2(pObSystemProcess, va, SidIntegrity.pb, SECURITY_MAX_SID_SIZE, VMM_FLAG_FORCECACHE_READ) && + VmmRead2(H, pObSystemProcess, va, SidIntegrity.pb, SECURITY_MAX_SID_SIZE, VMM_FLAG_FORCECACHE_READ) && IsValidSid(&SidIntegrity.SID) && ConvertSidToStringSidA(&SidIntegrity.SID, &szSidIntegrity); if(fSidIntegrity) { @@ -751,41 +762,43 @@ fail: } #endif /* _WIN32 */ #ifdef LINUX -VOID VmmProcess_TokenTryEnsure(_In_ PVMMOB_PROCESS_TABLE pt) { return; } +VOID VmmProcess_TokenTryEnsure(_In_ VMM_HANDLE H, _In_ PVMMOB_PROCESS_TABLE pt) { return; } #endif /* LINUX */ /* * Global Synchronization/Lock of VmmProcess_TokenTryEnsure() +* -- H * -- pt * -- pProcess */ -VOID VmmProcess_TokenTryEnsureLock(_In_ PVMMOB_PROCESS_TABLE pt, _In_ PVMM_PROCESS pProcess) +VOID VmmProcess_TokenTryEnsureLock(_In_ VMM_HANDLE H, _In_ PVMMOB_PROCESS_TABLE pt, _In_ PVMM_PROCESS pProcess) { if(pProcess->win.TOKEN.fInitialized) { return; } - EnterCriticalSection(&ctxVmm->LockMaster); + EnterCriticalSection(&H->vmm.LockMaster); if(!pProcess->win.TOKEN.fInitialized) { - VmmProcess_TokenTryEnsure(pt); + VmmProcess_TokenTryEnsure(H, pt); } - LeaveCriticalSection(&ctxVmm->LockMaster); + LeaveCriticalSection(&H->vmm.LockMaster); } /* * Retrieve a process for a given PID and optional PVMMOB_PROCESS_TABLE. * CALLER DECREF: return +* -- H * -- pt * -- dwPID * -- flags = 0 (recommended) or VMM_FLAG_PROCESS_TOKEN. * -- return */ -PVMM_PROCESS VmmProcessGetEx(_In_opt_ PVMMOB_PROCESS_TABLE pt, _In_ DWORD dwPID, _In_ QWORD flags) +PVMM_PROCESS VmmProcessGetEx(_In_ VMM_HANDLE H, _In_opt_ PVMMOB_PROCESS_TABLE pt, _In_ DWORD dwPID, _In_ QWORD flags) { - BOOL fToken = ((flags | ctxVmm->flags) & VMM_FLAG_PROCESS_TOKEN); + BOOL fToken = ((flags | H->vmm.flags) & VMM_FLAG_PROCESS_TOKEN); PVMM_PROCESS pObProcess, pObProcessClone; PVMMOB_PROCESS_TABLE pObTable; DWORD i, iStart; if(!pt) { - pObTable = (PVMMOB_PROCESS_TABLE)ObContainer_GetOb(ctxVmm->pObCPROC); - pObProcess = VmmProcessGetEx(pObTable, dwPID, flags); + pObTable = (PVMMOB_PROCESS_TABLE)ObContainer_GetOb(H->vmm.pObCPROC); + pObProcess = VmmProcessGetEx(H, pObTable, dwPID, flags); Ob_DECREF(pObTable); return pObProcess; } @@ -794,7 +807,7 @@ PVMM_PROCESS VmmProcessGetEx(_In_opt_ PVMMOB_PROCESS_TABLE pt, _In_ DWORD dwPID, if(!pt->_M[i]) { goto fail; } if(pt->_M[i]->dwPID == dwPID) { pObProcess = (PVMM_PROCESS)Ob_INCREF(pt->_M[i]); - if(pObProcess && fToken && !pObProcess->win.TOKEN.fInitialized) { VmmProcess_TokenTryEnsureLock(pt, pObProcess); } + if(pObProcess && fToken && !pObProcess->win.TOKEN.fInitialized) { VmmProcess_TokenTryEnsureLock(H, pt, pObProcess); } return pObProcess; } if(++i == VMM_PROCESSTABLE_ENTRIES_MAX) { i = 0; } @@ -802,8 +815,8 @@ PVMM_PROCESS VmmProcessGetEx(_In_opt_ PVMMOB_PROCESS_TABLE pt, _In_ DWORD dwPID, } fail: if(dwPID & VMM_PID_PROCESS_CLONE_WITH_KERNELMEMORY) { - if((pObProcess = VmmProcessGetEx(pt, dwPID & ~VMM_PID_PROCESS_CLONE_WITH_KERNELMEMORY, flags))) { - if((pObProcessClone = VmmProcessClone(pObProcess))) { + if((pObProcess = VmmProcessGetEx(H, pt, dwPID & ~VMM_PID_PROCESS_CLONE_WITH_KERNELMEMORY, flags))) { + if((pObProcessClone = VmmProcessClone(H, pObProcess))) { pObProcessClone->fUserOnly = FALSE; } Ob_DECREF(pObProcess); @@ -816,12 +829,13 @@ fail: /* * Retrieve a process for a given PID. * CALLER DECREF: return +* -- H * -- dwPID * -- return = a process struct, or NULL if not found. */ -inline PVMM_PROCESS VmmProcessGet(_In_ DWORD dwPID) +inline PVMM_PROCESS VmmProcessGet(_In_ VMM_HANDLE H, _In_ DWORD dwPID) { - return VmmProcessGetEx(NULL, dwPID, 0); + return VmmProcessGetEx(H, NULL, dwPID, 0); } /* @@ -831,22 +845,23 @@ inline PVMM_PROCESS VmmProcessGet(_In_ DWORD dwPID) * to it. * FUNCTION DECREF: pProcess * CALLER DECREF: return +* -- H * -- pt * -- pProcess = a process struct, or NULL if first. * NB! function DECREF's pProcess and must not be used after call! * -- flags = 0 (recommended) or VMM_FLAG_PROCESS_[TOKEN|SHOW_TERMINATED]. * -- return = a process struct, or NULL if not found. */ -PVMM_PROCESS VmmProcessGetNextEx(_In_opt_ PVMMOB_PROCESS_TABLE pt, _In_opt_ PVMM_PROCESS pProcess, _In_ QWORD flags) +PVMM_PROCESS VmmProcessGetNextEx(_In_ VMM_HANDLE H, _In_opt_ PVMMOB_PROCESS_TABLE pt, _In_opt_ PVMM_PROCESS pProcess, _In_ QWORD flags) { - BOOL fToken = ((flags | ctxVmm->flags) & VMM_FLAG_PROCESS_TOKEN); - BOOL fShowTerminated = ((flags | ctxVmm->flags) & VMM_FLAG_PROCESS_SHOW_TERMINATED); + BOOL fToken = ((flags | H->vmm.flags) & VMM_FLAG_PROCESS_TOKEN); + BOOL fShowTerminated = ((flags | H->vmm.flags) & VMM_FLAG_PROCESS_SHOW_TERMINATED); PVMM_PROCESS pProcessNew; DWORD i, iStart; if(!pt) { - pt = (PVMMOB_PROCESS_TABLE)ObContainer_GetOb(ctxVmm->pObCPROC); + pt = (PVMMOB_PROCESS_TABLE)ObContainer_GetOb(H->vmm.pObCPROC); if(!pt) { goto fail; } - pProcessNew = VmmProcessGetNextEx(pt, pProcess, flags); + pProcessNew = VmmProcessGetNextEx(H, pt, pProcess, flags); Ob_DECREF(pt); return pProcessNew; } @@ -858,7 +873,7 @@ restart: Ob_DECREF(pProcess); pProcess = pProcessNew; if(pProcess && pProcess->dwState && !fShowTerminated) { goto restart; } - if(pProcess && fToken && !pProcess->win.TOKEN.fInitialized) { VmmProcess_TokenTryEnsureLock(pt, pProcess); } + if(pProcess && fToken && !pProcess->win.TOKEN.fInitialized) { VmmProcess_TokenTryEnsureLock(H, pt, pProcess); } return pProcess; } i = iStart = pProcess->dwPID % VMM_PROCESSTABLE_ENTRIES_MAX; @@ -872,7 +887,7 @@ restart: Ob_DECREF(pProcess); pProcess = pProcessNew; if(pProcess && pProcess->dwState && !fShowTerminated) { goto restart; } - if(pProcess && fToken && !pProcess->win.TOKEN.fInitialized) { VmmProcess_TokenTryEnsureLock(pt, pProcess); } + if(pProcess && fToken && !pProcess->win.TOKEN.fInitialized) { VmmProcess_TokenTryEnsureLock(H, pt, pProcess); } return pProcess; } if(++i == VMM_PROCESSTABLE_ENTRIES_MAX) { i = 0; } @@ -889,14 +904,15 @@ fail: * previous process is terminated while having a reference to it. * FUNCTION DECREF: pProcess * CALLER DECREF: return +* -- H * -- pProcess = a process struct, or NULL if first. * NB! function DECREF's pProcess and must not be used after call! * -- flags = 0 (recommended) or VMM_FLAG_PROCESS_[TOKEN|SHOW_TERMINATED] * -- return = a process struct, or NULL if not found. */ -PVMM_PROCESS VmmProcessGetNext(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD flags) +PVMM_PROCESS VmmProcessGetNext(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ QWORD flags) { - return VmmProcessGetNextEx(NULL, pProcess, flags); + return VmmProcessGetNextEx(H, NULL, pProcess, flags); } /* @@ -922,11 +938,11 @@ VOID VmmProcessStatic_CloseObCallback(_In_ PVOID pVmmOb) * Object manager callback before 'static process' object cleanup * decrease refcount of any internal objects. */ -VOID VmmProcessStatic_Initialize(_In_ PVMM_PROCESS pProcess) +VOID VmmProcessStatic_Initialize(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess) { EnterCriticalSection(&pProcess->LockUpdate); Ob_DECREF_NULL(&pProcess->pObPersistent); - pProcess->pObPersistent = Ob_Alloc(OB_TAG_VMM_PROCESS_PERSISTENT, LMEM_ZEROINIT, sizeof(VMMOB_PROCESS_PERSISTENT), VmmProcessStatic_CloseObCallback, NULL); + pProcess->pObPersistent = Ob_AllocEx(H, OB_TAG_VMM_PROCESS_PERSISTENT, LMEM_ZEROINIT, sizeof(VMMOB_PROCESS_PERSISTENT), VmmProcessStatic_CloseObCallback, NULL); if(pProcess->pObPersistent) { pProcess->pObPersistent->pObCMapVadPrefetch = ObContainer_New(); pProcess->pObPersistent->pObCLdrModulesPrefetch32 = ObContainer_New(); @@ -1007,14 +1023,15 @@ VOID VmmProcessTable_CloseObCallback(_In_ PVOID pVmmOb) * user-mode process. * NB! USE WITH EXTREME CARE - MAY CRASH VMM IF USED MORE GENERALLY! * CALLER DECREF: return +* -- H * -- pProcess * -- return */ -PVMM_PROCESS VmmProcessClone(_In_ PVMM_PROCESS pProcess) +PVMM_PROCESS VmmProcessClone(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess) { PVMM_PROCESS pObProcessClone; if(pProcess->pObProcessCloneParent) { return NULL; } - pObProcessClone = (PVMM_PROCESS)Ob_Alloc(OB_TAG_VMM_PROCESS_CLONE, LMEM_ZEROINIT, sizeof(VMM_PROCESS), VmmProcessClone_CloseObCallback, NULL); + pObProcessClone = (PVMM_PROCESS)Ob_AllocEx(H, OB_TAG_VMM_PROCESS_CLONE, LMEM_ZEROINIT, sizeof(VMM_PROCESS), VmmProcessClone_CloseObCallback, NULL); if(!pObProcessClone) { return NULL; } memcpy((PBYTE)pObProcessClone + sizeof(OB), (PBYTE)pProcess + sizeof(OB), pProcess->ObHdr.cbData); pObProcessClone->pObProcessCloneParent = Ob_INCREF(pProcess); @@ -1029,7 +1046,9 @@ PVMM_PROCESS VmmProcessClone(_In_ PVMM_PROCESS pProcess) * Create a new process object. New process object are created in a separate * data structure and won't become visible to the "Process" functions until * after the VmmProcessCreateFinish have been called. +* NB! REQUIRE SINGLE THREAD: [H->vmm.LockMaster] * CALLER DECREF: return +* -- H * -- fTotalRefresh = create a completely new entry - i.e. do not copy any form * of data from the old entry such as module and memory maps. * -- dwPID @@ -1043,7 +1062,7 @@ PVMM_PROCESS VmmProcessClone(_In_ PVMM_PROCESS pProcess) * -- cbEPROCESS * -- return */ -PVMM_PROCESS VmmProcessCreateEntry(_In_ BOOL fTotalRefresh, _In_ DWORD dwPID, _In_ DWORD dwPPID, _In_ DWORD dwState, _In_ QWORD paDTB, _In_ QWORD paDTB_UserOpt, _In_ CHAR szName[16], _In_ BOOL fUserOnly, _In_reads_opt_(cbEPROCESS) PBYTE pbEPROCESS, _In_ DWORD cbEPROCESS) +PVMM_PROCESS VmmProcessCreateEntry(_In_ VMM_HANDLE H, _In_ BOOL fTotalRefresh, _In_ DWORD dwPID, _In_ DWORD dwPPID, _In_ DWORD dwState, _In_ QWORD paDTB, _In_ QWORD paDTB_UserOpt, _In_ CHAR szName[16], _In_ BOOL fUserOnly, _In_reads_opt_(cbEPROCESS) PBYTE pbEPROCESS, _In_ DWORD cbEPROCESS) { PVMMOB_PROCESS_TABLE ptOld = NULL, ptNew = NULL; QWORD i, iStart, cEmpty = 0, cValid = 0; @@ -1052,31 +1071,31 @@ PVMM_PROCESS VmmProcessCreateEntry(_In_ BOOL fTotalRefresh, _In_ DWORD dwPID, _I BOOL result; // 1: Sanity check DTB if(dwState == 0) { - pObDTB = VmmTlbGetPageTable(paDTB & ~0xfff, FALSE); + pObDTB = VmmTlbGetPageTable(H, paDTB & ~0xfff, FALSE); if(!pObDTB) { goto fail; } - result = VmmTlbPageTableVerify(pObDTB->h.pb, paDTB, (ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X64)); + result = VmmTlbPageTableVerify(H, pObDTB->h.pb, paDTB, (H->vmm.tpSystem == VMM_SYSTEM_WINDOWS_X64)); Ob_DECREF(pObDTB); if(!result) { goto fail; } } // 2: Allocate new 'Process Table' (if not already existing) - ptOld = (PVMMOB_PROCESS_TABLE)ObContainer_GetOb(ctxVmm->pObCPROC); + ptOld = (PVMMOB_PROCESS_TABLE)ObContainer_GetOb(H->vmm.pObCPROC); if(!ptOld) { goto fail; } ptNew = (PVMMOB_PROCESS_TABLE)ObContainer_GetOb(ptOld->pObCNewPROC); if(!ptNew) { - ptNew = (PVMMOB_PROCESS_TABLE)Ob_Alloc(OB_TAG_VMM_PROCESSTABLE, LMEM_ZEROINIT, sizeof(VMMOB_PROCESS_TABLE), VmmProcessTable_CloseObCallback, NULL); + ptNew = (PVMMOB_PROCESS_TABLE)Ob_AllocEx(H, OB_TAG_VMM_PROCESSTABLE, LMEM_ZEROINIT, sizeof(VMMOB_PROCESS_TABLE), VmmProcessTable_CloseObCallback, NULL); if(!ptNew) { goto fail; } ptNew->pObCNewPROC = ObContainer_New(); ObContainer_SetOb(ptOld->pObCNewPROC, ptNew); } // 3: Sanity check - process to create not already in 'new' table. - pProcess = VmmProcessGetEx(ptNew, dwPID, 0); + pProcess = VmmProcessGetEx(H, ptNew, dwPID, 0); if(pProcess) { goto fail; } // 4: Prepare existing item, or create new item, for new PID if(!fTotalRefresh) { - pProcess = VmmProcessGetEx(ptOld, dwPID, 0); + pProcess = VmmProcessGetEx(H, ptOld, dwPID, 0); } if(!pProcess) { - pProcess = (PVMM_PROCESS)Ob_Alloc(OB_TAG_VMM_PROCESS, LMEM_ZEROINIT, sizeof(VMM_PROCESS), VmmProcess_CloseObCallback, NULL); + pProcess = (PVMM_PROCESS)Ob_AllocEx(H, OB_TAG_VMM_PROCESS, LMEM_ZEROINIT, sizeof(VMM_PROCESS), VmmProcess_CloseObCallback, NULL); if(!pProcess) { goto fail; } if(!InitializeCriticalSectionAndSpinCount(&pProcess->LockUpdate, 4096)) { goto fail; } InitializeCriticalSection(&pProcess->LockPlugin); @@ -1099,11 +1118,11 @@ PVMM_PROCESS VmmProcessCreateEntry(_In_ BOOL fTotalRefresh, _In_ DWORD dwPID, _I memcpy(pProcess->win.EPROCESS.pb, pbEPROCESS, pProcess->win.EPROCESS.cb); } // attach pre-existing static process info entry or create new - pProcessOld = VmmProcessGet(dwPID); + pProcessOld = VmmProcessGet(H, dwPID); if(pProcessOld) { pProcess->pObPersistent = (PVMMOB_PROCESS_PERSISTENT)Ob_INCREF(pProcessOld->pObPersistent); } else { - VmmProcessStatic_Initialize(pProcess); + VmmProcessStatic_Initialize(H, pProcess); } Ob_DECREF(pProcessOld); pProcessOld = NULL; @@ -1135,11 +1154,12 @@ fail: /* * Activate the pending, not yet active, processes added by VmmProcessCreateEntry. * This will also clear any previous processes. +* -- H */ -VOID VmmProcessCreateFinish() +VOID VmmProcessCreateFinish(_In_ VMM_HANDLE H) { PVMMOB_PROCESS_TABLE ptNew, ptOld; - if(!(ptOld = ObContainer_GetOb(ctxVmm->pObCPROC))) { + if(!(ptOld = ObContainer_GetOb(H->vmm.pObCPROC))) { return; } if(!(ptNew = ObContainer_GetOb(ptOld->pObCNewPROC))) { @@ -1147,17 +1167,18 @@ VOID VmmProcessCreateFinish() return; } // Replace "existing" old process table with new. - ObContainer_SetOb(ctxVmm->pObCPROC, ptNew); + ObContainer_SetOb(H->vmm.pObCPROC, ptNew); Ob_DECREF(ptNew); Ob_DECREF(ptOld); } /* * Clear the TLB spider flag in all process objects. +* -- H */ -VOID VmmProcessTlbClear() +VOID VmmProcessTlbClear(_In_ VMM_HANDLE H) { - PVMMOB_PROCESS_TABLE pt = (PVMMOB_PROCESS_TABLE)ObContainer_GetOb(ctxVmm->pObCPROC); + PVMMOB_PROCESS_TABLE pt = (PVMMOB_PROCESS_TABLE)ObContainer_GetOb(H->vmm.pObCPROC); PVMM_PROCESS pProcess; WORD iProcess; if(!pt) { return; } @@ -1174,34 +1195,37 @@ VOID VmmProcessTlbClear() /* * Query process for its creation time. +* -- H * -- pProcess * -- return = time as FILETIME or 0 on error. */ -QWORD VmmProcess_GetCreateTimeOpt(_In_opt_ PVMM_PROCESS pProcess) +QWORD VmmProcess_GetCreateTimeOpt(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess) { - return (pProcess && ctxVmm->offset.EPROCESS.opt.CreateTime) ? *(PQWORD)(pProcess->win.EPROCESS.pb + ctxVmm->offset.EPROCESS.opt.CreateTime) : 0; + return (pProcess && H->vmm.offset.EPROCESS.opt.CreateTime) ? *(PQWORD)(pProcess->win.EPROCESS.pb + H->vmm.offset.EPROCESS.opt.CreateTime) : 0; } /* * Query process for its exit time. +* -- H * -- pProcess * -- return = time as FILETIME or 0 on error. */ -QWORD VmmProcess_GetExitTimeOpt(_In_opt_ PVMM_PROCESS pProcess) +QWORD VmmProcess_GetExitTimeOpt(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess) { - return (pProcess && ctxVmm->offset.EPROCESS.opt.ExitTime) ? *(PQWORD)(pProcess->win.EPROCESS.pb + ctxVmm->offset.EPROCESS.opt.ExitTime) : 0; + return (pProcess && H->vmm.offset.EPROCESS.opt.ExitTime) ? *(PQWORD)(pProcess->win.EPROCESS.pb + H->vmm.offset.EPROCESS.opt.ExitTime) : 0; } /* * List the PIDs and put them into the supplied table. +* -- H * -- pPIDs = user allocated DWORD array to receive result, or NULL. * -- pcPIDs = ptr to number of DWORDs in pPIDs on entry - number of PIDs in system on exit. -* -- flags = 0 (recommended) or VMM_FLAG_PROCESS_SHOW_TERMINATED (_only_ if default setting in ctxVmm->flags should be overridden) +* -- flags = 0 (recommended) or VMM_FLAG_PROCESS_SHOW_TERMINATED (_only_ if default setting in H->vmm.flags should be overridden) */ -VOID VmmProcessListPIDs(_Out_writes_opt_(*pcPIDs) PDWORD pPIDs, _Inout_ PSIZE_T pcPIDs, _In_ QWORD flags) +VOID VmmProcessListPIDs(_In_ VMM_HANDLE H, _Out_writes_opt_(*pcPIDs) PDWORD pPIDs, _Inout_ PSIZE_T pcPIDs, _In_ QWORD flags) { - PVMMOB_PROCESS_TABLE pt = (PVMMOB_PROCESS_TABLE)ObContainer_GetOb(ctxVmm->pObCPROC); - BOOL fShowTerminated = ((flags | ctxVmm->flags) & VMM_FLAG_PROCESS_SHOW_TERMINATED); + PVMMOB_PROCESS_TABLE pt = (PVMMOB_PROCESS_TABLE)ObContainer_GetOb(H->vmm.pObCPROC); + BOOL fShowTerminated = ((flags | H->vmm.flags) & VMM_FLAG_PROCESS_SHOW_TERMINATED); PVMM_PROCESS pProcess; WORD iProcess; DWORD i = 0; @@ -1233,232 +1257,47 @@ VOID VmmProcessListPIDs(_Out_writes_opt_(*pcPIDs) PDWORD pPIDs, _Inout_ PSIZE_T /* * Create the initial process table at startup. +* -- H */ -BOOL VmmProcessTableCreateInitial() +BOOL VmmProcessTableCreateInitial(_In_ VMM_HANDLE H) { - PVMMOB_PROCESS_TABLE pt = (PVMMOB_PROCESS_TABLE)Ob_Alloc(OB_TAG_VMM_PROCESSTABLE, LMEM_ZEROINIT, sizeof(VMMOB_PROCESS_TABLE), VmmProcessTable_CloseObCallback, NULL); + PVMMOB_PROCESS_TABLE pt = (PVMMOB_PROCESS_TABLE)Ob_AllocEx(H, OB_TAG_VMM_PROCESSTABLE, LMEM_ZEROINIT, sizeof(VMMOB_PROCESS_TABLE), VmmProcessTable_CloseObCallback, NULL); if(!pt) { return FALSE; } pt->pObCNewPROC = ObContainer_New(); - ctxVmm->pObCPROC = ObContainer_New(); - ObContainer_SetOb(ctxVmm->pObCPROC, pt); + H->vmm.pObCPROC = ObContainer_New(); + ObContainer_SetOb(H->vmm.pObCPROC, pt); Ob_DECREF(pt); return TRUE; } -// ---------------------------------------------------------------------------- -// WORK (THREAD POOL) API: -// The 'Work' thread pool contain by default 32 threads which is waiting to -// receive work scheduled by calling the VmmWork function. -// ---------------------------------------------------------------------------- -typedef struct tdVMMWORK_UNIT { - LPTHREAD_START_ROUTINE pfn; // function to call - PVOID ctx; // optional function parameter - HANDLE hEventFinish; // optional event to set when upon work completion -} VMMWORK_UNIT, *PVMMWORK_UNIT; - -typedef struct tdVMMWORK_THREAD_CONTEXT { - HANDLE hEventWakeup; - HANDLE hThread; -} VMMWORK_THREAD_CONTEXT, *PVMMWORK_THREAD_CONTEXT; - -DWORD VmmWork_MainWorkerLoop_ThreadProc(PVMMWORK_THREAD_CONTEXT ctx) -{ - PVMMWORK_UNIT pu; - while(ctxVmm->Work.fEnabled) { - if((pu = (PVMMWORK_UNIT)ObSet_Pop(ctxVmm->Work.psUnit))) { - ((DWORD(*)(LPVOID))pu->pfn)(pu->ctx); - if(pu->hEventFinish) { - SetEvent(pu->hEventFinish); - } - LocalFree(pu); - } else { - ResetEvent(ctx->hEventWakeup); - ObSet_Push(ctxVmm->Work.psThreadAvail, (QWORD)ctx); - WaitForSingleObject(ctx->hEventWakeup, INFINITE); - } - } - ObSet_Remove(ctxVmm->Work.psThreadAll, (QWORD)ctx); - CloseHandle(ctx->hEventWakeup); - CloseHandle(ctx->hThread); - LocalFree(ctx); - return 1; -} - -VOID VmmWork_Initialize() -{ - PVMMWORK_THREAD_CONTEXT p; - ctxVmm->Work.fEnabled = TRUE; - ctxVmm->Work.psUnit = ObSet_New(); - ctxVmm->Work.psThreadAll = ObSet_New(); - ctxVmm->Work.psThreadAvail = ObSet_New(); - while(ObSet_Size(ctxVmm->Work.psThreadAll) < VMM_WORK_THREADPOOL_NUM_THREADS) { - if((p = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMWORK_THREAD_CONTEXT)))) { - p->hEventWakeup = CreateEvent(NULL, TRUE, FALSE, NULL); - p->hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)VmmWork_MainWorkerLoop_ThreadProc, p, 0, NULL); - ObSet_Push(ctxVmm->Work.psThreadAll, (QWORD)p); - } - } -} - -VOID VmmWork_Close() -{ - PVMMWORK_UNIT pu; - PVMMWORK_THREAD_CONTEXT pt = NULL; - ctxVmm->Work.fEnabled = FALSE; - while(ObSet_Size(ctxVmm->Work.psThreadAll)) { - while((pt = (PVMMWORK_THREAD_CONTEXT)ObSet_GetNext(ctxVmm->Work.psThreadAll, (QWORD)pt))) { - SetEvent(pt->hEventWakeup); - } - SwitchToThread(); - } - while((pu = (PVMMWORK_UNIT)ObSet_Pop(ctxVmm->Work.psUnit))) { - if(pu->hEventFinish) { - SetEvent(pu->hEventFinish); - } - LocalFree(pu); - } - Ob_DECREF_NULL(&ctxVmm->Work.psUnit); - Ob_DECREF_NULL(&ctxVmm->Work.psThreadAll); - Ob_DECREF_NULL(&ctxVmm->Work.psThreadAvail); -} - -VOID VmmWork(_In_ LPTHREAD_START_ROUTINE pfn, _In_opt_ PVOID ctx, _In_opt_ HANDLE hEventFinish) -{ - PVMMWORK_UNIT pu; - PVMMWORK_THREAD_CONTEXT pt; - if((pu = LocalAlloc(0, sizeof(VMMWORK_UNIT)))) { - pu->pfn = pfn; - pu->ctx = ctx; - pu->hEventFinish = hEventFinish; - ObSet_Push(ctxVmm->Work.psUnit, (QWORD)pu); - if((pt = (PVMMWORK_THREAD_CONTEXT)ObSet_Pop(ctxVmm->Work.psThreadAvail))) { - SetEvent(pt->hEventWakeup); - } - } -} - -VOID VmmWorkWaitMultiple(_In_opt_ PVOID ctx, _In_ DWORD cWork, ...) -{ - DWORD i; - va_list arguments; - HANDLE hEventFinish[MAXIMUM_WAIT_OBJECTS] = { 0 }; - if(cWork > MAXIMUM_WAIT_OBJECTS) { return; } - va_start(arguments, cWork); - for(i = 0; i < cWork; i++) { - hEventFinish[i] = CreateEvent(NULL, TRUE, FALSE, NULL); - VmmWork(va_arg(arguments, LPTHREAD_START_ROUTINE), ctx, hEventFinish[i]); - } - va_end(arguments); - WaitForMultipleObjects(cWork, hEventFinish, TRUE, INFINITE); - for(i = 0; i < cWork; i++) { - if(hEventFinish[i]) { - CloseHandle(hEventFinish[i]); - } - } -} - -// ---------------------------------------------------------------------------- -// PROCESS PARALLELIZATION FUNCTIONALITY: -// ---------------------------------------------------------------------------- - -typedef struct tdVMM_PROCESS_ACTION_FOREACH { - HANDLE hEventFinish; - VOID(*pfnAction)(_In_ PVMM_PROCESS pProcess, _In_ PVOID ctx); - PVOID ctxAction; - DWORD cRemainingWork; // set to dwPIDs count on entry and decremented as-goes - when zero FinishEvent is set. - DWORD iPID; // set to dwPIDs count on entry and decremented as-goes - DWORD dwPIDs[]; -} VMM_PROCESS_ACTION_FOREACH, *PVMM_PROCESS_ACTION_FOREACH; - -DWORD VmmProcessActionForeachParallel_ThreadProc(PVMM_PROCESS_ACTION_FOREACH ctx) -{ - PVMM_PROCESS pObProcess = VmmProcessGet(ctx->dwPIDs[InterlockedDecrement(&ctx->iPID)]); - if(pObProcess) { - ctx->pfnAction(pObProcess, ctx->ctxAction); - Ob_DECREF(pObProcess); - } - if(0 == InterlockedDecrement(&ctx->cRemainingWork)) { - SetEvent(ctx->hEventFinish); - } - return 1; -} - -BOOL VmmProcessActionForeachParallel_CriteriaActiveOnly(_In_ PVMM_PROCESS pProcess, _In_opt_ PVOID ctx) -{ - return pProcess->dwState == 0; -} - -BOOL VmmProcessActionForeachParallel_CriteriaActiveUserOnly(_In_ PVMM_PROCESS pProcess, _In_opt_ PVOID ctx) -{ - return (pProcess->dwState == 0) && pProcess->fUserOnly; -} - -VOID VmmProcessActionForeachParallel(_In_opt_ PVOID ctxAction, _In_opt_ BOOL(*pfnCriteria)(_In_ PVMM_PROCESS pProcess, _In_opt_ PVOID ctx), _In_ VOID(*pfnAction)(_In_ PVMM_PROCESS pProcess, _In_opt_ PVOID ctx)) -{ - DWORD i, cProcess; - PVMM_PROCESS pObProcess = NULL; - POB_SET pObProcessSelectedSet = NULL; - PVMM_PROCESS_ACTION_FOREACH ctx = NULL; - // 1: select processes to queue using criteria function - if(!(pObProcessSelectedSet = ObSet_New())) { goto fail; } - while((pObProcess = VmmProcessGetNext(pObProcess, VMM_FLAG_PROCESS_SHOW_TERMINATED))) { - if(!pfnCriteria || pfnCriteria(pObProcess, ctx)) { - ObSet_Push(pObProcessSelectedSet, pObProcess->dwPID); - } - } - if(!(cProcess = ObSet_Size(pObProcessSelectedSet))) { goto fail; } - // 2: set up context for worker function - if(!(ctx = LocalAlloc(LMEM_ZEROINIT, sizeof(VMM_PROCESS_ACTION_FOREACH) + cProcess * sizeof(DWORD)))) { goto fail; } - if(!(ctx->hEventFinish = CreateEvent(NULL, TRUE, FALSE, NULL))) { goto fail; } - ctx->pfnAction = pfnAction; - ctx->ctxAction = ctxAction; - ctx->cRemainingWork = cProcess; - ctx->iPID = cProcess; - for(i = 0; i < cProcess; i++) { - ctx->dwPIDs[i] = (DWORD)ObSet_Pop(pObProcessSelectedSet); - } - // 3: parallelize onto worker threads and wait for completion - for(i = 0; i < cProcess; i++) { - VmmWork((PTHREAD_START_ROUTINE)VmmProcessActionForeachParallel_ThreadProc, ctx, NULL); - } - WaitForSingleObject(ctx->hEventFinish, INFINITE); -fail: - Ob_DECREF(pObProcessSelectedSet); - if(ctx) { - if(ctx->hEventFinish) { - CloseHandle(ctx->hEventFinish); - } - LocalFree(ctx); - } -} // ---------------------------------------------------------------------------- // INTERNAL VMMU FUNCTIONALITY: VIRTUAL MEMORY ACCESS. // ---------------------------------------------------------------------------- -VOID VmmWriteScatterPhysical(_Inout_ PPMEM_SCATTER ppMEMsPhys, _In_ DWORD cpMEMsPhys) +VOID VmmWriteScatterPhysical(_In_ VMM_HANDLE H, _Inout_ PPMEM_SCATTER ppMEMsPhys, _In_ DWORD cpMEMsPhys) { DWORD i; PMEM_SCATTER pMEM; - LcWriteScatter(ctxMain->hLC, cpMEMsPhys, ppMEMsPhys); + LcWriteScatter(H->hLC, cpMEMsPhys, ppMEMsPhys); for(i = 0; i < cpMEMsPhys; i++) { pMEM = ppMEMsPhys[i]; - InterlockedIncrement64(&ctxVmm->stat.cPhysWrite); + InterlockedIncrement64(&H->vmm.stat.cPhysWrite); if(pMEM->f && MEM_SCATTER_ADDR_ISVALID(pMEM)) { - VmmCacheInvalidate(pMEM->qwA & ~0xfff); + VmmCacheInvalidate(H, pMEM->qwA & ~0xfff); } } } -VOID VmmWriteScatterVirtual(_In_ PVMM_PROCESS pProcess, _Inout_ PPMEM_SCATTER ppMEMsVirt, _In_ DWORD cpMEMsVirt) +VOID VmmWriteScatterVirtual(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Inout_ PPMEM_SCATTER ppMEMsVirt, _In_ DWORD cpMEMsVirt) { DWORD i; QWORD qwPA_PTE = 0, qwPagedPA = 0; PMEM_SCATTER pMEM; BOOL fProcessMagicHandle = ((SIZE_T)pProcess >= PROCESS_MAGIC_HANDLE_THRESHOLD); // 0: 'magic' process handle - if(fProcessMagicHandle && !(pProcess = VmmProcessGet((DWORD)(0-(SIZE_T)pProcess)))) { return; } + if(fProcessMagicHandle && !(pProcess = VmmProcessGet(H, (DWORD)(0-(SIZE_T)pProcess)))) { return; } // 1: virt2phys translation for(i = 0; i < cpMEMsVirt; i++) { pMEM = ppMEMsVirt[i]; @@ -1467,36 +1306,38 @@ VOID VmmWriteScatterVirtual(_In_ PVMM_PROCESS pProcess, _Inout_ PPMEM_SCATTER pp pMEM->qwA = (QWORD)-1; continue; } - if(VmmVirt2Phys(pProcess, pMEM->qwA, &qwPA_PTE)) { + if(VmmVirt2Phys(H, pProcess, pMEM->qwA, &qwPA_PTE)) { pMEM->qwA = qwPA_PTE; continue; } // paged "read" also translate virtual -> physical for some // types of paged memory such as transition and prototype. - ctxVmm->fnMemoryModel.pfnPagedRead(pProcess, pMEM->qwA, qwPA_PTE, NULL, &qwPagedPA, NULL, 0); + H->vmm.fnMemoryModel.pfnPagedRead(H, pProcess, pMEM->qwA, qwPA_PTE, NULL, &qwPagedPA, NULL, 0); pMEM->qwA = qwPagedPA ? qwPagedPA : (QWORD)-1; } // write to physical addresses - VmmWriteScatterPhysical(ppMEMsVirt, cpMEMsVirt); + VmmWriteScatterPhysical(H, ppMEMsVirt, cpMEMsVirt); for(i = 0; i < cpMEMsVirt; i++) { ppMEMsVirt[i]->qwA = MEM_SCATTER_STACK_POP(ppMEMsVirt[i]); } if(fProcessMagicHandle) { Ob_DECREF(pProcess); } } -VOID VmmReadScatterPhysical(_Inout_ PPMEM_SCATTER ppMEMsPhys, _In_ DWORD cpMEMsPhys, _In_ QWORD flags) +#define VMM_READ_PHYSICAL_SPECULATIVE_PAGES 8 + +VOID VmmReadScatterPhysical(_In_ VMM_HANDLE H, _Inout_ PPMEM_SCATTER ppMEMsPhys, _In_ DWORD cpMEMsPhys, _In_ QWORD flags) { QWORD tp; // 0 = normal, 1 = already read, 2 = cache hit, 3 = speculative read BOOL fCache, fCacheRecent, fCachePut, fCacheForce; PMEM_SCATTER pMEM; DWORD i, c, cSpeculative; PVMMOB_CACHE_MEM pObCacheEntry, pObReservedMEM; - PMEM_SCATTER ppMEMsSpeculative[0x18]; - PVMMOB_CACHE_MEM ppObCacheSpeculative[0x18]; - fCache = !(VMM_FLAG_NOCACHE & (flags | ctxVmm->flags)); + PMEM_SCATTER ppMEMsSpeculative[VMM_READ_PHYSICAL_SPECULATIVE_PAGES]; + PVMMOB_CACHE_MEM ppObCacheSpeculative[VMM_READ_PHYSICAL_SPECULATIVE_PAGES]; + fCache = !(VMM_FLAG_NOCACHE & (flags | H->vmm.flags)); fCacheRecent = fCache && (VMM_FLAG_CACHE_RECENT_ONLY & flags); fCachePut = !(VMM_FLAG_NOCACHEPUT & flags); - fCacheForce = (VMM_FLAG_FORCECACHE_READ & flags) && !(VMM_FLAG_FORCECACHE_READ_DISABLE & (flags | ctxVmm->flags)); + fCacheForce = (VMM_FLAG_FORCECACHE_READ & flags) && !(VMM_FLAG_FORCECACHE_READ_DISABLE & (flags | H->vmm.flags)); // 1: cache read if(fCache) { c = 0, cSpeculative = 0; @@ -1509,19 +1350,19 @@ VOID VmmReadScatterPhysical(_Inout_ PPMEM_SCATTER ppMEMsPhys, _In_ DWORD cpMEMsP continue; } // retrieve from cache (if found) - if((pMEM->cb == 0x1000) && (pObCacheEntry = VmmCacheGetEx(VMM_CACHE_TAG_PHYS, pMEM->qwA, fCacheRecent))) { + if((pMEM->cb == 0x1000) && (pObCacheEntry = VmmCacheGetEx(H, VMM_CACHE_TAG_PHYS, pMEM->qwA, fCacheRecent))) { // in cache - copy data into requester and set as completed! MEM_SCATTER_STACK_PUSH(pMEM, 2); // 2: cache read pMEM->f = TRUE; memcpy(pMEM->pb, pObCacheEntry->pb, 0x1000); Ob_DECREF(pObCacheEntry); - InterlockedIncrement64(&ctxVmm->stat.cPhysCacheHit); + InterlockedIncrement64(&H->vmm.stat.cPhysCacheHit); c++; continue; } MEM_SCATTER_STACK_PUSH(pMEM, 1); // 1: normal read // add to potential speculative read map if read is small enough... - if(cSpeculative < 0x18) { + if(cSpeculative < VMM_READ_PHYSICAL_SPECULATIVE_PAGES) { ppMEMsSpeculative[cSpeculative++] = pMEM; } } @@ -1534,15 +1375,15 @@ VOID VmmReadScatterPhysical(_Inout_ PPMEM_SCATTER ppMEMsPhys, _In_ DWORD cpMEMsP } } // 2: speculative future read if negligible performance loss - if(fCache && fCachePut && cSpeculative && (cSpeculative < 0x18) && !(flags & VMMDLL_FLAG_NO_PREDICTIVE_READ)) { + if(fCache && fCachePut && cSpeculative && (cSpeculative < VMM_READ_PHYSICAL_SPECULATIVE_PAGES) && !(flags & VMMDLL_FLAG_NO_PREDICTIVE_READ)) { for(i = 0; i < cpMEMsPhys; i++) { pMEM = ppMEMsPhys[i]; if(1 != MEM_SCATTER_STACK_PEEK(pMEM, 1)) { MEM_SCATTER_STACK_POP(pMEM); } } - while(cSpeculative < 0x18) { - if((ppObCacheSpeculative[cSpeculative] = VmmCacheReserve(VMM_CACHE_TAG_PHYS))) { + while(cSpeculative < VMM_READ_PHYSICAL_SPECULATIVE_PAGES) { + if((ppObCacheSpeculative[cSpeculative] = VmmCacheReserve(H, VMM_CACHE_TAG_PHYS))) { pMEM = ppMEMsSpeculative[cSpeculative] = &ppObCacheSpeculative[cSpeculative]->h; MEM_SCATTER_STACK_PUSH(pMEM, 4); pMEM->f = FALSE; @@ -1554,7 +1395,7 @@ VOID VmmReadScatterPhysical(_Inout_ PPMEM_SCATTER ppMEMsPhys, _In_ DWORD cpMEMsP cpMEMsPhys = cSpeculative; } // 3: read! - LcReadScatter(ctxMain->hLC, cpMEMsPhys, ppMEMsPhys); + LcReadScatter(H->hLC, cpMEMsPhys, ppMEMsPhys); // 4: cache put if(fCache) { for(i = 0; i < cpMEMsPhys; i++) { @@ -1562,14 +1403,14 @@ VOID VmmReadScatterPhysical(_Inout_ PPMEM_SCATTER ppMEMsPhys, _In_ DWORD cpMEMsP tp = MEM_SCATTER_STACK_POP(pMEM); if(fCachePut) { if(tp == 4) { // 4 == speculative & backed by cache reserved - VmmCacheReserveReturn(ppObCacheSpeculative[i]); + VmmCacheReserveReturn(H, ppObCacheSpeculative[i]); } if((tp == 1) && pMEM->f) { // 1 = normal read - if((pObReservedMEM = VmmCacheReserve(VMM_CACHE_TAG_PHYS))) { + if((pObReservedMEM = VmmCacheReserve(H, VMM_CACHE_TAG_PHYS))) { pObReservedMEM->h.f = TRUE; pObReservedMEM->h.qwA = pMEM->qwA; memcpy(pObReservedMEM->h.pb, pMEM->pb, 0x1000); - VmmCacheReserveReturn(pObReservedMEM); + VmmCacheReserveReturn(H, pObReservedMEM); } } } @@ -1580,11 +1421,11 @@ VOID VmmReadScatterPhysical(_Inout_ PPMEM_SCATTER ppMEMsPhys, _In_ DWORD cpMEMsP pMEM = ppMEMsPhys[i]; if(pMEM->f) { // success - InterlockedIncrement64(&ctxVmm->stat.cPhysReadSuccess); + InterlockedIncrement64(&H->vmm.stat.cPhysReadSuccess); } else { // fail - InterlockedIncrement64(&ctxVmm->stat.cPhysReadFail); - if((flags & VMM_FLAG_ZEROPAD_ON_FAIL) && (pMEM->qwA < ctxMain->dev.paMax)) { + InterlockedIncrement64(&H->vmm.stat.cPhysReadFail); + if((flags & VMM_FLAG_ZEROPAD_ON_FAIL) && (pMEM->qwA < H->dev.paMax)) { ZeroMemory(pMEM->pb, pMEM->cb); pMEM->f = TRUE; } @@ -1592,7 +1433,7 @@ VOID VmmReadScatterPhysical(_Inout_ PPMEM_SCATTER ppMEMsPhys, _In_ DWORD cpMEMsP } } -VOID VmmReadScatterVirtual(_In_ PVMM_PROCESS pProcess, _Inout_updates_(cpMEMsVirt) PPMEM_SCATTER ppMEMsVirt, _In_ DWORD cpMEMsVirt, _In_ QWORD flags) +VOID VmmReadScatterVirtual(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Inout_updates_(cpMEMsVirt) PPMEM_SCATTER ppMEMsVirt, _In_ DWORD cpMEMsVirt, _In_ QWORD flags) { // NB! the buffers pIoPA / ppMEMsPhys are used for both: // - physical memory (grows from 0 upwards) @@ -1604,12 +1445,12 @@ VOID VmmReadScatterVirtual(_In_ PVMM_PROCESS pProcess, _Inout_updates_(cpMEMsVir PBYTE pbBufferMEMs, pbBufferLarge = NULL; PMEM_SCATTER pIoPA, pIoVA; PPMEM_SCATTER ppMEMsPhys = NULL; - BOOL fPaging = !(VMM_FLAG_NOPAGING & (flags | ctxVmm->flags)); + BOOL fPaging = !(VMM_FLAG_NOPAGING & (flags | H->vmm.flags)); BOOL fAltAddrPte = VMM_FLAG_ALTADDR_VA_PTE & flags; - BOOL fZeropadOnFail = VMM_FLAG_ZEROPAD_ON_FAIL & (flags | ctxVmm->flags); + BOOL fZeropadOnFail = VMM_FLAG_ZEROPAD_ON_FAIL & (flags | H->vmm.flags); BOOL fProcessMagicHandle = ((SIZE_T)pProcess >= PROCESS_MAGIC_HANDLE_THRESHOLD); // 0: 'magic' process handle - if(fProcessMagicHandle && !(pProcess = VmmProcessGet((DWORD)(0-(SIZE_T)pProcess)))) { return; } + if(fProcessMagicHandle && !(pProcess = VmmProcessGet(H, (DWORD)(0-(SIZE_T)pProcess)))) { return; } // 1: allocate / set up buffers (if needed) if(cpMEMsVirt < 0x20) { ZeroMemory(pbBufferSmall, sizeof(pbBufferSmall)); @@ -1635,10 +1476,10 @@ VOID VmmReadScatterVirtual(_In_ PVMM_PROCESS pProcess, _Inout_updates_(cpMEMsVir } // PHYSICAL MEMORY qwPA = 0; - fVirt2Phys = !fAltAddrPte && VmmVirt2Phys(pProcess, pIoVA->qwA, &qwPA); + fVirt2Phys = !fAltAddrPte && VmmVirt2Phys(H, pProcess, pIoVA->qwA, &qwPA); // PAGED MEMORY - if(!fVirt2Phys && fPaging && (pIoVA->cb == 0x1000) && ctxVmm->fnMemoryModel.pfnPagedRead) { - if(ctxVmm->fnMemoryModel.pfnPagedRead(pProcess, (fAltAddrPte ? 0 : pIoVA->qwA), (fAltAddrPte ? pIoVA->qwA : qwPA), pIoVA->pb, &qwPagedPA, NULL, flags)) { + if(!fVirt2Phys && fPaging && (pIoVA->cb == 0x1000) && H->vmm.fnMemoryModel.pfnPagedRead) { + if(H->vmm.fnMemoryModel.pfnPagedRead(H, pProcess, (fAltAddrPte ? 0 : pIoVA->qwA), (fAltAddrPte ? pIoVA->qwA : qwPA), pIoVA->pb, &qwPagedPA, NULL, flags)) { pIoVA->f = TRUE; continue; } @@ -1665,7 +1506,7 @@ VOID VmmReadScatterVirtual(_In_ PVMM_PROCESS pProcess, _Inout_updates_(cpMEMsVir } // 3: read and check result if(iPA) { - VmmReadScatterPhysical(ppMEMsPhys, iPA, flags); + VmmReadScatterPhysical(H, ppMEMsPhys, iPA, flags); while(iPA > 0) { iPA--; ((PMEM_SCATTER)MEM_SCATTER_STACK_POP(ppMEMsPhys[iPA]))->f = ppMEMsPhys[iPA]->f; @@ -1682,10 +1523,10 @@ VOID VmmReadScatterVirtual(_In_ PVMM_PROCESS pProcess, _Inout_updates_(cpMEMsVir * -- pProcess * -- pVirt2PhysInfo */ -VOID VmmVirt2PhysGetInformation(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo) +VOID VmmVirt2PhysGetInformation(_In_ VMM_HANDLE H, _Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo) { - if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_NA) { return; } - ctxVmm->fnMemoryModel.pfnVirt2PhysGetInformation(pProcess, pVirt2PhysInfo); + if(H->vmm.tpMemoryModel == VMM_MEMORYMODEL_NA) { return; } + H->vmm.fnMemoryModel.pfnVirt2PhysGetInformation(H, pProcess, pVirt2PhysInfo); } /* @@ -1696,12 +1537,13 @@ VOID VmmVirt2PhysGetInformation(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT * a previously stored address will be used. * It's not possible to use this function to retrieve multiple targeted * addresses in parallell. -* -- CALLER DECREF: return +* CALLER DECREF: return +* -- H * -- pProcess * -- paTarget = targeted physical address (or 0 if use previously saved). * -- return */ -PVMMOB_PHYS2VIRT_INFORMATION VmmPhys2VirtGetInformation(_In_ PVMM_PROCESS pProcess, _In_ QWORD paTarget) +PVMMOB_PHYS2VIRT_INFORMATION VmmPhys2VirtGetInformation(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD paTarget) { PVMMOB_PHYS2VIRT_INFORMATION pObP2V = NULL; if(paTarget) { @@ -1716,11 +1558,11 @@ PVMMOB_PHYS2VIRT_INFORMATION VmmPhys2VirtGetInformation(_In_ PVMM_PROCESS pProce pObP2V = ObContainer_GetOb(pProcess->Plugin.pObCPhys2Virt); if(paTarget && (!pObP2V || (pObP2V->paTarget != paTarget))) { Ob_DECREF_NULL(&pObP2V); - pObP2V = Ob_Alloc('PAVA', LMEM_ZEROINIT, sizeof(VMMOB_PHYS2VIRT_INFORMATION), NULL, NULL); + pObP2V = Ob_AllocEx(H, OB_TAG_VMM_VIRT2PHYS, LMEM_ZEROINIT, sizeof(VMMOB_PHYS2VIRT_INFORMATION), NULL, NULL); pObP2V->paTarget = paTarget; pObP2V->dwPID = pProcess->dwPID; - if(ctxVmm->fnMemoryModel.pfnPhys2VirtGetInformation) { - ctxVmm->fnMemoryModel.pfnPhys2VirtGetInformation(pProcess, pObP2V); + if(H->vmm.fnMemoryModel.pfnPhys2VirtGetInformation) { + H->vmm.fnMemoryModel.pfnPhys2VirtGetInformation(H, pProcess, pObP2V); ObContainer_SetOb(pProcess->Plugin.pObCPhys2Virt, pObP2V); } } @@ -1730,7 +1572,7 @@ PVMMOB_PHYS2VIRT_INFORMATION VmmPhys2VirtGetInformation(_In_ PVMM_PROCESS pProce EnterCriticalSection(&pProcess->LockUpdate); pObP2V = ObContainer_GetOb(pProcess->Plugin.pObCPhys2Virt); if(!pObP2V) { - pObP2V = Ob_Alloc('PAVA', LMEM_ZEROINIT, sizeof(VMMOB_PHYS2VIRT_INFORMATION), NULL, NULL); + pObP2V = Ob_AllocEx(H, OB_TAG_VMM_VIRT2PHYS, LMEM_ZEROINIT, sizeof(VMMOB_PHYS2VIRT_INFORMATION), NULL, NULL); pObP2V->dwPID = pProcess->dwPID; ObContainer_SetOb(pProcess->Plugin.pObCPhys2Virt, pObP2V); } @@ -1743,54 +1585,55 @@ PVMMOB_PHYS2VIRT_INFORMATION VmmPhys2VirtGetInformation(_In_ PVMM_PROCESS pProce // PUBLICALLY VISIBLE FUNCTIONALITY RELATED TO VMMU. // ---------------------------------------------------------------------------- -VOID VmmClose() +VOID VmmClose(_In_ VMM_HANDLE H) { - if(!ctxVmm) { return; } - if(ctxVmm->PluginManager.FLinkAll) { PluginManager_Close(); } - VmmWork_Close(); - VmmWinObj_Close(); - VmmWinReg_Close(); - VmmNet_Close(); - PDB_Close(); - Ob_DECREF_NULL(&ctxVmm->pObVfsDumpContext); - Ob_DECREF_NULL(&ctxVmm->pObPfnContext); - Ob_DECREF_NULL(&ctxVmm->pObCPROC); - if(ctxVmm->fnMemoryModel.pfnClose) { - ctxVmm->fnMemoryModel.pfnClose(); + static SRWLOCK LockSRW = SRWLOCK_INIT; + if(!H || !H->vmm.fInitializationStatus) { return; } + AcquireSRWLockExclusive(&LockSRW); + if(H->vmm.PluginManager.FLinkAll) { PluginManager_Close(H); } + VmmWinObj_Close(H); + VmmWinReg_Close(H); + VmmNet_Close(H); + PDB_Close(H); + Ob_DECREF_NULL(&H->vmm.pObVfsDumpContext); + Ob_DECREF_NULL(&H->vmm.pObPfnContext); + Ob_DECREF_NULL(&H->vmm.pObCPROC); + if(H->vmm.fnMemoryModel.pfnClose) { + H->vmm.fnMemoryModel.pfnClose(H); } - MmWin_PagingClose(); - VmmCacheClose(VMM_CACHE_TAG_PHYS); - VmmCacheClose(VMM_CACHE_TAG_TLB); - VmmCacheClose(VMM_CACHE_TAG_PAGING); - Ob_DECREF_NULL(&ctxVmm->Cache.PAGING_FAILED); - Ob_DECREF_NULL(&ctxVmm->Cache.pmPrototypePte); - Ob_DECREF_NULL(&ctxVmm->pObCMapPhysMem); - Ob_DECREF_NULL(&ctxVmm->pObCMapEvil); - Ob_DECREF_NULL(&ctxVmm->pObCMapUser); - Ob_DECREF_NULL(&ctxVmm->pObCMapNet); - Ob_DECREF_NULL(&ctxVmm->pObCMapObject); - Ob_DECREF_NULL(&ctxVmm->pObCMapKDriver); - Ob_DECREF_NULL(&ctxVmm->pObCMapPoolAll); - Ob_DECREF_NULL(&ctxVmm->pObCMapPoolBig); - Ob_DECREF_NULL(&ctxVmm->pObCMapService); - Ob_DECREF_NULL(&ctxVmm->pObCInfoDB); - Ob_DECREF_NULL(&ctxVmm->pObCCachePrefetchEPROCESS); - Ob_DECREF_NULL(&ctxVmm->pObCCachePrefetchRegistry); - Ob_DECREF_NULL(&ctxVmm->pObCacheMapEAT); - Ob_DECREF_NULL(&ctxVmm->pObCacheMapIAT); - Ob_DECREF_NULL(&ctxVmm->pObCacheMapHeapAlloc); - Ob_DECREF_NULL(&ctxVmm->pObCacheMapWinObjDisplay); - VmmLog_Close(); - DeleteCriticalSection(&ctxVmm->LockMaster); - DeleteCriticalSection(&ctxVmm->LockPlugin); - DeleteCriticalSection(&ctxVmm->LockUpdateMap); - DeleteCriticalSection(&ctxVmm->LockUpdateModule); - LocalFree(ctxVmm->ObjectTypeTable.pbMultiText); - LocalFree(ctxVmm); - ctxVmm = NULL; + MmWin_PagingClose(H); + VmmCacheClose(H, VMM_CACHE_TAG_PHYS); + VmmCacheClose(H, VMM_CACHE_TAG_TLB); + VmmCacheClose(H, VMM_CACHE_TAG_PAGING); + Ob_DECREF_NULL(&H->vmm.Cache.PAGING_FAILED); + Ob_DECREF_NULL(&H->vmm.Cache.pmPrototypePte); + Ob_DECREF_NULL(&H->vmm.pObCMapPhysMem); + Ob_DECREF_NULL(&H->vmm.pObCMapEvil); + Ob_DECREF_NULL(&H->vmm.pObCMapUser); + Ob_DECREF_NULL(&H->vmm.pObCMapNet); + Ob_DECREF_NULL(&H->vmm.pObCMapObject); + Ob_DECREF_NULL(&H->vmm.pObCMapKDriver); + Ob_DECREF_NULL(&H->vmm.pObCMapPoolAll); + Ob_DECREF_NULL(&H->vmm.pObCMapPoolBig); + Ob_DECREF_NULL(&H->vmm.pObCMapService); + Ob_DECREF_NULL(&H->vmm.pObCInfoDB); + Ob_DECREF_NULL(&H->vmm.pObCCachePrefetchEPROCESS); + Ob_DECREF_NULL(&H->vmm.pObCCachePrefetchRegistry); + Ob_DECREF_NULL(&H->vmm.pObCacheMapEAT); + Ob_DECREF_NULL(&H->vmm.pObCacheMapIAT); + Ob_DECREF_NULL(&H->vmm.pObCacheMapHeapAlloc); + Ob_DECREF_NULL(&H->vmm.pObCacheMapWinObjDisplay); + Ob_DECREF_NULL(&H->vmm.pObCacheMapObCompressedShared); + DeleteCriticalSection(&H->vmm.LockMaster); + DeleteCriticalSection(&H->vmm.LockPlugin); + DeleteCriticalSection(&H->vmm.LockUpdateMap); + DeleteCriticalSection(&H->vmm.LockUpdateModule); + LocalFree(H->vmm.ObjectTypeTable.pbMultiText); + ZeroMemory(&H->vmm, sizeof(VMM_CONTEXT)); + ReleaseSRWLockExclusive(&LockSRW); } -VOID VmmWriteEx(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _In_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbWrite) +VOID VmmWriteEx(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _In_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbWrite) { DWORD i = 0, oA = 0, cbWrite = 0, cbP, cMEMs; PBYTE pbBuffer; @@ -1814,9 +1657,9 @@ VOID VmmWriteEx(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _In_ PBYTE pb, _ } // write and count result if(pProcess) { - VmmWriteScatterVirtual(pProcess, ppMEMs, cMEMs); + VmmWriteScatterVirtual(H, pProcess, ppMEMs, cMEMs); } else { - VmmWriteScatterPhysical(ppMEMs, cMEMs); + VmmWriteScatterPhysical(H, ppMEMs, cMEMs); } if(pcbWrite) { for(i = 0; i < cMEMs; i++) { @@ -1829,14 +1672,14 @@ VOID VmmWriteEx(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _In_ PBYTE pb, _ LocalFree(pbBuffer); } -BOOL VmmWrite(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _In_reads_(cb) PBYTE pb, _In_ DWORD cb) +BOOL VmmWrite(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _In_reads_(cb) PBYTE pb, _In_ DWORD cb) { DWORD cbWrite; - VmmWriteEx(pProcess, qwA, pb, cb, &cbWrite); + VmmWriteEx(H, pProcess, qwA, pb, cb, &cbWrite); return (cbWrite == cb); } -VOID VmmReadEx(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ QWORD flags) +VOID VmmReadEx(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ QWORD flags) { DWORD cbP, cMEMs, cbRead = 0; PBYTE pbBuffer; @@ -1868,9 +1711,9 @@ VOID VmmReadEx(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _Out_writes_(cb) } // Read VMM and handle result if(pProcess) { - VmmReadScatterVirtual(pProcess, ppMEMs, cMEMs, flags); + VmmReadScatterVirtual(H, pProcess, ppMEMs, cMEMs, flags); } else { - VmmReadScatterPhysical(ppMEMs, cMEMs, flags); + VmmReadScatterPhysical(H, ppMEMs, cMEMs, flags); } for(i = 0; i < cMEMs; i++) { if(pMEMs[i].f) { @@ -1906,7 +1749,7 @@ VOID VmmReadEx(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _Out_writes_(cb) #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) #define STATUS_END_OF_FILE ((NTSTATUS)0xC0000011L) -NTSTATUS VmmReadAsFile(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwMemoryAddress, _In_ QWORD cbMemorySize, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS VmmReadAsFile(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwMemoryAddress, _In_ QWORD cbMemorySize, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { QWORD cbMax; if(cbMemorySize <= cbOffset) { @@ -1918,11 +1761,11 @@ NTSTATUS VmmReadAsFile(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwMemoryAddres if(!*pcbRead) { return STATUS_END_OF_FILE; } - VmmReadEx(pProcess, qwMemoryAddress + cbOffset, pb, *pcbRead, NULL, VMM_FLAG_ZEROPAD_ON_FAIL); + VmmReadEx(H, pProcess, qwMemoryAddress + cbOffset, pb, *pcbRead, NULL, VMM_FLAG_ZEROPAD_ON_FAIL); return STATUS_SUCCESS; } -NTSTATUS VmmWriteAsFile(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwMemoryAddress, _In_ QWORD cbMemorySize, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) +NTSTATUS VmmWriteAsFile(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwMemoryAddress, _In_ QWORD cbMemorySize, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) { QWORD cbMax; if(cbMemorySize <= cbOffset) { @@ -1934,13 +1777,13 @@ NTSTATUS VmmWriteAsFile(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwMemoryAddre if(!*pcbWrite) { return STATUS_END_OF_FILE; } - VmmWriteEx(pProcess, qwMemoryAddress + cbOffset, pb, *pcbWrite, NULL); + VmmWriteEx(H, pProcess, qwMemoryAddress + cbOffset, pb, *pcbWrite, NULL); return STATUS_SUCCESS; } _Success_(return) -BOOL VmmReadWtoU(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _In_ DWORD cb, _In_ QWORD flagsRead, _Maybenull_ _Writable_bytes_(cbBuffer) PBYTE pbBuffer, _In_ DWORD cbBuffer, _Out_opt_ LPSTR *pusz, _Out_opt_ PDWORD pcbu, _In_ DWORD flagsChar) +BOOL VmmReadWtoU(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _In_ DWORD cb, _In_ QWORD flagsRead, _Maybenull_ _Writable_bytes_(cbBuffer) PBYTE pbBuffer, _In_ DWORD cbBuffer, _Out_opt_ LPSTR *pusz, _Out_opt_ PDWORD pcbu, _In_ DWORD flagsChar) { BOOL fResult = FALSE; BYTE pbBufferTMP[2 * MAX_PATH + 2] = { 0 }; @@ -1949,7 +1792,7 @@ BOOL VmmReadWtoU(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _In_ DWORD cb, if(cb > sizeof(pbBufferTMP)) { if(!(pb = LocalAlloc(0, cb))) { goto fail; } } - VmmReadEx(pProcess, qwA, pb, cb, &cbRead, flagsRead); + VmmReadEx(H, pProcess, qwA, pb, cb, &cbRead, flagsRead); if(cbRead != cb) { if(cbBuffer && pbBuffer) { pbBuffer[0] = 0; } goto fail; @@ -1966,11 +1809,11 @@ fail: } _Success_(return) -BOOL VmmReadAlloc(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _Out_ PBYTE *ppb, _In_ DWORD cb, _In_ QWORD flags) +BOOL VmmReadAlloc(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _Out_ PBYTE *ppb, _In_ DWORD cb, _In_ QWORD flags) { PBYTE pb; if(!(pb = LocalAlloc(0, cb + 2ULL))) { return FALSE; } - if(!VmmRead2(pProcess, qwA, pb, cb, flags)) { + if(!VmmRead2(H, pProcess, qwA, pb, cb, flags)) { LocalFree(pb); return FALSE; } @@ -1981,11 +1824,11 @@ BOOL VmmReadAlloc(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _Out_ PBYTE *p } _Success_(return) -BOOL VmmReadAllocUnicodeString_Size(_In_ PVMM_PROCESS pProcess, _In_ BOOL f32, _In_ QWORD flags, _In_ QWORD vaUS, _Out_ PQWORD pvaStr, _Out_ PWORD pcbStr) +BOOL VmmReadAllocUnicodeString_Size(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ BOOL f32, _In_ QWORD flags, _In_ QWORD vaUS, _Out_ PQWORD pvaStr, _Out_ PWORD pcbStr) { BYTE pb[16]; DWORD cbRead; - VmmReadEx(pProcess, vaUS, pb, (f32 ? 8 : 16), &cbRead, flags); + VmmReadEx(H, pProcess, vaUS, pb, (f32 ? 8 : 16), &cbRead, flags); return (cbRead == (f32 ? 8 : 16)) && // read ok (*(PWORD)pb <= *(PWORD)(pb + 2)) && // size max >= size @@ -1996,17 +1839,17 @@ BOOL VmmReadAllocUnicodeString_Size(_In_ PVMM_PROCESS pProcess, _In_ BOOL f32, _ } _Success_(return) -BOOL VmmReadAllocUnicodeString(_In_ PVMM_PROCESS pProcess, _In_ BOOL f32, _In_ QWORD flags, _In_ QWORD vaUS, _In_ DWORD cchMax, _Out_opt_ LPWSTR *pwsz, _Out_opt_ PDWORD pcch) +BOOL VmmReadAllocUnicodeString(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ BOOL f32, _In_ QWORD flags, _In_ QWORD vaUS, _In_ DWORD cchMax, _Out_opt_ LPWSTR *pwsz, _Out_opt_ PDWORD pcch) { WORD cbStr; QWORD vaStr; if(pcch) { *pcch = 0; } if(pwsz) { *pwsz = NULL; } - if(VmmReadAllocUnicodeString_Size(pProcess, f32, 0, vaUS, &vaStr, &cbStr)) { + if(VmmReadAllocUnicodeString_Size(H, pProcess, f32, 0, vaUS, &vaStr, &cbStr)) { if(cchMax && (cbStr > (cchMax << 1))) { cbStr = (WORD)(cchMax << 1); } - if(!pwsz || VmmReadAlloc(pProcess, vaStr, (PBYTE *)pwsz, cbStr, flags)) { + if(!pwsz || VmmReadAlloc(H, pProcess, vaStr, (PBYTE *)pwsz, cbStr, flags)) { if(pcch) { *pcch = cbStr >> 1; } return TRUE; } @@ -2015,118 +1858,121 @@ BOOL VmmReadAllocUnicodeString(_In_ PVMM_PROCESS pProcess, _In_ BOOL f32, _In_ Q } _Success_(return) -BOOL VmmReadAllocUnicodeStringAsUTF8(_In_ PVMM_PROCESS pProcess, _In_ BOOL f32, _In_ QWORD flags, _In_ QWORD vaUS, _In_ DWORD cchMax, _Out_opt_ LPSTR *pusz, _Out_opt_ PDWORD pcbu) +BOOL VmmReadAllocUnicodeStringAsUTF8(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ BOOL f32, _In_ QWORD flags, _In_ QWORD vaUS, _In_ DWORD cchMax, _Out_opt_ LPSTR *pusz, _Out_opt_ PDWORD pcbu) { BOOL f; LPWSTR wszTMP = NULL; - f = VmmReadAllocUnicodeString(pProcess, f32, 0, vaUS, cchMax, &wszTMP, NULL) && + f = VmmReadAllocUnicodeString(H, pProcess, f32, 0, vaUS, cchMax, &wszTMP, NULL) && CharUtil_WtoU(wszTMP, cchMax, NULL, 0, pusz, pcbu, CHARUTIL_FLAG_ALLOC); LocalFree(wszTMP); return f; } _Success_(return) -BOOL VmmRead(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb) +BOOL VmmRead(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb) { DWORD cbRead; - VmmReadEx(pProcess, qwA, pb, cb, &cbRead, 0); + VmmReadEx(H, pProcess, qwA, pb, cb, &cbRead, 0); return (cbRead == cb); } _Success_(return) -BOOL VmmRead2(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _In_ QWORD flags) +BOOL VmmRead2(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _In_ QWORD flags) { DWORD cbRead; - VmmReadEx(pProcess, qwA, pb, cb, &cbRead, flags); + VmmReadEx(H, pProcess, qwA, pb, cb, &cbRead, flags); return (cbRead == cb); } _Success_(return) -BOOL VmmReadPage(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _Out_writes_(4096) PBYTE pbPage) +BOOL VmmReadPage(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _Out_writes_(4096) PBYTE pbPage) { DWORD cb; - VmmReadEx(pProcess, qwA, pbPage, 0x1000, &cb, 0); + VmmReadEx(H, pProcess, qwA, pbPage, 0x1000, &cb, 0); return cb == 0x1000; } -VOID VmmInitializeMemoryModel(_In_ VMM_MEMORYMODEL_TP tp) +VOID VmmInitializeMemoryModel(_In_ VMM_HANDLE H, _In_ VMM_MEMORYMODEL_TP tp) { switch(tp) { case VMM_MEMORYMODEL_X64: - MmX64_Initialize(); + MmX64_Initialize(H); break; case VMM_MEMORYMODEL_X86PAE: - MmX86PAE_Initialize(); + MmX86PAE_Initialize(H); break; case VMM_MEMORYMODEL_X86: - MmX86_Initialize(); + MmX86_Initialize(H); break; default: - if(ctxVmm->fnMemoryModel.pfnClose) { - ctxVmm->fnMemoryModel.pfnClose(); + if(H->vmm.fnMemoryModel.pfnClose) { + H->vmm.fnMemoryModel.pfnClose(H); } } } -VOID VmmInitializeFunctions() +VOID VmmInitializeFunctions(_In_ VMM_HANDLE H) { HMODULE hNtDll = NULL; if((hNtDll = LoadLibraryA("ntdll.dll"))) { - ctxVmm->fn.RtlDecompressBufferOpt = (VMMFN_RtlDecompressBuffer*)GetProcAddress(hNtDll, "RtlDecompressBuffer"); + H->vmm.fn.RtlDecompressBufferOpt = (VMMFN_RtlDecompressBuffer*)GetProcAddress(hNtDll, "RtlDecompressBuffer"); FreeLibrary(hNtDll); } return; } -BOOL VmmInitialize() +BOOL VmmInitialize(_In_ VMM_HANDLE H) { + static SRWLOCK LockSRW = SRWLOCK_INIT; + AcquireSRWLockExclusive(&LockSRW); // 1: allocate & initialize - if(ctxVmm) { VmmClose(); } - ctxVmm = (PVMM_CONTEXT)LocalAlloc(LMEM_ZEROINIT, sizeof(VMM_CONTEXT)); - if(!ctxVmm) { goto fail; } - ctxVmm->hModuleVmmOpt = GetModuleHandleA("vmm"); - if(ctxMain->cfg.tpForensicMode && !ctxMain->dev.fVolatile && !ctxMain->dev.fRemote) { + if(H->vmm.fInitializationStatus) { VmmClose(H); } + ZeroMemory(&H->vmm, sizeof(VMM_CONTEXT)); + H->vmm.hModuleVmmOpt = GetModuleHandleA("vmm"); + if(H->cfg.tpForensicMode && !H->dev.fVolatile && !H->dev.fRemote) { // forensic mode for local static files disables the forcache // read pattern to achieve greater forensic file consistency. - ctxVmm->flags |= VMM_FLAG_FORCECACHE_READ_DISABLE; + H->vmm.flags |= VMM_FLAG_FORCECACHE_READ_DISABLE; } // 2: CACHE INIT: Process Table - if(!VmmProcessTableCreateInitial()) { goto fail; } + if(!VmmProcessTableCreateInitial(H)) { goto fail; } // 3: CACHE INIT: Translation Lookaside Buffer (TLB) Cache Table - VmmCacheInitialize(VMM_CACHE_TAG_TLB); - if(!ctxVmm->Cache.TLB.fActive) { goto fail; } + VmmCacheInitialize(H, VMM_CACHE_TAG_TLB); + if(!H->vmm.Cache.TLB.fActive) { goto fail; } // 4: CACHE INIT: Physical Memory Cache Table - VmmCacheInitialize(VMM_CACHE_TAG_PHYS); - if(!ctxVmm->Cache.PHYS.fActive) { goto fail; } + VmmCacheInitialize(H, VMM_CACHE_TAG_PHYS); + if(!H->vmm.Cache.PHYS.fActive) { goto fail; } // 5: CACHE INIT: Paged Memory Cache Table - VmmCacheInitialize(VMM_CACHE_TAG_PAGING); - if(!ctxVmm->Cache.PAGING.fActive) { goto fail; } - if(!(ctxVmm->Cache.PAGING_FAILED = ObSet_New())) { goto fail; } + VmmCacheInitialize(H, VMM_CACHE_TAG_PAGING); + if(!H->vmm.Cache.PAGING.fActive) { goto fail; } + if(!(H->vmm.Cache.PAGING_FAILED = ObSet_New(H))) { goto fail; } // 6: CACHE INIT: Prototype PTE Cache Map - if(!(ctxVmm->Cache.pmPrototypePte = ObMap_New(OB_MAP_FLAGS_OBJECT_OB))) { goto fail; } - // 7: WORKER THREADS INIT: - VmmWork_Initialize(); - // 8: OTHER INIT: - ctxVmm->pObCMapPhysMem = ObContainer_New(); - ctxVmm->pObCMapEvil = ObContainer_New(); - ctxVmm->pObCMapUser = ObContainer_New(); - ctxVmm->pObCMapNet = ObContainer_New(); - ctxVmm->pObCMapObject = ObContainer_New(); - ctxVmm->pObCMapKDriver = ObContainer_New(); - ctxVmm->pObCMapPoolAll = ObContainer_New(); - ctxVmm->pObCMapPoolBig = ObContainer_New(); - ctxVmm->pObCMapService = ObContainer_New(); - ctxVmm->pObCInfoDB = ObContainer_New(); - ctxVmm->pObCCachePrefetchEPROCESS = ObContainer_New(); - ctxVmm->pObCCachePrefetchRegistry = ObContainer_New(); - InitializeCriticalSection(&ctxVmm->LockMaster); - InitializeCriticalSection(&ctxVmm->LockPlugin); - InitializeCriticalSection(&ctxVmm->LockUpdateMap); - InitializeCriticalSection(&ctxVmm->LockUpdateModule); - VmmInitializeFunctions(); + if(!(H->vmm.Cache.pmPrototypePte = ObMap_New(H, OB_MAP_FLAGS_OBJECT_OB))) { goto fail; } + // 7: OTHER INIT: + H->vmm.pObCMapPhysMem = ObContainer_New(); + H->vmm.pObCMapEvil = ObContainer_New(); + H->vmm.pObCMapUser = ObContainer_New(); + H->vmm.pObCMapNet = ObContainer_New(); + H->vmm.pObCMapObject = ObContainer_New(); + H->vmm.pObCMapKDriver = ObContainer_New(); + H->vmm.pObCMapPoolAll = ObContainer_New(); + H->vmm.pObCMapPoolBig = ObContainer_New(); + H->vmm.pObCMapService = ObContainer_New(); + H->vmm.pObCInfoDB = ObContainer_New(); + H->vmm.pObCCachePrefetchEPROCESS = ObContainer_New(); + H->vmm.pObCCachePrefetchRegistry = ObContainer_New(); + H->vmm.pObCacheMapObCompressedShared = ObCacheMap_New(H, OB_COMPRESSED_CACHED_ENTRIES_MAX, NULL, OB_CACHEMAP_FLAGS_OBJECT_OB); + InitializeCriticalSection(&H->vmm.LockMaster); + InitializeCriticalSection(&H->vmm.LockPlugin); + InitializeCriticalSection(&H->vmm.LockUpdateMap); + InitializeCriticalSection(&H->vmm.LockUpdateModule); + VmmInitializeFunctions(H); + H->vmm.fInitializationStatus = TRUE; + ReleaseSRWLockExclusive(&LockSRW); return TRUE; fail: - VmmClose(); + VmmClose(H); + ReleaseSRWLockExclusive(&LockSRW); return FALSE; } @@ -2148,19 +1994,19 @@ typedef struct tdVMM_MEMORY_SEARCH_INTERNAL_CONTEXT { * Search data inside region. */ _Success_(return) -BOOL VmmSearch_SearchRegion(_In_ PVMM_MEMORY_SEARCH_INTERNAL_CONTEXT ctxi, _In_ PVMM_MEMORY_SEARCH_CONTEXT ctxs) +BOOL VmmSearch_SearchRegion(_In_ VMM_HANDLE H, _In_ PVMM_MEMORY_SEARCH_INTERNAL_CONTEXT ctxi, _In_ PVMM_MEMORY_SEARCH_CONTEXT ctxs) { BYTE v; QWORD va, oMax; DWORD o, i, iS, cbRead; BOOL fMaskFail, f4; PVMM_MEMORY_SEARCH_CONTEXT_SEARCHENTRY pS; - if(ctxs->fAbortRequested || !ctxVmm->Work.fEnabled) { + if(ctxs->fAbortRequested || H->fAbort) { ctxs->fAbortRequested = TRUE; return FALSE; } ctxs->cbReadTotal += ctxi->cb; - VmmReadEx(ctxi->pProcess, ctxs->vaCurrent, ctxi->pb, ctxi->cb, &cbRead, ctxs->ReadFlags | VMM_FLAG_ZEROPAD_ON_FAIL); + VmmReadEx(H, ctxi->pProcess, ctxs->vaCurrent, ctxi->pb, ctxi->cb, &cbRead, ctxs->ReadFlags | VMM_FLAG_ZEROPAD_ON_FAIL); if(!cbRead) { return TRUE; } for(iS = 0; iS < ctxs->cSearch; iS++) { pS = ctxs->search + iS; @@ -2226,11 +2072,11 @@ BOOL VmmSearch_SearchRegion(_In_ PVMM_MEMORY_SEARCH_INTERNAL_CONTEXT ctxi, _In_ * Search a physical/virtual address range. */ _Success_(return) -BOOL VmmSearch_SearchRange(_In_ PVMM_MEMORY_SEARCH_INTERNAL_CONTEXT ctxi, _In_ PVMM_MEMORY_SEARCH_CONTEXT ctxs, _In_ QWORD vaMax) +BOOL VmmSearch_SearchRange(_In_ VMM_HANDLE H, _In_ PVMM_MEMORY_SEARCH_INTERNAL_CONTEXT ctxi, _In_ PVMM_MEMORY_SEARCH_CONTEXT ctxs, _In_ QWORD vaMax) { while(ctxs->vaCurrent < vaMax) { ctxi->cb = (DWORD)min(0x00100000, vaMax + 1 - ctxs->vaCurrent); - if(!VmmSearch_SearchRegion(ctxi, ctxs)) { return FALSE; } + if(!VmmSearch_SearchRegion(H, ctxi, ctxs)) { return FALSE; } ctxs->vaCurrent += ctxi->cb; if(!ctxs->vaCurrent) { ctxs->vaCurrent = 0xfffffffffffff000; @@ -2244,7 +2090,7 @@ BOOL VmmSearch_SearchRange(_In_ PVMM_MEMORY_SEARCH_INTERNAL_CONTEXT ctxi, _In_ P * Search virtual address space by walking either PTEs or VADs. */ _Success_(return) -BOOL VmmSearch_VirtPteVad(_In_ PVMM_MEMORY_SEARCH_INTERNAL_CONTEXT ctxi, _In_ PVMM_MEMORY_SEARCH_CONTEXT ctxs) +BOOL VmmSearch_VirtPteVad(_In_ VMM_HANDLE H, _In_ PVMM_MEMORY_SEARCH_INTERNAL_CONTEXT ctxi, _In_ PVMM_MEMORY_SEARCH_CONTEXT ctxs) { BOOL fResult = FALSE; DWORD ie = 0; @@ -2258,7 +2104,7 @@ BOOL VmmSearch_VirtPteVad(_In_ PVMM_MEMORY_SEARCH_INTERNAL_CONTEXT ctxi, _In_ PV ctxs->vaCurrent = ctxs->vaMin; if(ctxs->fForceVAD || (ctxi->pProcess->fUserOnly && !ctxs->fForcePTE)) { // VAD method: - if(!VmmMap_GetVad(ctxi->pProcess, &pObVAD, VMM_VADMAP_TP_CORE)) { goto fail; } + if(!VmmMap_GetVad(H, ctxi->pProcess, &pObVAD, VMM_VADMAP_TP_CORE)) { goto fail; } for(ie = 0; ie < pObVAD->cMap; ie++) { peVAD = pObVAD->pMap + ie; if(peVAD->vaStart + peVAD->vaEnd < ctxs->vaMin) { continue; } // skip entries below min address @@ -2268,11 +2114,11 @@ BOOL VmmSearch_VirtPteVad(_In_ PVMM_MEMORY_SEARCH_INTERNAL_CONTEXT ctxi, _In_ PV // TODO: is peVAD->vaEnd == 0xfff ???? ctxs->vaCurrent = max(ctxs->vaCurrent, peVAD->vaStart); vaMax = min(ctxs->vaMax, peVAD->vaEnd); - if(!VmmSearch_SearchRange(ctxi, ctxs, vaMax)) { goto fail; } + if(!VmmSearch_SearchRange(H, ctxi, ctxs, vaMax)) { goto fail; } } } else { // PTE method: - if(!VmmMap_GetPte(ctxi->pProcess, &pObPTE, FALSE)) { goto fail; } + if(!VmmMap_GetPte(H, ctxi->pProcess, &pObPTE, FALSE)) { goto fail; } for(ie = 0; ie < pObPTE->cMap; ie++) { pePTE = pObPTE->pMap + ie; cbPTE = pePTE->cPages << 12; @@ -2282,7 +2128,7 @@ BOOL VmmSearch_VirtPteVad(_In_ PVMM_MEMORY_SEARCH_INTERNAL_CONTEXT ctxi, _In_ PV if(ctxs->pfnFilterOptCB && !ctxs->pfnFilterOptCB(ctxs, pePTE, NULL)) { continue; } ctxs->vaCurrent = max(ctxs->vaCurrent, pePTE->vaBase); vaMax = min(ctxs->vaMax, pePTE->vaBase + cbPTE - 1); - if(!VmmSearch_SearchRange(ctxi, ctxs, vaMax)) { goto fail; } + if(!VmmSearch_SearchRange(H, ctxi, ctxs, vaMax)) { goto fail; } } } fResult = TRUE; @@ -2306,7 +2152,7 @@ fail: * -- return */ _Success_(return) -BOOL VmmSearch(_In_opt_ PVMM_PROCESS pProcess, _Inout_ PVMM_MEMORY_SEARCH_CONTEXT ctxs, _Out_opt_ POB_DATA *ppObAddressResult) +BOOL VmmSearch(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _Inout_ PVMM_MEMORY_SEARCH_CONTEXT ctxs, _Out_opt_ POB_DATA *ppObAddressResult) { static BYTE pbZERO[sizeof(ctxs->search[0].pb)] = {0}; DWORD iS; @@ -2325,8 +2171,8 @@ BOOL VmmSearch(_In_opt_ PVMM_PROCESS pProcess, _Inout_ PVMM_MEMORY_SEARCH_CONTEX } if(!ctxs->vaMax) { if(!pProcess) { - ctxs->vaMax = ctxMain->dev.paMax; - } else if(ctxVmm->tpMemoryModel == VMMDLL_MEMORYMODEL_X64) { + ctxs->vaMax = H->dev.paMax; + } else if(H->vmm.tpMemoryModel == VMMDLL_MEMORYMODEL_X64) { ctxs->vaMax = (QWORD)-1; } else { ctxs->vaMax = (DWORD)-1; @@ -2334,17 +2180,17 @@ BOOL VmmSearch(_In_opt_ PVMM_PROCESS pProcess, _Inout_ PVMM_MEMORY_SEARCH_CONTEX } // 2: allocate if(!(ctxi = LocalAlloc(0, sizeof(VMM_MEMORY_SEARCH_INTERNAL_CONTEXT)))) { goto fail; } - if(!(ctxi->psvaResult = ObSet_New())) { goto fail; } + if(!(ctxi->psvaResult = ObSet_New(H))) { goto fail; } ctxi->pProcess = pProcess; for(iS = 0; iS < ctxs->cSearch; iS++) { ctxi->fMask[iS] = (memcmp(ctxs->search[iS].pbSkipMask, pbZERO, ctxs->search[iS].cb) ? TRUE : FALSE); } // 3: perform search - if(pProcess && (ctxs->fForcePTE || ctxs->fForceVAD || (ctxVmm->tpMemoryModel == VMMDLL_MEMORYMODEL_X64))) { - fResult = VmmSearch_VirtPteVad(ctxi, ctxs); + if(pProcess && (ctxs->fForcePTE || ctxs->fForceVAD || (H->vmm.tpMemoryModel == VMMDLL_MEMORYMODEL_X64))) { + fResult = VmmSearch_VirtPteVad(H, ctxi, ctxs); } else { ctxs->vaCurrent = ctxs->vaMin; - fResult = VmmSearch_SearchRange(ctxi, ctxs, ctxs->vaMax); + fResult = VmmSearch_SearchRange(H, ctxi, ctxs, ctxs->vaMax); } // 4: finish if(fResult && ppObAddressResult) { @@ -2369,24 +2215,26 @@ fail: /* * Retrieve the PTE hardware page table memory map. * CALLER DECREF: ppObPteMap +* -- H * -- pProcess * -- ppObPteMap * -- fExtendedText * -- return */ _Success_(return) -BOOL VmmMap_GetPte(_In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_PTE *ppObPteMap, _In_ BOOL fExtendedText) +BOOL VmmMap_GetPte(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_PTE *ppObPteMap, _In_ BOOL fExtendedText) { return - (ctxVmm->tpMemoryModel != VMM_MEMORYMODEL_NA) && - ctxVmm->fnMemoryModel.pfnPteMapInitialize(pProcess) && - (!fExtendedText || VmmWinPte_InitializeMapText(pProcess)) && + (H->vmm.tpMemoryModel != VMM_MEMORYMODEL_NA) && + H->vmm.fnMemoryModel.pfnPteMapInitialize(H, pProcess) && + (!fExtendedText || VmmWinPte_InitializeMapText(H, pProcess)) && (*ppObPteMap = Ob_INCREF(pProcess->Map.pObPte)); } /* * Retrieve the VAD extended memory map by range specified by iPage and cPage. * CALLER DECREF: ppObVadExMap +* -- H * -- pProcess * -- ppObVadExMap * -- tpVmmVadMap = VMM_VADMAP_TP_* @@ -2395,24 +2243,25 @@ BOOL VmmMap_GetPte(_In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_PTE *ppObPteMap, * -- return */ _Success_(return) -BOOL VmmMap_GetVadEx(_In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_VADEX *ppObVadExMap, _In_ VMM_VADMAP_TP tpVmmVadMap, _In_ DWORD iPage, _In_ DWORD cPage) +BOOL VmmMap_GetVadEx(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_VADEX *ppObVadExMap, _In_ VMM_VADMAP_TP tpVmmVadMap, _In_ DWORD iPage, _In_ DWORD cPage) { - *ppObVadExMap = MmVadEx_MapInitialize(pProcess, tpVmmVadMap, iPage, cPage); + *ppObVadExMap = MmVadEx_MapInitialize(H, pProcess, tpVmmVadMap, iPage, cPage); return *ppObVadExMap != NULL; } /* * Retrieve the VAD memory map. * CALLER DECREF: ppObVadMap +* -- H * -- pProcess * -- ppObVadMap * -- tpVmmVadMap = VMM_VADMAP_TP_* * -- return */ _Success_(return) -BOOL VmmMap_GetVad(_In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_VAD *ppObVadMap, _In_ VMM_VADMAP_TP tpVmmVadMap) +BOOL VmmMap_GetVad(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_VAD *ppObVadMap, _In_ VMM_VADMAP_TP tpVmmVadMap) { - if(!MmVad_MapInitialize(pProcess, tpVmmVadMap, 0)) { return FALSE; } + if(!MmVad_MapInitialize(H, pProcess, tpVmmVadMap, 0)) { return FALSE; } *ppObVadMap = Ob_INCREF(pProcess->Map.pObVad); return *ppObVadMap != NULL; } @@ -2427,12 +2276,13 @@ int VmmMap_GetVadEntry_CmpFind(_In_ QWORD vaFind, _In_ QWORD qwEntry) /* * Retrieve a single PVMM_MAP_VADENTRY for a given VadMap and address inside it. +* -- H * -- pVadMap * -- va * -- return = PTR to VADENTRY or NULL on fail. Must not be used out of pVadMap scope. */ _Success_(return != NULL) -PVMM_MAP_VADENTRY VmmMap_GetVadEntry(_In_opt_ PVMMOB_MAP_VAD pVadMap, _In_ QWORD va) +PVMM_MAP_VADENTRY VmmMap_GetVadEntry(_In_ VMM_HANDLE H, _In_opt_ PVMMOB_MAP_VAD pVadMap, _In_ QWORD va) { if(!pVadMap) { return NULL; } return Util_qfind(va, pVadMap->cMap, pVadMap->pMap, sizeof(VMM_MAP_VADENTRY), VmmMap_GetVadEntry_CmpFind); @@ -2441,14 +2291,15 @@ PVMM_MAP_VADENTRY VmmMap_GetVadEntry(_In_opt_ PVMMOB_MAP_VAD pVadMap, _In_ QWORD /* * Retrieve the process module map. * CALLER DECREF: ppObModuleMap +* -- H * -- pProcess * -- ppObModuleMap * -- return */ _Success_(return) -BOOL VmmMap_GetModule(_In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_MODULE *ppObModuleMap) +BOOL VmmMap_GetModule(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_MODULE *ppObModuleMap) { - if(!pProcess->Map.pObModule && !VmmWinLdrModule_Initialize(pProcess, NULL)) { return FALSE; } + if(!pProcess->Map.pObModule && !VmmWinLdrModule_Initialize(H, pProcess, NULL)) { return FALSE; } *ppObModuleMap = Ob_INCREF(pProcess->Map.pObModule); return *ppObModuleMap != NULL; } @@ -2464,11 +2315,13 @@ int VmmMap_HashTableLookup_CmpFind(_In_ QWORD qwHash, _In_ QWORD qwEntry) /* * Retrieve a single PVMM_MAP_MODULEENTRY for a given ModuleMap and module name inside it. +* -- H * -- pModuleMap * -- uszModuleName * -- return = PTR to VMM_MAP_MODULEENTRY or NULL on fail. Must not be used out of pModuleMap scope. */ -PVMM_MAP_MODULEENTRY VmmMap_GetModuleEntry(_In_ PVMMOB_MAP_MODULE pModuleMap, _In_ LPSTR uszModuleName) +_Success_(return != NULL) +PVMM_MAP_MODULEENTRY VmmMap_GetModuleEntry(_In_ VMM_HANDLE H, _In_ PVMMOB_MAP_MODULE pModuleMap, _In_ LPSTR uszModuleName) { QWORD qwHash, *pqwHashIndex; qwHash = CharUtil_HashNameFsU(uszModuleName, 0); @@ -2479,6 +2332,7 @@ PVMM_MAP_MODULEENTRY VmmMap_GetModuleEntry(_In_ PVMMOB_MAP_MODULE pModuleMap, _I /* * Retrieve a single VMM_MAP_MODULEENTRY for a given process and module name. * CALLER DECREF: ppObModuleMap +* -- H * -- pProcessOpt * -- dwPidOpt * -- wszModuleName @@ -2487,14 +2341,14 @@ PVMM_MAP_MODULEENTRY VmmMap_GetModuleEntry(_In_ PVMMOB_MAP_MODULE pModuleMap, _I * -- return */ _Success_(return) -BOOL VmmMap_GetModuleEntryEx(_In_opt_ PVMM_PROCESS pProcessOpt, _In_opt_ DWORD dwPidOpt, _In_opt_ LPSTR uszModuleName, _Out_ PVMMOB_MAP_MODULE *ppObModuleMap, _Out_ PVMM_MAP_MODULEENTRY *pModuleEntry) +BOOL VmmMap_GetModuleEntryEx(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcessOpt, _In_opt_ DWORD dwPidOpt, _In_opt_ LPSTR uszModuleName, _Out_ PVMMOB_MAP_MODULE *ppObModuleMap, _Out_ PVMM_MAP_MODULEENTRY *pModuleEntry) { - PVMM_PROCESS pObProcess = pProcessOpt ? Ob_INCREF(pProcessOpt) : VmmProcessGet(dwPidOpt); + PVMM_PROCESS pObProcess = pProcessOpt ? Ob_INCREF(pProcessOpt) : VmmProcessGet(H, dwPidOpt); *ppObModuleMap = NULL; *pModuleEntry = NULL; - if(pObProcess && VmmMap_GetModule(pObProcess, ppObModuleMap)) { + if(pObProcess && VmmMap_GetModule(H, pObProcess, ppObModuleMap)) { if(uszModuleName && uszModuleName[0]) { - *pModuleEntry = VmmMap_GetModuleEntry(*ppObModuleMap, uszModuleName); + *pModuleEntry = VmmMap_GetModuleEntry(H, *ppObModuleMap, uszModuleName); } else if((*ppObModuleMap)->cMap) { *pModuleEntry = (*ppObModuleMap)->pMap; } @@ -2505,17 +2359,60 @@ BOOL VmmMap_GetModuleEntryEx(_In_opt_ PVMM_PROCESS pProcessOpt, _In_opt_ DWORD d return FALSE; } +/* +* Retrieve a single PVMM_MAP_MODULEENTRY for a given ModuleMap and virtual address inside it. +* -- H +* -- pModuleMap +* -- va = virtual address within the module range. +* -- return = PTR to VMM_MAP_MODULEENTRY or NULL on fail. Must not be used out of pModuleMap scope. +*/ +_Success_(return != NULL) +PVMM_MAP_MODULEENTRY VmmMap_GetModuleEntryEx2(_In_ VMM_HANDLE H, _In_ PVMMOB_MAP_MODULE pModuleMap, _In_ QWORD va) +{ + DWORD i; + for(i = 0; i < pModuleMap->cMap; i++) { + if((pModuleMap->pMap[i].vaBase <= va) && (pModuleMap->pMap[i].vaBase + pModuleMap->pMap[i].cbImageSize > va)) { + return pModuleMap->pMap + i; + } + } + return NULL; +} + +/* +* Retrieve POB_MAP for a given ModuleMap. +* CALLER DECREF: *ppmObModuleEntryByVA +* -- H +* -- pModuleMap +* -- ppmObModuleEntryByVA = map consisting of module entries keyed by va (only valid for duration of pModuleMap). +* -- return +*/ +_Success_(return) +BOOL VmmMap_GetModuleEntryEx3(_In_ VMM_HANDLE H, _In_ PVMMOB_MAP_MODULE pModuleMap, _Out_ POB_MAP *ppmObModuleEntryByVA) +{ + DWORD i; + POB_MAP pmOb = NULL; + PVMM_MAP_MODULEENTRY pe; + if(!(pmOb = ObMap_New(H, OB_MAP_FLAGS_OBJECT_VOID))) { return FALSE; } + for(i = 0; i < pModuleMap->cMap; i++) { + pe = pModuleMap->pMap + i; + ObMap_Push(pmOb, pe->vaBase, pe); + } + *ppmObModuleEntryByVA = pmOb; + return TRUE; +} + /* * Retrieve the process unloaded module map. * CALLER DECREF: ppObUnloadedModuleMap +* -- H * -- pProcess * -- ppObUnloadedModuleMap * -- return */ _Success_(return) -BOOL VmmMap_GetUnloadedModule(_In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_UNLOADEDMODULE *ppObUnloadedModuleMap) +BOOL VmmMap_GetUnloadedModule(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_UNLOADEDMODULE *ppObUnloadedModuleMap) { - if(!pProcess->Map.pObUnloadedModule && !VmmWinUnloadedModule_Initialize(pProcess)) { return FALSE; } + if(!pProcess->Map.pObUnloadedModule && !VmmWinUnloadedModule_Initialize(H, pProcess)) { return FALSE; } *ppObUnloadedModuleMap = Ob_INCREF(pProcess->Map.pObUnloadedModule); return *ppObUnloadedModuleMap != NULL; } @@ -2523,27 +2420,29 @@ BOOL VmmMap_GetUnloadedModule(_In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_UNLOA /* * Retrieve the process module export address table (EAT) map. * CALLER DECREF: ppObEatMap +* -- H * -- pProcess * -- pModule * -- ppObEatMap * -- return */ _Success_(return) -BOOL VmmMap_GetEAT(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_MODULEENTRY pModuleEntry, _Out_ PVMMOB_MAP_EAT *ppObEatMap) +BOOL VmmMap_GetEAT(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_MODULEENTRY pModuleEntry, _Out_ PVMMOB_MAP_EAT *ppObEatMap) { - *ppObEatMap = VmmWinEAT_Initialize(pProcess, pModuleEntry); + *ppObEatMap = VmmWinEAT_Initialize(H, pProcess, pModuleEntry); return *ppObEatMap != NULL; } /* * Retrieve the export entry index in pEatMap->pMap by function name. +* -- H * -- pEatMap * -- uszFunctionName * -- pdwEntryIndex = pointer to receive the pEatMap->pMap index. * -- return */ _Success_(return) -BOOL VmmMap_GetEATEntryIndexU(_In_ PVMMOB_MAP_EAT pEatMap, _In_ LPSTR uszFunctionName, _Out_ PDWORD pdwEntryIndex) +BOOL VmmMap_GetEATEntryIndexU(_In_ VMM_HANDLE H, _In_ PVMMOB_MAP_EAT pEatMap, _In_ LPSTR uszFunctionName, _Out_ PDWORD pdwEntryIndex) { QWORD qwHash, *pqwHashIndex; qwHash = (DWORD)CharUtil_Hash64U(uszFunctionName, TRUE); @@ -2555,29 +2454,31 @@ BOOL VmmMap_GetEATEntryIndexU(_In_ PVMMOB_MAP_EAT pEatMap, _In_ LPSTR uszFunctio /* * Retrieve the process module import address table (IAT) map. * CALLER DECREF: ppObIatMap +* -- H * -- pProcess * -- pModule * -- ppObIatMap * -- return */ _Success_(return) -BOOL VmmMap_GetIAT(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_MODULEENTRY pModuleEntry, _Out_ PVMMOB_MAP_IAT *ppObIatMap) +BOOL VmmMap_GetIAT(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_MODULEENTRY pModuleEntry, _Out_ PVMMOB_MAP_IAT *ppObIatMap) { - *ppObIatMap = VmmWinIAT_Initialize(pProcess, pModuleEntry); + *ppObIatMap = VmmWinIAT_Initialize(H, pProcess, pModuleEntry); return *ppObIatMap != NULL; } /* * Retrieve the heap map. * CALLER DECREF: ppObHeapMap +* -- H * -- pProcess * -- ppObHeapMap * -- return */ _Success_(return) -BOOL VmmMap_GetHeap(_In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_HEAP *ppObHeapMap) +BOOL VmmMap_GetHeap(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_HEAP *ppObHeapMap) { - if(!pProcess->Map.pObHeap && !VmmHeap_Initialize(pProcess)) { return FALSE; } + if(!pProcess->Map.pObHeap && !VmmHeap_Initialize(H, pProcess)) { return FALSE; } *ppObHeapMap = Ob_INCREF(pProcess->Map.pObHeap); return *ppObHeapMap != NULL; } @@ -2590,11 +2491,12 @@ int VmmMap_GetHeapEntry_CmpFind(_In_ QWORD va, _In_ QWORD qwEntry) /* * Retrieve a single PVMM_MAP_HEAPENTRY for a given HeapMap and heap virtual address. +* -- H * -- pHeapMap * -- vaHeap = virtual address of heap OR heap id. * -- return = PTR to VMM_MAP_HEAPENTRY or NULL on fail. Must not be used out of pHeapMap scope. */ -PVMM_MAP_HEAPENTRY VmmMap_GetHeapEntry(_In_ PVMMOB_MAP_HEAP pHeapMap, _In_ QWORD vaHeap) +PVMM_MAP_HEAPENTRY VmmMap_GetHeapEntry(_In_ VMM_HANDLE H, _In_ PVMMOB_MAP_HEAP pHeapMap, _In_ QWORD vaHeap) { DWORD i; if(vaHeap > 0x1000) { @@ -2609,14 +2511,15 @@ PVMM_MAP_HEAPENTRY VmmMap_GetHeapEntry(_In_ PVMMOB_MAP_HEAP pHeapMap, _In_ QWORD /* * Retrieve the heap alloc map. (memory allocations in the specified heap). * CALLER DECREF: ppObHeapAllocMap +* -- H * -- pProcess * -- ppObHeapAllocMap * -- return */ _Success_(return) -BOOL VmmMap_GetHeapAlloc(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaHeap, _Out_ PVMMOB_MAP_HEAPALLOC *ppObHeapAllocMap) +BOOL VmmMap_GetHeapAlloc(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD vaHeap, _Out_ PVMMOB_MAP_HEAPALLOC *ppObHeapAllocMap) { - *ppObHeapAllocMap = VmmHeapAlloc_Initialize(pProcess, vaHeap); + *ppObHeapAllocMap = VmmHeapAlloc_Initialize(H, pProcess, vaHeap); return *ppObHeapAllocMap != NULL; } @@ -2628,11 +2531,12 @@ int VmmMap_GetHeapAllocEntry_CmpFind(_In_ QWORD va, _In_ QWORD qwEntry) /* * Retrieve a single PVMM_MAP_HEAPALLOCENTRY for a given HeapAllocMap and a memory allocation address. +* -- H * -- pHeapAllocMap * -- vaAlloc * -- return = PTR to PVMM_MAP_HEAPALLOCENTRY or NULL on fail. Must not be used out of pHeapAllocMap scope. */ -PVMM_MAP_HEAPALLOCENTRY VmmMap_GetHeapAllocEntry(_In_ PVMMOB_MAP_HEAPALLOC pHeapAllocMap, _In_ QWORD vaAlloc) +PVMM_MAP_HEAPALLOCENTRY VmmMap_GetHeapAllocEntry(_In_ VMM_HANDLE H, _In_ PVMMOB_MAP_HEAPALLOC pHeapAllocMap, _In_ QWORD vaAlloc) { return Util_qfind(vaAlloc, pHeapAllocMap->cMap, pHeapAllocMap->pMap, sizeof(VMM_MAP_HEAPALLOCENTRY), VmmMap_GetHeapAllocEntry_CmpFind); } @@ -2640,14 +2544,15 @@ PVMM_MAP_HEAPALLOCENTRY VmmMap_GetHeapAllocEntry(_In_ PVMMOB_MAP_HEAPALLOC pHeap /* * Retrieve the thread map. * CALLER DECREF: ppObThreadMap +* -- H * -- pProcess * -- ppObThreadMap * -- return */ _Success_(return) -BOOL VmmMap_GetThread(_In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_THREAD *ppObThreadMap) +BOOL VmmMap_GetThread(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_THREAD *ppObThreadMap) { - if(!pProcess->Map.pObThread && !VmmWinThread_Initialize(pProcess)) { return FALSE; } + if(!pProcess->Map.pObThread && !VmmWinThread_Initialize(H, pProcess)) { return FALSE; } *ppObThreadMap = Ob_INCREF(pProcess->Map.pObThread); return *ppObThreadMap ? TRUE : FALSE; } @@ -2660,11 +2565,12 @@ int VmmMap_GetThreadEntry_CmpFind(_In_ QWORD dwTID, _In_ QWORD qwEntry) /* * Retrieve a single PVMM_MAP_THREADENTRY for a given ThreadMap and ThreadID. +* -- H * -- pThreadMap * -- dwTID * -- return = PTR to VMM_MAP_THREADENTRY or NULL on fail. Must not be used out of pThreadMap scope. */ -PVMM_MAP_THREADENTRY VmmMap_GetThreadEntry(_In_ PVMMOB_MAP_THREAD pThreadMap, _In_ DWORD dwTID) +PVMM_MAP_THREADENTRY VmmMap_GetThreadEntry(_In_ VMM_HANDLE H, _In_ PVMMOB_MAP_THREAD pThreadMap, _In_ DWORD dwTID) { return Util_qfind((QWORD)dwTID, pThreadMap->cMap, pThreadMap->pMap, sizeof(VMM_MAP_THREADENTRY), VmmMap_GetThreadEntry_CmpFind); } @@ -2672,15 +2578,16 @@ PVMM_MAP_THREADENTRY VmmMap_GetThreadEntry(_In_ PVMMOB_MAP_THREAD pThreadMap, _I /* * Retrieve the HANDLE map * CALLER DECREF: ppObHandleMap +* -- H * -- pProcess * -- ppObHandleMap * -- fExtendedText * -- return */ _Success_(return) -BOOL VmmMap_GetHandle(_In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_HANDLE *ppObHandleMap, _In_ BOOL fExtendedText) +BOOL VmmMap_GetHandle(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_HANDLE *ppObHandleMap, _In_ BOOL fExtendedText) { - if(!VmmWinHandle_Initialize(pProcess, fExtendedText)) { return FALSE; } + if(!VmmWinHandle_Initialize(H, pProcess, fExtendedText)) { return FALSE; } *ppObHandleMap = Ob_INCREF(pProcess->Map.pObHandle); return *ppObHandleMap != NULL; } @@ -2688,28 +2595,30 @@ BOOL VmmMap_GetHandle(_In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_HANDLE *ppObH /* * Retrieve the EVIL map * CALLER DECREF: ppObEvilMap +* -- H * -- pProcess = retrieve for specific process, or if NULL for all processes. * -- ppObEvilMap * -- return */ _Success_(return) -BOOL VmmMap_GetEvil(_In_opt_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_EVIL *ppObEvilMap) +BOOL VmmMap_GetEvil(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_EVIL *ppObEvilMap) { - *ppObEvilMap = VmmEvil_Initialize(pProcess); + *ppObEvilMap = VmmEvil_Initialize(H, pProcess); return *ppObEvilMap != NULL; } /* * Retrieve the Physical Memory Map. * CALLER DECREF: ppObPhysMem +* -- H * -- ppObPhysMem * -- return */ _Success_(return) -BOOL VmmMap_GetPhysMem(_Out_ PVMMOB_MAP_PHYSMEM *ppObPhysMem) +BOOL VmmMap_GetPhysMem(_In_ VMM_HANDLE H, _Out_ PVMMOB_MAP_PHYSMEM *ppObPhysMem) { - if(!(*ppObPhysMem = ObContainer_GetOb(ctxVmm->pObCMapPhysMem))) { - *ppObPhysMem = VmmWinPhysMemMap_Initialize(); + if(!(*ppObPhysMem = ObContainer_GetOb(H->vmm.pObCMapPhysMem))) { + *ppObPhysMem = VmmWinPhysMemMap_Initialize(H); } return *ppObPhysMem != NULL; } @@ -2717,14 +2626,15 @@ BOOL VmmMap_GetPhysMem(_Out_ PVMMOB_MAP_PHYSMEM *ppObPhysMem) /* * Retrieve the USER map * CALLER DECREF: ppObUserMap +* -- H * -- ppObUserMap * -- return */ _Success_(return) -BOOL VmmMap_GetUser(_Out_ PVMMOB_MAP_USER *ppObUserMap) +BOOL VmmMap_GetUser(_In_ VMM_HANDLE H, _Out_ PVMMOB_MAP_USER *ppObUserMap) { - if(!(*ppObUserMap = ObContainer_GetOb(ctxVmm->pObCMapUser))) { - *ppObUserMap = VmmWinUser_Initialize(); + if(!(*ppObUserMap = ObContainer_GetOb(H->vmm.pObCMapUser))) { + *ppObUserMap = VmmWinUser_Initialize(H); } return *ppObUserMap != NULL; } @@ -2732,14 +2642,15 @@ BOOL VmmMap_GetUser(_Out_ PVMMOB_MAP_USER *ppObUserMap) /* * Retrieve the OBJECT MANAGER map * CALLER DECREF: ppObObjectMap +* -- H * -- ppObObjectMap * -- return */ _Success_(return) -BOOL VmmMap_GetObject(_Out_ PVMMOB_MAP_OBJECT *ppObObjectMap) +BOOL VmmMap_GetObject(_In_ VMM_HANDLE H, _Out_ PVMMOB_MAP_OBJECT *ppObObjectMap) { - if(!(*ppObObjectMap = ObContainer_GetOb(ctxVmm->pObCMapObject))) { - *ppObObjectMap = VmmWinObjMgr_Initialize(); + if(!(*ppObObjectMap = ObContainer_GetOb(H->vmm.pObCMapObject))) { + *ppObObjectMap = VmmWinObjMgr_Initialize(H); } return *ppObObjectMap != NULL; } @@ -2747,27 +2658,29 @@ BOOL VmmMap_GetObject(_Out_ PVMMOB_MAP_OBJECT *ppObObjectMap) /* * Retrieve the KERNEL DRIVER map * CALLER DECREF: ppObKDriverMap +* -- H * -- ppObKDriverMap * -- return */ _Success_(return) -BOOL VmmMap_GetKDriver(_Out_ PVMMOB_MAP_KDRIVER *ppObKDriverMap) +BOOL VmmMap_GetKDriver(_In_ VMM_HANDLE H, _Out_ PVMMOB_MAP_KDRIVER *ppObKDriverMap) { - if(!(*ppObKDriverMap = ObContainer_GetOb(ctxVmm->pObCMapKDriver))) { - *ppObKDriverMap = VmmWinObjKDrv_Initialize(); + if(!(*ppObKDriverMap = ObContainer_GetOb(H->vmm.pObCMapKDriver))) { + *ppObKDriverMap = VmmWinObjKDrv_Initialize(H); } return *ppObKDriverMap != NULL; } /* * Retrieve the index of a VMM_MAP_POOLENTRYTAG within the PVMMOB_MAP_POOL. +* -- H * -- pPoolMap * -- dwPoolTag * -- pdwTagIndex * -- return */ _Success_(return) -BOOL VmmMap_GetPoolTag(_In_ PVMMOB_MAP_POOL pPoolMap, _In_ DWORD dwPoolTag, _Out_ PDWORD pdwTagIndex) +BOOL VmmMap_GetPoolTag(_In_ VMM_HANDLE H, _In_ PVMMOB_MAP_POOL pPoolMap, _In_ DWORD dwPoolTag, _Out_ PDWORD pdwTagIndex) { PVMM_MAP_POOLENTRYTAG pet; if(!(pet = Util_qfind((QWORD)dwPoolTag, pPoolMap->cTag, pPoolMap->pTag, sizeof(VMM_MAP_POOLENTRYTAG), Util_qfind_CmpFindTableDWORD))) { @@ -2781,13 +2694,14 @@ BOOL VmmMap_GetPoolTag(_In_ PVMMOB_MAP_POOL pPoolMap, _In_ DWORD dwPoolTag, _Out /* * Retrieve the index of a VMM_MAP_POOLENTRY within the PVMMOB_MAP_POOL. +* -- H * -- pPoolMap * -- vaPoolEntry * -- pdwEntryIndex * -- return */ _Success_(return) -BOOL VmmMap_GetPoolEntry(_In_ PVMMOB_MAP_POOL pPoolMap, _In_ QWORD vaPoolEntry, _Out_ PDWORD pdwEntryIndex) +BOOL VmmMap_GetPoolEntry(_In_ VMM_HANDLE H, _In_ PVMMOB_MAP_POOL pPoolMap, _In_ QWORD vaPoolEntry, _Out_ PDWORD pdwEntryIndex) { PVMM_MAP_POOLENTRY pe = Util_qfind(vaPoolEntry, pPoolMap->cMap, pPoolMap->pMap, sizeof(VMM_MAP_POOLENTRY), Util_qfind_CmpFindTableQWORD); if(!pe) { return FALSE; } @@ -2798,16 +2712,17 @@ BOOL VmmMap_GetPoolEntry(_In_ PVMMOB_MAP_POOL pPoolMap, _In_ QWORD vaPoolEntry, /* * Retrieve the POOL map. * CALLER DECREF: ppObPoolMap +* -- H * -- ppObPoolMap * -- fAll = TRUE: retrieve all pools; FALSE: retrieve big page pool only. * -- return */ _Success_(return) -BOOL VmmMap_GetPool(_Out_ PVMMOB_MAP_POOL *ppObPoolMap, _In_ BOOL fAll) +BOOL VmmMap_GetPool(_In_ VMM_HANDLE H, _Out_ PVMMOB_MAP_POOL *ppObPoolMap, _In_ BOOL fAll) { - *ppObPoolMap = fAll ? ObContainer_GetOb(ctxVmm->pObCMapPoolAll) : ObContainer_GetOb(ctxVmm->pObCMapPoolBig); + *ppObPoolMap = fAll ? ObContainer_GetOb(H->vmm.pObCMapPoolAll) : ObContainer_GetOb(H->vmm.pObCMapPoolBig); if(!*ppObPoolMap) { - *ppObPoolMap = VmmWinPool_Initialize(fAll); + *ppObPoolMap = VmmWinPool_Initialize(H, fAll); } return *ppObPoolMap != NULL; } @@ -2815,14 +2730,15 @@ BOOL VmmMap_GetPool(_Out_ PVMMOB_MAP_POOL *ppObPoolMap, _In_ BOOL fAll) /* * Retrieve the NETWORK CONNECTION map * CALLER DECREF: ppObNetMap +* -- H * -- ppObNetMap * -- return */ _Success_(return) -BOOL VmmMap_GetNet(_Out_ PVMMOB_MAP_NET *ppObNetMap) +BOOL VmmMap_GetNet(_In_ VMM_HANDLE H, _Out_ PVMMOB_MAP_NET *ppObNetMap) { - if(!(*ppObNetMap = ObContainer_GetOb(ctxVmm->pObCMapNet))) { - *ppObNetMap = VmmNet_Initialize(); + if(!(*ppObNetMap = ObContainer_GetOb(H->vmm.pObCMapNet))) { + *ppObNetMap = VmmNet_Initialize(H); } return *ppObNetMap != NULL; } @@ -2830,14 +2746,15 @@ BOOL VmmMap_GetNet(_Out_ PVMMOB_MAP_NET *ppObNetMap) /* * Retrieve the SERVICES map * CALLER DECREF: ppObServiceMap +* -- H * -- ppObServiceMap * -- return */ _Success_(return) -BOOL VmmMap_GetService(_Out_ PVMMOB_MAP_SERVICE *ppObServiceMap) +BOOL VmmMap_GetService(_In_ VMM_HANDLE H, _Out_ PVMMOB_MAP_SERVICE *ppObServiceMap) { - if(!(*ppObServiceMap = ObContainer_GetOb(ctxVmm->pObCMapService))) { - *ppObServiceMap = VmmWinSvc_Initialize(); + if(!(*ppObServiceMap = ObContainer_GetOb(H->vmm.pObCMapService))) { + *ppObServiceMap = VmmWinSvc_Initialize(H); } return *ppObServiceMap != NULL; } diff --git a/vmm/vmm.h b/vmm/vmm.h index 9aa7729..5b068c2 100644 --- a/vmm/vmm.h +++ b/vmm/vmm.h @@ -16,12 +16,18 @@ #define STRINGIZE(s) STRINGIZE2(s) #endif /* STRINGIZE2 */ +#ifndef VMM_STRLEN +#define VMM_STRLEN(s) (sizeof(s)/sizeof(s[0])-1) +#endif /* VMM_STRLEN */ + // ---------------------------------------------------------------------------- // VMM configuration constants and struct definitions below: // ---------------------------------------------------------------------------- +#define VMM_MAGIC 0xf3dc0fefea1e6601 + #define VMM_STATUS_SUCCESS STATUS_SUCCESS #define VMM_STATUS_UNSUCCESSFUL STATUS_UNSUCCESSFUL #define VMM_STATUS_END_OF_FILE STATUS_END_OF_FILE @@ -42,10 +48,6 @@ #define VMM_MEMMAP_FLAG_SCAN_PE 0x0002 #define VMM_MEMMAP_FLAG_ALL (VMM_MEMMAP_FLAG_MODULES | VMM_MEMMAP_FLAG_SCAN_PE) -#define VMM_CACHE_TABLESIZE 0x4011 // (not even # to prevent clogging at specific table 'hash' buckets) -#define VMM_CACHE_TLB_ENTRIES 0x4000 // -> 64MB of cached data -#define VMM_CACHE_PHYS_ENTRIES 0x4000 // -> 64MB of cached data - #define VMM_WORK_THREADPOOL_NUM_THREADS 0x20 #define VMM_FLAG_NOCACHE 0x00000001 // do not use the data cache (force reading from memory acquisition device). @@ -64,7 +66,7 @@ #define VMM_POOLTAG(v, tag) (v == _byteswap_ulong(tag)) #define VMM_POOLTAG_SHORT(v, tag) ((v & 0x00ffffff) == (_byteswap_ulong(tag) & 0x00ffffff)) -#define VMM_POOLTAG_PREPENDED(pb, o, tag) (VMM_POOLTAG(*(PDWORD)(pb + o - (ctxVmm->f32 ? 4 : 12)), tag)) +#define VMM_POOLTAG_PREPENDED(f32, pb, o, tag) (VMM_POOLTAG(*(PDWORD)(pb + o - (f32 ? 4 : 12)), tag)) #define VMM_PTR_OFFSET(f32, pb, o) ((f32) ? *(PDWORD)((o) + (PBYTE)(pb)) : *(PQWORD)((o) + (PBYTE)(pb))) #define VMM_PTR_OFFSET_DUAL(f32, pb, o32, o64) ((f32) ? *(PDWORD)((o32) + (PBYTE)(pb)) : *(PQWORD)((o64) + (PBYTE)(pb))) #define VMM_PTR_OFFSET_EX_FAST_REF(f32, pb, o) ((f32) ? (~0x7 & *(PDWORD)((o) + (PBYTE)(pb))) : (~0xfULL & *(PQWORD)((o) + (PBYTE)(pb)))) @@ -87,14 +89,14 @@ #define VMM_UADDR64_16(va) ((va) && (((va) & 0xffff80000000000f) == 0)) #define VMM_UADDR64_PAGE(va) ((va) && (((va) & 0xffff800000000fff) == 0)) -#define VMM_KADDR(va) (ctxVmm->f32 ? VMM_KADDR32(va) : VMM_KADDR64(va)) -#define VMM_KADDR_4_8(va) (ctxVmm->f32 ? VMM_KADDR32_4(va) : VMM_KADDR64_8(va)) -#define VMM_KADDR_8_16(va) (ctxVmm->f32 ? VMM_KADDR32_8(va) : VMM_KADDR64_16(va)) -#define VMM_KADDR_PAGE(va) (ctxVmm->f32 ? VMM_KADDR32_PAGE(va) : VMM_KADDR64_PAGE(va)) -#define VMM_UADDR(va) (ctxVmm->f32 ? VMM_UADDR32(va) : VMM_UADDR64(va)) -#define VMM_UADDR_4_8(va) (ctxVmm->f32 ? VMM_UADDR32_4(va) : VMM_UADDR64_8(va)) -#define VMM_UADDR_8_16(va) (ctxVmm->f32 ? VMM_UADDR32_8(va) : VMM_UADDR64_16(va)) -#define VMM_UADDR_PAGE(va) (ctxVmm->f32 ? VMM_UADDR32_PAGE(va) : VMM_UADDR64_PAGE(va)) +#define VMM_KADDR(f32, va) (f32 ? VMM_KADDR32(va) : VMM_KADDR64(va)) +#define VMM_KADDR_4_8(f32, va) (f32 ? VMM_KADDR32_4(va) : VMM_KADDR64_8(va)) +#define VMM_KADDR_8_16(f32, va) (f32 ? VMM_KADDR32_8(va) : VMM_KADDR64_16(va)) +#define VMM_KADDR_PAGE(f32, va) (f32 ? VMM_KADDR32_PAGE(va) : VMM_KADDR64_PAGE(va)) +#define VMM_UADDR(f32, va) (f32 ? VMM_UADDR32(va) : VMM_UADDR64(va)) +#define VMM_UADDR_4_8(f32, va) (f32 ? VMM_UADDR32_4(va) : VMM_UADDR64_8(va)) +#define VMM_UADDR_8_16(f32, va) (f32 ? VMM_UADDR32_8(va) : VMM_UADDR64_16(va)) +#define VMM_UADDR_PAGE(f32, va) (f32 ? VMM_UADDR32_PAGE(va) : VMM_UADDR64_PAGE(va)) #define VMM_KADDR_DUAL(f32, va) (f32 ? VMM_KADDR32(va) : VMM_KADDR64(va)) #define VMM_KADDR_DUAL_4_8(f32, va) (f32 ? VMM_KADDR32_4(va) : VMM_KADDR64_8(va)) @@ -482,10 +484,12 @@ typedef struct tdVMM_MAP_HANDLEENTRY { union { struct { DWORD cb; + DWORD dwoName; // offset in bytes to file object text start in uszText (if any) usually 0. } _InfoFile; struct { + QWORD qw3; QWORD qw2; - DWORD dw2; + DWORD dw3; DWORD dw; QWORD qw; } _Reserved; @@ -644,36 +648,39 @@ typedef struct tdVMM_MAP_SERVICEENTRY { QWORD _Reserved; } VMM_MAP_SERVICEENTRY, *PVMM_MAP_SERVICEENTRY; -typedef enum tdVMM_EVIL_TP { // EVIL types - sorted by "evilness" - VMM_EVIL_TP_PE_NA = 0, // _NA - VMM_EVIL_TP_PE_INJECTED = 1, // MODULE - VMM_EVIL_TP_PROC_NOLINK = 2, // _NA - VMM_EVIL_TP_PROC_PARENT = 3, // _NA - VMM_EVIL_TP_PROC_USER = 4, // _NA - VMM_EVIL_TP_PEB_MASQUERADE = 5, // _NA - VMM_EVIL_TP_PEB_BAD_LDR = 6, // _NA - VMM_EVIL_TP_PE_NOTLINKED = 7, // MODULE - VMM_EVIL_TP_VAD_PATCHED_PE = 8, // VADEX - VMM_EVIL_TP_VAD_PRIVATE_RWX = 9, // VADEX - VMM_EVIL_TP_VAD_NOIMAGE_RWX = 10, // VADEX - VMM_EVIL_TP_VAD_PRIVATE_RX = 11, // VADEX - VMM_EVIL_TP_VAD_NOIMAGE_RX = 12, // VADEX +typedef enum tdVMM_EVIL_TP { // EVIL types - sorted by "evilness" + VMM_EVIL_TP_PE_NA, // _NA + VMM_EVIL_TP_PE_INJECTED, // MODULE + VMM_EVIL_TP_PROC_NOLINK, // _NA + VMM_EVIL_TP_PROC_PARENT, // _NA + VMM_EVIL_TP_PROC_USER, // _NA + VMM_EVIL_TP_PEB_MASQUERADE, // _NA + VMM_EVIL_TP_DRIVER_PATH, // TEXT + VMM_EVIL_TP_PEB_BAD_LDR, // _NA + VMM_EVIL_TP_PE_NOTLINKED, // MODULE + VMM_EVIL_TP_VAD_PATCHED_PE, // VADEX + VMM_EVIL_TP_VAD_PRIVATE_RWX, // VADEX + VMM_EVIL_TP_VAD_NOIMAGE_RWX, // VADEX + VMM_EVIL_TP_VAD_PRIVATE_RX, // VADEX + VMM_EVIL_TP_VAD_NOIMAGE_RX, // VADEX + VMM_EVIL_TP_MAX } VMM_EVIL_TP; -static LPCSTR VMM_EVIL_TP_STRING[] = { - "UNKNOWN ", - "PE_INJECT ", - "PROC_NOLINK", - "PROC_PARENT", - "PROC_USER ", - "PEB_MASQ ", - "PEB_BAD_LDR", - "PE_NOLINK ", - "PE_PATCHED ", - "PRIVATE_RWX", - "NOIMAGE_RWX", - "PRIVATE_RX ", - "NOIMAGE_RX " +static LPCSTR VMM_EVIL_TP_STRING[VMM_EVIL_TP_MAX] = { + [VMM_EVIL_TP_PE_NA] = "UNKNOWN", + [VMM_EVIL_TP_PE_INJECTED] = "PE_INJECT", + [VMM_EVIL_TP_PROC_NOLINK] = "PROC_NOLINK", + [VMM_EVIL_TP_PROC_PARENT] = "PROC_PARENT", + [VMM_EVIL_TP_PROC_USER] = "PROC_USER", + [VMM_EVIL_TP_PEB_MASQUERADE] = "PEB_MASQ", + [VMM_EVIL_TP_DRIVER_PATH] = "DRIVER_PATH", + [VMM_EVIL_TP_PEB_BAD_LDR] = "PEB_BAD_LDR", + [VMM_EVIL_TP_PE_NOTLINKED] = "PE_NOLINK", + [VMM_EVIL_TP_VAD_PATCHED_PE] = "PE_PATCHED", + [VMM_EVIL_TP_VAD_PRIVATE_RWX] = "PRIVATE_RWX", + [VMM_EVIL_TP_VAD_NOIMAGE_RWX] = "NOIMAGE_RWX", + [VMM_EVIL_TP_VAD_PRIVATE_RX] = "PRIVATE_RX", + [VMM_EVIL_TP_VAD_NOIMAGE_RX] = "NOIMAGE_RX", }; typedef struct tdVMM_MAP_EVILENTRY { @@ -689,6 +696,8 @@ typedef struct tdVMM_MAP_EVILENTRY { WORD wPatchOffset; WORD wPatchByteCount; } VAD_PATCHED_PE; + DWORD cbuText; + LPSTR uszText; } VMM_MAP_EVILENTRY, *PVMM_MAP_EVILENTRY; typedef struct tdVMMOB_MAP_PTE { @@ -721,7 +730,7 @@ typedef struct tdVMMOB_MAP_VADEX { typedef struct tdVMMOB_MAP_MODULE { OB ObHdr; PQWORD pHashTableLookup; - PBYTE pbMultiText; // UTF-8 multi-string into by VMM_MAP_MODULEENTRY.usz* + PBYTE pbMultiText; // UTF-8 multi-string into by VMM_MAP_MODULEENTRY.usz* DWORD cbMultiText; DWORD cMap; // # map entries. VMM_MAP_MODULEENTRY pMap[]; // map entries. @@ -852,6 +861,8 @@ typedef struct tdVMMOB_MAP_SERVICE { typedef struct tdVMMOB_MAP_EVIL { OB ObHdr; QWORD tcCreateTime; // create timestamp [internally used only] + PBYTE pbMultiText; // multi-str pointed into by VMM_MAP_EVILENTRY.usz* + DWORD cbMultiText; DWORD cMap; // # map entries. VMM_MAP_EVILENTRY pMap[]; // map entries. } VMMOB_MAP_EVIL, *PVMMOB_MAP_EVIL; @@ -1011,13 +1022,16 @@ typedef struct tdVMMOB_PROCESS_TABLE { POB_CONTAINER pObCNewPROC; // contains VMM_PROCESS_TABLE } VMMOB_PROCESS_TABLE, *PVMMOB_PROCESS_TABLE; -#define VMM_CACHE_REGIONS 3 -#define VMM_CACHE_REGION_MEMS 0x5000 -#define VMM_CACHE_BUCKETS 0x5000 +#define VMM_CACHE_REGIONS 3 +#define VMM_CACHE_REGION_MEMS_INITALLOC FALSE +#define VMM_CACHE_REGION_MEMS_PHYS 0x5000 +#define VMM_CACHE_REGION_MEMS_TLB 0x3000 +#define VMM_CACHE_REGION_MEMS_PAGING 0x2000 +#define VMM_CACHE_BUCKETS 0x5000 -#define VMM_CACHE_TAG_PHYS 'CaPh' -#define VMM_CACHE_TAG_PAGING 'CaPg' -#define VMM_CACHE_TAG_TLB 'CaTb' +#define VMM_CACHE_TAG_PHYS 'CaPh' +#define VMM_CACHE_TAG_PAGING 'CaPg' +#define VMM_CACHE_TAG_TLB 'CaTb' typedef struct tdVMMOB_CACHE_MEM { OB Ob; @@ -1050,6 +1064,7 @@ typedef struct tdVMM_CACHE_TABLE { BOOL fActive; DWORD tag; DWORD iR; + DWORD cMaxMems; BOOL fAllActiveRegions; CRITICAL_SECTION Lock; VMM_CACHE_REGION R[VMM_CACHE_REGIONS]; @@ -1064,20 +1079,20 @@ typedef struct tdVMM_VIRT2PHYS_INFORMATION { } VMM_VIRT2PHYS_INFORMATION, *PVMM_VIRT2PHYS_INFORMATION; typedef struct tdVMM_MEMORYMODEL_FUNCTIONS { - VOID(*pfnClose)(); - BOOL(*pfnVirt2Phys)(_In_ QWORD paDTB, _In_ BOOL fUserOnly, _In_ BYTE iPML, _In_ QWORD va, _Out_ PQWORD ppa); - VOID(*pfnVirt2PhysVadEx)(_In_ QWORD paPT, _Inout_ PVMMOB_MAP_VADEX pVadEx, _In_ BYTE iPML, _Inout_ PDWORD piVadEx); - VOID(*pfnVirt2PhysGetInformation)(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo); - VOID(*pfnPhys2VirtGetInformation)(_In_ PVMM_PROCESS pProcess, _Inout_ PVMMOB_PHYS2VIRT_INFORMATION pP2V); - BOOL(*pfnPteMapInitialize)(_In_ PVMM_PROCESS pProcess); - VOID(*pfnTlbSpider)(_In_ PVMM_PROCESS pProcess); - BOOL(*pfnTlbPageTableVerify)(_Inout_ PBYTE pb, _In_ QWORD pa, _In_ BOOL fSelfRefReq); - BOOL(*pfnPagedRead)(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD va, _In_ QWORD pte, _Out_writes_opt_(4096) PBYTE pbPage, _Out_ PQWORD ppa, _Inout_opt_ PVMM_PTE_TP ptp, _In_ QWORD flags); -} VMM_MEMORYMODEL_FUNCTIONS; + VOID(*pfnClose)(_In_ VMM_HANDLE H); + BOOL(*pfnVirt2Phys)(_In_ VMM_HANDLE H, _In_ QWORD paDTB, _In_ BOOL fUserOnly, _In_ BYTE iPML, _In_ QWORD va, _Out_ PQWORD ppa); + VOID(*pfnVirt2PhysVadEx)(_In_ VMM_HANDLE H, _In_ QWORD paPT, _Inout_ PVMMOB_MAP_VADEX pVadEx, _In_ BYTE iPML, _Inout_ PDWORD piVadEx); + VOID(*pfnVirt2PhysGetInformation)(_In_ VMM_HANDLE H, _Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo); + VOID(*pfnPhys2VirtGetInformation)(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Inout_ PVMMOB_PHYS2VIRT_INFORMATION pP2V); + BOOL(*pfnPteMapInitialize)(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess); + VOID(*pfnTlbSpider)(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess); + BOOL(*pfnTlbPageTableVerify)(_In_ VMM_HANDLE H, _Inout_ PBYTE pb, _In_ QWORD pa, _In_ BOOL fSelfRefReq); + BOOL(*pfnPagedRead)(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ QWORD va, _In_ QWORD pte, _Out_writes_opt_(4096) PBYTE pbPage, _Out_ PQWORD ppa, _Inout_opt_ PVMM_PTE_TP ptp, _In_ QWORD flags); +} VMM_MEMORYMODEL_FUNCTIONS, *PVMM_MEMORYMODEL_FUNCTIONS; #define VMM_EPROCESS_DWORD(pProcess, offset) (*(PDWORD)(pProcess->win.EPROCESS.pb + offset)) #define VMM_EPROCESS_QWORD(pProcess, offset) (*(PQWORD)(pProcess->win.EPROCESS.pb + offset)) -#define VMM_EPROCESS_PTR(pProcess, offset) (ctxVmm->f32 ? VMM_EPROCESS_DWORD(pProcess, offset) : VMM_EPROCESS_QWORD(pProcess, offset)) +#define VMM_EPROCESS_PTR(f32, pProcess, offset) (f32 ? VMM_EPROCESS_DWORD(pProcess, offset) : VMM_EPROCESS_QWORD(pProcess, offset)) @@ -1085,7 +1100,7 @@ typedef struct tdVMM_MEMORYMODEL_FUNCTIONS { // VMM general constants and struct definitions below: // ---------------------------------------------------------------------------- -typedef struct tdVmmConfig { +typedef struct tdVMMCONFIG { QWORD paCR3; DWORD tpForensicMode; // command line forensic mode // flags below @@ -1110,6 +1125,15 @@ typedef struct tdVmmConfig { CHAR szLogLevel[MAX_PATH]; } VMMCONFIG, *PVMMCONFIG; +typedef struct tdVMMCONFIG_PDB { + BOOL fInitialized; + BOOL fEnable; + BOOL fServerEnable; + CHAR szLocal[MAX_PATH]; + CHAR szServer[MAX_PATH]; + CHAR szSymbolPath[MAX_PATH]; +} VMMCONFIG_PDB, *PVMMCONFIG_PDB; + typedef struct tdVMM_STATISTICS { QWORD cPhysCacheHit; QWORD cPhysReadSuccess; @@ -1372,7 +1396,16 @@ typedef struct tdVMM_DYNAMIC_LOAD_FUNCTIONS { VMMFN_RtlDecompressBuffer *RtlDecompressBufferOpt; // ntdll.dll!RtlDecompressBuffer } VMM_DYNAMIC_LOAD_FUNCTIONS; +// forward declarations of non-public types: +typedef struct tdVMMWORK_CONTEXT *PVMMWORK_CONTEXT; +typedef struct tdFC_CONTEXT *PFC_CONTEXT; +typedef struct tdVMMLOG_CONTEXT *PVMMLOG_CONTEXT; +typedef struct tdVMMSTATISTICS_CALL_CONTEXT *PVMMSTATISTICS_CALL_CONTEXT; +typedef struct tdMMWIN_CONTEXT *PMMWIN_CONTEXT; + +// main vmm context typedef struct tdVMM_CONTEXT { + BOOL fInitializationStatus; HMODULE hModuleVmmOpt; // only on _WIN32 builds! :: do not call FreeLibrary on hModuleVmm CRITICAL_SECTION LockMaster; CRITICAL_SECTION LockPlugin; @@ -1405,7 +1438,7 @@ typedef struct tdVMM_CONTEXT { POB pObVfsDumpContext; POB pObPfnContext; POB pObPdbContext; - PVOID pMmContext; + PMMWIN_CONTEXT pMmContext; PVOID pNetContext; struct { BYTE cProgressPercent; @@ -1424,11 +1457,9 @@ typedef struct tdVMM_CONTEXT { PVOID FLinkForensic; PVOID Root; PVOID Proc; - struct { - DWORD cEvent; - HANDLE hEvent[MAXIMUM_WAIT_OBJECTS]; - } fc; DWORD dwNextMID; + DWORD cIngestPhysmem; + DWORD cIngestVirtmem; } PluginManager; CRITICAL_SECTION LockUpdateMap; // lock for global maps - such as MapUser CRITICAL_SECTION LockUpdateModule; // lock for internal modules @@ -1451,6 +1482,7 @@ typedef struct tdVMM_CONTEXT { POB_CACHEMAP pObCacheMapIAT; POB_CACHEMAP pObCacheMapHeapAlloc; POB_CACHEMAP pObCacheMapWinObjDisplay; + POB_CACHEMAP pObCacheMapObCompressedShared; // page caches struct { VMM_CACHE_TABLE PHYS; @@ -1459,40 +1491,31 @@ typedef struct tdVMM_CONTEXT { POB_SET PAGING_FAILED; POB_MAP pmPrototypePte; // map with mm_vad.c managed data } Cache; - // worker threads - struct { - BOOL fEnabled; - POB_SET psThreadAll; - POB_SET psThreadAvail; - POB_SET psUnit; - } Work; WCHAR _EmptyWCHAR; VMMWIN_OBJECT_TYPE_TABLE ObjectTypeTable; } VMM_CONTEXT, *PVMM_CONTEXT; -typedef struct tdVMM_MAIN_CONTEXT { - VMMCONFIG cfg; +typedef struct tdVMM_HANDLE { + // core: + QWORD magic; + BOOL fAbort; + DWORD cThreadExternal; + DWORD cThreadInternal; + PVMMWORK_CONTEXT work; + // leechcore & config HANDLE hLC; LC_CONFIG dev; - struct { - BOOL fInitialized; - BOOL fEnable; - BOOL fServerEnable; - CHAR szLocal[MAX_PATH]; - CHAR szServer[MAX_PATH]; - CHAR szSymbolPath[MAX_PATH]; - } pdb; - PVOID pvStatistics; -} VMM_MAIN_CONTEXT, *PVMM_MAIN_CONTEXT; - - - -// ---------------------------------------------------------------------------- -// VMM global variables below: -// ---------------------------------------------------------------------------- - -extern PVMM_CONTEXT ctxVmm; -extern PVMM_MAIN_CONTEXT ctxMain; + VMMCONFIG cfg; + // utils: + VMMCONFIG_PDB pdb; + PVMMLOG_CONTEXT log; + DWORD logfilter; + PVMMSTATISTICS_CALL_CONTEXT statistics_call; + // forensic: + PFC_CONTEXT fc; + // vmm core: + VMM_CONTEXT vmm; +} *VMM_HANDLE; @@ -1504,14 +1527,16 @@ extern PVMM_MAIN_CONTEXT ctxMain; * Initialize a new VMM context. This must always be done before calling any * other VMM functions. An alternative way to do this is to call the function: * VmmProcInitialize. +* -- H * -- return */ -BOOL VmmInitialize(); +BOOL VmmInitialize(_In_ VMM_HANDLE H); /* * Close and clean up the VMM context inside the PCILeech context, if existing. +* -- H */ -VOID VmmClose(); +VOID VmmClose(_In_ VMM_HANDLE H); @@ -1522,46 +1547,42 @@ VOID VmmClose(); /* * Retrieve an item from the cache. * CALLER DECREF: return +* -- H * -- dwTblTag * -- qwA * -- return */ -PVMMOB_CACHE_MEM VmmCacheGet(_In_ DWORD dwTblTag, _In_ QWORD qwA); +PVMMOB_CACHE_MEM VmmCacheGet(_In_ VMM_HANDLE H, _In_ DWORD dwTblTag, _In_ QWORD qwA); /* * Retrieve a page table (0x1000 bytes) via the TLB cache. * CALLER DECREF: return +* -- H * -- pa * -- fCacheOnly = if set do not make a request to underlying device if not in cache. * -- return */ -PVMMOB_CACHE_MEM VmmTlbGetPageTable(_In_ QWORD pa, _In_ BOOL fCacheOnly); - -/* -* Check if an address page exists in the indicated cache. -* -- dwTblTag -* -- qwA -* -- return -*/ -BOOL VmmCacheExists(_In_ DWORD dwTblTag, _In_ QWORD qwA); +PVMMOB_CACHE_MEM VmmTlbGetPageTable(_In_ VMM_HANDLE H, _In_ QWORD pa, _In_ BOOL fCacheOnly); /* * Check out an empty memory cache item from the cache. NB! once the item is * filled (successfully or unsuccessfully) it must be returned to the cache with * VmmCacheReserveReturn and must _NOT_ otherwise be DEFREF'ed. * CALLER DECREF SPECIAL: return +* -- H * -- dwTblTag * -- return */ -PVMMOB_CACHE_MEM VmmCacheReserve(_In_ DWORD wTblTag); +PVMMOB_CACHE_MEM VmmCacheReserve(_In_ VMM_HANDLE H, _In_ DWORD wTblTag); /* * Return an entry retrieved with VmmCacheReserve to the cache. * NB! no other items may be returned with this function! * FUNCTION DECREF SPECIAL: pOb +* -- H * -- pOb */ -VOID VmmCacheReserveReturn(_In_opt_ PVMMOB_CACHE_MEM pOb); +VOID VmmCacheReserveReturn(_In_ VMM_HANDLE H, _In_opt_ PVMMOB_CACHE_MEM pOb); @@ -1571,18 +1592,20 @@ VOID VmmCacheReserveReturn(_In_opt_ PVMMOB_CACHE_MEM pOb); /* * Write a virtually contigious arbitrary amount of memory. +* -- H * -- pProcess * -- qwA * -- pb * -- cb * -- return = TRUE on success, FALSE on partial or zero write. */ -BOOL VmmWrite(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _In_reads_(cb) PBYTE pb, _In_ DWORD cb); +BOOL VmmWrite(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _In_reads_(cb) PBYTE pb, _In_ DWORD cb); /* * Read a contigious arbitrary amount of memory, virtual or physical. * Virtual memory is read if a process is specified in pProcess parameter. * Physical memory is read if NULL is specified in pProcess parameter. +* -- H * -- pProcess * -- qwA * -- pb @@ -1590,13 +1613,14 @@ BOOL VmmWrite(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _In_reads_(cb) PBY * -- return */ _Success_(return) -BOOL VmmRead(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb); +BOOL VmmRead(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb); /* * Identical functionality as provided by 'VmmRead' - but with flags parameter. * Read a contigious arbitrary amount of memory, virtual or physical. * Virtual memory is read if a process is specified in pProcess parameter. * Physical memory is read if NULL is specified in pProcess parameter. +* -- H * -- pProcess * -- qwA * -- pb @@ -1605,12 +1629,13 @@ BOOL VmmRead(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _Out_writes_(cb) PB * -- return */ _Success_(return) -BOOL VmmRead2(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _In_ QWORD flags); +BOOL VmmRead2(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _In_ QWORD flags); /* * Read memory and allocate the required buffer. Two additional null bytes are * also allocated on the returned buffer in case WCHAR-string data is read. * CALLER LocalFree: ppb +* -- H * -- pProcess * -- qwA * -- ppb = function allocated buffer - caller is responsible for LocalFree! @@ -1619,12 +1644,13 @@ BOOL VmmRead2(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _Out_writes_(cb) P * -- return = */ _Success_(return) -BOOL VmmReadAlloc(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _Out_ PBYTE *ppb, _In_ DWORD cb, _In_ QWORD flags); +BOOL VmmReadAlloc(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _Out_ PBYTE *ppb, _In_ DWORD cb, _In_ QWORD flags); /* * Read a Windows _UNICODE_STRING from into the function allocated buffer pwsz. * The allocated buffer is guaranteed to be NULL-terminated. * CALLER LocalFree: pwsz +* -- H * -- pProcess * -- f32 = 32/64-bit _UNICODE_STRING. * -- flags = = flags as in VMM_FLAG_* @@ -1635,12 +1661,13 @@ BOOL VmmReadAlloc(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _Out_ PBYTE *p * -- return */ _Success_(return) -BOOL VmmReadAllocUnicodeString(_In_ PVMM_PROCESS pProcess, _In_ BOOL f32, _In_ QWORD flags, _In_ QWORD vaUS, _In_ DWORD cchMax, _Out_opt_ LPWSTR *pwsz, _Out_opt_ PDWORD pcch); +BOOL VmmReadAllocUnicodeString(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ BOOL f32, _In_ QWORD flags, _In_ QWORD vaUS, _In_ DWORD cchMax, _Out_opt_ LPWSTR *pwsz, _Out_opt_ PDWORD pcch); /* * Read a Windows _UNICODE_STRING from into the function allocated buffer pusz. * The allocated buffer is guaranteed to be UTF8 and NULL terminated. * CALLER LocalFree: pusz +* -- H * -- pProcess * -- f32 = 32/64-bit _UNICODE_STRING. * -- flags = = flags as in VMM_FLAG_* @@ -1651,11 +1678,12 @@ BOOL VmmReadAllocUnicodeString(_In_ PVMM_PROCESS pProcess, _In_ BOOL f32, _In_ Q * -- return */ _Success_(return) -BOOL VmmReadAllocUnicodeStringAsUTF8(_In_ PVMM_PROCESS pProcess, _In_ BOOL f32, _In_ QWORD flags, _In_ QWORD vaUS, _In_ DWORD cchMax, _Out_opt_ LPSTR *pusz, _Out_opt_ PDWORD pcbu); +BOOL VmmReadAllocUnicodeStringAsUTF8(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ BOOL f32, _In_ QWORD flags, _In_ QWORD vaUS, _In_ DWORD cchMax, _Out_opt_ LPSTR *pusz, _Out_opt_ PDWORD pcbu); /* * Combines VmmRead2() and CharUtil_WtoU(). * CALLER LOCALFREE (if *pusz != pbBuffer): *pjsz +* -- H * -- pProcess * -- qwA * -- cb = max number of bytes to read. @@ -1671,6 +1699,7 @@ BOOL VmmReadAllocUnicodeStringAsUTF8(_In_ PVMM_PROCESS pProcess, _In_ BOOL f32, */ _Success_(return) BOOL VmmReadWtoU( + _In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _In_ DWORD cb, @@ -1687,6 +1716,7 @@ BOOL VmmReadWtoU( * the number of bytes read in pcbRead. * Virtual memory is read if a process is specified in pProcess. * Physical memory is read if NULL is specified in pProcess. +* -- H * -- pProcess = NULL=='physical memory read', PTR=='virtual memory read' * -- qwA * -- pb @@ -1694,7 +1724,7 @@ BOOL VmmReadWtoU( * -- pcbReadOpt * -- flags = flags as in VMM_FLAG_* */ -VOID VmmReadEx(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ QWORD flags); +VOID VmmReadEx(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ QWORD flags); /* * Read a single 4096-byte page of memory, virtual or physical. @@ -1706,43 +1736,48 @@ VOID VmmReadEx(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _Out_writes_(cb) * -- return */ _Success_(return) -BOOL VmmReadPage(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _Out_writes_(4096) PBYTE pbPage); +BOOL VmmReadPage(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwA, _Out_writes_(4096) PBYTE pbPage); /* * Scatter read virtual memory. Non contiguous 4096-byte pages. +* -- H * -- pProcess * -- ppMEMsVirt * -- cpMEMsVirt * -- flags = flags as in VMM_FLAG_*, [VMM_FLAG_NOCACHE for supression of data (not tlb) caching] */ -VOID VmmReadScatterVirtual(_In_ PVMM_PROCESS pProcess, _Inout_updates_(cpMEMsVirt) PPMEM_SCATTER ppMEMsVirt, _In_ DWORD cpMEMsVirt, _In_ QWORD flags); +VOID VmmReadScatterVirtual(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Inout_updates_(cpMEMsVirt) PPMEM_SCATTER ppMEMsVirt, _In_ DWORD cpMEMsVirt, _In_ QWORD flags); /* * Scatter read physical memory. Non contiguous 4096-byte pages. +* -- H * -- ppMEMsPhys * -- cpMEMsPhys * -- flags = flags as in VMM_FLAG_*, [VMM_FLAG_NOCACHE for supression of caching] */ -VOID VmmReadScatterPhysical(_Inout_ PPMEM_SCATTER ppMEMsPhys, _In_ DWORD cpMEMsPhys, _In_ QWORD flags); +VOID VmmReadScatterPhysical(_In_ VMM_HANDLE H, _Inout_ PPMEM_SCATTER ppMEMsPhys, _In_ DWORD cpMEMsPhys, _In_ QWORD flags); /* * Scatter write virtual memory. Non contiguous 4096-byte pages. +* -- H * -- pProcess * -- ppMEMsVirt * -- cpMEMsVirt */ -VOID VmmWriteScatterVirtual(_In_ PVMM_PROCESS pProcess, _Inout_ PPMEM_SCATTER ppMEMsVirt, _In_ DWORD cpMEMsVirt); +VOID VmmWriteScatterVirtual(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Inout_ PPMEM_SCATTER ppMEMsVirt, _In_ DWORD cpMEMsVirt); /* * Scatter write physical memory. Non contiguous 4096-byte pages. +* -- H * -- ppMEMsPhys * -- cpMEMsPhys */ -VOID VmmWriteScatterPhysical(_Inout_ PPMEM_SCATTER ppMEMsPhys, _In_ DWORD cpMEMsPhys); +VOID VmmWriteScatterPhysical(_In_ VMM_HANDLE H, _Inout_ PPMEM_SCATTER ppMEMsPhys, _In_ DWORD cpMEMsPhys); /* * Read a memory segment as a file. This function is mainly a helper function * for various file system functionality. +* -- H * -- pProcess = NULL=='physical memory read', PTR=='virtual memory read' * -- qwMemoryAddress * -- cbMemorySize @@ -1752,11 +1787,12 @@ VOID VmmWriteScatterPhysical(_Inout_ PPMEM_SCATTER ppMEMsPhys, _In_ DWORD cpMEMs * -- cbOffset * -- return = NTSTATUS value */ -NTSTATUS VmmReadAsFile(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwMemoryAddress, _In_ QWORD cbMemorySize, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset); +NTSTATUS VmmReadAsFile(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwMemoryAddress, _In_ QWORD cbMemorySize, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset); /* * Write to a memory segment as a file. This function is mainly a helper * function for virtual file system functionality. +* -- H * -- pProcess = NULL=='physical memory read', PTR=='virtual memory read' * -- qwMemoryAddress * -- cbMemorySize @@ -1766,13 +1802,14 @@ NTSTATUS VmmReadAsFile(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwMemoryAddres * -- cbOffset * -- return = NTSTATUS value */ -NTSTATUS VmmWriteAsFile(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwMemoryAddress, _In_ QWORD cbMemorySize, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset); +NTSTATUS VmmWriteAsFile(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwMemoryAddress, _In_ QWORD cbMemorySize, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset); /* * Translate a virtual address to a physical address by walking the page tables. * The successfully translated Physical Address (PA) is returned in ppa. * Upon fail the PTE will be returned in ppa (if possible) - which may be used * to further lookup virtual memory in case of PageFile or Win10 MemCompression. +* -- H * -- paDTB * -- fUserOnly * -- va @@ -1780,52 +1817,57 @@ NTSTATUS VmmWriteAsFile(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD qwMemoryAddre * -- return */ _Success_(return) -BOOL VmmVirt2PhysEx(_In_ QWORD paDTB, _In_ BOOL fUserOnly, _In_ QWORD va, _Out_ PQWORD ppa); +BOOL VmmVirt2PhysEx(_In_ VMM_HANDLE H, _In_ QWORD paDTB, _In_ BOOL fUserOnly, _In_ QWORD va, _Out_ PQWORD ppa); /* * Translate a virtual address to a physical address by walking the page tables. * The successfully translated Physical Address (PA) is returned in ppa. * Upon fail the PTE will be returned in ppa (if possible) - which may be used * to further lookup virtual memory in case of PageFile or Win10 MemCompression. +* -- H * -- pProcess * -- va * -- ppa * -- return */ _Success_(return) -BOOL VmmVirt2Phys(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD va, _Out_ PQWORD ppa); +BOOL VmmVirt2Phys(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ QWORD va, _Out_ PQWORD ppa); /* * Spider the TLB (page table cache) to load all page table pages into the cache. * This is done to speed up various subsequent virtual memory accesses. * NB! pages may fall out of the cache if it's in heavy use or doe to timing. +* -- H * -- pProcess */ -VOID VmmTlbSpider(_In_ PVMM_PROCESS pProcess); +VOID VmmTlbSpider(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess); /* * Try verify that a supplied page table in pb is valid by analyzing it. +* -- H * -- pb = 0x1000 bytes containing the page table page. * -- pa = physical address if the page table page. * -- fSelfRefReq = is a self referential entry required to be in the map? (PML4 for Windows). */ -BOOL VmmTlbPageTableVerify(_Inout_ PBYTE pb, _In_ QWORD pa, _In_ BOOL fSelfRefReq); +BOOL VmmTlbPageTableVerify(_In_ VMM_HANDLE H, _Inout_ PBYTE pb, _In_ QWORD pa, _In_ BOOL fSelfRefReq); /* * Prefetch a set of physical addresses contained in pTlbPrefetch into the TLB cache. * NB! pTlbPrefetch must not be updated/altered during the function call. +* -- H * -- pTlbPrefetch = the page table addresses to prefetch (on entry) and empty set on exit. */ -VOID VmmTlbPrefetch(_In_ POB_SET pTlbPrefetch); +VOID VmmTlbPrefetch(_In_ VMM_HANDLE H, _In_ POB_SET pTlbPrefetch); /* * Retrieve information of the virtual2physical address translation for the * supplied process. The Virtual address must be supplied in pVirt2PhysInfo upon * entry. +* -- H * -- pProcess * -- pVirt2PhysInfo */ -VOID VmmVirt2PhysGetInformation(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo); +VOID VmmVirt2PhysGetInformation(_In_ VMM_HANDLE H, _Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT2PHYS_INFORMATION pVirt2PhysInfo); /* * Retrieve information of the physical2virtual address translation for the @@ -1836,11 +1878,12 @@ VOID VmmVirt2PhysGetInformation(_Inout_ PVMM_PROCESS pProcess, _Inout_ PVMM_VIRT * It's not possible to use this function to retrieve multiple targeted * addresses in parallell. * CALLER DECREF: return +* -- H * -- pProcess * -- paTarget = targeted physical address (or 0 if use previously saved). * -- return */ -PVMMOB_PHYS2VIRT_INFORMATION VmmPhys2VirtGetInformation(_In_ PVMM_PROCESS pProcess, _In_ QWORD paTarget); +PVMMOB_PHYS2VIRT_INFORMATION VmmPhys2VirtGetInformation(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD paTarget); #define VMM_MEMORY_SEARCH_MAX 16 @@ -1889,146 +1932,86 @@ typedef struct tdVMM_MEMORY_SEARCH_CONTEXT { * To cancel a search prematurely set the fAbortRequested flag in pctx and * wait a short while. * CALLER DECREF: ppObAddressResult +* -- H * -- pProcess * -- ctxs * -- ppObAddress * -- return */ _Success_(return) -BOOL VmmSearch(_In_opt_ PVMM_PROCESS pProcess, _Inout_ PVMM_MEMORY_SEARCH_CONTEXT ctxs, _Out_opt_ POB_DATA *ppObAddressResult); +BOOL VmmSearch(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _Inout_ PVMM_MEMORY_SEARCH_CONTEXT ctxs, _Out_opt_ POB_DATA *ppObAddressResult); // ---------------------------------------------------------------------------- -// VMM process related function definitions below: +// WORK related function definitions below: // ---------------------------------------------------------------------------- -/* -* Retrieve a process for a given PID and optional PVMMOB_PROCESS_TABLE. -* CALLER DECREF: return -* -- pt -* -- dwPID -* -- flags = 0 (recommended) or VMM_FLAG_PROCESS_TOKEN. -* -- return -*/ -PVMM_PROCESS VmmProcessGetEx(_In_opt_ PVMMOB_PROCESS_TABLE pt, _In_ DWORD dwPID, _In_ QWORD flags); +#define VMMWORK_FLAG_PRIO_NORMAL 0 +#define VMMWORK_FLAG_PRIO_LOW 1 + +typedef VOID(*PVMM_WORK_START_ROUTINE_PVOID_PFN)(_In_ VMM_HANDLE H, _In_opt_ PVOID ctx); +typedef VOID(*PVMM_WORK_START_ROUTINE_VALUE_PFN)(_In_ VMM_HANDLE H, _In_ QWORD ctx); +typedef VOID(*PVMM_WORK_START_ROUTINE_OB_PFN)(_In_ VMM_HANDLE H, _In_ POB ctxOb); + +typedef BOOL(*PVMM_WORK_PROCESS_CRITERIA_PVOID_PFN)(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ PVOID ctx); +typedef VOID(*PVMM_WORK_PROCESS_START_ROUTINE_PVOID_PFN)(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ PVOID ctx); /* -* Retrieve a process for a given PID. -* CALLER DECREF: return -* -- dwPID -* -- return = a process struct, or NULL if not found. -*/ -PVMM_PROCESS VmmProcessGet(_In_ DWORD dwPID); - -/* -* Retrieve the next process given a process and a process table. This may be -* useful when iterating over a process list. NB! Listing of next item may fail -* prematurely if the previous process is terminated while having a reference -* to it. -* FUNCTION DECREF: pProcess -* CALLER DECREF: return -* -- pt -* -- pProcess = a process struct, or NULL if first. -* NB! function DECREF's pProcess and must not be used after call! -* -- flags = 0 (recommended) or VMM_FLAG_PROCESS_[TOKEN|SHOW_TERMINATED]. -* -- return = a process struct, or NULL if not found. -*/ -PVMM_PROCESS VmmProcessGetNextEx(_In_opt_ PVMMOB_PROCESS_TABLE pt, _In_opt_ PVMM_PROCESS pProcess, _In_ QWORD flags); - -/* -* Retrieve the next process given a process. This may be useful when iterating -* over a process list. NB! Listing of next item may fail prematurely if the -* previous process is terminated while having a reference to it. -* FUNCTION DECREF: pProcess -* CALLER DECREF: return -* -- pProcess = a process struct, or NULL if first. -* NB! function DECREF's pProcess and must not be used after call! -* -- flags = 0 (recommended) or VMM_FLAG_PROCESS_[TOKEN|SHOW_TERMINATED] -* -- return = a process struct, or NULL if not found. -*/ -PVMM_PROCESS VmmProcessGetNext(_In_opt_ PVMM_PROCESS pProcess, _In_ QWORD flags); - -/* -* Clone an original process entry creating a shallow clone. The user of this -* shallow clone may use it to set the fUserOnly flag to FALSE on an otherwise -* user-mode process to be able to access the whole kernel space for a standard -* user-mode process. -* NB! USE WITH EXTREME CARE - MAY CRASH VMM IF USED MORE GENERALLY! -* CALLER DECREF: return -* -- pProcess -* -- return -*/ -PVMM_PROCESS VmmProcessClone(_In_ PVMM_PROCESS pProcess); - -/* -* Create a new process object. New process object are created in a separate -* data structure and won't become visible to the "Process" functions until -* after the VmmProcessCreateFinish have been called. -* CALLER DECREF: return -* -- fTotalRefresh = create a completely new entry - i.e. do not copy any form -* of data from the old entry such as module and memory maps. -* -- dwPID -* -- dwPPID = parent PID (if any) -* -- dwState -* -- paDTB -* -- paDTB_UserOpt -* -- szName -* -- fUserOnly = user mode process (hide supervisor pages from view) -* -- pbEPROCESS -* -- cbEPROCESS -* -- return -*/ -PVMM_PROCESS VmmProcessCreateEntry(_In_ BOOL fTotalRefresh, _In_ DWORD dwPID, _In_ DWORD dwPPID, _In_ DWORD dwState, _In_ QWORD paDTB, _In_ QWORD paDTB_UserOpt, _In_ CHAR szName[16], _In_ BOOL fUserOnly, _In_reads_opt_(cbEPROCESS) PBYTE pbEPROCESS, _In_ DWORD cbEPROCESS); - -/* -* Query process for its creation time. -* -- pProcess -* -- return = time as FILETIME or 0 on error. -*/ -QWORD VmmProcess_GetCreateTimeOpt(_In_opt_ PVMM_PROCESS pProcess); - -/* -* Query process for its exit time. -* -- pProcess -* -- return = time as FILETIME or 0 on error. -*/ -QWORD VmmProcess_GetExitTimeOpt(_In_opt_ PVMM_PROCESS pProcess); - -/* -* Activate the pending, not yet active, processes added by VmmProcessCreateEntry. -* This will also clear any previous processes. -*/ -VOID VmmProcessCreateFinish(); - -/* -* List the PIDs and put them into the supplied table. -* -- pPIDs = user allocated DWORD array to receive result, or NULL. -* -- pcPIDs = ptr to number of DWORDs in pPIDs on entry - number of PIDs in system on exit. -* -- flags = 0 (recommended) or VMM_FLAG_PROCESS_SHOW_TERMINATED (_only_ if default setting in ctxVmm->flags should be overridden) -*/ -VOID VmmProcessListPIDs(_Out_writes_opt_(*pcPIDs) PDWORD pPIDs, _Inout_ PSIZE_T pcPIDs, _In_ QWORD flags); - -/* -* Schedule an asynchronous work item onto a worker thread. -* NB! longer running functions must monitor ctxVmm->Work.fEnabled and exit -* immediately if required! +* Schedule an asynchronous work item with a pvoid context onto a worker thread. +* NB! function is discouraged use VmmWork_Value()/VmmWork_Ob() for better ctx memory control. +* NB! longer running functions must monitor H->fAbort and exit immediately if required! +* -- H = VMM handle. * -- pfn -* -- ctx = optional context to provide to the pfn function. -* -- hEventFinish = optional event with will be set upon work completion. +* -- ctx = pvoid to provide to the function pfn +* -- hEventFinish = optional event which will be: (1) reset upon entry, (2) set upon completion. +* -- flags = VMMWORK_FLAG_* */ -VOID VmmWork(_In_ LPTHREAD_START_ROUTINE pfn, _In_opt_ PVOID ctx, _In_opt_ HANDLE hEventFinish); +VOID VmmWork_Void(_In_ VMM_HANDLE H, _In_ PVMM_WORK_START_ROUTINE_PVOID_PFN pfn, _In_ PVOID ctx, _In_opt_ HANDLE hEventFinish, _In_ DWORD flags); + +/* +* Schedule an asynchronous work item with a value context onto a worker thread. +* NB! longer running functions must monitor H->fAbort and exit immediately if required! +* -- H = VMM handle. +* -- pfn +* -- ctx = value to provide to the function pfn +* -- hEventFinish = optional event which will be: (1) reset upon entry, (2) set upon completion. +* -- flags = VMMWORK_FLAG_* +*/ +VOID VmmWork_Value(_In_ VMM_HANDLE H, _In_ PVMM_WORK_START_ROUTINE_VALUE_PFN pfn, _In_ QWORD ctx, _In_opt_ HANDLE hEventFinish, _In_ DWORD flags); + +/* +* Schedule an asynchronous work item with an object context onto a worker thread. +* NB! longer running functions must monitor H->fAbort and exit immediately if required! +* -- H = VMM handle. +* -- pfn +* -- ctx = object to provide to the function pfn +* -- hEventFinish = optional event which will be: (1) reset upon entry, (2) set upon completion. +* -- flags = VMMWORK_FLAG_* +*/ +VOID VmmWork_Ob(_In_ VMM_HANDLE H, _In_ PVMM_WORK_START_ROUTINE_OB_PFN pfn, _In_ POB ctx, _In_opt_ HANDLE hEventFinish, _In_ DWORD flags); /* * Schedule up to 64 asynchronous work items onto worker threads. * Function will wait for all work items to complete before returning. -* NB! longer running functions must monitor ctxVmm->Work.fEnabled and exit -* immediately if required! -* -- ctx = optional context to provide to the pfn functions. -* -- cWork = number of work LPTHREAD_START_ROUTINE following in varargs. -* -- ... = vararg of cWork LPTHREAD_START_ROUTINE work items. +* NB! longer running functions must monitor H->fAbort and exit if required. +* -- H = VMM handle. +* -- ctx = context to provide to the pfn functions. +* -- cWork = number of work PVMM_THREAD_START_ROUTINE_PFN following in varargs. +* -- ... = vararg of cWork PVMM_THREAD_START_ROUTINE_PFN work items. */ -VOID VmmWorkWaitMultiple(_In_opt_ PVOID ctx, _In_ DWORD cWork, ...); +VOID VmmWorkWaitMultiple_Void(_In_ VMM_HANDLE H, _In_ PVOID ctx, _In_ DWORD cWork, ...); + +/* +* Schedule up to 64 asynchronous work items onto worker threads. +* Function will wait for all work items to complete before returning. +* NB! longer running functions must monitor H->fAbort and exit if required. +* -- H = VMM handle. +* -- cWork = number of work items. +* -- pfns = an array of cWork PVMM_THREAD_START_ROUTINE_PFNs. +* -- ctxs = an array of cWork PVOID contexts (passed on to the pfns). +*/ +VOID VmmWorkWaitMultiple2_Void(_In_ VMM_HANDLE H, _In_ DWORD cWork, _In_count_(cWork) PVMM_WORK_START_ROUTINE_PVOID_PFN *pfns, _In_count_(cWork) PVOID *ctxs); /* * Perform multi-threaded parallel processing of processes in the process table. @@ -2042,14 +2025,20 @@ VOID VmmWorkWaitMultiple(_In_opt_ PVOID ctx, _In_ DWORD cWork, ...); * NB! Manipulation of ctx in pfnAction callback function must be thread-safe! * NB! For fast actions VmmProcessGetNext in single-threaded mode is recommended * over the use of this function! -* -- ctxAction = optional context forwarded to callback functions pfnCriteria / pfnAction. +* -- H = VMM handle. +* -- cMaxThread = max threads to use, 0 = default. +* -- ctx = optional context forwarded to callback functions pfnCriteria / pfnAction. * -- pfnCriteria = optional callback function selecting which processes to process. * -- pfnAction = processing function to be called in multi-threaded context. +* -- return */ -VOID VmmProcessActionForeachParallel( - _In_opt_ PVOID ctxAction, - _In_opt_ BOOL(*pfnCriteria)(_In_ PVMM_PROCESS pProcess, _In_opt_ PVOID ctx), - _In_ VOID(*pfnAction)(_In_ PVMM_PROCESS pProcess, _In_opt_ PVOID ctx) +_Success_(return) +BOOL VmmWork_ProcessActionForeachParallel_Void( + _In_ VMM_HANDLE H, + _In_opt_ DWORD cMaxThread, + _In_opt_ PVOID ctx, + _In_opt_ PVMM_WORK_PROCESS_CRITERIA_PVOID_PFN pfnCriteria, + _In_ PVMM_WORK_PROCESS_START_ROUTINE_PVOID_PFN pfnAction ); /* @@ -2059,26 +2048,151 @@ VOID VmmProcessActionForeachParallel( * -- ctx * -- return */ -BOOL VmmProcessActionForeachParallel_CriteriaActiveOnly(_In_ PVMM_PROCESS pProcess, _In_opt_ PVOID ctx); -BOOL VmmProcessActionForeachParallel_CriteriaActiveUserOnly(_In_ PVMM_PROCESS pProcess, _In_opt_ PVOID ctx); +BOOL VmmWork_ProcessActionForeachParallel_CriteriaActiveOnly(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ PVOID ctx); +BOOL VmmWork_ProcessActionForeachParallel_CriteriaActiveUserOnly(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ PVOID ctx); + + + +// ---------------------------------------------------------------------------- +// VMM process related function definitions below: +// ---------------------------------------------------------------------------- + +/* +* Retrieve a process for a given PID and optional PVMMOB_PROCESS_TABLE. +* CALLER DECREF: return +* -- H +* -- pt +* -- dwPID +* -- flags = 0 (recommended) or VMM_FLAG_PROCESS_TOKEN. +* -- return +*/ +PVMM_PROCESS VmmProcessGetEx(_In_ VMM_HANDLE H, _In_opt_ PVMMOB_PROCESS_TABLE pt, _In_ DWORD dwPID, _In_ QWORD flags); + +/* +* Retrieve a process for a given PID. +* CALLER DECREF: return +* -- H +* -- dwPID +* -- return = a process struct, or NULL if not found. +*/ +PVMM_PROCESS VmmProcessGet(_In_ VMM_HANDLE H, _In_ DWORD dwPID); + +/* +* Retrieve the next process given a process and a process table. This may be +* useful when iterating over a process list. NB! Listing of next item may fail +* prematurely if the previous process is terminated while having a reference +* to it. +* FUNCTION DECREF: pProcess +* CALLER DECREF: return +* -- H +* -- pt +* -- pProcess = a process struct, or NULL if first. +* NB! function DECREF's pProcess and must not be used after call! +* -- flags = 0 (recommended) or VMM_FLAG_PROCESS_[TOKEN|SHOW_TERMINATED]. +* -- return = a process struct, or NULL if not found. +*/ +PVMM_PROCESS VmmProcessGetNextEx(_In_ VMM_HANDLE H, _In_opt_ PVMMOB_PROCESS_TABLE pt, _In_opt_ PVMM_PROCESS pProcess, _In_ QWORD flags); + +/* +* Retrieve the next process given a process. This may be useful when iterating +* over a process list. NB! Listing of next item may fail prematurely if the +* previous process is terminated while having a reference to it. +* FUNCTION DECREF: pProcess +* CALLER DECREF: return +* -- H +* -- pProcess = a process struct, or NULL if first. +* NB! function DECREF's pProcess and must not be used after call! +* -- flags = 0 (recommended) or VMM_FLAG_PROCESS_[TOKEN|SHOW_TERMINATED] +* -- return = a process struct, or NULL if not found. +*/ +PVMM_PROCESS VmmProcessGetNext(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ QWORD flags); + +/* +* Clone an original process entry creating a shallow clone. The user of this +* shallow clone may use it to set the fUserOnly flag to FALSE on an otherwise +* user-mode process to be able to access the whole kernel space for a standard +* user-mode process. +* NB! USE WITH EXTREME CARE - MAY CRASH VMM IF USED MORE GENERALLY! +* CALLER DECREF: return +* -- H +* -- pProcess +* -- return +*/ +PVMM_PROCESS VmmProcessClone(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess); + +/* +* Create a new process object. New process object are created in a separate +* data structure and won't become visible to the "Process" functions until +* after the VmmProcessCreateFinish have been called. +* CALLER DECREF: return +* -- H +* -- fTotalRefresh = create a completely new entry - i.e. do not copy any form +* of data from the old entry such as module and memory maps. +* -- dwPID +* -- dwPPID = parent PID (if any) +* -- dwState +* -- paDTB +* -- paDTB_UserOpt +* -- szName +* -- fUserOnly = user mode process (hide supervisor pages from view) +* -- pbEPROCESS +* -- cbEPROCESS +* -- return +*/ +PVMM_PROCESS VmmProcessCreateEntry(_In_ VMM_HANDLE H, _In_ BOOL fTotalRefresh, _In_ DWORD dwPID, _In_ DWORD dwPPID, _In_ DWORD dwState, _In_ QWORD paDTB, _In_ QWORD paDTB_UserOpt, _In_ CHAR szName[16], _In_ BOOL fUserOnly, _In_reads_opt_(cbEPROCESS) PBYTE pbEPROCESS, _In_ DWORD cbEPROCESS); + +/* +* Query process for its creation time. +* -- H +* -- pProcess +* -- return = time as FILETIME or 0 on error. +*/ +QWORD VmmProcess_GetCreateTimeOpt(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess); + +/* +* Query process for its exit time. +* -- H +* -- pProcess +* -- return = time as FILETIME or 0 on error. +*/ +QWORD VmmProcess_GetExitTimeOpt(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess); + +/* +* Activate the pending, not yet active, processes added by VmmProcessCreateEntry. +* This will also clear any previous processes. +* -- H +*/ +VOID VmmProcessCreateFinish(_In_ VMM_HANDLE H); + +/* +* List the PIDs and put them into the supplied table. +* -- H +* -- pPIDs = user allocated DWORD array to receive result, or NULL. +* -- pcPIDs = ptr to number of DWORDs in pPIDs on entry - number of PIDs in system on exit. +* -- flags = 0 (recommended) or VMM_FLAG_PROCESS_SHOW_TERMINATED (_only_ if default setting in H->vmm.flags should be overridden) +*/ +VOID VmmProcessListPIDs(_In_ VMM_HANDLE H, _Out_writes_opt_(*pcPIDs) PDWORD pPIDs, _Inout_ PSIZE_T pcPIDs, _In_ QWORD flags); /* * Clear the oldest region of all InUse entries and make it the new active region. +* -- H * -- wTblTag */ -VOID VmmCacheClearPartial(_In_ DWORD dwTblTag); +VOID VmmCacheClearPartial(_In_ VMM_HANDLE H, _In_ DWORD dwTblTag); /* * Clear the specified cache from all entries. +* -- H * -- dwTblTag */ -VOID VmmCacheClear(_In_ DWORD dwTblTag); +VOID VmmCacheClear(_In_ VMM_HANDLE H, _In_ DWORD dwTblTag); /* * Invalidate cache entries belonging to a specific physical address. +* -- H * -- pa */ -VOID VmmCacheInvalidate(_In_ QWORD pa); +VOID VmmCacheInvalidate(_In_ VMM_HANDLE H, _In_ QWORD pa); /* * Prefetch a set of addresses contained in pPrefetchPages into the cache. This @@ -2089,43 +2203,47 @@ VOID VmmCacheInvalidate(_In_ QWORD pa); * -- pPrefetchPages * -- flags */ -VOID VmmCachePrefetchPages(_In_opt_ PVMM_PROCESS pProcess, _In_opt_ POB_SET pPrefetchPages, _In_ QWORD flags); +VOID VmmCachePrefetchPages(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_opt_ POB_SET pPrefetchPages, _In_ QWORD flags); /* * Prefetch a set of addresses. This is useful when reading data from somewhat * known addresses over higher latency connections. +* -- H * -- pProcess * -- cAddresses * -- ... = varargs of total cAddresses of addresses of type QWORD. */ -VOID VmmCachePrefetchPages2(_In_opt_ PVMM_PROCESS pProcess, _In_ DWORD cAddresses, ...); +VOID VmmCachePrefetchPages2(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ DWORD cAddresses, ...); /* * Prefetch a set of addresses contained in pPrefetchPagesNonPageAligned into * the cache by first converting them to page aligned pages. This is used when * reading data from somewhat known addresses over higher latency connections. * NB! pPrefetchPagesNonPageAligned must not be altered during the function call. +* -- H * -- pProcess * -- pPrefetchPagesNonPageAligned * -- cb * -- flags */ -VOID VmmCachePrefetchPages3(_In_opt_ PVMM_PROCESS pProcess, _In_opt_ POB_SET pPrefetchPagesNonPageAligned, _In_ DWORD cb, _In_ QWORD flags); +VOID VmmCachePrefetchPages3(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_opt_ POB_SET pPrefetchPagesNonPageAligned, _In_ DWORD cb, _In_ QWORD flags); /* * Prefetch an array of optionally non-page aligned addresses. This is useful * when reading data from somewhat known addresses over higher latency connections. +* -- H * -- pProcess * -- cAddresses * -- pqwAddresses = array of addresses to fetch * -- cb * -- flags */ -VOID VmmCachePrefetchPages4(_In_opt_ PVMM_PROCESS pProcess, _In_ DWORD cAddresses, _In_ PQWORD pqwAddresses, _In_ DWORD cb, _In_ QWORD flags); +VOID VmmCachePrefetchPages4(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_ DWORD cAddresses, _In_ PQWORD pqwAddresses, _In_ DWORD cb, _In_ QWORD flags); /* * Prefetch memory of optionally non-page aligned addresses which are derived * from pmPrefetchObjects by the pfnFilter filter function. +* -- H * -- pProcess * -- pmPrefetch = map of objects. * -- cb @@ -2133,14 +2251,15 @@ VOID VmmCachePrefetchPages4(_In_opt_ PVMM_PROCESS pProcess, _In_ DWORD cAddresse * -- pfnFilter = filter as required by ObMap_FilterSet function. * -- return = at least one object is found to be prefetched into cache. */ -BOOL VmmCachePrefetchPages5(_In_opt_ PVMM_PROCESS pProcess, _In_opt_ POB_MAP pmPrefetchObjects, _In_ DWORD cb, _In_ QWORD flags, _In_ VOID(*pfnFilter)(_In_ QWORD k, _In_ PVOID v, _Inout_ POB_SET ps)); +BOOL VmmCachePrefetchPages5(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _In_opt_ POB_MAP pmPrefetchObjects, _In_ DWORD cb, _In_ QWORD flags, _In_ VOID(*pfnFilter)(_In_ QWORD k, _In_ PVOID v, _Inout_ POB_SET ps)); /* * Initialize the memory model specified and discard any previous memory models * that may be in action. +* -- H * -- tp */ -VOID VmmInitializeMemoryModel(_In_ VMM_MEMORYMODEL_TP tp); +VOID VmmInitializeMemoryModel(_In_ VMM_HANDLE H, _In_ VMM_MEMORYMODEL_TP tp); @@ -2151,37 +2270,41 @@ VOID VmmInitializeMemoryModel(_In_ VMM_MEMORYMODEL_TP tp); /* * Retrieve the PTE hardware page table memory map. * CALLER DECREF: ppObPteMap +* -- H * -- pProcess * -- ppObPteMap * -- fExtendedText * -- return */ _Success_(return) -BOOL VmmMap_GetPte(_In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_PTE *ppObPteMap, _In_ BOOL fExtendedText); +BOOL VmmMap_GetPte(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_PTE *ppObPteMap, _In_ BOOL fExtendedText); /* * Retrieve the VAD memory map. * CALLER DECREF: ppObVadMap +* -- H * -- pProcess * -- ppObVadMap * -- tpVmmVadMap = VMM_VADMAP_TP_* * -- return */ _Success_(return) -BOOL VmmMap_GetVad(_In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_VAD *ppObVadMap, _In_ VMM_VADMAP_TP tpVmmVadMap); +BOOL VmmMap_GetVad(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_VAD *ppObVadMap, _In_ VMM_VADMAP_TP tpVmmVadMap); /* * Retrieve a single PVMM_MAP_VADENTRY for a given VadMap and address inside it. +* -- H * -- pVadMap * -- va * -- return = PTR to VADENTRY or NULL on fail. Must not be used out of pVadMap scope. */ _Success_(return != NULL) -PVMM_MAP_VADENTRY VmmMap_GetVadEntry(_In_opt_ PVMMOB_MAP_VAD pVadMap, _In_ QWORD va); +PVMM_MAP_VADENTRY VmmMap_GetVadEntry(_In_ VMM_HANDLE H, _In_opt_ PVMMOB_MAP_VAD pVadMap, _In_ QWORD va); /* * Retrieve the VAD extended memory map by range specified by iPage and cPage. * CALLER DECREF: ppObVadExMap +* -- H * -- pProcess * -- ppObVadExMap * -- tpVmmVadMap = VMM_VADMAP_TP_* @@ -2190,29 +2313,33 @@ PVMM_MAP_VADENTRY VmmMap_GetVadEntry(_In_opt_ PVMMOB_MAP_VAD pVadMap, _In_ QWORD * -- return */ _Success_(return) -BOOL VmmMap_GetVadEx(_In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_VADEX *ppObVadExMap, _In_ VMM_VADMAP_TP tpVmmVadMap, _In_ DWORD iPage, _In_ DWORD cPage); +BOOL VmmMap_GetVadEx(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_VADEX *ppObVadExMap, _In_ VMM_VADMAP_TP tpVmmVadMap, _In_ DWORD iPage, _In_ DWORD cPage); /* * Retrieve the process module map. * CALLER DECREF: ppObModuleMap +* -- H * -- pProcess * -- ppObModuleMap * -- return */ _Success_(return) -BOOL VmmMap_GetModule(_In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_MODULE *ppObModuleMap); +BOOL VmmMap_GetModule(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_MODULE *ppObModuleMap); /* * Retrieve a single VMM_MAP_MODULEENTRY for a given ModuleMap and module name inside it. +* -- H * -- pModuleMap * -- uszModuleName * -- return = PTR to VMM_MAP_MODULEENTRY or NULL on fail. Must not be used out of pModuleMap scope. */ -PVMM_MAP_MODULEENTRY VmmMap_GetModuleEntry(_In_ PVMMOB_MAP_MODULE pModuleMap, _In_ LPSTR uszModuleName); +_Success_(return != NULL) +PVMM_MAP_MODULEENTRY VmmMap_GetModuleEntry(_In_ VMM_HANDLE H, _In_ PVMMOB_MAP_MODULE pModuleMap, _In_ LPSTR uszModuleName); /* * Retrieve a single VMM_MAP_MODULEENTRY for a given process and module name. * CALLER DECREF: ppObModuleMap +* -- H * -- pProcessOpt * -- dwPidOpt * -- uszModuleName @@ -2221,95 +2348,125 @@ PVMM_MAP_MODULEENTRY VmmMap_GetModuleEntry(_In_ PVMMOB_MAP_MODULE pModuleMap, _I * -- return */ _Success_(return) -BOOL VmmMap_GetModuleEntryEx(_In_opt_ PVMM_PROCESS pProcessOpt, _In_opt_ DWORD dwPidOpt, _In_opt_ LPSTR uszModuleName, _Out_ PVMMOB_MAP_MODULE *ppObModuleMap, _Out_ PVMM_MAP_MODULEENTRY *pModuleEntry); +BOOL VmmMap_GetModuleEntryEx(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcessOpt, _In_opt_ DWORD dwPidOpt, _In_opt_ LPSTR uszModuleName, _Out_ PVMMOB_MAP_MODULE *ppObModuleMap, _Out_ PVMM_MAP_MODULEENTRY *pModuleEntry); + +/* +* Retrieve a single PVMM_MAP_MODULEENTRY for a given ModuleMap and virtual address inside it. +* -- H +* -- pModuleMap +* -- va = virtual address within the module range. +* -- return = PTR to VMM_MAP_MODULEENTRY or NULL on fail. Must not be used out of pModuleMap scope. +*/ +_Success_(return != NULL) +PVMM_MAP_MODULEENTRY VmmMap_GetModuleEntryEx2(_In_ VMM_HANDLE H, _In_ PVMMOB_MAP_MODULE pModuleMap, _In_ QWORD va); + +/* +* Retrieve POB_MAP for a given ModuleMap. +* CALLER DECREF: *ppmObModuleEntryByVA +* -- H +* -- pModuleMap +* -- ppmObModuleEntryByVA = map consisting of module entries keyed by va (only valid for duration of pModuleMap). +* -- return +*/ +_Success_(return) +BOOL VmmMap_GetModuleEntryEx3(_In_ VMM_HANDLE H, _In_ PVMMOB_MAP_MODULE pModuleMap, _Out_ POB_MAP *ppmObModuleEntryByVA); /* * Retrieve the process unloaded module map. * CALLER DECREF: ppObUnloadedModuleMap +* -- H * -- pProcess * -- ppObUnloadedModuleMap * -- return */ _Success_(return) -BOOL VmmMap_GetUnloadedModule(_In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_UNLOADEDMODULE *ppObUnloadedModuleMap); +BOOL VmmMap_GetUnloadedModule(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_UNLOADEDMODULE *ppObUnloadedModuleMap); /* * Retrieve the process module export address table (EAT) map. * CALLER DECREF: ppObEatMap +* -- H * -- pProcess * -- pModule * -- ppObEatMap * -- return */ _Success_(return) -BOOL VmmMap_GetEAT(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_MODULEENTRY pModuleEntry, _Out_ PVMMOB_MAP_EAT *ppObEatMap); +BOOL VmmMap_GetEAT(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_MODULEENTRY pModuleEntry, _Out_ PVMMOB_MAP_EAT *ppObEatMap); /* * Retrieve the export entry index in pEatMap->pMap by function name. +* -- H * -- pEatMap * -- uszFunctionName * -- pdwEntryIndex = pointer to receive the pEatMap->pMap index. * -- return */ _Success_(return) -BOOL VmmMap_GetEATEntryIndexU(_In_ PVMMOB_MAP_EAT pEatMap, _In_ LPSTR uszFunctionName, _Out_ PDWORD pdwEntryIndex); +BOOL VmmMap_GetEATEntryIndexU(_In_ VMM_HANDLE H, _In_ PVMMOB_MAP_EAT pEatMap, _In_ LPSTR uszFunctionName, _Out_ PDWORD pdwEntryIndex); /* * Retrieve the process module import address table (IAT) map. * CALLER DECREF: ppObIatMap +* -- H * -- pProcess * -- pModule * -- ppObIatMap * -- return */ _Success_(return) -BOOL VmmMap_GetIAT(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_MODULEENTRY pModuleEntry, _Out_ PVMMOB_MAP_IAT *ppObIatMap); +BOOL VmmMap_GetIAT(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_MODULEENTRY pModuleEntry, _Out_ PVMMOB_MAP_IAT *ppObIatMap); /* * Retrieve the heap map. * CALLER DECREF: ppObHeapMap +* -- H * -- pProcess * -- ppObHeapMap * -- return */ _Success_(return) -BOOL VmmMap_GetHeap(_In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_HEAP *ppObHeapMap); +BOOL VmmMap_GetHeap(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_HEAP *ppObHeapMap); /* * Retrieve a single PVMM_MAP_HEAPENTRY for a given HeapMap and heap virtual address. +* -- H * -- pHeapMap * -- vaHeap = virtual address of heap OR heap id. * -- return = PTR to VMM_MAP_HEAPENTRY or NULL on fail. Must not be used out of pHeapMap scope. */ -PVMM_MAP_HEAPENTRY VmmMap_GetHeapEntry(_In_ PVMMOB_MAP_HEAP pHeapMap, _In_ QWORD vaHeap); +PVMM_MAP_HEAPENTRY VmmMap_GetHeapEntry(_In_ VMM_HANDLE H, _In_ PVMMOB_MAP_HEAP pHeapMap, _In_ QWORD vaHeap); /* * Retrieve the heap alloc map. (memory allocations in the specified heap). * CALLER DECREF: ppObHeapAllocMap +* -- H * -- pProcess * -- ppObHeapAllocMap * -- return */ _Success_(return) -BOOL VmmMap_GetHeapAlloc(_In_ PVMM_PROCESS pProcess, _In_ QWORD vaHeap, _Out_ PVMMOB_MAP_HEAPALLOC *ppObHeapAllocMap); +BOOL VmmMap_GetHeapAlloc(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QWORD vaHeap, _Out_ PVMMOB_MAP_HEAPALLOC *ppObHeapAllocMap); /* * Retrieve a single PVMM_MAP_HEAPALLOCENTRY for a given HeapAllocMap and a memory allocation address. +* -- H * -- pHeapAllocMap * -- vaAlloc * -- return = PTR to PVMM_MAP_HEAPALLOCENTRY or NULL on fail. Must not be used out of pHeapAllocMap scope. */ -PVMM_MAP_HEAPALLOCENTRY VmmMap_GetHeapAllocEntry(_In_ PVMMOB_MAP_HEAPALLOC pHeapAllocMap, _In_ QWORD vaAlloc); +PVMM_MAP_HEAPALLOCENTRY VmmMap_GetHeapAllocEntry(_In_ VMM_HANDLE H, _In_ PVMMOB_MAP_HEAPALLOC pHeapAllocMap, _In_ QWORD vaAlloc); /* * Retrieve the thread map. * CALLER DECREF: ppObThreadMap +* -- H * -- pProcess * -- ppObThreadMap * -- return */ _Success_(return) -BOOL VmmMap_GetThread(_In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_THREAD *ppObThreadMap); +BOOL VmmMap_GetThread(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_THREAD *ppObThreadMap); /* * Retrieve a single PVMM_MAP_THREADENTRY for a given ThreadMap and ThreadID. @@ -2317,111 +2474,122 @@ BOOL VmmMap_GetThread(_In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_THREAD *ppObT * -- dwTID * -- return = PTR to VMM_MAP_THREADENTRY or NULL on fail. Must not be used out of pThreadMap scope. */ -PVMM_MAP_THREADENTRY VmmMap_GetThreadEntry(_In_ PVMMOB_MAP_THREAD pThreadMap, _In_ DWORD dwTID); +PVMM_MAP_THREADENTRY VmmMap_GetThreadEntry(_In_ VMM_HANDLE H, _In_ PVMMOB_MAP_THREAD pThreadMap, _In_ DWORD dwTID); /* * Retrieve the HANDLE map * CALLER DECREF: ppObHandleMap +* -- H * -- pProcess * -- ppObHandleMap * -- fExtendedText * -- return */ _Success_(return) -BOOL VmmMap_GetHandle(_In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_HANDLE *ppObHandleMap, _In_ BOOL fExtendedText); +BOOL VmmMap_GetHandle(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_HANDLE *ppObHandleMap, _In_ BOOL fExtendedText); /* * Retrieve the EVIL map * CALLER DECREF: ppObEvilMap +* -- H * -- pProcess = retrieve for specific process, or if NULL for all processes. * -- ppObEvilMap * -- return */ _Success_(return) -BOOL VmmMap_GetEvil(_In_opt_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_EVIL *ppObEvilMap); +BOOL VmmMap_GetEvil(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess, _Out_ PVMMOB_MAP_EVIL *ppObEvilMap); /* * Retrieve the OBJECT MANAGER map * CALLER DECREF: ppObObjectMap +* -- H * -- ppObObjectMap * -- return */ _Success_(return) -BOOL VmmMap_GetObject(_Out_ PVMMOB_MAP_OBJECT *ppObObjectMap); +BOOL VmmMap_GetObject(_In_ VMM_HANDLE H, _Out_ PVMMOB_MAP_OBJECT *ppObObjectMap); /* * Retrieve the KERNEL DRIVER map * CALLER DECREF: ppObKDriverMap +* -- H * -- ppObKDriverMap * -- return */ _Success_(return) -BOOL VmmMap_GetKDriver(_Out_ PVMMOB_MAP_KDRIVER *ppObKDriverMap); +BOOL VmmMap_GetKDriver(_In_ VMM_HANDLE H, _Out_ PVMMOB_MAP_KDRIVER *ppObKDriverMap); /* * Retrieve the index of a VMM_MAP_POOLENTRYTAG within the PVMMOB_MAP_POOL. +* -- H * -- pPoolMap * -- dwPoolTag * -- pdwTagIndex * -- return */ _Success_(return) -BOOL VmmMap_GetPoolTag(_In_ PVMMOB_MAP_POOL pPoolMap, _In_ DWORD dwPoolTag, _Out_ PDWORD pdwTagIndex); +BOOL VmmMap_GetPoolTag(_In_ VMM_HANDLE H, _In_ PVMMOB_MAP_POOL pPoolMap, _In_ DWORD dwPoolTag, _Out_ PDWORD pdwTagIndex); /* * Retrieve the index of a VMM_MAP_POOLENTRY within the PVMMOB_MAP_POOL. +* -- H * -- pPoolMap * -- vaPoolEntry * -- pdwEntryIndex * -- return */ _Success_(return) -BOOL VmmMap_GetPoolEntry(_In_ PVMMOB_MAP_POOL pPoolMap, _In_ QWORD vaPoolEntry, _Out_ PDWORD pdwEntryIndex); +BOOL VmmMap_GetPoolEntry(_In_ VMM_HANDLE H, _In_ PVMMOB_MAP_POOL pPoolMap, _In_ QWORD vaPoolEntry, _Out_ PDWORD pdwEntryIndex); /* * Retrieve the POOL map. * CALLER DECREF: ppObPoolMap +* -- H * -- ppObPoolMap * -- fAll = TRUE: retrieve all pools; FALSE: retrieve big page pool only. * -- return */ _Success_(return) -BOOL VmmMap_GetPool(_Out_ PVMMOB_MAP_POOL *ppObPoolMap, _In_ BOOL fAll); +BOOL VmmMap_GetPool(_In_ VMM_HANDLE H, _Out_ PVMMOB_MAP_POOL *ppObPoolMap, _In_ BOOL fAll); /* * Retrieve the NETWORK CONNECTION map * CALLER DECREF: ppObNetMap +* -- H * -- ppObNetMap * -- return */ _Success_(return) -BOOL VmmMap_GetNet(_Out_ PVMMOB_MAP_NET *ppObNetMap); +BOOL VmmMap_GetNet(_In_ VMM_HANDLE H, _Out_ PVMMOB_MAP_NET *ppObNetMap); /* * Retrieve the Physical Memory Map. * CALLER DECREF: ppObPhysMem +* -- H * -- ppObPhysMem * -- return */ _Success_(return) -BOOL VmmMap_GetPhysMem(_Out_ PVMMOB_MAP_PHYSMEM *ppObPhysMem); +BOOL VmmMap_GetPhysMem(_In_ VMM_HANDLE H, _Out_ PVMMOB_MAP_PHYSMEM *ppObPhysMem); /* * Retrieve the USER map * CALLER DECREF: ppObUserMap +* -- H * -- ppObUserMap * -- return */ _Success_(return) -BOOL VmmMap_GetUser(_Out_ PVMMOB_MAP_USER *ppObUserMap); +BOOL VmmMap_GetUser(_In_ VMM_HANDLE H, _Out_ PVMMOB_MAP_USER *ppObUserMap); /* * Retrieve the SERVICES map * CALLER DECREF: ppObServiceMap +* -- H * -- ppObServiceMap * -- return */ _Success_(return) -BOOL VmmMap_GetService(_Out_ PVMMOB_MAP_SERVICE *ppObServiceMap); +BOOL VmmMap_GetService(_In_ VMM_HANDLE H, _Out_ PVMMOB_MAP_SERVICE *ppObServiceMap); #endif /* __VMM_H__ */ diff --git a/vmm/vmm.vcxproj b/vmm/vmm.vcxproj index fbf8303..3e97cdc 100644 --- a/vmm/vmm.vcxproj +++ b/vmm/vmm.vcxproj @@ -254,6 +254,7 @@ + @@ -266,11 +267,14 @@ + + + @@ -298,6 +302,7 @@ + @@ -320,6 +325,7 @@ + @@ -334,6 +340,7 @@ + diff --git a/vmm/vmm.vcxproj.filters b/vmm/vmm.vcxproj.filters index c76543f..f076b5e 100644 --- a/vmm/vmm.vcxproj.filters +++ b/vmm/vmm.vcxproj.filters @@ -138,6 +138,9 @@ Header Files + + Header Files + @@ -374,6 +377,24 @@ Source Files + + Source Files + + + Source Files + + + Source Files\modules + + + Source Files\modules + + + Source Files\modules + + + Source Files\modules + diff --git a/vmm/vmmdll.c b/vmm/vmmdll.c index 5e4a7b1..444c29f 100644 --- a/vmm/vmmdll.c +++ b/vmm/vmmdll.c @@ -1,5 +1,4 @@ -// vmmdll.c : implementation of core dynamic link library (dll) functionality -// of the virtual memory manager (VMM) for The Memory Process File System. +// vmmdll.c : implementation of external exported library functions. // // (c) Ulf Frisk, 2018-2022 // Author: Ulf Frisk, pcileech@frizk.net @@ -22,462 +21,174 @@ #include "vmmwinreg.h" #include "mm_pfn.h" +// tags for external allocations: +#define OB_TAG_API_MAP_EAT 'EAT ' +#define OB_TAG_API_MAP_HANDLE 'HND ' +#define OB_TAG_API_MAP_HEAP 'HEAP' +#define OB_TAG_API_MAP_HEAP_ALLOC 'HEPA' +#define OB_TAG_API_MAP_IAT 'IAT ' +#define OB_TAG_API_MAP_MODULE 'MOD ' +#define OB_TAG_API_MAP_NET 'NET ' +#define OB_TAG_API_MAP_PHYSMEM 'PMEM' +#define OB_TAG_API_MAP_POOL 'POOL' +#define OB_TAG_API_MAP_PTE 'PTE ' +#define OB_TAG_API_MAP_SERVICES 'SVC ' +#define OB_TAG_API_MAP_THREAD 'THRD' +#define OB_TAG_API_MAP_UNLOADEDMODULE 'UMOD' +#define OB_TAG_API_MAP_USER 'USER' +#define OB_TAG_API_MAP_VAD 'VAD ' +#define OB_TAG_API_MAP_VAD_EX 'VADX' +#define OB_TAG_API_MODULE_FROM_NAME 'MODN' +#define OB_TAG_API_PROCESS_STRING 'PSTR' +#define OB_TAG_API_SEARCH 'SRCH' +#define OB_TAG_API_VFS_LIST_BLOB 'VFSB' + +//----------------------------------------------------------------------------- +// INITIALIZATION FUNCTIONALITY BELOW: +//----------------------------------------------------------------------------- + +/* +* Close all VMM_HANDLE and clean up everything! No VMM_HANDLE will be valid +* after this function has been called. +*/ +VOID VmmDllCore_CloseAll(); + +/* +* Close a VMM_HANDLE and clean up everything! The VMM_HANDLE will not be valid +* after this function has been called. +* -- H +*/ +VOID VmmDllCore_Close(_In_opt_ _Post_ptr_invalid_ VMM_HANDLE H); + +/* +* Initialize MemProcFS from user parameters. Upon success a VMM_HANDLE is returned. +* -- argc +* -- argv +* -- ppLcErrorInfo +* -- return +*/ +_Success_(return != NULL) +VMM_HANDLE VmmDllCore_Initialize(_In_ DWORD argc, _In_ LPSTR argv[], _Out_opt_ PPLC_CONFIG_ERRORINFO ppLcErrorInfo); + +EXPORTED_FUNCTION _Success_(return != NULL) +VMM_HANDLE VMMDLL_InitializeEx(_In_ DWORD argc, _In_ LPSTR argv[], _Out_opt_ PPLC_CONFIG_ERRORINFO ppLcErrorInfo) +{ + return VmmDllCore_Initialize(argc, argv, ppLcErrorInfo); +} + +EXPORTED_FUNCTION _Success_(return != NULL) +VMM_HANDLE VMMDLL_Initialize(_In_ DWORD argc, _In_ LPSTR argv[]) +{ + return VMMDLL_InitializeEx(argc, argv, NULL); +} + +EXPORTED_FUNCTION +VOID VMMDLL_Close(_In_opt_ _Post_ptr_invalid_ VMM_HANDLE H) +{ + if(H && (H->magic == VMM_MAGIC)) { + VmmDllCore_Close(H); + } +} + +EXPORTED_FUNCTION +VOID VMMDLL_CloseAll() +{ + VmmDllCore_CloseAll(); +} + + + // ---------------------------------------------------------------------------- // Synchronization macro below. The VMM isn't thread safe so it's important to // serialize access to it over the VMM LockMaster. This master lock is shared // with internal VMM housekeeping functionality. // ---------------------------------------------------------------------------- -#define CALL_IMPLEMENTATION_VMM(id, fn) { \ - QWORD tm; \ - BOOL result; \ - if(!ctxVmm) { return FALSE; } \ - tm = Statistics_CallStart(); \ - result = fn; \ - Statistics_CallEnd(id, tm); \ - return result; \ -} - -#define CALL_IMPLEMENTATION_VMM_RETURN(id, RetTp, RetValFail, fn) { \ - QWORD tm; \ - RetTp retVal; \ - if(!ctxVmm) { return ((RetTp)RetValFail); } /* UNSUCCESSFUL */ \ - tm = Statistics_CallStart(); \ - retVal = fn; \ - Statistics_CallEnd(id, tm); \ - return retVal; \ -} - -//----------------------------------------------------------------------------- -// INITIALIZATION FUNCTIONALITY BELOW: -//----------------------------------------------------------------------------- - -_Success_(return) -BOOL VmmDll_ConfigIntialize(_In_ DWORD argc, _In_ char* argv[]) -{ - char* argv2[3]; - DWORD i = 0, iPageFile; - if((argc == 2) && argv[1][0] && (argv[1][0] != '-')) { - // click to open -> only 1 argument ... - argv2[0] = argv[0]; - argv2[1] = "-device"; - argv2[2] = argv[1]; - return VmmDll_ConfigIntialize(3, argv2); - } - while(i < argc) { - if(0 == _stricmp(argv[i], "")) { - i++; - continue; - } else if(0 == _stricmp(argv[i], "-printf")) { - ctxMain->cfg.fVerboseDll = TRUE; - i++; - continue; - } else if(0 == _stricmp(argv[i], "-userinteract")) { - ctxMain->cfg.fUserInteract = TRUE; - i++; - continue; - } else if(0 == _stricmp(argv[i], "-v")) { - ctxMain->cfg.fVerbose = TRUE; - i++; - continue; - } else if(0 == _stricmp(argv[i], "-vv")) { - ctxMain->cfg.fVerboseExtra = TRUE; - i++; - continue; - } else if(0 == _stricmp(argv[i], "-vvv")) { - ctxMain->cfg.fVerboseExtraTlp = TRUE; - i++; - continue; - } else if(0 == _stricmp(argv[i], "-disable-symbolserver")) { - ctxMain->cfg.fDisableSymbolServerOnStartup = TRUE; - i++; - continue; - } else if(0 == _stricmp(argv[i], "-disable-symbols")) { - ctxMain->cfg.fDisableSymbolServerOnStartup = TRUE; - ctxMain->cfg.fDisableSymbols = TRUE; - i++; - continue; - } else if(0 == _stricmp(argv[i], "-disable-infodb")) { - ctxMain->cfg.fDisableInfoDB = TRUE; - i++; - continue; - } else if(0 == _stricmp(argv[i], "-disable-python")) { - ctxMain->cfg.fDisablePython = TRUE; - i++; - continue; - } else if(0 == _stricmp(argv[i], "-norefresh")) { - ctxMain->cfg.fDisableBackgroundRefresh = TRUE; - i++; - continue; - } else if(0 == _stricmp(argv[i], "-waitinitialize")) { - ctxMain->cfg.fWaitInitialize = TRUE; - i++; - continue; - } else if(i + 1 >= argc) { - return FALSE; - } else if(0 == _stricmp(argv[i], "-cr3")) { - ctxMain->cfg.paCR3 = Util_GetNumericA(argv[i + 1]); - i += 2; - continue; - } else if(0 == _stricmp(argv[i], "-forensic")) { - ctxMain->cfg.tpForensicMode = (DWORD)Util_GetNumericA(argv[i + 1]); - if(ctxMain->cfg.tpForensicMode > FC_DATABASE_TYPE_MAX) { return FALSE; } - i += 2; - continue; - } else if(0 == _stricmp(argv[i], "-max")) { - ctxMain->dev.paMax = Util_GetNumericA(argv[i + 1]); - i += 2; - continue; - } else if((0 == _stricmp(argv[i], "-device")) || (0 == strcmp(argv[i], "-z"))) { - strcpy_s(ctxMain->dev.szDevice, MAX_PATH, argv[i + 1]); - i += 2; - continue; - } else if(0 == _stricmp(argv[i], "-remote")) { - strcpy_s(ctxMain->dev.szRemote, MAX_PATH, argv[i + 1]); - i += 2; - continue; - } else if(0 == _stricmp(argv[i], "-memmap")) { - strcpy_s(ctxMain->cfg.szMemMap, MAX_PATH, argv[i + 1]); - i += 2; - continue; - } else if(0 == _stricmp(argv[i], "-memmap-str")) { - strcpy_s(ctxMain->cfg.szMemMapStr, _countof(ctxMain->cfg.szMemMapStr), argv[i + 1]); - i += 2; - continue; - } else if(0 == _stricmp(argv[i], "-pythonpath")) { - strcpy_s(ctxMain->cfg.szPythonPath, MAX_PATH, argv[i + 1]); - i += 2; - continue; - } else if(0 == _stricmp(argv[i], "-mount")) { - i += 2; - continue; - } else if(0 == _stricmp(argv[i], "-logfile")) { - strcpy_s(ctxMain->cfg.szLogFile, MAX_PATH, argv[i + 1]); - i += 2; - continue; - } else if(0 == _stricmp(argv[i], "-loglevel")) { - strcpy_s(ctxMain->cfg.szLogLevel, MAX_PATH, argv[i + 1]); - i += 2; - continue; - } else if(0 == _strnicmp(argv[i], "-pagefile", 9)) { - iPageFile = argv[i][9] - '0'; - if(iPageFile < 10) { - strcpy_s(ctxMain->cfg.szPageFile[iPageFile], MAX_PATH, argv[i + 1]); - } - i += 2; - continue; - } else { - return FALSE; - } - } - if(ctxMain->dev.paMax && (ctxMain->dev.paMax < 0x00100000)) { return FALSE; } - if(!ctxMain->dev.paMax && (ctxMain->cfg.szMemMap[0] || ctxMain->cfg.szMemMapStr[0])) { - // disable memory auto-detect when memmap is specified - ctxMain->dev.paMax = -1; - } - ctxMain->cfg.fFileInfoHeader = TRUE; - ctxMain->cfg.fVerbose = ctxMain->cfg.fVerbose && ctxMain->cfg.fVerboseDll; - ctxMain->cfg.fVerboseExtra = ctxMain->cfg.fVerboseExtra && ctxMain->cfg.fVerboseDll; - ctxMain->cfg.fVerboseExtraTlp = ctxMain->cfg.fVerboseExtraTlp && ctxMain->cfg.fVerboseDll; - ctxMain->dev.dwVersion = LC_CONFIG_VERSION; - ctxMain->dev.dwPrintfVerbosity |= ctxMain->cfg.fVerboseDll ? LC_CONFIG_PRINTF_ENABLED : 0; - ctxMain->dev.dwPrintfVerbosity |= ctxMain->cfg.fVerbose ? LC_CONFIG_PRINTF_V : 0; - ctxMain->dev.dwPrintfVerbosity |= ctxMain->cfg.fVerboseExtra ? LC_CONFIG_PRINTF_VV : 0; - ctxMain->dev.dwPrintfVerbosity |= ctxMain->cfg.fVerboseExtraTlp ? LC_CONFIG_PRINTF_VVV : 0; - VmmLog_LevelRefresh(); - return (ctxMain->dev.szDevice[0] != 0); -} - -VOID VmmDll_PrintHelp() -{ - vmmprintf( - " \n" \ - " THE MEMORY PROCESS FILE SYSTEM v%i.%i.%i COMMAND LINE REFERENCE: \n" \ - " The Memory Process File System may be used in stand-alone mode with support \n" \ - " for memory dump files, local memory via rekall winpmem driver or together with\n" \ - " PCILeech if pcileech.dll is placed in the application directory. For infor- \n" \ - " mation about PCILeech please consult the separate PCILeech documentation. \n" \ - " ----- \n" \ - " The Memory Process File System (c) 2018-2021 Ulf Frisk \n" \ - " License: GNU Affero General Public License v3.0 \n" \ - " Contact information: pcileech@frizk.net \n" \ - " The Memory Process File System: https://github.com/ufrisk/MemProcFS \n" \ - " LeechCore: https://github.com/ufrisk/LeechCore \n" \ - " PCILeech: https://github.com/ufrisk/pcileech \n" \ - " ----- \n" \ - " The recommended way to use the Memory Process File System is to specify the \n" \ - " memory acquisition device in the -device option and possibly more options. \n" \ - " Example 1: MemProcFS.exe -device c:\\temp\\memdump-win10x64.pmem \n" \ - " Example 2: MemProcFS.exe -device c:\\temp\\memdump-winXPx86.dumpit -v -vv \n" \ - " Example 3: MemProcFS.exe -device FPGA \n" \ - " Example 4: MemProcFS.exe -device PMEM://c:\\temp\\winpmem_x64.sys \n" \ - " The Memory Process File System may also be started the memory dump file name \n" \ - " as the only option. This allows to make file extensions associated so that \n" \ - " they may be opened by double-clicking on them. This mode allows no options. \n" \ - " Example 4: MemProcFS.exe c:\\dumps\\memdump-win7x64.dumpit \n" \ - " ----- \n" \ - " Valid options: \n" \ - " -device : select memory acquisition device or memory dump file to use. \n" \ - " Valid options: \n" \ - " such as, but not limited to: , PMEM, FPGA \n" \ - " --- \n" \ - " = memory dump file name optionally including path.\n" \ - " PMEM = use winpmem 'winpmem_64.sys' to acquire live memory. \n" \ - " PMEM://c:\\path\\to\\winpmem_64.sys = path to winpmem driver. \n" \ - " --- \n" \ - " Please see https://github.com/ufrisk/LeechCore for additional info. \n" \ - " -remote : connect to a remote host running the LeechAgent. Please see the \n" \ - " LeechCore documentation for more information. \n" \ - " -v : verbose option. Additional information is displayed in the output. \n" \ - " Option has no value. Example: -v \n" \ - " -vv : extra verbose option. More detailed additional information is shown \n" \ - " in output. Option has no value. Example: -vv \n" \ - " -vvv : super verbose option. Show all data transferred such as PCIe TLPs. \n" \ - " Option has no value. Example: -vvv \n" \ - " -logfile : specify an optional log file. \n" \ - " -loglevel : specify the log verbosity level as a comma-separated list. \n" \ - " Please consult https://github.com/ufrisk/MemProcFS/wiki for details. \n" \ - " example: -loglevel 4,f:5,f:VMM:6 \n" \ - " -cr3 : base address of kernel/process page table (PML4) / CR3 CPU register. \n" \ - " -max : memory max address, valid range: 0x0 .. 0xffffffffffffffff \n" \ - " default: auto-detect (max supported by device / target system). \n" \ - " -memmap-str : specify a physical memory map in parameter agrument text. \n" \ - " -memmap : specify a physical memory map given in a file or specify 'auto'. \n" \ - " example: -memmap c:\\temp\\my_custom_memory_map.txt \n" \ - " example: -memmap auto \n" \ - " -pagefile0..9 : specify specify page file / swap file. By default pagefile \n" \ - " have index 0 - example: -pagefile0 pagefile.sys while swapfile have \n" \ - " have index 1 - example: -pagefile1 swapfile.sys \n" \ - " -pythonpath : specify the path to a python 3 installation for Windows. \n" \ - " The path given should be to the directory that contain: python.dll \n" \ - " Example: -pythonpath \"C:\\Program Files\\Python37\" \n" \ - " -disable-python : prevent/disable the python plugin sub-system from loading.\n" \ - " Example: -disable-python \n" \ - " -disable-symbolserver : disable any integrations with the Microsoft Symbol \n" \ - " Server used by the debugging .pdb symbol subsystem. Functionality \n" \ - " will be limited if this is activated. Example: -disable-symbolserver \n" \ - " -disable-symbols : disable symbol lookups from .pdb files. \n" \ - " Example: -disable-symbols \n" \ - " -disable-infodb : disable the infodb and any symbol lookups via it. \n" \ - " Example: -disable-infodb \n" \ - " -mount : drive letter/path to mount The Memory Process File system at. \n" \ - " default: M Example: -mount Q \n" \ - " -norefresh : disable automatic cache and processes refreshes even when \n" \ - " running against a live memory target - such as PCIe FPGA or live \n" \ - " driver acquired memory. This is not recommended. Example: -norefresh \n" \ - " -waitinitialize : wait debugging .pdb symbol subsystem to fully start before\n" \ - " mounting file system and fully starting MemProcFS. \n" \ - " -userinteract = allow vmm.dll to, on the console, query the user for \n" \ - " information such as, but not limited to, leechcore device options. \n" \ - " Default: user interaction = disabled. \n" \ - " -forensic : start a forensic scan of the physical memory immediately after \n" \ - " startup if possible. Allowed parameter values range from 0-4. \n" \ - " Note! forensic mode is not available for live memory. \n" \ - " 0 = not enabled (default value) \n" \ - " 1 = forensic mode with in-memory sqlite database. \n" \ - " 2 = forensic mode with temp sqlite database deleted upon exit. \n" \ - " 3 = forensic mode with temp sqlite database remaining upon exit. \n" \ - " 4 = forensic mode with static named sqlite database (vmm.sqlite3). \n" \ - " default: 0 Example -forensic 4 \n" \ - " \n", - VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION - ); -} - -VOID VmmDll_FreeContext() -{ - if(ctxFc) { - FcClose(); - } - if(ctxVmm) { - VmmClose(); - } - if(ctxMain) { - Statistics_CallSetEnabled(FALSE); - LcClose(ctxMain->hLC); - LocalFree(ctxMain); - ctxMain = NULL; - } -} - /* -* Initialize memory map auto - i.e. retrieve it from the registry and load it into LeechCore. +* Verify that the supplied handle is valid and also check it out. +* This must be called by each external access which requires a VMM_HANDLE. +* Each successful VmmDllCore_HandleReserveExternal() call must be matched by +* a matched call to VmmDllCore_HandleReturnExternal() after completion. +* -- H * -- return */ _Success_(return) -BOOL VMMDLL_Initialize_MemMapAuto() -{ - BOOL fResult = FALSE; - DWORD i, cbMemMap = 0; - LPSTR szMemMap = NULL; - PVMMOB_MAP_PHYSMEM pObMap = NULL; - if(!VmmMap_GetPhysMem(&pObMap)) { goto fail; } - if(!(szMemMap = LocalAlloc(LMEM_ZEROINIT, 0x01000000))) { goto fail; } - for(i = 0; i < pObMap->cMap; i++) { - cbMemMap += snprintf(szMemMap + cbMemMap, 0x01000000 - cbMemMap - 1, "%016llx %016llx\n", pObMap->pMap[i].pa, pObMap->pMap[i].pa + pObMap->pMap[i].cb - 1); - } - fResult = - LcCommand(ctxMain->hLC, LC_CMD_MEMMAP_SET, cbMemMap, (PBYTE)szMemMap, NULL, NULL) && - LcGetOption(ctxMain->hLC, LC_OPT_CORE_ADDR_MAX, &ctxMain->dev.paMax); -fail: - Ob_DECREF(pObMap); - LocalFree(szMemMap); - return fResult; +BOOL VmmDllCore_HandleReserveExternal(_In_opt_ VMM_HANDLE H); + +/* +* Return a handle successfully reserved with a previous call to the function: +* VmmDllCore_HandleReserveExternal() +* -- H +*/ +VOID VmmDllCore_HandleReturnExternal(_In_ VMM_HANDLE H); + +#define CALL_IMPLEMENTATION_VMM(H, id, fn) { \ + QWORD tm; \ + BOOL result; \ + if(!VmmDllCore_HandleReserveExternal(H)) { return FALSE; } \ + tm = Statistics_CallStart(H); \ + result = fn; \ + Statistics_CallEnd(H, id, tm); \ + VmmDllCore_HandleReturnExternal(H); \ + return result; \ } -#ifdef _WIN32 - -_Success_(return) -BOOL VMMDLL_Initialize_RequestUserInput(_In_ DWORD argc, _In_ LPSTR argv[]) -{ - BOOL fResult; - LPSTR szProto; - DWORD i, cbRead = 0; - CHAR szInput[33] = { 0 }; - CHAR szDevice[MAX_PATH] = { 0 }; - HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); // must not be closed. - // 1: read input - vmmprintf("\n?> "); - fResult = ReadConsoleA(hStdIn, szInput, 32, &cbRead, NULL); - for(i = 0; i < _countof(szInput); i++) { - if((szInput[i] == '\r') || (szInput[i] == '\n')) { szInput[i] = 0; } - } - cbRead = (DWORD)strlen(szInput); - if(!cbRead) { return FALSE; } - // 2: clear "userinput" option and update "device" option - for(i = 0; i < argc; i++) { - if(0 == _stricmp(argv[i], "-userinteract")) { - argv[i] = ""; - } - if((i + 1 < argc) && ((0 == _stricmp(argv[i], "-device")) || (0 == strcmp(argv[i], "-z")))) { - szProto = strstr(argv[i + 1], "://"); - snprintf( - szDevice, - MAX_PATH - 1, - "%s%s%sid=%s", - argv[i + 1], - szProto ? "" : "://", - szProto && szProto[3] ? "," : "", - szInput); - argv[i + 1] = szDevice; - } - } - // 3: try re-initialize with new user input - return VMMDLL_InitializeEx(argc, argv, NULL); +#define CALL_IMPLEMENTATION_VMM_RETURN(H, id, RetTp, RetValFail, fn) { \ + QWORD tm; \ + RetTp retVal; \ + if(!VmmDllCore_HandleReserveExternal(H)) { return ((RetTp)RetValFail); } \ + tm = Statistics_CallStart(H); \ + retVal = fn; \ + Statistics_CallEnd(H, id, tm); \ + VmmDllCore_HandleReturnExternal(H); \ + return retVal; \ } -#endif /* _WIN32 */ +/* +* Query the size of memory allocated by the VMMDLL. +* -- pvMem +* -- return = number of bytes required to hold memory allocation. +*/ +_Success_(return != 0) +SIZE_T VmmDllCore_MemSizeExternal(_In_ PVOID pvMem); -EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_InitializeEx(_In_ DWORD argc, _In_ LPSTR argv[], _Out_opt_ PPLC_CONFIG_ERRORINFO ppLcErrorInfo) -{ - FILE *hFile = NULL; - BOOL f; - DWORD cbMemMap = 0; - PBYTE pbMemMap = NULL; - PLC_CONFIG_ERRORINFO pLcErrorInfo = NULL; - LPSTR uszUserText; - BYTE pbBuffer[3 * MAX_PATH]; - if(ppLcErrorInfo) { *ppLcErrorInfo = NULL; } - if(!(ctxMain = LocalAlloc(LMEM_ZEROINIT, sizeof(VMM_MAIN_CONTEXT)))) { return FALSE; } - // initialize configuration - if(!VmmDll_ConfigIntialize((DWORD)argc, argv)) { - VmmDll_PrintHelp(); - goto fail; - } - // ctxMain.cfg context is inintialized from here onwards - vmmprintf is working! - if(!(ctxMain->hLC = LcCreateEx(&ctxMain->dev, &pLcErrorInfo))) { -#ifdef _WIN32 - if(pLcErrorInfo && (pLcErrorInfo->dwVersion == LC_CONFIG_ERRORINFO_VERSION)) { - if(pLcErrorInfo->cwszUserText && CharUtil_WtoU(pLcErrorInfo->wszUserText, -1, pbBuffer, sizeof(pbBuffer), &uszUserText, NULL, 0)) { - vmmprintf("MESSAGE FROM MEMORY ACQUISITION DEVICE:\n=======================================\n%s\n", uszUserText); - } - if(ctxMain->cfg.fUserInteract && pLcErrorInfo->fUserInputRequest) { - LcMemFree(pLcErrorInfo); - return VMMDLL_Initialize_RequestUserInput(argc, argv); - } - } -#endif /* _WIN32 */ - vmmprintf("MemProcFS: Failed to connect to memory acquisition device.\n"); - goto fail; - } - // Set LeechCore MemMap (if exists and not auto - i.e. from file) - if(ctxMain->cfg.szMemMap[0] && _stricmp(ctxMain->cfg.szMemMap, "auto")) { - f = (pbMemMap = LocalAlloc(LMEM_ZEROINIT, 0x01000000)) && - !fopen_s(&hFile, ctxMain->cfg.szMemMap, "rb") && hFile && - (cbMemMap = (DWORD)fread(pbMemMap, 1, 0x01000000, hFile)) && (cbMemMap < 0x01000000) && - LcCommand(ctxMain->hLC, LC_CMD_MEMMAP_SET, cbMemMap, pbMemMap, NULL, NULL) && - LcGetOption(ctxMain->hLC, LC_OPT_CORE_ADDR_MAX, &ctxMain->dev.paMax); - LocalFree(pbMemMap); - if(hFile) { fclose(hFile); } - if(!f) { - vmmprintf("MemProcFS: Failed to load initial memory map from: '%s'.\n", ctxMain->cfg.szMemMap); - goto fail; - } - } - if(ctxMain->cfg.szMemMapStr[0]) { - f = LcCommand(ctxMain->hLC, LC_CMD_MEMMAP_SET, (DWORD)strlen(ctxMain->cfg.szMemMapStr), ctxMain->cfg.szMemMapStr, NULL, NULL) && - LcGetOption(ctxMain->hLC, LC_OPT_CORE_ADDR_MAX, &ctxMain->dev.paMax); - if(!f) { - vmmprintf("MemProcFS: Failed to load command line argument memory map.\n"); - goto fail; - } - } - // ctxMain.dev context is initialized from here onwards - device functionality is working! - if(!VmmProcInitialize()) { - vmmprintf("MOUNT: INFO: PROC file system not mounted.\n"); - goto fail; - } - // ctxVmm context is initialized from here onwards - vmm functionality is working! - // Set LeechCore MemMap (if auto) - if(ctxMain->cfg.szMemMap[0] && !_stricmp(ctxMain->cfg.szMemMap, "auto")) { - if(!VMMDLL_Initialize_MemMapAuto()) { - vmmprintf("MemProcFS: Failed to load initial memory map from: '%s'.\n", ctxMain->cfg.szMemMap); - goto fail; - } - } - // Initialize forensic mode (if set by user parameter) - if(ctxMain->cfg.tpForensicMode) { - if(!FcInitialize(ctxMain->cfg.tpForensicMode, FALSE)) { - if(ctxMain->dev.fVolatile) { - vmmprintf("MemProcFS: Failed to initialize forensic mode - volatile (live) memory not supported - please use memory dump!\n"); - } else { - vmmprintf("MemProcFS: Failed to initialize forensic mode.\n"); - } - goto fail; - } - } - return TRUE; -fail: - if(ppLcErrorInfo) { - *ppLcErrorInfo = pLcErrorInfo; - } else { - LcMemFree(pLcErrorInfo); - } - VmmDll_FreeContext(); - return FALSE; -} +/* +* Free memory allocated by the VMMDLL. +* -- pvMem +*/ +VOID VmmDllCore_MemFreeExternal(_Frees_ptr_opt_ PVOID pvMem); -EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_Initialize(_In_ DWORD argc, _In_ LPSTR argv[]) -{ - return VMMDLL_InitializeEx(argc, argv, NULL); -} +/* +* Allocate "external" memory to be free'd only by VMMDLL_MemFree // VmmDllCore_MemFreeExternal. +* CALLER VMMDLL_MemFree(return) +* -- H +* -- tag = tag identifying the type of object. +* -- cb = total size to allocate (not guaranteed to be zero-filled). +* -- cbHdr = size of header (guaranteed to be zero-filled). +* -- return +*/ +_Success_(return != NULL) +PVOID VmmDllCore_MemAllocExternal(_In_ VMM_HANDLE H, _In_ DWORD tag, _In_ SIZE_T cb, _In_ SIZE_T cbHdr); -EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_Close() +/* +* Query the size of memory allocated by the VMMDLL. +* -- pvMem +* -- return = number of bytes required to hold memory allocation. +*/ +EXPORTED_FUNCTION _Success_(return != 0) +SIZE_T VMMDLL_MemSize(_In_ PVOID pvMem) { - VmmDll_FreeContext(); - return TRUE; + return VmmDllCore_MemSizeExternal(pvMem); } /* * Free memory allocated by the VMMDLL. * -- pvMem */ -EXPORTED_FUNCTION VOID VMMDLL_MemFree(_Frees_ptr_opt_ PVOID pvMem) +EXPORTED_FUNCTION +VOID VMMDLL_MemFree(_Frees_ptr_opt_ PVOID pvMem) { - LocalFree(pvMem); + VmmDllCore_MemFreeExternal(pvMem); } @@ -487,11 +198,11 @@ EXPORTED_FUNCTION VOID VMMDLL_MemFree(_Frees_ptr_opt_ PVOID pvMem) //----------------------------------------------------------------------------- _Success_(return) -BOOL VMMDLL_InitializePlugins() +BOOL VMMDLL_InitializePlugins(_In_ VMM_HANDLE H) { - CALL_IMPLEMENTATION_VMM( + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_InitializePlugins, - PluginManager_Initialize()) + PluginManager_Initialize(H)) } @@ -500,18 +211,18 @@ BOOL VMMDLL_InitializePlugins() // CONFIGURATION SETTINGS BELOW: //----------------------------------------------------------------------------- -#define VMMDLL_REFRESH_CHECK(fOption, mask) (fOption & mask & 0xffff00000000) +#define VMMDLL_REFRESH_CHECK(fOption, mask) (fOption & mask & 0x0000ffff00000000) _Success_(return) -BOOL VMMDLL_ConfigGet(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue) +BOOL VMMDLL_ConfigGet_Impl(_In_ VMM_HANDLE H, _In_ ULONG64 fOption, _Out_ PULONG64 pqwValue) { if(!fOption || !pqwValue) { return FALSE; } switch(fOption & 0xffffffff00000000) { case VMMDLL_OPT_CORE_SYSTEM: - *pqwValue = ctxVmm->tpSystem; + *pqwValue = H->vmm.tpSystem; return TRUE; case VMMDLL_OPT_CORE_MEMORYMODEL: - *pqwValue = ctxVmm->tpMemoryModel; + *pqwValue = H->vmm.tpMemoryModel; return TRUE; case VMMDLL_OPT_CONFIG_VMM_VERSION_MAJOR: *pqwValue = VERSION_MAJOR; @@ -523,171 +234,176 @@ BOOL VMMDLL_ConfigGet(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue) *pqwValue = VERSION_REVISION; return TRUE; case VMMDLL_OPT_CONFIG_IS_REFRESH_ENABLED: - *pqwValue = ctxVmm->ThreadProcCache.fEnabled ? 1 : 0; + *pqwValue = H->vmm.ThreadProcCache.fEnabled ? 1 : 0; return TRUE; case VMMDLL_OPT_CONFIG_IS_PAGING_ENABLED: - *pqwValue = (ctxVmm->flags & VMM_FLAG_NOPAGING) ? 0 : 1; + *pqwValue = (H->vmm.flags & VMM_FLAG_NOPAGING) ? 0 : 1; return TRUE; case VMMDLL_OPT_CONFIG_TICK_PERIOD: - *pqwValue = ctxVmm->ThreadProcCache.cMs_TickPeriod; + *pqwValue = H->vmm.ThreadProcCache.cMs_TickPeriod; return TRUE; case VMMDLL_OPT_CONFIG_READCACHE_TICKS: - *pqwValue = ctxVmm->ThreadProcCache.cTick_MEM; + *pqwValue = H->vmm.ThreadProcCache.cTick_MEM; return TRUE; case VMMDLL_OPT_CONFIG_TLBCACHE_TICKS: - *pqwValue = ctxVmm->ThreadProcCache.cTick_TLB; + *pqwValue = H->vmm.ThreadProcCache.cTick_TLB; return TRUE; case VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_PARTIAL: - *pqwValue = ctxVmm->ThreadProcCache.cTick_Fast; + *pqwValue = H->vmm.ThreadProcCache.cTick_Fast; return TRUE; case VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_TOTAL: - *pqwValue = ctxVmm->ThreadProcCache.cTick_Medium; + *pqwValue = H->vmm.ThreadProcCache.cTick_Medium; return TRUE; case VMMDLL_OPT_CONFIG_STATISTICS_FUNCTIONCALL: - *pqwValue = Statistics_CallGetEnabled() ? 1 : 0; + *pqwValue = Statistics_CallGetEnabled(H) ? 1 : 0; return TRUE; case VMMDLL_OPT_WIN_VERSION_MAJOR: - *pqwValue = ctxVmm->kernel.dwVersionMajor; + *pqwValue = H->vmm.kernel.dwVersionMajor; return TRUE; case VMMDLL_OPT_WIN_VERSION_MINOR: - *pqwValue = ctxVmm->kernel.dwVersionMinor; + *pqwValue = H->vmm.kernel.dwVersionMinor; return TRUE; case VMMDLL_OPT_WIN_VERSION_BUILD: - *pqwValue = ctxVmm->kernel.dwVersionBuild; + *pqwValue = H->vmm.kernel.dwVersionBuild; return TRUE; case VMMDLL_OPT_WIN_SYSTEM_UNIQUE_ID: - *pqwValue = ctxVmm->dwSystemUniqueId; + *pqwValue = H->vmm.dwSystemUniqueId; return TRUE; case VMMDLL_OPT_FORENSIC_MODE: - *pqwValue = ctxFc ? (BYTE)ctxFc->db.tp : 0; + *pqwValue = H->fc ? (BYTE)H->fc->db.tp : 0; return TRUE; // core options affecting both vmm.dll and pcileech.dll case VMMDLL_OPT_CORE_PRINTF_ENABLE: - *pqwValue = ctxMain->cfg.fVerboseDll ? 1 : 0; + *pqwValue = H->cfg.fVerboseDll ? 1 : 0; return TRUE; case VMMDLL_OPT_CORE_VERBOSE: - *pqwValue = ctxMain->cfg.fVerbose ? 1 : 0; + *pqwValue = H->cfg.fVerbose ? 1 : 0; return TRUE; case VMMDLL_OPT_CORE_VERBOSE_EXTRA: - *pqwValue = ctxMain->cfg.fVerboseExtra ? 1 : 0; + *pqwValue = H->cfg.fVerboseExtra ? 1 : 0; return TRUE; case VMMDLL_OPT_CORE_VERBOSE_EXTRA_TLP: - *pqwValue = ctxMain->cfg.fVerboseExtraTlp ? 1 : 0; + *pqwValue = H->cfg.fVerboseExtraTlp ? 1 : 0; return TRUE; case VMMDLL_OPT_CORE_MAX_NATIVE_ADDRESS: - *pqwValue = ctxMain->dev.paMax; + *pqwValue = H->dev.paMax; return TRUE; default: // non-recognized option - possibly a device option to pass along to leechcore.dll - return LcGetOption(ctxMain->hLC, fOption, pqwValue); + return LcGetOption(H->hLC, fOption, pqwValue); } } _Success_(return) -BOOL VMMDLL_ConfigSet(_In_ ULONG64 fOption, _In_ ULONG64 qwValue) +BOOL VMMDLL_ConfigSet_Impl(_In_ VMM_HANDLE H, _In_ ULONG64 fOption, _In_ ULONG64 qwValue) { + if(!H || (H->magic != VMM_MAGIC)) { return FALSE; } // user-initiated refresh / cache flushes if((fOption & 0xffff000000000000) == 0x2001000000000000) { if(VMMDLL_REFRESH_CHECK(fOption, VMMDLL_OPT_REFRESH_FREQ_MEM)) { - VmmProcRefresh_MEM(); + VmmProcRefresh_MEM(H); + VmmProcRefresh_MEM(H); + VmmProcRefresh_MEM(H); + } + if(VMMDLL_REFRESH_CHECK(fOption, VMMDLL_OPT_REFRESH_FREQ_MEM_PARTIAL)) { + VmmProcRefresh_MEM(H); } if(VMMDLL_REFRESH_CHECK(fOption, VMMDLL_OPT_REFRESH_FREQ_TLB)) { - VmmProcRefresh_TLB(); + VmmProcRefresh_TLB(H); + VmmProcRefresh_TLB(H); + VmmProcRefresh_TLB(H); + } + if(VMMDLL_REFRESH_CHECK(fOption, VMMDLL_OPT_REFRESH_FREQ_TLB_PARTIAL)) { + VmmProcRefresh_TLB(H); } if(VMMDLL_REFRESH_CHECK(fOption, VMMDLL_OPT_REFRESH_FREQ_FAST)) { - VmmProcRefresh_Fast(); + VmmProcRefresh_Fast(H); } if(VMMDLL_REFRESH_CHECK(fOption, VMMDLL_OPT_REFRESH_FREQ_MEDIUM)) { - VmmProcRefresh_Medium(); + VmmProcRefresh_Medium(H); } if(VMMDLL_REFRESH_CHECK(fOption, VMMDLL_OPT_REFRESH_FREQ_SLOW)) { - VmmProcRefresh_Slow(); - } - if(VMMDLL_REFRESH_CHECK(fOption, VMMDLL_OPT_REFRESH_PAGING)) { - VmmCacheClear(VMM_CACHE_TAG_PAGING); - } - if(VMMDLL_REFRESH_CHECK(fOption, VMMDLL_OPT_REFRESH_USER)) { - VmmWinUser_Refresh(); - } - if(VMMDLL_REFRESH_CHECK(fOption, VMMDLL_OPT_REFRESH_PHYSMEMMAP)) { - VmmWinPhysMemMap_Refresh(); - } - if(VMMDLL_REFRESH_CHECK(fOption, VMMDLL_OPT_REFRESH_PFN)) { - MmPfn_Refresh(); - } - if(VMMDLL_REFRESH_CHECK(fOption, VMMDLL_OPT_REFRESH_OBJ)) { - VmmWinObj_Refresh(); - } - if(VMMDLL_REFRESH_CHECK(fOption, VMMDLL_OPT_REFRESH_NET)) { - VmmNet_Refresh(); + VmmProcRefresh_Slow(H); } return TRUE; } switch(fOption & 0xffffffff00000000) { case VMMDLL_OPT_CORE_PRINTF_ENABLE: - LcSetOption(ctxMain->hLC, fOption, qwValue); - ctxMain->cfg.fVerboseDll = qwValue ? TRUE : FALSE; - VmmLog_LevelRefresh(); - PluginManager_Notify(VMMDLL_PLUGIN_NOTIFY_VERBOSITYCHANGE, NULL, 0); + LcSetOption(H->hLC, fOption, qwValue); + H->cfg.fVerboseDll = qwValue ? TRUE : FALSE; + VmmLog_LevelRefresh(H); + PluginManager_Notify(H, VMMDLL_PLUGIN_NOTIFY_VERBOSITYCHANGE, NULL, 0); return TRUE; case VMMDLL_OPT_CORE_VERBOSE: - LcSetOption(ctxMain->hLC, fOption, qwValue); - ctxMain->cfg.fVerbose = qwValue ? TRUE : FALSE; - VmmLog_LevelRefresh(); - PluginManager_Notify(VMMDLL_PLUGIN_NOTIFY_VERBOSITYCHANGE, NULL, 0); + LcSetOption(H->hLC, fOption, qwValue); + H->cfg.fVerbose = qwValue ? TRUE : FALSE; + VmmLog_LevelRefresh(H); + PluginManager_Notify(H, VMMDLL_PLUGIN_NOTIFY_VERBOSITYCHANGE, NULL, 0); return TRUE; case VMMDLL_OPT_CORE_VERBOSE_EXTRA: - LcSetOption(ctxMain->hLC, fOption, qwValue); - ctxMain->cfg.fVerboseExtra = qwValue ? TRUE : FALSE; - VmmLog_LevelRefresh(); - PluginManager_Notify(VMMDLL_PLUGIN_NOTIFY_VERBOSITYCHANGE, NULL, 0); + LcSetOption(H->hLC, fOption, qwValue); + H->cfg.fVerboseExtra = qwValue ? TRUE : FALSE; + VmmLog_LevelRefresh(H); + PluginManager_Notify(H, VMMDLL_PLUGIN_NOTIFY_VERBOSITYCHANGE, NULL, 0); return TRUE; case VMMDLL_OPT_CORE_VERBOSE_EXTRA_TLP: - LcSetOption(ctxMain->hLC, fOption, qwValue); - ctxMain->cfg.fVerboseExtraTlp = qwValue ? TRUE : FALSE; - VmmLog_LevelRefresh(); - PluginManager_Notify(VMMDLL_PLUGIN_NOTIFY_VERBOSITYCHANGE, NULL, 0); + LcSetOption(H->hLC, fOption, qwValue); + H->cfg.fVerboseExtraTlp = qwValue ? TRUE : FALSE; + VmmLog_LevelRefresh(H); + PluginManager_Notify(H, VMMDLL_PLUGIN_NOTIFY_VERBOSITYCHANGE, NULL, 0); return TRUE; case VMMDLL_OPT_CONFIG_IS_PAGING_ENABLED: - ctxVmm->flags = (ctxVmm->flags & ~VMM_FLAG_NOPAGING) | (qwValue ? 0 : 1); + H->vmm.flags = (H->vmm.flags & ~VMM_FLAG_NOPAGING) | (qwValue ? 0 : 1); return TRUE; case VMMDLL_OPT_CONFIG_TICK_PERIOD: - ctxVmm->ThreadProcCache.cMs_TickPeriod = (DWORD)qwValue; + H->vmm.ThreadProcCache.cMs_TickPeriod = (DWORD)qwValue; return TRUE; case VMMDLL_OPT_CONFIG_READCACHE_TICKS: - ctxVmm->ThreadProcCache.cTick_MEM = (DWORD)qwValue; + H->vmm.ThreadProcCache.cTick_MEM = (DWORD)qwValue; return TRUE; case VMMDLL_OPT_CONFIG_TLBCACHE_TICKS: - ctxVmm->ThreadProcCache.cTick_TLB = (DWORD)qwValue; + H->vmm.ThreadProcCache.cTick_TLB = (DWORD)qwValue; return TRUE; case VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_PARTIAL: - ctxVmm->ThreadProcCache.cTick_Fast = (DWORD)qwValue; + H->vmm.ThreadProcCache.cTick_Fast = (DWORD)qwValue; return TRUE; case VMMDLL_OPT_CONFIG_PROCCACHE_TICKS_TOTAL: - ctxVmm->ThreadProcCache.cTick_Medium = (DWORD)qwValue; + H->vmm.ThreadProcCache.cTick_Medium = (DWORD)qwValue; return TRUE; case VMMDLL_OPT_CONFIG_STATISTICS_FUNCTIONCALL: - Statistics_CallSetEnabled(qwValue ? TRUE : FALSE); + Statistics_CallSetEnabled(H, qwValue ? TRUE : FALSE); return TRUE; case VMMDLL_OPT_FORENSIC_MODE: - return FcInitialize((DWORD)qwValue, FALSE); + return FcInitialize(H, (DWORD)qwValue, FALSE); default: // non-recognized option - possibly a device option to pass along to leechcore.dll - return LcSetOption(ctxMain->hLC, fOption, qwValue); + return LcSetOption(H->hLC, fOption, qwValue); } } +_Success_(return) +BOOL VMMDLL_ConfigGet(_In_ VMM_HANDLE H, _In_ ULONG64 fOption, _Out_ PULONG64 pqwValue) +{ + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_ConfigGet, VMMDLL_ConfigGet_Impl(H, fOption, pqwValue)) +} + +_Success_(return) +BOOL VMMDLL_ConfigSet(_In_ VMM_HANDLE H, _In_ ULONG64 fOption, _In_ ULONG64 qwValue) +{ + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_ConfigSet, VMMDLL_ConfigSet_Impl(H, fOption, qwValue)) +} + //----------------------------------------------------------------------------- // VFS - VIRTUAL FILE SYSTEM FUNCTIONALITY BELOW: //----------------------------------------------------------------------------- _Success_(return) -BOOL VMMDLL_VfsList_Impl_ProcessRoot(_In_ BOOL fNamePID, _Inout_ PHANDLE pFileList) +BOOL VMMDLL_VfsList_Impl_ProcessRoot(_In_ VMM_HANDLE H, _In_ BOOL fNamePID, _Inout_ PHANDLE pFileList) { PVMM_PROCESS pObProcess = NULL; CHAR uszBufferFileName[MAX_PATH]; VMMDLL_VFS_FILELIST_EXINFO ExInfo = { 0 }; - while((pObProcess = VmmProcessGetNext(pObProcess, 0))) { + while((pObProcess = VmmProcessGetNext(H, pObProcess, 0))) { if(fNamePID) { if(pObProcess->dwState) { sprintf_s(uszBufferFileName, MAX_PATH - 1, "%s-(%x)-%i", pObProcess->szName, pObProcess->dwState, pObProcess->dwPID); @@ -697,54 +413,54 @@ BOOL VMMDLL_VfsList_Impl_ProcessRoot(_In_ BOOL fNamePID, _Inout_ PHANDLE pFileLi } else { sprintf_s(uszBufferFileName, MAX_PATH - 1, "%i", pObProcess->dwPID); } - Util_VfsTimeStampFile(pObProcess, &ExInfo); + Util_VfsTimeStampFile(H, pObProcess, &ExInfo); VMMDLL_VfsList_AddDirectory(pFileList, uszBufferFileName, &ExInfo); } return TRUE; } -BOOL VMMDLL_VfsList_Impl(_In_ LPSTR uszPath, _Inout_ PHANDLE pFileList) +BOOL VMMDLL_VfsList_Impl(_In_ VMM_HANDLE H, _In_ LPSTR uszPath, _Inout_ PHANDLE pFileList) { BOOL result = FALSE; DWORD dwPID; LPSTR wszSubPath; PVMM_PROCESS pObProcess; - if(!ctxVmm || !VMMDLL_VfsList_IsHandleValid(pFileList)) { return FALSE; } + if(!VMMDLL_VfsList_IsHandleValid(pFileList)) { return FALSE; } if(uszPath[0] == '\\') { uszPath++; } if(Util_VfsHelper_GetIdDir(uszPath, FALSE, &dwPID, &wszSubPath)) { - if(!(pObProcess = VmmProcessGet(dwPID))) { return FALSE; } - PluginManager_List(pObProcess, wszSubPath, pFileList); + if(!(pObProcess = VmmProcessGet(H, dwPID))) { return FALSE; } + PluginManager_List(H, pObProcess, wszSubPath, pFileList); Ob_DECREF(pObProcess); return TRUE; } if(!_strnicmp(uszPath, "name", 4)) { if(strlen(uszPath) > 5) { return FALSE; } - return VMMDLL_VfsList_Impl_ProcessRoot(TRUE, pFileList); + return VMMDLL_VfsList_Impl_ProcessRoot(H, TRUE, pFileList); } if(!_strnicmp(uszPath, "pid", 3)) { if(strlen(uszPath) > 4) { return FALSE; } - return VMMDLL_VfsList_Impl_ProcessRoot(FALSE, pFileList); + return VMMDLL_VfsList_Impl_ProcessRoot(H, FALSE, pFileList); } - PluginManager_List(NULL, uszPath, pFileList); + PluginManager_List(H, NULL, uszPath, pFileList); return TRUE; } _Success_(return) -BOOL VMMDLL_VfsListU(_In_ LPSTR uszPath, _Inout_ PVMMDLL_VFS_FILELIST2 pFileList) +BOOL VMMDLL_VfsListU(_In_ VMM_HANDLE H, _In_ LPSTR uszPath, _Inout_ PVMMDLL_VFS_FILELIST2 pFileList) { - CALL_IMPLEMENTATION_VMM( + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_VfsList, - VMMDLL_VfsList_Impl(uszPath, (PHANDLE)pFileList)) + VMMDLL_VfsList_Impl(H, uszPath, (PHANDLE)pFileList)) } _Success_(return) -BOOL VMMDLL_VfsListW(_In_ LPWSTR wszPath, _Inout_ PVMMDLL_VFS_FILELIST2 pFileList) +BOOL VMMDLL_VfsListW(_In_ VMM_HANDLE H, _In_ LPWSTR wszPath, _Inout_ PVMMDLL_VFS_FILELIST2 pFileList) { LPSTR uszPath; BYTE pbBuffer[3 * MAX_PATH]; if(!CharUtil_WtoU(wszPath, -1, pbBuffer, sizeof(pbBuffer), &uszPath, NULL, 0)) { return FALSE; } - return VMMDLL_VfsListU(uszPath, pFileList); + return VMMDLL_VfsListU(H, uszPath, pFileList); } typedef struct tdVMMDLL_VFS_FILELISTBLOB_CREATE_CONTEXT { @@ -774,7 +490,7 @@ VOID VMMDLL_VfsListBlob_Impl_AddDirectory(_Inout_ HANDLE h, _In_ LPSTR uszName, } _Success_(return != NULL) -PVMMDLL_VFS_FILELISTBLOB VMMDLL_VfsListBlob_Impl(_In_ LPSTR uszPath) +PVMMDLL_VFS_FILELISTBLOB VMMDLL_VfsListBlob_Impl(_In_ VMM_HANDLE H, _In_ LPSTR uszPath) { BOOL fResult = FALSE; VMMDLL_VFS_FILELISTBLOB_CREATE_CONTEXT ctx = { 0 }; @@ -783,20 +499,19 @@ PVMMDLL_VFS_FILELISTBLOB VMMDLL_VfsListBlob_Impl(_In_ LPSTR uszPath) PVMMDLL_VFS_FILELISTBLOB pFLB = NULL; PVMMDLL_VFS_FILELISTBLOB_ENTRY pe; // 1: init - if(!(ctx.pme = ObMap_New(OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } - if(!(ctx.psm = ObStrMap_New(OB_STRMAP_FLAGS_STR_ASSIGN_OFFSET))) { goto fail; } + if(!(ctx.pme = ObMap_New(H, OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } + if(!(ctx.psm = ObStrMap_New(H, OB_STRMAP_FLAGS_STR_ASSIGN_OFFSET))) { goto fail; } // 2: call FL2.dwVersion = VMMDLL_VFS_FILELIST_VERSION; FL2.pfnAddFile = VMMDLL_VfsListBlob_Impl_AddFile; FL2.pfnAddDirectory = VMMDLL_VfsListBlob_Impl_AddDirectory; FL2.h = &ctx; - if(!VMMDLL_VfsList_Impl(uszPath, (PHANDLE)&FL2)) { goto fail; } + if(!VMMDLL_VfsList_Impl(H, uszPath, (PHANDLE)&FL2)) { goto fail; } // 3: assign result blob cFileEntry = ObMap_Size(ctx.pme); if(!ObStrMap_FinalizeBufferU(ctx.psm, 0, NULL, &cbMultiText)) { goto fail; } cbStruct = sizeof(VMMDLL_VFS_FILELISTBLOB) + cFileEntry * sizeof(VMMDLL_VFS_FILELISTBLOB_ENTRY) + cbMultiText; - if(!(pFLB = LocalAlloc(0, cbStruct))) { goto fail; } - ZeroMemory(pFLB, sizeof(VMMDLL_VFS_FILELISTBLOB)); + if(!(pFLB = VmmDllCore_MemAllocExternal(H, OB_TAG_API_VFS_LIST_BLOB, cbStruct, sizeof(VMMDLL_VFS_FILELISTBLOB)))) { goto fail; } // VMMDLL_MemFree() pFLB->dwVersion = VMMDLL_VFS_FILELISTBLOB_VERSION; pFLB->cbStruct = cbStruct; pFLB->cFileEntry = cFileEntry; @@ -811,86 +526,89 @@ PVMMDLL_VFS_FILELISTBLOB VMMDLL_VfsListBlob_Impl(_In_ LPSTR uszPath) fail: Ob_DECREF(ctx.pme); Ob_DECREF(ctx.psm); - if(!fResult) { LocalFree(pFLB); } - return fResult ? pFLB : NULL; + if(!fResult) { + VMMDLL_MemFree(pFLB); pFLB = NULL; + } + return pFLB; } _Success_(return != NULL) -PVMMDLL_VFS_FILELISTBLOB VMMDLL_VfsListBlobU(_In_ LPSTR uszPath) +PVMMDLL_VFS_FILELISTBLOB VMMDLL_VfsListBlobU(_In_ VMM_HANDLE H, _In_ LPSTR uszPath) { CALL_IMPLEMENTATION_VMM_RETURN( + H, STATISTICS_ID_VMMDLL_VfsListBlob, PVMMDLL_VFS_FILELISTBLOB, NULL, - VMMDLL_VfsListBlob_Impl(uszPath)) + VMMDLL_VfsListBlob_Impl(H, uszPath)) } -NTSTATUS VMMDLL_VfsRead_Impl(LPSTR uszPath, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS VMMDLL_VfsRead_Impl(_In_ VMM_HANDLE H, _In_ LPSTR uszPath, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt; DWORD dwPID; LPSTR uszSubPath; PVMM_PROCESS pObProcess; - if(!ctxVmm) { return VMM_STATUS_FILE_INVALID; } if(uszPath[0] == '\\') { uszPath++; } if(Util_VfsHelper_GetIdDir(uszPath, FALSE, &dwPID, &uszSubPath)) { - if(!(pObProcess = VmmProcessGet(dwPID))) { return VMM_STATUS_FILE_INVALID; } - nt = PluginManager_Read(pObProcess, uszSubPath, pb, cb, pcbRead, cbOffset); + if(!(pObProcess = VmmProcessGet(H, dwPID))) { return VMM_STATUS_FILE_INVALID; } + nt = PluginManager_Read(H, pObProcess, uszSubPath, pb, cb, pcbRead, cbOffset); Ob_DECREF(pObProcess); return nt; } - return PluginManager_Read(NULL, uszPath, pb, cb, pcbRead, cbOffset); + return PluginManager_Read(H, NULL, uszPath, pb, cb, pcbRead, cbOffset); } -NTSTATUS VMMDLL_VfsReadU(_In_ LPSTR uszFileName, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset) +NTSTATUS VMMDLL_VfsReadU(_In_ VMM_HANDLE H, _In_ LPSTR uszFileName, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset) { CALL_IMPLEMENTATION_VMM_RETURN( + H, STATISTICS_ID_VMMDLL_VfsRead, NTSTATUS, VMMDLL_STATUS_UNSUCCESSFUL, - VMMDLL_VfsRead_Impl(uszFileName, pb, cb, pcbRead, cbOffset)) + VMMDLL_VfsRead_Impl(H, uszFileName, pb, cb, pcbRead, 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_VfsReadW(_In_ VMM_HANDLE H, _In_ LPWSTR wszFileName, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset) { LPSTR uszFileName; BYTE pbBuffer[3 * MAX_PATH]; if(!CharUtil_WtoU(wszFileName, -1, pbBuffer, sizeof(pbBuffer), &uszFileName, NULL, 0)) { return VMM_STATUS_FILE_INVALID; } - return VMMDLL_VfsReadU(uszFileName, pb, cb, pcbRead, cbOffset); + return VMMDLL_VfsReadU(H, uszFileName, pb, cb, pcbRead, cbOffset); } -NTSTATUS VMMDLL_VfsWrite_Impl(_In_ LPSTR uszPath, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) +NTSTATUS VMMDLL_VfsWrite_Impl(_In_ VMM_HANDLE H, _In_ LPSTR uszPath, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ QWORD cbOffset) { NTSTATUS nt; DWORD dwPID; LPSTR uszSubPath; PVMM_PROCESS pObProcess; - if(!ctxVmm) { return VMM_STATUS_FILE_INVALID; } if(uszPath[0] == '\\') { uszPath++; } if(Util_VfsHelper_GetIdDir(uszPath, FALSE, &dwPID, &uszSubPath)) { - if(!(pObProcess = VmmProcessGet(dwPID))) { return VMM_STATUS_FILE_INVALID; } - nt = PluginManager_Write(pObProcess, uszSubPath, pb, cb, pcbWrite, cbOffset); + if(!(pObProcess = VmmProcessGet(H, dwPID))) { return VMM_STATUS_FILE_INVALID; } + nt = PluginManager_Write(H, pObProcess, uszSubPath, pb, cb, pcbWrite, cbOffset); Ob_DECREF(pObProcess); return nt; } - return PluginManager_Write(NULL, uszPath, pb, cb, pcbWrite, cbOffset); + return PluginManager_Write(H, NULL, uszPath, pb, cb, pcbWrite, cbOffset); } -NTSTATUS VMMDLL_VfsWriteU(_In_ LPSTR uszFileName, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset) +NTSTATUS VMMDLL_VfsWriteU(_In_ VMM_HANDLE H, _In_ LPSTR uszFileName, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset) { CALL_IMPLEMENTATION_VMM_RETURN( + H, STATISTICS_ID_VMMDLL_VfsWrite, NTSTATUS, VMMDLL_STATUS_UNSUCCESSFUL, - VMMDLL_VfsWrite_Impl(uszFileName, pb, cb, pcbWrite, cbOffset)) + VMMDLL_VfsWrite_Impl(H, uszFileName, pb, cb, pcbWrite, cbOffset)) } -NTSTATUS VMMDLL_VfsWriteW(_In_ LPWSTR wszFileName, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset) +NTSTATUS VMMDLL_VfsWriteW(_In_ VMM_HANDLE H, _In_ LPWSTR wszFileName, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset) { LPSTR uszFileName; BYTE pbBuffer[3 * MAX_PATH]; if(!CharUtil_WtoU(wszFileName, -1, pbBuffer, sizeof(pbBuffer), &uszFileName, NULL, 0)) { return VMM_STATUS_FILE_INVALID; } - return VMMDLL_VfsWriteU(uszFileName, pb, cb, pcbWrite, cbOffset); + return VMMDLL_VfsWriteU(H, uszFileName, pb, cb, pcbWrite, cbOffset); } EXPORTED_FUNCTION 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) @@ -929,17 +647,16 @@ EXPORTED_FUNCTION NTSTATUS VMMDLL_UtilVfsWriteFile_DWORD(_Inout_ PDWORD pdwTarge // VMM CORE FUNCTIONALITY BELOW: //----------------------------------------------------------------------------- -DWORD VMMDLL_MemReadScatter_Impl(_In_ DWORD dwPID, _Inout_ PPMEM_SCATTER ppMEMs, _In_ DWORD cpMEMs, _In_ DWORD flags) +DWORD VMMDLL_MemReadScatter_Impl(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _Inout_ PPMEM_SCATTER ppMEMs, _In_ DWORD cpMEMs, _In_ DWORD flags) { DWORD i, cMEMs; PVMM_PROCESS pObProcess = NULL; - if(!ctxVmm) { return 0; } if(dwPID == (DWORD)-1) { - VmmReadScatterPhysical(ppMEMs, cpMEMs, flags); + VmmReadScatterPhysical(H, ppMEMs, cpMEMs, flags); } else { - pObProcess = VmmProcessGet(dwPID); + pObProcess = VmmProcessGet(H, dwPID); if(!pObProcess) { return 0; } - VmmReadScatterVirtual(pObProcess, ppMEMs, cpMEMs, flags); + VmmReadScatterVirtual(H, pObProcess, ppMEMs, cpMEMs, flags); Ob_DECREF(pObProcess); } for(i = 0, cMEMs = 0; i < cpMEMs; i++) { @@ -950,26 +667,26 @@ DWORD VMMDLL_MemReadScatter_Impl(_In_ DWORD dwPID, _Inout_ PPMEM_SCATTER ppMEMs, return cMEMs; } -DWORD VMMDLL_MemReadScatter(_In_ DWORD dwPID, _Inout_ PPMEM_SCATTER ppMEMs, _In_ DWORD cpMEMs, _In_ DWORD flags) +DWORD VMMDLL_MemReadScatter(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _Inout_ PPMEM_SCATTER ppMEMs, _In_ DWORD cpMEMs, _In_ DWORD flags) { CALL_IMPLEMENTATION_VMM_RETURN( + H, STATISTICS_ID_VMMDLL_MemReadScatter, DWORD, 0, - VMMDLL_MemReadScatter_Impl(dwPID, ppMEMs, cpMEMs, flags)) + VMMDLL_MemReadScatter_Impl(H, dwPID, ppMEMs, cpMEMs, flags)) } -DWORD VMMDLL_MemWriteScatter_Impl(_In_ DWORD dwPID, _Inout_ PPMEM_SCATTER ppMEMs, _In_ DWORD cpMEMs) +DWORD VMMDLL_MemWriteScatter_Impl(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _Inout_ PPMEM_SCATTER ppMEMs, _In_ DWORD cpMEMs) { DWORD i, cMEMs; PVMM_PROCESS pObProcess = NULL; - if(!ctxVmm) { return 0; } if(dwPID == (DWORD)-1) { - VmmWriteScatterPhysical(ppMEMs, cpMEMs); + VmmWriteScatterPhysical(H, ppMEMs, cpMEMs); } else { - pObProcess = VmmProcessGet(dwPID); + pObProcess = VmmProcessGet(H, dwPID); if(!pObProcess) { return 0; } - VmmWriteScatterVirtual(pObProcess, ppMEMs, cpMEMs); + VmmWriteScatterVirtual(H, pObProcess, ppMEMs, cpMEMs); Ob_DECREF(pObProcess); } for(i = 0, cMEMs = 0; i < cpMEMs; i++) { @@ -980,66 +697,67 @@ DWORD VMMDLL_MemWriteScatter_Impl(_In_ DWORD dwPID, _Inout_ PPMEM_SCATTER ppMEMs return cMEMs; } -DWORD VMMDLL_MemWriteScatter(_In_ DWORD dwPID, _Inout_ PPMEM_SCATTER ppMEMs, _In_ DWORD cpMEMs) +DWORD VMMDLL_MemWriteScatter(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _Inout_ PPMEM_SCATTER ppMEMs, _In_ DWORD cpMEMs) { CALL_IMPLEMENTATION_VMM_RETURN( + H, STATISTICS_ID_VMMDLL_MemWriteScatter, DWORD, 0, - VMMDLL_MemWriteScatter_Impl(dwPID, ppMEMs, cpMEMs)) + VMMDLL_MemWriteScatter_Impl(H, dwPID, ppMEMs, cpMEMs)) } _Success_(return) -BOOL VMMDLL_MemReadEx_Impl(_In_ DWORD dwPID, _In_ ULONG64 qwA, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ ULONG64 flags) +BOOL VMMDLL_MemReadEx_Impl(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ ULONG64 qwA, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ ULONG64 flags) { PVMM_PROCESS pObProcess = NULL; if(dwPID != (DWORD)-1) { - pObProcess = VmmProcessGet(dwPID); + pObProcess = VmmProcessGet(H, dwPID); if(!pObProcess) { return FALSE; } } - VmmReadEx(pObProcess, qwA, pb, cb, pcbReadOpt, flags); + VmmReadEx(H, pObProcess, qwA, pb, cb, pcbReadOpt, flags); Ob_DECREF(pObProcess); return TRUE; } _Success_(return) -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_MemReadEx(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ ULONG64 qwA, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ ULONG64 flags) { - CALL_IMPLEMENTATION_VMM( + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_MemReadEx, - VMMDLL_MemReadEx_Impl(dwPID, qwA, pb, cb, pcbReadOpt, flags)) + VMMDLL_MemReadEx_Impl(H, dwPID, qwA, pb, cb, pcbReadOpt, flags)) } _Success_(return) -BOOL VMMDLL_MemRead(_In_ DWORD dwPID, _In_ ULONG64 qwA, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb) +BOOL VMMDLL_MemRead(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ ULONG64 qwA, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb) { DWORD dwRead; - return VMMDLL_MemReadEx(dwPID, qwA, pb, cb, &dwRead, 0) && (dwRead == cb); + return VMMDLL_MemReadEx(H, dwPID, qwA, pb, cb, &dwRead, 0) && (dwRead == cb); } _Success_(return) -BOOL VMMDLL_MemReadPage(_In_ DWORD dwPID, _In_ ULONG64 qwA, _Inout_bytecount_(4096) PBYTE pbPage) +BOOL VMMDLL_MemReadPage(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ ULONG64 qwA, _Inout_bytecount_(4096) PBYTE pbPage) { DWORD dwRead; - return VMMDLL_MemReadEx(dwPID, qwA, pbPage, 4096, &dwRead, 0) && (dwRead == 4096); + return VMMDLL_MemReadEx(H, dwPID, qwA, pbPage, 4096, &dwRead, 0) && (dwRead == 4096); } _Success_(return) -BOOL VMMDLL_MemPrefetchPages_Impl(_In_ DWORD dwPID, _In_reads_(cPrefetchAddresses) PULONG64 pPrefetchAddresses, _In_ DWORD cPrefetchAddresses) +BOOL VMMDLL_MemPrefetchPages_Impl(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_reads_(cPrefetchAddresses) PULONG64 pPrefetchAddresses, _In_ DWORD cPrefetchAddresses) { DWORD i; BOOL result = FALSE; PVMM_PROCESS pObProcess = NULL; POB_SET pObSet_PrefetchAddresses = NULL; if(dwPID != (DWORD)-1) { - pObProcess = VmmProcessGet(dwPID); + pObProcess = VmmProcessGet(H, dwPID); if(!pObProcess) { goto fail; } } - if(!(pObSet_PrefetchAddresses = ObSet_New())) { goto fail; } + if(!(pObSet_PrefetchAddresses = ObSet_New(H))) { goto fail; } for(i = 0; i < cPrefetchAddresses; i++) { ObSet_Push(pObSet_PrefetchAddresses, pPrefetchAddresses[i] & ~0xfff); } - VmmCachePrefetchPages(pObProcess, pObSet_PrefetchAddresses, 0); + VmmCachePrefetchPages(H, pObProcess, pObSet_PrefetchAddresses, 0); result = TRUE; fail: Ob_DECREF(pObSet_PrefetchAddresses); @@ -1048,65 +766,65 @@ fail: } _Success_(return) -BOOL VMMDLL_MemPrefetchPages(_In_ DWORD dwPID, _In_reads_(cPrefetchAddresses) PULONG64 pPrefetchAddresses, _In_ DWORD cPrefetchAddresses) +BOOL VMMDLL_MemPrefetchPages(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_reads_(cPrefetchAddresses) PULONG64 pPrefetchAddresses, _In_ DWORD cPrefetchAddresses) { - CALL_IMPLEMENTATION_VMM( + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_MemPrefetchPages, - VMMDLL_MemPrefetchPages_Impl(dwPID, pPrefetchAddresses, cPrefetchAddresses)) + VMMDLL_MemPrefetchPages_Impl(H, dwPID, pPrefetchAddresses, cPrefetchAddresses)) } _Success_(return) -BOOL VMMDLL_MemWrite_Impl(_In_ DWORD dwPID, _In_ ULONG64 qwA, _In_reads_(cb) PBYTE pb, _In_ DWORD cb) +BOOL VMMDLL_MemWrite_Impl(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ ULONG64 qwA, _In_reads_(cb) PBYTE pb, _In_ DWORD cb) { BOOL result; PVMM_PROCESS pObProcess = NULL; if(dwPID != (DWORD)-1) { - pObProcess = VmmProcessGet(dwPID); + pObProcess = VmmProcessGet(H, dwPID); if(!pObProcess) { return FALSE; } } - result = VmmWrite(pObProcess, qwA, pb, cb); + result = VmmWrite(H, pObProcess, qwA, pb, cb); Ob_DECREF(pObProcess); return result; } _Success_(return) -BOOL VMMDLL_MemWrite(_In_ DWORD dwPID, _In_ ULONG64 qwA, _In_reads_(cb) PBYTE pb, _In_ DWORD cb) +BOOL VMMDLL_MemWrite(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ ULONG64 qwA, _In_reads_(cb) PBYTE pb, _In_ DWORD cb) { - CALL_IMPLEMENTATION_VMM( + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_MemWrite, - VMMDLL_MemWrite_Impl(dwPID, qwA, pb, cb)) + VMMDLL_MemWrite_Impl(H, dwPID, qwA, pb, cb)) } _Success_(return) -BOOL VMMDLL_MemVirt2Phys_Impl(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PULONG64 pqwPA) +BOOL VMMDLL_MemVirt2Phys_Impl(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PULONG64 pqwPA) { BOOL result; - PVMM_PROCESS pObProcess = VmmProcessGet(dwPID); + PVMM_PROCESS pObProcess = VmmProcessGet(H, dwPID); if(!pObProcess) { return FALSE; } - result = VmmVirt2Phys(pObProcess, qwVA, pqwPA); + result = VmmVirt2Phys(H, pObProcess, qwVA, pqwPA); Ob_DECREF(pObProcess); return result; } _Success_(return) -BOOL VMMDLL_MemVirt2Phys(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PULONG64 pqwPA) +BOOL VMMDLL_MemVirt2Phys(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PULONG64 pqwPA) { - CALL_IMPLEMENTATION_VMM( + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_MemVirt2Phys, - VMMDLL_MemVirt2Phys_Impl(dwPID, qwVA, pqwPA)) + VMMDLL_MemVirt2Phys_Impl(H, dwPID, qwVA, pqwPA)) } _Success_(return) -BOOL VMMDLL_MemSearch_Impl(_In_ DWORD dwPID, _Inout_ PVMMDLL_MEM_SEARCH_CONTEXT ctx, _Out_opt_ PQWORD *ppva, _Out_opt_ PDWORD pcva) +BOOL VMMDLL_MemSearch_Impl(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _Inout_ PVMMDLL_MEM_SEARCH_CONTEXT ctx, _Out_opt_ PQWORD *ppva, _Out_opt_ PDWORD pcva) { BOOL fResult = FALSE; POB_DATA pObData = NULL; PVMM_PROCESS pObProcess = NULL; - if(!(pObProcess = VmmProcessGet(dwPID))) { goto fail; } - if(!VmmSearch(pObProcess, (PVMM_MEMORY_SEARCH_CONTEXT)ctx, &pObData)) { goto fail; } + if(!(pObProcess = VmmProcessGet(H, dwPID))) { goto fail; } + if(!VmmSearch(H, pObProcess, (PVMM_MEMORY_SEARCH_CONTEXT)ctx, &pObData)) { goto fail; } if(pObData) { if(ppva) { - if(!(*ppva = LocalAlloc(0, pObData->ObHdr.cbData))) { goto fail; } + if(!(*ppva = VmmDllCore_MemAllocExternal(H, OB_TAG_API_SEARCH, pObData->ObHdr.cbData, 0))) { goto fail; } // VMMDLL_MemFree() memcpy(*ppva, pObData->pqw, pObData->ObHdr.cbData); } if(pcva) { @@ -1121,23 +839,61 @@ fail: } _Success_(return) -BOOL VMMDLL_MemSearch(_In_ DWORD dwPID, _Inout_ PVMMDLL_MEM_SEARCH_CONTEXT ctx, _Out_opt_ PQWORD *ppva, _Out_opt_ PDWORD pcva) +BOOL VMMDLL_MemSearch(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _Inout_ PVMMDLL_MEM_SEARCH_CONTEXT ctx, _Out_opt_ PQWORD *ppva, _Out_opt_ PDWORD pcva) { if(pcva) { *pcva = 0; } if(ppva) { *ppva = NULL; } if(ctx->dwVersion != VMMDLL_MEM_SEARCH_VERSION) { return FALSE; } if(sizeof(VMMDLL_MEM_SEARCH_CONTEXT) != sizeof(VMM_MEMORY_SEARCH_CONTEXT)) { return FALSE; } - CALL_IMPLEMENTATION_VMM( + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_MemSearch, - VMMDLL_MemSearch_Impl(dwPID, ctx, ppva, pcva)) + VMMDLL_MemSearch_Impl(H, dwPID, ctx, ppva, pcva)) } + + +//----------------------------------------------------------------------------- +// FORENSIC-MODE SPECIFIC FUNCTIONALITY BELOW: +//----------------------------------------------------------------------------- + +_Success_(return != 0) +SIZE_T VMMDLL_ForensicFileAppend_DoWork(_In_ VMM_HANDLE H, _In_ LPSTR uszFileName, _In_z_ _Printf_format_string_ LPSTR uszFormat, _In_ va_list arglist) +{ + CALL_IMPLEMENTATION_VMM_RETURN(H, STATISTICS_ID_VMMDLL_ForensicFileAppend, SIZE_T, 0, FcFileAppendEx(H, uszFileName, uszFormat, arglist)) +} + +/* +* Append text data to a memory-backed forensics file. +* All text should be UTF-8 encoded. +* -- H +* -- uszFileName +* -- uszFormat +* -- .. +* -- return = number of bytes appended (excluding terminating null). +*/ +EXPORTED_FUNCTION _Success_(return != 0) +SIZE_T VMMDLL_ForensicFileAppend( + _In_ VMM_HANDLE H, + _In_ LPSTR uszFileName, + _In_z_ _Printf_format_string_ LPSTR uszFormat, + ... +) { + SIZE_T ret; + va_list arglist; + va_start(arglist, uszFormat); + ret = VMMDLL_ForensicFileAppend_DoWork(H, uszFileName, uszFormat, arglist); + va_end(arglist); + return ret; +} + + + //----------------------------------------------------------------------------- // VMM PROCESS FUNCTIONALITY BELOW: //----------------------------------------------------------------------------- _Success_(return) -BOOL VMMDLL_Map_GetPte_Impl(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbMapDst) PVMMDLL_MAP_PTE pMapDst, _Inout_ PDWORD pcbMapDst, _In_ BOOL fIdentifyModules, _In_ BOOL fWideChar) +BOOL VMMDLL_Map_GetPte_Impl(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ BOOL fIdentifyModules, _Out_ PVMMDLL_MAP_PTE *ppMapDst, _In_ BOOL fWideChar) { BOOL f, fResult = FALSE; PVMM_PROCESS pObProcess = NULL; @@ -1145,59 +901,58 @@ BOOL VMMDLL_Map_GetPte_Impl(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbMapDst) PVMMDLL_MAP_PTEENTRY peDst; PVMM_MAP_PTEENTRY peSrc; PVMMOB_MAP_PTE pObMapSrc = NULL; + PVMMDLL_MAP_PTE pMapDst = NULL; POB_STRMAP psmOb = NULL; + *ppMapDst = NULL; // 0: sanity check: if(sizeof(VMM_MAP_PTEENTRY) != sizeof(VMMDLL_MAP_PTEENTRY)) { goto fail; } // 1: fetch map [and populate strings]: - if(!(psmOb = ObStrMap_New(0))) { goto fail; } - if(!(pObProcess = VmmProcessGet(dwPID))) { goto fail; } - if(!VmmMap_GetPte(pObProcess, &pObMapSrc, fIdentifyModules)) { goto fail; } + if(!(psmOb = ObStrMap_New(H, 0))) { goto fail; } + if(!(pObProcess = VmmProcessGet(H, dwPID))) { goto fail; } + if(!VmmMap_GetPte(H, pObProcess, &pObMapSrc, fIdentifyModules)) { goto fail; } for(i = 0; i < pObMapSrc->cMap; i++) { peSrc = pObMapSrc->pMap + i; ObStrMap_PushU(psmOb, peSrc->uszText); } - // 2: byte count: + // 2: byte count & alloc: if(!ObStrMap_FinalizeBufferXUW(psmOb, 0, NULL, &cbDstStr, fWideChar)) { goto fail; } cbDstData = pObMapSrc->cMap * sizeof(VMMDLL_MAP_PTEENTRY); cbDst = sizeof(VMMDLL_MAP_PTE) + cbDstData + cbDstStr; - // 3: fill map [if required]: - if(pMapDst) { - if(*pcbMapDst < cbDst) { goto fail; } - ZeroMemory(pMapDst, sizeof(VMMDLL_MAP_PTE)); - pMapDst->dwVersion = VMMDLL_MAP_PTE_VERSION; - pMapDst->cMap = pObMapSrc->cMap; - memcpy(pMapDst->pMap, pObMapSrc->pMap, cbDstData); - // strmap below: - for(i = 0; i < pMapDst->cMap; i++) { - peSrc = pObMapSrc->pMap + i; - peDst = pMapDst->pMap + i; - f = ObStrMap_PushPtrUXUW(psmOb, peSrc->uszText, &peDst->uszText, NULL, fWideChar); - if(!f) { goto fail; } - } - pMapDst->pbMultiText = ((PBYTE)pMapDst->pMap) + cbDstData; - ObStrMap_FinalizeBufferXUW(psmOb, cbDstStr, pMapDst->pbMultiText, &pMapDst->cbMultiText, fWideChar); + if(!(pMapDst = VmmDllCore_MemAllocExternal(H, OB_TAG_API_MAP_PTE, cbDst, sizeof(VMMDLL_MAP_PTE)))) { goto fail; } // VMMDLL_MemFree() + // 3: fill map: + pMapDst->dwVersion = VMMDLL_MAP_PTE_VERSION; + pMapDst->cMap = pObMapSrc->cMap; + memcpy(pMapDst->pMap, pObMapSrc->pMap, cbDstData); + // strmap below: + for(i = 0; i < pMapDst->cMap; i++) { + peSrc = pObMapSrc->pMap + i; + peDst = pMapDst->pMap + i; + f = ObStrMap_PushPtrUXUW(psmOb, peSrc->uszText, &peDst->uszText, NULL, fWideChar); + if(!f) { goto fail; } } - fResult = TRUE; + pMapDst->pbMultiText = ((PBYTE)pMapDst->pMap) + cbDstData; + ObStrMap_FinalizeBufferXUW(psmOb, cbDstStr, pMapDst->pbMultiText, &pMapDst->cbMultiText, fWideChar); + *ppMapDst = pMapDst; fail: - *pcbMapDst = (DWORD)cbDst; + if(pMapDst && !*ppMapDst) { VMMDLL_MemFree(pMapDst); pMapDst = NULL; } Ob_DECREF(pObProcess); Ob_DECREF(pObMapSrc); Ob_DECREF(psmOb); - return fResult; + return *ppMapDst ? TRUE : FALSE; } -_Success_(return) BOOL VMMDLL_Map_GetPteU(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbPteMap) PVMMDLL_MAP_PTE pPteMap, _Inout_ PDWORD pcbPteMap, _In_ BOOL fIdentifyModules) +_Success_(return) BOOL VMMDLL_Map_GetPteU(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ BOOL fIdentifyModules, _Out_ PVMMDLL_MAP_PTE *ppPteMap) { - CALL_IMPLEMENTATION_VMM(STATISTICS_ID_VMMDLL_Map_GetPte, VMMDLL_Map_GetPte_Impl(dwPID, pPteMap, pcbPteMap, fIdentifyModules, FALSE)) + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_Map_GetPte, VMMDLL_Map_GetPte_Impl(H, dwPID, fIdentifyModules, ppPteMap, FALSE)) } -_Success_(return) BOOL VMMDLL_Map_GetPteW(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbPteMap) PVMMDLL_MAP_PTE pPteMap, _Inout_ PDWORD pcbPteMap, _In_ BOOL fIdentifyModules) +_Success_(return) BOOL VMMDLL_Map_GetPteW(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ BOOL fIdentifyModules, _Out_ PVMMDLL_MAP_PTE *ppPteMap) { - CALL_IMPLEMENTATION_VMM(STATISTICS_ID_VMMDLL_Map_GetPte, VMMDLL_Map_GetPte_Impl(dwPID, pPteMap, pcbPteMap, fIdentifyModules, TRUE)) + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_Map_GetPte, VMMDLL_Map_GetPte_Impl(H, dwPID, fIdentifyModules, ppPteMap, TRUE)) } _Success_(return) -BOOL VMMDLL_Map_GetVad_Impl(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbMapDst) PVMMDLL_MAP_VAD pMapDst, _Inout_ PDWORD pcbMapDst, _In_ BOOL fIdentifyModules, _In_ BOOL fWideChar) +BOOL VMMDLL_Map_GetVad_Impl(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ BOOL fIdentifyModules, _Out_ PVMMDLL_MAP_VAD *ppMapDst, _In_ BOOL fWideChar) { BOOL f, fResult = FALSE; PVMM_PROCESS pObProcess = NULL; @@ -1205,99 +960,95 @@ BOOL VMMDLL_Map_GetVad_Impl(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbMapDst) PVMMDLL_MAP_VADENTRY peDst; PVMM_MAP_VADENTRY peSrc; PVMMOB_MAP_VAD pObMapSrc = NULL; + PVMMDLL_MAP_VAD pMapDst = NULL; POB_STRMAP psmOb = NULL; + *ppMapDst = NULL; // 0: sanity check: if(sizeof(VMM_MAP_VADENTRY) != sizeof(VMMDLL_MAP_VADENTRY)) { goto fail; } // 1: fetch map [and populate strings]: - if(!(psmOb = ObStrMap_New(0))) { goto fail; } - if(!(pObProcess = VmmProcessGet(dwPID))) { goto fail; } - if(!VmmMap_GetVad(pObProcess, &pObMapSrc, (fIdentifyModules ? VMM_VADMAP_TP_FULL : VMM_VADMAP_TP_PARTIAL))) { goto fail; } + if(!(psmOb = ObStrMap_New(H, 0))) { goto fail; } + if(!(pObProcess = VmmProcessGet(H, dwPID))) { goto fail; } + if(!VmmMap_GetVad(H, pObProcess, &pObMapSrc, (fIdentifyModules ? VMM_VADMAP_TP_FULL : VMM_VADMAP_TP_PARTIAL))) { goto fail; } for(i = 0; i < pObMapSrc->cMap; i++) { peSrc = pObMapSrc->pMap + i; ObStrMap_PushU(psmOb, peSrc->uszText); } - // 2: byte count: + // 2: byte count & alloc: if(!ObStrMap_FinalizeBufferXUW(psmOb, 0, NULL, &cbDstStr, fWideChar)) { goto fail; } cbDstData = pObMapSrc->cMap * sizeof(VMMDLL_MAP_VADENTRY); cbDst = sizeof(VMMDLL_MAP_VAD) + cbDstData + cbDstStr; - // 3: fill map [if required]: - if(pMapDst) { - if(*pcbMapDst < cbDst) { goto fail; } - ZeroMemory(pMapDst, sizeof(VMMDLL_MAP_VAD)); - pMapDst->dwVersion = VMMDLL_MAP_VAD_VERSION; - pMapDst->cPage = pObMapSrc->cPage; - pMapDst->cMap = pObMapSrc->cMap; - memcpy(pMapDst->pMap, pObMapSrc->pMap, cbDstData); - // strmap below: - for(i = 0; i < pMapDst->cMap; i++) { - peSrc = pObMapSrc->pMap + i; - peDst = pMapDst->pMap + i; - f = ObStrMap_PushPtrUXUW(psmOb, peSrc->uszText, &peDst->uszText, NULL, fWideChar); - if(!f) { goto fail; } - } - pMapDst->pbMultiText = ((PBYTE)pMapDst->pMap) + cbDstData; - ObStrMap_FinalizeBufferXUW(psmOb, cbDstStr, pMapDst->pbMultiText, &pMapDst->cbMultiText, fWideChar); + if(!(pMapDst = VmmDllCore_MemAllocExternal(H, OB_TAG_API_MAP_VAD, cbDst, sizeof(VMMDLL_MAP_VAD)))) { goto fail; } // VMMDLL_MemFree() + // 3: fill map: + pMapDst->dwVersion = VMMDLL_MAP_VAD_VERSION; + pMapDst->cPage = pObMapSrc->cPage; + pMapDst->cMap = pObMapSrc->cMap; + memcpy(pMapDst->pMap, pObMapSrc->pMap, cbDstData); + // strmap below: + for(i = 0; i < pMapDst->cMap; i++) { + peSrc = pObMapSrc->pMap + i; + peDst = pMapDst->pMap + i; + f = ObStrMap_PushPtrUXUW(psmOb, peSrc->uszText, &peDst->uszText, NULL, fWideChar); + if(!f) { goto fail; } } - fResult = TRUE; + pMapDst->pbMultiText = ((PBYTE)pMapDst->pMap) + cbDstData; + ObStrMap_FinalizeBufferXUW(psmOb, cbDstStr, pMapDst->pbMultiText, &pMapDst->cbMultiText, fWideChar); + *ppMapDst = pMapDst; fail: - *pcbMapDst = cbDst; + if(pMapDst && !*ppMapDst) { VMMDLL_MemFree(pMapDst); pMapDst = NULL; } Ob_DECREF(pObProcess); Ob_DECREF(pObMapSrc); Ob_DECREF(psmOb); - return fResult; + return *ppMapDst ? TRUE : FALSE; } -_Success_(return) BOOL VMMDLL_Map_GetVadU(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbVadMap) PVMMDLL_MAP_VAD pVadMap, _Inout_ PDWORD pcbVadMap, _In_ BOOL fIdentifyModules) +_Success_(return) BOOL VMMDLL_Map_GetVadU(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ BOOL fIdentifyModules, _Out_ PVMMDLL_MAP_VAD *ppVadMap) { - CALL_IMPLEMENTATION_VMM(STATISTICS_ID_VMMDLL_Map_GetVad, VMMDLL_Map_GetVad_Impl(dwPID, pVadMap, pcbVadMap, fIdentifyModules, FALSE)) + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_Map_GetVad, VMMDLL_Map_GetVad_Impl(H, dwPID, fIdentifyModules, ppVadMap, FALSE)) } -_Success_(return) BOOL VMMDLL_Map_GetVadW(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbVadMap) PVMMDLL_MAP_VAD pVadMap, _Inout_ PDWORD pcbVadMap, _In_ BOOL fIdentifyModules) +_Success_(return) BOOL VMMDLL_Map_GetVadW(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ BOOL fIdentifyModules, _Out_ PVMMDLL_MAP_VAD *ppVadMap) { - CALL_IMPLEMENTATION_VMM(STATISTICS_ID_VMMDLL_Map_GetVad, VMMDLL_Map_GetVad_Impl(dwPID, pVadMap, pcbVadMap, fIdentifyModules, TRUE)) + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_Map_GetVad, VMMDLL_Map_GetVad_Impl(H, dwPID, fIdentifyModules, ppVadMap, TRUE)) } _Success_(return) -BOOL VMMDLL_Map_GetVadEx_Impl(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbVadExMap) PVMMDLL_MAP_VADEX pVadExMap, _Inout_ PDWORD pcbVadExMap, _In_ DWORD oPage, _In_ DWORD cPage) +BOOL VMMDLL_Map_GetVadEx_Impl(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ DWORD oPage, _In_ DWORD cPage, _Out_ PVMMDLL_MAP_VADEX *ppMapDst) { BOOL fResult = FALSE; - DWORD i, cbData = 0, cbDataMap; + DWORD i, cbDst = 0, cbDstData; PVMMOB_MAP_VADEX pObMap = NULL; PVMM_PROCESS pObProcess = NULL; - if(!pVadExMap) { - *pcbVadExMap = sizeof(VMMDLL_MAP_VADEX) + cPage * sizeof(VMMDLL_MAP_VADEXENTRY); - return TRUE; - } - if(!(pObProcess = VmmProcessGet(dwPID))) { goto fail; } - if(!VmmMap_GetVadEx(pObProcess, &pObMap, VMM_VADMAP_TP_FULL, oPage, cPage)) { goto fail; } - cbDataMap = pObMap->cMap * sizeof(VMMDLL_MAP_VADEXENTRY); - cbData = sizeof(VMMDLL_MAP_VADEX) + cbDataMap; - if(*pcbVadExMap < cbData) { goto fail; } - ZeroMemory(pVadExMap, sizeof(VMMDLL_MAP_VADEX)); - pVadExMap->dwVersion = VMMDLL_MAP_VADEX_VERSION; - pVadExMap->cMap = pObMap->cMap; - memcpy(pVadExMap->pMap, pObMap->pMap, cbDataMap); + PVMMDLL_MAP_VADEX pMapDst = NULL; + *ppMapDst = NULL; + if(!(pObProcess = VmmProcessGet(H, dwPID))) { goto fail; } + if(!VmmMap_GetVadEx(H, pObProcess, &pObMap, VMM_VADMAP_TP_FULL, oPage, cPage)) { goto fail; } + cbDstData = pObMap->cMap * sizeof(VMMDLL_MAP_VADEXENTRY); + cbDst = sizeof(VMMDLL_MAP_VADEX) + cbDstData; + if(!(pMapDst = VmmDllCore_MemAllocExternal(H, OB_TAG_API_MAP_VAD_EX, cbDst, sizeof(VMMDLL_MAP_VADEX)))) { goto fail; } // VMMDLL_MemFree() + pMapDst->dwVersion = VMMDLL_MAP_VADEX_VERSION; + pMapDst->cMap = pObMap->cMap; + memcpy(pMapDst->pMap, pObMap->pMap, cbDstData); for(i = 0; i < pObMap->cMap; i++) { - pVadExMap->pMap[i].vaVadBase = pObMap->pMap[i].peVad->vaStart; + pMapDst->pMap[i].vaVadBase = pObMap->pMap[i].peVad->vaStart; } - fResult = TRUE; + *ppMapDst = pMapDst; fail: - *pcbVadExMap = cbData; + if(pMapDst && !*ppMapDst) { VMMDLL_MemFree(pMapDst); pMapDst = NULL; } Ob_DECREF(pObProcess); Ob_DECREF(pObMap); - return fResult; + return *ppMapDst ? TRUE : FALSE; } _Success_(return) -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_GetVadEx(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ DWORD oPage, _In_ DWORD cPage, _Out_ PVMMDLL_MAP_VADEX *ppVadExMap) { - CALL_IMPLEMENTATION_VMM( + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_Map_GetVadEx, - VMMDLL_Map_GetVadEx_Impl(dwPID, pVadExMap, pcbVadExMap, oPage, cPage)) + VMMDLL_Map_GetVadEx_Impl(H, dwPID, oPage, cPage, ppVadExMap)) } _Success_(return) -BOOL VMMDLL_Map_GetModule_Impl(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbMapDst) PVMMDLL_MAP_MODULE pMapDst, _Inout_ PDWORD pcbMapDst, _In_ BOOL fWideChar) +BOOL VMMDLL_Map_GetModule_Impl(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_MODULE *ppMapDst, _In_ BOOL fWideChar) { BOOL f, fResult = FALSE; PVMM_PROCESS pObProcess = NULL; @@ -1305,61 +1056,60 @@ BOOL VMMDLL_Map_GetModule_Impl(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbMapD PVMMDLL_MAP_MODULEENTRY peDst; PVMM_MAP_MODULEENTRY peSrc; PVMMOB_MAP_MODULE pObMapSrc = NULL; + PVMMDLL_MAP_MODULE pMapDst = NULL; POB_STRMAP psmOb = NULL; + *ppMapDst = NULL; // 0: sanity check: if(sizeof(VMM_MAP_MODULEENTRY) != sizeof(VMMDLL_MAP_MODULEENTRY)) { goto fail; } // 1: fetch map [and populate strings]: - if(!(psmOb = ObStrMap_New(0))) { goto fail; } - if(!(pObProcess = VmmProcessGet(dwPID))) { goto fail; } - if(!VmmMap_GetModule(pObProcess, &pObMapSrc)) { goto fail; } + if(!(psmOb = ObStrMap_New(H, 0))) { goto fail; } + if(!(pObProcess = VmmProcessGet(H, dwPID))) { goto fail; } + if(!VmmMap_GetModule(H, pObProcess, &pObMapSrc)) { goto fail; } for(i = 0; i < pObMapSrc->cMap; i++) { peSrc = pObMapSrc->pMap + i; ObStrMap_PushU(psmOb, peSrc->uszText); ObStrMap_PushU(psmOb, peSrc->uszFullName); } - // 2: byte count: + // 2: byte count & alloc: if(!ObStrMap_FinalizeBufferXUW(psmOb, 0, NULL, &cbDstStr, fWideChar)) { goto fail; } cbDstData = pObMapSrc->cMap * sizeof(VMMDLL_MAP_MODULEENTRY); cbDst = sizeof(VMMDLL_MAP_MODULE) + cbDstData + cbDstStr; - // 3: fill map [if required]: - if(pMapDst) { - if(*pcbMapDst < cbDst) { goto fail; } - ZeroMemory(pMapDst, sizeof(VMMDLL_MAP_MODULE)); - pMapDst->dwVersion = VMMDLL_MAP_MODULE_VERSION; - pMapDst->cMap = pObMapSrc->cMap; - memcpy(pMapDst->pMap, pObMapSrc->pMap, cbDstData); - // strmap below: - for(i = 0; i < pMapDst->cMap; i++) { - peSrc = pObMapSrc->pMap + i; - peDst = pMapDst->pMap + i; - f = ObStrMap_PushPtrUXUW(psmOb, peSrc->uszText, &peDst->uszText, NULL, fWideChar) && - ObStrMap_PushPtrUXUW(psmOb, peSrc->uszFullName, &peDst->uszFullName, NULL, fWideChar); - if(!f) { goto fail; } - } - pMapDst->pbMultiText = ((PBYTE)pMapDst->pMap) + cbDstData; - ObStrMap_FinalizeBufferXUW(psmOb, cbDstStr, pMapDst->pbMultiText, &pMapDst->cbMultiText, fWideChar); + if(!(pMapDst = VmmDllCore_MemAllocExternal(H, OB_TAG_API_MAP_MODULE, cbDst, sizeof(VMMDLL_MAP_MODULE)))) { goto fail; } // VMMDLL_MemFree() + // 3: fill map: + pMapDst->dwVersion = VMMDLL_MAP_MODULE_VERSION; + pMapDst->cMap = pObMapSrc->cMap; + memcpy(pMapDst->pMap, pObMapSrc->pMap, cbDstData); + // strmap below: + for(i = 0; i < pMapDst->cMap; i++) { + peSrc = pObMapSrc->pMap + i; + peDst = pMapDst->pMap + i; + f = ObStrMap_PushPtrUXUW(psmOb, peSrc->uszText, &peDst->uszText, NULL, fWideChar) && + ObStrMap_PushPtrUXUW(psmOb, peSrc->uszFullName, &peDst->uszFullName, NULL, fWideChar); + if(!f) { goto fail; } } - fResult = TRUE; + pMapDst->pbMultiText = ((PBYTE)pMapDst->pMap) + cbDstData; + ObStrMap_FinalizeBufferXUW(psmOb, cbDstStr, pMapDst->pbMultiText, &pMapDst->cbMultiText, fWideChar); + *ppMapDst = pMapDst; fail: - *pcbMapDst = cbDst; + if(pMapDst && !*ppMapDst) { VMMDLL_MemFree(pMapDst); pMapDst = NULL; } Ob_DECREF(pObProcess); Ob_DECREF(pObMapSrc); Ob_DECREF(psmOb); - return fResult; + return *ppMapDst ? TRUE : FALSE; } -_Success_(return) BOOL VMMDLL_Map_GetModuleU(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbModuleMap) PVMMDLL_MAP_MODULE pModuleMap, _Inout_ PDWORD pcbModuleMap) +_Success_(return) BOOL VMMDLL_Map_GetModuleU(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_MODULE *ppModuleMap) { - CALL_IMPLEMENTATION_VMM(STATISTICS_ID_VMMDLL_Map_GetModule, VMMDLL_Map_GetModule_Impl(dwPID, pModuleMap, pcbModuleMap, FALSE)) + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_Map_GetModule, VMMDLL_Map_GetModule_Impl(H, dwPID, ppModuleMap, FALSE)) } -_Success_(return) BOOL VMMDLL_Map_GetModuleW(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbModuleMap) PVMMDLL_MAP_MODULE pModuleMap, _Inout_ PDWORD pcbModuleMap) +_Success_(return) BOOL VMMDLL_Map_GetModuleW(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_MODULE *ppModuleMap) { - CALL_IMPLEMENTATION_VMM(STATISTICS_ID_VMMDLL_Map_GetModule, VMMDLL_Map_GetModule_Impl(dwPID, pModuleMap, pcbModuleMap, TRUE)) + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_Map_GetModule, VMMDLL_Map_GetModule_Impl(H, dwPID, ppModuleMap, TRUE)) } _Success_(return) -BOOL VMMDLL_Map_GetModuleFromName_Impl(_In_ DWORD dwPID, _In_opt_ LPSTR uszModuleName, _Out_writes_bytes_opt_(*pcbDst) PVMMDLL_MAP_MODULEENTRY peDst, _Inout_opt_ PDWORD pcbDst, _In_ BOOL fWideChar) +BOOL VMMDLL_Map_GetModuleFromName_Impl(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_opt_ LPSTR uszModuleName, _Out_ PVMMDLL_MAP_MODULEENTRY *ppeDst, _In_ BOOL fWideChar) { BOOL f, fResult = FALSE; DWORD o = 0, cbDst = 0, cbDstStr, cbTMP; @@ -1367,57 +1117,51 @@ BOOL VMMDLL_Map_GetModuleFromName_Impl(_In_ DWORD dwPID, _In_opt_ LPSTR uszModul PVMM_MAP_MODULEENTRY peSrc = NULL; POB_STRMAP psmOb = NULL; PBYTE pbMultiText; + PVMMDLL_MAP_MODULEENTRY peDst = NULL; + *ppeDst = NULL; // 0: sanity check: - if(!peDst && !pcbDst) { goto fail; } if(sizeof(VMM_MAP_MODULEENTRY) != sizeof(VMMDLL_MAP_MODULEENTRY)) { goto fail; } - if(!VmmMap_GetModuleEntryEx(NULL, dwPID, uszModuleName, &pObMapSrc, &peSrc)) { goto fail; } - if(!pcbDst) { // case of no name module data request. - memcpy(peDst, peSrc, sizeof(VMMDLL_MAP_MODULEENTRY)); - peDst->wszText = NULL; - peDst->wszFullName = NULL; - return TRUE; - } + if(!VmmMap_GetModuleEntryEx(H, NULL, dwPID, uszModuleName, &pObMapSrc, &peSrc)) { goto fail; } // 1: fetch map [and populate strings]: - if(!(psmOb = ObStrMap_New(0))) { goto fail; } + if(!(psmOb = ObStrMap_New(H, 0))) { goto fail; } ObStrMap_PushU(psmOb, peSrc->uszText); ObStrMap_PushU(psmOb, peSrc->uszFullName); - // 2: byte count: + // 2: byte count & alloc: if(!ObStrMap_FinalizeBufferXUW(psmOb, 0, NULL, &cbDstStr, fWideChar)) { goto fail; } cbDst = sizeof(VMMDLL_MAP_MODULEENTRY) + cbDstStr; - if(peDst) { - if(*pcbDst < cbDst) { goto fail; } - memcpy(peDst, peSrc, sizeof(VMMDLL_MAP_MODULEENTRY)); - // strmap below: - f = ObStrMap_PushPtrUXUW(psmOb, peSrc->uszText, &peDst->uszText, NULL, fWideChar) && - ObStrMap_PushPtrUXUW(psmOb, peSrc->uszFullName, &peDst->uszFullName, NULL, fWideChar); - if(!f) { goto fail; } - pbMultiText = ((PBYTE)peDst) + sizeof(VMMDLL_MAP_MODULEENTRY); - ObStrMap_FinalizeBufferXUW(psmOb, cbDstStr, pbMultiText, &cbTMP, fWideChar); - } - fResult = TRUE; + if(!(peDst = VmmDllCore_MemAllocExternal(H, OB_TAG_API_MODULE_FROM_NAME, cbDst, sizeof(VMMDLL_MAP_MODULEENTRY)))) { goto fail; } // VMMDLL_MemFree() + // 3: fill entry: + memcpy(peDst, peSrc, sizeof(VMMDLL_MAP_MODULEENTRY)); + // strmap below: + f = ObStrMap_PushPtrUXUW(psmOb, peSrc->uszText, &peDst->uszText, NULL, fWideChar) && + ObStrMap_PushPtrUXUW(psmOb, peSrc->uszFullName, &peDst->uszFullName, NULL, fWideChar); + if(!f) { goto fail; } + pbMultiText = ((PBYTE)peDst) + sizeof(VMMDLL_MAP_MODULEENTRY); + ObStrMap_FinalizeBufferXUW(psmOb, cbDstStr, pbMultiText, &cbTMP, fWideChar); + *ppeDst = peDst; fail: - if(pcbDst) { *pcbDst = cbDst; } + if(ppeDst && !*ppeDst) { VMMDLL_MemFree(peDst); peDst = NULL; } Ob_DECREF(pObMapSrc); - return fResult; + return *ppeDst ? TRUE : FALSE; } -_Success_(return) BOOL VMMDLL_Map_GetModuleFromNameU(_In_ DWORD dwPID, _In_opt_ LPSTR uszModuleName, _Out_writes_bytes_opt_(*pcbModuleMapEntry) PVMMDLL_MAP_MODULEENTRY pModuleMapEntry, _Inout_opt_ PDWORD pcbModuleMapEntry) +_Success_(return) BOOL VMMDLL_Map_GetModuleFromNameU(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_opt_ LPSTR uszModuleName, _Out_ PVMMDLL_MAP_MODULEENTRY *ppModuleMapEntry) { - CALL_IMPLEMENTATION_VMM(STATISTICS_ID_VMMDLL_Map_GetModuleFromName, VMMDLL_Map_GetModuleFromName_Impl(dwPID, uszModuleName, pModuleMapEntry, pcbModuleMapEntry, FALSE)) + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_Map_GetModuleFromName, VMMDLL_Map_GetModuleFromName_Impl(H, dwPID, uszModuleName, ppModuleMapEntry, FALSE)) } -_Success_(return) BOOL VMMDLL_Map_GetModuleFromNameW(_In_ DWORD dwPID, _In_opt_ LPWSTR wszModuleName, _Out_writes_bytes_opt_(*pcbModuleMapEntry) PVMMDLL_MAP_MODULEENTRY pModuleMapEntry, _Inout_opt_ PDWORD pcbModuleMapEntry) +_Success_(return) BOOL VMMDLL_Map_GetModuleFromNameW(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_opt_ LPWSTR wszModuleName, _Out_ PVMMDLL_MAP_MODULEENTRY *ppModuleMapEntry) { LPSTR uszModuleName = NULL; BYTE pbBuffer[MAX_PATH]; if(wszModuleName) { if(!CharUtil_WtoU(wszModuleName, -1, pbBuffer, sizeof(pbBuffer), &uszModuleName, NULL, 0)) { return FALSE; } } - CALL_IMPLEMENTATION_VMM(STATISTICS_ID_VMMDLL_Map_GetModuleFromName, VMMDLL_Map_GetModuleFromName_Impl(dwPID, uszModuleName, pModuleMapEntry, pcbModuleMapEntry, TRUE)) + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_Map_GetModuleFromName, VMMDLL_Map_GetModuleFromName_Impl(H, dwPID, uszModuleName, ppModuleMapEntry, TRUE)) } _Success_(return) -BOOL VMMDLL_Map_GetUnloadedModule_Impl(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbMapDst) PVMMDLL_MAP_UNLOADEDMODULE pMapDst, _Inout_ PDWORD pcbMapDst, _In_ BOOL fWideChar) +BOOL VMMDLL_Map_GetUnloadedModule_Impl(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_UNLOADEDMODULE *ppMapDst, _In_ BOOL fWideChar) { BOOL f, fResult = FALSE; PVMM_PROCESS pObProcess = NULL; @@ -1425,59 +1169,58 @@ BOOL VMMDLL_Map_GetUnloadedModule_Impl(_In_ DWORD dwPID, _Out_writes_bytes_opt_( PVMMDLL_MAP_UNLOADEDMODULEENTRY peDst; PVMM_MAP_UNLOADEDMODULEENTRY peSrc; PVMMOB_MAP_UNLOADEDMODULE pObMapSrc = NULL; + PVMMDLL_MAP_UNLOADEDMODULE pMapDst = NULL; POB_STRMAP psmOb = NULL; + *ppMapDst = NULL; // 0: sanity check: if(sizeof(VMM_MAP_UNLOADEDMODULEENTRY) != sizeof(VMMDLL_MAP_UNLOADEDMODULEENTRY)) { goto fail; } // 1: fetch map [and populate strings]: - if(!(psmOb = ObStrMap_New(0))) { goto fail; } - if(!(pObProcess = VmmProcessGet(dwPID))) { goto fail; } - if(!VmmMap_GetUnloadedModule(pObProcess, &pObMapSrc)) { goto fail; } + if(!(psmOb = ObStrMap_New(H, 0))) { goto fail; } + if(!(pObProcess = VmmProcessGet(H, dwPID))) { goto fail; } + if(!VmmMap_GetUnloadedModule(H, pObProcess, &pObMapSrc)) { goto fail; } for(i = 0; i < pObMapSrc->cMap; i++) { peSrc = pObMapSrc->pMap + i; ObStrMap_PushU(psmOb, peSrc->uszText); } - // 2: byte count: + // 2: byte count & alloc: if(!ObStrMap_FinalizeBufferXUW(psmOb, 0, NULL, &cbDstStr, fWideChar)) { goto fail; } cbDstData = pObMapSrc->cMap * sizeof(VMMDLL_MAP_UNLOADEDMODULEENTRY); cbDst = sizeof(VMMDLL_MAP_UNLOADEDMODULE) + cbDstData + cbDstStr; - // 3: fill map [if required]: - if(pMapDst) { - if(*pcbMapDst < cbDst) { goto fail; } - ZeroMemory(pMapDst, sizeof(VMMDLL_MAP_UNLOADEDMODULE)); - pMapDst->dwVersion = VMMDLL_MAP_UNLOADEDMODULE_VERSION; - pMapDst->cMap = pObMapSrc->cMap; - memcpy(pMapDst->pMap, pObMapSrc->pMap, cbDstData); - // strmap below: - for(i = 0; i < pMapDst->cMap; i++) { - peSrc = pObMapSrc->pMap + i; - peDst = pMapDst->pMap + i; - f = ObStrMap_PushPtrUXUW(psmOb, peSrc->uszText, &peDst->uszText, NULL, fWideChar); - if(!f) { goto fail; } - } - pMapDst->pbMultiText = ((PBYTE)pMapDst->pMap) + cbDstData; - ObStrMap_FinalizeBufferXUW(psmOb, cbDstStr, pMapDst->pbMultiText, &pMapDst->cbMultiText, fWideChar); + if(!(pMapDst = VmmDllCore_MemAllocExternal(H, OB_TAG_API_MAP_UNLOADEDMODULE, cbDst, sizeof(VMMDLL_MAP_UNLOADEDMODULE)))) { goto fail; } // VMMDLL_MemFree() + // 3: fill map: + pMapDst->dwVersion = VMMDLL_MAP_UNLOADEDMODULE_VERSION; + pMapDst->cMap = pObMapSrc->cMap; + memcpy(pMapDst->pMap, pObMapSrc->pMap, cbDstData); + // strmap below: + for(i = 0; i < pMapDst->cMap; i++) { + peSrc = pObMapSrc->pMap + i; + peDst = pMapDst->pMap + i; + f = ObStrMap_PushPtrUXUW(psmOb, peSrc->uszText, &peDst->uszText, NULL, fWideChar); + if(!f) { goto fail; } } - fResult = TRUE; + pMapDst->pbMultiText = ((PBYTE)pMapDst->pMap) + cbDstData; + ObStrMap_FinalizeBufferXUW(psmOb, cbDstStr, pMapDst->pbMultiText, &pMapDst->cbMultiText, fWideChar); + *ppMapDst = pMapDst; fail: - *pcbMapDst = cbDst; + if(pMapDst && !*ppMapDst) { VMMDLL_MemFree(pMapDst); pMapDst = NULL; } Ob_DECREF(pObProcess); Ob_DECREF(pObMapSrc); Ob_DECREF(psmOb); - return fResult; + return *ppMapDst ? TRUE : FALSE; } -_Success_(return) BOOL VMMDLL_Map_GetUnloadedModuleU(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbUnloadedModuleMap) PVMMDLL_MAP_UNLOADEDMODULE pUnloadedModuleMap, _Inout_ PDWORD pcbUnloadedModuleMap) +_Success_(return) BOOL VMMDLL_Map_GetUnloadedModuleU(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_UNLOADEDMODULE *ppUnloadedModuleMap) { - CALL_IMPLEMENTATION_VMM(STATISTICS_ID_VMMDLL_Map_GetUnloadedModule, VMMDLL_Map_GetUnloadedModule_Impl(dwPID, pUnloadedModuleMap, pcbUnloadedModuleMap, FALSE)) + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_Map_GetUnloadedModule, VMMDLL_Map_GetUnloadedModule_Impl(H, dwPID, ppUnloadedModuleMap, FALSE)) } -_Success_(return) BOOL VMMDLL_Map_GetUnloadedModuleW(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbUnloadedModuleMap) PVMMDLL_MAP_UNLOADEDMODULE pUnloadedModuleMap, _Inout_ PDWORD pcbUnloadedModuleMap) +_Success_(return) BOOL VMMDLL_Map_GetUnloadedModuleW(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_UNLOADEDMODULE *ppUnloadedModuleMap) { - CALL_IMPLEMENTATION_VMM(STATISTICS_ID_VMMDLL_Map_GetUnloadedModule, VMMDLL_Map_GetUnloadedModule_Impl(dwPID, pUnloadedModuleMap, pcbUnloadedModuleMap, TRUE)) + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_Map_GetUnloadedModule, VMMDLL_Map_GetUnloadedModule_Impl(H, dwPID, ppUnloadedModuleMap, TRUE)) } _Success_(return) -BOOL VMMDLL_Map_GetEAT_Impl(_In_ DWORD dwPID, _In_ LPSTR uszModuleName, _Out_writes_bytes_opt_(*pcbMapDst) PVMMDLL_MAP_EAT pMapDst, _Inout_ PDWORD pcbMapDst, _In_ BOOL fWideChar) +BOOL VMMDLL_Map_GetEAT_Impl(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ LPSTR uszModuleName, _Out_ PVMMDLL_MAP_EAT *ppMapDst, _In_ BOOL fWideChar) { BOOL f, fResult = FALSE; PVMM_PROCESS pObProcess = NULL; @@ -1487,56 +1230,56 @@ BOOL VMMDLL_Map_GetEAT_Impl(_In_ DWORD dwPID, _In_ LPSTR uszModuleName, _Out_wri PVMMDLL_MAP_EATENTRY peDst; PVMM_MAP_EATENTRY peSrc; PVMMOB_MAP_EAT pObMapSrc = NULL; + PVMMDLL_MAP_EAT pMapDst = NULL; POB_STRMAP psmOb = NULL; + *ppMapDst = NULL; // 0: sanity check: if(sizeof(VMM_MAP_EATENTRY) != sizeof(VMMDLL_MAP_EATENTRY)) { goto fail; } // 1: fetch map [and populate strings]: - if(!(psmOb = ObStrMap_New(0))) { goto fail; } - if(!(pObProcess = VmmProcessGet(dwPID))) { goto fail; } - if(!VmmMap_GetModuleEntryEx(pObProcess, 0, uszModuleName, &pObModuleMap, &pModuleEntry)) { goto fail; } - if(!VmmMap_GetEAT(pObProcess, pModuleEntry, &pObMapSrc)) { goto fail; } + if(!(psmOb = ObStrMap_New(H, 0))) { goto fail; } + if(!(pObProcess = VmmProcessGet(H, dwPID))) { goto fail; } + if(!VmmMap_GetModuleEntryEx(H, pObProcess, 0, uszModuleName, &pObModuleMap, &pModuleEntry)) { goto fail; } + if(!VmmMap_GetEAT(H, pObProcess, pModuleEntry, &pObMapSrc)) { goto fail; } for(i = 0; i < pObMapSrc->cMap; i++) { peSrc = pObMapSrc->pMap + i; ObStrMap_PushU(psmOb, peSrc->uszFunction); } - // 2: byte count: + // 2: byte count & alloc: if(!ObStrMap_FinalizeBufferXUW(psmOb, 0, NULL, &cbDstStr, fWideChar)) { goto fail; } cbDstData = pObMapSrc->cMap * sizeof(VMMDLL_MAP_EATENTRY); cbDst = sizeof(VMMDLL_MAP_EAT) + cbDstData + cbDstStr; - // 3: fill map [if required]: - if(pMapDst) { - if(*pcbMapDst < cbDst) { goto fail; } - pMapDst->dwVersion = VMMDLL_MAP_EAT_VERSION; - pMapDst->vaModuleBase = pObMapSrc->vaModuleBase; - pMapDst->vaAddressOfFunctions = pObMapSrc->vaAddressOfFunctions; - pMapDst->vaAddressOfNames = pObMapSrc->vaAddressOfNames; - pMapDst->cNumberOfFunctions = pObMapSrc->cNumberOfFunctions; - pMapDst->cNumberOfNames = pObMapSrc->cNumberOfNames; - pMapDst->dwOrdinalBase = pObMapSrc->dwOrdinalBase; - pMapDst->cMap = pObMapSrc->cMap; - memcpy(pMapDst->pMap, pObMapSrc->pMap, cbDstData); - // strmap below: - for(i = 0; i < pMapDst->cMap; i++) { - peSrc = pObMapSrc->pMap + i; - peDst = pMapDst->pMap + i; - f = ObStrMap_PushPtrUXUW(psmOb, peSrc->uszFunction, &peDst->uszFunction, NULL, fWideChar); - if(!f) { goto fail; } - } - pMapDst->pbMultiText = ((PBYTE)pMapDst->pMap) + cbDstData; - ObStrMap_FinalizeBufferXUW(psmOb, cbDstStr, pMapDst->pbMultiText, &pMapDst->cbMultiText, fWideChar); + if(!(pMapDst = VmmDllCore_MemAllocExternal(H, OB_TAG_API_MAP_EAT, cbDst, sizeof(VMMDLL_MAP_EAT)))) { goto fail; } // VMMDLL_MemFree() + // 3: fill map: + pMapDst->dwVersion = VMMDLL_MAP_EAT_VERSION; + pMapDst->vaModuleBase = pObMapSrc->vaModuleBase; + pMapDst->vaAddressOfFunctions = pObMapSrc->vaAddressOfFunctions; + pMapDst->vaAddressOfNames = pObMapSrc->vaAddressOfNames; + pMapDst->cNumberOfFunctions = pObMapSrc->cNumberOfFunctions; + pMapDst->cNumberOfNames = pObMapSrc->cNumberOfNames; + pMapDst->dwOrdinalBase = pObMapSrc->dwOrdinalBase; + pMapDst->cMap = pObMapSrc->cMap; + memcpy(pMapDst->pMap, pObMapSrc->pMap, cbDstData); + // strmap below: + for(i = 0; i < pMapDst->cMap; i++) { + peSrc = pObMapSrc->pMap + i; + peDst = pMapDst->pMap + i; + f = ObStrMap_PushPtrUXUW(psmOb, peSrc->uszFunction, &peDst->uszFunction, NULL, fWideChar); + if(!f) { goto fail; } } - fResult = TRUE; + pMapDst->pbMultiText = ((PBYTE)pMapDst->pMap) + cbDstData; + ObStrMap_FinalizeBufferXUW(psmOb, cbDstStr, pMapDst->pbMultiText, &pMapDst->cbMultiText, fWideChar); + *ppMapDst = pMapDst; fail: - *pcbMapDst = cbDst; + if(pMapDst && !*ppMapDst) { VMMDLL_MemFree(pMapDst); pMapDst = NULL; } Ob_DECREF(pObModuleMap); Ob_DECREF(pObProcess); Ob_DECREF(pObMapSrc); Ob_DECREF(psmOb); - return fResult; + return *ppMapDst ? TRUE : FALSE; } _Success_(return) -BOOL VMMDLL_Map_GetIAT_Impl(_In_ DWORD dwPID, _In_ LPSTR uszModuleName, _Out_writes_bytes_opt_(*pcbMapDst) PVMMDLL_MAP_IAT pMapDst, _Inout_ PDWORD pcbMapDst, _In_ BOOL fWideChar) +BOOL VMMDLL_Map_GetIAT_Impl(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ LPSTR uszModuleName, _Out_ PVMMDLL_MAP_IAT *ppMapDst, _In_ BOOL fWideChar) { BOOL f, fResult = FALSE; PVMM_PROCESS pObProcess = NULL; @@ -1546,313 +1289,278 @@ BOOL VMMDLL_Map_GetIAT_Impl(_In_ DWORD dwPID, _In_ LPSTR uszModuleName, _Out_wri PVMMDLL_MAP_IATENTRY peDst; PVMM_MAP_IATENTRY peSrc; PVMMOB_MAP_IAT pObMapSrc = NULL; + PVMMDLL_MAP_IAT pMapDst = NULL; POB_STRMAP psmOb = NULL; + *ppMapDst = NULL; // 0: sanity check: if(sizeof(VMM_MAP_IATENTRY) != sizeof(VMMDLL_MAP_IATENTRY)) { goto fail; } // 1: fetch map [and populate strings]: - if(!(psmOb = ObStrMap_New(0))) { goto fail; } - if(!(pObProcess = VmmProcessGet(dwPID))) { goto fail; } - if(!VmmMap_GetModuleEntryEx(pObProcess, 0, uszModuleName, &pObModuleMap, &pModuleEntry)) { goto fail; } - if(!VmmMap_GetIAT(pObProcess, pModuleEntry, &pObMapSrc)) { goto fail; } + if(!(psmOb = ObStrMap_New(H, 0))) { goto fail; } + if(!(pObProcess = VmmProcessGet(H, dwPID))) { goto fail; } + if(!VmmMap_GetModuleEntryEx(H, pObProcess, 0, uszModuleName, &pObModuleMap, &pModuleEntry)) { goto fail; } + if(!VmmMap_GetIAT(H, pObProcess, pModuleEntry, &pObMapSrc)) { goto fail; } for(i = 0; i < pObMapSrc->cMap; i++) { peSrc = pObMapSrc->pMap + i; ObStrMap_PushU(psmOb, peSrc->uszModule); ObStrMap_PushU(psmOb, peSrc->uszFunction); } - // 2: byte count: + // 2: byte count & alloc: if(!ObStrMap_FinalizeBufferXUW(psmOb, 0, NULL, &cbDstStr, fWideChar)) { goto fail; } cbDstData = pObMapSrc->cMap * sizeof(VMMDLL_MAP_IATENTRY); cbDst = sizeof(VMMDLL_MAP_IAT) + cbDstData + cbDstStr; - // 3: fill map [if required]: - if(pMapDst) { - if(*pcbMapDst < cbDst) { goto fail; } - pMapDst->dwVersion = VMMDLL_MAP_IAT_VERSION; - pMapDst->vaModuleBase = pObMapSrc->vaModuleBase; - pMapDst->cMap = pObMapSrc->cMap; - memcpy(pMapDst->pMap, pObMapSrc->pMap, cbDstData); - // strmap below: - for(i = 0; i < pMapDst->cMap; i++) { - peSrc = pObMapSrc->pMap + i; - peDst = pMapDst->pMap + i; - f = ObStrMap_PushPtrUXUW(psmOb, peSrc->uszModule, &peDst->uszModule, NULL, fWideChar) && - ObStrMap_PushPtrUXUW(psmOb, peSrc->uszFunction, &peDst->uszFunction, NULL, fWideChar); - if(!f) { goto fail; } - } - pMapDst->pbMultiText = ((PBYTE)pMapDst->pMap) + cbDstData; - ObStrMap_FinalizeBufferXUW(psmOb, cbDstStr, pMapDst->pbMultiText, &pMapDst->cbMultiText, fWideChar); + if(!(pMapDst = VmmDllCore_MemAllocExternal(H, OB_TAG_API_MAP_IAT, cbDst, sizeof(VMMDLL_MAP_IAT)))) { goto fail; } // VMMDLL_MemFree() + // 3: fill map: + pMapDst->dwVersion = VMMDLL_MAP_IAT_VERSION; + pMapDst->vaModuleBase = pObMapSrc->vaModuleBase; + pMapDst->cMap = pObMapSrc->cMap; + memcpy(pMapDst->pMap, pObMapSrc->pMap, cbDstData); + // strmap below: + for(i = 0; i < pMapDst->cMap; i++) { + peSrc = pObMapSrc->pMap + i; + peDst = pMapDst->pMap + i; + f = ObStrMap_PushPtrUXUW(psmOb, peSrc->uszModule, &peDst->uszModule, NULL, fWideChar) && + ObStrMap_PushPtrUXUW(psmOb, peSrc->uszFunction, &peDst->uszFunction, NULL, fWideChar); + if(!f) { goto fail; } } - fResult = TRUE; + pMapDst->pbMultiText = ((PBYTE)pMapDst->pMap) + cbDstData; + ObStrMap_FinalizeBufferXUW(psmOb, cbDstStr, pMapDst->pbMultiText, &pMapDst->cbMultiText, fWideChar); + *ppMapDst = pMapDst; fail: - *pcbMapDst = cbDst; + if(pMapDst && !*ppMapDst) { VMMDLL_MemFree(pMapDst); pMapDst = NULL; } Ob_DECREF(pObModuleMap); Ob_DECREF(pObProcess); Ob_DECREF(pObMapSrc); Ob_DECREF(psmOb); - return fResult; + return *ppMapDst ? TRUE : FALSE; } -_Success_(return) BOOL VMMDLL_Map_GetEATU(_In_ DWORD dwPID, _In_ LPSTR uszModuleName, _Out_writes_bytes_opt_(*pcbEatMap) PVMMDLL_MAP_EAT pEatMap, _Inout_ PDWORD pcbEatMap) +_Success_(return) BOOL VMMDLL_Map_GetEATU(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ LPSTR uszModuleName, _Out_ PVMMDLL_MAP_EAT *ppEatMap) { - CALL_IMPLEMENTATION_VMM(STATISTICS_ID_VMMDLL_Map_GetEAT, VMMDLL_Map_GetEAT_Impl(dwPID, uszModuleName, pEatMap, pcbEatMap, FALSE)) + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_Map_GetEAT, VMMDLL_Map_GetEAT_Impl(H, dwPID, uszModuleName, ppEatMap, FALSE)) } -_Success_(return) BOOL VMMDLL_Map_GetEATW(_In_ DWORD dwPID, _In_ LPWSTR wszModuleName, _Out_writes_bytes_opt_(*pcbEatMap) PVMMDLL_MAP_EAT pEatMap, _Inout_ PDWORD pcbEatMap) +_Success_(return) BOOL VMMDLL_Map_GetEATW(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ LPWSTR wszModuleName, _Out_ PVMMDLL_MAP_EAT *ppEatMap) { LPSTR uszModuleName; BYTE pbBuffer[MAX_PATH]; if(!CharUtil_WtoU(wszModuleName, -1, pbBuffer, sizeof(pbBuffer), &uszModuleName, NULL, 0)) { return FALSE; } - CALL_IMPLEMENTATION_VMM(STATISTICS_ID_VMMDLL_Map_GetEAT, VMMDLL_Map_GetEAT_Impl(dwPID, uszModuleName, pEatMap, pcbEatMap, TRUE)) + return VMMDLL_Map_GetEATU(H, dwPID, uszModuleName, ppEatMap); } -_Success_(return) BOOL VMMDLL_Map_GetIATU(_In_ DWORD dwPID, _In_ LPSTR uszModuleName, _Out_writes_bytes_opt_(*pcbIatMap) PVMMDLL_MAP_IAT pIatMap, _Inout_ PDWORD pcbIatMap) +_Success_(return) BOOL VMMDLL_Map_GetIATU(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ LPSTR uszModuleName, _Out_ PVMMDLL_MAP_IAT *ppIatMap) { - CALL_IMPLEMENTATION_VMM(STATISTICS_ID_VMMDLL_Map_GetIAT, VMMDLL_Map_GetIAT_Impl(dwPID, uszModuleName, pIatMap, pcbIatMap, FALSE)) + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_Map_GetIAT, VMMDLL_Map_GetIAT_Impl(H, dwPID, uszModuleName, ppIatMap, FALSE)) } -_Success_(return) BOOL VMMDLL_Map_GetIATW(_In_ DWORD dwPID, _In_ LPWSTR wszModuleName, _Out_writes_bytes_opt_(*pcbIatMap) PVMMDLL_MAP_IAT pIatMap, _Inout_ PDWORD pcbIatMap) +_Success_(return) BOOL VMMDLL_Map_GetIATW(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ LPWSTR wszModuleName, _Out_ PVMMDLL_MAP_IAT *ppIatMap) { LPSTR uszModuleName; BYTE pbBuffer[MAX_PATH]; if(!CharUtil_WtoU(wszModuleName, -1, pbBuffer, sizeof(pbBuffer), &uszModuleName, NULL, 0)) { return FALSE; } - CALL_IMPLEMENTATION_VMM(STATISTICS_ID_VMMDLL_Map_GetIAT, VMMDLL_Map_GetIAT_Impl(dwPID, uszModuleName, pIatMap, pcbIatMap, TRUE)) + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_Map_GetIAT, VMMDLL_Map_GetIAT_Impl(H, dwPID, uszModuleName, ppIatMap, TRUE)) } _Success_(return) -BOOL VMMDLL_Map_GetHeapEx_Impl(_In_ DWORD dwPID, _Out_ PVMMDLL_MAP_HEAP *ppHeapMap) +BOOL VMMDLL_Map_GetHeap_Impl(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_HEAP * ppDstMap) { PVMMOB_MAP_HEAP pObMapSrc = NULL; + PVMMDLL_MAP_HEAP pMapDst = NULL; PVMM_PROCESS pObProcess = NULL; - *ppHeapMap = NULL; - if(!(pObProcess = VmmProcessGet(dwPID))) { goto fail; } - if(!VmmMap_GetHeap(pObProcess, &pObMapSrc)) { goto fail; } - if(!(*ppHeapMap = LocalAlloc(0, (SIZE_T)32 + pObMapSrc->ObHdr.cbData))) { goto fail; } - memcpy(*ppHeapMap, pObMapSrc, (SIZE_T)32 + pObMapSrc->ObHdr.cbData); - ZeroMemory(*ppHeapMap, 32); - (*ppHeapMap)->dwVersion = VMMDLL_MAP_HEAP_VERSION; - (*ppHeapMap)->pSegments = (PVMMDLL_MAP_HEAP_SEGMENTENTRY)((*ppHeapMap)->pMap + (*ppHeapMap)->cMap); + DWORD cbData = 0; + *ppDstMap = NULL; + if(!(pObProcess = VmmProcessGet(H, dwPID))) { goto fail; } + if(!VmmMap_GetHeap(H, pObProcess, &pObMapSrc)) { goto fail; } + cbData = pObMapSrc->cMap * sizeof(VMMDLL_MAP_HEAPENTRY) + pObMapSrc->cSegments * sizeof(VMMDLL_MAP_HEAP_SEGMENTENTRY); + if(!(pMapDst = VmmDllCore_MemAllocExternal(H, OB_TAG_API_MAP_HEAP, sizeof(VMMDLL_MAP_HEAP) + cbData, sizeof(VMMDLL_MAP_HEAP)))) { goto fail; } // VMMDLL_MemFree() + pMapDst->dwVersion = VMMDLL_MAP_HEAP_VERSION; + pMapDst->cMap = pObMapSrc->cMap; + pMapDst->cSegments = pObMapSrc->cSegments; + memcpy(pMapDst->pMap, pObMapSrc->pMap, cbData); + pMapDst->pSegments = (PVMMDLL_MAP_HEAP_SEGMENTENTRY)(pMapDst->pMap + pMapDst->cMap); + *ppDstMap = pMapDst; fail: Ob_DECREF(pObProcess); Ob_DECREF(pObMapSrc); - return *ppHeapMap ? TRUE : FALSE; + return *ppDstMap ? TRUE : FALSE; } _Success_(return) -BOOL VMMDLL_Map_GetHeapEx(_In_ DWORD dwPID, _Out_ PVMMDLL_MAP_HEAP *ppHeapMap) +BOOL VMMDLL_Map_GetHeap(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_HEAP *ppHeapMap) { CALL_IMPLEMENTATION_VMM( + H, STATISTICS_ID_VMMDLL_Map_GetHeapEx, - VMMDLL_Map_GetHeapEx_Impl(dwPID, ppHeapMap)) + VMMDLL_Map_GetHeap_Impl(H, dwPID, ppHeapMap)) } _Success_(return) -BOOL VMMDLL_Map_GetHeapAllocEx_Impl(_In_ DWORD dwPID, _In_ QWORD qwHeapNumOrAddress, _Out_ PVMMDLL_MAP_HEAPALLOC *ppHeapAllocMap) +BOOL VMMDLL_Map_GetHeapAlloc_Impl(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ QWORD qwHeapNumOrAddress, _Out_ PVMMDLL_MAP_HEAPALLOC *ppDstMap) { PVMMOB_MAP_HEAPALLOC pObMapSrc = NULL; + PVMMDLL_MAP_HEAPALLOC pMapDst = NULL; PVMM_PROCESS pObProcess = NULL; - *ppHeapAllocMap = NULL; - if(!(pObProcess = VmmProcessGet(dwPID))) { goto fail; } - if(!VmmMap_GetHeapAlloc(pObProcess, qwHeapNumOrAddress, &pObMapSrc)) { goto fail; } - if(!(*ppHeapAllocMap = LocalAlloc(0, (SIZE_T)32 + pObMapSrc->ObHdr.cbData))) { goto fail; } - memcpy(*ppHeapAllocMap, pObMapSrc, (SIZE_T)32 + pObMapSrc->ObHdr.cbData); - ZeroMemory(*ppHeapAllocMap, 32); - (*ppHeapAllocMap)->dwVersion = VMMDLL_MAP_HEAPALLOC_VERSION; - (*ppHeapAllocMap)->_Reserved2[0] = 0; - (*ppHeapAllocMap)->_Reserved2[1] = 0; + DWORD cbData = 0; + *ppDstMap = NULL; + if(!(pObProcess = VmmProcessGet(H, dwPID))) { goto fail; } + if(!VmmMap_GetHeapAlloc(H, pObProcess, qwHeapNumOrAddress, &pObMapSrc)) { goto fail; } + cbData = pObMapSrc->cMap * sizeof(VMMDLL_MAP_HEAPALLOCENTRY); + if(!(pMapDst = VmmDllCore_MemAllocExternal(H, OB_TAG_API_MAP_HEAP_ALLOC, sizeof(VMMDLL_MAP_HEAPALLOC) + cbData, sizeof(VMMDLL_MAP_HEAPALLOC)))) { goto fail; } // VMMDLL_MemFree() + pMapDst->dwVersion = VMMDLL_MAP_HEAPALLOC_VERSION; + pMapDst->cMap = pObMapSrc->cMap; + memcpy(pMapDst->pMap, pObMapSrc->pMap, cbData); + *ppDstMap = pMapDst; fail: Ob_DECREF(pObProcess); Ob_DECREF(pObMapSrc); - return *ppHeapAllocMap ? TRUE : FALSE; + return *ppDstMap ? TRUE : FALSE; } _Success_(return) -BOOL VMMDLL_Map_GetHeapAllocEx(_In_ DWORD dwPID, _In_ QWORD qwHeapNumOrAddress, _Out_ PVMMDLL_MAP_HEAPALLOC *ppHeapAllocMap) +BOOL VMMDLL_Map_GetHeapAlloc(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ QWORD qwHeapNumOrAddress, _Out_ PVMMDLL_MAP_HEAPALLOC *ppHeapAllocMap) { CALL_IMPLEMENTATION_VMM( + H, STATISTICS_ID_VMMDLL_Map_GetHeapAllocEx, - VMMDLL_Map_GetHeapAllocEx_Impl(dwPID, qwHeapNumOrAddress, ppHeapAllocMap)) + VMMDLL_Map_GetHeapAlloc_Impl(H, dwPID, qwHeapNumOrAddress, ppHeapAllocMap)) } _Success_(return) -BOOL VMMDLL_Map_GetThread_Impl(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbMapDst) PVMMDLL_MAP_THREAD pMapDst, _Inout_ PDWORD pcbMapDst) +BOOL VMMDLL_Map_GetThread_Impl(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_THREAD *ppMapDst) { - BOOL fResult = FALSE; - DWORD cbDst = 0, cbDstData; PVMMOB_MAP_THREAD pObMapSrc = NULL; + PVMMDLL_MAP_THREAD pMapDst = NULL; PVMM_PROCESS pObProcess = NULL; - if(!(pObProcess = VmmProcessGet(dwPID))) { goto fail; } - if(!VmmMap_GetThread(pObProcess, &pObMapSrc)) { goto fail; } - cbDstData = pObMapSrc->cMap * sizeof(VMMDLL_MAP_THREADENTRY); - cbDst = sizeof(VMMDLL_MAP_THREAD) + cbDstData; - if(pMapDst) { - if(*pcbMapDst < cbDst) { goto fail; } - ZeroMemory(pMapDst, sizeof(VMMDLL_MAP_HEAP)); - pMapDst->dwVersion = VMMDLL_MAP_THREAD_VERSION; - pMapDst->cMap = pObMapSrc->cMap; - memcpy(pMapDst->pMap, pObMapSrc->pMap, cbDstData); - } - fResult = TRUE; + DWORD cbData = 0; + *ppMapDst = NULL; + if(!(pObProcess = VmmProcessGet(H, dwPID))) { goto fail; } + if(!VmmMap_GetThread(H, pObProcess, &pObMapSrc)) { goto fail; } + cbData = pObMapSrc->cMap * sizeof(VMMDLL_MAP_THREADENTRY); + if(!(pMapDst = VmmDllCore_MemAllocExternal(H, OB_TAG_API_MAP_THREAD, sizeof(VMMDLL_MAP_THREAD) + cbData, sizeof(VMMDLL_MAP_THREAD)))) { goto fail; } // VMMDLL_MemFree() + pMapDst->dwVersion = VMMDLL_MAP_THREAD_VERSION; + pMapDst->cMap = pObMapSrc->cMap; + memcpy(pMapDst->pMap, pObMapSrc->pMap, cbData); + *ppMapDst = pMapDst; fail: - *pcbMapDst = cbDst; Ob_DECREF(pObProcess); Ob_DECREF(pObMapSrc); - return fResult; + return *ppMapDst ? TRUE : FALSE; } -_Success_(return) -BOOL VMMDLL_Map_GetThread(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbThreadMap) PVMMDLL_MAP_THREAD pThreadMap, _Inout_ PDWORD pcbThreadMap) +EXPORTED_FUNCTION +_Success_(return) BOOL VMMDLL_Map_GetThread(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_THREAD *ppThreadMap) { CALL_IMPLEMENTATION_VMM( + H, STATISTICS_ID_VMMDLL_Map_GetThread, - VMMDLL_Map_GetThread_Impl(dwPID, pThreadMap, pcbThreadMap)) + VMMDLL_Map_GetThread_Impl(H, dwPID, ppThreadMap)) } _Success_(return) -BOOL VMMDLL_Map_GetHandle_Impl(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbMapDst) PVMMDLL_MAP_HANDLE pMapDst, _Inout_ PDWORD pcbMapDst, _In_ BOOL fWideChar) +BOOL VMMDLL_Map_GetHandle_Impl(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_HANDLE *ppMapDst, _In_ BOOL fWideChar) { - BOOL f, fResult = FALSE; + BOOL f; PVMMWIN_OBJECT_TYPE pOT; PVMM_PROCESS pObProcess = NULL; DWORD i, cbDst = 0, cbDstData, cbDstStr; PVMMDLL_MAP_HANDLEENTRY peDst; PVMM_MAP_HANDLEENTRY peSrc; PVMMOB_MAP_HANDLE pObMapSrc = NULL; + PVMMDLL_MAP_HANDLE pMapDst = NULL; POB_STRMAP psmOb = NULL; + *ppMapDst = NULL; // 0: sanity check: if(sizeof(VMM_MAP_HANDLEENTRY) != sizeof(VMMDLL_MAP_HANDLEENTRY)) { goto fail; } // 1: fetch map [and populate strings]: - if(!(psmOb = ObStrMap_New(0))) { goto fail; } - if(!(pObProcess = VmmProcessGet(dwPID))) { goto fail; } - if(!VmmMap_GetHandle(pObProcess, &pObMapSrc, TRUE)) { goto fail; } + if(!(psmOb = ObStrMap_New(H, 0))) { goto fail; } + if(!(pObProcess = VmmProcessGet(H, dwPID))) { goto fail; } + if(!VmmMap_GetHandle(H, pObProcess, &pObMapSrc, TRUE)) { goto fail; } for(i = 0; i < pObMapSrc->cMap; i++) { peSrc = pObMapSrc->pMap + i; - pOT = VmmWin_ObjectTypeGet((BYTE)peSrc->iType); + pOT = VmmWin_ObjectTypeGet(H, (BYTE)peSrc->iType); ObStrMap_PushU(psmOb, (pOT ? pOT->usz : NULL)); ObStrMap_PushU(psmOb, peSrc->uszText); } - // 2: byte count: + // 2: byte count & alloc: if(!ObStrMap_FinalizeBufferXUW(psmOb, 0, NULL, &cbDstStr, fWideChar)) { goto fail; } cbDstData = pObMapSrc->cMap * sizeof(VMMDLL_MAP_HANDLEENTRY); cbDst = sizeof(VMMDLL_MAP_HANDLE) + cbDstData + cbDstStr; - // 3: fill map [if required]: - if(pMapDst) { - if(*pcbMapDst < cbDst) { goto fail; } - ZeroMemory(pMapDst, sizeof(VMMDLL_MAP_HANDLE)); - pMapDst->dwVersion = VMMDLL_MAP_HANDLE_VERSION; - pMapDst->cMap = pObMapSrc->cMap; - memcpy(pMapDst->pMap, pObMapSrc->pMap, cbDstData); - // strmap below: - for(i = 0; i < pMapDst->cMap; i++) { - peSrc = pObMapSrc->pMap + i; - peDst = pMapDst->pMap + i; - pOT = VmmWin_ObjectTypeGet((BYTE)peDst->iType); - f = ObStrMap_PushPtrUXUW(psmOb, (pOT ? pOT->usz : NULL), &peDst->uszType, NULL, fWideChar) && - ObStrMap_PushPtrUXUW(psmOb, peSrc->uszText, &peDst->uszText, NULL, fWideChar); - if(!f) { goto fail; } - } - pMapDst->pbMultiText = ((PBYTE)pMapDst->pMap) + cbDstData; - ObStrMap_FinalizeBufferXUW(psmOb, cbDstStr, pMapDst->pbMultiText, &pMapDst->cbMultiText, fWideChar); + if(!(pMapDst = VmmDllCore_MemAllocExternal(H, OB_TAG_API_MAP_HANDLE, cbDst, sizeof(VMMDLL_MAP_HANDLE)))) { goto fail; } // VMMDLL_MemFree() + // 3: fill map: + pMapDst->dwVersion = VMMDLL_MAP_HANDLE_VERSION; + pMapDst->cMap = pObMapSrc->cMap; + memcpy(pMapDst->pMap, pObMapSrc->pMap, cbDstData); + // strmap below: + for(i = 0; i < pMapDst->cMap; i++) { + peSrc = pObMapSrc->pMap + i; + peDst = pMapDst->pMap + i; + pOT = VmmWin_ObjectTypeGet(H, (BYTE)peDst->iType); + f = ObStrMap_PushPtrUXUW(psmOb, (pOT ? pOT->usz : NULL), &peDst->uszType, NULL, fWideChar) && + ObStrMap_PushPtrUXUW(psmOb, peSrc->uszText, &peDst->uszText, NULL, fWideChar); + if(!f) { goto fail; } } - fResult = TRUE; + pMapDst->pbMultiText = ((PBYTE)pMapDst->pMap) + cbDstData; + ObStrMap_FinalizeBufferXUW(psmOb, cbDstStr, pMapDst->pbMultiText, &pMapDst->cbMultiText, fWideChar); + *ppMapDst = pMapDst; fail: - *pcbMapDst = cbDst; + if(pMapDst && !*ppMapDst) { VMMDLL_MemFree(pMapDst); pMapDst = NULL; } Ob_DECREF(pObProcess); Ob_DECREF(pObMapSrc); Ob_DECREF(psmOb); - return fResult; + return *ppMapDst ? TRUE : FALSE; } -_Success_(return) BOOL VMMDLL_Map_GetHandleU(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbHandleMap) PVMMDLL_MAP_HANDLE pHandleMap, _Inout_ PDWORD pcbHandleMap) +_Success_(return) BOOL VMMDLL_Map_GetHandleU(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_HANDLE *ppHandleMap) { - CALL_IMPLEMENTATION_VMM(STATISTICS_ID_VMMDLL_Map_GetHandle, VMMDLL_Map_GetHandle_Impl(dwPID, pHandleMap, pcbHandleMap, FALSE)) + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_Map_GetHandle, VMMDLL_Map_GetHandle_Impl(H, dwPID, ppHandleMap, FALSE)) } -_Success_(return) BOOL VMMDLL_Map_GetHandleW(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbHandleMap) PVMMDLL_MAP_HANDLE pHandleMap, _Inout_ PDWORD pcbHandleMap) +_Success_(return) BOOL VMMDLL_Map_GetHandleW(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_HANDLE *ppHandleMap) { - CALL_IMPLEMENTATION_VMM(STATISTICS_ID_VMMDLL_Map_GetHandle, VMMDLL_Map_GetHandle_Impl(dwPID, pHandleMap, pcbHandleMap, TRUE)) + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_Map_GetHandle, VMMDLL_Map_GetHandle_Impl(H, dwPID, ppHandleMap, TRUE)) } _Success_(return) -BOOL VMMDLL_Map_GetPhysMem_Impl(_Out_writes_bytes_opt_(*pcbMapDst) PVMMDLL_MAP_PHYSMEM pMapDst, _Inout_ PDWORD pcbMapDst) +BOOL VMMDLL_Map_GetPhysMem_Impl(_In_ VMM_HANDLE H, _Out_ PVMMDLL_MAP_PHYSMEM *ppMapDst) { - BOOL fResult = FALSE; - DWORD cbDst = 0, cbDstData; + DWORD cbDst = 0, cbDstData = 0; PVMMOB_MAP_PHYSMEM pObMap = NULL; - if(!VmmMap_GetPhysMem(&pObMap)) { goto fail; } + PVMMDLL_MAP_PHYSMEM pMapDst = NULL; + *ppMapDst = NULL; + if(!VmmMap_GetPhysMem(H, &pObMap)) { goto fail; } cbDstData = pObMap->cMap * sizeof(VMMDLL_MAP_PHYSMEMENTRY); cbDst = sizeof(VMMDLL_MAP_PHYSMEM) + cbDstData; - if(pMapDst) { - if(*pcbMapDst < cbDst) { goto fail; } - ZeroMemory(pMapDst, cbDst); - pMapDst->dwVersion = VMMDLL_MAP_PHYSMEM_VERSION; - pMapDst->cMap = pObMap->cMap; - memcpy(pMapDst->pMap, pObMap->pMap, cbDstData); - } - fResult = TRUE; + if(!(pMapDst = VmmDllCore_MemAllocExternal(H, OB_TAG_API_MAP_PHYSMEM, cbDst, sizeof(VMMDLL_MAP_PHYSMEM)))) { goto fail; } // VMMDLL_MemFree() + pMapDst->dwVersion = VMMDLL_MAP_PHYSMEM_VERSION; + pMapDst->cMap = pObMap->cMap; + memcpy(pMapDst->pMap, pObMap->pMap, cbDstData); + *ppMapDst = pMapDst; fail: - *pcbMapDst = cbDst; + if(pMapDst && !*ppMapDst) { VMMDLL_MemFree(pMapDst); pMapDst = NULL; } Ob_DECREF(pObMap); - return fResult; + return *ppMapDst ? TRUE : FALSE; } _Success_(return) -BOOL VMMDLL_Map_GetPhysMem(_Out_writes_bytes_opt_(*pcbPhysMemMap) PVMMDLL_MAP_PHYSMEM pPhysMemMap, _Inout_ PDWORD pcbPhysMemMap) +BOOL VMMDLL_Map_GetPhysMem(_In_ VMM_HANDLE H, _Out_ PVMMDLL_MAP_PHYSMEM *ppPhysMemMap) { CALL_IMPLEMENTATION_VMM( + H, STATISTICS_ID_VMMDLL_Map_GetPhysMem, - VMMDLL_Map_GetPhysMem_Impl(pPhysMemMap, pcbPhysMemMap)) + VMMDLL_Map_GetPhysMem_Impl(H, ppPhysMemMap)) } _Success_(return) -BOOL VMMDLL_Map_GetPool_Impl(_Out_writes_bytes_opt_(*pcbMapDst) PVMMDLL_MAP_POOL pMapDst, _Inout_ PDWORD pcbMapDst) -{ - BOOL fResult = FALSE; - DWORD cbDst = 0, cbDstData, cbDstDataMap, cbDstDataTag; - PVMMOB_MAP_POOL pObMap = NULL; - if(!VmmMap_GetPool(&pObMap, TRUE)) { goto fail; } - cbDstDataMap = pObMap->cMap * sizeof(VMMDLL_MAP_POOLENTRY); - cbDstDataTag = pObMap->cTag * sizeof(VMMDLL_MAP_POOLENTRYTAG); - cbDstData = cbDstDataMap + cbDstDataTag + pObMap->cMap * sizeof(DWORD); - cbDst = sizeof(VMMDLL_MAP_POOL) + cbDstData; - if(pMapDst) { - if(*pcbMapDst < cbDst) { goto fail; } - ZeroMemory(pMapDst, sizeof(VMMDLL_MAP_POOL)); - pMapDst->dwVersion = VMMDLL_MAP_POOL_VERSION; - pMapDst->cbTotal = cbDst; - pMapDst->cMap = pObMap->cMap; - memcpy(pMapDst->pMap, pObMap->pMap, cbDstData); - // tag - pMapDst->cTag = pObMap->cTag; - pMapDst->pTag = (PVMMDLL_MAP_POOLENTRYTAG)(pMapDst->pMap + pMapDst->cMap); - // tag index - pMapDst->piTag2Map = (PDWORD)((QWORD)pMapDst->pTag + cbDstDataTag); - } - fResult = TRUE; -fail: - *pcbMapDst = cbDst; - Ob_DECREF(pObMap); - return fResult; -} - -_Success_(return) -BOOL VMMDLL_Map_GetPool(_Out_writes_bytes_opt_(*pcbPoolMap) PVMMDLL_MAP_POOL pPoolMap, _Inout_ PDWORD pcbPoolMap) -{ - CALL_IMPLEMENTATION_VMM( - STATISTICS_ID_VMMDLL_Map_GetPool, - VMMDLL_Map_GetPool_Impl(pPoolMap, pcbPoolMap)) -} - -_Success_(return) -BOOL VMMDLL_Map_GetPoolEx_Impl(_Out_ PVMMDLL_MAP_POOL* ppPoolMap, _In_ DWORD flags) +BOOL VMMDLL_Map_GetPool_Impl(_In_ VMM_HANDLE H, _Out_ PVMMDLL_MAP_POOL *ppPoolMap, _In_ DWORD flags) { DWORD cbDst = 0, cbDstData, cbDstDataMap, cbDstDataTag; PVMMDLL_MAP_POOL pMapDst = NULL; PVMMOB_MAP_POOL pObMap = NULL; - if(!VmmMap_GetPool(&pObMap, (flags != VMMDLL_POOLMAP_FLAG_BIG))) { goto fail; } + if(!VmmMap_GetPool(H, &pObMap, (flags != VMMDLL_POOLMAP_FLAG_BIG))) { goto fail; } cbDstDataMap = pObMap->cMap * sizeof(VMMDLL_MAP_POOLENTRY); cbDstDataTag = pObMap->cTag * sizeof(VMMDLL_MAP_POOLENTRYTAG); cbDstData = cbDstDataMap + cbDstDataTag + pObMap->cMap * sizeof(DWORD); cbDst = sizeof(VMMDLL_MAP_POOL) + cbDstData; - if(!(pMapDst = LocalAlloc(0, cbDst))) { goto fail; } + if(!(pMapDst = VmmDllCore_MemAllocExternal(H, OB_TAG_API_MAP_POOL, cbDst, sizeof(VMMDLL_MAP_POOL)))) { goto fail; } // VMMDLL_MemFree() if(pMapDst) { ZeroMemory(pMapDst, sizeof(VMMDLL_MAP_POOL)); pMapDst->dwVersion = VMMDLL_MAP_POOL_VERSION; @@ -1870,154 +1578,154 @@ BOOL VMMDLL_Map_GetPoolEx_Impl(_Out_ PVMMDLL_MAP_POOL* ppPoolMap, _In_ DWORD fla return TRUE; fail: *ppPoolMap = NULL; - LocalFree(pMapDst); + VMMDLL_MemFree(pMapDst); Ob_DECREF(pObMap); return FALSE; } _Success_(return) -BOOL VMMDLL_Map_GetPoolEx(_Out_ PVMMDLL_MAP_POOL* ppPoolMap, _In_ DWORD flags) +BOOL VMMDLL_Map_GetPool(_In_ VMM_HANDLE H, _Out_ PVMMDLL_MAP_POOL* ppPoolMap, _In_ DWORD flags) { - CALL_IMPLEMENTATION_VMM( - STATISTICS_ID_VMMDLL_Map_GetPoolEx, - VMMDLL_Map_GetPoolEx_Impl(ppPoolMap, flags)) + CALL_IMPLEMENTATION_VMM(H, + STATISTICS_ID_VMMDLL_Map_GetPool, + VMMDLL_Map_GetPool_Impl(H, ppPoolMap, flags)) } _Success_(return) -BOOL VMMDLL_Map_GetNet_Impl(_Out_writes_bytes_opt_(*pcbMapDst) PVMMDLL_MAP_NET pMapDst, _Inout_ PDWORD pcbMapDst, _In_ BOOL fWideChar) +BOOL VMMDLL_Map_GetNet_Impl(_In_ VMM_HANDLE H, _Out_ PVMMDLL_MAP_NET *ppMapDst, _In_ BOOL fWideChar) { BOOL f, fResult = FALSE; DWORD i, cbDst = 0, cbDstData, cbDstStr; PVMMDLL_MAP_NETENTRY peDst; PVMM_MAP_NETENTRY peSrc; PVMMOB_MAP_NET pObMapSrc = NULL; + PVMMDLL_MAP_NET pMapDst = NULL; POB_STRMAP psm = NULL; + *ppMapDst = NULL; // 0: sanity check: if(sizeof(VMM_MAP_NETENTRY) != sizeof(VMMDLL_MAP_NETENTRY)) { goto fail; } // 1: fetch map [and populate strings]: - if(!(psm = ObStrMap_New(0))) { goto fail; } - if(!VmmMap_GetNet(&pObMapSrc)) { goto fail; } + if(!(psm = ObStrMap_New(H, 0))) { goto fail; } + if(!VmmMap_GetNet(H, &pObMapSrc)) { goto fail; } for(i = 0; i < pObMapSrc->cMap; i++) { peSrc = pObMapSrc->pMap + i; ObStrMap_PushU(psm, peSrc->Src.uszText); ObStrMap_PushU(psm, peSrc->Dst.uszText); ObStrMap_PushU(psm, peSrc->uszText); } - // 2: byte count: + // 2: byte count & alloc: if(!ObStrMap_FinalizeBufferXUW(psm, 0, NULL, &cbDstStr, fWideChar)) { goto fail; } cbDstData = pObMapSrc->cMap * sizeof(VMMDLL_MAP_NETENTRY); cbDst = sizeof(VMMDLL_MAP_NET) + cbDstData + cbDstStr; - // 3: fill map [if required]: - if(pMapDst) { - if(*pcbMapDst < cbDst) { goto fail; } - ZeroMemory(pMapDst, cbDst); - pMapDst->dwVersion = VMMDLL_MAP_NET_VERSION; - pMapDst->cMap = pObMapSrc->cMap; - memcpy(pMapDst->pMap, pObMapSrc->pMap, cbDstData); - // strmap below: - for(i = 0; i < pMapDst->cMap; i++) { - peSrc = pObMapSrc->pMap + i; - peDst = pMapDst->pMap + i; - f = ObStrMap_PushPtrUXUW(psm, peSrc->Src.uszText, &peDst->Src.uszText, NULL, fWideChar) && - ObStrMap_PushPtrUXUW(psm, peSrc->Dst.uszText, &peDst->Dst.uszText, NULL, fWideChar) && - ObStrMap_PushPtrUXUW(psm, peSrc->uszText, &peDst->uszText, NULL, fWideChar); - if(!f) { goto fail; } - } - pMapDst->pbMultiText = ((PBYTE)pMapDst->pMap) + cbDstData; - ObStrMap_FinalizeBufferXUW(psm, cbDstStr, pMapDst->pbMultiText, &pMapDst->cbMultiText, fWideChar); + if(!(pMapDst = VmmDllCore_MemAllocExternal(H, OB_TAG_API_MAP_NET, cbDst, sizeof(VMMDLL_MAP_NET)))) { goto fail; } // VMMDLL_MemFree() + // 3: fill map: + pMapDst->dwVersion = VMMDLL_MAP_NET_VERSION; + pMapDst->cMap = pObMapSrc->cMap; + memcpy(pMapDst->pMap, pObMapSrc->pMap, cbDstData); + // strmap below: + for(i = 0; i < pMapDst->cMap; i++) { + peSrc = pObMapSrc->pMap + i; + peDst = pMapDst->pMap + i; + f = ObStrMap_PushPtrUXUW(psm, peSrc->Src.uszText, &peDst->Src.uszText, NULL, fWideChar) && + ObStrMap_PushPtrUXUW(psm, peSrc->Dst.uszText, &peDst->Dst.uszText, NULL, fWideChar) && + ObStrMap_PushPtrUXUW(psm, peSrc->uszText, &peDst->uszText, NULL, fWideChar); + if(!f) { goto fail; } } - fResult = TRUE; + pMapDst->pbMultiText = ((PBYTE)pMapDst->pMap) + cbDstData; + ObStrMap_FinalizeBufferXUW(psm, cbDstStr, pMapDst->pbMultiText, &pMapDst->cbMultiText, fWideChar); + *ppMapDst = pMapDst; fail: - *pcbMapDst = cbDst; + if(pMapDst && !*ppMapDst) { VMMDLL_MemFree(pMapDst); pMapDst = NULL; } Ob_DECREF(pObMapSrc); Ob_DECREF(psm); - return fResult; + return *ppMapDst ? TRUE : FALSE; } -_Success_(return) BOOL VMMDLL_Map_GetNetU(_Out_writes_bytes_opt_(*pcbNetMap) PVMMDLL_MAP_NET pNetMap, _Inout_ PDWORD pcbNetMap) +_Success_(return) BOOL VMMDLL_Map_GetNetU(_In_ VMM_HANDLE H, _Out_ PVMMDLL_MAP_NET *ppNetMap) { - CALL_IMPLEMENTATION_VMM(STATISTICS_ID_VMMDLL_Map_GetNet, VMMDLL_Map_GetNet_Impl(pNetMap, pcbNetMap, FALSE)) + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_Map_GetNet, VMMDLL_Map_GetNet_Impl(H, ppNetMap, FALSE)) } -_Success_(return) BOOL VMMDLL_Map_GetNetW(_Out_writes_bytes_opt_(*pcbNetMap) PVMMDLL_MAP_NET pNetMap, _Inout_ PDWORD pcbNetMap) +_Success_(return) BOOL VMMDLL_Map_GetNetW(_In_ VMM_HANDLE H, _Out_ PVMMDLL_MAP_NET *ppNetMap) { - CALL_IMPLEMENTATION_VMM(STATISTICS_ID_VMMDLL_Map_GetNet, VMMDLL_Map_GetNet_Impl(pNetMap, pcbNetMap, TRUE)) + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_Map_GetNet, VMMDLL_Map_GetNet_Impl(H, ppNetMap, TRUE)) } _Success_(return) -BOOL VMMDLL_Map_GetUsers_Impl(_Out_writes_bytes_opt_(*pcbMapDst) PVMMDLL_MAP_USER pMapDst, _Inout_ PDWORD pcbMapDst, _In_ BOOL fWideChar) +BOOL VMMDLL_Map_GetUsers_Impl(_In_ VMM_HANDLE H, _Out_ PVMMDLL_MAP_USER *ppMapDst, _In_ BOOL fWideChar) { BOOL f, fResult = FALSE; DWORD i, cbDst = 0, cbDstData, cbDstStr; PVMMDLL_MAP_USERENTRY peDst; PVMM_MAP_USERENTRY peSrc; PVMMOB_MAP_USER pObMapSrc = NULL; + PVMMDLL_MAP_USER pMapDst = NULL; POB_STRMAP psmOb = NULL; + *ppMapDst = NULL; // 1: fetch map [and populate strings]: - if(!(psmOb = ObStrMap_New(0))) { goto fail; } - if(!VmmMap_GetUser(&pObMapSrc)) { goto fail; } + if(!(psmOb = ObStrMap_New(H, 0))) { goto fail; } + if(!VmmMap_GetUser(H, &pObMapSrc)) { goto fail; } for(i = 0; i < pObMapSrc->cMap; i++) { peSrc = pObMapSrc->pMap + i; ObStrMap_PushU(psmOb, peSrc->szSID); ObStrMap_PushU(psmOb, peSrc->uszText); } - // 2: byte count: + // 2: byte count & alloc: if(!ObStrMap_FinalizeBufferXUW(psmOb, 0, NULL, &cbDstStr, fWideChar)) { goto fail; } cbDstData = pObMapSrc->cMap * sizeof(VMMDLL_MAP_USERENTRY); cbDst = sizeof(VMMDLL_MAP_USER) + cbDstData + cbDstStr; + if(!(pMapDst = VmmDllCore_MemAllocExternal(H, OB_TAG_API_MAP_USER, cbDst, sizeof(VMMDLL_MAP_USER)))) { goto fail; } // VMMDLL_MemFree() // 3: fill map [if required]: - if(pMapDst) { - if(*pcbMapDst < cbDst) { goto fail; } - ZeroMemory(pMapDst, cbDst); - pMapDst->dwVersion = VMMDLL_MAP_USER_VERSION; - pMapDst->cMap = pObMapSrc->cMap; + pMapDst->dwVersion = VMMDLL_MAP_USER_VERSION; + pMapDst->cMap = pObMapSrc->cMap; + for(i = 0; i < pMapDst->cMap; i++) { + peDst = pMapDst->pMap + i; + peDst->vaRegHive = pObMapSrc->pMap[i].vaRegHive; + // strmap below: for(i = 0; i < pMapDst->cMap; i++) { + peSrc = pObMapSrc->pMap + i; peDst = pMapDst->pMap + i; - peDst->vaRegHive = pObMapSrc->pMap[i].vaRegHive; - // strmap below: - for(i = 0; i < pMapDst->cMap; i++) { - peSrc = pObMapSrc->pMap + i; - peDst = pMapDst->pMap + i; - f = ObStrMap_PushPtrUXUW(psmOb, peSrc->uszText, &peDst->uszText, NULL, fWideChar) && - ObStrMap_PushPtrUXUW(psmOb, peSrc->szSID, &peDst->uszSID, NULL, fWideChar); - if(!f) { goto fail; } - } + f = ObStrMap_PushPtrUXUW(psmOb, peSrc->uszText, &peDst->uszText, NULL, fWideChar) && + ObStrMap_PushPtrUXUW(psmOb, peSrc->szSID, &peDst->uszSID, NULL, fWideChar); + if(!f) { goto fail; } } - pMapDst->pbMultiText = ((PBYTE)pMapDst->pMap) + cbDstData; - ObStrMap_FinalizeBufferXUW(psmOb, cbDstStr, pMapDst->pbMultiText, &pMapDst->cbMultiText, fWideChar); } - fResult = TRUE; + pMapDst->pbMultiText = ((PBYTE)pMapDst->pMap) + cbDstData; + ObStrMap_FinalizeBufferXUW(psmOb, cbDstStr, pMapDst->pbMultiText, &pMapDst->cbMultiText, fWideChar); + *ppMapDst = pMapDst; fail: - *pcbMapDst = cbDst; + if(pMapDst && !*ppMapDst) { VMMDLL_MemFree(pMapDst); pMapDst = NULL; } Ob_DECREF(pObMapSrc); Ob_DECREF(psmOb); - return fResult; + return *ppMapDst ? TRUE : FALSE; } -_Success_(return) BOOL VMMDLL_Map_GetUsersU(_Out_writes_bytes_opt_(*pcbUserMap) PVMMDLL_MAP_USER pUserMap, _Inout_ PDWORD pcbUserMap) +_Success_(return) BOOL VMMDLL_Map_GetUsersU(_In_ VMM_HANDLE H, _Out_ PVMMDLL_MAP_USER *ppUserMap) { - CALL_IMPLEMENTATION_VMM(STATISTICS_ID_VMMDLL_Map_GetUsers, VMMDLL_Map_GetUsers_Impl(pUserMap, pcbUserMap, FALSE)) + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_Map_GetUsers, VMMDLL_Map_GetUsers_Impl(H, ppUserMap, FALSE)) } -_Success_(return) BOOL VMMDLL_Map_GetUsersW(_Out_writes_bytes_opt_(*pcbUserMap) PVMMDLL_MAP_USER pUserMap, _Inout_ PDWORD pcbUserMap) +_Success_(return) BOOL VMMDLL_Map_GetUsersW(_In_ VMM_HANDLE H, _Out_ PVMMDLL_MAP_USER *ppUserMap) { - CALL_IMPLEMENTATION_VMM(STATISTICS_ID_VMMDLL_Map_GetUsers, VMMDLL_Map_GetUsers_Impl(pUserMap, pcbUserMap, TRUE)) + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_Map_GetUsers, VMMDLL_Map_GetUsers_Impl(H, ppUserMap, TRUE)) } _Success_(return) -BOOL VMMDLL_Map_GetServices_Impl(_Out_writes_bytes_opt_(*pcbMapDst) PVMMDLL_MAP_SERVICE pMapDst, _Inout_ PDWORD pcbMapDst, _In_ BOOL fWideChar) +BOOL VMMDLL_Map_GetServices_Impl(_In_ VMM_HANDLE H, _Out_ PVMMDLL_MAP_SERVICE *ppMapDst, _In_ BOOL fWideChar) { BOOL f, fResult = FALSE; DWORD i, cbDst = 0, cbDstData, cbDstStr; PVMMDLL_MAP_SERVICEENTRY peDst; PVMM_MAP_SERVICEENTRY peSrc; PVMMOB_MAP_SERVICE pObMapSrc = NULL; + PVMMDLL_MAP_SERVICE pMapDst = NULL; POB_STRMAP psmOb = NULL; + *ppMapDst = NULL; // 0: sanity check: if(sizeof(VMM_MAP_SERVICEENTRY) != sizeof(VMMDLL_MAP_SERVICEENTRY)) { goto fail; } // 1: fetch map [and populate strings]: - if(!(psmOb = ObStrMap_New(0))) { goto fail; } - if(!VmmMap_GetService(&pObMapSrc)) { goto fail; } + if(!(psmOb = ObStrMap_New(H, 0))) { goto fail; } + if(!VmmMap_GetService(H, &pObMapSrc)) { goto fail; } for(i = 0; i < pObMapSrc->cMap; i++) { peSrc = pObMapSrc->pMap + i; ObStrMap_PushU(psmOb, peSrc->uszServiceName); @@ -2027,52 +1735,49 @@ BOOL VMMDLL_Map_GetServices_Impl(_Out_writes_bytes_opt_(*pcbMapDst) PVMMDLL_MAP_ ObStrMap_PushU(psmOb, peSrc->uszUserAcct); ObStrMap_PushU(psmOb, peSrc->uszImagePath); } - // 2: byte count: + // 2: byte count & alloc: if(!ObStrMap_FinalizeBufferXUW(psmOb, 0, NULL, &cbDstStr, fWideChar)) { goto fail; } cbDstData = pObMapSrc->cMap * sizeof(VMMDLL_MAP_SERVICEENTRY); cbDst = sizeof(VMMDLL_MAP_SERVICE) + cbDstData + cbDstStr; - // 3: fill map [if required]: - if(pMapDst) { - if(*pcbMapDst < cbDst) { goto fail; } - ZeroMemory(pMapDst, sizeof(VMMDLL_MAP_SERVICE)); - pMapDst->dwVersion = VMMDLL_MAP_SERVICE_VERSION; - pMapDst->cMap = pObMapSrc->cMap; - memcpy(pMapDst->pMap, pObMapSrc->pMap, cbDstData); - // strmap below: - for(i = 0; i < pMapDst->cMap; i++) { - peSrc = pObMapSrc->pMap + i; - peDst = pMapDst->pMap + i; - f = ObStrMap_PushPtrUXUW(psmOb, peSrc->uszServiceName, &peDst->uszServiceName, NULL, fWideChar) && - ObStrMap_PushPtrUXUW(psmOb, peSrc->uszDisplayName, &peDst->uszDisplayName, NULL, fWideChar) && - ObStrMap_PushPtrUXUW(psmOb, peSrc->uszPath, &peDst->uszPath, NULL, fWideChar) && - ObStrMap_PushPtrUXUW(psmOb, peSrc->uszUserTp, &peDst->uszUserTp, NULL, fWideChar) && - ObStrMap_PushPtrUXUW(psmOb, peSrc->uszUserAcct, &peDst->uszUserAcct, NULL, fWideChar) && - ObStrMap_PushPtrUXUW(psmOb, peSrc->uszImagePath, &peDst->uszImagePath, NULL, fWideChar); - if(!f) { goto fail; } - } - pMapDst->pbMultiText = ((PBYTE)pMapDst->pMap) + cbDstData; - ObStrMap_FinalizeBufferXUW(psmOb, cbDstStr, pMapDst->pbMultiText, &pMapDst->cbMultiText, fWideChar); + if(!(pMapDst = VmmDllCore_MemAllocExternal(H, OB_TAG_API_MAP_SERVICES, cbDst, sizeof(VMMDLL_MAP_SERVICE)))) { goto fail; } // VMMDLL_MemFree() + // 3: fill map: + pMapDst->dwVersion = VMMDLL_MAP_SERVICE_VERSION; + pMapDst->cMap = pObMapSrc->cMap; + memcpy(pMapDst->pMap, pObMapSrc->pMap, cbDstData); + // strmap below: + for(i = 0; i < pMapDst->cMap; i++) { + peSrc = pObMapSrc->pMap + i; + peDst = pMapDst->pMap + i; + f = ObStrMap_PushPtrUXUW(psmOb, peSrc->uszServiceName, &peDst->uszServiceName, NULL, fWideChar) && + ObStrMap_PushPtrUXUW(psmOb, peSrc->uszDisplayName, &peDst->uszDisplayName, NULL, fWideChar) && + ObStrMap_PushPtrUXUW(psmOb, peSrc->uszPath, &peDst->uszPath, NULL, fWideChar) && + ObStrMap_PushPtrUXUW(psmOb, peSrc->uszUserTp, &peDst->uszUserTp, NULL, fWideChar) && + ObStrMap_PushPtrUXUW(psmOb, peSrc->uszUserAcct, &peDst->uszUserAcct, NULL, fWideChar) && + ObStrMap_PushPtrUXUW(psmOb, peSrc->uszImagePath, &peDst->uszImagePath, NULL, fWideChar); + if(!f) { goto fail; } } - fResult = TRUE; + pMapDst->pbMultiText = ((PBYTE)pMapDst->pMap) + cbDstData; + ObStrMap_FinalizeBufferXUW(psmOb, cbDstStr, pMapDst->pbMultiText, &pMapDst->cbMultiText, fWideChar); + *ppMapDst = pMapDst; fail: - *pcbMapDst = (DWORD)cbDst; + if(pMapDst && !*ppMapDst) { VMMDLL_MemFree(pMapDst); pMapDst = NULL; } Ob_DECREF(pObMapSrc); Ob_DECREF(psmOb); - return fResult; + return *ppMapDst ? TRUE : FALSE; } -_Success_(return) BOOL VMMDLL_Map_GetServicesU(_Out_writes_bytes_opt_(*pcbServiceMap) PVMMDLL_MAP_SERVICE pServiceMap, _Inout_ PDWORD pcbServiceMap) +_Success_(return) BOOL VMMDLL_Map_GetServicesU(_In_ VMM_HANDLE H, _Out_ PVMMDLL_MAP_SERVICE *ppServiceMap) { - CALL_IMPLEMENTATION_VMM(STATISTICS_ID_VMMDLL_Map_GetServices, VMMDLL_Map_GetServices_Impl(pServiceMap, pcbServiceMap, FALSE)) + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_Map_GetServices, VMMDLL_Map_GetServices_Impl(H, ppServiceMap, FALSE)) } -_Success_(return) BOOL VMMDLL_Map_GetServicesW(_Out_writes_bytes_opt_(*pcbServiceMap) PVMMDLL_MAP_SERVICE pServiceMap, _Inout_ PDWORD pcbServiceMap) +_Success_(return) BOOL VMMDLL_Map_GetServicesW(_In_ VMM_HANDLE H, _Out_ PVMMDLL_MAP_SERVICE *ppServiceMap) { - CALL_IMPLEMENTATION_VMM(STATISTICS_ID_VMMDLL_Map_GetServices, VMMDLL_Map_GetServices_Impl(pServiceMap, pcbServiceMap, TRUE)) + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_Map_GetServices, VMMDLL_Map_GetServices_Impl(H, ppServiceMap, TRUE)) } _Success_(return) -BOOL VMMDLL_Map_GetPfn_Impl(_In_ DWORD pPfns[], _In_ DWORD cPfns, _Out_writes_bytes_opt_(*pcbMapDst) PVMMDLL_MAP_PFN pMapDst, _Inout_ PDWORD pcbMapDst) +BOOL VMMDLL_Map_GetPfn_Impl(_In_ VMM_HANDLE H, _In_ DWORD pPfns[], _In_ DWORD cPfns, _Out_writes_bytes_opt_(*pcbMapDst) PVMMDLL_MAP_PFN pMapDst, _Inout_ PDWORD pcbMapDst) { BOOL fResult = FALSE; POB_SET psObPfns = NULL; @@ -2082,11 +1787,11 @@ BOOL VMMDLL_Map_GetPfn_Impl(_In_ DWORD pPfns[], _In_ DWORD cPfns, _Out_writes_by cbDst = sizeof(VMMDLL_MAP_PFN) + cbDstData; if(pMapDst) { if(*pcbMapDst < cbDst) { goto fail; } - if(!(psObPfns = ObSet_New())) { goto fail; } + if(!(psObPfns = ObSet_New(H))) { goto fail; } for(i = 0; i < cPfns; i++) { ObSet_Push(psObPfns, pPfns[i]); } - if(!MmPfn_Map_GetPfnScatter(psObPfns, &pObMapSrc, TRUE)) { goto fail; } + if(!MmPfn_Map_GetPfnScatter(H, psObPfns, &pObMapSrc, TRUE)) { goto fail; } ZeroMemory(pMapDst, cbDst); pMapDst->dwVersion = VMMDLL_MAP_PFN_VERSION; pMapDst->cMap = pObMapSrc->cMap; @@ -2103,34 +1808,32 @@ fail: } _Success_(return) -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_GetPfn(_In_ VMM_HANDLE H, _In_ DWORD pPfns[], _In_ DWORD cPfns, _Out_writes_bytes_opt_(*pcbPfnMap) PVMMDLL_MAP_PFN pPfnMap, _Inout_ PDWORD pcbPfnMap) { - CALL_IMPLEMENTATION_VMM( + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_Map_GetPfn, - VMMDLL_Map_GetPfn_Impl(pPfns, cPfns, pPfnMap, pcbPfnMap)) + VMMDLL_Map_GetPfn_Impl(H, pPfns, cPfns, pPfnMap, pcbPfnMap)) } _Success_(return) -BOOL VMMDLL_PidList_Impl(_Out_writes_opt_(*pcPIDs) PDWORD pPIDs, _Inout_ PULONG64 pcPIDs) +BOOL VMMDLL_PidList_Impl(_In_ VMM_HANDLE H, _Out_writes_opt_(*pcPIDs) PDWORD pPIDs, _Inout_ PSIZE_T pcPIDs) { - VmmProcessListPIDs(pPIDs, (PSIZE_T)pcPIDs, 0); + VmmProcessListPIDs(H, pPIDs, pcPIDs, 0); return (*pcPIDs ? TRUE : FALSE); } _Success_(return) -BOOL VMMDLL_PidList(_Out_writes_opt_(*pcPIDs) PDWORD pPIDs, _Inout_ PULONG64 pcPIDs) +BOOL VMMDLL_PidList(_In_ VMM_HANDLE H, _Out_writes_opt_(*pcPIDs) PDWORD pPIDs, _Inout_ PSIZE_T pcPIDs) { - CALL_IMPLEMENTATION_VMM( - STATISTICS_ID_VMMDLL_PidList, - VMMDLL_PidList_Impl(pPIDs, pcPIDs)) + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_PidList, VMMDLL_PidList_Impl(H, pPIDs, pcPIDs)) } _Success_(return) -BOOL VMMDLL_PidGetFromName_Impl(_In_ LPSTR szProcName, _Out_ PDWORD pdwPID) +BOOL VMMDLL_PidGetFromName_Impl(_In_ VMM_HANDLE H, _In_ LPSTR szProcName, _Out_ PDWORD pdwPID) { PVMM_PROCESS pObProcess = NULL; // 1: try locate process using long (full) name - while((pObProcess = VmmProcessGetNext(pObProcess, 0))) { + while((pObProcess = VmmProcessGetNext(H, pObProcess, 0))) { if(pObProcess->dwState) { continue; } if(!pObProcess->pObPersistent->uszNameLong || _stricmp(szProcName, pObProcess->pObPersistent->uszNameLong)) { continue; } *pdwPID = pObProcess->dwPID; @@ -2138,7 +1841,7 @@ BOOL VMMDLL_PidGetFromName_Impl(_In_ LPSTR szProcName, _Out_ PDWORD pdwPID) return TRUE; } // 2: try locate process using short (eprocess) name - while((pObProcess = VmmProcessGetNext(pObProcess, 0))) { + while((pObProcess = VmmProcessGetNext(H, pObProcess, 0))) { if(pObProcess->dwState) { continue; } if(_strnicmp(szProcName, pObProcess->szName, 15)) { continue; } *pdwPID = pObProcess->dwPID; @@ -2149,15 +1852,16 @@ BOOL VMMDLL_PidGetFromName_Impl(_In_ LPSTR szProcName, _Out_ PDWORD pdwPID) } _Success_(return) -BOOL VMMDLL_PidGetFromName(_In_ LPSTR szProcName, _Out_ PDWORD pdwPID) +BOOL VMMDLL_PidGetFromName(_In_ VMM_HANDLE H, _In_ LPSTR szProcName, _Out_ PDWORD pdwPID) { CALL_IMPLEMENTATION_VMM( + H, STATISTICS_ID_VMMDLL_PidGetFromName, - VMMDLL_PidGetFromName_Impl(szProcName, pdwPID)) + VMMDLL_PidGetFromName_Impl(H, szProcName, pdwPID)) } _Success_(return) -BOOL VMMDLL_ProcessGetInformation_Impl(_In_ DWORD dwPID, _Inout_opt_ PVMMDLL_PROCESS_INFORMATION pInfo, _In_ PSIZE_T pcbProcessInfo) +BOOL VMMDLL_ProcessGetInformation_Impl(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _Inout_opt_ PVMMDLL_PROCESS_INFORMATION pInfo, _In_ PSIZE_T pcbProcessInfo) { PVMM_PROCESS pObProcess = NULL; if(!pcbProcessInfo) { return FALSE; } @@ -2168,14 +1872,14 @@ BOOL VMMDLL_ProcessGetInformation_Impl(_In_ DWORD dwPID, _Inout_opt_ PVMMDLL_PRO if(*pcbProcessInfo < sizeof(VMMDLL_PROCESS_INFORMATION)) { return FALSE; } if(pInfo->magic != VMMDLL_PROCESS_INFORMATION_MAGIC) { return FALSE; } if(pInfo->wVersion != VMMDLL_PROCESS_INFORMATION_VERSION) { return FALSE; } - if(!(pObProcess = VmmProcessGetEx(NULL, dwPID, VMM_FLAG_PROCESS_TOKEN))) { return FALSE; } + if(!(pObProcess = VmmProcessGetEx(H, NULL, dwPID, VMM_FLAG_PROCESS_TOKEN))) { return FALSE; } ZeroMemory(pInfo, sizeof(VMMDLL_PROCESS_INFORMATION_MAGIC)); // set general parameters pInfo->magic = VMMDLL_PROCESS_INFORMATION_MAGIC; pInfo->wVersion = VMMDLL_PROCESS_INFORMATION_VERSION; pInfo->wSize = sizeof(VMMDLL_PROCESS_INFORMATION); - pInfo->tpMemoryModel = ctxVmm->tpMemoryModel; - pInfo->tpSystem = ctxVmm->tpSystem; + pInfo->tpMemoryModel = H->vmm.tpMemoryModel; + pInfo->tpSystem = H->vmm.tpSystem; pInfo->fUserOnly = pObProcess->fUserOnly; pInfo->dwPID = dwPID; pInfo->dwPPID = pObProcess->dwPPID; @@ -2185,8 +1889,8 @@ BOOL VMMDLL_ProcessGetInformation_Impl(_In_ DWORD dwPID, _Inout_opt_ PVMMDLL_PRO memcpy(pInfo->szName, pObProcess->szName, sizeof(pInfo->szName)); strncpy_s(pInfo->szNameLong, sizeof(pInfo->szNameLong), pObProcess->pObPersistent->uszNameLong, _TRUNCATE); // set operating system specific parameters - if((ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X64) || (ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X86)) { - if(ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X64) { + if((H->vmm.tpSystem == VMM_SYSTEM_WINDOWS_X64) || (H->vmm.tpSystem == VMM_SYSTEM_WINDOWS_X86)) { + if(H->vmm.tpSystem == VMM_SYSTEM_WINDOWS_X64) { pInfo->win.fWow64 = pObProcess->win.fWow64; pInfo->win.vaPEB32 = pObProcess->win.vaPEB32; } @@ -2204,33 +1908,33 @@ BOOL VMMDLL_ProcessGetInformation_Impl(_In_ DWORD dwPID, _Inout_opt_ PVMMDLL_PRO } _Success_(return) -BOOL VMMDLL_ProcessGetInformation(_In_ DWORD dwPID, _Inout_opt_ PVMMDLL_PROCESS_INFORMATION pProcessInformation, _In_ PSIZE_T pcbProcessInformation) +BOOL VMMDLL_ProcessGetInformation(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _Inout_opt_ PVMMDLL_PROCESS_INFORMATION pProcessInformation, _In_ PSIZE_T pcbProcessInformation) { - CALL_IMPLEMENTATION_VMM( - STATISTICS_ID_VMMDLL_ProcessGetInformation, - VMMDLL_ProcessGetInformation_Impl(dwPID, pProcessInformation, pcbProcessInformation)) + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_ProcessGetInformation, VMMDLL_ProcessGetInformation_Impl(H, dwPID, pProcessInformation, pcbProcessInformation)) } -BOOL VMMDLL_ProcessGetInformationString_Impl_CallbackCriteria(_In_ PVMM_PROCESS pProcess, _In_ PVOID ctx) +BOOL VMMDLL_ProcessGetInformationString_Impl_CallbackCriteria(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVOID ctx) { return !pProcess->pObPersistent->UserProcessParams.fProcessed; } -VOID VMMDLL_ProcessGetInformationString_Impl_CallbackAction(_In_ PVMM_PROCESS pProcess, _In_ PVOID ctx) +VOID VMMDLL_ProcessGetInformationString_Impl_CallbackAction(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVOID ctx) { - VmmWin_UserProcessParameters_Get(pProcess); + VmmWin_UserProcessParameters_Get(H, pProcess); } -LPSTR VMMDLL_ProcessGetInformationString_Impl(_In_ DWORD dwPID, _In_ DWORD fOptionString) +_Success_(return != NULL) +LPSTR VMMDLL_ProcessGetInformationString_Impl(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ DWORD fOptionString) { + SIZE_T csz; LPSTR sz = NULL, szStrDup = NULL; PVMM_PROCESS pObProcess = NULL; - if(!(pObProcess = VmmProcessGet(dwPID))) { return FALSE; } + if(!(pObProcess = VmmProcessGet(H, dwPID))) { return FALSE; } switch(fOptionString) { case VMMDLL_PROCESS_INFORMATION_OPT_STRING_PATH_USER_IMAGE: case VMMDLL_PROCESS_INFORMATION_OPT_STRING_CMDLINE: if(!pObProcess->pObPersistent->UserProcessParams.fProcessed) { - VmmProcessActionForeachParallel(NULL, VMMDLL_ProcessGetInformationString_Impl_CallbackCriteria, VMMDLL_ProcessGetInformationString_Impl_CallbackAction); + VmmWork_ProcessActionForeachParallel_Void(H, 0, NULL, VMMDLL_ProcessGetInformationString_Impl_CallbackCriteria, VMMDLL_ProcessGetInformationString_Impl_CallbackAction); } } switch(fOptionString) { @@ -2244,130 +1948,131 @@ LPSTR VMMDLL_ProcessGetInformationString_Impl(_In_ DWORD dwPID, _In_ DWORD fOpti sz = pObProcess->pObPersistent->UserProcessParams.uszCommandLine; break; } - szStrDup = Util_StrDupA(sz); + if(sz) { + csz = strlen(sz); + if((szStrDup = VmmDllCore_MemAllocExternal(H, OB_TAG_API_PROCESS_STRING, csz + 1, 0))) { + strncpy_s(szStrDup, csz + 1, sz, _TRUNCATE); + } + } Ob_DECREF(pObProcess); return szStrDup; } -LPSTR VMMDLL_ProcessGetInformationString(_In_ DWORD dwPID, _In_ DWORD fOptionString) +_Success_(return != NULL) +LPSTR VMMDLL_ProcessGetInformationString(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ DWORD fOptionString) { CALL_IMPLEMENTATION_VMM_RETURN( + H, STATISTICS_ID_VMMDLL_ProcessGetInformationString, LPSTR, NULL, - VMMDLL_ProcessGetInformationString_Impl(dwPID, fOptionString)) + VMMDLL_ProcessGetInformationString_Impl(H, dwPID, fOptionString)) } _Success_(return) -BOOL VMMDLL_ProcessGet_Directories_Sections_Impl( - _In_ DWORD dwPID, - _In_ LPSTR uszModule, - _In_ DWORD cData, - _Out_ PDWORD pcData, - _Out_writes_opt_(16) PIMAGE_DATA_DIRECTORY pDataDirectory, - _Out_opt_ PIMAGE_SECTION_HEADER pSections, - BOOL _In_ fDataDirectory, - BOOL _In_ fSections -) +BOOL VMMDLL_ProcessGet_Sections_Impl(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ LPSTR uszModule, _Out_writes_opt_(cSections) PIMAGE_SECTION_HEADER pSections, _In_ DWORD cSections, _Out_ PDWORD pcSections) { - DWORD i; + BOOL fResult = FALSE; PVMMOB_MAP_MODULE pObModuleMap = NULL; PVMM_MAP_MODULEENTRY pModule = NULL; PVMM_PROCESS pObProcess = NULL; - if(!(pObProcess = VmmProcessGet(dwPID))) { goto fail; } - // fetch requested module - if(!VmmMap_GetModuleEntryEx(pObProcess, 0, uszModule, &pObModuleMap, &pModule)) { goto fail; } - // data directories - if(fDataDirectory) { - if(!pDataDirectory) { *pcData = IMAGE_NUMBEROF_DIRECTORY_ENTRIES; goto success; } - if(cData < 16) { goto fail; } - if(!PE_DirectoryGetAll(pObProcess, pModule->vaBase, NULL, pDataDirectory)) { goto fail; } - *pcData = 16; - goto success; - } - // sections - if(fSections) { - i = PE_SectionGetNumberOf(pObProcess, pModule->vaBase); - if(!pSections) { *pcData = i; goto success; } - if(cData < i) { goto fail; } - if(!PE_SectionGetAll(pObProcess, pModule->vaBase, i, pSections)) { goto fail; } - *pcData = cData; - goto success; + if(!(pObProcess = VmmProcessGet(H, dwPID))) { goto fail; } + if(!VmmMap_GetModuleEntryEx(H, pObProcess, 0, uszModule, &pObModuleMap, &pModule)) { goto fail; } + *pcSections = PE_SectionGetNumberOf(H, pObProcess, pModule->vaBase); + if(pSections) { + if(cSections != *pcSections) { goto fail; } + if(!PE_SectionGetAll(H, pObProcess, pModule->vaBase, cSections, pSections)) { goto fail; } } + fResult = TRUE; fail: Ob_DECREF(pObModuleMap); Ob_DECREF(pObProcess); - return FALSE; -success: + return fResult; +} + +_Success_(return) +BOOL VMMDLL_ProcessGet_Directories_Impl(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ LPSTR uszModule, _Out_writes_(16) PIMAGE_DATA_DIRECTORY pDataDirectories) +{ + BOOL fResult = FALSE; + PVMMOB_MAP_MODULE pObModuleMap = NULL; + PVMM_MAP_MODULEENTRY pModule = NULL; + PVMM_PROCESS pObProcess = NULL; + if(!(pObProcess = VmmProcessGet(H, dwPID))) { goto fail; } + // fetch requested module + if(!VmmMap_GetModuleEntryEx(H, pObProcess, 0, uszModule, &pObModuleMap, &pModule)) { goto fail; } + // data directories + if(!PE_DirectoryGetAll(H, pObProcess, pModule->vaBase, NULL, pDataDirectories)) { goto fail; } + fResult = TRUE; +fail: Ob_DECREF(pObModuleMap); Ob_DECREF(pObProcess); - return TRUE; + return fResult; } _Success_(return) -BOOL VMMDLL_ProcessGetDirectoriesU(_In_ DWORD dwPID, _In_ LPSTR uszModule, _Out_writes_(16) PIMAGE_DATA_DIRECTORY pData, _In_ DWORD cData, _Out_ PDWORD pcData) +BOOL VMMDLL_ProcessGetDirectoriesU(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ LPSTR uszModule, _Out_writes_(16) PIMAGE_DATA_DIRECTORY pDataDirectories) { - CALL_IMPLEMENTATION_VMM( - STATISTICS_ID_VMMDLL_ProcessGetDirectories, - VMMDLL_ProcessGet_Directories_Sections_Impl(dwPID, uszModule, cData, pcData, pData, NULL, TRUE, FALSE)) + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_ProcessGetDirectories, VMMDLL_ProcessGet_Directories_Impl(H, dwPID, uszModule, pDataDirectories)) } _Success_(return) -BOOL VMMDLL_ProcessGetDirectoriesW(_In_ DWORD dwPID, _In_ LPWSTR wszModule, _Out_writes_(16) PIMAGE_DATA_DIRECTORY pData, _In_ DWORD cData, _Out_ PDWORD pcData) +BOOL VMMDLL_ProcessGetDirectoriesW(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ LPWSTR wszModule, _Out_writes_(16) PIMAGE_DATA_DIRECTORY pDataDirectories) { LPSTR uszModule; BYTE pbBuffer[MAX_PATH]; if(!CharUtil_WtoU(wszModule, -1, pbBuffer, sizeof(pbBuffer), &uszModule, NULL, 0)) { return FALSE; } - return VMMDLL_ProcessGetDirectoriesU(dwPID, uszModule, pData, cData, pcData); + return VMMDLL_ProcessGetDirectoriesU(H, dwPID, uszModule, pDataDirectories); } _Success_(return) -BOOL VMMDLL_ProcessGetSectionsU(_In_ DWORD dwPID, _In_ LPSTR uszModule, _Out_opt_ PIMAGE_SECTION_HEADER pData, _In_ DWORD cData, _Out_ PDWORD pcData) +BOOL VMMDLL_ProcessGetSectionsU(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ LPSTR uszModule, _Out_writes_opt_(cSections) PIMAGE_SECTION_HEADER pSections, _In_ DWORD cSections, _Out_ PDWORD pcSections) { CALL_IMPLEMENTATION_VMM( + H, STATISTICS_ID_VMMDLL_ProcessGetSections, - VMMDLL_ProcessGet_Directories_Sections_Impl(dwPID, uszModule, cData, pcData, NULL, pData, FALSE, TRUE)) + VMMDLL_ProcessGet_Sections_Impl(H, dwPID, uszModule, pSections, cSections, pcSections)) } _Success_(return) -BOOL VMMDLL_ProcessGetSectionsW(_In_ DWORD dwPID, _In_ LPWSTR wszModule, _Out_opt_ PIMAGE_SECTION_HEADER pData, _In_ DWORD cData, _Out_ PDWORD pcData) +BOOL VMMDLL_ProcessGetSectionsW(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ LPWSTR wszModule, _Out_writes_opt_(cSections) PIMAGE_SECTION_HEADER pSections, _In_ DWORD cSections, _Out_ PDWORD pcSections) { LPSTR uszModule; BYTE pbBuffer[MAX_PATH]; if(!CharUtil_WtoU(wszModule, -1, pbBuffer, sizeof(pbBuffer), &uszModule, NULL, 0)) { return FALSE; } - return VMMDLL_ProcessGetSectionsU(dwPID, uszModule, pData, cData, pcData); + return VMMDLL_ProcessGetSectionsU(H, dwPID, uszModule, pSections, cSections, pcSections); } -ULONG64 VMMDLL_ProcessGetModuleBase_Impl(_In_ DWORD dwPID, _In_ LPSTR uszModuleName) +ULONG64 VMMDLL_ProcessGetModuleBase_Impl(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ LPSTR uszModuleName) { QWORD vaModuleBase = 0; PVMM_MAP_MODULEENTRY peModule; PVMMOB_MAP_MODULE pObModuleMap = NULL; - if(VmmMap_GetModuleEntryEx(NULL, dwPID, uszModuleName, &pObModuleMap, &peModule)) { + if(VmmMap_GetModuleEntryEx(H, NULL, dwPID, uszModuleName, &pObModuleMap, &peModule)) { vaModuleBase = peModule->vaBase; Ob_DECREF(pObModuleMap); } return vaModuleBase; } -ULONG64 VMMDLL_ProcessGetModuleBaseU(_In_ DWORD dwPID, _In_ LPSTR uszModuleName) +ULONG64 VMMDLL_ProcessGetModuleBaseU(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ LPSTR uszModuleName) { CALL_IMPLEMENTATION_VMM_RETURN( + H, STATISTICS_ID_VMMDLL_ProcessGetModuleBase, ULONG64, 0, - VMMDLL_ProcessGetModuleBase_Impl(dwPID, uszModuleName)) + VMMDLL_ProcessGetModuleBase_Impl(H, dwPID, uszModuleName)) } -ULONG64 VMMDLL_ProcessGetModuleBaseW(_In_ DWORD dwPID, _In_ LPWSTR wszModuleName) +ULONG64 VMMDLL_ProcessGetModuleBaseW(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ LPWSTR wszModuleName) { LPSTR uszModuleName; BYTE pbBuffer[MAX_PATH]; if(!CharUtil_WtoU(wszModuleName, -1, pbBuffer, sizeof(pbBuffer), &uszModuleName, NULL, 0)) { return FALSE; } - return VMMDLL_ProcessGetModuleBaseU(dwPID, uszModuleName); + return VMMDLL_ProcessGetModuleBaseU(H, dwPID, uszModuleName); } -ULONG64 VMMDLL_ProcessGetProcAddress_Impl(_In_ DWORD dwPID, _In_ LPSTR uszModuleName, _In_ LPSTR szFunctionName) +ULONG64 VMMDLL_ProcessGetProcAddress_Impl(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ LPSTR uszModuleName, _In_ LPSTR szFunctionName) { PVMM_PROCESS pObProcess = NULL; PVMMOB_MAP_EAT pObEatMap = NULL; @@ -2375,10 +2080,10 @@ ULONG64 VMMDLL_ProcessGetProcAddress_Impl(_In_ DWORD dwPID, _In_ LPSTR uszModule PVMM_MAP_MODULEENTRY peModule; QWORD va = 0; DWORD i; - if(!(pObProcess = VmmProcessGet(dwPID))) { goto fail; } - if(!VmmMap_GetModuleEntryEx(NULL, dwPID, uszModuleName, &pObModuleMap, &peModule)) { goto fail; } - if(!VmmMap_GetEAT(pObProcess, peModule, &pObEatMap)) { goto fail; } - if(!VmmMap_GetEATEntryIndexU(pObEatMap, szFunctionName, &i)) { goto fail; } + if(!(pObProcess = VmmProcessGet(H, dwPID))) { goto fail; } + if(!VmmMap_GetModuleEntryEx(H, NULL, dwPID, uszModuleName, &pObModuleMap, &peModule)) { goto fail; } + if(!VmmMap_GetEAT(H, pObProcess, peModule, &pObEatMap)) { goto fail; } + if(!VmmMap_GetEATEntryIndexU(H, pObEatMap, szFunctionName, &i)) { goto fail; } va = pObEatMap->pMap[i].vaFunction; fail: Ob_DECREF(pObEatMap); @@ -2387,21 +2092,22 @@ fail: return va; } -ULONG64 VMMDLL_ProcessGetProcAddressU(_In_ DWORD dwPID, _In_ LPSTR uszModuleName, _In_ LPSTR szFunctionName) +ULONG64 VMMDLL_ProcessGetProcAddressU(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ LPSTR uszModuleName, _In_ LPSTR szFunctionName) { CALL_IMPLEMENTATION_VMM_RETURN( + H, STATISTICS_ID_VMMDLL_ProcessGetProcAddress, ULONG64, 0, - VMMDLL_ProcessGetProcAddress_Impl(dwPID, uszModuleName, szFunctionName)) + VMMDLL_ProcessGetProcAddress_Impl(H, dwPID, uszModuleName, szFunctionName)) } -ULONG64 VMMDLL_ProcessGetProcAddressW(_In_ DWORD dwPID, _In_ LPWSTR wszModuleName, _In_ LPSTR szFunctionName) +ULONG64 VMMDLL_ProcessGetProcAddressW(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ LPWSTR wszModuleName, _In_ LPSTR szFunctionName) { LPSTR uszModuleName; BYTE pbBuffer[MAX_PATH]; if(!CharUtil_WtoU(wszModuleName, -1, pbBuffer, sizeof(pbBuffer), &uszModuleName, NULL, 0)) { return FALSE; } - return VMMDLL_ProcessGetProcAddressU(dwPID, uszModuleName, szFunctionName); + return VMMDLL_ProcessGetProcAddressU(H, dwPID, uszModuleName, szFunctionName); } @@ -2410,25 +2116,34 @@ ULONG64 VMMDLL_ProcessGetProcAddressW(_In_ DWORD dwPID, _In_ LPWSTR wszModuleNam // LOGGING FUNCTIONALITY BELOW: //----------------------------------------------------------------------------- -VOID VMMDLL_LogEx(_In_opt_ VMMDLL_MODULE_ID MID, _In_ VMMDLL_LOGLEVEL dwLogLevel, _In_z_ _Printf_format_string_ LPSTR uszFormat, va_list arglist) +_Success_(return) +BOOL VMMDLL_LogEx2_Impl(_In_ VMM_HANDLE H, _In_opt_ VMMDLL_MODULE_ID MID, _In_ VMMDLL_LOGLEVEL dwLogLevel, _In_z_ _Printf_format_string_ LPSTR uszFormat, va_list arglist) { - QWORD tm; - if(!ctxVmm) { return; } if(MID & 0x80000000) { if((MID < VMMDLL_MID_MAIN) && (MID > VMMDLL_MID_PYTHON)) { - return; + return FALSE; } } - tm = Statistics_CallStart(); - VmmLogEx2((DWORD)MID, dwLogLevel, uszFormat, arglist); - Statistics_CallEnd(STATISTICS_ID_VMMDLL_Log, tm); + VmmLogEx2(H, (DWORD)MID, dwLogLevel, uszFormat, arglist); + return TRUE; } -VOID VMMDLL_Log(_In_opt_ VMMDLL_MODULE_ID MID, _In_ VMMDLL_LOGLEVEL dwLogLevel, _In_z_ _Printf_format_string_ LPSTR uszFormat, ...) +_Success_(return) +BOOL VMMDLL_LogEx2(_In_ VMM_HANDLE H, _In_opt_ VMMDLL_MODULE_ID MID, _In_ VMMDLL_LOGLEVEL dwLogLevel, _In_z_ _Printf_format_string_ LPSTR uszFormat, va_list arglist) +{ + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_Log, VMMDLL_LogEx2_Impl(H, MID, dwLogLevel, uszFormat, arglist)) +} + +VOID VMMDLL_LogEx(_In_ VMM_HANDLE H, _In_opt_ VMMDLL_MODULE_ID MID, _In_ VMMDLL_LOGLEVEL dwLogLevel, _In_z_ _Printf_format_string_ LPSTR uszFormat, va_list arglist) +{ + VMMDLL_LogEx2(H, MID, dwLogLevel, uszFormat, arglist); +} + +VOID VMMDLL_Log(_In_ VMM_HANDLE H, _In_opt_ VMMDLL_MODULE_ID MID, _In_ VMMDLL_LOGLEVEL dwLogLevel, _In_z_ _Printf_format_string_ LPSTR uszFormat, ...) { va_list arglist; va_start(arglist, uszFormat); - VMMDLL_LogEx((DWORD)MID, dwLogLevel, uszFormat, arglist); + VMMDLL_LogEx2(H, MID, dwLogLevel, uszFormat, arglist); va_end(arglist); } @@ -2446,24 +2161,24 @@ VOID VMMDLL_Log(_In_opt_ VMMDLL_MODULE_ID MID, _In_ VMMDLL_LOGLEVEL dwLogLevel, * -- return */ _Success_(return) -BOOL VMMDLL_WinReg_HiveList_Impl(_Out_writes_(cHives) PVMMDLL_REGISTRY_HIVE_INFORMATION pHives, _In_ DWORD cHives, _Out_ PDWORD pcHives) +BOOL VMMDLL_WinReg_HiveList_Impl(_In_ VMM_HANDLE H, _Out_writes_(cHives) PVMMDLL_REGISTRY_HIVE_INFORMATION pHives, _In_ DWORD cHives, _Out_ PDWORD pcHives) { BOOL fResult = TRUE; POB_REGISTRY_HIVE pObHive = NULL; if(!pHives) { - *pcHives = VmmWinReg_HiveCount(); + *pcHives = VmmWinReg_HiveCount(H); goto cleanup; } *pcHives = 0; - while((pObHive = VmmWinReg_HiveGetNext(pObHive))) { + while((pObHive = VmmWinReg_HiveGetNext(H, pObHive))) { if(*pcHives == cHives) { fResult = FALSE; goto cleanup; } - memcpy(pHives + *pcHives, pObHive, sizeof(VMMDLL_REGISTRY_HIVE_INFORMATION)); - pHives->magic = VMMDLL_REGISTRY_HIVE_INFORMATION_MAGIC; - pHives->wVersion = VMMDLL_REGISTRY_HIVE_INFORMATION_VERSION; - pHives->wSize = sizeof(VMMDLL_REGISTRY_HIVE_INFORMATION); + memcpy(pHives + (*pcHives), pObHive, sizeof(VMMDLL_REGISTRY_HIVE_INFORMATION)); + pHives[*pcHives].magic = VMMDLL_REGISTRY_HIVE_INFORMATION_MAGIC; + pHives[*pcHives].wVersion = VMMDLL_REGISTRY_HIVE_INFORMATION_VERSION; + pHives[*pcHives].wSize = sizeof(VMMDLL_REGISTRY_HIVE_INFORMATION); *pcHives += 1; } cleanup: @@ -2472,11 +2187,12 @@ cleanup: } _Success_(return) -BOOL VMMDLL_WinReg_HiveList(_Out_writes_(cHives) PVMMDLL_REGISTRY_HIVE_INFORMATION pHives, _In_ DWORD cHives, _Out_ PDWORD pcHives) +BOOL VMMDLL_WinReg_HiveList(_In_ VMM_HANDLE H, _Out_writes_(cHives) PVMMDLL_REGISTRY_HIVE_INFORMATION pHives, _In_ DWORD cHives, _Out_ PDWORD pcHives) { CALL_IMPLEMENTATION_VMM( + H, STATISTICS_ID_VMMDLL_WinRegHive_List, - VMMDLL_WinReg_HiveList_Impl(pHives, cHives, pcHives)) + VMMDLL_WinReg_HiveList_Impl(H, pHives, cHives, pcHives)) } /* @@ -2491,21 +2207,22 @@ BOOL VMMDLL_WinReg_HiveList(_Out_writes_(cHives) PVMMDLL_REGISTRY_HIVE_INFORMATI * -- flags = flags as in VMMDLL_FLAG_* */ _Success_(return) -BOOL VMMDLL_WinReg_HiveReadEx_Impl(_In_ ULONG64 vaCMHive, _In_ DWORD ra, _Out_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ ULONG64 flags) +BOOL VMMDLL_WinReg_HiveReadEx_Impl(_In_ VMM_HANDLE H, _In_ ULONG64 vaCMHive, _In_ DWORD ra, _Out_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ ULONG64 flags) { - POB_REGISTRY_HIVE pObHive = VmmWinReg_HiveGetByAddress(vaCMHive); + POB_REGISTRY_HIVE pObHive = VmmWinReg_HiveGetByAddress(H, vaCMHive); if(!pObHive) { return FALSE; } - VmmWinReg_HiveReadEx(pObHive, ra, pb, cb, pcbReadOpt, flags); + VmmWinReg_HiveReadEx(H, pObHive, ra, pb, cb, pcbReadOpt, flags); Ob_DECREF(pObHive); return TRUE; } _Success_(return) -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_HiveReadEx(_In_ VMM_HANDLE H, _In_ ULONG64 vaCMHive, _In_ DWORD ra, _Out_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ ULONG64 flags) { CALL_IMPLEMENTATION_VMM( + H, STATISTICS_ID_VMMDLL_WinRegHive_ReadEx, - VMMDLL_WinReg_HiveReadEx_Impl(vaCMHive, ra, pb, cb, pcbReadOpt, flags)) + VMMDLL_WinReg_HiveReadEx_Impl(H, vaCMHive, ra, pb, cb, pcbReadOpt, flags)) } /* @@ -2518,26 +2235,27 @@ BOOL VMMDLL_WinReg_HiveReadEx(_In_ ULONG64 vaCMHive, _In_ DWORD ra, _Out_ PBYTE * -- return = TRUE on success, FALSE on partial or zero write. */ _Success_(return) -BOOL VMMDLL_WinReg_HiveWrite_Impl(_In_ ULONG64 vaCMHive, _In_ DWORD ra, _In_ PBYTE pb, _In_ DWORD cb) +BOOL VMMDLL_WinReg_HiveWrite_Impl(_In_ VMM_HANDLE H, _In_ ULONG64 vaCMHive, _In_ DWORD ra, _In_ PBYTE pb, _In_ DWORD cb) { BOOL f; - POB_REGISTRY_HIVE pObHive = VmmWinReg_HiveGetByAddress(vaCMHive); + POB_REGISTRY_HIVE pObHive = VmmWinReg_HiveGetByAddress(H, vaCMHive); if(!pObHive) { return FALSE; } - f = VmmWinReg_HiveWrite(pObHive, ra, pb, cb); + f = VmmWinReg_HiveWrite(H, pObHive, ra, pb, cb); Ob_DECREF(pObHive); return f; } _Success_(return) -BOOL VMMDLL_WinReg_HiveWrite(_In_ ULONG64 vaCMHive, _In_ DWORD ra, _In_ PBYTE pb, _In_ DWORD cb) +BOOL VMMDLL_WinReg_HiveWrite(_In_ VMM_HANDLE H, _In_ ULONG64 vaCMHive, _In_ DWORD ra, _In_ PBYTE pb, _In_ DWORD cb) { CALL_IMPLEMENTATION_VMM( + H, STATISTICS_ID_VMMDLL_WinRegHive_Write, - VMMDLL_WinReg_HiveWrite_Impl(vaCMHive, ra, pb, cb)) + VMMDLL_WinReg_HiveWrite_Impl(H, vaCMHive, ra, pb, cb)) } _Success_(return) -BOOL VMMDLL_WinReg_EnumKeyEx_Impl(_In_opt_ LPSTR uszFullPathKey, _In_opt_ LPWSTR wszFullPathKey, _In_ DWORD dwIndex, _Out_writes_opt_(cbName) PBYTE pbName, _In_ DWORD cbName, _Out_ PDWORD pcchName, _Out_opt_ PFILETIME lpftLastWriteTime) +BOOL VMMDLL_WinReg_EnumKeyEx_Impl(_In_ VMM_HANDLE H, _In_opt_ LPSTR uszFullPathKey, _In_opt_ LPWSTR wszFullPathKey, _In_ DWORD dwIndex, _Out_writes_opt_(cbName) PBYTE pbName, _In_ DWORD cbName, _Out_ PDWORD pcchName, _Out_opt_ PFILETIME lpftLastWriteTime) { BOOL f; VMM_REGISTRY_KEY_INFO KeyInfo = { 0 }; @@ -2555,15 +2273,15 @@ BOOL VMMDLL_WinReg_EnumKeyEx_Impl(_In_opt_ LPSTR uszFullPathKey, _In_opt_ LPWSTR if(lpftLastWriteTime) { *(PQWORD)lpftLastWriteTime = 0; } return FALSE; } - f = VmmWinReg_PathHiveGetByFullPath(uszFullPathKey, &pObHive, uszPathKey) && - (pObKey = VmmWinReg_KeyGetByPath(pObHive, uszPathKey)); + f = VmmWinReg_PathHiveGetByFullPath(H, uszFullPathKey, &pObHive, uszPathKey) && + (pObKey = VmmWinReg_KeyGetByPath(H, pObHive, uszPathKey)); if(f) { if(f && (dwIndex == (DWORD)-1)) { // actual key VmmWinReg_KeyInfo(pObHive, pObKey, &KeyInfo); } else { // subkeys - f = (pmObSubKeys = VmmWinReg_KeyList(pObHive, pObKey)) && + f = (pmObSubKeys = VmmWinReg_KeyList(H, pObHive, pObKey)) && (pObSubKey = ObMap_GetByIndex(pmObSubKeys, dwIndex)); if(f) { VmmWinReg_KeyInfo(pObHive, pObSubKey, &KeyInfo); } } @@ -2583,7 +2301,7 @@ BOOL VMMDLL_WinReg_EnumKeyEx_Impl(_In_opt_ LPSTR uszFullPathKey, _In_opt_ LPWSTR } _Success_(return) -BOOL VMMDLL_WinReg_EnumValue_Impl(_In_opt_ LPSTR uszFullPathKey, _In_opt_ LPWSTR wszFullPathKey, _In_ DWORD dwIndex, _Out_writes_opt_(cbName) PBYTE pbName, _In_ DWORD cbName, _Out_ PDWORD pcchName, _Out_opt_ PDWORD lpType, _Out_writes_opt_(*lpcbData) PBYTE lpData, _Inout_opt_ PDWORD lpcbData) +BOOL VMMDLL_WinReg_EnumValue_Impl(_In_ VMM_HANDLE H, _In_opt_ LPSTR uszFullPathKey, _In_opt_ LPWSTR wszFullPathKey, _In_ DWORD dwIndex, _Out_writes_opt_(cbName) PBYTE pbName, _In_ DWORD cbName, _Out_ PDWORD pcchName, _Out_opt_ PDWORD lpType, _Out_writes_opt_(*lpcbData) PBYTE lpData, _Inout_opt_ PDWORD lpcbData) { BOOL f; VMM_REGISTRY_VALUE_INFO ValueInfo = { 0 }; @@ -2603,9 +2321,9 @@ BOOL VMMDLL_WinReg_EnumValue_Impl(_In_opt_ LPSTR uszFullPathKey, _In_opt_ LPWSTR if(lpcbData) { *lpcbData = 0; } return FALSE; } - f = VmmWinReg_PathHiveGetByFullPath(uszFullPathKey, &pObHive, uszPathKey) && - (pObKey = VmmWinReg_KeyGetByPath(pObHive, uszPathKey)) && - (pmObValues = VmmWinReg_KeyValueList(pObHive, pObKey)) && + f = VmmWinReg_PathHiveGetByFullPath(H, uszFullPathKey, &pObHive, uszPathKey) && + (pObKey = VmmWinReg_KeyGetByPath(H, pObHive, uszPathKey)) && + (pmObValues = VmmWinReg_KeyValueList(H, pObHive, pObKey)) && (pObValue = ObMap_GetByIndex(pmObValues, dwIndex)); if(f) { VmmWinReg_ValueInfo(pObHive, pObValue, &ValueInfo); @@ -2618,7 +2336,7 @@ BOOL VMMDLL_WinReg_EnumValue_Impl(_In_opt_ LPSTR uszFullPathKey, _In_opt_ LPWSTR } if(lpType) { *lpType = ValueInfo.dwType; } if(f && lpData) { - f = VmmWinReg_ValueQuery4(pObHive, pObValue, NULL, lpData, *lpcbData, lpcbData); + f = VmmWinReg_ValueQuery4(H, pObHive, pObValue, NULL, lpData, *lpcbData, lpcbData); } else if(lpcbData) { *lpcbData = ValueInfo.cbData; } @@ -2629,37 +2347,37 @@ BOOL VMMDLL_WinReg_EnumValue_Impl(_In_opt_ LPSTR uszFullPathKey, _In_opt_ LPWSTR return f; } -_Success_(return) BOOL VMMDLL_WinReg_EnumKeyExU(_In_ LPSTR uszFullPathKey, _In_ DWORD dwIndex, _Out_writes_opt_(*lpcchName) LPSTR lpName, _Inout_ LPDWORD lpcchName, _Out_opt_ PFILETIME lpftLastWriteTime) +_Success_(return) BOOL VMMDLL_WinReg_EnumKeyExU(_In_ VMM_HANDLE H, _In_ LPSTR uszFullPathKey, _In_ DWORD dwIndex, _Out_writes_opt_(*lpcchName) LPSTR lpName, _Inout_ LPDWORD lpcchName, _Out_opt_ PFILETIME lpftLastWriteTime) { - CALL_IMPLEMENTATION_VMM(STATISTICS_ID_VMMDLL_WinReg_EnumValueW, VMMDLL_WinReg_EnumKeyEx_Impl(uszFullPathKey, NULL, dwIndex, (PBYTE)lpName, *lpcchName, lpcchName, lpftLastWriteTime)) + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_WinReg_EnumValueW, VMMDLL_WinReg_EnumKeyEx_Impl(H, uszFullPathKey, NULL, dwIndex, (PBYTE)lpName, *lpcchName, lpcchName, lpftLastWriteTime)) } -_Success_(return) BOOL VMMDLL_WinReg_EnumKeyExW(_In_ LPWSTR wszFullPathKey, _In_ DWORD dwIndex, _Out_writes_opt_(*lpcchName) LPWSTR lpName, _Inout_ LPDWORD lpcchName, _Out_opt_ PFILETIME lpftLastWriteTime) +_Success_(return) BOOL VMMDLL_WinReg_EnumKeyExW(_In_ VMM_HANDLE H, _In_ LPWSTR wszFullPathKey, _In_ DWORD dwIndex, _Out_writes_opt_(*lpcchName) LPWSTR lpName, _Inout_ LPDWORD lpcchName, _Out_opt_ PFILETIME lpftLastWriteTime) { - CALL_IMPLEMENTATION_VMM(STATISTICS_ID_VMMDLL_WinReg_EnumValueW, VMMDLL_WinReg_EnumKeyEx_Impl(NULL, wszFullPathKey, dwIndex, (PBYTE)lpName, *lpcchName << 1, lpcchName, lpftLastWriteTime)) + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_WinReg_EnumValueW, VMMDLL_WinReg_EnumKeyEx_Impl(H, NULL, wszFullPathKey, dwIndex, (PBYTE)lpName, *lpcchName << 1, lpcchName, lpftLastWriteTime)) } -_Success_(return) 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) +_Success_(return) BOOL VMMDLL_WinReg_EnumValueU(_In_ VMM_HANDLE H, _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) { - CALL_IMPLEMENTATION_VMM(STATISTICS_ID_VMMDLL_WinReg_EnumValueW, VMMDLL_WinReg_EnumValue_Impl(uszFullPathKey, NULL, dwIndex, (PBYTE)lpValueName, *lpcchValueName, lpcchValueName, lpType, lpData, lpcbData)) + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_WinReg_EnumValueW, VMMDLL_WinReg_EnumValue_Impl(H, uszFullPathKey, NULL, dwIndex, (PBYTE)lpValueName, *lpcchValueName, lpcchValueName, lpType, lpData, lpcbData)) } -_Success_(return) 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) +_Success_(return) BOOL VMMDLL_WinReg_EnumValueW(_In_ VMM_HANDLE H, _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) { - CALL_IMPLEMENTATION_VMM(STATISTICS_ID_VMMDLL_WinReg_EnumValueW, VMMDLL_WinReg_EnumValue_Impl(NULL, wszFullPathKey, dwIndex, (PBYTE)lpValueName, *lpcchValueName << 1, lpcchValueName, lpType, lpData, lpcbData)) + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_WinReg_EnumValueW, VMMDLL_WinReg_EnumValue_Impl(H, NULL, wszFullPathKey, dwIndex, (PBYTE)lpValueName, *lpcchValueName << 1, lpcchValueName, lpType, lpData, lpcbData)) } -_Success_(return) 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) +_Success_(return) BOOL VMMDLL_WinReg_QueryValueExU(_In_ VMM_HANDLE H, _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) { - CALL_IMPLEMENTATION_VMM(STATISTICS_ID_VMMDLL_WinReg_QueryValueEx, VmmWinReg_ValueQuery2(uszFullPathKeyValue, lpType, lpData, lpcbData ? *lpcbData : 0, lpcbData)) + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_WinReg_QueryValueEx, VmmWinReg_ValueQuery2(H, uszFullPathKeyValue, lpType, lpData, lpcbData ? *lpcbData : 0, lpcbData)) } -_Success_(return) 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) +_Success_(return) BOOL VMMDLL_WinReg_QueryValueExW(_In_ VMM_HANDLE H, _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) { LPSTR uszFullPathKeyValue; BYTE pbBuffer[2 * MAX_PATH]; if(!CharUtil_WtoU(wszFullPathKeyValue, -1, pbBuffer, sizeof(pbBuffer), &uszFullPathKeyValue, NULL, 0)) { return FALSE; } - CALL_IMPLEMENTATION_VMM(STATISTICS_ID_VMMDLL_WinReg_QueryValueEx, VmmWinReg_ValueQuery2(uszFullPathKeyValue, lpType, lpData, lpcbData ? *lpcbData : 0, lpcbData)) + CALL_IMPLEMENTATION_VMM(H, STATISTICS_ID_VMMDLL_WinReg_QueryValueEx, VmmWinReg_ValueQuery2(H, uszFullPathKeyValue, lpType, lpData, lpcbData ? *lpcbData : 0, lpcbData)) } @@ -2669,34 +2387,35 @@ _Success_(return) BOOL VMMDLL_WinReg_QueryValueExW(_In_ LPWSTR wszFullPathKeyVal //----------------------------------------------------------------------------- _Success_(return) -BOOL VMMDLL_WinGetThunkInfoIAT_Impl(_In_ DWORD dwPID, _In_ LPSTR uszModuleName, _In_ LPSTR szImportModuleName, _In_ LPSTR szImportFunctionName, _Out_ PVMMDLL_WIN_THUNKINFO_IAT pThunkInfoIAT) +BOOL VMMDLL_WinGetThunkInfoIAT_Impl(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ LPSTR uszModuleName, _In_ LPSTR szImportModuleName, _In_ LPSTR szImportFunctionName, _Out_ PVMMDLL_WIN_THUNKINFO_IAT pThunkInfoIAT) { BOOL f = FALSE; QWORD vaModuleBase; PVMM_PROCESS pObProcess = NULL; f = (sizeof(VMMDLL_WIN_THUNKINFO_IAT) == sizeof(PE_THUNKINFO_IAT)) && - (pObProcess = VmmProcessGet(dwPID)) && - (vaModuleBase = VMMDLL_ProcessGetModuleBase_Impl(dwPID, uszModuleName)) && - PE_GetThunkInfoIAT(pObProcess, vaModuleBase, szImportModuleName, szImportFunctionName, (PPE_THUNKINFO_IAT)pThunkInfoIAT); + (pObProcess = VmmProcessGet(H, dwPID)) && + (vaModuleBase = VMMDLL_ProcessGetModuleBase_Impl(H, dwPID, uszModuleName)) && + PE_GetThunkInfoIAT(H, pObProcess, vaModuleBase, szImportModuleName, szImportFunctionName, (PPE_THUNKINFO_IAT)pThunkInfoIAT); Ob_DECREF(pObProcess); return f; } _Success_(return) -BOOL VMMDLL_WinGetThunkInfoIATU(_In_ DWORD dwPID, _In_ LPSTR uszModuleName, _In_ LPSTR szImportModuleName, _In_ LPSTR szImportFunctionName, _Out_ PVMMDLL_WIN_THUNKINFO_IAT pThunkInfoIAT) +BOOL VMMDLL_WinGetThunkInfoIATU(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ LPSTR uszModuleName, _In_ LPSTR szImportModuleName, _In_ LPSTR szImportFunctionName, _Out_ PVMMDLL_WIN_THUNKINFO_IAT pThunkInfoIAT) { CALL_IMPLEMENTATION_VMM( + H, STATISTICS_ID_VMMDLL_WinGetThunkIAT, - VMMDLL_WinGetThunkInfoIAT_Impl(dwPID, uszModuleName, szImportModuleName, szImportFunctionName, pThunkInfoIAT)) + VMMDLL_WinGetThunkInfoIAT_Impl(H, dwPID, uszModuleName, szImportModuleName, szImportFunctionName, pThunkInfoIAT)) } _Success_(return) -BOOL VMMDLL_WinGetThunkInfoIATW(_In_ DWORD dwPID, _In_ LPWSTR wszModuleName, _In_ LPSTR szImportModuleName, _In_ LPSTR szImportFunctionName, _Out_ PVMMDLL_WIN_THUNKINFO_IAT pThunkInfoIAT) +BOOL VMMDLL_WinGetThunkInfoIATW(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ LPWSTR wszModuleName, _In_ LPSTR szImportModuleName, _In_ LPSTR szImportFunctionName, _Out_ PVMMDLL_WIN_THUNKINFO_IAT pThunkInfoIAT) { LPSTR uszModuleName; BYTE pbBuffer[MAX_PATH]; if(!CharUtil_WtoU(wszModuleName, -1, pbBuffer, sizeof(pbBuffer), &uszModuleName, NULL, 0)) { return FALSE; } - return VMMDLL_WinGetThunkInfoIATU(dwPID, uszModuleName, szImportModuleName, szImportFunctionName, pThunkInfoIAT); + return VMMDLL_WinGetThunkInfoIATU(H, dwPID, uszModuleName, szImportModuleName, szImportFunctionName, pThunkInfoIAT); } @@ -2706,93 +2425,98 @@ BOOL VMMDLL_WinGetThunkInfoIATW(_In_ DWORD dwPID, _In_ LPWSTR wszModuleName, _In //----------------------------------------------------------------------------- _Success_(return) -BOOL VMMDLL_PdbLoad_Impl(_In_ DWORD dwPID, _In_ ULONG64 vaModuleBase, _Out_writes_(MAX_PATH) LPSTR szModuleName) +BOOL VMMDLL_PdbLoad_Impl(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ ULONG64 vaModuleBase, _Out_writes_(MAX_PATH) LPSTR szModuleName) { BOOL fResult; PDB_HANDLE hPdb; PVMM_PROCESS pObProcess; - if(!(pObProcess = VmmProcessGet(dwPID))) { return FALSE; } + if(!(pObProcess = VmmProcessGet(H, dwPID))) { return FALSE; } fResult = - (hPdb = PDB_GetHandleFromModuleAddress(pObProcess, vaModuleBase)) && - PDB_LoadEnsure(hPdb) && - PDB_GetModuleInfo(hPdb, szModuleName, NULL, NULL); + (hPdb = PDB_GetHandleFromModuleAddress(H, pObProcess, vaModuleBase)) && + PDB_LoadEnsure(H, hPdb) && + PDB_GetModuleInfo(H, hPdb, szModuleName, NULL, NULL); Ob_DECREF(pObProcess); return fResult; } _Success_(return) -BOOL VMMDLL_PdbLoad(_In_ DWORD dwPID, _In_ ULONG64 vaModuleBase, _Out_writes_(MAX_PATH) LPSTR szModuleName) +BOOL VMMDLL_PdbLoad(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ ULONG64 vaModuleBase, _Out_writes_(MAX_PATH) LPSTR szModuleName) { CALL_IMPLEMENTATION_VMM( + H, STATISTICS_ID_VMMDLL_PdbLoad, - VMMDLL_PdbLoad_Impl(dwPID, vaModuleBase, szModuleName)) + VMMDLL_PdbLoad_Impl(H, dwPID, vaModuleBase, szModuleName)) } _Success_(return) -BOOL VMMDLL_PdbSymbolName_Impl(_In_ LPSTR szModule, _In_ QWORD cbSymbolAddressOrOffset, _Out_writes_(MAX_PATH) LPSTR szSymbolName, _Out_opt_ PDWORD pdwSymbolDisplacement) +BOOL VMMDLL_PdbSymbolName_Impl(_In_ VMM_HANDLE H, _In_ LPSTR szModule, _In_ QWORD cbSymbolAddressOrOffset, _Out_writes_(MAX_PATH) LPSTR szSymbolName, _Out_opt_ PDWORD pdwSymbolDisplacement) { DWORD cbPdbModuleSize = 0; QWORD vaPdbModuleBase = 0; - PDB_HANDLE hPdb = PDB_GetHandleFromModuleName(szModule); - if(PDB_GetModuleInfo(hPdb, NULL, &vaPdbModuleBase, &cbPdbModuleSize)) { + PDB_HANDLE hPdb = PDB_GetHandleFromModuleName(H, szModule); + if(PDB_GetModuleInfo(H, hPdb, NULL, &vaPdbModuleBase, &cbPdbModuleSize)) { if((vaPdbModuleBase <= cbSymbolAddressOrOffset) && (vaPdbModuleBase + cbPdbModuleSize >= cbSymbolAddressOrOffset)) { cbSymbolAddressOrOffset -= vaPdbModuleBase; // cbSymbolAddressOrOffset is absolute address } } - return PDB_GetSymbolFromOffset(hPdb, (DWORD)cbSymbolAddressOrOffset, szSymbolName, pdwSymbolDisplacement); + return PDB_GetSymbolFromOffset(H, hPdb, (DWORD)cbSymbolAddressOrOffset, szSymbolName, pdwSymbolDisplacement); } _Success_(return) -BOOL VMMDLL_PdbSymbolName(_In_ LPSTR szModule, _In_ QWORD cbSymbolAddressOrOffset, _Out_writes_(MAX_PATH) LPSTR szSymbolName, _Out_opt_ PDWORD pdwSymbolDisplacement) +BOOL VMMDLL_PdbSymbolName(_In_ VMM_HANDLE H, _In_ LPSTR szModule, _In_ QWORD cbSymbolAddressOrOffset, _Out_writes_(MAX_PATH) LPSTR szSymbolName, _Out_opt_ PDWORD pdwSymbolDisplacement) { CALL_IMPLEMENTATION_VMM( + H, STATISTICS_ID_VMMDLL_PdbSymbolName, - VMMDLL_PdbSymbolName_Impl(szModule, cbSymbolAddressOrOffset, szSymbolName, pdwSymbolDisplacement)) + VMMDLL_PdbSymbolName_Impl(H, szModule, cbSymbolAddressOrOffset, szSymbolName, pdwSymbolDisplacement)) } _Success_(return) -BOOL VMMDLL_PdbSymbolAddress_Impl(_In_ LPSTR szModule, _In_ LPSTR szSymbolName, _Out_ PULONG64 pvaSymbolAddress) +BOOL VMMDLL_PdbSymbolAddress_Impl(_In_ VMM_HANDLE H, _In_ LPSTR szModule, _In_ LPSTR szSymbolName, _Out_ PULONG64 pvaSymbolAddress) { - PDB_HANDLE hPdb = (strcmp(szModule, "nt") && strcmp(szModule, "ntoskrnl")) ? PDB_GetHandleFromModuleName(szModule) : PDB_HANDLE_KERNEL; - return PDB_GetSymbolAddress(hPdb, szSymbolName, pvaSymbolAddress); + PDB_HANDLE hPdb = (strcmp(szModule, "nt") && strcmp(szModule, "ntoskrnl")) ? PDB_GetHandleFromModuleName(H, szModule) : PDB_HANDLE_KERNEL; + return PDB_GetSymbolAddress(H, hPdb, szSymbolName, pvaSymbolAddress); } _Success_(return) -BOOL VMMDLL_PdbSymbolAddress(_In_ LPSTR szModule, _In_ LPSTR szSymbolName, _Out_ PULONG64 pvaSymbolAddress) +BOOL VMMDLL_PdbSymbolAddress(_In_ VMM_HANDLE H, _In_ LPSTR szModule, _In_ LPSTR szSymbolName, _Out_ PULONG64 pvaSymbolAddress) { CALL_IMPLEMENTATION_VMM( + H, STATISTICS_ID_VMMDLL_PdbSymbolAddress, - VMMDLL_PdbSymbolAddress_Impl(szModule, szSymbolName, pvaSymbolAddress)) + VMMDLL_PdbSymbolAddress_Impl(H, szModule, szSymbolName, pvaSymbolAddress)) } _Success_(return) -BOOL VMMDLL_PdbTypeSize_Impl(_In_ LPSTR szModule, _In_ LPSTR szTypeName, _Out_ PDWORD pcbTypeSize) +BOOL VMMDLL_PdbTypeSize_Impl(_In_ VMM_HANDLE H, _In_ LPSTR szModule, _In_ LPSTR szTypeName, _Out_ PDWORD pcbTypeSize) { - PDB_HANDLE hPdb = (strcmp(szModule, "nt") && strcmp(szModule, "ntoskrnl")) ? PDB_GetHandleFromModuleName(szModule) : PDB_HANDLE_KERNEL; - return PDB_GetTypeSize(hPdb, szTypeName, pcbTypeSize); + PDB_HANDLE hPdb = (strcmp(szModule, "nt") && strcmp(szModule, "ntoskrnl")) ? PDB_GetHandleFromModuleName(H, szModule) : PDB_HANDLE_KERNEL; + return PDB_GetTypeSize(H, hPdb, szTypeName, pcbTypeSize); } _Success_(return) -BOOL VMMDLL_PdbTypeSize(_In_ LPSTR szModule, _In_ LPSTR szTypeName, _Out_ PDWORD pcbTypeSize) +BOOL VMMDLL_PdbTypeSize(_In_ VMM_HANDLE H, _In_ LPSTR szModule, _In_ LPSTR szTypeName, _Out_ PDWORD pcbTypeSize) { CALL_IMPLEMENTATION_VMM( + H, STATISTICS_ID_VMMDLL_PdbTypeSize, - VMMDLL_PdbTypeSize_Impl(szModule, szTypeName, pcbTypeSize)) + VMMDLL_PdbTypeSize_Impl(H, szModule, szTypeName, pcbTypeSize)) } _Success_(return) -BOOL VMMDLL_PdbTypeChildOffset_Impl(_In_ LPSTR szModule, _In_ LPSTR uszTypeName, _In_ LPSTR uszTypeChildName, _Out_ PDWORD pcbTypeChildOffset) +BOOL VMMDLL_PdbTypeChildOffset_Impl(_In_ VMM_HANDLE H, _In_ LPSTR szModule, _In_ LPSTR uszTypeName, _In_ LPSTR uszTypeChildName, _Out_ PDWORD pcbTypeChildOffset) { - PDB_HANDLE hPdb = (strcmp(szModule, "nt") && strcmp(szModule, "ntoskrnl")) ? PDB_GetHandleFromModuleName(szModule) : PDB_HANDLE_KERNEL; - return PDB_GetTypeChildOffset(hPdb, uszTypeName, uszTypeChildName, pcbTypeChildOffset); + PDB_HANDLE hPdb = (strcmp(szModule, "nt") && strcmp(szModule, "ntoskrnl")) ? PDB_GetHandleFromModuleName(H, szModule) : PDB_HANDLE_KERNEL; + return PDB_GetTypeChildOffset(H, hPdb, uszTypeName, uszTypeChildName, pcbTypeChildOffset); } _Success_(return) -BOOL VMMDLL_PdbTypeChildOffset(_In_ LPSTR szModule, _In_ LPSTR uszTypeName, _In_ LPSTR uszTypeChildName, _Out_ PDWORD pcbTypeChildOffset) +BOOL VMMDLL_PdbTypeChildOffset(_In_ VMM_HANDLE H, _In_ LPSTR szModule, _In_ LPSTR uszTypeName, _In_ LPSTR uszTypeChildName, _Out_ PDWORD pcbTypeChildOffset) { CALL_IMPLEMENTATION_VMM( + H, STATISTICS_ID_VMMDLL_PdbTypeChildOffset, - VMMDLL_PdbTypeChildOffset_Impl(szModule, uszTypeName, uszTypeChildName, pcbTypeChildOffset)) + VMMDLL_PdbTypeChildOffset_Impl(H, szModule, uszTypeName, uszTypeChildName, pcbTypeChildOffset)) } @@ -2805,9 +2529,7 @@ BOOL VMMDLL_PdbTypeChildOffset(_In_ LPSTR szModule, _In_ LPSTR uszTypeName, _In_ _Success_(return) BOOL VMMDLL_UtilFillHexAscii(_In_reads_opt_(cb) PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset, _Out_writes_opt_(*pcsz) LPSTR sz, _Inout_ PDWORD pcsz) { - CALL_IMPLEMENTATION_VMM( - STATISTICS_ID_VMMDLL_UtilFillHexAscii, - Util_FillHexAscii(pb, cb, cbInitialOffset, sz, pcsz)) + return Util_FillHexAscii(pb, cb, cbInitialOffset, sz, pcsz); } diff --git a/vmm/vmmdll.def b/vmm/vmmdll.def index b033755..eda3ed8 100644 --- a/vmm/vmmdll.def +++ b/vmm/vmmdll.def @@ -3,6 +3,8 @@ EXPORTS VMMDLL_Initialize VMMDLL_InitializeEx VMMDLL_Close + VMMDLL_CloseAll + VMMDLL_MemSize VMMDLL_MemFree VMMDLL_InitializePlugins @@ -55,7 +57,6 @@ EXPORTS VMMDLL_Map_GetNetW VMMDLL_Map_GetPfn VMMDLL_Map_GetPool - VMMDLL_Map_GetPoolEx VMMDLL_Map_GetPhysMem VMMDLL_Map_GetUsersU VMMDLL_Map_GetUsersW @@ -76,8 +77,8 @@ EXPORTS VMMDLL_Map_GetEATW VMMDLL_Map_GetIATU VMMDLL_Map_GetIATW - VMMDLL_Map_GetHeapEx - VMMDLL_Map_GetHeapAllocEx + VMMDLL_Map_GetHeap + VMMDLL_Map_GetHeapAlloc VMMDLL_Map_GetThread VMMDLL_Map_GetHandleU VMMDLL_Map_GetHandleW @@ -111,6 +112,7 @@ EXPORTS VMMDLL_PdbTypeSize VMMDLL_PdbTypeChildOffset + VMMDLL_ForensicFileAppend VMMDLL_UtilFillHexAscii VMMDLL_Log diff --git a/vmm/vmmdll.h b/vmm/vmmdll.h index 2bfce0d..b42dba7 100644 --- a/vmm/vmmdll.h +++ b/vmm/vmmdll.h @@ -1,13 +1,23 @@ // vmmdll.h : header file to include in projects that use vmm.dll / vmm.so // +// Please also consult the guide at: https://github.com/ufrisk/MemProcFS/wiki +// +// U/W functions +// ============= // Windows may access both UTF-8 *U and Wide-Char *W versions of functions // while Linux may only access UTF-8 versions. Some functionality may also // be degraded or unavailable on Linux. +// +// v5 API +// ====== +// v5 of the API support multiple concurrent parallel analysis tasks. +// To accomodate this significant changes have been done to the API which is +// largely incompatible (but very similar) to the earlier API versions. // // (c) Ulf Frisk, 2018-2022 // Author: Ulf Frisk, pcileech@frizk.net // -// Header Version: 4.9 +// Header Version: 5.0 // #include "leechcore.h" @@ -67,6 +77,8 @@ typedef uint16_t WCHAR, *PWCHAR, *LPWSTR, *LPCWSTR; #endif /* LINUX */ +typedef struct tdVMM_HANDLE *VMM_HANDLE; + //----------------------------------------------------------------------------- @@ -124,21 +136,34 @@ typedef uint16_t WCHAR, *PWCHAR, *LPWSTR, *LPCWSTR; * struct LC_CONFIG_ERRORINFO with extended error information upon * failure. Any memory received should be free'd by caller by * calling LcMemFree(). -* -- return = success/fail +* -- return = VMM_HANDLE on success for usage in subsequent API calls. NULL=fail. */ -EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_Initialize(_In_ DWORD argc, _In_ LPSTR argv[]); +EXPORTED_FUNCTION _Success_(return != NULL) +VMM_HANDLE VMMDLL_Initialize(_In_ DWORD argc, _In_ LPSTR argv[]); -EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_InitializeEx(_In_ DWORD argc, _In_ LPSTR argv[], _Out_opt_ PPLC_CONFIG_ERRORINFO ppLcErrorInfo); +EXPORTED_FUNCTION _Success_(return != NULL) +VMM_HANDLE VMMDLL_InitializeEx(_In_ DWORD argc, _In_ LPSTR argv[], _Out_opt_ PPLC_CONFIG_ERRORINFO ppLcErrorInfo); /* -* Close an initialized instance of VMM.DLL and clean up all allocated resources -* including plugins, linked PCILeech.DLL and other memory resources. -* -- return = success/fail. +* Close an instantiated version of VMM_HANDLE and free up any resources. +* -- hVMM */ -EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_Close(); +EXPORTED_FUNCTION +VOID VMMDLL_Close(_In_opt_ _Post_ptr_invalid_ VMM_HANDLE hVMM); + +/* +* Close all instantiated versions of VMM_HANDLE and free up all resources. +*/ +EXPORTED_FUNCTION +VOID VMMDLL_CloseAll(); + +/* +* Query the size of memory allocated by the VMMDLL. +* -- pvMem +* -- return = number of bytes required to hold memory allocation. +*/ +EXPORTED_FUNCTION _Success_(return != 0) +SIZE_T VMMDLL_MemSize(_In_ PVOID pvMem); /* * Free memory allocated by the VMMDLL. @@ -190,21 +215,13 @@ VOID VMMDLL_MemFree(_Frees_ptr_opt_ PVOID pvMem); #define VMMDLL_OPT_FORENSIC_MODE 0x2000020100000000 // RW - enable/retrieve forensic mode type [0-4]. #define VMMDLL_OPT_REFRESH_ALL 0x2001ffff00000000 // W - refresh all caches -#define VMMDLL_OPT_REFRESH_FREQ_MEM 0x2001000200000000 // W - refresh memory cache (excl. TLB) [partial 33%/call] -#define VMMDLL_OPT_REFRESH_FREQ_TLB 0x2001000400000000 // W - refresh page table (TLB) cache [partial 33%/call] +#define VMMDLL_OPT_REFRESH_FREQ_MEM 0x2001100000000000 // W - refresh memory cache (excl. TLB) [fully] +#define VMMDLL_OPT_REFRESH_FREQ_MEM_PARTIAL 0x2001000200000000 // W - refresh memory cache (excl. TLB) [partial 33%/call] +#define VMMDLL_OPT_REFRESH_FREQ_TLB 0x2001080000000000 // W - refresh page table (TLB) cache [fully] +#define VMMDLL_OPT_REFRESH_FREQ_TLB_PARTIAL 0x2001000400000000 // W - refresh page table (TLB) cache [partial 33%/call] #define VMMDLL_OPT_REFRESH_FREQ_FAST 0x2001040000000000 // W - refresh fast frequency - incl. partial process refresh #define VMMDLL_OPT_REFRESH_FREQ_MEDIUM 0x2001000100000000 // W - refresh medium frequency - incl. full process refresh #define VMMDLL_OPT_REFRESH_FREQ_SLOW 0x2001001000000000 // W - refresh slow frequency. -#define VMMDLL_OPT_REFRESH_PROCESS 0x2001000100000000 // W - DEPRECATED: refresh process listings -#define VMMDLL_OPT_REFRESH_READ 0x2001000200000000 // W - DEPRECATED: refresh physical read cache -#define VMMDLL_OPT_REFRESH_TLB 0x2001000400000000 // W - DEPRECATED: refresh page table (TLB) cache -#define VMMDLL_OPT_REFRESH_PAGING 0x2001000800000000 // W - DEPRECATED: refresh virtual memory 'paging' cache -#define VMMDLL_OPT_REFRESH_REGISTRY 0x2001001000000000 // W - DEPRECATED: -#define VMMDLL_OPT_REFRESH_USER 0x2001002000000000 // W - DEPRECATED: -#define VMMDLL_OPT_REFRESH_PHYSMEMMAP 0x2001004000000000 // W - DEPRECATED: -#define VMMDLL_OPT_REFRESH_PFN 0x2001008000000000 // W - DEPRECATED: -#define VMMDLL_OPT_REFRESH_OBJ 0x2001010000000000 // W - DEPRECATED: -#define VMMDLL_OPT_REFRESH_NET 0x2001020000000000 // W - DEPRECATED: static LPCSTR VMMDLL_MEMORYMODEL_TOSTRING[4] = { "N/A", "X86", "X86PAE", "X64" }; @@ -226,23 +243,25 @@ typedef enum tdVMMDLL_SYSTEM_TP { * Get a device specific option value. Please see defines VMMDLL_OPT_* for infor- * mation about valid option values. Please note that option values may overlap * between different device types with different meanings. +* -- hVMM * -- fOption * -- pqwValue = pointer to ULONG64 to receive option value. * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_ConfigGet(_In_ ULONG64 fOption, _Out_ PULONG64 pqwValue); +BOOL VMMDLL_ConfigGet(_In_ VMM_HANDLE hVMM, _In_ ULONG64 fOption, _Out_ PULONG64 pqwValue); /* * Set a device specific option value. Please see defines VMMDLL_OPT_* for infor- * mation about valid option values. Please note that option values may overlap * between different device types with different meanings. +* -- hVMM * -- fOption * -- qwValue * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_ConfigSet(_In_ ULONG64 fOption, _In_ ULONG64 qwValue); +BOOL VMMDLL_ConfigSet(_In_ VMM_HANDLE hVMM, _In_ ULONG64 fOption, _In_ ULONG64 qwValue); @@ -372,25 +391,28 @@ EXPORTED_FUNCTION BOOL VMMDLL_VfsList_IsHandleValid(_In_ HANDLE pFileList); * by callbacks into functions supplied in the pFileList parameter. * If information of an individual file is needed it's neccessary to list all * files in its directory. +* -- hVMM * -- [uw]szPath * -- pFileList * -- return */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_VfsListU(_In_ LPSTR uszPath, _Inout_ PVMMDLL_VFS_FILELIST2 pFileList); -_Success_(return) BOOL VMMDLL_VfsListW(_In_ LPWSTR wszPath, _Inout_ PVMMDLL_VFS_FILELIST2 pFileList); +_Success_(return) BOOL VMMDLL_VfsListU(_In_ VMM_HANDLE hVMM, _In_ LPSTR uszPath, _Inout_ PVMMDLL_VFS_FILELIST2 pFileList); +_Success_(return) BOOL VMMDLL_VfsListW(_In_ VMM_HANDLE hVMM, _In_ LPWSTR wszPath, _Inout_ PVMMDLL_VFS_FILELIST2 pFileList); /* * List a directory of files in MemProcFS and return a VMMDLL_VFS_FILELISTBLOB. * CALLER FREE: VMMDLL_MemFree(return) +* -- hVMM * -- uszPath * -- return */ EXPORTED_FUNCTION -_Success_(return != NULL) PVMMDLL_VFS_FILELISTBLOB VMMDLL_VfsListBlobU(_In_ LPSTR uszPath); +_Success_(return != NULL) PVMMDLL_VFS_FILELISTBLOB VMMDLL_VfsListBlobU(_In_ VMM_HANDLE hVMM, _In_ LPSTR uszPath); /* * Read select parts of a file in MemProcFS. +* -- hVMM * -- [uw]szFileName * -- pb * -- cb @@ -400,11 +422,12 @@ _Success_(return != NULL) PVMMDLL_VFS_FILELISTBLOB VMMDLL_VfsListBlobU(_In_ LPST * */ EXPORTED_FUNCTION -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_VfsReadU(_In_ VMM_HANDLE hVMM, _In_ LPSTR uszFileName, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset); +NTSTATUS VMMDLL_VfsReadW(_In_ VMM_HANDLE hVMM, _In_ LPWSTR wszFileName, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset); /* * Write select parts to a file in MemProcFS. +* -- hVMM * -- [uw]szFileName * -- pb * -- cb @@ -413,8 +436,8 @@ NTSTATUS VMMDLL_VfsReadW(_In_ LPWSTR wszFileName, _Out_writes_to_(cb, *pcbRead) * -- return */ EXPORTED_FUNCTION -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_VfsWriteU(_In_ VMM_HANDLE hVMM, _In_ LPSTR uszFileName, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset); +NTSTATUS VMMDLL_VfsWriteW(_In_ VMM_HANDLE hVMM, _In_ LPWSTR wszFileName, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset); /* * Utility functions for MemProcFS read/write towards different underlying data @@ -438,7 +461,7 @@ EXPORTED_FUNCTION NTSTATUS VMMDLL_UtilVfsWriteFile_DWORD(_Inout_ PDWORD pdwTarge // function. The plugin/module may decide to call pfnPluginManager_Register to // register plugins in the form of different names one or more times. // Example of registration function in a plugin DLL below: -// 'VOID InitializeVmmPlugin(_In_ PVMM_PLUGIN_REGINFO pRegInfo)' +// 'VOID InitializeVmmPlugin(_In_ VMM_HANDLE H, _In_ PVMM_PLUGIN_REGINFO pRegInfo)' //----------------------------------------------------------------------------- /* @@ -446,16 +469,17 @@ EXPORTED_FUNCTION NTSTATUS VMMDLL_UtilVfsWriteFile_DWORD(_Inout_ PDWORD pdwTarge * MemProcFS. Please note that plugins are not loaded by default - they have to * be explicitly loaded by calling this function. They will be unloaded on a * general close of the vmm dll. +* -- hVMM * -- return */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_InitializePlugins(); +BOOL VMMDLL_InitializePlugins(_In_ VMM_HANDLE hVMM); #define VMMDLL_PLUGIN_CONTEXT_MAGIC 0xc0ffee663df9301c #define VMMDLL_PLUGIN_CONTEXT_VERSION 5 #define VMMDLL_PLUGIN_REGINFO_MAGIC 0xc0ffee663df9301d -#define VMMDLL_PLUGIN_REGINFO_VERSION 13 -#define VMMDLL_PLUGIN_FORENSIC_JSONDATA_VERSION 0xc0ee0001 +#define VMMDLL_PLUGIN_REGINFO_VERSION 15 +#define VMMDLL_PLUGIN_FORENSIC_JSONDATA_VERSION 0xc0ee0002 #define VMMDLL_PLUGIN_NOTIFY_VERBOSITYCHANGE 0x01 #define VMMDLL_PLUGIN_NOTIFY_REFRESH_FAST 0x05 // refresh fast event - at partial process refresh. @@ -467,6 +491,7 @@ BOOL VMMDLL_InitializePlugins(); typedef DWORD VMMDLL_MODULE_ID; typedef HANDLE *PVMMDLL_PLUGIN_INTERNAL_CONTEXT; +typedef struct tdVMMDLL_CSV_HANDLE *VMMDLL_CSV_HANDLE; #define VMMDLL_MID_MAIN ((VMMDLL_MODULE_ID)0x80000001) #define VMMDLL_MID_PYTHON ((VMMDLL_MODULE_ID)0x80000002) @@ -486,7 +511,7 @@ typedef struct tdVMMDLL_PLUGIN_CONTEXT { typedef struct tdVMMDLL_PLUGIN_FORENSIC_JSONDATA { DWORD dwVersion; // must equal VMMDLL_PLUGIN_FORENSIC_JSONDATA_VERSION - BOOL fVerbose; + DWORD _FutureUse; LPSTR szjType; // log type/name (json encoded) DWORD i; DWORD dwPID; @@ -504,9 +529,11 @@ typedef struct tdVMMDLL_PLUGIN_FORENSIC_JSONDATA { } VMMDLL_PLUGIN_FORENSIC_JSONDATA, *PVMMDLL_PLUGIN_FORENSIC_JSONDATA; typedef struct tdVMMDLL_PLUGIN_FORENSIC_INGEST_PHYSMEM { - DWORD cMEMs; BOOL fValid; - QWORD paBase; + QWORD pa; + DWORD cb; + PBYTE pb; + DWORD cMEMs; PPMEM_SCATTER ppMEMs; PVMMDLL_MAP_PFN pPfnMap; } VMMDLL_PLUGIN_FORENSIC_INGEST_PHYSMEM, *PVMMDLL_PLUGIN_FORENSIC_INGEST_PHYSMEM; @@ -518,7 +545,7 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO { VMMDLL_MEMORYMODEL_TP tpMemoryModel; VMMDLL_SYSTEM_TP tpSystem; HMODULE hDLL; - BOOL(*pfnPluginManager_Register)(struct tdVMMDLL_PLUGIN_REGINFO *pPluginRegInfo); + BOOL(*pfnPluginManager_Register)(_In_ VMM_HANDLE H, struct tdVMMDLL_PLUGIN_REGINFO *pPluginRegInfo); DWORD _Reserved[32]; // python plugin information - not for general use struct { @@ -542,12 +569,12 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO { } reg_info; // function plugin registration info to be filled out by the plugin below: struct { - BOOL(*pfnList)(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList); - NTSTATUS(*pfnRead)(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset); - NTSTATUS(*pfnWrite)(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset); - VOID(*pfnNotify)(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent); - VOID(*pfnClose)(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP); - BOOL(*pfnVisibleModule)(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP); + BOOL(*pfnList)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList); + NTSTATUS(*pfnRead)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset); + NTSTATUS(*pfnWrite)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset); + VOID(*pfnNotify)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent); + VOID(*pfnClose)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP); + BOOL(*pfnVisibleModule)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP); PVOID pvReserved[10]; } reg_fn; // Optional forensic plugin functionality for forensic (more comprehensive) @@ -557,17 +584,20 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO { // Functions are called in the order of: // pfnInitialize(), pfnIngest*(), pfnTimeline(), pfnLogJSON(), pfnFinalize() struct { - PVOID(*pfnInitialize)(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP); - VOID(*pfnFinalize)(_In_opt_ PVOID ctxfc); + PVOID(*pfnInitialize)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP); + VOID(*pfnFinalize)(_In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc); VOID(*pfnTimeline)( + _In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc, _In_ HANDLE hTimeline, - _In_ VOID(*pfnAddEntry)(_In_ HANDLE hTimeline, _In_ QWORD ft, _In_ DWORD dwAction, _In_ DWORD dwPID, _In_ DWORD dwData32, _In_ QWORD qwData64, _In_ LPSTR uszText), - _In_ VOID(*pfnEntryAddBySql)(_In_ HANDLE hTimeline, _In_ DWORD cEntrySql, _In_ LPSTR *pszEntrySql)); - VOID(*pfnIngestPhysmem)(_In_opt_ PVOID ctxfc, _In_ PVMMDLL_PLUGIN_FORENSIC_INGEST_PHYSMEM pIngestPhysmem); - VOID(*pfnIngestFinalize)(_In_opt_ PVOID ctxfc); - PVOID pvReserved[10]; - VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)); + _In_ VOID(*pfnAddEntry)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ QWORD ft, _In_ DWORD dwAction, _In_ DWORD dwPID, _In_ DWORD dwData32, _In_ QWORD qwData64, _In_ LPSTR uszText), + _In_ VOID(*pfnEntryAddBySql)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ DWORD cEntrySql, _In_ LPSTR *pszEntrySql)); + VOID(*pfnIngestPhysmem)(_In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc, _In_ PVMMDLL_PLUGIN_FORENSIC_INGEST_PHYSMEM pIngestPhysmem); + VOID(*pfnIngestVirtmem)(_In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc, _In_ DWORD dwPID, _In_ QWORD va, _In_ PBYTE pb, _In_ DWORD cb); + VOID(*pfnIngestFinalize)(_In_ VMM_HANDLE H, _In_opt_ PVOID ctxfc); + PVOID pvReserved[8]; + VOID(*pfnLogCSV)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VMMDLL_CSV_HANDLE hCSV); + VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_FORENSIC_JSONDATA pData)); } reg_fnfc; // Additional system information - read/only by the plugins. struct { @@ -581,6 +611,29 @@ typedef struct tdVMMDLL_PLUGIN_REGINFO { +//----------------------------------------------------------------------------- +// FORENSIC-MODE SPECIFIC FUNCTIONALITY BELOW: +//----------------------------------------------------------------------------- + +/* +* Append text data to a memory-backed forensics file. +* All text should be UTF-8 encoded. +* -- H +* -- uszFileName +* -- uszFormat +* -- .. +* -- return = number of bytes appended (excluding terminating null). +*/ +EXPORTED_FUNCTION _Success_(return != 0) +SIZE_T VMMDLL_ForensicFileAppend( + _In_ VMM_HANDLE H, + _In_ LPSTR uszFileName, + _In_z_ _Printf_format_string_ LPSTR uszFormat, + ... +); + + + //----------------------------------------------------------------------------- // VMM LOG FUNCTIONALITY BELOW: // It's possible for external code (primarily external plugins) to make use of @@ -600,6 +653,7 @@ typedef enum tdVMMDLL_LOGLEVEL { /* * Log a message using the internal MemProcFS vmm logging system. Log messages * will be displayed/suppressed depending on current logging configuration. +* -- hVMM * -- MID = module id supplied by plugin context PVMMDLL_PLUGIN_CONTEXT or * id given by VMMDLL_MID_*. * -- dwLogLevel @@ -608,6 +662,7 @@ typedef enum tdVMMDLL_LOGLEVEL { */ EXPORTED_FUNCTION VOID VMMDLL_Log( + _In_ VMM_HANDLE hVMM, _In_opt_ VMMDLL_MODULE_ID MID, _In_ VMMDLL_LOGLEVEL dwLogLevel, _In_z_ _Printf_format_string_ LPSTR uszFormat, @@ -617,6 +672,7 @@ VOID VMMDLL_Log( /* * Log a message using the internal MemProcFS vmm logging system. Log messages * will be displayed/suppressed depending on current logging configuration. +* -- hVMM * -- MID = module id supplied by plugin context PVMMDLL_PLUGIN_CONTEXT or * id given by VMMDLL_MID_*. * -- dwLogLevel @@ -625,6 +681,7 @@ VOID VMMDLL_Log( */ EXPORTED_FUNCTION VOID VMMDLL_LogEx( + _In_ VMM_HANDLE hVMM, _In_opt_ VMMDLL_MODULE_ID MID, _In_ VMMDLL_LOGLEVEL dwLogLevel, _In_z_ _Printf_format_string_ LPSTR uszFormat, @@ -663,6 +720,7 @@ VOID VMMDLL_LogEx( * boost will be given if above hardware limit. Max size of each unit of work is * one 4k page (4096 bytes). Reads must not cross 4k page boundaries. Reads must * start at even DWORDs (4-bytes). +* -- hVMM * -- dwPID - PID of target process, (DWORD)-1 to read physical memory. * -- ppMEMs = array of scatter read headers. * -- cpMEMs = count of ppMEMs. @@ -670,33 +728,36 @@ VOID VMMDLL_LogEx( * -- return = the number of successfully read items. */ EXPORTED_FUNCTION -DWORD VMMDLL_MemReadScatter(_In_ DWORD dwPID, _Inout_ PPMEM_SCATTER ppMEMs, _In_ DWORD cpMEMs, _In_ DWORD flags); +DWORD VMMDLL_MemReadScatter(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Inout_ PPMEM_SCATTER ppMEMs, _In_ DWORD cpMEMs, _In_ DWORD flags); /* * Write memory in various non-contigious locations specified by the pointers to * the items in the ppMEMs array. Result for each unit of work will be given * individually. No upper limit of number of items to write Max size of each * unit of work is one 4k page (4096 bytes). Writes must not cross 4k page boundaries. +* -- hVMM * -- dwPID - PID of target process, (DWORD)-1 to write physical memory. * -- ppMEMs = array of scatter read headers. * -- cpMEMs = count of ppMEMs. * -- return = the number of hopefully successfully written items. */ EXPORTED_FUNCTION -DWORD VMMDLL_MemWriteScatter(_In_ DWORD dwPID, _Inout_ PPMEM_SCATTER ppMEMs, _In_ DWORD cpMEMs); +DWORD VMMDLL_MemWriteScatter(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Inout_ PPMEM_SCATTER ppMEMs, _In_ DWORD cpMEMs); /* * Read a single 4096-byte page of memory. +* -- hVMM * -- dwPID - PID of target process, (DWORD)-1 to read physical memory. * -- qwA * -- pbPage * -- return = success/fail (depending if all requested bytes are read or not). */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_MemReadPage(_In_ DWORD dwPID, _In_ ULONG64 qwA, _Inout_bytecount_(4096) PBYTE pbPage); +BOOL VMMDLL_MemReadPage(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ ULONG64 qwA, _Inout_bytecount_(4096) PBYTE pbPage); /* * Read a contigious arbitrary amount of memory. +* -- hVMM * -- dwPID - PID of target process, (DWORD)-1 to read physical memory. * -- qwA * -- pb @@ -704,10 +765,11 @@ BOOL VMMDLL_MemReadPage(_In_ DWORD dwPID, _In_ ULONG64 qwA, _Inout_bytecount_(40 * -- return = success/fail (depending if all requested bytes are read or not). */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_MemRead(_In_ DWORD dwPID, _In_ ULONG64 qwA, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb); +BOOL VMMDLL_MemRead(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ ULONG64 qwA, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb); /* * Read a contigious amount of memory and report the number of bytes read in pcbRead. +* -- hVMM * -- dwPID - PID of target process, (DWORD)-1 to read physical memory. * -- qwA * -- pb @@ -718,19 +780,20 @@ BOOL VMMDLL_MemRead(_In_ DWORD dwPID, _In_ ULONG64 qwA, _Out_writes_(cb) PBYTE p * read - it's recommended to verify pcbReadOpt parameter. */ EXPORTED_FUNCTION _Success_(return) -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_MemReadEx(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ ULONG64 qwA, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ ULONG64 flags); /* * Prefetch a number of addresses (specified in the pA array) into the memory * cache. This function is to be used to batch larger known reads into local * cache before making multiple smaller reads - which will then happen from * the cache. Function exists for performance reasons. +* -- hVMM * -- dwPID = PID of target process, (DWORD)-1 for physical memory. * -- pPrefetchAddresses = array of addresses to read into cache. * -- cPrefetchAddresses */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_MemPrefetchPages(_In_ DWORD dwPID, _In_reads_(cPrefetchAddresses) PULONG64 pPrefetchAddresses, _In_ DWORD cPrefetchAddresses); +BOOL VMMDLL_MemPrefetchPages(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_reads_(cPrefetchAddresses) PULONG64 pPrefetchAddresses, _In_ DWORD cPrefetchAddresses); /* * Write a contigious arbitrary amount of memory. Please note some virtual memory @@ -739,6 +802,7 @@ BOOL VMMDLL_MemPrefetchPages(_In_ DWORD dwPID, _In_reads_(cPrefetchAddresses) PU * in one process is likely to affect kernel32 in the whole system - in all * processes. Heaps and Stacks and other memory are usually safe to write to. * Please take care when writing to memory! +* -- hVMM * -- dwPID = PID of target process, (DWORD)-1 to read physical memory. * -- qwA * -- pb @@ -746,18 +810,19 @@ BOOL VMMDLL_MemPrefetchPages(_In_ DWORD dwPID, _In_reads_(cPrefetchAddresses) PU * -- return = TRUE on success, FALSE on partial or zero write. */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_MemWrite(_In_ DWORD dwPID, _In_ ULONG64 qwA, _In_reads_(cb) PBYTE pb, _In_ DWORD cb); +BOOL VMMDLL_MemWrite(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ ULONG64 qwA, _In_reads_(cb) PBYTE pb, _In_ DWORD cb); /* * Translate a virtual address to a physical address by walking the page tables * of the specified process. +* -- hVMM * -- dwPID * -- qwVA * -- pqwPA * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_MemVirt2Phys(_In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PULONG64 pqwPA); +BOOL VMMDLL_MemVirt2Phys(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ ULONG64 qwVA, _Out_ PULONG64 pqwPA); @@ -784,12 +849,13 @@ typedef HANDLE VMMDLL_SCATTER_HANDLE; /* * Initialize a scatter handle which is used to call VMMDLL_Scatter_* functions. * CALLER CLOSE: VMMDLL_Scatter_CloseHandle(return) +* -- hVMM * -- dwPID - PID of target process, (DWORD)-1 to read physical memory. * -- flags = optional flags as given by VMMDLL_FLAG_* * -- return = handle to be used in VMMDLL_Scatter_* functions. */ EXPORTED_FUNCTION _Success_(return != NULL) -VMMDLL_SCATTER_HANDLE VMMDLL_Scatter_Initialize(_In_ DWORD dwPID, _In_ DWORD flags); +VMMDLL_SCATTER_HANDLE VMMDLL_Scatter_Initialize(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ DWORD flags); /* * Prepare (add) a memory range for reading. The memory may after a call to @@ -898,7 +964,7 @@ VOID VMMDLL_Scatter_CloseHandle(_In_opt_ _Post_ptr_invalid_ VMMDLL_SCATTER_HANDL #define VMMDLL_MAP_HEAP_VERSION 4 #define VMMDLL_MAP_HEAPALLOC_VERSION 1 #define VMMDLL_MAP_THREAD_VERSION 4 -#define VMMDLL_MAP_HANDLE_VERSION 2 +#define VMMDLL_MAP_HANDLE_VERSION 3 #define VMMDLL_MAP_POOL_VERSION 2 #define VMMDLL_MAP_NET_VERSION 3 #define VMMDLL_MAP_PHYSMEM_VERSION 2 @@ -1139,7 +1205,7 @@ typedef struct tdVMMDLL_MAP_HANDLEENTRY { DWORD _FutureUse2; DWORD dwPID; DWORD dwPoolTag; - DWORD _FutureUse[5]; + DWORD _FutureUse[7]; union { LPSTR uszType; LPWSTR wszType; QWORD _Pad1; }; // U/W dependant } VMMDLL_MAP_HANDLEENTRY, *PVMMDLL_MAP_HANDLEENTRY; @@ -1392,173 +1458,165 @@ typedef struct tdVMMDLL_MAP_SERVICE { } VMMDLL_MAP_SERVICE, *PVMMDLL_MAP_SERVICE; /* -* Retrieve the memory map entries based on hardware page tables (PTE) for the -* process. If pPteMap is set to NULL the number of bytes required will be -* returned in parameter pcbPteMap. +* Retrieve the memory map entries based on hardware page tables (PTEs) for the process. * Entries returned are sorted on VMMDLL_MAP_PTEENTRY.va +* CALLER FREE: VMMDLL_MemFree(*ppVadMap) +* -- hVMM * -- dwPID -* -- pPteMap = buffer of minimum byte length *pcbPteMap or NULL. -* -- pcbPteMap = pointer to byte count of pPteMap buffer. * -- fIdentifyModules = try identify modules as well (= slower) +* -- ppPteMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetPteU(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbPteMap) PVMMDLL_MAP_PTE pPteMap, _Inout_ PDWORD pcbPteMap, _In_ BOOL fIdentifyModules); -_Success_(return) BOOL VMMDLL_Map_GetPteW(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbPteMap) PVMMDLL_MAP_PTE pPteMap, _Inout_ PDWORD pcbPteMap, _In_ BOOL fIdentifyModules); +_Success_(return) BOOL VMMDLL_Map_GetPteU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ BOOL fIdentifyModules, _Out_ PVMMDLL_MAP_PTE *ppPteMap); +_Success_(return) BOOL VMMDLL_Map_GetPteW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ BOOL fIdentifyModules, _Out_ PVMMDLL_MAP_PTE *ppPteMap); /* -* Retrieve memory map entries based on virtual address descriptor (VAD) for -* the process. If pVadMap is set to NULL the number of bytes required -* will be returned in parameter pcbVadMap. +* Retrieve memory map entries based on virtual address descriptor (VAD) for the process. * Entries returned are sorted on VMMDLL_MAP_VADENTRY.vaStart +* CALLER FREE: VMMDLL_MemFree(*ppVadMap) +* -- hVMM * -- dwPID -* -- pVadMap = buffer of minimum byte length *pcbVadMap or NULL. -* -- pcbVadMap = pointer to byte count of pVadMap buffer. * -- fIdentifyModules = try identify modules as well (= slower) +* -- ppVadMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetVadU(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbVadMap) PVMMDLL_MAP_VAD pVadMap, _Inout_ PDWORD pcbVadMap, _In_ BOOL fIdentifyModules); -_Success_(return) BOOL VMMDLL_Map_GetVadW(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbVadMap) PVMMDLL_MAP_VAD pVadMap, _Inout_ PDWORD pcbVadMap, _In_ BOOL fIdentifyModules); +_Success_(return) BOOL VMMDLL_Map_GetVadU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ BOOL fIdentifyModules, _Out_ PVMMDLL_MAP_VAD *ppVadMap); +_Success_(return) BOOL VMMDLL_Map_GetVadW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ BOOL fIdentifyModules, _Out_ PVMMDLL_MAP_VAD *ppVadMap); /* -* Retrieve extended memory map information about a select sub-set of the memory -* map. If pVadExMap is set to NULL the number of bytes required will be -* returned in the parameter pcbVadExMap. -* -- dwPID -* -- pVadExMap = buffer of minimum byte length *pcbVadExMap or NULL. -* -- pcbVadExMap = pointer to byte count of pVadExMap buffer. +* Retrieve extended memory map information about a sub-set of the memory map. +* CALLER FREE: VMMDLL_MemFree(*ppVadExMap) +* -- hVMM * -- oPage = offset in number of pages from process start. * -- cPage = number of pages to process from oPages base. +* -- ppVadExMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) -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_GetVadEx(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ DWORD oPage, _In_ DWORD cPage, _Out_ PVMMDLL_MAP_VADEX *ppVadExMap); /* -* Retrieve the modules (.dlls) for the specified process. If pModuleMap is set -* to NULL the number of bytes required will be returned in parameter pcbModuleMap. +* Retrieve the modules (.dlls) for the specified process. +* CALLER FREE: VMMDLL_MemFree(*ppModuleMap) +* -- hVMM * -- dwPID -* -- pModuleMap = buffer of minimum byte length *pcbModuleMap or NULL. -* -- pcbModuleMap = pointer to byte count of pModuleMap buffer. +* -- ppModuleMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetModuleU(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbModuleMap) PVMMDLL_MAP_MODULE pModuleMap, _Inout_ PDWORD pcbModuleMap); -_Success_(return) BOOL VMMDLL_Map_GetModuleW(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbModuleMap) PVMMDLL_MAP_MODULE pModuleMap, _Inout_ PDWORD pcbModuleMap); +_Success_(return) BOOL VMMDLL_Map_GetModuleU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_MODULE *ppModuleMap); +_Success_(return) BOOL VMMDLL_Map_GetModuleW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_MODULE *ppModuleMap); /* * Retrieve a module (.dll) entry given a process and module name. -* If pModuleMapEntry is set to NULL the number of bytes required -* will be returned in parameter pcbModuleMapEntry. -* If pcbModuleMapEntry is set to NULL the pModuleMapEntry is assumed to be of -* size sizeof(VMMDLL_MAP_MODULEENTRY) and data without names will be copied. +* CALLER FREE: VMMDLL_MemFree(*ppModuleMapEntry) +* -- hVMM * -- dwPID * -- [uw]szModuleName = module name (or ""/NULL for 1st module entry). -* -- pModuleMapEntry = buffer of minimum byte length *pcbModuleMapEntry or NULL. -* -- pcbModuleMapEntry = pointer to byte count of pModuleMapEntry buffer or NULL. +* -- ppModuleMapEntry = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetModuleFromNameU(_In_ DWORD dwPID, _In_opt_ LPSTR uszModuleName, _Out_writes_bytes_opt_(*pcbModuleMapEntry) PVMMDLL_MAP_MODULEENTRY pModuleMapEntry, _Inout_opt_ PDWORD pcbModuleMapEntry); -_Success_(return) BOOL VMMDLL_Map_GetModuleFromNameW(_In_ DWORD dwPID, _In_opt_ LPWSTR wszModuleName, _Out_writes_bytes_opt_(*pcbModuleMapEntry) PVMMDLL_MAP_MODULEENTRY pModuleMapEntry, _Inout_opt_ PDWORD pcbModuleMapEntry); +_Success_(return) BOOL VMMDLL_Map_GetModuleFromNameU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_opt_ LPSTR uszModuleName, _Out_ PVMMDLL_MAP_MODULEENTRY *ppModuleMapEntry); +_Success_(return) BOOL VMMDLL_Map_GetModuleFromNameW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_opt_ LPWSTR wszModuleName, _Out_ PVMMDLL_MAP_MODULEENTRY *ppModuleMapEntry); /* -* Retrieve the unloaded modules (.dll/.sys) for the specified process. If -* pUnloadedModuleMap is set to NULL the number of bytes required will be -* returned in parameter pcbUnloadedModuleMap. +* Retrieve the unloaded modules (.dll/.sys) for the specified process. +* CALLER FREE: VMMDLL_MemFree(*ppUnloadedModuleMap) +* -- hVMM * -- dwPID -* -- pUnloadedModuleMap = buffer of minimum byte length *pcbUnloadedModuleMap or NULL. -* -- pcbUnloadedModuleMap = pointer to byte count of pUnloadedModuleMap buffer. +* -- ppUnloadedModuleMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetUnloadedModuleU(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbUnloadedModuleMap) PVMMDLL_MAP_UNLOADEDMODULE pUnloadedModuleMap, _Inout_ PDWORD pcbUnloadedModuleMap); -_Success_(return) BOOL VMMDLL_Map_GetUnloadedModuleW(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbUnloadedModuleMap) PVMMDLL_MAP_UNLOADEDMODULE pUnloadedModuleMap, _Inout_ PDWORD pcbUnloadedModuleMap); +_Success_(return) BOOL VMMDLL_Map_GetUnloadedModuleU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_UNLOADEDMODULE *ppUnloadedModuleMap); +_Success_(return) BOOL VMMDLL_Map_GetUnloadedModuleW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_UNLOADEDMODULE *ppUnloadedModuleMap); /* * Retrieve the module exported functions from the export address table (EAT). -* If pEatMap is set to NULL the number of bytes required will be returned in -* parameter pcbEatMap. +* CALLER FREE: VMMDLL_MemFree(*ppEatMap) +* -- hVMM * -- dwPID * -- [uw]szModuleName -* -- pEatMap = buffer of minimum byte length *pcbEatMap or NULL. -* -- pcbEatMap = pointer to byte count of pEatMap buffer. +* -- ppEatMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetEATU(_In_ DWORD dwPID, _In_ LPSTR uszModuleName, _Out_writes_bytes_opt_(*pcbEatMap) PVMMDLL_MAP_EAT pEatMap, _Inout_ PDWORD pcbEatMap); -_Success_(return) BOOL VMMDLL_Map_GetEATW(_In_ DWORD dwPID, _In_ LPWSTR wszModuleName, _Out_writes_bytes_opt_(*pcbEatMap) PVMMDLL_MAP_EAT pEatMap, _Inout_ PDWORD pcbEatMap); +_Success_(return) BOOL VMMDLL_Map_GetEATU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPSTR uszModuleName, _Out_ PVMMDLL_MAP_EAT *ppEatMap); +_Success_(return) BOOL VMMDLL_Map_GetEATW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPWSTR wszModuleName, _Out_ PVMMDLL_MAP_EAT *ppEatMap); /* * Retrieve the module imported functions from the import address table (IAT). -* If pIatMap is set to NULL the number of bytes required will be returned in -* parameter pcbIatMap. +* CALLER FREE: VMMDLL_MemFree(*ppIatMap) +* -- hVMM * -- dwPID * -- [uw]szModuleName -* -- pIatMap = buffer of minimum byte length *pcbIatMap or NULL. -* -- pcbIatMap = pointer to byte count of pIatMap buffer. +* -- ppIatMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetIATU(_In_ DWORD dwPID, _In_ LPSTR uszModuleName, _Out_writes_bytes_opt_(*pcbIatMap) PVMMDLL_MAP_IAT pIatMap, _Inout_ PDWORD pcbIatMap); -_Success_(return) BOOL VMMDLL_Map_GetIATW(_In_ DWORD dwPID, _In_ LPWSTR wszModuleName, _Out_writes_bytes_opt_(*pcbIatMap) PVMMDLL_MAP_IAT pIatMap, _Inout_ PDWORD pcbIatMap); +_Success_(return) BOOL VMMDLL_Map_GetIATU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPSTR uszModuleName, _Out_ PVMMDLL_MAP_IAT *ppIatMap); +_Success_(return) BOOL VMMDLL_Map_GetIATW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPWSTR wszModuleName, _Out_ PVMMDLL_MAP_IAT *ppIatMap); /* * Retrieve the heaps for the specified process. -* CALLER VMMDLL_MemFree: *ppHeapMap +* CALLER FREE: VMMDLL_MemFree(*ppHeapMap) +* -- hVMM * -- dwPID * -- ppHeapMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetHeapEx(_In_ DWORD dwPID, _Out_ PVMMDLL_MAP_HEAP *ppHeapMap); +_Success_(return) BOOL VMMDLL_Map_GetHeap(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_HEAP *ppHeapMap); /* * Retrieve heap allocations for the specified process heap. -* CALLER VMMDLL_MemFree: *ppHeapAllocMap +* CALLER FREE: VMMDLL_MemFree(*ppHeapAllocMap) +* -- hVMM * -- dwPID * -- qwHeapNumOrAddress = number or virtual address of heap to retrieve allocations from. * -- ppHeapAllocMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetHeapAllocEx(_In_ DWORD dwPID, _In_ QWORD qwHeapNumOrAddress, _Out_ PVMMDLL_MAP_HEAPALLOC *ppHeapAllocMap); +_Success_(return) BOOL VMMDLL_Map_GetHeapAlloc(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ QWORD qwHeapNumOrAddress, _Out_ PVMMDLL_MAP_HEAPALLOC *ppHeapAllocMap); /* -* Retrieve the threads for the specified process. If pThreadMap is set to NULL -* the number of bytes required will be returned in parameter pcbThreadMap. +* Retrieve the threads for the specified process. * Entries returned are sorted on VMMDLL_MAP_THREADENTRY.dwTID +* CALLER FREE: VMMDLL_MemFree(*ppThreadMap) +* -- hVMM * -- dwPID -* -- pThreadMap = buffer of minimum byte length *pcbThreadMap or NULL. -* -- pcbThreadMap = pointer to byte count of pThreadMap buffer. +* -- ppThreadMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetThread(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbThreadMap) PVMMDLL_MAP_THREAD pThreadMap, _Inout_ PDWORD pcbThreadMap); +_Success_(return) BOOL VMMDLL_Map_GetThread(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_THREAD *ppThreadMap); /* -* Retrieve the handles for the specified process. If pHandleMap is set to NULL -* the number of bytes required will be returned in parameter pcbHandleMap. +* Retrieve the handles for the specified process. * Entries returned are sorted on VMMDLL_MAP_HANDLEENTRY.dwHandle +* CALLER FREE: VMMDLL_MemFree(*ppHandleMap) +* -- hVMM * -- dwPID -* -- pHandleMap = buffer of minimum byte length *pcbHandleMap or NULL. -* -- pcbHandleMap = pointer to byte count of pHandleMap buffer. +* -- ppHandleMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetHandleU(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbHandleMap) PVMMDLL_MAP_HANDLE pHandleMap, _Inout_ PDWORD pcbHandleMap); -_Success_(return) BOOL VMMDLL_Map_GetHandleW(_In_ DWORD dwPID, _Out_writes_bytes_opt_(*pcbHandleMap) PVMMDLL_MAP_HANDLE pHandleMap, _Inout_ PDWORD pcbHandleMap); +_Success_(return) BOOL VMMDLL_Map_GetHandleU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_HANDLE *ppHandleMap); +_Success_(return) BOOL VMMDLL_Map_GetHandleW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _Out_ PVMMDLL_MAP_HANDLE *ppHandleMap); /* -* Retrieve the physical memory ranges from the physical memory map that Windows -* have enumerated. -* -- pPhysMemMap = buffer of minimum byte length *pcbPhysMemMap or NULL. -* -- pcbPhysMemMap = pointer to byte count of pPhysMemMap buffer. +* Retrieve the physical memory ranges from the operating system physical memory map. +* CALLER FREE: VMMDLL_MemFree(*ppPhysMemMap) +* -- hVMM +* -- ppPhysMemMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree() * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetPhysMem(_Out_writes_bytes_opt_(*pcbPhysMemMap) PVMMDLL_MAP_PHYSMEM pPhysMemMap, _Inout_ PDWORD pcbPhysMemMap); +_Success_(return) BOOL VMMDLL_Map_GetPhysMem(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_PHYSMEM *ppPhysMemMap); /* * Retrieve the pool map - consisting of kernel allocated pool entries. @@ -1568,62 +1626,51 @@ _Success_(return) BOOL VMMDLL_Map_GetPhysMem(_Out_writes_bytes_opt_(*pcbPhysMemM * NB! The pool map relies on debug symbols. Please ensure supporting files * symsrv.dll, dbghelp.dll and info.db (found in the binary distribution) * is put alongside vmm.dll. (On Linux the .dll files aren't necessary). -* -- pPoolMap = buffer of minimum byte length *pcbPoolMap or NULL. -* -- pcbPoolMap = pointer to byte count of pPoolMap buffer. -* -- return = success/fail. -*/ -EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetPool(_Out_writes_bytes_opt_(*pcbPoolMap) PVMMDLL_MAP_POOL pPoolMap, _Inout_ PDWORD pcbPoolMap); - -/* -* Retrieve the pool map - consisting of kernel allocated pool entries. -* The pool map pMap is sorted by allocation virtual address. -* The pool map pTag is sorted by pool tag. -* NB! The pool map may contain both false negatives/positives. -* NB! The pool map relies on debug symbols. Please ensure supporting files -* symsrv.dll, dbghelp.dll and info.db (found in the binary distribution) -* is put alongside vmm.dll. (On Linux the .dll files aren't necessary). -* CALLER VMMDLL_MemFree: *ppPoolMap +* CALLER FREE: VMMDLL_MemFree(*ppPoolMap) +* -- hVMM * -- ppPoolMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- flags = VMMDLL_POOLMAP_FLAG* * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetPoolEx(_Out_ PVMMDLL_MAP_POOL* ppPoolMap, _In_ DWORD flags); +_Success_(return) BOOL VMMDLL_Map_GetPool(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_POOL *ppPoolMap, _In_ DWORD flags); /* * Retrieve the network connection map - consisting of active network connections, * listening sockets and other networking functionality. -* -- pNetMap = buffer of minimum byte length *pcbNetMap or NULL. -* -- pcbNetMap = pointer to byte count of pNetMap buffer. +* CALLER FREE: VMMDLL_MemFree(*ppNetMap) +* -- hVMM +* -- ppNetMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetNetU(_Out_writes_bytes_opt_(*pcbNetMap) PVMMDLL_MAP_NET pNetMap, _Inout_ PDWORD pcbNetMap); -_Success_(return) BOOL VMMDLL_Map_GetNetW(_Out_writes_bytes_opt_(*pcbNetMap) PVMMDLL_MAP_NET pNetMap, _Inout_ PDWORD pcbNetMap); +_Success_(return) BOOL VMMDLL_Map_GetNetU(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_NET *ppNetMap); +_Success_(return) BOOL VMMDLL_Map_GetNetW(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_NET *ppNetMap); /* * Retrieve the non well known users that are detected in the target system. * NB! There may be more users in the system than the ones that are detected, * only users with mounted registry hives may currently be detected - this is * the normal behaviour for users with active processes. -* -- pUserMap = buffer of minimum byte length *pcbUserMap or NULL. -* -- pcbUserMap = pointer to byte count of pUserMap buffer. +* CALLER FREE: VMMDLL_MemFree(*ppUserMap) +* -- hVMM +* -- ppUserMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetUsersU(_Out_writes_bytes_opt_(*pcbUserMap) PVMMDLL_MAP_USER pUserMap, _Inout_ PDWORD pcbUserMap); -_Success_(return) BOOL VMMDLL_Map_GetUsersW(_Out_writes_bytes_opt_(*pcbUserMap) PVMMDLL_MAP_USER pUserMap, _Inout_ PDWORD pcbUserMap); +_Success_(return) BOOL VMMDLL_Map_GetUsersU(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_USER *ppUserMap); +_Success_(return) BOOL VMMDLL_Map_GetUsersW(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_USER *ppUserMap); /* * Retrieve the services currently known by the service control manager (SCM). -* -- pServiceMap = buffer of minimum byte length *pcbServiceMap or NULL. -* -- pcbServiceMap = pointer to byte count of pServiceMap buffer. +* CALLER FREE: VMMDLL_MemFree(*ppServiceMap) +* -- hVMM +* -- ppServiceMap = ptr to receive result on success. must be free'd with VMMDLL_MemFree(). * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_Map_GetServicesU(_Out_writes_bytes_opt_(*pcbServiceMap) PVMMDLL_MAP_SERVICE pServiceMap, _Inout_ PDWORD pcbServiceMap); -_Success_(return) BOOL VMMDLL_Map_GetServicesW(_Out_writes_bytes_opt_(*pcbServiceMap) PVMMDLL_MAP_SERVICE pServiceMap, _Inout_ PDWORD pcbServiceMap); +_Success_(return) BOOL VMMDLL_Map_GetServicesU(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_SERVICE *ppServiceMap); +_Success_(return) BOOL VMMDLL_Map_GetServicesW(_In_ VMM_HANDLE hVMM, _Out_ PVMMDLL_MAP_SERVICE *ppServiceMap); @@ -1680,6 +1727,7 @@ typedef struct tdVMMDLL_MEM_SEARCH_CONTEXT { * To cancel a search prematurely set the fAbortRequested flag in the context * and wait a short while. * CALLER FREE: VMMDLL_MemFree(*ppva) +* -- hVMM * -- dwPID * -- ctx * -- ppva = pointer to receive addresses found. Free'd with VMMDLL_MemFree(). @@ -1687,7 +1735,13 @@ typedef struct tdVMMDLL_MEM_SEARCH_CONTEXT { * -- return */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_MemSearch(_In_ DWORD dwPID, _Inout_ PVMMDLL_MEM_SEARCH_CONTEXT ctx, _Out_opt_ PQWORD *ppva, _Out_opt_ PDWORD pcva); +BOOL VMMDLL_MemSearch( + _In_ VMM_HANDLE hVMM, + _In_ DWORD dwPID, + _Inout_ PVMMDLL_MEM_SEARCH_CONTEXT ctx, + _Out_opt_ PQWORD *ppva, + _Out_opt_ PDWORD pcva +); @@ -1775,6 +1829,7 @@ typedef struct tdVMMDLL_MAP_PFN { /* * Retrieve information about scattered PFNs. The PFNs are returned in order of * in which they are stored in the pPfns set. +* -- hVMM * -- pPfns * -- cPfns * -- pPfnMap = buffer of minimum byte length *pcbPfnMap or NULL. @@ -1782,7 +1837,13 @@ typedef struct tdVMMDLL_MAP_PFN { * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) -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_GetPfn( + _In_ VMM_HANDLE hVMM, + _In_ DWORD pPfns[], + _In_ DWORD cPfns, + _Out_writes_bytes_opt_(*pcbPfnMap) PVMMDLL_MAP_PFN pPfnMap, + _Inout_ PDWORD pcbPfnMap +); @@ -1796,21 +1857,23 @@ BOOL VMMDLL_Map_GetPfn(_In_ DWORD pPfns[], _In_ DWORD cPfns, _Out_writes_bytes_o * processes with the same name exists only one will be returned. If required to * parse all processes with the same name please iterate over the PID list by * calling VMMDLL_PidList together with VMMDLL_ProcessGetInformation. +* -- hVMM * -- szProcName = process name case insensitive. * -- pdwPID = pointer that will receive PID on success. * -- return */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_PidGetFromName(_In_ LPSTR szProcName, _Out_ PDWORD pdwPID); +BOOL VMMDLL_PidGetFromName(_In_ VMM_HANDLE hVMM, _In_ LPSTR szProcName, _Out_ PDWORD pdwPID); /* * List the PIDs in the system. +* -- hVMM * -- pPIDs = DWORD array of at least number of PIDs in system, or NULL. * -- pcPIDs = size of (in number of DWORDs) pPIDs array on entry, number of PIDs in system on exit. * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_PidList(_Out_writes_opt_(*pcPIDs) PDWORD pPIDs, _Inout_ PULONG64 pcPIDs); +BOOL VMMDLL_PidList(_In_ VMM_HANDLE hVMM, _Out_writes_opt_(*pcPIDs) PDWORD pPIDs, _Inout_ PSIZE_T pcPIDs); #define VMMDLL_PROCESS_INFORMATION_MAGIC 0xc0ffee663df9301e #define VMMDLL_PROCESS_INFORMATION_VERSION 7 @@ -1856,13 +1919,19 @@ typedef struct tdVMMDLL_PROCESS_INFORMATION { /* * Retrieve various process information from a PID. Process information such as * name, page directory bases and the process state may be retrieved. +* -- hVMM * -- dwPID * -- pProcessInformation = if null, size is given in *pcbProcessInfo * -- pcbProcessInformation = size of pProcessInfo (in bytes) on entry and exit * -- return = success/fail. */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_ProcessGetInformation(_In_ DWORD dwPID, _Inout_opt_ PVMMDLL_PROCESS_INFORMATION pProcessInformation, _In_ PSIZE_T pcbProcessInformation); +BOOL VMMDLL_ProcessGetInformation( + _In_ VMM_HANDLE hVMM, + _In_ DWORD dwPID, + _Inout_opt_ PVMMDLL_PROCESS_INFORMATION pProcessInformation, + _In_ PSIZE_T pcbProcessInformation +); #define VMMDLL_PROCESS_INFORMATION_OPT_STRING_PATH_KERNEL 1 #define VMMDLL_PROCESS_INFORMATION_OPT_STRING_PATH_USER_IMAGE 2 @@ -1874,18 +1943,20 @@ BOOL VMMDLL_ProcessGetInformation(_In_ DWORD dwPID, _Inout_opt_ PVMMDLL_PROCESS_ * NULL terminated. On failure NULL is returned. * NB! CALLER IS RESPONSIBLE FOR VMMDLL_MemFree return value! * CALLER FREE: VMMDLL_MemFree(return) +* -- hVMM * -- dwPID * -- fOptionString = string value to retrieve as given by VMMDLL_PROCESS_INFORMATION_OPT_STRING_* * -- return - fail: NULL, success: the string - NB! must be VMMDLL_MemFree'd by caller! */ -EXPORTED_FUNCTION -LPSTR VMMDLL_ProcessGetInformationString(_In_ DWORD dwPID, _In_ DWORD fOptionString); +EXPORTED_FUNCTION _Success_(return != NULL) +LPSTR VMMDLL_ProcessGetInformationString(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ DWORD fOptionString); /* * Retrieve information about: Data Directories, Sections, Export Address Table * and Import Address Table (IAT). * If the pData == NULL upon entry the number of entries of the pData array must * have in order to be able to hold the data is returned. +* -- hVMM * -- dwPID * -- [uw]szModule * -- pData @@ -1894,32 +1965,34 @@ LPSTR VMMDLL_ProcessGetInformationString(_In_ DWORD dwPID, _In_ DWORD fOptionStr * -- return = success/fail. */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_ProcessGetDirectoriesU(_In_ DWORD dwPID, _In_ LPSTR uszModule, _Out_writes_(16) PIMAGE_DATA_DIRECTORY pData, _In_ DWORD cData, _Out_ PDWORD pcData); -_Success_(return) BOOL VMMDLL_ProcessGetDirectoriesW(_In_ DWORD dwPID, _In_ LPWSTR wszModule, _Out_writes_(16) PIMAGE_DATA_DIRECTORY pData, _In_ DWORD cData, _Out_ PDWORD pcData); +_Success_(return) BOOL VMMDLL_ProcessGetDirectoriesU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPSTR uszModule, _Out_writes_(16) PIMAGE_DATA_DIRECTORY pDataDirectories); +_Success_(return) BOOL VMMDLL_ProcessGetDirectoriesW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPWSTR wszModule, _Out_writes_(16) PIMAGE_DATA_DIRECTORY pDataDirectories); EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_ProcessGetSectionsU(_In_ DWORD dwPID, _In_ LPSTR uszModule, _Out_opt_ PIMAGE_SECTION_HEADER pData, _In_ DWORD cData, _Out_ PDWORD pcData); -_Success_(return) BOOL VMMDLL_ProcessGetSectionsW(_In_ DWORD dwPID, _In_ LPWSTR wszModule, _Out_opt_ PIMAGE_SECTION_HEADER pData, _In_ DWORD cData, _Out_ PDWORD pcData); +_Success_(return) BOOL VMMDLL_ProcessGetSectionsU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPSTR uszModule, _Out_writes_opt_(cSections) PIMAGE_SECTION_HEADER pSections, _In_ DWORD cSections, _Out_ PDWORD pcSections); +_Success_(return) BOOL VMMDLL_ProcessGetSectionsW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPWSTR wszModule, _Out_writes_opt_(cSections) PIMAGE_SECTION_HEADER pSections, _In_ DWORD cSections, _Out_ PDWORD pcSections); /* * Retrieve the virtual address of a given function inside a process/module. +* -- hVMM * -- dwPID * -- [uw]szModuleName * -- szFunctionName * -- return = virtual address of function, zero on fail. */ EXPORTED_FUNCTION -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_ProcessGetProcAddressU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPSTR uszModuleName, _In_ LPSTR szFunctionName); +ULONG64 VMMDLL_ProcessGetProcAddressW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPWSTR wszModuleName, _In_ LPSTR szFunctionName); /* * Retrieve the base address of a given module. +* -- hVMM * -- dwPID * -- [uw]szModuleName * -- return = virtual address of module base, zero on fail. */ EXPORTED_FUNCTION -ULONG64 VMMDLL_ProcessGetModuleBaseU(_In_ DWORD dwPID, _In_ LPSTR uszModuleName); -ULONG64 VMMDLL_ProcessGetModuleBaseW(_In_ DWORD dwPID, _In_ LPWSTR wszModuleName); +ULONG64 VMMDLL_ProcessGetModuleBaseU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPSTR uszModuleName); +ULONG64 VMMDLL_ProcessGetModuleBaseW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPWSTR wszModuleName); @@ -1929,18 +2002,25 @@ ULONG64 VMMDLL_ProcessGetModuleBaseW(_In_ DWORD dwPID, _In_ LPWSTR wszModuleName /* * Load a .pdb symbol file and return its associated module name upon success. +* -- hVMM * -- dwPID * -- vaModuleBase * -- szModuleName = buffer to receive module name upon success. * -- return */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_PdbLoad(_In_ DWORD dwPID, _In_ ULONG64 vaModuleBase, _Out_writes_(MAX_PATH) LPSTR szModuleName); +BOOL VMMDLL_PdbLoad( + _In_ VMM_HANDLE hVMM, + _In_ DWORD dwPID, + _In_ ULONG64 vaModuleBase, + _Out_writes_(MAX_PATH) LPSTR szModuleName +); /* * Retrieve a symbol virtual address given a module name and a symbol name. * NB! not all modules may exist - initially only module "nt" is available. * NB! if multiple modules have the same name the 1st to be added will be used. +* -- hVMM * -- szModule * -- cbSymbolAddressOrOffset = symbol virtual address or symbol offset. * -- szSymbolName = buffer to receive symbol name upon success. @@ -1948,36 +2028,55 @@ BOOL VMMDLL_PdbLoad(_In_ DWORD dwPID, _In_ ULONG64 vaModuleBase, _Out_writes_(MA * -- return */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_PdbSymbolName(_In_ LPSTR szModule, _In_ QWORD cbSymbolAddressOrOffset, _Out_writes_(MAX_PATH) LPSTR szSymbolName, _Out_opt_ PDWORD pdwSymbolDisplacement); +BOOL VMMDLL_PdbSymbolName( + _In_ VMM_HANDLE hVMM, + _In_ LPSTR szModule, + _In_ QWORD cbSymbolAddressOrOffset, + _Out_writes_(MAX_PATH) LPSTR szSymbolName, + _Out_opt_ PDWORD pdwSymbolDisplacement +); /* * Retrieve a symbol virtual address given a module name and a symbol name. * NB! not all modules may exist - initially only module "nt" is available. * NB! if multiple modules have the same name the 1st to be added will be used. +* -- hVMM * -- szModule * -- szSymbolName * -- pvaSymbolAddress * -- return */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_PdbSymbolAddress(_In_ LPSTR szModule, _In_ LPSTR szSymbolName, _Out_ PULONG64 pvaSymbolAddress); +BOOL VMMDLL_PdbSymbolAddress( + _In_ VMM_HANDLE hVMM, + _In_ LPSTR szModule, + _In_ LPSTR szSymbolName, + _Out_ PULONG64 pvaSymbolAddress +); /* * Retrieve a type size given a module name and a type name. * NB! not all modules may exist - initially only module "nt" is available. * NB! if multiple modules have the same name the 1st to be added will be used. +* -- hVMM * -- szModule * -- szTypeName * -- pcbTypeSize * -- return */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_PdbTypeSize(_In_ LPSTR szModule, _In_ LPSTR szTypeName, _Out_ PDWORD pcbTypeSize); +BOOL VMMDLL_PdbTypeSize( + _In_ VMM_HANDLE hVMM, + _In_ LPSTR szModule, + _In_ LPSTR szTypeName, + _Out_ PDWORD pcbTypeSize +); /* * Locate the offset of a type child - typically a sub-item inside a struct. * NB! not all modules may exist - initially only module "nt" is available. * NB! if multiple modules have the same name the 1st to be added will be used. +* -- hVMM * -- szModule * -- uszTypeName * -- uszTypeChildName @@ -1985,7 +2084,13 @@ BOOL VMMDLL_PdbTypeSize(_In_ LPSTR szModule, _In_ LPSTR szTypeName, _Out_ PDWORD * -- return */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_PdbTypeChildOffset(_In_ LPSTR szModule, _In_ LPSTR uszTypeName, _In_ LPSTR uszTypeChildName, _Out_ PDWORD pcbTypeChildOffset); +BOOL VMMDLL_PdbTypeChildOffset( + _In_ VMM_HANDLE hVMM, + _In_ LPSTR szModule, + _In_ LPSTR uszTypeName, + _In_ LPSTR uszTypeChildName, + _Out_ PDWORD pcbTypeChildOffset +); @@ -1994,13 +2099,13 @@ BOOL VMMDLL_PdbTypeChildOffset(_In_ LPSTR szModule, _In_ LPSTR uszTypeName, _In_ //----------------------------------------------------------------------------- #define VMMDLL_REGISTRY_HIVE_INFORMATION_MAGIC 0xc0ffee653df8d01e -#define VMMDLL_REGISTRY_HIVE_INFORMATION_VERSION 3 +#define VMMDLL_REGISTRY_HIVE_INFORMATION_VERSION 4 typedef struct td_VMMDLL_REGISTRY_HIVE_INFORMATION { ULONG64 magic; WORD wVersion; WORD wSize; - BYTE _FutureReserved1[0x14]; + BYTE _FutureReserved1[0x34]; ULONG64 vaCMHIVE; ULONG64 vaHBASE_BLOCK; DWORD cbLength; @@ -2012,18 +2117,25 @@ typedef struct td_VMMDLL_REGISTRY_HIVE_INFORMATION { /* * Retrieve information about the registry hives in the target system. -* -- pHives = buffer of cHives * sizeof(VMMDLL_REGISTRY_HIVE_INFORMATION) to receive information about all hives. NULL to receive # hives in pcHives. +* -- pHives = buffer of cHives * sizeof(VMMDLL_REGISTRY_HIVE_INFORMATION) to + receive info about all hives. NULL to receive # hives in pcHives. * -- cHives * -- pcHives = if pHives == NULL: # total hives. if pHives: # read hives. * -- return */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_WinReg_HiveList(_Out_writes_(cHives) PVMMDLL_REGISTRY_HIVE_INFORMATION pHives, _In_ DWORD cHives, _Out_ PDWORD pcHives); +BOOL VMMDLL_WinReg_HiveList( + _In_ VMM_HANDLE hVMM, + _Out_writes_(cHives) PVMMDLL_REGISTRY_HIVE_INFORMATION pHives, + _In_ DWORD cHives, + _Out_ PDWORD pcHives +); /* * Read a contigious arbitrary amount of registry hive memory and report the * number of bytes read in pcbRead. * NB! Address space does not include regf registry hive file header! +* -- hVMM * -- vaCMHive * -- ra * -- pb @@ -2034,11 +2146,20 @@ BOOL VMMDLL_WinReg_HiveList(_Out_writes_(cHives) PVMMDLL_REGISTRY_HIVE_INFORMATI * read - it's recommended to verify pcbReadOpt parameter. */ EXPORTED_FUNCTION _Success_(return) -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_HiveReadEx( + _In_ VMM_HANDLE hVMM, + _In_ ULONG64 vaCMHive, + _In_ DWORD ra, + _Out_ PBYTE pb, + _In_ DWORD cb, + _Out_opt_ PDWORD pcbReadOpt, + _In_ ULONG64 flags +); /* * Write a virtually contigious arbitrary amount of memory to a registry hive. * NB! Address space does not include regf registry hive file header! +* -- hVMM * -- vaCMHive * -- ra * -- pb @@ -2046,7 +2167,13 @@ BOOL VMMDLL_WinReg_HiveReadEx(_In_ ULONG64 vaCMHive, _In_ DWORD ra, _Out_ PBYTE * -- return = TRUE on success, FALSE on partial or zero write. */ EXPORTED_FUNCTION _Success_(return) -BOOL VMMDLL_WinReg_HiveWrite(_In_ ULONG64 vaCMHive, _In_ DWORD ra, _In_ PBYTE pb, _In_ DWORD cb); +BOOL VMMDLL_WinReg_HiveWrite( + _In_ VMM_HANDLE hVMM, + _In_ ULONG64 vaCMHive, + _In_ DWORD ra, + _In_ PBYTE pb, + _In_ DWORD cb +); /* * Enumerate registry sub keys - similar to WINAPI function 'RegEnumKeyExW.' @@ -2056,6 +2183,7 @@ BOOL VMMDLL_WinReg_HiveWrite(_In_ ULONG64 vaCMHive, _In_ DWORD ra, _In_ PBYTE pb * 2) 'HKLM\ORPHAN\SAM\Key\SubKey' (orphan key) * 3) '0x\ROOT\Key\SubKey' * 4) '0x\ORPHAN\Key\SubKey' (orphan key) +* -- hVMM * -- uszFullPathKey * -- dwIndex = sub-key index 0..N (-1 for key). * -- lpName @@ -2065,6 +2193,7 @@ BOOL VMMDLL_WinReg_HiveWrite(_In_ ULONG64 vaCMHive, _In_ DWORD ra, _In_ PBYTE pb */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_WinReg_EnumKeyExU( + _In_ VMM_HANDLE hVMM, _In_ LPSTR uszFullPathKey, _In_ DWORD dwIndex, _Out_writes_opt_(*lpcchName) LPSTR lpName, @@ -2081,6 +2210,7 @@ BOOL VMMDLL_WinReg_EnumKeyExU( * 2) 'HKLM\ORPHAN\SAM\Key\SubKey' (orphan key) * 3) '0x\ROOT\Key\SubKey' * 4) '0x\ORPHAN\Key\SubKey' (orphan key) +* -- hVMM * -- uszFullPathKey * -- dwIndex * -- lpValueName @@ -2092,6 +2222,7 @@ BOOL VMMDLL_WinReg_EnumKeyExU( */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_WinReg_EnumValueU( + _In_ VMM_HANDLE hVMM, _In_ LPSTR uszFullPathKey, _In_ DWORD dwIndex, _Out_writes_opt_(*lpcchValueName) LPSTR lpValueName, @@ -2110,6 +2241,7 @@ BOOL VMMDLL_WinReg_EnumValueU( * 2) 'HKLM\ORPHAN\SAM\Key\SubKey\' (orphan key and default value) * 3) '0x\ROOT\Key\SubKey\Value' * 4) '0x\ORPHAN\Key\SubKey\Value' (orphan key value) +* -- hVMM * -- uszFullPathKeyValue * -- lpType * -- lpData @@ -2118,6 +2250,7 @@ BOOL VMMDLL_WinReg_EnumValueU( */ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_WinReg_QueryValueExU( + _In_ VMM_HANDLE hVMM, _In_ LPSTR uszFullPathKeyValue, _Out_opt_ LPDWORD lpType, _Out_writes_opt_(*lpcbData) LPBYTE lpData, @@ -2132,6 +2265,7 @@ BOOL VMMDLL_WinReg_QueryValueExU( * 2) 'HKLM\ORPHAN\SAM\Key\SubKey' (orphan key) * 3) '0x\ROOT\Key\SubKey' * 4) '0x\ORPHAN\Key\SubKey' (orphan key) +* -- hVMM * -- wszFullPathKey * -- dwIndex = sub-key index 0..N (-1 for key). * -- lpName @@ -2141,6 +2275,7 @@ BOOL VMMDLL_WinReg_QueryValueExU( */ _Success_(return) BOOL VMMDLL_WinReg_EnumKeyExW( + _In_ VMM_HANDLE hVMM, _In_ LPWSTR wszFullPathKey, _In_ DWORD dwIndex, _Out_writes_opt_(*lpcchName) LPWSTR lpName, @@ -2157,6 +2292,7 @@ BOOL VMMDLL_WinReg_EnumKeyExW( * 2) 'HKLM\ORPHAN\SAM\Key\SubKey' (orphan key) * 3) '0x\ROOT\Key\SubKey' * 4) '0x\ORPHAN\Key\SubKey' (orphan key) +* -- hVMM * -- wszFullPathKey * -- dwIndex * -- lpValueName @@ -2168,6 +2304,7 @@ BOOL VMMDLL_WinReg_EnumKeyExW( */ _Success_(return) BOOL VMMDLL_WinReg_EnumValueW( + _In_ VMM_HANDLE hVMM, _In_ LPWSTR wszFullPathKey, _In_ DWORD dwIndex, _Out_writes_opt_(*lpcchValueName) LPWSTR lpValueName, @@ -2186,6 +2323,7 @@ BOOL VMMDLL_WinReg_EnumValueW( * 2) 'HKLM\ORPHAN\SAM\Key\SubKey\' (orphan key and default value) * 3) '0x\ROOT\Key\SubKey\Value' * 4) '0x\ORPHAN\Key\SubKey\Value' (orphan key value) +* -- hVMM * -- wszFullPathKeyValue * -- lpType * -- lpData @@ -2194,6 +2332,7 @@ BOOL VMMDLL_WinReg_EnumValueW( */ _Success_(return) BOOL VMMDLL_WinReg_QueryValueExW( + _In_ VMM_HANDLE hVMM, _In_ LPWSTR wszFullPathKeyValue, _Out_opt_ LPDWORD lpType, _Out_writes_opt_(*lpcbData) LPBYTE lpData, @@ -2219,6 +2358,7 @@ typedef struct tdVMMDLL_WIN_THUNKINFO_IAT { * Retrieve information about the import address table IAT thunk for an imported * function. This includes the virtual address of the IAT thunk which is useful * for hooking. +* -- hVMM * -- dwPID * -- [uw]szModuleName * -- szImportModuleName @@ -2227,8 +2367,8 @@ typedef struct tdVMMDLL_WIN_THUNKINFO_IAT { * -- return */ EXPORTED_FUNCTION -_Success_(return) BOOL VMMDLL_WinGetThunkInfoIATU(_In_ DWORD dwPID, _In_ LPSTR uszModuleName, _In_ LPSTR szImportModuleName, _In_ LPSTR szImportFunctionName, _Out_ PVMMDLL_WIN_THUNKINFO_IAT pThunkInfoIAT); -_Success_(return) BOOL VMMDLL_WinGetThunkInfoIATW(_In_ DWORD dwPID, _In_ LPWSTR wszModuleName, _In_ LPSTR szImportModuleName, _In_ LPSTR szImportFunctionName, _Out_ PVMMDLL_WIN_THUNKINFO_IAT pThunkInfoIAT); +_Success_(return) BOOL VMMDLL_WinGetThunkInfoIATU(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPSTR uszModuleName, _In_ LPSTR szImportModuleName, _In_ LPSTR szImportFunctionName, _Out_ PVMMDLL_WIN_THUNKINFO_IAT pThunkInfoIAT); +_Success_(return) BOOL VMMDLL_WinGetThunkInfoIATW(_In_ VMM_HANDLE hVMM, _In_ DWORD dwPID, _In_ LPWSTR wszModuleName, _In_ LPSTR szImportModuleName, _In_ LPSTR szImportFunctionName, _Out_ PVMMDLL_WIN_THUNKINFO_IAT pThunkInfoIAT); diff --git a/vmm/vmmdll_core.c b/vmm/vmmdll_core.c new file mode 100644 index 0000000..4f14a5d --- /dev/null +++ b/vmm/vmmdll_core.c @@ -0,0 +1,739 @@ +// vmmdll_core.c : implementation of core library functionality which mainly +// consists of library initialization and cleanup/close functionality. +// +// (c) Ulf Frisk, 2022 +// Author: Ulf Frisk, pcileech@frizk.net +// + +#include "vmm.h" +#include "vmmdll.h" +#include "vmmlog.h" +#include "vmmproc.h" +#include "vmmwork.h" +#include "ob/ob.h" +#include "ob/ob_tag.h" +#include "charutil.h" +#include "util.h" +#include "fc.h" +#include "statistics.h" +#include "version.h" + +//----------------------------------------------------------------------------- +// INITIALIZATION AND CLOSE FUNCTIONALITY BELOW: +// +// Initialize and Close functionality is put behind a single shared global lock. +//----------------------------------------------------------------------------- + +// globals below: +#define VMM_HANDLE_MAX_COUNT 32 +static POB_MAP g_VMMDLL_ALLOCMAP_EXT = NULL; +static SRWLOCK g_VMMDLL_CORE_LOCK_SRW = SRWLOCK_INIT; +static POB_MAP g_VMMDLL_CORE_ALLHANDLE = NULL; +static DWORD g_VMMDLL_CORE_HANDLE_COUNT = 0; +static VMM_HANDLE g_VMMDLL_CORE_HANDLES[VMM_HANDLE_MAX_COUNT] = { 0 }; + +// forward declarations below: +VOID VmmDllCore_MemLeakFindExternal(_In_ VMM_HANDLE H); + +/* +* Verify that the supplied handle is valid and also check it out. +* This must be called by each external access which requires a VMM_HANDLE. +* Each successful VmmDllCore_HandleReserveExternal() call must be matched by +* a matched call to VmmDllCore_HandleReturnExternal() after completion. +* -- H +* -- return +*/ +_Success_(return) +BOOL VmmDllCore_HandleReserveExternal(_In_opt_ VMM_HANDLE H) +{ + DWORD i = 0; + BOOL fResult = FALSE; + if(!H || ((SIZE_T)H < 0x10000)) { return FALSE;} + AcquireSRWLockShared(&g_VMMDLL_CORE_LOCK_SRW); + for(i = 0; i < g_VMMDLL_CORE_HANDLE_COUNT; i++) { + if(g_VMMDLL_CORE_HANDLES[i] == H) { + InterlockedIncrement(&H->cThreadExternal); + fResult = (H->magic == VMM_MAGIC) && !H->fAbort; + break; + } + } + ReleaseSRWLockShared(&g_VMMDLL_CORE_LOCK_SRW); + return fResult; +} + +/* +* Return a handle successfully reserved with a previous call to the function: +* VmmDllCore_HandleReserveExternal() +* -- H +*/ +VOID VmmDllCore_HandleReturnExternal(_In_ VMM_HANDLE H) +{ + InterlockedDecrement(&H->cThreadExternal); +} + +/* +* Remove a handle from the external handle array. +* NB! Function is to be called behind exclusive lock g_VMMDLL_CORE_LOCK_SRW. +* -- H +*/ +VOID VmmDllCore_HandleRemove(_In_ VMM_HANDLE H) +{ + DWORD i; + if(H && (H->magic == VMM_MAGIC)) { + for(i = 0; i < g_VMMDLL_CORE_HANDLE_COUNT; i++) { + if(g_VMMDLL_CORE_HANDLES[i] == H) { + g_VMMDLL_CORE_HANDLE_COUNT--; + if(i < g_VMMDLL_CORE_HANDLE_COUNT) { + g_VMMDLL_CORE_HANDLES[i] = g_VMMDLL_CORE_HANDLES[g_VMMDLL_CORE_HANDLE_COUNT]; + g_VMMDLL_CORE_HANDLES[g_VMMDLL_CORE_HANDLE_COUNT] = NULL; + } else { + g_VMMDLL_CORE_HANDLES[i] = NULL; + } + break; + } + } + } +} + +/* +* Add a new handle to the external handle array. +* NB! Function is to be called behind exclusive lock g_VMMDLL_CORE_LOCK_SRW. +* -- H +*/ +_Success_(return) +BOOL VmmDllCore_HandleAdd(_In_ VMM_HANDLE H) +{ + if(g_VMMDLL_CORE_HANDLE_COUNT < VMM_HANDLE_MAX_COUNT) { + g_VMMDLL_CORE_HANDLES[g_VMMDLL_CORE_HANDLE_COUNT] = H; + g_VMMDLL_CORE_HANDLE_COUNT++; + return TRUE; + } + return FALSE; +} + +/* +* Close a VMM_HANDLE and clean up everything! The VMM_HANDLE will not be valid +* after this function has been called. Function call may take some time since +* it's dependent on thread-stoppage (which may take time) to do a clean cleanup. +* The strategy is: +* (1) disable external calls (set magic and abort flag) +* (2) wait for worker threads to exit (done on abort) when completed no +* threads except this one should access the handle. +* (3) shut down Forensic > Vmm > LeechCore > Threading > Log +* NB! Function is to be called behind exclusive lock g_VMMDLL_CORE_LOCK_SRW. +* -- H = a VMM_HANDLE fully or partially initialized +*/ +VOID VmmDllCore_CloseHandle(_In_opt_ _Post_ptr_invalid_ VMM_HANDLE H) +{ + QWORD tc, tcStart; + if(H) { + // 1: Remove handle from external allow-list. This will stop external + // API calls using the handle. + VmmDllCore_HandleRemove(H); + // 2: Set the abort flag. This will cause internal threading shutdown. + H->fAbort = TRUE; + H->magic = 0; + // 3: Abort work multithreading & forensic database queries (to speed up termination) + VmmWork_Interrupt(H); + FcInterrupt(H); + // 4: Wait for multi-threading to shut down + tcStart = GetTickCount64(); + while(H->cThreadExternal) { + tc = GetTickCount64(); + if((tc - tcStart) > 30000) { + tcStart = GetTickCount64(); + VmmLog(H, MID_CORE, LOGLEVEL_1_CRITICAL, "Shutdown waiting for long running external thread (%i).", H->cThreadExternal); + VmmWork_Interrupt(H); + FcInterrupt(H); + } + SwitchToThread(); + } + while(H->cThreadInternal) { + tc = GetTickCount64(); + if((tc - tcStart) > 30000) { + tcStart = GetTickCount64(); + VmmLog(H, MID_CORE, LOGLEVEL_1_CRITICAL, "Shutdown waiting for long running internal thread (%i).", H->cThreadExternal); + VmmWork_Interrupt(H); + FcInterrupt(H); + } + SwitchToThread(); + } + // 5: Close forensic sub-system. + FcClose(H); + // Close vmm sub-system. + VmmClose(H); + // Close leechcore + LcClose(H->hLC); + // Close work (multi-threading) + VmmWork_Close(H); + // Warn external (api-user) memory leaks + VmmDllCore_MemLeakFindExternal(H); + // Close logging (last) + Statistics_CallSetEnabled(H, FALSE); + VmmLog_Close(H); + LocalFree(H); + } +} + +/* +* Close a VMM_HANDLE and clean up everything! The VMM_HANDLE will not be valid +* after this function has been called. +* -- H +*/ +VOID VmmDllCore_Close(_In_opt_ _Post_ptr_invalid_ VMM_HANDLE H) +{ + AcquireSRWLockExclusive(&g_VMMDLL_CORE_LOCK_SRW); + VmmDllCore_CloseHandle(H); + ReleaseSRWLockExclusive(&g_VMMDLL_CORE_LOCK_SRW); +} + +/* +* Close all VMM_HANDLE and clean up everything! No VMM_HANDLE will be valid +* after this function has been called. +*/ +VOID VmmDllCore_CloseAll() +{ + VMM_HANDLE H; + AcquireSRWLockExclusive(&g_VMMDLL_CORE_LOCK_SRW); + while((H = g_VMMDLL_CORE_HANDLES[0])) { + VmmDllCore_CloseHandle(H); + } + ReleaseSRWLockExclusive(&g_VMMDLL_CORE_LOCK_SRW); +} + +/* +* Print the help. This requires a partially initialized VMM_HANDLE. +* -- H +*/ +VOID VmmDllCore_PrintHelp(_In_ VMM_HANDLE H) +{ + vmmprintf(H, + " \n" \ + " THE MEMORY PROCESS FILE SYSTEM v%i.%i.%i COMMAND LINE REFERENCE: \n" \ + " The Memory Process File System may be used in stand-alone mode with support \n" \ + " for memory dump files, local memory via rekall winpmem driver or together with\n" \ + " PCILeech if pcileech.dll is placed in the application directory. For infor- \n" \ + " mation about PCILeech please consult the separate PCILeech documentation. \n" \ + " ----- \n" \ + " The Memory Process File System (c) 2018-2021 Ulf Frisk \n" \ + " License: GNU Affero General Public License v3.0 \n" \ + " Contact information: pcileech@frizk.net \n" \ + " The Memory Process File System: https://github.com/ufrisk/MemProcFS \n" \ + " LeechCore: https://github.com/ufrisk/LeechCore \n" \ + " PCILeech: https://github.com/ufrisk/pcileech \n" \ + " ----- \n" \ + " The recommended way to use the Memory Process File System is to specify the \n" \ + " memory acquisition device in the -device option and possibly more options. \n" \ + " Example 1: MemProcFS.exe -device c:\\temp\\memdump-win10x64.pmem \n" \ + " Example 2: MemProcFS.exe -device c:\\temp\\memdump-winXPx86.dumpit -v -vv \n" \ + " Example 3: MemProcFS.exe -device FPGA \n" \ + " Example 4: MemProcFS.exe -device PMEM://c:\\temp\\winpmem_x64.sys \n" \ + " The Memory Process File System may also be started the memory dump file name \n" \ + " as the only option. This allows to make file extensions associated so that \n" \ + " they may be opened by double-clicking on them. This mode allows no options. \n" \ + " Example 4: MemProcFS.exe c:\\dumps\\memdump-win7x64.dumpit \n" \ + " ----- \n" \ + " Valid options: \n" \ + " -device : select memory acquisition device or memory dump file to use. \n" \ + " Valid options: \n" \ + " such as, but not limited to: , PMEM, FPGA \n" \ + " --- \n" \ + " = memory dump file name optionally including path.\n" \ + " PMEM = use winpmem 'winpmem_64.sys' to acquire live memory. \n" \ + " PMEM://c:\\path\\to\\winpmem_64.sys = path to winpmem driver. \n" \ + " --- \n" \ + " Please see https://github.com/ufrisk/LeechCore for additional info. \n" \ + " -remote : connect to a remote host running the LeechAgent. Please see the \n" \ + " LeechCore documentation for more information. \n" \ + " -v : verbose option. Additional information is displayed in the output. \n" \ + " Option has no value. Example: -v \n" \ + " -vv : extra verbose option. More detailed additional information is shown \n" \ + " in output. Option has no value. Example: -vv \n" \ + " -vvv : super verbose option. Show all data transferred such as PCIe TLPs. \n" \ + " Option has no value. Example: -vvv \n" \ + " -logfile : specify an optional log file. \n" \ + " -loglevel : specify the log verbosity level as a comma-separated list. \n" \ + " Please consult https://github.com/ufrisk/MemProcFS/wiki for details. \n" \ + " example: -loglevel 4,f:5,f:VMM:6 \n" \ + " -cr3 : base address of kernel/process page table (PML4) / CR3 CPU register. \n" \ + " -max : memory max address, valid range: 0x0 .. 0xffffffffffffffff \n" \ + " default: auto-detect (max supported by device / target system). \n" \ + " -memmap-str : specify a physical memory map in parameter agrument text. \n" \ + " -memmap : specify a physical memory map given in a file or specify 'auto'. \n" \ + " example: -memmap c:\\temp\\my_custom_memory_map.txt \n" \ + " example: -memmap auto \n" \ + " -pagefile0..9 : specify specify page file / swap file. By default pagefile \n" \ + " have index 0 - example: -pagefile0 pagefile.sys while swapfile have \n" \ + " have index 1 - example: -pagefile1 swapfile.sys \n" \ + " -pythonpath : specify the path to a python 3 installation for Windows. \n" \ + " The path given should be to the directory that contain: python.dll \n" \ + " Example: -pythonpath \"C:\\Program Files\\Python37\" \n" \ + " -disable-python : prevent/disable the python plugin sub-system from loading.\n" \ + " Example: -disable-python \n" \ + " -disable-symbolserver : disable any integrations with the Microsoft Symbol \n" \ + " Server used by the debugging .pdb symbol subsystem. Functionality \n" \ + " will be limited if this is activated. Example: -disable-symbolserver \n" \ + " -disable-symbols : disable symbol lookups from .pdb files. \n" \ + " Example: -disable-symbols \n" \ + " -disable-infodb : disable the infodb and any symbol lookups via it. \n" \ + " Example: -disable-infodb \n" \ + " -mount : drive letter/path to mount The Memory Process File system at. \n" \ + " default: M Example: -mount Q \n" \ + " -norefresh : disable automatic cache and processes refreshes even when \n" \ + " running against a live memory target - such as PCIe FPGA or live \n" \ + " driver acquired memory. This is not recommended. Example: -norefresh \n" \ + " -waitinitialize : wait debugging .pdb symbol subsystem to fully start before\n" \ + " mounting file system and fully starting MemProcFS. \n" \ + " -userinteract = allow vmm.dll to, on the console, query the user for \n" \ + " information such as, but not limited to, leechcore device options. \n" \ + " Default: user interaction = disabled. \n" \ + " -forensic : start a forensic scan of the physical memory immediately after \n" \ + " startup if possible. Allowed parameter values range from 0-4. \n" \ + " Note! forensic mode is not available for live memory. \n" \ + " 0 = not enabled (default value) \n" \ + " 1 = forensic mode with in-memory sqlite database. \n" \ + " 2 = forensic mode with temp sqlite database deleted upon exit. \n" \ + " 3 = forensic mode with temp sqlite database remaining upon exit. \n" \ + " 4 = forensic mode with static named sqlite database (vmm.sqlite3). \n" \ + " default: 0 Example -forensic 4 \n" \ + " \n", + VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION + ); +} + +/* +* Initialize command line config settings in H->cfg and H->dev. +* Upon failure the VMM_HANDLE will be partially intiialized. This is important +* since the '-printf' command line option is required to print info on-screen. +* It's recommended to put the '-printf' option as the first argument! +* -- H = a cleared fresh VMM_HANDLE not yet fully initialized. +* -- argc +* -- argv +* -- return +*/ +_Success_(return) +BOOL VmmDllCore_InitializeConfig(_In_ VMM_HANDLE H, _In_ DWORD argc, _In_ char *argv[]) +{ + char *argv2[3]; + DWORD i = 0, iPageFile; + if((argc == 2) && argv[1][0] && (argv[1][0] != '-')) { + // click to open -> only 1 argument ... + argv2[0] = argv[0]; + argv2[1] = "-device"; + argv2[2] = argv[1]; + return VmmDllCore_InitializeConfig(H, 3, argv2); + } + while(i < argc) { + if(0 == _stricmp(argv[i], "")) { + i++; + continue; + } else if(0 == _stricmp(argv[i], "-printf")) { + H->cfg.fVerboseDll = TRUE; + i++; + continue; + } else if(0 == _stricmp(argv[i], "-userinteract")) { + H->cfg.fUserInteract = TRUE; + i++; + continue; + } else if(0 == _stricmp(argv[i], "-v")) { + H->cfg.fVerbose = TRUE; + i++; + continue; + } else if(0 == _stricmp(argv[i], "-vv")) { + H->cfg.fVerboseExtra = TRUE; + i++; + continue; + } else if(0 == _stricmp(argv[i], "-vvv")) { + H->cfg.fVerboseExtraTlp = TRUE; + i++; + continue; + } else if(0 == _stricmp(argv[i], "-disable-symbolserver")) { + H->cfg.fDisableSymbolServerOnStartup = TRUE; + i++; + continue; + } else if(0 == _stricmp(argv[i], "-disable-symbols")) { + H->cfg.fDisableSymbolServerOnStartup = TRUE; + H->cfg.fDisableSymbols = TRUE; + i++; + continue; + } else if(0 == _stricmp(argv[i], "-disable-infodb")) { + H->cfg.fDisableInfoDB = TRUE; + i++; + continue; + } else if(0 == _stricmp(argv[i], "-disable-python")) { + H->cfg.fDisablePython = TRUE; + i++; + continue; + } else if(0 == _stricmp(argv[i], "-norefresh")) { + H->cfg.fDisableBackgroundRefresh = TRUE; + i++; + continue; + } else if(0 == _stricmp(argv[i], "-waitinitialize")) { + H->cfg.fWaitInitialize = TRUE; + i++; + continue; + } else if(i + 1 >= argc) { + return FALSE; + } else if(0 == _stricmp(argv[i], "-cr3")) { + H->cfg.paCR3 = Util_GetNumericA(argv[i + 1]); + i += 2; + continue; + } else if(0 == _stricmp(argv[i], "-forensic")) { + H->cfg.tpForensicMode = (DWORD)Util_GetNumericA(argv[i + 1]); + if(H->cfg.tpForensicMode > FC_DATABASE_TYPE_MAX) { return FALSE; } + i += 2; + continue; + } else if(0 == _stricmp(argv[i], "-max")) { + H->dev.paMax = Util_GetNumericA(argv[i + 1]); + i += 2; + continue; + } else if((0 == _stricmp(argv[i], "-device")) || (0 == strcmp(argv[i], "-z"))) { + strcpy_s(H->dev.szDevice, MAX_PATH, argv[i + 1]); + i += 2; + continue; + } else if(0 == _stricmp(argv[i], "-remote")) { + strcpy_s(H->dev.szRemote, MAX_PATH, argv[i + 1]); + i += 2; + continue; + } else if(0 == _stricmp(argv[i], "-memmap")) { + strcpy_s(H->cfg.szMemMap, MAX_PATH, argv[i + 1]); + i += 2; + continue; + } else if(0 == _stricmp(argv[i], "-memmap-str")) { + strcpy_s(H->cfg.szMemMapStr, _countof(H->cfg.szMemMapStr), argv[i + 1]); + i += 2; + continue; + } else if(0 == _stricmp(argv[i], "-pythonpath")) { + strcpy_s(H->cfg.szPythonPath, MAX_PATH, argv[i + 1]); + i += 2; + continue; + } else if(0 == _stricmp(argv[i], "-mount")) { + i += 2; + continue; + } else if(0 == _stricmp(argv[i], "-logfile")) { + strcpy_s(H->cfg.szLogFile, MAX_PATH, argv[i + 1]); + i += 2; + continue; + } else if(0 == _stricmp(argv[i], "-loglevel")) { + strcpy_s(H->cfg.szLogLevel, MAX_PATH, argv[i + 1]); + i += 2; + continue; + } else if(0 == _strnicmp(argv[i], "-pagefile", 9)) { + iPageFile = argv[i][9] - '0'; + if(iPageFile < 10) { + strcpy_s(H->cfg.szPageFile[iPageFile], MAX_PATH, argv[i + 1]); + } + i += 2; + continue; + } else { + return FALSE; + } + } + if(H->dev.paMax && (H->dev.paMax < 0x00100000)) { return FALSE; } + if(!H->dev.paMax && (H->cfg.szMemMap[0] || H->cfg.szMemMapStr[0])) { + // disable memory auto-detect when memmap is specified + H->dev.paMax = -1; + } + H->cfg.fFileInfoHeader = TRUE; + H->cfg.fVerbose = H->cfg.fVerbose && H->cfg.fVerboseDll; + H->cfg.fVerboseExtra = H->cfg.fVerboseExtra && H->cfg.fVerboseDll; + H->cfg.fVerboseExtraTlp = H->cfg.fVerboseExtraTlp && H->cfg.fVerboseDll; + H->dev.dwVersion = LC_CONFIG_VERSION; + H->dev.dwPrintfVerbosity |= H->cfg.fVerboseDll ? LC_CONFIG_PRINTF_ENABLED : 0; + H->dev.dwPrintfVerbosity |= H->cfg.fVerbose ? LC_CONFIG_PRINTF_V : 0; + H->dev.dwPrintfVerbosity |= H->cfg.fVerboseExtra ? LC_CONFIG_PRINTF_VV : 0; + H->dev.dwPrintfVerbosity |= H->cfg.fVerboseExtraTlp ? LC_CONFIG_PRINTF_VVV : 0; + return (H->dev.szDevice[0] != 0); +} + +/* +* Initialize memory map auto - i.e. retrieve it from the registry and load it into LeechCore. +* -- H +* -- return +*/ +_Success_(return) +BOOL VmmDllCore_InitializeMemMapAuto(_In_ VMM_HANDLE H) +{ + BOOL fResult = FALSE; + DWORD i, cbMemMap = 0; + LPSTR szMemMap = NULL; + PVMMOB_MAP_PHYSMEM pObMap = NULL; + if(!VmmMap_GetPhysMem(H, &pObMap)) { goto fail; } + if(!(szMemMap = LocalAlloc(LMEM_ZEROINIT, 0x01000000))) { goto fail; } + for(i = 0; i < pObMap->cMap; i++) { + cbMemMap += snprintf(szMemMap + cbMemMap, 0x01000000 - cbMemMap - 1, "%016llx %016llx\n", pObMap->pMap[i].pa, pObMap->pMap[i].pa + pObMap->pMap[i].cb - 1); + } + fResult = + LcCommand(H->hLC, LC_CMD_MEMMAP_SET, cbMemMap, (PBYTE)szMemMap, NULL, NULL) && + LcGetOption(H->hLC, LC_OPT_CORE_ADDR_MAX, &H->dev.paMax); +fail: + Ob_DECREF(pObMap); + LocalFree(szMemMap); + return fResult; +} + +#ifdef _WIN32 + +/* +* Request user input. This is done upon a request from LeechCore. User input is +* only requested in interactive user contexts. +* -- H = partially initialized VMM_HANDLE. +* -- argc +* -- argv +* -- return +*/ +_Success_(return != NULL) +VMM_HANDLE VmmDllCore_InitializeRequestUserInput(_In_ _Post_ptr_invalid_ VMM_HANDLE H, _In_ DWORD argc, _In_ LPSTR argv[]) +{ + LPSTR szProto; + DWORD i, cbRead = 0; + CHAR szInput[33] = { 0 }; + CHAR szDevice[MAX_PATH] = { 0 }; + HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); // must not be closed. + // 1: read input + vmmprintf(H, "\n?> "); + ReadConsoleA(hStdIn, szInput, 32, &cbRead, NULL); + for(i = 0; i < _countof(szInput); i++) { + if((szInput[i] == '\r') || (szInput[i] == '\n')) { szInput[i] = 0; } + } + cbRead = (DWORD)strlen(szInput); + if(!cbRead) { return NULL; } + // 2: clear "userinput" option and update "device" option + for(i = 0; i < argc; i++) { + if(0 == _stricmp(argv[i], "-userinteract")) { + argv[i] = ""; + } + if((i + 1 < argc) && ((0 == _stricmp(argv[i], "-device")) || (0 == strcmp(argv[i], "-z")))) { + szProto = strstr(argv[i + 1], "://"); + snprintf( + szDevice, + MAX_PATH - 1, + "%s%s%sid=%s", + argv[i + 1], + szProto ? "" : "://", + szProto && szProto[3] ? "," : "", + szInput); + argv[i + 1] = szDevice; + } + } + // 3: try re-initialize with new user input. + // (and close earlier partially initialized handle). + AcquireSRWLockExclusive(&g_VMMDLL_CORE_LOCK_SRW); + VmmDllCore_CloseHandle(H); + ReleaseSRWLockExclusive(&g_VMMDLL_CORE_LOCK_SRW); + return VMMDLL_InitializeEx(argc, argv, NULL); +} + +#endif /* _WIN32 */ + +/* +* Initialize MemProcFS from user parameters. Upon success a VMM_HANDLE is returned. +* The returned VMM_HANDLE will not yet be in any required external info maps. +* -- argc +* -- argv +* -- ppLcErrorInfo +* -- return +*/ +_Success_(return != NULL) +VMM_HANDLE VmmDllCore_Initialize(_In_ DWORD argc, _In_ LPSTR argv[], _Out_opt_ PPLC_CONFIG_ERRORINFO ppLcErrorInfo) +{ + VMM_HANDLE H = NULL; + FILE *hFile = NULL; + BOOL f; + DWORD cbMemMap = 0; + PBYTE pbMemMap = NULL; + PLC_CONFIG_ERRORINFO pLcErrorInfo = NULL; + LPSTR uszUserText; + BYTE pbBuffer[3 * MAX_PATH]; + AcquireSRWLockExclusive(&g_VMMDLL_CORE_LOCK_SRW); + if(ppLcErrorInfo) { *ppLcErrorInfo = NULL; } + if(!g_VMMDLL_ALLOCMAP_EXT) { + // allocate a shared global alloc map once at 1st init. (ok to "leak" this). + if(!(g_VMMDLL_ALLOCMAP_EXT = ObMap_New(NULL, OB_MAP_FLAGS_OBJECT_OB))) { goto fail; } + } + if(!(H = LocalAlloc(LMEM_ZEROINIT, sizeof(struct tdVMM_HANDLE)))) { goto fail; } + H->magic = VMM_MAGIC; + // 1: initialize configuration from command line + // after config initialization call vmmprintf should work regardless of + // success/fail. + if(!VmmDllCore_InitializeConfig(H, (DWORD)argc, argv)) { + VmmDllCore_PrintHelp(H); + goto fail; + } + // 9: upon success add handle to external allow-list. + if(!VmmDllCore_HandleAdd(H)) { + vmmprintf(H, "MemProcFS: Failed to add handle to external allow-list (max %i concurrent tasks allowed).\n", g_VMMDLL_CORE_HANDLE_COUNT); + goto fail; + } + // 2: initialize LeechCore memory acquisition device + if(!(H->hLC = LcCreateEx(&H->dev, &pLcErrorInfo))) { +#ifdef _WIN32 + if(pLcErrorInfo && (pLcErrorInfo->dwVersion == LC_CONFIG_ERRORINFO_VERSION)) { + if(pLcErrorInfo->cwszUserText && CharUtil_WtoU(pLcErrorInfo->wszUserText, -1, pbBuffer, sizeof(pbBuffer), &uszUserText, NULL, 0)) { + vmmprintf(H, "MESSAGE FROM MEMORY ACQUISITION DEVICE:\n=======================================\n%s\n", uszUserText); + } + if(H->cfg.fUserInteract && pLcErrorInfo->fUserInputRequest) { + LcMemFree(pLcErrorInfo); + // the request user input function will force a re-initialization upon + // success and free/discard the earlier partially initialized handle. + ReleaseSRWLockExclusive(&g_VMMDLL_CORE_LOCK_SRW); + return VmmDllCore_InitializeRequestUserInput(H, argc, argv); + } + } +#endif /* _WIN32 */ + vmmprintf(H, "MemProcFS: Failed to connect to memory acquisition device.\n"); + goto fail; + } + // 3: initialize/(refresh) the logging sub-system + VmmLog_LevelRefresh(H); + // 4: Set LeechCore MemMap (if exists and not auto - i.e. from file) + if(H->cfg.szMemMap[0] && _stricmp(H->cfg.szMemMap, "auto")) { + f = (pbMemMap = LocalAlloc(LMEM_ZEROINIT, 0x01000000)) && + !fopen_s(&hFile, H->cfg.szMemMap, "rb") && hFile && + (cbMemMap = (DWORD)fread(pbMemMap, 1, 0x01000000, hFile)) && (cbMemMap < 0x01000000) && + LcCommand(H->hLC, LC_CMD_MEMMAP_SET, cbMemMap, pbMemMap, NULL, NULL) && + LcGetOption(H->hLC, LC_OPT_CORE_ADDR_MAX, &H->dev.paMax); + LocalFree(pbMemMap); + if(hFile) { fclose(hFile); } + if(!f) { + vmmprintf(H, "MemProcFS: Failed to load initial memory map from: '%s'.\n", H->cfg.szMemMap); + goto fail; + } + } + if(H->cfg.szMemMapStr[0]) { + f = LcCommand(H->hLC, LC_CMD_MEMMAP_SET, (DWORD)strlen(H->cfg.szMemMapStr), H->cfg.szMemMapStr, NULL, NULL) && + LcGetOption(H->hLC, LC_OPT_CORE_ADDR_MAX, &H->dev.paMax); + if(!f) { + vmmprintf(H, "MemProcFS: Failed to load command line argument memory map.\n"); + goto fail; + } + } + // 5: initialize work (multi-threading sub-system). + if(!VmmWork_Initialize(H)) { + vmmprintf(H, "MemProcFS: Failed to initialize work multi-threading.\n"); + goto fail; + } + // 6: device context (H->dev) is initialized from here onwards - device functionality is working! + // try initialize vmm subsystem. + if(!VmmProcInitialize(H)) { + vmmprintf(H, "MOUNT: INFO: PROC file system not mounted.\n"); + goto fail; + } + // 7: vmm context (H->vmm) is initialized from here onwards - vmm functionality is working! + // set LeechCore MemMap (if auto). + if(H->cfg.szMemMap[0] && !_stricmp(H->cfg.szMemMap, "auto")) { + if(!VmmDllCore_InitializeMemMapAuto(H)) { + vmmprintf(H, "MemProcFS: Failed to load initial memory map from: '%s'.\n", H->cfg.szMemMap); + goto fail; + } + } + // 8: initialize forensic mode (if set by user parameter). + if(H->cfg.tpForensicMode) { + if(!FcInitialize(H, H->cfg.tpForensicMode, FALSE)) { + if(H->dev.fVolatile) { + vmmprintf(H, "MemProcFS: Failed to initialize forensic mode - volatile (live) memory not supported - please use memory dump!\n"); + } else { + vmmprintf(H, "MemProcFS: Failed to initialize forensic mode.\n"); + } + goto fail; + } + } + ReleaseSRWLockExclusive(&g_VMMDLL_CORE_LOCK_SRW); + return H; +fail: + if(ppLcErrorInfo) { + *ppLcErrorInfo = pLcErrorInfo; + } else { + LcMemFree(pLcErrorInfo); + } + VmmDllCore_CloseHandle(H); + ReleaseSRWLockExclusive(&g_VMMDLL_CORE_LOCK_SRW); + return NULL; +} + + + +//----------------------------------------------------------------------------- +// EXTERNAL MEMORY ALLOCATION / DEALLOCATION FUNCTIONALITY BELOW: +//----------------------------------------------------------------------------- + +typedef struct tdVMMDLLCORE_MEMLEAKEXTERNAL_CONTEXT { + VMM_HANDLE H; + DWORD c; +} VMMDLLCORE_MEMLEAKEXTERNAL_CONTEXT, *PVMMDLLCORE_MEMLEAKEXTERNAL_CONTEXT; + +VOID VmmDllCore_MemLeakFindExternal_MapFilterCB(_In_ QWORD k, _In_ POB v, _In_ PVMMDLLCORE_MEMLEAKEXTERNAL_CONTEXT ctx) +{ + if((v->H != ctx->H) || (ctx->c >= 10)) { return; } + ctx->c++; + VmmLog(ctx->H, MID_API, LOGLEVEL_2_WARNING, "MEMORY NOT DEALLOCATED AT CLOSE: va=0x%llx size=0x%x tag=%c%c%c%c", (QWORD)v + sizeof(OB), v->cbData, v->_tagCh[3], v->_tagCh[2], v->_tagCh[1], v->_tagCh[0]); + if(ctx->c == 10) { + VmmLog(ctx->H, MID_API, LOGLEVEL_2_WARNING, "MEMORY NOT DEALLOCATED AT CLOSE: FIRST %i ENTRIES SHOWN - WARNING MUTED!", ctx->c); + } +} + +/* +* Warn/Log potential user memory leaks at handle close. +* This is done by walking the external handle map. +* -- H +*/ +VOID VmmDllCore_MemLeakFindExternal(_In_ VMM_HANDLE H) +{ + VMMDLLCORE_MEMLEAKEXTERNAL_CONTEXT ctxFilter = { 0 }; + ctxFilter.H = H; + if(VmmLogIsActive(H, MID_API, LOGLEVEL_2_WARNING)) { + ObMap_Filter(g_VMMDLL_ALLOCMAP_EXT, &ctxFilter, (OB_MAP_FILTER_PFN)VmmDllCore_MemLeakFindExternal_MapFilterCB); + } +} + +/* +* Query the size of memory allocated by the VMMDLL. +* -- pvMem +* -- return = number of bytes required to hold memory allocation. +*/ +_Success_(return != 0) +SIZE_T VmmDllCore_MemSizeExternal(_In_ PVOID pvMem) +{ + POB pObMem; + if(ObMap_ExistsKey(g_VMMDLL_ALLOCMAP_EXT, (QWORD)pvMem)) { + pObMem = (POB)((SIZE_T)pvMem - sizeof(OB)); + if((pObMem->_magic2 == OB_HEADER_MAGIC) && (pObMem->_magic1 == OB_HEADER_MAGIC)) { + return pObMem->cbData; + } + } + return 0; +} + +/* +* Free memory allocated by the VMMDLL. +* -- pvMem +*/ +VOID VmmDllCore_MemFreeExternal(_Frees_ptr_opt_ PVOID pvMem) +{ + POB pObMem; + if((pObMem = ObMap_RemoveByKey(g_VMMDLL_ALLOCMAP_EXT, (QWORD)pvMem))) { + Ob_DECREF(pObMem); + } +} + +/* +* Allocate "external" memory to be free'd only by VMMDLL_MemFree // VmmDllCore_MemFreeExternal. +* CALLER VMMDLL_MemFree(return) +* -- H +* -- tag = tag identifying the type of object. +* -- cb = total size to allocate (not guaranteed to be zero-filled). +* -- cbHdr = size of header (guaranteed to be zero-filled). +* -- return +*/ +_Success_(return != NULL) +PVOID VmmDllCore_MemAllocExternal(_In_ VMM_HANDLE H, _In_ DWORD tag, _In_ SIZE_T cb, _In_ SIZE_T cbHdr) +{ + POB_DATA pObData; + if((cb > 0x40000000) || (cb < cbHdr)) { return NULL; } + if(!(pObData = (POB_DATA)Ob_AllocEx(H, tag, 0, cb + sizeof(OB), NULL, NULL))) { return NULL; } + ZeroMemory(pObData->pb, cbHdr); + ObMap_Push(g_VMMDLL_ALLOCMAP_EXT, (QWORD)pObData + sizeof(OB), pObData); // map will INCREF on success + pObData = Ob_DECREF(pObData); + return pObData ? pObData->pb : NULL; +} + diff --git a/vmm/vmmdll_scatter.c b/vmm/vmmdll_scatter.c index 7ae3063..c4d630d 100644 --- a/vmm/vmmdll_scatter.c +++ b/vmm/vmmdll_scatter.c @@ -32,6 +32,7 @@ typedef struct tdSCATTER_RANGE_WRITE { typedef struct tdSCATTER_CONTEXT { QWORD qwMagic; SRWLOCK LockSRW; + VMM_HANDLE H; DWORD dwReadFlags; BOOL fExecute; // read/write is already executed DWORD dwPID; @@ -395,7 +396,7 @@ BOOL VMMDLL_Scatter_ExecuteReadInternal(_In_ PSCATTER_CONTEXT ctx) } } // read scatter - VMMDLL_MemReadScatter(ctx->dwPID, ppMEMs, ctx->cPageTotal, ctx->dwReadFlags | VMMDLL_FLAG_NO_PREDICTIVE_READ); + VMMDLL_MemReadScatter(ctx->H, ctx->dwPID, ppMEMs, ctx->cPageTotal, ctx->dwReadFlags | VMMDLL_FLAG_NO_PREDICTIVE_READ); ctx->fExecute = TRUE; // range fixup (if required) pRange = ctx->pRanges; @@ -458,7 +459,7 @@ BOOL VMMDLL_Scatter_ExecuteWriteInternal(_In_ PSCATTER_CONTEXT ctx) } if(cb || pRange) { goto fail; } // leftover data should not happen! // write scatter - VMMDLL_MemWriteScatter(ctx->dwPID, ppMEMs, cMEMs); + VMMDLL_MemWriteScatter(ctx->H, ctx->dwPID, ppMEMs, cMEMs); // finish LocalFree(pbBuffer); return TRUE; @@ -508,19 +509,21 @@ BOOL VMMDLL_Scatter_Execute(_In_ VMMDLL_SCATTER_HANDLE hS) /* * Initialize a scatter handle which is used to call VMMDLL_Scatter_* functions. * CALLER CLOSE: VMMDLL_Scatter_CloseHandle(return) +* -- H * -- dwPID - PID of target process, (DWORD)-1 to read physical memory. * -- flags = optional flags as given by VMMDLL_FLAG_* * -- return = handle to be used in VMMDLL_Scatter_* functions. */ _Success_(return != NULL) -VMMDLL_SCATTER_HANDLE VMMDLL_Scatter_Initialize(_In_ DWORD dwPID, _In_ DWORD flags) +VMMDLL_SCATTER_HANDLE VMMDLL_Scatter_Initialize(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ DWORD flags) { PSCATTER_CONTEXT ctx = NULL; if(!(ctx = LocalAlloc(LMEM_ZEROINIT, sizeof(SCATTER_CONTEXT)))) { goto fail; } ctx->qwMagic = SCATTER_CONTEXT_MAGIC; + ctx->H = H; ctx->dwPID = dwPID; ctx->dwReadFlags = flags; - if(!(ctx->pmMEMs = ObMap_New(OB_MAP_FLAGS_OBJECT_VOID))) { goto fail; } + if(!(ctx->pmMEMs = ObMap_New(NULL, OB_MAP_FLAGS_OBJECT_VOID))) { goto fail; } return ctx; fail: VMMDLL_Scatter_CloseHandle((VMMDLL_SCATTER_HANDLE)ctx); diff --git a/vmm/vmmevil.c b/vmm/vmmevil.c index d227a7e..0daaae3 100644 --- a/vmm/vmmevil.c +++ b/vmm/vmmevil.c @@ -31,15 +31,37 @@ #define ROT13H_POWERSHELL 0x1b896fad #define VMMEVIL_IS_PARENT_PROCESS_STRICT(pChild, pParent) (pChild && pParent && (pChild->dwPPID == pParent->dwPID) && \ - VmmProcess_GetCreateTimeOpt(pChild) && VmmProcess_GetCreateTimeOpt(pParent) && \ - (VmmProcess_GetCreateTimeOpt(pChild) > VmmProcess_GetCreateTimeOpt(pParent))) + VmmProcess_GetCreateTimeOpt(H, pChild) && VmmProcess_GetCreateTimeOpt(H, pParent) && \ + (VmmProcess_GetCreateTimeOpt(H, pChild) > VmmProcess_GetCreateTimeOpt(H, pParent))) + +typedef struct tdVMMEVIL_INIT_CONTEXT { + POB_MAP pmEvil; + POB_STRMAP psmEvil; +} VMMEVIL_INIT_CONTEXT, *PVMMEVIL_INIT_CONTEXT; /* * Helper function to create an entry and add it to the pmEvil map. * The map holds the reference; the returned data must _NOT_ be free'd. +* -- ctxEvil +* -- pProcess +* -- tp +* -- va +* -- vaVadBase +* -- oVadEx +* -- uszText = optional descriptive text for the evil entry. +* -- fEvilAppSuppress = do not show in all-evil (only in process-evil). */ -PVMM_MAP_EVILENTRY VmmEvil_AddEvil_NoVadReq(_Inout_ POB_MAP pmEvil, _In_ PVMM_PROCESS pProcess, _In_ VMM_EVIL_TP tp, _In_ QWORD va, _In_ QWORD vaVadBase, _In_ DWORD oVadEx, _In_ BOOL fEvilAllSuppress) -{ +_Success_(return != NULL) +PVMM_MAP_EVILENTRY VmmEvil_AddEvil_NoVadReq( + _Inout_ PVMMEVIL_INIT_CONTEXT ctxEvil, + _In_ PVMM_PROCESS pProcess, + _In_ VMM_EVIL_TP tp, + _In_ QWORD va, + _In_ QWORD vaVadBase, + _In_ DWORD oVadEx, + _In_opt_ LPSTR uszText, + _In_ BOOL fEvilAllSuppress +) { QWORD qwKey; PVMM_MAP_EVILENTRY peEvil = NULL; if((peEvil = LocalAlloc(0, sizeof(VMM_MAP_EVILENTRY)))) { @@ -50,7 +72,12 @@ PVMM_MAP_EVILENTRY VmmEvil_AddEvil_NoVadReq(_Inout_ POB_MAP pmEvil, _In_ PVMM_PR peEvil->va = va; peEvil->oVadEx = oVadEx; peEvil->vaVad = vaVadBase; - if(!ObMap_Push(pmEvil, qwKey, peEvil)) { + peEvil->uszText = NULL; + peEvil->cbuText = 0; + if(uszText) { + ObStrMap_PushPtrUU(ctxEvil->psmEvil, uszText, &peEvil->uszText, &peEvil->cbuText); + } + if(!ObMap_Push(ctxEvil->pmEvil, qwKey, peEvil)) { LocalFree(peEvil); return NULL; } @@ -59,15 +86,58 @@ PVMM_MAP_EVILENTRY VmmEvil_AddEvil_NoVadReq(_Inout_ POB_MAP pmEvil, _In_ PVMM_PR return NULL; } -PVMM_MAP_EVILENTRY VmmEvil_AddEvil(_Inout_ POB_MAP pmEvil, _In_ PVMM_PROCESS pProcess, _In_ VMM_EVIL_TP tp, _In_ QWORD va, _In_ QWORD vaVadBase, _In_ DWORD oVadEx, _In_ BOOL fEvilAllSuppress) -{ - return vaVadBase ? VmmEvil_AddEvil_NoVadReq(pmEvil, pProcess, tp, va, vaVadBase, oVadEx, fEvilAllSuppress) : NULL; +_Success_(return != NULL) +PVMM_MAP_EVILENTRY VmmEvil_AddEvil( + _Inout_ PVMMEVIL_INIT_CONTEXT ctxEvil, + _In_ PVMM_PROCESS pProcess, + _In_ VMM_EVIL_TP tp, + _In_ QWORD va, + _In_ QWORD vaVadBase, + _In_ DWORD oVadEx, + _In_ BOOL fEvilAllSuppress +) { + return vaVadBase ? VmmEvil_AddEvil_NoVadReq(ctxEvil, pProcess, tp, va, vaVadBase, oVadEx, NULL, fEvilAllSuppress) : NULL; } +_Success_(return != NULL) +PVMM_MAP_EVILENTRY VmmEvil_AddEvilWithText( + _Inout_ PVMMEVIL_INIT_CONTEXT ctxEvil, + _In_ PVMM_PROCESS pProcess, + _In_ VMM_EVIL_TP tp, + _In_ QWORD va, + _In_ BOOL fEvilAllSuppress, + _In_z_ _Printf_format_string_ LPSTR uszFormat, + ... +) { + int csz = 0; + LPSTR usz = NULL; + va_list arglist, arglist_copy; + PVMM_MAP_EVILENTRY peEvil = NULL; + va_start(arglist, uszFormat); + va_copy(arglist_copy, arglist); + csz = _vscprintf(uszFormat, arglist_copy); + if((csz > 0) && (csz < 0x00100000) && (usz = LocalAlloc(0, (SIZE_T)csz + 1))) { + csz = _vsnprintf_s(usz, (SIZE_T)csz + 1, _TRUNCATE, uszFormat, arglist); + if(csz > 0) { + peEvil = VmmEvil_AddEvil_NoVadReq(ctxEvil, pProcess, tp, va, 0, 0, usz, fEvilAllSuppress); + } else { + LocalFree(usz); + } + } + va_end(arglist); + return peEvil; +} + + + +//----------------------------------------------------------------------------- +// FINDEVIL PROCESS SCANNING FUNCTIONALITY BELOW: +//----------------------------------------------------------------------------- + /* * Check a single VAD entry for: PRIVATE_EXECUTE and NOIMAGE_EXECUTE. */ -VOID VmmEvil_ProcessScan_VadNoImageExecuteEntry(_In_ PVMM_PROCESS pProcess, _In_ PVMMOB_MAP_VAD pVadMap, _In_ DWORD iVad, _Inout_ POB_MAP pmEvil, _Inout_ POB_SET psInjectedPE, _In_ BOOL fEvilAllSuppress) +VOID VmmEvil_ProcessScan_VadNoImageExecuteEntry(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVMMOB_MAP_VAD pVadMap, _In_ DWORD iVad, _Inout_ PVMMEVIL_INIT_CONTEXT ctxEvil, _Inout_ POB_SET psInjectedPE, _In_ BOOL fEvilAllSuppress) { DWORD iVadEx, cEvilRX = 0, cEvilRWX = 0; QWORD cbPE, qwHwPte; @@ -78,12 +148,12 @@ VOID VmmEvil_ProcessScan_VadNoImageExecuteEntry(_In_ PVMM_PROCESS pProcess, _In_ BOOL fPteA; peVad = pVadMap->pMap + iVad; // 1: check for PE header (injected PE) - cbPE = PE_GetSize(pProcess, peVad->vaStart); + cbPE = PE_GetSize(H, pProcess, peVad->vaStart); if(cbPE && (cbPE < 0x04000000)) { ObSet_Push(psInjectedPE, peVad->vaStart); } // 2: check executable pages - if(!VmmMap_GetVadEx(pProcess, &pObVadExMap, VMM_VADMAP_TP_PARTIAL, peVad->cVadExPagesBase, peVad->cVadExPages)) { return; } + if(!VmmMap_GetVadEx(H, pProcess, &pObVadExMap, VMM_VADMAP_TP_PARTIAL, peVad->cVadExPagesBase, peVad->cVadExPages)) { return; } for(iVadEx = 0; iVadEx < pObVadExMap->cMap; iVadEx++) { peVadEx = pObVadExMap->pMap + iVadEx; qwHwPte = (peVadEx->tp == VMM_PTE_TP_HARDWARE) ? peVadEx->pte : 0; @@ -99,7 +169,7 @@ VOID VmmEvil_ProcessScan_VadNoImageExecuteEntry(_In_ PVMM_PROCESS pProcess, _In_ tp = peVad->fPrivateMemory ? VMM_EVIL_TP_VAD_PRIVATE_RX : VMM_EVIL_TP_VAD_NOIMAGE_RX; } VmmEvil_AddEvil( - pmEvil, + ctxEvil, pProcess, tp, peVadEx->va, @@ -109,6 +179,7 @@ VOID VmmEvil_ProcessScan_VadNoImageExecuteEntry(_In_ PVMM_PROCESS pProcess, _In_ ); if((cEvilRWX >= VMMEVIL_MAXCOUNT_VAD_EXECUTE) && (cEvilRX >= VMMEVIL_MAXCOUNT_VAD_EXECUTE)) { break; } } + Ob_DECREF(pObVadExMap); } /* @@ -147,7 +218,7 @@ VOID VmmEvil_ProcessScan_VadNoImageExecute_ProcWhitelist(_In_ PVMM_PROCESS pProc * If such an entry is found the VAD is suspicious and additionally checked for: * INJECTED_PE, PRIVATE_EXECUTE and NOIMAGE_EXECUTE. */ -VOID VmmEvil_ProcessScan_VadNoImageExecute(_In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP pmEvil, _Inout_ POB_SET psInjectedPE) +VOID VmmEvil_ProcessScan_VadNoImageExecute(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Inout_ PVMMEVIL_INIT_CONTEXT ctxEvil, _Inout_ POB_SET psInjectedPE) { BOOL fRX, fRWX, fProcSuppressRX, fProcSuppressRWX; DWORD iVad, iPte = 0; @@ -155,8 +226,8 @@ VOID VmmEvil_ProcessScan_VadNoImageExecute(_In_ PVMM_PROCESS pProcess, _Inout_ P PVMM_MAP_VADENTRY peVad; PVMMOB_MAP_VAD pObVadMap = NULL; PVMMOB_MAP_VADEX pObVadExMap = NULL; - if(!VmmMap_GetPte(pProcess, &pObPteMap, FALSE)) { goto fail; } - if(!VmmMap_GetVad(pProcess, &pObVadMap, VMM_VADMAP_TP_PARTIAL)) { goto fail; } + if(!VmmMap_GetPte(H, pProcess, &pObPteMap, FALSE)) { goto fail; } + if(!VmmMap_GetVad(H, pProcess, &pObVadMap, VMM_VADMAP_TP_PARTIAL)) { goto fail; } VmmEvil_ProcessScan_VadNoImageExecute_ProcWhitelist(pProcess, &fProcSuppressRX, &fProcSuppressRWX); for(iVad = 0; (iVad < pObVadMap->cMap) && (iPte < pObPteMap->cMap); iVad++) { peVad = pObVadMap->pMap + iVad; @@ -179,27 +250,28 @@ VOID VmmEvil_ProcessScan_VadNoImageExecute(_In_ PVMM_PROCESS pProcess, _Inout_ P } // vad has hw executable page -> investigate closer if(fRX) { - VmmEvil_ProcessScan_VadNoImageExecuteEntry(pProcess, pObVadMap, iVad, pmEvil, psInjectedPE, fProcSuppressRX || (fRWX && fProcSuppressRWX)); + VmmEvil_ProcessScan_VadNoImageExecuteEntry(H, pProcess, pObVadMap, iVad, ctxEvil, psInjectedPE, fProcSuppressRX || (fRWX && fProcSuppressRWX)); } } fail: + Ob_DECREF(pObPteMap); Ob_DECREF(pObVadMap); } /* * verify */ -VOID VmmEvil_ProcessScan_VadImageExecuteNoProto_PhysicalPageVerify(_In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP pmEvil) +VOID VmmEvil_ProcessScan_VadImageExecuteNoProto_PhysicalPageVerify(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Inout_ PVMMEVIL_INIT_CONTEXT ctxEvil) { BOOL f; short i, o, c; POB_SET psObRemove = NULL; PVMM_MAP_EVILENTRY pe = NULL; BYTE pbPage1[0x1000], pbPage2[0x1000]; - if(!(psObRemove = ObSet_New())) { return; } - while((pe = ObMap_GetNext(pmEvil, pe))) { - f = VmmRead2(NULL, pe->VAD_PATCHED_PE.pa, pbPage1, 0x1000, VMM_FLAG_FORCECACHE_READ) && - VmmRead2(NULL, pe->VAD_PATCHED_PE.paProto, pbPage2, 0x1000, VMM_FLAG_FORCECACHE_READ) && + if(!(psObRemove = ObSet_New(H))) { return; } + while((pe = ObMap_GetNext(ctxEvil->pmEvil, pe))) { + f = VmmRead2(H, NULL, pe->VAD_PATCHED_PE.pa, pbPage1, 0x1000, VMM_FLAG_FORCECACHE_READ) && + VmmRead2(H, NULL, pe->VAD_PATCHED_PE.paProto, pbPage2, 0x1000, VMM_FLAG_FORCECACHE_READ) && memcmp(pbPage1, pbPage2, 0x1000); if(f) { for(i = 0xfff, o = 0, c = 0; i >= 0; i--) { @@ -215,7 +287,7 @@ VOID VmmEvil_ProcessScan_VadImageExecuteNoProto_PhysicalPageVerify(_In_ PVMM_PRO } } while((pe = (PVMM_MAP_EVILENTRY)ObSet_Pop(psObRemove))) { - LocalFree(ObMap_Remove(pmEvil, pe)); + LocalFree(ObMap_Remove(ctxEvil->pmEvil, pe)); } Ob_DECREF(psObRemove); } @@ -226,7 +298,7 @@ VOID VmmEvil_ProcessScan_VadImageExecuteNoProto_PhysicalPageVerify(_In_ PVMM_PRO * the prototype page. If its possible (i.e. no paged out pages) and there is a * mismatch then flag the page to the evil map. */ -VOID VmmEvil_ProcessScan_VadImageExecuteNoProto(_In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP pmEvil) +VOID VmmEvil_ProcessScan_VadImageExecuteNoProto(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Inout_ PVMMEVIL_INIT_CONTEXT ctxEvil) { QWORD qwHwPte; DWORD iVad, iVadEx, cPatch; @@ -236,13 +308,13 @@ VOID VmmEvil_ProcessScan_VadImageExecuteNoProto(_In_ PVMM_PROCESS pProcess, _Ino PVMMOB_MAP_VADEX pObVadExMap = NULL; PVMM_MAP_EVILENTRY peEvil; POB_SET pspaObPrefetch = NULL; - if(!(pspaObPrefetch = ObSet_New())) { goto fail; } - if(!VmmMap_GetVad(pProcess, &pObVadMap, VMM_VADMAP_TP_PARTIAL)) { goto fail; } + if(!(pspaObPrefetch = ObSet_New(H))) { goto fail; } + if(!VmmMap_GetVad(H, pProcess, &pObVadMap, VMM_VADMAP_TP_PARTIAL)) { goto fail; } // 1: fetch VAD_PATCHED_PE by iterating over image VADs for(iVad = 0; iVad < pObVadMap->cMap; iVad++) { peVad = pObVadMap->pMap + iVad; if(!peVad->fImage) { continue; } - if(!VmmMap_GetVadEx(pProcess, &pObVadExMap, VMM_VADMAP_TP_PARTIAL, peVad->cVadExPagesBase, peVad->cVadExPages)) { continue; } + if(!VmmMap_GetVadEx(H, pProcess, &pObVadExMap, VMM_VADMAP_TP_PARTIAL, peVad->cVadExPagesBase, peVad->cVadExPages)) { continue; } for(iVadEx = 0, cPatch = 0; (iVadEx < pObVadExMap->cMap) && (cPatch < VMMEVIL_MAXCOUNT_VAD_PATCHED_PE); iVadEx++) { peVadEx = pObVadExMap->pMap + iVadEx; qwHwPte = (peVadEx->tp == VMM_PTE_TP_HARDWARE) ? peVadEx->pte : 0; @@ -251,7 +323,7 @@ VOID VmmEvil_ProcessScan_VadImageExecuteNoProto(_In_ PVMM_PROCESS pProcess, _Ino if(peVadEx->pa == peVadEx->proto.pa) { continue; } cPatch++; peEvil = VmmEvil_AddEvil( - pmEvil, + ctxEvil, pProcess, VMM_EVIL_TP_VAD_PATCHED_PE, peVadEx->va, @@ -268,8 +340,8 @@ VOID VmmEvil_ProcessScan_VadImageExecuteNoProto(_In_ PVMM_PROCESS pProcess, _Ino } // 2: ensure binary difference between physical address and prototype. if(ObSet_Size(pspaObPrefetch)) { - VmmCachePrefetchPages(NULL, pspaObPrefetch, 0); - VmmEvil_ProcessScan_VadImageExecuteNoProto_PhysicalPageVerify(pProcess, pmEvil); + VmmCachePrefetchPages(H, NULL, pspaObPrefetch, 0); + VmmEvil_ProcessScan_VadImageExecuteNoProto_PhysicalPageVerify(H, pProcess, ctxEvil); } fail: Ob_DECREF(pObVadMap); @@ -282,14 +354,14 @@ fail: * with the evil map here. * The module map generation logic contains the actual detections. */ -VOID VmmEvil_ProcessScan_Modules(_In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP pmEvil) +VOID VmmEvil_ProcessScan_Modules(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Inout_ PVMMEVIL_INIT_CONTEXT ctxEvil) { BOOL fBadLdr = TRUE; DWORD i; PVMM_MAP_MODULEENTRY pe; PVMMOB_MAP_MODULE pObModuleMap = NULL; if((pProcess->dwPPID == 4) && !memcmp("MemCompression", pProcess->szName, 15)) { return; } - if(!VmmMap_GetModule(pProcess, &pObModuleMap)) { return; } + if(!VmmMap_GetModule(H, pProcess, &pObModuleMap)) { return; } for(i = 0; i < pObModuleMap->cMap; i++) { if(pObModuleMap->pMap[i].tp == VMM_MODULE_TP_NORMAL) { fBadLdr = FALSE; @@ -297,18 +369,18 @@ VOID VmmEvil_ProcessScan_Modules(_In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP pmE } } if(fBadLdr) { - VmmEvil_AddEvil_NoVadReq(pmEvil, pProcess, VMM_EVIL_TP_PEB_BAD_LDR, pProcess->win.vaPEB32 ? pProcess->win.vaPEB32 : pProcess->win.vaPEB, 0, 0, FALSE); + VmmEvil_AddEvil_NoVadReq(ctxEvil, pProcess, VMM_EVIL_TP_PEB_BAD_LDR, pProcess->win.vaPEB32 ? pProcess->win.vaPEB32 : pProcess->win.vaPEB, 0, 0, NULL, FALSE); } if(pProcess->win.EPROCESS.fNoLink) { - VmmEvil_AddEvil_NoVadReq(pmEvil, pProcess, VMM_EVIL_TP_PROC_NOLINK, pProcess->win.EPROCESS.va, 0, 0, FALSE); + VmmEvil_AddEvil_NoVadReq(ctxEvil, pProcess, VMM_EVIL_TP_PROC_NOLINK, pProcess->win.EPROCESS.va, 0, 0, NULL, FALSE); } for(i = 0; i < pObModuleMap->cMap; i++) { pe = pObModuleMap->pMap + i; if(pe->tp == VMM_MODULE_TP_INJECTED) { - VmmEvil_AddEvil(pmEvil, pProcess, VMM_EVIL_TP_PE_INJECTED, pe->vaBase, pe->vaBase, 0, FALSE); + VmmEvil_AddEvil(ctxEvil, pProcess, VMM_EVIL_TP_PE_INJECTED, pe->vaBase, pe->vaBase, 0, FALSE); } if(!fBadLdr && (pe->tp == VMM_MODULE_TP_NOTLINKED)) { - VmmEvil_AddEvil(pmEvil, pProcess, VMM_EVIL_TP_PE_NOTLINKED, pe->vaBase, pe->vaBase, 0, FALSE); + VmmEvil_AddEvil(ctxEvil, pProcess, VMM_EVIL_TP_PE_NOTLINKED, pe->vaBase, pe->vaBase, 0, FALSE); } } Ob_DECREF(pObModuleMap); @@ -318,19 +390,19 @@ VOID VmmEvil_ProcessScan_Modules(_In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP pmE * Locate PEB masquerading - i.e. when process image path in user-land differs from the kernel path. * https://www.ired.team/offensive-security/defense-evasion/masquerading-processes-in-userland-through-_peb */ -VOID VmmEvil_ProcessScan_PebMasquerade(_In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP pmEvil) +VOID VmmEvil_ProcessScan_PebMasquerade(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Inout_ PVMMEVIL_INIT_CONTEXT ctxEvil) { - PVMMWIN_USER_PROCESS_PARAMETERS pu = VmmWin_UserProcessParameters_Get(pProcess); + PVMMWIN_USER_PROCESS_PARAMETERS pu = VmmWin_UserProcessParameters_Get(H, pProcess); if(!pu || (pu->cbuImagePathName < 12) || pProcess->pObPersistent->cuszPathKernel < 24) { return; } // length sanity checks if(CharUtil_StrEndsWith(pProcess->pObPersistent->uszPathKernel, pu->uszImagePathName + 12, TRUE)) { return; } // ends-with if(!CharUtil_StrEndsWith(pProcess->pObPersistent->uszPathKernel, pu->uszImagePathName + strlen(pu->uszImagePathName) - 4, TRUE)) { return; } // file-ending match (remove windows apps) - VmmEvil_AddEvil_NoVadReq(pmEvil, pProcess, VMM_EVIL_TP_PEB_MASQUERADE, 0, 0, 0, FALSE); + VmmEvil_AddEvil_NoVadReq(ctxEvil, pProcess, VMM_EVIL_TP_PEB_MASQUERADE, 0, 0, 0, NULL, FALSE); } /* * Locate well known processes with bad users - i.e. cmd running as system. */ -VOID VmmEvil_ProcessScan_BadUser(_In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP pmEvil) +VOID VmmEvil_ProcessScan_BadUser(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Inout_ PVMMEVIL_INIT_CONTEXT ctxEvil) { CHAR uszUserName[18]; PVMM_PROCESS pObProcessWithToken; @@ -355,11 +427,11 @@ VOID VmmEvil_ProcessScan_BadUser(_In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP pmE default: return; } - pObProcessWithToken = pProcess->win.TOKEN.fInitialized ? Ob_INCREF(pProcess) : VmmProcessGetEx(NULL, pProcess->dwPID, VMM_FLAG_PROCESS_TOKEN); + pObProcessWithToken = pProcess->win.TOKEN.fInitialized ? Ob_INCREF(pProcess) : VmmProcessGetEx(H, NULL, pProcess->dwPID, VMM_FLAG_PROCESS_TOKEN); if(pObProcessWithToken && pObProcessWithToken->win.TOKEN.fSidUserValid) { - if(VmmWinUser_GetName(&pObProcessWithToken->win.TOKEN.SidUser.SID, uszUserName, 17, &fWellKnown)) { + if(VmmWinUser_GetName(H, &pObProcessWithToken->win.TOKEN.SidUser.SID, uszUserName, 17, &fWellKnown)) { if((fRequireWellKnown && !fWellKnown) || (!fRequireWellKnown && fWellKnown)) { - VmmEvil_AddEvil_NoVadReq(pmEvil, pProcess, VMM_EVIL_TP_PROC_USER, 0, 0, 0, FALSE); + VmmEvil_AddEvil_NoVadReq(ctxEvil, pProcess, VMM_EVIL_TP_PROC_USER, 0, 0, 0, NULL, FALSE); } } } @@ -369,12 +441,12 @@ VOID VmmEvil_ProcessScan_BadUser(_In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP pmE /* * Locate well known processes with bad parents. */ -VOID VmmEvil_ProcessScan_BadParent(_In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP pmEvil) +VOID VmmEvil_ProcessScan_BadParent(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Inout_ PVMMEVIL_INIT_CONTEXT ctxEvil) { DWORD dwH, dwHProcess; BOOL fBad = FALSE; PVMM_PROCESS pObParentProcess = NULL; - if((pObParentProcess = VmmProcessGetEx(NULL, pProcess->dwPPID, VMM_FLAG_PROCESS_SHOW_TERMINATED))) { + if((pObParentProcess = VmmProcessGetEx(H, NULL, pProcess->dwPPID, VMM_FLAG_PROCESS_SHOW_TERMINATED))) { if(VMMEVIL_IS_PARENT_PROCESS_STRICT(pProcess, pObParentProcess)) { dwH = CharUtil_Hash32A(pObParentProcess->szName, TRUE); dwHProcess = CharUtil_Hash32A(pProcess->szName, TRUE); @@ -403,7 +475,7 @@ VOID VmmEvil_ProcessScan_BadParent(_In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP p break; } if(fBad) { - VmmEvil_AddEvil_NoVadReq(pmEvil, pProcess, VMM_EVIL_TP_PROC_PARENT, 0, 0, 0, FALSE); + VmmEvil_AddEvil_NoVadReq(ctxEvil, pProcess, VMM_EVIL_TP_PROC_PARENT, 0, 0, 0, NULL, FALSE); } } Ob_DECREF(pObParentProcess); @@ -415,27 +487,103 @@ VOID VmmEvil_ProcessScan_BadParent(_In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP p * side effects - such as inserting "injected" modules into the process list. * Function is performance intensive since it performs multiple analysis steps. */ -VOID VmmEvil_ProcessScan(_In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP pmEvil) +VOID VmmEvil_ProcessScan(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Inout_ PVMMEVIL_INIT_CONTEXT ctxEvil) { POB_SET psObInjectedPE = NULL; if(!pProcess->fUserOnly) { goto fail; } - if(!(psObInjectedPE = ObSet_New())) { goto fail; } + if(!(psObInjectedPE = ObSet_New(H))) { goto fail; } // scan image vads for executable memory not matching prototype pages. - VmmEvil_ProcessScan_VadImageExecuteNoProto(pProcess, pmEvil); + VmmEvil_ProcessScan_VadImageExecuteNoProto(H, pProcess, ctxEvil); // update result with execute pages in non image vads. // also commit to modules map as injected PE (if possible). - VmmEvil_ProcessScan_VadNoImageExecute(pProcess, pmEvil, psObInjectedPE); - VmmWinLdrModule_Initialize(pProcess, psObInjectedPE); + VmmEvil_ProcessScan_VadNoImageExecute(H, pProcess, ctxEvil, psObInjectedPE); + VmmWinLdrModule_Initialize(H, pProcess, psObInjectedPE); // update result with interesting module entries. - VmmEvil_ProcessScan_Modules(pProcess, pmEvil); + VmmEvil_ProcessScan_Modules(H, pProcess, ctxEvil); // update with other process-related findings: - VmmEvil_ProcessScan_BadParent(pProcess, pmEvil); - VmmEvil_ProcessScan_BadUser(pProcess, pmEvil); - VmmEvil_ProcessScan_PebMasquerade(pProcess, pmEvil); + VmmEvil_ProcessScan_BadParent(H, pProcess, ctxEvil); + VmmEvil_ProcessScan_BadUser(H, pProcess, ctxEvil); + VmmEvil_ProcessScan_PebMasquerade(H, pProcess, ctxEvil); + // scan for kernel related issues (system process)} fail: Ob_DECREF(psObInjectedPE); } + + +//----------------------------------------------------------------------------- +// FINDEVIL KERNEL SCANNING FUNCTIONALITY BELOW: +//----------------------------------------------------------------------------- + +/* +* Locate kernel drivers loaded from non standard paths. +*/ +VOID VmmEvil_ProcessScan_KDriverPath(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _Inout_ PVMMEVIL_INIT_CONTEXT ctxEvil) +{ + // add more allowed paths to the list below: + LPSTR szPATH_ALLOWLIST[] = { + "\\SystemRoot\\system32\\DRIVERS\\", + "\\SystemRoot\\System32\\DriverStore\\", + "\\SystemRoot\\system32\\ntoskrnl.exe", + "\\SystemRoot\\System32\\win32k", + "\\SystemRoot\\system32\\hal.dll", + "\\??\\C:\\Windows\\system32\\DRIVERS\\", + "\\??\\C:\\Windows\\System32\\DriverStore\\", + "\\??\\C:\\ProgramData\\Microsoft\\Windows Defender\\Definition Updates\\", + }; + POB_MAP pmObModuleByVA = NULL; + PVMMOB_MAP_MODULE pObModuleMap = NULL; + PVMMOB_MAP_KDRIVER pObDriverMap = NULL; + PVMM_MAP_KDRIVERENTRY peDriver; + PVMM_MAP_MODULEENTRY peModule; + DWORD iDriver, iPathAllow; + BOOL fOK; + if(!VmmMap_GetKDriver(H, &pObDriverMap)) { goto fail; } + if(!VmmMap_GetModule(H, pSystemProcess, &pObModuleMap)) { goto fail; } + if(!VmmMap_GetModuleEntryEx3(H, pObModuleMap, &pmObModuleByVA)) { goto fail; } + for(iDriver = 0; iDriver < pObDriverMap->cMap; iDriver++) { + peDriver = pObDriverMap->pMap + iDriver; + peModule = ObMap_GetByKey(pmObModuleByVA, peDriver->vaStart); + if(!peModule) { + if(CharUtil_StrStartsWith(peDriver->uszPath, "\\FileSystem\\RAW", TRUE)) { continue; } + // evil: driver has no linked module: + VmmEvil_AddEvilWithText(ctxEvil, pSystemProcess, VMM_EVIL_TP_DRIVER_PATH, peDriver->va, FALSE, "Driver:[%s] Module:NOT_FOUND", peDriver->uszName); + VmmLog(H, MID_EVIL, LOGLEVEL_5_DEBUG, "DRIVER_PATH: Driver:[%s] Module:NOT_FOUND", peDriver->uszName); + continue; + } + fOK = FALSE; + for(iPathAllow = 0; iPathAllow < (sizeof(szPATH_ALLOWLIST) / sizeof(LPCSTR)); iPathAllow++) { + if(CharUtil_StrStartsWith(peModule->uszFullName, szPATH_ALLOWLIST[iPathAllow], TRUE)) { + fOK = TRUE; + break; + } + } + if(fOK) { continue; } + // evil: driver module not loaded from path in allowlist: + VmmEvil_AddEvilWithText(ctxEvil, pSystemProcess, VMM_EVIL_TP_DRIVER_PATH, peDriver->va, FALSE, "Driver:[%s] Module:[%s]", peDriver->uszName, peModule->uszFullName); + VmmLog(H, MID_EVIL, LOGLEVEL_5_DEBUG, "DRIVER_PATH: Driver:[%s] Module:[%s] ", peDriver->uszName, peModule->uszFullName); + } +fail: + Ob_DECREF(pmObModuleByVA); + Ob_DECREF(pObModuleMap); + Ob_DECREF(pObDriverMap); +} + +/* +* Scan kernel structures for evil. +* Function is performance intensive since it performs multiple analysis steps. +*/ +VOID VmmEvil_KernelScan(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _Inout_ PVMMEVIL_INIT_CONTEXT ctxEvil) +{ + VmmEvil_ProcessScan_KDriverPath(H, pSystemProcess, ctxEvil); + VmmLog(H, MID_EVIL, LOGLEVEL_6_TRACE, "COMPLETED_KERNEL_SCAN"); +} + + +//----------------------------------------------------------------------------- +// FINDEVIL GENERAL INITIALIZATION FUNCTIONALITY BELOW: +//----------------------------------------------------------------------------- + /* * qsort compare function for sorting evil findings */ @@ -459,63 +607,83 @@ int VmmEvil_InitializeMap_CmpSort(PVMM_MAP_EVILENTRY a, PVMM_MAP_EVILENTRY b) return 0; } +VOID VmmEvil_CleanupCB(_In_ PVOID pOb) +{ + PVMMOB_MAP_EVIL pMapEvil = (PVMMOB_MAP_EVIL)pOb; + LocalFree(pMapEvil->pbMultiText); +} + /* * Create VMMOB_MAP_EVIL from a given object manager map. * CALLER DECREF: return -* -- pmEvil +* -- H +* -- ctx * -- return */ -PVMMOB_MAP_EVIL VmmEvil_InitializeMap(_In_ POB_MAP pmEvil) +PVMMOB_MAP_EVIL VmmEvil_InitializeMap(_In_ VMM_HANDLE H, _In_ PVMMEVIL_INIT_CONTEXT ctx) { DWORD i; PVMM_MAP_EVILENTRY pe; PVMMOB_MAP_EVIL pObEvilMap = NULL; - pObEvilMap = Ob_Alloc(OB_TAG_MAP_EVIL, 0, sizeof(VMMOB_MAP_EVIL) + ObMap_Size(pmEvil) * sizeof(VMM_MAP_EVILENTRY), NULL, NULL); - if(!pObEvilMap) { - return Ob_Alloc(OB_TAG_MAP_EVIL, LMEM_ZEROINIT, sizeof(VMMOB_MAP_EVIL), NULL, NULL); + pObEvilMap = Ob_AllocEx(H, OB_TAG_MAP_EVIL, 0, sizeof(VMMOB_MAP_EVIL) + ObMap_Size(ctx->pmEvil) * sizeof(VMM_MAP_EVILENTRY), VmmEvil_CleanupCB, NULL); + if(pObEvilMap && !ObStrMap_FinalizeAllocU_DECREF_NULL(&ctx->psmEvil, &pObEvilMap->pbMultiText, &pObEvilMap->cMap)) { + Ob_DECREF(pObEvilMap); + pObEvilMap = NULL; } - pObEvilMap->tcCreateTime = ctxVmm->tcRefreshMedium; - pObEvilMap->cMap = ObMap_Size(pmEvil); + if(!pObEvilMap) { + return Ob_AllocEx(H, OB_TAG_MAP_EVIL, LMEM_ZEROINIT, sizeof(VMMOB_MAP_EVIL), NULL, NULL); + } + pObEvilMap->tcCreateTime = H->vmm.tcRefreshMedium; + pObEvilMap->cMap = ObMap_Size(ctx->pmEvil); for(i = 0; i < pObEvilMap->cMap; i++) { - pe = ObMap_GetByIndex(pmEvil, i); + pe = ObMap_GetByIndex(ctx->pmEvil, i); memcpy(pObEvilMap->pMap + i, pe, sizeof(VMM_MAP_EVILENTRY)); } qsort(pObEvilMap->pMap, pObEvilMap->cMap, sizeof(VMM_MAP_EVILENTRY), (int(*)(void const*, void const*))VmmEvil_InitializeMap_CmpSort); return pObEvilMap; } -BOOL VmmEvil_InitializeProcess(_In_ PVMM_PROCESS pProcess, _In_opt_ POB_MAP pmEvilAll) +BOOL VmmEvil_InitializeProcess(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ PVMMEVIL_INIT_CONTEXT ctxEvilAll) { + BOOL fResult = FALSE; DWORD i; QWORD qwKey; - POB_MAP pmObEvil = NULL; PVMM_MAP_EVILENTRY pe; PVMMOB_MAP_EVIL pEvilMap = NULL; - if((pProcess->dwState != 0) && !pProcess->fUserOnly) { return FALSE; } + VMMEVIL_INIT_CONTEXT ctxInit = { 0 }; + if((pProcess->dwState != 0) && !pProcess->fUserOnly) { goto fail; } if(!pProcess->Map.pObEvil) { + if(!(ctxInit.pmEvil = ObMap_New(H, OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } + if(!(ctxInit.psmEvil = ObStrMap_New(H, OB_STRMAP_FLAGS_CASE_SENSITIVE))) { goto fail; } EnterCriticalSection(&pProcess->Map.LockUpdateMapEvil); if(!pProcess->Map.pObEvil) { - if((pmObEvil = ObMap_New(OB_MAP_FLAGS_OBJECT_LOCALFREE))) { - VmmEvil_ProcessScan(pProcess, pmObEvil); - pProcess->Map.pObEvil = VmmEvil_InitializeMap(pmObEvil); + if(pProcess->dwPID == 4) { + VmmEvil_KernelScan(H, pProcess, &ctxInit); + } else { + VmmEvil_ProcessScan(H, pProcess, &ctxInit); } + pProcess->Map.pObEvil = VmmEvil_InitializeMap(H, &ctxInit); } - Ob_DECREF_NULL(&pmObEvil); LeaveCriticalSection(&pProcess->Map.LockUpdateMapEvil); } - if(!pProcess->Map.pObEvil) { return FALSE; } + if(!pProcess->Map.pObEvil) { goto fail; } // add to optional all process evil object manager map. - if(pmEvilAll) { + if(ctxEvilAll) { pEvilMap = pProcess->Map.pObEvil; for(i = 0; i < pEvilMap->cMap; i++) { if(pEvilMap->pMap[i].fEvilAllSuppress) { continue; } if(!(pe = LocalAlloc(0, sizeof(VMM_MAP_EVILENTRY)))) { continue; } memcpy(pe, pEvilMap->pMap + i, sizeof(VMM_MAP_EVILENTRY)); qwKey = VMM_MAP_EVILENTRY_HASH(pe->dwPID, pe->tp, pe->va); - ObMap_Push(pmEvilAll, qwKey, pe); + ObStrMap_PushPtrUU(ctxEvilAll->psmEvil, pEvilMap->pMap[i].uszText, &pe->uszText, &pe->cbuText); + ObMap_Push(ctxEvilAll->pmEvil, qwKey, pe); } } - return TRUE; + fResult = TRUE; +fail: + Ob_DECREF(ctxInit.pmEvil); + Ob_DECREF(ctxInit.psmEvil); + return fResult; } /* @@ -523,34 +691,35 @@ BOOL VmmEvil_InitializeProcess(_In_ PVMM_PROCESS pProcess, _In_opt_ POB_MAP pmEv * the same time as when doing it in parallel due to I/O; but serial iteration * does not clog worker threads. */ -DWORD VmmEvil_InitializeAll_ThreadProc(_In_opt_ PVOID pv) +VOID VmmEvil_InitializeAll_ThreadProc(_In_ VMM_HANDLE H, _In_ QWORD qwNotUsed) { SIZE_T i, cPIDs = 0; PDWORD pPIDs = NULL; - POB_MAP pmObEvilAll = NULL; PVMM_PROCESS pObProcess = NULL; PVMMOB_MAP_EVIL pObEvilMap = NULL; - if(!(pmObEvilAll = ObMap_New(OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } - VmmProcessListPIDs(NULL, &cPIDs, 0); + VMMEVIL_INIT_CONTEXT ctxInit = { 0 }; + if(!(ctxInit.pmEvil = ObMap_New(H, OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } + if(!(ctxInit.psmEvil = ObStrMap_New(H, OB_STRMAP_FLAGS_CASE_SENSITIVE))) { goto fail; } + VmmProcessListPIDs(H, NULL, &cPIDs, 0); if(!(pPIDs = LocalAlloc(LMEM_ZEROINIT, cPIDs * sizeof(DWORD)))) { goto fail; } - VmmProcessListPIDs(pPIDs, &cPIDs, 0); - for(i = 0; i < cPIDs; i++) { - ctxVmm->EvilContext.cProgressPercent = min(99, max(1, (BYTE)(i * 100 / cPIDs))); - if((pObProcess = VmmProcessGet(pPIDs[i]))) { - if(!pObProcess->dwState && pObProcess->fUserOnly) { - VmmEvil_InitializeProcess(pObProcess, pmObEvilAll); + VmmProcessListPIDs(H, pPIDs, &cPIDs, 0); + for(i = 0; (i < cPIDs) && !H->fAbort; i++) { + H->vmm.EvilContext.cProgressPercent = min(99, max(1, (BYTE)(i * 100 / cPIDs))); + if((pObProcess = VmmProcessGet(H, pPIDs[i]))) { + if(!pObProcess->dwState && (pObProcess->fUserOnly || (pObProcess->dwPID == 4))) { + VmmEvil_InitializeProcess(H, pObProcess, &ctxInit); } Ob_DECREF_NULL(&pObProcess); } } - pObEvilMap = VmmEvil_InitializeMap(pmObEvilAll); - ObContainer_SetOb(ctxVmm->pObCMapEvil, pObEvilMap); - ctxVmm->EvilContext.cProgressPercent = 100; + pObEvilMap = VmmEvil_InitializeMap(H, &ctxInit); + ObContainer_SetOb(H->vmm.pObCMapEvil, pObEvilMap); + H->vmm.EvilContext.cProgressPercent = 100; fail: - Ob_DECREF(pmObEvilAll); + Ob_DECREF(ctxInit.pmEvil); + Ob_DECREF(ctxInit.psmEvil); Ob_DECREF(pObEvilMap); LocalFree(pPIDs); - return 0; } /* @@ -558,52 +727,54 @@ fail: * may have a significant performance impact when running. If a process is * specified analysis is run for that process in synchronous mode. * If NULL is specified analysis is run for all processes in async mode. -* Retrieve progress by reading ctxVmm->EvilContext.cProgressPercent. +* Retrieve progress by reading H->vmm.EvilContext.cProgressPercent. * CALLER DECREF: return +* -- H * -- pProcess * -- return */ -PVMMOB_MAP_EVIL VmmEvil_Initialize(_In_opt_ PVMM_PROCESS pProcess) +PVMMOB_MAP_EVIL VmmEvil_Initialize(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess) { PVMMOB_MAP_EVIL pObEvilMap = NULL; - if(ctxVmm->f32 || (ctxVmm->kernel.dwVersionBuild < 9600)) { return NULL; } // only support 64-bit Win8.1+ for now + if(H->vmm.f32 || (H->vmm.kernel.dwVersionBuild < 9600)) { return NULL; } // only support 64-bit Win8.1+ for now if(pProcess) { // single process entry if(pProcess->Map.pObEvil) { return Ob_INCREF(pProcess->Map.pObEvil); } - VmmEvil_InitializeProcess(pProcess, NULL); + VmmEvil_InitializeProcess(H, pProcess, NULL); return Ob_INCREF(pProcess->Map.pObEvil); } // all process entry - if((pObEvilMap = ObContainer_GetOb(ctxVmm->pObCMapEvil))) { - if(pObEvilMap->tcCreateTime == ctxVmm->tcRefreshMedium) { return pObEvilMap; } + if((pObEvilMap = ObContainer_GetOb(H->vmm.pObCMapEvil))) { + if(pObEvilMap->tcCreateTime == H->vmm.tcRefreshMedium) { return pObEvilMap; } Ob_DECREF_NULL(&pObEvilMap); } - EnterCriticalSection(&ctxVmm->LockMaster); - if((pObEvilMap = ObContainer_GetOb(ctxVmm->pObCMapEvil))) { - if(pObEvilMap->tcCreateTime == ctxVmm->tcRefreshMedium) { - LeaveCriticalSection(&ctxVmm->LockMaster); + EnterCriticalSection(&H->vmm.LockMaster); + if((pObEvilMap = ObContainer_GetOb(H->vmm.pObCMapEvil))) { + if(pObEvilMap->tcCreateTime == H->vmm.tcRefreshMedium) { + LeaveCriticalSection(&H->vmm.LockMaster); return pObEvilMap; } Ob_DECREF_NULL(&pObEvilMap); } - if(ctxVmm->EvilContext.cProgressPercent == 100) { ctxVmm->EvilContext.cProgressPercent = 0; } - if(ctxVmm->EvilContext.cProgressPercent == 0) { - ctxVmm->EvilContext.cProgressPercent = 1; - VmmWork((LPTHREAD_START_ROUTINE)VmmEvil_InitializeAll_ThreadProc, NULL, NULL); + if(H->vmm.EvilContext.cProgressPercent == 100) { H->vmm.EvilContext.cProgressPercent = 0; } + if(H->vmm.EvilContext.cProgressPercent == 0) { + H->vmm.EvilContext.cProgressPercent = 1; + VmmWork_Value(H, VmmEvil_InitializeAll_ThreadProc, 0, 0, VMMWORK_FLAG_PRIO_NORMAL); } - LeaveCriticalSection(&ctxVmm->LockMaster); + LeaveCriticalSection(&H->vmm.LockMaster); return NULL; } /* * Initialize the global evil map in a synchronously waiting until it's finished. +* -- H */ -VOID VmmEvil_InitializeAll_WaitFinish() +VOID VmmEvil_InitializeAll_WaitFinish(_In_ VMM_HANDLE H) { - Ob_DECREF(VmmEvil_Initialize(NULL)); - while(ctxVmm->EvilContext.cProgressPercent != 100) { + Ob_DECREF(VmmEvil_Initialize(H, NULL)); + while(H->vmm.EvilContext.cProgressPercent != 100) { Sleep(50); } } \ No newline at end of file diff --git a/vmm/vmmevil.h b/vmm/vmmevil.h index cc96549..35d6fb1 100644 --- a/vmm/vmmevil.h +++ b/vmm/vmmevil.h @@ -13,16 +13,18 @@ * may have a significant performance impact when running. If a process is * specified analysis is run for that process in synchronous mode. * If NULL is specified analysis is run for all processes in async mode. -* Retrieve progress by reading ctxVmm->EvilContext.cProgressPercent. +* Retrieve progress by reading H->vmm.EvilContext.cProgressPercent. * CALLER DECREF: return +* -- H * -- pProcess * -- return */ -PVMMOB_MAP_EVIL VmmEvil_Initialize(_In_opt_ PVMM_PROCESS pProcess); +PVMMOB_MAP_EVIL VmmEvil_Initialize(_In_ VMM_HANDLE H, _In_opt_ PVMM_PROCESS pProcess); /* * Initialize the global evil map in a synchronously waiting until it's finished. +* -- H */ -VOID VmmEvil_InitializeAll_WaitFinish(); +VOID VmmEvil_InitializeAll_WaitFinish(_In_ VMM_HANDLE H); #endif /* __VMMEVIL_H__ */ diff --git a/vmm/vmmheap.c b/vmm/vmmheap.c index 6588413..6659a4b 100644 --- a/vmm/vmmheap.c +++ b/vmm/vmmheap.c @@ -160,13 +160,14 @@ typedef struct tdVMMHEAPNT_CTX { } VMMHEAPNT_CTX, *PVMMHEAPNT_CTX; -VOID VmmHeapAlloc_NtInit(_In_ PVMMHEAPNT_CTX ctx); -VOID VmmHeapAlloc_SegInit(_In_ PVMMHEAPNT_CTX ctx); +VOID VmmHeapAlloc_NtInit(_In_ VMM_HANDLE H, _In_ PVMMHEAPNT_CTX ctx); +VOID VmmHeapAlloc_SegInit(_In_ VMM_HANDLE H, _In_ PVMMHEAPNT_CTX ctx); /* * Push an entry onto the heap store list. */ VOID VmmHeapAlloc_PushItem( + _In_ VMM_HANDLE H, _In_ PVMMWINHEAP_CTX_STORE *ppStore, _In_ VMM_HEAPALLOC_TP tp, _In_ QWORD va, @@ -191,13 +192,13 @@ VOID VmmHeapAlloc_PushItem( pe->cb = cb; pe->tp = tp; pStore->c++; - VmmLog(MID_HEAP, LOGLEVEL_6_TRACE, "[%-8s %llx +%x]", VMM_HEAPALLOC_TP_STR[pe->tp], pe->va, pe->cb); + VmmLog(H, MID_HEAP, LOGLEVEL_6_TRACE, "[%-8s %llx +%x]", VMM_HEAPALLOC_TP_STR[pe->tp], pe->va, pe->cb); } /* * Push large allocations onto the heap store list. */ -VOID VmmHeapAlloc_PushLarge(_In_ PVMMHEAPNT_CTX ctx, _In_ PVMMOB_MAP_HEAP pHeapMap, _In_ PVMM_MAP_HEAPENTRY peHeap) +VOID VmmHeapAlloc_PushLarge(_In_ VMM_HANDLE H, _In_ PVMMHEAPNT_CTX ctx, _In_ PVMMOB_MAP_HEAP pHeapMap, _In_ PVMM_MAP_HEAPENTRY peHeap) { BYTE pbBuffer[0x40]; DWORD i, cbHeapHdr = (ctx->f32 ? 0x20 : 0x40); @@ -209,7 +210,7 @@ VOID VmmHeapAlloc_PushLarge(_In_ PVMMHEAPNT_CTX ctx, _In_ PVMMOB_MAP_HEAP pHeapM if(peSegment->iHeap == peHeap->iHeap) { if(peSegment->tp == VMM_HEAP_SEGMENT_TP_NT_LARGE) { cbAlloc = peSegment->cb; - if(ctx->qwHeapEncoding && VmmRead(ctx->pProcess, peSegment->va, pbBuffer, sizeof(pbBuffer))) { + if(ctx->qwHeapEncoding && VmmRead(H, ctx->pProcess, peSegment->va, pbBuffer, sizeof(pbBuffer))) { cbAlloc = VMM_PTR_OFFSET_DUAL(ctx->f32, pbBuffer, 0x10, 0x20); if((cbAlloc > 0x1000) && (cbAlloc <= peSegment->cb)) { if(VmmHeap_GetEntryDecoded(ctx->f32, ctx->qwHeapEncoding, pbBuffer, (ctx->f32 ? 0x18 : 0x30), &eH)) { @@ -219,10 +220,10 @@ VOID VmmHeapAlloc_PushLarge(_In_ PVMMHEAPNT_CTX ctx, _In_ PVMMOB_MAP_HEAP pHeapM cbAlloc = peSegment->cb; } } - VmmHeapAlloc_PushItem(&ctx->pStore, VMM_HEAPALLOC_TP_NT_LARGE, peSegment->va + cbHeapHdr, (DWORD)(cbAlloc - cbHeapHdr)); + VmmHeapAlloc_PushItem(H, &ctx->pStore, VMM_HEAPALLOC_TP_NT_LARGE, peSegment->va + cbHeapHdr, (DWORD)(cbAlloc - cbHeapHdr)); } if(peSegment->tp == VMM_HEAP_SEGMENT_TP_SEG_LARGE) { - VmmHeapAlloc_PushItem(&ctx->pStore, VMM_HEAPALLOC_TP_SEG_LARGE, peSegment->va, peSegment->cb); + VmmHeapAlloc_PushItem(H, &ctx->pStore, VMM_HEAPALLOC_TP_SEG_LARGE, peSegment->va, peSegment->cb); } } } @@ -230,6 +231,7 @@ VOID VmmHeapAlloc_PushLarge(_In_ PVMMHEAPNT_CTX ctx, _In_ PVMMOB_MAP_HEAP pHeapM /* * Fetch LFH / Heap key from symbols. +* -- H * -- pProcess * -- f32 * -- pqwNtHeapKey = the HeapKey or 0 on fail @@ -237,22 +239,22 @@ VOID VmmHeapAlloc_PushLarge(_In_ PVMMHEAPNT_CTX ctx, _In_ PVMMOB_MAP_HEAP pHeapM * -- pdqSegLfhKey = the LfhKey or 0 on fail * -- pdwNtLfhKey = the LfhKey or 0 on fail (32-bit nt-heap key) */ -VOID VmmHeapAlloc_GetHeapKeys(_In_ PVMM_PROCESS pProcess, _In_ BOOL f32, _Out_opt_ PQWORD pqwNtHeapKey, _Out_opt_ PQWORD pqwSegHeapGbl, _Out_opt_ PDWORD pdwSegLfhKey, _Out_opt_ PDWORD pdwNtLfhKey) +VOID VmmHeapAlloc_GetHeapKeys(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ BOOL f32, _Out_opt_ PQWORD pqwNtHeapKey, _Out_opt_ PQWORD pqwSegHeapGbl, _Out_opt_ PDWORD pdwSegLfhKey, _Out_opt_ PDWORD pdwNtLfhKey) { DWORD i; DWORD oHeapGlobals = 0; - BOOL fWow = (f32 && !ctxVmm->f32); + BOOL fWow = (f32 && !H->vmm.f32); PVMMOB_MAP_MODULE pObModuleMap = NULL; PVMM_MAP_MODULEENTRY pNtdll; PDB_HANDLE hPDB = (fWow ? PDB_HANDLE_NTDLL_WOW64 : PDB_HANDLE_NTDLL); // try fast path first: (windows os and symbols already loaded) if(pqwSegHeapGbl) { *pqwSegHeapGbl = 0; } if(pdwSegLfhKey) { *pdwSegLfhKey = 0; } - if(pqwNtHeapKey && !PDB_GetSymbolQWORD(hPDB, "RtlpHeapKey", pProcess, pqwNtHeapKey)) { *pqwNtHeapKey = 0; } - if(pdwNtLfhKey && !PDB_GetSymbolDWORD(hPDB, "RtlpLFHKey", pProcess, pdwNtLfhKey)) { *pdwNtLfhKey = 0; } + if(pqwNtHeapKey && !PDB_GetSymbolQWORD(H, hPDB, "RtlpHeapKey", pProcess, pqwNtHeapKey)) { *pqwNtHeapKey = 0; } + if(pdwNtLfhKey && !PDB_GetSymbolDWORD(H, hPDB, "RtlpLFHKey", pProcess, pdwNtLfhKey)) { *pdwNtLfhKey = 0; } if(!pqwSegHeapGbl && !pdwSegLfhKey && (!pqwNtHeapKey || *pqwNtHeapKey) && (!pdwNtLfhKey || *pdwNtLfhKey)) { return; } // try slow path: (load symbols via module list) - if(VmmMap_GetModuleEntryEx(pProcess, 0, "ntdll.dll", &pObModuleMap, &pNtdll)) { + if(VmmMap_GetModuleEntryEx(H, pProcess, 0, "ntdll.dll", &pObModuleMap, &pNtdll)) { if(fWow != pNtdll->fWoW64) { pNtdll = NULL; for(i = 0; i < pObModuleMap->cMap; i++) { @@ -262,14 +264,14 @@ VOID VmmHeapAlloc_GetHeapKeys(_In_ PVMM_PROCESS pProcess, _In_ BOOL f32, _Out_op } } if(pNtdll) { - PDB_LoadEnsure(PDB_GetHandleFromModuleAddress(pProcess, pNtdll->vaBase)); + PDB_LoadEnsure(H, PDB_GetHandleFromModuleAddress(H, pProcess, pNtdll->vaBase)); //if(pqwSegHeapGbl) { PDB_GetSymbolQWORD2(hPDB, pNtdll->vaBase, "RtlpHpHeapGlobals", pProcess, pqwSegHeapGbl); } - if(pqwNtHeapKey) { PDB_GetSymbolQWORD2(hPDB, pNtdll->vaBase, "RtlpHeapKey", pProcess, pqwNtHeapKey); } - if(pdwNtLfhKey) { PDB_GetSymbolDWORD2(hPDB, pNtdll->vaBase, "RtlpLFHKey", pProcess, pdwNtLfhKey); } + if(pqwNtHeapKey) { PDB_GetSymbolQWORD2(H, hPDB, pNtdll->vaBase, "RtlpHeapKey", pProcess, pqwNtHeapKey); } + if(pdwNtLfhKey) { PDB_GetSymbolDWORD2(H, hPDB, pNtdll->vaBase, "RtlpLFHKey", pProcess, pdwNtLfhKey); } if(pqwSegHeapGbl || pdwSegLfhKey) { - if(PDB_GetSymbolOffset(hPDB, "RtlpHpHeapGlobals", &oHeapGlobals) && oHeapGlobals) { - VmmRead(pProcess, pNtdll->vaBase + oHeapGlobals, (PBYTE)pqwSegHeapGbl, sizeof(QWORD)); - VmmRead(pProcess, pNtdll->vaBase + oHeapGlobals + (f32 ? 4 : 8), (PBYTE)pdwSegLfhKey, sizeof(DWORD)); + if(PDB_GetSymbolOffset(H, hPDB, "RtlpHpHeapGlobals", &oHeapGlobals) && oHeapGlobals) { + VmmRead(H, pProcess, pNtdll->vaBase + oHeapGlobals, (PBYTE)pqwSegHeapGbl, sizeof(QWORD)); + VmmRead(H, pProcess, pNtdll->vaBase + oHeapGlobals + (f32 ? 4 : 8), (PBYTE)pdwSegLfhKey, sizeof(DWORD)); } } } @@ -294,45 +296,46 @@ VOID VmmHeapAlloc_CloseObCallback(_In_ PVOID pVmmOb) /* * Initialize a new heap allocation map. * This function is called in a single-threaded process lock. +* -- H * -- pProcess * -- vaHeap = va of heap or heap id. * -- return */ _Success_(return != NULL) -PVMMOB_MAP_HEAPALLOC VmmHeapAlloc_Init_DoWork(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaHeap) +PVMMOB_MAP_HEAPALLOC VmmHeapAlloc_Init_DoWork(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaHeap) { PVMMHEAPNT_CTX ctx = NULL; PVMMWINHEAP_CTX_STORE pStore; DWORD iMap = 0, cEntry; SIZE_T cbAlloc; PVMMOB_MAP_HEAPALLOC pObAlloc = NULL; - VmmLog(MID_HEAP, LOGLEVEL_6_TRACE, "INIT HEAPALLOCMAP START: pid=%5i heap=%llx", pProcess->dwPID, vaHeap); + VmmLog(H, MID_HEAP, LOGLEVEL_6_TRACE, "INIT HEAPALLOCMAP START: pid=%5i heap=%llx", pProcess->dwPID, vaHeap); // 1: init if(!(ctx = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMHEAPNT_CTX)))) { goto fail; } - if(!VmmMap_GetHeap(pProcess, &ctx->pHeapMap) || !(ctx->pHeapEntry = VmmMap_GetHeapEntry(ctx->pHeapMap, vaHeap))) { - VmmLog(MID_HEAP, LOGLEVEL_5_DEBUG, "FAIL: NO HEAP ENTRY: pid=%i %va=%llx", pProcess->dwPID, vaHeap); + if(!VmmMap_GetHeap(H, pProcess, &ctx->pHeapMap) || !(ctx->pHeapEntry = VmmMap_GetHeapEntry(H, ctx->pHeapMap, vaHeap))) { + VmmLog(H, MID_HEAP, LOGLEVEL_5_DEBUG, "FAIL: NO HEAP ENTRY: pid=%i %va=%llx", pProcess->dwPID, vaHeap); goto fail; } ctx->f32 = ctx->pHeapEntry->f32; - ctx->po = ctx->f32 ? &ctxVmm->offset.HEAP32 : &ctxVmm->offset.HEAP64; + ctx->po = ctx->f32 ? &H->vmm.offset.HEAP32 : &H->vmm.offset.HEAP64; if(!(ctx->pStore = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMWINHEAP_CTX_STORE)))) { goto fail; } ctx->pProcess = pProcess; // 2: dispatch to nt/segment heap subsystems if(ctx->pHeapEntry->tp == VMM_HEAP_TP_NT) { - VmmHeapAlloc_NtInit(ctx); + VmmHeapAlloc_NtInit(H, ctx); } else if(ctx->pHeapEntry->tp == VMM_HEAP_TP_SEG) { - VmmHeapAlloc_SegInit(ctx); + VmmHeapAlloc_SegInit(H, ctx); } else { - VmmLog(MID_HEAP, LOGLEVEL_2_WARNING, "FAIL: UNSUPPORTED HEAP TYPE - SHOULD NOT HAPPEN!: pid=%i %va=%llx", pProcess->dwPID, vaHeap); + VmmLog(H, MID_HEAP, LOGLEVEL_2_WARNING, "FAIL: UNSUPPORTED HEAP TYPE - SHOULD NOT HAPPEN!: pid=%i %va=%llx", pProcess->dwPID, vaHeap); goto fail; } // 3: add large entries from heap map segments - VmmHeapAlloc_PushLarge(ctx, ctx->pHeapMap, ctx->pHeapEntry); + VmmHeapAlloc_PushLarge(H, ctx, ctx->pHeapMap, ctx->pHeapEntry); // 4: alloc/create map object cEntry = ctx->pStore->c + ctx->pStore->cPrevious; cbAlloc = sizeof(VMMOB_MAP_HEAPALLOC) + cEntry * sizeof(VMM_MAP_HEAPALLOCENTRY); if(cbAlloc > 0x80000000) { goto fail; } - if(!(pObAlloc = Ob_Alloc(OB_TAG_MAP_HEAPALLOC, 0, cbAlloc, VmmHeapAlloc_CloseObCallback, NULL))) { goto fail; } + if(!(pObAlloc = Ob_AllocEx(H, OB_TAG_MAP_HEAPALLOC, 0, cbAlloc, VmmHeapAlloc_CloseObCallback, NULL))) { goto fail; } pObAlloc->pHeapMap = Ob_INCREF(ctx->pHeapMap); pObAlloc->pHeapEntry = ctx->pHeapEntry; pObAlloc->cMap = cEntry; @@ -352,50 +355,51 @@ fail: Ob_DECREF(ctx->pHeapMap); LocalFree(ctx); } - VmmLog(MID_HEAP, LOGLEVEL_6_TRACE, "INIT HEAPALLOCMAP END: pid=%5i heap=%llx alloc=%x", pProcess->dwPID, vaHeap, (pObAlloc ? pObAlloc->cMap : 0)); + VmmLog(H, MID_HEAP, LOGLEVEL_6_TRACE, "INIT HEAPALLOCMAP END: pid=%5i heap=%llx alloc=%x", pProcess->dwPID, vaHeap, (pObAlloc ? pObAlloc->cMap : 0)); return pObAlloc; } /* * Refresh any cached heap allocation maps. */ -VOID VmmHeapAlloc_Refresh() +VOID VmmHeapAlloc_Refresh(_In_ VMM_HANDLE H) { - ObCacheMap_Clear(ctxVmm->pObCacheMapHeapAlloc); + ObCacheMap_Clear(H->vmm.pObCacheMapHeapAlloc); } /* * Retrive the heap allocation map for the specific heap. * The map is cached up until a total process refresh is made (medium refresh). * CALLER DECREF: return +* -- H * -- pProcess * -- vaHeap = va of heap or heap id. * -- return */ -PVMMOB_MAP_HEAPALLOC VmmHeapAlloc_Initialize(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaHeap) +PVMMOB_MAP_HEAPALLOC VmmHeapAlloc_Initialize(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaHeap) { PVMMOB_MAP_HEAPALLOC pObHeapAlloc = NULL; // 1: ensure cache map exists (or init) - if(!ctxVmm->pObCacheMapHeapAlloc) { - EnterCriticalSection(&ctxVmm->LockPlugin); - if(!ctxVmm->pObCacheMapHeapAlloc) { - ctxVmm->pObCacheMapHeapAlloc = ObCacheMap_New(0x10, NULL, OB_CACHEMAP_FLAGS_OBJECT_OB); + if(!H->vmm.pObCacheMapHeapAlloc) { + EnterCriticalSection(&H->vmm.LockPlugin); + if(!H->vmm.pObCacheMapHeapAlloc) { + H->vmm.pObCacheMapHeapAlloc = ObCacheMap_New(H, 0x10, NULL, OB_CACHEMAP_FLAGS_OBJECT_OB); } - LeaveCriticalSection(&ctxVmm->LockPlugin); + LeaveCriticalSection(&H->vmm.LockPlugin); } // 2: try fetch from cache map - if(!(pObHeapAlloc = ObCacheMap_GetByKey(ctxVmm->pObCacheMapHeapAlloc, vaHeap + pProcess->dwPID))) { + if(!(pObHeapAlloc = ObCacheMap_GetByKey(H->vmm.pObCacheMapHeapAlloc, vaHeap + pProcess->dwPID))) { EnterCriticalSection(&pProcess->LockUpdate); - if(!(pObHeapAlloc = ObCacheMap_GetByKey(ctxVmm->pObCacheMapHeapAlloc, vaHeap + pProcess->dwPID))) { - if((pObHeapAlloc = VmmHeapAlloc_Init_DoWork(pProcess, vaHeap))) { - ObCacheMap_Push(ctxVmm->pObCacheMapHeapAlloc, vaHeap + pProcess->dwPID, pObHeapAlloc, 0); + if(!(pObHeapAlloc = ObCacheMap_GetByKey(H->vmm.pObCacheMapHeapAlloc, vaHeap + pProcess->dwPID))) { + if((pObHeapAlloc = VmmHeapAlloc_Init_DoWork(H, pProcess, vaHeap))) { + ObCacheMap_Push(H->vmm.pObCacheMapHeapAlloc, vaHeap + pProcess->dwPID, pObHeapAlloc, 0); } } LeaveCriticalSection(&pProcess->LockUpdate); } // 3: on fail, create dummy map and push to cache - if(!pObHeapAlloc && (pObHeapAlloc = Ob_Alloc(OB_TAG_MAP_HEAPALLOC, LMEM_ZEROINIT, sizeof(VMMOB_MAP_HEAPALLOC), NULL, NULL))) { - ObCacheMap_Push(ctxVmm->pObCacheMapHeapAlloc, vaHeap + pProcess->dwPID, pObHeapAlloc, 0); + if(!pObHeapAlloc && (pObHeapAlloc = Ob_AllocEx(H, OB_TAG_MAP_HEAPALLOC, LMEM_ZEROINIT, sizeof(VMMOB_MAP_HEAPALLOC), NULL, NULL))) { + ObCacheMap_Push(H->vmm.pObCacheMapHeapAlloc, vaHeap + pProcess->dwPID, pObHeapAlloc, 0); } return pObHeapAlloc; } @@ -439,7 +443,7 @@ typedef union tdVMMHEAPALLOC_SEG_HEAP_VS_CHUNK_HEADER_SIZE64 { * Parse the vs heap segment - [ntdll!_HEAP_VS_SUBSEGMENT] // [ntdll!_HEAP_VS_CHUNK_HEADER] * TODO: VERIFY HEAP ALLOCATIONS BETTER! */ -VOID VmmHeapAlloc_SegVS(_In_ PVMMHEAPNT_CTX ctx, _In_ DWORD iCtx, _In_ QWORD va, _In_ PBYTE pb, _In_ DWORD cb) +VOID VmmHeapAlloc_SegVS(_In_ VMM_HANDLE H, _In_ PVMMHEAPNT_CTX ctx, _In_ DWORD iCtx, _In_ QWORD va, _In_ PBYTE pb, _In_ DWORD cb) { DWORD cbPoolHdr, oVsChunkHdr, cbChunkSize, oBlock, cbBlock, cbAdjust; QWORD vaBlock, vaChunkHeader; @@ -466,7 +470,7 @@ VOID VmmHeapAlloc_SegVS(_In_ PVMMHEAPNT_CTX ctx, _In_ DWORD iCtx, _In_ QWORD va, // loop over pool entries while(oVsChunkHdr + 0x30 < cb) { vaChunkHeader = va + oVsChunkHdr; - if(ctxVmm->f32) { + if(H->vmm.f32) { pChunkSize32 = (PVMMHEAPALLOC_SEG_HEAP_VS_CHUNK_HEADER_SIZE32)(pb + oVsChunkHdr); pChunkSize32->HeaderBits = (DWORD)(pChunkSize32->HeaderBits ^ vaChunkHeader ^ ctx->qwSegHeapGbl); fAlloc = (pChunkSize32->Allocated & 1) ? TRUE : FALSE; @@ -493,7 +497,7 @@ VOID VmmHeapAlloc_SegVS(_In_ PVMMHEAPNT_CTX ctx, _In_ DWORD iCtx, _In_ QWORD va, vaBlock += cbAdjust; } if(((vaBlock & ~0xfff) == ((vaBlock + cbBlock - cbPoolHdr) & ~0xfff)) || (cbBlock >= 0xff0)) { - VmmHeapAlloc_PushItem(&ctx->pStore, VMM_HEAPALLOC_TP_SEG_VS, vaBlock, cbBlock); + VmmHeapAlloc_PushItem(H, &ctx->pStore, VMM_HEAPALLOC_TP_SEG_VS, vaBlock, cbBlock); } } oVsChunkHdr += cbChunkSize; @@ -504,7 +508,7 @@ VOID VmmHeapAlloc_SegVS(_In_ PVMMHEAPNT_CTX ctx, _In_ DWORD iCtx, _In_ QWORD va, * Parse the low fragmentation heap segment - [ntdll!_HEAP_LFH_SUBSEGMENT] * TODO: VERIFY HEAP ALLOCATIONS BETTER! */ -VOID VmmHeapAlloc_SegLFH(_In_ PVMMHEAPNT_CTX ctx, _In_ DWORD iCtx, _In_ QWORD va, _In_ PBYTE pb, _In_ DWORD cb) +VOID VmmHeapAlloc_SegLFH(_In_ VMM_HANDLE H, _In_ PVMMHEAPNT_CTX ctx, _In_ DWORD iCtx, _In_ QWORD va, _In_ PBYTE pb, _In_ DWORD cb) { UCHAR ucBits; PBYTE pbBitmap; @@ -524,7 +528,7 @@ VOID VmmHeapAlloc_SegLFH(_In_ PVMMHEAPNT_CTX ctx, _In_ DWORD iCtx, _In_ QWORD va if((oBlock & 0xfff) + cbBlockSize > 0x1000) { continue; } // block do not cross page boundaries ucBits = pbBitmap[iBlock >> 2] >> ((iBlock & 0x3) << 1); if(((ucBits & 3) == 1)) { - VmmHeapAlloc_PushItem(&ctx->pStore, VMM_HEAPALLOC_TP_SEG_LFH, va + oBlock, cbBlockSize); + VmmHeapAlloc_PushItem(H, &ctx->pStore, VMM_HEAPALLOC_TP_SEG_LFH, va + oBlock, cbBlockSize); } } } @@ -532,7 +536,7 @@ VOID VmmHeapAlloc_SegLFH(_In_ PVMMHEAPNT_CTX ctx, _In_ DWORD iCtx, _In_ QWORD va /* * Parse a single segment heap range descriptor */ -DWORD VmmHeapAlloc_SegRangeDescriptor(_In_ PVMMHEAPNT_CTX ctx, _In_ DWORD iCtx, _In_ QWORD vaPgSeg, _In_ PBYTE pbPgSeg, _In_ DWORD cbPgSeg, _In_ DWORD iRD) +DWORD VmmHeapAlloc_SegRangeDescriptor(_In_ VMM_HANDLE H, _In_ PVMMHEAPNT_CTX ctx, _In_ DWORD iCtx, _In_ QWORD vaPgSeg, _In_ PBYTE pbPgSeg, _In_ DWORD cbPgSeg, _In_ DWORD iRD) { UCHAR ucUnitSize, ucRangeFlags; DWORD oRange, cbRange, oRD; @@ -549,10 +553,10 @@ DWORD VmmHeapAlloc_SegRangeDescriptor(_In_ PVMMHEAPNT_CTX ctx, _In_ DWORD iCtx, // Large Pool - not yet supported! } else if(ucRangeFlags == 11) { // Lfh - VmmHeapAlloc_SegLFH(ctx, iCtx, vaPgSeg + oRange, pbPgSeg + oRange, cbRange); + VmmHeapAlloc_SegLFH(H, ctx, iCtx, vaPgSeg + oRange, pbPgSeg + oRange, cbRange); } else if(ucRangeFlags == 15) { // Vs - VmmHeapAlloc_SegVS(ctx, iCtx, vaPgSeg + oRange, pbPgSeg + oRange, cbRange); + VmmHeapAlloc_SegVS(H, ctx, iCtx, vaPgSeg + oRange, pbPgSeg + oRange, cbRange); } return ucUnitSize; } @@ -560,7 +564,7 @@ DWORD VmmHeapAlloc_SegRangeDescriptor(_In_ PVMMHEAPNT_CTX ctx, _In_ DWORD iCtx, /* * Init Segment heap entries (excl. large entries) */ -VOID VmmHeapAlloc_SegInit(_In_ PVMMHEAPNT_CTX ctx) +VOID VmmHeapAlloc_SegInit(_In_ VMM_HANDLE H, _In_ PVMMHEAPNT_CTX ctx) { BOOL f32 = ctx->f32; DWORD i, o, iCtx, iRD; @@ -570,19 +574,19 @@ VOID VmmHeapAlloc_SegInit(_In_ PVMMHEAPNT_CTX ctx) BYTE pbSegHdr[0x400]; PVMM_MAP_HEAP_SEGMENTENTRY peSegment; // 1: init - if(ctxVmm->kernel.dwVersionBuild < 16299) { - VmmLog(MID_HEAP, LOGLEVEL_5_DEBUG, "FAIL: Segment Heap not supported below Win10 1709 / 16299"); + if(H->vmm.kernel.dwVersionBuild < 16299) { + VmmLog(H, MID_HEAP, LOGLEVEL_5_DEBUG, "FAIL: Segment Heap not supported below Win10 1709 / 16299"); goto fail; } // 2: fetch keys - VmmHeapAlloc_GetHeapKeys(ctx->pProcess, ctx->f32, NULL, &ctx->qwSegHeapGbl, &ctx->dwSegLfhKey, NULL); + VmmHeapAlloc_GetHeapKeys(H, ctx->pProcess, ctx->f32, NULL, &ctx->qwSegHeapGbl, &ctx->dwSegLfhKey, NULL); if(!ctx->qwSegHeapGbl || !ctx->dwSegLfhKey) { - VmmLog(MID_HEAP, LOGLEVEL_6_TRACE, "FAIL: HEAP / LFH KEY"); + VmmLog(H, MID_HEAP, LOGLEVEL_6_TRACE, "FAIL: HEAP / LFH KEY"); goto fail; } // 3: fetch heap seg context info: - if(!VmmRead(ctx->pProcess, ctx->pHeapEntry->va, pbSegHdr, sizeof(pbSegHdr))) { - VmmLog(MID_HEAP, LOGLEVEL_5_DEBUG, "FAIL: Segment heap fail read at: %llx", ctx->pHeapEntry->va); + if(!VmmRead(H, ctx->pProcess, ctx->pHeapEntry->va, pbSegHdr, sizeof(pbSegHdr))) { + VmmLog(H, MID_HEAP, LOGLEVEL_5_DEBUG, "FAIL: Segment heap fail read at: %llx", ctx->pHeapEntry->va); goto fail; } for(i = 0; i < 2; i++) { @@ -600,7 +604,7 @@ VOID VmmHeapAlloc_SegInit(_In_ PVMMHEAPNT_CTX ctx) LocalFree(pbPgSeg); cbPgSeg = peSegment->cb; if(!(pbPgSeg = LocalAlloc(0, cbPgSeg))) { goto fail; } - VmmRead2(ctx->pProcess, peSegment->va, pbPgSeg, cbPgSeg, VMM_FLAG_ZEROPAD_ON_FAIL); + VmmRead2(H, ctx->pProcess, peSegment->va, pbPgSeg, cbPgSeg, VMM_FLAG_ZEROPAD_ON_FAIL); // signature check: vaSignature = VMM_PTR_OFFSET_DUAL(f32, pbPgSeg, 8, 16) ^ peSegment->va ^ ctx->qwSegHeapGbl ^ 0xa2e64eada2e64ead; iCtx = (DWORD)-1; @@ -610,7 +614,7 @@ VOID VmmHeapAlloc_SegInit(_In_ PVMMHEAPNT_CTX ctx) // walk range descriptors: iRD = ctx->segctx[iCtx].ucFirstDescriptorIndex; while(iRD < 256) { - iRD += VmmHeapAlloc_SegRangeDescriptor(ctx, iCtx, peSegment->va, pbPgSeg, cbPgSeg, iRD); + iRD += VmmHeapAlloc_SegRangeDescriptor(H, ctx, iCtx, peSegment->va, pbPgSeg, cbPgSeg, iRD); } } } @@ -642,10 +646,10 @@ BOOL VmmHeapAlloc_NtInitLfhUserData_VerifyEncoded(_In_ BOOL f32, _In_ PVMMHEAPAL return !fFail; } -VOID VmmHeapAlloc_NtInitLfhUserDataWin7(_In_ PVMMHEAPNT_CTX ctx, _In_ QWORD vaLfhUD, _In_ PBYTE pbLfhUD, _In_ DWORD cbLfhUD) +VOID VmmHeapAlloc_NtInitLfhUserDataWin7(_In_ VMM_HANDLE H, _In_ PVMMHEAPNT_CTX ctx, _In_ QWORD vaLfhUD, _In_ PBYTE pbLfhUD, _In_ DWORD cbLfhUD) { BYTE pbSubSegment[0x20]; - BOOL f32 = ctxVmm->f32; + BOOL f32 = H->vmm.f32; QWORD vaSubSegment, vaChunk; DWORD cbChunk, cbUnitSize = ctx->f32 ? 8 : 16; DWORD cbHeaderSize = ctx->f32 ? 0x10 : 0x20; @@ -655,7 +659,7 @@ VOID VmmHeapAlloc_NtInitLfhUserDataWin7(_In_ PVMMHEAPNT_CTX ctx, _In_ QWORD vaLf // 2: fetch _HEAP_SUBSEGMENT with BlockSize, BlockCount and AggregateExchg (_INTERLOCK_SEQ) vaSubSegment = VMM_PTR_OFFSET(vaLfhUD, pbLfhUD, 0); if(!VMM_UADDR_DUAL_4_8(f32, vaSubSegment)) { return; } - if(!VmmRead(ctx->pProcess, vaSubSegment, pbSubSegment, sizeof(pbSubSegment))) { return; } + if(!VmmRead(H, ctx->pProcess, vaSubSegment, pbSubSegment, sizeof(pbSubSegment))) { return; } dwBlockSize = *(PWORD)(pbSubSegment + (f32 ? 0x10 : 0x18)); cBlock = *(PWORD)(pbSubSegment + (f32 ? 0x14 : 0x1c)); cFreeBlock = *(PWORD)(pbSubSegment + (f32 ? 0x08 : 0x10)); @@ -672,7 +676,7 @@ VOID VmmHeapAlloc_NtInitLfhUserDataWin7(_In_ PVMMHEAPNT_CTX ctx, _In_ QWORD vaLf vaChunk -= cbUnitSize; cbChunk = 8; } - VmmHeapAlloc_PushItem(&ctx->pStore, VMM_HEAPALLOC_TP_NT_LFH, vaChunk, cbChunk); + VmmHeapAlloc_PushItem(H, &ctx->pStore, VMM_HEAPALLOC_TP_NT_LFH, vaChunk, cbChunk); } } @@ -680,7 +684,7 @@ VOID VmmHeapAlloc_NtInitLfhUserDataWin7(_In_ PVMMHEAPNT_CTX ctx, _In_ QWORD vaLf * Parse a _HEAP_USERDATA_HEADER for potential LFH entries. * NB! Windows 7 and earlier are not supported! */ -VOID VmmHeapAlloc_NtInitLfhUserData(_In_ PVMMHEAPNT_CTX ctx, _In_ QWORD vaLfhUD, _In_ PBYTE pbLfhUD, _In_ DWORD cbLfhUD) +VOID VmmHeapAlloc_NtInitLfhUserData(_In_ VMM_HANDLE H, _In_ PVMMHEAPNT_CTX ctx, _In_ QWORD vaLfhUD, _In_ PBYTE pbLfhUD, _In_ DWORD cbLfhUD) { PDWORD pdwBitmapData; DWORD cbUnitSize = ctx->f32 ? 8 : 16; @@ -711,7 +715,7 @@ VOID VmmHeapAlloc_NtInitLfhUserData(_In_ PVMMHEAPNT_CTX ctx, _In_ QWORD vaLfhUD, vaChunk -= cbUnitSize; cbChunk = 8; } - VmmHeapAlloc_PushItem(&ctx->pStore, VMM_HEAP_SEGMENT_TP_NT_LFH, vaChunk, cbChunk); + VmmHeapAlloc_PushItem(H, &ctx->pStore, VMM_HEAP_SEGMENT_TP_NT_LFH, vaChunk, cbChunk); } } iBit += 32; @@ -721,35 +725,35 @@ VOID VmmHeapAlloc_NtInitLfhUserData(_In_ PVMMHEAPNT_CTX ctx, _In_ QWORD vaLfhUD, /* * Parse NT heap segment for heap entries. */ -VOID VmmHeapAlloc_NtInitSeg(_In_ PVMMHEAPNT_CTX ctx, _In_ QWORD vaSegment, _In_ PBYTE pbSegment, _In_ DWORD cbSegment, _In_ DWORD oFirst) +VOID VmmHeapAlloc_NtInitSeg(_In_ VMM_HANDLE H, _In_ PVMMHEAPNT_CTX ctx, _In_ QWORD vaSegment, _In_ PBYTE pbSegment, _In_ DWORD cbSegment, _In_ DWORD oFirst) { DWORD cbUnitSize = ctx->f32 ? 8 : 16; QWORD vaChunk; _HEAPENTRY eH; DWORD cbAlloc, dwPreviousSize = 0, oEntry = oFirst; - VmmLog(MID_HEAP, LOGLEVEL_6_TRACE, "PARSE SEGMENT: %llx :: %x ", vaSegment, cbSegment); + VmmLog(H, MID_HEAP, LOGLEVEL_6_TRACE, "PARSE SEGMENT: %llx :: %x ", vaSegment, cbSegment); while(oEntry < cbSegment - 0x10) { vaChunk = vaSegment + oEntry; if(!VmmHeap_GetEntryDecoded(ctx->f32, ctx->qwHeapEncoding, pbSegment, oEntry, &eH)) { - VmmLog(MID_HEAP, LOGLEVEL_6_TRACE, "FAIL: (CHECKSUM) AT: %llx %x", vaSegment, oEntry); + VmmLog(H, MID_HEAP, LOGLEVEL_6_TRACE, "FAIL: (CHECKSUM) AT: %llx %x", vaSegment, oEntry); break; } if(dwPreviousSize && (dwPreviousSize != eH.PreviousSize)) { - VmmLog(MID_HEAP, LOGLEVEL_6_TRACE, "FAIL: (PREVSIZE) AT: %llx %x", vaSegment, oEntry); + VmmLog(H, MID_HEAP, LOGLEVEL_6_TRACE, "FAIL: (PREVSIZE) AT: %llx %x", vaSegment, oEntry); break; } cbAlloc = (eH.Size - 1) * cbUnitSize - eH.UnusedBytes; if((eH.Flags & 1) && cbAlloc && (cbAlloc < 0x01000000)) { if(eH.Flags & 8) { // internal: potential lfh - if(ctxVmm->kernel.dwVersionBuild <= 7601) { - VmmHeapAlloc_NtInitLfhUserDataWin7(ctx, vaChunk + cbUnitSize, pbSegment + oEntry + cbUnitSize, cbAlloc); + if(H->vmm.kernel.dwVersionBuild <= 7601) { + VmmHeapAlloc_NtInitLfhUserDataWin7(H, ctx, vaChunk + cbUnitSize, pbSegment + oEntry + cbUnitSize, cbAlloc); } else { - VmmHeapAlloc_NtInitLfhUserData(ctx, vaChunk + cbUnitSize, pbSegment + oEntry + cbUnitSize, cbAlloc); + VmmHeapAlloc_NtInitLfhUserData(H, ctx, vaChunk + cbUnitSize, pbSegment + oEntry + cbUnitSize, cbAlloc); } } else { // only store active non-internal - VmmHeapAlloc_PushItem(&ctx->pStore, VMM_HEAPALLOC_TP_NT_HEAP, vaChunk + cbUnitSize, cbAlloc); + VmmHeapAlloc_PushItem(H, &ctx->pStore, VMM_HEAPALLOC_TP_NT_HEAP, vaChunk + cbUnitSize, cbAlloc); } } dwPreviousSize = eH.Size; @@ -760,21 +764,21 @@ VOID VmmHeapAlloc_NtInitSeg(_In_ PVMMHEAPNT_CTX ctx, _In_ QWORD vaSegment, _In_ /* * Init NT heap entries (excl. large entries) */ -VOID VmmHeapAlloc_NtInit(_In_ PVMMHEAPNT_CTX ctx) +VOID VmmHeapAlloc_NtInit(_In_ VMM_HANDLE H, _In_ PVMMHEAPNT_CTX ctx) { DWORD i, cbSegment, dwSegmentSignature; BYTE pbSegmentHdr[0x80]; PBYTE pbSegment; QWORD vaFirstEntry, vaLastEntry; PVMM_MAP_HEAP_SEGMENTENTRY peSegment; - if(ctxVmm->kernel.dwVersionBuild <= 2600) { - VmmLog(MID_HEAP, LOGLEVEL_5_DEBUG, "FAIL: HeapAlloc not supported on WinXP"); + if(H->vmm.kernel.dwVersionBuild <= 2600) { + VmmLog(H, MID_HEAP, LOGLEVEL_5_DEBUG, "FAIL: HeapAlloc not supported on WinXP"); return; } // 1: fetch encoding heap entry if(ctx->po->nt.HEAP.Encoding) { - if(!VmmRead(ctx->pProcess, ctx->pHeapEntry->va + ctx->po->nt.HEAP.Encoding + (ctx->f32 ? 0 : 8), (PBYTE)&ctx->qwHeapEncoding, sizeof(QWORD))) { - VmmLog(MID_HEAP, LOGLEVEL_4_VERBOSE, "FAIL: Fetch Heap Encoding: %llx", ctx->pHeapEntry->va); + if(!VmmRead(H, ctx->pProcess, ctx->pHeapEntry->va + ctx->po->nt.HEAP.Encoding + (ctx->f32 ? 0 : 8), (PBYTE)&ctx->qwHeapEncoding, sizeof(QWORD))) { + VmmLog(H, MID_HEAP, LOGLEVEL_4_VERBOSE, "FAIL: Fetch Heap Encoding: %llx", ctx->pHeapEntry->va); } } // 2: walk segments to find any LFH area, this is required for LFH decode: @@ -788,15 +792,15 @@ VOID VmmHeapAlloc_NtInit(_In_ PVMMHEAPNT_CTX ctx) } // 3: fetch Lfh Key if LFH area exists if(ctx->vaLfh) { - VmmHeapAlloc_GetHeapKeys(ctx->pProcess, ctx->f32, NULL, NULL, NULL, &ctx->dwLfhKey); - VmmLog(MID_HEAP, LOGLEVEL_6_TRACE, "%s LFH KEY: %x ", (ctx->dwLfhKey ? "LOAD" : "FAIL"), ctx->dwLfhKey); + VmmHeapAlloc_GetHeapKeys(H, ctx->pProcess, ctx->f32, NULL, NULL, NULL, &ctx->dwLfhKey); + VmmLog(H, MID_HEAP, LOGLEVEL_6_TRACE, "%s LFH KEY: %x ", (ctx->dwLfhKey ? "LOAD" : "FAIL"), ctx->dwLfhKey); } // 4: walk segments and process them! for(i = 0; i < ctx->pHeapMap->cSegments; i++) { peSegment = ctx->pHeapMap->pSegments + i; if(peSegment->iHeap == ctx->pHeapEntry->iHeap) { if(peSegment->tp == VMM_HEAP_SEGMENT_TP_NT_SEGMENT) { - if(!VmmRead(ctx->pProcess, peSegment->va, pbSegmentHdr, sizeof(pbSegmentHdr))) { continue; } + if(!VmmRead(H, ctx->pProcess, peSegment->va, pbSegmentHdr, sizeof(pbSegmentHdr))) { continue; } // signature check dwSegmentSignature = *(PDWORD)(pbSegmentHdr + (ctx->f32 ? 8 : 16)); if(((dwSegmentSignature != 0xffeeffee) && (dwSegmentSignature != 0xeeffeeff))) { continue; } @@ -809,8 +813,8 @@ VOID VmmHeapAlloc_NtInit(_In_ PVMMHEAPNT_CTX ctx) if(cbSegment > peSegment->cb) { continue; } // read/alloc and dispatch if((pbSegment = LocalAlloc(0, cbSegment))) { - VmmReadEx(ctx->pProcess, peSegment->va, pbSegment, cbSegment, NULL, VMM_FLAG_ZEROPAD_ON_FAIL); - VmmHeapAlloc_NtInitSeg(ctx, peSegment->va, pbSegment, cbSegment, (DWORD)(vaFirstEntry - peSegment->va)); + VmmReadEx(H, ctx->pProcess, peSegment->va, pbSegment, cbSegment, NULL, VMM_FLAG_ZEROPAD_ON_FAIL); + VmmHeapAlloc_NtInitSeg(H, ctx, peSegment->va, pbSegment, cbSegment, (DWORD)(vaFirstEntry - peSegment->va)); LocalFree(pbSegment); } } @@ -838,6 +842,7 @@ typedef struct tdVMMHEAP_INIT_CONTEXT { * Callback function for initialization of segment heap _HEAP_LARGE_ALLOC_DATA. */ VOID VmmHeap_InitializeSegment_SegLargeAllocCB( + _In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVMMHEAP_INIT_CONTEXT ctx, _In_ QWORD va, @@ -865,13 +870,13 @@ VOID VmmHeap_InitializeSegment_SegLargeAllocCB( e.va = p64->VirtualAddress; e.cb = (DWORD)min(0xffffffff, (p64->AllocatedPages << 12) - p64->UnusedBytes); } - if((peV = VmmMap_GetVadEntry(ctx->pVadMap, va)) && (cbVad = peV->vaEnd + 1 + peV->vaStart) && (cbVad >= e.cb)) { + if((peV = VmmMap_GetVadEntry(H, ctx->pVadMap, va)) && (cbVad = peV->vaEnd + 1 + peV->vaStart) && (cbVad >= e.cb)) { e.tp = VMM_HEAP_SEGMENT_TP_SEG_LARGE; e.iHeap = iInitialEntry; ObMap_PushCopy(ctx->pmeHeapSegment, va, &e, sizeof(VMM_MAP_HEAP_SEGMENTENTRY)); - VmmLog(MID_HEAP, LOGLEVEL_6_TRACE, "SEG_LargeAlloc LOCATED: va=%llx iH=%i cb=%x", e.va, e.iHeap, e.cb); + VmmLog(H, MID_HEAP, LOGLEVEL_6_TRACE, "SEG_LargeAlloc LOCATED: va=%llx iH=%i cb=%x", e.va, e.iHeap, e.cb); } else { - VmmLog(MID_HEAP, LOGLEVEL_6_TRACE, "WARN: SEG_LargeAlloc NO MATCHING VAD: va=%llx", va); + VmmLog(H, MID_HEAP, LOGLEVEL_6_TRACE, "WARN: SEG_LargeAlloc NO MATCHING VAD: va=%llx", va); } *pfValidFLink = VMM_UADDR_DUAL_4_8(ctx->f32, vaFLink); *pfValidBLink = VMM_UADDR_DUAL_4_8(ctx->f32, vaBLink); @@ -881,6 +886,7 @@ VOID VmmHeap_InitializeSegment_SegLargeAllocCB( * Callback function for initialization of segment heap _HEAP_PAGE_SEGMENT. */ VOID VmmHeap_InitializeSegment_SegPageSegmentCB( + _In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVMMHEAP_INIT_CONTEXT ctx, _In_ QWORD va, @@ -899,15 +905,15 @@ VOID VmmHeap_InitializeSegment_SegPageSegmentCB( if(va & 0xfff) { return; } *pfValidFLink = VMM_UADDR_DUAL_PAGE(ctx->f32, vaFLink); *pfValidBLink = VMM_UADDR_DUAL_PAGE(ctx->f32, vaBLink); - if((peV = VmmMap_GetVadEntry(ctx->pVadMap, va))) { + if((peV = VmmMap_GetVadEntry(H, ctx->pVadMap, va))) { e.cb = (DWORD)min(0x00100000, peV->vaEnd + 1 - va); // guesstimate segment size e.tp = VMM_HEAP_SEGMENT_TP_SEG_SEGMENT; e.va = va; e.iHeap = iInitialEntry / 2; ObMap_PushCopy(ctx->pmeHeapSegment, va, &e, sizeof(VMM_MAP_HEAP_SEGMENTENTRY)); - VmmLog(MID_HEAP, LOGLEVEL_6_TRACE, "SEG_PAGESEG LOCATED: va=%llx iH=%i", e.va, e.iHeap); + VmmLog(H, MID_HEAP, LOGLEVEL_6_TRACE, "SEG_PAGESEG LOCATED: va=%llx iH=%i", e.va, e.iHeap); } else { - VmmLog(MID_HEAP, LOGLEVEL_6_TRACE, "WARN: SEG_PAGESEG NO MATCHING VAD: va=%llx", va); + VmmLog(H, MID_HEAP, LOGLEVEL_6_TRACE, "WARN: SEG_PAGESEG NO MATCHING VAD: va=%llx", va); } } @@ -915,6 +921,7 @@ VOID VmmHeap_InitializeSegment_SegPageSegmentCB( * Callback function for initialization of NT heap large allocation. */ VOID VmmHeap_InitializeSegment_NtLargeAllocCB( + _In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVMMHEAP_INIT_CONTEXT ctx, _In_ QWORD va, @@ -934,17 +941,17 @@ VOID VmmHeap_InitializeSegment_NtLargeAllocCB( VMM_MAP_HEAP_SEGMENTENTRY e = { 0 }; if(va & 0xfff) { return; } if(!VMM_UADDR_DUAL_4_8(f32, vaFLink) || !VMM_UADDR_DUAL_4_8(f32, vaBLink)) { - VmmLog(MID_HEAP, LOGLEVEL_6_TRACE, "WARN: NT_LargeAlloc BAD ENTRY #1: va=%llx", va); + VmmLog(H, MID_HEAP, LOGLEVEL_6_TRACE, "WARN: NT_LargeAlloc BAD ENTRY #1: va=%llx", va); return; } cbCommit = VMM_PTR_OFFSET_DUAL(f32, pb, 0x10, 0x20); cbReserved = VMM_PTR_OFFSET_DUAL(f32, pb, 0x14, 0x28); if(!cbCommit || (cbCommit > cbReserved) || (cbReserved < 0x40)) { - VmmLog(MID_HEAP, LOGLEVEL_6_TRACE, "WARN: NT_LargeAlloc BAD ENTRY #2: va=%llx", va); + VmmLog(H, MID_HEAP, LOGLEVEL_6_TRACE, "WARN: NT_LargeAlloc BAD ENTRY #2: va=%llx", va); return; } - if(!(peVad = VmmMap_GetVadEntry(ctx->pVadMap, va))) { - VmmLog(MID_HEAP, LOGLEVEL_6_TRACE, "WARN: NT_LargeAlloc NO MATCHING VAD: va=%llx", va); + if(!(peVad = VmmMap_GetVadEntry(H, ctx->pVadMap, va))) { + VmmLog(H, MID_HEAP, LOGLEVEL_6_TRACE, "WARN: NT_LargeAlloc NO MATCHING VAD: va=%llx", va); return; } cbVad = peVad->vaEnd + 1 + max(va, peVad->vaStart); @@ -955,13 +962,14 @@ VOID VmmHeap_InitializeSegment_NtLargeAllocCB( e.va = va; e.iHeap = iInitialEntry / 2; ObMap_PushCopy(ctx->pmeHeapSegment, va, &e, sizeof(VMM_MAP_HEAP_SEGMENTENTRY)); - VmmLog(MID_HEAP, LOGLEVEL_6_TRACE, "NT_LargeAlloc LOCATED: va=%llx iH=%i", e.va, e.iHeap); + VmmLog(H, MID_HEAP, LOGLEVEL_6_TRACE, "NT_LargeAlloc LOCATED: va=%llx iH=%i", e.va, e.iHeap); } /* * Callback function for initialization of NT heap _HEAP_SEGMENT. */ VOID VmmHeap_InitializeSegment_NtHeapSegmentCB( + _In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVMMHEAP_INIT_CONTEXT ctx, _In_ QWORD va, @@ -984,11 +992,11 @@ VOID VmmHeap_InitializeSegment_NtHeapSegmentCB( DWORD dwSegmentSignature; QWORD vaHeap, cNumberOfPages; if(!va || !(!vaFLink || VMM_UADDR_DUAL_4_8(f32, vaFLink)) || !(!vaBLink || VMM_UADDR_DUAL_4_8(f32, vaBLink))) { - VmmLog(MID_HEAP, LOGLEVEL_6_TRACE, "WARN: NT_SEG BAD ENTRY: va=%llx", va); + VmmLog(H, MID_HEAP, LOGLEVEL_6_TRACE, "WARN: NT_SEG BAD ENTRY: va=%llx", va); return; } if(f32) { - if(ctxVmm->kernel.dwVersionBuild <= 2600) { + if(H->vmm.kernel.dwVersionBuild <= 2600) { ph32XP = (_PHEAP_SEGMENT32_XP)pb; vaHeap = ph32XP->Heap; cNumberOfPages = ph32XP->NumberOfPages; @@ -1007,12 +1015,12 @@ VOID VmmHeap_InitializeSegment_NtHeapSegmentCB( } if((va & 0xfff) || (cNumberOfPages >= 0x00f00000) || ((dwSegmentSignature != 0xffeeffee) && (dwSegmentSignature != 0xeeffeeff))) { if(!(va & 0xfff)) { - VmmLog(MID_HEAP, LOGLEVEL_6_TRACE, "WARN: NT_SEG BAD SEGMENT: va=%llx sig=%08x pg=%x", va, dwSegmentSignature, (DWORD)cNumberOfPages); + VmmLog(H, MID_HEAP, LOGLEVEL_6_TRACE, "WARN: NT_SEG BAD SEGMENT: va=%llx sig=%08x pg=%x", va, dwSegmentSignature, (DWORD)cNumberOfPages); } return; } - if(!(pH = ObMap_GetByKey(ctx->pmeHeap, vaHeap)) && (ctxVmm->kernel.dwVersionBuild > 2600)) { - VmmLog(MID_HEAP, LOGLEVEL_6_TRACE, "WARN: NT_SEG BAD HEAP: va=%llx vaH=%llx", va, vaHeap); + if(!(pH = ObMap_GetByKey(ctx->pmeHeap, vaHeap)) && (H->vmm.kernel.dwVersionBuild > 2600)) { + VmmLog(H, MID_HEAP, LOGLEVEL_6_TRACE, "WARN: NT_SEG BAD HEAP: va=%llx vaH=%llx", va, vaHeap); return; } *pfValidFLink = ((vaFLink & 0xfff) < 0x40); @@ -1022,13 +1030,13 @@ VOID VmmHeap_InitializeSegment_NtHeapSegmentCB( e.va = va; e.iHeap = pH ? pH->iHeap : iInitialEntry; ObMap_PushCopy(ctx->pmeHeapSegment, va, &e, sizeof(VMM_MAP_HEAP_SEGMENTENTRY)); - VmmLog(MID_HEAP, LOGLEVEL_6_TRACE, "NT_SEG LOCATED: va=%llx iH=%i vaH=%llx", e.va, e.iHeap, vaHeap); + VmmLog(H, MID_HEAP, LOGLEVEL_6_TRACE, "NT_SEG LOCATED: va=%llx iH=%i vaH=%llx", e.va, e.iHeap, vaHeap); } /* * Initialize any segment heaps in process. */ -VOID VmmHeap_Initialize3264_SegmentHeap(_In_ PVMMHEAP_INIT_CONTEXT ctx, _In_ BOOL f32) +VOID VmmHeap_Initialize3264_SegmentHeap(_In_ VMM_HANDLE H, _In_ PVMMHEAP_INIT_CONTEXT ctx, _In_ BOOL f32) { PVMM_MAP_HEAPENTRY peH = NULL; VMM_MAP_HEAP_SEGMENTENTRY eR; @@ -1048,7 +1056,7 @@ VOID VmmHeap_Initialize3264_SegmentHeap(_In_ PVMMHEAP_INIT_CONTEXT ctx, _In_ BOO peH = ObMap_GetByIndex(ctx->pmeHeap, iHeap); if((peH->tp != VMM_HEAP_TP_SEG) || (peH->f32 != f32)) { continue; } // 2.1: add the _SEGMENT_HEAP itself as a range: - if((peV = VmmMap_GetVadEntry(ctx->pVadMap, peH->va))) { + if((peV = VmmMap_GetVadEntry(H, ctx->pVadMap, peH->va))) { eR.tp = VMM_HEAP_SEGMENT_TP_SEG_HEAP; eR.cb = (DWORD)min(0xffffffff, peV->vaEnd + 1 - peV->vaStart); eR.va = peH->va; @@ -1056,7 +1064,7 @@ VOID VmmHeap_Initialize3264_SegmentHeap(_In_ PVMMHEAP_INIT_CONTEXT ctx, _In_ BOO ObMap_PushCopy(ctx->pmeHeapSegment, eR.va, &eR, sizeof(VMM_MAP_HEAP_SEGMENTENTRY)); } // 2.2: pepare list walk of _HEAP_PAGE_SEGMENT - if(!VmmRead(ctx->pProcess, peH->va, pbBuffer, sizeof(pbBuffer))) { continue; } + if(!VmmRead(H, ctx->pProcess, peH->va, pbBuffer, sizeof(pbBuffer))) { continue; } for(i = 0; i < 2; i++) { ova = ctx->po->seg.SEGMENT_HEAP.SegContexts + i * ctx->po->seg.HEAP_SEG_CONTEXT.cb + ctx->po->seg.HEAP_SEG_CONTEXT.SegmentListHead; va = VMM_PTR_OFFSET(f32, pbBuffer, ova); @@ -1081,6 +1089,7 @@ VOID VmmHeap_Initialize3264_SegmentHeap(_In_ PVMMHEAP_INIT_CONTEXT ctx, _In_ BOO // 3: walk _HEAP_PAGE_SEGMENT lists: if(fPageSegment) { VmmWin_ListTraversePrefetch( + H, ctx->pProcess, f32, ctx, @@ -1098,6 +1107,7 @@ VOID VmmHeap_Initialize3264_SegmentHeap(_In_ PVMMHEAP_INIT_CONTEXT ctx, _In_ BOO // perspective of the list traversal function. if(fLargeAlloc) { VmmWin_ListTraversePrefetch( + H, ctx->pProcess, f32, ctx, @@ -1117,7 +1127,7 @@ fail: /* * Initialize process heaps (NT and Segment) from either a 32-bit or 64-bit PEB. */ -VOID VmmHeap_InitializeInternal(_In_ PVMMHEAP_INIT_CONTEXT ctx, _In_ BOOL f32) +VOID VmmHeap_InitializeInternal(_In_ VMM_HANDLE H, _In_ PVMMHEAP_INIT_CONTEXT ctx, _In_ BOOL f32) { BOOL f, fNtAllocD = FALSE, fSegmentHeap = FALSE; QWORD va, vaPEB, vaHeap; @@ -1133,9 +1143,9 @@ VOID VmmHeap_InitializeInternal(_In_ PVMMHEAP_INIT_CONTEXT ctx, _In_ BOOL f32) if(f32) { // 1: read PEB f = (vaPEB = (DWORD)(ctx->pProcess->win.fWow64 ? ctx->pProcess->win.vaPEB32 : ctx->pProcess->win.vaPEB)) && - VmmRead(ctx->pProcess, vaPEB, pbBuffer, sizeof(PEB32)); + VmmRead(H, ctx->pProcess, vaPEB, pbBuffer, sizeof(PEB32)); if(!f) { - VmmLog(MID_HEAP, LOGLEVEL_6_TRACE, "FAIL: HEAP BAD PEB: va=%llx", vaPEB); + VmmLog(H, MID_HEAP, LOGLEVEL_6_TRACE, "FAIL: HEAP BAD PEB: va=%llx", vaPEB); return; } // 2: read heap array @@ -1143,18 +1153,18 @@ VOID VmmHeap_InitializeInternal(_In_ PVMMHEAP_INIT_CONTEXT ctx, _In_ BOOL f32) f = (pPEB32->NumberOfHeaps < VMMHEAP_MAX_HEAPS) && (pPEB32->NumberOfHeaps <= pPEB32->MaximumNumberOfHeaps) && VMM_UADDR32_4(pPEB32->ProcessHeaps) && - VmmRead(ctx->pProcess, pPEB32->ProcessHeaps, (PBYTE)vaHeaps32, cMaxHeaps * sizeof(DWORD)) && + VmmRead(H, ctx->pProcess, pPEB32->ProcessHeaps, (PBYTE)vaHeaps32, cMaxHeaps * sizeof(DWORD)) && (vaHeaps32[0] == pPEB32->ProcessHeap); if(!f) { - VmmLog(MID_HEAP, LOGLEVEL_6_TRACE, "FAIL: HEAP BAD ARRAY: va=%x #=%i #m=%i", pPEB32->ProcessHeaps, pPEB32->NumberOfHeaps, pPEB32->MaximumNumberOfHeaps); + VmmLog(H, MID_HEAP, LOGLEVEL_6_TRACE, "FAIL: HEAP BAD ARRAY: va=%x #=%i #m=%i", pPEB32->ProcessHeaps, pPEB32->NumberOfHeaps, pPEB32->MaximumNumberOfHeaps); return; } } else { // 1: read PEB f = (vaPEB = ctx->pProcess->win.vaPEB) && - VmmRead(ctx->pProcess, vaPEB, pbBuffer, sizeof(PEB64)); + VmmRead(H, ctx->pProcess, vaPEB, pbBuffer, sizeof(PEB64)); if(!f) { - VmmLog(MID_HEAP, LOGLEVEL_6_TRACE, "FAIL: HEAP BAD PEB: va=%llx", vaPEB); + VmmLog(H, MID_HEAP, LOGLEVEL_6_TRACE, "FAIL: HEAP BAD PEB: va=%llx", vaPEB); return; } // 2: read heap array @@ -1162,10 +1172,10 @@ VOID VmmHeap_InitializeInternal(_In_ PVMMHEAP_INIT_CONTEXT ctx, _In_ BOOL f32) f = (pPEB64->NumberOfHeaps < VMMHEAP_MAX_HEAPS) && (pPEB64->NumberOfHeaps <= pPEB64->MaximumNumberOfHeaps) && VMM_UADDR64_8(pPEB64->ProcessHeaps) && - VmmRead(ctx->pProcess, pPEB64->ProcessHeaps, (PBYTE)vaHeaps64, cMaxHeaps * sizeof(QWORD)) && + VmmRead(H, ctx->pProcess, pPEB64->ProcessHeaps, (PBYTE)vaHeaps64, cMaxHeaps * sizeof(QWORD)) && (vaHeaps64[0] == pPEB64->ProcessHeap); if(!f) { - VmmLog(MID_HEAP, LOGLEVEL_6_TRACE, "FAIL: HEAP BAD ARRAY: va=%llx #=%i #m=%i", pPEB64->ProcessHeaps, pPEB64->NumberOfHeaps, pPEB64->MaximumNumberOfHeaps); + VmmLog(H, MID_HEAP, LOGLEVEL_6_TRACE, "FAIL: HEAP BAD ARRAY: va=%llx #=%i #m=%i", pPEB64->ProcessHeaps, pPEB64->NumberOfHeaps, pPEB64->MaximumNumberOfHeaps); return; } } @@ -1178,22 +1188,22 @@ VOID VmmHeap_InitializeInternal(_In_ PVMMHEAP_INIT_CONTEXT ctx, _In_ BOOL f32) if(VMM_UADDR_DUAL_PAGE(f32, vaHeap)) { ObSet_Push(ctx->psPrefetch, vaHeap); } else if(vaHeap) { - VmmLog(MID_HEAP, LOGLEVEL_6_TRACE, "WARN: HEAP BAD ADDR: va=%llx i=%i", vaHeap, iHeap); + VmmLog(H, MID_HEAP, LOGLEVEL_6_TRACE, "WARN: HEAP BAD ADDR: va=%llx i=%i", vaHeap, iHeap); vaHeaps32[iHeap] = 0; vaHeaps64[iHeap] = 0; } } - VmmCachePrefetchPages(ctx->pProcess, ctx->psPrefetch, 0); + VmmCachePrefetchPages(H, ctx->pProcess, ctx->psPrefetch, 0); // 4: read & add heaps: eH.f32 = f32; for(iHeap = 0; iHeap < cMaxHeaps; iHeap++) { vaHeap = f32 ? vaHeaps32[iHeap] : vaHeaps64[iHeap]; if(!vaHeap) { continue; } if(ObMap_ExistsKey(ctx->pmeHeap, vaHeap)) { - VmmLog(MID_HEAP, LOGLEVEL_6_TRACE, "WARN: HEAP EXISTS: va=%llx", vaHeap); + VmmLog(H, MID_HEAP, LOGLEVEL_6_TRACE, "WARN: HEAP EXISTS: va=%llx", vaHeap); continue; } - if(!VmmRead2(ctx->pProcess, vaHeap, pbBuffer, sizeof(pbBuffer), VMM_FLAG_FORCECACHE_READ)) { continue; } + if(!VmmRead2(H, ctx->pProcess, vaHeap, pbBuffer, sizeof(pbBuffer), VMM_FLAG_FORCECACHE_READ)) { continue; } dwSignature = *(PDWORD)(pbBuffer + (f32 ? 8 : 16)); eH.iHeap = ObMap_Size(ctx->pmeHeap); eH.dwHeapNum = iHeap; @@ -1209,33 +1219,34 @@ VOID VmmHeap_InitializeInternal(_In_ PVMMHEAP_INIT_CONTEXT ctx, _In_ BOOL f32) avaNtLargeAlloc[2 * cNtSegment] = (DWORD)VMM_PTR_OFFSET(f32, pbBuffer, (QWORD)ctx->po->nt.HEAP.VirtualAllocdBlocks + (f32 ? 4 : 8)) & ~0xfff; } // LFH (frontend) area - if((pbBuffer[ctx->po->nt.HEAP.FrontEndHeapType] == 2) && (va = VMM_PTR_OFFSET(f32, pbBuffer, ctx->po->nt.HEAP.FrontEndHeap)) && VMM_UADDR_PAGE(va)) { + if((pbBuffer[ctx->po->nt.HEAP.FrontEndHeapType] == 2) && (va = VMM_PTR_OFFSET(f32, pbBuffer, ctx->po->nt.HEAP.FrontEndHeap)) && VMM_UADDR_PAGE(H->vmm.f32, va)) { eR.tp = VMM_HEAP_SEGMENT_TP_NT_LFH; eR.va = va; eR.cb = 0x20000; eR.iHeap = cNtSegment; ObMap_PushCopy(ctx->pmeHeapSegment, va, &eR, sizeof(VMM_MAP_HEAP_SEGMENTENTRY)); - VmmLog(MID_HEAP, LOGLEVEL_6_TRACE, "NT_LFH LOCATED: va=%llx iH=%i vaH=%llx", eR.va, eR.iHeap, vaHeap); + VmmLog(H, MID_HEAP, LOGLEVEL_6_TRACE, "NT_LFH LOCATED: va=%llx iH=%i vaH=%llx", eR.va, eR.iHeap, vaHeap); } // NtSegment avaNtSegment[cNtSegment++] = vaHeap; eH.tp = VMM_HEAP_TP_NT; break; case 0xddeeddee: // SEGMENT HEAP - if(ctxVmm->kernel.dwVersionBuild <= 9200) { continue; } // segment heap not valid on Win8.0 and before + if(H->vmm.kernel.dwVersionBuild <= 9200) { continue; } // segment heap not valid on Win8.0 and before eH.tp = VMM_HEAP_TP_SEG; fSegmentHeap = TRUE; break; default: - VmmLog(MID_HEAP, LOGLEVEL_6_TRACE, "WARN: HEAP BAD SIGNATURE: va=%llx sig=%08x", vaHeap, dwSignature); + VmmLog(H, MID_HEAP, LOGLEVEL_6_TRACE, "WARN: HEAP BAD SIGNATURE: va=%llx sig=%08x", vaHeap, dwSignature); continue; } ObMap_PushCopy(ctx->pmeHeap, vaHeap, &eH, sizeof(VMM_MAP_HEAPENTRY)); - VmmLog(MID_HEAP, LOGLEVEL_6_TRACE, "%s_HEAP LOCATED: va=%llx iH=%i", VMM_HEAP_TP_STR[eH.tp], vaHeap, eH.iHeap); + VmmLog(H, MID_HEAP, LOGLEVEL_6_TRACE, "%s_HEAP LOCATED: va=%llx iH=%i", VMM_HEAP_TP_STR[eH.tp], vaHeap, eH.iHeap); } // 5: walk nt heap ranges (_HEAP_SEGMENT) in an efficient way: if(cNtSegment) { VmmWin_ListTraversePrefetch( + H, ctx->pProcess, f32, ctx, @@ -1251,6 +1262,7 @@ VOID VmmHeap_InitializeInternal(_In_ PVMMHEAP_INIT_CONTEXT ctx, _In_ BOOL f32) // 6: walk nt heap ranges (_HEAP_VIRTUAL_ALLOC_ENTRY): if(fNtAllocD) { VmmWin_ListTraversePrefetch( + H, ctx->pProcess, f32, ctx, @@ -1265,7 +1277,7 @@ VOID VmmHeap_InitializeInternal(_In_ PVMMHEAP_INIT_CONTEXT ctx, _In_ BOOL f32) } // 7: initialize segment heap ranges if they exists: if(fSegmentHeap) { - VmmHeap_Initialize3264_SegmentHeap(ctx, f32); + VmmHeap_Initialize3264_SegmentHeap(H, ctx, f32); } LocalFree(avaBuffer); } @@ -1285,7 +1297,7 @@ int VmmHeap_qsort_HeapEntry(PVMM_MAP_HEAPENTRY p1, PVMM_MAP_HEAPENTRY p2) * upon completion be assigned to pProcess->Map.pObHeap * -- pProcess */ -VOID VmmHeap_Initialize_DoWork(_In_ PVMM_PROCESS pProcess) +VOID VmmHeap_Initialize_DoWork(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess) { QWORD qwScatterPre = 0, qwScatterPost = 0; VMMHEAP_INIT_CONTEXT ctxInit = { 0 }; @@ -1293,37 +1305,40 @@ VOID VmmHeap_Initialize_DoWork(_In_ PVMM_PROCESS pProcess) PVMM_MAP_HEAPENTRY peH; PVMM_MAP_HEAP_SEGMENTENTRY peR; DWORD i, cbData, cHeaps, cSegments; + BOOL fLog = VmmLogIsActive(H, MID_HEAP, LOGLEVEL_6_TRACE); // init: - VmmLog(MID_HEAP, LOGLEVEL_6_TRACE, "INIT HEAPMAP START: pid=%5i", pProcess->dwPID); - //LcGetOption(ctxMain->hLC, LC_OPT_CORE_STATISTICS_CALL_COUNT | LC_STATISTICS_ID_READSCATTER, &qwScatterPre); + if(fLog) { + VmmLog(H, MID_HEAP, LOGLEVEL_6_TRACE, "INIT HEAPMAP START: pid=%5i", pProcess->dwPID); + LcGetOption(H->hLC, LC_OPT_CORE_STATISTICS_CALL_COUNT | LC_STATISTICS_ID_READSCATTER, &qwScatterPre); + } ctxInit.pProcess = pProcess; - if(!(ctxInit.psPrefetch = ObSet_New())) { goto fail; } - if(!(ctxInit.pmeHeap = ObMap_New(OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } - if(!(ctxInit.pmeHeapSegment = ObMap_New(OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } - if(!VmmMap_GetVad(pProcess, &ctxInit.pVadMap, VMM_VADMAP_TP_CORE)) { - VmmLog(MID_HEAP, LOGLEVEL_5_DEBUG, "FAIL: NO VAD: pid=%i", pProcess->dwPID); + if(!(ctxInit.psPrefetch = ObSet_New(H))) { goto fail; } + if(!(ctxInit.pmeHeap = ObMap_New(H, OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } + if(!(ctxInit.pmeHeapSegment = ObMap_New(H, OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } + if(!VmmMap_GetVad(H, pProcess, &ctxInit.pVadMap, VMM_VADMAP_TP_CORE)) { + VmmLog(H, MID_HEAP, LOGLEVEL_5_DEBUG, "FAIL: NO VAD: pid=%i", pProcess->dwPID); goto fail; } // fetch data: - if((ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X86) || ((ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X64) && pProcess->win.fWow64)) { - if(!ctxVmm->offset.HEAP32.fValid) { goto fail; } - ctxInit.po = &ctxVmm->offset.HEAP32; + if((H->vmm.tpSystem == VMM_SYSTEM_WINDOWS_X86) || ((H->vmm.tpSystem == VMM_SYSTEM_WINDOWS_X64) && pProcess->win.fWow64)) { + if(!H->vmm.offset.HEAP32.fValid) { goto fail; } + ctxInit.po = &H->vmm.offset.HEAP32; ctxInit.f32 = TRUE; - VmmHeap_InitializeInternal(&ctxInit, TRUE); + VmmHeap_InitializeInternal(H, &ctxInit, TRUE); ObSet_Clear(ctxInit.psPrefetch); } - if(ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X64) { - if(!ctxVmm->offset.HEAP64.fValid) { goto fail; } - ctxInit.po = &ctxVmm->offset.HEAP64; + if(H->vmm.tpSystem == VMM_SYSTEM_WINDOWS_X64) { + if(!H->vmm.offset.HEAP64.fValid) { goto fail; } + ctxInit.po = &H->vmm.offset.HEAP64; ctxInit.f32 = FALSE; - VmmHeap_InitializeInternal(&ctxInit, FALSE); + VmmHeap_InitializeInternal(H, &ctxInit, FALSE); } // alloc and fill map object: cHeaps = ObMap_Size(ctxInit.pmeHeap); cSegments = ObMap_Size(ctxInit.pmeHeapSegment); if((cHeaps > VMMHEAP_MAX_HEAPS) || (cSegments > 0x00100000)) { goto fail; } cbData = sizeof(VMMOB_MAP_HEAP) + cHeaps * sizeof(VMM_MAP_HEAPENTRY) + cSegments * sizeof(VMM_MAP_HEAP_SEGMENTENTRY); - if(!(pObHeapMap = Ob_Alloc(OB_TAG_MAP_HEAP, 0, cbData, NULL, NULL))) { goto fail; } + if(!(pObHeapMap = Ob_AllocEx(H, OB_TAG_MAP_HEAP, 0, cbData, NULL, NULL))) { goto fail; } pObHeapMap->cMap = cHeaps; for(i = 0; i < cHeaps; i++) { peH = ObMap_GetByIndex(ctxInit.pmeHeap, i); @@ -1343,8 +1358,10 @@ fail: Ob_DECREF(ctxInit.pmeHeap); Ob_DECREF(ctxInit.pmeHeapSegment); Ob_DECREF(ctxInit.psPrefetch); - //LcGetOption(ctxMain->hLC, LC_OPT_CORE_STATISTICS_CALL_COUNT | LC_STATISTICS_ID_READSCATTER, &qwScatterPost); - VmmLog(MID_HEAP, LOGLEVEL_6_TRACE, "INIT HEAPMAP END: pid=%5i scatter=%lli", pProcess->dwPID, qwScatterPost - qwScatterPre); + if(fLog) { + LcGetOption(H->hLC, LC_OPT_CORE_STATISTICS_CALL_COUNT | LC_STATISTICS_ID_READSCATTER, &qwScatterPost); + VmmLog(H, MID_HEAP, LOGLEVEL_6_TRACE, "INIT HEAPMAP END: pid=%5i scatter=%lli", pProcess->dwPID, qwScatterPost - qwScatterPre); + } } /* @@ -1354,13 +1371,14 @@ fail: * -- pProcess * -- return */ -BOOL VmmHeap_Initialize(_In_ PVMM_PROCESS pProcess) +BOOL VmmHeap_Initialize(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess) { - if(pProcess->Map.pObHeap) { return TRUE; } - VmmTlbSpider(pProcess); + if(pProcess->Map.pObHeap) { return TRUE; } // heap already exist + if(pProcess->dwState == 1) { return FALSE; } // terminated process + VmmTlbSpider(H, pProcess); EnterCriticalSection(&pProcess->LockUpdate); if(!pProcess->Map.pObHeap) { - VmmHeap_Initialize_DoWork(pProcess); + VmmHeap_Initialize_DoWork(H, pProcess); } LeaveCriticalSection(&pProcess->LockUpdate); return pProcess->Map.pObHeap ? TRUE : FALSE; diff --git a/vmm/vmmheap.h b/vmm/vmmheap.h index e2a0b73..8b0cbc8 100644 --- a/vmm/vmmheap.h +++ b/vmm/vmmheap.h @@ -12,24 +12,27 @@ * Initialize the heap map containing information about the process heaps in the * specific process. This is performed by a PEB walk/scan of in-process memory * structures. This may be unreliable if a process is obfuscated or tampered. +* -- H * -- pProcess * -- return */ -BOOL VmmHeap_Initialize(_In_ PVMM_PROCESS pProcess); +BOOL VmmHeap_Initialize(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess); /* * Refresh any cached heap allocation maps. +* -- H */ -VOID VmmHeapAlloc_Refresh(); +VOID VmmHeapAlloc_Refresh(_In_ VMM_HANDLE H); /* * Retrive the heap allocation map for the specific heap. * The map is cached up until a total process refresh is made (medium refresh). * CALLER DECREF: return +* -- H * -- pProcess * -- vaHeap = va of heap or heap id. * -- return */ -PVMMOB_MAP_HEAPALLOC VmmHeapAlloc_Initialize(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaHeap); +PVMMOB_MAP_HEAPALLOC VmmHeapAlloc_Initialize(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaHeap); #endif /* __VMMHEAP_H__ */ diff --git a/vmm/vmmlog.c b/vmm/vmmlog.c index 0681867..1bc7453 100644 --- a/vmm/vmmlog.c +++ b/vmm/vmmlog.c @@ -20,29 +20,6 @@ static LPCSTR VMMLOG_LEVEL_STR[] = { "ALL " }; -// max 8 chars long! -static LPCSTR VMMLOG_MID_STR[] = { - "N/A", - // externally exposed built-in modules: - "MAIN", - "PYTHON", - "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", - // vmm internal built-in module: - "CORE", - "VMMDLL", - "VMM", - "PROCESS", - "FORENSIC", - "REGISTRY", - "PLUGIN", - "NET", - "PE", - "PDB", - "INFODB", - "HEAP", - "OFFSET" -}; - typedef struct tdVMMLOG_MODULE_MODULEINFO { DWORD dwMID; // module id VMMLOG_LEVEL dwLevelD; // log level display (other than default) @@ -51,115 +28,124 @@ typedef struct tdVMMLOG_MODULE_MODULEINFO { } VMMLOG_CONTEXT_MODULEINFO, *PVMMLOG_CONTEXT_MODULEINFO; typedef struct tdVMMLOG_CONTEXT { - BOOL fInitialized; FILE* pFile; VMMLOG_LEVEL dwLevelD; // log level display (default) VMMLOG_LEVEL dwLevelF; // log level file (default) VMMLOG_LEVEL dwLevelMID; // max log level of all module specific overrides - DWORD iModuleNameNext; + DWORD iNextMID; // max MID+1in ModuleInfo VMMLOG_CONTEXT_MODULEINFO ModuleInfo[VMMLOG_MID_MODULE_MAX]; VMMLOG_CONTEXT_MODULEINFO CoreInfo[(MID_MAX & 0x7fffffff) + 1]; -} VMMLOG_CONTEXT; - -VMMLOG_CONTEXT ctxLog = { 0 }; -VMMLOG_LEVEL g_VmmLogLevelFilter = LOGLEVEL_NONE; +} VMMLOG_CONTEXT, *PVMMLOG_CONTEXT; /* * Helper function to get a log module info object. */ -inline PVMMLOG_CONTEXT_MODULEINFO VmmLog_GetModuleInfo(_In_ DWORD dwMID) +inline PVMMLOG_CONTEXT_MODULEINFO VmmLog_GetModuleInfo(_In_ VMM_HANDLE H, _In_ DWORD dwMID) { + PVMMLOG_CONTEXT ctxLog = H->log; + if(!ctxLog) { return NULL; } if(dwMID & 0x80000000) { - return (dwMID <= MID_MAX) ? &ctxLog.CoreInfo[dwMID & 0x7fffffff] : NULL; + return (dwMID <= MID_MAX) ? &ctxLog->CoreInfo[dwMID & 0x7fffffff] : NULL; } else { - return (dwMID < ctxLog.iModuleNameNext) ? &ctxLog.ModuleInfo[dwMID] : NULL; + return (dwMID < ctxLog->iNextMID) ? &ctxLog->ModuleInfo[dwMID] : NULL; } } /* * Close and clean-up internal logging data structures. +* This should only be done last at system exit before shut-down. +* -- H */ -VOID VmmLog_Close() +VOID VmmLog_Close(_In_ VMM_HANDLE H) { - DWORD dwMID; PVMMLOG_CONTEXT_MODULEINFO pmi; - g_VmmLogLevelFilter = LOGLEVEL_NONE; - if(ctxLog.pFile) { - fclose(ctxLog.pFile); - ctxLog.pFile = NULL; + DWORD dwMID; + H->logfilter = (DWORD)LOGLEVEL_NONE; + if(H->log) { + if(H->log->pFile) { + fclose(H->log->pFile); + } + for(dwMID = 0; dwMID < H->log->iNextMID; dwMID++) { + if((pmi = VmmLog_GetModuleInfo(H, dwMID))) { + LocalFree(pmi->uszName); + } + } + LocalFree(H->log); + H->log = NULL; } - for(dwMID = 1; dwMID < ctxLog.iModuleNameNext; dwMID++) { - pmi = VmmLog_GetModuleInfo(dwMID); - LocalFree(pmi->uszName); - } - ZeroMemory(&ctxLog, sizeof(VMMLOG_CONTEXT)); } /* * Get the log level for either display (on-screen) or file. +* -- H * -- dwMID = specify MID to get specific level override (i.e. not default MID) * -- fDisplay * -- return */ -VMMLOG_LEVEL VmmLog_LevelGet(_In_opt_ DWORD dwMID, _In_ BOOL fDisplay) +VMMLOG_LEVEL VmmLog_LevelGet(_In_ VMM_HANDLE H, _In_opt_ DWORD dwMID, _In_ BOOL fDisplay) { + PVMMLOG_CONTEXT ctxLog = H->log; PVMMLOG_CONTEXT_MODULEINFO pmi; + if(!ctxLog) { return LOGLEVEL_NONE; } if(dwMID) { - pmi = VmmLog_GetModuleInfo(dwMID); + pmi = VmmLog_GetModuleInfo(H, dwMID); if(!pmi) { return LOGLEVEL_NONE; } return fDisplay ? pmi->dwLevelD : pmi->dwLevelF; } else { - return fDisplay ? ctxLog.dwLevelD : ctxLog.dwLevelF; + return fDisplay ? ctxLog->dwLevelD : ctxLog->dwLevelF; } } /* * Set the log level for either display (on-screen) or file. +* -- H * -- dwMID = specify MID (other than 0) to set specific module level override. * -- dwLogLevel * -- fDisplay = TRUE(display), FALSE(file) * -- fSetOrIncrease = TRUE(set), FALSE(increase) */ -VOID VmmLog_LevelSet(_In_opt_ DWORD dwMID, _In_ VMMLOG_LEVEL dwLogLevel, _In_ BOOL fDisplay, _In_ BOOL fSetOrIncrease) +VOID VmmLog_LevelSet(_In_ VMM_HANDLE H, _In_opt_ DWORD dwMID, _In_ VMMLOG_LEVEL dwLogLevel, _In_ BOOL fDisplay, _In_ BOOL fSetOrIncrease) { + PVMMLOG_CONTEXT ctxLog = H->log; PVMMLOG_CONTEXT_MODULEINFO pmi = NULL; - if((dwLogLevel < 0) || (dwLogLevel > LOGLEVEL_ALL)) { return; } + if(!ctxLog || (dwLogLevel < 0) || (dwLogLevel > LOGLEVEL_ALL)) { return; } if(dwMID) { - if(!(pmi = VmmLog_GetModuleInfo(dwMID))) { return; } + if(!(pmi = VmmLog_GetModuleInfo(H, dwMID))) { return; } if(fDisplay) { pmi->dwLevelD = fSetOrIncrease ? dwLogLevel : max(dwLogLevel, pmi->dwLevelD); } else { pmi->dwLevelF = fSetOrIncrease ? dwLogLevel : max(dwLogLevel, pmi->dwLevelF); } // recalculate max log level of all module specific overrides - if(ctxLog.dwLevelMID <= dwLogLevel) { - ctxLog.dwLevelMID = max(ctxLog.dwLevelMID, dwLogLevel); + if(ctxLog->dwLevelMID <= dwLogLevel) { + ctxLog->dwLevelMID = max(ctxLog->dwLevelMID, dwLogLevel); } else { - ctxLog.dwLevelMID = 0; - for(dwMID = 1; dwMID < ctxLog.iModuleNameNext; dwMID++) { - pmi = VmmLog_GetModuleInfo(dwMID); - ctxLog.dwLevelMID = max(ctxLog.dwLevelMID, max(pmi->dwLevelD, pmi->dwLevelF)); + ctxLog->dwLevelMID = 0; + for(dwMID = 1; dwMID < ctxLog->iNextMID; dwMID++) { + pmi = VmmLog_GetModuleInfo(H, dwMID); + ctxLog->dwLevelMID = max(ctxLog->dwLevelMID, max(pmi->dwLevelD, pmi->dwLevelF)); } for(dwMID = MID_NA; dwMID <= MID_MAX; dwMID++) { - pmi = VmmLog_GetModuleInfo(dwMID); - ctxLog.dwLevelMID = max(ctxLog.dwLevelMID, max(pmi->dwLevelD, pmi->dwLevelF)); + pmi = VmmLog_GetModuleInfo(H, dwMID); + ctxLog->dwLevelMID = max(ctxLog->dwLevelMID, max(pmi->dwLevelD, pmi->dwLevelF)); } } } else { if(fDisplay) { - ctxLog.dwLevelD = fSetOrIncrease ? dwLogLevel : max(dwLogLevel, ctxLog.dwLevelD); + ctxLog->dwLevelD = fSetOrIncrease ? dwLogLevel : max(dwLogLevel, ctxLog->dwLevelD); } else { - ctxLog.dwLevelF = fSetOrIncrease ? dwLogLevel : max(dwLogLevel, ctxLog.dwLevelF); + ctxLog->dwLevelF = fSetOrIncrease ? dwLogLevel : max(dwLogLevel, ctxLog->dwLevelF); } } - g_VmmLogLevelFilter = max(ctxLog.dwLevelMID, max(ctxLog.dwLevelD, ctxLog.dwLevelF)); + H->logfilter = (DWORD)max(ctxLog->dwLevelMID, max(ctxLog->dwLevelD, ctxLog->dwLevelF)); } /* * Refresh the display logging settings from settings. */ -VOID VmmLog_LevelRefresh() +VOID VmmLog_LevelRefresh(_In_ VMM_HANDLE H) { + PVMMLOG_CONTEXT ctxLog = H->log; DWORD i, dwMID, dwTokenMID; PVMMLOG_CONTEXT_MODULEINFO pmi; CHAR ch, szModuleName[9], szTokenBuffer[MAX_PATH]; @@ -167,42 +153,43 @@ VOID VmmLog_LevelRefresh() BOOL fModuleName, fDisplay; VMMLOG_LEVEL dwLogLevel; // initialize built-in log entries - if(!ctxLog.fInitialized) { + if(!ctxLog) { + H->log = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMLOG_CONTEXT)); + if(!(ctxLog = H->log)) { return; } for(dwMID = MID_NA; dwMID <= MID_MAX; dwMID++) { - pmi = VmmLog_GetModuleInfo(dwMID); + pmi = VmmLog_GetModuleInfo(H, dwMID); pmi->dwMID = dwMID; pmi->uszName = (LPSTR)VMMLOG_MID_STR[dwMID & 0x7fffffff]; } - ctxLog.fInitialized = TRUE; } // clear module overrides (if any): - for(dwMID = 1; dwMID < ctxLog.iModuleNameNext; dwMID++) { - pmi = VmmLog_GetModuleInfo(dwMID); + for(dwMID = 1; dwMID < ctxLog->iNextMID; dwMID++) { + pmi = VmmLog_GetModuleInfo(H, dwMID); pmi->dwLevelD = LOGLEVEL_NONE; pmi->dwLevelF = LOGLEVEL_NONE; } for(dwMID = MID_NA; dwMID <= MID_MAX; dwMID++) { - pmi = VmmLog_GetModuleInfo(dwMID); + pmi = VmmLog_GetModuleInfo(H, dwMID); pmi->dwLevelD = LOGLEVEL_NONE; pmi->dwLevelF = LOGLEVEL_NONE; } // legacy settings (use as base settings): - if(ctxMain->cfg.fVerboseDll) { - VmmLog_LevelSet(0, LOGLEVEL_INFO, TRUE, FALSE); - if(ctxMain->cfg.fVerbose) { VmmLog_LevelSet(0, LOGLEVEL_VERBOSE, TRUE, FALSE); } - if(ctxMain->cfg.fVerboseExtra) { VmmLog_LevelSet(0, LOGLEVEL_DEBUG, TRUE, FALSE); } - if(ctxMain->cfg.fVerboseExtraTlp) { VmmLog_LevelSet(0, LOGLEVEL_TRACE, TRUE, FALSE); } + if(H->cfg.fVerboseDll) { + VmmLog_LevelSet(H, 0, LOGLEVEL_INFO, TRUE, FALSE); + if(H->cfg.fVerbose) { VmmLog_LevelSet(H, 0, LOGLEVEL_VERBOSE, TRUE, FALSE); } + if(H->cfg.fVerboseExtra) { VmmLog_LevelSet(H, 0, LOGLEVEL_DEBUG, TRUE, FALSE); } + if(H->cfg.fVerboseExtraTlp) { VmmLog_LevelSet(H, 0, LOGLEVEL_TRACE, TRUE, FALSE); } } else { - VmmLog_LevelSet(0, LOGLEVEL_NONE, TRUE, FALSE); + VmmLog_LevelSet(H, 0, LOGLEVEL_NONE, TRUE, FALSE); } // open file (if log file specified and file handle not already open): - if(ctxMain->cfg.szLogFile[0] && !ctxLog.pFile) { - ctxLog.pFile = _fsopen(ctxMain->cfg.szLogFile, "a", 0x20 /* _SH_DENYWR */); + if(H->cfg.szLogFile[0] && !ctxLog->pFile) { + ctxLog->pFile = _fsopen(H->cfg.szLogFile, "a", 0x20 /* _SH_DENYWR */); } - ctxLog.dwLevelF = ctxLog.pFile ? ctxLog.dwLevelD : LOGLEVEL_NONE; + ctxLog->dwLevelF = ctxLog->pFile ? ctxLog->dwLevelD : LOGLEVEL_NONE; // new settings (specified in -loglevel parameter): - if(!ctxMain->cfg.szLogLevel[0]) { return; } - strncpy_s(szTokenBuffer, sizeof(szTokenBuffer), ctxMain->cfg.szLogLevel, _TRUNCATE); + if(!H->cfg.szLogLevel[0]) { return; } + strncpy_s(szTokenBuffer, sizeof(szTokenBuffer), H->cfg.szLogLevel, _TRUNCATE); szTokenInitial = szTokenBuffer; while((szToken = strtok_s(szTokenInitial, ",", &szTokenContext))) { szTokenInitial = NULL; @@ -210,7 +197,7 @@ VOID VmmLog_LevelRefresh() fModuleName = FALSE; // parse file or display (default): if((szToken[0] == 'f') && (szToken[1] == ':')) { - if(!ctxLog.pFile) { continue; } + if(!ctxLog->pFile) { continue; } fDisplay = FALSE; szToken += 2; } else { @@ -233,15 +220,15 @@ VOID VmmLog_LevelRefresh() i++; } if(fModuleName) { - for(dwMID = 1; dwMID < ctxLog.iModuleNameNext; dwMID++) { - pmi = VmmLog_GetModuleInfo(dwMID); + for(dwMID = 1; dwMID < ctxLog->iNextMID; dwMID++) { + pmi = VmmLog_GetModuleInfo(H, dwMID); if(pmi->uszName && !_stricmp(pmi->uszName, szModuleName)) { dwTokenMID = dwMID; break; } } for(dwMID = MID_NA; dwMID <= MID_MAX; dwMID++) { - pmi = VmmLog_GetModuleInfo(dwMID); + pmi = VmmLog_GetModuleInfo(H, dwMID); if(pmi->uszName && !_stricmp(pmi->uszName, szModuleName)) { dwTokenMID = dwMID; break; @@ -252,7 +239,7 @@ VOID VmmLog_LevelRefresh() // parse log level & apply: if((szToken[0] >= '0') && (szToken[0] <= '7') && (szToken[1] == 0)) { dwLogLevel = szToken[0] - '0'; - VmmLog_LevelSet(dwTokenMID, dwLogLevel, fDisplay, TRUE); + VmmLog_LevelSet(H, dwTokenMID, dwLogLevel, fDisplay, TRUE); } } } @@ -260,44 +247,47 @@ VOID VmmLog_LevelRefresh() /* * Register a new module ID (MID) with the log database. * This function should be called in a single-threaded context by the plugin manager. +* -- H * -- dwMID = the module ID (MID) to register * -- uszModuleName * -- fExternal = externally loaded module (dll/so). */ -VOID VmmLog_RegisterModule(_In_ DWORD dwMID, _In_ LPSTR uszModuleName, _In_ BOOL fExternal) +VOID VmmLog_RegisterModule(_In_ VMM_HANDLE H, _In_ DWORD dwMID, _In_ LPSTR uszModuleName, _In_ BOOL fExternal) { PVMMLOG_CONTEXT_MODULEINFO pmi; + if(!H->log) { return; } if(dwMID >= VMMLOG_MID_MODULE_MAX) { return; } - if(ctxLog.iModuleNameNext == VMMLOG_MID_MODULE_MAX) { return; } - pmi = ctxLog.ModuleInfo + dwMID; + pmi = H->log->ModuleInfo + dwMID; if(pmi->uszName) { LocalFree(pmi->uszName); ZeroMemory(pmi, sizeof(VMMLOG_CONTEXT_MODULEINFO)); } if(CharUtil_UtoU(uszModuleName, 8, NULL, 0, &pmi->uszName, NULL, CHARUTIL_FLAG_ALLOC)) { - ctxLog.iModuleNameNext++; } pmi->dwMID = dwMID; + H->log->iNextMID = dwMID + 1; } /* * Log a message "printf" style. Whether the message is displayed and/or saved * to log file depends on the internal logging setup. +* -- H * -- dwMID = module ID (MID) * -- dwLogLevel = log level as defined by LOGLEVEL_* * -- uszFormat * -- ... */ -VOID VmmLogEx(_In_ DWORD dwMID, _In_ VMMLOG_LEVEL dwLogLevel, _In_z_ _Printf_format_string_ LPSTR uszFormat, ...) +VOID VmmLogEx(_In_ VMM_HANDLE H, _In_ DWORD dwMID, _In_ VMMLOG_LEVEL dwLogLevel, _In_z_ _Printf_format_string_ LPSTR uszFormat, ...) { va_list arglist; va_start(arglist, uszFormat); - VmmLogEx2(dwMID, dwLogLevel, uszFormat, arglist); + VmmLogEx2(H, dwMID, dwLogLevel, uszFormat, arglist); va_end(arglist); } /* * Log a message "printf" style followed by a hexascii printout. +* -- H * -- dwMID = module ID (MID) * -- dwLogLevel = log level as defined by LOGLEVEL_* * -- pb = binary to log @@ -306,7 +296,7 @@ VOID VmmLogEx(_In_ DWORD dwMID, _In_ VMMLOG_LEVEL dwLogLevel, _In_z_ _Printf_for * -- uszFormat * -- ... */ -VOID VmmLogHexAsciiEx(_In_ DWORD dwMID, _In_ VMMLOG_LEVEL dwLogLevel, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset, _In_z_ _Printf_format_string_ LPSTR uszFormat, ...) +VOID VmmLogHexAsciiEx(_In_ VMM_HANDLE H, _In_ DWORD dwMID, _In_ VMMLOG_LEVEL dwLogLevel, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset, _In_z_ _Printf_format_string_ LPSTR uszFormat, ...) { LPSTR usz; va_list arglist; @@ -330,39 +320,44 @@ VOID VmmLogHexAsciiEx(_In_ DWORD dwMID, _In_ VMMLOG_LEVEL dwLogLevel, _In_reads_ } // 4: log va_start(arglist, uszFormat); - VmmLogEx2(dwMID, dwLogLevel, usz, arglist); + VmmLogEx2(H, dwMID, dwLogLevel, usz, arglist); va_end(arglist); LocalFree(usz); } /* * Check whether the MID/LogLevel will log to any output. +* -- H * -- dwMID = module ID (MID) * -- dwLogLevel = log level as defined by LOGLEVEL_* * -- return = TRUE(will log), FALSE(will NOT log). */ -BOOL VmmLogIsActive(_In_ DWORD dwMID, _In_ VMMLOG_LEVEL dwLogLevel) +BOOL VmmLogIsActive(_In_ VMM_HANDLE H, _In_ DWORD dwMID, _In_ VMMLOG_LEVEL dwLogLevel) { + PVMMLOG_CONTEXT ctxLog = H->log; PVMMLOG_CONTEXT_MODULEINFO pmi; BOOL fD = FALSE, fF = FALSE; + if(!ctxLog) { return FALSE; } // sanity checks, get module info object and check if logs should happen to display/file: - if((dwLogLevel < LOGLEVEL_NONE) || (dwLogLevel > LOGLEVEL_ALL) || (dwLogLevel > g_VmmLogLevelFilter)) { return FALSE; } - if(!(pmi = VmmLog_GetModuleInfo(dwMID))) { return FALSE; } - fD = ((dwLogLevel <= ctxLog.dwLevelD) || (dwLogLevel <= pmi->dwLevelD)); // log to display - fF = ((dwLogLevel <= ctxLog.dwLevelF) || (dwLogLevel <= pmi->dwLevelF)) && ctxLog.pFile; // log to file + if((dwLogLevel < LOGLEVEL_NONE) || (dwLogLevel > LOGLEVEL_ALL) || (dwLogLevel > (VMMLOG_LEVEL)H->logfilter)) { return FALSE; } + if(!(pmi = VmmLog_GetModuleInfo(H, dwMID))) { return FALSE; } + fD = ((dwLogLevel <= ctxLog->dwLevelD) || (dwLogLevel <= pmi->dwLevelD)); // log to display + fF = ((dwLogLevel <= ctxLog->dwLevelF) || (dwLogLevel <= pmi->dwLevelF)) && ctxLog->pFile; // log to file return fD || fF; } /* * Log a message using a va_list. Whether the message is displayed and/or saved * to log file depends on the internal logging setup. +* -- H * -- dwMID = module ID (MID) * -- dwLogLevel = log level as defined by LOGLEVEL_* * -- uszFormat * -- arglist */ -VOID VmmLogEx2(_In_ DWORD dwMID, _In_ VMMLOG_LEVEL dwLogLevel, _In_z_ _Printf_format_string_ LPSTR uszFormat, va_list arglist) +VOID VmmLogEx2(_In_ VMM_HANDLE H, _In_ DWORD dwMID, _In_ VMMLOG_LEVEL dwLogLevel, _In_z_ _Printf_format_string_ LPSTR uszFormat, va_list arglist) { + PVMMLOG_CONTEXT ctxLog = H->log; PVMMLOG_CONTEXT_MODULEINFO pmi; BOOL fD = FALSE, fF = FALSE; CHAR uszBufferSmall[3 * MAX_PATH]; @@ -371,15 +366,16 @@ VOID VmmLogEx2(_In_ DWORD dwMID, _In_ VMMLOG_LEVEL dwLogLevel, _In_z_ _Printf_fo DWORD cchBuffer = sizeof(uszBufferSmall); DWORD i = 0, cchFormat; int cch; + if(!ctxLog) { return; } // sanity checks, get module info object and check if logs should happen to display/file: - if((dwLogLevel < LOGLEVEL_NONE) || (dwLogLevel > LOGLEVEL_ALL) || (dwLogLevel > g_VmmLogLevelFilter)) { return; } - if(!(pmi = VmmLog_GetModuleInfo(dwMID))) { return; } - fD = ((dwLogLevel <= ctxLog.dwLevelD) || (dwLogLevel <= pmi->dwLevelD)); // log to display - fF = ((dwLogLevel <= ctxLog.dwLevelF) || (dwLogLevel <= pmi->dwLevelF)) && ctxLog.pFile; // log to file + if((dwLogLevel < LOGLEVEL_NONE) || (dwLogLevel > LOGLEVEL_ALL) || (dwLogLevel > (VMMLOG_LEVEL)H->logfilter)) { return; } + if(!(pmi = VmmLog_GetModuleInfo(H, dwMID))) { return; } + fD = ((dwLogLevel <= ctxLog->dwLevelD) || (dwLogLevel <= pmi->dwLevelD)); // log to display + fF = ((dwLogLevel <= ctxLog->dwLevelF) || (dwLogLevel <= pmi->dwLevelF)) && ctxLog->pFile; // log to file if(!fD && !fF) { return; } // create message part of the log (allocate buffer if required) cch = _vsnprintf_s(uszBuffer, cchBuffer, _TRUNCATE, uszFormat, arglist); - if((cch < 0) || (cch > sizeof(uszBufferSmall) - 2)) { + if((cch < 0) || ((SIZE_T)cch > sizeof(uszBufferSmall) - 2)) { cchFormat = (DWORD)strlen(uszFormat); cchBuffer = cchFormat + 3 * MAX_PATH; uszBuffer = LocalAlloc(0, cchBuffer); @@ -400,7 +396,7 @@ VOID VmmLogEx2(_In_ DWORD dwMID, _In_ VMMLOG_LEVEL dwLogLevel, _In_z_ _Printf_fo // log to file if(fF) { Util_FileTime2String(Util_FileTimeNow(), szTime); - fprintf(ctxLog.pFile, "%s %s %-10s %s\n", szTime, VMMLOG_LEVEL_STR[dwLogLevel], szHead, uszBuffer); + fprintf(ctxLog->pFile, "%s %s %-10s %s\n", szTime, VMMLOG_LEVEL_STR[dwLogLevel], szHead, uszBuffer); } // cleanup if(uszBuffer != uszBufferSmall) { LocalFree(uszBuffer); } diff --git a/vmm/vmmlog.h b/vmm/vmmlog.h index 0ff748b..5cb141b 100644 --- a/vmm/vmmlog.h +++ b/vmm/vmmlog.h @@ -26,12 +26,13 @@ typedef enum tdVMMLOG_LEVEL { LOGLEVEL_7_ALL = 7, } VMMLOG_LEVEL; -// NB! also update VMMLOG_MID_STR in vmmlog.c when adding new built-in types. +// NB! also update VMMLOG_MID_STR when adding new built-in types. #define MID_NA 0x80000000 #define MID_MAIN 0x80000001 #define MID_PYTHON 0x80000002 +#define MID_DEBUG 0x80000003 #define MID_CORE 0x80000010 -#define MID_VMMDLL 0x80000011 +#define MID_API 0x80000011 #define MID_VMM 0x80000012 #define MID_PROCESS 0x80000013 #define MID_FORENSIC 0x80000014 @@ -43,57 +44,89 @@ typedef enum tdVMMLOG_LEVEL { #define MID_INFODB 0x8000001a #define MID_HEAP 0x8000001b #define MID_OFFSET 0x8000001c -#define MID_MAX 0x8000001c +#define MID_EVIL 0x8000001d +#define MID_MAX 0x8000001d -extern VMMLOG_LEVEL g_VmmLogLevelFilter; +// max 8 chars long! +static LPCSTR VMMLOG_MID_STR[] = { + "N/A", + // externally exposed built-in modules: + "MAIN", + "PYTHON", + "DEBUG", + "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", + // vmm internal built-in module: + "CORE", + "API", + "VMM", + "PROCESS", + "FORENSIC", + "REGISTRY", + "PLUGIN", + "NET", + "PE", + "PDB", + "INFODB", + "HEAP", + "OFFSET", + "EVIL" +}; /* * Refresh the display logging settings from settings. -* This function must be called at least once _before_ logging anything! +* NB! This function must be called at least once _before_ logging anything! +* -- H */ -VOID VmmLog_LevelRefresh(); +VOID VmmLog_LevelRefresh(_In_ VMM_HANDLE H); /* * Close and clean-up internal logging data structures. +* This should only be done last at system exit before shut-down. +* -- H */ -VOID VmmLog_Close(); +VOID VmmLog_Close(_In_ VMM_HANDLE H); /* * Get the log level for either display (on-screen) or file. +* -- H * -- dwMID = specify MID (other than 0) to get specific module level override. * -- fDisplay * -- return */ -VMMLOG_LEVEL VmmLog_LevelGet(_In_opt_ DWORD dwMID, _In_ BOOL fDisplay); +VMMLOG_LEVEL VmmLog_LevelGet(_In_ VMM_HANDLE H, _In_opt_ DWORD dwMID, _In_ BOOL fDisplay); /* * Set the log level for either display (on-screen) or file. +* -- H * -- dwMID = specify MID (other than 0) to set specific module level override. * -- dwLogLevel * -- fDisplay = TRUE(display), FALSE(file) * -- fSetOrIncrease = TRUE(set), FALSE(increase) */ -VOID VmmLog_LevelSet(_In_opt_ DWORD dwMID, _In_ VMMLOG_LEVEL dwLogLevel, _In_ BOOL fDisplay, _In_ BOOL fSetOrIncrease); +VOID VmmLog_LevelSet(_In_ VMM_HANDLE H, _In_opt_ DWORD dwMID, _In_ VMMLOG_LEVEL dwLogLevel, _In_ BOOL fDisplay, _In_ BOOL fSetOrIncrease); /* * Register a new module ID (MID) with the log database. * This function should be called in a single-threaded context by the plugin manager. +* -- H * -- dwMID = the module ID (MID) to register * -- uszModuleName * -- fExternal = externally loaded module (dll/so). */ -VOID VmmLog_RegisterModule(_In_ DWORD dwMID, _In_ LPSTR uszModuleName, _In_ BOOL fExternal); +VOID VmmLog_RegisterModule(_In_ VMM_HANDLE H, _In_ DWORD dwMID, _In_ LPSTR uszModuleName, _In_ BOOL fExternal); /* * Check whether the MID/LogLevel will log to any output. +* -- H * -- dwMID = module ID (MID) * -- dwLogLevel = log level as defined by LOGLEVEL_* * -- return = TRUE(will log), FALSE(will NOT log). */ -BOOL VmmLogIsActive(_In_ DWORD dwMID, _In_ VMMLOG_LEVEL dwLogLevel); +BOOL VmmLogIsActive(_In_ VMM_HANDLE H, _In_ DWORD dwMID, _In_ VMMLOG_LEVEL dwLogLevel); /* * Log a message "printf" style followed by a hexascii printout. +* -- H * -- dwMID = module ID (MID) * -- dwLogLevel = log level as defined by LOGLEVEL_* * -- pb = binary to log @@ -103,6 +136,7 @@ BOOL VmmLogIsActive(_In_ DWORD dwMID, _In_ VMMLOG_LEVEL dwLogLevel); * -- ... */ VOID VmmLogHexAsciiEx( + _In_ VMM_HANDLE H, _In_ DWORD dwMID, _In_ VMMLOG_LEVEL dwLogLevel, _In_reads_(cb) PBYTE pb, @@ -115,36 +149,39 @@ VOID VmmLogHexAsciiEx( /* * Log a message "printf" style. Whether the message is displayed and/or saved * to log file depends on the internal logging setup. +* -- H * -- dwMID = module ID (MID) * -- dwLogLevel = log level as defined by LOGLEVEL_* * -- uszFormat * -- ... */ -VOID VmmLogEx(_In_ DWORD dwMID, _In_ VMMLOG_LEVEL dwLogLevel, _In_z_ _Printf_format_string_ LPSTR uszFormat, ...); +VOID VmmLogEx(_In_ VMM_HANDLE H, _In_ DWORD dwMID, _In_ VMMLOG_LEVEL dwLogLevel, _In_z_ _Printf_format_string_ LPSTR uszFormat, ...); /* * Log a message using a va_list. Whether the message is displayed and/or saved * to log file depends on the internal logging setup. +* -- H * -- dwMID = module ID (MID) * -- dwLogLevel = log level as defined by LOGLEVEL_* * -- uszFormat * -- arglist */ -VOID VmmLogEx2(_In_ DWORD dwMID, _In_ VMMLOG_LEVEL dwLogLevel, _In_z_ _Printf_format_string_ LPSTR uszFormat, va_list arglist); +VOID VmmLogEx2(_In_ VMM_HANDLE H, _In_ DWORD dwMID, _In_ VMMLOG_LEVEL dwLogLevel, _In_z_ _Printf_format_string_ LPSTR uszFormat, va_list arglist); /* * Log amessage "printf" style. +* -- H * -- dwMID * -- dwLogLevel * -- format * -- ... */ -#define VmmLog(dwMID, dwLogLevel, format, ...) { if(dwLogLevel <= g_VmmLogLevelFilter) { VmmLogEx(dwMID, dwLogLevel, format, ##__VA_ARGS__); } } +#define VmmLog(H, dwMID, dwLogLevel, format, ...) { if(dwLogLevel <= (VMMLOG_LEVEL)H->logfilter) { VmmLogEx(H, dwMID, dwLogLevel, format, ##__VA_ARGS__); } } /* * printf a message to the console if allowed (i.e. not suppressed in a dll context). * NB! VmmLog* functions are preferred if possible! */ -#define vmmprintf(format, ...) { if(ctxMain->cfg.fVerboseDll) { printf(format, ##__VA_ARGS__); } } +#define vmmprintf(H, format, ...) { if(H->cfg.fVerboseDll) { printf(format, ##__VA_ARGS__); } } #endif /* __VMMLOG_H__ */ diff --git a/vmm/vmmnet.c b/vmm/vmmnet.c index e9bea83..bd0b6d0 100644 --- a/vmm/vmmnet.c +++ b/vmm/vmmnet.c @@ -117,12 +117,13 @@ int VmmNet_TcpE_CmpSort(PVMM_MAP_NETENTRY a, PVMM_MAP_NETENTRY b) /* * Fuzz offsets in TcpE if required. Upon a successful fuzz values will be stored -* in the ctxVmm global context. +* in the vmm handle. +* -- H * -- ctx * -- pSystemProcess * -- vaTcpE_UdpA - virtual address of a TCP ENDPOINT entry (TcpE). */ -VOID VmmNet_TcpE_Fuzz(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSystemProcess, _In_ QWORD vaTcpE) +VOID VmmNet_TcpE_Fuzz(_In_ VMM_HANDLE H, _In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSystemProcess, _In_ QWORD vaTcpE) { BOOL f; QWORD o, va; @@ -132,9 +133,9 @@ VOID VmmNet_TcpE_Fuzz(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSystemProcess PVMMNET_OFFSET_TcpE po = &ctx->oTcpE; if(po->_fValid || po->_fProcessedTry) { goto fail; } po->_fProcessedTry = TRUE; - if(!VmmRead(pSystemProcess, vaTcpE, pb, 0x300)) { goto fail; } + if(!VmmRead(H, pSystemProcess, vaTcpE, pb, 0x300)) { goto fail; } // Search for EPROCESS value in TcpE struct - while((pObProcess = VmmProcessGetNext(pObProcess, VMM_FLAG_PROCESS_SHOW_TERMINATED))) { + while((pObProcess = VmmProcessGetNext(H, pObProcess, VMM_FLAG_PROCESS_SHOW_TERMINATED))) { for(o = 0x80; o < 0x300; o += 8) { va = *(PQWORD)(pb + o); if(!VMM_KADDR64_16(va)) { continue; } @@ -142,14 +143,14 @@ VOID VmmNet_TcpE_Fuzz(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSystemProcess po->EProcess = (WORD)o; // INET_AF offset: f = VMM_KADDR64_16(*(PQWORD)(pb + 0x10)) && - VmmRead(pSystemProcess, *(PQWORD)(pb + 0x10) - 0x0c, (PBYTE)&dwPoolTagInNl, 4) && + VmmRead(H, pSystemProcess, *(PQWORD)(pb + 0x10) - 0x0c, (PBYTE)&dwPoolTagInNl, 4) && (dwPoolTagInNl == 'lNnI'); po->INET_AF = f ? 0x10 : 0x18; // INET_AF AF offset - po->INET_AF_AF = (ctxVmm->kernel.dwVersionBuild < 9200) ? 0x14 : 0x18; // VISTA-WIN7 or WIN8+ + po->INET_AF_AF = (H->vmm.kernel.dwVersionBuild < 9200) ? 0x14 : 0x18; // VISTA-WIN7 or WIN8+ // check for state offset po->State = (*(PDWORD)(pb + 0x6c) <= 13) ? 0x6c : 0x68; - if(ctxVmm->kernel.dwVersionBuild >= 22000) { + if(H->vmm.kernel.dwVersionBuild >= 22000) { po->State = 0x70; } // static or relative offsets @@ -161,15 +162,15 @@ VOID VmmNet_TcpE_Fuzz(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSystemProcess po->_Size = po->Time + 8; po->_fValid = TRUE; // print result - if(ctxMain->cfg.fVerboseExtra) { - VmmLog(MID_NET, LOGLEVEL_DEBUG, "FuzzTcpE: 0x%016llx", vaTcpE); - VmmLog(MID_NET, LOGLEVEL_DEBUG, + if(H->cfg.fVerboseExtra) { + VmmLog(H, MID_NET, LOGLEVEL_DEBUG, "FuzzTcpE: 0x%016llx", vaTcpE); + VmmLog(H, MID_NET, LOGLEVEL_DEBUG, " _Size %03X, InetAF %03X, InetAFAF %03X, InetAddr %03X, FLinkAll %03X", po->_Size, po->INET_AF, po->INET_AF_AF, po->INET_Addr, po->FLink); - VmmLog(MID_NET, LOGLEVEL_DEBUG, + VmmLog(H, MID_NET, LOGLEVEL_DEBUG, " State %03X, SrcPort %03X, DstPort %03X, EProcess %03X, Time %03X", po->State, po->PortSrc, po->PortDst, po->EProcess, po->Time); - VmmLogHexAsciiEx(MID_NET, LOGLEVEL_DEBUG, pb, 0x300, 0, ""); + VmmLogHexAsciiEx(H, MID_NET, LOGLEVEL_DEBUG, pb, 0x300, 0, ""); } Ob_DECREF(pObProcess); return; @@ -183,6 +184,7 @@ fail: /* * Retrieve the virtual addresses of the TCP ENDPOINT structs in memory (TcpE). * The virtual addresses will be put into the pObSet_TcpEndpoints set upon success. +* -- H * -- ctx * -- pSystemProcess * -- pPoolMap @@ -191,9 +193,9 @@ fail: * -- return */ _Success_(return) -BOOL VmmNet_TcpE_GetAddressEPs(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSystemProcess, _In_opt_ PVMMOB_MAP_POOL pPoolMap, _Inout_ POB_SET psvaOb_TcpE, _Inout_ POB_SET psvaOb_TcTW) +BOOL VmmNet_TcpE_GetAddressEPs(_In_ VMM_HANDLE H, _In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSystemProcess, _In_opt_ PVMMOB_MAP_POOL pPoolMap, _Inout_ POB_SET psvaOb_TcpE, _Inout_ POB_SET psvaOb_TcTW) { - BOOL f, fResult = FALSE; + BOOL f, f32 = H->vmm.f32, fResult = FALSE; QWORD va, va2, va3; DWORD i, j, o, iEntry, oStartHT, oListPT = 0, cbRead, cbTcpHT; BYTE pb[0x810] = { 0 }; @@ -202,12 +204,12 @@ BOOL VmmNet_TcpE_GetAddressEPs(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSyst PRTL_DYNAMIC_HASH_TABLE pTcpHT; DWORD iPoolTag, dwPoolTag; PVMM_MAP_POOLENTRYTAG pePoolTag; - if(!(pObTcHT = ObSet_New())) { goto fail; } - if(!(pObHTab_TcpE = ObSet_New())) { goto fail; } - if(!(pObTcpE = ObSet_New())) { goto fail; } + if(!(pObTcHT = ObSet_New(H))) { goto fail; } + if(!(pObHTab_TcpE = ObSet_New(H))) { goto fail; } + if(!(pObTcpE = ObSet_New(H))) { goto fail; } if(!(pbPartitionTable = LocalAlloc(LMEM_ZEROINIT, 0x4000))) { goto fail; } // 1: enumerate possible TcHT by walking tcpip.sys!PartitionTable - VmmReadEx(pSystemProcess, ctx->vaPartitionTable, pbPartitionTable, 0x4000, NULL, 0); + VmmReadEx(H, pSystemProcess, ctx->vaPartitionTable, pbPartitionTable, 0x4000, NULL, 0); oStartHT = (DWORD)(*(PQWORD)(pbPartitionTable + 0x10) - *(PQWORD)(pbPartitionTable + 0x00)); if(oStartHT < 0x40) { goto fail; } cbTcpHT = 0x10 + oStartHT + ctx->cPartition * sizeof(RTL_DYNAMIC_HASH_TABLE); @@ -232,14 +234,14 @@ BOOL VmmNet_TcpE_GetAddressEPs(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSyst } } if(0 == ObSet_Size(pObTcHT)) { goto fail; } - VmmCachePrefetchPages3(pSystemProcess, pObTcHT, cbTcpHT, 0); + VmmCachePrefetchPages3(H, pSystemProcess, pObTcHT, cbTcpHT, 0); // 2: enumerate possible/interesting TCP hash tables - TcHT. while((va = ObSet_Pop(pObTcHT))) { ZeroMemory(pbTcHT, cbTcpHT); - VmmReadEx(pSystemProcess, va, pbTcHT, cbTcpHT, &cbRead, VMM_FLAG_FORCECACHE_READ); - if((cbTcpHT != cbRead) || !VMM_POOLTAG_PREPENDED(pbTcHT, 0x10, 'TcHT')) { continue; } + VmmReadEx(H, pSystemProcess, va, pbTcHT, cbTcpHT, &cbRead, VMM_FLAG_FORCECACHE_READ); + if((cbTcpHT != cbRead) || !VMM_POOLTAG_PREPENDED(f32, pbTcHT, 0x10, 'TcHT')) { continue; } // Common TCP Hash Table: Contains TcTW - if(ctxVmm->kernel.dwVersionBuild >= 20348) { + if(H->vmm.kernel.dwVersionBuild >= 20348) { o = oStartHT - sizeof(RTL_DYNAMIC_HASH_TABLE); if(((PRTL_DYNAMIC_HASH_TABLE)(pbTcHT + o - 0x10))->DivisorMask == 0x7f) { o -= 0x10; } for(; o >= 2 * sizeof(RTL_DYNAMIC_HASH_TABLE); o -= sizeof(RTL_DYNAMIC_HASH_TABLE)) { @@ -258,13 +260,13 @@ BOOL VmmNet_TcpE_GetAddressEPs(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSyst } } if(0 == ObSet_Size(pObHTab_TcpE)) { goto fail; } - VmmCachePrefetchPages3(pSystemProcess, pObHTab_TcpE, 0x810, 0); + VmmCachePrefetchPages3(H, pSystemProcess, pObHTab_TcpE, 0x810, 0); // 3: Enumerate TCP Endpoints 'TcpE' out of the potential 'HTab' while((va = ObSet_Pop(pObHTab_TcpE))) { - VmmReadEx(pSystemProcess, va, pb, 0x810, &cbRead, VMM_FLAG_FORCECACHE_READ); + VmmReadEx(H, pSystemProcess, va, pb, 0x810, &cbRead, VMM_FLAG_FORCECACHE_READ); if(0x810 != cbRead) { continue; } - if((*(PDWORD)(pb + 0x04) != 'baTH') && (ctxVmm->kernel.dwVersionBuild != 10240)) { - VmmLog(MID_NET, LOGLEVEL_DEBUG, "UNEXPECTED POOL HDR: '%c%c%c%c' EXPECT: 'HTab' AT VA: 0x%016llx", pb[4], pb[5], pb[6], pb[7], va); + if((*(PDWORD)(pb + 0x04) != 'baTH') && (H->vmm.kernel.dwVersionBuild != 10240)) { + VmmLog(H, MID_NET, LOGLEVEL_DEBUG, "UNEXPECTED POOL HDR: '%c%c%c%c' EXPECT: 'HTab' AT VA: 0x%016llx", pb[4], pb[5], pb[6], pb[7], va); continue; } for(o = 0x10; o < 0x800; o += 0x10) { @@ -277,20 +279,20 @@ BOOL VmmNet_TcpE_GetAddressEPs(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSyst } } if(0 == ObSet_Size(pObTcpE)) { goto fail; } - VmmCachePrefetchPages3(pSystemProcess, pObTcpE, 0x50, 0); + VmmCachePrefetchPages3(H, pSystemProcess, pObTcpE, 0x50, 0); // 4: Verify and transfer to outgoing result set pObTcpE_Located while((va = ObSet_Pop(pObTcpE))) { - VmmReadEx(pSystemProcess, va, pb, 0x50, &cbRead, VMM_FLAG_FORCECACHE_READ); + VmmReadEx(H, pSystemProcess, va, pb, 0x50, &cbRead, VMM_FLAG_FORCECACHE_READ); if(0x50 != cbRead) { continue; } - if(VMM_POOLTAG_PREPENDED(pb, 0x10, 'TcpE') || VMM_POOLTAG_PREPENDED(pb, 0x10, 'TTcb')) { + if(VMM_POOLTAG_PREPENDED(f32, pb, 0x10, 'TcpE') || VMM_POOLTAG_PREPENDED(f32, pb, 0x10, 'TTcb')) { ObSet_Push(psvaOb_TcpE, va + 0x10); continue; } - if(VMM_POOLTAG_PREPENDED(pb, 0x50, 'TcTW')) { + if(VMM_POOLTAG_PREPENDED(f32, pb, 0x50, 'TcTW')) { ObSet_Push(psvaOb_TcTW, va + 0x50); continue; } - VmmLog(MID_NET, LOGLEVEL_DEBUG, "UNEXPECTED POOL HDR: '%c%c%c%c' EXPECT: 'TcpE/TTcb/TcTW' AT VA: 0x%016llx", pb[4], pb[5], pb[6], pb[7], va); + VmmLog(H, MID_NET, LOGLEVEL_DEBUG, "UNEXPECTED POOL HDR: '%c%c%c%c' EXPECT: 'TcpE/TTcb/TcTW' AT VA: 0x%016llx", pb[4], pb[5], pb[6], pb[7], va); } // 5: fill extra candidates from pool headers: if(pPoolMap) { @@ -300,7 +302,7 @@ BOOL VmmNet_TcpE_GetAddressEPs(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSyst case 1: o = 0x00; dwPoolTag = 'TTcb'; break; default: o = 0x40; dwPoolTag = 'TcTW'; break; } - if(VmmMap_GetPoolTag(pPoolMap, dwPoolTag, &iPoolTag)) { + if(VmmMap_GetPoolTag(H, pPoolMap, dwPoolTag, &iPoolTag)) { pePoolTag = pPoolMap->pTag + iPoolTag; for(j = 0; j < pePoolTag->cEntry; j++) { iEntry = pPoolMap->piTag2Map[pePoolTag->iTag2Map + j]; @@ -321,7 +323,7 @@ fail: } _Success_(return) -BOOL VmmNet_TcpE_Enumerate(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSystemProcess, _In_ POB_SET pSet_TcpE, _Inout_ POB_MAP pmTcpE) +BOOL VmmNet_TcpE_Enumerate(_In_ VMM_HANDLE H, _In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSystemProcess, _In_ POB_SET pSet_TcpE, _Inout_ POB_MAP pmTcpE) { BOOL f; QWORD va, ftTime, vaEPROCESS; @@ -332,11 +334,11 @@ BOOL VmmNet_TcpE_Enumerate(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSystemPr PVMM_PROCESS pObProcess = NULL; PVMMNET_OFFSET_TcpE po = &ctx->oTcpE; QWORD vaINET_AF, vaINET_Addr, vaINET_Src, vaINET_Dst; - if(!(pObPrefetch = ObSet_New())) { goto fail; } - VmmCachePrefetchPages3(pSystemProcess, pSet_TcpE, po->_Size, 0); + if(!(pObPrefetch = ObSet_New(H))) { goto fail; } + VmmCachePrefetchPages3(H, pSystemProcess, pSet_TcpE, po->_Size, 0); // 1: retrieve general info from main struct (TcpE) while((va = ObSet_Pop(pSet_TcpE))) { - VmmReadEx(pSystemProcess, va, pb, po->_Size, &cbRead, VMM_FLAG_FORCECACHE_READ); + VmmReadEx(H, pSystemProcess, va, pb, po->_Size, &cbRead, VMM_FLAG_FORCECACHE_READ); if(po->_Size != cbRead) { continue; } ftTime = *(PQWORD)(pb + po->Time); if(!ftTime || (ftTime > 0x0200000000000000)) { continue; } @@ -352,7 +354,7 @@ BOOL VmmNet_TcpE_Enumerate(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSystemPr pe->_Reserved1 = *(PQWORD)(pb + po->INET_AF); // vaINET_AF pe->_Reserved2 = *(PQWORD)(pb + po->INET_Addr); // vaINET_Addr vaEPROCESS = *(PQWORD)(pb + po->EProcess); - while((pObProcess = VmmProcessGetNext(pObProcess, VMM_FLAG_PROCESS_SHOW_TERMINATED))) { + while((pObProcess = VmmProcessGetNext(H, pObProcess, VMM_FLAG_PROCESS_SHOW_TERMINATED))) { if(vaEPROCESS == pObProcess->win.EPROCESS.va) { pe->dwPID = pObProcess->dwPID; Ob_DECREF_NULL(&pObProcess); @@ -364,9 +366,9 @@ BOOL VmmNet_TcpE_Enumerate(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSystemPr ObMap_Push(pmTcpE, va, pe); } // 2: retrieve address family and ptr to address - VmmCachePrefetchPages3(pSystemProcess, pObPrefetch, 0x30, 0); + VmmCachePrefetchPages3(H, pSystemProcess, pObPrefetch, 0x30, 0); Ob_DECREF_NULL(&pObPrefetch); - if(!(pObPrefetch = ObSet_New())) { goto fail; } + if(!(pObPrefetch = ObSet_New(H))) { goto fail; } for(i = 0, c = ObMap_Size(pmTcpE); i < c; i++) { pe = ObMap_GetByIndex(pmTcpE, i); vaINET_AF = pe->_Reserved1; @@ -374,19 +376,19 @@ BOOL VmmNet_TcpE_Enumerate(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSystemPr pe->_Reserved1 = 0; pe->_Reserved2 = 0; // 2.1 fetch INET_AF - VmmReadEx(pSystemProcess, vaINET_AF - 0x10, pb, 0x30, &cbRead, VMM_FLAG_FORCECACHE_READ); + VmmReadEx(H, pSystemProcess, vaINET_AF - 0x10, pb, 0x30, &cbRead, VMM_FLAG_FORCECACHE_READ); if(0x30 != cbRead) { continue; } if(*(PDWORD)(pb + 0x04) != 'lNnI') { - VmmLog(MID_NET, LOGLEVEL_DEBUG, "UNEXPECTED POOL HDR: '%c%c%c%c' EXPECT: 'InNl' AT VA: 0x%016llx", pb[4], pb[5], pb[6], pb[7], vaINET_AF); + VmmLog(H, MID_NET, LOGLEVEL_DEBUG, "UNEXPECTED POOL HDR: '%c%c%c%c' EXPECT: 'InNl' AT VA: 0x%016llx", pb[4], pb[5], pb[6], pb[7], vaINET_AF); continue; } pe->AF = *(PWORD)(pb + 0x10 + po->INET_AF_AF); if((pe->AF != AF_INET) && (pe->AF != AF_INET6)) { - VmmLog(MID_NET, LOGLEVEL_DEBUG, "UNEXPECTED INET_AF: %i EXPECT: %i or %i AT VA: 0x%016llx", pe->AF, AF_INET, AF_INET6, vaINET_AF); + VmmLog(H, MID_NET, LOGLEVEL_DEBUG, "UNEXPECTED INET_AF: %i EXPECT: %i or %i AT VA: 0x%016llx", pe->AF, AF_INET, AF_INET6, vaINET_AF); continue; } // 2.2 fetch ptrs to INET_ADDR SRC/DST and queue for prefetch - VmmReadEx(pSystemProcess, vaINET_Addr, pb, 0x18, &cbRead, VMM_FLAG_FORCECACHE_READ); + VmmReadEx(H, pSystemProcess, vaINET_Addr, pb, 0x18, &cbRead, VMM_FLAG_FORCECACHE_READ); if((0x18 != cbRead) || !VMM_KADDR64_8(*(PQWORD)(pb + 0x00)) || !VMM_KADDR64_8(*(PQWORD)(pb + 0x10))) { continue; } pe->_Reserved1 = *(PQWORD)(pb + 0x00); // vaINET_Src pe->_Reserved2 = *(PQWORD)(pb + 0x10); // vaINET_Dst @@ -394,7 +396,7 @@ BOOL VmmNet_TcpE_Enumerate(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSystemPr ObSet_Push(pObPrefetch, pe->_Reserved2); } // 3: retrieve src / dst addresses - VmmCachePrefetchPages3(pSystemProcess, pObPrefetch, 0x18, 0); + VmmCachePrefetchPages3(H, pSystemProcess, pObPrefetch, 0x18, 0); Ob_DECREF_NULL(&pObPrefetch); for(i = 0, c = ObMap_Size(pmTcpE); i < c; i++) { pe = ObMap_GetByIndex(pmTcpE, i); @@ -404,18 +406,18 @@ BOOL VmmNet_TcpE_Enumerate(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSystemPr pe->_Reserved2 = 0; if((pe->AF == AF_INET) || (pe->AF == AF_INET6)) { // 3.1 src address - VmmReadEx(pSystemProcess, vaINET_Src, pb, 0x18, &cbRead, VMM_FLAG_FORCECACHE_READ); + VmmReadEx(H, pSystemProcess, vaINET_Src, pb, 0x18, &cbRead, VMM_FLAG_FORCECACHE_READ); f = (0x18 == cbRead) && VMM_KADDR64_8(*(PQWORD)(pb + 0x10)) && - VmmRead(pSystemProcess, *(PQWORD)(pb + 0x10), pb, 0x08) && + VmmRead(H, pSystemProcess, *(PQWORD)(pb + 0x10), pb, 0x08) && VMM_KADDR64_8(*(PQWORD)pb) && - VmmRead(pSystemProcess, *(PQWORD)pb, pb, 0x20); + VmmRead(H, pSystemProcess, *(PQWORD)pb, pb, 0x20); if(f) { pe->Src.fValid = TRUE; memcpy(pe->Src.pbAddr, pb, (pe->AF == AF_INET) ? 4 : 16); } // 3.2 dst address - VmmReadEx(pSystemProcess, vaINET_Dst, pb, 0x20, &cbRead, VMM_FLAG_FORCECACHE_READ); + VmmReadEx(H, pSystemProcess, vaINET_Dst, pb, 0x20, &cbRead, VMM_FLAG_FORCECACHE_READ); if(0x20 == cbRead) { pe->Dst.fValid = TRUE; memcpy(pe->Dst.pbAddr, pb, (pe->AF == AF_INET) ? 4 : 16); @@ -429,7 +431,7 @@ fail: } _Success_(return) -BOOL VmmNet_TcpTW_Enumerate(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSystemProcess, _In_ POB_SET pSet_TcpTW, _Inout_ POB_MAP pmTcpE) +BOOL VmmNet_TcpTW_Enumerate(_In_ VMM_HANDLE H, _In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSystemProcess, _In_ POB_SET pSet_TcpTW, _Inout_ POB_MAP pmTcpE) { BOOL f; QWORD va; @@ -440,11 +442,11 @@ BOOL VmmNet_TcpTW_Enumerate(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSystemP PVMMNET_OFFSET_TcTW po = &ctx->oTcTW; QWORD vaINET_AF, vaINET_Addr, vaINET_Src; if(!ObSet_Size(pSet_TcpTW)) { goto fail; } - if(!(pObPrefetch = ObSet_New())) { goto fail; } - VmmCachePrefetchPages3(pSystemProcess, pSet_TcpTW, po->_Size, 0); + if(!(pObPrefetch = ObSet_New(H))) { goto fail; } + VmmCachePrefetchPages3(H, pSystemProcess, pSet_TcpTW, po->_Size, 0); // 1: retrieve general info from main struct (TcpE) while((va = ObSet_Pop(pSet_TcpTW))) { - if(!VmmRead2(pSystemProcess, va, pb, po->_Size, VMM_FLAG_FORCECACHE_READ)) { continue; } + if(!VmmRead2(H, pSystemProcess, va, pb, po->_Size, VMM_FLAG_FORCECACHE_READ)) { continue; } if(!VMM_KADDR64_8(*(PQWORD)(pb + po->INET_AF)) || !VMM_KADDR64_8(*(PQWORD)(pb + po->INET_Addr))) { continue; } @@ -464,9 +466,9 @@ BOOL VmmNet_TcpTW_Enumerate(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSystemP ObMap_Push(pmTcpE, va, pe); } // 2: retrieve address family and ptr to source address - VmmCachePrefetchPages3(pSystemProcess, pObPrefetch, 0x30, 0); + VmmCachePrefetchPages3(H, pSystemProcess, pObPrefetch, 0x30, 0); Ob_DECREF_NULL(&pObPrefetch); - if(!(pObPrefetch = ObSet_New())) { goto fail; } + if(!(pObPrefetch = ObSet_New(H))) { goto fail; } for(i = 0, c = ObMap_Size(pmTcpE); i < c; i++) { pe = ObMap_GetByIndex(pmTcpE, i); vaINET_AF = pe->_Reserved1; @@ -474,25 +476,25 @@ BOOL VmmNet_TcpTW_Enumerate(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSystemP pe->_Reserved1 = 0; pe->_Reserved2 = 0; // 2.1 fetch INET_AF - VmmReadEx(pSystemProcess, vaINET_AF - 0x10, pb, 0x30, &cbRead, VMM_FLAG_FORCECACHE_READ); + VmmReadEx(H, pSystemProcess, vaINET_AF - 0x10, pb, 0x30, &cbRead, VMM_FLAG_FORCECACHE_READ); if(0x30 != cbRead) { continue; } if(*(PDWORD)(pb + 0x04) != 'lNnI') { - VmmLog(MID_NET, LOGLEVEL_DEBUG, "UNEXPECTED POOL HDR: '%c%c%c%c' EXPECT: 'InNl' AT VA: 0x%016llx", pb[4], pb[5], pb[6], pb[7], vaINET_AF); + VmmLog(H, MID_NET, LOGLEVEL_DEBUG, "UNEXPECTED POOL HDR: '%c%c%c%c' EXPECT: 'InNl' AT VA: 0x%016llx", pb[4], pb[5], pb[6], pb[7], vaINET_AF); continue; } pe->AF = *(PWORD)(pb + 0x10 + ctx->oTcpE.INET_AF_AF); if((pe->AF != AF_INET) && (pe->AF != AF_INET6)) { - VmmLog(MID_NET, LOGLEVEL_DEBUG, "UNEXPECTED INET_AF: %i EXPECT: %i or %i AT VA: 0x%016llx", pe->AF, AF_INET, AF_INET6, vaINET_AF); + VmmLog(H, MID_NET, LOGLEVEL_DEBUG, "UNEXPECTED INET_AF: %i EXPECT: %i or %i AT VA: 0x%016llx", pe->AF, AF_INET, AF_INET6, vaINET_AF); continue; } // 2.2 fetch ptrs to INET_ADDR SRC and queue for prefetch - VmmReadEx(pSystemProcess, vaINET_Addr, pb, 0x18, &cbRead, VMM_FLAG_FORCECACHE_READ); + VmmReadEx(H, pSystemProcess, vaINET_Addr, pb, 0x18, &cbRead, VMM_FLAG_FORCECACHE_READ); if((0x18 != cbRead) || !VMM_KADDR64_8(*(PQWORD)(pb + 0x10))) { continue; } pe->_Reserved1 = *(PQWORD)(pb + 0x10); // vaINET_Src ObSet_Push(pObPrefetch, pe->_Reserved1); } // 3: retrieve src address - VmmCachePrefetchPages3(pSystemProcess, pObPrefetch, 0x38, 0); + VmmCachePrefetchPages3(H, pSystemProcess, pObPrefetch, 0x38, 0); Ob_DECREF_NULL(&pObPrefetch); for(i = 0, c = ObMap_Size(pmTcpE); i < c; i++) { pe = ObMap_GetByIndex(pmTcpE, i); @@ -501,7 +503,7 @@ BOOL VmmNet_TcpTW_Enumerate(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSystemP pe->_Reserved1 = 0; if((pe->AF == AF_INET) || (pe->AF == AF_INET6)) { // 3.1 src address - VmmReadEx(pSystemProcess, vaINET_Src, pb, 0x38, &cbRead, VMM_FLAG_FORCECACHE_READ); + VmmReadEx(H, pSystemProcess, vaINET_Src, pb, 0x38, &cbRead, VMM_FLAG_FORCECACHE_READ); f = (0x38 == cbRead) && VMM_KADDR64_8(*(PQWORD)(pb + 0x00)) && VMM_KADDR64_8(*(PQWORD)(pb + 0x10)) && @@ -522,20 +524,20 @@ fail: * Retrieve active TCP connections. * NB! Function may be started asynchronously. */ -DWORD VmmNet_TcpE_DoWork(PVOID lpThreadParameter) +DWORD VmmNet_TcpE_DoWork(_In_ VMM_HANDLE H, PVOID lpThreadParameter) { PVMMNET_ASYNC_CONTEXT actx = (PVMMNET_ASYNC_CONTEXT)lpThreadParameter; PVMMNET_CONTEXT ctx = actx->ctx; PVMM_PROCESS pSystemProcess = actx->pSystemProcess; POB_MAP pmNetEntries = actx->pmNetEntries; POB_SET pObTcpE = NULL, pObTcpTW = NULL; - if(!(pObTcpE = ObSet_New())) { goto fail; } - if(!(pObTcpTW = ObSet_New())) { goto fail; } - if(!VmmNet_TcpE_GetAddressEPs(ctx, pSystemProcess, actx->pPoolMap, pObTcpE, pObTcpTW)) { goto fail; } - VmmNet_TcpE_Fuzz(ctx, pSystemProcess, ObSet_Get(pObTcpE, 0)); + if(!(pObTcpE = ObSet_New(H))) { goto fail; } + if(!(pObTcpTW = ObSet_New(H))) { goto fail; } + if(!VmmNet_TcpE_GetAddressEPs(H, ctx, pSystemProcess, actx->pPoolMap, pObTcpE, pObTcpTW)) { goto fail; } + VmmNet_TcpE_Fuzz(H, ctx, pSystemProcess, ObSet_Get(pObTcpE, 0)); if(!ctx->oTcpE._fValid) { goto fail; } - VmmNet_TcpE_Enumerate(ctx, pSystemProcess, pObTcpE, pmNetEntries); - VmmNet_TcpTW_Enumerate(ctx, pSystemProcess, pObTcpTW, pmNetEntries); + VmmNet_TcpE_Enumerate(H, ctx, pSystemProcess, pObTcpE, pmNetEntries); + VmmNet_TcpTW_Enumerate(H, ctx, pSystemProcess, pObTcpTW, pmNetEntries); fail: Ob_DECREF(pObTcpE); Ob_DECREF(pObTcpTW); @@ -566,12 +568,13 @@ VOID VmmNet_InPP_FilterTcpLUdpA(_In_ QWORD k, _In_ PVOID v, _Inout_opt_ PVOID ct * Perform post processing of already enumerated UdpA / TcpL entries in map * pmNetEntriesPre. Upon completion valid entries will be transferred to map * pmNetEntries. +* -- H * -- ctx * -- pSystemProcess * -- pmNetEntriesPre = map of partial not-yet completed entries. * -- pmNetEntries = result map of completed net entries. */ -VOID VmmNet_InPP_PostTcpLUdpA(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSystemProcess, _Inout_ POB_MAP pmNetEntriesPre, _Inout_ POB_MAP pmNetEntries) +VOID VmmNet_InPP_PostTcpLUdpA(_In_ VMM_HANDLE H, _In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSystemProcess, _Inout_ POB_MAP pmNetEntriesPre, _Inout_ POB_MAP pmNetEntries) { DWORD o, cbRead; BYTE pb[0x30] = { 0 }; @@ -579,8 +582,8 @@ VOID VmmNet_InPP_PostTcpLUdpA(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSyste POB_MAP pmOb = NULL; QWORD vaINET_AF, vaLocal_Addr; PVMM_MAP_NETENTRY pe = NULL; - if(!(pmOb = ObMap_New(0))) { goto fail; } - if(!(psObPrefetch = ObSet_New())) { goto fail; } + if(!(pmOb = ObMap_New(H, 0))) { goto fail; } + if(!(psObPrefetch = ObSet_New(H))) { goto fail; } if(!ObMap_Filter(pmNetEntriesPre, pmOb, VmmNet_InPP_FilterTcpLUdpA)) { goto fail; } // 1: prefetch while((pe = ObMap_GetNext(pmOb, pe))) { @@ -589,7 +592,7 @@ VOID VmmNet_InPP_PostTcpLUdpA(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSyste } if(!ObSet_Size(psObPrefetch)) { goto fail; } // 2: retrieve address family and ptr to address - VmmCachePrefetchPages3(pSystemProcess, psObPrefetch, 0x30, 0); + VmmCachePrefetchPages3(H, pSystemProcess, psObPrefetch, 0x30, 0); ObSet_Clear(psObPrefetch); while((pe = ObMap_GetNext(pmOb, pe))) { vaINET_AF = pe->_Reserved1; @@ -597,21 +600,21 @@ VOID VmmNet_InPP_PostTcpLUdpA(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSyste pe->_Reserved1 = 0; pe->_Reserved2 = 0; // 2.1 fetch INET_AF - VmmReadEx(pSystemProcess, vaINET_AF - 0x10, pb, 0x30, &cbRead, VMM_FLAG_FORCECACHE_READ); + VmmReadEx(H, pSystemProcess, vaINET_AF - 0x10, pb, 0x30, &cbRead, VMM_FLAG_FORCECACHE_READ); if(0x30 != cbRead) { continue; } if(*(PDWORD)(pb + 0x04) != 'lNnI') { - VmmLog(MID_NET, LOGLEVEL_DEBUG, "UNEXPECTED POOL HDR: '%c%c%c%c' EXPECT: 'InNl' AT VA: 0x%016llx", pb[4], pb[5], pb[6], pb[7], vaINET_AF); + VmmLog(H, MID_NET, LOGLEVEL_DEBUG, "UNEXPECTED POOL HDR: '%c%c%c%c' EXPECT: 'InNl' AT VA: 0x%016llx", pb[4], pb[5], pb[6], pb[7], vaINET_AF); continue; } pe->AF = *(PWORD)(pb + 0x10 + ctx->oTcpL.INET_AF_AF); if((pe->AF != AF_INET) && (pe->AF != AF_INET6)) { - VmmLog(MID_NET, LOGLEVEL_DEBUG, "UNEXPECTED INET_AF: %i EXPECT: %i or %i AT VA: 0x%016llx", pe->AF, AF_INET, AF_INET6, vaINET_AF); + VmmLog(H, MID_NET, LOGLEVEL_DEBUG, "UNEXPECTED INET_AF: %i EXPECT: %i or %i AT VA: 0x%016llx", pe->AF, AF_INET, AF_INET6, vaINET_AF); continue; } // 2.2 fetch ptrs to INET_ADDR SRC and queue for prefetch if(vaLocal_Addr) { - o = ((pe->dwPoolTag == 'UdpA') && ctxVmm->kernel.dwVersionBuild >= 10240) ? 0x18 : 0x10; // UDP-Win10 special offset - VmmReadEx(pSystemProcess, vaLocal_Addr, pb, 0x20, &cbRead, VMM_FLAG_FORCECACHE_READ); + o = ((pe->dwPoolTag == 'UdpA') && H->vmm.kernel.dwVersionBuild >= 10240) ? 0x18 : 0x10; // UDP-Win10 special offset + VmmReadEx(H, pSystemProcess, vaLocal_Addr, pb, 0x20, &cbRead, VMM_FLAG_FORCECACHE_READ); if((0x20 != cbRead) || !VMM_KADDR64_8(*(PQWORD)(pb + o))) { continue; } pe->_Reserved2 = *(PQWORD)(pb + o); // vaSrc ObSet_Push(psObPrefetch, pe->_Reserved2); @@ -620,24 +623,24 @@ VOID VmmNet_InPP_PostTcpLUdpA(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSyste } } // 3: retrieve addr ptr - VmmCachePrefetchPages3(pSystemProcess, psObPrefetch, 8, 0); + VmmCachePrefetchPages3(H, pSystemProcess, psObPrefetch, 8, 0); ObSet_Clear(psObPrefetch); while((pe = ObMap_GetNext(pmOb, pe))) { if(pe->_Reserved2) { vaLocal_Addr = pe->_Reserved2; pe->_Reserved2 = 0; - VmmReadEx(pSystemProcess, vaLocal_Addr, pb, 8, &cbRead, VMM_FLAG_FORCECACHE_READ); + VmmReadEx(H, pSystemProcess, vaLocal_Addr, pb, 8, &cbRead, VMM_FLAG_FORCECACHE_READ); if((8 != cbRead) || !VMM_KADDR64_8(*(PQWORD)(pb))) { continue; } pe->_Reserved2 = *(PQWORD)(pb); // vaSrc ObSet_Push(psObPrefetch, pe->_Reserved2); } } // 4: retrieve addr - VmmCachePrefetchPages3(pSystemProcess, psObPrefetch, 0x20, 0); + VmmCachePrefetchPages3(H, pSystemProcess, psObPrefetch, 0x20, 0); while((pe = ObMap_GetNext(pmOb, pe))) { if(pe->_Reserved2) { - o = ((pe->dwPoolTag == 'UdpA') && ctxVmm->kernel.dwVersionBuild >= 10240) ? 0x18 : 0; // UDP-Win10 special offset - if(VmmRead2(pSystemProcess, pe->_Reserved2 + o, pb, 16, VMM_FLAG_FORCECACHE_READ)) { + o = ((pe->dwPoolTag == 'UdpA') && H->vmm.kernel.dwVersionBuild >= 10240) ? 0x18 : 0; // UDP-Win10 special offset + if(VmmRead2(H, pSystemProcess, pe->_Reserved2 + o, pb, 16, VMM_FLAG_FORCECACHE_READ)) { pe->Src.fValid = TRUE; memcpy(pe->Src.pbAddr, pb, (pe->AF == AF_INET) ? 4 : 16); } @@ -668,7 +671,7 @@ PVMM_MAP_NETENTRY VmmNet_InPP_TcpE(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS p /* * Enumerate PortPool UdpA / TcpL entries. */ -PVMM_MAP_NETENTRY VmmNet_InPP_TcpL_UdpA(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSystemProcess, _In_ DWORD dwPoolTag, PVMMNET_OFFSET_TcpL_UdpA po, _In_ QWORD vaTcpE_UdpA, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Inout_ POB_SET psEP_Next) +PVMM_MAP_NETENTRY VmmNet_InPP_TcpL_UdpA(_In_ VMM_HANDLE H, _In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSystemProcess, _In_ DWORD dwPoolTag, PVMMNET_OFFSET_TcpL_UdpA po, _In_ QWORD vaTcpE_UdpA, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _Inout_ POB_SET psEP_Next) { DWORD c = 0; QWORD ftTime, vaNext, vaEPROCESS; @@ -697,7 +700,7 @@ PVMM_MAP_NETENTRY VmmNet_InPP_TcpL_UdpA(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROC } vaEPROCESS = *(PQWORD)(pb + po->EProcess); if(VMM_KADDR64_16(vaEPROCESS)) { - while((pObProcess = VmmProcessGetNext(pObProcess, VMM_FLAG_PROCESS_SHOW_TERMINATED))) { + while((pObProcess = VmmProcessGetNext(H, pObProcess, VMM_FLAG_PROCESS_SHOW_TERMINATED))) { if(vaEPROCESS == pObProcess->win.EPROCESS.va) { pe->dwPID = pObProcess->dwPID; Ob_DECREF_NULL(&pObProcess); @@ -711,7 +714,7 @@ PVMM_MAP_NETENTRY VmmNet_InPP_TcpL_UdpA(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROC /* * Dispatch a PortPool entry to its enumeration function. */ -VOID VmmNet_InPP_Dispatch(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSystemProcess, _In_ DWORD tag, _In_ QWORD va, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _In_ DWORD oFLink, _Inout_ POB_SET psEP_Next, _Inout_ POB_MAP pmNetEntriesPre) +VOID VmmNet_InPP_Dispatch(_In_ VMM_HANDLE H, _In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSystemProcess, _In_ DWORD tag, _In_ QWORD va, _In_reads_(cb) PBYTE pb, _In_ DWORD cb, _In_ DWORD oFLink, _Inout_ POB_SET psEP_Next, _Inout_ POB_MAP pmNetEntriesPre) { PVMM_MAP_NETENTRY pe; PVMMNET_OFFSET_TcpL_UdpA po = &ctx->oTcpL; @@ -721,12 +724,12 @@ VOID VmmNet_InPP_Dispatch(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSystemPro VmmNet_InPP_TcpE(ctx, pSystemProcess, va, pb, cb, psEP_Next); } if(tag == 'TcpL') { - if((pe = VmmNet_InPP_TcpL_UdpA(ctx, pSystemProcess, 'TcpL', &ctx->oTcpL, va, pb, cb, psEP_Next))) { + if((pe = VmmNet_InPP_TcpL_UdpA(H, ctx, pSystemProcess, 'TcpL', &ctx->oTcpL, va, pb, cb, psEP_Next))) { ObMap_Push(pmNetEntriesPre, va, pe); } } if(tag == 'UdpA') { - if((pe = VmmNet_InPP_TcpL_UdpA(ctx, pSystemProcess, 'UdpA', &ctx->oUdpA, va, pb, cb, psEP_Next))) { + if((pe = VmmNet_InPP_TcpL_UdpA(H, ctx, pSystemProcess, 'UdpA', &ctx->oUdpA, va, pb, cb, psEP_Next))) { ObMap_Push(pmNetEntriesPre, va, pe); } } @@ -736,8 +739,10 @@ VOID VmmNet_InPP_Dispatch(_In_ PVMMNET_CONTEXT ctx, _In_ PVMM_PROCESS pSystemPro * Enumerate PortPool entries and put valid ones into the result map. * NB! Function may be started asynchronously. */ -DWORD VmmNet_InPP_DoWork(PVOID lpThreadParameter) +DWORD VmmNet_InPP_DoWork(_In_ VMM_HANDLE H, PVOID lpThreadParameter) { + BOOL f32 = H->vmm.f32; + DWORD dwVersionBuild = H->vmm.kernel.dwVersionBuild; PVMMNET_ASYNC_CONTEXT actx = (PVMMNET_ASYNC_CONTEXT)lpThreadParameter; PVMMNET_CONTEXT ctx = actx->ctx; PVMM_PROCESS pSystemProcess = actx->pSystemProcess; @@ -748,16 +753,16 @@ DWORD VmmNet_InPP_DoWork(PVOID lpThreadParameter) POB_SET psObPA = NULL, psObPreEP = NULL, psObEP = NULL, psObEP_Next = NULL, psObEP_SWAP; POB_MAP pmObNetEntriesPre = NULL; PVMM_MAP_POOLENTRYTAG pePoolTag; - if(!(psObPA = ObSet_New())) { goto fail; } - if(!(psObPreEP = ObSet_New())) { goto fail; } - if(!(psObEP = ObSet_New())) { goto fail; } - if(!(psObEP_Next = ObSet_New())) { goto fail; } - if(!(pmObNetEntriesPre = ObMap_New(OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } + if(!(psObPA = ObSet_New(H))) { goto fail; } + if(!(psObPreEP = ObSet_New(H))) { goto fail; } + if(!(psObEP = ObSet_New(H))) { goto fail; } + if(!(psObEP_Next = ObSet_New(H))) { goto fail; } + if(!(pmObNetEntriesPre = ObMap_New(H, OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } // set offsets - if(ctxVmm->kernel.dwVersionBuild <= 9200) { + if(dwVersionBuild <= 9200) { oInPPe = 0x08; cbInPPe = 0x10; - } else if(ctxVmm->kernel.dwVersionBuild <= 18363) { + } else if(dwVersionBuild <= 18363) { oInPPe = 0x08; cbInPPe = 0x18; } else { @@ -765,14 +770,14 @@ DWORD VmmNet_InPP_DoWork(PVOID lpThreadParameter) cbInPPe = 0x20; } // fetch InPA - VmmCachePrefetchPages2(pSystemProcess, 2, ctx->vaTcpPortPool, ctx->vaUdpPortPool); + VmmCachePrefetchPages2(H, pSystemProcess, 2, ctx->vaTcpPortPool, ctx->vaUdpPortPool); for(i = 0; i < 2; i++) { - if(!VmmRead2(pSystemProcess, i ? ctx->vaTcpPortPool : ctx->vaUdpPortPool, pb, 0x1000, VMM_FLAG_FORCECACHE_READ)) { continue; } + if(!VmmRead2(H, pSystemProcess, i ? ctx->vaTcpPortPool : ctx->vaUdpPortPool, pb, 0x1000, VMM_FLAG_FORCECACHE_READ)) { continue; } // offet for ptrs into InPA starts at +0a0 + extra, each InPA is responsible for 256 ports. if(!oInPA) { for(o = 0x0a0; o < 0x100; o += 8) { va = *(PQWORD)(pb + o); - if(VMM_KADDR64_16(va) && !VMM_KADDR64_PAGE(va) && VmmRead(pSystemProcess, va - 0x10, pb2, 0x20) && VMM_POOLTAG_PREPENDED(pb2, 0x10, 'InPA')) { + if(VMM_KADDR64_16(va) && !VMM_KADDR64_PAGE(va) && VmmRead(H, pSystemProcess, va - 0x10, pb2, 0x20) && VMM_POOLTAG_PREPENDED(f32, pb2, 0x10, 'InPA')) { oInPA = o; break; } @@ -788,9 +793,9 @@ DWORD VmmNet_InPP_DoWork(PVOID lpThreadParameter) } if(!ObSet_Size(psObPA)) { goto fail; } // fetch InPA tables - VmmCachePrefetchPages3(pSystemProcess, psObPA, 0x40, 0); + VmmCachePrefetchPages3(H, pSystemProcess, psObPA, 0x40, 0); while((va = ObSet_Pop(psObPA))) { - if(VmmRead2(pSystemProcess, va, pb, 0x40, VMM_FLAG_FORCECACHE_READ) && VMM_POOLTAG_PREPENDED(pb, 0x10, 'InPA')) { + if(VmmRead2(H, pSystemProcess, va, pb, 0x40, VMM_FLAG_FORCECACHE_READ) && VMM_POOLTAG_PREPENDED(f32, pb, 0x10, 'InPA')) { va = *(PQWORD)(pb + 0x28); if(!VMM_KADDR64_PAGE(va)) { va = *(PQWORD)(pb + 0x30); @@ -802,9 +807,9 @@ DWORD VmmNet_InPP_DoWork(PVOID lpThreadParameter) } if(!ObSet_Size(psObPreEP)) { goto fail; } // fetch initial addresses for endpoints / listeners. - VmmCachePrefetchPages(pSystemProcess, psObPreEP, 0); + VmmCachePrefetchPages(H, pSystemProcess, psObPreEP, 0); while((va = ObSet_Pop(psObPreEP))) { - VmmRead2(pSystemProcess, va, pb, 256 * cbInPPe, VMM_FLAG_FORCECACHE_READ | VMM_FLAG_ZEROPAD_ON_FAIL); + VmmRead2(H, pSystemProcess, va, pb, 256 * cbInPPe, VMM_FLAG_FORCECACHE_READ | VMM_FLAG_ZEROPAD_ON_FAIL); for(i = 0; i < 256; i++) { // TODO - 0-255 va = *(PQWORD)(pb + i * cbInPPe + oInPPe) & ~7; if(VMM_KADDR64_8(va)) { @@ -815,7 +820,7 @@ DWORD VmmNet_InPP_DoWork(PVOID lpThreadParameter) // fetch candidate addresses for endpoints / listeners from pool tagging if(actx->pPoolMap) { for(i = 0; i < 2; i++) { - if(VmmMap_GetPoolTag(actx->pPoolMap, (i ? 'TcpL' : 'UdpA'), &iPoolTag)) { + if(VmmMap_GetPoolTag(H, actx->pPoolMap, (i ? 'TcpL' : 'UdpA'), &iPoolTag)) { pePoolTag = actx->pPoolMap->pTag + iPoolTag; for(j = 0; j < pePoolTag->cEntry; j++) { iEntry = actx->pPoolMap->piTag2Map[pePoolTag->iTag2Map + j]; @@ -826,21 +831,21 @@ DWORD VmmNet_InPP_DoWork(PVOID lpThreadParameter) } // fetch and process endpoints / listeners while(ObSet_Size(psObEP) || ObSet_Size(psObEP_Next)) { - VmmCachePrefetchPages3(pSystemProcess, psObEP, VMMNET_EP_SIZE, 0); + VmmCachePrefetchPages3(H, pSystemProcess, psObEP, VMMNET_EP_SIZE, 0); while((va = ObSet_Pop(psObEP))) { oFLink = VMMNET_EP_OFFSET; if(va & 8) { oFLink -= 8; va += 8; } - VmmRead2(pSystemProcess, va, pb, VMMNET_EP_SIZE, VMM_FLAG_FORCECACHE_READ | VMM_FLAG_ZEROPAD_ON_FAIL); + VmmRead2(H, pSystemProcess, va, pb, VMMNET_EP_SIZE, VMM_FLAG_FORCECACHE_READ | VMM_FLAG_ZEROPAD_ON_FAIL); for(o = 0x10; o < 0x80; o += 0x10) { tag = 0; - if(VMM_POOLTAG_PREPENDED(pb, o, 'TcpL')) { tag = 'TcpL'; } - if(VMM_POOLTAG_PREPENDED(pb, o, 'TcpE')) { tag = 'TcpE'; } - if(VMM_POOLTAG_PREPENDED(pb, o, 'UdpA')) { tag = 'UdpA'; } + if(VMM_POOLTAG_PREPENDED(f32, pb, o, 'TcpL')) { tag = 'TcpL'; } + if(VMM_POOLTAG_PREPENDED(f32, pb, o, 'TcpE')) { tag = 'TcpE'; } + if(VMM_POOLTAG_PREPENDED(f32, pb, o, 'UdpA')) { tag = 'UdpA'; } if(tag) { - VmmNet_InPP_Dispatch(ctx, pSystemProcess, tag, va + o, pb + o, VMMNET_EP_SIZE - 8 - o, oFLink - o, psObEP_Next, pmObNetEntriesPre); + VmmNet_InPP_Dispatch(H, ctx, pSystemProcess, tag, va + o, pb + o, VMMNET_EP_SIZE - 8 - o, oFLink - o, psObEP_Next, pmObNetEntriesPre); break; } } @@ -851,7 +856,7 @@ DWORD VmmNet_InPP_DoWork(PVOID lpThreadParameter) } // post processing of entries // TODO: add post processing of InPP-TcpE - VmmNet_InPP_PostTcpLUdpA(ctx, pSystemProcess, pmObNetEntriesPre, pmNetEntries); + VmmNet_InPP_PostTcpLUdpA(H, ctx, pSystemProcess, pmObNetEntriesPre, pmNetEntries); fail: Ob_DECREF(psObEP_Next); Ob_DECREF(psObEP); @@ -875,11 +880,11 @@ VOID VmmNet_CallbackCleanup_ObMapNet(PVMMOB_MAP_NET pOb) /* * Set static offsets for the 'TcpL' / 'UdpA' / 'TcTW' structs depending on OS version. */ -VOID VmmNet_Initialize_Context_Fuzz_TcpL_UdpA_TcTW(_In_ PVMMNET_CONTEXT ctx) +VOID VmmNet_Initialize_Context_Fuzz_TcpL_UdpA_TcTW(_In_ VMM_HANDLE H, _In_ PVMMNET_CONTEXT ctx) { PVMMNET_OFFSET_TcTW potw; PVMMNET_OFFSET_TcpL_UdpA po; - DWORD dwBuild = ctxVmm->kernel.dwVersionBuild; + DWORD dwBuild = H->vmm.kernel.dwVersionBuild; // TcpL po = &ctx->oTcpL; if(dwBuild >= 10240) { @@ -937,21 +942,22 @@ VOID VmmNet_Initialize_Context_Fuzz_TcpL_UdpA_TcTW(_In_ PVMMNET_CONTEXT ctx) * port pool structures in memory on more recent Windows 10 systems. * The port pool may be located by traversing pool allocations such as: * tcpip!TcpCompartmentSet [InCS] -> [InCo] -> [TcCo/UdCo] -> [InPP large]. +* -- H * -- pSystemProcess * -- vaInCS * -- dwTagTcpUdp * -- return = address of TcpPortPool / UdpPortPool on success, zero on fail. */ -QWORD VmmNet_Initialize_Context_PortPool(_In_ PVMM_PROCESS pSystemProcess, _In_ QWORD vaInCS, _In_ DWORD dwTagTcpUdp) +QWORD VmmNet_Initialize_Context_PortPool(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ QWORD vaInCS, _In_ DWORD dwTagTcpUdp) { - BOOL f; + BOOL f, f32 = H->vmm.f32; BYTE pb[0x200]; POB_SET psvaOb = NULL; QWORD o, va, vaTcCo = 0, vaInPP = 0; // 1: InCS struct - if(!(psvaOb = ObSet_New())) { goto fail; } - if(!VmmRead(pSystemProcess, vaInCS - 0x10, pb, 0x180)) { goto fail; } - if(!VMM_POOLTAG_PREPENDED(pb, 0x10, 'InCS')) { goto fail; } + if(!(psvaOb = ObSet_New(H))) { goto fail; } + if(!VmmRead(H, pSystemProcess, vaInCS - 0x10, pb, 0x180)) { goto fail; } + if(!VMM_POOLTAG_PREPENDED(f32, pb, 0x10, 'InCS')) { goto fail; } for(o = 0x10; o < 0x180; o += 8) { va = *(PQWORD)(pb + o); if(VMM_KADDR64_16(va)) { @@ -959,10 +965,10 @@ QWORD VmmNet_Initialize_Context_PortPool(_In_ PVMM_PROCESS pSystemProcess, _In_ } } // 2: InCo struct - VmmCachePrefetchPages3(pSystemProcess, psvaOb, 0x40, 0); + VmmCachePrefetchPages3(H, pSystemProcess, psvaOb, 0x40, 0); while((va = ObSet_Pop(psvaOb))) { - f = VmmRead2(pSystemProcess, va, pb, 0x40, VMM_FLAG_FORCECACHE_READ) && - VMM_POOLTAG_PREPENDED(pb, 0x10, 'InCo') && + f = VmmRead2(H, pSystemProcess, va, pb, 0x40, VMM_FLAG_FORCECACHE_READ) && + VMM_POOLTAG_PREPENDED(f32, pb, 0x10, 'InCo') && (va = *(PQWORD)(pb + 0x30)) && VMM_KADDR64_16(va); if(f) { @@ -972,8 +978,8 @@ QWORD VmmNet_Initialize_Context_PortPool(_In_ PVMM_PROCESS pSystemProcess, _In_ } if(!vaTcCo) { goto fail; } // 3: TcCo/UdCo struct - f = VmmRead(pSystemProcess, vaTcCo - 0x10, pb, 0x20) && - VMM_POOLTAG_PREPENDED(pb, 0x10, dwTagTcpUdp) && + f = VmmRead(H, pSystemProcess, vaTcCo - 0x10, pb, 0x20) && + VMM_POOLTAG_PREPENDED(f32, pb, 0x10, dwTagTcpUdp) && (vaInPP = *(PQWORD)(pb + 0x10)) && VMM_KADDR64_PAGE(vaInPP); if(!f) { vaInPP = 0; } @@ -987,7 +993,7 @@ fail: * required data to look up networking information. * -- pSystemProcess */ -VOID VmmNet_Initialize_Context(_In_ PVMM_PROCESS pSystemProcess) +VOID VmmNet_Initialize_Context(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess) { BOOL fResult = FALSE; QWORD va; @@ -996,29 +1002,29 @@ VOID VmmNet_Initialize_Context(_In_ PVMM_PROCESS pSystemProcess) PVMM_MAP_MODULEENTRY peModuleTcpip; if(!(ctx = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMNET_CONTEXT)))) { goto fail; } // 1: fetch tcpip.sys info - if(!VmmMap_GetModuleEntryEx(pSystemProcess, 0, "tcpip.sys", &pObModuleMap, &peModuleTcpip)) { goto fail; } + if(!VmmMap_GetModuleEntryEx(H, pSystemProcess, 0, "tcpip.sys", &pObModuleMap, &peModuleTcpip)) { goto fail; } ctx->vaModuleTcpip = peModuleTcpip->vaBase; // 2: ensure load of tcp handle - PDB_LoadEnsure(PDB_GetHandleFromModuleAddress(pSystemProcess, ctx->vaModuleTcpip)); + PDB_LoadEnsure(H, PDB_GetHandleFromModuleAddress(H, pSystemProcess, ctx->vaModuleTcpip)); // 4: retrieve pdb information - PDB_GetSymbolPTR2(PDB_HANDLE_TCPIP, ctx->vaModuleTcpip, "PartitionTable", pSystemProcess, &ctx->vaPartitionTable); - PDB_GetSymbolDWORD2(PDB_HANDLE_TCPIP, ctx->vaModuleTcpip, "PartitionCount", pSystemProcess, &ctx->cPartition); - if(!VMM_KADDR(ctx->vaPartitionTable) || !ctx->cPartition || (ctx->cPartition > 64)) { goto fail; } + PDB_GetSymbolPTR2(H, PDB_HANDLE_TCPIP, ctx->vaModuleTcpip, "PartitionTable", pSystemProcess, &ctx->vaPartitionTable); + PDB_GetSymbolDWORD2(H, PDB_HANDLE_TCPIP, ctx->vaModuleTcpip, "PartitionCount", pSystemProcess, &ctx->cPartition); + if(!VMM_KADDR(H->vmm.f32, ctx->vaPartitionTable) || !ctx->cPartition || (ctx->cPartition > 64)) { goto fail; } // 3: retrieve TcpPortPool / UdpPortPool - if(ctxVmm->kernel.dwVersionBuild <= 10586) { - PDB_GetSymbolPTR2(PDB_HANDLE_TCPIP, ctx->vaModuleTcpip, "TcpPortPool", pSystemProcess, &ctx->vaTcpPortPool); - PDB_GetSymbolPTR2(PDB_HANDLE_TCPIP, ctx->vaModuleTcpip, "UdpPortPool", pSystemProcess, &ctx->vaUdpPortPool); + if(H->vmm.kernel.dwVersionBuild <= 10586) { + PDB_GetSymbolPTR2(H, PDB_HANDLE_TCPIP, ctx->vaModuleTcpip, "TcpPortPool", pSystemProcess, &ctx->vaTcpPortPool); + PDB_GetSymbolPTR2(H, PDB_HANDLE_TCPIP, ctx->vaModuleTcpip, "UdpPortPool", pSystemProcess, &ctx->vaUdpPortPool); } else { - if(PDB_GetSymbolPTR2(PDB_HANDLE_TCPIP, ctx->vaModuleTcpip, "TcpCompartmentSet", pSystemProcess, &va)) { - ctx->vaTcpPortPool = VmmNet_Initialize_Context_PortPool(pSystemProcess, va, 'TcCo'); + if(PDB_GetSymbolPTR2(H, PDB_HANDLE_TCPIP, ctx->vaModuleTcpip, "TcpCompartmentSet", pSystemProcess, &va)) { + ctx->vaTcpPortPool = VmmNet_Initialize_Context_PortPool(H, pSystemProcess, va, 'TcCo'); } - if(PDB_GetSymbolPTR2(PDB_HANDLE_TCPIP, ctx->vaModuleTcpip, "UdpCompartmentSet", pSystemProcess, &va)) { - ctx->vaUdpPortPool = VmmNet_Initialize_Context_PortPool(pSystemProcess, va, 'UdCo'); + if(PDB_GetSymbolPTR2(H, PDB_HANDLE_TCPIP, ctx->vaModuleTcpip, "UdpCompartmentSet", pSystemProcess, &va)) { + ctx->vaUdpPortPool = VmmNet_Initialize_Context_PortPool(H, pSystemProcess, va, 'UdCo'); } } // 4: set offsets - VmmNet_Initialize_Context_Fuzz_TcpL_UdpA_TcTW(ctx); - VmmLog(MID_NET, LOGLEVEL_DEBUG, "NET INIT: \n\t PartitionTable: 0x%llx [%i] \n\t TcpPortPool: 0x%llx \n\t UdpPortPool: 0x%llx", ctx->vaPartitionTable, ctx->cPartition, ctx->vaTcpPortPool, ctx->vaUdpPortPool); + VmmNet_Initialize_Context_Fuzz_TcpL_UdpA_TcTW(H, ctx); + VmmLog(H, MID_NET, LOGLEVEL_DEBUG, "NET INIT: \n\t PartitionTable: 0x%llx [%i] \n\t TcpPortPool: 0x%llx \n\t UdpPortPool: 0x%llx", ctx->vaPartitionTable, ctx->cPartition, ctx->vaTcpPortPool, ctx->vaUdpPortPool); fResult = TRUE; fail: if(!fResult) { @@ -1026,18 +1032,19 @@ fail: ctx = NULL; } Ob_DECREF(pObModuleMap); - ctxVmm->pNetContext = ctx; + H->vmm.pNetContext = ctx; } /* * Retrieve a Map containing the network connections of the system if possible. * CALLER DECREF: return +* -- H * -- pSystemProcess * -- return */ -PVMMOB_MAP_NET VmmNet_Initialize_DoWork(_In_ PVMM_PROCESS pSystemProcess) +PVMMOB_MAP_NET VmmNet_Initialize_DoWork(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess) { - PVMMNET_CONTEXT ctx = (PVMMNET_CONTEXT)ctxVmm->pNetContext; + PVMMNET_CONTEXT ctx = (PVMMNET_CONTEXT)H->vmm.pNetContext; LPCSTR szSTATES[] = { "CLOSED", "LISTENING", @@ -1064,21 +1071,21 @@ PVMMOB_MAP_NET VmmNet_Initialize_DoWork(_In_ PVMM_PROCESS pSystemProcess) VMMNET_ASYNC_CONTEXT actx = { 0 }; POB_STRMAP psmOb = NULL; // 1: fetch / initialize context - if(ctxVmm->f32) { goto fail; } + if(H->vmm.f32) { goto fail; } if(!ctx) { - VmmNet_Initialize_Context(pSystemProcess); - if(!(ctx = (PVMMNET_CONTEXT)ctxVmm->pNetContext)) { goto fail; } + VmmNet_Initialize_Context(H, pSystemProcess); + if(!(ctx = (PVMMNET_CONTEXT)H->vmm.pNetContext)) { goto fail; } } - if(!(pmObNetEntries = ObMap_New(OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } + if(!(pmObNetEntries = ObMap_New(H, OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } // enumeration may take some time - schedule work in parallel to speed things up. actx.ctx = ctx; actx.pmNetEntries = pmObNetEntries; actx.pSystemProcess = pSystemProcess; - VmmMap_GetPool(&actx.pPoolMap, TRUE); - VmmWorkWaitMultiple(&actx, 2, VmmNet_TcpE_DoWork, VmmNet_InPP_DoWork); + VmmMap_GetPool(H, &actx.pPoolMap, TRUE); + VmmWorkWaitMultiple_Void(H, &actx, 2, VmmNet_TcpE_DoWork, VmmNet_InPP_DoWork); cNetEntries = ObMap_Size(pmObNetEntries); - if(!(psmOb = ObStrMap_New(OB_STRMAP_FLAGS_STR_ASSIGN_TEMPORARY))) { goto fail; } - if(!(pObNet = Ob_Alloc(OB_TAG_MAP_NET, LMEM_ZEROINIT, sizeof(VMMOB_MAP_NET) + cNetEntries * sizeof(VMM_MAP_NETENTRY), (OB_CLEANUP_CB)VmmNet_CallbackCleanup_ObMapNet, NULL))) { goto fail; } + if(!(psmOb = ObStrMap_New(H, OB_STRMAP_FLAGS_STR_ASSIGN_TEMPORARY))) { goto fail; } + if(!(pObNet = Ob_AllocEx(H, OB_TAG_MAP_NET, LMEM_ZEROINIT, sizeof(VMMOB_MAP_NET) + cNetEntries * sizeof(VMM_MAP_NETENTRY), (OB_CLEANUP_CB)VmmNet_CallbackCleanup_ObMapNet, NULL))) { goto fail; } for(i = 0; i < cNetEntries; i++) { pe = pObNet->pMap + i; pNetEntry = ObMap_GetByIndex(pmObNetEntries, i); @@ -1130,27 +1137,28 @@ fail: /* * Create a network connection map and assign to the global context upon success. * CALLER DECREF: return +* -- H * -- return */ -PVMMOB_MAP_NET VmmNet_Initialize() +PVMMOB_MAP_NET VmmNet_Initialize(_In_ VMM_HANDLE H) { PVMMOB_MAP_NET pObNet = NULL; PVMM_PROCESS pObSystemProcess = NULL; - if((pObNet = ObContainer_GetOb(ctxVmm->pObCMapNet))) { return pObNet; } - EnterCriticalSection(&ctxVmm->LockUpdateMap); - if((pObNet = ObContainer_GetOb(ctxVmm->pObCMapNet))) { - LeaveCriticalSection(&ctxVmm->LockUpdateMap); + if((pObNet = ObContainer_GetOb(H->vmm.pObCMapNet))) { return pObNet; } + EnterCriticalSection(&H->vmm.LockUpdateMap); + if((pObNet = ObContainer_GetOb(H->vmm.pObCMapNet))) { + LeaveCriticalSection(&H->vmm.LockUpdateMap); return pObNet; } - if((pObSystemProcess = VmmProcessGet(4))) { - pObNet = VmmNet_Initialize_DoWork(pObSystemProcess); + if((pObSystemProcess = VmmProcessGet(H, 4))) { + pObNet = VmmNet_Initialize_DoWork(H, pObSystemProcess); Ob_DECREF_NULL(&pObSystemProcess); } if(!pObNet) { - pObNet = Ob_Alloc(OB_TAG_MAP_NET, LMEM_ZEROINIT, sizeof(VMMOB_MAP_NET), NULL, NULL); + pObNet = Ob_AllocEx(H, OB_TAG_MAP_NET, LMEM_ZEROINIT, sizeof(VMMOB_MAP_NET), NULL, NULL); } - ObContainer_SetOb(ctxVmm->pObCMapNet, pObNet); - LeaveCriticalSection(&ctxVmm->LockUpdateMap); + ObContainer_SetOb(H->vmm.pObCMapNet, pObNet); + LeaveCriticalSection(&H->vmm.LockUpdateMap); return pObNet; } @@ -1158,19 +1166,21 @@ PVMMOB_MAP_NET VmmNet_Initialize() * Close the networking functionality. * NB! Close() should only be called on vmm exit. To clear internal state plesae * use function: VmmNet_Refresh(). +* -- H */ -VOID VmmNet_Close() +VOID VmmNet_Close(_In_ VMM_HANDLE H) { - EnterCriticalSection(&ctxVmm->LockMaster); - LocalFree(ctxVmm->pNetContext); - ctxVmm->pNetContext = NULL; - LeaveCriticalSection(&ctxVmm->LockMaster); + EnterCriticalSection(&H->vmm.LockMaster); + LocalFree(H->vmm.pNetContext); + H->vmm.pNetContext = NULL; + LeaveCriticalSection(&H->vmm.LockMaster); } /* * Refresh the network connection map. +* -- H */ -VOID VmmNet_Refresh() +VOID VmmNet_Refresh(_In_ VMM_HANDLE H) { - ObContainer_SetOb(ctxVmm->pObCMapNet, NULL); + ObContainer_SetOb(H->vmm.pObCMapNet, NULL); } diff --git a/vmm/vmmnet.h b/vmm/vmmnet.h index f07f295..b3d6d5b 100644 --- a/vmm/vmmnet.h +++ b/vmm/vmmnet.h @@ -11,20 +11,23 @@ /* * Create a network connection map and assign to the global context upon success. * CALLER DECREF: return +* -- H * -- return */ -PVMMOB_MAP_NET VmmNet_Initialize(); +PVMMOB_MAP_NET VmmNet_Initialize(_In_ VMM_HANDLE H); /* * Refresh the network connection map. +* -- H */ -VOID VmmNet_Refresh(); +VOID VmmNet_Refresh(_In_ VMM_HANDLE H); /* * Close the networking functionality. * NB! Close() should only be called on vmm exit. To clear internal state plesae * use function: VmmNet_Refresh(). +* -- H */ -VOID VmmNet_Close(); +VOID VmmNet_Close(_In_ VMM_HANDLE H); #endif /* __VMMNET_H__ */ diff --git a/vmm/vmmproc.c b/vmm/vmmproc.c index 84b284f..d52bdcc 100644 --- a/vmm/vmmproc.c +++ b/vmm/vmmproc.c @@ -25,47 +25,48 @@ /* * Try initialize from user supplied CR3/PML4 supplied in parameter at startup. +* -- H * -- ctx * -- return */ -BOOL VmmProcUserCR3TryInitialize64() +BOOL VmmProcUserCR3TryInitialize64(_In_ VMM_HANDLE H) { PVMM_PROCESS pObProcess; - VmmInitializeMemoryModel(VMM_MEMORYMODEL_X64); - pObProcess = VmmProcessCreateEntry(TRUE, 1, 0, 0, ctxMain->cfg.paCR3, 0, "unknown_process", FALSE, NULL, 0); - VmmProcessCreateFinish(); + VmmInitializeMemoryModel(H, VMM_MEMORYMODEL_X64); + pObProcess = VmmProcessCreateEntry(H, TRUE, 1, 0, 0, H->cfg.paCR3, 0, "unknown_process", FALSE, NULL, 0); + VmmProcessCreateFinish(H); if(!pObProcess) { - VmmLog(MID_CORE, LOGLEVEL_VERBOSE, "FAIL: Initialization of Process failed from user-defined CR3 %016llx", ctxMain->cfg.paCR3); - VmmInitializeMemoryModel(VMM_MEMORYMODEL_NA); + VmmLog(H, MID_CORE, LOGLEVEL_VERBOSE, "FAIL: Initialization of Process failed from user-defined CR3 %016llx", H->cfg.paCR3); + VmmInitializeMemoryModel(H, VMM_MEMORYMODEL_NA); return FALSE; } - VmmTlbSpider(pObProcess); + VmmTlbSpider(H, pObProcess); Ob_DECREF(pObProcess); - ctxVmm->tpSystem = VMM_SYSTEM_UNKNOWN_X64; - ctxVmm->kernel.paDTB = ctxMain->cfg.paCR3; + H->vmm.tpSystem = VMM_SYSTEM_UNKNOWN_X64; + H->vmm.kernel.paDTB = H->cfg.paCR3; return TRUE; } -BOOL VmmProc_RefreshProcesses(_In_ BOOL fRefreshTotal) +BOOL VmmProc_RefreshProcesses(_In_ VMM_HANDLE H, _In_ BOOL fRefreshTotal) { BOOL fResult = FALSE; PVMM_PROCESS pObProcessSystem; // statistic count - if(!fRefreshTotal) { InterlockedIncrement64(&ctxVmm->stat.cProcessRefreshPartial); } - if(fRefreshTotal) { InterlockedIncrement64(&ctxVmm->stat.cProcessRefreshFull); } + if(!fRefreshTotal) { InterlockedIncrement64(&H->vmm.stat.cProcessRefreshPartial); } + if(fRefreshTotal) { InterlockedIncrement64(&H->vmm.stat.cProcessRefreshFull); } // Single user-defined X64 process - if(fRefreshTotal && (ctxVmm->tpSystem == VMM_SYSTEM_UNKNOWN_X64)) { - fResult = VmmProcUserCR3TryInitialize64(); + if(fRefreshTotal && (H->vmm.tpSystem == VMM_SYSTEM_UNKNOWN_X64)) { + fResult = VmmProcUserCR3TryInitialize64(H); } // Windows OS - if((ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X64) || (ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X86)) { - VmmLog(MID_CORE, LOGLEVEL_DEBUG, "PROCESS_REFRESH: %s", (fRefreshTotal ? "Total" : "Partial")); - pObProcessSystem = VmmProcessGet(4); + if((H->vmm.tpSystem == VMM_SYSTEM_WINDOWS_X64) || (H->vmm.tpSystem == VMM_SYSTEM_WINDOWS_X86)) { + VmmLog(H, MID_CORE, LOGLEVEL_DEBUG, "PROCESS_REFRESH: %s", (fRefreshTotal ? "Total" : "Partial")); + pObProcessSystem = VmmProcessGet(H, 4); if(!pObProcessSystem) { - VmmLog(MID_CORE, LOGLEVEL_CRITICAL, "SYSTEM PROCESS NOT FOUND - SHOULD NOT HAPPEN"); + VmmLog(H, MID_CORE, LOGLEVEL_CRITICAL, "SYSTEM PROCESS NOT FOUND - SHOULD NOT HAPPEN"); return FALSE; } - fResult = VmmWinProcess_Enumerate(pObProcessSystem, fRefreshTotal, NULL); + fResult = VmmWinProcess_Enumerate(H, pObProcessSystem, fRefreshTotal, NULL); Ob_DECREF(pObProcessSystem); } return fResult; @@ -98,142 +99,151 @@ BOOL VmmProc_RefreshProcesses(_In_ BOOL fRefreshTotal) * 5. VmmProcRefresh_Slow() = slow refresh. * A slower more comprehensive refresh layer does not equal that the lower * faster refresh layers are run automatically - user has to refresh them too. +* -- H */ _Success_(return) -BOOL VmmProcRefresh_MEM() +BOOL VmmProcRefresh_MEM(_In_ VMM_HANDLE H) { - EnterCriticalSection(&ctxVmm->LockMaster); - ctxVmm->tcRefreshMEM++; - VmmCacheClearPartial(VMM_CACHE_TAG_PHYS); - InterlockedIncrement64(&ctxVmm->stat.cPhysRefreshCache); - VmmCacheClearPartial(VMM_CACHE_TAG_PAGING); - InterlockedIncrement64(&ctxVmm->stat.cPageRefreshCache); - ObSet_Clear(ctxVmm->Cache.PAGING_FAILED); - LeaveCriticalSection(&ctxVmm->LockMaster); + EnterCriticalSection(&H->vmm.LockMaster); + H->vmm.tcRefreshMEM++; + VmmCacheClearPartial(H, VMM_CACHE_TAG_PHYS); + InterlockedIncrement64(&H->vmm.stat.cPhysRefreshCache); + VmmCacheClearPartial(H, VMM_CACHE_TAG_PAGING); + InterlockedIncrement64(&H->vmm.stat.cPageRefreshCache); + ObSet_Clear(H->vmm.Cache.PAGING_FAILED); + LeaveCriticalSection(&H->vmm.LockMaster); return TRUE; } _Success_(return) -BOOL VmmProcRefresh_TLB() +BOOL VmmProcRefresh_TLB(_In_ VMM_HANDLE H) { - EnterCriticalSection(&ctxVmm->LockMaster); - ctxVmm->tcRefreshTLB++; - VmmCacheClearPartial(VMM_CACHE_TAG_TLB); - InterlockedIncrement64(&ctxVmm->stat.cTlbRefreshCache); - LeaveCriticalSection(&ctxVmm->LockMaster); + EnterCriticalSection(&H->vmm.LockMaster); + H->vmm.tcRefreshTLB++; + VmmCacheClearPartial(H, VMM_CACHE_TAG_TLB); + InterlockedIncrement64(&H->vmm.stat.cTlbRefreshCache); + LeaveCriticalSection(&H->vmm.LockMaster); return TRUE; } _Success_(return) -BOOL VmmProcRefresh_Fast() +BOOL VmmProcRefresh_Fast(_In_ VMM_HANDLE H) { - EnterCriticalSection(&ctxVmm->LockMaster); - ctxVmm->tcRefreshFast++; - if(!VmmProc_RefreshProcesses(FALSE)) { - LeaveCriticalSection(&ctxVmm->LockMaster); - VmmLog(MID_CORE, LOGLEVEL_CRITICAL, "Failed to refresh MemProcFS - aborting!"); + EnterCriticalSection(&H->vmm.LockMaster); + H->vmm.tcRefreshFast++; + if(!VmmProc_RefreshProcesses(H, FALSE)) { + LeaveCriticalSection(&H->vmm.LockMaster); + VmmLog(H, MID_CORE, LOGLEVEL_CRITICAL, "Failed to refresh MemProcFS - aborting!"); return FALSE; } - PluginManager_Notify(VMMDLL_PLUGIN_NOTIFY_REFRESH_FAST, NULL, 0); - LeaveCriticalSection(&ctxVmm->LockMaster); + PluginManager_Notify(H, VMMDLL_PLUGIN_NOTIFY_REFRESH_FAST, NULL, 0); + LeaveCriticalSection(&H->vmm.LockMaster); return TRUE; } _Success_(return) -BOOL VmmProcRefresh_Medium() +BOOL VmmProcRefresh_Medium(_In_ VMM_HANDLE H) { - EnterCriticalSection(&ctxVmm->LockMaster); - ctxVmm->tcRefreshMedium++; - if(!VmmProc_RefreshProcesses(TRUE)) { - LeaveCriticalSection(&ctxVmm->LockMaster); - VmmLog(MID_CORE, LOGLEVEL_CRITICAL, "Failed to refresh MemProcFS - aborting!"); + EnterCriticalSection(&H->vmm.LockMaster); + H->vmm.tcRefreshMedium++; + if(!VmmProc_RefreshProcesses(H, TRUE)) { + LeaveCriticalSection(&H->vmm.LockMaster); + VmmLog(H, MID_CORE, LOGLEVEL_CRITICAL, "Failed to refresh MemProcFS - aborting!"); return FALSE; } - VmmNet_Refresh(); - VmmWinObj_Refresh(); - MmPfn_Refresh(); - VmmHeapAlloc_Refresh(); - PluginManager_Notify(VMMDLL_PLUGIN_NOTIFY_REFRESH_MEDIUM, NULL, 0); - LeaveCriticalSection(&ctxVmm->LockMaster); + VmmNet_Refresh(H); + VmmWinObj_Refresh(H); + MmPfn_Refresh(H); + VmmHeapAlloc_Refresh(H); + PluginManager_Notify(H, VMMDLL_PLUGIN_NOTIFY_REFRESH_MEDIUM, NULL, 0); + LeaveCriticalSection(&H->vmm.LockMaster); return TRUE; } _Success_(return) -BOOL VmmProcRefresh_Slow() +BOOL VmmProcRefresh_Slow(_In_ VMM_HANDLE H) { - EnterCriticalSection(&ctxVmm->LockMaster); - ctxVmm->tcRefreshSlow++; - VmmWinReg_Refresh(); - VmmWinUser_Refresh(); - VmmWinSvc_Refresh(); - VmmWinPool_Refresh(); - VmmWinPhysMemMap_Refresh(); - PluginManager_Notify(VMMDLL_PLUGIN_NOTIFY_REFRESH_SLOW, NULL, 0); - LeaveCriticalSection(&ctxVmm->LockMaster); + EnterCriticalSection(&H->vmm.LockMaster); + H->vmm.tcRefreshSlow++; + VmmWinReg_Refresh(H); + VmmWinUser_Refresh(H); + VmmWinSvc_Refresh(H); + VmmWinPool_Refresh(H); + VmmWinPhysMemMap_Refresh(H); + PluginManager_Notify(H, VMMDLL_PLUGIN_NOTIFY_REFRESH_SLOW, NULL, 0); + LeaveCriticalSection(&H->vmm.LockMaster); return TRUE; } -DWORD VmmProcCacheUpdaterThread() +VOID VmmProcCacheUpdaterThread(_In_ VMM_HANDLE H, _In_ QWORD qwNotUsed) { - QWORD i = 0; + QWORD i = 0, qwTickPeriodCount; BOOL fRefreshMEM, fRefreshTLB, fRefreshFast, fRefreshMedium, fRefreshSlow; - VmmLog(MID_CORE, LOGLEVEL_VERBOSE, "VmmProc: Start periodic cache flushing"); - if(ctxMain->dev.fRemote) { - ctxVmm->ThreadProcCache.cMs_TickPeriod = VMMPROC_UPDATERTHREAD_REMOTE_PERIOD; - ctxVmm->ThreadProcCache.cTick_MEM = VMMPROC_UPDATERTHREAD_REMOTE_MEM; - ctxVmm->ThreadProcCache.cTick_TLB = VMMPROC_UPDATERTHREAD_REMOTE_TLB; - ctxVmm->ThreadProcCache.cTick_Fast = VMMPROC_UPDATERTHREAD_REMOTE_PROC_REFRESHLIST; - ctxVmm->ThreadProcCache.cTick_Medium = VMMPROC_UPDATERTHREAD_REMOTE_PROC_REFRESHTOTAL; - ctxVmm->ThreadProcCache.cTick_Slow = VMMPROC_UPDATERTHREAD_REMOTE_REGISTRY; + VmmLog(H, MID_CORE, LOGLEVEL_VERBOSE, "VmmProc: Start periodic cache flushing"); + if(H->dev.fRemote) { + H->vmm.ThreadProcCache.cMs_TickPeriod = VMMPROC_UPDATERTHREAD_REMOTE_PERIOD; + H->vmm.ThreadProcCache.cTick_MEM = VMMPROC_UPDATERTHREAD_REMOTE_MEM; + H->vmm.ThreadProcCache.cTick_TLB = VMMPROC_UPDATERTHREAD_REMOTE_TLB; + H->vmm.ThreadProcCache.cTick_Fast = VMMPROC_UPDATERTHREAD_REMOTE_PROC_REFRESHLIST; + H->vmm.ThreadProcCache.cTick_Medium = VMMPROC_UPDATERTHREAD_REMOTE_PROC_REFRESHTOTAL; + H->vmm.ThreadProcCache.cTick_Slow = VMMPROC_UPDATERTHREAD_REMOTE_REGISTRY; } else { - ctxVmm->ThreadProcCache.cMs_TickPeriod = VMMPROC_UPDATERTHREAD_LOCAL_PERIOD; - ctxVmm->ThreadProcCache.cTick_MEM = VMMPROC_UPDATERTHREAD_LOCAL_MEM; - ctxVmm->ThreadProcCache.cTick_TLB = VMMPROC_UPDATERTHREAD_LOCAL_TLB; - ctxVmm->ThreadProcCache.cTick_Fast = VMMPROC_UPDATERTHREAD_LOCAL_PROC_REFRESHLIST; - ctxVmm->ThreadProcCache.cTick_Medium = VMMPROC_UPDATERTHREAD_LOCAL_PROC_REFRESHTOTAL; - ctxVmm->ThreadProcCache.cTick_Slow = VMMPROC_UPDATERTHREAD_LOCAL_REGISTRY; + H->vmm.ThreadProcCache.cMs_TickPeriod = VMMPROC_UPDATERTHREAD_LOCAL_PERIOD; + H->vmm.ThreadProcCache.cTick_MEM = VMMPROC_UPDATERTHREAD_LOCAL_MEM; + H->vmm.ThreadProcCache.cTick_TLB = VMMPROC_UPDATERTHREAD_LOCAL_TLB; + H->vmm.ThreadProcCache.cTick_Fast = VMMPROC_UPDATERTHREAD_LOCAL_PROC_REFRESHLIST; + H->vmm.ThreadProcCache.cTick_Medium = VMMPROC_UPDATERTHREAD_LOCAL_PROC_REFRESHTOTAL; + H->vmm.ThreadProcCache.cTick_Slow = VMMPROC_UPDATERTHREAD_LOCAL_REGISTRY; } - while(ctxVmm->Work.fEnabled && ctxVmm->ThreadProcCache.fEnabled) { - Sleep(ctxVmm->ThreadProcCache.cMs_TickPeriod); + while(!H->fAbort && H->vmm.ThreadProcCache.fEnabled) { + if(H->vmm.ThreadProcCache.cMs_TickPeriod > 100) { + qwTickPeriodCount = 0; + while((qwTickPeriodCount < H->vmm.ThreadProcCache.cMs_TickPeriod) && !H->fAbort) { + qwTickPeriodCount += 25; + Sleep(25); + } + } else { + Sleep(H->vmm.ThreadProcCache.cMs_TickPeriod); + } + if(H->fAbort) { break; } i++; - fRefreshTLB = !(i % ctxVmm->ThreadProcCache.cTick_TLB); - fRefreshMEM = !(i % ctxVmm->ThreadProcCache.cTick_MEM); - fRefreshSlow = !(i % ctxVmm->ThreadProcCache.cTick_Slow); - fRefreshMedium = !(i % ctxVmm->ThreadProcCache.cTick_Medium); - fRefreshFast = !(i % ctxVmm->ThreadProcCache.cTick_Fast) && !fRefreshMedium; + fRefreshTLB = !(i % H->vmm.ThreadProcCache.cTick_TLB); + fRefreshMEM = !(i % H->vmm.ThreadProcCache.cTick_MEM); + fRefreshSlow = !(i % H->vmm.ThreadProcCache.cTick_Slow); + fRefreshMedium = !(i % H->vmm.ThreadProcCache.cTick_Medium); + fRefreshFast = !(i % H->vmm.ThreadProcCache.cTick_Fast) && !fRefreshMedium; // PHYS / TLB cache clear - EnterCriticalSection(&ctxVmm->LockMaster); + EnterCriticalSection(&H->vmm.LockMaster); if(fRefreshMEM) { - VmmProcRefresh_MEM(); + VmmProcRefresh_MEM(H); } if(fRefreshTLB) { - VmmProcRefresh_TLB(); + VmmProcRefresh_TLB(H); } if(fRefreshFast) { - VmmProcRefresh_Fast(); // incl. partial process refresh + VmmProcRefresh_Fast(H); // incl. partial process refresh } if(fRefreshMedium) { - VmmProcRefresh_Medium(); // incl. full process refresh + VmmProcRefresh_Medium(H); // incl. full process refresh } if(fRefreshSlow) { - VmmProcRefresh_Slow(); + VmmProcRefresh_Slow(H); } - LeaveCriticalSection(&ctxVmm->LockMaster); + LeaveCriticalSection(&H->vmm.LockMaster); } - VmmLog(MID_CORE, LOGLEVEL_VERBOSE, "Exit periodic cache flushing"); - return 0; + VmmLog(H, MID_CORE, LOGLEVEL_VERBOSE, "Exit periodic cache flushing"); } -BOOL VmmProcInitialize() +BOOL VmmProcInitialize(_In_ VMM_HANDLE H) { BOOL result = FALSE; - if(!VmmInitialize()) { return FALSE; } + if(!VmmInitialize(H)) { return FALSE; } // 1: try initialize 'windows' with an optionally supplied CR3 - result = VmmWinInit_TryInitialize(ctxMain->cfg.paCR3); + result = VmmWinInit_TryInitialize(H, H->cfg.paCR3); if(!result) { - result = ctxMain->cfg.paCR3 && VmmProcUserCR3TryInitialize64(); + result = H->cfg.paCR3 && VmmProcUserCR3TryInitialize64(H); if(!result) { - vmmprintf( + vmmprintf(H, "VmmProc: Unable to auto-identify operating system for PROC file system mount. \n" \ " Specify PageDirectoryBase (DTB/CR3) in -cr3 option if value if known. \n"); } @@ -242,9 +252,9 @@ BOOL VmmProcInitialize() // worker thread in case the backend is a volatile device (FPGA). // If the underlying device isn't volatile then there is no need to update! // NB! Files are not considered to be volatile. - if(result && ctxMain->dev.fVolatile && !ctxMain->cfg.fDisableBackgroundRefresh) { - ctxVmm->ThreadProcCache.fEnabled = TRUE; - VmmWork((LPTHREAD_START_ROUTINE)VmmProcCacheUpdaterThread, NULL, 0); + if(result && H->dev.fVolatile && !H->cfg.fDisableBackgroundRefresh) { + H->vmm.ThreadProcCache.fEnabled = TRUE; + VmmWork_Value(H, VmmProcCacheUpdaterThread, 0, 0, VMMWORK_FLAG_PRIO_NORMAL); } return result; } diff --git a/vmm/vmmproc.h b/vmm/vmmproc.h index d5a7bcd..235fa0a 100644 --- a/vmm/vmmproc.h +++ b/vmm/vmmproc.h @@ -18,19 +18,20 @@ * A slower more comprehensive refresh layer does not equal that the lower * faster refresh layers are run automatically - user has to refresh them too. */ -_Success_(return) BOOL VmmProcRefresh_MEM(); -_Success_(return) BOOL VmmProcRefresh_TLB(); -_Success_(return) BOOL VmmProcRefresh_Fast(); -_Success_(return) BOOL VmmProcRefresh_Medium(); -_Success_(return) BOOL VmmProcRefresh_Slow(); +_Success_(return) BOOL VmmProcRefresh_MEM(_In_ VMM_HANDLE H); +_Success_(return) BOOL VmmProcRefresh_TLB(_In_ VMM_HANDLE H); +_Success_(return) BOOL VmmProcRefresh_Fast(_In_ VMM_HANDLE H); +_Success_(return) BOOL VmmProcRefresh_Medium(_In_ VMM_HANDLE H); +_Success_(return) BOOL VmmProcRefresh_Slow(_In_ VMM_HANDLE H); /* * Tries to automatically identify the operating system given by the supplied * memory device (fpga hardware or file). If an operating system is successfully * identified a VMM_CONTEXT will be created and stored within the PCILEECH_CONTEXT. * If the VMM fails to identify an operating system FALSE is returned. +* -- H * -- return */ -BOOL VmmProcInitialize(); +BOOL VmmProcInitialize(_In_ VMM_HANDLE H); #endif /* __VMMPROC_H__ */ diff --git a/vmm/vmmwin.c b/vmm/vmmwin.c index ba4ce07..0502cdd 100644 --- a/vmm/vmmwin.c +++ b/vmm/vmmwin.c @@ -25,13 +25,13 @@ // GENERAL FUNCTIONALITY // ---------------------------------------------------------------------------- -PIMAGE_NT_HEADERS VmmWin_GetVerifyHeaderPE(_In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModule, _Inout_ PBYTE pbModuleHeader, _Out_ PBOOL pfHdr32) +PIMAGE_NT_HEADERS VmmWin_GetVerifyHeaderPE(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ QWORD vaModule, _Inout_ PBYTE pbModuleHeader, _Out_ PBOOL pfHdr32) { PIMAGE_DOS_HEADER dosHeader; PIMAGE_NT_HEADERS ntHeader; *pfHdr32 = FALSE; if(vaModule) { - if(!VmmReadPage(pProcess, vaModule, pbModuleHeader)) { return NULL; } + if(!VmmReadPage(H, pProcess, vaModule, pbModuleHeader)) { return NULL; } } dosHeader = (PIMAGE_DOS_HEADER)pbModuleHeader; // dos header. if(!dosHeader || dosHeader->e_magic != IMAGE_DOS_SIGNATURE) { return NULL; } @@ -57,9 +57,9 @@ int VmmWin_HashTableLookup_CmpSort(PDWORD pdw1, PDWORD pdw2) * Callback function for cache map entry validity - an entry is valid * if it's in the same medium refresh tickcount. */ -BOOL VmmWinEATIAT_Callback_ValidEntry(_Inout_ PQWORD qwContext, _In_ QWORD qwKey, _In_ PVOID pvObject) +BOOL VmmWinEATIAT_Callback_ValidEntry(_In_ VMM_HANDLE H, _Inout_ PQWORD qwContext, _In_ QWORD qwKey, _In_ PVOID pvObject) { - return *qwContext == ctxVmm->tcRefreshMedium; + return *qwContext == H->vmm.tcRefreshMedium; } VOID VmmWinEAT_ObCloseCallback(_In_ PVMMOB_MAP_EAT pObEAT) @@ -70,11 +70,12 @@ VOID VmmWinEAT_ObCloseCallback(_In_ PVMMOB_MAP_EAT pObEAT) /* * Helper function for EAT initialization. * CALLER DECREF: return +* -- H * -- pProcess * -- pModule * -- return */ -PVMMOB_MAP_EAT VmmWinEAT_Initialize_DoWork(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_MODULEENTRY pModule) +PVMMOB_MAP_EAT VmmWinEAT_Initialize_DoWork(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_MODULEENTRY pModule) { BYTE pbModuleHeader[0x1000] = { 0 }; PIMAGE_NT_HEADERS64 ntHeader64; @@ -90,7 +91,7 @@ PVMMOB_MAP_EAT VmmWinEAT_Initialize_DoWork(_In_ PVMM_PROCESS pProcess, _In_ PVMM PVMMOB_MAP_EAT pObEAT = NULL; PVMM_MAP_EATENTRY pe; // load both 32/64 bit ntHeader (only one will be valid) - if(!(ntHeader64 = (PIMAGE_NT_HEADERS64)VmmWin_GetVerifyHeaderPE(pProcess, pModule->vaBase, pbModuleHeader, &fHdr32))) { goto fail; } + if(!(ntHeader64 = (PIMAGE_NT_HEADERS64)VmmWin_GetVerifyHeaderPE(H, pProcess, pModule->vaBase, pbModuleHeader, &fHdr32))) { goto fail; } ntHeader32 = (PIMAGE_NT_HEADERS32)ntHeader64; // load Export Address Table (EAT) oExpDir = fHdr32 ? @@ -102,7 +103,7 @@ PVMMOB_MAP_EAT VmmWinEAT_Initialize_DoWork(_In_ PVMM_PROCESS pProcess, _In_ PVMM vaExpDir = pModule->vaBase + oExpDir; if(!oExpDir || !cbExpDir || cbExpDir > 0x01000000) { goto fail; } if(!(pbExpDir = LocalAlloc(0, cbExpDir + 1ULL))) { goto fail; } - if(!VmmRead(pProcess, vaExpDir, pbExpDir, cbExpDir)) { goto fail; } + if(!VmmRead(H, pProcess, vaExpDir, pbExpDir, cbExpDir)) { goto fail; } pbExpDir[cbExpDir] = 0; // sanity check EAT pExpDir = (PIMAGE_EXPORT_DIRECTORY)pbExpDir; @@ -118,8 +119,8 @@ PVMMOB_MAP_EAT VmmWinEAT_Initialize_DoWork(_In_ PVMM_PROCESS pProcess, _In_ PVMM pwNameOrdinals = (PWORD)(pbExpDir + pExpDir->AddressOfNameOrdinals - oExpDir); pdwRvaFunctions = (PDWORD)(pbExpDir + pExpDir->AddressOfFunctions - oExpDir); // allocate EAT-MAP - if(!(pObStrMap = ObStrMap_New(OB_STRMAP_FLAGS_CASE_SENSITIVE))) { goto fail; } - if(!(pObEAT = Ob_Alloc(OB_TAG_MAP_EAT, LMEM_ZEROINIT, sizeof(VMMOB_MAP_EAT) + pExpDir->NumberOfFunctions * (sizeof(VMM_MAP_EATENTRY) + sizeof(QWORD)), (OB_CLEANUP_CB)VmmWinEAT_ObCloseCallback, NULL))) { goto fail; } + if(!(pObStrMap = ObStrMap_New(H, OB_STRMAP_FLAGS_CASE_SENSITIVE))) { goto fail; } + if(!(pObEAT = Ob_AllocEx(H, OB_TAG_MAP_EAT, LMEM_ZEROINIT, sizeof(VMMOB_MAP_EAT) + pExpDir->NumberOfFunctions * (sizeof(VMM_MAP_EATENTRY) + sizeof(QWORD)), (OB_CLEANUP_CB)VmmWinEAT_ObCloseCallback, NULL))) { goto fail; } pObEAT->pHashTableLookup = (PQWORD)((QWORD)pObEAT + sizeof(VMMOB_MAP_EAT) + pExpDir->NumberOfFunctions * sizeof(VMM_MAP_EATENTRY)); pObEAT->cMap = pExpDir->NumberOfFunctions; pObEAT->vaModuleBase = pModule->vaBase; @@ -161,29 +162,30 @@ PVMMOB_MAP_EAT VmmWinEAT_Initialize_DoWork(_In_ PVMM_PROCESS pProcess, _In_ PVMM fail: Ob_DECREF(pObStrMap); LocalFree(pbExpDir); - return Ob_Alloc(OB_TAG_MAP_EAT, LMEM_ZEROINIT, sizeof(VMMOB_MAP_EAT), NULL, NULL); + return Ob_AllocEx(H, OB_TAG_MAP_EAT, LMEM_ZEROINIT, sizeof(VMMOB_MAP_EAT), NULL, NULL); } /* * Initialize EAT (exported functions) for a specific module. * CALLER DECREF: return +* -- H * -- pProcess * -- pModule * -- return */ -PVMMOB_MAP_EAT VmmWinEAT_Initialize(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_MODULEENTRY pModule) +PVMMOB_MAP_EAT VmmWinEAT_Initialize(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_MODULEENTRY pModule) { BOOL f; PVMMOB_MAP_EAT pObMap = NULL; QWORD qwKey = (pProcess->dwPID ^ ((QWORD)pProcess->dwPID << 48) ^ pModule->vaBase); - f = ctxVmm->pObCacheMapEAT || - (ctxVmm->pObCacheMapEAT = ObCacheMap_New(0x20, VmmWinEATIAT_Callback_ValidEntry, OB_CACHEMAP_FLAGS_OBJECT_OB)); + f = H->vmm.pObCacheMapEAT || + (H->vmm.pObCacheMapEAT = ObCacheMap_New(H, 0x20, VmmWinEATIAT_Callback_ValidEntry, OB_CACHEMAP_FLAGS_OBJECT_OB)); if(!f) { return NULL; } - if((pObMap = ObCacheMap_GetByKey(ctxVmm->pObCacheMapEAT, qwKey))) { return pObMap; } + if((pObMap = ObCacheMap_GetByKey(H->vmm.pObCacheMapEAT, qwKey))) { return pObMap; } EnterCriticalSection(&pProcess->LockUpdate); - pObMap = ObCacheMap_GetByKey(ctxVmm->pObCacheMapEAT, qwKey); - if(!pObMap && (pObMap = VmmWinEAT_Initialize_DoWork(pProcess, pModule))) { - ObCacheMap_Push(ctxVmm->pObCacheMapEAT, qwKey, pObMap, ctxVmm->tcRefreshMedium); + pObMap = ObCacheMap_GetByKey(H->vmm.pObCacheMapEAT, qwKey); + if(!pObMap && (pObMap = VmmWinEAT_Initialize_DoWork(H, pProcess, pModule))) { + ObCacheMap_Push(H->vmm.pObCacheMapEAT, qwKey, pObMap, H->vmm.tcRefreshMedium); } LeaveCriticalSection(&pProcess->LockUpdate); return pObMap; @@ -197,11 +199,12 @@ VOID VmmWinIAT_ObCloseCallback(_In_ PVMMOB_MAP_IAT pObIAT) /* * Helper function for IAT initialization. * CALLER DECREF: return +* -- H * -- pProcess * -- pModule * -- return */ -PVMMOB_MAP_IAT VmmWinIAT_Initialize_DoWork(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_MODULEENTRY pModule) +PVMMOB_MAP_IAT VmmWinIAT_Initialize_DoWork(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_MODULEENTRY pModule) { BYTE pbModuleHeader[0x1000] = { 0 }; PIMAGE_NT_HEADERS64 ntHeader64; @@ -220,19 +223,19 @@ PVMMOB_MAP_IAT VmmWinIAT_Initialize_DoWork(_In_ PVMM_PROCESS pProcess, _In_ PVMM if(pModule->cbImageSize > PE_MAX_SUPPORTED_SIZE) { goto fail; } // above max supported size (may be indication of corrupt data) cbModule = pModule->cbImageSize; if(!(pbModule = LocalAlloc(LMEM_ZEROINIT, cbModule))) { goto fail; } - VmmReadEx(pProcess, pModule->vaBase, pbModule, cbModule, &cbRead, 0); + VmmReadEx(H, pProcess, pModule->vaBase, pbModule, cbModule, &cbRead, 0); if(cbRead <= 0x2000) { goto fail; } pbModule[cbModule - 1] = 0; // load both 32/64 bit ntHeader (only one will be valid) - if(!(ntHeader64 = (PIMAGE_NT_HEADERS64)VmmWin_GetVerifyHeaderPE(pProcess, pModule->vaBase, pbModuleHeader, &fHdr32))) { goto fail; } + if(!(ntHeader64 = (PIMAGE_NT_HEADERS64)VmmWin_GetVerifyHeaderPE(H, pProcess, pModule->vaBase, pbModuleHeader, &fHdr32))) { goto fail; } ntHeader32 = (PIMAGE_NT_HEADERS32)ntHeader64; oImportDirectory = fHdr32 ? ntHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress : ntHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; if(!oImportDirectory || (oImportDirectory >= cbModule)) { goto fail; } // Allocate IAT-MAP - if(!(pObStrMap = ObStrMap_New(OB_STRMAP_FLAGS_CASE_SENSITIVE))) { goto fail; } - if(!(pObIAT = Ob_Alloc(OB_TAG_MAP_IAT, LMEM_ZEROINIT, sizeof(VMMOB_MAP_IAT) + pModule->cIAT * sizeof(VMM_MAP_IATENTRY), (OB_CLEANUP_CB)VmmWinIAT_ObCloseCallback, NULL))) { goto fail; } + if(!(pObStrMap = ObStrMap_New(H, OB_STRMAP_FLAGS_CASE_SENSITIVE))) { goto fail; } + if(!(pObIAT = Ob_AllocEx(H, OB_TAG_MAP_IAT, LMEM_ZEROINIT, sizeof(VMMOB_MAP_IAT) + pModule->cIAT * sizeof(VMM_MAP_IATENTRY), (OB_CLEANUP_CB)VmmWinIAT_ObCloseCallback, NULL))) { goto fail; } pObIAT->cMap = pModule->cIAT; pObIAT->vaModuleBase = pModule->vaBase; // Walk imported modules / functions @@ -316,29 +319,30 @@ PVMMOB_MAP_IAT VmmWinIAT_Initialize_DoWork(_In_ PVMM_PROCESS pProcess, _In_ PVMM fail: LocalFree(pbModule); Ob_DECREF(pObStrMap); - return Ob_Alloc(OB_TAG_MAP_IAT, LMEM_ZEROINIT, sizeof(VMMOB_MAP_IAT), NULL, NULL); + return Ob_AllocEx(H, OB_TAG_MAP_IAT, LMEM_ZEROINIT, sizeof(VMMOB_MAP_IAT), NULL, NULL); } /* * Initialize IAT (imported functions) for a specific module. * CALLER DECREF: return +* -- H * -- pProcess * -- pModule * -- return */ -PVMMOB_MAP_IAT VmmWinIAT_Initialize(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_MODULEENTRY pModule) +PVMMOB_MAP_IAT VmmWinIAT_Initialize(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_MODULEENTRY pModule) { BOOL f; PVMMOB_MAP_IAT pObMap = NULL; QWORD qwKey = (pProcess->dwPID ^ ((QWORD)pProcess->dwPID << 48) ^ pModule->vaBase); - f = ctxVmm->pObCacheMapIAT || - (ctxVmm->pObCacheMapIAT = ObCacheMap_New(0x20, VmmWinEATIAT_Callback_ValidEntry, OB_CACHEMAP_FLAGS_OBJECT_OB)); + f = H->vmm.pObCacheMapIAT || + (H->vmm.pObCacheMapIAT = ObCacheMap_New(H, 0x20, VmmWinEATIAT_Callback_ValidEntry, OB_CACHEMAP_FLAGS_OBJECT_OB)); if(!f) { return NULL; } - if((pObMap = ObCacheMap_GetByKey(ctxVmm->pObCacheMapIAT, qwKey))) { return pObMap; } + if((pObMap = ObCacheMap_GetByKey(H->vmm.pObCacheMapIAT, qwKey))) { return pObMap; } EnterCriticalSection(&pProcess->LockUpdate); - pObMap = ObCacheMap_GetByKey(ctxVmm->pObCacheMapIAT, qwKey); - if(!pObMap && (pObMap = VmmWinIAT_Initialize_DoWork(pProcess, pModule))) { - ObCacheMap_Push(ctxVmm->pObCacheMapIAT, qwKey, pObMap, ctxVmm->tcRefreshMedium); + pObMap = ObCacheMap_GetByKey(H->vmm.pObCacheMapIAT, qwKey); + if(!pObMap && (pObMap = VmmWinIAT_Initialize_DoWork(H, pProcess, pModule))) { + ObCacheMap_Push(H->vmm.pObCacheMapIAT, qwKey, pObMap, H->vmm.tcRefreshMedium); } LeaveCriticalSection(&pProcess->LockUpdate); return pObMap; @@ -369,7 +373,7 @@ VOID VmmWinLdrModule_Initialize_VSetPutVA(_In_ POB_SET pObSet_vaAll, _In_ POB_SE } } -VOID VmmWinLdrModule_Initialize64(_In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP pmModules, _In_ BOOL fUserOnly) +VOID VmmWinLdrModule_Initialize64(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP pmModules, _In_ BOOL fUserOnly) { QWORD vaModuleLdrFirst64, vaModuleLdr64 = 0; BYTE pbPEB64[sizeof(PEB64)], pbPEBLdrData64[sizeof(PEB_LDR_DATA64)], pbLdrModule64[sizeof(LDR_MODULE64)]; @@ -382,17 +386,17 @@ VOID VmmWinLdrModule_Initialize64(_In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP pm DWORD i, cbReadData; // prefetch existing addresses (if any) & allocate new vaModuleLdr VSet pObSet_vaAll = ObContainer_GetOb(pProcess->pObPersistent->pObCLdrModulesPrefetch64); - VmmCachePrefetchPages3(pProcess, pObSet_vaAll, sizeof(LDR_MODULE64), 0); + VmmCachePrefetchPages3(H, pProcess, pObSet_vaAll, sizeof(LDR_MODULE64), 0); Ob_DECREF_NULL(&pObSet_vaAll); - if(!(pObSet_vaAll = ObSet_New())) { goto fail; } - if(!(pObSet_vaTry1 = ObSet_New())) { goto fail; } - if(!(pObSet_vaTry2 = ObSet_New())) { goto fail; } + if(!(pObSet_vaAll = ObSet_New(H))) { goto fail; } + if(!(pObSet_vaTry1 = ObSet_New(H))) { goto fail; } + if(!(pObSet_vaTry2 = ObSet_New(H))) { goto fail; } // set up initial entry in vaModuleLdr DataSet if(fUserOnly) { // User mode process -> walk PEB LDR list to enumerate modules / .dlls. if(!pProcess->win.vaPEB) { goto fail; } - if(!VmmRead(pProcess, pProcess->win.vaPEB, pbPEB64, sizeof(PEB64))) { goto fail; } - if(!VmmRead(pProcess, (QWORD)pPEB64->Ldr, pbPEBLdrData64, sizeof(PEB_LDR_DATA64))) { goto fail; } + if(!VmmRead(H, pProcess, pProcess->win.vaPEB, pbPEB64, sizeof(PEB64))) { goto fail; } + if(!VmmRead(H, pProcess, (QWORD)pPEB64->Ldr, pbPEBLdrData64, sizeof(PEB_LDR_DATA64))) { goto fail; } for(i = 0; i < 6; i++) { vaModuleLdrFirst64 = *(PQWORD)((PBYTE)&pPEBLdrData64->InLoadOrderModuleList + (5 - i) * sizeof(QWORD)); if(VMM_UADDR64_8(vaModuleLdrFirst64)) { @@ -402,26 +406,26 @@ VOID VmmWinLdrModule_Initialize64(_In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP pm } } else { // Kernel mode process -> walk PsLoadedModuleList to enumerate drivers / .sys and .dlls. - if(!ctxVmm->kernel.vaPsLoadedModuleListPtr) { goto fail; } - if(!VmmRead(pProcess, ctxVmm->kernel.vaPsLoadedModuleListPtr, (PBYTE)&vaModuleLdrFirst64, sizeof(QWORD)) || !vaModuleLdrFirst64) { goto fail; } - if(!VmmRead(pProcess, ctxVmm->kernel.vaPsLoadedModuleListPtr, pbPEBLdrData64, sizeof(PEB_LDR_DATA64))) { goto fail; } + if(!H->vmm.kernel.vaPsLoadedModuleListPtr) { goto fail; } + if(!VmmRead(H, pProcess, H->vmm.kernel.vaPsLoadedModuleListPtr, (PBYTE)&vaModuleLdrFirst64, sizeof(QWORD)) || !vaModuleLdrFirst64) { goto fail; } + if(!VmmRead(H, pProcess, H->vmm.kernel.vaPsLoadedModuleListPtr, pbPEBLdrData64, sizeof(PEB_LDR_DATA64))) { goto fail; } ObSet_Push(pObSet_vaAll, vaModuleLdrFirst64); ObSet_Push(pObSet_vaTry1, vaModuleLdrFirst64); } // iterate over modules using all available linked lists in an efficient way. fTry1 = TRUE; vaModuleLdr64 = 0; - VmmCachePrefetchPages3(pProcess, pObSet_vaTry1, sizeof(PEB_LDR_DATA64), 0); + VmmCachePrefetchPages3(H, pProcess, pObSet_vaTry1, sizeof(PEB_LDR_DATA64), 0); while(ObMap_Size(pmModules) < VMMPROCWINDOWS_MAX_MODULES) { if(fTry1) { vaModuleLdr64 = ObSet_Pop(pObSet_vaTry1); if(!vaModuleLdr64 && (0 == ObSet_Size(pObSet_vaTry2))) { break; } if(!vaModuleLdr64) { - VmmCachePrefetchPages3(pProcess, pObSet_vaAll, sizeof(PEB_LDR_DATA64), 0); + VmmCachePrefetchPages3(H, pProcess, pObSet_vaAll, sizeof(PEB_LDR_DATA64), 0); fTry1 = FALSE; continue; } - VmmReadEx(pProcess, vaModuleLdr64, pbLdrModule64, sizeof(LDR_MODULE64), &cbReadData, VMM_FLAG_FORCECACHE_READ); + VmmReadEx(H, pProcess, vaModuleLdr64, pbLdrModule64, sizeof(LDR_MODULE64), &cbReadData, VMM_FLAG_FORCECACHE_READ); if(cbReadData != sizeof(LDR_MODULE64)) { ObSet_Push(pObSet_vaTry2, vaModuleLdr64); continue; @@ -430,7 +434,7 @@ VOID VmmWinLdrModule_Initialize64(_In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP pm vaModuleLdr64 = ObSet_Pop(pObSet_vaTry2); if(!vaModuleLdr64 && (0 == ObSet_Size(pObSet_vaTry1))) { break; } if(!vaModuleLdr64) { fTry1 = TRUE; continue; } - if(!VmmRead(pProcess, vaModuleLdr64, pbLdrModule64, sizeof(LDR_MODULE64))) { continue; } + if(!VmmRead(H, pProcess, vaModuleLdr64, pbLdrModule64, sizeof(LDR_MODULE64))) { continue; } } if(!pLdrModule64->BaseAddress || (pLdrModule64->BaseAddress & 0xfff)) { continue; } if(!pLdrModule64->SizeOfImage || (pLdrModule64->SizeOfImage >= 0x40000000)) { continue; } @@ -471,7 +475,7 @@ VOID VmmWinLdrModule_Initialize64(_In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP pm } } // save prefetch addresses (if desirable) - if(ctxMain->dev.fVolatile && ctxVmm->ThreadProcCache.fEnabled) { + if(H->dev.fVolatile && H->vmm.ThreadProcCache.fEnabled) { ObContainer_SetOb(pProcess->pObPersistent->pObCLdrModulesPrefetch64, pObSet_vaAll); } fail: @@ -479,11 +483,11 @@ fail: Ob_DECREF(pObSet_vaTry1); Ob_DECREF(pObSet_vaTry2); if(!fUserOnly && pProcess->win.vaPEB) { - VmmWinLdrModule_Initialize64(pProcess, pmModules, TRUE); + VmmWinLdrModule_Initialize64(H, pProcess, pmModules, TRUE); } } -VOID VmmWinLdrModule_Initialize32(_In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP pmModules, _In_ BOOL fUserOnly) +VOID VmmWinLdrModule_Initialize32(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP pmModules, _In_ BOOL fUserOnly) { DWORD vaModuleLdrFirst32, vaModuleLdr32 = 0; BYTE pbPEB32[sizeof(PEB32)], pbPEBLdrData32[sizeof(PEB_LDR_DATA32)], pbLdrModule32[sizeof(LDR_MODULE32)]; @@ -496,16 +500,16 @@ VOID VmmWinLdrModule_Initialize32(_In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP pm DWORD i, cbReadData; // prefetch existing addresses (if any) & allocate new vaModuleLdr VSet pObSet_vaAll = ObContainer_GetOb(pProcess->pObPersistent->pObCLdrModulesPrefetch32); - VmmCachePrefetchPages3(pProcess, pObSet_vaAll, sizeof(LDR_MODULE32), 0); + VmmCachePrefetchPages3(H, pProcess, pObSet_vaAll, sizeof(LDR_MODULE32), 0); Ob_DECREF(pObSet_vaAll); - if(!(pObSet_vaAll = ObSet_New())) { goto fail; } - if(!(pObSet_vaTry1 = ObSet_New())) { goto fail; } - if(!(pObSet_vaTry2 = ObSet_New())) { goto fail; } + if(!(pObSet_vaAll = ObSet_New(H))) { goto fail; } + if(!(pObSet_vaTry1 = ObSet_New(H))) { goto fail; } + if(!(pObSet_vaTry2 = ObSet_New(H))) { goto fail; } // set up initial entry in vaModuleLdr DataSet if(fUserOnly) { if(!pProcess->win.vaPEB32) { goto fail; } - if(!VmmRead(pProcess, pProcess->win.vaPEB32, pbPEB32, sizeof(PEB32))) { goto fail; } - if(!VmmRead(pProcess, (QWORD)pPEB32->Ldr, pbPEBLdrData32, sizeof(PEB_LDR_DATA32))) { goto fail; } + if(!VmmRead(H, pProcess, pProcess->win.vaPEB32, pbPEB32, sizeof(PEB32))) { goto fail; } + if(!VmmRead(H, pProcess, (QWORD)pPEB32->Ldr, pbPEBLdrData32, sizeof(PEB_LDR_DATA32))) { goto fail; } for(i = 0; i < 6; i++) { vaModuleLdrFirst32 = *(PDWORD)((PBYTE)&pPEBLdrData32->InLoadOrderModuleList + (5 - i) * sizeof(DWORD)); if(VMM_UADDR32_4(vaModuleLdrFirst32)) { @@ -514,11 +518,11 @@ VOID VmmWinLdrModule_Initialize32(_In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP pm } } - } else if(ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X86) { + } else if(H->vmm.tpSystem == VMM_SYSTEM_WINDOWS_X86) { // Kernel mode process -> walk PsLoadedModuleList to enumerate drivers / .sys and .dlls. - if(!ctxVmm->kernel.vaPsLoadedModuleListPtr) { goto fail; } - if(!VmmRead(pProcess, ctxVmm->kernel.vaPsLoadedModuleListPtr, (PBYTE)&vaModuleLdrFirst32, sizeof(DWORD)) || !vaModuleLdrFirst32) { goto fail; } - if(!VmmRead(pProcess, ctxVmm->kernel.vaPsLoadedModuleListPtr, pbPEBLdrData32, sizeof(PEB_LDR_DATA32))) { goto fail; } + if(!H->vmm.kernel.vaPsLoadedModuleListPtr) { goto fail; } + if(!VmmRead(H, pProcess, H->vmm.kernel.vaPsLoadedModuleListPtr, (PBYTE)&vaModuleLdrFirst32, sizeof(DWORD)) || !vaModuleLdrFirst32) { goto fail; } + if(!VmmRead(H, pProcess, H->vmm.kernel.vaPsLoadedModuleListPtr, pbPEBLdrData32, sizeof(PEB_LDR_DATA32))) { goto fail; } ObSet_Push(pObSet_vaAll, vaModuleLdrFirst32); ObSet_Push(pObSet_vaTry1, vaModuleLdrFirst32); } else { @@ -527,17 +531,17 @@ VOID VmmWinLdrModule_Initialize32(_In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP pm // iterate over modules using all available linked lists in an efficient way. fTry1 = TRUE; vaModuleLdr32 = 0; - VmmCachePrefetchPages3(pProcess, pObSet_vaTry1, sizeof(PEB_LDR_DATA32), 0); + VmmCachePrefetchPages3(H, pProcess, pObSet_vaTry1, sizeof(PEB_LDR_DATA32), 0); while(ObMap_Size(pmModules) < VMMPROCWINDOWS_MAX_MODULES) { if(fTry1) { vaModuleLdr32 = (DWORD)ObSet_Pop(pObSet_vaTry1); if(!vaModuleLdr32 && (0 == ObSet_Size(pObSet_vaTry2))) { break; } if(!vaModuleLdr32) { - VmmCachePrefetchPages3(pProcess, pObSet_vaAll, sizeof(PEB_LDR_DATA32), 0); + VmmCachePrefetchPages3(H, pProcess, pObSet_vaAll, sizeof(PEB_LDR_DATA32), 0); fTry1 = FALSE; continue; } - VmmReadEx(pProcess, vaModuleLdr32, pbLdrModule32, sizeof(LDR_MODULE32), &cbReadData, VMM_FLAG_FORCECACHE_READ); + VmmReadEx(H, pProcess, vaModuleLdr32, pbLdrModule32, sizeof(LDR_MODULE32), &cbReadData, VMM_FLAG_FORCECACHE_READ); if(cbReadData != sizeof(LDR_MODULE64)) { ObSet_Push(pObSet_vaTry2, vaModuleLdr32); continue; @@ -546,7 +550,7 @@ VOID VmmWinLdrModule_Initialize32(_In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP pm vaModuleLdr32 = (DWORD)ObSet_Pop(pObSet_vaTry2); if(!vaModuleLdr32 && (0 == ObSet_Size(pObSet_vaTry1))) { break; } if(!vaModuleLdr32) { fTry1 = TRUE; continue; } - if(!VmmRead(pProcess, vaModuleLdr32, pbLdrModule32, sizeof(LDR_MODULE32))) { continue; } + if(!VmmRead(H, pProcess, vaModuleLdr32, pbLdrModule32, sizeof(LDR_MODULE32))) { continue; } } if(!pLdrModule32->BaseAddress || (pLdrModule32->BaseAddress & 0xfff)) { continue; } if(!pLdrModule32->SizeOfImage || (pLdrModule32->SizeOfImage >= 0x10000000)) { continue; } @@ -587,7 +591,7 @@ VOID VmmWinLdrModule_Initialize32(_In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP pm } } // save prefetch addresses (if desirable) - if(ctxMain->dev.fVolatile && ctxVmm->ThreadProcCache.fEnabled) { + if(H->dev.fVolatile && H->vmm.ThreadProcCache.fEnabled) { ObContainer_SetOb(pProcess->pObPersistent->pObCLdrModulesPrefetch64, pObSet_vaAll); } fail: @@ -595,11 +599,11 @@ fail: Ob_DECREF(pObSet_vaTry1); Ob_DECREF(pObSet_vaTry2); if(!fUserOnly && pProcess->win.vaPEB) { - VmmWinLdrModule_Initialize32(pProcess, pmModules, TRUE); + VmmWinLdrModule_Initialize32(H, pProcess, pmModules, TRUE); } } -VOID VmmWinLdrModule_InitializeVAD(_In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP pmModules) +VOID VmmWinLdrModule_InitializeVAD(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP pmModules) { BOOL fX; DWORD iVad, iPte = 0; @@ -608,19 +612,19 @@ VOID VmmWinLdrModule_InitializeVAD(_In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP p PVMMOB_MAP_VAD pObVadMap = NULL; VMM_MAP_MODULEENTRY oModule; if(!pProcess->fUserOnly) { return; } - if(!VmmMap_GetVad(pProcess, &pObVadMap, VMM_VADMAP_TP_PARTIAL)) { return; } + if(!VmmMap_GetVad(H, pProcess, &pObVadMap, VMM_VADMAP_TP_PARTIAL)) { return; } for(iVad = 0; iVad < pObVadMap->cMap; iVad++) { peVad = pObVadMap->pMap + iVad; if(!peVad->fImage) { continue; } if(ObMap_ExistsKey(pmModules, peVad->vaStart)) { continue; } ZeroMemory(&oModule, sizeof(VMM_MAP_MODULEENTRY)); oModule.vaBase = peVad->vaStart; - oModule.cbImageSize = (DWORD)PE_GetSize(pProcess, oModule.vaBase); + oModule.cbImageSize = (DWORD)PE_GetSize(H, pProcess, oModule.vaBase); if(!oModule.cbImageSize || (oModule.cbImageSize > 0x04000000)) { continue; } oModule.fWoW64 = pProcess->win.fWow64 && (oModule.vaBase < 0xffffffff); // image vad not already in map found; check if pte map contains hw // executable pte's -> assume unlinked module, otherwise assume data. - if(!pObPteMap && !VmmMap_GetPte(pProcess, &pObPteMap, FALSE)) { goto fail; } + if(!pObPteMap && !VmmMap_GetPte(H, pProcess, &pObPteMap, FALSE)) { goto fail; } // move pte index to current vad while((iPte < pObPteMap->cMap) && (pObPteMap->pMap[iPte].vaBase + (pObPteMap->pMap[iPte].cPages << 12) <= peVad->vaStart)) { iPte++; @@ -640,11 +644,11 @@ fail: } _Success_(return) -BOOL VmmWinLdrModule_InitializeInjectedEntry(_In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP pmModules, _In_ QWORD vaModuleBase) +BOOL VmmWinLdrModule_InitializeInjectedEntry(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP pmModules, _In_ QWORD vaModuleBase) { QWORD cbImageSize; VMM_MAP_MODULEENTRY oModule = { 0 }; - cbImageSize = PE_GetSize(pProcess, vaModuleBase); + cbImageSize = PE_GetSize(H, pProcess, vaModuleBase); if(ObMap_ExistsKey(pmModules, vaModuleBase)) { return FALSE; } if(!cbImageSize || cbImageSize > 0x04000000) { return FALSE; } oModule.vaBase = vaModuleBase; @@ -654,7 +658,7 @@ BOOL VmmWinLdrModule_InitializeInjectedEntry(_In_ PVMM_PROCESS pProcess, _Inout_ return ObMap_PushCopy(pmModules, oModule.vaBase, &oModule, sizeof(VMM_MAP_MODULEENTRY)); } -VOID VmmWinLdrModule_InitializeInjected(_In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP pmModules, _Inout_opt_ POB_SET psvaInjected) +VOID VmmWinLdrModule_InitializeInjected(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Inout_ POB_MAP pmModules, _Inout_opt_ POB_SET psvaInjected) { DWORD i; QWORD va; @@ -662,7 +666,7 @@ VOID VmmWinLdrModule_InitializeInjected(_In_ PVMM_PROCESS pProcess, _Inout_ POB_ POB_DATA pvaObDataInjected = NULL; BOOL fObAlloc_psvaInjected; if(!psvaInjected && !ObContainer_Exists(pProcess->pObPersistent->pObCLdrModulesInjected)) { return; } - fObAlloc_psvaInjected = !psvaInjected && (psvaInjected = ObSet_New()); + fObAlloc_psvaInjected = !psvaInjected && (psvaInjected = ObSet_New(H)); // merge previously saved injected modules into 'psvaInjected' address set if((pvaObDataInjected = ObContainer_GetOb(pProcess->pObPersistent->pObCLdrModulesInjected))) { ObSet_PushData(psvaInjected, pvaObDataInjected); @@ -670,11 +674,11 @@ VOID VmmWinLdrModule_InitializeInjected(_In_ PVMM_PROCESS pProcess, _Inout_ POB_ } // add injected modules module map if(ObSet_Size(psvaInjected)) { - if(!VmmMap_GetVad(pProcess, &pObVadMap, VMM_VADMAP_TP_FULL)) { goto fail; } + if(!VmmMap_GetVad(H, pProcess, &pObVadMap, VMM_VADMAP_TP_FULL)) { goto fail; } i = 0; while(i < ObSet_Size(psvaInjected)) { va = ObSet_Get(psvaInjected, i); - if(!VmmWinLdrModule_InitializeInjectedEntry(pProcess, pmModules, va)) { + if(!VmmWinLdrModule_InitializeInjectedEntry(H, pProcess, pmModules, va)) { ObSet_Remove(psvaInjected, va); } else { i++; @@ -696,7 +700,7 @@ fail: } _Success_(return) -BOOL VmmWinLdrModule_Initialize_Name(_In_ PVMM_PROCESS pProcess, _Inout_ PVMMOB_MAP_MODULE pModuleMap) +BOOL VmmWinLdrModule_Initialize_Name(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Inout_ PVMMOB_MAP_MODULE pModuleMap) { BOOL fWow64 = pProcess->win.fWow64; DWORD i; @@ -705,16 +709,16 @@ BOOL VmmWinLdrModule_Initialize_Name(_In_ PVMM_PROCESS pProcess, _Inout_ PVMMOB_ POB_STRMAP psmOb = NULL; LPSTR uszPrefix; CHAR uszName[MAX_PATH], uszFullName[MAX_PATH], szNamePE[MAX_PATH]; - if(!(psmOb = ObStrMap_New(OB_STRMAP_FLAGS_CASE_INSENSITIVE))) { return FALSE; } + if(!(psmOb = ObStrMap_New(H, OB_STRMAP_FLAGS_CASE_INSENSITIVE))) { return FALSE; } // 1: prefetch - psObPrefetch = ObSet_New(); + psObPrefetch = ObSet_New(H); for(i = 0; i < pModuleMap->cMap; i++) { pe = pModuleMap->pMap + i; ObSet_Push_PageAlign(psObPrefetch, pe->vaBase, 0x1000); ObSet_Push_PageAlign(psObPrefetch, pe->_Reserved1, MAX_PATH * 2); ObSet_Push_PageAlign(psObPrefetch, pe->_Reserved3, MAX_PATH * 2); } - VmmCachePrefetchPages(pProcess, psObPrefetch, 0); + VmmCachePrefetchPages(H, pProcess, psObPrefetch, 0); // 2: iterate over entries for(i = 0; i < pModuleMap->cMap; i++) { pe = pModuleMap->pMap + i; @@ -723,17 +727,17 @@ BOOL VmmWinLdrModule_Initialize_Name(_In_ PVMM_PROCESS pProcess, _Inout_ PVMMOB_ uszPrefix = ""; // name from ldr list if(pe->_Reserved1) { - VmmReadWtoU(pProcess, pe->_Reserved1, min(pe->cbuText, 2 * MAX_PATH), VMM_FLAG_FORCECACHE_READ, uszName, sizeof(uszName), NULL, NULL, CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR | CHARUTIL_FLAG_STR_BUFONLY); + VmmReadWtoU(H, pProcess, pe->_Reserved1, min(pe->cbuText, 2 * MAX_PATH), VMM_FLAG_FORCECACHE_READ, uszName, sizeof(uszName), NULL, NULL, CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR | CHARUTIL_FLAG_STR_BUFONLY); CharUtil_FixFsNameU(uszName, sizeof(uszName), uszName, 0, FALSE); pe->_Reserved1 = 0; } // fullname from ldr list if(pe->_Reserved3) { - VmmReadWtoU(pProcess, pe->_Reserved3, min(pe->cbuFullName, 2 * MAX_PATH), VMM_FLAG_FORCECACHE_READ, uszFullName, sizeof(uszFullName), NULL, NULL, CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR | CHARUTIL_FLAG_STR_BUFONLY); + VmmReadWtoU(H, pProcess, pe->_Reserved3, min(pe->cbuFullName, 2 * MAX_PATH), VMM_FLAG_FORCECACHE_READ, uszFullName, sizeof(uszFullName), NULL, NULL, CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR | CHARUTIL_FLAG_STR_BUFONLY); pe->_Reserved3 = 0; } // name from pe embedded - if(!uszName[0] && PE_GetModuleName(pProcess, pe->vaBase, szNamePE, MAX_PATH)) { + if(!uszName[0] && PE_GetModuleName(H, pProcess, pe->vaBase, szNamePE, MAX_PATH)) { CharUtil_FixFsName(uszName, sizeof(uszName), NULL, szNamePE, NULL, MAX_PATH, 0, FALSE); } // name from VAD not feasible due to deadlock risk when initializing VAD names. @@ -766,31 +770,31 @@ VOID VmmWinLdrModule_Initialize_SetHash(_In_ PVMM_PROCESS pProcess, _Inout_ PVMM qsort(pModuleMap->pHashTableLookup, pModuleMap->cMap, sizeof(QWORD), (int(*)(const void*, const void*))VmmWin_HashTableLookup_CmpSort); } -VOID VmmWinLdrModule_Initialize_SetSize(_In_ PVMM_PROCESS pProcess, _Inout_ PVMMOB_MAP_MODULE pModuleMap) +VOID VmmWinLdrModule_Initialize_SetSize(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Inout_ PVMMOB_MAP_MODULE pModuleMap) { DWORD i; BYTE pbModuleHeader[0x1000]; PVMM_MAP_MODULEENTRY pe; POB_SET psObPrefetch = NULL; // prefetch MZ header - if(!(psObPrefetch = ObSet_New())) { return; } + if(!(psObPrefetch = ObSet_New(H))) { return; } for(i = 0; i < pModuleMap->cMap; i++) { ObSet_Push(psObPrefetch, pModuleMap->pMap[i].vaBase); } // fetch size values from cache loaded nt header. - VmmCachePrefetchPages(pProcess, psObPrefetch, 0); ObSet_Clear(psObPrefetch); + VmmCachePrefetchPages(H, pProcess, psObPrefetch, 0); ObSet_Clear(psObPrefetch); for(i = 0; i < pModuleMap->cMap; i++) { pe = pModuleMap->pMap + i; - if(!VmmRead2(pProcess, pe->vaBase, pbModuleHeader, 0x1000, VMM_FLAG_FORCECACHE_READ)) { continue; } - pe->cbFileSizeRaw = PE_FileRaw_Size(pProcess, 0, pbModuleHeader); - pe->cSection = PE_SectionGetNumberOfEx(pProcess, 0, pbModuleHeader); - pe->cIAT = PE_IatGetNumberOfEx(pProcess, 0, pbModuleHeader); - ObSet_Push_PageAlign(psObPrefetch, pe->vaBase + PE_DirectoryGetOffset(pProcess, 0, pbModuleHeader, IMAGE_DIRECTORY_ENTRY_EXPORT), sizeof(IMAGE_EXPORT_DIRECTORY)); + if(!VmmRead2(H, pProcess, pe->vaBase, pbModuleHeader, 0x1000, VMM_FLAG_FORCECACHE_READ)) { continue; } + pe->cbFileSizeRaw = PE_FileRaw_Size(H, pProcess, 0, pbModuleHeader); + pe->cSection = PE_SectionGetNumberOfEx(H, pProcess, 0, pbModuleHeader); + pe->cIAT = PE_IatGetNumberOfEx(H, pProcess, 0, pbModuleHeader); + ObSet_Push_PageAlign(psObPrefetch, pe->vaBase + PE_DirectoryGetOffset(H, pProcess, 0, pbModuleHeader, IMAGE_DIRECTORY_ENTRY_EXPORT), sizeof(IMAGE_EXPORT_DIRECTORY)); } // fetch number of exports (EAT) - VmmCachePrefetchPages(pProcess, psObPrefetch, 0); + VmmCachePrefetchPages(H, pProcess, psObPrefetch, 0); for(i = 0; i < pModuleMap->cMap; i++) { - pModuleMap->pMap[i].cEAT = PE_EatGetNumberOfEx(pProcess, pModuleMap->pMap[i].vaBase, NULL); + pModuleMap->pMap[i].cEAT = PE_EatGetNumberOfEx(H, pProcess, pModuleMap->pMap[i].vaBase, NULL); } Ob_DECREF(psObPrefetch); } @@ -809,7 +813,7 @@ VOID VmmWinLdrModule_CallbackCleanup_ObMapModule(PVMMOB_MAP_MODULE pOb) * -- return */ _Success_(return) -BOOL VmmWinLdrModule_Initialize(_In_ PVMM_PROCESS pProcess, _Inout_opt_ POB_SET psvaInjected) +BOOL VmmWinLdrModule_Initialize(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Inout_opt_ POB_SET psvaInjected) { PVMM_MAP_MODULEENTRY pe; POB_MAP pmObModules = NULL; @@ -817,26 +821,26 @@ BOOL VmmWinLdrModule_Initialize(_In_ PVMM_PROCESS pProcess, _Inout_opt_ POB_SET DWORD i, cModules, cbObMap; // check if already initialized -> skip if(pProcess->Map.pObModule && (!psvaInjected || !ObSet_Size(psvaInjected))) { return TRUE; } - VmmTlbSpider(pProcess); + VmmTlbSpider(H, pProcess); EnterCriticalSection(&pProcess->LockUpdate); if(pProcess->Map.pObModule && (!psvaInjected || !ObSet_Size(psvaInjected))) { goto fail; } // not strict fail - but triggr cleanup and success. // set up context - if(!(pmObModules = ObMap_New(OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } + if(!(pmObModules = ObMap_New(H, OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } // fetch modules: "ordinary" linked list - if((ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X86) || ((ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X64) && pProcess->win.fWow64)) { - VmmWinLdrModule_Initialize32(pProcess, pmObModules, pProcess->fUserOnly); + if((H->vmm.tpSystem == VMM_SYSTEM_WINDOWS_X86) || ((H->vmm.tpSystem == VMM_SYSTEM_WINDOWS_X64) && pProcess->win.fWow64)) { + VmmWinLdrModule_Initialize32(H, pProcess, pmObModules, pProcess->fUserOnly); } - if(ctxVmm->tpSystem == VMM_SYSTEM_WINDOWS_X64) { - VmmWinLdrModule_Initialize64(pProcess, pmObModules, pProcess->fUserOnly); + if(H->vmm.tpSystem == VMM_SYSTEM_WINDOWS_X64) { + VmmWinLdrModule_Initialize64(H, pProcess, pmObModules, pProcess->fUserOnly); } // fetch modules: VADs - VmmWinLdrModule_InitializeVAD(pProcess, pmObModules); + VmmWinLdrModule_InitializeVAD(H, pProcess, pmObModules); // fetch modules: optional injected - VmmWinLdrModule_InitializeInjected(pProcess, pmObModules, psvaInjected); + VmmWinLdrModule_InitializeInjected(H, pProcess, pmObModules, psvaInjected); // set up module map object cModules = ObMap_Size(pmObModules); cbObMap = sizeof(VMMOB_MAP_MODULE) + cModules * (sizeof(VMM_MAP_MODULEENTRY) + sizeof(QWORD)); - if(!(pObMap = Ob_Alloc(OB_TAG_MAP_MODULE, LMEM_ZEROINIT, cbObMap, (OB_CLEANUP_CB)VmmWinLdrModule_CallbackCleanup_ObMapModule, NULL))) { goto fail; } + if(!(pObMap = Ob_AllocEx(H, OB_TAG_MAP_MODULE, LMEM_ZEROINIT, cbObMap, (OB_CLEANUP_CB)VmmWinLdrModule_CallbackCleanup_ObMapModule, NULL))) { goto fail; } pObMap->pHashTableLookup = (PQWORD)(((PBYTE)pObMap) + sizeof(VMMOB_MAP_MODULE) + cModules * sizeof(VMM_MAP_MODULEENTRY)); pObMap->cMap = cModules; for(i = 0; i < cModules; i++) { @@ -848,9 +852,9 @@ BOOL VmmWinLdrModule_Initialize(_In_ PVMM_PROCESS pProcess, _Inout_opt_ POB_SET qsort(pObMap->pMap + 1, pObMap->cMap - 1, sizeof(VMM_MAP_MODULEENTRY), Util_qsort_QWORD); } // fetch module names - if(!VmmWinLdrModule_Initialize_Name(pProcess, pObMap)) { goto fail; } + if(!VmmWinLdrModule_Initialize_Name(H, pProcess, pObMap)) { goto fail; } // fetch raw file size, #sections, imports (IAT) and exports (EAT) - VmmWinLdrModule_Initialize_SetSize(pProcess, pObMap); + VmmWinLdrModule_Initialize_SetSize(H, pProcess, pObMap); // set name hash table VmmWinLdrModule_Initialize_SetHash(pProcess, pObMap); // finish set-up @@ -859,7 +863,7 @@ BOOL VmmWinLdrModule_Initialize(_In_ PVMM_PROCESS pProcess, _Inout_opt_ POB_SET fail: if(!pProcess->Map.pObModule) { // try set up zero-sized module map on fail - pObMap = Ob_Alloc(OB_TAG_MAP_MODULE, LMEM_ZEROINIT, sizeof(VMMOB_MAP_MODULE), NULL, NULL); + pObMap = Ob_AllocEx(H, OB_TAG_MAP_MODULE, LMEM_ZEROINIT, sizeof(VMMOB_MAP_MODULE), NULL, NULL); pProcess->Map.pObModule = pObMap; } LeaveCriticalSection(&pProcess->LockUpdate); @@ -880,7 +884,7 @@ VOID VmmWinUnloadedModule_CallbackCleanup_ObMapUnloadedModule(PVMMOB_MAP_UNLOADE LocalFree(pOb->pbMultiText); } -QWORD VmmWinUnloadedModule_vaNtdllUnloadedArray(_In_ PVMM_PROCESS pProcess, _In_ BOOL f32) +QWORD VmmWinUnloadedModule_vaNtdllUnloadedArray(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ BOOL f32) { BYTE pb[8]; PDB_HANDLE hPDB; @@ -888,33 +892,33 @@ QWORD VmmWinUnloadedModule_vaNtdllUnloadedArray(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_MODULEENTRY peModule; PVMMOB_MAP_MODULE pObModuleMap = NULL; // 1: fetch cached - vaUnloadedArray = f32 ? ctxVmm->ContextUnloadedModule.vaNtdll32 : ctxVmm->ContextUnloadedModule.vaNtdll64; + vaUnloadedArray = f32 ? H->vmm.ContextUnloadedModule.vaNtdll32 : H->vmm.ContextUnloadedModule.vaNtdll64; if((DWORD)vaUnloadedArray == (DWORD)-1) { return 0; } if(vaUnloadedArray) { return vaUnloadedArray; } // 2: fetch ntdll module - if(!VmmMap_GetModuleEntryEx(pProcess, 0, "ntdll.dll", &pObModuleMap, &peModule)) { goto fail; } + if(!VmmMap_GetModuleEntryEx(H, pProcess, 0, "ntdll.dll", &pObModuleMap, &peModule)) { goto fail; } // 2.1: try fetch addr RtlpUnloadEventTrace from dism of RtlGetUnloadEventTrace export - if((va = PE_GetProcAddress(pProcess, peModule->vaBase, "RtlGetUnloadEventTrace")) && VmmRead(pProcess, va, pb, 8)) { + if((va = PE_GetProcAddress(H, pProcess, peModule->vaBase, "RtlGetUnloadEventTrace")) && VmmRead(H, pProcess, va, pb, 8)) { if(f32 && (pb[0] == 0xb8) && (pb[5] == 0xc3)) { // x86 dism vaUnloadedArray = *(PDWORD)(pb + 1); } if(!f32 && (pb[0] == 0x48) && (pb[1] == 0x8d) && (pb[2] == 0x05) && (pb[7] == 0xc3)) { // x64 dism va += 7ULL + *(PDWORD)(pb + 3); - if(VmmRead(pProcess, va, pb, 8)) { + if(VmmRead(H, pProcess, va, pb, 8)) { vaUnloadedArray = va; } } } // 2.2: try fetch addr ntdll!RtlpUnloadEventTrace from PDB if(!vaUnloadedArray) { - hPDB = PDB_GetHandleFromModuleAddress(pProcess, peModule->vaBase); - PDB_GetSymbolAddress(hPDB, "RtlpUnloadEventTrace", &vaUnloadedArray); + hPDB = PDB_GetHandleFromModuleAddress(H, pProcess, peModule->vaBase); + PDB_GetSymbolAddress(H, hPDB, "RtlpUnloadEventTrace", &vaUnloadedArray); } // 3: commit to cache if(f32) { - ctxVmm->ContextUnloadedModule.vaNtdll32 = vaUnloadedArray ? (DWORD)vaUnloadedArray : (DWORD)-1; + H->vmm.ContextUnloadedModule.vaNtdll32 = vaUnloadedArray ? (DWORD)vaUnloadedArray : (DWORD)-1; } else { - ctxVmm->ContextUnloadedModule.vaNtdll64 = vaUnloadedArray ? vaUnloadedArray : (QWORD)-1; + H->vmm.ContextUnloadedModule.vaNtdll64 = vaUnloadedArray ? vaUnloadedArray : (QWORD)-1; } fail: Ob_DECREF(pObModuleMap); @@ -926,9 +930,10 @@ fail: * by parsing the array RtlpUnloadEventTrace in ntdll.dll. The array location is * retrieved by (1) parsing exports or (2) loading symbol from ntdll.dll PDB. */ -VOID VmmWinUnloadedModule_InitializeUser(_In_ PVMM_PROCESS pProcess) +VOID VmmWinUnloadedModule_InitializeUser(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess) { - BOOL f32 = ctxVmm->f32 || pProcess->win.fWow64; + BOOL f32 = (H->vmm.f32 || pProcess->win.fWow64); + DWORD dwVersionBuild = H->vmm.kernel.dwVersionBuild; BYTE pbBuffer[RTL_UNLOAD_EVENT_TRACE_NUMBER * 0x68] = { 0 }; QWORD cbStruct, vaUnloadedArray; DWORD i, cbBuffer, cMap; @@ -938,13 +943,13 @@ VOID VmmWinUnloadedModule_InitializeUser(_In_ PVMM_PROCESS pProcess) PVMMOB_MAP_UNLOADEDMODULE pObMap = NULL; POB_STRMAP psmOb = NULL; // 1: fetch unloaded modules array - if(!(vaUnloadedArray = VmmWinUnloadedModule_vaNtdllUnloadedArray(pProcess, f32))) { return; } + if(!(vaUnloadedArray = VmmWinUnloadedModule_vaNtdllUnloadedArray(H, pProcess, f32))) { return; } cbBuffer = RTL_UNLOAD_EVENT_TRACE_NUMBER * (f32 ? sizeof(RTL_UNLOAD_EVENT_TRACE32) : sizeof(RTL_UNLOAD_EVENT_TRACE64)); - VmmRead2(pProcess, vaUnloadedArray, pbBuffer, cbBuffer, VMM_FLAG_ZEROPAD_ON_FAIL); + VmmRead2(H, pProcess, vaUnloadedArray, pbBuffer, cbBuffer, VMM_FLAG_ZEROPAD_ON_FAIL); // 2: parse data and count if(f32) { cbStruct = 0x5c; - if(ctxVmm->kernel.dwVersionBuild <= 6002) { cbStruct = 0x54; } // <= VISTA SP2 + if(dwVersionBuild <= 6002) { cbStruct = 0x54; } // <= VISTA SP2 for(cMap = 0; cMap < RTL_UNLOAD_EVENT_TRACE_NUMBER; cMap++) { pe32 = (PRTL_UNLOAD_EVENT_TRACE32)(pbBuffer + cMap * cbStruct); if(!VMM_UADDR32_PAGE(pe32->BaseAddress)) { break; } @@ -953,7 +958,7 @@ VOID VmmWinUnloadedModule_InitializeUser(_In_ PVMM_PROCESS pProcess) } } else { cbStruct = 0x68; - if(ctxVmm->kernel.dwVersionBuild <= 6002) { cbStruct = 0x60; } // <= VISTA SP2 + if(dwVersionBuild <= 6002) { cbStruct = 0x60; } // <= VISTA SP2 for(cMap = 0; cMap < RTL_UNLOAD_EVENT_TRACE_NUMBER; cMap++) { pe64 = (PRTL_UNLOAD_EVENT_TRACE64)(pbBuffer + cMap * cbStruct); if(!VMM_UADDR64_PAGE(pe64->BaseAddress)) { break; } @@ -962,8 +967,8 @@ VOID VmmWinUnloadedModule_InitializeUser(_In_ PVMM_PROCESS pProcess) } } // 3: alloc and fill - if(!(psmOb = ObStrMap_New(0))) { return; } - pObMap = Ob_Alloc(OB_TAG_MAP_UNLOADEDMODULE, LMEM_ZEROINIT, sizeof(VMMOB_MAP_UNLOADEDMODULE) + cMap * sizeof(VMM_MAP_UNLOADEDMODULEENTRY), (OB_CLEANUP_CB)VmmWinUnloadedModule_CallbackCleanup_ObMapUnloadedModule, NULL); + if(!(psmOb = ObStrMap_New(H, 0))) { return; } + pObMap = Ob_AllocEx(H, OB_TAG_MAP_UNLOADEDMODULE, LMEM_ZEROINIT, sizeof(VMMOB_MAP_UNLOADEDMODULE) + cMap * sizeof(VMM_MAP_UNLOADEDMODULEENTRY), (OB_CLEANUP_CB)VmmWinUnloadedModule_CallbackCleanup_ObMapUnloadedModule, NULL); if(!pObMap) { Ob_DECREF(psmOb); return; @@ -1000,9 +1005,9 @@ VOID VmmWinUnloadedModule_InitializeUser(_In_ PVMM_PROCESS pProcess) * MmUnloadedDrivers and MmLastUnloadedDriver. This function requires a valid PDB * for the kernel to properly function. */ -VOID VmmWinUnloadedModule_InitializeKernel(_In_ PVMM_PROCESS pProcess) +VOID VmmWinUnloadedModule_InitializeKernel(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess) { - BOOL f, f32 = ctxVmm->f32; + BOOL f, f32 = H->vmm.f32; QWORD i, j, va = 0; DWORD cMap = 0, cUnloadMax, cbStruct, cbMultiText = 2, owszMultiText = 1; PMM_UNLOADED_DRIVER32 pe32; @@ -1011,13 +1016,13 @@ VOID VmmWinUnloadedModule_InitializeKernel(_In_ PVMM_PROCESS pProcess) PVMMOB_MAP_UNLOADEDMODULE pObMap = NULL; POB_STRMAP psmOb = NULL; BYTE pbBuffer[MM_UNLOADED_DRIVER_MAX * sizeof(MM_UNLOADED_DRIVER64)] = { 0 }; - if(!ctxVmm->kernel.opt.vaMmUnloadedDrivers || !ctxVmm->kernel.opt.vaMmLastUnloadedDriver) { return; } + if(!H->vmm.kernel.opt.vaMmUnloadedDrivers || !H->vmm.kernel.opt.vaMmLastUnloadedDriver) { return; } // 1: fetch data cbStruct = f32 ? sizeof(MM_UNLOADED_DRIVER32) : sizeof(MM_UNLOADED_DRIVER64); - if(!VmmRead(pProcess, ctxVmm->kernel.opt.vaMmUnloadedDrivers, (PBYTE)&va, f32 ? sizeof(DWORD) : sizeof(QWORD))) { return; } - if(!VmmRead(pProcess, ctxVmm->kernel.opt.vaMmLastUnloadedDriver, (PBYTE)&cUnloadMax, sizeof(DWORD))) { return; } - if(!VMM_KADDR_4_8(va) || !cUnloadMax || (cUnloadMax > MM_UNLOADED_DRIVER_MAX)) { return; } - if(!VmmRead(pProcess, va, pbBuffer, cUnloadMax * cbStruct)) { return; } + if(!VmmRead(H, pProcess, H->vmm.kernel.opt.vaMmUnloadedDrivers, (PBYTE)&va, f32 ? sizeof(DWORD) : sizeof(QWORD))) { return; } + if(!VmmRead(H, pProcess, H->vmm.kernel.opt.vaMmLastUnloadedDriver, (PBYTE)&cUnloadMax, sizeof(DWORD))) { return; } + if(!VMM_KADDR_4_8(f32, va) || !cUnloadMax || (cUnloadMax > MM_UNLOADED_DRIVER_MAX)) { return; } + if(!VmmRead(H, pProcess, va, pbBuffer, cUnloadMax * cbStruct)) { return; } // 2: parse data and count for(i = 0; i < cUnloadMax; i++) { if(f32) { @@ -1043,8 +1048,8 @@ VOID VmmWinUnloadedModule_InitializeKernel(_In_ PVMM_PROCESS pProcess) } } // 3: alloc and fill - if(!(psmOb = ObStrMap_New(0))) { return; } - pObMap = Ob_Alloc(OB_TAG_MAP_UNLOADEDMODULE, LMEM_ZEROINIT, sizeof(VMMOB_MAP_UNLOADEDMODULE) + cMap * sizeof(VMM_MAP_UNLOADEDMODULEENTRY), (OB_CLEANUP_CB)VmmWinUnloadedModule_CallbackCleanup_ObMapUnloadedModule, NULL); + if(!(psmOb = ObStrMap_New(H, 0))) { return; } + pObMap = Ob_AllocEx(H, OB_TAG_MAP_UNLOADEDMODULE, LMEM_ZEROINIT, sizeof(VMMOB_MAP_UNLOADEDMODULE) + cMap * sizeof(VMM_MAP_UNLOADEDMODULEENTRY), (OB_CLEANUP_CB)VmmWinUnloadedModule_CallbackCleanup_ObMapUnloadedModule, NULL); if(!pObMap) { Ob_DECREF(psmOb); return; @@ -1075,23 +1080,24 @@ VOID VmmWinUnloadedModule_InitializeKernel(_In_ PVMM_PROCESS pProcess) /* * Initialize the unloaded module map containing information about unloaded modules. +* -- H * -- pProcess * -- return */ _Success_(return) -BOOL VmmWinUnloadedModule_Initialize(_In_ PVMM_PROCESS pProcess) +BOOL VmmWinUnloadedModule_Initialize(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess) { if(pProcess->Map.pObUnloadedModule) { return TRUE; } EnterCriticalSection(&pProcess->LockUpdate); if(!pProcess->Map.pObUnloadedModule) { if(pProcess->fUserOnly) { - VmmWinUnloadedModule_InitializeUser(pProcess); + VmmWinUnloadedModule_InitializeUser(H, pProcess); } else { - VmmWinUnloadedModule_InitializeKernel(pProcess); + VmmWinUnloadedModule_InitializeKernel(H, pProcess); } } if(!pProcess->Map.pObUnloadedModule) { - pProcess->Map.pObUnloadedModule = Ob_Alloc(OB_TAG_MAP_UNLOADEDMODULE, LMEM_ZEROINIT, sizeof(VMMOB_MAP_UNLOADEDMODULE), NULL, NULL); + pProcess->Map.pObUnloadedModule = Ob_AllocEx(H, OB_TAG_MAP_UNLOADEDMODULE, LMEM_ZEROINIT, sizeof(VMMOB_MAP_UNLOADEDMODULE), NULL, NULL); } LeaveCriticalSection(&pProcess->LockUpdate); return pProcess->Map.pObUnloadedModule ? TRUE : FALSE; @@ -1103,9 +1109,9 @@ BOOL VmmWinUnloadedModule_Initialize(_In_ PVMM_PROCESS pProcess) // USER PROCESS PARAMETERS FUNCTIONALITY BELOW: // ---------------------------------------------------------------------------- -PVMMWIN_USER_PROCESS_PARAMETERS VmmWin_UserProcessParameters_Get(_In_ PVMM_PROCESS pProcess) +PVMMWIN_USER_PROCESS_PARAMETERS VmmWin_UserProcessParameters_Get(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess) { - BOOL f, f32 = ctxVmm->f32; + BOOL f, f32 = H->vmm.f32; LPWSTR wszTMP = NULL; DWORD i, cEnv = 0; LPWSTR wszEnv; @@ -1114,28 +1120,28 @@ PVMMWIN_USER_PROCESS_PARAMETERS VmmWin_UserProcessParameters_Get(_In_ PVMM_PROCE if(pu->fProcessed || pProcess->dwState) { return pu; } EnterCriticalSection(&pProcess->LockUpdate); if(pu->fProcessed || pProcess->dwState) { LeaveCriticalSection(&pProcess->LockUpdate); return pu; } - if(ctxVmm->f32) { + if(f32) { f = pProcess->win.vaPEB && - VmmRead(pProcess, pProcess->win.vaPEB + 0x10, (PBYTE)&vaUserProcessParameters, sizeof(DWORD)) && + VmmRead(H, pProcess, pProcess->win.vaPEB + 0x10, (PBYTE)&vaUserProcessParameters, sizeof(DWORD)) && !(vaUserProcessParameters & 0x80000003); } else { f = pProcess->win.vaPEB && - VmmRead(pProcess, pProcess->win.vaPEB + 0x20, (PBYTE)&vaUserProcessParameters, sizeof(QWORD)) && + VmmRead(H, pProcess, pProcess->win.vaPEB + 0x20, (PBYTE)&vaUserProcessParameters, sizeof(QWORD)) && !(vaUserProcessParameters & 0xffff800000000007); } if(f) { // ImagePathName or DllPath - if(!VmmReadAllocUnicodeStringAsUTF8(pProcess, f32, 0, vaUserProcessParameters + (f32 ? 0x038 : 0x060), 0x400, &pu->uszImagePathName, &pu->cbuImagePathName)) { // ImagePathName - VmmReadAllocUnicodeStringAsUTF8(pProcess, f32, 0, vaUserProcessParameters + (f32 ? 0x030 : 0x050), 0x400, &pu->uszImagePathName, &pu->cbuImagePathName); // DllPath (mutually exclusive with ImagePathName?) + if(!VmmReadAllocUnicodeStringAsUTF8(H, pProcess, f32, 0, vaUserProcessParameters + (f32 ? 0x038 : 0x060), 0x400, &pu->uszImagePathName, &pu->cbuImagePathName)) { // ImagePathName + VmmReadAllocUnicodeStringAsUTF8(H, pProcess, f32, 0, vaUserProcessParameters + (f32 ? 0x030 : 0x050), 0x400, &pu->uszImagePathName, &pu->cbuImagePathName); // DllPath (mutually exclusive with ImagePathName?) } - VmmReadAllocUnicodeStringAsUTF8(pProcess, f32, 0, vaUserProcessParameters + (f32 ? 0x040 : 0x070), 0x00010000, &pu->uszCommandLine, &pu->cbuCommandLine); - VmmReadAllocUnicodeStringAsUTF8(pProcess, f32, 0, vaUserProcessParameters + (f32 ? 0x070 : 0x0b0), 0x00010000, &pu->uszWindowTitle, &pu->cbuWindowTitle); + VmmReadAllocUnicodeStringAsUTF8(H, pProcess, f32, 0, vaUserProcessParameters + (f32 ? 0x040 : 0x070), 0x00010000, &pu->uszCommandLine, &pu->cbuCommandLine); + VmmReadAllocUnicodeStringAsUTF8(H, pProcess, f32, 0, vaUserProcessParameters + (f32 ? 0x070 : 0x0b0), 0x00010000, &pu->uszWindowTitle, &pu->cbuWindowTitle); } - if(f && (ctxVmm->kernel.dwVersionBuild >= 6000)) { + if(f && (H->vmm.kernel.dwVersionBuild >= 6000)) { // Environment (multi-str) - VmmRead(pProcess, vaUserProcessParameters + (f32 ? 0x048 : 0x080), (PBYTE)&vaEnv, (f32 ? 4 : 8)); // Environment - VmmRead(pProcess, vaUserProcessParameters + (f32 ? 0x290 : 0x3f0), (PBYTE)&cEnv, sizeof(DWORD)); // EnvironmentSize - if(vaEnv && (cEnv > 0x10) && (cEnv < 0x10000) && VmmReadAlloc(pProcess, vaEnv, (PBYTE *)&wszEnv, cEnv, 0)) { + VmmRead(H, pProcess, vaUserProcessParameters + (f32 ? 0x048 : 0x080), (PBYTE)&vaEnv, (f32 ? 4 : 8)); // Environment + VmmRead(H, pProcess, vaUserProcessParameters + (f32 ? 0x290 : 0x3f0), (PBYTE)&cEnv, sizeof(DWORD)); // EnvironmentSize + if(vaEnv && (cEnv > 0x10) && (cEnv < 0x10000) && VmmReadAlloc(H, pProcess, vaEnv, (PBYTE *)&wszEnv, cEnv, 0)) { cEnv = (cEnv >> 1); // bytes to wchar_count for(i = 0; i < cEnv; i++) { if(!wszEnv[i]) { @@ -1213,7 +1219,7 @@ VOID VmmWinPte_InitializeMapText_MapTag(_In_ PVMM_PROCESS pProcess, _In_ POB_STR /* * Identify module names by scanning for PE headers and tag them into the memory map. */ -VOID VmmWinPte_InitializeMapText_ScanHeaderPE(_In_ PVMM_PROCESS pProcess, _In_ POB_STRMAP psm) +VOID VmmWinPte_InitializeMapText_ScanHeaderPE(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ POB_STRMAP psm) { DWORD cMap; PVMMOB_MAP_PTE pObMemMap = NULL; @@ -1225,13 +1231,13 @@ VOID VmmWinPte_InitializeMapText_ScanHeaderPE(_In_ PVMM_PROCESS pProcess, _In_ P CHAR szBuffer[MAX_PATH]; // 1: checks and allocate buffers for parallel read of MZ header candidates if(!LcAllocScatter1(0x400, &ppMEMs)) { goto fail; } - if(!VmmMap_GetPte(pProcess, &pObMemMap, FALSE)) { goto fail; } + if(!VmmMap_GetPte(H, pProcess, &pObMemMap, FALSE)) { goto fail; } if(!pObMemMap || !pObMemMap->cMap) { goto fail; } cMap = pObMemMap->cMap; pMap = pObMemMap->pMap; // 2: scan memory map for MZ header candidates and put them on list for read for(i = 0; i < cMap - 1; i++) { - if(ctxVmm->tpMemoryModel == VMM_MEMORYMODEL_X86) { + if(H->vmm.tpMemoryModel == VMM_MEMORYMODEL_X86) { result = !(pMap[i].vaBase & 0xffff) && // starts at even 0x10000 offset !pMap[i].cbuText; // tag not already set @@ -1252,10 +1258,10 @@ VOID VmmWinPte_InitializeMapText_ScanHeaderPE(_In_ PVMM_PROCESS pProcess, _In_ P } // 3: read all MZ header candicates previously selected and try load name from them (after read is successful) if(cMEMs) { - VmmReadScatterVirtual(pProcess, ppMEMs, cMEMs, 0); + VmmReadScatterVirtual(H, pProcess, ppMEMs, cMEMs, 0); for(i = 0; i < cMEMs; i++) { if(ppMEMs[i]->f) { - result = PE_GetModuleNameEx(pProcess, ppMAPs[i]->vaBase, TRUE, ppMEMs[i]->pb, szBuffer, _countof(szBuffer), &cbImageSize); + result = PE_GetModuleNameEx(H, pProcess, ppMAPs[i]->vaBase, TRUE, ppMEMs[i]->pb, szBuffer, _countof(szBuffer), &cbImageSize); if(result && (cbImageSize < 0x01000000)) { VmmWinPte_InitializeMapText_MapTag(pProcess, psm, ppMAPs[i]->vaBase, ppMAPs[i]->vaBase + cbImageSize - 1, szBuffer, FALSE); } @@ -1267,12 +1273,12 @@ fail: Ob_DECREF(pObMemMap); } -VOID VmmWinPte_InitializeMapText_Modules(_In_ PVMM_PROCESS pProcess, _In_ POB_STRMAP psm) +VOID VmmWinPte_InitializeMapText_Modules(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ POB_STRMAP psm) { DWORD i; PVMM_MAP_MODULEENTRY pModule; PVMMOB_MAP_MODULE pObModuleMap = NULL; - if(VmmMap_GetModule(pProcess, &pObModuleMap)) { + if(VmmMap_GetModule(H, pProcess, &pObModuleMap)) { // update memory map with names for(i = 0; i < pObModuleMap->cMap; i++) { pModule = pObModuleMap->pMap + i; @@ -1282,14 +1288,14 @@ VOID VmmWinPte_InitializeMapText_Modules(_In_ PVMM_PROCESS pProcess, _In_ POB_ST } } -VOID VmmWinPte_InitializeMapText_Drivers(_In_ PVMM_PROCESS pProcess, _In_ POB_STRMAP psm) +VOID VmmWinPte_InitializeMapText_Drivers(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ POB_STRMAP psm) { DWORD i; PVMM_MAP_KDRIVERENTRY pDrv; PVMMOB_MAP_KDRIVER pObDrvMap = NULL; if(pProcess->dwPID != 4) { return; } - VmmWinPte_InitializeMapText_MapTag(pProcess, psm, ctxVmm->kernel.vaBase, ctxVmm->kernel.cbSize, "nt", FALSE); - if(VmmMap_GetKDriver(&pObDrvMap)) { + VmmWinPte_InitializeMapText_MapTag(pProcess, psm, H->vmm.kernel.vaBase, H->vmm.kernel.cbSize, "nt", FALSE); + if(VmmMap_GetKDriver(H, &pObDrvMap)) { // update memory map with names for(i = 0; i < pObDrvMap->cMap; i++) { pDrv = pObDrvMap->pMap + i; @@ -1301,15 +1307,15 @@ VOID VmmWinPte_InitializeMapText_Drivers(_In_ PVMM_PROCESS pProcess, _In_ POB_ST } } -VOID VmmWinPte_InitializeMapText_DoWork(_In_ PVMM_PROCESS pProcess) +VOID VmmWinPte_InitializeMapText_DoWork(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess) { DWORD i; PVMMOB_MAP_PTE pMapPte = pProcess->Map.pObPte; POB_STRMAP psmOb = NULL; - if(!(psmOb = ObStrMap_New(OB_STRMAP_FLAGS_STR_ASSIGN_TEMPORARY))) { return; } - VmmWinPte_InitializeMapText_Drivers(pProcess, psmOb); - VmmWinPte_InitializeMapText_Modules(pProcess, psmOb); - VmmWinPte_InitializeMapText_ScanHeaderPE(pProcess, psmOb); + if(!(psmOb = ObStrMap_New(H, OB_STRMAP_FLAGS_STR_ASSIGN_TEMPORARY))) { return; } + VmmWinPte_InitializeMapText_Drivers(H, pProcess, psmOb); + VmmWinPte_InitializeMapText_Modules(H, pProcess, psmOb); + VmmWinPte_InitializeMapText_ScanHeaderPE(H, pProcess, psmOb); ObStrMap_FinalizeAllocU_DECREF_NULL(&psmOb, &pMapPte->pbMultiText, &pMapPte->cbMultiText); // fixups not set values for(i = 0; i < pMapPte->cMap; i++) { @@ -1325,17 +1331,18 @@ VOID VmmWinPte_InitializeMapText_DoWork(_In_ PVMM_PROCESS pProcess) * Try initialize PteMap text descriptions. This function will first try to pop- * ulate the pre-existing VMMOB_MAP_PTE object in pProcess with module names and * then, if failed or partially failed, try to initialize from PE file headers. +* -- H * -- pProcess * -- return */ _Success_(return) -BOOL VmmWinPte_InitializeMapText(_In_ PVMM_PROCESS pProcess) +BOOL VmmWinPte_InitializeMapText(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess) { if(pProcess->Map.pObPte->fTagScan) { return TRUE; } EnterCriticalSection(&pProcess->LockUpdate); if(!pProcess->Map.pObPte->fTagScan) { - VmmTlbSpider(pProcess); - VmmWinPte_InitializeMapText_DoWork(pProcess); + VmmTlbSpider(H, pProcess); + VmmWinPte_InitializeMapText_DoWork(H, pProcess); } LeaveCriticalSection(&pProcess->LockUpdate); return pProcess->Map.pObPte->fTagScan; @@ -1365,12 +1372,12 @@ int VmmWinThread_Initialize_CmpThreadEntry(PVMM_MAP_THREADENTRY v1, PVMM_MAP_THR (v1->dwTID > v2->dwTID) ? 1 : 0; } -VOID VmmWinThread_Initialize_DoWork_Pre(_In_ PVMM_PROCESS pSystemProcess, _In_opt_ PVMMWIN_INITIALIZETHREAD_CONTEXT ctx, _In_ QWORD va, _In_ PBYTE pb, _In_ DWORD cb, _In_ QWORD vaFLink, _In_ QWORD vaBLink, _In_ POB_SET pVSetAddress, _Inout_ PBOOL pfValidEntry, _Inout_ PBOOL pfValidFLink, _Inout_ PBOOL pfValidBLink) +VOID VmmWinThread_Initialize_DoWork_Pre(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_opt_ PVMMWIN_INITIALIZETHREAD_CONTEXT ctx, _In_ QWORD va, _In_ PBYTE pb, _In_ DWORD cb, _In_ QWORD vaFLink, _In_ QWORD vaBLink, _In_ POB_SET pVSetAddress, _Inout_ PBOOL pfValidEntry, _Inout_ PBOOL pfValidFLink, _Inout_ PBOOL pfValidBLink) { - BOOL f, f32 = ctxVmm->f32; + BOOL f, f32 = H->vmm.f32; DWORD dwTID; PVMM_MAP_THREADENTRY e; - PVMM_OFFSET_ETHREAD ot = &ctxVmm->offset.ETHREAD; + PVMM_OFFSET_ETHREAD ot = &H->vmm.offset.ETHREAD; // 1: sanity check f = ctx && (f32 ? VMM_KADDR32_4(vaFLink) : VMM_KADDR64_8(vaFLink)) && @@ -1407,9 +1414,9 @@ VOID VmmWinThread_Initialize_DoWork_Pre(_In_ PVMM_PROCESS pSystemProcess, _In_op ObMap_Push(ctx->pmThread, e->dwTID, e); // map will free allocation when cleared } -VOID VmmWinThread_Initialize_DoWork(_In_ PVMM_PROCESS pProcess) +VOID VmmWinThread_Initialize_DoWork(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess) { - BOOL f, f32 = ctxVmm->f32; + BOOL f, f32 = H->vmm.f32; BYTE pb[0x200]; DWORD i, cMap, cbTrapFrame = 0; QWORD va, vaThreadListEntry; @@ -1419,46 +1426,47 @@ VOID VmmWinThread_Initialize_DoWork(_In_ PVMM_PROCESS pProcess) PVMM_MAP_THREADENTRY pThreadEntry; PVMM_PROCESS pObSystemProcess = NULL; VMMWIN_INITIALIZETHREAD_CONTEXT ctx = { 0 }; - PVMM_OFFSET_ETHREAD ot = &ctxVmm->offset.ETHREAD; + PVMM_OFFSET_ETHREAD ot = &H->vmm.offset.ETHREAD; // 1: set up and perform list traversal call. - vaThreadListEntry = VMM_PTR_OFFSET(f32, pProcess->win.EPROCESS.pb, ctxVmm->offset.ETHREAD.oThreadListHeadKP); + vaThreadListEntry = VMM_PTR_OFFSET(f32, pProcess->win.EPROCESS.pb, H->vmm.offset.ETHREAD.oThreadListHeadKP); if(f32 ? !VMM_KADDR32_4(vaThreadListEntry) : !VMM_KADDR64_8(vaThreadListEntry)) { goto fail; } - if(!(pObSystemProcess = VmmProcessGet(4))) { goto fail; } - if(!(psObTeb = ObSet_New())) { goto fail; } - if(!(psObTrapFrame = ObSet_New())) { goto fail; } - if(!(pmObThreads = ObMap_New(OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } + if(!(pObSystemProcess = VmmProcessGet(H, 4))) { goto fail; } + if(!(psObTeb = ObSet_New(H))) { goto fail; } + if(!(psObTrapFrame = ObSet_New(H))) { goto fail; } + if(!(pmObThreads = ObMap_New(H, OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } ctx.pmThread = pmObThreads; ctx.psObTeb = psObTeb; ctx.psObTrapFrame = psObTrapFrame; ctx.pProcess = pProcess; - va = vaThreadListEntry - ctxVmm->offset.ETHREAD.oThreadListEntry; + va = vaThreadListEntry - H->vmm.offset.ETHREAD.oThreadListEntry; VmmWin_ListTraversePrefetch( + H, pObSystemProcess, f32, &ctx, 1, &va, - ctxVmm->offset.ETHREAD.oThreadListEntry, - ctxVmm->offset.ETHREAD.oMax, + H->vmm.offset.ETHREAD.oThreadListEntry, + H->vmm.offset.ETHREAD.oMax, (VMMWIN_LISTTRAVERSE_PRE_CB)VmmWinThread_Initialize_DoWork_Pre, NULL, pProcess->pObPersistent->pObCMapThreadPrefetch); // 2: transfer result from generic map into PVMMOB_MAP_THREAD if(!(cMap = ObMap_Size(pmObThreads))) { goto fail; } - if(!(pObThreadMap = Ob_Alloc(OB_TAG_MAP_THREAD, 0, sizeof(VMMOB_MAP_THREAD) + cMap * sizeof(VMM_MAP_THREADENTRY), NULL, NULL))) { goto fail; } + if(!(pObThreadMap = Ob_AllocEx(H, OB_TAG_MAP_THREAD, 0, sizeof(VMMOB_MAP_THREAD) + cMap * sizeof(VMM_MAP_THREADENTRY), NULL, NULL))) { goto fail; } pObThreadMap->cMap = cMap; cbTrapFrame = ((ot->oTrapRsp < 0x200 - 8) && (ot->oTrapRip < 0x200 - 8)) ? 8 + max(ot->oTrapRsp, ot->oTrapRip) : 0; - VmmCachePrefetchPages3(pObSystemProcess, psObTrapFrame, cbTrapFrame, 0); - VmmCachePrefetchPages3(pProcess, psObTeb, 0x20, 0); + VmmCachePrefetchPages3(H, pObSystemProcess, psObTrapFrame, cbTrapFrame, 0); + VmmCachePrefetchPages3(H, pProcess, psObTeb, 0x20, 0); for(i = 0; i < cMap; i++) { pThreadEntry = (PVMM_MAP_THREADENTRY)ObMap_GetByIndex(pmObThreads, i); // fetch Teb - if(VmmRead2(pProcess, pThreadEntry->vaTeb, pb, 0x20, VMM_FLAG_FORCECACHE_READ)) { + if(VmmRead2(H, pProcess, pThreadEntry->vaTeb, pb, 0x20, VMM_FLAG_FORCECACHE_READ)) { pThreadEntry->vaStackBaseUser = VMM_PTR_OFFSET_DUAL(f32, pb, 4, 8); pThreadEntry->vaStackLimitUser = VMM_PTR_OFFSET_DUAL(f32, pb, 8, 16); } // fetch TrapFrame (RSP/RIP) - if(cbTrapFrame && VmmRead2(pObSystemProcess, pThreadEntry->vaTrapFrame, pb, cbTrapFrame, VMM_FLAG_FORCECACHE_READ)) { + if(cbTrapFrame && VmmRead2(H, pObSystemProcess, pThreadEntry->vaTrapFrame, pb, cbTrapFrame, VMM_FLAG_FORCECACHE_READ)) { pThreadEntry->vaRIP = VMM_PTR_OFFSET(f32, pb, ot->oTrapRip); pThreadEntry->vaRSP = VMM_PTR_OFFSET(f32, pb, ot->oTrapRsp); f = ((pThreadEntry->vaStackBaseUser > pThreadEntry->vaRSP) && (pThreadEntry->vaStackLimitUser < pThreadEntry->vaRSP)) || @@ -1485,19 +1493,20 @@ fail: * Initialize the thread map for a specific process. * NB! The threading sub-system is dependent on pdb symbols and may take a small * amount of time before it's available after system startup. +* -- H * -- pProcess * -- return */ -BOOL VmmWinThread_Initialize(_In_ PVMM_PROCESS pProcess) +BOOL VmmWinThread_Initialize(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess) { if(pProcess->Map.pObThread) { return TRUE; } - if(!ctxVmm->fThreadMapEnabled) { return FALSE; } - VmmTlbSpider(pProcess); + if(!H->vmm.fThreadMapEnabled) { return FALSE; } + VmmTlbSpider(H, pProcess); EnterCriticalSection(&pProcess->Map.LockUpdateThreadExtendedInfo); if(!pProcess->Map.pObThread) { - VmmWinThread_Initialize_DoWork(pProcess); + VmmWinThread_Initialize_DoWork(H, pProcess); if(!pProcess->Map.pObThread) { - pProcess->Map.pObThread = Ob_Alloc(OB_TAG_MAP_THREAD, LMEM_ZEROINIT, sizeof(VMMOB_MAP_THREAD), NULL, NULL); + pProcess->Map.pObThread = Ob_AllocEx(H, OB_TAG_MAP_THREAD, LMEM_ZEROINIT, sizeof(VMMOB_MAP_THREAD), NULL, NULL); } } LeaveCriticalSection(&pProcess->Map.LockUpdateThreadExtendedInfo); @@ -1544,11 +1553,12 @@ static const VMMWIN_OBJECTTYPE_NAME2OBJECT_ENTRY VMMWIN_OBJECTTYPE_NAME2OBJECT_A * Retrieve a pointer to a VMMWIN_OBJECT_TYPE if possible. Initialization of the * table takes place on first use. The table only exists in Win7+ and is is * dependant on PDB symbol functionality for initialization. +* -- H * -- iObjectType * -- return */ _Success_(return != NULL) -PVMMWIN_OBJECT_TYPE VmmWin_ObjectTypeGet(_In_ BYTE iObjectType) +PVMMWIN_OBJECT_TYPE VmmWin_ObjectTypeGet(_In_ VMM_HANDLE H, _In_ BYTE iObjectType) { static SRWLOCK InitLockSRW = { 0 }; BOOL f, fResult = FALSE; @@ -1563,26 +1573,26 @@ PVMMWIN_OBJECT_TYPE VmmWin_ObjectTypeGet(_In_ BYTE iObjectType) PQWORD pva64; PDWORD pva32; PVMMWIN_OBJECT_TYPE ptp; - if(ctxVmm->ObjectTypeTable.fInitialized) { - return ctxVmm->ObjectTypeTable.h[iObjectType].usz ? &ctxVmm->ObjectTypeTable.h[iObjectType] : NULL; + if(H->vmm.ObjectTypeTable.fInitialized) { + return H->vmm.ObjectTypeTable.h[iObjectType].usz ? &H->vmm.ObjectTypeTable.h[iObjectType] : NULL; } - PDB_Initialize_WaitComplete(); + PDB_Initialize_WaitComplete(H); AcquireSRWLockExclusive(&InitLockSRW); - if(ctxVmm->ObjectTypeTable.fInitialized) { + if(H->vmm.ObjectTypeTable.fInitialized) { ReleaseSRWLockExclusive(&InitLockSRW); - return ctxVmm->ObjectTypeTable.h[iObjectType].usz ? &ctxVmm->ObjectTypeTable.h[iObjectType] : NULL; + return H->vmm.ObjectTypeTable.h[iObjectType].usz ? &H->vmm.ObjectTypeTable.h[iObjectType] : NULL; } - if(!(pObSystemProcess = VmmProcessGet(4))) { goto fail; } - if(!PDB_GetSymbolAddress(PDB_HANDLE_KERNEL, "ObTypeIndexTable", &vaTypeTable)) { goto fail; } - if(ctxVmm->kernel.dwVersionMajor == 10) { - if(!PDB_GetSymbolDWORD(PDB_HANDLE_KERNEL, "ObHeaderCookie", pObSystemProcess, &i)) { goto fail; } - ctxVmm->ObjectTypeTable.bObjectHeaderCookie = (BYTE)i; + if(!(pObSystemProcess = VmmProcessGet(H, 4))) { goto fail; } + if(!PDB_GetSymbolAddress(H, PDB_HANDLE_KERNEL, "ObTypeIndexTable", &vaTypeTable)) { goto fail; } + if(H->vmm.kernel.dwVersionMajor == 10) { + if(!PDB_GetSymbolDWORD(H, PDB_HANDLE_KERNEL, "ObHeaderCookie", pObSystemProcess, &i)) { goto fail; } + H->vmm.ObjectTypeTable.bObjectHeaderCookie = (BYTE)i; } // fetch and count object type addresses ZeroMemory(ava, sizeof(ava)); ZeroMemory(acbwsz, sizeof(acbwsz)); - VmmReadEx(pObSystemProcess, vaTypeTable, pb, 256 * 8, NULL, VMM_FLAG_ZEROPAD_ON_FAIL); - if(ctxVmm->f32) { + VmmReadEx(H, pObSystemProcess, vaTypeTable, pb, 256 * 8, NULL, VMM_FLAG_ZEROPAD_ON_FAIL); + if(H->vmm.f32) { pva32 = (PDWORD)pb; while(VMM_KADDR32_8(pva32[cType]) && (cType < 256)) { ava[cType] = pva32[cType]; @@ -1597,66 +1607,67 @@ PVMMWIN_OBJECT_TYPE VmmWin_ObjectTypeGet(_In_ BYTE iObjectType) } if(cType == 2) { goto fail; } // none found // fetch unicode length and addresses of text - VmmCachePrefetchPages4(pObSystemProcess, cType, ava, 0x10, 0); + VmmCachePrefetchPages4(H, pObSystemProcess, cType, ava, 0x10, 0); for(i = 2; i < cType; i++) { - f = VmmRead2(pObSystemProcess, ava[i] + (ctxVmm->f32 ? 8 : 16), pb, 0x10, VMM_FLAG_FORCECACHE_READ); + f = VmmRead2(H, pObSystemProcess, ava[i] + (H->vmm.f32 ? 8 : 16), pb, 0x10, VMM_FLAG_FORCECACHE_READ); f = f && (*(PWORD)(pb) < MAX_PATH); f = f && (*(PWORD)(pb) <= *(PQWORD)(pb + 2)); f = f && (acbwsz[i] = *(PWORD)(pb)); - f = f && (ava[i] = ctxVmm->f32 ? *(PDWORD)(pb + 4) : *(PQWORD)(pb + 8)); - f = f && (ctxVmm->f32 ? VMM_KADDR32_8(ava[i]) : VMM_KADDR64_16(ava[i])); + f = f && (ava[i] = H->vmm.f32 ? *(PDWORD)(pb + 4) : *(PQWORD)(pb + 8)); + f = f && (H->vmm.f32 ? VMM_KADDR32_8(ava[i]) : VMM_KADDR64_16(ava[i])); if(!f) { ava[i] = 0; } - ctxVmm->ObjectTypeTable.h[i].iType = i; + H->vmm.ObjectTypeTable.h[i].iType = i; } // fetch text wsz = (LPWSTR)(pb + 16); - VmmCachePrefetchPages4(pObSystemProcess, cType, ava, 2 * MAX_PATH, 0); - if(!(pObStrMap = ObStrMap_New(0))) { goto fail; } + VmmCachePrefetchPages4(H, pObSystemProcess, cType, ava, 2 * MAX_PATH, 0); + if(!(pObStrMap = ObStrMap_New(H, 0))) { goto fail; } for(i = 2; i < cType; i++) { - if(ava[i] && VmmRead2(pObSystemProcess, ava[i] - 16, pb, 16 + acbwsz[i], VMM_FLAG_FORCECACHE_READ) && VMM_POOLTAG_PREPENDED(pb, 16, 'ObNm')) { + if(ava[i] && VmmRead2(H, pObSystemProcess, ava[i] - 16, pb, 16 + acbwsz[i], VMM_FLAG_FORCECACHE_READ) && VMM_POOLTAG_PREPENDED(H->vmm.f32, pb, 16, 'ObNm')) { wsz[acbwsz[i] >> 1] = 0; - ObStrMap_PushPtrWU(pObStrMap, wsz, &ctxVmm->ObjectTypeTable.h[i].usz, &ctxVmm->ObjectTypeTable.h[i].cbu); + ObStrMap_PushPtrWU(pObStrMap, wsz, &H->vmm.ObjectTypeTable.h[i].usz, &H->vmm.ObjectTypeTable.h[i].cbu); } } - ObStrMap_FinalizeAllocU_DECREF_NULL(&pObStrMap, (PBYTE*)&ctxVmm->ObjectTypeTable.pbMultiText, &ctxVmm->ObjectTypeTable.cbMultiText); + ObStrMap_FinalizeAllocU_DECREF_NULL(&pObStrMap, (PBYTE*)&H->vmm.ObjectTypeTable.pbMultiText, &H->vmm.ObjectTypeTable.cbMultiText); // specific type lookups for(i = 2; i < cType; i++) { - ptp = ctxVmm->ObjectTypeTable.h + i; + ptp = H->vmm.ObjectTypeTable.h + i; for(j = 0; j < sizeof(VMMWIN_OBJECTTYPE_NAME2OBJECT_ARRAY) / sizeof(VMMWIN_OBJECTTYPE_NAME2OBJECT_ENTRY); j++) { if(ptp->usz && (ptp->usz[0] == VMMWIN_OBJECTTYPE_NAME2OBJECT_ARRAY[j].usz[0]) && !strcmp(ptp->usz, VMMWIN_OBJECTTYPE_NAME2OBJECT_ARRAY[j].usz)) { - ctxVmm->ObjectTypeTable._tpAll[j] = (BYTE)i; - PDB_GetTypeSize(PDB_HANDLE_KERNEL, VMMWIN_OBJECTTYPE_NAME2OBJECT_ARRAY[j].sz, &ptp->cb); + H->vmm.ObjectTypeTable._tpAll[j] = (BYTE)i; + PDB_GetTypeSize(H, PDB_HANDLE_KERNEL, VMMWIN_OBJECTTYPE_NAME2OBJECT_ARRAY[j].sz, &ptp->cb); ptp->szType = VMMWIN_OBJECTTYPE_NAME2OBJECT_ARRAY[j].sz; } } } // finish! - ctxVmm->ObjectTypeTable.c = cType; + H->vmm.ObjectTypeTable.c = cType; fResult = TRUE; // fall-trough to cleanup / "fail" fail: - ctxVmm->ObjectTypeTable.fInitialized = TRUE; - if(!fResult) { ctxVmm->ObjectTypeTable.fInitializedFailed = TRUE; } + H->vmm.ObjectTypeTable.fInitialized = TRUE; + if(!fResult) { H->vmm.ObjectTypeTable.fInitializedFailed = TRUE; } ReleaseSRWLockExclusive(&InitLockSRW); Ob_DECREF(pObSystemProcess); - return ctxVmm->ObjectTypeTable.h[iObjectType].usz ? &ctxVmm->ObjectTypeTable.h[iObjectType] : NULL; + return H->vmm.ObjectTypeTable.h[iObjectType].usz ? &H->vmm.ObjectTypeTable.h[iObjectType] : NULL; } /* * _OBJECT_HEADER.TypeIndex is encoded on Windows 10 - this function decodes it. * https://medium.com/@ashabdalhalim/e8f907e7073a +* -- H * -- vaObjectHeader * -- iTypeIndexTableEncoded * -- return */ -BYTE VmmWin_ObjectTypeGetIndexFromEncoded(_In_ QWORD vaObjectHeader, _In_ BYTE iTypeIndexTableEncoded) +BYTE VmmWin_ObjectTypeGetIndexFromEncoded(_In_ VMM_HANDLE H, _In_ QWORD vaObjectHeader, _In_ BYTE iTypeIndexTableEncoded) { - if(ctxVmm->kernel.dwVersionMajor != 10) { return iTypeIndexTableEncoded; } - if(!ctxVmm->ObjectTypeTable.fInitialized) { VmmWin_ObjectTypeGet(0); } // DUMMY call to initialize ctxVmm->ObjectTypeTable - if(ctxVmm->ObjectTypeTable.fInitializedFailed) { return 0; } - return iTypeIndexTableEncoded ^ (BYTE)(vaObjectHeader >> 8) ^ ctxVmm->ObjectTypeTable.bObjectHeaderCookie; + if(H->vmm.kernel.dwVersionMajor != 10) { return iTypeIndexTableEncoded; } + if(!H->vmm.ObjectTypeTable.fInitialized) { VmmWin_ObjectTypeGet(H, 0); } // DUMMY call to initialize H->vmm.ObjectTypeTable + if(H->vmm.ObjectTypeTable.fInitializedFailed) { return 0; } + return iTypeIndexTableEncoded ^ (BYTE)(vaObjectHeader >> 8) ^ H->vmm.ObjectTypeTable.bObjectHeaderCookie; } typedef struct tdVMMWIN_INITIALIZE_HANDLE_CONTEXT { @@ -1680,11 +1691,12 @@ VOID VmmWinHandle_CloseObCallback(_In_ PVMMOB_MAP_HANDLE pOb) /* * Spider the handle table hierarchy if there is one. +* -- H * -- ctx * -- vaTable * -- fLevel2 */ -VOID VmmWinHandle_InitializeCore_SpiderTables(_In_ PVMMWIN_INITIALIZE_HANDLE_CONTEXT ctx, _In_ QWORD vaTable, _In_ BOOL fLevel2) +VOID VmmWinHandle_InitializeCore_SpiderTables(_In_ VMM_HANDLE H, _In_ PVMMWIN_INITIALIZE_HANDLE_CONTEXT ctx, _In_ QWORD vaTable, _In_ BOOL fLevel2) { QWORD i, va = 0; union { @@ -1692,13 +1704,13 @@ VOID VmmWinHandle_InitializeCore_SpiderTables(_In_ PVMMWIN_INITIALIZE_HANDLE_CON DWORD pdw[0x400]; QWORD pqw[0x200]; } u; - if(!VmmRead(ctx->pSystemProcess, vaTable, u.pb, 0x1000)) { return; } - if(ctxVmm->f32) { + if(!VmmRead(H, ctx->pSystemProcess, vaTable, u.pb, 0x1000)) { return; } + if(H->vmm.f32) { for(i = 0; i < 0x400; i++) { va = u.pdw[i]; if(!VMM_KADDR32_PAGE(va)) { return; } if(fLevel2) { - VmmWinHandle_InitializeCore_SpiderTables(ctx, va, FALSE); + VmmWinHandle_InitializeCore_SpiderTables(H, ctx, va, FALSE); if(ctx->cTables == ctx->cTablesMax) { return; } } else { ctx->pvaTables[ctx->cTables] = va; @@ -1711,7 +1723,7 @@ VOID VmmWinHandle_InitializeCore_SpiderTables(_In_ PVMMWIN_INITIALIZE_HANDLE_CON va = u.pqw[i]; if(!VMM_KADDR64_PAGE(va)) { return; } if(fLevel2) { - VmmWinHandle_InitializeCore_SpiderTables(ctx, va, FALSE); + VmmWinHandle_InitializeCore_SpiderTables(H, ctx, va, FALSE); if(ctx->cTables == ctx->cTablesMax) { return; } } else { ctx->pvaTables[ctx->cTables] = va; @@ -1724,10 +1736,11 @@ VOID VmmWinHandle_InitializeCore_SpiderTables(_In_ PVMMWIN_INITIALIZE_HANDLE_CON /* * Count the number of valid handles. +* -- H * -- ctx * -- return = the number of valid handles. */ -DWORD VmmWinHandle_InitializeCore_CountHandles(_In_ PVMMWIN_INITIALIZE_HANDLE_CONTEXT ctx) +DWORD VmmWinHandle_InitializeCore_CountHandles(_In_ VMM_HANDLE H, _In_ PVMMWIN_INITIALIZE_HANDLE_CONTEXT ctx) { QWORD va; DWORD iTable, i, cHandles = 0; @@ -1736,10 +1749,10 @@ DWORD VmmWinHandle_InitializeCore_CountHandles(_In_ PVMMWIN_INITIALIZE_HANDLE_CO DWORD pdw[0x400]; QWORD pqw[0x200]; } u; - VmmCachePrefetchPages4(ctx->pSystemProcess, ctx->cTables, ctx->pvaTables, 0x1000, 0); + VmmCachePrefetchPages4(H, ctx->pSystemProcess, ctx->cTables, ctx->pvaTables, 0x1000, 0); for(iTable = 0; iTable < ctx->cTables; iTable++) { - if(!VmmRead(ctx->pSystemProcess, ctx->pvaTables[iTable], u.pb, 0x1000)) { continue; } - if(ctxVmm->f32) { + if(!VmmRead(H, ctx->pSystemProcess, ctx->pvaTables[iTable], u.pb, 0x1000)) { continue; } + if(H->vmm.f32) { for(i = 1; i < 512; i++) { if(!VMM_KADDR32(u.pdw[i << 1])) { continue; } cHandles++; @@ -1747,7 +1760,7 @@ DWORD VmmWinHandle_InitializeCore_CountHandles(_In_ PVMMWIN_INITIALIZE_HANDLE_CO } else { for(i = 1; i < 256; i++) { va = u.pqw[i << 1]; - if(ctxVmm->kernel.dwVersionBuild >= 9200) { // Win8 or later + if(H->vmm.kernel.dwVersionBuild >= 9200) { // Win8 or later va = 0xffff000000000000 | (va >> 16); } if(!VMM_KADDR64(va)) { continue; } @@ -1761,11 +1774,12 @@ DWORD VmmWinHandle_InitializeCore_CountHandles(_In_ PVMMWIN_INITIALIZE_HANDLE_CO /* * Read the handle tables and populate only basic information into the HandleMap * i.e. data that don't require reading of the actual objects pointed to. +* -- H * -- ctx * -- vaHandleTable * -- dwBaseHandleId */ -VOID VmmWinHandle_InitializeCore_ReadHandleTable(_In_ PVMMWIN_INITIALIZE_HANDLE_CONTEXT ctx, _In_ QWORD vaHandleTable, _In_ DWORD dwBaseHandleId) +VOID VmmWinHandle_InitializeCore_ReadHandleTable(_In_ VMM_HANDLE H, _In_ PVMMWIN_INITIALIZE_HANDLE_CONTEXT ctx, _In_ QWORD vaHandleTable, _In_ DWORD dwBaseHandleId) { DWORD i; QWORD va; @@ -1775,8 +1789,8 @@ VOID VmmWinHandle_InitializeCore_ReadHandleTable(_In_ PVMMWIN_INITIALIZE_HANDLE_ DWORD pdw[0x400]; QWORD pqw[0x200]; } u; - if(!VmmRead(ctx->pSystemProcess, vaHandleTable, u.pb, 0x1000)) { return; } - if(ctxVmm->f32) { + if(!VmmRead(H, ctx->pSystemProcess, vaHandleTable, u.pb, 0x1000)) { return; } + if(H->vmm.f32) { for(i = 1; i < 512; i++) { if(ctx->iMap == ctx->pHandleMap->cMap) { break; } va = u.pdw[i << 1] & ~3; @@ -1792,9 +1806,9 @@ VOID VmmWinHandle_InitializeCore_ReadHandleTable(_In_ PVMMWIN_INITIALIZE_HANDLE_ for(i = 1; i < 256; i++) { if(ctx->iMap == ctx->pHandleMap->cMap) { break; } va = u.pqw[i << 1]; - if(ctxVmm->kernel.dwVersionBuild >= 9600) { // Win8.1 or later + if(H->vmm.kernel.dwVersionBuild >= 9600) { // Win8.1 or later va = 0xffff000000000000 | (va >> 16); - } else if(ctxVmm->kernel.dwVersionBuild >= 9200) { // Win8 or later + } else if(H->vmm.kernel.dwVersionBuild >= 9200) { // Win8 or later va = 0xfffff80000000000 | (va >> 19); } if(!VMM_KADDR64(va)) { continue; } @@ -1832,7 +1846,7 @@ typedef struct tdVMMWIN_OBJECT_HEADER64 { QWORD SecurityDescriptor; } VMMWIN_OBJECT_HEADER64, *PVMMWIN_OBJECT_HEADER64; -DWORD VmmWinHandle_InitializeText_GetPoolHeader2(DWORD dwPoolHeaderCandidate) +DWORD VmmWinHandle_InitializeText_GetPoolHeader2(_In_ VMM_HANDLE H, DWORD dwPoolHeaderCandidate) { CHAR i, ch; for(i = 0; i < 32; i = i + 8) { @@ -1840,7 +1854,7 @@ DWORD VmmWinHandle_InitializeText_GetPoolHeader2(DWORD dwPoolHeaderCandidate) if(ch >= 'a' && ch <= 'z') { continue; } if(ch >= 'A' && ch <= 'Z') { continue; } if(ch == ' ') { continue; } - if((i == 24) && (ctxVmm->kernel.dwVersionBuild <= 9601)) { + if((i == 24) && (H->vmm.kernel.dwVersionBuild <= 9601)) { return 0x20000000 | (dwPoolHeaderCandidate & 0x00ffffff); // last char usually A-Z in win7 } return 0; @@ -1848,12 +1862,12 @@ DWORD VmmWinHandle_InitializeText_GetPoolHeader2(DWORD dwPoolHeaderCandidate) return dwPoolHeaderCandidate; } -DWORD VmmWinHandle_InitializeText_GetPoolHeader32(_In_reads_(0x40) PBYTE pb, _Out_ PDWORD pdwOffset) +DWORD VmmWinHandle_InitializeText_GetPoolHeader32(_In_ VMM_HANDLE H, _In_reads_(0x40) PBYTE pb, _Out_ PDWORD pdwOffset) { DWORD dwPoolHeader, i = 0x40; while(i) { i -= 0x08; - if((dwPoolHeader = VmmWinHandle_InitializeText_GetPoolHeader2(*(PDWORD)(pb + i + 4)))) { + if((dwPoolHeader = VmmWinHandle_InitializeText_GetPoolHeader2(H, *(PDWORD)(pb + i + 4)))) { *pdwOffset = i + 4; return dwPoolHeader; } @@ -1862,12 +1876,12 @@ DWORD VmmWinHandle_InitializeText_GetPoolHeader32(_In_reads_(0x40) PBYTE pb, _Ou return 0; } -DWORD VmmWinHandle_InitializeText_GetPoolHeader64(_In_reads_(0x60) PBYTE pb, _Out_ PDWORD pdwOffset) +DWORD VmmWinHandle_InitializeText_GetPoolHeader64(_In_ VMM_HANDLE H, _In_reads_(0x60) PBYTE pb, _Out_ PDWORD pdwOffset) { DWORD dwPoolHeader, i = 0x60; while(i) { i -= 0x10; - if((dwPoolHeader = VmmWinHandle_InitializeText_GetPoolHeader2(*(PDWORD)(pb + i + 4)))) { + if((dwPoolHeader = VmmWinHandle_InitializeText_GetPoolHeader2(H, *(PDWORD)(pb + i + 4)))) { *pdwOffset = i + 4; return dwPoolHeader; } @@ -1886,21 +1900,22 @@ typedef struct tdVMMWINHANDLE_REGHELPER { /* * Helper function for VmmWinHandle_InitializeText_DoWork that fetches registry * names provided that the underlying _CM_KEY_CONTROL_BLOCK is prefetched. +* -- H * -- pSystemProcess * -- pm */ -VOID VmmWinHandle_InitializeText_DoWork_RegKeyHelper(_In_ PVMM_PROCESS pSystemProcess, _In_ POB_MAP pm) +VOID VmmWinHandle_InitializeText_DoWork_RegKeyHelper(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ POB_MAP pm) { BYTE pb[0x30]; - DWORD raCell, dwBuild = ctxVmm->kernel.dwVersionBuild; + DWORD raCell, dwVersionBuild = H->vmm.kernel.dwVersionBuild; QWORD vaHive; POB_REGISTRY_KEY pObKey = NULL; POB_REGISTRY_HIVE pObHive = NULL; PVMMWINHANDLE_REGHELPER prh = NULL; while((prh = ObMap_GetNext(pm, prh))) { - if(!VmmRead2(pSystemProcess, prh->vaCmKeyControlBlock, pb, 0x30, VMM_FLAG_FORCECACHE_READ)) { continue; } - if(ctxVmm->f32) { - if((dwBuild >= 7600) && (dwBuild <= 10586)) { + if(!VmmRead2(H, pSystemProcess, prh->vaCmKeyControlBlock, pb, 0x30, VMM_FLAG_FORCECACHE_READ)) { continue; } + if(H->vmm.f32) { + if((dwVersionBuild >= 7600) && (dwVersionBuild <= 10586)) { // Win7 :: Win10_10586 vaHive = *(PDWORD)(pb + 0x14); raCell = *(PDWORD)(pb + 0x18); @@ -1910,7 +1925,7 @@ VOID VmmWinHandle_InitializeText_DoWork_RegKeyHelper(_In_ PVMM_PROCESS pSystemPr } if(!VMM_KADDR32(vaHive)) { continue; } } else { - if((dwBuild <= 6002) || ((dwBuild >= 14393) && (dwBuild <= 17763))) { + if((dwVersionBuild <= 6002) || ((dwVersionBuild >= 14393) && (dwVersionBuild <= 17763))) { // VISTA & Win10_1607 :: Win10_1809 vaHive = *(PQWORD)(pb + 0x18); raCell = *(PDWORD)(pb + 0x20); @@ -1925,9 +1940,9 @@ VOID VmmWinHandle_InitializeText_DoWork_RegKeyHelper(_In_ PVMM_PROCESS pSystemPr prh->raKeyCell = raCell; } while((prh = ObMap_GetNext(pm, prh))) { - if((pObHive = VmmWinReg_HiveGetByAddress(prh->vaHive))) { - if((pObKey = VmmWinReg_KeyGetByCellOffset(pObHive, prh->raKeyCell))) { - VmmWinReg_KeyInfo2(pObHive, pObKey, &prh->KeyInfo); + if((pObHive = VmmWinReg_HiveGetByAddress(H, prh->vaHive))) { + if((pObKey = VmmWinReg_KeyGetByCellOffset(H, pObHive, prh->raKeyCell))) { + VmmWinReg_KeyInfo2(H, pObHive, pObKey, &prh->KeyInfo); Ob_DECREF_NULL(&pObKey); } Ob_DECREF_NULL(&pObHive); @@ -1935,28 +1950,28 @@ VOID VmmWinHandle_InitializeText_DoWork_RegKeyHelper(_In_ PVMM_PROCESS pSystemPr } } -VOID VmmWinHandle_InitializeText_DoWork_FileSizeHelper(_In_ PVMM_PROCESS pSystemProcess, _In_ POB_SET psPrefetch, _In_ PVMMOB_MAP_HANDLE pHandleMap) +VOID VmmWinHandle_InitializeText_DoWork_FileSizeHelper(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ POB_SET psPrefetch, _In_ PVMMOB_MAP_HANDLE pHandleMap) { - BOOL f; + BOOL f, f32 = H->vmm.f32; QWORD i, cMax, cb, va; BYTE pb[0x100]; PVMM_MAP_HANDLEENTRY pe; // 1: fetch, if required, _SHARED_CACHE_MAP // _CONTROL_AREA if(0 == ObSet_Size(psPrefetch)) { return; } - VmmCachePrefetchPages3(pSystemProcess, psPrefetch, 0x20, 0); + VmmCachePrefetchPages3(H, pSystemProcess, psPrefetch, 0x20, 0); ObSet_Clear(psPrefetch); for(i = 0, cMax = pHandleMap->cMap; i < cMax; i++) { pe = pHandleMap->pMap + i; if(pe->tpInfoEx != HANDLEENTRY_TP_INFO_FILE) { continue; } - if(!VmmRead2(pSystemProcess, pe->_Reserved.qw - 0x10, pb, 0x20, VMM_FLAG_FORCECACHE_READ)) { continue; } - if(VMM_POOLTAG_PREPENDED(pb, 0x10, 'CcSc')) { + if(!VmmRead2(H, pSystemProcess, pe->_Reserved.qw - 0x10, pb, 0x20, VMM_FLAG_FORCECACHE_READ)) { continue; } + if(VMM_POOLTAG_PREPENDED(f32, pb, 0x10, 'CcSc')) { cb = *(PQWORD)(pb + 0x10 + O_SHARED_CACHE_MAP_FileSize); pe->_InfoFile.cb = (cb <= 0xffffffff) ? (DWORD)cb : 0xffffffff; continue; } - f = VMM_POOLTAG_PREPENDED(pb, 0x10, 'MmCa') && - (va = VMM_PTR_OFFSET(ctxVmm->f32, pb + 0x10, O_CONTROL_AREA_Segment)) && - VMM_KADDR_8_16(va); + f = VMM_POOLTAG_PREPENDED(f32, pb, 0x10, 'MmCa') && + (va = VMM_PTR_OFFSET(f32, pb + 0x10, O_CONTROL_AREA_Segment)) && + VMM_KADDR_8_16(f32, va); if(f) { pe->_Reserved.qw = va; ObSet_Push(psPrefetch, va - 0x10); @@ -1964,27 +1979,28 @@ VOID VmmWinHandle_InitializeText_DoWork_FileSizeHelper(_In_ PVMM_PROCESS pSystem } // 2: fetch, if required, _SEGMENT if(0 == ObSet_Size(psPrefetch)) { return; } - VmmCachePrefetchPages3(pSystemProcess, psPrefetch, 0x30, 0); + VmmCachePrefetchPages3(H, pSystemProcess, psPrefetch, 0x30, 0); for(i = 0, cMax = pHandleMap->cMap; i < cMax; i++) { pe = pHandleMap->pMap + i; if(pe->tpInfoEx != HANDLEENTRY_TP_INFO_FILE) { continue; } - if(!VmmRead2(pSystemProcess, pe->_Reserved.qw - 0x10, pb, 0x30, VMM_FLAG_FORCECACHE_READ)) { continue; } - if(VMM_POOLTAG_PREPENDED(pb, 0x10, 'MmSm')) { - cb = *(PQWORD)(pb + 0x10 + (ctxVmm->f32 ? O32_SEGMENT_SizeOfSegment : O64_SEGMENT_SizeOfSegment)); + if(!VmmRead2(H, pSystemProcess, pe->_Reserved.qw - 0x10, pb, 0x30, VMM_FLAG_FORCECACHE_READ)) { continue; } + if(VMM_POOLTAG_PREPENDED(f32, pb, 0x10, 'MmSm')) { + cb = *(PQWORD)(pb + 0x10 + (f32 ? O32_SEGMENT_SizeOfSegment : O64_SEGMENT_SizeOfSegment)); cb = (cb <= 0xffffffff) ? cb : 0xffffffff; pe->_InfoFile.cb = (DWORD)(pe->_InfoFile.cb ? min(pe->_InfoFile.cb, cb) : cb); } } } -VOID VmmWinHandle_InitializeText_DoWork(_In_ PVMM_PROCESS pSystemProcess, _In_ PVMMOB_MAP_HANDLE pHandleMap) +VOID VmmWinHandle_InitializeText_DoWork(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ PVMMOB_MAP_HANDLE pHandleMap) { - BOOL f, fThreadingEnabled; + BOOL f, f32 = H->vmm.f32, fThreadingEnabled; + PVMM_OFFSET po = &H->vmm.offset; PBYTE pbMultiText = NULL; QWORD va; - DWORD i, cbRead, oPoolHdr, cbObjectRead; + DWORD i, cbRead, oPoolHdr, cbObjectRead, dwoName, dwTag; BYTE pbBuffer[2 * MAX_PATH]; - POB_SET psObPrefetch = NULL, psObRegPrefetch = NULL; + POB_SET psObPrefetch = NULL, psObDevRegPrefetch = NULL; POB_MAP pmObRegHelperMap = NULL; PUNICODE_STRING32 pus32; PUNICODE_STRING64 pus64; @@ -2010,28 +2026,28 @@ VOID VmmWinHandle_InitializeText_DoWork(_In_ PVMM_PROCESS pSystemProcess, _In_ P } u; PVMMWINHANDLE_REGHELPER pRegHelp = NULL; POB_STRMAP psmOb = NULL; - fThreadingEnabled = (ctxVmm->offset.ETHREAD.oCid > 0); - cbObjectRead = max(ctxVmm->offset.EPROCESS.PID + 0x08, ctxVmm->offset.ETHREAD.oCid + 0x20); + fThreadingEnabled = (po->ETHREAD.oCid > 0); + cbObjectRead = max(po->EPROCESS.PID + 0x08, po->ETHREAD.oCid + 0x20); cbObjectRead = 0x90 + max(0x70, cbObjectRead); // 1: cache prefetch object data - if(!(psObPrefetch = ObSet_New())) { goto fail; } - if(!(psObRegPrefetch = ObSet_New())) { goto fail; } - if(!(pmObRegHelperMap = ObMap_New(OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } + if(!(psObPrefetch = ObSet_New(H))) { goto fail; } + if(!(psObDevRegPrefetch = ObSet_New(H))) { goto fail; } + if(!(pmObRegHelperMap = ObMap_New(H, OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } for(i = 0; i < pHandleMap->cMap; i++) { ObSet_Push(psObPrefetch, pHandleMap->pMap[i].vaObject - 0x90); } - VmmCachePrefetchPages3(pSystemProcess, psObPrefetch, cbObjectRead, 0); + VmmCachePrefetchPages3(H, pSystemProcess, psObPrefetch, cbObjectRead, 0); ObSet_Clear(psObPrefetch); // 2: read and interpret object data - if(ctxVmm->f32) { + if(f32) { for(i = 0; i < pHandleMap->cMap; i++) { pe = pHandleMap->pMap + i; - VmmReadEx(pSystemProcess, pe->vaObject - 0x60, u.pb, cbObjectRead, &cbRead, VMM_FLAG_ZEROPAD_ON_FAIL | VMM_FLAG_FORCECACHE_READ); + VmmReadEx(H, pSystemProcess, pe->vaObject - 0x60, u.pb, cbObjectRead, &cbRead, VMM_FLAG_ZEROPAD_ON_FAIL | VMM_FLAG_FORCECACHE_READ); if(cbRead < 0x60) { continue; } // fetch and validate type index (if possible) - pe->iType = VmmWin_ObjectTypeGetIndexFromEncoded(pe->vaObject - 0x18, u.O32.Header.TypeIndex); + pe->iType = VmmWin_ObjectTypeGetIndexFromEncoded(H, pe->vaObject - 0x18, u.O32.Header.TypeIndex); // fetch pool tag (if found) - pe->dwPoolTag = VmmWinHandle_InitializeText_GetPoolHeader32(u.pb, &oPoolHdr); + pe->dwPoolTag = VmmWinHandle_InitializeText_GetPoolHeader32(H, u.pb, &oPoolHdr); // fetch remaining object header values pe->qwHandleCount = u.O32.Header.HandleCount; pe->qwPointerCount = u.O32.Header.PointerCount; @@ -2046,15 +2062,23 @@ VOID VmmWinHandle_InitializeText_DoWork(_In_ PVMM_PROCESS pSystemProcess, _In_ P if(!(pRegHelp = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMWINHANDLE_REGHELPER)))) { continue; } pRegHelp->vaCmKeyControlBlock = *(PDWORD)(u.O32.pb + 4); ObMap_Push(pmObRegHelperMap, pe->vaObject, pRegHelp); // map is responsible for free of pRegHelp - ObSet_Push(psObRegPrefetch, pRegHelp->vaCmKeyControlBlock); + ObSet_Push(psObDevRegPrefetch, pRegHelp->vaCmKeyControlBlock); } else if((pe->dwPoolTag & 0x00ffffff) == 'orP') { // PROCESS - pe->_Reserved.dw = *(PDWORD)(u.O32.pb + ctxVmm->offset.EPROCESS.PID); + pe->_Reserved.dw = *(PDWORD)(u.O32.pb + po->EPROCESS.PID); } else if(((pe->dwPoolTag & 0x00ffffff) == 'rhT') && fThreadingEnabled) { // THREAD - if(ctxVmm->offset.ETHREAD.oCid && *(PDWORD)(u.O32.pb + ctxVmm->offset.ETHREAD.oCid + 4)) { - pe->_Reserved.dw = *(PDWORD)(u.O32.pb + ctxVmm->offset.ETHREAD.oCid + 4); + if(po->ETHREAD.oCid && *(PDWORD)(u.O32.pb + po->ETHREAD.oCid + 4)) { + pe->_Reserved.dw = *(PDWORD)(u.O32.pb + po->ETHREAD.oCid + 4); } } else if((pe->dwPoolTag & 0x00ffffff) == 'liF') { // FILE HANDLE + // file name (from file object) pus32 = (PUNICODE_STRING32)(u.O32.pb + O32_FILE_OBJECT_FileName); + // ptr to DeviceObject (to retrieve its name) + va = *(PDWORD)(u.O32.pb + O32_FILE_OBJECT_DeviceObject); + if(VMM_KADDR32_4(va)) { + pe->_Reserved.qw3 = va; + ObSet_Push(psObDevRegPrefetch, va - 0x60); + } + // ptr to SectionObjectPointer (to retrieve file size) if((va = *(PDWORD)(u.O32.pb + O32_FILE_OBJECT_SectionObjectPointer)) && VMM_KADDR32_4(va)) { ObSet_Push(psObPrefetch, va); pe->tpInfoEx = HANDLEENTRY_TP_INFO_PRE_1; @@ -2076,13 +2100,12 @@ VOID VmmWinHandle_InitializeText_DoWork(_In_ PVMM_PROCESS pSystemProcess, _In_ P } else { for(i = 0; i < pHandleMap->cMap; i++) { pe = pHandleMap->pMap + i; - max(0x70, ctxVmm->offset.ETHREAD.oCid + 0x10); - VmmReadEx(pSystemProcess, pe->vaObject - 0x90, u.pb, cbObjectRead, &cbRead, VMM_FLAG_ZEROPAD_ON_FAIL | VMM_FLAG_FORCECACHE_READ); + VmmReadEx(H, pSystemProcess, pe->vaObject - 0x90, u.pb, cbObjectRead, &cbRead, VMM_FLAG_ZEROPAD_ON_FAIL | VMM_FLAG_FORCECACHE_READ); if(cbRead < 0x90) { continue; } // fetch and validate type index (if possible) - pe->iType = VmmWin_ObjectTypeGetIndexFromEncoded(pe->vaObject - 0x30, u.O64.Header.TypeIndex); + pe->iType = VmmWin_ObjectTypeGetIndexFromEncoded(H, pe->vaObject - 0x30, u.O64.Header.TypeIndex); // fetch pool tag (if found) - pe->dwPoolTag = VmmWinHandle_InitializeText_GetPoolHeader64(u.pb, &oPoolHdr); + pe->dwPoolTag = VmmWinHandle_InitializeText_GetPoolHeader64(H, u.pb, &oPoolHdr); // fetch remaining object header values pe->qwHandleCount = u.O64.Header.HandleCount; pe->qwPointerCount = u.O64.Header.PointerCount; @@ -2097,21 +2120,28 @@ VOID VmmWinHandle_InitializeText_DoWork(_In_ PVMM_PROCESS pSystemProcess, _In_ P if(!(pRegHelp = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMWINHANDLE_REGHELPER)))) { continue; } pRegHelp->vaCmKeyControlBlock = *(PQWORD)(u.O64.pb + 8); ObMap_Push(pmObRegHelperMap, pe->vaObject, pRegHelp); // map is responsible for free of pRegHelp - ObSet_Push(psObRegPrefetch, pRegHelp->vaCmKeyControlBlock); + ObSet_Push(psObDevRegPrefetch, pRegHelp->vaCmKeyControlBlock); } else if((pe->dwPoolTag & 0x00ffffff) == 'orP') { // PROCESS - pe->_Reserved.dw = *(PDWORD)(u.O64.pb + ctxVmm->offset.EPROCESS.PID); + pe->_Reserved.dw = *(PDWORD)(u.O64.pb + po->EPROCESS.PID); } else if(((pe->dwPoolTag & 0x00ffffff) == 'rhT') && fThreadingEnabled) { // THREAD - if(ctxVmm->offset.ETHREAD.oCid && *(PDWORD)(u.O64.pb + ctxVmm->offset.ETHREAD.oCid + 8)) { - pe->_Reserved.dw = *(PDWORD)(u.O64.pb + ctxVmm->offset.ETHREAD.oCid + 8); + if(po->ETHREAD.oCid && *(PDWORD)(u.O64.pb + po->ETHREAD.oCid + 8)) { + pe->_Reserved.dw = *(PDWORD)(u.O64.pb + po->ETHREAD.oCid + 8); } } else if((pe->dwPoolTag & 0x00ffffff) == 'liF') { // FILE HANDLE + // file name (from file object) pus64 = (PUNICODE_STRING64)(u.O64.pb + O64_FILE_OBJECT_FileName); + // ptr to DeviceObject (to retrieve its name) + va = *(PQWORD)(u.O64.pb + O64_FILE_OBJECT_DeviceObject); + if(VMM_KADDR64_8(va)) { + pe->_Reserved.qw3 = va; + ObSet_Push(psObDevRegPrefetch, va - 0x90); + } + // ptr to SectionObjectPointer (to retrieve file size) if((va = *(PQWORD)(u.O64.pb + O64_FILE_OBJECT_SectionObjectPointer)) && VMM_KADDR64_8(va)) { pe->tpInfoEx = HANDLEENTRY_TP_INFO_PRE_1; pe->_Reserved.qw2 = va; ObSet_Push(psObPrefetch, va); } - } else if(pe->dwPoolTag && (oPoolHdr <= 0x38)) { pus64 = &u.O64.String; } @@ -2126,16 +2156,54 @@ VOID VmmWinHandle_InitializeText_DoWork(_In_ PVMM_PROCESS pSystemProcess, _In_ P } } } - // registry key retrieve names - VmmCachePrefetchPages3(pSystemProcess, psObRegPrefetch, 0x30, 0); - VmmWinHandle_InitializeText_DoWork_RegKeyHelper(pSystemProcess, pmObRegHelperMap); + // registry key retrieve names & file device object parse + VmmCachePrefetchPages3(H, pSystemProcess, psObDevRegPrefetch, 0x90, 0); + for(i = 0; i < pHandleMap->cMap; i++) { + // file object -> device object name ptr + pe = pHandleMap->pMap + i; + va = pe->_Reserved.qw3; + pe->_Reserved.qw3 = 0; + if(va && (pe->dwPoolTag & 0x00ffffff) == 'liF') { + if(f32) { + VmmReadEx(H, pSystemProcess, va - 0x60, u.pb, cbObjectRead, &cbRead, VMM_FLAG_ZEROPAD_ON_FAIL | VMM_FLAG_FORCECACHE_READ); + if(cbRead < 0x60) { continue; } + dwTag = VmmWinHandle_InitializeText_GetPoolHeader32(H, u.pb, &oPoolHdr); + if((dwTag & 0x00ffffff) != 'veD') { continue; } + pus32 = &u.O32.String; + f = pus32 && (pus32->Length > 2) && + !(pus32->Length & 1) && (pus32->Length < (2 * MAX_PATH)) && (pus32->Length <= pus32->MaximumLength) && + VMM_KADDR32(pus32->Buffer); + if(f) { + pe->_Reserved.dw3 = pus32->Length; + pe->_Reserved.qw3 = pus32->Buffer; + ObSet_Push(psObPrefetch, pus32->Buffer); + } + } else { + VmmReadEx(H, pSystemProcess, va - 0x90, u.pb, cbObjectRead, &cbRead, VMM_FLAG_ZEROPAD_ON_FAIL | VMM_FLAG_FORCECACHE_READ); + if(cbRead < 0x90) { continue; } + dwTag = VmmWinHandle_InitializeText_GetPoolHeader64(H, u.pb, &oPoolHdr); + if((dwTag & 0x00ffffff) != 'veD') { continue; } + pus64 = &u.O64.String; + f = pus64 && (pus64->Length > 2) && + !(pus64->Length & 1) && (pus64->Length < (2 * MAX_PATH)) && (pus64->Length <= pus64->MaximumLength) && + VMM_KADDR64(pus64->Buffer); + if(f) { + pe->_Reserved.dw3 = pus64->Length; + pe->_Reserved.qw3 = pus64->Buffer; + ObSet_Push(psObPrefetch, pus64->Buffer); + } + } + } + } + VmmWinHandle_InitializeText_DoWork_RegKeyHelper(H, pSystemProcess, pmObRegHelperMap); // create and fill text descriptions // also get potential _FILE_OBJECT->SectionObjectPointer->SharedCacheMap (if applicable) - psmOb = ObStrMap_New(0); - VmmCachePrefetchPages3(pSystemProcess, psObPrefetch, MAX_PATH * 2, 0); + psmOb = ObStrMap_New(H, 0); + VmmCachePrefetchPages3(H, pSystemProcess, psObPrefetch, MAX_PATH * 2, 0); ObSet_Clear(psObPrefetch); for(i = 0; i < pHandleMap->cMap; i++) { pe = pHandleMap->pMap + i; + dwoName = 0; if((pe->dwPoolTag & 0x00ffffff) == 'yeK') { // REG KEY if((pRegHelp = ObMap_GetByKey(pmObRegHelperMap, pe->vaObject))) { if(pRegHelp->KeyInfo.uszName[0]) { @@ -2145,7 +2213,7 @@ VOID VmmWinHandle_InitializeText_DoWork(_In_ PVMM_PROCESS pSystemProcess, _In_ P } } } else if((pe->dwPoolTag & 0x00ffffff) == 'orP') { // PROCESS - if((pe->_Reserved.dw < 99999) && (pObProcessHnd = VmmProcessGet(pe->_Reserved.dw))) { + if((pe->_Reserved.dw < 99999) && (pObProcessHnd = VmmProcessGet(H, pe->_Reserved.dw))) { ObStrMap_PushUU_snprintf_s(psmOb, &pe->uszText, &pe->cbuText, "PID %i - %s", pObProcessHnd->dwPID, pObProcessHnd->szName); Ob_DECREF_NULL(&pObProcessHnd); } @@ -2154,24 +2222,32 @@ VOID VmmWinHandle_InitializeText_DoWork(_In_ PVMM_PROCESS pSystemProcess, _In_ P ObStrMap_PushUU_snprintf_s(psmOb, &pe->uszText, &pe->cbuText, "TID %i", pe->_Reserved.dw); } } else if(pe->_Reserved.qw) { - if(VmmReadWtoU(pSystemProcess, pe->_Reserved.qw, pe->_Reserved.dw, VMM_FLAG_FORCECACHE_READ, pbBuffer, sizeof(pbBuffer), &uszTMP, NULL, CHARUTIL_FLAG_TRUNCATE)) { - ObStrMap_PushPtrUU(psmOb, uszTMP, &pe->uszText, &pe->cbuText); + if(((pe->dwPoolTag & 0x00ffffff) == 'liF') && pe->_Reserved.qw3) { // FILE with DeviceObjectName + pbBuffer[dwoName++] = '\\'; + if(VmmReadWtoU(H, pSystemProcess, pe->_Reserved.qw3, pe->_Reserved.dw3, VMM_FLAG_FORCECACHE_READ, pbBuffer + dwoName, sizeof(pbBuffer) - dwoName, &uszTMP, NULL, CHARUTIL_FLAG_TRUNCATE)) { + dwoName = (DWORD)strlen((LPSTR)pbBuffer); + } + } + if(VmmReadWtoU(H, pSystemProcess, pe->_Reserved.qw, pe->_Reserved.dw, VMM_FLAG_FORCECACHE_READ, pbBuffer + dwoName, sizeof(pbBuffer) - dwoName, &uszTMP, NULL, CHARUTIL_FLAG_TRUNCATE)) { + ObStrMap_PushPtrUU(psmOb, (LPSTR)pbBuffer, &pe->uszText, &pe->cbuText); } } // Process _SECTION_OBJECT_POINTERS DataSectionObject&SharedCacheMap: - if((pe->tpInfoEx == HANDLEENTRY_TP_INFO_PRE_1) && VmmRead2(pSystemProcess, pe->_Reserved.qw2, u.pb, 0x18, VMM_FLAG_FORCECACHE_READ)) { + if((pe->tpInfoEx == HANDLEENTRY_TP_INFO_PRE_1) && VmmRead2(H, pSystemProcess, pe->_Reserved.qw2, u.pb, 0x18, VMM_FLAG_FORCECACHE_READ)) { pe->_InfoFile.cb = 0; - f = VMM_KADDR_4_8((va = VMM_PTR_OFFSET_DUAL(ctxVmm->f32, u.pb, O32_SECTION_OBJECT_POINTERS_SharedCacheMap, O64_SECTION_OBJECT_POINTERS_SharedCacheMap))) || - VMM_KADDR_4_8((va = VMM_PTR_OFFSET_DUAL(ctxVmm->f32, u.pb, O32_SECTION_OBJECT_POINTERS_DataSectionObject, O64_SECTION_OBJECT_POINTERS_DataSectionObject))); + f = VMM_KADDR_4_8(f32, (va = VMM_PTR_OFFSET_DUAL(f32, u.pb, O32_SECTION_OBJECT_POINTERS_SharedCacheMap, O64_SECTION_OBJECT_POINTERS_SharedCacheMap))) || + VMM_KADDR_4_8(f32, (va = VMM_PTR_OFFSET_DUAL(f32, u.pb, O32_SECTION_OBJECT_POINTERS_DataSectionObject, O64_SECTION_OBJECT_POINTERS_DataSectionObject))); if(f) { pe->_Reserved.qw = va; pe->tpInfoEx = HANDLEENTRY_TP_INFO_FILE; ObSet_Push(psObPrefetch, va - 0x10); } } + pe->_InfoFile.cb = 0; + pe->_InfoFile.dwoName = dwoName; } // retrieve (if applicable) file sizes - VmmWinHandle_InitializeText_DoWork_FileSizeHelper(pSystemProcess, psObPrefetch, pHandleMap); + VmmWinHandle_InitializeText_DoWork_FileSizeHelper(H, pSystemProcess, psObPrefetch, pHandleMap); // finish ObStrMap_FinalizeAllocU_DECREF_NULL(&psmOb, &pHandleMap->pbMultiText, &pHandleMap->cbMultiText); for(i = 0; i < pHandleMap->cMap; i++) { @@ -2183,15 +2259,15 @@ VOID VmmWinHandle_InitializeText_DoWork(_In_ PVMM_PROCESS pSystemProcess, _In_ P } fail: Ob_DECREF(psObPrefetch); - Ob_DECREF(psObRegPrefetch); + Ob_DECREF(psObDevRegPrefetch); Ob_DECREF(pmObRegHelperMap); Ob_DECREF(psmOb); } -VOID VmmWinHandle_InitializeCore_DoWork(_In_ PVMM_PROCESS pSystemProcess, _In_ PVMM_PROCESS pProcess) +VOID VmmWinHandle_InitializeCore_DoWork(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ PVMM_PROCESS pProcess) { BOOL fResult = FALSE; - BOOL f32 = ctxVmm->f32; + BOOL f32 = H->vmm.f32; BYTE pb[0x20], iLevel; WORD oTableCode; DWORD i, cHandles, iHandleMap = 0; @@ -2200,31 +2276,31 @@ VOID VmmWinHandle_InitializeCore_DoWork(_In_ PVMM_PROCESS pSystemProcess, _In_ P PVMMOB_MAP_HANDLE pObHandleMap = NULL; ctx.pSystemProcess = pSystemProcess; ctx.pProcess = pProcess; - vaHandleTable = VMM_PTR_OFFSET(f32, pProcess->win.EPROCESS.pb, ctxVmm->offset.EPROCESS.ObjectTable); - if(!VMM_KADDR(vaHandleTable) || !VmmRead(pSystemProcess, vaHandleTable - 0x10, pb, 0x20)) { return; } - if(!VMM_POOLTAG_PREPENDED(pb, 0x10, 'Obtb') && !VMM_KADDR_PAGE(vaHandleTable)) { return; } - oTableCode = (ctxVmm->kernel.dwVersionBuild < 9200) ? 0 : 8; // WinXP::Win7 -> 0, otherwise 8. + vaHandleTable = VMM_PTR_OFFSET(f32, pProcess->win.EPROCESS.pb, H->vmm.offset.EPROCESS.ObjectTable); + if(!VMM_KADDR(f32, vaHandleTable) || !VmmRead(H, pSystemProcess, vaHandleTable - 0x10, pb, 0x20)) { return; } + if(!VMM_POOLTAG_PREPENDED(f32, pb, 0x10, 'Obtb') && !VMM_KADDR_PAGE(f32, vaHandleTable)) { return; } + oTableCode = (H->vmm.kernel.dwVersionBuild < 9200) ? 0 : 8; // WinXP::Win7 -> 0, otherwise 8. vaTableCode = VMM_PTR_OFFSET(f32, pb + 0x10, oTableCode) & ~7; iLevel = VMM_PTR_OFFSET(f32, pb + 0x10, oTableCode) & 7; - if((iLevel > 2) || !VMM_KADDR_PAGE(vaTableCode)) { return; } + if((iLevel > 2) || !VMM_KADDR_PAGE(f32, vaTableCode)) { return; } ctx.cTablesMax = f32 ? 1024 : 512; ctx.cTablesMax = iLevel ? ((iLevel == 1) ? (ctx.cTablesMax * ctx.cTablesMax) : ctx.cTablesMax) : 1; if(!(ctx.pvaTables = LocalAlloc(0, ctx.cTablesMax * sizeof(QWORD)))) { return; } if(iLevel) { - VmmWinHandle_InitializeCore_SpiderTables(&ctx, vaTableCode, (iLevel == 2)); + VmmWinHandle_InitializeCore_SpiderTables(H, &ctx, vaTableCode, (iLevel == 2)); } else { ctx.cTables = 1; ctx.pvaTables[0] = vaTableCode; } // count handles and allocate map - if(!(cHandles = VmmWinHandle_InitializeCore_CountHandles(&ctx))) { goto fail; } + if(!(cHandles = VmmWinHandle_InitializeCore_CountHandles(H, &ctx))) { goto fail; } cHandles = min(cHandles, 256 * 1024); - ctx.pHandleMap = pObHandleMap = Ob_Alloc(OB_TAG_MAP_HANDLE, LMEM_ZEROINIT, sizeof(VMMOB_MAP_HANDLE) + cHandles * sizeof(VMM_MAP_HANDLEENTRY), (OB_CLEANUP_CB)VmmWinHandle_CloseObCallback, NULL); + ctx.pHandleMap = pObHandleMap = Ob_AllocEx(H, OB_TAG_MAP_HANDLE, LMEM_ZEROINIT, sizeof(VMMOB_MAP_HANDLE) + cHandles * sizeof(VMM_MAP_HANDLEENTRY), (OB_CLEANUP_CB)VmmWinHandle_CloseObCallback, NULL); if(!pObHandleMap) { goto fail; } pObHandleMap->cMap = cHandles; // walk handle tables to fill map with core handle information for(i = 0; i < ctx.cTables; i++) { - VmmWinHandle_InitializeCore_ReadHandleTable(&ctx, ctx.pvaTables[i], i * (f32 ? 2048 : 1024)); + VmmWinHandle_InitializeCore_ReadHandleTable(H, &ctx, ctx.pvaTables[i], i * (f32 ? 2048 : 1024)); } pObHandleMap->cMap = ctx.iMap; pProcess->Map.pObHandle = Ob_INCREF(pObHandleMap); @@ -2234,15 +2310,15 @@ fail: } _Success_(return) -BOOL VmmWinHandle_InitializeCore(_In_ PVMM_PROCESS pProcess) +BOOL VmmWinHandle_InitializeCore(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess) { PVMM_PROCESS pObSystemProcess; if(pProcess->Map.pObHandle) { return TRUE; } EnterCriticalSection(&pProcess->LockUpdate); - if(!pProcess->Map.pObHandle && (pObSystemProcess = VmmProcessGet(4))) { - VmmWinHandle_InitializeCore_DoWork(pObSystemProcess, pProcess); + if(!pProcess->Map.pObHandle && (pObSystemProcess = VmmProcessGet(H, 4))) { + VmmWinHandle_InitializeCore_DoWork(H, pObSystemProcess, pProcess); if(!pProcess->Map.pObHandle) { - pProcess->Map.pObHandle = Ob_Alloc(OB_TAG_MAP_HANDLE, LMEM_ZEROINIT, sizeof(VMMOB_MAP_HANDLE), (OB_CLEANUP_CB)VmmWinHandle_CloseObCallback, NULL); + pProcess->Map.pObHandle = Ob_AllocEx(H, OB_TAG_MAP_HANDLE, LMEM_ZEROINIT, sizeof(VMMOB_MAP_HANDLE), (OB_CLEANUP_CB)VmmWinHandle_CloseObCallback, NULL); } Ob_DECREF(pObSystemProcess); } @@ -2251,13 +2327,13 @@ BOOL VmmWinHandle_InitializeCore(_In_ PVMM_PROCESS pProcess) } _Success_(return) -BOOL VmmWinHandle_InitializeText(_In_ PVMM_PROCESS pProcess) +BOOL VmmWinHandle_InitializeText(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess) { PVMM_PROCESS pObSystemProcess; if(pProcess->Map.pObHandle->pbMultiText) { return TRUE; } EnterCriticalSection(&pProcess->Map.LockUpdateThreadExtendedInfo); - if(!pProcess->Map.pObHandle->pbMultiText && (pObSystemProcess = VmmProcessGet(4))) { - VmmWinHandle_InitializeText_DoWork(pObSystemProcess, pProcess->Map.pObHandle); + if(!pProcess->Map.pObHandle->pbMultiText && (pObSystemProcess = VmmProcessGet(H, 4))) { + VmmWinHandle_InitializeText_DoWork(H, pObSystemProcess, pProcess->Map.pObHandle); Ob_DECREF(pObSystemProcess); } LeaveCriticalSection(&pProcess->Map.LockUpdateThreadExtendedInfo); @@ -2267,15 +2343,16 @@ BOOL VmmWinHandle_InitializeText(_In_ PVMM_PROCESS pProcess) /* * Initialize Handles for a specific process. Extended information text may take * extra time to initialize. +* -- H * -- pProcess * -- fExtendedText = also fetch extended info such as handle paths/names. * -- return */ _Success_(return) -BOOL VmmWinHandle_Initialize(_In_ PVMM_PROCESS pProcess, _In_ BOOL fExtendedText) +BOOL VmmWinHandle_Initialize(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ BOOL fExtendedText) { if(pProcess->Map.pObHandle && (!fExtendedText || pProcess->Map.pObHandle->pbMultiText)) { return TRUE; } - return VmmWinHandle_InitializeCore(pProcess) && (!fExtendedText || VmmWinHandle_InitializeText(pProcess)); + return VmmWinHandle_InitializeCore(H, pProcess) && (!fExtendedText || VmmWinHandle_InitializeText(H, pProcess)); } // ---------------------------------------------------------------------------- @@ -2307,12 +2384,13 @@ typedef struct tdVMMWIN_PHYSMEMMAP_REGISTRY_MEMORY_RANGE64 { * Retrieve the physical memory by parsing the registry. This is only used as a * fallback in case it cannot be parsed from kernel due to the extra overhead * by parsing the registry hardware hive. +* -- H * -- return */ _Success_(return != NULL) -PVMMOB_MAP_PHYSMEM VmmWinPhysMemMap_InitializeFromRegistry_DoWork() +PVMMOB_MAP_PHYSMEM VmmWinPhysMemMap_InitializeFromRegistry_DoWork(_In_ VMM_HANDLE H) { - BOOL f32 = ctxVmm->f32; + BOOL f32 = H->vmm.f32; DWORD cMap, cbData = 0; PBYTE pbData = NULL; QWORD c1, i, o; @@ -2320,9 +2398,9 @@ PVMMOB_MAP_PHYSMEM VmmWinPhysMemMap_InitializeFromRegistry_DoWork() PVMMWIN_PHYSMEMMAP_REGISTRY_MEMORY_RANGE64 pMR64; PVMMOB_MAP_PHYSMEM pObPhysMemMap = NULL; // 1: fetch binary data from registry - if(!VmmWinReg_ValueQuery2("HKLM\\HARDWARE\\RESOURCEMAP\\System Resources\\Physical Memory\\.Translated", NULL, NULL, 0, &cbData) || !cbData) { goto fail; } + if(!VmmWinReg_ValueQuery2(H, "HKLM\\HARDWARE\\RESOURCEMAP\\System Resources\\Physical Memory\\.Translated", NULL, NULL, 0, &cbData) || !cbData) { goto fail; } if(!(pbData = LocalAlloc(0, cbData))) { goto fail; } - if(!VmmWinReg_ValueQuery2("HKLM\\HARDWARE\\RESOURCEMAP\\System Resources\\Physical Memory\\.Translated", NULL, pbData, cbData, &cbData)) { goto fail; } + if(!VmmWinReg_ValueQuery2(H, "HKLM\\HARDWARE\\RESOURCEMAP\\System Resources\\Physical Memory\\.Translated", NULL, pbData, cbData, &cbData)) { goto fail; } if(cbData < (DWORD)(f32 ? 0x18 : 0x28)) { goto fail; } // 2: fetch number of memory regions and allocate map object. c1 = *(PQWORD)pbData; @@ -2331,7 +2409,7 @@ PVMMOB_MAP_PHYSMEM VmmWinPhysMemMap_InitializeFromRegistry_DoWork() cMap = *(PDWORD)(pbData + o); // this should be loop in case of c1 > 1, but works for now ... if(f32 && (!cMap || (cbData < cMap * sizeof(VMMWIN_PHYSMEMMAP_REGISTRY_MEMORY_RANGE32) + 0x0c))) { goto fail; } if(!f32 && (!cMap || (cbData < cMap * sizeof(VMMWIN_PHYSMEMMAP_REGISTRY_MEMORY_RANGE64) + 0x14))) { goto fail; } - if(!(pObPhysMemMap = Ob_Alloc(OB_TAG_MAP_PHYSMEM, LMEM_ZEROINIT, sizeof(VMMOB_MAP_PHYSMEM) + cMap * sizeof(VMM_MAP_PHYSMEMENTRY), NULL, NULL))) { goto fail; } + if(!(pObPhysMemMap = Ob_AllocEx(H, OB_TAG_MAP_PHYSMEM, LMEM_ZEROINIT, sizeof(VMMOB_MAP_PHYSMEM) + cMap * sizeof(VMM_MAP_PHYSMEMENTRY), NULL, NULL))) { goto fail; } pObPhysMemMap->cMap = cMap; // 3: iterate over the memory regions. o += sizeof(DWORD); @@ -2365,23 +2443,24 @@ fail: * Retrieve the physical memory map from the kernel by parsing the kernel symbol * 'MmPhysicalMemoryBlock'. This is the preferred way of fetching the memory map * due to better efficiency as compared to fallback - parsing from registry. +* -- H * -- return */ _Success_(return != NULL) -PVMMOB_MAP_PHYSMEM VmmWinPhysMemMap_InitializeFromKernel_DoWork() +PVMMOB_MAP_PHYSMEM VmmWinPhysMemMap_InitializeFromKernel_DoWork(_In_ VMM_HANDLE H) { QWORD i, c, vaPhysicalMemoryBlock = 0; _PHYSICAL_MEMORY_DESCRIPTOR32 Md32; _PHYSICAL_MEMORY_DESCRIPTOR64 Md64; PVMM_PROCESS pObSystemProcess = NULL; PVMMOB_MAP_PHYSMEM pObMemMap = NULL; - if(!(pObSystemProcess = VmmProcessGet(4))) { goto fail; } - if(!PDB_GetSymbolPTR(PDB_HANDLE_KERNEL, "MmPhysicalMemoryBlock", pObSystemProcess, (PVOID)&vaPhysicalMemoryBlock)) { goto fail; } - if(!VMM_KADDR_4_8(vaPhysicalMemoryBlock)) { goto fail; } - if(ctxVmm->f32) { - if(!VmmRead2(pObSystemProcess, vaPhysicalMemoryBlock, (PBYTE)&Md32, sizeof(_PHYSICAL_MEMORY_DESCRIPTOR32), VMMDLL_FLAG_ZEROPAD_ON_FAIL)) { goto fail; } + if(!(pObSystemProcess = VmmProcessGet(H, 4))) { goto fail; } + if(!PDB_GetSymbolPTR(H, PDB_HANDLE_KERNEL, "MmPhysicalMemoryBlock", pObSystemProcess, (PVOID)&vaPhysicalMemoryBlock)) { goto fail; } + if(!VMM_KADDR_4_8(H->vmm.f32, vaPhysicalMemoryBlock)) { goto fail; } + if(H->vmm.f32) { + if(!VmmRead2(H, pObSystemProcess, vaPhysicalMemoryBlock, (PBYTE)&Md32, sizeof(_PHYSICAL_MEMORY_DESCRIPTOR32), VMMDLL_FLAG_ZEROPAD_ON_FAIL)) { goto fail; } if(!Md32.NumberOfRuns || (Md32.NumberOfRuns > _PHYSICAL_MEMORY_MAX_RUNS)) { goto fail; } - if(!(pObMemMap = Ob_Alloc(OB_TAG_MAP_PHYSMEM, LMEM_ZEROINIT, sizeof(VMMOB_MAP_PHYSMEM) + Md32.NumberOfRuns * sizeof(VMM_MAP_PHYSMEMENTRY), NULL, NULL))) { goto fail; } + if(!(pObMemMap = Ob_AllocEx(H, OB_TAG_MAP_PHYSMEM, LMEM_ZEROINIT, sizeof(VMMOB_MAP_PHYSMEM) + Md32.NumberOfRuns * sizeof(VMM_MAP_PHYSMEMENTRY), NULL, NULL))) { goto fail; } pObMemMap->cMap = Md32.NumberOfRuns; for(i = 0, c = 0; i < Md32.NumberOfRuns; i++) { pObMemMap->pMap[i].pa = (QWORD)Md32.Run[i].BasePage << 12; @@ -2391,9 +2470,9 @@ PVMMOB_MAP_PHYSMEM VmmWinPhysMemMap_InitializeFromKernel_DoWork() } if(c != Md32.NumberOfPages) { goto fail; } } else { - if(!VmmRead2(pObSystemProcess, vaPhysicalMemoryBlock, (PBYTE)&Md64, sizeof(_PHYSICAL_MEMORY_DESCRIPTOR64), VMMDLL_FLAG_ZEROPAD_ON_FAIL)) { goto fail; } + if(!VmmRead2(H, pObSystemProcess, vaPhysicalMemoryBlock, (PBYTE)&Md64, sizeof(_PHYSICAL_MEMORY_DESCRIPTOR64), VMMDLL_FLAG_ZEROPAD_ON_FAIL)) { goto fail; } if(!Md64.NumberOfRuns || (Md64.NumberOfRuns > _PHYSICAL_MEMORY_MAX_RUNS)) { goto fail; } - if(!(pObMemMap = Ob_Alloc(OB_TAG_MAP_PHYSMEM, LMEM_ZEROINIT, sizeof(VMMOB_MAP_PHYSMEM) + Md64.NumberOfRuns * sizeof(VMM_MAP_PHYSMEMENTRY), NULL, NULL))) { goto fail; } + if(!(pObMemMap = Ob_AllocEx(H, OB_TAG_MAP_PHYSMEM, LMEM_ZEROINIT, sizeof(VMMOB_MAP_PHYSMEM) + Md64.NumberOfRuns * sizeof(VMM_MAP_PHYSMEMENTRY), NULL, NULL))) { goto fail; } pObMemMap->cMap = Md64.NumberOfRuns; for(i = 0, c = 0; i < Md64.NumberOfRuns; i++) { pObMemMap->pMap[i].pa = Md64.Run[i].BasePage << 12; @@ -2412,35 +2491,37 @@ fail: /* * Create a physical memory map and assign to the global context upon success. * CALLER DECREF: return +* -- H * -- return */ -PVMMOB_MAP_PHYSMEM VmmWinPhysMemMap_Initialize() +PVMMOB_MAP_PHYSMEM VmmWinPhysMemMap_Initialize(_In_ VMM_HANDLE H) { PVMMOB_MAP_PHYSMEM pObPhysMem; - if((pObPhysMem = ObContainer_GetOb(ctxVmm->pObCMapPhysMem))) { return pObPhysMem; } - EnterCriticalSection(&ctxVmm->LockUpdateMap); - if((pObPhysMem = ObContainer_GetOb(ctxVmm->pObCMapPhysMem))) { - LeaveCriticalSection(&ctxVmm->LockUpdateMap); + if((pObPhysMem = ObContainer_GetOb(H->vmm.pObCMapPhysMem))) { return pObPhysMem; } + EnterCriticalSection(&H->vmm.LockUpdateMap); + if((pObPhysMem = ObContainer_GetOb(H->vmm.pObCMapPhysMem))) { + LeaveCriticalSection(&H->vmm.LockUpdateMap); return pObPhysMem; } - pObPhysMem = VmmWinPhysMemMap_InitializeFromKernel_DoWork(); + pObPhysMem = VmmWinPhysMemMap_InitializeFromKernel_DoWork(H); if(!pObPhysMem) { // fallback to parsing registry (if error on no loaded symbols) - pObPhysMem = VmmWinPhysMemMap_InitializeFromRegistry_DoWork(); + pObPhysMem = VmmWinPhysMemMap_InitializeFromRegistry_DoWork(H); } if(!pObPhysMem) { - pObPhysMem = Ob_Alloc(OB_TAG_MAP_PHYSMEM, LMEM_ZEROINIT, sizeof(VMMOB_MAP_PHYSMEM), NULL, NULL); + pObPhysMem = Ob_AllocEx(H, OB_TAG_MAP_PHYSMEM, LMEM_ZEROINIT, sizeof(VMMOB_MAP_PHYSMEM), NULL, NULL); } - ObContainer_SetOb(ctxVmm->pObCMapPhysMem, pObPhysMem); - LeaveCriticalSection(&ctxVmm->LockUpdateMap); + ObContainer_SetOb(H->vmm.pObCMapPhysMem, pObPhysMem); + LeaveCriticalSection(&H->vmm.LockUpdateMap); return pObPhysMem; } /* * Refresh the physical memory map. +* -- H */ -VOID VmmWinPhysMemMap_Refresh() +VOID VmmWinPhysMemMap_Refresh(_In_ VMM_HANDLE H) { - ObContainer_SetOb(ctxVmm->pObCMapPhysMem, NULL); + ObContainer_SetOb(H->vmm.pObCMapPhysMem, NULL); } // ---------------------------------------------------------------------------- @@ -2456,6 +2537,7 @@ VOID VmmWinPhysMemMap_Refresh() * Retrieve the account name of the user account given a SID. * NB! Names for well known SIDs will be given in the language of the system * running MemProcFS and not in the name of the analyzed system. +* -- H * -- pSID * -- uszName * -- cbuName @@ -2463,7 +2545,7 @@ VOID VmmWinPhysMemMap_Refresh() * -- return */ _Success_(return) -BOOL VmmWinUser_GetName(_In_opt_ PSID pSID, _Out_writes_(cbuName) LPSTR uszName, _In_ DWORD cbuName, _Out_opt_ PBOOL pfAccountWellKnown) +BOOL VmmWinUser_GetName(_In_ VMM_HANDLE H, _In_opt_ PSID pSID, _Out_writes_(cbuName) LPSTR uszName, _In_ DWORD cbuName, _Out_opt_ PBOOL pfAccountWellKnown) { BOOL f; SID_NAME_USE eUse; @@ -2477,7 +2559,7 @@ BOOL VmmWinUser_GetName(_In_opt_ PSID pSID, _Out_writes_(cbuName) LPSTR uszName, if(!ConvertSidToStringSidA(pSID, &szSID)) { return FALSE; } dwHashSID = CharUtil_Hash32A(szSID, FALSE); LocalFree(szSID); - if(VmmMap_GetUser(&pObUser)) { + if(VmmMap_GetUser(H, &pObUser)) { for(i = 0; i < pObUser->cMap; i++) { if(dwHashSID != pObUser->pMap[i].dwHashSID) { continue; } // user entry located @@ -2517,31 +2599,35 @@ VOID VmmWinUser_CloseObCallback(_In_ PVOID pVmmUserMap) /* * Fill the pmOb map with user information grabbed from the SOFTWARE hive profiles: * HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList +* -- H * -- pmOb */ -VOID VmmWinUser_Initialize_DoWork_ProfileReg(_In_ POB_MAP pmOb) +VOID VmmWinUser_Initialize_DoWork_ProfileReg(_In_ VMM_HANDLE H, _In_ POB_MAP pmOb) { BOOL f; DWORD dwType, cbBuffer; BYTE pbBuffer[MAX_PATH]; BYTE szBufferPath[MAX_PATH]; POB_REGISTRY_HIVE pObHive = NULL; - POB_REGISTRY_KEY pObKeyParent, pObKey; - POB_REGISTRY_VALUE pObValue; + POB_REGISTRY_KEY pObKeyParent, pObKey = NULL; + POB_REGISTRY_VALUE pObValue = NULL; POB_MAP pmObKeys; VMM_REGISTRY_KEY_INFO KeyInfo; VMM_MAP_USERENTRY e; - if(VmmWinReg_KeyHiveGetByFullPath("HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList", &pObHive, &pObKeyParent)) { - pmObKeys = VmmWinReg_KeyList(pObHive, pObKeyParent); - while((pObKey = ObMap_Pop(pmObKeys))) { + if(VmmWinReg_KeyHiveGetByFullPath(H, "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList", &pObHive, &pObKeyParent)) { + pmObKeys = VmmWinReg_KeyList(H, pObHive, pObKeyParent); + while(TRUE) { + if(pObKey) { Ob_DECREF_NULL(&pObKey); } + if(!(pObKey = ObMap_Pop(pmObKeys))) { break; } VmmWinReg_KeyInfo(pObHive, pObKey, &KeyInfo); if(_strnicmp(KeyInfo.uszName, "S-1-5-21-", 9)) { continue; } e.dwHashSID = CharUtil_Hash32A(KeyInfo.uszName, FALSE); if(ObMap_ExistsKey(pmOb, e.dwHashSID)) { continue; } - f = (pObValue = VmmWinReg_KeyValueGetByName(pObHive, pObKey, "ProfileImagePath")) && - VmmWinReg_ValueQuery4(pObHive, pObValue, &dwType, pbBuffer, sizeof(pbBuffer), &cbBuffer) && + f = (pObValue = VmmWinReg_KeyValueGetByName(H, pObHive, pObKey, "ProfileImagePath")) && + VmmWinReg_ValueQuery4(H, pObHive, pObValue, &dwType, pbBuffer, sizeof(pbBuffer), &cbBuffer) && ((dwType == REG_SZ) || (dwType == REG_EXPAND_SZ)) && CharUtil_WtoU((LPWSTR)pbBuffer, cbBuffer / 2, szBufferPath, sizeof(szBufferPath), NULL, NULL, CHARUTIL_FLAG_TRUNCATE | CHARUTIL_FLAG_STR_BUFONLY); + Ob_DECREF_NULL(&pObValue); if(!f) { continue; } e.cbSID = 0; e.cbuText = 0; @@ -2564,9 +2650,10 @@ VOID VmmWinUser_Initialize_DoWork_ProfileReg(_In_ POB_MAP pmOb) /* * Fill the pmOb map with user information by walking potential user hives. +* -- H * -- pmOb */ -VOID VmmWinUser_Initialize_DoWork_UserHive(_In_ POB_MAP pmOb) +VOID VmmWinUser_Initialize_DoWork_UserHive(_In_ VMM_HANDLE H, _In_ POB_MAP pmOb) { BOOL f; VMM_MAP_USERENTRY e; @@ -2577,7 +2664,7 @@ VOID VmmWinUser_Initialize_DoWork_UserHive(_In_ POB_MAP pmOb) LPSTR szHiveUser, szHiveNtdat; LPWSTR wszSymlinkSid, wszSymlinkUser; POB_REGISTRY_HIVE pObHive = NULL; - while((pObHive = VmmWinReg_HiveGetNext(pObHive))) { + while((pObHive = VmmWinReg_HiveGetNext(H, pObHive))) { szBufferUser[0] = 0; ZeroMemory(&e, sizeof(VMM_MAP_USERENTRY)); szHiveUser = StrStrIA(pObHive->uszName, "-USER_S-"); @@ -2589,17 +2676,17 @@ VOID VmmWinUser_Initialize_DoWork_UserHive(_In_ POB_MAP pmOb) if(!szHiveUser && !StrStrIA(szHiveNtdat, "-unknown")) { continue; } if(szHiveUser && ((strlen(szHiveUser) < 20) || StrStrIA(szHiveUser, "Classes"))) { continue; } // get username - f = VmmWinReg_ValueQuery1(pObHive, "ROOT\\Volatile Environment\\USERNAME", &dwType, NULL, pbBuffer, sizeof(pbBuffer) - 2, &cbBuffer, 0) && + f = VmmWinReg_ValueQuery1(H, pObHive, "ROOT\\Volatile Environment\\USERNAME", &dwType, NULL, pbBuffer, sizeof(pbBuffer) - 2, &cbBuffer, 0) && (dwType == REG_SZ) && CharUtil_WtoU((LPWSTR)pbBuffer, cbBuffer / 2, szBufferUser, sizeof(szBufferUser), NULL, NULL, CHARUTIL_FLAG_TRUNCATE | CHARUTIL_FLAG_STR_BUFONLY); - if(!f && (ctxVmm->kernel.dwVersionBuild > 2600)) { continue; } // allow missing USERNAME only if WinXP + if(!f && (H->vmm.kernel.dwVersionBuild > 2600)) { continue; } // allow missing USERNAME only if WinXP // get sid if(szHiveUser) { ConvertStringSidToSidA(szHiveUser + 6, &e.pSID); } if(!e.pSID) { i = 0; - if(!VmmWinReg_ValueQuery1(pObHive, "ROOT\\Software\\Classes\\SymbolicLinkValue", &dwType, NULL, (PBYTE)wszBufferSymlink, sizeof(wszBufferSymlink) - 2, NULL, 0) || (dwType != REG_LINK)) { continue; } + if(!VmmWinReg_ValueQuery1(H, pObHive, "ROOT\\Software\\Classes\\SymbolicLinkValue", &dwType, NULL, (PBYTE)wszBufferSymlink, sizeof(wszBufferSymlink) - 2, NULL, 0) || (dwType != REG_LINK)) { continue; } wszBufferSymlink[MAX_PATH - 1] = 0; if(!(wszSymlinkSid = wcsstr(wszBufferSymlink, L"\\S-"))) { continue; } if(wcslen(wszSymlinkSid) < 20) { continue; } @@ -2608,7 +2695,7 @@ VOID VmmWinUser_Initialize_DoWork_UserHive(_In_ POB_MAP pmOb) if(!ConvertStringSidToSidW(wszSymlinkSid + 1, &e.pSID) || !e.pSID) { continue; } } // get username - WinXP only - if(!szBufferUser[0] && (ctxVmm->kernel.dwVersionBuild <= 2600)) { + if(!szBufferUser[0] && (H->vmm.kernel.dwVersionBuild <= 2600)) { i = 0; wszSymlinkUser = wszBufferSymlink + 10; while(wszSymlinkUser[i] && (wszSymlinkUser[i] != L'\\') && ++i); @@ -2641,27 +2728,28 @@ VOID VmmWinUser_Initialize_DoWork_UserHive(_In_ POB_MAP pmOb) * Create a user map and assign it to the ctxVmm global context upon success. * NB! function must be called in single-threaded context. * CALLER DECREF: return +* -- H * -- return */ -PVMMOB_MAP_USER VmmWinUser_Initialize_DoWork() +PVMMOB_MAP_USER VmmWinUser_Initialize_DoWork(_In_ VMM_HANDLE H) { DWORD i; POB_MAP pmOb = NULL; POB_STRMAP psmOb = NULL; PVMM_MAP_USERENTRY pe, peDst, peSrc; PVMMOB_MAP_USER pObMapUser = NULL; - if(!(pmOb = ObMap_New(OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } + if(!(pmOb = ObMap_New(H, OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } // 1: user hive enumeration (from user registry hives) - VmmWinUser_Initialize_DoWork_UserHive(pmOb); + VmmWinUser_Initialize_DoWork_UserHive(H, pmOb); // 2: user profile enumeration (from software hive) // this is quite performance intense (and will slow down start-up) -> // avoid loading users using this method for now (unless command line forensic mode). - if(ctxMain->cfg.tpForensicMode) { - VmmWinUser_Initialize_DoWork_ProfileReg(pmOb); + if(H->cfg.tpForensicMode) { + VmmWinUser_Initialize_DoWork_ProfileReg(H, pmOb); } // 3: create user map and assign data - if(!(psmOb = ObStrMap_New(OB_STRMAP_FLAGS_CASE_INSENSITIVE))) { goto fail; } - if(!(pObMapUser = Ob_Alloc(OB_TAG_MAP_USER, LMEM_ZEROINIT, sizeof(VMMOB_MAP_USER) + ObMap_Size(pmOb) * sizeof(VMM_MAP_USERENTRY), VmmWinUser_CloseObCallback, NULL))) { goto fail; } + if(!(psmOb = ObStrMap_New(H, OB_STRMAP_FLAGS_CASE_INSENSITIVE))) { goto fail; } + if(!(pObMapUser = Ob_AllocEx(H, OB_TAG_MAP_USER, LMEM_ZEROINIT, sizeof(VMMOB_MAP_USER) + ObMap_Size(pmOb) * sizeof(VMM_MAP_USERENTRY), VmmWinUser_CloseObCallback, NULL))) { goto fail; } pObMapUser->cMap = ObMap_Size(pmOb); for(i = 0; i < pObMapUser->cMap; i++) { peSrc = ObMap_GetByIndex(pmOb, i); @@ -2690,38 +2778,40 @@ fail: /* * Create a user map and assign to the global context upon success. * CALLER DECREF: return +* -- H * -- return */ -PVMMOB_MAP_USER VmmWinUser_Initialize() +PVMMOB_MAP_USER VmmWinUser_Initialize(_In_ VMM_HANDLE H) { PVMMOB_MAP_USER pObUser; - if((pObUser = ObContainer_GetOb(ctxVmm->pObCMapUser))) { return pObUser; } - EnterCriticalSection(&ctxVmm->LockUpdateMap); - if((pObUser = ObContainer_GetOb(ctxVmm->pObCMapUser))) { - LeaveCriticalSection(&ctxVmm->LockUpdateMap); + if((pObUser = ObContainer_GetOb(H->vmm.pObCMapUser))) { return pObUser; } + EnterCriticalSection(&H->vmm.LockUpdateMap); + if((pObUser = ObContainer_GetOb(H->vmm.pObCMapUser))) { + LeaveCriticalSection(&H->vmm.LockUpdateMap); return pObUser; } - pObUser = VmmWinUser_Initialize_DoWork(); + pObUser = VmmWinUser_Initialize_DoWork(H); if(!pObUser) { - pObUser = Ob_Alloc(OB_TAG_MAP_USER, LMEM_ZEROINIT, sizeof(VMMOB_MAP_USER), NULL, NULL); + pObUser = Ob_AllocEx(H, OB_TAG_MAP_USER, LMEM_ZEROINIT, sizeof(VMMOB_MAP_USER), NULL, NULL); } - ObContainer_SetOb(ctxVmm->pObCMapUser, pObUser); - LeaveCriticalSection(&ctxVmm->LockUpdateMap); + ObContainer_SetOb(H->vmm.pObCMapUser, pObUser); + LeaveCriticalSection(&H->vmm.LockUpdateMap); return pObUser; } #endif /* _WIN32 */ #ifdef LINUX -_Success_(return) BOOL VmmWinUser_GetName(_In_opt_ PSID pSID, _Out_writes_(cbuName) LPSTR uszName, _In_ DWORD cbuName, _Out_opt_ PBOOL pfAccountWellKnown) { return FALSE; } -PVMMOB_MAP_USER VmmWinUser_Initialize() { return NULL; } +_Success_(return) BOOL VmmWinUser_GetName(_In_ VMM_HANDLE H, _In_opt_ PSID pSID, _Out_writes_(cbuName) LPSTR uszName, _In_ DWORD cbuName, _Out_opt_ PBOOL pfAccountWellKnown) { return FALSE; } +PVMMOB_MAP_USER VmmWinUser_Initialize(_In_ VMM_HANDLE H) { return NULL; } #endif /* LINUX */ /* * Refresh the user map. +* -- H */ -VOID VmmWinUser_Refresh() +VOID VmmWinUser_Refresh(_In_ VMM_HANDLE H) { - ObContainer_SetOb(ctxVmm->pObCMapUser, NULL); + ObContainer_SetOb(H->vmm.pObCMapUser, NULL); } // ---------------------------------------------------------------------------- @@ -2731,20 +2821,20 @@ VOID VmmWinUser_Refresh() #define VMMPROC_EPROCESS64_MAX_SIZE 0x800 #define VMMPROC_EPROCESS32_MAX_SIZE 0x480 -VOID VmmWinProcess_OffsetLocator_Print() +VOID VmmWinProcess_OffsetLocator_Print(_In_ VMM_HANDLE H) { - PVMM_OFFSET_EPROCESS po = &ctxVmm->offset.EPROCESS; - VmmLog(MID_PROCESS, LOGLEVEL_DEBUG, "OK: %s", + PVMM_OFFSET_EPROCESS po = &H->vmm.offset.EPROCESS; + VmmLog(H, MID_PROCESS, LOGLEVEL_DEBUG, "OK: %s", (po->fValid ? "TRUE" : "FALSE")); - VmmLog(MID_PROCESS, LOGLEVEL_DEBUG, " PID: %03x PPID: %03x STAT: %03x DTB: %03x DTBU: %03x NAME: %03x PEB: %03x", + VmmLog(H, MID_PROCESS, LOGLEVEL_DEBUG, " PID: %03x PPID: %03x STAT: %03x DTB: %03x DTBU: %03x NAME: %03x PEB: %03x", po->PID, po->PPID, po->State, po->DTB, po->DTB_User, po->Name, po->PEB); - VmmLog(MID_PROCESS, LOGLEVEL_DEBUG, " FLnk: %03x BLnk: %03x oMax: %03x SeAu: %03x VadR: %03x ObjT: %03x WoW: %03x", + VmmLog(H, MID_PROCESS, LOGLEVEL_DEBUG, " FLnk: %03x BLnk: %03x oMax: %03x SeAu: %03x VadR: %03x ObjT: %03x WoW: %03x", po->FLink, po->BLink, po->cbMaxOffset, po->SeAuditProcessCreationInfo, po->VadRoot, po->ObjectTable, po->Wow64Process); } -VOID VmmWinProcess_OffsetLocator_SetMaxOffset() +VOID VmmWinProcess_OffsetLocator_SetMaxOffset(_In_ VMM_HANDLE H) { - PVMM_OFFSET_EPROCESS po = &ctxVmm->offset.EPROCESS; + PVMM_OFFSET_EPROCESS po = &H->vmm.offset.EPROCESS; WORD o; o = max(po->opt.CreateTime, po->opt.ExitTime); o = max(max(o, po->State), max(po->DTB, po->DTB_User)); @@ -2759,24 +2849,24 @@ VOID VmmWinProcess_OffsetLocator_SetMaxOffset() * This is more resilient - but also add a slow dependency on the symbol server so only * use this as a fallback for now. */ -VOID VmmWinProcess_OffsetLocatorSYMSERV(_In_ PVMM_PROCESS pSystemProcess) +VOID VmmWinProcess_OffsetLocatorSYMSERV(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess) { - PVMM_OFFSET_EPROCESS po = &ctxVmm->offset.EPROCESS; - InfoDB_Initialize(); - PDB_Initialize(NULL, FALSE); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_DISPATCHER_HEADER", "SignalState", &po->State); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_KPROCESS", "DirectoryTableBase", &po->DTB); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_KPROCESS", "UserDirectoryTableBase", &po->DTB_User); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_EPROCESS", "ImageFileName", &po->Name); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_EPROCESS", "UniqueProcessId", &po->PID); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_EPROCESS", "InheritedFromUniqueProcessId", &po->PPID); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_EPROCESS", "ActiveProcessLinks", &po->FLink); - po->BLink = po->FLink + ctxVmm->f32 ? 4 : 8; - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_EPROCESS", "Peb", &po->PEB); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_EPROCESS", "SeAuditProcessCreationInfo", &po->SeAuditProcessCreationInfo); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_EPROCESS", "VadRoot", &po->VadRoot); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_EPROCESS", "ObjectTable", &po->ObjectTable); - if(!ctxVmm->f32) { + PVMM_OFFSET_EPROCESS po = &H->vmm.offset.EPROCESS; + InfoDB_Initialize(H); + PDB_Initialize(H, NULL, FALSE); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_DISPATCHER_HEADER", "SignalState", &po->State); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_KPROCESS", "DirectoryTableBase", &po->DTB); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_KPROCESS", "UserDirectoryTableBase", &po->DTB_User); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_EPROCESS", "ImageFileName", &po->Name); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_EPROCESS", "UniqueProcessId", &po->PID); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_EPROCESS", "InheritedFromUniqueProcessId", &po->PPID); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_EPROCESS", "ActiveProcessLinks", &po->FLink); + po->BLink = po->FLink + H->vmm.f32 ? 4 : 8; + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_EPROCESS", "Peb", &po->PEB); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_EPROCESS", "SeAuditProcessCreationInfo", &po->SeAuditProcessCreationInfo); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_EPROCESS", "VadRoot", &po->VadRoot); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_EPROCESS", "ObjectTable", &po->ObjectTable); + if(!H->vmm.f32) { if(po->Name < po->PEB) { po->f64VistaOr7 = TRUE; po->Wow64Process = po->Name + 0x40; // Vista, Win7 @@ -2784,16 +2874,16 @@ VOID VmmWinProcess_OffsetLocatorSYMSERV(_In_ PVMM_PROCESS pSystemProcess) po->Wow64Process = po->PEB + 0x30; // Win8, Win10 } } - PDB_GetTypeSizeShort(PDB_HANDLE_KERNEL, "_EPROCESS", &po->cbMaxOffset); + PDB_GetTypeSizeShort(H, PDB_HANDLE_KERNEL, "_EPROCESS", &po->cbMaxOffset); po->fValid = po->State && po->DTB && po->Name && po->PPID && po->FLink && po->PEB && po->VadRoot && po->SeAuditProcessCreationInfo && po->ObjectTable; } /* * Very ugly hack that tries to locate some offsets required within the EPROCESS struct. */ -VOID VmmWinProcess_OffsetLocator64(_In_ PVMM_PROCESS pSystemProcess) +VOID VmmWinProcess_OffsetLocator64(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess) { - PVMM_OFFSET_EPROCESS po = &ctxVmm->offset.EPROCESS; + PVMM_OFFSET_EPROCESS po = &H->vmm.offset.EPROCESS; BOOL f; WORD i, j, cLoopProtect; QWORD va1, vaPEB, paPEB, vaP, oP; @@ -2802,8 +2892,8 @@ VOID VmmWinProcess_OffsetLocator64(_In_ PVMM_PROCESS pSystemProcess) QWORD paMax, paDTB_0, paDTB_1; POB_SET psObOff = NULL, psObVa = NULL; ZeroMemory(po, sizeof(VMM_OFFSET_EPROCESS)); - if(!VmmRead(pSystemProcess, pSystemProcess->win.EPROCESS.va, pbSYSTEM, VMMPROC_EPROCESS64_MAX_SIZE)) { return; } - VmmLogHexAsciiEx(MID_PROCESS, LOGLEVEL_DEBUG, pbSYSTEM, VMMPROC_EPROCESS64_MAX_SIZE, 0, "SYSTEM DTB: %016llx EPROCESS: %016llx", pSystemProcess->paDTB, pSystemProcess->win.EPROCESS.va); + if(!VmmRead(H, pSystemProcess, pSystemProcess->win.EPROCESS.va, pbSYSTEM, VMMPROC_EPROCESS64_MAX_SIZE)) { return; } + VmmLogHexAsciiEx(H, MID_PROCESS, LOGLEVEL_DEBUG, pbSYSTEM, VMMPROC_EPROCESS64_MAX_SIZE, 0, "SYSTEM DTB: %016llx EPROCESS: %016llx", pSystemProcess->paDTB, pSystemProcess->win.EPROCESS.va); // find offset State (static for now) if(*(PDWORD)(pbSYSTEM + 0x04)) { return; } po->State = 0x04; @@ -2825,7 +2915,7 @@ VOID VmmWinProcess_OffsetLocator64(_In_ PVMM_PROCESS pSystemProcess) // PID = correct, this is a candidate if(0xffff000000000000 != (0xffff000000000003 & *(PQWORD)(pbSYSTEM + i + 8))) { continue; } // FLinkAll not valid kernel pointer va1 = *(PQWORD)(pbSYSTEM + i + 8) - i - 8; - f = VmmRead(pSystemProcess, va1, pb1, VMMPROC_EPROCESS64_MAX_SIZE); + f = VmmRead(H, pSystemProcess, va1, pb1, VMMPROC_EPROCESS64_MAX_SIZE); if(!f) { continue; } f = FALSE; if((*(PQWORD)(pb1 + po->Name) != 0x6578652e73736d73) && // smss.exe @@ -2851,12 +2941,12 @@ VOID VmmWinProcess_OffsetLocator64(_In_ PVMM_PROCESS pSystemProcess) memcpy(pbSMSS, pbSYSTEM, VMMPROC_EPROCESS64_MAX_SIZE); while(++cLoopProtect < 8) { va1 = *(PQWORD)(pbSMSS + po->FLink) - po->FLink; - f = VmmRead(pSystemProcess, va1, pbSMSS, VMMPROC_EPROCESS64_MAX_SIZE) && + f = VmmRead(H, pSystemProcess, va1, pbSMSS, VMMPROC_EPROCESS64_MAX_SIZE) && (*(PQWORD)(pbSMSS + po->Name) == 0x6578652e73736d73); if(f) { break; } } if(!f) { return; } - VmmLogHexAsciiEx(MID_PROCESS, LOGLEVEL_DEBUG, pbSMSS, VMMPROC_EPROCESS64_MAX_SIZE, 0, "EPROCESS smss.exe BELOW:"); + VmmLogHexAsciiEx(H, MID_PROCESS, LOGLEVEL_DEBUG, pbSMSS, VMMPROC_EPROCESS64_MAX_SIZE, 0, "EPROCESS smss.exe BELOW:"); } // find offset for ParentPid (_EPROCESS!InheritedFromUniqueProcessId) // (parent pid is assumed to be located between BLink and Name @@ -2877,8 +2967,8 @@ VOID VmmWinProcess_OffsetLocator64(_In_ PVMM_PROCESS pSystemProcess) vaPEB = *(PQWORD)(pbSMSS + i); if(!vaPEB || (vaPEB & 0xffff800000000fff)) { continue; } // Verify potential PEB - if(!VmmVirt2PhysEx(*(PQWORD)(pbSMSS + po->DTB), TRUE, vaPEB, &paPEB)) { continue; } - if(!VmmReadPage(NULL, paPEB, pbPage)) { continue; } + if(!VmmVirt2PhysEx(H, *(PQWORD)(pbSMSS + po->DTB), TRUE, vaPEB, &paPEB)) { continue; } + if(!VmmReadPage(H, NULL, paPEB, pbPage)) { continue; } if(*(PWORD)pbPage == 0x5a4d) { continue; } // MZ header -> likely entry point or something not PEB ... po->PEB = i; f = TRUE; @@ -2887,7 +2977,7 @@ VOID VmmWinProcess_OffsetLocator64(_In_ PVMM_PROCESS pSystemProcess) if(f) { break; } // failed locating PEB (paging?) -> try next process in EPROCESS list. va1 = *(PQWORD)(pbSMSS + po->FLink) - po->FLink; - if(!VmmRead(pSystemProcess, va1, pbSMSS, VMMPROC_EPROCESS64_MAX_SIZE)) { return; } + if(!VmmRead(H, pSystemProcess, va1, pbSMSS, VMMPROC_EPROCESS64_MAX_SIZE)) { return; } } if(!f) { return; } } @@ -2903,8 +2993,8 @@ VOID VmmWinProcess_OffsetLocator64(_In_ PVMM_PROCESS pSystemProcess) // locate various offsets primarily by reading pointers and checking pool // headers in an efficient way (minimize number of reads). { - if(!(psObVa = ObSet_New())) { goto fail; } - if(!(psObOff = ObSet_New())) { goto fail; } + if(!(psObVa = ObSet_New(H))) { goto fail; } + if(!(psObOff = ObSet_New(H))) { goto fail; } // ObjectTable candidate pointers for(i = po->Name - 0x0e0; i < po->Name - 0x020; i += 8) { vaP = *(PQWORD)(pbSYSTEM + i); @@ -2924,13 +3014,13 @@ VOID VmmWinProcess_OffsetLocator64(_In_ PVMM_PROCESS pSystemProcess) } } // prefetch result into cache - VmmCachePrefetchPages3(pSystemProcess, psObVa, 0x40, 0); + VmmCachePrefetchPages3(H, pSystemProcess, psObVa, 0x40, 0); // interpret result while(ObSet_Size(psObVa)) { oP = ObSet_Pop(psObOff); vaP = ObSet_Pop(psObVa); - if(!VmmRead2(pSystemProcess, vaP, pbPage, 0x40, VMM_FLAG_FORCECACHE_READ)) { - if(((vaP + 0x10) & 0xfff) || !VmmRead2(pSystemProcess, vaP + 0x10, pbPage + 0x10, 0x30, VMM_FLAG_FORCECACHE_READ)) { + if(!VmmRead2(H, pSystemProcess, vaP, pbPage, 0x40, VMM_FLAG_FORCECACHE_READ)) { + if(((vaP + 0x10) & 0xfff) || !VmmRead2(H, pSystemProcess, vaP + 0x10, pbPage + 0x10, 0x30, VMM_FLAG_FORCECACHE_READ)) { continue; } } @@ -2973,7 +3063,7 @@ VOID VmmWinProcess_OffsetLocator64(_In_ PVMM_PROCESS pSystemProcess) // smss.exe do not have an entry since it's running as admin ... { ZeroMemory(pbZero, 0x800); - paMax = ctxMain->dev.paMax; + paMax = H->dev.paMax; for(i = 0x240; i < VMMPROC_EPROCESS64_MAX_SIZE - 8; i += 8) { paDTB_0 = *(PQWORD)(pbSYSTEM + i); paDTB_1 = *(PQWORD)(pbSMSS + i); @@ -2981,16 +3071,16 @@ VOID VmmWinProcess_OffsetLocator64(_In_ PVMM_PROCESS pSystemProcess) paDTB_0 && !(paDTB_0 & 0xffe) && (paDTB_0 < paMax) && - VmmReadPage(NULL, (paDTB_0 & ~0xfff), pbPage) && + VmmReadPage(H, NULL, (paDTB_0 & ~0xfff), pbPage) && !memcmp(pbPage, pbZero, 0x800) && - VmmTlbPageTableVerify(pbPage, (paDTB_0 & ~0xfff), TRUE); + VmmTlbPageTableVerify(H, pbPage, (paDTB_0 & ~0xfff), TRUE); if(f) { po->DTB_User = i; break; } } } - VmmWinProcess_OffsetLocator_SetMaxOffset(); + VmmWinProcess_OffsetLocator_SetMaxOffset(H); po->fValid = TRUE; fail: Ob_DECREF(psObVa); @@ -3000,34 +3090,36 @@ fail: /* * Post-process new process in the "new" process table before they are comitted VmmProcessCreateFinish() * At this moment "only" the full path and name is retrieved by using 'SeAuditProcessCreationInfo'. +* -- H * -- pSystemProcess */ -VOID VmmWinProcess_Enumerate_PostProcessing(_In_ PVMM_PROCESS pSystemProcess) +VOID VmmWinProcess_Enumerate_PostProcessing(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess) { + BOOL f32 = H->vmm.f32; DWORD i; LPSTR uszPathKernel; POB_SET pObPrefetchAddr = NULL; PVMM_PROCESS pObProcess = NULL; PVMMOB_PROCESS_TABLE ptObCurrent = NULL, ptObNew = NULL; PVMMOB_PROCESS_PERSISTENT pProcPers; - if(!(pObPrefetchAddr = ObSet_New())) { goto fail; } - if(!(ptObCurrent = (PVMMOB_PROCESS_TABLE)ObContainer_GetOb(ctxVmm->pObCPROC))) { goto fail; } + if(!(pObPrefetchAddr = ObSet_New(H))) { goto fail; } + if(!(ptObCurrent = (PVMMOB_PROCESS_TABLE)ObContainer_GetOb(H->vmm.pObCPROC))) { goto fail; } if(!(ptObNew = (PVMMOB_PROCESS_TABLE)ObContainer_GetOb(ptObCurrent->pObCNewPROC))) { goto fail; } // 1: Iterate to gather memory locations of "SeAuditProcessCreationInfo" / "kernel path" for new processes - while((pObProcess = VmmProcessGetNextEx(ptObNew, pObProcess, VMM_FLAG_PROCESS_SHOW_TERMINATED))) { + while((pObProcess = VmmProcessGetNextEx(H, ptObNew, pObProcess, VMM_FLAG_PROCESS_SHOW_TERMINATED))) { if(!pObProcess->pObPersistent->fIsPostProcessingComplete) { - ObSet_Push_PageAlign(pObPrefetchAddr, VMM_EPROCESS_PTR(pObProcess, ctxVmm->offset.EPROCESS.SeAuditProcessCreationInfo), 540); + ObSet_Push_PageAlign(pObPrefetchAddr, VMM_EPROCESS_PTR(f32, pObProcess, H->vmm.offset.EPROCESS.SeAuditProcessCreationInfo), 540); } } if(0 == ObSet_Size(pObPrefetchAddr)) { goto fail; } - VmmCachePrefetchPages(pSystemProcess, pObPrefetchAddr, 0); + VmmCachePrefetchPages(H, pSystemProcess, pObPrefetchAddr, 0); // 2: Fetch "kernel path" and set "long name" for new processes. - while((pObProcess = VmmProcessGetNextEx(ptObNew, pObProcess, VMM_FLAG_PROCESS_SHOW_TERMINATED))) { + while((pObProcess = VmmProcessGetNextEx(H, ptObNew, pObProcess, VMM_FLAG_PROCESS_SHOW_TERMINATED))) { pProcPers = pObProcess->pObPersistent; if(!pProcPers->fIsPostProcessingComplete) { pProcPers->fIsPostProcessingComplete = TRUE; uszPathKernel = NULL; - if(VmmReadAllocUnicodeStringAsUTF8(pSystemProcess, ctxVmm->f32, VMM_FLAG_FORCECACHE_READ, VMM_EPROCESS_PTR(pObProcess, ctxVmm->offset.EPROCESS.SeAuditProcessCreationInfo), 0x400, &uszPathKernel, NULL)) { + if(VmmReadAllocUnicodeStringAsUTF8(H, pSystemProcess, f32, VMM_FLAG_FORCECACHE_READ, VMM_EPROCESS_PTR(f32, pObProcess, H->vmm.offset.EPROCESS.SeAuditProcessCreationInfo), 0x400, &uszPathKernel, NULL)) { if(memcmp(uszPathKernel, "\\Device\\", 8)) { LocalFree(uszPathKernel); uszPathKernel = NULL; } @@ -3061,18 +3153,28 @@ typedef struct tdVMMWIN_ENUMERATE_EPROCESS_CONTEXT { POB_SET pObSetPrefetchDTB; } VMMWIN_ENUMERATE_EPROCESS_CONTEXT, *PVMMWIN_ENUMERATE_EPROCESS_CONTEXT; -VOID VmmWinProcess_Enum64_Pre(_In_ PVMM_PROCESS pProcess, _In_opt_ PVMMWIN_ENUMERATE_EPROCESS_CONTEXT ctx, _In_ QWORD va, _In_ PBYTE pb, _In_ DWORD cb, _In_ QWORD vaFLink, _In_ QWORD vaBLink, _In_ POB_SET pVSetAddress, _Inout_ PBOOL pfValidEntry, _Inout_ PBOOL pfValidFLink, _Inout_ PBOOL pfValidBLink) +VOID VmmWinProcess_Enum64_Pre(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ PVMMWIN_ENUMERATE_EPROCESS_CONTEXT ctx, _In_ QWORD va, _In_ PBYTE pb, _In_ DWORD cb, _In_ QWORD vaFLink, _In_ QWORD vaBLink, _In_ POB_SET pVSetAddress, _Inout_ PBOOL pfValidEntry, _Inout_ PBOOL pfValidFLink, _Inout_ PBOOL pfValidBLink) { if(!ctx || !VMM_KADDR64_16(va)) { return; } - ObSet_Push(ctx->pObSetPrefetchDTB, *(PQWORD)(pb + ctxVmm->offset.EPROCESS.DTB) & ~0xfff); + ObSet_Push(ctx->pObSetPrefetchDTB, *(PQWORD)(pb + H->vmm.offset.EPROCESS.DTB) & ~0xfff); *pfValidFLink = VMM_KADDR64_8(vaFLink); *pfValidBLink = VMM_KADDR64_8(vaBLink); *pfValidEntry = *pfValidFLink || *pfValidBLink; } -VOID VmmWinProcess_Enum64_Post(_In_ PVMM_PROCESS pSystemProcess, _In_opt_ PVMMWIN_ENUMERATE_EPROCESS_CONTEXT ctx, _In_ QWORD va, _In_ PBYTE pb, _In_ DWORD cb) +/* +* Process enumeration callback function: +* NB! REQUIRE SINGLE THREAD: [H->vmm.LockMaster] +* -- H +* -- pSystemProcess +* -- ctx +* -- va +* -- pb +* -- cb +*/ +VOID VmmWinProcess_Enum64_Post(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_opt_ PVMMWIN_ENUMERATE_EPROCESS_CONTEXT ctx, _In_ QWORD va, _In_ PBYTE pb, _In_ DWORD cb) { - PVMM_OFFSET_EPROCESS po = &ctxVmm->offset.EPROCESS; + PVMM_OFFSET_EPROCESS po = &H->vmm.offset.EPROCESS; PQWORD pqwDTB, pqwDTB_User, pqwPEB, pqwWow64Process; PDWORD pdwState, pdwPID, pdwPPID; LPSTR szName; @@ -3089,7 +3191,7 @@ VOID VmmWinProcess_Enum64_Post(_In_ PVMM_PROCESS pSystemProcess, _In_opt_ PVMMWI pqwWow64Process = (PQWORD)(pb + po->Wow64Process); if(*pqwDTB & 0xfffff00000000000) { return; } // NB! Fail if target system have more than 16TB of memory (unlikely) if(ctx->pObSetPrefetchDTB) { // prefetch any physical pages in ctx->pObSetPrefetchDTB on 1st run only - VmmCachePrefetchPages(NULL, ctx->pObSetPrefetchDTB, 0); + VmmCachePrefetchPages(H, NULL, ctx->pObSetPrefetchDTB, 0); Ob_DECREF_NULL(&ctx->pObSetPrefetchDTB); } if(*pdwPID && *pqwDTB && *(PQWORD)szName) { @@ -3098,6 +3200,7 @@ VOID VmmWinProcess_Enum64_Post(_In_ PVMM_PROCESS pSystemProcess, _In_opt_ PVMMWI !((*pdwPID == 4) || ((*pdwState == 0) && (*pqwPEB == 0)) || (*(PQWORD)szName == 0x78652e7373727363)) || // csrss.exe ((*(PQWORD)(szName + 0x00) == 0x72706d6f436d654d) && (*(PDWORD)(szName + 0x08) == 0x69737365)); // MemCompression "process" pObProcess = VmmProcessCreateEntry( + H, ctx->fTotalRefresh, *pdwPID, *pdwPPID, @@ -3109,7 +3212,7 @@ VOID VmmWinProcess_Enum64_Post(_In_ PVMM_PROCESS pSystemProcess, _In_opt_ PVMMWI pb, cb); if(!pObProcess) { - VmmLog(MID_PROCESS, LOGLEVEL_VERBOSE, "WARNING: PID '%i' already exists or bad DTB", *pdwPID); + VmmLog(H, MID_PROCESS, LOGLEVEL_VERBOSE, "WARNING: PID '%i' already exists or bad DTB", *pdwPID); if(++ctx->cNewProcessCollision >= 8) { return; } @@ -3120,7 +3223,7 @@ VOID VmmWinProcess_Enum64_Post(_In_ PVMM_PROCESS pSystemProcess, _In_opt_ PVMMWI pObProcess->win.EPROCESS.fNoLink = ctx->fNoLinkEPROCESS; // PEB if(*pqwPEB & 0xfff) { - VmmLog(MID_PROCESS, LOGLEVEL_VERBOSE, "WARNING: Bad PEB alignment for PID: '%i' (0x%016llx)", *pdwPID, *pqwPEB); + VmmLog(H, MID_PROCESS, LOGLEVEL_VERBOSE, "WARNING: Bad PEB alignment for PID: '%i' (0x%016llx)", *pdwPID, *pqwPEB); } else { pObProcess->win.vaPEB = *pqwPEB; } @@ -3136,7 +3239,7 @@ VOID VmmWinProcess_Enum64_Post(_In_ PVMM_PROCESS pSystemProcess, _In_opt_ PVMMWI } else { szName[14] = 0; // in case of bad string data ... } - VmmLog(MID_PROCESS, LOGLEVEL_DEBUG, "%04i (%s) %08x %012llx %016llx %012llx %s", + VmmLog(H, MID_PROCESS, LOGLEVEL_DEBUG, "%04i (%s) %08x %012llx %016llx %012llx %s", ctx->cProc, !pObProcess ? "skip" : (pObProcess->dwState ? "exit" : "list"), *pdwPID, @@ -3153,85 +3256,90 @@ VOID VmmWinProcess_Enum64_Post(_In_ PVMM_PROCESS pSystemProcess, _In_opt_ PVMMWI * undergoing a fetch. */ VOID VmmWinProcess_Enum_AddNoLink( + _In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_opt_ POB_SET psvaNoLinkEPROCESS, _In_ PVMMWIN_ENUMERATE_EPROCESS_CONTEXT ctx, - _In_ VOID(*pfnCallback_Post)(_In_ PVMM_PROCESS pProcess, _In_opt_ PVOID ctx, _In_ QWORD va, _In_reads_(cb) PBYTE pb, _In_ DWORD cb) + _In_ VOID(*pfnCallback_Post)(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ PVOID ctx, _In_ QWORD va, _In_reads_(cb) PBYTE pb, _In_ DWORD cb) ) { QWORD va; BYTE pb[0x1000]; - DWORD cb = ctxVmm->offset.EPROCESS.cbMaxOffset; + DWORD cb = H->vmm.offset.EPROCESS.cbMaxOffset; ctx->fNoLinkEPROCESS = TRUE; while((va = ObSet_Pop(psvaNoLinkEPROCESS))) { - if(VmmRead(pSystemProcess, va, pb, cb)) { - pfnCallback_Post(pSystemProcess, ctx, va, pb, cb); + if(VmmRead(H, pSystemProcess, va, pb, cb)) { + pfnCallback_Post(H, pSystemProcess, ctx, va, pb, cb); } } } /* * Try walk the EPROCESS list in the Windows kernel to enumerate processes into -* the VMM/PROC file system. +* the VMM/PROC file system. 64-bit version. * NB! This may be done to refresh an existing PID cache hence migration code. +* NB! REQUIRE SINGLE THREAD : [H->vmm.LockMaster] +* -- H * -- pSystemProcess * -- fTotalRefresh * -- psvaNoLinkEPROCESS = optional list of non-linked EPROCESS va's. * -- return */ -BOOL VmmWinProcess_Enum64(_In_ PVMM_PROCESS pSystemProcess, _In_ BOOL fTotalRefresh, _In_opt_ POB_SET psvaNoLinkEPROCESS) +BOOL VmmWinProcess_Enum64(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ BOOL fTotalRefresh, _In_opt_ POB_SET psvaNoLinkEPROCESS) { - PVMM_OFFSET_EPROCESS po = &ctxVmm->offset.EPROCESS; + PVMM_OFFSET_EPROCESS po = &H->vmm.offset.EPROCESS; VMMWIN_ENUMERATE_EPROCESS_CONTEXT ctx = { 0 }; // retrieve offsets if(!po->fValid) { - VmmWinProcess_OffsetLocator64(pSystemProcess); - VmmWinProcess_OffsetLocator_Print(); + VmmWinProcess_OffsetLocator64(H, pSystemProcess); + VmmWinProcess_OffsetLocator_Print(H); if(!po->fValid) { - VmmLog(MID_PROCESS, LOGLEVEL_INFO, "Unable to fuzz EPROCESS offsets - trying debug symbols"); - VmmWinProcess_OffsetLocatorSYMSERV(pSystemProcess); - VmmWinProcess_OffsetLocator_Print(); + VmmLog(H, MID_PROCESS, LOGLEVEL_INFO, "Unable to fuzz EPROCESS offsets - trying debug symbols"); + VmmWinProcess_OffsetLocatorSYMSERV(H, pSystemProcess); + VmmWinProcess_OffsetLocator_Print(H); } if(!po->fValid) { - VmmLog(MID_PROCESS, LOGLEVEL_CRITICAL, "Unable to locate EPROCESS offsets"); + VmmLog(H, MID_PROCESS, LOGLEVEL_CRITICAL, "Unable to locate EPROCESS offsets"); return FALSE; } } - VmmLog(MID_PROCESS, LOGLEVEL_DEBUG, "SYSTEM DTB: %016llx EPROCESS: %016llx", pSystemProcess->paDTB, pSystemProcess->win.EPROCESS.va); + VmmLog(H, MID_PROCESS, LOGLEVEL_DEBUG, "SYSTEM DTB: %016llx EPROCESS: %016llx", pSystemProcess->paDTB, pSystemProcess->win.EPROCESS.va); // set up context ctx.fTotalRefresh = fTotalRefresh; - if(!(ctx.pObSetPrefetchDTB = ObSet_New())) { return FALSE; } + if(!(ctx.pObSetPrefetchDTB = ObSet_New(H))) { return FALSE; } // traverse EPROCESS linked list - VmmLog(MID_PROCESS, LOGLEVEL_DEBUG, " # STATE PID DTB EPROCESS PEB NAME"); + VmmLog(H, MID_PROCESS, LOGLEVEL_DEBUG, " # STATE PID DTB EPROCESS PEB NAME"); VmmWin_ListTraversePrefetch( + H, pSystemProcess, FALSE, &ctx, 1, &pSystemProcess->win.EPROCESS.va, - ctxVmm->offset.EPROCESS.FLink, - ctxVmm->offset.EPROCESS.cbMaxOffset, + H->vmm.offset.EPROCESS.FLink, + H->vmm.offset.EPROCESS.cbMaxOffset, (VMMWIN_LISTTRAVERSE_PRE_CB)VmmWinProcess_Enum64_Pre, (VMMWIN_LISTTRAVERSE_POST_CB)VmmWinProcess_Enum64_Post, - ctxVmm->pObCCachePrefetchEPROCESS); + H->vmm.pObCCachePrefetchEPROCESS); // add no-link entries (if any) VmmWinProcess_Enum_AddNoLink( + H, pSystemProcess, psvaNoLinkEPROCESS, &ctx, - (VOID(*)(PVMM_PROCESS, PVOID, QWORD, PBYTE, DWORD))VmmWinProcess_Enum64_Post); + (VOID(*)(VMM_HANDLE, PVMM_PROCESS, PVOID, QWORD, PBYTE, DWORD))VmmWinProcess_Enum64_Post); // set resulting prefetch cache Ob_DECREF_NULL(&ctx.pObSetPrefetchDTB); - VmmWinProcess_Enumerate_PostProcessing(pSystemProcess); - VmmProcessCreateFinish(); + VmmWinProcess_Enumerate_PostProcessing(H, pSystemProcess); + VmmProcessCreateFinish(H); return (ctx.cProc > 10); } /* * Very ugly hack that tries to locate some offsets required withn the EPROCESS struct. */ -VOID VmmWinProcess_OffsetLocator32(_In_ PVMM_PROCESS pSystemProcess) +VOID VmmWinProcess_OffsetLocator32(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess) { - PVMM_OFFSET_EPROCESS po = &ctxVmm->offset.EPROCESS; + PVMM_OFFSET_EPROCESS po = &H->vmm.offset.EPROCESS; BOOL f; WORD i, j, cLoopProtect; DWORD va1, vaPEB, vaP, oP; @@ -3241,8 +3349,8 @@ VOID VmmWinProcess_OffsetLocator32(_In_ PVMM_PROCESS pSystemProcess) //QWORD paMax, paDTB_0, paDTB_1; POB_SET psObOff = NULL, psObVa = NULL; ZeroMemory(po, sizeof(VMM_OFFSET_EPROCESS)); - if(!VmmRead(pSystemProcess, pSystemProcess->win.EPROCESS.va, pbSYSTEM, VMMPROC_EPROCESS32_MAX_SIZE)) { return; } - VmmLogHexAsciiEx(MID_PROCESS, LOGLEVEL_DEBUG, pbSYSTEM, VMMPROC_EPROCESS32_MAX_SIZE, 0, "SYSTEM DTB: %016llx EPROCESS: %016llx", pSystemProcess->paDTB, pSystemProcess->win.EPROCESS.va); + if(!VmmRead(H, pSystemProcess, pSystemProcess->win.EPROCESS.va, pbSYSTEM, VMMPROC_EPROCESS32_MAX_SIZE)) { return; } + VmmLogHexAsciiEx(H, MID_PROCESS, LOGLEVEL_DEBUG, pbSYSTEM, VMMPROC_EPROCESS32_MAX_SIZE, 0, "SYSTEM DTB: %016llx EPROCESS: %016llx", pSystemProcess->paDTB, pSystemProcess->win.EPROCESS.va); // find offset State (static for now) if(*(PDWORD)(pbSYSTEM + 0x04)) { return; } po->State = 0x04; @@ -3263,7 +3371,7 @@ VOID VmmWinProcess_OffsetLocator32(_In_ PVMM_PROCESS pSystemProcess) // PID = correct, this is a candidate if(0x80000000 != (0x80000003 & *(PDWORD)(pbSYSTEM + i + 4))) { continue; } // FLinkAll not valid kernel pointer va1 = *(PDWORD)(pbSYSTEM + i + 4) - i - 4; - f = VmmRead(pSystemProcess, va1, pb1, VMMPROC_EPROCESS32_MAX_SIZE); + f = VmmRead(H, pSystemProcess, va1, pb1, VMMPROC_EPROCESS32_MAX_SIZE); if(!f) { continue; } f = FALSE; if((*(PQWORD)(pb1 + po->Name) != 0x6578652e73736d73) && // smss.exe @@ -3289,12 +3397,12 @@ VOID VmmWinProcess_OffsetLocator32(_In_ PVMM_PROCESS pSystemProcess) memcpy(pbSMSS, pbSYSTEM, VMMPROC_EPROCESS32_MAX_SIZE); while(++cLoopProtect < 8) { va1 = *(PDWORD)(pbSMSS + po->FLink) - po->FLink; - f = VmmRead(pSystemProcess, va1, pbSMSS, VMMPROC_EPROCESS32_MAX_SIZE) && + f = VmmRead(H, pSystemProcess, va1, pbSMSS, VMMPROC_EPROCESS32_MAX_SIZE) && (*(PQWORD)(pbSMSS + po->Name) == 0x6578652e73736d73); if(f) { break; } } if(!f) { return; } - VmmLogHexAsciiEx(MID_PROCESS, LOGLEVEL_DEBUG, pbSMSS, VMMPROC_EPROCESS32_MAX_SIZE, 0, "EPROCESS smss.exe BELOW:"); + VmmLogHexAsciiEx(H, MID_PROCESS, LOGLEVEL_DEBUG, pbSMSS, VMMPROC_EPROCESS32_MAX_SIZE, 0, "EPROCESS smss.exe BELOW:"); } // find offset for ParentPid (_EPROCESS!InheritedFromUniqueProcessId) // (parent pid is assumed to be located between BLink and Name @@ -3315,8 +3423,8 @@ VOID VmmWinProcess_OffsetLocator32(_In_ PVMM_PROCESS pSystemProcess) vaPEB = *(PDWORD)(pbSMSS + i); if(!vaPEB || (vaPEB & 0x80000fff)) { continue; } // Verify potential PEB - if(!VmmVirt2PhysEx(*(PDWORD)(pbSMSS + po->DTB), TRUE, vaPEB, &paPEB)) { continue; } - if(!VmmReadPage(NULL, paPEB, pbPage)) { continue; } + if(!VmmVirt2PhysEx(H, *(PDWORD)(pbSMSS + po->DTB), TRUE, vaPEB, &paPEB)) { continue; } + if(!VmmReadPage(H, NULL, paPEB, pbPage)) { continue; } if(*(PWORD)pbPage == 0x5a4d) { continue; } // MZ header -> likely entry point or something not PEB ... po->PEB = i; f = TRUE; @@ -3325,15 +3433,15 @@ VOID VmmWinProcess_OffsetLocator32(_In_ PVMM_PROCESS pSystemProcess) if(f) { break; } // failed locating PEB (paging?) -> try next process in EPROCESS list. va1 = *(PDWORD)(pbSMSS + po->FLink) - po->FLink; - if(!VmmRead(pSystemProcess, va1, pbSMSS, VMMPROC_EPROCESS32_MAX_SIZE)) { return; } + if(!VmmRead(H, pSystemProcess, va1, pbSMSS, VMMPROC_EPROCESS32_MAX_SIZE)) { return; } } if(!f) { return; } } // locate various offsets primarily by reading pointers and checking pool // headers in an efficient way (minimize number of reads). { - if(!(psObVa = ObSet_New())) { goto fail; } - if(!(psObOff = ObSet_New())) { goto fail; } + if(!(psObVa = ObSet_New(H))) { goto fail; } + if(!(psObOff = ObSet_New(H))) { goto fail; } // ObjectTable candidate pointers for(i = po->Name - 0x0c0; i < po->Name - 0x010; i += 4) { vaP = *(PDWORD)(pbSYSTEM + i); @@ -3353,13 +3461,13 @@ VOID VmmWinProcess_OffsetLocator32(_In_ PVMM_PROCESS pSystemProcess) } } // prefetch result into cache - VmmCachePrefetchPages3(pSystemProcess, psObVa, 0x40, 0); + VmmCachePrefetchPages3(H, pSystemProcess, psObVa, 0x40, 0); // interpret result while(ObSet_Size(psObVa)) { oP = (DWORD)ObSet_Pop(psObOff); vaP = (DWORD)ObSet_Pop(psObVa); - if(!VmmRead2(pSystemProcess, vaP, pbPage, 0x40, VMM_FLAG_FORCECACHE_READ)) { - if(((vaP + 0x10) & 0xfff) || !VmmRead2(pSystemProcess, vaP + 0x10ULL, pbPage + 0x10, 0x30, VMM_FLAG_FORCECACHE_READ)) { + if(!VmmRead2(H, pSystemProcess, vaP, pbPage, 0x40, VMM_FLAG_FORCECACHE_READ)) { + if(((vaP + 0x10) & 0xfff) || !VmmRead2(H, pSystemProcess, vaP + 0x10ULL, pbPage + 0x10, 0x30, VMM_FLAG_FORCECACHE_READ)) { continue; } } @@ -3402,25 +3510,35 @@ VOID VmmWinProcess_OffsetLocator32(_In_ PVMM_PROCESS pSystemProcess) } } // DTB_USER not searched for in 32-bit EPROCESS - VmmWinProcess_OffsetLocator_SetMaxOffset(); + VmmWinProcess_OffsetLocator_SetMaxOffset(H); po->fValid = TRUE; fail: Ob_DECREF(psObVa); Ob_DECREF(psObOff); } -VOID VmmWinProcess_Enum32_Pre(_In_ PVMM_PROCESS pProcess, _In_opt_ PVMMWIN_ENUMERATE_EPROCESS_CONTEXT ctx, _In_ QWORD va, _In_ PBYTE pb, _In_ DWORD cb, _In_ QWORD vaFLink, _In_ QWORD vaBLink, _In_ POB_SET pVSetAddress, _Inout_ PBOOL pfValidEntry, _Inout_ PBOOL pfValidFLink, _Inout_ PBOOL pfValidBLink) +VOID VmmWinProcess_Enum32_Pre(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ PVMMWIN_ENUMERATE_EPROCESS_CONTEXT ctx, _In_ QWORD va, _In_ PBYTE pb, _In_ DWORD cb, _In_ QWORD vaFLink, _In_ QWORD vaBLink, _In_ POB_SET pVSetAddress, _Inout_ PBOOL pfValidEntry, _Inout_ PBOOL pfValidFLink, _Inout_ PBOOL pfValidBLink) { if(!ctx || !VMM_KADDR32_8(va)) { return; } - ObSet_Push(ctx->pObSetPrefetchDTB, *(PDWORD)(pb + ctxVmm->offset.EPROCESS.DTB) & ~0xfff); + ObSet_Push(ctx->pObSetPrefetchDTB, *(PDWORD)(pb + H->vmm.offset.EPROCESS.DTB) & ~0xfff); *pfValidFLink = VMM_KADDR32_4(vaFLink); *pfValidBLink = VMM_KADDR32_4(vaBLink); *pfValidEntry = *pfValidFLink || *pfValidBLink; } -VOID VmmWinProcess_Enum32_Post(_In_ PVMM_PROCESS pSystemProcess, _In_opt_ PVMMWIN_ENUMERATE_EPROCESS_CONTEXT ctx, _In_ QWORD va, _In_ PBYTE pb, _In_ DWORD cb) +/* +* Process enumeration callback function: +* NB! REQUIRE SINGLE THREAD: [H->vmm.LockMaster] +* -- H +* -- pSystemProcess +* -- ctx +* -- va +* -- pb +* -- cb +*/ +VOID VmmWinProcess_Enum32_Post(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_opt_ PVMMWIN_ENUMERATE_EPROCESS_CONTEXT ctx, _In_ QWORD va, _In_ PBYTE pb, _In_ DWORD cb) { - PVMM_OFFSET_EPROCESS po = &ctxVmm->offset.EPROCESS; + PVMM_OFFSET_EPROCESS po = &H->vmm.offset.EPROCESS; PDWORD pdwDTB, pdwDTB_User, pdwPEB; PDWORD pdwState, pdwPID, pdwPPID; LPSTR szName; @@ -3435,7 +3553,7 @@ VOID VmmWinProcess_Enum32_Post(_In_ PVMM_PROCESS pSystemProcess, _In_opt_ PVMMWI szName = (LPSTR)(pb + po->Name); pdwPEB = (PDWORD)(pb + po->PEB); if(ctx->pObSetPrefetchDTB) { // prefetch any physical pages in ctx->pObSetPrefetchDTB on 1st run only - VmmCachePrefetchPages(NULL, ctx->pObSetPrefetchDTB, 0); + VmmCachePrefetchPages(H, NULL, ctx->pObSetPrefetchDTB, 0); Ob_DECREF_NULL(&ctx->pObSetPrefetchDTB); } if(*pdwPID && *pdwDTB && *(PQWORD)szName) { @@ -3444,6 +3562,7 @@ VOID VmmWinProcess_Enum32_Post(_In_ PVMM_PROCESS pSystemProcess, _In_opt_ PVMMWI !((*pdwPID == 4) || ((*pdwState == 0) && (*pdwPEB == 0)) || (*(PQWORD)szName == 0x78652e7373727363)) || // csrss.exe ((*(PQWORD)(szName + 0x00) == 0x72706d6f436d654d) && (*(PDWORD)(szName + 0x08) == 0x69737365)); // MemCompression "process" pObProcess = VmmProcessCreateEntry( + H, ctx->fTotalRefresh, *pdwPID, *pdwPPID, @@ -3455,7 +3574,7 @@ VOID VmmWinProcess_Enum32_Post(_In_ PVMM_PROCESS pSystemProcess, _In_opt_ PVMMWI pb, cb); if(!pObProcess) { - VmmLog(MID_PROCESS, LOGLEVEL_VERBOSE, "WARNING: PID '%i' already exists or bad DTB", *pdwPID); + VmmLog(H, MID_PROCESS, LOGLEVEL_VERBOSE, "WARNING: PID '%i' already exists or bad DTB", *pdwPID); if(++ctx->cNewProcessCollision >= 8) { return; } @@ -3466,7 +3585,7 @@ VOID VmmWinProcess_Enum32_Post(_In_ PVMM_PROCESS pSystemProcess, _In_opt_ PVMMWI pObProcess->win.EPROCESS.fNoLink = ctx->fNoLinkEPROCESS; // PEB if(*pdwPEB & 0xfff) { - VmmLog(MID_PROCESS, LOGLEVEL_VERBOSE, "WARNING: Bad PEB alignment for PID: '%i' (0x%08x)", *pdwPID, *pdwPEB); + VmmLog(H, MID_PROCESS, LOGLEVEL_VERBOSE, "WARNING: Bad PEB alignment for PID: '%i' (0x%08x)", *pdwPID, *pdwPEB); } else { pObProcess->win.vaPEB = *pdwPEB; pObProcess->win.vaPEB32 = *pdwPEB; @@ -3474,7 +3593,7 @@ VOID VmmWinProcess_Enum32_Post(_In_ PVMM_PROCESS pSystemProcess, _In_opt_ PVMMWI } else { szName[14] = 0; // in case of bad string data ... } - VmmLog(MID_PROCESS, LOGLEVEL_DEBUG, "%04i (%s) %08x %08x %08x %08x %s", + VmmLog(H, MID_PROCESS, LOGLEVEL_DEBUG, "%04i (%s) %08x %08x %08x %08x %s", ctx->cProc, !pObProcess ? "skip" : (pObProcess->dwState ? "exit" : "list"), *pdwPID, @@ -3486,50 +3605,63 @@ VOID VmmWinProcess_Enum32_Post(_In_ PVMM_PROCESS pSystemProcess, _In_opt_ PVMMWI ctx->cProc++; } -BOOL VmmWinProcess_Enum32(_In_ PVMM_PROCESS pSystemProcess, _In_ BOOL fTotalRefresh, _In_opt_ POB_SET psvaNoLinkEPROCESS) +/* +* Try walk the EPROCESS list in the Windows kernel to enumerate processes into +* the VMM/PROC file system. 32-bit version. +* NB! This may be done to refresh an existing PID cache hence migration code. +* NB! REQUIRE SINGLE THREAD : [H->vmm.LockMaster] +* -- H +* -- pSystemProcess +* -- fTotalRefresh +* -- psvaNoLinkEPROCESS = optional list of non-linked EPROCESS va's. +* -- return +*/ +BOOL VmmWinProcess_Enum32(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ BOOL fTotalRefresh, _In_opt_ POB_SET psvaNoLinkEPROCESS) { - PVMM_OFFSET_EPROCESS po = &ctxVmm->offset.EPROCESS; + PVMM_OFFSET_EPROCESS po = &H->vmm.offset.EPROCESS; VMMWIN_ENUMERATE_EPROCESS_CONTEXT ctx = { 0 }; // retrieve offsets if(!po->fValid) { - VmmWinProcess_OffsetLocator32(pSystemProcess); - VmmWinProcess_OffsetLocator_Print(); + VmmWinProcess_OffsetLocator32(H, pSystemProcess); + VmmWinProcess_OffsetLocator_Print(H); if(!po->fValid) { - VmmLog(MID_PROCESS, LOGLEVEL_INFO, "Unable to fuzz EPROCESS offsets - trying debug symbols"); - VmmWinProcess_OffsetLocatorSYMSERV(pSystemProcess); + VmmLog(H, MID_PROCESS, LOGLEVEL_INFO, "Unable to fuzz EPROCESS offsets - trying debug symbols"); + VmmWinProcess_OffsetLocatorSYMSERV(H, pSystemProcess); } if(!po->fValid) { - VmmLog(MID_PROCESS, LOGLEVEL_CRITICAL, "Unable to locate EPROCESS offsets"); + VmmLog(H, MID_PROCESS, LOGLEVEL_CRITICAL, "Unable to locate EPROCESS offsets"); return FALSE; } } - VmmLog(MID_PROCESS, LOGLEVEL_DEBUG, "SYSTEM DTB: %016llx EPROCESS: %08x", pSystemProcess->paDTB, (DWORD)pSystemProcess->win.EPROCESS.va); + VmmLog(H, MID_PROCESS, LOGLEVEL_DEBUG, "SYSTEM DTB: %016llx EPROCESS: %08x", pSystemProcess->paDTB, (DWORD)pSystemProcess->win.EPROCESS.va); // set up context ctx.fTotalRefresh = fTotalRefresh; - if(!(ctx.pObSetPrefetchDTB = ObSet_New())) { return FALSE; } + if(!(ctx.pObSetPrefetchDTB = ObSet_New(H))) { return FALSE; } // traverse EPROCESS linked list - VmmLog(MID_PROCESS, LOGLEVEL_DEBUG, " # STATE PID DTB EPROCESS PEB NAME"); + VmmLog(H, MID_PROCESS, LOGLEVEL_DEBUG, " # STATE PID DTB EPROCESS PEB NAME"); VmmWin_ListTraversePrefetch( + H, pSystemProcess, TRUE, &ctx, 1, &pSystemProcess->win.EPROCESS.va, - ctxVmm->offset.EPROCESS.FLink, - ctxVmm->offset.EPROCESS.cbMaxOffset, + po->FLink, + po->cbMaxOffset, (VMMWIN_LISTTRAVERSE_PRE_CB)VmmWinProcess_Enum32_Pre, (VMMWIN_LISTTRAVERSE_POST_CB)VmmWinProcess_Enum32_Post, - ctxVmm->pObCCachePrefetchEPROCESS); + H->vmm.pObCCachePrefetchEPROCESS); // add no-link entries (if any) VmmWinProcess_Enum_AddNoLink( + H, pSystemProcess, psvaNoLinkEPROCESS, &ctx, - (VOID(*)(PVMM_PROCESS, PVOID, QWORD, PBYTE, DWORD))VmmWinProcess_Enum32_Post); + (VOID(*)(VMM_HANDLE, PVMM_PROCESS, PVOID, QWORD, PBYTE, DWORD))VmmWinProcess_Enum32_Post); // set resulting prefetch cache Ob_DECREF_NULL(&ctx.pObSetPrefetchDTB); - VmmWinProcess_Enumerate_PostProcessing(pSystemProcess); - VmmProcessCreateFinish(); + VmmWinProcess_Enumerate_PostProcessing(H, pSystemProcess); + VmmProcessCreateFinish(H); return (ctx.cProc > 10); } @@ -3539,9 +3671,9 @@ BOOL VmmWinProcess_Enum32(_In_ PVMM_PROCESS pSystemProcess, _In_ BOOL fTotalRefr * CALLER DECREF: return * -- return = Set of vaEPROCESS if no-link addresses exist. NULL otherwise. */ -POB_SET VmmWinProcess_Enumerate_FindNoLinkProcesses() +POB_SET VmmWinProcess_Enumerate_FindNoLinkProcesses(_In_ VMM_HANDLE H) { - BOOL f32 = ctxVmm->f32; + BOOL f32 = H->vmm.f32; BYTE tpProcess, tpObjectEncrypted; DWORD i, cbHdr; POB_SET psOb = NULL, psObNoLink = NULL; @@ -3553,32 +3685,32 @@ POB_SET VmmWinProcess_Enumerate_FindNoLinkProcesses() POBJECT_HEADER64 pHdr64 = (POBJECT_HEADER64)pbHdr; // 1: Initialize cbHdr = f32 ? sizeof(OBJECT_HEADER32) : sizeof(OBJECT_HEADER64); - if(!(psOb = ObSet_New())) { goto fail; } - if(!(pObSystemProcess = VmmProcessGet(4))) { goto fail; } - if(!VmmWin_ObjectTypeGet(2) || !(tpProcess = ctxVmm->ObjectTypeTable.tpProcess)) { goto fail; } - if(!VmmMap_GetHandle(pObSystemProcess, &pObHandleMap, FALSE)) { goto fail; } + if(!(psOb = ObSet_New(H))) { goto fail; } + if(!(pObSystemProcess = VmmProcessGet(H, 4))) { goto fail; } + if(!VmmWin_ObjectTypeGet(H, 2) || !(tpProcess = H->vmm.ObjectTypeTable.tpProcess)) { goto fail; } + if(!VmmMap_GetHandle(H, pObSystemProcess, &pObHandleMap, FALSE)) { goto fail; } // 2: Prefetch object headers for(i = 0; i < pObHandleMap->cMap; i++) { ObSet_Push_PageAlign(psOb, pObHandleMap->pMap[i].vaObject - cbHdr, cbHdr); } - VmmCachePrefetchPages(pObSystemProcess, psOb, 0); + VmmCachePrefetchPages(H, pObSystemProcess, psOb, 0); ObSet_Clear(psOb); // 3: Index processes by EPROCESS va - while((pObProcess = VmmProcessGetNext(pObProcess, VMM_FLAG_PROCESS_SHOW_TERMINATED))) { + while((pObProcess = VmmProcessGetNext(H, pObProcess, VMM_FLAG_PROCESS_SHOW_TERMINATED))) { ObSet_Push(psOb, pObProcess->win.EPROCESS.va); } // 4: Check handles for process not in EPROCESS set for(i = 0; i < pObHandleMap->cMap; i++) { pe = pObHandleMap->pMap + i; - if(!VmmRead2(pObSystemProcess, pe->vaObject - cbHdr, pbHdr, cbHdr, VMM_FLAG_FORCECACHE_READ | VMM_FLAG_NOPAGING)) { continue; } + if(!VmmRead2(H, pObSystemProcess, pe->vaObject - cbHdr, pbHdr, cbHdr, VMM_FLAG_FORCECACHE_READ | VMM_FLAG_NOPAGING)) { continue; } tpObjectEncrypted = f32 ? pHdr32->TypeIndex : pHdr64->TypeIndex; - if(tpProcess == VmmWin_ObjectTypeGetIndexFromEncoded(pe->vaObject - cbHdr, tpObjectEncrypted)) { + if(tpProcess == VmmWin_ObjectTypeGetIndexFromEncoded(H, pe->vaObject - cbHdr, tpObjectEncrypted)) { if(ObSet_Exists(psOb, pe->vaObject)) { continue; } // process object not in process list found - if(!psObNoLink && !(psObNoLink = ObSet_New())) { goto fail; } + if(!psObNoLink && !(psObNoLink = ObSet_New(H))) { goto fail; } ObSet_Push(psOb, pe->vaObject); ObSet_Push(psObNoLink, pe->vaObject); - VmmLog(MID_PROCESS, LOGLEVEL_DEBUG, "NOLINK_EPROCESS: %016llx", pe->vaObject); + VmmLog(H, MID_PROCESS, LOGLEVEL_DEBUG, "NOLINK_EPROCESS: %016llx", pe->vaObject); } } fail: @@ -3588,19 +3720,20 @@ fail: return psObNoLink; } -BOOL VmmWinProcess_Enumerate(_In_ PVMM_PROCESS pSystemProcess, _In_ BOOL fRefreshTotal, _In_opt_ POB_SET psvaNoLinkEPROCESS) +BOOL VmmWinProcess_Enumerate(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ BOOL fRefreshTotal, _In_opt_ POB_SET psvaNoLinkEPROCESS) { + BOOL fResult = FALSE; // spider TLB and set up initial system process and enumerate EPROCESS - VmmTlbSpider(pSystemProcess); - switch(ctxVmm->tpMemoryModel) { - case VMM_MEMORYMODEL_X64: - return VmmWinProcess_Enum64(pSystemProcess, fRefreshTotal, psvaNoLinkEPROCESS); - case VMM_MEMORYMODEL_X86: - case VMM_MEMORYMODEL_X86PAE: - return VmmWinProcess_Enum32(pSystemProcess, fRefreshTotal, psvaNoLinkEPROCESS); - default: - return FALSE; + VmmTlbSpider(H, pSystemProcess); + // update processes within global lock (to avoid potential race conditions). + EnterCriticalSection(&H->vmm.LockMaster); + if(H->vmm.tpMemoryModel == VMM_MEMORYMODEL_X64) { + fResult = VmmWinProcess_Enum64(H, pSystemProcess, fRefreshTotal, psvaNoLinkEPROCESS); + } else if((H->vmm.tpMemoryModel == VMM_MEMORYMODEL_X86PAE) || (H->vmm.tpMemoryModel == VMM_MEMORYMODEL_X86)) { + fResult = VmmWinProcess_Enum32(H, pSystemProcess, fRefreshTotal, psvaNoLinkEPROCESS); } + LeaveCriticalSection(&H->vmm.LockMaster); + return fResult; } // ---------------------------------------------------------------------------- @@ -3630,6 +3763,7 @@ BOOL VmmWinProcess_Enumerate(_In_ PVMM_PROCESS pSystemProcess, _In_ BOOL fRefres * should no longer be continued to be walked in the direction. * The function keeps track of the initial array index if it's below 0xffff. * CALLER_DECREF: return +* -- H * -- pProcess * -- f32 * -- ctx = ctx to pass along to callback function (if any) @@ -3642,6 +3776,7 @@ BOOL VmmWinProcess_Enumerate(_In_ PVMM_PROCESS pSystemProcess, _In_ BOOL fRefres * -- pPrefetchAddressContainer = optional pointer to a PVMMOBCONTAINER containing a POB_VSET of prefetch addresses to use/update. */ VOID VmmWin_ListTraversePrefetch( + _In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ BOOL f32, _In_opt_ PVOID ctx, @@ -3662,13 +3797,13 @@ VOID VmmWin_ListTraversePrefetch( BOOL fValidEntry, fValidFLink, fValidBLink, fTry1; // 1: Prefetch any addresses stored in optional address container pObSet_vaAll = ObContainer_GetOb(pPrefetchAddressContainer); - VmmCachePrefetchPages3(pProcess, pObSet_vaAll, cbData, 0); + VmmCachePrefetchPages3(H, pProcess, pObSet_vaAll, cbData, 0); Ob_DECREF_NULL(&pObSet_vaAll); // 2: Prepare/Allocate and set up initial entry - if(!(pObSet_vaAll = ObSet_New())) { goto fail; } - if(!(pObSet_vaTry1 = ObSet_New())) { goto fail; } - if(!(pObSet_vaTry2 = ObSet_New())) { goto fail; } - if(!(pObSet_vaValid = ObSet_New())) { goto fail; } + if(!(pObSet_vaAll = ObSet_New(H))) { goto fail; } + if(!(pObSet_vaTry1 = ObSet_New(H))) { goto fail; } + if(!(pObSet_vaTry2 = ObSet_New(H))) { goto fail; } + if(!(pObSet_vaValid = ObSet_New(H))) { goto fail; } if(!(pbData = LocalAlloc(0, cbData))) { goto fail; } while(cvaDataStart) { cvaDataStart--; @@ -3683,13 +3818,13 @@ VOID VmmWin_ListTraversePrefetch( exvaData = ObSet_Pop(pObSet_vaTry1); if(!exvaData && (0 == ObSet_Size(pObSet_vaTry2))) { break; } if(!exvaData) { - VmmCachePrefetchPages3(pProcess, pObSet_vaAll, cbData, 0); + VmmCachePrefetchPages3(H, pProcess, pObSet_vaAll, cbData, 0); fTry1 = FALSE; continue; } vaData = VMMWIN_LISTTRAVERSEPREFETCH_EXVA_GET_VA(exvaData); idData = VMMWIN_LISTTRAVERSEPREFETCH_EXVA_GET_ID(exvaData); - VmmReadEx(pProcess, vaData, pbData, cbData, &cbReadData, VMM_FLAG_FORCECACHE_READ); + VmmReadEx(H, pProcess, vaData, pbData, cbData, &cbReadData, VMM_FLAG_FORCECACHE_READ); if(cbReadData != cbData) { ObSet_Push(pObSet_vaTry2, exvaData); continue; @@ -3700,13 +3835,13 @@ VOID VmmWin_ListTraversePrefetch( if(!exvaData) { fTry1 = TRUE; continue; } vaData = VMMWIN_LISTTRAVERSEPREFETCH_EXVA_GET_VA(exvaData); idData = VMMWIN_LISTTRAVERSEPREFETCH_EXVA_GET_ID(exvaData); - if(!VmmRead(pProcess, vaData, pbData, cbData)) { continue; } + if(!VmmRead(H, pProcess, vaData, pbData, cbData)) { continue; } } vaFLink = f32 ? *(PDWORD)(pbData + oListStart + 0) : *(PQWORD)(pbData + oListStart + 0); vaBLink = f32 ? *(PDWORD)(pbData + oListStart + 4) : *(PQWORD)(pbData + oListStart + 8); if(pfnCallback_Pre) { fValidEntry = FALSE; fValidFLink = FALSE; fValidBLink = FALSE; - pfnCallback_Pre(pProcess, ctx, vaData, pbData, cbData, vaFLink, vaBLink, pObSet_vaAll, &fValidEntry, &fValidFLink, &fValidBLink, idData); + pfnCallback_Pre(H, pProcess, ctx, vaData, pbData, cbData, vaFLink, vaBLink, pObSet_vaAll, &fValidEntry, &fValidFLink, &fValidBLink, idData); } else { if(f32) { fValidFLink = !(vaFLink & 0x03); @@ -3730,20 +3865,20 @@ VOID VmmWin_ListTraversePrefetch( } } // 4: Prefetch additional gathered addresses into cache. - VmmCachePrefetchPages3(pProcess, pObSet_vaAll, cbData, 0); + VmmCachePrefetchPages3(H, pProcess, pObSet_vaAll, cbData, 0); // 5: 2nd main list walk. Call into optional pfnCallback_Post to do the main // processing of the list items. if(pfnCallback_Post) { while((exvaData = ObSet_Pop(pObSet_vaValid))) { vaData = VMMWIN_LISTTRAVERSEPREFETCH_EXVA_GET_VA(exvaData); idData = VMMWIN_LISTTRAVERSEPREFETCH_EXVA_GET_ID(exvaData); - if(VmmRead(pProcess, vaData, pbData, cbData)) { - pfnCallback_Post(pProcess, ctx, vaData, pbData, cbData, idData); + if(VmmRead(H, pProcess, vaData, pbData, cbData)) { + pfnCallback_Post(H, pProcess, ctx, vaData, pbData, cbData, idData); } } } // 6: Store/Update the optional container with the newly prefetch addresses (if possible and desirable). - if(pPrefetchAddressContainer && ctxMain->dev.fVolatile && ctxVmm->ThreadProcCache.fEnabled) { + if(pPrefetchAddressContainer && H->dev.fVolatile && H->vmm.ThreadProcCache.fEnabled) { ObContainer_SetOb(pPrefetchAddressContainer, pObSet_vaAll); } fail: diff --git a/vmm/vmmwin.h b/vmm/vmmwin.h index 8149708..81d6d65 100644 --- a/vmm/vmmwin.h +++ b/vmm/vmmwin.h @@ -11,108 +11,120 @@ /* * Initialize EAT (exported functions) for a specific module. * CALLER DECREF: return +* -- H * -- pProcess * -- pModule * -- return */ -PVMMOB_MAP_EAT VmmWinEAT_Initialize(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_MODULEENTRY pModule); +PVMMOB_MAP_EAT VmmWinEAT_Initialize(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_MODULEENTRY pModule); /* * Initialize IAT (imported functions) for a specific module. * CALLER DECREF: return +* -- H * -- pProcess * -- pModule * -- return */ -PVMMOB_MAP_IAT VmmWinIAT_Initialize(_In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_MODULEENTRY pModule); +PVMMOB_MAP_IAT VmmWinIAT_Initialize(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVMM_MAP_MODULEENTRY pModule); /* * Try initialize PteMap text descriptions. This function will first try to pop- * ulate the pre-existing VMMOB_MAP_PTE object in pProcess with module names and * then, if failed or partially failed, try to initialize from PE file headers. +* -- H * -- pProcess * -- return */ _Success_(return) -BOOL VmmWinPte_InitializeMapText(_In_ PVMM_PROCESS pProcess); +BOOL VmmWinPte_InitializeMapText(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess); /* * Initialize the module map containing information about loaded modules in the * system. This is performed by a PEB/Ldr walk/scan of in-process memory * structures. This may be unreliable if a process is obfuscated or tampered. +* -- H * -- pProcess * -- psvaInjected = optional set of injected addresses, updated on exit. * -- return */ _Success_(return) -BOOL VmmWinLdrModule_Initialize(_In_ PVMM_PROCESS pProcess, _Inout_opt_ POB_SET psvaInjected); +BOOL VmmWinLdrModule_Initialize(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Inout_opt_ POB_SET psvaInjected); /* * Initialize the unloaded module map containing information about unloaded modules. +* -- H * -- pProcess * -- return */ _Success_(return) -BOOL VmmWinUnloadedModule_Initialize(_In_ PVMM_PROCESS pProcess); +BOOL VmmWinUnloadedModule_Initialize(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess); /* * Initialize the thread map for a specific process. * NB! The threading sub-system is dependent on pdb symbols and may take a small * amount of time before it's available after system startup. +* -- H * -- pProcess * -- return */ -BOOL VmmWinThread_Initialize(_In_ PVMM_PROCESS pProcess); +BOOL VmmWinThread_Initialize(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess); /* * Initialize Handles for a specific process. Extended information text may take * extra time to initialize. +* -- H * -- pProcess * -- fExtendedText = also fetch extended info such as handle paths/names. * -- return */ _Success_(return) -BOOL VmmWinHandle_Initialize(_In_ PVMM_PROCESS pProcess, _In_ BOOL fExtendedText); +BOOL VmmWinHandle_Initialize(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ BOOL fExtendedText); /* * Retrieve a pointer to a VMMWIN_OBJECT_TYPE if possible. Initialization of the * table takes place on first use. The table only exists in Win7+ and is is * dependant on PDB symbol functionality for initialization. +* -- H * -- iObjectType * -- return */ _Success_(return != NULL) -PVMMWIN_OBJECT_TYPE VmmWin_ObjectTypeGet(_In_ BYTE iObjectType); +PVMMWIN_OBJECT_TYPE VmmWin_ObjectTypeGet(_In_ VMM_HANDLE H, _In_ BYTE iObjectType); /* * _OBJECT_HEADER.TypeIndex is encoded on Windows 10 - this function decodes it. * https://medium.com/@ashabdalhalim/e8f907e7073a +* -- H * -- vaObjectHeader * -- iTypeIndexTableEncoded * -- return */ -BYTE VmmWin_ObjectTypeGetIndexFromEncoded(_In_ QWORD vaObjectHeader, _In_ BYTE iTypeIndexTableEncoded); +BYTE VmmWin_ObjectTypeGetIndexFromEncoded(_In_ VMM_HANDLE H, _In_ QWORD vaObjectHeader, _In_ BYTE iTypeIndexTableEncoded); /* * Try walk the EPROCESS list in the Windows kernel to enumerate processes into * the VMM/PROC file system. * NB! This may be done to refresh an existing PID cache hence migration code. +* -- H * -- pSystemProcess * -- fTotalRefresh = create completely new process entries (instead of updating). * -- psvaNoLinkEPROCESS = optional set of no-link EPROCESS virtual addresses. * -- return */ -BOOL VmmWinProcess_Enumerate(_In_ PVMM_PROCESS pSystemProcess, _In_ BOOL fRefreshTotal, _In_opt_ POB_SET psvaNoLinkEPROCESS); +BOOL VmmWinProcess_Enumerate(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ BOOL fRefreshTotal, _In_opt_ POB_SET psvaNoLinkEPROCESS); /* * Locate EPROCESS objects not linked by the EPROCESS list. * This is achieved by analyzing the object table for the SYSTEM process. * CALLER DECREF: return +* -- H * -- return = Set of vaEPROCESS if no-link addresses exist. NULL otherwise. */ -POB_SET VmmWinProcess_Enumerate_FindNoLinkProcesses(); +POB_SET VmmWinProcess_Enumerate_FindNoLinkProcesses(_In_ VMM_HANDLE H); typedef VOID(*VMMWIN_LISTTRAVERSE_PRE_CB)( + _In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ PVOID ctx, _In_ QWORD va, @@ -127,6 +139,7 @@ typedef VOID(*VMMWIN_LISTTRAVERSE_PRE_CB)( _In_ WORD iInitialEntry // entry is from index: iInitialEntry in array pvaDataStart ); typedef VOID(*VMMWIN_LISTTRAVERSE_POST_CB)( + _In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ PVOID ctx, _In_ QWORD va, @@ -143,6 +156,7 @@ typedef VOID(*VMMWIN_LISTTRAVERSE_POST_CB)( * The callback function must only return FALSE on severe errors when the list * should no longer be continued to be walked in the direction. * CALLER_DECREF: return +* -- H * -- pProcess * -- f32 = TRUE if 32-bit, FALSE if 64-bit * -- ctx = ctx to pass along to callback function (if any) @@ -155,6 +169,7 @@ typedef VOID(*VMMWIN_LISTTRAVERSE_POST_CB)( * -- pPrefetchAddressContainer = optional pointer to a PVMMOBCONTAINER containing a POB_VSET of prefetch addresses to use/update. */ VOID VmmWin_ListTraversePrefetch( + _In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ BOOL f32, _In_opt_ PVOID ctx, @@ -171,27 +186,31 @@ VOID VmmWin_ListTraversePrefetch( * Retrieve user process parameters - such as the command line (if existing). * NB! PVMMWIN_USER_PROCESS_PARAMETERS points into pProcess and must not be * free'd or used after pProcess goes out of scope or are DECREF'ed. +* -- H * -- pProcess * -- return */ -PVMMWIN_USER_PROCESS_PARAMETERS VmmWin_UserProcessParameters_Get(_In_ PVMM_PROCESS pProcess); +PVMMWIN_USER_PROCESS_PARAMETERS VmmWin_UserProcessParameters_Get(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess); /* * Create a physical memory map and assign to the global context upon success. * CALLER DECREF: return +* -- H * -- return */ -PVMMOB_MAP_PHYSMEM VmmWinPhysMemMap_Initialize(); +PVMMOB_MAP_PHYSMEM VmmWinPhysMemMap_Initialize(_In_ VMM_HANDLE H); /* * Refresh the physical memory map. +* -- H */ -VOID VmmWinPhysMemMap_Refresh(); +VOID VmmWinPhysMemMap_Refresh(_In_ VMM_HANDLE H); /* * Retrieve the account name of the user account given a SID. * NB! Names for well known SIDs will be given in the language of the system * running MemProcFS and not in the name of the analyzed system. +* -- H * -- pSID * -- uszName * -- cbuName @@ -199,18 +218,20 @@ VOID VmmWinPhysMemMap_Refresh(); * -- return */ _Success_(return) -BOOL VmmWinUser_GetName(_In_opt_ PSID pSID, _Out_writes_(cbuName) LPSTR uszName, _In_ DWORD cbuName, _Out_opt_ PBOOL pfAccountWellKnown); +BOOL VmmWinUser_GetName(_In_ VMM_HANDLE H, _In_opt_ PSID pSID, _Out_writes_(cbuName) LPSTR uszName, _In_ DWORD cbuName, _Out_opt_ PBOOL pfAccountWellKnown); /* * Create a user map and assign to the global context upon success. * CALLER DECREF: return +* -- H * -- return */ -PVMMOB_MAP_USER VmmWinUser_Initialize(); +PVMMOB_MAP_USER VmmWinUser_Initialize(_In_ VMM_HANDLE H); /* * Refresh the user map. +* -- H */ -VOID VmmWinUser_Refresh(); +VOID VmmWinUser_Refresh(_In_ VMM_HANDLE H); #endif /* __VMMWIN_H__ */ diff --git a/vmm/vmmwindef.h b/vmm/vmmwindef.h index 9c79d81..ed43c68 100644 --- a/vmm/vmmwindef.h +++ b/vmm/vmmwindef.h @@ -6,6 +6,8 @@ #define __VMMWINDEF_H__ #include "oscompatibility.h" +#define O32_FILE_OBJECT_DeviceObject 0x004 +#define O64_FILE_OBJECT_DeviceObject 0x008 #define O32_FILE_OBJECT_SectionObjectPointer 0x014 #define O64_FILE_OBJECT_SectionObjectPointer 0x028 #define O32_FILE_OBJECT_PrivateCacheMap 0x018 diff --git a/vmm/vmmwininit.c b/vmm/vmmwininit.c index 99c64c0..7b5870a 100644 --- a/vmm/vmmwininit.c +++ b/vmm/vmmwininit.c @@ -20,49 +20,51 @@ /* * Try initialize threading - this is dependent on available PDB symbols. +* -- H */ -VOID VmmWinInit_TryInitializeThreading() +VOID VmmWinInit_TryInitializeThreading(_In_ VMM_HANDLE H) { BOOL f; DWORD cbEThread = 0; - PVMM_OFFSET_ETHREAD pti = &ctxVmm->offset.ETHREAD; - f = PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_EPROCESS", "ThreadListHead", &pti->oThreadListHeadKP) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_KTHREAD", "StackBase", &pti->oStackBase) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_KTHREAD", "StackLimit", &pti->oStackLimit) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_KTHREAD", "State", &pti->oState) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_KTHREAD", "SuspendCount", &pti->oSuspendCount) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_KTHREAD", "Priority", &pti->oPriority) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_KTHREAD", "BasePriority", &pti->oBasePriority) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_KTHREAD", "WaitReason", &pti->oWaitReason) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_KTHREAD", "Teb", &pti->oTeb) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_KTHREAD", "TrapFrame", &pti->oTrapFrame) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_KTHREAD", "KernelTime", &pti->oKernelTime) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_KTHREAD", "UserTime", &pti->oUserTime) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_KTHREAD", "Affinity", &pti->oAffinity) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_ETHREAD", "CreateTime", &pti->oCreateTime) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_ETHREAD", "ExitTime", &pti->oExitTime) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_ETHREAD", "ExitStatus", &pti->oExitStatus) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_ETHREAD", "StartAddress", &pti->oStartAddress) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_ETHREAD", "ThreadListEntry", &pti->oThreadListEntry) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_ETHREAD", "Cid", &pti->oCid) && - PDB_GetTypeSize(PDB_HANDLE_KERNEL, "_ETHREAD", &cbEThread) && - (PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_KTRAP_FRAME", "Rip", &pti->oTrapRip) || PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_KTRAP_FRAME", "Eip", &pti->oTrapRip)) && - (PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_KTRAP_FRAME", "Rsp", &pti->oTrapRsp) || PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_KTRAP_FRAME", "HardwareEsp", &pti->oTrapRsp)); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_KTHREAD", "Process", &pti->oProcessOpt); // optional - does not exist in xp. - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_KTHREAD", "Running", &pti->oRunningOpt); // optional - does not exist in vista/xp. + PVMM_OFFSET_ETHREAD pti = &H->vmm.offset.ETHREAD; + f = PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_EPROCESS", "ThreadListHead", &pti->oThreadListHeadKP) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_KTHREAD", "StackBase", &pti->oStackBase) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_KTHREAD", "StackLimit", &pti->oStackLimit) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_KTHREAD", "State", &pti->oState) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_KTHREAD", "SuspendCount", &pti->oSuspendCount) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_KTHREAD", "Priority", &pti->oPriority) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_KTHREAD", "BasePriority", &pti->oBasePriority) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_KTHREAD", "WaitReason", &pti->oWaitReason) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_KTHREAD", "Teb", &pti->oTeb) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_KTHREAD", "TrapFrame", &pti->oTrapFrame) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_KTHREAD", "KernelTime", &pti->oKernelTime) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_KTHREAD", "UserTime", &pti->oUserTime) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_KTHREAD", "Affinity", &pti->oAffinity) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_ETHREAD", "CreateTime", &pti->oCreateTime) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_ETHREAD", "ExitTime", &pti->oExitTime) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_ETHREAD", "ExitStatus", &pti->oExitStatus) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_ETHREAD", "StartAddress", &pti->oStartAddress) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_ETHREAD", "ThreadListEntry", &pti->oThreadListEntry) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_ETHREAD", "Cid", &pti->oCid) && + PDB_GetTypeSize(H, PDB_HANDLE_KERNEL, "_ETHREAD", &cbEThread) && + (PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_KTRAP_FRAME", "Rip", &pti->oTrapRip) || PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_KTRAP_FRAME", "Eip", &pti->oTrapRip)) && + (PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_KTRAP_FRAME", "Rsp", &pti->oTrapRsp) || PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_KTRAP_FRAME", "HardwareEsp", &pti->oTrapRsp)); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_KTHREAD", "Process", &pti->oProcessOpt); // optional - does not exist in xp. + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_KTHREAD", "Running", &pti->oRunningOpt); // optional - does not exist in vista/xp. pti->oMax = (WORD)(cbEThread + 8); - pti->oTebStackBase = ctxVmm->f32 ? 0x004 : 0x008; - pti->oTebStackLimit = ctxVmm->f32 ? 0x008 : 0x010; - ctxVmm->fThreadMapEnabled = f; + pti->oTebStackBase = H->vmm.f32 ? 0x004 : 0x008; + pti->oTebStackLimit = H->vmm.f32 ? 0x008 : 0x010; + H->vmm.fThreadMapEnabled = f; } /* * Try initialize not yet initialized values in the optional windows kernel -* context ctxVmm->kernel.opt +* context H->vmm.kernel.opt * This function should be run once the system is fully up and running. * This is a best-effort function, uninitialized values will remain zero. +* -- H */ -VOID VmmWinInit_TryInitializeKernelOptionalValues() +VOID VmmWinInit_TryInitializeKernelOptionalValues(_In_ VMM_HANDLE H) { BOOL f; PVMM_PROCESS pObSystemProcess = NULL; @@ -72,217 +74,219 @@ VOID VmmWinInit_TryInitializeKernelOptionalValues() DWORD oKdpDataBlockEncoded, dwKDBG, dwo; BYTE bKdpDataBlockEncoded; PVMM_OFFSET_FILE pof; - if(ctxVmm->kernel.opt.fInitialized) { return; } - if(!(pObSystemProcess = VmmProcessGet(4))) { return; } + if(H->vmm.kernel.opt.fInitialized) { return; } + if(!(pObSystemProcess = VmmProcessGet(H, 4))) { return; } // Optional EPROCESS and _TOKEN offsets - if(!ctxVmm->offset.EPROCESS.opt.Token) { + if(!H->vmm.offset.EPROCESS.opt.Token) { // EPROCESS / KPROCESS - if(PDB_GetTypeChildOffset(PDB_HANDLE_KERNEL, "_EPROCESS", "Token", &dwo) && (dwo < pObSystemProcess->win.EPROCESS.cb - 8)) { - ctxVmm->offset.EPROCESS.opt.Token = (WORD)dwo; + if(PDB_GetTypeChildOffset(H, PDB_HANDLE_KERNEL, "_EPROCESS", "Token", &dwo) && (dwo < pObSystemProcess->win.EPROCESS.cb - 8)) { + H->vmm.offset.EPROCESS.opt.Token = (WORD)dwo; } - if(PDB_GetTypeChildOffset(PDB_HANDLE_KERNEL, "_EPROCESS", "CreateTime", &dwo) && (dwo < pObSystemProcess->win.EPROCESS.cb - 8)) { - ctxVmm->offset.EPROCESS.opt.CreateTime = (WORD)dwo; + if(PDB_GetTypeChildOffset(H, PDB_HANDLE_KERNEL, "_EPROCESS", "CreateTime", &dwo) && (dwo < pObSystemProcess->win.EPROCESS.cb - 8)) { + H->vmm.offset.EPROCESS.opt.CreateTime = (WORD)dwo; } - if(PDB_GetTypeChildOffset(PDB_HANDLE_KERNEL, "_EPROCESS", "ExitTime", &dwo) && (dwo < pObSystemProcess->win.EPROCESS.cb - 8)) { - ctxVmm->offset.EPROCESS.opt.ExitTime = (WORD)dwo; + if(PDB_GetTypeChildOffset(H, PDB_HANDLE_KERNEL, "_EPROCESS", "ExitTime", &dwo) && (dwo < pObSystemProcess->win.EPROCESS.cb - 8)) { + H->vmm.offset.EPROCESS.opt.ExitTime = (WORD)dwo; } - if(PDB_GetTypeChildOffset(PDB_HANDLE_KERNEL, "_KPROCESS", "KernelTime", &dwo) && (dwo < pObSystemProcess->win.EPROCESS.cb - 8)) { - ctxVmm->offset.EPROCESS.opt.KernelTime = (WORD)dwo; + if(PDB_GetTypeChildOffset(H, PDB_HANDLE_KERNEL, "_KPROCESS", "KernelTime", &dwo) && (dwo < pObSystemProcess->win.EPROCESS.cb - 8)) { + H->vmm.offset.EPROCESS.opt.KernelTime = (WORD)dwo; } - if(PDB_GetTypeChildOffset(PDB_HANDLE_KERNEL, "_KPROCESS", "UserTime", &dwo) && (dwo < pObSystemProcess->win.EPROCESS.cb - 8)) { - ctxVmm->offset.EPROCESS.opt.UserTime = (WORD)dwo; + if(PDB_GetTypeChildOffset(H, PDB_HANDLE_KERNEL, "_KPROCESS", "UserTime", &dwo) && (dwo < pObSystemProcess->win.EPROCESS.cb - 8)) { + H->vmm.offset.EPROCESS.opt.UserTime = (WORD)dwo; } // TOKEN - PDB_GetTypeSizeShort(PDB_HANDLE_KERNEL, "_TOKEN", &ctxVmm->offset.EPROCESS.opt.TOKEN_cb); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_TOKEN", "IntegrityLevelIndex", &ctxVmm->offset.EPROCESS.opt.TOKEN_IntegrityLevelIndex); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_TOKEN", "SessionId", &ctxVmm->offset.EPROCESS.opt.TOKEN_SessionId); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_TOKEN", "TokenId", &ctxVmm->offset.EPROCESS.opt.TOKEN_TokenId); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_TOKEN", "UserAndGroups", &ctxVmm->offset.EPROCESS.opt.TOKEN_UserAndGroups); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_TOKEN", "UserAndGroupCount", &ctxVmm->offset.EPROCESS.opt.TOKEN_UserAndGroupCount); + PDB_GetTypeSizeShort(H, PDB_HANDLE_KERNEL, "_TOKEN", &H->vmm.offset.EPROCESS.opt.TOKEN_cb); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_TOKEN", "IntegrityLevelIndex", &H->vmm.offset.EPROCESS.opt.TOKEN_IntegrityLevelIndex); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_TOKEN", "SessionId", &H->vmm.offset.EPROCESS.opt.TOKEN_SessionId); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_TOKEN", "TokenId", &H->vmm.offset.EPROCESS.opt.TOKEN_TokenId); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_TOKEN", "UserAndGroups", &H->vmm.offset.EPROCESS.opt.TOKEN_UserAndGroups); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_TOKEN", "UserAndGroupCount", &H->vmm.offset.EPROCESS.opt.TOKEN_UserAndGroupCount); } // Optional _FILE_OBJECT related offsets - if(!ctxVmm->offset.FILE.fValid) { - pof = &ctxVmm->offset.FILE; + if(!H->vmm.offset.FILE.fValid) { + pof = &H->vmm.offset.FILE; // _FILE_OBJECT - PDB_GetTypeSizeShort(PDB_HANDLE_KERNEL, "_FILE_OBJECT", &pof->_FILE_OBJECT.cb); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_FILE_OBJECT", "DeviceObject", &pof->_FILE_OBJECT.oDeviceObject); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_FILE_OBJECT", "SectionObjectPointer", &pof->_FILE_OBJECT.oSectionObjectPointer); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_FILE_OBJECT", "FileName", &pof->_FILE_OBJECT.oFileName); - pof->_FILE_OBJECT.oFileNameBuffer = pof->_FILE_OBJECT.oFileName + (ctxVmm->f32 ? 4 : 8); + PDB_GetTypeSizeShort(H, PDB_HANDLE_KERNEL, "_FILE_OBJECT", &pof->_FILE_OBJECT.cb); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_FILE_OBJECT", "DeviceObject", &pof->_FILE_OBJECT.oDeviceObject); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_FILE_OBJECT", "SectionObjectPointer", &pof->_FILE_OBJECT.oSectionObjectPointer); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_FILE_OBJECT", "FileName", &pof->_FILE_OBJECT.oFileName); + pof->_FILE_OBJECT.oFileNameBuffer = pof->_FILE_OBJECT.oFileName + (H->vmm.f32 ? 4 : 8); // _SECTION_OBJECT_POINTERS - PDB_GetTypeSizeShort(PDB_HANDLE_KERNEL, "_SECTION_OBJECT_POINTERS", &pof->_SECTION_OBJECT_POINTERS.cb); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_SECTION_OBJECT_POINTERS", "DataSectionObject", &pof->_SECTION_OBJECT_POINTERS.oDataSectionObject); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_SECTION_OBJECT_POINTERS", "SharedCacheMap", &pof->_SECTION_OBJECT_POINTERS.oSharedCacheMap); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_SECTION_OBJECT_POINTERS", "ImageSectionObject", &pof->_SECTION_OBJECT_POINTERS.oImageSectionObject); + PDB_GetTypeSizeShort(H, PDB_HANDLE_KERNEL, "_SECTION_OBJECT_POINTERS", &pof->_SECTION_OBJECT_POINTERS.cb); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_SECTION_OBJECT_POINTERS", "DataSectionObject", &pof->_SECTION_OBJECT_POINTERS.oDataSectionObject); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_SECTION_OBJECT_POINTERS", "SharedCacheMap", &pof->_SECTION_OBJECT_POINTERS.oSharedCacheMap); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_SECTION_OBJECT_POINTERS", "ImageSectionObject", &pof->_SECTION_OBJECT_POINTERS.oImageSectionObject); // _VACB - PDB_GetTypeSizeShort(PDB_HANDLE_KERNEL, "_VACB", &pof->_VACB.cb); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_VACB", "BaseAddress", &pof->_VACB.oBaseAddress); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_VACB", "SharedCacheMap", &pof->_VACB.oSharedCacheMap); + PDB_GetTypeSizeShort(H, PDB_HANDLE_KERNEL, "_VACB", &pof->_VACB.cb); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_VACB", "BaseAddress", &pof->_VACB.oBaseAddress); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_VACB", "SharedCacheMap", &pof->_VACB.oSharedCacheMap); // _SHARED_CACHE_MAP - PDB_GetTypeSizeShort(PDB_HANDLE_KERNEL, "_SHARED_CACHE_MAP", &pof->_SHARED_CACHE_MAP.cb); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_SHARED_CACHE_MAP", "FileSize", &pof->_SHARED_CACHE_MAP.oFileSize); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_SHARED_CACHE_MAP", "SectionSize", &pof->_SHARED_CACHE_MAP.oSectionSize); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_SHARED_CACHE_MAP", "ValidDataLength", &pof->_SHARED_CACHE_MAP.oValidDataLength); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_SHARED_CACHE_MAP", "InitialVacbs", &pof->_SHARED_CACHE_MAP.oInitialVacbs); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_SHARED_CACHE_MAP", "Vacbs", &pof->_SHARED_CACHE_MAP.oVacbs); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_SHARED_CACHE_MAP", "FileObjectFastRef", &pof->_SHARED_CACHE_MAP.oFileObjectFastRef); + PDB_GetTypeSizeShort(H, PDB_HANDLE_KERNEL, "_SHARED_CACHE_MAP", &pof->_SHARED_CACHE_MAP.cb); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_SHARED_CACHE_MAP", "FileSize", &pof->_SHARED_CACHE_MAP.oFileSize); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_SHARED_CACHE_MAP", "SectionSize", &pof->_SHARED_CACHE_MAP.oSectionSize); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_SHARED_CACHE_MAP", "ValidDataLength", &pof->_SHARED_CACHE_MAP.oValidDataLength); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_SHARED_CACHE_MAP", "InitialVacbs", &pof->_SHARED_CACHE_MAP.oInitialVacbs); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_SHARED_CACHE_MAP", "Vacbs", &pof->_SHARED_CACHE_MAP.oVacbs); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_SHARED_CACHE_MAP", "FileObjectFastRef", &pof->_SHARED_CACHE_MAP.oFileObjectFastRef); // _CONTROL_AREA - PDB_GetTypeSizeShort(PDB_HANDLE_KERNEL, "_CONTROL_AREA", &pof->_CONTROL_AREA.cb); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_CONTROL_AREA", "Segment", &pof->_CONTROL_AREA.oSegment); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_CONTROL_AREA", "FilePointer", &pof->_CONTROL_AREA.oFilePointer); + PDB_GetTypeSizeShort(H, PDB_HANDLE_KERNEL, "_CONTROL_AREA", &pof->_CONTROL_AREA.cb); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_CONTROL_AREA", "Segment", &pof->_CONTROL_AREA.oSegment); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_CONTROL_AREA", "FilePointer", &pof->_CONTROL_AREA.oFilePointer); // _SEGMENT - PDB_GetTypeSizeShort(PDB_HANDLE_KERNEL, "_SEGMENT", &pof->_SEGMENT.cb); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_SEGMENT", "ControlArea", &pof->_SEGMENT.oControlArea); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_SEGMENT", "SizeOfSegment", &pof->_SEGMENT.oSizeOfSegment); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_SEGMENT", "PrototypePte", &pof->_SEGMENT.oPrototypePte); + PDB_GetTypeSizeShort(H, PDB_HANDLE_KERNEL, "_SEGMENT", &pof->_SEGMENT.cb); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_SEGMENT", "ControlArea", &pof->_SEGMENT.oControlArea); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_SEGMENT", "SizeOfSegment", &pof->_SEGMENT.oSizeOfSegment); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_SEGMENT", "PrototypePte", &pof->_SEGMENT.oPrototypePte); // _SUBSECTION - PDB_GetTypeSizeShort(PDB_HANDLE_KERNEL, "_SUBSECTION", &pof->_SUBSECTION.cb); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_SUBSECTION", "ControlArea", &pof->_SUBSECTION.oControlArea); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_SUBSECTION", "NextSubsection", &pof->_SUBSECTION.oNextSubsection); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_SUBSECTION", "NumberOfFullSectors", &pof->_SUBSECTION.oNumberOfFullSectors); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_SUBSECTION", "PtesInSubsection", &pof->_SUBSECTION.oPtesInSubsection); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_SUBSECTION", "StartingSector", &pof->_SUBSECTION.oStartingSector); - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_SUBSECTION", "SubsectionBase", &pof->_SUBSECTION.oSubsectionBase); + PDB_GetTypeSizeShort(H, PDB_HANDLE_KERNEL, "_SUBSECTION", &pof->_SUBSECTION.cb); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_SUBSECTION", "ControlArea", &pof->_SUBSECTION.oControlArea); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_SUBSECTION", "NextSubsection", &pof->_SUBSECTION.oNextSubsection); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_SUBSECTION", "NumberOfFullSectors", &pof->_SUBSECTION.oNumberOfFullSectors); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_SUBSECTION", "PtesInSubsection", &pof->_SUBSECTION.oPtesInSubsection); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_SUBSECTION", "StartingSector", &pof->_SUBSECTION.oStartingSector); + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_SUBSECTION", "SubsectionBase", &pof->_SUBSECTION.oSubsectionBase); pof->fValid = pof->_SUBSECTION.cb ? TRUE : FALSE; } // cpu count - if(!ctxVmm->kernel.opt.cCPUs) { - PDB_GetSymbolDWORD(PDB_HANDLE_KERNEL, "KiTotalCpuSetCount", pObSystemProcess, &ctxVmm->kernel.opt.cCPUs); - if(ctxVmm->kernel.opt.cCPUs > 128) { ctxVmm->kernel.opt.cCPUs = 0; } + if(!H->vmm.kernel.opt.cCPUs) { + PDB_GetSymbolDWORD(H, PDB_HANDLE_KERNEL, "KiTotalCpuSetCount", pObSystemProcess, &H->vmm.kernel.opt.cCPUs); + if(H->vmm.kernel.opt.cCPUs > 128) { H->vmm.kernel.opt.cCPUs = 0; } } - if(!ctxVmm->kernel.opt.cCPUs && VmmWinReg_KeyHiveGetByFullPath("HKLM\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor", &pObHive, &pObKey)) { - pmObSubkeys = VmmWinReg_KeyList(pObHive, pObKey); - ctxVmm->kernel.opt.cCPUs = ObMap_Size(pmObSubkeys); + if(!H->vmm.kernel.opt.cCPUs && VmmWinReg_KeyHiveGetByFullPath(H, "HKLM\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor", &pObHive, &pObKey)) { + pmObSubkeys = VmmWinReg_KeyList(H, pObHive, pObKey); + H->vmm.kernel.opt.cCPUs = ObMap_Size(pmObSubkeys); } // pfn database & pfn subsystem initialize - if(!ctxVmm->kernel.opt.vaPfnDatabase) { - PDB_GetSymbolPTR(PDB_HANDLE_KERNEL, "MmPfnDatabase", pObSystemProcess, &ctxVmm->kernel.opt.vaPfnDatabase); + if(!H->vmm.kernel.opt.vaPfnDatabase) { + PDB_GetSymbolPTR(H, PDB_HANDLE_KERNEL, "MmPfnDatabase", pObSystemProcess, &H->vmm.kernel.opt.vaPfnDatabase); } - MmPfn_Initialize(pObSystemProcess); + MmPfn_Initialize(H, pObSystemProcess); // PsLoadedModuleListExp - if(!ctxVmm->kernel.opt.vaPsLoadedModuleListExp) { - PDB_GetSymbolAddress(PDB_HANDLE_KERNEL, "PsLoadedModuleList", &ctxVmm->kernel.opt.vaPsLoadedModuleListExp); + if(!H->vmm.kernel.opt.vaPsLoadedModuleListExp) { + PDB_GetSymbolAddress(H, PDB_HANDLE_KERNEL, "PsLoadedModuleList", &H->vmm.kernel.opt.vaPsLoadedModuleListExp); } // MmUnloadedDrivers / MmLastUnloadedDriver - if(!ctxVmm->kernel.opt.vaMmUnloadedDrivers || !ctxVmm->kernel.opt.vaMmLastUnloadedDriver) { - PDB_GetSymbolAddress(PDB_HANDLE_KERNEL, "MmUnloadedDrivers", &ctxVmm->kernel.opt.vaMmUnloadedDrivers); - PDB_GetSymbolAddress(PDB_HANDLE_KERNEL, "MmLastUnloadedDriver", &ctxVmm->kernel.opt.vaMmLastUnloadedDriver); + if(!H->vmm.kernel.opt.vaMmUnloadedDrivers || !H->vmm.kernel.opt.vaMmLastUnloadedDriver) { + PDB_GetSymbolAddress(H, PDB_HANDLE_KERNEL, "MmUnloadedDrivers", &H->vmm.kernel.opt.vaMmUnloadedDrivers); + PDB_GetSymbolAddress(H, PDB_HANDLE_KERNEL, "MmLastUnloadedDriver", &H->vmm.kernel.opt.vaMmLastUnloadedDriver); } // KdDebuggerDataBlock (KDBG) - if(!ctxVmm->kernel.opt.KDBG.va && PDB_GetSymbolAddress(PDB_HANDLE_KERNEL, "KdDebuggerDataBlock", &ctxVmm->kernel.opt.KDBG.va)) { - f = !ctxVmm->f32 && - VmmRead(pObSystemProcess, ctxVmm->kernel.opt.KDBG.va + 0x10, (PBYTE)&dwKDBG, sizeof(DWORD)) && (dwKDBG != 0x4742444b) && - PDB_GetSymbolOffset(PDB_HANDLE_KERNEL, "KdpDataBlockEncoded", &oKdpDataBlockEncoded) && - PDB_GetSymbolPBYTE(PDB_HANDLE_KERNEL, "KdpDataBlockEncoded", pObSystemProcess, &bKdpDataBlockEncoded, 1) && + if(!H->vmm.kernel.opt.KDBG.va && PDB_GetSymbolAddress(H, PDB_HANDLE_KERNEL, "KdDebuggerDataBlock", &H->vmm.kernel.opt.KDBG.va)) { + f = !H->vmm.f32 && + VmmRead(H, pObSystemProcess, H->vmm.kernel.opt.KDBG.va + 0x10, (PBYTE)&dwKDBG, sizeof(DWORD)) && (dwKDBG != 0x4742444b) && + PDB_GetSymbolOffset(H, PDB_HANDLE_KERNEL, "KdpDataBlockEncoded", &oKdpDataBlockEncoded) && + PDB_GetSymbolPBYTE(H, PDB_HANDLE_KERNEL, "KdpDataBlockEncoded", pObSystemProcess, &bKdpDataBlockEncoded, 1) && (bKdpDataBlockEncoded == 1); if(f) { - ctxVmm->kernel.opt.KDBG.vaKdpDataBlockEncoded = ctxVmm->kernel.vaBase + oKdpDataBlockEncoded; - PDB_GetSymbolQWORD(PDB_HANDLE_KERNEL, "KiWaitAlways", pObSystemProcess, &ctxVmm->kernel.opt.KDBG.qwKiWaitAlways); - PDB_GetSymbolQWORD(PDB_HANDLE_KERNEL, "KiWaitNever", pObSystemProcess, &ctxVmm->kernel.opt.KDBG.qwKiWaitNever); + H->vmm.kernel.opt.KDBG.vaKdpDataBlockEncoded = H->vmm.kernel.vaBase + oKdpDataBlockEncoded; + PDB_GetSymbolQWORD(H, PDB_HANDLE_KERNEL, "KiWaitAlways", pObSystemProcess, &H->vmm.kernel.opt.KDBG.qwKiWaitAlways); + PDB_GetSymbolQWORD(H, PDB_HANDLE_KERNEL, "KiWaitNever", pObSystemProcess, &H->vmm.kernel.opt.KDBG.qwKiWaitNever); } } // IopInvalidDeviceRequest - if(!ctxVmm->kernel.opt.vaIopInvalidDeviceRequest) { - PDB_GetSymbolAddress(PDB_HANDLE_KERNEL, "IopInvalidDeviceRequest", &ctxVmm->kernel.opt.vaIopInvalidDeviceRequest); + if(!H->vmm.kernel.opt.vaIopInvalidDeviceRequest) { + PDB_GetSymbolAddress(H, PDB_HANDLE_KERNEL, "IopInvalidDeviceRequest", &H->vmm.kernel.opt.vaIopInvalidDeviceRequest); } // _OBJECT_HEADER InfoMask headers: - PDB_GetTypeSizeShort(PDB_HANDLE_KERNEL, "_OBJECT_HEADER_CREATOR_INFO", &ctxVmm->offset._OBJECT_HEADER_CREATOR_INFO.cb); - PDB_GetTypeSizeShort(PDB_HANDLE_KERNEL, "_OBJECT_HEADER_NAME_INFO", &ctxVmm->offset._OBJECT_HEADER_NAME_INFO.cb); - PDB_GetTypeSizeShort(PDB_HANDLE_KERNEL, "_OBJECT_HEADER_HANDLE_INFO", &ctxVmm->offset._OBJECT_HEADER_HANDLE_INFO.cb); - PDB_GetTypeSizeShort(PDB_HANDLE_KERNEL, "_OBJECT_HEADER_QUOTA_INFO", &ctxVmm->offset._OBJECT_HEADER_QUOTA_INFO.cb); - PDB_GetTypeSizeShort(PDB_HANDLE_KERNEL, "_OBJECT_HEADER_PROCESS_INFO", &ctxVmm->offset._OBJECT_HEADER_PROCESS_INFO.cb); - PDB_GetTypeSizeShort(PDB_HANDLE_KERNEL, "_OBJECT_HEADER_AUDIT_INFO", &ctxVmm->offset._OBJECT_HEADER_AUDIT_INFO.cb); - PDB_GetTypeSizeShort(PDB_HANDLE_KERNEL, "_POOL_HEADER", &ctxVmm->offset._POOL_HEADER.cb); + PDB_GetTypeSizeShort(H, PDB_HANDLE_KERNEL, "_OBJECT_HEADER_CREATOR_INFO", &H->vmm.offset._OBJECT_HEADER_CREATOR_INFO.cb); + PDB_GetTypeSizeShort(H, PDB_HANDLE_KERNEL, "_OBJECT_HEADER_NAME_INFO", &H->vmm.offset._OBJECT_HEADER_NAME_INFO.cb); + PDB_GetTypeSizeShort(H, PDB_HANDLE_KERNEL, "_OBJECT_HEADER_HANDLE_INFO", &H->vmm.offset._OBJECT_HEADER_HANDLE_INFO.cb); + PDB_GetTypeSizeShort(H, PDB_HANDLE_KERNEL, "_OBJECT_HEADER_QUOTA_INFO", &H->vmm.offset._OBJECT_HEADER_QUOTA_INFO.cb); + PDB_GetTypeSizeShort(H, PDB_HANDLE_KERNEL, "_OBJECT_HEADER_PROCESS_INFO", &H->vmm.offset._OBJECT_HEADER_PROCESS_INFO.cb); + PDB_GetTypeSizeShort(H, PDB_HANDLE_KERNEL, "_OBJECT_HEADER_AUDIT_INFO", &H->vmm.offset._OBJECT_HEADER_AUDIT_INFO.cb); + PDB_GetTypeSizeShort(H, PDB_HANDLE_KERNEL, "_POOL_HEADER", &H->vmm.offset._POOL_HEADER.cb); // Other: - PDB_GetSymbolQWORD(PDB_HANDLE_KERNEL, "KeBootTime", pObSystemProcess, &ctxVmm->kernel.opt.ftBootTime); + PDB_GetSymbolQWORD(H, PDB_HANDLE_KERNEL, "KeBootTime", pObSystemProcess, &H->vmm.kernel.opt.ftBootTime); // Cleanup Ob_DECREF(pObKey); Ob_DECREF(pObHive); Ob_DECREF(pmObSubkeys); Ob_DECREF(pObSystemProcess); - ctxVmm->kernel.opt.fInitialized = TRUE; + H->vmm.kernel.opt.fInitialized = TRUE; } /* * Log heap offsets */ -VOID VmmWinInit_InitializeOffsetStatic_Heap_Print(_In_ BOOL f32, _In_ PVMM_OFFSET_HEAP po) +VOID VmmWinInit_InitializeOffsetStatic_Heap_Print(_In_ VMM_HANDLE H, _In_ BOOL f32, _In_ PVMM_OFFSET_HEAP po) { - if(!VmmLogIsActive(MID_OFFSET, LOGLEVEL_6_TRACE)) { return; } - VmmLog(MID_OFFSET, LOGLEVEL_6_TRACE, "HEAP: %s(%s)", (po->fValid ? "SUCCESS" : "FAIL"), (f32 ? "32" : "64")); - VmmLog(MID_OFFSET, LOGLEVEL_6_TRACE, " _HEAP: Encoding: %03x VirtualAllocdBlocks: %03x FrontEndHeap: %03x FrontEndHeapType: %03x" , + if(!VmmLogIsActive(H, MID_OFFSET, LOGLEVEL_6_TRACE)) { return; } + VmmLog(H, MID_OFFSET, LOGLEVEL_6_TRACE, "HEAP: %s(%s)", (po->fValid ? "SUCCESS" : "FAIL"), (f32 ? "32" : "64")); + VmmLog(H, MID_OFFSET, LOGLEVEL_6_TRACE, " _HEAP: Encoding: %03x VirtualAllocdBlocks: %03x FrontEndHeap: %03x FrontEndHeapType: %03x" , po->nt.HEAP.Encoding, po->nt.HEAP.VirtualAllocdBlocks, po->nt.HEAP.FrontEndHeap, po->nt.HEAP.FrontEndHeapType); - VmmLog(MID_OFFSET, LOGLEVEL_6_TRACE, " _HEAP_SEGMENT: FirstEntry(%03x FirstEntry(%03x", + VmmLog(H, MID_OFFSET, LOGLEVEL_6_TRACE, " _HEAP_SEGMENT: FirstEntry(%03x FirstEntry(%03x", po->nt.HEAP_SEGMENT.FirstEntry, po->nt.HEAP_SEGMENT.LastValidEntry); - VmmLog(MID_OFFSET, LOGLEVEL_6_TRACE, " _HEAP_USERDATA_HEADER: Signature: %03x EncodedOffsets: %03x BusyBitmap: %03x BitmapData: %03x", + VmmLog(H, MID_OFFSET, LOGLEVEL_6_TRACE, " _HEAP_USERDATA_HEADER: Signature: %03x EncodedOffsets: %03x BusyBitmap: %03x BitmapData: %03x", po->nt.HEAP_USERDATA_HEADER.Signature, po->nt.HEAP_USERDATA_HEADER.EncodedOffsets, po->nt.HEAP_USERDATA_HEADER.BusyBitmap, po->nt.HEAP_USERDATA_HEADER.BitmapData); - VmmLog(MID_OFFSET, LOGLEVEL_6_TRACE, " _SEGMENT_HEAP: LargeAllocMetadata: %03x LargeReservedPages: %03x SegContexts: %03x", + VmmLog(H, MID_OFFSET, LOGLEVEL_6_TRACE, " _SEGMENT_HEAP: LargeAllocMetadata: %03x LargeReservedPages: %03x SegContexts: %03x", po->seg.SEGMENT_HEAP.LargeAllocMetadata, po->seg.SEGMENT_HEAP.LargeReservedPages, po->seg.SEGMENT_HEAP.SegContexts); - VmmLog(MID_OFFSET, LOGLEVEL_6_TRACE, " _HEAP_SEG_CONTEXT: SegmentListHead: %03x UnitShift: %03x FirstDescriptorIndex: %03x", + VmmLog(H, MID_OFFSET, LOGLEVEL_6_TRACE, " _HEAP_SEG_CONTEXT: SegmentListHead: %03x UnitShift: %03x FirstDescriptorIndex: %03x", po->seg.HEAP_SEG_CONTEXT.SegmentListHead, po->seg.HEAP_SEG_CONTEXT.UnitShift, po->seg.HEAP_SEG_CONTEXT.FirstDescriptorIndex); - VmmLog(MID_OFFSET, LOGLEVEL_6_TRACE, " _HEAP_PAGE_RANGE_DESCRIPTOR: TreeSignature: %03x RangeFlags: %03x UnitSize: %03x", + VmmLog(H, MID_OFFSET, LOGLEVEL_6_TRACE, " _HEAP_PAGE_RANGE_DESCRIPTOR: TreeSignature: %03x RangeFlags: %03x UnitSize: %03x", po->seg.HEAP_PAGE_RANGE_DESCRIPTOR.TreeSignature, po->seg.HEAP_PAGE_RANGE_DESCRIPTOR.RangeFlags, po->seg.HEAP_PAGE_RANGE_DESCRIPTOR.UnitSize); - VmmLog(MID_OFFSET, LOGLEVEL_6_TRACE, " _HEAP_LFH_SUBSEGMENT: BlockOffsets: %03x BlockBitmap: %03x", + VmmLog(H, MID_OFFSET, LOGLEVEL_6_TRACE, " _HEAP_LFH_SUBSEGMENT: BlockOffsets: %03x BlockBitmap: %03x", po->seg.HEAP_LFH_SUBSEGMENT.BlockOffsets, po->seg.HEAP_LFH_SUBSEGMENT.BlockBitmap); - VmmLog(MID_OFFSET, LOGLEVEL_6_TRACE, " _SEGMENT_HEAP %03x _HEAP_SEG_CONTEXT %03x _HEAP_PAGE_SEGMENT %03x _HEAP_PAGE_RANGE_DESCRIPTOR %03x _HEAP_VS_CHUNK_HEADER %03x ", + VmmLog(H, MID_OFFSET, LOGLEVEL_6_TRACE, " _SEGMENT_HEAP %03x _HEAP_SEG_CONTEXT %03x _HEAP_PAGE_SEGMENT %03x _HEAP_PAGE_RANGE_DESCRIPTOR %03x _HEAP_VS_CHUNK_HEADER %03x ", po->seg.SEGMENT_HEAP.cb, po->seg.HEAP_SEG_CONTEXT.cb, po->seg.HEAP_PAGE_SEGMENT.cb, po->seg.HEAP_PAGE_RANGE_DESCRIPTOR.cb, po->seg.HEAP_VS_CHUNK_HEADER.cb); } /* * Initialization of heap offsets statically based on build number. +* -- H */ -VOID VmmWinInit_InitializeOffsetStatic_Heap() +VOID VmmWinInit_InitializeOffsetStatic_Heap(_In_ VMM_HANDLE H) { DWORD i; BOOL f32; PDB_HANDLE hPDB; PVMM_OFFSET_HEAP po; for(i = 0; i < 2; i++) { - if(ctxVmm->f32) { + if(H->vmm.f32) { if(i) { return; } f32 = TRUE; hPDB = PDB_HANDLE_NTDLL; - po = &ctxVmm->offset.HEAP32; + po = &H->vmm.offset.HEAP32; } else { f32 = i ? FALSE : TRUE; hPDB = f32 ? PDB_HANDLE_NTDLL_WOW64 : PDB_HANDLE_NTDLL; - po = f32 ? &ctxVmm->offset.HEAP32 : &ctxVmm->offset.HEAP64; + po = f32 ? &H->vmm.offset.HEAP32 : &H->vmm.offset.HEAP64; } // NT HEAP: - PDB_GetTypeChildOffsetShort(hPDB, "_HEAP", "Encoding", &po->nt.HEAP.Encoding); - PDB_GetTypeChildOffsetShort(hPDB, "_HEAP", "VirtualAllocdBlocks", &po->nt.HEAP.VirtualAllocdBlocks); - PDB_GetTypeChildOffsetShort(hPDB, "_HEAP", "FrontEndHeap", &po->nt.HEAP.FrontEndHeap); - PDB_GetTypeChildOffsetShort(hPDB, "_HEAP", "FrontEndHeapType", &po->nt.HEAP.FrontEndHeapType); - PDB_GetTypeChildOffsetShort(hPDB, "_HEAP_SEGMENT", "FirstEntry", &po->nt.HEAP_SEGMENT.FirstEntry); - PDB_GetTypeChildOffsetShort(hPDB, "_HEAP_SEGMENT", "LastValidEntry", &po->nt.HEAP_SEGMENT.LastValidEntry); - PDB_GetTypeChildOffsetShort(hPDB, "_HEAP_USERDATA_HEADER", "Signature", &po->nt.HEAP_USERDATA_HEADER.Signature); - PDB_GetTypeChildOffsetShort(hPDB, "_HEAP_USERDATA_HEADER", "EncodedOffsets", &po->nt.HEAP_USERDATA_HEADER.EncodedOffsets); - PDB_GetTypeChildOffsetShort(hPDB, "_HEAP_USERDATA_HEADER", "BusyBitmap", &po->nt.HEAP_USERDATA_HEADER.BusyBitmap); - PDB_GetTypeChildOffsetShort(hPDB, "_HEAP_USERDATA_HEADER", "BitmapData", &po->nt.HEAP_USERDATA_HEADER.BitmapData); + PDB_GetTypeChildOffsetShort(H, hPDB, "_HEAP", "Encoding", &po->nt.HEAP.Encoding); + PDB_GetTypeChildOffsetShort(H, hPDB, "_HEAP", "VirtualAllocdBlocks", &po->nt.HEAP.VirtualAllocdBlocks); + PDB_GetTypeChildOffsetShort(H, hPDB, "_HEAP", "FrontEndHeap", &po->nt.HEAP.FrontEndHeap); + PDB_GetTypeChildOffsetShort(H, hPDB, "_HEAP", "FrontEndHeapType", &po->nt.HEAP.FrontEndHeapType); + PDB_GetTypeChildOffsetShort(H, hPDB, "_HEAP_SEGMENT", "FirstEntry", &po->nt.HEAP_SEGMENT.FirstEntry); + PDB_GetTypeChildOffsetShort(H, hPDB, "_HEAP_SEGMENT", "LastValidEntry", &po->nt.HEAP_SEGMENT.LastValidEntry); + PDB_GetTypeChildOffsetShort(H, hPDB, "_HEAP_USERDATA_HEADER", "Signature", &po->nt.HEAP_USERDATA_HEADER.Signature); + PDB_GetTypeChildOffsetShort(H, hPDB, "_HEAP_USERDATA_HEADER", "EncodedOffsets", &po->nt.HEAP_USERDATA_HEADER.EncodedOffsets); + PDB_GetTypeChildOffsetShort(H, hPDB, "_HEAP_USERDATA_HEADER", "BusyBitmap", &po->nt.HEAP_USERDATA_HEADER.BusyBitmap); + PDB_GetTypeChildOffsetShort(H, hPDB, "_HEAP_USERDATA_HEADER", "BitmapData", &po->nt.HEAP_USERDATA_HEADER.BitmapData); // SEGMENT HEAP: - PDB_GetTypeChildOffsetShort(hPDB, "_SEGMENT_HEAP", "LargeAllocMetadata", &po->seg.SEGMENT_HEAP.LargeAllocMetadata); - PDB_GetTypeChildOffsetShort(hPDB, "_SEGMENT_HEAP", "LargeReservedPages", &po->seg.SEGMENT_HEAP.LargeReservedPages); - PDB_GetTypeChildOffsetShort(hPDB, "_SEGMENT_HEAP", "SegContexts", &po->seg.SEGMENT_HEAP.SegContexts); - PDB_GetTypeChildOffsetShort(hPDB, "_HEAP_SEG_CONTEXT", "SegmentListHead", &po->seg.HEAP_SEG_CONTEXT.SegmentListHead); - PDB_GetTypeChildOffsetShort(hPDB, "_HEAP_SEG_CONTEXT", "UnitShift", &po->seg.HEAP_SEG_CONTEXT.UnitShift); - PDB_GetTypeChildOffsetShort(hPDB, "_HEAP_SEG_CONTEXT", "FirstDescriptorIndex", &po->seg.HEAP_SEG_CONTEXT.FirstDescriptorIndex); - PDB_GetTypeChildOffsetShort(hPDB, "_HEAP_PAGE_RANGE_DESCRIPTOR", "TreeSignature", &po->seg.HEAP_PAGE_RANGE_DESCRIPTOR.TreeSignature); - PDB_GetTypeChildOffsetShort(hPDB, "_HEAP_PAGE_RANGE_DESCRIPTOR", "RangeFlags", &po->seg.HEAP_PAGE_RANGE_DESCRIPTOR.RangeFlags); - PDB_GetTypeChildOffsetShort(hPDB, "_HEAP_PAGE_RANGE_DESCRIPTOR", "UnitSize", &po->seg.HEAP_PAGE_RANGE_DESCRIPTOR.UnitSize); - PDB_GetTypeChildOffsetShort(hPDB, "_HEAP_LFH_SUBSEGMENT", "BlockOffsets", &po->seg.HEAP_LFH_SUBSEGMENT.BlockOffsets); - PDB_GetTypeChildOffsetShort(hPDB, "_HEAP_LFH_SUBSEGMENT", "BlockBitmap", &po->seg.HEAP_LFH_SUBSEGMENT.BlockBitmap); - PDB_GetTypeSizeShort(hPDB, "_SEGMENT_HEAP", &po->seg.SEGMENT_HEAP.cb); - PDB_GetTypeSizeShort(hPDB, "_HEAP_SEG_CONTEXT", &po->seg.HEAP_SEG_CONTEXT.cb); - PDB_GetTypeSizeShort(hPDB, "_HEAP_PAGE_SEGMENT", &po->seg.HEAP_PAGE_SEGMENT.cb); - PDB_GetTypeSizeShort(hPDB, "_HEAP_PAGE_RANGE_DESCRIPTOR", &po->seg.HEAP_PAGE_RANGE_DESCRIPTOR.cb); - PDB_GetTypeSizeShort(hPDB, "_HEAP_VS_CHUNK_HEADER", &po->seg.HEAP_VS_CHUNK_HEADER.cb); + PDB_GetTypeChildOffsetShort(H, hPDB, "_SEGMENT_HEAP", "LargeAllocMetadata", &po->seg.SEGMENT_HEAP.LargeAllocMetadata); + PDB_GetTypeChildOffsetShort(H, hPDB, "_SEGMENT_HEAP", "LargeReservedPages", &po->seg.SEGMENT_HEAP.LargeReservedPages); + PDB_GetTypeChildOffsetShort(H, hPDB, "_SEGMENT_HEAP", "SegContexts", &po->seg.SEGMENT_HEAP.SegContexts); + PDB_GetTypeChildOffsetShort(H, hPDB, "_HEAP_SEG_CONTEXT", "SegmentListHead", &po->seg.HEAP_SEG_CONTEXT.SegmentListHead); + PDB_GetTypeChildOffsetShort(H, hPDB, "_HEAP_SEG_CONTEXT", "UnitShift", &po->seg.HEAP_SEG_CONTEXT.UnitShift); + PDB_GetTypeChildOffsetShort(H, hPDB, "_HEAP_SEG_CONTEXT", "FirstDescriptorIndex", &po->seg.HEAP_SEG_CONTEXT.FirstDescriptorIndex); + PDB_GetTypeChildOffsetShort(H, hPDB, "_HEAP_PAGE_RANGE_DESCRIPTOR", "TreeSignature", &po->seg.HEAP_PAGE_RANGE_DESCRIPTOR.TreeSignature); + PDB_GetTypeChildOffsetShort(H, hPDB, "_HEAP_PAGE_RANGE_DESCRIPTOR", "RangeFlags", &po->seg.HEAP_PAGE_RANGE_DESCRIPTOR.RangeFlags); + PDB_GetTypeChildOffsetShort(H, hPDB, "_HEAP_PAGE_RANGE_DESCRIPTOR", "UnitSize", &po->seg.HEAP_PAGE_RANGE_DESCRIPTOR.UnitSize); + PDB_GetTypeChildOffsetShort(H, hPDB, "_HEAP_LFH_SUBSEGMENT", "BlockOffsets", &po->seg.HEAP_LFH_SUBSEGMENT.BlockOffsets); + PDB_GetTypeChildOffsetShort(H, hPDB, "_HEAP_LFH_SUBSEGMENT", "BlockBitmap", &po->seg.HEAP_LFH_SUBSEGMENT.BlockBitmap); + PDB_GetTypeSizeShort(H, hPDB, "_SEGMENT_HEAP", &po->seg.SEGMENT_HEAP.cb); + PDB_GetTypeSizeShort(H, hPDB, "_HEAP_SEG_CONTEXT", &po->seg.HEAP_SEG_CONTEXT.cb); + PDB_GetTypeSizeShort(H, hPDB, "_HEAP_PAGE_SEGMENT", &po->seg.HEAP_PAGE_SEGMENT.cb); + PDB_GetTypeSizeShort(H, hPDB, "_HEAP_PAGE_RANGE_DESCRIPTOR", &po->seg.HEAP_PAGE_RANGE_DESCRIPTOR.cb); + PDB_GetTypeSizeShort(H, hPDB, "_HEAP_VS_CHUNK_HEADER", &po->seg.HEAP_VS_CHUNK_HEADER.cb); po->fValid = po->nt.HEAP.VirtualAllocdBlocks || po->nt.HEAP.FrontEndHeap || po->seg.SEGMENT_HEAP.cb; - VmmWinInit_InitializeOffsetStatic_Heap_Print(f32, po); + VmmWinInit_InitializeOffsetStatic_Heap_Print(H, f32, po); } } /* * Helper/Worker function for VmmWinInit_FindNtosScan64_SmallPageWalk(). +* -- H * -- paTable = set to: physical address of PML4 * -- va = set to 0 * -- vaMin = 0xFFFFF80000000000 (if windows kernel) @@ -290,16 +294,16 @@ VOID VmmWinInit_InitializeOffsetStatic_Heap() * -- iPML = set to 4 * -- psvaKernelCandidates */ -VOID VmmWinInit_FindNtosScan64_SmallPageWalk_DoWork(_In_ QWORD paTable, _In_ QWORD vaBase, _In_ QWORD vaMin, _In_ QWORD vaMax, _In_ BYTE iPML, _In_ POB_SET psvaKernelCandidates) +VOID VmmWinInit_FindNtosScan64_SmallPageWalk_DoWork(_In_ VMM_HANDLE H, _In_ QWORD paTable, _In_ QWORD vaBase, _In_ QWORD vaMin, _In_ QWORD vaMax, _In_ BYTE iPML, _In_ POB_SET psvaKernelCandidates) { static const QWORD PML_REGION_SIZE[5] = { 0, 12, 21, 30, 39 }; QWORD i, j, pte, vaCurrent; PVMMOB_CACHE_MEM pObPTEs = NULL; BOOL f; - pObPTEs = VmmTlbGetPageTable(paTable, FALSE); + pObPTEs = VmmTlbGetPageTable(H, paTable, FALSE); if(!pObPTEs) { return; } if(iPML == 4) { - if(!VmmTlbPageTableVerify(pObPTEs->pb, paTable, TRUE)) { goto finish; } + if(!VmmTlbPageTableVerify(H, pObPTEs->pb, paTable, TRUE)) { goto finish; } vaBase = 0; } for(i = 0; i < 512; i++) { @@ -322,7 +326,7 @@ VOID VmmWinInit_FindNtosScan64_SmallPageWalk_DoWork(_In_ QWORD paTable, _In_ QWO } } if(pte & 0x80) { continue; } // PS (large page) -> NOT VALID - VmmWinInit_FindNtosScan64_SmallPageWalk_DoWork(pte & 0x0000fffffffff000, vaCurrent, vaMin, vaMax, iPML - 1, psvaKernelCandidates); + VmmWinInit_FindNtosScan64_SmallPageWalk_DoWork(H, pte & 0x0000fffffffff000, vaCurrent, vaMin, vaMax, iPML - 1, psvaKernelCandidates); } finish: Ob_DECREF(pObPTEs); @@ -336,22 +340,23 @@ finish: * - page #0 be read/write * - page #1-#32 be read/execute * - page starts with MZ and contains POOLCODE +* -- H * -- pSystemProcess * -- vaMin = 0xFFFFF80000000000 * -- vaMax = 0xFFFFF803FFFFFFFF * -- pvaBase * -- pcbSize */ -VOID VmmWinInit_FindNtosScan64_SmallPageWalk(_In_ PVMM_PROCESS pSystemProcess, _In_ QWORD vaMin, _In_ QWORD vaMax, _Inout_ PQWORD pvaBase, _Inout_ PQWORD pcbSize) +VOID VmmWinInit_FindNtosScan64_SmallPageWalk(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ QWORD vaMin, _In_ QWORD vaMax, _Inout_ PQWORD pvaBase, _Inout_ PQWORD pcbSize) { QWORD o, va; BYTE pb[4096]; POB_SET psObKernelVa = NULL; - if(!(psObKernelVa = ObSet_New())) { return; } - VmmWinInit_FindNtosScan64_SmallPageWalk_DoWork(pSystemProcess->paDTB, 0, vaMin, vaMax, 4, psObKernelVa); - VmmCachePrefetchPages(pSystemProcess, psObKernelVa, 0); + if(!(psObKernelVa = ObSet_New(H))) { return; } + VmmWinInit_FindNtosScan64_SmallPageWalk_DoWork(H, pSystemProcess->paDTB, 0, vaMin, vaMax, 4, psObKernelVa); + VmmCachePrefetchPages(H, pSystemProcess, psObKernelVa, 0); while((va = ObSet_Pop(psObKernelVa))) { - if(VmmReadPage(pSystemProcess, va, pb)) { + if(VmmReadPage(H, pSystemProcess, va, pb)) { if(pb[0] != 'M' || pb[1] != 'Z') { continue; } for(o = 0; o < 0x1000; o += 8) { if(*(PQWORD)(pb + o) == 0x45444F434C4F4F50) { // POOLCODE @@ -370,6 +375,7 @@ VOID VmmWinInit_FindNtosScan64_SmallPageWalk(_In_ PVMM_PROCESS pSystemProcess, _ * Scan a page table hierarchy between virtual addresses between vaMin and vaMax * for the first occurence of large 2MB pages. This is usually 'ntoskrnl.exe' if * the OS is Windows. 'ntoskrnl.exe'. +* -- H * -- paTable = set to: physical address of PML4 * -- va = set to 0 * -- vaMin = 0xFFFFF80000000000 (if windows kernel) @@ -378,17 +384,17 @@ VOID VmmWinInit_FindNtosScan64_SmallPageWalk(_In_ PVMM_PROCESS pSystemProcess, _ * -- pvaBase * -- pcbSize */ -VOID VmmWinInit_FindNtosScan64_LargePageWalk(_In_ QWORD paTable, _In_ QWORD vaBase, _In_ QWORD vaMin, _In_ QWORD vaMax, _In_ BYTE iPML, _Inout_ PQWORD pvaBase, _Inout_ PQWORD pcbSize) +VOID VmmWinInit_FindNtosScan64_LargePageWalk(_In_ VMM_HANDLE H, _In_ QWORD paTable, _In_ QWORD vaBase, _In_ QWORD vaMin, _In_ QWORD vaMax, _In_ BYTE iPML, _Inout_ PQWORD pvaBase, _Inout_ PQWORD pcbSize) { const QWORD PML_REGION_SIZE[5] = { 0, 12, 21, 30, 39 }; QWORD i, pte, vaCurrent; PVMMOB_CACHE_MEM pObPTEs = NULL; - pObPTEs = VmmTlbGetPageTable(paTable, FALSE); + pObPTEs = VmmTlbGetPageTable(H, paTable, FALSE); if(!pObPTEs) { return; } if(iPML == 4) { *pvaBase = 0; *pcbSize = 0; - if(!VmmTlbPageTableVerify(pObPTEs->pb, paTable, TRUE)) { goto finish; } + if(!VmmTlbPageTableVerify(H, pObPTEs->pb, paTable, TRUE)) { goto finish; } vaBase = 0; } for(i = 0; i < 512; i++) { @@ -408,7 +414,7 @@ VOID VmmWinInit_FindNtosScan64_LargePageWalk(_In_ QWORD paTable, _In_ QWORD vaBa continue; } else { if(pte & 0x80) { continue; } // PS = 1 - VmmWinInit_FindNtosScan64_LargePageWalk(pte & 0x0000fffffffff000, vaCurrent, vaMin, vaMax, iPML - 1, pvaBase, pcbSize); + VmmWinInit_FindNtosScan64_LargePageWalk(H, pte & 0x0000fffffffff000, vaCurrent, vaMin, vaMax, iPML - 1, pvaBase, pcbSize); } } finish: @@ -420,10 +426,11 @@ finish: * be unknown. This functions walks the page table in the area in which ntoskrnl * is loaded looking for 2MB large pages. If an area in 2MB pages are found it * is scanned for the ntoskrnl.exe base. +* -- H * -- pSystemProcess * -- return = virtual address of ntoskrnl.exe base if successful, otherwise 0. */ -QWORD VmmWinInit_FindNtosScan64(PVMM_PROCESS pSystemProcess) +QWORD VmmWinInit_FindNtosScan64(_In_ VMM_HANDLE H, PVMM_PROCESS pSystemProcess) { PBYTE pb; QWORD p, o, vaCurrentMin, vaBase, cbSize; @@ -432,9 +439,9 @@ QWORD VmmWinInit_FindNtosScan64(PVMM_PROCESS pSystemProcess) while(TRUE) { vaBase = 0; cbSize = 0; - VmmWinInit_FindNtosScan64_LargePageWalk(pSystemProcess->paDTB, 0, vaCurrentMin, 0xFFFFF807FFFFFFFF, 4, &vaBase, &cbSize); + VmmWinInit_FindNtosScan64_LargePageWalk(H, pSystemProcess->paDTB, 0, vaCurrentMin, 0xFFFFF807FFFFFFFF, 4, &vaBase, &cbSize); if(!vaBase) { - VmmWinInit_FindNtosScan64_SmallPageWalk(pSystemProcess, vaCurrentMin, 0xFFFFF807FFFFFFFF, &vaBase, &cbSize); + VmmWinInit_FindNtosScan64_SmallPageWalk(H, pSystemProcess, vaCurrentMin, 0xFFFFF807FFFFFFFF, &vaBase, &cbSize); } if(!vaBase) { return 0; } vaCurrentMin = vaBase + cbSize; @@ -442,13 +449,13 @@ QWORD VmmWinInit_FindNtosScan64(PVMM_PROCESS pSystemProcess) if(cbSize <= 0x00400000) { continue; } // too small // try locate ntoskrnl.exe base inside suggested area if(!(pb = (PBYTE)LocalAlloc(0, (DWORD)cbSize))) { return 0; } - VmmReadEx(pSystemProcess, vaBase, pb, (DWORD)cbSize, NULL, 0); + VmmReadEx(H, pSystemProcess, vaBase, pb, (DWORD)cbSize, NULL, 0); for(p = 0; p < cbSize; p += 0x1000) { // check for (1) MZ header, (2) POOLCODE section, (3) ntoskrnl.exe module name if(*(PWORD)(pb + p) != 0x5a4d) { continue; } // MZ header for(o = 0; o < 0x1000; o += 8) { if(*(PQWORD)(pb + p + o) == 0x45444F434C4F4F50) { // POOLCODE - PE_GetModuleNameEx(pSystemProcess, vaBase + p, FALSE, pb + p, szModuleName, _countof(szModuleName), NULL); + PE_GetModuleNameEx(H, pSystemProcess, vaBase + p, FALSE, pb + p, szModuleName, _countof(szModuleName), NULL); if(!_stricmp(szModuleName, "ntoskrnl.exe")) { LocalFree(pb); return vaBase + p; @@ -465,10 +472,11 @@ QWORD VmmWinInit_FindNtosScan64(PVMM_PROCESS pSystemProcess) * Locate the virtual base address of 'ntoskrnl.exe' given any address inside * the kernel. Localization will be done by a scan-back method. A maximum of * 32MB will be scanned back. +* -- H * -- pSystemProcess * -- return = virtual address of ntoskrnl.exe base if successful, otherwise 0 */ -QWORD VmmWinInit_FindNtosScanHint64(_In_ PVMM_PROCESS pSystemProcess, _In_ QWORD vaHint) +QWORD VmmWinInit_FindNtosScanHint64(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ QWORD vaHint) { PBYTE pb; QWORD vaBase, o, p, vaNtosTry = 0; @@ -480,7 +488,7 @@ QWORD VmmWinInit_FindNtosScanHint64(_In_ PVMM_PROCESS pSystemProcess, _In_ QWORD if(!pb) { goto cleanup; } // Scan back in 2MB chunks a time, (ntoskrnl.exe is loaded in 2MB pages except in low memory situations). for(vaBase = vaHint & ~0x1fffff; vaBase + 0x02000000 > vaHint; vaBase -= 0x200000) { - VmmReadEx(pSystemProcess, vaBase, pb, 0x200000, &cbRead, 0); + VmmReadEx(H, pSystemProcess, vaBase, pb, 0x200000, &cbRead, 0); // Only fail here if all virtual memory in read fails. reason is that kernel is // properly mapped in memory (with NX MZ header in separate page) with empty // space before next valid kernel pages when running Virtualization Based Security. @@ -495,7 +503,7 @@ QWORD VmmWinInit_FindNtosScanHint64(_In_ PVMM_PROCESS pSystemProcess, _In_ QWORD if(pNtHeader->Signature != IMAGE_NT_SIGNATURE) { continue; } // NT header signature for(o = 0; o < 0x1000; o += 8) { if(*(PQWORD)(pb + p + o) == 0x45444F434C4F4F50) { // POOLCODE - if(!PE_GetModuleNameEx(pSystemProcess, vaBase + p, FALSE, pb + p, szModuleName, _countof(szModuleName), NULL)) { + if(!PE_GetModuleNameEx(H, pSystemProcess, vaBase + p, FALSE, pb + p, szModuleName, _countof(szModuleName), NULL)) { vaNtosTry = vaBase + p; continue; } @@ -518,10 +526,11 @@ cleanup: * of 'ntoskrnl.exe'. NB! this is a very non-optimized way of doing things and * should be improved upon to increase startup performance - but 72MB is not a * huge amount of memory and it's only scanned at startup ... +* -- H * -- pSystemProcess * -- return = virtual address of ntoskrnl.exe base if successful, otherwise 0. */ -DWORD VmmWinInit_FindNtosScan32(_In_ PVMM_PROCESS pSystemProcess) +DWORD VmmWinInit_FindNtosScan32(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess) { DWORD vaBase, ova; DWORD o, vaNtosTry = 0; @@ -533,7 +542,7 @@ DWORD VmmWinInit_FindNtosScan32(_In_ PVMM_PROCESS pSystemProcess) for(vaBase = 0x80000000; vaBase < 0x88000000; vaBase += 0x1000) { ova = vaBase % 0x00800000; if(ova == 0) { - VmmReadEx(pSystemProcess, vaBase, pb, 0x00800000, NULL, 0); + VmmReadEx(H, pSystemProcess, vaBase, pb, 0x00800000, NULL, 0); } // check for (1) MZ+NT header, (2) POOLCODE section, (3) ntoskrnl.exe module name (if possible to read) pDosHeader = (PIMAGE_DOS_HEADER)(pb + ova); // DOS header @@ -543,7 +552,7 @@ DWORD VmmWinInit_FindNtosScan32(_In_ PVMM_PROCESS pSystemProcess) if(pNtHeader->Signature != IMAGE_NT_SIGNATURE) { continue; } // NT header signature for(o = 0; o < 0x800; o += 8) { if(*(PQWORD)(pb + ova + o) == 0x45444F434C4F4F50) { // POOLCODE - if(!PE_GetModuleNameEx(pSystemProcess, (QWORD)vaBase + ova, FALSE, pb + ova, szModuleName, _countof(szModuleName), NULL)) { + if(!PE_GetModuleNameEx(H, pSystemProcess, (QWORD)vaBase + ova, FALSE, pb + ova, szModuleName, _countof(szModuleName), NULL)) { vaNtosTry = vaBase; continue; } @@ -561,42 +570,43 @@ DWORD VmmWinInit_FindNtosScan32(_In_ PVMM_PROCESS pSystemProcess) /* * Scan for the 'ntoskrnl.exe' by using the DTB and memory model information -* from the ctxVmm. Return the system process (if found). +* from the vmm handle. Return the system process (if found). * CALLER DECREF: return +* -- H * -- return = system process - NB! CALLER must DECREF! */ -PVMM_PROCESS VmmWinInit_FindNtosScan() +PVMM_PROCESS VmmWinInit_FindNtosScan(_In_ VMM_HANDLE H) { QWORD vaKernelBase = 0, cbKernelSize, vaKernelHint; PVMM_PROCESS pObSystemProcess = NULL; // 1: Pre-initialize System PID (required by VMM) - pObSystemProcess = VmmProcessCreateEntry(TRUE, 4, 0, 0, ctxVmm->kernel.paDTB, 0, "System ", FALSE, NULL, 0); + pObSystemProcess = VmmProcessCreateEntry(H, TRUE, 4, 0, 0, H->vmm.kernel.paDTB, 0, "System ", FALSE, NULL, 0); if(!pObSystemProcess) { return NULL; } - VmmProcessCreateFinish(); + VmmProcessCreateFinish(H); // 2: Spider DTB to speed things up. - VmmTlbSpider(pObSystemProcess); + VmmTlbSpider(H, pObSystemProcess); // 3: Find the base of 'ntoskrnl.exe' - if(VMM_MEMORYMODEL_X64 == ctxVmm->tpMemoryModel) { - LcGetOption(ctxMain->hLC, LC_OPT_MEMORYINFO_OS_KERNELBASE, &vaKernelBase); + if(VMM_MEMORYMODEL_X64 == H->vmm.tpMemoryModel) { + LcGetOption(H->hLC, LC_OPT_MEMORYINFO_OS_KERNELBASE, &vaKernelBase); if(!vaKernelBase) { - vaKernelHint = ctxVmm->kernel.vaEntry; - if(!vaKernelHint) { LcGetOption(ctxMain->hLC, LC_OPT_MEMORYINFO_OS_KERNELHINT, &vaKernelHint); } - if(!vaKernelHint) { LcGetOption(ctxMain->hLC, LC_OPT_MEMORYINFO_OS_PsActiveProcessHead, &vaKernelHint); } - if(!vaKernelHint) { LcGetOption(ctxMain->hLC, LC_OPT_MEMORYINFO_OS_PsLoadedModuleList, &vaKernelHint); } + vaKernelHint = H->vmm.kernel.vaEntry; + if(!vaKernelHint) { LcGetOption(H->hLC, LC_OPT_MEMORYINFO_OS_KERNELHINT, &vaKernelHint); } + if(!vaKernelHint) { LcGetOption(H->hLC, LC_OPT_MEMORYINFO_OS_PsActiveProcessHead, &vaKernelHint); } + if(!vaKernelHint) { LcGetOption(H->hLC, LC_OPT_MEMORYINFO_OS_PsLoadedModuleList, &vaKernelHint); } if(vaKernelHint) { - vaKernelBase = VmmWinInit_FindNtosScanHint64(pObSystemProcess, vaKernelHint); + vaKernelBase = VmmWinInit_FindNtosScanHint64(H, pObSystemProcess, vaKernelHint); } } if(!vaKernelBase) { - vaKernelBase = VmmWinInit_FindNtosScan64(pObSystemProcess); + vaKernelBase = VmmWinInit_FindNtosScan64(H, pObSystemProcess); } } else { - vaKernelBase = VmmWinInit_FindNtosScan32(pObSystemProcess); + vaKernelBase = VmmWinInit_FindNtosScan32(H, pObSystemProcess); } if(!vaKernelBase) { goto fail; } - cbKernelSize = PE_GetSize(pObSystemProcess, vaKernelBase); - ctxVmm->kernel.vaBase = vaKernelBase; - ctxVmm->kernel.cbSize = cbKernelSize; + cbKernelSize = PE_GetSize(H, pObSystemProcess, vaKernelBase); + H->vmm.kernel.vaBase = vaKernelBase; + H->vmm.kernel.cbSize = cbKernelSize; return pObSystemProcess; fail: Ob_DECREF(pObSystemProcess); @@ -646,14 +656,14 @@ BOOL VmmWinInit_DTB_FindValidate_X86PAE(_In_ QWORD pa, _In_reads_(0x1000) PBYTE } _Success_(return) -BOOL VmmWinInit_DTB_FindValidate_X64(_In_ QWORD pa, _In_reads_(0x1000) PBYTE pbPage) +BOOL VmmWinInit_DTB_FindValidate_X64(_In_ VMM_HANDLE H, _In_ QWORD pa, _In_reads_(0x1000) PBYTE pbPage) { DWORD cKernelValid = 0, i; DWORD cUserZero = 0, cKernelZero = 0; QWORD *ptes, paMax; BOOL fSelfRef = FALSE; ptes = (PQWORD)pbPage; - paMax = ctxMain->dev.paMax; + paMax = H->dev.paMax; // check for user-mode page table with PDPT below max physical address and not NX. if((ptes[0] & 1) && ((ptes[0] & 0x0000fffffffff000) > paMax)) { return FALSE; } for(i = 0; i < 256; i++) { // user-mode @@ -675,10 +685,10 @@ BOOL VmmWinInit_DTB_FindValidate_X64(_In_ QWORD pa, _In_reads_(0x1000) PBYTE pbP * Find and validate the low stub (loaded <1MB if exists). The low stub almost * always exists on real hardware. It may be missing on virtual machines though. * Upon success both the PML4 and 'ntoskrnl.exe' KernelEntry point are located. -* The PML4 is stored as the ctxVmm->kernel.paDTB and the KernelEntry is stored -* as ctxVmm->kernel.vaHintOpt +* The PML4 is stored as the H->vmm.kernel.paDTB and the KernelEntry is stored +* as H->vmm.kernel.vaHintOpt */ -BOOL VmmWinInit_DTB_FindValidate_X64_LowStub(_In_ PBYTE pbLowStub1M) +BOOL VmmWinInit_DTB_FindValidate_X64_LowStub(_In_ VMM_HANDLE H, _In_ PBYTE pbLowStub1M) { DWORD o = 0; while(o < 0x100000) { @@ -686,8 +696,8 @@ BOOL VmmWinInit_DTB_FindValidate_X64_LowStub(_In_ PBYTE pbLowStub1M) if(0x00000001000600E9 != (0xffffffffffff00ff & *(PQWORD)(pbLowStub1M + o + 0x000))) { continue; } // START BYTES if(0xfffff80000000000 != (0xfffff80000000003 & *(PQWORD)(pbLowStub1M + o + 0x070))) { continue; } // KERNEL ENTRY if(0xffffff0000000fff & *(PQWORD)(pbLowStub1M + o + 0x0a0)) { continue; } // PML4 - ctxVmm->kernel.vaEntry = *(PQWORD)(pbLowStub1M + o + 0x070); - ctxVmm->kernel.paDTB = *(PQWORD)(pbLowStub1M + o + 0x0a0); + H->vmm.kernel.vaEntry = *(PQWORD)(pbLowStub1M + o + 0x070); + H->vmm.kernel.paDTB = *(PQWORD)(pbLowStub1M + o + 0x0a0); return TRUE; } return FALSE; @@ -696,11 +706,12 @@ BOOL VmmWinInit_DTB_FindValidate_X64_LowStub(_In_ PBYTE pbLowStub1M) /* * Tries to locate the Directory Table Base and the Memory Model by using various * detection and scanning functions. Upon success memory model and kernel DTB is -* returned in the ctxVmm context. --- return +* returned in the vmm handle. +* -- H +* -- return */ _Success_(return) -BOOL VmmWinInit_DTB_FindValidate() +BOOL VmmWinInit_DTB_FindValidate(_In_ VMM_HANDLE H) { DWORD pa; QWORD paDTB = 0; @@ -708,20 +719,20 @@ BOOL VmmWinInit_DTB_FindValidate() if(!(pb16M = LocalAlloc(LMEM_ZEROINIT, 0x01000000))) { return FALSE; } // 1: try locate DTB via X64 low stub in lower 1MB - // avoiding normally reserved memory at a0000-fffff. - LcRead(ctxMain->hLC, 0x1000, 0x9f000, pb16M + 0x1000); - if(VmmWinInit_DTB_FindValidate_X64_LowStub(pb16M)) { - VmmInitializeMemoryModel(VMM_MEMORYMODEL_X64); - paDTB = ctxVmm->kernel.paDTB; + LcRead(H->hLC, 0x1000, 0x9f000, pb16M + 0x1000); + if(VmmWinInit_DTB_FindValidate_X64_LowStub(H, pb16M)) { + VmmInitializeMemoryModel(H, VMM_MEMORYMODEL_X64); + paDTB = H->vmm.kernel.paDTB; } // 2: try locate DTB by scanning in lower 16MB // X64 if(!paDTB) { for(pa = 0; pa < 0x01000000; pa += 0x1000) { if(pa == 0x00100000) { - LcRead(ctxMain->hLC, 0x00100000, 0x00f00000, pb16M + 0x00100000); + LcRead(H->hLC, 0x00100000, 0x00f00000, pb16M + 0x00100000); } - if(VmmWinInit_DTB_FindValidate_X64(pa, pb16M + pa)) { - VmmInitializeMemoryModel(VMM_MEMORYMODEL_X64); + if(VmmWinInit_DTB_FindValidate_X64(H, pa, pb16M + pa)) { + VmmInitializeMemoryModel(H, VMM_MEMORYMODEL_X64); paDTB = pa; break; } @@ -731,7 +742,7 @@ BOOL VmmWinInit_DTB_FindValidate() if(!paDTB) { for(pa = 0; pa < 0x01000000; pa += 0x1000) { if(VmmWinInit_DTB_FindValidate_X86PAE(pa, pb16M + pa)) { - VmmInitializeMemoryModel(VMM_MEMORYMODEL_X86PAE); + VmmInitializeMemoryModel(H, VMM_MEMORYMODEL_X86PAE); paDTB = pa; break; } @@ -741,7 +752,7 @@ BOOL VmmWinInit_DTB_FindValidate() if(!paDTB) { for(pa = 0; pa < 0x01000000; pa += 0x1000) { if(VmmWinInit_DTB_FindValidate_X86(pa, pb16M + pa)) { - VmmInitializeMemoryModel(VMM_MEMORYMODEL_X86); + VmmInitializeMemoryModel(H, VMM_MEMORYMODEL_X86); paDTB = pa; break; } @@ -749,40 +760,41 @@ BOOL VmmWinInit_DTB_FindValidate() } LocalFree(pb16M); if(!paDTB) { return FALSE; } - ctxVmm->kernel.paDTB = paDTB; + H->vmm.kernel.paDTB = paDTB; return TRUE; } /* * Validate a DTB supplied by the user. The memory model will be detected and -* the result will be stored in the ctxVmm context upon success. +* the result will be stored in the vmm handle upon success. +* -- H * -- paDTB * -- return */ -BOOL VmmWinInit_DTB_Validate(QWORD paDTB) +BOOL VmmWinInit_DTB_Validate(_In_ VMM_HANDLE H, _In_ QWORD paDTB) { BYTE pb[0x1000]; paDTB = paDTB & ~0xfff; - if(!LcRead(ctxMain->hLC, paDTB, 0x1000, pb)) { return FALSE; } - if(VmmWinInit_DTB_FindValidate_X64(paDTB, pb)) { - VmmInitializeMemoryModel(VMM_MEMORYMODEL_X64); - ctxVmm->kernel.paDTB = paDTB; + if(!LcRead(H->hLC, paDTB, 0x1000, pb)) { return FALSE; } + if(VmmWinInit_DTB_FindValidate_X64(H, paDTB, pb)) { + VmmInitializeMemoryModel(H, VMM_MEMORYMODEL_X64); + H->vmm.kernel.paDTB = paDTB; return TRUE; } if(VmmWinInit_DTB_FindValidate_X86PAE(paDTB, pb)) { - VmmInitializeMemoryModel(VMM_MEMORYMODEL_X86PAE); - ctxVmm->kernel.paDTB = paDTB; + VmmInitializeMemoryModel(H, VMM_MEMORYMODEL_X86PAE); + H->vmm.kernel.paDTB = paDTB; return TRUE; } if(VmmWinInit_DTB_FindValidate_X86(paDTB, pb)) { - VmmInitializeMemoryModel(VMM_MEMORYMODEL_X86); - ctxVmm->kernel.paDTB = paDTB; + VmmInitializeMemoryModel(H, VMM_MEMORYMODEL_X86); + H->vmm.kernel.paDTB = paDTB; return TRUE; } return FALSE; } -BOOL VmmWinInit_FindPsLoadedModuleListKDBG(_In_ PVMM_PROCESS pSystemProcess) +BOOL VmmWinInit_FindPsLoadedModuleListKDBG(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess) { PBYTE pbData = NULL, pbKDBG; IMAGE_SECTION_HEADER SectionHeader; @@ -790,53 +802,53 @@ BOOL VmmWinInit_FindPsLoadedModuleListKDBG(_In_ PVMM_PROCESS pSystemProcess) QWORD va, va64 = 0; // 1: Try locate 'PsLoadedModuleList' by querying the microsoft crash dump // file used. This will fail if another memory acqusition device is used. - if(LcGetOption(ctxMain->hLC, LC_OPT_MEMORYINFO_OS_PsLoadedModuleList, &va) && va) { - LcGetOption(ctxMain->hLC, LC_OPT_MEMORYINFO_OS_PFN, &ctxVmm->kernel.opt.vaPfnDatabase); - LcGetOption(ctxMain->hLC, LC_OPT_MEMORYINFO_OS_KdDebuggerDataBlock, &ctxVmm->kernel.opt.KDBG.va); - if(ctxVmm->f32 && VmmRead(pSystemProcess, va, (PBYTE)&va32, 4) && (va32 > 0x80000000)) { - ctxVmm->kernel.opt.vaPsLoadedModuleListExp = va; - ctxVmm->kernel.vaPsLoadedModuleListPtr = va32; + if(LcGetOption(H->hLC, LC_OPT_MEMORYINFO_OS_PsLoadedModuleList, &va) && va) { + LcGetOption(H->hLC, LC_OPT_MEMORYINFO_OS_PFN, &H->vmm.kernel.opt.vaPfnDatabase); + LcGetOption(H->hLC, LC_OPT_MEMORYINFO_OS_KdDebuggerDataBlock, &H->vmm.kernel.opt.KDBG.va); + if(H->vmm.f32 && VmmRead(H, pSystemProcess, va, (PBYTE)&va32, 4) && (va32 > 0x80000000)) { + H->vmm.kernel.opt.vaPsLoadedModuleListExp = va; + H->vmm.kernel.vaPsLoadedModuleListPtr = va32; return TRUE; } - if(!ctxVmm->f32 && VmmRead(pSystemProcess, va, (PBYTE)&va64, 8) && (va64 > 0xffff800000000000)) { - ctxVmm->kernel.opt.vaPsLoadedModuleListExp = va; - ctxVmm->kernel.vaPsLoadedModuleListPtr = va64; + if(!H->vmm.f32 && VmmRead(H, pSystemProcess, va, (PBYTE)&va64, 8) && (va64 > 0xffff800000000000)) { + H->vmm.kernel.opt.vaPsLoadedModuleListExp = va; + H->vmm.kernel.vaPsLoadedModuleListPtr = va64; return TRUE; } } // (optionally) Locate the PFN database: // The PFN database is static on before Windows 10 x64 1607/14393. - if(!ctxVmm->f32 && (ctxVmm->kernel.dwVersionBuild < 14393)) { - ctxVmm->kernel.opt.vaPfnDatabase = 0xfffffa8000000000; + if(!H->vmm.f32 && (H->vmm.kernel.dwVersionBuild < 14393)) { + H->vmm.kernel.opt.vaPfnDatabase = 0xfffffa8000000000; } // 2: Try locate 'PsLoadedModuleList' by exported kernel symbol. If this is // possible _and_ the system is 64-bit it's most probably Windows 10 and // KDBG will be encrypted so no need to continue looking for it. - ctxVmm->kernel.vaPsLoadedModuleListPtr = PE_GetProcAddress(pSystemProcess, ctxVmm->kernel.vaBase, "PsLoadedModuleList"); - if(ctxVmm->kernel.vaPsLoadedModuleListPtr && !ctxVmm->f32) { - ctxVmm->kernel.opt.vaPsLoadedModuleListExp = ctxVmm->kernel.vaPsLoadedModuleListPtr; + H->vmm.kernel.vaPsLoadedModuleListPtr = PE_GetProcAddress(H, pSystemProcess, H->vmm.kernel.vaBase, "PsLoadedModuleList"); + if(H->vmm.kernel.vaPsLoadedModuleListPtr && !H->vmm.f32) { + H->vmm.kernel.opt.vaPsLoadedModuleListExp = H->vmm.kernel.vaPsLoadedModuleListPtr; return TRUE; } // 3: Try locate 'KDBG' by looking in 'ntoskrnl.exe' '.text' section. This // is the normal way of finding it on 64-bit Windows below Windows 10. // This also works on 32-bit Windows versions - so use this method for // simplicity rather than using a separate 32-bit method. - if(!ctxVmm->kernel.opt.KDBG.va && (ctxVmm->f32 || ctxVmm->kernel.dwVersionMajor < 10)) { - if(!PE_SectionGetFromName(pSystemProcess, ctxVmm->kernel.vaBase, ".data", &SectionHeader)) { goto fail; } + if(!H->vmm.kernel.opt.KDBG.va && (H->vmm.f32 || H->vmm.kernel.dwVersionMajor < 10)) { + if(!PE_SectionGetFromName(H, pSystemProcess, H->vmm.kernel.vaBase, ".data", &SectionHeader)) { goto fail; } if((SectionHeader.Misc.VirtualSize > 0x00100000) || (SectionHeader.VirtualAddress > 0x01000000)) { goto fail; } if(!(pbData = LocalAlloc(LMEM_ZEROINIT, SectionHeader.Misc.VirtualSize))) { goto fail; } - VmmReadEx(pSystemProcess, ctxVmm->kernel.vaBase + SectionHeader.VirtualAddress, pbData, SectionHeader.Misc.VirtualSize, NULL, 0); + VmmReadEx(H, pSystemProcess, H->vmm.kernel.vaBase + SectionHeader.VirtualAddress, pbData, SectionHeader.Misc.VirtualSize, NULL, 0); for(o = 16; o <= SectionHeader.Misc.VirtualSize - 0x290; o += 4) { if(*(PDWORD)(pbData + o) == 0x4742444b) { // KDBG tag pbKDBG = pbData + o - 16; - if(ctxVmm->kernel.vaBase != *(PQWORD)(pbKDBG + 0x18)) { continue; } + if(H->vmm.kernel.vaBase != *(PQWORD)(pbKDBG + 0x18)) { continue; } // fetch PsLoadedModuleList va = *(PQWORD)(pbKDBG + 0x48); - if((va < ctxVmm->kernel.vaBase) || (va > ctxVmm->kernel.vaBase + ctxVmm->kernel.cbSize)) { goto fail; } - if(!VmmRead(pSystemProcess, va, (PBYTE)&ctxVmm->kernel.vaPsLoadedModuleListPtr, ctxVmm->f32 ? 4 : 8)) { goto fail; } - ctxVmm->kernel.opt.vaPsLoadedModuleListExp = va; + if((va < H->vmm.kernel.vaBase) || (va > H->vmm.kernel.vaBase + H->vmm.kernel.cbSize)) { goto fail; } + if(!VmmRead(H, pSystemProcess, va, (PBYTE)&H->vmm.kernel.vaPsLoadedModuleListPtr, H->vmm.f32 ? 4 : 8)) { goto fail; } + H->vmm.kernel.opt.vaPsLoadedModuleListExp = va; // finish! - ctxVmm->kernel.opt.KDBG.va = ctxVmm->kernel.vaBase + SectionHeader.VirtualAddress + o - 16; + H->vmm.kernel.opt.KDBG.va = H->vmm.kernel.vaBase + SectionHeader.VirtualAddress + o - 16; LocalFree(pbData); return TRUE; } @@ -844,64 +856,65 @@ BOOL VmmWinInit_FindPsLoadedModuleListKDBG(_In_ PVMM_PROCESS pSystemProcess) } // 4: Try locate by querying the PDB for symbols. At this point the PDB // subsystem may not be fully initialized yet so wait for it to init. - PDB_Initialize_WaitComplete(); - if(PDB_GetSymbolPTR(PDB_HANDLE_KERNEL, "PsLoadedModuleList", pSystemProcess, &ctxVmm->kernel.vaPsLoadedModuleListPtr)) { - PDB_GetSymbolAddress(PDB_HANDLE_KERNEL, "PsLoadedModuleList", &ctxVmm->kernel.opt.vaPsLoadedModuleListExp); + PDB_Initialize_WaitComplete(H); + if(PDB_GetSymbolPTR(H, PDB_HANDLE_KERNEL, "PsLoadedModuleList", pSystemProcess, &H->vmm.kernel.vaPsLoadedModuleListPtr)) { + PDB_GetSymbolAddress(H, PDB_HANDLE_KERNEL, "PsLoadedModuleList", &H->vmm.kernel.opt.vaPsLoadedModuleListExp); return TRUE; } fail: LocalFree(pbData); - return (0 != ctxVmm->kernel.vaPsLoadedModuleListPtr); + return (0 != H->vmm.kernel.vaPsLoadedModuleListPtr); } /* * Retrieve the operating system versioning information by looking at values in * the PEB of the process 'smss.exe'. +* -- H * -- pProcessSMSS * -- return */ -VOID VmmWinInit_VersionNumber(_In_ PVMM_PROCESS pProcessSMSS) +VOID VmmWinInit_VersionNumber(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcessSMSS) { BOOL fRead; BYTE pbPEB[0x130]; PVMM_PROCESS pObProcess = NULL; - fRead = VmmRead(pProcessSMSS, pProcessSMSS->win.vaPEB, pbPEB, 0x130); + fRead = VmmRead(H, pProcessSMSS, pProcessSMSS->win.vaPEB, pbPEB, 0x130); if(!fRead) { // failed (paging?) - try to read from crss.exe / lsass.exe / winlogon.exe - while((pObProcess = VmmProcessGetNext(pObProcess, 0))) { + while((pObProcess = VmmProcessGetNext(H, pObProcess, 0))) { if(!strcmp("crss.exe", pObProcess->szName) || !strcmp("lsass.exe", pObProcess->szName) || !strcmp("winlogon.exe", pObProcess->szName)) { - if((fRead = VmmRead(pObProcess, pObProcess->win.vaPEB, pbPEB, 0x130))) { break; } + if((fRead = VmmRead(H, pObProcess, pObProcess->win.vaPEB, pbPEB, 0x130))) { break; } } } Ob_DECREF_NULL(&pObProcess); } if(fRead) { - if(ctxVmm->f32) { - ctxVmm->kernel.dwVersionMajor = *(PDWORD)(pbPEB + 0x0a4); - ctxVmm->kernel.dwVersionMinor = *(PDWORD)(pbPEB + 0x0a8); - ctxVmm->kernel.dwVersionBuild = *(PWORD)(pbPEB + 0x0ac); + if(H->vmm.f32) { + H->vmm.kernel.dwVersionMajor = *(PDWORD)(pbPEB + 0x0a4); + H->vmm.kernel.dwVersionMinor = *(PDWORD)(pbPEB + 0x0a8); + H->vmm.kernel.dwVersionBuild = *(PWORD)(pbPEB + 0x0ac); } else { - ctxVmm->kernel.dwVersionMajor = *(PDWORD)(pbPEB + 0x118); - ctxVmm->kernel.dwVersionMinor = *(PDWORD)(pbPEB + 0x11c); - ctxVmm->kernel.dwVersionBuild = *(PWORD)(pbPEB + 0x120); + H->vmm.kernel.dwVersionMajor = *(PDWORD)(pbPEB + 0x118); + H->vmm.kernel.dwVersionMinor = *(PDWORD)(pbPEB + 0x11c); + H->vmm.kernel.dwVersionBuild = *(PWORD)(pbPEB + 0x120); } - } else if(PDB_GetSymbolDWORD(PDB_HANDLE_KERNEL, "NtBuildNumber", PVMM_PROCESS_SYSTEM, &ctxVmm->kernel.dwVersionBuild)) { - ctxVmm->kernel.dwVersionBuild = (WORD)ctxVmm->kernel.dwVersionBuild; - if(ctxVmm->kernel.dwVersionBuild) { - if(ctxVmm->kernel.dwVersionBuild >= 10240) { // 10 (incl. win11) - ctxVmm->kernel.dwVersionMajor = 10; - ctxVmm->kernel.dwVersionMinor = 0; - } else if(ctxVmm->kernel.dwVersionBuild >= 9100) { // 8 - ctxVmm->kernel.dwVersionMajor = 6; - ctxVmm->kernel.dwVersionMinor = 3; - } else if(ctxVmm->kernel.dwVersionBuild >= 7600) { // 7 - ctxVmm->kernel.dwVersionMajor = 6; - ctxVmm->kernel.dwVersionMinor = 1; - } else if(ctxVmm->kernel.dwVersionBuild >= 6000) { // VISTA - ctxVmm->kernel.dwVersionMajor = 6; - ctxVmm->kernel.dwVersionMinor = 0; + } else if(PDB_GetSymbolDWORD(H, PDB_HANDLE_KERNEL, "NtBuildNumber", PVMM_PROCESS_SYSTEM, &H->vmm.kernel.dwVersionBuild)) { + H->vmm.kernel.dwVersionBuild = (WORD)H->vmm.kernel.dwVersionBuild; + if(H->vmm.kernel.dwVersionBuild) { + if(H->vmm.kernel.dwVersionBuild >= 10240) { // 10 (incl. win11) + H->vmm.kernel.dwVersionMajor = 10; + H->vmm.kernel.dwVersionMinor = 0; + } else if(H->vmm.kernel.dwVersionBuild >= 9100) { // 8 + H->vmm.kernel.dwVersionMajor = 6; + H->vmm.kernel.dwVersionMinor = 3; + } else if(H->vmm.kernel.dwVersionBuild >= 7600) { // 7 + H->vmm.kernel.dwVersionMajor = 6; + H->vmm.kernel.dwVersionMinor = 1; + } else if(H->vmm.kernel.dwVersionBuild >= 6000) { // VISTA + H->vmm.kernel.dwVersionMajor = 6; + H->vmm.kernel.dwVersionMinor = 0; } else { // XP - ctxVmm->kernel.dwVersionMajor = 5; - ctxVmm->kernel.dwVersionMinor = 1; + H->vmm.kernel.dwVersionMajor = 5; + H->vmm.kernel.dwVersionMinor = 1; } } } @@ -910,178 +923,178 @@ VOID VmmWinInit_VersionNumber(_In_ PVMM_PROCESS pProcessSMSS) /* * Helper fucntion to VmmWinInit_TryInitialize. Tries to locate the EPROCESS of * the SYSTEM process and return it. +* -- H * -- pSystemProcess * -- return */ -QWORD VmmWinInit_FindSystemEPROCESS(_In_ PVMM_PROCESS pSystemProcess) +QWORD VmmWinInit_FindSystemEPROCESS(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess) { - BOOL f32 = ctxVmm->f32; + BOOL f32 = H->vmm.f32; IMAGE_SECTION_HEADER SectionHeader; BYTE pbALMOSTRO[0x80], pbSYSTEM[0x300]; QWORD i, vaPsInitialSystemProcess, vaSystemEPROCESS; // 1: try locate System EPROCESS by PsInitialSystemProcess exported symbol (works on all win versions) - vaPsInitialSystemProcess = PE_GetProcAddress(pSystemProcess, ctxVmm->kernel.vaBase, "PsInitialSystemProcess"); - if(VmmRead(pSystemProcess, vaPsInitialSystemProcess, (PBYTE)& vaSystemEPROCESS, 8)) { - if((VMM_MEMORYMODEL_X86 == ctxVmm->tpMemoryModel) || (VMM_MEMORYMODEL_X86PAE == ctxVmm->tpMemoryModel)) { + vaPsInitialSystemProcess = PE_GetProcAddress(H, pSystemProcess, H->vmm.kernel.vaBase, "PsInitialSystemProcess"); + if(VmmRead(H, pSystemProcess, vaPsInitialSystemProcess, (PBYTE)& vaSystemEPROCESS, 8)) { + if((VMM_MEMORYMODEL_X86 == H->vmm.tpMemoryModel) || (VMM_MEMORYMODEL_X86PAE == H->vmm.tpMemoryModel)) { vaSystemEPROCESS &= 0xffffffff; } pSystemProcess->win.EPROCESS.va = vaSystemEPROCESS; - VmmLog(MID_CORE, LOGLEVEL_DEBUG, "PsInitialSystemProcess located at %016llx", vaPsInitialSystemProcess); + VmmLog(H, MID_CORE, LOGLEVEL_DEBUG, "PsInitialSystemProcess located at %016llx", vaPsInitialSystemProcess); goto success; } // 2: fail - paging? try to retrive using PDB subsystem - this may take some time to initialize // and download symbols - but it's better than failing totally ... - InfoDB_Initialize(); - PDB_Initialize(NULL, FALSE); - PDB_GetSymbolPTR(PDB_HANDLE_KERNEL, "PsInitialSystemProcess", pSystemProcess, &vaSystemEPROCESS); + InfoDB_Initialize(H); + PDB_Initialize(H, NULL, FALSE); + PDB_GetSymbolPTR(H, PDB_HANDLE_KERNEL, "PsInitialSystemProcess", pSystemProcess, &vaSystemEPROCESS); if(vaSystemEPROCESS) { goto success; } // 3: fail - paging? (or not windows) - this should ideally not happen - but it happens rarely... // try scan beginning of ALMOSTRO section for pointers and validate (working on pre-win10 only) - if(!PE_SectionGetFromName(pSystemProcess, ctxVmm->kernel.vaBase, "ALMOSTRO", &SectionHeader)) { return 0; } - if(!VmmRead(pSystemProcess, ctxVmm->kernel.vaBase + SectionHeader.VirtualAddress, pbALMOSTRO, sizeof(pbALMOSTRO))) { return 0; } + if(!PE_SectionGetFromName(H, pSystemProcess, H->vmm.kernel.vaBase, "ALMOSTRO", &SectionHeader)) { return 0; } + if(!VmmRead(H, pSystemProcess, H->vmm.kernel.vaBase + SectionHeader.VirtualAddress, pbALMOSTRO, sizeof(pbALMOSTRO))) { return 0; } for(i = 0; i < sizeof(pbALMOSTRO); i += f32 ? 4 : 8) { vaSystemEPROCESS = f32 ? *(PDWORD)(pbALMOSTRO + i) : *(PQWORD)(pbALMOSTRO + i); if(f32 ? VMM_KADDR32_8(vaSystemEPROCESS) : VMM_KADDR64_16(vaSystemEPROCESS)) { - if(VmmRead(pSystemProcess, vaSystemEPROCESS, pbSYSTEM, sizeof(pbSYSTEM))) { - if(f32 && ((*(PDWORD)(pbSYSTEM + 0x18) & ~0xf) == ctxVmm->kernel.paDTB)) { goto success; } // 32-bit EPROCESS DTB at fixed offset - if(!f32 && ((*(PQWORD)(pbSYSTEM + 0x28) & ~0xf) == ctxVmm->kernel.paDTB)) { goto success; } // 64-bit EPROCESS DTB at fixed offset + if(VmmRead(H, pSystemProcess, vaSystemEPROCESS, pbSYSTEM, sizeof(pbSYSTEM))) { + if(f32 && ((*(PDWORD)(pbSYSTEM + 0x18) & ~0xf) == H->vmm.kernel.paDTB)) { goto success; } // 32-bit EPROCESS DTB at fixed offset + if(!f32 && ((*(PQWORD)(pbSYSTEM + 0x28) & ~0xf) == H->vmm.kernel.paDTB)) { goto success; } // 64-bit EPROCESS DTB at fixed offset } } } return 0; success: - VmmLog(MID_CORE, LOGLEVEL_DEBUG, "EPROCESS located at %016llx", vaSystemEPROCESS); + VmmLog(H, MID_CORE, LOGLEVEL_DEBUG, "EPROCESS located at %016llx", vaSystemEPROCESS); return vaSystemEPROCESS; } /* * Async initialization of remaining actions in VmmWinInit_TryInitialize. -* -- lpParameter +* -- H +* -- qwNotUsed * -- return */ -DWORD VmmWinInit_TryInitialize_Async(LPVOID lpParameter) +VOID VmmWinInit_TryInitialize_Async(_In_ VMM_HANDLE H, _In_ QWORD qwNotUsed) { POB_SET psObNoLinkEPROCESS = NULL; PVMM_PROCESS pObSystemProcess = NULL; - PDB_Initialize_WaitComplete(); - MmWin_PagingInitialize(TRUE); // initialize full paging (memcompression) - VmmWinInit_TryInitializeThreading(); - VmmWinInit_InitializeOffsetStatic_Heap(); - VmmWinInit_TryInitializeKernelOptionalValues(); + PDB_Initialize_WaitComplete(H); + MmWin_PagingInitialize(H, TRUE); // initialize full paging (memcompression) + VmmWinInit_TryInitializeThreading(H); + VmmWinInit_InitializeOffsetStatic_Heap(H); + VmmWinInit_TryInitializeKernelOptionalValues(H); // locate no-link processes [only in non-volatile memory due to performance]. - if(!ctxMain->dev.fVolatile && (psObNoLinkEPROCESS = VmmWinProcess_Enumerate_FindNoLinkProcesses())) { - if((pObSystemProcess = VmmProcessGet(4))) { - VmmWinProcess_Enumerate(pObSystemProcess, FALSE, psObNoLinkEPROCESS); + if(!H->dev.fVolatile && (psObNoLinkEPROCESS = VmmWinProcess_Enumerate_FindNoLinkProcesses(H))) { + if((pObSystemProcess = VmmProcessGet(H, 4))) { + VmmWinProcess_Enumerate(H, pObSystemProcess, FALSE, psObNoLinkEPROCESS); } Ob_DECREF(psObNoLinkEPROCESS); Ob_DECREF(pObSystemProcess); } - return 1; } /* * Initialize the "system unique tag" - i.e. an unique system-dependent id. +* -- H */ -VOID VmmWinInit_TryInitialize_SystemUniqueTag() +VOID VmmWinInit_TryInitialize_SystemUniqueTag(_In_ VMM_HANDLE H) { BYTE pbSHA256[32] = { 0 }; PVMM_PROCESS pObSystemProcess = NULL; - if((pObSystemProcess = VmmProcessGet(4))) { + if((pObSystemProcess = VmmProcessGet(H, 4))) { Util_HashSHA256(pObSystemProcess->win.EPROCESS.pb, pObSystemProcess->win.EPROCESS.cb, pbSHA256); - ctxVmm->dwSystemUniqueId = *(PDWORD)pbSHA256; - snprintf(ctxVmm->szSystemUniqueTag, _countof(ctxVmm->szSystemUniqueTag), "%i_%x", ctxVmm->kernel.dwVersionBuild, ctxVmm->dwSystemUniqueId); + H->vmm.dwSystemUniqueId = *(PDWORD)pbSHA256; + snprintf(H->vmm.szSystemUniqueTag, _countof(H->vmm.szSystemUniqueTag), "%i_%x", H->vmm.kernel.dwVersionBuild, H->vmm.dwSystemUniqueId); } Ob_DECREF(pObSystemProcess); } /* * Try initialize the VMM from scratch with new WINDOWS support. +* -- H * -- paDTBOpt * -- return */ -BOOL VmmWinInit_TryInitialize(_In_opt_ QWORD paDTBOpt) +BOOL VmmWinInit_TryInitialize(_In_ VMM_HANDLE H, _In_opt_ QWORD paDTBOpt) { - HANDLE hThreadInitializeAsync; PVMM_PROCESS pObSystemProcess = NULL, pObProcess = NULL; // Fetch Directory Base (DTB (PML4)) and initialize Memory Model. QWORD vaKERN1 = 0, vaKERN2; - LcGetOption(ctxMain->hLC, LC_OPT_MEMORYINFO_OS_KERNELBASE, &vaKERN1); - LcGetOption(ctxMain->hLC, LC_OPT_MEMORYINFO_OS_KERNELHINT, &vaKERN2); + LcGetOption(H->hLC, LC_OPT_MEMORYINFO_OS_KERNELBASE, &vaKERN1); + LcGetOption(H->hLC, LC_OPT_MEMORYINFO_OS_KERNELHINT, &vaKERN2); - if(paDTBOpt && !VmmWinInit_DTB_Validate(paDTBOpt)) { - VmmLog(MID_CORE, LOGLEVEL_CRITICAL, "Initialization Failed. Unable to verify user-supplied (0x%016llx) DTB. #1", paDTBOpt); + if(paDTBOpt && !VmmWinInit_DTB_Validate(H, paDTBOpt)) { + VmmLog(H, MID_CORE, LOGLEVEL_CRITICAL, "Initialization Failed. Unable to verify user-supplied (0x%016llx) DTB. #1", paDTBOpt); goto fail; } - if(!ctxVmm->kernel.paDTB && LcGetOption(ctxMain->hLC, LC_OPT_MEMORYINFO_OS_DTB, &paDTBOpt)) { - if(!VmmWinInit_DTB_Validate(paDTBOpt)) { - VmmLog(MID_CORE, LOGLEVEL_WARNING, "Unable to verify crash-dump supplied DTB. (0x%016llx) #1", paDTBOpt); + if(!H->vmm.kernel.paDTB && LcGetOption(H->hLC, LC_OPT_MEMORYINFO_OS_DTB, &paDTBOpt)) { + if(!VmmWinInit_DTB_Validate(H, paDTBOpt)) { + VmmLog(H, MID_CORE, LOGLEVEL_WARNING, "Unable to verify crash-dump supplied DTB. (0x%016llx) #1", paDTBOpt); } } - if(!ctxVmm->kernel.paDTB && !VmmWinInit_DTB_FindValidate()) { - VmmLog(MID_CORE, LOGLEVEL_CRITICAL, "Initialization Failed. Unable to locate valid DTB. #2"); + if(!H->vmm.kernel.paDTB && !VmmWinInit_DTB_FindValidate(H)) { + VmmLog(H, MID_CORE, LOGLEVEL_CRITICAL, "Initialization Failed. Unable to locate valid DTB. #2"); goto fail; } - VmmLog(MID_CORE, LOGLEVEL_DEBUG, "DTB located at: %016llx. MemoryModel: %s", ctxVmm->kernel.paDTB, VMM_MEMORYMODEL_TOSTRING[ctxVmm->tpMemoryModel]); + VmmLog(H, MID_CORE, LOGLEVEL_DEBUG, "DTB located at: %016llx. MemoryModel: %s", H->vmm.kernel.paDTB, VMM_MEMORYMODEL_TOSTRING[H->vmm.tpMemoryModel]); // Fetch 'ntoskrnl.exe' base address - if(!(pObSystemProcess = VmmWinInit_FindNtosScan())) { - VmmLog(MID_CORE, LOGLEVEL_CRITICAL, "Initialization Failed. Unable to locate ntoskrnl.exe. #3"); + if(!(pObSystemProcess = VmmWinInit_FindNtosScan(H))) { + VmmLog(H, MID_CORE, LOGLEVEL_CRITICAL, "Initialization Failed. Unable to locate ntoskrnl.exe. #3"); goto fail; } - VmmLog(MID_CORE, LOGLEVEL_DEBUG, "NTOS located at: %016llx", ctxVmm->kernel.vaBase); + VmmLog(H, MID_CORE, LOGLEVEL_DEBUG, "NTOS located at: %016llx", H->vmm.kernel.vaBase); // Initialize Paging (Limited Mode) - MmWin_PagingInitialize(FALSE); + MmWin_PagingInitialize(H, FALSE); // Locate System EPROCESS - pObSystemProcess->win.EPROCESS.va = VmmWinInit_FindSystemEPROCESS(pObSystemProcess); + pObSystemProcess->win.EPROCESS.va = VmmWinInit_FindSystemEPROCESS(H, pObSystemProcess); if(!pObSystemProcess->win.EPROCESS.va) { - VmmLog(MID_CORE, LOGLEVEL_CRITICAL, "Initialization Failed. Unable to locate EPROCESS. #4"); + VmmLog(H, MID_CORE, LOGLEVEL_CRITICAL, "Initialization Failed. Unable to locate EPROCESS. #4"); goto fail; } // Enumerate processes - if(!VmmWinProcess_Enumerate(pObSystemProcess, TRUE, NULL)) { - VmmLog(MID_CORE, LOGLEVEL_CRITICAL, "Initialization Failed. Unable to walk EPROCESS. #5"); + if(!VmmWinProcess_Enumerate(H, pObSystemProcess, TRUE, NULL)) { + VmmLog(H, MID_CORE, LOGLEVEL_CRITICAL, "Initialization Failed. Unable to walk EPROCESS. #5"); goto fail; } - ctxVmm->tpSystem = (VMM_MEMORYMODEL_X64 == ctxVmm->tpMemoryModel) ? VMM_SYSTEM_WINDOWS_X64 : VMM_SYSTEM_WINDOWS_X86; + H->vmm.tpSystem = (VMM_MEMORYMODEL_X64 == H->vmm.tpMemoryModel) ? VMM_SYSTEM_WINDOWS_X64 : VMM_SYSTEM_WINDOWS_X86; // Retrieve operating system version information from 'smss.exe' process // Optionally retrieve PID of Registry process - while((pObProcess = VmmProcessGetNext(pObProcess, 0))) { + while((pObProcess = VmmProcessGetNext(H, pObProcess, 0))) { if(pObProcess->dwPPID == 4) { if(!memcmp("Registry", pObProcess->szName, 9)) { - ctxVmm->kernel.dwPidRegistry = pObProcess->dwPID; + H->vmm.kernel.dwPidRegistry = pObProcess->dwPID; } if(!_stricmp("smss.exe", pObProcess->szName)) { - VmmWinInit_VersionNumber(pObProcess); + VmmWinInit_VersionNumber(H, pObProcess); } } } // Initialization functionality: - InfoDB_Initialize(); - PDB_Initialize(NULL, TRUE); // Async init of PDB subsystem. - VmmWinInit_FindPsLoadedModuleListKDBG(pObSystemProcess); // Find PsLoadedModuleList and possibly KDBG. - VmmWinObj_Initialize(); // Windows Objects Manager. - VmmWinReg_Initialize(); // Registry. - VmmWinInit_TryInitialize_SystemUniqueTag(); + InfoDB_Initialize(H); + PDB_Initialize(H, NULL, TRUE); // Async init of PDB subsystem. + VmmWinInit_FindPsLoadedModuleListKDBG(H, pObSystemProcess); // Find PsLoadedModuleList and possibly KDBG. + VmmWinObj_Initialize(H); // Windows Objects Manager. + VmmWinReg_Initialize(H); // Registry. + VmmWinInit_TryInitialize_SystemUniqueTag(H); // Async Initialization functionality: - hThreadInitializeAsync = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)VmmWinInit_TryInitialize_Async, (LPVOID)NULL, 0, NULL); - if(hThreadInitializeAsync) { - if(ctxMain->cfg.fWaitInitialize) { - WaitForSingleObject(hThreadInitializeAsync, INFINITE); - } - CloseHandle(hThreadInitializeAsync); + if(H->cfg.fWaitInitialize) { + VmmWinInit_TryInitialize_Async(H, 0); // synchronous initialization + } else { + VmmWork_Value(H, VmmWinInit_TryInitialize_Async, 0, 0, VMMWORK_FLAG_PRIO_NORMAL); // async initialization } // return Ob_DECREF(pObSystemProcess); - vmmprintf( + vmmprintf(H, "Initialized %i-bit Windows %i.%i.%i\n", - (ctxVmm->f32 ? 32 : 64), - ctxVmm->kernel.dwVersionMajor, - ctxVmm->kernel.dwVersionMinor, - ctxVmm->kernel.dwVersionBuild); + (H->vmm.f32 ? 32 : 64), + H->vmm.kernel.dwVersionMajor, + H->vmm.kernel.dwVersionMinor, + H->vmm.kernel.dwVersionBuild); return TRUE; fail: - VmmInitializeMemoryModel(VMM_MEMORYMODEL_NA); // clean memory model - ZeroMemory(&ctxVmm->kernel, sizeof(VMM_KERNELINFO)); + VmmInitializeMemoryModel(H, VMM_MEMORYMODEL_NA); // clean memory model + ZeroMemory(&H->vmm.kernel, sizeof(VMM_KERNELINFO)); Ob_DECREF(pObSystemProcess); return FALSE; } diff --git a/vmm/vmmwininit.h b/vmm/vmmwininit.h index 51aca2c..382613c 100644 --- a/vmm/vmmwininit.h +++ b/vmm/vmmwininit.h @@ -12,18 +12,20 @@ /* * Try initialize not yet initialized values in the optional windows kernel -* context ctxVmm->kernel.opt +* context H->vmm.kernel.opt * This function should be run once the system is fully up and running. * This is a best-effort function, uninitialized values will remain zero. +* -- H */ -VOID VmmWinInit_TryInitializeKernelOptionalValues(); +VOID VmmWinInit_TryInitializeKernelOptionalValues(_In_ VMM_HANDLE H); /* * Try initialize the VMM from scratch with new WINDOWS support. +* -- H * -- paDTB * -- return */ _Success_(return) -BOOL VmmWinInit_TryInitialize(_In_opt_ QWORD paDTB); +BOOL VmmWinInit_TryInitialize(_In_ VMM_HANDLE H, _In_opt_ QWORD paDTB); #endif /* __VMMWININIT_H__ */ diff --git a/vmm/vmmwinobj.c b/vmm/vmmwinobj.c index 7fe75b6..f3a5f99 100644 --- a/vmm/vmmwinobj.c +++ b/vmm/vmmwinobj.c @@ -26,15 +26,15 @@ typedef struct tdVMMWINOBJ_CONTEXT { // EXPORTED INITIALIZATION/REFRESH/CLOSE FUNCTIONALITY BELOW: //----------------------------------------------------------------------------- -VOID VmmWinObj_Initialize() +VOID VmmWinObj_Initialize(_In_ VMM_HANDLE H) { PVMMWINOBJ_CONTEXT ctx; if(!(ctx = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMWINOBJ_CONTEXT)))) { goto fail; } - if(!(ctx->psError = ObSet_New())) { goto fail; } - if(!(ctx->pmByObj = ObMap_New(OB_MAP_FLAGS_OBJECT_OB))) { goto fail; } - if(!(ctx->pmByWorkitem = ObMap_New(OB_MAP_FLAGS_OBJECT_OB))) { goto fail; } + if(!(ctx->psError = ObSet_New(H))) { goto fail; } + if(!(ctx->pmByObj = ObMap_New(H, OB_MAP_FLAGS_OBJECT_OB))) { goto fail; } + if(!(ctx->pmByWorkitem = ObMap_New(H, OB_MAP_FLAGS_OBJECT_OB))) { goto fail; } InitializeCriticalSection(&ctx->LockUpdate); - ctxVmm->pObjects = ctx; + H->vmm.pObjects = ctx; return; fail: if(ctx) { @@ -45,11 +45,11 @@ fail: } } -VOID VmmWinObj_Close() +VOID VmmWinObj_Close(_In_ VMM_HANDLE H) { - PVMMWINOBJ_CONTEXT ctx = ctxVmm->pObjects; + PVMMWINOBJ_CONTEXT ctx = H->vmm.pObjects; if(ctx) { - ctxVmm->pObjects = NULL; + H->vmm.pObjects = NULL; Ob_DECREF(ctx->psError); Ob_DECREF(ctx->pmByObj); Ob_DECREF(ctx->pmByWorkitem); @@ -57,19 +57,19 @@ VOID VmmWinObj_Close() } } -VOID VmmWinObj_Refresh() +VOID VmmWinObj_Refresh(_In_ VMM_HANDLE H) { - PVMMWINOBJ_CONTEXT ctx = ctxVmm->pObjects; + PVMMWINOBJ_CONTEXT ctx = H->vmm.pObjects; if(ctx) { EnterCriticalSection(&ctx->LockUpdate); ObSet_Clear(ctx->psError); ObMap_Clear(ctx->pmByObj); ObMap_Clear(ctx->pmByWorkitem); - ObCacheMap_Clear(ctxVmm->pObCacheMapWinObjDisplay); + ObCacheMap_Clear(H->vmm.pObCacheMapWinObjDisplay); LeaveCriticalSection(&ctx->LockUpdate); } - ObContainer_SetOb(ctxVmm->pObCMapObject, NULL); - ObContainer_SetOb(ctxVmm->pObCMapKDriver, NULL); + ObContainer_SetOb(H->vmm.pObCMapObject, NULL); + ObContainer_SetOb(H->vmm.pObCMapKDriver, NULL); } @@ -81,12 +81,13 @@ VOID VmmWinObj_Refresh() /* * Retrieve an object from the object cache. * CALLER DECREF: return +* -- H * -- va = virtual address of the object to retrieve. * -- return = the object, NULL if not found in cache. */ -POB_VMMWINOBJ_OBJECT VmmWinObj_Get(_In_ QWORD va) +POB_VMMWINOBJ_OBJECT VmmWinObj_Get(_In_ VMM_HANDLE H, _In_ QWORD va) { - PVMMWINOBJ_CONTEXT ctx = ctxVmm->pObjects; + PVMMWINOBJ_CONTEXT ctx = H->vmm.pObjects; return ObMap_GetByKey(ctx->pmByObj, va); } @@ -125,24 +126,25 @@ VOID VmmWinObjFile_Initialize_SharedCacheMap_Filter(_In_ QWORD k, _In_ POB_VMMWI /* * Fetch _SHARED_CACHE_MAP data into the OB_VMMWINOBJ_FILE contained by the pm map * in a efficient way. +* -- H * -- pSystemProcess * -- pm */ -VOID VmmWinObjFile_Initialize_SharedCacheMap(_In_ PVMM_PROCESS pSystemProcess, _In_ POB_MAP pmFiles) +VOID VmmWinObjFile_Initialize_SharedCacheMap(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ POB_MAP pmFiles) { - BOOL f, f32 = ctxVmm->f32; + BOOL f, f32 = H->vmm.f32; BYTE pb[0x300]; POB_VMMWINOBJ_FILE peObFile = NULL; - PVMM_OFFSET_FILE po = &ctxVmm->offset.FILE; + PVMM_OFFSET_FILE po = &H->vmm.offset.FILE; // 1: Prefetch valid _SHARED_CACHE_MAP into cache. - if(!VmmCachePrefetchPages5(pSystemProcess, pmFiles, 0x10 + po->_SHARED_CACHE_MAP.cb, 0, (VOID(*)(QWORD, PVOID, POB_SET))VmmWinObjFile_Initialize_SharedCacheMap_Filter)) { return; } + if(!VmmCachePrefetchPages5(H, pSystemProcess, pmFiles, 0x10 + po->_SHARED_CACHE_MAP.cb, 0, (VOID(*)(QWORD, PVOID, POB_SET))VmmWinObjFile_Initialize_SharedCacheMap_Filter)) { return; } // 2: process _SHARED_CACHE_MAP while((peObFile = ObMap_GetNext(pmFiles, peObFile))) { f = peObFile->_SHARED_CACHE_MAP.va && - VmmRead2(pSystemProcess, peObFile->_SHARED_CACHE_MAP.va - 0x10, pb, po->_SHARED_CACHE_MAP.cb, VMM_FLAG_FORCECACHE_READ) && - VMM_POOLTAG_PREPENDED(pb, 0x10, 'CcSc') && + VmmRead2(H, pSystemProcess, peObFile->_SHARED_CACHE_MAP.va - 0x10, pb, po->_SHARED_CACHE_MAP.cb, VMM_FLAG_FORCECACHE_READ) && + VMM_POOLTAG_PREPENDED(f32, pb, 0x10, 'CcSc') && (peObFile->_SHARED_CACHE_MAP.vaVacbs = VMM_PTR_OFFSET(f32, pb + 0x10, po->_SHARED_CACHE_MAP.oVacbs)) && - VMM_KADDR_4_8(peObFile->_SHARED_CACHE_MAP.vaVacbs) && + VMM_KADDR_4_8(f32, peObFile->_SHARED_CACHE_MAP.vaVacbs) && (peObFile->_SHARED_CACHE_MAP.cbFileSize = *(PQWORD)(pb + 0x10 + po->_SHARED_CACHE_MAP.oFileSize)) && (peObFile->_SHARED_CACHE_MAP.cbSectionSize = *(PQWORD)(pb + 0x10 + po->_SHARED_CACHE_MAP.oSectionSize)); peObFile->_SHARED_CACHE_MAP.fValid = f; @@ -158,30 +160,31 @@ VOID VmmWinObjFile_Initialize_SharedCacheMap(_In_ PVMM_PROCESS pSystemProcess, _ * entries are usually stacked in an array-like pattern immediately after the * _CONTROL_AREA object. This makes them very likely to be in the memory cache, * hence need for performance enhancing caching functionality +* -- H * -- pSystemProcess * -- pf */ -BOOL VmmWinObjFile_Initialize_ControlArea_Subsection(_In_ PVMM_PROCESS pSystemProcess, _In_ POB_VMMWINOBJ_FILE pf) +BOOL VmmWinObjFile_Initialize_ControlArea_Subsection(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ POB_VMMWINOBJ_FILE pf) { QWORD va; - BOOL f = TRUE, fSoft; + BOOL f = TRUE, fSoft, f32 = H->vmm.f32; BYTE pb[0x80] = { 0 }; DWORD i = 0, dwStartingSectorNext = 0; VMMWINOBJ_FILE_SUBSECTION ps[VMMWINOBJ_FILE_OBJECT_SUBSECTION_MAX]; - PVMM_OFFSET_FILE po = &ctxVmm->offset.FILE; + PVMM_OFFSET_FILE po = &H->vmm.offset.FILE; // 1: Fetch # _SUBSECTION va = pf->vaControlArea + po->_CONTROL_AREA.cb; - while(f && (i < VMMWINOBJ_FILE_OBJECT_SUBSECTION_MAX) && VMM_KADDR_4_8(va) && VmmRead2(pSystemProcess, va, pb, po->_SUBSECTION.cb, VMM_FLAG_FORCECACHE_READ)) { + while(f && (i < VMMWINOBJ_FILE_OBJECT_SUBSECTION_MAX) && VMM_KADDR_4_8(f32, va) && VmmRead2(H, pSystemProcess, va, pb, po->_SUBSECTION.cb, VMM_FLAG_FORCECACHE_READ)) { ps[i].dwStartingSector = *(PDWORD)(pb + po->_SUBSECTION.oStartingSector); ps[i].dwNumberOfFullSectors = *(PDWORD)(pb + po->_SUBSECTION.oNumberOfFullSectors); - f = (pf->vaControlArea == VMM_PTR_OFFSET(ctxVmm->f32, pb, po->_SUBSECTION.oControlArea)) && - (ps[i].vaSubsectionBase = VMM_PTR_OFFSET(ctxVmm->f32, pb, po->_SUBSECTION.oSubsectionBase)) && VMM_KADDR_4_8(ps[i].vaSubsectionBase) && + f = (pf->vaControlArea == VMM_PTR_OFFSET(f32, pb, po->_SUBSECTION.oControlArea)) && + (ps[i].vaSubsectionBase = VMM_PTR_OFFSET(f32, pb, po->_SUBSECTION.oSubsectionBase)) && VMM_KADDR_4_8(f32, ps[i].vaSubsectionBase) && (ps[i].dwPtesInSubsection = *(PDWORD)(pb + po->_SUBSECTION.oPtesInSubsection)); fSoft = f && (dwStartingSectorNext <= ps[i].dwStartingSector) && - (dwStartingSectorNext = ps[i].dwStartingSector + max(1, ps[i].dwNumberOfFullSectors)) && - ++i; - va = VMM_PTR_OFFSET(ctxVmm->f32, pb, po->_SUBSECTION.oNextSubsection); + (dwStartingSectorNext = ps[i].dwStartingSector + max(1, ps[i].dwNumberOfFullSectors)); + if(fSoft) { i++; } + va = VMM_PTR_OFFSET(f32, pb, po->_SUBSECTION.oNextSubsection); } // 2: fill valid _SUBSECTION(s) info into 'pf'. if(i) { @@ -212,30 +215,33 @@ VOID VmmWinObjFile_Initialize_ControlArea_Filter(_In_ QWORD k, _In_ POB_VMMWINOB /* * Fetch _CONTROL_AREA data into the OB_VMMWINOBJ_FILE contained by the pm map * in a efficient way. +* -- H * -- pSystemProcess * -- pm */ -VOID VmmWinObjFile_Initialize_ControlArea(_In_ PVMM_PROCESS pSystemProcess, _In_ POB_MAP pmFiles) +VOID VmmWinObjFile_Initialize_ControlArea(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ POB_MAP pmFiles) { - BOOL f, f32 = ctxVmm->f32; + BOOL f, f32 = H->vmm.f32; BYTE pb[0x100]; POB_VMMWINOBJ_FILE peObFile = NULL; - PVMM_OFFSET_FILE po = &ctxVmm->offset.FILE; + PVMM_OFFSET_FILE po = &H->vmm.offset.FILE; // 1: Prefetch valid _CONTROL_AREA and following _SUBSECTION into cache. - if(!VmmCachePrefetchPages5(pSystemProcess, pmFiles, 0x1000, 0, (VOID(*)(QWORD, PVOID, POB_SET))VmmWinObjFile_Initialize_ControlArea_Filter)) { return; } + if(!VmmCachePrefetchPages5(H, pSystemProcess, pmFiles, 0x1000, 0, (VOID(*)(QWORD, PVOID, POB_SET))VmmWinObjFile_Initialize_ControlArea_Filter)) { return; } // 2: get _SEGMENT pointer and sub-process _SUBSECTION(s) while((peObFile = ObMap_GetNext(pmFiles, peObFile))) { f = peObFile->vaControlArea && - VmmRead2(pSystemProcess, peObFile->vaControlArea, pb, po->_CONTROL_AREA.cb, VMM_FLAG_FORCECACHE_READ) && - VMM_KADDR(VMM_PTR_OFFSET(f32, pb, po->_CONTROL_AREA.oFilePointer)) && - (peObFile->_SEGMENT.va = VMM_PTR_OFFSET(f32, pb, po->_CONTROL_AREA.oSegment)) && VMM_KADDR_4_8(peObFile->_SEGMENT.va) && - VmmWinObjFile_Initialize_ControlArea_Subsection(pSystemProcess, peObFile); + VmmRead2(H, pSystemProcess, peObFile->vaControlArea, pb, po->_CONTROL_AREA.cb, VMM_FLAG_FORCECACHE_READ) && + VMM_KADDR(f32, VMM_PTR_OFFSET(f32, pb, po->_CONTROL_AREA.oFilePointer)) && + (peObFile->_SEGMENT.va = VMM_PTR_OFFSET(f32, pb, po->_CONTROL_AREA.oSegment)) && VMM_KADDR_4_8(f32, peObFile->_SEGMENT.va); + if(f) { + VmmWinObjFile_Initialize_ControlArea_Subsection(H, pSystemProcess, peObFile); + } } // 3: Prefetch valid _SEGMENT into cache. - if(!VmmCachePrefetchPages5(pSystemProcess, pmFiles, po->_SEGMENT.cb, 0, (VOID(*)(QWORD, PVOID, POB_SET))VmmWinObjFile_Initialize_ControlArea_FilterSegment)) { return; } + if(!VmmCachePrefetchPages5(H, pSystemProcess, pmFiles, po->_SEGMENT.cb, 0, (VOID(*)(QWORD, PVOID, POB_SET))VmmWinObjFile_Initialize_ControlArea_FilterSegment)) { return; } // 4: get _SEGMENT data while((peObFile = ObMap_GetNext(pmFiles, peObFile))) { - if(peObFile->_SEGMENT.va && VmmRead2(pSystemProcess, peObFile->_SEGMENT.va, pb, po->_SEGMENT.cb, VMM_FLAG_FORCECACHE_READ) && (peObFile->vaControlArea == VMM_PTR_OFFSET(f32, pb, po->_SEGMENT.oControlArea))) { + if(peObFile->_SEGMENT.va && VmmRead2(H, pSystemProcess, peObFile->_SEGMENT.va, pb, po->_SEGMENT.cb, VMM_FLAG_FORCECACHE_READ) && (peObFile->vaControlArea == VMM_PTR_OFFSET(f32, pb, po->_SEGMENT.oControlArea))) { peObFile->_SEGMENT.cbSizeOfSegment = *(PQWORD)(pb + po->_SEGMENT.oSizeOfSegment); peObFile->_SEGMENT.vaPrototypePte = *(PQWORD)(pb + po->_SEGMENT.oPrototypePte); peObFile->_SEGMENT.fValid = TRUE; @@ -256,7 +262,7 @@ VOID VmmWinObjFile_Initialize_FileObject_Filter(_In_ QWORD k, _In_ POB_VMMWINOBJ /* * Filter function for VmmWinObjFile_Initialize_FileObjects. */ -BOOL VmmWinObjFile_Initialize_FileObject_FilterRemove(_In_ QWORD k, _In_ POB_VMMWINOBJ_FILE v) +BOOL VmmWinObjFile_Initialize_FileObject_FilterRemove(_In_ VMM_HANDLE H, _In_ QWORD k, _In_ POB_VMMWINOBJ_FILE v) { BOOL f = !v->dwNameHash || @@ -265,20 +271,21 @@ BOOL VmmWinObjFile_Initialize_FileObject_FilterRemove(_In_ QWORD k, _In_ POB_VMM (v->fData && (!v->_SEGMENT.fValid || !v->cSUBSECTION)) || (v->fImage && !v->cSUBSECTION); if(f) { - ObSet_Push(ctxVmm->pObjects->psError, v->va); + ObSet_Push(H->vmm.pObjects->psError, v->va); } return f; } /* * Initialize new file objects. +* -- H * -- pSystemProcess * -- psvaFiles = set of virtual addresses to _FILE_OBJECTs to initialize. * -- pmFilesResult = reults map, new valid objects are added to this map. */ -VOID VmmWinObjFile_Initialize_FileObjects(_In_ PVMM_PROCESS pSystemProcess, _Inout_ POB_SET psvaFiles, _Inout_ POB_MAP pmFilesResult) +VOID VmmWinObjFile_Initialize_FileObjects(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _Inout_ POB_SET psvaFiles, _Inout_ POB_MAP pmFilesResult) { - BOOL f, f32 = ctxVmm->f32; + BOOL f, f32 = H->vmm.f32; QWORD va; DWORD cbPath; QWORD vaSectionObjectPointers, vaFileNameBuffer; @@ -286,19 +293,19 @@ VOID VmmWinObjFile_Initialize_FileObjects(_In_ PVMM_PROCESS pSystemProcess, _Ino POB_MAP pmObFiles = NULL; POB_VMMWINOBJ_FILE peObFile = NULL; WCHAR wszNameBuffer[MAX_PATH + 1] = { 0 }; - PVMMWINOBJ_CONTEXT ctx = ctxVmm->pObjects; - PVMM_OFFSET_FILE po = &ctxVmm->offset.FILE; - if(!(pmObFiles = ObMap_New(OB_MAP_FLAGS_OBJECT_OB))) { return; } + PVMMWINOBJ_CONTEXT ctx = H->vmm.pObjects; + PVMM_OFFSET_FILE po = &H->vmm.offset.FILE; + if(!(pmObFiles = ObMap_New(H, OB_MAP_FLAGS_OBJECT_OB))) { return; } // 1: prefetch _FILE_OBJECT - VmmCachePrefetchPages3(pSystemProcess, psvaFiles, po->_FILE_OBJECT.cb, 0); + VmmCachePrefetchPages3(H, pSystemProcess, psvaFiles, po->_FILE_OBJECT.cb, 0); // 2: set up initial FileObjects while((va = ObSet_Pop(psvaFiles))) { - f = VmmRead2(pSystemProcess, va, pb, po->_FILE_OBJECT.cb, VMM_FLAG_FORCECACHE_READ) && + f = VmmRead2(H, pSystemProcess, va, pb, po->_FILE_OBJECT.cb, VMM_FLAG_FORCECACHE_READ) && (cbPath = *(PWORD)(pb + po->_FILE_OBJECT.oFileName)) && !(cbPath & 1) && (vaFileNameBuffer = VMM_PTR_OFFSET(f32, pb, po->_FILE_OBJECT.oFileNameBuffer)) && (vaSectionObjectPointers = VMM_PTR_OFFSET(f32, pb, po->_FILE_OBJECT.oSectionObjectPointer)) && - VMM_KADDR(vaFileNameBuffer) && VMM_KADDR_4_8(vaSectionObjectPointers) && - (peObFile = Ob_Alloc(OB_TAG_OBJ_FILE, LMEM_ZEROINIT, sizeof(OB_VMMWINOBJ_FILE), (OB_CLEANUP_CB)VmmWinObj_CallbackCleanup_ObObjFile, NULL)); + VMM_KADDR(f32, vaFileNameBuffer) && VMM_KADDR_4_8(f32, vaSectionObjectPointers) && + (peObFile = Ob_AllocEx(H, OB_TAG_OBJ_FILE, LMEM_ZEROINIT, sizeof(OB_VMMWINOBJ_FILE), (OB_CLEANUP_CB)VmmWinObj_CallbackCleanup_ObObjFile, NULL)); if(f) { peObFile->tp = VMMWINOBJ_TYPE_FILE; peObFile->va = va; @@ -312,7 +319,7 @@ VOID VmmWinObjFile_Initialize_FileObjects(_In_ PVMM_PROCESS pSystemProcess, _Ino } } // 3: prefetch _UNICODE_STRING and _SECTION_OBJECT_POINTERS - if(!VmmCachePrefetchPages5(pSystemProcess, pmObFiles, MAX_PATH * 2, 0, (VOID(*)(QWORD, PVOID, POB_SET))VmmWinObjFile_Initialize_FileObject_Filter)) { goto finish; } + if(!VmmCachePrefetchPages5(H, pSystemProcess, pmObFiles, MAX_PATH * 2, 0, (VOID(*)(QWORD, PVOID, POB_SET))VmmWinObjFile_Initialize_FileObject_Filter)) { goto finish; } // 4: fill _UNICODE_STRING and _SECTION_OBJECT_POINTERS while((peObFile = ObMap_GetNext(pmObFiles, peObFile))) { // _UNICODE_STRING @@ -322,36 +329,37 @@ VOID VmmWinObjFile_Initialize_FileObjects(_In_ PVMM_PROCESS pSystemProcess, _Ino vaFileNameBuffer += cbPath - MAX_PATH * 2; cbPath = MAX_PATH * 2; } - if(!VmmReadWtoU(pSystemProcess, vaFileNameBuffer, cbPath, VMM_FLAG_FORCECACHE_READ, NULL, 0, &peObFile->uszPath, NULL, CHARUTIL_FLAG_ALLOC)) { + if(!VmmReadWtoU(H, pSystemProcess, vaFileNameBuffer, cbPath, VMM_FLAG_FORCECACHE_READ, NULL, 0, &peObFile->uszPath, NULL, CHARUTIL_FLAG_ALLOC)) { if(!(peObFile->uszPath = (LPSTR)LocalAlloc(LMEM_ZEROINIT, 1))) { continue; } } peObFile->uszName = CharUtil_PathSplitLast(peObFile->uszPath); peObFile->dwNameHash = CharUtil_HashNameFsU(peObFile->uszName, 0); // _SECTION_OBJECT_POINTERS - if(!VmmRead2(pSystemProcess, peObFile->vaSectionObjectPointers, pb, po->_SECTION_OBJECT_POINTERS.cb, VMM_FLAG_FORCECACHE_READ)) { continue; } - if((va = VMM_PTR_OFFSET(f32, pb, po->_SECTION_OBJECT_POINTERS.oDataSectionObject)) && VMM_KADDR_8_16(va)) { + if(!VmmRead2(H, pSystemProcess, peObFile->vaSectionObjectPointers, pb, po->_SECTION_OBJECT_POINTERS.cb, VMM_FLAG_FORCECACHE_READ)) { continue; } + if((va = VMM_PTR_OFFSET(f32, pb, po->_SECTION_OBJECT_POINTERS.oDataSectionObject)) && VMM_KADDR_8_16(f32, va)) { peObFile->fData = TRUE; peObFile->vaControlArea = va; } - if((va = VMM_PTR_OFFSET(f32, pb, po->_SECTION_OBJECT_POINTERS.oImageSectionObject)) && VMM_KADDR_8_16(va)) { + if((va = VMM_PTR_OFFSET(f32, pb, po->_SECTION_OBJECT_POINTERS.oImageSectionObject)) && VMM_KADDR_8_16(f32, va)) { peObFile->fImage = TRUE; peObFile->vaControlArea = va; } - if((va = VMM_PTR_OFFSET(f32, pb, po->_SECTION_OBJECT_POINTERS.oSharedCacheMap)) && VMM_KADDR_8_16(va)) { + if((va = VMM_PTR_OFFSET(f32, pb, po->_SECTION_OBJECT_POINTERS.oSharedCacheMap)) && VMM_KADDR_8_16(f32, va)) { peObFile->fCache = TRUE; peObFile->_SHARED_CACHE_MAP.va = va; } } // 5: fetch sub-objects - VmmWinObjFile_Initialize_ControlArea(pSystemProcess, pmObFiles); - VmmWinObjFile_Initialize_SharedCacheMap(pSystemProcess, pmObFiles); + VmmWinObjFile_Initialize_ControlArea(H, pSystemProcess, pmObFiles); + VmmWinObjFile_Initialize_SharedCacheMap(H, pSystemProcess, pmObFiles); // 6: finish - move valid to result map and invalid to error set. finish: - ObMap_RemoveByFilter(pmObFiles, (BOOL(*)(QWORD, PVOID))VmmWinObjFile_Initialize_FileObject_FilterRemove); + ObMap_RemoveByFilter(pmObFiles, (OB_MAP_FILTER_REMOVE_PFN_CB)VmmWinObjFile_Initialize_FileObject_FilterRemove); while((peObFile = ObMap_GetNext(pmObFiles, peObFile))) { ObMap_Push(pmFilesResult, peObFile->va, peObFile); ObMap_Push(ctx->pmByObj, peObFile->va, peObFile); } + Ob_DECREF(pmObFiles); } /* @@ -371,21 +379,22 @@ VOID VmmWinObjFile_GetByProcess_DoWork_AddInitial(_In_ QWORD va, _In_ POB_MAP pm /* * Retrieve and initialize all _FILE_OBJECTs belonging to the process either * by retrieving from Handles or Vads. +* -- H * -- pProcess * -- pmObFiles * -- fHandles = TRUE = files from handles, FALSE = files from VADs */ -VOID VmmWinObjFile_GetByProcess_DoWork(_In_ PVMM_PROCESS pProcess, _In_ POB_MAP pmObFiles, _In_ BOOL fHandles) +VOID VmmWinObjFile_GetByProcess_DoWork(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ POB_MAP pmObFiles, _In_ BOOL fHandles) { DWORD i, iMax; POB_SET psvaObFiles = NULL; PVMMOB_MAP_VAD pmObVad = NULL; PVMMOB_MAP_HANDLE pmObHandle = NULL; - PVMMWINOBJ_CONTEXT ctx = ctxVmm->pObjects; - if(!(psvaObFiles = ObSet_New())) { return; } + PVMMWINOBJ_CONTEXT ctx = H->vmm.pObjects; + if(!(psvaObFiles = ObSet_New(H))) { return; } if(fHandles) { // handle map -> file objects - if(VmmMap_GetHandle(pProcess, &pmObHandle, TRUE)) { + if(VmmMap_GetHandle(H, pProcess, &pmObHandle, TRUE)) { for(i = 0, iMax = pmObHandle->cMap; i < iMax; i++) { if((pmObHandle->pMap[i].dwPoolTag & 0x00ffffff) == 'liF') { VmmWinObjFile_GetByProcess_DoWork_AddInitial(pmObHandle->pMap[i].vaObject, pmObFiles, psvaObFiles, ctx); @@ -395,7 +404,7 @@ VOID VmmWinObjFile_GetByProcess_DoWork(_In_ PVMM_PROCESS pProcess, _In_ POB_MAP } } else { // vad map -> file objects - if(VmmMap_GetVad(pProcess, &pmObVad, VMM_VADMAP_TP_PARTIAL)) { + if(VmmMap_GetVad(H, pProcess, &pmObVad, VMM_VADMAP_TP_PARTIAL)) { for(i = 0, iMax = pmObVad->cMap; i < iMax; i++) { if(pmObVad->pMap[i].vaFileObject) { VmmWinObjFile_GetByProcess_DoWork_AddInitial(pmObVad->pMap[i].vaFileObject, pmObFiles, psvaObFiles, ctx); @@ -406,29 +415,30 @@ VOID VmmWinObjFile_GetByProcess_DoWork(_In_ PVMM_PROCESS pProcess, _In_ POB_MAP } // Fetch and initialize new file objects if(ObSet_Size(psvaObFiles)) { - VmmWinObjFile_Initialize_FileObjects(PVMM_PROCESS_SYSTEM, psvaObFiles, pmObFiles); + VmmWinObjFile_Initialize_FileObjects(H, PVMM_PROCESS_SYSTEM, psvaObFiles, pmObFiles); } Ob_DECREF(psvaObFiles); } /* * Retrieve all _FILE_OBJECT related to a process. -* CALLER DECREF: ppmObFiles +* CALLER DECREF: *ppmObFiles +* -- H * -- pProcess * -- ppmObFiles * -- fHandles = TRUE = files from handles, FALSE = files from VADs * -- return */ _Success_(return) -BOOL VmmWinObjFile_GetByProcess(_In_ PVMM_PROCESS pProcess, _Out_ POB_MAP * ppmObFiles, _In_ BOOL fHandles) +BOOL VmmWinObjFile_GetByProcess(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Out_ POB_MAP *ppmObFiles, _In_ BOOL fHandles) { DWORD i, iMax; POB_MAP pmObFiles = NULL; POB_SET psObKeyData = NULL; POB_DATA pObData = NULL; POB_VMMWINOBJ_FILE pObFile = NULL; - PVMMWINOBJ_CONTEXT ctx = ctxVmm->pObjects; - if(!ctx || !ctxVmm->offset.FILE.fValid || !(pmObFiles = ObMap_New(OB_MAP_FLAGS_OBJECT_OB))) { return FALSE; } + PVMMWINOBJ_CONTEXT ctx = H->vmm.pObjects; + if(!ctx || !H->vmm.offset.FILE.fValid || !(pmObFiles = ObMap_New(H, OB_MAP_FLAGS_OBJECT_OB))) { return FALSE; } EnterCriticalSection(&ctx->LockUpdate); // 1: try fetch from already completed process workitem cache if((pObData = ObMap_GetByKey(ctx->pmByWorkitem, (fHandles ? VMMWINOBJ_WORKITEM_FILEPROCSCAN_HANDLE : VMMWINOBJ_WORKITEM_FILEPROCSCAN_VAD) | pProcess->dwPID))) { @@ -444,7 +454,7 @@ BOOL VmmWinObjFile_GetByProcess(_In_ PVMM_PROCESS pProcess, _Out_ POB_MAP * ppmO goto success; } // 2: try fetch from process handles, and put result in process workitem cache - VmmWinObjFile_GetByProcess_DoWork(pProcess, pmObFiles, fHandles); + VmmWinObjFile_GetByProcess_DoWork(H, pProcess, pmObFiles, fHandles); if((psObKeyData = ObMap_FilterSet(pmObFiles, ObMap_FilterSet_FilterAllKey))) { if((pObData = ObSet_GetAll(psObKeyData))) { ObMap_Push(ctx->pmByWorkitem, (fHandles ? VMMWINOBJ_WORKITEM_FILEPROCSCAN_HANDLE : VMMWINOBJ_WORKITEM_FILEPROCSCAN_VAD) | pProcess->dwPID, pObData); @@ -468,17 +478,18 @@ success: * Helper function to retrieve a Page Table Entry (PTE). Retrieval is done in a * fairly performance intensive (non-cached) way, but it's assumed this function * won't be heavily called. +* -- H * -- pSystemProcess * -- vaPteBase * -- iPte * -- fVmmRead = VMM_FLAGS_* flags. * -- return = the PTE or 0 on fail. */ -QWORD VmmWinObjFile_ReadSubsectionAndSharedCache_GetPteSubsection(_In_ PVMM_PROCESS pSystemProcess, _In_ QWORD vaPteBase, _In_ QWORD iPte, _In_ QWORD fVmmRead) +QWORD VmmWinObjFile_ReadSubsectionAndSharedCache_GetPteSubsection(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ QWORD vaPteBase, _In_ QWORD iPte, _In_ QWORD fVmmRead) { QWORD pte = 0; - DWORD cbPte = ctxVmm->tpMemoryModel == VMMDLL_MEMORYMODEL_X86 ? 4 : 8; - VmmReadEx(pSystemProcess, vaPteBase + iPte * cbPte, (PBYTE)&pte, cbPte, NULL, fVmmRead); + DWORD cbPte = H->vmm.tpMemoryModel == VMMDLL_MEMORYMODEL_X86 ? 4 : 8; + VmmReadEx(H, pSystemProcess, vaPteBase + iPte * cbPte, (PBYTE)&pte, cbPte, NULL, fVmmRead); return pte; } @@ -486,26 +497,27 @@ QWORD VmmWinObjFile_ReadSubsectionAndSharedCache_GetPteSubsection(_In_ PVMM_PROC * Helper function to retrieve the virtual address of a _SHARED_CACHE_MAP entry. * Retrieval is done in a performance intensive (non-cached) way, but it's * assumed this function won't be heavily called. +* -- H * -- pSystemProcess * -- pFile * -- iPte * -- fVmmRead * -- return = the virtual address or 0 on fail. */ -QWORD VmmWinObjFile_ReadSubsectionAndSharedCache_GetVaSharedCache(_In_ PVMM_PROCESS pSystemProcess, _In_ POB_VMMWINOBJ_FILE pFile, _In_ QWORD iPte, _In_ QWORD fVmmRead) +QWORD VmmWinObjFile_ReadSubsectionAndSharedCache_GetVaSharedCache(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ POB_VMMWINOBJ_FILE pFile, _In_ QWORD iPte, _In_ QWORD fVmmRead) { - BOOL f; + BOOL f, f32 = H->vmm.f32; BYTE pbVacb[0x40]; QWORD va, iVacb, vaVacbs, vaVacb; - PVMM_OFFSET_FILE po = &ctxVmm->offset.FILE; + PVMM_OFFSET_FILE po = &H->vmm.offset.FILE; iVacb = (iPte << 12) / pFile->_SHARED_CACHE_MAP.cbSectionSize; - vaVacbs = pFile->_SHARED_CACHE_MAP.vaVacbs + iVacb * (ctxVmm->f32 ? 4 : 8); - f = VmmRead2(pSystemProcess, vaVacbs, pbVacb, 8, fVmmRead) && - (vaVacb = VMM_PTR_OFFSET(ctxVmm->f32, pbVacb, 0)) && - VMM_KADDR_4_8(vaVacb) && - VmmRead2(pSystemProcess, vaVacb, pbVacb, po->_VACB.cb, fVmmRead) && - (pFile->_SHARED_CACHE_MAP.va == VMM_PTR_OFFSET(ctxVmm->f32, pbVacb, po->_VACB.oSharedCacheMap)) && - (va = VMM_PTR_OFFSET(ctxVmm->f32, pbVacb, po->_VACB.oBaseAddress)); + vaVacbs = pFile->_SHARED_CACHE_MAP.vaVacbs + iVacb * (f32 ? 4 : 8); + f = VmmRead2(H, pSystemProcess, vaVacbs, pbVacb, 8, fVmmRead) && + (vaVacb = VMM_PTR_OFFSET(f32, pbVacb, 0)) && + VMM_KADDR_4_8(f32, vaVacb) && + VmmRead2(H, pSystemProcess, vaVacb, pbVacb, po->_VACB.cb, fVmmRead) && + (pFile->_SHARED_CACHE_MAP.va == VMM_PTR_OFFSET(f32, pbVacb, po->_VACB.oSharedCacheMap)) && + (va = VMM_PTR_OFFSET(f32, pbVacb, po->_VACB.oBaseAddress)); return f ? (va + (iPte << 12)) : 0; } @@ -514,6 +526,7 @@ QWORD VmmWinObjFile_ReadSubsectionAndSharedCache_GetVaSharedCache(_In_ PVMM_PROC * Function is very similar to the VmmReadEx() function. Reading is not yet * optimized, but the assumption is the function won't be called frequently so * any inefficencies should only have a minor performance impact. +* -- H * -- pSystemProcess * -- pFile * -- iSubsection @@ -524,7 +537,7 @@ QWORD VmmWinObjFile_ReadSubsectionAndSharedCache_GetVaSharedCache(_In_ PVMM_PROC * -- fVmmRead = VMM_FLAGS_* flags. * -- fSharedCache = pFile contains a _SHARED_CACHE_MAP that should be read. */ -VOID VmmWinObjFile_ReadSubsectionAndSharedCache(_In_ PVMM_PROCESS pSystemProcess, _In_ POB_VMMWINOBJ_FILE pFile, _In_ DWORD iSubsection, _In_ QWORD cbOffset, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ QWORD fVmmRead, _In_ BOOL fSharedCache) +VOID VmmWinObjFile_ReadSubsectionAndSharedCache(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ POB_VMMWINOBJ_FILE pFile, _In_ DWORD iSubsection, _In_ QWORD cbOffset, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ QWORD fVmmRead, _In_ BOOL fSharedCache) { BOOL fReadSubsection = FALSE, fReadSharedCacheMap = FALSE; DWORD cbP, cMEMs, cbRead = 0; @@ -560,13 +573,13 @@ VOID VmmWinObjFile_ReadSubsectionAndSharedCache(_In_ PVMM_PROCESS pSystemProcess if(fSharedCache) { for(i = 0; i < cMEMs; i++) { iPte = i + ((cbOffset - oA) >> 12); - pMEMs[i].qwA = VmmWinObjFile_ReadSubsectionAndSharedCache_GetVaSharedCache(pSystemProcess, pFile, iPte, fVmmRead); + pMEMs[i].qwA = VmmWinObjFile_ReadSubsectionAndSharedCache_GetVaSharedCache(H, pSystemProcess, pFile, iPte, fVmmRead); if(pMEMs[i].qwA) { fReadSharedCacheMap = TRUE; } } if(fReadSharedCacheMap) { - VmmReadScatterVirtual(pSystemProcess, ppMEMs, cMEMs, fVmmRead); + VmmReadScatterVirtual(H, pSystemProcess, ppMEMs, cMEMs, fVmmRead); } } // Read from _SUBSECTION @@ -574,11 +587,11 @@ VOID VmmWinObjFile_ReadSubsectionAndSharedCache(_In_ PVMM_PROCESS pSystemProcess for(i = 0; i < cMEMs; i++) { if(pMEMs[i].f) { continue; } iPte = i + ((cbOffset - oA) >> 12); - pMEMs[i].qwA = (iPte < pFile->pSUBSECTION[iSubsection].dwPtesInSubsection) ? VmmWinObjFile_ReadSubsectionAndSharedCache_GetPteSubsection(pSystemProcess, pFile->pSUBSECTION[iSubsection].vaSubsectionBase, iPte, fVmmRead) : 0; + pMEMs[i].qwA = (iPte < pFile->pSUBSECTION[iSubsection].dwPtesInSubsection) ? VmmWinObjFile_ReadSubsectionAndSharedCache_GetPteSubsection(H, pSystemProcess, pFile->pSUBSECTION[iSubsection].vaSubsectionBase, iPte, fVmmRead) : 0; fReadSubsection = TRUE; } if(fReadSubsection) { - VmmReadScatterVirtual(pSystemProcess, ppMEMs, cMEMs, fVmmRead | VMM_FLAG_ALTADDR_VA_PTE); + VmmReadScatterVirtual(H, pSystemProcess, ppMEMs, cMEMs, fVmmRead | VMM_FLAG_ALTADDR_VA_PTE); } } // Handle Result @@ -616,6 +629,7 @@ VOID VmmWinObjFile_ReadSubsectionAndSharedCache(_In_ PVMM_PROCESS pSystemProcess /* * Read an image _FILE_OBJECT. i.e. a PE-file with multiple sections. Reading is * performed by reading the necessary underlying _SUBSECTIONs. +* -- H * -- pSystemProcess * -- pFile * -- cbOffset @@ -625,7 +639,7 @@ VOID VmmWinObjFile_ReadSubsectionAndSharedCache(_In_ PVMM_PROCESS pSystemProcess * -- return */ _Success_(return != 0) -DWORD VmmWinObjFile_ReadImage(_In_ PVMM_PROCESS pSystemProcess, _In_ POB_VMMWINOBJ_FILE pFile, _In_ QWORD cbOffset, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _In_ QWORD fVmmRead) +DWORD VmmWinObjFile_ReadImage(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ POB_VMMWINOBJ_FILE pFile, _In_ QWORD cbOffset, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _In_ QWORD fVmmRead) { DWORD cbRead, cbReadTotal = 0; DWORD iSubsection; @@ -643,6 +657,7 @@ DWORD VmmWinObjFile_ReadImage(_In_ PVMM_PROCESS pSystemProcess, _In_ POB_VMMWINO cbAdjusted = min(cb - cbReadBufferOffset, cbSubsection - cbSubsectionOffset); cbRead = 0; VmmWinObjFile_ReadSubsectionAndSharedCache( + H, pSystemProcess, pFile, iSubsection, @@ -660,6 +675,7 @@ DWORD VmmWinObjFile_ReadImage(_In_ PVMM_PROCESS pSystemProcess, _In_ POB_VMMWINO /* * Read a contigious amount of file data and report the number of bytes read. +* -- H * -- pFile * -- cbOffset * -- pb @@ -668,7 +684,7 @@ DWORD VmmWinObjFile_ReadImage(_In_ PVMM_PROCESS pSystemProcess, _In_ POB_VMMWINO * -- return = the number of bytes read. */ _Success_(return != 0) -DWORD VmmWinObjFile_Read(_In_ POB_VMMWINOBJ_FILE pFile, _In_ QWORD cbOffset, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _In_ QWORD fVmmRead) +DWORD VmmWinObjFile_Read(_In_ VMM_HANDLE H, _In_ POB_VMMWINOBJ_FILE pFile, _In_ QWORD cbOffset, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _In_ QWORD fVmmRead) { DWORD cbRead = 0; PVMM_PROCESS pObSystemProcess = NULL; @@ -679,17 +695,17 @@ DWORD VmmWinObjFile_Read(_In_ POB_VMMWINOBJ_FILE pFile, _In_ QWORD cbOffset, _Ou } cb = (DWORD)(pFile->cb - cbOffset); } - if(!(pObSystemProcess = VmmProcessGet(4))) { return 0; } + if(!(pObSystemProcess = VmmProcessGet(H, 4))) { return 0; } if(pFile->fImage) { - cbRead = VmmWinObjFile_ReadImage(pObSystemProcess, pFile, cbOffset, pb, cb, fVmmRead | VMM_FLAG_ZEROPAD_ON_FAIL); + cbRead = VmmWinObjFile_ReadImage(H, pObSystemProcess, pFile, cbOffset, pb, cb, fVmmRead | VMM_FLAG_ZEROPAD_ON_FAIL); goto finish; } if(pFile->fCache && pFile->_SHARED_CACHE_MAP.fValid) { - VmmWinObjFile_ReadSubsectionAndSharedCache(pObSystemProcess, pFile, 0, cbOffset, pb, cb, &cbRead, fVmmRead | VMM_FLAG_ZEROPAD_ON_FAIL, TRUE); + VmmWinObjFile_ReadSubsectionAndSharedCache(H, pObSystemProcess, pFile, 0, cbOffset, pb, cb, &cbRead, fVmmRead | VMM_FLAG_ZEROPAD_ON_FAIL, TRUE); goto finish; } if(pFile->fData && (pFile->cSUBSECTION == 1)) { - VmmWinObjFile_ReadSubsectionAndSharedCache(pObSystemProcess, pFile, 0, cbOffset, pb, cb, &cbRead, fVmmRead | VMM_FLAG_ZEROPAD_ON_FAIL, FALSE); + VmmWinObjFile_ReadSubsectionAndSharedCache(H, pObSystemProcess, pFile, 0, cbOffset, pb, cb, &cbRead, fVmmRead | VMM_FLAG_ZEROPAD_ON_FAIL, FALSE); goto finish; } finish: @@ -733,7 +749,7 @@ typedef struct tdVMM_WINOBJ_SETUP_CONTEXT { /* * Process a single object in the initial setup phase. */ -VOID VmmWinObjMgr_Initialize_ProcessObject(_Inout_ PVMM_WINOBJ_SETUP_CONTEXT ctxInit, _In_reads_(0x70) PBYTE pb, _In_ PVMM_WINOBJ_SETUP_OBJECT pe) +VOID VmmWinObjMgr_Initialize_ProcessObject(_In_ VMM_HANDLE H, _Inout_ PVMM_WINOBJ_SETUP_CONTEXT ctxInit, _In_reads_(0x70) PBYTE pb, _In_ PVMM_WINOBJ_SETUP_OBJECT pe) { DWORD vaDir32[37]; QWORD vaDir64[37]; @@ -746,11 +762,11 @@ VOID VmmWinObjMgr_Initialize_ProcessObject(_Inout_ PVMM_WINOBJ_SETUP_CONTEXT ctx PVMM_WINOBJ_SETUP_OBJECT peNext; BYTE i, iTp; if(!ObSet_Push(ctxInit->psvaAllObj, pe->va)) { goto fail; } // loop/duplicate protect - if(ctxVmm->f32) { + if(H->vmm.f32) { pHdr32 = (POBJECT_HEADER32)(pb + 0x20); if(pHdr32->SecurityDescriptor && !VMM_KADDR32(pHdr32->SecurityDescriptor)) { goto fail; } - iTp = VmmWin_ObjectTypeGetIndexFromEncoded(pe->va - 0x18, pHdr32->TypeIndex); - if(iTp < 2 || iTp >= ctxVmm->ObjectTypeTable.c) { goto fail; } + iTp = VmmWin_ObjectTypeGetIndexFromEncoded(H, pe->va - 0x18, pHdr32->TypeIndex); + if(iTp < 2 || iTp >= H->vmm.ObjectTypeTable.c) { goto fail; } if(!(pHdr32->InfoMask & 2)) { goto fail; } pName32 = (POBJECT_HEADER_NAME_INFO32)(pb + (pHdr32->InfoMask & 1 ? 0 : 0x10)); if((pName32->Name.Length & 1) || pName32->Name.Length > 0x200) { goto fail; } @@ -764,7 +780,7 @@ VOID VmmWinObjMgr_Initialize_ProcessObject(_Inout_ PVMM_WINOBJ_SETUP_CONTEXT ctx pe->iType = iTp; pe->vaName = pName32->Name.Buffer; pe->cchName = pName32->Name.Length >> 1; - if((iTp == 3) && VmmRead(ctxInit->pSystemProcess, pe->va, (PBYTE)vaDir32, 37 * sizeof(DWORD))) { + if((iTp == 3) && VmmRead(H, ctxInit->pSystemProcess, pe->va, (PBYTE)vaDir32, 37 * sizeof(DWORD))) { // OBJECT_TYPE == DIRECTORY ObSet_Push(ctxInit->psObjectDir, (QWORD)pe); for(i = 0; i < 37; i++) { @@ -778,8 +794,8 @@ VOID VmmWinObjMgr_Initialize_ProcessObject(_Inout_ PVMM_WINOBJ_SETUP_CONTEXT ctx } else { pHdr64 = (POBJECT_HEADER64)(pb + 0x40); if(pHdr64->SecurityDescriptor && !VMM_KADDR64(pHdr64->SecurityDescriptor)) { goto fail; } - iTp = VmmWin_ObjectTypeGetIndexFromEncoded(pe->va - 0x30, pHdr64->TypeIndex); - if(iTp < 2 || iTp >= ctxVmm->ObjectTypeTable.c) { goto fail; } + iTp = VmmWin_ObjectTypeGetIndexFromEncoded(H, pe->va - 0x30, pHdr64->TypeIndex); + if(iTp < 2 || iTp >= H->vmm.ObjectTypeTable.c) { goto fail; } if(!(pHdr64->InfoMask & 2)) { goto fail; } pName64 = (POBJECT_HEADER_NAME_INFO64)(pb + (pHdr64->InfoMask & 1 ? 0 : 0x20)); if((pName64->Name.Length & 1) || pName64->Name.Length > 0x200) { goto fail; } @@ -793,7 +809,7 @@ VOID VmmWinObjMgr_Initialize_ProcessObject(_Inout_ PVMM_WINOBJ_SETUP_CONTEXT ctx pe->iType = iTp; pe->vaName = pName64->Name.Buffer; pe->cchName = pName64->Name.Length >> 1; - if((iTp == 3) && VmmRead(ctxInit->pSystemProcess, pe->va, (PBYTE)vaDir64, 37 * sizeof(QWORD))) { + if((iTp == 3) && VmmRead(H, ctxInit->pSystemProcess, pe->va, (PBYTE)vaDir64, 37 * sizeof(QWORD))) { // OBJECT_TYPE == DIRECTORY ObSet_Push(ctxInit->psObjectDir, (QWORD)pe); for(i = 0; i < 37; i++) { @@ -806,9 +822,9 @@ VOID VmmWinObjMgr_Initialize_ProcessObject(_Inout_ PVMM_WINOBJ_SETUP_CONTEXT ctx } } // OBJECT_TYPE == _OBJECT_SYMBOLIC_LINK --> EXTENDED INFO - if((iTp == ctxVmm->ObjectTypeTable.tpSymbolicLink) && VmmRead(ctxInit->pSystemProcess, pe->va, pb, 0x18)) { + if((iTp == H->vmm.ObjectTypeTable.tpSymbolicLink) && VmmRead(H, ctxInit->pSystemProcess, pe->va, pb, 0x18)) { pe->ExtInfo.ft = *(PQWORD)pb; - if(ctxVmm->f32) { + if(H->vmm.f32) { pus32 = (PUNICODE_STRING32)(pb + 8); if(!(pus32->Length & 1) && (pus32->Length < 0x200) && VMM_KADDR32(pus32->Buffer)) { pe->ExtInfo.cchName = pus32->Length; @@ -832,11 +848,11 @@ fail: /* * Process a single _OBJECT_DIRECTORY_ENTRY in the initial setup phase. */ -VOID VmmWinObjMgr_Initialize_ProcessDirectoryObjectEntry(_Inout_ PVMM_WINOBJ_SETUP_CONTEXT ctxInit, _In_reads_(0x10) PBYTE pb, _In_ PVMM_WINOBJ_SETUP_OBJECT pe) +VOID VmmWinObjMgr_Initialize_ProcessDirectoryObjectEntry(_In_ VMM_HANDLE H, _Inout_ PVMM_WINOBJ_SETUP_CONTEXT ctxInit, _In_reads_(0x10) PBYTE pb, _In_ PVMM_WINOBJ_SETUP_OBJECT pe) { QWORD vaNext, vaObject; PVMM_WINOBJ_SETUP_OBJECT peNext; - if(ctxVmm->f32) { + if(H->vmm.f32) { vaNext = *(PDWORD)pb; // _OBJECT_DIRECTORY_ENTRY.ChainLink vaObject = *(PDWORD)(pb + 4); // _OBJECT_DIRECTORY_ENTRY.Object if(!VMM_KADDR32_4(vaObject) || (vaNext && !VMM_KADDR32_4(vaNext))) { goto fail; } @@ -859,12 +875,12 @@ fail: } _Success_(return) -BOOL VmmWinObjMgr_Initialize_ObjectNameExtInfo(_In_ PVMM_PROCESS pSystemProcess, _Inout_ POB_STRMAP pStrMap, _Inout_ PVMM_MAP_OBJECTENTRY pe, _In_ PVMM_WINOBJ_SETUP_OBJECT pes, _In_ BOOL fForce) +BOOL VmmWinObjMgr_Initialize_ObjectNameExtInfo(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _Inout_ POB_STRMAP pStrMap, _Inout_ PVMM_MAP_OBJECTENTRY pe, _In_ PVMM_WINOBJ_SETUP_OBJECT pes, _In_ BOOL fForce) { WCHAR wsz[0x201]; if(pes->ExtInfo.cchName == (DWORD)-1) { return TRUE; } pe->ExtInfo.ft = pes->ExtInfo.ft; - if(pes->ExtInfo.vaName && VmmRead2(pSystemProcess, pes->ExtInfo.vaName, (PBYTE)wsz, min(0x400, pes->ExtInfo.cchName << 1), VMM_FLAG_FORCECACHE_READ)) { + if(pes->ExtInfo.vaName && VmmRead2(H, pSystemProcess, pes->ExtInfo.vaName, (PBYTE)wsz, min(0x400, pes->ExtInfo.cchName << 1), VMM_FLAG_FORCECACHE_READ)) { wsz[min(0x200, pes->ExtInfo.cchName)] = 0; ObStrMap_PushPtrWU(pStrMap, wsz, &pe->ExtInfo.usz, NULL); pes->ExtInfo.cchName = -1; @@ -882,11 +898,11 @@ BOOL VmmWinObjMgr_Initialize_ObjectNameExtInfo(_In_ PVMM_PROCESS pSystemProcess, * Fetch object name for a single object */ _Success_(return) -BOOL VmmWinObjMgr_Initialize_ObjectName(_In_ PVMM_PROCESS pSystemProcess, _Inout_ POB_STRMAP pStrMap, _Inout_ PVMM_MAP_OBJECTENTRY pe, _In_ PVMM_WINOBJ_SETUP_OBJECT pes, _In_ BOOL fForce) +BOOL VmmWinObjMgr_Initialize_ObjectName(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _Inout_ POB_STRMAP pStrMap, _Inout_ PVMM_MAP_OBJECTENTRY pe, _In_ PVMM_WINOBJ_SETUP_OBJECT pes, _In_ BOOL fForce) { WCHAR wsz[0x201]; if(pes->cchName == (DWORD)-1) { return TRUE; } - if(pes->vaName && VmmRead2(pSystemProcess, pes->vaName, (PBYTE)wsz, min(0x400, pes->cchName << 1), VMM_FLAG_FORCECACHE_READ)) { + if(pes->vaName && VmmRead2(H, pSystemProcess, pes->vaName, (PBYTE)wsz, min(0x400, pes->cchName << 1), VMM_FLAG_FORCECACHE_READ)) { wsz[min(0x200, pes->cchName)] = 0; ObStrMap_PushPtrWU(pStrMap, wsz, &pe->uszName, &pe->cbuName); pes->cchName = -1; @@ -904,31 +920,31 @@ BOOL VmmWinObjMgr_Initialize_ObjectName(_In_ PVMM_PROCESS pSystemProcess, _Inout * Lookup and set object names and other string data. */ _Success_(return) -BOOL VmmWinObjMgr_Initialize_ObMapLookupStr(_Inout_ PVMMOB_MAP_OBJECT pMap, _Inout_ PVMM_WINOBJ_SETUP_CONTEXT ctxInit) +BOOL VmmWinObjMgr_Initialize_ObMapLookupStr(_In_ VMM_HANDLE H, _Inout_ PVMMOB_MAP_OBJECT pMap, _Inout_ PVMM_WINOBJ_SETUP_CONTEXT ctxInit) { DWORD i; PVMM_WINOBJ_SETUP_OBJECT pes; PVMM_MAP_OBJECTENTRY pe; POB_STRMAP pObStrMap = NULL; - if(!(pObStrMap = ObStrMap_New(OB_STRMAP_FLAGS_CASE_SENSITIVE))) { return FALSE; } + if(!(pObStrMap = ObStrMap_New(H, OB_STRMAP_FLAGS_CASE_SENSITIVE))) { return FALSE; } ObSet_Clear(ctxInit->psvaPrefetch); for(i = 0; i < pMap->cMap; i++) { pe = pMap->pMap + i; pes = (PVMM_WINOBJ_SETUP_OBJECT)pe->_Reserved; - if(!VmmWinObjMgr_Initialize_ObjectName(ctxInit->pSystemProcess, pObStrMap, pe, pes, FALSE)) { + if(!VmmWinObjMgr_Initialize_ObjectName(H, ctxInit->pSystemProcess, pObStrMap, pe, pes, FALSE)) { ObSet_Push_PageAlign(ctxInit->psvaPrefetch, pes->vaName, pes->cchName << 1); } - if(!VmmWinObjMgr_Initialize_ObjectNameExtInfo(ctxInit->pSystemProcess, pObStrMap, pe, pes, FALSE)) { + if(!VmmWinObjMgr_Initialize_ObjectNameExtInfo(H, ctxInit->pSystemProcess, pObStrMap, pe, pes, FALSE)) { ObSet_Push_PageAlign(ctxInit->psvaPrefetch, pes->ExtInfo.vaName, pes->ExtInfo.cchName << 1); } } if(ObSet_Size(ctxInit->psvaPrefetch)) { - VmmCachePrefetchPages(ctxInit->pSystemProcess, ctxInit->psvaPrefetch, 0); + VmmCachePrefetchPages(H, ctxInit->pSystemProcess, ctxInit->psvaPrefetch, 0); for(i = 0; i < pMap->cMap; i++) { pe = pMap->pMap + i; pes = (PVMM_WINOBJ_SETUP_OBJECT)pe->_Reserved; - VmmWinObjMgr_Initialize_ObjectName(ctxInit->pSystemProcess, pObStrMap, pe, pes, TRUE); - VmmWinObjMgr_Initialize_ObjectNameExtInfo(ctxInit->pSystemProcess, pObStrMap, pe, pes, TRUE); + VmmWinObjMgr_Initialize_ObjectName(H, ctxInit->pSystemProcess, pObStrMap, pe, pes, TRUE); + VmmWinObjMgr_Initialize_ObjectNameExtInfo(H, ctxInit->pSystemProcess, pObStrMap, pe, pes, TRUE); } } if(!ObStrMap_FinalizeAllocU_DECREF_NULL(&pObStrMap, &pMap->pbMultiText, &pMap->cbMultiText)) { return FALSE; } @@ -966,10 +982,12 @@ VOID VmmWinObjMgr_CallbackCleanup_ObObjectMap(PVMMOB_MAP_OBJECT pOb) /* * Allocate an object manager map, fill it with initial (non string) data and return it. * CALLER DECREF: return +* -- H +* -- ctxInit * -- return */ _Success_(return != NULL) -PVMMOB_MAP_OBJECT VmmWinObjMgr_Initialize_ObMapAlloc(_Inout_ PVMM_WINOBJ_SETUP_CONTEXT ctxInit) +PVMMOB_MAP_OBJECT VmmWinObjMgr_Initialize_ObMapAlloc(_In_ VMM_HANDLE H, _Inout_ PVMM_WINOBJ_SETUP_CONTEXT ctxInit) { DWORD i, cDir, cAll, cType[256] = { 0 }, iTypeSort; PVMMOB_MAP_OBJECT pObMap = NULL; @@ -995,11 +1013,11 @@ PVMMOB_MAP_OBJECT VmmWinObjMgr_Initialize_ObMapAlloc(_Inout_ PVMM_WINOBJ_SETUP_C } Ob_DECREF_NULL(&pObData); // 3: alloc - pObMap = Ob_Alloc(OB_TAG_MAP_OBJECT, LMEM_ZEROINIT, sizeof(VMMOB_MAP_OBJECT) + cAll * (sizeof(VMM_MAP_OBJECTENTRY) + sizeof(DWORD)), (OB_CLEANUP_CB)VmmWinObjMgr_CallbackCleanup_ObObjectMap, NULL); + pObMap = Ob_AllocEx(H, OB_TAG_MAP_OBJECT, LMEM_ZEROINIT, sizeof(VMMOB_MAP_OBJECT) + cAll * (sizeof(VMM_MAP_OBJECTENTRY) + sizeof(DWORD)), (OB_CLEANUP_CB)VmmWinObjMgr_CallbackCleanup_ObObjectMap, NULL); if(!pObMap) { return NULL; } pObMap->cMap = cAll; pObMap->piTypeSort = (PDWORD)((QWORD)pObMap + sizeof(VMMOB_MAP_OBJECT) + cAll * sizeof(VMM_MAP_OBJECTENTRY)); - for(i = 1; i < ctxVmm->ObjectTypeTable.c; i++) { + for(i = 1; i < H->vmm.ObjectTypeTable.c; i++) { pObMap->iTypeSortBase[i] = pObMap->iTypeSortBase[i-1] + cType[i-1]; } // 4: populate @@ -1007,7 +1025,7 @@ PVMMOB_MAP_OBJECT VmmWinObjMgr_Initialize_ObMapAlloc(_Inout_ PVMM_WINOBJ_SETUP_C pe = pObMap->pMap + pes->dwId; pe->va = pes->va; pe->id = pes->dwId; - pe->pType = ctxVmm->ObjectTypeTable.h + pes->iType; + pe->pType = H->vmm.ObjectTypeTable.h + pes->iType; iTypeSort = pObMap->iTypeSortBase[pes->iType] + pObMap->cType[pes->iType]++; pObMap->piTypeSort[iTypeSort] = pe->id; if(pes->pParent) { @@ -1024,31 +1042,32 @@ PVMMOB_MAP_OBJECT VmmWinObjMgr_Initialize_ObMapAlloc(_Inout_ PVMM_WINOBJ_SETUP_C /* * Create an object manager map, in a single threaded context, and return it upon success. * CALLER DECREF: return +* -- H * -- return */ _Success_(return != NULL) -PVMMOB_MAP_OBJECT VmmWinObjMgr_Initialize_DoWork() +PVMMOB_MAP_OBJECT VmmWinObjMgr_Initialize_DoWork(_In_ VMM_HANDLE H) { BOOL fResult = FALSE; - DWORD c, i, cbHdr = ctxVmm->f32 ? 0x38 : 0x70; + DWORD c, i, cbHdr = H->vmm.f32 ? 0x38 : 0x70; QWORD vaRootDirectoryObject = 0; PVMM_WINOBJ_SETUP_OBJECT pes; VMM_WINOBJ_SETUP_CONTEXT ctxInit = { 0 }; BYTE pb[0x70]; PVMMOB_MAP_OBJECT pObObjectMap = NULL; // 1: INIT - if(!VmmWin_ObjectTypeGet(3)) { goto fail; } // ensure type table initialization - if(!(ctxInit.pSystemProcess = VmmProcessGet(4))) { goto fail; } - if(!PDB_GetSymbolPTR(PDB_HANDLE_KERNEL, "ObpRootDirectoryObject", ctxInit.pSystemProcess, &vaRootDirectoryObject)) { goto fail; } - if(!VMM_KADDR_8_16(vaRootDirectoryObject)) { goto fail; } + if(!VmmWin_ObjectTypeGet(H, 3)) { goto fail; } // ensure type table initialization + if(!(ctxInit.pSystemProcess = VmmProcessGet(H, 4))) { goto fail; } + if(!PDB_GetSymbolPTR(H, PDB_HANDLE_KERNEL, "ObpRootDirectoryObject", ctxInit.pSystemProcess, &vaRootDirectoryObject)) { goto fail; } + if(!VMM_KADDR_8_16(H->vmm.f32, vaRootDirectoryObject)) { goto fail; } for(i = 0; i < 2; i++) { - if(!(ctxInit.psObj[i] = ObSet_New())) { goto fail; } - if(!(ctxInit.psDirEntry[i] = ObSet_New())) { goto fail; } + if(!(ctxInit.psObj[i] = ObSet_New(H))) { goto fail; } + if(!(ctxInit.psDirEntry[i] = ObSet_New(H))) { goto fail; } } - if(!(ctxInit.psObjectAll = ObSet_New())) { goto fail; } - if(!(ctxInit.psObjectDir = ObSet_New())) { goto fail; } - if(!(ctxInit.psvaAllObj = ObSet_New())) { goto fail; } - if(!(ctxInit.psvaPrefetch = ObSet_New())) { goto fail; } + if(!(ctxInit.psObjectAll = ObSet_New(H))) { goto fail; } + if(!(ctxInit.psObjectDir = ObSet_New(H))) { goto fail; } + if(!(ctxInit.psvaAllObj = ObSet_New(H))) { goto fail; } + if(!(ctxInit.psvaPrefetch = ObSet_New(H))) { goto fail; } if(!(pes = LocalAlloc(LMEM_ZEROINIT, sizeof(VMM_WINOBJ_SETUP_OBJECT)))) { goto fail; } pes->va = vaRootDirectoryObject; ObSet_Push(ctxInit.psObj[0], (QWORD)pes); @@ -1056,15 +1075,15 @@ PVMMOB_MAP_OBJECT VmmWinObjMgr_Initialize_DoWork() while(ObSet_Size(ctxInit.psObj[0]) || ObSet_Size(ctxInit.psDirEntry[0])) { while(ObSet_Size(ctxInit.psObj[0]) || ObSet_Size(ctxInit.psDirEntry[0])) { while((pes = (PVMM_WINOBJ_SETUP_OBJECT)ObSet_Pop(ctxInit.psObj[0]))) { - if(VmmRead2(ctxInit.pSystemProcess, pes->va - cbHdr, pb, cbHdr, VMM_FLAG_FORCECACHE_READ)) { - VmmWinObjMgr_Initialize_ProcessObject(&ctxInit, pb, pes); + if(VmmRead2(H, ctxInit.pSystemProcess, pes->va - cbHdr, pb, cbHdr, VMM_FLAG_FORCECACHE_READ)) { + VmmWinObjMgr_Initialize_ProcessObject(H, &ctxInit, pb, pes); } else { ObSet_Push(ctxInit.psObj[1], (QWORD)pes); } } while((pes = (PVMM_WINOBJ_SETUP_OBJECT)ObSet_Pop(ctxInit.psDirEntry[0]))) { - if(VmmRead2(ctxInit.pSystemProcess, pes->va, pb, 0x18, VMM_FLAG_FORCECACHE_READ)) { - VmmWinObjMgr_Initialize_ProcessDirectoryObjectEntry(&ctxInit, pb, pes); + if(VmmRead2(H, ctxInit.pSystemProcess, pes->va, pb, 0x18, VMM_FLAG_FORCECACHE_READ)) { + VmmWinObjMgr_Initialize_ProcessDirectoryObjectEntry(H, &ctxInit, pb, pes); } else { ObSet_Push(ctxInit.psDirEntry[1], (QWORD)pes); } @@ -1076,10 +1095,10 @@ PVMMOB_MAP_OBJECT VmmWinObjMgr_Initialize_DoWork() for(i = 0; i < c; i++) { ObSet_Push_PageAlign(ctxInit.psvaPrefetch, ((PVMM_WINOBJ_SETUP_OBJECT)ObSet_Get(ctxInit.psObj[1], i))->va - cbHdr, cbHdr); } - VmmCachePrefetchPages(ctxInit.pSystemProcess, ctxInit.psvaPrefetch, 0); + VmmCachePrefetchPages(H, ctxInit.pSystemProcess, ctxInit.psvaPrefetch, 0); while((pes = (PVMM_WINOBJ_SETUP_OBJECT)ObSet_Pop(ctxInit.psObj[1]))) { - if(VmmRead2(ctxInit.pSystemProcess, pes->va - cbHdr, pb, cbHdr, VMM_FLAG_FORCECACHE_READ)) { - VmmWinObjMgr_Initialize_ProcessObject(&ctxInit, pb, pes); + if(VmmRead2(H, ctxInit.pSystemProcess, pes->va - cbHdr, pb, cbHdr, VMM_FLAG_FORCECACHE_READ)) { + VmmWinObjMgr_Initialize_ProcessObject(H, &ctxInit, pb, pes); } else { LocalFree(pes); } @@ -1091,10 +1110,10 @@ PVMMOB_MAP_OBJECT VmmWinObjMgr_Initialize_DoWork() for(i = 0; i < c; i++) { ObSet_Push_PageAlign(ctxInit.psvaPrefetch, ((PVMM_WINOBJ_SETUP_OBJECT)ObSet_Get(ctxInit.psDirEntry[1], i))->va, 0x18); } - VmmCachePrefetchPages(ctxInit.pSystemProcess, ctxInit.psvaPrefetch, 0); + VmmCachePrefetchPages(H, ctxInit.pSystemProcess, ctxInit.psvaPrefetch, 0); while((pes = (PVMM_WINOBJ_SETUP_OBJECT)ObSet_Pop(ctxInit.psDirEntry[1]))) { - if(VmmRead2(ctxInit.pSystemProcess, pes->va, pb, 0x18, VMM_FLAG_FORCECACHE_READ)) { - VmmWinObjMgr_Initialize_ProcessDirectoryObjectEntry(&ctxInit, pb, pes); + if(VmmRead2(H, ctxInit.pSystemProcess, pes->va, pb, 0x18, VMM_FLAG_FORCECACHE_READ)) { + VmmWinObjMgr_Initialize_ProcessDirectoryObjectEntry(H, &ctxInit, pb, pes); } else { LocalFree(pes); } @@ -1103,9 +1122,9 @@ PVMMOB_MAP_OBJECT VmmWinObjMgr_Initialize_DoWork() } } // 3: ALLOC ObMap and populate with initial data - if(!(pObObjectMap = VmmWinObjMgr_Initialize_ObMapAlloc(&ctxInit))) { goto fail; } + if(!(pObObjectMap = VmmWinObjMgr_Initialize_ObMapAlloc(H, &ctxInit))) { goto fail; } // 4: STRING LOOKUP: - if(!VmmWinObjMgr_Initialize_ObMapLookupStr(pObObjectMap, &ctxInit)) { goto fail; } + if(!VmmWinObjMgr_Initialize_ObMapLookupStr(H, pObObjectMap, &ctxInit)) { goto fail; } Ob_INCREF(pObObjectMap); fail: for(i = 0; i < 2; i++) { @@ -1135,22 +1154,23 @@ fail: /* * Create an object manager map and assign to the global vmm context upon success. * CALLER DECREF: return +* -- H * -- return */ -PVMMOB_MAP_OBJECT VmmWinObjMgr_Initialize() +PVMMOB_MAP_OBJECT VmmWinObjMgr_Initialize(_In_ VMM_HANDLE H) { PVMMOB_MAP_OBJECT pObObject = NULL; - if((pObObject = ObContainer_GetOb(ctxVmm->pObCMapObject))) { return pObObject; } - EnterCriticalSection(&ctxVmm->LockUpdateMap); - if((pObObject = ObContainer_GetOb(ctxVmm->pObCMapObject))) { - LeaveCriticalSection(&ctxVmm->LockUpdateMap); + if((pObObject = ObContainer_GetOb(H->vmm.pObCMapObject))) { return pObObject; } + EnterCriticalSection(&H->vmm.LockUpdateMap); + if((pObObject = ObContainer_GetOb(H->vmm.pObCMapObject))) { + LeaveCriticalSection(&H->vmm.LockUpdateMap); return pObObject; } - if(!(pObObject = VmmWinObjMgr_Initialize_DoWork())) { - pObObject = Ob_Alloc(OB_TAG_MAP_OBJECT, LMEM_ZEROINIT, sizeof(VMMOB_MAP_OBJECT), NULL, NULL); + if(!(pObObject = VmmWinObjMgr_Initialize_DoWork(H))) { + pObObject = Ob_AllocEx(H, OB_TAG_MAP_OBJECT, LMEM_ZEROINIT, sizeof(VMMOB_MAP_OBJECT), NULL, NULL); } - ObContainer_SetOb(ctxVmm->pObCMapObject, pObObject); - LeaveCriticalSection(&ctxVmm->LockUpdateMap); + ObContainer_SetOb(H->vmm.pObCMapObject, pObObject); + LeaveCriticalSection(&H->vmm.LockUpdateMap); return pObObject; } @@ -1182,11 +1202,12 @@ int VmmWinObjKDrv_Initialize_DoWork_CmpSort(_In_ PVMM_MAP_KDRIVERENTRY a, _In_ P /* * Worker function to initialize a new kernel driver map. * CALLER DECREF: return +* -- H * -- return */ -PVMMOB_MAP_KDRIVER VmmWinObjKDrv_Initialize_DoWork() +PVMMOB_MAP_KDRIVER VmmWinObjKDrv_Initialize_DoWork(_In_ VMM_HANDLE H) { - BOOL f32 = ctxVmm->f32; + BOOL f32 = H->vmm.f32; DWORD i, j, cDriver, iObMapDriverBase; PVMM_PROCESS pObSystemProcess = NULL; PVMMOB_MAP_KDRIVER pObMap = NULL; @@ -1199,17 +1220,17 @@ PVMMOB_MAP_KDRIVER VmmWinObjKDrv_Initialize_DoWork() PDRIVER_OBJECT32 pD32 = (PDRIVER_OBJECT32)pbBuffer; PDRIVER_OBJECT64 pD64 = (PDRIVER_OBJECT64)pbBuffer; // 1: pre-init - if(!(pObSystemProcess = VmmProcessGet(4))) { goto fail; } - if(!(psObPrefetch = ObSet_New())) { goto fail; } - if(!(psmObText = ObStrMap_New(OB_STRMAP_FLAGS_CASE_SENSITIVE))) { goto fail; } - if(!VmmMap_GetObject(&pObObjMap)) { goto fail; } + if(!(pObSystemProcess = VmmProcessGet(H, 4))) { goto fail; } + if(!(psObPrefetch = ObSet_New(H))) { goto fail; } + if(!(psmObText = ObStrMap_New(H, OB_STRMAP_FLAGS_CASE_SENSITIVE))) { goto fail; } + if(!VmmMap_GetObject(H, &pObObjMap)) { goto fail; } // 2: alloc object - cDriver = pObObjMap->cType[ctxVmm->ObjectTypeTable.tpDriver]; - pObMap = Ob_Alloc(OB_TAG_MAP_KDRIVER, LMEM_ZEROINIT, sizeof(VMMOB_MAP_KDRIVER) + cDriver * sizeof(VMM_MAP_KDRIVERENTRY), (OB_CLEANUP_CB)VmmWinObjKDrv_ObCloseCallback, NULL); + cDriver = pObObjMap->cType[H->vmm.ObjectTypeTable.tpDriver]; + pObMap = Ob_AllocEx(H, OB_TAG_MAP_KDRIVER, LMEM_ZEROINIT, sizeof(VMMOB_MAP_KDRIVER) + cDriver * sizeof(VMM_MAP_KDRIVERENTRY), (OB_CLEANUP_CB)VmmWinObjKDrv_ObCloseCallback, NULL); if(!pObMap) { goto fail; } pObMap->cMap = cDriver; // 3: get initial data from object map and prefetch - iObMapDriverBase = pObObjMap->iTypeSortBase[ctxVmm->ObjectTypeTable.tpDriver]; + iObMapDriverBase = pObObjMap->iTypeSortBase[H->vmm.ObjectTypeTable.tpDriver]; for(i = 0; i < cDriver; i++) { pe = pObMap->pMap + i; peObj = pObObjMap->pMap + pObObjMap->piTypeSort[iObMapDriverBase + i]; @@ -1218,12 +1239,12 @@ PVMMOB_MAP_KDRIVER VmmWinObjKDrv_Initialize_DoWork() pe->va = peObj->va; pe->dwHash = peObj->dwHash; } - VmmCachePrefetchPages(pObSystemProcess, psObPrefetch, 0); + VmmCachePrefetchPages(H, pObSystemProcess, psObPrefetch, 0); ObSet_Clear(psObPrefetch); // 4: fetch driver objects and populate for(i = 0; i < cDriver; i++) { pe = pObMap->pMap + i; - if(!VmmRead2(pObSystemProcess, pe->va, pbBuffer, (f32 ? sizeof(DRIVER_OBJECT32) : sizeof(DRIVER_OBJECT64)), VMM_FLAG_FORCECACHE_READ)) { continue; } + if(!VmmRead2(H, pObSystemProcess, pe->va, pbBuffer, (f32 ? sizeof(DRIVER_OBJECT32) : sizeof(DRIVER_OBJECT64)), VMM_FLAG_FORCECACHE_READ)) { continue; } if(f32) { if(VMM_KADDR32(pD32->DriverStart) && (pD32->DriverSize < 0x10000000)) { pe->vaStart = pD32->DriverStart; @@ -1268,22 +1289,23 @@ fail: /* * Create an kernel driver map and assign to the global vmm context upon success. * CALLER DECREF: return +* -- H * -- return */ -PVMMOB_MAP_KDRIVER VmmWinObjKDrv_Initialize() +PVMMOB_MAP_KDRIVER VmmWinObjKDrv_Initialize(_In_ VMM_HANDLE H) { PVMMOB_MAP_KDRIVER pObKDriver = NULL; - if((pObKDriver = ObContainer_GetOb(ctxVmm->pObCMapKDriver))) { return pObKDriver; } - EnterCriticalSection(&ctxVmm->LockUpdateMap); - if((pObKDriver = ObContainer_GetOb(ctxVmm->pObCMapKDriver))) { - LeaveCriticalSection(&ctxVmm->LockUpdateMap); + if((pObKDriver = ObContainer_GetOb(H->vmm.pObCMapKDriver))) { return pObKDriver; } + EnterCriticalSection(&H->vmm.LockUpdateMap); + if((pObKDriver = ObContainer_GetOb(H->vmm.pObCMapKDriver))) { + LeaveCriticalSection(&H->vmm.LockUpdateMap); return pObKDriver; } - if(!(pObKDriver = VmmWinObjKDrv_Initialize_DoWork())) { - pObKDriver = Ob_Alloc(OB_TAG_MAP_KDRIVER, LMEM_ZEROINIT, sizeof(VMMOB_MAP_KDRIVER), NULL, NULL); + if(!(pObKDriver = VmmWinObjKDrv_Initialize_DoWork(H))) { + pObKDriver = Ob_AllocEx(H, OB_TAG_MAP_KDRIVER, LMEM_ZEROINIT, sizeof(VMMOB_MAP_KDRIVER), NULL, NULL); } - ObContainer_SetOb(ctxVmm->pObCMapKDriver, pObKDriver); - LeaveCriticalSection(&ctxVmm->LockUpdateMap); + ObContainer_SetOb(H->vmm.pObCMapKDriver, pObKDriver); + LeaveCriticalSection(&H->vmm.LockUpdateMap); return pObKDriver; } @@ -1319,6 +1341,7 @@ VOID _VmmWinObjDisplay_ObCloseCallback(_In_ POB_OBJECT_DISPLAY pObObjectDisplay) * Retrieve a display object representing object information normally displayed * in a object-subdirectory to a '$_INFO' directory. * CALLER DECREF: *ppObjectDisplay +* -- H * -- szTypeName * -- vaObject * -- fDataObj @@ -1327,42 +1350,42 @@ VOID _VmmWinObjDisplay_ObCloseCallback(_In_ POB_OBJECT_DISPLAY pObObjectDisplay) * -- return */ _Success_(return) -BOOL VmmWinObjDisplay_Get(_In_ LPSTR szTypeName, _In_ QWORD vaObject, _In_ BOOL fDataObj, _In_ BOOL fDataHdr, _Out_ POB_OBJECT_DISPLAY *ppObObjectDisplay) +BOOL VmmWinObjDisplay_Get(_In_ VMM_HANDLE H, _In_ LPSTR szTypeName, _In_ QWORD vaObject, _In_ BOOL fDataObj, _In_ BOOL fDataHdr, _Out_ POB_OBJECT_DISPLAY *ppObObjectDisplay) { LPSTR szData = NULL; BOOL fResult = FALSE; POB_OBJECT_DISPLAY pOb = NULL; - AcquireSRWLockExclusive(&ctxVmm->LockSRW.WinObjDisplay); + AcquireSRWLockExclusive(&H->vmm.LockSRW.WinObjDisplay); // 1: fetch existing object from cache - if(!ctxVmm->pObCacheMapWinObjDisplay) { - if(!(ctxVmm->pObCacheMapWinObjDisplay = ObCacheMap_New(0x10000, NULL, OB_CACHEMAP_FLAGS_OBJECT_OB))) { goto fail; } + if(!H->vmm.pObCacheMapWinObjDisplay) { + if(!(H->vmm.pObCacheMapWinObjDisplay = ObCacheMap_New(H, 0x10000, NULL, OB_CACHEMAP_FLAGS_OBJECT_OB))) { goto fail; } } - if(!(pOb = ObCacheMap_GetByKey(ctxVmm->pObCacheMapWinObjDisplay, vaObject))) { - if(!(pOb = Ob_Alloc(OB_TAG_OBJ_DISPLAY, LMEM_ZEROINIT, sizeof(OB_OBJECT_DISPLAY), (OB_CLEANUP_CB)_VmmWinObjDisplay_ObCloseCallback, NULL))) { goto fail; } + if(!(pOb = ObCacheMap_GetByKey(H->vmm.pObCacheMapWinObjDisplay, vaObject))) { + if(!(pOb = Ob_AllocEx(H, OB_TAG_OBJ_DISPLAY, LMEM_ZEROINIT, sizeof(OB_OBJECT_DISPLAY), (OB_CLEANUP_CB)_VmmWinObjDisplay_ObCloseCallback, NULL))) { goto fail; } pOb->va = vaObject; - ObCacheMap_Push(ctxVmm->pObCacheMapWinObjDisplay, vaObject, pOb, 0); + ObCacheMap_Push(H->vmm.pObCacheMapWinObjDisplay, vaObject, pOb, 0); } if((pOb->cbObj == (DWORD)-1) || (pOb->cbHdr == (DWORD)-1)) { goto fail; } // 2: fetch object data (if required) if(!pOb->cbObj || (fDataObj && !pOb->pdcObj)) { - if(!PDB_DisplayTypeNt(szTypeName, 1, vaObject, TRUE, FALSE, (fDataObj ? &szData : NULL), &pOb->cbObj, &pOb->cbType)) { goto fail; } + if(!PDB_DisplayTypeNt(H, szTypeName, 1, vaObject, TRUE, FALSE, (fDataObj ? &szData : NULL), &pOb->cbObj, &pOb->cbType)) { goto fail; } if(szData) { - pOb->pdcObj = ObCompressed_NewFromByte(szData, pOb->cbObj); + pOb->pdcObj = ObCompressed_NewFromByte(H, H->vmm.pObCacheMapObCompressedShared, szData, pOb->cbObj); LocalFree(szData); szData = NULL; if(!pOb->pdcObj) { goto fail; } } } // 2: fetch header data (if required) if(!pOb->cbHdr || (fDataHdr && !pOb->pdcHdr)) { - if(!PDB_DisplayTypeNt(szTypeName, 1, vaObject, TRUE, TRUE, (fDataHdr ? &szData : NULL), &pOb->cbHdr, NULL)) { goto fail; } + if(!PDB_DisplayTypeNt(H, szTypeName, 1, vaObject, TRUE, TRUE, (fDataHdr ? &szData : NULL), &pOb->cbHdr, NULL)) { goto fail; } if(szData) { - pOb->pdcHdr = ObCompressed_NewFromByte(szData, pOb->cbHdr); + pOb->pdcHdr = ObCompressed_NewFromByte(H, H->vmm.pObCacheMapObCompressedShared, szData, pOb->cbHdr); LocalFree(szData); szData = NULL; if(!pOb->pdcHdr) { goto fail; } } } *ppObObjectDisplay = pOb; - ReleaseSRWLockExclusive(&ctxVmm->LockSRW.WinObjDisplay); + ReleaseSRWLockExclusive(&H->vmm.LockSRW.WinObjDisplay); return TRUE; fail: if(pOb) { @@ -1370,12 +1393,13 @@ fail: pOb->cbHdr = -1; } Ob_DECREF(pOb); - ReleaseSRWLockExclusive(&ctxVmm->LockSRW.WinObjDisplay); + ReleaseSRWLockExclusive(&H->vmm.LockSRW.WinObjDisplay); return FALSE; } /* * Vfs Read: helper function to read object files in an object information dir. +* -- H * -- wszPathFile * -- iTypeIndex = the object type index in the ObjectTypeTable * -- vaObject @@ -1385,36 +1409,36 @@ fail: * -- cbOffset * -- return */ -NTSTATUS VmmWinObjDisplay_VfsRead(_In_ LPSTR uszPathFile, _In_opt_ DWORD iTypeIndex, _In_ QWORD vaObject, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) +NTSTATUS VmmWinObjDisplay_VfsRead(_In_ VMM_HANDLE H, _In_ LPSTR uszPathFile, _In_opt_ DWORD iTypeIndex, _In_ QWORD vaObject, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; POB_OBJECT_DISPLAY pObObjDisp = NULL; PVMMWIN_OBJECT_TYPE ptp = NULL; if(CharUtil_StrEndsWith(uszPathFile, "obj-address.txt", TRUE)) { - if(ctxVmm->f32) { + if(H->vmm.f32) { return Util_VfsReadFile_FromDWORD((DWORD)vaObject, pb, cb, pcbRead, cbOffset, FALSE); } else { return Util_VfsReadFile_FromQWORD(vaObject, pb, cb, pcbRead, cbOffset, FALSE); } } - ptp = VmmWin_ObjectTypeGet((BYTE)iTypeIndex); + ptp = VmmWin_ObjectTypeGet(H, (BYTE)iTypeIndex); if(ptp && CharUtil_StrEndsWith(uszPathFile, "obj-type.txt", TRUE)) { return Util_VfsReadFile_FromPBYTE(ptp->usz, strlen(ptp->usz), pb, cb, pcbRead, cbOffset); } if(CharUtil_StrEndsWith(uszPathFile, "obj-data.mem", TRUE)) { - if(ptp && ptp->szType && VmmWinObjDisplay_Get(ptp->szType, vaObject, FALSE, FALSE, &pObObjDisp)) { - nt = Util_VfsReadFile_FromMEM(PVMM_PROCESS_SYSTEM, pObObjDisp->va, pObObjDisp->cbType, VMM_FLAG_ZEROPAD_ON_FAIL, pb, cb, pcbRead, cbOffset); + if(ptp && ptp->szType && VmmWinObjDisplay_Get(H, ptp->szType, vaObject, FALSE, FALSE, &pObObjDisp)) { + nt = Util_VfsReadFile_FromMEM(H, PVMM_PROCESS_SYSTEM, pObObjDisp->va, pObObjDisp->cbType, VMM_FLAG_ZEROPAD_ON_FAIL, pb, cb, pcbRead, cbOffset); Ob_DECREF(pObObjDisp); return nt; } - return Util_VfsReadFile_FromMEM(PVMM_PROCESS_SYSTEM, vaObject, VMMWINOBJDISPLAY_DEFAULT_OBJECT_MEMSIZE, VMM_FLAG_ZEROPAD_ON_FAIL, pb, cb, pcbRead, cbOffset); + return Util_VfsReadFile_FromMEM(H, PVMM_PROCESS_SYSTEM, vaObject, VMMWINOBJDISPLAY_DEFAULT_OBJECT_MEMSIZE, VMM_FLAG_ZEROPAD_ON_FAIL, pb, cb, pcbRead, cbOffset); } - if(CharUtil_StrEndsWith(uszPathFile, "obj-data.txt", TRUE) && ptp && ptp->szType && VmmWinObjDisplay_Get(ptp->szType, vaObject, TRUE, FALSE, &pObObjDisp)) { + if(CharUtil_StrEndsWith(uszPathFile, "obj-data.txt", TRUE) && ptp && ptp->szType && VmmWinObjDisplay_Get(H, ptp->szType, vaObject, TRUE, FALSE, &pObObjDisp)) { nt = Util_VfsReadFile_FromObCompressedStrA(pObObjDisp->pdcObj, pb, cb, pcbRead, cbOffset); Ob_DECREF(pObObjDisp); return nt; } - if(CharUtil_StrEndsWith(uszPathFile, "obj-header.txt", TRUE) && ptp && ptp->szType && VmmWinObjDisplay_Get(ptp->szType, vaObject, FALSE, TRUE, &pObObjDisp)) { + if(CharUtil_StrEndsWith(uszPathFile, "obj-header.txt", TRUE) && ptp && ptp->szType && VmmWinObjDisplay_Get(H, ptp->szType, vaObject, FALSE, TRUE, &pObObjDisp)) { nt = Util_VfsReadFile_FromObCompressedStrA(pObObjDisp->pdcHdr, pb, cb, pcbRead, cbOffset); Ob_DECREF(pObObjDisp); return nt; @@ -1425,16 +1449,17 @@ NTSTATUS VmmWinObjDisplay_VfsRead(_In_ LPSTR uszPathFile, _In_opt_ DWORD iTypeIn /* * Vfs List: helper function to list object files in an object information dir. +* -- H * -- iTypeIndex = the object type index in the ObjectTypeTable * -- vaObject * -- pFileList */ -VOID VmmWinObjDisplay_VfsList(_In_opt_ DWORD iTypeIndex, _In_ QWORD vaObject, _Inout_ PHANDLE pFileList) +VOID VmmWinObjDisplay_VfsList(_In_ VMM_HANDLE H, _In_opt_ DWORD iTypeIndex, _In_ QWORD vaObject, _Inout_ PHANDLE pFileList) { PVMMWIN_OBJECT_TYPE ptp = NULL; POB_OBJECT_DISPLAY pObObjDisp = NULL; - ptp = VmmWin_ObjectTypeGet((BYTE)iTypeIndex); - if(ptp && ptp->szType && VmmWinObjDisplay_Get(ptp->szType, vaObject, FALSE, FALSE, &pObObjDisp)) { + ptp = VmmWin_ObjectTypeGet(H, (BYTE)iTypeIndex); + if(ptp && ptp->szType && VmmWinObjDisplay_Get(H, ptp->szType, vaObject, FALSE, FALSE, &pObObjDisp)) { VMMDLL_VfsList_AddFile(pFileList, "obj-header.txt", pObObjDisp->cbHdr - 1, NULL); VMMDLL_VfsList_AddFile(pFileList, "obj-data.txt", pObObjDisp->cbObj - 1, NULL); VMMDLL_VfsList_AddFile(pFileList, "obj-data.mem", pObObjDisp->cbType, NULL); @@ -1444,6 +1469,6 @@ VOID VmmWinObjDisplay_VfsList(_In_opt_ DWORD iTypeIndex, _In_ QWORD vaObject, _I if(ptp) { VMMDLL_VfsList_AddFile(pFileList, "obj-type.txt", strlen(ptp->usz), NULL); } - VMMDLL_VfsList_AddFile(pFileList, "obj-address.txt", ctxVmm->f32 ? 8 : 16, NULL); + VMMDLL_VfsList_AddFile(pFileList, "obj-address.txt", H->vmm.f32 ? 8 : 16, NULL); Ob_DECREF(pObObjDisp); } diff --git a/vmm/vmmwinobj.h b/vmm/vmmwinobj.h index e1fd02b..585d7ce 100644 --- a/vmm/vmmwinobj.h +++ b/vmm/vmmwinobj.h @@ -65,47 +65,54 @@ typedef struct tdOB_VMMWINOBJ_FILE { /* * Initialize the Object sub-system. This should ideally be done on Vmm Init(). +* -- H */ -VOID VmmWinObj_Initialize(); +VOID VmmWinObj_Initialize(_In_ VMM_HANDLE H); /* * Create an object manager map and assign to the global vmm context upon success. * CALLER DECREF: return +* -- H * -- return */ -PVMMOB_MAP_OBJECT VmmWinObjMgr_Initialize(); +PVMMOB_MAP_OBJECT VmmWinObjMgr_Initialize(_In_ VMM_HANDLE H); /* * Refresh the Object sub-system. +* -- H */ -VOID VmmWinObj_Refresh(); +VOID VmmWinObj_Refresh(_In_ VMM_HANDLE H); /* * Cleanup the Object sub-system. This should ideally be done on Vmm Close(). +* -- H */ -VOID VmmWinObj_Close(); +VOID VmmWinObj_Close(_In_ VMM_HANDLE H); /* * Retrieve an object from the object cache. * CALLER DECREF: return +* -- H * -- va = virtual address of the object to retrieve. * -- return = the object, NULL if not found in cache. */ -POB_VMMWINOBJ_OBJECT VmmWinObj_Get(_In_ QWORD va); +POB_VMMWINOBJ_OBJECT VmmWinObj_Get(_In_ VMM_HANDLE H, _In_ QWORD va); /* * Retrieve all _FILE_OBJECT related to a process. * CALLER DECREF: *ppmObFiles +* -- H * -- pProcess * -- ppmObFiles * -- fHandles = TRUE = files from handles, FALSE = files from VADs * -- return */ _Success_(return) -BOOL VmmWinObjFile_GetByProcess(_In_ PVMM_PROCESS pProcess, _Out_ POB_MAP *ppmObFiles, _In_ BOOL fHandles); +BOOL VmmWinObjFile_GetByProcess(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _Out_ POB_MAP *ppmObFiles, _In_ BOOL fHandles); /* * Read a contigious amount of file data and report the number of bytes read. +* -- H * -- pFile * -- cbOffset * -- pb @@ -114,24 +121,19 @@ BOOL VmmWinObjFile_GetByProcess(_In_ PVMM_PROCESS pProcess, _Out_ POB_MAP *ppmOb * -- return = the number of bytes read. */ _Success_(return != 0) -DWORD VmmWinObjFile_Read(_In_ POB_VMMWINOBJ_FILE pFile, _In_ QWORD cbOffset, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _In_ QWORD fVmmRead); - -/* -* Create an object manager map and assign to the global vmm context upon success. -* CALLER DECREF: return -* -- return -*/ -PVMMOB_MAP_OBJECT VmmWinObjMgr_Initialize(); +DWORD VmmWinObjFile_Read(_In_ VMM_HANDLE H, _In_ POB_VMMWINOBJ_FILE pFile, _In_ QWORD cbOffset, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _In_ QWORD fVmmRead); /* * Create an kernel driver map and assign to the global vmm context upon success. * CALLER DECREF: return +* -- H * -- return */ -PVMMOB_MAP_KDRIVER VmmWinObjKDrv_Initialize(); +PVMMOB_MAP_KDRIVER VmmWinObjKDrv_Initialize(_In_ VMM_HANDLE H); /* * Vfs Read: helper function to read object files in an object information dir. +* -- H * -- uszPathFile * -- iTypeIndex = the object type index in the ObjectTypeTable * -- vaObject @@ -141,14 +143,15 @@ PVMMOB_MAP_KDRIVER VmmWinObjKDrv_Initialize(); * -- cbOffset * -- return */ -NTSTATUS VmmWinObjDisplay_VfsRead(_In_ LPSTR uszPathFile, _In_opt_ DWORD iTypeIndex, _In_ QWORD vaObject, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset); +NTSTATUS VmmWinObjDisplay_VfsRead(_In_ VMM_HANDLE H, _In_ LPSTR uszPathFile, _In_opt_ DWORD iTypeIndex, _In_ QWORD vaObject, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset); /* * Vfs List: helper function to list object files in an object information dir. +* -- H * -- iTypeIndex = the object type index in the ObjectTypeTable * -- vaObject * -- pFileList */ -VOID VmmWinObjDisplay_VfsList(_In_opt_ DWORD iTypeIndex, _In_ QWORD vaObject, _Inout_ PHANDLE pFileList); +VOID VmmWinObjDisplay_VfsList(_In_ VMM_HANDLE H, _In_opt_ DWORD iTypeIndex, _In_ QWORD vaObject, _Inout_ PHANDLE pFileList); #endif /* __VMMWINOBJ_H__ */ diff --git a/vmm/vmmwinpool.c b/vmm/vmmwinpool.c index 36423d3..2caf183 100644 --- a/vmm/vmmwinpool.c +++ b/vmm/vmmwinpool.c @@ -107,10 +107,12 @@ int _VmmWinPool_qsort_PoolEntry(PVMM_MAP_POOLENTRY p1, PVMM_MAP_POOLENTRY p2) } _Success_(return != NULL) -PVMMOB_MAP_POOL VmmWinPool_Initialize_BigPool_DoWork(_In_ PVMM_PROCESS pSystemProcess) +PVMMOB_MAP_POOL VmmWinPool_Initialize_BigPool_DoWork(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess) { + BOOL f32 = H->vmm.f32; + DWORD dwVersionBuild = H->vmm.kernel.dwVersionBuild; DWORD i, j, o, cPoolBigTable = 0, iEntry, cbEntry = 0x10; - DWORD cTag, dwBuild, cTag2Map = 0; + DWORD cTag, cTag2Map = 0; QWORD cEntry; QWORD cbPool, va = 0, vaPoolBigTable = 0; PBYTE pb = NULL; @@ -126,23 +128,23 @@ PVMMOB_MAP_POOL VmmWinPool_Initialize_BigPool_DoWork(_In_ PVMM_PROCESS pSystemPr P_BIGPOOL32_VISTA pbpVI32; P_BIGPOOL32_XP pbpXP32; // 0: winxp big pool code is not working - return empty pool - if(ctxVmm->kernel.dwVersionBuild < 6000) { - return (PVMMOB_MAP_POOL)Ob_Alloc(OB_TAG_MAP_POOL, LMEM_ZEROINIT, sizeof(VMMOB_MAP_POOL), NULL, NULL); + if(dwVersionBuild < 6000) { + return (PVMMOB_MAP_POOL)Ob_AllocEx(H, OB_TAG_MAP_POOL, LMEM_ZEROINIT, sizeof(VMMOB_MAP_POOL), NULL, NULL); } // 1: initial sizes - if(!ctxVmm->f32) { + if(!f32) { cbEntry = 0x18; - if(ctxVmm->kernel.dwVersionBuild >= 20348) { cbEntry = 0x20; } // SERVER-2022 / WIN11 and above + if(dwVersionBuild >= 20348) { cbEntry = 0x20; } // SERVER-2022 / WIN11 and above } // 2: initial allocs - if(!(pObCnt = ObCounter_New(0))) { goto fail; } - if(!PDB_GetSymbolPTR(PDB_HANDLE_KERNEL, "PoolBigPageTable", pSystemProcess, (PVOID)&vaPoolBigTable)) { goto fail; } - if(!PDB_GetSymbolDWORD(PDB_HANDLE_KERNEL, "PoolBigPageTableSize", pSystemProcess, &cPoolBigTable)) { goto fail; } - if(!VMM_KADDR_PAGE(vaPoolBigTable) || (cPoolBigTable & 0xfff) || (cPoolBigTable > 0x01000000)) { goto fail; } + if(!(pObCnt = ObCounter_New(H, 0))) { goto fail; } + if(!PDB_GetSymbolPTR(H, PDB_HANDLE_KERNEL, "PoolBigPageTable", pSystemProcess, (PVOID)&vaPoolBigTable)) { goto fail; } + if(!PDB_GetSymbolDWORD(H, PDB_HANDLE_KERNEL, "PoolBigPageTableSize", pSystemProcess, &cPoolBigTable)) { goto fail; } + if(!VMM_KADDR_PAGE(f32, vaPoolBigTable) || (cPoolBigTable & 0xfff) || (cPoolBigTable > 0x01000000)) { goto fail; } if(!(pb = LocalAlloc(0, (SIZE_T)cbEntry * cPoolBigTable))) { goto fail; } - VmmReadEx(pSystemProcess, vaPoolBigTable, pb, cbEntry * cPoolBigTable, NULL, VMM_FLAG_ZEROPAD_ON_FAIL); + VmmReadEx(H, pSystemProcess, vaPoolBigTable, pb, cbEntry * cPoolBigTable, NULL, VMM_FLAG_ZEROPAD_ON_FAIL); // 3: count entries - if(ctxVmm->f32) { + if(f32) { for(i = 0, o = 0; i < cPoolBigTable; i++) { if(VMM_KADDR32(*(PDWORD)(pb + o))) { ObCounter_Inc(pObCnt, (QWORD)(*(PDWORD)(pb + o + 4))); @@ -165,14 +167,14 @@ PVMMOB_MAP_POOL VmmWinPool_Initialize_BigPool_DoWork(_In_ PVMM_PROCESS pSystemPr cbPool += (DWORD)cEntry * sizeof(VMM_MAP_POOLENTRY); cbPool += cTag * sizeof(VMM_MAP_POOLENTRYTAG); cbPool += (DWORD)cEntry * sizeof(DWORD); - if(!(pObPool = Ob_Alloc(OB_TAG_MAP_POOL, LMEM_ZEROINIT, (SIZE_T)cbPool, NULL, NULL))) { goto fail; } + if(!(pObPool = Ob_AllocEx(H, OB_TAG_MAP_POOL, LMEM_ZEROINIT, (SIZE_T)cbPool, NULL, NULL))) { goto fail; } pObPool->cTag = cTag; pObPool->cMap = (DWORD)cEntry; pObPool->pTag = (PVMM_MAP_POOLENTRYTAG)(pObPool->pMap + pObPool->cMap); pObPool->piTag2Map = (PDWORD)(pObPool->pTag + pObPool->cTag); // 5: fill tags sorted by pool tag and set up shortcut hashmap if(!ObCounter_GetAllSortedByKey(pObCnt, pObPool->cTag, (POB_COUNTER_ENTRY)pObPool->pTag)) { goto fail; } - if(!(pmObTag = ObMap_New(OB_MAP_FLAGS_OBJECT_VOID))) { goto fail; } + if(!(pmObTag = ObMap_New(H, OB_MAP_FLAGS_OBJECT_VOID))) { goto fail; } for(i = 0; i < pObPool->cTag; i++) { peTag = pObPool->pTag + i; cTag2Map += peTag->cEntry; @@ -180,19 +182,18 @@ PVMMOB_MAP_POOL VmmWinPool_Initialize_BigPool_DoWork(_In_ PVMM_PROCESS pSystemPr ObMap_Push(pmObTag, 0x100000000 | peTag->dwTag, peTag); } // 6: populate map entries (os dependent) - dwBuild = ctxVmm->kernel.dwVersionBuild; - if(ctxVmm->f32) { + if(f32) { for(i = 0, j = 0, o = 0; i < cPoolBigTable; i++) { va = *(PDWORD)(pb + o); if(VMM_KADDR32(va)) { pePool = pObPool->pMap + j; pePool->va = va; pePool->dwTag = *(PDWORD)(pb + o + 4); - if(dwBuild >= 10240) { + if(dwVersionBuild >= 10240) { pbp1032 = (P_BIGPOOL32_10)(pb + o); pePool->tpPool = VmmWinPool_PoolTypeConvert(pbp1032->PoolType); pePool->cb = pbp1032->NumberOfBytes; - } else if(dwBuild >= 6000) { + } else if(dwVersionBuild >= 6000) { pbpVI32 = (P_BIGPOOL32_VISTA)(pb + o); pePool->tpPool = VmmWinPool_PoolTypeConvert(pbpVI32->PoolType); pePool->cb = pbpVI32->NumberOfBytes; @@ -212,7 +213,7 @@ PVMMOB_MAP_POOL VmmWinPool_Initialize_BigPool_DoWork(_In_ PVMM_PROCESS pSystemPr pePool = pObPool->pMap + j; pePool->va = va; pePool->dwTag = *(PDWORD)(pb + o + 8); - if(dwBuild >= 10240) { + if(dwVersionBuild >= 10240) { pbp1064 = (P_BIGPOOL64_10)(pb + o); pePool->tpPool = VmmWinPool_PoolTypeConvert(pbp1064->PoolType); pePool->cb = (DWORD)min(0xffffffff, pbp1064->NumberOfBytes); @@ -269,6 +270,7 @@ typedef struct tdVMMWINPOOL_CTX_POOLSTORE { * NB! va, pbPoolBlock, cbPoolEntry should _INCLUDE_ pool header! */ VOID VmmWinPool_AllPool_PushItem( + _In_ VMM_HANDLE H, _In_ PVMMWINPOOL_CTX_POOLSTORE *ppStore, _In_ VMM_MAP_POOL_TP tp, _In_ VMM_MAP_POOL_TPSS tpSS, @@ -281,7 +283,7 @@ VOID VmmWinPool_AllPool_PushItem( PVMM_MAP_POOLENTRY pe; DWORD i, cbHdr = 0, cbPoolEntryHdr, dwTag = 0; CHAR c; - BOOL fBadTag = FALSE, f32 = ctxVmm->f32; + BOOL fBadTag = FALSE, f32 = H->vmm.f32; DWORD cbBigPoolThreshold = f32 ? 0xff0 : 0xfe0; if(cbPoolBlock < cbBigPoolThreshold) { cbHdr = f32 ? 8 : 16; @@ -328,13 +330,14 @@ VOID VmmWinPool_AllPool_PushItem( /* * Create the pool map. * CALLER DECREF: return +* -- H * -- pPoolBig * -- ppStore * -- cStore * -- return */ _Success_(return != NULL) -PVMMOB_MAP_POOL VmmWinPool_AllPool_CreateMap(_In_ PVMMOB_MAP_POOL pPoolBig, _In_reads_(cStore) PVMMWINPOOL_CTX_POOLSTORE *ppStore, _In_ DWORD cStore) +PVMMOB_MAP_POOL VmmWinPool_AllPool_CreateMap(_In_ VMM_HANDLE H, _In_ PVMMOB_MAP_POOL pPoolBig, _In_reads_(cStore) PVMMWINPOOL_CTX_POOLSTORE *ppStore, _In_ DWORD cStore) { PVMMWINPOOL_CTX_POOLSTORE pStore; PVMMOB_MAP_POOL pObPool = NULL; @@ -346,7 +349,7 @@ PVMMOB_MAP_POOL VmmWinPool_AllPool_CreateMap(_In_ PVMMOB_MAP_POOL pPoolBig, _In_ PVMM_MAP_POOLENTRYTAG peTag; // 1: count tags and entries cEntry = pPoolBig->cMap; - if(!(pObCnt = ObCounter_New(0))) { goto fail; } + if(!(pObCnt = ObCounter_New(H, 0))) { goto fail; } for(i = 0; i < pPoolBig->cTag; i++) { ObCounter_Set(pObCnt, (QWORD)pPoolBig->pTag[i].dwTag, (QWORD)pPoolBig->pTag[i].cEntry); } @@ -367,14 +370,14 @@ PVMMOB_MAP_POOL VmmWinPool_AllPool_CreateMap(_In_ PVMMOB_MAP_POOL pPoolBig, _In_ cbPool += cTag * sizeof(VMM_MAP_POOLENTRYTAG); cbPool += (DWORD)cEntry * sizeof(DWORD); if(cbPool > 0x80000000) { goto fail; } - if(!(pObPool = Ob_Alloc(OB_TAG_MAP_POOL, LMEM_ZEROINIT, (SIZE_T)cbPool, NULL, NULL))) { goto fail; } + if(!(pObPool = Ob_AllocEx(H, OB_TAG_MAP_POOL, LMEM_ZEROINIT, (SIZE_T)cbPool, NULL, NULL))) { goto fail; } pObPool->cTag = cTag; pObPool->cMap = cEntry; pObPool->pTag = (PVMM_MAP_POOLENTRYTAG)(pObPool->pMap + pObPool->cMap); pObPool->piTag2Map = (PDWORD)(pObPool->pTag + pObPool->cTag); // 3: fill tags sorted by pool tag and set up shortcut hashmap if(!ObCounter_GetAllSortedByKey(pObCnt, pObPool->cTag, (POB_COUNTER_ENTRY)pObPool->pTag)) { goto fail; } - if(!(pmObTag = ObMap_New(OB_MAP_FLAGS_OBJECT_VOID))) { goto fail; } + if(!(pmObTag = ObMap_New(H, OB_MAP_FLAGS_OBJECT_VOID))) { goto fail; } for(i = 0; i < pObPool->cTag; i++) { peTag = pObPool->pTag + i; cTag2Map += peTag->cEntry; @@ -530,12 +533,12 @@ typedef union td_HEAP_VS_CHUNK_HEADER_SIZE64 { } _HEAP_VS_CHUNK_HEADER_SIZE64, *P_HEAP_VS_CHUNK_HEADER_SIZE64; _Success_(return) -BOOL VmmWinPool_AllPool1903_Offsets(_In_ PVMM_PROCESS pSystemProcess, _Out_ PVMMWINPOOL_OFFSETS po) +BOOL VmmWinPool_AllPool1903_Offsets(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _Out_ PVMMWINPOOL_OFFSETS po) { // static initialization: po->_EX_POOL_HEAP_MANAGER_STATE.oHeapKey = 0; po->_EX_HEAP_POOL_NODE.oHeaps = 0; - if(ctxVmm->f32) { + if(H->vmm.f32) { po->cbBigPoolThreshold = 0xff0; po->_EX_POOL_HEAP_MANAGER_STATE.oLfhKey = 4; po->_HEAP_VS_CHUNK_HEADER.cb = 8; @@ -546,24 +549,24 @@ BOOL VmmWinPool_AllPool1903_Offsets(_In_ PVMM_PROCESS pSystemProcess, _Out_ PVMM } // dynamic symbol-based initialization: BOOL f = - PDB_GetSymbolAddress(PDB_HANDLE_KERNEL, "ExPoolState", &po->vaExPoolState) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_EX_POOL_HEAP_MANAGER_STATE", "NumberOfPools", &po->_EX_POOL_HEAP_MANAGER_STATE.oNumberOfPools) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_EX_POOL_HEAP_MANAGER_STATE", "PoolNode", &po->_EX_POOL_HEAP_MANAGER_STATE.oPoolNode) && - PDB_GetTypeChildOffset(PDB_HANDLE_KERNEL, "_EX_POOL_HEAP_MANAGER_STATE", "SpecialHeaps", &po->_EX_POOL_HEAP_MANAGER_STATE.oSpecialHeaps) && - PDB_GetTypeSizeShort(PDB_HANDLE_KERNEL, "_EX_HEAP_POOL_NODE", &po->_EX_HEAP_POOL_NODE.cb) && (po->_EX_HEAP_POOL_NODE.cb < 0x4000) && - PDB_GetTypeSizeShort(PDB_HANDLE_KERNEL, "_SEGMENT_HEAP", &po->_SEGMENT_HEAP.cb) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_SEGMENT_HEAP", "SegContexts", &po->_SEGMENT_HEAP.oSegContexts) && - PDB_GetTypeSizeShort(PDB_HANDLE_KERNEL, "_HEAP_SEG_CONTEXT", &po->_HEAP_SEG_CONTEXT.cb) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_HEAP_SEG_CONTEXT", "UnitShift", &po->_HEAP_SEG_CONTEXT.oUnitShift) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_HEAP_SEG_CONTEXT", "FirstDescriptorIndex", &po->_HEAP_SEG_CONTEXT.oFirstDescriptorIndex) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_HEAP_SEG_CONTEXT", "SegmentListHead", &po->_HEAP_SEG_CONTEXT.oSegmentListHead) && - PDB_GetTypeSizeShort(PDB_HANDLE_KERNEL, "_HEAP_PAGE_SEGMENT", &po->_HEAP_PAGE_SEGMENT.cb) && (po->_HEAP_PAGE_SEGMENT.cb <= 0x2000) && - PDB_GetTypeSizeShort(PDB_HANDLE_KERNEL, "_HEAP_PAGE_RANGE_DESCRIPTOR", &po->_HEAP_PAGE_RANGE_DESCRIPTOR.cb) && (256 * po->_HEAP_PAGE_RANGE_DESCRIPTOR.cb == po->_HEAP_PAGE_SEGMENT.cb) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_HEAP_PAGE_RANGE_DESCRIPTOR", "UnitSize", &po->_HEAP_PAGE_RANGE_DESCRIPTOR.oUnitSize) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_HEAP_PAGE_RANGE_DESCRIPTOR", "RangeFlags", &po->_HEAP_PAGE_RANGE_DESCRIPTOR.oRangeFlags) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_HEAP_PAGE_RANGE_DESCRIPTOR", "TreeSignature", &po->_HEAP_PAGE_RANGE_DESCRIPTOR.oTreeSignature) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_HEAP_LFH_SUBSEGMENT", "BlockOffsets", &po->_HEAP_LFH_SUBSEGMENT.oBlockOffsets) && - PDB_GetTypeChildOffsetShort(PDB_HANDLE_KERNEL, "_HEAP_LFH_SUBSEGMENT", "BlockBitmap", &po->_HEAP_LFH_SUBSEGMENT.oBlockBitmap); + PDB_GetSymbolAddress(H, PDB_HANDLE_KERNEL, "ExPoolState", &po->vaExPoolState) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_EX_POOL_HEAP_MANAGER_STATE", "NumberOfPools", &po->_EX_POOL_HEAP_MANAGER_STATE.oNumberOfPools) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_EX_POOL_HEAP_MANAGER_STATE", "PoolNode", &po->_EX_POOL_HEAP_MANAGER_STATE.oPoolNode) && + PDB_GetTypeChildOffset(H, PDB_HANDLE_KERNEL, "_EX_POOL_HEAP_MANAGER_STATE", "SpecialHeaps", &po->_EX_POOL_HEAP_MANAGER_STATE.oSpecialHeaps) && + PDB_GetTypeSizeShort(H, PDB_HANDLE_KERNEL, "_EX_HEAP_POOL_NODE", &po->_EX_HEAP_POOL_NODE.cb) && (po->_EX_HEAP_POOL_NODE.cb < 0x4000) && + PDB_GetTypeSizeShort(H, PDB_HANDLE_KERNEL, "_SEGMENT_HEAP", &po->_SEGMENT_HEAP.cb) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_SEGMENT_HEAP", "SegContexts", &po->_SEGMENT_HEAP.oSegContexts) && + PDB_GetTypeSizeShort(H, PDB_HANDLE_KERNEL, "_HEAP_SEG_CONTEXT", &po->_HEAP_SEG_CONTEXT.cb) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_HEAP_SEG_CONTEXT", "UnitShift", &po->_HEAP_SEG_CONTEXT.oUnitShift) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_HEAP_SEG_CONTEXT", "FirstDescriptorIndex", &po->_HEAP_SEG_CONTEXT.oFirstDescriptorIndex) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_HEAP_SEG_CONTEXT", "SegmentListHead", &po->_HEAP_SEG_CONTEXT.oSegmentListHead) && + PDB_GetTypeSizeShort(H, PDB_HANDLE_KERNEL, "_HEAP_PAGE_SEGMENT", &po->_HEAP_PAGE_SEGMENT.cb) && (po->_HEAP_PAGE_SEGMENT.cb <= 0x2000) && + PDB_GetTypeSizeShort(H, PDB_HANDLE_KERNEL, "_HEAP_PAGE_RANGE_DESCRIPTOR", &po->_HEAP_PAGE_RANGE_DESCRIPTOR.cb) && (256 * po->_HEAP_PAGE_RANGE_DESCRIPTOR.cb == po->_HEAP_PAGE_SEGMENT.cb) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_HEAP_PAGE_RANGE_DESCRIPTOR", "UnitSize", &po->_HEAP_PAGE_RANGE_DESCRIPTOR.oUnitSize) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_HEAP_PAGE_RANGE_DESCRIPTOR", "RangeFlags", &po->_HEAP_PAGE_RANGE_DESCRIPTOR.oRangeFlags) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_HEAP_PAGE_RANGE_DESCRIPTOR", "TreeSignature", &po->_HEAP_PAGE_RANGE_DESCRIPTOR.oTreeSignature) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_HEAP_LFH_SUBSEGMENT", "BlockOffsets", &po->_HEAP_LFH_SUBSEGMENT.oBlockOffsets) && + PDB_GetTypeChildOffsetShort(H, PDB_HANDLE_KERNEL, "_HEAP_LFH_SUBSEGMENT", "BlockBitmap", &po->_HEAP_LFH_SUBSEGMENT.oBlockBitmap); return f; } @@ -572,8 +575,9 @@ BOOL VmmWinPool_AllPool1903_Offsets(_In_ PVMM_PROCESS pSystemProcess, _Out_ PVMM * heaps as well as the HeapKey and LfhKey. */ _Success_(return) -BOOL VmmWinPool_AllPool1903_1_HeapMgr(PVMMWINPOOL_CTX ctx, PVMMWINPOOL_OFFSETS poff) +BOOL VmmWinPool_AllPool1903_1_HeapMgr(_In_ VMM_HANDLE H, PVMMWINPOOL_CTX ctx, PVMMWINPOOL_OFFSETS poff) { + BOOL f32 = H->vmm.f32; DWORD i, iPoolNode, cPools = 0; QWORD va = 0, oBase = 0, vaBase = 0, vaHeapGlobals = 0; PVMMWINPOOL_HEAP pHeap; @@ -582,18 +586,18 @@ BOOL VmmWinPool_AllPool1903_1_HeapMgr(PVMMWINPOOL_CTX ctx, PVMMWINPOOL_OFFSETS p ObSet_Push_PageAlign(ctx->psPrefetch, poff->vaExPoolState, 8); ObSet_Push_PageAlign(ctx->psPrefetch, poff->vaExPoolState + poff->_EX_POOL_HEAP_MANAGER_STATE.oNumberOfPools, 4); ObSet_Push_PageAlign(ctx->psPrefetch, poff->vaExPoolState + poff->_EX_POOL_HEAP_MANAGER_STATE.oSpecialHeaps, 0x20); - VmmCachePrefetchPages(ctx->pSystemProcess, ctx->psPrefetch, 0); + VmmCachePrefetchPages(H, ctx->pSystemProcess, ctx->psPrefetch, 0); // 1.1 - va heap globals - VmmReadEx(ctx->pSystemProcess, poff->vaExPoolState, (PBYTE)&vaHeapGlobals, ctxVmm->f32 ? 4 : 8, NULL, VMM_FLAG_FORCECACHE_READ); - if(!VMM_KADDR_4_8(vaHeapGlobals)) { goto fail; } + VmmReadEx(H, ctx->pSystemProcess, poff->vaExPoolState, (PBYTE)&vaHeapGlobals, f32 ? 4 : 8, NULL, VMM_FLAG_FORCECACHE_READ); + if(!VMM_KADDR_4_8(f32, vaHeapGlobals)) { goto fail; } // 1.2 - # pools - VmmReadEx(ctx->pSystemProcess, poff->vaExPoolState + poff->_EX_POOL_HEAP_MANAGER_STATE.oNumberOfPools, (PBYTE)&cPools, 4, NULL, VMM_FLAG_FORCECACHE_READ); + VmmReadEx(H, ctx->pSystemProcess, poff->vaExPoolState + poff->_EX_POOL_HEAP_MANAGER_STATE.oNumberOfPools, (PBYTE)&cPools, 4, NULL, VMM_FLAG_FORCECACHE_READ); if(!cPools || cPools > 64) { goto fail; } // 1.3 - special heaps for(i = 0; i < 4; i++) { - VmmReadEx(ctx->pSystemProcess, poff->vaExPoolState + poff->_EX_POOL_HEAP_MANAGER_STATE.oSpecialHeaps, ctx->pb, 0x20, NULL, VMM_FLAG_FORCECACHE_READ); - va = ctxVmm->f32 ? *(PDWORD)(ctx->pb + i * 4ULL) : *(PQWORD)(ctx->pb + i * 8ULL); - if(VMM_KADDR_PAGE(va) && (pHeap = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMWINPOOL_HEAP)))) { + VmmReadEx(H, ctx->pSystemProcess, poff->vaExPoolState + poff->_EX_POOL_HEAP_MANAGER_STATE.oSpecialHeaps, ctx->pb, 0x20, NULL, VMM_FLAG_FORCECACHE_READ); + va = f32 ? *(PDWORD)(ctx->pb + i * 4ULL) : *(PQWORD)(ctx->pb + i * 8ULL); + if(VMM_KADDR_PAGE(f32, va) && (pHeap = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMWINPOOL_HEAP)))) { pHeap->va = va; pHeap->fSpecial = TRUE; pHeap->iPoolNode = (DWORD)-1; @@ -610,18 +614,18 @@ BOOL VmmWinPool_AllPool1903_1_HeapMgr(PVMMWINPOOL_CTX ctx, PVMMWINPOOL_OFFSETS p ObSet_Clear(ctx->psPrefetch); ObSet_Push_PageAlign(ctx->psPrefetch, vaHeapGlobals, 0x10); ObSet_Push_PageAlign(ctx->psPrefetch, poff->vaExPoolState + poff->_EX_POOL_HEAP_MANAGER_STATE.oPoolNode, cPools * poff->_EX_HEAP_POOL_NODE.cb); - VmmCachePrefetchPages(ctx->pSystemProcess, ctx->psPrefetch, 0); + VmmCachePrefetchPages(H, ctx->pSystemProcess, ctx->psPrefetch, 0); // 2.1 - heap globals - if(!VmmRead2(ctx->pSystemProcess, vaHeapGlobals, ctx->pb, 0x10, VMM_FLAG_FORCECACHE_READ)) { goto fail; } - ctx->qwKeyHeap = VMM_PTR_OFFSET_DUAL(ctxVmm->f32, ctx->pb, 0, 0); - ctx->qwKeyLfh = VMM_PTR_OFFSET_DUAL(ctxVmm->f32, ctx->pb, 4, 8); + if(!VmmRead2(H, ctx->pSystemProcess, vaHeapGlobals, ctx->pb, 0x10, VMM_FLAG_FORCECACHE_READ)) { goto fail; } + ctx->qwKeyHeap = VMM_PTR_OFFSET_DUAL(f32, ctx->pb, 0, 0); + ctx->qwKeyLfh = VMM_PTR_OFFSET_DUAL(f32, ctx->pb, 4, 8); // 2.2 - pool heaps vaBase = poff->vaExPoolState + poff->_EX_POOL_HEAP_MANAGER_STATE.oPoolNode; - VmmReadEx(ctx->pSystemProcess, vaBase, ctx->pb, cPools * poff->_EX_HEAP_POOL_NODE.cb, NULL, VMM_FLAG_FORCECACHE_READ); + VmmReadEx(H, ctx->pSystemProcess, vaBase, ctx->pb, cPools * poff->_EX_HEAP_POOL_NODE.cb, NULL, VMM_FLAG_FORCECACHE_READ); for(iPoolNode = 0; iPoolNode < cPools; iPoolNode++) { for(i = 0; i < 4; i++) { - va = ctxVmm->f32 ? *(PDWORD)(ctx->pb + oBase + i * 4ULL) : *(PQWORD)(ctx->pb + oBase + i * 8ULL); - if(VMM_KADDR_PAGE(va) && (pHeap = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMWINPOOL_HEAP)))) { + va = f32 ? *(PDWORD)(ctx->pb + oBase + i * 4ULL) : *(PQWORD)(ctx->pb + oBase + i * 8ULL); + if(VMM_KADDR_PAGE(f32, va) && (pHeap = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMWINPOOL_HEAP)))) { pHeap->va = va; pHeap->fSpecial = FALSE; pHeap->iPoolNode = iPoolNode; @@ -646,8 +650,9 @@ fail: * TODO: PARSE LargeAllocMetadata */ _Success_(return) -BOOL VmmWinPool_AllPool1903_2_HeapFillSegmentHeap(PVMMWINPOOL_CTX ctx) +BOOL VmmWinPool_AllPool1903_2_HeapFillSegmentHeap(_In_ VMM_HANDLE H, PVMMWINPOOL_CTX ctx) { + BOOL f32 = H->vmm.f32; PVMMWINPOOL_HEAP peHeap; PVMMWINPOOL_HEAP_PAGE_SEGMENT pePgSeg; POB_SET psvaObPrefetch = NULL; @@ -657,20 +662,20 @@ BOOL VmmWinPool_AllPool1903_2_HeapFillSegmentHeap(PVMMWINPOOL_CTX ctx) // 1: prefetch if(!(cSegHeap = ObMap_Size(ctx->pmHeap))) { return FALSE; } if(!(psvaObPrefetch = ObMap_FilterSet(ctx->pmHeap, ObMap_FilterSet_FilterAllKey))) { return FALSE; } - VmmCachePrefetchPages3(ctx->pSystemProcess, psvaObPrefetch, ctx->po->_SEGMENT_HEAP.cb, 0); + VmmCachePrefetchPages3(H, ctx->pSystemProcess, psvaObPrefetch, ctx->po->_SEGMENT_HEAP.cb, 0); Ob_DECREF_NULL(&psvaObPrefetch); // 2: iterate nt!_SEGMENT_HEAP -> FETCH ADDR nt!_HEAP_PAGE_SEGMENT for(iSegHeap = 0; iSegHeap < cSegHeap; iSegHeap++) { peHeap = ObMap_GetByIndex(ctx->pmHeap, iSegHeap); - if(!VmmRead2(ctx->pSystemProcess, peHeap->va, ctx->pb, ctx->po->_SEGMENT_HEAP.cb, VMMDLL_FLAG_FORCECACHE_READ)) { continue; } - if(*(PDWORD)(ctx->pb + (ctxVmm->f32 ? 8 : 16)) != 0xddeeddee) { continue; } // _SEGMENT_HEAP.Signature == 0xddeeddee + if(!VmmRead2(H, ctx->pSystemProcess, peHeap->va, ctx->pb, ctx->po->_SEGMENT_HEAP.cb, VMMDLL_FLAG_FORCECACHE_READ)) { continue; } + if(*(PDWORD)(ctx->pb + (f32 ? 8 : 16)) != 0xddeeddee) { continue; } // _SEGMENT_HEAP.Signature == 0xddeeddee for(iSegHeapCtx = 0; iSegHeapCtx < 2; iSegHeapCtx++) { oBase = ctx->po->_SEGMENT_HEAP.oSegContexts + iSegHeapCtx * ctx->po->_HEAP_SEG_CONTEXT.cb; ucUnitShift = *(PUCHAR)(ctx->pb + oBase + ctx->po->_HEAP_SEG_CONTEXT.oUnitShift); ucFirstDescriptorIndex = *(PUCHAR)(ctx->pb + oBase + ctx->po->_HEAP_SEG_CONTEXT.oFirstDescriptorIndex); for(i = 0; i < 2; i++) { - va = VMM_PTR_OFFSET_DUAL(ctxVmm->f32, ctx->pb + oBase + ctx->po->_HEAP_SEG_CONTEXT.oSegmentListHead, i * 4ULL, i * 8ULL); - if(VMM_KADDR_PAGE(va) && !ObMap_ExistsKey(ctx->pmPgSeg, va) && (pePgSeg = LocalAlloc(0, sizeof(VMMWINPOOL_HEAP_PAGE_SEGMENT)))) { + va = VMM_PTR_OFFSET_DUAL(f32, ctx->pb + oBase + ctx->po->_HEAP_SEG_CONTEXT.oSegmentListHead, i * 4ULL, i * 8ULL); + if(VMM_KADDR_PAGE(f32, va) && !ObMap_ExistsKey(ctx->pmPgSeg, va) && (pePgSeg = LocalAlloc(0, sizeof(VMMWINPOOL_HEAP_PAGE_SEGMENT)))) { pePgSeg->va = va; pePgSeg->pHeap = peHeap; pePgSeg->ucUnitShift = ucUnitShift; @@ -689,7 +694,7 @@ BOOL VmmWinPool_AllPool1903_2_HeapFillSegmentHeap(PVMMWINPOOL_CTX ctx) * next following likely addresses in FLink, BLink list - segments are usually * located 1MB apart. */ -VOID VmmWinPool_AllPool1903_3_HeapFillPageSegment_Prefetch(_In_ PVMMWINPOOL_CTX ctx, _In_ POB_SET psva) +VOID VmmWinPool_AllPool1903_3_HeapFillPageSegment_Prefetch(_In_ VMM_HANDLE H, _In_ PVMMWINPOOL_CTX ctx, _In_ POB_SET psva) { QWORD va; DWORD i, j, iMax, cb; @@ -704,30 +709,32 @@ VOID VmmWinPool_AllPool1903_3_HeapFillPageSegment_Prefetch(_In_ PVMMWINPOOL_CTX ObSet_Push_PageAlign(ctx->psPrefetch, va - j * 0x00100000ULL, cb); } } - VmmCachePrefetchPages(ctx->pSystemProcess, ctx->psPrefetch, 0); + VmmCachePrefetchPages(H, ctx->pSystemProcess, ctx->psPrefetch, 0); } /* * Process a single segment candidate. +* -- H * -- ctx * -- psvaNext * -- va * -- return = TRUE if processed, FALSE if memory read fail - i.e. read retry after prefetch is recommended */ -BOOL VmmWinPool_AllPool1903_3_HeapFillPageSegment_ProcessSingleCandidate(_In_ PVMMWINPOOL_CTX ctx, _In_ POB_SET psvaNext, _In_ QWORD va) +BOOL VmmWinPool_AllPool1903_3_HeapFillPageSegment_ProcessSingleCandidate(_In_ VMM_HANDLE H, _In_ PVMMWINPOOL_CTX ctx, _In_ POB_SET psvaNext, _In_ QWORD va) { + BOOL f32 = H->vmm.f32; QWORD i, vaNext, vaSignature; PVMMWINPOOL_HEAP_PAGE_SEGMENT pe, peNext; if(!(pe = ObMap_GetByKey(ctx->pmPgSeg, va))) { return TRUE; } - if(!VmmRead2(ctx->pSystemProcess, pe->va, pe->pb, ctx->po->_HEAP_PAGE_SEGMENT.cb, VMMDLL_FLAG_FORCECACHE_READ)) { return FALSE; } + if(!VmmRead2(H, ctx->pSystemProcess, pe->va, pe->pb, ctx->po->_HEAP_PAGE_SEGMENT.cb, VMMDLL_FLAG_FORCECACHE_READ)) { return FALSE; } // signature check - vaSignature = VMM_PTR_OFFSET_DUAL(ctxVmm->f32, pe->pb, 8, 16) ^ ctx->qwKeyHeap ^ va ^ 0xa2e64eada2e64ead; - if(!VMM_KADDR_4_8(vaSignature)) { return TRUE; } + vaSignature = VMM_PTR_OFFSET_DUAL(f32, pe->pb, 8, 16) ^ ctx->qwKeyHeap ^ va ^ 0xa2e64eada2e64ead; + if(!VMM_KADDR_4_8(f32, vaSignature)) { return TRUE; } pe->fValid = TRUE; // flink/blink for(i = 0; i < 2; i++) { - vaNext = VMM_PTR_OFFSET_DUAL(ctxVmm->f32, pe->pb, i * 4, i * 8); - if(VMM_KADDR_PAGE(vaNext) && !ObMap_ExistsKey(ctx->pmPgSeg, vaNext) && (peNext = LocalAlloc(0, sizeof(VMMWINPOOL_HEAP_PAGE_SEGMENT)))) { + vaNext = VMM_PTR_OFFSET_DUAL(f32, pe->pb, i * 4, i * 8); + if(VMM_KADDR_PAGE(f32, vaNext) && !ObMap_ExistsKey(ctx->pmPgSeg, vaNext) && (peNext = LocalAlloc(0, sizeof(VMMWINPOOL_HEAP_PAGE_SEGMENT)))) { peNext->va = vaNext; peNext->pHeap = pe->pHeap; peNext->ucUnitShift = pe->ucUnitShift; @@ -743,24 +750,24 @@ BOOL VmmWinPool_AllPool1903_3_HeapFillPageSegment_ProcessSingleCandidate(_In_ PV /* * fetch and parse [nt!_HEAP_PAGE_SEGMENT] */ -VOID VmmWinPool_AllPool1903_3_HeapFillPageSegment(_In_ PVMMWINPOOL_CTX ctx) +VOID VmmWinPool_AllPool1903_3_HeapFillPageSegment(_In_ VMM_HANDLE H, _In_ PVMMWINPOOL_CTX ctx) { QWORD va; POB_SET psvaObTry1 = NULL, psvaObTry2 = NULL; - if(!(psvaObTry2 = ObSet_New())) { goto fail; } + if(!(psvaObTry2 = ObSet_New(H))) { goto fail; } if(!(psvaObTry1 = ObMap_FilterSet(ctx->pmPgSeg, ObMap_FilterSet_FilterAllKey))) { goto fail; } while(TRUE) { // try1 items while((va = ObSet_Pop(psvaObTry1))) { - if(!VmmWinPool_AllPool1903_3_HeapFillPageSegment_ProcessSingleCandidate(ctx, psvaObTry1, va)) { + if(!VmmWinPool_AllPool1903_3_HeapFillPageSegment_ProcessSingleCandidate(H, ctx, psvaObTry1, va)) { ObSet_Push(psvaObTry2, va); } } // prefetch & try2 items if(!ObSet_Size(psvaObTry2)) { break; } - VmmWinPool_AllPool1903_3_HeapFillPageSegment_Prefetch(ctx, psvaObTry2); + VmmWinPool_AllPool1903_3_HeapFillPageSegment_Prefetch(H, ctx, psvaObTry2); while((va = ObSet_Pop(psvaObTry2))) { - VmmWinPool_AllPool1903_3_HeapFillPageSegment_ProcessSingleCandidate(ctx, psvaObTry1, va); + VmmWinPool_AllPool1903_3_HeapFillPageSegment_ProcessSingleCandidate(H, ctx, psvaObTry1, va); } } fail: @@ -773,7 +780,7 @@ fail: * maps and return its unit size. * TODO: add support for LargePool. */ -UCHAR VmmWinPool_AllPool1903_4_HeapPageRangeDescriptor_SingleDescriptor(_In_ PVMMWINPOOL_CTX ctx, _In_ PVMMWINPOOL_HEAP_PAGE_SEGMENT pPgSeg, _In_ DWORD iRD) +UCHAR VmmWinPool_AllPool1903_4_HeapPageRangeDescriptor_SingleDescriptor(_In_ VMM_HANDLE H, _In_ PVMMWINPOOL_CTX ctx, _In_ PVMMWINPOOL_HEAP_PAGE_SEGMENT pPgSeg, _In_ DWORD iRD) { QWORD vaRange; UCHAR ucUnitSize, ucRangeFlags; @@ -782,7 +789,7 @@ UCHAR VmmWinPool_AllPool1903_4_HeapPageRangeDescriptor_SingleDescriptor(_In_ PVM oRD = ctx->po->_HEAP_PAGE_RANGE_DESCRIPTOR.cb * iRD; ucUnitSize = *(PUCHAR)(pPgSeg->pb + oRD + ctx->po->_HEAP_PAGE_RANGE_DESCRIPTOR.oUnitSize); ucRangeFlags = *(PUCHAR)(pPgSeg->pb + oRD + ctx->po->_HEAP_PAGE_RANGE_DESCRIPTOR.oRangeFlags); - if(ctxVmm->f32) { ucRangeFlags &= 0x1f; } + if(H->vmm.f32) { ucRangeFlags &= 0x1f; } vaRange = pPgSeg->va + iRD * (1ULL << pPgSeg->ucUnitShift); cbRange = ucUnitSize * (1ULL << pPgSeg->ucUnitShift); if(ucUnitSize == 0) { return 1; } @@ -815,7 +822,7 @@ UCHAR VmmWinPool_AllPool1903_4_HeapPageRangeDescriptor_SingleDescriptor(_In_ PVM * TODO: add support for LargePool. */ _Success_(return) -BOOL VmmWinPool_AllPool1903_4_HeapPageRangeDescriptor(PVMMWINPOOL_CTX ctx) +BOOL VmmWinPool_AllPool1903_4_HeapPageRangeDescriptor(_In_ VMM_HANDLE H, PVMMWINPOOL_CTX ctx) { DWORD iPgSeg, cPgSegMax, iRD; PVMMWINPOOL_HEAP_PAGE_SEGMENT pePgSeg; @@ -825,7 +832,7 @@ BOOL VmmWinPool_AllPool1903_4_HeapPageRangeDescriptor(PVMMWINPOOL_CTX ctx) if(!pePgSeg || !pePgSeg->fValid) { continue; } iRD = pePgSeg->ucFirstDescriptorIndex; while(iRD < 256) { - iRD += VmmWinPool_AllPool1903_4_HeapPageRangeDescriptor_SingleDescriptor(ctx, pePgSeg, iRD); + iRD += VmmWinPool_AllPool1903_4_HeapPageRangeDescriptor_SingleDescriptor(H, ctx, pePgSeg, iRD); } } return ObMap_Size(ctx->pmLfh) || ObMap_Size(ctx->pmVs); @@ -835,12 +842,14 @@ BOOL VmmWinPool_AllPool1903_4_HeapPageRangeDescriptor(PVMMWINPOOL_CTX ctx) * Parse the vs heap segment - [nt!_HEAP_VS_SUBSEGMENT] // [nt!_HEAP_VS_CHUNK_HEADER] */ VOID VmmWinPool_AllPool1903_5_VS_DoWork( + _In_ VMM_HANDLE H, _In_ PVMMWINPOOL_CTX ctx, _In_ QWORD va, _In_ PBYTE pb, _In_ DWORD cb, _In_ PVMMWINPOOL_HEAP_PAGE_SEGMENT pPgSeg ) { + BOOL f32 = H->vmm.f32; DWORD cbPoolHdr, oVsChunkHdr, cbChunkSize, oBlock, cbBlock, cbAdjust; QWORD vaBlock, vaChunkHeader; WORD wSize, wSignature; @@ -848,7 +857,7 @@ VOID VmmWinPool_AllPool1903_5_VS_DoWork( P_HEAP_VS_CHUNK_HEADER_SIZE32 pChunkSize32; P_HEAP_VS_CHUNK_HEADER_SIZE64 pChunkSize64; // 32/64-bit dependent offsets: - if(ctxVmm->f32) { + if(f32) { cbPoolHdr = 8; oVsChunkHdr = 0x18; wSize = *(PWORD)(ctx->pb + 0x14); @@ -866,7 +875,7 @@ VOID VmmWinPool_AllPool1903_5_VS_DoWork( // loop over pool entries while(oVsChunkHdr + 0x30 < cb) { vaChunkHeader = va + oVsChunkHdr; - if(ctxVmm->f32) { + if(f32) { pChunkSize32 = (P_HEAP_VS_CHUNK_HEADER_SIZE32)(pb + oVsChunkHdr); pChunkSize32->HeaderBits = (DWORD)(pChunkSize32->HeaderBits ^ vaChunkHeader ^ ctx->qwKeyHeap); fAlloc = (pChunkSize32->Allocated & 1) ? TRUE : FALSE; @@ -896,7 +905,7 @@ VOID VmmWinPool_AllPool1903_5_VS_DoWork( // nb! allocation (excl. chunkhdr) does not cross page boundary if((cbBlock < ctx->po->cbBigPoolThreshold) || ((vaBlock & 0xfff) < ctx->po->cbBigPoolThreshold)) { // Larger [0xff0+] Vs allocations are also visible in big pool table - so skip these duplicates! - VmmWinPool_AllPool_PushItem(&ctx->pVs, pPgSeg->pHeap->tpPool, VMM_MAP_POOL_TPSS_VS, vaBlock, pb + oBlock, cbBlock, TRUE); + VmmWinPool_AllPool_PushItem(H, &ctx->pVs, pPgSeg->pHeap->tpPool, VMM_MAP_POOL_TPSS_VS, vaBlock, pb + oBlock, cbBlock, TRUE); } } } @@ -908,6 +917,7 @@ VOID VmmWinPool_AllPool1903_5_VS_DoWork( * Parse the low fragmentation heap segment - [nt!_HEAP_LFH_SUBSEGMENT] */ VOID VmmWinPool_AllPool1903_5_LFH_DoWork( + _In_ VMM_HANDLE H, _In_ PVMMWINPOOL_CTX ctx, _In_ QWORD va, _In_ PBYTE pb, @@ -930,7 +940,7 @@ VOID VmmWinPool_AllPool1903_5_LFH_DoWork( oBlock = oFirstBlock + iBlock * cbBlockSize; if((oBlock & 0xfff) + cbBlockSize > 0x1000) { continue; } // block do not cross page boundaries ucBits = pbBitmap[iBlock >> 2] >> ((iBlock & 0x3) << 1); - VmmWinPool_AllPool_PushItem(&ctx->pLfh, pPgSeg->pHeap->tpPool, VMM_MAP_POOL_TPSS_LFH, va + oBlock, pb + oBlock, cbBlockSize, ((ucBits & 3) == 1)); + VmmWinPool_AllPool_PushItem(H, &ctx->pLfh, pPgSeg->pHeap->tpPool, VMM_MAP_POOL_TPSS_LFH, va + oBlock, pb + oBlock, cbBlockSize, ((ucBits & 3) == 1)); } } @@ -939,7 +949,7 @@ VOID VmmWinPool_AllPool1903_5_LFH_DoWork( * This should be done in a fairly efficient by fetching around 8MB LFH/VS data * per read call to the underlying system. */ -VOID VmmWinPool_AllPool1903_5_LFHVS(_In_ PVMMWINPOOL_CTX ctx, _In_ BOOL fVS) +VOID VmmWinPool_AllPool1903_5_LFHVS(_In_ VMM_HANDLE H, _In_ PVMMWINPOOL_CTX ctx, _In_ BOOL fVS) { DWORD i, iSS, iPrefetchBase = 0, cMax; QWORD cbPrefetch = 0; @@ -949,22 +959,22 @@ VOID VmmWinPool_AllPool1903_5_LFHVS(_In_ PVMMWINPOOL_CTX ctx, _In_ BOOL fVS) PVMMWINPOOL_HEAP_LFH_VS pe; pbBuffer = fVS ? ctx->pb : ctx->pb + VMMWINPOOL_PREFETCH_BUFFER_SIZE; pmVsLfh = fVS ? ctx->pmVs : ctx->pmLfh; - if(!(psObPrefetch = ObSet_New())) { return; } + if(!(psObPrefetch = ObSet_New(H))) { return; } cMax = ObMap_Size(pmVsLfh); for(iSS = 0; iSS < cMax; iSS++) { pe = ObMap_GetByIndex(pmVsLfh, iSS); ObSet_Push_PageAlign(psObPrefetch, pe->va, pe->cb); cbPrefetch += pe->cb; if((cbPrefetch > VMMWINPOOL_PREFETCH_BUFFER_SIZE) || (iSS + 1 == cMax)) { - VmmCachePrefetchPages(ctx->pSystemProcess, psObPrefetch, 0); + VmmCachePrefetchPages(H, ctx->pSystemProcess, psObPrefetch, 0); for(i = iPrefetchBase; i <= iSS; i++) { pe = ObMap_GetByIndex(pmVsLfh, i); if(pe->cb > VMMWINPOOL_PREFETCH_BUFFER_SIZE) { continue; } - VmmReadEx(ctx->pSystemProcess, pe->va, pbBuffer, pe->cb, NULL, VMM_FLAG_FORCECACHE_READ | VMM_FLAG_ZEROPAD_ON_FAIL); + VmmReadEx(H, ctx->pSystemProcess, pe->va, pbBuffer, pe->cb, NULL, VMM_FLAG_FORCECACHE_READ | VMM_FLAG_ZEROPAD_ON_FAIL); if(fVS) { - VmmWinPool_AllPool1903_5_VS_DoWork(ctx, pe->va, pbBuffer, pe->cb, pe->pPgSeg); + VmmWinPool_AllPool1903_5_VS_DoWork(H, ctx, pe->va, pbBuffer, pe->cb, pe->pPgSeg); } else { - VmmWinPool_AllPool1903_5_LFH_DoWork(ctx, pe->va, pbBuffer, pe->cb, pe->pPgSeg); + VmmWinPool_AllPool1903_5_LFH_DoWork(H, ctx, pe->va, pbBuffer, pe->cb, pe->pPgSeg); } } ObSet_Clear(psObPrefetch); @@ -975,27 +985,28 @@ VOID VmmWinPool_AllPool1903_5_LFHVS(_In_ PVMMWINPOOL_CTX ctx, _In_ BOOL fVS) Ob_DECREF(psObPrefetch); } -DWORD WINAPI VmmWinPool_AllPool1903_5_LFH(_In_ PVOID lpThreadParam) +DWORD WINAPI VmmWinPool_AllPool1903_5_LFH(_In_ VMM_HANDLE H, _In_ PVOID lpThreadParam) { - VmmWinPool_AllPool1903_5_LFHVS(lpThreadParam, FALSE); + VmmWinPool_AllPool1903_5_LFHVS(H, lpThreadParam, FALSE); return 0; } -DWORD WINAPI VmmWinPool_AllPool1903_5_VS(_In_ PVOID lpThreadParam) +DWORD WINAPI VmmWinPool_AllPool1903_5_VS(_In_ VMM_HANDLE H, _In_ PVOID lpThreadParam) { - VmmWinPool_AllPool1903_5_LFHVS(lpThreadParam, TRUE); + VmmWinPool_AllPool1903_5_LFHVS(H, lpThreadParam, TRUE); return 0; } /* * Create a pool map containing all pool entries on Windows 10 1809 and above. * CALLER DECREF: return +* -- H * -- pSystemProcess * -- pPoolBig * -- return */ _Success_(return != NULL) -PVMMOB_MAP_POOL VmmWinPool_AllPool1903_DoWork(_In_ PVMM_PROCESS pSystemProcess, _In_ PVMMOB_MAP_POOL pPoolBig) +PVMMOB_MAP_POOL VmmWinPool_AllPool1903_DoWork(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ PVMMOB_MAP_POOL pPoolBig) { PVMMOB_MAP_POOL pObPoolAll = NULL; PVMMWINPOOL_CTX ctx = NULL; @@ -1003,25 +1014,25 @@ PVMMOB_MAP_POOL VmmWinPool_AllPool1903_DoWork(_In_ PVMM_PROCESS pSystemProcess, PVMMWINPOOL_CTX_POOLSTORE pStore; // 1: alloc & init if(!(ctx = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMWINPOOL_CTX)))) { goto fail; } - if(!(ctx->pmHeap = ObMap_New(OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } - if(!(ctx->pmPgSeg = ObMap_New(OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } - if(!(ctx->pmLfh = ObMap_New(OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } - if(!(ctx->pmVs = ObMap_New(OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } - if(!(ctx->psPrefetch = ObSet_New())) { goto fail; } + if(!(ctx->pmHeap = ObMap_New(H, OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } + if(!(ctx->pmPgSeg = ObMap_New(H, OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } + if(!(ctx->pmLfh = ObMap_New(H, OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } + if(!(ctx->pmVs = ObMap_New(H, OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } + if(!(ctx->psPrefetch = ObSet_New(H))) { goto fail; } if(!(ctx->pVs = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMWINPOOL_CTX_POOLSTORE)))) { goto fail; } if(!(ctx->pLfh = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMWINPOOL_CTX_POOLSTORE)))) { goto fail; } ctx->pSystemProcess = pSystemProcess; ctx->po = &off; // 2: do work in different stages - if(!VmmWinPool_AllPool1903_Offsets(pSystemProcess, &off)) { goto fail; } - if(!VmmWinPool_AllPool1903_1_HeapMgr(ctx, &off)) { goto fail; } - if(!VmmWinPool_AllPool1903_2_HeapFillSegmentHeap(ctx)) { goto fail; } - VmmWinPool_AllPool1903_3_HeapFillPageSegment(ctx); - if(!VmmWinPool_AllPool1903_4_HeapPageRangeDescriptor(ctx)) { goto fail; } + if(!VmmWinPool_AllPool1903_Offsets(H, pSystemProcess, &off)) { goto fail; } + if(!VmmWinPool_AllPool1903_1_HeapMgr(H, ctx, &off)) { goto fail; } + if(!VmmWinPool_AllPool1903_2_HeapFillSegmentHeap(H, ctx)) { goto fail; } + VmmWinPool_AllPool1903_3_HeapFillPageSegment(H, ctx); + if(!VmmWinPool_AllPool1903_4_HeapPageRangeDescriptor(H, ctx)) { goto fail; } // 3: fetch LFH and VS heap allocations in two separate threads - VmmWorkWaitMultiple(ctx, 2, VmmWinPool_AllPool1903_5_LFH, VmmWinPool_AllPool1903_5_VS); + VmmWorkWaitMultiple_Void(H, ctx, 2, VmmWinPool_AllPool1903_5_LFH, VmmWinPool_AllPool1903_5_VS); // 4: create pool map given the lfh, vs and big pool entries - pObPoolAll = VmmWinPool_AllPool_CreateMap(pPoolBig, (PVMMWINPOOL_CTX_POOLSTORE[2]){ ctx->pLfh, ctx->pVs }, 2); + pObPoolAll = VmmWinPool_AllPool_CreateMap(H, pPoolBig, (PVMMWINPOOL_CTX_POOLSTORE[2]){ ctx->pLfh, ctx->pVs }, 2); fail: if(ctx) { while(ctx->pVs) { @@ -1064,7 +1075,7 @@ typedef struct tdVMMWINPOOL7_CTX { } VMMWINPOOL7_CTX, *PVMMWINPOOL7_CTX; _Success_(return) -BOOL VmmWinPool_AllPool7_RangeInit(_In_ PVMMWINPOOL7_CTX ctx) +BOOL VmmWinPool_AllPool7_RangeInit(_In_ VMM_HANDLE H, _In_ PVMMWINPOOL7_CTX ctx) { BOOL fResult = FALSE; QWORD va, vaPteTop = 0; @@ -1074,14 +1085,14 @@ BOOL VmmWinPool_AllPool7_RangeInit(_In_ PVMMWINPOOL7_CTX ctx) POB_SET psvaOb = NULL; PVMMOB_MAP_HANDLE pObHnd = NULL; PVMMOB_MAP_OBJECT pObObj = NULL; - if(!(psvaOb = ObSet_New())) { goto fail; } + if(!(psvaOb = ObSet_New(H))) { goto fail; } // 1: fetch sorted handle & object addresses (which are residing inside the pool): - if(VmmMap_GetHandle(ctx->pSystemProcess, &pObHnd, FALSE)) { + if(VmmMap_GetHandle(H, ctx->pSystemProcess, &pObHnd, FALSE)) { for(i = 0; i < pObHnd->cMap; i++) { ObSet_Push(psvaOb, pObHnd->pMap[i].vaObject & ~0x1fffff); // 2MB align } } - if(VmmMap_GetObject(&pObObj)) { + if(VmmMap_GetObject(H, &pObObj)) { for(i = 0; i < pObObj->cMap; i++) { ObSet_Push(psvaOb, pObObj->pMap[i].va & ~0x1fffff); // 2MB align } @@ -1107,9 +1118,9 @@ fail: return fResult; } -VOID VmmWinPool_AllPool7_ProcessSingleRange(_In_ PVMMWINPOOL7_CTX ctx, _In_ PVMMWINPOOL7_RANGE pe, _In_ PBYTE pb) +VOID VmmWinPool_AllPool7_ProcessSingleRange(_In_ VMM_HANDLE H, _In_ PVMMWINPOOL7_CTX ctx, _In_ PVMMWINPOOL7_RANGE pe, _In_ PBYTE pb) { - BOOL f, fTagBad, fPrev = FALSE, f32 = ctxVmm->f32; + BOOL f, fTagBad, fPrev = FALSE, f32 = H->vmm.f32; CHAR ch; DWORD cbBlock = f32 ? 8 : 16; DWORD i, o = 0, dwPrevBlockSize = 0; @@ -1161,6 +1172,7 @@ VOID VmmWinPool_AllPool7_ProcessSingleRange(_In_ PVMMWINPOOL7_CTX ctx, _In_ PVMM } // add pool entry! VmmWinPool_AllPool_PushItem( + H, &ctx->pStore, pe->tp, VMM_MAP_POOL_TPSS_NA, @@ -1184,25 +1196,25 @@ next: * Process ranges within ctx->pmRange in a fairly efficient way. */ _Success_(return) -BOOL VmmWinPool_AllPool7_ProcessRanges(_In_ PVMMWINPOOL7_CTX ctx) +BOOL VmmWinPool_AllPool7_ProcessRanges(_In_ VMM_HANDLE H, _In_ PVMMWINPOOL7_CTX ctx) { DWORD iRP, iR, cR, iPrefetchBase = 0; QWORD cbPrefetch = 0; PVMMWINPOOL7_RANGE pe; POB_SET psObPrefetch = NULL; - if(!(psObPrefetch = ObSet_New())) { return FALSE; } + if(!(psObPrefetch = ObSet_New(H))) { return FALSE; } cR = ObMap_Size(ctx->pmRange); for(iRP = 0; iRP < cR; iRP++) { pe = ObMap_GetByIndex(ctx->pmRange, iRP); ObSet_Push_PageAlign(psObPrefetch, pe->va, pe->cb); cbPrefetch += pe->cb; if((cbPrefetch > VMMWINPOOL_PREFETCH_BUFFER_SIZE) || (iRP + 1 == cR)) { - VmmCachePrefetchPages(ctx->pSystemProcess, psObPrefetch, 0); + VmmCachePrefetchPages(H, ctx->pSystemProcess, psObPrefetch, 0); for(iR = iPrefetchBase; iR <= iRP; iR++) { pe = ObMap_GetByIndex(ctx->pmRange, iR); if(pe->cb > 0x00200000) { continue; } - VmmReadEx(ctx->pSystemProcess, pe->va, ctx->pbBuffer2M, pe->cb, NULL, VMM_FLAG_FORCECACHE_READ | VMM_FLAG_ZEROPAD_ON_FAIL); - VmmWinPool_AllPool7_ProcessSingleRange(ctx, pe, ctx->pbBuffer2M); + VmmReadEx(H, ctx->pSystemProcess, pe->va, ctx->pbBuffer2M, pe->cb, NULL, VMM_FLAG_FORCECACHE_READ | VMM_FLAG_ZEROPAD_ON_FAIL); + VmmWinPool_AllPool7_ProcessSingleRange(H, ctx, pe, ctx->pbBuffer2M); } ObSet_Clear(psObPrefetch); iPrefetchBase = iRP + 1; @@ -1216,25 +1228,26 @@ BOOL VmmWinPool_AllPool7_ProcessRanges(_In_ PVMMWINPOOL7_CTX ctx) /* * Create a pool map containing all pool entries on Windows Vista to Windows10_1809 * CALLER DECREF: return +* -- H * -- pSystemProcess * -- pPoolBig * -- return */ _Success_(return != NULL) -PVMMOB_MAP_POOL VmmWinPool_AllPool7_DoWork(_In_ PVMM_PROCESS pSystemProcess, _In_ PVMMOB_MAP_POOL pPoolBig) +PVMMOB_MAP_POOL VmmWinPool_AllPool7_DoWork(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ PVMMOB_MAP_POOL pPoolBig) { PVMMOB_MAP_POOL pObPoolAll = NULL; PVMMWINPOOL7_CTX ctx = NULL; PVMMWINPOOL_CTX_POOLSTORE pStore; // 1: alloc & init if(!(ctx = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMWINPOOL7_CTX)))) { goto fail; } - if(!(ctx->pmRange = ObMap_New(OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } + if(!(ctx->pmRange = ObMap_New(H, OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } if(!(ctx->pStore = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMWINPOOL_CTX_POOLSTORE)))) { goto fail; } ctx->pSystemProcess = pSystemProcess; //if(!VmmWinPool_AllPool7_Offset(ctx)) { goto fail; } - if(!VmmWinPool_AllPool7_RangeInit(ctx)) { goto fail; } - if(!VmmWinPool_AllPool7_ProcessRanges(ctx)) { goto fail; } - pObPoolAll = VmmWinPool_AllPool_CreateMap(pPoolBig, &ctx->pStore, 1); + if(!VmmWinPool_AllPool7_RangeInit(H, ctx)) { goto fail; } + if(!VmmWinPool_AllPool7_ProcessRanges(H, ctx)) { goto fail; } + pObPoolAll = VmmWinPool_AllPool_CreateMap(H, pPoolBig, &ctx->pStore, 1); fail: if(ctx) { while(ctx->pStore) { @@ -1257,53 +1270,55 @@ fail: /* * Create a pool map containing all pool entries. * CALLER DECREF: return +* -- H * -- pSystemProcess * -- pPoolBig * -- return */ _Success_(return != NULL) -PVMMOB_MAP_POOL VmmWinPool_Initialize_AllPool_DoWork(_In_ PVMM_PROCESS pSystemProcess, _In_ PVMMOB_MAP_POOL pPoolBig) +PVMMOB_MAP_POOL VmmWinPool_Initialize_AllPool_DoWork(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess, _In_ PVMMOB_MAP_POOL pPoolBig) { - return (ctxVmm->kernel.dwVersionBuild >= 18362) ? - VmmWinPool_AllPool1903_DoWork(pSystemProcess, pPoolBig) : // 1903+ - VmmWinPool_AllPool7_DoWork(pSystemProcess, pPoolBig); // XP->1809 + return (H->vmm.kernel.dwVersionBuild >= 18362) ? + VmmWinPool_AllPool1903_DoWork(H, pSystemProcess, pPoolBig) : // 1903+ + VmmWinPool_AllPool7_DoWork(H, pSystemProcess, pPoolBig); // XP->1809 } /* * Create a pool map and assign to the global vmm context upon success. * CALLER DECREF: return +* -- H * -- fAll = TRUE: retrieve all pools; FALSE: retrieve big page pool only. * -- return */ -PVMMOB_MAP_POOL VmmWinPool_Initialize(_In_ BOOL fAll) +PVMMOB_MAP_POOL VmmWinPool_Initialize(_In_ VMM_HANDLE H, _In_ BOOL fAll) { PVMM_PROCESS pObSystemProcess = NULL; PVMMOB_MAP_POOL pObPoolBig = NULL, pObPoolAll = NULL; - if(fAll && (pObPoolAll = ObContainer_GetOb(ctxVmm->pObCMapPoolAll))) { return pObPoolAll; } - if((pObPoolBig = ObContainer_GetOb(ctxVmm->pObCMapPoolBig)) && !fAll) { return pObPoolBig; } + if(fAll && (pObPoolAll = ObContainer_GetOb(H->vmm.pObCMapPoolAll))) { return pObPoolAll; } + if((pObPoolBig = ObContainer_GetOb(H->vmm.pObCMapPoolBig)) && !fAll) { return pObPoolBig; } // fetch big pool map (if required) - if(!pObPoolBig && (pObSystemProcess = VmmProcessGet(4))) { - EnterCriticalSection(&ctxVmm->LockUpdateMap); - if(!(pObPoolBig = ObContainer_GetOb(ctxVmm->pObCMapPoolBig))) { - pObPoolBig = VmmWinPool_Initialize_BigPool_DoWork(pObSystemProcess); - ObContainer_SetOb(ctxVmm->pObCMapPoolBig, pObPoolBig); + if(!pObPoolBig && (pObSystemProcess = VmmProcessGet(H, 4))) { + EnterCriticalSection(&H->vmm.LockUpdateMap); + if(!(pObPoolBig = ObContainer_GetOb(H->vmm.pObCMapPoolBig))) { + pObPoolBig = VmmWinPool_Initialize_BigPool_DoWork(H, pObSystemProcess); + ObContainer_SetOb(H->vmm.pObCMapPoolBig, pObPoolBig); } - LeaveCriticalSection(&ctxVmm->LockUpdateMap); + LeaveCriticalSection(&H->vmm.LockUpdateMap); Ob_DECREF_NULL(&pObSystemProcess); } if(!fAll || !pObPoolBig) { return pObPoolBig; } // fetch all pool map - if(!pObPoolAll && (pObSystemProcess = VmmProcessGet(4))) { - EnterCriticalSection(&ctxVmm->LockUpdateMap); - if(!(pObPoolAll = ObContainer_GetOb(ctxVmm->pObCMapPoolAll))) { - pObPoolAll = VmmWinPool_Initialize_AllPool_DoWork(pObSystemProcess, pObPoolBig); + if(!pObPoolAll && (pObSystemProcess = VmmProcessGet(H, 4))) { + EnterCriticalSection(&H->vmm.LockUpdateMap); + if(!(pObPoolAll = ObContainer_GetOb(H->vmm.pObCMapPoolAll))) { + pObPoolAll = VmmWinPool_Initialize_AllPool_DoWork(H, pObSystemProcess, pObPoolBig); if(!pObPoolAll) { // if all pool map fail - fallback to big pool map pObPoolAll = Ob_INCREF(pObPoolBig); } - ObContainer_SetOb(ctxVmm->pObCMapPoolAll, pObPoolAll); + ObContainer_SetOb(H->vmm.pObCMapPoolAll, pObPoolAll); } - LeaveCriticalSection(&ctxVmm->LockUpdateMap); + LeaveCriticalSection(&H->vmm.LockUpdateMap); Ob_DECREF_NULL(&pObSystemProcess); } Ob_DECREF(pObPoolBig); @@ -1312,9 +1327,10 @@ PVMMOB_MAP_POOL VmmWinPool_Initialize(_In_ BOOL fAll) /* * Refresh the Pool sub-system. +* -- H */ -VOID VmmWinPool_Refresh() +VOID VmmWinPool_Refresh(_In_ VMM_HANDLE H) { - ObContainer_SetOb(ctxVmm->pObCMapPoolAll, NULL); - ObContainer_SetOb(ctxVmm->pObCMapPoolBig, NULL); + ObContainer_SetOb(H->vmm.pObCMapPoolAll, NULL); + ObContainer_SetOb(H->vmm.pObCMapPoolBig, NULL); } diff --git a/vmm/vmmwinpool.h b/vmm/vmmwinpool.h index 19a89b6..a7b85ab 100644 --- a/vmm/vmmwinpool.h +++ b/vmm/vmmwinpool.h @@ -10,15 +10,17 @@ /* * Refresh the Pool sub-system. +* -- H */ -VOID VmmWinPool_Refresh(); +VOID VmmWinPool_Refresh(_In_ VMM_HANDLE H); /* * Create an pool map and assign to the global vmm context upon success. * CALLER DECREF: return +* -- H * -- fAll = TRUE: retrieve all pools; FALSE: retrieve big page pool only. * -- return */ -PVMMOB_MAP_POOL VmmWinPool_Initialize(_In_ BOOL fAll); +PVMMOB_MAP_POOL VmmWinPool_Initialize(_In_ VMM_HANDLE H, _In_ BOOL fAll); #endif /* __VMMWINPOOL_H__ */ diff --git a/vmm/vmmwinreg.c b/vmm/vmmwinreg.c index 1c958b3..4c3c565 100644 --- a/vmm/vmmwinreg.c +++ b/vmm/vmmwinreg.c @@ -61,13 +61,14 @@ typedef struct tdVMMWIN_REGISTRY_CONTEXT { /* * Retrieve the 'Registry' process - or if not found the 'SYSTEM' process. * CALLER DECREF: return +* -- H * -- return */ -PVMM_PROCESS VmmWinReg_GetRegistryProcess() +PVMM_PROCESS VmmWinReg_GetRegistryProcess(_In_ VMM_HANDLE H) { - PVMM_PROCESS pObProcess = VmmProcessGet(ctxVmm->kernel.dwPidRegistry); + PVMM_PROCESS pObProcess = VmmProcessGet(H, H->vmm.kernel.dwPidRegistry); if(pObProcess) { return pObProcess; } - return VmmProcessGet(4); + return VmmProcessGet(H, 4); } #define _IS_HMAP_KDDR64(a) ((a & 0xffff800000000ff0) == 0xffff800000000000) @@ -80,9 +81,9 @@ PVMM_PROCESS VmmWinReg_GetRegistryProcess() #define _IS_HMAP_SIZE32(a) (a && !(a & 0xffff0fff)) _Success_(return) -BOOL VmmWinReg_Reg2Virt64(_In_ PVMM_PROCESS pProcessRegistry, _In_ POB_REGISTRY_HIVE pRegistryHive, _In_ DWORD ra, _Out_ PQWORD pva) +BOOL VmmWinReg_Reg2Virt64(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcessRegistry, _In_ POB_REGISTRY_HIVE pRegistryHive, _In_ DWORD ra, _Out_ PQWORD pva) { - PVMMWIN_REGISTRY_OFFSET po = &ctxVmm->pRegistry->Offset; + PVMMWIN_REGISTRY_OFFSET po = &H->vmm.pRegistry->Offset; QWORD iSV, iDirectory, iTable; QWORD vaTable, vaCell, oCell; BYTE pbHE[0x40]; @@ -98,7 +99,7 @@ BOOL VmmWinReg_Reg2Virt64(_In_ PVMM_PROCESS pProcessRegistry, _In_ POB_REGISTRY_ if(ra >= pRegistryHive->_DUAL[iSV].cb) { return FALSE; } if(iDirectory || !pRegistryHive->_DUAL[iSV].vaHMAP_TABLE_SmallDir) { // REG directory is array of max 1024 pointers to tables [ nt!_HMAP_DIRECTORY +0x000 Directory : [1024] Ptr64 _HMAP_TABLE ] - if(!VmmRead(pProcessRegistry, pRegistryHive->_DUAL[iSV].vaHMAP_DIRECTORY + iDirectory * sizeof(QWORD), (PBYTE)&vaTable, sizeof(QWORD)) || !vaTable) { return FALSE; } + if(!VmmRead(H, pProcessRegistry, pRegistryHive->_DUAL[iSV].vaHMAP_DIRECTORY + iDirectory * sizeof(QWORD), (PBYTE)&vaTable, sizeof(QWORD)) || !vaTable) { return FALSE; } } else { vaTable = pRegistryHive->_DUAL[iSV].vaHMAP_TABLE_SmallDir; } @@ -112,8 +113,8 @@ BOOL VmmWinReg_Reg2Virt64(_In_ PVMM_PROCESS pProcessRegistry, _In_ POB_REGISTRY_ // [ + 0x000 BlockOffset : Uint8B ] // [ + 0x008 PermanentBinAddress : Uint8B ] // [ --------------------------------------- ] - if(!VmmRead(pProcessRegistry, vaTable + iTable * po->HE._Size, (PBYTE)&pbHE, po->HE._Size)) { return FALSE; } - if(ctxVmm->kernel.dwVersionMajor == 10) { + if(!VmmRead(H, pProcessRegistry, vaTable + iTable * po->HE._Size, (PBYTE)&pbHE, po->HE._Size)) { return FALSE; } + if(H->vmm.kernel.dwVersionMajor == 10) { oCell = *(PQWORD)pbHE; vaCell = *(PQWORD)(pbHE + 8); if((oCell & 0xfff) || (oCell >= 0x10000)) { return FALSE; } @@ -127,9 +128,9 @@ BOOL VmmWinReg_Reg2Virt64(_In_ PVMM_PROCESS pProcessRegistry, _In_ POB_REGISTRY_ } _Success_(return) -BOOL VmmWinReg_Reg2Virt32(_In_ PVMM_PROCESS pProcessRegistry, _In_ POB_REGISTRY_HIVE pRegistryHive, _In_ DWORD ra, _Out_ PQWORD pva) +BOOL VmmWinReg_Reg2Virt32(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcessRegistry, _In_ POB_REGISTRY_HIVE pRegistryHive, _In_ DWORD ra, _Out_ PQWORD pva) { - PVMMWIN_REGISTRY_OFFSET po = &ctxVmm->pRegistry->Offset; + PVMMWIN_REGISTRY_OFFSET po = &H->vmm.pRegistry->Offset; QWORD iSV, iDirectory, iTable; DWORD vaTable, vaCell, oCell; BYTE pbHE[0x20]; @@ -145,7 +146,7 @@ BOOL VmmWinReg_Reg2Virt32(_In_ PVMM_PROCESS pProcessRegistry, _In_ POB_REGISTRY_ if(ra >= pRegistryHive->_DUAL[iSV].cb) { return FALSE; } // DIRECTORY if(iDirectory || !pRegistryHive->_DUAL[iSV].vaHMAP_TABLE_SmallDir) { - if(!VmmRead(pProcessRegistry, pRegistryHive->_DUAL[iSV].vaHMAP_DIRECTORY + iDirectory * sizeof(DWORD), (PBYTE)&vaTable, sizeof(DWORD)) || !vaTable) { return FALSE; } + if(!VmmRead(H, pProcessRegistry, pRegistryHive->_DUAL[iSV].vaHMAP_DIRECTORY + iDirectory * sizeof(DWORD), (PBYTE)&vaTable, sizeof(DWORD)) || !vaTable) { return FALSE; } } else { vaTable = (DWORD)pRegistryHive->_DUAL[iSV].vaHMAP_TABLE_SmallDir; } @@ -158,8 +159,8 @@ BOOL VmmWinReg_Reg2Virt32(_In_ PVMM_PROCESS pProcessRegistry, _In_ POB_REGISTRY_ // [ + 0x000 BlockOffset : Uint4B ] // [ + 0x004 PermanentBinAddress : Uint4B ] // [ --------------------------------------- ] - if(!VmmRead(pProcessRegistry, vaTable + iTable * po->HE._Size, (PBYTE)&pbHE, po->HE._Size)) { return FALSE; } - if(ctxVmm->kernel.dwVersionMajor == 10) { + if(!VmmRead(H, pProcessRegistry, vaTable + iTable * po->HE._Size, (PBYTE)&pbHE, po->HE._Size)) { return FALSE; } + if(H->vmm.kernel.dwVersionMajor == 10) { oCell = *(PDWORD)pbHE; vaCell = *(PDWORD)(pbHE + 4); if((oCell & 0xfff) || (oCell >= 0x10000)) { return FALSE; } @@ -181,12 +182,12 @@ BOOL VmmWinReg_Reg2Virt32(_In_ PVMM_PROCESS pProcessRegistry, _In_ POB_REGISTRY_ * -- return */ _Success_(return) -BOOL VmmWinReg_Reg2Virt(_In_ PVMM_PROCESS pProcessRegistry, _In_ POB_REGISTRY_HIVE pRegistryHive, _In_ DWORD ra, _Out_ PQWORD pva) +BOOL VmmWinReg_Reg2Virt(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcessRegistry, _In_ POB_REGISTRY_HIVE pRegistryHive, _In_ DWORD ra, _Out_ PQWORD pva) { if(!pProcessRegistry || !pRegistryHive) { return FALSE; } - return ctxVmm->f32 ? - VmmWinReg_Reg2Virt32(pProcessRegistry, pRegistryHive, ra, pva) : - VmmWinReg_Reg2Virt64(pProcessRegistry, pRegistryHive, ra, pva); + return H->vmm.f32 ? + VmmWinReg_Reg2Virt32(H, pProcessRegistry, pRegistryHive, ra, pva) : + VmmWinReg_Reg2Virt64(H, pProcessRegistry, pRegistryHive, ra, pva); } /* @@ -194,24 +195,25 @@ BOOL VmmWinReg_Reg2Virt(_In_ PVMM_PROCESS pProcessRegistry, _In_ POB_REGISTRY_HI * request item into a virtual memory scatter request item and submits it to * the underlying vmm sub-system. See VmmReadScatterVirtual for additional * information. +* -- H * -- pProcessRegistry * -- pRegistryHive * -- ppMEMsReg * -- cpMEMsReg * -- flags */ -VOID VmmWinReg_ReadScatter(_In_ PVMM_PROCESS pProcessRegistry, _In_ POB_REGISTRY_HIVE pRegistryHive, _Inout_ PPMEM_SCATTER ppMEMsReg, _In_ DWORD cpMEMsReg, _In_ QWORD flags) +VOID VmmWinReg_ReadScatter(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcessRegistry, _In_ POB_REGISTRY_HIVE pRegistryHive, _Inout_ PPMEM_SCATTER ppMEMsReg, _In_ DWORD cpMEMsReg, _In_ QWORD flags) { DWORD i; PMEM_SCATTER pMEM; for(i = 0; i < cpMEMsReg; i++) { pMEM = ppMEMsReg[i]; MEM_SCATTER_STACK_PUSH(pMEM, pMEM->qwA); - if(pMEM->f || !VmmWinReg_Reg2Virt(pProcessRegistry, pRegistryHive, (DWORD)pMEM->qwA, &pMEM->qwA)) { + if(pMEM->f || !VmmWinReg_Reg2Virt(H, pProcessRegistry, pRegistryHive, (DWORD)pMEM->qwA, &pMEM->qwA)) { pMEM->qwA = -1; } } - VmmReadScatterVirtual(pProcessRegistry, ppMEMsReg, cpMEMsReg, flags); + VmmReadScatterVirtual(H, pProcessRegistry, ppMEMsReg, cpMEMsReg, flags); for(i = 0; i < cpMEMsReg; i++) { pMEM = ppMEMsReg[i]; pMEM->qwA = MEM_SCATTER_STACK_POP(pMEM); @@ -222,6 +224,7 @@ VOID VmmWinReg_ReadScatter(_In_ PVMM_PROCESS pProcessRegistry, _In_ POB_REGISTRY * Read a contigious arbitrary amount of registry hive memory and report the * number of bytes read in pcbRead. * NB! Address space does not include regf registry hive file header! +* -- H * -- pRegistryHive * -- ra * -- pb @@ -229,7 +232,7 @@ VOID VmmWinReg_ReadScatter(_In_ PVMM_PROCESS pProcessRegistry, _In_ POB_REGISTRY * -- pcbRead * -- flags = flags as in VMM_FLAG_* */ -VOID VmmWinReg_HiveReadEx(_In_ POB_REGISTRY_HIVE pRegistryHive, _In_ DWORD ra, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ QWORD flags) +VOID VmmWinReg_HiveReadEx(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pRegistryHive, _In_ DWORD ra, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ QWORD flags) { PVMM_PROCESS pObProcessRegistry = NULL; DWORD cbP, cMEMs, cbRead = 0; @@ -261,9 +264,9 @@ VOID VmmWinReg_HiveReadEx(_In_ POB_REGISTRY_HIVE pRegistryHive, _In_ DWORD ra, _ pMEMs[cMEMs - 1].pb = pbBuffer + 0x1000; } // Read REG and handle result - pObProcessRegistry = VmmWinReg_GetRegistryProcess(); + pObProcessRegistry = VmmWinReg_GetRegistryProcess(H); if(pObProcessRegistry) { - VmmWinReg_ReadScatter(pObProcessRegistry, pRegistryHive, ppMEMs, cMEMs, flags); + VmmWinReg_ReadScatter(H, pObProcessRegistry, pRegistryHive, ppMEMs, cMEMs, flags); Ob_DECREF(pObProcessRegistry); pObProcessRegistry = NULL; } @@ -299,16 +302,17 @@ VOID VmmWinReg_HiveReadEx(_In_ POB_REGISTRY_HIVE pRegistryHive, _In_ DWORD ra, _ } _Success_(return) -BOOL VmmWinReg_HiveRead(_In_ POB_REGISTRY_HIVE pRegistryHive, _In_ DWORD ra, _Out_ PBYTE pb, _In_ DWORD cb) +BOOL VmmWinReg_HiveRead(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pRegistryHive, _In_ DWORD ra, _Out_ PBYTE pb, _In_ DWORD cb) { DWORD cbRead; - VmmWinReg_HiveReadEx(pRegistryHive, ra, pb, cb, &cbRead, 0); + VmmWinReg_HiveReadEx(H, pRegistryHive, ra, pb, cb, &cbRead, 0); return (cbRead == cb); } /* * Write a virtually contigious arbitrary amount of memory. * NB! Address space does not include regf registry hive file header! +* -- H * -- pRegistryHive * -- ra * -- pb @@ -316,17 +320,17 @@ BOOL VmmWinReg_HiveRead(_In_ POB_REGISTRY_HIVE pRegistryHive, _In_ DWORD ra, _Ou * -- return = TRUE on success, FALSE on partial or zero write. */ _Success_(return) -BOOL VmmWinReg_HiveWrite(_In_ POB_REGISTRY_HIVE pRegistryHive, _In_ DWORD ra, _In_reads_(cb) PBYTE pb, _In_ DWORD cb) +BOOL VmmWinReg_HiveWrite(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pRegistryHive, _In_ DWORD ra, _In_reads_(cb) PBYTE pb, _In_ DWORD cb) { QWORD vaWrite; DWORD cbWrite; BOOL fSuccess = TRUE; PVMM_PROCESS pObProcessRegistry = NULL; - if(!cb || !(pObProcessRegistry = VmmWinReg_GetRegistryProcess())) { return FALSE; } + if(!cb || !(pObProcessRegistry = VmmWinReg_GetRegistryProcess(H))) { return FALSE; } while(cb) { cbWrite = 0x1000 - (ra & 0xfff); - if(VmmWinReg_Reg2Virt(pObProcessRegistry, pRegistryHive, ra, &vaWrite) && vaWrite) { - fSuccess = VmmWrite(pObProcessRegistry, vaWrite, pb, cbWrite) && fSuccess; + if(VmmWinReg_Reg2Virt(H, pObProcessRegistry, pRegistryHive, ra, &vaWrite) && vaWrite) { + fSuccess = VmmWrite(H, pObProcessRegistry, vaWrite, pb, cbWrite) && fSuccess; } else { fSuccess = FALSE; } @@ -344,33 +348,33 @@ BOOL VmmWinReg_HiveWrite(_In_ POB_REGISTRY_HIVE pRegistryHive, _In_ DWORD ra, _I // Locate potential registry hive addresses by looking at ntoskrnl.exe '.data' // section (Windows 10) or by scanning lower physical memory (Win 7/8). Once // potential hives are located then FUZZ offsets within the hive page. Upon -// success offsets are stored in the core ctxVmm->RegistryOffset global object. +// success offsets are stored in the core H->vmm.RegistryOffset global object. //----------------------------------------------------------------------------- -VOID VmmWinReg_FuzzHiveOffsets_PrintResultVerbose(_In_ PBYTE pb, _In_ DWORD cb) +VOID VmmWinReg_FuzzHiveOffsets_PrintResultVerbose(_In_ VMM_HANDLE H, _In_ PBYTE pb, _In_ DWORD cb) { - PVMMWIN_REGISTRY_OFFSET po = &ctxVmm->pRegistry->Offset; - VmmLog(MID_REGISTRY, LOGLEVEL_DEBUG, + PVMMWIN_REGISTRY_OFFSET po = &H->vmm.pRegistry->Offset; + VmmLog(H, MID_REGISTRY, LOGLEVEL_DEBUG, "CM.Sig %03X, CM.Len0 %03X, CM.StorMap0 %03X, CM.StorSmallDir0 %03X, CM.BaseBlock %03X", po->CM.Signature, po->CM.Length0, po->CM.StorageMap0, po->CM.StorageSmallDir0, po->CM.BaseBlock); - VmmLog(MID_REGISTRY, LOGLEVEL_DEBUG, + VmmLog(H, MID_REGISTRY, LOGLEVEL_DEBUG, " CM.Len1 %03X, CM.StorMap1 %03X, CM.StorSmallDir1 %03X, HE._Size %03X", po->CM.Length1, po->CM.StorageMap1, po->CM.StorageSmallDir1, po->HE._Size); - VmmLog(MID_REGISTRY, LOGLEVEL_DEBUG, + VmmLog(H, MID_REGISTRY, LOGLEVEL_DEBUG, "CM.FLAll %03X, CM._Size %03X, CM.FileFull %03X, CM.FileUserPath %03X, CM.HiveRoot %03X", po->CM.FLinkAll, po->CM._Size, po->CM.FileFullPathOpt, po->CM.FileUserNameOpt, po->CM.HiveRootPathOpt); - VmmLog(MID_REGISTRY, LOGLEVEL_DEBUG, + VmmLog(H, MID_REGISTRY, LOGLEVEL_DEBUG, "BB.Sig %03X, BB.Length %03X, BB.FileName %03X, BB.Major %03X, BB.Minor %03X", po->BB.Signature, po->BB.Length, po->BB.FileName, po->BB.Major, po->BB.Minor); } /* * Fuzz required offsets for registry structures and upon success store the -* result in ctxVmm->RegistryOffset. This function is overly complicated and +* result in H->vmm.RegistryOffset. This function is overly complicated and * should ideally be replaced with parsing the structs from Microsoft SymSrv - * but that will introduce additional dependencies also ... This works for now. */ -BOOL VmmWinReg_FuzzHiveOffsets64(_In_ PVMM_PROCESS pProcessSystem, _In_ QWORD vaCMHIVE, _In_reads_(0x1000) PBYTE pbCMHIVE) +BOOL VmmWinReg_FuzzHiveOffsets64(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcessSystem, _In_ QWORD vaCMHIVE, _In_reads_(0x1000) PBYTE pbCMHIVE) { CONST BYTE pbTEXT_REGISTRY[] = { '\\', 0, 'R', 0, 'E', 0, 'G', 0, 'I', 0, 'S', 0, 'T', 0, 'R', 0, 'Y', 0, '\\', 0, }; BOOL f; @@ -386,7 +390,7 @@ BOOL VmmWinReg_FuzzHiveOffsets64(_In_ PVMM_PROCESS pProcessSystem, _In_ QWORD va if(vaCMHIVE) { vaCMHIVE += 0x10; } } if(*(PDWORD)(pbCMHIVE + 0x000) != 0xBEE0BEE0) { return FALSE; } - po = &ctxVmm->pRegistry->Offset; + po = &H->vmm.pRegistry->Offset; po->CM.Signature = 0; // _CMHIVE.BaseBlock for(o = 0x30; o < 0x60; o += 8) { @@ -403,7 +407,7 @@ BOOL VmmWinReg_FuzzHiveOffsets64(_In_ PVMM_PROCESS pProcessSystem, _In_ QWORD va (*(PDWORD)(pbCMHIVE + o + 0x000) < 0x40000000) && // _DUAL[0].Length < 1GB VMM_KADDR64_8(*(PQWORD)(pbCMHIVE + o + 0x008)) && // _DUAL[0].Map = kernel 8-byte align ((vaSmallDir == 0) || VMM_KADDR64_PAGE(vaSmallDir)) && // _DUAL[0].SmallDir = kernel page base - VmmRead(pProcessSystem, *(PQWORD)(pbCMHIVE + o + 0x008), (PBYTE)&qw, sizeof(QWORD)) && // [_DUAL[0].Map] + VmmRead(H, pProcessSystem, *(PQWORD)(pbCMHIVE + o + 0x008), (PBYTE)&qw, sizeof(QWORD)) && // [_DUAL[0].Map] ((vaSmallDir == 0) || (vaSmallDir == qw)); // _DUAL[0].SmallDir = 1st entry in _DUAL.Map 'directory' if(f) { break; } } @@ -422,9 +426,9 @@ BOOL VmmWinReg_FuzzHiveOffsets64(_In_ PVMM_PROCESS pProcessSystem, _In_ QWORD va VMM_KADDR64_8(*(PQWORD)(pbCMHIVE + o + 8)) && // BLink (*(PQWORD)(pbCMHIVE + o) != *(PQWORD)(pbCMHIVE + o + 8)) && // FLinkAll != BLink ((*(PQWORD)(pbCMHIVE + o) - o) != vaCMHIVE) && // Not ptr to this CMHIVE - VmmRead(pProcessSystem, *(PQWORD)(pbCMHIVE + o) + 8, (PBYTE)&qw, sizeof(QWORD)) && // Read FLinkAll->BLink + VmmRead(H, pProcessSystem, *(PQWORD)(pbCMHIVE + o) + 8, (PBYTE)&qw, sizeof(QWORD)) && // Read FLinkAll->BLink (!vaCMHIVE || (qw - o == vaCMHIVE)) && // vaCMHIVE == FLinkAll->BLink - VmmRead(pProcessSystem, ((*(PQWORD)(pbCMHIVE + o) - o)), (PBYTE)&dw, sizeof(DWORD)) && + VmmRead(H, pProcessSystem, ((*(PQWORD)(pbCMHIVE + o) - o)), (PBYTE)&dw, sizeof(DWORD)) && (dw == 0xBEE0BEE0); // Signature check if(f) { break; } } @@ -436,7 +440,7 @@ BOOL VmmWinReg_FuzzHiveOffsets64(_In_ PVMM_PROCESS pProcessSystem, _In_ QWORD va (*(PWORD)(pbCMHIVE + o) > 12) && // UNICODE_STRING.Length > 12 (\\REGISTRY\\) (*(PWORD)(pbCMHIVE + o) < 0xff) && // UNICODE_STRING.Length < 0xff VMM_KADDR64(*(PQWORD)(pbCMHIVE + o + 8)) && // Is kernel address - VmmRead(pProcessSystem, *(PQWORD)(pbCMHIVE + o + 8), pbBuffer, 20) && // Read STRING + VmmRead(H, pProcessSystem, *(PQWORD)(pbCMHIVE + o + 8), pbBuffer, 20) && // Read STRING !memcmp(pbBuffer, pbTEXT_REGISTRY, 20); // Starts with '\REGISTRY\' if(f) { break; } } @@ -450,10 +454,10 @@ BOOL VmmWinReg_FuzzHiveOffsets64(_In_ PVMM_PROCESS pProcessSystem, _In_ QWORD va ZeroMemory(qwHE, sizeof(qwHE)); po->HE._Size = 0x018; // Most common (default try) if(!vaSmallDir) { - VmmRead(pProcessSystem, *(PQWORD)(pbCMHIVE + po->CM.StorageMap0), (PBYTE)&vaSmallDir, sizeof(QWORD)); + VmmRead(H, pProcessSystem, *(PQWORD)(pbCMHIVE + po->CM.StorageMap0), (PBYTE)&vaSmallDir, sizeof(QWORD)); } if((vaSmallDir & 0xffff800000000fff) == 0xffff800000000000) { - VmmRead(pProcessSystem, vaSmallDir, (PBYTE)qwHE, sizeof(qwHE)); + VmmRead(H, pProcessSystem, vaSmallDir, (PBYTE)qwHE, sizeof(qwHE)); f = _IS_HMAP_KDDR64(qwHE[0]) && _IS_HMAP_KDDR64(qwHE[1]) && _IS_HMAP_ZERO64(qwHE[2]) && _IS_HMAP_SIZE64(qwHE[3]) && _IS_HMAP_ZERO64(qwHE[4]) && _IS_HMAP_ZERO64(qwHE[5]) && _IS_HMAP_ZERO64(qwHE[6]) && _IS_HMAP_ZERO64(qwHE[7]); if(f) { po->HE._Size = 0x20; } // only 1 entry in table of length 0x20 @@ -471,11 +475,11 @@ BOOL VmmWinReg_FuzzHiveOffsets64(_In_ PVMM_PROCESS pProcessSystem, _In_ QWORD va po->BB.FileName = 0x030; // CMHIVE virtual address hint po->vaHintCMHIVE = vaCMHIVE ? vaCMHIVE : (*(PQWORD)(pbCMHIVE + po->CM.FLinkAll) - po->CM.FLinkAll); - VmmWinReg_FuzzHiveOffsets_PrintResultVerbose((PBYTE)qwHE, sizeof(qwHE)); + VmmWinReg_FuzzHiveOffsets_PrintResultVerbose(H, (PBYTE)qwHE, sizeof(qwHE)); return TRUE; } -BOOL VmmWinReg_FuzzHiveOffsets32(_In_ PVMM_PROCESS pProcessSystem, _In_ QWORD vaCMHIVE, _In_reads_(0x1000) PBYTE pbCMHIVE) +BOOL VmmWinReg_FuzzHiveOffsets32(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcessSystem, _In_ QWORD vaCMHIVE, _In_reads_(0x1000) PBYTE pbCMHIVE) { CONST BYTE pbTEXT_REGISTRY[] = { '\\', 0, 'R', 0, 'E', 0, 'G', 0, 'I', 0, 'S', 0, 'T', 0, 'R', 0, 'Y', 0, '\\', 0, }; BOOL f; @@ -483,7 +487,7 @@ BOOL VmmWinReg_FuzzHiveOffsets32(_In_ PVMM_PROCESS pProcessSystem, _In_ QWORD va DWORD dw, vaSmallDir; BYTE pbBuffer[20]; DWORD dwHE[0x10]; - PVMMWIN_REGISTRY_OFFSET po = &ctxVmm->pRegistry->Offset; + PVMMWIN_REGISTRY_OFFSET po = &H->vmm.pRegistry->Offset; // _CMHIVE BASE for(o = 0; o < 0x40; o += 8) { if(*(PQWORD)(pbCMHIVE + o + 0x004) == 0xBEE0BEE030314D43) { @@ -493,7 +497,7 @@ BOOL VmmWinReg_FuzzHiveOffsets32(_In_ PVMM_PROCESS pProcessSystem, _In_ QWORD va } } if(*(PDWORD)(pbCMHIVE + 0x000) != 0xBEE0BEE0) { return FALSE; } - po = &ctxVmm->pRegistry->Offset; + po = &H->vmm.pRegistry->Offset; po->CM.Signature = 0; // _CMHIVE.BaseBlock for(o = 0x18; o < 0x30; o += 4) { @@ -502,9 +506,9 @@ BOOL VmmWinReg_FuzzHiveOffsets32(_In_ PVMM_PROCESS pProcessSystem, _In_ QWORD va if(!f) { return FALSE; } po->CM.BaseBlock = o; // sizeof(_DUAL): - if(ctxVmm->kernel.dwVersionBuild < 6000) { + if(H->vmm.kernel.dwVersionBuild < 6000) { cbDual = 0x0dc; // WinXP - } else if(ctxVmm->kernel.dwVersionBuild < 9200) { + } else if(H->vmm.kernel.dwVersionBuild < 9200) { cbDual = 0x13c; // WinVista-Win7 } else { cbDual = 0x19c; // Win8+ @@ -516,7 +520,7 @@ BOOL VmmWinReg_FuzzHiveOffsets32(_In_ PVMM_PROCESS pProcessSystem, _In_ QWORD va (*(PDWORD)(pbCMHIVE + o + 0x000) < 0x40000000) && // _DUAL[0].Length < 1GB VMM_KADDR32_4(*(PDWORD)(pbCMHIVE + o + 0x004)) && // _DUAL[0].Map = kernel 4-byte align ((vaSmallDir == 0) || VMM_KADDR32_PAGE(vaSmallDir)) && // _DUAL[0].SmallDir = kernel page base - VmmRead(pProcessSystem, *(PDWORD)(pbCMHIVE + o + 0x004), (PBYTE)&dw, sizeof(DWORD)) && // [_DUAL[0].Map] + VmmRead(H, pProcessSystem, *(PDWORD)(pbCMHIVE + o + 0x004), (PBYTE)&dw, sizeof(DWORD)) && // [_DUAL[0].Map] ((vaSmallDir == 0) || (vaSmallDir == dw)); // _DUAL[0].SmallDir = 1st entry in _DUAL.Map 'directory' if(f) { break; } } @@ -531,15 +535,15 @@ BOOL VmmWinReg_FuzzHiveOffsets32(_In_ PVMM_PROCESS pProcessSystem, _In_ QWORD va o += cbDual; // _CMHIVE _LIST_ENTRY for(; o < 0x800; o += 4) { - f = VMM_KADDR32_4(*(PDWORD)(pbCMHIVE + o)) && // FLinkAll - VMM_KADDR32_4(*(PDWORD)(pbCMHIVE + o + 4)) && // BLink - (*(PDWORD)(pbCMHIVE + o) != *(PDWORD)(pbCMHIVE + o + 4)) && // FLinkAll != BLink - VmmRead(pProcessSystem, *(PDWORD)(pbCMHIVE + o) + sizeof(DWORD), (PBYTE)&dw, sizeof(DWORD)) && // Read FLinkAll->BLink - VmmRead(pProcessSystem, (QWORD)dw - o + po->CM.Signature, (PBYTE)&dw, sizeof(DWORD)) && // Read (FLinkAll->BLink) Signature - (dw == 0xBEE0BEE0) && // Signature check - VmmRead(pProcessSystem, *(PDWORD)(pbCMHIVE + o + 4), (PBYTE)&dw, sizeof(DWORD)) && // Read BLink->FLinkAll - VmmRead(pProcessSystem, (QWORD)dw - o + po->CM.Signature, (PBYTE)&dw, sizeof(DWORD)) && // Read (BLink->FLinkAll) Signature - (dw == 0xBEE0BEE0); // Signature check + f = VMM_KADDR32_4(*(PDWORD)(pbCMHIVE + o)) && // FLinkAll + VMM_KADDR32_4(*(PDWORD)(pbCMHIVE + o + 4)) && // BLink + (*(PDWORD)(pbCMHIVE + o) != *(PDWORD)(pbCMHIVE + o + 4)) && // FLinkAll != BLink + VmmRead(H, pProcessSystem, *(PDWORD)(pbCMHIVE + o) + sizeof(DWORD), (PBYTE)&dw, sizeof(DWORD)) && // Read FLinkAll->BLink + VmmRead(H, pProcessSystem, (QWORD)dw - o + po->CM.Signature, (PBYTE)&dw, sizeof(DWORD)) && // Read (FLinkAll->BLink) Signature + (dw == 0xBEE0BEE0) && // Signature check + VmmRead(H, pProcessSystem, *(PDWORD)(pbCMHIVE + o + 4), (PBYTE)&dw, sizeof(DWORD)) && // Read BLink->FLinkAll + VmmRead(H, pProcessSystem, (QWORD)dw - o + po->CM.Signature, (PBYTE)&dw, sizeof(DWORD)) && // Read (BLink->FLinkAll) Signature + (dw == 0xBEE0BEE0); // Signature check if(f) { break; } } if(!f) { return FALSE; } @@ -550,7 +554,7 @@ BOOL VmmWinReg_FuzzHiveOffsets32(_In_ PVMM_PROCESS pProcessSystem, _In_ QWORD va (*(PWORD)(pbCMHIVE + o) > 12) && // UNICODE_STRING.Length > 12 (\\REGISTRY\\) (*(PWORD)(pbCMHIVE + o) < 0xff) && // UNICODE_STRING.Length < 0xff VMM_KADDR32(*(PDWORD)(pbCMHIVE + o + 4)) && // Is kernel address - VmmRead(pProcessSystem, *(PDWORD)(pbCMHIVE + o + 4), pbBuffer, 20) && // Read STRING + VmmRead(H, pProcessSystem, *(PDWORD)(pbCMHIVE + o + 4), pbBuffer, 20) && // Read STRING !memcmp(pbBuffer, pbTEXT_REGISTRY, 20); // Starts with '\REGISTRY\' if(f) { po->CM.HiveRootPathOpt = o; @@ -566,10 +570,10 @@ BOOL VmmWinReg_FuzzHiveOffsets32(_In_ PVMM_PROCESS pProcessSystem, _In_ QWORD va ZeroMemory(dwHE, sizeof(dwHE)); po->HE._Size = 0x00c; // Most common (default try) if(!vaSmallDir) { - VmmRead(pProcessSystem, *(PDWORD)(pbCMHIVE + po->CM.StorageMap0), (PBYTE)&vaSmallDir, sizeof(DWORD)); + VmmRead(H, pProcessSystem, *(PDWORD)(pbCMHIVE + po->CM.StorageMap0), (PBYTE)&vaSmallDir, sizeof(DWORD)); } if((vaSmallDir & 0x80000fff) == 0x80000000) { - VmmRead(pProcessSystem, vaSmallDir, (PBYTE)dwHE, sizeof(dwHE)); + VmmRead(H, pProcessSystem, vaSmallDir, (PBYTE)dwHE, sizeof(dwHE)); f = _IS_HMAP_ADDR32(dwHE[0]) && _IS_HMAP_ADDR32(dwHE[1]) && _IS_HMAP_SIZE32(dwHE[3]) && _IS_HMAP_ADDR32(dwHE[4]) && _IS_HMAP_ADDR32(dwHE[5]) && _IS_HMAP_SIZE32(dwHE[7]); if(f) { po->HE._Size = 0x010; } @@ -588,7 +592,7 @@ BOOL VmmWinReg_FuzzHiveOffsets32(_In_ PVMM_PROCESS pProcessSystem, _In_ QWORD va po->BB.FileName = 0x030; // CMHIVE virtual address hint po->vaHintCMHIVE = vaCMHIVE ? vaCMHIVE : (*(PDWORD)(pbCMHIVE + po->CM.FLinkAll) - po->CM.FLinkAll); - VmmWinReg_FuzzHiveOffsets_PrintResultVerbose((PBYTE)dwHE, sizeof(dwHE)); + VmmWinReg_FuzzHiveOffsets_PrintResultVerbose(H, (PBYTE)dwHE, sizeof(dwHE)); return TRUE; } @@ -598,25 +602,26 @@ BOOL VmmWinReg_FuzzHiveOffsets32(_In_ PVMM_PROCESS pProcessSystem, _In_ QWORD va * The search algorithm looks for promising addresses in ntoskrnl.exe .data * section and checks if any of these addresses are part of a CMHIVE. If the * above technique fail then the lower memory is scanned (also fail sometimes). +* -- H * -- return */ #define MAX_NUM_POTENTIAL_HIVE_HINT 0x20 -BOOL VmmWinReg_LocateRegistryHive() +BOOL VmmWinReg_LocateRegistryHive(_In_ VMM_HANDLE H) { BOOL result = FALSE; - BOOL f32 = ctxVmm->f32; - PVMM_PROCESS pObProcessSystem = VmmProcessGet(4); + BOOL f32 = H->vmm.f32; + PVMM_PROCESS pObProcessSystem = VmmProcessGet(H, 4); IMAGE_SECTION_HEADER SectionHeader; DWORD iSection, cbSectionSize, cbPoolHdr, cbPoolHdrMax, cPotentialHive, o, p, i; QWORD vaPotentialHive[MAX_NUM_POTENTIAL_HIVE_HINT]; PBYTE pb = NULL; PPMEM_SCATTER ppMEMs = NULL; - if(!VmmProcessGet(4) || !(pb = LocalAlloc(0, 0x01000000))) { goto cleanup; } + if(!pObProcessSystem || !(pb = LocalAlloc(0, 0x01000000))) { goto cleanup; } // 1: Try locate registry by scanning ntoskrnl.exe .data section. for(iSection = 0; iSection < 2; iSection++) { // 1st check '.data' section, then PAGEDATA' for pointers. - if(!PE_SectionGetFromName(pObProcessSystem, ctxVmm->kernel.vaBase, iSection ? "PAGEDATA" : ".data", &SectionHeader)) { goto cleanup; } + if(!PE_SectionGetFromName(H, pObProcessSystem, H->vmm.kernel.vaBase, iSection ? "PAGEDATA" : ".data", &SectionHeader)) { goto cleanup; } cbSectionSize = min(0x01000000, SectionHeader.Misc.VirtualSize); - VmmReadEx(pObProcessSystem, ctxVmm->kernel.vaBase + SectionHeader.VirtualAddress, pb, min(0x01000000, SectionHeader.Misc.VirtualSize), NULL, VMM_FLAG_ZEROPAD_ON_FAIL); + VmmReadEx(H, pObProcessSystem, H->vmm.kernel.vaBase + SectionHeader.VirtualAddress, pb, min(0x01000000, SectionHeader.Misc.VirtualSize), NULL, VMM_FLAG_ZEROPAD_ON_FAIL); cbPoolHdrMax = f32 ? 0x08 : 0x10; for(cbPoolHdr = 0; cbPoolHdr <= cbPoolHdrMax; cbPoolHdr += cbPoolHdrMax) { for(cPotentialHive = 0, o = 0; o < cbSectionSize && cPotentialHive < MAX_NUM_POTENTIAL_HIVE_HINT; o += (f32 ? 4 : 8)) { @@ -635,10 +640,10 @@ BOOL VmmWinReg_LocateRegistryHive() for(i = 0; i < cPotentialHive; i++) { ppMEMs[i]->qwA = vaPotentialHive[i] & ~0xfff; } - VmmReadScatterVirtual(pObProcessSystem, ppMEMs, cPotentialHive, 0); + VmmReadScatterVirtual(H, pObProcessSystem, ppMEMs, cPotentialHive, 0); for(i = 0; i < cPotentialHive; i++) { if(ppMEMs[i]->f) { - if((result = f32 ? VmmWinReg_FuzzHiveOffsets32(pObProcessSystem, ppMEMs[i]->qwA, ppMEMs[i]->pb) : VmmWinReg_FuzzHiveOffsets64(pObProcessSystem, ppMEMs[i]->qwA, ppMEMs[i]->pb))) { + if((result = f32 ? VmmWinReg_FuzzHiveOffsets32(H, pObProcessSystem, ppMEMs[i]->qwA, ppMEMs[i]->pb) : VmmWinReg_FuzzHiveOffsets64(H, pObProcessSystem, ppMEMs[i]->qwA, ppMEMs[i]->pb))) { goto cleanup; } } @@ -648,9 +653,9 @@ BOOL VmmWinReg_LocateRegistryHive() // 2: As a fallback - try locate registry by scanning lower physical memory. // This is much slower, but will work sometimes when the above method fail. for(o = 0x00000000; o < 0x08000000; o += 0x01000000) { - VmmReadEx(NULL, o, pb, 0x01000000, NULL, 0); + VmmReadEx(H, NULL, o, pb, 0x01000000, NULL, 0); for(p = 0; p < 0x01000000; p += 0x1000) { - if((result = f32 ? VmmWinReg_FuzzHiveOffsets32(pObProcessSystem, 0, pb + p) : VmmWinReg_FuzzHiveOffsets64(pObProcessSystem, 0, pb + p))) { + if((result = f32 ? VmmWinReg_FuzzHiveOffsets32(H, pObProcessSystem, 0, pb + p) : VmmWinReg_FuzzHiveOffsets64(H, pObProcessSystem, 0, pb + p))) { goto cleanup; } } @@ -686,9 +691,9 @@ VOID VmmWinReg_CallbackCleanup_ObRegistryHive(POB_REGISTRY_HIVE pOb) * Callback function from VmmWin_ListTraversePrefetch[32|64]. * Gather referenced addresses into prefetch dataset. */ -VOID VmmWinReg_EnumHive64_Pre(_In_ PVMM_PROCESS pProcess, _In_opt_ POB_MAP pHiveMap, _In_ QWORD va, _In_ PBYTE pb, _In_ DWORD cb, _In_ QWORD vaFLink, _In_ QWORD vaBLink, _In_ POB_SET pVSetAddress, _Inout_ PBOOL pfValidEntry, _Inout_ PBOOL pfValidFLink, _Inout_ PBOOL pfValidBLink) +VOID VmmWinReg_EnumHive64_Pre(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ POB_MAP pHiveMap, _In_ QWORD va, _In_ PBYTE pb, _In_ DWORD cb, _In_ QWORD vaFLink, _In_ QWORD vaBLink, _In_ POB_SET pVSetAddress, _Inout_ PBOOL pfValidEntry, _Inout_ PBOOL pfValidFLink, _Inout_ PBOOL pfValidBLink) { - PVMMWIN_REGISTRY_OFFSET po = &ctxVmm->pRegistry->Offset; + PVMMWIN_REGISTRY_OFFSET po = &H->vmm.pRegistry->Offset; if((va & 0xffff800000000007) != 0xffff800000000000) { return; } // not aligned kernel address *pfValidFLink = ((vaFLink & 0xffff800000000007) == 0xffff800000000000); // aligned kernel address *pfValidBLink = ((vaBLink & 0xffff800000000007) == 0xffff800000000000); // aligned kernel address @@ -701,9 +706,9 @@ VOID VmmWinReg_EnumHive64_Pre(_In_ PVMM_PROCESS pProcess, _In_opt_ POB_MAP pHive } } -VOID VmmWinReg_EnumHive32_Pre(_In_ PVMM_PROCESS pProcess, _In_opt_ POB_MAP pHiveMap, _In_ QWORD va, _In_ PBYTE pb, _In_ DWORD cb, _In_ QWORD vaFLink, _In_ QWORD vaBLink, _In_ POB_SET pVSetAddress, _Inout_ PBOOL pfValidEntry, _Inout_ PBOOL pfValidFLink, _Inout_ PBOOL pfValidBLink) +VOID VmmWinReg_EnumHive32_Pre(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ POB_MAP pHiveMap, _In_ QWORD va, _In_ PBYTE pb, _In_ DWORD cb, _In_ QWORD vaFLink, _In_ QWORD vaBLink, _In_ POB_SET pVSetAddress, _Inout_ PBOOL pfValidEntry, _Inout_ PBOOL pfValidFLink, _Inout_ PBOOL pfValidBLink) { - PVMMWIN_REGISTRY_OFFSET po = &ctxVmm->pRegistry->Offset; + PVMMWIN_REGISTRY_OFFSET po = &H->vmm.pRegistry->Offset; if((va & 0x80000007) != 0x80000000) { return; } // not aligned kernel address *pfValidFLink = ((vaFLink & 0x80000003) == 0x80000000); // aligned kernel address *pfValidBLink = ((vaBLink & 0x80000003) == 0x80000000); // aligned kernel address @@ -733,7 +738,7 @@ VOID VmmWinReg_HiveGetShortName(_In_ POB_REGISTRY_HIVE pHive, _Out_writes_(32) L * Callback function from VmmWin_ListTraversePrefetch[32|64]. * Set up a single Registry Hive. */ -VOID VmmWinReg_EnumHive64_Post(_In_ PVMM_PROCESS pProcess, _In_opt_ POB_MAP pHiveMap, _In_ QWORD vaData, _In_ PBYTE pbData, _In_ DWORD cbData) +VOID VmmWinReg_EnumHive64_Post(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ POB_MAP pHiveMap, _In_ QWORD vaData, _In_ PBYTE pbData, _In_ DWORD cbData) { BOOL f; CHAR chDefault = '_'; @@ -741,7 +746,7 @@ VOID VmmWinReg_EnumHive64_Post(_In_ PVMM_PROCESS pProcess, _In_opt_ POB_MAP pHiv CHAR szHiveFileNameShort[32+1] = { 0 }; CHAR szHiveFileNameLong[72] = { 0 }; POB_REGISTRY_HIVE pObHive = NULL; - PVMMWIN_REGISTRY_OFFSET po = &ctxVmm->pRegistry->Offset; + PVMMWIN_REGISTRY_OFFSET po = &H->vmm.pRegistry->Offset; // 1: validity check f = VMM_KADDR64_16(vaData) && pHiveMap && @@ -751,7 +756,7 @@ VOID VmmWinReg_EnumHive64_Post(_In_ PVMM_PROCESS pProcess, _In_opt_ POB_MAP pHiv (*(PDWORD)(pbData + po->CM.Length0) <= 0x40000000); // Length < 1GB if(!f) { return; } // 2: Allocate and Initialize - if(!(pObHive = Ob_Alloc(OB_TAG_REG_HIVE, LMEM_ZEROINIT, sizeof(OB_REGISTRY_HIVE), (OB_CLEANUP_CB)VmmWinReg_CallbackCleanup_ObRegistryHive, NULL))) { return; } + if(!(pObHive = Ob_AllocEx(H, OB_TAG_REG_HIVE, LMEM_ZEROINIT, sizeof(OB_REGISTRY_HIVE), (OB_CLEANUP_CB)VmmWinReg_CallbackCleanup_ObRegistryHive, NULL))) { return; } pObHive->vaCMHIVE = vaData; pObHive->vaHBASE_BLOCK = *(PQWORD)(pbData + po->CM.BaseBlock); pObHive->cbLength = *(PDWORD)(pbData + po->CM.Length0); @@ -764,6 +769,7 @@ VOID VmmWinReg_EnumHive64_Post(_In_ PVMM_PROCESS pProcess, _In_opt_ POB_MAP pHiv InitializeCriticalSection(&pObHive->LockUpdate); //_HBASE_BLOCK.FileName VmmReadWtoU( + H, pProcess, *(PQWORD)(pbData + po->CM.BaseBlock) + po->BB.FileName, 2 * _countof(pObHive->uszNameShort) - 2, @@ -776,6 +782,7 @@ VOID VmmWinReg_EnumHive64_Post(_In_ PVMM_PROCESS pProcess, _In_opt_ POB_MAP pHiv ); if(po->CM.HiveRootPathOpt && *(PQWORD)(pbData + po->CM.HiveRootPathOpt)) { // _CMHIVE.HiveRootPath VmmReadWtoU( + H, pProcess, *(PQWORD)(pbData + po->CM.HiveRootPathOpt + 8), min(*(PWORD)(pbData + po->CM.HiveRootPathOpt), 2 * _countof(pObHive->uszHiveRootPath) - 2), @@ -789,6 +796,7 @@ VOID VmmWinReg_EnumHive64_Post(_In_ PVMM_PROCESS pProcess, _In_opt_ POB_MAP pHiv } if(!pObHive->uszHiveRootPath[0] && po->CM.FileUserNameOpt && *(PQWORD)(pbData + po->CM.FileUserNameOpt)) { // _CMHIVE.FileUserName (as backup to _CMHIVE.HiveRootPath) VmmReadWtoU( + H, pProcess, *(PQWORD)(pbData + po->CM.FileUserNameOpt + 8), min(*(PWORD)(pbData + po->CM.FileUserNameOpt), 2 * _countof(pObHive->uszHiveRootPath) - 2), @@ -815,11 +823,11 @@ VOID VmmWinReg_EnumHive64_Post(_In_ PVMM_PROCESS pProcess, _In_opt_ POB_MAP pHiv (szHiveFileNameLong[0] ? szHiveFileNameLong : "unknown")); // 4: Attach and Return ObMap_Push(pHiveMap, pObHive->vaCMHIVE, pObHive); - VmmLog(MID_REGISTRY, LOGLEVEL_DEBUG, "HIVE_ENUM: %04i: %s", ObMap_Size(pHiveMap), pObHive->uszName); + VmmLog(H, MID_REGISTRY, LOGLEVEL_DEBUG, "HIVE_ENUM: %04i: %s", ObMap_Size(pHiveMap), pObHive->uszName); Ob_DECREF(pObHive); } -VOID VmmWinReg_EnumHive32_Post(_In_ PVMM_PROCESS pProcess, _In_opt_ POB_MAP pHiveMap, _In_ QWORD vaData, _In_ PBYTE pbData, _In_ DWORD cbData) +VOID VmmWinReg_EnumHive32_Post(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ POB_MAP pHiveMap, _In_ QWORD vaData, _In_ PBYTE pbData, _In_ DWORD cbData) { BOOL f; CHAR chDefault = '_'; @@ -827,7 +835,7 @@ VOID VmmWinReg_EnumHive32_Post(_In_ PVMM_PROCESS pProcess, _In_opt_ POB_MAP pHiv CHAR szHiveFileNameShort[32+1] = { 0 }; CHAR szHiveFileNameLong[72] = { 0 }; POB_REGISTRY_HIVE pObHive = NULL; - PVMMWIN_REGISTRY_OFFSET po = &ctxVmm->pRegistry->Offset; + PVMMWIN_REGISTRY_OFFSET po = &H->vmm.pRegistry->Offset; // 1: validity check f = VMM_KADDR32_8(vaData) && pHiveMap && @@ -838,7 +846,7 @@ VOID VmmWinReg_EnumHive32_Post(_In_ PVMM_PROCESS pProcess, _In_opt_ POB_MAP pHiv (*(PDWORD)(pbData + po->CM.Length0) <= 0x40000000); // Length < 1GB if(!f) { return; } // 2: Allocate and Initialize - if(!(pObHive = Ob_Alloc(OB_TAG_REG_HIVE, LMEM_ZEROINIT, sizeof(OB_REGISTRY_HIVE), (OB_CLEANUP_CB)VmmWinReg_CallbackCleanup_ObRegistryHive, NULL))) { return; } + if(!(pObHive = Ob_AllocEx(H, OB_TAG_REG_HIVE, LMEM_ZEROINIT, sizeof(OB_REGISTRY_HIVE), (OB_CLEANUP_CB)VmmWinReg_CallbackCleanup_ObRegistryHive, NULL))) { return; } pObHive->vaCMHIVE = vaData; pObHive->vaHBASE_BLOCK = *(PDWORD)(pbData + po->CM.BaseBlock); pObHive->cbLength = *(PDWORD)(pbData + po->CM.Length0); @@ -851,6 +859,7 @@ VOID VmmWinReg_EnumHive32_Post(_In_ PVMM_PROCESS pProcess, _In_opt_ POB_MAP pHiv InitializeCriticalSection(&pObHive->LockUpdate); //_HBASE_BLOCK.FileName VmmReadWtoU( + H, pProcess, (QWORD)*(PDWORD)(pbData + po->CM.BaseBlock) + po->BB.FileName, 2 * _countof(pObHive->uszNameShort) - 2, @@ -863,6 +872,7 @@ VOID VmmWinReg_EnumHive32_Post(_In_ PVMM_PROCESS pProcess, _In_opt_ POB_MAP pHiv ); if(po->CM.HiveRootPathOpt && *(PQWORD)(pbData + po->CM.HiveRootPathOpt)) { // _CMHIVE.HiveRootPath VmmReadWtoU( + H, pProcess, *(PDWORD)(pbData + po->CM.HiveRootPathOpt + 4), min(*(PWORD)(pbData + po->CM.HiveRootPathOpt), 2 * _countof(pObHive->uszHiveRootPath) - 2), @@ -876,6 +886,7 @@ VOID VmmWinReg_EnumHive32_Post(_In_ PVMM_PROCESS pProcess, _In_opt_ POB_MAP pHiv } if(!pObHive->uszHiveRootPath[0] && po->CM.FileUserNameOpt && *(PQWORD)(pbData + po->CM.FileUserNameOpt)) { // _CMHIVE.FileUserName (as backup to _CMHIVE.HiveRootPath) VmmReadWtoU( + H, pProcess, *(PDWORD)(pbData + po->CM.FileUserNameOpt + 4), min(*(PWORD)(pbData + po->CM.FileUserNameOpt), 2 * _countof(pObHive->uszHiveRootPath) - 2), @@ -902,37 +913,38 @@ VOID VmmWinReg_EnumHive32_Post(_In_ PVMM_PROCESS pProcess, _In_opt_ POB_MAP pHiv (szHiveFileNameLong[0] ? szHiveFileNameLong : "unknown")); // 4: Attach and Return ObMap_Push(pHiveMap, pObHive->vaCMHIVE, pObHive); // pRegistry->pmHive takes responsibility for pObHive reference - VmmLog(MID_REGISTRY, LOGLEVEL_DEBUG, "HIVE_ENUM: %04i: %s", ObMap_Size(pHiveMap), pObHive->uszName); + VmmLog(H, MID_REGISTRY, LOGLEVEL_DEBUG, "HIVE_ENUM: %04i: %s", ObMap_Size(pHiveMap), pObHive->uszName); } /* * Internal function to create / set up a new registry objects. * NB! This function must NOT be called in a multi-threaded way. * CALLER DECREF: return +* -- H * -- return */ -POB_MAP VmmWinReg_HiveMap_New() +POB_MAP VmmWinReg_HiveMap_New(_In_ VMM_HANDLE H) { - BOOL f32 = ctxVmm->f32; + BOOL f32 = H->vmm.f32; POB_MAP pObHiveMap = NULL; - POB_REGISTRY_HIVE pHiveCurrent = NULL; PVMM_PROCESS pObProcessSystem = NULL; - if(!(pObProcessSystem = VmmProcessGet(4))) { goto fail; } - if(!ctxVmm->pRegistry->Offset.vaHintCMHIVE && !VmmWinReg_LocateRegistryHive()) { goto fail; } - if(!(pObHiveMap = ObMap_New(OB_MAP_FLAGS_OBJECT_OB))) { goto fail; } + if(!(pObProcessSystem = VmmProcessGet(H, 4))) { goto fail; } + if(!H->vmm.pRegistry->Offset.vaHintCMHIVE && !VmmWinReg_LocateRegistryHive(H)) { goto fail; } + if(!(pObHiveMap = ObMap_New(H, OB_MAP_FLAGS_OBJECT_OB))) { goto fail; } // Traverse the CMHIVE linked list in an efficient way VmmWin_ListTraversePrefetch( + H, pObProcessSystem, f32, pObHiveMap, 1, - &ctxVmm->pRegistry->Offset.vaHintCMHIVE, - ctxVmm->pRegistry->Offset.CM.FLinkAll, - ctxVmm->pRegistry->Offset.CM._Size, + &H->vmm.pRegistry->Offset.vaHintCMHIVE, + H->vmm.pRegistry->Offset.CM.FLinkAll, + H->vmm.pRegistry->Offset.CM._Size, (VMMWIN_LISTTRAVERSE_PRE_CB)(f32 ? VmmWinReg_EnumHive32_Pre : VmmWinReg_EnumHive64_Pre), (VMMWIN_LISTTRAVERSE_POST_CB)(f32 ? VmmWinReg_EnumHive32_Post : VmmWinReg_EnumHive64_Post), - ctxVmm->pObCCachePrefetchRegistry); - ObContainer_SetOb(ctxVmm->pRegistry->pObCHiveMap, pObHiveMap); + H->vmm.pObCCachePrefetchRegistry); + ObContainer_SetOb(H->vmm.pRegistry->pObCHiveMap, pObHiveMap); Ob_DECREF(pObProcessSystem); return pObHiveMap; fail: @@ -945,26 +957,27 @@ fail: * Retrieve the hive map containing the hive objects. * If the map is not yet initialized this call will initalize the hive map. * CALLER DECREF: return +* -- H * -- return = a map containing the hive objects */ -POB_MAP VmmWinReg_HiveMap() +POB_MAP VmmWinReg_HiveMap(_In_ VMM_HANDLE H) { POB_MAP pObHiveMap; - if(!ctxVmm->pRegistry) { return NULL; } - pObHiveMap = ObContainer_GetOb(ctxVmm->pRegistry->pObCHiveMap); + if(!H->vmm.pRegistry) { return NULL; } + pObHiveMap = ObContainer_GetOb(H->vmm.pRegistry->pObCHiveMap); if(!pObHiveMap) { - EnterCriticalSection(&ctxVmm->pRegistry->LockUpdate); - pObHiveMap = ObContainer_GetOb(ctxVmm->pRegistry->pObCHiveMap); + EnterCriticalSection(&H->vmm.pRegistry->LockUpdate); + pObHiveMap = ObContainer_GetOb(H->vmm.pRegistry->pObCHiveMap); if(!pObHiveMap) { - pObHiveMap = VmmWinReg_HiveMap_New(); + pObHiveMap = VmmWinReg_HiveMap_New(H); } - LeaveCriticalSection(&ctxVmm->pRegistry->LockUpdate); + LeaveCriticalSection(&H->vmm.pRegistry->LockUpdate); } return pObHiveMap; } _Success_(return) -BOOL VmmWinReg_KeyInitialize(_In_ POB_REGISTRY_HIVE pHive); +BOOL VmmWinReg_KeyInitialize(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive); /* * Ensure a registry hive snapshot is taken of the hive and stored within the @@ -972,11 +985,12 @@ BOOL VmmWinReg_KeyInitialize(_In_ POB_REGISTRY_HIVE pHive); * memory and performing analysis on it to generate a key tree for convenient * parsing of the keys. Any keys derived from the hive must never be used after * Ob_DECREF has been called on the hive. +* -- H * -- pHive * -- return */ _Success_(return) -BOOL VmmWinReg_HiveSnapshotEnsure(_In_ POB_REGISTRY_HIVE pHive) +BOOL VmmWinReg_HiveSnapshotEnsure(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive) { DWORD i, cbRead; // 1: check already cached @@ -990,15 +1004,15 @@ BOOL VmmWinReg_HiveSnapshotEnsure(_In_ POB_REGISTRY_HIVE pHive) return TRUE; } // 3: allocate new - pHive->Snapshot.pmKeyHash = ObMap_New(OB_MAP_FLAGS_OBJECT_OB); - pHive->Snapshot.pmKeyOffset = ObMap_New(OB_MAP_FLAGS_OBJECT_OB); + pHive->Snapshot.pmKeyHash = ObMap_New(H, OB_MAP_FLAGS_OBJECT_OB); + pHive->Snapshot.pmKeyOffset = ObMap_New(H, OB_MAP_FLAGS_OBJECT_OB); if(!pHive->Snapshot.pmKeyHash || !pHive->Snapshot.pmKeyOffset) { goto fail; } for(i = 0; i < 2; i++) { pHive->Snapshot._DUAL[i].cb = pHive->_DUAL[i].cb; if(!(pHive->Snapshot._DUAL[i].pb = LocalAlloc(0, pHive->Snapshot._DUAL[i].cb))) { goto fail; } - VmmWinReg_HiveReadEx(pHive, (i ? 0x80000000 : 0), pHive->Snapshot._DUAL[i].pb, pHive->Snapshot._DUAL[i].cb, &cbRead, VMM_FLAG_ZEROPAD_ON_FAIL); + VmmWinReg_HiveReadEx(H, pHive, (i ? 0x80000000 : 0), pHive->Snapshot._DUAL[i].pb, pHive->Snapshot._DUAL[i].cb, &cbRead, VMM_FLAG_ZEROPAD_ON_FAIL); } - if(!VmmWinReg_KeyInitialize(pHive)) { goto fail; } + if(!VmmWinReg_KeyInitialize(H, pHive)) { goto fail; } pHive->Snapshot.fInitialized = TRUE; LeaveCriticalSection(&pHive->LockUpdate); return TRUE; @@ -1019,13 +1033,13 @@ fail: // EXPORTED INITIALIZATION/REFRESH/CLOSE FUNCTIONALITY BELOW: //----------------------------------------------------------------------------- -VOID VmmWinReg_Initialize() +VOID VmmWinReg_Initialize(_In_ VMM_HANDLE H) { PVMMWIN_REGISTRY_CONTEXT ctx; if(!(ctx = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMWIN_REGISTRY_CONTEXT)))) { goto fail; } if(!(ctx->pObCHiveMap = ObContainer_New())) { goto fail; } InitializeCriticalSection(&ctx->LockUpdate); - ctxVmm->pRegistry = ctx; + H->vmm.pRegistry = ctx; return; fail: if(ctx) { @@ -1034,20 +1048,20 @@ fail: } } -VOID VmmWinReg_Close() +VOID VmmWinReg_Close(_In_ VMM_HANDLE H) { - if(ctxVmm->pRegistry) { - Ob_DECREF(ctxVmm->pRegistry->pObCHiveMap); - DeleteCriticalSection(&ctxVmm->pRegistry->LockUpdate); - LocalFree(ctxVmm->pRegistry); - ctxVmm->pRegistry = NULL; + if(H->vmm.pRegistry) { + Ob_DECREF(H->vmm.pRegistry->pObCHiveMap); + DeleteCriticalSection(&H->vmm.pRegistry->LockUpdate); + LocalFree(H->vmm.pRegistry); + H->vmm.pRegistry = NULL; } } -VOID VmmWinReg_Refresh() +VOID VmmWinReg_Refresh(_In_ VMM_HANDLE H) { - if(ctxVmm->pRegistry) { - ObContainer_SetOb(ctxVmm->pRegistry->pObCHiveMap, NULL); + if(H->vmm.pRegistry) { + ObContainer_SetOb(H->vmm.pRegistry->pObCHiveMap, NULL); } } @@ -1057,20 +1071,20 @@ VOID VmmWinReg_Refresh() // EXPORTED HIVE FUNCTIONALITY BELOW: //----------------------------------------------------------------------------- -DWORD VmmWinReg_HiveCount() +DWORD VmmWinReg_HiveCount(_In_ VMM_HANDLE H) { DWORD c; - POB_MAP pObHiveMap = VmmWinReg_HiveMap(); + POB_MAP pObHiveMap = VmmWinReg_HiveMap(H); c = ObMap_Size(pObHiveMap); Ob_DECREF(pObHiveMap); return c; } -POB_REGISTRY_HIVE VmmWinReg_HiveGetNext(_In_opt_ POB_REGISTRY_HIVE pObRegistryHive) +POB_REGISTRY_HIVE VmmWinReg_HiveGetNext(_In_ VMM_HANDLE H, _In_opt_ POB_REGISTRY_HIVE pObRegistryHive) { POB_MAP pObHiveMap; POB_REGISTRY_HIVE pObRegistryHiveReturn = NULL; - if((pObHiveMap = VmmWinReg_HiveMap())) { + if((pObHiveMap = VmmWinReg_HiveMap(H))) { pObRegistryHiveReturn = ObMap_GetNextByKey(pObHiveMap, (pObRegistryHive ? pObRegistryHive->vaCMHIVE : 0), pObRegistryHive); pObRegistryHive = NULL; } @@ -1079,11 +1093,11 @@ POB_REGISTRY_HIVE VmmWinReg_HiveGetNext(_In_opt_ POB_REGISTRY_HIVE pObRegistryHi return pObRegistryHiveReturn; } -POB_REGISTRY_HIVE VmmWinReg_HiveGetByAddress(_In_ QWORD vaCMHIVE) +POB_REGISTRY_HIVE VmmWinReg_HiveGetByAddress(_In_ VMM_HANDLE H, _In_ QWORD vaCMHIVE) { POB_MAP pObHiveMap; POB_REGISTRY_HIVE pObRegistryHiveReturn = NULL; - if((pObHiveMap = VmmWinReg_HiveMap())) { + if((pObHiveMap = VmmWinReg_HiveMap(H))) { pObRegistryHiveReturn = ObMap_GetByKey(pObHiveMap, vaCMHIVE); } Ob_DECREF(pObHiveMap); @@ -1295,12 +1309,13 @@ VOID VmmWinReg_KeyInitializeCreateKey_AddChild(_In_opt_ POB_REGISTRY_KEY pObKeyP /* * Try to create a new key from a given hbin offset. * CALLER DECREF: return +* -- H * -- pHive * -- oCell * -- iLevel * -- return */ -POB_REGISTRY_KEY VmmWinReg_KeyInitializeCreateKey(_In_ POB_REGISTRY_HIVE pHive, _In_ DWORD oCell, _In_ DWORD iLevel) +POB_REGISTRY_KEY VmmWinReg_KeyInitializeCreateKey(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_ DWORD oCell, _In_ DWORD iLevel) { QWORD qwKeyHash; WORD iSuffix = 0; @@ -1327,7 +1342,7 @@ POB_REGISTRY_KEY VmmWinReg_KeyInitializeCreateKey(_In_ POB_REGISTRY_HIVE pHive, pObKeyParent = ObMap_GetByKey(pHive->Snapshot.pmKeyOffset, pnk->Parent); if(!pObKeyParent) { if(iLevel < 0x10) { - pObKeyParent = VmmWinReg_KeyInitializeCreateKey(pHive, pnk->Parent, iLevel + 1); + pObKeyParent = VmmWinReg_KeyInitializeCreateKey(H, pHive, pnk->Parent, iLevel + 1); } if(!pObKeyParent) { pObKeyParent = ObMap_GetByKey(pHive->Snapshot.pmKeyOffset, pnk->Parent); @@ -1348,7 +1363,7 @@ POB_REGISTRY_KEY VmmWinReg_KeyInitializeCreateKey(_In_ POB_REGISTRY_HIVE pHive, iSuffix++; } // 5: allocate and prepare - pObKey = Ob_Alloc(OB_TAG_REG_KEY, LMEM_ZEROINIT, sizeof(OB_REGISTRY_KEY), (OB_CLEANUP_CB)VmmWinReg_CallbackCleanup_ObRegKey, NULL); + pObKey = Ob_AllocEx(H, OB_TAG_REG_KEY, LMEM_ZEROINIT, sizeof(OB_REGISTRY_KEY), (OB_CLEANUP_CB)VmmWinReg_CallbackCleanup_ObRegKey, NULL); if(!pObKey) { goto fail; } pObKey->dwCellHead = dwCellHead; pObKey->iSuffix = iSuffix; @@ -1360,24 +1375,23 @@ POB_REGISTRY_KEY VmmWinReg_KeyInitializeCreateKey(_In_ POB_REGISTRY_HIVE pHive, pObKey->qwHashKeyThis = VmmWinReg_KeyHashName(pnk, iSuffix) + ((pObKey->qwHashKeyParent >> 13) | (pObKey->qwHashKeyParent << 51)); // 7: store to cache if(!ObMap_Push(pHive->Snapshot.pmKeyOffset, oCell, pObKey)) { - VmmLog(MID_REGISTRY, LOGLEVEL_WARNING, "SHOULD NOT HAPPEN #1"); + VmmLog(H, MID_REGISTRY, LOGLEVEL_WARNING, "SHOULD NOT HAPPEN #1"); } if(!ObMap_Push(pHive->Snapshot.pmKeyHash, pObKey->qwHashKeyThis, pObKey)) { - VmmLog(MID_REGISTRY, LOGLEVEL_WARNING, "SHOULD NOT HAPPEN #2"); + VmmLog(H, MID_REGISTRY, LOGLEVEL_WARNING, "SHOULD NOT HAPPEN #2"); } VmmWinReg_KeyInitializeCreateKey_AddChild(pObKeyParent, oCell); - Ob_DECREF(pObKeyParent); - return pObKey; + Ob_INCREF(pObKey); fail: - Ob_DECREF(pObKey); Ob_DECREF(pObKeyParent); - return NULL; + return Ob_DECREF(pObKey); } /* * Create a dummy key - used to create 'ROOT' and 'ORPHAN' root keys. * (Helper function to VmmWinReg_KeyInitializeRootKey) * CALLER DECREF: return +* -- H * -- pHive * -- oCell * -- qwKeyParentHash @@ -1385,14 +1399,14 @@ fail: * -- fActive * -- return */ -POB_REGISTRY_KEY VmmWinReg_KeyInitializeRootKeyDummy(_In_ POB_REGISTRY_HIVE pHive, _In_ DWORD oCell, _In_ QWORD qwKeyParentHash, _In_ LPSTR uszName, _In_ BOOL fActive) +POB_REGISTRY_KEY VmmWinReg_KeyInitializeRootKeyDummy(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_ DWORD oCell, _In_ QWORD qwKeyParentHash, _In_ LPSTR uszName, _In_ BOOL fActive) { DWORD cbw; WORD cbuName; POB_REGISTRY_KEY pObKey = NULL; cbuName = (WORD)(strlen(uszName) + 1); // 1: allocate dummy entry - pObKey = Ob_Alloc(OB_TAG_REG_KEY, LMEM_ZEROINIT, sizeof(OB_REGISTRY_KEY) + REG_CM_KEY_NODE_SIZEOF + 2ULL * cbuName, (OB_CLEANUP_CB)VmmWinReg_CallbackCleanup_ObRegKey, NULL); + pObKey = Ob_AllocEx(H, OB_TAG_REG_KEY, LMEM_ZEROINIT, sizeof(OB_REGISTRY_KEY) + REG_CM_KEY_NODE_SIZEOF + 2ULL * cbuName, (OB_CLEANUP_CB)VmmWinReg_CallbackCleanup_ObRegKey, NULL); if(!pObKey) { return NULL; } pObKey->oCell = oCell; pObKey->cbCell = 4 + REG_CM_KEY_NODE_SIZEOF + cbuName * 2ULL - 2; @@ -1411,18 +1425,18 @@ POB_REGISTRY_KEY VmmWinReg_KeyInitializeRootKeyDummy(_In_ POB_REGISTRY_HIVE pHiv /* * Create a dummy key - used to create 'ROOT' and 'ORPHAN' root keys. +* -- H * -- pHive * -- return */ _Success_(return) -BOOL VmmWinReg_KeyInitializeRootKey(_In_ POB_REGISTRY_HIVE pHive) +BOOL VmmWinReg_KeyInitializeRootKey(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive) { PREG_CM_KEY_NODE pnk; DWORD i, oRootKey = -1, cbCell, cbKey; - POB_REGISTRY_KEY pObKeyRoot = NULL; QWORD qwKeyRootHash = 0; // 1: get root key offset from regf-header (this is most often 0x20) - if(!VmmRead(PVMM_PROCESS_SYSTEM, pHive->vaHBASE_BLOCK + 0x24, (PBYTE)&oRootKey, sizeof(DWORD)) || !oRootKey || (oRootKey > pHive->Snapshot._DUAL[0].cb - REG_CM_KEY_NODE_SIZEOF)) { + if(!VmmRead(H, PVMM_PROCESS_SYSTEM, pHive->vaHBASE_BLOCK + 0x24, (PBYTE)&oRootKey, sizeof(DWORD)) || !oRootKey || (oRootKey > pHive->Snapshot._DUAL[0].cb - REG_CM_KEY_NODE_SIZEOF)) { // regf base block unreadable or corrupt - try locate root key in 1st hive page i = 0x20; while(TRUE) { @@ -1438,8 +1452,8 @@ BOOL VmmWinReg_KeyInitializeRootKey(_In_ POB_REGISTRY_HIVE pHive) break; } } - Ob_DECREF(VmmWinReg_KeyInitializeRootKeyDummy(pHive, oRootKey, 0, "ROOT", TRUE)); - Ob_DECREF(VmmWinReg_KeyInitializeRootKeyDummy(pHive, 0x7ffffffe, 0, "ORPHAN", FALSE)); + Ob_DECREF(VmmWinReg_KeyInitializeRootKeyDummy(H, pHive, oRootKey, 0, "ROOT", TRUE)); + Ob_DECREF(VmmWinReg_KeyInitializeRootKeyDummy(H, pHive, 0x7ffffffe, 0, "ORPHAN", FALSE)); return TRUE; } @@ -1448,14 +1462,15 @@ BOOL VmmWinReg_KeyInitializeRootKey(_In_ POB_REGISTRY_HIVE pHive) * contents into memory then walking the complete hive to try to find and index * relations beteen parent-child registry keys - which are then stored into * hash maps for faster lookups. +* -- H * -- pHive * -- return */ _Success_(return) -BOOL VmmWinReg_KeyInitialize(_In_ POB_REGISTRY_HIVE pHive) +BOOL VmmWinReg_KeyInitialize(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive) { DWORD oCell, dwSignature, cbCell, cbHbin, iSV, iHbin; - if(!VmmWinReg_KeyInitializeRootKey(pHive)) { return FALSE; } + if(!VmmWinReg_KeyInitializeRootKey(H, pHive)) { return FALSE; } for(iSV = 0; iSV < 2; iSV++) { iHbin = 0; while(iHbin < (pHive->Snapshot._DUAL[iSV].cb & ~0xfff)) { @@ -1465,14 +1480,15 @@ BOOL VmmWinReg_KeyInitialize(_In_ POB_REGISTRY_HIVE pHive) continue; } if(dwSignature != REG_SIGNATURE_HBIN) { - VmmLog(MID_REGISTRY, LOGLEVEL_DEBUG, "BAD HBIN HEADER: Hive=%016llx HBin=%08x Sig=%08x", pHive->vaCMHIVE, ((iSV << 31) | iHbin), dwSignature); + VmmLog(H, MID_REGISTRY, LOGLEVEL_DEBUG, "BAD HBIN HEADER: Hive=%016llx HBin=%08x Sig=%08x", pHive->vaCMHIVE, ((iSV << 31) | iHbin), dwSignature); iHbin += 0x1000; continue; } cbHbin = *(PDWORD)(pHive->Snapshot._DUAL[iSV].pb + iHbin + 8); + cbHbin = min(cbHbin, pHive->Snapshot._DUAL[iSV].cb - iHbin); if((cbHbin & 0xfff) || (cbHbin > 0x10000)) { cbHbin = 0x1000; } oCell = 0x20; - while(oCell < cbHbin) { + while(oCell + 4 < cbHbin) { cbCell = REG_CELL_SIZE_EX(pHive->Snapshot._DUAL[iSV].pb, (QWORD)iHbin + oCell); if(!cbCell || (oCell + cbCell) > cbHbin) { oCell += 4; @@ -1483,7 +1499,7 @@ BOOL VmmWinReg_KeyInitialize(_In_ POB_REGISTRY_HIVE pHive) continue; } if(REG_CM_KEY_SIGNATURE_KEYNODE == *(PWORD)(pHive->Snapshot._DUAL[iSV].pb + iHbin + oCell + 4)) { - Ob_DECREF(VmmWinReg_KeyInitializeCreateKey(pHive, iHbin + oCell + (iSV ? 0x80000000 : 0), 0)); + Ob_DECREF(VmmWinReg_KeyInitializeCreateKey(H, pHive, iHbin + oCell + (iSV ? 0x80000000 : 0), 0)); } oCell += (cbCell + 3) & ~0x3; } @@ -1495,11 +1511,12 @@ BOOL VmmWinReg_KeyInitialize(_In_ POB_REGISTRY_HIVE pHive) /* * Try to create a key-value object manager object from the given cell offset. +* -- H * -- pHive * -- oCell = offset to cell (incl. static/volatile bit). * -- return */ -POB_REGISTRY_VALUE VmmWinReg_KeyValueGetByOffset(_In_ POB_REGISTRY_HIVE pHive, _In_ DWORD oCell) +POB_REGISTRY_VALUE VmmWinReg_KeyValueGetByOffset(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_ DWORD oCell) { DWORD dwCellHead, cbCell, cbKeyValue; PREG_CM_KEY_VALUE pvk; @@ -1513,7 +1530,7 @@ POB_REGISTRY_VALUE VmmWinReg_KeyValueGetByOffset(_In_ POB_REGISTRY_HIVE pHive, _ if(pvk->Signature != REG_CM_KEY_SIGNATURE_KEYVALUE) { return NULL; } if(((QWORD)pvk->NameLength << ((pvk->Flags & REG_CM_KEY_VALUE_FLAGS_COMP_NAME) ? 0 : 1)) > (cbKeyValue - REG_CM_KEY_VALUE_SIZEOF)) { return NULL; } // 2: allocate and prepare - pObKeyValue = Ob_Alloc(OB_TAG_REG_KEYVALUE, LMEM_ZEROINIT, sizeof(OB_REGISTRY_VALUE), NULL, NULL); + pObKeyValue = Ob_AllocEx(H, OB_TAG_REG_KEYVALUE, LMEM_ZEROINIT, sizeof(OB_REGISTRY_VALUE), NULL, NULL); if(!pObKeyValue) { return NULL; } pObKeyValue->dwCellHead = dwCellHead; pObKeyValue->oCell = oCell; @@ -1525,12 +1542,13 @@ POB_REGISTRY_VALUE VmmWinReg_KeyValueGetByOffset(_In_ POB_REGISTRY_HIVE pHive, _ /* * Helper function (core functionality) for the VmmWinReg_ValueQuery1/VmmWinReg_ValueQueryInternal functions. * CALLER DECREF: return +* -- H * -- pHice * -- pKey * -- wszKeyValueName * -- return */ -POB_REGISTRY_VALUE VmmWinReg_ValueByKeyAndName(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY pKey, _In_ LPCSTR uszKeyValueName) +POB_REGISTRY_VALUE VmmWinReg_ValueByKeyAndName(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY pKey, _In_ LPCSTR uszKeyValueName) { DWORD cbListCell, iValues, cValues, *praValues; POB_REGISTRY_VALUE pObKeyValue; @@ -1544,7 +1562,7 @@ POB_REGISTRY_VALUE VmmWinReg_ValueByKeyAndName(_In_ POB_REGISTRY_HIVE pHive, _In cValues = min(pKey->pKey->ValueList.Count, (cbListCell - 4) >> 2); praValues = (PDWORD)(pbSnapshot + oListCellRaw + 4); for(iValues = 0; iValues < cValues; iValues++) { - pObKeyValue = VmmWinReg_KeyValueGetByOffset(pHive, praValues[iValues]); + pObKeyValue = VmmWinReg_KeyValueGetByOffset(H, pHive, praValues[iValues]); if(!pObKeyValue) { continue; } VmmWinReg_ValueInfo(pHive, pObKeyValue, &ValueInfo); if(!_stricmp(uszKeyValueName, ValueInfo.uszName)) { return pObKeyValue; } @@ -1694,13 +1712,14 @@ success: * Retrieve registry hive and key/value path from a "full" path starting with: * '0x...', 'by-hive\0x...' or 'HKLM\' * CALLER DECREF: *ppObHive +* -- H * -- uszPathFull * -- ppObHive * -- uszPathKeyValue * -- return */ _Success_(return) -BOOL VmmWinReg_PathHiveGetByFullPath(_In_ LPSTR uszPathFull, _Out_ POB_REGISTRY_HIVE *ppHive, _Out_writes_(MAX_PATH) LPSTR uszPathKeyValue) +BOOL VmmWinReg_PathHiveGetByFullPath(_In_ VMM_HANDLE H, _In_ LPSTR uszPathFull, _Out_ POB_REGISTRY_HIVE *ppHive, _Out_writes_(MAX_PATH) LPSTR uszPathKeyValue) { BOOL fUser = FALSE, fUserSystem = FALSE, fOrphan = FALSE; DWORD i; @@ -1723,16 +1742,16 @@ BOOL VmmWinReg_PathHiveGetByFullPath(_In_ LPSTR uszPathFull, _Out_ POB_REGISTRY_ if(strstr("LocalService", uszPath1)) { fUserSystem = TRUE; strncpy_s(uszPath1, sizeof(uszPath1), "NTUSERDAT-USER_S-1-5-19", _TRUNCATE); } if(strstr("NetworkService", uszPath1)) { fUserSystem = TRUE; strncpy_s(uszPath1, sizeof(uszPath1), "NTUSERDAT-USER_S-1-5-20", _TRUNCATE); } if(fUserSystem) { - while((pObHive = VmmWinReg_HiveGetNext(pObHive))) { + while((pObHive = VmmWinReg_HiveGetNext(H, pObHive))) { if(strstr(pObHive->uszName, uszPath1)) { *ppHive = pObHive; return TRUE; // CALLER DECREF: *ppHive } } - } else if(VmmMap_GetUser(&pObUserMap)) { + } else if(VmmMap_GetUser(H, &pObUserMap)) { for(i = 0; i < pObUserMap->cMap; i++) { if(strstr(pObUserMap->pMap[i].uszText, uszPath1)) { - *ppHive = VmmWinReg_HiveGetByAddress(pObUserMap->pMap[i].vaRegHive); + *ppHive = VmmWinReg_HiveGetByAddress(H, pObUserMap->pMap[i].vaRegHive); Ob_DECREF(pObUserMap); return (*ppHive != NULL); // CALLER DECREF: *ppHive } @@ -1740,21 +1759,21 @@ BOOL VmmWinReg_PathHiveGetByFullPath(_In_ LPSTR uszPathFull, _Out_ POB_REGISTRY_ Ob_DECREF_NULL(&pObUserMap); } } else { - while((pObHive = VmmWinReg_HiveGetNext(pObHive))) { + while((pObHive = VmmWinReg_HiveGetNext(H, pObHive))) { if(strstr(pObHive->uszNameShort, uszPath1)) { *ppHive = pObHive; return TRUE; // CALLER DECREF: *ppHive } } - while((pObHive = VmmWinReg_HiveGetNext(pObHive))) { + while((pObHive = VmmWinReg_HiveGetNext(H, pObHive))) { if(strstr(pObHive->uszHiveRootPath, uszPath1)) { *ppHive = pObHive; return TRUE; // CALLER DECREF: *ppHive } } if(!_stricmp(uszPath1, "HARDWARE")) { - while((pObHive = VmmWinReg_HiveGetNext(pObHive))) { - if(!pObHive->uszNameShort[0] && !pObHive->uszHiveRootPath[0] && (pObKey = VmmWinReg_KeyGetByPath(pObHive, "ROOT\\RESOURCEMAP"))) { + while((pObHive = VmmWinReg_HiveGetNext(H, pObHive))) { + if(!pObHive->uszNameShort[0] && !pObHive->uszHiveRootPath[0] && (pObKey = VmmWinReg_KeyGetByPath(H, pObHive, "ROOT\\RESOURCEMAP"))) { Ob_DECREF(pObKey); *ppHive = pObHive; return TRUE; // CALLER DECREF: *ppHive @@ -1768,7 +1787,7 @@ BOOL VmmWinReg_PathHiveGetByFullPath(_In_ LPSTR uszPathFull, _Out_ POB_REGISTRY_ if(!strncmp(uszPathFull, "by-hive\\", 8)) { uszPathFull += 8; } - *ppHive = VmmWinReg_HiveGetByAddress(Util_GetNumericA(uszPathFull)); + *ppHive = VmmWinReg_HiveGetByAddress(H, Util_GetNumericA(uszPathFull)); if(!*ppHive) { return FALSE; } usz = CharUtil_PathSplitNext(uszPathFull); CharUtil_UtoU(usz, -1, uszPathKeyValue, MAX_PATH, NULL, NULL, CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR | CHARUTIL_FLAG_STR_BUFONLY); @@ -1779,18 +1798,19 @@ BOOL VmmWinReg_PathHiveGetByFullPath(_In_ LPSTR uszPathFull, _Out_ POB_REGISTRY_ * Retrieve registry hive and key from a "full" path starting with: * '0x...', 'by-hive\0x...' or 'HKLM\' * CALLER DECREF: *ppObHive, *ppObKey +* -- H * -- uszPathFull * -- ppObHive * -- ppObKey * -- return */ _Success_(return) -BOOL VmmWinReg_KeyHiveGetByFullPath(_In_ LPSTR uszPathFull, _Out_ POB_REGISTRY_HIVE *ppObHive, _Out_opt_ POB_REGISTRY_KEY *ppObKey) +BOOL VmmWinReg_KeyHiveGetByFullPath(_In_ VMM_HANDLE H, _In_ LPSTR uszPathFull, _Out_ POB_REGISTRY_HIVE *ppObHive, _Out_opt_ POB_REGISTRY_KEY *ppObKey) { CHAR uszPathKey[MAX_PATH]; - if(!VmmWinReg_PathHiveGetByFullPath(uszPathFull, ppObHive, uszPathKey)) { return FALSE; } + if(!VmmWinReg_PathHiveGetByFullPath(H, uszPathFull, ppObHive, uszPathKey)) { return FALSE; } if(!ppObKey) { return TRUE; } - if((*ppObKey = VmmWinReg_KeyGetByPath(*ppObHive, uszPathKey))) { return TRUE; } + if((*ppObKey = VmmWinReg_KeyGetByPath(H, *ppObHive, uszPathKey))) { return TRUE; } Ob_DECREF_NULL(ppObHive); return FALSE; } @@ -1799,29 +1819,32 @@ BOOL VmmWinReg_KeyHiveGetByFullPath(_In_ LPSTR uszPathFull, _Out_ POB_REGISTRY_H * Retrieve a registry key by its path. If no registry key is found then NULL * will be returned. * CALLER DECREF: return +* -- H * -- pHive * -- uszPath * -- return */ _Success_(return != NULL) -POB_REGISTRY_KEY VmmWinReg_KeyGetByPath(_In_ POB_REGISTRY_HIVE pHive, _In_ LPSTR uszPath) +POB_REGISTRY_KEY VmmWinReg_KeyGetByPath(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_ LPSTR uszPath) { - if(!VmmWinReg_HiveSnapshotEnsure(pHive)) { return NULL; } + if(!VmmWinReg_HiveSnapshotEnsure(H, pHive)) { return NULL; } return (POB_REGISTRY_KEY)ObMap_GetByKey(pHive->Snapshot.pmKeyHash, CharUtil_HashPathFsU(uszPath)); } /* * Retrieve a registry key by parent key and name. * If no registry key is found then NULL is returned. +* CALLER DECREF: return +* -- H * -- pHive * -- pParentKey * -- uszChildName * -- return */ _Success_(return != NULL) -POB_REGISTRY_KEY VmmWinReg_KeyGetByChildName(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY pParentKey, _In_ LPSTR uszChildName) +POB_REGISTRY_KEY VmmWinReg_KeyGetByChildName(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY pParentKey, _In_ LPSTR uszChildName) { - if(!VmmWinReg_HiveSnapshotEnsure(pHive)) { return NULL; } + if(!VmmWinReg_HiveSnapshotEnsure(H, pHive)) { return NULL; } return (POB_REGISTRY_KEY)ObMap_GetByKey(pHive->Snapshot.pmKeyHash, VmmWinReg_KeyHashChildName(pParentKey, uszChildName)); } @@ -1829,14 +1852,15 @@ POB_REGISTRY_KEY VmmWinReg_KeyGetByChildName(_In_ POB_REGISTRY_HIVE pHive, _In_ * Retrieve a registry key by its cell offset (incl. static/volatile bit). * If no registry key is found then NULL will be returned. * CALLER DECREF: return +* -- H * -- pHive * -- raCellOffset * -- return */ _Success_(return != NULL) -POB_REGISTRY_KEY VmmWinReg_KeyGetByCellOffset(_In_ POB_REGISTRY_HIVE pHive, _In_ DWORD raCellOffset) +POB_REGISTRY_KEY VmmWinReg_KeyGetByCellOffset(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_ DWORD raCellOffset) { - if(!VmmWinReg_HiveSnapshotEnsure(pHive)) { return NULL; } + if(!VmmWinReg_HiveSnapshotEnsure(H, pHive)) { return NULL; } return (POB_REGISTRY_KEY)ObMap_GetByKey(pHive->Snapshot.pmKeyOffset, raCellOffset); } @@ -1845,17 +1869,18 @@ POB_REGISTRY_KEY VmmWinReg_KeyGetByCellOffset(_In_ POB_REGISTRY_HIVE pHive, _In_ * The resulting keys are returned in a no-key map (set). If no parent key is * given the root keys are returned. * CALLER DECREF: return +* -- H * -- pHive * -- pKeyParent * -- return */ -POB_MAP VmmWinReg_KeyList(_In_ POB_REGISTRY_HIVE pHive, _In_opt_ POB_REGISTRY_KEY pKeyParent) +POB_MAP VmmWinReg_KeyList(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_opt_ POB_REGISTRY_KEY pKeyParent) { DWORD i; POB_MAP pmObSubkeys; POB_REGISTRY_KEY pKeyChild; - if(!VmmWinReg_HiveSnapshotEnsure(pHive)) { return NULL; } - if(!(pmObSubkeys = ObMap_New(OB_MAP_FLAGS_OBJECT_OB | OB_MAP_FLAGS_NOKEY))) { return NULL; } + if(!VmmWinReg_HiveSnapshotEnsure(H, pHive)) { return NULL; } + if(!(pmObSubkeys = ObMap_New(H, OB_MAP_FLAGS_OBJECT_OB | OB_MAP_FLAGS_NOKEY))) { return NULL; } if(pKeyParent) { for(i = 0; i < pKeyParent->Child.c; i++) { pKeyChild = ObMap_GetByKey(pHive->Snapshot.pmKeyOffset, pKeyParent->Child.po[i]); @@ -1893,11 +1918,12 @@ VOID VmmWinReg_KeyInfo(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY pKey, /* * Retrieve information about a registry key - pKeyInfo->wszName = set to full path. +* -- H * -- pHive * -- pKey * -- pKeyInfo */ -VOID VmmWinReg_KeyInfo2(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY pKey, _Out_ PVMM_REGISTRY_KEY_INFO pKeyInfo) +VOID VmmWinReg_KeyInfo2(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY pKey, _Out_ PVMM_REGISTRY_KEY_INFO pKeyInfo) { POB_SET ps; QWORD qwHashKeyParent; @@ -1908,7 +1934,7 @@ VOID VmmWinReg_KeyInfo2(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY pKey CHAR szHiveShortName[33] = { 0 }; CHAR uszPath[MAX_PATH] = { 0 }; VmmWinReg_KeyInfo(pHive, pKey, pKeyInfo); - if(!(ps = ObSet_New())) { return; } + if(!(ps = ObSet_New(H))) { return; } ObSet_Push(ps, (QWORD)Ob_INCREF(pKey)); qwHashKeyParent = pKey->qwHashKeyParent; while((pObKey = ObMap_GetByKey(pHive->Snapshot.pmKeyHash, qwHashKeyParent))) { @@ -1942,11 +1968,12 @@ VOID VmmWinReg_KeyInfo2(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY pKey * Retrive registry values given a key. The resulting values are returned in a * no-key map (set). If no values are found the empty set or NULL are returned. * CALLER DECREF: return +* -- H * -- pHive * -- pKeyParent * -- return = ObMap of POB_REGISTRY_VALUE */ -POB_MAP VmmWinReg_KeyValueList(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY pKeyParent) +POB_MAP VmmWinReg_KeyValueList(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY pKeyParent) { DWORD cbListCell, iValues, cValues, *praValues; POB_REGISTRY_VALUE pObKeyValue; @@ -1954,15 +1981,15 @@ POB_MAP VmmWinReg_KeyValueList(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_K DWORD oListCellRaw = REG_CELL_ORAW(pKeyParent->pKey->ValueList.List); DWORD cbSnapshot = pHive->Snapshot._DUAL[REG_CELL_SV(pKeyParent->pKey->ValueList.List)].cb; PBYTE pbSnapshot = pHive->Snapshot._DUAL[REG_CELL_SV(pKeyParent->pKey->ValueList.List)].pb; - if(!VmmWinReg_HiveSnapshotEnsure(pHive)) { return NULL; } - if(!(pmObValues = ObMap_New(OB_MAP_FLAGS_OBJECT_OB | OB_MAP_FLAGS_NOKEY))) { return NULL; } + if(!VmmWinReg_HiveSnapshotEnsure(H, pHive)) { return NULL; } + if(!(pmObValues = ObMap_New(H, OB_MAP_FLAGS_OBJECT_OB | OB_MAP_FLAGS_NOKEY))) { return NULL; } if(!pKeyParent->pKey->ValueList.Count || (oListCellRaw > cbSnapshot - 8)) { return pmObValues; } if(!VmmWinReg_KeyValidateCellSize(pHive, pKeyParent->pKey->ValueList.List, 8, 0x1000)) { return pmObValues; } cbListCell = REG_CELL_SIZE_EX(pbSnapshot, oListCellRaw); cValues = min(pKeyParent->pKey->ValueList.Count, (cbListCell - 4) >> 2); praValues = (PDWORD)(pbSnapshot + oListCellRaw + 4); for(iValues = 0; iValues < cValues; iValues++) { - pObKeyValue = VmmWinReg_KeyValueGetByOffset(pHive, praValues[iValues]); + pObKeyValue = VmmWinReg_KeyValueGetByOffset(H, pHive, praValues[iValues]); ObMap_Push(pmObValues, 0, pObKeyValue); Ob_DECREF_NULL(&pObKeyValue); } @@ -1973,17 +2000,18 @@ POB_MAP VmmWinReg_KeyValueList(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_K * Retrive registry values given a key and value name. * NB! VmmWinReg_KeyValueList is the preferred function. * CALLER DECREF: return +* -- H * -- pHive * -- pKeyParent * -- uszValueName = value name or NULL for default. * -- return = registry value or NULL if not found. */ -POB_REGISTRY_VALUE VmmWinReg_KeyValueGetByName(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY pKeyParent, _In_ LPSTR uszValueName) +POB_REGISTRY_VALUE VmmWinReg_KeyValueGetByName(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY pKeyParent, _In_ LPSTR uszValueName) { POB_MAP pmObValues = NULL; POB_REGISTRY_VALUE pObValue = NULL; VMM_REGISTRY_VALUE_INFO ValueInfo = { 0 }; - if(!(pmObValues = VmmWinReg_KeyValueList(pHive, pKeyParent))) { return NULL; } + if(!(pmObValues = VmmWinReg_KeyValueList(H, pHive, pKeyParent))) { return NULL; } if(!uszValueName) { uszValueName = "(Default)"; } @@ -2021,6 +2049,7 @@ VOID VmmWinReg_ValueInfo(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_VALUE p /* * Read a registry value - similar to WINAPI function 'RegQueryValueEx'. +* -- H * -- pHive * -- uszPathKeyValue * -- pdwType @@ -2032,7 +2061,7 @@ VOID VmmWinReg_ValueInfo(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_VALUE p * -- return */ _Success_(return) -BOOL VmmWinReg_ValueQuery1(_In_ POB_REGISTRY_HIVE pHive, _In_ LPSTR uszPathKeyValue, _Out_opt_ PDWORD pdwType, _Out_opt_ PDWORD pra, _Out_writes_opt_(cb) PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbRead, _In_ QWORD cbOffset) +BOOL VmmWinReg_ValueQuery1(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_ LPSTR uszPathKeyValue, _Out_opt_ PDWORD pdwType, _Out_opt_ PDWORD pra, _Out_writes_opt_(cb) PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbRead, _In_ QWORD cbOffset) { BOOL f; LPSTR uszValueName; @@ -2040,10 +2069,10 @@ BOOL VmmWinReg_ValueQuery1(_In_ POB_REGISTRY_HIVE pHive, _In_ LPSTR uszPathKeyVa POB_REGISTRY_KEY pObKey = NULL; POB_REGISTRY_VALUE pObKeyValue = NULL; if(pcbRead) { *pcbRead = 0; } - f = VmmWinReg_HiveSnapshotEnsure(pHive) && + f = VmmWinReg_HiveSnapshotEnsure(H, pHive) && (uszValueName = CharUtil_PathSplitLastEx(uszPathKeyValue, uszPathKey, sizeof(uszPathKey))) && - (pObKey = VmmWinReg_KeyGetByPath(pHive, uszPathKey)) && - (pObKeyValue = VmmWinReg_ValueByKeyAndName(pHive, pObKey, uszValueName)) && + (pObKey = VmmWinReg_KeyGetByPath(H, pHive, uszPathKey)) && + (pObKeyValue = VmmWinReg_ValueByKeyAndName(H, pHive, pObKey, uszValueName)) && (pb ? VmmWinReg_ValueQueryInternal(pHive, pObKeyValue, pdwType, pra, NULL, pb, cb, pcbRead, (DWORD)cbOffset) : VmmWinReg_ValueQueryInternal(pHive, pObKeyValue, pdwType, pra, pcbRead, NULL, 0, NULL, 0)); Ob_DECREF(pObKeyValue); Ob_DECREF(pObKey); @@ -2052,6 +2081,7 @@ BOOL VmmWinReg_ValueQuery1(_In_ POB_REGISTRY_HIVE pHive, _In_ LPSTR uszPathKeyVa /* * Read a registry value - similar to WINAPI function 'RegQueryValueEx'. +* -- H * -- uszFullPathKeyValue * -- pdwType * -- pbData @@ -2060,19 +2090,20 @@ BOOL VmmWinReg_ValueQuery1(_In_ POB_REGISTRY_HIVE pHive, _In_ LPSTR uszPathKeyVa * -- return */ _Success_(return) -BOOL VmmWinReg_ValueQuery2(_In_ LPSTR uszFullPathKeyValue, _Out_opt_ PDWORD pdwType, _Out_writes_opt_(cbData) PBYTE pbData, _In_ DWORD cbData, _Out_opt_ PDWORD pcbData) +BOOL VmmWinReg_ValueQuery2(_In_ VMM_HANDLE H, _In_ LPSTR uszFullPathKeyValue, _Out_opt_ PDWORD pdwType, _Out_writes_opt_(cbData) PBYTE pbData, _In_ DWORD cbData, _Out_opt_ PDWORD pcbData) { BOOL f; CHAR uszPathKeyValue[MAX_PATH]; POB_REGISTRY_HIVE pObHive = NULL; - f = VmmWinReg_PathHiveGetByFullPath(uszFullPathKeyValue, &pObHive, uszPathKeyValue) && - VmmWinReg_ValueQuery1(pObHive, uszPathKeyValue, pdwType, NULL, pbData, cbData, pcbData, 0); + f = VmmWinReg_PathHiveGetByFullPath(H, uszFullPathKeyValue, &pObHive, uszPathKeyValue) && + VmmWinReg_ValueQuery1(H, pObHive, uszPathKeyValue, pdwType, NULL, pbData, cbData, pcbData, 0); Ob_DECREF(pObHive); return f; } /* * Read a registry value - similar to WINAPI function 'RegQueryValueEx'. +* -- H * -- pHive * -- uszPathKeyValue * -- pdwType @@ -2082,13 +2113,14 @@ BOOL VmmWinReg_ValueQuery2(_In_ LPSTR uszFullPathKeyValue, _Out_opt_ PDWORD pdwT * -- return */ _Success_(return) -BOOL VmmWinReg_ValueQuery3(_In_ POB_REGISTRY_HIVE pHive, _In_ LPSTR uszPathKeyValue, _Out_opt_ PDWORD pdwType, _Out_writes_opt_(cbData) PBYTE pbData, _In_ DWORD cbData, _Out_opt_ PDWORD pcbData) +BOOL VmmWinReg_ValueQuery3(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_ LPSTR uszPathKeyValue, _Out_opt_ PDWORD pdwType, _Out_writes_opt_(cbData) PBYTE pbData, _In_ DWORD cbData, _Out_opt_ PDWORD pcbData) { - return VmmWinReg_ValueQuery1(pHive, uszPathKeyValue, pdwType, NULL, pbData, cbData, pcbData, 0); + return VmmWinReg_ValueQuery1(H, pHive, uszPathKeyValue, pdwType, NULL, pbData, cbData, pcbData, 0); } /* * Read a registry value - similar to WINAPI function 'RegQueryValueEx'. +* -- H * -- pHive * -- pObKeyValue * -- pdwType @@ -2098,9 +2130,9 @@ BOOL VmmWinReg_ValueQuery3(_In_ POB_REGISTRY_HIVE pHive, _In_ LPSTR uszPathKeyVa * -- return */ _Success_(return) -BOOL VmmWinReg_ValueQuery4(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_VALUE pKeyValue, _Out_opt_ PDWORD pdwType, _Out_writes_opt_(cbData) PBYTE pbData, _In_ DWORD cbData, _Out_opt_ PDWORD pcbData) +BOOL VmmWinReg_ValueQuery4(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_VALUE pKeyValue, _Out_opt_ PDWORD pdwType, _Out_writes_opt_(cbData) PBYTE pbData, _In_ DWORD cbData, _Out_opt_ PDWORD pcbData) { - if(VmmWinReg_HiveSnapshotEnsure(pHive)) { + if(VmmWinReg_HiveSnapshotEnsure(H, pHive)) { return VmmWinReg_ValueQueryInternal(pHive, pKeyValue, pdwType, NULL, NULL, pbData, cbData, pcbData, 0); } if(pdwType) { *pdwType = 0; } @@ -2110,6 +2142,7 @@ BOOL VmmWinReg_ValueQuery4(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_VALUE /* * Read a registry value - similar to WINAPI function 'RegQueryValueEx'. +* -- H * -- pHive * -- pObKey * -- uszValueName @@ -2120,12 +2153,12 @@ BOOL VmmWinReg_ValueQuery4(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_VALUE * -- return */ _Success_(return) -BOOL VmmWinReg_ValueQuery5(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY pKey, _In_ LPSTR uszValueName, _Out_opt_ PDWORD pdwType, _Out_writes_opt_(cbData) PBYTE pbData, _In_ DWORD cbData, _Out_opt_ PDWORD pcbData) +BOOL VmmWinReg_ValueQuery5(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY pKey, _In_ LPSTR uszValueName, _Out_opt_ PDWORD pdwType, _Out_writes_opt_(cbData) PBYTE pbData, _In_ DWORD cbData, _Out_opt_ PDWORD pcbData) { BOOL fResult = FALSE; POB_REGISTRY_VALUE pObKeyValue; - if((pObKeyValue = VmmWinReg_KeyValueGetByName(pHive, pKey, uszValueName))) { - fResult = VmmWinReg_ValueQuery4(pHive, pObKeyValue, pdwType, pbData, cbData, pcbData); + if((pObKeyValue = VmmWinReg_KeyValueGetByName(H, pHive, pKey, uszValueName))) { + fResult = VmmWinReg_ValueQuery4(H, pHive, pObKeyValue, pdwType, pbData, cbData, pcbData); Ob_DECREF(pObKeyValue); } return fResult; @@ -2185,6 +2218,7 @@ VOID VmmWinReg_KeyFullPath(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY p * Function to allow the forensic sub-system to request extraction of all keys * and their values from a specific hive. The key information will be delivered * back to the forensic sub-system by the use of callback functions. +* -- H * -- pHive * -- hCallback1 * -- hCallback2 @@ -2193,12 +2227,13 @@ VOID VmmWinReg_KeyFullPath(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY p * -- pfnJsonValueCB */ VOID VmmWinReg_ForensicGetAllKeysAndValues( + _In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_ HANDLE hCallback1, _In_ HANDLE hCallback2, - _In_ VOID(*pfnKeyCB)(_In_ HANDLE hCallback1, _In_ HANDLE hCallback2, _In_ LPSTR uszPathName, _In_ QWORD vaHive, _In_ DWORD dwCell, _In_ DWORD dwCellParent, _In_ QWORD ftLastWrite), - _In_ VOID(*pfnJsonKeyCB)(_Inout_ PVMMWINREG_FORENSIC_CONTEXT ctx, _In_z_ LPSTR uszPathName, _In_ QWORD ftLastWrite), - _In_ VOID(*pfnJsonValueCB)(_Inout_ PVMMWINREG_FORENSIC_CONTEXT ctx) + _In_ VOID(*pfnKeyCB)(_In_ VMM_HANDLE H, _In_ HANDLE hCallback1, _In_ HANDLE hCallback2, _In_ LPSTR uszPathName, _In_ QWORD vaHive, _In_ DWORD dwCell, _In_ DWORD dwCellParent, _In_ QWORD ftLastWrite), + _In_ VOID(*pfnJsonKeyCB)(_In_ VMM_HANDLE H, _Inout_ PVMMWINREG_FORENSIC_CONTEXT ctx, _In_z_ LPSTR uszPathName, _In_ QWORD ftLastWrite), + _In_ VOID(*pfnJsonValueCB)(_In_ VMM_HANDLE H, _Inout_ PVMMWINREG_FORENSIC_CONTEXT ctx) ) { DWORD i, c, oHive, j, jMax; CHAR uszFullPath[1024]; @@ -2208,7 +2243,7 @@ VOID VmmWinReg_ForensicGetAllKeysAndValues( POB_REGISTRY_VALUE pObValue = NULL; PVMMWINREG_FORENSIC_CONTEXT ctx; if(!(ctx = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMWINREG_FORENSIC_CONTEXT)))) { return; } - if(VmmWinReg_HiveSnapshotEnsure(pHive)) { + if(VmmWinReg_HiveSnapshotEnsure(H, pHive)) { oHive = 0; uszHivePrefix = ""; if(pHive->uszHiveRootPath[oHive] == '\\') { @@ -2226,19 +2261,19 @@ VOID VmmWinReg_ForensicGetAllKeysAndValues( uszHivePrefix = "HKU\\"; } c = ObMap_Size(pHive->Snapshot.pmKeyOffset); - for(i = 0; i < c; i++) { + for(i = 0; ((i < c) && !H->fAbort); i++) { if((pObKey = ObMap_GetByIndex(pHive->Snapshot.pmKeyOffset, i))) { VmmWinReg_KeyFullPath(pHive, pObKey, uszHivePrefix, pHive->uszHiveRootPath + oHive, uszFullPath); // registry timeline: - pfnKeyCB(hCallback1, hCallback2, uszFullPath, pHive->vaCMHIVE, pObKey->oCell, pObKey->pKey->Parent, pObKey->pKey->LastWriteTime); + pfnKeyCB(H, hCallback1, hCallback2, uszFullPath, pHive->vaCMHIVE, pObKey->oCell, pObKey->pKey->Parent, pObKey->pKey->LastWriteTime); // registry json data: - pfnJsonKeyCB(ctx, uszFullPath, pObKey->pKey->LastWriteTime); - if((pmObValues = VmmWinReg_KeyValueList(pHive, pObKey))) { + pfnJsonKeyCB(H, ctx, uszFullPath, pObKey->pKey->LastWriteTime); + if((pmObValues = VmmWinReg_KeyValueList(H, pHive, pObKey))) { for(j = 0, jMax = ObMap_Size(pmObValues); j < jMax; j++) { if((pObValue = ObMap_GetByIndex(pmObValues, j))) { VmmWinReg_ValueInfo(pHive, pObValue, &ctx->value.info); VmmWinReg_ValueQueryInternal(pHive, pObValue, NULL, NULL, NULL, ctx->value.pb, sizeof(ctx->value.pb), &ctx->value.cb, 0); - pfnJsonValueCB(ctx); + pfnJsonValueCB(H, ctx); Ob_DECREF_NULL(&pObValue); } } diff --git a/vmm/vmmwinreg.h b/vmm/vmmwinreg.h index 89e5fbd..1fe8175 100644 --- a/vmm/vmmwinreg.h +++ b/vmm/vmmwinreg.h @@ -58,48 +58,55 @@ typedef struct tdOB_REGISTRY_VALUE *POB_REGISTRY_VALUE; /* * Initialize the Registry sub-system. This should ideally be done on Vmm Init(). +* -- H */ -VOID VmmWinReg_Initialize(); +VOID VmmWinReg_Initialize(_In_ VMM_HANDLE H); /* * Refresh the Registry sub-system. +* -- H */ -VOID VmmWinReg_Refresh(); +VOID VmmWinReg_Refresh(_In_ VMM_HANDLE H); /* * Cleanup the Registry sub-system. This should ideally be done on Vmm Close(). +* -- H */ -VOID VmmWinReg_Close(); +VOID VmmWinReg_Close(_In_ VMM_HANDLE H); /* * Retrieve the next registry hive given a registry hive. This may be useful * when iterating over registry hives. * FUNCTION DECREF: pObRegistryHive * CALLER DECREF: return +* -- H * -- pObRegistryHive = a registry hive struct, or NULL if first. NB! function DECREF's - pObRegistryHive and must not be used after call! * -- return = a registry hive struct, or NULL if not found. */ -POB_REGISTRY_HIVE VmmWinReg_HiveGetNext(_In_opt_ POB_REGISTRY_HIVE pObRegistryHive); +POB_REGISTRY_HIVE VmmWinReg_HiveGetNext(_In_ VMM_HANDLE H, _In_opt_ POB_REGISTRY_HIVE pObRegistryHive); /* * Retrieve the next registry hive given a hive address. * CALLER DECREF: return +* -- H * -- vaCMHIVE * -- return = a registry hive struct, or NULL if not found. */ -POB_REGISTRY_HIVE VmmWinReg_HiveGetByAddress(_In_ QWORD vaCMHIVE); +POB_REGISTRY_HIVE VmmWinReg_HiveGetByAddress(_In_ VMM_HANDLE H, _In_ QWORD vaCMHIVE); /* * Get the number of total registry hives. +* -- H * -- return */ -DWORD VmmWinReg_HiveCount(); +DWORD VmmWinReg_HiveCount(_In_ VMM_HANDLE H); /* * Read a contigious arbitrary amount of registry hive memory and report the * number of bytes read in pcbRead. * NB! Address space does not include regf registry hive file header! +* -- H * -- pRegistryHive * -- ra * -- pb @@ -107,11 +114,12 @@ DWORD VmmWinReg_HiveCount(); * -- pcbRead * -- flags = flags as in VMM_FLAG_* */ -VOID VmmWinReg_HiveReadEx(_In_ POB_REGISTRY_HIVE pRegistryHive, _In_ DWORD ra, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ QWORD flags); +VOID VmmWinReg_HiveReadEx(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pRegistryHive, _In_ DWORD ra, _Out_writes_(cb) PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ QWORD flags); /* * Write a virtually contigious arbitrary amount of memory. * NB! Address space does not include regf registry hive file header! +* -- H * -- pRegistryHive * -- ra * -- pb @@ -119,75 +127,81 @@ VOID VmmWinReg_HiveReadEx(_In_ POB_REGISTRY_HIVE pRegistryHive, _In_ DWORD ra, _ * -- return = TRUE on success, FALSE on partial or zero write. */ _Success_(return) -BOOL VmmWinReg_HiveWrite(_In_ POB_REGISTRY_HIVE pRegistryHive, _In_ DWORD ra, _In_reads_(cb) PBYTE pb, _In_ DWORD cb); +BOOL VmmWinReg_HiveWrite(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pRegistryHive, _In_ DWORD ra, _In_reads_(cb) PBYTE pb, _In_ DWORD cb); /* * Retrieve registry hive and key/value path from a "full" path starting with: * '0x...', 'by-hive\0x...' or 'HKLM\' * CALLER DECREF: *ppObHive +* -- H * -- uszPathFull * -- ppObHive * -- uszPathKeyValue * -- return */ _Success_(return) -BOOL VmmWinReg_PathHiveGetByFullPath(_In_ LPSTR uszPathFull, _Out_ POB_REGISTRY_HIVE *ppHive, _Out_writes_(MAX_PATH) LPSTR uszPathKeyValue); +BOOL VmmWinReg_PathHiveGetByFullPath(_In_ VMM_HANDLE H, _In_ LPSTR uszPathFull, _Out_ POB_REGISTRY_HIVE *ppHive, _Out_writes_(MAX_PATH) LPSTR uszPathKeyValue); /* * Retrieve registry hive and key from a "full" path starting with: * '0x...', 'by-hive\0x...' or 'HKLM\' * CALLER DECREF: *ppObHive, *ppObKey +* -- H * -- uszPathFull * -- ppObHive * -- ppObKey * -- return */ _Success_(return) -BOOL VmmWinReg_KeyHiveGetByFullPath(_In_ LPSTR uszPathFull, _Out_ POB_REGISTRY_HIVE *ppObHive, _Out_opt_ POB_REGISTRY_KEY *ppObKey); +BOOL VmmWinReg_KeyHiveGetByFullPath(_In_ VMM_HANDLE H, _In_ LPSTR uszPathFull, _Out_ POB_REGISTRY_HIVE *ppObHive, _Out_opt_ POB_REGISTRY_KEY *ppObKey); /* * Retrieve a registry key by its path. If no registry key is found then NULL * will be returned. * CALLER DECREF: return +* -- H * -- pHive * -- uszPath * -- return */ _Success_(return != NULL) -POB_REGISTRY_KEY VmmWinReg_KeyGetByPath(_In_ POB_REGISTRY_HIVE pHive, _In_ LPSTR uszPath); +POB_REGISTRY_KEY VmmWinReg_KeyGetByPath(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_ LPSTR uszPath); /* * Retrieve a registry key by parent key and name. * If no registry key is found then NULL is returned. +* -- H * -- pHive * -- pParentKey * -- uszChildName * -- return */ _Success_(return != NULL) -POB_REGISTRY_KEY VmmWinReg_KeyGetByChildName(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY pParentKey, _In_ LPSTR uszChildName); +POB_REGISTRY_KEY VmmWinReg_KeyGetByChildName(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY pParentKey, _In_ LPSTR uszChildName); /* * Retrieve a registry key by its cell offset (incl. static/volatile bit). * If no registry key is found then NULL will be returned. * CALLER DECREF: return +* -- H * -- pHive * -- raCellOffset * -- return */ _Success_(return != NULL) -POB_REGISTRY_KEY VmmWinReg_KeyGetByCellOffset(_In_ POB_REGISTRY_HIVE pHive, _In_ DWORD raCellOffset); +POB_REGISTRY_KEY VmmWinReg_KeyGetByCellOffset(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_ DWORD raCellOffset); /* * Retrive registry sub-keys from the level directly below the given parent key. * The resulting keys are returned in a no-key map (set). If no parent key is * given the root keys are returned. * CALLER DECREF: return +* -- H * -- pHive * -- pKeyParent * -- return = ObMap of POB_REGISTRY_KEY */ -POB_MAP VmmWinReg_KeyList(_In_ POB_REGISTRY_HIVE pHive, _In_opt_ POB_REGISTRY_KEY pKeyParent); +POB_MAP VmmWinReg_KeyList(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_opt_ POB_REGISTRY_KEY pKeyParent); /* * Retrieve information about a registry key. @@ -199,40 +213,44 @@ VOID VmmWinReg_KeyInfo(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY pKey, /* * Retrieve information about a registry key - pKeyInfo->wszName = set to full path. +* -- H * -- pHive * -- pKey * -- pKeyInfo */ -VOID VmmWinReg_KeyInfo2(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY pKey, _Out_ PVMM_REGISTRY_KEY_INFO pKeyInfo); +VOID VmmWinReg_KeyInfo2(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY pKey, _Out_ PVMM_REGISTRY_KEY_INFO pKeyInfo); /* * Retrive registry values given a key. The resulting values are returned in a * no-key map (set). If no values are found the empty set or NULL are returned. * CALLER DECREF: return +* -- H * -- pHive * -- pKeyParent * -- return = ObMap of POB_REGISTRY_VALUE */ -POB_MAP VmmWinReg_KeyValueList(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY pKeyParent); +POB_MAP VmmWinReg_KeyValueList(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY pKeyParent); /* * Try to create a key-value object manager object from the given cell offset. +* -- H * -- pHive * -- oCell = offset to cell (incl. static/volatile bit). * -- return */ -POB_REGISTRY_VALUE VmmWinReg_KeyValueGetByOffset(_In_ POB_REGISTRY_HIVE pHive, _In_ DWORD oCell); +POB_REGISTRY_VALUE VmmWinReg_KeyValueGetByOffset(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_ DWORD oCell); /* * Retrive registry values given a key and value name. * NB! VmmWinReg_KeyValueList is the preferred function. * CALLER DECREF: return +* -- H * -- pHive * -- pKeyParent * -- uszValueName = value name or NULL for default. * -- return = registry value or NULL if not found. */ -POB_REGISTRY_VALUE VmmWinReg_KeyValueGetByName(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY pKeyParent, _In_ LPSTR uszValueName); +POB_REGISTRY_VALUE VmmWinReg_KeyValueGetByName(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY pKeyParent, _In_ LPSTR uszValueName); /* * Retrieve information about a registry key value. @@ -244,6 +262,7 @@ VOID VmmWinReg_ValueInfo(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_VALUE p /* * Read a registry value - similar to WINAPI function 'RegQueryValueEx'. +* -- H * -- pHive * -- uszPathKeyValue * -- pdwType @@ -255,10 +274,11 @@ VOID VmmWinReg_ValueInfo(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_VALUE p * -- return */ _Success_(return) -BOOL VmmWinReg_ValueQuery1(_In_ POB_REGISTRY_HIVE pHive, _In_ LPSTR uszPathKeyValue, _Out_opt_ PDWORD pdwType, _Out_opt_ PDWORD pra, _Out_writes_opt_(cb) PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbRead, _In_ QWORD cbOffset); +BOOL VmmWinReg_ValueQuery1(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_ LPSTR uszPathKeyValue, _Out_opt_ PDWORD pdwType, _Out_opt_ PDWORD pra, _Out_writes_opt_(cb) PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbRead, _In_ QWORD cbOffset); /* * Read a registry value - similar to WINAPI function 'RegQueryValueEx'. +* -- H * -- uszFullPathKeyValue * -- pdwType * -- pbData @@ -267,10 +287,11 @@ BOOL VmmWinReg_ValueQuery1(_In_ POB_REGISTRY_HIVE pHive, _In_ LPSTR uszPathKeyVa * -- return */ _Success_(return) -BOOL VmmWinReg_ValueQuery2(_In_ LPSTR uszFullPathKeyValue, _Out_opt_ PDWORD pdwType, _Out_writes_opt_(cbData) PBYTE pbData, _In_ DWORD cbData, _Out_opt_ PDWORD pcbData); +BOOL VmmWinReg_ValueQuery2(_In_ VMM_HANDLE H, _In_ LPSTR uszFullPathKeyValue, _Out_opt_ PDWORD pdwType, _Out_writes_opt_(cbData) PBYTE pbData, _In_ DWORD cbData, _Out_opt_ PDWORD pcbData); /* * Read a registry value - similar to WINAPI function 'RegQueryValueEx'. +* -- H * -- pHive * -- uszPathKeyValue * -- pdwType @@ -280,10 +301,11 @@ BOOL VmmWinReg_ValueQuery2(_In_ LPSTR uszFullPathKeyValue, _Out_opt_ PDWORD pdwT * -- return */ _Success_(return) -BOOL VmmWinReg_ValueQuery3(_In_ POB_REGISTRY_HIVE pHive, _In_ LPSTR uszPathKeyValue, _Out_opt_ PDWORD pdwType, _Out_writes_opt_(cbData) PBYTE pbData, _In_ DWORD cbData, _Out_opt_ PDWORD pcbData); +BOOL VmmWinReg_ValueQuery3(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_ LPSTR uszPathKeyValue, _Out_opt_ PDWORD pdwType, _Out_writes_opt_(cbData) PBYTE pbData, _In_ DWORD cbData, _Out_opt_ PDWORD pcbData); /* * Read a registry value - similar to WINAPI function 'RegQueryValueEx'. +* -- H * -- pHive * -- pKeyValue * -- pdwType @@ -293,10 +315,11 @@ BOOL VmmWinReg_ValueQuery3(_In_ POB_REGISTRY_HIVE pHive, _In_ LPSTR uszPathKeyVa * -- return */ _Success_(return) -BOOL VmmWinReg_ValueQuery4(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_VALUE pKeyValue, _Out_opt_ PDWORD pdwType, _Out_writes_opt_(cbData) PBYTE pbData, _In_ DWORD cbData, _Out_opt_ PDWORD pcbData); +BOOL VmmWinReg_ValueQuery4(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_VALUE pKeyValue, _Out_opt_ PDWORD pdwType, _Out_writes_opt_(cbData) PBYTE pbData, _In_ DWORD cbData, _Out_opt_ PDWORD pcbData); /* * Read a registry value - similar to WINAPI function 'RegQueryValueEx'. +* -- H * -- pHive * -- pObKey * -- uszValueName @@ -307,7 +330,7 @@ BOOL VmmWinReg_ValueQuery4(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_VALUE * -- return */ _Success_(return) -BOOL VmmWinReg_ValueQuery5(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY pKey, _In_ LPSTR uszValueName, _Out_opt_ PDWORD pdwType, _Out_writes_opt_(cbData) PBYTE pbData, _In_ DWORD cbData, _Out_opt_ PDWORD pcbData); +BOOL VmmWinReg_ValueQuery5(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY pKey, _In_ LPSTR uszValueName, _Out_opt_ PDWORD pdwType, _Out_writes_opt_(cbData) PBYTE pbData, _In_ DWORD cbData, _Out_opt_ PDWORD pcbData); typedef struct tdVMMWINREG_FORENSIC_CONTEXT { struct { @@ -328,6 +351,7 @@ typedef struct tdVMMWINREG_FORENSIC_CONTEXT { * Function to allow the forensic sub-system to request extraction of all keys * and their values from a specific hive. The key information will be delivered * back to the forensic sub-system by the use of callback functions. +* -- H * -- pHive * -- hCallback1 * -- hCallback2 @@ -336,12 +360,13 @@ typedef struct tdVMMWINREG_FORENSIC_CONTEXT { * -- pfnJsonValueCB */ VOID VmmWinReg_ForensicGetAllKeysAndValues( + _In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_ HANDLE hCallback1, _In_ HANDLE hCallback2, - _In_ VOID(*pfnKeyCB)(_In_ HANDLE hCallback1, _In_ HANDLE hCallback2, _In_ LPSTR uszPathName, _In_ QWORD vaHive, _In_ DWORD dwCell, _In_ DWORD dwCellParent, _In_ QWORD ftLastWrite), - _In_ VOID(*pfnJsonKeyCB)(_Inout_ PVMMWINREG_FORENSIC_CONTEXT ctx, _In_z_ LPSTR uszPathName, _In_ QWORD ftLastWrite), - _In_ VOID(*pfnJsonValueCB)(_Inout_ PVMMWINREG_FORENSIC_CONTEXT ctx) + _In_ VOID(*pfnKeyCB)(_In_ VMM_HANDLE H, _In_ HANDLE hCallback1, _In_ HANDLE hCallback2, _In_ LPSTR uszPathName, _In_ QWORD vaHive, _In_ DWORD dwCell, _In_ DWORD dwCellParent, _In_ QWORD ftLastWrite), + _In_ VOID(*pfnJsonKeyCB)(_In_ VMM_HANDLE H, _Inout_ PVMMWINREG_FORENSIC_CONTEXT ctx, _In_z_ LPSTR uszPathName, _In_ QWORD ftLastWrite), + _In_ VOID(*pfnJsonValueCB)(_In_ VMM_HANDLE H, _Inout_ PVMMWINREG_FORENSIC_CONTEXT ctx) ); #endif /* __VMMWINREG_H__ */ diff --git a/vmm/vmmwinsvc.c b/vmm/vmmwinsvc.c index fc7b14f..a3f4693 100644 --- a/vmm/vmmwinsvc.c +++ b/vmm/vmmwinsvc.c @@ -48,10 +48,10 @@ typedef struct tdVMMWINSVC_CONTEXT { * Retrieve required offsets for parsing services by os build version. * -- ctx */ -VOID VmmWinSvc_OffsetLocator(_In_ PVMMWINSVC_CONTEXT ctx) +VOID VmmWinSvc_OffsetLocator(_In_ VMM_HANDLE H, _In_ PVMMWINSVC_CONTEXT ctx) { - BOOL f32 = ctxVmm->f32; - DWORD dwBuild = ctxVmm->kernel.dwVersionBuild; + BOOL f32 = H->vmm.f32; + DWORD dwBuild = H->vmm.kernel.dwVersionBuild; VMMWINSVC_OFFSET_SC16 o16 = { 0 }; VMMWINSVC_OFFSET_SC19 o19 = { 0 }; if(f32) { @@ -107,17 +107,18 @@ VOID VmmWinSvc_OffsetLocator(_In_ PVMMWINSVC_CONTEXT ctx) /* * Retrieve the services.exe process. * CALLER DECREF: return +* -- H * -- return */ -PVMM_PROCESS VmmWinSvc_GetProcessServices() +PVMM_PROCESS VmmWinSvc_GetProcessServices(_In_ VMM_HANDLE H) { BOOL f; LPSTR szPProc; PVMM_PROCESS pObProcess = NULL, pObProcessParent = NULL; - while((pObProcess = VmmProcessGetNext(pObProcess, 0))) { + while((pObProcess = VmmProcessGetNext(H, pObProcess, 0))) { if(!_stricmp("services.exe", pObProcess->szName)) { - szPProc = (ctxVmm->kernel.dwVersionBuild == 2600) ? "winlogon.exe" : "wininit.exe"; - f = (pObProcessParent = VmmProcessGet(pObProcess->dwPPID)) && + szPProc = (H->vmm.kernel.dwVersionBuild == 2600) ? "winlogon.exe" : "wininit.exe"; + f = (pObProcessParent = VmmProcessGet(H, pObProcess->dwPPID)) && !_stricmp(szPProc, pObProcessParent->szName); Ob_DECREF_NULL(&pObProcessParent); if(f) { return pObProcess; } @@ -128,11 +129,13 @@ PVMM_PROCESS VmmWinSvc_GetProcessServices() /* * Retrieve services list start/end from services.exe!ServiceDatabase PDB symbol. +* -- H * -- pProcessServices * -- pvaListHead */ -VOID VmmWinSvc_ListHeadFromPDB(_In_ PVMM_PROCESS pSvcProcess, _Out_writes_(2) PQWORD pvaListHead) +VOID VmmWinSvc_ListHeadFromPDB(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSvcProcess, _Out_writes_(2) PQWORD pvaListHead) { + BOOL f32 = H->vmm.f32; PDB_HANDLE hPdbServices; PVMM_MAP_MODULEENTRY peModuleServices; PVMMOB_MAP_MODULE pObModuleMap = NULL; @@ -140,37 +143,38 @@ VOID VmmWinSvc_ListHeadFromPDB(_In_ PVMM_PROCESS pSvcProcess, _Out_writes_(2) PQ DWORD dwoSymSvcDB = 0; pvaListHead[0] = 0; pvaListHead[1] = 0; - if(!VmmMap_GetModuleEntryEx(pSvcProcess, 0, "services.exe", &pObModuleMap, &peModuleServices)) { goto fail; } - if(!(hPdbServices = PDB_GetHandleFromModuleAddress(pSvcProcess, peModuleServices->vaBase))) { goto fail; } - if(!PDB_GetSymbolOffset(hPdbServices, "ServiceDatabase", &dwoSymSvcDB)) { goto fail; } - if(!VmmRead(pSvcProcess, peModuleServices->vaBase + dwoSymSvcDB, pbSymSvcDB, sizeof(pbSymSvcDB))) { goto fail; } - pvaListHead[0] = (QWORD)VMM_PTR_OFFSET_DUAL(ctxVmm->f32, pbSymSvcDB, 4, 8); - pvaListHead[1] = (QWORD)VMM_PTR_OFFSET_DUAL(ctxVmm->f32, pbSymSvcDB, 8, 16); - if(!VMM_UADDR_4_8(pvaListHead[0]) || !VMM_UADDR_4_8(pvaListHead[1])) { goto fail; } + if(!VmmMap_GetModuleEntryEx(H, pSvcProcess, 0, "services.exe", &pObModuleMap, &peModuleServices)) { goto fail; } + if(!(hPdbServices = PDB_GetHandleFromModuleAddress(H, pSvcProcess, peModuleServices->vaBase))) { goto fail; } + if(!PDB_GetSymbolOffset(H, hPdbServices, "ServiceDatabase", &dwoSymSvcDB)) { goto fail; } + if(!VmmRead(H, pSvcProcess, peModuleServices->vaBase + dwoSymSvcDB, pbSymSvcDB, sizeof(pbSymSvcDB))) { goto fail; } + pvaListHead[0] = (QWORD)VMM_PTR_OFFSET_DUAL(f32, pbSymSvcDB, 4, 8); + pvaListHead[1] = (QWORD)VMM_PTR_OFFSET_DUAL(f32, pbSymSvcDB, 8, 16); + if(!VMM_UADDR_4_8(f32, pvaListHead[0]) || !VMM_UADDR_4_8(f32, pvaListHead[1])) { goto fail; } fail: Ob_DECREF(pObModuleMap); } /* * Retrieve services objects from vad and prefetch vad into cache. +* -- H * -- ctx * -- pSvcProcess * -- pvaListHead */ -VOID VmmWinSvc_ListHeadFromVAD(_In_ PVMMWINSVC_CONTEXT ctx, _In_ PVMM_PROCESS pSvcProcess, _Inout_updates_(2) PQWORD pvaListHead) +VOID VmmWinSvc_ListHeadFromVAD(_In_ VMM_HANDLE H, _In_ PVMMWINSVC_CONTEXT ctx, _In_ PVMM_PROCESS pSvcProcess, _Inout_updates_(2) PQWORD pvaListHead) { - BOOL f32 = ctxVmm->f32; + BOOL f32 = H->vmm.f32; QWORD va1, va2; DWORD i, o, dwTag, cbVad; BYTE pb2[0x10], *pb = NULL; PVMM_MAP_VADENTRY pe; PVMMOB_MAP_VAD pObVadMap = NULL; - if(!VmmMap_GetVad(pSvcProcess, &pObVadMap, VMM_VADMAP_TP_CORE)) { goto finish; } + if(!VmmMap_GetVad(H, pSvcProcess, &pObVadMap, VMM_VADMAP_TP_CORE)) { goto finish; } // 1: if address exist -> prefetch vad and finish - if(pvaListHead[0] && (pe = VmmMap_GetVadEntry(pObVadMap, pvaListHead[0]))) { + if(pvaListHead[0] && (pe = VmmMap_GetVadEntry(H, pObVadMap, pvaListHead[0]))) { cbVad = (DWORD)(pe->vaEnd + 1 - pe->vaStart); if(cbVad <= 0x00200000) { - VmmCachePrefetchPages4(pSvcProcess, 1, &pe->vaStart, cbVad, 0); + VmmCachePrefetchPages4(H, pSvcProcess, 1, &pe->vaStart, cbVad, 0); } goto finish; } @@ -181,7 +185,7 @@ VOID VmmWinSvc_ListHeadFromVAD(_In_ PVMMWINSVC_CONTEXT ctx, _In_ PVMM_PROCESS pS if(!pe->fPrivateMemory || (pe->CommitCharge < 0x10)) { continue; } cbVad = (DWORD)(pe->vaEnd + 1 - pe->vaStart); if((cbVad > 0x00200000) || (cbVad < 0x00010000)) { continue; } - VmmReadEx(pSvcProcess, pe->vaStart, pb, cbVad, NULL, VMM_FLAG_ZEROPAD_ON_FAIL); + VmmReadEx(H, pSvcProcess, pe->vaStart, pb, cbVad, NULL, VMM_FLAG_ZEROPAD_ON_FAIL); dwTag = _byteswap_ulong(ctx->dwTag); for(o = 0x1000; o < 0x00200000; o += 4) { if(dwTag == *(PDWORD)(pb + o)) { @@ -190,12 +194,12 @@ VOID VmmWinSvc_ListHeadFromVAD(_In_ PVMMWINSVC_CONTEXT ctx, _In_ PVMM_PROCESS pS va2 = VMM_PTR_OFFSET(f32, pb + o - ctx->oSc19.Tag, ctx->oSc19.FLink); } else { // serH entry va1 = VMM_PTR_OFFSET_DUAL(f32, pb + o, 0x0c, 0x10); // TODO: verify 32-bit version - if(!VMM_UADDR_4_8(va1)) { continue; } - if(!VmmRead(pSvcProcess, va1, pb2, 0x10)) { continue; } + if(!VMM_UADDR_4_8(f32, va1)) { continue; } + if(!VmmRead(H, pSvcProcess, va1, pb2, 0x10)) { continue; } va1 = VMM_PTR_OFFSET(f32, pb2, 0); va2 = VMM_PTR_OFFSET_DUAL(f32, pb2, 4, 8); } - if((va1 < 0x10000) || !VMM_UADDR_4_8(va1) || (va2 < 0x10000) || !VMM_UADDR_4_8(va2)) { continue; } + if((va1 < 0x10000) || !VMM_UADDR_4_8(f32, va1) || (va2 < 0x10000) || !VMM_UADDR_4_8(f32, va2)) { continue; } pvaListHead[0] = va1; pvaListHead[1] = va2; goto finish; @@ -210,15 +214,16 @@ finish: /* * Retrieve services from the service database list structure. * CALLER DECREF: return +* -- H * -- ctx * -- pProcessSvc * -- cVaListHead * -- pvaListHead * -- return */ -POB_MAP VmmWinSvc_MainListWalk(_In_ PVMMWINSVC_CONTEXT ctx, _In_ PVMM_PROCESS pProcessSvc, _In_ DWORD cVaListHead, _In_reads_(cVaListHead) PQWORD pvaListHead) +POB_MAP VmmWinSvc_MainListWalk(_In_ VMM_HANDLE H, _In_ PVMMWINSVC_CONTEXT ctx, _In_ PVMM_PROCESS pProcessSvc, _In_ DWORD cVaListHead, _In_reads_(cVaListHead) PQWORD pvaListHead) { - BOOL f32 = ctxVmm->f32; + BOOL f32 = H->vmm.f32; DWORD dwOrdinal, dwStartType; QWORD i, va, va1, va2, va3; BYTE pb[0x200] = { 0 }; @@ -226,27 +231,27 @@ POB_MAP VmmWinSvc_MainListWalk(_In_ PVMMWINSVC_CONTEXT ctx, _In_ PVMM_PROCESS pP POB_MAP pmSvc = NULL; PVMM_MAP_SERVICEENTRY pe; PVMMWINSVC_OFFSET_SC19 o = &ctx->oSc19; - if(!(psA = ObSet_New())) { goto fail; } - if(!(pmSvc = ObMap_New(OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } + if(!(psA = ObSet_New(H))) { goto fail; } + if(!(pmSvc = ObMap_New(H, OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; } for(i = 0; i < cVaListHead; i++) { ObSet_Push(psA, pvaListHead[i]); } while((va = ObSet_Pop(psA))) { // read & sanity check if(ObMap_ExistsKey(pmSvc, va)) { continue; } - if(!VmmRead(pProcessSvc, va, pb, o->_Size)) { continue; } + if(!VmmRead(H, pProcessSvc, va, pb, o->_Size)) { continue; } if(o->fTag && !VMM_POOLTAG(*(PDWORD)(pb + o->Tag), o->TagV)) { continue; } if((dwOrdinal = *(PDWORD)(pb + o->Ordinal)) > 0xffff) { continue; } if((dwStartType = *(PDWORD)(pb + o->SvcTp)) > SERVICE_TYPE_ALL) { continue; } // BLink / FLink va1 = VMM_PTR_OFFSET(f32, pb, o->BLink); va2 = VMM_PTR_OFFSET(f32, pb, o->FLink); - if(!VMM_UADDR_4_8(va1)) { va1 = 0; } - if(!VMM_UADDR_4_8(va2)) { va2 = 0; } + if(!VMM_UADDR_4_8(f32, va1)) { va1 = 0; } + if(!VMM_UADDR_4_8(f32, va2)) { va2 = 0; } if(!va1 && !va2) { continue; } ObSet_Push(psA, va1); ObSet_Push(psA, va2); - if(!VMM_UADDR(VMM_PTR_OFFSET(f32, pb, o->NmShort))) { continue; } + if(!VMM_UADDR(f32, VMM_PTR_OFFSET(f32, pb, o->NmShort))) { continue; } // allocate & assign if(!(pe = LocalAlloc(LMEM_ZEROINIT, sizeof(VMM_MAP_SERVICEENTRY)))) { continue; } ObMap_Push(pmSvc, va, pe); @@ -260,7 +265,7 @@ POB_MAP VmmWinSvc_MainListWalk(_In_ PVMMWINSVC_CONTEXT ctx, _In_ PVMM_PROCESS pP pe->_vaReservedPath = VMM_PTR_OFFSET(f32, pb, o->ExtInfo); } else { va3 = VMM_PTR_OFFSET(f32, pb, o->ExtInfo); - pe->_Reserved = VMM_UADDR_4_8(va3) ? va3 : 0; + pe->_Reserved = VMM_UADDR_4_8(f32, va3) ? va3 : 0; } } Ob_INCREF(pmSvc); @@ -272,34 +277,35 @@ fail: /* * Retrieve the extended service info such as service process id, service user * and other data which is found in the 'Sc16' data structure. +* -- H * -- ctx * -- pProcessSvc * -- pmSvc */ -VOID VmmWinSvc_GetExtendedInfo(_In_ PVMMWINSVC_CONTEXT ctx, _In_ PVMM_PROCESS pProcessSvc, _In_ POB_MAP pmSvc) +VOID VmmWinSvc_GetExtendedInfo(_In_ VMM_HANDLE H, _In_ PVMMWINSVC_CONTEXT ctx, _In_ PVMM_PROCESS pProcessSvc, _In_ POB_MAP pmSvc) { - BOOL f32 = ctxVmm->f32; + BOOL f32 = H->vmm.f32; QWORD va; BYTE pb[0x80] = { 0 }; POB_SET psObPrefetch = NULL; PVMM_MAP_SERVICEENTRY pe = NULL; PVMMWINSVC_OFFSET_SC16 o = &ctx->oSc16; - if((psObPrefetch = ObSet_New())) { + if((psObPrefetch = ObSet_New(H))) { while((pe = ObMap_GetNext(pmSvc, pe))) { ObSet_Push(psObPrefetch, pe->_Reserved); } - VmmCachePrefetchPages3(pProcessSvc, psObPrefetch, o->_Size, 0); + VmmCachePrefetchPages3(H, pProcessSvc, psObPrefetch, o->_Size, 0); Ob_DECREF_NULL(&psObPrefetch); } while((pe = ObMap_GetNext(pmSvc, pe))) { if((va = pe->_Reserved)) { pe->_Reserved = 0; - if(!VmmRead2(pProcessSvc, va, pb, o->_Size, VMM_FLAG_FORCECACHE_READ)) { continue; } + if(!VmmRead2(H, pProcessSvc, va, pb, o->_Size, VMM_FLAG_FORCECACHE_READ)) { continue; } if(o->fTag) { if(!VMM_POOLTAG(*(PDWORD)(pb + o->Tag), 'Sc16')) { continue; } } else { - if(!(va = VMM_PTR_OFFSET(f32, pb, o->BLink)) || !VMM_UADDR_4_8(va)) { continue; } - if(!(va = VMM_PTR_OFFSET(f32, pb, o->FLink)) || !VMM_UADDR_4_8(va)) { continue; } + if(!(va = VMM_PTR_OFFSET(f32, pb, o->BLink)) || !VMM_UADDR_4_8(f32, va)) { continue; } + if(!(va = VMM_PTR_OFFSET(f32, pb, o->FLink)) || !VMM_UADDR_4_8(f32, va)) { continue; } } pe->dwPID = *(PDWORD)(pb + o->Pid); pe->_vaReservedPath = VMM_PTR_OFFSET(f32, pb, o->StartupPath); @@ -311,17 +317,18 @@ VOID VmmWinSvc_GetExtendedInfo(_In_ PVMMWINSVC_CONTEXT ctx, _In_ PVMM_PROCESS pP /* * Add a string from an address uniquely to the ObStrMap. +* -- H * -- pProcessSvc * -- psm * -- puszText * -- qwA * -- fNullOnFail = set pwszText to NULL on fail (i.e. don't include in OB_STRMAP psm) */ -VOID VmmWinSvc_ResolveStrAddSingle(_In_ PVMM_PROCESS pProcessSvc, _In_ POB_STRMAP psm, _Out_ LPSTR *puszText, _In_ QWORD qwA, _In_ BOOL fNullOnFail) +VOID VmmWinSvc_ResolveStrAddSingle(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcessSvc, _In_ POB_STRMAP psm, _Out_ LPSTR *puszText, _In_ QWORD qwA, _In_ BOOL fNullOnFail) { WCHAR wsz[2048] = { 0 }; - if((qwA < 0x10000) || !VMM_UADDR(qwA)) { goto fail; } - VmmRead2(pProcessSvc, qwA, (PBYTE)wsz, sizeof(wsz) - 2, VMM_FLAG_FORCECACHE_READ); + if((qwA < 0x10000) || !VMM_UADDR(H->vmm.f32, qwA)) { goto fail; } + VmmRead2(H, pProcessSvc, qwA, (PBYTE)wsz, sizeof(wsz) - 2, VMM_FLAG_FORCECACHE_READ); if(!wsz[0]) { goto fail; } if(wsz[0] > 0xff || wsz[1] > 0xff || wsz[2] > 0xff) { goto fail; } ObStrMap_PushPtrWU(psm, wsz, puszText, NULL); @@ -334,22 +341,22 @@ fail: } } -VOID VmmWinSvc_ResolveStrRegistry(_In_ PVMM_PROCESS pProcessSvc, _In_ PVMMOB_MAP_SERVICE pSvcMap, _In_ POB_STRMAP psm) +VOID VmmWinSvc_ResolveStrRegistry(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcessSvc, _In_ PVMMOB_MAP_SERVICE pSvcMap, _In_ POB_STRMAP psm) { DWORD i, dwType, cbData = 0; PVMM_MAP_SERVICEENTRY pe; POB_REGISTRY_HIVE pObHive = NULL; CHAR usz[MAX_PATH + 1]; USHORT wsz[MAX_PATH + 1]; - VmmWinReg_KeyHiveGetByFullPath("HKLM\\SYSTEM", &pObHive, NULL); + VmmWinReg_KeyHiveGetByFullPath(H, "HKLM\\SYSTEM", &pObHive, NULL); for(i = 0; i < pSvcMap->cMap; i++) { pe = pSvcMap->pMap + i; cbData = 0; if(pObHive) { _snprintf_s(usz, MAX_PATH, _TRUNCATE, "ROOT\\ControlSet001\\Services\\%s\\parameters\\ServiceDll", pe->uszServiceName); - if(!VmmWinReg_ValueQuery3(pObHive, usz, &dwType, (PBYTE)wsz, MAX_PATH * 2, &cbData) || (dwType != REG_EXPAND_SZ)) { + if(!VmmWinReg_ValueQuery3(H, pObHive, usz, &dwType, (PBYTE)wsz, MAX_PATH * 2, &cbData) || (dwType != REG_EXPAND_SZ)) { _snprintf_s(usz, MAX_PATH, _TRUNCATE, "ROOT\\ControlSet001\\Services\\%s\\ImagePath", pe->uszServiceName); - if(!VmmWinReg_ValueQuery3(pObHive, usz, &dwType, (PBYTE)wsz, MAX_PATH * 2, &cbData) || (dwType != REG_EXPAND_SZ)) { + if(!VmmWinReg_ValueQuery3(H, pObHive, usz, &dwType, (PBYTE)wsz, MAX_PATH * 2, &cbData) || (dwType != REG_EXPAND_SZ)) { cbData = 0; } } @@ -362,12 +369,13 @@ VOID VmmWinSvc_ResolveStrRegistry(_In_ PVMM_PROCESS pProcessSvc, _In_ PVMMOB_MAP /* * Resolve all "primordial" strings related to the services. +* -- H * -- pProcessSvc * -- pSvcMap * -- return */ _Success_(return) -BOOL VmmWinSvc_ResolveStrAll(_In_ PVMM_PROCESS pProcessSvc, _In_ PVMMOB_MAP_SERVICE pSvcMap) +BOOL VmmWinSvc_ResolveStrAll(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcessSvc, _In_ PVMMOB_MAP_SERVICE pSvcMap) { DWORD i; BOOL fProcessUser; @@ -377,9 +385,9 @@ BOOL VmmWinSvc_ResolveStrAll(_In_ PVMM_PROCESS pProcessSvc, _In_ PVMMOB_MAP_SERV POB_SET psObPrefetch; POB_STRMAP pObStrMap; // 1: initialize - if(!(pObStrMap = ObStrMap_New(OB_STRMAP_FLAGS_CASE_SENSITIVE | OB_STRMAP_FLAGS_STR_ASSIGN_TEMPORARY))) { return FALSE; } + if(!(pObStrMap = ObStrMap_New(H, OB_STRMAP_FLAGS_CASE_SENSITIVE | OB_STRMAP_FLAGS_STR_ASSIGN_TEMPORARY))) { return FALSE; } // 2: prefetch for performance reasons - if((psObPrefetch = ObSet_New())) { + if((psObPrefetch = ObSet_New(H))) { for(i = 0; i < pSvcMap->cMap; i++) { pe = pSvcMap->pMap + i; ObSet_Push(psObPrefetch, pe->_vaReservedServiceName); @@ -388,17 +396,17 @@ BOOL VmmWinSvc_ResolveStrAll(_In_ PVMM_PROCESS pProcessSvc, _In_ PVMMOB_MAP_SERV ObSet_Push(psObPrefetch, pe->_vaReservedUserTp); ObSet_Push(psObPrefetch, pe->_vaReservedUserAcct); } - VmmCachePrefetchPages3(pProcessSvc, psObPrefetch, 2 * 2048, 0); + VmmCachePrefetchPages3(H, pProcessSvc, psObPrefetch, 2 * 2048, 0); Ob_DECREF_NULL(&psObPrefetch); } // 3.1: fetch strings - general for(i = 0; i < pSvcMap->cMap; i++) { pe = pSvcMap->pMap + i; - VmmWinSvc_ResolveStrAddSingle(pProcessSvc, pObStrMap, &pe->uszServiceName, pe->_vaReservedServiceName, FALSE); - VmmWinSvc_ResolveStrAddSingle(pProcessSvc, pObStrMap, &pe->uszDisplayName, pe->_vaReservedDisplayName, FALSE); - VmmWinSvc_ResolveStrAddSingle(pProcessSvc, pObStrMap, &pe->uszPath, pe->_vaReservedPath, FALSE); - VmmWinSvc_ResolveStrAddSingle(pProcessSvc, pObStrMap, &pe->uszUserTp, pe->_vaReservedUserTp, FALSE); - VmmWinSvc_ResolveStrAddSingle(pProcessSvc, pObStrMap, &pe->uszUserAcct, pe->_vaReservedUserAcct, TRUE); + VmmWinSvc_ResolveStrAddSingle(H, pProcessSvc, pObStrMap, &pe->uszServiceName, pe->_vaReservedServiceName, FALSE); + VmmWinSvc_ResolveStrAddSingle(H, pProcessSvc, pObStrMap, &pe->uszDisplayName, pe->_vaReservedDisplayName, FALSE); + VmmWinSvc_ResolveStrAddSingle(H, pProcessSvc, pObStrMap, &pe->uszPath, pe->_vaReservedPath, FALSE); + VmmWinSvc_ResolveStrAddSingle(H, pProcessSvc, pObStrMap, &pe->uszUserTp, pe->_vaReservedUserTp, FALSE); + VmmWinSvc_ResolveStrAddSingle(H, pProcessSvc, pObStrMap, &pe->uszUserAcct, pe->_vaReservedUserAcct, TRUE); } // 3.2: fetch strings - user (if does not exist already) for(i = 0; i < pSvcMap->cMap; i++) { @@ -406,15 +414,15 @@ BOOL VmmWinSvc_ResolveStrAll(_In_ PVMM_PROCESS pProcessSvc, _In_ PVMMOB_MAP_SERV if(!pe->uszUserAcct) { fProcessUser = pe->dwPID && - (pObProcessUser = VmmProcessGetEx(NULL, pe->dwPID, VMM_FLAG_PROCESS_TOKEN)) && + (pObProcessUser = VmmProcessGetEx(H, NULL, pe->dwPID, VMM_FLAG_PROCESS_TOKEN)) && pObProcessUser->win.TOKEN.fInitialized && pObProcessUser->win.TOKEN.fSidUserValid && - VmmWinUser_GetName(&pObProcessUser->win.TOKEN.SidUser.SID, usz, sizeof(usz), NULL); + VmmWinUser_GetName(H, &pObProcessUser->win.TOKEN.SidUser.SID, usz, sizeof(usz), NULL); ObStrMap_PushPtrUU(pObStrMap, fProcessUser ? usz : NULL, &pe->uszUserAcct, NULL); Ob_DECREF_NULL(&pObProcessUser); } } // 3.3: fetch strings - image path from registry - VmmWinSvc_ResolveStrRegistry(pProcessSvc, pSvcMap, pObStrMap); + VmmWinSvc_ResolveStrRegistry(H, pProcessSvc, pSvcMap, pObStrMap); // 4: resolve strmap and return ObStrMap_FinalizeAllocU_DECREF_NULL(&pObStrMap, &pSvcMap->pbMultiText, &pSvcMap->cbMultiText); return TRUE; @@ -444,21 +452,21 @@ int VmmWinSvc_CmpSort(PVMM_MAP_SERVICEENTRY a, PVMM_MAP_SERVICEENTRY b) /* * Prefetch registry system hive to speed things up at later lookup. */ -DWORD VmmWinSvc_PrefetchRegSystemHive_ThreadProc(PVOID lpThreadParameter) +VOID VmmWinSvc_PrefetchRegSystemHive_ThreadProc(_In_ VMM_HANDLE H, QWORD qwNotUsed) { POB_REGISTRY_HIVE pObHive; - if(VmmWinReg_KeyHiveGetByFullPath("HKLM\\SYSTEM", &pObHive, NULL)) { + if(VmmWinReg_KeyHiveGetByFullPath(H, "HKLM\\SYSTEM", &pObHive, NULL)) { Ob_DECREF(pObHive); } - return 0; } /* * Retrieve services list as a map object manager object. * CALLER DECREF: return +* -- H * -- return */ -PVMMOB_MAP_SERVICE VmmWinSvc_Initialize_DoWork() +PVMMOB_MAP_SERVICE VmmWinSvc_Initialize_DoWork(_In_ VMM_HANDLE H) { VMMWINSVC_CONTEXT InitCtx = { 0 }; PVMM_PROCESS pObSvcProcess = NULL; @@ -468,21 +476,21 @@ PVMMOB_MAP_SERVICE VmmWinSvc_Initialize_DoWork() PVMMOB_MAP_SERVICE pObServiceMap = NULL; PVMM_MAP_SERVICEENTRY pe = NULL; // 0: prefetch SYSTEM reg hive - VmmWork((LPTHREAD_START_ROUTINE)VmmWinSvc_PrefetchRegSystemHive_ThreadProc, NULL, NULL); + VmmWork_Value(H, VmmWinSvc_PrefetchRegSystemHive_ThreadProc, 0, 0, VMMWORK_FLAG_PRIO_NORMAL); // 1: initialize - if(!(pObSvcProcess = VmmWinSvc_GetProcessServices())) { goto fail; } - VmmWinSvc_OffsetLocator(&InitCtx); - if(ctxVmm->kernel.dwVersionBuild >= 15063) { - VmmWinSvc_ListHeadFromPDB(pObSvcProcess, vaSvcDatabase); + if(!(pObSvcProcess = VmmWinSvc_GetProcessServices(H))) { goto fail; } + VmmWinSvc_OffsetLocator(H, &InitCtx); + if(H->vmm.kernel.dwVersionBuild >= 15063) { + VmmWinSvc_ListHeadFromPDB(H, pObSvcProcess, vaSvcDatabase); } - VmmWinSvc_ListHeadFromVAD(&InitCtx, pObSvcProcess, vaSvcDatabase); + VmmWinSvc_ListHeadFromVAD(H, &InitCtx, pObSvcProcess, vaSvcDatabase); if(!vaSvcDatabase[0] && !vaSvcDatabase[1]) { goto fail; } // 2: walk services list and resolve extended info - if(!(pmObSvc = VmmWinSvc_MainListWalk(&InitCtx, pObSvcProcess, 2, vaSvcDatabase))) { goto fail; } - VmmWinSvc_GetExtendedInfo(&InitCtx, pObSvcProcess, pmObSvc); + if(!(pmObSvc = VmmWinSvc_MainListWalk(H, &InitCtx, pObSvcProcess, 2, vaSvcDatabase))) { goto fail; } + VmmWinSvc_GetExtendedInfo(H, &InitCtx, pObSvcProcess, pmObSvc); // 3: allocate, assign and sort services map cSvc = ObMap_Size(pmObSvc); - if(!(pObServiceMap = Ob_Alloc(OB_TAG_MAP_SERVICE, 0, sizeof(VMMOB_MAP_SERVICE) + cSvc * sizeof(VMM_MAP_SERVICEENTRY), VmmWinSvc_CloseObCallback, NULL))) { goto fail; } + if(!(pObServiceMap = Ob_AllocEx(H, OB_TAG_MAP_SERVICE, 0, sizeof(VMMOB_MAP_SERVICE) + cSvc * sizeof(VMM_MAP_SERVICEENTRY), VmmWinSvc_CloseObCallback, NULL))) { goto fail; } pObServiceMap->cMap = cSvc; for(i = 0; i < cSvc; i++) { if((pe = ObMap_GetByIndex(pmObSvc, i))) { @@ -491,7 +499,7 @@ PVMMOB_MAP_SERVICE VmmWinSvc_Initialize_DoWork() } qsort(pObServiceMap->pMap, pObServiceMap->cMap, sizeof(VMM_MAP_SERVICEENTRY), (int(*)(void const *, void const *))VmmWinSvc_CmpSort); // 4: resolve strings - if(!VmmWinSvc_ResolveStrAll(pObSvcProcess, pObServiceMap)) { + if(!VmmWinSvc_ResolveStrAll(H, pObSvcProcess, pObServiceMap)) { Ob_DECREF_NULL(&pObServiceMap); goto fail; } @@ -504,30 +512,31 @@ fail: /* * Create a service map and assign to the global context upon success. * CALLER DECREF: return +* -- H * -- return */ -PVMMOB_MAP_SERVICE VmmWinSvc_Initialize() +PVMMOB_MAP_SERVICE VmmWinSvc_Initialize(_In_ VMM_HANDLE H) { PVMMOB_MAP_SERVICE pObSvc; - if((pObSvc = ObContainer_GetOb(ctxVmm->pObCMapService))) { return pObSvc; } - EnterCriticalSection(&ctxVmm->LockUpdateMap); - if((pObSvc = ObContainer_GetOb(ctxVmm->pObCMapService))) { - LeaveCriticalSection(&ctxVmm->LockUpdateMap); + if((pObSvc = ObContainer_GetOb(H->vmm.pObCMapService))) { return pObSvc; } + EnterCriticalSection(&H->vmm.LockUpdateMap); + if((pObSvc = ObContainer_GetOb(H->vmm.pObCMapService))) { + LeaveCriticalSection(&H->vmm.LockUpdateMap); return pObSvc; } - pObSvc = VmmWinSvc_Initialize_DoWork(); + pObSvc = VmmWinSvc_Initialize_DoWork(H); if(!pObSvc) { - pObSvc = Ob_Alloc(OB_TAG_MAP_SERVICE, LMEM_ZEROINIT, sizeof(VMMOB_MAP_SERVICE), NULL, NULL); + pObSvc = Ob_AllocEx(H, OB_TAG_MAP_SERVICE, LMEM_ZEROINIT, sizeof(VMMOB_MAP_SERVICE), NULL, NULL); } - ObContainer_SetOb(ctxVmm->pObCMapService, pObSvc); - LeaveCriticalSection(&ctxVmm->LockUpdateMap); + ObContainer_SetOb(H->vmm.pObCMapService, pObSvc); + LeaveCriticalSection(&H->vmm.LockUpdateMap); return pObSvc; } /* * Refresh the service map. */ -VOID VmmWinSvc_Refresh() +VOID VmmWinSvc_Refresh(_In_ VMM_HANDLE H) { - ObContainer_SetOb(ctxVmm->pObCMapService, NULL); + ObContainer_SetOb(H->vmm.pObCMapService, NULL); } diff --git a/vmm/vmmwinsvc.h b/vmm/vmmwinsvc.h index 11979b5..33515bb 100644 --- a/vmm/vmmwinsvc.h +++ b/vmm/vmmwinsvc.h @@ -8,11 +8,13 @@ /* * Create a service map and assign to the global context upon success. * CALLER DECREF: return +* -- H * -- return */ -PVMMOB_MAP_SERVICE VmmWinSvc_Initialize(); +PVMMOB_MAP_SERVICE VmmWinSvc_Initialize(_In_ VMM_HANDLE H); /* * Refresh the service map. +* -- H */ -VOID VmmWinSvc_Refresh(); +VOID VmmWinSvc_Refresh(_In_ VMM_HANDLE H); diff --git a/vmm/vmmwork.c b/vmm/vmmwork.c new file mode 100644 index 0000000..56112ac --- /dev/null +++ b/vmm/vmmwork.c @@ -0,0 +1,372 @@ +// vmmwork.c : implementation of the internal MemprocFS 'work' threading solution. +// +// (c) Ulf Frisk, 2022 +// Author: Ulf Frisk, pcileech@frizk.net +// + +#include "vmm.h" +#include "ob/ob.h" +#include "ob/ob_tag.h" + +// ---------------------------------------------------------------------------- +// WORK (THREAD POOL) API: +// The 'Work' thread pool contain by default 16 threads which is waiting to +// receive work scheduled by calling the VmmWork function. +// ---------------------------------------------------------------------------- + +typedef struct tdVMMWORK_CONTEXT { + POB_SET psThreadAvail; // available (sleeping) threads + POB_SET psThreadAll; // all (alive non exited) threads + POB_SET psThreadExit; // exited (dead) threads + POB_MAP pmUnit; // normal prio work units + POB_MAP pmUnitLow; // low prio work units (per-process actions) +} VMMWORK_CONTEXT, *PVMMWORK_CONTEXT; + +typedef struct tdVMMWORK_THREAD_CONTEXT { + VMM_HANDLE H; // VMM handle + HANDLE hEventWakeup; // wakeup event for the thread + HANDLE hThread; // thread handle +} VMMWORK_THREAD_CONTEXT, *PVMMWORK_THREAD_CONTEXT; + +typedef struct tdOB_VMMWORK_UNIT { + OB ObHdr; + VMM_HANDLE H; // VMM handle + PVMM_WORK_START_ROUTINE_PVOID_PFN pfnVoid; // by-void function to call + PVOID ctxVoid; // by-void optional function parameter + PVMM_WORK_START_ROUTINE_VALUE_PFN pfnValue; // by-value function to call + QWORD ctxValue; // by-value context/value. + PVMM_WORK_START_ROUTINE_OB_PFN pfnOb; // by-object function to call + POB ctxOb; // by-object context/object. + HANDLE hEventFinish; // optional event to set when upon work completion +} OB_VMMWORK_UNIT, *POB_VMMWORK_UNIT; + +VOID VmmWork_CallbackCleanup_ObVmmWorkUnit(_In_ PVOID pOb) +{ + POB_VMMWORK_UNIT pObWorkUnit = pOb; + Ob_DECREF(pObWorkUnit->ctxOb); + if(pObWorkUnit->hEventFinish) { + SetEvent(pObWorkUnit->hEventFinish); + } +} + +/* +* Main worker thread loop. It will perform a work unit if available otherwise +* sleep until work becomes available. +*/ +DWORD VmmWork_MainWorkerLoop_ThreadProc(PVMMWORK_THREAD_CONTEXT ctx) +{ + POB_VMMWORK_UNIT puOb; + VMM_HANDLE H = ctx->H; + InterlockedIncrement(&H->cThreadInternal); + while(!H->fAbort) { + puOb = (POB_VMMWORK_UNIT)ObMap_Pop(H->work->pmUnit); + if(!puOb && (ObSet_Size(H->work->psThreadAvail) > (VMM_WORK_THREADPOOL_NUM_THREADS / 2))) { + puOb = (POB_VMMWORK_UNIT)ObMap_Pop(H->work->pmUnitLow); + } + if(puOb) { + if(puOb->pfnVoid) { + puOb->pfnVoid(puOb->H, puOb->ctxVoid); + } + if(puOb->pfnValue) { + puOb->pfnValue(puOb->H, puOb->ctxValue); + } + if(puOb->pfnOb) { + puOb->pfnOb(puOb->H, puOb->ctxOb); + } + Ob_DECREF_NULL(&puOb); + } else { + ResetEvent(ctx->hEventWakeup); + ObSet_Push(H->work->psThreadAvail, (QWORD)ctx); + WaitForSingleObject(ctx->hEventWakeup, INFINITE); + } + } + ObSet_Remove(H->work->psThreadAll, (QWORD)ctx); + ObSet_Push(H->work->psThreadExit, (QWORD)ctx); + InterlockedDecrement(&H->cThreadInternal); + return 1; +} + +/* +* Initialize the VmmWork sub-system. This should only be done at handle init. +* -- H +* -- return +*/ +_Success_(return) +BOOL VmmWork_Initialize(_In_ VMM_HANDLE H) +{ + PVMMWORK_THREAD_CONTEXT p; + PVMMWORK_CONTEXT ctx = NULL; + if(!(ctx = (PVMMWORK_CONTEXT)LocalAlloc(LMEM_ZEROINIT, sizeof(VMMWORK_CONTEXT)))) { goto fail; } + if(!(ctx->pmUnit = ObMap_New(H, OB_MAP_FLAGS_OBJECT_OB | OB_MAP_FLAGS_NOKEY))) { goto fail; } + if(!(ctx->pmUnitLow = ObMap_New(H, OB_MAP_FLAGS_OBJECT_OB | OB_MAP_FLAGS_NOKEY))) { goto fail; } + if(!(ctx->psThreadAll = ObSet_New(H))) { goto fail; } + if(!(ctx->psThreadExit = ObSet_New(H))) { goto fail; } + if(!(ctx->psThreadAvail = ObSet_New(H))) { goto fail; } + H->work = ctx; + while(ObSet_Size(ctx->psThreadAll) < VMM_WORK_THREADPOOL_NUM_THREADS) { + if((p = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMWORK_THREAD_CONTEXT)))) { + p->H = H; + p->hEventWakeup = CreateEvent(NULL, TRUE, FALSE, NULL); + p->hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)VmmWork_MainWorkerLoop_ThreadProc, p, 0, NULL); + ObSet_Push(ctx->psThreadAll, (QWORD)p); + } + } + return TRUE; +fail: + LocalFree(ctx); + return FALSE; +} + +/* +* Interrupt the VmmWork sub-system (exit threads pre-maturely). This is +* done early in the cleanup process before VmmWork_Close() is called. +* -- H +*/ +VOID VmmWork_Interrupt(_In_ VMM_HANDLE H) +{ + PVMMWORK_THREAD_CONTEXT pt; + if(H->work) { + // 1: set wakeup event for all available (waiting) threads + while((pt = (PVMMWORK_THREAD_CONTEXT)ObSet_Pop(H->work->psThreadAvail))) { + SetEvent(pt->hEventWakeup); + } + // 2: cleanup still queued work units + ObMap_Clear(H->work->pmUnit); + ObMap_Clear(H->work->pmUnitLow); + } +} + +/* +* Close the VmmWork sub-system. Wait until all worker threads have exited. +* -- H +*/ +VOID VmmWork_Close(_In_ VMM_HANDLE H) +{ + PVMMWORK_THREAD_CONTEXT pt = NULL; + if(H->work) { + // 1: wait for exit of all threads + while(ObSet_Size(H->work->psThreadAll)) { + while((pt = (PVMMWORK_THREAD_CONTEXT)ObSet_GetNext(H->work->psThreadAll, (QWORD)pt))) { + SetEvent(pt->hEventWakeup); + } + SwitchToThread(); + } + // 2: cleanup still queued work units + ObMap_Clear(H->work->pmUnit); + ObMap_Clear(H->work->pmUnitLow); + // 3: cleanup exited threads and their contexts + while((pt = (PVMMWORK_THREAD_CONTEXT)ObSet_Pop(H->work->psThreadExit))) { + CloseHandle(pt->hEventWakeup); + CloseHandle(pt->hThread); + LocalFree(pt); + } + // 4: cleanup main work context + Ob_DECREF(H->work->pmUnit); + Ob_DECREF(H->work->pmUnitLow); + Ob_DECREF(H->work->psThreadAll); + Ob_DECREF(H->work->psThreadExit); + Ob_DECREF(H->work->psThreadAvail); + LocalFree(H->work); H->work = NULL; + } +} + +/* +* Queue a work item object. +* -- H +* -- flags = VMMWORK_FLAG_* +* -- ppu +*/ +VOID VmmWork_QueueWorkUnit_DECREF_NULL(_In_ VMM_HANDLE H, _In_ DWORD flags, _In_ POB_VMMWORK_UNIT *ppu) +{ + PVMMWORK_THREAD_CONTEXT pt; + if(!H->fAbort) { + if(flags & VMMWORK_FLAG_PRIO_LOW) { + if((*ppu)->hEventFinish) { ResetEvent((*ppu)->hEventFinish); } + ObMap_Push(H->work->pmUnitLow, 0, *ppu); + } else { + if((*ppu)->hEventFinish) { ResetEvent((*ppu)->hEventFinish); } + ObMap_Push(H->work->pmUnit, 0, *ppu); + } + if((pt = (PVMMWORK_THREAD_CONTEXT)ObSet_Pop(H->work->psThreadAvail))) { + SetEvent(pt->hEventWakeup); + } + } + Ob_DECREF_NULL(ppu); +} + +VOID VmmWork_Value(_In_ VMM_HANDLE H, _In_ PVMM_WORK_START_ROUTINE_VALUE_PFN pfn, _In_ QWORD ctx, _In_opt_ HANDLE hEventFinish, _In_ DWORD flags) +{ + POB_VMMWORK_UNIT pObU; + if((pObU = Ob_AllocEx(H, OB_TAG_WORK_WORKUNIT, LMEM_ZEROINIT, sizeof(OB_VMMWORK_UNIT), VmmWork_CallbackCleanup_ObVmmWorkUnit, NULL))) { + pObU->H = H; + pObU->pfnValue = pfn; + pObU->ctxValue = ctx; + pObU->hEventFinish = hEventFinish; + VmmWork_QueueWorkUnit_DECREF_NULL(H, flags, &pObU); + } +} + +VOID VmmWork_Ob(_In_ VMM_HANDLE H, _In_ PVMM_WORK_START_ROUTINE_OB_PFN pfn, _In_ POB ctx, _In_opt_ HANDLE hEventFinish, _In_ DWORD flags) +{ + POB_VMMWORK_UNIT pObU; + if((pObU = Ob_AllocEx(H, OB_TAG_WORK_WORKUNIT, LMEM_ZEROINIT, sizeof(OB_VMMWORK_UNIT), VmmWork_CallbackCleanup_ObVmmWorkUnit, NULL))) { + pObU->H = H; + pObU->pfnOb = pfn; + pObU->ctxOb = Ob_INCREF(ctx); + pObU->hEventFinish = hEventFinish; + VmmWork_QueueWorkUnit_DECREF_NULL(H, flags, &pObU); + } +} + +VOID VmmWork_Void(_In_ VMM_HANDLE H, _In_ PVMM_WORK_START_ROUTINE_PVOID_PFN pfn, _In_ PVOID ctx, _In_opt_ HANDLE hEventFinish, _In_ DWORD flags) +{ + POB_VMMWORK_UNIT pObU; + if((pObU = Ob_AllocEx(H, OB_TAG_WORK_WORKUNIT, LMEM_ZEROINIT, sizeof(OB_VMMWORK_UNIT), VmmWork_CallbackCleanup_ObVmmWorkUnit, NULL))) { + pObU->H = H; + pObU->pfnVoid = pfn; + pObU->ctxVoid = ctx; + pObU->hEventFinish = hEventFinish; + VmmWork_QueueWorkUnit_DECREF_NULL(H, flags, &pObU); + } +} + +VOID VmmWorkWaitMultiple2_Void(_In_ VMM_HANDLE H, _In_ DWORD cWork, _In_count_(cWork) PVMM_WORK_START_ROUTINE_PVOID_PFN *pfns, _In_count_(cWork) PVOID *ctxs) +{ + DWORD i; + HANDLE hEventFinish[MAXIMUM_WAIT_OBJECTS]; + if(H->fAbort || (cWork == 0) || (cWork > MAXIMUM_WAIT_OBJECTS)) { return; } + for(i = 1; i < cWork; i++) { + hEventFinish[i] = CreateEvent(NULL, TRUE, FALSE, NULL); + VmmWork_Void(H, pfns[i], ctxs[i], hEventFinish[i], VMMWORK_FLAG_PRIO_NORMAL); + } + pfns[0](H, ctxs[0]); + WaitForMultipleObjects(cWork - 1, hEventFinish + 1, TRUE, INFINITE); + for(i = 1; i < cWork; i++) { + if(hEventFinish[i]) { + CloseHandle(hEventFinish[i]); + } + } +} + +VOID VmmWorkWaitMultiple_Void(_In_ VMM_HANDLE H, _In_ PVOID ctx, _In_ DWORD cWork, ...) +{ + DWORD i; + va_list arguments; + PVOID ctxs[MAXIMUM_WAIT_OBJECTS]; + PVMM_WORK_START_ROUTINE_PVOID_PFN pfns[MAXIMUM_WAIT_OBJECTS]; + if(H->fAbort || (cWork == 0) || (cWork > MAXIMUM_WAIT_OBJECTS)) { return; } + va_start(arguments, cWork); + for(i = 0; i < cWork; i++) { + ctxs[i] = ctx; + pfns[i] = va_arg(arguments, PVMM_WORK_START_ROUTINE_PVOID_PFN); + } + va_end(arguments); + VmmWorkWaitMultiple2_Void(H, cWork, pfns, ctxs); +} + + + +// ---------------------------------------------------------------------------- +// PROCESS PARALLELIZATION FUNCTIONALITY: +// ---------------------------------------------------------------------------- + +typedef struct tdOB_VMMWORK_FOREACH_PROCESS { + OB ObHdr; + VMM_HANDLE H; + HANDLE hEventFinish; + VOID(*pfnAction)(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ PVOID ctx); + PVOID ctxAction; + DWORD iPID; // set to dwPIDs count on entry and decremented as-goes + DWORD dwPIDs[]; +} OB_VMMWORK_FOREACH_PROCESS, *POB_VMMWORK_FOREACH_PROCESS; + +VOID VmmWork_CallbackCleanup0_ObVmmWorkForeachProcess(_In_ PVOID pOb) +{ + POB_VMMWORK_FOREACH_PROCESS pObProc = pOb; + if(pObProc->hEventFinish) { + CloseHandle(pObProc->hEventFinish); + } +} + +VOID VmmWork_CallbackCleanup1_ObVmmWorkForeachProcess(_In_ PVOID pOb) +{ + POB_VMMWORK_FOREACH_PROCESS pObProc = pOb; + SetEvent(pObProc->hEventFinish); +} + +VOID VmmWork_ProcessActionForeachParallel_ThreadProc(_In_ VMM_HANDLE H, _In_ POB_VMMWORK_FOREACH_PROCESS ctx) +{ + PVMM_PROCESS pObProcess = VmmProcessGet(H, ctx->dwPIDs[InterlockedDecrement(&ctx->iPID)]); + if(pObProcess) { + ctx->pfnAction(H, pObProcess, ctx->ctxAction); + Ob_DECREF(pObProcess); + } +} + +BOOL VmmWork_ProcessActionForeachParallel_CriteriaActiveOnly(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ PVOID ctx) +{ + return pProcess->dwState == 0; +} + +BOOL VmmWork_ProcessActionForeachParallel_CriteriaActiveUserOnly(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_opt_ PVOID ctx) +{ + return (pProcess->dwState == 0) && pProcess->fUserOnly; +} + +_Success_(return) +BOOL VmmWork_ProcessActionForeachParallel_Void( + _In_ VMM_HANDLE H, + _In_opt_ DWORD cMaxThread, + _In_opt_ PVOID ctxAction, + _In_opt_ PVMM_WORK_PROCESS_CRITERIA_PVOID_PFN pfnCriteria, + _In_ PVMM_WORK_PROCESS_START_ROUTINE_PVOID_PFN pfnAction +) { + BOOL fResult = FALSE; + DWORD i, cProcess; + PVMM_PROCESS pObProcess = NULL; + POB_SET pObProcessSelectedSet = NULL; + POB_VMMWORK_FOREACH_PROCESS ctxOb = NULL; + cMaxThread = max(2, cMaxThread); + cMaxThread = min(cMaxThread, VMM_WORK_THREADPOOL_NUM_THREADS / 4); + // 1: select processes to queue using criteria function + if(!(pObProcessSelectedSet = ObSet_New(H))) { goto fail; } + while((pObProcess = VmmProcessGetNext(H, pObProcess, VMM_FLAG_PROCESS_SHOW_TERMINATED))) { + if(!pfnCriteria || pfnCriteria(H, pObProcess, ctxOb)) { + ObSet_Push(pObProcessSelectedSet, pObProcess->dwPID); + } + } + // 2: set up context for worker function + ctxOb = Ob_AllocEx( + H, + OB_TAG_WORK_PER_PROCESS, + LMEM_ZEROINIT, + sizeof(OB_VMMWORK_FOREACH_PROCESS) + cMaxThread * sizeof(DWORD), + VmmWork_CallbackCleanup0_ObVmmWorkForeachProcess, + VmmWork_CallbackCleanup1_ObVmmWorkForeachProcess); + if(!ctxOb) { goto fail; } + if(!(ctxOb->hEventFinish = CreateEvent(NULL, TRUE, FALSE, NULL))) { goto fail; } + ctxOb->H = H; + ctxOb->pfnAction = pfnAction; + ctxOb->ctxAction = ctxAction; + while((cProcess = ObSet_Size(pObProcessSelectedSet))) { + cProcess = min(cProcess, cMaxThread); + ctxOb->iPID = cProcess; + for(i = 0; i < cProcess; i++) { + ctxOb->dwPIDs[i] = (DWORD)ObSet_Pop(pObProcessSelectedSet); + } + // 3: parallelize onto worker threads and wait for completion + Ob_INCREF(ctxOb); + for(i = 0; i < cProcess; i++) { + VmmWork_Ob(H, (PVMM_WORK_START_ROUTINE_OB_PFN)VmmWork_ProcessActionForeachParallel_ThreadProc, (POB)ctxOb, NULL, VMMWORK_FLAG_PRIO_LOW); + } + Ob_DECREF(ctxOb); + WaitForSingleObject(ctxOb->hEventFinish, INFINITE); + ResetEvent(ctxOb->hEventFinish); + if(H->fAbort) { goto fail; } + } + fResult = TRUE; +fail: + Ob_DECREF(pObProcessSelectedSet); + Ob_DECREF(ctxOb); + return fResult; +} diff --git a/vmm/vmmwork.h b/vmm/vmmwork.h new file mode 100644 index 0000000..04f7532 --- /dev/null +++ b/vmm/vmmwork.h @@ -0,0 +1,32 @@ +// vmmwork.h : declarations of the internal MemprocFS 'work' threading solution. +// +// (c) Ulf Frisk, 2022 +// Author: Ulf Frisk, pcileech@frizk.net +// + +#ifndef __VMMWORK_H__ +#define __VMMWORK_H__ +#include "vmm.h" + +/* +* Initialize the VmmWork sub-system. This should only be done at handle init. +* -- H +* -- return +*/ +_Success_(return) +BOOL VmmWork_Initialize(_In_ VMM_HANDLE H); + +/* +* Interrupt the VmmWork sub-system (exit threads pre-maturely). This is +* usually done early in the cleanup process before VmmWork_Close() is called. +* -- H +*/ +VOID VmmWork_Interrupt(_In_ VMM_HANDLE H); + +/* +* Close the VmmWork sub-system. Wait until all worker threads have exited. +* -- H +*/ +VOID VmmWork_Close(_In_ VMM_HANDLE H); + +#endif /* __VMMWORK_H__ */ diff --git a/vmm_example/vmmdll_example.c b/vmm_example/vmmdll_example.c index 9768e01..b0ff3fe 100644 --- a/vmm_example/vmmdll_example.c +++ b/vmm_example/vmmdll_example.c @@ -140,12 +140,17 @@ LPSTR VadMap_Type(_In_ PVMMDLL_MAP_VADENTRY pVad) } // ---------------------------------------------------------------------------- -// Main entry point which contains various sample code how to use PCILeech DLL. +// 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, dwPID; @@ -159,8 +164,8 @@ int main(_In_ int argc, _In_ char* argv[]) printf("# Initialize from file: \n"); ShowKeyPress(); printf("CALL: VMMDLL_InitializeFile\n"); - result = VMMDLL_Initialize(3, (LPSTR[]) { "", "-device", _INITIALIZE_FROM_FILE }); - if(result) { + hVMM = VMMDLL_Initialize(3, (LPSTR[]) { "", "-device", _INITIALIZE_FROM_FILE }); + if(hVMM) { printf("SUCCESS: VMMDLL_InitializeFile\n"); } else { printf("FAIL: VMMDLL_InitializeFile\n"); @@ -174,7 +179,7 @@ int main(_In_ int argc, _In_ char* argv[]) printf("# Initialize from FPGA: \n"); ShowKeyPress(); printf("CALL: VMMDLL_Initialize\n"); - result = VMMDLL_Initialize(3, (LPSTR[]) { "", "-device", "fpga" }); + hVMM = VMMDLL_Initialize(3, (LPSTR[]) { "", "-device", "fpga" }); if(result) { printf("SUCCESS: VMMDLL_Initialize\n"); } else { @@ -186,9 +191,9 @@ int main(_In_ int argc, _In_ char* argv[]) ShowKeyPress(); printf("CALL: VMMDLL_ConfigGet\n"); result = - VMMDLL_ConfigGet(LC_OPT_FPGA_FPGA_ID, &qwID) && - VMMDLL_ConfigGet(LC_OPT_FPGA_VERSION_MAJOR, &qwVersionMajor) && - VMMDLL_ConfigGet(LC_OPT_FPGA_VERSION_MINOR, &qwVersionMinor); + 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); @@ -230,7 +235,7 @@ int main(_In_ int argc, _In_ char* argv[]) printf("# Get PID from the first 'explorer.exe' process found. \n"); ShowKeyPress(); printf("CALL: VMMDLL_PidGetFromName\n"); - result = VMMDLL_PidGetFromName("explorer.exe", &dwPID); + result = VMMDLL_PidGetFromName(hVMM, "explorer.exe", &dwPID); if(result) { printf("SUCCESS: VMMDLL_PidGetFromName\n"); printf(" PID = %i\n", dwPID); @@ -239,14 +244,14 @@ int main(_In_ int argc, _In_ char* argv[]) return 1; } - + // 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(-1, 0x1000, pbPage1, 0x1000); + result = VMMDLL_MemRead(hVMM, -1, 0x1000, pbPage1, 0x1000); if(result) { printf("SUCCESS: VMMDLL_MemRead\n"); PrintHexAscii(pbPage1, 0x100); @@ -268,7 +273,7 @@ int main(_In_ int argc, _In_ char* argv[]) printf(" (3) Read resulting data from physical memory. \n"); ShowKeyPress(); printf("CALL: VMMDLL_MemRead - BEFORE WRITE\n"); - result = VMMDLL_MemRead(-1, 0x1000, pbPage1, 0x1000); + result = VMMDLL_MemRead(hVMM, -1, 0x1000, pbPage1, 0x1000); if(result) { printf("SUCCESS: VMMDLL_MemRead - BEFORE WRITE\n"); PrintHexAscii(pbPage1, 0x100); @@ -284,9 +289,9 @@ int main(_In_ int argc, _In_ char* argv[]) 0x55, 0x55, 0x55, 0x55, 0x66, 0x66, 0x66, 0x66, 0x77, 0x77, 0x77, 0x77, 0x88, 0x88, 0x88, 0x88, }; - VMMDLL_MemWrite(-1, 0x1000, pbWriteDataPhysical, cbWriteDataPhysical); + VMMDLL_MemWrite(hVMM, -1, 0x1000, pbWriteDataPhysical, cbWriteDataPhysical); printf("CALL: VMMDLL_MemRead - AFTER WRITE\n"); - result = VMMDLL_MemRead(-1, 0x1000, pbPage1, 0x1000); + result = VMMDLL_MemRead(hVMM, -1, 0x1000, pbPage1, 0x1000); if(result) { printf("SUCCESS: VMMDLL_MemRead - AFTER WRITE\n"); PrintHexAscii(pbPage1, 0x100); @@ -305,7 +310,7 @@ int main(_In_ int argc, _In_ char* argv[]) printf("# Get PID from the first 'explorer.exe' process found. \n"); ShowKeyPress(); printf("CALL: VMMDLL_PidGetFromName\n"); - result = VMMDLL_PidGetFromName("explorer.exe", &dwPID); + result = VMMDLL_PidGetFromName(hVMM, "explorer.exe", &dwPID); if(result) { printf("SUCCESS: VMMDLL_PidGetFromName\n"); printf(" PID = %i\n", dwPID); @@ -326,7 +331,7 @@ int main(_In_ int argc, _In_ char* argv[]) ProcessInformation.magic = VMMDLL_PROCESS_INFORMATION_MAGIC; ProcessInformation.wVersion = VMMDLL_PROCESS_INFORMATION_VERSION; printf("CALL: VMMDLL_ProcessGetInformation\n"); - result = VMMDLL_ProcessGetInformation(dwPID, &ProcessInformation, &cbProcessInformation); + result = VMMDLL_ProcessGetInformation(hVMM, dwPID, &ProcessInformation, &cbProcessInformation); if(result) { printf("SUCCESS: VMMDLL_ProcessGetInformation\n"); printf(" Name = %s\n", ProcessInformation.szName); @@ -353,35 +358,21 @@ int main(_In_ int argc, _In_ char* argv[]) printf("------------------------------------------------------------\n"); printf("# Get PTE Memory Map of 'explorer.exe'. \n"); ShowKeyPress(); - DWORD cbPteMap = 0; PVMMDLL_MAP_PTE pPteMap = NULL; PVMMDLL_MAP_PTEENTRY pPteMapEntry; - printf("CALL: VMMDLL_Map_GetPteU #1\n"); - result = VMMDLL_Map_GetPteU(dwPID, NULL, &cbPteMap, TRUE); - if(result) { - printf("SUCCESS: VMMDLL_Map_GetPteU #1\n"); - printf(" ByteCount = %i\n", cbPteMap); - } else { - printf("FAIL: VMMDLL_Map_GetPteU #1\n"); - return 1; - } - pPteMap = (PVMMDLL_MAP_PTE)LocalAlloc(0, cbPteMap); - if(!pPteMap) { - printf("FAIL: OutOfMemory\n"); - return 1; - } - printf("CALL: VMMDLL_Map_GetPteU #2\n"); - result = VMMDLL_Map_GetPteU(dwPID, pPteMap, &cbPteMap, TRUE); + printf("CALL: VMMDLL_Map_GetPteU\n"); + result = VMMDLL_Map_GetPteU(hVMM, dwPID, TRUE, &pPteMap); if(!result) { - printf("FAIL: VMMDLL_Map_GetPteU #2\n"); + 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 #2\n"); + printf("SUCCESS: VMMDLL_Map_GetPteU\n"); printf(" # #PAGES ADRESS_RANGE SRWX\n"); printf(" ====================================================\n"); for(i = 0; i < pPteMap->cMap; i++) { @@ -399,8 +390,7 @@ int main(_In_ int argc, _In_ char* argv[]) pPteMapEntry->uszText ); } - LocalFree(pPteMap); - pPteMap = NULL; + VMMDLL_MemFree(pPteMap); pPteMap = NULL; } @@ -411,35 +401,21 @@ int main(_In_ int argc, _In_ char* argv[]) printf("# Get VAD Memory Map of 'explorer.exe'. \n"); ShowKeyPress(); CHAR szVadProtection[7] = { 0 }; - DWORD cbVadMap = 0; PVMMDLL_MAP_VAD pVadMap = NULL; PVMMDLL_MAP_VADENTRY pVadMapEntry; - printf("CALL: VMMDLL_Map_GetVadU #1\n"); - result = VMMDLL_Map_GetVadU(dwPID, NULL, &cbVadMap, TRUE); - if(result) { - printf("SUCCESS: VMMDLL_Map_GetVadU #1\n"); - printf(" ByteCount = %i\n", cbVadMap); - } else { - printf("FAIL: VMMDLL_Map_GetVadU #1\n"); - return 1; - } - pVadMap = (PVMMDLL_MAP_VAD)LocalAlloc(0, cbVadMap); - if(!pVadMap) { - printf("FAIL: OutOfMemory\n"); - return 1; - } - printf("CALL: VMMDLL_Map_GetVadU #2\n"); - result = VMMDLL_Map_GetVadU(dwPID, pVadMap, &cbVadMap, TRUE); + printf("CALL: VMMDLL_Map_GetVadU\n"); + result = VMMDLL_Map_GetVadU(hVMM, dwPID, TRUE, &pVadMap); if(!result) { - printf("FAIL: VMMDLL_Map_GetVadU #2\n"); + 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 #2\n"); + printf("SUCCESS: VMMDLL_Map_GetVadU\n"); printf(" # ADRESS_RANGE KERNEL_ADDR TYPE PROT INFO \n"); printf(" ============================================================================\n"); for(i = 0; i < pVadMap->cMap; i++) { @@ -456,8 +432,7 @@ int main(_In_ int argc, _In_ char* argv[]) pVadMapEntry->uszText ); } - LocalFree(pVadMap); - pVadMap = NULL; + VMMDLL_MemFree(pVadMap); pVadMap = NULL; } @@ -469,34 +444,20 @@ int main(_In_ int argc, _In_ char* argv[]) printf("------------------------------------------------------------\n"); printf("# Get Module Map of 'explorer.exe'. \n"); ShowKeyPress(); - DWORD cbModuleMap = 0; PVMMDLL_MAP_MODULE pModuleMap = NULL; - printf("CALL: VMMDLL_Map_GetModuleU #1\n"); - result = VMMDLL_Map_GetModuleU(dwPID, NULL, &cbModuleMap); - if(result) { - printf("SUCCESS: VMMDLL_Map_GetModuleU #1\n"); - printf(" ByteCount = %i\n", cbModuleMap); - } else { - printf("FAIL: VMMDLL_Map_GetModuleU #1\n"); - return 1; - } - pModuleMap = (PVMMDLL_MAP_MODULE)LocalAlloc(0, cbModuleMap); - if(!pModuleMap) { - printf("FAIL: OutOfMemory\n"); - return 1; - } - printf("CALL: VMMDLL_Map_GetModuleU #2\n"); - result = VMMDLL_Map_GetModuleU(dwPID, pModuleMap, &cbModuleMap); + printf("CALL: VMMDLL_Map_GetModuleU\n"); + result = VMMDLL_Map_GetModuleU(hVMM, dwPID, &pModuleMap); if(!result) { - printf("FAIL: VMMDLL_Map_GetModuleU #2\n"); + 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 #2\n"); + printf("SUCCESS: VMMDLL_Map_GetModuleU\n"); printf(" MODULE_NAME BASE SIZE ENTRY PATH\n"); printf(" ==========================================================================================\n"); for(i = 0; i < pModuleMap->cMap; i++) { @@ -510,8 +471,7 @@ int main(_In_ int argc, _In_ char* argv[]) pModuleMap->pMap[i].uszFullName ); } - LocalFree(pModuleMap); - pModuleMap = NULL; + VMMDLL_MemFree(pModuleMap); pModuleMap = NULL; } @@ -520,34 +480,20 @@ int main(_In_ int argc, _In_ char* argv[]) printf("------------------------------------------------------------\n"); printf("# Get Unloaded Module Map of 'explorer.exe'. \n"); ShowKeyPress(); - DWORD cbUnloadedMap = 0; PVMMDLL_MAP_UNLOADEDMODULE pUnloadedMap = NULL; - printf("CALL: VMMDLL_Map_GetUnloadedModuleU #1\n"); - result = VMMDLL_Map_GetUnloadedModuleU(dwPID, NULL, &cbUnloadedMap); - if(result) { - printf("SUCCESS: VMMDLL_Map_GetUnloadedModuleU #1\n"); - printf(" ByteCount = %i\n", cbUnloadedMap); - } else { - printf("FAIL: VMMDLL_Map_GetUnloadedModuleU #1\n"); - return 1; - } - pUnloadedMap = (PVMMDLL_MAP_UNLOADEDMODULE)LocalAlloc(0, cbUnloadedMap); - if(!pUnloadedMap) { - printf("FAIL: OutOfMemory\n"); - return 1; - } - printf("CALL: VMMDLL_Map_GetUnloadedModuleU #2\n"); - result = VMMDLL_Map_GetUnloadedModuleU(dwPID, pUnloadedMap, &cbUnloadedMap); + printf("CALL: VMMDLL_Map_GetUnloadedModuleU\n"); + result = VMMDLL_Map_GetUnloadedModuleU(hVMM, dwPID, &pUnloadedMap); if(!result) { - printf("FAIL: VMMDLL_Map_GetUnloadedModuleU #2\n"); + 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 #2\n"); + printf("SUCCESS: VMMDLL_Map_GetUnloadedModuleU\n"); printf(" MODULE_NAME BASE SIZE\n"); printf(" =================================================================\n"); for(i = 0; i < pUnloadedMap->cMap; i++) { @@ -559,8 +505,7 @@ int main(_In_ int argc, _In_ char* argv[]) pUnloadedMap->pMap[i].cbImageSize ); } - LocalFree(pUnloadedMap); - pUnloadedMap = NULL; + VMMDLL_MemFree(pUnloadedMap); pUnloadedMap = NULL; } @@ -573,8 +518,8 @@ int main(_In_ int argc, _In_ char* argv[]) printf("# Get module by name 'explorer.exe' in 'explorer.exe'. \n"); ShowKeyPress(); printf("CALL: VMMDLL_Map_GetModuleFromNameU\n"); - VMMDLL_MAP_MODULEENTRY ModuleEntryExplorer; - result = VMMDLL_Map_GetModuleFromNameU(dwPID, "explorer.exe", &ModuleEntryExplorer, NULL); + PVMMDLL_MAP_MODULEENTRY pModuleEntryExplorer; + result = VMMDLL_Map_GetModuleFromNameU(hVMM, dwPID, "explorer.exe", &pModuleEntryExplorer); if(result) { printf("SUCCESS: VMMDLL_Map_GetModuleFromNameU\n"); printf(" MODULE_NAME BASE SIZE ENTRY\n"); @@ -582,52 +527,38 @@ int main(_In_ int argc, _In_ char* argv[]) printf( " %-40.40s %i %016llx %08x %016llx\n", "explorer.exe", - ModuleEntryExplorer.fWoW64 ? 32 : 64, - ModuleEntryExplorer.vaBase, - ModuleEntryExplorer.cbImageSize, - ModuleEntryExplorer.vaEntry + pModuleEntryExplorer->fWoW64 ? 32 : 64, + pModuleEntryExplorer->vaBase, + pModuleEntryExplorer->cbImageSize, + pModuleEntryExplorer->vaEntry ); } else { printf("FAIL: VMMDLL_Map_GetModuleFromNameU\n"); + VMMDLL_MemFree(pModuleEntryExplorer); pModuleEntryExplorer = NULL; return 1; } -#ifdef _WIN32 // 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(); - DWORD cbThreadMap = 0; PVMMDLL_MAP_THREAD pThreadMap = NULL; PVMMDLL_MAP_THREADENTRY pThreadMapEntry; - printf("CALL: VMMDLL_Map_GetThread #1\n"); - result = VMMDLL_Map_GetThread(dwPID, NULL, &cbThreadMap); - if(result) { - printf("SUCCESS: VMMDLL_Map_GetThread #1\n"); - printf(" ByteCount = %i\n", cbThreadMap); - } else { - printf("FAIL: VMMDLL_Map_GetThread #1\n"); - return 1; - } - pThreadMap = (PVMMDLL_MAP_THREAD)LocalAlloc(0, cbThreadMap); - if(!pThreadMap) { - printf("FAIL: OutOfMemory\n"); - return 1; - } - printf("CALL: VMMDLL_Map_GetThread #2\n"); - result = VMMDLL_Map_GetThread(dwPID, pThreadMap, &cbThreadMap); + printf("CALL: VMMDLL_Map_GetThread\n"); + result = VMMDLL_Map_GetThread(hVMM, dwPID, &pThreadMap); if(!result) { - printf("FAIL: VMMDLL_Map_GetThread #2\n"); + 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 #2\n"); + 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++) { @@ -646,10 +577,8 @@ int main(_In_ int argc, _In_ char* argv[]) pThreadMapEntry->vaRIP ); } - LocalFree(pThreadMap); - pThreadMap = NULL; + VMMDLL_MemFree(pThreadMap); pThreadMap = NULL; } -#endif // HANDLES: Retrieve handle information about handles in the explorer.exe @@ -657,35 +586,21 @@ int main(_In_ int argc, _In_ char* argv[]) printf("------------------------------------------------------------\n"); printf("# Get Handle Information of 'explorer.exe'. \n"); ShowKeyPress(); - DWORD cbHandleMap = 0; PVMMDLL_MAP_HANDLE pHandleMap = NULL; PVMMDLL_MAP_HANDLEENTRY pHandleMapEntry; - printf("CALL: VMMDLL_Map_GetHandleU #1\n"); - result = VMMDLL_Map_GetHandleU(dwPID, NULL, &cbHandleMap); - if(result) { - printf("SUCCESS: VMMDLL_Map_GetHandleU #1\n"); - printf(" ByteCount = %i\n", cbHandleMap); - } else { - printf("FAIL: VMMDLL_Map_GetHandleU #1\n"); - return 1; - } - pHandleMap = (PVMMDLL_MAP_HANDLE)LocalAlloc(0, cbHandleMap); - if(!pHandleMap) { - printf("FAIL: OutOfMemory\n"); - return 1; - } - printf("CALL: VMMDLL_Map_GetHandleU #2\n"); - result = VMMDLL_Map_GetHandleU(dwPID, pHandleMap, &cbHandleMap); + printf("CALL: VMMDLL_Map_GetHandleU\n"); + result = VMMDLL_Map_GetHandleU(hVMM, dwPID, &pHandleMap); if(!result) { - printf("FAIL: VMMDLL_Map_GetHandleU #2\n"); + 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 #2\n"); + printf("SUCCESS: VMMDLL_Map_GetHandleU\n"); printf(" # HANDLE PID ADDR_OBJECT ACCESS TYPE DESCRIPTION\n"); printf(" ===========================================================================\n"); for(i = 0; i < pHandleMap->cMap; i++) { @@ -701,11 +616,48 @@ int main(_In_ int argc, _In_ char* argv[]) pHandleMapEntry->uszText ); } - LocalFree(pHandleMap); - pHandleMap = NULL; + 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; + } + + // 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) @@ -717,7 +669,7 @@ int main(_In_ int argc, _In_ char* argv[]) printf(" (3) Read resulting data from virtual memory. \n"); ShowKeyPress(); printf("CALL: VMMDLL_MemRead - BEFORE WRITE\n"); - result = VMMDLL_MemRead(dwPID, ModuleEntryExplorer.vaBase, pbPage1, 0x1000); + result = VMMDLL_MemRead(hVMM, dwPID, pModuleEntryExplorer->vaBase, pbPage1, 0x1000); if(result) { printf("SUCCESS: VMMDLL_MemRead - BEFORE WRITE\n"); PrintHexAscii(pbPage1, 0x80); @@ -733,9 +685,9 @@ int main(_In_ int argc, _In_ char* argv[]) 0x79, 0x20, 0x4d, 0x65, 0x6d, 0x50, 0x72, 0x6f, 0x63, 0x46, 0x53, 0x00, }; - VMMDLL_MemWrite(dwPID, ModuleEntryExplorer.vaBase + 0x58, pbWriteDataVirtual, cbWriteDataVirtual); + VMMDLL_MemWrite(hVMM, dwPID, pModuleEntryExplorer->vaBase + 0x58, pbWriteDataVirtual, cbWriteDataVirtual); printf("CALL: VMMDLL_MemRead - AFTER WRITE\n"); - result = VMMDLL_MemRead(dwPID, ModuleEntryExplorer.vaBase, pbPage1, 0x1000); + result = VMMDLL_MemRead(hVMM, dwPID, pModuleEntryExplorer->vaBase, pbPage1, 0x1000); if(result) { printf("SUCCESS: VMMDLL_MemRead - AFTER WRITE\n"); PrintHexAscii(pbPage1, 0x80); @@ -754,8 +706,8 @@ int main(_In_ int argc, _In_ char* argv[]) printf("# Get by name 'kernel32.dll' in 'explorer.exe'. \n"); ShowKeyPress(); printf("CALL: VMMDLL_Map_GetModuleFromNameU\n"); - VMMDLL_MAP_MODULEENTRY ModuleEntryKernel32; - result = VMMDLL_Map_GetModuleFromNameU(dwPID, "kernel32.dll", &ModuleEntryKernel32, NULL); + PVMMDLL_MAP_MODULEENTRY pModuleEntryKernel32; + result = VMMDLL_Map_GetModuleFromNameU(hVMM, dwPID, "kernel32.dll", &pModuleEntryKernel32); if(result) { printf("SUCCESS: VMMDLL_Map_GetModuleFromNameU\n"); printf(" MODULE_NAME BASE SIZE ENTRY\n"); @@ -763,13 +715,14 @@ int main(_In_ int argc, _In_ char* argv[]) printf( " %-40.40S %i %016llx %08x %016llx\n", L"kernel32.dll", - ModuleEntryKernel32.fWoW64 ? 32 : 64, - ModuleEntryKernel32.vaBase, - ModuleEntryKernel32.cbImageSize, - ModuleEntryKernel32.vaEntry + pModuleEntryKernel32->fWoW64 ? 32 : 64, + pModuleEntryKernel32->vaBase, + pModuleEntryKernel32->cbImageSize, + pModuleEntryKernel32->vaEntry ); } else { printf("FAIL: VMMDLL_Map_GetModuleFromNameU\n"); + VMMDLL_MemFree(pModuleEntryKernel32); pModuleEntryKernel32 = NULL; return 1; } @@ -783,7 +736,7 @@ int main(_In_ int argc, _In_ char* argv[]) ShowKeyPress(); DWORD cRead; printf("CALL: VMMDLL_MemReadEx\n"); - result = VMMDLL_MemReadEx(dwPID, ModuleEntryKernel32.vaBase, pbPage2, 0x1000, &cRead, 0); // standard cached read + 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"); @@ -801,7 +754,7 @@ int main(_In_ int argc, _In_ char* argv[]) printf("CALL: VMMDLL_ProcessGetSectionsU #1\n"); DWORD cSections; PIMAGE_SECTION_HEADER pSectionHeaders; - result = VMMDLL_ProcessGetSectionsU(dwPID, "kernel32.dll", NULL, 0, &cSections); + result = VMMDLL_ProcessGetSectionsU(hVMM, dwPID, "kernel32.dll", NULL, 0, &cSections); if(result) { printf("SUCCESS: VMMDLL_ProcessGetSectionsU #1\n"); printf(" Count = %i\n", cSections); @@ -815,7 +768,7 @@ int main(_In_ int argc, _In_ char* argv[]) return 1; } printf("CALL: VMMDLL_ProcessGetSectionsU #2\n"); - result = VMMDLL_ProcessGetSectionsU(dwPID, "kernel32.dll", pSectionHeaders, cSections, &cSections); + result = VMMDLL_ProcessGetSectionsU(hVMM, dwPID, "kernel32.dll", pSectionHeaders, cSections, &cSections); if(result) { printf("SUCCESS: VMMDLL_ProcessGetSectionsU #2\n"); printf(" # NAME OFFSET SIZE RWX\n"); @@ -858,14 +811,14 @@ int main(_In_ int argc, _In_ char* argv[]) 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 = ModuleEntryKernel32.vaBase + pSectionHeaders[i].VirtualAddress; + 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(dwPID, ppMEMs, cSections, VMMDLL_FLAG_NOCACHE | VMMDLL_FLAG_ZEROPAD_ON_FAIL | VMMDLL_FLAG_NOPAGING)) { + 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"); @@ -891,10 +844,9 @@ int main(_In_ int argc, _In_ char* argv[]) 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" }; - DWORD cDirectories; IMAGE_DATA_DIRECTORY pDirectories[16]; printf("CALL: VMMDLL_ProcessGetDirectoriesU\n"); - result = VMMDLL_ProcessGetDirectoriesU(dwPID, "kernel32.dll", pDirectories, 16, &cDirectories); + result = VMMDLL_ProcessGetDirectoriesU(hVMM, dwPID, "kernel32.dll", pDirectories); if(result) { printf("SUCCESS: PCIleech_VmmProcess_GetDirectories\n"); printf(" # NAME OFFSET SIZE\n"); @@ -918,34 +870,21 @@ int main(_In_ int argc, _In_ char* argv[]) printf("------------------------------------------------------------\n"); printf("# exports of 'kernel32.dll' in 'explorer.exe'. \n"); ShowKeyPress(); - DWORD cbEatMap = 0; PVMMDLL_MAP_EAT pEatMap = NULL; PVMMDLL_MAP_EATENTRY pEatMapEntry; - printf("CALL: VMMDLL_Map_GetEATU #1\n"); - result = VMMDLL_Map_GetEATU(dwPID, "kernel32.dll", NULL, &cbEatMap); - if(result) { - printf("SUCCESS: VMMDLL_Map_GetEATU #1\n"); - } else { - printf("FAIL: VMMDLL_Map_GetEATU #1\n"); - return 1; - } - pEatMap = (PVMMDLL_MAP_EAT)LocalAlloc(0, cbEatMap); - if(!pEatMap) { - printf("FAIL: OutOfMemory\n"); - return 1; - } - printf("CALL: VMMDLL_Map_GetEATU #2\n"); - result = VMMDLL_Map_GetEATU(dwPID, "kernel32.dll", pEatMap, &cbEatMap); + printf("CALL: VMMDLL_Map_GetEATU\n"); + result = VMMDLL_Map_GetEATU(hVMM, dwPID, "kernel32.dll", &pEatMap); if(!result) { - printf("FAIL: VMMDLL_Map_GetEATU #2\n"); + 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 #2\n"); + printf("SUCCESS: VMMDLL_Map_GetEATU\n"); printf(" # ORD NAME\n"); printf(" =============================\n"); for(i = 0; i < pEatMap->cMap; i++) { @@ -957,6 +896,7 @@ int main(_In_ int argc, _In_ char* argv[]) pEatMapEntry->uszFunction ); } + VMMDLL_MemFree(pEatMap); pEatMap = NULL; } @@ -967,31 +907,19 @@ int main(_In_ int argc, _In_ char* argv[]) DWORD cbIatMap = 0; PVMMDLL_MAP_IAT pIatMap = NULL; PVMMDLL_MAP_IATENTRY pIatMapEntry; - printf("CALL: VMMDLL_Map_GetIATU #1\n"); - result = VMMDLL_Map_GetIATU(dwPID, "kernel32.dll", NULL, &cbIatMap); - if(result) { - printf("SUCCESS: VMMDLL_Map_GetIATU #1\n"); - } else { - printf("FAIL: VMMDLL_Map_GetIATU #1\n"); - return 1; - } - pIatMap = (PVMMDLL_MAP_IAT)LocalAlloc(LMEM_ZEROINIT, cbIatMap); - if(!pIatMap) { - printf("FAIL: OutOfMemory\n"); - return 1; - } - printf("CALL: VMMDLL_Map_GetIATU #2\n"); - result = VMMDLL_Map_GetIATU(dwPID, "kernel32.dll", pIatMap, &cbIatMap); + printf("CALL: VMMDLL_Map_GetIATU\n"); + result = VMMDLL_Map_GetIATU(hVMM, dwPID, "kernel32.dll", &pIatMap); if(!result) { - printf("FAIL: VMMDLL_Map_GetIATU #2\n"); + 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 #2\n"); + printf("SUCCESS: VMMDLL_Map_GetIATU\n"); printf(" # VIRTUAL_ADDRESS MODULE!NAME\n"); printf(" ===================================\n"); for(i = 0; i < pIatMap->cMap; i++) { @@ -1004,6 +932,7 @@ int main(_In_ int argc, _In_ char* argv[]) pIatMapEntry->uszFunction ); } + VMMDLL_MemFree(pIatMap); pIatMap = NULL; } @@ -1013,7 +942,7 @@ int main(_In_ int argc, _In_ char* argv[]) printf(" by virtual file system (vfs) functionality. \n"); ShowKeyPress(); printf("CALL: VMMDLL_InitializePlugins\n"); - result = VMMDLL_InitializePlugins(); + result = VMMDLL_InitializePlugins(hVMM); if(result) { printf("SUCCESS: VMMDLL_InitializePlugins\n"); } else { @@ -1036,7 +965,7 @@ int main(_In_ int argc, _In_ char* argv[]) VfsFileList.pfnAddDirectory = CallbackList_AddDirectory; VfsFileList.pfnAddFile = CallbackList_AddFile; printf("CALL: VMMDLL_VfsListU\n"); - result = VMMDLL_VfsListU("\\", &VfsFileList); + result = VMMDLL_VfsListU(hVMM, "\\", &VfsFileList); if(result) { printf("SUCCESS: VMMDLL_VfsListU\n"); } else { @@ -1048,10 +977,10 @@ int main(_In_ int argc, _In_ char* argv[]) // 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 the pmem file. \n"); + printf("# Call the file system 'Read' function on memory.pmem. \n"); ShowKeyPress(); printf("CALL: VMMDLL_VfsReadU\n"); - nt = VMMDLL_VfsReadU("\\memory.pmem", pbPage1, 0x100, &i, 0x1000); + nt = VMMDLL_VfsReadU(hVMM, "\\memory.pmem", pbPage1, 0x100, &i, 0x1000); if(nt == VMMDLL_STATUS_SUCCESS) { printf("SUCCESS: VMMDLL_VfsReadU\n"); PrintHexAscii(pbPage1, i); @@ -1063,11 +992,11 @@ int main(_In_ int argc, _In_ char* argv[]) // Virtual File System: 'Read' statistics from the .status module/plugin. printf("------------------------------------------------------------\n"); - printf("# Call file system 'Read' on .status\\statistics \n"); + printf("# Call file system 'Read' on conf\\statistics.txt \n"); ShowKeyPress(); printf("CALL: VMMDLL_VfsReadU\n"); ZeroMemory(pbPage1, 0x1000); - nt = VMMDLL_VfsReadU("\\.status\\statistics", pbPage1, 0xfff, &i, 0); + 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); @@ -1082,7 +1011,7 @@ int main(_In_ int argc, _In_ char* argv[]) printf("# Get ntoskrnl.exe base virtual address \n"); ShowKeyPress(); printf("CALL: VMMDLL_ProcessGetModuleBaseU\n"); - va = VMMDLL_ProcessGetModuleBaseU(4, "ntoskrnl.exe"); + va = VMMDLL_ProcessGetModuleBaseU(hVMM, 4, "ntoskrnl.exe"); if(va) { printf("SUCCESS: VMMDLL_ProcessGetModuleBaseU\n"); printf(" %s = %016llx\n", "ntoskrnl.exe", va); @@ -1097,7 +1026,7 @@ int main(_In_ int argc, _In_ char* argv[]) printf("# Get proc address for ntoskrnl.exe!KeGetCurrentIrql \n"); ShowKeyPress(); printf("CALL: VMMDLL_ProcessGetProcAddressU\n"); - va = VMMDLL_ProcessGetProcAddressU(4, "ntoskrnl.exe", "KeGetCurrentIrql"); + va = VMMDLL_ProcessGetProcAddressU(hVMM, 4, "ntoskrnl.exe", "KeGetCurrentIrql"); if(va) { printf("SUCCESS: VMMDLL_ProcessGetProcAddressU\n"); printf(" %s!%s = %016llx\n", "ntoskrnl.exe", "KeGetCurrentIrql", va); @@ -1114,7 +1043,7 @@ int main(_In_ int argc, _In_ char* argv[]) VMMDLL_WIN_THUNKINFO_IAT oThunkInfoIAT; ZeroMemory(&oThunkInfoIAT, sizeof(VMMDLL_WIN_THUNKINFO_IAT)); printf("CALL: VMMDLL_WinGetThunkInfoIATU\n"); - result = VMMDLL_WinGetThunkInfoIATU(4, "ntoskrnl.Exe", "hal.Dll", "HalSendNMI", &oThunkInfoIAT); + result = VMMDLL_WinGetThunkInfoIATU(hVMM, 4, "ntoskrnl.Exe", "hal.Dll", "HalSendNMI", &oThunkInfoIAT); if(result) { printf("SUCCESS: VMMDLL_WinGetThunkInfoIATU\n"); printf(" vaFunction: %016llx\n", oThunkInfoIAT.vaFunction); @@ -1134,7 +1063,7 @@ int main(_In_ int argc, _In_ char* argv[]) DWORD cWinRegHives; PVMMDLL_REGISTRY_HIVE_INFORMATION pWinRegHives = NULL; printf("CALL: VMMDLL_WinReg_HiveList\n"); - result = VMMDLL_WinReg_HiveList(NULL, 0, &cWinRegHives); + result = VMMDLL_WinReg_HiveList(hVMM, NULL, 0, &cWinRegHives); if(!result || !cWinRegHives) { printf("FAIL: VMMDLL_WinReg_HiveList #1 - Get # Hives.\n"); return 1; @@ -1144,7 +1073,7 @@ int main(_In_ int argc, _In_ char* argv[]) printf("FAIL: OutOfMemory\n"); return 1; } - result = VMMDLL_WinReg_HiveList(pWinRegHives, cWinRegHives, &cWinRegHives); + result = VMMDLL_WinReg_HiveList(hVMM, pWinRegHives, cWinRegHives, &cWinRegHives); if(result && cWinRegHives) { printf("SUCCESS: VMMDLL_WinReg_HiveList\n"); for(i = 0; i < cWinRegHives; i++) { @@ -1160,33 +1089,24 @@ int main(_In_ int argc, _In_ char* argv[]) printf("------------------------------------------------------------\n"); printf("# Retrieve Physical Memory Map \n"); ShowKeyPress(); - DWORD cbPhysMemMap = 0; PVMMDLL_MAP_PHYSMEM pPhysMemMap = NULL; printf("CALL: VMMDLL_Map_GetPhysMem\n"); - result = VMMDLL_Map_GetPhysMem(NULL, &cbPhysMemMap); + result = VMMDLL_Map_GetPhysMem(hVMM, &pPhysMemMap); if(!result) { printf("FAIL: VMMDLL_Map_GetPhysMem #1 - Get # Hives.\n"); return 1; } - pPhysMemMap = LocalAlloc(LMEM_ZEROINIT, cbPhysMemMap); - if(!pPhysMemMap) { - printf("FAIL: OutOfMemory\n"); - return 1; - } - result = VMMDLL_Map_GetPhysMem(pPhysMemMap, &cbPhysMemMap); - if(!result) { - printf("FAIL: VMMDLL_Map_GetPhysMem #2\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; } - if(result) { + { 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; } @@ -1195,7 +1115,7 @@ int main(_In_ int argc, _In_ char* argv[]) printf("# Read 0x100 bytes from offset 0x1000 of registry hive \n"); ShowKeyPress(); printf("CALL: VMMDLL_WinReg_HiveReadEx\n"); - result = VMMDLL_WinReg_HiveReadEx(pWinRegHives[0].vaCMHIVE, 0x1000, pbPage1, 0x100, NULL, 0); + result = VMMDLL_WinReg_HiveReadEx(hVMM, pWinRegHives[0].vaCMHIVE, 0x1000, pbPage1, 0x100, NULL, 0); if(result) { printf("SUCCESS: VMMDLL_WinReg_HiveReadEx\n"); PrintHexAscii(pbPage1, 0x100); @@ -1215,7 +1135,7 @@ int main(_In_ int argc, _In_ char* argv[]) PVMMDLL_MAP_PFNENTRY pPfnEntry; cPfns = sizeof(dwPfns) / sizeof(DWORD); printf("CALL: VMMDLL_Map_GetPfn #1\n"); - result = VMMDLL_Map_GetPfn(dwPfns, cPfns, NULL, &cbPfnMap); + result = VMMDLL_Map_GetPfn(hVMM, dwPfns, cPfns, NULL, &cbPfnMap); if(!result) { printf("FAIL: VMMDLL_Map_GetPfn #1\n"); return 1; @@ -1225,7 +1145,7 @@ int main(_In_ int argc, _In_ char* argv[]) printf("FAIL: OutOfMemory\n"); return 1; } - result = VMMDLL_Map_GetPfn(dwPfns, cPfns, pPfnMap, &cbPfnMap); + result = VMMDLL_Map_GetPfn(hVMM, dwPfns, cPfns, pPfnMap, &cbPfnMap); if(!result) { printf("FAIL: VMMDLL_Map_GetPfn #2\n"); return 1; @@ -1256,27 +1176,17 @@ int main(_In_ int argc, _In_ char* argv[]) printf("------------------------------------------------------------\n"); printf("# Retrieve SERVICES \n"); ShowKeyPress(); - DWORD cbServiceMap = 0; PVMMDLL_MAP_SERVICE pServiceMap = NULL; PVMMDLL_MAP_SERVICEENTRY pServiceEntry; - printf("CALL: VMMDLL_Map_GetServicesU #1\n"); - result = VMMDLL_Map_GetServicesU(NULL, &cbServiceMap); + printf("CALL: VMMDLL_Map_GetServicesU\n"); + result = VMMDLL_Map_GetServicesU(hVMM, &pServiceMap); if(!result) { printf("FAIL: VMMDLL_Map_GetServicesU #1\n"); return 1; } - pServiceMap = LocalAlloc(LMEM_ZEROINIT, cbServiceMap); - if(!pServiceMap) { - printf("FAIL: OutOfMemory\n"); - return 1; - } - result = VMMDLL_Map_GetServicesU(pServiceMap, &cbServiceMap); - if(!result) { - printf("FAIL: VMMDLL_Map_GetServicesU #2\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; } { @@ -1295,6 +1205,7 @@ int main(_In_ int argc, _In_ char* argv[]) pServiceEntry->uszUserAcct ); } + VMMDLL_MemFree(pServiceMap); pServiceMap = NULL; } @@ -1303,28 +1214,18 @@ int main(_In_ int argc, _In_ char* argv[]) printf("# Retrieve Pool Tag Map \n"); ShowKeyPress(); DWORD iPoolTagEntry = 0, iPoolEntry = 0; - DWORD cbPoolMap = 0; PVMMDLL_MAP_POOL pPoolMap = NULL; PVMMDLL_MAP_POOLENTRY pPoolEntry; PVMMDLL_MAP_POOLENTRYTAG pPoolTag; printf("CALL: VMMDLL_Map_GetPool\n"); - result = VMMDLL_Map_GetPool(NULL, &cbPoolMap); + result = VMMDLL_Map_GetPool(hVMM, &pPoolMap, VMMDLL_POOLMAP_FLAG_ALL); if(!result) { - printf("FAIL: VMMDLL_Map_GetPool #1.\n"); - return 1; - } - pPoolMap = LocalAlloc(LMEM_ZEROINIT, cbPoolMap); - if(!pPoolMap) { - printf("FAIL: OutOfMemory\n"); - return 1; - } - result = VMMDLL_Map_GetPool(pPoolMap, &cbPoolMap); - if(!result) { - printf("FAIL: VMMDLL_Map_GetPool #2\n"); + 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) { @@ -1347,8 +1248,7 @@ int main(_In_ int argc, _In_ char* argv[]) } printf("SUCCESS: VMMDLL_Map_GetPool\n"); } - LocalFree(pPoolMap); - pPoolMap = NULL; + VMMDLL_MemFree(pPoolMap); pPoolMap = NULL; // Read virtual memory from multiple locations in one efficient sweep @@ -1360,13 +1260,13 @@ int main(_In_ int argc, _In_ char* argv[]) QWORD vaNt, vaHal, vaCi, vaBeep; BYTE pbNt[0x400]; DWORD cbNt = 0, cbCi = 0; - vaNt = VMMDLL_ProcessGetModuleBaseU(4, "ntoskrnl.exe"); - vaHal = VMMDLL_ProcessGetModuleBaseU(4, "hal.dll"); - vaCi = VMMDLL_ProcessGetModuleBaseU(4, "CI.DLL"); - vaBeep = VMMDLL_ProcessGetModuleBaseU(4, "beep.sys"); + 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(4, VMMDLL_FLAG_NOCACHE | VMMDLL_FLAG_NOPAGING_IO); + hS = VMMDLL_Scatter_Initialize(hVMM, 4, VMMDLL_FLAG_NOCACHE | VMMDLL_FLAG_NOPAGING_IO); if(result) { printf("SUCCESS: VMMDLL_Scatter_Initialize\n"); } else { @@ -1427,16 +1327,30 @@ int main(_In_ int argc, _In_ char* argv[]) printf("# Log a message using the MemProcFS logging system. \n"); ShowKeyPress(); printf("CALL: VMMDLL_ConfigSet - printf enable\n"); - VMMDLL_ConfigSet(VMMDLL_OPT_CORE_PRINTF_ENABLE, 1); + 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"); + + + + // 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"); diff --git a/vmmjava/VmmExample.java b/vmmjava/VmmExample.java index dc7f640..971d5e4 100644 --- a/vmmjava/VmmExample.java +++ b/vmmjava/VmmExample.java @@ -16,7 +16,7 @@ public class VmmExample { // arguments are as they are given on the command line. // also required is to specify the path to the native MemProcFS files // important! remember to close the vmm object after use to free up native resources! - String strPathToNativeBinaries = "C:\\Github\\MemProcFS"; + String strPathToNativeBinaries = "C:\\Github\\MemProcFS-dev\\files"; String[] argv = {"-printf", "-device", "c:\\dumps\\WIN7-X64-SP1-1.pmem"}; IVmm vmm = IVmm.initializeVmm(strPathToNativeBinaries, argv); diff --git a/vmmjava/vmm/internal/VmmImpl.java b/vmmjava/vmm/internal/VmmImpl.java index 2f7332e..d28bb69 100644 --- a/vmmjava/vmm/internal/VmmImpl.java +++ b/vmmjava/vmm/internal/VmmImpl.java @@ -24,10 +24,8 @@ public class VmmImpl implements IVmm //----------------------------------------------------------------------------- // INITIALIZATION FUNCTIONALITY BELOW: //----------------------------------------------------------------------------- - - private static final Object objLock = new Object(); - private static String vmmNativeLibraryPath = null; - private static VmmImpl vmmActive = null; + private Pointer hVMM = null; + private String vmmNativeLibraryPath = null; /* * Do not allow direct class instantiation from outside. @@ -36,24 +34,22 @@ public class VmmImpl implements IVmm { } + private VmmImpl(String vmmNativeLibraryPath, String argv[]) + { + System.setProperty("jna.library.path", vmmNativeLibraryPath); + hVMM = VmmNative.INSTANCE.VMMDLL_Initialize(argv.length, argv); + if(hVMM == null) { throw new VmmException("Vmm Init: failed in native code."); } + VmmNative.INSTANCE.VMMDLL_InitializePlugins(hVMM); + this.vmmNativeLibraryPath = vmmNativeLibraryPath; + } + public static IVmm Initialize(String vmmNativeLibraryPath, String argv[]) { - synchronized(objLock) { - if(vmmActive != null) { - throw new VmmException("vmm already initialized - close before re-initialize!"); - } - System.setProperty("jna.library.path", vmmNativeLibraryPath); - boolean f = VmmNative.INSTANCE.VMMDLL_Initialize(argv.length, argv); - if(!f) { throw new VmmException("Vmm Init: failed in native code."); } - VmmNative.INSTANCE.VMMDLL_InitializePlugins(); - VmmImpl.vmmNativeLibraryPath = vmmNativeLibraryPath; - VmmImpl.vmmActive = new VmmImpl(); - } - return VmmImpl.vmmActive; + return new VmmImpl(vmmNativeLibraryPath, argv); } public boolean isValid() { - return vmmActive != null; + return hVMM != null; } public String getNativeLibraryPath() { @@ -62,12 +58,8 @@ public class VmmImpl implements IVmm public void close() { - synchronized(objLock) { - if(vmmActive != null) { - VmmNative.INSTANCE.VMMDLL_Close(); - vmmActive = null; - } - } + VmmNative.INSTANCE.VMMDLL_Close(hVMM); + hVMM = null; } /* @@ -87,7 +79,7 @@ public class VmmImpl implements IVmm @Override public String toString() { - return (vmmActive != null) ? "Vmm" : "VmmNotValid"; + return (hVMM != null) ? "Vmm" : "VmmNotValid"; } @@ -99,14 +91,14 @@ public class VmmImpl implements IVmm public long getConfig(long fOption) { LongByReference pqw = new LongByReference(); - boolean f = VmmNative.INSTANCE.VMMDLL_ConfigGet(fOption, pqw); + boolean f = VmmNative.INSTANCE.VMMDLL_ConfigGet(hVMM, fOption, pqw); if(!f) { throw new VmmException(); } return pqw.getValue(); } public void setConfig(long fOption, long qw) { - boolean f = VmmNative.INSTANCE.VMMDLL_ConfigSet(fOption, qw); + boolean f = VmmNative.INSTANCE.VMMDLL_ConfigSet(hVMM, fOption, qw); if(!f) { throw new VmmException(); } } @@ -158,7 +150,7 @@ public class VmmImpl implements IVmm result.add(e); } }; - boolean f = VmmNative.INSTANCE.VMMDLL_VfsListU(_utilStringToCString(path), vfs); + boolean f = VmmNative.INSTANCE.VMMDLL_VfsListU(hVMM, _utilStringToCString(path), vfs); if(!f) { throw new VmmException(); } return result; } @@ -167,7 +159,7 @@ public class VmmImpl implements IVmm { IntByReference pcbRead = new IntByReference(); Pointer pb = new Memory(size); - VmmNative.INSTANCE.VMMDLL_VfsReadU(_utilStringToCString(file), pb, size, pcbRead, offset); + VmmNative.INSTANCE.VMMDLL_VfsReadU(hVMM, _utilStringToCString(file), pb, size, pcbRead, offset); if(0 == pcbRead.getValue()) { throw new VmmException(); } size = Math.min(size, pcbRead.getValue()); byte[] result = new byte[size]; @@ -186,7 +178,7 @@ public class VmmImpl implements IVmm IntByReference pcbWrite = new IntByReference(); Pointer pb = new Memory(data.length); pb.write(0, data, 0, data.length); - VmmNative.INSTANCE.VMMDLL_VfsWriteU(_utilStringToCString(file), pb, data.length, pcbWrite, offset); + VmmNative.INSTANCE.VMMDLL_VfsWriteU(hVMM, _utilStringToCString(file), pb, data.length, pcbWrite, offset); if(0 == pcbWrite.getValue()) { throw new VmmException(); } } @@ -293,7 +285,7 @@ public class VmmImpl implements IVmm { IntByReference pcbRead = new IntByReference(); Pointer pb = new Memory(size); - boolean f = VmmNative.INSTANCE.VMMDLL_MemReadEx(pid, va, pb, size, pcbRead, flags); + boolean f = VmmNative.INSTANCE.VMMDLL_MemReadEx(hVMM, pid, va, pb, size, pcbRead, flags); if(!f) { throw new VmmException(); } size = Math.min(size, pcbRead.getValue()); byte[] result = new byte[size]; @@ -305,27 +297,27 @@ public class VmmImpl implements IVmm { Pointer pb = new Memory(data.length); pb.write(0, data, 0, data.length); - boolean f = VmmNative.INSTANCE.VMMDLL_MemWrite(pid, va, pb, data.length); + boolean f = VmmNative.INSTANCE.VMMDLL_MemWrite(hVMM, pid, va, pb, data.length); if(!f) { throw new VmmException(); } } public void _memPrefetchPages(int pid, long[] vas) { - boolean f = VmmNative.INSTANCE.VMMDLL_MemPrefetchPages(pid, vas, vas.length); + boolean f = VmmNative.INSTANCE.VMMDLL_MemPrefetchPages(hVMM, pid, vas, vas.length); if(!f) { throw new VmmException(); } } public long _memVirtualToPhysical(int pid, long va) { LongByReference pa = new LongByReference(); - boolean f = VmmNative.INSTANCE.VMMDLL_MemVirt2Phys(pid, va, pa); + boolean f = VmmNative.INSTANCE.VMMDLL_MemVirt2Phys(hVMM, pid, va, pa); if(!f) { throw new VmmException(); } return pa.getValue(); } public IVmmMemScatterMemory _memScatterInitialize(int pid, int flags) { - Pointer hS = VmmNative.INSTANCE.VMMDLL_Scatter_Initialize(pid, flags); + Pointer hS = VmmNative.INSTANCE.VMMDLL_Scatter_Initialize(hVMM, pid, flags); if(hS == null) { throw new VmmException(); } return new VmmMemScatterMemoryImpl(hS, pid, flags); } @@ -371,7 +363,7 @@ public class VmmImpl implements IVmm private VmmPdbImpl(int dwPID, long vaModuleBase) { byte[] szModuleName = new byte[VmmNative.MAX_PATH]; - boolean f = VmmNative.INSTANCE.VMMDLL_PdbLoad(dwPID, vaModuleBase, szModuleName); + boolean f = VmmNative.INSTANCE.VMMDLL_PdbLoad(hVMM, dwPID, vaModuleBase, szModuleName); if(!f) { throw new VmmException(); } this.pdbName = Native.toString(szModuleName); } @@ -391,7 +383,7 @@ public class VmmImpl implements IVmm public long getSymbolAddress(String strSymbol) { LongByReference pvaSymbolAddress = new LongByReference(); - boolean f = VmmNative.INSTANCE.VMMDLL_PdbSymbolAddress(pdbName, strSymbol, pvaSymbolAddress); + boolean f = VmmNative.INSTANCE.VMMDLL_PdbSymbolAddress(hVMM, pdbName, strSymbol, pvaSymbolAddress); if(!f) { throw new VmmException(); } return pvaSymbolAddress.getValue(); } @@ -399,21 +391,21 @@ public class VmmImpl implements IVmm public String getSymbolName(long vaSymbolOrOffset) { IntByReference pdwSymbolDisplacement = new IntByReference(); byte[] szSymbolName = new byte[VmmNative.MAX_PATH]; - boolean f = VmmNative.INSTANCE.VMMDLL_PdbSymbolName(pdbName, vaSymbolOrOffset, szSymbolName, pdwSymbolDisplacement); + boolean f = VmmNative.INSTANCE.VMMDLL_PdbSymbolName(hVMM, pdbName, vaSymbolOrOffset, szSymbolName, pdwSymbolDisplacement); if(!f) { throw new VmmException(); } return Native.toString(szSymbolName); } public int getTypeChildOffset(String strTypeName, String strChild) { IntByReference pcbTypeChildOffset = new IntByReference(); - boolean f = VmmNative.INSTANCE.VMMDLL_PdbTypeChildOffset(pdbName, strTypeName, strChild, pcbTypeChildOffset); + boolean f = VmmNative.INSTANCE.VMMDLL_PdbTypeChildOffset(hVMM, pdbName, strTypeName, strChild, pcbTypeChildOffset); if(!f) { throw new VmmException(); } return pcbTypeChildOffset.getValue(); } public int getTypeSize(String strTypeName) { IntByReference pcbTypeSize = new IntByReference(); - boolean f = VmmNative.INSTANCE.VMMDLL_PdbTypeSize(pdbName, strTypeName, pcbTypeSize); + boolean f = VmmNative.INSTANCE.VMMDLL_PdbTypeSize(hVMM, pdbName, strTypeName, pcbTypeSize); if(!f) { throw new VmmException(); } return pcbTypeSize.getValue(); } @@ -448,13 +440,10 @@ public class VmmImpl implements IVmm public List mapPhysicalMemory() { - IntByReference pcbMap = new IntByReference(); - boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetPhysMem(null, pcbMap); + PointerByReference pptr = new PointerByReference(); + boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetPhysMem(hVMM, pptr); if(!f) { throw new VmmException(); } - Pointer ptr = new Memory(pcbMap.getValue()); - f = VmmNative.INSTANCE.VMMDLL_Map_GetPhysMem(ptr, pcbMap); - if(!f) { throw new VmmException(); } - VmmNative.VMMDLL_MAP_PHYSMEM pMap = new VmmNative.VMMDLL_MAP_PHYSMEM(ptr); + VmmNative.VMMDLL_MAP_PHYSMEM pMap = new VmmNative.VMMDLL_MAP_PHYSMEM(pptr.getValue()); // process result: ArrayList result = new ArrayList(); for(VmmNative.VMMDLL_MAP_PHYSMEM_ENTRY n : pMap.pMap) { @@ -463,18 +452,16 @@ public class VmmImpl implements IVmm e.cb = n.cb; result.add(e); } + VmmNative.INSTANCE.VMMDLL_MemFree(pptr.getValue()); return result; } public List mapNet() { - IntByReference pcbMap = new IntByReference(); - boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetNetU(null, pcbMap); + PointerByReference pptr = new PointerByReference(); + boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetNetU(hVMM, pptr); if(!f) { throw new VmmException(); } - Pointer ptr = new Memory(pcbMap.getValue()); - f = VmmNative.INSTANCE.VMMDLL_Map_GetNetU(ptr, pcbMap); - if(!f) { throw new VmmException(); } - VmmNative.VMMDLL_MAP_NET pMap = new VmmNative.VMMDLL_MAP_NET(ptr); + VmmNative.VMMDLL_MAP_NET pMap = new VmmNative.VMMDLL_MAP_NET(pptr.getValue()); // process result: ArrayList result = new ArrayList(); for(VmmNative.VMMDLL_MAP_NETENTRY n : pMap.pMap) { @@ -494,18 +481,16 @@ public class VmmImpl implements IVmm e.dstStr = n.Dst.uszText; result.add(e); } + VmmNative.INSTANCE.VMMDLL_MemFree(pptr.getValue()); return result; } public List mapUser() { - IntByReference pcbMap = new IntByReference(); - boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetUsersU(null, pcbMap); + PointerByReference pptr = new PointerByReference(); + boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetUsersU(hVMM, pptr); if(!f) { throw new VmmException(); } - Pointer ptr = new Memory(pcbMap.getValue()); - f = VmmNative.INSTANCE.VMMDLL_Map_GetUsersU(ptr, pcbMap); - if(!f) { throw new VmmException(); } - VmmNative.VMMDLL_MAP_USER pMap = new VmmNative.VMMDLL_MAP_USER(ptr); + VmmNative.VMMDLL_MAP_USER pMap = new VmmNative.VMMDLL_MAP_USER(pptr.getValue()); // process result: ArrayList result = new ArrayList(); for(VmmNative.VMMDLL_MAP_USERENTRY n : pMap.pMap) { @@ -515,18 +500,16 @@ public class VmmImpl implements IVmm e.vaRegHive = n.vaRegHive; result.add(e); } + VmmNative.INSTANCE.VMMDLL_MemFree(pptr.getValue()); return result; } public List mapService() { - IntByReference pcbMap = new IntByReference(); - boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetServicesU(null, pcbMap); + PointerByReference pptr = new PointerByReference(); + boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetServicesU(hVMM, pptr); if(!f) { throw new VmmException(); } - Pointer ptr = new Memory(pcbMap.getValue()); - f = VmmNative.INSTANCE.VMMDLL_Map_GetServicesU(ptr, pcbMap); - if(!f) { throw new VmmException(); } - VmmNative.VMMDLL_MAP_SERVICE pMap = new VmmNative.VMMDLL_MAP_SERVICE(ptr); + VmmNative.VMMDLL_MAP_SERVICE pMap = new VmmNative.VMMDLL_MAP_SERVICE(pptr.getValue()); // process result: ArrayList result = new ArrayList(); for(VmmNative.VMMDLL_MAP_SERVICEENTRY n : pMap.pMap) { @@ -550,13 +533,14 @@ public class VmmImpl implements IVmm e.dwWaitHint = n.ServiceStatus.dwWaitHint; result.add(e); } + VmmNative.INSTANCE.VMMDLL_MemFree(pptr.getValue()); return result; } public VmmMap_PoolMap mapPool() { PointerByReference pptr = new PointerByReference(); - boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetPoolEx(pptr, VmmNative.VMMDLL_POOLMAP_FLAG_ALL); + boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetPool(hVMM, pptr, VmmNative.VMMDLL_POOLMAP_FLAG_ALL); if(!f) { throw new VmmException(); } VmmNative.VMMDLL_MAP_POOL pMap = new VmmNative.VMMDLL_MAP_POOL(pptr.getValue()); // process result: @@ -605,12 +589,12 @@ public class VmmImpl implements IVmm */ private void ensure() { if(this.info == null) { - IntByReference pcbInfo = new IntByReference(); + LongByReference pcbInfo = new LongByReference(); VmmNative.VMMDLL_PROCESS_INFORMATION pInfo = new VmmNative.VMMDLL_PROCESS_INFORMATION(); pcbInfo.setValue(Native.getNativeSize(VmmNative.VMMDLL_PROCESS_INFORMATION.class, pInfo)); pInfo.magic = VmmNative.MMDLL_PROCESS_INFORMATION_MAGIC; pInfo.wVersion = VmmNative.VMMDLL_PROCESS_INFORMATION_VERSION; - boolean f = VmmNative.INSTANCE.VMMDLL_ProcessGetInformation(pid, pInfo, pcbInfo); + boolean f = VmmNative.INSTANCE.VMMDLL_ProcessGetInformation(hVMM, pid, pInfo, pcbInfo); if(!f) { throw new VmmException(); } if(pInfo.wVersion != VmmNative.VMMDLL_PROCESS_INFORMATION_VERSION) { throw new VmmException("Bad Version"); } this.info = pInfo; @@ -651,13 +635,10 @@ public class VmmImpl implements IVmm } public List mapHandle() { - IntByReference pcbMap = new IntByReference(); - boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetHandleU(pid, null, pcbMap); + PointerByReference pptr = new PointerByReference(); + boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetHandleU(hVMM, pid, pptr); if(!f) { throw new VmmException(); } - Pointer ptr = new Memory(pcbMap.getValue()); - f = VmmNative.INSTANCE.VMMDLL_Map_GetHandleU(pid, ptr, pcbMap); - if(!f) { throw new VmmException(); } - VmmNative.VMMDLL_MAP_HANDLE pMap = new VmmNative.VMMDLL_MAP_HANDLE(ptr); + VmmNative.VMMDLL_MAP_HANDLE pMap = new VmmNative.VMMDLL_MAP_HANDLE(pptr.getValue()); // process result: ArrayList result = new ArrayList(); for(VmmNative.VMMDLL_MAP_HANDLEENTRY n : pMap.pMap) { @@ -675,12 +656,13 @@ public class VmmImpl implements IVmm e.type = n.uszType; result.add(e); } + VmmNative.INSTANCE.VMMDLL_MemFree(pptr.getValue()); return result; } public List mapHeapAlloc(long qwHeapNumOrAddress) { PointerByReference pptr = new PointerByReference(); - boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetHeapAllocEx(pid, qwHeapNumOrAddress, pptr); + boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetHeapAlloc(hVMM, pid, qwHeapNumOrAddress, pptr); if(!f) { throw new VmmException(); } VmmNative.VMMDLL_MAP_HEAPALLOC pMap = new VmmNative.VMMDLL_MAP_HEAPALLOC(pptr.getValue()); // process result: @@ -699,7 +681,7 @@ public class VmmImpl implements IVmm public VmmMap_HeapMap mapHeap() { PointerByReference pptr = new PointerByReference(); - boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetHeapEx(pid, pptr); + boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetHeap(hVMM, pid, pptr); if(!f) { throw new VmmException(); } VmmNative.VMMDLL_MAP_HEAP pMap = new VmmNative.VMMDLL_MAP_HEAP(pptr.getValue()); // process result: @@ -728,13 +710,10 @@ public class VmmImpl implements IVmm } public List mapPte() { - IntByReference pcbMap = new IntByReference(); - boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetPteU(pid, null, pcbMap, true); + PointerByReference pptr = new PointerByReference(); + boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetPteU(hVMM, pid, true, pptr); if(!f) { throw new VmmException(); } - Pointer ptr = new Memory(pcbMap.getValue()); - f = VmmNative.INSTANCE.VMMDLL_Map_GetPteU(pid, ptr, pcbMap, true); - if(!f) { throw new VmmException(); } - VmmNative.VMMDLL_MAP_PTE pMap = new VmmNative.VMMDLL_MAP_PTE(ptr); + VmmNative.VMMDLL_MAP_PTE pMap = new VmmNative.VMMDLL_MAP_PTE(pptr.getValue()); // process result: ArrayList result = new ArrayList(); for(VmmNative.VMMDLL_MAP_PTEENTRY n : pMap.pMap) { @@ -747,17 +726,15 @@ public class VmmImpl implements IVmm e.cSoftware = n.cSoftware; result.add(e); } + VmmNative.INSTANCE.VMMDLL_MemFree(pptr.getValue()); return result; } public List mapThread() { - IntByReference pcbMap = new IntByReference(); - boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetThread(pid, null, pcbMap); + PointerByReference pptr = new PointerByReference(); + boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetThread(hVMM, pid, pptr); if(!f) { throw new VmmException(); } - Pointer ptr = new Memory(pcbMap.getValue()); - f = VmmNative.INSTANCE.VMMDLL_Map_GetThread(pid, ptr, pcbMap); - if(!f) { throw new VmmException(); } - VmmNative.VMMDLL_MAP_THREAD pMap = new VmmNative.VMMDLL_MAP_THREAD(ptr); + VmmNative.VMMDLL_MAP_THREAD pMap = new VmmNative.VMMDLL_MAP_THREAD(pptr.getValue()); // process result: ArrayList result = new ArrayList(); for(VmmNative.VMMDLL_MAP_THREADENTRY n : pMap.pMap) { @@ -788,17 +765,15 @@ public class VmmImpl implements IVmm e.bWaitReason = n.bWaitReason; result.add(e); } + VmmNative.INSTANCE.VMMDLL_MemFree(pptr.getValue()); return result; } public List mapUnloadedModule() { - IntByReference pcbMap = new IntByReference(); - boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetUnloadedModuleU(pid, null, pcbMap); + PointerByReference pptr = new PointerByReference(); + boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetUnloadedModuleU(hVMM, pid, pptr); if(!f) { throw new VmmException(); } - Pointer ptr = new Memory(pcbMap.getValue()); - f = VmmNative.INSTANCE.VMMDLL_Map_GetUnloadedModuleU(pid, ptr, pcbMap); - if(!f) { throw new VmmException(); } - VmmNative.VMMDLL_MAP_UNLOADEDMODULE pMap = new VmmNative.VMMDLL_MAP_UNLOADEDMODULE(ptr); + VmmNative.VMMDLL_MAP_UNLOADEDMODULE pMap = new VmmNative.VMMDLL_MAP_UNLOADEDMODULE(pptr.getValue()); // process result: ArrayList result = new ArrayList(); for(VmmNative.VMMDLL_MAP_UNLOADEDMODULEENTRY n : pMap.pMap) { @@ -812,17 +787,15 @@ public class VmmImpl implements IVmm e.ftUnload = n.ftUnload; result.add(e); } + VmmNative.INSTANCE.VMMDLL_MemFree(pptr.getValue()); return result; } public List mapVad() { - IntByReference pcbMap = new IntByReference(); - boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetVadU(pid, null, pcbMap, true); + PointerByReference pptr = new PointerByReference(); + boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetVadU(hVMM, pid, true, pptr); if(!f) { throw new VmmException(); } - Pointer ptr = new Memory(pcbMap.getValue()); - f = VmmNative.INSTANCE.VMMDLL_Map_GetVadU(pid, ptr, pcbMap, true); - if(!f) { throw new VmmException(); } - VmmNative.VMMDLL_MAP_VAD pMap = new VmmNative.VMMDLL_MAP_VAD(ptr); + VmmNative.VMMDLL_MAP_VAD pMap = new VmmNative.VMMDLL_MAP_VAD(pptr.getValue()); // process result: ArrayList result = new ArrayList(); for(VmmNative.VMMDLL_MAP_VADENTRY n : pMap.pMap) { @@ -842,17 +815,15 @@ public class VmmImpl implements IVmm e.cVadExPagesBase = n.cVadExPagesBase; result.add(e); } + VmmNative.INSTANCE.VMMDLL_MemFree(pptr.getValue()); return result; } public List mapVadEx(int oPage, int cPage) { - IntByReference pcbMap = new IntByReference(); - boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetVadEx(pid, null, pcbMap, oPage, cPage); + PointerByReference pptr = new PointerByReference(); + boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetVadEx(hVMM, pid, oPage, cPage, pptr); if(!f) { throw new VmmException(); } - Pointer ptr = new Memory(pcbMap.getValue()); - f = VmmNative.INSTANCE.VMMDLL_Map_GetVadEx(pid, ptr, pcbMap, oPage, cPage); - if(!f) { throw new VmmException(); } - VmmNative.VMMDLL_MAP_VADEX pMap = new VmmNative.VMMDLL_MAP_VADEX(ptr); + VmmNative.VMMDLL_MAP_VADEX pMap = new VmmNative.VMMDLL_MAP_VADEX(pptr.getValue()); // process result: ArrayList result = new ArrayList(); for(VmmNative.VMMDLL_MAP_VADEXENTRY n : pMap.pMap) { @@ -868,6 +839,7 @@ public class VmmImpl implements IVmm e.vaVadBase = n.vaVadBase; result.add(e); } + VmmNative.INSTANCE.VMMDLL_MemFree(pptr.getValue()); return result; } @@ -927,15 +899,24 @@ public class VmmImpl implements IVmm } public String getPathUser() { - return VmmNative.INSTANCE.VMMDLL_ProcessGetInformationString(pid, VmmNative.VMMDLL_PROCESS_INFORMATION_OPT_STRING_PATH_USER_IMAGE); + Pointer p = VmmNative.INSTANCE.VMMDLL_ProcessGetInformationString(hVMM, pid, VmmNative.VMMDLL_PROCESS_INFORMATION_OPT_STRING_PATH_USER_IMAGE); + String s = p.getString(0); + VmmNative.INSTANCE.VMMDLL_MemFree(p); + return s; } public String getCmdLine() { - return VmmNative.INSTANCE.VMMDLL_ProcessGetInformationString(pid, VmmNative.VMMDLL_PROCESS_INFORMATION_OPT_STRING_CMDLINE); + Pointer p = VmmNative.INSTANCE.VMMDLL_ProcessGetInformationString(hVMM, pid, VmmNative.VMMDLL_PROCESS_INFORMATION_OPT_STRING_CMDLINE); + String s = p.getString(0); + VmmNative.INSTANCE.VMMDLL_MemFree(p); + return s; } public String getPathKernel() { - return VmmNative.INSTANCE.VMMDLL_ProcessGetInformationString(pid, VmmNative.VMMDLL_PROCESS_INFORMATION_OPT_STRING_PATH_KERNEL); + Pointer p = VmmNative.INSTANCE.VMMDLL_ProcessGetInformationString(hVMM, pid, VmmNative.VMMDLL_PROCESS_INFORMATION_OPT_STRING_PATH_KERNEL); + String s = p.getString(0); + VmmNative.INSTANCE.VMMDLL_MemFree(p); + return s; } public int getTpMemoryModel() { @@ -972,29 +953,25 @@ public class VmmImpl implements IVmm } public IVmmModule moduleGet(String name) { - IntByReference pcbMap = new IntByReference(); - boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetModuleFromNameU(pid, name, null, pcbMap); + PointerByReference pptr = new PointerByReference(); + boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetModuleFromNameU(hVMM, pid, name, pptr); if(!f) { throw new VmmException(); } - Pointer ptr = new Memory(pcbMap.getValue()); - f = VmmNative.INSTANCE.VMMDLL_Map_GetModuleFromNameU(pid, name, ptr, pcbMap); - if(!f) { throw new VmmException(); } - VmmNative.VMMDLL_MAP_MODULEENTRY pEntry = new VmmNative.VMMDLL_MAP_MODULEENTRY(ptr); + VmmNative.VMMDLL_MAP_MODULEENTRY pEntry = new VmmNative.VMMDLL_MAP_MODULEENTRY(pptr.getValue()); + VmmNative.INSTANCE.VMMDLL_MemFree(pptr.getValue()); return new VmmImpl.VmmModuleImpl(this, pEntry); } public List moduleGetAll() { - IntByReference pcbMap = new IntByReference(); - boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetModuleU(pid, null, pcbMap); + PointerByReference pptr = new PointerByReference(); + boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetModuleU(hVMM, pid, pptr); if(!f) { throw new VmmException(); } - Pointer ptr = new Memory(pcbMap.getValue()); - f = VmmNative.INSTANCE.VMMDLL_Map_GetModuleU(pid, ptr, pcbMap); - if(!f) { throw new VmmException(); } - VmmNative.VMMDLL_MAP_MODULE pMap = new VmmNative.VMMDLL_MAP_MODULE(ptr); + VmmNative.VMMDLL_MAP_MODULE pMap = new VmmNative.VMMDLL_MAP_MODULE(pptr.getValue()); // process result: ArrayList result = new ArrayList(); for(VmmNative.VMMDLL_MAP_MODULEENTRY n : pMap.pMap) { result.add(new VmmImpl.VmmModuleImpl(this, n)); } + VmmNative.INSTANCE.VMMDLL_MemFree(pptr.getValue()); return result; } } @@ -1015,7 +992,7 @@ public class VmmImpl implements IVmm public IVmmProcess processGet(String name) { IntByReference pdwPID = new IntByReference(); - boolean f = VmmNative.INSTANCE.VMMDLL_PidGetFromName(_utilStringToCString(name), pdwPID); + boolean f = VmmNative.INSTANCE.VMMDLL_PidGetFromName(hVMM, _utilStringToCString(name), pdwPID); if(!f) { throw new VmmException(); } return new VmmProcessImpl(pdwPID.getValue()); } @@ -1023,10 +1000,10 @@ public class VmmImpl implements IVmm public List processGetAll() { LongByReference pcPIDs = new LongByReference(); - boolean f = VmmNative.INSTANCE.VMMDLL_PidList(null, pcPIDs); + boolean f = VmmNative.INSTANCE.VMMDLL_PidList(hVMM, null, pcPIDs); if(!f) { throw new VmmException(); } int[] pids = new int[(int)pcPIDs.getValue()]; - f = VmmNative.INSTANCE.VMMDLL_PidList(pids, pcPIDs); + f = VmmNative.INSTANCE.VMMDLL_PidList(hVMM, pids, pcPIDs); if(!f) { throw new VmmException(); } // process result: ArrayList result = new ArrayList(); @@ -1106,15 +1083,14 @@ public class VmmImpl implements IVmm } public long getProcAddress(String szFunctionName) { - return VmmNative.INSTANCE.VMMDLL_ProcessGetProcAddressU(pid, module.uszText, szFunctionName); + return VmmNative.INSTANCE.VMMDLL_ProcessGetProcAddressU(hVMM, pid, module.uszText, szFunctionName); } @Override public List mapDataDirectory() { final String[] DIRECTORIES = { "EXPORT", "IMPORT", "RESOURCE", "EXCEPTION", "SECURITY", "BASERELOC", "DEBUG", "ARCHITECTURE", "GLOBALPTR", "TLS", "LOAD_CONFIG", "BOUND_IMPORT", "IAT", "DELAY_IMPORT", "COM_DESCRIPTOR", "RESERVED" }; - IntByReference pcData = new IntByReference(); VmmNative.IMAGE_DATA_DIRECTORY[] aData = new VmmNative.IMAGE_DATA_DIRECTORY[16]; - boolean f = VmmNative.INSTANCE.VMMDLL_ProcessGetDirectoriesU(pid, module.uszText, aData, 16, pcData); + boolean f = VmmNative.INSTANCE.VMMDLL_ProcessGetDirectoriesU(hVMM, pid, module.uszText, aData); if(!f) { throw new VmmException(); } // process result: ArrayList result = new ArrayList(); @@ -1132,11 +1108,11 @@ public class VmmImpl implements IVmm public List mapSection() { IntByReference pcData = new IntByReference(); - boolean f = VmmNative.INSTANCE.VMMDLL_ProcessGetSectionsU(pid, module.uszText, null, 0, pcData); + boolean f = VmmNative.INSTANCE.VMMDLL_ProcessGetSectionsU(hVMM, pid, module.uszText, null, 0, pcData); if(!f) { throw new VmmException(); } int cData = pcData.getValue(); VmmNative.IMAGE_SECTION_HEADER[] aData = new VmmNative.IMAGE_SECTION_HEADER[cData]; - f = VmmNative.INSTANCE.VMMDLL_ProcessGetSectionsU(pid, module.uszText, aData, cData, pcData); + f = VmmNative.INSTANCE.VMMDLL_ProcessGetSectionsU(hVMM, pid, module.uszText, aData, cData, pcData); if(!f) { throw new VmmException(); } // process result: ArrayList result = new ArrayList(); @@ -1158,13 +1134,10 @@ public class VmmImpl implements IVmm } public List mapExport() { - IntByReference pcbMap = new IntByReference(); - boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetEATU(pid, module.uszText, null, pcbMap); + PointerByReference pptr = new PointerByReference(); + boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetEATU(hVMM, pid, module.uszText, pptr); if(!f) { throw new VmmException(); } - Pointer ptr = new Memory(pcbMap.getValue()); - f = VmmNative.INSTANCE.VMMDLL_Map_GetEATU(pid, module.uszText, ptr, pcbMap); - if(!f) { throw new VmmException(); } - VmmNative.VMMDLL_MAP_EAT pMap = new VmmNative.VMMDLL_MAP_EAT(ptr); + VmmNative.VMMDLL_MAP_EAT pMap = new VmmNative.VMMDLL_MAP_EAT(pptr.getValue()); // process result: ArrayList result = new ArrayList(); for(VmmNative.VMMDLL_MAP_EATENTRY n : pMap.pMap) { @@ -1177,17 +1150,15 @@ public class VmmImpl implements IVmm e.uszModule = module.uszText; result.add(e); } + VmmNative.INSTANCE.VMMDLL_MemFree(pptr.getValue()); return result; } public List mapImport() { - IntByReference pcbMap = new IntByReference(); - boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetIATU(pid, module.uszText, null, pcbMap); + PointerByReference pptr = new PointerByReference(); + boolean f = VmmNative.INSTANCE.VMMDLL_Map_GetIATU(hVMM, pid, module.uszText, pptr); if(!f) { throw new VmmException(); } - Pointer ptr = new Memory(pcbMap.getValue()); - f = VmmNative.INSTANCE.VMMDLL_Map_GetIATU(pid, module.uszText, ptr, pcbMap); - if(!f) { throw new VmmException(); } - VmmNative.VMMDLL_MAP_IAT pMap = new VmmNative.VMMDLL_MAP_IAT(ptr); + VmmNative.VMMDLL_MAP_IAT pMap = new VmmNative.VMMDLL_MAP_IAT(pptr.getValue()); // process result: ArrayList result = new ArrayList(); for(VmmNative.VMMDLL_MAP_IATENTRY n : pMap.pMap) { @@ -1203,6 +1174,7 @@ public class VmmImpl implements IVmm e.rvaNameFunction = n.rvaNameFunction; result.add(e); } + VmmNative.INSTANCE.VMMDLL_MemFree(pptr.getValue()); return result; } @@ -1261,7 +1233,7 @@ public class VmmImpl implements IVmm public byte[] memRead(int ra, int size, int flags) { IntByReference pcbRead = new IntByReference(); Pointer pb = new Memory(size); - boolean f = VmmNative.INSTANCE.VMMDLL_WinReg_HiveReadEx(hive.vaCMHIVE, ra, pb, size, pcbRead, flags); + boolean f = VmmNative.INSTANCE.VMMDLL_WinReg_HiveReadEx(hVMM, hive.vaCMHIVE, ra, pb, size, pcbRead, flags); if(!f) { throw new VmmException(); } size = Math.min(size, pcbRead.getValue()); byte[] result = new byte[size]; @@ -1270,7 +1242,7 @@ public class VmmImpl implements IVmm } public void memWrite(int ra, byte[] data) { - boolean f = VmmNative.INSTANCE.VMMDLL_WinReg_HiveWrite(hive.vaCMHIVE, ra, data, data.length); + boolean f = VmmNative.INSTANCE.VMMDLL_WinReg_HiveWrite(hVMM, hive.vaCMHIVE, ra, data, data.length); if(!f) { throw new VmmException(); } } @@ -1322,7 +1294,7 @@ public class VmmImpl implements IVmm byte[] lpName = new byte[VmmNative.MAX_PATH]; IntByReference lpcchName = new IntByReference(VmmNative.MAX_PATH); HashMap result = new HashMap(); - while(VmmNative.INSTANCE.VMMDLL_WinReg_EnumKeyExU(strPath, i, lpName, lpcchName, null)) { + while(VmmNative.INSTANCE.VMMDLL_WinReg_EnumKeyExU(hVMM, strPath, i, lpName, lpcchName, null)) { String strName = Native.toString(lpName); result.put(strName, new VmmRegKeyImpl(strPath + "\\" + strName)); i++; @@ -1336,7 +1308,7 @@ public class VmmImpl implements IVmm IntByReference lpcchValueName = new IntByReference(VmmNative.MAX_PATH); IntByReference lpType = new IntByReference(); HashMap result = new HashMap(); - while(VmmNative.INSTANCE.VMMDLL_WinReg_EnumValueU(strPath, i, lpValueName, lpcchValueName, lpType, null, null)) { + while(VmmNative.INSTANCE.VMMDLL_WinReg_EnumValueU(hVMM, strPath, i, lpValueName, lpcchValueName, lpType, null, null)) { String strName = Native.toString(lpValueName); result.put(strName, new VmmRegValueImpl(strPath + "\\" + strName, lpType.getValue())); i++; @@ -1347,7 +1319,7 @@ public class VmmImpl implements IVmm public long getTime() { IntByReference cch = new IntByReference(); LongByReference lpftLastWriteTime = new LongByReference(); - boolean f = VmmNative.INSTANCE.VMMDLL_WinReg_EnumKeyExU(strPath, -1, null, cch, lpftLastWriteTime); + boolean f = VmmNative.INSTANCE.VMMDLL_WinReg_EnumKeyExU(hVMM, strPath, -1, null, cch, lpftLastWriteTime); if(!f) { throw new VmmException(); } return lpftLastWriteTime.getValue(); } @@ -1377,10 +1349,10 @@ public class VmmImpl implements IVmm public byte[] getValue() { IntByReference lpType = new IntByReference(); IntByReference lpcbData = new IntByReference(); - boolean f = VmmNative.INSTANCE.VMMDLL_WinReg_QueryValueExU(strPath, lpType, null, lpcbData); + boolean f = VmmNative.INSTANCE.VMMDLL_WinReg_QueryValueExU(hVMM, strPath, lpType, null, lpcbData); if(!f) { throw new VmmException(); } byte[] data = new byte[lpcbData.getValue()]; - f = VmmNative.INSTANCE.VMMDLL_WinReg_QueryValueExU(strPath, lpType, data, lpcbData); + f = VmmNative.INSTANCE.VMMDLL_WinReg_QueryValueExU(hVMM, strPath, lpType, data, lpcbData); if(!f) { throw new VmmException(); } return data; } @@ -1418,11 +1390,11 @@ public class VmmImpl implements IVmm public List regHive() { IntByReference pcHives = new IntByReference(); - boolean f = VmmNative.INSTANCE.VMMDLL_WinReg_HiveList(null, 0, pcHives); + boolean f = VmmNative.INSTANCE.VMMDLL_WinReg_HiveList(hVMM, null, 0, pcHives); if(!f) { throw new VmmException(); } int cHives = pcHives.getValue(); VMMDLL_REGISTRY_HIVE_INFORMATION[] pHives = new VMMDLL_REGISTRY_HIVE_INFORMATION[cHives]; - f = VmmNative.INSTANCE.VMMDLL_WinReg_HiveList(pHives, cHives, pcHives); + f = VmmNative.INSTANCE.VMMDLL_WinReg_HiveList(hVMM, pHives, cHives, pcHives); if(!f) { throw new VmmException(); } cHives = pcHives.getValue(); ArrayList result = new ArrayList(); @@ -1434,7 +1406,7 @@ public class VmmImpl implements IVmm public IVmmRegKey regKey(String strFullPath) { IntByReference lpcchName = new IntByReference(); - boolean f = VmmNative.INSTANCE.VMMDLL_WinReg_EnumKeyExU(strFullPath, -1, null, lpcchName, null); + boolean f = VmmNative.INSTANCE.VMMDLL_WinReg_EnumKeyExU(hVMM, strFullPath, -1, null, lpcchName, null); if(!f) { return null; } return new VmmRegKeyImpl(strFullPath); } @@ -1442,7 +1414,7 @@ public class VmmImpl implements IVmm public IVmmRegValue regValue(String strFullPath) { IntByReference lpType = new IntByReference(); IntByReference lpcbData = new IntByReference(); - boolean f = VmmNative.INSTANCE.VMMDLL_WinReg_QueryValueExU(strFullPath, lpType, null, lpcbData); + boolean f = VmmNative.INSTANCE.VMMDLL_WinReg_QueryValueExU(hVMM, strFullPath, lpType, null, lpcbData); if(!f) { return null; } return new VmmRegValueImpl(strFullPath, lpType.getValue()); } diff --git a/vmmjava/vmm/internal/VmmNative.java b/vmmjava/vmm/internal/VmmNative.java index 367f128..252ee48 100644 --- a/vmmjava/vmm/internal/VmmNative.java +++ b/vmmjava/vmm/internal/VmmNative.java @@ -45,18 +45,20 @@ interface VmmNative extends Library { - boolean VMMDLL_Initialize(int argc, String argv[]); - boolean VMMDLL_Close(); + Pointer VMMDLL_Initialize(int argc, String argv[]); + void VMMDLL_Close(Pointer hVMM); + void VMMDLL_CloseAll(); + long VMMDLL_MemSize(Pointer pvMem); void VMMDLL_MemFree(Pointer pvMem); - boolean VMMDLL_ConfigGet(long fOption, LongByReference pqwValue); - boolean VMMDLL_ConfigSet(long fOption, long qwValue); + boolean VMMDLL_ConfigGet(Pointer hVMM, long fOption, LongByReference pqwValue); + boolean VMMDLL_ConfigSet(Pointer hVMM, long fOption, long qwValue); - boolean VMMDLL_InitializePlugins(); + boolean VMMDLL_InitializePlugins(Pointer hVMM); @@ -74,20 +76,20 @@ interface VmmNative extends Library { } } - boolean VMMDLL_VfsListU(byte[] uszPath, VMMDLL_VFS_FILELIST2 pFileList); - int VMMDLL_VfsReadU(byte[] uszFileName, Pointer pb, int cb, IntByReference pcbRead, long cbOffset); - int VMMDLL_VfsWriteU(byte[] uszFileName, Pointer pb, int cb, IntByReference pcbWrite, long cbOffset); + boolean VMMDLL_VfsListU(Pointer hVMM, byte[] uszPath, VMMDLL_VFS_FILELIST2 pFileList); + int VMMDLL_VfsReadU(Pointer hVMM, byte[] uszFileName, Pointer pb, int cb, IntByReference pcbRead, long cbOffset); + int VMMDLL_VfsWriteU(Pointer hVMM, byte[] uszFileName, Pointer pb, int cb, IntByReference pcbWrite, long cbOffset); - boolean VMMDLL_MemReadEx(int dwPID, long qwA, Pointer pb, int cb, IntByReference pcbReadOpt, int flags); - boolean VMMDLL_MemPrefetchPages(int dwPID, long[] pPrefetchAddresses, int cPrefetchAddresses); - boolean VMMDLL_MemWrite(int dwPID, long qwA, Pointer pb, int cb); - boolean VMMDLL_MemVirt2Phys(int dwPID, long qwVA, LongByReference pqwPA); + boolean VMMDLL_MemReadEx(Pointer hVMM, int dwPID, long qwA, Pointer pb, int cb, IntByReference pcbReadOpt, int flags); + boolean VMMDLL_MemPrefetchPages(Pointer hVMM, int dwPID, long[] pPrefetchAddresses, int cPrefetchAddresses); + boolean VMMDLL_MemWrite(Pointer hVMM, int dwPID, long qwA, Pointer pb, int cb); + boolean VMMDLL_MemVirt2Phys(Pointer hVMM, int dwPID, long qwVA, LongByReference pqwPA); - Pointer VMMDLL_Scatter_Initialize(int dwPID, int flags); + Pointer VMMDLL_Scatter_Initialize(Pointer hVMM, int dwPID, int flags); boolean VMMDLL_Scatter_Prepare(Pointer hS, long va, int cb); boolean VMMDLL_Scatter_PrepareWrite(Pointer hS, long va, Pointer pb, int cb); boolean VMMDLL_Scatter_Execute(Pointer hS); @@ -97,8 +99,8 @@ interface VmmNative extends Library { - boolean VMMDLL_PidGetFromName(byte[] szProcName, IntByReference pdwPID); - boolean VMMDLL_PidList(int[] pPIDs, LongByReference pcPIDs); + boolean VMMDLL_PidGetFromName(Pointer hVMM, byte[] szProcName, IntByReference pdwPID); + boolean VMMDLL_PidList(Pointer hVMM, int[] pPIDs, LongByReference pcPIDs); @@ -128,7 +130,7 @@ interface VmmNative extends Library { } } - boolean VMMDLL_Map_GetPhysMem(Pointer pPhysMemMap, IntByReference pcbPhysMemMap); + boolean VMMDLL_Map_GetPhysMem(Pointer hVMM, PointerByReference ppPhysMemMap); @@ -177,7 +179,7 @@ interface VmmNative extends Library { } } - boolean VMMDLL_Map_GetNetU(Pointer pNetMap, IntByReference pcbNetMap); + boolean VMMDLL_Map_GetNetU(Pointer hVMM, PointerByReference ppPhysMemMap); @@ -210,7 +212,7 @@ interface VmmNative extends Library { } } - boolean VMMDLL_Map_GetUsersU(Pointer pUserMap, IntByReference pcbUserMap); + boolean VMMDLL_Map_GetUsersU(Pointer hVMM, PointerByReference ppUserMap); @@ -262,7 +264,7 @@ interface VmmNative extends Library { } } - boolean VMMDLL_Map_GetServicesU(Pointer pServiceMap, IntByReference pcbServiceMap); + boolean VMMDLL_Map_GetServicesU(Pointer hVMM, PointerByReference ppServiceMap); @@ -299,7 +301,7 @@ interface VmmNative extends Library { } } - boolean VMMDLL_Map_GetPoolEx(PointerByReference pServiceMap, int flags); + boolean VMMDLL_Map_GetPool(Pointer hVMM, PointerByReference ppPoolMap, int flags); @@ -340,7 +342,7 @@ interface VmmNative extends Library { } } - boolean VMMDLL_Map_GetHandleU(int dwPID, Pointer pHandleMap, IntByReference pcbHandleMap); + boolean VMMDLL_Map_GetHandleU(Pointer hVMM, int dwPID, PointerByReference ppHandleMap); @@ -385,7 +387,7 @@ interface VmmNative extends Library { } } - boolean VMMDLL_Map_GetHeapEx(int dwPID, PointerByReference ppHeapMap); + boolean VMMDLL_Map_GetHeap(Pointer hVMM, int dwPID, PointerByReference ppHeapMap); @@ -415,7 +417,7 @@ interface VmmNative extends Library { } } - boolean VMMDLL_Map_GetHeapAllocEx(int dwPID, long qwHeapNumOrAddress, PointerByReference ppHeapAllocMap); + boolean VMMDLL_Map_GetHeapAlloc(Pointer hVMM, int dwPID, long qwHeapNumOrAddress, PointerByReference ppHeapAllocMap); @@ -451,7 +453,7 @@ interface VmmNative extends Library { } } - boolean VMMDLL_Map_GetPteU(int dwPID, Pointer pPteMap, IntByReference pcbPteMap, boolean fIdentifyModules); + boolean VMMDLL_Map_GetPteU(Pointer hVMM, int dwPID, boolean fIdentifyModules, PointerByReference ppPteMap); @@ -503,7 +505,7 @@ interface VmmNative extends Library { } } - boolean VMMDLL_Map_GetThread(int dwPID, Pointer pThreadMap, IntByReference pcbThreadMap); + boolean VMMDLL_Map_GetThread(Pointer hVMM, int dwPID, PointerByReference ppThreadMap); @@ -539,7 +541,7 @@ interface VmmNative extends Library { } } - boolean VMMDLL_Map_GetUnloadedModuleU(int dwPID, Pointer pUnloadedModuleMap, IntByReference pcbUnloadedModuleMap); + boolean VMMDLL_Map_GetUnloadedModuleU(Pointer hVMM, int dwPID, PointerByReference ppUnloadedModuleMap); @@ -584,7 +586,7 @@ interface VmmNative extends Library { } } - boolean VMMDLL_Map_GetVadU(int dwPID, Pointer pVadMap, IntByReference pcbVadMap, boolean fIdentifyModules); + boolean VMMDLL_Map_GetVadU(Pointer hVMM, int dwPID, boolean fIdentifyModules, PointerByReference ppVadMap); @@ -620,7 +622,7 @@ interface VmmNative extends Library { } } - boolean VMMDLL_Map_GetVadEx(int dwPID, Pointer pVadExMap, IntByReference pcbVadExMap, int oPage, int cPage); + boolean VMMDLL_Map_GetVadEx(Pointer hVMM, int dwPID, int oPage, int cPage, PointerByReference ppVadExMap); @@ -655,8 +657,8 @@ interface VmmNative extends Library { public int IntegrityLevel; } - boolean VMMDLL_ProcessGetInformation(int dwPID, VMMDLL_PROCESS_INFORMATION pProcessInformation, IntByReference pcbProcessInformation); - String VMMDLL_ProcessGetInformationString(int dwPID, int fOptionString); + boolean VMMDLL_ProcessGetInformation(Pointer hVMM, int dwPID, VMMDLL_PROCESS_INFORMATION pProcessInformation, LongByReference pcbProcessInformation); + Pointer VMMDLL_ProcessGetInformationString(Pointer hVMM, int dwPID, int fOptionString); @@ -710,12 +712,12 @@ interface VmmNative extends Library { } } - boolean VMMDLL_Map_GetModuleU(int dwPID, Pointer pModuleMap, IntByReference pcbModuleMap); - boolean VMMDLL_Map_GetModuleFromNameU(int dwPID, String uszModuleName, Pointer pModuleMapEntry, IntByReference pcbModuleMap); + boolean VMMDLL_Map_GetModuleU(Pointer hVMM, int dwPID, PointerByReference ppModuleMap); + boolean VMMDLL_Map_GetModuleFromNameU(Pointer hVMM, int dwPID, String uszModuleName, PointerByReference ppModuleMapEntry); - long VMMDLL_ProcessGetProcAddressU(int dwPID, String uszModuleName, String szFunctionName); + long VMMDLL_ProcessGetProcAddressU(Pointer hVMM, int dwPID, String uszModuleName, String szFunctionName); @@ -755,7 +757,7 @@ interface VmmNative extends Library { } } - boolean VMMDLL_Map_GetEATU(int dwPID, String uszModuleName, Pointer pEatMap, IntByReference pcbEatMap); + boolean VMMDLL_Map_GetEATU(Pointer hVMM, int dwPID, String uszModuleName, PointerByReference ppEatMap); @@ -797,7 +799,7 @@ interface VmmNative extends Library { } } - boolean VMMDLL_Map_GetIATU(int dwPID, String uszModuleName, Pointer pIatMap, IntByReference pcbIatMap); + boolean VMMDLL_Map_GetIATU(Pointer hVMM, int dwPID, String uszModuleName, PointerByReference ppIatMap); @@ -807,7 +809,7 @@ interface VmmNative extends Library { public int Size; } - boolean VMMDLL_ProcessGetDirectoriesU(int dwPID, String uszModule, IMAGE_DATA_DIRECTORY[] pData, int cData, IntByReference pcData); + boolean VMMDLL_ProcessGetDirectoriesU(Pointer hVMM, int dwPID, String uszModule, IMAGE_DATA_DIRECTORY[] pData); @@ -825,15 +827,15 @@ interface VmmNative extends Library { public int Characteristics; } - boolean VMMDLL_ProcessGetSectionsU(int dwPID, String uszModule, IMAGE_SECTION_HEADER[] pData, int cData, IntByReference pcData); + boolean VMMDLL_ProcessGetSectionsU(Pointer hVMM, int dwPID, String uszModule, IMAGE_SECTION_HEADER[] pData, int cData, IntByReference pcData); - boolean VMMDLL_PdbLoad(int dwPID, long vaModuleBase, byte[] szModuleName); - boolean VMMDLL_PdbSymbolName(String szModule, long cbSymbolAddressOrOffset, byte[] szModuleName, IntByReference pdwSymbolDisplacement); - boolean VMMDLL_PdbSymbolAddress(String szModule, String szTypeName, LongByReference pcbTypeSize); - boolean VMMDLL_PdbTypeSize(String szModule, String szTypeName, IntByReference pcbTypeSize); - boolean VMMDLL_PdbTypeChildOffset(String szModule, String uszTypeName, String uszTypeChildName, IntByReference pdwSymbolDisplacement); + boolean VMMDLL_PdbLoad(Pointer hVMM, int dwPID, long vaModuleBase, byte[] szModuleName); + boolean VMMDLL_PdbSymbolName(Pointer hVMM, String szModule, long cbSymbolAddressOrOffset, byte[] szModuleName, IntByReference pdwSymbolDisplacement); + boolean VMMDLL_PdbSymbolAddress(Pointer hVMM, String szModule, String szTypeName, LongByReference pcbTypeSize); + boolean VMMDLL_PdbTypeSize(Pointer hVMM, String szModule, String szTypeName, IntByReference pcbTypeSize); + boolean VMMDLL_PdbTypeChildOffset(Pointer hVMM, String szModule, String uszTypeName, String uszTypeChildName, IntByReference pdwSymbolDisplacement); @@ -842,7 +844,7 @@ interface VmmNative extends Library { public long magic; public short wVersion; public short wSize; - public byte[] _FutureReserved1 = new byte[0x14]; + public byte[] _FutureReserved1 = new byte[0x34]; public long vaCMHIVE; public long vaHBASE_BLOCK; public int cbLength; @@ -852,10 +854,10 @@ interface VmmNative extends Library { public long[] _FutureReserved = new long[0x10]; } - boolean VMMDLL_WinReg_HiveList(VMMDLL_REGISTRY_HIVE_INFORMATION[] pHives, int cHives, IntByReference pcHives); - boolean VMMDLL_WinReg_HiveReadEx(long vaCMHive, int ra, Pointer ptr, int cb, IntByReference pcbReadOpt, long flags); - boolean VMMDLL_WinReg_HiveWrite(long vaCMHive, int ra, byte[] pb, int cb); - boolean VMMDLL_WinReg_EnumKeyExU(String uszFullPathKey, int dwIndex, byte[] lpName, IntByReference lpcchName, LongByReference lpftLastWriteTime); - boolean VMMDLL_WinReg_EnumValueU(String uszFullPathKey, int dwIndex, byte[] lpValueName, IntByReference lpcchValueName, IntByReference lpType, byte[] lpData, IntByReference lpcbData); - boolean VMMDLL_WinReg_QueryValueExU(String uszFullPathKeyValue, IntByReference lpType, byte[] lpData, IntByReference lpcbData); + boolean VMMDLL_WinReg_HiveList(Pointer hVMM, VMMDLL_REGISTRY_HIVE_INFORMATION[] pHives, int cHives, IntByReference pcHives); + boolean VMMDLL_WinReg_HiveReadEx(Pointer hVMM, long vaCMHive, int ra, Pointer ptr, int cb, IntByReference pcbReadOpt, long flags); + boolean VMMDLL_WinReg_HiveWrite(Pointer hVMM, long vaCMHive, int ra, byte[] pb, int cb); + boolean VMMDLL_WinReg_EnumKeyExU(Pointer hVMM, String uszFullPathKey, int dwIndex, byte[] lpName, IntByReference lpcchName, LongByReference lpftLastWriteTime); + boolean VMMDLL_WinReg_EnumValueU(Pointer hVMM, String uszFullPathKey, int dwIndex, byte[] lpValueName, IntByReference lpcchValueName, IntByReference lpType, byte[] lpData, IntByReference lpcbData); + boolean VMMDLL_WinReg_QueryValueExU(Pointer hVMM, String uszFullPathKeyValue, IntByReference lpType, byte[] lpData, IntByReference lpcbData); } diff --git a/vmmpyc/version.h b/vmmpyc/version.h index bf06691..d9cebc7 100644 --- a/vmmpyc/version.h +++ b/vmmpyc/version.h @@ -1,10 +1,10 @@ #define STRINGIZE2(s) #s #define STRINGIZE(s) STRINGIZE2(s) -#define VERSION_MAJOR 4 -#define VERSION_MINOR 9 -#define VERSION_REVISION 3 -#define VERSION_BUILD 72 +#define VERSION_MAJOR 5 +#define VERSION_MINOR 0 +#define VERSION_REVISION 0 +#define VERSION_BUILD 73 #define VER_FILE_DESCRIPTION_STR "MemProcFS : Python API" #define VER_FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_BUILD diff --git a/vmmpyc/vmmpyc.c b/vmmpyc/vmmpyc.c index b944ac9..ed1e2a7 100644 --- a/vmmpyc/vmmpyc.c +++ b/vmmpyc/vmmpyc.c @@ -10,7 +10,7 @@ //----------------------------------------------------------------------------- // ([DWORD], (DWORD)) -> [{...}] -PyObject* VmmPyc_MemReadScatter(_In_ DWORD dwPID, _In_ LPSTR szFN, PyObject *args) +PyObject* VmmPyc_MemReadScatter(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ LPSTR szFN, PyObject *args) { PyObject *pyListSrc, *pyListItemSrc, *pyListDst, *pyDict; BOOL result; @@ -37,7 +37,7 @@ PyObject* VmmPyc_MemReadScatter(_In_ DWORD dwPID, _In_ LPSTR szFN, PyObject *arg } // call c-dll for vmm Py_BEGIN_ALLOW_THREADS; - result = VMMDLL_MemReadScatter(dwPID, ppMEMs, cMEMs, flags); + result = VMMDLL_MemReadScatter(H, dwPID, ppMEMs, cMEMs, flags); Py_END_ALLOW_THREADS; if(!result) { LcMemFree(ppMEMs); @@ -62,7 +62,7 @@ PyObject* VmmPyc_MemReadScatter(_In_ DWORD dwPID, _In_ LPSTR szFN, PyObject *arg } // (ULONG64, DWORD, (ULONG64)) -> PBYTE -PyObject* VmmPyc_MemRead(_In_ DWORD dwPID, _In_ LPSTR szFN, PyObject *args) +PyObject* VmmPyc_MemRead(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ LPSTR szFN, PyObject *args) { PyObject *pyBytes; BOOL result; @@ -75,7 +75,7 @@ PyObject* VmmPyc_MemRead(_In_ DWORD dwPID, _In_ LPSTR szFN, PyObject *args) pb = LocalAlloc(0, cb); if(!pb) { return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS; - result = VMMDLL_MemReadEx(dwPID, qwA, pb, cb, &cbRead, flags); + result = VMMDLL_MemReadEx(H, dwPID, qwA, pb, cb, &cbRead, flags); Py_END_ALLOW_THREADS; if(!result) { LocalFree(pb); @@ -87,7 +87,7 @@ PyObject* VmmPyc_MemRead(_In_ DWORD dwPID, _In_ LPSTR szFN, PyObject *args) } // (ULONG64, PBYTE) -> None -PyObject* VmmPyc_MemWrite(_In_ DWORD dwPID, _In_ LPSTR szFN, PyObject *args) +PyObject* VmmPyc_MemWrite(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ LPSTR szFN, PyObject *args) { BOOL result; ULONG64 va; @@ -100,7 +100,7 @@ PyObject* VmmPyc_MemWrite(_In_ DWORD dwPID, _In_ LPSTR szFN, PyObject *args) return Py_BuildValue("s", NULL); // zero-byte write is always successful. } Py_BEGIN_ALLOW_THREADS; - result = VMMDLL_MemWrite(dwPID, va, pb, (DWORD)cb); + result = VMMDLL_MemWrite(H, dwPID, va, pb, (DWORD)cb); Py_END_ALLOW_THREADS; if(!result) { return PyErr_Format(PyExc_RuntimeError, "%s: Failed.", szFN); } return Py_BuildValue("s", NULL); // None returned on success. diff --git a/vmmpyc/vmmpyc.h b/vmmpyc/vmmpyc.h index 7cfba58..4a8dbdf 100644 --- a/vmmpyc/vmmpyc.h +++ b/vmmpyc/vmmpyc.h @@ -92,6 +92,9 @@ extern PyObject *g_pPyType_Module; extern PyObject *g_pPyType_Process; extern PyObject *g_pPyType_ProcessMaps; +extern VMM_HANDLE g_PluginVMM; +extern BOOL g_PluginVMM_LoadedOnce; + typedef struct tdPyObj_Vmm { PyObject_HEAD BOOL fValid; @@ -99,32 +102,38 @@ typedef struct tdPyObj_Vmm { PyObject *pyObjVfs; PyObject *pyObjKernel; PyObject *pyObjMemory; + VMM_HANDLE hVMM; } PyObj_Vmm; typedef struct tdPyObj_Pdb { PyObject_HEAD BOOL fValid; + PyObj_Vmm *pyVMM; CHAR szModule[MAX_PATH]; } PyObj_Pdb; typedef struct tdPyObj_Vfs { PyObject_HEAD BOOL fValid; + PyObj_Vmm *pyVMM; } PyObj_Vfs; typedef struct tdPyObj_Maps { PyObject_HEAD BOOL fValid; + PyObj_Vmm *pyVMM; } PyObj_Maps; typedef struct tdPyObj_PhysicalMemory { PyObject_HEAD BOOL fValid; + PyObj_Vmm *pyVMM; } PyObj_PhysicalMemory; typedef struct tdPyObj_ScatterMemory { PyObject_HEAD BOOL fValid; + PyObj_Vmm *pyVMM; DWORD dwPID; DWORD dwReadFlags; VMMDLL_SCATTER_HANDLE hScatter; @@ -133,6 +142,7 @@ typedef struct tdPyObj_ScatterMemory { typedef struct tdPyObj_Module { PyObject_HEAD BOOL fValid; + PyObj_Vmm *pyVMM; DWORD dwPID; VMMDLL_MAP_MODULEENTRY ModuleEntry; CHAR uszText[64]; @@ -142,6 +152,7 @@ typedef struct tdPyObj_Module { typedef struct tdPyObj_ModuleMaps { PyObject_HEAD BOOL fValid; + PyObj_Vmm *pyVMM; DWORD dwPID; CHAR uszModule[64]; } PyObj_ModuleMaps; @@ -149,6 +160,7 @@ typedef struct tdPyObj_ModuleMaps { typedef struct tdPyObj_Kernel { PyObject_HEAD BOOL fValid; + PyObj_Vmm *pyVMM; PyObject *pyObjPdb; PyObject *pyObjProcess; } PyObj_Kernel; @@ -156,6 +168,7 @@ typedef struct tdPyObj_Kernel { typedef struct tdPyObj_Process { PyObject_HEAD BOOL fValid; + PyObj_Vmm *pyVMM; DWORD dwPID; BOOL fValidInfo; VMMDLL_PROCESS_INFORMATION Info; @@ -164,30 +177,35 @@ typedef struct tdPyObj_Process { typedef struct tdPyObj_ProcessMaps { PyObject_HEAD BOOL fValid; + PyObj_Vmm *pyVMM; DWORD dwPID; } PyObj_ProcessMaps; typedef struct tdPyObj_VirtualMemory { PyObject_HEAD BOOL fValid; + PyObj_Vmm *pyVMM; DWORD dwPID; } PyObj_VirtualMemory; typedef struct tdPyObj_RegHive { PyObject_HEAD BOOL fValid; + PyObj_Vmm *pyVMM; VMMDLL_REGISTRY_HIVE_INFORMATION Info; } PyObj_RegHive; typedef struct tdPyObj_RegMemory { PyObject_HEAD BOOL fValid; + PyObj_Vmm *pyVMM; QWORD vaCMHive; } PyObj_RegMemory; typedef struct tdPyObj_RegKey { PyObject_HEAD BOOL fValid; + PyObj_Vmm *pyVMM; PyObject *pyName; // unicode object CHAR uszPath[2 * MAX_PATH]; QWORD ftLastWrite; @@ -196,6 +214,7 @@ typedef struct tdPyObj_RegKey { typedef struct tdPyObj_RegValue { PyObject_HEAD BOOL fValid; + PyObj_Vmm *pyVMM; PyObject *pyName; // unicode object CHAR uszPath[2 * MAX_PATH]; BOOL fValue; @@ -264,25 +283,25 @@ _Success_(return) BOOL VmmPycScatterMemory_InitializeType(PyObject *pModule); _Success_(return) BOOL VmmPycVirtualMemory_InitializeType(PyObject *pModule); _Success_(return) BOOL VmmPycRegMemory_InitializeType(PyObject *pModule); -PyObj_Pdb* VmmPycPdb_InitializeInternal1(_In_ DWORD dwPID, _In_ QWORD vaModuleBase); -PyObj_Pdb* VmmPycPdb_InitializeInternal2(_In_ LPSTR szModule); -PyObj_Vfs* VmmPycVfs_InitializeInternal(); -PyObj_Maps* VmmPycMaps_InitializeInternal(); -PyObj_PhysicalMemory* VmmPycPhysicalMemory_InitializeInternal(); -PyObj_ScatterMemory *VmmPycScatterMemory_InitializeInternal(_In_ DWORD dwPID, _In_ DWORD dwReadFlags); -PyObj_Kernel* VmmPycKernel_InitializeInternal(); -PyObj_Process* VmmPycProcess_InitializeInternal(_In_ DWORD dwPID, _In_ BOOL fVerify); -PyObj_ProcessMaps* VmmPycProcessMaps_InitializeInternal(_In_ DWORD dwPID); -PyObj_VirtualMemory* VmmPycVirtualMemory_InitializeInternal(_In_ DWORD dwPID); -PyObj_Module* VmmPycModule_InitializeInternal(_In_ DWORD dwPID, _In_ PVMMDLL_MAP_MODULEENTRY pe); -PyObj_ModuleMaps* VmmPycModuleMaps_InitializeInternal(_In_ DWORD dwPID, _In_ LPSTR uszModule); -PyObj_RegHive* VmmPycRegHive_InitializeInternal(_In_ PVMMDLL_REGISTRY_HIVE_INFORMATION pInfo); -PyObj_RegMemory* VmmPycRegMemory_InitializeInternal(_In_ QWORD vaCMHive); -PyObj_RegKey* VmmPycRegKey_InitializeInternal(_In_ LPSTR uszFullPathKey, _In_ BOOL fVerify); -PyObj_RegValue* VmmPycRegValue_InitializeInternal(_In_ LPSTR uszFullPathKeyValue, _In_ BOOL fVerify); +PyObj_Pdb* VmmPycPdb_InitializeInternal1(_In_ PyObj_Vmm *pyVMM, _In_ DWORD dwPID, _In_ QWORD vaModuleBase); +PyObj_Pdb* VmmPycPdb_InitializeInternal2(_In_ PyObj_Vmm *pyVMM, _In_ LPSTR szModule); +PyObj_Vfs* VmmPycVfs_InitializeInternal(_In_ PyObj_Vmm *pyVMM); +PyObj_Maps* VmmPycMaps_InitializeInternal(_In_ PyObj_Vmm *pyVMM); +PyObj_PhysicalMemory* VmmPycPhysicalMemory_InitializeInternal(_In_ PyObj_Vmm *pyVMM); +PyObj_ScatterMemory *VmmPycScatterMemory_InitializeInternal(_In_ PyObj_Vmm *pyVMM, _In_ DWORD dwPID, _In_ DWORD dwReadFlags); +PyObj_Kernel* VmmPycKernel_InitializeInternal(_In_ PyObj_Vmm *pyVMM); +PyObj_Process* VmmPycProcess_InitializeInternal(_In_ PyObj_Vmm *pyVMM, _In_ DWORD dwPID, _In_ BOOL fVerify); +PyObj_ProcessMaps* VmmPycProcessMaps_InitializeInternal(_In_ PyObj_Vmm *pyVMM, _In_ DWORD dwPID); +PyObj_VirtualMemory* VmmPycVirtualMemory_InitializeInternal(_In_ PyObj_Vmm *pyVMM, _In_ DWORD dwPID); +PyObj_Module* VmmPycModule_InitializeInternal(_In_ PyObj_Vmm *pyVMM, _In_ DWORD dwPID, _In_ PVMMDLL_MAP_MODULEENTRY pe); +PyObj_ModuleMaps* VmmPycModuleMaps_InitializeInternal(_In_ PyObj_Vmm *pyVMM, _In_ DWORD dwPID, _In_ LPSTR uszModule); +PyObj_RegHive* VmmPycRegHive_InitializeInternal(_In_ PyObj_Vmm *pyVMM, _In_ PVMMDLL_REGISTRY_HIVE_INFORMATION pInfo); +PyObj_RegMemory* VmmPycRegMemory_InitializeInternal(_In_ PyObj_Vmm *pyVMM, _In_ QWORD vaCMHive); +PyObj_RegKey* VmmPycRegKey_InitializeInternal(_In_ PyObj_Vmm *pyVMM, _In_ LPSTR uszFullPathKey, _In_ BOOL fVerify); +PyObj_RegValue* VmmPycRegValue_InitializeInternal(_In_ PyObj_Vmm *pyVMM, _In_ LPSTR uszFullPathKeyValue, _In_ BOOL fVerify); -PyObject* VmmPyc_MemReadScatter(_In_ DWORD dwPID, _In_ LPSTR szFN, PyObject *args); -PyObject* VmmPyc_MemRead(_In_ DWORD dwPID, _In_ LPSTR szFN, PyObject *args); -PyObject* VmmPyc_MemWrite(_In_ DWORD dwPID, _In_ LPSTR szFN, PyObject *args); +PyObject* VmmPyc_MemReadScatter(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ LPSTR szFN, PyObject *args); +PyObject* VmmPyc_MemRead(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ LPSTR szFN, PyObject *args); +PyObject* VmmPyc_MemWrite(_In_ VMM_HANDLE H, _In_ DWORD dwPID, _In_ LPSTR szFN, PyObject *args); #endif /* __VMMPYC_H__ */ diff --git a/vmmpyc/vmmpyc_kernel.c b/vmmpyc/vmmpyc_kernel.c index 584f0bd..d0c9181 100644 --- a/vmmpyc/vmmpyc_kernel.c +++ b/vmmpyc/vmmpyc_kernel.c @@ -12,7 +12,7 @@ static PyObject* VmmPycKernel_build(PyObj_Kernel *self, void *closure) { QWORD qwBuild = 0; - VMMDLL_ConfigGet(VMMDLL_OPT_WIN_VERSION_BUILD, &qwBuild); + VMMDLL_ConfigGet(self->pyVMM->hVMM, VMMDLL_OPT_WIN_VERSION_BUILD, &qwBuild); return PyLong_FromLongLong(qwBuild); } @@ -21,7 +21,7 @@ static PyObject* VmmPycKernel_process(PyObj_Kernel *self, void *closure) { if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "Kernel.process: Not initialized."); } - return (PyObject*)VmmPycProcess_InitializeInternal(4, FALSE); + return (PyObject*)VmmPycProcess_InitializeInternal(self->pyVMM, 4, FALSE); } //----------------------------------------------------------------------------- @@ -29,13 +29,14 @@ VmmPycKernel_process(PyObj_Kernel *self, void *closure) //----------------------------------------------------------------------------- PyObj_Kernel* -VmmPycKernel_InitializeInternal() +VmmPycKernel_InitializeInternal(_In_ PyObj_Vmm *pyVMM) { PyObj_Kernel *pyObjKernel; if(!(pyObjKernel = PyObject_New(PyObj_Kernel, (PyTypeObject*)g_pPyType_Kernel))) { return NULL; } + Py_INCREF(pyVMM); pyObjKernel->pyVMM = pyVMM; pyObjKernel->fValid = TRUE; - pyObjKernel->pyObjProcess = (PyObject*)VmmPycProcess_InitializeInternal(4, FALSE); - pyObjKernel->pyObjPdb = (PyObject*)VmmPycPdb_InitializeInternal2("nt"); + pyObjKernel->pyObjProcess = (PyObject*)VmmPycProcess_InitializeInternal(pyVMM, 4, FALSE); + pyObjKernel->pyObjPdb = (PyObject*)VmmPycPdb_InitializeInternal2(pyVMM, "nt"); return pyObjKernel; } @@ -56,6 +57,7 @@ static void VmmPycKernel_dealloc(PyObj_Kernel *self) { self->fValid = FALSE; + Py_XDECREF(self->pyVMM); self->pyVMM = NULL; Py_XDECREF(self->pyObjPdb); self->pyObjPdb = NULL; Py_XDECREF(self->pyObjProcess); self->pyObjProcess = NULL; } diff --git a/vmmpyc/vmmpyc_maps.c b/vmmpyc/vmmpyc_maps.c index bed805d..7a9b2cb 100644 --- a/vmmpyc/vmmpyc_maps.c +++ b/vmmpyc/vmmpyc_maps.c @@ -37,7 +37,7 @@ VmmPycMaps_pool(PyObj_Maps *self, PyObject *args) if(!(pyDictResultVA = PyDict_New())) { return PyErr_NoMemory(); } PyDict_SetItemString_DECREF(pyDictResult, "va", pyDictResultVA); if(!(pyDictResultTag = PyDict_New())) { return PyErr_NoMemory(); } PyDict_SetItemString_DECREF(pyDictResult, "tag", pyDictResultTag); Py_BEGIN_ALLOW_THREADS; - result = VMMDLL_Map_GetPoolEx(&pPoolMap, VMMDLL_POOLMAP_FLAG_ALL); + result = VMMDLL_Map_GetPool(self->pyVMM->hVMM, &pPoolMap, VMMDLL_POOLMAP_FLAG_ALL); Py_END_ALLOW_THREADS; if(!result || (pPoolMap->dwVersion != VMMDLL_MAP_POOL_VERSION)) { Py_DECREF(pyDictResult); @@ -74,22 +74,18 @@ VmmPycMaps_net(PyObj_Maps *self, PyObject *args) { PyObject *pyList, *pyDictTcpE; BOOL result; - DWORD i, dwIpVersion, cbNetMap = 0; + DWORD i, dwIpVersion; PVMMDLL_MAP_NET pNetMap = NULL; PVMMDLL_MAP_NETENTRY pe; CHAR szTime[24]; if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "Maps.net(): Not initialized."); } if(!(pyList = PyList_New(0))) { return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS; - result = - VMMDLL_Map_GetNetU(NULL, &cbNetMap) && - cbNetMap && - (pNetMap = LocalAlloc(0, cbNetMap)) && - VMMDLL_Map_GetNetU(pNetMap, &cbNetMap); + result = VMMDLL_Map_GetNetU(self->pyVMM->hVMM, &pNetMap); Py_END_ALLOW_THREADS; if(!result || (pNetMap->dwVersion != VMMDLL_MAP_NET_VERSION)) { Py_DECREF(pyList); - LocalFree(pNetMap); + VMMDLL_MemFree(pNetMap); return PyErr_Format(PyExc_RuntimeError, "Maps.net(): Failed."); } // add tcp endpoint entries to TcpE list @@ -123,22 +119,17 @@ VmmPycMaps_memmap(PyObj_Maps *self, PyObject *args) { PyObject *pyList, *pyList_MemRange; BOOL result; - DWORD cbPhysMemMap = 0; ULONG64 i; PVMMDLL_MAP_PHYSMEM pPhysMemMap = NULL; PVMMDLL_MAP_PHYSMEMENTRY pe; if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "Maps.memmap(): Not initialized."); } if(!(pyList = PyList_New(0))) { return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS; - result = - VMMDLL_Map_GetPhysMem(NULL, &cbPhysMemMap) && - cbPhysMemMap && - (pPhysMemMap = LocalAlloc(0, cbPhysMemMap)) && - VMMDLL_Map_GetPhysMem(pPhysMemMap, &cbPhysMemMap); + result = VMMDLL_Map_GetPhysMem(self->pyVMM->hVMM, &pPhysMemMap); Py_END_ALLOW_THREADS; if(!result || (pPhysMemMap->dwVersion != VMMDLL_MAP_PHYSMEM_VERSION)) { Py_DECREF(pyList); - LocalFree(pPhysMemMap); + VMMDLL_MemFree(pPhysMemMap); return PyErr_Format(PyExc_RuntimeError, "Maps.memmap(): Failed."); } for(i = 0; i < pPhysMemMap->cMap; i++) { @@ -149,7 +140,7 @@ VmmPycMaps_memmap(PyObj_Maps *self, PyObject *args) PyList_Append_DECREF(pyList, pyList_MemRange); } } - LocalFree(pPhysMemMap); + VMMDLL_MemFree(pPhysMemMap); return pyList; } @@ -184,9 +175,9 @@ VmmPycMaps_pfn(PyObj_Maps *self, PyObject *args) // call c-dll for vmm Py_BEGIN_ALLOW_THREADS; result = - VMMDLL_Map_GetPfn(pPfns, cPfns, NULL, &cbPfnMap) && + VMMDLL_Map_GetPfn(self->pyVMM->hVMM, pPfns, cPfns, NULL, &cbPfnMap) && (pPfnMap = LocalAlloc(0, cbPfnMap)) && - VMMDLL_Map_GetPfn(pPfns, cPfns, pPfnMap, &cbPfnMap); + VMMDLL_Map_GetPfn(self->pyVMM->hVMM, pPfns, cPfns, pPfnMap, &cbPfnMap); Py_END_ALLOW_THREADS; if(!result || (pPfnMap->dwVersion != VMMDLL_MAP_PFN_VERSION)) { LocalFree(pPfnMap); @@ -218,22 +209,17 @@ VmmPycMaps_user(PyObj_Maps *self, PyObject *args) { PyObject *pyList, *pyDict; BOOL result; - DWORD cbUserMap = 0; ULONG64 i; PVMMDLL_MAP_USER pUserMap = NULL; PVMMDLL_MAP_USERENTRY pe; if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "Maps.user(): Not initialized."); } if(!(pyList = PyList_New(0))) { return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS; - result = - VMMDLL_Map_GetUsersU(NULL, &cbUserMap) && - cbUserMap && - (pUserMap = LocalAlloc(0, cbUserMap)) && - VMMDLL_Map_GetUsersU(pUserMap, &cbUserMap); + result = VMMDLL_Map_GetUsersU(self->pyVMM->hVMM, &pUserMap); Py_END_ALLOW_THREADS; if(!result || (pUserMap->dwVersion != VMMDLL_MAP_USER_VERSION)) { Py_DECREF(pyList); - LocalFree(pUserMap); + VMMDLL_MemFree(pUserMap);; return PyErr_Format(PyExc_RuntimeError, "Maps.user(): Failed."); } for(i = 0; i < pUserMap->cMap; i++) { @@ -245,7 +231,7 @@ VmmPycMaps_user(PyObj_Maps *self, PyObject *args) PyList_Append_DECREF(pyList, pyDict); } } - LocalFree(pUserMap); + VMMDLL_MemFree(pUserMap); return pyList; } @@ -255,22 +241,17 @@ VmmPycMaps_service(PyObj_Maps *self, PyObject *args) { PyObject *pyDictResult, *pyDict; BOOL result; - DWORD cbServiceMap = 0; ULONG64 i; PVMMDLL_MAP_SERVICE pServiceMap = NULL; PVMMDLL_MAP_SERVICEENTRY pe; if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "Maps.service(): Not initialized."); } if(!(pyDictResult = PyDict_New())) { return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS; - result = - VMMDLL_Map_GetServicesU(NULL, &cbServiceMap) && - cbServiceMap && - (pServiceMap = LocalAlloc(0, cbServiceMap)) && - VMMDLL_Map_GetServicesU(pServiceMap, &cbServiceMap); + result = VMMDLL_Map_GetServicesU(self->pyVMM->hVMM, &pServiceMap); Py_END_ALLOW_THREADS; if(!result || (pServiceMap->dwVersion != VMMDLL_MAP_SERVICE_VERSION)) { Py_DECREF(pyDictResult); - LocalFree(pServiceMap); + VMMDLL_MemFree(pServiceMap); return PyErr_Format(PyExc_RuntimeError, "Maps.service(): Failed."); } for(i = 0; i < pServiceMap->cMap; i++) { @@ -296,7 +277,7 @@ VmmPycMaps_service(PyObj_Maps *self, PyObject *args) PyDict_SetItemDWORD_DECREF(pyDictResult, pe->dwOrdinal, pyDict); } } - LocalFree(pServiceMap); + VMMDLL_MemFree(pServiceMap); return pyDictResult; } @@ -305,10 +286,11 @@ VmmPycMaps_service(PyObj_Maps *self, PyObject *args) //----------------------------------------------------------------------------- PyObj_Maps* -VmmPycMaps_InitializeInternal() +VmmPycMaps_InitializeInternal(_In_ PyObj_Vmm *pyVMM) { PyObj_Maps *pyObj; if(!(pyObj = PyObject_New(PyObj_Maps, (PyTypeObject*)g_pPyType_Maps))) { return NULL; } + Py_INCREF(pyVMM); pyObj->pyVMM = pyVMM; pyObj->fValid = TRUE; return pyObj; } diff --git a/vmmpyc/vmmpyc_module.c b/vmmpyc/vmmpyc_module.c index 013fc69..8295a4e 100644 --- a/vmmpyc/vmmpyc_module.c +++ b/vmmpyc/vmmpyc_module.c @@ -18,7 +18,7 @@ VmmPycModule_procaddress(PyObj_Module *self, PyObject *args) return PyErr_Format(PyExc_RuntimeError, "Module.procaddress(): Illegal argument."); } Py_BEGIN_ALLOW_THREADS; - va = VMMDLL_ProcessGetProcAddressU(self->dwPID, self->ModuleEntry.uszText, uszProcName); + va = VMMDLL_ProcessGetProcAddressU(self->pyVMM->hVMM, self->dwPID, self->ModuleEntry.uszText, uszProcName); Py_END_ALLOW_THREADS; return va ? PyLong_FromUnsignedLongLong(va) : @@ -31,7 +31,7 @@ VmmPycModule_pdb(PyObj_Module *self, void *closure) { PyObject *pyObjPdb; if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "Module.pdb: Not initialized."); } - pyObjPdb = (PyObject *)VmmPycPdb_InitializeInternal1(self->dwPID, self->ModuleEntry.vaBase); + pyObjPdb = (PyObject *)VmmPycPdb_InitializeInternal1(self->pyVMM, self->dwPID, self->ModuleEntry.vaBase); return pyObjPdb ? pyObjPdb : PyErr_Format(PyExc_RuntimeError, "Module.pdb: Not initialized."); } @@ -40,7 +40,7 @@ static PyObject* VmmPycModule_maps(PyObj_Module *self, void *closure) { if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "Module.maps: Not initialized."); } - return (PyObject*)VmmPycModuleMaps_InitializeInternal(self->dwPID, self->ModuleEntry.uszText); + return (PyObject*)VmmPycModuleMaps_InitializeInternal(self->pyVMM, self->dwPID, self->ModuleEntry.uszText); } // -> PyObj_Process @@ -48,7 +48,7 @@ static PyObject* VmmPycModule_process(PyObj_Module *self, void *closure) { if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "Module.process: Not initialized."); } - return (PyObject*)VmmPycProcess_InitializeInternal(self->dwPID, FALSE); + return (PyObject*)VmmPycProcess_InitializeInternal(self->pyVMM, self->dwPID, FALSE); } // -> STR @@ -72,18 +72,19 @@ VmmPycModule_fullname(PyObj_Module *self, void *closure) //----------------------------------------------------------------------------- PyObj_Module* -VmmPycModule_InitializeInternal(_In_ DWORD dwPID, _In_ PVMMDLL_MAP_MODULEENTRY pe) +VmmPycModule_InitializeInternal(_In_ PyObj_Vmm *pyVMM, _In_ DWORD dwPID, _In_ PVMMDLL_MAP_MODULEENTRY pe) { - PyObj_Module *pyM; - if(!(pyM = PyObject_New(PyObj_Module, (PyTypeObject*)g_pPyType_Module))) { return NULL; } - pyM->fValid = TRUE; - pyM->dwPID = dwPID; - memcpy(&pyM->ModuleEntry, pe, sizeof(VMMDLL_MAP_MODULEENTRY)); - strncpy_s(pyM->uszText, _countof(pyM->uszText), pe->uszText, _TRUNCATE); - strncpy_s(pyM->uszFullName, _countof(pyM->uszFullName), pe->uszFullName, _TRUNCATE); - pyM->ModuleEntry.uszText = pyM->uszText; - pyM->ModuleEntry.uszFullName = pyM->uszFullName; - return pyM; + PyObj_Module *pyObj; + if(!(pyObj = PyObject_New(PyObj_Module, (PyTypeObject*)g_pPyType_Module))) { return NULL; } + Py_INCREF(pyVMM); pyObj->pyVMM = pyVMM; + pyObj->fValid = TRUE; + pyObj->dwPID = dwPID; + memcpy(&pyObj->ModuleEntry, pe, sizeof(VMMDLL_MAP_MODULEENTRY)); + strncpy_s(pyObj->uszText, _countof(pyObj->uszText), pe->uszText, _TRUNCATE); + strncpy_s(pyObj->uszFullName, _countof(pyObj->uszFullName), pe->uszFullName, _TRUNCATE); + pyObj->ModuleEntry.uszText = pyObj->uszText; + pyObj->ModuleEntry.uszFullName = pyObj->uszFullName; + return pyObj; } static PyObject* @@ -108,6 +109,7 @@ static void VmmPycModule_dealloc(PyObj_Module *self) { self->fValid = FALSE; + Py_XDECREF(self->pyVMM); self->pyVMM = NULL; } _Success_(return) diff --git a/vmmpyc/vmmpyc_modulemaps.c b/vmmpyc/vmmpyc_modulemaps.c index 02cfad4..bae283e 100644 --- a/vmmpyc/vmmpyc_modulemaps.c +++ b/vmmpyc/vmmpyc_modulemaps.c @@ -13,7 +13,7 @@ VmmPycModuleMaps_directories(PyObj_ModuleMaps *self, PyObject *args) { PyObject *pyList, *pyDict; BOOL result; - DWORD i, cDirectories; + DWORD i; PIMAGE_DATA_DIRECTORY pe, pDirectories = NULL; LPCSTR DIRECTORIES[16] = { "EXPORT", "IMPORT", "RESOURCE", "EXCEPTION", "SECURITY", "BASERELOC", "DEBUG", "ARCHITECTURE", "GLOBALPTR", "TLS", "LOAD_CONFIG", "BOUND_IMPORT", "IAT", "DELAY_IMPORT", "COM_DESCRIPTOR", "RESERVED" }; if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "ModuleMaps.directories(): Not initialized."); } @@ -21,7 +21,7 @@ VmmPycModuleMaps_directories(PyObj_ModuleMaps *self, PyObject *args) Py_BEGIN_ALLOW_THREADS; result = (pDirectories = LocalAlloc(0, 16 * sizeof(IMAGE_DATA_DIRECTORY))) && - VMMDLL_ProcessGetDirectoriesU(self->dwPID, self->uszModule, pDirectories, 16, &cDirectories); + VMMDLL_ProcessGetDirectoriesU(self->pyVMM->hVMM, self->dwPID, self->uszModule, pDirectories); Py_END_ALLOW_THREADS; if(!result) { Py_DECREF(pyList); @@ -56,10 +56,10 @@ VmmPycModuleMaps_sections(PyObj_ModuleMaps *self, PyObject *args) if(!(pyList = PyList_New(0))) { return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS; result = - VMMDLL_ProcessGetSectionsU(self->dwPID, self->uszModule, NULL, 0, &cSections) && + VMMDLL_ProcessGetSectionsU(self->pyVMM->hVMM, self->dwPID, self->uszModule, NULL, 0, &cSections) && cSections && (pSections = LocalAlloc(0, cSections * sizeof(IMAGE_SECTION_HEADER))) && - VMMDLL_ProcessGetSectionsU(self->dwPID, self->uszModule, pSections, cSections, &cSections); + VMMDLL_ProcessGetSectionsU(self->pyVMM->hVMM, self->dwPID, self->uszModule, pSections, cSections, &cSections); Py_END_ALLOW_THREADS; if(!result) { Py_DECREF(pyList); @@ -95,7 +95,7 @@ VmmPycModuleMaps_eat(PyObj_ModuleMaps *self, PyObject *args) { PyObject *pyDictTop, *pyList, *pyDict; BOOL result; - DWORD i, cbEatMap = 0; + DWORD i; PVMMDLL_MAP_EATENTRY pe; PVMMDLL_MAP_EAT pEatMap = NULL; if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "ModuleMaps.eat(): Not initialized."); } @@ -103,14 +103,12 @@ VmmPycModuleMaps_eat(PyObj_ModuleMaps *self, PyObject *args) if(!(pyList = PyList_New(0))) { return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS; result = - VMMDLL_Map_GetEATU(self->dwPID, self->uszModule, NULL, &cbEatMap) && - (pEatMap = LocalAlloc(0, cbEatMap)) && - VMMDLL_Map_GetEATU(self->dwPID, self->uszModule, pEatMap, &cbEatMap) && + VMMDLL_Map_GetEATU(self->pyVMM->hVMM, self->dwPID, self->uszModule, &pEatMap) && (pEatMap->dwVersion == VMMDLL_MAP_EAT_VERSION); Py_END_ALLOW_THREADS; if(!result) { Py_DECREF(pyList); - LocalFree(pEatMap); + VMMDLL_MemFree(pEatMap); return PyErr_Format(PyExc_RuntimeError, "ModuleMaps.eat(): Failed."); } for(i = 0; i < pEatMap->cMap; i++) { @@ -133,7 +131,7 @@ VmmPycModuleMaps_eat(PyObj_ModuleMaps *self, PyObject *args) PyDict_SetItemString_DECREF(pyDictTop, "c-afn", PyLong_FromUnsignedLong(pEatMap->cNumberOfFunctions)); PyDict_SetItemString_DECREF(pyDictTop, "c-anm", PyLong_FromUnsignedLong(pEatMap->cNumberOfNames)); PyDict_SetItemString_DECREF(pyDictTop, "e", pyList); - LocalFree(pEatMap); + VMMDLL_MemFree(pEatMap); return pyDictTop; } @@ -143,21 +141,19 @@ VmmPycModuleMaps_iat(PyObj_ModuleMaps *self, PyObject *args) { PyObject *pyList, *pyDict; BOOL result; - DWORD i, cbIatMap = 0; + DWORD i; PVMMDLL_MAP_IATENTRY pe; PVMMDLL_MAP_IAT pIatMap = NULL; if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "ModuleMaps.iat(): Not initialized."); } if(!(pyList = PyList_New(0))) { return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS; result = - VMMDLL_Map_GetIATU(self->dwPID, self->uszModule, NULL, &cbIatMap) && - (pIatMap = LocalAlloc(0, cbIatMap)) && - VMMDLL_Map_GetIATU(self->dwPID, self->uszModule, pIatMap, &cbIatMap) && + VMMDLL_Map_GetIATU(self->pyVMM->hVMM, self->dwPID, self->uszModule, &pIatMap) && (pIatMap->dwVersion == VMMDLL_MAP_IAT_VERSION); Py_END_ALLOW_THREADS; if(!result) { Py_DECREF(pyList); - LocalFree(pIatMap); + VMMDLL_MemFree(pIatMap); return PyErr_Format(PyExc_RuntimeError, "ModuleMaps.iat(): Failed."); } for(i = 0; i < pIatMap->cMap; i++) { @@ -177,7 +173,7 @@ VmmPycModuleMaps_iat(PyObj_ModuleMaps *self, PyObject *args) PyList_Append_DECREF(pyList, pyDict); } } - LocalFree(pIatMap); + VMMDLL_MemFree(pIatMap); return pyList; } @@ -186,14 +182,15 @@ VmmPycModuleMaps_iat(PyObj_ModuleMaps *self, PyObject *args) //----------------------------------------------------------------------------- PyObj_ModuleMaps* -VmmPycModuleMaps_InitializeInternal(_In_ DWORD dwPID, _In_ LPSTR uszModule) +VmmPycModuleMaps_InitializeInternal(_In_ PyObj_Vmm *pyVMM, _In_ DWORD dwPID, _In_ LPSTR uszModule) { - PyObj_ModuleMaps *pyObjModuleMaps; - if(!(pyObjModuleMaps = PyObject_New(PyObj_ModuleMaps, (PyTypeObject*)g_pPyType_ModuleMaps))) { return NULL; } - pyObjModuleMaps->fValid = TRUE; - pyObjModuleMaps->dwPID = dwPID; - strncpy_s(pyObjModuleMaps->uszModule, _countof(pyObjModuleMaps->uszModule), uszModule, _TRUNCATE); - return pyObjModuleMaps; + PyObj_ModuleMaps *pyObj; + if(!(pyObj = PyObject_New(PyObj_ModuleMaps, (PyTypeObject*)g_pPyType_ModuleMaps))) { return NULL; } + Py_INCREF(pyVMM); pyObj->pyVMM = pyVMM; + pyObj->fValid = TRUE; + pyObj->dwPID = dwPID; + strncpy_s(pyObj->uszModule, _countof(pyObj->uszModule), uszModule, _TRUNCATE); + return pyObj; } static PyObject* @@ -218,6 +215,7 @@ static void VmmPycModuleMaps_dealloc(PyObj_ModuleMaps *self) { self->fValid = FALSE; + Py_XDECREF(self->pyVMM); self->pyVMM = NULL; } _Success_(return) diff --git a/vmmpyc/vmmpyc_pdb.c b/vmmpyc/vmmpyc_pdb.c index b2cca95..ef88810 100644 --- a/vmmpyc/vmmpyc_pdb.c +++ b/vmmpyc/vmmpyc_pdb.c @@ -21,7 +21,7 @@ VmmPycPdb_symbol_name(PyObj_Pdb *self, PyObject *args) return PyErr_Format(PyExc_RuntimeError, "Pdb.symbol_name(): Illegal argument."); } Py_BEGIN_ALLOW_THREADS; - result = VMMDLL_PdbSymbolName(self->szModule, cbSymbolAddressOrOffset, szSymbolName, &dwSymbolDisplacement); + result = VMMDLL_PdbSymbolName(self->pyVMM->hVMM, self->szModule, cbSymbolAddressOrOffset, szSymbolName, &dwSymbolDisplacement); Py_END_ALLOW_THREADS; if(!result) { return PyErr_Format(PyExc_RuntimeError, "Pdb.symbol_name(): Failed."); @@ -45,7 +45,7 @@ VmmPycPdb_symbol_address(PyObj_Pdb *self, PyObject *args) return PyErr_Format(PyExc_RuntimeError, "Pdb.symbol_address(): Illegal argument."); } Py_BEGIN_ALLOW_THREADS; - result = VMMDLL_PdbSymbolAddress(self->szModule, uszTypeName, &vaSymbol); + result = VMMDLL_PdbSymbolAddress(self->pyVMM->hVMM, self->szModule, uszTypeName, &vaSymbol); Py_END_ALLOW_THREADS; if(!result) { return PyErr_Format(PyExc_RuntimeError, "Pdb.symbol_address(): Failed."); @@ -65,7 +65,7 @@ VmmPycPdb_type_size(PyObj_Pdb *self, PyObject *args) return PyErr_Format(PyExc_RuntimeError, "Pdb.type_size(): Illegal argument."); } Py_BEGIN_ALLOW_THREADS; - result = VMMDLL_PdbTypeSize(self->szModule, uszTypeName, &dwSize); + result = VMMDLL_PdbTypeSize(self->pyVMM->hVMM, self->szModule, uszTypeName, &dwSize); Py_END_ALLOW_THREADS; if(!result) { return PyErr_Format(PyExc_RuntimeError, "Pdb.type_size(): Failed."); @@ -86,7 +86,7 @@ VmmPycPdb_type_child_offset(PyObj_Pdb *self, PyObject *args) return PyErr_Format(PyExc_RuntimeError, "Pdb.type_child_offset(): Illegal argument."); } Py_BEGIN_ALLOW_THREADS; - result = VMMDLL_PdbTypeChildOffset(self->szModule, uszTypeName, uszTypeChildName, &dwChildOffset); + result = VMMDLL_PdbTypeChildOffset(self->pyVMM->hVMM, self->szModule, uszTypeName, uszTypeChildName, &dwChildOffset); Py_END_ALLOW_THREADS; if(!result) { return PyErr_Format(PyExc_RuntimeError, "Pdb.type_child_offset(): Failed."); @@ -99,25 +99,26 @@ VmmPycPdb_type_child_offset(PyObj_Pdb *self, PyObject *args) //----------------------------------------------------------------------------- PyObj_Pdb* -VmmPycPdb_InitializeInternal2(_In_ LPSTR szModule) +VmmPycPdb_InitializeInternal2(_In_ PyObj_Vmm *pyVMM, _In_ LPSTR szModule) { PyObj_Pdb *pyObjPdb; if(!(pyObjPdb = PyObject_New(PyObj_Pdb, (PyTypeObject*)g_pPyType_Pdb))) { return NULL; } strncpy_s(pyObjPdb->szModule, MAX_PATH, szModule, _TRUNCATE); + Py_INCREF(pyVMM); pyObjPdb->pyVMM = pyVMM; pyObjPdb->fValid = TRUE; return pyObjPdb; } PyObj_Pdb* -VmmPycPdb_InitializeInternal1(_In_ DWORD dwPID, _In_ QWORD vaModuleBase) +VmmPycPdb_InitializeInternal1(_In_ PyObj_Vmm *pyVMM, _In_ DWORD dwPID, _In_ QWORD vaModuleBase) { BOOL result; CHAR szModule[MAX_PATH]; Py_BEGIN_ALLOW_THREADS; - result = VMMDLL_PdbLoad(dwPID, vaModuleBase, szModule); + result = VMMDLL_PdbLoad(pyVMM->hVMM, dwPID, vaModuleBase, szModule); Py_END_ALLOW_THREADS; if(!result) { return NULL; } - return VmmPycPdb_InitializeInternal2(szModule); + return VmmPycPdb_InitializeInternal2(pyVMM, szModule); } static PyObject* @@ -138,6 +139,7 @@ static void VmmPycPdb_dealloc(PyObj_Pdb *self) { self->fValid = FALSE; + Py_XDECREF(self->pyVMM); self->pyVMM = NULL; } _Success_(return) diff --git a/vmmpyc/vmmpyc_physicalmemory.c b/vmmpyc/vmmpyc_physicalmemory.c index b2a45c2..0c83fc1 100644 --- a/vmmpyc/vmmpyc_physicalmemory.c +++ b/vmmpyc/vmmpyc_physicalmemory.c @@ -12,7 +12,7 @@ static PyObject* VmmPycPhysicalMemory_read(PyObj_PhysicalMemory *self, PyObject *args) { if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "PhysicalMemory.read(): Not initialized."); } - return VmmPyc_MemRead((DWORD)-1, "PhysicalMemory.read()", args); + return VmmPyc_MemRead(self->pyVMM->hVMM, (DWORD)-1, "PhysicalMemory.read()", args); } // (ULONG64, DWORD, (ULONG64)) -> PBYTE @@ -20,7 +20,7 @@ static PyObject* VmmPycPhysicalMemory_read_scatter(PyObj_PhysicalMemory *self, PyObject *args) { if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "PhysicalMemory.read_scatter(): Not initialized."); } - return VmmPyc_MemReadScatter((DWORD)-1, "PhysicalMemory.read_scatter()", args); + return VmmPyc_MemReadScatter(self->pyVMM->hVMM, (DWORD)-1, "PhysicalMemory.read_scatter()", args); } // (ULONG64, PBYTE) -> None @@ -28,7 +28,7 @@ static PyObject* VmmPycPhysicalMemory_write(PyObj_PhysicalMemory *self, PyObject *args) { if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "PhysicalMemory.write(): Not initialized."); } - return VmmPyc_MemWrite((DWORD)-1, "PhysicalMemory.write()", args); + return VmmPyc_MemWrite(self->pyVMM->hVMM, (DWORD)-1, "PhysicalMemory.write()", args); } // ((DWORD)) -> PyObj_ScatterMemory @@ -40,7 +40,7 @@ VmmPycPhysicalMemory_scatter_initialize(PyObj_PhysicalMemory *self, PyObject *ar if(!PyArg_ParseTuple(args, "|k", &dwReadFlags)) { // borrowed reference return PyErr_Format(PyExc_RuntimeError, "PhysicalMemory.scatter_initialize(): Illegal argument."); } - return (PyObject*)VmmPycScatterMemory_InitializeInternal((DWORD)-1, dwReadFlags); + return (PyObject*)VmmPycScatterMemory_InitializeInternal(self->pyVMM, (DWORD)-1, dwReadFlags); } //----------------------------------------------------------------------------- @@ -48,10 +48,11 @@ VmmPycPhysicalMemory_scatter_initialize(PyObj_PhysicalMemory *self, PyObject *ar //----------------------------------------------------------------------------- PyObj_PhysicalMemory* -VmmPycPhysicalMemory_InitializeInternal() +VmmPycPhysicalMemory_InitializeInternal(_In_ PyObj_Vmm *pyVMM) { PyObj_PhysicalMemory *pyObj; if(!(pyObj = PyObject_New(PyObj_PhysicalMemory, (PyTypeObject *)g_pPyType_PhysicalMemory))) { return NULL; } + Py_INCREF(pyVMM); pyObj->pyVMM = pyVMM; pyObj->fValid = TRUE; return pyObj; } @@ -73,6 +74,7 @@ static void VmmPycPhysicalMemory_dealloc(PyObj_PhysicalMemory *self) { self->fValid = FALSE; + Py_XDECREF(self->pyVMM); self->pyVMM = NULL; } _Success_(return) diff --git a/vmmpyc/vmmpyc_process.c b/vmmpyc/vmmpyc_process.c index b43e958..1aa1fec 100644 --- a/vmmpyc/vmmpyc_process.c +++ b/vmmpyc/vmmpyc_process.c @@ -15,7 +15,7 @@ VmmPycProcess_cmdline(PyObj_Process *self, PyObject *args) LPSTR sz; if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "Process.cmdline(): Not initialized."); } Py_BEGIN_ALLOW_THREADS; - sz = VMMDLL_ProcessGetInformationString(self->dwPID, VMMDLL_PROCESS_INFORMATION_OPT_STRING_CMDLINE); + sz = VMMDLL_ProcessGetInformationString(self->pyVMM->hVMM, self->dwPID, VMMDLL_PROCESS_INFORMATION_OPT_STRING_CMDLINE); Py_END_ALLOW_THREADS; if(!sz) { return PyErr_Format(PyExc_RuntimeError, "Process.cmdline(): Failed."); } pyUnicode = PyUnicode_DecodeUTF8(sz, strlen(sz), NULL); @@ -31,7 +31,7 @@ VmmPycProcess_pathuser(PyObj_Process *self, PyObject *args) LPSTR sz; if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "Process.pathuser(): Not initialized."); } Py_BEGIN_ALLOW_THREADS; - sz = VMMDLL_ProcessGetInformationString(self->dwPID, VMMDLL_PROCESS_INFORMATION_OPT_STRING_PATH_USER_IMAGE); + sz = VMMDLL_ProcessGetInformationString(self->pyVMM->hVMM, self->dwPID, VMMDLL_PROCESS_INFORMATION_OPT_STRING_PATH_USER_IMAGE); Py_END_ALLOW_THREADS; if(!sz) { return PyErr_Format(PyExc_RuntimeError, "Process.pathuser(): Failed."); } pyUnicode = PyUnicode_DecodeUTF8(sz, strlen(sz), NULL); @@ -47,7 +47,7 @@ VmmPycProcess_pathkernel(PyObj_Process *self, PyObject *args) LPSTR sz; if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "Process.pathkernel(): Not initialized."); } Py_BEGIN_ALLOW_THREADS; - sz = VMMDLL_ProcessGetInformationString(self->dwPID, VMMDLL_PROCESS_INFORMATION_OPT_STRING_PATH_KERNEL); + sz = VMMDLL_ProcessGetInformationString(self->pyVMM->hVMM, self->dwPID, VMMDLL_PROCESS_INFORMATION_OPT_STRING_PATH_KERNEL); Py_END_ALLOW_THREADS; if(!sz) { return PyErr_Format(PyExc_RuntimeError, "Process.pathkernel(): Failed."); } pyUnicode = PyUnicode_DecodeUTF8(sz, strlen(sz), NULL); @@ -61,29 +61,24 @@ VmmPycProcess_module_list(PyObj_Process *self, PyObject *args) { PyObject *pyList, *pyObjModule; BOOL result; - DWORD cbModuleMap = 0; ULONG64 i; PVMMDLL_MAP_MODULE pModuleMap = NULL; if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "Process.module_list(): Not initialized."); } if(!(pyList = PyList_New(0))) { return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS; - result = - VMMDLL_Map_GetModuleU(self->dwPID, NULL, &cbModuleMap) && - cbModuleMap && - (pModuleMap = LocalAlloc(0, cbModuleMap)) && - VMMDLL_Map_GetModuleU(self->dwPID, pModuleMap, &cbModuleMap); + result = VMMDLL_Map_GetModuleU(self->pyVMM->hVMM, self->dwPID, &pModuleMap); Py_END_ALLOW_THREADS; if(!result || (pModuleMap->dwVersion != VMMDLL_MAP_MODULE_VERSION)) { Py_DECREF(pyList); - LocalFree(pModuleMap); + VMMDLL_MemFree(pModuleMap); return PyErr_Format(PyExc_RuntimeError, "Process.module_list(): Failed."); } for(i = 0; i < pModuleMap->cMap; i++) { - if((pyObjModule = (PyObject*)VmmPycModule_InitializeInternal(self->dwPID, pModuleMap->pMap + i))) { + if((pyObjModule = (PyObject*)VmmPycModule_InitializeInternal(self->pyVMM, self->dwPID, pModuleMap->pMap + i))) { PyList_Append_DECREF(pyList, pyObjModule); } } - LocalFree(pModuleMap); + VMMDLL_MemFree(pModuleMap); return pyList; } @@ -93,7 +88,6 @@ VmmPycProcess_module(PyObj_Process *self, PyObject *args) { PyObject *pyObjModule; BOOL result; - DWORD cbModule = 0; LPSTR uszModuleName = NULL; PVMMDLL_MAP_MODULEENTRY pe = NULL; if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "Process.module(): Not initialized."); } @@ -101,18 +95,14 @@ VmmPycProcess_module(PyObj_Process *self, PyObject *args) return PyErr_Format(PyExc_RuntimeError, "Process.module(): Illegal argument."); } Py_BEGIN_ALLOW_THREADS; - result = - VMMDLL_Map_GetModuleFromNameU(self->dwPID, uszModuleName, NULL, &cbModule) && - cbModule && - (pe = LocalAlloc(0, cbModule)) && - VMMDLL_Map_GetModuleFromNameU(self->dwPID, uszModuleName, pe, &cbModule); + result = VMMDLL_Map_GetModuleFromNameU(self->pyVMM->hVMM, self->dwPID, uszModuleName, &pe); Py_END_ALLOW_THREADS; if(!result) { - LocalFree(pe); + VMMDLL_MemFree(pe); return PyErr_Format(PyExc_RuntimeError, "Process.module(): Failed."); } - pyObjModule = (PyObject*)VmmPycModule_InitializeInternal(self->dwPID, pe); - LocalFree(pe); + pyObjModule = (PyObject*)VmmPycModule_InitializeInternal(self->pyVMM, self->dwPID, pe); + VMMDLL_MemFree(pe); return pyObjModule ? pyObjModule : PyErr_Format(PyExc_RuntimeError, "Process.module(): Failed."); } @@ -121,7 +111,7 @@ static PyObject* VmmPycProcess_memory(PyObj_Process *self, void *closure) { if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "Process.memory: Not initialized."); } - return (PyObject*)VmmPycVirtualMemory_InitializeInternal(self->dwPID); + return (PyObject*)VmmPycVirtualMemory_InitializeInternal(self->pyVMM, self->dwPID); } // -> *PyObj_ProcessMaps @@ -129,7 +119,7 @@ static PyObject* VmmPycProcess_maps(PyObj_Process *self, void *closure) { if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "Process.maps: Not initialized."); } - return (PyObject *)VmmPycProcessMaps_InitializeInternal(self->dwPID); + return (PyObject *)VmmPycProcessMaps_InitializeInternal(self->pyVMM, self->dwPID); } //----------------------------------------------------------------------------- @@ -148,7 +138,7 @@ VmmPycProcess_EnsureInfo(_Inout_ PyObj_Process *self, _In_ LPSTR szFN) ZeroMemory(&self->Info, sizeof(VMMDLL_PROCESS_INFORMATION)); self->Info.magic = VMMDLL_PROCESS_INFORMATION_MAGIC; self->Info.wVersion = VMMDLL_PROCESS_INFORMATION_VERSION; - result = VMMDLL_ProcessGetInformation(self->dwPID, &self->Info, &cbInfo); + result = VMMDLL_ProcessGetInformation(self->pyVMM->hVMM, self->dwPID, &self->Info, &cbInfo); Py_END_ALLOW_THREADS; if(!result) { return PyErr_Format(PyExc_RuntimeError, "Process.%s: Failed.", szFN); @@ -315,22 +305,24 @@ VmmPycProcess_integrity(PyObj_Process *self, void *closure) //----------------------------------------------------------------------------- PyObj_Process* -VmmPycProcess_InitializeInternal(_In_ DWORD dwPID, _In_ BOOL fVerify) +VmmPycProcess_InitializeInternal(_In_ PyObj_Vmm *pyVMM, _In_ DWORD dwPID, _In_ BOOL fVerify) { - PyObj_Process *pyObjProc; - DWORD cbModuleMap = 0; + PyObj_Process *pyObj; + PVMMDLL_MAP_MODULE pModuleMap = NULL; BOOL fResult; if(fVerify) { Py_BEGIN_ALLOW_THREADS; - fResult = VMMDLL_Map_GetModuleU(dwPID, NULL, &cbModuleMap); + fResult = VMMDLL_Map_GetModuleU(pyVMM->hVMM, dwPID, &pModuleMap); Py_END_ALLOW_THREADS; if(!fResult) { return NULL; } + VMMDLL_MemFree(pModuleMap); } - if(!(pyObjProc = PyObject_New(PyObj_Process, (PyTypeObject*)g_pPyType_Process))) { return NULL; } - pyObjProc->fValid = TRUE; - pyObjProc->dwPID = dwPID; - pyObjProc->fValidInfo = FALSE; - return pyObjProc; + if(!(pyObj = PyObject_New(PyObj_Process, (PyTypeObject*)g_pPyType_Process))) { return NULL; } + Py_INCREF(pyVMM); pyObj->pyVMM = pyVMM; + pyObj->fValid = TRUE; + pyObj->dwPID = dwPID; + pyObj->fValidInfo = FALSE; + return pyObj; } static PyObject* @@ -352,6 +344,7 @@ static void VmmPycProcess_dealloc(PyObj_Process *self) { self->fValid = FALSE; + Py_XDECREF(self->pyVMM); self->pyVMM = NULL; } _Success_(return) diff --git a/vmmpyc/vmmpyc_processmaps.c b/vmmpyc/vmmpyc_processmaps.c index 068e3cc..5ee3efe 100644 --- a/vmmpyc/vmmpyc_processmaps.c +++ b/vmmpyc/vmmpyc_processmaps.c @@ -13,7 +13,7 @@ VmmPycProcessMaps_pte(PyObj_ProcessMaps *self, PyObject *args) { PyObject *pyList, *pyDict; BOOL result, fIdentifyModules; - DWORD i, cbPteMap = 0; + DWORD i; PVMMDLL_MAP_PTEENTRY pe; PVMMDLL_MAP_PTE pPteMap = NULL; CHAR sz[5]; @@ -23,15 +23,11 @@ VmmPycProcessMaps_pte(PyObj_ProcessMaps *self, PyObject *args) } if(!(pyList = PyList_New(0))) { return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS; - result = - VMMDLL_Map_GetPteU(self->dwPID, NULL, &cbPteMap, fIdentifyModules) && - cbPteMap && - (pPteMap = LocalAlloc(0, cbPteMap)) && - VMMDLL_Map_GetPteU(self->dwPID, pPteMap, &cbPteMap, fIdentifyModules); + result = VMMDLL_Map_GetPteU(self->pyVMM->hVMM, self->dwPID, fIdentifyModules, &pPteMap); Py_END_ALLOW_THREADS; if(!result || (pPteMap->dwVersion != VMMDLL_MAP_PTE_VERSION)) { Py_DECREF(pyList); - LocalFree(pPteMap); + VMMDLL_MemFree(pPteMap); return PyErr_Format(PyExc_RuntimeError, "ProcessMaps.pte(): Failed."); } for(i = 0; i < pPteMap->cMap; i++) { @@ -53,7 +49,7 @@ VmmPycProcessMaps_pte(PyObj_ProcessMaps *self, PyObject *args) PyList_Append_DECREF(pyList, pyDict); } } - LocalFree(pPteMap); + VMMDLL_MemFree(pPteMap); return pyList; } @@ -95,7 +91,7 @@ VmmPycProcessMaps_vad(PyObj_ProcessMaps *self, PyObject *args) { PyObject *pyList, *pyDict; BOOL result, fIdentifyModules = FALSE; - DWORD i, cbVadMap = 0; + DWORD i; PVMMDLL_MAP_VADENTRY pe; PVMMDLL_MAP_VAD pVadMap = NULL; CHAR szVadProtection[7] = { 0 }; @@ -105,15 +101,11 @@ VmmPycProcessMaps_vad(PyObj_ProcessMaps *self, PyObject *args) } if(!(pyList = PyList_New(0))) { return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS; - result = - VMMDLL_Map_GetVadU(self->dwPID, NULL, &cbVadMap, fIdentifyModules) && - cbVadMap && - (pVadMap = LocalAlloc(0, cbVadMap)) && - VMMDLL_Map_GetVadU(self->dwPID, pVadMap, &cbVadMap, fIdentifyModules); + result = VMMDLL_Map_GetVadU(self->pyVMM->hVMM, self->dwPID, fIdentifyModules, &pVadMap); Py_END_ALLOW_THREADS; if(!result || (pVadMap->dwVersion != VMMDLL_MAP_VAD_VERSION)) { Py_DECREF(pyList); - LocalFree(pVadMap); + VMMDLL_MemFree(pVadMap); return PyErr_Format(PyExc_RuntimeError, "ProcessMaps.vad(): Failed."); } for(i = 0; i < pVadMap->cMap; i++) { @@ -135,7 +127,7 @@ VmmPycProcessMaps_vad(PyObj_ProcessMaps *self, PyObject *args) PyList_Append_DECREF(pyList, pyDict); } } - LocalFree(pVadMap); + VMMDLL_MemFree(pVadMap); return pyList; } @@ -159,7 +151,6 @@ VmmPycProcessMaps_vad_ex(PyObj_ProcessMaps *self, PyObject *args) PyObject *pyList, *pyDict; BOOL result; DWORD oPage, cPage, i; - DWORD cbVadExMap = 0; PVMMDLL_MAP_VADEXENTRY pe; PVMMDLL_MAP_VADEX pVadExMap = NULL; if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "ProcessMaps.vad_ex(): Not initialized."); } @@ -169,14 +160,11 @@ VmmPycProcessMaps_vad_ex(PyObj_ProcessMaps *self, PyObject *args) if(!(pyList = PyList_New(0))) { return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS; result = - VMMDLL_Map_GetVadEx(self->dwPID, NULL, &cbVadExMap, oPage, cPage) && - cbVadExMap && - (pVadExMap = LocalAlloc(0, cbVadExMap)) && - VMMDLL_Map_GetVadEx(self->dwPID, pVadExMap, &cbVadExMap, oPage, cPage); + VMMDLL_Map_GetVadEx(self->pyVMM->hVMM, self->dwPID, oPage, cPage, &pVadExMap); Py_END_ALLOW_THREADS; if(!result || (pVadExMap->dwVersion != VMMDLL_MAP_VADEX_VERSION)) { Py_DECREF(pyList); - LocalFree(pVadExMap); + VMMDLL_MemFree(pVadExMap); return PyErr_Format(PyExc_RuntimeError, "ProcessMaps.vad_ex(): Failed."); } for(i = 0; i < pVadExMap->cMap; i++) { @@ -194,7 +182,7 @@ VmmPycProcessMaps_vad_ex(PyObj_ProcessMaps *self, PyObject *args) PyList_Append_DECREF(pyList, pyDict); } } - LocalFree(pVadExMap); + VMMDLL_MemFree(pVadExMap); return pyList; } @@ -204,22 +192,17 @@ VmmPycProcessMaps_unloaded_module(PyObj_ProcessMaps *self, PyObject *args) { PyObject *pyList, *pyDict; BOOL result; - DWORD cbUnloadedMap = 0; ULONG64 i; PVMMDLL_MAP_UNLOADEDMODULE pUnloadedMap = NULL; PVMMDLL_MAP_UNLOADEDMODULEENTRY pe; if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "ProcessMaps.unloaded_module(): Not initialized."); } if(!(pyList = PyList_New(0))) { return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS; - result = - VMMDLL_Map_GetUnloadedModuleU(self->dwPID, NULL, &cbUnloadedMap) && - cbUnloadedMap && - (pUnloadedMap = LocalAlloc(0, cbUnloadedMap)) && - VMMDLL_Map_GetUnloadedModuleU(self->dwPID, pUnloadedMap, &cbUnloadedMap); + result = VMMDLL_Map_GetUnloadedModuleU(self->pyVMM->hVMM, self->dwPID, &pUnloadedMap); Py_END_ALLOW_THREADS; if(!result || (pUnloadedMap->dwVersion != VMMDLL_MAP_UNLOADEDMODULE_VERSION)) { Py_DECREF(pyList); - LocalFree(pUnloadedMap); + VMMDLL_MemFree(pUnloadedMap); return PyErr_Format(PyExc_RuntimeError, "ProcessMaps.unloaded_module(): Failed."); } for(i = 0; i < pUnloadedMap->cMap; i++) { @@ -235,7 +218,7 @@ VmmPycProcessMaps_unloaded_module(PyObj_ProcessMaps *self, PyObject *args) PyList_Append_DECREF(pyList, pyDict); } } - LocalFree(pUnloadedMap); + VMMDLL_MemFree(pUnloadedMap); return pyList; } @@ -256,7 +239,7 @@ VmmPycProcessMaps_heap(PyObj_ProcessMaps *self, PyObject *args) PyDict_SetItemString_DECREF(pyDictResult, "heap", pyDictHeap); PyDict_SetItemString_DECREF(pyDictResult, "segment", pyListSegment); Py_BEGIN_ALLOW_THREADS; - result = VMMDLL_Map_GetHeapEx(self->dwPID, &pHeapMap); + result = VMMDLL_Map_GetHeap(self->pyVMM->hVMM, self->dwPID, &pHeapMap); Py_END_ALLOW_THREADS; if(!result || (pHeapMap->dwVersion != VMMDLL_MAP_HEAP_VERSION)) { Py_DECREF(pyDictResult); @@ -302,7 +285,7 @@ VmmPycProcessMaps_heapalloc(PyObj_ProcessMaps *self, PyObject *args) } if(!(pyListResult = PyList_New(0))) { return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS; - result = VMMDLL_Map_GetHeapAllocEx(self->dwPID, vaHeap, &pHeapAllocMap); + result = VMMDLL_Map_GetHeapAlloc(self->pyVMM->hVMM, self->dwPID, vaHeap, &pHeapAllocMap); Py_END_ALLOW_THREADS; if(!result || (pHeapAllocMap->dwVersion != VMMDLL_MAP_HEAPALLOC_VERSION)) { Py_DECREF(pyListResult); @@ -329,22 +312,17 @@ VmmPycProcessMaps_thread(PyObj_ProcessMaps *self, PyObject *args) PyObject *pyList, *pyDict; BOOL result; DWORD i; - DWORD cbThreadMap = 0; PVMMDLL_MAP_THREADENTRY pe; PVMMDLL_MAP_THREAD pThreadMap = NULL; if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "ProcessMaps.thread(): Not initialized."); } CHAR szTimeUTC[MAX_PATH]; if(!(pyList = PyList_New(0))) { return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS; - result = - VMMDLL_Map_GetThread(self->dwPID, NULL, &cbThreadMap) && - cbThreadMap && - (pThreadMap = LocalAlloc(0, cbThreadMap)) && - VMMDLL_Map_GetThread(self->dwPID, pThreadMap, &cbThreadMap); + result = VMMDLL_Map_GetThread(self->pyVMM->hVMM, self->dwPID, &pThreadMap); Py_END_ALLOW_THREADS; if(!result || (pThreadMap->dwVersion != VMMDLL_MAP_THREAD_VERSION)) { Py_DECREF(pyList); - LocalFree(pThreadMap); + VMMDLL_MemFree(pThreadMap); return PyErr_Format(PyExc_RuntimeError, "ProcessMaps.thread(): Failed."); } for(i = 0; i < pThreadMap->cMap; i++) { @@ -377,7 +355,7 @@ VmmPycProcessMaps_thread(PyObj_ProcessMaps *self, PyObject *args) PyList_Append_DECREF(pyList, pyDict); } } - LocalFree(pThreadMap); + VMMDLL_MemFree(pThreadMap); return pyList; } @@ -387,22 +365,17 @@ VmmPycProcessMaps_handle(PyObj_ProcessMaps *self, PyObject *args) { PyObject *pyList, *pyDict; BOOL result; - DWORD cbHandleMap = 0; ULONG64 i; PVMMDLL_MAP_HANDLE pHandleMap = NULL; PVMMDLL_MAP_HANDLEENTRY pe; if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "ProcessMaps.handle(): Not initialized."); } if(!(pyList = PyList_New(0))) { return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS; - result = - VMMDLL_Map_GetHandleU(self->dwPID, NULL, &cbHandleMap) && - cbHandleMap && - (pHandleMap = LocalAlloc(0, cbHandleMap)) && - VMMDLL_Map_GetHandleU(self->dwPID, pHandleMap, &cbHandleMap); + result = VMMDLL_Map_GetHandleU(self->pyVMM->hVMM, self->dwPID, &pHandleMap); Py_END_ALLOW_THREADS; if(!result || (pHandleMap->dwVersion != VMMDLL_MAP_HANDLE_VERSION)) { Py_DECREF(pyList); - LocalFree(pHandleMap); + VMMDLL_MemFree(pHandleMap); return PyErr_Format(PyExc_RuntimeError, "ProcessMaps.handle(): Failed."); } for(i = 0; i < pHandleMap->cMap; i++) { @@ -423,7 +396,7 @@ VmmPycProcessMaps_handle(PyObj_ProcessMaps *self, PyObject *args) PyList_Append_DECREF(pyList, pyDict); } } - LocalFree(pHandleMap); + VMMDLL_MemFree(pHandleMap); return pyList; } @@ -432,10 +405,11 @@ VmmPycProcessMaps_handle(PyObj_ProcessMaps *self, PyObject *args) //----------------------------------------------------------------------------- PyObj_ProcessMaps* -VmmPycProcessMaps_InitializeInternal(_In_ DWORD dwPID) +VmmPycProcessMaps_InitializeInternal(_In_ PyObj_Vmm *pyVMM, _In_ DWORD dwPID) { PyObj_ProcessMaps *pyObj; if(!(pyObj = PyObject_New(PyObj_ProcessMaps, (PyTypeObject*)g_pPyType_ProcessMaps))) { return NULL; } + Py_INCREF(pyVMM); pyObj->pyVMM = pyVMM; pyObj->fValid = TRUE; pyObj->dwPID = dwPID; return pyObj; @@ -460,6 +434,7 @@ static void VmmPycProcessMaps_dealloc(PyObj_ProcessMaps *self) { self->fValid = FALSE; + Py_XDECREF(self->pyVMM); self->pyVMM = NULL; } _Success_(return) diff --git a/vmmpyc/vmmpyc_reghive.c b/vmmpyc/vmmpyc_reghive.c index 7fc3035..7fad3c9 100644 --- a/vmmpyc/vmmpyc_reghive.c +++ b/vmmpyc/vmmpyc_reghive.c @@ -14,7 +14,7 @@ VmmPycRegHive_rootkey(PyObj_RegHive *self, PyObject *args) CHAR uszPathKey[MAX_PATH]; if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "RegHive.rootkey: Not initialized."); } _snprintf_s(uszPathKey, sizeof(uszPathKey), _TRUNCATE, "0x%016llx\\ROOT", self->Info.vaCMHIVE); - return (PyObject*)VmmPycRegKey_InitializeInternal(uszPathKey, FALSE); + return (PyObject*)VmmPycRegKey_InitializeInternal(self->pyVMM, uszPathKey, FALSE); } // -> ObjRegKey @@ -24,7 +24,7 @@ VmmPycRegHive_orphankey(PyObj_RegHive *self, PyObject *args) CHAR uszPathKey[MAX_PATH]; if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "RegHive.orphankey: Not initialized."); } _snprintf_s(uszPathKey, sizeof(uszPathKey), _TRUNCATE, "0x%016llx\\ORPHAN", self->Info.vaCMHIVE); - return (PyObject*)VmmPycRegKey_InitializeInternal(uszPathKey, FALSE); + return (PyObject*)VmmPycRegKey_InitializeInternal(self->pyVMM, uszPathKey, FALSE); } // -> *PyObj_RegMemory @@ -32,7 +32,7 @@ static PyObject* VmmPycRegHive_memory(PyObj_RegHive *self, void *closure) { if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "RegHive.memory: Not initialized."); } - return (PyObject*)VmmPycRegMemory_InitializeInternal(self->Info.vaCMHIVE); + return (PyObject*)VmmPycRegMemory_InitializeInternal(self->pyVMM, self->Info.vaCMHIVE); } //----------------------------------------------------------------------------- @@ -40,13 +40,14 @@ VmmPycRegHive_memory(PyObj_RegHive *self, void *closure) //----------------------------------------------------------------------------- PyObj_RegHive* -VmmPycRegHive_InitializeInternal(_In_ PVMMDLL_REGISTRY_HIVE_INFORMATION pInfo) +VmmPycRegHive_InitializeInternal(_In_ PyObj_Vmm *pyVMM, _In_ PVMMDLL_REGISTRY_HIVE_INFORMATION pInfo) { - PyObj_RegHive *pyHive; - if(!(pyHive = PyObject_New(PyObj_RegHive, (PyTypeObject*)g_pPyType_RegHive))) { return NULL; } - pyHive->fValid = TRUE; - memcpy(&pyHive->Info, pInfo, sizeof(VMMDLL_REGISTRY_HIVE_INFORMATION)); - return pyHive; + PyObj_RegHive *pyObj; + if(!(pyObj = PyObject_New(PyObj_RegHive, (PyTypeObject*)g_pPyType_RegHive))) { return NULL; } + Py_INCREF(pyVMM); pyObj->pyVMM = pyVMM; + pyObj->fValid = TRUE; + memcpy(&pyObj->Info, pInfo, sizeof(VMMDLL_REGISTRY_HIVE_INFORMATION)); + return pyObj; } static PyObject* @@ -71,6 +72,7 @@ static void VmmPycRegHive_dealloc(PyObj_RegHive *self) { self->fValid = FALSE; + Py_XDECREF(self->pyVMM); self->pyVMM = NULL; } _Success_(return) diff --git a/vmmpyc/vmmpyc_regkey.c b/vmmpyc/vmmpyc_regkey.c index 01955e2..78ab536 100644 --- a/vmmpyc/vmmpyc_regkey.c +++ b/vmmpyc/vmmpyc_regkey.c @@ -13,7 +13,7 @@ static BOOL VmmPycRegKey_EnsureLastWrite(PyObj_RegKey *self) BOOL result = FALSE; if(!self->ftLastWrite) { Py_BEGIN_ALLOW_THREADS; - result = VMMDLL_WinReg_EnumKeyExU(self->uszPath, -1, NULL, &cch, (PFILETIME)&self->ftLastWrite); + result = VMMDLL_WinReg_EnumKeyExU(self->pyVMM->hVMM, self->uszPath, -1, NULL, &cch, (PFILETIME)&self->ftLastWrite); Py_END_ALLOW_THREADS; } return result || self->ftLastWrite; @@ -57,10 +57,10 @@ VmmPycRegKey_values(PyObj_RegKey *self, void *closure) while(TRUE) { Py_BEGIN_ALLOW_THREADS; cch = MAX_PATH; - fResult = VMMDLL_WinReg_EnumValueU(self->uszPath, i++, uszValueName, &cch, NULL, NULL, NULL); + fResult = VMMDLL_WinReg_EnumValueU(self->pyVMM->hVMM, self->uszPath, i++, uszValueName, &cch, NULL, NULL, NULL); Py_END_ALLOW_THREADS; if(!fResult) { break; } - PyList_Append_DECREF(pyList, (PyObject*)VmmPycRegValue_InitializeInternal(usz, FALSE)); + PyList_Append_DECREF(pyList, (PyObject*)VmmPycRegValue_InitializeInternal(self->pyVMM, usz, FALSE)); } return pyList; } @@ -84,10 +84,10 @@ VmmPycRegKey_values_dict(PyObj_RegKey *self, void *closure) while(TRUE) { Py_BEGIN_ALLOW_THREADS; cch = MAX_PATH; - fResult = VMMDLL_WinReg_EnumValueU(self->uszPath, i++, uszValueName, &cch, NULL, NULL, NULL); + fResult = VMMDLL_WinReg_EnumValueU(self->pyVMM->hVMM, self->uszPath, i++, uszValueName, &cch, NULL, NULL, NULL); Py_END_ALLOW_THREADS; if(!fResult) { break; } - if((pyObjValue = VmmPycRegValue_InitializeInternal(usz, FALSE))) { + if((pyObjValue = VmmPycRegValue_InitializeInternal(self->pyVMM, usz, FALSE))) { PyDict_SetItemUnicode_DECREF(pyDict, pyObjValue->pyName, (PyObject*)pyObjValue); } } @@ -112,10 +112,10 @@ VmmPycRegKey_subkeys(PyObj_RegKey *self, void *closure) while(TRUE) { Py_BEGIN_ALLOW_THREADS; cch = MAX_PATH; - fResult = VMMDLL_WinReg_EnumKeyExU(self->uszPath, i++, uszKeyName, &cch, NULL); + fResult = VMMDLL_WinReg_EnumKeyExU(self->pyVMM->hVMM, self->uszPath, i++, uszKeyName, &cch, NULL); Py_END_ALLOW_THREADS; if(!fResult) { break; } - PyList_Append_DECREF(pyList, (PyObject*)VmmPycRegKey_InitializeInternal(usz, FALSE)); + PyList_Append_DECREF(pyList, (PyObject*)VmmPycRegKey_InitializeInternal(self->pyVMM, usz, FALSE)); } return pyList; } @@ -139,10 +139,10 @@ VmmPycRegKey_subkeys_dict(PyObj_RegKey *self, void *closure) while(TRUE) { Py_BEGIN_ALLOW_THREADS; cch = MAX_PATH; - fResult = VMMDLL_WinReg_EnumKeyExU(self->uszPath, i++, uszKeyName, &cch, NULL); + fResult = VMMDLL_WinReg_EnumKeyExU(self->pyVMM->hVMM, self->uszPath, i++, uszKeyName, &cch, NULL); Py_END_ALLOW_THREADS; if(!fResult) { break; } - if((pyObjKey = VmmPycRegKey_InitializeInternal(usz, FALSE))) { + if((pyObjKey = VmmPycRegKey_InitializeInternal(self->pyVMM, usz, FALSE))) { PyDict_SetItemUnicode_DECREF(pyDict, pyObjKey->pyName, (PyObject*)pyObjKey); } } @@ -158,7 +158,7 @@ VmmPycRegKey_parent(PyObj_RegKey *self, void *closure) if(!Util_PathSplitLastEx(self->uszPath, uszParentPath, sizeof(uszParentPath))) { return PyErr_Format(PyExc_RuntimeError, "RegKey.parent: No parent key."); } - return (PyObject*)VmmPycRegKey_InitializeInternal(uszParentPath, FALSE); + return (PyObject*)VmmPycRegKey_InitializeInternal(self->pyVMM, uszParentPath, FALSE); } // -> STR @@ -183,12 +183,13 @@ VmmPycRegKey_path(PyObj_RegKey *self, void *closure) //----------------------------------------------------------------------------- PyObj_RegKey* -VmmPycRegKey_InitializeInternal(_In_ LPSTR uszFullPathKey, _In_ BOOL fVerify) +VmmPycRegKey_InitializeInternal(_In_ PyObj_Vmm *pyVMM, _In_ LPSTR uszFullPathKey, _In_ BOOL fVerify) { PyObj_RegKey *pyObj; - if(!(pyObj = PyObject_New(PyObj_RegKey, (PyTypeObject*)g_pPyType_RegKey))) { return NULL; } + if(!(pyObj = PyObject_New(PyObj_RegKey, (PyTypeObject*)g_pPyType_RegKey))) { return NULL; } + Py_INCREF(pyVMM); pyObj->pyVMM = pyVMM; pyObj->fValid = TRUE; - pyObj->ftLastWrite = 0; + pyObj->ftLastWrite = 0; strncpy_s(pyObj->uszPath, _countof(pyObj->uszPath), uszFullPathKey, _TRUNCATE); pyObj->pyName = PyUnicode_FromString(Util_PathSplitLastU(pyObj->uszPath)); if(fVerify && !VmmPycRegKey_EnsureLastWrite(pyObj)) { @@ -217,6 +218,7 @@ VmmPycRegKey_dealloc(PyObj_RegKey *self) { self->fValid = FALSE; Py_XDECREF(self->pyName); + Py_XDECREF(self->pyVMM); self->pyVMM = NULL; } _Success_(return) diff --git a/vmmpyc/vmmpyc_regmemory.c b/vmmpyc/vmmpyc_regmemory.c index ce69d87..cde30de 100644 --- a/vmmpyc/vmmpyc_regmemory.c +++ b/vmmpyc/vmmpyc_regmemory.c @@ -24,7 +24,7 @@ VmmPycRegMemory_read(PyObj_RegMemory *self, PyObject *args) pb = LocalAlloc(0, cb); if(!pb) { return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS; - result = VMMDLL_WinReg_HiveReadEx(self->vaCMHive, ra, pb, cb, &cbRead, flags); + result = VMMDLL_WinReg_HiveReadEx(self->pyVMM->hVMM, self->vaCMHive, ra, pb, cb, &cbRead, flags); Py_END_ALLOW_THREADS; if(!result) { LocalFree(pb); @@ -50,7 +50,7 @@ VmmPycRegMemory_write(PyObj_RegMemory *self, PyObject *args) return Py_BuildValue("s", NULL); // zero-byte write is always successful. } Py_BEGIN_ALLOW_THREADS; - result = VMMDLL_WinReg_HiveWrite(self->vaCMHive, ra, pb, (DWORD)cb); + result = VMMDLL_WinReg_HiveWrite(self->pyVMM->hVMM, self->vaCMHive, ra, pb, (DWORD)cb); Py_END_ALLOW_THREADS; if(!result) { return PyErr_Format(PyExc_RuntimeError, "RegMemory.write(): Failed."); } return Py_BuildValue("s", NULL); // None returned on success. @@ -61,10 +61,11 @@ VmmPycRegMemory_write(PyObj_RegMemory *self, PyObject *args) //----------------------------------------------------------------------------- PyObj_RegMemory* -VmmPycRegMemory_InitializeInternal(_In_ QWORD vaCMHive) +VmmPycRegMemory_InitializeInternal(_In_ PyObj_Vmm *pyVMM, _In_ QWORD vaCMHive) { PyObj_RegMemory *pyObj; if(!(pyObj = PyObject_New(PyObj_RegMemory, (PyTypeObject*)g_pPyType_RegMemory))) { return NULL; } + Py_INCREF(pyVMM); pyObj->pyVMM = pyVMM; pyObj->fValid = TRUE; pyObj->vaCMHive = vaCMHive; return pyObj; @@ -89,6 +90,7 @@ static void VmmPycRegMemory_dealloc(PyObj_RegMemory *self) { self->fValid = FALSE; + Py_XDECREF(self->pyVMM); self->pyVMM = NULL; } _Success_(return) diff --git a/vmmpyc/vmmpyc_regvalue.c b/vmmpyc/vmmpyc_regvalue.c index 10d73bc..8dade80 100644 --- a/vmmpyc/vmmpyc_regvalue.c +++ b/vmmpyc/vmmpyc_regvalue.c @@ -13,7 +13,7 @@ static BOOL VmmPycRegValue_EnsureValue(PyObj_RegValue *self) DWORD cb = sizeof(self->Value.pb); if(self->fValue) { return TRUE; } Py_BEGIN_ALLOW_THREADS; - result = VMMDLL_WinReg_QueryValueExU(self->uszPath, &self->tp, self->Value.pb, &cb); + result = VMMDLL_WinReg_QueryValueExU(self->pyVMM->hVMM, self->uszPath, &self->tp, self->Value.pb, &cb); Py_END_ALLOW_THREADS; if(result) { if(cb < sizeof(self->Value.pb)) { @@ -22,7 +22,7 @@ static BOOL VmmPycRegValue_EnsureValue(PyObj_RegValue *self) self->cb = cb; } else { Py_BEGIN_ALLOW_THREADS; - result = VMMDLL_WinReg_QueryValueExU(self->uszPath, &self->tp, NULL, &cb); + result = VMMDLL_WinReg_QueryValueExU(self->pyVMM->hVMM, self->uszPath, &self->tp, NULL, &cb); Py_END_ALLOW_THREADS; self->fValueData = FALSE; self->fValue = result; @@ -66,7 +66,7 @@ VmmPycRegValue_value(PyObj_RegValue *self, PyObject *args) cb = self->cb; if(!(pb = LocalAlloc(LMEM_ZEROINIT, cb))) { return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS; - result = VMMDLL_WinReg_QueryValueExU(self->uszPath, NULL, pb, &cb); + result = VMMDLL_WinReg_QueryValueExU(self->pyVMM->hVMM, self->uszPath, NULL, pb, &cb); Py_END_ALLOW_THREADS; if(!result) { LocalFree(pb); @@ -151,7 +151,7 @@ VmmPycRegValue_InternalValueString(PyObj_RegValue *self, PyObject *args, _In_ LP memcpy(pb, self->Value.pb, cb); } else { Py_BEGIN_ALLOW_THREADS; - result = VMMDLL_WinReg_QueryValueExU(self->uszPath, NULL, pb, &cb); + result = VMMDLL_WinReg_QueryValueExU(self->pyVMM->hVMM, self->uszPath, NULL, pb, &cb); Py_END_ALLOW_THREADS; if(!result) { LocalFree(pb); @@ -204,7 +204,7 @@ VmmPycRegValue_parent(PyObj_RegValue *self, void *closure) if(!Util_PathSplitLastEx(self->uszPath, uszParentPath, sizeof(uszParentPath))) { return PyErr_Format(PyExc_RuntimeError, "RegValue.parent: No parent key."); } - return (PyObject*)VmmPycRegKey_InitializeInternal(uszParentPath, FALSE); + return (PyObject*)VmmPycRegKey_InitializeInternal(self->pyVMM, uszParentPath, FALSE); } // -> STR @@ -229,11 +229,12 @@ VmmPycRegValue_path(PyObj_RegValue *self, void *closure) //----------------------------------------------------------------------------- PyObj_RegValue* -VmmPycRegValue_InitializeInternal(_In_ LPSTR uszFullPathKeyValue, _In_ BOOL fVerify) +VmmPycRegValue_InitializeInternal(_In_ PyObj_Vmm *pyVMM, _In_ LPSTR uszFullPathKeyValue, _In_ BOOL fVerify) { DWORD cch = 0; PyObj_RegValue *pyObj; if(!(pyObj = PyObject_New(PyObj_RegValue, (PyTypeObject*)g_pPyType_RegValue))) { return NULL; } + Py_INCREF(pyVMM); pyObj->pyVMM = pyVMM; pyObj->fValid = TRUE; pyObj->fValue = FALSE; pyObj->fValueData = FALSE; @@ -265,6 +266,7 @@ VmmPycRegValue_dealloc(PyObj_RegValue *self) { self->fValid = FALSE; Py_XDECREF(self->pyName); + Py_XDECREF(self->pyVMM); self->pyVMM = NULL; } _Success_(return) diff --git a/vmmpyc/vmmpyc_scattermemory.c b/vmmpyc/vmmpyc_scattermemory.c index 26279df..21da9b2 100644 --- a/vmmpyc/vmmpyc_scattermemory.c +++ b/vmmpyc/vmmpyc_scattermemory.c @@ -110,14 +110,15 @@ VmmPycScatterMemory_close(PyObj_ScatterMemory *self, PyObject *args) //----------------------------------------------------------------------------- PyObj_ScatterMemory* -VmmPycScatterMemory_InitializeInternal(_In_ DWORD dwPID, _In_ DWORD dwReadFlags) +VmmPycScatterMemory_InitializeInternal(_In_ PyObj_Vmm *pyVMM, _In_ DWORD dwPID, _In_ DWORD dwReadFlags) { PyObj_ScatterMemory *pyObj; if(!(pyObj = PyObject_New(PyObj_ScatterMemory, (PyTypeObject*)g_pPyType_ScatterMemory))) { return NULL; } + Py_INCREF(pyVMM); pyObj->pyVMM = pyVMM; pyObj->fValid = TRUE; pyObj->dwPID = dwPID; pyObj->dwReadFlags = dwReadFlags; - pyObj->hScatter = VMMDLL_Scatter_Initialize(dwPID, dwReadFlags); + pyObj->hScatter = VMMDLL_Scatter_Initialize(pyVMM->hVMM, dwPID, dwReadFlags); if(!pyObj->hScatter) { Py_DECREF(pyObj); return NULL; @@ -149,6 +150,7 @@ VmmPycScatterMemory_dealloc(PyObj_ScatterMemory *self) { self->fValid = FALSE; VMMDLL_Scatter_CloseHandle(self->hScatter); + Py_XDECREF(self->pyVMM); self->pyVMM = NULL; } _Success_(return) diff --git a/vmmpyc/vmmpyc_vfs.c b/vmmpyc/vmmpyc_vfs.c index 1b28c4b..bbfd831 100644 --- a/vmmpyc/vmmpyc_vfs.c +++ b/vmmpyc/vmmpyc_vfs.c @@ -77,7 +77,7 @@ VmmPycVfs_list(PyObj_Vfs *self, PyObject *args) hFileList.pfnAddDirectory = VmmPycVfs_list_AddDirectory; hFileList.dwVersion = VMMDLL_VFS_FILELIST_VERSION; uszPath = Util_ReplaceSlashAlloc(uszPathPython); - result = uszPath && VMMDLL_VfsListU(uszPath, &hFileList); + result = uszPath && VMMDLL_VfsListU(self->pyVMM->hVMM, uszPath, &hFileList); LocalFree(uszPath); pE = *(PVMMPYCVFS_LIST*)hFileList.h; Py_END_ALLOW_THREADS; @@ -122,7 +122,7 @@ VmmPycVfs_read(PyObj_Vfs *self, PyObject *args) if(!(pb = LocalAlloc(0, cb))) { return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS; uszPath = Util_ReplaceSlashAlloc(uszPathPython); - nt = VMMDLL_VfsReadU(uszPath, pb, cb, &cbRead, cbOffset); + nt = VMMDLL_VfsReadU(self->pyVMM->hVMM, uszPath, pb, cb, &cbRead, cbOffset); LocalFree(uszPath); Py_END_ALLOW_THREADS; if(nt != VMMDLL_STATUS_SUCCESS) { @@ -156,7 +156,7 @@ VmmPycVfs_write(PyObj_Vfs *self, PyObject *args) } Py_BEGIN_ALLOW_THREADS; uszPath = Util_ReplaceSlashAlloc(uszPathPython); - result = uszPath && (VMMDLL_STATUS_SUCCESS == VMMDLL_VfsWriteU(uszPath, pb, (DWORD)cb, &cbWritten, cbOffset)); + result = uszPath && (VMMDLL_STATUS_SUCCESS == VMMDLL_VfsWriteU(self->pyVMM->hVMM, uszPath, pb, (DWORD)cb, &cbWritten, cbOffset)); LocalFree(uszPath); Py_END_ALLOW_THREADS; if(!result) { @@ -170,12 +170,13 @@ VmmPycVfs_write(PyObj_Vfs *self, PyObject *args) //----------------------------------------------------------------------------- PyObj_Vfs* -VmmPycVfs_InitializeInternal() +VmmPycVfs_InitializeInternal(_In_ PyObj_Vmm *pyVMM) { - PyObj_Vfs *pyObjVfs; - if(!(pyObjVfs = PyObject_New(PyObj_Vfs, (PyTypeObject *)g_pPyType_Vfs))) { return NULL; } - pyObjVfs->fValid = TRUE; - return pyObjVfs; + PyObj_Vfs *pyObj; + if(!(pyObj = PyObject_New(PyObj_Vfs, (PyTypeObject *)g_pPyType_Vfs))) { return NULL; } + Py_INCREF(pyVMM); pyObj->pyVMM = pyVMM; + pyObj->fValid = TRUE; + return pyObj; } static PyObject* @@ -195,6 +196,7 @@ static void VmmPycVfs_dealloc(PyObj_Vfs *self) { self->fValid = FALSE; + Py_XDECREF(self->pyVMM); self->pyVMM = NULL; } _Success_(return) diff --git a/vmmpyc/vmmpyc_virtualmemory.c b/vmmpyc/vmmpyc_virtualmemory.c index 9f8c57d..156f649 100644 --- a/vmmpyc/vmmpyc_virtualmemory.c +++ b/vmmpyc/vmmpyc_virtualmemory.c @@ -12,7 +12,7 @@ static PyObject* VmmPycVirtualMemory_read(PyObj_VirtualMemory *self, PyObject *args) { if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "VirtualMemory.read(): Not initialized."); } - return VmmPyc_MemRead(self->dwPID, "VirtualMemory.read()", args); + return VmmPyc_MemRead(self->pyVMM->hVMM, self->dwPID, "VirtualMemory.read()", args); } // (ULONG64, DWORD, (ULONG64)) -> [{...}] @@ -20,7 +20,7 @@ static PyObject* VmmPycVirtualMemory_read_scatter(PyObj_VirtualMemory *self, PyObject *args) { if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "VirtualMemory.read_scatter(): Not initialized."); } - return VmmPyc_MemReadScatter(self->dwPID, "VirtualMemory.read_scatter()", args); + return VmmPyc_MemReadScatter(self->pyVMM->hVMM, self->dwPID, "VirtualMemory.read_scatter()", args); } // (ULONG64, PBYTE) -> None @@ -28,7 +28,7 @@ static PyObject* VmmPycVirtualMemory_write(PyObj_VirtualMemory *self, PyObject *args) { if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "VirtualMemory.write(): Not initialized."); } - return VmmPyc_MemWrite(self->dwPID, "VirtualMemory.write()", args); + return VmmPyc_MemWrite(self->pyVMM->hVMM, self->dwPID, "VirtualMemory.write()", args); } // (ULONG64) -> ULONG64 @@ -42,7 +42,7 @@ VmmPycVirtualMemory_virt2phys(PyObj_VirtualMemory *self, PyObject *args) return PyErr_Format(PyExc_RuntimeError, "VirtualMemory.virt2phys(): Illegal argument."); } Py_BEGIN_ALLOW_THREADS; - result = VMMDLL_MemVirt2Phys(self->dwPID, va, &pa); + result = VMMDLL_MemVirt2Phys(self->pyVMM->hVMM, self->dwPID, va, &pa); Py_END_ALLOW_THREADS; if(!result) { return PyErr_Format(PyExc_RuntimeError, "VirtualMemory.virt2phys(): Failed."); } return PyLong_FromUnsignedLongLong(pa); @@ -57,7 +57,7 @@ VmmPycVirtualMemory_scatter_initialize(PyObj_VirtualMemory *self, PyObject *args if(!PyArg_ParseTuple(args, "|k", &dwReadFlags)) { // borrowed reference return PyErr_Format(PyExc_RuntimeError, "VirtualMemory.scatter_initialize(): Illegal argument."); } - return (PyObject*)VmmPycScatterMemory_InitializeInternal(self->dwPID, dwReadFlags); + return (PyObject*)VmmPycScatterMemory_InitializeInternal(self->pyVMM, self->dwPID, dwReadFlags); } //----------------------------------------------------------------------------- @@ -65,10 +65,11 @@ VmmPycVirtualMemory_scatter_initialize(PyObj_VirtualMemory *self, PyObject *args //----------------------------------------------------------------------------- PyObj_VirtualMemory* -VmmPycVirtualMemory_InitializeInternal(_In_ DWORD dwPID) +VmmPycVirtualMemory_InitializeInternal(_In_ PyObj_Vmm *pyVMM, _In_ DWORD dwPID) { PyObj_VirtualMemory *pyObj; if(!(pyObj = PyObject_New(PyObj_VirtualMemory, (PyTypeObject*)g_pPyType_VirtualMemory))) { return NULL; } + Py_INCREF(pyVMM); pyObj->pyVMM = pyVMM; pyObj->fValid = TRUE; pyObj->dwPID = dwPID; return pyObj; @@ -93,6 +94,7 @@ static void VmmPycVirtualMemory_dealloc(PyObj_VirtualMemory *self) { self->fValid = FALSE; + Py_XDECREF(self->pyVMM); self->pyVMM = NULL; } _Success_(return) diff --git a/vmmpyc/vmmpyc_vmm.c b/vmmpyc/vmmpyc_vmm.c index 3762aa1..3a5f6dd 100644 --- a/vmmpyc/vmmpyc_vmm.c +++ b/vmmpyc/vmmpyc_vmm.c @@ -13,15 +13,15 @@ VmmPycVmm_process_list(PyObj_Vmm *self, PyObject *args) { PyObject *pyList; BOOL result; - ULONG64 cPIDs = 0; + SIZE_T cPIDs = 0; DWORD i, *pPIDs = NULL; if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "Vmm.process_list(): Not initialized."); } if(!(pyList = PyList_New(0))) { return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS; result = - VMMDLL_PidList(NULL, &cPIDs) && + VMMDLL_PidList(self->hVMM, NULL, &cPIDs) && (pPIDs = LocalAlloc(LMEM_ZEROINIT, (SIZE_T)(cPIDs * sizeof(DWORD)))) && - VMMDLL_PidList(pPIDs, &cPIDs); + VMMDLL_PidList(self->hVMM, pPIDs, &cPIDs); Py_END_ALLOW_THREADS; if(!result) { Py_DECREF(pyList); @@ -29,7 +29,7 @@ VmmPycVmm_process_list(PyObj_Vmm *self, PyObject *args) return PyErr_Format(PyExc_RuntimeError, "Vmm.process_list(): Failed."); } for(i = 0; i < cPIDs; i++) { - PyList_Append_DECREF(pyList, (PyObject*)VmmPycProcess_InitializeInternal(pPIDs[i], FALSE)); + PyList_Append_DECREF(pyList, (PyObject*)VmmPycProcess_InitializeInternal(self, pPIDs[i], FALSE)); } LocalFree(pPIDs); return pyList; @@ -46,7 +46,7 @@ VmmPycVmm_process(PyObj_Vmm *self, PyObject *args) if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "Vmm.process(): Not initialized."); } if(PyArg_ParseTuple(args, "k", &dwPID)) { // argument: by-pid: - pyObjProcess = (PyObject*)VmmPycProcess_InitializeInternal(dwPID, TRUE); + pyObjProcess = (PyObject*)VmmPycProcess_InitializeInternal(self, dwPID, TRUE); if(!pyObjProcess) { return PyErr_Format(PyExc_RuntimeError, "Vmm.process(): No such process - %i.", dwPID); } @@ -58,10 +58,10 @@ VmmPycVmm_process(PyObj_Vmm *self, PyObject *args) return PyErr_Format(PyExc_RuntimeError, "Vmm.process(): Illegal argument."); } Py_BEGIN_ALLOW_THREADS; - result = VMMDLL_PidGetFromName(szProcessName, &dwPID); + result = VMMDLL_PidGetFromName(self->hVMM, szProcessName, &dwPID); Py_END_ALLOW_THREADS; if(!result) { return PyErr_Format(PyExc_RuntimeError, "Vmm.process(): Failed."); } - return (PyObject*)VmmPycProcess_InitializeInternal(dwPID, FALSE); + return (PyObject*)VmmPycProcess_InitializeInternal(self, dwPID, FALSE); } // (PBYTE, (DWORD)) -> STR @@ -98,23 +98,6 @@ VmmPycVmm_hex(PyObj_Vmm *self, PyObject *args) return pyString; } -// -> None -static PyObject* -VmmPycVmm_initialize_plugins(PyObj_Vmm *self, PyObject *args) -{ - BOOL result; - if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "Vmm.initialize_plugins(): Not initialized."); } - Py_BEGIN_ALLOW_THREADS; - result = VMMDLL_InitializePlugins(); - Py_END_ALLOW_THREADS; - if(!result) { return PyErr_Format(PyExc_RuntimeError, "Vmm.initialize_plugins(): Initialization of plugin subsystem failed."); } - // success! initialize plugin-dependant members (vfs): - if(!self->pyObjVfs) { - self->pyObjVfs = (PyObject*)VmmPycVfs_InitializeInternal(); - } - return Py_BuildValue("s", NULL); // None returned on success. -} - // (ULONG64) -> ULONG64 static PyObject* VmmPycVmm_get_config(PyObj_Vmm *self, PyObject *args) @@ -126,7 +109,7 @@ VmmPycVmm_get_config(PyObj_Vmm *self, PyObject *args) return PyErr_Format(PyExc_RuntimeError, "Vmm.get_config(): Illegal argument."); } Py_BEGIN_ALLOW_THREADS; - result = VMMDLL_ConfigGet(fOption, &qwValue); + result = VMMDLL_ConfigGet(self->hVMM, fOption, &qwValue); Py_END_ALLOW_THREADS; if(!result) { return PyErr_Format(PyExc_RuntimeError, "Vmm.get_config(): Unable to retrieve value for option."); } return PyLong_FromUnsignedLongLong(qwValue); @@ -143,7 +126,7 @@ VmmPycVmm_set_config(PyObj_Vmm *self, PyObject *args) return PyErr_Format(PyExc_RuntimeError, "Vmm.set_config(): Illegal argument."); } Py_BEGIN_ALLOW_THREADS; - result = VMMDLL_ConfigSet(fOption, qwValue); + result = VMMDLL_ConfigSet(self->hVMM, fOption, qwValue); Py_END_ALLOW_THREADS; if(!result) { return PyErr_Format(PyExc_RuntimeError, "Vmm.set_config(): Unable to set value for option."); } return Py_BuildValue("s", NULL); // None returned on success. @@ -160,12 +143,12 @@ VmmPycVmm_reg_hive_list(PyObj_Vmm *self, PyObject *args) if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "Vmm.reg_hive_list(): Not initialized."); } if(!(pyList = PyList_New(0))) { return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS; - VMMDLL_WinReg_HiveList(NULL, 0, &cHives); + VMMDLL_WinReg_HiveList(self->hVMM, NULL, 0, &cHives); result = - VMMDLL_WinReg_HiveList(NULL, 0, &cHives) && + VMMDLL_WinReg_HiveList(self->hVMM, NULL, 0, &cHives) && cHives && (pHives = LocalAlloc(0, cHives * sizeof(VMMDLL_REGISTRY_HIVE_INFORMATION))) && - VMMDLL_WinReg_HiveList(pHives, cHives, &cHives); + VMMDLL_WinReg_HiveList(self->hVMM, pHives, cHives, &cHives); Py_END_ALLOW_THREADS; if(!result) { Py_DECREF(pyList); @@ -173,7 +156,7 @@ VmmPycVmm_reg_hive_list(PyObj_Vmm *self, PyObject *args) return PyErr_Format(PyExc_RuntimeError, "Vmm.reg_hive_list(): Failed."); } for(i = 0; i < cHives; i++) { - if((pyHive = (PyObject*)VmmPycRegHive_InitializeInternal(pHives + i))) { + if((pyHive = (PyObject*)VmmPycRegHive_InitializeInternal(self, pHives + i))) { PyList_Append_DECREF(pyList, pyHive); } } @@ -191,7 +174,7 @@ VmmPycVmm_reg_key(PyObj_Vmm *self, PyObject *args) if(!PyArg_ParseTuple(args, "s", &uszName) || !uszName) { return PyErr_Format(PyExc_RuntimeError, "Vmm.reg_key(): Illegal argument."); } - pyObj = (PyObject*)VmmPycRegKey_InitializeInternal(uszName, TRUE); + pyObj = (PyObject*)VmmPycRegKey_InitializeInternal(self, uszName, TRUE); if(!pyObj && (pyUnicodeName = PyUnicode_FromString(uszName))) { pyObj = PyErr_Format(PyExc_RuntimeError, "Vmm.reg_key('%U'): Failed.", pyUnicodeName); Py_XDECREF(pyObj); @@ -209,7 +192,7 @@ VmmPycVmm_reg_value(PyObj_Vmm *self, PyObject *args) if(!PyArg_ParseTuple(args, "s", &uszName) || !uszName) { return PyErr_Format(PyExc_RuntimeError, "Vmm.reg_value(): Illegal argument."); } - pyObj = (PyObject *)VmmPycRegValue_InitializeInternal(uszName, TRUE); + pyObj = (PyObject *)VmmPycRegValue_InitializeInternal(self, uszName, TRUE); if(!pyObj && (pyUnicodeName = PyUnicode_FromString(uszName))) { pyObj = PyErr_Format(PyExc_RuntimeError, "Vmm.reg_value('%U'): Failed.", pyUnicodeName); Py_XDECREF(pyUnicodeName); @@ -222,7 +205,7 @@ static PyObject* VmmPycVmm_maps(PyObj_Vmm *self, void *closure) { if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "Vmm.maps: Not initialized."); } - return (PyObject*)VmmPycMaps_InitializeInternal(); + return (PyObject*)VmmPycMaps_InitializeInternal(self); } //----------------------------------------------------------------------------- @@ -241,7 +224,6 @@ VmmPycVmm_init(PyObj_Vmm *self, PyObject *args, PyObject *kwds) DWORD PARAM_OFFSET = 2; static char *kwlist[] = { "args", NULL }; PyObject *pyListSrc = NULL, *pyString, **pyBytesDstArgs, *pyObjProcessTest; - BOOL result; DWORD i, cDstArgs; LPSTR *pszDstArgs; self->fVmmCoreOpenType = FALSE; @@ -275,34 +257,44 @@ VmmPycVmm_init(PyObj_Vmm *self, PyObject *args, PyObject *kwds) pszDstArgs[i] = pyBytesDstArgs[i] ? PyBytes_AsString(pyBytesDstArgs[i]) : ""; } Py_BEGIN_ALLOW_THREADS; - result = VMMDLL_Initialize(cDstArgs, pszDstArgs); - if(result) { - VMMDLL_InitializePlugins(); + self->hVMM = VMMDLL_Initialize(cDstArgs, pszDstArgs); + if(self->hVMM) { + VMMDLL_InitializePlugins(self->hVMM); } Py_END_ALLOW_THREADS; for(i = PARAM_OFFSET; i < cDstArgs; i++) { Py_XDECREF(pyBytesDstArgs[i]); } - if(!result) { + if(!self->hVMM) { PyErr_SetString(PyExc_TypeError, "Vmm.init(): Initialization of vmm failed."); return -1; } self->fVmmCoreOpenType = TRUE; // initialize vfs: if(!self->pyObjVfs) { - self->pyObjVfs = (PyObject *)VmmPycVfs_InitializeInternal(); + self->pyObjVfs = (PyObject *)VmmPycVfs_InitializeInternal(self); } } else { // INITIALIZE EXISTING VMM (CHECK IF EXISTING IS VALID) - pyObjProcessTest = (PyObject*)VmmPycProcess_InitializeInternal(4, TRUE); + self->hVMM = g_PluginVMM; + pyObjProcessTest = (PyObject*)VmmPycProcess_InitializeInternal(self, 4, TRUE); if(!pyObjProcessTest) { PyErr_SetString(PyExc_TypeError, "Vmm.init(): Initialization of existing vmm failed - please initialize with startup options."); return -1; } + if(g_PluginVMM_LoadedOnce) { + PyErr_SetString(PyExc_TypeError, "Vmm.init(): Initialization of existing vmm failed - only allowed once per process."); + return -1; + } + if(!g_PluginVMM) { + PyErr_SetString(PyExc_TypeError, "Vmm.init(): Missing VMM handle."); + return -1; + } + g_PluginVMM_LoadedOnce = TRUE; Py_DECREF(pyObjProcessTest); } // success - initialize type object and return! - self->pyObjKernel = (PyObject*)VmmPycKernel_InitializeInternal(); - self->pyObjMemory = (PyObject*)VmmPycPhysicalMemory_InitializeInternal(); + self->pyObjKernel = (PyObject*)VmmPycKernel_InitializeInternal(self); + self->pyObjMemory = (PyObject*)VmmPycPhysicalMemory_InitializeInternal(self); self->fValid = TRUE; return 0; } @@ -314,7 +306,7 @@ VmmPycVmm_dealloc(PyObj_Vmm *self) self->fValid = FALSE; if(self->fVmmCoreOpenType) { Py_BEGIN_ALLOW_THREADS; - VMMDLL_Close(); + VMMDLL_Close(self->hVMM); Py_END_ALLOW_THREADS; } } @@ -337,7 +329,6 @@ BOOL VmmPycVmm_InitializeType(PyObject *pModule) { static PyMethodDef PyMethods[] = { {"close", (PyCFunction)VmmPycVmm_close, METH_VARARGS, "Close the VMM."}, - {"initialize_plugins", (PyCFunction)VmmPycVmm_initialize_plugins, METH_VARARGS, "Initialize plugin sub-system."}, {"get_config", (PyCFunction)VmmPycVmm_get_config, METH_VARARGS, "Get configuration value."}, {"set_config", (PyCFunction)VmmPycVmm_set_config, METH_VARARGS, "Set configuration value."}, {"process_list", (PyCFunction)VmmPycVmm_process_list, METH_VARARGS, "List processes."}, diff --git a/vmmpyc/vmmpycplugin.c b/vmmpyc/vmmpycplugin.c index 813d003..5adbee5 100644 --- a/vmmpyc/vmmpycplugin.c +++ b/vmmpyc/vmmpycplugin.c @@ -12,6 +12,9 @@ static BOOL g_fPythonStandalone = FALSE; PyObject *g_pPyType_VmmPycPlugin = NULL; +VMM_HANDLE g_PluginVMM = NULL; +BOOL g_PluginVMM_LoadedOnce = FALSE; + //----------------------------------------------------------------------------- // PY2C PYTHON CALLBACK FUNCTIONALITY BELOW: //----------------------------------------------------------------------------- @@ -62,7 +65,7 @@ BOOL PY2C_Util_TranslatePathDelimiterU(_Out_writes_(3 * MAX_PATH) LPSTR dst, LPS return FALSE; } -BOOL PY2C_Callback_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileList) +BOOL PY2C_Callback_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList) { BOOL result = FALSE; PyObject *args = NULL, *pyList = NULL, *pyDict, *pyPid = NULL, *pyPath = NULL, *pyBytes_Name; @@ -72,10 +75,10 @@ BOOL PY2C_Callback_List(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Inout_ PHANDLE pFileLi SIZE_T i, cList; CHAR uszPathBuffer[3 * MAX_PATH]; if(!ctxPY2C->fInitialized) { return FALSE; } - if(!PY2C_Util_TranslatePathDelimiterU(uszPathBuffer, ctx->uszPath)) { return FALSE; } + if(!PY2C_Util_TranslatePathDelimiterU(uszPathBuffer, ctxP->uszPath)) { return FALSE; } gstate = PyGILState_Ensure(); if(!(pyPath = PyUnicode_FromString(uszPathBuffer))) { goto pyfail; } - pyPid = (ctx->dwPID == -1) ? NULL : PyLong_FromUnsignedLong(ctx->dwPID); + pyPid = (ctxP->dwPID == -1) ? NULL : PyLong_FromUnsignedLong(ctxP->dwPID); args = Py_BuildValue("OO", (pyPid ? pyPid : Py_None), pyPath); if(!args) { goto pyfail; } pyList = PyObject_CallObject(ctxPY2C->fnList, args); @@ -110,17 +113,17 @@ pyfail: return result; } -NTSTATUS PY2C_Callback_Read(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset) +NTSTATUS PY2C_Callback_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ ULONG64 cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; PyObject *args = NULL, *pyBytes = NULL, *pyPid = NULL, *pyPath = NULL; PyGILState_STATE gstate; CHAR uszPathBuffer[3 * MAX_PATH]; if(!ctxPY2C->fInitialized) { return VMMDLL_STATUS_FILE_INVALID; } - if(!PY2C_Util_TranslatePathDelimiterU(uszPathBuffer, ctx->uszPath)) { return VMMDLL_STATUS_FILE_INVALID; } + if(!PY2C_Util_TranslatePathDelimiterU(uszPathBuffer, ctxP->uszPath)) { return VMMDLL_STATUS_FILE_INVALID; } gstate = PyGILState_Ensure(); if(!(pyPath = PyUnicode_FromString(uszPathBuffer))) { goto pyfail; } - pyPid = (ctx->dwPID == -1) ? NULL : PyLong_FromUnsignedLong(ctx->dwPID); + pyPid = (ctxP->dwPID == -1) ? NULL : PyLong_FromUnsignedLong(ctxP->dwPID); args = Py_BuildValue("OOkK", pyPid ? pyPid : Py_None, pyPath, @@ -144,7 +147,7 @@ pyfail: return nt; } -NTSTATUS PY2C_Callback_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset) +NTSTATUS PY2C_Callback_Write(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ LPVOID pb, _In_ DWORD cb, _Out_ PDWORD pcbWrite, _In_ ULONG64 cbOffset) { NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID; PyObject *args = NULL, *pyLong = NULL, *pyPid = NULL, *pyPath = NULL; @@ -152,10 +155,10 @@ NTSTATUS PY2C_Callback_Write(_In_ PVMMDLL_PLUGIN_CONTEXT ctx, _In_ LPVOID pb, _I CHAR uszPathBuffer[3 * MAX_PATH]; *pcbWrite = 0; if(!ctxPY2C->fInitialized) { return VMMDLL_STATUS_FILE_INVALID; } - if(!PY2C_Util_TranslatePathDelimiterU(uszPathBuffer, ctx->uszPath)) { return VMMDLL_STATUS_FILE_INVALID; } + if(!PY2C_Util_TranslatePathDelimiterU(uszPathBuffer, ctxP->uszPath)) { return VMMDLL_STATUS_FILE_INVALID; } gstate = PyGILState_Ensure(); if(!(pyPath = PyUnicode_FromString(uszPathBuffer))) { goto pyfail; } - pyPid = (ctx->dwPID == -1) ? NULL : PyLong_FromUnsignedLong(ctx->dwPID); + pyPid = (ctxP->dwPID == -1) ? NULL : PyLong_FromUnsignedLong(ctxP->dwPID); args = Py_BuildValue("OOy#K", pyPid ? pyPid : Py_None, pyPath, @@ -177,7 +180,7 @@ pyfail: return nt; } -VOID PY2C_Callback_Notify(_In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent) +VOID PY2C_Callback_Notify(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ DWORD fEvent, _In_opt_ PVOID pvEvent, _In_opt_ DWORD cbEvent) { PyObject *args, *pyResult = NULL; PyGILState_STATE gstate; @@ -261,11 +264,11 @@ VOID Util_GetPathDll(_Out_writes_(MAX_PATH) PWCHAR wszPath, _In_opt_ HMODULE hMo VOID VmmPyPlugin_UpdateVerbosity() { ULONG64 f; - VMMDLL_ConfigGet(VMMDLL_OPT_CORE_PRINTF_ENABLE, &f); ctxPY2C->fPrintf = f ? TRUE : FALSE; + VMMDLL_ConfigGet(g_PluginVMM, VMMDLL_OPT_CORE_PRINTF_ENABLE, &f); ctxPY2C->fPrintf = f ? TRUE : FALSE; if(ctxPY2C->fPrintf) { - VMMDLL_ConfigGet(VMMDLL_OPT_CORE_VERBOSE, &f); ctxPY2C->fVerbose = f ? TRUE : FALSE; - VMMDLL_ConfigGet(VMMDLL_OPT_CORE_VERBOSE_EXTRA, &f); ctxPY2C->fVerboseExtra = f ? TRUE : FALSE; - VMMDLL_ConfigGet(VMMDLL_OPT_CORE_VERBOSE_EXTRA_TLP, &f); ctxPY2C->fVerboseExtraTlp = f ? TRUE : FALSE; + VMMDLL_ConfigGet(g_PluginVMM, VMMDLL_OPT_CORE_VERBOSE, &f); ctxPY2C->fVerbose = f ? TRUE : FALSE; + VMMDLL_ConfigGet(g_PluginVMM, VMMDLL_OPT_CORE_VERBOSE_EXTRA, &f); ctxPY2C->fVerboseExtra = f ? TRUE : FALSE; + VMMDLL_ConfigGet(g_PluginVMM, VMMDLL_OPT_CORE_VERBOSE_EXTRA_TLP, &f); ctxPY2C->fVerboseExtraTlp = f ? TRUE : FALSE; } else { ctxPY2C->fVerbose = FALSE; ctxPY2C->fVerboseExtra = FALSE; @@ -398,15 +401,20 @@ fail: return FALSE; } -BOOL VmmPyPlugin_PythonInitialize(_In_ HMODULE hDllPython, _In_ HMODULE hDllModule, _In_ BOOL fPythonStandalone) +BOOL VmmPyPlugin_PythonInitialize(_In_ VMM_HANDLE H, _In_ HMODULE hDllPython, _In_ HMODULE hDllModule, _In_ BOOL fPythonStandalone) { + BOOL f; + if(g_PluginVMM) { return FALSE; } + g_PluginVMM = H; g_fPythonStandalone = fPythonStandalone; - return fPythonStandalone ? + f = fPythonStandalone ? VmmPyPlugin_PythonInitializeStandalone() : VmmPyPlugin_PythonInitializeEmbedded(hDllPython, hDllModule); + if(!f) { g_PluginVMM = NULL; } + return f; } -VOID PYTHON_Close(_In_ PVMMDLL_PLUGIN_CONTEXT ctx) +VOID PYTHON_Close(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctx) { __try { PY2C_Callback_Close(); @@ -416,6 +424,7 @@ VOID PYTHON_Close(_In_ PVMMDLL_PLUGIN_CONTEXT ctx) Py_FinalizeEx(); } __except(EXCEPTION_EXECUTE_HANDLER) { ; } } + g_PluginVMM = NULL; } /* @@ -425,13 +434,15 @@ VOID PYTHON_Close(_In_ PVMMDLL_PLUGIN_CONTEXT ctx) * after the DLL is loaded. The DLL then must fill the appropriate information * into the supplied struct and call the pfnPluginManager_Register function to * register itself with the plugin manager. +* -- H * -- pRegInfo */ __declspec(dllexport) -VOID InitializeVmmPlugin(_In_ PVMMDLL_PLUGIN_REGINFO pRegInfo) +VOID InitializeVmmPlugin(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_REGINFO pRegInfo) { + if(g_PluginVMM) { return; } if((pRegInfo->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRegInfo->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; } - if(VmmPyPlugin_PythonInitialize(pRegInfo->python.hReservedDllPython3X, pRegInfo->hDLL, pRegInfo->python.fPythonStandalone)) { + if(VmmPyPlugin_PythonInitialize(H, pRegInfo->python.hReservedDllPython3X, pRegInfo->hDLL, pRegInfo->python.fPythonStandalone)) { strcpy_s(pRegInfo->reg_info.uszPathName, 128, "py"); // module name - 'py'. pRegInfo->reg_info.fRootModule = TRUE; // module shows in root directory. pRegInfo->reg_info.fProcessModule = TRUE; // module shows in process directory. @@ -440,6 +451,6 @@ VOID InitializeVmmPlugin(_In_ PVMMDLL_PLUGIN_REGINFO pRegInfo) pRegInfo->reg_fn.pfnWrite = PY2C_Callback_Write; // Write function supported. pRegInfo->reg_fn.pfnNotify = PY2C_Callback_Notify; // Notify function supported. pRegInfo->reg_fn.pfnClose = PYTHON_Close; // Close module handle. - pRegInfo->pfnPluginManager_Register(pRegInfo); // Register with the plugin maanger. + pRegInfo->pfnPluginManager_Register(H, pRegInfo); // Register with the plugin maanger. } } diff --git a/vmmsharp/vmm_example.cs b/vmmsharp/vmm_example.cs index 8f2c951..00e4bab 100644 --- a/vmmsharp/vmm_example.cs +++ b/vmmsharp/vmm_example.cs @@ -26,7 +26,7 @@ class vmm_example ulong ft = 0; if(pExInfo != IntPtr.Zero) { - vmm.VMMDLL_VFS_FILELIST_EXINFO n = Marshal.PtrToStructure(pExInfo); + Vmm.VMMDLL_VFS_FILELIST_EXINFO n = Marshal.PtrToStructure(pExInfo); ft = n.ftLastWriteTime; } Console.WriteLine("VFS LIST CALLBACK: HANDLE: " + h + " FILE: '" + wszName + "' SIZE '" + cb + "'\tFileWriteTime " + ft); @@ -38,7 +38,7 @@ class vmm_example ulong ft = 0; if (pExInfo != IntPtr.Zero) { - vmm.VMMDLL_VFS_FILELIST_EXINFO n = Marshal.PtrToStructure(pExInfo); + Vmm.VMMDLL_VFS_FILELIST_EXINFO n = Marshal.PtrToStructure(pExInfo); ft = n.ftLastWriteTime; } Console.WriteLine("VFS LIST CALLBACK: HANDLE: " + h + " FILE: '" + wszName + "'\tFileWriteTime " + ft); @@ -50,17 +50,17 @@ class vmm_example bool result; uint nt; // initialize vmm with verbose mode with fpga device - //vmm.Initialize("-printf", "-v", "-device", "fpga"); + //vmm vmm = new vmm("-printf", "-v", "-device", "fpga"); // initialize vmm with verbose mode with dump file - vmm.Initialize("-printf", "-v", "-device", "c:\\dumps\\WIN7-X64-SP1-1.pmem"); + Vmm vmm = new Vmm("-printf", "-v", "-device", "c:\\dumps\\WIN7-X64-SP1-1.pmem"); // get / set vmm config options ulong ulOptionMM, ulOptionVV; - result = vmm.ConfigGet(vmm.OPT_CORE_MEMORYMODEL, out ulOptionMM); - result = vmm.ConfigGet(vmm.OPT_CORE_VERBOSE_EXTRA, out ulOptionVV); - result = vmm.ConfigSet(vmm.OPT_CORE_VERBOSE_EXTRA, 1); - result = vmm.ConfigGet(vmm.OPT_CORE_VERBOSE_EXTRA, out ulOptionVV); + result = vmm.ConfigGet(Vmm.OPT_CORE_MEMORYMODEL, out ulOptionMM); + result = vmm.ConfigGet(Vmm.OPT_CORE_VERBOSE_EXTRA, out ulOptionVV); + result = vmm.ConfigSet(Vmm.OPT_CORE_VERBOSE_EXTRA, 1); + result = vmm.ConfigGet(Vmm.OPT_CORE_VERBOSE_EXTRA, out ulOptionVV); // initialize plugins (required for vfs) vmm.InitializePlugins(); @@ -82,39 +82,39 @@ class vmm_example vmm.PidGetFromName("explorer.exe", out dwExplorerPID); // get kernel path of explorer.exe - string strKernel32KernelPath = vmm.ProcessGetInformationString(dwExplorerPID, vmm.VMMDLL_PROCESS_INFORMATION_OPT_STRING_PATH_KERNEL); + string strKernel32KernelPath = vmm.ProcessGetInformationString(dwExplorerPID, Vmm.VMMDLL_PROCESS_INFORMATION_OPT_STRING_PATH_KERNEL); // retrieve process information of explorer.exe - vmm.PROCESS_INFORMATION ProcInfo = vmm.ProcessGetInformation(dwExplorerPID); + Vmm.PROCESS_INFORMATION ProcInfo = vmm.ProcessGetInformation(dwExplorerPID); // get procaddress of kernel32.dll!GetTickCount64 and module base ulong vaTickCount64 = vmm.ProcessGetProcAddress(dwExplorerPID, "kernel32.dll", "GetTickCount64"); ulong vaKernel32Base = vmm.ProcessGetModuleBase(dwExplorerPID, "kernel32.dll"); // retrieve Directories/Sections/IAT/EAT from kernel32.dll of explorer.exe - vmm.IMAGE_DATA_DIRECTORY[] DIRs = vmm.ProcessGetDirectories(dwExplorerPID, "kernel32.dll"); - vmm.IMAGE_SECTION_HEADER[] SECTIONs = vmm.ProcessGetSections(dwExplorerPID, "kernel32.dll"); + Vmm.IMAGE_DATA_DIRECTORY[] DIRs = vmm.ProcessGetDirectories(dwExplorerPID, "kernel32.dll"); + Vmm.IMAGE_SECTION_HEADER[] SECTIONs = vmm.ProcessGetSections(dwExplorerPID, "kernel32.dll"); // retrieve different "map" structures related to explorer.exe and the system. - vmm.MAP_PTEENTRY[] mPte = vmm.Map_GetPte(dwExplorerPID); - vmm.MAP_VADENTRY[] mVad = vmm.Map_GetVad(dwExplorerPID); - vmm.MAP_VADEXENTRY[] mVadEx = vmm.Map_GetVadEx(dwExplorerPID, 0, 10); - vmm.MAP_MODULEENTRY[] mModule = vmm.Map_GetModule(dwExplorerPID); - vmm.MAP_MODULEENTRY mModuleKernel32 = vmm.Map_GetModuleFromName(dwExplorerPID, "kernel32.dll"); - vmm.MAP_UNLOADEDMODULEENTRY[] mUnloadedModule = vmm.Map_GetUnloadedModule(dwExplorerPID); - vmm.MAP_EATINFO EatInfo; - vmm.MAP_EATENTRY[] mEAT = vmm.Map_GetEAT(dwExplorerPID, "kernel32.dll", out EatInfo); - vmm.MAP_IATENTRY[] mIAT = vmm.Map_GetIAT(dwExplorerPID, "kernel32.dll"); - vmm.MAP_HEAP mHeap = vmm.Map_GetHeap(dwExplorerPID); - vmm.MAP_HEAPALLOCENTRY[] mHeapAlloc = vmm.Map_GetHeapAlloc(dwExplorerPID, 2); - vmm.MAP_THREADENTRY[] mThreads = vmm.Map_GetThread(dwExplorerPID); - vmm.MAP_HANDLEENTRY[] mHandles = vmm.Map_GetHandle(dwExplorerPID); - vmm.MAP_NETENTRY[] mNetworkConnections = vmm.Map_GetNet(); - vmm.MAP_PHYSMEMENTRY[] mPhysMemRanges = vmm.Map_GetPhysMem(); - vmm.MAP_POOLENTRY[] mPoolAllocations = vmm.Map_GetPool(); - vmm.MAP_USERENTRY[] mUsers = vmm.Map_GetUsers(); - vmm.MAP_SERVICEENTRY[] mServices = vmm.Map_GetServices(); - vmm.MAP_PFNENTRY[] mPfn = vmm.Map_GetPfn(1, 2, 1024); + Vmm.MAP_PTEENTRY[] mPte = vmm.Map_GetPte(dwExplorerPID); + Vmm.MAP_VADENTRY[] mVad = vmm.Map_GetVad(dwExplorerPID); + Vmm.MAP_VADEXENTRY[] mVadEx = vmm.Map_GetVadEx(dwExplorerPID, 0, 10); + Vmm.MAP_MODULEENTRY[] mModule = vmm.Map_GetModule(dwExplorerPID); + Vmm.MAP_MODULEENTRY mModuleKernel32 = vmm.Map_GetModuleFromName(dwExplorerPID, "kernel32.dll"); + Vmm.MAP_UNLOADEDMODULEENTRY[] mUnloadedModule = vmm.Map_GetUnloadedModule(dwExplorerPID); + Vmm.MAP_EATINFO EatInfo; + Vmm.MAP_EATENTRY[] mEAT = vmm.Map_GetEAT(dwExplorerPID, "kernel32.dll", out EatInfo); + Vmm.MAP_IATENTRY[] mIAT = vmm.Map_GetIAT(dwExplorerPID, "kernel32.dll"); + Vmm.MAP_HEAP mHeap = vmm.Map_GetHeap(dwExplorerPID); + Vmm.MAP_HEAPALLOCENTRY[] mHeapAlloc = vmm.Map_GetHeapAlloc(dwExplorerPID, 2); + Vmm.MAP_THREADENTRY[] mThreads = vmm.Map_GetThread(dwExplorerPID); + Vmm.MAP_HANDLEENTRY[] mHandles = vmm.Map_GetHandle(dwExplorerPID); + Vmm.MAP_NETENTRY[] mNetworkConnections = vmm.Map_GetNet(); + Vmm.MAP_PHYSMEMENTRY[] mPhysMemRanges = vmm.Map_GetPhysMem(); + Vmm.MAP_POOLENTRY[] mPoolAllocations = vmm.Map_GetPool(); + Vmm.MAP_USERENTRY[] mUsers = vmm.Map_GetUsers(); + Vmm.MAP_SERVICEENTRY[] mServices = vmm.Map_GetServices(); + Vmm.MAP_PFNENTRY[] mPfn = vmm.Map_GetPfn(1, 2, 1024); // read first 128 bytes of kernel32.dll byte[] dataKernel32MZ = vmm.MemRead(dwExplorerPID, mModuleKernel32.vaBase, 128, 0); @@ -125,19 +125,19 @@ class vmm_example // read two independent chunks of memory in one single efficient call. // also use the nocache flag. - IntPtr hS; - if(vmm.Scatter_Initialize(dwExplorerPID, vmm.FLAG_NOCACHE, out hS)) + VmmScatter scatter = vmm.Scatter_Initialize(dwExplorerPID, Vmm.FLAG_NOCACHE); + if(scatter != null) { // prepare multiple ranges to read - vmm.Scatter_Prepare(hS, mModuleKernel32.vaBase, 0x100); - vmm.Scatter_Prepare(hS, mModuleKernel32.vaBase + 0x2000, 0x100); + scatter.Prepare(mModuleKernel32.vaBase, 0x100); + scatter.Prepare(mModuleKernel32.vaBase + 0x2000, 0x100); // execute actual read operation to underlying system - vmm.Scatter_Execute(hS); - byte[] pbKernel32_100_1 = vmm.Scatter_Read(hS, mModuleKernel32.vaBase, 0x80); - byte[] pbKernel32_100_2 = vmm.Scatter_Read(hS, mModuleKernel32.vaBase + 0x2000, 0x100); + scatter.Execute(); + byte[] pbKernel32_100_1 = scatter.Read(mModuleKernel32.vaBase, 0x80); + byte[] pbKernel32_100_2 = scatter.Read(mModuleKernel32.vaBase + 0x2000, 0x100); // clean up scatter handle hS (free native memory) // NB! hS handle should not be used after this! - vmm.Scatter_CloseHandle(ref hS); + scatter.Close(); } // load .pdb of kernel32 from microsoft symbol server and query it @@ -157,12 +157,12 @@ class vmm_example result = vmm.PdbTypeChildOffset("nt", "_IMAGE_NT_HEADERS64", "OptionalHeader", out oOptionalHeaders); // WINDOWS REGISTRY QUERY / READ / WRITE - vmm.REGISTRY_HIVE_INFORMATION[] RegHives = vmm.RegHiveList(); + Vmm.REGISTRY_HIVE_INFORMATION[] RegHives = vmm.RegHiveList(); if(RegHives.Length > 0) { byte[] RegHiveData = vmm.RegHiveRead(RegHives[0].vaCMHIVE, 0x1000, 0x100, 0); } - vmm.REGISTRY_ENUM RegEnum = vmm.RegEnum("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion"); + Vmm.REGISTRY_ENUM RegEnum = vmm.RegEnum("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion"); if(RegEnum.ValueList.Count > 0) { uint RegValueType; diff --git a/vmmsharp/vmmsharp.cs b/vmmsharp/vmmsharp.cs index c0a8973..a51bc44 100644 --- a/vmmsharp/vmmsharp.cs +++ b/vmmsharp/vmmsharp.cs @@ -14,7 +14,7 @@ using System.Collections.Generic; * (c) Ulf Frisk, 2020-2022 * Author: Ulf Frisk, pcileech@frizk.net * - * Version 4.9 + * Version 5.0 * */ @@ -276,51 +276,51 @@ namespace vmmsharp } } - public static class vmm + public class Vmm : IDisposable { //--------------------------------------------------------------------- // CORE FUNCTIONALITY BELOW: //--------------------------------------------------------------------- - public static ulong OPT_CORE_PRINTF_ENABLE = 0x4000000100000000; // RW - public static ulong OPT_CORE_VERBOSE = 0x4000000200000000; // RW - public static ulong OPT_CORE_VERBOSE_EXTRA = 0x4000000300000000; // RW - public static ulong OPT_CORE_VERBOSE_EXTRA_TLP = 0x4000000400000000; // RW - public static ulong OPT_CORE_MAX_NATIVE_ADDRESS = 0x4000000800000000; // R + public static ulong OPT_CORE_PRINTF_ENABLE = 0x4000000100000000; // RW + public static ulong OPT_CORE_VERBOSE = 0x4000000200000000; // RW + public static ulong OPT_CORE_VERBOSE_EXTRA = 0x4000000300000000; // RW + public static ulong OPT_CORE_VERBOSE_EXTRA_TLP = 0x4000000400000000; // RW + public static ulong OPT_CORE_MAX_NATIVE_ADDRESS = 0x4000000800000000; // R - public static ulong OPT_CORE_SYSTEM = 0x2000000100000000; // R - public static ulong OPT_CORE_MEMORYMODEL = 0x2000000200000000; // R + public static ulong OPT_CORE_SYSTEM = 0x2000000100000000; // R + public static ulong OPT_CORE_MEMORYMODEL = 0x2000000200000000; // R - public static ulong OPT_CONFIG_IS_REFRESH_ENABLED = 0x2000000300000000; // R - 1/0 - public static ulong OPT_CONFIG_TICK_PERIOD = 0x2000000400000000; // RW - base tick period in ms - public static ulong OPT_CONFIG_READCACHE_TICKS = 0x2000000500000000; // RW - memory cache validity period (in ticks) - public static ulong OPT_CONFIG_TLBCACHE_TICKS = 0x2000000600000000; // RW - page table (tlb) cache validity period (in ticks) + public static ulong OPT_CONFIG_IS_REFRESH_ENABLED = 0x2000000300000000; // R - 1/0 + public static ulong OPT_CONFIG_TICK_PERIOD = 0x2000000400000000; // RW - base tick period in ms + public static ulong OPT_CONFIG_READCACHE_TICKS = 0x2000000500000000; // RW - memory cache validity period (in ticks) + public static ulong OPT_CONFIG_TLBCACHE_TICKS = 0x2000000600000000; // RW - page table (tlb) cache validity period (in ticks) public static ulong OPT_CONFIG_PROCCACHE_TICKS_PARTIAL = 0x2000000700000000; // RW - process refresh (partial) period (in ticks) - public static ulong OPT_CONFIG_PROCCACHE_TICKS_TOTAL = 0x2000000800000000; // RW - process refresh (full) period (in ticks) - public static ulong OPT_CONFIG_VMM_VERSION_MAJOR = 0x2000000900000000; // R - public static ulong OPT_CONFIG_VMM_VERSION_MINOR = 0x2000000A00000000; // R - public static ulong OPT_CONFIG_VMM_VERSION_REVISION = 0x2000000B00000000; // R + public static ulong OPT_CONFIG_PROCCACHE_TICKS_TOTAL = 0x2000000800000000; // RW - process refresh (full) period (in ticks) + public static ulong OPT_CONFIG_VMM_VERSION_MAJOR = 0x2000000900000000; // R + public static ulong OPT_CONFIG_VMM_VERSION_MINOR = 0x2000000A00000000; // R + public static ulong OPT_CONFIG_VMM_VERSION_REVISION = 0x2000000B00000000; // R public static ulong OPT_CONFIG_STATISTICS_FUNCTIONCALL = 0x2000000C00000000; // RW - enable function call statistics (.status/statistics_fncall file) - public static ulong OPT_CONFIG_IS_PAGING_ENABLED = 0x2000000D00000000; // RW - 1/0 + public static ulong OPT_CONFIG_IS_PAGING_ENABLED = 0x2000000D00000000; // RW - 1/0 - public static ulong OPT_WIN_VERSION_MAJOR = 0x2000010100000000; // R - public static ulong OPT_WIN_VERSION_MINOR = 0x2000010200000000; // R - public static ulong OPT_WIN_VERSION_BUILD = 0x2000010300000000; // R + public static ulong OPT_WIN_VERSION_MAJOR = 0x2000010100000000; // R + public static ulong OPT_WIN_VERSION_MINOR = 0x2000010200000000; // R + public static ulong OPT_WIN_VERSION_BUILD = 0x2000010300000000; // R - public static ulong OPT_FORENSIC_MODE = 0x2000020100000000; // RW - enable/retrieve forensic mode type [0-4]. + public static ulong OPT_FORENSIC_MODE = 0x2000020100000000; // RW - enable/retrieve forensic mode type [0-4]. - public static ulong OPT_REFRESH_ALL = 0x2001ffff00000000; // W - refresh all caches - public static ulong OPT_REFRESH_FREQ_FAST = 0x2001040000000000; // W - refresh fast frequency (including partial process listings) - public static ulong OPT_REFRESH_FREQ_MEDIUM = 0x2001000100000000; // W - refresh medium frequency (including full process listings) - public static ulong OPT_REFRESH_FREQ_SLOW = 0x2001001000000000; // W - refresh slow frequency (including registry) - public static ulong OPT_REFRESH_READ = 0x2001000200000000; // W - refresh physical read cache - public static ulong OPT_REFRESH_TLB = 0x2001000400000000; // W - refresh page table (TLB) cache - public static ulong OPT_REFRESH_PAGING = 0x2001000800000000; // W - refresh virtual memory 'paging' cache - public static ulong OPT_REFRESH_USER = 0x2001002000000000; // W - public static ulong OPT_REFRESH_PHYSMEMMAP = 0x2001004000000000; // W - public static ulong OPT_REFRESH_PFN = 0x2001008000000000; // W - public static ulong OPT_REFRESH_OBJ = 0x2001010000000000; // W - public static ulong OPT_REFRESH_NET = 0x2001020000000000; // W + public static ulong OPT_REFRESH_ALL = 0x2001ffff00000000; // W - refresh all caches + public static ulong OPT_REFRESH_FREQ_FAST = 0x2001040000000000; // W - refresh fast frequency (including partial process listings) + public static ulong OPT_REFRESH_FREQ_MEDIUM = 0x2001000100000000; // W - refresh medium frequency (including full process listings) + public static ulong OPT_REFRESH_FREQ_SLOW = 0x2001001000000000; // W - refresh slow frequency (including registry) + public static ulong OPT_REFRESH_READ = 0x2001000200000000; // W - refresh physical read cache + public static ulong OPT_REFRESH_TLB = 0x2001000400000000; // W - refresh page table (TLB) cache + public static ulong OPT_REFRESH_PAGING = 0x2001000800000000; // W - refresh virtual memory 'paging' cache + public static ulong OPT_REFRESH_USER = 0x2001002000000000; // W + public static ulong OPT_REFRESH_PHYSMEMMAP = 0x2001004000000000; // W + public static ulong OPT_REFRESH_PFN = 0x2001008000000000; // W + public static ulong OPT_REFRESH_OBJ = 0x2001010000000000; // W + public static ulong OPT_REFRESH_NET = 0x2001020000000000; // W public enum MEMORYMODEL_TP @@ -339,17 +339,29 @@ namespace vmmsharp SYSTEM_WINDOWS_X86 = 4 } - public static unsafe bool Initialize(out lc.CONFIG_ERRORINFO ConfigErrorInfo, params string[] args) + private bool disposed = false; + private IntPtr hVMM = IntPtr.Zero; + + // private zero-argument constructor - do not use! + private Vmm() + { + } + + private static unsafe IntPtr Initialize(out lc.CONFIG_ERRORINFO ConfigErrorInfo, params string[] args) { IntPtr pLcErrorInfo; int cbERROR_INFO = System.Runtime.InteropServices.Marshal.SizeOf(typeof(lci.LC_CONFIG_ERRORINFO)); - bool fResult = vmmi.VMMDLL_InitializeEx(args.Length, args, out pLcErrorInfo); + IntPtr hVMM = vmmi.VMMDLL_InitializeEx(args.Length, args, out pLcErrorInfo); long vaLcCreateErrorInfo = pLcErrorInfo.ToInt64(); ConfigErrorInfo = new lc.CONFIG_ERRORINFO(); ConfigErrorInfo.strUserText = ""; + if (hVMM.ToInt64() == 0) + { + throw new Exception("VMM INIT FAILED."); + } if (vaLcCreateErrorInfo == 0) { - return fResult; + return hVMM; } lci.LC_CONFIG_ERRORINFO e = Marshal.PtrToStructure(pLcErrorInfo); if (e.dwVersion == lc.CONFIG_ERRORINFO_VERSION) @@ -362,23 +374,60 @@ namespace vmmsharp } } lci.LcMemFree(pLcErrorInfo); - return fResult; + return hVMM; } - public static bool Initialize(params string[] args) + public Vmm(out lc.CONFIG_ERRORINFO ConfigErrorInfo, params string[] args) + { + this.hVMM = Vmm.Initialize(out ConfigErrorInfo, args); + } + + public Vmm(params string[] args) { lc.CONFIG_ERRORINFO ErrorInfo; - return Initialize(out ErrorInfo, args); + this.hVMM = Vmm.Initialize(out ErrorInfo, args); } - [DllImport("vmm.dll", EntryPoint = "VMMDLL_Close")] - public static extern bool Close(); + ~Vmm() + { + Dispose(disposing: false); + } - [DllImport("vmm.dll", EntryPoint = "VMMDLL_ConfigGet")] - public static extern bool ConfigGet(ulong fOption, out ulong pqwValue); + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } - [DllImport("vmm.dll", EntryPoint = "VMMDLL_ConfigSet")] - public static extern bool ConfigSet(ulong fOption, ulong qwValue); + protected virtual void Dispose(bool disposing) + { + if (!this.disposed) + { + vmmi.VMMDLL_Close(hVMM); + hVMM = IntPtr.Zero; + disposed = true; + } + } + + public void Close() + { + Dispose(disposing: true); + } + + public static void CloseAll() + { + vmmi.VMMDLL_CloseAll(); + } + + public bool ConfigGet(ulong fOption, out ulong pqwValue) + { + return vmmi.VMMDLL_ConfigGet(hVMM, fOption, out pqwValue); + } + + public bool ConfigSet(ulong fOption, ulong qwValue) + { + return vmmi.VMMDLL_ConfigSet(hVMM, fOption, qwValue); + } //--------------------------------------------------------------------- // VFS (VIRTUAL FILE SYSTEM) FUNCTIONALITY BELOW: @@ -400,7 +449,7 @@ namespace vmmsharp [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate bool VfsCallBack_AddDirectory(ulong h, [MarshalAs(UnmanagedType.LPUTF8Str)] string wszName, IntPtr pExInfo); - public static bool VfsList(string wszPath, ulong h, VfsCallBack_AddFile CallbackFile, VfsCallBack_AddDirectory CallbackDirectory) + public bool VfsList(string wszPath, ulong h, VfsCallBack_AddFile CallbackFile, VfsCallBack_AddDirectory CallbackDirectory) { vmmi.VMMDLL_VFS_FILELIST FileList; FileList.dwVersion = vmmi.VMMDLL_VFS_FILELIST_VERSION; @@ -408,16 +457,16 @@ namespace vmmsharp FileList._Reserved = 0; FileList.pfnAddFile = Marshal.GetFunctionPointerForDelegate(CallbackFile); FileList.pfnAddDirectory = Marshal.GetFunctionPointerForDelegate(CallbackDirectory); - return vmmi.VMMDLL_VfsList(wszPath, ref FileList); + return vmmi.VMMDLL_VfsList(hVMM, wszPath, ref FileList); } - public static unsafe uint VfsRead(string wszFileName, uint cb, ulong cbOffset, out byte[] pbData) + public unsafe uint VfsRead(string wszFileName, uint cb, ulong cbOffset, out byte[] pbData) { uint nt, cbRead = 0; byte[] data = new byte[cb]; fixed (byte* pb = data) { - nt = vmmi.VMMDLL_VfsRead(wszFileName, pb, cb, out cbRead, cbOffset); + nt = vmmi.VMMDLL_VfsRead(hVMM, wszFileName, pb, cb, out cbRead, cbOffset); pbData = new byte[cbRead]; if (cbRead > 0) { @@ -427,37 +476,43 @@ namespace vmmsharp } } - public static unsafe uint VfsWrite(string wszFileName, byte[] pbData, ulong cbOffset) + public unsafe uint VfsWrite(string wszFileName, byte[] pbData, ulong cbOffset) { uint cbRead = 0; fixed (byte* pb = pbData) { - return vmmi.VMMDLL_VfsWrite(wszFileName, pb, (uint)pbData.Length, out cbRead, cbOffset); + return vmmi.VMMDLL_VfsWrite(hVMM, wszFileName, pb, (uint)pbData.Length, out cbRead, cbOffset); } } + + //--------------------------------------------------------------------- // PLUGIN FUNCTIONALITY BELOW: //--------------------------------------------------------------------- - [DllImport("vmm.dll", EntryPoint = "VMMDLL_InitializePlugins")] - public static extern bool InitializePlugins(); + public bool InitializePlugins() + { + return vmmi.VMMDLL_InitializePlugins(hVMM); + } + + //--------------------------------------------------------------------- // MEMORY READ/WRITE FUNCTIONALITY BELOW: //--------------------------------------------------------------------- - public static uint PID_PROCESS_WITH_KERNELMEMORY = 0x80000000; // Combine with dwPID to enable process kernel memory (NB! use with extreme care). + public static uint PID_PROCESS_WITH_KERNELMEMORY = 0x80000000; // Combine with dwPID to enable process kernel memory (NB! use with extreme care). - public static uint FLAG_NOCACHE = 0x0001; // do not use the data cache (force reading from memory acquisition device) - public static uint FLAG_ZEROPAD_ON_FAIL = 0x0002; // zero pad failed physical memory reads and report success if read within range of physical memory. - public static uint FLAG_FORCECACHE_READ = 0x0008; // force use of cache - fail non-cached pages - only valid for reads, invalid with VMM_FLAG_NOCACHE/VMM_FLAG_ZEROPAD_ON_FAIL. - public static uint FLAG_NOPAGING = 0x0010; // do not try to retrieve memory from paged out memory from pagefile/compressed (even if possible) - public static uint FLAG_NOPAGING_IO = 0x0020; // do not try to retrieve memory from paged out memory if read would incur additional I/O (even if possible). - public static uint FLAG_NOCACHEPUT = 0x0100; // do not write back to the data cache upon successful read from memory acquisition device. - public static uint FLAG_CACHE_RECENT_ONLY = 0x0200; // only fetch from the most recent active cache region when reading. + public static uint FLAG_NOCACHE = 0x0001; // do not use the data cache (force reading from memory acquisition device) + public static uint FLAG_ZEROPAD_ON_FAIL = 0x0002; // zero pad failed physical memory reads and report success if read within range of physical memory. + public static uint FLAG_FORCECACHE_READ = 0x0008; // force use of cache - fail non-cached pages - only valid for reads, invalid with VMM_FLAG_NOCACHE/VMM_FLAG_ZEROPAD_ON_FAIL. + public static uint FLAG_NOPAGING = 0x0010; // do not try to retrieve memory from paged out memory from pagefile/compressed (even if possible) + public static uint FLAG_NOPAGING_IO = 0x0020; // do not try to retrieve memory from paged out memory if read would incur additional I/O (even if possible). + public static uint FLAG_NOCACHEPUT = 0x0100; // do not write back to the data cache upon successful read from memory acquisition device. + public static uint FLAG_CACHE_RECENT_ONLY = 0x0200; // only fetch from the most recent active cache region when reading. - public static unsafe MEM_SCATTER[] MemReadScatter(uint pid, uint flags, params ulong[] qwA) + public unsafe MEM_SCATTER[] MemReadScatter(uint pid, uint flags, params ulong[] qwA) { int i; long vappMEMs, vapMEM; @@ -474,7 +529,7 @@ namespace vmmsharp Marshal.WriteInt64(pMEM_qwA, (long)(qwA[i] & ~(ulong)0xfff)); } MEM_SCATTER[] MEMs = new MEM_SCATTER[qwA.Length]; - vmmi.VMMDLL_MemReadScatter(pid, pppMEMs, (uint)MEMs.Length, flags); + vmmi.VMMDLL_MemReadScatter(hVMM, pid, pppMEMs, (uint)MEMs.Length, flags); for (i = 0; i < MEMs.Length; i++) { pMEM = Marshal.ReadIntPtr(new IntPtr(vappMEMs + i * 8)); @@ -488,13 +543,20 @@ namespace vmmsharp return MEMs; } - public static unsafe byte[] MemRead(uint pid, ulong qwA, uint cb, uint flags = 0) + public VmmScatter Scatter_Initialize(uint pid, uint flags) + { + IntPtr hS = vmmi.VMMDLL_Scatter_Initialize(hVMM, pid, flags); + if (hS.ToInt64() == 0) { return null; } + return new VmmScatter(hS); + } + + public unsafe byte[] MemRead(uint pid, ulong qwA, uint cb, uint flags = 0) { uint cbRead; byte[] data = new byte[cb]; fixed (byte* pb = data) { - if(!vmmi.VMMDLL_MemReadEx(pid, qwA, pb, cb, out cbRead, flags)) + if (!vmmi.VMMDLL_MemReadEx(hVMM, pid, qwA, pb, cb, out cbRead, flags)) { return null; } @@ -506,70 +568,27 @@ namespace vmmsharp return data; } - public static unsafe bool MemPrefetchPages(uint pid, ulong[] qwA) + public unsafe bool MemPrefetchPages(uint pid, ulong[] qwA) { byte[] data = new byte[qwA.Length * sizeof(ulong)]; System.Buffer.BlockCopy(qwA, 0, data, 0, data.Length); fixed (byte* pb = data) { - return vmmi.VMMDLL_MemPrefetchPages(pid, pb, (uint)qwA.Length); + return vmmi.VMMDLL_MemPrefetchPages(hVMM, pid, pb, (uint)qwA.Length); } } - public static unsafe bool MemWrite(uint pid, ulong qwA, byte[] data) + public unsafe bool MemWrite(uint pid, ulong qwA, byte[] data) { fixed (byte* pb = data) { - return vmmi.VMMDLL_MemWrite(pid, qwA, pb, (uint)data.Length); + return vmmi.VMMDLL_MemWrite(hVMM, pid, qwA, pb, (uint)data.Length); } } - [DllImport("vmm.dll", EntryPoint = "VMMDLL_MemVirt2Phys")] - public static extern bool MemVirt2Phys(uint dwPID, ulong qwVA, out ulong pqwPA); - - - - //--------------------------------------------------------------------- - // MEMORY NEW SCATTER READ/WRITE FUNCTIONALITY BELOW: - //--------------------------------------------------------------------- - - public static bool Scatter_Initialize(uint pid, uint flags, out IntPtr hS) + public bool MemVirt2Phys(uint dwPID, ulong qwVA, out ulong pqwPA) { - hS = vmmi.VMMDLL_Scatter_Initialize(pid, flags); - return hS != IntPtr.Zero; - } - - [DllImport("vmm.dll", EntryPoint = "VMMDLL_Scatter_Prepare")] - public static extern bool Scatter_Prepare(IntPtr hS, ulong qwA, uint cb); - - [DllImport("vmm.dll", EntryPoint = "VMMDLL_Scatter_ExecuteRead")] - public static extern bool Scatter_Execute(IntPtr hS); - - public static unsafe byte[] Scatter_Read(IntPtr hS, ulong qwA, uint cb) - { - uint cbRead; - byte[] data = new byte[cb]; - fixed (byte* pb = data) - { - if (!vmmi.VMMDLL_Scatter_Read(hS, qwA, cb, pb, out cbRead)) - { - return null; - } - } - if (cbRead != cb) - { - Array.Resize(ref data, (int)cbRead); - } - return data; - } - - [DllImport("vmm.dll", EntryPoint = "VMMDLL_Scatter_Clear")] - public static extern bool Scatter_Clear(IntPtr hS, uint dwPID, uint flags); - - public static void Scatter_CloseHandle(ref IntPtr hS) - { - vmmi.VMMDLL_Scatter_CloseHandle(hS); - hS = IntPtr.Zero; + return vmmi.VMMDLL_MemVirt2Phys(hVMM, dwPID, qwVA, out pqwPA); } @@ -585,7 +604,7 @@ namespace vmmsharp public byte[] pbSearchSkipMask; } - public static unsafe ulong[] MemSearchM(uint pid, VMMDLL_MEM_SEARCHENTRY[] search, ulong vaMin = 0, ulong vaMax = 0xffffffffffffffff, uint cMaxResult = 0x10000, uint ReadFlags = 0) + public unsafe ulong[] MemSearchM(uint pid, VMMDLL_MEM_SEARCHENTRY[] search, ulong vaMin = 0, ulong vaMax = 0xffffffffffffffff, uint cMaxResult = 0x10000, uint ReadFlags = 0) { // checks: if (search == null || search.Length == 0 || search.Length > 16) { return new ulong[0]; } @@ -599,7 +618,7 @@ namespace vmmsharp es[i].cb = (uint)search[i].pbSearch.Length; es[i].pb = new byte[32]; search[i].pbSearch.CopyTo(es[i].pb, 0); - if(search[i].pbSearchSkipMask != null && search[i].pbSearchSkipMask.Length > 0) + if (search[i].pbSearchSkipMask != null && search[i].pbSearchSkipMask.Length > 0) { es[i].pbSkipMask = new byte[32]; search[i].pbSearchSkipMask.CopyTo(es[i].pbSkipMask, 0); @@ -617,7 +636,7 @@ namespace vmmsharp // perform native search: uint pcva; IntPtr ppva; - if (!vmmi.VMMDLL_MemSearch(pid, ref ctx, out ppva, out pcva)) { return new ulong[0]; } + if (!vmmi.VMMDLL_MemSearch(hVMM, pid, ref ctx, out ppva, out pcva)) { return new ulong[0]; } ulong[] result = new ulong[pcva]; for (int i = 0; i < pcva; i++) { @@ -627,7 +646,7 @@ namespace vmmsharp return result; } - public static unsafe ulong[] MemSearch1(uint pid, byte[] pbSearch, ulong vaMin = 0, ulong vaMax = 0xffffffffffffffff, uint cMaxResult = 0x10000, uint ReadFlags = 0, byte[] pbSearchSkipMask = null, uint cbAlign = 1) + public unsafe ulong[] MemSearch1(uint pid, byte[] pbSearch, ulong vaMin = 0, ulong vaMax = 0xffffffffffffffff, uint cMaxResult = 0x10000, uint ReadFlags = 0, byte[] pbSearchSkipMask = null, uint cbAlign = 1) { VMMDLL_MEM_SEARCHENTRY[] es = new VMMDLL_MEM_SEARCHENTRY[1]; es[0].cbAlign = cbAlign; @@ -638,11 +657,11 @@ namespace vmmsharp - //--------------------------------------------------------------------- - // PROCESS FUNCTIONALITY BELOW: - //--------------------------------------------------------------------- + //--------------------------------------------------------------------- + // PROCESS FUNCTIONALITY BELOW: + //--------------------------------------------------------------------- - public struct PROCESS_INFORMATION + public struct PROCESS_INFORMATION { public bool fValid; public uint tpMemoryModel; @@ -665,18 +684,20 @@ namespace vmmsharp public uint IntegrityLevel; } - [DllImport("vmm.dll", EntryPoint = "VMMDLL_PidGetFromName")] - public static extern bool PidGetFromName([MarshalAs(UnmanagedType.LPStr)] string szProcName, out uint pdwPID); + public bool PidGetFromName(string szProcName, out uint pdwPID) + { + return vmmi.VMMDLL_PidGetFromName(hVMM, szProcName, out pdwPID); + } - public static unsafe uint[] PidList() + public unsafe uint[] PidList() { bool result; ulong c = 0; - result = vmmi.VMMDLL_PidList(null, ref c); + result = vmmi.VMMDLL_PidList(hVMM, null, ref c); if (!result || (c == 0)) { return new uint[0]; } fixed (byte* pb = new byte[c * 4]) { - result = vmmi.VMMDLL_PidList(pb, ref c); + result = vmmi.VMMDLL_PidList(hVMM, pb, ref c); if (!result || (c == 0)) { return new uint[0]; } uint[] m = new uint[c]; for (ulong i = 0; i < c; i++) @@ -687,7 +708,7 @@ namespace vmmsharp } } - public static unsafe PROCESS_INFORMATION ProcessGetInformation(uint pid) + public unsafe PROCESS_INFORMATION ProcessGetInformation(uint pid) { bool result; ulong cbENTRY = (ulong)System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_PROCESS_INFORMATION)); @@ -695,7 +716,7 @@ namespace vmmsharp { Marshal.WriteInt64(new IntPtr(pb + 0), (long)vmmi.VMMDLL_PROCESS_INFORMATION_MAGIC); Marshal.WriteInt16(new IntPtr(pb + 8), (short)vmmi.VMMDLL_PROCESS_INFORMATION_VERSION); - result = vmmi.VMMDLL_ProcessGetInformation(pid, pb, ref cbENTRY); + result = vmmi.VMMDLL_ProcessGetInformation(hVMM, pid, pb, ref cbENTRY); if (!result) { return new PROCESS_INFORMATION(); } vmmi.VMMDLL_PROCESS_INFORMATION n = Marshal.PtrToStructure((System.IntPtr)pb); if (n.wVersion != vmmi.VMMDLL_PROCESS_INFORMATION_VERSION) { return new PROCESS_INFORMATION(); } @@ -727,9 +748,9 @@ namespace vmmsharp public static uint VMMDLL_PROCESS_INFORMATION_OPT_STRING_PATH_USER_IMAGE = 2; public static uint VMMDLL_PROCESS_INFORMATION_OPT_STRING_CMDLINE = 3; - public static unsafe string ProcessGetInformationString(uint pid, uint fOptionString) + public unsafe string ProcessGetInformationString(uint pid, uint fOptionString) { - byte* pb = vmmi.VMMDLL_ProcessGetInformationString(pid, fOptionString); + byte* pb = vmmi.VMMDLL_ProcessGetInformationString(hVMM, pid, fOptionString); if (pb == null) { return ""; } string s = Marshal.PtrToStringAnsi((System.IntPtr)pb); vmmi.VMMDLL_MemFree(pb); @@ -757,7 +778,7 @@ namespace vmmsharp public uint Size; } - public static unsafe IMAGE_DATA_DIRECTORY[] ProcessGetDirectories(uint pid, string wszModule) + public unsafe IMAGE_DATA_DIRECTORY[] ProcessGetDirectories(uint pid, string wszModule) { string[] PE_DATA_DIRECTORIES = new string[16] { "EXPORT", "IMPORT", "RESOURCE", "EXCEPTION", "SECURITY", "BASERELOC", "DEBUG", "ARCHITECTURE", "GLOBALPTR", "TLS", "LOAD_CONFIG", "BOUND_IMPORT", "IAT", "DELAY_IMPORT", "COM_DESCRIPTOR", "RESERVED" }; bool result; @@ -765,8 +786,8 @@ namespace vmmsharp uint cbENTRY = (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_IMAGE_DATA_DIRECTORY)); fixed (byte* pb = new byte[16 * cbENTRY]) { - result = vmmi.VMMDLL_ProcessGetDirectories(pid, wszModule, pb, 16, out cData); - if (!result || (cData != 16)) { return new IMAGE_DATA_DIRECTORY[0]; } + result = vmmi.VMMDLL_ProcessGetDirectories(hVMM, pid, wszModule, pb); + if (!result) { return new IMAGE_DATA_DIRECTORY[0]; } IMAGE_DATA_DIRECTORY[] m = new IMAGE_DATA_DIRECTORY[16]; for (int i = 0; i < 16; i++) { @@ -781,16 +802,16 @@ namespace vmmsharp } } - public static unsafe IMAGE_SECTION_HEADER[] ProcessGetSections(uint pid, string wszModule) + public unsafe IMAGE_SECTION_HEADER[] ProcessGetSections(uint pid, string wszModule) { bool result; uint cData; uint cbENTRY = (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_IMAGE_SECTION_HEADER)); - result = vmmi.VMMDLL_ProcessGetSections(pid, wszModule, null, 0, out cData); - if(!result || (cData == 0)) { return new IMAGE_SECTION_HEADER[0]; } + result = vmmi.VMMDLL_ProcessGetSections(hVMM, pid, wszModule, null, 0, out cData); + if (!result || (cData == 0)) { return new IMAGE_SECTION_HEADER[0]; } fixed (byte* pb = new byte[cData * cbENTRY]) { - result = vmmi.VMMDLL_ProcessGetSections(pid, wszModule, pb, cData, out cData); + result = vmmi.VMMDLL_ProcessGetSections(hVMM, pid, wszModule, pb, cData, out cData); if (!result || (cData == 0)) { return new IMAGE_SECTION_HEADER[0]; } IMAGE_SECTION_HEADER[] m = new IMAGE_SECTION_HEADER[cData]; for (int i = 0; i < cData; i++) @@ -813,11 +834,15 @@ namespace vmmsharp } } - [DllImport("vmm.dll", EntryPoint = "VMMDLL_ProcessGetProcAddressW")] - public static extern ulong ProcessGetProcAddress(uint pid, [MarshalAs(UnmanagedType.LPWStr)] string wszModuleName, [MarshalAs(UnmanagedType.LPStr)] string szFunctionName); + public ulong ProcessGetProcAddress(uint pid, string wszModuleName, string szFunctionName) + { + return vmmi.VMMDLL_ProcessGetProcAddress(hVMM, pid, wszModuleName, szFunctionName); + } - [DllImport("vmm.dll", EntryPoint = "VMMDLL_ProcessGetModuleBaseW")] - public static extern ulong ProcessGetModuleBase(uint pid, [MarshalAs(UnmanagedType.LPWStr)] string wszModuleName); + public ulong ProcessGetModuleBase(uint pid, string wszModuleName) + { + return vmmi.VMMDLL_ProcessGetModuleBase(hVMM, pid, wszModuleName); + } @@ -825,13 +850,13 @@ namespace vmmsharp // WINDOWS SPECIFIC DEBUGGING / SYMBOL FUNCTIONALITY BELOW: //--------------------------------------------------------------------- - public static unsafe bool PdbLoad(uint pid, ulong vaModuleBase, out string szModuleName) + public unsafe bool PdbLoad(uint pid, ulong vaModuleBase, out string szModuleName) { szModuleName = ""; byte[] data = new byte[260]; fixed (byte* pb = data) { - bool result = vmmi.VMMDLL_PdbLoad(pid, vaModuleBase, pb); + bool result = vmmi.VMMDLL_PdbLoad(hVMM, pid, vaModuleBase, pb); if(!result) { return false; } szModuleName = Encoding.UTF8.GetString(data); szModuleName = szModuleName.Substring(0, szModuleName.IndexOf((char)0)); @@ -839,14 +864,14 @@ namespace vmmsharp return true; } - public static unsafe bool PdbSymbolName(string szModule, ulong cbSymbolAddressOrOffset, out string szSymbolName, out uint pdwSymbolDisplacement) + public unsafe bool PdbSymbolName(string szModule, ulong cbSymbolAddressOrOffset, out string szSymbolName, out uint pdwSymbolDisplacement) { szSymbolName = ""; pdwSymbolDisplacement = 0; byte[] data = new byte[260]; fixed (byte* pb = data) { - bool result = vmmi.VMMDLL_PdbSymbolName(szModule, cbSymbolAddressOrOffset, pb, out pdwSymbolDisplacement); + bool result = vmmi.VMMDLL_PdbSymbolName(hVMM, szModule, cbSymbolAddressOrOffset, pb, out pdwSymbolDisplacement); if (!result) { return false; } szSymbolName = Encoding.UTF8.GetString(data); szSymbolName = szSymbolName.Substring(0, szSymbolName.IndexOf((char)0)); @@ -854,16 +879,20 @@ namespace vmmsharp return true; } - [DllImport("vmm.dll", EntryPoint = "VMMDLL_PdbSymbolAddress")] - public static extern bool PdbSymbolAddress([MarshalAs(UnmanagedType.LPStr)] string szModule, [MarshalAs(UnmanagedType.LPStr)] string szSymbolName, out ulong pvaSymbolAddress); - - [DllImport("vmm.dll", EntryPoint = "VMMDLL_PdbTypeSize")] - public static extern bool PdbTypeSize([MarshalAs(UnmanagedType.LPStr)] string szModule, [MarshalAs(UnmanagedType.LPStr)] string szTypeName, out uint pcbTypeSize); - - [DllImport("vmm.dll", EntryPoint = "VMMDLL_PdbTypeChildOffset")] - public static extern bool PdbTypeChildOffset([MarshalAs(UnmanagedType.LPStr)] string szModule, [MarshalAs(UnmanagedType.LPStr)] string szTypeName, [MarshalAs(UnmanagedType.LPStr)] string wszTypeChildName, out uint pcbTypeChildOffset); + public bool PdbSymbolAddress(string szModule, string szSymbolName, out ulong pvaSymbolAddress) + { + return vmmi.VMMDLL_PdbSymbolAddress(hVMM, szModule, szSymbolName, out pvaSymbolAddress); + } + public bool PdbTypeSize(string szModule, string szTypeName, out uint pcbTypeSize) + { + return vmmi.VMMDLL_PdbTypeSize(hVMM, szModule, szTypeName, out pcbTypeSize); + } + public bool PdbTypeChildOffset(string szModule, string szTypeName, string wszTypeChildName, out uint pcbTypeChildOffset) + { + return vmmi.VMMDLL_PdbTypeChildOffset(hVMM, szModule, szTypeName, wszTypeChildName, out pcbTypeChildOffset); + } @@ -1181,310 +1210,277 @@ namespace vmmsharp public byte priority; } - public static unsafe MAP_PTEENTRY[] Map_GetPte(uint pid, bool fIdentifyModules = true) + public unsafe MAP_PTEENTRY[] Map_GetPte(uint pid, bool fIdentifyModules = true) { - bool result; - uint cb = 0; int cbMAP = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_PTE)); int cbENTRY = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_PTEENTRY)); - result = vmmi.VMMDLL_Map_GetPte(pid, null, ref cb, fIdentifyModules); - if (!result || (cb == 0)) { return new MAP_PTEENTRY[0]; } - fixed (byte* pb = new byte[cb]) + IntPtr pMap = IntPtr.Zero; + MAP_PTEENTRY[] m = new MAP_PTEENTRY[0]; + if (!vmmi.VMMDLL_Map_GetPte(hVMM, pid, fIdentifyModules, out pMap)) { goto fail; } + vmmi.VMMDLL_MAP_PTE nM = Marshal.PtrToStructure(pMap); + if (nM.dwVersion != vmmi.VMMDLL_MAP_PTE_VERSION) { goto fail; } + m = new MAP_PTEENTRY[nM.cMap]; + for (int i = 0; i < nM.cMap; i++) { - result = vmmi.VMMDLL_Map_GetPte(pid, pb, ref cb, fIdentifyModules); - if (!result) { return new MAP_PTEENTRY[0]; } - vmmi.VMMDLL_MAP_PTE pm = Marshal.PtrToStructure((System.IntPtr)pb); - if (pm.dwVersion != vmmi.VMMDLL_MAP_PTE_VERSION) { return new MAP_PTEENTRY[0]; } - MAP_PTEENTRY[] m = new MAP_PTEENTRY[pm.cMap]; - for (int i = 0; i < pm.cMap; i++) - { - vmmi.VMMDLL_MAP_PTEENTRY n = Marshal.PtrToStructure((System.IntPtr)(pb + cbMAP + i * cbENTRY)); - MAP_PTEENTRY e; - e.vaBase = n.vaBase; - e.vaEnd = n.vaBase + (n.cPages << 12) - 1; - e.cbSize = n.cPages << 12; - e.cPages = n.cPages; - e.fPage = n.fPage; - e.fWoW64 = n.fWoW64; - e.wszText = n.wszText; - e.cSoftware = n.cSoftware; - m[i] = e; - } - return m; + vmmi.VMMDLL_MAP_PTEENTRY n = Marshal.PtrToStructure((System.IntPtr)(pMap.ToInt64() + cbMAP + i * cbENTRY)); + MAP_PTEENTRY e; + e.vaBase = n.vaBase; + e.vaEnd = n.vaBase + (n.cPages << 12) - 1; + e.cbSize = n.cPages << 12; + e.cPages = n.cPages; + e.fPage = n.fPage; + e.fWoW64 = n.fWoW64; + e.wszText = n.wszText; + e.cSoftware = n.cSoftware; + m[i] = e; } + fail: + vmmi.VMMDLL_MemFree((byte*)pMap.ToPointer()); + return m; } - public static unsafe MAP_VADENTRY[] Map_GetVad(uint pid, bool fIdentifyModules = true) + public unsafe MAP_VADENTRY[] Map_GetVad(uint pid, bool fIdentifyModules = true) { - bool result; - uint cb = 0; int cbMAP = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_VAD)); int cbENTRY = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_VADENTRY)); - result = vmmi.VMMDLL_Map_GetVad(pid, null, ref cb, fIdentifyModules); - if (!result || (cb == 0)) { return new MAP_VADENTRY[0]; } - fixed (byte* pb = new byte[cb]) + IntPtr pMap = IntPtr.Zero; + MAP_VADENTRY[] m = new MAP_VADENTRY[0]; + if (!vmmi.VMMDLL_Map_GetVad(hVMM, pid, fIdentifyModules, out pMap)) { goto fail; } + vmmi.VMMDLL_MAP_VAD nM = Marshal.PtrToStructure(pMap); + if (nM.dwVersion != vmmi.VMMDLL_MAP_VAD_VERSION) { goto fail; } + m = new MAP_VADENTRY[nM.cMap]; + for (int i = 0; i < nM.cMap; i++) { - result = vmmi.VMMDLL_Map_GetVad(pid, pb, ref cb, fIdentifyModules); - if (!result) { return new MAP_VADENTRY[0]; } - vmmi.VMMDLL_MAP_VAD pm = Marshal.PtrToStructure((System.IntPtr)pb); - if (pm.dwVersion != vmmi.VMMDLL_MAP_VAD_VERSION) { return new MAP_VADENTRY[0]; } - MAP_VADENTRY[] m = new MAP_VADENTRY[pm.cMap]; - for (int i = 0; i < pm.cMap; i++) - { - vmmi.VMMDLL_MAP_VADENTRY n = Marshal.PtrToStructure((System.IntPtr)(pb + cbMAP + i * cbENTRY)); - MAP_VADENTRY e; - e.vaStart = n.vaStart; - e.vaEnd = n.vaEnd; - e.cbSize = n.vaEnd + 1 - n.vaStart; - e.vaVad = n.vaVad; - e.VadType = n.dw0 & 0x07; - e.Protection = (n.dw0 >> 3) & 0x1f; - e.fImage = ((n.dw0 >> 8) & 1) == 1; - e.fFile = ((n.dw0 >> 9) & 1) == 1; - e.fPageFile = ((n.dw0 >> 10) & 1) == 1; - e.fPrivateMemory = ((n.dw0 >> 11) & 1) == 1; - e.fTeb = ((n.dw0 >> 12) & 1) == 1; - e.fStack = ((n.dw0 >> 13) & 1) == 1; - e.fSpare = (n.dw0 >> 14) & 0x03; - e.HeapNum = (n.dw0 >> 16) & 0x1f; - e.fHeap = ((n.dw0 >> 23) & 1) == 1; - e.cwszDescription = (n.dw0 >> 24) & 0xff; - e.CommitCharge = n.dw1 & 0x7fffffff; - e.MemCommit = ((n.dw1 >> 31) & 1) == 1; - e.u2 = n.u2; - e.cbPrototypePte = n.cbPrototypePte; - e.vaPrototypePte = n.vaPrototypePte; - e.vaSubsection = n.vaSubsection; - e.wszText = n.wszText; - e.vaFileObject = n.vaFileObject; - e.cVadExPages = n.cVadExPages; - e.cVadExPagesBase = n.cVadExPagesBase; - m[i] = e; - } - return m; + vmmi.VMMDLL_MAP_VADENTRY n = Marshal.PtrToStructure((System.IntPtr)(pMap.ToInt64() + cbMAP + i * cbENTRY)); + MAP_VADENTRY e; + e.vaStart = n.vaStart; + e.vaEnd = n.vaEnd; + e.cbSize = n.vaEnd + 1 - n.vaStart; + e.vaVad = n.vaVad; + e.VadType = n.dw0 & 0x07; + e.Protection = (n.dw0 >> 3) & 0x1f; + e.fImage = ((n.dw0 >> 8) & 1) == 1; + e.fFile = ((n.dw0 >> 9) & 1) == 1; + e.fPageFile = ((n.dw0 >> 10) & 1) == 1; + e.fPrivateMemory = ((n.dw0 >> 11) & 1) == 1; + e.fTeb = ((n.dw0 >> 12) & 1) == 1; + e.fStack = ((n.dw0 >> 13) & 1) == 1; + e.fSpare = (n.dw0 >> 14) & 0x03; + e.HeapNum = (n.dw0 >> 16) & 0x1f; + e.fHeap = ((n.dw0 >> 23) & 1) == 1; + e.cwszDescription = (n.dw0 >> 24) & 0xff; + e.CommitCharge = n.dw1 & 0x7fffffff; + e.MemCommit = ((n.dw1 >> 31) & 1) == 1; + e.u2 = n.u2; + e.cbPrototypePte = n.cbPrototypePte; + e.vaPrototypePte = n.vaPrototypePte; + e.vaSubsection = n.vaSubsection; + e.wszText = n.wszText; + e.vaFileObject = n.vaFileObject; + e.cVadExPages = n.cVadExPages; + e.cVadExPagesBase = n.cVadExPagesBase; + m[i] = e; } + fail: + vmmi.VMMDLL_MemFree((byte*)pMap.ToPointer()); + return m; } - public static unsafe MAP_VADEXENTRY[] Map_GetVadEx(uint pid, uint oPages, uint cPages) + public unsafe MAP_VADEXENTRY[] Map_GetVadEx(uint pid, uint oPages, uint cPages) { - bool result; - uint cb = 0; int cbMAP = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_VADEX)); int cbENTRY = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_VADEXENTRY)); - result = vmmi.VMMDLL_Map_GetVadEx(pid, null, ref cb, oPages, cPages); - if (!result || (cb == 0)) { return new MAP_VADEXENTRY[0]; } - fixed (byte* pb = new byte[cb]) + IntPtr pMap = IntPtr.Zero; + MAP_VADEXENTRY[] m = new MAP_VADEXENTRY[0]; + if (!vmmi.VMMDLL_Map_GetVadEx(hVMM, pid, oPages, cPages, out pMap)) { goto fail; } + vmmi.VMMDLL_MAP_VADEX nM = Marshal.PtrToStructure(pMap); + if (nM.dwVersion != vmmi.VMMDLL_MAP_VADEX_VERSION) { goto fail; } + m = new MAP_VADEXENTRY[nM.cMap]; + for (int i = 0; i < nM.cMap; i++) { - result = vmmi.VMMDLL_Map_GetVadEx(pid, pb, ref cb, oPages, cPages); - if (!result) { return new MAP_VADEXENTRY[0]; } - vmmi.VMMDLL_MAP_VADEX pm = Marshal.PtrToStructure((System.IntPtr)pb); - if (pm.dwVersion != vmmi.VMMDLL_MAP_VADEX_VERSION) { return new MAP_VADEXENTRY[0]; } - MAP_VADEXENTRY[] m = new MAP_VADEXENTRY[pm.cMap]; - for (int i = 0; i < pm.cMap; i++) - { - vmmi.VMMDLL_MAP_VADEXENTRY n = Marshal.PtrToStructure((System.IntPtr)(pb + cbMAP + i * cbENTRY)); - MAP_VADEXENTRY e; - e.tp = n.tp; - e.iPML = n.iPML; - e.va = n.va; - e.pa = n.pa; - e.pte = n.pte; - e.proto.tp = n.proto_tp; - e.proto.pa = n.proto_pa; - e.proto.pte = n.proto_pte; - e.vaVadBase = n.vaVadBase; - m[i] = e; - } - return m; + vmmi.VMMDLL_MAP_VADEXENTRY n = Marshal.PtrToStructure((System.IntPtr)(pMap.ToInt64() + cbMAP + i * cbENTRY)); + MAP_VADEXENTRY e; + e.tp = n.tp; + e.iPML = n.iPML; + e.va = n.va; + e.pa = n.pa; + e.pte = n.pte; + e.proto.tp = n.proto_tp; + e.proto.pa = n.proto_pa; + e.proto.pte = n.proto_pte; + e.vaVadBase = n.vaVadBase; + m[i] = e; } + fail: + vmmi.VMMDLL_MemFree((byte*)pMap.ToPointer()); + return m; } - public static unsafe MAP_MODULEENTRY[] Map_GetModule(uint pid) + public unsafe MAP_MODULEENTRY[] Map_GetModule(uint pid) { - bool result; - uint cb = 0; int cbMAP = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_MODULE)); int cbENTRY = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_MODULEENTRY)); - result = vmmi.VMMDLL_Map_GetModule(pid, null, ref cb); - if(!result || (cb == 0)) { return new MAP_MODULEENTRY[0]; } - fixed(byte* pb = new byte[cb]) + IntPtr pMap = IntPtr.Zero; + MAP_MODULEENTRY[] m = new MAP_MODULEENTRY[0]; + if (!vmmi.VMMDLL_Map_GetModule(hVMM, pid, out pMap)) { goto fail; } + vmmi.VMMDLL_MAP_MODULE nM = Marshal.PtrToStructure(pMap); + if (nM.dwVersion != vmmi.VMMDLL_MAP_MODULE_VERSION) { goto fail; } + m = new MAP_MODULEENTRY[nM.cMap]; + for (int i = 0; i < nM.cMap; i++) { - result = vmmi.VMMDLL_Map_GetModule(pid, pb, ref cb); - if(!result) { return new MAP_MODULEENTRY[0]; } - vmmi.VMMDLL_MAP_MODULE pm = Marshal.PtrToStructure((System.IntPtr)pb); - if(pm.dwVersion != vmmi.VMMDLL_MAP_MODULE_VERSION) { return new MAP_MODULEENTRY[0]; } - MAP_MODULEENTRY[] m = new MAP_MODULEENTRY[pm.cMap]; - for (int i = 0; i < pm.cMap; i++) - { - vmmi.VMMDLL_MAP_MODULEENTRY n = Marshal.PtrToStructure((System.IntPtr)(pb + cbMAP + i * cbENTRY)); - MAP_MODULEENTRY e; - e.fValid = true; - e.vaBase = n.vaBase; - e.vaEntry = n.vaEntry; - e.cbImageSize = n.cbImageSize; - e.fWow64 = n.fWow64; - e.wszText = n.wszText; - e.wszFullName = n.wszFullName; - e.tp = n.tp; - e.cbFileSizeRaw = n.cbFileSizeRaw; - e.cSection = n.cSection; - e.cEAT = n.cEAT; - e.cIAT = n.cIAT; - m[i] = e; - } - return m; - } - } - - public static unsafe MAP_MODULEENTRY Map_GetModuleFromName(uint pid, string wszModuleName) - { - bool result; - uint cbENTRY = 0; - result = vmmi.VMMDLL_Map_GetModuleFromName(pid, wszModuleName, null, ref cbENTRY); - if (!result || (cbENTRY == 0)) { return new MAP_MODULEENTRY(); } - fixed (byte* pb = new byte[cbENTRY]) - { - result = vmmi.VMMDLL_Map_GetModuleFromName(pid, wszModuleName, pb, ref cbENTRY); - if (!result) { return new MAP_MODULEENTRY(); } - vmmi.VMMDLL_MAP_MODULEENTRY n = Marshal.PtrToStructure((System.IntPtr)pb); + vmmi.VMMDLL_MAP_MODULEENTRY n = Marshal.PtrToStructure((System.IntPtr)(pMap.ToInt64() + cbMAP + i * cbENTRY)); MAP_MODULEENTRY e; e.fValid = true; e.vaBase = n.vaBase; e.vaEntry = n.vaEntry; e.cbImageSize = n.cbImageSize; e.fWow64 = n.fWow64; - e.wszText = wszModuleName; + e.wszText = n.wszText; e.wszFullName = n.wszFullName; e.tp = n.tp; e.cbFileSizeRaw = n.cbFileSizeRaw; e.cSection = n.cSection; e.cEAT = n.cEAT; e.cIAT = n.cIAT; - return e; + m[i] = e; } + fail: + vmmi.VMMDLL_MemFree((byte*)pMap.ToPointer()); + return m; } - public static unsafe MAP_UNLOADEDMODULEENTRY[] Map_GetUnloadedModule(uint pid) + public unsafe MAP_MODULEENTRY Map_GetModuleFromName(uint pid, string wszModuleName) + { + IntPtr pMap = IntPtr.Zero; + MAP_MODULEENTRY e = new MAP_MODULEENTRY(); + if (!vmmi.VMMDLL_Map_GetModuleFromName(hVMM, pid, wszModuleName, out pMap)) { goto fail; } + vmmi.VMMDLL_MAP_MODULEENTRY nM = Marshal.PtrToStructure(pMap); + e.fValid = true; + e.vaBase = nM.vaBase; + e.vaEntry = nM.vaEntry; + e.cbImageSize = nM.cbImageSize; + e.fWow64 = nM.fWow64; + e.wszText = wszModuleName; + e.wszFullName = nM.wszFullName; + e.tp = nM.tp; + e.cbFileSizeRaw = nM.cbFileSizeRaw; + e.cSection = nM.cSection; + e.cEAT = nM.cEAT; + e.cIAT = nM.cIAT; + fail: + vmmi.VMMDLL_MemFree((byte*)pMap.ToPointer()); + return e; + } + + public unsafe MAP_UNLOADEDMODULEENTRY[] Map_GetUnloadedModule(uint pid) { - bool result; - uint cb = 0; int cbMAP = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_UNLOADEDMODULE)); int cbENTRY = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_UNLOADEDMODULEENTRY)); - result = vmmi.VMMDLL_Map_GetUnloadedModule(pid, null, ref cb); - if (!result || (cb == 0)) { return new MAP_UNLOADEDMODULEENTRY[0]; } - fixed (byte* pb = new byte[cb]) + IntPtr pMap = IntPtr.Zero; + MAP_UNLOADEDMODULEENTRY[] m = new MAP_UNLOADEDMODULEENTRY[0]; + if (!vmmi.VMMDLL_Map_GetUnloadedModule(hVMM, pid, out pMap)) { goto fail; } + vmmi.VMMDLL_MAP_UNLOADEDMODULE nM = Marshal.PtrToStructure(pMap); + if (nM.dwVersion != vmmi.VMMDLL_MAP_UNLOADEDMODULE_VERSION) { goto fail; } + m = new MAP_UNLOADEDMODULEENTRY[nM.cMap]; + for (int i = 0; i < nM.cMap; i++) { - result = vmmi.VMMDLL_Map_GetUnloadedModule(pid, pb, ref cb); - if (!result) { return new MAP_UNLOADEDMODULEENTRY[0]; } - vmmi.VMMDLL_MAP_UNLOADEDMODULE pm = Marshal.PtrToStructure((System.IntPtr)pb); - if (pm.dwVersion != vmmi.VMMDLL_MAP_UNLOADEDMODULE_VERSION) { return new MAP_UNLOADEDMODULEENTRY[0]; } - MAP_UNLOADEDMODULEENTRY[] m = new MAP_UNLOADEDMODULEENTRY[pm.cMap]; - for (int i = 0; i < pm.cMap; i++) - { - vmmi.VMMDLL_MAP_UNLOADEDMODULEENTRY n = Marshal.PtrToStructure((System.IntPtr)(pb + cbMAP + i * cbENTRY)); - MAP_UNLOADEDMODULEENTRY e; - e.vaBase = n.vaBase; - e.cbImageSize = n.cbImageSize; - e.fWow64 = n.fWow64; - e.wszText = n.wszText; - e.dwCheckSum = n.dwCheckSum; - e.dwTimeDateStamp = n.dwTimeDateStamp; - e.ftUnload = n.ftUnload; - m[i] = e; - } - return m; + vmmi.VMMDLL_MAP_UNLOADEDMODULEENTRY n = Marshal.PtrToStructure((System.IntPtr)(pMap.ToInt64() + cbMAP + i * cbENTRY)); + MAP_UNLOADEDMODULEENTRY e; + e.vaBase = n.vaBase; + e.cbImageSize = n.cbImageSize; + e.fWow64 = n.fWow64; + e.wszText = n.wszText; + e.dwCheckSum = n.dwCheckSum; + e.dwTimeDateStamp = n.dwTimeDateStamp; + e.ftUnload = n.ftUnload; + m[i] = e; } + fail: + vmmi.VMMDLL_MemFree((byte*)pMap.ToPointer()); + return m; } - public static unsafe MAP_EATENTRY[] Map_GetEAT(uint pid, string wszModule, out MAP_EATINFO EatInfo) + public unsafe MAP_EATENTRY[] Map_GetEAT(uint pid, string wszModule, out MAP_EATINFO EatInfo) { - bool result; - uint cb = 0; + EatInfo = new MAP_EATINFO(); int cbMAP = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_EAT)); int cbENTRY = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_EATENTRY)); - EatInfo = new MAP_EATINFO(); - result = vmmi.VMMDLL_Map_GetEAT(pid, wszModule, null, ref cb); - if (!result || (cb == 0)) { return new MAP_EATENTRY[0]; } - fixed (byte* pb = new byte[cb]) + IntPtr pMap = IntPtr.Zero; + MAP_EATENTRY[] m = new MAP_EATENTRY[0]; + if (!vmmi.VMMDLL_Map_GetEAT(hVMM, pid, wszModule, out pMap)) { goto fail; } + vmmi.VMMDLL_MAP_EAT nM = Marshal.PtrToStructure(pMap); + if (nM.dwVersion != vmmi.VMMDLL_MAP_EAT_VERSION) { goto fail; } + m = new MAP_EATENTRY[nM.cMap]; + for (int i = 0; i < nM.cMap; i++) { - result = vmmi.VMMDLL_Map_GetEAT(pid, wszModule, pb, ref cb); - if (!result) { return new MAP_EATENTRY[0]; } - vmmi.VMMDLL_MAP_EAT pm = Marshal.PtrToStructure((System.IntPtr)pb); - if (pm.dwVersion != vmmi.VMMDLL_MAP_EAT_VERSION) { return new MAP_EATENTRY[0]; } - MAP_EATENTRY[] m = new MAP_EATENTRY[pm.cMap]; - for (int i = 0; i < pm.cMap; i++) - { - vmmi.VMMDLL_MAP_EATENTRY n = Marshal.PtrToStructure((System.IntPtr)(pb + cbMAP + i * cbENTRY)); - MAP_EATENTRY e; - e.vaFunction = n.vaFunction; - e.dwOrdinal = n.dwOrdinal; - e.oFunctionsArray = n.oFunctionsArray; - e.oNamesArray = n.oNamesArray; - e.wszFunction = n.wszFunction; - m[i] = e; - } - EatInfo.fValid = true; - EatInfo.vaModuleBase = pm.vaModuleBase; - EatInfo.vaAddressOfFunctions = pm.vaAddressOfFunctions; - EatInfo.vaAddressOfNames = pm.vaAddressOfNames; - EatInfo.cNumberOfFunctions = pm.cNumberOfFunctions; - EatInfo.cNumberOfNames = pm.cNumberOfNames; - EatInfo.dwOrdinalBase = pm.dwOrdinalBase; - return m; + vmmi.VMMDLL_MAP_EATENTRY n = Marshal.PtrToStructure((System.IntPtr)(pMap.ToInt64() + cbMAP + i * cbENTRY)); + MAP_EATENTRY e; + e.vaFunction = n.vaFunction; + e.dwOrdinal = n.dwOrdinal; + e.oFunctionsArray = n.oFunctionsArray; + e.oNamesArray = n.oNamesArray; + e.wszFunction = n.wszFunction; + m[i] = e; } + EatInfo.fValid = true; + EatInfo.vaModuleBase = nM.vaModuleBase; + EatInfo.vaAddressOfFunctions = nM.vaAddressOfFunctions; + EatInfo.vaAddressOfNames = nM.vaAddressOfNames; + EatInfo.cNumberOfFunctions = nM.cNumberOfFunctions; + EatInfo.cNumberOfNames = nM.cNumberOfNames; + EatInfo.dwOrdinalBase = nM.dwOrdinalBase; + fail: + vmmi.VMMDLL_MemFree((byte*)pMap.ToPointer()); + return m; } - public static unsafe MAP_IATENTRY[] Map_GetIAT(uint pid, string wszModule) + public unsafe MAP_IATENTRY[] Map_GetIAT(uint pid, string wszModule) { - bool result; - uint cb = 0; int cbMAP = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_IAT)); int cbENTRY = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_IATENTRY)); - result = vmmi.VMMDLL_Map_GetIAT(pid, wszModule, null, ref cb); - if (!result || (cb == 0)) { return new MAP_IATENTRY[0]; } - fixed (byte* pb = new byte[cb]) + IntPtr pMap = IntPtr.Zero; + MAP_IATENTRY[] m = new MAP_IATENTRY[0]; + if (!vmmi.VMMDLL_Map_GetIAT(hVMM, pid, wszModule, out pMap)) { goto fail; } + vmmi.VMMDLL_MAP_IAT nM = Marshal.PtrToStructure(pMap); + if (nM.dwVersion != vmmi.VMMDLL_MAP_IAT_VERSION) { goto fail; } + m = new MAP_IATENTRY[nM.cMap]; + for (int i = 0; i < nM.cMap; i++) { - result = vmmi.VMMDLL_Map_GetIAT(pid, wszModule, pb, ref cb); - if (!result) { return new MAP_IATENTRY[0]; } - vmmi.VMMDLL_MAP_IAT pm = Marshal.PtrToStructure((System.IntPtr)pb); - if (pm.dwVersion != vmmi.VMMDLL_MAP_IAT_VERSION) { return new MAP_IATENTRY[0]; } - MAP_IATENTRY[] m = new MAP_IATENTRY[pm.cMap]; - for (int i = 0; i < pm.cMap; i++) - { - vmmi.VMMDLL_MAP_IATENTRY n = Marshal.PtrToStructure((System.IntPtr)(pb + cbMAP + i * cbENTRY)); - MAP_IATENTRY e; - e.vaFunction = n.vaFunction; - e.wszFunction = n.wszFunction; - e.wszModule = n.wszModule; - e.f32 = n.f32; - e.wHint = n.wHint; - e.rvaFirstThunk = n.rvaFirstThunk; - e.rvaOriginalFirstThunk = n.rvaOriginalFirstThunk; - e.rvaNameModule = n.rvaNameModule; - e.rvaNameFunction = n.rvaNameFunction; - e.vaModule = pm.vaModuleBase; - m[i] = e; - } - return m; + vmmi.VMMDLL_MAP_IATENTRY n = Marshal.PtrToStructure((System.IntPtr)(pMap.ToInt64() + cbMAP + i * cbENTRY)); + MAP_IATENTRY e; + e.vaFunction = n.vaFunction; + e.wszFunction = n.wszFunction; + e.wszModule = n.wszModule; + e.f32 = n.f32; + e.wHint = n.wHint; + e.rvaFirstThunk = n.rvaFirstThunk; + e.rvaOriginalFirstThunk = n.rvaOriginalFirstThunk; + e.rvaNameModule = n.rvaNameModule; + e.rvaNameFunction = n.rvaNameFunction; + e.vaModule = nM.vaModuleBase; + m[i] = e; } + fail: + vmmi.VMMDLL_MemFree((byte*)pMap.ToPointer()); + return m; } - public static unsafe MAP_HEAP Map_GetHeap(uint pid) + public unsafe MAP_HEAP Map_GetHeap(uint pid) { - IntPtr pHeapMap = IntPtr.Zero; + IntPtr pMap = IntPtr.Zero; int cbMAP = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_HEAP)); int cbENTRY = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_HEAPENTRY)); int cbSEGENTRY = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_HEAPSEGMENTENTRY)); MAP_HEAP Heap; Heap.heaps = new MAP_HEAPENTRY[0]; Heap.segments = new MAP_HEAPSEGMENTENTRY[0]; - if(!vmmi.VMMDLL_Map_GetHeapEx(pid, out pHeapMap)) { goto fail; } - vmmi.VMMDLL_MAP_HEAP nM = Marshal.PtrToStructure(pHeapMap); + if(!vmmi.VMMDLL_Map_GetHeap(hVMM, pid, out pMap)) { goto fail; } + vmmi.VMMDLL_MAP_HEAP nM = Marshal.PtrToStructure(pMap); if (nM.dwVersion != vmmi.VMMDLL_MAP_HEAP_VERSION) { goto fail; } Heap.heaps = new MAP_HEAPENTRY[nM.cMap]; for (int i = 0; i < nM.cMap; i++) { - vmmi.VMMDLL_MAP_HEAPENTRY nH = Marshal.PtrToStructure((System.IntPtr)(pHeapMap.ToInt64() + cbMAP + i * cbENTRY)); + vmmi.VMMDLL_MAP_HEAPENTRY nH = Marshal.PtrToStructure((System.IntPtr)(pMap.ToInt64() + cbMAP + i * cbENTRY)); Heap.heaps[i].va = nH.va; Heap.heaps[i].f32 = nH.f32; Heap.heaps[i].tpHeap = nH.tp; @@ -1500,16 +1496,16 @@ namespace vmmsharp Heap.segments[i].iHeapNum = nH.iHeap; } fail: - vmmi.VMMDLL_MemFree((byte*)pHeapMap.ToPointer()); + vmmi.VMMDLL_MemFree((byte*)pMap.ToPointer()); return Heap; } - public static unsafe MAP_HEAPALLOCENTRY[] Map_GetHeapAlloc(uint pid, ulong vaHeapOrHeapNum) + public unsafe MAP_HEAPALLOCENTRY[] Map_GetHeapAlloc(uint pid, ulong vaHeapOrHeapNum) { IntPtr pHeapAllocMap = IntPtr.Zero; int cbMAP = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_HEAPALLOC)); int cbENTRY = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_HEAPALLOCENTRY)); - if (!vmmi.VMMDLL_Map_GetHeapAllocEx(pid, vaHeapOrHeapNum, out pHeapAllocMap)) { return new MAP_HEAPALLOCENTRY[0]; } + if (!vmmi.VMMDLL_Map_GetHeapAlloc(hVMM, pid, vaHeapOrHeapNum, out pHeapAllocMap)) { return new MAP_HEAPALLOCENTRY[0]; } vmmi.VMMDLL_MAP_HEAPALLOC nM = Marshal.PtrToStructure(pHeapAllocMap); if (nM.dwVersion != vmmi.VMMDLL_MAP_HEAPALLOC_VERSION) { vmmi.VMMDLL_MemFree((byte*)pHeapAllocMap.ToPointer()); @@ -1527,167 +1523,150 @@ namespace vmmsharp return m; } - public static unsafe MAP_THREADENTRY[] Map_GetThread(uint pid) + public unsafe MAP_THREADENTRY[] Map_GetThread(uint pid) { - bool result; - uint cb = 0; int cbMAP = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_THREAD)); int cbENTRY = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_THREADENTRY)); - result = vmmi.VMMDLL_Map_GetThread(pid, null, ref cb); - if (!result || (cb == 0)) { return new MAP_THREADENTRY[0]; } - fixed (byte* pb = new byte[cb]) + IntPtr pMap = IntPtr.Zero; + MAP_THREADENTRY[] m = new MAP_THREADENTRY[0]; + if (!vmmi.VMMDLL_Map_GetThread(hVMM, pid, out pMap)) { goto fail; } + vmmi.VMMDLL_MAP_THREAD nM = Marshal.PtrToStructure(pMap); + if (nM.dwVersion != vmmi.VMMDLL_MAP_THREAD_VERSION) { goto fail; } + m = new MAP_THREADENTRY[nM.cMap]; + for (int i = 0; i < nM.cMap; i++) { - result = vmmi.VMMDLL_Map_GetThread(pid, pb, ref cb); - if (!result) { return new MAP_THREADENTRY[0]; } - vmmi.VMMDLL_MAP_THREAD pm = Marshal.PtrToStructure((System.IntPtr)pb); - if (pm.dwVersion != vmmi.VMMDLL_MAP_THREAD_VERSION) { return new MAP_THREADENTRY[0]; } - MAP_THREADENTRY[] m = new MAP_THREADENTRY[pm.cMap]; - for (int i = 0; i < pm.cMap; i++) - { - vmmi.VMMDLL_MAP_THREADENTRY n = Marshal.PtrToStructure((System.IntPtr)(pb + cbMAP + i * cbENTRY)); - MAP_THREADENTRY e; - e.dwTID = n.dwTID; - e.dwPID = n.dwPID; - e.dwExitStatus = n.dwExitStatus; - e.bState = n.bState; - e.bRunning = n.bRunning; - e.bPriority = n.bPriority; - e.bBasePriority = n.bBasePriority; - e.vaETHREAD = n.vaETHREAD; - e.vaTeb = n.vaTeb; - e.ftCreateTime = n.ftCreateTime; - e.ftExitTime = n.ftExitTime; - e.vaStartAddress = n.vaStartAddress; - e.vaStackBaseUser = n.vaStackBaseUser; - e.vaStackLimitUser = n.vaStackLimitUser; - e.vaStackBaseKernel = n.vaStackBaseKernel; - e.vaStackLimitKernel = n.vaStackLimitKernel; - e.vaTrapFrame = n.vaTrapFrame; - e.vaRIP = n.vaRIP; - e.vaRSP = n.vaRSP; - e.qwAffinity = n.qwAffinity; - e.dwUserTime = n.dwUserTime; - e.dwKernelTime = n.dwKernelTime; - e.bSuspendCount = n.bSuspendCount; - e.bWaitReason = n.bWaitReason; - m[i] = e; - } - return m; + vmmi.VMMDLL_MAP_THREADENTRY n = Marshal.PtrToStructure((System.IntPtr)(pMap.ToInt64() + cbMAP + i * cbENTRY)); + MAP_THREADENTRY e; + e.dwTID = n.dwTID; + e.dwPID = n.dwPID; + e.dwExitStatus = n.dwExitStatus; + e.bState = n.bState; + e.bRunning = n.bRunning; + e.bPriority = n.bPriority; + e.bBasePriority = n.bBasePriority; + e.vaETHREAD = n.vaETHREAD; + e.vaTeb = n.vaTeb; + e.ftCreateTime = n.ftCreateTime; + e.ftExitTime = n.ftExitTime; + e.vaStartAddress = n.vaStartAddress; + e.vaStackBaseUser = n.vaStackBaseUser; + e.vaStackLimitUser = n.vaStackLimitUser; + e.vaStackBaseKernel = n.vaStackBaseKernel; + e.vaStackLimitKernel = n.vaStackLimitKernel; + e.vaTrapFrame = n.vaTrapFrame; + e.vaRIP = n.vaRIP; + e.vaRSP = n.vaRSP; + e.qwAffinity = n.qwAffinity; + e.dwUserTime = n.dwUserTime; + e.dwKernelTime = n.dwKernelTime; + e.bSuspendCount = n.bSuspendCount; + e.bWaitReason = n.bWaitReason; + m[i] = e; } + fail: + vmmi.VMMDLL_MemFree((byte*)pMap.ToPointer()); + return m; } - public static unsafe MAP_HANDLEENTRY[] Map_GetHandle(uint pid) + public unsafe MAP_HANDLEENTRY[] Map_GetHandle(uint pid) { - bool result; - uint cb = 0; int cbMAP = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_HANDLE)); int cbENTRY = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_HANDLEENTRY)); - result = vmmi.VMMDLL_Map_GetHandle(pid, null, ref cb); - if (!result || (cb == 0)) { return new MAP_HANDLEENTRY[0]; } - fixed (byte* pb = new byte[cb]) + IntPtr pMap = IntPtr.Zero; + MAP_HANDLEENTRY[] m = new MAP_HANDLEENTRY[0]; + if (!vmmi.VMMDLL_Map_GetHandle(hVMM, pid, out pMap)) { goto fail; } + vmmi.VMMDLL_MAP_HANDLE nM = Marshal.PtrToStructure(pMap); + if (nM.dwVersion != vmmi.VMMDLL_MAP_HANDLE_VERSION) { goto fail; } + m = new MAP_HANDLEENTRY[nM.cMap]; + for (int i = 0; i < nM.cMap; i++) { - result = vmmi.VMMDLL_Map_GetHandle(pid, pb, ref cb); - if (!result) { return new MAP_HANDLEENTRY[0]; } - vmmi.VMMDLL_MAP_HANDLE pm = Marshal.PtrToStructure((System.IntPtr)pb); - if (pm.dwVersion != vmmi.VMMDLL_MAP_HANDLE_VERSION) { return new MAP_HANDLEENTRY[0]; } - MAP_HANDLEENTRY[] m = new MAP_HANDLEENTRY[pm.cMap]; - for (int i = 0; i < pm.cMap; i++) - { - vmmi.VMMDLL_MAP_HANDLEENTRY n = Marshal.PtrToStructure((System.IntPtr)(pb + cbMAP + i * cbENTRY)); - MAP_HANDLEENTRY e; - e.vaObject = n.vaObject; - e.dwHandle = n.dwHandle; - e.dwGrantedAccess = n.dwGrantedAccess_iType & 0x00ffffff; - e.iType = n.dwGrantedAccess_iType >> 24; - e.qwHandleCount = n.qwHandleCount; - e.qwPointerCount = n.qwPointerCount; - e.vaObjectCreateInfo = n.vaObjectCreateInfo; - e.vaSecurityDescriptor = n.vaSecurityDescriptor; - e.wszText = n.wszText; - e.dwPID = n.dwPID; - e.dwPoolTag = n.dwPoolTag; - e.wszType = n.wszType; - m[i] = e; - } - return m; + vmmi.VMMDLL_MAP_HANDLEENTRY n = Marshal.PtrToStructure((System.IntPtr)(pMap.ToInt64() + cbMAP + i * cbENTRY)); + MAP_HANDLEENTRY e; + e.vaObject = n.vaObject; + e.dwHandle = n.dwHandle; + e.dwGrantedAccess = n.dwGrantedAccess_iType & 0x00ffffff; + e.iType = n.dwGrantedAccess_iType >> 24; + e.qwHandleCount = n.qwHandleCount; + e.qwPointerCount = n.qwPointerCount; + e.vaObjectCreateInfo = n.vaObjectCreateInfo; + e.vaSecurityDescriptor = n.vaSecurityDescriptor; + e.wszText = n.wszText; + e.dwPID = n.dwPID; + e.dwPoolTag = n.dwPoolTag; + e.wszType = n.wszType; + m[i] = e; } + fail: + vmmi.VMMDLL_MemFree((byte*)pMap.ToPointer()); + return m; } - public static unsafe MAP_NETENTRY[] Map_GetNet() + public unsafe MAP_NETENTRY[] Map_GetNet() { - bool result; - uint cb = 0; int cbMAP = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_NET)); int cbENTRY = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_NETENTRY)); - result = vmmi.VMMDLL_Map_GetNet(null, ref cb); - if (!result || (cb == 0)) { return new MAP_NETENTRY[0]; } - fixed (byte* pb = new byte[cb]) + IntPtr pMap = IntPtr.Zero; + MAP_NETENTRY[] m = new MAP_NETENTRY[0]; + if (!vmmi.VMMDLL_Map_GetNet(hVMM, out pMap)) { goto fail; } + vmmi.VMMDLL_MAP_NET nM = Marshal.PtrToStructure(pMap); + if (nM.dwVersion != vmmi.VMMDLL_MAP_NET_VERSION) { goto fail; } + m = new MAP_NETENTRY[nM.cMap]; + for (int i = 0; i < nM.cMap; i++) { - result = vmmi.VMMDLL_Map_GetNet(pb, ref cb); - if (!result) { return new MAP_NETENTRY[0]; } - vmmi.VMMDLL_MAP_NET pm = Marshal.PtrToStructure((System.IntPtr)pb); - if (pm.dwVersion != vmmi.VMMDLL_MAP_NET_VERSION) { return new MAP_NETENTRY[0]; } - MAP_NETENTRY[] m = new MAP_NETENTRY[pm.cMap]; - for (int i = 0; i < pm.cMap; i++) - { - vmmi.VMMDLL_MAP_NETENTRY n = Marshal.PtrToStructure((System.IntPtr)(pb + cbMAP + i * cbENTRY)); - MAP_NETENTRY e; - e.dwPID = n.dwPID; - e.dwState = n.dwState; - e.dwPoolTag = n.dwPoolTag; - e.AF = n.AF; - e.src.fValid = n.src_fValid; - e.src.port = n.src_port; - e.src.pbAddr = n.src_pbAddr; - e.src.wszText = n.src_wszText; - e.dst.fValid = n.dst_fValid; - e.dst.port = n.dst_port; - e.dst.pbAddr = n.dst_pbAddr; - e.dst.wszText = n.dst_wszText; - e.vaObj = n.vaObj; - e.ftTime = n.ftTime; - e.wszText = n.wszText; - m[i] = e; - } - return m; + vmmi.VMMDLL_MAP_NETENTRY n = Marshal.PtrToStructure((System.IntPtr)(pMap.ToInt64() + cbMAP + i * cbENTRY)); + MAP_NETENTRY e; + e.dwPID = n.dwPID; + e.dwState = n.dwState; + e.dwPoolTag = n.dwPoolTag; + e.AF = n.AF; + e.src.fValid = n.src_fValid; + e.src.port = n.src_port; + e.src.pbAddr = n.src_pbAddr; + e.src.wszText = n.src_wszText; + e.dst.fValid = n.dst_fValid; + e.dst.port = n.dst_port; + e.dst.pbAddr = n.dst_pbAddr; + e.dst.wszText = n.dst_wszText; + e.vaObj = n.vaObj; + e.ftTime = n.ftTime; + e.wszText = n.wszText; + m[i] = e; } + fail: + vmmi.VMMDLL_MemFree((byte*)pMap.ToPointer()); + return m; } - public static unsafe MAP_PHYSMEMENTRY[] Map_GetPhysMem() + public unsafe MAP_PHYSMEMENTRY[] Map_GetPhysMem() { - bool result; - uint cb = 0; int cbMAP = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_PHYSMEM)); int cbENTRY = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_PHYSMEMENTRY)); - result = vmmi.VMMDLL_Map_GetPhysMem(null, ref cb); - if (!result || (cb == 0)) { return new MAP_PHYSMEMENTRY[0]; } - fixed (byte* pb = new byte[cb]) + IntPtr pMap = IntPtr.Zero; + MAP_PHYSMEMENTRY[] m = new MAP_PHYSMEMENTRY[0]; + if (!vmmi.VMMDLL_Map_GetPhysMem(hVMM, out pMap)) { goto fail; } + vmmi.VMMDLL_MAP_PHYSMEM nM = Marshal.PtrToStructure(pMap); + if (nM.dwVersion != vmmi.VMMDLL_MAP_PHYSMEM_VERSION) { goto fail; } + m = new MAP_PHYSMEMENTRY[nM.cMap]; + for (int i = 0; i < nM.cMap; i++) { - result = vmmi.VMMDLL_Map_GetPhysMem(pb, ref cb); - if (!result) { return new MAP_PHYSMEMENTRY[0]; } - vmmi.VMMDLL_MAP_PHYSMEM pm = Marshal.PtrToStructure((System.IntPtr)pb); - if (pm.dwVersion != vmmi.VMMDLL_MAP_PHYSMEM_VERSION) { return new MAP_PHYSMEMENTRY[0]; } - MAP_PHYSMEMENTRY[] m = new MAP_PHYSMEMENTRY[pm.cMap]; - for (int i = 0; i < pm.cMap; i++) - { - vmmi.VMMDLL_MAP_PHYSMEMENTRY n = Marshal.PtrToStructure((System.IntPtr)(pb + cbMAP + i * cbENTRY)); - MAP_PHYSMEMENTRY e; - e.pa = n.pa; - e.cb = n.cb; - m[i] = e; - } - return m; + vmmi.VMMDLL_MAP_PHYSMEMENTRY n = Marshal.PtrToStructure((System.IntPtr)(pMap.ToInt64() + cbMAP + i * cbENTRY)); + MAP_PHYSMEMENTRY e; + e.pa = n.pa; + e.cb = n.cb; + m[i] = e; } + fail: + vmmi.VMMDLL_MemFree((byte*)pMap.ToPointer()); + return m; } - - public static unsafe MAP_POOLENTRY[] Map_GetPool() + public unsafe MAP_POOLENTRY[] Map_GetPool() { byte[] tag = { 0, 0, 0, 0}; IntPtr pN = IntPtr.Zero; int cbMAP = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_POOL)); int cbENTRY = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_POOLENTRY)); - if (!vmmi.VMMDLL_Map_GetPoolEx(out pN, 0)) { return new MAP_POOLENTRY[0]; } + if (!vmmi.VMMDLL_Map_GetPool(hVMM, out pN, 0)) { return new MAP_POOLENTRY[0]; } vmmi.VMMDLL_MAP_POOL nM = Marshal.PtrToStructure(pN); if (nM.dwVersion != vmmi.VMMDLL_MAP_POOL_VERSION) { vmmi.VMMDLL_MemFree((byte*)pN.ToPointer()); @@ -1712,78 +1691,69 @@ namespace vmmsharp return eM; } - - public static unsafe MAP_USERENTRY[] Map_GetUsers() + public unsafe MAP_USERENTRY[] Map_GetUsers() { - bool result; - uint cb = 0; int cbMAP = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_USER)); int cbENTRY = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_USERENTRY)); - result = vmmi.VMMDLL_Map_GetUsers(null, ref cb); - if (!result || (cb == 0)) { return new MAP_USERENTRY[0]; } - fixed (byte* pb = new byte[cb]) + IntPtr pMap = IntPtr.Zero; + MAP_USERENTRY[] m = new MAP_USERENTRY[0]; + if (!vmmi.VMMDLL_Map_GetUsers(hVMM, out pMap)) { goto fail; } + vmmi.VMMDLL_MAP_USER nM = Marshal.PtrToStructure(pMap); + if (nM.dwVersion != vmmi.VMMDLL_MAP_USER_VERSION) { goto fail; } + m = new MAP_USERENTRY[nM.cMap]; + for (int i = 0; i < nM.cMap; i++) { - result = vmmi.VMMDLL_Map_GetUsers(pb, ref cb); - if (!result) { return new MAP_USERENTRY[0]; } - vmmi.VMMDLL_MAP_USER pm = Marshal.PtrToStructure((System.IntPtr)pb); - if (pm.dwVersion != vmmi.VMMDLL_MAP_USER_VERSION) { return new MAP_USERENTRY[0]; } - MAP_USERENTRY[] m = new MAP_USERENTRY[pm.cMap]; - for (int i = 0; i < pm.cMap; i++) - { - vmmi.VMMDLL_MAP_USERENTRY n = Marshal.PtrToStructure((System.IntPtr)(pb + cbMAP + i * cbENTRY)); - MAP_USERENTRY e; - e.szSID = n.wszSID; - e.wszText = n.wszText; - e.vaRegHive = n.vaRegHive; - m[i] = e; - } - return m; + vmmi.VMMDLL_MAP_USERENTRY n = Marshal.PtrToStructure((System.IntPtr)(pMap.ToInt64() + cbMAP + i * cbENTRY)); + MAP_USERENTRY e; + e.szSID = n.wszSID; + e.wszText = n.wszText; + e.vaRegHive = n.vaRegHive; + m[i] = e; } + fail: + vmmi.VMMDLL_MemFree((byte*)pMap.ToPointer()); + return m; } - public static unsafe MAP_SERVICEENTRY[] Map_GetServices() + public unsafe MAP_SERVICEENTRY[] Map_GetServices() { - bool result; - uint cb = 0; int cbMAP = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_SERVICE)); int cbENTRY = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_SERVICEENTRY)); - result = vmmi.VMMDLL_Map_GetServices(null, ref cb); - if (!result || (cb == 0)) { return new MAP_SERVICEENTRY[0]; } - fixed (byte* pb = new byte[cb]) + IntPtr pMap = IntPtr.Zero; + MAP_SERVICEENTRY[] m = new MAP_SERVICEENTRY[0]; + if (!vmmi.VMMDLL_Map_GetServices(hVMM, out pMap)) { goto fail; } + vmmi.VMMDLL_MAP_SERVICE nM = Marshal.PtrToStructure(pMap); + if (nM.dwVersion != vmmi.VMMDLL_MAP_SERVICE_VERSION) { goto fail; } + m = new MAP_SERVICEENTRY[nM.cMap]; + for (int i = 0; i < nM.cMap; i++) { - result = vmmi.VMMDLL_Map_GetServices(pb, ref cb); - if (!result) { return new MAP_SERVICEENTRY[0]; } - vmmi.VMMDLL_MAP_SERVICE pm = Marshal.PtrToStructure((System.IntPtr)pb); - if (pm.dwVersion != vmmi.VMMDLL_MAP_SERVICE_VERSION) { return new MAP_SERVICEENTRY[0]; } - MAP_SERVICEENTRY[] m = new MAP_SERVICEENTRY[pm.cMap]; - for (int i = 0; i < pm.cMap; i++) - { - vmmi.VMMDLL_MAP_SERVICEENTRY n = Marshal.PtrToStructure((System.IntPtr)(pb + cbMAP + i * cbENTRY)); - MAP_SERVICEENTRY e; - e.vaObj = n.vaObj; - e.dwPID = n.dwPID; - e.dwOrdinal = n.dwOrdinal; - e.wszServiceName = n.wszServiceName; - e.wszDisplayName = n.wszDisplayName; - e.wszPath = n.wszPath; - e.wszUserTp = n.wszUserTp; - e.wszUserAcct = n.wszUserAcct; - e.wszImagePath = n.wszImagePath; - e.dwStartType = n.dwStartType; - e.dwServiceType = n.dwServiceType; - e.dwCurrentState = n.dwCurrentState; - e.dwControlsAccepted = n.dwControlsAccepted; - e.dwWin32ExitCode = n.dwWin32ExitCode; - e.dwServiceSpecificExitCode = n.dwServiceSpecificExitCode; - e.dwCheckPoint = n.dwCheckPoint; - e.dwWaitHint = n.dwWaitHint; - m[i] = e; - } - return m; + vmmi.VMMDLL_MAP_SERVICEENTRY n = Marshal.PtrToStructure((System.IntPtr)(pMap.ToInt64() + cbMAP + i * cbENTRY)); + MAP_SERVICEENTRY e; + e.vaObj = n.vaObj; + e.dwPID = n.dwPID; + e.dwOrdinal = n.dwOrdinal; + e.wszServiceName = n.wszServiceName; + e.wszDisplayName = n.wszDisplayName; + e.wszPath = n.wszPath; + e.wszUserTp = n.wszUserTp; + e.wszUserAcct = n.wszUserAcct; + e.wszImagePath = n.wszImagePath; + e.dwStartType = n.dwStartType; + e.dwServiceType = n.dwServiceType; + e.dwCurrentState = n.dwCurrentState; + e.dwControlsAccepted = n.dwControlsAccepted; + e.dwWin32ExitCode = n.dwWin32ExitCode; + e.dwServiceSpecificExitCode = n.dwServiceSpecificExitCode; + e.dwCheckPoint = n.dwCheckPoint; + e.dwWaitHint = n.dwWaitHint; + m[i] = e; } + fail: + vmmi.VMMDLL_MemFree((byte*)pMap.ToPointer()); + return m; } - public static unsafe MAP_PFNENTRY[] Map_GetPfn(params uint[] pfns) + public unsafe MAP_PFNENTRY[] Map_GetPfn(params uint[] pfns) { bool result; uint cbPfns; @@ -1798,8 +1768,8 @@ namespace vmmsharp fixed (byte* pb = new byte[cbPfns]) { result = - vmmi.VMMDLL_Map_GetPfn(pbPfns, (uint)pfns.Length, null, ref cbPfns) && - vmmi.VMMDLL_Map_GetPfn(pbPfns, (uint)pfns.Length, pb, ref cbPfns); + vmmi.VMMDLL_Map_GetPfn(hVMM, pbPfns, (uint)pfns.Length, null, ref cbPfns) && + vmmi.VMMDLL_Map_GetPfn(hVMM, pbPfns, (uint)pfns.Length, pb, ref cbPfns); if (!result) { return new MAP_PFNENTRY[0]; } vmmi.VMMDLL_MAP_PFN pm = Marshal.PtrToStructure((System.IntPtr)pb); if (pm.dwVersion != vmmi.VMMDLL_MAP_PFN_VERSION) { return new MAP_PFNENTRY[0]; } @@ -1866,42 +1836,43 @@ namespace vmmsharp public List ValueList; } - public static unsafe REGISTRY_HIVE_INFORMATION[] RegHiveList() + public unsafe REGISTRY_HIVE_INFORMATION[] RegHiveList() { bool result; uint cHives; int cbENTRY = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_REGISTRY_HIVE_INFORMATION)); - result = vmmi.VMMDLL_WinReg_HiveList(null, 0, out cHives); + result = vmmi.VMMDLL_WinReg_HiveList(hVMM, null, 0, out cHives); if (!result || (cHives == 0)) { return new REGISTRY_HIVE_INFORMATION[0]; } fixed (byte* pb = new byte[cHives * cbENTRY]) { - result = vmmi.VMMDLL_WinReg_HiveList(pb, cHives, out cHives); + result = vmmi.VMMDLL_WinReg_HiveList(hVMM, pb, cHives, out cHives); if (!result) { return new REGISTRY_HIVE_INFORMATION[0]; } REGISTRY_HIVE_INFORMATION[] m = new REGISTRY_HIVE_INFORMATION[cHives]; for (int i = 0; i < cHives; i++) { vmmi.VMMDLL_REGISTRY_HIVE_INFORMATION n = Marshal.PtrToStructure((System.IntPtr)(pb + i * cbENTRY)); REGISTRY_HIVE_INFORMATION e; + if(n.wVersion != vmmi.VMMDLL_REGISTRY_HIVE_INFORMATION_VERSION) { return new REGISTRY_HIVE_INFORMATION[0]; } e.vaCMHIVE = n.vaCMHIVE; e.vaHBASE_BLOCK = n.vaHBASE_BLOCK; e.cbLength = n.cbLength; - e.szName = System.Text.Encoding.UTF8.GetString(n.szName); + e.szName = System.Text.Encoding.UTF8.GetString(n.uszName); e.szName = e.szName.Substring(0, e.szName.IndexOf((char)0)); - e.szNameShort = n.wszNameShort; - e.szHiveRootPath = n.wszHiveRootPath; + e.szNameShort = System.Text.Encoding.UTF8.GetString(n.uszNameShort); + e.szHiveRootPath = System.Text.Encoding.UTF8.GetString(n.uszHiveRootPath); m[i] = e; } return m; } } - public static unsafe byte[] RegHiveRead(ulong vaCMHIVE, uint ra, uint cb, uint flags = 0) + public unsafe byte[] RegHiveRead(ulong vaCMHIVE, uint ra, uint cb, uint flags = 0) { uint cbRead; byte[] data = new byte[cb]; fixed (byte* pb = data) { - if(!vmmi.VMMDLL_WinReg_HiveReadEx(vaCMHIVE, ra, pb, cb, out cbRead, flags)) + if(!vmmi.VMMDLL_WinReg_HiveReadEx(hVMM, vaCMHIVE, ra, pb, cb, out cbRead, flags)) { return null; } @@ -1914,15 +1885,15 @@ namespace vmmsharp } - public static unsafe bool RegHiveWrite(ulong vaCMHIVE, uint ra, byte[] data) + public unsafe bool RegHiveWrite(ulong vaCMHIVE, uint ra, byte[] data) { fixed (byte* pb = data) { - return vmmi.VMMDLL_WinReg_HiveWrite(vaCMHIVE, ra, pb, (uint)data.Length); + return vmmi.VMMDLL_WinReg_HiveWrite(hVMM, vaCMHIVE, ra, pb, (uint)data.Length); } } - public static unsafe REGISTRY_ENUM RegEnum(string wszFullPathKey) + public unsafe REGISTRY_ENUM RegEnum(string wszFullPathKey) { uint i, cchName, lpType, cbData = 0; ulong ftLastWriteTime; @@ -1934,7 +1905,7 @@ namespace vmmsharp { i = 0; cchName = 0x800; - while (vmmi.VMMDLL_WinReg_EnumKeyExW(wszFullPathKey, i, pb, ref cchName, out ftLastWriteTime)) + while (vmmi.VMMDLL_WinReg_EnumKeyExW(hVMM, wszFullPathKey, i, pb, ref cchName, out ftLastWriteTime)) { REGISTRY_KEY_ENUM e = new REGISTRY_KEY_ENUM(); e.ftLastWriteTime = ftLastWriteTime; @@ -1945,7 +1916,7 @@ namespace vmmsharp } i = 0; cchName = 0x800; - while (vmmi.VMMDLL_WinReg_EnumValueW(wszFullPathKey, i, pb, ref cchName, out lpType, null, ref cbData)) + while (vmmi.VMMDLL_WinReg_EnumValueW(hVMM, wszFullPathKey, i, pb, ref cchName, out lpType, null, ref cbData)) { REGISTRY_VALUE_ENUM e = new REGISTRY_VALUE_ENUM(); e.type = lpType; @@ -1959,11 +1930,11 @@ namespace vmmsharp return re; } - public static unsafe byte[] RegValueRead(string wszFullPathKeyValue, out uint tp) + public unsafe byte[] RegValueRead(string wszFullPathKeyValue, out uint tp) { bool result; uint cb = 0; - result = vmmi.VMMDLL_WinReg_QueryValueExW(wszFullPathKeyValue, out tp, null, ref cb); + result = vmmi.VMMDLL_WinReg_QueryValueExW(hVMM, wszFullPathKeyValue, out tp, null, ref cb); if(!result) { return null; @@ -1971,12 +1942,98 @@ namespace vmmsharp byte[] data = new byte[cb]; fixed (byte* pb = data) { - result = vmmi.VMMDLL_WinReg_QueryValueExW(wszFullPathKeyValue, out tp, pb, ref cb); + result = vmmi.VMMDLL_WinReg_QueryValueExW(hVMM, wszFullPathKeyValue, out tp, pb, ref cb); return result ? data : null; } } } + public class VmmScatter : IDisposable + { + //--------------------------------------------------------------------- + // MEMORY NEW SCATTER READ/WRITE FUNCTIONALITY BELOW: + //--------------------------------------------------------------------- + bool disposed = false; + IntPtr hS = IntPtr.Zero; + + private VmmScatter() + { + ; + } + + internal VmmScatter(IntPtr hS) + { + this.hS = hS; + } + + ~VmmScatter() + { + Dispose(disposing: false); + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!this.disposed) + { + vmmi.VMMDLL_Scatter_CloseHandle(hS); + hS = IntPtr.Zero; + disposed = true; + } + } + + public void Close() + { + Dispose(disposing: true); + } + + public unsafe byte[] Read(ulong qwA, uint cb) + { + uint cbRead; + byte[] data = new byte[cb]; + fixed (byte* pb = data) + { + if (!vmmi.VMMDLL_Scatter_Read(hS, qwA, cb, pb, out cbRead)) + { + return null; + } + } + if (cbRead != cb) + { + Array.Resize(ref data, (int)cbRead); + } + return data; + } + + public bool Prepare(ulong qwA, uint cb) + { + return vmmi.VMMDLL_Scatter_Prepare(hS, qwA, cb); + } + + public unsafe bool PrepareWrite(ulong qwA, byte[] data) + { + fixed (byte* pb = data) + { + return vmmi.VMMDLL_Scatter_PrepareWrite(hS, qwA, pb, (uint)data.Length); + } + } + + public bool Execute() + { + return vmmi.VMMDLL_Scatter_Execute(hS); + } + + public bool Clear(uint dwPID, uint flags) + { + return vmmi.VMMDLL_Scatter_Clear(hS, dwPID, flags); + } + } + internal static class lci @@ -2052,22 +2109,37 @@ namespace vmmsharp internal static uint VMMDLL_MAP_PFN_VERSION = 1; internal static uint VMMDLL_MAP_SERVICE_VERSION = 3; internal static uint VMMDLL_MEM_SEARCH_VERSION = 0xfe3e0002; + internal static uint VMMDLL_REGISTRY_HIVE_INFORMATION_VERSION = 4; - [DllImport("vmm.dll", EntryPoint = "VMMDLL_Initialize")] - internal static extern bool VMMDLL_Initialize( - int argc, - string[] argv); - [DllImport("vmm.dll", EntryPoint = "VMMDLL_InitializeEx")] - internal static extern bool VMMDLL_InitializeEx( + internal static extern IntPtr VMMDLL_InitializeEx( int argc, string[] argv, out IntPtr ppLcErrorInfo); + [DllImport("vmm.dll", EntryPoint = "VMMDLL_CloseAll")] + public static extern void VMMDLL_CloseAll(); + + [DllImport("vmm.dll", EntryPoint = "VMMDLL_Close")] + public static extern void VMMDLL_Close( + IntPtr hVMM); + + [DllImport("vmm.dll", EntryPoint = "VMMDLL_ConfigGet")] + public static extern bool VMMDLL_ConfigGet( + IntPtr hVMM, + ulong fOption, + out ulong pqwValue); + + [DllImport("vmm.dll", EntryPoint = "VMMDLL_ConfigSet")] + public static extern bool VMMDLL_ConfigSet( + IntPtr hVMM, + ulong fOption, + ulong qwValue); + [DllImport("vmm.dll", EntryPoint = "VMMDLL_MemFree")] - internal static extern unsafe bool VMMDLL_MemFree( + internal static extern unsafe void VMMDLL_MemFree( byte* pvMem); @@ -2089,11 +2161,13 @@ namespace vmmsharp [DllImport("vmm.dll", EntryPoint = "VMMDLL_VfsListU")] internal static extern unsafe bool VMMDLL_VfsList( + IntPtr hVMM, [MarshalAs(UnmanagedType.LPUTF8Str)] string wcsPath, ref VMMDLL_VFS_FILELIST pFileList); [DllImport("vmm.dll", EntryPoint = "VMMDLL_VfsReadU")] internal static extern unsafe uint VMMDLL_VfsRead( + IntPtr hVMM, [MarshalAs(UnmanagedType.LPUTF8Str)] string wcsFileName, byte* pb, uint cb, @@ -2102,6 +2176,7 @@ namespace vmmsharp [DllImport("vmm.dll", EntryPoint = "VMMDLL_VfsWriteU")] internal static extern unsafe uint VMMDLL_VfsWrite( + IntPtr hVMM, [MarshalAs(UnmanagedType.LPUTF8Str)] string wcsFileName, byte* pb, uint cb, @@ -2110,10 +2185,18 @@ namespace vmmsharp + // PLUGIN FUNCTIONALITY BELOW: + + [DllImport("vmm.dll", EntryPoint = "VMMDLL_InitializePlugins")] + public static extern bool VMMDLL_InitializePlugins(IntPtr hVMM); + + + // MEMORY READ/WRITE FUNCTIONALITY BELOW: [DllImport("vmm.dll", EntryPoint = "VMMDLL_MemReadScatter")] internal static extern unsafe uint VMMDLL_MemReadScatter( + IntPtr hVMM, uint dwPID, IntPtr ppMEMs, uint cpMEMs, @@ -2121,6 +2204,7 @@ namespace vmmsharp [DllImport("vmm.dll", EntryPoint = "VMMDLL_MemReadEx")] internal static extern unsafe bool VMMDLL_MemReadEx( + IntPtr hVMM, uint dwPID, ulong qwA, byte* pb, @@ -2130,23 +2214,34 @@ namespace vmmsharp [DllImport("vmm.dll", EntryPoint = "VMMDLL_MemPrefetchPages")] internal static extern unsafe bool VMMDLL_MemPrefetchPages( + IntPtr hVMM, uint dwPID, byte* pPrefetchAddresses, uint cPrefetchAddresses); [DllImport("vmm.dll", EntryPoint = "VMMDLL_MemWrite")] internal static extern unsafe bool VMMDLL_MemWrite( + IntPtr hVMM, uint dwPID, ulong qwA, byte* pb, uint cb); + [DllImport("vmm.dll", EntryPoint = "VMMDLL_MemVirt2Phys")] + public static extern bool VMMDLL_MemVirt2Phys( + IntPtr hVMM, + uint dwPID, + ulong qwVA, + out ulong pqwPA + ); + // MEMORY NEW SCATTER READ/WRITE FUNCTIONALITY BELOW: [DllImport("vmm.dll", EntryPoint = "VMMDLL_Scatter_Initialize")] internal static extern unsafe IntPtr VMMDLL_Scatter_Initialize( + IntPtr hVMM, uint dwPID, uint flags); @@ -2156,7 +2251,18 @@ namespace vmmsharp ulong va, uint cb); + [DllImport("vmm.dll", EntryPoint = "VMMDLL_Scatter_PrepareWrite")] + internal static extern unsafe bool VMMDLL_Scatter_PrepareWrite( + IntPtr hS, + ulong va, + byte* pb, + uint cb); + [DllImport("vmm.dll", EntryPoint = "VMMDLL_Scatter_ExecuteRead")] + internal static extern unsafe bool VMMDLL_Scatter_ExecuteRead( + IntPtr hS); + + [DllImport("vmm.dll", EntryPoint = "VMMDLL_Scatter_Execute")] internal static extern unsafe bool VMMDLL_Scatter_Execute( IntPtr hS); @@ -2168,6 +2274,9 @@ namespace vmmsharp byte* pb, out uint pcbRead); + [DllImport("vmm.dll", EntryPoint = "VMMDLL_Scatter_Clear")] + public static extern bool SVMMDLL_Scatter_Clear(IntPtr hS, uint dwPID, uint flags); + [DllImport("vmm.dll", EntryPoint = "VMMDLL_Scatter_Clear")] internal static extern unsafe bool VMMDLL_Scatter_Clear( IntPtr hS, @@ -2183,7 +2292,16 @@ namespace vmmsharp // PROCESS FUNCTIONALITY BELOW: [DllImport("vmm.dll", EntryPoint = "VMMDLL_PidList")] - internal static extern unsafe bool VMMDLL_PidList(byte* pPIDs, ref ulong pcPIDs); + internal static extern unsafe bool VMMDLL_PidList(IntPtr hVMM, byte* pPIDs, ref ulong pcPIDs); + + [DllImport("vmm.dll", EntryPoint = "VMMDLL_PidGetFromName")] + public static extern bool VMMDLL_PidGetFromName(IntPtr hVMM, [MarshalAs(UnmanagedType.LPStr)] string szProcName, out uint pdwPID); + + [DllImport("vmm.dll", EntryPoint = "VMMDLL_ProcessGetProcAddressW")] + public static extern ulong VMMDLL_ProcessGetProcAddress(IntPtr hVMM, uint pid, [MarshalAs(UnmanagedType.LPWStr)] string wszModuleName, [MarshalAs(UnmanagedType.LPStr)] string szFunctionName); + + [DllImport("vmm.dll", EntryPoint = "VMMDLL_ProcessGetModuleBaseW")] + public static extern ulong VMMDLL_ProcessGetModuleBase(IntPtr hVMM, uint pid, [MarshalAs(UnmanagedType.LPWStr)] string wszModuleName); internal static ulong VMMDLL_PROCESS_INFORMATION_MAGIC = 0xc0ffee663df9301e; internal static ushort VMMDLL_PROCESS_INFORMATION_VERSION = 7; @@ -2217,12 +2335,14 @@ namespace vmmsharp [DllImport("vmm.dll", EntryPoint = "VMMDLL_ProcessGetInformation")] internal static extern unsafe bool VMMDLL_ProcessGetInformation( + IntPtr hVMM, uint dwPID, byte* pProcessInformation, ref ulong pcbProcessInformation); [DllImport("vmm.dll", EntryPoint = "VMMDLL_ProcessGetInformationString")] internal static extern unsafe byte* VMMDLL_ProcessGetInformationString( + IntPtr hVMM, uint dwPID, uint fOptionString); @@ -2250,14 +2370,14 @@ namespace vmmsharp [DllImport("vmm.dll", EntryPoint = "VMMDLL_ProcessGetDirectoriesW")] internal static extern unsafe bool VMMDLL_ProcessGetDirectories( + IntPtr hVMM, uint dwPID, [MarshalAs(UnmanagedType.LPWStr)] string wszModule, - byte* pData, - uint cData, - out uint pcData); + byte* pData); [DllImport("vmm.dll", EntryPoint = "VMMDLL_ProcessGetSectionsW")] internal static extern unsafe bool VMMDLL_ProcessGetSections( + IntPtr hVMM, uint dwPID, [MarshalAs(UnmanagedType.LPWStr)] string wszModule, byte* pData, @@ -2270,17 +2390,42 @@ namespace vmmsharp [DllImport("vmm.dll", EntryPoint = "VMMDLL_PdbLoad")] internal static extern unsafe bool VMMDLL_PdbLoad( + IntPtr hVMM, uint dwPID, ulong vaModuleBase, byte* pModuleMapEntry); [DllImport("vmm.dll", EntryPoint = "VMMDLL_PdbSymbolName")] internal static extern unsafe bool VMMDLL_PdbSymbolName( + IntPtr hVMM, [MarshalAs(UnmanagedType.LPStr)] string szModule, ulong cbSymbolAddressOrOffset, byte* szSymbolName, out uint pdwSymbolDisplacement); + [DllImport("vmm.dll", EntryPoint = "VMMDLL_PdbSymbolAddress")] + public static extern bool VMMDLL_PdbSymbolAddress( + IntPtr hVMM, + [MarshalAs(UnmanagedType.LPStr)] string szModule, + [MarshalAs(UnmanagedType.LPStr)] string szSymbolName, + out ulong pvaSymbolAddress); + + [DllImport("vmm.dll", EntryPoint = "VMMDLL_PdbTypeSize")] + public static extern bool VMMDLL_PdbTypeSize( + IntPtr hVMM, + [MarshalAs(UnmanagedType.LPStr)] string szModule, + [MarshalAs(UnmanagedType.LPStr)] string szTypeName, + out uint pcbTypeSize); + + [DllImport("vmm.dll", EntryPoint = "VMMDLL_PdbTypeChildOffset")] + public static extern bool VMMDLL_PdbTypeChildOffset( + IntPtr hVMM, + [MarshalAs(UnmanagedType.LPStr)] string szModule, + [MarshalAs(UnmanagedType.LPStr)] string szTypeName, + [MarshalAs(UnmanagedType.LPStr)] string wszTypeChildName, + out uint pcbTypeChildOffset); + + // VMMDLL_Map_GetPte @@ -2310,10 +2455,10 @@ namespace vmmsharp [DllImport("vmm.dll", EntryPoint = "VMMDLL_Map_GetPteW")] internal static extern unsafe bool VMMDLL_Map_GetPte( + IntPtr hVMM, uint dwPid, - byte* pPteMap, - ref uint pcbPteMap, - bool fIdentifyModules); + bool fIdentifyModules, + out IntPtr ppPteMap); @@ -2353,10 +2498,10 @@ namespace vmmsharp [DllImport("vmm.dll", EntryPoint = "VMMDLL_Map_GetVadW")] internal static extern unsafe bool VMMDLL_Map_GetVad( + IntPtr hVMM, uint dwPid, - byte* pVadMap, - ref uint pcbVadMap, - bool fIdentifyModules); + bool fIdentifyModules, + out IntPtr ppVadMap); @@ -2387,11 +2532,11 @@ namespace vmmsharp [DllImport("vmm.dll", EntryPoint = "VMMDLL_Map_GetVadEx")] internal static extern unsafe bool VMMDLL_Map_GetVadEx( + IntPtr hVMM, uint dwPid, - byte* pVadMap, - ref uint pcbVadMap, uint oPage, - uint cPage); + uint cPage, + out IntPtr ppVadExMap); @@ -2427,16 +2572,19 @@ namespace vmmsharp } [DllImport("vmm.dll", EntryPoint = "VMMDLL_Map_GetModuleW")] - internal static extern unsafe bool VMMDLL_Map_GetModule(uint dwPid, byte* pModuleMap, ref uint pcbModuleMap); + internal static extern unsafe bool VMMDLL_Map_GetModule( + IntPtr hVMM, + uint dwPid, + out IntPtr ppModuleMap); // VMMDLL_Map_GetModuleFromName [DllImport("vmm.dll", EntryPoint = "VMMDLL_Map_GetModuleFromNameW")] internal static extern unsafe bool VMMDLL_Map_GetModuleFromName( + IntPtr hVMM, uint dwPID, [MarshalAs(UnmanagedType.LPWStr)] string wszModuleName, - byte* pModuleMapEntry, - ref uint pcbModuleMapEntry); + out IntPtr ppModuleMapEntry); @@ -2466,7 +2614,10 @@ namespace vmmsharp } [DllImport("vmm.dll", EntryPoint = "VMMDLL_Map_GetUnloadedModuleW")] - internal static extern unsafe bool VMMDLL_Map_GetUnloadedModule(uint dwPid, byte* pModuleMap, ref uint pcbModuleMap); + internal static extern unsafe bool VMMDLL_Map_GetUnloadedModule( + IntPtr hVMM, + uint dwPid, + out IntPtr ppModuleMap); @@ -2500,10 +2651,10 @@ namespace vmmsharp [DllImport("vmm.dll", EntryPoint = "VMMDLL_Map_GetEATW")] internal static extern unsafe bool VMMDLL_Map_GetEAT( + IntPtr hVMM, uint dwPid, [MarshalAs(UnmanagedType.LPWStr)] string wszModuleName, - byte* pEatMap, - ref uint pcbEatMap); + out IntPtr ppEatMap); @@ -2538,10 +2689,10 @@ namespace vmmsharp [DllImport("vmm.dll", EntryPoint = "VMMDLL_Map_GetIATW")] internal static extern unsafe bool VMMDLL_Map_GetIAT( + IntPtr hVMM, uint dwPid, [MarshalAs(UnmanagedType.LPWStr)] string wszModuleName, - byte* pIatMap, - ref uint pcbIatMap); + out IntPtr ppIatMap); @@ -2576,8 +2727,9 @@ namespace vmmsharp internal uint cMap; } - [DllImport("vmm.dll", EntryPoint = "VMMDLL_Map_GetHeapEx")] - internal static extern unsafe bool VMMDLL_Map_GetHeapEx( + [DllImport("vmm.dll", EntryPoint = "VMMDLL_Map_GetHeap")] + internal static extern unsafe bool VMMDLL_Map_GetHeap( + IntPtr hVMM, uint dwPid, out IntPtr ppHeapMap); @@ -2603,8 +2755,9 @@ namespace vmmsharp internal uint cMap; } - [DllImport("vmm.dll", EntryPoint = "VMMDLL_Map_GetHeapAllocEx")] - internal static extern unsafe bool VMMDLL_Map_GetHeapAllocEx( + [DllImport("vmm.dll", EntryPoint = "VMMDLL_Map_GetHeapAlloc")] + internal static extern unsafe bool VMMDLL_Map_GetHeapAlloc( + IntPtr hVMM, uint dwPid, ulong qwHeapNumOrAddress, out IntPtr ppHeapAllocMap); @@ -2654,9 +2807,9 @@ namespace vmmsharp [DllImport("vmm.dll", EntryPoint = "VMMDLL_Map_GetThread")] internal static extern unsafe bool VMMDLL_Map_GetThread( + IntPtr hVMM, uint dwPid, - byte* pThreadMap, - ref uint pcbThreadMap); + out IntPtr ppThreadMap); @@ -2692,9 +2845,9 @@ namespace vmmsharp [DllImport("vmm.dll", EntryPoint = "VMMDLL_Map_GetHandleW")] internal static extern unsafe bool VMMDLL_Map_GetHandle( + IntPtr hVMM, uint dwPid, - byte* pHandleMap, - ref uint pcbHandleMap); + out IntPtr ppHandleMap); @@ -2740,8 +2893,8 @@ namespace vmmsharp [DllImport("vmm.dll", EntryPoint = "VMMDLL_Map_GetNetW")] internal static extern unsafe bool VMMDLL_Map_GetNet( - byte* pNetMap, - ref uint pcbNetMap); + IntPtr hVMM, + out IntPtr ppNetMap); @@ -2765,8 +2918,8 @@ namespace vmmsharp [DllImport("vmm.dll", EntryPoint = "VMMDLL_Map_GetPhysMem")] internal static extern unsafe bool VMMDLL_Map_GetPhysMem( - byte* pNetMap, - ref uint pcbNetMap); + IntPtr hVMM, + out IntPtr ppPhysMemMap); @@ -2797,8 +2950,9 @@ namespace vmmsharp internal uint cMap; } - [DllImport("vmm.dll", EntryPoint = "VMMDLL_Map_GetPoolEx")] - internal static extern unsafe bool VMMDLL_Map_GetPoolEx( + [DllImport("vmm.dll", EntryPoint = "VMMDLL_Map_GetPool")] + internal static extern unsafe bool VMMDLL_Map_GetPool( + IntPtr hVMM, out IntPtr ppHeapAllocMap, uint flags); @@ -2828,8 +2982,8 @@ namespace vmmsharp [DllImport("vmm.dll", EntryPoint = "VMMDLL_Map_GetUsersW")] internal static extern unsafe bool VMMDLL_Map_GetUsers( - byte* pbUserMap, - ref uint pcbUserMap); + IntPtr hVMM, + out IntPtr ppUserMap); @@ -2873,8 +3027,8 @@ namespace vmmsharp [DllImport("vmm.dll", EntryPoint = "VMMDLL_Map_GetServicesW")] internal static extern unsafe bool VMMDLL_Map_GetServices( - byte* pbServiceMap, - ref uint pcbServiceMap); + IntPtr hVMM, + out IntPtr ppServiceMap); @@ -2905,6 +3059,7 @@ namespace vmmsharp [DllImport("vmm.dll", EntryPoint = "VMMDLL_Map_GetPfn")] internal static extern unsafe bool VMMDLL_Map_GetPfn( + IntPtr hVMM, byte* pPfns, uint cPfns, byte* pPfnMap, @@ -2914,30 +3069,32 @@ namespace vmmsharp // REGISTRY FUNCTIONALITY BELOW: - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet = CharSet.Unicode)] + [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] internal struct VMMDLL_REGISTRY_HIVE_INFORMATION { internal ulong magic; internal ushort wVersion; internal ushort wSize; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x14)] internal byte[] _FutureReserved1; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x34)] internal byte[] _FutureReserved1; internal ulong vaCMHIVE; internal ulong vaHBASE_BLOCK; internal uint cbLength; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] internal byte[] szName; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 33)] internal string wszNameShort; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] internal string wszHiveRootPath; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] internal byte[] uszName; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 33)] internal byte[] uszNameShort; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 260)] internal byte[] uszHiveRootPath; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x10)] internal ulong[] _FutureReserved; } [DllImport("vmm.dll", EntryPoint = "VMMDLL_WinReg_HiveList")] internal static extern unsafe bool VMMDLL_WinReg_HiveList( + IntPtr hVMM, byte* pHives, uint cHives, out uint pcHives); [DllImport("vmm.dll", EntryPoint = "VMMDLL_WinReg_HiveReadEx")] internal static extern unsafe bool VMMDLL_WinReg_HiveReadEx( + IntPtr hVMM, ulong vaCMHive, uint ra, byte* pb, @@ -2947,6 +3104,7 @@ namespace vmmsharp [DllImport("vmm.dll", EntryPoint = "VMMDLL_WinReg_HiveWrite")] internal static extern unsafe bool VMMDLL_WinReg_HiveWrite( + IntPtr hVMM, ulong vaCMHive, uint ra, byte* pb, @@ -2954,6 +3112,7 @@ namespace vmmsharp [DllImport("vmm.dll", EntryPoint = "VMMDLL_WinReg_EnumKeyExW")] internal static extern unsafe bool VMMDLL_WinReg_EnumKeyExW( + IntPtr hVMM, [MarshalAs(UnmanagedType.LPWStr)] string wszFullPathKey, uint dwIndex, byte* lpName, @@ -2962,6 +3121,7 @@ namespace vmmsharp [DllImport("vmm.dll", EntryPoint = "VMMDLL_WinReg_EnumValueW")] internal static extern unsafe bool VMMDLL_WinReg_EnumValueW( + IntPtr hVMM, [MarshalAs(UnmanagedType.LPWStr)] string wszFullPathKey, uint dwIndex, byte* lpValueName, @@ -2972,6 +3132,7 @@ namespace vmmsharp [DllImport("vmm.dll", EntryPoint = "VMMDLL_WinReg_QueryValueExW")] internal static extern unsafe bool VMMDLL_WinReg_QueryValueExW( + IntPtr hVMM, [MarshalAs(UnmanagedType.LPWStr)] string wszFullPathKeyValue, out uint lpType, byte* lpData, @@ -3016,6 +3177,7 @@ namespace vmmsharp [DllImport("vmm.dll", EntryPoint = "VMMDLL_MemSearch")] internal static extern unsafe bool VMMDLL_MemSearch( + IntPtr hVMM, uint dwPID, ref VMMDLL_MEM_SEARCH_CONTEXT ctx, out IntPtr ppva,