标签:
尝试了好久,终于成功输出了hello world
实验环境
$uname -a Linux archlinux 4.2.5-1-ARCH #1 SMP PREEMPT Tue Oct 27 08:13:28 CET 2015 x86_64 GNU/Linux
$gcc --version
gcc (GCC) 5.2.0
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
核心代码
hello.s
1 section .text 2 global _start 3 4 _start: 5 6 jmp msg 7 8 code: 9 xor rax, rax ;clean up the registers 10 xor rbx, rbx 11 xor rdx, rdx 12 xor rcx, rcx 13 14 mov al, 4 ;syscall write 15 mov bl, 1 ;stdout is 1 16 pop rcx ;save string address 17 mov dl, 12 ;length of the string 18 int 0x80 19 20 xor rax, rax 21 mov al, 1 ;exit the shellcode 22 xor rbx,rbx 23 int 0x80 24 msg: 25 call code 26 db ‘hello world‘, 10
这里有几个值得注意的地方:
1. 由于c语言中的字符串以‘\0‘为结尾,我们生成的shell code就不能包含00字节,所以能用al就绝不用ax or eax or rax,bl,dl同理。
2. 注意到代码里有个莫名奇妙的pop rcx没有?有没有发现代码的组织很奇怪?为什么要先jmp到msg在call code呢?事实上这也是为了去掉00字节。
call 指令会将返回的地址(这里就是第26行)push到栈上,之后再pop到rcx。
$nasm -f elf64 hello.s -o hello.o $ld -s -o hello hello.o $./hello hello world $objdump -d hello
hello: file format elf64-x86-64
Disassembly of section .text:
0000000000400080 <.text>:
400080: eb 1f jmp 0x4000a1
400082: 48 31 c0 xor %rax,%rax
400085: 48 31 db xor %rbx,%rbx
400088: 48 31 d2 xor %rdx,%rdx
40008b: 48 31 c9 xor %rcx,%rcx
40008e: b0 04 mov $0x4,%al
400090: b3 01 mov $0x1,%bl
400092: 59 pop %rcx
400093: b2 0c mov $0xc,%dl
400095: cd 80 int $0x80
400097: 48 31 c0 xor %rax,%rax
40009a: b0 01 mov $0x1,%al
40009c: 48 31 db xor %rbx,%rbx
40009f: cd 80 int $0x80
4000a1: e8 dc ff ff ff callq 0x400082
4000a6: 68 65 6c 6c 6f pushq $0x6f6c6c65
4000ab: 20 77 6f and %dh,0x6f(%rdi)
4000ae: 72 6c jb 0x40011c
4000b0: 64 fs
4000b1: 0a .byte 0xa
可以看到没有00字节
可以写个小程序从objdump的输出中得到shellcode
1 #include <stdio.h> 2 char code[] = "\xeb\x1f\x48\x31\xc0\x48\x31\xdb\x48\x31\xd2\x48\x31\xc9\xb0\x04\xb3" 3 "\x01\x59\xb2\x0b\xcd\x80\x48\x31\xc0\xb0\x01\x48\x31\xdb\xcd\x80\xe8" 4 "\xdc\xff\xff\xff\x68\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64"; 5 6 7 int main() 8 { 9 void (*hello)(); 10 hello = (void (*)())code; 11 (*hello)(); 12 return 0;}
编译选项很重要,现代编译器似乎有保护
$gcc -z execstack hello.c $./a.out hello world
大功告成。
我的第一个shell code -- hello world
标签:
原文地址:http://www.cnblogs.com/cfeitong/p/5041958.html