【问题标题】:C Function to Step through its own AssemblyC 函数单步执行自己的程序集
【发布时间】:2017-11-27 18:59:59
【问题描述】:

我想知道是否有一种方法可以在 C 程序中编写一个函数,该函数遍历另一个函数来定位调用指令的地址。

比如我想在main函数中找到ret指令使用的地址。

我的第一个想法是创建一个从“&main()”开始的while循环,然后每次循环将地址加1,直到指令在当前地址“ret”并返回地址。

【问题讨论】:

  • 这行得通吗?..
  • 不同的 x86 指令具有不同的长度,并且可能包含可能被误认为是“ret”指令的 立即 数据值。此外,一个函数可以有多个 'ret' 指令,或者有 'ret' 指令的变体。
  • 这样做的目的是什么?你这样做到底想达到什么目的?
  • @ethanelle:查找当前函数调用链通常是通过跟踪堆栈来完成的。每个函数都会在堆栈上留下信息。最特别的是,必须保存先前函数的返回地址。 (尽管最近的返回地址可能保存在寄存器中并且不会保存到堆栈中,除非并且直到即将执行另一个调用。)在堆栈上追溯过去是“容易的”,因为从帧中有明确的链接框架,所以你只需要按照链接到最后一个。不幸的是,正如 Ian Abbott 所提到的,程序可能被编译为不使用帧指针,......
  • ... 在这种情况下,无法直接获得所需的信息,并且很难追溯。在任何情况下,您都应该输入一个新问题,例如“我如何编写一个可以追溯其自己的堆栈帧的程序?”这样的问题。 (但先搜索现有问题。)

标签: c assembly


【解决方案1】:

当然可以编写反汇编机器代码的程序。 (显然,这是特定于体系结构的。这样的程序只适用于它所设计的体系结构。)这样的程序可以获取其main 例程的地址并对其进行检查。 (在某些 C 实现中,指向函数的指针实际上并不是函数代码的地址。但是,旨在反汇编代码的程序会考虑到这一点。)

对于新手来说,这将是一项相当困难的任务。

您的程序不会在指令之间将地址增加一个字节。许多体系结构具有四个字节的固定指令大小,但其他大小也是可能的。 x86-64 架构(以各种名称闻名)具有可变的指令大小。拆卸它相当复杂。作为反汇编指令过程的一部分,你必须弄清楚它有多大,这样你就知道下一条指令在哪里。

不过,一般来说,确定哪条返回指令是由main 执行的返回指令并不总是可行的。尽管函数通常以直截了当的方式编写,但它们可能会跳来跳去。一个函数可能有多个返回语句。它的代码可能位于多个不连续的位置,甚至可能与其他函数共享代码。 (我不知道这是否是常见编译器中的常见做法,但它可能是。)当然,main 可能永远不会返回(并且,如果编译器检测到这一点,它可能根本不会费心编写返回指令)。

(顺便说一句,有一个数学证明,不可能编写一个总是确定程序是否终止的程序。这被称为Halting Problem。)

【讨论】:

  • 感谢您如此深入的回复!我知道其中很多都是特定于架构的。但是如果你可以假设这些变量是理想的常量(main 真的很简单,调用一个函数,然后有一个 return 0 语句,就是这样。),程序可以读取字节直到它识别为一个字节作为返回指令吗?跨度>
  • 不,不能保证 call 指令跳转到的地址部分与 ret 指令不同。如前所述,这是一项相当复杂的任务,即使是最基本的。
  • 您首先需要能够找到指令边界,这意味着您需要它们的长度。这是我计算 x86-32 指令长度的代码:stackoverflow.com/a/23843450/120163 这样,您可以可靠地识别操作码字节,从而对指令进行解码。您可以使用它来逐步执行程序中的说明,寻找您喜欢的任何内容。
  • gcc/clang 不合并函数的常见尾部。即使具有相同的功能,它们通常也不擅长合并返回路径,例如jle .L2 在自己的块中转到ret 是很常见的,而不是在另一个块的末尾跳转到ret。此外,一个函数的代码不会与其他函数的代码交错,除非一个块被标记为cold 并放在它自己的部分中。我认为这确实发生在一些异常处理路径上。
  • @ethanelle:您的建议可以在 MIPS 或 ARM(没有 Thumb2 或 MIPS16)等固定宽度的 ISA 上正常工作。虽然它在 32 位 ARM 上很复杂,因为有多种返回方式。 (bx lr,或者弹出到PC,因为程序计数器是16个寄存器之一。)MIPS应该与jr $ra非常一致,但我认为代码可以将返回地址重新加载到任何其他寄存器中......无论如何,您不会在另一条指令中找到 4 字节的返回指令作为数据,因为所有指令都是 4 字节。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多