0

我们有一个插件系统,它通过 dlopening/LoadLibrarying dll/so/dylib 然后 dlsyming/GetProcAddressing 函数调用 dll(用户生成的插件)中的函数,然后将结果存储在函数指针中。

不幸的是,由于复制粘贴了一些错误的示例代码,这些 dll 中的一些没有正确的函数签名,并且不包含 return 语句。

一个 dll 可能包含以下内容:

extern "C" void Foo() { stuffWithNoReturn(); } // copy-paste from bad code

或者它可能包含以下内容:

extern "C" int Foo() { doStuff(); return 1; } // good code

加载 dll 的应用程序依赖于返回值,但是有大量没有返回语句的 dll。我正在尝试检测这种情况,并警告用户他的插件存在问题。

这个天真的代码应该解释我想要做什么:

typedef int (*Foo_f)(void);
Foo_f func = (Foo_f)getFromDll(); // does dlsym or GetProcAddress depending on platform
int canary = 0x42424242;
canary = (*func)();
if (canary == 0x42424242)
   printf("You idiot, this is the wrong signature!!!\n");
else
   real_return_value = canary;

不幸的是,这不起作用,金丝雀在调用具有已知缺陷的 dll 后包含一个随机值。我天真地假设调用一个没有返回语句的函数会使金丝雀完好无损,但事实并非如此。

我的下一个想法是编写一点内联汇编程序来调用该函数,并在返回时检查 eax 寄存器,但 Visual Studio 2015 不再允许在 x64 代码中使用 __asm()。

我知道没有符合标准的解决方案,因为将函数指针转换为错误的类型当然是未定义的行为。但是,如果有人有一个至少可以在 64 位 Windows 上使用 Visual C++ 的解决方案,或者一个可以在 MacOS 上使用 clang 的解决方案,我会非常高兴。

4

1 回答 1

0

@Lorinczy Zsigmond 是正确的,如果函数执行某些操作但不返回任何内容,则寄存器的内容是未定义的。然而,我们发现在实践中,不返回任何内容的插件也几乎总是具有编译为 retn 0x0 并且保持返回寄存器不变的空函数。我们可以通过使用已知值 (0xdeadbeef) 喷洒 rax 寄存器并检查它来检测这种情况。

于 2018-01-13T04:39:05.950 回答