【问题标题】:Using GetProcAddress when the name might be decorated当名称可能被修饰时使用 GetProcAddress
【发布时间】:2015-08-31 12:40:42
【问题描述】:

在 32 位 DLL 上使用 GetProcAddress() 的正确方法是什么?在win32上,共有三种调用约定,cdecl、stdcall和fastcall。如果 DLL 中的函数是foo,它们将以下列方式装饰名称:_foo_foo@N@foo@N

但是如果 dll 的作者使用了 .def 文件,那么导出的名称将被更改为“foo”而没有任何修饰。

这给我带来了麻烦,因为如果我想从使用 stdcall 的 dll 加载 foo,我应该使用修饰名称吗:

void *h = LoadLibraryEx(L"foo.dll", NULL, 0);
GetProcAddres((HMODULE)h, L"_foo@16");

或未装饰的:

void *h = LoadLibraryEx(L"foo.dll", NULL, 0);
GetProcAddres((HMODULE)h, L"foo");

?我应该猜吗?我查看了很多 32 位 DLL 文件(stdcall 和 cdecl),它们似乎都导出了未修饰的名称。但是你能假设总是如此吗?

【问题讨论】:

    标签: winapi calling-convention stdcall getprocaddress name-decoration


    【解决方案1】:

    这里真的没有捷径或明确的规则。您必须知道函数的名称。正常情况是您在编译时就知道函数的名称。在这种情况下,导出的名称是否被损坏、修饰或与语义名称完全无关都无关紧要。可以按序号导出不带名称的函数。同样,您需要知道函数是如何导出的。

    如果您看到一个库的头文件,并希望通过显式链接 (LoadLibrary/GetProcAddress) 链接到它,那么您将需要找出函数的名称。使用像 dumpbin 或 Dependency Walker 这样的工具来做到这一点。

    现在,可能导致您提出问题的另一种情况是您在编译时不知道名称。例如,名称由程序的用户以一种或另一种方式提供。同样,要求用户知道函数的导出名称是很合理的。

    最后,您可以解析可执行文件的 PE 元数据,以枚举其导出的函数。这将为您提供导出函数名称和导出函数序号的列表。这就是像 dumpbin 和 Dependency Walker 这样的工具所做的。

    【讨论】:

    • 那么其他使用 GetProcAddress() 动态加载库的人是做什么的呢?有许多语言和 VM:s 可以在事先不知道名称是否经过修饰的情况下做得很好。
    • 他们确实知道这些名字
    • @BjörnLindqvist:你能给我们举一个具体的例子来说明你的意思吗?例如,“如果我在 Python 中执行 this this 发生”?
    • 不确定我可以。以 Julia 和 Python 语言(使用 ctypes)为例,您可以仅使用 dll 名称、函数名称和调用约定来加载和调用任意函数。我假设这是因为您可以假设导出的名称 == 未修饰的名称(他们还能怎么做?),所以大卫的回答毕竟是正确的。
    • @DavidHeffernan:哦,那么可能只有 PHP 了? :-)
    【解决方案2】:

    如果在编译时使用__declspec(dllexport),在头文件中使用__declspec(dllimport),以及extern "c",则不需要修饰这些函数。 __declspec 有助于使用未修饰的名称,但函数重载、命名空间和类仍然需要相同的方式来区分它们。

    通常,面向对象的函数是使用函数序号而不是它们的修饰名称导出的。将序数转换为(char*)(unsigned short)ordinal,因此,GetProcAddress(module, (char*)(unsigned short)ordinal);

    编辑:虽然大多数 Windows 使用 UTF-16,但 GetProcAddress 使用 UTF-8,因此它不能使用宽字符串。

    GetProcAddress(module, L"foo") 等同于GetProcAddress(module, "f");

    【讨论】:

      猜你喜欢
      • 2017-11-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-25
      • 2010-10-03
      • 1970-01-01
      相关资源
      最近更新 更多