My problem is in calling shellcode in C#. I alloc memory in the process, write there my bytes and try to call it with Marshal.GetDelegateFromFunctionPointer(). It seems working, but, only if my function doesn't have parameters. If there's any parameter there then it's value equals {Unable to read memory}. In C++ I just need to typedef func, cast it, and call. How to do this properly in C#? (Shellcode performs jump to another C# func)
First of all in C# you have to declare delegate with all required parameters and calling convension. When you use GetDelegateForFunctionPointer ptr is converted to a delegate that invokes the unmanaged method using the __stdcall calling convention on Windows, or the __cdecl calling convention on Linux and macOS. You can set the calling convention by applying the UnmanagedFunctionPointerAttribute to the delegate.
Also you need indicate how to marshal parameters between managed and unmanaged code to achieve this you should use MarshalAsAttribute
See remarks section of Marshal.GetDelegateForFunctionPointer
and UnmanagedFunctionPointerAttribute
and MarshalAsAttribute
Example:
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
private static extern IntPtr LoadLibraryW([MarshalAs(UnmanagedType.LPWStr)] string libFileName);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true)]
private static extern IntPtr GetProcAddress(IntPtr hModule, [MarshalAs(UnmanagedType.LPStr)] string lpProcName);
const int MEM_COMMIT = 0x00001000;
const int PAGE_READWRITE = 0x04;
const int PAGE_EXECUTE_READ = 0x20;
[DllImport("kernel32.dll", ExactSpelling = true)]
private static extern IntPtr VirtualAlloc(IntPtr address, IntPtr size, int allocationType, int protect);
[DllImport("kernel32.dll", ExactSpelling = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool VirtualProtect(IntPtr address, IntPtr size, int newProtect, out int oldProtect);
private delegate int GetTempPath(int nBufferLength, [MarshalAs(UnmanagedType.LPStr)] StringBuilder buffer);
static void Main(string[] args)
{
IntPtr hModule = LoadLibraryW("c:\\windows\\system32\\kernel32.dll");
IntPtr procAddress = GetProcAddress(hModule, "GetTempPathA");
// allocate page with read/write access
IntPtr page = VirtualAlloc(IntPtr.Zero, new IntPtr(4096), MEM_COMMIT, PAGE_READWRITE);
// write to allocated memory
// mov r11, procAddress
Marshal.WriteByte(page, 0, 0x49);
Marshal.WriteByte(page, 1, 0xBB);
Marshal.WriteInt64(page, 2, procAddress.ToInt64());
// jmp r11
Marshal.WriteByte(page, 0xA, 0x41);
Marshal.WriteByte(page, 0xB, 0xFF);
Marshal.WriteByte(page, 0xC, 0xE3);
// protect memory to allow execute code
bool result = VirtualProtect(page, new IntPtr(4096), PAGE_EXECUTE_READ, out int oldProtect);
var getTempPathTrampoline = Marshal.GetDelegateForFunctionPointer<GetTempPath>(page);
StringBuilder builder = new StringBuilder(1024);
getTempPathTrampoline(1024, builder);
Console.WriteLine(builder.ToString());
}
Example (call managed code)
static void Main(string[] args)
{
GetTempPath delegateToManaged = ManagedMethod;
IntPtr managedPtr = Marshal.GetFunctionPointerForDelegate(delegateToManaged);
// allocate page with read/write access
IntPtr page = VirtualAlloc(IntPtr.Zero, new IntPtr(4096), MEM_COMMIT, PAGE_READWRITE);
// write to allocated memory
// mov r11, procAddress
Marshal.WriteByte(page, 0, 0x49);
Marshal.WriteByte(page, 1, 0xBB);
Marshal.WriteInt64(page, 2, managedPtr.ToInt64());
// jmp r11
Marshal.WriteByte(page, 0xA, 0x41);
Marshal.WriteByte(page, 0xB, 0xFF);
Marshal.WriteByte(page, 0xC, 0xE3);
// protect memory to allow execute code
bool result = VirtualProtect(page, new IntPtr(4096), PAGE_EXECUTE_READ, out int oldProtect);
var getTempPathTrampoline = Marshal.GetDelegateForFunctionPointer<GetTempPath>(page);
StringBuilder builder = new StringBuilder(1024);
getTempPathTrampoline(1024, builder);
Console.WriteLine(builder.ToString());
}
public static int ManagedMethod(int nBufferLength, StringBuilder buffer)
{
buffer.Append("Hello World");
return 0;
}
Related
I'm trying to modify some code that dumps a specific file and I want to modify the first bytes of the dumped file.
I've already done it in a C equivalent program like this :
[...]
SetFilePointer(hDmpFile, 0, 0, FILE_BEGIN);
WriteFile(hDmpFile, "AA", 2, NULL, NULL);
I want to do the same thing in C# but I got some error regarding the WriteFile() function.
Here's what I've done so far :
[...]
public enum EMoveMethod : uint
{
Begin = 0,
Current = 1,
End = 2
}
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint SetFilePointer(
[In] SafeFileHandle hFile,
[In] int lDistanceToMove,
[Out] out int lpDistanceToMoveHigh,
[In] EMoveMethod dwMoveMethod);
[DllImport("kernel32.dll", BestFitMapping = true, CharSet = CharSet.Ansi)]
public static extern bool WriteFile(
IntPtr hFile,
System.Text.StringBuilder lpBuffer,
uint nNumberOfBytesToWrite,
out uint lpNumberOfBytesWritten,
[In] ref System.Threading.NativeOverlapped lpOverlapped);
[...]
int moveDistanceHighBits = 0;
uint test = SetFilePointer(hDmpFile, 0, out moveDistanceHighBits, EMoveMethod.Begin);
uint test2 = WriteFile(hDmpFile, "AA", 2, null, null);
hDmpFile.Dispose();
[...]
Here's the error I got when executing the file :
Unhandled Exception: System.NotImplementedException: The method or operation is not implemented.
at Foo.Program.WriteFile(SafeFileHandle hDmpFile, String v1, Int32 v2, Object value1, Object value2)
at Foo.Program.Execute(String[] args)
at Foo.Program.Main(String[] args)
For the record, I'm an absolute disaster when it comes to coding and I've never done C#...
When testing the performance in SQL clr assembly it seems that call to unmaged code is extrem slow
I did the test as console app and as clr assembly with the following result
Console App:
decimal.Parse("-49823174320.9293800") 304.7 ns 855.7 cycles
PInvoke.Empty()...........................................11.9 ns 33.6 cycles
Clr assembly:
decimal.Parse("-49823174320.9293800") 304.7 ns 855.7 cycles
PInvoke.Empty()......................................5095.4 ns 14308.1 cycles
The PInvoke.Empty() is an asm function with only ret statement. This function is created with virtualAlloc.
public static class Pinvoke
{
[SuppressUnmanagedCodeSecurity]
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate ulong FuncUInt64();
private const uint PAGE_EXECUTE = 0x10;
private const uint PAGE_EXECUTE_READWRITE = 0x40;
private const uint MEM_COMMIT = 0x1000;
private const uint MEM_RELEASE = 0x8000;
public static readonly FuncUInt64 Empty;
private static readonly byte[] ReturnOnlyAsm = { 0xC3 };
static Pinvoke()
{
var buf = IntPtr.Zero;
try
{
// We pad the functions to 64 bytes (the length of a cacheline on the Intel processors)
var rdtscpLength = (ReturnOnlyAsm.Length & 63) != 0 ? (ReturnOnlyAsm.Length | 63) + 1 : ReturnOnlyAsm.Length;
buf = VirtualAlloc(IntPtr.Zero, (IntPtr) rdtscpLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (buf == IntPtr.Zero) throw new Win32Exception();
Marshal.Copy(ReturnOnlyAsm, 0, buf, ReturnOnlyAsm.Length);
for (var i = ReturnOnlyAsm.Length; i < rdtscpLength; i++) Marshal.WriteByte(buf, i, 0x90); // nop
// Change the access of the allocated memory from R/W to Execute
var result = VirtualProtect(buf, (IntPtr) rdtscpLength, PAGE_EXECUTE, out var oldProtection);
if (!result) throw new Win32Exception();
// Create a delegate to the "function"
Empty = (FuncUInt64) Marshal.GetDelegateForFunctionPointer(buf, typeof(FuncUInt64));
buf = IntPtr.Zero;
}
finally
{
if (buf != IntPtr.Zero)
VirtualFree(buf, IntPtr.Zero, MEM_RELEASE);
}
}
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
private static extern IntPtr VirtualAlloc(IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, uint flProtect);
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool VirtualProtect(IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, out uint lpflOldProtect);
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool VirtualFree(IntPtr lpAddress, IntPtr dwSize, uint dwFreeType);
}
The decimal parse has no unmanged code but the GetTimestamp has. Calls to unmanged code seems to be more than 250 times slower
For code used to test see https://github.com/Anderman/SqlClrPerformance.
This code used asm code trick to call the rdtscp timer and will only run on 64 bit.
Used sql server 2017 (13.0.1742.0) and tested with release build for both sql and console app.
Also tested with a the Stopwatch which is not so accurate, but reveals the same issue
private void swGetCurrentProcess()
{
var i = 0;
var sw = Stopwatch.StartNew();
do
{
i++;
Process.GetCurrentProcess();
} while (sw.ElapsedMilliseconds < 5000);
var nanoSecodsPerIteration = 5_000_000_000 / i;
_reporter($"GetCurrentProcess with StopWatch {nanoSecodsPerIteration,5:0.0} ns ");
}
Console:
GetCurrentProcess with StopWatch 426.0 ns
SqlClr:
GetCurrentProcess with StopWatch 12422.0 ns
My processor (Intel i7) supports the POPCNT instruction and I would like to call it from my C# application. Is this possible?
I believe I read somewhere that it isn't, but the JIT will invoke it if it finds it available but what function would I have to call that may be substituted with such an instruction?
Popcount is being called millions of times in a loop so I'd like to be able to have this CPU optimization if possible.
You want to play with fire, and here we like to play with fire...
class Program
{
const uint PAGE_EXECUTE_READWRITE = 0x40;
const uint MEM_COMMIT = 0x1000;
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr VirtualAlloc(IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, uint flProtect);
private delegate int IntReturner();
static void Main(string[] args)
{
List<byte> bodyBuilder = new List<byte>();
bodyBuilder.Add(0xb8); // MOV EAX,
bodyBuilder.AddRange(BitConverter.GetBytes(42)); // 42
bodyBuilder.Add(0xc3); // RET
byte[] body = bodyBuilder.ToArray();
IntPtr buf = VirtualAlloc(IntPtr.Zero, (IntPtr)body.Length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
Marshal.Copy(body, 0, buf, body.Length);
IntReturner ptr = (IntReturner)Marshal.GetDelegateForFunctionPointer(buf, typeof(IntReturner));
Console.WriteLine(ptr());
}
}
(this small example of assembly will simply return 42... I think it's the perfect number for this answer :-) )
In the end the trick is that:
A) You must know the opcodes corresponding to the asm you want to write
B) You use VirtualAlloc to make a page of memory executable
C) In some way you copy your opcodes there
(the code was taken from http://www.cnblogs.com/netact/archive/2013/01/10/2855448.html)
Ok... the other one was as written on the site (minus an error on the uint -> IntPtr dwSize), this one is how it should be written (or at least it's a +1 compared to the original... I would encapsulate everything in a IDisposable class instead of using try... finally)
class Program
{
const uint PAGE_READWRITE = 0x04;
const uint PAGE_EXECUTE = 0x10;
const uint MEM_COMMIT = 0x1000;
const uint MEM_RELEASE = 0x8000;
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr VirtualAlloc(IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, uint flProtect);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool VirtualProtect(IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, out uint lpflOldProtect);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool VirtualFree(IntPtr lpAddress, IntPtr dwSize, uint dwFreeType);
private delegate int IntReturner();
static void Main(string[] args)
{
List<byte> bodyBuilder = new List<byte>();
bodyBuilder.Add(0xb8); // MOV EAX,
bodyBuilder.AddRange(BitConverter.GetBytes(42)); // 42
bodyBuilder.Add(0xc3); // RET
byte[] body = bodyBuilder.ToArray();
IntPtr buf = IntPtr.Zero;
try
{
// We VirtualAlloc body.Length bytes, with R/W access
// Note that from what I've read, MEM_RESERVE is useless
// if the first parameter is IntPtr.Zero
buf = VirtualAlloc(IntPtr.Zero, (IntPtr)body.Length, MEM_COMMIT, PAGE_READWRITE);
if (buf == IntPtr.Zero)
{
throw new Win32Exception();
}
// Copy our instructions in the buf
Marshal.Copy(body, 0, buf, body.Length);
// Change the access of the allocated memory from R/W to Execute
uint oldProtection;
bool result = VirtualProtect(buf, (IntPtr)body.Length, PAGE_EXECUTE, out oldProtection);
if (!result)
{
throw new Win32Exception();
}
// Create a delegate to the "function"
// Sadly we can't use Funct<int>
var fun = (IntReturner)Marshal.GetDelegateForFunctionPointer(buf, typeof(IntReturner));
Console.WriteLine(fun());
}
finally
{
if (buf != IntPtr.Zero)
{
// Free the allocated memory
bool result = VirtualFree(buf, IntPtr.Zero, MEM_RELEASE);
if (!result)
{
throw new Win32Exception();
}
}
}
}
}
I tried to pinvoke a PKCS#11 function in C#. I have a CKR_DATA_LEN_RANGE error in this C# code:
[DllImport("D:/Program Files/Eracom/ProtectToolkit C SDK/bin/sw/cryptoki.dll",
SetLastError = true)]
private static extern UInt32 C_Encrypt(CK_SESSION_HANDLE hSession,
IntPtr pData, CK_ULONG ulDataLen,
out IntPtr pEncryptedData,out CK_ULONG pulEncryptedData);
/* ...Main... */
CK_BYTE[] text = new CK_BYTE[] {1,2,3,4,5,6,7,8};
System.UInt32 t, tt = (System.UInt32)text.Length;
IntPtr pdata = Marshal.AllocHGlobal(text[0]*text.Length);
Marshal.Copy(text, 0, pdata, text.Length);
IntPtr chif = IntPtr.Zero;
tt = (System.UInt32)Marshal.SizeOf(pdata);
rv = C_Encrypt(h, pdata, tt,out chif,out t);
What could be causing this error?
I resolved the problem by my self. The C_Encrypt function takes byte arrays as arguments, not pointers to integers; this made my size computations wrong.
[DllImport("D:/Program Files/Eracom/ProtectToolkit C SDK/bin/sw/cryptoki.dll",
SetLastError = true)]
private static extern UInt32 C_Encrypt(CK_SESSION_HANDLE hSession,
CK_BYTE[] pData, CK_ULONG ulDataLen,
CK_BYTE[] pEncryptedData, ref CK_ULONG pulEncryptedData);
I need to use an unmanaged VC++ dll.
It has the following two functions that require C# wrappers:
bool ReadData(byte* byteData, byte dataSize);
bool WriteData(byte* byteData, byte dataSize);
They both return true if they succeed, but false otherwise.
Currently in C# I have a class (WRAP) with functions:
[DllImport("kirf.dll", EntryPoint = "ReadData", SetLastError=true)]
[return: MarshalAs(UnmanagedType.VariantBool)]
public static extern Boolean ReadData([Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)]out Byte[] bytesData, Byte dataSize);
[DllImport("kirf.dll", EntryPoint = "WriteRFCard", SetLastError = true)]
[return: MarshalAs(UnmanagedType.VariantBool)]
public static extern Boolean WriteRFCard[In]Byte[] bytesData, [In]Byte dataSize);
I then have
byte[] newData = new byte[17];
byte dataSize = 17;
bool result = WRAP.ReadData(out newData, dataSize);
This always gives me a result=false, newData = null, and no error thrown(or rather it always come back successful).
And
byte[] bytesData = new Byte[] { (byte)0x9B, (byte)0x80, (byte)0x12, (byte)0x38, (byte)0x5E, (byte)0x0A, (byte)0x74, (byte)0x6E, (byte)0xE6, (byte)0xC0, (byte)0x68, (byte)0xCB, (byte)0xD3, (byte)0xE6, (byte)0xAB, (byte)0x9C, (byte)0x00 };
byte dataSize = 17;
bool actual = WRAP.WriteData(bytesData, dataSize);
Any ideas as to what I could be doing wrong?
edit
This is how I eventually managed it:
[DllImport("kirf.dll", EntryPoint = "ReadData", SetLastError=true)]
[return: MarshalAs(UnmanagedType.VariantBool)]
public static extern Boolean ReadData([Out] Byte[] bytesData, Byte dataSize);
[DllImport("kirf.dll", EntryPoint = "WriteData", SetLastError = true)]
[return: MarshalAs(UnmanagedType.VariantBool)]
public static extern Boolean WriteData([In] Byte[] bytesData, Byte dataSize);
And:
Byte[] newData=new byte[17];
bool result = KABA_KIRF.ReadData(newData, (Byte)newData.Length);
and
bool result = KABA_KIRF.WriteData(data, datasize);
where data was a Byte[] parameter passed into the function.
Does ReadData create a new byte array? Otherwise, I don't think bytesData should be an out param.
Look at the PInvoke spec of ReadFile for comparison:
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool ReadFile(IntPtr hFile, [Out] byte[] lpBuffer,
uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped);
lpNumberOfBytesRead is an out param, because ReadFile changes the value of it. i.e. if you pass a local variable for lpNumberOfBytesRead, ReadFile will change the value on the stack. The value of lpBuffer on the other hand is not changed: It still points to the same byte array after the call. The [In,Out]-Attributes tell PInvoke what to do with the contents of the array you pass.