逆向工程和解释汇编代码

Posted

技术标签:

【中文标题】逆向工程和解释汇编代码【英文标题】:Reverse engineering and interpreting assembly code 【发布时间】:2021-08-16 08:22:57 【问题描述】:

我在对这个汇编代码进行逆向工程以推断数组维度的值时遇到了困难。

给我

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 的值。

我们总是感谢任何和所有的帮助:)

谢谢:))

【问题讨论】:

【参考方案1】:

索引二维数组必须将第一个索引缩放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 太聪明以至于不能这么简单:它是multiplying using one or two 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 语法输出。)

【讨论】:

好的!这条线做了什么“leaq array1(%rip), %rax”?在asm代码中,这部分“array1[i1][j1].x”对应于哪里? @MeganDarcy:这会将array1 的地址放入RAX。 How to load address of function or label into register。像mov $array1, %eax,除了它在与位置无关的代码中工作(这是现代发行版上的gcc默认值 - 这就是为什么我在Godbolt链接中使用-fpie来匹配你的asm。没有它,你会看到GCC使用像这样的寻址模式array1(%rcx, %rdx),利用符号地址作为 32 位符号扩展的绝对地址与其他寄存器一起使用的能力。) 好的,谢谢!我说 A 是 3 而 B 是 12 对吗?还不太清楚如何获得 B 值 @MeganDarcy:这不是 12;这看起来与您的 asm 不同,更多的 LEA 乘以 3,然后是 4,因为它添加到 j1。顺便说一句,我刚刚更新了答案中的 Godbolt 链接以使用 __attribute__((ms_abi)) - 抱歉,我昨天没有注意到您的代码使用的是 Windows 调用约定,而不是 x86-64 System V;您的第一个参数在 RCX 中,而不是 RDI。 (我试图为这类问题写一个一般性的答案,而不是为你做作业)。无论如何,您可以通过找到 i2 的乘数来找到 B 值,这是到达 R8D 的变量。

以上是关于逆向工程和解释汇编代码的主要内容,如果未能解决你的问题,请参考以下文章

什么是android逆向工程师

逆向工程部分

第4章 x86反汇编速成班

将汇编代码逆向工程为 c 代码

从汇编逆向工程优化的 c 代码

反编译和反汇编有啥区别?