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