让DLL从其调用.exe中导入符号

问题描述 投票:0回答:1

相关但不等同于DLL Get Symbols From Its Parent (Loader)

有没有办法说服Windows加载程序从加载可执行文件或中间dll解析A.dll引用的特定符号而不指定文件来解析A.dll中的符号?

如果加载.exe具有已知名称,但是如果它不是......那么很明显该如何做到这一点

这是你真正想要这样做的一个很好的理由:https://www.gnu.org/software/libc/manual/html_node/Replacing-malloc.html

如果可以做到这一点,一个好的答案会说明如何以某种方式做到这一点。

我一半期待答案是不能做到的。在这种情况下,一个好的答案将说明为什么这是不可能的。 “构建工具不支持这一点。”是一个糟糕的答案。

windows dll dllimport dllexport
1个回答
2
投票

当我们使用import时,我们需要准确指出模块名称和函数名称。我们不能使用复杂的算法。也为exe不存在众所周知的别名,我们可以使用恰好exe名称。比较:如果得到GetModuleHandle我们可以使用NULL获取用于创建调用进程(.exe文件)的文件的句柄。但是,如果LoadLibraryExW我们不能使用0或空字符串(L"")或另一个别名说 - 我们想要exe的句柄。当加载器加载我们的模块时 - 他从IMAGE_IMPORT_DESCRIPTOR读取dll名称并尝试使用此名称首先通过LoadLibraryExW的低级私有核心加载模块。这里需要确切的名字。或加载失败。结果使用import - 这里不是解决方案,如果我们在构建时不知道exe名称

可能的变体 - 在运行时自己解决函数指针。在这里,我们可以通过HMODULE获得exe GetModuleHandle(0)。如果需要我们不仅可以在exe中搜索函数,还可以在其他地方搜索函数。可以实现任何搜索算法。

这里存在几种方式。具体的例子让我们需要获得带签名函数的指针:

void WINAPI fn(int i);

我们可以声明指向这个函数的指针并在运行时解析它

void (WINAPI *fn)(int);

*(void**)&fn = GetProcAddress(GetModuleHandleW(0), "fn");

DLL_PROCESS_ATTACH上说

稍微不同的解决方案(尽管在二进制级别它是完全等效的)使用__declspec(dllimport)属性声明函数。这仅适用于CL.EXE(更多称为MSVC)编译器。所以

__declspec(dllimport) void fn(int i);

在这种情况下,CL自己生成一个名为__imp_ ## __FUNCDNAME__ name的函数指针。所以事实上与第一个变体相同,当我们自己声明指针时。只有语法和符号名称的区别。它看起来像__imp_?fn2@@YAXH@Z。这里的问题是__imp_?fn2@@YAXH@Z不是c / c ++的有效名称 - 我们不能从c / c ++直接赋值给它。即使我们用extern "C"声明函数 - 函数名称将包含用于@__stdcall函数的__fastcall符号(非法用于c ++),用于x86。对于不同的平台(x86,x64等),名称也会有所不同。访问此类名称 - 需要或使用外部asm文件(对于名称中有效的asm ?@符号)或使用/alternatename链接器选项 - 通过它来设置此类名称和访问符号的别名。说的像

__pragma(comment(linker, "/alternatename:__imp_?fn@@YAXH@Z=__imp_fn"))

和init via

*(void**)&__imp_fn = GetProcAddress(GetModuleHandle(0), "fn");

另一个选项在函数声明中使用__declspec(dllimport) +添加导入库,其中定义了所有__imp___FUNCDNAME__(例如__imp_?fn2@@YAXH@Z)。 (即使我们没有这样的库,我们也可以轻松地自己创建它 - 所有需要的东西 - 正确的函数声明与空实现)。在我们将这样的导入lib添加到链接器输入之后 - 添加/DELAYLOAD:dllname,其中dllname - 来自import lib的确切名称。感觉这个dllname将(可能)与exe不匹配 - 所有需要的东西 - 它必须是唯一的。我们需要自己处理delayload(当我们第一次调用fn时调用)。对于实现延迟加载,我们需要implement

extern "C" FARPROC WINAPI __delayLoadHelper2(   
   PCImgDelayDescr pidd,  
   FARPROC * ppfnIATEntry  
); 

我们可以自己实现它,或者将delayimp.lib添加到我们的项目中。在这里(在delayimp.libdelayLoadHelper2并实施。但是我们必须自定义这个过程(默认实现(在/include/DelayHlp.cpp中查看)将使用LoadLibraryExAdllname,在我们的例子中没有例外 - 否则我们可以简单地使用import)。所以我们需要强制实施__pfnDliNotifyHook2

例如:

FARPROC WINAPI MyDliHook(
                             unsigned        dliNotify,
                             PDelayLoadInfo  pdli
                             )
{
    switch (dliNotify)
    {
    case dliNotePreLoadLibrary:
        if (!strcmp(pdli->szDll, "unique_exe_alias"))
        {
            return (FARPROC)GetModuleHandle(0);
        }
    }

    return 0;
}

const PfnDliHook  __pfnDliNotifyHook2 = MyDliHook;

我们可以查找dliNotePreLoadLibrary通知,而不是默认LoadLibraryEx(dli.szDll, NULL, 0);使用GetModuleHandle(0);获取exe的基础。 “unique_exe_alias”(链接器从导入库获得)这里扮演的角色不是真正的exe名称,这是未知的,但exe的唯一标签(别名)

© www.soinside.com 2019 - 2024. All rights reserved.