291 lines
8.0 KiB
C++
291 lines
8.0 KiB
C++
#include "winghexdisasm.h"
|
|
#include <QApplication>
|
|
#include <QHBoxLayout>
|
|
#include <QLabel>
|
|
#include <QMessageBox>
|
|
#include <QMetaEnum>
|
|
#include <QSettings>
|
|
#include <QVBoxLayout>
|
|
|
|
Q_DECLARE_METATYPE(cs_arch)
|
|
Q_DECLARE_METATYPE(cs_mode)
|
|
|
|
#define ICONRES(name) QIcon(":/WingHexDisasm/img/" name ".png")
|
|
#define HOSTICONRES(name) QIcon(HOSTRESPIMG(name))
|
|
|
|
WingHexDisasm::WingHexDisasm(QObject *parent) { Q_UNUSED(parent); }
|
|
|
|
bool WingHexDisasm::init(QList<WingPluginInfo> loadedplugin) {
|
|
Q_UNUSED(loadedplugin);
|
|
|
|
if (SDKVERSION < 8) {
|
|
QMessageBox::critical(nullptr, "Error",
|
|
"UnSupported Plugin System Version!",
|
|
QMessageBox::Ok);
|
|
return false;
|
|
}
|
|
|
|
auto translator = new QTranslator(this);
|
|
|
|
auto s = GETPLUGINQM("WingHexDisasm.qm");
|
|
if (!translator->load(s) || !QApplication::installTranslator(translator)) {
|
|
QMessageBox::critical(nullptr, "Error", "Error Loading Translation File!",
|
|
QMessageBox::Ok);
|
|
return false;
|
|
}
|
|
|
|
w = new QWidget;
|
|
auto vlayout = new QVBoxLayout(w);
|
|
auto hlayout = new QHBoxLayout;
|
|
|
|
hlayout->addWidget(new QLabel(tr("Arch :"), w));
|
|
hlayout->addSpacing(10);
|
|
|
|
// 默认 x86_64 64 位指令
|
|
arch = new QComboBox(w);
|
|
QStringList archs({"ARM", "ARM64", "MIPS", "X86_64", "PPC", "SPARC", "SYSZ",
|
|
"XCORE", "M68K", "TMS320C64X", "M680X", "EVM", "MOS65XX",
|
|
"WASM", "BPF", "RISCV"});
|
|
arch->addItems(archs);
|
|
arch->setCurrentIndex(3);
|
|
|
|
void (QComboBox::*indexChanged)(int index) = &QComboBox::currentIndexChanged;
|
|
connect(arch, indexChanged, [=](int index) {
|
|
switch (index) {
|
|
case 0:
|
|
carch = cs_arch::CS_ARCH_ARM;
|
|
break;
|
|
case 1:
|
|
carch = cs_arch::CS_ARCH_ARM64;
|
|
break;
|
|
case 2:
|
|
carch = cs_arch::CS_ARCH_MIPS;
|
|
break;
|
|
case 3:
|
|
carch = cs_arch::CS_ARCH_X86;
|
|
break;
|
|
case 4:
|
|
carch = cs_arch::CS_ARCH_PPC;
|
|
break;
|
|
case 5:
|
|
carch = cs_arch::CS_ARCH_SPARC;
|
|
break;
|
|
case 6:
|
|
carch = cs_arch::CS_ARCH_SYSZ;
|
|
break;
|
|
case 7:
|
|
carch = cs_arch::CS_ARCH_XCORE;
|
|
break;
|
|
case 8:
|
|
carch = cs_arch::CS_ARCH_M68K;
|
|
break;
|
|
case 9:
|
|
carch = cs_arch::CS_ARCH_TMS320C64X;
|
|
break;
|
|
case 10:
|
|
carch = cs_arch::CS_ARCH_M680X;
|
|
break;
|
|
case 11:
|
|
carch = cs_arch::CS_ARCH_EVM;
|
|
break;
|
|
case 12:
|
|
carch = cs_arch::CS_ARCH_MOS65XX;
|
|
break;
|
|
case 13:
|
|
carch = cs_arch::CS_ARCH_WASM;
|
|
break;
|
|
case 14:
|
|
carch = cs_arch::CS_ARCH_BPF;
|
|
break;
|
|
case 15:
|
|
carch = cs_arch::CS_ARCH_RISCV;
|
|
break;
|
|
}
|
|
});
|
|
|
|
hlayout->addWidget(arch);
|
|
hlayout->addSpacing(30);
|
|
|
|
hlayout->addWidget(new QLabel(tr("Mode :"), w));
|
|
hlayout->addSpacing(10);
|
|
|
|
mode = new QComboBox(w);
|
|
QStringList modes({"x16", "x32", "x64", "THUMB", "MIPS32", "MIPS64"});
|
|
mode->addItems(modes);
|
|
mode->setCurrentIndex(2);
|
|
|
|
connect(mode, indexChanged, [=](int index) {
|
|
switch (index) {
|
|
case 0:
|
|
cmode = cs_mode::CS_MODE_16;
|
|
break;
|
|
case 1:
|
|
cmode = cs_mode::CS_MODE_32;
|
|
break;
|
|
case 2:
|
|
cmode = cs_mode::CS_MODE_64;
|
|
break;
|
|
case 3:
|
|
cmode = cs_mode::CS_MODE_THUMB;
|
|
break;
|
|
case 4:
|
|
cmode = cs_mode::CS_MODE_MIPS32;
|
|
break;
|
|
case 5:
|
|
cmode = cs_mode::CS_MODE_MIPS64;
|
|
break;
|
|
}
|
|
});
|
|
|
|
hlayout->addWidget(mode);
|
|
hlayout->addSpacing(10);
|
|
|
|
cbintel = new QCheckBox("Intel", w);
|
|
cbintel->setChecked(true);
|
|
connect(cbintel, &QCheckBox::toggled, [=] { this->disasm(tmpbuf); });
|
|
hlayout->addWidget(cbintel);
|
|
vlayout->addSpacing(10);
|
|
|
|
txtAsm = new QTextBrowser(w);
|
|
txtAsm->setUndoRedoEnabled(false);
|
|
vlayout->addItem(hlayout);
|
|
vlayout->addWidget(txtAsm);
|
|
|
|
PluginDockWidgetInit(dw, w, tr("DisasmWindow"), "DisasmWindow");
|
|
|
|
PluginMenuInitBegin(menu, tr("WingHexDisasm")) {
|
|
menu->setIcon(ICONRES("icon"));
|
|
PluginMenuAddItemIconAction(menu, tr("Disasm"), ICONRES("analyse"),
|
|
WingHexDisasm::on_disasm);
|
|
PluginMenuAddItemIconAction(menu, tr("Clear"), HOSTICONRES("clearhis"),
|
|
WingHexDisasm::on_clear);
|
|
menu->addSeparator();
|
|
PluginMenuAddItemIconLamba(menu, tr("Author"), HOSTICONRES("author"), [=] {
|
|
auto authord =
|
|
newAboutDialog(QPixmap(), {":/WingHexDisasm", ":/WingHexDisasm/img"});
|
|
authord->exec();
|
|
delete authord;
|
|
});
|
|
PluginMenuAddItemIconLamba(menu, tr("Sponsor"), HOSTICONRES("sponsor"),
|
|
[=] {
|
|
auto sponsor = newSponsorDialog();
|
|
sponsor->exec();
|
|
delete sponsor;
|
|
});
|
|
}
|
|
PluginMenuInitEnd();
|
|
|
|
QMenu *tmenu;
|
|
PluginMenuInitBegin(tmenu, "") {
|
|
PluginMenuAddItemIconAction(tmenu, tr("Disasm"), ICONRES("analyse"),
|
|
WingHexDisasm::on_disasm);
|
|
PluginMenuAddItemIconAction(tmenu, tr("Clear"), HOSTICONRES("clearhis"),
|
|
WingHexDisasm::on_clear);
|
|
}
|
|
PluginMenuInitEnd();
|
|
PluginToolButtonInit(tbtn, tmenu, ICONRES("icon"));
|
|
loadSetting();
|
|
return true;
|
|
}
|
|
|
|
WingHexDisasm::~WingHexDisasm() {}
|
|
|
|
void WingHexDisasm::unload() { saveSetting(); }
|
|
|
|
int WingHexDisasm::sdkVersion() { return SDKVERSION; }
|
|
|
|
QMenu *WingHexDisasm::registerMenu() { return menu; }
|
|
|
|
QToolButton *WingHexDisasm::registerToolButton() { return tbtn; }
|
|
|
|
void WingHexDisasm::registerDockWidget(
|
|
QHash<QDockWidget *, Qt::DockWidgetArea> &rdw) {
|
|
rdw.insert(dw, Qt::DockWidgetArea::NoDockWidgetArea);
|
|
}
|
|
|
|
const QString WingHexDisasm::pluginName() { return tr("WingHexDisasm"); }
|
|
|
|
const QString WingHexDisasm::pluginAuthor() { return WINGSUMMER; }
|
|
|
|
uint WingHexDisasm::pluginVersion() { return 1; }
|
|
|
|
const QString WingHexDisasm::signature() { return WINGSUMMER; }
|
|
|
|
const QString WingHexDisasm::pluginComment() {
|
|
return tr("A small disassembly plugin for WingHexExplorer.");
|
|
}
|
|
|
|
void WingHexDisasm::plugin2MessagePipe(WingPluginMessage type,
|
|
QList<QVariant> msg) {
|
|
Q_UNUSED(type);
|
|
Q_UNUSED(msg);
|
|
}
|
|
|
|
void WingHexDisasm::disasm(QByteArray code) {
|
|
csh handle;
|
|
cs_err err = cs_open(carch, cmode, &handle);
|
|
|
|
if (err != CS_ERR_OK) {
|
|
txtAsm->setText(tr("Error: Failed capstone initialization"));
|
|
} else if (code.length()) {
|
|
size_t count;
|
|
cs_insn *insn;
|
|
cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON);
|
|
cs_option(handle, CS_OPT_SKIPDATA, CS_OPT_ON);
|
|
|
|
if (cbintel->isChecked()) {
|
|
cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_INTEL);
|
|
} else {
|
|
cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
|
|
}
|
|
|
|
auto *t = code.data();
|
|
count = cs_disasm(handle, reinterpret_cast<uint8_t *>(t),
|
|
size_t(code.size()), 0, 0, &insn);
|
|
if (count > 0) {
|
|
txtAsm->clear();
|
|
size_t j;
|
|
QStringList asms;
|
|
for (j = 0; j < count; j++) {
|
|
asms << (QString("%1 %2;").arg(insn[j].mnemonic).arg(insn[j].op_str));
|
|
}
|
|
txtAsm->setText(asms.join('\n'));
|
|
cs_free(insn, count);
|
|
} else {
|
|
txtAsm->setText(tr("Error: Failed to disassemble given op codes"));
|
|
}
|
|
cs_close(&handle);
|
|
tmpbuf.swap(code);
|
|
}
|
|
}
|
|
|
|
void WingHexDisasm::on_disasm() {
|
|
if (reader.currentDoc() < 0) {
|
|
this->toast(ICONRES("icon"), tr("No Document Opened"));
|
|
return;
|
|
}
|
|
if (reader.selectLength()) {
|
|
this->disasm(reader.selectedBytes());
|
|
} else {
|
|
this->toast(ICONRES("icon"), tr("No Selection Bytes"));
|
|
}
|
|
}
|
|
|
|
void WingHexDisasm::on_clear() { txtAsm->clear(); }
|
|
|
|
void WingHexDisasm::saveSetting() {
|
|
QSettings settings("wingsummer", "WingHexDisasm");
|
|
settings.setValue("arch", carch);
|
|
settings.setValue("mode", cmode);
|
|
}
|
|
|
|
void WingHexDisasm::loadSetting() {
|
|
QSettings settings("wingsummer", "WingHexDisasm");
|
|
carch = settings.value("arch", cs_arch::CS_ARCH_X86).value<cs_arch>();
|
|
cmode = settings.value("mode", cs_mode::CS_MODE_64).value<cs_mode>();
|
|
}
|
|
|
|
#if QT_VERSION < 0x050000
|
|
Q_EXPORT_PLUGIN2(WingHexDisasm, GenericPlugin)
|
|
#endif // QT_VERSION < 0x050000
|