Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F4823567
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Size
51 KB
Referenced Files
None
Subscribers
None
View Options
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 <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 "datareporter.h"
#include <QDir>
#include <QTextStream>
#include <QtScript/QScriptEngine>
#include <QMessageBox>
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<found_report_templates.count();i++) {
// Build complete path to template file
report_template=report_dir.path();
report_template.append(QDir::separator());
report_template.append(found_report_templates.value(i));
// Extract report category and name from file name (<category>_<name>.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;i<this->report_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;i<this->report_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;i<this->report_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 <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 DATAREPORTER_H
#define DATAREPORTER_H
#include <QList>
#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<ReportTemplate*> 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 <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 "datareporterengine.h"
#include <QString>
#include <QMap>
#include <QMapIterator>
#include <QStringList>
#include <QDateTime>
DataReporterEngine::DataReporterEngine(RegistryHive *p_hive) : QScriptEngine() {
// Init vars
this->p_registry_hive=p_hive;
this->report_content="";
// Add our types to engine
qScriptRegisterMetaType<s_RegistryKeyValue>(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;i<context->argumentCount();++i) {
//if(i>0) content.append(" ");
content.append(context->argument(i).toString());
}
//QScriptValue calleeData=context->callee().data();
//DataReporterEngine *engine=
// qobject_cast<DataReporterEngine*>(calleeData.toQObject());
qobject_cast<DataReporterEngine*>(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;i<context->argumentCount();++i) {
//if(i>0) content.append(" ");
content.append(context->argument(i).toString());
}
qobject_cast<DataReporterEngine*>(engine)->
report_content.append(content).append("\n");
return engine->undefinedValue();
}
/*
* GetRegistryNodes
*/
QScriptValue DataReporterEngine::GetRegistryNodes(QScriptContext *context,
QScriptEngine *engine)
{
QScriptValue calleeData;
RegistryHive *p_hive;
QMap<QString,int> 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<RegistryHive*>(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<QString,int> 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<QString,int> 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<RegistryHive*>(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<QString,int> 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<QByteArray>(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<RegistryHive*>(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<QByteArray>(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<QByteArray>(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 <gillen.dan@pinguin.lu> 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 <gillen.dan@pinguin.lu> Tue, 09 Aug 2011 17:00:00 +0200
fred (0.1.0alpha1) unstable; urgency=low
* First public release
-- Daniel Gillen <gillen.dan@pinguin.lu> 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 <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
+ #define FRED_REPORT_TEMPLATE_DIR "/usr/share/fred/report_templates/"
+#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 "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;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()));
}
}
}
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 <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 <hivex.h>
#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("<html>");
println(" <head><title>User Accounts</title></head>");
println(" <body>");
println(" <h2>User accounts</h2>");
-println(" <p>");
// Iterate over all user names
var user_names=GetRegistryNodes("\\SAM\\Domains\\Account\\Users\\Names");
for(var i=0;i<user_names.length;i++) {
+ println(" <p>");
+
// Print user name
- println(user_names[i],"<br />");
+ println(" ",user_names[i],"<br />");
+
+ println(" <table style=\"margin-left:20px\">");
// 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,")","<br />");
+ println("<tr><td>RID:</td><td>",Number(user_rid).toString(10)," (",user_rid,")","</td></td>");
// 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),"<br />");
- println(" Creation time: ",RegistryKeyValueToVariant(f_key.value,"filetime",24),"<br />");
- println(" Last login time: ",RegistryKeyValueToVariant(f_key.value,"filetime",40),"<br />");
+ println("<tr><td>Last login time:</td><td>",RegistryKeyValueToVariant(f_key.value,"filetime",8),"</td></td>");
+ println("<tr><td>Last pw change:</td><td>",RegistryKeyValueToVariant(f_key.value,"filetime",24),"</td></td>");
+ println("<tr><td>Last failed login:</td><td>",RegistryKeyValueToVariant(f_key.value,"filetime",40),"</td></td>");
+ println("<tr><td>Account expires:</td><td>",RegistryKeyValueToVariant(f_key.value,"filetime",32),"</td></td>");
+
+ println("<tr><td>Total logins:</td><td>",RegistryKeyValueToVariant(f_key.value,"uint16",66),"</td></td>");
+ println("<tr><td>Failed logins:</td><td>",RegistryKeyValueToVariant(f_key.value,"uint16",64),"</td></td>");
+
+ var acc_flags=Number(RegistryKeyValueToVariant(f_key.value,"uint16",56));
+ print("<tr><td>Account flags:</td><td>");
+ 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("</td></td>");
+
+
+
+
+ println(" </table>");
+
- println("<br />");
+ println(" </p>");
}
-println(" </p>");
println("</html>");
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, May 11, 6:34 AM (1 d, 15 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1247634
Default Alt Text
(51 KB)
Attached To
Mode
rFRED fred
Attached
Detach File
Event Timeline
Log In to Comment