有许多技术可以从 shellcode 中去除零。 本节讨论了一些可能对本实验有用的常见技术。 amd64 和 arm64 架构的除零技术基本思想相同,但指令不同,这里以 amd64 指令为例。 在 Apple 机器上工作的学生可以参考在线文档中的 arm64 指导: 编写 ARM64 shellcode

  • 如果我们想将零赋值给 rax,可以使用 "mov rax, 0", 但这样做会在机器代码中产生零。 一种典型的解决方法是使用 "xor rax, rax",即将 rax 自己与自己异或,结果是零,并将其存储到 rax。

  • 如果我们想将 0x99 存储到 rax。 不能直接使用 "mov rax, 0x99",因为第二个操作数会扩展为 8 字节, 即 0x0000000000000099,包含七个零。 解决这个问题的方法是先将 rax 置零,然后将一字节数字 0x99 赋值给 al 寄存器,即 eax 寄存器的最低有效 8 位。

xor rax, rax
mov al,  0x99
  • 另一种方法是使用移位。 同样,我们想将 0x99 存储到 rax。 首先将 0xFFFFFFFFFFFF99 存储到 rax。 然后左移该寄存器 56 位,这样 rax 中的值就变成了 0x9900000000000000。 然后再右移该寄存器 56 位, 最高的 56 位(7 字节)将被填充为 0x00, rax 中的值会变成 0x0000000000000099。
mov  rax, 0xFFFFFFFFFFFFFF99
shl  rax, 56
shr  rax, 56
  • 字符串需要以零结尾,但如果我们使用下面代码的第一行定义字符串,代码中会包含一个零。 为了解决这个问题,我们使用第二行定义字符串,即在字符串末尾放置一个非零字节(0xFF)。
db 'abcdef', 0x00 
db 'abcdef', 0xFF
  • 在获取字符串地址后,我们可以动态地将非零字节替换为 0x00。 假设我们已将字符串的地址保存到 rbx, 我们还知道字符串的长度(不包括零)为 6, 因此可以使用以下指令将 0xFF 替换为 0x00。
xor al, al
mov [rbx+6], al
最后修改: 2025年07月26日 星期六 09:00