問題描述
從內聯彙編修改 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 malloc
ed 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
(by robert、Jonathon Reinhart)