这个是系统架构,下面是测试代码「hello.c」:
char shellCode[] = "\xeb\x1a\x5e\x48\x31\xff\x48\x31\xd2\x48\x31\xc0\x66\xff\xc7\xb2\x0d\xb0\x01\x0f\x05\x48\x31\xff\xb0\x3c\x0f\x05\xe8\xe1\xff\xff\xff\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64\x21\x0a"; int main (void) { long p; *(&p+2) = (long)shellCode; return 0; }
奇怪了就,gcc 生成目标文件,然后看了下节头:
明摆着就就一个text 段可执行,居然真把shellcode 给执行了,这货明摆着在「.data」 里:
话说这地方真是费解了,写这个程序主要是看BINARY HACKS 的GNU 编程HACK 那一章,说2.6 之后都已经打了补丁,成了不可执行栈了,需要用objcopy 为数据所在的段增加X 标记才可以。于是手贱参考shellcode 的原理试了下,结果成了这个样子。。。
有空再回头看下,今晚要补完《濑户之花嫁》。
另外自己写的那段shellcode 是X86_64 版本的,就是调用了个write 系统调用,吐槽下X86_64 汇编系统调用的寄存器约定改的。。参数上来就用到rdi,给di 赋值1,为了避免产生\x0 都要换成xorq 和incw。。。
对于字符串的地址的运行时定位,我用的下面的方法确定的地址:
_start: jmp begin shellCode: popq %rsi # 出栈字符串地址 # 操作字符串的代码 begin: call shellCode # 利用call 指令压栈的特性把字符串地址压栈 .ascii "string"完了之后编译下,并且反汇编得到shellcode:
# as -o write.o write.s # ld -o write write.o # echo -e "\\\x""$(objdump -d write | perl -nE 's/.+:\s([a-f0-9 ]+).+/$1/g and s/\s+/\\\\x/g and print')""\b\b "
执行后会得到shellcode:
\xeb\x1a\x5e\x48\x31\xff\x48\x31\xd2\x48\x31\xc0\x66\xff\xc7\xb2\x0d\xb0\x01\x0f\x05\x48\x31\xff\xb0\x3c\x0f\x05\xe8\xe1\xff\xff\xff\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64\x21\x0a
话说X86 的架构得自己重写代码,因为调用约定全改了。。它好好的为什么要改呢。。?