2009-10-03 96 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