2014-10-31 98 views
4

我正在玩弄操作二進制的調用函數。我有下面的代碼:編輯ELF二進制調用指令

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

void myfunc2(char *str2, char *str1); 

    enter code here 

void myfunc(char *str2, char *str1) 
{ 
    memcpy(str2 + strlen(str2), str1, strlen(str1)); 
} 

int main(int argc, char **argv) 
{ 
    char str1[4] = "tim"; 
    char str2[10] = "hello "; 

    myfunc((char *)&str2, (char *)&str1); 

    printf("%s\n", str2); 

     myfunc2((char *)&str2, (char *)&str1); 

    printf("%s\n", str2); 

    return 0; 
} 

void myfunc2(char *str2, char *str1) 
{ 
    memcpy(str2, str1, strlen(str1)); 
} 

我已經編譯二進制和使用readelf或objdump的,我可以看到我的兩個功能駐留在:

46:0000000000 40072c 52 FUNC全局默認13 myfunc2所* *

54:0000000000 40064d 77 FUNC全局默認13 MYFUNC **

使用命令objdump的-D測試(我的二進制文件名),我可以看到該main有兩個callq函數。我試圖編輯第一個使用上述地址72c指向myfunc2,但這不起作用;導致二進制失敗。

000000000040069a <main>: 
    40069a: 55      push %rbp 
    40069b: 48 89 e5    mov %rsp,%rbp 
    40069e: 48 83 ec 40    sub $0x40,%rsp 
    4006a2: 89 7d cc    mov %edi,-0x34(%rbp) 
    4006a5: 48 89 75 c0    mov %rsi,-0x40(%rbp) 
    4006a9: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax 
    4006b0: 00 00 
    4006b2: 48 89 45 f8    mov %rax,-0x8(%rbp) 
    4006b6: 31 c0     xor %eax,%eax 
    4006b8: c7 45 d0 74 69 6d 00 movl $0x6d6974,-0x30(%rbp) 
    4006bf: 48 b8 68 65 6c 6c 6f movabs $0x206f6c6c6568,%rax 
    4006c6: 20 00 00 
    4006c9: 48 89 45 e0    mov %rax,-0x20(%rbp) 
    4006cd: 66 c7 45 e8 00 00  movw $0x0,-0x18(%rbp) 
    4006d3: 48 8d 55 d0    lea -0x30(%rbp),%rdx 
    4006d7: 48 8d 45 e0    lea -0x20(%rbp),%rax 
    4006db: 48 89 d6    mov %rdx,%rsi 
    4006de: 48 89 c7    mov %rax,%rdi 
    4006e1: e8 67 ff ff ff   callq 40064d <myfunc> 
    4006e6: 48 8d 45 e0    lea -0x20(%rbp),%rax 
    4006ea: 48 89 c7    mov %rax,%rdi 
    4006ed: e8 0e fe ff ff   callq 400500 <[email protected]> 
    4006f2: 48 8d 55 d0    lea -0x30(%rbp),%rdx 
    4006f6: 48 8d 45 e0    lea -0x20(%rbp),%rax 
    4006fa: 48 89 d6    mov %rdx,%rsi 
    4006fd: 48 89 c7    mov %rax,%rdi 
    400700: e8 27 00 00 00   callq 40072c <myfunc2> 
    400705: 48 8d 45 e0    lea -0x20(%rbp),%rax 
    400709: 48 89 c7    mov %rax,%rdi 
    40070c: e8 ef fd ff ff   callq 400500 <[email protected]> 
    400711: b8 00 00 00 00   mov $0x0,%eax 
    400716: 48 8b 4d f8    mov -0x8(%rbp),%rcx 
    40071a: 64 48 33 0c 25 28 00 xor %fs:0x28,%rcx 
    400721: 00 00 
    400723: 74 05     je  40072a <main+0x90> 
    400725: e8 f6 fd ff ff   callq 400520 <[email protected]> 
    40072a: c9      leaveq 
    40072b: c3      retq 

我懷疑我需要通過相對位置或使用lea/mov指令來計算地址信息。

任何援助,以瞭解如何修改呼叫功能,將不勝感激 - 請像上的howtos遍佈互聯網的大部分編輯字符串沒有指針...

+1

你也應該如編譯C代碼'gcc -fverbose-asm -S'然後查看生成的彙編代碼。順便說一句,你確切的問題是什麼?您是否精確讀過'callq' x86機器指令的文檔? – 2014-10-31 10:12:15

+3

而不是'myfunc((char *)&str2,(char *)&str1);',爲什麼不寫'myfunc(str2,str1);'?當然這更容易閱讀?我永遠不會理解這個instist – unwind 2014-10-31 10:13:06

+1

您還需要閱讀[x86-64 ABI](http://www.x86-64.org/documentation_folder/abi.pdf)規範 – 2014-10-31 10:17:18

回答

6

爲了改寫地址,你有了解callq指令的編碼方式。

讓我們第一次調用的反彙編輸出:

4006e1: e8 67 ff ff ff   callq 40064d <myfunc> 
4006e6: ... 

你可以清楚地看到,指令編碼有5個字節。 e8字節是指令操作碼,67 ff ff ff是要跳轉到的地址。此時,人們會問這個問題:67 ff ff ff0x40064d有什麼關係?

那麼,答案是e8編碼所謂的「相對調用」,跳轉是相對於下一條指令的位置執行的。您必須計算與被調用函數之間的距離才能重寫地址。如果調用是絕對的(ff),則可以將函數地址放在這4個字節中。

爲了證明這種情況下,考慮下面的算術:

0x004006e6 + 0xffffff67 == 0x10040064d 
+0

非常好,好吧,上面說過,如果編碼指令恰好是不同的大小 - 我可能不那麼幸運。這是相同的指令,所以會好還是不好? – mcdoomington 2014-10-31 15:22:41

+0

在特定的情況下,它不應該成爲一個問題 - 它可以很容易地用5個字節再次編碼。但是,在一般情況下,如果您需要替換更大的指令,它將打破該指令下的所有代碼。下面的說明可能會使用與PC相關的尋址或「call」尋址,它們的所有地址都將被您所介紹的這種差異所抵消。如果新指令較小,則可以用「NOP」來填充該問題。 – 2014-10-31 15:30:42

+0

好吧,計算「相對位置」 - 這是從myfunc調用main到myfunc2的位置嗎?這對我來說有點模糊 – mcdoomington 2014-10-31 15:41:05