Skip to content
This repository was archived by the owner on Feb 24, 2026. It is now read-only.

Commit eecde7d

Browse files
committed
Version 3.150 - Refactor VmmSearch to stateless API; add new native APIs
- Refactored VmmSearch from object/disposable to static/stateless API (breaking change); updated all usages and tests - Added VMMDLL_MemReadPage and VMMDLL_WinGetThunkInfoIATW native APIs - Introduced new SearchItem and SearchResult types for clarity and safety - Added MemReadPage, MemReadPagePooled, and WinGetThunkInfoIAT methods to Vmm
1 parent 14c4dc4 commit eecde7d

7 files changed

Lines changed: 324 additions & 320 deletions

File tree

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,13 @@ Install-Package VmmSharpEx
1010
This library is **Windows Only**, and only bundles/targets the Windows x64 native libraries.
1111

1212
## Changelog
13+
- Version 3.150
14+
- Added new APIs: VMMDLL_MemReadPage, VMMDLL_WinGetThunkInfoIATW
15+
- Refactor VmmSearch to a static/stateless API. Provides better resource cleanup guarantees than the former object-based model. **This is a breaking change.**
1316
- Version 3.140
14-
- Bump MemProcFS to 5.16.10 (fixes rare access violation in Scatter API)
17+
- Bump MemProcFS to 5.16.11 (fixes rare buffer overflow/access violation in Scatter API)
18+
- Improve finalizer safety
19+
- #nullable support
1520
- Version 3.130
1621
- Optimized lots of methods and implementations.
1722
- Some breaking changes with a few renames and changed Map_Get return values to return NULL on failure instead of an empty array.

src/VmmSharpEx/Extensions/VmmExtensions.cs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -243,20 +243,25 @@ public static ulong FindSignature(this Vmm vmm, uint pid, string signature, ulon
243243
skipBytes[i] = 0;
244244
}
245245
}
246-
using var vmmSearch = vmm.CreateSearch(
246+
var entries = new VmmSearch.SearchItem[]
247+
{
248+
new VmmSearch.SearchItem
249+
{
250+
Search = searchBytes,
251+
SkipMask = skipBytes
252+
}
253+
};
254+
var vmmSearch = vmm.MemSearch(
247255
pid: pid,
256+
searchItems: entries,
248257
addr_min: addrMin,
249258
addr_max: addrMax,
250259
cMaxResult: 1);
251-
vmmSearch.AddEntry(
252-
search: searchBytes,
253-
skipmask: skipBytes);
254-
var result = vmmSearch.GetResult();
255-
if (result.Results.Count == 0)
260+
if (vmmSearch.Results.Count == 0)
256261
{
257262
return 0;
258263
}
259-
return result.Results.First().Address;
264+
return vmmSearch.Results.First().Address;
260265
}
261266
}
262267
}

src/VmmSharpEx/Internal/Vmmi.cs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ internal static partial class Vmmi
4747
public const uint VMMDLL_MAP_VM_VERSION = 2;
4848
public const uint VMMDLL_MAP_PFN_VERSION = 1;
4949
public const uint VMMDLL_MAP_SERVICE_VERSION = 3;
50-
public const uint VMMDLL_MEM_SEARCH_VERSION = 0xfe3e0003;
5150
public const uint VMMDLL_REGISTRY_HIVE_INFORMATION_VERSION = 4;
5251

5352
public const uint VMMDLL_VFS_FILELIST_EXINFO_VERSION = 1;
@@ -1000,6 +999,14 @@ public static unsafe partial bool VMMDLL_MemReadEx(
1000999
out uint pcbReadOpt,
10011000
VmmFlags flags);
10021001

1002+
[LibraryImport("vmm.dll", EntryPoint = "VMMDLL_MemReadPage")]
1003+
[return: MarshalAs(UnmanagedType.Bool)]
1004+
public static unsafe partial bool VMMDLL_MemReadPage(
1005+
IntPtr hVMM,
1006+
uint dwPID,
1007+
ulong qwA,
1008+
byte* pbPage);
1009+
10031010
[LibraryImport("vmm.dll", EntryPoint = "VMMDLL_MemPrefetchPages")]
10041011
[return: MarshalAs(UnmanagedType.Bool)]
10051012
public static unsafe partial bool VMMDLL_MemPrefetchPages(
@@ -1458,6 +1465,8 @@ public static unsafe partial bool VMMDLL_Log(
14581465
[MarshalAs(UnmanagedType.LPStr)] string uszFormat,
14591466
[MarshalAs(UnmanagedType.LPUTF8Str)] string uszTextToLog);
14601467

1468+
// Misc
1469+
14611470
[LibraryImport("vmm.dll", EntryPoint = "VMMDLL_LogCallback")]
14621471
[return: MarshalAs(UnmanagedType.Bool)]
14631472
public static partial bool VMMDLL_LogCallback(
@@ -1472,5 +1481,16 @@ public static unsafe partial bool VMMDLL_MemCallback(
14721481
IntPtr ctxUser,
14731482
Vmm.VMMDLL_MEM_CALLBACK_PFN pfnCB);
14741483

1484+
[LibraryImport("vmm.dll", EntryPoint = "VMMDLL_WinGetThunkInfoIATW", StringMarshalling = StringMarshalling.Utf16)]
1485+
[return: MarshalAs(UnmanagedType.Bool)]
1486+
public static partial bool VMMDLL_WinGetThunkInfoIATW(
1487+
IntPtr hVMM,
1488+
uint dwPID,
1489+
[MarshalAs(UnmanagedType.LPWStr)] string wszModuleName,
1490+
[MarshalAs(UnmanagedType.LPStr)] string szImportModuleName,
1491+
[MarshalAs(UnmanagedType.LPStr)] string szImportFunctionName,
1492+
out Vmm.VMMDLL_WIN_THUNKINFO_IAT pThunkInfoIAT
1493+
);
1494+
14751495
#endregion
14761496
}

src/VmmSharpEx/Vmm.cs

Lines changed: 91 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@
1717

1818
using Collections.Pooled;
1919
using System.Buffers;
20+
using System.Net;
2021
using System.Runtime.CompilerServices;
2122
using System.Runtime.InteropServices;
2223
using System.Text;
2324
using VmmSharpEx.Internal;
2425
using VmmSharpEx.Options;
2526
using VmmSharpEx.Refresh;
2627
using VmmSharpEx.Scatter;
28+
using static System.Runtime.InteropServices.JavaScript.JSType;
2729

2830
namespace VmmSharpEx;
2931

@@ -582,6 +584,43 @@ public unsafe bool MemReadSpan<T>(uint pid, ulong va, Span<T> span, VmmFlags fla
582584
}
583585
}
584586

587+
/// <summary>
588+
/// Read a single 4096-byte page of memory.
589+
/// </summary>
590+
/// <param name="pid">PID of target process, (DWORD)-1 to read physical memory.</param>
591+
/// <param name="qwA">Page address to read from.</param>
592+
/// <returns>Byte array on success; otherwise null.</returns>
593+
public unsafe byte[]? MemReadPage(uint pid, ulong qwA)
594+
{
595+
var arr = new byte[0x1000];
596+
fixed (byte* pb = arr)
597+
{
598+
if (!Vmmi.VMMDLL_MemReadPage(_handle, pid, qwA, pb))
599+
return null;
600+
}
601+
return arr;
602+
}
603+
604+
/// <summary>
605+
/// Read a single 4096-byte page of memory (Pooled).
606+
/// </summary>
607+
/// <param name="pid">PID of target process, (DWORD)-1 to read physical memory.</param>
608+
/// <param name="qwA">Page address to read from.</param>
609+
/// <returns>Pooled array on success; otherwise null.</returns>
610+
public unsafe IMemoryOwner<byte>? MemReadPagePooled(uint pid, ulong qwA)
611+
{
612+
var pooled = new PooledMemory<byte>(0x1000);
613+
fixed (byte* pb = pooled.Memory.Span)
614+
{
615+
if (!Vmmi.VMMDLL_MemReadPage(_handle, pid, qwA, pb))
616+
{
617+
pooled.Dispose();
618+
return null;
619+
}
620+
}
621+
return pooled;
622+
}
623+
585624
/// <summary>
586625
/// Prefetch pages into the MemProcFS internal cache.
587626
/// </summary>
@@ -3489,20 +3528,6 @@ public bool MemCallback(VmmMemCallbackType type, IntPtr context, VMMDLL_MEM_CALL
34893528
return Vmmi.VMMDLL_MemCallback(_handle, type, context, pfnCB);
34903529
}
34913530

3492-
/// <summary>
3493-
/// Create a <see cref="VmmSearch"/> object for searching memory.
3494-
/// </summary>
3495-
/// <param name="pid">Process ID (PID) for this operation.</param>
3496-
/// <param name="addr_min">Minimum address to search (inclusive).</param>
3497-
/// <param name="addr_max">Maximum address to search (inclusive).</param>
3498-
/// <param name="cMaxResult">Maximum number of results to collect (0 = unlimited).</param>
3499-
/// <param name="readFlags">Optional read flags passed to the search engine.</param>
3500-
/// <returns>A configured <see cref="VmmSearch"/> instance.</returns>
3501-
public VmmSearch CreateSearch(uint pid, ulong addr_min = 0, ulong addr_max = ulong.MaxValue, uint cMaxResult = 0, uint readFlags = 0)
3502-
{
3503-
return new VmmSearch(this, pid, addr_min, addr_max, cMaxResult, readFlags);
3504-
}
3505-
35063531
/// <summary>
35073532
/// Throw an exception if memory writing is disabled.
35083533
/// </summary>
@@ -3516,6 +3541,58 @@ internal void ThrowIfMemWritesDisabled()
35163541
}
35173542
}
35183543

3544+
[StructLayout(LayoutKind.Sequential)]
3545+
public struct VMMDLL_WIN_THUNKINFO_IAT
3546+
{
3547+
private int _fValid; // WIN32 BOOL
3548+
public bool fValid
3549+
{
3550+
readonly get => _fValid != 0;
3551+
set => _fValid = value ? 1 : 0;
3552+
}
3553+
private int _f32; // WIN32 BOOL
3554+
/// <summary>
3555+
/// if TRUE fn is a 32-bit/4-byte entry, otherwise 64-bit/8-byte entry.
3556+
/// </summary>
3557+
public bool f32
3558+
{
3559+
readonly get => _f32 != 0;
3560+
set => _f32 = value ? 1 : 0;
3561+
}
3562+
/// <summary>
3563+
/// address of import address table 'thunk'.
3564+
/// </summary>
3565+
public ulong vaThunk;
3566+
/// <summary>
3567+
/// value if import address table 'thunk' == address of imported function.
3568+
/// </summary>
3569+
public ulong vaFunction;
3570+
/// <summary>
3571+
/// address of name string for imported module.
3572+
/// </summary>
3573+
public ulong vaNameModule;
3574+
/// <summary>
3575+
/// address of name string for imported function.
3576+
/// </summary>
3577+
public ulong vaNameFunction;
3578+
}
3579+
3580+
/// <summary>
3581+
/// Retrieve information about the import address table IAT thunk for an imported
3582+
/// function.This includes the virtual address of the IAT thunk which is useful
3583+
/// for hooking.
3584+
/// </summary>
3585+
/// <param name="dwPID"></param>
3586+
/// <param name="wszModuleName"></param>
3587+
/// <param name="szImportModuleName"></param>
3588+
/// <param name="szImportFunctionName"></param>
3589+
/// <param name="pThunkInfoIAT"></param>
3590+
/// <returns><see langword="true"/> if the call was successful, otherwise <see langword="false"/>.</returns>
3591+
public bool WinGetThunkInfoIAT(uint dwPID, string wszModuleName, string szImportModuleName, string szImportFunctionName, out VMMDLL_WIN_THUNKINFO_IAT pThunkInfoIAT)
3592+
{
3593+
return Vmmi.VMMDLL_WinGetThunkInfoIATW(_handle, dwPID, wszModuleName, szImportModuleName, szImportFunctionName, out pThunkInfoIAT);
3594+
}
3595+
35193596
#endregion // Utility functionality
35203597

35213598
#region Custom Refresh Functionality

0 commit comments

Comments
 (0)