views:

174

answers:

3

Somebody over at SO posted a question asking how he could "hide" a function. This was my answer:

#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;
}

but, there are problems:

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

My first question is why is the inline assembly failing ... what would be the right way to do it? Other thing -- the code for "ret" or "retn" is 0x00 , right... my code xor's stuff until it reaches a return ... so why is it SEGFAULTing?

+1  A: 

GCC inline asm uses AT&T syntax (if no specific options are selected for using Intel's one).

Here's an example:

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

Thus, your problem is that "text" is not identifiable from your call (and following instruction too).

See here for reference.

Moreover your code is not portable between 32 and 64 bit environments. Compile it with -m32 flag to ensure proper analysis (GCC will complain anyway if you fall in error).

A complete solution to your problem is on this post on GCC Mailing list. Here's a snippet:

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 */ );

On windows systems there's also an additional asm ( "addl %0, %%esp" : /* No outputs */ : "g" (method->args_size * 4) ); to do. Google for better details.

ZZambia
+1  A: 

As a high level point, I'm not quite sure why you're trying to use inline assembly to do a simple call into printf, as all you've done is create an incorrect version of a function call (your inline pushes something onto the stack, but never pop it off, most likely causing problems cause GCC isn't aware that you've modified the stack pointer in the middle of the function. This is fine in a trivial example, but could lead to non-obvious errors in a more complicated function)

Here's a correct implementation of your top function:

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;
}

As for your last question, the usual opcode for RET is "C3", but there are many variations, have a look at http://pdos.csail.mit.edu/6.828/2009/readings/i386/RET.htm Your idea of searching for RET is also faulty as due to the fact that when you see the byte 0xC3 in a random set of instructions, it does NOT mean you've encountered a ret. As the 0xC3 may simply be the data/attributes of another instruction (as a side note, it's particularly hard to try and parse x86 instructions as you're doing due to the fact x86 is a CISC architecture with instruction lengths between 1-16 bytes)

As another note, not all OS's allow modification to the text/code segment (Where executable instructions are stored), so the the code you have in main may not work regardless.

Falaina
A: 

It is not printf but _printf

Arabcoder