我一直在为我的最终任务在一个程序工作,我发现了以下奇怪的行为。
我编写了一个跟踪器,以便能够从subprocess读取/写入内存。 我的意图是读取当前执行的指令在一个给定的点,然后反汇编,以获得有关内存操作数等信息。
出于testing目的,使用用C编写的简单的HelloWorld。
我写的示踪剂的代码,尽pipe简化,以便更容易理解,是这样的:
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; }
控制执行的代码如下。 基本上它只是从/ 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
看来,几个指令后,阅读function停止获取任何数据。 没有错误被抛出,唯一的问题是读取内存返回0字节 。 这意味着EOF是根据read()手册页中的信息达到的,但lseek()返回0xFFFFFFFFFFFF的大小,所以应该没有问题。 因为我使用程序计数器作为偏移量,所以所有的读取落在映射的区域内。
除了页面权限之外,我无法真正想到任何东西,但是它们都具有读权限设置,否则它甚至不会执行。 这个过程是正确的Ptraced ,执行运行正常,与预期的行为,甚至寄存器是完全一样的控制testing(一个testing用于检查原来的行为)。
我目前的猜测是,它在某个点到达了映射区域的末尾,并且描述符无效,因此在最后“无效”指令,但是即使在每次读取时打开文件,结果也不会改变。
这是内存映射和最后一次有效读取的读取偏移量。
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 – >这显示无效指令
第一个无效的偏移量7fe3eb606a7d – >这将返回EOF
任何帮助或任何想法将非常感激。 谢谢。
那么,我不知道这是一个更新,或一个非常具体的内核版本或任何你想要调用它造成的错误。 完全安装操作系统后,一切工作正常 。 我可以得到指令流,而读取函数总是返回数据。
在抹HD之前和安装之前,我试了ptrace(PTRACE_PEEKDATA),没有运气。 现在一切正常。
我不是真的相信这个问题会帮助任何人,但有时一个干净的开始是一条路。 尽管我不愿意承认这一点,但时不时发生的事,并不总是与编码软件有关。