SIGSEGV,在mmapping区域之后

时间:2016-04-15 06:30:22

标签: c linux memory mmap

我试图在SIGQUIT之后从核心转储恢复进程。 我真的想要那块虚拟内存,但是当我尝试映射它时,我得到了SIGSEGV。

编辑:这个区域不是免费的:0xf75d2000 - 0xf7774000,但我仍然想拥有它。 enter image description here

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <string.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <ucontext.h>
#include <elf.h>
#include <sys/procfs.h>
#include <sys/user.h>
#include <linux/unistd.h>
#include <linux/unistd.h>
#include <asm/ldt.h>
#include  <signal.h>
bool flag = false;
int argc2;
char ** argv2;
int main2(){
    FILE * file = fopen("/proc/self/maps", "r");
    if (file) {
        char c;
        while ((c = getc(file)) != EOF)
        putchar(c);
        fclose(file);
    }
    fflush(stdout);
    void* res = mmap((void*)(0xf75d2000), 0x001a5000, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
    return 0;
}
int main(int argc, char ** argv){
    argc2 = argc;
    argv2 = argv;
    ucontext_t cont;
    getcontext (&cont);
    if(!flag){
      void* a = mmap((void*)0x34B000, 81920, PROT_EXEC | PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
      if(a == MAP_FAILED){
        printf("mmapfail");
        return 1;
      }
      cont.uc_mcontext.gregs[REG_ESP] = 0x355000;
      flag = true;
      setcontext(&cont);
    } else{
      exit(main2());
    }
}

我正在编译它:

gcc -static -Wl,-Ttext=0x4A9480,--build-idone,-Tdata=0x639480,--section-start=.plt=0x3B9480,--section-start=.rel.plt=0x3AF480,--section-start=.note.ABI-tag=0x39B480 main.c -o main -m32

2 个答案:

答案 0 :(得分:1)

The address you are trying to map (0xf75d2000) is above the userspace/kernel split in virtual memory. If your kernel is configured with CONFIG_VMSPLIT_3G, you can't map arbitrary addresses above 0xc0000000.

The existing mappings were setup in kernel to expose the vDSO space (to assist with system calls).

答案 1 :(得分:0)

当然你得到了一个SEGV。您将MAP_FIXED的内容映射到某个不属于您的地址,然后从您的脚下拉出堆栈。你不能这样做。

地址空间不适合你。MAP_FIXED只能安全地覆盖早期的映射。您可以在一个实验中玩游戏,之后您将丢弃该程序,但任何其他用途都无法正常工作。

现在,您对setcontext的调用将会崩溃,因为它不知道返回的位置。你甚至知道函数调用和堆栈是如何交互的吗?你对setcontext的调用会将返回地址保存在堆栈上,然后setcontext会更改堆栈指针,然后它会尝试返回并死掉,因为它读取0作为返回地址(或者setcontext可能会将旧堆栈指针保存在其他寄存器中并将其恢复从它返回之前的那个寄存器和崩溃是你的另一个mmap覆盖真正的堆栈)。请不要这样做。您可以在不作为操作系统的情况下可靠地更改堆栈的唯一机会是使用sigaltstack设置信号处理程序,捕获该信号并且永远不会从信号处理程序返回。

但是,由于您将新堆栈的内存映射到MAP_FIXED到某个随机地址,您可能会覆盖其他一些重要的数据结构,但它仍然无效。