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:在函数“main”中:
encode.c:13:警告:从不兼容的指针类型初始化
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 返回 1 个退出状态

我的第一个问题是为什么内联汇编失败了......正确的方法是什么?另一件事——“ret”或“retn”的代码是 0x00 ,对……我的代码 xor 的东西直到它返回……那为什么它是 SEGFAULTing 呢?

4

3 回答 3

1

GCC 内联 asm 使用 AT&T 语法(如果没有选择使用 Intel 的特定选项)。

这是一个例子:

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

因此,您的问题是无法从您的电话中识别出“文本”(并且也按照说明进行操作)。

请参阅此处以供参考。

此外,您的代码不能在 32 位和 64 位环境之间移植。使用 -m32 标志编译它以确保正确分析(如果您出错,GCC 无论如何都会抱怨)。

您的问题的完整解决方案在 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) );的工作要做。谷歌以获得更好的细节。

于 2009-10-03T08:10:34.833 回答
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;
}

至于你的最后一个问题,RET 的常用操作码是“C3”,但有很多变化,看看http://pdos.csail.mit.edu/6.828/2009/readings/i386/RET.htm 你的搜索 RET 的想法也是错误的,因为当您在随机指令集中看到字节 0xC3 时,并不意味着您遇到了 ret。由于 0xC3 可能只是另一条指令的数据/属性(作为旁注,由于 x86 是指令长度在 1-16 字节之间的 CISC 架构,因此尝试解析 x86 指令特别困难) )

另请注意,并非所有操作系统都允许修改文本/代码段(存储可执行指令的位置),因此您在 main 中的代码可能无论如何都无法工作。

于 2009-10-03T08:39:30.363 回答
0

它不是 printf 而是 _printf

于 2009-10-21T12:50:55.903 回答