zxdb 中的汇编语言

拆卸

disassemble 命令(简称 di)从当前位置进行反汇编。如果有的话,说明和调用目的地将带有源代码行信息注解:

[zxdb] di
miscsvc.cc:118
 ▶ 0x20bc1c7aa60a  mov     dword ptr [rbx + 0x10c], eax
miscsvc.cc:122
   0x20bc1c7aa610  movabs  rax, -0x5555555555555556
   0x20bc1c7aa61a  mov     qword ptr [rbx + 0xe8], rax
   0x20bc1c7aa621  mov     qword ptr [rbx + 0xe8], 0x0
   0x20bc1c7aa62c  mov     rdi, qword ptr [rbx + 0xb0]
   0x20bc1c7aa633  mov     rax, qword ptr [rbx + 0xe8]
   0x20bc1c7aa63a  mov     qword ptr [rbx + 0x20], rax
   0x20bc1c7aa63e  call    0x20d    ➔ std::__2::size<>()

di 命令也可以接受地址或符号作为参数。如果指定函数名称,则会对整个函数进行反汇编:

[zxdb] di main
miscsvc.cc:88
   0x20bc1c7aa000  push    rbp
   0x20bc1c7aa001  mov     rbp, rsp
   0x20bc1c7aa004  push    rbx
   0x20bc1c7aa005  and     rsp, -0x20
   0x20bc1c7aa009  sub     rsp, 0x140
   0x20bc1c7aa010  mov     rbx, rsp
   0x20bc1c7aa013  mov     rax, qword ptr fs:[0x10]
   ...

开关

disassemble 命令接受以下开关:

  • --num=<lines>-n <lines>:要发出的行数或指令数。默认为给定函数中的指令(如果位置是函数名称),否则默认为 16。

  • --raw-r:除了解码后的指令之外,还输出原始字节。

单步进入机器指令

可以使用以下 Zxdb 命令对机器指令执行单步操作:

  • nexti / ni:单步进入下一条指令,单步执行函数调用。

  • stepi / si:在函数调用之后单步调试下一条指令。

例如:

[zxdb] ni
🛑 main(int, const char**) • main.cc:102
main.cc:99
 ▶ 0x23f711346233  mov   edx, 0x20
   0x23f711346238  call  0x35a3a3  ➔ __asan_memcpy
   0x23f71134623d  mov   rdi, qword ptr [rbx + 0x258]
   0x23f711346244  call  0x1677    ➔ $anon::DecodeCommandLine

[zxdb] ni
🛑 main(int, const char**) • main.cc:102
main.cc:99
 ▶ 0x23f711346238  call  0x35a3a3 ➔ __asan_memcpy
   0x23f71134623d  mov   rdi, qword ptr [rbx + 0x258]
   0x23f711346244  call  0x1677   ➔ $anon::DecodeCommandLine
   0x23f711346249  mov   rdi, qword ptr [rbx + 0x260]

Zxdb 会维护关于最后一个命令是汇编命令还是源代码的信息,并显示有关步进或断点命中的信息。如需切换到汇编语言模式,请输入 disassemble;如需切换回源代码模式,请输入 list

寄存器

regs 命令会显示最常见的 CPU 寄存器。

[zxdb] regs
General Purpose Registers
      rax  0xfffffffffffffffa = -6
      rbx          0x50b7085b
      rcx                 0x0 = 0
      rdx      0x2023de8c87a0
      rsi  0x7fffffffffffffff
      rdi          0x50b7085b
      rbp      0x224bb1e0b950
      rsp      0x224bb1e0b928
      ...

通过切换到 regs 命令,可显示 CPU 寄存器的其他类别和选项:

  • --all-a:启用所有注册类别(并不意味着 -e)。

  • --float-f:输出专用浮点寄存器。在大多数情况下,您应改用 --vector,因为所有 64 位 ARM 代码和大多数 x64 代码都使用矢量寄存器来存储浮点。

  • --vector-v:输出矢量寄存器。如需了解更多详情,请参阅下文。

  • --debug-d:输出调试寄存器。

  • --extended-e:启用更详细的标志解码。这样可以获得通常对日常调试没有帮助的更多信息。这包括 x64 的 rflags 寄存器中的系统级标志等信息。

表达式中的寄存器

寄存器可以在表达式中使用,就像变量一样。寄存器的规范名称是 $reg(register name)

[zxdb] print $reg(x3)
79

此外,如果没有同名的变量,也可以使用原始寄存器名称:

[zxdb] print x3
79

可以使用普通表达式评估语法来分配寄存器:

[zxdb] print x3 = 0
0

矢量寄存器

regs --vector 命令根据当前的 vector-format 设置在表中显示矢量寄存器。使用 get vector-format 查看当前值和文档,使用 set vector-format <new-value> 设置新的矢量格式。可能的值为:

  • i8(有符号)或 u8(无符号):8 位整数数组。
  • i16(有符号)或 u16(无符号):16 位整数数组。
  • i32(有符号)或 u32(无符号):32 位整数数组。
  • i64(有符号)或 u64(无符号):64 位整数数组。
  • i128(有符号)或 u128(无符号):128 位整数数组。
  • float:单精度浮点数数组。
  • double:双精度浮点数数组。这是默认值。
[zxdb] set vector-format double

[zxdb] regs -v
Vector Registers
  mxcsr 0x1fa0 = 8096

   Name [3] [2] [1]       [0]
   ymm0   0   0   0         0
   ymm1   0   0   0   3.14159
   ymm2   0   0   0         0
   ymm3   0   0   0         0
   ...

矢量寄存器还可用作表达式中的数组。vector-format 设置可控制如何将每个寄存器转换为数组值。例如,如需显示解释为 x86 矢量寄存器 ymm1 的浮点值的低 32 位:

[zxdb] set vector-format float

[zxdb] print ymm1[0]
3.14159

转换为数组时,低位被分配为索引 0,从此开始递增。请注意,regs 中的矢量寄存器表在右侧显示低值。