从内联汇编修改 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
,您必须 jmp
或 call
,或 ret
。
尝试将您的地址移至 rax
,然后移至 jmp rax
。确保将 rax
标记为 "clobbered"。
不过,更简单的方法是创建一个函数指针,将其指向您分配的内存,然后调用它。
另请注意,您的 malloc
ed 内存不会被标记为可执行,因此您的测试将立即崩溃。要解决此问题,您可以使用 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
我正在尝试修改 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
,您必须 jmp
或 call
,或 ret
。
尝试将您的地址移至 rax
,然后移至 jmp rax
。确保将 rax
标记为 "clobbered"。
不过,更简单的方法是创建一个函数指针,将其指向您分配的内存,然后调用它。
另请注意,您的 malloc
ed 内存不会被标记为可执行,因此您的测试将立即崩溃。要解决此问题,您可以使用 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