Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F4823564
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Size
75 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/trunk/datainterpreter.cpp b/trunk/datainterpretertable.cpp
similarity index 89%
rename from trunk/datainterpreter.cpp
rename to trunk/datainterpretertable.cpp
index 7ea8375..3af93b9 100644
--- a/trunk/datainterpreter.cpp
+++ b/trunk/datainterpretertable.cpp
@@ -1,111 +1,111 @@
/*******************************************************************************
* fred Copyright (c) 2011-2012 by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* 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 <http://www.gnu.org/licenses/>. *
*******************************************************************************/
-#include "datainterpreter.h"
+#include "datainterpretertable.h"
#include <QHeaderView>
#include <QFontMetrics>
#include <QMenu>
#include <QApplication>
#include <QClipboard>
-DataInterpreter::DataInterpreter(QWidget *p_parent)
+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()));
}
-DataInterpreter::~DataInterpreter() {
+DataInterpreterTable::~DataInterpreterTable() {
// Free table widget items
this->ClearValues();
// Delete context menu actions
delete this->p_action_copy_value;
}
-void DataInterpreter::AddValue(QString name, QString 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 DataInterpreter::ClearValues() {
+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 DataInterpreter::sizeHintForColumn(int column) const {
+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;i<this->rowCount();i++) {
item_width=fm.width(this->item(i,column)->text())+10;
if(item_width>size_hint) size_hint=item_width;
}
return size_hint;
}
-void DataInterpreter::contextMenuEvent(QContextMenuEvent *p_event) {
+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 DataInterpreter::SlotCopyValue() {
+void DataInterpreterTable::SlotCopyValue() {
QApplication::clipboard()->
setText(this->selectedIndexes().at(1).data().toString(),
QClipboard::Clipboard);
}
diff --git a/trunk/datainterpreter.h b/trunk/datainterpretertable.h
similarity index 91%
copy from trunk/datainterpreter.h
copy to trunk/datainterpretertable.h
index d1ee0a3..891fccd 100644
--- a/trunk/datainterpreter.h
+++ b/trunk/datainterpretertable.h
@@ -1,68 +1,68 @@
/*******************************************************************************
* fred Copyright (c) 2011-2012 by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* 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 <http://www.gnu.org/licenses/>. *
*******************************************************************************/
-#ifndef DATAINTERPRETER_H
-#define DATAINTERPRETER_H
+#ifndef DATAINTERPRETERTABLE_H
+#define DATAINTERPRETERTABLE_H
#include <QWidget>
#include <QTableWidget>
#include <QContextMenuEvent>
#include <QAction>
-class DataInterpreter : public QTableWidget {
+class DataInterpreterTable : public QTableWidget {
Q_OBJECT
public:
- DataInterpreter(QWidget *p_parent=0);
- ~DataInterpreter();
+ DataInterpreterTable(QWidget *p_parent=0);
+ ~DataInterpreterTable();
/*
* AddValue
*
* Add a value pair (name,value) to data interprter.
*/
void AddValue(QString name, QString value);
/*
* ClearValues
*
* Remove all value pairs from table
*/
void ClearValues();
protected:
/*
* sizeHintForColumn
*
* Needed reimplementation in order to allow resizeColumnsToContent
* to resize hidden columns too.
*/
int sizeHintForColumn(int column) const;
void contextMenuEvent(QContextMenuEvent *p_event);
private:
QAction *p_action_copy_value;
private slots:
void SlotCopyValue();
};
-#endif // DATAINTERPRETER_H
+#endif // DATAINTERPRETERTABLE_H
diff --git a/trunk/datainterpreterwidget.cpp b/trunk/datainterpreterwidget.cpp
new file mode 100644
index 0000000..f71c7fa
--- /dev/null
+++ b/trunk/datainterpreterwidget.cpp
@@ -0,0 +1,202 @@
+/*******************************************************************************
+* fred Copyright (c) 2011 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* 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 <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include "datainterpreterwidget.h"
+#include "registryhive.h"
+
+DataInterpreterWidget::DataInterpreterWidget(QWidget *p_parent) :
+ QWidget(p_parent)
+{
+ // Init private vars
+ this->data=QByteArray();
+ this->endianness=DataInterpreterWidget::Endianness_LittleEndian;
+
+ // Set widget layout. Setting it's parent to "this" will also call
+ // this->SetLayout.
+ this->p_widget_layout=new QVBoxLayout(this);
+
+ // Create sub-widgets
+ this->p_data_interpreter_table=new DataInterpreterTable();
+ this->p_endianness_selector_layout=new QHBoxLayout();
+ this->p_endianness_selector_le=new QRadioButton(tr("Little endian"));
+ this->p_endianness_selector_be=new QRadioButton(tr("Big endian"));
+
+ // Add endianness selector buttons to their layout
+ this->p_endianness_selector_layout->addWidget(this->p_endianness_selector_le);
+ this->p_endianness_selector_layout->addWidget(this->p_endianness_selector_be);
+
+ // Add sub-widgets to our layout
+ this->p_widget_layout->addWidget(this->p_data_interpreter_table);
+ this->p_widget_layout->addLayout(this->p_endianness_selector_layout);
+
+ // Configure widget and sub-widgets
+ this->setContentsMargins(0,0,0,0);
+ this->p_widget_layout->setContentsMargins(0,0,0,0);
+ this->p_endianness_selector_layout->setContentsMargins(0,0,0,0);
+ this->p_endianness_selector_le->setContentsMargins(0,0,0,0);
+ this->p_endianness_selector_be->setContentsMargins(0,0,0,0);
+ this->setEnabled(false);
+
+ // Set initial endianness selector state
+ this->p_endianness_selector_le->setChecked(
+ (this->endianness==DataInterpreterWidget::Endianness_LittleEndian));
+ this->p_endianness_selector_be->setChecked(
+ (this->endianness==DataInterpreterWidget::Endianness_BigEndian));
+
+ // Connect signals
+ this->connect(this->p_endianness_selector_le,
+ SIGNAL(clicked(bool)),
+ this,
+ SLOT(SlotEndiannessSelectorLeClicked(bool)));
+ this->connect(this->p_endianness_selector_be,
+ SIGNAL(clicked(bool)),
+ this,
+ SLOT(SlotEndiannessSelectorBeClicked(bool)));
+}
+
+DataInterpreterWidget::~DataInterpreterWidget() {
+ delete this->p_endianness_selector_le;
+ delete this->p_endianness_selector_be;
+ delete this->p_endianness_selector_layout;
+ delete this->p_data_interpreter_table;
+ delete this->p_widget_layout;
+}
+
+void DataInterpreterWidget::SetData(QByteArray new_data) {
+ // Save new data and interpret it
+ this->data=new_data;
+ this->InterpretData();
+}
+
+void DataInterpreterWidget::InterpretData() {
+ // Get data length
+ int data_length=this->data.size();
+
+ // Remove old values from data interpreter table
+ this->p_data_interpreter_table->ClearValues();
+
+ if(data_length>=1) {
+ this->p_data_interpreter_table->AddValue("int8:",
+ RegistryHive::KeyValueToString(
+ this->data,
+ "int8"));
+ this->p_data_interpreter_table->AddValue("uint8:",
+ RegistryHive::KeyValueToString(
+ this->data,
+ "uint8"));
+ }
+ if(data_length>=2) {
+ this->p_data_interpreter_table->AddValue(
+ "int16:",
+ RegistryHive::KeyValueToString(
+ this->data,
+ "int16",
+ 0,
+ 0,
+ this->endianness==DataInterpreterWidget::Endianness_LittleEndian));
+ this->p_data_interpreter_table->AddValue(
+ "uint16:",
+ RegistryHive::KeyValueToString(
+ this->data,
+ "uint16",
+ 0,
+ 0,
+ this->endianness==DataInterpreterWidget::Endianness_LittleEndian));
+ }
+ if(data_length>=4) {
+ this->p_data_interpreter_table->AddValue(
+ "int32:",
+ RegistryHive::KeyValueToString(
+ this->data,
+ "int32",
+ 0,
+ 0,
+ this->endianness==DataInterpreterWidget::Endianness_LittleEndian));
+ this->p_data_interpreter_table->AddValue(
+ "uint32:",
+ RegistryHive::KeyValueToString(
+ this->data,
+ "uint32",
+ 0,
+ 0,
+ this->endianness==DataInterpreterWidget::Endianness_LittleEndian));
+ this->p_data_interpreter_table->AddValue(
+ "unixtime:",
+ RegistryHive::KeyValueToString(
+ this->data,
+ "unixtime",
+ 0,
+ 0,
+ this->endianness==DataInterpreterWidget::Endianness_LittleEndian));
+ }
+ if(data_length>=8) {
+ this->p_data_interpreter_table->AddValue(
+ "int64:",
+ RegistryHive::KeyValueToString(
+ this->data,
+ "int64",
+ 0,
+ 0,
+ this->endianness==DataInterpreterWidget::Endianness_LittleEndian));
+ this->p_data_interpreter_table->AddValue(
+ "uint64:",
+ RegistryHive::KeyValueToString(
+ this->data,
+ "uint64",
+ 0,
+ 0,
+ this->endianness==DataInterpreterWidget::Endianness_LittleEndian));
+/*
+ TODO: Check how one could implement this
+ this->p_data_interpreter_table->AddValue(
+ "unixtime64:",
+ RegistryHive::KeyValueToString(
+ this->data,
+ "unixtime64",
+ 0,
+ 0,
+ this->endianness==DataInterpreterWidget::Endianness_LittleEndian));
+*/
+ this->p_data_interpreter_table->AddValue(
+ "filetime64:",
+ RegistryHive::KeyValueToString(
+ this->data,
+ "filetime",
+ 0,
+ 0,
+ this->endianness==DataInterpreterWidget::Endianness_LittleEndian));
+ }
+}
+
+void DataInterpreterWidget::SlotEndiannessSelectorLeClicked(bool checked) {
+ if(checked) {
+ // Save selected endianness and update interpreted values
+ this->endianness=DataInterpreterWidget::Endianness_LittleEndian;
+ this->InterpretData();
+ }
+}
+
+void DataInterpreterWidget::SlotEndiannessSelectorBeClicked(bool checked) {
+ if(checked) {
+ // Save selected endianness and update interpreted values
+ this->endianness=DataInterpreterWidget::Endianness_BigEndian;
+ this->InterpretData();
+ }
+}
diff --git a/trunk/datainterpreter.h b/trunk/datainterpreterwidget.h
similarity index 58%
rename from trunk/datainterpreter.h
rename to trunk/datainterpreterwidget.h
index d1ee0a3..2eeace2 100644
--- a/trunk/datainterpreter.h
+++ b/trunk/datainterpreterwidget.h
@@ -1,68 +1,72 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2012 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011 by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* 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 <http://www.gnu.org/licenses/>. *
*******************************************************************************/
-#ifndef DATAINTERPRETER_H
-#define DATAINTERPRETER_H
+#ifndef DATAINTERPRETERWIDGET_H
+#define DATAINTERPRETERWIDGET_H
#include <QWidget>
-#include <QTableWidget>
-#include <QContextMenuEvent>
-#include <QAction>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QRadioButton>
+#include <QString>
+#include <QByteArray>
-class DataInterpreter : public QTableWidget {
+#include "datainterpretertable.h"
+
+class DataInterpreterWidget : public QWidget {
Q_OBJECT
public:
- DataInterpreter(QWidget *p_parent=0);
- ~DataInterpreter();
+ enum Endianness {
+ Endianness_LittleEndian=0,
+ Endianness_BigEndian
+ };
- /*
- * AddValue
- *
- * Add a value pair (name,value) to data interprter.
- */
- void AddValue(QString name, QString value);
- /*
- * ClearValues
- *
- * Remove all value pairs from table
- */
- void ClearValues();
+ explicit DataInterpreterWidget(QWidget *p_parent=0);
+ ~DataInterpreterWidget();
- protected:
/*
- * sizeHintForColumn
+ * SetData
*
- * Needed reimplementation in order to allow resizeColumnsToContent
- * to resize hidden columns too.
+ * Set data to be interpreted (will also interpret it).
*/
- int sizeHintForColumn(int column) const;
- void contextMenuEvent(QContextMenuEvent *p_event);
+ void SetData(QByteArray new_data);
private:
- QAction *p_action_copy_value;
+ // Widget layout
+ QVBoxLayout *p_widget_layout;
+ // Sub-widgets
+ DataInterpreterTable *p_data_interpreter_table;
+ QHBoxLayout *p_endianness_selector_layout;
+ QRadioButton *p_endianness_selector_le;
+ QRadioButton *p_endianness_selector_be;
+ // Vars
+ QByteArray data;
+ int endianness;
- private slots:
- void SlotCopyValue();
+ void InterpretData();
+ private slots:
+ void SlotEndiannessSelectorLeClicked(bool checked);
+ void SlotEndiannessSelectorBeClicked(bool checked);
};
-#endif // DATAINTERPRETER_H
+#endif // DATAINTERPRETERWIDGET_H
diff --git a/trunk/fred.pro b/trunk/fred.pro
index d9791e7..d4db4c2 100644
--- a/trunk/fred.pro
+++ b/trunk/fred.pro
@@ -1,109 +1,111 @@
#*******************************************************************************
# fred Copyright (c) 2011-2012 by Gillen Daniel <gillen.dan@pinguin.lu> *
# *
# 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 <http://www.gnu.org/licenses/>. *
#******************************************************************************/
# Generate compileinfo.h
system(bash compileinfo.sh > compileinfo.h)
#compileinfo.target = compileinfo.h
#compileinfo.commands = $$PWD/compileinfo.sh > compileinfo.h
#QMAKE_EXTRA_TARGETS += compileinfo
#PRE_TARGETDEPS += compileinfo.h
# Build fred
QMAKE_CXXFLAGS += -Wall
QT += core \
gui \
script \
webkit
CONFIG += console
TARGET = fred
TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp \
registrynode.cpp \
registrynodetreemodel.cpp \
registrykey.cpp \
registrykeytablemodel.cpp \
dlgabout.cpp \
dlgkeydetails.cpp \
qhexedit/qhexedit_p.cpp \
qhexedit/qhexedit.cpp \
- datainterpreter.cpp \
reporttemplate.cpp \
datareporter.cpp \
datareporterengine.cpp \
registryhive.cpp \
qtscript_types/bytearray.cpp \
qtscript_types/bytearrayprototype.cpp \
qtscript_types/bytearrayiterator.cpp \
dlgreportviewer.cpp \
registrykeytable.cpp \
registrynodetree.cpp \
dlgsearch.cpp \
threadsearch.cpp \
searchresultwidget.cpp \
tabwidget.cpp \
- argparser.cpp
+ argparser.cpp \
+ datainterpretertable.cpp \
+ datainterpreterwidget.cpp
HEADERS += mainwindow.h \
registrynode.h \
registrynodetreemodel.h \
registrykey.h \
registrykeytablemodel.h \
dlgabout.h \
dlgkeydetails.h \
qhexedit/qhexedit_p.h \
qhexedit/qhexedit.h \
- datainterpreter.h \
reporttemplate.h \
datareporter.h \
datareporterengine.h \
registryhive.h \
qtscript_types/bytearray.h \
qtscript_types/bytearrayprototype.h \
qtscript_types/bytearrayiterator.h \
dlgreportviewer.h \
registrykeytable.h \
registrynodetree.h \
dlgsearch.h \
threadsearch.h \
searchresultwidget.h \
tabwidget.h \
- argparser.h
+ argparser.h \
+ datainterpretertable.h \
+ datainterpreterwidget.h
FORMS += mainwindow.ui \
dlgabout.ui \
dlgkeydetails.ui \
dlgreportviewer.ui \
dlgsearch.ui
#LIBS += -lhivex
LIBS += $$PWD/hivex/lib/.libs/libhivex.a \
#DEFINES += __STDC_FORMAT_MACROS
RESOURCES += fred.qrc
RC_FILE = fred.rc
ICON = resources/fred.icns
diff --git a/trunk/mainwindow.cpp b/trunk/mainwindow.cpp
index f9db758..29faec1 100644
--- a/trunk/mainwindow.cpp
+++ b/trunk/mainwindow.cpp
@@ -1,745 +1,621 @@
/*******************************************************************************
* fred Copyright (c) 2011-2012 by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* 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 <http://www.gnu.org/licenses/>. *
*******************************************************************************/
#ifndef FRED_REPORT_TEMPLATE_DIR
#ifndef __MINGW32__
#define FRED_REPORT_TEMPLATE_DIR "/usr/share/fred/report_templates/"
#else
#define FRED_REPORT_TEMPLATE_DIR ".\\report_templates\\"
#endif
#endif
#include <QFileDialog>
#include <QMessageBox>
#include <QStringList>
#include <QDesktopWidget>
#include <QDir>
#include <QSplitter>
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "dlgabout.h"
#include "dlgkeydetails.h"
#include "dlgreportviewer.h"
#include "dlgsearch.h"
#include "compileinfo.h"
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_key_table_model=NULL;
this->p_search_thread=NULL;
this->search_result_widgets.clear();
// Check for ~/.fred config dir
this->CheckUserConfigDir();
// Set main window size
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_node_tree->setHeaderHidden(true);
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_horizontal_splitter2=new QSplitter();
this->p_horizontal_splitter2->setOrientation(Qt::Horizontal);
this->p_hex_edit_widget=new QWidget(this->p_horizontal_splitter2);
this->p_hex_edit_layout=new QVBoxLayout(this->p_hex_edit_widget);
this->p_hex_edit_layout->setContentsMargins(0,0,0,0);
this->p_hex_edit=new QHexEdit();
this->p_hex_edit->setReadOnly(true);
this->p_hex_edit_status_bar=new QLabel();
- this->p_data_interpreter_widget=new QWidget(this->p_horizontal_splitter2);
- this->p_data_interpreter_layout=
- new QVBoxLayout(this->p_data_interpreter_widget);
- this->p_data_interpreter_layout->setContentsMargins(0,0,0,0);
- this->p_data_interpreter=new DataInterpreter();
-
- this->p_data_interpreter_endianes_widget=new QWidget();
- this->p_data_interpreter_endianes_layout=
- new QHBoxLayout(this->p_data_interpreter_endianes_widget);
- this->p_data_interpreter_endianes_layout->setContentsMargins(0,0,0,0);
- this->p_data_interpreter_endianes_be=new QRadioButton(tr("Big endian"));
- this->p_data_interpreter_endianes_le=new QRadioButton(tr("Little endian"));
-
- // Little endian is default
- this->p_data_interpreter_endianes_le->setChecked(true);
-
- // Disable radio buttons until a hive is opened
- this->p_data_interpreter_endianes_be->setEnabled(false);
- this->p_data_interpreter_endianes_le->setEnabled(false);
+ this->p_data_interpreter_widget=
+ new DataInterpreterWidget(this->p_horizontal_splitter2);
// Make sure hex viewer font is monospaced.
QFont mono_font("Monospace");
mono_font.setStyleHint(QFont::TypeWriter);
this->p_hex_edit->setFont(mono_font);
// Add hexedit page to tab_widget
this->p_tab_widget->addTab(this->p_horizontal_splitter2,tr("Hex viewer"));
// Lay out widgets
this->p_hex_edit_layout->addWidget(this->p_hex_edit);
this->p_hex_edit_layout->addWidget(this->p_hex_edit_status_bar);
- this->p_data_interpreter_endianes_layout->
- addWidget(this->p_data_interpreter_endianes_be);
- this->p_data_interpreter_endianes_layout->
- addWidget(this->p_data_interpreter_endianes_le);
-
- this->p_data_interpreter_layout->addWidget(this->p_data_interpreter);
- this->p_data_interpreter_layout->
- addWidget(this->p_data_interpreter_endianes_widget);
-
this->p_horizontal_splitter2->addWidget(this->p_hex_edit_widget);
this->p_horizontal_splitter2->addWidget(this->p_data_interpreter_widget);
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);
QSizePolicy hex_edit_widget_policy=this->p_hex_edit_widget->sizePolicy();
hex_edit_widget_policy.setVerticalStretch(2);
hex_edit_widget_policy.setHorizontalStretch(200);
this->p_hex_edit_widget->setSizePolicy(hex_edit_widget_policy);
QSizePolicy data_interpreter_widget_policy=
this->p_data_interpreter_widget->sizePolicy();
data_interpreter_widget_policy.setVerticalStretch(2);
data_interpreter_widget_policy.setHorizontalStretch(0);
this->p_data_interpreter_widget->
setSizePolicy(data_interpreter_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_hex_edit,
SIGNAL(currentAddressChanged(int)),
this,
SLOT(SlotHexEditAddressChanged(int)));
this->connect(this->p_tab_widget,
SIGNAL(tabCloseRequested(int)),
this,
SLOT(SlotTabCloseButtonClicked(int)));
// Add central widget
this->setCentralWidget(this->p_horizontal_splitter);
this->centralWidget()->setContentsMargins(4,4,4,0);
// Set window title
this->UpdateWindowTitle();
// Set last open location to home dir
this->last_open_location=QDir::homePath();
// Load report templates and update menu
this->p_data_reporter=new DataReporter();
// Load reports from system wide include dir
this->p_data_reporter->LoadReportTemplates(FRED_REPORT_TEMPLATE_DIR);
// Load user's report templates
this->p_data_reporter->LoadReportTemplates(QDir::homePath()
.append(QDir::separator())
.append(".fred")
.append(QDir::separator())
.append("report_templates"));
this->UpdateDataReporterMenu();
// Finally, react on some command line arguments
if(this->p_args->IsSet("hive-file")) {
this->OpenHive(this->p_args->GetArgVal("hive-file"));
}
}
MainWindow::~MainWindow() {
if(this->is_hive_open) {
this->p_hive->Close();
}
delete ui;
}
void MainWindow::on_action_Quit_triggered() {
qApp->exit();
}
void MainWindow::on_action_Open_hive_triggered() {
QString hive_file="";
hive_file=QFileDialog::getOpenFileName(this,
tr("Open registry hive"),
this->last_open_location,
tr("All files (*)"));
if(hive_file=="") return;
this->OpenHive(hive_file);
}
void MainWindow::on_action_Close_hive_triggered() {
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;
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->setData(QByteArray());
this->p_hex_edit_status_bar->setText("");
- this->p_data_interpreter->ClearValues();
- // Disable radio buttons
- this->p_data_interpreter_endianes_be->setEnabled(false);
- this->p_data_interpreter_endianes_le->setEnabled(false);
+ this->p_data_interpreter_widget->SetData(QByteArray());
+ this->p_data_interpreter_widget->setEnabled(false);
// Close hive
this->p_hive->Close();
this->is_hive_open=false;
this->ui->action_Close_hive->setEnabled(false);
this->ui->ActionSearch->setEnabled(false);
this->ui->MenuReports->setEnabled(false);
this->UpdateWindowTitle();
}
}
void MainWindow::on_actionAbout_Qt_triggered() {
QMessageBox::aboutQt(this,tr("About Qt"));
}
void MainWindow::on_actionAbout_fred_triggered() {
DlgAbout dlg_about(this);
dlg_about.exec();
}
void MainWindow::on_ActionSearch_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);
QList<QByteArray> keywords;
keywords.append(QByteArray(QString("Windows").toAscii()));
// 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);
p_search_thread->Search(this->p_hive->Filename(),
dlg_search.Keywords(),
dlg_search.SearchNodeNames(),
dlg_search.SearchKeyNames(),
dlg_search.SearchKeyValues());
}
}
void MainWindow::SlotNodeTreeClicked(QModelIndex index) {
QString node_path;
if(!index.isValid()) return;
- //Built node path
+ // 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->setData(QByteArray());
this->p_hex_edit_status_bar->setText("");
- this->p_data_interpreter->ClearValues();
+ this->p_data_interpreter_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);
// Set focus back to nodetree to be able to navigate with keyboard
this->p_node_tree->setFocus();
}
void MainWindow::SlotKeyTableDoubleClicked(QModelIndex index) {
Q_UNUSED(index);
/*
QModelIndex key_index;
QModelIndex node_index;
QStringList nodes;
QString key_name;
QString key_type;
QByteArray key_value;
if(!index.isValid()) return;
// Get key name, type and value
key_index=this->p_reg_key_table_model->index(index.row(),0);
key_name=this->p_reg_key_table_model->data(key_index,Qt::DisplayRole)
.toString();
key_index=this->p_reg_key_table_model->index(index.row(),1);
key_type=this->p_reg_key_table_model->data(key_index,Qt::DisplayRole)
.toString();ThreadSearch
key_index=this->p_reg_key_table_model->index(index.row(),2);
key_value=this->p_reg_key_table_model->data(key_index,
RegistryKeyTableModel::
AdditionalRoles_GetRawData)
.toByteArray();
// Get current node
node_index=this->p_node_tree->currentIndex();
//Built node path
nodes.clear();
nodes.append(this->p_reg_node_tree_model->
data(node_index,Qt::DisplayRole).toString());
while(this->p_reg_node_tree_model->parent(node_index)!=QModelIndex()) {
// Prepend all parent nodes
node_index=this->p_reg_node_tree_model->parent(node_index);
nodes.prepend(this->p_reg_node_tree_model->
data(node_index,Qt::DisplayRole).toString());
}
DlgKeyDetails dlg_key_details(this);
dlg_key_details.SetValues(nodes,key_name,key_type,key_value);
dlg_key_details.exec();
*/
}
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->setData(this->selected_key_value);
// Set focus back to nodetree to be able to navigate with keyboard
this->p_key_table->setFocus();
}
void MainWindow::SlotHexEditAddressChanged(int hex_offset) {
if(!this->is_hive_open || this->selected_key_value.isEmpty()) return;
// Update hex edit status bar
this->p_hex_edit_status_bar->
setText(QString("Byte offset: 0x%1 (%2)")
.arg((uint16_t)hex_offset,4,16,QChar('0'))
.arg(hex_offset));
// Update data interpreter
this->UpdateDataInterpreter(hex_offset);
}
void MainWindow::SlotReportClicked() {
// Get report category and name from sender and it's parent
QString category=((QMenu*)((QAction*)QObject::sender())->parent())->title();
QString report=((QAction*)QObject::sender())->text();
// Generate report
QString report_content=this->p_data_reporter->GenerateReport(this->p_hive,
category,
report);
// Show result in report viewer
if(report_content!=QString()) {
DlgReportViewer *p_dlg_report_view=new DlgReportViewer(report_content,this);
p_dlg_report_view->exec();
delete p_dlg_report_view;
} else {
// TODO: Something went wrong!
}
}
void MainWindow::SlotSearchFinished() {
delete this->p_search_thread;
this->p_search_thread=NULL;
this->ui->ActionSearch->setEnabled(true);
// Enable result widget
this->search_result_widgets.last()->setEnabled(true);
}
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 \<key name> from path
path.chop(key.length()+1);
}
// Expand treeview to correct node
QList<QModelIndex> indexes=
this->p_reg_node_tree_model->GetIndexListOf(path);
for(i=0;i<indexes.count();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::Select);
// TODO: This does not work!!
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));
}
}
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);
}
void MainWindow::CheckUserConfigDir() {
QString user_config_dir=QDir::homePath()
.append(QDir::separator())
.append(".fred");
if(!QDir(user_config_dir).exists()) {
// User config dir does not exists, try to create it
if(!QDir().mkpath(user_config_dir)) {
// TODO: Maybe warn user
return;
}
user_config_dir.append(QDir::separator()).append("report_templates");
if(!QDir().mkpath(user_config_dir)) {
// TODO: Maybe warn user
return;
}
}
}
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()));
}
}
void MainWindow::UpdateDataInterpreter(int hex_offset) {
- const char *p_data;
- int remaining_data_len;
- bool little_endian=this->p_data_interpreter_endianes_le->isChecked();
-
- // Remove all old values from data interpreter
- this->p_data_interpreter->ClearValues();
-
- // Calculate how many bytes are remainig after current offset
- remaining_data_len=this->selected_key_value.size()-hex_offset;
- if(!remaining_data_len>0) {
- // Nothing to show
- return;
- }
-
- // Get pointer to data at current offset
- p_data=this->selected_key_value.constData();
- p_data+=hex_offset;
-
- if(remaining_data_len>=1) {
- this->p_data_interpreter->AddValue("int8:",
- RegistryHive::KeyValueToString(
- this->selected_key_value,
- "int8",
- hex_offset));
- this->p_data_interpreter->AddValue("uint8:",
- RegistryHive::KeyValueToString(
- this->selected_key_value,
- "uint8",
- hex_offset));
- }
- if(remaining_data_len>=2) {
- this->p_data_interpreter->AddValue("int16:",
- RegistryHive::KeyValueToString(
- this->selected_key_value,
- "int16",
- hex_offset,
- 0,
- little_endian));
- this->p_data_interpreter->AddValue("uint16:",
- RegistryHive::KeyValueToString(
- this->selected_key_value,
- "uint16",
- hex_offset,
- 0,
- little_endian));
- }
- if(remaining_data_len>=4) {
- this->p_data_interpreter->AddValue("int32:",
- RegistryHive::KeyValueToString(
- this->selected_key_value,
- "int32",
- hex_offset,
- 0,
- little_endian));
- this->p_data_interpreter->AddValue("uint32:",
- RegistryHive::KeyValueToString(
- this->selected_key_value,
- "uint32",
- hex_offset,
- 0,
- little_endian));
- this->p_data_interpreter->AddValue("unixtime:",
- RegistryHive::KeyValueToString(
- this->selected_key_value,
- "unixtime",
- hex_offset,
- 0,
- little_endian));
- }
- if(remaining_data_len>=8) {
- this->p_data_interpreter->AddValue("int64:",
- RegistryHive::KeyValueToString(
- this->selected_key_value,
- "int64",
- hex_offset,
- 0,
- little_endian));
- this->p_data_interpreter->AddValue("uint64:",
- RegistryHive::KeyValueToString(
- this->selected_key_value,
- "uint64",
- hex_offset,
- 0,
- little_endian));
-/*
- TODO: Check one could implement this
- this->p_data_interpreter->AddValue("unixtime64:",
- RegistryHive::KeyValueToString(
- this->selected_key_value,
- "unixtime64",
- hex_offset));
-*/
- this->p_data_interpreter->AddValue("filetime64:",
- RegistryHive::KeyValueToString(
- this->selected_key_value,
- "filetime",
- hex_offset,
- 0,
- little_endian));
- }
+ // Update data interpreter. There is currently no interpretition that uses
+ // more then 8 bytes, so only pass 8 bytes at max.
+ this->p_data_interpreter_widget->SetData(
+ this->selected_key_value.mid(hex_offset,8));
}
void MainWindow::UpdateDataReporterMenu() {
int i=0,ii=0;
QMenu *p_category_entry;
QAction *p_report_entry;
QStringList categories=this->p_data_reporter->GetAvailableReportCategories();
QStringList reports;
for(i=0;i<categories.count();i++) {
// First create category submenu
p_category_entry=this->ui->MenuReports->addMenu(categories.value(i));
// Now add category reports
reports=this->p_data_reporter->GetAvailableReports(categories.value(i));
for(ii=0;ii<reports.count();ii++) {
p_report_entry=new QAction(reports.value(ii),p_category_entry);
p_category_entry->addAction(p_report_entry);
this->connect(p_report_entry,
SIGNAL(triggered()),
this,
SLOT(SlotReportClicked()));
}
}
}
void MainWindow::OpenHive(QString hive_file) {
// Update last open location
this->last_open_location=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();
// Try to open hive
if(!this->p_hive->Open(hive_file)) {
QMessageBox::critical(this,
tr("Error opening hive file"),
tr("Unable to open file '%1'").arg(hive_file));
return;
}
// Create tree model
this->p_reg_node_tree_model=
new RegistryNodeTreeModel(this->p_hive);
this->p_node_tree->setModel(this->p_reg_node_tree_model);
this->is_hive_open=true;
this->ui->action_Close_hive->setEnabled(true);
this->ui->ActionSearch->setEnabled(true);
this->ui->MenuReports->setEnabled(true);
- // Enable radio buttons for endianes selection
- this->p_data_interpreter_endianes_be->setEnabled(true);
- this->p_data_interpreter_endianes_le->setEnabled(true);
+ // Enable data interpreter
+ this->p_data_interpreter_widget->setEnabled(true);
this->UpdateWindowTitle(hive_file);
}
diff --git a/trunk/mainwindow.h b/trunk/mainwindow.h
index 4eb288e..e1211a9 100644
--- a/trunk/mainwindow.h
+++ b/trunk/mainwindow.h
@@ -1,144 +1,151 @@
/*******************************************************************************
* fred Copyright (c) 2011-2012 by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* 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 <http://www.gnu.org/licenses/>. *
*******************************************************************************/
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QWidget>
#include <QLabel>
#include <QTabWidget>
#include <QVBoxLayout>
#include <QSplitter>
#include <QString>
#include <QByteArray>
#include <hivex.h>
#include "argparser.h"
#include "registryhive.h"
#include "registrynodetree.h"
#include "registrynodetreemodel.h"
#include "registrykeytable.h"
#include "registrykeytablemodel.h"
#include "qhexedit/qhexedit.h"
-#include "datainterpreter.h"
+#include "datainterpreterwidget.h"
#include "datareporter.h"
#include "threadsearch.h"
#include "searchresultwidget.h"
#include "tabwidget.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(ArgParser *p_arg_parser);
~MainWindow();
private slots:
void on_action_Quit_triggered();
void on_action_Open_hive_triggered();
void on_action_Close_hive_triggered();
void on_actionAbout_Qt_triggered();
void on_actionAbout_fred_triggered();
void on_ActionSearch_triggered();
void SlotNodeTreeClicked(QModelIndex index);
void SlotKeyTableClicked(QModelIndex index);
void SlotKeyTableDoubleClicked(QModelIndex index);
void SlotHexEditAddressChanged(int hex_offset);
void SlotReportClicked();
void SlotSearchFinished();
void SlotSearchResultWidgetDoubleClicked(QModelIndex index);
void SlotTabCloseButtonClicked(int index);
+/*
+ void SlotDataInterpreterEndiannessBe(bool checked);
+ void SlotDataInterpreterEndiannessLe(bool checked);
+*/
private:
Ui::MainWindow *ui;
ArgParser *p_args;
QString last_open_location;
RegistryHive *p_hive;
bool is_hive_open;
RegistryNodeTreeModel *p_reg_node_tree_model;
RegistryKeyTableModel *p_reg_key_table_model;
QByteArray selected_key_value;
QList<SearchResultWidget*> search_result_widgets;
// Widgets etc...
RegistryNodeTree *p_node_tree;
RegistryKeyTable *p_key_table;
TabWidget *p_tab_widget;
QWidget *p_hex_edit_widget;
QVBoxLayout *p_hex_edit_layout;
QHexEdit *p_hex_edit;
QLabel *p_hex_edit_status_bar;
+/*
QWidget *p_data_interpreter_widget;
QVBoxLayout *p_data_interpreter_layout;
DataInterpreter *p_data_interpreter;
- QWidget *p_data_interpreter_endianes_widget;
- QHBoxLayout *p_data_interpreter_endianes_layout;
- QRadioButton *p_data_interpreter_endianes_be;
- QRadioButton *p_data_interpreter_endianes_le;
+ QWidget *p_data_interpreter_endianness_widget;
+ QHBoxLayout *p_data_interpreter_endianness_layout;
+ QRadioButton *p_data_interpreter_endianness_be;
+ QRadioButton *p_data_interpreter_endianness_le;
+*/
+ DataInterpreterWidget *p_data_interpreter_widget;
QSplitter *p_horizontal_splitter;
QSplitter *p_horizontal_splitter2;
QSplitter *p_vertical_splitter;
DataReporter *p_data_reporter;
ThreadSearch *p_search_thread;
/*
* CheckUserConfigDir
*
* Checks for and possibly creates the ~/.fred directory
*/
void CheckUserConfigDir();
/*
* UpdateWindowTitle
*
* Updates the window title
*/
void UpdateWindowTitle(QString filename="");
/*
* UpdateDataInterpreter
*
* Update data interpreter
*/
void UpdateDataInterpreter(int hex_offset);
/*
* UpdateDataReporterMenu
*
*/
void UpdateDataReporterMenu();
/*
* OpenHive
*
* Open a registry hive
*/
void OpenHive(QString hive_file);
};
#endif // MAINWINDOW_H
diff --git a/trunk/registryhive.cpp b/trunk/registryhive.cpp
index 7228815..7b2a64b 100644
--- a/trunk/registryhive.cpp
+++ b/trunk/registryhive.cpp
@@ -1,592 +1,592 @@
/*******************************************************************************
* fred Copyright (c) 2011-2012 by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* 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 <http://www.gnu.org/licenses/>. *
*******************************************************************************/
#include "registryhive.h"
#include <QStringList>
#include <QDateTime>
#include <stdlib.h>
#include <stdio.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
/*
* 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;
}
/*
* ~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;
return true;
}
/*
* Close
*/
bool RegistryHive::Close(bool commit_changes) {
if(this->is_hive_open) {
if(commit_changes) {
// Commit changes before closing hive.
// TODO: Maybe it would be more secure to commit changes to a new file and
// then move it over the original one.
hivex_commit(this->p_hive,NULL,0);
}
// As hivex_close will _ALWAYS_ free the handle, we don't need the following
// values anymore
this->hive_file="";
this->is_hive_open=false;
// Close hive
if(hivex_close(this->p_hive)!=0) return false;
}
return true;
}
QString RegistryHive::Filename() {
if(this->is_hive_open) return this->hive_file;
return QString();
}
/*
* GetNodes
*/
QMap<QString,int> RegistryHive::GetNodes(QString path) {
hive_node_h parent_node;
// Get handle to last node in path
if(!this->GetNodeHandle(path,&parent_node)) return QMap<QString,int>();
// Get and return nodes
return this->GetNodesHelper(parent_node);
}
/*
* GetNodes
*/
QMap<QString,int> RegistryHive::GetNodes(int parent_node) {
if(parent_node==0) {
this->SetError(tr("Invalid parent node handle specified!"));
return QMap<QString,int>();
}
// Get and return nodes
return this->GetNodesHelper(parent_node);
}
/*
* GetKeys
*/
QMap<QString,int> RegistryHive::GetKeys(QString path) {
hive_node_h parent_node;
// Get handle to last node in path
if(!this->GetNodeHandle(path,&parent_node)) return QMap<QString,int>();
// Get and return keys
return this->GetKeysHelper(parent_node);
}
/*
* GetKeys
*/
QMap<QString,int> RegistryHive::GetKeys(int parent_node) {
if(parent_node==0) {
this->SetError(tr("Invalid parent node handle specified!"));
return QMap<QString,int>();
}
// Get and return keys
return this->GetKeysHelper(parent_node);
}
/*
* 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);
}
/*
* KeyValueToString
*/
QString RegistryHive::KeyValueToString(QByteArray value, int value_type) {
QString ret="";
int i=0;
#define ToHexStr() { \
for(i=0;i<value.size();i++) { \
ret.append(QString().sprintf("%02X ",(uint8_t)(value.constData()[i]))); \
} \
ret.chop(1); \
}
switch(value_type) {
case hive_t_REG_NONE:
// Just a key without a value, but to be certain...
ToHexStr();
break;
case hive_t_REG_SZ:
// A Windows string (encoding is unknown, but often UTF16-LE)
// TODO: What happens if encoding is not UTF16-LE ??? Thx Billy!!!
ret=value.size() ? QString().fromUtf16((ushort*)(value.constData())) : "";
break;
case hive_t_REG_EXPAND_SZ:
// A Windows string that contains %env% (environment variable expansion)
ret=value.size() ? QString().fromUtf16((ushort*)(value.constData())) : "";
break;
case hive_t_REG_BINARY:
// A blob of binary
ToHexStr();
break;
case hive_t_REG_DWORD:
// DWORD (32 bit integer), little endian
ret=QString().sprintf("0x%08X",*(uint32_t*)value.constData());
break;
case hive_t_REG_DWORD_BIG_ENDIAN:
// DWORD (32 bit integer), big endian
ret=QString().sprintf("0x%08X",*(uint32_t*)value.constData());
break;
case hive_t_REG_LINK:
// Symbolic link to another part of the registry tree
ToHexStr();
break;
case hive_t_REG_MULTI_SZ:
// Multiple Windows strings.
// See http://blogs.msdn.com/oldnewthing/archive/2009/10/08/9904646.aspx
ToHexStr();
break;
case hive_t_REG_RESOURCE_LIST:
// Resource list
ToHexStr();
break;
case hive_t_REG_FULL_RESOURCE_DESCRIPTOR:
// Resource descriptor
ToHexStr();
break;
case hive_t_REG_RESOURCE_REQUIREMENTS_LIST:
// Resouce requirements list
ToHexStr();
break;
case hive_t_REG_QWORD:
// QWORD (64 bit integer). Usually little endian.
ret=
QString("0x%1").arg((quint64)(*(uint64_t*)value.constData()),16,16,QChar('0'));
break;
default:
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;
- // TODO: This will fail on platforms with different endianes!
+ // TODO: This will fail on platforms with different endianness!
#define bswap_16(value) ((((value) & 0xff) << 8) | ((value) >> 8))
#define bswap_32(value) \
(((uint32_t)bswap_16((uint16_t)((value) & 0xffff)) << 16) | \
(uint32_t)bswap_16((uint16_t)((value) >> 16)))
#define bswap_64(value) \
(((uint64_t)bswap_32((uint32_t)((value) & 0xffffffff)) << 32) | \
(uint64_t)bswap_32((uint32_t)((value) >> 32))) \
// ConvertFull name
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=*(int16_t*)p_data;
if(little_endian) ret=QString().sprintf("%d",val);
else ret=QString().sprintf("%d",bswap_16(val));
} else if(format=="uint16" && remaining_data_len>=2) {
uint16_t val=*(uint16_t*)p_data;
if(little_endian) ret=QString().sprintf("%u",val);
else ret=QString().sprintf("%u",bswap_16(val));
} else if(format=="int32" && remaining_data_len>=4) {
int32_t val=*(int32_t*)p_data;
if(little_endian) ret=QString().sprintf("%d",val);
else ret=QString().sprintf("%d",bswap_32(val));
} else if(format=="uint32" && remaining_data_len>=4) {
uint32_t val=*(uint32_t*)p_data;
if(little_endian) ret=QString().sprintf("%u",val);
else ret=QString().sprintf("%u",bswap_32(val));
} else if(format=="unixtime" && remaining_data_len>=4) {
uint32_t val=*(uint32_t*)p_data;
if(!little_endian) val=bswap_32(val);
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=*(int64_t*)p_data;
if(little_endian) ret=QString("%1").arg(val);
- else ret=QString("%1").arg(bswap_64(val));
+ else ret=QString("%1").arg((int64_t)bswap_64(val));
} else if(format=="uint64" && remaining_data_len>=8) {
uint64_t val=*(uint64_t*)p_data;
if(little_endian) ret=QString("%1").arg(val);
else ret=QString("%1").arg(bswap_64(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=*(uint64_t*)p_data;
if(!little_endian) val=bswap_64(val);
if(val==0) {
ret="n/a";
} else {
// TODO: Warn if >32bit
QDateTime date_time;
date_time.setTimeSpec(Qt::UTC);
date_time.setTime_t((val-EPOCH_DIFF)/10000000);
ret=date_time.toString("yyyy/MM/dd hh:mm:ss");
}
} else if(format=="ascii") {
// TODO: This fails bad if the string is not null terminated!! It might be
// wise checking for a null char here
ret=QString().fromAscii((char*)p_data,length);
} else if(format=="utf16" && remaining_data_len>=2) {
ret=QString().fromUtf16((ushort*)p_data,length);
} else {
// Unknown variant type or another error
return QString();
}
return ret;
}
/*
* KeyTypeToString
*/
QString RegistryHive::KeyTypeToString(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;
}
/*
* 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;i<nodes.count();i++) {
// printf("Spotting node '%s'\n",nodes.value(i).toAscii().constData());
*p_node=hivex_node_get_child(this->p_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;
}
/*
* GetNodesHelper
*/
QMap<QString,int> RegistryHive::GetNodesHelper(hive_node_h parent_node) {
QMap<QString,int> 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<QString,int>();
}
// 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<QString,int>();
}
keys.insert(QString(p_name),(int)child_nodes[i]);
free(p_name);
i++;
}
free(child_nodes);
return keys;
}
/*
* GetKeysHelper
*/
QMap<QString,int> RegistryHive::GetKeysHelper(hive_node_h parent_node) {
QMap<QString,int> 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<QString,int>();
}
// 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<QString,int>();
}
keys.insert(QString(p_name),p_keys[i]);
free(p_name);
i++;
}
free(p_keys);
return keys;
}
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;
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, May 11, 6:33 AM (1 d, 15 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1247631
Default Alt Text
(75 KB)
Attached To
Mode
rFRED fred
Attached
Detach File
Event Timeline
Log In to Comment