【问题标题】:How mingw32-g++ compiler know where to inject system calls in the WIN32 machine executable?mingw32-g++ 编译器如何知道在 WIN32 机器可执行文件中注入系统调用的位置?
【发布时间】:2018-07-26 10:47:27
【问题描述】:

今天,只是为了测试的目的,我提出了以下想法,在CodeBlocks中创建和编译一个朴素的源代码,使用Release目标删除不必要的调试代码,一个main函数三个 nop 操作只是为了更快地找到 main 函数的入口点。

CodeBlocks 示例幼稚程序:

使用 IDA 反汇编程序,我看到了一些奇怪的东西,操作系统实际上可以在主函数中添加额外的机器代码调用(隐式添加),对驻留在 kernel32.dll 中的系统函数的调用,用于操作系统线程处理。

IDA 程序视图:

在机器代码中,仅出于测试原因,三个“nop”(90)被替换为“and esp,0FFFFFFF0h”,程序再次重新打包,这就是为什么“无操作”操作码在视图中不可用.

观察到的行为:

为每个打开的进程创建一个新线程是逻辑,我们可以在TaskManager中探索它,一个进程在它自己的线程中运行,这就是编译器添加此代码的原因(隐式默认线程)。

我的问题:

编译器如何知道在哪里自动“注入”这个调用代码?

为什么之前没有在将路由到主函数入口点的上层函数(sub_401B8C)中进行此调用?

【问题讨论】:

  • 大概只添加到main。调用函数是 C 运行时的一部分,在此编译期间不会生成。也不是操作系统添加它,它可能是在机器代码生成阶段之前添加的。实际上,您可以在 gcc -S 输出中看到它已经为 call ___main(一个不幸的命名选择) PS:请不要将代码发布为图像。
  • 投了反对票,因为您所有的代码示例都以图片的形式发布。请不要那样做!
  • 你的陈述语无伦次。在您的问题中,您声称操作系统能够以某种方式注入代码,但在您解释的comment 中,调用是由编译器或链接器插入的。实际上,您甚至没有提供那么多细节。该结构无助于澄清这些。
  • 您已经确定,“[i] 物理上不存在于磁盘上的文件中”。这几乎排除了操作系统以任何方式参与。如果代码在磁盘上的 PE 映像中结束,则生成该代码的要么是编译器,要么是链接器。我不明白,您对什么感到困惑,或者 “两种变体” 是什么。
  • 代码是在编译时添加的,当生成的代码用于托管环境(而不是独立的)时,对于名为 main 的函数是特殊的。and esp, 0FFFFFFF0h 用于对齐堆栈在 GCC 生成的代码所需的 16 字节边界上,正如 Jester 在他的回答中指出的那样,调用是调用全局构造函数的 GCC 运行时代码(库)。你不会发现编译器为main以外的函数生成的额外代码

标签: winapi assembly mingw portable-executable ida


【解决方案1】:

引用gcc manual

如果没有可用的 init 部分,当 GCC 编译任何调用的函数时 main(或更准确地说,任何指定为程序入口的函数 通过调用expand_main_function的语言前端),它 插入对 __main 的过程调用作为之后的第一个可执行代码 功能序言。 __main 函数在 libgcc2.c 和 运行全局构造函数。

【讨论】:

  • "它插入一个对 __main 的过程调用作为第一个可执行代码",非常感谢!线程处理发生在 start() 过程中。
猜你喜欢
  • 2020-04-19
  • 2015-04-04
  • 2012-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-09
  • 2013-05-21
  • 2011-04-02
相关资源
最近更新 更多