逆向工程和解释汇编代码

Reverse engineering and interpreting assembly code

我在逆向工程此汇编代码以推断数组维度的值时遇到困难。

我给了

struct vec3 {
  long z;
  int x;
  unsigned short y;

};

struct vec3 array1[2][A];
struct vec3 array2[8][B];
int arrayfunc(int i1, int j1, int i2, int j2){
   return array1[i1][j1].x  + array1[i1][j1].y - array2[i2][j2].y;
}

这是提供的 C 代码,成员数据 x、y、z 的类型未知,但这是我推断的。

arrayfunc:
    leaq    array1(%rip), %rax
    movslq  %ecx, %rcx
    movslq  %edx, %r10
    movslq  %r9d, %r9
    leaq    (%rcx,%rcx,2), %rdx
    movslq  %r8d, %r8
    movq    %rax, %rcx
    addq    %r10, %rdx
    salq    , %rdx
    movzwl  12(%rax,%rdx), %eax
    addl    8(%rcx,%rdx), %eax
    leaq    (%r9,%r8,2), %rdx
    leaq    array2(%rip), %rcx
    salq    , %rdx
    movzwl  12(%rcx,%rdx), %edx
    subl    %edx, %eax
    ret    

这里的问题是我不确定如何从汇编代码中找到 A 和 B 的值。

我们将不胜感激 :)

谢谢:))

索引二维数组必须按 sizeof(struct vec3[A]) 缩放第一个索引:array1 是一个数组数组,每个较小的数组有 A 个元素。所以你看看汇编,看看它乘以什么。

给定,struct vec3 array1[2][A];
array1[i1][j1].x 与平面一维数组的地址数学运算相同:array1[ (i1*A) + j1 ].x。在 C 中,我们按元素而不是字节进行索引,因此 asm 也必须按 sizeof(struct vec3) 缩放。这显然是 sal , %reg 指令所做的,因为在填充对齐后结构大小为 16 字节。

请注意,前导维度 [2] 根本没有计算在内;那只是告诉你总共有多少space。设置几何的是后面的维度;不同行中同一列之间的步幅。


如果您还没有看到 C 将如何针对不同的 A 和 B 值进行编译,请尝试使用一些示例,看看当您将 A 或 B 增加 1 时会发生什么变化。https://godbolt.org/ 是理想的喜欢玩那样的东西。

例如https://godbolt.org/z/zrecTcqMs A 和 B 使用素数 3 和 7,因此即使不更改数字,您也可以看出它们是哪个的倍数。

除了 GCC 太聪明以至于它不会这么简单:它是 , e.g. RCX + RCX*2 = RCX*3, not using imul , %rcx, %rdx for example. If you use large non-simple numbers like 12345 for A and B, you'll see actual imul. https://godbolt.org/z/4G3qc5d5E


我使用 gcc -fpie 使其使用与位置无关的代码:一个 RIP 相关的 LEA 将数组地址放入寄存器,而不是像 array1(%rcx, %rdx, 2) 这样需要数组地址的寻址模式(在.data 或 .bss 部分)以适应机器代码中的 32 位符号扩展 disp32。

我还使用 __attribute__((ms_abi)) 来像您的代码一样使用 Windows x64 调用约定,因为 Godbolt 编译器资源管理器上的 GCC 的目标是 Linux。 (MSVC 是 Godbolt 上唯一默认以 Windows 为目标的编译器,但它不会以 AT&T 语法输出。)