#include "HexdumpWidget.h" #include "ui_HexdumpWidget.h" #include "common/Helpers.h" #include "common/Configuration.h" #include "common/TempConfig.h" #include #include #include #include #include #include #include #include #include HexdumpWidget::HexdumpWidget(MainWindow *main, QAction *action) : MemoryDockWidget(CutterCore::MemoryWidgetType::Hexdump, main, action), ui(new Ui::HexdumpWidget), seekable(new CutterSeekable(this)) { ui->setupUi(this); /* * Ugly hack just for the layout issue * QSettings saves the state with the object names * By doing this hack, * you can at least avoid some mess by dismissing all the Extra Widgets */ QString name = "Hexdump"; if (!action) { name = "Extra Hexdump"; } setObjectName(name); ui->copyMD5->setIcon(QIcon(":/img/icons/copy.svg")); ui->copySHA1->setIcon(QIcon(":/img/icons/copy.svg")); ui->splitter->setChildrenCollapsible(false); QToolButton *closeButton = new QToolButton; QIcon closeIcon = QIcon(":/img/icons/delete.svg"); closeButton->setIcon(closeIcon); closeButton->setAutoRaise(true); ui->hexSideTab_2->setCornerWidget(closeButton); ui->openSideViewB->hide(); // hide button at startup since side view is visible connect(closeButton, &QToolButton::clicked, this, [this] { showSidePanel(false); }); connect(ui->openSideViewB, &QToolButton::clicked, this, [this] { showSidePanel(true); }); ui->bytesMD5->setPlaceholderText("Select bytes to display information"); ui->bytesEntropy->setPlaceholderText("Select bytes to display information"); ui->bytesSHA1->setPlaceholderText("Select bytes to display information"); ui->hexDisasTextEdit->setPlaceholderText("Select bytes to display information"); setupFonts(); ui->openSideViewB->setStyleSheet("" "QToolButton {" " border : 0px;" " padding : 0px;" " margin : 0px;" "}" "QToolButton:hover {" " border : 1px solid;" " border-width : 1px;" " border-color : #3daee9" "}"); this->setWindowTitle(tr("Hexdump")); refreshDeferrer = createReplacingRefreshDeferrer(false, [this](const RVA *offset) { refresh(offset ? *offset : RVA_INVALID); }); connect(&syncAction, SIGNAL(triggered(bool)), this, SLOT(toggleSync())); syncAction.setText(tr("Sync/unsync offset")); this->ui->hexTextView->addAction(&syncAction); connect(Config(), SIGNAL(fontsUpdated()), this, SLOT(fontsUpdated())); connect(this, &QDockWidget::visibilityChanged, this, [](bool visibility) { if (visibility) { Core()->setMemoryWidgetPriority(CutterCore::MemoryWidgetType::Hexdump); } }); connect(Core(), &CutterCore::refreshAll, this, [this]() { refresh(); }); connect(seekable, &CutterSeekable::seekableSeekChanged, this, &HexdumpWidget::onSeekChanged); connect(ui->hexTextView, &HexWidget::positionChanged, this, [this](RVA addr) { if (!sent_seek) { sent_seek = true; seekable->seek(addr); sent_seek = false; } }); connect(ui->hexTextView, &HexWidget::selectionChanged, this, &HexdumpWidget::selectionChanged); connect(ui->hexSideTab_2, &QTabWidget::currentChanged, this, &HexdumpWidget::refreshSelectionInfo); initParsing(); selectHexPreview(); } void HexdumpWidget::onSeekChanged(RVA addr) { if (sent_seek) { sent_seek = false; return; } refresh(addr); } HexdumpWidget::~HexdumpWidget() {} void HexdumpWidget::refresh() { refresh(RVA_INVALID); } void HexdumpWidget::refresh(RVA addr) { if (!refreshDeferrer->attemptRefresh(addr == RVA_INVALID ? nullptr : new RVA(addr))) { return; } sent_seek = true; if (addr != RVA_INVALID) { ui->hexTextView->seek(addr); } else { ui->hexTextView->refresh(); refreshSelectionInfo(); } sent_seek = false; } void HexdumpWidget::initParsing() { // Fill the plugins combo for the hexdump sidebar ui->parseArchComboBox->insertItems(0, Core()->getAsmPluginNames()); ui->parseEndianComboBox->setCurrentIndex(Core()->getConfigb("cfg.bigendian") ? 1 : 0); } void HexdumpWidget::selectionChanged(HexWidget::Selection selection) { if (selection.empty) { clearParseWindow(); } else { updateParseWindow(selection.startAddress, selection.endAddress - selection.startAddress + 1); } } void HexdumpWidget::on_parseArchComboBox_currentTextChanged(const QString &/*arg1*/) { refreshSelectionInfo(); } void HexdumpWidget::on_parseBitsComboBox_currentTextChanged(const QString &/*arg1*/) { refreshSelectionInfo(); } void HexdumpWidget::toggleSync() { QString windowTitle = tr("Hexdump"); seekable->toggleSynchronization(); if (seekable->isSynchronized()) { setWindowTitle(windowTitle); } else { setWindowTitle(windowTitle + CutterSeekable::tr(" (unsynced)")); } } void HexdumpWidget::setupFonts() { QFont font = Config()->getFont(); ui->hexDisasTextEdit->setFont(font); ui->hexTextView->setMonospaceFont(font); } void HexdumpWidget::refreshSelectionInfo() { selectionChanged(ui->hexTextView->getSelection()); } void HexdumpWidget::fontsUpdated() { setupFonts(); } void HexdumpWidget::clearParseWindow() { ui->hexDisasTextEdit->setPlainText(""); ui->bytesEntropy->setText(""); ui->bytesMD5->setText(""); ui->bytesSHA1->setText(""); } void HexdumpWidget::showSidePanel(bool show) { ui->hexSideTab_2->setVisible(show); ui->openSideViewB->setHidden(show); if (show) { refreshSelectionInfo(); } } void HexdumpWidget::updateParseWindow(RVA start_address, int size) { if (!ui->hexSideTab_2->isVisible()) { return; } QString address = RAddressString(start_address); QString argument = QString("%1@" + address).arg(size); if (ui->hexSideTab_2->currentIndex() == 0) { // scope for TempConfig // Get selected combos QString arch = ui->parseArchComboBox->currentText(); QString bits = ui->parseBitsComboBox->currentText(); bool bigEndian = ui->parseEndianComboBox->currentIndex() == 1; TempConfig tempConfig; tempConfig .set("asm.arch", arch) .set("asm.bits", bits) .set("cfg.bigendian", bigEndian); switch (ui->parseTypeComboBox->currentIndex()) { case 0: // Disassembly ui->hexDisasTextEdit->setPlainText(Core()->cmd("pda " + argument)); break; case 1: // String ui->hexDisasTextEdit->setPlainText(Core()->cmd("pcs " + argument)); break; case 2: // Assembler ui->hexDisasTextEdit->setPlainText(Core()->cmd("pca " + argument)); break; case 3: // C byte array ui->hexDisasTextEdit->setPlainText(Core()->cmd("pc " + argument)); break; case 4: // C half-word ui->hexDisasTextEdit->setPlainText(Core()->cmd("pch " + argument)); break; case 5: // C word ui->hexDisasTextEdit->setPlainText(Core()->cmd("pcw " + argument)); break; case 6: // C dword ui->hexDisasTextEdit->setPlainText(Core()->cmd("pcd " + argument)); break; case 7: // Python ui->hexDisasTextEdit->setPlainText(Core()->cmd("pcp " + argument)); break; case 8: // JSON ui->hexDisasTextEdit->setPlainText(Core()->cmd("pcj " + argument)); break; case 9: // JavaScript ui->hexDisasTextEdit->setPlainText(Core()->cmd("pcJ " + argument)); break; default: ui->hexDisasTextEdit->setPlainText(""); } } else { // Fill the information tab hashes and entropy ui->bytesMD5->setText(Core()->cmd("ph md5 " + argument).trimmed()); ui->bytesSHA1->setText(Core()->cmd("ph sha1 " + argument).trimmed()); ui->bytesEntropy->setText(Core()->cmd("ph entropy " + argument).trimmed()); ui->bytesMD5->setCursorPosition(0); ui->bytesSHA1->setCursorPosition(0); } } void HexdumpWidget::on_parseTypeComboBox_currentTextChanged(const QString &) { if (ui->parseTypeComboBox->currentIndex() == 0) { ui->hexSideFrame_2->show(); } else { ui->hexSideFrame_2->hide(); } refreshSelectionInfo(); } void HexdumpWidget::on_parseEndianComboBox_currentTextChanged(const QString &) { refreshSelectionInfo(); } void HexdumpWidget::on_hexSideTab_2_currentChanged(int /*index*/) { /* if (index == 2) { // Add data to HTML Polar functions graph QFile html(":/html/bar.html"); if(!html.open(QIODevice::ReadOnly)) { QMessageBox::information(0,"error",html.errorString()); } QString code = html.readAll(); html.close(); this->histoWebView->setHtml(code); this->histoWebView->show(); } else { this->histoWebView->hide(); } */ } void HexdumpWidget::resizeEvent(QResizeEvent *event) { QDockWidget::resizeEvent(event); refresh(); } QWidget *HexdumpWidget::widgetToFocusOnRaise() { return ui->hexTextView; } void HexdumpWidget::on_copyMD5_clicked() { QString md5 = ui->bytesMD5->text(); QClipboard *clipboard = QApplication::clipboard(); clipboard->setText(md5); // FIXME // this->main->addOutput("MD5 copied to clipboard: " + md5); } void HexdumpWidget::on_copySHA1_clicked() { QString sha1 = ui->bytesSHA1->text(); QClipboard *clipboard = QApplication::clipboard(); clipboard->setText(sha1); // FIXME // this->main->addOutput("SHA1 copied to clipboard: " + sha1); } void HexdumpWidget::selectHexPreview() { // Pre-select arch and bits in the hexdump sidebar QString arch = Core()->getConfig("asm.arch"); QString bits = Core()->getConfig("asm.bits"); if (ui->parseArchComboBox->findText(arch) != -1) { ui->parseArchComboBox->setCurrentIndex(ui->parseArchComboBox->findText(arch)); } if (ui->parseBitsComboBox->findText(bits) != -1) { ui->parseBitsComboBox->setCurrentIndex(ui->parseBitsComboBox->findText(bits)); } }