views:

78

answers:

3

Hi I'm trying to load raw machine code into memory and run it from within a C program, right now when the program executes it breaks when trying to run mprotect on the memory to make it executable. I'm also not entirely sure that if the memory does get set right it will execute. I am currently running this on Ubuntu Linux x86 (Maybe the problem is Ubuntu's over-protection?)

What I currently have is the following:

#include <memory.h>
#include <sys/mman.h>
#include <stdio.h>

int main ( int argc, char **argv )
{
 FILE *fp;
 int sz = 0;
 char *membuf;
 int output = 0;

 fp = fopen(argv[1],"rb");

 if(fp == NULL)
 {
  printf("Failed to open file, aborting!\n");
  exit(1);
 }

 fseek(fp, 0L, SEEK_END);
 sz = ftell(fp);
 fseek(fp, 0L, SEEK_SET);


 membuf = (char *)malloc(sz*sizeof(char));
 if(membuf == NULL)
 {
  printf("Failed to allocate memory, aborting!\n");
  exit(1);
 }

  memset(membuf, 0x90, sz*sizeof(char));

 if( mprotect(membuf, sz*sizeof(char), PROT_EXEC | PROT_READ | PROT_WRITE) == -1)
 {
  perror("mprotect");
  printf("mprotect failed!!! aborting!\n");
  exit(1);
 }



 if(!(fread(membuf, sz*sizeof(char), 1, fp)))
 {
  perror("fread");
  printf("Read failed, aborting!\n");
  exit(1);
 }
 __asm__
 ( 
  "call %%eax;"
  : "=a" (output)
       : "a" (membuf)
 );
 printf("Output = %x\n", output);

 return 0;
}

I do get the compiler warning:

/tmp/ccVnhHak.s: Assembler messages:
/tmp/ccVnhHak.s:107: Warning: indirect call without `*'

I've not gotten the program to reach this code yet so I am unable to see if my assembler code is doing what it should.

+3  A: 

Ok, here's the answer, according to our discussion in the comments :)

The memory region should be aligned to the system page size. posix_memalign() call is a right way to allocate memory in such case :)

Roman D
So it has to be allocated in multiples of the page size I assume, and not from a file length
ChartreuseKitsune
Well, if i get it right, only the address is aligned, not the size. The size is given in bytes (acc. to the man)
Roman D
Okay that seems to have gotten it past the mprotect error. Using: membuf = (char *)memalign(pagesize, sz*sizeof(char)); Instead of malloc.
ChartreuseKitsune
Okay now that mprotect is no longer failing, is there any guess as to why the code is producing a segfault, gdb shows 0x0804b004 in ?? (). I am passing a file to it with valid byte code in it, not an ELF
ChartreuseKitsune
I guess your program runs through a sequence of NOPs in your array, and, since there's no ret instruction, it goes right into the wilderness well beyond the allocated region
Roman D
Hmm that is odd, would it run the machine code before the NOPs, because it should print a string to the terminal before dieing
ChartreuseKitsune
@Chartreuse: You're going to need to single-instruction-step `si` in GDB. From the look of it, you got past the first instruction because the address doesn't end in `0`. You probably have no hope of getting symbols so it will be `?? ()`, but that's not really so bad. Debug your object code elsewhere before trying to load it, examine your environment closely, open a new question if you're stuck.
Potatoswatter
Okay thanks for the all the help, it was much quicker than expected.
ChartreuseKitsune
A: 

Add an 0xc3 (return instruction) after your 0x90 (noop) bytes. Your program might be crashing because it runs off the end of the NOOPs and either into uninitialized memory, who knows what lurks there, or into the end of the executable page. I can't really tell without looking at what's in the file you're loading.

BTW strace is very useful for these sorts of programs. It would have told you what the error in mprotect was.

Bernd Jendrissek
+1  A: 

Using all perms PROT_EXEC | PROT_READ | PROT_WRIT is also not needed and kinda dangerous. You don't need PROT_WRITE generally, just exec and read is enough.

Some secured kernels don't even allow PROT_EXEC | PROT_WRIT.

rurban