2011-05-06 49 views
3

我正在嘗試讀取內存中相對於X86_64上的%rip的值。在我的第一個例子中,我只是想讀如何獲取動態生成的X86_64以返回相對於RIP/RBP的值

如果我使用C下面的代碼,我可以調用它,並得到正確的結果(\x....C3C9):

void * test() { 
    __asm("mov 0(%rip), %rax"); 
} 

生成的代碼如下:

0000000000400624 <test>: 
    400624: 55      push %rbp 
    400625: 48 89 e5    mov %rsp,%rbp 
    400628: 48 8b 05 00 00 00 00 mov 0x0(%rip),%rax  # 40062f <test+0xb> 
    40062f: c9      leaveq 
    400630: c3      retq 

如果我現在不過直接把這個代碼在內存中,並執行它,我收到了段錯誤,而我希望閱讀\x0000C3C9

int main() 
{ 
    int codesize = 9; 
    unsigned char * code = (unsigned char*)malloc(1024); 
    memcpy(code, "\x48\x8B\x5\x0\x0\x0\x0\xC9\xC3\x00\x00", codesize + 2); 
    mprotect(code, codesize, PROT_EXEC | PROT_READ); 
    goto *code; 
} 

我做錯了什麼?

編輯 答案是,我不應該使用mallocmmap分配一個頁對齊的內存區域:

(unsigned char*)mmap(NULL, 1024, PROT_WRITE | PROT_READ, MAP_ANONYMOUS | MAP_SHARED, -1, 0); 

當然,我應該檢查調用的返回值到mprotect。它返回-1標記它失敗。

+0

我被人誰又被刪除了他的評論評論,但是他引導我正確的方向。他說得對,「保護」失敗了(愚蠢的我,我應該檢查)。我猜'malloc'(顯然)不會返回與頁面邊界對齊的內存。通過使用'(unsigned char *)mmap(NULL,1024,PROT_WRITE | PROT_READ,MAP_ANONYMOUS | MAP_SHARED,-1,0);'它確實有效。 – tverwaes 2011-05-06 00:28:07

+1

如果您將'PROT_EXEC'添加到'mmap'調用中,則不需要'mprotect'。 – 2011-05-06 00:31:40

+0

因爲我讀過某些內核不允許同時使用'PROT_WRITE'和'PROT_EXEC'的情況,所以我沒有這樣做。我誤解了嗎? – tverwaes 2011-05-06 00:36:12

回答

1

您最有可能在mprotect()調用期間獲得SIGSEGV。如果由malloc()返回的內存的代碼執行被操作系統禁止(最有可能的是如果你沒有使用一些古老的內核),mprotect()只是段錯誤。這不是一個錯誤,它是一個功能。

+0

'mprotect'不會段錯誤。實際上它會成功,但如果它不能成功,它將返回-1並設置「errno」。 – 2011-05-06 00:26:21

+0

實際上,如果參數不是頁面對齊,但會返回一個錯誤,而不是段錯誤。隨後的代碼然後段錯誤。 – 2011-05-06 00:32:03

+0

是的,就我所知,這是問題所在。我只是習慣使用靜態字符串而不是'malloc',這似乎工作。我猜靜態字符串是頁面對齊的,但malloc的字符串不是。 – tverwaes 2011-05-06 00:35:21

0

ret指令基本上是pop value from the stack; goto value

當你goto <your_code>ret最終得到執行的問題是,你有垃圾的堆(也許ret指令試圖goto 9因爲codesize是在堆棧的頂部,誰知道變量...)上。

基本上,它不起作用,因爲你不正確地使用你的asm代碼片段。

請問你在做什麼?我能幫助:)


測試程序,讓您的RIP:

static inline unsigned long get_rip(void) 
{ 
    unsigned long val; 
    asm volatile(
     "call 1f\n" 
     "1: popq %0\n" 
     : "=r"(val)); 
    return val; 
} 

int main() 
{ 
    printf("rip = %p\n", (void *)get_rip()); 
    return 0; 
} 
+0

爲什麼堆棧上會有垃圾?當我'goto '我還沒有碰到堆棧,所以我只是在運行它,就好像它直接在'main'函數中一樣。我正在研究一個Smalltalk - > ASM編譯器(用Smalltalk編寫),因爲我想完全擺脫虛擬機。 X86_64似乎是一個開始的好地方。很多東西都可以學習,但很有趣:) – tverwaes 2011-05-06 00:40:49

+0

發佈了一段代碼片段,告訴你如何獲得rip值:) – 2011-05-06 00:44:29

+1

'retq'前面的'leaveq'指令應該使堆棧指針指向main的返回地址()',假設'main()'使用了一個普通的函數序言。 – caf 2011-05-06 01:08:54

相關問題