汇编工作,但 shellcode 不工作
Assembly works, but shellcode does not
我有一个 x64 处理器,我正在研究 shell代码。
我有以下代码:
section .text
global _start
_start:
push rax
mov rbx, 0x68732f6e69622f2f
shr rbx, 0x8
push rbx
mov rdi, rsp
;mov rdi, com
mov al, 59
syscall
当使用 foolowing 命令编译时:
nasm -g -f elf64 execve.asm
并链接到:
ld execve.o -o execve
运行没问题。它打开一个shell。如果我从中得到 shell 代码:
"\x50\x48\xbb\x2f\x2f\x62\x69\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\xb0\x3b\x0f\x05"
并使用这个 C 程序:
int main(void)
{
const char shellcode[] = "\x50\x48\xbb\x2f\x2f\x62\x69\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\xb0\x3b\x0f\x05";
(*(void (*)()) shellcode)();
return 0;
}
编译它:
gcc -fno-stack-protector -z execstack -o ex2 ex.c
如果 运行 它 returns 一个分段错误,但它应该执行一个 shell。为什么?
感谢帮助!
您遗漏了 \x6e
。
这会导致 segv,因为 exec 失败并且在系统调用之后没有 return。
您的独立程序集取决于寄存器 rsi
和 rdx
被清零。
(从http://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/可以看出
sys_execve
通过寄存器 rdi
、rsi
和 rdx
接受三个参数,如果 rdi
是正确的文件名并且 Linux 也会接受它rsi
和 rdx
为零)。
程序启动时可能会出现这种情况,但当您运行
程序中间。
因此,如果 rsi
和 rdx
中有垃圾,系统调用将失败并且指令流
将继续执行它在 syscall 指令之后找到的垃圾字节,最终导致崩溃(这确实是你的情况,正如你所看到的,如果你 运行 程序通过 gdb
)
使系统调用成功的最简单方法是将第二个和第三个参数清零:
section .text
global _start
_start:
xor rax, rax
xor rsi, rsi ; zero 2nd argument
xor rdx, rdx ; zero 3rd argument
push rax
mov rbx, 0x68732f6e69622f2f
shr rbx, 0x8
push rbx
mov rdi, rsp
mov al, 59
syscall
对应的C代码:
int main(void)
{
char shellcode[] =
"\x48\x31\xc0\x48\x31\xd2\x48\x31\xf6\x50\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\xb0\x3b\x0f\x05"
;
((void (*)()) shellcode)();
return 0;
}
我有一个 x64 处理器,我正在研究 shell代码。
我有以下代码:
section .text
global _start
_start:
push rax
mov rbx, 0x68732f6e69622f2f
shr rbx, 0x8
push rbx
mov rdi, rsp
;mov rdi, com
mov al, 59
syscall
当使用 foolowing 命令编译时:
nasm -g -f elf64 execve.asm
并链接到:
ld execve.o -o execve
运行没问题。它打开一个shell。如果我从中得到 shell 代码:
"\x50\x48\xbb\x2f\x2f\x62\x69\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\xb0\x3b\x0f\x05"
并使用这个 C 程序:
int main(void)
{
const char shellcode[] = "\x50\x48\xbb\x2f\x2f\x62\x69\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\xb0\x3b\x0f\x05";
(*(void (*)()) shellcode)();
return 0;
} 编译它:
gcc -fno-stack-protector -z execstack -o ex2 ex.c
如果 运行 它 returns 一个分段错误,但它应该执行一个 shell。为什么? 感谢帮助!
您遗漏了 \x6e
。
这会导致 segv,因为 exec 失败并且在系统调用之后没有 return。
您的独立程序集取决于寄存器 rsi
和 rdx
被清零。
(从http://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/可以看出
sys_execve
通过寄存器 rdi
、rsi
和 rdx
接受三个参数,如果 rdi
是正确的文件名并且 Linux 也会接受它rsi
和 rdx
为零)。
程序启动时可能会出现这种情况,但当您运行 程序中间。
因此,如果 rsi
和 rdx
中有垃圾,系统调用将失败并且指令流
将继续执行它在 syscall 指令之后找到的垃圾字节,最终导致崩溃(这确实是你的情况,正如你所看到的,如果你 运行 程序通过 gdb
)
使系统调用成功的最简单方法是将第二个和第三个参数清零:
section .text
global _start
_start:
xor rax, rax
xor rsi, rsi ; zero 2nd argument
xor rdx, rdx ; zero 3rd argument
push rax
mov rbx, 0x68732f6e69622f2f
shr rbx, 0x8
push rbx
mov rdi, rsp
mov al, 59
syscall
对应的C代码:
int main(void)
{
char shellcode[] =
"\x48\x31\xc0\x48\x31\xd2\x48\x31\xf6\x50\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\xb0\x3b\x0f\x05"
;
((void (*)()) shellcode)();
return 0;
}