diff --git a/trunk/datareporter.cpp b/trunk/datareporter.cpp index cdea365..1dcbed4 100644 --- a/trunk/datareporter.cpp +++ b/trunk/datareporter.cpp @@ -1,155 +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() { 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/"); QStringList found_report_templates=report_dir. - entryList(QStringList()<<"*.js"); + entryList(QStringList()<<"*.qs"); for(i=0;i_.js) + // Extract report category and name from file 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); // 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()); - break; + return QString(); } // Read template file QTextStream in(&template_file); while(!in.atEnd()) { - report_code.append(in.readLine()); + 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()) { + 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())); - break; + return QString(); } - - if(engine.hasUncaughtException()) qDebug("Exception in processing!"); - - break; + return engine.report_content; } - return engine.report_content; + return QString(); } diff --git a/trunk/datareporterengine.cpp b/trunk/datareporterengine.cpp index 0b8808e..0fa312a 100644 --- a/trunk/datareporterengine.cpp +++ b/trunk/datareporterengine.cpp @@ -1,203 +1,360 @@ /******************************************************************************* * 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); + 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); + 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); + 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(" "); + //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(" "); + //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 - s.value=obj.property("value").toVariant().toByteArray(); + // 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(); - // TODO: Does not work!! - key_value=qscriptvalue_cast(context->argument(0)); - //key_value=context->argument(0).toVariant().toByteArray(); + // Cast ByteArray argument to QByteArray and convert + key_value=qvariant_cast(context->argument(0).data().toVariant()); ret=RegistryHive::KeyValueToString(key_value, - hive_t_REG_SZ /*context->argument(1).toInteger()*/); + 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; - qDebug("Type: %u Sring: %c", - context->argument(1).toInteger(), - ret.toAscii().constData()); + // Convert + 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 { + 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()!=2) return engine->undefinedValue(); + if(context->argumentCount()!=1) return engine->undefinedValue(); + + ret=RegistryHive::KeyTypeToString(context->argument(0).toInt32()); + + return engine->newVariant(ret); } diff --git a/trunk/datareporterengine.h b/trunk/datareporterengine.h index 2bf7ee6..fae13d8 100644 --- a/trunk/datareporterengine.h +++ b/trunk/datareporterengine.h @@ -1,68 +1,74 @@ /******************************************************************************* * 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 DATAREPORTERENGINE_H #define DATAREPORTERENGINE_H #include #include #include #include #include #include "registryhive.h" #include "qtscript_types/bytearray.h" class DataReporterEngine : public QScriptEngine { Q_OBJECT public: struct s_RegistryKeyValue { int type; int length; QByteArray value; }; RegistryHive *p_registry_hive; QString report_content; DataReporterEngine(RegistryHive *p_hive); ~DataReporterEngine(); private: ByteArray *p_type_byte_array; static QScriptValue Print(QScriptContext *context, QScriptEngine *engine); static QScriptValue PrintLn(QScriptContext *context, QScriptEngine *engine); + static QScriptValue GetRegistryNodes(QScriptContext *context, + QScriptEngine *engine); + static QScriptValue GetRegistryKeys(QScriptContext *context, + QScriptEngine *engine); static QScriptValue RegistryKeyValueToScript(QScriptEngine *engine, const s_RegistryKeyValue &s); static void RegistryKeyValueFromScript(const QScriptValue &obj, s_RegistryKeyValue &s); static QScriptValue GetRegistryKeyValue(QScriptContext *context, QScriptEngine *engine); static QScriptValue RegistryKeyValueToString(QScriptContext *context, QScriptEngine *engine); + static QScriptValue RegistryKeyValueToVariant(QScriptContext *context, + QScriptEngine *engine); static QScriptValue RegistryKeyTypeToString(QScriptContext *context, QScriptEngine *engine); }; Q_DECLARE_METATYPE(DataReporterEngine::s_RegistryKeyValue) #endif // DATAREPORTERENGINE_H diff --git a/trunk/dlgreportviewer.cpp b/trunk/dlgreportviewer.cpp index 2eeccde..6c47c63 100644 --- a/trunk/dlgreportviewer.cpp +++ b/trunk/dlgreportviewer.cpp @@ -1,50 +1,57 @@ /******************************************************************************* * 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 "dlgreportviewer.h" #include "ui_dlgreportviewer.h" #include DlgReportViewer::DlgReportViewer(QString &report_data, QWidget *p_parent) : QDialog(p_parent), ui(new Ui::DlgReportViewer) { ui->setupUi(this); + + // Set report content this->ui->WebView->setHtml(report_data); + + // Set dialog title based on report content title + QString report_title=this->ui->WebView->title(); + if(report_title.isEmpty()) this->setWindowTitle("Report Viewer"); + else this->setWindowTitle(report_title.prepend("Report Viewer : ")); } DlgReportViewer::~DlgReportViewer() { delete ui; } void DlgReportViewer::changeEvent(QEvent *e) { QDialog::changeEvent(e); switch(e->type()) { case QEvent::LanguageChange: ui->retranslateUi(this); break; default: break; } } void DlgReportViewer::on_BtnClose_clicked() { this->accept(); } diff --git a/trunk/mainwindow.cpp b/trunk/mainwindow.cpp index a02557a..4a359e6 100644 --- a/trunk/mainwindow.cpp +++ b/trunk/mainwindow.cpp @@ -1,458 +1,462 @@ /******************************************************************************* * 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 #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; // 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(); 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); - DlgReportViewer dlg_report_view(report_content,this); - dlg_report_view.exec(); + if(report_content!=QString()) { + DlgReportViewer dlg_report_view(report_content,this); + dlg_report_view.exec(); + } else { + // TODO: Something went wrong! + } } 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/qtscript_types/bytearray.cpp b/trunk/qtscript_types/bytearray.cpp index 0986ab6..e6dc920 100644 --- a/trunk/qtscript_types/bytearray.cpp +++ b/trunk/qtscript_types/bytearray.cpp @@ -1,179 +1,193 @@ /******************************************************************************* * Copyright (c) 2011 by Gillen Daniel * * * * Derived from code by Nokia Corporation and/or its subsidiary(-ies) under a * * compatible license: * * * * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). * * All rights reserved. * * * * This program is free software: you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the Free * * Software Foundation, either version 3 of the License, or (at your option) * * any later version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #include #include "bytearray.h" #include "bytearrayiterator.h" #include "bytearrayprototype.h" #include Q_DECLARE_METATYPE(QByteArray*) Q_DECLARE_METATYPE(ByteArray*) +/* static qint32 toArrayIndex(const QString &str) { QByteArray bytes = str.toUtf8(); char *eptr; quint32 pos = strtoul(bytes.constData(), &eptr, 10); if((eptr == bytes.constData() + bytes.size()) && (QByteArray::number(pos) == bytes)) { return pos; } return -1; } +*/ ByteArray::ByteArray(QScriptEngine *engine) : QObject(engine), QScriptClass(engine) { qScriptRegisterMetaType(engine, this->toScriptValue, this->fromScriptValue); - length=engine->toStringHandle(QLatin1String("length")); + this->length=engine->toStringHandle(QLatin1String("length")); this->proto=engine->newQObject(new ByteArrayPrototype(this), QScriptEngine::QtOwnership, QScriptEngine::SkipMethodsInEnumeration | QScriptEngine::ExcludeSuperClassMethods | QScriptEngine::ExcludeSuperClassProperties); QScriptValue global=engine->globalObject(); - this->proto.setPrototype(global.property("Object").property("prototype")); + proto.setPrototype(global.property("Object").property("prototype")); - this->ctor=engine->newFunction(construct); + this->ctor=engine->newFunction(this->construct,this->proto); this->ctor.setData(qScriptValueFromValue(engine,this)); } ByteArray::~ByteArray() {} QScriptClass::QueryFlags ByteArray::queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id) { QByteArray *ba=qscriptvalue_cast(object.data()); if(!ba) return 0; - if(name!=length) { - qint32 pos=toArrayIndex(name); - if(pos==-1) return 0; + if(name!=this->length) { + bool is_array_index; + qint32 pos=name.toArrayIndex(&is_array_index); + if(!is_array_index) return 0; *id=pos; if((flags & HandlesReadAccess) && (pos>=ba->size())) flags &= ~HandlesReadAccess; } return flags; } QScriptValue ByteArray::property(const QScriptValue &object, const QScriptString &name, uint id) { QByteArray *ba=qscriptvalue_cast(object.data()); if(!ba) return QScriptValue(); if(name==length) return ba->length(); else { qint32 pos=id; if((pos < 0) || (pos >= ba->size())) return QScriptValue(); return uint(ba->at(pos)) & 255; } return QScriptValue(); } void ByteArray::setProperty(QScriptValue &object, const QScriptString &name, uint id, const QScriptValue &value) { QByteArray *ba=qscriptvalue_cast(object.data()); if(!ba) return; - if(name==length) ba->resize(value.toInt32()); + if(name==length) this->resize(*ba,value.toInt32()); else { qint32 pos=id; if(pos<0) return; - if(ba->size()<=pos) ba->resize(pos + 1); + if(ba->size()<=pos) this->resize(*ba,pos + 1); (*ba)[pos]=char(value.toInt32()); } } QScriptValue::PropertyFlags ByteArray::propertyFlags(const QScriptValue &object, const QScriptString &name, uint id) { Q_UNUSED(object); Q_UNUSED(id); if(name==length) { return QScriptValue::Undeletable | QScriptValue::SkipInEnumeration; } return QScriptValue::Undeletable; } QScriptClassPropertyIterator *ByteArray::newIterator(const QScriptValue &object) { return new ByteArrayIterator(object); } QString ByteArray::name() const { return QLatin1String("ByteArray"); } QScriptValue ByteArray::prototype() const { - return this->proto; + return proto; } QScriptValue ByteArray::constructor() { - return this->ctor; + return ctor; } QScriptValue ByteArray::newInstance(int size) { + this->engine()->reportAdditionalMemoryCost(size); return newInstance(QByteArray(size,0)); } QScriptValue ByteArray::newInstance(const QByteArray &ba) { QScriptValue data=engine()->newVariant(qVariantFromValue(ba)); return engine()->newObject(this,data); } QScriptValue ByteArray::construct(QScriptContext *ctx, QScriptEngine *) { ByteArray *cls=qscriptvalue_cast(ctx->callee().data()); if(!cls) return QScriptValue(); - int size=ctx->argument(0).toInt32(); + QScriptValue arg=ctx->argument(0); + if(arg.instanceOf(ctx->callee())) + return cls->newInstance(qscriptvalue_cast(arg)); + int size=arg.toInt32(); return cls->newInstance(size); } QScriptValue ByteArray::toScriptValue(QScriptEngine *eng, const QByteArray &ba) { QScriptValue ctor=eng->globalObject().property("ByteArray"); ByteArray *cls=qscriptvalue_cast(ctor.data()); if(!cls) return eng->newVariant(qVariantFromValue(ba)); return cls->newInstance(ba); } void ByteArray::fromScriptValue(const QScriptValue &obj, QByteArray &ba) { - ba=qscriptvalue_cast(obj.data()); + ba=qvariant_cast(obj.data().toVariant()); } + +void ByteArray::resize(QByteArray &ba, int newSize) { + int oldSize=ba.size(); + ba.resize(newSize); + if(newSize>oldSize) + this->engine()->reportAdditionalMemoryCost(newSize-oldSize); + } diff --git a/trunk/qtscript_types/bytearray.h b/trunk/qtscript_types/bytearray.h index 56f859c..154f577 100644 --- a/trunk/qtscript_types/bytearray.h +++ b/trunk/qtscript_types/bytearray.h @@ -1,74 +1,76 @@ /******************************************************************************* * Copyright (c) 2011 by Gillen Daniel * * * * Derived from code by Nokia Corporation and/or its subsidiary(-ies) under a * * compatible license: * * * * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). * * All rights reserved. * * * * This program is free software: you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the Free * * Software Foundation, either version 3 of the License, or (at your option) * * any later version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ // Description: http://cs.karelia.ru/~aborod/doc/qt/script-customclass.html #ifndef BYTEARRAY_H #define BYTEARRAY_H #include #include #include class ByteArray : public QObject, public QScriptClass { public: ByteArray(QScriptEngine *engine); ~ByteArray(); QScriptValue constructor(); QScriptValue newInstance(int size = 0); QScriptValue newInstance(const QByteArray &ba); QueryFlags queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id); QScriptValue property(const QScriptValue &object, const QScriptString &name, uint id); void setProperty(QScriptValue &object, const QScriptString &name, uint id, const QScriptValue &value); QScriptValue::PropertyFlags propertyFlags(const QScriptValue &object, const QScriptString &name, uint id); QScriptClassPropertyIterator *newIterator(const QScriptValue &object); QString name() const; QScriptValue prototype() const; private: static QScriptValue construct(QScriptContext *ctx, QScriptEngine *eng); static QScriptValue toScriptValue(QScriptEngine *eng, const QByteArray &ba); static void fromScriptValue(const QScriptValue &obj, QByteArray &ba); + void resize(QByteArray &ba, int newSize); + QScriptString length; QScriptValue proto; QScriptValue ctor; }; #endif // BYTEARRAY_H diff --git a/trunk/qtscript_types/bytearrayiterator.cpp b/trunk/qtscript_types/bytearrayiterator.cpp index 8ef3069..920f699 100644 --- a/trunk/qtscript_types/bytearrayiterator.cpp +++ b/trunk/qtscript_types/bytearrayiterator.cpp @@ -1,74 +1,74 @@ /******************************************************************************* * Copyright (c) 2011 by Gillen Daniel * * * * Derived from code by Nokia Corporation and/or its subsidiary(-ies) under a * * compatible license: * * * * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). * * All rights reserved. * * * * This program is free software: you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the Free * * Software Foundation, either version 3 of the License, or (at your option) * * any later version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #include "bytearrayiterator.h" #include Q_DECLARE_METATYPE(QByteArray*) ByteArrayIterator::ByteArrayIterator(const QScriptValue &object) : QScriptClassPropertyIterator(object) { toFront(); } ByteArrayIterator::~ByteArrayIterator() {} bool ByteArrayIterator::hasNext() const { QByteArray *ba=qscriptvalue_cast(object().data()); return m_indexsize(); } void ByteArrayIterator::next() { m_last=m_index; ++m_index; } bool ByteArrayIterator::hasPrevious() const { return(m_index>0); } void ByteArrayIterator::previous() { --m_index; m_last=m_index; } void ByteArrayIterator::toFront() { m_index=0; m_last=-1; } void ByteArrayIterator::toBack() { QByteArray *ba=qscriptvalue_cast(object().data()); m_index=ba->size(); m_last=-1; } QScriptString ByteArrayIterator::name() const { - return QScriptString(); + return this->object().engine()->toStringHandle(QString::number(this->m_last)); } uint ByteArrayIterator::id() const { return m_last; } diff --git a/trunk/report_templates/SAM_UserAccounts.qs b/trunk/report_templates/SAM_UserAccounts.qs new file mode 100644 index 0000000..c66852d --- /dev/null +++ b/trunk/report_templates/SAM_UserAccounts.qs @@ -0,0 +1,37 @@ +// 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"); + + // 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,")","
"); + + // 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(""); diff --git a/trunk/report_templates/SOFTWARE_WindowsVersion.js b/trunk/report_templates/SOFTWARE_WindowsVersion.js deleted file mode 100644 index 503f80c..0000000 --- a/trunk/report_templates/SOFTWARE_WindowsVersion.js +++ /dev/null @@ -1,18 +0,0 @@ -println(""); -println(" Windows version info"); -println(" "); -println("

Windows version info

"); -println("

"); - -var val=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion","ProductName"); - -print("ProductVersion: "); -println(RegistryHive.KeyValueToString(val.value,1)); - -println("

"); -println(""); - -//for(var i=0;i<(val.length-1);i+=2) { -// print(String.fromCharCode(val.value[i])); -//} - diff --git a/trunk/report_templates/SOFTWARE_WindowsVersion.qs b/trunk/report_templates/SOFTWARE_WindowsVersion.qs new file mode 100644 index 0000000..ec564a9 --- /dev/null +++ b/trunk/report_templates/SOFTWARE_WindowsVersion.qs @@ -0,0 +1,22 @@ +println(""); +println(" Windows version info"); +println(" "); +println("

Windows version info

"); +println("

"); + +// Windows version +var val=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion","ProductName"); +println("Windows version: ",RegistryKeyValueToString(val.value,1),"
"); + +// Install date +var val=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion","InstallDate"); +println("Install date: ",RegistryKeyValueToVariant(val.value,"unixtime"),"
"); + +// Owner and Organization info +var val=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion","RegisteredOwner"); +println("Registered owner: ",RegistryKeyValueToString(val.value,1),"
"); +var val=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion","RegisteredOrganization"); +println("Registered organization: ",RegistryKeyValueToString(val.value,1),"
"); + +println("

"); +println("");