Does .NET interop cache the generated unmanaged thunks to managed method? - c#

For example, I use unmanaged Win32 timer:
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void TimerProc(IntPtr hWnd, uint uMsg, IntPtr nIDEvent, uint dwTime);
[DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
public static extern IntPtr SetTimer(IntPtr hWnd, IntPtr nIDEvent,
uint uElapse, TimerProc lpTimerFunc);
// ...
TimerProc timerProc = delegate { this.Beep(); };
// ...
var timerId = NativeMethods.SetTimer(IntPtr.Zero, IntPtr.Zero, 500, timerProc);
I wonder if the unmanaged pointer for lpTimerFunc which is passed to the actual SetTimer API remains the same for as longs as the managed timerProc remians the same, no matter how many times I call NativeMethods.SetTimer? Or does a new unmanaged thunk get generated for timerProc each time I call NativeMethods.SetTimer?

Each delegate will have its own thunk, so it depends on how you create your delegate. If you create a new delegate each time you call SetTimer, you'll have lots of them. If create it once for your class, you'll only have one.

Related

View a type within a dll to use in a function used by that Dll

I've got a COM interface dll, and some documentation about the methods within the dll, however from what I can tell with the documentation, the method requires a custom struct be passed in as an out parameter, but the documentation doesn't provide any information about the struct itself.
The function I'm calling from c# is as follows:
API
UINT OpenRequest ([out] PHCOMS phComs,
[in] PCHAR pEndPointName,
[in] UINT fBlockingMode,
[in] UINT fOpenMode,
[in] UINT fDataType,
[in] HINSTANCE hInstance)
My issue is that PHCOMS is a type described in the documentation as:
The address of a variable of type HCOMS. The communications handle to be used by the other API calls, is returned in this variable. If an error occurs this will be NULL.
This function starts by allocating a comms handle (hComs), if
available, to the application. This handle is used for creating a new
connection object. The parameters of this function are assigned to the
relevant members. For this object, a pointer instance is created for
connecting to the interface, as well as the PC Headerpched
interface
I've had a look at various dll inspectors and other posts on SO but can't find anything that helps with how I can actually create a struct that's going to be validly accepted by the function.
I am also unsure if I'm misinterpreting what I need to do - is it possible that I just need to pass a standard handle through to the function or something similar? Is the PHComs type a non custom type that I just can't find info on in google?
Right now I'm attempting to call the function through c# using the DLLImport attribute over an extern function which seems to be ok except that the handle I get back is never valid, which I'm blindly (I've never done something like this before) trying to do like this
[DllImport("MyDll.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
public static extern uint OpenRequest(ref SafeProcessHandle hComs, string host, uint fBlockingMode, uint fOpenMode, uint fDataType, SafeProcessHandle hInstance);
static void Main(string[] args)
{
IntPtr h = new IntPtr();
var handle = new SafeProcessHandle(h, true);
uint test = 0;
test = OpenRequest(ref handle, "Host01", 0, 0, 0, handle);
handle.Dispose();
}
Any assistance on how to setup my test properly would help too since I'm blindly guessing about the IntPtr and use of whatever Safe*Handle Classes.
Edit
I've changed it to be like this following Hans' comment:
As you said, there are other methods that use that handle, for example the ConnectRequest added below.
Any suggestion as to what the HInstance parameter refers to? I doubt it's correct that I'm just passing the same handle/IntPtr in again?
The documentation says:
hInstance HINSTANCE Windows programs must pass their instance handle.
[DllImport("MyDll.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
public static extern uint OpenRequest(out IntPtr hComs, string host, uint fBlockingMode, uint fOpenMode, uint fDataType, IntPtr hInstance);
[DllImport("MyDll.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
public static extern uint ConnectRequest(IntPtr hComs, uint cTimeOut);
static void Main(string[] args)
{
IntPtr hComs = new IntPtr();
uint test_OpenRequest = 0;
test_OpenRequest = OpenRequest(out hComs, "Host01", 0, 0, 0, hComs);
}
Edit 2
[DllImport("WinCom32.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
public static extern uint OpenRequest(out IntPtr hComs, string host, uint fBlockingMode, uint fOpenMode, uint fDataType, IntPtr hInstance);
static void Main(string[] args)
{
IntPtr hComs = new IntPtr();
uint test_Request = 0;
string hostName = ConfigurationManager.AppSettings["HostName"];
IntPtr hInstance = Marshal.GetHINSTANCE(Assembly.GetEntryAssembly().GetModules()[0]);
test_Request = OpenRequest(out hComs, hostName, 0, 0, 1, hInstance);
Console.WriteLine("Request response value: " + test_Request.ToString());
}
There's a test application I can run that shows that this is supposed to work because it's able to connect to the host, so I've got to be doing something wrong.

Importing kernel32 functions for allocating virtual memory in C#?

I have several DLL files that are on my hard disk. A process on my server contains important file data that I want to log by allocating virtual memory inside the process. I don't have the source code of that process, so I need to reside to more extreem measures. I want it to start the DLL main function. The allocation of memory externally needs to be written in C# due to the fact I want to use it with WPF.
How can you excute your own source code in another process with C#?
In order to execute your own source code inside a process you need to virtually allocate memory for the process and write the path of your DLL inside that memory address you allocated. You will use that DLL path to catapult your dll inside the process using the exported function in kernel32.dll LoadLibraryW.
Each process on the windows platform has a specified memory size dedicated to that process. One of the reasons is for security, a process can’t read or write data to other processes. So in order to be able to write/inject your DLL you need to open a HANDLE. You can do this if you import the OpenProcess function from the kernel32.dll. What this briefly means is that you are using the windows api. Here is how you import the kernel32 DLL in C#
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr OpenProcess(
uint dwDesiredAccess,
int bInheritHandle,
uint dwProcessId
);
You can find the full documentation of the windows api in the holy bible
Now, you want to allocate memory to the process that you got a handle from by using the OpenProcess function. Use the VirtualAllocEx function, lets consult the MSDN
How hath thou allocated thou memory?
LPVOID WINAPI VirtualAllocEx(
_In_ HANDLE hProcess,
_In_opt_ LPVOID lpAddress,
_In_ SIZE_T dwSize,
_In_ DWORD flAllocationType,
_In_ DWORD flProtect
);
As we can see it takes 5 parameters. The HANDLE object that you collected earlier. An optional parameter that we won’t use. The size of your DLL that you can get if you convert your DLL into an array of bytes. The type of memory allocation, we want to both reserve and commit allocation so use (0x1000 | 0x2000) and last the protection for the allocated memory that we will put on write 0x40.
STEP 1 Allocate memory ✓
STEP 2 Write DLL path
STEP 3 use LoadLibraryW
The second step involves using WriteProcessMemory to simply write the dll path in memory. Convert String to array of bytes
byte[] bytes = Encoding.ASCII.GetBytes(DllPath);
Write that array of bytes on the memory you allocated with the windows api function WriteProcessMemory like so.
WriteProcessMemory(processHandle, allocatedMemory, bytes, (uint)bytes.Length, 0)
STEP 1 Allocate memory ✓
STEP 2 Write DLL path ✓
STEP 3 use LoadLibraryW
This will be a bit tricky to explain if you have no clue on what exported functions are so ill try to give you an abstract understanding.
When creating an application you need to import DLLs that windows provided in order to use some functionalities. For example, you want to send a HTTP request in your application. Even without you knowing you need to load windows ws2.dll (windows socket) library. The windows OS provided a handy function that will literally load a library called LoadLibraryW. Where can I find this fantastic function? Well no worries child, the kernel32.dll got you covered. All you need to do is find a pointer to the LoadLibraryW function. Again, show faith in the MSDN and it shall reward you.
FARPROC WINAPI GetProcAddress(
_In_ HMODULE hModule,
_In_ LPCSTR lpProcName
);
HMODULE WINAPI GetModuleHandle(
_In_opt_ LPCTSTR lpModuleName
);
You can read the documentation for more information. Simply put this will find your LoadLibraryW function inside kernel32.dll since it is an exported function.
IntPtr lpLLAddress = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryW");
STEP 1 Allocate memory ✓
STEP 2 Write DLL path ✓
STEP 3 use LoadLibraryW ✓
Start a remotethread inside your process that will simply execute your loadlibrary code
CreateRemoteThread(hndProc, (IntPtr)null, (IntPtr)null, lpLLAddress, lpAddress, 0, (IntPtr)null)
After that simply close the handle to the process and your dll should be ‘injected’ inside the process. At any rate if you still haven't figured it out or simply want a class that does it for you here is some source code
DLLinjector
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace dllInjectExample
{
public enum DllInjectionResult
{
DllNotFound,
GameProcessNotFound,
InjectionFailed,
Success
}
public static class DllInjector
{
static readonly IntPtr INTPTR_ZERO = (IntPtr)0;
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr OpenProcess(uint dwDesiredAccess, int bInheritHandle, uint dwProcessId);
[DllImport("kernel32.dll", SetLastError = true)]
static extern int CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, uint flProtect);
[DllImport("kernel32.dll", SetLastError = true)]
static extern int WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] buffer, uint size, int lpNumberOfBytesWritten);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttribute, IntPtr dwStackSize, IntPtr lpStartAddress,
IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
public static DllInjectionResult Inject(string sProcName, string sDllPath)
{
if (!File.Exists(sDllPath))
{
return DllInjectionResult.DllNotFound;
}
uint _procId = 0;
Process[] _procs = Process.GetProcesses();
for (int i = 0; i < _procs.Length; i++)
{
if (_procs[i].ProcessName == sProcName)
{
_procId = (uint)_procs[i].Id;
break;
}
}
if (_procId == 0)
{
return DllInjectionResult.GameProcessNotFound;
}
if (!bInject(_procId, sDllPath))
{
return DllInjectionResult.InjectionFailed;
}
return DllInjectionResult.Success;
}
private static bool bInject(uint pToBeInjected, string sDllPath)
{
IntPtr hndProc = OpenProcess((0x2 | 0x8 | 0x10 | 0x20 | 0x400), 1, pToBeInjected);
if (hndProc == INTPTR_ZERO)
{
return false;
}
IntPtr lpAddress = VirtualAllocEx(hndProc, (IntPtr)null, (IntPtr)sDllPath.Length, (0x1000 | 0x2000), 0X40);
if (lpAddress == INTPTR_ZERO)
{
return false;
}
byte[] bytes = Encoding.ASCII.GetBytes(sDllPath);
if (WriteProcessMemory(hndProc, lpAddress, bytes, (uint)bytes.Length, 0) == 0)
{
return false;
}
IntPtr lpLLAddress = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryW");
if (lpLLAddress == INTPTR_ZERO)
{
return false;
}
if (CreateRemoteThread(hndProc, (IntPtr)null, INTPTR_ZERO, lpLLAddress, lpAddress, 0, (IntPtr)null) == INTPTR_ZERO)
{
return false;
}
CloseHandle(hndProc);
return true;
}
}
}
Example injecting into csgo since I have no other idea why you would want to inject a dll?
if (Process.GetProcessesByName("csgo").Count() == 0)
{
Process Proc = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo(#"D:\Application\Steam\Steam.exe");
Proc.StartInfo = startInfo;
Proc.StartInfo.Arguments = "-applaunch 730";
Proc.StartInfo.UseShellExecute = false;
Proc.StartInfo.CreateNoWindow = false;
Proc.Start();
Thread.Sleep(15000);
}
while (Process.GetProcessesByName("csgo").Count() == 0)
{
}
var something = DllInjector.Inject("csgo", #"C:\Visual Studio 2015\Projects\XGame\Debug\XGamedll.dll");

Memory access violation while passing void* param to DLL function

I'm adding new disk device to system from my C# code, so I want to call
[System.Runtime.InteropServices.DllImport("Shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public extern static void SHChangeNotify(long wEventId, uint uFlags, IntPtr dwItem1, IntPtr dwItem2);
like below
MyWin32Functions.SHChangeNotify(0x00000100/*ADDRIVE*/, 0x0005/*PATHW*/, driveLetter, IntPtr.Zero);
dwItem1 is void* and we should pass a wchar_t* (pointing to null terminated string) containing drive root in this case; so driveLetter above is
string letter = "Z:\\";
byte[] data = Encoding.Default.GetBytes(letter);
byte[] zdata = new byte[data.Length + 1];
data.CopyTo(zdata, 0);
IntPtr p = System.Runtime.InteropServices.Marshal.AllocHGlobal(zdata.Length);
System.Runtime.InteropServices.Marshal.Copy(zdata, 0, p, zdata.Length);
(my code almost same as code in similiar case: How to call SHChangeNotify from C# without error 14007
but I get System.AccessViolationException)
Any suggestions what am I doing wrong?
The first parameter in your interop signature should be an int, not a long. Though the Win32 function is declared as LONG, a LONG in Win32 is 32-bit.
[System.Runtime.InteropServices.DllImport("Shell32.dll")]
public extern static void SHChangeNotify(int wEventId, uint uFlags, IntPtr dwItem1, IntPtr dwItem2);
This MSDN article shows the common mapping between Win32 types an .NET types for Platform Invoke.

convert C++ code to C#: SendMessageTimeout()

First of all docu for SendMessageTimeout:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644952%28v=vs.85%29.aspx
i have this C++ code and i want to convert it to C#:
LRESULT success = SendMessageTimeout(
HWND_BROADCAST,
WM_SETTINGCHANGE,
0,
(LPARAM) "Environment",
SMTO_ABORTIFHUNG,
5000,
NULL
);
What i did in C#:
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr SendMessageTimeout(
IntPtr hWnd,
uint Msg,
UIntPtr wParam,
IntPtr lParam,
uint fuFlags,
uint uTimeout,
out UIntPtr lpdwResult
);
SendMessageTimeout(
(IntPtr)0xFFFFFFFF, //HWND_BROADCAST
0x001A, //WM_SETTINGCHANGE
(UIntPtr)0,
(IntPtr)"Environment", // ERROR_1: can't convert string to IntPtr
0x0002, // SMTO_ABORTIFHUNG
5000,
out UIntPtr.Zero // ERROR_2: a static readonly field can not be passed ref or out
);
For your issues.
HWND_BROADCAST is 0xFFFF not 0xFFFFFFFF
You will have to allocate memory for the LPARAM value manually using Marshal.StringToHGlobalUni and then free it after the call using Marshal.FreeHGlobal. You must free this memory or it will leak. Marshal'd memory is not garbage collected.
For lpdwResult just create an IntPtr variable and pass that in. You can just ignore its value.
The code should be something like this:
IntPtr result = IntPtr.Zero;
IntPtr setting = Marshal.StringToHGlobalUni("Environment");
SendMessageTimeout(
(IntPtr)0xFFFF, //HWND_BROADCAST
0x001A, //WM_SETTINGCHANGE
(UIntPtr)0,
(IntPtr)setting,
0x0002, // SMTO_ABORTIFHUNG
5000,
out result
);
Marshal.FreeHGlobal(setting);
In general you need to be careful when freeing memory that you pass to a SendMessage call since you don't know what the receving window will do with the pointer that you pass to it. Howerver since WM_SETTINGCHANGE is a built in Windows message, Windows will handle this pointer for you.
SendMessage is a bit painful due to the non-descript argument types it uses. Necessary because it needs to do many jobs. Necessary in the C language, but not in C#. What you want to do here is take advantage of the C# language supporting overloads. The IntPtr arguments can just be reference type references, the pinvoke marshaller will properly convert them to a pointer and take care of the memory management hassle. So just craft another one that's compatible with the way you want to use it:
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr SendMessageTimeout(
IntPtr hWnd,
int Msg,
IntPtr wParam,
string lParam,
int fuFlags,
int uTimeout,
IntPtr lpdwResult
);
Now you can use:
SendMessageTimeout((IntPtr)0xffff, 0x001A, IntPtr.Zero, "Environment",
2, 5000, IntPtr.Zero);

DLLImport -> how to handle a HANDLE in C#

in my C# code I want to import a C++ DLL. I use the dllimport and it works fine with a some of the functions. But in one function I get a HANDLE which I need later to call another function.
[DllImport("SiUSBXp.dll")]
public static extern int SI_Open(UInt32 deviceNum,ref IntPtr devHandle ); // this function gets the HANDLE
[DllImport("SiUSBXp.dll")]
public static extern int SI_Write([In]IntPtr devHandle, [In, Out] byte[] inputByte, UInt32 size,ref UInt32 bytesWritten); // this function needs the HANDLE
In my code these functions are called like this:
IntPtr devHandle = new IntPtr();
UInt32 bytesWritten = new UInt32();
byte[] byteArr = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
SI_Open(0, ref devHandle);
SI_Write(devHandle, byteArr, 10, ref bytesWritten);
If I do it like this I get an "System.AccessViolationException". I searched here and in the internet but didnt find a specific answer. How do I use the IntPtr correctly, so it works?
Best Regards
Toby
Your SI_Write function looks quite like Windows Kernel32's WriteFile.
So, I would do this:
[DllImport("SiUSBXp.dll", SetLastError = true)]
static extern int SI_Open(uint dwDevice, ref IntPtr cyHandle);
[DllImport("SiUSBXp.dll", SetLastError = true)]
static extern int SI_Write(IntPtr cyHandle, byte[] lpBuffer,
uint dwBytesToWrite, out uint lpdwBytesWritten);
EDIT: I found this documentation USBXPRESS® PROGRAMMER’S GUIDE on the web, and it states that the SI_Write prototype looks actually much closer to WriteFile than I thought. The doc states this:
SI_STATUS SI_Write (HANDLE Handle, LPVOID Buffer, DWORD NumBytesToWrite,
DWORD *NumBytesWritten, OVERLAPPED* o = NULL)
It means the .NET prototype should be this instead:
[DllImport("SiUSBXp.dll")]
static extern int SI_Write(IntPtr Handle, byte[] Buffer,
uint NumBytesToWrite, out uint NumBytesWritten, IntPtr o);
o is optional so you can pass IntPtr.Zero.
You are making a classic C programmer mistake, you don't check the return value of the functions. Which tells you whether or not the function failed. A likely scenario is that SI_Open() returned a failure code. You ignore it and use the uninitialized handle value anyway. A kaboom is not unusual.
The next possible mistake is that you don't use the CallingConvention property in the [DllImport] statement. It is fairly likely to be needed, Cdecl is the default unless the native function is declared with __stdcall. Also an excellent way to invoke a kaboom. If you still have trouble then you are going to have to debug the native code.
Btw, you get rid of the awkward syntax by using out instead of ref. In both functions.
[DllImport("SiUSBXp.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int SI_Open(UInt32 deviceNum, out IntPtr devHandle );
try this:
[DllImport("SiUSBXp.dll")]
public static extern int SI_Open(UInt32 deviceNum, ref IntPtr devHandle); // this function gets the HANDLE
[DllImport("SiUSBXp.dll")]
public static extern int SI_Write(IntPtr devHandle, ref byte[] inputByte, UInt32 size, ref UInt32 bytesWritten); // this function needs the HANDLE
EDIT:
#Hans Passant is right. This is the correct way to pass a byte[] into a LPVOID parameter. ref used to coerce an object into LPVOID, but isn't needed for an array. What happens when you try this?
[DllImport("SiUSBXp.dll")]
public static extern int SI_Write(IntPtr devHandle, byte[] inputByte, UInt32 size, ref UInt32 bytesWritten); // this function needs the HANDLE
Did you try the answer #Simon Mourier gave? He was first to provide this declaration and his answer deserves to be accepted.
bad: static extern void DoStuff(**byte[] inputByte**);
good: static extern void DoStuff(**[In, MarshalAs(UnmanagedType.LPArray)] byte[] inputByte**);

Categories