Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C Linux外壳代码“;你好,世界&引用;_C_Linux_Assembly_Nasm_Shellcode - Fatal编程技术网

C Linux外壳代码“;你好,世界&引用;

C Linux外壳代码“;你好,世界&引用;,c,linux,assembly,nasm,shellcode,C,Linux,Assembly,Nasm,Shellcode,我有以下工作NASM代码: global _start section .text _start: mov eax, 0x4 mov ebx, 0x1 mov ecx, message mov edx, 0xF int 0x80 mov eax, 0x1 mov ebx, 0x0 int 0x80 section .data message: db "Hello, World!", 0dh, 0ah 将“Hello

我有以下工作NASM代码:

global _start

section .text

_start:
    mov eax, 0x4
    mov ebx, 0x1
    mov ecx, message
    mov edx, 0xF
    int 0x80

    mov eax, 0x1
    mov ebx, 0x0
    int 0x80

section .data
    message: db "Hello, World!", 0dh, 0ah
将“Hello,World!\n”打印到屏幕上。我还有以下C包装器,其中包含前面的NASM对象代码:

char code[] =
"\xb8\x04\x00\x00\x00"
"\xbb\x01\x00\x00\x00"
"\xb9\x00\x00\x00\x00"
"\xba\x0f\x00\x00\x00"
"\xcd\x80\xb8\x01\x00"
"\x00\x00\xbb\x00\x00"
"\x00\x00\xcd\x80";

int main(void)
{
    (*(void(*)())code)();
}
但是,当我运行代码时,似乎没有执行汇编代码,但程序可以正常退出。有什么想法吗


谢谢

当您注入此外壳代码时,您不知道
消息中的内容

mov ecx, message
在注入过程中,它可以是任何内容,但不会是
“Hello world!\r\n”
,因为它位于数据部分,而您只转储文本部分。您可以看到您的外壳代码没有“Hello world!\r\n”:

这是外壳代码开发中的常见问题,解决方法如下:

global _start

section .text

_start:
    jmp MESSAGE      ; 1) lets jump to MESSAGE

GOBACK:
    mov eax, 0x4
    mov ebx, 0x1
    pop ecx          ; 3) we are poping into `ecx`, now we have the
                     ; address of "Hello, World!\r\n" 
    mov edx, 0xF
    int 0x80

    mov eax, 0x1
    mov ebx, 0x0
    int 0x80

MESSAGE:
    call GOBACK       ; 2) we are going back, since we used `call`, that means
                      ; the return address, which is in this case the address 
                      ; of "Hello, World!\r\n", is pushed into the stack.
    db "Hello, World!", 0dh, 0ah

section .data
现在转储文本部分:

$ nasm -f elf shellcode.asm
$ ld shellcode.o -o shellcode
$ ./shellcode 
Hello, World!
$ objdump -d shellcode

shellcode:     file format elf32-i386


Disassembly of section .text:

08048060 <_start>:
 8048060:   e9 1e 00 00 00   jmp    8048083 <MESSAGE>

08048065 <GOBACK>:
 8048065:   b8 04 00 00 00   mov    $0x4,%eax
 804806a:   bb 01 00 00 00   mov    $0x1,%ebx
 804806f:   59               pop    %ecx
 8048070:   ba 0f 00 00 00   mov    $0xf,%edx
 8048075:   cd 80            int    $0x80
 8048077:   b8 01 00 00 00   mov    $0x1,%eax
 804807c:   bb 00 00 00 00   mov    $0x0,%ebx
 8048081:   cd 80            int    $0x80

08048083 <MESSAGE>:
 8048083:   e8 dd ff ff ff   call   8048065 <GOBACK>
 8048088:   48               dec    %eax                    <-+
 8048089:   65               gs                               |
 804808a:   6c               insb   (%dx),%es:(%edi)          |
 804808b:   6c               insb   (%dx),%es:(%edi)          |
 804808c:   6f               outsl  %ds:(%esi),(%dx)          |
 804808d:   2c 20            sub    $0x20,%al                 |
 804808f:   57               push   %edi                      |
 8048090:   6f               outsl  %ds:(%esi),(%dx)          |
 8048091:   72 6c            jb     80480ff <MESSAGE+0x7c>    |
 8048093:   64               fs                               |
 8048094:   21               .byte 0x21                       |
 8048095:   0d               .byte 0xd                        |
 8048096:   0a               .byte 0xa                      <-+

$
因此,我们的C包装将是:

char code[] = 

    "\xe9\x1e\x00\x00\x00"  //          jmp    (relative) <MESSAGE>
    "\xb8\x04\x00\x00\x00"  //          mov    $0x4,%eax
    "\xbb\x01\x00\x00\x00"  //          mov    $0x1,%ebx
    "\x59"                  //          pop    %ecx
    "\xba\x0f\x00\x00\x00"  //          mov    $0xf,%edx
    "\xcd\x80"              //          int    $0x80
    "\xb8\x01\x00\x00\x00"  //          mov    $0x1,%eax
    "\xbb\x00\x00\x00\x00"  //          mov    $0x0,%ebx
    "\xcd\x80"              //          int    $0x80
    "\xe8\xdd\xff\xff\xff"  //          call   (relative) <GOBACK>
    "Hello wolrd!\r\n";     // OR       "\x48\x65\x6c\x6c\x6f\x2c\x20\x57"
                            //          "\x6f\x72\x6c\x64\x21\x0d\x0a"


int main(int argc, char **argv)
{
    (*(void(*)())code)();

    return 0;
}
它起作用了。(
-m32
在64位系统上也是必需的。
int$0x80
32位ABI不能与饼图可执行文件中的
.rodata
那样的64位地址一起工作。此外,机器代码是为32位进行汇编的。在64位模式下,相同的字节序列可能会解码为等效的指令,但这并不总是正确的(案例)

现代GNU
ld
.rodata
.text
放在一个单独的段中,因此它可能是不可执行的。过去,使用
const char code[]
将可执行代码放入只读数据页就足够了。至少对于不想修改自身的外壳代码。

如上所述,外壳代码不包含消息字节。在定义
msg
字节之前,跳转到
MESSAGE
标签并调用
GOBACK
例程是一个很好的移动,因为msg的地址将作为返回地址位于堆栈顶部,可以弹出到
ecx
,其中存储msg的地址

但是您和的代码都有一点限制。 它包含
空字节(\x00)
,当被函数指针取消引用时,这些字节将被视为字符串的结尾

有一个聪明的方法解决这个问题。存储在
eax、ebx和edx中的值足够小,可以通过分别访问
al、bl和dl
直接写入相应寄存器的下半字节。 上半字节可能包含垃圾值,因此可以对其进行异或运算。

b8 04 00 00 00 ------ mov $0x4,%eax

变成

b0 04          ------ mov $0x4,%al
31 c0          ------ xor    %eax,%eax

与以前的指令集不同,新指令集不包含任何空字节

最后的程序如下所示:

global _start

section .text

_start:
jmp message

proc:
    xor eax, eax
    mov al, 0x04
    xor ebx, ebx
    mov bl, 0x01
    pop ecx
    xor edx, edx
    mov dl, 0x16
    int 0x80

    xor eax, eax
    mov al, 0x01
    xor ebx, ebx
    mov bl, 0x01   ; return 1
    int 0x80

message:
    call proc
    msg db " y0u sp34k 1337 ? "

section .data
装配和连接:

$ nasm -f elf hello.asm -o hello.o
$ ld -s -m elf_i386 hello.o -o hello
$ ./hello
 y0u sp34k 1337 ? $ 
现在从hello二进制文件中提取外壳代码:

$ for i in `objdump -d hello | tr '\t' ' ' | tr ' ' '\n' | egrep '^[0-9a-f]{2}$' ` ; do echo -n "\\x$i" ; done
输出:

\xeb\x19\x31\xc0\xb0\x04\x31\xdb\xb3\x01\x59\x31\xd2\xb2\x12\xcd\x80\x31\xc0\xb0\x01\x31\xdb\xb3\x01\xcd\x80\xe8\xe2\xff\xff\xff\x20\x79\x30\x75\x20\x73\x70\x33\x34\x6b\x20\x31\x33\x33\x37\x20\x3f\x20
现在我们可以使用我们的驱动程序来启动外壳代码

#include <stdio.h>

char shellcode[] = "\xeb\x19\x31\xc0\xb0\x04\x31\xdb"
                   "\xb3\x01\x59\x31\xd2\xb2\x12\xcd"
                   "\x80\x31\xc0\xb0\x01\x31\xdb\xb3"
                   "\x01\xcd\x80\xe8\xe2\xff\xff\xff"
                   "\x20\x79\x30\x75\x20\x73\x70\x33"
                   "\x34\x6b\x20\x31\x33\x33\x37\x20"
                   "\x3f\x20";


int main(int argc, char **argv) {
    (*(void(*)())shellcode)();
    return 0;
}
$ ./launcher
 y0u sp34k 1337 ? $ 
现在可以调用
启动器来启动外壳代码

#include <stdio.h>

char shellcode[] = "\xeb\x19\x31\xc0\xb0\x04\x31\xdb"
                   "\xb3\x01\x59\x31\xd2\xb2\x12\xcd"
                   "\x80\x31\xc0\xb0\x01\x31\xdb\xb3"
                   "\x01\xcd\x80\xe8\xe2\xff\xff\xff"
                   "\x20\x79\x30\x75\x20\x73\x70\x33"
                   "\x34\x6b\x20\x31\x33\x33\x37\x20"
                   "\x3f\x20";


int main(int argc, char **argv) {
    (*(void(*)())shellcode)();
    return 0;
}
$ ./launcher
 y0u sp34k 1337 ? $ 
对于更复杂的外壳代码,还有另一个障碍。现代Linux内核具有或
地址空间布局随机化
您可能需要在注入外壳代码之前禁用此功能,尤其是在缓冲区溢出时。

root@localhost:~# echo 0 > /proc/sys/kernel/randomize_va_space 

我不知道你为什么没有得到任何选票,但这是一个很好的答案。谢谢您的帮助。@REALFREE Null byte如果您使用的函数需要以Null结尾的字符串类字符串函数,如
strcpy
,则可能会出现问题,因为它无法读取整个外壳代码string。否则没关系。
$ ./launcher
 y0u sp34k 1337 ? $ 
root@localhost:~# echo 0 > /proc/sys/kernel/randomize_va_space