We would like to hook calls to LoadLibrary in order to download assemblies that are not found. We have a handler for ResolveAssembly that handles the managed assemblies, but we also need to handle unmanaged assemblies.
We have attempted to hook LoadLibrary calls by re-writing the imports table via techniques specified in "Programming Applications for Microsoft Windows", but when we call WriteProcessMemory() we get a permission denied error (998). (Yes, we're running with elevated privs)
Has anyone succeeded in re-writing the imports table while the CLR is loaded? Can anyone point me in the right direction?
Update: We resolved the permission denied issue, but now when we iterate the Imports Table of a mixed assembly (managed + unmanaged), the only entry we find is mscoree.dll. Does anyone know how to find the native imports? (we're working in C++/CLI).
I have successfully hooked from Managed code. However, I did it by injecting an unmanaged DLL into the remote process and have it rewrite the import table in DllMain. You may want to consider this method.
Here is my hooking function:
//structure of a function to hook
struct HookedFunction {
public:
LPTSTR moduleName;
LPTSTR functionName;
LPVOID newfunc;
LPVOID* oldfunc;
};
BOOL Hook(HMODULE Module, struct HookedFunction Function) {
//parse dos header
IMAGE_DOS_HEADER* dos_header = (IMAGE_DOS_HEADER*)Module;
if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) return 0; //not a dos program
//parse nt header
IMAGE_NT_HEADERS* nt_header = (IMAGE_NT_HEADERS*)(dos_header->e_lfanew + (SIZE_T)Module);
if (nt_header->Signature != IMAGE_NT_SIGNATURE) return 0; //not a windows program
//optional header (pretty much not optional)
IMAGE_OPTIONAL_HEADER optional_header = nt_header->OptionalHeader;
if (optional_header.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) return 0; //no optional header
IMAGE_IMPORT_DESCRIPTOR* idt_address = (IMAGE_IMPORT_DESCRIPTOR*)(optional_header.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + (SIZE_T)Module);
if (!optional_header.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size) return 0; //no import table
//enumerate the import dlls
BOOL hooked = false;
for(IMAGE_IMPORT_DESCRIPTOR* i = idt_address; i->Name != NULL; i++)
//check the import filename
if (!_stricmp(Function.moduleName, (char*)(i->Name + (SIZE_T)Module)))
//enumerate imported functions for this dll
for (int j = 0; *(j + (LPVOID*)(i->FirstThunk + (SIZE_T)Module)) != NULL; j++)
//check if the function matches the function we are looking for
if (!_stricmp(Function.functionName, (char*)(*(j + (SIZE_T*)(i->OriginalFirstThunk + (SIZE_T)Module)) + (SIZE_T)Module + 2) )) {
//replace the function
LPVOID* memloc = j + (LPVOID*)(i->FirstThunk + (SIZE_T)Module);
if (*memloc != Function.newfunc) { //not already hooked
DWORD oldrights;
DWORD newrights = PAGE_READWRITE;
VirtualProtect(memloc, sizeof(LPVOID), newrights, &oldrights);
if (Function.oldfunc && !*Function.oldfunc)
*Function.oldfunc = *memloc;
*memloc = Function.newfunc;
VirtualProtect(memloc, sizeof(LPVOID), oldrights, &newrights);
}
hooked = true;
}
return hooked;
}
Should work, but try using detours (or the free N-CodeHook) instead.
Detours is almost the de-facto way of instrumenting Win32 binaries.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With