我可以以编程方式推断出 C++ 使用的调用约定吗? dll?

发布于 2024-08-22 00:26:23 字数 509 浏览 14 评论 0原文

想象一下,您想要编写一个程序来测试 c++ dll 文件中的函数。 您应该允许用户选择一个 dll(我们假设我们正在讨论 c++ dll)。 他应该能够获得 dll 导出的所有函数的列表。 然后,用户应该能够从列表中选择一个函数名称,手动输入参数列表(参数都是基本类型,如 int、double、bool 或 char 数组(例如 c 类型字符串))并尝试使用指定的参数运行选定的函数。 他想知道该函数是否使用指定的参数运行,或者它们是否导致它崩溃(例如,因为它们与签名不匹配)。

主要问题是,C++ 作为一种强类型语言,要求您在编译时知道函数调用的参数的数量和类型。就我而言,我根本不知道这些参数是什么,直到用户在运行时选择它们。

我想出的唯一解决方案是使用程序集手动将参数推送到调用堆栈上。

然而,我开始明白,如果我想搞乱汇编,我最好确保我知道 dll 中的函数使用的是哪个调用约定。

所以(最后:)这是我的问题:我可以以编程方式推断出调用约定吗? Dependency Walker 不会帮助我,而且我不知道如何手动读取 PE 格式。

Imagine you'd like to write a program that tests functions in a c++ dll file.
You should enable the user to select a dll (we assume we are talking about c++ dlls).
He should be able to obtain a list of all functions exported by the dll.
Then, the user should be able to select a function name from the list, manually input a list of arguments ( the arguments are all basic types, like int, double, bool or char arrays (e.g. c-type strings) ) and attempt to run the selected function with the specified arguments.
He'd like to know if the function runs with the specified arguments, or do they cause it to crash ( because they don't match the signature for example ).

The main problem is that C++, being a strongly typed language, requires you to know the number and type of the arguments for a function call at compile time.And in my case, I simply don't know what these arguments are, until the user selects them at runtime.

The only solution I came up with, was to use assembly to manually push the arguments on the call stack.

However, I've come to understand that if I want to mess with assembly, I'd better make damn sure that I know which calling convention are the functions in the dll using.

So (finally:) here's my question: can I deduce the calling convention programmaticaly? Dependency Walker won't help me, and I've no idea how to manually read PE format.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

感性 2024-08-29 00:26:23

答案是也许

如果函数名称是 C++ 修饰的,那么您可以从名称修饰中确定参数计数和类型,这是最好的情况,如果首先使用 MSVC 编写代码,则很有可能。

如果导出的函数是 stdcall 调用约定(Windows api 的默认设置),您可以确定要推送的字节数,但不能确定参数的类型。

坏消息是,对于 C 调用约定,没有任何方法可以通过查看符号名称来判断。您需要有权访问源代码或调试信息。

http://en.wikipedia.org/wiki/X86_calling_conventions

函数的名称因为导出不需要与链接器看到的名称有任何关系,但大多数时候,导出的名称和链接器看到的符号名称是相同的。

The answer is maybe.

If the functions names are C++ decorated, then you can determine the argument count and types from the name decoration, this is your best case scenario, and fairly likely if MSVC was used to write the code in the first place.

If the exported functions are stdcall calling convention (the default for windows api), you can determine the number of bytes to be pushed, but not the types of the arguments.

The bad news is that for C calling convention, there isn't any way to tell by looking at the symbol names. You would need to have access to the source code or the debug info.

http://en.wikipedia.org/wiki/X86_calling_conventions

The name that a function is given as an export is not required to have any relationship with the name that the linker sees, but most of the time, the exported name and the symbol name that the linker sees are the same.

绝不服输 2024-08-29 00:26:23

您没有指定您在这里谈论的是 32 位还是 64 位,您和其他发帖者概述的困难主要适用于 32 位代码。在 64 位 Windows 上,本质上只有一种调用约定(它也在 John Knoeller 链接的维基百科文章中),这意味着您确实知道调用约定(当然,任何人都除外)自己做饭)。

此外,根据 Microsoft x64 调用约定,不知道要调用的函数的参数数量并不会阻止您调用它,您可以根据需要/用户希望提供尽可能多的参数。这是因为您作为调用者预留了堆栈空间并随后将其清理。 -- 当然,不提供正确的[数量]参数可能仍然会让被调用的函数做一些愚蠢的事情,因为您提供了无效的输入,但那是另一个故事了。

You didn't specify whether you're talking 32-bit or 64-bit here, and the difficulties outlined by you and the other posters mainly apply to 32-bit code. On 64-bit Windows, there's essentially only one calling convention (it's in also in the wikipedia article linked by John Knoeller), which means that you do know the calling convention (of course with the exception of anybody cooking up their own).

Also, with the Microsoft x64 calling convention, not knowing the number of parameters of the function to be called does not stop you from calling it, providing as many parameters as you wish/the user wishes to. This is because you as a caller set aside stack space and clean it up afterwards. -- Of course, not providing the right [number of] parameters may still have the called function do silly things because you're providing invalid input, but that's another story.

月亮是我掰弯的 2024-08-29 00:26:23

不幸的是,编译后的代码不仅仅说“这里这个函数是一个快速调用,这里这个函数是一个 stdcall”。

即使像 IDA 这样的现代反汇编器也不会默认尝试推断调用类型(idk 中可能有插件或选项)。

基本上,如果你是一个人,90% 的情况下你都会看前几条说明并告诉自己。如果它们是 pop 和 push,则为 stdcall,如果通过寄存器(尤其是 ecx)传递参数,则为 cdecl。 Fastcall 也使用寄存器,但做了一些特殊的事情......不知道我的头脑。但所有这些信息都是无用的,因为你的程序显然不是人类。

如果你正在进行测试,你至少有头文件吗?这是一种非常困难的剥猫皮的方法。

The compiled code does not just say 'Here this function is a fastcall, and this one here is stdcall' unfortunately.

Not even modern disassemblers like IDA try to deduce call types by default (there might be a plugin or an option somewhere idk).

Basically if you are a human you cn look at the first few instructions and tell 90% of the time. If they are pop and push, its stdcall, if its passing params through the registers (especially ecx) then its cdecl. Fastcall also uses the registers but does something special.. dunno off the top of my head. But all this info is useless because your program obviously will not be a human.

If you are doing testing, dont you at least have the header files?? This is an awfully hard way to skin a cat..

梦情居士 2024-08-29 00:26:23

如果您想知道 C++ 函数使用什么调用约定,您最好的希望是研究

  1. 声明该函数的标头以及
  2. 编译特定 DLL 的编译器的文档。

但老实说,这整件事听起来有点混乱。为什么你的朋友希望能够做到这一点,为什么他不能通过解析声明相关函数的标头来获取他需要的信息?

If you want to know what calling convention a C++ function uses, your best hope is to study

  1. The header that declares that function, and
  2. The documentation for the compiler that compiled your particular DLL.

But this whole thing sounds like a bit of a mess, honestly. Why does your friend want to be able to do this, and why can't he get the information he needs by parsing a header that declares the relevant functions?

意犹 2024-08-29 00:26:23

本页描述了 VC++6 将参数和调用约定信息编码为符号名称的方式: http: //www.bottledlight.com/docs/mangle.html

我怀疑更高版本的 VC++ 会兼容,但我还没有证实这一点。

编译器附带了一些自动执行此操作的工具: http://msdn .microsoft.com/en-us/library/5x49w699.aspx

名称修改仅适用于 C++ 函数;如果函数是“extern“C””那么这将不起作用。

This page describes the way VC++6 encodes parameter and calling convention info into a symbol name: http://www.bottledlight.com/docs/mangle.html

I suspect that later versions of VC++ will be compatible but I haven't confirmed this.

There are also some tools that automate this which accompany the compiler: http://msdn.microsoft.com/en-us/library/5x49w699.aspx

The name mangling only applies for C++ functions; if a function is 'extern "C"' then this won't work.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文