|
| 1 | +#include "fasm.h" |
| 2 | + |
| 3 | +Fasm::Fasm(QString bytes) : QMainWindow(nullptr) |
| 4 | +{ |
| 5 | + this->setWindowTitle("Fasm"); |
| 6 | + this->setWindowIcon(QIcon("/usr/share/icons/fhex.png")); |
| 7 | + this->setMinimumSize(800, 500); |
| 8 | + textAsm = new QTextEdit(this); |
| 9 | + textOpcodes = new QTextEdit(this); |
| 10 | + textAsm->setStyleSheet(TEXTEDIT_STYLE); |
| 11 | + textOpcodes->setStyleSheet(TEXTEDIT_STYLE); |
| 12 | + this->textOpcodes->setPlainText(bytes); |
| 13 | + statusbar = new QLabel; |
| 14 | + QLabel *lblArch = new QLabel("Arch:"); |
| 15 | + QLabel *lblMode = new QLabel("Mode:"); |
| 16 | + QLabel *lblAsm = new QLabel("Assembly:"); |
| 17 | + QLabel *lblOpcodes = new QLabel("Op codes:"); |
| 18 | + cmbArch = new QComboBox; |
| 19 | + cmbArch->addItem("X86"); |
| 20 | + cmbArch->addItem("ARM"); |
| 21 | + cmbArch->addItem("ARM64"); |
| 22 | + cmbArch->addItem("MIPS"); |
| 23 | + cmbMode = new QComboBox; |
| 24 | + cmbMode->addItem("32 bit"); |
| 25 | + cmbMode->addItem("64 bit"); |
| 26 | + cmbMode->addItem("ARM"); |
| 27 | + cmbMode->addItem("THUMB"); |
| 28 | + cmbMode->addItem("MIPS32"); |
| 29 | + cmbMode->addItem("MIPS64"); |
| 30 | + QPushButton *setDisasm = new QPushButton("Disassemble"); |
| 31 | + connect(setDisasm, &QPushButton::clicked, this, &Fasm::on_btnSetDisasm_click); |
| 32 | + QPushButton *setAsm = new QPushButton("Assemble"); |
| 33 | + connect(setAsm, &QPushButton::clicked, this, &Fasm::on_btnSetAsm_click); |
| 34 | + QHBoxLayout *hbox = new QHBoxLayout; |
| 35 | + QHBoxLayout *buttons = new QHBoxLayout; |
| 36 | + QGridLayout *gridLayout = new QGridLayout; |
| 37 | + hbox->addWidget(lblArch, 0, Qt::AlignRight); |
| 38 | + hbox->addWidget(cmbArch, 0, Qt::AlignLeft); |
| 39 | + hbox->addWidget(lblMode, 0, Qt::AlignRight); |
| 40 | + hbox->addWidget(cmbMode, 0, Qt::AlignLeft); |
| 41 | + buttons->addWidget(setDisasm, 0, Qt::AlignRight); |
| 42 | + buttons->addWidget(setAsm, 0, Qt::AlignLeft); |
| 43 | + gridLayout->addLayout(hbox, 0, 0); |
| 44 | + gridLayout->addLayout(buttons, 0, 1); |
| 45 | + gridLayout->addWidget(lblAsm, 1, 0); |
| 46 | + gridLayout->addWidget(lblOpcodes, 1, 1); |
| 47 | + gridLayout->addWidget(textAsm, 2, 0); |
| 48 | + gridLayout->addWidget(textOpcodes, 2, 1); |
| 49 | + gridLayout->addWidget(statusbar, 3, 0, 1, 2); |
| 50 | + QWidget *mainWidget = new QWidget(); |
| 51 | + mainWidget->setLayout(gridLayout); |
| 52 | + this->setCentralWidget(mainWidget); |
| 53 | + ks = nullptr; |
| 54 | + loadKeystone(); |
| 55 | + loadCapstone(); |
| 56 | +} |
| 57 | + |
| 58 | +void Fasm::loadCapstone() { |
| 59 | + updateArchMode(); |
| 60 | + cs_opt_skipdata skipdata = { |
| 61 | + .mnemonic = "db", |
| 62 | + }; |
| 63 | + cs_err err = cs_open(carch, cmode, &cs); |
| 64 | + if (err != CS_ERR_OK){ |
| 65 | + this->statusbar->setText("Error: Failed capstone initialization"); |
| 66 | + } else if (this->textOpcodes->toPlainText() != ""){ |
| 67 | + size_t count; |
| 68 | + cs_insn *insn; |
| 69 | + cs_option(cs, CS_OPT_DETAIL, CS_OPT_ON); |
| 70 | + cs_option(cs, CS_OPT_SKIPDATA, CS_OPT_ON); |
| 71 | + cs_option(cs, CS_OPT_SKIPDATA_SETUP, (size_t)&skipdata); |
| 72 | + QByteArray bytes = QByteArray::fromHex(this->textOpcodes->toPlainText().toUtf8()); |
| 73 | + char *t = bytes.data(); |
| 74 | + count = cs_disasm(cs, reinterpret_cast<uint8_t*>(QByteArray::fromHex(this->textOpcodes->toPlainText().toUtf8()).data()), bytes.size(), 0, 0, &insn); |
| 75 | + if (count > 0) { |
| 76 | + this->statusbar->setText("Disassembled " + QString::number(count) + " instructions"); |
| 77 | + this->textAsm->clear(); |
| 78 | + size_t j; |
| 79 | + for (j = 0; j < count; j++) { |
| 80 | + this->textAsm->setPlainText(this->textAsm->toPlainText() + insn[j].mnemonic + " " + insn[j].op_str + ";\r\n"); |
| 81 | + } |
| 82 | + cs_free(insn, count); |
| 83 | + } else { |
| 84 | + this->statusbar->setText("Error: Failed to disassemble given op codes\n"); |
| 85 | + } |
| 86 | + cs_close(&cs); |
| 87 | + } |
| 88 | +} |
| 89 | + |
| 90 | +void Fasm::updateArchMode() { |
| 91 | + QString txtArch = cmbArch->currentText(); |
| 92 | + QString txtMode = cmbMode->currentText(); |
| 93 | + |
| 94 | + if (txtArch == "X86") { |
| 95 | + karch = KS_ARCH_X86; |
| 96 | + carch = CS_ARCH_X86; |
| 97 | + } else if (txtArch == "ARM") { |
| 98 | + karch = KS_ARCH_ARM; |
| 99 | + carch = CS_ARCH_ARM; |
| 100 | + } else if (txtArch == "ARM64") { |
| 101 | + karch = KS_ARCH_ARM64; |
| 102 | + carch = CS_ARCH_ARM64; |
| 103 | + } else if (txtArch == "MIPS") { |
| 104 | + karch = KS_ARCH_MIPS; |
| 105 | + carch = CS_ARCH_MIPS; |
| 106 | + } |
| 107 | + |
| 108 | + if (txtMode == "32 bit") { |
| 109 | + kmode = KS_MODE_32; |
| 110 | + cmode = CS_MODE_32; |
| 111 | + } else if (txtMode == "64 bit") { |
| 112 | + kmode = KS_MODE_64; |
| 113 | + cmode = CS_MODE_64; |
| 114 | + } else if (txtMode == "ARM") { |
| 115 | + kmode = KS_MODE_ARM; |
| 116 | + cmode = CS_MODE_ARM; |
| 117 | + } else if (txtMode == "THUMB") { |
| 118 | + kmode = KS_MODE_THUMB; |
| 119 | + cmode = CS_MODE_THUMB; |
| 120 | + } else if (txtMode == "MIPS32") { |
| 121 | + kmode = KS_MODE_MIPS32; |
| 122 | + cmode = CS_MODE_MIPS32; |
| 123 | + } else if (txtMode == "MIPS64") { |
| 124 | + kmode = KS_MODE_MIPS64; |
| 125 | + cmode = CS_MODE_MIPS64; |
| 126 | + } |
| 127 | +} |
| 128 | + |
| 129 | +void Fasm::loadKeystone() { |
| 130 | + if (ks != nullptr) { |
| 131 | + ks_close(ks); |
| 132 | + ks = nullptr; |
| 133 | + } |
| 134 | + updateArchMode(); |
| 135 | + ks_err err; |
| 136 | + err = ks_open(karch, kmode, &ks); |
| 137 | + if (err != KS_ERR_OK) { |
| 138 | + statusbar->setText("Error: Failed keystone initialization"); |
| 139 | + } else if (this->textAsm->toPlainText() != "") { |
| 140 | + this->textOpcodes->clear(); |
| 141 | + QString assembly = this->textAsm->toPlainText(); |
| 142 | + for (uint8_t b : asmToOpcodes(assembly)) { |
| 143 | + this->textOpcodes->setPlainText(this->textOpcodes->toPlainText() + QString::number(b, 16).rightJustified(2,'0')); |
| 144 | + } |
| 145 | + } |
| 146 | +} |
| 147 | + |
| 148 | +vector<uint8_t> Fasm::asmToOpcodes(QString &assembly) { |
| 149 | + vector<uint8_t> bytes; |
| 150 | + unsigned char *encode; |
| 151 | + size_t count; |
| 152 | + size_t size; |
| 153 | + if (ks_asm(ks, assembly.toStdString().c_str(), 0, &encode, &size, &count) != KS_ERR_OK) { |
| 154 | + this->statusbar->setText("Keystone error " + QString::number(ks_errno(ks))); |
| 155 | + } else { |
| 156 | + size_t i; |
| 157 | + for (i = 0; i < size; i++) { |
| 158 | + bytes.push_back(encode[i]); |
| 159 | + } |
| 160 | + this->statusbar->setText("Compiled: " + QString::number(size) + " bytes | Statements: " + QString::number(count) + " | Bytes: " + QString::number(bytes.size())); |
| 161 | + } |
| 162 | + |
| 163 | + ks_free(encode); |
| 164 | + return bytes; |
| 165 | +} |
| 166 | + |
| 167 | +Fasm::~Fasm() { |
| 168 | + ks_close(ks); |
| 169 | +} |
| 170 | + |
| 171 | +void Fasm::on_btnSetAsm_click() { |
| 172 | + this->loadKeystone(); |
| 173 | +} |
| 174 | + |
| 175 | +void Fasm::on_btnSetDisasm_click() { |
| 176 | + this->loadCapstone(); |
| 177 | +} |
0 commit comments