From 34577de8264ca3f35360c304cf40dc5c2e51298c Mon Sep 17 00:00:00 2001
From: Youssef Ayman <62572632+ELJoOker2004@users.noreply.github.com>
Date: Wed, 3 Jun 2026 17:44:06 +0300
Subject: [PATCH 1/5] Add \Device\KsecDD emulation and mask 32-bit syscall
arguments
- Emulate \Device\KsecDD (RNG + memory encrypt/decrypt) so the bcrypt/CNG
DllMain succeeds during Windows PE process initialization.
- Mask ULONG syscall arguments that were read as 64-bit; some ntdll builds
leave garbage in the upper 32 bits, which broke handler argument checks.
---
.../OS/Windows/Devices/KsecDevice.cs | 89 +++++++++++++++++++
.../OS/Windows/Files/NtCreateFile.cs | 2 +-
.../OS/Windows/Files/NtCreateSection.cs | 2 +-
.../OS/Windows/Files/NtQueryDirectoryFile.cs | 4 +-
.../Emulation/OS/Windows/Misc/NtContinue.cs | 2 +-
.../OS/Windows/Misc/NtCreateEvent.cs | 2 +-
.../OS/Windows/Misc/NtCreateIoCompletion.cs | 2 +-
.../OS/Windows/Misc/NtCreateMutant.cs | 4 +-
.../OS/Windows/Misc/NtCreateSemaphore.cs | 2 +-
.../OS/Windows/Misc/NtCreateTimer2.cs | 4 +-
.../Misc/NtCreateWaitCompletionPacket.cs | 2 +-
.../OS/Windows/Misc/NtDelayExecution.cs | 2 +-
.../OS/Windows/Misc/NtDuplicateObject.cs | 2 +-
.../Emulation/OS/Windows/Misc/NtOpenMutant.cs | 2 +-
.../OS/Windows/Misc/NtOpenSemaphore.cs | 2 +-
.../OS/Windows/Misc/NtRaiseException.cs | 2 +-
.../Windows/Misc/NtWaitForMultipleObjects.cs | 2 +-
.../OS/Windows/Misc/NtWaitForSingleObject.cs | 2 +-
.../Process/NtAllocateVirtualMemory.cs | 4 +-
.../Process/NtAllocateVirtualMemoryEx.cs | 10 ++-
.../OS/Windows/Process/NtCreateProcess.cs | 2 +-
.../OS/Windows/Process/NtCreateThreadEx.cs | 4 +-
.../Windows/Process/NtCreateWorkerFactory.cs | 2 +-
.../OS/Windows/Process/NtDuplicateToken.cs | 4 +-
.../OS/Windows/Process/NtFreeVirtualMemory.cs | 2 +-
.../OS/Windows/Process/NtOpenProcessToken.cs | 2 +-
.../Windows/Process/NtProtectVirtualMemory.cs | 2 +-
.../Process/NtQuerySystemInformationEx.cs | 8 +-
.../OS/Windows/Process/NtTerminateProcess.cs | 2 +-
.../OS/Windows/Process/NtTerminateThread.cs | 2 +-
.../OS/Windows/Win32k/NtUserMessageCall.cs | 2 +-
31 files changed, 135 insertions(+), 40 deletions(-)
create mode 100644 Brovan/Core/Emulation/OS/Windows/Devices/KsecDevice.cs
diff --git a/Brovan/Core/Emulation/OS/Windows/Devices/KsecDevice.cs b/Brovan/Core/Emulation/OS/Windows/Devices/KsecDevice.cs
new file mode 100644
index 0000000..09ecf19
--- /dev/null
+++ b/Brovan/Core/Emulation/OS/Windows/Devices/KsecDevice.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Security.Cryptography;
+
+namespace Brovan.Core.Emulation.OS.Windows
+{
+ ///
+ /// Emulates \Device\KsecDD (Kernel Security Support Provider device). During process
+ /// initialization bcrypt/CNG (and the CRT) open this device and use it for random number
+ /// generation (IOCTL_KSEC_RNG) and for RtlEncryptMemory/RtlDecryptMemory
+ /// (IOCTL_KSEC_*_MEMORY). If the open fails the owning DllMain returns FALSE and the process
+ /// aborts with STATUS_DLL_INIT_FAILED, so the device must at least be openable.
+ ///
+ internal sealed class KsecDevice : IWinDevice
+ {
+ public string DeviceName => "\\Device\\KsecDD";
+
+ private const uint IOCTL_KSEC_RNG = 0x390004;
+ private const uint IOCTL_KSEC_RNG_REKEY = 0x390008;
+ private const uint IOCTL_KSEC_ENCRYPT_MEMORY = 0x39000C;
+ private const uint IOCTL_KSEC_DECRYPT_MEMORY = 0x390010;
+ private const uint IOCTL_KSEC_ENCRYPT_MEMORY_CROSS_PROCESS = 0x390014;
+ private const uint IOCTL_KSEC_DECRYPT_MEMORY_CROSS_PROCESS = 0x390018;
+ private const uint IOCTL_KSEC_ENCRYPT_MEMORY_SAME_LOGON = 0x39001C;
+ private const uint IOCTL_KSEC_DECRYPT_MEMORY_SAME_LOGON = 0x390020;
+ // FILE_DEVICE_KSEC function 0x100 (104-byte input, 8-byte output). bcrypt/CNG issues this
+ // from its DllMain during process init and only requires the call to succeed.
+ private const uint IOCTL_KSEC_CLIENT_HANDSHAKE = 0x390400;
+
+ public NTSTATUS Create(BinaryEmulator Instance, string DevicePath, byte[] EaBuffer, out string InternalPath, out WinDeviceDelegate Handler)
+ {
+ InternalPath = DevicePath;
+ Handler = Handle;
+ return NTSTATUS.STATUS_SUCCESS;
+ }
+
+ private NTSTATUS Handle(uint IOCTL, ref DeviceData Data, BinaryEmulator Instance)
+ {
+ switch (IOCTL)
+ {
+ case IOCTL_KSEC_RNG:
+ case IOCTL_KSEC_RNG_REKEY:
+ if (Data.OutputBuffer == null || Data.OutputLength == 0)
+ return NTSTATUS.STATUS_INVALID_PARAMETER;
+
+ uint Size = Math.Min(Data.OutputLength, (uint)Data.OutputBuffer.Length);
+ if (Size == 0)
+ return NTSTATUS.STATUS_INVALID_PARAMETER;
+
+ RandomNumberGenerator.Fill(Data.OutputBuffer.AsSpan(0, (int)Size));
+ Data.Information = Size;
+ return NTSTATUS.STATUS_SUCCESS;
+
+ case IOCTL_KSEC_ENCRYPT_MEMORY:
+ case IOCTL_KSEC_DECRYPT_MEMORY:
+ case IOCTL_KSEC_ENCRYPT_MEMORY_CROSS_PROCESS:
+ case IOCTL_KSEC_DECRYPT_MEMORY_CROSS_PROCESS:
+ case IOCTL_KSEC_ENCRYPT_MEMORY_SAME_LOGON:
+ case IOCTL_KSEC_DECRYPT_MEMORY_SAME_LOGON:
+ {
+ // RtlEncryptMemory/RtlDecryptMemory: emulate as identity so an encrypt followed
+ // by a decrypt round-trips to the original plaintext within the emulated process.
+ byte[] Source = (Data.InputBuffer != null && Data.InputBuffer.Length > 0) ? Data.InputBuffer : Data.OutputBuffer;
+ if (Data.OutputBuffer != null && Source != null)
+ {
+ int Count = Math.Min(Data.OutputBuffer.Length, Source.Length);
+ if (!ReferenceEquals(Source, Data.OutputBuffer))
+ Array.Copy(Source, Data.OutputBuffer, Count);
+ Data.Information = (uint)Count;
+ }
+ return NTSTATUS.STATUS_SUCCESS;
+ }
+
+ case IOCTL_KSEC_CLIENT_HANDSHAKE:
+ // Acknowledge with success and a zeroed output token so the owning DllMain
+ // returns TRUE instead of aborting the process with STATUS_DLL_INIT_FAILED.
+ if (Data.OutputBuffer != null && Data.OutputLength > 0)
+ {
+ uint OutN = Math.Min(Data.OutputLength, (uint)Data.OutputBuffer.Length);
+ Data.OutputBuffer.AsSpan(0, (int)OutN).Clear();
+ Data.Information = OutN;
+ }
+ return NTSTATUS.STATUS_SUCCESS;
+
+ default:
+ return NTSTATUS.STATUS_INVALID_DEVICE_REQUEST;
+ }
+ }
+ }
+}
diff --git a/Brovan/Core/Emulation/OS/Windows/Files/NtCreateFile.cs b/Brovan/Core/Emulation/OS/Windows/Files/NtCreateFile.cs
index a8f92bd..de8c67c 100644
--- a/Brovan/Core/Emulation/OS/Windows/Files/NtCreateFile.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Files/NtCreateFile.cs
@@ -31,7 +31,7 @@ public NTSTATUS Handle(BinaryEmulator Instance)
private NTSTATUS Handle64(BinaryEmulator Instance)
{
ulong FileHandlePtr = Instance.WinHelper.GetArg64(0);
- ulong DesiredAccess = Instance.WinHelper.GetArg64(1);
+ ulong DesiredAccess = (uint)Instance.WinHelper.GetArg64(1);
ulong ObjectAttributesPtr = Instance.WinHelper.GetArg64(2);
ulong IoStatusBlockPtr = Instance.WinHelper.GetArg64(3);
uint CreateDisposition = (uint)Instance.WinHelper.GetArg64(7);
diff --git a/Brovan/Core/Emulation/OS/Windows/Files/NtCreateSection.cs b/Brovan/Core/Emulation/OS/Windows/Files/NtCreateSection.cs
index b437c47..c5edad8 100644
--- a/Brovan/Core/Emulation/OS/Windows/Files/NtCreateSection.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Files/NtCreateSection.cs
@@ -13,7 +13,7 @@ public NTSTATUS Handle(BinaryEmulator Instance)
return Instance.WinUnimplemented;
ulong SectionHandlePtr = Instance.WinHelper.GetArg64(0);
- ulong DesiredAccess = Instance.WinHelper.GetArg64(1);
+ ulong DesiredAccess = (uint)Instance.WinHelper.GetArg64(1);
ulong ObjectAttributesPtr = Instance.WinHelper.GetArg64(2);
ulong MaximumSizePtr = Instance.WinHelper.GetArg64(3);
uint SectionPageProtection = (uint)Instance.WinHelper.GetArg64(4);
diff --git a/Brovan/Core/Emulation/OS/Windows/Files/NtQueryDirectoryFile.cs b/Brovan/Core/Emulation/OS/Windows/Files/NtQueryDirectoryFile.cs
index f5b0051..fb5c2cb 100644
--- a/Brovan/Core/Emulation/OS/Windows/Files/NtQueryDirectoryFile.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Files/NtQueryDirectoryFile.cs
@@ -20,9 +20,9 @@ public NTSTATUS Handle(BinaryEmulator Instance)
ulong FileInformation = Instance.WinHelper.GetArg64(5);
uint Length = (uint)Instance.WinHelper.GetArg64(6);
uint FileInformationClass = (uint)Instance.WinHelper.GetArg64(7);
- bool ReturnSingleEntry = Instance.WinHelper.GetArg64(8) != 0;
+ bool ReturnSingleEntry = (uint)Instance.WinHelper.GetArg64(8) != 0;
ulong FileName = Instance.WinHelper.GetArg64(9);
- bool RestartScan = Instance.WinHelper.GetArg64(10) != 0;
+ bool RestartScan = (uint)Instance.WinHelper.GetArg64(10) != 0;
uint QueryFlags = 0;
if (RestartScan)
diff --git a/Brovan/Core/Emulation/OS/Windows/Misc/NtContinue.cs b/Brovan/Core/Emulation/OS/Windows/Misc/NtContinue.cs
index d3281b9..dfaa8df 100644
--- a/Brovan/Core/Emulation/OS/Windows/Misc/NtContinue.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Misc/NtContinue.cs
@@ -7,7 +7,7 @@ internal class NtContinue : IWinSyscall
public NTSTATUS Handle(BinaryEmulator Instance)
{
ulong ContextPtr = Instance.WinHelper.GetArg64(0);
- bool TestAlert = Instance.WinHelper.GetArg64(1) != 0;
+ bool TestAlert = (uint)Instance.WinHelper.GetArg64(1) != 0;
return Continue(Instance, ContextPtr, TestAlert);
}
diff --git a/Brovan/Core/Emulation/OS/Windows/Misc/NtCreateEvent.cs b/Brovan/Core/Emulation/OS/Windows/Misc/NtCreateEvent.cs
index 7aeb9d3..ed93285 100644
--- a/Brovan/Core/Emulation/OS/Windows/Misc/NtCreateEvent.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Misc/NtCreateEvent.cs
@@ -9,7 +9,7 @@ public NTSTATUS Handle(BinaryEmulator Instance)
if (Instance._binary.Architecture == BinaryArchitecture.x64)
{
ulong EventHandlePtr = Instance.WinHelper.GetArg64(0);
- ulong DesiredAccess = Instance.WinHelper.GetArg64(1);
+ ulong DesiredAccess = (uint)Instance.WinHelper.GetArg64(1);
ulong ObjectAttributes = Instance.WinHelper.GetArg64(2);
uint EventType = (uint)Instance.WinHelper.GetArg64(3);
bool InitialState = (byte)Instance.WinHelper.GetArg64(4, true) != 0;
diff --git a/Brovan/Core/Emulation/OS/Windows/Misc/NtCreateIoCompletion.cs b/Brovan/Core/Emulation/OS/Windows/Misc/NtCreateIoCompletion.cs
index a872c21..2fdbf46 100644
--- a/Brovan/Core/Emulation/OS/Windows/Misc/NtCreateIoCompletion.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Misc/NtCreateIoCompletion.cs
@@ -9,7 +9,7 @@ public NTSTATUS Handle(BinaryEmulator Instance)
if (Instance._binary.Architecture == BinaryArchitecture.x64)
{
ulong IoCompletionHandlePtr = Instance.WinHelper.GetArg64(0);
- ulong DesiredAccess = Instance.WinHelper.GetArg64(1);
+ ulong DesiredAccess = (uint)Instance.WinHelper.GetArg64(1);
ulong Count = Instance.WinHelper.GetArg64(3);
if (IoCompletionHandlePtr == 0)
diff --git a/Brovan/Core/Emulation/OS/Windows/Misc/NtCreateMutant.cs b/Brovan/Core/Emulation/OS/Windows/Misc/NtCreateMutant.cs
index 717d1cd..d9a430c 100644
--- a/Brovan/Core/Emulation/OS/Windows/Misc/NtCreateMutant.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Misc/NtCreateMutant.cs
@@ -11,9 +11,9 @@ public NTSTATUS Handle(BinaryEmulator Instance)
if (Instance._binary.Architecture == BinaryArchitecture.x64)
{
ulong MutantHandlePtr = Instance.WinHelper.GetArg64(0);
- ulong DesiredAccess = Instance.WinHelper.GetArg64(1);
+ ulong DesiredAccess = (uint)Instance.WinHelper.GetArg64(1);
ulong ObjectAttributesPtr = Instance.WinHelper.GetArg64(2);
- bool InitialOwner = Instance.WinHelper.GetArg64(3) != 0;
+ bool InitialOwner = (uint)Instance.WinHelper.GetArg64(3) != 0;
return HandleCreateMutant64(Instance, MutantHandlePtr, DesiredAccess, ObjectAttributesPtr, InitialOwner);
}
diff --git a/Brovan/Core/Emulation/OS/Windows/Misc/NtCreateSemaphore.cs b/Brovan/Core/Emulation/OS/Windows/Misc/NtCreateSemaphore.cs
index 83d16bd..aca2b0d 100644
--- a/Brovan/Core/Emulation/OS/Windows/Misc/NtCreateSemaphore.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Misc/NtCreateSemaphore.cs
@@ -9,7 +9,7 @@ public NTSTATUS Handle(BinaryEmulator Instance)
if (Instance._binary.Architecture == BinaryArchitecture.x64)
{
ulong SemaphoreHandlePtr = Instance.WinHelper.GetArg64(0);
- ulong DesiredAccess = Instance.WinHelper.GetArg64(1);
+ ulong DesiredAccess = (uint)Instance.WinHelper.GetArg64(1);
ulong ObjectAttributesPtr = Instance.WinHelper.GetArg64(2);
int InitialCount = (int)Instance.WinHelper.GetArg64(3, true);
int MaximumCount = (int)Instance.WinHelper.GetArg64(4, true);
diff --git a/Brovan/Core/Emulation/OS/Windows/Misc/NtCreateTimer2.cs b/Brovan/Core/Emulation/OS/Windows/Misc/NtCreateTimer2.cs
index 4feadaf..3a3a985 100644
--- a/Brovan/Core/Emulation/OS/Windows/Misc/NtCreateTimer2.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Misc/NtCreateTimer2.cs
@@ -11,8 +11,8 @@ public NTSTATUS Handle(BinaryEmulator Instance)
ulong TimerHandlePtr = Instance.WinHelper.GetArg64(0);
ulong TimerIdPtr = Instance.WinHelper.GetArg64(1);
ulong ObjectAttributesPtr = Instance.WinHelper.GetArg64(2);
- ulong Attributes = Instance.WinHelper.GetArg64(3);
- ulong DesiredAccess = Instance.WinHelper.GetArg64(4);
+ ulong Attributes = (uint)Instance.WinHelper.GetArg64(3);
+ ulong DesiredAccess = (uint)Instance.WinHelper.GetArg64(4);
if (TimerHandlePtr == 0)
return NTSTATUS.STATUS_INVALID_PARAMETER;
diff --git a/Brovan/Core/Emulation/OS/Windows/Misc/NtCreateWaitCompletionPacket.cs b/Brovan/Core/Emulation/OS/Windows/Misc/NtCreateWaitCompletionPacket.cs
index a4edc11..ca23259 100644
--- a/Brovan/Core/Emulation/OS/Windows/Misc/NtCreateWaitCompletionPacket.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Misc/NtCreateWaitCompletionPacket.cs
@@ -9,7 +9,7 @@ public NTSTATUS Handle(BinaryEmulator Instance)
if (Instance._binary.Architecture == BinaryArchitecture.x64)
{
ulong WaitCompletionPacketHandlePtr = Instance.WinHelper.GetArg64(0);
- ulong DesiredAccess = Instance.WinHelper.GetArg64(1);
+ ulong DesiredAccess = (uint)Instance.WinHelper.GetArg64(1);
ulong ObjectAttributes = Instance.WinHelper.GetArg64(2);
if (WaitCompletionPacketHandlePtr == 0)
diff --git a/Brovan/Core/Emulation/OS/Windows/Misc/NtDelayExecution.cs b/Brovan/Core/Emulation/OS/Windows/Misc/NtDelayExecution.cs
index 090e886..8378d5e 100644
--- a/Brovan/Core/Emulation/OS/Windows/Misc/NtDelayExecution.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Misc/NtDelayExecution.cs
@@ -83,7 +83,7 @@ public NTSTATUS Handle(BinaryEmulator Instance)
if (Instance._binary.Architecture != BinaryArchitecture.x64)
return Instance.WinUnimplemented;
- bool Alertable = Instance.WinHelper.GetArg64(0) != 0;
+ bool Alertable = (uint)Instance.WinHelper.GetArg64(0) != 0;
ulong DelayIntervalPtr = Instance.WinHelper.GetArg64(1);
long DelayMs = ReadDelayMs(Instance, DelayIntervalPtr);
EmulatedThread Thread = Instance.CurrentThread;
diff --git a/Brovan/Core/Emulation/OS/Windows/Misc/NtDuplicateObject.cs b/Brovan/Core/Emulation/OS/Windows/Misc/NtDuplicateObject.cs
index ea44a9c..2606fda 100644
--- a/Brovan/Core/Emulation/OS/Windows/Misc/NtDuplicateObject.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Misc/NtDuplicateObject.cs
@@ -16,7 +16,7 @@ public NTSTATUS Handle(BinaryEmulator Instance)
ulong SourceHandle = Instance.WinHelper.GetArg64(1);
ulong TargetProcessHandle = Instance.WinHelper.GetArg64(2);
ulong TargetHandlePtr = Instance.WinHelper.GetArg64(3);
- ulong DesiredAccess = Instance.WinHelper.GetArg64(4);
+ ulong DesiredAccess = (uint)Instance.WinHelper.GetArg64(4);
uint HandleAttributes = (uint)Instance.WinHelper.GetArg64(5);
uint Options = (uint)Instance.WinHelper.GetArg64(6);
diff --git a/Brovan/Core/Emulation/OS/Windows/Misc/NtOpenMutant.cs b/Brovan/Core/Emulation/OS/Windows/Misc/NtOpenMutant.cs
index 1740f93..0195512 100644
--- a/Brovan/Core/Emulation/OS/Windows/Misc/NtOpenMutant.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Misc/NtOpenMutant.cs
@@ -11,7 +11,7 @@ public NTSTATUS Handle(BinaryEmulator Instance)
if (Instance._binary.Architecture == BinaryArchitecture.x64)
{
ulong MutantHandlePtr = Instance.WinHelper.GetArg64(0);
- ulong DesiredAccess = Instance.WinHelper.GetArg64(1);
+ ulong DesiredAccess = (uint)Instance.WinHelper.GetArg64(1);
ulong ObjectAttributesPtr = Instance.WinHelper.GetArg64(2);
return HandleOpenMutant64(Instance, MutantHandlePtr, DesiredAccess, ObjectAttributesPtr);
diff --git a/Brovan/Core/Emulation/OS/Windows/Misc/NtOpenSemaphore.cs b/Brovan/Core/Emulation/OS/Windows/Misc/NtOpenSemaphore.cs
index 68586dd..468cda6 100644
--- a/Brovan/Core/Emulation/OS/Windows/Misc/NtOpenSemaphore.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Misc/NtOpenSemaphore.cs
@@ -11,7 +11,7 @@ public NTSTATUS Handle(BinaryEmulator Instance)
if (Instance._binary.Architecture == BinaryArchitecture.x64)
{
ulong SemaphoreHandlePtr = Instance.WinHelper.GetArg64(0);
- ulong DesiredAccess = Instance.WinHelper.GetArg64(1);
+ ulong DesiredAccess = (uint)Instance.WinHelper.GetArg64(1);
ulong ObjectAttributesPtr = Instance.WinHelper.GetArg64(2);
return HandleOpenSemaphore64(Instance, SemaphoreHandlePtr, DesiredAccess, ObjectAttributesPtr);
diff --git a/Brovan/Core/Emulation/OS/Windows/Misc/NtRaiseException.cs b/Brovan/Core/Emulation/OS/Windows/Misc/NtRaiseException.cs
index 6dbf94d..e8f98ea 100644
--- a/Brovan/Core/Emulation/OS/Windows/Misc/NtRaiseException.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Misc/NtRaiseException.cs
@@ -17,7 +17,7 @@ public NTSTATUS Handle(BinaryEmulator Instance)
ulong ExceptionRecordPtr = Instance.WinHelper.GetArg64(0);
ulong ContextRecordPtr = Instance.WinHelper.GetArg64(1);
- bool FirstChance = Instance.WinHelper.GetArg64(2) != 0;
+ bool FirstChance = (uint)Instance.WinHelper.GetArg64(2) != 0;
_ = FirstChance;
if (ExceptionRecordPtr == 0 || ContextRecordPtr == 0)
diff --git a/Brovan/Core/Emulation/OS/Windows/Misc/NtWaitForMultipleObjects.cs b/Brovan/Core/Emulation/OS/Windows/Misc/NtWaitForMultipleObjects.cs
index e1fd312..2594dbe 100644
--- a/Brovan/Core/Emulation/OS/Windows/Misc/NtWaitForMultipleObjects.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Misc/NtWaitForMultipleObjects.cs
@@ -82,7 +82,7 @@ public NTSTATUS Handle(BinaryEmulator Instance)
uint Count = (uint)Instance.WinHelper.GetArg64(0);
ulong HandlesPtr = Instance.WinHelper.GetArg64(1);
uint WaitType = (uint)Instance.WinHelper.GetArg64(2);
- bool Alertable = Instance.WinHelper.GetArg64(3) != 0;
+ bool Alertable = (uint)Instance.WinHelper.GetArg64(3) != 0;
ulong TimeoutPtr = Instance.WinHelper.GetArg64(4);
EmulatedThread Thread = Instance.CurrentThread;
diff --git a/Brovan/Core/Emulation/OS/Windows/Misc/NtWaitForSingleObject.cs b/Brovan/Core/Emulation/OS/Windows/Misc/NtWaitForSingleObject.cs
index 8f3ff81..ab7e3d2 100644
--- a/Brovan/Core/Emulation/OS/Windows/Misc/NtWaitForSingleObject.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Misc/NtWaitForSingleObject.cs
@@ -31,7 +31,7 @@ public NTSTATUS Handle(BinaryEmulator Instance)
return Instance.WinUnimplemented;
ulong Handle = Instance.WinHelper.GetArg64(0);
- bool Alertable = Instance.WinHelper.GetArg64(1) != 0;
+ bool Alertable = (uint)Instance.WinHelper.GetArg64(1) != 0;
ulong TimeoutPtr = Instance.WinHelper.GetArg64(2);
EmulatedThread Thread = Instance.CurrentThread;
diff --git a/Brovan/Core/Emulation/OS/Windows/Process/NtAllocateVirtualMemory.cs b/Brovan/Core/Emulation/OS/Windows/Process/NtAllocateVirtualMemory.cs
index d4c9f77..85f0b76 100644
--- a/Brovan/Core/Emulation/OS/Windows/Process/NtAllocateVirtualMemory.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Process/NtAllocateVirtualMemory.cs
@@ -38,8 +38,8 @@ public NTSTATUS Handle(BinaryEmulator Instance)
ulong BaseAddressPtr = Instance.WinHelper.GetArg64(1);
ulong ZeroBits = Instance.WinHelper.GetArg64(2); // ignored for now
ulong RegionSizePtr = Instance.WinHelper.GetArg64(3);
- ulong AllocationTypeValue = Instance.WinHelper.GetArg64(4);
- ulong ProtectValue = Instance.WinHelper.GetArg64(5);
+ ulong AllocationTypeValue = (uint)Instance.WinHelper.GetArg64(4);
+ ulong ProtectValue = (uint)Instance.WinHelper.GetArg64(5);
ulong RegionSize = 0;
if (ProcessHandle != ulong.MaxValue)
{
diff --git a/Brovan/Core/Emulation/OS/Windows/Process/NtAllocateVirtualMemoryEx.cs b/Brovan/Core/Emulation/OS/Windows/Process/NtAllocateVirtualMemoryEx.cs
index d341173..5f1c7d8 100644
--- a/Brovan/Core/Emulation/OS/Windows/Process/NtAllocateVirtualMemoryEx.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Process/NtAllocateVirtualMemoryEx.cs
@@ -33,10 +33,14 @@ public NTSTATUS Handle(BinaryEmulator Instance)
ulong ProcessHandle = Instance.WinHelper.GetArg64(0);
ulong BaseAddressPtr = Instance.WinHelper.GetArg64(1);
ulong RegionSizePtr = Instance.WinHelper.GetArg64(2);
- ulong AllocationTypeValue = Instance.WinHelper.GetArg64(3);
- ulong ProtectValue = Instance.WinHelper.GetArg64(4);
+ // AllocationType, PageProtection and ExtendedParameterCount are ULONG (32-bit) in the
+ // syscall signature; the caller can leave garbage in the upper 32 bits of the register,
+ // so mask to 32 bits. Without this, a real count of 0 with non-zero high bits is read as
+ // non-zero and wrongly fails the "count != 0 but pointer == 0" check (INVALID_PARAMETER).
+ ulong AllocationTypeValue = (uint)Instance.WinHelper.GetArg64(3);
+ ulong ProtectValue = (uint)Instance.WinHelper.GetArg64(4);
ulong ExtendedParametersPtr = Instance.WinHelper.GetArg64(5);
- ulong ExtendedParameterCount = Instance.WinHelper.GetArg64(6);
+ ulong ExtendedParameterCount = (uint)Instance.WinHelper.GetArg64(6);
if (ProtectValue == 0x08 || ProtectValue == 0x80)
return NTSTATUS.STATUS_INVALID_PAGE_PROTECTION;
diff --git a/Brovan/Core/Emulation/OS/Windows/Process/NtCreateProcess.cs b/Brovan/Core/Emulation/OS/Windows/Process/NtCreateProcess.cs
index 0b618bc..817088d 100644
--- a/Brovan/Core/Emulation/OS/Windows/Process/NtCreateProcess.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Process/NtCreateProcess.cs
@@ -15,7 +15,7 @@ public NTSTATUS Handle(BinaryEmulator Instance)
if (Instance._binary.Architecture == BinaryArchitecture.x64)
{
ulong ProcessHandlePtr = Instance.WinHelper.GetArg64(0);
- ulong DesiredAccess = Instance.WinHelper.GetArg64(1);
+ ulong DesiredAccess = (uint)Instance.WinHelper.GetArg64(1);
ulong ObjectAttributesPtr = Instance.WinHelper.GetArg64(2);
ulong ParentProcess = Instance.WinHelper.GetArg64(3);
ulong InheritObjectTable = Instance.WinHelper.GetArg64(4);
diff --git a/Brovan/Core/Emulation/OS/Windows/Process/NtCreateThreadEx.cs b/Brovan/Core/Emulation/OS/Windows/Process/NtCreateThreadEx.cs
index 36f7be3..e357490 100644
--- a/Brovan/Core/Emulation/OS/Windows/Process/NtCreateThreadEx.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Process/NtCreateThreadEx.cs
@@ -53,11 +53,11 @@ public NTSTATUS Handle(BinaryEmulator Instance)
return Instance.WinUnimplemented;
ulong ThreadHandlePtr = Instance.WinHelper.GetArg64(0);
- ulong DesiredAccess = Instance.WinHelper.GetArg64(1);
+ ulong DesiredAccess = (uint)Instance.WinHelper.GetArg64(1);
ulong ProcessHandle = Instance.WinHelper.GetArg64(3);
ulong StartRoutine = Instance.WinHelper.GetArg64(4);
ulong Argument = Instance.WinHelper.GetArg64(5);
- ulong CreateFlags = Instance.WinHelper.GetArg64(6);
+ ulong CreateFlags = (uint)Instance.WinHelper.GetArg64(6);
ulong StackSize = Instance.WinHelper.GetArg64(8);
ulong AttributeList = Instance.WinHelper.GetArg64(10);
diff --git a/Brovan/Core/Emulation/OS/Windows/Process/NtCreateWorkerFactory.cs b/Brovan/Core/Emulation/OS/Windows/Process/NtCreateWorkerFactory.cs
index daa4799..f651a1c 100644
--- a/Brovan/Core/Emulation/OS/Windows/Process/NtCreateWorkerFactory.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Process/NtCreateWorkerFactory.cs
@@ -9,7 +9,7 @@ public NTSTATUS Handle(BinaryEmulator Instance)
if (Instance._binary.Architecture == BinaryArchitecture.x64)
{
ulong WorkerFactoryHandlePtr = Instance.WinHelper.GetArg64(0);
- ulong DesiredAccess = Instance.WinHelper.GetArg64(1);
+ ulong DesiredAccess = (uint)Instance.WinHelper.GetArg64(1);
ulong ObjectAttributesPtr = Instance.WinHelper.GetArg64(2);
ulong IoCompletionHandle = Instance.WinHelper.GetArg64(3);
ulong WorkerProcessHandle = Instance.WinHelper.GetArg64(4);
diff --git a/Brovan/Core/Emulation/OS/Windows/Process/NtDuplicateToken.cs b/Brovan/Core/Emulation/OS/Windows/Process/NtDuplicateToken.cs
index 348fe43..94e75f9 100644
--- a/Brovan/Core/Emulation/OS/Windows/Process/NtDuplicateToken.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Process/NtDuplicateToken.cs
@@ -24,9 +24,9 @@ public NTSTATUS Handle(BinaryEmulator Instance)
if (Is64)
{
ExistingTokenHandle = Instance.WinHelper.GetArg64(0);
- DesiredAccess = Instance.WinHelper.GetArg64(1);
+ DesiredAccess = (uint)Instance.WinHelper.GetArg64(1);
ObjectAttributesPtr = Instance.WinHelper.GetArg64(2);
- EffectiveOnly = Instance.WinHelper.GetArg64(3) != 0;
+ EffectiveOnly = (uint)Instance.WinHelper.GetArg64(3) != 0;
RequestedTokenType = (uint)Instance.WinHelper.GetArg64(4);
NewTokenHandlePtr = Instance.WinHelper.GetArg64(5);
}
diff --git a/Brovan/Core/Emulation/OS/Windows/Process/NtFreeVirtualMemory.cs b/Brovan/Core/Emulation/OS/Windows/Process/NtFreeVirtualMemory.cs
index bcba40e..2747d16 100644
--- a/Brovan/Core/Emulation/OS/Windows/Process/NtFreeVirtualMemory.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Process/NtFreeVirtualMemory.cs
@@ -17,7 +17,7 @@ public NTSTATUS Handle(BinaryEmulator Instance)
ulong ProcessHandle = Instance.WinHelper.GetArg64(0);
ulong BaseAddressPtr = Instance.WinHelper.GetArg64(1);
ulong RegionSizePtr = Instance.WinHelper.GetArg64(2);
- ulong FreeType = Instance.WinHelper.GetArg64(3);
+ ulong FreeType = (uint)Instance.WinHelper.GetArg64(3);
if (BaseAddressPtr == 0 || RegionSizePtr == 0)
return NTSTATUS.STATUS_INVALID_PARAMETER;
diff --git a/Brovan/Core/Emulation/OS/Windows/Process/NtOpenProcessToken.cs b/Brovan/Core/Emulation/OS/Windows/Process/NtOpenProcessToken.cs
index eea1921..a0e3f79 100644
--- a/Brovan/Core/Emulation/OS/Windows/Process/NtOpenProcessToken.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Process/NtOpenProcessToken.cs
@@ -16,7 +16,7 @@ public NTSTATUS Handle(BinaryEmulator Instance)
if (Is64)
{
ProcessHandle = Instance.WinHelper.GetArg64(0);
- DesiredAccess = Instance.WinHelper.GetArg64(1);
+ DesiredAccess = (uint)Instance.WinHelper.GetArg64(1);
TokenHandlePtr = Instance.WinHelper.GetArg64(2);
if (TokenHandlePtr == 0 || !Instance.IsRegionMapped(TokenHandlePtr, 8))
diff --git a/Brovan/Core/Emulation/OS/Windows/Process/NtProtectVirtualMemory.cs b/Brovan/Core/Emulation/OS/Windows/Process/NtProtectVirtualMemory.cs
index 27d6789..8d2cb27 100644
--- a/Brovan/Core/Emulation/OS/Windows/Process/NtProtectVirtualMemory.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Process/NtProtectVirtualMemory.cs
@@ -16,7 +16,7 @@ public NTSTATUS Handle(BinaryEmulator Instance)
ulong ProcessHandle = Instance.WinHelper.GetArg64(0);
ulong BaseAddressPtr = Instance.WinHelper.GetArg64(1);
ulong RegionSizePtr = Instance.WinHelper.GetArg64(2);
- ulong NewProtection = Instance.WinHelper.GetArg64(3);
+ ulong NewProtection = (uint)Instance.WinHelper.GetArg64(3);
ulong OldProtectionPtr = Instance.WinHelper.GetArg64(4);
// current process
diff --git a/Brovan/Core/Emulation/OS/Windows/Process/NtQuerySystemInformationEx.cs b/Brovan/Core/Emulation/OS/Windows/Process/NtQuerySystemInformationEx.cs
index 105b563..51052d5 100644
--- a/Brovan/Core/Emulation/OS/Windows/Process/NtQuerySystemInformationEx.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Process/NtQuerySystemInformationEx.cs
@@ -10,11 +10,13 @@ public NTSTATUS Handle(BinaryEmulator Instance)
{
if (Instance._binary.Architecture == BinaryArchitecture.x64)
{
- SYSTEM_INFORMATION_CLASS SystemInformationClass = (SYSTEM_INFORMATION_CLASS)Instance.WinHelper.GetArg64(0);
+ // SystemInformationClass, InputBufferLength and SystemInformationLength are ULONG (32-bit);
+ // mask to 32 bits since the caller can leave garbage in the upper half of the (stack-passed) slots.
+ SYSTEM_INFORMATION_CLASS SystemInformationClass = (SYSTEM_INFORMATION_CLASS)(uint)Instance.WinHelper.GetArg64(0);
ulong InputBufferPtr = Instance.WinHelper.GetArg64(1);
- ulong InputBufferLength = Instance.WinHelper.GetArg64(2);
+ ulong InputBufferLength = (uint)Instance.WinHelper.GetArg64(2);
ulong SystemInformationPtr = Instance.WinHelper.GetArg64(3);
- ulong SystemInformationLength = Instance.WinHelper.GetArg64(4);
+ ulong SystemInformationLength = (uint)Instance.WinHelper.GetArg64(4);
ulong ReturnLengthPtr = Instance.WinHelper.GetArg64(5);
if (InputBufferLength != 0)
diff --git a/Brovan/Core/Emulation/OS/Windows/Process/NtTerminateProcess.cs b/Brovan/Core/Emulation/OS/Windows/Process/NtTerminateProcess.cs
index a1b151b..6a80cec 100644
--- a/Brovan/Core/Emulation/OS/Windows/Process/NtTerminateProcess.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Process/NtTerminateProcess.cs
@@ -14,7 +14,7 @@ public NTSTATUS Handle(BinaryEmulator Instance)
if (Instance._binary.Architecture == BinaryArchitecture.x64)
{
ulong ProcessHandle = Instance.WinHelper.GetArg64(0);
- ulong ExitCode = Instance.WinHelper.GetArg64(1);
+ ulong ExitCode = (uint)Instance.WinHelper.GetArg64(1);
if (ExitCode == 0)
{
diff --git a/Brovan/Core/Emulation/OS/Windows/Process/NtTerminateThread.cs b/Brovan/Core/Emulation/OS/Windows/Process/NtTerminateThread.cs
index 6c9a4bb..113c650 100644
--- a/Brovan/Core/Emulation/OS/Windows/Process/NtTerminateThread.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Process/NtTerminateThread.cs
@@ -10,7 +10,7 @@ public NTSTATUS Handle(BinaryEmulator Instance)
return Instance.WinUnimplemented;
ulong ThreadHandle = Instance.WinHelper.GetArg64(0);
- ulong ExitStatus = Instance.WinHelper.GetArg64(1);
+ ulong ExitStatus = (uint)Instance.WinHelper.GetArg64(1);
bool TerminatingSelfByNullHandle = ThreadHandle == 0;
EmulatedThread TargetThread = null;
diff --git a/Brovan/Core/Emulation/OS/Windows/Win32k/NtUserMessageCall.cs b/Brovan/Core/Emulation/OS/Windows/Win32k/NtUserMessageCall.cs
index bc637d4..ba42cbf 100644
--- a/Brovan/Core/Emulation/OS/Windows/Win32k/NtUserMessageCall.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Win32k/NtUserMessageCall.cs
@@ -14,7 +14,7 @@ public NTSTATUS Handle(BinaryEmulator Instance)
ulong WParam = Instance.WinHelper.GetArg64(2);
ulong LParam = Instance.WinHelper.GetArg64(3);
ulong XParam = Instance.WinHelper.GetArg64(4);
- ulong Flags = Instance.WinHelper.GetArg64(6);
+ ulong Flags = (uint)Instance.WinHelper.GetArg64(6);
bool Ansi = (XParam & 1) != 0 || (Flags & 1) != 0;
if ((Message & 0xFFFE0000u) != 0)
From 8fc14662ab70331e65f30ee6f8944587ab5c3f39 Mon Sep 17 00:00:00 2001
From: Ezz Aldeen Bayoumi <90452585+AdvDebug@users.noreply.github.com>
Date: Thu, 4 Jun 2026 12:49:45 +0300
Subject: [PATCH 2/5] Remove comments for Ksec Device
---
.../Core/Emulation/OS/Windows/Devices/KsecDevice.cs | 12 +-----------
1 file changed, 1 insertion(+), 11 deletions(-)
diff --git a/Brovan/Core/Emulation/OS/Windows/Devices/KsecDevice.cs b/Brovan/Core/Emulation/OS/Windows/Devices/KsecDevice.cs
index 09ecf19..efd5e0a 100644
--- a/Brovan/Core/Emulation/OS/Windows/Devices/KsecDevice.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Devices/KsecDevice.cs
@@ -4,11 +4,7 @@
namespace Brovan.Core.Emulation.OS.Windows
{
///
- /// Emulates \Device\KsecDD (Kernel Security Support Provider device). During process
- /// initialization bcrypt/CNG (and the CRT) open this device and use it for random number
- /// generation (IOCTL_KSEC_RNG) and for RtlEncryptMemory/RtlDecryptMemory
- /// (IOCTL_KSEC_*_MEMORY). If the open fails the owning DllMain returns FALSE and the process
- /// aborts with STATUS_DLL_INIT_FAILED, so the device must at least be openable.
+ /// Emulates \Device\KsecDD (Kernel Security Support Provider device)
///
internal sealed class KsecDevice : IWinDevice
{
@@ -22,8 +18,6 @@ internal sealed class KsecDevice : IWinDevice
private const uint IOCTL_KSEC_DECRYPT_MEMORY_CROSS_PROCESS = 0x390018;
private const uint IOCTL_KSEC_ENCRYPT_MEMORY_SAME_LOGON = 0x39001C;
private const uint IOCTL_KSEC_DECRYPT_MEMORY_SAME_LOGON = 0x390020;
- // FILE_DEVICE_KSEC function 0x100 (104-byte input, 8-byte output). bcrypt/CNG issues this
- // from its DllMain during process init and only requires the call to succeed.
private const uint IOCTL_KSEC_CLIENT_HANDSHAKE = 0x390400;
public NTSTATUS Create(BinaryEmulator Instance, string DevicePath, byte[] EaBuffer, out string InternalPath, out WinDeviceDelegate Handler)
@@ -57,8 +51,6 @@ private NTSTATUS Handle(uint IOCTL, ref DeviceData Data, BinaryEmulator Instance
case IOCTL_KSEC_ENCRYPT_MEMORY_SAME_LOGON:
case IOCTL_KSEC_DECRYPT_MEMORY_SAME_LOGON:
{
- // RtlEncryptMemory/RtlDecryptMemory: emulate as identity so an encrypt followed
- // by a decrypt round-trips to the original plaintext within the emulated process.
byte[] Source = (Data.InputBuffer != null && Data.InputBuffer.Length > 0) ? Data.InputBuffer : Data.OutputBuffer;
if (Data.OutputBuffer != null && Source != null)
{
@@ -71,8 +63,6 @@ private NTSTATUS Handle(uint IOCTL, ref DeviceData Data, BinaryEmulator Instance
}
case IOCTL_KSEC_CLIENT_HANDSHAKE:
- // Acknowledge with success and a zeroed output token so the owning DllMain
- // returns TRUE instead of aborting the process with STATUS_DLL_INIT_FAILED.
if (Data.OutputBuffer != null && Data.OutputLength > 0)
{
uint OutN = Math.Min(Data.OutputLength, (uint)Data.OutputBuffer.Length);
From 740309df94348c66af3be251eb4f60ecfaf11eb5 Mon Sep 17 00:00:00 2001
From: Ezz Aldeen Bayoumi <90452585+AdvDebug@users.noreply.github.com>
Date: Thu, 4 Jun 2026 12:54:44 +0300
Subject: [PATCH 3/5] Add the latest commit back to NtAllocateVirtualMemoryEx
but with fixes
---
.../Process/NtAllocateVirtualMemoryEx.cs | 144 +++++++++++++++---
1 file changed, 124 insertions(+), 20 deletions(-)
diff --git a/Brovan/Core/Emulation/OS/Windows/Process/NtAllocateVirtualMemoryEx.cs b/Brovan/Core/Emulation/OS/Windows/Process/NtAllocateVirtualMemoryEx.cs
index 5f1c7d8..4abc555 100644
--- a/Brovan/Core/Emulation/OS/Windows/Process/NtAllocateVirtualMemoryEx.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Process/NtAllocateVirtualMemoryEx.cs
@@ -7,6 +7,8 @@ internal class NtAllocateVirtualMemoryEx : IWinSyscall
{
private const ulong PageSize = 0x1000;
private const ulong AllocationGranularity = 0x10000;
+ private const ulong MemReset = 0x00080000UL;
+ private const ulong MemResetUndo = 0x01000000UL;
private static ulong FindFreeBaseAddress(BinaryEmulator Instance, ulong Size, bool IsX64)
{
@@ -26,6 +28,79 @@ private static ulong FindFreeBaseAddress(BinaryEmulator Instance, ulong Size, bo
return 0;
}
+ private static bool TryApplyResetState(BinaryEmulator Instance, ulong BaseAddress, ulong RegionSize, bool Reset, out NTSTATUS Status)
+ {
+ Status = NTSTATUS.STATUS_SUCCESS;
+
+ if (BaseAddress == 0 || RegionSize == 0)
+ {
+ Status = NTSTATUS.STATUS_INVALID_PARAMETER;
+ return false;
+ }
+
+ if ((BaseAddress & (PageSize - 1)) != 0 || (RegionSize & (PageSize - 1)) != 0)
+ {
+ Status = NTSTATUS.STATUS_CONFLICTING_ADDRESSES;
+ return false;
+ }
+
+ ulong End = BaseAddress + RegionSize;
+ if (End < BaseAddress)
+ {
+ Status = NTSTATUS.STATUS_CONFLICTING_ADDRESSES;
+ return false;
+ }
+
+ ulong Current = BaseAddress;
+ ulong AllocationBase = 0;
+ bool HasAllocationBase = false;
+
+ while (Current < End)
+ {
+ if (!Instance.TryFindMemoryRegionIndex(Current, out int Index) || !Instance.TryFindMemoryRegion(Current, out MemoryRegion Region))
+ {
+ Status = NTSTATUS.STATUS_MEMORY_NOT_ALLOCATED;
+ return false;
+ }
+
+ if (!Region.IsReserved || !Region.IsCommitted)
+ {
+ Status = NTSTATUS.STATUS_MEMORY_NOT_ALLOCATED;
+ return false;
+ }
+
+ if (!HasAllocationBase)
+ {
+ AllocationBase = Region.AllocationBase;
+ HasAllocationBase = true;
+ }
+ else if (Region.AllocationBase != AllocationBase)
+ {
+ Status = NTSTATUS.STATUS_MEMORY_NOT_ALLOCATED;
+ return false;
+ }
+
+ ulong RegionEnd = Region.BaseAddress + Region.Size;
+ if (RegionEnd <= Current)
+ {
+ Status = NTSTATUS.STATUS_MEMORY_NOT_ALLOCATED;
+ return false;
+ }
+
+ if (Region.IsReset == Reset)
+ {
+ Current = Math.Min(RegionEnd, End);
+ continue;
+ }
+
+ Region.IsReset = Reset;
+ Instance.SetMemoryRegion(Index, Region);
+ Current = Math.Min(RegionEnd, End);
+ }
+
+ return true;
+ }
+
public NTSTATUS Handle(BinaryEmulator Instance)
{
if (Instance._binary.Architecture == BinaryArchitecture.x64)
@@ -33,18 +108,11 @@ public NTSTATUS Handle(BinaryEmulator Instance)
ulong ProcessHandle = Instance.WinHelper.GetArg64(0);
ulong BaseAddressPtr = Instance.WinHelper.GetArg64(1);
ulong RegionSizePtr = Instance.WinHelper.GetArg64(2);
- // AllocationType, PageProtection and ExtendedParameterCount are ULONG (32-bit) in the
- // syscall signature; the caller can leave garbage in the upper 32 bits of the register,
- // so mask to 32 bits. Without this, a real count of 0 with non-zero high bits is read as
- // non-zero and wrongly fails the "count != 0 but pointer == 0" check (INVALID_PARAMETER).
ulong AllocationTypeValue = (uint)Instance.WinHelper.GetArg64(3);
ulong ProtectValue = (uint)Instance.WinHelper.GetArg64(4);
ulong ExtendedParametersPtr = Instance.WinHelper.GetArg64(5);
ulong ExtendedParameterCount = (uint)Instance.WinHelper.GetArg64(6);
- if (ProtectValue == 0x08 || ProtectValue == 0x80)
- return NTSTATUS.STATUS_INVALID_PAGE_PROTECTION;
-
if (BaseAddressPtr == 0 || RegionSizePtr == 0)
return NTSTATUS.STATUS_INVALID_PARAMETER;
@@ -52,12 +120,6 @@ public NTSTATUS Handle(BinaryEmulator Instance)
if (RegionSizeRaw == 0 || AllocationTypeValue == 0 || ProtectValue == 0)
return NTSTATUS.STATUS_INVALID_PARAMETER;
- if (ExtendedParameterCount != 0 && ExtendedParametersPtr == 0)
- return NTSTATUS.STATUS_INVALID_PARAMETER;
-
- if (ExtendedParameterCount == 0 && ExtendedParametersPtr != 0)
- return NTSTATUS.STATUS_INVALID_PARAMETER;
-
if (ProcessHandle != ulong.MaxValue)
{
if (!Instance.WinHelper.ValidProcessHandle(ProcessHandle))
@@ -73,16 +135,43 @@ public NTSTATUS Handle(BinaryEmulator Instance)
return Instance.WinUnimplemented;
}
+ bool Reset = (AllocationTypeValue & MemReset) != 0;
+ bool ResetUndo = (AllocationTypeValue & MemResetUndo) != 0;
+ if (Reset || ResetUndo)
+ {
+ if ((Reset && ResetUndo) || (Reset && AllocationTypeValue != MemReset) || (ResetUndo && AllocationTypeValue != MemResetUndo))
+ return NTSTATUS.STATUS_INVALID_PARAMETER;
+
+ ulong BaseAddressReset = Instance.ReadMemoryULong(BaseAddressPtr);
+ ulong RegionSizeReset = BinaryEmulator.AlignUp(RegionSizeRaw, PageSize);
+ if (!TryApplyResetState(Instance, BaseAddressReset, RegionSizeReset, Reset, out NTSTATUS ResetStatus))
+ return ResetStatus;
+
+ if (!Instance._emulator.WriteMemory(BaseAddressPtr, BaseAddressReset))
+ return NTSTATUS.STATUS_ACCESS_VIOLATION;
+
+ if (!Instance._emulator.WriteMemory(RegionSizePtr, RegionSizeReset))
+ return NTSTATUS.STATUS_ACCESS_VIOLATION;
+
+ return NTSTATUS.STATUS_SUCCESS;
+ }
+
ulong RegionSize = BinaryEmulator.AlignUp(RegionSizeRaw, PageSize);
ulong BaseAddress = Instance.ReadMemoryULong(BaseAddressPtr);
bool Reserve = (AllocationTypeValue & 0x2000UL) != 0; // MEM_RESERVE
- bool Commit = (AllocationTypeValue & 0x1000UL) != 0; // MEM_COMMIT
+ bool Commit = (AllocationTypeValue & 0x1000UL) != 0; // MEM_COMMIT
Instance.TriggerEventMessage($"[+] NtAllocateVirtualMemoryEx (BaseAddress: 0x{BaseAddress:X}, RegionSize: {RegionSize}, Commit: {Commit}, Reserve: {Reserve})", LogFlags.Syscall);
if (!Reserve && !Commit)
+ {
+ if ((AllocationTypeValue & 0x00080000UL) != 0 || // MEM_RESET
+ (AllocationTypeValue & 0x01000000UL) != 0) // MEM_RESET_UNDO
+ return Instance.WinUnimplemented;
+
return NTSTATUS.STATUS_INVALID_PARAMETER;
+ }
if (!Reserve && Commit && BaseAddress == 0)
Reserve = true;
@@ -138,12 +227,6 @@ public NTSTATUS Handle(BinaryEmulator Instance)
if (RegionSizeRaw32 == 0 || AllocationTypeValue == 0 || ProtectValue == 0)
return NTSTATUS.STATUS_INVALID_PARAMETER;
- if (ExtendedParameterCount != 0 && ExtendedParametersPtr == 0)
- return NTSTATUS.STATUS_INVALID_PARAMETER;
-
- if (ExtendedParameterCount == 0 && ExtendedParametersPtr != 0)
- return NTSTATUS.STATUS_INVALID_PARAMETER;
-
if (ProcessHandle != uint.MaxValue)
{
if (!Instance.WinHelper.ValidProcessHandle(ProcessHandle))
@@ -159,6 +242,27 @@ public NTSTATUS Handle(BinaryEmulator Instance)
return Instance.WinUnimplemented;
}
+ bool Reset = (AllocationTypeValue & MemReset) != 0;
+ bool ResetUndo = (AllocationTypeValue & MemResetUndo) != 0;
+ if (Reset || ResetUndo)
+ {
+ if ((Reset && ResetUndo) || (Reset && AllocationTypeValue != MemReset) || (ResetUndo && AllocationTypeValue != MemResetUndo))
+ return NTSTATUS.STATUS_INVALID_PARAMETER;
+
+ ulong BaseAddressReset = Instance.ReadMemoryUInt(BaseAddressPtr);
+ ulong RegionSizeReset = BinaryEmulator.AlignUp(RegionSizeRaw32, PageSize);
+ if (!TryApplyResetState(Instance, BaseAddressReset, RegionSizeReset, Reset, out NTSTATUS ResetStatus))
+ return ResetStatus;
+
+ if (!Instance._emulator.WriteMemory(BaseAddressPtr, (uint)BaseAddressReset))
+ return NTSTATUS.STATUS_ACCESS_VIOLATION;
+
+ if (!Instance._emulator.WriteMemory(RegionSizePtr, (uint)RegionSizeReset))
+ return NTSTATUS.STATUS_ACCESS_VIOLATION;
+
+ return NTSTATUS.STATUS_SUCCESS;
+ }
+
ulong RegionSize = BinaryEmulator.AlignUp(RegionSizeRaw32, PageSize);
ulong BaseAddress = Instance.ReadMemoryUInt(BaseAddressPtr);
From 47bf250318d5c5dc063df36bbf260337d69d2ae6 Mon Sep 17 00:00:00 2001
From: Ezz Aldeen Bayoumi <90452585+AdvDebug@users.noreply.github.com>
Date: Thu, 4 Jun 2026 12:59:43 +0300
Subject: [PATCH 4/5] Editing NtAllocateVirtualMemory to have the latest
changes with the fixes
---
.../Process/NtAllocateVirtualMemory.cs | 125 +++++++++++++++++-
1 file changed, 119 insertions(+), 6 deletions(-)
diff --git a/Brovan/Core/Emulation/OS/Windows/Process/NtAllocateVirtualMemory.cs b/Brovan/Core/Emulation/OS/Windows/Process/NtAllocateVirtualMemory.cs
index 85f0b76..9d9eca6 100644
--- a/Brovan/Core/Emulation/OS/Windows/Process/NtAllocateVirtualMemory.cs
+++ b/Brovan/Core/Emulation/OS/Windows/Process/NtAllocateVirtualMemory.cs
@@ -7,6 +7,79 @@ internal class NtAllocateVirtualMemory : IWinSyscall
{
private const ulong PageSize = 0x1000;
private const ulong AllocationGranularity = 0x10000;
+ private const ulong MemReset = 0x00080000UL;
+ private const ulong MemResetUndo = 0x01000000UL;
+
+ private static bool TryApplyResetState(BinaryEmulator Instance, ulong BaseAddress, ulong RegionSize, bool Reset, out NTSTATUS Status)
+ {
+ Status = NTSTATUS.STATUS_SUCCESS;
+
+ if (BaseAddress == 0 || RegionSize == 0)
+ {
+ Status = NTSTATUS.STATUS_INVALID_PARAMETER;
+ return false;
+ }
+
+ if ((BaseAddress & (PageSize - 1)) != 0 || (RegionSize & (PageSize - 1)) != 0)
+ {
+ Status = NTSTATUS.STATUS_CONFLICTING_ADDRESSES;
+ return false;
+ }
+
+ ulong End = BaseAddress + RegionSize;
+ if (End < BaseAddress)
+ {
+ Status = NTSTATUS.STATUS_CONFLICTING_ADDRESSES;
+ return false;
+ }
+
+ ulong Current = BaseAddress;
+ ulong AllocationBase = 0;
+ bool HasAllocationBase = false;
+
+ while (Current < End)
+ {
+ if (!Instance.TryFindMemoryRegionIndex(Current, out int Index) || !Instance.TryFindMemoryRegion(Current, out MemoryRegion Region))
+ {
+ Status = NTSTATUS.STATUS_MEMORY_NOT_ALLOCATED;
+ return false;
+ }
+
+ if (!Region.IsReserved || !Region.IsCommitted)
+ {
+ Status = NTSTATUS.STATUS_MEMORY_NOT_ALLOCATED;
+ return false;
+ }
+
+ if (!HasAllocationBase)
+ {
+ AllocationBase = Region.AllocationBase;
+ HasAllocationBase = true;
+ }
+ else if (Region.AllocationBase != AllocationBase)
+ {
+ Status = NTSTATUS.STATUS_MEMORY_NOT_ALLOCATED;
+ return false;
+ }
+
+ ulong RegionEnd = Region.BaseAddress + Region.Size;
+ if (RegionEnd <= Current)
+ {
+ Status = NTSTATUS.STATUS_MEMORY_NOT_ALLOCATED;
+ return false;
+ }
+
+ if (Region.IsReset != Reset)
+ {
+ Region.IsReset = Reset;
+ Instance.SetMemoryRegion(Index, Region);
+ }
+
+ Current = Math.Min(RegionEnd, End);
+ }
+
+ return true;
+ }
///
/// Finds a free base address (allocation granularity aligned) that does not overlap any existing region.
@@ -71,13 +144,33 @@ public NTSTATUS Handle(BinaryEmulator Instance)
if (RegionSizeRaw == 0 || AllocationTypeValue == 0 || ProtectValue == 0)
return NTSTATUS.STATUS_INVALID_PARAMETER;
- RegionSize = BinaryEmulator.AlignUp(RegionSizeRaw, PageSize);
-
ulong BaseAddress = Instance.ReadMemoryULong(BaseAddressPtr);
bool Reserve = (AllocationTypeValue & 0x2000UL) != 0; // MEM_RESERVE
bool Commit = (AllocationTypeValue & 0x1000UL) != 0; // MEM_COMMIT
+ bool Reset = (AllocationTypeValue & MemReset) != 0;
+ bool ResetUndo = (AllocationTypeValue & MemResetUndo) != 0;
+ if (Reset || ResetUndo)
+ {
+ if ((Reset && ResetUndo) || (Reset && AllocationTypeValue != MemReset) || (ResetUndo && AllocationTypeValue != MemResetUndo))
+ return NTSTATUS.STATUS_INVALID_PARAMETER;
+
+ ulong ResetRegionSize = BinaryEmulator.AlignUp(RegionSizeRaw, PageSize);
+ if (!TryApplyResetState(Instance, BaseAddress, ResetRegionSize, Reset, out NTSTATUS ResetStatus))
+ return ResetStatus;
+
+ if (!Instance._emulator.WriteMemory(BaseAddressPtr, BaseAddress))
+ return NTSTATUS.STATUS_ACCESS_VIOLATION;
+
+ if (!Instance._emulator.WriteMemory(RegionSizePtr, ResetRegionSize))
+ return NTSTATUS.STATUS_ACCESS_VIOLATION;
+
+ return NTSTATUS.STATUS_SUCCESS;
+ }
+
+ RegionSize = BinaryEmulator.AlignUp(RegionSizeRaw, PageSize);
+
Instance.TriggerEventMessage($"[+] NtAllocateVirtualMemory (BaseAddress: 0x{BaseAddress:X}, RegionSize: {RegionSize}, Commit: {Commit}, Reserve: {Reserve})", LogFlags.Syscall);
if (!Reserve && Commit && BaseAddress == 0)
@@ -157,13 +250,33 @@ public NTSTATUS Handle(BinaryEmulator Instance)
if (RegionSizeRaw == 0 || AllocationTypeValue == 0 || ProtectValue == 0)
return NTSTATUS.STATUS_INVALID_PARAMETER;
- RegionSize = BinaryEmulator.AlignUp(RegionSizeRaw, PageSize);
-
uint BaseAddress32 = Instance.ReadMemoryUInt(BaseAddressPtr);
ulong BaseAddress = BaseAddress32;
bool Reserve = (AllocationTypeValue & 0x2000U) != 0; // MEM_RESERVE
- bool Commit = (AllocationTypeValue & 0x1000U) != 0; // MEM_COMMIT
+ bool Commit = (AllocationTypeValue & 0x1000U) != 0; // MEM_COMMIT
+
+ bool Reset = (AllocationTypeValue & MemReset) != 0;
+ bool ResetUndo = (AllocationTypeValue & MemResetUndo) != 0;
+ if (Reset || ResetUndo)
+ {
+ if ((Reset && ResetUndo) || (Reset && AllocationTypeValue != MemReset) || (ResetUndo && AllocationTypeValue != MemResetUndo))
+ return NTSTATUS.STATUS_INVALID_PARAMETER;
+
+ ulong ResetRegionSize = BinaryEmulator.AlignUp(RegionSizeRaw, PageSize);
+ if (!TryApplyResetState(Instance, BaseAddress, ResetRegionSize, Reset, out NTSTATUS ResetStatus))
+ return ResetStatus;
+
+ if (!Instance._emulator.WriteMemory(BaseAddressPtr, (uint)BaseAddress))
+ return NTSTATUS.STATUS_ACCESS_VIOLATION;
+
+ if (!Instance._emulator.WriteMemory(RegionSizePtr, (uint)ResetRegionSize))
+ return NTSTATUS.STATUS_ACCESS_VIOLATION;
+
+ return NTSTATUS.STATUS_SUCCESS;
+ }
+
+ RegionSize = BinaryEmulator.AlignUp(RegionSizeRaw, PageSize);
Instance.TriggerEventMessage($"[+] NtAllocateVirtualMemory (BaseAddress: 0x{BaseAddress:X}, RegionSize: {RegionSize}, Commit: {Commit}, Reserve: {Reserve})", LogFlags.Syscall);
@@ -203,4 +316,4 @@ public NTSTATUS Handle(BinaryEmulator Instance)
}
}
}
-}
\ No newline at end of file
+}
From 453b0b9d3bd4dd260fae16ab3099dc92c1e4d684 Mon Sep 17 00:00:00 2001
From: Ezz Aldeen Bayoumi <90452585+AdvDebug@users.noreply.github.com>
Date: Thu, 4 Jun 2026 13:32:26 +0300
Subject: [PATCH 5/5] Adding more robust build config
---
Brovan/Brovan.csproj | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/Brovan/Brovan.csproj b/Brovan/Brovan.csproj
index 99d708c..e7424db 100644
--- a/Brovan/Brovan.csproj
+++ b/Brovan/Brovan.csproj
@@ -1,4 +1,4 @@
-
+
Exe
@@ -33,8 +33,13 @@
-
-
+
+ <_ModifiedTargetPath>$([System.String]::Copy('$(TargetPath)').Replace('.dll', '.exe'))
+
+
+
+
+