Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.2k views
in Technique[技术] by (71.8m points)

macos - Testing Shellcode From C - Bus Error 10

Below, I written x64 assembly that prints 'Hello, World!' from a syscall on Mac OS X 10.8. It assembles and runs perfect when executed standalone.

; Assemble and link with:
; nasm -f macho64 -o HelloWorld.o HelloWorld.s
; ld -arch x86_64 -o HelloWorld HelloWorld.o

global start

section .text

start:

    push rbp
    mov rbp, rsp

    jmp short String

    xor rdi, rdi
    mov di, 0x01

StringRet:
    pop rsi

    xor rdx, rdx
    mov dl, 0xE

    mov r8b, 0x02
    shl r8, 24
    or r8, 0x04
    mov rax, r8

    syscall            ; System call for write(4)

    xor edi, edi

    mov r8b, 0x02
    shl r8, 24
    or r8, 0x01
    mov rax, r8

    syscall            ; System call for exit(1)

    mov rsp, rbp
    pop rbp

String:

    call StringRet
    db 'Hello, World!'

The problem I'm having is when I try to run this code as shell code from a c program. I used otool to get the following machine opcodes.

otool -t HelloWorld.o

char code[] = "x55x48x89xe5x41xb0x02x49xc1xe0x18x49x83xc8x04x4c"
              "x89xc0x48x31xffx66xbfx01x00xebx1ex5ex48x31xd2xb2"
              "x0ex0fx05x41xb0x02x49xc1xe0x18x49x83xc8x01x4cx89"
              "xc0x31xffx0fx05x48x89xecx5dxe8xddxffxffxffx48x65"
              "x6cx6cx6fx2cx20x57x6fx72x6cx64x21";

And below is the c program I'm using to execute this. But I keep getting a Bus error: 10.

; Compile:
; gcc -o HelloWorldTest HelloWorldTest.c

char code[] = "x55x48x89xe5x41xb0x02x49xc1xe0x18x49x83xc8x04x4c"
              "x89xc0x48x31xffx66xbfx01x00xebx1ex5ex48x31xd2xb2"
              "x0ex0fx05x41xb0x02x49xc1xe0x18x49x83xc8x01x4cx89"
              "xc0x31xffx0fx05x48x89xecx5dxe8xddxffxffxffx48x65"
              "x6cx6cx6fx2cx20x57x6fx72x6cx64x21";

int main()
{
    int (*ret)();

    ret = (int(*)())code;

    (int)(*ret)();

    return 0;
}

When I step through with gdb I get KERN_PROTECTION_FAILURE right when execution is passed to the shellcode.

Updated Question:

The above was solved by Carl Norum, it was due to memory protection. I have a different problem but is similar to above. Instead of having the shell code in the same file, I want to read the shell code from a .txt file and execute it. Below I tried marking a section of memory as PROT_EXEC and read the contents of the .txt file into it and execute. But it won't work, I'm getting the same error, KERN_PROTECTION_FAILURE, I tried using mprotect and mmap to mark a section of memory as PROT_EXEC.

#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
#include <stdlib.h>

int (*ret)();

unsigned char* buf;

int main()
{
    FILE* file;
    file = fopen("text.txt", "rb");

    unsigned int len = ftell(file);

    buf = (char*)malloc(len);
    fread(buf, 1, len, file);

    fclose(file);

    mprotect(&buf, len, PROT_EXEC);

   // I also tried mmap, but same error.
   /*void *ptr = mmap(0, 1024, PROT_EXEC, MAP_ANON | MAP_PRIVATE, -1, 0);

    if (ptr == MAP_FAILED)
    {
        perror("mmap");
        exit(-1);
    }

    memcpy(ptr, buf, 1024);*/

    ret = buf;

    ret();

    return 0;
}

This is the text.txt file I'm reading in, its the same hello world code:

x55x48x89xe5xebx33x48x31xffx66xbfx01x00x5ex48x31xd2xb2x0ex41xb0x02x49xc1xe0x18x49x83xc8x04x4cx89xc0x0fx05x31xffx41xb0x02x49xc1xe0x18x49x83xc8x01x4cx89xc0x0fx05x48x89xecx5dxe8xc8xffxffxffx48x65x6cx6cx6fx2cx20x57x6fx72x6cx64x21x0a

Since I'm copying the contents of the txt file into PROC_EXEC memory, I don't understand why I'm getting KERN_PROTECTION_FAILURE.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Your program tries to execute the shellcode from a memory paged marked "execute disable", which is the default for memory in the data section. That's why you see the KERN_PROTECTION_FAILURE. You need to put the shellcode in the text section:

__attribute__((section("__TEXT,__text")))
char code[] = ...

After doing that, your program works fine:

$ clang -Wall -Wextra -pedantic -O2 example.c -o example
$ ./example
Hello, World!

Editorial note: You don't need the typecast on your function pointer invocation. Just ret(); will be fine. You'll need to get rid of at least the (int) part to compile without warnings.

Edit:

Here's a program that works without requiring you to do section-override gymnastics:

#include <sys/mman.h>
#include <inttypes.h>
#include <unistd.h>

char code[] = "x55x48x89xe5x41xb0x02x49xc1xe0x18x49x83xc8x04x4c"
              "x89xc0x48x31xffx66xbfx01x00xebx1ex5ex48x31xd2xb2"
              "x0ex0fx05x41xb0x02x49xc1xe0x18x49x83xc8x01x4cx89"
              "xc0x31xffx0fx05x48x89xecx5dxe8xddxffxffxffx48x65"
              "x6cx6cx6fx2cx20x57x6fx72x6cx64x21x0a";

int main()
{
    int (*ret)() = (int (*)())code;
    void *page = (void *)((uintptr_t)code & ~(getpagesize() - 1));

    mprotect(page, sizeof code, PROT_EXEC);

    ret();

    return 0;
}

Example runs:

$ clang -O2 -Wall -Wextra example.c -o example
$ ./example
Hello, World!
$ gcc -O2 -Wall -Wextra example.c -o example
$ ./example
Hello, World!

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...