这个答案一般无法回答.从技术上讲,如果您使用详尽的调试信息编译可执行文件(代码可能仍然是优化的发行版本),那么可执行文件将包含额外的部分,提供二进制文件的某种反射性.在*nix系统(您提到dl_open
)上,这是通过ELF二进制文件的额外部分中的DWARF调试数据实现的.类似于MacOS X上的Mach Universal Binaries.
然而,Windows PE使用完全不同的格式,所以不幸的是DWARF不是truley cross plattform(实际上在我的3D引擎的早期开发阶段我为Windows实现了ELF/DWARF加载器,因此我可以使用通用格式的各种引擎模块,所以可以做一些认真的努力).
如果您不想实现自己的加载器或调试信息访问器,那么您可以通过导出的一些额外符号(通过一些标准命名方案)嵌入反射信息,这些符号引用函数名称表,映射到它们的签名.在C源文件的情况下编写解析器以从源文件本身提取信息是相当简单的.众所周知,C++ OTOH很难正确解析,你需要一些完全成熟的编译器才能正确解析它.为此,开发了GCCXML,技术上是一个GCC,它以XML格式而不是对象二进制形式发出AST.然后,发出的XML更容易解析.
从提取的信息中创建具有某种链表/数组/等的源文件.描述每个功能的结构.如果不直接导出每个函数的符号,而是使用函数指针初始化反射结构中的某个字段,则会得到一个非常漂亮且干净的带注释的导出方案.从技术上讲,您也可以将此信息放在二进制文件的特殊部分中,但将其放入只读数据部分也可以完成这项工作.
但是,如果给你一个第三方二进制文件 - 比如最糟糕的情况它是从C源编译的,没有调试信息和所有没有外部参考的符号被剥离 - 你几乎搞砸了.您可以做的最好的事情是对函数访问可以传递参数的各个位置的方式应用一些二元分析.
这只会告诉您参数的数量和每个参数值的大小,而不是类型或名称/含义.当对某些程序进行逆向工程(例如恶意软件分析或安全审计)时,识别传递给函数的参数的类型和含义是主要工作之一.最近我遇到了一些我不得不为调试目的而反向的驱动程序,你无法相信我在Linux内核模块中找到C++符号这一事实让我感到震惊(你不能以理智的方式在Linux内核中使用C++) ),但也松了一口气,因为C++名称错误为我提供了大量信息.
小智 5
在 Linux(或 Mac)上,您可以组合使用“nm”和“c++filt”(用于 C++ 库)
nm mylibrary.so | C++过滤器
或者
nm mylibrary.a | C++过滤器
“nm”将为您提供损坏的形式,而“c++filt”尝试将它们置于更易于阅读的格式中。您可能希望在 nm 中使用一些选项来过滤结果,尤其是在库很大的情况下(或者您可以“grep”最终输出以查找特定项目)