我一直在尝试按照本教程(https://paraschetal.in/writing-your-own-shellcode)编写自己的shellcode。 99%的代码对我来说是有意义的,但是我心中只有两个挥之不去的疑问-这与编写shellcode有关
首先,我想我理解为什么我们要避免使用空字节,但是如何使用以下内容来避免使用空字节?
xor eax, eax
eax
现在不是正好包含空字节吗?还是包含0?当我们对其自身进行异或运算时,它返回False,对吗?
第二,该教程说:
最后,我们将系统调用号码(11或0xb)加载到eax 寄存器。但是,如果我们在指令中使用eax,则结果 shellcode将包含一些NULL(\ x00)字节,我们不希望这样。 我们的eax寄存器已经为NULL。所以我们只加载系统调用 编号而不是整个eax寄存器。
mov byte al, 0x0b
现在我知道这里发生了什么,数字11(对于execve
)正在加载到eax
寄存器的前8位(即al
)中。但是eax
的其余部分仍然包含空字节,那么这里到底能实现什么?
请注意,我花了大部分时间试图了解这一点后才来这里,所以请放轻松:)
答案 0 :(得分:5)
漏洞通常会攻击C代码,因此 shell代码通常需要以 NUL终止的字符串形式提供。如果外壳程序代码包含NUL字节,则被利用的C代码可能忽略,并从第一个零字节开始丢弃其余代码。
这仅涉及机器代码。如果您需要使用数字0xb调用系统调用,那么自然地您需要能够在EAX寄存器中生成数字0xb,但是您只能使用机器代码本身中不包含零字节的那些形式的机器代码。
xor eax, eax
会将eax
中的所有1个位都反转,即零。它的功能等同于
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。
如果后一个外壳程序代码由C程序以空终止的字符串处理,则b8 0b 00
之后的其余外壳程序可被程序丢弃并替换为内存中的其他字节,从本质上讲Shellcode不起作用。
答案 1 :(得分:3)
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字节。