diff --git a/hexwalk/entropychart.cpp b/hexwalk/entropychart.cpp index 43004ec..9be73d4 100644 --- a/hexwalk/entropychart.cpp +++ b/hexwalk/entropychart.cpp @@ -1,5 +1,5 @@ #include "entropychart.h" - +#include EntropyChart::EntropyChart(QWidget *parent): QChartView(parent) { @@ -12,7 +12,29 @@ void EntropyChart::mousePressEvent(QMouseEvent * event){ auto pickVal = this->mapToScene(curPoint); pickVal = this->chart()->mapFromScene(curPoint); pickVal = this->chart()->mapToValue(curPoint,this->chart()->series().at(0)); - +emit rubberBandEvent(); emit mousePressed(qint64(pickVal.x())); + QChartView::mousePressEvent(event); + +} +void EntropyChart::resizeEvent(QResizeEvent *event){ + + emit rubberBandEvent(); + QChartView::resizeEvent(event); +} +void EntropyChart::mouseReleaseEvent(QMouseEvent *event){ + emit rubberBandEvent(); + QChartView::mouseReleaseEvent(event); +} + +void EntropyChart::mouseMoveEvent(QMouseEvent * event){ + auto curPoint = QCursor::pos(); + curPoint = this->mapFromGlobal(curPoint); + auto pickVal = this->mapToScene(curPoint); + pickVal = this->chart()->mapFromScene(curPoint); + pickVal = this->chart()->mapToValue(curPoint,this->chart()->series().at(0)); + + emit mouseMoved(qint64(pickVal.x())); + QChartView::mouseMoveEvent(event); } diff --git a/hexwalk/entropychart.h b/hexwalk/entropychart.h index 87791f4..82bab2a 100644 --- a/hexwalk/entropychart.h +++ b/hexwalk/entropychart.h @@ -12,8 +12,14 @@ Q_OBJECT signals: void mousePressed(qint64 value); + void mouseMoved(qint64 address); + void rubberBandEvent(); protected: void mousePressEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void resizeEvent(QResizeEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + diff --git a/hexwalk/entropydialog.cpp b/hexwalk/entropydialog.cpp index a14c995..c0261dc 100644 --- a/hexwalk/entropydialog.cpp +++ b/hexwalk/entropydialog.cpp @@ -2,6 +2,7 @@ #include "ui_entropydialog.h" #include #include +#include EntropyDialog::EntropyDialog(QHexEdit * hexedit,QWidget *parent) : QDialog(parent), @@ -35,14 +36,24 @@ void EntropyDialog::calculate() { qint64 cursor = 0; qint64 dataSize = 1024; - QLineSeries *series = new QLineSeries(); + qint64 blockSize = 1024; + + if(_hexed->getSize() > 32*1024*1024) + { + blockSize = 4096; + } + if(_hexed->getSize() > 128*1024*1024) + { + blockSize = 16384; + } + series = new QLineSeries(); progrDialog = new QProgressDialog("Entropy calculation in progress...","Cancel",0,100,this); progrDialog->setValue(0); progrDialog->show(); while(cursor < _hexed->getSize()) { - dataSize = 1024; + dataSize = blockSize; if(dataSize > (_hexed->getSize()-cursor)) { dataSize = (_hexed->getSize()-cursor); @@ -63,7 +74,7 @@ void EntropyDialog::calculate() chart->legend()->hide(); chart->addSeries(series); chart->createDefaultAxes(); - chart->axes(Qt::Vertical).back()->setRange(0.0,1.1); + chart->axes(Qt::Vertical).back()->setRange(0.0,1.0); chart->axes(Qt::Vertical).back()->setLabelsBrush(QBrush(QColor("lightgray"))); chart->axes(Qt::Horizontal).back()->setLabelsBrush(QBrush(QColor("lightgray"))); chart->setTitle("Entropy chart"); @@ -73,7 +84,8 @@ void EntropyDialog::calculate() //entropyView = new EntropyChart(chart,this); //entropyView->setRenderHint(QPainter::Antialiasing); ui->entropyChart->setChart(chart); - + ui->entropyChart->setRubberBand(QChartView::HorizontalRubberBand); + ui->entropyChart->setDragMode(QGraphicsView::ScrollHandDrag); //QLayoutItem *item; /*while((item=ui->verticalLayout->takeAt(0)) != NULL) @@ -82,6 +94,8 @@ void EntropyDialog::calculate() } ui->verticalLayout->addWidget(entropyView);*/ connect(ui->entropyChart,SIGNAL(mousePressed(qint64)),this,SLOT(mousePressed(qint64))); + connect(ui->entropyChart,SIGNAL(mouseMoved(qint64)),this,SLOT(mouseMoved(qint64))); + connect(ui->entropyChart,SIGNAL(rubberBandEvent()),this,SLOT(limitZoomOut())); } @@ -90,6 +104,53 @@ void EntropyDialog::mousePressed(qint64 value) _hexed->setCursorPosition(2*value); _hexed->ensureVisible(); } +void EntropyDialog::mouseMoved(qint64 address) +{ + if(address > 0 && address < _hexed->getSize()){ + + ui->AddressEdt->setText(QString::asprintf("%lld",address)); + ui->ValueEdt->setText(QString::asprintf("%3.2f",findClosestPoint(series,address).y())); + } +} + +void EntropyDialog::limitZoomOut() { + + // Limit zoom out to 1.0x + + + + QValueAxis *axisX = dynamic_cast(ui->entropyChart->chart()->axisX()); + if (axisX) { + qreal newMin = axisX->min(); + qreal newMax = axisX->max(); + if(axisX->min()< 0.0) + { + ui->entropyChart->chart()->axes(Qt::Horizontal).back()->setRange(0.0,axisX->max()); + } + if(axisX->max()>_hexed->getSize()) + { + ui->entropyChart->chart()->axes(Qt::Horizontal).back()->setRange(axisX->min(),_hexed->getSize()); + } + } + +} + +QPointF EntropyDialog::findClosestPoint(QLineSeries* lineSeries, qreal x) { + QPointF closestPoint; + qreal minDistance = std::numeric_limits::max(); + + // Itera sui punti della serie e trova il punto piĆ¹ vicino + for (const QPointF& point : lineSeries->points()) { + qreal distance = qAbs(point.x() - x); + if (distance < minDistance) { + minDistance = distance; + closestPoint = point; + } + } + + return closestPoint; +} + EntropyDialog::~EntropyDialog() { diff --git a/hexwalk/entropydialog.h b/hexwalk/entropydialog.h index d2570be..ceb876d 100644 --- a/hexwalk/entropydialog.h +++ b/hexwalk/entropydialog.h @@ -21,6 +21,8 @@ class EntropyDialog : public QDialog void calculate(); public slots: void mousePressed(qint64 value); + void mouseMoved(qint64 address); + void limitZoomOut(); private slots: void on_buttonBox_clicked(QAbstractButton *button); @@ -32,6 +34,8 @@ private slots: double blockEntropy(QByteArray * data); EntropyChart *entropyView; QProgressDialog *progrDialog; + QLineSeries *series = NULL; + QPointF findClosestPoint(QLineSeries* lineSeries, qreal x); }; #endif // ENTROPYDIALOG_H diff --git a/hexwalk/entropydialog.ui b/hexwalk/entropydialog.ui index 11e0b24..45e5c05 100644 --- a/hexwalk/entropydialog.ui +++ b/hexwalk/entropydialog.ui @@ -15,16 +15,46 @@ - + - - - - 0 - 0 - - - + + + + + + + + Value: + + + + + + + + + + Address: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + diff --git a/hexwalk/hexwalk.pro b/hexwalk/hexwalk.pro index 1d79ee0..602a8aa 100644 --- a/hexwalk/hexwalk.pro +++ b/hexwalk/hexwalk.pro @@ -6,7 +6,7 @@ QMAKE_LFLAGS += -no-pie -lstdc++ -Bstatic -static-libgcc -static-libstdc++ -stat #Only for Mac: #ICON = images/hexwalk.icns ############### -VERSION = "1.5.0" +VERSION = "1.6.0" QMAKE_TARGET_COPYRIGHT = "gcarmix" QMAKE_TARGET_PRODUCT = "HexWalk" HEADERS = \ diff --git a/hexwalk/hexwalkmain.cpp b/hexwalk/hexwalkmain.cpp index 0ce7c0a..ba1c4eb 100644 --- a/hexwalk/hexwalkmain.cpp +++ b/hexwalk/hexwalkmain.cpp @@ -117,6 +117,9 @@ void HexWalkMain::createMenus() editMenu = menuBar()->addMenu(tr("&Edit")); editMenu->addAction(undoAct); editMenu->addAction(redoAct); + editMenu->addAction(copyAct); + editMenu->addAction(pasteAct); + editMenu->addAction(cutAct); editMenu->addAction(saveSelectionReadable); editMenu->addSeparator(); editMenu->addAction(advancedFindAct); @@ -219,6 +222,16 @@ void HexWalkMain::createActions() redoAct->setShortcuts(QKeySequence::Redo); connect(redoAct, SIGNAL(triggered()), hexEdit, SLOT(redo())); + copyAct = new QAction( tr("&Copy"), this); + copyAct->setShortcuts(QKeySequence::Copy); + connect(copyAct, SIGNAL(triggered()), hexEdit, SLOT(copyText())); + pasteAct = new QAction(tr("&Paste"), this); + pasteAct->setShortcuts(QKeySequence::Paste); + connect(pasteAct, SIGNAL(triggered()), hexEdit, SLOT(pasteText())); + cutAct = new QAction( tr("&Cut"), this); + cutAct->setShortcuts(QKeySequence::Cut); + connect(cutAct, SIGNAL(triggered()), hexEdit, SLOT(cutText())); + saveSelectionReadable = new QAction(tr("&Save Selection Readable..."), this); saveSelectionReadable->setStatusTip(tr("Save selection in readable form")); connect(saveSelectionReadable, SIGNAL(triggered()), this, SLOT(saveSelectionToReadableFile())); diff --git a/hexwalk/hexwalkmain.h b/hexwalk/hexwalkmain.h index 6fc6ca2..2b763ad 100644 --- a/hexwalk/hexwalkmain.h +++ b/hexwalk/hexwalkmain.h @@ -112,6 +112,9 @@ private slots: QAction *undoAct; QAction *redoAct; + QAction *copyAct; + QAction *pasteAct; + QAction *cutAct; QAction *saveSelectionReadable; QAction *aboutAct; diff --git a/hexwalk/stringsdialog.cpp b/hexwalk/stringsdialog.cpp index 37ddd16..47a39ac 100644 --- a/hexwalk/stringsdialog.cpp +++ b/hexwalk/stringsdialog.cpp @@ -43,13 +43,16 @@ void StringsDialog::searchStrings() progrDialog = new QProgressDialog("Search in progress...","Cancel",0,100,this); progrDialog->setValue(0); progrDialog->show(); - while(ui->tableWidget->rowCount() > 0) + /*while(ui->tableWidget->rowCount() > 0) { ui->tableWidget->removeRow(0); - } + }*/ + ui->tableWidget->clearContents(); + ui->tableWidget->setRowCount(0); + while(cursor < _hexEdit->getSize()) { - dataSize = 4096; + dataSize = 16384; if(dataSize > (_hexEdit->getSize()-cursor)) { dataSize = (_hexEdit->getSize()-cursor); @@ -166,12 +169,12 @@ void StringsDialog::searchStrings() cursor+=dataSize; progrDialog->setValue(int(100.0*(double(cursor)/double(_hexEdit->getSize())))); QCoreApplication::processEvents(); - if(occurrencies > 65535) + /*if(occurrencies > 100000) { QMessageBox::warning(this, tr("HexWalk"),tr("Too much occurrencies found, stopping search.")); break; - } + }*/ if(progrDialog->wasCanceled()) break; } @@ -214,3 +217,27 @@ void StringsDialog::on_tableWidget_clicked(const QModelIndex &index) } + +void StringsDialog::on_btnNext_clicked() +{ + findStringInColumn(ui->edtFind->text()); +} + +bool StringsDialog::findStringInColumn(const QString& target) { + int rowCount = ui->tableWidget->rowCount(); + int currentRow = ui->tableWidget->currentRow() +1; + for (int row = currentRow; row < rowCount; ++row) { + QTableWidgetItem* item = ui->tableWidget->item(row, 1); + if (item && item->text().contains(target)) { + //item->setSelected(true); + ui->tableWidget->setCurrentItem(ui->tableWidget->item(row, 1)); + + // Scroll to make the item visible + ui->tableWidget->scrollToItem(ui->tableWidget->item(row, 1), QAbstractItemView::PositionAtTop); + qDebug() << "Found at row:" << row << "column:" << 1; + return true; + } + } + qDebug() << "String not found in column:" << 1; + return false; +} diff --git a/hexwalk/stringsdialog.h b/hexwalk/stringsdialog.h index f9dcdc8..5d0d41c 100644 --- a/hexwalk/stringsdialog.h +++ b/hexwalk/stringsdialog.h @@ -21,11 +21,14 @@ private slots: void on_tableWidget_clicked(const QModelIndex &index); + void on_btnNext_clicked(); + private: Ui::StringsDialog *ui; QHexEdit * _hexEdit; void searchStrings(); QProgressDialog *progrDialog; + bool findStringInColumn(const QString& target); }; diff --git a/hexwalk/stringsdialog.ui b/hexwalk/stringsdialog.ui index 98d76c3..adeb1c4 100644 --- a/hexwalk/stringsdialog.ui +++ b/hexwalk/stringsdialog.ui @@ -168,6 +168,40 @@ Results + + + + + + Find: + + + + + + + + + + Next + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + diff --git a/hexwalk/tagsdialog.cpp b/hexwalk/tagsdialog.cpp index 09ad482..9b0e1d4 100644 --- a/hexwalk/tagsdialog.cpp +++ b/hexwalk/tagsdialog.cpp @@ -262,3 +262,9 @@ void TagsDialog::on_resetBtn_clicked() hexEdit->update(); hexEdit->ensureVisible(); } + +void TagsDialog::on_closeBtn_clicked() +{ + this->hide(); +} + diff --git a/hexwalk/tagsdialog.h b/hexwalk/tagsdialog.h index 1b21a93..7805eaa 100644 --- a/hexwalk/tagsdialog.h +++ b/hexwalk/tagsdialog.h @@ -43,6 +43,8 @@ private slots: void on_resetBtn_clicked(); + void on_closeBtn_clicked(); + private: Ui::TagsDialog *ui; EditTagDialog * edittagDialog; diff --git a/hexwalk/tagsdialog.ui b/hexwalk/tagsdialog.ui index 79e42d2..4e9063f 100644 --- a/hexwalk/tagsdialog.ui +++ b/hexwalk/tagsdialog.ui @@ -14,13 +14,6 @@ HexWalk - Byte Pattern - - - - Reset - - - @@ -65,6 +58,20 @@ + + + + Reset + + + + + + + Close + + + diff --git a/src/qhexedit.cpp b/src/qhexedit.cpp index c70639e..d4ef62c 100644 --- a/src/qhexedit.cpp +++ b/src/qhexedit.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "qhexedit.h" #include @@ -38,7 +39,8 @@ QHexEdit::QHexEdit(QWidget *parent) : QAbstractScrollArea(parent) setAddressFontColor(QPalette::WindowText); setAsciiAreaColor(this->palette().alternateBase().color()); setAsciiFontColor(QPalette::WindowText); - + setContextMenuPolicy(Qt::CustomContextMenu); + connect(this, &QAbstractScrollArea::customContextMenuRequested, this, &QHexEdit::showContextMenu); connect(&_cursorTimer, SIGNAL(timeout()), this, SLOT(updateCursor())); connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(adjust())); connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(adjust())); @@ -1275,3 +1277,82 @@ void QHexEdit::updateCursor() _blink = true; viewport()->update(_cursorRect); } +void QHexEdit::showContextMenu(const QPoint &pos) +{ + QMenu contextMenu; + if(!_editAreaIsAscii) + { + if(getSelectionEnd() - getSelectionBegin()> 0) + { + + + QAction *copyAction = contextMenu.addAction("Copy"); + connect(copyAction, &QAction::triggered, this, &QHexEdit::copyText); + + QAction *cutAction = contextMenu.addAction("Cut"); + connect(cutAction, &QAction::triggered, this, &QHexEdit::cutText); + + + } + QAction *pasteAction = contextMenu.addAction("Paste"); + connect(pasteAction, &QAction::triggered, this, &QHexEdit::pasteText); + + contextMenu.exec(mapToGlobal(pos)); + } + + +} +void QHexEdit::copyText(){ + QByteArray ba; + if(!_editAreaIsAscii) + { + ba = _chunks->data(getSelectionBegin(), getSelectionEnd() - getSelectionBegin()).toHex(); + for (qint64 idx = 32; idx < ba.size(); idx +=33) + ba.insert(idx, "\n"); + } + else + { + ba = _chunks->data(getSelectionBegin(), getSelectionEnd() - getSelectionBegin()); + for (int i = 0; i < ba.length(); i++) { + if(ba.at(i) < 32 || ba.at(i) > 126) + { + ba[i] = '.'; + } + } + } + + + QClipboard *clipboard = QApplication::clipboard(); + clipboard->setText(ba); +} +void QHexEdit::pasteText(){ + QClipboard *clipboard = QApplication::clipboard(); + QByteArray ba = QByteArray().fromHex(clipboard->text().toLatin1()); + if (_overwriteMode) + { + ba = ba.left(std::min(ba.size(), (_chunks->size() - _bPosCurrent))); + replace(_bPosCurrent, ba.size(), ba); + } + else + insert(_bPosCurrent, ba); + setCursorPosition(_cursorPosition + 2 * ba.size()); + resetSelection(getSelectionBegin()); +} +void QHexEdit::cutText(){ + QByteArray ba = _chunks->data(getSelectionBegin(), getSelectionEnd() - getSelectionBegin()).toHex(); + for (qint64 idx = 32; idx < ba.size(); idx +=33) + ba.insert(idx, "\n"); + QClipboard *clipboard = QApplication::clipboard(); + clipboard->setText(ba); + if (_overwriteMode) + { + qint64 len = getSelectionEnd() - getSelectionBegin(); + replace(getSelectionBegin(), (int)len, QByteArray((int)len, char(0))); + } + else + { + remove(getSelectionBegin(), getSelectionEnd() - getSelectionBegin()); + } + setCursorPosition(2 * getSelectionBegin()); + resetSelection(2 * getSelectionBegin()); +} diff --git a/src/qhexedit.h b/src/qhexedit.h index 53d2903..a883513 100644 --- a/src/qhexedit.h +++ b/src/qhexedit.h @@ -403,6 +403,10 @@ private slots: void dataChangedPrivate(int idx=0); // emit dataChanged() signal void refresh(); // ensureVisible() and readBuffers() void updateCursor(); // update blinking cursor + void showContextMenu(const QPoint &pos); + void copyText(); + void pasteText(); + void cutText(); private: // Name convention: pixel positions start with _px