#include "Mainwindow.hxx"
#include "qt.hxx"
+#include "bindings/Guile.hxx"
#include "disassembler/llvm/LLVMDisassembler.hxx"
-
+#include "core/Function.hxx"
+#include "core/BasicBlock.hxx"
+#include "core/InformationManager.hxx"
+#include "core/events/RenameFunctionEvent.hxx"
+#include "core/events/NewFunctionEvent.hxx"
+
+#include "widgets/FridaDock.hxx"
+#include "widgets/LogDock.hxx"
+#include "widgets/ScriptingDock.hxx"
#include "widgets/CFGScene.hxx"
+#include "widgets/FunctionWidget.hxx"
#include "dialogs/NewFunctionDialog.hxx"
-#include "dialogs/RenameFunctionDialog.hxx"
+#include "dialogs/SimpleStringDialog.hxx"
#include <sstream>
-namespace {
- BasicBlockWidget *
- local__add_basic_block(BasicBlock * block, Disassembler * dis,
- Mainwindow * mainwindow,
- std::map<uint64_t, BasicBlockWidget*>& known_blocks,
- CFGScene * scene, uint64_t starty, uint64_t startx);
-}
-
Mainwindow::Mainwindow(InformationManager* mgr)
: manager(mgr)
- , logger(log4cxx::Logger::getLogger("Mainwindow")) {
+ , logger(log4cxx::Logger::getLogger("gui.Mainwindow")) {
openAction = new QAction(tr("&Open"), this);
- // saveAction = new QAction(tr("&Save"), this);
+ loadAction = new QAction(tr("&Load"), this);
+ saveAction = new QAction(tr("&Save"), this);
exitAction = new QAction(tr("E&xit"), this);
- connect(openAction, SIGNAL(triggered()),
- this, SLOT(open()));
- // connect(saveAction, SIGNAL(triggered()), this, SLOT(save()));
- connect(exitAction, SIGNAL(triggered()),
- qApp, SLOT(quit()));
+ connect(openAction, &QAction::triggered,
+ this, &Mainwindow::open);
+ connect(loadAction, &QAction::triggered,
+ this, &Mainwindow::load);
+ connect(saveAction, &QAction::triggered,
+ this, &Mainwindow::save);
+ connect(exitAction, &QAction::triggered,
+ qApp, &QApplication::quit);
fileMenu = menuBar()->addMenu(tr("&File"));
fileMenu->addAction(openAction);
- // fileMenu->addAction(saveAction);
+ fileMenu->addAction(loadAction);
+ fileMenu->addAction(saveAction);
fileMenu->addSeparator();
fileMenu->addAction(exitAction);
- scripting = new ScriptingDock(tr("Scripting"), this);
- scripting->setAllowedAreas(Qt::BottomDockWidgetArea);
- addDockWidget(Qt::BottomDockWidgetArea, scripting);
-
- listWidget = new QListWidget();
+ QMenu* interpretermenu = menuBar()->addMenu(tr("&Interpreter"));
+
+ fdock = new FridaDock(tr("Frida Dock"), this);
+
+ fdock->addTab(new LogDock(fdock), "Log");
+
+ fdock->addTab(new ScriptingDock(manager->getInterpreter("GUILE"), fdock), "guile");
+ fdock->setAllowedAreas(Qt::BottomDockWidgetArea);
+ addDockWidget(Qt::BottomDockWidgetArea, fdock);
+ QAction* guileLoad = new QAction(tr("&GUILE"), this);
+ interpretermenu->addAction(guileLoad);
+ connect(guileLoad, &QAction::triggered,
+ [&]() {
+ QString fileName = QFileDialog::getOpenFileName(this, tr("Open Script"), "",
+ tr("Scripts") + " (*." +
+ manager->getInterpreter("GUILE")->fileExtension().c_str() + ")");
+ if(! fileName.isNull()) {
+ std::stringstream a, b;
+ std::string c;
+ manager->getInterpreter("GUILE")->loadFile(fileName.toStdString(), a, b, c);
+ }
+ });
+
+ listWidget = new QTreeWidget();
+ listWidget->setColumnCount(1);
+ listWidget->setDragDropMode(QAbstractItemView::InternalMove);
listWidget->setContextMenuPolicy(Qt::CustomContextMenu);
connect(listWidget, SIGNAL(customContextMenuRequested(const QPoint&)),
this, SLOT(showListContextMenu(const QPoint&)));
addDockWidget(Qt::LeftDockWidgetArea, dockWidget);
setCentralWidget(stackedWidget);
- connect(listWidget, SIGNAL(currentRowChanged(int)),
- this, SLOT(switchMainPlane(int)));
+ connect(listWidget, &QTreeWidget::currentItemChanged,
+ [=] (QTreeWidgetItem* current, QTreeWidgetItem*) {
+ switchMainPlane(current);
+ });
setWindowTitle(tr("FRIDA"));
- mgr->connect_new_function_signal([&] (Function* fun) {addFunction(fun);});
- mgr->connect_new_dyn_symbol_signal([&] (const std::string& name) {
- auto item = new QListWidgetItem(name.c_str(), listWidget);
- item->setBackground(QBrush(QColor(0xff, 0xdd, 0xdd)));
- });
+ external = new QTreeWidgetItem(listWidget, QStringList("External Functions"));
+ external->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
+ external->setBackground(0, QBrush(QColor(0xff, 0xdd, 0xdd)));
+ connect(mgr, &InformationManager::resetEvent,
+ [this,mgr]() {
+ connect(this, SIGNAL(requestNewFunctionByAddress(uint64_t)),
+ mgr->getDisassembler(), SLOT(disassembleFunctionAt(uint64_t)));
+ });
+ connect(mgr, &InformationManager::newFunctionEvent,
+ this, &Mainwindow::handleNewFunctionEvent);
+ connect(mgr, &InformationManager::renameFunctionEvent,
+ [&](RenameFunctionEvent* event) {
+ if (objects_list_by_address.find(event->address) == objects_list_by_address.end())
+ return;
+ auto item = objects_list_by_address[event->address];
+ if (item) item->setText(0, event->new_name.c_str());
+ });
setGlobalHotkeys();
}
shortcut = new QShortcut(QKeySequence("r"), listWidget);
connect(shortcut, &QShortcut::activated, [=]() {
- QListWidgetItem * item = listWidget->currentItem();
- if (item) renameFunction(item);
+ QTreeWidgetItem * item = listWidget->currentItem();
+ if (item) renameFunction(objects_list[item]->getFunction());
});
}
+void Mainwindow::handleNewFunctionEvent(NewFunctionEvent event) {
+ std::string name = event.function->getName();
+ if (event.function->isDynamic()) {
+ auto item = new QTreeWidgetItem(external, QStringList(name.c_str()));
+ item->setBackground(0, QBrush(QColor(0xff, 0xdd, 0xdd)));
+ } else {
+ addFunction(event.function);
+ }
+}
+
void Mainwindow::quit()
{
QMessageBox messageBox;
}
void Mainwindow::open() {
- QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), "",
- tr("Binaries (*)"));
+ QFileDialog dialog(this, tr("Open bianry"), "", tr("Binaries (*)"));
+
+ if (dialog.exec()) {
+ QStringList files = dialog.selectedFiles();
+ if(1 != files.size()) {
+ LOG4CXX_ERROR(logger, "Needs exactly one file name")
+ } else {
+ manager->reset(files[0].toStdString());
+ }
+ }
+}
+
+void Mainwindow::load() {
+ QFileDialog dialog(this, tr("Open saved FrIDa file"), "", tr("Frida Archives (*.frida)"));
- manager->reset(fileName.toStdString());
+ if (dialog.exec()) {
+ QStringList files = dialog.selectedFiles();
+ if(1 != files.size()) {
+ LOG4CXX_ERROR(logger, "Needs exactly one file name")
+ } else {
+ manager->load(files[0].toStdString());
+ }
+ }
+}
+
+void Mainwindow::save() {
+ QString filename = QFileDialog::getSaveFileName(this, tr("Save File"), "", tr("Frida Archives (*.frida)"));
+ manager->save(filename.toStdString());
}
void Mainwindow::switchMainPlaneToAddress(uint64_t address) {
if (objects_list_by_address.find(address) != objects_list_by_address.end()) {
LOG4CXX_DEBUG(logger, "Switching to function " << std::hex << address);
- QListWidgetItem * item = objects_list_by_address[address];
+ QTreeWidgetItem * item = objects_list_by_address[address];
listWidget->setCurrentItem(item);
stackedWidget->setCurrentWidget(objects_list[item]);
} else {
}
}
-void Mainwindow::switchMainPlane(int index) {
- stackedWidget->setCurrentWidget(objects_list[listWidget->currentItem()]);
+void Mainwindow::switchMainPlane(QTreeWidgetItem* to) {
+ if (objects_list.end() != objects_list.find(to))
+ stackedWidget->setCurrentWidget(objects_list[to]);
}
void Mainwindow::showListContextMenu(const QPoint& point) {
- QListWidgetItem * item = listWidget->itemAt(point);
+ QAction * act;
+ QTreeWidgetItem * item = listWidget->itemAt(point);
QMenu menu(this);
+
+ act = menu.addAction("Add Function");
+ connect(act, &QAction::triggered, this, &Mainwindow::requestNewFunction);
+
+ act = menu.addAction("Add Group");
+ connect(act, &QAction::triggered, this, &Mainwindow::requestNewGroup);
+
if (item) {
- QAction * act = menu.addAction("Rename Function");
- connect(act, &QAction::triggered, [=]() {this->renameFunction(item);});
- } else {
- QAction * act = menu.addAction("AddFunction");
- connect(act, SIGNAL(triggered()), this, SLOT(requestNewFunction()));
+ if (objects_list.find(item) != objects_list.end()) {
+ act = menu.addAction("Rename Function");
+ connect(act, &QAction::triggered, [=]() {this->renameFunction(objects_list[item]->getFunction());});
+ } else {
+ act = menu.addAction("Rename Group");
+ connect(act, &QAction::triggered, [=]() {renameGroup(item);});
+ }
+
+
+ QMenu* submenu = menu.addMenu("Move to group");
+
+ for (QTreeWidgetItem* groupitem : group_list) {
+ act = submenu->addAction(groupitem->text(0));
+ connect(act, &QAction::triggered,
+ [=] () {
+ listWidget->invisibleRootItem()->removeChild(item);
+ groupitem->addChild(item);
+ });
+ }
}
+
menu.exec(listWidget->mapToGlobal(point));
}
NewFunctionDialog dialog;
int result = dialog.exec();
if (QDialog::Accepted == result) {
- requestNewFunctionByAddress(dialog.result());
+ emit requestNewFunctionByAddress(dialog.result());
} else {
LOG4CXX_DEBUG(logger, "requestNewFunction aborted");
}
}
-void Mainwindow::requestNewFunctionByAddress(uint64_t address) {
- LOG4CXX_DEBUG(logger, "requesting Function at " << std::hex << address);
- manager->getDisassembler()->disassembleFunctionAt(address);
- switchMainPlaneToAddress(address);
+void Mainwindow::requestNewGroup() {
+ SimpleStringDialog dialog("New Group");
+ int result = dialog.exec();
+ if (QDialog::Accepted == result) {
+ QTreeWidgetItem * external = new QTreeWidgetItem(listWidget, QStringList(dialog.result()));
+ external->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
+ group_list.push_back(external);
+ } else {
+ LOG4CXX_DEBUG(logger, "requestNewGroup aborted");
+ }
}
-void Mainwindow::renameFunction(QListWidgetItem * item) {
- RenameFunctionDialog dialog;
+void Mainwindow::renameFunction(Function* function) {
+ SimpleStringDialog dialog("New name");
int result = dialog.exec();
if (QDialog::Accepted == result) {
- LOG4CXX_DEBUG(logger, "renaming Function " << item->text().toStdString()
+ LOG4CXX_DEBUG(logger, "renaming Function " << function->getName()
<< " to " << dialog.result().toStdString());
- item->setText(dialog.result());
+ function->setName(dialog.result().toStdString());
} else {
LOG4CXX_DEBUG(logger, "renameFunction aborted");
}
}
-void Mainwindow::addFunction(Function* fun) {
- if (functions.find(fun) != functions.end())
- return;
-
- functions.insert(fun);
-
- QTabWidget * w = new QTabWidget();
-
- // CFG
- CFGScene * scene = new CFGScene;
-
- Disassembler * dis = manager->getDisassembler();
- BasicBlock * block = dis->getBasicBlock(fun->getStartAddress());
-
- uint64_t start_address(std::numeric_limits<uint64_t>::max());
- for (auto b : fun->blocks()) {
- if (b.first < start_address)
- start_address = b.first;
+void Mainwindow::renameGroup(QTreeWidgetItem* item) {
+ SimpleStringDialog dialog("New name");
+ int result = dialog.exec();
+ if (QDialog::Accepted == result) {
+ LOG4CXX_DEBUG(logger, "renaming group " << item->text(0).toStdString()
+ << " to " << dialog.result().toStdString());
+ item->setText(0, dialog.result());
+ } else {
+ LOG4CXX_DEBUG(logger, "renameFunction aborted");
}
+}
- local__add_basic_block(block, manager->getDisassembler(), this,
- blocks, scene, start_address, 100);
-
- QGraphicsView * view = new QGraphicsView(scene);
- w->addTab(view, "CFG");
+void Mainwindow::addFunction(Function* fun) {
+ if (functions.find(fun->getStartAddress()) != functions.end())
+ return;
- // Listing
- QTableWidget * t = new QTableWidget();
- t->setColumnCount(3);
- t->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
+ functions.insert(std::make_pair(fun->getStartAddress(), fun));
- w->addTab(t, "Listing");
+ FunctionWidget * w = new FunctionWidget(fun, this);
- QListWidgetItem * item = new QListWidgetItem(fun->getName().c_str(), listWidget);
+ QTreeWidgetItem * item = new QTreeWidgetItem(listWidget, QStringList(fun->getName().c_str()));
stackedWidget->addWidget(w);
objects_list.insert(std::make_pair(item, w));
LOG4CXX_DEBUG(logger, "Adding function widget at " << std::hex
<< fun->getStartAddress());
objects_list_by_address.insert(std::make_pair(fun->getStartAddress(), item));
}
-
-namespace {
- BasicBlockWidget *
- local__add_basic_block(BasicBlock * block, Disassembler * dis,
- Mainwindow * mainwindow,
- std::map<uint64_t, BasicBlockWidget*>& known_blocks,
- CFGScene * scene, uint64_t starty, uint64_t startx) {
-
- decltype(known_blocks.begin()) old;
- if ((old = known_blocks.find(block->getStartAddress())) != known_blocks.end())
- return old->second;
-
- std::stringstream s;
- s << "BLOCK_" << std::hex << block->getStartAddress()
- << "_" << block->getEndAddress();
- BasicBlockWidget * widget = new BasicBlockWidget(s.str().c_str(),
- block, mainwindow);
-
- known_blocks.insert(std::make_pair(block->getStartAddress(), widget));
-
- scene->addItem(widget);
- widget->setFlag(QGraphicsItem::ItemIsMovable, true);
- widget->moveBy(100*startx, block->getStartAddress() - starty);
-
- dis->printEachInstruction(block->getStartAddress(),
- block->getEndAddress(),
- [&](uint8_t* bytes,
- size_t byte_count,
- const std::string& line,
- const std::string& ref) {
- widget->addItem(bytes, byte_count,
- line.c_str() + 1, // remove \t
- ref.c_str());
- });
-
- BasicBlockWidget *tmp, *nextl(NULL), *nextr(NULL);
- BasicBlock * tmpblock;
- if (block->getNextBlock(0) != 0) {
- int xshift = 0;
- if (block->getNextBlock(1) != 0)
- xshift = 1;
- tmpblock = dis->getBasicBlock(block->getNextBlock(0));
- tmp = local__add_basic_block(tmpblock, dis,
- mainwindow,
- known_blocks,
- scene, starty, startx+xshift);
- nextl = tmp;
- tmp->addPrevious(widget);
- }
- if (block->getNextBlock(1) != 0) {
- tmpblock = dis->getBasicBlock(block->getNextBlock(1));
- tmp = local__add_basic_block(tmpblock, dis,
- mainwindow,
- known_blocks,
- scene, starty, startx-1);
- nextr = tmp;
- tmp->addPrevious(widget);
- }
- widget->addNext(nextl, nextr);
- return widget;
- }
-}