从ptraced进程读取/ proc / pid / mem返回EOF

时间:2014-08-08 11:56:54

标签: linux ptrace

上下文

我一直在为我的最终任务工作,我发现了以下奇怪的行为。

我编写了一个跟踪器,以便能够从子进程读取/写入内存。我的目的是在给定的点读取当前执行的指令,然后对其进行反汇编以获取有关存储器操作数等的一些信息。

出于测试目的,使用了用C编写的简单HelloWorld。

信息

我写过的跟踪器的代码,虽然为了更容易理解而被简化,但是:

size_t tracer::readMem(ADDR_t offset, char *buff, size_t len) {
    REQUIRE(_state != TRCS_UNINITIALISED);

    if (_memsdescr < 0 || fcntl(_memsdescr, F_GETFL) < 0) {
        _memsdescr = open(("/proc/" + to_string(_child_pid_t) + "/mem").c_str(), O_LARGEFILE);
        if (_memsdescr < 0) {
            logmanager::getInstance ().emplaceBasicLogger ("tracer")
                    .log ( SLVL_ERROR, "Process\' memory could not be "
                           " opened. \n");
            PANIC;
        } else {
            logmanager::getInstance ().emplaceBasicLogger ("tracer")
                    .logfmt ( SLVL_DEBUG, "Opened process' memory. %lx bytes long\n",
                              lseek(_memsdescr, 0, SEEK_END));
        }
    }

    ASSERT(offset <= lseek(_memsdescr, 0, SEEK_END));

    int ret = pread(_memsdescr, buff, len, offset);
    if (ret < 0) {
        logmanager::getInstance ().emplaceBasicLogger ("tracer")
                .logfmt( SLVL_ERROR, "Error reading from memory descriptor: %s\n", sys_errlist[errno]);
    }
    return ret;

}

控制exectution的代码如下。基本上它所做的就是从/ proc / mem读取15个字节的块。通过在调用ptrace(PTRACE_SINGLESTEP)之后获取RIP(指令指针)的值来获得这些块的地址。这意味着我尝试读取的所有内存都应映射到进程的内存空间中。

trc.load (filename);
        trc.launchProgram();
        cout << "   Started with pid " << trc.getChildPid() << endl << endl;

        //memspacy::memory_map::printSystemProcVmap(trc.getChildPid());

        //inj.prop_setTraceSyscalls (true);

        while (trc.prop_getState () != memspacy::TRCS_STOPPED) {

            //if (trc.isSyscall()){
            //  trc.showSyscall();
            //}

            //HERE IS WHERE THE DISASSEMBLY takes place
            if (trc.readMem(trc.peekReg(a_RIP), inst_buff, MAX_ARCH_INST_LEN)
                    && dec.disassemble()) {
                dec.printFormatted();

            }

            trc.singleStep();
        }

问题

HelloWorld应该由几千个指令组成,但我得到的输出就是这个。

mov %rsp, %rdi
add %al, (%rax)
push %rdi
push %rsi
push %rsp
mov %edi, %ebx
in %dx, %al 
xor %ecx, -0x3f(%rax)
invalid

有用的事实

似乎在几条指令之后,读取功能停止获取所有数据。 没有抛出错误,唯一的问题是读取内存返回0字节。这意味着根据read()联机帮助页中的信息达到EOF,但lseek()返回的大小为0xFFFFFFFFFFFF,因此在该端应该没有问题。因此,所有读取都在映射区域内,因为我使用程序计数器作为偏移量。

我真的不能想到除了页面权限之外的任何东西,但是它们都设置了读取权限,否则它甚至都不会执行。 该过程是正确的Ptraced ,并且执行运行正常,具有预期的行为,甚至寄存器与控制测试(用于检查原始行为的测试)完全相同。

我目前的猜测是,它在某个时刻到达映射区域的末尾并且使描述符无效,因此最后的“无效”指令,但即使在每次读取时打开文件,结果也不会改变。

数据

这是内存映射和最后一次有效读取的读取偏移量。

00400000-00401000 r-xp 00000000 08:06 7602542                            /home/amontes/workspace/memspacy_build/assets/test/test
00600000-00602000 rw-p 00000000 08:06 7602542                            /home/amontes/workspace/memspacy_build/assets/test/test
**7fe3eb602000-7fe3eb625000 r-xp 00000000 08:11 657171                     /lib/x86_64-linux-gnu/ld-2.19.so**
7fe3eb824000-7fe3eb826000 rw-p 00022000 08:11 657171                     /lib/x86_64-linux-gnu/ld-2.19.so
7fe3eb826000-7fe3eb827000 rw-p 00000000 00:00 0 
7fff57783000-7fff577a4000 rw-p 00000000 00:00 0                          [stack]
7fff577fe000-7fff57800000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

最后有效偏移7fe3eb606a7c - &gt;这显示无效指令

第一个无效偏移7fe3eb606a7d - &gt;这将返回EOF


任何帮助或任何想法都会非常感激。谢谢。

1 个答案:

答案 0 :(得分:0)

好吧,我不知道这是一个由某些更新引起的错误,还是一个非常具体的内核版本或者你想要调用它的任何内容。 干净安装操作系统后,一切正常。我可以得到指令流,而read函数总是返回数据。

在擦拭HD之前和安装之前,我试过ptrace(PTRACE_PEEKDATA)没有运气。现在一切正常。

我真的不相信这个问题会对任何人有所帮助,但有时一个干净的开始是要走的路。尽管我不愿意承认,但我不时发生这种情况,并不总是与编码软件有关。