diff --git a/CsWhispers.Generator/CsWhispers.Generator.csproj b/CsWhispers.Generator/CsWhispers.Generator.csproj index 2d96bb3..6ddb44b 100644 --- a/CsWhispers.Generator/CsWhispers.Generator.csproj +++ b/CsWhispers.Generator/CsWhispers.Generator.csproj @@ -4,7 +4,7 @@ netstandard2.0 enable enable - 12 + 12.0 true true false @@ -18,6 +18,8 @@ CsWhispers Source generator to add D/Invoke and indirect syscall methods to a C# project. Copyright (c) Daniel Duggan 2024 + Debug + AnyCPU;x86 @@ -28,10 +30,6 @@ true - - true - - all diff --git a/CsWhispers.Generator/Source/MEMORY_BASIC_INFORMATION.cs b/CsWhispers.Generator/Source/MEMORY_BASIC_INFORMATION.cs index 2ca6531..bf1dea2 100644 --- a/CsWhispers.Generator/Source/MEMORY_BASIC_INFORMATION.cs +++ b/CsWhispers.Generator/Source/MEMORY_BASIC_INFORMATION.cs @@ -2,12 +2,11 @@ public unsafe struct MEMORY_BASIC_INFORMATION { - void* BaseAddress; - void* AllocationBase; - uint AllocationProtect; - ushort PartitionId; - nuint RegionSize; - uint State; - uint Protect; - uint Type; + public void* BaseAddress; + public void* AllocationBase; + public uint AllocationProtect; + public nuint RegionSize; + public uint State; + public uint Protect; + public uint Type; } \ No newline at end of file diff --git a/CsWhispers.Generator/Source/NtAllocateVirtualMemory.cs b/CsWhispers.Generator/Source/NtAllocateVirtualMemory.cs index 9d113c6..9149a1f 100644 --- a/CsWhispers.Generator/Source/NtAllocateVirtualMemory.cs +++ b/CsWhispers.Generator/Source/NtAllocateVirtualMemory.cs @@ -6,6 +6,8 @@ public static unsafe partial class Syscalls { private const string ZwAllocateVirtualMemoryHash = "D80FB8F3EA00B69B2CAAB144EB70BE34"; + private static int NtAllocateVirtualMemoryJit() { return 5; } + public static NTSTATUS NtAllocateVirtualMemory( HANDLE processHandle, void* baseAddress, @@ -18,15 +20,7 @@ public static NTSTATUS NtAllocateVirtualMemory( fixed (byte* buffer = stub) { - var ptr = (IntPtr)buffer; - var size = new IntPtr(stub.Length); - - Native.NtProtectVirtualMemory( - new HANDLE((IntPtr)(-1)), - ref ptr, - ref size, - 0x00000020, - out var oldProtect); + IntPtr ptr = PrepareJit(nameof(NtAllocateVirtualMemoryJit), buffer, stub.Length); var ntAllocateVirtualMemory = Marshal.GetDelegateForFunctionPointer(ptr); @@ -38,13 +32,6 @@ public static NTSTATUS NtAllocateVirtualMemory( allocationType, protect); - Native.NtProtectVirtualMemory( - new HANDLE((IntPtr)(-1)), - ref ptr, - ref size, - oldProtect, - out _); - return status; } } diff --git a/CsWhispers.Generator/Source/NtClose.cs b/CsWhispers.Generator/Source/NtClose.cs index f4ce33f..1bbd640 100644 --- a/CsWhispers.Generator/Source/NtClose.cs +++ b/CsWhispers.Generator/Source/NtClose.cs @@ -4,7 +4,9 @@ namespace CsWhispers; public static unsafe partial class Syscalls { - private const string ZwCloseHash = "F11693417BD581AAA27083765DB7A812"; + private const string ZwCloseHash = "D5E973CE71E99CE43DB3C3FFFFEB4623"; + + private static int NtCloseJit() { return 5; } public static NTSTATUS NtClose(HANDLE handle) { @@ -12,27 +14,12 @@ public static NTSTATUS NtClose(HANDLE handle) fixed (byte* buffer = stub) { - var ptr = (IntPtr)buffer; - var size = new IntPtr(stub.Length); - - Native.NtProtectVirtualMemory( - new HANDLE((IntPtr)(-1)), - ref ptr, - ref size, - 0x00000020, - out var oldProtect); + IntPtr ptr = PrepareJit(nameof(NtCloseJit), buffer, stub.Length); var ntClose = Marshal.GetDelegateForFunctionPointer(ptr); var status = ntClose(handle); - Native.NtProtectVirtualMemory( - new HANDLE((IntPtr)(-1)), - ref ptr, - ref size, - oldProtect, - out _); - return status; } } diff --git a/CsWhispers.Generator/Source/NtCreateSection.cs b/CsWhispers.Generator/Source/NtCreateSection.cs index 0647ade..daadde3 100644 --- a/CsWhispers.Generator/Source/NtCreateSection.cs +++ b/CsWhispers.Generator/Source/NtCreateSection.cs @@ -6,6 +6,8 @@ public static unsafe partial class Syscalls { private const string ZwCreateSectionHash = "12C4C6E5EB9B290330CA3A7E5D43D0FA"; + private static int NtCreateSectionJit() { return 5; } + public static NTSTATUS NtCreateSection( HANDLE* sectionHandle, uint desiredAccess, @@ -19,15 +21,7 @@ public static NTSTATUS NtCreateSection( fixed (byte* buffer = stub) { - var ptr = (IntPtr)buffer; - var size = new IntPtr(stub.Length); - - Native.NtProtectVirtualMemory( - new HANDLE((IntPtr)(-1)), - ref ptr, - ref size, - 0x00000020, - out var oldProtect); + IntPtr ptr = PrepareJit(nameof(NtCreateSectionJit), buffer, stub.Length); var ntCreateSection = Marshal.GetDelegateForFunctionPointer(ptr); @@ -40,13 +34,6 @@ public static NTSTATUS NtCreateSection( allocationAttributes, fileHandle); - Native.NtProtectVirtualMemory( - new HANDLE((IntPtr)(-1)), - ref ptr, - ref size, - oldProtect, - out _); - return status; } } diff --git a/CsWhispers.Generator/Source/NtCreateThreadEx.cs b/CsWhispers.Generator/Source/NtCreateThreadEx.cs index ae64648..423978c 100644 --- a/CsWhispers.Generator/Source/NtCreateThreadEx.cs +++ b/CsWhispers.Generator/Source/NtCreateThreadEx.cs @@ -5,7 +5,9 @@ namespace CsWhispers; public static unsafe partial class Syscalls { private const string ZwCreateThreadExHash = "434AE47989589026C54B874E5D12D365"; - + + private static int NtCreateThreadExJit() { return 5; } + public static NTSTATUS NtCreateThreadEx( HANDLE* threadHandle, uint desiredAccess, @@ -23,15 +25,7 @@ public static NTSTATUS NtCreateThreadEx( fixed (byte* buffer = stub) { - var ptr = (IntPtr)buffer; - var size = new IntPtr(stub.Length); - - Native.NtProtectVirtualMemory( - new HANDLE((IntPtr)(-1)), - ref ptr, - ref size, - 0x00000020, - out var oldProtect); + IntPtr ptr = PrepareJit(nameof(NtCreateThreadExJit), buffer, stub.Length); var ntCreateThreadEx = Marshal.GetDelegateForFunctionPointer(ptr); @@ -48,13 +42,6 @@ public static NTSTATUS NtCreateThreadEx( maximumStackSize, attributeList); - Native.NtProtectVirtualMemory( - new HANDLE((IntPtr)(-1)), - ref ptr, - ref size, - oldProtect, - out _); - return status; } } diff --git a/CsWhispers.Generator/Source/NtFreeVirtualMemory.cs b/CsWhispers.Generator/Source/NtFreeVirtualMemory.cs index 7e924a1..609adbf 100644 --- a/CsWhispers.Generator/Source/NtFreeVirtualMemory.cs +++ b/CsWhispers.Generator/Source/NtFreeVirtualMemory.cs @@ -6,25 +6,19 @@ public static unsafe partial class Syscalls { private const string ZwFreeVirtualMemoryHash = "A2356248E8839427AE2D390367DC1A40"; + private static int NtFreeVirtualMemoryJit() { return 5; } + public static NTSTATUS NtFreeVirtualMemory( HANDLE processHandle, void* baseAddress, uint* regionSize, uint freeType) { - var stub = GetSyscallStub(ZwCloseHash); + var stub = GetSyscallStub(ZwFreeVirtualMemoryHash); fixed (byte* buffer = stub) { - var ptr = (IntPtr)buffer; - var size = new IntPtr(stub.Length); - - Native.NtProtectVirtualMemory( - new HANDLE((IntPtr)(-1)), - ref ptr, - ref size, - 0x00000020, - out var oldProtect); + IntPtr ptr = PrepareJit(nameof(NtFreeVirtualMemoryJit), buffer, stub.Length); var ntFreeVirtualMemory = Marshal.GetDelegateForFunctionPointer(ptr); @@ -34,13 +28,6 @@ public static NTSTATUS NtFreeVirtualMemory( regionSize, freeType); - Native.NtProtectVirtualMemory( - new HANDLE((IntPtr)(-1)), - ref ptr, - ref size, - oldProtect, - out _); - return status; } } diff --git a/CsWhispers.Generator/Source/NtMapViewOfSection.cs b/CsWhispers.Generator/Source/NtMapViewOfSection.cs index ac098f4..d73c25e 100644 --- a/CsWhispers.Generator/Source/NtMapViewOfSection.cs +++ b/CsWhispers.Generator/Source/NtMapViewOfSection.cs @@ -6,6 +6,8 @@ public static unsafe partial class Syscalls { private const string ZwMapViewOfSectionHash = "C72A45E418708097B7D23865D6187D5E"; + private static int NtMapViewOfSectionJit() { return 5; } + public static NTSTATUS NtMapViewOfSection( HANDLE sectionHandle, HANDLE processHandle, @@ -22,15 +24,7 @@ public static NTSTATUS NtMapViewOfSection( fixed (byte* buffer = stub) { - var ptr = (IntPtr)buffer; - var size = new IntPtr(stub.Length); - - Native.NtProtectVirtualMemory( - new HANDLE((IntPtr)(-1)), - ref ptr, - ref size, - 0x00000020, - out var oldProtect); + IntPtr ptr = PrepareJit(nameof(NtMapViewOfSectionJit), buffer, stub.Length); var ntMapViewOfSection = Marshal.GetDelegateForFunctionPointer(ptr); @@ -46,13 +40,6 @@ public static NTSTATUS NtMapViewOfSection( allocationType, win32Protect); - Native.NtProtectVirtualMemory( - new HANDLE((IntPtr)(-1)), - ref ptr, - ref size, - oldProtect, - out _); - return status; } } diff --git a/CsWhispers.Generator/Source/NtOpenFile.cs b/CsWhispers.Generator/Source/NtOpenFile.cs index 7a801f9..a2b4500 100644 --- a/CsWhispers.Generator/Source/NtOpenFile.cs +++ b/CsWhispers.Generator/Source/NtOpenFile.cs @@ -6,6 +6,8 @@ public static unsafe partial class Syscalls { private const string ZwOpenFileHash = "568DFAF213A08F28C9D58D1234D4218A"; + private static int NtOpenFileJit() { return 5; } + public static NTSTATUS NtOpenFile( HANDLE* fileHandle, uint desiredAccess, @@ -18,15 +20,7 @@ public static NTSTATUS NtOpenFile( fixed (byte* buffer = stub) { - var ptr = (IntPtr)buffer; - var size = new IntPtr(stub.Length); - - Native.NtProtectVirtualMemory( - new HANDLE((IntPtr)(-1)), - ref ptr, - ref size, - 0x00000020, - out var oldProtect); + IntPtr ptr = PrepareJit(nameof(NtOpenFileJit), buffer, stub.Length); var ntOpenFile = Marshal.GetDelegateForFunctionPointer(ptr); @@ -38,13 +32,6 @@ public static NTSTATUS NtOpenFile( shareAccess, openOptions); - Native.NtProtectVirtualMemory( - new HANDLE((IntPtr)(-1)), - ref ptr, - ref size, - oldProtect, - out _); - return status; } } diff --git a/CsWhispers.Generator/Source/NtOpenProcess.cs b/CsWhispers.Generator/Source/NtOpenProcess.cs index f0ad6c9..fc517af 100644 --- a/CsWhispers.Generator/Source/NtOpenProcess.cs +++ b/CsWhispers.Generator/Source/NtOpenProcess.cs @@ -6,6 +6,8 @@ public static unsafe partial class Syscalls { private const string ZwOpenProcessHash = "00B6CA92B16374B1C81FC54DFE03DF52"; + private static int NtOpenProcessJit() { return 5; } + public static NTSTATUS NtOpenProcess( HANDLE* processHandle, uint desiredAccess, @@ -13,34 +15,18 @@ public static NTSTATUS NtOpenProcess( CLIENT_ID* clientId) { var stub = GetSyscallStub(ZwOpenProcessHash); - fixed (byte* buffer = stub) { - var ptr = (IntPtr)buffer; - var size = new IntPtr(stub.Length); + IntPtr ptr = PrepareJit(nameof(NtOpenProcessJit), buffer, stub.Length); - Native.NtProtectVirtualMemory( - new HANDLE((IntPtr)(-1)), - ref ptr, - ref size, - 0x00000020, - out var oldProtect); - var ntOpenProcess = Marshal.GetDelegateForFunctionPointer(ptr); - + var status = ntOpenProcess( processHandle, desiredAccess, objectAttributes, clientId); - Native.NtProtectVirtualMemory( - new HANDLE((IntPtr)(-1)), - ref ptr, - ref size, - oldProtect, - out _); - return status; } } diff --git a/CsWhispers.Generator/Source/NtProtectVirtualMemory.cs b/CsWhispers.Generator/Source/NtProtectVirtualMemory.cs index 3f3f26d..fd88f53 100644 --- a/CsWhispers.Generator/Source/NtProtectVirtualMemory.cs +++ b/CsWhispers.Generator/Source/NtProtectVirtualMemory.cs @@ -6,6 +6,8 @@ public static unsafe partial class Syscalls { private const string ZwProtectVirtualMemoryHash = "95429C4A177A230D88166479D035C143"; + private static int NtProtectVirtualMemoryJit() { return 5; } + public static NTSTATUS NtProtectVirtualMemory( HANDLE processHandle, void* baseAddress, @@ -17,15 +19,7 @@ public static NTSTATUS NtProtectVirtualMemory( fixed (byte* buffer = stub) { - var ptr = (IntPtr)buffer; - var size = new IntPtr(stub.Length); - - Native.NtProtectVirtualMemory( - new HANDLE((IntPtr)(-1)), - ref ptr, - ref size, - 0x00000020, - out var oldProtect); + IntPtr ptr = PrepareJit(nameof(NtProtectVirtualMemoryJit), buffer, stub.Length); var ntProtectVirtualMemory = Marshal.GetDelegateForFunctionPointer(ptr); @@ -36,13 +30,6 @@ public static NTSTATUS NtProtectVirtualMemory( newAccessProtection, oldAccessProtection); - Native.NtProtectVirtualMemory( - new HANDLE((IntPtr)(-1)), - ref ptr, - ref size, - oldProtect, - out _); - return status; } } diff --git a/CsWhispers.Generator/Source/NtQueryVirtualMemory.cs b/CsWhispers.Generator/Source/NtQueryVirtualMemory.cs index 15dacb7..9e454be 100644 --- a/CsWhispers.Generator/Source/NtQueryVirtualMemory.cs +++ b/CsWhispers.Generator/Source/NtQueryVirtualMemory.cs @@ -6,6 +6,8 @@ public static unsafe partial class Syscalls { private const string ZwQueryVirtualMemoryHash = "0F4ECCBB2DFD9932319A2C18098B34E6"; + private static int NtQueryVirtualMemoryJit() { return 5; } + public static NTSTATUS NtQueryVirtualMemory( HANDLE processHandle, void* baseAddress, @@ -18,15 +20,7 @@ public static NTSTATUS NtQueryVirtualMemory( fixed (byte* temp = stub) { - var ptr = (IntPtr)temp; - var size = new IntPtr(stub.Length); - - Native.NtProtectVirtualMemory( - new HANDLE((IntPtr)(-1)), - ref ptr, - ref size, - 0x00000020, - out var oldProtect); + IntPtr ptr = PrepareJit(nameof(NtQueryVirtualMemoryJit), temp, stub.Length); var ntQueryVirtualMemory = Marshal.GetDelegateForFunctionPointer(ptr); @@ -38,13 +32,6 @@ public static NTSTATUS NtQueryVirtualMemory( length, resultLength); - Native.NtProtectVirtualMemory( - new HANDLE((IntPtr)(-1)), - ref ptr, - ref size, - oldProtect, - out _); - return status; } } diff --git a/CsWhispers.Generator/Source/NtReadVirtualMemory.cs b/CsWhispers.Generator/Source/NtReadVirtualMemory.cs index f120d4a..f9040cf 100644 --- a/CsWhispers.Generator/Source/NtReadVirtualMemory.cs +++ b/CsWhispers.Generator/Source/NtReadVirtualMemory.cs @@ -6,6 +6,8 @@ public static unsafe partial class Syscalls { private const string ZwReadVirtualMemoryHash = "A2EAF21913E6BA93656FC0BEC4F1B7B1"; + private static int NtReadVirtualMemoryJit() { return 5; } + public static NTSTATUS NtReadVirtualMemory( HANDLE processHandle, void* baseAddress, @@ -17,15 +19,7 @@ public static NTSTATUS NtReadVirtualMemory( fixed (byte* temp = stub) { - var ptr = (IntPtr)temp; - var size = new IntPtr(stub.Length); - - Native.NtProtectVirtualMemory( - new HANDLE((IntPtr)(-1)), - ref ptr, - ref size, - 0x00000020, - out var oldProtect); + IntPtr ptr = PrepareJit(nameof(NtReadVirtualMemoryJit), temp, stub.Length); var ntReadVirtualMemory = Marshal.GetDelegateForFunctionPointer(ptr); @@ -36,13 +30,6 @@ public static NTSTATUS NtReadVirtualMemory( numberOfBytesToRead, numberOfBytesRead); - Native.NtProtectVirtualMemory( - new HANDLE((IntPtr)(-1)), - ref ptr, - ref size, - oldProtect, - out _); - return status; } } diff --git a/CsWhispers.Generator/Source/NtUnmapViewOfSection.cs b/CsWhispers.Generator/Source/NtUnmapViewOfSection.cs index af049bc..f0613f4 100644 --- a/CsWhispers.Generator/Source/NtUnmapViewOfSection.cs +++ b/CsWhispers.Generator/Source/NtUnmapViewOfSection.cs @@ -6,6 +6,8 @@ public static unsafe partial class Syscalls { private const string ZwUnmapViewOfSectionHash = "57447AEA45A1F4B2C045B0E316FE8F12"; + private static int NtUnmapViewOfSectionJit() { return 5; } + public static NTSTATUS NtUnmapViewOfSection( HANDLE processHandle, [Optional] void* baseAddress) @@ -14,15 +16,7 @@ public static NTSTATUS NtUnmapViewOfSection( fixed (byte* buffer = stub) { - var ptr = (IntPtr)buffer; - var size = new IntPtr(stub.Length); - - Native.NtProtectVirtualMemory( - new HANDLE((IntPtr)(-1)), - ref ptr, - ref size, - 0x00000020, - out var oldProtect); + IntPtr ptr = PrepareJit(nameof(NtUnmapViewOfSectionJit), buffer, stub.Length); var ntUnmapViewOfSection = Marshal.GetDelegateForFunctionPointer(ptr); @@ -30,13 +24,6 @@ public static NTSTATUS NtUnmapViewOfSection( processHandle, baseAddress); - Native.NtProtectVirtualMemory( - new HANDLE((IntPtr)(-1)), - ref ptr, - ref size, - oldProtect, - out _); - return status; } } diff --git a/CsWhispers.Generator/Source/NtWriteVirtualMemory.cs b/CsWhispers.Generator/Source/NtWriteVirtualMemory.cs index 401d03c..f15ec02 100644 --- a/CsWhispers.Generator/Source/NtWriteVirtualMemory.cs +++ b/CsWhispers.Generator/Source/NtWriteVirtualMemory.cs @@ -6,6 +6,8 @@ public static unsafe partial class Syscalls { private const string ZwWriteVirtualMemoryHash = "8ECD3BD989CAB9EFE34A0625285BAA0F"; + private static int NtWriteVirtualMemoryJit() { return 5; } + public static NTSTATUS NtWriteVirtualMemory( HANDLE processHandle, void* baseAddress, @@ -17,15 +19,7 @@ public static NTSTATUS NtWriteVirtualMemory( fixed (byte* temp = stub) { - var ptr = (IntPtr)temp; - var size = new IntPtr(stub.Length); - - Native.NtProtectVirtualMemory( - new HANDLE((IntPtr)(-1)), - ref ptr, - ref size, - 0x00000020, - out var oldProtect); + IntPtr ptr = PrepareJit(nameof(NtWriteVirtualMemoryJit), temp, stub.Length); var ntWriteVirtualMemory = Marshal.GetDelegateForFunctionPointer(ptr); @@ -36,13 +30,6 @@ public static NTSTATUS NtWriteVirtualMemory( numberOfBytesToWrite, numberOfBytesWritten); - Native.NtProtectVirtualMemory( - new HANDLE((IntPtr)(-1)), - ref ptr, - ref size, - oldProtect, - out _); - return status; } } diff --git a/CsWhispers.Generator/Source/Syscalls.cs b/CsWhispers.Generator/Source/Syscalls.cs index ae225ff..cbd3aeb 100644 --- a/CsWhispers.Generator/Source/Syscalls.cs +++ b/CsWhispers.Generator/Source/Syscalls.cs @@ -1,10 +1,12 @@ using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Text; +using System.Runtime.CompilerServices; +using System.Reflection; namespace CsWhispers; -public static partial class Syscalls +public unsafe static partial class Syscalls { private const long Key = 0xdeadbeef; private static readonly List SyscallList = []; @@ -17,26 +19,143 @@ public static partial class Syscalls 0x41, 0xFF, 0xE3 // jmp r11 ]; - private static byte[] GetSyscallStub(string functionHash) + private static readonly byte[] Wow64IndirectSyscallStub = + [ + 0xB8, 0x00, 0x00, 0x00, 0x00, // mov eax, ssn + 0xBA, 0x00, 0x00, 0x00, 0x00, // mov edx, < wow64 transition > + 0xB9, 0x00, 0x00, 0x00, 0x00, // mov ecx, < address of [call edx] > + 0xFF, 0xE1 // jmp ecx + ]; + + private unsafe static IntPtr PrepareJit(string func, byte* buffer, int length) + { + IntPtr ptr; + MethodInfo method = typeof(Syscalls).GetMethod(func, BindingFlags.Static | BindingFlags.NonPublic); + RuntimeHelpers.PrepareMethod(method.MethodHandle); + + IntPtr pMethod = method.MethodHandle.GetFunctionPointer(); + if (Marshal.ReadByte(pMethod) != 0xe9) + { + ptr = pMethod; + } + else + { + Int32 offset = Marshal.ReadInt32(pMethod, 1); + UInt64 addr = (UInt64)pMethod + (UInt64)offset; + while (addr % 16 != 0) addr++; + ptr = (IntPtr)addr; + } + + for (int i = 0; i < length; i++) + { + *(byte*)IntPtr.Add(ptr, i) = *(byte*)(IntPtr.Add((IntPtr)buffer, i)); + } + + return ptr; + } + + private unsafe static byte[] GetSyscallStub(string functionHash) { var ssn = GetSyscallNumber(functionHash); var syscall = SyscallList[ssn]; - var stub = X64IndirectSyscallStub; - stub[4] = (byte)ssn; - var address = BitConverter.GetBytes((long)syscall.Address + 18); - Buffer.BlockCopy(address, 0, stub, 10, address.Length); + byte[] stub; + + if (IntPtr.Size == 8) + { + stub = X64IndirectSyscallStub; + stub[4] = (byte)ssn; + + var address = new byte[8]; + var delta = 0; + + while (true) + { + if (ssn - delta >= 0) + address = BitConverter.GetBytes((long)SyscallList[ssn - delta].Address + 18); + if (*(ushort*)BitConverter.ToUInt64(address, 0) == 0x050F) + break; + + if (ssn + delta < SyscallList.Count) + address = BitConverter.GetBytes((long)SyscallList[ssn + delta].Address + 18); + if (*(ushort*)BitConverter.ToUInt64(address, 0) == 0x050F) + break; + + // Todo: Handle case where we somehow get no stub(??) + if (ssn - delta <= 0 && ssn + delta > SyscallList.Count) + break; + + delta++; + } + Buffer.BlockCopy(address, 0, stub, 10, address.Length); + } + else + { + stub = Wow64IndirectSyscallStub; + stub[1] = (byte)ssn; + + var address = new byte[4]; + var delta = 0; + + // Get the Wow64Transition Address + while (true) + { + if (ssn - delta >= 0) + address = BitConverter.GetBytes((uint)SyscallList[ssn - delta].Address); + if (*(byte*)(BitConverter.ToUInt32(address, 0) + 0x5) == 0xBA && + *(ushort*)(BitConverter.ToUInt32(address, 0) + 0xA) == 0xD2FF) + break; + + if (ssn + delta < SyscallList.Count) + address = BitConverter.GetBytes((uint)SyscallList[ssn + delta].Address); + if (*(byte*)(BitConverter.ToUInt32(address, 0) + 0x5) == 0xBA && + *(ushort*)(BitConverter.ToUInt32(address, 0) + 0xA) == 0xD2FF) + break; + + // Todo: Handle case where we somehow get no stub(??) + if (ssn - delta <= 0 && ssn + delta > SyscallList.Count) + break; + + delta++; + } + var Wow64Value = BitConverter.GetBytes(*(uint*)(BitConverter.ToUInt32(address, 0) + 0x6)); + Buffer.BlockCopy(Wow64Value, 0, stub, 6, Wow64Value.Length); + + // Get the call edx + delta = 0; + while (true) + { + if (ssn - delta >= 0) + address = BitConverter.GetBytes((uint)SyscallList[ssn - delta].Address + 0xA); + if (*(ushort*)BitConverter.ToUInt32(address, 0) == 0xD2FF) + break; + + if (ssn + delta < SyscallList.Count) + address = BitConverter.GetBytes((uint)SyscallList[ssn + delta].Address + 0xA); + if (*(ushort*)BitConverter.ToUInt32(address, 0) == 0xD2FF) + break; + + if (ssn - delta <= 0 && ssn + delta > SyscallList.Count) + break; + + delta++; + } + Buffer.BlockCopy(address, 0, stub, 11, address.Length); + } return stub; } - + private static int GetSyscallNumber(string functionHash) { - var hModule = Generic.GetLoadedModuleAddress("ntdll.dll"); - if (!PopulateSyscallList(hModule)) - return -1; + if (SyscallList.Count == 0) + { + var hModule = Generic.GetLoadedModuleAddress("ntdll.dll"); + if (!PopulateSyscallList(hModule)) + return -1; + } for (var i = 0; i < SyscallList.Count; i++) if (functionHash.Equals(SyscallList[i].Hash, StringComparison.OrdinalIgnoreCase)) @@ -47,10 +166,6 @@ private static int GetSyscallNumber(string functionHash) private static bool PopulateSyscallList(IntPtr moduleBase) { - // Return early if the list is already populated. - if (SyscallList.Count > 0) - return true; - var functionPtr = IntPtr.Zero; // Temp Entry to assign the attributes values before adding the element to the list diff --git a/CsWhispers.Sample/CsWhispers.Sample.csproj b/CsWhispers.Sample/CsWhispers.Sample.csproj index 0b33f33..274dd7f 100644 --- a/CsWhispers.Sample/CsWhispers.Sample.csproj +++ b/CsWhispers.Sample/CsWhispers.Sample.csproj @@ -1,71 +1,65 @@  - - - Debug - AnyCPU - {F3EFEF07-0F1A-4162-A2D8-56CE9028CB9D} - Exe - Properties - CsWhispers.Sample - CsWhispers.Sample - v4.8.1 - 512 - true - 12 - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - true - false - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - true - false - - - - - - - - - - - - - - {30ce2e3a-61d4-4d06-9280-dc73ca4c32e1} - CsWhispers.Generator - false - Analyzer - - - - - - - - - + \ No newline at end of file diff --git a/CsWhispers.Sample/Program.cs b/CsWhispers.Sample/Program.cs index a2fcc27..fa2ece9 100644 --- a/CsWhispers.Sample/Program.cs +++ b/CsWhispers.Sample/Program.cs @@ -11,13 +11,13 @@ public static void Main(string[] args) NTSTATUS status; HANDLE hProcess; OBJECT_ATTRIBUTES oa; - + // read shellcode var shellcode = File.ReadAllBytes(@"C:\Payloads\msgbox.bin"); - + // inject into self using var self = Process.GetCurrentProcess(); - + var cid = new CLIENT_ID { UniqueProcess = new HANDLE((IntPtr)self.Id) @@ -28,11 +28,11 @@ public static void Main(string[] args) PROCESS_ALL_ACCESS, &oa, &cid); - + // allocate memory void* baseAddress; var szShellcode = (uint)shellcode.Length; - + status = NtAllocateVirtualMemory( hProcess, &baseAddress, @@ -69,5 +69,7 @@ public static void Main(string[] args) 0, 0, null); + + Console.ReadKey(); } } \ No newline at end of file diff --git a/CsWhispers.Sample/app.config b/CsWhispers.Sample/app.config new file mode 100644 index 0000000..312bb3f --- /dev/null +++ b/CsWhispers.Sample/app.config @@ -0,0 +1,3 @@ + + + diff --git a/CsWhispers.Tests/CsWhispers.Tests.csproj b/CsWhispers.Tests/CsWhispers.Tests.csproj index b0f1491..a21ddc2 100644 --- a/CsWhispers.Tests/CsWhispers.Tests.csproj +++ b/CsWhispers.Tests/CsWhispers.Tests.csproj @@ -1,44 +1,125 @@ - - + + + + + + + {FD24F0D1-7C40-4106-A37D-3F10AB825625} + Library + Properties + CsWhispers.Tests + CsWhispers.Tests + v4.7.2 + 512 + bin\Debug\ + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 15.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + 12.0 + true + 15.0 + AnyCPU + false + + + {FD24F0D1-7C40-4106-A37D-3F10AB825625} + + + {FD24F0D1-7C40-4106-A37D-3F10AB825625} + Library + Properties + CsWhispers.Tests + CsWhispers.Tests + v4.7.2 + 512 + bin\x86\Debug\ + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 15.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + 12.0 + true + 15.0 + AnyCPU + false + + + + + ..\packages\Microsoft.TestPlatform.ObjectModel.17.8.0\lib\net462\Microsoft.TestPlatform.CoreUtilities.dll + + + ..\packages\Microsoft.TestPlatform.ObjectModel.17.8.0\lib\net462\Microsoft.TestPlatform.PlatformAbstractions.dll + + + ..\packages\Microsoft.TestPlatform.ObjectModel.17.8.0\lib\net462\Microsoft.VisualStudio.TestPlatform.ObjectModel.dll + + + ..\packages\NuGet.Frameworks.6.5.0\lib\net472\NuGet.Frameworks.dll + + + + ..\packages\System.Collections.Immutable.1.5.0\lib\netstandard2.0\System.Collections.Immutable.dll + + + + + + + ..\packages\System.Reflection.Metadata.1.6.0\lib\netstandard2.0\System.Reflection.Metadata.dll + + + + + + ..\packages\xunit.abstractions.2.0.3\lib\net35\xunit.abstractions.dll + + + ..\packages\xunit.assert.2.7.0\lib\netstandard1.1\xunit.assert.dll + + + ..\packages\xunit.extensibility.core.2.7.0\lib\net452\xunit.core.dll + + + ..\packages\xunit.extensibility.execution.2.7.0\lib\net452\xunit.execution.desktop.dll + + + + + + + + + + + + + + + {30ce2e3a-61d4-4d06-9280-dc73ca4c32e1} + CsWhispers.Generator + false + Analyzer + + + + + + + + + - net8.0 - enable - disable - false - true + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - true - - - - true - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - false - Analyzer - - - - - - - - - + + + + + + \ No newline at end of file diff --git a/CsWhispers.Tests/CsWhispers.txt b/CsWhispers.Tests/CsWhispers.txt index 65b009f..c01a268 100644 --- a/CsWhispers.Tests/CsWhispers.txt +++ b/CsWhispers.Tests/CsWhispers.txt @@ -1,4 +1,16 @@ NtOpenProcess +NtAllocateVirtualMemory +NtProtectVirtualMemory +NtFreeVirtualMemory +NtWriteVirtualMemory +NtReadVirtualMemory +NtQueryVirtualMemory +NtCreateThreadEx +NtOpenFile +NtClose +NtCreateSection +NtMapViewOfSection +NtUnmapViewOfSection NTSTATUS HANDLE @@ -6,4 +18,10 @@ OBJECT_ATTRIBUTES CLIENT_ID UNICODE_STRING PWSTR -PCWSTR \ No newline at end of file +PCWSTR +MEMORY_INFORMATION_CLASS +MEMORY_BASIC_INFORMATION +USER_THREAD_START_ROUTINE +PS_ATTRIBUTE_LIST +IO_STATUS_BLOCK +SECTION_INHERIT \ No newline at end of file diff --git a/CsWhispers.Tests/Properties/AssemblyInfo.cs b/CsWhispers.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..ebcc6d3 --- /dev/null +++ b/CsWhispers.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,20 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("CsWhispers.Tests2")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CsWhispers.Tests2")] +[assembly: AssemblyCopyright("Copyright © 2024")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: ComVisible(false)] + +[assembly: Guid("fd24f0d1-7c40-4106-a37d-3f10ab825625")] + +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/CsWhispers.Tests/SyscallTest.cs b/CsWhispers.Tests/SyscallTest.cs index 2935063..d58eaa7 100644 --- a/CsWhispers.Tests/SyscallTest.cs +++ b/CsWhispers.Tests/SyscallTest.cs @@ -1,21 +1,54 @@ using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; namespace CsWhispers.Tests; public sealed class SyscallTest { [Fact] - public static unsafe void OpenProcess() + public static unsafe void OpenProcess_Hooked() { - using var self = Process.GetCurrentProcess(); + IntPtr pNtOpenProcess = Generic.GetExportAddress(Generic.GetLoadedModuleAddress("ntdll.dll"), "NtOpenProcess"); + IntPtr ogNtOpenProcess = pNtOpenProcess; + + var size = 0; + if (IntPtr.Size == 8) + size = 0x14; + else + size = 0xC; + byte[] patch = new byte[size]; + byte[] ogBytes = new byte[size]; + + uint OldProtect = 0; + uint RegionSize = 0x14; NTSTATUS status; + status = NtProtectVirtualMemory( + new HANDLE((IntPtr)(-1)), + &pNtOpenProcess, + &RegionSize, + PAGE_EXECUTE_READWRITE, + &OldProtect); + + pNtOpenProcess = ogNtOpenProcess; + + Marshal.Copy(pNtOpenProcess, ogBytes, 0, size); + Marshal.Copy(patch, 0, pNtOpenProcess, size); + + using var self = Process.GetCurrentProcess(); + HANDLE hProcess; OBJECT_ATTRIBUTES oa; - + + // IDK WHY WOW64 NEEDS THIS TO BE FILLED I WASTED 5 HOURS ON THIS + if (IntPtr.Size == 4) + { + oa.Length = (uint)sizeof(OBJECT_ATTRIBUTES); + } CLIENT_ID cid = new() { - UniqueProcess = (HANDLE)self.Id + UniqueProcess = new((IntPtr)self.Id) }; status = NtOpenProcess( @@ -23,8 +56,609 @@ public static unsafe void OpenProcess() PROCESS_ALL_ACCESS, &oa, &cid); + + Assert.Equal(NTSTATUS.Severity.Success, status.SeverityCode); + Assert.NotEqual(HANDLE.Null, hProcess); + + Marshal.Copy(ogBytes, 0, pNtOpenProcess, size); + } + + [Fact] + public static unsafe void OpenProcess() + { + using var self = Process.GetCurrentProcess(); + NTSTATUS status; + HANDLE hProcess; + OBJECT_ATTRIBUTES oa; + + CLIENT_ID cid = new() + { + UniqueProcess = new((IntPtr)self.Id) + }; + // IDK WHY WOW64 NEEDS THIS TO BE FILLED I WASTED 5 HOURS ON THIS + if (IntPtr.Size == 4) + { + oa.Length = (uint)sizeof(OBJECT_ATTRIBUTES); + } + status = NtOpenProcess( + &hProcess, + PROCESS_ALL_ACCESS, + &oa, + &cid); + Assert.Equal(NTSTATUS.Severity.Success, status.SeverityCode); Assert.NotEqual(HANDLE.Null, hProcess); } + + [Fact] + public static unsafe void AllocateVirtualMemory() + { + + NTSTATUS status; + HANDLE hProcess = new((IntPtr)(-1)); + void* BaseAddress = (void*)0; + uint RegionSize = 1024; + + + status = NtAllocateVirtualMemory( + hProcess, + &BaseAddress, + 0, + &RegionSize, + MEM_COMMIT | MEM_RESERVE, + PAGE_EXECUTE_READWRITE); + + Assert.Equal(NTSTATUS.Severity.Success, status.SeverityCode); + Assert.NotEqual(IntPtr.Zero, (IntPtr)BaseAddress); + } + + [Fact] + public static unsafe void ProtectVirtualMemory() + { + + NTSTATUS status; + HANDLE hProcess = new((IntPtr)(-1)); + void* BaseAddress = (void*)0; + uint RegionSize = 1024; + + + status = NtAllocateVirtualMemory( + hProcess, + &BaseAddress, + 0, + &RegionSize, + MEM_COMMIT | MEM_RESERVE, + PAGE_EXECUTE_READWRITE); + + Assert.Equal(NTSTATUS.Severity.Success, status.SeverityCode); + Assert.NotEqual(IntPtr.Zero, (IntPtr)BaseAddress); + + uint OldProtect = 0; + status = NtProtectVirtualMemory( + hProcess, + &BaseAddress, + &RegionSize, + PAGE_READWRITE, + &OldProtect); + + Assert.Equal(NTSTATUS.Severity.Success, status.SeverityCode); + Assert.Equal(OldProtect, PAGE_EXECUTE_READWRITE); + + } + + [Fact] + public static unsafe void FreeVirtualMemory() + { + + NTSTATUS status; + HANDLE hProcess = new((IntPtr)(-1)); + void* BaseAddress = (void*)0; + uint RegionSize = 1024; + + + status = NtAllocateVirtualMemory( + hProcess, + &BaseAddress, + 0, + &RegionSize, + MEM_COMMIT | MEM_RESERVE, + PAGE_EXECUTE_READWRITE); + + Assert.Equal(NTSTATUS.Severity.Success, status.SeverityCode); + Assert.NotEqual(IntPtr.Zero, (IntPtr)BaseAddress); + + RegionSize = 0; + status = NtFreeVirtualMemory( + hProcess, + &BaseAddress, + &RegionSize, + MEM_RELEASE); + + Assert.Equal(NTSTATUS.Severity.Success, status.SeverityCode); + Assert.NotEqual((uint)0, RegionSize); + + } + + [Fact] + public static unsafe void WriteVirtualMemory() + { + + NTSTATUS status; + HANDLE hProcess = new((IntPtr)(-1)); + void* BaseAddress = (void*)0; + uint RegionSize = 1024; + + status = NtAllocateVirtualMemory( + hProcess, + &BaseAddress, + 0, + &RegionSize, + MEM_COMMIT | MEM_RESERVE, + PAGE_EXECUTE_READWRITE); + + Assert.Equal(NTSTATUS.Severity.Success, status.SeverityCode); + Assert.NotEqual(IntPtr.Zero, (IntPtr)BaseAddress); + + byte[] Bytes = { 0x90, 0x90, 0x90, 0xc3 }; + uint Length = (uint)Bytes.Length; + uint BytesWritten = 0; + + fixed (byte* pBytes = Bytes) + { + status = NtWriteVirtualMemory( + hProcess, + BaseAddress, + pBytes, + Length, + &BytesWritten); + } + Assert.Equal(NTSTATUS.Severity.Success, status.SeverityCode); + Assert.Equal(BytesWritten, Length); + + } + + [Fact] + public static unsafe void ReadVirtualMemory() + { + + NTSTATUS status; + HANDLE hProcess = new((IntPtr)(-1)); + void* BaseAddress = (void*)0; + uint RegionSize = 1024; + + + status = NtAllocateVirtualMemory( + hProcess, + &BaseAddress, + 0, + &RegionSize, + MEM_COMMIT | MEM_RESERVE, + PAGE_EXECUTE_READWRITE); + + Assert.Equal(NTSTATUS.Severity.Success, status.SeverityCode); + Assert.NotEqual(IntPtr.Zero, (IntPtr)BaseAddress); + + byte[] BytesWrite = { 0x90, 0x90, 0x90, 0xc3 }; + byte[] BytesRead = new byte[5]; + uint Length = (uint)BytesWrite.Length; + uint BytesWritten = 0; + fixed (byte* pBytesWrite = BytesWrite, pBytesRead = BytesRead) + { + status = NtWriteVirtualMemory( + hProcess, + BaseAddress, + pBytesWrite, + Length, + &BytesWritten); + + Assert.Equal(NTSTATUS.Severity.Success, status.SeverityCode); + Assert.Equal(BytesWritten, Length); + + uint BytesReaded = 0; + status = NtReadVirtualMemory( + hProcess, + BaseAddress, + pBytesRead, + Length, + &BytesReaded); + + Assert.Equal(NTSTATUS.Severity.Success, status.SeverityCode); + Assert.Equal(*(uint*)pBytesRead, *(uint*)pBytesWrite); + Assert.Equal(Length, BytesReaded); + } + + } + + [Fact] + public static unsafe void QueryVirtualMemory() + { + + NTSTATUS status; + HANDLE hProcess = new((IntPtr)(-1)); + void* BaseAddress = (void*)0; + uint RegionSize = 1024; + + + status = NtAllocateVirtualMemory( + hProcess, + &BaseAddress, + 0, + &RegionSize, + MEM_COMMIT | MEM_RESERVE, + PAGE_EXECUTE_READWRITE); + + Assert.Equal(NTSTATUS.Severity.Success, status.SeverityCode); + Assert.NotEqual(IntPtr.Zero, (IntPtr)BaseAddress); + + MEMORY_BASIC_INFORMATION Information = default; + uint Length = (uint)sizeof(MEMORY_BASIC_INFORMATION); + status = NtQueryVirtualMemory( + hProcess, + BaseAddress, + MEMORY_INFORMATION_CLASS.MemoryBasicInformation, + &Information, + (uint)sizeof(MEMORY_BASIC_INFORMATION), + &Length + ); + + Assert.Equal(NTSTATUS.Severity.Success, status.SeverityCode); + Assert.Equal((uint)sizeof(MEMORY_BASIC_INFORMATION), Length); + Assert.Equal(Information.AllocationProtect, PAGE_EXECUTE_READWRITE); + } + + [Fact] + public static unsafe void CreateThreadEx() + { + + NTSTATUS status; + HANDLE hProcess = new((IntPtr)(-1)); + void* BaseAddress = (void*)0; + uint RegionSize = 1024; + + + status = NtAllocateVirtualMemory( + hProcess, + &BaseAddress, + 0, + &RegionSize, + MEM_COMMIT | MEM_RESERVE, + PAGE_EXECUTE_READWRITE); + + Assert.Equal(NTSTATUS.Severity.Success, status.SeverityCode); + Assert.NotEqual(IntPtr.Zero, (IntPtr)BaseAddress); + + byte[] Bytes = { 0x90, 0x90, 0x90, 0xc3 }; + uint Length = (uint)Bytes.Length; + uint BytesWritten = 0; + fixed (byte* pBytes = Bytes) + { + status = NtWriteVirtualMemory( + hProcess, + BaseAddress, + pBytes, + Length, + &BytesWritten); + + Assert.Equal(NTSTATUS.Severity.Success, status.SeverityCode); + Assert.Equal(BytesWritten, Length); + + HANDLE hThread; + USER_THREAD_START_ROUTINE StartAddress = (USER_THREAD_START_ROUTINE)Marshal.GetDelegateForFunctionPointer((IntPtr)BaseAddress); + status = NtCreateThreadEx( + &hThread, + THREAD_ALL_ACCESS, + (OBJECT_ATTRIBUTES*)IntPtr.Zero, + hProcess, + StartAddress, + (void*)IntPtr.Zero, + 0, + 0, + 0, + 0, + (PS_ATTRIBUTE_LIST*)0); + + Assert.Equal(NTSTATUS.Severity.Success, status.SeverityCode); + Assert.NotEqual(IntPtr.Zero, hThread.Value); + } + } + + [Fact] + public static unsafe void OpenFile() + { + + string devicePath = "\\??\\C:\\Windows\\System32\\ntdll.dll"; + + fixed (char* pDevicePath = devicePath) + { + NTSTATUS status; + HANDLE hFile; + UNICODE_STRING str = new() + { + Length = (ushort)(devicePath.Length * 2), + MaximumLength = (ushort)(devicePath.Length * 2), + Buffer = new PWSTR(pDevicePath) + }; + OBJECT_ATTRIBUTES Attributes = new() + { + Length = (uint)sizeof(OBJECT_ATTRIBUTES), + RootDirectory = new HANDLE(IntPtr.Zero), + ObjectName = &str, + Attributes = OBJ_CASE_INSENSITIVE, + SecurityDescriptor = (void*)0, + SecurityQualityOfService = (void*)0, + }; + IO_STATUS_BLOCK status_block; + status = NtOpenFile( + &hFile, + GENERIC_READ, + &Attributes, + &status_block, + FILE_SHARE_READ, + 0); + + Assert.Equal(NTSTATUS.Severity.Success, status.SeverityCode); + Assert.NotEqual(HANDLE.Null, hFile); + + } + + } + + [Fact] + public static unsafe void Close() + { + + string devicePath = "\\??\\C:\\Windows\\System32\\ntdll.dll"; + + fixed (char* pDevicePath = devicePath) + { + NTSTATUS status; + HANDLE hFile; + UNICODE_STRING str = new() + { + Length = (ushort)(devicePath.Length * 2), + MaximumLength = (ushort)(devicePath.Length * 2), + Buffer = new PWSTR(pDevicePath) + }; + OBJECT_ATTRIBUTES Attributes = new() + { + Length = (uint)sizeof(OBJECT_ATTRIBUTES), + RootDirectory = new HANDLE(IntPtr.Zero), + ObjectName = &str, + Attributes = OBJ_CASE_INSENSITIVE, + SecurityDescriptor = (void*)0, + SecurityQualityOfService = (void*)0, + }; + IO_STATUS_BLOCK status_block; + status = NtOpenFile( + &hFile, + GENERIC_READ, + &Attributes, + &status_block, + FILE_SHARE_READ, + 0); + + Assert.Equal(NTSTATUS.Severity.Success, status.SeverityCode); + Assert.NotEqual(HANDLE.Null, hFile); + + status = NtClose(hFile); + Assert.Equal(NTSTATUS.Severity.Success, status.SeverityCode); + } + } + + [Fact] + public static unsafe void CreateSection() + { + + string devicePath = "\\??\\C:\\Windows\\System32\\ntdll.dll"; + + fixed (char* pDevicePath = devicePath) + { + NTSTATUS status; + HANDLE hFile; + UNICODE_STRING str = new() + { + Length = (ushort)(devicePath.Length * 2), + MaximumLength = (ushort)(devicePath.Length * 2), + Buffer = new PWSTR(pDevicePath) + }; + OBJECT_ATTRIBUTES Attributes = new() + { + Length = (uint)sizeof(OBJECT_ATTRIBUTES), + RootDirectory = new HANDLE(IntPtr.Zero), + ObjectName = &str, + Attributes = OBJ_CASE_INSENSITIVE, + SecurityDescriptor = (void*)0, + SecurityQualityOfService = (void*)0, + }; + IO_STATUS_BLOCK status_block; + status = NtOpenFile( + &hFile, + GENERIC_READ, + &Attributes, + &status_block, + FILE_SHARE_READ, + 0); + + Assert.Equal(NTSTATUS.Severity.Success, status.SeverityCode); + Assert.NotEqual(HANDLE.Null, hFile); + + HANDLE hSection; + status = NtCreateSection( + &hSection, + SECTION_MAP_READ, + (OBJECT_ATTRIBUTES*)0, + (long*)0, + PAGE_READONLY, + SEC_IMAGE, + hFile); + + Assert.Equal(NTSTATUS.Severity.Success, status.SeverityCode); + Assert.NotEqual(HANDLE.Null, hSection); + } + + } + + [Fact] + public static unsafe void MapViewOfSection() + { + + string devicePath = "\\??\\C:\\Windows\\System32\\ntdll.dll"; + + fixed (char* pDevicePath = devicePath) + { + NTSTATUS status; + HANDLE hFile; + UNICODE_STRING str = new() + { + Length = (ushort)(devicePath.Length * 2), + MaximumLength = (ushort)(devicePath.Length * 2), + Buffer = new PWSTR(pDevicePath) + }; + OBJECT_ATTRIBUTES Attributes = new() + { + Length = (uint)sizeof(OBJECT_ATTRIBUTES), + RootDirectory = new HANDLE(IntPtr.Zero), + ObjectName = &str, + Attributes = OBJ_CASE_INSENSITIVE, + SecurityDescriptor = (void*)0, + SecurityQualityOfService = (void*)0, + }; + IO_STATUS_BLOCK status_block; + status = NtOpenFile( + &hFile, + GENERIC_READ, + &Attributes, + &status_block, + FILE_SHARE_READ, + 0); + + Assert.Equal(NTSTATUS.Severity.Success, status.SeverityCode); + Assert.NotEqual(HANDLE.Null, hFile); + + HANDLE hSection; + status = NtCreateSection( + &hSection, + SECTION_MAP_READ, + (OBJECT_ATTRIBUTES*)0, + (long*)0, + PAGE_READONLY, + SEC_IMAGE, + hFile); + + Assert.Equal(NTSTATUS.Severity.Success, status.SeverityCode); + Assert.NotEqual(HANDLE.Null, hSection); + + long offset = 0; + IntPtr BaseAddress; + nuint ViewSize = 0; + status = NtMapViewOfSection( + hSection, + new HANDLE((IntPtr)(-1)), + &BaseAddress, + 0, + 0, + &offset, + &ViewSize, + SECTION_INHERIT.ViewShare, + 0, + PAGE_READONLY); + + Assert.Equal(0x40000003, status.Value); + Assert.NotEqual(IntPtr.Zero, BaseAddress); + } + } + + [Fact] + public static unsafe void UnmapViewOfSection() + { + + string devicePath = "\\??\\C:\\Windows\\System32\\ntdll.dll"; + + HANDLE hProcess = new HANDLE((IntPtr)(-1)); + fixed (char* pDevicePath = devicePath) + { + NTSTATUS status; + HANDLE hFile; + UNICODE_STRING str = new() + { + Length = (ushort)(devicePath.Length * 2), + MaximumLength = (ushort)(devicePath.Length * 2), + Buffer = new PWSTR(pDevicePath) + }; + OBJECT_ATTRIBUTES Attributes = new() + { + Length = (uint)sizeof(OBJECT_ATTRIBUTES), + RootDirectory = new HANDLE(IntPtr.Zero), + ObjectName = &str, + Attributes = OBJ_CASE_INSENSITIVE, + SecurityDescriptor = (void*)0, + SecurityQualityOfService = (void*)0, + }; + IO_STATUS_BLOCK status_block; + status = NtOpenFile( + &hFile, + GENERIC_READ, + &Attributes, + &status_block, + FILE_SHARE_READ, + 0); + + Assert.Equal(NTSTATUS.Severity.Success, status.SeverityCode); + Assert.NotEqual(HANDLE.Null, hFile); + + HANDLE hSection; + status = NtCreateSection( + &hSection, + SECTION_MAP_READ, + (OBJECT_ATTRIBUTES*)0, + (long*)0, + PAGE_READONLY, + SEC_IMAGE, + hFile); + + Assert.Equal(NTSTATUS.Severity.Success, status.SeverityCode); + Assert.NotEqual(HANDLE.Null, hSection); + + long offset = 0; + IntPtr BaseAddress; + nuint ViewSize = 0; + status = NtMapViewOfSection( + hSection, + hProcess, + &BaseAddress, + 0, + 0, + &offset, + &ViewSize, + SECTION_INHERIT.ViewShare, + 0, + PAGE_READONLY); + + Assert.Equal(0x40000003, status.Value); + Assert.NotEqual(IntPtr.Zero, BaseAddress); + + status = NtUnmapViewOfSection( + hProcess, + (void*)BaseAddress); + + Assert.Equal(NTSTATUS.Severity.Success, status.SeverityCode); + + MEMORY_BASIC_INFORMATION Information = default; + uint Length = (uint)sizeof(MEMORY_BASIC_INFORMATION); + status = NtQueryVirtualMemory( + hProcess, + (void*)BaseAddress, + MEMORY_INFORMATION_CLASS.MemoryBasicInformation, + &Information, + (uint)sizeof(MEMORY_BASIC_INFORMATION), + &Length + ); + + Assert.Equal(NTSTATUS.Severity.Success, status.SeverityCode); + Assert.Equal((uint)sizeof(MEMORY_BASIC_INFORMATION), Length); + Assert.Equal(Information.State, MEM_FREE); + + } + } } \ No newline at end of file diff --git a/CsWhispers.Tests/app.config b/CsWhispers.Tests/app.config new file mode 100644 index 0000000..1687b19 --- /dev/null +++ b/CsWhispers.Tests/app.config @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/CsWhispers.Tests/packages.config b/CsWhispers.Tests/packages.config new file mode 100644 index 0000000..f36ae1a --- /dev/null +++ b/CsWhispers.Tests/packages.config @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CsWhispers.sln b/CsWhispers.sln index 7b86516..d3f700f 100644 --- a/CsWhispers.sln +++ b/CsWhispers.sln @@ -1,28 +1,47 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CsWhispers.Generator", "CsWhispers.Generator\CsWhispers.Generator.csproj", "{30CE2E3A-61D4-4D06-9280-DC73CA4C32E1}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CsWhispers.Tests", "CsWhispers.Tests\CsWhispers.Tests.csproj", "{DE6EC43A-33E7-48D5-AB5A-848F86F26448}" +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34616.47 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CsWhispers.Generator", "CsWhispers.Generator\CsWhispers.Generator.csproj", "{30CE2E3A-61D4-4D06-9280-DC73CA4C32E1}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CsWhispers.Sample", "CsWhispers.Sample\CsWhispers.Sample.csproj", "{F3EFEF07-0F1A-4162-A2D8-56CE9028CB9D}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CsWhispers.Tests", "CsWhispers.Tests\CsWhispers.Tests.csproj", "{FD24F0D1-7C40-4106-A37D-3F10AB825625}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {30CE2E3A-61D4-4D06-9280-DC73CA4C32E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {30CE2E3A-61D4-4D06-9280-DC73CA4C32E1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {30CE2E3A-61D4-4D06-9280-DC73CA4C32E1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {30CE2E3A-61D4-4D06-9280-DC73CA4C32E1}.Release|Any CPU.Build.0 = Release|Any CPU - {DE6EC43A-33E7-48D5-AB5A-848F86F26448}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DE6EC43A-33E7-48D5-AB5A-848F86F26448}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DE6EC43A-33E7-48D5-AB5A-848F86F26448}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DE6EC43A-33E7-48D5-AB5A-848F86F26448}.Release|Any CPU.Build.0 = Release|Any CPU + {30CE2E3A-61D4-4D06-9280-DC73CA4C32E1}.Debug|x86.ActiveCfg = Debug|Any CPU + {30CE2E3A-61D4-4D06-9280-DC73CA4C32E1}.Debug|x86.Build.0 = Debug|Any CPU + {30CE2E3A-61D4-4D06-9280-DC73CA4C32E1}.Release|Any CPU.ActiveCfg = Debug|Any CPU + {30CE2E3A-61D4-4D06-9280-DC73CA4C32E1}.Release|x86.ActiveCfg = Debug|Any CPU {F3EFEF07-0F1A-4162-A2D8-56CE9028CB9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F3EFEF07-0F1A-4162-A2D8-56CE9028CB9D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F3EFEF07-0F1A-4162-A2D8-56CE9028CB9D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F3EFEF07-0F1A-4162-A2D8-56CE9028CB9D}.Release|Any CPU.Build.0 = Release|Any CPU + {F3EFEF07-0F1A-4162-A2D8-56CE9028CB9D}.Debug|x86.ActiveCfg = Debug|x86 + {F3EFEF07-0F1A-4162-A2D8-56CE9028CB9D}.Debug|x86.Build.0 = Debug|x86 + {F3EFEF07-0F1A-4162-A2D8-56CE9028CB9D}.Release|Any CPU.ActiveCfg = Debug|Any CPU + {F3EFEF07-0F1A-4162-A2D8-56CE9028CB9D}.Release|x86.ActiveCfg = Debug|x86 + {FD24F0D1-7C40-4106-A37D-3F10AB825625}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FD24F0D1-7C40-4106-A37D-3F10AB825625}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FD24F0D1-7C40-4106-A37D-3F10AB825625}.Debug|x86.ActiveCfg = Debug|x86 + {FD24F0D1-7C40-4106-A37D-3F10AB825625}.Debug|x86.Build.0 = Debug|x86 + {FD24F0D1-7C40-4106-A37D-3F10AB825625}.Release|Any CPU.ActiveCfg = Debug|Any CPU + {FD24F0D1-7C40-4106-A37D-3F10AB825625}.Release|Any CPU.Build.0 = Debug|Any CPU + {FD24F0D1-7C40-4106-A37D-3F10AB825625}.Release|x86.ActiveCfg = Debug|x86 + {FD24F0D1-7C40-4106-A37D-3F10AB825625}.Release|x86.Build.0 = Debug|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {86C69EE4-C025-4D7F-9AD4-058BA919FFFF} EndGlobalSection EndGlobal