3

我想在 mprotect 处理程序中获取当前的程序计数器(PC)值。从那里我想将 PC 的值增加“n”条指令,以便程序跳过一些指令。我想为 linux 内核版本 3.0.1 做所有这些。关于我可以获得 PC 值的数据结构以及如何更新该值的任何帮助?示例代码将不胜感激。提前致谢。

我的想法是在写入内存地址时使用一些任务。所以我的想法是使用 mprotect 使地址写保护。当一些代码试图在那个内存地址上写一些东西时,我将使用 mprotect 处理程序来执行一些操作。处理好处理程序后,我想让写操作成功。所以我的想法是使内存地址在处理程序内部不受保护,然后再次执行写操作。当代码从处理函数返回时,PC 将指向原始写指令,而我希望它指向下一条指令。因此,无论指令长度如何,我都想将 PC 增加一条指令。

检查以下流程

MprotectHandler(){
    unprotect the memory address on which protection fault arised
    write it again
    set PC to the next instruction of original write instruction
}

内部主要功能:

main(){
    mprotect a memory address
    try to write the mprotected address // original write instruction
    Other instruction    // after mprotect handler execution, PC should point here
}
4

2 回答 2

1

由于在几个 CISC 处理器上计算指令长度很繁琐,我推荐一个稍微不同的过程:fork using clone(..., CLONE_VM, ...)into a tracer and a tracee thread, and in the tracer instead of

    write it again
    set PC to the next instruction of original write instruction

做一个

    ptrace(PTRACE_SINGLESTEP, ...)

- 在跟踪陷阱之后,您可能想再次保护内存。

于 2014-10-16T11:45:55.173 回答
1

这是演示基本原理的示例代码:

#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/ucontext.h>

static void
handler(int signal, siginfo_t* siginfo, void* uap) {
    printf("Attempt to access memory at address %p\n", siginfo->si_addr);
    mcontext_t *mctx = &((ucontext_t *)uap)->uc_mcontext;
    greg_t *rsp = &mctx->gregs[15];
    greg_t *rip = &mctx->gregs[16];

    // Jump past the bad memory write.
    *rip = *rip + 7;
}

static void
dobad(uintptr_t *addr) {
    *addr = 0x998877;
    printf("I'm a survivor!\n");
}

int
main(int argc, char *argv[]) {
    struct sigaction act;
    memset(&act, 0, sizeof(struct sigaction));
    sigemptyset(&act.sa_mask);
    act.sa_sigaction = handler;
    act.sa_flags = SA_SIGINFO | SA_ONSTACK;

    sigaction(SIGSEGV, &act, NULL);

    // Write to an address we don't have access to.
    dobad((uintptr_t*)0x1234);

    return 0;
}

它向您展示了如何更新 PC 以响应页面错误。它缺少您必须自己实现的以下内容:

于 2016-09-29T05:35:40.093 回答