XOR 如何防止 shellcode 中的 NULL 字节

How does XOR prevent NULL bytes in shellcode

我一直在尝试按照本教程 (https://paraschetal.in/writing-your-own-shellcode) 学习如何编写自己的 shellcode。 99% 的内容对我来说都是有意义的,但我心中只有两个挥之不去的疑虑——这与一般编写 shellcode 有关

首先,我想我理解为什么我们要避免空字节但是如何使用以下避免空字节?

xor eax, eax

eax 现在不完全包含空字节吗?或者它是否包含 0?当我们与自身异或时,它 returns 错误,正确吗?

其次,教程说:

Finally, we’ll load the syscall number(11 or 0xb) to the eax register. However if we use eax in our instruction, the resulting shellcode will contain some NULL(\x00) bytes and we don’t want that. Our eax register already is NULL. So we’ll just load the syscall number to the al register instead of the entire eax register.

mov byte  al, 0x0b

现在我明白这是怎么回事了,数字 11(代表 execve)被加载到 eax 寄存器的前 8 位(即 al) .但是 eax 的其余部分仍然包含空字节,那么这里到底实现了什么?

请注意,在花了一天的大部分时间试图理解这一点之后,我来到这里是最后的手段,所以请放轻松:)

漏洞通常攻击C代码,因此shell代码通常需要以NUL结尾的字符串[=49]传递=].如果 shell 代码包含 NUL 字节,则被利用的 C 代码可能 忽略 并丢弃从 第一个零字节 [=49] 开始的其余代码=].

这仅涉及 机器代码。如果你需要调用编号为0xb的系统调用,那么自然你需要能够在EAX寄存器中产生编号0xb,但你只能使用机器代码本身不包含零字节的那些形式的机器代码.


xor eax, eax

将反转 eax 中的所有 1 ,即 zero。它在功能上等同于

mov eax, 0

除了后者机器码.

中将0编码为零字节

的机器码
xor eax, eax
mov byte al, 0x0b

31 c0 b0 0b

如您所见,其中没有嵌入零字节。

的机器码
mov eax, 0xb

b8 0b 00 00 00

这两个程序在功能上是等同的,因为它们将 EAX 寄存器的值设置为 0xb。

如果后面的 shell 代码被 C 程序处理为空终止字符串,则 b8 0b 00 之后的其余部分可能会被程序丢弃并被其他字节替换在内存中,基本上使 shell 代码不起作用。

指令mov eax, 0汇编为

b8 00 00 00 00

其中包含 NUL 字节。但是,指令 xor eax, eax 汇编为

31 c0

不含 NUL 字节,适合 shell 代码。

同样适用于mov al, 0x0b。如果你做mov eax, 0x0b,编码就是

b8 0b 00 00 00

其中包含 NUL 字节。但是,mov al, 0x0b 编码为

b0 0b

避免 NUL 字节。