有人在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?
答案 0 :(得分:1)
GCC inline asm使用AT&amp; 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) );
要做。谷歌提供更好的细节。
答案 1 :(得分: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中的代码都可能无法正常工作。
答案 2 :(得分:0)
不是printf而是_printf