Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modify RIP register from inline assembly

Tags:

c

assembly

x86-64

I am trying to modify the rip register (just for fun). buffer should be a memory address, so I do not know why I get Error: operand type mismatch for 'movq'

#include <stdio.h>
#include <stdlib.h> 

int main(){
        char* buffer;
        buffer = (char*) malloc(8*sizeof(char));
        asm volatile("movq %0, %%rip \n" : : "r" (buffer));
        free(buffer);
}
like image 705
robert Avatar asked Dec 14 '22 10:12

robert


1 Answers

In x86 you cannot use rip directly as the source or destination of a mov. To change rip you must jmp or call, or ret.

Try moving your address the rax and then jmp rax. Make sure you mark rax as "clobbered".

The easier way to do what you're attempting though, would be to simply create a function pointer, point it at your allocated memory, and call it.

Note also that your malloced memory will not be marked executable so your test will crash immediately. To remedy this, you can use mprotect(2) to change the page permissions. This changes them for the entire page, however. The better solution is to use mmap(2) to map anonymous, executable pages.


First, we write a little assembly function:

prog.s

[BITS 64]
global addints

;; unsigned long addints(unsigned long x, unsigned int y);
addints:
    mov     rax, rdi    ;; x
    add     rax, rsi    ;; y
    ret

Then assemble it, and look at the opcodes:

$ nasm -o binary prog.s
$ ndisasm -b64 prog
00000000  4889F8            mov rax,rdi
00000003  4801F0            add rax,rsi
00000006  C3                ret

Now code that into our sample program:

mmap.c

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

#define PAGE_SIZE   0x1000  /* always 4 KiB (min.) on x86 */

static const uint8_t mycode[] = {
    0x48, 0x89, 0xF8,   /* mov rax, rdi */
    0x48, 0x01, 0xF0,   /* add rax, rsi */
    0xC3,               /* ret */
};

int main(void)
{
    void *m;

    /* Use mmap to allocate a page of executable memory */
    m = mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
             MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

    if (m == MAP_FAILED) {
        fprintf(stderr, "mmap() failed: %m\n");
        exit(2);
    }

    /* Copy our code into the executable memory */
    memcpy(m, mycode, sizeof(mycode));

    /* For safety, remove the 'writable' flag */
    mprotect(m, PAGE_SIZE, PROT_READ | PROT_EXEC);

    /* Create a function pointer, and point it at the executable memory */
    unsigned long (*func)(unsigned long x, unsigned long y) = m;

    /* Call our code */
    unsigned long result = func(7, 3);

    printf("Result: %lu\n", result);

    return 0;
}

And give it a whirl:

$ gcc -Wall -Werror -o mmap mmap.c
$ ./mmap
Result: 10

No assembly required!

like image 81
Jonathon Reinhart Avatar answered Jan 04 '23 22:01

Jonathon Reinhart