CS:覆盖对 IDA 输出中全局变量的访问,例如 mov eax,cs:x?
CS: override on access to global variables in IDA output, like mov eax, cs:x?
我正在编写简单的程序然后分析它们。
今天我写了这个:
#include <stdio.h>
int x;
int main(void){
printf("Enter X:\n");
scanf("%d",&x);
printf("You enter %d...\n",x);
return 0;
}
编译成这样:
push rbp
mov rbp, rsp
lea rdi, s ; "Enter X:"
call _puts
lea rsi, x
lea rdi, aD ; "%d"
mov eax, 0
call ___isoc99_scanf
mov eax, cs:x <- don't understand this
mov esi, eax
lea rdi, format ; "You enter %d...\n"
mov eax, 0
call _printf
mov eax, 0
pop rbp
retn
我不明白cs:x
是什么意思。
我使用 Ubuntu x64、GCC 10.3.0 和 IDA pro 7.6。
TL:DR: IDA 混淆地使用 cs:
表示 64 位代码中的 RIP 相对寻址模式。
在 IDA 中,mov eax, x
表示 mov eax, DWORD [x]
,这反过来意味着从变量 x
.
中读取一个 DWORD
为了完整起见,mov rax, OFFSET x
表示 mov rax, x
(即将 x
的地址放在 rax
中)。
在 64 位中,位移仍然是 32 位的,因此,对于位置无关的可执行文件,并不总是可以通过对其地址进行编码来寻址变量(因为它是 64 位的,不适合 32 位的位字段)。而在与位置无关的代码中,这是不可取的。
相反,使用 。
在 NASM 中,RIP 相对寻址采用 mov eax, [REL x]
形式,在 gas 中为 mov x(%rip), %eax
。
此外,在 NASM 中,如果 DEFAULT REL
处于活动状态,则指令可以缩短为 mov eax, [x]
,这与 32 位语法相同。
每个反汇编器都会以不同的方式反汇编 RIP 相关操作数。正如您评论的那样,Ghidra 给出了 mov eax, DWORD PTR [x]
.
IDA 使用 mov eax, cs:x
表示 mov eax, [REL x]
/mov x(%rip), %eax
.
;IDA listing, 64-bit code
mov eax, x ;This is mov eax, [x] in NASM and most likely wrong unless your exec is not PIE and always loaded <= 4GiB
mov eax, cs:x ;This is mov eax, [REL x] in NASM and idiomatic to 64-bit programs
简而言之,您几乎可以忽略 cs:
,因为这正是 64 位模式下变量的寻址方式。
当然,如上面的列表所示,使用或不使用 RIP 相对寻址告诉您程序可以加载到任何地方或刚好低于 4GiB。
IDA 显示的 cs
前缀让我失望。
我可以看出它在心理上类似于“代码”,因此类似于 rip
寄存器,但我认为 RIP 相对寻址并不意味着 cs
段覆盖。
在32位模式下,代码段通常是只读的,所以像mov [cs:x], eax
这样的指令会出错。
在这种情况下,将 cs:
放在操作数前面是错误的。
在 64 位模式下,段覆盖(除了 fs
/gs
)被忽略(以及代码段的读取位无论如何都会被忽略),所以 cs:
的存在并不重要,因为 ds
和 cs
实际上是无法区分的。 (即使 ss
或 ds
覆盖也不会更改非规范地址的 #GP 或 #SS 例外。)
可能 AGU 甚至不再读取 fs
或 gs
以外的段基址的段影子寄存器。 (虽然即使在 32 位模式下,对于段基址 = 0 的正常情况,也有一个延迟较低的快速路径,因此硬件可能只是让它完成它的工作。)
在我看来 cs:
仍然具有误导性 - 2E
前缀字节在机器代码中仍然可以作为填充。大多数工具仍将其称为 CS 前缀,尽管 http://ref.x86asm.net/coder64.html 在 64 位模式下将其称为“空前缀”。这里没有这样的字节,cs:
不是暗示 RIP 相对寻址的明显或明确的方式。
我正在编写简单的程序然后分析它们。 今天我写了这个:
#include <stdio.h>
int x;
int main(void){
printf("Enter X:\n");
scanf("%d",&x);
printf("You enter %d...\n",x);
return 0;
}
编译成这样:
push rbp
mov rbp, rsp
lea rdi, s ; "Enter X:"
call _puts
lea rsi, x
lea rdi, aD ; "%d"
mov eax, 0
call ___isoc99_scanf
mov eax, cs:x <- don't understand this
mov esi, eax
lea rdi, format ; "You enter %d...\n"
mov eax, 0
call _printf
mov eax, 0
pop rbp
retn
我不明白cs:x
是什么意思。
我使用 Ubuntu x64、GCC 10.3.0 和 IDA pro 7.6。
TL:DR: IDA 混淆地使用 cs:
表示 64 位代码中的 RIP 相对寻址模式。
在 IDA 中,mov eax, x
表示 mov eax, DWORD [x]
,这反过来意味着从变量 x
.
中读取一个 DWORD
为了完整起见,mov rax, OFFSET x
表示 mov rax, x
(即将 x
的地址放在 rax
中)。
在 64 位中,位移仍然是 32 位的,因此,对于位置无关的可执行文件,并不总是可以通过对其地址进行编码来寻址变量(因为它是 64 位的,不适合 32 位的位字段)。而在与位置无关的代码中,这是不可取的。
相反,使用
在 NASM 中,RIP 相对寻址采用 mov eax, [REL x]
形式,在 gas 中为 mov x(%rip), %eax
。
此外,在 NASM 中,如果 DEFAULT REL
处于活动状态,则指令可以缩短为 mov eax, [x]
,这与 32 位语法相同。
每个反汇编器都会以不同的方式反汇编 RIP 相关操作数。正如您评论的那样,Ghidra 给出了 mov eax, DWORD PTR [x]
.
IDA 使用 mov eax, cs:x
表示 mov eax, [REL x]
/mov x(%rip), %eax
.
;IDA listing, 64-bit code
mov eax, x ;This is mov eax, [x] in NASM and most likely wrong unless your exec is not PIE and always loaded <= 4GiB
mov eax, cs:x ;This is mov eax, [REL x] in NASM and idiomatic to 64-bit programs
简而言之,您几乎可以忽略 cs:
,因为这正是 64 位模式下变量的寻址方式。
当然,如上面的列表所示,使用或不使用 RIP 相对寻址告诉您程序可以加载到任何地方或刚好低于 4GiB。
IDA 显示的 cs
前缀让我失望。
我可以看出它在心理上类似于“代码”,因此类似于 rip
寄存器,但我认为 RIP 相对寻址并不意味着 cs
段覆盖。
在32位模式下,代码段通常是只读的,所以像mov [cs:x], eax
这样的指令会出错。
在这种情况下,将 cs:
放在操作数前面是错误的。
在 64 位模式下,段覆盖(除了 fs
/gs
)被忽略(以及代码段的读取位无论如何都会被忽略),所以 cs:
的存在并不重要,因为 ds
和 cs
实际上是无法区分的。 (即使 ss
或 ds
覆盖也不会更改非规范地址的 #GP 或 #SS 例外。)
可能 AGU 甚至不再读取 fs
或 gs
以外的段基址的段影子寄存器。 (虽然即使在 32 位模式下,对于段基址 = 0 的正常情况,也有一个延迟较低的快速路径,因此硬件可能只是让它完成它的工作。)
在我看来 cs:
仍然具有误导性 - 2E
前缀字节在机器代码中仍然可以作为填充。大多数工具仍将其称为 CS 前缀,尽管 http://ref.x86asm.net/coder64.html 在 64 位模式下将其称为“空前缀”。这里没有这样的字节,cs:
不是暗示 RIP 相对寻址的明显或明确的方式。