逆向工程和解释汇编代码
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 语法输出。)
我在逆向工程此汇编代码以推断数组维度的值时遇到困难。
我给了
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 太聪明以至于它不会这么简单:它是 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 语法输出。)