最近,我一直在计算机上浏览各种DLL,我认为一个不错的起点是图像入口点(通常为_DllMainCRTStartup)。

从我看到的CRT源代码(MSVC)来看,它调用了另一个具有相同参数(HMODULE,DWORD,LPVOID)的函数(__DllMainCRTStartup)。但是,我看过的许多二进制文件似乎与以下内容有所不同:两个通过寄存器ecx / edx。被调用的函数希望它们也在那里。我期望看到的是所有三个都被压入堆栈,我相信这是_cdecl约定的工作方式。这是一个例子:它是CRT的旧版本吗?还是完全不同的编译器?奖金,如果您也知道这是什么样的调用约定,对我来说就像__fastcall的一个表亲!

非常感谢!
我应该从CRT源代码(至少是VS 2012附带的版本)中添加函数原型。

  push        dword ptr [ebp+8]
  mov         ecx,dword ptr [ebp+10h]
  mov         edx,dword ptr [ebp+0Ch]
  call        10024E5B // __DllMainCRTStartup


Editx2: >
我刚刚看过“相关”链接:哪种x86调用约定通过ESI传递第一个参数?

看来这可能是LTCG的结果,链接器基本上只是决定做任何喜欢的事情,因为它了解所有组件!

评论

为什么_DllMainCRTStartup遵守任何调用约定?没有人会强迫编译器这样做-这不是可以从外部模块调用的公共符号。

好吧,这不一定很明显,我只是想知道为什么在源代码中将其标记为__cdecl的原因

#1 楼

通过全局优化(链接时代码生成),编译器可以自由地忽略所有在外部不可见的函数的声明的调用约定,也就是说,既不导出也不固定(通过获取其地址并传递给外部代码)。

这会导致生成的二进制文件难以分析,因为即使启动代码中众所周知的部分也可以在全局优化下变形和融合。它的行为和嵌入的魔术常数(例如用于初始化堆栈保护cookie及其补码的常数)仍然可以识别,但是通过IDA的FLIRT等简单机制识别库对象代码的成功率令人dive目结舌。

另外,在这种情况下,从标头或IDA的签名文件中提取的函数原型可能很可能是错误的。这可能会使IDA的分析引擎(和阅读器)误入歧途,从而甚至在有问题的功能离开多个调用级别时也引起问题。 。