把"Hello, World\n"转为机器码shellcode 来显示,执行却是Segmentation fault 真心求指点

时间:2021-03-31 17:09:10
把"Hello, World\n"转为机器码shellcode 来显示,执行却是Segmentation fault 真心求指点
我想把字符串转变为shellcode显示出来,可是却有问题了

首先下面是我的hello.s文件来显示"Hello, World\n"

下面的代码是AT&T的语法,不是Intel的,所以用的是as编译器, 

而不是 nasm

这个文件可以正常的把"Hello, World\n" 打印出来(问题不在这里)


.global _start
_start:
    jmp    do_call
jump_back:
    xor %eax, %eax
    xor %ebx, %ebx
    xor %ecx, %ecx
    xor %edx, %edx
    movb $4, %al
    movb $14, %dl
    popl %ecx
    movb $1, %bl
    int    $0x80

    xor %eax, %eax
    movb $1, %al
    xor %ebx, %ebx
    int $0x80

do_call:
    call    jump_back
hello:
    .ascii "Hello, World!\n"

然后用as编译,

$ as hello.s -o hello.o

$ ld hello.o -o hello

然后用objdump得到机器码

$ objdump -d hello

08048054 <_start>:
8048054:    eb 19                    jmp    804806f <do_call>

08048056 <jump_back>:
8048056:    31 c0                    xor    %eax,%eax
8048058:    31 db                    xor    %ebx,%ebx
804805a:    31 c9                    xor    %ecx,%ecx
804805c:    31 d2                    xor    %edx,%edx
804805e:    b0 04                    mov    $0x4,%al
8048060:    b2 0e                    mov    $0xe,%dl
8048062:    59                           pop    %ecx
8048063:    b3 01                    mov    $0x1,%bl
8048065:    cd 80                    int    $0x80
8048067:    31 c0                    xor    %eax,%eax
8048069:    b0 01                    mov    $0x1,%al
804806b:    31 db                    xor    %ebx,%ebx
804806d:    cd 80                    int    $0x80

0804806f <do_call>:
804806f:    e8 e2 ff ff ff           call   8048056 <jump_back>

08048074 <hello>:
8048074:    48                       dec    %eax
8048075:    65                       gs
8048076:    6c                       insb   (%dx),%es:(%edi)
8048077:    6c                       insb   (%dx),%es:(%edi)
8048078:    6f                       outsl  %ds:(%esi),(%dx)
8048079:    2c 20                    sub    $0x20,%al
804807b:    57                       push   %edi
804807c:    6f                       outsl  %ds:(%esi),(%dx)
804807d:    72 6c                    jb     80480eb <hello+0x77>
804807f:    64 21 0a                 and    %ecx,%fs:(%edx)

然后我把机器码串写来,写入文件hello_test.c

#include <stdlib.h>
char shellcode[] = "\xeb\x19\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x04"\
                    "\xb2\x0e\x59\xb3\x01\xcd\x80\x31\xc0\xb0\x01"\
                    "\x31\xdb\xcd\x80\xe8\xe2\xff\xff\xff"\
                    "\x48\x65\x6c\x6c\x6f\x2c\x20\x57\x6f\x72\x6c"\
                    "\x64\x21\x0a";
int main(int argc, char **argv) {
    int (*ret)();
    ret = (int(*)())shellcode;
    (int)(*ret)();
    exit(0);
}


然后编译
$ gcc -g hello_test.c -o hello_test
$ ./hello_test
Segmentation fault

怎么会出现这个错误啊

于是我看了一下

$ strace ./hello_test
(...)
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
+++ killed by SIGSEGV +++
Segmentation fault

我实在不明白为什么会这样

于是我关掉了gcc 的stack保护,再编译
$ gcc -fno-stack-protector hello_test.c -o hello_test
$ ./hello_test
Segmentation fault

还是不行,晕了啊
有没有可以指点明路的高人

7 个解决方案

#1



#include <stdlib.h>
const unsigned char shellcode[] = "\xeb\x19\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x04"\
                    "\xb2\x0e\x59\xb3\x01\xcd\x80\x31\xc0\xb0\x01"\
                    "\x31\xdb\xcd\x80\xe8\xe2\xff\xff\xff"\
                    "\x48\x65\x6c\x6c\x6f\x2c\x20\x57\x6f\x72\x6c"\
                    "\x64\x21\x0a";
int main(int argc, char **argv) {
    int (*ret)();
    ret = (int(*)())shellcode;
    (int)(*ret)();
    exit(0);
}

#2


link的时候必须指明可执行栈

gcc参数加上 -z execstack

#3


引用 1 楼  的回复:
C/C++ code

#include <stdlib.h>
const unsigned char shellcode[] = "\xeb\x19\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x04"\
                    "\xb2\x0e\x59\xb3\x01\xcd\x80\x31\xc0\xb0\x01"\
            ……

非常感謝你的回复,重新试了一下,确实成功了

我试了几次,unsigned char 也不可以,一定要加上const 
我在*上找到了可能我觉得正确的解释
http://*.com/questions/1576489/where-are-constant-variables-stored-in-c
一句话也就是加上const就把shellcode放到了 text section吧

#4


引用 2 楼  的回复:
link的时候必须指明可执行栈

gcc参数加上 -z execstack

非常感謝nevil的回复,这个方法也让我的程序跑起来了
下面是一张图
把"Hello, World\n"转为机器码shellcode 来显示,执行却是Segmentation fault 真心求指点
shellcode在这里应该是被当做一个函数吧,有自己的stack
所以要加上execstack 选项

#5


对头,归根到底就是要让你这段shellcode所放的内存有执行的权限

引用 3 楼  的回复:
引用 1 楼  的回复:

C/C++ code

#include <stdlib.h>
const unsigned char shellcode[] = "\xeb\x19\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x04"\
"\xb2\x0e\x59\xb3\x01\xcd\x80\x31\xc0\xb0\x01"\
……

非常感謝你的……

#6


我也遇到这个问题了,明明返回地址已经覆盖成功了,eip里面已经是jmp esp的地址,esp里面已经是shellcode了,就是不能运行,加上-z execvestack可以了,哎,现在的系统为了对付缓冲区溢出也是煞费苦心啊。。。以后想靠溢出干啥的,恐怕是不再可行了吧

#7


引用 6 楼 yanxf07 的回复:
我也遇到这个问题了,明明返回地址已经覆盖成功了,eip里面已经是jmp esp的地址,esp里面已经是shellcode了,就是不能运行,加上-z execvestack可以了,哎,现在的系统为了对付缓冲区溢出也是煞费苦心啊。。。以后想靠溢出干啥的,恐怕是不再可行了吧


more important: shellcode is for injection but who would disable overflow protection during compilation? no one...

#1



#include <stdlib.h>
const unsigned char shellcode[] = "\xeb\x19\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x04"\
                    "\xb2\x0e\x59\xb3\x01\xcd\x80\x31\xc0\xb0\x01"\
                    "\x31\xdb\xcd\x80\xe8\xe2\xff\xff\xff"\
                    "\x48\x65\x6c\x6c\x6f\x2c\x20\x57\x6f\x72\x6c"\
                    "\x64\x21\x0a";
int main(int argc, char **argv) {
    int (*ret)();
    ret = (int(*)())shellcode;
    (int)(*ret)();
    exit(0);
}

#2


link的时候必须指明可执行栈

gcc参数加上 -z execstack

#3


引用 1 楼  的回复:
C/C++ code

#include <stdlib.h>
const unsigned char shellcode[] = "\xeb\x19\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x04"\
                    "\xb2\x0e\x59\xb3\x01\xcd\x80\x31\xc0\xb0\x01"\
            ……

非常感謝你的回复,重新试了一下,确实成功了

我试了几次,unsigned char 也不可以,一定要加上const 
我在*上找到了可能我觉得正确的解释
http://*.com/questions/1576489/where-are-constant-variables-stored-in-c
一句话也就是加上const就把shellcode放到了 text section吧

#4


引用 2 楼  的回复:
link的时候必须指明可执行栈

gcc参数加上 -z execstack

非常感謝nevil的回复,这个方法也让我的程序跑起来了
下面是一张图
把"Hello, World\n"转为机器码shellcode 来显示,执行却是Segmentation fault 真心求指点
shellcode在这里应该是被当做一个函数吧,有自己的stack
所以要加上execstack 选项

#5


对头,归根到底就是要让你这段shellcode所放的内存有执行的权限

引用 3 楼  的回复:
引用 1 楼  的回复:

C/C++ code

#include <stdlib.h>
const unsigned char shellcode[] = "\xeb\x19\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x04"\
"\xb2\x0e\x59\xb3\x01\xcd\x80\x31\xc0\xb0\x01"\
……

非常感謝你的……

#6


我也遇到这个问题了,明明返回地址已经覆盖成功了,eip里面已经是jmp esp的地址,esp里面已经是shellcode了,就是不能运行,加上-z execvestack可以了,哎,现在的系统为了对付缓冲区溢出也是煞费苦心啊。。。以后想靠溢出干啥的,恐怕是不再可行了吧

#7


引用 6 楼 yanxf07 的回复:
我也遇到这个问题了,明明返回地址已经覆盖成功了,eip里面已经是jmp esp的地址,esp里面已经是shellcode了,就是不能运行,加上-z execvestack可以了,哎,现在的系统为了对付缓冲区溢出也是煞费苦心啊。。。以后想靠溢出干啥的,恐怕是不再可行了吧


more important: shellcode is for injection but who would disable overflow protection during compilation? no one...