5

I have the following assembly function (shown with objdump already)

0000000000000000 <add>:
   0:   b8 06 00 00 00          mov    $0x6,%eax
   5:   c3                      retq  

Now in C I made the following code:

#include <stdio.h>

typedef int (*funcp) (int x);

unsigned char foo[] = {0xb8,0x06,0x00,0x00,0x00,0xc3};

int main(void)
{
  int i;
  funcp f = (funcp)foo;
  i = (*f);
  
  printf("exit = %d\n", i);
  return 0;
}

In the global variable foo I typed the memory address of my function in assembly and tried to execute it but it does not return 6 as expected. How can I execute functions for their memory addresses? furthermore, where can i research more on the subject?

obs: sometimes I got the Segmentation fault (core dumped) error

20
  • 1
    For a start, you have to use () to call a function. Commented Nov 17, 2020 at 14:21
  • 5
    The data section is usually not executable, meaning your code will run into a segmentation fault. Commented Nov 17, 2020 at 14:39
  • 1
    gcc -z execstack temp1.c works for me. I get 6 as output. Commented Nov 17, 2020 at 14:51
  • 3
    @fuz: -z execstack on Linux made all readable pages executable until very recent kernel versions. Linux's ELF program loader set the read-implies-exec process "personality" flag when seeing the executable GNU stack metadata. Linux default behavior against `.data` section - PT_GNU_STACK == RWX no longer implies exec-all; I just updated my Arch Linux and gcc -zexecstack doesn't make .data (or .rodata) executable. See also Unexpected exec permission from mmap.... Commented Nov 17, 2020 at 15:54
  • 1
    @fuz: Yes, __attribute__((section(".text"))) works. I get Assembler messages: /tmp/ccNetmKQ.s:28: Warning: ignoring changed section attributes for .text but it does run. godbolt.org/z/draGeh. On my desktop, -Wl,-N makes it fail to link: /usr/bin/ld: cannot find -lgcc_s. Both of those things (array in text section, and read/write text section) would be necessary for a non-const executable array. Commented Nov 17, 2020 at 16:41

1 Answer 1

0

The NX flag might be your 'friend' here. Parts of memory which are never meant to be executed as binary machine code can be marked as No-eXecute. See https://en.wikipedia.org/wiki/NX_bit . So, depending on architecture, operating system and settings, and even BIOS settings.

So this feature might be on or off. If NX is used on the data-section of your program, it will not run. You will need to mmap() a piece of memory with PROT_EXEC set, copy the data in, then run it.

For the following, I changed the binary to be an amd64 code (+1 func). When using the mmap() copy, it works. When directly calling foo, it fails (on my machine with NX active)

(code without err-check, freeing of mem, etc)

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

typedef int (*funcp) (int x);

unsigned char foo[] = {0x8d,0x47,0x01,0xc3};
//unsigned char foo[] = {0xc3,0xb8,0x06,0x00,0x00,0x00,0xc3};

int main(void)
{
  int i;

  void *mem2;

  mem2 = mmap(0,4096,PROT_WRITE|PROT_READ|PROT_EXEC,MAP_PRIVATE|MAP_ANONYMOUS|MAP_EXECUTABLE,-1,0);

  memcpy(mem2,foo,sizeof(foo));


  funcp f = (funcp)mem2;
  i = f(42);

  printf("exit = %d\n", i);
  return 0;
}
Sign up to request clarification or add additional context in comments.

1 Comment

That's not fully safe in GNU C without __builtin___clear_cache to let the compiler know the store into that buffer isn't "dead", i.e. that it will be read as code. (No actual cache invalidation has to happen on x86, with its coherent I-cache, but there is a possible compile-time optimization problem.) See How to get c code to execute hex machine code?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.