I have been playing with EasyHook for a while now and have been very successfull with statically linked DLLs. Now I tried to hook a function from a DLL that is dynamically loaded from the Host Application using the same approach as with the statically linked DLLs.
In this scenario, the hook failed to work. I got the following exception when trying to create the hook:
System.DllNotFoundException: The given library is not loaded into the current process.
The Exception is very correct in stating that the library is not yet loaded, but the Host/hooked Process is about to load it in a few ns/ms after it started (which totally doesn't matter).
The tutorials and the results from my searches on the internet only covered hooking a statically linked DLL. I haven't found anything about dynamically loaded DLLs. One solution that comes to mind: Hook LoadLibrary and GetProcAddress and wait for the right winapi call to do the desired replacement.
Is there any other/an easier way to hook functions from a dynamically loaded DLL?
There is one constraint: The external program cannot be changed to use the DLL in a static way.
To facilitate a possible solution, here are some snippets that show what I want to hook:
First, this is the DLL with the AddIntegers function that I want to replace (Code is in Delphi)
library Calculate;
function AddIntegers(_a, _b: integer): integer; stdcall;
begin
Result := _a + _b;
end;
exports
AddIntegers;
begin
end.
Second, this is the program using the above DLL using the exported AddIntegers function.
program HostConsole;
{$APPTYPE CONSOLE}
uses
Winapi.Windows, System.SysUtils;
var
n1, n2, sum: Int32;
// Variables for DLL Loading
h: HMODULE;
AddIntegers: function(_a, _b: integer): integer; stdcall;
begin
try
// Load Library
h := LoadLibrary('Calculate.dll');
if h = 0 then
begin;
raise Exception.Create('Cannot load DLL');
end;
// Load function
AddIntegers := GetProcAddress(h, 'AddIntegers');
if not Assigned(AddIntegers) then
begin
raise Exception.Create('Cannot find function');
end;
Write('Enter first number: ');
Readln(n1);
Write('Enter second number: ');
Readln(n2);
// To the calculation
sum := AddIntegers(n1, n2);
Writeln('The sum is ', sum);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
// Unload Library
FreeLibrary(h);
Readln;
end.
It took me some time, but I finally figured it out: You can only hook something when it is there. As long as a module isn't loaded, there is no way for you to hook it.
How do modules get loaded?
As from the code in the question LoadLibrary() makes the module available. This means, in order to have the first point in time when a module becomes available, you need to hook LoadLibrary()!
Hooking LoadLibrary()
In case someone is looking for a way to call the function, here is one possible way:
[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
delegate IntPtr LoadLibrary_Delegate(string lpFileName);
[DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern IntPtr LoadLibrary(string lpFileName);
IntPtr LoadLibrary_Hook(string lpFileName)
{
IntPtr result = LoadLibrary(lpFileName);
if (lpFileName == "<FILENAME HERE>")
{
// Apply hook
}
return result;
}
Now that you know when a library is loaded, you can hook its functions. You can also now hook any function that is statically loaded alongside the checked library.
Hint: In my actual use case, the .dll is loaded right after startup and will be freed once the application terminates. If the library is loaded and unloaded several times, you should check for memory leaks. Yes, EasyHook might be unaware that a hooked library is unloaded.
Related
I have a piece of C# program loading a dll function:
[DllImport("/Users/frk/Workspaces/MySharedLibrary.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto, EntryPoint = "MyCFunction")]
public static extern int MyFunction( [In][MarshalAs(UnmanagedType.I4)]MyFormat format, [In][MarshalAs(UnmanagedType.LPArray)] byte[] myString, [In][MarshalAs(UnmanagedType.I4)] int myStringLength, [MarshalAs(UnmanagedType.LPArray)] byte[] output, ref UIntPtr outputLength);
and calling it
int result = MyFunction(format, inPut, inputLength, outPut, ref outputLength);
on the C++ side, I have:
MyCPPFunction that works perfectly when called from a C test executable. That MyCPPFunction contains somewhere deep in its dependencies a global const variable declared and initialized in an anonymous namespace:
namespace
{
constexpr unsigned RandTileSize = 256;
std::array<unsigned, RandTileSize * RandTileSize> GenerateSamples()
{
std::array<unsigned, RandTileSize * RandTileSize> samples;
std::mt19937 rd(0);
std::uniform_int_distribution<unsigned> distribution(0, 255);
for (unsigned i = 0; i < RandTileSize * RandTileSize; ++i)
{
samples[i] = distribution(rd);
}
return samples;
};
const auto samples = GenerateSamples();<-- Option#1 this causes a stack overflow when loading the dll in C# environment
unsigned Sample(unsigned index)
{
static const auto samples = GenerateSamples();<-- Option#2 this works and dll loads correctly
return samples[index];
}
}
I am confused here since afaik, the option 1 should allocate memory in the code part of the dll, which the C# environment should deal with right ?
How can we have option #1 not to cause memory allocation problems while loading the dll ?
The lifetime of a static variable in a function within a DLL is from the first time the statement is encountered, to the time the DLL unloads.
The lifetime of a class or file scoped variable is from the time the DLL loads until the time the DLL unloads.
The consequence of this is that in the failing case, your initialisation code is running while the DLL is in the process of loading.
It is not generally a good idea to run nontrivial code in class constructors, as there are limits to what can safely be done inside the loader lock.
In particular if you perform any action which requires dynamically loading another DLL (such as LoadLibrary or calling a delay-load linked function) this is likely to cause difficult-to-diagnose issues.
Without diagnosing exactly what has gone wrong in your case the answer is simple: Use option2 or option 3.
Option 3:
void MyDLLInitialize(){
// Initialize the dll here
}
void MyDLLUninitialize(){
// Uninitialize the dll here
}
Then call these functions from C# before you use any other DLL function, and after you have finished with it, respectively.
I am calling a DLL function written in Delphi XE2 from C# using P/Invoke. It appears to be working when calls are made sequentially from a single thread. However, when multiple threads are calling the function, the C# host application throws System.AccessViolationException seemingly at random.
Why does the code below trigger an access violation and how do I fix this?
Minimum Delphi library code for reproducing the problem:
library pinvokeproblem;
{$R *.res}
uses Windows, SysUtils;
procedure Test(const testByte: byte); stdcall;
begin
OutputDebugString(PWideChar(IntToStr(testByte)));
end;
exports Test;
end.
Minimum C# host application code to reproduce the problem:
[DllImport(
"pinvokeproblem.dll",
CallingConvention = CallingConvention.StdCall,
EntryPoint = "Test")]
private static extern void Test(byte testByte);
public static void Main(string[] args)
{
for (int i = 1; i <= 1000; i++) // more iterations = better chance to fail
{
int threadCount = 10;
Parallel.For(1, threadCount, new ParallelOptions { MaxDegreeOfParallelism = threadCount }, test =>
{
byte byteArgument = 42;
Test(byteArgument);
Console.WriteLine(String.Format("Iteration {0}: {1}", test, byteArgument));
});
}
}
Additional information:
Platform is x64 Windows 7. C# host application built for x86 in .NET 4.0, Delphi DLL compiled for 32-bit.
The library appears to be working OK when used in a multi-threaded Delphi host application.
An MSVC version of the DLL with the function signature extern __declspec(dllexport) void __stdcall Test(char testByte) works fine with the C# host (which suggests this is somehow specific to Delphi).
The code will not fail if the library function has no return value (void) and arguments.
Changing the calling convention in both code to cdecl did not help.
Any ideas would be much appreciated.
All you have to do is set IsMultiThread to True (as the first line in your DLL's main begin..end block) to switch the memory manager to a thread-safe mode:
IsMultiThread := True;
I have an API function in my application:
<Runtime.InteropServices.DllImport("kernel32.dll", SetLastError:=True, CharSet:=Runtime.InteropServices.CharSet.Ansi, ExactSpelling:=True)>
Private Shared Function GetProcAddress(ByVal hModule As IntPtr, ByVal procName As String) As IntPtr
End Function
I just want to learn the pointer 'IntPtr' value of this function. How can I do it?
Note: I will show you the exact thing that I want in C++
void* fnGetProcAddress;
fnGetProcAddress = GetProcAddress;
Well, you can continue using P/Invoke...
(Note, this is in C#, but easily convertible)
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
public static extern IntPtr GetModuleHandle(string moduleName);
var hModule = GetModuleHandle("kernel32.dll");
var procAddress = GetProcAddress(hModule, "GetProcAddress");
I want to get this address and write it in a BinaryStream as UInt32
This is a very troublesome plan. Short from the wrong data type, you have no guarantees whatsoever that the address you write is still valid when you read the stream:
The DLL might simply not be loaded when you read the stream. It does require making the LoadLibrary() call to get it in the process. So at a very minimum you'd also have to serialize the DLL path.
DLLs do not promise to get loaded at the exact same address again. The load address embedded in the DLL header is merely a request, it is very common that the requested address is already in use by another DLL, forcing Windows to relocate the DLL. That relocated address is not predictable. A far bigger problem is that relocation is intentionally done on modern Windows versions. A feature called Address Space Layout Randomization, enabled when the DLL was linked with the /DYNAMICBASE linker option. It is an anti-malware feature, making it intentionally hard for malware to patch code.
Surely there's a better way to do what you want to do. You however made the common mistake of not explaining your reasons, it is impossible to guess at.
I'm exploring the idea of building a bridge between a DLL plugin for a 3rd party app and a C# app. I'm writing both the plugin DLL and the C# application. The plugin will be loaded into the 3rd party app and then I want to use call the plugin from C# to indirectly get data from the 3rd party app.
I am able to successfully call an exported function from the DLL from C#. For example:
C++ DLL:
extern "C" __declspec(dllexport) char * HelloFromDll()
{
char *result;
result = "Hello from my DLL";
return result;
}
C#:
using System.Runtime.InteropServices;
[DllImport(#"MyDll.dll")]
private static extern string HelloFromDll();
I can then call this DLL function from C# and display the string in the UI. However, as soon as I create an export function that calls a function from my 3rd party app, I get an AccessViolationException. For example,
extern "C" __declspec(dllexport) char * GetData()
{
char *result;
result = 3rdPartyLibrary::SomeFunction();
return result;
}
Through some testing, the error seems to occur as soon as I make a call to a 3rd party function. How can I fix this?
This function is very difficult to use in a C program as well. Returning strings from functions is a poorly supported scenario. There's a memory management problem, it isn't clear who owns the string. In most cases the caller is expected to take ownership of the string and free it after using it. That's not going to work out well for your function, the program will crash since you returned a string literal.
The .NET pinvoke marshaller needs to solve this problem as well. With the extra problem that it cannot use the allocator that's used by the C code. It is going to call CoTaskMemFree (the COM allocator). That causes an undiagnosable memory leak on XP, a crash on Vista and Win7.
Just don't write C code like this. Always let the caller pass the buffer for the string. Now there's no guessing who owns the memory. Like this:
extern "C" __declspec(dllexport) void HelloFromDll(char* buffer, int bufferSize)
{
strcpy_s(result, bufferSize, "Hello from my DLL");
}
With your C# code like this:
[DllImport("foo.dll", CharSet = CharSet.Ansi)]
private static extern void HelloFromDll(StringBuilder buffer, int bufferSize);
...
var sb = new StringBuilder(666);
HelloFromDll(sb, sb.Capacity);
string result = sb.ToString();
From your question it seems that this is the scenario:
ProcessA (3rd party App) --> loads X.DLL --> initializes the plugin --> does other stuff.
ProcessB (Your C# App) --> loads X.DLL --> calls GetData();
Does X.DLL loaded in ProcessA have any mechanism to talk to X.DLL loaded in ProcessB?
if not then this approach is flawed. Your code probbably crashes because "3rdPartyLibrary" class hasn't been initialised in your C# app as it is completely different copy of the DLL.
For you to extract this data you need a query interface defined by X.DLL which can talk across processes, maybe sockets?
Then ProcessB talks to this interface and extracts the data. if using sockets, then your X.DLL would implement both server and client code, where your GetData() would use this mechanism (maybe sockets) and query the data and return it.
So : X.DLL in ProcessA should act like a server.
And: X.DLL (or write a Y.DLL) in ProcessB should act like a client and get this information from ProcessA.
btw, if the query is only needed to be done once, just hard code this is in X.DLL and dump to disk, and then explore at your convinience :-)
Generally, a returned char* needs to be returned as an IntPtr:
[DllImport(#"MyDll.dll")]
private static IntPtr HelloFromDll();
Then, you'll need to convert that IntPtr into a string:
string retVal=Marshal.PtrToStringAnsi(HelloFromDll());
Strings are a bit difficult in P/Invoke. My general rule of thumb is:
Input char* parameter = c# string
Return char * = IntPtr (use PtrToStringAnsi)
Output char* parameter = c# StringBuilder - and be sure to pre-allocate it large enough
before (ie = new StringBuilder(size)) calling the function.
I'm encountering a strange memory read/write error while calling a compiled DLL from C#. I use DllImport to get a handle to the function we need, which writes a return value to a parametric pointer to an int (i.e., int* out). This function is called multiple times within a thread, and runs successfully over the execution life of the first thread. However, if one launches another thread after the first has completed, the call to the external dll throws an AccessViolationException. Since the multiple calls from the first thread execute successfully, I'm thinking this is somehow related to the first thread not releasing the pointers to the relevant integer parameters(?). If so, how can I explicitly release that memory? Or, perhaps someone has a different insight into what might be going on here? Thank you very much.
EDIT: Danny has requested more specifics, and I'm happy to oblige. Here is where the external routine is invoked:
int success = -1;
unsafe
{
int res = 0;
int* res_ptr = &res;
int len = cmd.ToCharArray().Length;
int* len_ptr = &len;
CmdInterpreter(ref cmd, len_ptr, res_ptr);
success = *res_ptr;
}
Where CmdInterpreter is defined as:
[DllImport("brugs.dll", EntryPoint="CmdInterpreter",
ExactSpelling=false, CallingConvention = CallingConvention.StdCall)]
public static unsafe extern void CmdInterpreter(ref string cmd, int *len, int *res);
Please let me know if there is any additional info that would be helpful. Thank you!
Given that the problem only occurs when multiple threads are involved, it may be that the command interpreter DLL is using some sort of thread-local storage and doing it incorrectly. It could also have to do with the COM initialization state of the second thread (the one that generates the error).
It would be interesting to know what happens if you launch your new thread and have it call into the DLL before making any calls into the DLL on your first/main thread. If it works, that might support the thread-local storage theory. If it fails, that would support the COM state theory.
It may be the [DllImport]. If you post the [DllImport] signature, and the DLL's ptototype, maybe we can spot a problem.
I read that the Managed, Native, and COM Interop Team released the PInvoke Interop Assistant on CodePlex. http://www.codeplex.com/clrinterop/Release/ProjectReleases.aspx?ReleaseId=14120