?? memoryregions.cpp
字號:
/*Copyright (C) 2006 Evan Teran eteran@alum.rit.eduThis program is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2 of the License, or(at your option) any later version.This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.*/#include "MemoryRegions.h"#include "SymbolManager.h"#include "DebuggerCoreInterface.h"#include "Debugger.h"#include "Util.h"#include "State.h"#include <sstream>#include <iostream>#include <string>#include <asm/unistd.h>#include <sys/mman.h>#include <QApplication>#include <QFile>#include <QTextStream>#include <QMessageBox>const unsigned int MemoryRegions::Region::READ = PROT_READ;const unsigned int MemoryRegions::Region::WRITE = PROT_WRITE;const unsigned int MemoryRegions::Region::EXEC = PROT_EXEC;struct BackupInfo { char *buffer; std::size_t size; BaseTypes::address_t tempAddress; uint32_t perms; State state; DebugEventHandlerInterface *eventhandler;};//------------------------------------------------------------------------------// Name: MemoryRegions(BaseTypes::pid_t pid)// Desc: constructor//------------------------------------------------------------------------------MemoryRegions::MemoryRegions(BaseTypes::pid_t pid) : m_PID(pid) { sync();}//------------------------------------------------------------------------------// Name: proccessMapLine(QString &line)// Desc: parses the data from a line of a memory map file//------------------------------------------------------------------------------void MemoryRegions::proccessMapLine(QString &line) { // TODO: use QT's way of doing this std::istringstream ss(qPrintable(line)); std::string perms; Region region; // read the starting address in hex if(ss >> std::hex >> region.start) { // skip the dash if(ss.ignore(1)) { // read the ending address and then the permissions if(ss >> std::hex >> region.end >> perms) { std::string temp[2]; std::string name; // read in the region base, then skip the next two fields if(ss >> region.base >> temp[0] >> temp[1]) { // read in the name, we dont check for success because it's // allowed to not be there (and would therefore be the // empty string) ss >> name; // create a bitmask for the permissions region.permissions = 0; if(perms[0] == 'r') region.permissions |= Region::READ; if(perms[1] == 'w') region.permissions |= Region::WRITE; if(perms[2] == 'x') region.permissions |= Region::EXEC; region.name = name.c_str(); m_Regions.push_back(region); // TODO: make this happen less often! if(!region.name.isEmpty()) { if(region.base == 0x00000000) { if(region.executable()) { if(Debugger::symbolManager != 0) { Debugger::symbolManager->loadSymbolFile(region.name, region.start); } } } } } } } }}//------------------------------------------------------------------------------// Name: sync()// Desc: reads a memory map file line by line//------------------------------------------------------------------------------void MemoryRegions::sync() { m_Regions.clear(); if(m_PID != 0) { const QString mapFile(QString().sprintf("/proc/%d/maps", m_PID)); QFile file(mapFile); if(file.open(QIODevice::ReadOnly | QIODevice::Text)) { QTextStream in(&file); QString line = in.readLine(); while (!line.isNull()) { proccessMapLine(line); line = in.readLine(); } } }}//------------------------------------------------------------------------------// Name: operator==(const Region &o)// Desc: compares two regions for equality//------------------------------------------------------------------------------bool MemoryRegions::Region::operator==(const Region &o) { return start == o.start && end == o.end && permissions == o.permissions && name == o.name && base == o.base;}//------------------------------------------------------------------------------// Name: handleEvent(DebugEvent event)// Desc: //------------------------------------------------------------------------------void MemoryRegions::Region::handleEvent(DebugEvent event) { Q_UNUSED(event); // TODO: check that the event was caused by a hlt in our shellcode if(backupInfo != 0) { // restore the original code and register state Debugger::debuggerBase->writeBytes(backupInfo->tempAddress, backupInfo->buffer, backupInfo->size); Debugger::debuggerBase->setState(backupInfo->state); // update permissions mask permissions = backupInfo->perms; // restore the event handler Debugger::setDebugEventHandler(backupInfo->eventhandler); safeDeleteArray(backupInfo->buffer); safeDelete(backupInfo); } lock = 0;}//------------------------------------------------------------------------------// Name: ~Region()// Desc: //------------------------------------------------------------------------------MemoryRegions::Region::~Region() { if(backupInfo != 0) { safeDeleteArray(backupInfo->buffer); safeDelete(backupInfo); }}//------------------------------------------------------------------------------// Name: setPermissions(bool read, bool write, bool execute)// Desc: attempts to change the permissions of a given region by injecting// shellcode into the debugged process, and executing a mprotect syscall// we probably need to ensure that the debug event server thread is not// waiting for an event at this moment because we need to catch the "hlt"// instruction we injected in order to restore the original code// we also probably need this code to work perfectly in order to implement// memory access breakpoints//------------------------------------------------------------------------------void MemoryRegions::Region::setPermissions(bool read, bool write, bool execute, BaseTypes::address_t tempAddress) {#ifdef Q_OS_LINUX uint32_t perms = 0; const uint32_t len = size(); const uint32_t addr = start; const uint32_t syscallnum = __NR_mprotect; if(read) perms |= READ; if(write) perms |= WRITE; if(execute) perms |= EXEC; // start nowhere near portable code #define LEN_OFFSET 1 #define ADDR_OFFSET 6 #define PERM_OFFSET 11 #define SYSCALL_OFFSET 16 // TODO: only compile this code on x86 char shellcode[] = { "\xb9\x00\x10\x00\x00" // mov $0x00001000,%ecx "\xbb\x00\x40\x00\x00" // mov $0x00004000,%ebx "\xba\x07\x00\x00\x00" // mov $0x00000007,%edx "\xb8\x7d\x00\x00\x00" // mov $0x7d,%eax "\xcd\x80" // int $0x80 "\xf4" // hlt }; // put the data in the right part of the shellcode std::memcpy(&shellcode[LEN_OFFSET], &len, sizeof(len)); std::memcpy(&shellcode[ADDR_OFFSET], &addr, sizeof(addr)); std::memcpy(&shellcode[PERM_OFFSET], &perms, sizeof(perms)); std::memcpy(&shellcode[SYSCALL_OFFSET], &syscallnum, sizeof(syscallnum)); #undef LEN_OFFSET #undef ADDR_OFFSET #undef PERM_OFFSET #undef SYSCALL_OFFSET // end nowhere near portable code backupInfo = new BackupInfo; backupInfo->buffer = new char[sizeof(shellcode)]; backupInfo->size = sizeof(shellcode); backupInfo->tempAddress = tempAddress; backupInfo->perms = perms; // get the current register state of the process Debugger::debuggerBase->getState(backupInfo->state); // backup the bytes currently at our temp address if(Debugger::debuggerBase->readBytes(tempAddress, backupInfo->buffer, backupInfo->size)) { // write out our shellcode if(Debugger::debuggerBase->writeBytes(tempAddress, shellcode, sizeof(shellcode))) { // set eip in the state to out temp address const uint32_t orig_eip = backupInfo->state.eip; backupInfo->state.eip = tempAddress; Debugger::debuggerBase->setState(backupInfo->state); backupInfo->state.eip = orig_eip; lock = 1; backupInfo->eventhandler = Debugger::setDebugEventHandler(this); // run and wait for the "crash" caused by the hlt instruction // should be a SIGSEGV on Linux Debugger::debuggerBase->resume(0); // this is a crappy solution but it works good enough for now while(lock) { QApplication::processEvents(); } return; } } // we only get here if something was not successful, start cleaning up if(backupInfo != 0) { safeDeleteArray(backupInfo->buffer); safeDelete(backupInfo); }#else #error "Unsupported Platform"#endif}//------------------------------------------------------------------------------// Name: setPermissions(bool read, bool write, bool execute)// Desc: wrapper around normal set permissions//------------------------------------------------------------------------------void MemoryRegions::Region::setPermissions(bool read, bool write, bool execute) { BaseTypes::address_t tempAddress = 0x00000000; int count = 0; int ret = QMessageBox::Yes; const QVector<Region> regions = Debugger::memoryRegions->regions(); // search for an executable region to run our shell code foreach(Region region, regions) { if(region.executable()) { if(tempAddress == 0x00000000) { tempAddress = region.start; } ++count; } } if(count == 1 && !execute) { ret = QMessageBox::question(Debugger::debuggerGUI, "Removing Execute Permissions On Last Executable Region", "You are about to remove execute permissions from the last executable region. Because of the need " "to run code in the process to change permissions, there will be no way to undo this. In addition, " "the process will no longer be able to run as it will have no execute permissions in any regions. " "Odds are this is not what you want to do." "Are you sure you want to remove execute permissions from this region?", QMessageBox::Yes, QMessageBox::No, QMessageBox::NoButton); } if(ret == QMessageBox::Yes) { if(tempAddress != 0x00000000) { setPermissions(read, write, execute, tempAddress); } else { QMessageBox::information(Debugger::debuggerGUI, "No Suitable Address Found", "This feature relies on running shellcode in the debugged process, no executable memory region was found. Unfortunately, this means that no more region permission changes can be made (it also means that there is nothing the process can continue to do since it cannot execute at all)."); } }}//------------------------------------------------------------------------------// Name: findBaseAddress(const QString &name, bool *ok) const// Desc: //------------------------------------------------------------------------------BaseTypes::address_t MemoryRegions::findBaseAddress(const QString &name, bool *ok) const { setBool(ok, false); QVector<Region> r = regions(); foreach(Region region, r) { if(region.base == 0x00000000) { if(region.name.endsWith(name)) { setBool(ok, true); return region.start; } } } return 0x00000000;}//------------------------------------------------------------------------------// Name: findRegion(BaseTypes::address_t address) const// Desc: //------------------------------------------------------------------------------bool MemoryRegions::findRegion(BaseTypes::address_t address) const { QVector<Region> r = regions(); foreach(Region i, r) { if(address >= i.start && address < i.end) { return true; } } return false;}//------------------------------------------------------------------------------// Name: findRegion(BaseTypes::address_t address, MemoryRegions::Region ®ion) const// Desc: //------------------------------------------------------------------------------bool MemoryRegions::findRegion(BaseTypes::address_t address, MemoryRegions::Region ®ion) const { QVector<Region> r = regions(); foreach(Region i, r) { if(address >= i.start && address < i.end) { region = i; return true; } } return false;}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -