从内联汇编修改 RIP 寄存器

Modify RIP register from inline assembly

我正在尝试修改 rip 寄存器(只是为了好玩)。 buffer应该是内存地址,所以不知道为什么会得到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);
}

在 x86 中,您不能直接使用 rip 作为 mov 的源或目标。要更改 rip,您必须 jmpcall,或 ret

尝试将您的地址移至 rax,然后移至 jmp rax。确保将 rax 标记为 "clobbered"。

不过,更简单的方法是创建一个函数指针,将其指向您分配的内存,然后调用它。

另请注意,您的 malloced 内存不会被标记为可执行,因此您的测试将立即崩溃。要解决此问题,您可以使用 mprotect(2) to change the page permissions. This changes them for the entire page, however. The better solution is to use mmap(2) 映射匿名的可执行页面。


首先,我们编写一个小的汇编函数:

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

然后assemble它,看看操作码:

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

现在将其编码到我们的示例程序中:

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

试一试:

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