diff --git a/trunk/datainterpretertable.cpp b/trunk/datainterpretertable.cpp index f4efd41..63e6aa6 100644 --- a/trunk/datainterpretertable.cpp +++ b/trunk/datainterpretertable.cpp @@ -1,111 +1,111 @@ /******************************************************************************* * fred Copyright (c) 2011-2013 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * 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 3 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. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ -#include "datainterpretertable.h" - #include #include #include #include #include +#include "datainterpretertable.h" + DataInterpreterTable::DataInterpreterTable(QWidget *p_parent) : QTableWidget(p_parent) { this->setColumnCount(2); this->setTextElideMode(Qt::ElideNone); this->horizontalHeader()->setHidden(true); this->verticalHeader()->setHidden(true); this->setSelectionBehavior(QAbstractItemView::SelectRows); this->setSelectionMode(QAbstractItemView::SingleSelection); // Create context menu actions this->p_action_copy_value=new QAction(tr("Copy value"),this); this->connect(this->p_action_copy_value, SIGNAL(triggered()), this, SLOT(SlotCopyValue())); } DataInterpreterTable::~DataInterpreterTable() { // Free table widget items this->ClearValues(); // Delete context menu actions delete this->p_action_copy_value; } void DataInterpreterTable::AddValue(QString name, QString value) { QTableWidgetItem *p_name_item=new QTableWidgetItem(name); p_name_item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); QTableWidgetItem *p_value_item=new QTableWidgetItem(value); p_value_item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); this->setRowCount(this->rowCount()+1); this->setItem(this->rowCount()-1,0,p_name_item); this->setItem(this->rowCount()-1,1,p_value_item); this->resizeColumnsToContents(); this->resizeRowsToContents(); } void DataInterpreterTable::ClearValues() { // Free all items while(this->rowCount()>0) { delete this->item(0,0); delete this->item(0,1); this->setRowCount(this->rowCount()-1); } } int DataInterpreterTable::sizeHintForColumn(int column) const { int size_hint=0; int i=0; int item_width=0; QFontMetrics fm(this->fontMetrics()); // Find string that needs the most amount of space for(i=0;irowCount();i++) { item_width=fm.width(this->item(i,column)->text())+10; if(item_width>size_hint) size_hint=item_width; } return size_hint; } void DataInterpreterTable::contextMenuEvent(QContextMenuEvent *p_event) { // Only show context menu when a node is selected if(this->selectedIndexes().count()!=2) return; // Only show context menu when user clicked on selected row if(!(this->indexAt(p_event->pos())==this->selectedIndexes().at(0) || this->indexAt(p_event->pos())==this->selectedIndexes().at(1))) { return; } // Create context menu and add actions QMenu context_menu(this); context_menu.addAction(this->p_action_copy_value); context_menu.exec(p_event->globalPos()); } void DataInterpreterTable::SlotCopyValue() { QApplication::clipboard()-> setText(this->selectedIndexes().at(1).data().toString(), QClipboard::Clipboard); } diff --git a/trunk/dlgaddkey.cpp b/trunk/dlgaddkey.cpp index 2989fa7..ff966c6 100644 --- a/trunk/dlgaddkey.cpp +++ b/trunk/dlgaddkey.cpp @@ -1,446 +1,441 @@ /******************************************************************************* * fred Copyright (c) 2011-2013 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * 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 3 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. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #include #include #include #include #include #include #include "dlgaddkey.h" #include "ui_dlgaddkey.h" #include "registryhive.h" #define MACROS_ENDIANNESS #include "macros.h" DlgAddKey::DlgAddKey(QWidget *p_parent, QString key_name, QString key_value_type, QByteArray key_value) : QDialog(p_parent), ui(new Ui::DlgAddKey) { this->p_current_widget=NULL; ui->setupUi(this); this->ansi_encoded=false; // Create widgets this->CreateValueWidgets(); // Set dialog title if(key_name.isEmpty() && key_value_type.isEmpty() && key_value.isEmpty()) { // If no values were passed, we consider this the ddd key dialog this->setWindowTitle(tr("Add key")); } else { // If a value was passed, this is considered the edit key dialog this->setWindowTitle(tr("Edit key")); this->ui->EdtKeyName->setEnabled(false); this->ui->CmbKeyType->setEnabled(false); } // Preload key value type values QStringList value_types=RegistryHive::GetKeyValueTypes(); this->ui->CmbKeyType->addItems(value_types); // Load values if(!key_name.isEmpty()) this->ui->EdtKeyName->setText(key_name); if(!key_value_type.isEmpty()) this->ui->CmbKeyType->setCurrentIndex(value_types.indexOf(key_value_type)); if(!key_value.isEmpty()) this->SetValueWidgetData(key_value,key_value_type); // Connect signals this->connect(this->p_number_widget_rb_dec, SIGNAL(clicked(bool)), this, SLOT(SlotNumberWidgetRbDecClicked(bool))); this->connect(this->p_number_widget_rb_hex, SIGNAL(clicked(bool)), this, SLOT(SlotNumberWidgetRbHexClicked(bool))); } DlgAddKey::~DlgAddKey() { this->DestroyValueWidgets(); delete ui; } QString DlgAddKey::KeyName() { return this->ui->EdtKeyName->text(); } QString DlgAddKey::KeyType() { return this->ui->CmbKeyType->currentText(); } QByteArray DlgAddKey::KeyValue() { return this->GetValueWidgetData(); } void DlgAddKey::on_BtnCancel_clicked() { this->reject(); } void DlgAddKey::on_BtnOk_clicked() { QString key_value_type=this->KeyType(); // Check entered data for correctness if(key_value_type=="REG_MULTI_SZ") { // REG_MULTI_SZ's can't contain empty sub-strings QString cur_data=this->p_text_widget_text_edit->toPlainText(); QString new_data=cur_data; // TODO: Do we need to check for \r\n on Windows?? new_data.replace(QRegExp("\n\n*"),"\n"); if(new_data.startsWith("\n")) new_data.remove(0,1); if(new_data.endsWith("\n")) new_data.chop(1); if(cur_data!=new_data) { if(QMessageBox::information(this, tr("Invalid data"), tr("A REG_MULTI_SZ can not contain empty " "sub-strings! If you continue, they " "will be removed."), QMessageBox::Yes, QMessageBox::No)==QMessageBox::Yes) { this->p_text_widget_text_edit->setPlainText(new_data); } else { return; } } } else if(key_value_type=="REG_DWORD" || key_value_type=="REG_DWORD_BIG_ENDIAN") { bool ok=false; if(this->p_number_widget_rb_dec->isChecked()) { - this->p_number_widget_line_edit->text().toInt(&ok); + this->p_number_widget_line_edit->text().toUInt(&ok); } else { - // TODO: There seems to be a problem with 0xFFFFFFFF - this->p_number_widget_line_edit->text().toInt(&ok,16); + this->p_number_widget_line_edit->text().toUInt(&ok,16); } if(!ok) { QMessageBox::information(this, tr("Invalid data"), tr("The value you entered could not be " "converted to a %1! Please correct it.") .arg(key_value_type), QMessageBox::Ok); return; } } else if(key_value_type=="REG_QWORD") { bool ok=false; if(this->p_number_widget_rb_dec->isChecked()) { - this->p_number_widget_line_edit->text().toLongLong(&ok); + this->p_number_widget_line_edit->text().toULongLong(&ok); } else { - this->p_number_widget_line_edit->text().toLongLong(&ok,16); + this->p_number_widget_line_edit->text().toULongLong(&ok,16); } if(!ok) { QMessageBox::information(this, tr("Invalid data"), tr("The value you entered could not be " "converted to a %1! Please correct it.") .arg(key_value_type), QMessageBox::Ok); return; } } this->accept(); } void DlgAddKey::on_CmbKeyType_currentIndexChanged(const QString &arg1) { // Remove current widget from grid layout if(this->p_current_widget!=NULL) { this->ui->gridLayout->removeWidget(this->p_current_widget); this->p_current_widget->setVisible(false); this->p_current_widget=NULL; } // Add new widget for selected value type if(arg1=="REG_SZ" || arg1=="REG_EXPAND_SZ") { // Line edit widget for REG_SZ and REG_EXPAND_SZ this->ui->gridLayout->addWidget(this->p_line_widget,2,1); this->p_current_widget=this->p_line_widget; } else if(arg1=="REG_MULTI_SZ") { // Text edit widget for REG_MULTI_SZ this->ui->gridLayout->addWidget(this->p_text_widget,2,1); this->p_current_widget=this->p_text_widget; } else if(arg1=="REG_DWORD" || arg1=="REG_DWORD_BIG_ENDIAN" || arg1=="REG_QWORD") { // Number widget for REG_DWORD, REG_DWORD_BIG_ENDIAN and REG_QWORD this->ui->gridLayout->addWidget(this->p_number_widget,2,1); this->p_current_widget=this->p_number_widget; } else if(arg1=="REG_BINARY" || arg1=="REG_LINK" || arg1=="REG_RESOURCE_LIST" || arg1=="REG_FULL_RESOURCE_DESC" || arg1=="REG_RESOURCE_REQ_LIST") { // Binary widget for all other types this->ui->gridLayout->addWidget(this->p_binary_widget,2,1); this->p_current_widget=this->p_binary_widget; } if(arg1!="REG_NONE") { this->p_current_widget->setVisible(true); this->ui->LblKeyValue->setVisible(true); } else { this->ui->LblKeyValue->setVisible(false); } } +void DlgAddKey::SlotNumberWidgetRbDecClicked(bool checked) { + if(checked) { + bool ok=false; + if(this->KeyType()=="REG_QWORD") { + uint64_t num=this->p_number_widget_line_edit->text().toULongLong(&ok,16); + if(ok) { + // Convert number to dec + this->p_number_widget_line_edit->setText(QString().sprintf("%u",num)); + } + } else { + uint32_t num=this->p_number_widget_line_edit->text().toUInt(&ok,16); + if(ok) { + // Convert number to dec + this->p_number_widget_line_edit->setText(QString().sprintf("%u",num)); + } + } + if(!ok) { + QMessageBox::warning(this, + tr("Errror"), + tr("Unable to convert entered value to decimal!"), + QMessageBox::Ok); + this->p_number_widget_rb_hex->setChecked(true); + } + } +} + +void DlgAddKey::SlotNumberWidgetRbHexClicked(bool checked) { + if(checked) { + bool ok=false; + if(this->KeyType()=="REG_QWORD") { + uint64_t num=this->p_number_widget_line_edit->text().toULongLong(&ok); + if(ok) { + // Convert number to hex + this->p_number_widget_line_edit->setText(QString().sprintf("%016X", + num)); + } + } else { + uint32_t num=this->p_number_widget_line_edit->text().toUInt(&ok); + if(ok) { + // Convert number to hex + this->p_number_widget_line_edit->setText(QString().sprintf("%08X",num)); + } + } + if(!ok) { + QMessageBox::warning(this, + tr("Errror"), + tr("Unable to convert entered value to hex!"), + QMessageBox::Ok); + this->p_number_widget_rb_dec->setChecked(true); + } + } +} + void DlgAddKey::CreateValueWidgets() { this->p_line_widget=new QWidget(); this->p_line_widget_layout=new QHBoxLayout(this->p_line_widget); //this->p_line_widget_layout_rb_ansi=new QRadioButton(tr("Ansi")); //this->p_line_widget_layout_rb_unicode=new QRadioButton(tr("Unicode")); //this->p_line_widget_layout_rb_unicode->setChecked(true); this->p_line_widget_line_edit=new QLineEdit(); this->p_line_widget->setContentsMargins(0,0,0,0); this->p_line_widget_layout->setContentsMargins(0,0,0,0); this->p_line_widget_layout->addWidget(this->p_line_widget_line_edit); //this->p_line_widget_layout->addWidget(this->p_line_widget_layout_rb_ansi); //this->p_line_widget_layout->addWidget(this->p_line_widget_layout_rb_unicode); this->p_text_widget=new QWidget(); this->p_text_widget_layout=new QHBoxLayout(this->p_text_widget); this->p_text_widget_text_edit=new QPlainTextEdit(); this->p_text_widget->setContentsMargins(0,0,0,0); this->p_text_widget_layout->setContentsMargins(0,0,0,0); this->p_text_widget_layout->addWidget(this->p_text_widget_text_edit); this->p_number_widget=new QWidget(); this->p_number_widget_layout=new QHBoxLayout(this->p_number_widget); this->p_number_widget_line_edit=new QLineEdit(); this->p_number_widget_rb_dec=new QRadioButton(tr("Dec base")); this->p_number_widget_rb_dec->setChecked(true); this->p_number_widget_rb_hex=new QRadioButton(tr("Hex base")); this->p_number_widget->setContentsMargins(0,0,0,0); this->p_number_widget_layout->setContentsMargins(0,0,0,0); this->p_number_widget_layout->addWidget(this->p_number_widget_line_edit); this->p_number_widget_layout->addWidget(this->p_number_widget_rb_dec); this->p_number_widget_layout->addWidget(this->p_number_widget_rb_hex); this->p_binary_widget=new QWidget(); this->p_binary_widget_layout=new QHBoxLayout(this->p_binary_widget); this->p_binary_widget_hex_edit=new HexEditWidget(this,false,false); this->p_binary_widget->setContentsMargins(0,0,0,0); this->p_binary_widget_layout->setContentsMargins(0,0,0,0); this->p_binary_widget_layout->addWidget(this->p_binary_widget_hex_edit); } void DlgAddKey::DestroyValueWidgets() { //delete this->p_line_widget_layout_rb_ansi; //delete this->p_line_widget_layout_rb_unicode; delete this->p_line_widget_line_edit; delete this->p_line_widget_layout; delete this->p_line_widget; delete this->p_text_widget_text_edit; delete this->p_text_widget_layout; delete this->p_text_widget; delete this->p_number_widget_rb_hex; delete this->p_number_widget_rb_dec; delete this->p_number_widget_line_edit; delete this->p_number_widget_layout; delete this->p_number_widget; delete this->p_binary_widget_hex_edit; delete this->p_binary_widget_layout; delete this->p_binary_widget; } void DlgAddKey::SetValueWidgetData(QByteArray &key_value, QString &key_value_type) { if(key_value_type=="REG_SZ" || key_value_type=="REG_EXPAND_SZ") { this->p_line_widget_line_edit->setText( RegistryHive::KeyValueToString(key_value, RegistryHive::StringToKeyValueType( key_value_type))); } else if(key_value_type=="REG_MULTI_SZ") { QStringList strings= RegistryHive::KeyValueToStringList(key_value,&(this->ansi_encoded)); this->p_text_widget_text_edit->setPlainText(strings.join("\n")); } else if(key_value_type=="REG_DWORD") { this->p_number_widget_line_edit->setText( - RegistryHive::KeyValueToString(key_value,"int32")); + RegistryHive::KeyValueToString(key_value,"uint32")); } else if(key_value_type=="REG_DWORD_BIG_ENDIAN") { this->p_number_widget_line_edit->setText( - RegistryHive::KeyValueToString(key_value,"int32",0,0,false)); + RegistryHive::KeyValueToString(key_value,"uint32",0,0,false)); } else if(key_value_type=="REG_QWORD") { this->p_number_widget_line_edit->setText( - RegistryHive::KeyValueToString(key_value,"int64",0,0,false)); + RegistryHive::KeyValueToString(key_value,"uint64",0,0,false)); } else if(key_value_type=="REG_BINARY" || key_value_type=="REG_LINK" || key_value_type=="REG_RESOURCE_LIST" || key_value_type=="REG_FULL_RESOURCE_DESC" || key_value_type=="REG_RESOURCE_REQ_LIST") { this->p_binary_widget_hex_edit->SetData(key_value); } } QByteArray DlgAddKey::GetValueWidgetData() { QString key_value_type=this->KeyType(); if(key_value_type=="REG_SZ" || key_value_type=="REG_EXPAND_SZ") { // TODO: Wouldn't it be wise to let the user choose the encoding? // Get data QString data=this->p_line_widget_line_edit->text(); // Convert data to UTF16LE buffer uint16_t *p_buf=NULL; int buf_len=this->ToUtf16LeBuf(&p_buf,data.utf16(),data.size()); if(p_buf==NULL || buf_len==0) { // TODO: Inform user there was an error??? return QByteArray("\x00\x00",2); } // Construct ByteArray, free buffer and return QByteArray ret=QByteArray((char*)p_buf,buf_len); free(p_buf); return ret; } else if(key_value_type=="REG_MULTI_SZ") { // TODO: Let the user choose the encoding / endianness // TODO: Do we need to check for \r\n on Windows?? return RegistryHive::StringListToKeyValue( this->p_text_widget_text_edit-> toPlainText().split("\n", QString::SkipEmptyParts), true, this->ansi_encoded); } else if(key_value_type=="REG_DWORD" || key_value_type=="REG_DWORD_BIG_ENDIAN") { - int32_t val; + uint32_t val; if(this->p_number_widget_rb_dec->isChecked()) { - val=this->p_number_widget_line_edit->text().toInt(); + val=this->p_number_widget_line_edit->text().toUInt(); } else { - val=this->p_number_widget_line_edit->text().toInt(0,16); + val=this->p_number_widget_line_edit->text().toUInt(0,16); } if(key_value_type=="REG_DWORD") val=HTOLE32(val); else val=HTOBE32(val); return QByteArray((char*)&val,4); } else if(key_value_type=="REG_QWORD") { - int64_t val; + uint64_t val; if(this->p_number_widget_rb_dec->isChecked()) { - val=this->p_number_widget_line_edit->text().toLongLong(); + val=this->p_number_widget_line_edit->text().toULongLong(); } else { - val=this->p_number_widget_line_edit->text().toLongLong(0,16); + val=this->p_number_widget_line_edit->text().toULongLong(0,16); } val=HTOLE64(val); return QByteArray((char*)&val,8); } else if(key_value_type=="REG_BINARY" || key_value_type=="REG_LINK" || key_value_type=="REG_RESOURCE_LIST" || key_value_type=="REG_FULL_RESOURCE_DESC" || key_value_type=="REG_RESOURCE_REQ_LIST") { return this->p_binary_widget_hex_edit->GetData(); } return QByteArray(); } int DlgAddKey::ToUtf16LeBuf(uint16_t **pp_buf, const uint16_t *p_data, int ascii_len) { // Calculate utf16 buffer size // TODO: This fails if there are chars that need more than 16bit!! int buf_len=(ascii_len*2)+2; // Alloc buffer and set to 0x00h *pp_buf=(uint16_t*)malloc(buf_len); if(*pp_buf==NULL) return 0; memset(*pp_buf,0,buf_len); if(ascii_len==0) { // Empty string, we're done (buffer contains \0\0) return buf_len; } // Fill buffer with UTF16 string (ignoring \0\0 at the end) memcpy(*pp_buf,p_data,buf_len-2); // Make sure endianness is LE for(int i=0;iKeyType(); - - //if() TODO -} - -void DlgAddKey::SlotNumberWidgetRbDecClicked(bool checked) { - if(checked) { - bool ok=false; - if(this->KeyType()=="REG_QWORD") { - int64_t num=this->p_number_widget_line_edit->text().toLongLong(&ok,16); - if(ok) { - // Convert number to dec - this->p_number_widget_line_edit->setText(QString().arg(num)); - // Set input mask to 17 digit chars, 16 optional, 1 required - this->p_number_widget_line_edit->setInputMask("#000000000000000009;0"); - } - } else { - int32_t num=this->p_number_widget_line_edit->text().toLong(&ok,16); - if(ok) { - // Convert number to dec - this->p_number_widget_line_edit->setText(QString().arg(num)); - // Set input mask to 10 digit chars, 9 optional, 1 required - this->p_number_widget_line_edit->setInputMask("#0000000009;0"); - } - } - } -} - -void DlgAddKey::SlotNumberWidgetRbHexClicked(bool checked) { - if(checked) { - bool ok=false; - if(this->KeyType()=="REG_QWORD") { - uint64_t num=this->p_number_widget_line_edit->text().toULongLong(&ok); - if(ok) { - // Convert number to hex - this->p_number_widget_line_edit->setText(QString().sprintf("%016X", - num)); - // Set input mask to 16 hex chars, 15 optional, 1 required - this->p_number_widget_line_edit->setInputMask("hhhhhhhhhhhhhhhH;0"); - } - } else { - uint32_t num=this->p_number_widget_line_edit->text().toULong(&ok); - if(ok) { - // Convert number to hex - this->p_number_widget_line_edit->setText(QString().sprintf("%08X",num)); - // Set input mask to 8 hex chars, 7 optional, 1 required - this->p_number_widget_line_edit->setInputMask("hhhhhhhH;0"); - } - } - if(!ok) { - // TODO: Display error - this->p_number_widget_rb_dec->setChecked(true); - } - } -} diff --git a/trunk/dlgpreferences.cpp b/trunk/dlgpreferences.cpp index 077e2ac..8a8b4b7 100644 --- a/trunk/dlgpreferences.cpp +++ b/trunk/dlgpreferences.cpp @@ -1,215 +1,235 @@ -#include "dlgpreferences.h" -#include "ui_dlgpreferences.h" +/******************************************************************************* +* fred Copyright (c) 2011-2013 by Gillen Daniel * +* * +* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * +* with special feautures useful during forensic analysis. * +* * +* 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 3 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. * +* * +* You should have received a copy of the GNU General Public License along with * +* this program. If not, see . * +*******************************************************************************/ #include #include #include #include #include #include #include +#include "dlgpreferences.h" +#include "ui_dlgpreferences.h" + /******************************************************************************* * Public ******************************************************************************/ DlgPreferences::DlgPreferences(Settings *p_sets, QWidget *p_parent) : QDialog(p_parent), ui(new Ui::DlgPreferences) { ui->setupUi(this); this->p_settings=p_sets; // Load current values this->LoadPreferences(); } DlgPreferences::~DlgPreferences() { delete ui; } /******************************************************************************* * Private slots ******************************************************************************/ void DlgPreferences::on_BtnCancel_clicked() { this->reject(); } void DlgPreferences::on_ListReportLocations_clicked(const QModelIndex &index) { if(!index.isValid()) { // No valid row selected, disable some buttons this->ui->BtnEditReportLoc->setEnabled(false); this->ui->BtnRemoveReportLoc->setEnabled(false); this->ui->BtnMoveReportLocUp->setEnabled(false); this->ui->BtnMoveReportLocDown->setEnabled(false); this->ui->BtnAddReportLoc->setFocus(); return; } if(this->ui->ListReportLocations->count()==1) { // Only one item left, disable up/down buttons this->ui->BtnEditReportLoc->setEnabled(true); this->ui->BtnRemoveReportLoc->setEnabled(true); this->ui->BtnMoveReportLocUp->setEnabled(false); this->ui->BtnMoveReportLocDown->setEnabled(false); return; } if(index.row()==0) { // First row selected, disable up button this->ui->BtnEditReportLoc->setEnabled(true); this->ui->BtnRemoveReportLoc->setEnabled(true); this->ui->BtnMoveReportLocUp->setEnabled(false); this->ui->BtnMoveReportLocDown->setEnabled(true); return; } if(index.row()==(this->ui->ListReportLocations->count()-1)) { // Last row selected, disable down button this->ui->BtnEditReportLoc->setEnabled(true); this->ui->BtnRemoveReportLoc->setEnabled(true); this->ui->BtnMoveReportLocUp->setEnabled(true); this->ui->BtnMoveReportLocDown->setEnabled(false); return; } // Any other valid row selected, enable up/down buttons this->ui->BtnEditReportLoc->setEnabled(true); this->ui->BtnRemoveReportLoc->setEnabled(true); this->ui->BtnMoveReportLocUp->setEnabled(true); this->ui->BtnMoveReportLocDown->setEnabled(true); } void DlgPreferences::on_BtnAddReportLoc_clicked() { QString new_loc=QFileDialog::getExistingDirectory(this, tr("Select new report " "directory")); if(!new_loc.isEmpty()) { this->ui->ListReportLocations->addItem(new_loc); } } void DlgPreferences::on_BtnEditReportLoc_clicked() { QModelIndex cur_item=this->ui->ListReportLocations->currentIndex(); if(!cur_item.isValid()) return; // Get selected item QListWidgetItem *p_item=this->ui->ListReportLocations->item(cur_item.row()); // Let user select new directory QString new_loc=QFileDialog::getExistingDirectory(this, tr("Edit report directory"), p_item->text()); if(!new_loc.isEmpty()) { p_item->setText(new_loc); } } void DlgPreferences::on_BtnRemoveReportLoc_clicked() { QModelIndex cur_item=this->ui->ListReportLocations->currentIndex(); if(!cur_item.isValid()) return; QListWidgetItem *p_item= this->ui->ListReportLocations->takeItem(cur_item.row()); delete p_item; // Update buttons this->on_ListReportLocations_clicked( this->ui->ListReportLocations->currentIndex()); } void DlgPreferences::on_BtnMoveReportLocUp_clicked() { QModelIndex cur_item=this->ui->ListReportLocations->currentIndex(); if(!cur_item.isValid() || cur_item.row()==0) return; // Move selected item up QListWidgetItem *p_item= this->ui->ListReportLocations->takeItem(cur_item.row()); this->ui->ListReportLocations->insertItem(cur_item.row()-1,p_item); // Reselect moved item and update buttons this->ui->ListReportLocations->setCurrentItem(p_item); this->on_ListReportLocations_clicked( this->ui->ListReportLocations->currentIndex()); } void DlgPreferences::on_BtnMoveReportLocDown_clicked() { QModelIndex cur_item=this->ui->ListReportLocations->currentIndex(); if(!cur_item.isValid() || cur_item.row()==(this->ui->ListReportLocations->count()-1)) { return; } // Move selected item up QListWidgetItem *p_item= this->ui->ListReportLocations->takeItem(cur_item.row()); this->ui->ListReportLocations->insertItem(cur_item.row()+1,p_item); // Reselect moved item and update buttons this->ui->ListReportLocations->setCurrentItem(p_item); this->on_ListReportLocations_clicked( this->ui->ListReportLocations->currentIndex()); } void DlgPreferences::on_BtnReset_clicked() { if(QMessageBox::warning(this, tr("Reset default settings"), tr("Are you sure to reset all settings to their defaults?"), QMessageBox::No, QMessageBox::Yes)==QMessageBox::Yes) { this->p_settings->Reset(); this->LoadPreferences(); } } void DlgPreferences::on_BtnOk_clicked() { this->SavePreferences(); this->accept(); } /******************************************************************************* * Private ******************************************************************************/ void DlgPreferences::LoadPreferences() { // Load general preferences this->ui->SpinBoxRecentFiles->setValue( this->p_settings->GetRecentFilesDepth()); this->ui->ChkBoxSavePositions->setChecked( this->p_settings->GetWindowGeometryStatus()); this->ui->ChkBoxOpenReadOnly->setChecked( this->p_settings->GetOpenHivesReadOnly()); // Populate report location list this->ui->ListReportLocations->clear(); QStringList report_dirs=this->p_settings->GetReportTemplateDirs(); QListIterator it_report_dirs(report_dirs); if(!report_dirs.isEmpty()) { while(it_report_dirs.hasNext()) { this->ui->ListReportLocations->addItem(it_report_dirs.next()); } this->ui->ListReportLocations->setCurrentRow(0); this->ui->BtnEditReportLoc->setEnabled(true); this->ui->BtnRemoveReportLoc->setEnabled(true); this->ui->BtnMoveReportLocDown->setEnabled(true); } } void DlgPreferences::SavePreferences() { // Save general preferences this->p_settings->SetRecentFilesDepth(this->ui->SpinBoxRecentFiles->value()); this->p_settings->SetWindowGeometryStatus( this->ui->ChkBoxSavePositions->isChecked()); this->p_settings->SetOpenHivesReadOnly( this->ui->ChkBoxOpenReadOnly->isChecked()); // Save report location list QStringList report_dirs; for(int i=0;iui->ListReportLocations->count();i++) { report_dirs.append(this->ui->ListReportLocations->item(i)->text()); } this->p_settings->SetReportTemplateDirs(report_dirs); } diff --git a/trunk/dlgpreferences.h b/trunk/dlgpreferences.h index 60c52eb..af342b8 100644 --- a/trunk/dlgpreferences.h +++ b/trunk/dlgpreferences.h @@ -1,40 +1,60 @@ +/******************************************************************************* +* fred Copyright (c) 2011-2013 by Gillen Daniel * +* * +* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * +* with special feautures useful during forensic analysis. * +* * +* 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 3 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. * +* * +* You should have received a copy of the GNU General Public License along with * +* this program. If not, see . * +*******************************************************************************/ + #ifndef DLGPREFERENCES_H #define DLGPREFERENCES_H #include #include #include "settings.h" namespace Ui { class DlgPreferences; } class DlgPreferences : public QDialog { Q_OBJECT public: explicit DlgPreferences(Settings *p_sets, QWidget *p_parent=0); ~DlgPreferences(); private slots: void on_BtnCancel_clicked(); void on_ListReportLocations_clicked(const QModelIndex &index); void on_BtnAddReportLoc_clicked(); void on_BtnEditReportLoc_clicked(); void on_BtnRemoveReportLoc_clicked(); void on_BtnMoveReportLocUp_clicked(); void on_BtnMoveReportLocDown_clicked(); void on_BtnReset_clicked(); void on_BtnOk_clicked(); private: Ui::DlgPreferences *ui; Settings *p_settings; void LoadPreferences(); void SavePreferences(); }; #endif // DLGPREFERENCES_H diff --git a/trunk/dlgreportchooser.cpp b/trunk/dlgreportchooser.cpp index d9852ec..d433f1c 100644 --- a/trunk/dlgreportchooser.cpp +++ b/trunk/dlgreportchooser.cpp @@ -1,159 +1,159 @@ /******************************************************************************* * fred Copyright (c) 2011-2013 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * 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 3 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. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ -#include "dlgreportchooser.h" -#include "ui_dlgreportchooser.h" - #include #include #include #include +#include "dlgreportchooser.h" +#include "ui_dlgreportchooser.h" + DlgReportChooser::DlgReportChooser(Reports *p_reps, QString hive_type_string, Settings *p_sets, QWidget *p_parent) : QDialog(p_parent), ui(new Ui::DlgReportChooser) { QStringList tree_cats; QString cur_tree_cat; QTreeWidgetItem *p_tree_cat_widget; QTreeWidgetItem *p_tree_cat_rep_widget; QList tree_cat_reports; ReportTemplate* p_report; // Init private vars this->ui->setupUi(this); this->p_reports=p_reps; this->p_settings=p_sets; this->hive_type=hive_type_string; this->tree_category_items.clear(); this->selected_reports.clear(); // Restore dialog geometry if possible QByteArray geometry=this->p_settings->GetWindowGeometry("DlgReportChooser"); if(!geometry.isEmpty()) this->restoreGeometry(geometry); // Populate tree with reports tree_cats=this->p_reports->GetAvailableReportCategories(); QListIterator tree_cat_it(tree_cats); while(tree_cat_it.hasNext()) { cur_tree_cat=tree_cat_it.next(); p_tree_cat_widget=new QTreeWidgetItem(this->ui->TrReports); p_tree_cat_widget->setText(0,cur_tree_cat); p_tree_cat_widget->setFlags(Qt::ItemIsEnabled| Qt::ItemIsUserCheckable| Qt::ItemIsTristate); p_tree_cat_widget->setCheckState(0,Qt::Unchecked); tree_cat_reports=this->p_reports->GetAvailableReports(cur_tree_cat); QListIterator tree_cat_rep_it(tree_cat_reports); while(tree_cat_rep_it.hasNext()) { p_report=tree_cat_rep_it.next(); p_tree_cat_rep_widget=new QTreeWidgetItem(p_tree_cat_widget); // Save pointer to ReportTemplate alongside p_tree_cat_rep_widget->setData(0, Qt::UserRole, QVariant().fromValue(p_report)); p_tree_cat_rep_widget->setText(0,p_report->Name()); p_tree_cat_rep_widget->setFlags(Qt::ItemIsEnabled| Qt::ItemIsSelectable| Qt::ItemIsUserCheckable); if(this->hive_type!="UNKNOWN" && this->hive_type==p_report->Hive()) { p_tree_cat_rep_widget->setCheckState(0,Qt::Checked); } else { p_tree_cat_rep_widget->setCheckState(0,Qt::Unchecked); } } this->tree_category_items.append(p_tree_cat_widget); } // Finally, expand all categories this->ui->TrReports->expandAll(); } DlgReportChooser::~DlgReportChooser() { // Save dialog geometry this->p_settings->SetWindowGeometry("DlgReportChooser",this->saveGeometry()); delete this->ui; } QList DlgReportChooser::GetSelectedReports() { return this->selected_reports; } void DlgReportChooser::changeEvent(QEvent *p_event) { QDialog::changeEvent(p_event); switch (p_event->type()) { case QEvent::LanguageChange: this->ui->retranslateUi(this); break; default: break; } } void DlgReportChooser::on_BtnCancel_clicked() { this->reject(); } void DlgReportChooser::on_TrReports_currentItemChanged( QTreeWidgetItem *p_current, QTreeWidgetItem *p_previous) { Q_UNUSED(p_previous) // If item has no parent, clear labels and return if(p_current->parent()==NULL) { this->ui->LblHive->clear(); this->ui->LblAuthor->clear(); this->ui->LblDesc->clear(); return; } // Update labels this->ui->LblHive->setText( p_current->data(0,Qt::UserRole).value()->Hive()); this->ui->LblAuthor->setText( p_current->data(0,Qt::UserRole).value()->Author()); this->ui->LblDesc->setText( p_current->data(0,Qt::UserRole).value()->Description()); } void DlgReportChooser::on_BtnGenerate_clicked() { QTreeWidgetItem *p_cat; int i; // Add selected reports to selected_reports QListIterator cat_it(this->tree_category_items); while(cat_it.hasNext()) { p_cat=cat_it.next(); for(i=0;ichildCount();i++) { if(p_cat->child(i)->checkState(0)==Qt::Checked) { // Get saved pointer to ReportTemplate and append it to selected_reps this->selected_reports.append(p_cat-> child(i)->data(0,Qt::UserRole).value()); } } } this->accept(); } diff --git a/trunk/dlgreportchooser.h b/trunk/dlgreportchooser.h index fb178f4..4c05951 100644 --- a/trunk/dlgreportchooser.h +++ b/trunk/dlgreportchooser.h @@ -1,65 +1,65 @@ /******************************************************************************* * fred Copyright (c) 2011-2013 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * 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 3 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. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #ifndef DLGREPORTCHOOSER_H #define DLGREPORTCHOOSER_H -#include "reports.h" -#include "settings.h" - #include #include #include +#include "reports.h" +#include "settings.h" + namespace Ui { class DlgReportChooser; } class DlgReportChooser : public QDialog { Q_OBJECT public: explicit DlgReportChooser(Reports *p_reps, QString hive_type_string, Settings *p_sets, QWidget *p_parent=0); ~DlgReportChooser(); QList GetSelectedReports(); protected: void changeEvent(QEvent *p_event); private slots: void on_BtnCancel_clicked(); void on_TrReports_currentItemChanged(QTreeWidgetItem *p_current, QTreeWidgetItem *p_previous); void on_BtnGenerate_clicked(); private: Ui::DlgReportChooser *ui; Reports *p_reports; Settings *p_settings; QString hive_type; QList tree_category_items; QList selected_reports; }; #endif // DLGREPORTCHOOSER_H diff --git a/trunk/dlgreportviewer.cpp b/trunk/dlgreportviewer.cpp index c7cbe5f..697d818 100644 --- a/trunk/dlgreportviewer.cpp +++ b/trunk/dlgreportviewer.cpp @@ -1,116 +1,116 @@ /******************************************************************************* * fred Copyright (c) 2011-2013 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * 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 3 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. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ -#include "dlgreportviewer.h" -#include "ui_dlgreportviewer.h" - #include #include #include #include #include +#include "dlgreportviewer.h" +#include "ui_dlgreportviewer.h" + DlgReportViewer::DlgReportViewer(QString &report_data, Settings *p_sets, QWidget *p_parent) : QMainWindow(p_parent,Qt::Dialog | Qt::Popup), ui(new Ui::DlgReportViewer) { // Init local vars ui->setupUi(this); this->p_local_event_loop=NULL; this->orig_report_data=report_data; this->p_settings=p_sets; // Try to restore dialog geometry QByteArray geometry=this->p_settings->GetWindowGeometry("DlgReportViewer"); if(!geometry.isEmpty()) this->restoreGeometry(geometry); // Set report content this->ui->WebView->setHtml(report_data); // Set dialog title based on report content title QString report_title=this->ui->WebView->title(); this->setWindowTitle("Report Viewer"); } DlgReportViewer::~DlgReportViewer() { // Save dialog geometry this->p_settings->SetWindowGeometry("DlgReportViewer",this->saveGeometry()); delete ui; if(this->p_local_event_loop!=NULL) this->p_local_event_loop->exit(); } void DlgReportViewer::changeEvent(QEvent *p_event) { QMainWindow::changeEvent(p_event); switch(p_event->type()) { case QEvent::LanguageChange: ui->retranslateUi(this); break; default: break; } } void DlgReportViewer::closeEvent(QCloseEvent *p_event) { // Make sure we exit the local event loop on exit if(this->p_local_event_loop!=NULL) { this->p_local_event_loop->exit(); this->p_local_event_loop=NULL; } p_event->accept(); } void DlgReportViewer::exec() { // Create local event loop this->p_local_event_loop=new QEventLoop(this); // Show window and enter loop this->show(); this->p_local_event_loop->exec(); } void DlgReportViewer::on_action_Print_triggered() { // Print report QPrinter printer; QPrintDialog *p_dlg_print=new QPrintDialog(&printer); if(p_dlg_print->exec()==QDialog::Accepted) { this->ui->WebView->print(&printer); } delete p_dlg_print; } void DlgReportViewer::on_action_Close_triggered() { this->close(); } void DlgReportViewer::on_action_Save_triggered() { QString filename=QFileDialog::getSaveFileName(this, tr("Save report as"), "", "ODF file (*.odf)"); if(filename!="") { QTextDocument *p_doc=new QTextDocument(this); p_doc->setHtml(this->orig_report_data); QTextDocumentWriter *p_doc_writer=new QTextDocumentWriter(filename); p_doc_writer->setFormat(QByteArray("ODF")); p_doc_writer->write(p_doc); delete p_doc_writer; delete p_doc; } } diff --git a/trunk/dlgreportviewer.h b/trunk/dlgreportviewer.h index 8336028..3472cee 100644 --- a/trunk/dlgreportviewer.h +++ b/trunk/dlgreportviewer.h @@ -1,62 +1,62 @@ /******************************************************************************* * fred Copyright (c) 2011-2013 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * 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 3 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. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #ifndef DLGREPORTVIEWER_H #define DLGREPORTVIEWER_H -#include "settings.h" - #include #include #include +#include "settings.h" + namespace Ui { class DlgReportViewer; } class DlgReportViewer : public QMainWindow { Q_OBJECT public: explicit DlgReportViewer(QString &report_data, Settings *p_sets, QWidget *p_parent=0); ~DlgReportViewer(); void exec(); protected: void changeEvent(QEvent *p_event); void closeEvent(QCloseEvent *p_event); private slots: void on_action_Print_triggered(); void on_action_Close_triggered(); void on_action_Save_triggered(); private: Ui::DlgReportViewer *ui; QEventLoop *p_local_event_loop; QString orig_report_data; Settings *p_settings; }; #endif // DLGREPORTVIEWER_H diff --git a/trunk/dlgsearch.cpp b/trunk/dlgsearch.cpp index e22dec0..12179c7 100644 --- a/trunk/dlgsearch.cpp +++ b/trunk/dlgsearch.cpp @@ -1,135 +1,136 @@ /******************************************************************************* * fred Copyright (c) 2011-2013 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * 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 3 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. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ +#include + #include "dlgsearch.h" #include "ui_dlgsearch.h" -#include DlgSearch::DlgSearch(QWidget *parent) : QDialog(parent), ui(new Ui::DlgSearch) { ui->setupUi(this); } DlgSearch::~DlgSearch() { delete ui; } QList DlgSearch::Keywords() { return this->keywords; } bool DlgSearch::SearchNodeNames() { return this->search_nodes; } bool DlgSearch::SearchKeyNames() { return this->search_keys; } bool DlgSearch::SearchKeyValues() { return this->search_values; } void DlgSearch::changeEvent(QEvent *e) { QDialog::changeEvent(e); switch (e->type()) { case QEvent::LanguageChange: ui->retranslateUi(this); break; default: break; } } void DlgSearch::keyPressEvent(QKeyEvent *p_event) { if(p_event->key()==Qt::Key_Return || p_event->key()==Qt::Key_Enter) { this->on_BtnSearch_clicked(); } else { QDialog::keyPressEvent(p_event); } } void DlgSearch::on_BtnCancel_clicked() { this->reject(); } void DlgSearch::on_BtnSearch_clicked() { if(this->ui->EdtValue->text()=="" || (!this->ui->CbAscii->isChecked() && !this->ui->CbUtf16->isChecked() && !this->ui->CbHex->isChecked())) { // No value type specified QMessageBox::critical(this, tr("Error"), tr("Please specify a search value and type!")); return; } if(!this->ui->CbNodeNames->isChecked() && !this->ui->CbKeyNames->isChecked() && !this->ui->CbKeyValues->isChecked()) { // No target specified QMessageBox::critical(this, tr("Error"), tr("Please specify a search target!")); return; } // Save settings QString keyword=this->ui->EdtValue->text(); this->keywords.clear(); if(this->ui->CbAscii->isChecked()) this->keywords.append(QByteArray(keyword.toAscii())); if(this->ui->CbUtf16->isChecked()) { // TODO: .size()*2 will definetly fail sometimes!!!! this->keywords.append(QByteArray((char*)(keyword.utf16()),keyword.size()*2)); } if(this->ui->CbHex->isChecked()) { // TODO: Convert to hex } this->search_nodes=this->ui->CbNodeNames->isChecked(); this->search_keys=this->ui->CbKeyNames->isChecked(); this->search_values=this->ui->CbKeyValues->isChecked(); this->accept(); } void DlgSearch::on_CbAscii_toggled(bool checked) { // It is not possible to search for text and hex if(checked && this->ui->CbHex->isChecked()) this->ui->CbHex->setChecked(false); } void DlgSearch::on_CbUtf16_toggled(bool checked) { // It is not possible to search for text and hex if(checked && this->ui->CbHex->isChecked()) this->ui->CbHex->setChecked(false); } void DlgSearch::on_CbHex_toggled(bool checked) { // It is not possible to search for text and hex if(checked) { this->ui->CbAscii->setChecked(false); this->ui->CbUtf16->setChecked(false); } } diff --git a/trunk/dlgsearch.ui b/trunk/dlgsearch.ui index a2cf3cd..a3e27f4 100644 --- a/trunk/dlgsearch.ui +++ b/trunk/dlgsearch.ui @@ -1,152 +1,152 @@ DlgSearch 0 0 400 216 0 0 - Search + Find :/icons/resources/fred.png:/icons/resources/fred.png true Search value ASCII true UTF16 true false Hexadecimal Search in Node names true Key names true Key values true &Cancel Qt::Horizontal 40 20 &Search diff --git a/trunk/mainwindow.cpp b/trunk/mainwindow.cpp index e49a326..bcaaec6 100644 --- a/trunk/mainwindow.cpp +++ b/trunk/mainwindow.cpp @@ -1,1070 +1,1103 @@ /******************************************************************************* * fred Copyright (c) 2011-2013 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * 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 3 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. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #include #include #include #include #include #include #include #include #include #include "mainwindow.h" #include "ui_mainwindow.h" #include "dlgabout.h" #include "dlgreportchooser.h" #include "dlgreportviewer.h" #include "dlgsearch.h" #include "dlgpreferences.h" #include "dlgaddkey.h" #include "compileinfo.h" /******************************************************************************* * Public ******************************************************************************/ /* * Constructor */ MainWindow::MainWindow(ArgParser *p_arg_parser) : QMainWindow(0), ui(new Ui::MainWindow) { ui->setupUi(this); // Initialize private vars this->p_args=p_arg_parser; this->p_hive=new RegistryHive(this); this->is_hive_open=false; this->p_reg_node_tree_model=NULL; this->p_reg_node_tree_model_proxy=NULL; this->p_reg_key_table_model=NULL; this->p_search_thread=NULL; this->search_result_widgets.clear(); // Init and load settings this->p_settings=new Settings(this); this->is_hive_writable=!this->p_settings->GetOpenHivesReadOnly(); // Set main window size QByteArray geometry=this->p_settings->GetWindowGeometry("MainWindow"); if(!geometry.isEmpty()) { // Restore saved geometry this->restoreGeometry(geometry); } else { // No saved geometry, calculate and set default int cur_screen=QApplication::desktop()->screenNumber(this); int window_width= QApplication::desktop()->availableGeometry(cur_screen).width()*0.5; int window_height= QApplication::desktop()->availableGeometry(cur_screen).height()*0.5; int window_x= (QApplication::desktop()->availableGeometry(cur_screen).width()/2)- (window_width/2); int window_y= (QApplication::desktop()->availableGeometry(cur_screen).height()/2)- (window_height/2); this->setGeometry(window_x, window_y, window_width, window_height); } // Create widgets this->p_horizontal_splitter=new QSplitter(); this->p_horizontal_splitter->setOrientation(Qt::Horizontal); this->p_node_tree=new RegistryNodeTree(this->p_horizontal_splitter); this->p_vertical_splitter=new QSplitter(this->p_horizontal_splitter); this->p_vertical_splitter->setOrientation(Qt::Vertical); this->p_key_table=new RegistryKeyTable(this->p_vertical_splitter); this->p_tab_widget=new TabWidget(this->p_vertical_splitter); this->p_hex_edit_widget=new HexEditWidget(); this->p_hex_edit_widget->setEnabled(false); // Add hexedit page to tab_widget this->p_tab_widget->addTab(this->p_hex_edit_widget,tr("Hex viewer")); // Add widgets to their splitters this->p_vertical_splitter->addWidget(this->p_key_table); this->p_vertical_splitter->addWidget(this->p_tab_widget); this->p_horizontal_splitter->addWidget(this->p_node_tree); this->p_horizontal_splitter->addWidget(this->p_vertical_splitter); // Set stretch factors QSizePolicy node_tree_policy=this->p_node_tree->sizePolicy(); node_tree_policy.setHorizontalStretch(1); node_tree_policy.setVerticalStretch(100); this->p_node_tree->setSizePolicy(node_tree_policy); QSizePolicy vertical_splitter_policy=this->p_vertical_splitter->sizePolicy(); vertical_splitter_policy.setHorizontalStretch(4); vertical_splitter_policy.setVerticalStretch(100); this->p_vertical_splitter->setSizePolicy(vertical_splitter_policy); QSizePolicy key_table_policy=this->p_key_table->sizePolicy(); key_table_policy.setVerticalStretch(5); key_table_policy.setHorizontalStretch(100); this->p_key_table->setSizePolicy(key_table_policy); QSizePolicy tab_widget_policy=this->p_tab_widget->sizePolicy(); tab_widget_policy.setVerticalStretch(2); tab_widget_policy.setHorizontalStretch(200); this->p_tab_widget->setSizePolicy(tab_widget_policy); // Connect signals this->connect(this->p_node_tree, SIGNAL(clicked(QModelIndex)), this, SLOT(SlotNodeTreeClicked(QModelIndex))); this->connect(this->p_node_tree, SIGNAL(activated(QModelIndex)), this, SLOT(SlotNodeTreeClicked(QModelIndex))); this->connect(this->p_node_tree, SIGNAL(CurrentItemChanged(QModelIndex)), this, SLOT(SlotNodeTreeClicked(QModelIndex))); this->connect(this->p_key_table, SIGNAL(clicked(QModelIndex)), this, SLOT(SlotKeyTableClicked(QModelIndex))); this->connect(this->p_key_table, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(SlotKeyTableDoubleClicked(QModelIndex))); this->connect(this->p_key_table, SIGNAL(CurrentItemChanged(QModelIndex)), this, SLOT(SlotKeyTableClicked(QModelIndex))); this->connect(this->p_tab_widget, SIGNAL(tabCloseRequested(int)), this, SLOT(SlotTabCloseButtonClicked(int))); this->connect(this->p_node_tree, SIGNAL(SignalAddNode(QModelIndex)), this, SLOT(SlotAddNode(QModelIndex))); this->connect(this->p_node_tree, SIGNAL(SignalDeleteNode(QModelIndex)), this, SLOT(SlotDeleteNode(QModelIndex))); this->connect(this->p_key_table, SIGNAL(SignalAddKey()), this, SLOT(SlotAddKey())); this->connect(this->p_key_table, SIGNAL(SignalEditKey(QModelIndex)), this, SLOT(SlotEditKey(QModelIndex))); this->connect(this->p_key_table, SIGNAL(SignalDeleteKey(QModelIndex)), this, SLOT(SlotDeleteKey(QModelIndex))); // Add central widget this->setCentralWidget(this->p_horizontal_splitter); this->centralWidget()->setContentsMargins(4,4,4,0); // Set window title this->UpdateWindowTitle(); // Create and update recently opened menu this->p_recently_opened_menu=new QMenu(this); this->ui->ActionRecentlyOpened->setMenu(this->p_recently_opened_menu); this->UpdateRecentlyOpenedMenu(); // Update EnableWriteSupport menu according to defaults this->UpdateEnableWriteSupportMenu(); // Load report templates this->p_reports=new Reports(this->p_settings); // Finally, react on some command line arguments if(this->p_args->IsSet("maximized")) { this->setWindowState(Qt::WindowMaximized); } if(this->p_args->IsSet("fullscreen")) { this->setWindowState(Qt::WindowFullScreen); } if(this->p_args->IsSet("hive-file")) { - this->OpenHive(this->p_args->GetArgVal("hive-file")); + // Resolve path + this->OpenHive(QDir(this->p_args->GetArgVal("hive-file")).canonicalPath()); } } /* * Destructor */ MainWindow::~MainWindow() { if(this->is_hive_open) { this->p_hive->Close(); } // Delete created objects delete this->p_reports; this->ClearRecentlyOpenedMenu(); delete this->p_recently_opened_menu; delete this->p_hex_edit_widget; delete this->p_tab_widget; delete this->p_key_table; delete this->p_vertical_splitter; delete this->p_node_tree; delete this->p_horizontal_splitter; delete this->p_settings; delete this->p_hive; delete ui; } /******************************************************************************* * Protected ******************************************************************************/ /* * closeEvent */ void MainWindow::closeEvent(QCloseEvent *p_event) { Q_UNUSED(p_event) // Make sure the user can save any changes // TODO: If saving fails, let the user cancel closing this->SaveHiveChanges(); // Save window position and size on exit this->p_settings->SetWindowGeometry("MainWindow",this->saveGeometry()); QMainWindow::closeEvent(p_event); } /******************************************************************************* * Private slots ******************************************************************************/ /* - * on_action_Open_hive_triggered + * on_ActionOpenHive_triggered */ -void MainWindow::on_action_Open_hive_triggered() { +void MainWindow::on_ActionOpenHive_triggered() { QString hive_file=""; hive_file=QFileDialog::getOpenFileName(this, tr("Open registry hive"), this->p_settings->GetLastOpenLocation(), tr("All files (*)")); if(hive_file=="") return; this->OpenHive(hive_file); } /* - * on_action_Close_hive_triggered + * on_ActionSave_triggered */ -void MainWindow::on_action_Close_hive_triggered() { +void MainWindow::on_ActionSave_triggered() { + if(!(this->is_hive_open && this->is_hive_writable)) { + this->ui->ActionSave->setEnabled(false); + return; + } + this->SaveHiveChanges(true); + if(!this->p_hive->HasChangesToCommit()) { + this->ui->ActionSave->setEnabled(false); + } +} + +/* + * on_ActionCloseHive_triggered + */ +void MainWindow::on_ActionCloseHive_triggered() { // Make sure the user can save any changes // TODO: If saving fails, let the user cancel closing this->SaveHiveChanges(); if(this->is_hive_open) { // Remove search results while(this->p_tab_widget->count()>1) { this->p_tab_widget->removeTab(this->p_tab_widget->count()-1); delete this->search_result_widgets.at(this->p_tab_widget->count()-1); this->search_result_widgets.removeLast(); } // Delete models if(this->p_reg_node_tree_model!=NULL) { this->p_node_tree->setModel(NULL); delete this->p_reg_node_tree_model_proxy; delete this->p_reg_node_tree_model; this->p_reg_node_tree_model_proxy=NULL; this->p_reg_node_tree_model=NULL; } if(this->p_reg_key_table_model!=NULL) { this->p_key_table->setModel(NULL); delete this->p_reg_key_table_model; this->p_reg_key_table_model=NULL; } // Remove any data from hex edit and data interpreter this->p_hex_edit_widget->SetData(QByteArray()); this->p_hex_edit_widget->setEnabled(false); // Close hive this->p_hive->Close(); this->is_hive_open=false; this->is_hive_writable=!this->p_settings->GetOpenHivesReadOnly(); this->UpdateWindowTitle(); this->UpdateMenuStates(); this->UpdateEnableWriteSupportMenu(); } } /* - * on_action_Quit_triggered + * on_ActionQuit_triggered */ -void MainWindow::on_action_Quit_triggered() { +void MainWindow::on_ActionQuit_triggered() { qApp->exit(); } /* - * on_ActionSearch_triggered + * on_ActionFind_triggered */ -void MainWindow::on_ActionSearch_triggered() { +void MainWindow::on_ActionFind_triggered() { DlgSearch dlg_search(this); if(dlg_search.exec()==QDialog::Accepted) { // Create search thread and connect needed signals/slots this->p_search_thread=new ThreadSearch(this); // Add new search widget to tabwidget and to internal widget list SearchResultWidget *p_search_widget= new SearchResultWidget(this->p_tab_widget); p_search_widget->setEnabled(false); this->search_result_widgets.append(p_search_widget); this->connect(p_search_widget, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(SlotSearchResultWidgetDoubleClicked(QModelIndex))); this->p_tab_widget->addTab(p_search_widget,tr("Search results"),true); this->p_tab_widget->setCurrentIndex(this->p_tab_widget->count()-1); // Connect search thread to result widget this->connect(this->p_search_thread, SIGNAL(SignalFoundMatch(ThreadSearch::eMatchType, QString,QString,QString)), p_search_widget, SLOT(SlotFoundMatch(ThreadSearch::eMatchType, QString,QString,QString))); this->connect(this->p_search_thread, SIGNAL(finished()), this, SLOT(SlotSearchFinished())); this->connect(this->p_search_thread, SIGNAL(finished()), p_search_widget, SLOT(SlotSearchFinished())); // Start searching - this->ui->ActionSearch->setEnabled(false); + this->ui->ActionFind->setEnabled(false); p_search_thread->Search(this->p_hive->Filename(), dlg_search.Keywords(), dlg_search.SearchNodeNames(), dlg_search.SearchKeyNames(), dlg_search.SearchKeyValues()); } } /* * on_ActionEnableWriteSupport_triggered */ void MainWindow::on_ActionEnableWriteSupport_triggered() { // There might be unsaved changes, give the user the chance to save them if(!this->SaveHiveChanges()) return; // Reopen hive // Reopen has read_only as parameter. Thus we need to pass // !this->is_hive_writable which is the case when passing // this->is_hive_writable as long as we do it before actually changing our // internal state. if(!this->p_hive->Reopen(this->is_hive_writable)) { QMessageBox::critical(this, tr("Error"), tr("Unable to switch write-support: %1") .arg(this->p_hive->GetErrorMsg())); return; } // Switch internal state this->is_hive_writable=!this->is_hive_writable; this->UpdateEnableWriteSupportMenu(); this->p_node_tree->SetWritable(this->is_hive_writable); this->p_key_table->SetWritable(this->is_hive_writable); this->UpdateWindowTitle(this->p_hive->Filename()); } /* * on_ActionPreferences_triggered */ void MainWindow::on_ActionPreferences_triggered() { DlgPreferences dlg_preferences(this->p_settings,this); dlg_preferences.exec(); // Update vars, objects and GUI elements which might be affected by the new // settings this->UpdateRecentlyOpenedMenu(); this->is_hive_writable=!this->p_settings->GetOpenHivesReadOnly(); this->UpdateEnableWriteSupportMenu(); this->p_reports->LoadReportTemplates(); } /* * on_ActionGenerateReport_triggered */ void MainWindow::on_ActionGenerateReport_triggered() { DlgReportChooser dlg_repchooser(this->p_reports, this->p_hive->HiveTypeToString( this->p_hive->HiveType()), this->p_settings, this); if(dlg_repchooser.exec()==QDialog::Accepted) { QList selected_reports; // Get selected report selected_reports=dlg_repchooser.GetSelectedReports(); if(selected_reports.isEmpty()) return; // Generate report(s) QString report_result=""; if(this->p_reports->GenerateReport(this->p_hive, selected_reports, report_result, false)) { // Report generation was successfull, show reports DlgReportViewer *p_dlg_report_view=new DlgReportViewer(report_result, this->p_settings, this); p_dlg_report_view->exec(); delete p_dlg_report_view; } else { // TODO: Inform user qDebug()<<"ERROR: "<p_reports->LoadReportTemplates(); } /* - * on_actionAbout_Qt_triggered + * on_ActionAboutQt_triggered */ -void MainWindow::on_actionAbout_Qt_triggered() { +void MainWindow::on_ActionAboutQt_triggered() { QMessageBox::aboutQt(this,tr("About Qt")); } /* - * on_actionAbout_fred_triggered + * on_ActionAboutFred_triggered */ -void MainWindow::on_actionAbout_fred_triggered() { +void MainWindow::on_ActionAboutFred_triggered() { DlgAbout dlg_about(this); dlg_about.exec(); } /* * SlotNodeTreeClicked */ void MainWindow::SlotNodeTreeClicked(QModelIndex index) { QString node_path; if(!index.isValid()) return; // Map proxy index to tree model index index=this->p_reg_node_tree_model_proxy->mapToSource(index); // Built node path node_path=this->p_reg_node_tree_model->GetNodePath(index); // Create table model and attach it to the table view if(this->p_reg_key_table_model!=NULL) { // If a previous model was set, delete it and clear hexedit etc... this->p_key_table->setModel(NULL); delete this->p_reg_key_table_model; this->p_hex_edit_widget->SetData(QByteArray()); } this->p_reg_key_table_model=new RegistryKeyTableModel(this->p_hive,node_path); this->p_key_table->setModel(this->p_reg_key_table_model, this->is_hive_writable); // Set focus back to nodetree to be able to navigate with keyboard this->p_node_tree->setFocus(); } /* * SlotKeyTableClicked */ void MainWindow::SlotKeyTableClicked(QModelIndex index) { if(!index.isValid()) return; this->selected_key_value= this->p_reg_key_table_model->data(this->p_reg_key_table_model-> index(index.row(),2), RegistryKeyTableModel:: AdditionalRoles_GetRawData) .toByteArray(); this->p_hex_edit_widget->SetData(this->selected_key_value); // Set focus back to nodetree to be able to navigate with keyboard this->p_key_table->setFocus(); } /* * SlotKeyTableDoubleClicked */ void MainWindow::SlotKeyTableDoubleClicked(QModelIndex index) { if(!index.isValid()) return; if(!this->is_hive_open) return; if(this->is_hive_writable) this->SlotEditKey(index); } /* * SlotSearchFinished */ void MainWindow::SlotSearchFinished() { delete this->p_search_thread; this->p_search_thread=NULL; - this->ui->ActionSearch->setEnabled(true); + this->ui->ActionFind->setEnabled(true); // Enable result widget this->search_result_widgets.last()->setEnabled(true); } /* * SlotSearchResultWidgetDoubleClicked */ void MainWindow::SlotSearchResultWidgetDoubleClicked(QModelIndex index) { SearchResultWidget *p_sender; QString path; QString match_type; QString value; QString key=""; int i; if(!index.isValid()) return; // Get pointer to sender p_sender=(SearchResultWidget*)QObject::sender(); // Get path and matchtype path=p_sender->item(index.row(),0)->text(); match_type=p_sender->item(index.row(),1)->text(); value=p_sender->item(index.row(),2)->text(); if(match_type==tr("Node name")) { // Node name is not part of path. Add it if(path=="\\") path.append(value); else path.append("\\").append(value); } else if(match_type==tr("Key name")) { // Key name is stored in value key=value; } else if(match_type==tr("Key value")) { // Key name is part of path. Save and remove it QStringList nodes=path.split("\\",QString::SkipEmptyParts); key=nodes.at(nodes.count()-1); // Remove \ from path path.chop(key.length()+1); } // Expand treeview to correct node QList indexes= this->p_reg_node_tree_model->GetIndexListOf(path); for(i=0;ip_reg_node_tree_model_proxy-> mapFromSource(indexes.at(i))); this->p_node_tree->expand(indexes.at(i)); } if(indexes.count()>0) { // Scroll to last expanded node, select it and update widgets this->p_node_tree->scrollTo(indexes.at(indexes.count()-1), QAbstractItemView::PositionAtCenter); this->p_node_tree->selectionModel()->clear(); this->p_node_tree->selectionModel()-> select(indexes.at(indexes.count()-1), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows | QItemSelectionModel::Current); this->SlotNodeTreeClicked(indexes.at(indexes.count()-1)); } // Select correct key if search matched on keay name / value if(key!="") { int row=this->p_reg_key_table_model->GetKeyRow(key); this->p_key_table->clearSelection(); this->p_key_table->scrollTo(this->p_reg_key_table_model->index(row,0), QAbstractItemView::PositionAtCenter); this->p_key_table->selectRow(row); this->SlotKeyTableClicked(this->p_reg_key_table_model->index(row,0)); } } /* * SlotTabCloseButtonClicked */ void MainWindow::SlotTabCloseButtonClicked(int index) { // Delete tab widget and remove tab this->p_tab_widget->removeTab(index); delete this->search_result_widgets.at(index-1); this->search_result_widgets.removeAt(index-1); } /* * SlotRecentlyOpenedFileClicked */ void MainWindow::SlotRecentlyOpenedFileClicked(bool checked) { Q_UNUSED(checked) QAction *p_sender=(QAction*)QObject::sender(); this->OpenHive(p_sender->text()); } /* * SlotAddNode */ void MainWindow::SlotAddNode(QModelIndex index) { QString node_path; int new_node_id; if(!index.isValid()) return; // Map proxy index to tree model index and get node path index=this->p_reg_node_tree_model_proxy->mapToSource(index); node_path=this->p_reg_node_tree_model->GetNodePath(index); // Query user for a node name bool ok=false; QString node_name=QInputDialog::getText(this, tr("Add node"), tr("Please specify a name for the new node"), QLineEdit::Normal, QString(), &ok); if(ok) { if((new_node_id=this->p_hive->AddNode(node_path,node_name))==0) { QMessageBox::critical(this, tr("Error"), tr("Unable to create node '%1\\%2': %3!") .arg(node_path, node_name, this->p_hive->GetErrorMsg())); } else { // Add node to model. We have to pass node_name as Ascii as utf8 names are // not supported inside hives! QModelIndex new_node_index= this->p_reg_node_tree_model->AddNode(this->p_hive, index, new_node_id, node_name.toAscii()); // Now that node has been added, expand parent and select new node this->p_node_tree->expand( this->p_reg_node_tree_model_proxy->mapFromSource(index)); new_node_index= this->p_reg_node_tree_model_proxy->mapFromSource(new_node_index); this->p_node_tree->scrollTo(new_node_index, QAbstractItemView::PositionAtCenter); this->p_node_tree->selectionModel()->clear(); this->p_node_tree->selectionModel()-> select(new_node_index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows | QItemSelectionModel::Current); - // And finally update key table + // Finally update key table and enable Save menu this->SlotNodeTreeClicked(new_node_index); + this->ui->ActionSave->setEnabled(true); } } } /* * SlotDeleteNode */ void MainWindow::SlotDeleteNode(QModelIndex index) { QString node_path; if(!index.isValid()) return; // Map proxy index to tree model index and get node path index=this->p_reg_node_tree_model_proxy->mapToSource(index); node_path=this->p_reg_node_tree_model->GetNodePath(index); if(QMessageBox::warning(this, tr("Delete node"), tr("Are you sure you want to remove the node '%1' and all of its child nodes?").arg(node_path), QMessageBox::Yes, QMessageBox::No)==QMessageBox::Yes) { // Remove node from hive if(!this->p_hive->DeleteNode(node_path)) { QMessageBox::critical(this, tr("Error"), tr("Unable to delete node '%1': %2!") .arg(node_path,this->p_hive->GetErrorMsg())); return; } // Remove node from tree model and select nearest node QModelIndex next_node_index=this->p_reg_node_tree_model->RemoveNode(index); if(next_node_index.isValid()) { next_node_index= this->p_reg_node_tree_model_proxy->mapFromSource(next_node_index); this->p_node_tree->selectionModel()->clear(); this->p_node_tree->selectionModel()-> select(next_node_index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows | QItemSelectionModel::Current); } - // And finally update key table + // And finally update key table and enable Save menu this->SlotNodeTreeClicked(next_node_index); + this->ui->ActionSave->setEnabled(true); } } /* * SlotAddKey */ void MainWindow::SlotAddKey() { DlgAddKey dlg_add_key(this); if(dlg_add_key.exec()==QDialog::Accepted) { // Get selected parent node QModelIndex parent_node=this->p_node_tree->currentIndex(); parent_node=this->p_reg_node_tree_model_proxy->mapToSource(parent_node); QString parent_node_path=this->p_reg_node_tree_model->GetNodePath(parent_node); // Add key int new_key=this->p_hive->AddKey(parent_node_path, dlg_add_key.KeyName(), dlg_add_key.KeyType(), dlg_add_key.KeyValue()); if(new_key==0) { QMessageBox::critical(this, tr("Error"), tr("Unable to add key: %1") .arg(this->p_hive->GetErrorMsg())); return; } // Add new key to the key table model QModelIndex new_key_index= this->p_reg_key_table_model->AddKey(this->p_hive,new_key); if(new_key_index.isValid()) { this->p_key_table->clearSelection(); this->p_key_table->scrollTo(new_key_index, QAbstractItemView::PositionAtCenter); this->p_key_table->selectRow(new_key_index.row()); } + // Update key table and enable save menu this->SlotKeyTableClicked(new_key_index); + this->ui->ActionSave->setEnabled(true); } } /* * SlotEditKey */ void MainWindow::SlotEditKey(QModelIndex index) { if(!index.isValid()) return; // Get current values QString key_name= this->p_reg_key_table_model->data(this->p_reg_key_table_model-> index(index.row(), RegistryKeyTableModel:: ColumnContent_KeyName), Qt::DisplayRole).toString(); QString key_value_type= this->p_reg_key_table_model->data(this->p_reg_key_table_model-> index(index.row(), RegistryKeyTableModel:: ColumnContent_KeyType), Qt::DisplayRole).toString(); QByteArray key_value= this->p_reg_key_table_model->data(this->p_reg_key_table_model-> index(index.row(), RegistryKeyTableModel:: ColumnContent_KeyValue), RegistryKeyTableModel:: AdditionalRoles_GetRawData).toByteArray(); // Exec update dialog DlgAddKey dlg_update_key(this,key_name,key_value_type,key_value); if(dlg_update_key.exec()==QDialog::Accepted) { // Get selected parent node QModelIndex parent_node=this->p_node_tree->currentIndex(); parent_node=this->p_reg_node_tree_model_proxy->mapToSource(parent_node); QString parent_node_path=this->p_reg_node_tree_model->GetNodePath(parent_node); // Update key int new_key=this->p_hive->UpdateKey(parent_node_path, dlg_update_key.KeyName(), dlg_update_key.KeyType(), dlg_update_key.KeyValue()); if(new_key==0) { QMessageBox::critical(this, tr("Error"), tr("Unable to update key: %1") .arg(this->p_hive->GetErrorMsg())); return; } // Update key in key table model QModelIndex new_key_index= this->p_reg_key_table_model->UpdateKey(this->p_hive,new_key); this->p_key_table->clearSelection(); if(new_key_index.isValid()) { this->p_key_table->scrollTo(new_key_index, QAbstractItemView::PositionAtCenter); this->p_key_table->selectRow(new_key_index.row()); // TODO: Update geometry in case data has been added and is now expanding // behind the right border // Update HexEditWidget } + // Update key table and enable Save menu this->SlotKeyTableClicked(new_key_index); + this->ui->ActionSave->setEnabled(true); } } /* * SlotDeleteKey */ void MainWindow::SlotDeleteKey(QModelIndex index) { if(!index.isValid()) return; // Get selected key name QString key_name= this->p_reg_key_table_model->data(this->p_reg_key_table_model-> index(index.row(), RegistryKeyTableModel:: ColumnContent_KeyName), Qt::DisplayRole).toString(); // Get selected parent node QModelIndex parent_node=this->p_node_tree->currentIndex(); parent_node=this->p_reg_node_tree_model_proxy->mapToSource(parent_node); QString parent_node_path=this->p_reg_node_tree_model->GetNodePath(parent_node); if(QMessageBox::warning(this, tr("Delete key"), tr("Are you sure you want to remove the key '%1\\%2'?") .arg(parent_node_path,key_name), QMessageBox::Yes, QMessageBox::No)==QMessageBox::Yes) { // Remove key from hive if(!this->p_hive->DeleteKey(parent_node_path,key_name)) { QMessageBox::critical(this, tr("Error"), tr("Unable to delete key '%1\\%2': %3") .arg(parent_node_path, key_name, this->p_hive->GetErrorMsg())); return; } // Remove key from table model and update selection QModelIndex new_key_index=this->p_reg_key_table_model->RemoveKey(index); this->p_key_table->clearSelection(); if(new_key_index.isValid()) { this->p_key_table->scrollTo(new_key_index, QAbstractItemView::PositionAtCenter); this->p_key_table->selectRow(new_key_index.row()); } + // Enable Save menu + this->ui->ActionSave->setEnabled(true); } } /******************************************************************************* * Private ******************************************************************************/ /* * OpenHive */ void MainWindow::OpenHive(QString hive_file) { // Update last open location this->p_settings->SetLastOpenLocation( hive_file.left(hive_file.lastIndexOf(QDir::separator()))); // If another hive is currently open, close it - if(this->is_hive_open) this->on_action_Close_hive_triggered(); + if(this->is_hive_open) this->on_ActionCloseHive_triggered(); // Try to open hive if(!this->p_hive->Open(hive_file,!this->is_hive_writable)) { QMessageBox::critical(this, tr("Error opening hive file"), tr("Unable to open file '%1'").arg(hive_file)); return; } // Create tree model & proxy this->p_reg_node_tree_model=new RegistryNodeTreeModel(this->p_hive); this->p_reg_node_tree_model_proxy=new RegistryNodeTreeModelProxy(this); //this->p_reg_node_tree_model_proxy->setDynamicSortFilter(true); this->p_reg_node_tree_model_proxy-> setSourceModel(this->p_reg_node_tree_model); this->p_node_tree->setModel(this->p_reg_node_tree_model_proxy, this->is_hive_writable); this->is_hive_open=true; // Enable data interpreter this->p_hex_edit_widget->setEnabled(true); // Update window title this->UpdateWindowTitle(hive_file); // Update menu states this->UpdateMenuStates(); // Add file to recent list and update recently opened menu this->p_settings->AddRecentFile(hive_file); this->UpdateRecentlyOpenedMenu(); } /* * UpdateWindowTitle */ void MainWindow::UpdateWindowTitle(QString filename) { if(filename=="") { this->setWindowTitle(QString("%1 v%2").arg(APP_TITLE,APP_VERSION)); } else { this->setWindowTitle(QString("%1 v%2 - %3").arg(APP_TITLE, APP_VERSION, filename.toLocal8Bit() .constData())); if(!this->is_hive_writable) { this->setWindowTitle(this->windowTitle().append(QString(" (%1)") .arg(tr("read-only")))); } } } /* * UpdateMenuStates */ void MainWindow::UpdateMenuStates() { if(this->is_hive_open) { - this->ui->action_Close_hive->setEnabled(true); - this->ui->ActionSearch->setEnabled(true); + this->ui->ActionCloseHive->setEnabled(true); + this->ui->ActionFind->setEnabled(true); this->ui->ActionEnableWriteSupport->setEnabled(true); this->ui->ActionGenerateReport->setEnabled(true); this->ui->ActionReloadReportTemplates->setEnabled(true); this->UpdateEnableWriteSupportMenu(); } else { - this->ui->action_Close_hive->setEnabled(false); + this->ui->ActionSave->setEnabled(false); + this->ui->ActionCloseHive->setEnabled(false); this->ui->ActionEnableWriteSupport->setEnabled(false); - this->ui->ActionSearch->setEnabled(false); + this->ui->ActionFind->setEnabled(false); this->ui->ActionEnableWriteSupport->setEnabled(false); this->ui->ActionGenerateReport->setEnabled(false); this->ui->ActionReloadReportTemplates->setEnabled(false); } } /* * ClearRecentlyOpenedMenu */ void MainWindow::ClearRecentlyOpenedMenu() { QAction *p_action; // Remove existing menu entries QList menu_entries=this->p_recently_opened_menu->actions(); QListIterator it_me(menu_entries); while(it_me.hasNext()) { p_action=it_me.next(); this->p_recently_opened_menu->removeAction(p_action); delete p_action; } } /* * UpdateRecentlyOpenedMenu */ void MainWindow::UpdateRecentlyOpenedMenu() { QStringList recent_files=this->p_settings->GetRecentFiles(); QAction *p_action; // Remove existing menu entries this->ClearRecentlyOpenedMenu(); // If there are no recent files, disable submenu and return if(recent_files.isEmpty()) { this->ui->ActionRecentlyOpened->setEnabled(false); return; } else { this->ui->ActionRecentlyOpened->setEnabled(true); } // Add recently opened files to menu QListIterator it_rf(recent_files); while(it_rf.hasNext()) { // Create menu entry p_action=new QAction(it_rf.next(),this->p_recently_opened_menu); // Connect it to us this->connect(p_action, SIGNAL(triggered(bool)), this, SLOT(SlotRecentlyOpenedFileClicked(bool))); // Add it to submenu this->p_recently_opened_menu->addAction(p_action); } } /* * UpdateEnableWriteSupportMenu */ void MainWindow::UpdateEnableWriteSupportMenu() { if(!this->is_hive_writable) { this->ui->ActionEnableWriteSupport->setText(tr("Enable &write support")); this->p_node_tree->SetWritable(false); this->p_key_table->SetWritable(false); } else { this->ui->ActionEnableWriteSupport->setEnabled(false); this->p_node_tree->SetWritable(true); this->p_key_table->SetWritable(true); } } /* * SaveHiveChanges */ -bool MainWindow::SaveHiveChanges() { +bool MainWindow::SaveHiveChanges(bool force) { if(!this->is_hive_open) return true; if(!this->is_hive_writable) return true; if(!this->p_hive->HasChangesToCommit()) return true; - // There are unsaved changes, ask user if we should commit them - switch(QMessageBox::information(this, - tr("Hive contains unsaved data"), - tr("Do you want to save them now?"), - QMessageBox::Yes, - QMessageBox::No, - QMessageBox::Cancel)) - { - case QMessageBox::Yes: { - if(!this->p_hive->CommitChanges()) { - QMessageBox::critical(this, - tr("Saving changes"), - tr("Unable to save changes: %1") - .arg(this->p_hive->GetErrorMsg())); + if(!force) { + // There are unsaved changes, ask user if we should commit them + switch(QMessageBox::information(this, + tr("Hive contains unsaved data"), + tr("Do you want to save them now?"), + QMessageBox::Yes, + QMessageBox::No, + QMessageBox::Cancel)) + { + case QMessageBox::Yes: { + if(!this->p_hive->CommitChanges()) { + QMessageBox::critical(this, + tr("Saving changes"), + tr("Unable to save changes: %1") + .arg(this->p_hive->GetErrorMsg())); + return false; + } + break; + } + case QMessageBox::No: { + break; + } + default: { return false; } - break; - } - case QMessageBox::No: { - // TODO: Discard any changes if we are changing to read-only! - break; } - default: { + } else { + if(!this->p_hive->CommitChanges()) { + QMessageBox::critical(this, + tr("Saving changes"), + tr("Unable to save changes: %1") + .arg(this->p_hive->GetErrorMsg())); return false; } } return true; } diff --git a/trunk/mainwindow.h b/trunk/mainwindow.h index 77ddb0c..75ed4c0 100644 --- a/trunk/mainwindow.h +++ b/trunk/mainwindow.h @@ -1,127 +1,127 @@ /******************************************************************************* * fred Copyright (c) 2011-2013 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * 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 3 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. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include #include #include #include - #include #include -#include +//#include #include "argparser.h" #include "registryhive.h" #include "registrynodetree.h" #include "registrynodetreemodel.h" #include "registrynodetreemodelproxy.h" #include "registrykeytable.h" #include "registrykeytablemodel.h" #include "hexeditwidget.h" #include "reports.h" #include "threadsearch.h" #include "searchresultwidget.h" #include "tabwidget.h" #include "settings.h" namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(ArgParser *p_arg_parser); ~MainWindow(); protected: void closeEvent(QCloseEvent *p_event); private slots: - void on_action_Open_hive_triggered(); - void on_action_Close_hive_triggered(); - void on_action_Quit_triggered(); - void on_ActionSearch_triggered(); + void on_ActionOpenHive_triggered(); + void on_ActionCloseHive_triggered(); + void on_ActionQuit_triggered(); void on_ActionEnableWriteSupport_triggered(); void on_ActionPreferences_triggered(); void on_ActionGenerateReport_triggered(); void on_ActionReloadReportTemplates_triggered(); - void on_actionAbout_Qt_triggered(); - void on_actionAbout_fred_triggered(); - + void on_ActionAboutQt_triggered(); + void on_ActionAboutFred_triggered(); + void on_ActionFind_triggered(); void SlotNodeTreeClicked(QModelIndex index); void SlotKeyTableClicked(QModelIndex index); void SlotKeyTableDoubleClicked(QModelIndex index); void SlotSearchFinished(); void SlotSearchResultWidgetDoubleClicked(QModelIndex index); void SlotTabCloseButtonClicked(int index); void SlotRecentlyOpenedFileClicked(bool checked); void SlotAddNode(QModelIndex index); void SlotDeleteNode(QModelIndex index); void SlotAddKey(); void SlotEditKey(QModelIndex index); void SlotDeleteKey(QModelIndex index); + void on_ActionSave_triggered(); + private: Ui::MainWindow *ui; ArgParser *p_args; RegistryHive *p_hive; bool is_hive_open; bool is_hive_writable; QByteArray selected_key_value; QList search_result_widgets; Settings *p_settings; // Models RegistryNodeTreeModel *p_reg_node_tree_model; RegistryNodeTreeModelProxy *p_reg_node_tree_model_proxy; RegistryKeyTableModel *p_reg_key_table_model; // Widgets etc... RegistryNodeTree *p_node_tree; RegistryKeyTable *p_key_table; TabWidget *p_tab_widget; HexEditWidget *p_hex_edit_widget; QSplitter *p_horizontal_splitter; QSplitter *p_vertical_splitter; Reports *p_reports; QMenu *p_recently_opened_menu; // Threads ThreadSearch *p_search_thread; // Functions void OpenHive(QString hive_file); void UpdateWindowTitle(QString filename=""); void UpdateMenuStates(); void ClearRecentlyOpenedMenu(); void UpdateRecentlyOpenedMenu(); void UpdateEnableWriteSupportMenu(); - bool SaveHiveChanges(); + bool SaveHiveChanges(bool force=false); }; #endif // MAINWINDOW_H diff --git a/trunk/mainwindow.ui b/trunk/mainwindow.ui index f71b0df..6056ea3 100644 --- a/trunk/mainwindow.ui +++ b/trunk/mainwindow.ui @@ -1,184 +1,187 @@ MainWindow 0 0 508 317 0 0 0 0 MainWindow :/icons/resources/fred.png:/icons/resources/fred.png 0 0 508 - 27 + 29 &File - + - + - + &Help - - + + true &Reports &Edit - + - + &Open hive Ctrl+O - + false Close hive - + &Quit Ctrl+Q - + About Qt - + About fred - + false - &Search + &Find - Ctrl+S + Ctrl+F true &Preferences false Generate report false Reload report templates false Recently opened false Enable &write support false - Save + &Save + + + Ctrl+S diff --git a/trunk/qhexedit/qhexedit.h b/trunk/qhexedit/qhexedit.h index e427efb..f399ae7 100644 --- a/trunk/qhexedit/qhexedit.h +++ b/trunk/qhexedit/qhexedit.h @@ -1,177 +1,178 @@ /******************************************************************************* * qhexedit Copyright (c) 2011-2013 by Gillen Daniel * * * * Simple hex editor widget for Qt. * * * * Derived from code by Simon Winfried under a compatible license: * * Copyright (c) 2010 by Simon Winfried * * * * 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 3 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. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #ifndef QHEXEDIT_H #define QHEXEDIT_H #include + #include "qhexedit_p.h" /** \mainpage QHexEdit is a binary editor widget for Qt. \version Version 0.4.6 \image html hexedit.png */ /*! QHexEdit is a hex editor widget written in C++ for the Qt (Qt4) framework. It is a simple editor for binary data, just like QPlainTextEdit is for text data. There are sip configuration files included, so it is easy to create bindings for PyQt and you can use this widget also in python. QHexEdit takes the data of a QByteArray (setData()) and shows it. You can use the mouse or the keyboard to navigate inside the widget. If you hit the keys (0..9, a..f) you will change the data. Changed data is highlighted and can be accessed via data(). Normaly QHexEdit works in the overwrite Mode. You can set overwriteMode(false) and insert data. In this case the size of data() increases. It is also possible to delete bytes under the cursor, here the size of data decreases. There are some limitations: The size of data has in general to be below 10 megabytes, otherwise the scroll sliders ard not shown and you can't scroll any more. Copy and paste functionality is perhaps a subject of a later release. */ class QHexEdit : public QScrollArea { Q_OBJECT /*! Property data holds the content of QHexEdit. Call setData() to set the content of QHexEdit, data() returns the actual content. */ Q_PROPERTY(QByteArray data READ data WRITE setData) /*! Property addressOffset is added to the Numbers of the Address Area. A offset in the address area (left side) is sometimes usefull, whe you show only a segment of a complete memory picture. With setAddressOffset() you set this property - with addressOffset() you get the actual value. */ Q_PROPERTY(int addressOffset READ addressOffset WRITE setAddressOffset) /*! Property address area color sets (setAddressAreaColor()) the backgorund color of address areas. You can also read the color (addressaAreaColor()). */ Q_PROPERTY(QColor addressAreaColor READ addressAreaColor WRITE setAddressAreaColor) /*! Property highlighting color sets (setHighlightingColor()) the backgorund color of highlighted text areas. You can also read the color (highlightingColor()). */ Q_PROPERTY(QColor highlightingColor READ highlightingColor WRITE setHighlightingColor) /*! Porperty overwrite mode sets (setOverwriteMode()) or gets (overwriteMode()) the mode in which the editor works. In overwritem mode the user will overwrite existing data. */ Q_PROPERTY(bool overwriteMode READ overwriteMode WRITE setOverwriteMode) /*! Porperty read only sets (setReadOnly()) or gets (readOnly()) the current editable mode. */ Q_PROPERTY(bool readOnly READ readOnly WRITE setReadOnly) public: /*! Creates an instance of QHexEdit. \param parent Parent widget of QHexEdit. */ QHexEdit(QWidget *parent = 0); /*! Inserts a byte array. \param i Index position, where to insert \param ba byte array, which is to insert */ void insert(int i, const QByteArray & ba); /*! Inserts a char. \param i Index position, where to insert \param ch Char, which is to insert */ void insert(int i, char ch); /*! Removes len bytes from the content. \param pos Index position, where to remove \param len Amount of bytes to remove */ void remove(int pos, int len=1); /*! Set the font of the widget. Please use fixed width fonts like Mono or Courier.*/ void setFont(const QFont &); /*! \cond docNever */ void setAddressOffset(int offset); int addressOffset(); void setData(QByteArray const &data); QByteArray data(); void setAddressAreaColor(QColor const &color); QColor addressAreaColor(); void setHighlightingColor(QColor const &color); QColor highlightingColor(); void setOverwriteMode(bool); bool overwriteMode(); void setReadOnly(bool); bool readOnly(); /*! \endcond docNever */ public slots: /*! Set the minimum width of the address area. \param addressWidth Width in characters. */ void setAddressWidth(int addressWidth); /*! Switch the address area on or off. \param addressArea true (show it), false (hide it). */ void setAddressArea(bool addressArea); /*! Switch the ascii area on or off. \param asciiArea true (show it), false (hide it). */ void setAsciiArea(bool asciiArea); /*! Switch the highlighting feature on or of. \param mode true (show it), false (hide it). */ void setHighlighting(bool mode); signals: /*! Contains the address, where the cursor is located. */ void currentAddressChanged(int address); /*! Contains the size of the data to edit. */ void currentSizeChanged(int size); /*! The signal is emited every time, the data is changed. */ void dataChanged(); /*! The signal is emited every time, the overwrite mode is changed. */ void overwriteModeChanged(bool state); private: /*! \cond docNever */ QHexEditPrivate *qHexEdit_p; QHBoxLayout *layout; QScrollArea *scrollArea; /*! \endcond docNever */ }; #endif diff --git a/trunk/qtscript_types/bytearray.cpp b/trunk/qtscript_types/bytearray.cpp index 0eed658..e65d855 100644 --- a/trunk/qtscript_types/bytearray.cpp +++ b/trunk/qtscript_types/bytearray.cpp @@ -1,181 +1,181 @@ /******************************************************************************* * Copyright (c) 2011-2013 by Gillen Daniel * * * * Derived from code by Nokia Corporation and/or its subsidiary(-ies) under a * * compatible license: * * * * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). * * All rights reserved. * * * * 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 3 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. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #include +#include + #include "bytearray.h" #include "bytearrayiterator.h" #include "bytearrayprototype.h" -#include - Q_DECLARE_METATYPE(QByteArray*) Q_DECLARE_METATYPE(ByteArray*) ByteArray::ByteArray(QScriptEngine *engine) : QObject(engine), QScriptClass(engine) { qScriptRegisterMetaType(engine, this->toScriptValue, this->fromScriptValue); this->length=engine->toStringHandle(QLatin1String("length")); this->proto=engine->newQObject(new ByteArrayPrototype(this), QScriptEngine::QtOwnership, QScriptEngine::SkipMethodsInEnumeration | QScriptEngine::ExcludeSuperClassMethods | QScriptEngine::ExcludeSuperClassProperties); QScriptValue global=engine->globalObject(); proto.setPrototype(global.property("Object").property("prototype")); this->ctor=engine->newFunction(this->construct,this->proto); this->ctor.setData(qScriptValueFromValue(engine,this)); } ByteArray::~ByteArray() {} QScriptClass::QueryFlags ByteArray::queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id) { QByteArray *ba=qscriptvalue_cast(object.data()); if(!ba) return 0; if(name!=this->length) { bool is_array_index; qint32 pos=name.toArrayIndex(&is_array_index); if(!is_array_index) return 0; *id=pos; if((flags & HandlesReadAccess) && (pos>=ba->size())) flags &= ~HandlesReadAccess; } return flags; } QScriptValue ByteArray::property(const QScriptValue &object, const QScriptString &name, uint id) { QByteArray *ba=qscriptvalue_cast(object.data()); if(!ba) return QScriptValue(); if(name==length) return ba->length(); else { qint32 pos=id; if((pos < 0) || (pos >= ba->size())) return QScriptValue(); return uint(ba->at(pos)) & 255; } return QScriptValue(); } void ByteArray::setProperty(QScriptValue &object, const QScriptString &name, uint id, const QScriptValue &value) { QByteArray *ba=qscriptvalue_cast(object.data()); if(!ba) return; if(name==length) this->resize(*ba,value.toInt32()); else { qint32 pos=id; if(pos<0) return; if(ba->size()<=pos) this->resize(*ba,pos + 1); (*ba)[pos]=char(value.toInt32()); } } QScriptValue::PropertyFlags ByteArray::propertyFlags(const QScriptValue &object, const QScriptString &name, uint id) { Q_UNUSED(object); Q_UNUSED(id); if(name==length) { return QScriptValue::Undeletable | QScriptValue::SkipInEnumeration; } return QScriptValue::Undeletable; } QScriptClassPropertyIterator *ByteArray::newIterator(const QScriptValue &object) { return new ByteArrayIterator(object); } QString ByteArray::name() const { return QLatin1String("ByteArray"); } QScriptValue ByteArray::prototype() const { return proto; } QScriptValue ByteArray::constructor() { return ctor; } QScriptValue ByteArray::newInstance(int size) { #if QT_VERSION >= 0x040700 this->engine()->reportAdditionalMemoryCost(size); #endif return newInstance(QByteArray(size,0)); } QScriptValue ByteArray::newInstance(const QByteArray &ba) { QScriptValue data=engine()->newVariant(qVariantFromValue(ba)); return engine()->newObject(this,data); } QScriptValue ByteArray::construct(QScriptContext *ctx, QScriptEngine *) { ByteArray *cls=qscriptvalue_cast(ctx->callee().data()); if(!cls) return QScriptValue(); QScriptValue arg=ctx->argument(0); if(arg.instanceOf(ctx->callee())) return cls->newInstance(qscriptvalue_cast(arg)); int size=arg.toInt32(); return cls->newInstance(size); } QScriptValue ByteArray::toScriptValue(QScriptEngine *eng, const QByteArray &ba) { QScriptValue ctor=eng->globalObject().property("ByteArray"); ByteArray *cls=qscriptvalue_cast(ctor.data()); if(!cls) return eng->newVariant(qVariantFromValue(ba)); return cls->newInstance(ba); } void ByteArray::fromScriptValue(const QScriptValue &obj, QByteArray &ba) { ba=qvariant_cast(obj.data().toVariant()); } void ByteArray::resize(QByteArray &ba, int newSize) { int oldSize=ba.size(); ba.resize(newSize); #if QT_VERSION >= 0x040700 if(newSize>oldSize) this->engine()->reportAdditionalMemoryCost(newSize-oldSize); #endif } diff --git a/trunk/qtscript_types/bytearrayiterator.cpp b/trunk/qtscript_types/bytearrayiterator.cpp index c499d2b..747cbee 100644 --- a/trunk/qtscript_types/bytearrayiterator.cpp +++ b/trunk/qtscript_types/bytearrayiterator.cpp @@ -1,74 +1,74 @@ /******************************************************************************* * Copyright (c) 2011-2013 by Gillen Daniel * * * * Derived from code by Nokia Corporation and/or its subsidiary(-ies) under a * * compatible license: * * * * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). * * All rights reserved. * * * * 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 3 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. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ -#include "bytearrayiterator.h" - #include +#include "bytearrayiterator.h" + Q_DECLARE_METATYPE(QByteArray*) ByteArrayIterator::ByteArrayIterator(const QScriptValue &object) : QScriptClassPropertyIterator(object) { toFront(); } ByteArrayIterator::~ByteArrayIterator() {} bool ByteArrayIterator::hasNext() const { QByteArray *ba=qscriptvalue_cast(object().data()); return m_indexsize(); } void ByteArrayIterator::next() { m_last=m_index; ++m_index; } bool ByteArrayIterator::hasPrevious() const { return(m_index>0); } void ByteArrayIterator::previous() { --m_index; m_last=m_index; } void ByteArrayIterator::toFront() { m_index=0; m_last=-1; } void ByteArrayIterator::toBack() { QByteArray *ba=qscriptvalue_cast(object().data()); m_index=ba->size(); m_last=-1; } QScriptString ByteArrayIterator::name() const { return this->object().engine()->toStringHandle(QString::number(this->m_last)); } uint ByteArrayIterator::id() const { return m_last; } diff --git a/trunk/qtscript_types/bytearrayprototype.cpp b/trunk/qtscript_types/bytearrayprototype.cpp index c61f06c..af6fb83 100644 --- a/trunk/qtscript_types/bytearrayprototype.cpp +++ b/trunk/qtscript_types/bytearrayprototype.cpp @@ -1,109 +1,110 @@ /******************************************************************************* * Copyright (c) 2011-2013 by Gillen Daniel * * * * Derived from code by Nokia Corporation and/or its subsidiary(-ies) under a * * compatible license: * * * * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). * * All rights reserved. * * * * 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 3 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. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ -#include "bytearrayprototype.h" #include +#include "bytearrayprototype.h" + Q_DECLARE_METATYPE(QByteArray*) ByteArrayPrototype::ByteArrayPrototype(QObject *p_parent) : QObject(p_parent) {} ByteArrayPrototype::~ByteArrayPrototype() {} QByteArray *ByteArrayPrototype::thisByteArray() const { return qscriptvalue_cast(thisObject().data()); } void ByteArrayPrototype::chop(int n) { thisByteArray()->chop(n); } bool ByteArrayPrototype::equals(const QByteArray &other) { return *thisByteArray()==other; } QByteArray ByteArrayPrototype::left(int len) const { return thisByteArray()->left(len); } QByteArray ByteArrayPrototype::mid(int pos, int len) const { return thisByteArray()->mid(pos,len); } QScriptValue ByteArrayPrototype::remove(int pos, int len) { thisByteArray()->remove(pos,len); return thisObject(); } QScriptValue ByteArrayPrototype::append(const QByteArray &ba) { thisByteArray()->append(ba); return thisObject(); } QScriptValue ByteArrayPrototype::appendByte(char byte) const { thisByteArray()->append(byte); return thisObject(); } QByteArray ByteArrayPrototype::right(int len) const { return thisByteArray()->right(len); } /* QByteArray ByteArrayPrototype::simplified() const { return thisByteArray()->simplified(); } */ int ByteArrayPrototype::size() const { return thisByteArray()->size(); } QByteArray ByteArrayPrototype::toBase64() const { return thisByteArray()->toBase64(); } QByteArray ByteArrayPrototype::toLower() const { return thisByteArray()->toLower(); } QByteArray ByteArrayPrototype::toUpper() const { return thisByteArray()->toUpper(); } QByteArray ByteArrayPrototype::trimmed() const { return thisByteArray()->trimmed(); } void ByteArrayPrototype::truncate(int pos) { thisByteArray()->truncate(pos); } QString ByteArrayPrototype::toLatin1String() const { return QString::fromLatin1(*thisByteArray()); } QScriptValue ByteArrayPrototype::valueOf() const { return thisObject().data(); } diff --git a/trunk/registryhive.cpp b/trunk/registryhive.cpp index 60bc408..00ad235 100644 --- a/trunk/registryhive.cpp +++ b/trunk/registryhive.cpp @@ -1,1359 +1,1362 @@ /******************************************************************************* * fred Copyright (c) 2011-2013 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * 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 3 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. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #include #include -#include -#include #include +#include +#include + #include "registryhive.h" #define MACROS_ENDIANNESS #include "macros.h" // TODO: __WORDSIZE is not defined under mingw and I currently have no idea how // to identify a 64bit windows #ifndef __WORDSIZE #define __WORDSIZE 32 #endif #if __WORDSIZE == 64 #define EPOCH_DIFF 0x19DB1DED53E8000 #else #define EPOCH_DIFF 0x19DB1DED53E8000LL #endif /******************************************************************************* * Public ******************************************************************************/ /* * RegistryHive */ RegistryHive::RegistryHive(QObject *p_parent) : QObject(p_parent) { this->erro_msg=""; this->is_error=false; this->hive_file=""; this->p_hive=NULL; this->is_hive_open=false; this->is_hive_writable=false; this->has_changes_to_commit=false; } /* * ~RegistryHive */ RegistryHive::~RegistryHive() { if(this->is_hive_open) this->Close(); } /* * Error */ bool RegistryHive::Error() { return this->is_error; } /* * GetErrorMsg */ QString RegistryHive::GetErrorMsg() { QString msg=this->erro_msg; this->erro_msg=""; this->is_error=false; return msg; } /* * Open */ bool RegistryHive::Open(QString file, bool read_only) { if(this->is_hive_open) return false; // Open hive file this->p_hive=hivex_open(file.toAscii().constData(), read_only ? 0 : HIVEX_OPEN_WRITE); if(this->p_hive==NULL) return false; // Set local vars this->hive_file=file; this->is_hive_open=true; this->is_hive_writable=!read_only; return true; } /* * Reopen */ bool RegistryHive::Reopen(bool read_only) { if(!this->is_hive_open) return false; // Close hive first if(hivex_close(this->p_hive)!=0) { // According to the docs, even if hivex_close fails, it frees all handles. // So we consider this fatal and final! this->hive_file=""; this->is_hive_open=false; this->is_hive_writable=false; this->has_changes_to_commit=false; return false; } // Reopen same hive this->p_hive=hivex_open(this->hive_file.toAscii().constData(), read_only ? 0 : HIVEX_OPEN_WRITE); if(this->p_hive==NULL) { this->hive_file=""; this->is_hive_open=false; this->is_hive_writable=false; this->has_changes_to_commit=false; return false; } // Update local vars this->is_hive_writable=!read_only; this->has_changes_to_commit=false; return true; } /* * CommitChanges */ bool RegistryHive::CommitChanges() { if(!this->is_hive_open || !this->is_hive_writable) return false; if(!this->has_changes_to_commit) return true; // TODO: Maybe it would be more secure to commit changes to a new file and // then move it over the original one. if(hivex_commit(this->p_hive,NULL,0)!=0) { return false; } + + this->has_changes_to_commit=false; return true; } /* * Close */ bool RegistryHive::Close() { if(this->is_hive_open) { // As hivex_close will _ALWAYS_ free the handle, we don't need the following // values anymore this->hive_file=""; this->is_hive_open=false; this->is_hive_writable=false; this->has_changes_to_commit=false; // Close hive if(hivex_close(this->p_hive)!=0) return false; } return true; } /* * Filename */ QString RegistryHive::Filename() { if(this->is_hive_open) return this->hive_file; return QString(); } /* * HiveType */ RegistryHive::teHiveType RegistryHive::HiveType() { // Check for SYSTEM hive if(this->PathExists("\\Select") && this->PathExists("\\MountedDevices")) return RegistryHive::eHiveType_SYSTEM; // Check for SOFTWARE hive if(this->PathExists("\\Microsoft\\Windows\\CurrentVersion") && this->PathExists("\\Microsoft\\Windows NT\\CurrentVersion")) return RegistryHive::eHiveType_SOFTWARE; // Check for SAM if(this->PathExists("SAM\\Domains\\Account\\Users")) return RegistryHive::eHiveType_SAM; // Check for SECURITY if(this->PathExists("\\Policy\\Accounts") && this->PathExists("\\Policy\\PolAdtEv")) return RegistryHive::eHiveType_SECURITY; // Check for NTUSER.DAT if(this->PathExists("\\Software\\Microsoft\\Windows\\CurrentVersion")) return RegistryHive::eHiveType_NTUSER; // Unknown hive return RegistryHive::eHiveType_UNKNOWN; } /* * HiveTypeToString */ QString RegistryHive::HiveTypeToString(teHiveType hive_type) { switch(hive_type) { case RegistryHive::eHiveType_SYSTEM: return "SYSTEM"; break; case RegistryHive::eHiveType_SOFTWARE: return "SOFTWARE"; break; case RegistryHive::eHiveType_SAM: return "SAM"; break; case RegistryHive::eHiveType_SECURITY: return "SECURITY"; break; case RegistryHive::eHiveType_NTUSER: return "NTUSER"; break; default: return "UNKNOWN"; } } /* * HasChangesToCommit */ bool RegistryHive::HasChangesToCommit() { return this->has_changes_to_commit; } /* * GetNodes */ QMap RegistryHive::GetNodes(QString path) { hive_node_h parent_node; // Get handle to last node in path if(!this->GetNodeHandle(path,&parent_node)) return QMap(); // Get and return nodes return this->GetNodesHelper(parent_node); } /* * GetNodes */ QMap RegistryHive::GetNodes(int parent_node) { if(parent_node==0) { this->SetError(tr("Invalid parent node handle specified!")); return QMap(); } // Get and return nodes return this->GetNodesHelper(parent_node); } /* * GetKeys */ QMap RegistryHive::GetKeys(QString path) { hive_node_h parent_node; // Get handle to last node in path if(!this->GetNodeHandle(path,&parent_node)) return QMap(); // Get and return keys return this->GetKeysHelper(parent_node); } /* * GetKeys */ QMap RegistryHive::GetKeys(int parent_node) { if(parent_node==0) { this->SetError(tr("Invalid parent node handle specified!")); return QMap(); } // Get and return keys return this->GetKeysHelper(parent_node); } /* * GetKeyName */ bool RegistryHive::GetKeyName(int hive_key, QString &key_name) { char *buf; if(!this->is_hive_open) { this->SetError(tr("Need to operate on an open hive!")); return false; } buf=hivex_value_key(this->p_hive,(hive_value_h)hive_key); if(buf==NULL) { this->SetError(tr("Unable to get key name for key '%1'").arg(hive_key)); return false; } key_name=QString(buf); free(buf); return true; } /* * GetKeyValue */ QByteArray RegistryHive::GetKeyValue(QString path, QString key, int *p_value_type, size_t *p_value_len) { hive_node_h parent_node; hive_value_h hive_key; // Get handle to last node in path if(!this->GetNodeHandle(path,&parent_node)) return QByteArray(); // Get key handle hive_key=hivex_node_get_value(this->p_hive, parent_node,key.toAscii().constData()); if(hive_key==0) { this->SetError(tr("Unable to get key handle!")); *p_value_len=-1; return QByteArray(); } // Get and return key value return this->GetKeyValueHelper(hive_key,p_value_type,p_value_len); } /* * GetKeyValue */ QByteArray RegistryHive::GetKeyValue(int hive_key, int *p_value_type, size_t *p_value_len) { if(hive_key==0) { this->SetError(tr("Invalid key handle specified!")); *p_value_type=-1; return QByteArray(); } // Get and return key value return this->GetKeyValueHelper(hive_key,p_value_type,p_value_len); } /* * GetKeyModTime */ int64_t RegistryHive::GetNodeModTime(QString path) { hive_node_h node; // Get handle to last node in path if(!this->GetNodeHandle(path,&node)) { this->SetError(tr("Unable to get node handle!")); return 0; } // Get and return node's last modification timestamp return this->GetNodeModTime(node); } /* * GetKeyModTime */ int64_t RegistryHive::GetNodeModTime(int node) { if(node==0) { this->SetError(tr("Invalid node handle specified!")); return 0; } // Get and return key's last modification timestamp return hivex_node_timestamp(this->p_hive,node); } /* * KeyValueToString */ QString RegistryHive::KeyValueToString(QByteArray value, int value_type) { QString ret=""; #define ToHexStr() { \ for(int i=0;i=2 && value.endsWith(QByteArray("\x00\x00",2))) { // Seems to be a unicode string, convert to host endianness and return // TODO: What if it is UTF16-BE?? Thx Billy! QByteArray buf=value; UTF16LETOH(buf.data(),buf.size()); ret=QString().fromUtf16((ushort*)(buf.constData())); } else if(value.endsWith(QByteArray("\x00",1))) { // Seems to be an ansi string ret=QString().fromAscii((char*)value.constData()); } else { // If we can't detect encoding, return string as hex ToHexStr(); } break; case hive_t_REG_MULTI_SZ: // Multiple Windows strings. // I suppose this is always LE encoded! M$ devs really suck! ret=RegistryHive::KeyValueToStringList(value).join("\n"); break; case hive_t_REG_DWORD: // DWORD (32 bit integer), little endian ret=QString().sprintf("0x%08X",LE32TOH(*(uint32_t*)value.constData())); break; case hive_t_REG_DWORD_BIG_ENDIAN: // DWORD (32 bit integer), big endian ret=QString().sprintf("0x%08X",BE32TOH(*(uint32_t*)value.constData())); break; case hive_t_REG_QWORD: // QWORD (64 bit integer). Usually little endian (grrrr). ret= QString("0x%1").arg((quint64)LE64TOH(*(uint64_t*)value.constData()), 16, 16, QChar('0')); break; case hive_t_REG_NONE: case hive_t_REG_BINARY: case hive_t_REG_LINK: case hive_t_REG_RESOURCE_LIST: case hive_t_REG_FULL_RESOURCE_DESCRIPTOR: case hive_t_REG_RESOURCE_REQUIREMENTS_LIST: default: // A key without a value (REG_NONE), a blob of binary (REG_BINARY), a // symbolic link to another part of the registry tree (REG_LINK), a // resource list (REG_RESOURCE_LIST), a resource descriptor // (FULL_RESOURCE_DESCRIPTOR), a resource requirements list // (REG_RESOURCE_REQUIREMENTS_LIST) or something unknown. // All these are converted to hex. ToHexStr(); } #undef ToHexStr return ret; } /* * KeyValueToString */ QString RegistryHive::KeyValueToString(QByteArray key_value, QString format, int offset, int length, bool little_endian) { int remaining_data_len; const char *p_data; QString ret=""; // Calculate how many bytes are remainig after specified offset remaining_data_len=key_value.size()-offset; if(!remaining_data_len>0) { // Nothing to show return QString(); } // Get pointer to data at specified offset p_data=key_value.constData(); p_data+=offset; // Convert value if(format=="int8" && remaining_data_len>=1) { ret=QString().sprintf("%d",*(int8_t*)p_data); } else if(format=="uint8" && remaining_data_len>=1) { ret=QString().sprintf("%u",*(uint8_t*)p_data); } else if(format=="int16" && remaining_data_len>=2) { int16_t val; if(little_endian) val=LE16TOH(*(int16_t*)p_data); else val=BE16TOH(*(int16_t*)p_data); ret=QString().sprintf("%d",val); } else if(format=="uint16" && remaining_data_len>=2) { uint16_t val; if(little_endian) val=LE16TOH(*(uint16_t*)p_data); else val=BE16TOH(*(uint16_t*)p_data); ret=QString().sprintf("%u",val); } else if(format=="int32" && remaining_data_len>=4) { int32_t val; if(little_endian) val=LE32TOH(*(int32_t*)p_data); else val=BE32TOH(*(int32_t*)p_data); ret=QString().sprintf("%d",val); } else if(format=="uint32" && remaining_data_len>=4) { uint32_t val; if(little_endian) val=LE32TOH(*(uint32_t*)p_data); else val=BE32TOH(*(uint32_t*)p_data); ret=QString().sprintf("%u",val); } else if(format=="unixtime" && remaining_data_len>=4) { uint32_t val; if(little_endian) val=LE32TOH(*(uint32_t*)p_data); else val=BE32TOH(*(uint32_t*)p_data); if(val==0) { ret="n/a"; } else { QDateTime date_time; date_time.setTimeSpec(Qt::UTC); date_time.setTime_t(val); ret=date_time.toString("yyyy/MM/dd hh:mm:ss"); } } else if(format=="int64" && remaining_data_len>=8) { int64_t val; if(little_endian) val=LE64TOH(*(int64_t*)p_data); else val=BE64TOH(*(int64_t*)p_data); ret=QString("%1").arg(val); } else if(format=="uint64" && remaining_data_len>=8) { uint64_t val; if(little_endian) val=LE64TOH(*(uint64_t*)p_data); else val=BE64TOH(*(uint64_t*)p_data); ret=QString("%1").arg(val); /* // TODO: Check how one could implement this } else if(format=="unixtime64" && remaining_data_len>=8) { if(*(uint64_t*)p_data==0) { ret="n/a"; } else { uint64_t secs=*(uint64_t*)p_data; QDateTime date_time; date_time.setTimeSpec(Qt::UTC); // Set 32bit part of date/time date_time.setTime_t(secs&0xFFFFFFFF); // Now add high 32bit part of date/time date_time.addSecs(secs>>32); ret=date_time.toString("yyyy/MM/dd hh:mm:ss"); } */ } else if(format=="filetime" && remaining_data_len>=8) { uint64_t val; if(little_endian) val=LE64TOH(*(uint64_t*)p_data); else val=BE64TOH(*(uint64_t*)p_data); if(val==0) { ret="n/a"; } else { // TODO: Warn if >32bit QDateTime date_time; date_time.setTimeSpec(Qt::UTC); date_time.setTime_t(RegistryHive::FiletimeToUnixtime(val)); ret=date_time.toString("yyyy/MM/dd hh:mm:ss"); } } else if(format=="ascii") { if(length!=-1) { // User specified how many bytes to convert ret=QString().fromAscii((char*)p_data,length); } else { // User did not specify how many bytes to convert, make sure data is 0 // terminated if(key_value.indexOf("\x00",offset)!=-1) { // Data is 0 terminated ret=QString().fromAscii((char*)p_data); } else { // Data is not 0 terminated, convert all remaining_data_len bytes ret=QString().fromAscii((char*)p_data,remaining_data_len); } } } else if(format=="utf16" && remaining_data_len>=2) { QByteArray buf; if(length!=-1) { // User specified how many bytes to convert buf=key_value.mid(offset,(length%2)==0 ? length : length-1); buf.append("\x00\x00",2); } else { // User did not specify how many bytes to convert, make sure data is // double 0 terminated int null_offset=RegistryHive::FindUnicodeStringEnd(key_value.mid(offset)); if(null_offset!=-1) { // Data is double 0 terminated buf=key_value.mid(offset,null_offset+2); } else { // Data is not double 0 terminated, convert all remaining_data_len bytes buf=key_value.mid(offset, (remaining_data_len%2)==0 ? remaining_data_len : remaining_data_len-1); buf.append("\x00\x00",2); } } // Convert from requested endianness to host if(little_endian) { UTF16LETOH(buf.data(),buf.size()); } else { UTF16BETOH(buf.data(),buf.size()); } ret=QString().fromUtf16((ushort*)buf.constData()); } else { // Unknown variant type or another error // TODO: Maybe return an error return QString(); } return ret; } /* * KeyValueToStringList * * Should only be used for REG_MULTI_SZ values */ QStringList RegistryHive::KeyValueToStringList(QByteArray value, bool little_endian, bool *p_ansi_encoded) { // Try to find value encoding (ANSI vs UNICODE) bool is_ansi; if(value.size()<=2) { // http://blogs.msdn.com/b/oldnewthing/archive/2009/10/08/9904646.aspx // Ansi version of a REG_MULTI_SZ needs to be terminated by 2 \0 chars. // So as long as the byte array has less or equal to 2 chars, it must be // empty. return QStringList(); } else if(value.size()==3) { // Only 3 chars, this can only be an ansi string consisting of 1 char and 2 // \0 to terminate it return QStringList() < strings_it(strings); while(strings_it.hasNext()) { cur_string=strings_it.next(); if(ansi_encoded) { // Ansi encoding, simply append char string and terminating \0 result.append(cur_string.toAscii().constData(),cur_string.size()); result.append("\x00",1); } else { // Unicode encoding // First, convert value to utf16 // TODO: May fail if there is a char that needs more than 16 bit buf=QByteArray((char*)(cur_string.utf16()),cur_string.size()*2); // Then convert to correct endianness if(little_endian) { HTOUTF16LE(buf.data(),buf.size()); } else { HTOUTF16BE(buf.data(),buf.size()); } // And finally append converted value and terminating \0\0 to result result.append(buf); result.append("\x00\x00",2); } } // Append terminating \0 chars and return if(ansi_encoded) result.append("\x00",1); else result.append("\x00\x00",2); return result; } /* * GetKeyValueTypes */ QStringList RegistryHive::GetKeyValueTypes() { return QStringList()<<"REG_NONE" <<"REG_SZ" <<"REG_EXPAND_SZ" <<"REG_BINARY" <<"REG_DWORD" <<"REG_DWORD_BIG_ENDIAN" <<"REG_LINK" <<"REG_MULTI_SZ" <<"REG_RESOURCE_LIST" <<"REG_FULL_RESOURCE_DESC" <<"REG_RESOURCE_REQ_LIST" <<"REG_QWORD"; } /* * KeyTypeToString */ QString RegistryHive::KeyValueTypeToString(int value_type) { QString ret=""; switch(value_type) { case hive_t_REG_NONE: ret="REG_NONE"; break; case hive_t_REG_SZ: ret="REG_SZ"; break; case hive_t_REG_EXPAND_SZ: ret="REG_EXPAND_SZ"; break; case hive_t_REG_BINARY: ret="REG_BINARY"; break; case hive_t_REG_DWORD: ret="REG_DWORD"; break; case hive_t_REG_DWORD_BIG_ENDIAN: ret="REG_DWORD_BIG_ENDIAN"; break; case hive_t_REG_LINK: ret="REG_LINK"; break; case hive_t_REG_MULTI_SZ: ret="REG_MULTI_SZ"; break; case hive_t_REG_RESOURCE_LIST: ret="REG_RESOURCE_LIST"; break; case hive_t_REG_FULL_RESOURCE_DESCRIPTOR: ret="REG_FULL_RESOURCE_DESC"; break; case hive_t_REG_RESOURCE_REQUIREMENTS_LIST: ret="REG_RESOURCE_REQ_LIST"; break; case hive_t_REG_QWORD: ret="REG_QWORD"; break; default: ret=QString().sprintf("0x%08X",(uint32_t)value_type); } return ret; } /* * StringToKeyValueType */ int RegistryHive::StringToKeyValueType(QString value_type) { if(value_type=="REG_NONE") return hive_t_REG_NONE; if(value_type=="REG_SZ") return hive_t_REG_SZ; if(value_type=="REG_EXPAND_SZ") return hive_t_REG_EXPAND_SZ; if(value_type=="REG_BINARY") return hive_t_REG_BINARY; if(value_type=="REG_DWORD") return hive_t_REG_DWORD; if(value_type=="REG_DWORD_BIG_ENDIAN") return hive_t_REG_DWORD_BIG_ENDIAN; if(value_type=="REG_LINK") return hive_t_REG_LINK; if(value_type=="REG_MULTI_SZ") return hive_t_REG_MULTI_SZ; if(value_type=="REG_RESOURCE_LIST") return hive_t_REG_RESOURCE_LIST; if(value_type=="REG_FULL_RESOURCE_DESC") return hive_t_REG_FULL_RESOURCE_DESCRIPTOR; if(value_type=="REG_RESOURCE_REQ_LIST") return hive_t_REG_RESOURCE_REQUIREMENTS_LIST; if(value_type=="REG_QWORD") return hive_t_REG_QWORD; // I think this might be a good default :-) return hive_t_REG_BINARY; } /* * FiletimeToUnixtime */ uint64_t RegistryHive::FiletimeToUnixtime(int64_t filetime) { return (unsigned)((filetime-EPOCH_DIFF)/10000000); } /* * AddNode */ int RegistryHive::AddNode(QString parent_node_path, QString node_name) { if(!this->is_hive_writable) return 0; // Make sure name does not contain a backslash char if(node_name.contains('\\')) { this->SetError(tr("Unable to add node with name '%1'. " "Names can not include a backslash character.") .arg(node_name)); return 0; } // Get node handle to the parent where the new node should be created hive_node_h parent_node; if(!this->GetNodeHandle(parent_node_path,&parent_node)) { this->SetError(tr("Unable to get node handle for '%1'!") .arg(parent_node_path)); return 0; } // Make sure there is no other node with same name QMap child_nodes=this->GetNodes(parent_node); if(child_nodes.contains(node_name.toAscii())) { this->SetError(tr("The node '%1\\%2' already exists!") .arg(parent_node_path,node_name)); return 0; } // Add new node hive_node_h new_node=hivex_node_add_child(this->p_hive, parent_node, node_name.toAscii().constData()); if(new_node==0) { this->SetError(tr("Unable to create new node '%1\\%2'!") .arg(parent_node_path,node_name)); return 0; } this->has_changes_to_commit=true; return new_node; } /* * DeleteNode */ bool RegistryHive::DeleteNode(QString node_path) { if(!this->is_hive_writable) return false; // Get node handle to the node that should be deleted hive_node_h node; if(!this->GetNodeHandle(node_path,&node)) { this->SetError(tr("Unable to get node handle for '%1'!") .arg(node_path)); return false; } // Delete node if(hivex_node_delete_child(this->p_hive,node)==-1) { this->SetError(tr("Unable to delete node '%1'!") .arg(node_path)); return false; } this->has_changes_to_commit=true; return true; } /* * AddKey */ int RegistryHive::AddKey(QString parent_node_path, QString key_name, QString key_value_type, QByteArray key_value) { if(!this->is_hive_open || !this->is_hive_writable) { this->SetError(tr("Hive has not been opened or opened read-only!")); return false; } return this->SetKey(parent_node_path, key_name, key_value_type, key_value, true); } /* * UpdateKey */ int RegistryHive::UpdateKey(QString parent_node_path, QString key_name, QString key_value_type, QByteArray key_value) { if(!this->is_hive_open || !this->is_hive_writable) { this->SetError(tr("Hive has not been opened or opened read-only!")); return false; } return this->SetKey(parent_node_path, key_name, key_value_type, key_value, false); } /* * DeleteKey */ bool RegistryHive::DeleteKey(QString parent_node_path, QString key_name) { if(!this->is_hive_open || !this->is_hive_writable) { this->SetError(tr("Hive has not been opened or opened read-only!")); return false; } // libhivex offers no possibility to delete a single key :-( // As a work around, this function temporarly stores all keys of the specified // node, then deletes them all an re-creates all but the one that should be // deleted. // Get handle to parent node hive_node_h parent_node; if(!this->GetNodeHandle(parent_node_path,&parent_node)) { return false; } // Get all child keys hive_value_h *p_keys=hivex_node_values(this->p_hive,parent_node); if(p_keys==NULL) { this->SetError(tr("Unable to enumerate child keys for parent '%1'!") .arg(parent_node_path)); return false; } // Get all child key values except the one that should be deleted int i=0; char *p_name; int node_keys_count=0; hive_set_value *node_keys=NULL; #define FREE_NODE_KEYS() { \ for(int x=0;xp_hive,p_keys[i]); if(p_name==NULL) { this->SetError(tr("Unable to get key name for a child of '%1'!") .arg(parent_node_path)); return false; } if(QString(p_name)!=key_name) { // Current key is not the one that should be deleted, save it // Alloc mem for new hive_set_value struct in node_keys array node_keys=(hive_set_value*)realloc(node_keys, sizeof(hive_set_value)* (node_keys_count+1)); if(node_keys==NULL) { this->SetError(tr("Unable to alloc enough memory for all child keys!")); return false; } // Save key name in hive_set_value struct node_keys[node_keys_count].key=p_name; // Get key value, key value type and key value len and save to // hive_set_value struct node_keys[node_keys_count].value= hivex_value_value(this->p_hive, p_keys[i], &(node_keys[node_keys_count].t), &(node_keys[node_keys_count].len)); if(node_keys[node_keys_count].value==NULL) { this->SetError(tr("Unable to get value for key '%1'!").arg(p_name)); free(p_name); // Free all temporary stored keys FREE_NODE_KEYS(); return false; } node_keys_count++; } else { // Current key is to be deleted, ignore it free(p_name); } i++; } // Save all stored keys to hive, which will discard the one that should be // deleted if(hivex_node_set_values(this->p_hive, parent_node, node_keys_count, node_keys, 0)!=0) { this->SetError(tr("Unable to re-save all child keys! Please discard any " "changes you made and start over. No doing so might end " "in data loss!")); // Free all temporary stored keys FREE_NODE_KEYS(); return false; } // Free all temporary stored keys and return FREE_NODE_KEYS(); #undef FREE_NODE_KEYS this->has_changes_to_commit=true; return true; } /******************************************************************************* * Private ******************************************************************************/ /* * HivexError2String */ QString RegistryHive::HivexError2String(int error) { switch(error) { case ENOTSUP: return QString("Corrupt or unsupported Registry file format."); break; case HIVEX_NO_KEY: return QString("Missing root key."); break; case EINVAL: return QString("Passed an invalid argument to the function."); break; case EFAULT: return QString("Followed a Registry pointer which goes outside the " "registry or outside a registry block."); break; case ELOOP: return QString("Registry contains cycles."); break; case ERANGE: return QString("Field in the registry out of range."); break; case EEXIST: return QString("Registry key already exists."); break; case EROFS: return QString("Tried to write to a registry which is not opened for " "writing."); break; default: return QString("Unknown error."); } } /* * SetError */ void RegistryHive::SetError(QString msg) { this->erro_msg=msg; this->is_error=true; } /* * GetNodeHandle */ bool RegistryHive::GetNodeHandle(QString &path, hive_node_h *p_node) { QStringList nodes; int i=0; // Get root node handle *p_node=hivex_root(this->p_hive); if(*p_node==0) { this->SetError(tr("Unable to get root node!")); return false; } if(path!="\\") { // If we aren't listing the root node, we have to get a handle to the // last node in the path. Split path into nodes nodes=path.split('\\',QString::SkipEmptyParts); // Iterate to the correct parent node for(i=0;ip_hive, *p_node, nodes.value(i).toAscii().constData()); if(*p_node==0) { this->SetError(tr("Unable to find node '%1'!").arg(nodes.value(i))); return false; } } } return true; } /* * GetKeyHandle */ bool RegistryHive::GetKeyHandle(QString &parent_node_path, QString &key_name, hive_value_h *p_key) { // Get handle to parent node hive_node_h parent_node; if(!this->GetNodeHandle(parent_node_path,&parent_node)) { return false; } // Get handle to key *p_key=hivex_node_get_value(this->p_hive, parent_node, key_name.toAscii().constData()); if(*p_key==0) { this->SetError(tr("Unable to get handle to key '%1\\%2'!") .arg(parent_node_path,key_name)); return false; } return true; } /* * GetNodesHelper */ QMap RegistryHive::GetNodesHelper(hive_node_h parent_node) { QMap keys; char *p_name; int i=0; // Get child nodes hive_node_h *child_nodes=hivex_node_children(this->p_hive,parent_node); if(child_nodes==NULL) { this->SetError( tr("Unable to enumerate child nodes!")); return QMap(); } // Build result keys.clear(); i=0; while(child_nodes[i]) { p_name=hivex_node_name(this->p_hive,child_nodes[i]); if(p_name==NULL) { this->SetError(tr("Unable to get node name!")); free(child_nodes); return QMap(); } keys.insert(QString(p_name),(int)child_nodes[i]); free(p_name); i++; } free(child_nodes); return keys; } /* * GetKeysHelper */ QMap RegistryHive::GetKeysHelper(hive_node_h parent_node) { QMap keys; char *p_name; int i=0; // Get child keys hive_value_h *p_keys=hivex_node_values(this->p_hive,parent_node); if(p_keys==NULL) { this->SetError( tr("Unable to enumerate child keys!")); return QMap(); } // Build result list keys.clear(); i=0; while(p_keys[i]) { p_name=hivex_value_key(this->p_hive,p_keys[i]); if(p_name==NULL) { this->SetError(tr("Unable to get key name!")); return QMap(); } keys.insert(QString(p_name),p_keys[i]); free(p_name); i++; } free(p_keys); return keys; } /* * GetKeyValueHelper */ QByteArray RegistryHive::GetKeyValueHelper(hive_value_h hive_key, int *p_value_type, size_t *p_value_len) { QByteArray key_value; char *p_key_value; p_key_value=hivex_value_value(this->p_hive, hive_key, (hive_type*)p_value_type, p_value_len); if(p_key_value==NULL) { this->SetError(tr("Unable to get key value!")); *p_value_type=-1; return QByteArray(); } // Feed QByteArray and free p_key_value key_value=QByteArray(p_key_value,*p_value_len); free(p_key_value); return key_value; } /* * PathExists */ bool RegistryHive::PathExists(QString path) { bool ret; hive_node_h node; ret=this->GetNodeHandle(path,&node); if(!ret || this->Error()) { // Clear error and return false this->GetErrorMsg(); return false; } return true; } /* * SetKey */ int RegistryHive::SetKey(QString &parent_node_path, QString &key_name, QString &key_value_type, QByteArray &key_value, bool create_key) { // Get node handle to the node that holds the key to create/update hive_node_h parent_node; if(!this->GetNodeHandle(parent_node_path,&parent_node)) { return 0; } // Make sure key exists if we should update it if(!create_key) { hive_value_h temp_key=hivex_node_get_value(this->p_hive, parent_node, key_name.toAscii().constData()); if(temp_key==0) { this->SetError(tr("Inexisting key '%1\\%2' can't be updated!") .arg(parent_node_path,key_name)); return 0; } } // Create and populate hive_set_value structure hive_set_value key_val; key_val.key=(char*)malloc((sizeof(char)*key_name.toAscii().count())+1); key_val.value=(char*)malloc(sizeof(char)*key_value.size()); if(key_val.key==NULL || key_val.value==NULL) { this->SetError(tr("Unable to alloc memory for hive_set_value struct!")); return 0; } strcpy(key_val.key,key_name.toAscii().constData()); key_val.t=(hive_type)this->StringToKeyValueType(key_value_type); key_val.len=key_value.size(); memcpy(key_val.value,key_value.constData(),key_value.size()); // Create/Update key if(hivex_node_set_value(this->p_hive,parent_node,&key_val,0)!=0) { this->SetError(tr("Unable to update key '%1\\%2'!") .arg(parent_node_path,key_name)); return 0; } // Free the hive_set_value structure free(key_val.key); free(key_val.value); // To make sure everything worked, a hadle to the new key is now requeried // from hive and then returned hive_value_h key; if(!this->GetKeyHandle(parent_node_path,key_name,&key)) { return 0; } this->has_changes_to_commit=true; return key; } /* * FindUnicodeStringEnd */ int RegistryHive::FindUnicodeStringEnd(QByteArray data, int offset) { int end_pos; for(end_pos=offset;end_pos<(data.size()-1);end_pos+=2) { if(*((uint16_t*)(data.constData()+end_pos))==0) break; } return end_pos<(data.size()-1) ? end_pos : -1; } diff --git a/trunk/registrykeytable.cpp b/trunk/registrykeytable.cpp index a15e7b8..63358ea 100644 --- a/trunk/registrykeytable.cpp +++ b/trunk/registrykeytable.cpp @@ -1,213 +1,213 @@ /******************************************************************************* * fred Copyright (c) 2011-2013 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * 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 3 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. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ -#include "registrykeytable.h" - #include #include #include +#include "registrykeytable.h" + /******************************************************************************* * Public ******************************************************************************/ RegistryKeyTable::RegistryKeyTable(QWidget *p_parent) : QTableView(p_parent) { this->is_writable=false; // Configure widget this->setSelectionMode(QAbstractItemView::SingleSelection); this->setSelectionBehavior(QAbstractItemView::SelectRows); this->setAutoScroll(false); this->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); this->verticalHeader()->setHidden(true); this->setTextElideMode(Qt::ElideNone); // Create context menu item this->p_action_add_key=new QAction(tr("Add new key"),this); this->p_action_edit_key=new QAction(tr("Edit selected key"),this); this->p_action_delete_key=new QAction(tr("Delete selected key"),this); this->p_menu_copy=new QMenu(tr("Copy"),this); this->p_action_copy_key_name= new QAction(tr("Selected key name"),this->p_menu_copy); this->p_menu_copy->addAction(this->p_action_copy_key_name); this->p_action_copy_key_value= new QAction(tr("Selected key value"),this->p_menu_copy); this->p_menu_copy->addAction(this->p_action_copy_key_value); // Connect context menu signals this->connect(this->p_action_add_key, SIGNAL(triggered()), this, SLOT(SlotAddKey())); this->connect(this->p_action_edit_key, SIGNAL(triggered()), this, SLOT(SlotEditKey())); this->connect(this->p_action_delete_key, SIGNAL(triggered()), this, SLOT(SlotDeleteKey())); this->connect(this->p_action_copy_key_name, SIGNAL(triggered()), this, SLOT(SlotCopyKeyName())); this->connect(this->p_action_copy_key_value, SIGNAL(triggered()), this, SLOT(SlotCopyKeyValue())); } RegistryKeyTable::~RegistryKeyTable() { // Delete context menu delete this->p_action_copy_key_name; delete this->p_action_copy_key_value; delete this->p_menu_copy; delete this->p_action_delete_key; delete this->p_action_edit_key; delete this->p_action_add_key; } void RegistryKeyTable::setModel(QAbstractItemModel *p_model, bool writable) { QTableView::setModel(p_model); // Resize table rows / columns to fit data this->resizeColumnsToContents(); this->resizeRowsToContents(); this->horizontalHeader()->stretchLastSection(); if(p_model!=NULL && p_model->rowCount()>0) { // Select first table item this->selectRow(0); } // Set writable status this->SetWritable(writable); } void RegistryKeyTable::SetWritable(bool writable) { this->is_writable=writable; this->p_action_add_key->setEnabled(this->is_writable); this->p_action_edit_key->setEnabled(this->is_writable); this->p_action_delete_key->setEnabled(this->is_writable); } /* void RegistryKeyTable::selectRow(QString key_name) { int i; this->clearSelection(); for(i=0;imodel()->rowCount();i++) { if(this->model()) } } */ /******************************************************************************* * Protected ******************************************************************************/ int RegistryKeyTable::sizeHintForColumn(int column) const { int size_hint=-1; int i=0; int item_width=0; QFontMetrics fm(this->fontMetrics()); QModelIndex idx; if(this->model()==NULL) return -1; // Find string that needs the most amount of space idx=this->model()->index(i,column); while(idx.isValid()) { item_width=fm.width(this->model()->data(idx).toString())+10; if(item_width>size_hint) size_hint=item_width; idx=this->model()->index(++i,column); } return size_hint; } void RegistryKeyTable::contextMenuEvent(QContextMenuEvent *p_event) { // Only show context menu if a hive is open (a model was set) if(this->model()==NULL) return; // Decide what menus should be enabled if(this->selectedIndexes().count()==3) { // A row is selected, enable full context menu this->p_action_add_key->setEnabled(this->is_writable); this->p_action_edit_key->setEnabled(this->is_writable); this->p_action_delete_key->setEnabled(this->is_writable); this->p_menu_copy->setEnabled(true); } else { // No row is selected, disable all menu items except AddKey this->p_action_add_key->setEnabled(this->is_writable); this->p_action_edit_key->setEnabled(false); this->p_action_delete_key->setEnabled(false); this->p_menu_copy->setEnabled(false); } // Emit clicked signal (makes sure item under cursor is selected if it wasn't) emit(this->clicked(this->indexAt(p_event->pos()))); // Create context menu, add actions and show it QMenu context_menu(this); context_menu.addAction(this->p_action_add_key); context_menu.addAction(this->p_action_edit_key); context_menu.addAction(this->p_action_delete_key); context_menu.addSeparator(); context_menu.addMenu(this->p_menu_copy); context_menu.exec(p_event->globalPos()); } void RegistryKeyTable::currentChanged(const QModelIndex ¤t, const QModelIndex &previous) { // Call parent class's currentChanged first QTableView::currentChanged(current,previous); // Now emit our signal QModelIndex current_item=QModelIndex(current); emit(RegistryKeyTable::CurrentItemChanged(current_item)); } /******************************************************************************* * Private slots ******************************************************************************/ void RegistryKeyTable::SlotAddKey() { emit(this->SignalAddKey()); } void RegistryKeyTable::SlotEditKey() { emit(this->SignalEditKey(this->selectedIndexes().at(0))); } void RegistryKeyTable::SlotDeleteKey() { emit(this->SignalDeleteKey(this->selectedIndexes().at(0))); } void RegistryKeyTable::SlotCopyKeyName() { QApplication::clipboard()-> setText(this->selectedIndexes().at(0).data().toString(), QClipboard::Clipboard); } void RegistryKeyTable::SlotCopyKeyValue() { QApplication::clipboard()-> setText(this->selectedIndexes().at(2).data().toString(), QClipboard::Clipboard); } diff --git a/trunk/registrynodetreemodel.cpp b/trunk/registrynodetreemodel.cpp index f474f44..2797e05 100644 --- a/trunk/registrynodetreemodel.cpp +++ b/trunk/registrynodetreemodel.cpp @@ -1,327 +1,327 @@ /******************************************************************************* * fred Copyright (c) 2011-2013 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * 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 3 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. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ -#include "registrynodetreemodel.h" - #include #include #include #include #include +#include "registrynodetreemodel.h" + /******************************************************************************* * Public ******************************************************************************/ RegistryNodeTreeModel::RegistryNodeTreeModel(RegistryHive *p_hive, QObject *p_parent) : QAbstractItemModel(p_parent) { // Create root node. It's values will be used as header values. this->p_root_node=new RegistryNode(QList()<SetupModelData(p_hive,this->p_root_node); } RegistryNodeTreeModel::~RegistryNodeTreeModel() { delete this->p_root_node; } QVariant RegistryNodeTreeModel::data(const QModelIndex &index, int role) const { if(!index.isValid()) return QVariant(); if(role!=Qt::DisplayRole) return QVariant(); RegistryNode *p_node=static_cast(index.internalPointer()); switch(role) { case Qt::DisplayRole: { switch(index.column()) { case RegistryNodeTreeModel::ColumnContent_NodeName: { return p_node->Data(index.column()); break; } case RegistryNodeTreeModel::ColumnContent_NodeModTime: { QDateTime date_time; bool ok=false; date_time.setTimeSpec(Qt::UTC); date_time.setTime_t(RegistryHive::FiletimeToUnixtime( p_node->Data(index.column()).toLongLong(&ok))); if(ok) return date_time.toString("yyyy/MM/dd hh:mm:ss"); else return tr("Unknown"); break; } default: { return QVariant(); } } break; } default: { return QVariant(); } } // Control will never reach this, but in order to stop g++ complaining... return QVariant(); } Qt::ItemFlags RegistryNodeTreeModel::flags(const QModelIndex &index) const { if(!index.isValid()) return 0; return Qt::ItemIsEnabled | Qt::ItemIsSelectable; } QVariant RegistryNodeTreeModel::headerData(int section, Qt::Orientation orientation, int role) const { // Only horizontal header is supported if(orientation!=Qt::Horizontal) return QVariant(); switch(role) { case Qt::TextAlignmentRole: // Handle text alignment return Qt::AlignCenter; break; case Qt::DisplayRole: // Header text return this->p_root_node->Data(section); break; default: return QVariant(); } } QModelIndex RegistryNodeTreeModel::index(int row, int column, const QModelIndex &parent) const { if(!this->hasIndex(row,column,parent)) return QModelIndex(); RegistryNode *p_parent_node; if(!parent.isValid()) { p_parent_node=this->p_root_node; } else { p_parent_node=static_cast(parent.internalPointer()); } RegistryNode *p_child_node=p_parent_node->Child(row); if(p_child_node) { return this->createIndex(row,column,p_child_node); } else { return QModelIndex(); } } QModelIndex RegistryNodeTreeModel::parent(const QModelIndex &index) const { if(!index.isValid()) return QModelIndex(); RegistryNode *p_child_node= static_cast(index.internalPointer()); RegistryNode *p_parent_node=p_child_node->Parent(); if(p_parent_node==this->p_root_node) { return QModelIndex(); } else { return this->createIndex(p_parent_node->Row(),0,p_parent_node); } } int RegistryNodeTreeModel::rowCount(const QModelIndex &parent) const { if(parent.column()>0) return 0; RegistryNode *p_parent_node; if(!parent.isValid()) { p_parent_node=this->p_root_node; } else { p_parent_node=static_cast(parent.internalPointer()); } return p_parent_node->ChildCount(); } int RegistryNodeTreeModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return 2; } QList RegistryNodeTreeModel::GetIndexListOf(QString path) { RegistryNode *p_parent_node=this->p_root_node; QList ret; QStringList nodes=path.split("\\",QString::SkipEmptyParts); bool found=false; // Create a list of all index's that form the supplied path ret.clear(); for(int i=0;iChildCount();ii++) { if(p_parent_node->Child(ii)->Data(0)==nodes.at(i)) { ret.append(this->createIndex(ii,0,p_parent_node->Child(ii))); p_parent_node=p_parent_node->Child(ii); found=true; break; } } // Break when last child node was found if(found && i==nodes.count()-1) break; // Return an empty list when a child node wasn't found else if(!found) return QList(); } return ret; } QString RegistryNodeTreeModel::GetNodePath(QModelIndex child_index) { QString path; // Make the specified index point to the ColumnContent_NodeName column! child_index=this->GetNodeNameIndex(child_index); // Get current node name path=this->data(child_index,Qt::DisplayRole).toString().prepend("\\"); // Build node path by prepending all parent nodes names while(this->parent(child_index)!=QModelIndex()) { child_index=this->parent(child_index); path.prepend(this->data(child_index, Qt::DisplayRole).toString().prepend("\\")); } return path; } QModelIndex RegistryNodeTreeModel::AddNode(RegistryHive *p_hive, QModelIndex parent_index, int new_node_id, QString new_node_name) { RegistryNode *p_parent_node; int64_t key_mod_time; RegistryNode *p_node; // Make the specified index point to the ColumnContent_NodeName column! parent_index=this->GetNodeNameIndex(parent_index); // Get pointer to parent node p_parent_node=static_cast(parent_index.internalPointer()); // Tell users of this view that we are going to insert a row emit(RegistryNodeTreeModel::beginInsertRows(parent_index, p_parent_node->ChildCount(), p_parent_node->ChildCount())); // Create and add new node in internal node list key_mod_time=p_hive->GetNodeModTime(new_node_id); p_node=new RegistryNode(QList()<AppendChild(p_node); // Tell users of this view we have finished inserting a row emit(RegistryNodeTreeModel::endInsertRows()); // Return index to new node return this->createIndex(p_parent_node->ChildCount()-1,0,p_node); } QModelIndex RegistryNodeTreeModel::RemoveNode(QModelIndex index) { RegistryNode *p_node; RegistryNode *p_parent_node; int node_row; QModelIndex parent_node_index; // Make the specified index point to the ColumnContent_NodeName column! index=this->GetNodeNameIndex(index); // Get pointers to current node and its parent p_node=static_cast(index.internalPointer()); p_parent_node=p_node->Parent(); // Get current nodes row node_row=p_node->Row(); // Create index of parent node parent_node_index=this->createIndex(p_parent_node->Row(),0,p_parent_node); // Tell users of this view that we are going to remove a row emit(RegistryNodeTreeModel::beginRemoveRows(parent_node_index, node_row, node_row)); // Remove node p_parent_node->RemoveChild(node_row); // Tell users of this view we have finished removing a row emit(RegistryNodeTreeModel::endRemoveRows()); // Find a suitable index that should be selected after the current one has // been deleted. if(p_parent_node->ChildCount()>0) { // Parent node still has child nodes, return nearest child node if(node_rowChildCount()) { // Any child node removed except the last one, row is still valid return this->createIndex(node_row,0,p_parent_node->Child(node_row)); } else { // Last child node removed, row-1 should be valid return this->createIndex(node_row-1,0,p_parent_node->Child(node_row-1)); } } // If no child nodes are left, return parent node except if it is our root // node! if(p_parent_node->Parent()!=NULL) return parent_node_index; else return QModelIndex(); } /******************************************************************************* * Private ******************************************************************************/ void RegistryNodeTreeModel::SetupModelData(RegistryHive *p_hive, RegistryNode *p_parent, int hive_node) { QMap hive_children; RegistryNode *p_node; int64_t key_mod_time; // Get all sub nodes of current hive node if(hive_node) hive_children=p_hive->GetNodes(hive_node); else hive_children=p_hive->GetNodes("\\"); if(hive_children.isEmpty()) return; // Recursivly iterate over all sub nodes QMapIterator i(hive_children); while(i.hasNext()) { i.next(); key_mod_time=p_hive->GetNodeModTime(i.value()); // TODO: Maybe we have to call GetErrorMsg in case an error occured p_node=new RegistryNode(QList()<AppendChild(p_node); this->SetupModelData(p_hive,p_node,i.value()); } } QModelIndex RegistryNodeTreeModel::GetNodeNameIndex(QModelIndex index) { return this->index(index.row(), RegistryNodeTreeModel::ColumnContent_NodeName, index.parent()); } diff --git a/trunk/reportengine.cpp b/trunk/reportengine.cpp index 659afec..eb0fd08 100644 --- a/trunk/reportengine.cpp +++ b/trunk/reportengine.cpp @@ -1,559 +1,559 @@ /******************************************************************************* * fred Copyright (c) 2011-2013 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * 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 3 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. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ -#include "reportengine.h" - #include #include #include #include #include +#include "reportengine.h" + /******************************************************************************* * Public ******************************************************************************/ ReportEngine::ReportEngine(RegistryHive *p_hive) : QScriptEngine() { // Init vars this->p_registry_hive=p_hive; this->report_content=""; // Add our constants this->globalObject().setProperty("ENGINE_API_VERSION", FRED_REPORTENGINE_API_VERSION, QScriptValue::ReadOnly| QScriptValue::Undeletable); /* this->globalObject().setProperty("HIVE_FILE", this->p_registry_hive->Filename(), QScriptValue::ReadOnly| QScriptValue::Undeletable); */ // Add our types to engine qScriptRegisterMetaType(this, this->RegistryKeyValueToScript, this->RegistryKeyValueFromScript); this->p_type_byte_array=new ByteArray(this); this->globalObject().setProperty("ByteArray", this->p_type_byte_array->constructor()); // TODO: Is it really necessary to explicitly export these functions // here ?????????? // Add our functions // print QScriptValue func_print=this->newFunction(this->Print); this->globalObject().setProperty("print",func_print); // println QScriptValue func_println=this->newFunction(this->PrintLn); this->globalObject().setProperty("println",func_println); // RegistryKeyValueToString QScriptValue func_value_to_string= this->newFunction(this->RegistryKeyValueToString,2); this->globalObject().setProperty("RegistryKeyValueToString", func_value_to_string); // RegistryKeyValueToVariant QScriptValue func_value_to_variant= this->newFunction(this->RegistryKeyValueToVariant); this->globalObject().setProperty("RegistryKeyValueToVariant", func_value_to_variant); // RegistryKeyValueToStringList QScriptValue func_value_to_string_list= this->newFunction(this->RegistryKeyValueToStringList); this->globalObject().setProperty("RegistryKeyValueToStringList", func_value_to_string_list); // RegistryKeyTypeToString QScriptValue func_type_to_string= this->newFunction(this->RegistryKeyTypeToString,1); this->globalObject().setProperty("RegistryKeyTypeToString", func_type_to_string); } ReportEngine::~ReportEngine() { delete this->p_type_byte_array; } /* * GetReportTemplateInfo */ QMap ReportEngine::GetReportTemplateInfo(QString file) { // Read template file QString report_code; if(!this->GetReportTemplateFileContents(file,report_code)) { QMap error_msg; error_msg["error"]=report_code; return error_msg; } // Evaluate report template script QScriptValue report_result=this->evaluate(report_code,file); if (report_result.isError() || this->hasUncaughtException()) { QMap error_msg; error_msg["error"]=QString("File: %1\n Line: %2\nError: %3") .arg(file) .arg(report_result.property("lineNumber").toInt32()) .arg(report_result.toString()); return error_msg; } // Try to call the fred_report_info script function and return result QScriptValue fred_report_info_func= this->globalObject().property("fred_report_info"); if(!fred_report_info_func.isFunction()) { QMap error_msg; error_msg["error"]= QString("Report template '%1' does not have a fred_report_info function!") .arg(file) .arg(report_result.property("lineNumber").toInt32()) .arg(report_result.toString()); return error_msg; } QScriptValue fred_report_info_res=fred_report_info_func.call(); // TODO: Maybe do more checking on return value return fred_report_info_res.toVariant().toMap(); } /* * GenerateReport */ bool ReportEngine::GenerateReport(RegistryHive *p_hive, QString report_file, QString &report_result, bool console_mode) { // Clear internal buffer this->report_content.clear(); // Update exported functions this->UpdateExportedFunctions(p_hive); // Read template file QString report_code; if(!this->GetReportTemplateFileContents(report_file,report_code)) { report_result=report_code; return false; } // Evaluate report template script QScriptValue script_result=this->evaluate(report_code,report_file); if (script_result.isError() || this->hasUncaughtException()) { script_result=QString("File: %1\n Line: %2\nError: %3") .arg(report_file) .arg(script_result.property("lineNumber").toInt32()) .arg(script_result.toString()); return false; } // Try to call the fred_report_html script function and return result QScriptValue fred_report_html_func= this->globalObject().property("fred_report_html"); if(!fred_report_html_func.isFunction()) { report_result= QString("Report template '%1' does not have a fred_report_info function!") .arg(report_file) .arg(script_result.property("lineNumber").toInt32()) .arg(script_result.toString()); return false; } QScriptValue fred_report_html_res=fred_report_html_func.call(); // TODO: Maybe do more checking on return value report_result=this->report_content; return true; } /******************************************************************************* * Public Slots ******************************************************************************/ /******************************************************************************* * Private ******************************************************************************/ /* * Print */ QScriptValue ReportEngine::Print(QScriptContext *context, QScriptEngine *engine) { int i; QString content; // Append all arguments to content for(i=0;iargumentCount();++i) { //if(i>0) content.append(" "); content.append(context->argument(i).toString()); } qobject_cast(engine)->report_content.append(content); return engine->undefinedValue(); } /* * PrintLn */ QScriptValue ReportEngine::PrintLn(QScriptContext *context, QScriptEngine *engine) { int i; QString content; // Append all arguments to content for(i=0;iargumentCount();++i) { //if(i>0) content.append(" "); content.append(context->argument(i).toString()); } qobject_cast(engine)-> report_content.append(content).append("\n"); return engine->undefinedValue(); } /* * GetRegistryNodes */ QScriptValue ReportEngine::GetRegistryNodes(QScriptContext *context, QScriptEngine *engine) { QScriptValue calleeData; RegistryHive *p_hive; QMap nodes; QScriptValue ret_nodes; int ii=0; // This function needs one argument, parent node path if(context->argumentCount()!=1) return engine->undefinedValue(); // Get calle data (Pointer to RegistryHive class) calleeData=context->callee().data(); p_hive=qobject_cast(calleeData.toQObject()); // Get nodes nodes=p_hive->GetNodes(context->argument(0).toString()); if(p_hive->Error()) { // Clear error state p_hive->GetErrorMsg(); return engine->undefinedValue(); } // Build script array ret_nodes=engine->newArray(nodes.count()); QMapIterator i(nodes); while(i.hasNext()) { i.next(); ret_nodes.setProperty(ii++,QScriptValue(i.key())); } return ret_nodes; } /* * GetRegistryKeys */ QScriptValue ReportEngine::GetRegistryKeys(QScriptContext *context, QScriptEngine *engine) { QScriptValue calleeData; RegistryHive *p_hive; QMap keys; QScriptValue ret_keys; int ii=0; // This function needs one argument, parent node path if(context->argumentCount()!=1) return engine->undefinedValue(); // Get calle data (Pointer to RegistryHive class) calleeData=context->callee().data(); p_hive=qobject_cast(calleeData.toQObject()); // Get keys keys=p_hive->GetKeys(context->argument(0).toString()); if(p_hive->Error()) { // Clear error state p_hive->GetErrorMsg(); return engine->undefinedValue(); } // Build script array ret_keys=engine->newArray(keys.count()); QMapIterator i(keys); while(i.hasNext()) { i.next(); ret_keys.setProperty(ii++,QScriptValue(i.key())); } return ret_keys; } /* * RegistryKeyValueToScript */ QScriptValue ReportEngine::RegistryKeyValueToScript(QScriptEngine *engine, const s_RegistryKeyValue &s) { QScriptValue obj=engine->newObject(); obj.setProperty("type",s.type); obj.setProperty("length",s.length); ByteArray *p_byte_array=new ByteArray(engine); obj.setProperty("value",p_byte_array->newInstance(s.value)); return obj; } /* * RegistryKeyValueFromScriptValue */ void ReportEngine::RegistryKeyValueFromScript(const QScriptValue &obj, s_RegistryKeyValue &s) { s.type=obj.property("type").toInt32(); s.length=obj.property("length").toInt32(); s.value=qvariant_cast(obj.property("value").data().toVariant()); } /* * GetRegistryKeyValue */ QScriptValue ReportEngine::GetRegistryKeyValue(QScriptContext *context, QScriptEngine *engine) { QScriptValue calleeData; RegistryHive *p_hive; QByteArray key_value; int key_type=0; size_t key_length=0; s_RegistryKeyValue script_key_value; // This function needs two arguments, key path and key name if(context->argumentCount()!=2) return engine->undefinedValue(); // Get calle data (Pointer to RegistryHive class) calleeData=context->callee().data(); p_hive=qobject_cast(calleeData.toQObject()); // Get key value key_value=p_hive->GetKeyValue(context->argument(0).toString(), context->argument(1).toString(), &key_type, &key_length); if(p_hive->Error()) { // Get error message to clear error state p_hive->GetErrorMsg(); // printf("\nError: %s\n",p_hive->GetErrorMsg().toAscii().constData()); return engine->undefinedValue(); } // Save key value to s_RegistryKeyValue struct script_key_value.type=key_type; script_key_value.length=key_length; script_key_value.value=key_value; return ReportEngine::RegistryKeyValueToScript(engine,script_key_value); } /* * RegistryKeyValueToString */ QScriptValue ReportEngine::RegistryKeyValueToString(QScriptContext *context, QScriptEngine *engine) { QByteArray key_value; QString ret=""; // This function needs two arguments, key value and value type if(context->argumentCount()!=2) return engine->undefinedValue(); // Cast ByteArray argument to QByteArray and convert key_value=qvariant_cast(context->argument(0).data().toVariant()); ret=RegistryHive::KeyValueToString(key_value, context->argument(1).toInt32()); return engine->newVariant(ret); } /* * RegistryKeyValueToVariant */ QScriptValue ReportEngine::RegistryKeyValueToVariant(QScriptContext *context, QScriptEngine *engine) { int offset=0; int length=-1; bool little_endian=true; QByteArray key_value; QString format=""; QString ret=""; // This function needs at least two arguments, key value and variant type, // and may have three optional arguments, offset, length and little_endian if(context->argumentCount()<2 || context->argumentCount()>5) { return engine->undefinedValue(); } if(context->argumentCount()==3) { offset=context->argument(2).toInt32(); } if(context->argumentCount()==4) { offset=context->argument(2).toInt32(); length=context->argument(3).toInt32(); } if(context->argumentCount()==5) { offset=context->argument(2).toInt32(); length=context->argument(3).toInt32(); little_endian=(context->argument(4).toInt32()==1); } // Cast ByteArray argument to QByteArray key_value=qvariant_cast(context->argument(0).data().toVariant()); format=context->argument(1).toString(); ret=RegistryHive::KeyValueToString(key_value,format,offset,length,little_endian); return engine->newVariant(ret); } /* * RegistryKeyValueToStringList */ QScriptValue ReportEngine::RegistryKeyValueToStringList(QScriptContext *context, QScriptEngine *engine) { QByteArray value; QStringList strings; QScriptValue ret; int i=0; bool little_endian=true; // This function needs one arguments, key value, and may have a second // specifying endianness if(context->argumentCount()==0 || context->argumentCount()>2) return engine->undefinedValue(); if(context->argumentCount()==2) { little_endian=context->argument(2).toBool(); } // Cast ByteArray argument to QByteArray and convert value=qvariant_cast(context->argument(0).data().toVariant()); strings=RegistryHive::KeyValueToStringList(value,little_endian); // Build script array ret=engine->newArray(strings.count()); QListIterator str_it(strings); while(str_it.hasNext()) { ret.setProperty(i++,QScriptValue(str_it.next())); } return ret; } /* * RegistryKeyTypeToString */ QScriptValue ReportEngine::RegistryKeyTypeToString(QScriptContext *context, QScriptEngine *engine) { QString ret=""; // This function needs one argument, key type if(context->argumentCount()!=1) return engine->undefinedValue(); ret=RegistryHive::KeyValueTypeToString(context->argument(0).toInt32()); return engine->newVariant(ret); } /* * GetRegistryNodeModTime */ QScriptValue ReportEngine::GetRegistryNodeModTime(QScriptContext *context, QScriptEngine *engine) { QScriptValue calleeData; RegistryHive *p_hive; int64_t mod_time=0; // This function needs one argument, node path if(context->argumentCount()!=1) return engine->undefinedValue(); // Get calle data (Pointer to RegistryHive class) calleeData=context->callee().data(); p_hive=qobject_cast(calleeData.toQObject()); mod_time=p_hive->GetNodeModTime(context->argument(0).toString()); if(p_hive->Error()) { // Get error message to clear error state p_hive->GetErrorMsg(); return engine->undefinedValue(); } QDateTime date_time; date_time.setTimeSpec(Qt::UTC); date_time.setTime_t(RegistryHive::FiletimeToUnixtime(mod_time)); return engine->newVariant(date_time.toString("yyyy/MM/dd hh:mm:ss")); } /* * GetReportTemplateFileContents */ bool ReportEngine::GetReportTemplateFileContents(QString file, QString &contents) { // Open report template file QFile template_file(file); if(!template_file.open(QIODevice::ReadOnly | QIODevice::Text)) { contents=QString("Couldn't open report template file '%1'!").arg(file); return false; } // Read template file and close it contents.clear(); QTextStream in(&template_file); while(!in.atEnd()) contents.append(in.readLine()).append("\n"); template_file.close(); return true; } /* * UpdateExportedFunctions */ void ReportEngine::UpdateExportedFunctions(RegistryHive *p_hive) { this->p_registry_hive=p_hive; // GetRegistryNodes QScriptValue func_get_nodes=this->newFunction(this->GetRegistryNodes,1); func_get_nodes.setData(this->newQObject(this->p_registry_hive)); this->globalObject().setProperty("GetRegistryNodes",func_get_nodes); // GetRegistryKeys QScriptValue func_get_keys=this->newFunction(this->GetRegistryKeys,1); func_get_keys.setData(this->newQObject(this->p_registry_hive)); this->globalObject().setProperty("GetRegistryKeys",func_get_keys); // GetRegistryKeyValue QScriptValue func_get_key_value=this->newFunction(this->GetRegistryKeyValue, 2); func_get_key_value.setData(this->newQObject(this->p_registry_hive)); this->globalObject().setProperty("GetRegistryKeyValue",func_get_key_value); // GetRegistryNodeModTime QScriptValue func_get_node_modt= this->newFunction(this->GetRegistryNodeModTime,1); func_get_node_modt.setData(this->newQObject(this->p_registry_hive)); this->globalObject().setProperty("GetRegistryNodeModTime",func_get_node_modt); } diff --git a/trunk/reports.cpp b/trunk/reports.cpp index 62fb8b8..8920d99 100644 --- a/trunk/reports.cpp +++ b/trunk/reports.cpp @@ -1,203 +1,205 @@ /******************************************************************************* * fred Copyright (c) 2011-2013 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * 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 3 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. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ -#include "reports.h" - #include #include #include #include #include +#include "reports.h" + /******************************************************************************* * Public ******************************************************************************/ Reports::Reports(Settings *p_sets) { this->p_settings=p_sets; this->p_engine=new ReportEngine(NULL); this->report_templates.clear(); if(this->p_settings!=NULL) this->LoadReportTemplates(); } Reports::~Reports() { qDeleteAll(this->report_templates); delete this->p_engine; } void Reports::LoadReportTemplates() { // Delete any previously loaded reports qDeleteAll(this->report_templates); this->report_templates.clear(); // Return if we have no settings loaded if(this->p_settings==NULL) return; // Load all available reports QStringList report_dirs=this->p_settings->GetReportTemplateDirs(); QListIterator report_dir_it(report_dirs); while(report_dir_it.hasNext()) { this->LoadReportTemplatesFromDir(report_dir_it.next()); } } QStringList Reports::GetAvailableReportCategories() { QStringList ret; QString cat; int i; ret.clear(); for(i=0;ireport_templates.count();i++) { cat=this->report_templates.value(i)->Category(); if(!ret.contains(cat)) ret.append(cat); } ret.sort(); return ret; } QList Reports::GetAvailableReports(QString category) { QList ret; QString cat; int i=0; ret.clear(); for(i=0;ireport_templates.count();i++) { cat=this->report_templates.value(i)->Category(); if(cat==category) ret.append(this->report_templates.value(i)); } return ret; } bool Reports::GenerateReport(RegistryHive *p_hive, QString report_file, QString &report_result, bool console_mode) { return this->p_engine->GenerateReport(p_hive, report_file, report_result, console_mode); } bool Reports::GenerateReport(RegistryHive *p_hive, QList report_list, QString &report_result, bool console_mode) { bool ret; QString res; QListIterator rep_it(report_list); while(rep_it.hasNext()) { res=""; ret=this->GenerateReport(p_hive, rep_it.next()->File(), res, console_mode); if(ret) report_result.append(res); // TODO: Inform user something didn't work } return true; } /******************************************************************************* * Private ******************************************************************************/ void Reports::LoadReportTemplatesFromDir(QString dir) { QString report_template=""; QString report_category,report_name,report_author,report_desc,report_hive; bool found; int i; ReportTemplate *p_report; // Get all template files in report_templates directory QDir report_dir(dir); QStringList found_report_templates=report_dir. entryList(QStringList()<<"*.qs"); QListIterator it(found_report_templates); while(it.hasNext()) { // Build path to template file report_template=report_dir.path(); report_template.append(QDir::separator()); report_template.append(it.next()); // Get report info QMap report_info=this->p_engine-> GetReportTemplateInfo(report_template); if(report_info.contains("error")) { // TODO: Inform user qDebug()<<"Error in report '"< FRED_REPORTENGINE_API_VERSION) { // TODO: Inform user - qDebug()<<"Report '"<report_templates.count();i++) { if(this->report_templates.at(i)->Category()==report_category && this->report_templates.at(i)->Name()==report_name) { found=true; break; } } // Add to or update report template list if(!found) { // Add report to list p_report=new ReportTemplate(report_template, report_category, report_name, report_author, report_desc, report_hive); this->report_templates.append(p_report); } else { // Update report entry p_report=this->report_templates.at(i); p_report->SetFile(report_template); p_report->SetAuthor(report_author); p_report->SetDescription(report_desc); } } } diff --git a/trunk/reports.h b/trunk/reports.h index b3d5fe2..6ef00da 100644 --- a/trunk/reports.h +++ b/trunk/reports.h @@ -1,57 +1,57 @@ /******************************************************************************* * fred Copyright (c) 2011-2013 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * 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 3 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. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #ifndef REPORTS_H #define REPORTS_H -#include "reporttemplate.h" -#include "reportengine.h" -#include "settings.h" - #include #include #include +#include "reporttemplate.h" +#include "reportengine.h" +#include "settings.h" + class Reports { public: Reports(Settings *p_sets=NULL); ~Reports(); void LoadReportTemplates(); QStringList GetAvailableReportCategories(); QList GetAvailableReports(QString category); bool GenerateReport(RegistryHive *p_hive, QString report_file, QString &report_result, bool console_mode=false); bool GenerateReport(RegistryHive *p_hive, QList report_list, QString &report_result, bool console_mode=false); private: Settings *p_settings; QList report_templates; ReportEngine *p_engine; void LoadReportTemplatesFromDir(QString dir); }; #endif // REPORTS_H diff --git a/trunk/searchresultwidget.cpp b/trunk/searchresultwidget.cpp index 0607165..8fea4cb 100644 --- a/trunk/searchresultwidget.cpp +++ b/trunk/searchresultwidget.cpp @@ -1,124 +1,124 @@ /******************************************************************************* * fred Copyright (c) 2011-2013 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * 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 3 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. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ -#include "searchresultwidget.h" - #include #include #include #include #include //#include +#include "searchresultwidget.h" + SearchResultWidget::SearchResultWidget(QWidget *p_parent) : QTableWidget(p_parent) { // Create our delegate instance this->p_delegate=new SearchResultTableDelegate(); this->setItemDelegate(this->p_delegate); this->setColumnCount(3); this->setRowCount(0); this->setTextElideMode(Qt::ElideNone); this->verticalHeader()->setHidden(true); this->setSelectionBehavior(QAbstractItemView::SelectRows); this->setSelectionMode(QAbstractItemView::SingleSelection); this->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); this->setHorizontalHeaderLabels(QStringList()<p_delegate; } void SearchResultWidget::SlotFoundMatch(ThreadSearch::eMatchType match_type, QString path, QString key, QString value) { QTableWidgetItem *p_item; // QTextEdit* p_te; QString full_path; QString type; QString match; switch(match_type) { case ThreadSearch::eMatchType_NodeName: type=tr("Node name"); full_path=path; match=key; break; case ThreadSearch::eMatchType_KeyName: type=tr("Key name"); full_path=path; match=key; break; case ThreadSearch::eMatchType_KeyValue: type=tr("Key value"); full_path=path+"\\"+key; //if(value.length()<6934) match=value; //else //match=value.left(5610); //match=QString(value); match=value; break; } int rows=this->rowCount(); this->setRowCount(rows+1); // TODO: Use setCellWidget to add QTextEdit and then use insertText and // insertHtml to format match p_item=new QTableWidgetItem(full_path=="" ? "\\" : full_path); p_item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); this->setItem(rows,0,p_item); p_item=new QTableWidgetItem(type); p_item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); this->setItem(rows,1,p_item); p_item=new QTableWidgetItem(match); p_item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); this->setItem(rows,2,p_item); // p_te=new QTextEdit(match); // p_te->setReadOnly(true); // this->setCellWidget(rows,2,p_te); } int SearchResultWidget::sizeHintForColumn(int column) const { int size_hint=0; int i=0; int item_width=0; QFontMetrics fm(this->fontMetrics()); // if(column<0 || column>=this->columnCount()) return -1; // Find string that needs the most amount of space for(i=0;irowCount();i++) { item_width=fm.width(this->item(i,column)->text())+10; if(item_width>size_hint) size_hint=item_width; } return size_hint; } void SearchResultWidget::SlotSearchFinished() { this->resizeColumnsToContents(); this->resizeRowsToContents(); } diff --git a/trunk/settings.cpp b/trunk/settings.cpp index e45a7dc..a7341cc 100644 --- a/trunk/settings.cpp +++ b/trunk/settings.cpp @@ -1,206 +1,206 @@ /******************************************************************************* * fred Copyright (c) 2011-2013 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * 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 3 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. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ -#include "settings.h" - #include +#include "settings.h" + #ifndef FRED_REPORT_TEMPLATE_DIR #ifndef __MINGW32__ #define SYSTEM_REPORT_TEMPLATE_DIR "/usr/share/fred/report_templates" #else #define SYSTEM_REPORT_TEMPLATE_DIR ".\\report_templates\\" #endif #endif #define APP_ORGANIZATION "pinguin.lu" #define APP_NAME "fred" // Default settings #define DEFAULT_REPORT_TEMPLATE_DIRS QStringList()<user_report_template_dir #define DEFAULT_WINDOW_GEOMETRY_STATUS true #define DEFAULT_RECENT_FILES_DEPTH 5 #define DEFAULT_LAST_OPEN_LOCATION QDir::homePath() #define DEFAULT_OPEN_HIVES_READ_ONLY true /******************************************************************************* * Public ******************************************************************************/ Settings::Settings(QObject *p_parent) : QObject(p_parent) { // Init vars this->p_settings=NULL; this->initialized=false; this->user_settings_dir=QDir::homePath() .append(QDir::separator()).append(".fred"); this->user_report_template_dir=QString(this->user_settings_dir) .append(QDir::separator()) .append("report_templates"); // Make sure config dirs exist if(!QDir(this->user_settings_dir).exists()) { // User config dir does not exists, try to create it if(!QDir().mkpath(this->user_settings_dir)) { // TODO: Maybe warn user return; } } if(!QDir(this->user_report_template_dir).exists()) { // Create config dir sub folder for report templates if(!QDir().mkpath(this->user_report_template_dir)) { // TODO: Maybe warn user return; } } // Create / open settings #ifndef __MINGW32__ // On any Unix-like OS, settings should be saved in the .fred folder this->p_settings=new QSettings(QString(this->user_settings_dir) .append(QDir::separator()) .append("fred.conf"), QSettings::NativeFormat, this); #else // On Windows, it can be stored inside registry this->p_settings=new QSettings(QSettings::NativeFormat, QSettings::UserScope, APP_ORGANIZATION, APP_NAME, this); #endif if(this->p_settings->status()!=QSettings::NoError || !this->p_settings->isWritable()) { return; } this->initialized=true; } void Settings::Reset() { if(!this->initialized) return; // Clear all current settings this->p_settings->clear(); } void Settings::SetReportTemplateDirs(QStringList &dirs) { if(!this->initialized) return; this->p_settings->setValue("ReportTemplateDirs",dirs); } QStringList Settings::GetReportTemplateDirs() { if(!this->initialized) return DEFAULT_REPORT_TEMPLATE_DIRS; return this->p_settings->value("ReportTemplateDirs", DEFAULT_REPORT_TEMPLATE_DIRS).toStringList(); } void Settings::SetWindowGeometryStatus(bool save) { if(!this->initialized) return; this->p_settings->setValue("WindowGeometries/EnableSaving",save); } bool Settings::GetWindowGeometryStatus() { if(!this->initialized) return DEFAULT_WINDOW_GEOMETRY_STATUS; return this->p_settings->value("WindowGeometries/EnableSaving", DEFAULT_WINDOW_GEOMETRY_STATUS).toBool(); } void Settings::SetWindowGeometry(QString window_name, QByteArray geometry) { if(!this->initialized || !this->GetWindowGeometryStatus()) return; this->p_settings->setValue(QString("WindowGeometries/%1").arg(window_name), geometry); } QByteArray Settings::GetWindowGeometry(QString window_name) { if(!this->initialized || !this->GetWindowGeometryStatus()) { return QByteArray(); } return this->p_settings->value(QString("WindowGeometries/%1") .arg(window_name)).toByteArray(); } void Settings::SetRecentFilesDepth(int depth) { if(!this->initialized) return; this->p_settings->setValue("RecentFilesDepth",depth); // Make sure there are currently not more recent files as allowed QStringList recent_files=this->GetRecentFiles(); while(recent_files.count()>depth) recent_files.removeLast(); this->SetRecentFiles(recent_files); } int Settings::GetRecentFilesDepth() { if(!this->initialized) return DEFAULT_RECENT_FILES_DEPTH; return this->p_settings->value("RecentFilesDepth", DEFAULT_RECENT_FILES_DEPTH).toInt(); } void Settings::SetRecentFiles(QStringList &recent_files) { if(!this->initialized) return; this->p_settings->setValue("RecentFiles",recent_files); } void Settings::AddRecentFile(QString file) { // Get recent files QStringList recent_files=this->GetRecentFiles(); if(recent_files.contains(file)) { // File already exists in recent list. Simply move it to top recent_files.move(recent_files.indexOf(file),0); } else { // We only save RecentFilesDepth() files at max while(recent_files.count()>=this->GetRecentFilesDepth()) recent_files.removeLast(); recent_files.prepend(file); } this->SetRecentFiles(recent_files); } QStringList Settings::GetRecentFiles() { if(!this->initialized) return QStringList(); return this->p_settings->value("RecentFiles",QStringList()).toStringList(); } void Settings::SetLastOpenLocation(QString dir) { if(!this->initialized) return; this->p_settings->setValue("LastOpenLocation",dir); } QString Settings::GetLastOpenLocation() { if(!this->initialized) return DEFAULT_LAST_OPEN_LOCATION; QString last_loc; last_loc=this->p_settings->value("RecentFiles", DEFAULT_LAST_OPEN_LOCATION).toString(); if(QDir(last_loc).exists()) return last_loc; else return DEFAULT_LAST_OPEN_LOCATION; } void Settings::SetOpenHivesReadOnly(bool read_only) { if(!this->initialized) return; this->p_settings->setValue("OpenFilesReadOnly",read_only); } bool Settings::GetOpenHivesReadOnly() { if(!this->initialized) return DEFAULT_OPEN_HIVES_READ_ONLY; return this->p_settings->value("OpenFilesReadOnly", DEFAULT_OPEN_HIVES_READ_ONLY).toBool(); } diff --git a/trunk/tabwidget.cpp b/trunk/tabwidget.cpp index f3cec34..467938e 100644 --- a/trunk/tabwidget.cpp +++ b/trunk/tabwidget.cpp @@ -1,65 +1,65 @@ /******************************************************************************* * fred Copyright (c) 2011-2013 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * 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 3 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. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ -#include "tabwidget.h" - #include #include #include #include #include +#include "tabwidget.h" + TabWidget::TabWidget(QWidget *p_parent) : QTabWidget(p_parent) {} int TabWidget::addTab(QWidget *p_widget, const QString &title, bool close_button) { // Add tab int tab_index=QTabWidget::addTab(p_widget,title); // If desired, add a close button to the tab if(close_button) { // Create close button QPushButton *p_close_button= new QPushButton(QIcon(":/icons/close_button"),QString()); p_close_button->setFlat(true); p_close_button->setIconSize(QSize(14,14)); p_close_button->setGeometry(p_close_button->x(),p_close_button->y(),14,14); // Connect clicked signal this->connect(p_close_button, SIGNAL(clicked()), this, SLOT(SlotCloseButtonClicked())); this->tabBar()->setTabButton(tab_index,QTabBar::RightSide,p_close_button); } return tab_index; } void TabWidget::SlotCloseButtonClicked() { // Find index of tab to close. The trolls do it by iterating over all tabs // and comparing their widget with QObject::sender(). QPushButton *p_close_button=(QPushButton*)(QObject::sender()); int index=this->tabBar()->tabAt(QPoint(p_close_button->x(), p_close_button->y())); // Emit tabCloseRequested emit(this->tabCloseRequested(index)); } diff --git a/trunk/threadsearch.cpp b/trunk/threadsearch.cpp index 5df3a97..267c614 100644 --- a/trunk/threadsearch.cpp +++ b/trunk/threadsearch.cpp @@ -1,195 +1,195 @@ /******************************************************************************* * fred Copyright (c) 2011-2013 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * 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 3 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. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ -#include "threadsearch.h" -#include "registryhive.h" - #include #include +#include "threadsearch.h" +#include "registryhive.h" + ThreadSearch::ThreadSearch(QObject *p_parent) : QThread(p_parent) { this->hive_file=""; this->h_hive=NULL; this->keywords=QList(); this->search_nodes=false; this->search_keys=false; this->search_values=false; this->root_node=0; // Register meta types to be used in signals qRegisterMetaType("ThreadSearch::eMatchType"); } bool ThreadSearch::Search(QString registry_hive, QList search_keywords, bool search_node_names, bool search_key_names, bool search_key_values, QString search_path) { this->hive_file=registry_hive; this->keywords=search_keywords; this->search_nodes=search_node_names; this->search_keys=search_key_names; this->search_values=search_key_values; this->root_path=search_path=="\\" ? "" : search_path; // Try to open hive this->h_hive=hivex_open(this->hive_file.toAscii().constData(),0); if(this->h_hive==NULL) return false; // Get root node this->root_node=hivex_root(this->h_hive); if(this->root_node==0) { hivex_close(this->h_hive); return false; } // If a root path was specified, iterate to it if(this->root_path!="") { QStringList path_nodes=search_path.split("\\",QString::SkipEmptyParts); int i; for(i=0;iroot_node=hivex_node_get_child(this->h_hive, this->root_node, path_nodes.at(i).toAscii().constData()); if(this->root_node==0) { hivex_close(this->h_hive); return false; } } } this->start(); return true; } void ThreadSearch::run() { this->Match(); hivex_close(this->h_hive); } void ThreadSearch::Match(QString path, hive_node_h node) { char *p_node_name; int i,ii; hive_node_h *p_node_childs; QByteArray *p_byte_array; if(node!=0) { p_node_name=hivex_node_name(this->h_hive,node); if(p_node_name==NULL) return; if(this->search_nodes) { // Compare node name to keywords p_byte_array=new QByteArray(p_node_name); for(i=0;ikeywords.count();i++) { if(p_byte_array->indexOf(this->keywords.at(i))!=-1) { emit(SignalFoundMatch(ThreadSearch::eMatchType_NodeName, path, QString(p_node_name), QString())); break; } } delete p_byte_array; } if(this->search_keys || this->search_values) { // Get key,value pairs for current node hive_value_h *p_keys=hivex_node_values(this->h_hive,node); if(p_keys==NULL) { delete p_node_name; return; } if(this->search_keys) { // Compare key names to keywords char *p_keyname; for(i=0;p_keys[i];i++) { p_keyname=hivex_value_key(this->h_hive,p_keys[i]); if(p_keyname==NULL) continue; p_byte_array=new QByteArray(p_keyname); for(ii=0;iikeywords.count();ii++) { if(p_byte_array->indexOf(this->keywords.at(ii))!=-1) { emit(SignalFoundMatch(ThreadSearch::eMatchType_KeyName, path+"\\"+p_node_name, strlen(p_keyname)==0 ? QString("(default)") : QString(p_keyname), QString())); break; } } delete p_byte_array; delete p_keyname; } } if(this->search_values) { // Compare key values to keywords char *p_value; hive_type val_type; size_t val_len; for(i=0;p_keys[i];i++) { p_value=hivex_value_value(this->h_hive,p_keys[i],&val_type,&val_len); if(p_value==NULL) continue; p_byte_array=new QByteArray(p_value,val_len); for(ii=0;iikeywords.count();ii++) { if(p_byte_array->indexOf(this->keywords.at(ii))!=-1) { char *p_keyname=hivex_value_key(this->h_hive,p_keys[i]); if(p_keyname==NULL) continue; emit(SignalFoundMatch(ThreadSearch::eMatchType_KeyValue, path+"\\"+p_node_name, strlen(p_keyname)==0 ? QString("(default)") : QString(p_keyname), RegistryHive::KeyValueToString(*p_byte_array,val_type))); delete p_keyname; break; } } delete p_byte_array; delete p_value; } } delete p_keys; } // Search in subnodes p_node_childs=hivex_node_children(this->h_hive,node); if(p_node_childs!=NULL) { i=0; while(p_node_childs[i]) { this->Match(path+"\\"+p_node_name,p_node_childs[i]); i++; } delete p_node_childs; } delete p_node_name; } else { p_node_childs=hivex_node_children(this->h_hive,this->root_node); if(p_node_childs!=NULL) { i=0; while(p_node_childs[i]) { this->Match(this->root_path,p_node_childs[i]); i++; } delete p_node_childs; } } }