4

我们想挂接对 LoadLibrary 的调用,以下载未找到的程序集。我们有一个处理托管程序集的 ResolveAssembly 处理程序,但我们还需要处理非托管程序集。

我们试图通过“Microsoft Windows 编程应用程序”中指定的技术重写导入表来挂钩 LoadLibrary 调用,但是当我们调用 WriteProcessMemory() 时,我们得到一个权限被拒绝错误 (998)。(是的,我们正在使用提升的权限运行)

有没有人在加载 CLR 时成功地重写了导入表?谁能指出我正确的方向?

更新:我们解决了权限被拒绝的问题,但现在当我们迭代混合程序集(托管 + 非托管)的导入表时,我们找到的唯一条目是 mscoree.dll。有谁知道如何找到本地进口?(我们在 C++/CLI 中工作)。

4

4 回答 4

10

我已经成功地从托管代码中挂钩。但是,我通过将非托管 DLL 注入远程进程并让它重写 DllMain 中的导入表来做到这一点。您可能需要考虑这种方法。

这是我的挂钩功能:

//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;
}
于 2009-04-21T02:31:21.000 回答
7

应该可以,但请尝试使用detours(或免费的N-CodeHook)。
Detours 几乎是检测 Win32 二进制文件的实际方式。

于 2009-04-20T20:02:53.400 回答
2

我们通过在调用 WriteProcessMemory( ) 之前调用 VirtualProtect()解决了指定的问题,然后再次调用它以恢复保护级别。这会暂时取消对 IAT 所在内存的只读保护。这对我们很有效,并解决了调用 LoadLibrary() 时的问题。

现在,如果我能弄清楚为什么当非托管程序集链接到库(而不是静态库)时不调用 LoadLibrary( )...

顺便说一句,Detour 和N-Code Hook看起来都是不错的产品,很可能是我应该采用的方式,但如果可能的话,我想避免添加第 3 方程序集。

于 2009-04-21T02:14:09.293 回答
0

最好的方法是挂钩 LoadLibrary/LoadLibraryEx,在需要时进行下载,然后将下载的文件传递到链中。但是,我担心在下载过程中会阻止 GUI。

于 2009-04-20T22:18:45.350 回答