让 dll 从其调用.exe导入符号



与DLL相关但不等同于DLL 从其父级(加载器(获取符号

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

如果加载.exe具有已知名称,则很明显该怎么做,但如果不是......

以下是您实际上想要这样做的一个很好的理由:https://www.gnu.org/software/libc/manual/html_node/Replacing-malloc.html

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

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

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

可能的变体 - 在运行时自行解析函数指针。 在这里,我们可以通过GetModuleHandle(0)获得 exeHMODULE. 此外,如果需要,我们不仅可以在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__名称的函数的指针。 所以事实上,当我们自己声明指针时,与第一个变体相同。 只是语法和..符号名称的区别。 它会看起来像__imp_?fn2@@YAXH@Z. 这里的问题是__imp_?fn2@@YAXH@ZC/C++ 无效的名称 - 我们不能从C/C++直接为其赋值。 即使我们声明函数extern "C"- 函数名称将包含@符号(对于C++,对于 C__stdcall++,对于x86__fastcall函数是非法的(。对于不同的平台(x86x64等(,名称也会有所不同。要访问此类名称 - 需要或使用外部 ASM 文件(对于ASM?和名称有效的@符号(/alternatename或使用链接器选项 - 用于设置此类名称的别名并通过它访问符号。说喜欢

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

并通过以下方式初始化

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

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

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

我们可以自己实现它,也可以delayimp.lib添加到我们的项目中。 这里(在delayimp.lib(delayLoadHelper2并实现。 但是我们必须自定义此过程(默认实现(在/include/DelayHlp.cpp中查找(将与dllname一起使用LoadLibraryExA,这在我们的例子中并不例外 - 否则我们可以简单地按原样使用导入(。 所以我们需要强制实现__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 的唯一标记(别名(

最新更新