2009-10-03 101 views
0

有人在SO發佈了一個問題,詢問他如何「隱藏」一個函數。這是我的回答:內聯彙編和函數覆蓋導致段錯誤

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

int encrypt(void) 
{ 
    char *text="Hello World"; 
    asm("push text"); 
    asm("call printf"); 
    return 0; 
} 

int main(int argc, char *argv[]) 
{ 
    volatile unsigned char *i=encrypt; 
    while(*i!=0x00) 
    *i++^=0xBE; 
    return EXIT_SUCCESS; 
} 

,但也有問題:

 
encode.c: In function `main': 
encode.c:13: warning: initialization from incompatible pointer type 
C:\DOCUME~1\Aviral\LOCALS~1\Temp/ccYaOZhn.o:encode.c:(.text+0xf): undefined reference to `text' 
C:\DOCUME~1\Aviral\LOCALS~1\Temp/ccYaOZhn.o:encode.c:(.text+0x14): undefined reference to `printf' 
collect2: ld returned 1 exit status 

我的第一個問題是,爲什麼是內聯彙編失敗......這將是正確的做到這一點呢?其他的東西 - 「ret」或「retn」的代碼是0x00,正確的...我的代碼xor的東西,直到達到一個返回......那麼爲什麼它是SEGFAULTing?

回答

1

作爲一個高級別一點,我不明白爲什麼你要使用內聯彙編做一個簡單的通話將printf的,因爲所有你要做的就是創建一個函數調用的版本不正確(您內聯將某些東西壓入堆棧,但從不彈出它,很可能導致問題,因爲GCC並不知道你已經在函數中間修改了堆棧指針,這在一個簡單的例子中很好,但可能會導致在更復雜的功能非明顯的錯誤)

這裏是一個正確的實現您的頂級功能:

int encrypt(void) 
{ 
    char *text="Hello World"; 
    char *formatString = "%s\n"; 
    // volatile really isn't necessary but I just use it by habit 
    asm volatile("pushl %0;\n\t" 
       "pushl %1;\n\t" 
      "call printf;\n\t" 
       "addl $0x8, %%esp\n\t"   
       : 
       : "r"(text), "r"(formatString) 
       ); 

    return 0; 
} 

至於你啦ST的問題,爲RET通常的操作碼是「C3」,但也有許多變化,看看http://pdos.csail.mit.edu/6.828/2009/readings/i386/RET.htm 你的搜索RET的想法也是錯誤的,由於這樣的事實,當你看到字節0xC3隨機集這並不意味着你遇到了ret。由於0xC3可能僅僅是另一條指令的數據/屬性(作爲一個附註,因爲x86的指令長度在1到16個字節之間的CISC體系結構,因此在嘗試和解析x86指令時特別困難)

作爲另一個注意,不是所有的OS允許修改文本/代碼段(其中可執行指令存儲),所以你主要有代碼可能無法正常工作無關。

1

GCC內聯彙編使用AT & T語法(如果選擇使用英特爾的一個沒有特定的選項)。

下面是一個例子:

int a=10, b; 
asm ("movl %1, %%eax; 
     movl %%eax, %0;" 
     :"=r"(b)  /* output */ 
     :"r"(a)   /* input */ 
     :"%eax"   /* clobbered register */ 
    );  

因此,你的問題是,「文本」是不是從你的電話識別(和下一條指令太)。

請參閱here以供參考。

此外,您的代碼在32位和64位環境之間不可移植。使用-m32標誌編譯它以確保正確的分析(如果出現錯誤,GCC無論如何都會抱怨)。

到您問題的完整解決方案是this後GCC郵件列表上。 這裏有一個片段:

for (i = method->args_size - 1; i >= 0; i--) { 
    asm("pushl %0": /* no outputs */: \ 
     "g" (stack_frame->op_stack[i])); 
} 

asm("call *%0" : /* no outputs */ : "g" (fp) : 
    "%eax", "%ecx", "%edx", "%cc", "memory"); 

asm ("movl %%eax, %0" : "=g" (ret_value) : /* No inputs */); 

在Windows系統上還有還有一個額外的asm ("addl %0, %%esp" : /* No outputs */ : "g" (method->args_size * 4));做。谷歌更好的細節。

0

它不是printf的,但_printf