Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F4324492
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Size
181 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/trunk/debian/changelog b/trunk/debian/changelog
index e56d0f7..4e11672 100644
--- a/trunk/debian/changelog
+++ b/trunk/debian/changelog
@@ -1,50 +1,50 @@
-fred (0.1.0) stable; urgency=low
+fred (0.1.0beta5) stable; urgency=low
fred (0.1.0beta4) unstable; urgency=low
* Fixed some minor UI bugs
* Massive code cleanup in mainwindow.cpp
* Added ability to switch data interpreter's endianness
* Added ability in hex editor to select and copy selected bytes / text
-- Daniel Gillen <gillen.dan@pinguin.lu> Mon, 25 Jun 2012 00:00:00 +0200
fred (0.1.0beta3) unstable; urgency=low
* Added search functionality
* Added various context menus to copy values to clipboard
* Now linking statically against libhivex to support older Debian / Ubuntu distros
* Some small fixes to ease portability
-- Daniel Gillen <gillen.dan@pinguin.lu> Sun, 04 Sep 2011 00:15:00 +0200
fred (0.1.0beta2) unstable; urgency=low
* Fixed some more bugs and subclassed QTreeView and QTableView
-- Daniel Gillen <gillen.dan@pinguin.lu> Tue, 23 Aug 2011 17:00:00 +0200
fred (0.1.0beta1) unstable; urgency=low
* Fixed some minor bugs and added more report templates
-- Daniel Gillen <gillen.dan@pinguin.lu> Mon, 22 Aug 2011 08:00:00 +0200
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 window.
* 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/dlgaddkey.cpp b/trunk/dlgaddkey.cpp
index 81253ad..f2a41d2 100644
--- a/trunk/dlgaddkey.cpp
+++ b/trunk/dlgaddkey.cpp
@@ -1,382 +1,379 @@
/*******************************************************************************
* fred Copyright (c) 2011-2013 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 <QString>
#include <QStringList>
#include <QMessageBox>
#include <QRegExp>
#include <stdlib.h>
#include <QDebug>
#include "dlgaddkey.h"
#include "ui_dlgaddkey.h"
#include "registryhive.h"
#define MACROS_ENDIANNESS
#include "macros.h"
DlgAddKey::DlgAddKey(QWidget *p_parent,
QString key_name,
QString key_value_type,
QByteArray key_value) :
QDialog(p_parent),
ui(new Ui::DlgAddKey)
{
this->p_current_widget=NULL;
ui->setupUi(this);
+ this->ansi_encoded=false;
// Create widgets
this->CreateValueWidgets();
// Set dialog title
if(key_name.isEmpty() && key_value_type.isEmpty() && key_value.isEmpty()) {
// If no values were passed, we consider this the ddd key dialog
this->setWindowTitle(tr("Add key"));
} else {
// If a value was passed, this is considered the edit key dialog
this->setWindowTitle(tr("Edit key"));
this->ui->EdtKeyName->setEnabled(false);
this->ui->CmbKeyType->setEnabled(false);
}
// Preload key value type values
QStringList value_types=RegistryHive::GetKeyValueTypes();
this->ui->CmbKeyType->addItems(value_types);
// Load values
if(!key_name.isEmpty()) this->ui->EdtKeyName->setText(key_name);
if(!key_value_type.isEmpty())
this->ui->CmbKeyType->setCurrentIndex(value_types.indexOf(key_value_type));
if(!key_value.isEmpty()) this->SetValueWidgetData(key_value,key_value_type);
}
DlgAddKey::~DlgAddKey() {
this->DestroyValueWidgets();
delete ui;
}
QString DlgAddKey::KeyName() {
return this->ui->EdtKeyName->text();
}
QString DlgAddKey::KeyType() {
return this->ui->CmbKeyType->currentText();
}
QByteArray DlgAddKey::KeyValue() {
return this->GetValueWidgetData();
}
void DlgAddKey::on_BtnCancel_clicked() {
this->reject();
}
void DlgAddKey::on_BtnOk_clicked() {
QString key_value_type=this->KeyType();
// Check entered data for correctness
if(key_value_type=="REG_MULTI_SZ") {
// REG_MULTI_SZ's can't contain empty sub-strings
QString cur_data=this->p_text_widget_text_edit->toPlainText();
QString new_data=cur_data;
// TODO: Do we need to check for \r\n on Windows??
new_data.replace(QRegExp("\n\n*"),"\n");
if(new_data.startsWith("\n")) new_data.remove(0,1);
if(new_data.endsWith("\n")) new_data.chop(1);
if(cur_data!=new_data) {
if(QMessageBox::information(this,
tr("Invalid data"),
- tr("A REG_MULTI_SZ can not contain empty sub-strings! If you continue, they will be removed."),
+ tr("A REG_MULTI_SZ can not contain empty "
+ "sub-strings! If you continue, they "
+ "will be removed."),
QMessageBox::Yes,
QMessageBox::No)==QMessageBox::Yes)
{
this->p_text_widget_text_edit->setPlainText(new_data);
} else {
return;
}
}
} else if(key_value_type=="REG_DWORD" ||
key_value_type=="REG_DWORD_BIG_ENDIAN")
{
bool ok=false;
if(this->p_number_widget_rb_decimal->isChecked()) {
this->p_number_widget_line_edit->text().toInt(&ok);
} else {
// TODO: There seems to be a problem with 0xFFFFFFFF
this->p_number_widget_line_edit->text().toInt(&ok,16);
}
if(!ok) {
QMessageBox::information(this,
tr("Invalid data"),
- tr("The value you entered could not be converted to a %1! Please correct it.").arg(key_value_type),
+ tr("The value you entered could not be "
+ "converted to a %1! Please correct it.")
+ .arg(key_value_type),
QMessageBox::Ok);
return;
}
} else if(key_value_type=="REG_QWORD") {
bool ok=false;
if(this->p_number_widget_rb_decimal->isChecked()) {
this->p_number_widget_line_edit->text().toLongLong(&ok);
} else {
this->p_number_widget_line_edit->text().toLongLong(&ok,16);
}
if(!ok) {
QMessageBox::information(this,
tr("Invalid data"),
- tr("The value you entered could not be converted to a %1! Please correct it.").arg(key_value_type),
+ tr("The value you entered could not be "
+ "converted to a %1! Please correct it.")
+ .arg(key_value_type),
QMessageBox::Ok);
return;
}
}
this->accept();
}
void DlgAddKey::on_CmbKeyType_currentIndexChanged(const QString &arg1) {
// Remove current widget from grid layout
if(this->p_current_widget!=NULL) {
this->ui->gridLayout->removeWidget(this->p_current_widget);
this->p_current_widget->setVisible(false);
this->p_current_widget=NULL;
}
// Add new widget for selected value type
if(arg1=="REG_SZ" || arg1=="REG_EXPAND_SZ") {
// Line edit widget for REG_SZ and REG_EXPAND_SZ
this->ui->gridLayout->addWidget(this->p_line_widget,2,1);
this->p_current_widget=this->p_line_widget;
} else if(arg1=="REG_MULTI_SZ") {
// Text edit widget for REG_MULTI_SZ
this->ui->gridLayout->addWidget(this->p_text_widget,2,1);
this->p_current_widget=this->p_text_widget;
} else if(arg1=="REG_DWORD" ||
arg1=="REG_DWORD_BIG_ENDIAN" ||
arg1=="REG_QWORD")
{
// Number widget for REG_DWORD, REG_DWORD_BIG_ENDIAN and REG_QWORD
this->ui->gridLayout->addWidget(this->p_number_widget,2,1);
this->p_current_widget=this->p_number_widget;
} else if(arg1=="REG_BINARY" ||
arg1=="REG_LINK" ||
arg1=="REG_RESOURCE_LIST" ||
arg1=="REG_FULL_RESOURCE_DESC" ||
arg1=="REG_RESOURCE_REQ_LIST")
{
// Binary widget for all other types
this->ui->gridLayout->addWidget(this->p_binary_widget,2,1);
this->p_current_widget=this->p_binary_widget;
}
if(arg1!="REG_NONE") {
this->p_current_widget->setVisible(true);
this->ui->LblKeyValue->setVisible(true);
} else {
this->ui->LblKeyValue->setVisible(false);
}
}
void DlgAddKey::CreateValueWidgets() {
this->p_line_widget=new QWidget();
this->p_line_widget_layout=new QHBoxLayout(this->p_line_widget);
+ //this->p_line_widget_layout_rb_ansi=new QRadioButton(tr("Ansi"));
+ //this->p_line_widget_layout_rb_unicode=new QRadioButton(tr("Unicode"));
+ //this->p_line_widget_layout_rb_unicode->setChecked(true);
this->p_line_widget_line_edit=new QLineEdit();
this->p_line_widget->setContentsMargins(0,0,0,0);
this->p_line_widget_layout->setContentsMargins(0,0,0,0);
this->p_line_widget_layout->addWidget(this->p_line_widget_line_edit);
+ //this->p_line_widget_layout->addWidget(this->p_line_widget_layout_rb_ansi);
+ //this->p_line_widget_layout->addWidget(this->p_line_widget_layout_rb_unicode);
this->p_text_widget=new QWidget();
this->p_text_widget_layout=new QHBoxLayout(this->p_text_widget);
this->p_text_widget_text_edit=new QPlainTextEdit();
this->p_text_widget->setContentsMargins(0,0,0,0);
this->p_text_widget_layout->setContentsMargins(0,0,0,0);
this->p_text_widget_layout->addWidget(this->p_text_widget_text_edit);
this->p_number_widget=new QWidget();
this->p_number_widget_layout=new QHBoxLayout(this->p_number_widget);
this->p_number_widget_line_edit=new QLineEdit();
this->p_number_widget_rb_decimal=new QRadioButton(tr("Dec base"));
this->p_number_widget_rb_decimal->setChecked(true);
this->p_number_widget_rb_hex=new QRadioButton(tr("Hex base"));
this->p_number_widget->setContentsMargins(0,0,0,0);
this->p_number_widget_layout->setContentsMargins(0,0,0,0);
this->p_number_widget_layout->addWidget(this->p_number_widget_line_edit);
this->p_number_widget_layout->addWidget(this->p_number_widget_rb_decimal);
this->p_number_widget_layout->addWidget(this->p_number_widget_rb_hex);
this->p_binary_widget=new QWidget();
this->p_binary_widget_layout=new QHBoxLayout(this->p_binary_widget);
this->p_binary_widget_hex_edit=new HexEditWidget(this,false,false);
this->p_binary_widget->setContentsMargins(0,0,0,0);
this->p_binary_widget_layout->setContentsMargins(0,0,0,0);
this->p_binary_widget_layout->addWidget(this->p_binary_widget_hex_edit);
}
void DlgAddKey::DestroyValueWidgets() {
+ //delete this->p_line_widget_layout_rb_ansi;
+ //delete this->p_line_widget_layout_rb_unicode;
delete this->p_line_widget_line_edit;
delete this->p_line_widget_layout;
delete this->p_line_widget;
delete this->p_text_widget_text_edit;
delete this->p_text_widget_layout;
delete this->p_text_widget;
delete this->p_number_widget_rb_hex;
delete this->p_number_widget_rb_decimal;
delete this->p_number_widget_line_edit;
delete this->p_number_widget_layout;
delete this->p_number_widget;
delete this->p_binary_widget_hex_edit;
delete this->p_binary_widget_layout;
delete this->p_binary_widget;
}
void DlgAddKey::SetValueWidgetData(QByteArray &key_value,
QString &key_value_type)
{
if(key_value_type=="REG_SZ" || key_value_type=="REG_EXPAND_SZ") {
this->p_line_widget_line_edit->setText(
RegistryHive::KeyValueToString(key_value,
RegistryHive::StringToKeyValueType(
key_value_type)));
} else if(key_value_type=="REG_MULTI_SZ") {
- // TODO: Switch to RegistryHive::KeyValueStringList
- // TODO: Identify if this is UTF16 or UTF8 and remember it
- QStringList strings=RegistryHive::KeyValueToStringList(key_value);
+ QStringList strings=
+ RegistryHive::KeyValueToStringList(key_value,&(this->ansi_encoded));
this->p_text_widget_text_edit->setPlainText(strings.join("\n"));
} else if(key_value_type=="REG_DWORD") {
this->p_number_widget_line_edit->setText(
RegistryHive::KeyValueToString(key_value,"int32"));
} else if(key_value_type=="REG_DWORD_BIG_ENDIAN") {
this->p_number_widget_line_edit->setText(
RegistryHive::KeyValueToString(key_value,"int32",0,0,false));
} else if(key_value_type=="REG_QWORD") {
this->p_number_widget_line_edit->setText(
RegistryHive::KeyValueToString(key_value,"int64",0,0,false));
} else if(key_value_type=="REG_BINARY" ||
key_value_type=="REG_LINK" ||
key_value_type=="REG_RESOURCE_LIST" ||
key_value_type=="REG_FULL_RESOURCE_DESC" ||
key_value_type=="REG_RESOURCE_REQ_LIST")
{
this->p_binary_widget_hex_edit->SetData(key_value);
}
}
QByteArray DlgAddKey::GetValueWidgetData() {
QString key_value_type=this->KeyType();
if(key_value_type=="REG_SZ" || key_value_type=="REG_EXPAND_SZ") {
// TODO: Wouldn't it be wise to let the user choose the encoding?
// Get data
QString data=this->p_line_widget_line_edit->text();
// Convert data to UTF16LE buffer
uint16_t *p_buf=NULL;
int buf_len=this->ToUtf16LeBuf(&p_buf,data.utf16(),data.size());
if(p_buf==NULL || buf_len==0) {
// TODO: Inform user there was an error???
return QByteArray("\x00\x00",2);
}
// Construct ByteArray, free buffer and return
QByteArray ret=QByteArray((char*)p_buf,buf_len);
free(p_buf);
return ret;
} else if(key_value_type=="REG_MULTI_SZ") {
- // TODO: Switch to RegistryHive::StringListToKeyValue
- // TODO: Wouldn't it be wise to let the user choose the encoding?
- // TODO: When editing, use same encoding as original data
- QString data=this->p_text_widget_text_edit->toPlainText();
- // Convert data to UTF16LE buffer
- uint16_t *p_buf=NULL;
- int buf_len=this->ToUtf16LeBuf(&p_buf,data.utf16(),data.size());
- if(p_buf==NULL || buf_len==0) {
- // TODO: Inform user there was an error???
- return QByteArray("\x00\x00\x00\x00",4);
- }
- // Replace \n in buffer with \0 which actually converts it to a
- // semi REG_MULTI_SZ :-)
+ // TODO: Let the user choose the encoding / endianness
// TODO: Do we need to check for \r\n on Windows??
- for(int i=0;i<buf_len;i++) {
- if(LE32TOH(p_buf[i])==10) p_buf[i]=0;
- }
- // Construct ByteArray
- QByteArray ret=QByteArray((char*)p_buf,buf_len);
- // Append \0\0 to the end to make a real REG_MULTI_SZ
- ret.append("\x00\x00",2);
- // Free buffer and return
- free(p_buf);
- return ret;
+ return RegistryHive::StringListToKeyValue(
+ this->p_text_widget_text_edit->
+ toPlainText().split("\n",
+ QString::SkipEmptyParts),
+ true,
+ this->ansi_encoded);
} else if(key_value_type=="REG_DWORD" ||
key_value_type=="REG_DWORD_BIG_ENDIAN")
{
int32_t val;
if(this->p_number_widget_rb_decimal->isChecked()) {
val=this->p_number_widget_line_edit->text().toInt();
} else {
val=this->p_number_widget_line_edit->text().toInt(0,16);
}
if(key_value_type=="REG_DWORD") val=HTOLE32(val);
else val=HTOBE32(val);
return QByteArray((char*)&val,4);
} else if(key_value_type=="REG_QWORD") {
int64_t val;
if(this->p_number_widget_rb_decimal->isChecked()) {
val=this->p_number_widget_line_edit->text().toLongLong();
} else {
val=this->p_number_widget_line_edit->text().toLongLong(0,16);
}
val=HTOLE64(val);
return QByteArray((char*)&val,8);
} else if(key_value_type=="REG_BINARY" ||
key_value_type=="REG_LINK" ||
key_value_type=="REG_RESOURCE_LIST" ||
key_value_type=="REG_FULL_RESOURCE_DESC" ||
key_value_type=="REG_RESOURCE_REQ_LIST")
{
return this->p_binary_widget_hex_edit->GetData();
}
return QByteArray();
}
int DlgAddKey::ToUtf16LeBuf(uint16_t **pp_buf,
const uint16_t *p_data,
int ascii_len)
{
// Calculate utf16 buffer size
// TODO: This fails if there are chars that need more than 16bit!!
int buf_len=(ascii_len*2)+2;
// Alloc buffer and set to 0x00h
*pp_buf=(uint16_t*)malloc(buf_len);
if(*pp_buf==NULL) return 0;
memset(*pp_buf,0,buf_len);
if(ascii_len==0) {
// Empty string, we're done (buffer contains \0\0)
return buf_len;
}
// Fill buffer with UTF16 string (ignoring \0\0 at the end)
memcpy(*pp_buf,p_data,buf_len-2);
// Make sure endianness is LE
for(int i=0;i<ascii_len;i++) {
(*pp_buf)[i]=HTOLE16((*pp_buf)[i]);
}
return buf_len;
}
diff --git a/trunk/dlgaddkey.h b/trunk/dlgaddkey.h
index 136fad8..d7e7ac8 100644
--- a/trunk/dlgaddkey.h
+++ b/trunk/dlgaddkey.h
@@ -1,83 +1,86 @@
/*******************************************************************************
* fred Copyright (c) 2011-2013 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 DLGADDKEY_H
#define DLGADDKEY_H
#include <QDialog>
#include <QWidget>
#include <QHBoxLayout>
#include <QLineEdit>
#include <QPlainTextEdit>
#include <QRadioButton>
#include <inttypes.h>
#include "hexeditwidget.h"
namespace Ui {
class DlgAddKey;
}
class DlgAddKey : public QDialog {
Q_OBJECT
public:
explicit DlgAddKey(QWidget *p_parent=0,
QString key_name=QString(),
QString key_value_type=QString(),
QByteArray key_value=QByteArray());
~DlgAddKey();
QString KeyName();
QString KeyType();
QByteArray KeyValue();
private slots:
void on_BtnCancel_clicked();
void on_BtnOk_clicked();
void on_CmbKeyType_currentIndexChanged(const QString &arg1);
private:
Ui::DlgAddKey *ui;
QWidget *p_current_widget;
QWidget *p_line_widget;
QHBoxLayout *p_line_widget_layout;
+ //QRadioButton *p_line_widget_layout_rb_ansi;
+ //QRadioButton *p_line_widget_layout_rb_unicode;
QLineEdit *p_line_widget_line_edit;
QWidget *p_text_widget;
QHBoxLayout *p_text_widget_layout;
QPlainTextEdit *p_text_widget_text_edit;
QWidget *p_number_widget;
QHBoxLayout *p_number_widget_layout;
QLineEdit *p_number_widget_line_edit;
QRadioButton *p_number_widget_rb_decimal;
QRadioButton *p_number_widget_rb_hex;
QWidget *p_binary_widget;
QHBoxLayout *p_binary_widget_layout;
HexEditWidget *p_binary_widget_hex_edit;
+ bool ansi_encoded;
void CreateValueWidgets();
void DestroyValueWidgets();
void SetValueWidgetData(QByteArray &key_value, QString &key_value_type);
QByteArray GetValueWidgetData();
int ToUtf16LeBuf(uint16_t **pp_buf,const uint16_t *p_data, int ascii_len);
};
#endif // DLGADDKEY_H
diff --git a/trunk/macros.h b/trunk/macros.h
index 64902a7..681c425 100644
--- a/trunk/macros.h
+++ b/trunk/macros.h
@@ -1,263 +1,288 @@
/*******************************************************************************
* Copyright (c) 2011 by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* This file contains macros with some very often used code pieces. It should *
* primarily make my everyday life easier and improve code portability. *
* *
* 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/>. *
*******************************************************************************/
// Available macro groups:
//
// MACROS_FILE, MACROS_STRING, MACROS_WSTRING, MACROS_ENDIANNESS, MACROS_MUTEX,
// MACROS_MEMORY, MACROS_LOGGING
//
// Define one or more of these before including this file to make them available
#ifndef MACROS_H
#define MACROS_H
/*
* Macros for file access
*/
#ifdef MACROS_FILE
#include <stdio.h>
#undef FOPEN
#ifndef __APPLE__
#define FOPEN (FILE*)fopen64
#else
// Apple always uses fopen
#define FOPEN (FILE*)fopen
#endif // __APPLE__
#undef FCLOSE
#define FCLOSE(var,err_ret) { \
if(fclose(var)!=0) { \
LOG_ERROR("Couldn't close file!") \
err_ret; \
} \
}
#undef FSEEK
#define FSEEK(hfile,off,whence,err_ret) { \
if(fseeko(hfile,off,whence)!=0) { \
LOG_ERROR("Couldn't seek to offset %u!",off); \
err_ret; \
} \
}
#undef FTELL
#define FTELL(hfile,var,err_ret) { \
if((var=ftello(hfile))==-1) { \
LOG_ERROR("Unable to get file position!"); \
err_ret; \
} \
}
#undef FTELLSIZE
#define FTELLSIZE(hfile,var,err_ret) { \
FSEEK(hfile,0,SEEK_END,err_ret); \
FTELL(hfile,var,err_ret); \
rewind(hfile); \
}
#endif
/*
* Macros for string functions
*
* Will also include MACROS_MEMORY and MACROS_LOGGING
*/
#ifdef MACROS_STRING
#include <string.h>
// These macros rely partly on memory macros, so those are needed too
#define MACROS_MEMORY
#undef STRSET
#define STRSET(dst,src,err_ret) { \
MALLOC(dst,char*,(strlen(src)+1)*sizeof(char),err_ret) \
strcpy(dst,src); \
}
#undef STRNSET
#define STRNSET(dst,src,size,err_ret) { \
MALLOC(dst,char*,((size)+1)*sizeof(char),err_ret) \
strncpy(dst,src,size); \
(dst)[size]='\0'; \
}
#undef STRAPP
#define STRAPP(var1,var2,err_ret) { \
REALLOC(var1,char*,(strlen(var1)+strlen(var2)+1)*sizeof(char),err_ret) \
strcpy((var1)+strlen(var1),var2); \
}
#undef STRNAPP
#define STRNAPP(var1,var2,size,err_ret) { \
REALLOC(var1,char*,(strlen(var1)+(size)+1)*sizeof(char),err_ret) \
(var1)[strlen(var1)+(size)]='\0'; \
strncpy((var1)+strlen(var1),var2,size); \
}
#endif
/*
* Macros for wide string functions
*
* Will also include MACROS_MEMORY and MACROS_LOGGING
*/
#ifdef MACROS_WSTRING
#include <string.h>
// These macros rely partly on memory macros, so those are needed too
#define MACROS_MEMORY
#undef WSTRSET
#define WSTRSET(dst,src,err_ret) { \
MALLOC(dst,wchar_t*,(wcslen(src)+1)*sizeof(wchar_t),err_ret) \
wcscpy(dst,src); \
}
#undef WSTRNSET
#define WSTRNSET(dst,src,size,err_ret) { \
MALLOC(dst,wchar_t*,((size)+1)*sizeof(wchar_t),err_ret) \
wcsncpy(dst,src,size); \
(dst)[size]=L'\0'; \
}
#endif
/*
* Macros for endianness conversion
*/
#ifdef MACROS_ENDIANNESS
+ #include <inttypes.h>
#include <endian.h>
#undef LE16TOH
#define LE16TOH(var) le16toh(var)
#undef BE16TOH
#define BE16TOH(var) be16toh(var)
#undef LE32TOH
#define LE32TOH(var) le32toh(var)
#undef BE32TOH
#define BE32TOH(var) be32toh(var)
#undef LE64TOH
#define LE64TOH(var) le64toh(var)
#undef BE64TOH
#define BE64TOH(var) be64toh(var)
#undef HTOLE16
#define HTOLE16(var) htole16(var)
#undef HTOBE16
#define HTOBE16(var) htobe16(var)
#undef HTOLE32
#define HTOLE32(var) htole32(var)
#undef HTOBE32
#define HTOBE32(var) htobe32(var)
#undef HTOLE64
#define HTOLE64(var) htole64(var)
#undef HTOBE64
#define HTOBE64(var) htobe64(var)
+ #undef UTF16LETOH
+ #define UTF16LETOH(buf,buf_len) { \
+ for(int buf_off=0;buf_off<((buf_len)-1);buf_off+=2) { \
+ *((uint16_t*)((buf)+buf_off))=LE16TOH(*((uint16_t*)((buf)+buf_off))); \
+ } \
+ }
+ #undef UTF16BETOH
+ #define UTF16BETOH(buf,buf_len) { \
+ for(int buf_off=0;buf_off<((buf_len)-1);buf_off+=2) { \
+ *((uint16_t*)((buf)+buf_off))=BE16TOH(*((uint16_t*)((buf)+buf_off))); \
+ } \
+ }
+ #undef HTOUTF16LE
+ #define HTOUTF16LE(buf,buf_len) { \
+ for(int buf_off=0;buf_off<((buf_len)-1);buf_off+=2) { \
+ *((uint16_t*)((buf)+buf_off))=HTOLE16(*((uint16_t*)((buf)+buf_off))); \
+ } \
+ }
+ #undef HTOUTF16BE
+ #define HTOUTF16BE(buf,buf_len) { \
+ for(int buf_off=0;buf_off<((buf_len)-1);buf_off+=2) { \
+ *((uint16_t*)((buf)+buf_off))=HTOBE16(*((uint16_t*)((buf)+buf_off))); \
+ } \
+ }
#endif
/*
* Macros for mutex access
*/
#ifdef MACROS_MUTEX
#include <pthread.h>
#undef MUTEX_INIT
#define MUTEX_INIT(var) { \
pthread_mutex_init(&(var),NULL); \
}
#undef MUTEX_DESTROY
#define MUTEX_DESTROY(var) { \
pthread_mutex_destroy(&(var)); \
}
#undef MUTEX_LOCK
#define MUTEX_LOCK(var) { \
pthread_mutex_lock(&(var)); \
}
#undef MUTEX_UNLOCK
#define MUTEX_UNLOCK(var) { \
pthread_mutex_unlock(&(var)); \
}
#endif
/*
* Macros for memory management
*
* Will also include MACROS_LOGGING!
*/
#ifdef MACROS_MEMORY
#include <stdlib.h>
// These macros rely partly on logging macros, so those are needed too
#define MACROS_LOGGING
#undef MALLOC
#define MALLOC(var,var_type,size,err_ret) { \
(var)=(var_type)malloc(size); \
if((var)==NULL) { \
LOG_ERROR("Couldn't allocate memmory!\n"); \
err_ret; \
} \
}
#undef REALLOC
#define REALLOC(var,var_type,size,err_ret) { \
(var)=(var_type)realloc((var),size); \
if((var)==NULL) { \
LOG_ERROR("Couldn't allocate memmory!\n"); \
err_ret; \
} \
}
#undef FREE
#define FREE(var) free(var)
#endif
/*
* Macros to ease debugging and error reporting
*
* These require the following function to be implemented somewhere:
*
* #include <stdio.h>
* #include <stdarg.h>
*
* static void LogMessage(char *p_message_type,
* char *p_calling_function,
* int line,
* char *p_message,
* ...)
* {
* va_list VaList;
* // Print message "header"
* printf("%s: %s@%u : ",
* p_message_type,
* p_calling_function,
* line);
* // Print message with variable parameters
* va_start(VaList,p_message);
* vprintf(p_message,VaList);
* va_end(VaList);
* printf("\n");
* }
*/
#ifdef MACROS_LOGGING
#undef LOG_ERROR
#define LOG_ERROR(...) \
LogMessage("ERROR",(char*)__FUNCTION__,__LINE__,__VA_ARGS__);
#undef LOG_DEBUG
#define LOG_DEBUG(...) { \
LogMessage("DEBUG",(char*)__FUNCTION__,__LINE__,__VA_ARGS__); \
}
#endif
#endif // MACROS_H
/*
----- Change history -----
20130611: * Added ability to only include specific macro groups.
20110428: * Initial release.
*/
diff --git a/trunk/mainwindow.cpp b/trunk/mainwindow.cpp
index 06cdc6a..e49a326 100644
--- a/trunk/mainwindow.cpp
+++ b/trunk/mainwindow.cpp
@@ -1,1078 +1,1070 @@
/*******************************************************************************
* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
* with special feautures useful during forensic analysis. *
* *
* This program is free software: you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the Free *
* Software Foundation, either version 3 of the License, or (at your option) *
* any later version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
* more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
*******************************************************************************/
-#ifndef FRED_REPORT_TEMPLATE_DIR
- #ifndef __MINGW32__
- #define FRED_REPORT_TEMPLATE_DIR "/usr/share/fred/report_templates/"
- #else
- #define FRED_REPORT_TEMPLATE_DIR ".\\report_templates\\"
- #endif
-#endif
-
#include <QFileDialog>
#include <QMessageBox>
#include <QStringList>
#include <QDesktopWidget>
#include <QDir>
#include <QSplitter>
#include <QListIterator>
#include <QInputDialog>
#include <QDebug>
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "dlgabout.h"
#include "dlgreportchooser.h"
#include "dlgreportviewer.h"
#include "dlgsearch.h"
#include "dlgpreferences.h"
#include "dlgaddkey.h"
#include "compileinfo.h"
/*******************************************************************************
* Public
******************************************************************************/
/*
* Constructor
*/
MainWindow::MainWindow(ArgParser *p_arg_parser) :
QMainWindow(0), ui(new Ui::MainWindow)
{
ui->setupUi(this);
// Initialize private vars
this->p_args=p_arg_parser;
this->p_hive=new RegistryHive(this);
this->is_hive_open=false;
this->p_reg_node_tree_model=NULL;
this->p_reg_node_tree_model_proxy=NULL;
this->p_reg_key_table_model=NULL;
this->p_search_thread=NULL;
this->search_result_widgets.clear();
// Init and load settings
this->p_settings=new Settings(this);
this->is_hive_writable=!this->p_settings->GetOpenHivesReadOnly();
// Set main window size
QByteArray geometry=this->p_settings->GetWindowGeometry("MainWindow");
if(!geometry.isEmpty()) {
// Restore saved geometry
this->restoreGeometry(geometry);
} else {
// No saved geometry, calculate and set default
int cur_screen=QApplication::desktop()->screenNumber(this);
int window_width=
QApplication::desktop()->availableGeometry(cur_screen).width()*0.5;
int window_height=
QApplication::desktop()->availableGeometry(cur_screen).height()*0.5;
int window_x=
(QApplication::desktop()->availableGeometry(cur_screen).width()/2)-
(window_width/2);
int window_y=
(QApplication::desktop()->availableGeometry(cur_screen).height()/2)-
(window_height/2);
this->setGeometry(window_x,
window_y,
window_width,
window_height);
}
// Create widgets
this->p_horizontal_splitter=new QSplitter();
this->p_horizontal_splitter->setOrientation(Qt::Horizontal);
this->p_node_tree=new RegistryNodeTree(this->p_horizontal_splitter);
this->p_vertical_splitter=new QSplitter(this->p_horizontal_splitter);
this->p_vertical_splitter->setOrientation(Qt::Vertical);
this->p_key_table=new RegistryKeyTable(this->p_vertical_splitter);
this->p_tab_widget=new TabWidget(this->p_vertical_splitter);
this->p_hex_edit_widget=new HexEditWidget();
this->p_hex_edit_widget->setEnabled(false);
// Add hexedit page to tab_widget
this->p_tab_widget->addTab(this->p_hex_edit_widget,tr("Hex viewer"));
// Add widgets to their splitters
this->p_vertical_splitter->addWidget(this->p_key_table);
this->p_vertical_splitter->addWidget(this->p_tab_widget);
this->p_horizontal_splitter->addWidget(this->p_node_tree);
this->p_horizontal_splitter->addWidget(this->p_vertical_splitter);
// Set stretch factors
QSizePolicy node_tree_policy=this->p_node_tree->sizePolicy();
node_tree_policy.setHorizontalStretch(1);
node_tree_policy.setVerticalStretch(100);
this->p_node_tree->setSizePolicy(node_tree_policy);
QSizePolicy vertical_splitter_policy=this->p_vertical_splitter->sizePolicy();
vertical_splitter_policy.setHorizontalStretch(4);
vertical_splitter_policy.setVerticalStretch(100);
this->p_vertical_splitter->setSizePolicy(vertical_splitter_policy);
QSizePolicy key_table_policy=this->p_key_table->sizePolicy();
key_table_policy.setVerticalStretch(5);
key_table_policy.setHorizontalStretch(100);
this->p_key_table->setSizePolicy(key_table_policy);
QSizePolicy tab_widget_policy=this->p_tab_widget->sizePolicy();
tab_widget_policy.setVerticalStretch(2);
tab_widget_policy.setHorizontalStretch(200);
this->p_tab_widget->setSizePolicy(tab_widget_policy);
// Connect signals
this->connect(this->p_node_tree,
SIGNAL(clicked(QModelIndex)),
this,
SLOT(SlotNodeTreeClicked(QModelIndex)));
this->connect(this->p_node_tree,
SIGNAL(activated(QModelIndex)),
this,
SLOT(SlotNodeTreeClicked(QModelIndex)));
this->connect(this->p_node_tree,
SIGNAL(CurrentItemChanged(QModelIndex)),
this,
SLOT(SlotNodeTreeClicked(QModelIndex)));
this->connect(this->p_key_table,
SIGNAL(clicked(QModelIndex)),
this,
SLOT(SlotKeyTableClicked(QModelIndex)));
this->connect(this->p_key_table,
SIGNAL(doubleClicked(QModelIndex)),
this,
SLOT(SlotKeyTableDoubleClicked(QModelIndex)));
this->connect(this->p_key_table,
SIGNAL(CurrentItemChanged(QModelIndex)),
this,
SLOT(SlotKeyTableClicked(QModelIndex)));
this->connect(this->p_tab_widget,
SIGNAL(tabCloseRequested(int)),
this,
SLOT(SlotTabCloseButtonClicked(int)));
this->connect(this->p_node_tree,
SIGNAL(SignalAddNode(QModelIndex)),
this,
SLOT(SlotAddNode(QModelIndex)));
this->connect(this->p_node_tree,
SIGNAL(SignalDeleteNode(QModelIndex)),
this,
SLOT(SlotDeleteNode(QModelIndex)));
this->connect(this->p_key_table,
SIGNAL(SignalAddKey()),
this,
SLOT(SlotAddKey()));
this->connect(this->p_key_table,
SIGNAL(SignalEditKey(QModelIndex)),
this,
SLOT(SlotEditKey(QModelIndex)));
this->connect(this->p_key_table,
SIGNAL(SignalDeleteKey(QModelIndex)),
this,
SLOT(SlotDeleteKey(QModelIndex)));
// Add central widget
this->setCentralWidget(this->p_horizontal_splitter);
this->centralWidget()->setContentsMargins(4,4,4,0);
// Set window title
this->UpdateWindowTitle();
// Create and update recently opened menu
this->p_recently_opened_menu=new QMenu(this);
this->ui->ActionRecentlyOpened->setMenu(this->p_recently_opened_menu);
this->UpdateRecentlyOpenedMenu();
// Update EnableWriteSupport menu according to defaults
this->UpdateEnableWriteSupportMenu();
// Load report templates
this->p_reports=new Reports(this->p_settings);
// Finally, react on some command line arguments
if(this->p_args->IsSet("maximized")) {
this->setWindowState(Qt::WindowMaximized);
}
if(this->p_args->IsSet("fullscreen")) {
this->setWindowState(Qt::WindowFullScreen);
}
if(this->p_args->IsSet("hive-file")) {
this->OpenHive(this->p_args->GetArgVal("hive-file"));
}
}
/*
* Destructor
*/
MainWindow::~MainWindow() {
if(this->is_hive_open) {
this->p_hive->Close();
}
// Delete created objects
delete this->p_reports;
this->ClearRecentlyOpenedMenu();
delete this->p_recently_opened_menu;
delete this->p_hex_edit_widget;
delete this->p_tab_widget;
delete this->p_key_table;
delete this->p_vertical_splitter;
delete this->p_node_tree;
delete this->p_horizontal_splitter;
delete this->p_settings;
delete this->p_hive;
delete ui;
}
/*******************************************************************************
* Protected
******************************************************************************/
/*
* closeEvent
*/
void MainWindow::closeEvent(QCloseEvent *p_event) {
Q_UNUSED(p_event)
// Make sure the user can save any changes
// TODO: If saving fails, let the user cancel closing
this->SaveHiveChanges();
// Save window position and size on exit
this->p_settings->SetWindowGeometry("MainWindow",this->saveGeometry());
QMainWindow::closeEvent(p_event);
}
/*******************************************************************************
* Private slots
******************************************************************************/
/*
* on_action_Open_hive_triggered
*/
void MainWindow::on_action_Open_hive_triggered() {
QString hive_file="";
hive_file=QFileDialog::getOpenFileName(this,
tr("Open registry hive"),
this->p_settings->GetLastOpenLocation(),
tr("All files (*)"));
if(hive_file=="") return;
this->OpenHive(hive_file);
}
/*
* on_action_Close_hive_triggered
*/
void MainWindow::on_action_Close_hive_triggered() {
// Make sure the user can save any changes
// TODO: If saving fails, let the user cancel closing
this->SaveHiveChanges();
if(this->is_hive_open) {
// Remove search results
while(this->p_tab_widget->count()>1) {
this->p_tab_widget->removeTab(this->p_tab_widget->count()-1);
delete this->search_result_widgets.at(this->p_tab_widget->count()-1);
this->search_result_widgets.removeLast();
}
// Delete models
if(this->p_reg_node_tree_model!=NULL) {
this->p_node_tree->setModel(NULL);
delete this->p_reg_node_tree_model_proxy;
delete this->p_reg_node_tree_model;
this->p_reg_node_tree_model_proxy=NULL;
this->p_reg_node_tree_model=NULL;
}
if(this->p_reg_key_table_model!=NULL) {
this->p_key_table->setModel(NULL);
delete this->p_reg_key_table_model;
this->p_reg_key_table_model=NULL;
}
// Remove any data from hex edit and data interpreter
this->p_hex_edit_widget->SetData(QByteArray());
this->p_hex_edit_widget->setEnabled(false);
// Close hive
this->p_hive->Close();
this->is_hive_open=false;
this->is_hive_writable=!this->p_settings->GetOpenHivesReadOnly();
this->UpdateWindowTitle();
this->UpdateMenuStates();
this->UpdateEnableWriteSupportMenu();
}
}
/*
* on_action_Quit_triggered
*/
void MainWindow::on_action_Quit_triggered() {
qApp->exit();
}
/*
* on_ActionSearch_triggered
*/
void MainWindow::on_ActionSearch_triggered() {
DlgSearch dlg_search(this);
if(dlg_search.exec()==QDialog::Accepted) {
// Create search thread and connect needed signals/slots
this->p_search_thread=new ThreadSearch(this);
// Add new search widget to tabwidget and to internal widget list
SearchResultWidget *p_search_widget=
new SearchResultWidget(this->p_tab_widget);
p_search_widget->setEnabled(false);
this->search_result_widgets.append(p_search_widget);
this->connect(p_search_widget,
SIGNAL(doubleClicked(QModelIndex)),
this,
SLOT(SlotSearchResultWidgetDoubleClicked(QModelIndex)));
this->p_tab_widget->addTab(p_search_widget,tr("Search results"),true);
this->p_tab_widget->setCurrentIndex(this->p_tab_widget->count()-1);
// Connect search thread to result widget
this->connect(this->p_search_thread,
SIGNAL(SignalFoundMatch(ThreadSearch::eMatchType,
QString,QString,QString)),
p_search_widget,
SLOT(SlotFoundMatch(ThreadSearch::eMatchType,
QString,QString,QString)));
this->connect(this->p_search_thread,
SIGNAL(finished()),
this,
SLOT(SlotSearchFinished()));
this->connect(this->p_search_thread,
SIGNAL(finished()),
p_search_widget,
SLOT(SlotSearchFinished()));
// Start searching
this->ui->ActionSearch->setEnabled(false);
p_search_thread->Search(this->p_hive->Filename(),
dlg_search.Keywords(),
dlg_search.SearchNodeNames(),
dlg_search.SearchKeyNames(),
dlg_search.SearchKeyValues());
}
}
/*
* on_ActionEnableWriteSupport_triggered
*/
void MainWindow::on_ActionEnableWriteSupport_triggered() {
// There might be unsaved changes, give the user the chance to save them
if(!this->SaveHiveChanges()) return;
// Reopen hive
// Reopen has read_only as parameter. Thus we need to pass
// !this->is_hive_writable which is the case when passing
// this->is_hive_writable as long as we do it before actually changing our
// internal state.
if(!this->p_hive->Reopen(this->is_hive_writable)) {
QMessageBox::critical(this,
tr("Error"),
tr("Unable to switch write-support: %1")
.arg(this->p_hive->GetErrorMsg()));
return;
}
// Switch internal state
this->is_hive_writable=!this->is_hive_writable;
this->UpdateEnableWriteSupportMenu();
this->p_node_tree->SetWritable(this->is_hive_writable);
this->p_key_table->SetWritable(this->is_hive_writable);
this->UpdateWindowTitle(this->p_hive->Filename());
}
/*
* on_ActionPreferences_triggered
*/
void MainWindow::on_ActionPreferences_triggered() {
DlgPreferences dlg_preferences(this->p_settings,this);
dlg_preferences.exec();
// Update vars, objects and GUI elements which might be affected by the new
// settings
this->UpdateRecentlyOpenedMenu();
this->is_hive_writable=!this->p_settings->GetOpenHivesReadOnly();
this->UpdateEnableWriteSupportMenu();
this->p_reports->LoadReportTemplates();
}
/*
* on_ActionGenerateReport_triggered
*/
void MainWindow::on_ActionGenerateReport_triggered() {
DlgReportChooser dlg_repchooser(this->p_reports,
this->p_hive->HiveTypeToString(
this->p_hive->HiveType()),
this->p_settings,
this);
if(dlg_repchooser.exec()==QDialog::Accepted) {
QList<ReportTemplate*> selected_reports;
// Get selected report
selected_reports=dlg_repchooser.GetSelectedReports();
if(selected_reports.isEmpty()) return;
// Generate report(s)
QString report_result="";
if(this->p_reports->GenerateReport(this->p_hive,
selected_reports,
report_result,
false))
{
// Report generation was successfull, show reports
DlgReportViewer *p_dlg_report_view=new DlgReportViewer(report_result,
this->p_settings,
this);
p_dlg_report_view->exec();
delete p_dlg_report_view;
} else {
// TODO: Inform user
qDebug()<<"ERROR: "<<report_result;
}
}
}
/*
* on_ActionReloadReportTemplates_triggered
*/
void MainWindow::on_ActionReloadReportTemplates_triggered() {
this->p_reports->LoadReportTemplates();
}
/*
* on_actionAbout_Qt_triggered
*/
void MainWindow::on_actionAbout_Qt_triggered() {
QMessageBox::aboutQt(this,tr("About Qt"));
}
/*
* on_actionAbout_fred_triggered
*/
void MainWindow::on_actionAbout_fred_triggered() {
DlgAbout dlg_about(this);
dlg_about.exec();
}
/*
* SlotNodeTreeClicked
*/
void MainWindow::SlotNodeTreeClicked(QModelIndex index) {
QString node_path;
if(!index.isValid()) return;
// Map proxy index to tree model index
index=this->p_reg_node_tree_model_proxy->mapToSource(index);
// Built node path
node_path=this->p_reg_node_tree_model->GetNodePath(index);
// Create table model and attach it to the table view
if(this->p_reg_key_table_model!=NULL) {
// If a previous model was set, delete it and clear hexedit etc...
this->p_key_table->setModel(NULL);
delete this->p_reg_key_table_model;
this->p_hex_edit_widget->SetData(QByteArray());
}
this->p_reg_key_table_model=new RegistryKeyTableModel(this->p_hive,node_path);
this->p_key_table->setModel(this->p_reg_key_table_model,
this->is_hive_writable);
// Set focus back to nodetree to be able to navigate with keyboard
this->p_node_tree->setFocus();
}
/*
* SlotKeyTableClicked
*/
void MainWindow::SlotKeyTableClicked(QModelIndex index) {
if(!index.isValid()) return;
this->selected_key_value=
this->p_reg_key_table_model->data(this->p_reg_key_table_model->
index(index.row(),2),
RegistryKeyTableModel::
AdditionalRoles_GetRawData)
.toByteArray();
this->p_hex_edit_widget->SetData(this->selected_key_value);
// Set focus back to nodetree to be able to navigate with keyboard
this->p_key_table->setFocus();
}
/*
* SlotKeyTableDoubleClicked
*/
void MainWindow::SlotKeyTableDoubleClicked(QModelIndex index) {
if(!index.isValid()) return;
if(!this->is_hive_open) return;
if(this->is_hive_writable) this->SlotEditKey(index);
}
/*
* SlotSearchFinished
*/
void MainWindow::SlotSearchFinished() {
delete this->p_search_thread;
this->p_search_thread=NULL;
this->ui->ActionSearch->setEnabled(true);
// Enable result widget
this->search_result_widgets.last()->setEnabled(true);
}
/*
* SlotSearchResultWidgetDoubleClicked
*/
void MainWindow::SlotSearchResultWidgetDoubleClicked(QModelIndex index) {
SearchResultWidget *p_sender;
QString path;
QString match_type;
QString value;
QString key="";
int i;
if(!index.isValid()) return;
// Get pointer to sender
p_sender=(SearchResultWidget*)QObject::sender();
// Get path and matchtype
path=p_sender->item(index.row(),0)->text();
match_type=p_sender->item(index.row(),1)->text();
value=p_sender->item(index.row(),2)->text();
if(match_type==tr("Node name")) {
// Node name is not part of path. Add it
if(path=="\\") path.append(value);
else path.append("\\").append(value);
} else if(match_type==tr("Key name")) {
// Key name is stored in value
key=value;
} else if(match_type==tr("Key value")) {
// Key name is part of path. Save and remove it
QStringList nodes=path.split("\\",QString::SkipEmptyParts);
key=nodes.at(nodes.count()-1);
// Remove \<key name> from path
path.chop(key.length()+1);
}
// Expand treeview to correct node
QList<QModelIndex> indexes=
this->p_reg_node_tree_model->GetIndexListOf(path);
for(i=0;i<indexes.count();i++) {
indexes.replace(i,this->p_reg_node_tree_model_proxy->
mapFromSource(indexes.at(i)));
this->p_node_tree->expand(indexes.at(i));
}
if(indexes.count()>0) {
// Scroll to last expanded node, select it and update widgets
this->p_node_tree->scrollTo(indexes.at(indexes.count()-1),
QAbstractItemView::PositionAtCenter);
this->p_node_tree->selectionModel()->clear();
this->p_node_tree->selectionModel()->
select(indexes.at(indexes.count()-1),
QItemSelectionModel::ClearAndSelect |
QItemSelectionModel::Rows |
QItemSelectionModel::Current);
this->SlotNodeTreeClicked(indexes.at(indexes.count()-1));
}
// Select correct key if search matched on keay name / value
if(key!="") {
int row=this->p_reg_key_table_model->GetKeyRow(key);
this->p_key_table->clearSelection();
this->p_key_table->scrollTo(this->p_reg_key_table_model->index(row,0),
QAbstractItemView::PositionAtCenter);
this->p_key_table->selectRow(row);
this->SlotKeyTableClicked(this->p_reg_key_table_model->index(row,0));
}
}
/*
* SlotTabCloseButtonClicked
*/
void MainWindow::SlotTabCloseButtonClicked(int index) {
// Delete tab widget and remove tab
this->p_tab_widget->removeTab(index);
delete this->search_result_widgets.at(index-1);
this->search_result_widgets.removeAt(index-1);
}
/*
* SlotRecentlyOpenedFileClicked
*/
void MainWindow::SlotRecentlyOpenedFileClicked(bool checked) {
Q_UNUSED(checked)
QAction *p_sender=(QAction*)QObject::sender();
this->OpenHive(p_sender->text());
}
/*
* SlotAddNode
*/
void MainWindow::SlotAddNode(QModelIndex index) {
QString node_path;
int new_node_id;
if(!index.isValid()) return;
// Map proxy index to tree model index and get node path
index=this->p_reg_node_tree_model_proxy->mapToSource(index);
node_path=this->p_reg_node_tree_model->GetNodePath(index);
// Query user for a node name
bool ok=false;
QString node_name=QInputDialog::getText(this,
tr("Add node"),
tr("Please specify a name for the new node"),
QLineEdit::Normal,
QString(),
&ok);
if(ok) {
if((new_node_id=this->p_hive->AddNode(node_path,node_name))==0) {
QMessageBox::critical(this,
tr("Error"),
tr("Unable to create node '%1\\%2': %3!")
.arg(node_path,
node_name,
this->p_hive->GetErrorMsg()));
} else {
// Add node to model. We have to pass node_name as Ascii as utf8 names are
// not supported inside hives!
QModelIndex new_node_index=
this->p_reg_node_tree_model->AddNode(this->p_hive,
index,
new_node_id,
node_name.toAscii());
// Now that node has been added, expand parent and select new node
this->p_node_tree->expand(
this->p_reg_node_tree_model_proxy->mapFromSource(index));
new_node_index=
this->p_reg_node_tree_model_proxy->mapFromSource(new_node_index);
this->p_node_tree->scrollTo(new_node_index,
QAbstractItemView::PositionAtCenter);
this->p_node_tree->selectionModel()->clear();
this->p_node_tree->selectionModel()->
select(new_node_index,
QItemSelectionModel::ClearAndSelect |
QItemSelectionModel::Rows |
QItemSelectionModel::Current);
// And finally update key table
this->SlotNodeTreeClicked(new_node_index);
}
}
}
/*
* SlotDeleteNode
*/
void MainWindow::SlotDeleteNode(QModelIndex index) {
QString node_path;
if(!index.isValid()) return;
// Map proxy index to tree model index and get node path
index=this->p_reg_node_tree_model_proxy->mapToSource(index);
node_path=this->p_reg_node_tree_model->GetNodePath(index);
if(QMessageBox::warning(this,
tr("Delete node"),
tr("Are you sure you want to remove the node '%1' and all of its child nodes?").arg(node_path),
QMessageBox::Yes,
QMessageBox::No)==QMessageBox::Yes)
{
// Remove node from hive
if(!this->p_hive->DeleteNode(node_path)) {
QMessageBox::critical(this,
tr("Error"),
tr("Unable to delete node '%1': %2!")
.arg(node_path,this->p_hive->GetErrorMsg()));
return;
}
// Remove node from tree model and select nearest node
QModelIndex next_node_index=this->p_reg_node_tree_model->RemoveNode(index);
if(next_node_index.isValid()) {
next_node_index=
this->p_reg_node_tree_model_proxy->mapFromSource(next_node_index);
this->p_node_tree->selectionModel()->clear();
this->p_node_tree->selectionModel()->
select(next_node_index,
QItemSelectionModel::ClearAndSelect |
QItemSelectionModel::Rows |
QItemSelectionModel::Current);
}
// And finally update key table
this->SlotNodeTreeClicked(next_node_index);
}
}
/*
* SlotAddKey
*/
void MainWindow::SlotAddKey() {
DlgAddKey dlg_add_key(this);
if(dlg_add_key.exec()==QDialog::Accepted) {
// Get selected parent node
QModelIndex parent_node=this->p_node_tree->currentIndex();
parent_node=this->p_reg_node_tree_model_proxy->mapToSource(parent_node);
QString parent_node_path=this->p_reg_node_tree_model->GetNodePath(parent_node);
// Add key
int new_key=this->p_hive->AddKey(parent_node_path,
dlg_add_key.KeyName(),
dlg_add_key.KeyType(),
dlg_add_key.KeyValue());
if(new_key==0) {
QMessageBox::critical(this,
tr("Error"),
tr("Unable to add key: %1")
.arg(this->p_hive->GetErrorMsg()));
return;
}
// Add new key to the key table model
QModelIndex new_key_index=
this->p_reg_key_table_model->AddKey(this->p_hive,new_key);
if(new_key_index.isValid()) {
this->p_key_table->clearSelection();
this->p_key_table->scrollTo(new_key_index,
QAbstractItemView::PositionAtCenter);
this->p_key_table->selectRow(new_key_index.row());
}
this->SlotKeyTableClicked(new_key_index);
}
}
/*
* SlotEditKey
*/
void MainWindow::SlotEditKey(QModelIndex index) {
if(!index.isValid()) return;
// Get current values
QString key_name=
this->p_reg_key_table_model->data(this->p_reg_key_table_model->
index(index.row(),
RegistryKeyTableModel::
ColumnContent_KeyName),
Qt::DisplayRole).toString();
QString key_value_type=
this->p_reg_key_table_model->data(this->p_reg_key_table_model->
index(index.row(),
RegistryKeyTableModel::
ColumnContent_KeyType),
Qt::DisplayRole).toString();
QByteArray key_value=
this->p_reg_key_table_model->data(this->p_reg_key_table_model->
index(index.row(),
RegistryKeyTableModel::
ColumnContent_KeyValue),
RegistryKeyTableModel::
AdditionalRoles_GetRawData).toByteArray();
// Exec update dialog
DlgAddKey dlg_update_key(this,key_name,key_value_type,key_value);
if(dlg_update_key.exec()==QDialog::Accepted) {
// Get selected parent node
QModelIndex parent_node=this->p_node_tree->currentIndex();
parent_node=this->p_reg_node_tree_model_proxy->mapToSource(parent_node);
QString parent_node_path=this->p_reg_node_tree_model->GetNodePath(parent_node);
// Update key
int new_key=this->p_hive->UpdateKey(parent_node_path,
dlg_update_key.KeyName(),
dlg_update_key.KeyType(),
dlg_update_key.KeyValue());
if(new_key==0) {
QMessageBox::critical(this,
tr("Error"),
tr("Unable to update key: %1")
.arg(this->p_hive->GetErrorMsg()));
return;
}
// Update key in key table model
QModelIndex new_key_index=
this->p_reg_key_table_model->UpdateKey(this->p_hive,new_key);
this->p_key_table->clearSelection();
if(new_key_index.isValid()) {
this->p_key_table->scrollTo(new_key_index,
QAbstractItemView::PositionAtCenter);
this->p_key_table->selectRow(new_key_index.row());
// TODO: Update geometry in case data has been added and is now expanding
// behind the right border
// Update HexEditWidget
}
this->SlotKeyTableClicked(new_key_index);
}
}
/*
* SlotDeleteKey
*/
void MainWindow::SlotDeleteKey(QModelIndex index) {
if(!index.isValid()) return;
// Get selected key name
QString key_name=
this->p_reg_key_table_model->data(this->p_reg_key_table_model->
index(index.row(),
RegistryKeyTableModel::
ColumnContent_KeyName),
Qt::DisplayRole).toString();
// Get selected parent node
QModelIndex parent_node=this->p_node_tree->currentIndex();
parent_node=this->p_reg_node_tree_model_proxy->mapToSource(parent_node);
QString parent_node_path=this->p_reg_node_tree_model->GetNodePath(parent_node);
if(QMessageBox::warning(this,
tr("Delete key"),
tr("Are you sure you want to remove the key '%1\\%2'?")
.arg(parent_node_path,key_name),
QMessageBox::Yes,
QMessageBox::No)==QMessageBox::Yes)
{
// Remove key from hive
if(!this->p_hive->DeleteKey(parent_node_path,key_name)) {
QMessageBox::critical(this,
tr("Error"),
tr("Unable to delete key '%1\\%2': %3")
.arg(parent_node_path,
key_name,
this->p_hive->GetErrorMsg()));
return;
}
// Remove key from table model and update selection
QModelIndex new_key_index=this->p_reg_key_table_model->RemoveKey(index);
this->p_key_table->clearSelection();
if(new_key_index.isValid()) {
this->p_key_table->scrollTo(new_key_index,
QAbstractItemView::PositionAtCenter);
this->p_key_table->selectRow(new_key_index.row());
}
}
}
/*******************************************************************************
* Private
******************************************************************************/
/*
* OpenHive
*/
void MainWindow::OpenHive(QString hive_file) {
// Update last open location
this->p_settings->SetLastOpenLocation(
hive_file.left(hive_file.lastIndexOf(QDir::separator())));
// If another hive is currently open, close it
if(this->is_hive_open) this->on_action_Close_hive_triggered();
// Try to open hive
if(!this->p_hive->Open(hive_file,!this->is_hive_writable)) {
QMessageBox::critical(this,
tr("Error opening hive file"),
tr("Unable to open file '%1'").arg(hive_file));
return;
}
// Create tree model & proxy
this->p_reg_node_tree_model=new RegistryNodeTreeModel(this->p_hive);
this->p_reg_node_tree_model_proxy=new RegistryNodeTreeModelProxy(this);
//this->p_reg_node_tree_model_proxy->setDynamicSortFilter(true);
this->p_reg_node_tree_model_proxy->
setSourceModel(this->p_reg_node_tree_model);
this->p_node_tree->setModel(this->p_reg_node_tree_model_proxy,
this->is_hive_writable);
this->is_hive_open=true;
// Enable data interpreter
this->p_hex_edit_widget->setEnabled(true);
// Update window title
this->UpdateWindowTitle(hive_file);
// Update menu states
this->UpdateMenuStates();
// Add file to recent list and update recently opened menu
this->p_settings->AddRecentFile(hive_file);
this->UpdateRecentlyOpenedMenu();
}
/*
* UpdateWindowTitle
*/
void MainWindow::UpdateWindowTitle(QString filename) {
if(filename=="") {
this->setWindowTitle(QString("%1 v%2").arg(APP_TITLE,APP_VERSION));
} else {
this->setWindowTitle(QString("%1 v%2 - %3").arg(APP_TITLE,
APP_VERSION,
filename.toLocal8Bit()
.constData()));
if(!this->is_hive_writable) {
this->setWindowTitle(this->windowTitle().append(QString(" (%1)")
.arg(tr("read-only"))));
}
}
}
/*
* UpdateMenuStates
*/
void MainWindow::UpdateMenuStates() {
if(this->is_hive_open) {
this->ui->action_Close_hive->setEnabled(true);
- this->ui->ActionEnableWriteSupport->setEnabled(true);
this->ui->ActionSearch->setEnabled(true);
this->ui->ActionEnableWriteSupport->setEnabled(true);
this->ui->ActionGenerateReport->setEnabled(true);
this->ui->ActionReloadReportTemplates->setEnabled(true);
+ this->UpdateEnableWriteSupportMenu();
} else {
this->ui->action_Close_hive->setEnabled(false);
this->ui->ActionEnableWriteSupport->setEnabled(false);
this->ui->ActionSearch->setEnabled(false);
this->ui->ActionEnableWriteSupport->setEnabled(false);
this->ui->ActionGenerateReport->setEnabled(false);
this->ui->ActionReloadReportTemplates->setEnabled(false);
}
}
/*
* ClearRecentlyOpenedMenu
*/
void MainWindow::ClearRecentlyOpenedMenu() {
QAction *p_action;
// Remove existing menu entries
QList<QAction*> menu_entries=this->p_recently_opened_menu->actions();
QListIterator<QAction*> it_me(menu_entries);
while(it_me.hasNext()) {
p_action=it_me.next();
this->p_recently_opened_menu->removeAction(p_action);
delete p_action;
}
}
/*
* UpdateRecentlyOpenedMenu
*/
void MainWindow::UpdateRecentlyOpenedMenu() {
QStringList recent_files=this->p_settings->GetRecentFiles();
QAction *p_action;
// Remove existing menu entries
this->ClearRecentlyOpenedMenu();
// If there are no recent files, disable submenu and return
if(recent_files.isEmpty()) {
this->ui->ActionRecentlyOpened->setEnabled(false);
return;
} else {
this->ui->ActionRecentlyOpened->setEnabled(true);
}
// Add recently opened files to menu
QListIterator<QString> it_rf(recent_files);
while(it_rf.hasNext()) {
// Create menu entry
p_action=new QAction(it_rf.next(),this->p_recently_opened_menu);
// Connect it to us
this->connect(p_action,
SIGNAL(triggered(bool)),
this,
SLOT(SlotRecentlyOpenedFileClicked(bool)));
// Add it to submenu
this->p_recently_opened_menu->addAction(p_action);
}
}
/*
* UpdateEnableWriteSupportMenu
*/
void MainWindow::UpdateEnableWriteSupportMenu() {
if(!this->is_hive_writable) {
this->ui->ActionEnableWriteSupport->setText(tr("Enable &write support"));
this->p_node_tree->SetWritable(false);
this->p_key_table->SetWritable(false);
} else {
- this->ui->ActionEnableWriteSupport->setText(tr("Disable &write support"));
+ this->ui->ActionEnableWriteSupport->setEnabled(false);
this->p_node_tree->SetWritable(true);
this->p_key_table->SetWritable(true);
}
}
/*
* SaveHiveChanges
*/
bool MainWindow::SaveHiveChanges() {
if(!this->is_hive_open) return true;
if(!this->is_hive_writable) return true;
if(!this->p_hive->HasChangesToCommit()) return true;
// There are unsaved changes, ask user if we should commit them
switch(QMessageBox::information(this,
tr("Hive contains unsaved data"),
tr("Do you want to save them now?"),
QMessageBox::Yes,
QMessageBox::No,
QMessageBox::Cancel))
{
case QMessageBox::Yes: {
if(!this->p_hive->CommitChanges()) {
QMessageBox::critical(this,
tr("Saving changes"),
tr("Unable to save changes: %1")
.arg(this->p_hive->GetErrorMsg()));
return false;
}
break;
}
case QMessageBox::No: {
// TODO: Discard any changes if we are changing to read-only!
break;
}
default: {
return false;
}
}
return true;
}
diff --git a/trunk/registryhive.cpp b/trunk/registryhive.cpp
index f3bacf4..60bc408 100644
--- a/trunk/registryhive.cpp
+++ b/trunk/registryhive.cpp
@@ -1,1343 +1,1359 @@
/*******************************************************************************
* fred Copyright (c) 2011-2013 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 <QStringList>
#include <QDateTime>
#include <stdlib.h>
#include <stdio.h>
#include <QDebug>
#include "registryhive.h"
#define MACROS_ENDIANNESS
#include "macros.h"
// TODO: __WORDSIZE is not defined under mingw and I currently have no idea how
// to identify a 64bit windows
#ifndef __WORDSIZE
#define __WORDSIZE 32
#endif
#if __WORDSIZE == 64
#define EPOCH_DIFF 0x19DB1DED53E8000
#else
#define EPOCH_DIFF 0x19DB1DED53E8000LL
#endif
/*******************************************************************************
* Public
******************************************************************************/
/*
* RegistryHive
*/
RegistryHive::RegistryHive(QObject *p_parent) : QObject(p_parent) {
this->erro_msg="";
this->is_error=false;
this->hive_file="";
this->p_hive=NULL;
this->is_hive_open=false;
this->is_hive_writable=false;
this->has_changes_to_commit=false;
}
/*
* ~RegistryHive
*/
RegistryHive::~RegistryHive() {
if(this->is_hive_open) this->Close();
}
/*
* Error
*/
bool RegistryHive::Error() {
return this->is_error;
}
/*
* GetErrorMsg
*/
QString RegistryHive::GetErrorMsg() {
QString msg=this->erro_msg;
this->erro_msg="";
this->is_error=false;
return msg;
}
/*
* Open
*/
bool RegistryHive::Open(QString file, bool read_only) {
if(this->is_hive_open) return false;
// Open hive file
this->p_hive=hivex_open(file.toAscii().constData(),
read_only ? 0 : HIVEX_OPEN_WRITE);
if(this->p_hive==NULL) return false;
// Set local vars
this->hive_file=file;
this->is_hive_open=true;
this->is_hive_writable=!read_only;
return true;
}
/*
* Reopen
*/
bool RegistryHive::Reopen(bool read_only) {
if(!this->is_hive_open) return false;
// Close hive first
if(hivex_close(this->p_hive)!=0) {
// According to the docs, even if hivex_close fails, it frees all handles.
// So we consider this fatal and final!
this->hive_file="";
this->is_hive_open=false;
this->is_hive_writable=false;
this->has_changes_to_commit=false;
return false;
}
// Reopen same hive
this->p_hive=hivex_open(this->hive_file.toAscii().constData(),
read_only ? 0 : HIVEX_OPEN_WRITE);
if(this->p_hive==NULL) {
this->hive_file="";
this->is_hive_open=false;
this->is_hive_writable=false;
this->has_changes_to_commit=false;
return false;
}
// Update local vars
this->is_hive_writable=!read_only;
this->has_changes_to_commit=false;
return true;
}
/*
* CommitChanges
*/
bool RegistryHive::CommitChanges() {
if(!this->is_hive_open || !this->is_hive_writable) return false;
if(!this->has_changes_to_commit) return true;
// TODO: Maybe it would be more secure to commit changes to a new file and
// then move it over the original one.
if(hivex_commit(this->p_hive,NULL,0)!=0) {
return false;
}
return true;
}
/*
* Close
*/
bool RegistryHive::Close() {
if(this->is_hive_open) {
// As hivex_close will _ALWAYS_ free the handle, we don't need the following
// values anymore
this->hive_file="";
this->is_hive_open=false;
this->is_hive_writable=false;
this->has_changes_to_commit=false;
// Close hive
if(hivex_close(this->p_hive)!=0) return false;
}
return true;
}
/*
* Filename
*/
QString RegistryHive::Filename() {
if(this->is_hive_open) return this->hive_file;
return QString();
}
/*
* HiveType
*/
RegistryHive::teHiveType RegistryHive::HiveType() {
// Check for SYSTEM hive
if(this->PathExists("\\Select") && this->PathExists("\\MountedDevices"))
return RegistryHive::eHiveType_SYSTEM;
// Check for SOFTWARE hive
if(this->PathExists("\\Microsoft\\Windows\\CurrentVersion") &&
this->PathExists("\\Microsoft\\Windows NT\\CurrentVersion"))
return RegistryHive::eHiveType_SOFTWARE;
// Check for SAM
if(this->PathExists("SAM\\Domains\\Account\\Users"))
return RegistryHive::eHiveType_SAM;
// Check for SECURITY
if(this->PathExists("\\Policy\\Accounts") &&
this->PathExists("\\Policy\\PolAdtEv"))
return RegistryHive::eHiveType_SECURITY;
// Check for NTUSER.DAT
if(this->PathExists("\\Software\\Microsoft\\Windows\\CurrentVersion"))
return RegistryHive::eHiveType_NTUSER;
// Unknown hive
return RegistryHive::eHiveType_UNKNOWN;
}
/*
* HiveTypeToString
*/
QString RegistryHive::HiveTypeToString(teHiveType hive_type) {
switch(hive_type) {
case RegistryHive::eHiveType_SYSTEM:
return "SYSTEM";
break;
case RegistryHive::eHiveType_SOFTWARE:
return "SOFTWARE";
break;
case RegistryHive::eHiveType_SAM:
return "SAM";
break;
case RegistryHive::eHiveType_SECURITY:
return "SECURITY";
break;
case RegistryHive::eHiveType_NTUSER:
return "NTUSER";
break;
default:
return "UNKNOWN";
}
}
/*
* HasChangesToCommit
*/
bool RegistryHive::HasChangesToCommit() {
return this->has_changes_to_commit;
}
/*
* GetNodes
*/
QMap<QString,int> RegistryHive::GetNodes(QString path) {
hive_node_h parent_node;
// Get handle to last node in path
if(!this->GetNodeHandle(path,&parent_node)) return QMap<QString,int>();
// Get and return nodes
return this->GetNodesHelper(parent_node);
}
/*
* GetNodes
*/
QMap<QString,int> RegistryHive::GetNodes(int parent_node) {
if(parent_node==0) {
this->SetError(tr("Invalid parent node handle specified!"));
return QMap<QString,int>();
}
// Get and return nodes
return this->GetNodesHelper(parent_node);
}
/*
* GetKeys
*/
QMap<QString,int> RegistryHive::GetKeys(QString path) {
hive_node_h parent_node;
// Get handle to last node in path
if(!this->GetNodeHandle(path,&parent_node)) return QMap<QString,int>();
// Get and return keys
return this->GetKeysHelper(parent_node);
}
/*
* GetKeys
*/
QMap<QString,int> RegistryHive::GetKeys(int parent_node) {
if(parent_node==0) {
this->SetError(tr("Invalid parent node handle specified!"));
return QMap<QString,int>();
}
// Get and return keys
return this->GetKeysHelper(parent_node);
}
/*
* GetKeyName
*/
bool RegistryHive::GetKeyName(int hive_key, QString &key_name) {
char *buf;
if(!this->is_hive_open) {
this->SetError(tr("Need to operate on an open hive!"));
return false;
}
buf=hivex_value_key(this->p_hive,(hive_value_h)hive_key);
if(buf==NULL) {
this->SetError(tr("Unable to get key name for key '%1'").arg(hive_key));
return false;
}
key_name=QString(buf);
free(buf);
return true;
}
/*
* GetKeyValue
*/
QByteArray RegistryHive::GetKeyValue(QString path,
QString key,
int *p_value_type,
size_t *p_value_len)
{
hive_node_h parent_node;
hive_value_h hive_key;
// Get handle to last node in path
if(!this->GetNodeHandle(path,&parent_node)) return QByteArray();
// Get key handle
hive_key=hivex_node_get_value(this->p_hive,
parent_node,key.toAscii().constData());
if(hive_key==0) {
this->SetError(tr("Unable to get key handle!"));
*p_value_len=-1;
return QByteArray();
}
// Get and return key value
return this->GetKeyValueHelper(hive_key,p_value_type,p_value_len);
}
/*
* GetKeyValue
*/
QByteArray RegistryHive::GetKeyValue(int hive_key,
int *p_value_type,
size_t *p_value_len)
{
if(hive_key==0) {
this->SetError(tr("Invalid key handle specified!"));
*p_value_type=-1;
return QByteArray();
}
// Get and return key value
return this->GetKeyValueHelper(hive_key,p_value_type,p_value_len);
}
/*
* GetKeyModTime
*/
int64_t RegistryHive::GetNodeModTime(QString path) {
hive_node_h node;
// Get handle to last node in path
if(!this->GetNodeHandle(path,&node)) {
this->SetError(tr("Unable to get node handle!"));
return 0;
}
// Get and return node's last modification timestamp
return this->GetNodeModTime(node);
}
/*
* GetKeyModTime
*/
int64_t RegistryHive::GetNodeModTime(int node) {
if(node==0) {
this->SetError(tr("Invalid node handle specified!"));
return 0;
}
// Get and return key's last modification timestamp
return hivex_node_timestamp(this->p_hive,node);
}
/*
* KeyValueToString
*/
QString RegistryHive::KeyValueToString(QByteArray value, int value_type) {
QString ret="";
- int i=0;
- #define ToHexStr() { \
- for(i=0;i<value.size();i++) { \
- ret.append(QString().sprintf("%02X ",(uint8_t)(value.constData()[i]))); \
- } \
- ret.chop(1); \
+ #define ToHexStr() { \
+ for(int i=0;i<value.size();i++) { \
+ ret.append(QString().sprintf("%02X ",(uint8_t)(value.constData()[i]))); \
+ } \
+ ret.chop(1); \
}
+ // Convert value according to it's type
switch(value_type) {
- case hive_t_REG_NONE:
- // Just a key without a value, but to be certain...
- ToHexStr();
- break;
case hive_t_REG_SZ:
- // A Windows string (encoding is unknown, but often UTF16-LE)
- // TODO: What happens if encoding is not UTF16-LE ??? Thx Billy!!!
- ret=value.size() ? QString().fromUtf16((ushort*)(value.constData())) : "";
- break;
case hive_t_REG_EXPAND_SZ:
- // A Windows string (encoding is unknown, but often UTF16-LE) that may
- // contain %env% (environment variable expansion) elements
- // TODO: What happens if encoding is not UTF16-LE ??? Thx Billy!!!
- ret=value.size() ? QString().fromUtf16((ushort*)(value.constData())) : "";
+ // A Windows string (REG_SZ), or a Windows string containing %env%
+ // (environment variable expansion) elements (REG_EXPAND_SZ).
+ // Encoding is unknown, but often UTF16-LE (isn't this great?)
+ // Try to detect ANSI vs UNICODE encoding
+ if(value.size()==0) {
+ ret=QString();
+ } else if(value.size()>=2 && value.endsWith(QByteArray("\x00\x00",2))) {
+ // Seems to be a unicode string, convert to host endianness and return
+ // TODO: What if it is UTF16-BE?? Thx Billy!
+ QByteArray buf=value;
+ UTF16LETOH(buf.data(),buf.size());
+ ret=QString().fromUtf16((ushort*)(buf.constData()));
+ } else if(value.endsWith(QByteArray("\x00",1))) {
+ // Seems to be an ansi string
+ ret=QString().fromAscii((char*)value.constData());
+ } else {
+ // If we can't detect encoding, return string as hex
+ ToHexStr();
+ }
break;
- case hive_t_REG_BINARY:
- // A blob of binary
- ToHexStr();
+ case hive_t_REG_MULTI_SZ:
+ // Multiple Windows strings.
+ // I suppose this is always LE encoded! M$ devs really suck!
+ ret=RegistryHive::KeyValueToStringList(value).join("\n");
break;
case hive_t_REG_DWORD:
// DWORD (32 bit integer), little endian
ret=QString().sprintf("0x%08X",LE32TOH(*(uint32_t*)value.constData()));
break;
case hive_t_REG_DWORD_BIG_ENDIAN:
// DWORD (32 bit integer), big endian
ret=QString().sprintf("0x%08X",BE32TOH(*(uint32_t*)value.constData()));
break;
- case hive_t_REG_LINK:
- // Symbolic link to another part of the registry tree
- ToHexStr();
- break;
- case hive_t_REG_MULTI_SZ:
- // Multiple Windows strings.
- // I suppose this is always LE encoded! M$ devs really suck!
- ret=RegistryHive::KeyValueToStringList(value).join("\n");
- break;
- case hive_t_REG_RESOURCE_LIST:
- // Resource list
- ToHexStr();
- break;
- case hive_t_REG_FULL_RESOURCE_DESCRIPTOR:
- // Resource descriptor
- ToHexStr();
- break;
- case hive_t_REG_RESOURCE_REQUIREMENTS_LIST:
- // Resouce requirements list
- ToHexStr();
- break;
case hive_t_REG_QWORD:
- // QWORD (64 bit integer). Usually little endian.
+ // QWORD (64 bit integer). Usually little endian (grrrr).
ret=
QString("0x%1").arg((quint64)LE64TOH(*(uint64_t*)value.constData()),
16,
16,
QChar('0'));
break;
+ case hive_t_REG_NONE:
+ case hive_t_REG_BINARY:
+ case hive_t_REG_LINK:
+ case hive_t_REG_RESOURCE_LIST:
+ case hive_t_REG_FULL_RESOURCE_DESCRIPTOR:
+ case hive_t_REG_RESOURCE_REQUIREMENTS_LIST:
default:
+ // A key without a value (REG_NONE), a blob of binary (REG_BINARY), a
+ // symbolic link to another part of the registry tree (REG_LINK), a
+ // resource list (REG_RESOURCE_LIST), a resource descriptor
+ // (FULL_RESOURCE_DESCRIPTOR), a resource requirements list
+ // (REG_RESOURCE_REQUIREMENTS_LIST) or something unknown.
+ // All these are converted to hex.
ToHexStr();
}
#undef ToHexStr
return ret;
}
/*
* KeyValueToString
*/
QString RegistryHive::KeyValueToString(QByteArray key_value,
QString format,
int offset,
int length,
bool little_endian)
{
int remaining_data_len;
const char *p_data;
QString ret="";
// Calculate how many bytes are remainig after specified offset
remaining_data_len=key_value.size()-offset;
if(!remaining_data_len>0) {
// Nothing to show
return QString();
}
// Get pointer to data at specified offset
p_data=key_value.constData();
p_data+=offset;
// Convert value
if(format=="int8" && remaining_data_len>=1) {
ret=QString().sprintf("%d",*(int8_t*)p_data);
} else if(format=="uint8" && remaining_data_len>=1) {
ret=QString().sprintf("%u",*(uint8_t*)p_data);
} else if(format=="int16" && remaining_data_len>=2) {
int16_t val;
if(little_endian) val=LE16TOH(*(int16_t*)p_data);
else val=BE16TOH(*(int16_t*)p_data);
ret=QString().sprintf("%d",val);
} else if(format=="uint16" && remaining_data_len>=2) {
uint16_t val;
if(little_endian) val=LE16TOH(*(uint16_t*)p_data);
else val=BE16TOH(*(uint16_t*)p_data);
ret=QString().sprintf("%u",val);
} else if(format=="int32" && remaining_data_len>=4) {
int32_t val;
if(little_endian) val=LE32TOH(*(int32_t*)p_data);
else val=BE32TOH(*(int32_t*)p_data);
ret=QString().sprintf("%d",val);
} else if(format=="uint32" && remaining_data_len>=4) {
uint32_t val;
if(little_endian) val=LE32TOH(*(uint32_t*)p_data);
else val=BE32TOH(*(uint32_t*)p_data);
ret=QString().sprintf("%u",val);
} else if(format=="unixtime" && remaining_data_len>=4) {
uint32_t val;
if(little_endian) val=LE32TOH(*(uint32_t*)p_data);
else val=BE32TOH(*(uint32_t*)p_data);
if(val==0) {
ret="n/a";
} else {
QDateTime date_time;
date_time.setTimeSpec(Qt::UTC);
date_time.setTime_t(val);
ret=date_time.toString("yyyy/MM/dd hh:mm:ss");
}
} else if(format=="int64" && remaining_data_len>=8) {
int64_t val;
if(little_endian) val=LE64TOH(*(int64_t*)p_data);
else val=BE64TOH(*(int64_t*)p_data);
ret=QString("%1").arg(val);
} else if(format=="uint64" && remaining_data_len>=8) {
uint64_t val;
if(little_endian) val=LE64TOH(*(uint64_t*)p_data);
else val=BE64TOH(*(uint64_t*)p_data);
ret=QString("%1").arg(val);
/*
// TODO: Check how one could implement this
} else if(format=="unixtime64" && remaining_data_len>=8) {
if(*(uint64_t*)p_data==0) {
ret="n/a";
} else {
uint64_t secs=*(uint64_t*)p_data;
QDateTime date_time;
date_time.setTimeSpec(Qt::UTC);
// Set 32bit part of date/time
date_time.setTime_t(secs&0xFFFFFFFF);
// Now add high 32bit part of date/time
date_time.addSecs(secs>>32);
ret=date_time.toString("yyyy/MM/dd hh:mm:ss");
}
*/
} else if(format=="filetime" && remaining_data_len>=8) {
uint64_t val;
if(little_endian) val=LE64TOH(*(uint64_t*)p_data);
else val=BE64TOH(*(uint64_t*)p_data);
if(val==0) {
ret="n/a";
} else {
// TODO: Warn if >32bit
QDateTime date_time;
date_time.setTimeSpec(Qt::UTC);
date_time.setTime_t(RegistryHive::FiletimeToUnixtime(val));
ret=date_time.toString("yyyy/MM/dd hh:mm:ss");
}
} else if(format=="ascii") {
if(length!=-1) {
// User specified how many bytes to convert
ret=QString().fromAscii((char*)p_data,length);
} else {
// User did not specify how many bytes to convert, make sure data is 0
// terminated
if(key_value.indexOf("\x00",offset)!=-1) {
// Data is 0 terminated
ret=QString().fromAscii((char*)p_data);
} else {
// Data is not 0 terminated, convert all remaining_data_len bytes
ret=QString().fromAscii((char*)p_data,remaining_data_len);
}
}
} else if(format=="utf16" && remaining_data_len>=2) {
+ QByteArray buf;
if(length!=-1) {
// User specified how many bytes to convert
- ret=QString().fromUtf16((ushort*)p_data,length);
+ buf=key_value.mid(offset,(length%2)==0 ? length : length-1);
+ buf.append("\x00\x00",2);
} else {
// User did not specify how many bytes to convert, make sure data is
// double 0 terminated
- if(key_value.indexOf(QByteArray("\x00\x00",2),offset)!=-1) {
+ int null_offset=RegistryHive::FindUnicodeStringEnd(key_value.mid(offset));
+ if(null_offset!=-1) {
// Data is double 0 terminated
- ret=QString().fromUtf16((ushort*)p_data);
+ buf=key_value.mid(offset,null_offset+2);
} else {
// Data is not double 0 terminated, convert all remaining_data_len bytes
- ret=QString().fromUtf16((ushort*)p_data,remaining_data_len);
+ buf=key_value.mid(offset,
+ (remaining_data_len%2)==0 ?
+ remaining_data_len : remaining_data_len-1);
+ buf.append("\x00\x00",2);
}
}
+ // Convert from requested endianness to host
+ if(little_endian) {
+ UTF16LETOH(buf.data(),buf.size());
+ } else {
+ UTF16BETOH(buf.data(),buf.size());
+ }
+ ret=QString().fromUtf16((ushort*)buf.constData());
} else {
// Unknown variant type or another error
+ // TODO: Maybe return an error
return QString();
}
return ret;
}
/*
* KeyValueToStringList
*
* Should only be used for REG_MULTI_SZ values
*/
QStringList RegistryHive::KeyValueToStringList(QByteArray value,
bool little_endian,
bool *p_ansi_encoded)
{
// Try to find value encoding (ANSI vs UNICODE)
bool is_ansi;
if(value.size()<=2) {
// http://blogs.msdn.com/b/oldnewthing/archive/2009/10/08/9904646.aspx
// Ansi version of a REG_MULTI_SZ needs to be terminated by 2 \0 chars.
// So as long as the byte array has less or equal to 2 chars, it must be
// empty.
return QStringList();
} else if(value.size()==3) {
// Only 3 chars, this can only be an ansi string consisting of 1 char and 2
// \0 to terminate it
return QStringList()
<<QString(QChar((char)*((uint8_t*)(value.constData()))));
} else if(value.size()==4) {
if((uint32_t)*((uint32_t*)(value.constData()))==0) {
// http://blogs.msdn.com/b/oldnewthing/archive/2009/10/08/9904646.aspx
// Unicode version of a REG_MULTI_SZ needs to be terminated by 4 \0 chars.
// So as long as the byte array has less or equal to 4 chars, and they are
// all 0 it must be empty.
return QStringList();
} else {
// Must be the ansi version of REG_MULTI_SZ
is_ansi=true;
}
} else if((uint32_t)*((uint32_t*)(value.right(4).constData()))==0) {
- // Value end with 4 \0 chars, it must be unicode
+ // Value ends with 4 \0 chars, it must be unicode
is_ansi=false;
} else if((uint32_t)*((uint32_t*)(value.right(3).constData()))==0) {
- // Value end with 3 \0 chars. Not possible according to the specs, but
+ // Value ends with 3 \0 chars. Not possible according to the specs, but
// already seen in values M$ is storing! Those were unicode.
is_ansi=false;
} else if((uint16_t)*((uint16_t*)(value.right(2).constData()))==0) {
- // Value only end with 2 \0 chars, it must be ansi
+ // Value only ends with 2 \0 chars, it must be ansi
is_ansi=true;
} else {
// Value has more than 4 chars but does not end in 2 or 4 \0 chars. This
// is not according to specs!
return QStringList();
}
// Convert value to string list
QStringList result=QStringList();
QByteArray buf;
int last_pos=0,cur_pos=0;
if(!is_ansi) {
// Extract unicode strings
while(last_pos<value.size() &&
- (cur_pos=value.indexOf(QByteArray("\x00\x00",2),last_pos))!=-1)
+ (cur_pos=RegistryHive::FindUnicodeStringEnd(value,last_pos))!=-1)
{
if(cur_pos==last_pos) break;
- buf=value.mid(last_pos,(cur_pos-last_pos)+3);
+ buf=value.mid(last_pos,(cur_pos-last_pos)+2);
if(little_endian) {
// Convert from LE to host
- for(int i=0;i<buf.size();i+=2) {
- *((uint16_t*)(buf.data()+i))=LE16TOH(*((uint16_t*)(buf.data()+i)));
- }
+ UTF16LETOH(buf.data(),buf.size());
} else {
// Convert from BE to host
- for(int i=0;i<buf.size();i+=2) {
- *((uint16_t*)(buf.data()+i))=BE16TOH(*((uint16_t*)(buf.data()+i)));
- }
+ UTF16BETOH(buf.data(),buf.size());
}
result.append(QString().fromUtf16((ushort*)buf.constData()));
- last_pos=cur_pos+3;
+ last_pos=cur_pos+2;
}
} else {
// Extract ansi strings
while(last_pos<value.count() &&
(cur_pos=value.indexOf(QByteArray("\x00",1),last_pos))!=-1)
{
if(cur_pos==last_pos) break;
result.append(QString().fromLocal8Bit(value.mid(last_pos,
(cur_pos-last_pos)+1)
.constData()));
last_pos=cur_pos+1;
}
}
if(p_ansi_encoded!=NULL) *p_ansi_encoded=is_ansi;
return result;
}
/*
* StringListToKeyValue
*/
QByteArray RegistryHive::StringListToKeyValue(QStringList strings,
bool little_endian,
bool ansi_encoded)
{
// Return empty key value if there are no strings
if(strings.count()==0) {
if(ansi_encoded) return QByteArray("\x00\x00",2);
else return QByteArray("\x00\x00\x00\x00",4);
}
// Convert string list
QByteArray result=QByteArray();
QString cur_string;
QByteArray buf;
QListIterator<QString> strings_it(strings);
while(strings_it.hasNext()) {
cur_string=strings_it.next();
if(ansi_encoded) {
// Ansi encoding, simply append char string and terminating \0
result.append(cur_string.toAscii().constData(),cur_string.size());
result.append("\x00",1);
} else {
// Unicode encoding
// First, convert value to utf16
// TODO: May fail if there is a char that needs more than 16 bit
buf=QByteArray((char*)(cur_string.utf16()),cur_string.size()*2);
// Then convert to correct endianness
if(little_endian) {
- for(int i=0;i<buf.size();i+=2) {
- *((uint16_t*)(buf.data()+i))=HTOLE16(*((uint16_t*)(buf.data()+i)));
- }
+ HTOUTF16LE(buf.data(),buf.size());
} else {
- for(int i=0;i<buf.size();i+=2) {
- *((uint16_t*)(buf.data()+i))=HTOBE16(*((uint16_t*)(buf.data()+i)));
- }
+ HTOUTF16BE(buf.data(),buf.size());
}
// And finally append converted value and terminating \0\0 to result
result.append(buf);
result.append("\x00\x00",2);
}
}
// Append terminating \0 chars and return
if(ansi_encoded) result.append("\x00",1);
else result.append("\x00\x00",2);
return result;
}
/*
* GetKeyValueTypes
*/
QStringList RegistryHive::GetKeyValueTypes() {
return QStringList()<<"REG_NONE"
<<"REG_SZ"
<<"REG_EXPAND_SZ"
<<"REG_BINARY"
<<"REG_DWORD"
<<"REG_DWORD_BIG_ENDIAN"
<<"REG_LINK"
<<"REG_MULTI_SZ"
<<"REG_RESOURCE_LIST"
<<"REG_FULL_RESOURCE_DESC"
<<"REG_RESOURCE_REQ_LIST"
<<"REG_QWORD";
}
/*
* KeyTypeToString
*/
QString RegistryHive::KeyValueTypeToString(int value_type) {
QString ret="";
switch(value_type) {
case hive_t_REG_NONE:
ret="REG_NONE";
break;
case hive_t_REG_SZ:
ret="REG_SZ";
break;
case hive_t_REG_EXPAND_SZ:
ret="REG_EXPAND_SZ";
break;
case hive_t_REG_BINARY:
ret="REG_BINARY";
break;
case hive_t_REG_DWORD:
ret="REG_DWORD";
break;
case hive_t_REG_DWORD_BIG_ENDIAN:
ret="REG_DWORD_BIG_ENDIAN";
break;
case hive_t_REG_LINK:
ret="REG_LINK";
break;
case hive_t_REG_MULTI_SZ:
ret="REG_MULTI_SZ";
break;
case hive_t_REG_RESOURCE_LIST:
ret="REG_RESOURCE_LIST";
break;
case hive_t_REG_FULL_RESOURCE_DESCRIPTOR:
ret="REG_FULL_RESOURCE_DESC";
break;
case hive_t_REG_RESOURCE_REQUIREMENTS_LIST:
ret="REG_RESOURCE_REQ_LIST";
break;
case hive_t_REG_QWORD:
ret="REG_QWORD";
break;
default:
ret=QString().sprintf("0x%08X",(uint32_t)value_type);
}
return ret;
}
/*
* StringToKeyValueType
*/
int RegistryHive::StringToKeyValueType(QString value_type) {
if(value_type=="REG_NONE") return hive_t_REG_NONE;
if(value_type=="REG_SZ") return hive_t_REG_SZ;
if(value_type=="REG_EXPAND_SZ") return hive_t_REG_EXPAND_SZ;
if(value_type=="REG_BINARY") return hive_t_REG_BINARY;
if(value_type=="REG_DWORD") return hive_t_REG_DWORD;
if(value_type=="REG_DWORD_BIG_ENDIAN") return hive_t_REG_DWORD_BIG_ENDIAN;
if(value_type=="REG_LINK") return hive_t_REG_LINK;
if(value_type=="REG_MULTI_SZ") return hive_t_REG_MULTI_SZ;
if(value_type=="REG_RESOURCE_LIST") return hive_t_REG_RESOURCE_LIST;
if(value_type=="REG_FULL_RESOURCE_DESC")
return hive_t_REG_FULL_RESOURCE_DESCRIPTOR;
if(value_type=="REG_RESOURCE_REQ_LIST")
return hive_t_REG_RESOURCE_REQUIREMENTS_LIST;
if(value_type=="REG_QWORD") return hive_t_REG_QWORD;
// I think this might be a good default :-)
return hive_t_REG_BINARY;
}
/*
* FiletimeToUnixtime
*/
uint64_t RegistryHive::FiletimeToUnixtime(int64_t filetime) {
return (unsigned)((filetime-EPOCH_DIFF)/10000000);
}
/*
* AddNode
*/
int RegistryHive::AddNode(QString parent_node_path, QString node_name) {
if(!this->is_hive_writable) return 0;
// Make sure name does not contain a backslash char
if(node_name.contains('\\')) {
this->SetError(tr("Unable to add node with name '%1'. "
"Names can not include a backslash character.")
.arg(node_name));
return 0;
}
// Get node handle to the parent where the new node should be created
hive_node_h parent_node;
if(!this->GetNodeHandle(parent_node_path,&parent_node)) {
this->SetError(tr("Unable to get node handle for '%1'!")
.arg(parent_node_path));
return 0;
}
// Make sure there is no other node with same name
QMap<QString,int> child_nodes=this->GetNodes(parent_node);
if(child_nodes.contains(node_name.toAscii())) {
this->SetError(tr("The node '%1\\%2' already exists!")
.arg(parent_node_path,node_name));
return 0;
}
// Add new node
hive_node_h new_node=hivex_node_add_child(this->p_hive,
parent_node,
node_name.toAscii().constData());
if(new_node==0) {
this->SetError(tr("Unable to create new node '%1\\%2'!")
.arg(parent_node_path,node_name));
return 0;
}
this->has_changes_to_commit=true;
return new_node;
}
/*
* DeleteNode
*/
bool RegistryHive::DeleteNode(QString node_path) {
if(!this->is_hive_writable) return false;
// Get node handle to the node that should be deleted
hive_node_h node;
if(!this->GetNodeHandle(node_path,&node)) {
this->SetError(tr("Unable to get node handle for '%1'!")
.arg(node_path));
return false;
}
// Delete node
if(hivex_node_delete_child(this->p_hive,node)==-1) {
this->SetError(tr("Unable to delete node '%1'!")
.arg(node_path));
return false;
}
this->has_changes_to_commit=true;
return true;
}
/*
* AddKey
*/
int RegistryHive::AddKey(QString parent_node_path,
QString key_name,
QString key_value_type,
QByteArray key_value)
{
if(!this->is_hive_open || !this->is_hive_writable) {
this->SetError(tr("Hive has not been opened or opened read-only!"));
return false;
}
return this->SetKey(parent_node_path,
key_name,
key_value_type,
key_value,
true);
}
/*
* UpdateKey
*/
int RegistryHive::UpdateKey(QString parent_node_path,
QString key_name,
QString key_value_type,
QByteArray key_value)
{
if(!this->is_hive_open || !this->is_hive_writable) {
this->SetError(tr("Hive has not been opened or opened read-only!"));
return false;
}
return this->SetKey(parent_node_path,
key_name,
key_value_type,
key_value,
false);
}
/*
* DeleteKey
*/
bool RegistryHive::DeleteKey(QString parent_node_path, QString key_name) {
if(!this->is_hive_open || !this->is_hive_writable) {
this->SetError(tr("Hive has not been opened or opened read-only!"));
return false;
}
// libhivex offers no possibility to delete a single key :-(
// As a work around, this function temporarly stores all keys of the specified
// node, then deletes them all an re-creates all but the one that should be
// deleted.
// Get handle to parent node
hive_node_h parent_node;
if(!this->GetNodeHandle(parent_node_path,&parent_node)) {
return false;
}
// Get all child keys
hive_value_h *p_keys=hivex_node_values(this->p_hive,parent_node);
if(p_keys==NULL) {
this->SetError(tr("Unable to enumerate child keys for parent '%1'!")
.arg(parent_node_path));
return false;
}
// Get all child key values except the one that should be deleted
int i=0;
char *p_name;
int node_keys_count=0;
hive_set_value *node_keys=NULL;
#define FREE_NODE_KEYS() { \
for(int x=0;x<node_keys_count;x++) { \
free(node_keys[x].key); \
free(node_keys[x].value); \
} \
free(node_keys); \
}
while(p_keys[i]) {
p_name=hivex_value_key(this->p_hive,p_keys[i]);
if(p_name==NULL) {
this->SetError(tr("Unable to get key name for a child of '%1'!")
.arg(parent_node_path));
return false;
}
if(QString(p_name)!=key_name) {
// Current key is not the one that should be deleted, save it
// Alloc mem for new hive_set_value struct in node_keys array
node_keys=(hive_set_value*)realloc(node_keys,
sizeof(hive_set_value)*
(node_keys_count+1));
if(node_keys==NULL) {
this->SetError(tr("Unable to alloc enough memory for all child keys!"));
return false;
}
// Save key name in hive_set_value struct
node_keys[node_keys_count].key=p_name;
// Get key value, key value type and key value len and save to
// hive_set_value struct
node_keys[node_keys_count].value=
hivex_value_value(this->p_hive,
p_keys[i],
&(node_keys[node_keys_count].t),
&(node_keys[node_keys_count].len));
if(node_keys[node_keys_count].value==NULL) {
this->SetError(tr("Unable to get value for key '%1'!").arg(p_name));
free(p_name);
// Free all temporary stored keys
FREE_NODE_KEYS();
return false;
}
node_keys_count++;
} else {
// Current key is to be deleted, ignore it
free(p_name);
}
i++;
}
// Save all stored keys to hive, which will discard the one that should be
// deleted
if(hivex_node_set_values(this->p_hive,
parent_node,
node_keys_count,
node_keys,
0)!=0)
{
this->SetError(tr("Unable to re-save all child keys! Please discard any "
"changes you made and start over. No doing so might end "
"in data loss!"));
// Free all temporary stored keys
FREE_NODE_KEYS();
return false;
}
// Free all temporary stored keys and return
FREE_NODE_KEYS();
#undef FREE_NODE_KEYS
this->has_changes_to_commit=true;
return true;
}
/*******************************************************************************
* Private
******************************************************************************/
/*
* HivexError2String
*/
QString RegistryHive::HivexError2String(int error) {
switch(error) {
case ENOTSUP:
return QString("Corrupt or unsupported Registry file format.");
break;
case HIVEX_NO_KEY:
return QString("Missing root key.");
break;
case EINVAL:
return QString("Passed an invalid argument to the function.");
break;
case EFAULT:
return QString("Followed a Registry pointer which goes outside the "
"registry or outside a registry block.");
break;
case ELOOP:
return QString("Registry contains cycles.");
break;
case ERANGE:
return QString("Field in the registry out of range.");
break;
case EEXIST:
return QString("Registry key already exists.");
break;
case EROFS:
return QString("Tried to write to a registry which is not opened for "
"writing.");
break;
default:
return QString("Unknown error.");
}
}
/*
* SetError
*/
void RegistryHive::SetError(QString msg) {
this->erro_msg=msg;
this->is_error=true;
}
/*
* GetNodeHandle
*/
bool RegistryHive::GetNodeHandle(QString &path, hive_node_h *p_node) {
QStringList nodes;
int i=0;
// Get root node handle
*p_node=hivex_root(this->p_hive);
if(*p_node==0) {
this->SetError(tr("Unable to get root node!"));
return false;
}
if(path!="\\") {
// If we aren't listing the root node, we have to get a handle to the
// last node in the path. Split path into nodes
nodes=path.split('\\',QString::SkipEmptyParts);
// Iterate to the correct parent node
for(i=0;i<nodes.count();i++) {
*p_node=hivex_node_get_child(this->p_hive,
*p_node,
nodes.value(i).toAscii().constData());
if(*p_node==0) {
this->SetError(tr("Unable to find node '%1'!").arg(nodes.value(i)));
return false;
}
}
}
return true;
}
/*
* GetKeyHandle
*/
bool RegistryHive::GetKeyHandle(QString &parent_node_path,
QString &key_name,
hive_value_h *p_key)
{
// Get handle to parent node
hive_node_h parent_node;
if(!this->GetNodeHandle(parent_node_path,&parent_node)) {
return false;
}
// Get handle to key
*p_key=hivex_node_get_value(this->p_hive,
parent_node,
key_name.toAscii().constData());
if(*p_key==0) {
this->SetError(tr("Unable to get handle to key '%1\\%2'!")
.arg(parent_node_path,key_name));
return false;
}
return true;
}
/*
* GetNodesHelper
*/
QMap<QString,int> RegistryHive::GetNodesHelper(hive_node_h parent_node) {
QMap<QString,int> keys;
char *p_name;
int i=0;
// Get child nodes
hive_node_h *child_nodes=hivex_node_children(this->p_hive,parent_node);
if(child_nodes==NULL) {
this->SetError(
tr("Unable to enumerate child nodes!"));
return QMap<QString,int>();
}
// Build result
keys.clear();
i=0;
while(child_nodes[i]) {
p_name=hivex_node_name(this->p_hive,child_nodes[i]);
if(p_name==NULL) {
this->SetError(tr("Unable to get node name!"));
free(child_nodes);
return QMap<QString,int>();
}
keys.insert(QString(p_name),(int)child_nodes[i]);
free(p_name);
i++;
}
free(child_nodes);
return keys;
}
/*
* GetKeysHelper
*/
QMap<QString,int> RegistryHive::GetKeysHelper(hive_node_h parent_node) {
QMap<QString,int> keys;
char *p_name;
int i=0;
// Get child keys
hive_value_h *p_keys=hivex_node_values(this->p_hive,parent_node);
if(p_keys==NULL) {
this->SetError(
tr("Unable to enumerate child keys!"));
return QMap<QString,int>();
}
// Build result list
keys.clear();
i=0;
while(p_keys[i]) {
p_name=hivex_value_key(this->p_hive,p_keys[i]);
if(p_name==NULL) {
this->SetError(tr("Unable to get key name!"));
return QMap<QString,int>();
}
keys.insert(QString(p_name),p_keys[i]);
free(p_name);
i++;
}
free(p_keys);
return keys;
}
/*
* GetKeyValueHelper
*/
QByteArray RegistryHive::GetKeyValueHelper(hive_value_h hive_key,
int *p_value_type,
size_t *p_value_len)
{
QByteArray key_value;
char *p_key_value;
p_key_value=hivex_value_value(this->p_hive,
hive_key,
(hive_type*)p_value_type,
p_value_len);
if(p_key_value==NULL) {
this->SetError(tr("Unable to get key value!"));
*p_value_type=-1;
return QByteArray();
}
// Feed QByteArray and free p_key_value
key_value=QByteArray(p_key_value,*p_value_len);
free(p_key_value);
return key_value;
}
/*
* PathExists
*/
bool RegistryHive::PathExists(QString path) {
bool ret;
hive_node_h node;
ret=this->GetNodeHandle(path,&node);
if(!ret || this->Error()) {
// Clear error and return false
this->GetErrorMsg();
return false;
}
return true;
}
/*
* SetKey
*/
int RegistryHive::SetKey(QString &parent_node_path,
QString &key_name,
QString &key_value_type,
QByteArray &key_value,
bool create_key)
{
// Get node handle to the node that holds the key to create/update
hive_node_h parent_node;
if(!this->GetNodeHandle(parent_node_path,&parent_node)) {
return 0;
}
// Make sure key exists if we should update it
if(!create_key) {
hive_value_h temp_key=hivex_node_get_value(this->p_hive,
parent_node,
key_name.toAscii().constData());
if(temp_key==0) {
this->SetError(tr("Inexisting key '%1\\%2' can't be updated!")
.arg(parent_node_path,key_name));
return 0;
}
}
// Create and populate hive_set_value structure
hive_set_value key_val;
key_val.key=(char*)malloc((sizeof(char)*key_name.toAscii().count())+1);
key_val.value=(char*)malloc(sizeof(char)*key_value.size());
if(key_val.key==NULL || key_val.value==NULL) {
this->SetError(tr("Unable to alloc memory for hive_set_value struct!"));
return 0;
}
strcpy(key_val.key,key_name.toAscii().constData());
key_val.t=(hive_type)this->StringToKeyValueType(key_value_type);
key_val.len=key_value.size();
memcpy(key_val.value,key_value.constData(),key_value.size());
// Create/Update key
if(hivex_node_set_value(this->p_hive,parent_node,&key_val,0)!=0) {
this->SetError(tr("Unable to update key '%1\\%2'!")
.arg(parent_node_path,key_name));
return 0;
}
// Free the hive_set_value structure
free(key_val.key);
free(key_val.value);
// To make sure everything worked, a hadle to the new key is now requeried
// from hive and then returned
hive_value_h key;
if(!this->GetKeyHandle(parent_node_path,key_name,&key)) {
return 0;
}
this->has_changes_to_commit=true;
return key;
}
+
+/*
+ * FindUnicodeStringEnd
+ */
+int RegistryHive::FindUnicodeStringEnd(QByteArray data, int offset) {
+ int end_pos;
+ for(end_pos=offset;end_pos<(data.size()-1);end_pos+=2) {
+ if(*((uint16_t*)(data.constData()+end_pos))==0) break;
+ }
+ return end_pos<(data.size()-1) ? end_pos : -1;
+}
diff --git a/trunk/registryhive.h b/trunk/registryhive.h
index b9a319b..b782a03 100644
--- a/trunk/registryhive.h
+++ b/trunk/registryhive.h
@@ -1,131 +1,132 @@
/*******************************************************************************
* fred Copyright (c) 2011-2013 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 REGISTRYHIVE_H
#define REGISTRYHIVE_H
#include <QObject>
#include <QMap>
#include <hivex.h>
class RegistryHive : public QObject {
Q_OBJECT
public:
typedef enum eHiveType {
eHiveType_UNKNOWN=0,
eHiveType_SYSTEM,
eHiveType_SOFTWARE,
eHiveType_SAM,
eHiveType_SECURITY,
eHiveType_NTUSER
} teHiveType;
explicit RegistryHive(QObject *p_parent=0);
~RegistryHive();
bool Error();
QString GetErrorMsg();
bool Open(QString file, bool read_only=true);
bool Reopen(bool read_only=true);
bool CommitChanges();
bool Close();
QString Filename();
teHiveType HiveType();
QString HiveTypeToString(teHiveType hive_type);
bool HasChangesToCommit();
QMap<QString,int> GetNodes(QString path="\\");
QMap<QString,int> GetNodes(int parent_node=0);
QMap<QString,int> GetKeys(QString path="\\");
QMap<QString,int> GetKeys(int parent_node=0);
bool GetKeyName(int hive_key, QString &key_name);
QByteArray GetKeyValue(QString path,
QString key,
int *p_value_type,
size_t *p_value_len);
QByteArray GetKeyValue(int hive_key,
int *p_value_type,
size_t *p_value_len);
int64_t GetNodeModTime(QString path);
int64_t GetNodeModTime(int node);
static QString KeyValueToString(QByteArray value, int value_type);
static QString KeyValueToString(QByteArray value,
QString format,
int offset=0,
int length=-1,
bool little_endian=true);
static QStringList KeyValueToStringList(QByteArray value,
bool little_endian=true,
bool *p_ansi_encoded=NULL);
static QByteArray StringListToKeyValue(QStringList strings,
bool little_endian=true,
bool ansi_encoded=false);
static QStringList GetKeyValueTypes();
static QString KeyValueTypeToString(int value_type);
static int StringToKeyValueType(QString value_type);
static uint64_t FiletimeToUnixtime(int64_t filetime);
int AddNode(QString parent_node_path, QString node_name);
bool DeleteNode(QString node_path);
int AddKey(QString parent_node_path,
QString key_name,
QString key_value_type,
QByteArray key_value);
int UpdateKey(QString parent_node_path,
QString key_name,
QString key_value_type,
QByteArray key_value);
bool DeleteKey(QString parent_node_path, QString key_name);
private:
QString erro_msg;
bool is_error;
QString hive_file;
hive_h *p_hive;
bool is_hive_open;
bool is_hive_writable;
bool has_changes_to_commit;
QString HivexError2String(int error);
void SetError(QString msg);
bool GetNodeHandle(QString &path, hive_node_h *p_node);
bool GetKeyHandle(QString &parent_node_path,
QString &key_name,
hive_value_h *p_key);
QMap<QString,int> GetNodesHelper(hive_node_h parent_node);
QMap<QString,int> GetKeysHelper(hive_node_h parent_node);
QByteArray GetKeyValueHelper(hive_value_h hive_key,
int *p_value_type,
size_t *p_value_len);
bool PathExists(QString path);
int SetKey(QString &parent_node_path,
QString &key_name,
QString &key_value_type,
QByteArray &key_value,
bool create_key);
+ static int FindUnicodeStringEnd(QByteArray data, int offset=0);
};
#endif // REGISTRYHIVE_H
diff --git a/trunk/registrykeytable.cpp b/trunk/registrykeytable.cpp
index d01cfe5..a15e7b8 100644
--- a/trunk/registrykeytable.cpp
+++ b/trunk/registrykeytable.cpp
@@ -1,211 +1,213 @@
/*******************************************************************************
* fred Copyright (c) 2011-2013 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 "registrykeytable.h"
#include <QHeaderView>
#include <QApplication>
#include <QClipboard>
/*******************************************************************************
* Public
******************************************************************************/
RegistryKeyTable::RegistryKeyTable(QWidget *p_parent) : QTableView(p_parent) {
this->is_writable=false;
// Configure widget
this->setSelectionMode(QAbstractItemView::SingleSelection);
this->setSelectionBehavior(QAbstractItemView::SelectRows);
this->setAutoScroll(false);
this->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
this->verticalHeader()->setHidden(true);
this->setTextElideMode(Qt::ElideNone);
// Create context menu item
this->p_action_add_key=new QAction(tr("Add new key"),this);
this->p_action_edit_key=new QAction(tr("Edit selected key"),this);
this->p_action_delete_key=new QAction(tr("Delete selected key"),this);
this->p_menu_copy=new QMenu(tr("Copy"),this);
this->p_action_copy_key_name=
new QAction(tr("Selected key name"),this->p_menu_copy);
this->p_menu_copy->addAction(this->p_action_copy_key_name);
this->p_action_copy_key_value=
new QAction(tr("Selected key value"),this->p_menu_copy);
this->p_menu_copy->addAction(this->p_action_copy_key_value);
// Connect context menu signals
this->connect(this->p_action_add_key,
SIGNAL(triggered()),
this,
SLOT(SlotAddKey()));
this->connect(this->p_action_edit_key,
SIGNAL(triggered()),
this,
SLOT(SlotEditKey()));
this->connect(this->p_action_delete_key,
SIGNAL(triggered()),
this,
SLOT(SlotDeleteKey()));
this->connect(this->p_action_copy_key_name,
SIGNAL(triggered()),
this,
SLOT(SlotCopyKeyName()));
this->connect(this->p_action_copy_key_value,
SIGNAL(triggered()),
this,
SLOT(SlotCopyKeyValue()));
}
RegistryKeyTable::~RegistryKeyTable() {
// Delete context menu
delete this->p_action_copy_key_name;
delete this->p_action_copy_key_value;
delete this->p_menu_copy;
delete this->p_action_delete_key;
delete this->p_action_edit_key;
delete this->p_action_add_key;
}
void RegistryKeyTable::setModel(QAbstractItemModel *p_model, bool writable) {
QTableView::setModel(p_model);
// Resize table rows / columns to fit data
this->resizeColumnsToContents();
this->resizeRowsToContents();
this->horizontalHeader()->stretchLastSection();
if(p_model!=NULL && p_model->rowCount()>0) {
// Select first table item
this->selectRow(0);
}
// Set writable status
this->SetWritable(writable);
}
void RegistryKeyTable::SetWritable(bool writable) {
this->is_writable=writable;
this->p_action_add_key->setEnabled(this->is_writable);
this->p_action_edit_key->setEnabled(this->is_writable);
this->p_action_delete_key->setEnabled(this->is_writable);
}
/*
void RegistryKeyTable::selectRow(QString key_name) {
int i;
this->clearSelection();
for(i=0;i<this->model()->rowCount();i++) {
if(this->model())
}
}
*/
/*******************************************************************************
* Protected
******************************************************************************/
int RegistryKeyTable::sizeHintForColumn(int column) const {
int size_hint=-1;
int i=0;
int item_width=0;
QFontMetrics fm(this->fontMetrics());
QModelIndex idx;
if(this->model()==NULL) return -1;
// Find string that needs the most amount of space
idx=this->model()->index(i,column);
while(idx.isValid()) {
item_width=fm.width(this->model()->data(idx).toString())+10;
if(item_width>size_hint) size_hint=item_width;
idx=this->model()->index(++i,column);
}
return size_hint;
}
void RegistryKeyTable::contextMenuEvent(QContextMenuEvent *p_event) {
// Only show context menu if a hive is open (a model was set)
if(this->model()==NULL) return;
// Decide what menus should be enabled
if(this->selectedIndexes().count()==3) {
// A row is selected, enable full context menu
- this->p_action_edit_key->setEnabled(true);
- this->p_action_delete_key->setEnabled(true);
+ this->p_action_add_key->setEnabled(this->is_writable);
+ this->p_action_edit_key->setEnabled(this->is_writable);
+ this->p_action_delete_key->setEnabled(this->is_writable);
this->p_menu_copy->setEnabled(true);
} else {
// No row is selected, disable all menu items except AddKey
+ this->p_action_add_key->setEnabled(this->is_writable);
this->p_action_edit_key->setEnabled(false);
this->p_action_delete_key->setEnabled(false);
this->p_menu_copy->setEnabled(false);
}
// Emit clicked signal (makes sure item under cursor is selected if it wasn't)
emit(this->clicked(this->indexAt(p_event->pos())));
// Create context menu, add actions and show it
QMenu context_menu(this);
context_menu.addAction(this->p_action_add_key);
context_menu.addAction(this->p_action_edit_key);
context_menu.addAction(this->p_action_delete_key);
context_menu.addSeparator();
context_menu.addMenu(this->p_menu_copy);
context_menu.exec(p_event->globalPos());
}
void RegistryKeyTable::currentChanged(const QModelIndex ¤t,
const QModelIndex &previous)
{
// Call parent class's currentChanged first
QTableView::currentChanged(current,previous);
// Now emit our signal
QModelIndex current_item=QModelIndex(current);
emit(RegistryKeyTable::CurrentItemChanged(current_item));
}
/*******************************************************************************
* Private slots
******************************************************************************/
void RegistryKeyTable::SlotAddKey() {
emit(this->SignalAddKey());
}
void RegistryKeyTable::SlotEditKey() {
emit(this->SignalEditKey(this->selectedIndexes().at(0)));
}
void RegistryKeyTable::SlotDeleteKey() {
emit(this->SignalDeleteKey(this->selectedIndexes().at(0)));
}
void RegistryKeyTable::SlotCopyKeyName() {
QApplication::clipboard()->
setText(this->selectedIndexes().at(0).data().toString(),
QClipboard::Clipboard);
}
void RegistryKeyTable::SlotCopyKeyValue() {
QApplication::clipboard()->
setText(this->selectedIndexes().at(2).data().toString(),
QClipboard::Clipboard);
}
diff --git a/trunk/report_templates/NTUSER_Autoruns.qs b/trunk/report_templates/NTUSER_Autoruns.qs
index f0a40a0..e67797c 100644
--- a/trunk/report_templates/NTUSER_Autoruns.qs
+++ b/trunk/report_templates/NTUSER_Autoruns.qs
@@ -1,61 +1,56 @@
function fred_report_info() {
var info={report_cat : "NTUSER",
report_name : "Autoruns",
report_author : "Gillen Daniel",
report_desc : "Dump autorun keys",
fred_api : 2,
hive : "NTUSER"
};
return info;
}
function IsValid(val) {
if(typeof val !== 'undefined') return true;
else return false;
}
function print_table_row(cell01,cell02) {
println(" <tr><td>",cell01,"</td><td>",cell02,"</td></tr>");
}
function ListAutoruns(autorun_path,autorun_key) {
println(" <p style=\"font-size:12; white-space:nowrap\">");
println(" <u>"+autorun_key+"</u><br />");
var run_keys=GetRegistryKeys(autorun_path+autorun_key);
if(IsValid(run_keys) && run_keys.length>0) {
println(" <table style=\"margin-left:20px; font-size:12; white-space:nowrap\">");
print_table_row("<b>Name</b>","<b>Executable</b>");
for(var i=0;i<run_keys.length;i++) {
var val=GetRegistryKeyValue(autorun_path+autorun_key,run_keys[i]);
print_table_row(run_keys[i],RegistryKeyValueToString(val.value,val.type));
}
println(" </table>");
} else {
println(" None");
}
println(" </p>");
}
function fred_report_html() {
var val;
-// println("<html>");
-// println(" <head><title>User Autoruns</title></head>");
-// println(" <body style=\"font-size:12\">");
println(" <h2>User Autoruns</h2>");
// Run
ListAutoruns("\\Microsoft\\Windows\\CurrentVersion\\","Run");
// RunOnce
ListAutoruns("\\Microsoft\\Windows\\CurrentVersion\\","RunOnce");
// RunOnceEx
ListAutoruns("\\Microsoft\\Windows\\CurrentVersion\\","RunOnceEx");
// TODO: There might be a Run under WindowsNT\CurrentVersion\Run too!
-
-// println("</html>");
}
diff --git a/trunk/report_templates/NTUSER_LaunchedApplications.qs b/trunk/report_templates/NTUSER_LaunchedApplications.qs
index 1e4bb61..346296f 100644
--- a/trunk/report_templates/NTUSER_LaunchedApplications.qs
+++ b/trunk/report_templates/NTUSER_LaunchedApplications.qs
@@ -1,111 +1,108 @@
function fred_report_info() {
var info={report_cat : "NTUSER",
report_name : "Launched applications",
report_author : "Gillen Daniel",
report_desc : "Dump IE launched applications",
fred_api : 2,
hive : "NTUSER"
};
return info;
}
function IsValid(val) {
if(typeof val !== 'undefined') return true;
else return false;
}
function PrintTableRow(cell01,cell02,cell03) {
println(" <tr><td style=\"white-space:nowrap\">",cell01,"</td><td style=\"padding:2px; white-space:nowrap\">",cell02,"</td><td style=\"padding:2px; white-space:nowrap\">",cell03,"</td></tr>");
}
function Rot13Decode(val) {
var ret="";
for(var i=0;i<val.length;i++) {
var decoded=val.charCodeAt(i);
if((decoded>64 && decoded<91) || (decoded>96 && decoded<123)) {
if((decoded-13)<65 || (decoded>96 && (decoded-13)<97)) {
decoded=(decoded-13)+26;
} else {
if(decoded>96 && (decoded-13)<97) {
decoded+=13;
} else {
decoded-=13;
}
}
ret+=String.fromCharCode(decoded);
} else {
ret+=val[i];
}
}
return ret;
}
function PrintUserAssistEntry(key,val,os) {
var run_count;
var last_run;
switch(os) {
case "winxp":
run_count=RegistryKeyValueToVariant(val.value,"uint32",4);
break;
case "win7":
run_count=RegistryKeyValueToVariant(val.value,"uint32",4,0,1);
last_run=RegistryKeyValueToVariant(val.value,"filetime",60);
break;
}
PrintTableRow(key,run_count,last_run);
}
function fred_report_html() {
-// println("<html>");
-// println(" <head><title>Launched Applications</title></head>");
-// println(" <body style=\"font-size:12\">");
println(" <h2>Launched applications</h2>");
// First, we need to find the correct GUID for the current Windows version
var path;
var apps;
var os;
// Windows XP
os="winxp";
path="\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\UserAssist\\{5E6AB780-7743-11CF-A12B-00AA004AE837}\\Count";
apps=GetRegistryKeys(path);
// TODO: Determine GUIDs for Vista / Win8
if(!IsValid(apps)) {
// Windows 7
os="win7";
path="\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\UserAssist\\{CEBFF5CD-ACE2-4F4F-9178-9926F41749EA}\\Count";
apps=GetRegistryKeys(path);
}
if(IsValid(apps)) {
if(apps.length!=0) {
println(" <p style=\"font-size:12\">");
println(" <table style=\"margin-left:20px; font-size:12\">");
println(" <tr><td><b>Application</b></td><td style=\"padding:2px\"><b>Run count</b></td><td style=\"padding:2px\"><b>Last run</b></td></tr>");
for(var i=0;i<apps.length;i++) {
var val=GetRegistryKeyValue(path,apps[i]);
PrintUserAssistEntry(Rot13Decode(apps[i]),val,os);
}
println(" </table>");
println(" </p>");
} else {
println(" <p><font color='red'>");
println(" The list of launched applications is empty.");
println(" </font></p>");
}
} else {
println(" <p><font color='red'>");
println(" This registry hive does not contain a list of launched applications!");
println(" </font></p>");
}
}
diff --git a/trunk/report_templates/NTUSER_RecentDocs.qs b/trunk/report_templates/NTUSER_RecentDocs.qs
index 32228fe..bd8b2fa 100644
--- a/trunk/report_templates/NTUSER_RecentDocs.qs
+++ b/trunk/report_templates/NTUSER_RecentDocs.qs
@@ -1,54 +1,49 @@
function fred_report_info() {
var info={report_cat : "NTUSER",
report_name : "Recent documents",
report_author : "Gillen Daniel",
report_desc : "Dump recent docs",
fred_api : 2,
hive : "NTUSER"
};
return info;
}
function IsValid(val) {
if(typeof val !== 'undefined') return true;
else return false;
}
function fred_report_html() {
-// println("<html>");
-// println(" <head><title>Recent Documents</title></head>");
-// println(" <body style=\"font-size:12\">");
println(" <h2>Recent documents</h2>");
// Get list of recent docs
var recent_docs=GetRegistryKeyValue("\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RecentDocs","MRUListEx");
if(IsValid(recent_docs)) {
// Iterate over all recent docs
var i=0;
var runlist=RegistryKeyValueToVariant(recent_docs.value,"uint32",i);
if(Number(runlist)!=0xffffffff) {
println(" <p style=\"font-size:12\">");
println(" <table style=\"margin-left:20px; font-size:12\">");
while(Number(runlist)!=0xffffffff) {
var entry=GetRegistryKeyValue("\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RecentDocs",runlist.toString(10));
println(" <tr><td style=\"white-space:nowrap\">",RegistryKeyValueToVariant(entry.value,"utf16",0),"</td></tr>");
i+=4;
runlist=RegistryKeyValueToVariant(recent_docs.value,"uint32",i);
}
println(" </table>");
println(" </p>");
} else {
println(" <p><font color='red'>");
println(" The list of recent documents is empty.");
println(" </font></p>");
}
} else {
println(" <p><font color='red'>");
println(" This registry hive does not contain a list of recent documents!");
println(" </font></p>");
}
-
-// println("</html>");
}
diff --git a/trunk/report_templates/NTUSER_TypedUrls.qs b/trunk/report_templates/NTUSER_TypedUrls.qs
index f5c4e1c..d8465c7 100644
--- a/trunk/report_templates/NTUSER_TypedUrls.qs
+++ b/trunk/report_templates/NTUSER_TypedUrls.qs
@@ -1,49 +1,44 @@
function fred_report_info() {
var info={report_cat : "NTUSER",
report_name : "Typed URLs",
report_author : "Gillen Daniel",
report_desc : "Dump typed URLs",
fred_api : 2,
hive : "NTUSER"
};
return info;
}
function IsValid(val) {
if(typeof val !== 'undefined') return true;
else return false;
}
function fred_report_html() {
-// println("<html>");
-// println(" <head><title>Typed Urls</title></head>");
-// println(" <body style=\"font-size:12\">");
println(" <h2>Typed urls</h2>");
// Iterate over all typed urls
var typed_urls=GetRegistryKeys("\\Software\\Microsoft\\Internet Explorer\\TypedURLs");
if(IsValid(typed_urls)) {
if(typed_urls.length!=0) {
println(" <p style=\"font-size:12\">");
println(" <table style=\"margin-left:20px; font-size:12\">");
for(var i=0;i<typed_urls.length;i++) {
var val=GetRegistryKeyValue("\\Software\\Microsoft\\Internet Explorer\\TypedURLs",typed_urls[i]);
println(" <tr><td style=\"white-space:nowrap\">",RegistryKeyValueToString(val.value,val.type),"</td></tr>");
}
println(" </table>");
println(" </p>");
} else {
println(" <p><font color='red'>");
println(" The list of typed urls is empty.");
println(" </font></p>");
}
} else {
println(" <p><font color='red'>");
println(" This registry hive does not contain a list of typed urls!");
println(" </font></p>");
}
-
-// println("</html>");
}
diff --git a/trunk/report_templates/NTUSER_Windows7_SearchKeywords.qs b/trunk/report_templates/NTUSER_Windows7_SearchKeywords.qs
index fe97c28..b4afed4 100644
--- a/trunk/report_templates/NTUSER_Windows7_SearchKeywords.qs
+++ b/trunk/report_templates/NTUSER_Windows7_SearchKeywords.qs
@@ -1,54 +1,49 @@
function fred_report_info() {
var info={report_cat : "NTUSER",
report_name : "Windows 7 search keywords",
report_author : "Gillen Daniel",
report_desc : "Dump Windows 7 search keywords",
fred_api : 2,
hive : "NTUSER"
};
return info;
}
function IsValid(val) {
if(typeof val !== 'undefined') return true;
else return false;
}
function fred_report_html() {
-// println("<html>");
-// println(" <head><title>Document And Folder Search Keywords</title></head>");
-// println(" <body style=\"font-size:12\">");
println(" <h2>Document and folder search keywords</h2>");
// Get list of search keys
var mrulist=GetRegistryKeyValue("\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\WordWheelQuery","MRUListEx");
if(IsValid(mrulist)) {
// Iterate over all items
var i=0;
var runlist=RegistryKeyValueToVariant(mrulist.value,"uint32",i);
if(Number(runlist)!=0xffffffff) {
println(" <p style=\"font-size:12\">");
println(" <table style=\"margin-left:20px; font-size:12\">");
while(Number(runlist)!=0xffffffff) {
var entry=GetRegistryKeyValue("\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\WordWheelQuery",runlist.toString(10));
println(" <tr><td style=\"white-space:nowrap\">",RegistryKeyValueToVariant(entry.value,"utf16",0),"</td></tr>");
i+=4;
runlist=RegistryKeyValueToVariant(mrulist.value,"uint32",i);
}
println(" </table>");
println(" </p>");
} else {
println(" <p><font color='red'>");
println(" The list of document and search keywords is empty.");
println(" </font></p>");
}
} else {
println(" <p><font color='red'>");
println(" This registry hive does not contain a list of document and folder search keywords!");
println(" </font></p>");
}
-
-// println("</html>");
}
diff --git a/trunk/report_templates/NTUSER_Windows7_TypedPaths.qs b/trunk/report_templates/NTUSER_Windows7_TypedPaths.qs
index 947a9c6..96ccb20 100644
--- a/trunk/report_templates/NTUSER_Windows7_TypedPaths.qs
+++ b/trunk/report_templates/NTUSER_Windows7_TypedPaths.qs
@@ -1,49 +1,44 @@
function fred_report_info() {
var info={report_cat : "NTUSER",
report_name : "Windows 7 typed paths",
report_author : "Gillen Daniel",
report_desc : "Dump Windows 7 typed paths",
fred_api : 2,
hive : "NTUSER"
};
return info;
}
function IsValid(val) {
if(typeof val !== 'undefined') return true;
else return false;
}
function fred_report_html() {
-// println("<html>");
-// println(" <head><title>Typed Paths</title></head>");
-// println(" <body style=\"font-size:12\">");
println(" <h2>Typed paths</h2>");
// Iterate over all typed paths
var urls=GetRegistryKeys("\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\TypedPaths");
if(IsValid(urls)) {
if(urls.length!=0) {
println(" <p style=\"font-size:12\">");
println(" <table style=\"margin-left:20px; font-size:12\">");
for(var i=0;i<urls.length;i++) {
var val=GetRegistryKeyValue("\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\TypedPaths",urls[i]);
println(" <tr><td style=\"white-space:nowrap\">",RegistryKeyValueToString(val.value,val.type),"</td></tr>");
}
println(" </table>");
println(" </p>");
} else {
println(" <p><font color='red'>");
println(" The list of typed paths is empty.");
println(" </font></p>");
}
} else {
println(" <p><font color='red'>");
println(" This registry hive does not contain a list of typed paths!");
println(" </font></p>");
}
-
-// println("</html>");
}
diff --git a/trunk/report_templates/NTUSER_WindowsLiveAccounts.qs b/trunk/report_templates/NTUSER_WindowsLiveAccounts.qs
index c52547b..5c48bd1 100644
--- a/trunk/report_templates/NTUSER_WindowsLiveAccounts.qs
+++ b/trunk/report_templates/NTUSER_WindowsLiveAccounts.qs
@@ -1,48 +1,43 @@
function fred_report_info() {
var info={report_cat : "NTUSER",
report_name : "Windows Live accounts",
report_author : "Gillen Daniel",
report_desc : "Dump Windows Live accounts",
fred_api : 2,
hive : "NTUSER"
};
return info;
}
function IsValid(val) {
if(typeof val !== 'undefined') return true;
else return false;
}
function fred_report_html() {
-// println("<html>");
-// println(" <head><title>Windows Live Accounts</title></head>");
-// println(" <body style=\"font-size:12\">");
println(" <h2>Windows live accounts</h2>");
// Iterate over all contacts
var accounts=GetRegistryKeys("\\Software\\Microsoft\\Windows Live Contacts\\Database");
if(IsValid(accounts)) {
println(" <p style=\"font-size:12\">");
println(" <table style=\"margin-left:20px; font-size:12\">");
for(var i=0;i<accounts.length;i++) {
var val=GetRegistryKeyValue("\\Software\\Microsoft\\Windows Live Contacts\\Database",accounts[i]);
println(" <tr><td>",accounts[i],"</td><td>",RegistryKeyValueToString(val.value,val.type),"</td></tr>");
}
accounts=GetRegistryKeys("\\Software\\Microsoft\\Windows Live Contacts\\Me");
for(var i=0;i<accounts.length;i++) {
var val=GetRegistryKeyValue("\\Software\\Microsoft\\Windows Live Contacts\\Me",accounts[i]);
println(" <tr><td>",accounts[i],"</td><td>",RegistryKeyValueToString(val.value,val.type),"</td></tr>");
}
println(" </table>");
println(" </p>");
} else {
println(" <p><font color='red'>");
println(" This registry hive does not contain a list of Windows Live Accounts!");
println(" </font></p>");
}
-
-// println("</html>");
}
diff --git a/trunk/report_templates/SAM_UserAccounts.qs b/trunk/report_templates/SAM_UserAccounts.qs
index f3ee71c..6eb2770 100644
--- a/trunk/report_templates/SAM_UserAccounts.qs
+++ b/trunk/report_templates/SAM_UserAccounts.qs
@@ -1,109 +1,104 @@
function fred_report_info() {
var info={report_cat : "SAM",
report_name : "User accounts",
report_author : "Gillen Daniel",
report_desc : "Dump Windows user accounts",
fred_api : 2,
hive : "SAM"
};
return info;
}
function IsValid(val) {
if(typeof val !== 'undefined') return true;
else return false;
}
function print_table_row(cell01,cell02) {
println(" <tr><td>",cell01,"</td><td>",cell02,"</td></tr>");
}
function print_v_info(v_key_value,info_name,str_off) {
var offset=Number(RegistryKeyValueToVariant(v_key_value,"uint16",str_off))+0x0cc;
var len=Number(RegistryKeyValueToVariant(v_key_value,"uint16",str_off+4))/2;
if(len>0) print_table_row(info_name,RegistryKeyValueToVariant(v_key_value,"utf16",offset,len));
}
function fred_report_html() {
// See http://windowsir.blogspot.com/2006/08/getting-user-info-from-image.html
-// println("<html>");
-// println(" <head><title>User Accounts</title></head>");
-// println(" <body style=\"font-size:12\">");
println(" <h2>User accounts</h2>");
// Iterate over all user names
var user_names=GetRegistryNodes("\\SAM\\Domains\\Account\\Users\\Names");
if(IsValid(user_names)) {
for(var i=0;i<user_names.length;i++) {
println(" <p style=\"font-size:12; white-space:nowrap\">");
// Print user name
println(" <u>",user_names[i],"</u><br />");
println(" <table style=\"margin-left:20px; font-size:12\">");
// 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(" <tr><td>RID:</td><td>",Number(user_rid).toString(10)," (",user_rid,")","</td></tr>");
// 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");
print_v_info(v_key.value,"Full name:",0x18);
print_v_info(v_key.value,"Comment:",0x24);
print_v_info(v_key.value,"Home directory:",0x48);
print_v_info(v_key.value,"Home directory drive:",0x54);
print_v_info(v_key.value,"Logon script path:",0x60);
print_v_info(v_key.value,"Profile path:",0x6c);
// Get user's F key and print various infos
var f_key=GetRegistryKeyValue(String().concat("\\SAM\\Domains\\Account\\Users\\",user_rid),"F");
print_table_row("Last login time:",RegistryKeyValueToVariant(f_key.value,"filetime",8));
print_table_row("Last pw change:",RegistryKeyValueToVariant(f_key.value,"filetime",24));
print_table_row("Last failed login:",RegistryKeyValueToVariant(f_key.value,"filetime",40));
print_table_row("Account expires:",RegistryKeyValueToVariant(f_key.value,"filetime",32));
print_table_row("Total logins:",RegistryKeyValueToVariant(f_key.value,"uint16",66));
print_table_row("Failed logins:",RegistryKeyValueToVariant(f_key.value,"uint16",64));
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 ");
// I 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 ");
print(" (",acc_flags,")");
println("</td></tr>");
// Get password hint if available
var hint=GetRegistryKeyValue(String().concat("\\SAM\\Domains\\Account\\Users\\",user_rid),"UserPasswordHint");
if(typeof hint !== 'undefined') {
// Append missing trailing utf16 zero byte
hint.value.appendByte(0);
hint.value.appendByte(0);
print_table_row("Password hint:",RegistryKeyValueToVariant(hint.value,"utf16"));
}
// TODO: User group membership
println(" </table>");
println(" </p>");
}
} else {
println(" <p><font color='red'>");
println(" Unable to enumerate users!<br />");
println(" Are you sure you are running this report against the correct registry hive?");
println(" </font></p>");
}
-
-// println("</html>");
}
diff --git a/trunk/report_templates/SOFTWARE_Autoruns.qs b/trunk/report_templates/SOFTWARE_Autoruns.qs
index d335d70..053e63d 100644
--- a/trunk/report_templates/SOFTWARE_Autoruns.qs
+++ b/trunk/report_templates/SOFTWARE_Autoruns.qs
@@ -1,61 +1,56 @@
function fred_report_info() {
var info={report_cat : "SOFTWARE",
report_name : "Autoruns",
report_author : "Gillen Daniel",
report_desc : "Dump autoruns",
fred_api : 2,
hive : "SOFTWARE"
};
return info;
}
function IsValid(val) {
if(typeof val !== 'undefined') return true;
else return false;
}
function print_table_row(cell01,cell02) {
println(" <tr><td>",cell01,"</td><td>",cell02,"</td></tr>");
}
function ListAutoruns(autorun_path,autorun_key) {
println(" <p style=\"font-size:12; white-space:nowrap\">");
println(" <u>"+autorun_key+"</u><br />");
var run_keys=GetRegistryKeys(autorun_path+autorun_key);
if(IsValid(run_keys) && run_keys.length>0) {
println(" <table style=\"margin-left:20px; font-size:12; white-space:nowrap\">");
print_table_row("<b>Name</b>","<b>Executable</b>");
for(var i=0;i<run_keys.length;i++) {
var val=GetRegistryKeyValue(autorun_path+autorun_key,run_keys[i]);
print_table_row(run_keys[i],RegistryKeyValueToString(val.value,val.type));
}
println(" </table>");
} else {
println(" None");
}
println(" </p>");
}
function fred_report_html() {
var val;
-// println("<html>");
-// println(" <head><title>System Autoruns</title></head>");
-// println(" <body style=\"font-size:12\">");
println(" <h2>System Autoruns</h2>");
// Run
ListAutoruns("\\Microsoft\\Windows\\CurrentVersion\\","Run");
// RunOnce
ListAutoruns("\\Microsoft\\Windows\\CurrentVersion\\","RunOnce");
// RunOnceEx
ListAutoruns("\\Microsoft\\Windows\\CurrentVersion\\","RunOnceEx");
// TODO: There might be a Run under WindowsNT\CurrentVersion\Run too!
-
-// println("</html>");
}
diff --git a/trunk/report_templates/SOFTWARE_ProfileList.qs b/trunk/report_templates/SOFTWARE_ProfileList.qs
index 435e7e0..3f00709 100644
--- a/trunk/report_templates/SOFTWARE_ProfileList.qs
+++ b/trunk/report_templates/SOFTWARE_ProfileList.qs
@@ -1,56 +1,51 @@
function fred_report_info() {
var info={report_cat : "SOFTWARE",
report_name : "Profile list",
report_author : "Gillen Daniel",
report_desc : "Dump profile list",
fred_api : 2,
hive : "SOFTWARE"
};
return info;
}
function IsValid(val) {
if(typeof val !== 'undefined') return true;
else return false;
}
function print_table_row(cell01,cell02) {
println(" <tr><td>",cell01,"</td><td>",cell02,"</td></tr>");
}
function fred_report_html() {
var val;
-// println("<html>");
-// println(" <head><title>Profile List</title></head>");
-// println(" <body style=\"font-size:12\">");
println(" <h2>Profile List</h2>");
var profile_list=GetRegistryNodes("\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList");
if(IsValid(profile_list) && profile_list.length>0) {
for(var i=0;i<profile_list.length;i++) {
println(" <p style=\"font-size:12; white-space:nowrap\">");
println(" <u>"+profile_list[i]+"</u><br />");
println(" <table style=\"margin-left:20px; font-size:12; white-space:nowrap\">");
// Get profile image path
val=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\"+profile_list[i],"ProfileImagePath");
print_table_row("Profile image path:",IsValid(val) ? RegistryKeyValueToString(val.value,val.type) : "n/a");
// Get last load time (Saved as 2 dwords. Another "good" idea of M$ ;-))
var loadtime_low=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\"+profile_list[i],"ProfileLoadTimeLow");
var loadtime_high=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\"+profile_list[i],"ProfileLoadTimeHigh");
print_table_row("Profile load time:",(IsValid(loadtime_low) && IsValid(loadtime_high)) ? RegistryKeyValueToVariant(loadtime_low.value.append(loadtime_high.value),"filetime",0) : "n/a");
// TODO: There is more to decode under \\Microsoft\\Windows NT\\CurrentVersion\\ProfileList
println(" </table>");
println(" </p>");
}
println(" </table>");
} else {
println(" None");
}
-
-// println("</html>");
}
diff --git a/trunk/report_templates/SOFTWARE_WindowsVersion.qs b/trunk/report_templates/SOFTWARE_WindowsVersion.qs
index 0a06fb3..b2151f4 100644
--- a/trunk/report_templates/SOFTWARE_WindowsVersion.qs
+++ b/trunk/report_templates/SOFTWARE_WindowsVersion.qs
@@ -1,109 +1,104 @@
function fred_report_info() {
var info={report_cat : "SOFTWARE",
report_name : "Windows version",
report_author : "Gillen Daniel",
report_desc : "Dump Windows version info",
fred_api : 2,
hive : "SOFTWARE"
};
return info;
}
function IsValid(val) {
if(typeof val !== 'undefined') return true;
else return false;
}
function print_table_row(cell01,cell02) {
println(" <tr><td>",cell01,"</td><td>",cell02,"</td></tr>");
}
function DecodeProductKey(arr) {
//ProductKey is base24 encoded
var keychars=new Array("B","C","D","F","G","H","J","K","M","P","Q","R","T","V","W","X","Y","2","3","4","6","7","8","9");
var key=new Array(30);
var ret="";
var ncur;
if(arr.length<66) return ret;
arr=arr.mid(52,15);
for(var ilbyte=24;ilbyte>=0;ilbyte--) {
ncur=0;
for(var ilkeybyte=14;ilkeybyte>=0;ilkeybyte--) {
ncur=ncur*256^arr[ilkeybyte];
arr[ilkeybyte]=ncur/24;
ncur%=24;
}
ret=keychars[ncur]+ret;
if(ilbyte%5==0 && ilbyte!=0) ret="-"+ret;
}
return ret;
}
function fred_report_html() {
-// println("<html>");
-// println(" <head><title>Windows version info</title></head>");
-// println(" <body style=\"font-size:12\">");
println(" <h2>Windows version info</h2>");
// Windows version sp and build info
var val=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion","ProductName");
if(IsValid(val)) {
println(" <p style=\"font-size:12; white-space:nowrap\">");
println(" <table style=\"margin-left:20px; font-size:12; white-space:nowrap\">");
print(" <tr><td>Windows version:</td><td>",RegistryKeyValueToString(val.value,val.type));
var val=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion","CSDVersion");
if(IsValid(val)) {
print(" ",RegistryKeyValueToString(val.value,val.type));
}
var val=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion","CurrentBuildNumber");
if(IsValid(val)) {
print(" build ",RegistryKeyValueToString(val.value,val.type));
}
println("</td></tr>");
// Build string
var val=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion","BuildLab");
print_table_row("Build string:",(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "n/a");
// Extended build string
var val=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion","BuildLabEx");
print_table_row("Extended build string:",(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "n/a");
// Install date
var val=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion","InstallDate");
print_table_row("Install date:",(IsValid(val)) ? RegistryKeyValueToVariant(val.value,"unixtime") : "n/a");
// Owner and Organization info
var val=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion","RegisteredOwner");
print_table_row("Registered owner:",(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "n/a");
var val=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion","RegisteredOrganization");
print_table_row("Registered organization:",(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "n/a");
// Windows ID / Key
var val=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion","ProductId");
print_table_row("Product ID:",(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "n/a");
var val=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion","DigitalProductId");
if(IsValid(val)) {
var key=DecodeProductKey(val.value);
if(key!="BBBBB-BBBBB-BBBBB-BBBBB-BBBBB") print_table_row("Product Key:",key);
else print_table_row("Product Key:","n/a (Probably a volume license key was used)");
} else print_table_row("Product Key:","n/a");
// Install directory / Source directory
var val=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion","PathName");
print_table_row("Install path:",(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "n/a");
var val=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion","SourcePath");
print_table_row("Source path:",(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "n/a");
println(" </table>");
println(" </p>");
} else {
println(" <p><font color='red'>");
println(" Unable to get product name!<br />");
println(" Are you sure you are running this report against the correct registry hive?");
println(" </font></p>");
}
-
-// println("</html>");
}
diff --git a/trunk/report_templates/SYSTEM_CurrentNetworkSettings.qs b/trunk/report_templates/SYSTEM_CurrentNetworkSettings.qs
index 7a6dac4..6a0a940 100644
--- a/trunk/report_templates/SYSTEM_CurrentNetworkSettings.qs
+++ b/trunk/report_templates/SYSTEM_CurrentNetworkSettings.qs
@@ -1,141 +1,136 @@
function fred_report_info() {
var info={report_cat : "SYSTEM",
report_name : "Current network settings",
report_author : "Gillen Daniel",
report_desc : "Dump current network settings",
fred_api : 2,
hive : "SYSTEM"
};
return info;
}
function IsValid(val) {
if(typeof val !== 'undefined') return true;
else return false;
}
function print_table_row(cell01,cell02) {
println(" <tr><td>",cell01,"</td><td>",cell02,"</td></tr>");
}
function ZeroPad(number,padlen) {
var ret=number.toString(10);
if(!padlen || ret.length>=padlen) return ret;
return Math.pow(10,padlen-ret.length).toString().slice(1)+ret;
}
function fred_report_html() {
// See Appendix A: TCP/IP Configuration Parameters:
// http://technet.microsoft.com/de-de/library/cc739819%28v=WS.10%29.aspx
var val;
-// println("<html>");
-// println(" <head><title>Current Network Settings (Tcp/Ip)</title></head>");
-// println(" <body style=\"font-size:12\">");
println(" <h2>Current network settings (Tcp/Ip)</h2>");
// Get current controlset
var cur_controlset=GetRegistryKeyValue("\\Select","Current");
if(IsValid(cur_controlset)) {
cur_controlset=RegistryKeyValueToString(cur_controlset.value,cur_controlset.type);
// Current holds a DWORD value, thus we get a string like 0x00000000, but
// control sets are referenced by its decimal representation.
cur_controlset="ControlSet"+ZeroPad(parseInt(String(cur_controlset).substr(2,8),16),3)
println(" <p style=\"font-size:12; white-space:nowrap\">");
println(" <table style=\"margin-left:20px; font-size:12; white-space:nowrap\">");
print_table_row("Active control set:",cur_controlset);
// Computer name
val=GetRegistryKeyValue(cur_controlset+"\\Control\\ComputerName\\ComputerName","ComputerName");
print_table_row("Computer name:",(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "");
println(" </table>");
println(" <br />");
// Iterate over all available network adapters
var adapters=GetRegistryNodes(cur_controlset+"\\Services\\Tcpip\\Parameters\\Adapters");
for(var i=0;i<adapters.length;i++) {
// Try to get a human readable name
// According to http://technet.microsoft.com/de-de/library/cc780532%28v=ws.10%29.aspx
// the {4D36E972-E325-11CE-BFC1-08002BE10318} key name might be (and hopefully is) static :)
val=GetRegistryKeyValue(cur_controlset+"\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\"+adapters[i]+"\\Connection","Name");
if(IsValid(val)) {
println(" <u>",RegistryKeyValueToString(val.value,val.type),"</u>");
} else {
println(" <u>",adapters[i],"</u>");
}
// Get settings node
var adapter_settings_node=GetRegistryKeyValue(cur_controlset+"\\Services\\Tcpip\\Parameters\\Adapters\\"+adapters[i],"IpConfig");
adapter_settings_node=RegistryKeyValueToVariant(adapter_settings_node.value,"utf16",0);
println(" <table style=\"margin-left:20px; font-size:12; white-space:nowrap\">");
//print_table_row("Adapter id:",adapters[i]);
// Get configuration mode
val=GetRegistryKeyValue(cur_controlset+"\\Services\\"+adapter_settings_node,"EnableDHCP");
val=Number(RegistryKeyValueToString(val.value,val.type));
if(val) {
// DHCP enabled
print_table_row("Configuration mode:","DHCP");
// DHCP server
val=GetRegistryKeyValue(cur_controlset+"\\Services\\"+adapter_settings_node,"DhcpServer");
print_table_row("Last used DHCP server:",(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "");
// IP address
val=GetRegistryKeyValue(cur_controlset+"\\Services\\"+adapter_settings_node,"DhcpIPAddress");
print_table_row("IP address:",(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "");
// Subnet mask
val=GetRegistryKeyValue(cur_controlset+"\\Services\\"+adapter_settings_node,"DhcpSubnetMask");
print_table_row("Subnet mask:",(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "");
// Nameserver(s)
val=GetRegistryKeyValue(cur_controlset+"\\Services\\"+adapter_settings_node,"DhcpNameServer");
print_table_row("Nameserver(s):",(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "");
// Domain
val=GetRegistryKeyValue(cur_controlset+"\\Services\\"+adapter_settings_node,"DhcpDomain");
print_table_row("Domain:",(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "");
// Default gw
val=GetRegistryKeyValue(cur_controlset+"\\Services\\"+adapter_settings_node,"DhcpDefaultGateway");
print_table_row("Default gateway:",(IsValid(val)) ? RegistryKeyValueToVariant(val.value,"utf16",0) : "");
// Lease obtained
val=GetRegistryKeyValue(cur_controlset+"\\Services\\"+adapter_settings_node,"LeaseObtainedTime");
print_table_row("Lease obtained:",(IsValid(val)) ? RegistryKeyValueToVariant(val.value,"unixtime",0) : "");
// Lease valid until
val=GetRegistryKeyValue(cur_controlset+"\\Services\\"+adapter_settings_node,"LeaseTerminatesTime");
print_table_row("Lease terminates:",(IsValid(val)) ? RegistryKeyValueToVariant(val.value,"unixtime",0) : "");
} else {
print_table_row("Configuration mode:","Manual");
// IP address
val=GetRegistryKeyValue(cur_controlset+"\\Services\\"+adapter_settings_node,"IPAddress");
print_table_row("IP address:",(IsValid(val)) ? RegistryKeyValueToVariant(val.value,"utf16",0) : "");
// Subnet mask
val=GetRegistryKeyValue(cur_controlset+"\\Services\\"+adapter_settings_node,"SubnetMask");
print_table_row("Subnet mask:",(IsValid(val)) ? RegistryKeyValueToVariant(val.value,"utf16",0) : "");
// Nameserver
val=GetRegistryKeyValue(cur_controlset+"\\Services\\"+adapter_settings_node,"NameServer");
print_table_row("Nameserver:",(IsValid(val)) ? RegistryKeyValueToVariant(val.value,"utf16",0) : "");
// Domain
val=GetRegistryKeyValue(cur_controlset+"\\Services\\"+adapter_settings_node,"Domain");
print_table_row("Domain:",(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "");
// Default gw
val=GetRegistryKeyValue(cur_controlset+"\\Services\\"+adapter_settings_node,"DefaultGateway");
print_table_row("Default gateway:",(IsValid(val)) ? RegistryKeyValueToVariant(val.value,"utf16",0) : "");
}
// TODO: Check for EnableSecurityFilters, TCPAllowedPorts and UDPAllowedPorts to get firewall status.
println(" </table>");
println(" <br />");
// TODO: Get persistent routes from \ControlSet001\Services\Tcpip\Parameters\PersistentRoutes
}
println(" </p>");
} else {
println(" <p><font color='red'>");
println(" Unable to determine current control set!<br />");
println(" Are you sure you are running this report against the correct registry hive?");
println(" </font></p>");
}
-
-// println("</html>");
}
diff --git a/trunk/report_templates/SYSTEM_Services.qs b/trunk/report_templates/SYSTEM_Services.qs
index 4344e66..64c2748 100644
--- a/trunk/report_templates/SYSTEM_Services.qs
+++ b/trunk/report_templates/SYSTEM_Services.qs
@@ -1,111 +1,106 @@
function fred_report_info() {
var info={report_cat : "SYSTEM",
report_name : "Services",
report_author : "Gillen Daniel",
report_desc : "Dump services",
fred_api : 2,
hive : "SYSTEM"
};
return info;
}
function IsValid(val) {
if(typeof val !== 'undefined') return true;
else return false;
}
function ZeroPad(number,padlen) {
var ret=number.toString(10);
if(!padlen || ret.length>=padlen) return ret;
return Math.pow(10,padlen-ret.length).toString().slice(1)+ret;
}
function PrintTableRow(cell01,cell02,cell03,cell04,cell05) {
println(" <tr><td style=\"padding:2px\">",cell01,"</td><td style=\"padding:2px\">",cell02,"</td><td style=\"padding:2px\">",cell03,"</td><td style=\"padding:2px\">",cell04,"</td><td style=\"padding:2px\">",cell05,"</td></tr>");
}
function ListService(service_node) {
// Service name
var name=GetRegistryKeyValue(service_node,"DisplayName");
name=(IsValid(name)) ? RegistryKeyValueToString(name.value,name.type) : "Unknwon";
// Service group
var group=GetRegistryKeyValue(service_node,"Group");
group=(IsValid(group)) ? RegistryKeyValueToString(group.value,group.type) : "";
// Service exe
var image=GetRegistryKeyValue(service_node,"ImagePath");
image=(IsValid(image)) ? RegistryKeyValueToString(image.value,image.type) : "Unknwon";
// Start
var start=GetRegistryKeyValue(service_node,"Start");
start=(IsValid(start)) ? RegistryKeyValueToString(start.value,start.type) : -1;
switch(Number(start)) {
case 0:
start="Boot";
break;
case 1:
start="System";
break;
case 2:
start="Automatic";
break;
case 3:
start="Manual";
break;
case 4:
start="Disabled";
break;
default:
start="Unknown";
}
// Description
var desc=GetRegistryKeyValue(service_node,"Description");
desc=(IsValid(desc)) ? RegistryKeyValueToString(desc.value,desc.type) : "";
PrintTableRow(name,group,start,image,desc)
}
function fred_report_html() {
var val;
-// println("<html>");
-// println(" <head><title>Services</title></head>");
-// println(" <body style=\"font-size:12\">");
println(" <h2>Services</h2>");
// Get current controlset
var cur_controlset=GetRegistryKeyValue("\\Select","Current");
if(IsValid(cur_controlset)) {
cur_controlset=RegistryKeyValueToString(cur_controlset.value,cur_controlset.type);
// Current holds a DWORD value, thus we get a string like 0x00000000, but
// control sets are referenced by its decimal representation.
cur_controlset="ControlSet"+ZeroPad(parseInt(String(cur_controlset).substr(2,8),16),3)
// Get list of possible services
var services=GetRegistryNodes(cur_controlset+"\\Services");
if(IsValid(services)) {
println(" <p style=\"font-size:12; white-space:nowrap\">");
println(" <table style=\"margin-left:20px; font-size:12; white-space:nowrap\">");
println(" <tr><td style=\"padding:2px\"><b>Name</b></td><td style=\"padding:2px\"><b>Group</b></td><td><b>Startup</b></td><td style=\"padding:2px\"><b>Image path</b></td><td style=\"padding:2px\"><b>Description</b></td></tr>");
for(var i=0;i<services.length;i++) {
// Get service type
val=GetRegistryKeyValue(cur_controlset+"\\Services\\"+services[i],"Type");
if(!IsValid(val)) continue;
val=RegistryKeyValueToString(val.value,val.type);
if(Number(val)!=16 && Number(val)!=32) continue;
ListService(cur_controlset+"\\Services\\"+services[i]);
}
println(" </table>");
println(" </p>");
} else {
println(" <p><font color='red'>");
println(" This registry hive does not contain any services!<br />");
println(" </font></p>");
}
} else {
println(" <p><font color='red'>");
println(" Unable to determine current control set!<br />");
println(" Are you sure you are running this report against the correct registry hive?");
println(" </font></p>");
}
-
-// println("</html>");
}
diff --git a/trunk/report_templates/SYSTEM_ShutdownTime.qs b/trunk/report_templates/SYSTEM_ShutdownTime.qs
index 443552b..1e5ce77 100644
--- a/trunk/report_templates/SYSTEM_ShutdownTime.qs
+++ b/trunk/report_templates/SYSTEM_ShutdownTime.qs
@@ -1,57 +1,52 @@
function fred_report_info() {
var info={report_cat : "SYSTEM",
report_name : "Shutdown time",
report_author : "Gillen Daniel",
report_desc : "Dump last known shutdown time",
fred_api : 2,
hive : "SYSTEM"
};
return info;
}
function IsValid(val) {
if(typeof val !== 'undefined') return true;
else return false;
}
function print_table_row(cell01,cell02) {
println(" <tr><td>",cell01,"</td><td>",cell02,"</td></tr>");
}
function fred_report_html() {
var val;
-// println("<html>");
-// println(" <head><title>Last known shutdown time</title></head>");
-// println(" <body style=\"font-size:12\">");
println(" <h2>Last known shutdown time</h2>");
// Get current controlset
var cur_controlset=GetRegistryKeyValue("\\Select","Current");
if(IsValid(cur_controlset)) {
cur_controlset=RegistryKeyValueToString(cur_controlset.value,cur_controlset.type);
// Current holds a DWORD value, thus we get a string like 0x00000000, but
// control sets are referenced only with the last 3 digits.
cur_controlset="ControlSet"+String(cur_controlset).substr(7,3);
println(" <p style=\"font-size:12; white-space:nowrap\">");
println(" <table style=\"margin-left:20px; font-size:12; white-space:nowrap\">");
print_table_row("Active control set:",cur_controlset);
// Shutdown time
val=GetRegistryKeyValue(cur_controlset+"\\Control\\Windows","ShutdownTime");
print_table_row("Shutdown time:",(IsValid(val)) ? RegistryKeyValueToVariant(val.value,"filetime") : "Unknown");
println(" </table>");
println(" <br />");
println(" </p>");
} else {
println(" <p><font color='red'>");
println(" Unable to determine current control set!<br />");
println(" Are you sure you are running this report against the correct registry hive?");
println(" </font></p>");
}
-
-// println("</html>");
}
diff --git a/trunk/report_templates/SYSTEM_SystemTimeInfo.qs b/trunk/report_templates/SYSTEM_SystemTimeInfo.qs
index 588a14a..0f7ae70 100644
--- a/trunk/report_templates/SYSTEM_SystemTimeInfo.qs
+++ b/trunk/report_templates/SYSTEM_SystemTimeInfo.qs
@@ -1,122 +1,117 @@
function fred_report_info() {
var info={report_cat : "SYSTEM",
report_name : "System time info",
report_author : "Gillen Daniel",
report_desc : "Dump system time info",
fred_api : 2,
hive : "SYSTEM"
};
return info;
}
function IsValid(val) {
if(typeof val !== 'undefined') return true;
else return false;
}
function print_table_row(cell01,cell02) {
println(" <tr><td>",cell01,"</td><td>",cell02,"</td></tr>");
}
function ToUTC(num) {
var retnum=new Number(num);
if(retnum&0x80000000) {
retnum=((0xFFFFFFFF-retnum)+1)/60;
return "UTC+"+Number(retnum).toString(10);
} else {
retnum=retnum/60;
if(retnum!=0) return "UTC-"+Number(retnum).toString(10);
else return "UTC+"+Number(retnum).toString(10);
}
}
function ZeroPad(number,padlen) {
var ret=number.toString(10);
if(!padlen || ret.length>=padlen) return ret;
return Math.pow(10,padlen-ret.length).toString().slice(1)+ret;
}
function fred_report_html() {
var val;
-// println("<html>");
-// println(" <head><title>System Time Info</title></head>");
-// println(" <body style=\"font-size:12\">");
println(" <h2>System time info</h2>");
// Get current controlset
var cur_controlset=GetRegistryKeyValue("\\Select","Current");
if(IsValid(cur_controlset)) {
cur_controlset=RegistryKeyValueToString(cur_controlset.value,cur_controlset.type);
// Current holds a DWORD value, thus we get a string like 0x00000000, but
// control sets are referenced by its decimal representation.
cur_controlset="ControlSet"+ZeroPad(parseInt(String(cur_controlset).substr(2,8),16),3)
println(" <p style=\"font-size:12; white-space:nowrap\">");
println(" <u>Time zone info</u>");
println(" <table style=\"margin-left:20px; font-size:12; white-space:nowrap\">");
// Active time bias
val=GetRegistryKeyValue(cur_controlset+"\\Control\\TimeZoneInformation","ActiveTimeBias");
print_table_row("Active time bias:",(IsValid(val)) ? ToUTC(RegistryKeyValueToString(val.value,val.type)) : "n/a");
// Std. tz name and bias
val=GetRegistryKeyValue(cur_controlset+"\\Control\\TimeZoneInformation","StandardName");
print_table_row("Std. time zone name:",(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "n/a");
val=GetRegistryKeyValue(cur_controlset+"\\Control\\TimeZoneInformation","StandardBias");
print_table_row("Std. time bias:",(IsValid(val)) ? ToUTC(RegistryKeyValueToString(val.value,val.type)) : "n/a");
// Daylight tz name and bias
val=GetRegistryKeyValue(cur_controlset+"\\Control\\TimeZoneInformation","DaylightName");
print_table_row("Daylight time zone name:",(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "n/a");
val=GetRegistryKeyValue(cur_controlset+"\\Control\\TimeZoneInformation","DaylightBias");
print_table_row("Daylight time bias:",(IsValid(val)) ? ToUTC(RegistryKeyValueToString(val.value,val.type)) : "n/a");
println(" </table>");
println(" <br />");
println(" <u>W32Time service info</u>");
println(" <table style=\"margin-left:20px; font-size:12; white-space:nowrap\">");
// Get W32Time service settings
val=GetRegistryKeyValue(cur_controlset+"\\Services\\W32Time","Start");
if(IsValid(val)) {
print(" <tr><td>Startup method:</td><td>");
val=RegistryKeyValueToString(val.value,val.type);
switch(Number(val)) {
case 0:
print("Boot");
break;
case 1:
print("System");
break;
case 2:
print("Automatic");
break;
case 3:
print("Manual");
break;
case 4:
print("Disabled");
break;
default:
print("Unknown");
}
println("</td></tr>");
// If service is enabled, get ntp server
if(Number(val)<4) {
val=GetRegistryKeyValue(cur_controlset+"\\Services\\W32Time\\Parameters","NtpServer");
print_table_row("NTP server(s):",(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "n/a");
}
} else print_table_row("Startup method:","n/a");
println(" </table>");
println(" </p>");
} else {
println(" <p><font color='red'>");
println(" Unable to determine current control set!<br />");
println(" Are you sure you are running this report against the correct registry hive?");
println(" </font></p>");
}
-
-// println("</html>");
}
diff --git a/trunk/report_templates/SYSTEM_UsbStorageDevices.qs b/trunk/report_templates/SYSTEM_UsbStorageDevices.qs
index e7cded4..20667d0 100644
--- a/trunk/report_templates/SYSTEM_UsbStorageDevices.qs
+++ b/trunk/report_templates/SYSTEM_UsbStorageDevices.qs
@@ -1,150 +1,145 @@
function fred_report_info() {
var info={report_cat : "SYSTEM",
report_name : "USB storage devices",
report_author : "Gillen Daniel",
report_desc : "Dump USB storage devices",
fred_api : 2,
hive : "SYSTEM"
};
return info;
}
function IsValid(val) {
if(typeof val !== 'undefined') return true;
else return false;
}
function print_table_row(cell01,cell02) {
println(" <tr><td>",cell01,"</td><td>",cell02,"</td></tr>");
}
function ZeroPad(number,padlen) {
var ret=number.toString(10);
if(!padlen || ret.length>=padlen) return ret;
return Math.pow(10,padlen-ret.length).toString().slice(1)+ret;
}
function fred_report_html() {
// TODO: There is more here. Check http://www.forensicswiki.org/wiki/USB_History_Viewing
var val;
-// println("<html>");
-// println(" <head><title>USB Storage Devices</title></head>");
-// println(" <body style=\"font-size:12\">");
println(" <h2>USB storage devices</h2>");
// Preload MountedDevices to possibly identify mount points of USB storage devices
var mnt_keys=GetRegistryKeys("\\MountedDevices");
var mnt_values=new Array();
if(IsValid(mnt_keys)) {
for(var i=0;i<mnt_keys.length;i++) {
val=GetRegistryKeyValue("\\MountedDevices",mnt_keys[i]);
mnt_values[i]=RegistryKeyValueToVariant(val.value,"utf16");
}
}
// Get current controlset
var cur_controlset=GetRegistryKeyValue("\\Select","Current");
if(IsValid(cur_controlset)) {
cur_controlset=RegistryKeyValueToString(cur_controlset.value,cur_controlset.type);
// Current holds a DWORD value, thus we get a string like 0x00000000, but
// control sets are referenced by its decimal representation.
cur_controlset="ControlSet"+ZeroPad(parseInt(String(cur_controlset).substr(2,8),16),3)
println(" <p style=\"font-size:12; white-space:nowrap\">");
println(" <u>Settings</u><br />");
println(" <table style=\"margin-left:20px; font-size:12; white-space:nowrap\">");
// Are USB storage devices enabled?
// http://www.forensicmag.com/article/windows-7-registry-forensics-part-5
// Is this true for WinXP etc.. ???
var val=GetRegistryKeyValue(cur_controlset+"\\services\\USBSTOR","Start");
if(IsValid(val)) {
val=RegistryKeyValueToString(val.value,val.type);
val=parseInt(String(val).substr(2,8),10);
switch(val) {
case 3:
print_table_row("Storage driver enabled:","Yes");
break;
case 4:
print_table_row("Storage driver enabled:","No");
break;
default:
print_table_row("Storage driver enabled:","Unknown");
}
} else {
print_table_row("Storage driver enabled:","Unknown");
}
println(" </table>");
println(" </p>");
println(" <p style=\"font-size:12; white-space:nowrap\">");
println(" <u>Devices</u><br />");
var storage_roots=GetRegistryNodes(cur_controlset+"\\Enum\\USBSTOR");
if(IsValid(storage_roots)) {
for(var i=0;i<storage_roots.length;i++) {
println(" <u style=\"margin-left:20px; font-size:12; white-space:nowrap\">",storage_roots[i],"</u><br />");
var storage_subroots=GetRegistryNodes(cur_controlset+"\\Enum\\USBSTOR\\"+storage_roots[i]);
for(ii=0;ii<storage_subroots.length;ii++) {
println(" <table style=\"margin-left:20px; font-size:12; white-space:nowrap\">");
// If the second character of the unique instance ID is a '&', then the ID was
// generated by the system, as the device did not have a serial number.
if(String(storage_subroots[ii]).charAt(1)=="&") print_table_row("Unique ID:",storage_subroots[ii]+" (Generated by system)");
else print_table_row("Unique ID:",storage_subroots[ii]);
val=GetRegistryKeyValue(cur_controlset+"\\Enum\\USBSTOR\\"+storage_roots[i]+"\\"+storage_subroots[ii],"Class");
print_table_row("Class:",(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "");
val=GetRegistryKeyValue(cur_controlset+"\\Enum\\USBSTOR\\"+storage_roots[i]+"\\"+storage_subroots[ii],"DeviceDesc");
print_table_row("Device description:",(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "");
val=GetRegistryKeyValue(cur_controlset+"\\Enum\\USBSTOR\\"+storage_roots[i]+"\\"+storage_subroots[ii],"FriendlyName");
print_table_row("Friendly name:",(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "");
val=GetRegistryKeyValue(cur_controlset+"\\Enum\\USBSTOR\\"+storage_roots[i]+"\\"+storage_subroots[ii],"ParentIdPrefix");
if(IsValid(val)) {
// Windows XP uses the ParentId to link to MountedDevices
var parent_id=RegistryKeyValueToString(val.value,val.type);
print_table_row("Parent ID prefix:",parent_id);
// Find mount point(s)
print(" <tr><td>Mount point(s):</td><td>");
var br=0;
for(var iii=0;iii<mnt_keys.length;iii++) {
if(String(mnt_values[iii]).indexOf("#"+parent_id+"&")!=-1) {
if(br==1) print("<br />");
else br=1;
print(mnt_keys[iii]);
}
}
if(br==0) print("n/a");
println("</td></tr>");
} else {
// Since Vista, Unique IDs are used
// Find mount point(s)
print(" <tr><td>Mount point(s):</td><td>");
var br=0;
for(var iii=0;iii<mnt_keys.length;iii++) {
if(String(mnt_values[iii]).indexOf("#"+storage_subroots[ii]+"#")!=-1) {
if(br==1) print("<br />");
else br=1;
print(mnt_keys[iii]);
}
}
if(br==0) print("n/a");
println("</td></tr>");
}
println(" </table>");
println(" <br />");
}
}
} else {
println(" <font color='red'>This registry hive does not contain a list of attached USB storage devices!</font>");
}
println(" </p>");
} else {
println(" <p><font color='red'>");
println(" Unable to determine current control set!<br />");
println(" Are you sure you are running this report against the correct registry hive?");
println(" </font></p>");
}
-
-// println("</html>");
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Mon, Dec 23, 11:36 AM (11 h, 43 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1176932
Default Alt Text
(181 KB)
Attached To
Mode
rFRED fred
Attached
Detach File
Event Timeline
Log In to Comment