【问题标题】:How would I translate the following assembly code from the compiler to C when working with structs?使用结构时,如何将以下汇编代码从编译器翻译成 C?
【发布时间】:2021-07-25 08:41:03
【问题描述】:

假设我定义了一个新的struct

struct s {
   int *x;
   struct {
      short sh[2];
      int i;
   } w;
   struct s *next;
};

另外,我写了一个函数来初始化它:

void init_s(struct s *ss) {
   ss->w.sh[1] = /* Line 1 */;
   ss->x = /* Line 2 */;
   ss->next = /* Line 3 */;
}

编译器为init_s生成以下汇编代码:

init_s:             # line 1
   movw 8(%rdi), %ax    # line 2
   movw %ax, 10(%rdi)   # line 3
   leaq 12(%rdi), %rax  # line 4
   movq %rax, (%rdi)    # line 5
   movq %rdi, 16(%rdi)  # line 6
   retq                 # line 7

我要做的是根据程序集为init_s 填写缺少的代码行。我已经弄清楚(或者至少我是这么认为的)第 1 行和第 2 行。第 1 行应该是 ss->w.sh[0],第 2 行应该是 &(ss->w.sh[2])。但是,我在第 3 行遇到问题。我认为它会是基于程序集的&(ss->x),但我觉得这是不正确的,我不知道为什么。非常感谢任何反馈或建议,以帮助我了解有关程序集和结构的更多信息。

【问题讨论】:

  • 虽然我知道您的 init_s 是一个带有占位符的示例,但也许您还应该显示用于生成程序集的实际编译代码?
  • @AKX:我认为这个想法是对init_s进行逆向工程。
  • 没错。我没有意识到第一部分是假设的。

标签: c pointers assembly struct x86-64


【解决方案1】:

第一行应该是ss->w.sh[0]

我同意。

第 2 行应该是 &(ss->w.sh[2])

这是正确的地址,除了 ss->w.sh 只有 2 个元素,所以 w.sh[2] 超出范围。相反,它是指向结构的下一个成员的指针,即ss->x = &(ss->w.i)。这对于 ss->x 成员是 int * 而不是 short * 也是有意义的。

但是,我在第 3 行遇到问题。我认为基于程序集应该是 &(ss->x)

类似的问题:%rdi 确实可以是指向ss->x 的指针,但是将&ss->x(类型int **)分配给ss->next(类型@987654335)在类型方面没有意义@)。您还可以将%rdi 视为指向结构*ss 本身的指针,这更明智:ss->next = ss;。它创建一个带有单个节点的循环链表,其next 就是它本身。

这里的寓意是,在 C 中可以有不同的方式来引用相同的地址,所有这些都会生成相同的程序集,并且您必须使用常识来对作者更有可能做出有根据的猜测故意的。从理论上讲,C 代码的作者可能将ss->next = (struct s *)&(ss->x); 写为第三行——我们无法证明他们没有——但ss->next = ss; 更明智,因此更有可能。

这就是为什么逆向工程既是一门艺术又是一门科学的原因。

【讨论】:

  • 感谢您澄清您的推理。现在将其视为链表更有意义。当我写我的问题时,我也没有意识到 w.sh 的索引超出了范围。作为一个直到最近才使用 C 和指针的人,结构对我来说有点奇怪。
猜你喜欢
  • 1970-01-01
  • 2021-07-25
  • 1970-01-01
  • 2023-03-08
  • 2012-10-17
  • 1970-01-01
  • 2021-08-16
  • 2015-01-13
  • 2022-11-20
相关资源
最近更新 更多