diff --git a/trunk/datareporter.cpp b/trunk/datareporter.cpp index 1dcbed4..10072dc 100644 --- a/trunk/datareporter.cpp +++ b/trunk/datareporter.cpp @@ -1,152 +1,152 @@ /******************************************************************************* * fred Copyright (c) 2011 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 "datareporter.h" #include #include #include #include DataReporter::DataReporter() { this->report_templates.clear(); //this->p_report_engine=new DataReporterEngine(); } DataReporter::~DataReporter() { //delete this->p_report_engine; qDeleteAll(this->report_templates); } -void DataReporter::LoadReportTemplates() { +void DataReporter::LoadReportTemplates(QString dir) { QString report_template=""; int i=0; QString report_category=""; QString report_name=""; ReportTemplate *p_report; // Get all template files in report_templates directory - QDir report_dir("../trunk/report_templates/"); + QDir report_dir(dir); QStringList found_report_templates=report_dir. entryList(QStringList()<<"*.qs"); for(i=0;i_.qs) report_category=found_report_templates.value(i).left( found_report_templates.value(i).indexOf("_")); report_name=found_report_templates.value(i).mid( found_report_templates.value(i).indexOf("_")+1); - report_name=report_name.left(report_name.lastIndexOf(".")-1); + report_name=report_name.left(report_name.lastIndexOf(".")); // Add report to list p_report=new ReportTemplate(report_category, report_name, report_template); this->report_templates.append(p_report); } } QStringList DataReporter::GetAvailableReportCategories() { QStringList ret; QString cat; int i=0; 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; } QStringList DataReporter::GetAvailableReports(QString category) { QStringList 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)->Name()); } ret.sort(); return ret; } QString DataReporter::GenerateReport(RegistryHive *p_hive, QString report_category, QString report_name) { int i=0; ReportTemplate *p_report; DataReporterEngine engine(p_hive); QString report_code; //ReportData report_data; for(i=0;ireport_templates.count();i++) { p_report=this->report_templates.value(i); if(p_report->Category()!=report_category || p_report->Name()!=report_name) { continue; } QScriptValue hive_value=engine.newQObject(p_hive); engine.globalObject().setProperty("RegistryHive",hive_value); //QScriptValue return_value=engine.newQObject(&report_data); //engine.globalObject().setProperty("ReportData",return_value); // Open report template QFile template_file(p_report->File()); if(!template_file.open(QIODevice::ReadOnly | QIODevice::Text)) { qDebug("Couldn't open file '%s'",p_report->File().toAscii().constData()); return QString(); } // Read template file QTextStream in(&template_file); while(!in.atEnd()) { report_code.append(in.readLine()).append("\n"); } // Close report template file template_file.close(); QScriptValue report_result=engine.evaluate(report_code,p_report->File()); if (report_result.isError() || engine.hasUncaughtException()) { QMessageBox::critical(0, "Hello Script", QString::fromLatin1("%0:%1: %2") .arg(p_report->File()) .arg(report_result.property("lineNumber").toInt32()) .arg(report_result.toString())); return QString(); } return engine.report_content; } return QString(); } diff --git a/trunk/datareporter.h b/trunk/datareporter.h index 2bac96f..e9e887f 100644 --- a/trunk/datareporter.h +++ b/trunk/datareporter.h @@ -1,48 +1,48 @@ /******************************************************************************* * fred Copyright (c) 2011 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 DATAREPORTER_H #define DATAREPORTER_H #include #include "reporttemplate.h" #include "datareporterengine.h" #include "registryhive.h" class DataReporter { public: DataReporter(); ~DataReporter(); - void LoadReportTemplates(); + void LoadReportTemplates(QString dir); QStringList GetAvailableReportCategories(); QStringList GetAvailableReports(QString category); QString GenerateReport(RegistryHive *p_hive, QString report_category, QString report_name); private: QList report_templates; //DataReporterEngine *p_report_engine; }; #endif // DATAREPORTER_H diff --git a/trunk/datareporterengine.cpp b/trunk/datareporterengine.cpp index 0fa312a..a3965ad 100644 --- a/trunk/datareporterengine.cpp +++ b/trunk/datareporterengine.cpp @@ -1,360 +1,373 @@ /******************************************************************************* * fred Copyright (c) 2011 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 "datareporterengine.h" #include #include #include #include #include DataReporterEngine::DataReporterEngine(RegistryHive *p_hive) : QScriptEngine() { // Init vars this->p_registry_hive=p_hive; this->report_content=""; // 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()); // 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); // 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); // 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); // RegistryKeyTypeToString QScriptValue func_type_to_string= this->newFunction(this->RegistryKeyTypeToString,1); this->globalObject().setProperty("RegistryKeyTypeToString", func_type_to_string); /* // Add RegistryHive object QScriptValue obj_registry_hive=this->newQObject(this->p_registry_hive); this->globalObject().setProperty("RegistryHive",obj_registry_hive); */ } DataReporterEngine::~DataReporterEngine() { delete this->p_type_byte_array; } QScriptValue DataReporterEngine::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()); } //QScriptValue calleeData=context->callee().data(); //DataReporterEngine *engine= // qobject_cast(calleeData.toQObject()); qobject_cast(engine)->report_content.append(content); return engine->undefinedValue(); } QScriptValue DataReporterEngine::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 DataReporterEngine::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 DataReporterEngine::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 DataReporterEngine::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 DataReporterEngine::RegistryKeyValueFromScript(const QScriptValue &obj, s_RegistryKeyValue &s) { s.type=obj.property("type").toInt32(); s.length=obj.property("length").toInt32(); // TODO: Don't know if this works, but it probably does ;) s.value=qvariant_cast(obj.property("value").data().toVariant()); } QScriptValue DataReporterEngine::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() || key_length==-1) { // Get error message ro clear error state p_hive->GetErrorMsg(); 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 DataReporterEngine::RegistryKeyValueToScript(engine,script_key_value); } QScriptValue DataReporterEngine::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); } QScriptValue DataReporterEngine::RegistryKeyValueToVariant( QScriptContext *context, QScriptEngine *engine) { int offset=0; QByteArray key_value; QString variant_type; int remaining_data_len; const char *p_data; QString ret=""; // This function needs at least two arguments, key value and variant type, // and may have an optional third argument specifying an offset if(context->argumentCount()<2 || context->argumentCount()>3) return engine->undefinedValue(); if(context->argumentCount()==3) offset=context->argument(2).toInt32(); // Cast ByteArray argument to QByteArray key_value=qvariant_cast(context->argument(0).data().toVariant()); variant_type=context->argument(1).toString(); // 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 engine->undefinedValue(); } // Get pointer to data at specified offset p_data=key_value.constData(); p_data+=offset; // Convert - if(variant_type=="unixtime" && remaining_data_len>=4) { + if(variant_type=="int8" && remaining_data_len>=1) { + ret=QString().sprintf("%d",*(int8_t*)p_data); + } else if(variant_type=="uint8" && remaining_data_len>=1) { + ret=QString().sprintf("%u",*(uint8_t*)p_data); + } else if(variant_type=="int16" && remaining_data_len>=2) { + ret=QString().sprintf("%d",*(int16_t*)p_data); + } else if(variant_type=="uint16" && remaining_data_len>=2) { + ret=QString().sprintf("%u",*(uint16_t*)p_data); + } else if(variant_type=="int32" && remaining_data_len>=4) { + ret=QString().sprintf("%d",*(int32_t*)p_data); + } else if(variant_type=="uint32" && remaining_data_len>=4) { + ret=QString().sprintf("%d",*(uint32_t*)p_data); + } else if(variant_type=="unixtime" && remaining_data_len>=4) { if(*(uint32_t*)p_data==0) { ret="n/a"; } else { QDateTime date_time; date_time.setTime_t(*(uint32_t*)p_data); ret=date_time.toString("yyyy/MM/dd hh:mm:ss"); } } else if(variant_type=="filetime" && remaining_data_len>=8) { if(*(uint64_t*)p_data==0) { ret="n/a"; } else { + // TODO: Warn if >32bit QDateTime date_time; date_time.setTime_t((*(uint64_t*)p_data-116444736000000000)/10000000); ret=date_time.toString("yyyy/MM/dd hh:mm:ss"); } } else if(variant_type=="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); } else if(variant_type=="utf16" && remaining_data_len>=2) { ret=QString().fromUtf16((ushort*)p_data); } else { // Unknown variant type or another error return engine->undefinedValue(); } return engine->newVariant(ret); } QScriptValue DataReporterEngine::RegistryKeyTypeToString( QScriptContext *context, QScriptEngine *engine) { QString ret=""; // This function needs one arguments, key type if(context->argumentCount()!=1) return engine->undefinedValue(); ret=RegistryHive::KeyTypeToString(context->argument(0).toInt32()); return engine->newVariant(ret); } diff --git a/trunk/debian/changelog b/trunk/debian/changelog index e1f6769..9edc012 100644 --- a/trunk/debian/changelog +++ b/trunk/debian/changelog @@ -1,12 +1,18 @@ +fred (0.1.0alpha3) unstable; urgency=low + + * Added data report engine and 2 basic report templates + + -- Daniel Gillen Wed, 17 Aug 2011 11:30:00 +0200 + fred (0.1.0alpha2) unstable; urgency=low * Integrated hexeditor into main windows. * Added data interpreters -- Daniel Gillen Tue, 09 Aug 2011 17:00:00 +0200 fred (0.1.0alpha1) unstable; urgency=low * First public release -- Daniel Gillen Sat, 06 Aug 2011 22:00:00 +0200 diff --git a/trunk/debian/fred.dirs b/trunk/debian/fred.dirs index a59ccc8..7344f38 100644 --- a/trunk/debian/fred.dirs +++ b/trunk/debian/fred.dirs @@ -1,3 +1,4 @@ usr/bin usr/share/applications usr/share/pixmaps +usr/share/fred diff --git a/trunk/debian/fred.install b/trunk/debian/fred.install index 7b9c38e..6b145bc 100644 --- a/trunk/debian/fred.install +++ b/trunk/debian/fred.install @@ -1,2 +1,4 @@ resources/fred.desktop usr/share/applications/ resources/fred.png usr/share/pixmaps/ +report_templates/SAM_UserAccounts.qs usr/share/fred/report_templates/ +report_templates/SOFTWARE_WindowsVersion.qs usr/share/fred/report_templates/ diff --git a/trunk/debian/rules b/trunk/debian/rules index ef35770..690dd2d 100755 --- a/trunk/debian/rules +++ b/trunk/debian/rules @@ -1,98 +1,98 @@ #!/usr/bin/make -f # -*- makefile -*- # Sample debian/rules that uses debhelper. # This file was originally written by Joey Hess and Craig Small. # As a special exception, when this file is copied by dh-make into a # dh-make output file, you may use that output file without restriction. # This special exception was added by Craig Small in version 0.37 of dh-make. # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 configure: configure-stamp configure-stamp: dh_testdir # Add here commands to configure the package. - qmake-qt4 + qmake-qt4 DEFINES+="FRED_REPORT_TEMPLATE_DIR=\'\\\"/usr/share/fred/report_templates\\\"\'" touch configure-stamp build: build-stamp build-stamp: configure-stamp dh_testdir # Add here commands to compile the package. # Optimised make for fast compilation on multi-core machines $(MAKE) -j$(shell cat /proc/cpuinfo | grep ^processor | wc -l) lrelease fred.pro touch $@ clean: dh_testdir dh_testroot rm -f build-stamp configure-stamp # dpkg-buildpackage starts with cleaning, so we have to be sure that there's a Makefile (and thus call qmake-qt4) qmake-qt4 # Add here commands to clean up after the build process. $(MAKE) clean # remove leftover files: rm -f fred rm -f compileinfo.cpp #rm -f fred_*.qm dh_clean install: build dh_testdir dh_testroot dh_clean -k dh_installdirs # Add here commands to install the package into debian/fred. # $(MAKE) DESTDIR=$(CURDIR)/debian/fred install cp fred debian/fred/usr/bin #cp fred_*.qm debian/fred/usr/share/fred # Build architecture-independent files here. binary-indep: build install # We have nothing to do by default. # Build architecture-dependent files here. binary-arch: build install dh_testdir dh_testroot dh_installchangelogs # dh_installdocs # dh_installexamples dh_install dh_installmenu # dh_installdebconf # dh_installlogrotate # dh_installemacsen # dh_installpam # dh_installmime # dh_python # dh_installinit # dh_installcron # dh_installinfo # dh_installman dh_link dh_strip dh_compress dh_fixperms # dh_perl # dh_makeshlibs dh_installdeb dh_shlibdeps dh_gencontrol dh_md5sums dh_builddeb binary: binary-indep binary-arch .PHONY: build clean binary-indep binary-arch binary install configure diff --git a/trunk/mainwindow.cpp b/trunk/mainwindow.cpp index 4a359e6..9a276d9 100644 --- a/trunk/mainwindow.cpp +++ b/trunk/mainwindow.cpp @@ -1,462 +1,494 @@ /******************************************************************************* * fred Copyright (c) 2011 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 FRED_REPORT_TEMPLATE_DIR + #define FRED_REPORT_TEMPLATE_DIR "/usr/share/fred/report_templates/" +#endif + #include #include #include #include #include #include #include "mainwindow.h" #include "ui_mainwindow.h" #include "dlgabout.h" #include "dlgkeydetails.h" #include "dlgreportviewer.h" #include "compileinfo.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); // Initialize private vars 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; + // 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 QTreeView(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 QTableView(this->p_vertical_splitter); this->p_key_table->setSelectionBehavior(QAbstractItemView::SelectRows); this->p_horizontal_splitter2=new QSplitter(this->p_vertical_splitter); 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=new DataInterpreter(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); // 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_horizontal_splitter2->addWidget(this->p_hex_edit_widget); this->p_horizontal_splitter2->addWidget(this->p_data_interpreter); this->p_vertical_splitter->addWidget(this->p_key_table); this->p_vertical_splitter->addWidget(this->p_horizontal_splitter2); 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 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_policy=this->p_data_interpreter->sizePolicy(); data_interpreter_policy.setVerticalStretch(2); data_interpreter_policy.setHorizontalStretch(0); this->p_data_interpreter->setSizePolicy(data_interpreter_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_key_table /*->selectionModel()*/, /* SIGNAL(selectionChanged(QItemSelection,QItemSelection)) */ SIGNAL(clicked(QModelIndex)), this, SLOT(SlotKeyTableClicked(QModelIndex))); this->connect(this->p_key_table, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(SlotKeyTableDoubleClicked(QModelIndex))); this->connect(this->p_hex_edit, SIGNAL(currentAddressChanged(int)), this, SLOT(SlotHexEditAddressChanged(int))); // Add central widget this->setContentsMargins(4,4,4,0); this->setCentralWidget(this->p_horizontal_splitter); // 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(); - this->p_data_reporter->LoadReportTemplates(); + // 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(); } 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; // 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->MenuReports->setEnabled(true); this->UpdateWindowTitle(hive_file); } void MainWindow::on_action_Close_hive_triggered() { if(this->is_hive_open) { // Delete models if(this->p_reg_node_tree_model!=NULL) { delete this->p_reg_node_tree_model; this->p_reg_node_tree_model=NULL; } if(this->p_reg_key_table_model!=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(); // Close hive this->p_hive->Close(); this->is_hive_open=false; this->ui->action_Close_hive->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::SlotNodeTreeClicked(QModelIndex index) { QString node_path; //Built node path node_path.clear(); node_path=this->p_reg_node_tree_model->data(index,Qt::DisplayRole) .toString().prepend("\\"); while(this->p_reg_node_tree_model->parent(index)!=QModelIndex()) { // Prepend all parent nodes index=this->p_reg_node_tree_model->parent(index); node_path.prepend(this->p_reg_node_tree_model->data(index,Qt::DisplayRole) .toString().prepend("\\")); } // Create table model and attach it to the table view if(this->p_reg_key_table_model!=NULL) delete this->p_reg_key_table_model; this->p_reg_key_table_model=new RegistryKeyTableModel(this->p_hive,node_path); this->p_key_table->setModel(this->p_reg_key_table_model); // Resize table rows / columns to fit data this->p_key_table->resizeColumnsToContents(); this->p_key_table->horizontalHeader()->stretchLastSection(); } void MainWindow::SlotKeyTableDoubleClicked(QModelIndex 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(); 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); } void MainWindow::SlotHexEditAddressChanged(int hex_offset) { // Update hex edit status bar this->p_hex_edit_status_bar-> setText(QString().sprintf("Byte offset: 0x%04X (%u)",hex_offset,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(); QString report_content=this->p_data_reporter->GenerateReport(this->p_hive, category, report); if(report_content!=QString()) { DlgReportViewer dlg_report_view(report_content,this); dlg_report_view.exec(); } else { // TODO: Something went wrong! } } +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().sprintf("%s v%s",APP_TITLE,APP_VERSION)); } else { this->setWindowTitle(QString().sprintf("%s v%s - %s", APP_TITLE, APP_VERSION, filename.toLocal8Bit().constData())); } } void MainWindow::UpdateDataInterpreter(int hex_offset) { QDateTime date_time; const char *p_data; int remaining_data_len; // 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; #define rotl32(x,n) (((x) << n) | ((x) >> (32 - n))) //#define rotr32(x,n) (((x) >> n) | ((x) << (32 - n))) #define rotl64(x,n) (((x) << n) | ((x) >> (64 - n))) //#define rotr64(x,n) (((x) >> n) | ((x) << (64 - n))) if(remaining_data_len>=1) { this->p_data_interpreter->AddValue("int8:", QString().sprintf("%d", *(int8_t*)p_data)); this->p_data_interpreter->AddValue("uint8:", QString().sprintf("%u", *(uint8_t*)p_data)); } if(remaining_data_len>=2) { this->p_data_interpreter->AddValue("int16:", QString().sprintf("%d", *(int16_t*)p_data)); this->p_data_interpreter->AddValue("uint16:", QString().sprintf("%u", *(uint16_t*)p_data)); } if(remaining_data_len>=4) { this->p_data_interpreter->AddValue("int32:", QString().sprintf("%d", *(int32_t*)p_data)); this->p_data_interpreter->AddValue("uint32:", QString().sprintf("%d", *(uint32_t*)p_data)); date_time.setTime_t(*(uint32_t*)p_data); this->p_data_interpreter->AddValue("Unixtime:", date_time. toString("yyyy/MM/dd hh:mm:ss")); } if(remaining_data_len>=8) { this->p_data_interpreter->AddValue("int64:", QString().sprintf("%d", *(int64_t*)p_data)); this->p_data_interpreter->AddValue("uint64:", QString().sprintf("%d", *(uint64_t*)p_data)); date_time.setTime_t((*(uint64_t*)p_data-116444736000000000)/10000000); this->p_data_interpreter->AddValue("Win64time:", date_time. toString("yyyy/MM/dd hh:mm:ss")); } #undef rotl32 #undef rotl64 } 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;iui->MenuReports->addMenu(categories.value(i)); // Now add category reports reports=this->p_data_reporter->GetAvailableReports(categories.value(i)); for(ii=0;iiaddAction(p_report_entry); this->connect(p_report_entry, SIGNAL(triggered()), this, SLOT(SlotReportClicked())); } } } diff --git a/trunk/mainwindow.h b/trunk/mainwindow.h index 2304058..a42c911 100644 --- a/trunk/mainwindow.h +++ b/trunk/mainwindow.h @@ -1,101 +1,107 @@ /******************************************************************************* * fred Copyright (c) 2011 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 "registryhive.h" #include "registrynodetreemodel.h" #include "registrykeytablemodel.h" #include "qhexedit/qhexedit.h" #include "datainterpreter.h" #include "datareporter.h" namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~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 SlotNodeTreeClicked(QModelIndex index); void SlotKeyTableClicked(QModelIndex index); void SlotKeyTableDoubleClicked(QModelIndex index); void SlotHexEditAddressChanged(int hex_offset); void SlotReportClicked(); private: Ui::MainWindow *ui; 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; // Widgets etc... QTreeView *p_node_tree; QTableView *p_key_table; QWidget *p_hex_edit_widget; QHexEdit *p_hex_edit; QLabel *p_hex_edit_status_bar; DataInterpreter *p_data_interpreter; QVBoxLayout *p_hex_edit_layout; QSplitter *p_horizontal_splitter; QSplitter *p_horizontal_splitter2; QSplitter *p_vertical_splitter; DataReporter *p_data_reporter; + /* + * 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(); }; #endif // MAINWINDOW_H diff --git a/trunk/report_templates/SAM_UserAccounts.qs b/trunk/report_templates/SAM_UserAccounts.qs index c66852d..ba6d384 100644 --- a/trunk/report_templates/SAM_UserAccounts.qs +++ b/trunk/report_templates/SAM_UserAccounts.qs @@ -1,37 +1,64 @@ // See http://windowsir.blogspot.com/2006/08/getting-user-info-from-image.html println(""); println(" User Accounts"); println(" "); println("

User accounts

"); -println("

"); // Iterate over all user names var user_names=GetRegistryNodes("\\SAM\\Domains\\Account\\Users\\Names"); for(var i=0;i"); + // Print user name - println(user_names[i],"
"); + println(" ",user_names[i],"
"); + + println(" "); // Get user rid stored in "default" key var user_rid=GetRegistryKeyValue(String().concat("\\SAM\\Domains\\Account\\Users\\Names\\",user_names[i]),""); user_rid=RegistryKeyTypeToString(user_rid.type); - println("  RID: ",Number(user_rid).toString(10)," (",user_rid,")","
"); + println(""); // RegistryKeyTypeToString returns the rid prepended with "0x". We have to remove that for further processing user_rid=String(user_rid).substr(2); - + // Get user's V key and print various infos var v_key=GetRegistryKeyValue(String().concat("\\SAM\\Domains\\Account\\Users\\",user_rid),"V"); - // Get user's F key and print various infos var f_key=GetRegistryKeyValue(String().concat("\\SAM\\Domains\\Account\\Users\\",user_rid),"F"); - println("  Last lockout time: ",RegistryKeyValueToVariant(f_key.value,"filetime",8),"
"); - println("  Creation time: ",RegistryKeyValueToVariant(f_key.value,"filetime",24),"
"); - println("  Last login time: ",RegistryKeyValueToVariant(f_key.value,"filetime",40),"
"); + println(""); + println(""); + println(""); + println(""); + + println(""); + println(""); + + var acc_flags=Number(RegistryKeyValueToVariant(f_key.value,"uint16",56)); + print(""); + + + + + println("
RID:",Number(user_rid).toString(10)," (",user_rid,")","
Last login time:",RegistryKeyValueToVariant(f_key.value,"filetime",8),"
Last pw change:",RegistryKeyValueToVariant(f_key.value,"filetime",24),"
Last failed login:",RegistryKeyValueToVariant(f_key.value,"filetime",40),"
Account expires:",RegistryKeyValueToVariant(f_key.value,"filetime",32),"
Total logins:",RegistryKeyValueToVariant(f_key.value,"uint16",66),"
Failed logins:",RegistryKeyValueToVariant(f_key.value,"uint16",64),"
Account flags:"); + if(acc_flags&0x0001) print("Disabled "); + if(acc_flags&0x0002) print("HomeDirReq "); + if(acc_flags&0x0004) print("PwNotReq "); + if(acc_flags&0x0008) print("TempDupAcc "); + // Don't think this would be useful to show + //if(acc_flags&0x0010) print("NormUserAcc "); + if(acc_flags&0x0020) print("MnsAcc "); + if(acc_flags&0x0040) print("DomTrustAcc "); + if(acc_flags&0x0080) print("WksTrustAcc "); + if(acc_flags&0x0100) print("SrvTrustAcc "); + if(acc_flags&0x0200) print("NoPwExpiry "); + if(acc_flags&0x0400) print("AccAutoLock "); + println("
"); + - println("
"); + println("

"); } -println("

"); println("");