2012-03-31 11 views
6

Tôi muốn có một phương thức C đơn giản để có thể chạy hex bytecode trên máy Linux 64 bit. Đây là chương trình C mà tôi có:Làm cách nào để lấy mã c để thực thi mã byte hex?

char code[] = "\x48\x31\xc0"; 
#include <stdio.h> 
int main(int argc, char **argv) 
{ 
     int (*func)(); 
     func = (int (*)()) code; 
     (int)(*func)(); 
     printf("%s\n","DONE"); 
} 

Mã mà tôi đang cố gắng để chạy ("\x48\x31\xc0") Tôi thu được bằng writting chương trình lắp ráp đơn giản này (nó không phải thực sự làm bất cứ điều gì)

.text 
.globl _start 
_start: 
     xorq %rax, %rax 

và sau đó biên dịch và objdump-ing nó để có được bytecode.

Tuy nhiên, khi tôi chạy chương trình C, tôi nhận được lỗi phân đoạn. Ý tưởng nào?

+5

Ngay cả khi phân đoạn dữ liệu của bạn có thể thực thi hoặc bạn chưa bật NX, bạn mong đợi điều này sẽ làm gì? Nó thực hiện một lệnh và sau đó lệnh sau đó (mà bạn không kiểm soát) và sau đó lệnh sau đó, cho đến khi nó đạt đến bộ nhớ không đại diện cho mã hoặc mã hợp pháp kích hoạt một segfault. –

+1

Bạn sẽ cần phải thêm mã byte cho một 'ret' vì hàm gián tiếp gọi bạn làm nên là một' cuộc gọi' đẩy địa chỉ trả về vào ngăn xếp. Atleast, đây là phỏng đoán tốt nhất của tôi, tôi chưa bao giờ thấy bất cứ điều gì như thế này cả. – Chris

+0

Tôi hy vọng điều này không làm gì cả, nhưng tôi muốn nó có thể chạy mà không bị rơi. – Nosrettap

Trả lời

13

Đây là một ví dụ đơn giản.

main.c:

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

int main() 
{ 
    /*                
     mov rax, 60   ; sys_exit 
     mov rdi, 2 
     syscall             
    */ 
    char code[] = { 
     0x48, 0xb8, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 
     0x00, 0x00, 0x48, 0xbf, 0x02, 0x00, 0x00, 0x00, 
     0x00, 0x00, 0x00, 0x00, 0x0f, 0x05 
    }; 

    void *buf; 

    /* copy code to executable buffer */  
    buf = mmap (0,sizeof(code),PROT_READ|PROT_WRITE|PROT_EXEC, 
       MAP_PRIVATE|MAP_ANON,-1,0); 
    memcpy (buf, code, sizeof(code)); 

    /* run code */ 
    ((void (*) (void))buf)(); 

    return 0; 
} 

Run này với

./main ;echo $? 

tôi đã chọn để làm một _exit (2) trong việc lắp ráp để làm cho nó dễ dàng để kiểm tra xem mã được chạy đúng. Trong thực tế, bạn sẽ muốn thêm một ret ở cuối mã của bạn để trả về kiểm soát.

+0

Có, 'ret' rất quan trọng để quay trở lại chức năng gọi. – Chris

+1

Cảm ơn sự giúp đỡ. Tôi chỉ muốn thêm rằng objdump -d có thể giúp bạn có được mã byte cho một tệp thực thi. – Jeff

4

Mã máy của bạn có thể không sao, nhưng đối tượng CPU của bạn.

CPU hiện đại quản lý bộ nhớ trong phân đoạn. Trong hoạt động bình thường, hệ điều hành sẽ tải chương trình mới vào phân đoạn chương trình-văn bản và thiết lập ngăn xếp trong phân đoạn dữ liệu. Hệ điều hành yêu cầu CPU không bao giờ chạy mã trong một đoạn dữ liệu. Mã của bạn nằm trong code[], trong một đoạn dữ liệu. Vì vậy, segfault.

2

Việc này sẽ mất một chút công sức.

biến code bạn được lưu trữ trong phần .data của thực thi của bạn:

$ readelf -p .data exploit 

String dump of section '.data': 
    [ 10] H1À 

H1À là giá trị của biến của bạn.

Phần .datakhông thực thi:

$ readelf -S exploit 
There are 30 section headers, starting at offset 0x1150: 
Section Headers: 
    [Nr] Name    Type    Address   Offset 
     Size    EntSize   Flags Link Info Align 
[...] 
    [24] .data    PROGBITS   0000000000601010 00001010 
     0000000000000014 0000000000000000 WA  0  0  8 

Tất cả các bộ vi xử lý 64-bit Tôi quen thuộc với sự hỗ trợ trang không thực thi natively trong pagetables. Hầu hết các bộ vi xử lý 32-bit mới hơn (các bộ xử lý hỗ trợ PAE) cung cấp đủ không gian bổ sung trong các trang của chúng cho hệ điều hành để mô phỏng các trang không thực thi được phần cứng. Bạn sẽ cần phải chạy một hệ điều hành cổ hoặc một bộ xử lý cổ để có được một phần .data được đánh dấu là có thể thực thi được.

Vì đây chỉ là cờ trong tệp thực thi, bạn nên có thể đặt cờ X thông qua một số cơ chế khác, nhưng tôi không biết cách làm như vậy. Và hệ điều hành của bạn thậm chí có thể không cho phép bạn có các trang có thể ghi được cả thực thi.