首页 > 解决方案 > 逆向工程和解释汇编代码

问题描述

我很难对这个汇编代码进行逆向工程来推断数组维度的值。

我被给

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    $4, %rdx
    movzwl  12(%rax,%rdx), %eax
    addl    8(%rcx,%rdx), %eax
    leaq    (%r9,%r8,2), %rdx
    leaq    array2(%rip), %rcx
    salq    $4, %rdx
    movzwl  12(%rcx,%rdx), %edx
    subl    %edx, %eax
    ret    

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

任何和所有的帮助总是很感激:)

谢谢 :))

标签: arraysassemblyx86reverse-engineeringgnu-assembler

解决方案


索引 2D 数组必须通过sizeof(struct vec3[A]):缩放第一个索引,array1这是一个数组数组,每个较小的数组都有A元素。因此,您查看 asm 并查看它的乘积。

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

请注意,前导维度[2]根本不参与计算;这只是告诉你你有多少总空间。设置几何的是后来的尺寸;不同行中同一列之间的步幅。


如果您还没有看到 C 如何针对不同的 A 和 B 值进行编译,请尝试使用一些示例,看看当您将 A 或 B 增加 1 时会发生什么变化。 https://godbolt.org/非常适合玩周围有类似的东西。

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

除了 GCC 太聪明以至于不能这么简单:它使用一个或两个 LEA 相乘,例如RCX + RCX*2= RCX*3,而不是使用imul $3, %rcx, %rdx例如。如果您对 A 和 B 使用大的非简单数字(例如 12345),您将看到实际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 语法输出。)


推荐阅读