我正在尝试在我的Ubuntu 64位上编写我的第一个“Hello world”shellcode,但它不起作用。
我有文件 hello.asm :
; 64-bit "Hello World!" in Linux NASM
global _start ; global entry point export for ld
section .text
_start:
; sys_write(stdout, message, length)
mov rax, 1 ; sys_write
mov rdi, 1 ; stdout
mov rsi, message ; message address
mov rdx, length ; message string length
syscall
; sys_exit(return_code)
mov rax, 60 ; sys_exit
mov rdi, 0 ; return 0 (success)
syscall
section .data
message: db 'Hello, world!',0x0A ; message and newline
length: equ $-message ; NASM definition pseudo-instruction
我使用了这个命令:
nasm -felf64 hello.asm -o hello.o
ld -o hello hello.o
objdump -d hello
我将来自objdump的shellcode放入我的C程序中:
char code[] = "\xb8\x01\x00\x00\x00\xbf\x01\x00\x00\x00\x48\xbe\xd8\x00\x60\x00\x00\x00\x00\x00\xba\x0e\x00\x00\x00\x0f\x05\xb8\x3c\x00\x00\x00\xbf\x00\x00\x00\x00\x0f\x05";
int main(int argc, char **argv)
{
int (*func)();
func = (int (*)()) code;
(int)(*func)();
return 0;
}
并在gcc中编译它,但运行后我有“Segmentation fault(core dumped)”。
我不知道我做错了什么。汇编程序代码似乎有效,因为当我运行 ./ hello 时,它会输出“Hello world”。
答案 0 :(得分:3)
如果要将其插入缓冲区,最好删除nullbytes,但主要问题可能是数据段中有字符串?
我像这样重写了它并让它发挥作用。
global _start
_start:
jmp short string
code:
pop rsi
xor rax, rax
mov al, 1
mov rdi, rax
mov rdx, rdi
add rdx, 14
syscall
xor rax, rax
add rax, 60
xor rdi, rdi
syscall
string:
call code
db 'Hello, world!',0x0A
$ nasm -felf64 hello.asm -o hello.o
$ ld -s -o hello hello.o
$ for i in $(objdump -d hello |grep "^ " |cut -f2); do echo -n '\x'$i; done; echo
\xeb\x1e\x5e\x48\x31\xc0\xb0\x01\x48\x89\xc7\x48\x89\xfa\x48\x83\xc2\x0e\x0f\x05\x48\x31\xc0\x48\x83\xc0\x3c\x48\x31\xff\x0f\x05\xe8\xdd\xff\xff\xff\x48\x65\x6c\x6c\x6f\x2c\x20\x77\x6f\x72\x6c\x64\x21\x0a
char code[] = "\xeb\x1e\x5e\x48\x31\xc0\xb0\x01\x48\x89\xc7\x4\x89\xfa \x48\x83\xc2\x0e\x0f\x05\x48\x31\xc0\x48\x83\xc0\x3c\x48\x31\xff\x0f\x05\xe8\xdd\xff\xff\xff\x48\x65\x6c\x6c\x6f\x2c\x20\x77\x6f\x72\x6c\x64\x21\x0a";
int main(int argc, char **argv)
{
int (*func)();
func = (int (*)()) code;
(int)(*func)();
return 0;
}
$ gcc -fno-stack-protector -z execstack -o code code.c
$./code
Hello, world!
答案 1 :(得分:1)
您可以简单地使用nasm -felf64
进行编译并与ld
相关联。不需要gcc
。我相信您偶然发现的问题是代码中的x86
样式equ $-message
计算。对于x86_64,这是无效的。这是一个简单的例子:
section .data
string1 db 0xa, " Hello StackOverflow!!!", 0xa, 0xa, 0
section .text
global _start
_start:
; calculate the length of string
mov rdi, string1 ; string1 to destination index
xor rcx, rcx ; zero rcx
not rcx ; set rcx = -1
xor al,al ; zero the al register (initialize to NUL)
cld ; clear the direction flag
repnz scasb ; get the string length (dec rcx through NUL)
not rcx ; rev all bits of negative results in absolute value
dec rcx ; -1 to skip the null-terminator, ecx contains length
mov rdx, rcx ; put length in rdx
; write string to stdout
mov rsi, string1 ; string1 to source index
mov rax, 1 ; set write to command
mov rdi,rax ; set destination index to rax (stdout)
syscall ; call kernel
; exit
xor rdi,rdi ; zero rdi (rdi hold return value)
mov rax, 0x3c ; set syscall number to 60 (0x3c hex)
syscall ; call kernel
<强>编译/输出强>
$ nasm -felf64 -o hello-stack_64.o hello-stack_64.asm
$ ld -o hello-stack_64 hello-stack_64.o
$ ./hello-stack_64
Hello StackOverflow!!!
答案 2 :(得分:0)
希望回答这个问题还为时不晚:)
您必须使用此代码编译C代码(禁用堆栈保护并使其可执行):
gcc -fno-stack-protector -z execstack -o hello hello.c
祝你好运
答案 3 :(得分:0)
这里存在两层问题。
1)char data[] = ...
将被放入数据段,这是不可执行的。您需要const char data[] = ...
,以便将其放入文本段中。 (从技术上讲,它将位于只读数据段中,可能被标记为不可执行,但据我所知目前没有人这样做。)< / p>
2)这是我在反汇编data
:
0: b8 01 00 00 00 mov eax, 0x1
5: bf 01 00 00 00 mov edi, 0x1
a: 48 be d8 00 60 00 00 movabs rsi, 0x6000d8
11: 00 00 00
14: ba 0e 00 00 00 mov edx, 0xe
19: 0f 05 syscall
1b: b8 3c 00 00 00 mov eax, 0x3c
20: bf 00 00 00 00 mov edi, 0x0
25: 0f 05 syscall
这是我尝试运行时得到的结果:
$ strace ./a.out
execve("./a.out", ["./a.out"], [/* 38 vars */]) = 0
write(1, 0x6000d8, 14) = -1 EFAULT (Bad address)
_exit(0) = ?
+++ exited with 0 +++
你可以看到 问题是您只将代码放入0x6000d8
,而不是字符串。您需要在代码之后立即放置字符串,并使用PC相对寻址来获取它。 nighter的答案显示了这样做(在data
下可能没有出现\x00
字节的额外约束下,如果你实际上在这里利用了典型的缓冲区溢出,这将是必要的而不只是用机器语言搞笑。)