├── README.md ├── LICENSE ├── dialogdisasm.cpp ├── dialogdisasm.h ├── dialogdisasm.ui ├── xdisasm.pri ├── dialogdisasmlabels.h ├── dialogdisasmprocess.h ├── dialogdisasmlabels.ui ├── dialogasmsignature.h ├── xdisasmmodel.h ├── dialogdisasmprocess.cpp ├── dialogdisasmlabels.cpp ├── xdisasmwidget.h ├── xdisasmwidget.ui ├── xdisasm.h ├── dialogasmsignature.ui ├── dialogasmsignature.cpp ├── xdisasmmodel.cpp ├── dialogdisasmprocess.ui ├── xdisasmwidget.cpp └── xdisasm.cpp /README.md: -------------------------------------------------------------------------------- 1 | # XDisasm 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019-2025 hors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /dialogdisasm.cpp: -------------------------------------------------------------------------------- 1 | // copyright (c) 2020-2025 hors 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | #include "dialogdisasm.h" 22 | 23 | #include "ui_dialogdisasm.h" 24 | 25 | DialogDisasm::DialogDisasm(QWidget *pParent, QIODevice *pDevice, XDisasmModel::SHOWOPTIONS *pShowOptions, XDisasm::OPTIONS *pDisasmOptions) 26 | : QDialog(pParent), ui(new Ui::DialogDisasm) { 27 | ui->setupUi(this); 28 | 29 | setWindowFlags(Qt::Window); 30 | 31 | ui->widgetDisasm->setData(pDevice, pShowOptions, pDisasmOptions, true); 32 | } 33 | 34 | DialogDisasm::~DialogDisasm() { 35 | delete ui; 36 | } 37 | 38 | void DialogDisasm::on_pushButtonClose_clicked() { 39 | this->close(); 40 | } 41 | -------------------------------------------------------------------------------- /dialogdisasm.h: -------------------------------------------------------------------------------- 1 | // copyright (c) 2020-2025 hors 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | #ifndef DIALOGDISASM_H 22 | #define DIALOGDISASM_H 23 | 24 | #include 25 | 26 | #include "xdisasmwidget.h" 27 | 28 | namespace Ui { 29 | class DialogDisasm; 30 | } 31 | 32 | class DialogDisasm : public QDialog { 33 | Q_OBJECT 34 | 35 | public: 36 | explicit DialogDisasm(QWidget *pParent, QIODevice *pDevice, XDisasmModel::SHOWOPTIONS *pShowOptions = 0, XDisasm::OPTIONS *pDisasmOptions = 0); 37 | ~DialogDisasm(); 38 | 39 | private slots: 40 | void on_pushButtonClose_clicked(); 41 | 42 | private: 43 | Ui::DialogDisasm *ui; 44 | }; 45 | 46 | #endif // DIALOGDISASM_H 47 | -------------------------------------------------------------------------------- /dialogdisasm.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | DialogDisasm 4 | 5 | 6 | Qt::ApplicationModal 7 | 8 | 9 | 10 | 0 11 | 0 12 | 763 13 | 599 14 | 15 | 16 | 17 | Disasm 18 | 19 | 20 | true 21 | 22 | 23 | 24 | 25 | 26 | 27 | 0 28 | 0 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | Qt::Horizontal 39 | 40 | 41 | 42 | 40 43 | 20 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | Close 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | XDisasmWidget 62 | QWidget 63 |
xdisasmwidget.h
64 | 1 65 |
66 |
67 | 68 | 69 |
70 | -------------------------------------------------------------------------------- /xdisasm.pri: -------------------------------------------------------------------------------- 1 | INCLUDEPATH += $$PWD 2 | DEPENDPATH += $$PWD 3 | 4 | SOURCES += \ 5 | $$PWD/dialogdisasm.cpp \ 6 | $$PWD/dialogdisasmlabels.cpp \ 7 | $$PWD/dialogdisasmprocess.cpp \ 8 | $$PWD/dialogasmsignature.cpp \ 9 | $$PWD/xdisasm.cpp \ 10 | $$PWD/xdisasmmodel.cpp \ 11 | $$PWD/xdisasmwidget.cpp 12 | 13 | HEADERS += \ 14 | $$PWD/dialogdisasm.h \ 15 | $$PWD/dialogdisasmlabels.h \ 16 | $$PWD/dialogdisasmprocess.h \ 17 | $$PWD/dialogasmsignature.h \ 18 | $$PWD/xdisasm.h \ 19 | $$PWD/xdisasmmodel.h \ 20 | $$PWD/xdisasmwidget.h 21 | 22 | FORMS += \ 23 | $$PWD/dialogdisasm.ui \ 24 | $$PWD/dialogdisasmlabels.ui \ 25 | $$PWD/dialogdisasmprocess.ui \ 26 | $$PWD/dialogasmsignature.ui \ 27 | $$PWD/xdisasmwidget.ui 28 | 29 | !contains(XCONFIG, xcapstone) { 30 | XCONFIG += xcapstone 31 | include($$PWD/../XCapstone/xcapstone.pri) 32 | } 33 | 34 | !contains(XCONFIG, dialoggotoaddress) { 35 | XCONFIG += dialoggotoaddress 36 | include($$PWD/../FormatDialogs/dialoggotoaddress.pri) 37 | } 38 | 39 | !contains(XCONFIG, xlineedithex) { 40 | XCONFIG += xlineedithex 41 | include($$PWD/../Controls/xlineedithex.pri) 42 | } 43 | 44 | !contains(XCONFIG, xformats) { 45 | XCONFIG += xformats 46 | include($$PWD/../Formats/xformats.pri) 47 | } 48 | 49 | !contains(XCONFIG, dialoggotoaddress) { 50 | XCONFIG += dialoggotoaddress 51 | include($$PWD/../FormatDialogs/dialoggotoaddress.pri) 52 | } 53 | 54 | !contains(XCONFIG, dialogdump) { 55 | XCONFIG += dialogdump 56 | include($$PWD/../FormatDialogs/dialogdump.pri) 57 | } 58 | 59 | !contains(XCONFIG, qhexview) { 60 | XCONFIG += qhexview 61 | include($$PWD/../QHexView/qhexview.pri) 62 | } 63 | 64 | !contains(XCONFIG, allformatwidgets) { 65 | XCONFIG += allformatwidgets 66 | include($$PWD/../FormatWidgets/allformatwidgets.pri) 67 | } 68 | 69 | !contains(XCONFIG, xoptions) { 70 | XCONFIG += xoptions 71 | include($$PWD/../XOptions/xoptions.pri) 72 | } 73 | -------------------------------------------------------------------------------- /dialogdisasmlabels.h: -------------------------------------------------------------------------------- 1 | // copyright (c) 2019-2025 hors 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | #ifndef DIALOGDISASMLABELS_H 22 | #define DIALOGDISASMLABELS_H 23 | 24 | #include 25 | #include 26 | 27 | #include "xdisasm.h" 28 | 29 | namespace Ui { 30 | class DialogDisasmLabels; 31 | } 32 | 33 | class DialogDisasmLabels : public QDialog { 34 | Q_OBJECT 35 | 36 | public: 37 | explicit DialogDisasmLabels(QWidget *pParent, XDisasm::STATS *pDisasmStats); 38 | ~DialogDisasmLabels(); 39 | qint64 getAddress(); 40 | 41 | private slots: 42 | void on_pushButtonClose_clicked(); 43 | void on_pushButtonGoTo_clicked(); 44 | void on_tableViewLabels_doubleClicked(const QModelIndex &index); 45 | void goTo(); 46 | 47 | private: 48 | Ui::DialogDisasmLabels *ui; 49 | XDisasm::STATS *g_pDisasmStats; 50 | qint64 g_nAddress; 51 | }; 52 | 53 | #endif // DIALOGDISASMLABELS_H 54 | -------------------------------------------------------------------------------- /dialogdisasmprocess.h: -------------------------------------------------------------------------------- 1 | // copyright (c) 2019-2025 hors 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | #ifndef DIALOGDISASMPROCESS_H 22 | #define DIALOGDISASMPROCESS_H 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include "xdisasm.h" 29 | 30 | namespace Ui { 31 | class DialogDisasmProcess; 32 | } 33 | 34 | class DialogDisasmProcess : public QDialog { 35 | Q_OBJECT 36 | 37 | public: 38 | explicit DialogDisasmProcess(QWidget *pParent = nullptr); 39 | ~DialogDisasmProcess(); 40 | void setData(QIODevice *pDevice, XDisasm::OPTIONS *pOptions, qint64 nStartAddress, XDisasm::DM dm); 41 | 42 | private slots: 43 | void on_pushButtonCancel_clicked(); 44 | void timerSlot(); 45 | 46 | signals: 47 | void errorMessage(QString sText); 48 | 49 | private: 50 | Ui::DialogDisasmProcess *ui; 51 | QThread *g_pThread; 52 | XDisasm *g_pDisasm; 53 | QTimer *g_pTimer; 54 | }; 55 | 56 | #endif // DIALOGDISASMPROCESS_H 57 | -------------------------------------------------------------------------------- /dialogdisasmlabels.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | DialogDisasmLabels 4 | 5 | 6 | Qt::ApplicationModal 7 | 8 | 9 | 10 | 0 11 | 0 12 | 439 13 | 405 14 | 15 | 16 | 17 | Labels 18 | 19 | 20 | true 21 | 22 | 23 | 24 | 25 | 26 | QAbstractItemView::NoEditTriggers 27 | 28 | 29 | QAbstractItemView::SingleSelection 30 | 31 | 32 | QAbstractItemView::SelectRows 33 | 34 | 35 | false 36 | 37 | 38 | 20 39 | 40 | 41 | 20 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | Qt::Horizontal 51 | 52 | 53 | 54 | 40 55 | 20 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | Go to 64 | 65 | 66 | 67 | 68 | 69 | 70 | Close 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /dialogasmsignature.h: -------------------------------------------------------------------------------- 1 | // copyright (c) 2019-2025 hors 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | #ifndef DIALOGASMSIGNATURE_H 22 | #define DIALOGASMSIGNATURE_H 23 | 24 | #include 25 | #include 26 | 27 | #include "xdisasmmodel.h" 28 | #include "xlineedithex.h" 29 | #include "xoptions.h" 30 | 31 | namespace Ui { 32 | class DialogAsmSignature; 33 | } 34 | 35 | class DialogAsmSignature : public QDialog { 36 | Q_OBJECT 37 | 38 | public: 39 | explicit DialogAsmSignature(QWidget *pParent, QIODevice *pDevice, XDisasmModel *pModel, qint64 nAddress); 40 | ~DialogAsmSignature(); 41 | void reload(); 42 | 43 | private slots: 44 | void on_pushButtonOK_clicked(); 45 | void reloadSignature(); 46 | void on_checkBoxSpaces_toggled(bool bChecked); 47 | void on_checkBoxUpper_toggled(bool bChecked); 48 | void on_lineEditWildcard_textChanged(const QString &sText); 49 | void on_pushButtonCopy_clicked(); 50 | QString replaceWild(QString sString, qint32 nOffset, qint32 nSize, QChar cWild); 51 | void on_spinBoxCount_valueChanged(int nValue); 52 | 53 | void on_comboBoxMethod_currentIndexChanged(int nIndex); 54 | 55 | private: 56 | Ui::DialogAsmSignature *ui; 57 | QIODevice *g_pDevice; 58 | XDisasmModel *g_pModel; 59 | qint64 g_nAddress; 60 | QList g_listRecords; 61 | }; 62 | 63 | #endif // DIALOGASMSIGNATURE_H 64 | -------------------------------------------------------------------------------- /xdisasmmodel.h: -------------------------------------------------------------------------------- 1 | // copyright (c) 2019-2025 hors 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | #ifndef XDISASMMODEL_H 22 | #define XDISASMMODEL_H 23 | 24 | #include 25 | #include 26 | 27 | #include "xdisasm.h" 28 | 29 | class XDisasmModel : public QAbstractTableModel { 30 | Q_OBJECT 31 | 32 | public: 33 | enum UD { 34 | UD_ADDRESS = 0, 35 | UD_OFFSET, 36 | UD_RELADDRESS, 37 | UD_SIZE 38 | }; 39 | 40 | enum DMCOLUMN { 41 | DMCOLUMN_ADDRESS = 0, 42 | DMCOLUMN_OFFSET, 43 | DMCOLUMN_LABEL, 44 | DMCOLUMN_BYTES, 45 | DMCOLUMN_OPCODE 46 | }; 47 | 48 | struct VEIW_RECORD { 49 | QString sAddress; 50 | QString sOffset; 51 | QString sLabel; 52 | QString sBytes; 53 | QString sOpcode; 54 | }; 55 | 56 | struct SHOWOPTIONS { 57 | bool bShowLabels; 58 | }; 59 | 60 | explicit XDisasmModel(QIODevice *pDevice, XDisasm::STATS *pStats, SHOWOPTIONS *pShowOptions, QObject *pParent); 61 | ~XDisasmModel(); 62 | // Header: 63 | QVariant headerData(int section, Qt::Orientation orientation, int nRole = Qt::DisplayRole) const override; 64 | // Basic functionality: 65 | int rowCount(const QModelIndex &parent = QModelIndex()) const override; 66 | int columnCount(const QModelIndex &parent = QModelIndex()) const override; 67 | QVariant data(const QModelIndex &index, int nRole = Qt::DisplayRole) const override; 68 | VEIW_RECORD getViewRecord(int nRow); 69 | qint64 getPositionCount() const; 70 | qint64 positionToAddress(qint64 nPosition); 71 | qint64 addressToPosition(qint64 nAddress); 72 | qint64 offsetToPosition(qint64 nOffset); 73 | qint64 relAddressToPosition(qint64 nRelAddress); 74 | XDisasm::STATS *getStats(); 75 | void _beginResetModel(); 76 | void _endResetModel(); 77 | void resetCache(); 78 | bool initDisasm(); 79 | 80 | private: 81 | QIODevice *g_pDevice; 82 | XDisasm::STATS *g_pStats; 83 | SHOWOPTIONS *g_pShowOptions; 84 | 85 | QQueue g_quRecords; 86 | QMap g_mapRecords; 87 | csh g_disasm_handle; 88 | bool g_bDisasmInit; 89 | }; 90 | 91 | #endif // XDISASMMODEL_H 92 | -------------------------------------------------------------------------------- /dialogdisasmprocess.cpp: -------------------------------------------------------------------------------- 1 | // copyright (c) 2019-2025 hors 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | #include "dialogdisasmprocess.h" 22 | 23 | #include "ui_dialogdisasmprocess.h" 24 | 25 | DialogDisasmProcess::DialogDisasmProcess(QWidget *pParent) : QDialog(pParent), ui(new Ui::DialogDisasmProcess) { 26 | ui->setupUi(this); 27 | 28 | g_pDisasm = new XDisasm; 29 | g_pThread = new QThread; 30 | 31 | g_pDisasm->moveToThread(g_pThread); 32 | 33 | connect(g_pDisasm, SIGNAL(processFinished()), this, SLOT(close())); 34 | connect(g_pThread, SIGNAL(started()), g_pDisasm, SLOT(process())); 35 | connect(g_pDisasm, SIGNAL(errorMessage(QString)), this, SIGNAL(errorMessage(QString))); 36 | 37 | g_pTimer = new QTimer(this); 38 | connect(g_pTimer, SIGNAL(timeout()), this, SLOT(timerSlot())); 39 | } 40 | 41 | DialogDisasmProcess::~DialogDisasmProcess() { 42 | g_pTimer->stop(); 43 | delete g_pTimer; 44 | 45 | g_pDisasm->stop(); 46 | 47 | g_pThread->quit(); 48 | g_pThread->wait(); 49 | 50 | delete ui; 51 | 52 | delete g_pThread; 53 | delete g_pDisasm; 54 | } 55 | 56 | void DialogDisasmProcess::setData(QIODevice *pDevice, XDisasm::OPTIONS *pOptions, qint64 nStartAddress, XDisasm::DM dm) { 57 | g_pDisasm->setData(pDevice, pOptions, nStartAddress, dm); 58 | 59 | g_pThread->start(); 60 | g_pTimer->start(1000); 61 | } 62 | 63 | void DialogDisasmProcess::on_pushButtonCancel_clicked() { 64 | g_pDisasm->stop(); 65 | } 66 | 67 | void DialogDisasmProcess::timerSlot() { 68 | // TODO more info 69 | ui->lineEditOpcodes->setText(QString("%1").arg(g_pDisasm->getStats()->mapRecords.count())); 70 | ui->lineEditCalls->setText(QString("%1").arg(g_pDisasm->getStats()->stCalls.count())); 71 | ui->lineEditJumps->setText(QString("%1").arg(g_pDisasm->getStats()->stJumps.count())); 72 | ui->lineEditRefFrom->setText(QString("%1").arg(g_pDisasm->getStats()->mmapRefFrom.count())); 73 | ui->lineEditRefTo->setText(QString("%1").arg(g_pDisasm->getStats()->mmapRefTo.count())); 74 | 75 | ui->lineEditDataLabels->setText(QString("%1").arg(g_pDisasm->getStats()->mmapDataLabels.count())); 76 | ui->lineEditVB->setText(QString("%1").arg(g_pDisasm->getStats()->mapVB.count())); 77 | ui->lineEditStrings->setText(QString("%1").arg(g_pDisasm->getStats()->mapLabelStrings.count())); 78 | ui->lineEditPositions->setText(QString("%1").arg(g_pDisasm->getStats()->mapPositions.count())); 79 | ui->lineEditAddresses->setText(QString("%1").arg(g_pDisasm->getStats()->mapAddresses.count())); 80 | } 81 | -------------------------------------------------------------------------------- /dialogdisasmlabels.cpp: -------------------------------------------------------------------------------- 1 | // copyright (c) 2019-2025 hors 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | #include "dialogdisasmlabels.h" 22 | 23 | #include "ui_dialogdisasmlabels.h" 24 | 25 | DialogDisasmLabels::DialogDisasmLabels(QWidget *pParent, XDisasm::STATS *pDisasmStats) : QDialog(pParent), ui(new Ui::DialogDisasmLabels) { 26 | ui->setupUi(this); 27 | 28 | this->g_pDisasmStats = pDisasmStats; 29 | g_nAddress = 0; 30 | 31 | int nNumberOfLabels = pDisasmStats->mapLabelStrings.count(); 32 | 33 | QStandardItemModel *pModel = new QStandardItemModel(nNumberOfLabels, 2, this); 34 | 35 | pModel->setHeaderData(0, Qt::Horizontal, tr("Name")); 36 | pModel->setHeaderData(1, Qt::Horizontal, tr("Address")); 37 | 38 | int i = 0; 39 | QMapIterator iMap(pDisasmStats->mapLabelStrings); 40 | while (iMap.hasNext()) { 41 | iMap.next(); 42 | 43 | QString sName = iMap.value(); 44 | qint64 nAddress = iMap.key(); 45 | 46 | QStandardItem *pItemName = new QStandardItem; 47 | pItemName->setText(sName); 48 | pItemName->setData(nAddress); 49 | pModel->setItem(i, 0, pItemName); 50 | 51 | QStandardItem *pItemAddress = new QStandardItem; 52 | pItemAddress->setText(QString("0x%1").arg(nAddress, 8, 16, QChar('0'))); // TODO function in Binary 53 | pModel->setItem(i, 1, pItemAddress); 54 | 55 | i++; 56 | } 57 | 58 | ui->tableViewLabels->setModel(pModel); 59 | 60 | ui->tableViewLabels->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); 61 | ui->tableViewLabels->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Interactive); 62 | 63 | ui->pushButtonGoTo->setEnabled(nNumberOfLabels); 64 | 65 | if (nNumberOfLabels) { 66 | ui->tableViewLabels->setCurrentIndex(pModel->index(0, 0)); 67 | } 68 | } 69 | 70 | DialogDisasmLabels::~DialogDisasmLabels() { 71 | delete ui; 72 | } 73 | 74 | qint64 DialogDisasmLabels::getAddress() { 75 | return g_nAddress; 76 | } 77 | 78 | void DialogDisasmLabels::on_pushButtonClose_clicked() { 79 | done(QDialog::Rejected); 80 | } 81 | 82 | void DialogDisasmLabels::on_pushButtonGoTo_clicked() { 83 | goTo(); 84 | } 85 | 86 | void DialogDisasmLabels::on_tableViewLabels_doubleClicked(const QModelIndex &index) { 87 | Q_UNUSED(index) 88 | 89 | goTo(); 90 | } 91 | 92 | void DialogDisasmLabels::goTo() { 93 | QItemSelectionModel *pSelectionModel = ui->tableViewLabels->selectionModel(); 94 | 95 | if (pSelectionModel) { 96 | QModelIndexList listIndexes = pSelectionModel->selectedRows(0); 97 | 98 | if (listIndexes.count()) { 99 | g_nAddress = listIndexes.at(0).data(Qt::UserRole + 1).toLongLong(); 100 | 101 | done(QDialog::Accepted); 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /xdisasmwidget.h: -------------------------------------------------------------------------------- 1 | // copyright (c) 2019-2025 hors 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | #ifndef FORMDISASM_H 22 | #define FORMDISASM_H 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "dialogasmsignature.h" 31 | #include "dialogdisasmlabels.h" 32 | #include "dialogdisasmprocess.h" 33 | #include "dialogdumpprocess.h" 34 | #include "dialoggotoaddress.h" 35 | #include "dialoghex.h" 36 | #include "dialoghexsignature.h" 37 | #include "xdisasmmodel.h" 38 | #include "xlineedithex.h" 39 | #include "xoptions.h" 40 | #include "xshortcuts.h" 41 | 42 | namespace Ui { 43 | class XDisasmWidget; 44 | } 45 | 46 | class XDisasmWidget : public QWidget { 47 | Q_OBJECT 48 | 49 | struct SELECTION_STAT { 50 | qint64 nAddress; 51 | qint64 nOffset; 52 | qint64 nRelAddress; 53 | qint64 nSize; 54 | qint32 nCount; 55 | }; 56 | 57 | public: 58 | explicit XDisasmWidget(QWidget *pParent = nullptr); 59 | void setData(QIODevice *pDevice, XDisasmModel::SHOWOPTIONS *pShowOptions = 0, XDisasm::OPTIONS *pDisasmOptions = 0, bool bAuto = true); 60 | void analyze(); 61 | void goToAddress(qint64 nAddress); 62 | void goToOffset(qint64 nOffset); 63 | void goToRelAddress(qint64 nRelAddress); 64 | void goToDisasmAddress(qint64 nAddress); 65 | void goToEntryPoint(); 66 | void disasm(qint64 nAddress); 67 | void toData(qint64 nAddress, qint64 nSize); 68 | void signature(qint64 nAddress, qint64 nSize); 69 | void hex(qint64 nOffset); 70 | void clear(); 71 | ~XDisasmWidget(); 72 | void process(QIODevice *pDevice, XDisasm::OPTIONS *pOptions, qint64 nStartAddress, XDisasm::DM dm); 73 | XDisasm::STATS *getDisasmStats(); 74 | void setBackupFileName(QString sBackupFileName); 75 | 76 | private slots: 77 | void on_pushButtonLabels_clicked(); 78 | void on_tableViewDisasm_customContextMenuRequested(const QPoint &pos); 79 | void _goToAddress(); 80 | void _goToRelAddress(); 81 | void _goToOffset(); 82 | void _goToEntryPoint(); 83 | void _copyAddress(); 84 | void _copyOffset(); 85 | void _copyRelAddress(); 86 | void _dumpToFile(); 87 | void _disasm(); 88 | void _toData(); 89 | void _signature(); 90 | void _hex(); 91 | SELECTION_STAT getSelectionStat(); 92 | void on_pushButtonAnalyze_clicked(); 93 | void _goToPosition(qint32 nPosition); 94 | void on_pushButtonOverlay_clicked(); 95 | void setEdited(bool bState); 96 | void on_pushButtonHex_clicked(); 97 | void errorMessage(QString sText); 98 | 99 | private: 100 | Ui::XDisasmWidget *ui; 101 | QIODevice *g_pDevice; 102 | XDisasmModel::SHOWOPTIONS *g_pShowOptions; 103 | XDisasm::OPTIONS *g_pDisasmOptions; 104 | XDisasmModel *g_pModel; 105 | XDisasmModel::SHOWOPTIONS g_showOptions; 106 | XDisasm::OPTIONS g_disasmOptions; 107 | QString g_sBackupFileName; // TODO save backup 108 | }; 109 | 110 | #endif // FORMDISASM_H 111 | -------------------------------------------------------------------------------- /xdisasmwidget.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | XDisasmWidget 4 | 5 | 6 | 7 | 0 8 | 0 9 | 833 10 | 639 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 0 19 | 20 | 21 | 0 22 | 23 | 24 | 0 25 | 26 | 27 | 0 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 120 36 | 0 37 | 38 | 39 | 40 | Type 41 | 42 | 43 | 44 | 0 45 | 46 | 47 | 0 48 | 49 | 50 | 0 51 | 52 | 53 | 0 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | Analyze 65 | 66 | 67 | 68 | 69 | 70 | 71 | Labels 72 | 73 | 74 | 75 | 76 | 77 | 78 | Hex 79 | 80 | 81 | 82 | 83 | 84 | 85 | Overlay 86 | 87 | 88 | 89 | 90 | 91 | 92 | Qt::Horizontal 93 | 94 | 95 | 96 | 40 97 | 20 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 0 109 | 0 110 | 111 | 112 | 113 | Qt::CustomContextMenu 114 | 115 | 116 | QAbstractItemView::NoEditTriggers 117 | 118 | 119 | QAbstractItemView::ContiguousSelection 120 | 121 | 122 | QAbstractItemView::SelectRows 123 | 124 | 125 | 20 126 | 127 | 128 | 20 129 | 130 | 131 | false 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /xdisasm.h: -------------------------------------------------------------------------------- 1 | // copyright (c) 2019-2025 hors 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | #ifndef XDISASM_H 22 | #define XDISASM_H 23 | 24 | #include "capstone/capstone.h" 25 | #include "xformats.h" 26 | 27 | class XDisasm : public QObject { 28 | Q_OBJECT 29 | 30 | static const int N_X64_OPCODE_SIZE = 15; 31 | static const int N_OPCODE_COUNT = 100000; 32 | 33 | public: 34 | enum DM { 35 | DM_UNKNOWN = 0, 36 | DM_DISASM, 37 | DM_TODATA 38 | }; 39 | 40 | enum VBT { 41 | VBT_UNKNOWN = 0, 42 | VBT_OPCODE, 43 | VBT_DATA, 44 | VBT_DATABLOCK 45 | }; 46 | 47 | enum RECORD_TYPE { 48 | RECORD_TYPE_UNKNOWN = 0, 49 | RECORD_TYPE_OPCODE, 50 | RECORD_TYPE_DATA, 51 | }; 52 | 53 | struct RECORD { 54 | qint64 nOffset; 55 | qint64 nSize; 56 | RECORD_TYPE type; 57 | }; 58 | 59 | // enum LABEL_TYPE 60 | // { 61 | // LABEL_TYPE_UNKNOWN=0; 62 | // LABEL_TYPE_ 63 | // }; 64 | 65 | struct LABEL { 66 | qint64 nName; 67 | }; 68 | 69 | struct VIEW_BLOCK { 70 | qint64 nAddress; 71 | qint64 nOffset; 72 | qint64 nSize; 73 | VBT type; 74 | }; 75 | 76 | struct STATS { 77 | bool bInit; 78 | XBinary::_MEMORY_MAP memoryMap; 79 | cs_arch csarch; 80 | cs_mode csmode; 81 | qint64 nImageBase; 82 | qint64 nImageSize; 83 | qint64 nEntryPointAddress; 84 | QMap mapRecords; 85 | QMultiMap mmapRefTo; 86 | QMultiMap mmapRefFrom; 87 | QSet stCalls; 88 | QSet stJumps; 89 | QMultiMap mmapDataLabels; // TODO Check 90 | QMap mapVB; 91 | QMap mapLabelStrings; 92 | qint64 nPositions; 93 | QMap mapPositions; 94 | QMap mapAddresses; 95 | bool bIsOverlayPresent; 96 | qint64 nOverlayOffset; 97 | qint64 nOverlaySize; 98 | }; 99 | 100 | struct OPTIONS { 101 | bool bIsImage; 102 | qint64 nImageBase; 103 | XBinary::FT fileType; 104 | XDisasm::STATS stats; 105 | }; 106 | 107 | explicit XDisasm(QObject *pParent = nullptr); 108 | ~XDisasm(); 109 | void setData(QIODevice *pDevice, OPTIONS *pOptions, qint64 nStartAddress, DM dm); 110 | void stop(); 111 | STATS *getStats(); 112 | static qint64 getVBSize(QMap *pMapVB); 113 | static QString getDisasmString(csh disasm_handle, qint64 nAddress, char *pData, qint32 nDataSize); 114 | 115 | enum SM { 116 | SM_NORMAL = 0, 117 | SM_RELATIVEADDRESS 118 | }; 119 | 120 | struct SIGNATURE_OPTIONS { 121 | QIODevice *pDevice; 122 | XBinary::_MEMORY_MAP memoryMap; 123 | cs_arch csarch; 124 | cs_mode csmode; 125 | int nCount; 126 | SM sm; 127 | }; 128 | 129 | struct SIGNATURE_RECORD { 130 | qint64 nAddress; 131 | QString sOpcode; 132 | QByteArray baOpcode; 133 | qint32 nDispOffset; 134 | qint32 nDispSize; 135 | qint32 nImmOffset; 136 | qint32 nImmSize; 137 | bool bIsConst; 138 | }; 139 | 140 | static QList getSignature(SIGNATURE_OPTIONS *pSignatureOptions, qint64 nAddress); 141 | 142 | public slots: 143 | void processDisasm(); 144 | void processToData(); 145 | void process(); 146 | 147 | private: 148 | bool isEndBranchOpcode(uint nOpcodeID); 149 | static bool isJmpOpcode(uint nOpcodeID); 150 | static bool isCallOpcode(uint nOpcodeID); 151 | void _disasm(qint64 nInitAddress, qint64 nAddress); 152 | void _adjust(); 153 | void _updatePositions(); 154 | bool _insertOpcode(qint64 nAddress, RECORD *pOpcode); 155 | 156 | signals: 157 | void errorMessage(QString sText); 158 | void processFinished(); 159 | 160 | private: 161 | DM g_dm; 162 | csh g_disasm_handle; 163 | bool g_bStop; 164 | QIODevice *g_pDevice; 165 | OPTIONS *g_pOptions; 166 | qint64 g_nStartAddress; 167 | }; 168 | 169 | #endif // XDISASM_H 170 | -------------------------------------------------------------------------------- /dialogasmsignature.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | DialogAsmSignature 4 | 5 | 6 | Qt::ApplicationModal 7 | 8 | 9 | 10 | 0 11 | 0 12 | 709 13 | 450 14 | 15 | 16 | 17 | Signature 18 | 19 | 20 | true 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 1 29 | 30 | 31 | 20 32 | 33 | 34 | 8 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 200 43 | 0 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | Qt::Horizontal 52 | 53 | 54 | 55 | 40 56 | 20 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | QAbstractItemView::NoEditTriggers 67 | 68 | 69 | QAbstractItemView::SingleSelection 70 | 71 | 72 | QAbstractItemView::SelectRows 73 | 74 | 75 | false 76 | 77 | 78 | false 79 | 80 | 81 | 20 82 | 83 | 84 | 20 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 16777215 93 | 100 94 | 95 | 96 | 97 | true 98 | 99 | 100 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> 101 | <html><head><meta name="qrichtext" content="1" /><style type="text/css"> 102 | p, li { white-space: pre-wrap; } 103 | </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> 104 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | Spaces 114 | 115 | 116 | 117 | 118 | 119 | 120 | Upper 121 | 122 | 123 | true 124 | 125 | 126 | 127 | 128 | 129 | 130 | Wildcard 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 20 139 | 16777215 140 | 141 | 142 | 143 | . 144 | 145 | 146 | 1 147 | 148 | 149 | Qt::AlignCenter 150 | 151 | 152 | 153 | 154 | 155 | 156 | Qt::Horizontal 157 | 158 | 159 | 160 | 40 161 | 20 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | Copy 170 | 171 | 172 | 173 | 174 | 175 | 176 | OK 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | -------------------------------------------------------------------------------- /dialogasmsignature.cpp: -------------------------------------------------------------------------------- 1 | // copyright (c) 2019-2025 hors 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | #include "dialogasmsignature.h" 22 | 23 | #include "ui_dialogasmsignature.h" 24 | 25 | DialogAsmSignature::DialogAsmSignature(QWidget *pParent, QIODevice *pDevice, XDisasmModel *pModel, qint64 nAddress) 26 | : QDialog(pParent), ui(new Ui::DialogAsmSignature) { 27 | ui->setupUi(this); 28 | 29 | this->g_pDevice = pDevice; 30 | this->g_pModel = pModel; 31 | this->g_nAddress = nAddress; 32 | 33 | // XOptions::setMonoFont(ui->tableWidgetSignature); 34 | XOptions::setMonoFont(ui->textEditSignature); 35 | 36 | QSignalBlocker signalBlocker1(ui->spinBoxCount); 37 | QSignalBlocker signalBlocke2r(ui->comboBoxMethod); 38 | 39 | ui->comboBoxMethod->addItem("", XDisasm::SM_NORMAL); 40 | ui->comboBoxMethod->addItem(tr("Relative virtual address"), XDisasm::SM_RELATIVEADDRESS); 41 | 42 | reload(); 43 | } 44 | 45 | DialogAsmSignature::~DialogAsmSignature() { 46 | delete ui; 47 | } 48 | 49 | void DialogAsmSignature::reload() { 50 | XDisasm::SIGNATURE_OPTIONS options = {}; 51 | 52 | options.csarch = g_pModel->getStats()->csarch; 53 | options.csmode = g_pModel->getStats()->csmode; 54 | options.memoryMap = g_pModel->getStats()->memoryMap; 55 | options.pDevice = g_pDevice; 56 | options.nCount = ui->spinBoxCount->value(); 57 | options.sm = (XDisasm::SM)(ui->comboBoxMethod->currentData().toInt()); 58 | 59 | g_listRecords = XDisasm::getSignature(&options, g_nAddress); 60 | 61 | int nSymbolWidth = XLineEditHEX::getSymbolWidth(ui->tableWidgetSignature); 62 | 63 | int nNumberOfRecords = g_listRecords.count(); 64 | 65 | ui->tableWidgetSignature->clear(); 66 | 67 | ui->tableWidgetSignature->setColumnCount(5); 68 | ui->tableWidgetSignature->setRowCount(nNumberOfRecords); 69 | 70 | QStringList listHeaders; 71 | listHeaders.append(tr("Address")); 72 | listHeaders.append(tr("Bytes")); 73 | listHeaders.append(tr("Opcode")); 74 | listHeaders.append(tr("")); 75 | listHeaders.append(tr("")); 76 | 77 | ui->tableWidgetSignature->setHorizontalHeaderLabels(listHeaders); 78 | 79 | for (int i = 0; i < nNumberOfRecords; i++) { 80 | ui->tableWidgetSignature->setItem(i, 0, new QTableWidgetItem(XBinary::valueToHex(g_pModel->getStats()->memoryMap.mode, g_listRecords.at(i).nAddress))); 81 | ui->tableWidgetSignature->setItem(i, 1, new QTableWidgetItem(g_listRecords.at(i).baOpcode.toHex().data())); 82 | 83 | if (!g_listRecords.at(i).bIsConst) { 84 | QPushButton *pUseSignatureButton = new QPushButton(this); 85 | pUseSignatureButton->setText(g_listRecords.at(i).sOpcode); 86 | pUseSignatureButton->setCheckable(true); 87 | connect(pUseSignatureButton, SIGNAL(clicked()), this, SLOT(reloadSignature())); 88 | 89 | ui->tableWidgetSignature->setCellWidget(i, 2, pUseSignatureButton); 90 | 91 | if (g_listRecords.at(i).nDispSize) { 92 | QPushButton *pDispButton = new QPushButton(this); 93 | pDispButton->setText(QString("d")); 94 | pDispButton->setCheckable(true); 95 | pDispButton->setMaximumWidth(nSymbolWidth * 6); 96 | connect(pDispButton, SIGNAL(clicked()), this, SLOT(reloadSignature())); 97 | 98 | ui->tableWidgetSignature->setCellWidget(i, 3, pDispButton); 99 | } 100 | 101 | if (g_listRecords.at(i).nImmSize) { 102 | QPushButton *pImmButton = new QPushButton(this); 103 | pImmButton->setText(QString("i")); 104 | pImmButton->setCheckable(true); 105 | pImmButton->setMaximumWidth(nSymbolWidth * 6); 106 | connect(pImmButton, SIGNAL(clicked()), this, SLOT(reloadSignature())); 107 | 108 | ui->tableWidgetSignature->setCellWidget(i, 4, pImmButton); 109 | } 110 | } else { 111 | ui->tableWidgetSignature->setItem(i, 2, new QTableWidgetItem(g_listRecords.at(i).sOpcode)); 112 | } 113 | } 114 | 115 | ui->tableWidgetSignature->setColumnWidth(0, nSymbolWidth * 12); 116 | ui->tableWidgetSignature->setColumnWidth(1, nSymbolWidth * 8); 117 | ui->tableWidgetSignature->setColumnWidth(2, nSymbolWidth * 20); 118 | ui->tableWidgetSignature->setColumnWidth(3, nSymbolWidth * 6); 119 | ui->tableWidgetSignature->setColumnWidth(4, nSymbolWidth * 6); 120 | 121 | ui->tableWidgetSignature->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Interactive); 122 | ui->tableWidgetSignature->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch); 123 | ui->tableWidgetSignature->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Interactive); 124 | ui->tableWidgetSignature->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Interactive); 125 | ui->tableWidgetSignature->horizontalHeader()->setSectionResizeMode(4, QHeaderView::Interactive); 126 | 127 | reloadSignature(); 128 | } 129 | 130 | void DialogAsmSignature::reloadSignature() { 131 | QString sText; 132 | 133 | QChar cWild = QChar('.'); 134 | QString _sWild = ui->lineEditWildcard->text(); 135 | 136 | if (_sWild.size()) { 137 | cWild = _sWild.at(0); 138 | } 139 | 140 | int nNumberOfRecords = g_listRecords.count(); 141 | 142 | for (int i = 0; i < nNumberOfRecords; i++) { 143 | bool bUse = true; 144 | bool bDisp = true; 145 | bool bImm = true; 146 | 147 | QPushButton *pUseSignatureButton = dynamic_cast(ui->tableWidgetSignature->cellWidget(i, 2)); 148 | QPushButton *pDispButton = dynamic_cast(ui->tableWidgetSignature->cellWidget(i, 3)); 149 | QPushButton *pImmButton = dynamic_cast(ui->tableWidgetSignature->cellWidget(i, 4)); 150 | 151 | if (pUseSignatureButton) { 152 | bUse = !(pUseSignatureButton->isChecked()); 153 | } 154 | 155 | if (pDispButton) { 156 | pDispButton->setEnabled(bUse); 157 | bDisp = !(pDispButton->isChecked()); 158 | } 159 | 160 | if (pImmButton) { 161 | pImmButton->setEnabled(bUse); 162 | bImm = !(pImmButton->isChecked()); 163 | } 164 | 165 | int nSize = g_listRecords.at(i).baOpcode.size(); 166 | 167 | QString sRecord; 168 | 169 | if (bUse) { 170 | sRecord = g_listRecords.at(i).baOpcode.toHex().data(); 171 | 172 | if (!bDisp) { 173 | sRecord = replaceWild(sRecord, g_listRecords.at(i).nDispOffset, g_listRecords.at(i).nDispSize, cWild); 174 | } 175 | 176 | if (!bImm) { 177 | sRecord = replaceWild(sRecord, g_listRecords.at(i).nImmOffset, g_listRecords.at(i).nImmSize, cWild); 178 | } 179 | 180 | if (g_listRecords.at(i).bIsConst) { 181 | sRecord = replaceWild(sRecord, g_listRecords.at(i).nImmOffset, g_listRecords.at(i).nImmSize, QChar('$')); 182 | } 183 | } else { 184 | for (int j = 0; j < nSize; j++) { 185 | sRecord += cWild; 186 | sRecord += cWild; 187 | } 188 | } 189 | 190 | sText += sRecord; 191 | } 192 | 193 | if (ui->checkBoxUpper->isChecked()) { 194 | sText = sText.toUpper(); 195 | } else { 196 | sText = sText.toLower(); 197 | } 198 | 199 | if (ui->checkBoxSpaces->isChecked()) { 200 | QString _sText; 201 | 202 | int nSize = sText.size(); 203 | 204 | for (int i = 0; i < nSize; i++) { 205 | _sText += sText.at(i); 206 | 207 | if ((i % 2) && (i != (nSize - 1))) { 208 | _sText += QChar(' '); 209 | } 210 | } 211 | 212 | sText = _sText; 213 | } 214 | 215 | ui->textEditSignature->setText(sText); 216 | } 217 | 218 | void DialogAsmSignature::on_pushButtonOK_clicked() { 219 | this->close(); 220 | } 221 | 222 | void DialogAsmSignature::on_checkBoxSpaces_toggled(bool bChecked) { 223 | reloadSignature(); 224 | } 225 | 226 | void DialogAsmSignature::on_checkBoxUpper_toggled(bool bChecked) { 227 | reloadSignature(); 228 | } 229 | 230 | void DialogAsmSignature::on_lineEditWildcard_textChanged(const QString &sText) { 231 | reloadSignature(); 232 | } 233 | 234 | void DialogAsmSignature::on_pushButtonCopy_clicked() { 235 | QClipboard *clipboard = QApplication::clipboard(); 236 | clipboard->setText(ui->textEditSignature->toPlainText()); 237 | } 238 | 239 | QString DialogAsmSignature::replaceWild(QString sString, qint32 nOffset, qint32 nSize, QChar cWild) { 240 | QString sResult = sString; 241 | QString sWild; 242 | 243 | sWild = sWild.fill(cWild, nSize * 2); 244 | 245 | sResult = sResult.replace(nOffset * 2, nSize * 2, sWild); 246 | 247 | return sResult; 248 | } 249 | 250 | void DialogAsmSignature::on_spinBoxCount_valueChanged(int nValue) { 251 | Q_UNUSED(nValue) 252 | 253 | reload(); 254 | } 255 | 256 | void DialogAsmSignature::on_comboBoxMethod_currentIndexChanged(int nIndex) { 257 | Q_UNUSED(nIndex) 258 | 259 | reload(); 260 | } 261 | -------------------------------------------------------------------------------- /xdisasmmodel.cpp: -------------------------------------------------------------------------------- 1 | // copyright (c) 2019-2025 hors 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | #include "xdisasmmodel.h" 22 | 23 | XDisasmModel::XDisasmModel(QIODevice *pDevice, XDisasm::STATS *pStats, SHOWOPTIONS *pShowOptions, QObject *pParent) : QAbstractTableModel(pParent) { 24 | this->g_pDevice = pDevice; 25 | this->g_pStats = pStats; 26 | this->g_pShowOptions = pShowOptions; 27 | 28 | g_bDisasmInit = false; 29 | } 30 | 31 | XDisasmModel::~XDisasmModel() { 32 | if (g_bDisasmInit) { 33 | cs_close(&g_disasm_handle); 34 | } 35 | } 36 | 37 | QVariant XDisasmModel::headerData(int section, Qt::Orientation orientation, int nRole) const { 38 | QVariant result; 39 | 40 | if (orientation == Qt::Horizontal) { 41 | if (nRole == Qt::DisplayRole) { 42 | switch (section) { 43 | case DMCOLUMN_ADDRESS: 44 | result = tr("Address"); 45 | break; 46 | case DMCOLUMN_OFFSET: 47 | result = tr("Offset"); 48 | break; 49 | case DMCOLUMN_LABEL: 50 | result = tr("Label"); 51 | break; 52 | case DMCOLUMN_BYTES: 53 | result = tr("Bytes"); 54 | break; 55 | case DMCOLUMN_OPCODE: 56 | result = tr("Opcode"); 57 | break; 58 | } 59 | } 60 | } 61 | 62 | return result; 63 | } 64 | 65 | int XDisasmModel::rowCount(const QModelIndex &parent) const { 66 | if (parent.isValid()) { 67 | return 0; 68 | } 69 | 70 | // return XBinary::getTotalVirtualSize(&(pStats->listMM)); 71 | // return pStats->mapVB.count(); 72 | return getPositionCount(); 73 | } 74 | 75 | int XDisasmModel::columnCount(const QModelIndex &parent) const { 76 | int nResult = 5; // TODO Def 77 | 78 | if (parent.isValid()) { 79 | nResult = 0; 80 | } 81 | 82 | return nResult; 83 | } 84 | 85 | QVariant XDisasmModel::data(const QModelIndex &index, int nRole) const { 86 | if (!index.isValid()) // TODO optimize 87 | { 88 | return QVariant(); 89 | } 90 | 91 | QVariant result; 92 | 93 | if (nRole == Qt::DisplayRole) { 94 | XDisasmModel *_this = const_cast(this); 95 | 96 | VEIW_RECORD vrRecord = {}; 97 | 98 | int nRow = index.row(); 99 | 100 | if (_this->g_quRecords.contains(nRow)) { 101 | vrRecord = _this->g_mapRecords.value(nRow); 102 | } else { 103 | vrRecord = _this->getViewRecord(nRow); 104 | 105 | _this->g_quRecords.enqueue(nRow); 106 | _this->g_mapRecords.insert(nRow, vrRecord); 107 | 108 | if (_this->g_quRecords.count() > 1000) // TODO const 109 | { 110 | qint64 _nPos = _this->g_quRecords.dequeue(); 111 | _this->g_mapRecords.remove(_nPos); 112 | } 113 | } 114 | 115 | int nColumn = index.column(); 116 | 117 | switch (nColumn) { 118 | case DMCOLUMN_ADDRESS: 119 | result = vrRecord.sAddress; 120 | break; 121 | case DMCOLUMN_OFFSET: 122 | result = vrRecord.sOffset; 123 | break; 124 | case DMCOLUMN_LABEL: 125 | result = vrRecord.sLabel; 126 | break; 127 | case DMCOLUMN_BYTES: 128 | result = vrRecord.sBytes; 129 | break; 130 | case DMCOLUMN_OPCODE: 131 | result = vrRecord.sOpcode; 132 | break; 133 | } 134 | } else if (nRole == Qt::UserRole + UD_ADDRESS) { 135 | XDisasmModel *_this = const_cast(this); 136 | 137 | int nRow = index.row(); 138 | 139 | result = _this->positionToAddress(nRow); 140 | } else if (nRole == Qt::UserRole + UD_OFFSET) { 141 | XDisasmModel *_this = const_cast(this); 142 | 143 | int nRow = index.row(); 144 | 145 | qint64 nAddress = _this->positionToAddress(nRow); 146 | 147 | result = XBinary::addressToOffset(&(g_pStats->memoryMap), nAddress); 148 | } else if (nRole == Qt::UserRole + UD_RELADDRESS) { 149 | XDisasmModel *_this = const_cast(this); 150 | 151 | int nRow = index.row(); 152 | 153 | qint64 nAddress = _this->positionToAddress(nRow); 154 | 155 | result = XBinary::addressToRelAddress(&(g_pStats->memoryMap), nAddress); 156 | } else if (nRole == Qt::UserRole + UD_SIZE) { 157 | result = 1; 158 | 159 | XDisasmModel *_this = const_cast(this); 160 | 161 | int nRow = index.row(); 162 | 163 | qint64 nAddress = _this->positionToAddress(nRow); 164 | 165 | if (g_pStats->mapVB.contains(nAddress)) { 166 | result = g_pStats->mapVB.value(nAddress).nSize; 167 | } 168 | } 169 | 170 | return result; 171 | } 172 | 173 | XDisasmModel::VEIW_RECORD XDisasmModel::getViewRecord(int nRow) { 174 | VEIW_RECORD result = {0}; 175 | 176 | qint64 nAddress = positionToAddress(nRow); 177 | 178 | qint64 nOffset = XBinary::addressToOffset(&(g_pStats->memoryMap), nAddress); 179 | 180 | qint64 nSize = 1; 181 | 182 | // TODO check 183 | if (nAddress > 0xFFFFFFFF) { 184 | result.sAddress = XBinary::valueToHex((quint64)nAddress); 185 | } else { 186 | result.sAddress = XBinary::valueToHex((quint32)nAddress); 187 | } 188 | 189 | if (nOffset != -1) { 190 | result.sOffset = XBinary::valueToHex((quint32)nOffset); 191 | } 192 | 193 | if (g_pStats->mapVB.contains(nAddress)) { 194 | nSize = g_pStats->mapVB.value(nAddress).nSize; 195 | } 196 | 197 | QByteArray baData; 198 | 199 | if (nOffset != -1) { 200 | if (g_pDevice->seek(nOffset)) { 201 | baData = g_pDevice->read(nSize); 202 | result.sBytes = baData.toHex(); 203 | } 204 | } else { 205 | result.sBytes = QString("byte 0x%1 dup(?)").arg(nSize, 0, 16); 206 | } 207 | 208 | if (g_pStats->mapVB.value(nAddress).type == XDisasm::VBT_OPCODE) { 209 | // result.sOpcode=pStats->mapOpcodes.value(nAddress).sString; 210 | if (!g_bDisasmInit) { 211 | g_bDisasmInit = initDisasm(); 212 | } 213 | 214 | result.sOpcode = XDisasm::getDisasmString(g_disasm_handle, nAddress, baData.data(), baData.size()); 215 | 216 | if (g_pShowOptions->bShowLabels) { 217 | if (g_pStats->mmapRefTo.contains(nAddress)) { 218 | QList listRefs = g_pStats->mmapRefTo.values(nAddress); 219 | 220 | int nNumberOfRefs = listRefs.count(); 221 | 222 | for (int i = 0; i < nNumberOfRefs; i++) { 223 | QString sAddress = QString("0x%1").arg(listRefs.at(i), 0, 16); 224 | QString sRString = g_pStats->mapLabelStrings.value(listRefs.at(i)); 225 | result.sOpcode = result.sOpcode.replace(sAddress, sRString); 226 | } 227 | } 228 | } 229 | } 230 | 231 | result.sLabel = g_pStats->mapLabelStrings.value(nAddress); 232 | 233 | return result; 234 | } 235 | 236 | qint64 XDisasmModel::getPositionCount() const { 237 | return g_pStats->nPositions; 238 | } 239 | 240 | qint64 XDisasmModel::positionToAddress(qint64 nPosition) { 241 | qint64 nResult = 0; 242 | 243 | if (g_pStats->mapPositions.count()) { 244 | nResult = g_pStats->mapPositions.value(nPosition, -1); 245 | 246 | if (nResult == -1) { 247 | QMap::const_iterator iter = g_pStats->mapPositions.lowerBound(nPosition); 248 | 249 | if (iter != g_pStats->mapPositions.end()) { 250 | qint64 nDelta = iter.key() - nPosition; 251 | 252 | nResult = iter.value() - nDelta; 253 | } else { 254 | qint64 nLastPosition = g_pStats->mapPositions.lastKey(); 255 | qint64 nDelta = nPosition - nLastPosition; 256 | 257 | nResult = g_pStats->mapPositions.value(nLastPosition); 258 | nResult += g_pStats->mapVB.value(nResult).nSize; 259 | 260 | if (nDelta > 1) { 261 | nResult += (nDelta - 1); 262 | } 263 | } 264 | } 265 | } 266 | 267 | return nResult; 268 | } 269 | 270 | qint64 XDisasmModel::addressToPosition(qint64 nAddress) { 271 | qint64 nResult = 0; 272 | 273 | if (g_pStats) { 274 | if (g_pStats->mapPositions.count()) { 275 | nResult = g_pStats->mapAddresses.value(nAddress, -1); 276 | 277 | if (nResult == -1) { 278 | QMap::iterator iter = g_pStats->mapAddresses.lowerBound(nAddress); 279 | 280 | if ((iter != g_pStats->mapAddresses.end()) && (iter != g_pStats->mapAddresses.begin())) { 281 | iter--; 282 | qint64 nPosition = iter.value(); 283 | 284 | qint64 nKeyAddress = g_pStats->mapAddresses.key(nPosition); 285 | 286 | XDisasm::VIEW_BLOCK vb = g_pStats->mapVB.value(nKeyAddress); 287 | 288 | if (vb.nSize) { 289 | if ((vb.nAddress <= nAddress) && (nAddress < (vb.nAddress + vb.nSize))) { 290 | nResult = nPosition; 291 | } 292 | } 293 | } 294 | } 295 | 296 | if (nResult == -1) { 297 | QMap::const_iterator iterEnd = g_pStats->mapAddresses.lowerBound(nAddress); 298 | 299 | if (iterEnd != g_pStats->mapAddresses.end()) { 300 | qint64 nKeyAddress = iterEnd.key(); 301 | qint64 nPosition = iterEnd.value(); 302 | 303 | qint64 nDelta = nKeyAddress - nAddress; 304 | 305 | nResult = nPosition - nDelta; 306 | } else { 307 | qint64 nLastAddress = g_pStats->mapAddresses.lastKey(); 308 | nResult = g_pStats->mapAddresses.value(nLastAddress); 309 | nResult++; 310 | 311 | qint64 nDelta = nAddress - (nLastAddress + g_pStats->mapVB.value(nLastAddress).nSize); 312 | 313 | if (nDelta > 0) { 314 | nResult += (nDelta); 315 | } 316 | } 317 | } 318 | } 319 | 320 | if (nResult < 0) // TODO Check 321 | { 322 | nResult = 0; 323 | } 324 | } 325 | 326 | return nResult; 327 | } 328 | 329 | qint64 XDisasmModel::offsetToPosition(qint64 nOffset) { 330 | qint64 nResult = 0; 331 | 332 | qint64 nAddress = XBinary::offsetToAddress(&(g_pStats->memoryMap), nOffset); 333 | 334 | if (nAddress != -1) { 335 | nResult = addressToPosition(nAddress); 336 | } 337 | 338 | return nResult; 339 | } 340 | 341 | qint64 XDisasmModel::relAddressToPosition(qint64 nRelAddress) { 342 | qint64 nResult = 0; 343 | 344 | qint64 nAddress = XBinary::relAddressToAddress(&(g_pStats->memoryMap), nRelAddress); 345 | 346 | if (nAddress != -1) { 347 | nResult = addressToPosition(nAddress); 348 | } 349 | 350 | return nResult; 351 | } 352 | 353 | XDisasm::STATS *XDisasmModel::getStats() { 354 | return g_pStats; 355 | } 356 | 357 | void XDisasmModel::_beginResetModel() { 358 | beginResetModel(); 359 | } 360 | 361 | void XDisasmModel::_endResetModel() { 362 | resetCache(); 363 | endResetModel(); 364 | } 365 | 366 | void XDisasmModel::resetCache() { 367 | g_mapRecords.clear(); 368 | g_quRecords.clear(); 369 | } 370 | 371 | bool XDisasmModel::initDisasm() { 372 | bool bResult = false; 373 | 374 | cs_err err = cs_open(g_pStats->csarch, g_pStats->csmode, &g_disasm_handle); 375 | if (!err) { 376 | cs_option(g_disasm_handle, CS_OPT_DETAIL, CS_OPT_ON); // TODO Check 377 | } 378 | 379 | return bResult; 380 | } 381 | -------------------------------------------------------------------------------- /dialogdisasmprocess.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | DialogDisasmProcess 4 | 5 | 6 | 7 | 0 8 | 0 9 | 566 10 | 224 11 | 12 | 13 | 14 | Disasm 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Opcodes 23 | 24 | 25 | Qt::AlignCenter 26 | 27 | 28 | 29 | 1 30 | 31 | 32 | 1 33 | 34 | 35 | 1 36 | 37 | 38 | 1 39 | 40 | 41 | 1 42 | 43 | 44 | 45 | 46 | Qt::AlignCenter 47 | 48 | 49 | true 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | Calls 60 | 61 | 62 | Qt::AlignCenter 63 | 64 | 65 | 66 | 1 67 | 68 | 69 | 1 70 | 71 | 72 | 1 73 | 74 | 75 | 1 76 | 77 | 78 | 1 79 | 80 | 81 | 82 | 83 | Qt::AlignCenter 84 | 85 | 86 | true 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | Jumps 97 | 98 | 99 | Qt::AlignCenter 100 | 101 | 102 | 103 | 1 104 | 105 | 106 | 1 107 | 108 | 109 | 1 110 | 111 | 112 | 1 113 | 114 | 115 | 1 116 | 117 | 118 | 119 | 120 | Qt::AlignCenter 121 | 122 | 123 | true 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | Ref to 134 | 135 | 136 | Qt::AlignCenter 137 | 138 | 139 | 140 | 1 141 | 142 | 143 | 1 144 | 145 | 146 | 1 147 | 148 | 149 | 1 150 | 151 | 152 | 1 153 | 154 | 155 | 156 | 157 | Qt::AlignCenter 158 | 159 | 160 | true 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | Ref from 171 | 172 | 173 | Qt::AlignCenter 174 | 175 | 176 | 177 | 1 178 | 179 | 180 | 1 181 | 182 | 183 | 1 184 | 185 | 186 | 1 187 | 188 | 189 | 1 190 | 191 | 192 | 193 | 194 | Qt::AlignCenter 195 | 196 | 197 | true 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | Data labels 212 | 213 | 214 | Qt::AlignCenter 215 | 216 | 217 | 218 | 1 219 | 220 | 221 | 1 222 | 223 | 224 | 1 225 | 226 | 227 | 1 228 | 229 | 230 | 1 231 | 232 | 233 | 234 | 235 | Qt::AlignCenter 236 | 237 | 238 | true 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | VB 249 | 250 | 251 | Qt::AlignCenter 252 | 253 | 254 | 255 | 1 256 | 257 | 258 | 1 259 | 260 | 261 | 1 262 | 263 | 264 | 1 265 | 266 | 267 | 1 268 | 269 | 270 | 271 | 272 | Qt::AlignCenter 273 | 274 | 275 | true 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | Label strings 286 | 287 | 288 | Qt::AlignCenter 289 | 290 | 291 | 292 | 1 293 | 294 | 295 | 1 296 | 297 | 298 | 1 299 | 300 | 301 | 1 302 | 303 | 304 | 1 305 | 306 | 307 | 308 | 309 | Qt::AlignCenter 310 | 311 | 312 | true 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | Positions 323 | 324 | 325 | Qt::AlignCenter 326 | 327 | 328 | 329 | 1 330 | 331 | 332 | 1 333 | 334 | 335 | 1 336 | 337 | 338 | 1 339 | 340 | 341 | 1 342 | 343 | 344 | 345 | 346 | Qt::AlignCenter 347 | 348 | 349 | true 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | Addresses 360 | 361 | 362 | Qt::AlignCenter 363 | 364 | 365 | 366 | 1 367 | 368 | 369 | 1 370 | 371 | 372 | 1 373 | 374 | 375 | 1 376 | 377 | 378 | 1 379 | 380 | 381 | 382 | 383 | Qt::AlignCenter 384 | 385 | 386 | true 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | Qt::Vertical 399 | 400 | 401 | 402 | 20 403 | 169 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | Qt::Horizontal 414 | 415 | 416 | 417 | 40 418 | 20 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | Cancel 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | -------------------------------------------------------------------------------- /xdisasmwidget.cpp: -------------------------------------------------------------------------------- 1 | // copyright (c) 2019-2025 hors 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | #include "xdisasmwidget.h" 22 | 23 | #include "ui_xdisasmwidget.h" 24 | 25 | XDisasmWidget::XDisasmWidget(QWidget *pParent) : QWidget(pParent), ui(new Ui::XDisasmWidget) { 26 | ui->setupUi(this); 27 | 28 | XOptions::setMonoFont(ui->tableViewDisasm); 29 | 30 | // new QShortcut(QKeySequence(XShortcuts::GOTOENTRYPOINT), this, SLOT(_goToEntryPoint())); 31 | // new QShortcut(QKeySequence(XShortcuts::GOTOADDRESS), this, SLOT(_goToAddress())); 32 | // new QShortcut(QKeySequence(XShortcuts::GOTOOFFSET), this, SLOT(_goToOffset())); 33 | // new QShortcut(QKeySequence(XShortcuts::GOTORELADDRESS), this, SLOT(_goToRelAddress())); 34 | // new QShortcut(QKeySequence(XShortcuts::DUMPTOFILE), this, SLOT(_dumpToFile())); 35 | // new QShortcut(QKeySequence(XShortcuts::DISASM), this, SLOT(_disasm())); 36 | // new QShortcut(QKeySequence(XShortcuts::TODATA), this, SLOT(_toData())); 37 | // new QShortcut(QKeySequence(XShortcuts::HEXSIGNATURE), this, SLOT(_signature())); 38 | // new QShortcut(QKeySequence(XShortcuts::COPYADDRESS), this, SLOT(_copyAddress())); 39 | // new QShortcut(QKeySequence(XShortcuts::COPYOFFSET), this, SLOT(_copyOffset())); 40 | // new QShortcut(QKeySequence(XShortcuts::COPYRELADDRESS), this, SLOT(_copyRelAddress())); 41 | // new QShortcut(QKeySequence(XShortcuts::HEX), this, SLOT(_hex())); 42 | 43 | g_pShowOptions = 0; 44 | g_pDisasmOptions = 0; 45 | g_pModel = 0; 46 | 47 | g_showOptions = {}; 48 | g_disasmOptions = {}; 49 | } 50 | 51 | void XDisasmWidget::setData(QIODevice *pDevice, XDisasmModel::SHOWOPTIONS *pShowOptions, XDisasm::OPTIONS *pDisasmOptions, bool bAuto) { 52 | this->g_pDevice = pDevice; 53 | 54 | if (pShowOptions) { 55 | this->g_pShowOptions = pShowOptions; 56 | } else { 57 | this->g_pShowOptions = &g_showOptions; 58 | } 59 | 60 | if (pDisasmOptions) { 61 | this->g_pDisasmOptions = pDisasmOptions; 62 | } else { 63 | this->g_pDisasmOptions = &g_disasmOptions; 64 | } 65 | 66 | QSet stFileType = XBinary::getFileTypes(pDevice); 67 | 68 | stFileType.remove(XBinary::FT_BINARY); 69 | stFileType.insert(XBinary::FT_BINARY16); 70 | stFileType.insert(XBinary::FT_BINARY32); 71 | stFileType.insert(XBinary::FT_BINARY64); 72 | stFileType.insert(XBinary::FT_COM); 73 | 74 | QList listFileTypes = XBinary::_getFileTypeListFromSet(stFileType); 75 | 76 | XFormats::setFileTypeComboBox(this->g_pDisasmOptions->fileType, pDevice, ui->comboBoxType); 77 | 78 | if (bAuto) { 79 | analyze(); 80 | } 81 | } 82 | 83 | void XDisasmWidget::analyze() { 84 | if (g_pDisasmOptions && g_pShowOptions) { 85 | XBinary::FT fileType = (XBinary::FT)ui->comboBoxType->currentData().toInt(); 86 | g_pDisasmOptions->fileType = fileType; 87 | 88 | g_pDisasmOptions->stats = {}; 89 | 90 | QItemSelectionModel *modelOld = ui->tableViewDisasm->selectionModel(); 91 | ui->tableViewDisasm->setModel(0); 92 | 93 | process(g_pDevice, g_pDisasmOptions, -1, XDisasm::DM_DISASM); 94 | 95 | g_pModel = new XDisasmModel(g_pDevice, &(g_pDisasmOptions->stats), g_pShowOptions, this); 96 | 97 | ui->tableViewDisasm->setModel(g_pModel); 98 | delete modelOld; 99 | 100 | int nSymbolWidth = XLineEditHEX::getSymbolWidth(this); 101 | 102 | // TODO 16/32/64 width 103 | ui->tableViewDisasm->setColumnWidth(0, nSymbolWidth * 14); 104 | ui->tableViewDisasm->setColumnWidth(1, nSymbolWidth * 8); 105 | ui->tableViewDisasm->setColumnWidth(2, nSymbolWidth * 12); 106 | ui->tableViewDisasm->setColumnWidth(3, nSymbolWidth * 20); 107 | ui->tableViewDisasm->setColumnWidth(4, nSymbolWidth * 8); 108 | 109 | ui->tableViewDisasm->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Interactive); 110 | ui->tableViewDisasm->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Interactive); 111 | ui->tableViewDisasm->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Interactive); 112 | ui->tableViewDisasm->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Interactive); 113 | ui->tableViewDisasm->horizontalHeader()->setSectionResizeMode(4, QHeaderView::Stretch); 114 | 115 | ui->pushButtonOverlay->setEnabled(g_pDisasmOptions->stats.bIsOverlayPresent); 116 | 117 | goToAddress(g_pDisasmOptions->stats.nEntryPointAddress); 118 | } 119 | } 120 | 121 | void XDisasmWidget::goToAddress(qint64 nAddress) { 122 | if (g_pModel) { 123 | qint64 nPosition = g_pModel->addressToPosition(nAddress); 124 | 125 | _goToPosition(nPosition); 126 | } 127 | } 128 | 129 | void XDisasmWidget::goToOffset(qint64 nOffset) { 130 | if (g_pModel) { 131 | qint64 nPosition = g_pModel->offsetToPosition(nOffset); 132 | 133 | _goToPosition(nPosition); 134 | } 135 | } 136 | 137 | void XDisasmWidget::goToRelAddress(qint64 nRelAddress) { 138 | if (g_pModel) { 139 | qint64 nPosition = g_pModel->relAddressToPosition(nRelAddress); 140 | 141 | _goToPosition(nPosition); 142 | } 143 | } 144 | 145 | void XDisasmWidget::goToDisasmAddress(qint64 nAddress) { 146 | if (!g_pDisasmOptions->stats.bInit) { 147 | process(g_pDevice, g_pDisasmOptions, nAddress, XDisasm::DM_DISASM); 148 | } 149 | 150 | goToAddress(nAddress); 151 | } 152 | 153 | void XDisasmWidget::goToEntryPoint() { 154 | if (!g_pDisasmOptions->stats.bInit) { 155 | process(g_pDevice, g_pDisasmOptions, -1, XDisasm::DM_DISASM); 156 | } 157 | 158 | goToAddress(g_pDisasmOptions->stats.nEntryPointAddress); 159 | } 160 | 161 | void XDisasmWidget::disasm(qint64 nAddress) { 162 | process(g_pDevice, g_pDisasmOptions, nAddress, XDisasm::DM_DISASM); 163 | 164 | goToAddress(nAddress); 165 | } 166 | 167 | void XDisasmWidget::toData(qint64 nAddress, qint64 nSize) { 168 | process(g_pDevice, g_pDisasmOptions, nAddress, XDisasm::DM_TODATA); 169 | 170 | goToAddress(nAddress); 171 | } 172 | 173 | void XDisasmWidget::signature(qint64 nAddress, qint64 nSize) { 174 | if (g_pDisasmOptions->stats.mapRecords.value(nAddress).type == XDisasm::RECORD_TYPE_OPCODE) { 175 | DialogAsmSignature ds(this, g_pDevice, g_pModel, nAddress); 176 | 177 | ds.exec(); 178 | } else { 179 | qint64 nOffset = XBinary::addressToOffset(&(g_pDisasmOptions->stats.memoryMap), nAddress); 180 | 181 | if (nOffset != -1) { 182 | DialogHexSignature dhs(this, g_pDevice, nOffset, nSize); 183 | 184 | dhs.exec(); 185 | } 186 | } 187 | } 188 | 189 | void XDisasmWidget::hex(qint64 nOffset) { 190 | QHexView::OPTIONS hexOptions = {}; 191 | 192 | XBinary binary(g_pDevice); 193 | 194 | hexOptions.memoryMap = binary.getMemoryMap(); 195 | hexOptions.sBackupFileName = g_sBackupFileName; 196 | hexOptions.nStartAddress = nOffset; 197 | hexOptions.nStartSelectionAddress = nOffset; 198 | hexOptions.nSizeOfSelection = 1; 199 | 200 | DialogHex dialogHex(this, g_pDevice, &hexOptions); 201 | 202 | connect(&dialogHex, SIGNAL(editState(bool)), this, SLOT(setEdited(bool))); 203 | 204 | dialogHex.exec(); 205 | } 206 | 207 | void XDisasmWidget::clear() { 208 | ui->tableViewDisasm->setModel(0); 209 | } 210 | 211 | XDisasmWidget::~XDisasmWidget() { 212 | delete ui; 213 | } 214 | 215 | void XDisasmWidget::process(QIODevice *pDevice, XDisasm::OPTIONS *pOptions, qint64 nStartAddress, XDisasm::DM dm) { 216 | DialogDisasmProcess ddp(this); 217 | 218 | connect(&ddp, SIGNAL(errorMessage(QString)), this, SLOT(errorMessage(QString))); 219 | 220 | ddp.setData(pDevice, pOptions, nStartAddress, dm); 221 | ddp.exec(); 222 | 223 | if (g_pModel) { 224 | g_pModel->resetCache(); 225 | } 226 | 227 | // if(pModel) 228 | // { 229 | // pModel->_beginResetModel(); 230 | 231 | // DialogDisasmProcess ddp(this); 232 | 233 | // connect(&ddp,SIGNAL(errorMessage(QString)),this,SLOT(errorMessage(QString))); 234 | 235 | // ddp.setData(pDevice,pOptions,nStartAddress,dm); 236 | // ddp.exec(); 237 | 238 | // pModel->_endResetModel(); 239 | // } 240 | } 241 | 242 | XDisasm::STATS *XDisasmWidget::getDisasmStats() { 243 | return &(g_pDisasmOptions->stats); 244 | } 245 | 246 | void XDisasmWidget::setBackupFileName(QString sBackupFileName) { 247 | this->g_sBackupFileName = sBackupFileName; 248 | } 249 | 250 | void XDisasmWidget::on_pushButtonLabels_clicked() { 251 | if (g_pModel) { 252 | DialogDisasmLabels dialogDisasmLabels(this, g_pModel->getStats()); 253 | 254 | if (dialogDisasmLabels.exec() == QDialog::Accepted) { 255 | goToAddress(dialogDisasmLabels.getAddress()); 256 | } 257 | } 258 | } 259 | 260 | void XDisasmWidget::on_tableViewDisasm_customContextMenuRequested(const QPoint &pos) { 261 | if (g_pModel) { 262 | SELECTION_STAT selectionStat = getSelectionStat(); 263 | 264 | QMenu contextMenu(this); 265 | 266 | QMenu goToMenu(tr("Go to"), this); 267 | 268 | QAction actionGoToEntryPoint(tr("Entry point"), this); 269 | // actionGoToEntryPoint.setShortcut(QKeySequence(XShortcuts::GOTOENTRYPOINT)); 270 | connect(&actionGoToEntryPoint, SIGNAL(triggered()), this, SLOT(_goToEntryPoint())); 271 | 272 | QAction actionGoToAddress(tr("Virtual address"), this); 273 | // actionGoToAddress.setShortcut(QKeySequence(XShortcuts::GOTOADDRESS)); 274 | connect(&actionGoToAddress, SIGNAL(triggered()), this, SLOT(_goToAddress())); 275 | 276 | QAction actionGoToRelAddress(tr("Relative virtual address"), this); 277 | // actionGoToRelAddress.setShortcut(QKeySequence(XShortcuts::GOTORELADDRESS)); 278 | connect(&actionGoToRelAddress, SIGNAL(triggered()), this, SLOT(_goToRelAddress())); 279 | 280 | QAction actionGoToOffset(tr("File offset"), this); 281 | // actionGoToOffset.setShortcut(QKeySequence(XShortcuts::GOTOOFFSET)); 282 | connect(&actionGoToOffset, SIGNAL(triggered()), this, SLOT(_goToOffset())); 283 | 284 | goToMenu.addAction(&actionGoToEntryPoint); 285 | goToMenu.addAction(&actionGoToAddress); 286 | goToMenu.addAction(&actionGoToRelAddress); 287 | goToMenu.addAction(&actionGoToOffset); 288 | 289 | contextMenu.addMenu(&goToMenu); 290 | 291 | QMenu copyMenu(tr("Copy"), this); 292 | 293 | QAction actionCopyAddress(tr("Virtual address"), this); 294 | // actionCopyAddress.setShortcut(QKeySequence(XShortcuts::COPYADDRESS)); 295 | connect(&actionCopyAddress, SIGNAL(triggered()), this, SLOT(_copyAddress())); 296 | 297 | QAction actionCopyRelAddress(tr("Relative virtual address"), this); 298 | // actionCopyRelAddress.setShortcut(QKeySequence(XShortcuts::COPYRELADDRESS)); 299 | connect(&actionCopyRelAddress, SIGNAL(triggered()), this, SLOT(_copyRelAddress())); 300 | 301 | QAction actionCopyOffset(tr("File offset"), this); 302 | // actionCopyOffset.setShortcut(QKeySequence(XShortcuts::COPYOFFSET)); 303 | connect(&actionCopyOffset, SIGNAL(triggered()), this, SLOT(_copyOffset())); 304 | 305 | copyMenu.addAction(&actionCopyAddress); 306 | copyMenu.addAction(&actionCopyRelAddress); 307 | copyMenu.addAction(&actionCopyOffset); 308 | 309 | contextMenu.addMenu(©Menu); 310 | 311 | QAction actionHex(QString("Hex"), this); 312 | // actionHex.setShortcut(QKeySequence(XShortcuts::HEX)); 313 | connect(&actionHex, SIGNAL(triggered()), this, SLOT(_hex())); 314 | 315 | QAction actionSignature(tr("Signature"), this); 316 | // actionSignature.setShortcut(QKeySequence(XShortcuts::HEXSIGNATURE)); 317 | connect(&actionSignature, SIGNAL(triggered()), this, SLOT(_signature())); 318 | 319 | QAction actionDump(tr("Dump to file"), this); 320 | // actionDump.setShortcut(QKeySequence(XShortcuts::DUMPTOFILE)); 321 | connect(&actionDump, SIGNAL(triggered()), this, SLOT(_dumpToFile())); 322 | 323 | QAction actionDisasm(tr("Disasm"), this); 324 | // actionDisasm.setShortcut(QKeySequence(XShortcuts::DISASM)); 325 | connect(&actionDisasm, SIGNAL(triggered()), this, SLOT(_disasm())); 326 | 327 | QAction actionToData(tr("To data"), this); 328 | // actionToData.setShortcut(QKeySequence(XShortcuts::TODATA)); 329 | connect(&actionToData, SIGNAL(triggered()), this, SLOT(_toData())); 330 | 331 | contextMenu.addAction(&actionHex); 332 | contextMenu.addAction(&actionSignature); 333 | 334 | if ((selectionStat.nSize) && XBinary::isSolidAddressRange(&(g_pModel->getStats()->memoryMap), selectionStat.nAddress, selectionStat.nSize)) { 335 | contextMenu.addAction(&actionDump); 336 | } 337 | 338 | if (selectionStat.nCount == 1) { 339 | contextMenu.addAction(&actionDisasm); 340 | contextMenu.addAction(&actionToData); 341 | } 342 | 343 | contextMenu.exec(ui->tableViewDisasm->viewport()->mapToGlobal(pos)); 344 | 345 | // TODO data -> group 346 | // TODO add Label 347 | // TODO rename label 348 | // TODO remove label mb TODO custom label and Disasm label 349 | } 350 | } 351 | 352 | void XDisasmWidget::_goToAddress() { 353 | if (g_pModel) { 354 | DialogGoToAddress da(this, &(g_pModel->getStats()->memoryMap), DialogGoToAddress::TYPE_ADDRESS); 355 | if (da.exec() == QDialog::Accepted) { 356 | goToAddress(da.getValue()); 357 | } 358 | } 359 | } 360 | 361 | void XDisasmWidget::_goToRelAddress() { 362 | if (g_pModel) { 363 | DialogGoToAddress da(this, &(g_pModel->getStats()->memoryMap), DialogGoToAddress::TYPE_RELVIRTUALADDRESS); 364 | if (da.exec() == QDialog::Accepted) { 365 | goToRelAddress(da.getValue()); 366 | } 367 | } 368 | } 369 | 370 | void XDisasmWidget::_goToOffset() { 371 | if (g_pModel) { 372 | DialogGoToAddress da(this, &(g_pModel->getStats()->memoryMap), DialogGoToAddress::TYPE_OFFSET); 373 | if (da.exec() == QDialog::Accepted) { 374 | goToOffset(da.getValue()); 375 | } 376 | } 377 | } 378 | 379 | void XDisasmWidget::_goToEntryPoint() { 380 | goToEntryPoint(); 381 | } 382 | 383 | void XDisasmWidget::_copyAddress() { 384 | if (g_pModel) { 385 | SELECTION_STAT selectionStat = getSelectionStat(); 386 | 387 | if (selectionStat.nSize) { 388 | QApplication::clipboard()->setText(QString("%1").arg(selectionStat.nAddress, 0, 16)); 389 | } 390 | } 391 | } 392 | 393 | void XDisasmWidget::_copyOffset() { 394 | if (g_pModel) { 395 | SELECTION_STAT selectionStat = getSelectionStat(); 396 | 397 | if (selectionStat.nSize) { 398 | QApplication::clipboard()->setText(QString("%1").arg(selectionStat.nOffset, 0, 16)); 399 | } 400 | } 401 | } 402 | 403 | void XDisasmWidget::_copyRelAddress() { 404 | if (g_pModel) { 405 | SELECTION_STAT selectionStat = getSelectionStat(); 406 | 407 | if (selectionStat.nSize) { 408 | QApplication::clipboard()->setText(QString("%1").arg(selectionStat.nRelAddress, 0, 16)); 409 | } 410 | } 411 | } 412 | 413 | void XDisasmWidget::_dumpToFile() { 414 | if (g_pModel) { 415 | SELECTION_STAT selectionStat = getSelectionStat(); 416 | 417 | if (selectionStat.nSize) { 418 | QString sFilter; 419 | sFilter += QString("%1 (*.bin)").arg(tr("Raw data")); 420 | QString sSaveFileName = "Result"; // TODO default directory / TODO getDumpName 421 | QString sFileName = QFileDialog::getSaveFileName(this, tr("Save dump"), sSaveFileName, sFilter); 422 | 423 | qint64 nOffset = XBinary::addressToOffset(&(g_pModel->getStats()->memoryMap), selectionStat.nAddress); 424 | 425 | if (!sFileName.isEmpty()) { 426 | DialogDumpProcess dd(this, g_pDevice, nOffset, selectionStat.nSize, sFileName, DumpProcess::DT_OFFSET); 427 | 428 | dd.exec(); 429 | } 430 | } 431 | } 432 | } 433 | 434 | void XDisasmWidget::_disasm() { 435 | if (g_pModel) { 436 | SELECTION_STAT selectionStat = getSelectionStat(); 437 | 438 | if (selectionStat.nSize) { 439 | disasm(selectionStat.nAddress); 440 | } 441 | } 442 | } 443 | 444 | void XDisasmWidget::_toData() { 445 | if (g_pModel) { 446 | SELECTION_STAT selectionStat = getSelectionStat(); 447 | 448 | if (selectionStat.nSize) { 449 | toData(selectionStat.nAddress, selectionStat.nSize); 450 | } 451 | } 452 | } 453 | 454 | void XDisasmWidget::_signature() { 455 | if (g_pModel) { 456 | SELECTION_STAT selectionStat = getSelectionStat(); 457 | 458 | if (selectionStat.nSize) { 459 | signature(selectionStat.nAddress, selectionStat.nSize); 460 | } 461 | } 462 | } 463 | 464 | void XDisasmWidget::_hex() { 465 | if (g_pModel) { 466 | SELECTION_STAT selectionStat = getSelectionStat(); 467 | 468 | hex(selectionStat.nOffset); 469 | } 470 | } 471 | 472 | XDisasmWidget::SELECTION_STAT XDisasmWidget::getSelectionStat() { 473 | SELECTION_STAT result = {}; 474 | result.nAddress = -1; 475 | 476 | QModelIndexList il = ui->tableViewDisasm->selectionModel()->selectedRows(); 477 | 478 | result.nCount = il.count(); 479 | 480 | if (result.nCount) { 481 | result.nAddress = il.at(0).data(Qt::UserRole + XDisasmModel::UD_ADDRESS).toLongLong(); 482 | result.nOffset = il.at(0).data(Qt::UserRole + XDisasmModel::UD_OFFSET).toLongLong(); 483 | result.nRelAddress = il.at(0).data(Qt::UserRole + XDisasmModel::UD_RELADDRESS).toLongLong(); 484 | 485 | qint64 nLastElementAddress = il.at(result.nCount - 1).data(Qt::UserRole + XDisasmModel::UD_ADDRESS).toLongLong(); 486 | qint64 nLastElementSize = il.at(result.nCount - 1).data(Qt::UserRole + XDisasmModel::UD_SIZE).toLongLong(); 487 | 488 | result.nSize = (nLastElementAddress + nLastElementSize) - result.nAddress; 489 | } 490 | 491 | return result; 492 | } 493 | 494 | void XDisasmWidget::on_pushButtonAnalyze_clicked() { 495 | analyze(); 496 | } 497 | 498 | void XDisasmWidget::_goToPosition(qint32 nPosition) { 499 | if (ui->tableViewDisasm->verticalScrollBar()->maximum() == 0) { 500 | ui->tableViewDisasm->verticalScrollBar()->setMaximum(nPosition); // Hack 501 | } 502 | 503 | ui->tableViewDisasm->verticalScrollBar()->setValue(nPosition); 504 | 505 | ui->tableViewDisasm->setCurrentIndex(ui->tableViewDisasm->model()->index(nPosition, 0)); 506 | } 507 | 508 | void XDisasmWidget::on_pushButtonOverlay_clicked() { 509 | hex(g_pDisasmOptions->stats.nOverlayOffset); 510 | } 511 | 512 | void XDisasmWidget::setEdited(bool bState) { 513 | if (bState) { 514 | analyze(); 515 | } 516 | } 517 | 518 | void XDisasmWidget::on_pushButtonHex_clicked() { 519 | hex(0); 520 | } 521 | 522 | void XDisasmWidget::errorMessage(QString sText) { 523 | QMessageBox::critical(this, tr("Error"), sText); 524 | } 525 | -------------------------------------------------------------------------------- /xdisasm.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019-2025 hors 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | #include "xdisasm.h" 22 | 23 | XDisasm::XDisasm(QObject *pParent) : QObject(pParent) { 24 | g_pOptions = 0; 25 | g_nStartAddress = 0; 26 | g_disasm_handle = 0; 27 | g_bStop = false; 28 | } 29 | 30 | XDisasm::~XDisasm() { 31 | if (g_disasm_handle) { 32 | cs_close(&g_disasm_handle); 33 | g_disasm_handle = 0; 34 | } 35 | } 36 | 37 | void XDisasm::setData(QIODevice *pDevice, XDisasm::OPTIONS *pOptions, qint64 nStartAddress, XDisasm::DM dm) { 38 | this->g_pDevice = pDevice; 39 | this->g_pOptions = pOptions; 40 | this->g_nStartAddress = nStartAddress; 41 | this->g_dm = dm; 42 | } 43 | 44 | void XDisasm::_disasm(qint64 nInitAddress, qint64 nAddress) { 45 | g_pOptions->stats.mmapRefFrom.insert(nAddress, nInitAddress); 46 | g_pOptions->stats.mmapRefTo.insert(nInitAddress, nAddress); 47 | 48 | while (!g_bStop) { 49 | if (g_pOptions->stats.mapRecords.contains(nAddress)) { 50 | break; 51 | } 52 | 53 | bool bStopBranch = false; 54 | int nDelta = 0; 55 | 56 | qint64 nOffset = XBinary::addressToOffset(&(g_pOptions->stats.memoryMap), 57 | nAddress); // TODO optimize if image 58 | if (nOffset != -1) { 59 | char opcode[N_X64_OPCODE_SIZE]; 60 | 61 | XBinary::_zeroMemory(opcode, N_X64_OPCODE_SIZE); 62 | 63 | size_t nDataSize = XBinary::read_array(g_pDevice, nOffset, opcode, N_X64_OPCODE_SIZE); 64 | 65 | uint8_t *pData = (uint8_t *)opcode; 66 | 67 | cs_insn *pInsn = 0; 68 | size_t nNumberOfOpcodes = cs_disasm(g_disasm_handle, pData, nDataSize, nAddress, 1, &pInsn); 69 | 70 | if (nNumberOfOpcodes > 0) { 71 | if (pInsn->size > 1) { 72 | bStopBranch = !XBinary::isAddressPhysical(&(g_pOptions->stats.memoryMap), nAddress + pInsn->size - 1); 73 | } 74 | 75 | if (!bStopBranch) { 76 | for (int i = 0; i < pInsn->detail->x86.op_count; i++) { 77 | if (pInsn->detail->x86.operands[i].type == X86_OP_IMM) { 78 | qint64 nImm = pInsn->detail->x86.operands[i].imm; 79 | 80 | if (isJmpOpcode(pInsn->id)) { 81 | if (isCallOpcode(pInsn->id)) { 82 | g_pOptions->stats.stCalls.insert(nImm); 83 | } else { 84 | g_pOptions->stats.stJumps.insert(nImm); 85 | } 86 | 87 | if (nAddress != nImm) { 88 | _disasm(nAddress, nImm); 89 | } 90 | } 91 | } 92 | } 93 | 94 | RECORD opcode = {}; 95 | opcode.nOffset = nOffset; 96 | opcode.nSize = pInsn->size; 97 | opcode.type = RECORD_TYPE_OPCODE; 98 | 99 | if (!_insertOpcode(nAddress, &opcode)) { 100 | bStopBranch = true; 101 | } 102 | 103 | nDelta = pInsn->size; 104 | 105 | if (isEndBranchOpcode(pInsn->id)) { 106 | bStopBranch = true; 107 | } 108 | } 109 | 110 | cs_free(pInsn, nNumberOfOpcodes); 111 | } else { 112 | bStopBranch = true; 113 | } 114 | 115 | if (XBinary::_isMemoryZeroFilled(opcode, N_X64_OPCODE_SIZE)) { 116 | bStopBranch = true; 117 | } 118 | } 119 | 120 | if (nDelta) { 121 | nAddress += nDelta; 122 | } else { 123 | bStopBranch = true; 124 | } 125 | 126 | if (bStopBranch) { 127 | break; 128 | } 129 | } 130 | } 131 | 132 | void XDisasm::processDisasm() { 133 | g_bStop = false; 134 | 135 | if (!g_pOptions->stats.bInit) { 136 | g_pOptions->stats.csarch = CS_ARCH_X86; 137 | g_pOptions->stats.csmode = CS_MODE_16; 138 | 139 | XBinary::FT fileType = g_pOptions->fileType; 140 | 141 | if (fileType == XBinary::FT_UNKNOWN) { 142 | fileType = XBinary::getPrefFileType(g_pDevice); 143 | } 144 | 145 | if ((fileType == XBinary::FT_PE32) || (fileType == XBinary::FT_PE64)) { 146 | XPE pe(g_pDevice, g_pOptions->bIsImage, g_pOptions->nImageBase); 147 | 148 | g_pOptions->stats.memoryMap = pe.getMemoryMap(); 149 | g_pOptions->stats.nEntryPointAddress = pe.getEntryPointAddress(&g_pOptions->stats.memoryMap); 150 | g_pOptions->stats.bIsOverlayPresent = pe.isOverlayPresent(); 151 | g_pOptions->stats.nOverlaySize = pe.getOverlaySize(); 152 | g_pOptions->stats.nOverlayOffset = pe.getOverlayOffset(); 153 | 154 | XBinary::MODE modeBinary = pe.getMode(); 155 | 156 | g_pOptions->stats.csarch = CS_ARCH_X86; 157 | if (modeBinary == XBinary::MODE_32) { 158 | g_pOptions->stats.csmode = CS_MODE_32; 159 | } else if (modeBinary == XBinary::MODE_64) { 160 | g_pOptions->stats.csmode = CS_MODE_64; 161 | } 162 | } else if ((fileType == XBinary::FT_ELF32) || (fileType == XBinary::FT_ELF64)) { 163 | XELF elf(g_pDevice, g_pOptions->bIsImage, g_pOptions->nImageBase); 164 | 165 | g_pOptions->stats.memoryMap = elf.getMemoryMap(); 166 | g_pOptions->stats.nEntryPointAddress = elf.getEntryPointAddress(&g_pOptions->stats.memoryMap); 167 | g_pOptions->stats.bIsOverlayPresent = elf.isOverlayPresent(); 168 | g_pOptions->stats.nOverlaySize = elf.getOverlaySize(); 169 | g_pOptions->stats.nOverlayOffset = elf.getOverlayOffset(); 170 | } else if ((fileType == XBinary::FT_MACHO32) || (fileType == XBinary::FT_MACHO64)) { 171 | XMACH mach(g_pDevice, g_pOptions->bIsImage, g_pOptions->nImageBase); 172 | 173 | g_pOptions->stats.memoryMap = mach.getMemoryMap(); 174 | g_pOptions->stats.nEntryPointAddress = mach.getEntryPointAddress(&g_pOptions->stats.memoryMap); 175 | g_pOptions->stats.bIsOverlayPresent = mach.isOverlayPresent(); 176 | g_pOptions->stats.nOverlaySize = mach.getOverlaySize(); 177 | g_pOptions->stats.nOverlayOffset = mach.getOverlayOffset(); 178 | } else if (fileType == XBinary::FT_MSDOS) { 179 | XMSDOS msdos(g_pDevice, g_pOptions->bIsImage, g_pOptions->nImageBase); 180 | 181 | g_pOptions->stats.memoryMap = msdos.getMemoryMap(); 182 | g_pOptions->stats.nEntryPointAddress = msdos.getEntryPointAddress(&g_pOptions->stats.memoryMap); 183 | g_pOptions->stats.bIsOverlayPresent = msdos.isOverlayPresent(); 184 | g_pOptions->stats.nOverlaySize = msdos.getOverlaySize(); 185 | g_pOptions->stats.nOverlayOffset = msdos.getOverlayOffset(); 186 | } else if (fileType == XBinary::FT_NE) { 187 | XNE ne(g_pDevice, g_pOptions->bIsImage, g_pOptions->nImageBase); 188 | 189 | g_pOptions->stats.memoryMap = ne.getMemoryMap(); 190 | g_pOptions->stats.nEntryPointAddress = ne.getEntryPointAddress(&g_pOptions->stats.memoryMap); 191 | g_pOptions->stats.bIsOverlayPresent = ne.isOverlayPresent(); 192 | g_pOptions->stats.nOverlaySize = ne.getOverlaySize(); 193 | g_pOptions->stats.nOverlayOffset = ne.getOverlayOffset(); 194 | } else if ((fileType == XBinary::FT_LE) || (fileType == XBinary::FT_LX)) { 195 | XLE le(g_pDevice, g_pOptions->bIsImage, g_pOptions->nImageBase); 196 | 197 | g_pOptions->stats.memoryMap = le.getMemoryMap(); 198 | g_pOptions->stats.nEntryPointAddress = le.getEntryPointAddress(&g_pOptions->stats.memoryMap); 199 | g_pOptions->stats.bIsOverlayPresent = le.isOverlayPresent(); 200 | g_pOptions->stats.nOverlaySize = le.getOverlaySize(); 201 | g_pOptions->stats.nOverlayOffset = le.getOverlayOffset(); 202 | } else if (fileType == XBinary::FT_COM) { 203 | XCOM xcom(g_pDevice, g_pOptions->bIsImage, g_pOptions->nImageBase); 204 | 205 | g_pOptions->stats.memoryMap = xcom.getMemoryMap(); 206 | g_pOptions->stats.nEntryPointAddress = xcom.getEntryPointAddress(&g_pOptions->stats.memoryMap); 207 | } else if ((fileType == XBinary::FT_BINARY16) || (fileType == XBinary::FT_BINARY)) { 208 | XBinary binary(g_pDevice, g_pOptions->bIsImage, g_pOptions->nImageBase); 209 | 210 | binary.setArch("8086"); 211 | binary.setMode(XBinary::MODE_16); 212 | 213 | g_pOptions->stats.memoryMap = binary.getMemoryMap(); 214 | g_pOptions->stats.nEntryPointAddress = binary.getEntryPointAddress(&g_pOptions->stats.memoryMap); 215 | } else if (fileType == XBinary::FT_BINARY32) { 216 | XBinary binary(g_pDevice, g_pOptions->bIsImage, g_pOptions->nImageBase); 217 | 218 | binary.setArch("386"); 219 | binary.setMode(XBinary::MODE_32); 220 | 221 | g_pOptions->stats.memoryMap = binary.getMemoryMap(); 222 | g_pOptions->stats.nEntryPointAddress = binary.getEntryPointAddress(&g_pOptions->stats.memoryMap); 223 | } else if (fileType == XBinary::FT_BINARY64) { 224 | XBinary binary(g_pDevice, g_pOptions->bIsImage, g_pOptions->nImageBase); 225 | 226 | binary.setArch("AMD64"); 227 | binary.setMode(XBinary::MODE_64); 228 | 229 | g_pOptions->stats.memoryMap = binary.getMemoryMap(); 230 | g_pOptions->stats.nEntryPointAddress = binary.getEntryPointAddress(&g_pOptions->stats.memoryMap); 231 | } 232 | 233 | g_pOptions->stats.nImageBase = g_pOptions->stats.memoryMap.nModuleAddress; 234 | // pOptions->stats.nImageSize=XBinary::getTotalVirtualSize(&(pOptions->stats.memoryMap)); 235 | g_pOptions->stats.nImageSize = g_pOptions->stats.memoryMap.nImageSize; 236 | 237 | if (XBinary::isX86asm(g_pOptions->stats.memoryMap.sArch)) { 238 | g_pOptions->stats.csarch = CS_ARCH_X86; 239 | if ((g_pOptions->stats.memoryMap.mode == XBinary::MODE_16) || (g_pOptions->stats.memoryMap.mode == XBinary::MODE_16SEG)) { 240 | g_pOptions->stats.csmode = CS_MODE_16; 241 | } else if (g_pOptions->stats.memoryMap.mode == XBinary::MODE_32) { 242 | g_pOptions->stats.csmode = CS_MODE_32; 243 | } else if (g_pOptions->stats.memoryMap.mode == XBinary::MODE_64) { 244 | g_pOptions->stats.csmode = CS_MODE_64; 245 | } 246 | 247 | cs_err err = cs_open(g_pOptions->stats.csarch, g_pOptions->stats.csmode, &g_disasm_handle); 248 | if (!err) { 249 | cs_option(g_disasm_handle, CS_OPT_DETAIL, 250 | CS_OPT_ON); // TODO Check 251 | } 252 | 253 | _disasm(0, g_pOptions->stats.nEntryPointAddress); 254 | 255 | if (g_nStartAddress != -1) { 256 | if (g_nStartAddress != g_pOptions->stats.nEntryPointAddress) { 257 | _disasm(0, g_nStartAddress); 258 | } 259 | } 260 | 261 | _adjust(); 262 | _updatePositions(); 263 | 264 | g_pOptions->stats.bInit = true; 265 | 266 | if (g_disasm_handle) { 267 | cs_close(&g_disasm_handle); 268 | g_disasm_handle = 0; 269 | } 270 | } else { 271 | emit errorMessage(QString("%1: %2").arg("Architecture").arg(g_pOptions->stats.memoryMap.sArch)); 272 | } 273 | } else { 274 | if (XBinary::isX86asm(g_pOptions->stats.memoryMap.sArch)) { 275 | // TODO move to function 276 | if (g_disasm_handle == 0) { 277 | cs_err err = cs_open(g_pOptions->stats.csarch, g_pOptions->stats.csmode, &g_disasm_handle); 278 | if (!err) { 279 | cs_option(g_disasm_handle, CS_OPT_DETAIL, 280 | CS_OPT_ON); // TODO Check 281 | } 282 | } 283 | 284 | _disasm(0, g_nStartAddress); 285 | 286 | _adjust(); 287 | _updatePositions(); 288 | 289 | if (g_disasm_handle) { 290 | cs_close(&g_disasm_handle); 291 | g_disasm_handle = 0; 292 | } 293 | } else { 294 | emit errorMessage(QString("%1: %2").arg("Architecture").arg(g_pOptions->stats.memoryMap.sArch)); 295 | } 296 | } 297 | 298 | emit processFinished(); 299 | } 300 | 301 | void XDisasm::processToData() { 302 | g_pOptions->stats.mapRecords.remove(this->g_nStartAddress); 303 | 304 | _adjust(); 305 | _updatePositions(); 306 | 307 | emit processFinished(); 308 | } 309 | 310 | void XDisasm::process() { 311 | if (g_dm == DM_DISASM) { 312 | processDisasm(); 313 | } else if (g_dm == DM_TODATA) { 314 | processToData(); 315 | } 316 | } 317 | 318 | void XDisasm::stop() { 319 | g_bStop = true; 320 | } 321 | 322 | XDisasm::STATS *XDisasm::getStats() { 323 | return &(g_pOptions->stats); 324 | } 325 | 326 | void XDisasm::_adjust() { 327 | g_pOptions->stats.mapLabelStrings.clear(); 328 | g_pOptions->stats.mapVB.clear(); 329 | 330 | if (!g_bStop) { 331 | g_pOptions->stats.mapLabelStrings.insert(g_pOptions->stats.nEntryPointAddress, "entry_point"); 332 | 333 | QSetIterator iFL(g_pOptions->stats.stCalls); 334 | while (iFL.hasNext() && (!g_bStop)) { 335 | qint64 nAddress = iFL.next(); 336 | 337 | if (!g_pOptions->stats.mapLabelStrings.contains(nAddress)) { 338 | g_pOptions->stats.mapLabelStrings.insert(nAddress, QString("func_%1").arg(nAddress, 0, 16)); 339 | } 340 | } 341 | 342 | QSetIterator iJL(g_pOptions->stats.stJumps); 343 | while (iJL.hasNext() && (!g_bStop)) { 344 | qint64 nAddress = iJL.next(); 345 | 346 | if (!g_pOptions->stats.mapLabelStrings.contains(nAddress)) { 347 | g_pOptions->stats.mapLabelStrings.insert(nAddress, QString("lab_%1").arg(nAddress, 0, 16)); 348 | } 349 | } 350 | 351 | // QSet stFunctionLabels; 352 | // QSet stJmpLabels; 353 | // QMap mapDataSizeLabels; // Set Max 354 | // QSet stDataLabels; 355 | 356 | // TODO Strings 357 | QMapIterator iRecords(g_pOptions->stats.mapRecords); 358 | while (iRecords.hasNext() && (!g_bStop)) { 359 | iRecords.next(); 360 | 361 | qint64 nAddress = iRecords.key(); 362 | 363 | VIEW_BLOCK record; 364 | record.nAddress = nAddress; 365 | record.nOffset = iRecords.value().nOffset; 366 | record.nSize = iRecords.value().nSize; 367 | 368 | if (iRecords.value().type == RECORD_TYPE_OPCODE) { 369 | record.type = VBT_OPCODE; 370 | } else if (iRecords.value().type == RECORD_TYPE_DATA) { 371 | record.type = VBT_DATA; 372 | } 373 | 374 | if (!g_pOptions->stats.mapVB.contains(nAddress)) { 375 | g_pOptions->stats.mapVB.insert(nAddress, record); 376 | } 377 | } 378 | 379 | int nNumberOfRecords = g_pOptions->stats.memoryMap.listRecords.count(); // TODO 380 | 381 | for (int i = 0; (i < nNumberOfRecords) && (!g_bStop); i++) { 382 | qint64 nRegionAddress = g_pOptions->stats.memoryMap.listRecords.at(i).nAddress; 383 | qint64 nRegionOffset = g_pOptions->stats.memoryMap.listRecords.at(i).nOffset; 384 | qint64 nRegionSize = g_pOptions->stats.memoryMap.listRecords.at(i).nSize; 385 | 386 | if (nRegionAddress != -1) { 387 | for (qint64 nCurrentAddress = nRegionAddress, nCurrentOffset = nRegionOffset; 388 | (nCurrentAddress < (nRegionAddress + nRegionSize)) && (!g_bStop);) { 389 | VIEW_BLOCK vb = g_pOptions->stats.mapVB.value(nCurrentAddress); 390 | 391 | if (!vb.nSize) { 392 | QMap::const_iterator iter = g_pOptions->stats.mapVB.lowerBound(nCurrentAddress); 393 | 394 | qint64 nBlockAddress = 0; 395 | qint64 nBlockOffset = 0; 396 | qint64 nBlockSize = 0; 397 | 398 | qint64 nIterKey = iter.key(); 399 | 400 | if (g_pOptions->stats.mapVB.count()) { 401 | if (nIterKey == g_pOptions->stats.mapVB.firstKey()) // TODO move outside 'for' 402 | { 403 | // nBlockAddress=pOptions->stats.nImageBase; 404 | nBlockAddress = g_pOptions->stats.memoryMap.listRecords.at(0).nAddress; 405 | nBlockOffset = g_pOptions->stats.memoryMap.listRecords.at(0).nOffset; 406 | 407 | if (nIterKey < (nRegionAddress + nRegionSize)) { 408 | nBlockSize = iter.key() - g_pOptions->stats.nImageBase; 409 | } else { 410 | nBlockSize = (nRegionAddress + nRegionSize) - nBlockAddress; 411 | } 412 | } else if (iter == g_pOptions->stats.mapVB.end()) { 413 | nBlockAddress = nCurrentAddress; 414 | nBlockOffset = nCurrentOffset; 415 | 416 | nBlockSize = (nRegionAddress + nRegionSize) - nBlockAddress; 417 | } else { 418 | nBlockAddress = nCurrentAddress; 419 | nBlockOffset = nCurrentOffset; 420 | if (nIterKey < (nRegionAddress + nRegionSize)) { 421 | nBlockSize = iter.key() - nBlockAddress; 422 | } else { 423 | nBlockSize = (nRegionAddress + nRegionSize) - nBlockAddress; 424 | } 425 | } 426 | } else { 427 | nBlockAddress = nCurrentAddress; 428 | nBlockOffset = nCurrentOffset; 429 | 430 | nBlockSize = (nRegionAddress + nRegionSize) - nBlockAddress; 431 | } 432 | 433 | qint64 _nAddress = nBlockAddress; 434 | qint64 _nOffset = nBlockOffset; 435 | qint64 _nSize = nBlockSize; 436 | 437 | if (_nOffset != -1) { 438 | while (_nSize >= 16) { 439 | VIEW_BLOCK record; 440 | record.nAddress = _nAddress; 441 | record.nOffset = _nOffset; 442 | record.nSize = 16; 443 | record.type = VBT_DATABLOCK; 444 | 445 | if (!g_pOptions->stats.mapVB.contains(_nAddress)) { 446 | g_pOptions->stats.mapVB.insert(_nAddress, record); 447 | } 448 | 449 | _nSize -= 16; 450 | _nAddress += 16; 451 | _nOffset += 16; 452 | } 453 | } else { 454 | VIEW_BLOCK record; 455 | record.nAddress = _nAddress; 456 | record.nOffset = -1; 457 | record.nSize = _nSize; 458 | record.type = VBT_DATABLOCK; 459 | 460 | if (!g_pOptions->stats.mapVB.contains(_nAddress)) { 461 | g_pOptions->stats.mapVB.insert(_nAddress, record); 462 | } 463 | } 464 | 465 | nCurrentAddress = nBlockAddress + nBlockSize; 466 | if (nBlockOffset != -1) { 467 | nCurrentOffset = nBlockOffset + nBlockSize; 468 | } 469 | } else { 470 | nCurrentAddress = vb.nAddress + vb.nSize; 471 | if (nCurrentOffset != -1) { 472 | nCurrentOffset = vb.nOffset + vb.nSize; 473 | } 474 | } 475 | } 476 | } 477 | } 478 | 479 | // QMapIterator iDS(stats.mmapDataLabels); 480 | // while(iDS.hasNext()) 481 | // { 482 | // iDS.next(); 483 | 484 | // qint64 nAddress=iDS.key(); 485 | 486 | // VIEW_BLOCK record; 487 | // record.nOffset=pBinary->addressToOffset(pListMM,nAddress); 488 | // record.nSize=iDS.value(); 489 | // record.type=VBT_DATA; 490 | 491 | // if(!stats.mapVB.contains(nAddress)) 492 | // { 493 | // stats.mapVB.insert(nAddress,record); 494 | // } 495 | // } 496 | 497 | // QSetIterator iD(stats.stDataLabels); 498 | // while(iD.hasNext()&&(!bStop)) 499 | // { 500 | // qint64 nAddress=iD.next(); 501 | 502 | // VIEW_BLOCK record; 503 | // record.nOffset=pBinary->addressToOffset(pListMM,nAddress); 504 | // record.nSize=0; 505 | // record.type=VBT_DATA; 506 | 507 | // if(!stats.mapVB.contains(nAddress)) 508 | // { 509 | // stats.mapVB.insert(nAddress,record); 510 | // } 511 | // } 512 | 513 | // TODO Check errors 514 | } 515 | } 516 | 517 | void XDisasm::_updatePositions() { 518 | qint64 nImageSize = g_pOptions->stats.nImageSize; 519 | qint64 nNumberOfVBs = g_pOptions->stats.mapVB.count(); 520 | qint64 nVBSize = getVBSize(&(g_pOptions->stats.mapVB)); 521 | g_pOptions->stats.nPositions = nImageSize + nNumberOfVBs - nVBSize; // TODO 522 | 523 | g_pOptions->stats.mapPositions.clear(); 524 | // TODO cache 525 | qint64 nCurrentAddress = g_pOptions->stats.nImageBase; // TODO 526 | 527 | for (qint64 i = 0; i < g_pOptions->stats.nPositions; i++) { 528 | bool bIsVBPresent = g_pOptions->stats.mapVB.contains(nCurrentAddress); 529 | 530 | if (bIsVBPresent) { 531 | g_pOptions->stats.mapPositions.insert(i, nCurrentAddress); 532 | g_pOptions->stats.mapAddresses.insert(nCurrentAddress, i); 533 | 534 | nCurrentAddress += g_pOptions->stats.mapVB.value(nCurrentAddress).nSize - 1; 535 | } 536 | 537 | nCurrentAddress++; 538 | } 539 | } 540 | 541 | bool XDisasm::_insertOpcode(qint64 nAddress, XDisasm::RECORD *pOpcode) { 542 | g_pOptions->stats.mapRecords.insert(nAddress, *pOpcode); 543 | 544 | int nNumberOfRecords = g_pOptions->stats.mapRecords.count(); 545 | 546 | return (nNumberOfRecords < N_OPCODE_COUNT); 547 | } 548 | 549 | qint64 XDisasm::getVBSize(QMap *pMapVB) { 550 | qint64 nResult = 0; 551 | 552 | QMapIterator i(*pMapVB); 553 | while (i.hasNext()) { 554 | i.next(); 555 | 556 | nResult += i.value().nSize; 557 | } 558 | 559 | return nResult; 560 | } 561 | 562 | QString XDisasm::getDisasmString(csh disasm_handle, qint64 nAddress, char *pData, qint32 nDataSize) { 563 | QString sResult; 564 | 565 | cs_insn *pInsn = 0; 566 | size_t nNumberOfOpcodes = cs_disasm(disasm_handle, (uint8_t *)pData, nDataSize, nAddress, 1, &pInsn); 567 | 568 | if (nNumberOfOpcodes > 0) { 569 | QString sMnemonic = pInsn->mnemonic; 570 | QString sArgs = pInsn->op_str; 571 | 572 | sResult = sMnemonic; 573 | if (sArgs != "") { 574 | sResult += " " + sArgs; 575 | } 576 | 577 | cs_free(pInsn, nNumberOfOpcodes); 578 | } 579 | 580 | return sResult; 581 | } 582 | 583 | QList XDisasm::getSignature(XDisasm::SIGNATURE_OPTIONS *pSignatureOptions, qint64 nAddress) { 584 | QList listResult; 585 | 586 | csh _disasm_handle; 587 | cs_err err = cs_open(pSignatureOptions->csarch, pSignatureOptions->csmode, &_disasm_handle); 588 | if (!err) { 589 | cs_option(_disasm_handle, CS_OPT_DETAIL, CS_OPT_ON); 590 | } 591 | 592 | QSet stRecords; 593 | 594 | bool bStopBranch = false; 595 | 596 | for (int i = 0; (i < pSignatureOptions->nCount) && (!bStopBranch); i++) { 597 | qint64 nOffset = XBinary::addressToOffset(&(pSignatureOptions->memoryMap), nAddress); 598 | if (nOffset != -1) { 599 | char opcode[N_X64_OPCODE_SIZE]; 600 | 601 | XBinary::_zeroMemory(opcode, N_X64_OPCODE_SIZE); 602 | 603 | size_t nDataSize = XBinary::read_array(pSignatureOptions->pDevice, nOffset, opcode, N_X64_OPCODE_SIZE); 604 | 605 | uint8_t *pData = (uint8_t *)opcode; 606 | 607 | cs_insn *pInsn = 0; 608 | size_t count = cs_disasm(_disasm_handle, pData, nDataSize, nAddress, 1, &pInsn); 609 | 610 | if (count > 0) { 611 | if (pInsn->size > 1) { 612 | bStopBranch = !XBinary::isAddressPhysical(&(pSignatureOptions->memoryMap), nAddress + pInsn->size - 1); 613 | } 614 | 615 | if (stRecords.contains(nAddress)) { 616 | bStopBranch = true; 617 | } 618 | 619 | if (!bStopBranch) { 620 | SIGNATURE_RECORD record = {}; 621 | 622 | record.nAddress = nAddress; 623 | record.sOpcode = pInsn->mnemonic; 624 | QString sArgs = pInsn->op_str; 625 | 626 | if (sArgs != "") { 627 | record.sOpcode += " " + sArgs; 628 | } 629 | 630 | record.baOpcode = QByteArray(opcode, pInsn->size); 631 | 632 | record.nDispOffset = pInsn->detail->x86.encoding.disp_offset; 633 | record.nDispSize = pInsn->detail->x86.encoding.disp_size; 634 | record.nImmOffset = pInsn->detail->x86.encoding.imm_offset; 635 | record.nImmSize = pInsn->detail->x86.encoding.imm_size; 636 | 637 | stRecords.insert(nAddress); 638 | 639 | nAddress += pInsn->size; 640 | 641 | if (pSignatureOptions->sm == XDisasm::SM_RELATIVEADDRESS) { 642 | for (int i = 0; i < pInsn->detail->x86.op_count; i++) { 643 | if (pInsn->detail->x86.operands[i].type == X86_OP_IMM) { 644 | qint64 nImm = pInsn->detail->x86.operands[i].imm; 645 | 646 | if (isJmpOpcode(pInsn->id)) { 647 | nAddress = nImm; 648 | record.bIsConst = true; 649 | } 650 | } 651 | } 652 | } 653 | 654 | listResult.append(record); 655 | } 656 | 657 | cs_free(pInsn, count); 658 | } else { 659 | bStopBranch = true; 660 | } 661 | } 662 | } 663 | 664 | cs_close(&_disasm_handle); 665 | 666 | return listResult; 667 | } 668 | 669 | bool XDisasm::isEndBranchOpcode(uint nOpcodeID) { 670 | bool bResult = false; 671 | 672 | // TODO more checks 673 | if ((nOpcodeID == X86_INS_JMP) || (nOpcodeID == X86_INS_RET) || (nOpcodeID == X86_INS_INT3)) { 674 | bResult = true; 675 | } 676 | 677 | return bResult; 678 | } 679 | 680 | bool XDisasm::isJmpOpcode(uint nOpcodeID) { 681 | bool bResult = false; 682 | 683 | if ((nOpcodeID == X86_INS_JMP) || (nOpcodeID == X86_INS_JA) || (nOpcodeID == X86_INS_JAE) || (nOpcodeID == X86_INS_JB) || (nOpcodeID == X86_INS_JBE) || 684 | (nOpcodeID == X86_INS_JCXZ) || (nOpcodeID == X86_INS_JE) || (nOpcodeID == X86_INS_JECXZ) || (nOpcodeID == X86_INS_JG) || (nOpcodeID == X86_INS_JGE) || 685 | (nOpcodeID == X86_INS_JL) || (nOpcodeID == X86_INS_JLE) || (nOpcodeID == X86_INS_JNE) || (nOpcodeID == X86_INS_JNO) || (nOpcodeID == X86_INS_JNP) || 686 | (nOpcodeID == X86_INS_JNS) || (nOpcodeID == X86_INS_JO) || (nOpcodeID == X86_INS_JP) || (nOpcodeID == X86_INS_JRCXZ) || (nOpcodeID == X86_INS_JS) || 687 | (nOpcodeID == X86_INS_LOOP) || (nOpcodeID == X86_INS_LOOPE) || (nOpcodeID == X86_INS_LOOPNE) || (nOpcodeID == X86_INS_CALL)) { 688 | bResult = true; 689 | } 690 | 691 | return bResult; 692 | } 693 | 694 | bool XDisasm::isCallOpcode(uint nOpcodeID) { 695 | bool bResult = false; 696 | 697 | if (nOpcodeID == X86_INS_CALL) { 698 | bResult = true; 699 | } 700 | 701 | return bResult; 702 | } 703 | --------------------------------------------------------------------------------