#include "CPUStack.h" #include #include "Configuration.h" #include "Bridge.h" #include "HexEditDialog.h" #include "WordEditDialog.h" CPUStack::CPUStack(QWidget* parent) : HexDump(parent) { fontsUpdated(); setShowHeader(false); int charwidth = getCharWidth(); ColumnDescriptor_t wColDesc; DataDescriptor_t dDesc; mForceColumn = 1; wColDesc.isData = true; //void* wColDesc.itemCount = 1; wColDesc.separator = 0; #ifdef _WIN64 wColDesc.data.itemSize = Qword; wColDesc.data.qwordMode = HexQword; #else wColDesc.data.itemSize = Dword; wColDesc.data.dwordMode = HexDword; #endif appendDescriptor(8 + charwidth * 2 * sizeof(uint_t), "void*", false, wColDesc); wColDesc.isData = false; //comments wColDesc.itemCount = 0; wColDesc.separator = 0; dDesc.itemSize = Byte; dDesc.byteMode = AsciiByte; wColDesc.data = dDesc; appendDescriptor(2000, "Comments", false, wColDesc); connect(Bridge::getBridge(), SIGNAL(stackDumpAt(uint_t, uint_t)), this, SLOT(stackDumpAt(uint_t, uint_t))); connect(Bridge::getBridge(), SIGNAL(selectionStackGet(SELECTIONDATA*)), this, SLOT(selectionGet(SELECTIONDATA*))); connect(Bridge::getBridge(), SIGNAL(selectionStackSet(const SELECTIONDATA*)), this, SLOT(selectionSet(const SELECTIONDATA*))); setupContextMenu(); mGoto = 0; backgroundColor = ConfigColor("StackBackgroundColor"); textColor = ConfigColor("StackTextColor"); selectionColor = ConfigColor("StackSelectionColor"); } void CPUStack::colorsUpdated() { HexDump::colorsUpdated(); backgroundColor = ConfigColor("StackBackgroundColor"); textColor = ConfigColor("StackTextColor"); selectionColor = ConfigColor("StackSelectionColor"); } void CPUStack::fontsUpdated() { setFont(ConfigFont("Stack")); } void CPUStack::setupContextMenu() { //Binary menu mBinaryMenu = new QMenu("B&inary", this); //Binary->Edit mBinaryEditAction = new QAction("&Edit", this); mBinaryEditAction->setShortcutContext(Qt::WidgetShortcut); this->addAction(mBinaryEditAction); connect(mBinaryEditAction, SIGNAL(triggered()), this, SLOT(binaryEditSlot())); mBinaryMenu->addAction(mBinaryEditAction); //Binary->Fill mBinaryFillAction = new QAction("&Fill...", this); mBinaryFillAction->setShortcutContext(Qt::WidgetShortcut); this->addAction(mBinaryFillAction); connect(mBinaryFillAction, SIGNAL(triggered()), this, SLOT(binaryFillSlot())); mBinaryMenu->addAction(mBinaryFillAction); //Binary->Separator mBinaryMenu->addSeparator(); //Binary->Copy mBinaryCopyAction = new QAction("&Copy", this); mBinaryCopyAction->setShortcutContext(Qt::WidgetShortcut); this->addAction(mBinaryCopyAction); connect(mBinaryCopyAction, SIGNAL(triggered()), this, SLOT(binaryCopySlot())); mBinaryMenu->addAction(mBinaryCopyAction); //Binary->Paste mBinaryPasteAction = new QAction("&Paste", this); mBinaryPasteAction->setShortcutContext(Qt::WidgetShortcut); this->addAction(mBinaryPasteAction); connect(mBinaryPasteAction, SIGNAL(triggered()), this, SLOT(binaryPasteSlot())); mBinaryMenu->addAction(mBinaryPasteAction); //Binary->Paste (Ignore Size) mBinaryPasteIgnoreSizeAction = new QAction("Paste (&Ignore Size)", this); mBinaryPasteIgnoreSizeAction->setShortcutContext(Qt::WidgetShortcut); this->addAction(mBinaryPasteIgnoreSizeAction); connect(mBinaryPasteIgnoreSizeAction, SIGNAL(triggered()), this, SLOT(binaryPasteIgnoreSizeSlot())); mBinaryMenu->addAction(mBinaryPasteIgnoreSizeAction); // Restore Selection mUndoSelection = new QAction("&Restore selection", this); mUndoSelection->setShortcutContext(Qt::WidgetShortcut); this->addAction(mUndoSelection); connect(mUndoSelection, SIGNAL(triggered()), this, SLOT(undoSelectionSlot())); // Modify mModifyAction = new QAction("Modify", this); connect(mModifyAction, SIGNAL(triggered()), this, SLOT(modifySlot())); #ifdef _WIN64 mGotoSp = new QAction("Follow R&SP", this); mGotoBp = new QAction("Follow R&BP", this); #else mGotoSp = new QAction("Follow E&SP", this); mGotoBp = new QAction("Follow E&BP", this); #endif //_WIN64 mGotoSp->setShortcutContext(Qt::WidgetShortcut); this->addAction(mGotoSp); connect(mGotoSp, SIGNAL(triggered()), this, SLOT(gotoSpSlot())); connect(mGotoBp, SIGNAL(triggered()), this, SLOT(gotoBpSlot())); //Find Pattern mFindPatternAction = new QAction("&Find Pattern...", this); mFindPatternAction->setShortcutContext(Qt::WidgetShortcut); this->addAction(mFindPatternAction); connect(mFindPatternAction, SIGNAL(triggered()), this, SLOT(findPattern())); mGotoExpression = new QAction("&Expression", this); mGotoExpression->setShortcutContext(Qt::WidgetShortcut); this->addAction(mGotoExpression); connect(mGotoExpression, SIGNAL(triggered()), this, SLOT(gotoExpressionSlot())); mFollowDisasm = new QAction("&Follow in Disassembler", this); mFollowDisasm->setShortcutContext(Qt::WidgetShortcut); mFollowDisasm->setShortcut(QKeySequence("enter")); this->addAction(mFollowDisasm); connect(mFollowDisasm, SIGNAL(triggered()), this, SLOT(followDisasmSlot())); connect(this, SIGNAL(enterPressedSignal()), this, SLOT(followDisasmSlot())); mFollowDump = new QAction("Follow in &Dump", this); connect(mFollowDump, SIGNAL(triggered()), this, SLOT(followDumpSlot())); mFollowStack = new QAction("Follow in &Stack", this); connect(mFollowStack, SIGNAL(triggered()), this, SLOT(followStackSlot())); mPluginMenu = new QMenu(this); Bridge::getBridge()->emitMenuAddToList(this, mPluginMenu, GUI_STACK_MENU); refreshShortcutsSlot(); connect(Config(), SIGNAL(shortcutsUpdated()), this, SLOT(refreshShortcutsSlot())); } void CPUStack::refreshShortcutsSlot() { mBinaryEditAction->setShortcut(ConfigShortcut("ActionBinaryEdit")); mBinaryFillAction->setShortcut(ConfigShortcut("ActionBinaryFill")); mBinaryCopyAction->setShortcut(ConfigShortcut("ActionBinaryCopy")); mBinaryPasteAction->setShortcut(ConfigShortcut("ActionBinaryPaste")); mBinaryPasteIgnoreSizeAction->setShortcut(ConfigShortcut("ActionBinaryPasteIgnoreSize")); mUndoSelection->setShortcut(ConfigShortcut("ActionUndoSelection")); mGotoSp->setShortcut(ConfigShortcut("ActionGotoOrigin")); mFindPatternAction->setShortcut(ConfigShortcut("ActionFindPattern")); mGotoExpression->setShortcut(ConfigShortcut("ActionGotoExpression")); } QString CPUStack::paintContent(QPainter* painter, int_t rowBase, int rowOffset, int col, int x, int y, int w, int h) { // Reset byte offset when base address is reached if(rowBase == 0 && mByteOffset != 0) printDumpAt(mMemPage->getBase(), false, false); // Compute RVA int wBytePerRowCount = getBytePerRowCount(); int_t wRva = (rowBase + rowOffset) * wBytePerRowCount - mByteOffset; uint_t wVa = rvaToVa(wRva); bool wIsSelected = isSelected(wRva); if(wIsSelected) //highlight if selected painter->fillRect(QRect(x, y, w, h), QBrush(selectionColor)); bool wActiveStack = true; if(wVa < mCsp) //inactive stack wActiveStack = false; STACK_COMMENT comment; if(col == 0) // paint stack address { char label[MAX_LABEL_SIZE] = ""; QString addrText = ""; int_t cur_addr = rvaToVa((rowBase + rowOffset) * getBytePerRowCount() - mByteOffset); if(mRvaDisplayEnabled) //RVA display { int_t rva = cur_addr - mRvaDisplayBase; if(rva == 0) { #ifdef _WIN64 addrText = "$ ==> "; #else addrText = "$ ==> "; #endif //_WIN64 } else if(rva > 0) { #ifdef _WIN64 addrText = "$+" + QString("%1").arg(rva, -15, 16, QChar(' ')).toUpper(); #else addrText = "$+" + QString("%1").arg(rva, -7, 16, QChar(' ')).toUpper(); #endif //_WIN64 } else if(rva < 0) { #ifdef _WIN64 addrText = "$-" + QString("%1").arg(-rva, -15, 16, QChar(' ')).toUpper(); #else addrText = "$-" + QString("%1").arg(-rva, -7, 16, QChar(' ')).toUpper(); #endif //_WIN64 } } addrText += AddressToString(cur_addr); if(DbgGetLabelAt(cur_addr, SEG_DEFAULT, label)) //has label { char module[MAX_MODULE_SIZE] = ""; if(DbgGetModuleAt(cur_addr, module) && !QString(label).startsWith("JMP.&")) addrText += " <" + QString(module) + "." + QString(label) + ">"; else addrText += " <" + QString(label) + ">"; } else *label = 0; QColor background; if(*label) //label { if(wVa == mCsp) //CSP { background = ConfigColor("StackCspBackgroundColor"); painter->setPen(QPen(ConfigColor("StackCspColor"))); } else //no CSP { background = ConfigColor("StackLabelBackgroundColor"); painter->setPen(ConfigColor("StackLabelColor")); } } else //no label { if(wVa == mCsp) //CSP { background = ConfigColor("StackCspBackgroundColor"); painter->setPen(QPen(ConfigColor("StackCspColor"))); } else if(wIsSelected) //selected normal address { background = ConfigColor("StackSelectedAddressBackgroundColor"); painter->setPen(QPen(ConfigColor("StackSelectedAddressColor"))); //black address (DisassemblySelectedAddressColor) } else //normal address { background = ConfigColor("StackAddressBackgroundColor"); painter->setPen(QPen(ConfigColor("StackAddressColor"))); } } if(background.alpha()) painter->fillRect(QRect(x, y, w, h), QBrush(background)); //fill background when defined painter->drawText(QRect(x + 4, y , w - 4 , h), Qt::AlignVCenter | Qt::AlignLeft, addrText); } else if(mDescriptor.at(col - 1).isData == true) //paint stack data { int wBytePerRowCount = getBytePerRowCount(); int_t wRva = (rowBase + rowOffset) * wBytePerRowCount - mByteOffset; printSelected(painter, rowBase, rowOffset, col, x, y, w, h); QList richText; getString(col - 1, wRva, &richText); if(!wActiveStack) { QColor inactiveColor = ConfigColor("StackInactiveTextColor"); for(int i = 0; i < richText.size(); i++) { richText[i].flags = RichTextPainter::FlagColor; richText[i].textColor = inactiveColor; } } RichTextPainter::paintRichText(painter, x, y, w, h, 4, &richText, getCharWidth()); } else if(DbgStackCommentGet(rvaToVa(wRva), &comment)) //paint stack comments { QString wStr = QString(comment.comment); if(wActiveStack) { if(*comment.color) painter->setPen(QPen(QColor(QString(comment.color)))); else painter->setPen(QPen(textColor)); } else painter->setPen(QPen(ConfigColor("StackInactiveTextColor"))); painter->drawText(QRect(x + 4, y , w - 4 , h), Qt::AlignVCenter | Qt::AlignLeft, wStr); } return ""; } void CPUStack::contextMenuEvent(QContextMenuEvent* event) { if(!DbgIsDebugging()) return; QMenu* wMenu = new QMenu(this); //create context menu wMenu->addAction(mModifyAction); wMenu->addMenu(mBinaryMenu); int_t start = rvaToVa(getSelectionStart()); int_t end = rvaToVa(getSelectionEnd()); if(DbgFunctions()->PatchInRange(start, end)) //nothing patched in selected range wMenu->addAction(mUndoSelection); wMenu->addAction(mFindPatternAction); wMenu->addAction(mGotoSp); wMenu->addAction(mGotoBp); wMenu->addAction(mGotoExpression); uint_t selectedData; if(mMemPage->read((byte_t*)&selectedData, getInitialSelection(), sizeof(uint_t))) if(DbgMemIsValidReadPtr(selectedData)) //data is a pointer { uint_t stackBegin = mMemPage->getBase(); uint_t stackEnd = stackBegin + mMemPage->getSize(); if(selectedData >= stackBegin && selectedData < stackEnd) wMenu->addAction(mFollowStack); else wMenu->addAction(mFollowDisasm); wMenu->addAction(mFollowDump); } wMenu->addSeparator(); wMenu->addActions(mPluginMenu->actions()); wMenu->exec(event->globalPos()); } void CPUStack::mouseDoubleClickEvent(QMouseEvent* event) { if(event->button() != Qt::LeftButton) return; switch(getColumnIndexFromX(event->x())) { case 0: //address { //very ugly way to calculate the base of the current row (no clue why it works) int_t deltaRowBase = getInitialSelection() % getBytePerRowCount() + mByteOffset; if(deltaRowBase >= getBytePerRowCount()) deltaRowBase -= getBytePerRowCount(); int_t mSelectedVa = rvaToVa(getInitialSelection() - deltaRowBase); if(mRvaDisplayEnabled && mSelectedVa == mRvaDisplayBase) mRvaDisplayEnabled = false; else { mRvaDisplayEnabled = true; mRvaDisplayBase = mSelectedVa; mRvaDisplayPageBase = mMemPage->getBase(); } reloadData(); } break; default: { modifySlot(); } break; } } void CPUStack::stackDumpAt(uint_t addr, uint_t csp) { mCsp = csp; printDumpAt(addr); } void CPUStack::gotoSpSlot() { if(!DbgIsDebugging()) return; DbgCmdExec("sdump csp"); } void CPUStack::gotoBpSlot() { #ifdef _WIN64 DbgCmdExec("sdump rbp"); #else DbgCmdExec("sdump ebp"); #endif //_WIN64 } void CPUStack::gotoExpressionSlot() { if(!DbgIsDebugging()) return; uint_t size = 0; uint_t base = DbgMemFindBaseAddr(mCsp, &size); if(!mGoto) mGoto = new GotoDialog(this); mGoto->validRangeStart = base; mGoto->validRangeEnd = base + size; mGoto->setWindowTitle("Enter expression to follow in Stack..."); if(mGoto->exec() == QDialog::Accepted) { QString cmd; DbgCmdExec(cmd.sprintf("sdump \"%s\"", mGoto->expressionText.toUtf8().constData()).toUtf8().constData()); } } void CPUStack::selectionGet(SELECTIONDATA* selection) { selection->start = rvaToVa(getSelectionStart()); selection->end = rvaToVa(getSelectionEnd()); Bridge::getBridge()->setResult(1); } void CPUStack::selectionSet(const SELECTIONDATA* selection) { int_t selMin = mMemPage->getBase(); int_t selMax = selMin + mMemPage->getSize(); int_t start = selection->start; int_t end = selection->end; if(start < selMin || start >= selMax || end < selMin || end >= selMax) //selection out of range { Bridge::getBridge()->setResult(0); return; } setSingleSelection(start - selMin); expandSelectionUpTo(end - selMin); reloadData(); Bridge::getBridge()->setResult(1); } void CPUStack::followDisasmSlot() { uint_t selectedData; if(mMemPage->read((byte_t*)&selectedData, getInitialSelection(), sizeof(uint_t))) if(DbgMemIsValidReadPtr(selectedData)) //data is a pointer { QString addrText = QString("%1").arg(selectedData, sizeof(int_t) * 2, 16, QChar('0')).toUpper(); DbgCmdExec(QString("disasm " + addrText).toUtf8().constData()); } } void CPUStack::followDumpSlot() { uint_t selectedData; if(mMemPage->read((byte_t*)&selectedData, getInitialSelection(), sizeof(uint_t))) if(DbgMemIsValidReadPtr(selectedData)) //data is a pointer { QString addrText = QString("%1").arg(selectedData, sizeof(int_t) * 2, 16, QChar('0')).toUpper(); DbgCmdExec(QString("dump " + addrText).toUtf8().constData()); } } void CPUStack::followStackSlot() { uint_t selectedData; if(mMemPage->read((byte_t*)&selectedData, getInitialSelection(), sizeof(uint_t))) if(DbgMemIsValidReadPtr(selectedData)) //data is a pointer { QString addrText = QString("%1").arg(selectedData, sizeof(int_t) * 2, 16, QChar('0')).toUpper(); DbgCmdExec(QString("sdump " + addrText).toUtf8().constData()); } } void CPUStack::binaryEditSlot() { HexEditDialog hexEdit(this); int_t selStart = getSelectionStart(); int_t selSize = getSelectionEnd() - selStart + 1; byte_t* data = new byte_t[selSize]; mMemPage->read(data, selStart, selSize); hexEdit.mHexEdit->setData(QByteArray((const char*)data, selSize)); delete [] data; hexEdit.setWindowTitle("Edit data at " + QString("%1").arg(rvaToVa(selStart), sizeof(int_t) * 2, 16, QChar('0')).toUpper()); if(hexEdit.exec() != QDialog::Accepted) return; int_t dataSize = hexEdit.mHexEdit->data().size(); int_t newSize = selSize > dataSize ? selSize : dataSize; data = new byte_t[newSize]; mMemPage->read(data, selStart, newSize); QByteArray patched = hexEdit.mHexEdit->applyMaskedData(QByteArray((const char*)data, newSize)); mMemPage->write(patched.constData(), selStart, patched.size()); GuiUpdateAllViews(); } void CPUStack::binaryFillSlot() { HexEditDialog hexEdit(this); hexEdit.mHexEdit->setOverwriteMode(false); int_t selStart = getSelectionStart(); hexEdit.setWindowTitle("Fill data at " + QString("%1").arg(rvaToVa(selStart), sizeof(int_t) * 2, 16, QChar('0')).toUpper()); if(hexEdit.exec() != QDialog::Accepted) return; QString pattern = hexEdit.mHexEdit->pattern(); int_t selSize = getSelectionEnd() - selStart + 1; byte_t* data = new byte_t[selSize]; mMemPage->read(data, selStart, selSize); hexEdit.mHexEdit->setData(QByteArray((const char*)data, selSize)); delete [] data; hexEdit.mHexEdit->fill(0, QString(pattern)); QByteArray patched(hexEdit.mHexEdit->data()); mMemPage->write(patched, selStart, patched.size()); GuiUpdateAllViews(); } void CPUStack::binaryCopySlot() { HexEditDialog hexEdit(this); int_t selStart = getSelectionStart(); int_t selSize = getSelectionEnd() - selStart + 1; byte_t* data = new byte_t[selSize]; mMemPage->read(data, selStart, selSize); hexEdit.mHexEdit->setData(QByteArray((const char*)data, selSize)); delete [] data; Bridge::CopyToClipboard(hexEdit.mHexEdit->pattern(true)); } void CPUStack::binaryPasteSlot() { HexEditDialog hexEdit(this); int_t selStart = getSelectionStart(); int_t selSize = getSelectionEnd() - selStart + 1; QClipboard* clipboard = QApplication::clipboard(); hexEdit.mHexEdit->setData(clipboard->text()); byte_t* data = new byte_t[selSize]; mMemPage->read(data, selStart, selSize); QByteArray patched = hexEdit.mHexEdit->applyMaskedData(QByteArray((const char*)data, selSize)); if(patched.size() < selSize) selSize = patched.size(); mMemPage->write(patched.constData(), selStart, selSize); GuiUpdateAllViews(); } void CPUStack::binaryPasteIgnoreSizeSlot() { HexEditDialog hexEdit(this); int_t selStart = getSelectionStart(); int_t selSize = getSelectionEnd() - selStart + 1; QClipboard* clipboard = QApplication::clipboard(); hexEdit.mHexEdit->setData(clipboard->text()); byte_t* data = new byte_t[selSize]; mMemPage->read(data, selStart, selSize); QByteArray patched = hexEdit.mHexEdit->applyMaskedData(QByteArray((const char*)data, selSize)); delete [] data; mMemPage->write(patched.constData(), selStart, patched.size()); GuiUpdateAllViews(); } void CPUStack::findPattern() { HexEditDialog hexEdit(this); hexEdit.showEntireBlock(true); hexEdit.mHexEdit->setOverwriteMode(false); hexEdit.setWindowTitle("Find Pattern..."); if(hexEdit.exec() != QDialog::Accepted) return; int_t addr = rvaToVa(getSelectionStart()); if(hexEdit.entireBlock()) addr = DbgMemFindBaseAddr(addr, 0); QString addrText = QString("%1").arg(addr, sizeof(int_t) * 2, 16, QChar('0')).toUpper(); DbgCmdExec(QString("findall " + addrText + ", " + hexEdit.mHexEdit->pattern() + ", &data&").toUtf8().constData()); emit displayReferencesWidget(); } void CPUStack::undoSelectionSlot() { int_t start = rvaToVa(getSelectionStart()); int_t end = rvaToVa(getSelectionEnd()); if(!DbgFunctions()->PatchInRange(start, end)) //nothing patched in selected range return; DbgFunctions()->PatchRestoreRange(start, end); reloadData(); } void CPUStack::modifySlot() { int_t addr = getInitialSelection(); WordEditDialog wEditDialog(this); int_t value = 0; mMemPage->read(&value, addr, sizeof(int_t)); wEditDialog.setup("Modify", value, sizeof(int_t)); if(wEditDialog.exec() != QDialog::Accepted) return; value = wEditDialog.getVal(); mMemPage->write(&value, addr, sizeof(int_t)); reloadData(); }