從內聯彙編修改 RIP 寄存器 (Modify RIP register from inline assembly)


問題描述

從內聯彙編修改 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);
}

參考解法

方法 1:

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!

(by robertJonathon Reinhart)

參考文件

  1. Modify RIP register from inline assembly (CC BY‑SA 2.5/3.0/4.0)

#assembly #C #x86-64






相關問題

內聯彙編 - cdecl 和準備堆棧 (Inline assembly - cdecl and preparing the stack)

ASM 使用代碼查找偏移量 (ASM find offset with code)

顯示字符的 Ascii 值 (Displaying Ascii values of characters)

x86 彙編程序崩潰,可能忽略了簡單的錯誤 (x86 assembly procedure crashes, possibly overlooking simple error)

是否可以在 C++ 結構中編寫靜態程序集數據? (Is it possible to write static assembly data in C++ struct?)

將小於 %ecx 的 1 推入堆棧 (push 1 less than %ecx to stack)

emu8086 : ARR 不包含任何值 (emu8086 : ARR do not contain any value)

劊子手游戲,語法修復 x86 gcc 程序集和 C (hangman game, syntax fix x86 gcc assembly & C)

如何將內存中的 96 位加載到 XMM 寄存器中? (How to load 96 bits from memory into an XMM register?)

如何使用 Assembly 中的 printf? (How do you use printf from Assembly?)

摩托羅拉 68HC12 實時中斷寄存器 (Motorola 68HC12 Real Time Interrupt Registers)

我可以用 OR 操作代替 MOV 操作嗎? (Can I substitute a MOV operation with an OR operation?)







留言討論