10

I am trying to make some self-modifing native code on Android and run it in the emulator. My sample is based on the HelloJNI sample from the android-ndk. It looks like this:

#define NOPE_LENGTH 4

typedef void (*FUNC) (void);

// 00000be4 <nope>:
//     be4: 46c0        nop         (mov r8, r8)
//     be6: 4770        bx  lr
void nope(void) {
    __asm__ __volatile__ ("nop");
}

void execute(void){
    void *code = mmap(NULL, NOPE_LENGTH, PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

    if (code != MAP_FAILED) {
        memcpy(code, nope, NOPE_LENGTH);

        ((FUNC)code)();
    }
}

The problem is that this code is crashing. What is wrong?

Иван
  • 434
  • 3
  • 16
  • 2
    Note: if you actually modify the code you will need to flush the instruction cache -- the I and D caches on ARM are not coherent, so the fact that you can see values at a given location does not mean that the CPU will see them when it tries to execute. Dalvik uses Linux cacheflush(2) in its JIT compiler implementation. – fadden Dec 17 '10 at 00:40

1 Answers1

11

At a guess, nope() was compiled as Thumb, but you're calling it as ARM (assuming mmap returns a word-aligned pointer). To call Thumb code, the low bit of the address should be set. Try something like this:

( (FUNC)(((unsigned int)code)|1) )();

To do it properly, you should ensure alignment of the allocated memory (2 for Thumb and 4 for ARM), make sure that the code you're trying to run is Thumb (or ARM) and set the bit 0 accordingly.

Igor Skochinsky
  • 24,629
  • 2
  • 72
  • 109
  • Thank you. Having compiled the code with -marm option and having provided the proper alignment for the memory block I successfully executed the code. – Иван Dec 17 '10 at 10:29