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')) + + + + +