blob: 2910eaf9ea9b5f6968d26df6b650eac954f232e0 [file] [log] [blame] [raw]
/* PE Header Editor
Copyright 2007-2014 PC GO Ld.
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*/
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "options.h"
#include "ui_options.h"
#include "pe-struct.h"
#include <assert.h>
#include <QtCore/QDebug>
#include <QtCore/QFile>
#include <QtCore/QSettings>
#include <QtGui/QCloseEvent>
#include <QtGui/QFileDialog>
#include <QtGui/QMessageBox>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent), ui(new Ui::MainWindow) {
ui->setupUi(this);
is_modified = false;
pe = NULL;
set_current_file(0);
}
MainWindow::~MainWindow() {
delete ui;
}
void MainWindow::load(const QString &filename) {
QFile file(filename, this);
if(!file.open(QFile::ReadOnly)) {
QString msg = tr("Load file %1 failed").arg(filename);
QMessageBox::warning(this, 0, msg);
ui->statusBar->showMessage(msg, 10);
return;
}
file.seek(0x3c);
QDataStream s(&file);
if(s.readRawData((char *)&pe_offset, sizeof pe_offset) < 1) {
QString msg = tr("Cannot locate the PE header");
QMessageBox::warning(this, 0, msg);
goto failed;
}
if(!pe_offset) {
QString msg = tr("Unexcepted PE offset, %1 may not a valid PE file").arg(filename);
QMessageBox::warning(this, 0, msg);
goto failed;
}
file.seek(pe_offset);
if(!pe) pe = new PortableExecutable;
if(s.readRawData((char *)pe, sizeof(PortableExecutable)) < 1) {
QString msg = tr("Cannot read PE header");
QMessageBox::warning(this, 0, msg);
goto failed;
}
//qDebug("pe->pe_signature = 0x%x", pe->pe_signature);
if(pe->pe_signature != 0x4550) {
QString msg = tr("The PE signature not found, %1 may not a valid PE file\n").arg(filename);
QMessageBox::warning(this, 0, msg);
goto failed;
}
update_table();
ui->TreeWidget->setEnabled(true);
ui->action_SaveAs->setEnabled(true);
ui->ReferenceBrowser->setEnabled(true);
set_current_file(filename);
return;
failed:
if(pe) {
delete pe;
pe = NULL;
}
file.close();
}
void MainWindow::open_file() {
if(!maybe_save()) return;
QString filename = QFileDialog::getOpenFileName(this, NULL, NULL, NULL, NULL, QFileDialog::DontUseNativeDialog);
if(!filename.isEmpty()) load(filename);
}
bool MainWindow::save_file(const QString &filename) {
if(!QFile::exists(current_file)) {
QString msg = tr("Cannot save because the file %1 is removed").arg(current_file);
QMessageBox::warning(this, 0, msg);
ui->statusBar->showMessage(msg, 10);
return false;
}
QFile old_file(current_file, this);
if(!old_file.copy(filename)) {
QString msg = tr("Cannot create file %1 for copying").arg(filename);
QMessageBox::warning(this, 0, msg);
ui->statusBar->showMessage(msg, 10);
return false;
}
set_current_file(filename);
old_file.close();
return is_modified ? save_file() : true;
}
bool MainWindow::save_file() {
if(!QFile::exists(current_file)) {
QString msg = tr("Cannot save because the file %1 is removed").arg(current_file);
QMessageBox::warning(this, 0, msg);
ui->statusBar->showMessage(msg, 10);
return true; // Returns true because we can't save this file any more
}
if(config->value("SavingConfirm", true).toBool()) {
if(QMessageBox::information(this, "PE Header Editor", tr("Are you sure you want to overwrite this file?"), QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) {
return false;
}
}
QFile file(current_file, this);
// XXX: If we use QFile::WriteOnly, the file will be truncated, that is a bug of Qt?
if(!file.open(QFile::ReadWrite)) {
QString msg = tr("Cannot open file %1 for writing").arg(current_file);
QMessageBox::warning(this, 0, msg);
ui->statusBar->showMessage(msg, 10);
return false;
}
file.seek(pe_offset);
QDataStream s(&file);
if(s.writeRawData((const char *)pe, sizeof(PortableExecutable)) < 1) {
QString msg = tr("Write failed");
QMessageBox::warning(this, 0, msg);
ui->statusBar->showMessage(msg, 10);
return false;
}
file.close();
ui->statusBar->showMessage(tr("File %1 saved").arg(current_file));
set_modified(false);
return true;
}
bool MainWindow::save_file_as() {
QString filename = QFileDialog::getSaveFileName(this, tr("Save As"), current_file, NULL, NULL, QFileDialog::DontUseNativeDialog);
if(filename.isEmpty()) return false;
return save_file(filename);
}
void MainWindow::modified() {
set_modified(true);
}
void MainWindow::set_modified(bool mod) {
setWindowModified(mod);
is_modified = mod;
ui->action_Save->setEnabled(mod);
}
bool MainWindow::maybe_save() {
if(is_modified) {
QMessageBox::StandardButton r = QMessageBox::warning(this, 0,
tr("The table has been modified.\nDo you want to save your changes?"),
QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
if(r == QMessageBox::Save) return save_file();
if(r == QMessageBox::Cancel) return false;
}
return true;
}
QString MainWindow::stripped_name(const QString &filename) {
return QFileInfo(filename).fileName();
}
void MainWindow::set_current_file(const QString &filename) {
//static int seq_number = 1;
//is_untitled = filename.isEmpty();
//if(is_untitled) {
if(filename.isEmpty()) {
setWindowTitle(tr("PE Header Editor"));
} else {
current_file = QFileInfo(filename).canonicalFilePath();
setWindowTitle(QString("%1[*] - %2").arg(stripped_name(current_file)).arg(tr("PE Header Editor")));
}
is_modified = false;
setWindowModified(false);
}
/*
void MainWindow::init_value_reference() {
QTreeWidget
}*/
void MainWindow::set_pe_header_item(const QString &name, uint8_t value, const QString &comment) {
QString v;
v.sprintf(config->value("Hexadecimal", true).toBool() ? "0x%hhx" : "%hhu", value);
set_pe_header_item(name, v, comment, "uint8");
}
void MainWindow::set_pe_header_item(const QString &name, uint16_t value, const QString &comment) {
QString v;
v.sprintf(config->value("Hexadecimal", true).toBool() ? "0x%hhx" : "%hhu", value);
set_pe_header_item(name, v, comment, "uint16");
}
void MainWindow::set_pe_header_item(const QString &name, uint32_t value, const QString &comment) {
QString v;
v.sprintf(config->value("Hexadecimal", true).toBool() ? "0x%hhx" : "%hhu", value);
set_pe_header_item(name, v, comment, "uint32");
}
void MainWindow::set_pe_header_item(const QString &name, const QString &value, const QString &comment, const QString &type) {
//qDebug("function: add_pe_header_item(%s, %s, %s, %s)", name.toLocal8Bit().data(), value.toLocal8Bit().data(), comment.toLocal8Bit().data(), type.toLocal8Bit().data());
qDebug() << value;
QTreeWidgetItem *item;
QList<QTreeWidgetItem *> r = ui->TreeWidget->findItems(name, Qt::MatchFixedString, 0);
int exists = r.length();
if(exists) {
assert(exists == 1);
item = r[0];
} else {
item = new QTreeWidgetItem;
item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
}
item->setText(0, name);
item->setText(1, type);
item->setText(2, value);
item->setText(3, comment);
if(!exists) ui->TreeWidget->addTopLevelItem(item);
}
QString MainWindow::get_comment_from_value_reference(const QTreeWidget *value_reference, const QString &value) {
int value_count = value_reference->topLevelItemCount();
//if(!value_count) return QString();
while(value_count--) {
QTreeWidgetItem *value_item = value_reference->topLevelItem(value_count);
if(value_item->text(0) == value) return value_item->text(1);
}
return QString();
}
QString MainWindow::get_comment_and_update(const QString &name, uint32_t value, bool update_struct, bool update_reference) {
if(name == "machine") {
if(update_struct) pe->machine = value;
if(update_reference) {
ui->ReferenceBrowser->setText(tr("Machine\nWhat platform the program running"));
ui->stackedWidget->setCurrentWidget(ui->page_machine);
return QString();
}
QString v;
v.sprintf("0x%x", value);
return get_comment_from_value_reference(ui->ValueReference_machine, v);
} else if(name == "sections_count") {
if(update_struct) pe->sections_count = value;
if(update_reference) {
ui->ReferenceBrowser->setText(tr("Sections Count"));
ui->stackedWidget->setCurrentWidget(ui->page_empty);
}
return QString();
} else if(name == "time_stamp") {
if(update_struct) pe->time_stamp = value;
if(update_reference) {
ui->ReferenceBrowser->setText(tr("Time Stamp"));
ui->stackedWidget->setCurrentWidget(ui->page_empty);
}
return QString ();
} else if(name == "symbol_table_pointer") {
if(update_struct) pe->symbol_table_pointer = value;
if(update_reference) {
ui->ReferenceBrowser->setText(tr("Symbol Table Pointer"));
ui->stackedWidget->setCurrentWidget(ui->page_empty);
}
return QString ();
} else if(name == "symbols_count") {
if(update_struct) pe->symbols_count = value;
if(update_reference) {
ui->ReferenceBrowser->setText(tr("Symbols Count"));
ui->stackedWidget->setCurrentWidget(ui->page_empty);
}
return QString ();
} else if(name == "optional_header_size") {
if(update_struct) pe->optional_header_size = value;
if(update_reference) {
ui->ReferenceBrowser->setText(tr("Optional Header Size"));
ui->stackedWidget->setCurrentWidget(ui->page_empty);
}
return QString ();
} else if(name == "characteristics") {
if(update_struct) pe->characteristics = value;
if(update_reference) {
ui->ReferenceBrowser->setText(tr("Characteristics"));
ui->stackedWidget->setCurrentWidget(ui->page_characteristics);
return QString ();
}
QString v;
v.sprintf("0x%x", value);
return get_comment_from_value_reference(ui->ValueReference_characteristics, v);
} else if(name == "magic") {
if(update_struct) pe->magic = value;
if(update_reference) {
ui->ReferenceBrowser->setText(tr("magic"));
ui->stackedWidget->setCurrentWidget(ui->page_magic);
}
QString v;
v.sprintf("0x%x", value);
return get_comment_from_value_reference(ui->ValueReference_magic, v);
} else if(name == "major_linker_version") {
if(update_struct) pe->major_linker_version = value;
if(update_reference) {
ui->ReferenceBrowser->setText(tr("Major Linker Version"));
ui->stackedWidget->setCurrentWidget(ui->page_empty);
}
return QString ();
} else if(name == "minor_linker_version") {
if(update_struct) pe->minor_linker_version = value;
if(update_reference) {
ui->ReferenceBrowser->setText(tr("Minor Linker Version"));
ui->stackedWidget->setCurrentWidget(ui->page_empty);
}
return QString ();
} else if(name == "code_size") {
if(update_struct) pe->code_size = value;
if(update_reference) {
ui->ReferenceBrowser->setText(tr("Code Size"));
ui->stackedWidget->setCurrentWidget(ui->page_empty);
}
return QString ();
} else if(name == "initialized_data_size") {
if(update_struct) pe->initialized_data_size = value;
if(update_reference) {
ui->ReferenceBrowser->setText(tr("Initialized data size"));
ui->stackedWidget->setCurrentWidget(ui->page_empty);
}
return QString ();
} else if(name == "uninitialized_data_size") {
if(update_struct) pe->uninitialized_data_size = value;
if(update_reference) {
ui->ReferenceBrowser->setText(tr("Uninitialized data size"));
ui->stackedWidget->setCurrentWidget(ui->page_empty);
}
return QString ();
} else if(name == "entry_point_address") {
if(update_struct) pe->entry_point_address = value;
if(update_reference) {
ui->ReferenceBrowser->setText(tr("Entry point address"));
ui->stackedWidget->setCurrentWidget(ui->page_empty);
}
return QString ();
} else if(name == "code_base") {
if(update_struct) pe->code_base = value;
if(update_reference) {
ui->ReferenceBrowser->setText(tr("Code base"));
ui->stackedWidget->setCurrentWidget(ui->page_empty);
}
return QString ();
} else if(name == "data_base") {
if(update_struct) pe->data_base = value;
if(update_reference) {
ui->ReferenceBrowser->setText(tr("Data base"));
ui->stackedWidget->setCurrentWidget(ui->page_empty);
}
return QString ();
} else if(name == "image_base") {
if(update_struct) pe->image_base = value;
if(update_reference) {
ui->ReferenceBrowser->setText(tr("Image base"));
ui->stackedWidget->setCurrentWidget(ui->page_empty);
}
return QString ();
} else if(name == "section_alignment") {
if(update_struct) pe->section_alignment = value;
if(update_reference) {
ui->ReferenceBrowser->setText(tr("Section alignment"));
ui->stackedWidget->setCurrentWidget(ui->page_empty);
}
return QString ();
} else if(name == "file_alignment") {
if(update_struct) pe->file_alignment = value;
if(update_reference) {
ui->ReferenceBrowser->setText(tr("File alignment"));
ui->stackedWidget->setCurrentWidget(ui->page_empty);
}
return QString ();
} else if(name == "major_os_version") {
if(update_struct) pe->major_os_version = value;
if(update_reference) {
ui->ReferenceBrowser->setText(tr("Major OS version"));
ui->stackedWidget->setCurrentWidget(ui->page_empty);
}
return QString ();
} else if(name == "minor_os_version") {
if(update_struct) pe->minor_os_version = value;
if(update_reference) {
ui->ReferenceBrowser->setText(tr("Minor OS version"));
ui->stackedWidget->setCurrentWidget(ui->page_empty);
}
return QString ();
} else if(name == "major_image_version") {
if(update_struct) pe->major_image_version = value;
if(update_reference) {
ui->ReferenceBrowser->setText(tr("Major image version"));
ui->stackedWidget->setCurrentWidget(ui->page_empty);
}
return QString ();
} else if(name == "minor_image_version") {
if(update_struct) pe->minor_image_version = value;
if(update_reference) {
ui->ReferenceBrowser->setText(tr("Minor image version"));
ui->stackedWidget->setCurrentWidget(ui->page_empty);
}
return QString ();
} else if(name == "major_subsystem_version") {
if(update_struct) pe->major_subsystem_version = value;
if(update_reference) {
ui->ReferenceBrowser->setText(tr("Major subsystem version"));
ui->stackedWidget->setCurrentWidget(ui->page_empty);
}
return QString ();
} else if(name == "minor_subsystem_version") {
if(update_struct) pe->minor_subsystem_version = value;
if(update_reference) {
ui->ReferenceBrowser->setText(tr("Minor subsystem version"));
ui->stackedWidget->setCurrentWidget(ui->page_empty);
}
return QString ();
} else if(name == "may_be_a_version") {
if(update_struct) pe->may_be_a_version = value;
if(update_reference) {
ui->ReferenceBrowser->setText(tr("Reserved, may be a version"));
ui->stackedWidget->setCurrentWidget(ui->page_empty);
}
return QString ();
} else if(name == "image_size") {
if(update_struct) pe->image_size = value;
if(update_reference) {
ui->ReferenceBrowser->setText(tr("Image size"));
ui->stackedWidget->setCurrentWidget(ui->page_empty);
}
return QString ();
} else if(name == "headers_size") {
if(update_struct) pe->headers_size = value;
if(update_reference) {
ui->ReferenceBrowser->setText(tr("Headers size"));
ui->stackedWidget->setCurrentWidget(ui->page_empty);
}
return QString ();
} else if(name == "check_sum") {
if(update_struct) pe->check_sum = value;
if(update_reference) {
ui->ReferenceBrowser->setText(tr("Check sum"));
ui->stackedWidget->setCurrentWidget(ui->page_empty);
}
return QString ();
} else if(name == "subsystem") {
if(update_struct) pe->subsystem = value;
if(update_reference) {
ui->ReferenceBrowser->setText(tr("Subsystem"));
ui->stackedWidget->setCurrentWidget(ui->page_subsystem);
return QString();
}
QString v;
v.sprintf("%u", value);
return get_comment_from_value_reference(ui->ValueReference_subsystem, v);
}
return QString();
}
/*
void MainWindow::update_references(const QString &name) {
int items_count = ui->stackedWidget->count();
for(int i=1; i<items_count; i++) {
}
}*/
void MainWindow::update_item_value(QTreeWidgetItem *item) {
//update_references(item->text(0));
QString v = item->text(2);
int base = v.startsWith("0x") ? 16 : 10;
item->setText(3, get_comment_and_update(item->text(0), v.toUInt(NULL, base), true, false));
}
void MainWindow::update_references(QTreeWidgetItem *item) {
// Didn't need value when we updating the reference
get_comment_and_update(item->text(0), 0, false, true);
}
#define DEFINE_PE_HEADER_ITEM(NAME) set_pe_header_item(#NAME, pe->NAME, get_comment_and_update(#NAME, pe->NAME, false, false))
void MainWindow::update_table() {
DEFINE_PE_HEADER_ITEM(machine);
DEFINE_PE_HEADER_ITEM(sections_count);
DEFINE_PE_HEADER_ITEM(time_stamp);
DEFINE_PE_HEADER_ITEM(symbol_table_pointer);
DEFINE_PE_HEADER_ITEM(symbols_count);
DEFINE_PE_HEADER_ITEM(optional_header_size);
DEFINE_PE_HEADER_ITEM(characteristics);
DEFINE_PE_HEADER_ITEM(magic);
DEFINE_PE_HEADER_ITEM(major_linker_version);
DEFINE_PE_HEADER_ITEM(minor_linker_version);
DEFINE_PE_HEADER_ITEM(code_size);
DEFINE_PE_HEADER_ITEM(initialized_data_size);
DEFINE_PE_HEADER_ITEM(uninitialized_data_size);
DEFINE_PE_HEADER_ITEM(entry_point_address);
DEFINE_PE_HEADER_ITEM(code_base);
DEFINE_PE_HEADER_ITEM(data_base);
DEFINE_PE_HEADER_ITEM(image_base);
DEFINE_PE_HEADER_ITEM(section_alignment);
DEFINE_PE_HEADER_ITEM(file_alignment);
DEFINE_PE_HEADER_ITEM(major_os_version);
DEFINE_PE_HEADER_ITEM(minor_os_version);
DEFINE_PE_HEADER_ITEM(major_image_version);
DEFINE_PE_HEADER_ITEM(minor_image_version);
DEFINE_PE_HEADER_ITEM(major_subsystem_version);
DEFINE_PE_HEADER_ITEM(minor_subsystem_version);
DEFINE_PE_HEADER_ITEM(may_be_a_version);
DEFINE_PE_HEADER_ITEM(image_size);
DEFINE_PE_HEADER_ITEM(headers_size);
DEFINE_PE_HEADER_ITEM(check_sum);
DEFINE_PE_HEADER_ITEM(subsystem);
}
void MainWindow::edit_item(QTreeWidgetItem *item, int column) {
qDebug("slot: edit_item(%p, %d)", item, column);
item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable);
ui->TreeWidget->editItem(item, 2);
item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
}
void MainWindow::about() {
QMessageBox::about(this, tr("About"), tr("<h3>PE Header Editor %1</h3>Copyright 2007-2014 PC GO Ld.<br><br>").arg(VERSION) +
tr("This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.<br>"
"This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details."));
}
void MainWindow::load_ui_layout() {
QSize windowsize = config->value("MainWindowSize").toSize();
if(windowsize.width() > 0 && windowsize.height() > 0) resize(windowsize);
ui->DockWidget_Reference->setVisible(config->value("ShowInformationWidget", true).toBool());
ui->DockWidget_ValueReference->setVisible(config->value("ShowValueReferenceWidget", true).toBool());
}
void MainWindow::save_ui_layout() {
qDebug("slot: save_ui_layout()");
config->setValue("ShowInformationWidget", ui->DockWidget_Reference->isVisible());
config->setValue("ShowValueReferenceWidget", ui->DockWidget_ValueReference->isVisible());
if(!isMaximized()) config->setValue("MainWindowSize", size());
}
void MainWindow::closeEvent(QCloseEvent *event) {
if(maybe_save()) {
save_ui_layout();
event->accept();
} else {
event->ignore();
}
}
void MainWindow::options() {
Options d;
bool m = is_modified;
d.ui->checkBox_confirm->setChecked(config->value("SavingConfirm", true).toBool());
bool hex1 = config->value("Hexadecimal", true).toBool();
d.ui->checkBox_hex->setChecked(hex1);
d.ui->checkBox_toolbar_label->setChecked(config->value("ShowToolBarTextLabel", true).toBool());
d.ui->checkBox_info_widget->setChecked(config->value("ShowInformationWidget", true).toBool());
d.ui->checkBox_ref_widget->setChecked(config->value("ShowValueReferenceWidget", true).toBool());
if(d.exec()) {
config->setValue("SavingConfirm", d.ui->checkBox_confirm->isChecked());
bool hex2 = d.ui->checkBox_hex->isChecked();
config->setValue("Hexadecimal", hex2);
config->setValue("ShowToolBarTextLabel", d.ui->checkBox_toolbar_label->isChecked());
config->setValue("ShowInformationWidget", d.ui->checkBox_info_widget->isChecked());
config->setValue("ShowValueReferenceWidget", d.ui->checkBox_ref_widget->isChecked());
load_ui_layout();
if(hex1 != hex2) {
update_table();
set_modified(m);
}
}
}