diff --git a/trunk/datareporterengine.cpp b/trunk/datareporterengine.cpp index a3965ad..2e1aad0 100644 --- a/trunk/datareporterengine.cpp +++ b/trunk/datareporterengine.cpp @@ -1,373 +1,383 @@ /******************************************************************************* * fred Copyright (c) 2011 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * This program is free software: you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the Free * * Software Foundation, either version 3 of the License, or (at your option) * * any later version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #include "datareporterengine.h" #include #include #include #include #include DataReporterEngine::DataReporterEngine(RegistryHive *p_hive) : QScriptEngine() { // Init vars this->p_registry_hive=p_hive; this->report_content=""; // Add our types to engine qScriptRegisterMetaType(this, this->RegistryKeyValueToScript, this->RegistryKeyValueFromScript); this->p_type_byte_array=new ByteArray(this); this->globalObject().setProperty("ByteArray", this->p_type_byte_array->constructor()); // Add our functions // print QScriptValue func_print=this->newFunction(this->Print); this->globalObject().setProperty("print",func_print); // println QScriptValue func_println=this->newFunction(this->PrintLn); this->globalObject().setProperty("println",func_println); // GetRegistryNodes QScriptValue func_get_nodes=this->newFunction(this->GetRegistryNodes,1); func_get_nodes.setData(this->newQObject(this->p_registry_hive)); this->globalObject().setProperty("GetRegistryNodes",func_get_nodes); // GetRegistryKeys QScriptValue func_get_keys=this->newFunction(this->GetRegistryKeys,1); func_get_keys.setData(this->newQObject(this->p_registry_hive)); this->globalObject().setProperty("GetRegistryKeys",func_get_keys); // GetRegistryKeyValue QScriptValue func_get_key_value=this->newFunction(this->GetRegistryKeyValue, 2); func_get_key_value.setData(this->newQObject(this->p_registry_hive)); this->globalObject().setProperty("GetRegistryKeyValue",func_get_key_value); // RegistryKeyValueToString QScriptValue func_value_to_string= this->newFunction(this->RegistryKeyValueToString,2); this->globalObject().setProperty("RegistryKeyValueToString", func_value_to_string); // RegistryKeyValueToVariant QScriptValue func_value_to_variant= this->newFunction(this->RegistryKeyValueToVariant); this->globalObject().setProperty("RegistryKeyValueToVariant", func_value_to_variant); // RegistryKeyTypeToString QScriptValue func_type_to_string= this->newFunction(this->RegistryKeyTypeToString,1); this->globalObject().setProperty("RegistryKeyTypeToString", func_type_to_string); /* // Add RegistryHive object QScriptValue obj_registry_hive=this->newQObject(this->p_registry_hive); this->globalObject().setProperty("RegistryHive",obj_registry_hive); */ } DataReporterEngine::~DataReporterEngine() { delete this->p_type_byte_array; } QScriptValue DataReporterEngine::Print(QScriptContext *context, QScriptEngine *engine) { int i; QString content; // Append all arguments to content for(i=0;iargumentCount();++i) { //if(i>0) content.append(" "); content.append(context->argument(i).toString()); } //QScriptValue calleeData=context->callee().data(); //DataReporterEngine *engine= // qobject_cast(calleeData.toQObject()); qobject_cast(engine)->report_content.append(content); return engine->undefinedValue(); } QScriptValue DataReporterEngine::PrintLn(QScriptContext *context, QScriptEngine *engine) { int i; QString content; // Append all arguments to content for(i=0;iargumentCount();++i) { //if(i>0) content.append(" "); content.append(context->argument(i).toString()); } qobject_cast(engine)-> report_content.append(content).append("\n"); return engine->undefinedValue(); } /* * GetRegistryNodes */ QScriptValue DataReporterEngine::GetRegistryNodes(QScriptContext *context, QScriptEngine *engine) { QScriptValue calleeData; RegistryHive *p_hive; QMap nodes; QScriptValue ret_nodes; int ii=0; // This function needs one argument, parent node path if(context->argumentCount()!=1) return engine->undefinedValue(); // Get calle data (Pointer to RegistryHive class) calleeData=context->callee().data(); p_hive=qobject_cast(calleeData.toQObject()); // Get nodes nodes=p_hive->GetNodes(context->argument(0).toString()); if(p_hive->Error()) { // Clear error state p_hive->GetErrorMsg(); return engine->undefinedValue(); } // Build script array ret_nodes=engine->newArray(nodes.count()); QMapIterator i(nodes); while(i.hasNext()) { i.next(); ret_nodes.setProperty(ii++,QScriptValue(i.key())); } return ret_nodes; } /* * GetRegistryKeys */ QScriptValue DataReporterEngine::GetRegistryKeys(QScriptContext *context, QScriptEngine *engine) { QScriptValue calleeData; RegistryHive *p_hive; QMap keys; QScriptValue ret_keys; int ii=0; // This function needs one argument, parent node path if(context->argumentCount()!=1) return engine->undefinedValue(); // Get calle data (Pointer to RegistryHive class) calleeData=context->callee().data(); p_hive=qobject_cast(calleeData.toQObject()); // Get keys keys=p_hive->GetKeys(context->argument(0).toString()); if(p_hive->Error()) { // Clear error state p_hive->GetErrorMsg(); return engine->undefinedValue(); } // Build script array ret_keys=engine->newArray(keys.count()); QMapIterator i(keys); while(i.hasNext()) { i.next(); ret_keys.setProperty(ii++,QScriptValue(i.key())); } return ret_keys; } /* * RegistryKeyValueToScript */ QScriptValue DataReporterEngine::RegistryKeyValueToScript(QScriptEngine *engine, const s_RegistryKeyValue &s) { QScriptValue obj=engine->newObject(); obj.setProperty("type",s.type); obj.setProperty("length",s.length); ByteArray *p_byte_array=new ByteArray(engine); obj.setProperty("value",p_byte_array->newInstance(s.value)); return obj; } /* * RegistryKeyValueFromScriptValue */ void DataReporterEngine::RegistryKeyValueFromScript(const QScriptValue &obj, s_RegistryKeyValue &s) { s.type=obj.property("type").toInt32(); s.length=obj.property("length").toInt32(); // TODO: Don't know if this works, but it probably does ;) s.value=qvariant_cast(obj.property("value").data().toVariant()); } QScriptValue DataReporterEngine::GetRegistryKeyValue(QScriptContext *context, QScriptEngine *engine) { QScriptValue calleeData; RegistryHive *p_hive; QByteArray key_value; int key_type=0; size_t key_length=0; s_RegistryKeyValue script_key_value; // This function needs two arguments, key path and key name if(context->argumentCount()!=2) return engine->undefinedValue(); // Get calle data (Pointer to RegistryHive class) calleeData=context->callee().data(); p_hive=qobject_cast(calleeData.toQObject()); // Get key value key_value=p_hive->GetKeyValue(context->argument(0).toString(), context->argument(1).toString(), &key_type, &key_length); if(p_hive->Error() || key_length==-1) { // Get error message ro clear error state p_hive->GetErrorMsg(); return engine->undefinedValue(); } // Save key value to s_RegistryKeyValue struct script_key_value.type=key_type; script_key_value.length=key_length; script_key_value.value=key_value; return DataReporterEngine::RegistryKeyValueToScript(engine,script_key_value); } QScriptValue DataReporterEngine::RegistryKeyValueToString( QScriptContext *context, QScriptEngine *engine) { QByteArray key_value; QString ret=""; // This function needs two arguments, key value and value type if(context->argumentCount()!=2) return engine->undefinedValue(); // Cast ByteArray argument to QByteArray and convert key_value=qvariant_cast(context->argument(0).data().toVariant()); ret=RegistryHive::KeyValueToString(key_value, context->argument(1).toInt32()); return engine->newVariant(ret); } QScriptValue DataReporterEngine::RegistryKeyValueToVariant( QScriptContext *context, QScriptEngine *engine) { int offset=0; + int length=0; QByteArray key_value; QString variant_type; int remaining_data_len; const char *p_data; QString ret=""; // This function needs at least two arguments, key value and variant type, - // and may have an optional third argument specifying an offset - if(context->argumentCount()<2 || context->argumentCount()>3) + // and may have two optional arguments, offset and length + if(context->argumentCount()<2 || context->argumentCount()>4) { return engine->undefinedValue(); - if(context->argumentCount()==3) offset=context->argument(2).toInt32(); + } + if(context->argumentCount()==3) { + offset=context->argument(2).toInt32(); + length=-1; + } + if(context->argumentCount()==4) { + offset=context->argument(2).toInt32(); + length=context->argument(3).toInt32(); + } + // Cast ByteArray argument to QByteArray key_value=qvariant_cast(context->argument(0).data().toVariant()); variant_type=context->argument(1).toString(); // Calculate how many bytes are remainig after specified offset remaining_data_len=key_value.size()-offset; if(!remaining_data_len>0) { // Nothing to show return engine->undefinedValue(); } // Get pointer to data at specified offset p_data=key_value.constData(); p_data+=offset; - // Convert + // ConvertFull name if(variant_type=="int8" && remaining_data_len>=1) { ret=QString().sprintf("%d",*(int8_t*)p_data); } else if(variant_type=="uint8" && remaining_data_len>=1) { ret=QString().sprintf("%u",*(uint8_t*)p_data); } else if(variant_type=="int16" && remaining_data_len>=2) { ret=QString().sprintf("%d",*(int16_t*)p_data); } else if(variant_type=="uint16" && remaining_data_len>=2) { ret=QString().sprintf("%u",*(uint16_t*)p_data); } else if(variant_type=="int32" && remaining_data_len>=4) { ret=QString().sprintf("%d",*(int32_t*)p_data); } else if(variant_type=="uint32" && remaining_data_len>=4) { ret=QString().sprintf("%d",*(uint32_t*)p_data); } else if(variant_type=="unixtime" && remaining_data_len>=4) { if(*(uint32_t*)p_data==0) { ret="n/a"; } else { QDateTime date_time; date_time.setTime_t(*(uint32_t*)p_data); ret=date_time.toString("yyyy/MM/dd hh:mm:ss"); } } else if(variant_type=="filetime" && remaining_data_len>=8) { if(*(uint64_t*)p_data==0) { ret="n/a"; } else { // TODO: Warn if >32bit QDateTime date_time; date_time.setTime_t((*(uint64_t*)p_data-116444736000000000)/10000000); ret=date_time.toString("yyyy/MM/dd hh:mm:ss"); } } else if(variant_type=="ascii") { // TODO: This fails bad if the string is not null terminated!! It might be // wise checking for a null char here - ret=QString().fromAscii((char*)p_data); + ret=QString().fromAscii((char*)p_data,length); } else if(variant_type=="utf16" && remaining_data_len>=2) { - ret=QString().fromUtf16((ushort*)p_data); + ret=QString().fromUtf16((ushort*)p_data,length); } else { // Unknown variant type or another error return engine->undefinedValue(); } return engine->newVariant(ret); } QScriptValue DataReporterEngine::RegistryKeyTypeToString( QScriptContext *context, QScriptEngine *engine) { QString ret=""; // This function needs one arguments, key type if(context->argumentCount()!=1) return engine->undefinedValue(); ret=RegistryHive::KeyTypeToString(context->argument(0).toInt32()); return engine->newVariant(ret); } diff --git a/trunk/qtscript_types/bytearray.cpp b/trunk/qtscript_types/bytearray.cpp index e6dc920..37df935 100644 --- a/trunk/qtscript_types/bytearray.cpp +++ b/trunk/qtscript_types/bytearray.cpp @@ -1,193 +1,181 @@ /******************************************************************************* * Copyright (c) 2011 by Gillen Daniel * * * * Derived from code by Nokia Corporation and/or its subsidiary(-ies) under a * * compatible license: * * * * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). * * All rights reserved. * * * * This program is free software: you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the Free * * Software Foundation, either version 3 of the License, or (at your option) * * any later version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #include #include "bytearray.h" #include "bytearrayiterator.h" #include "bytearrayprototype.h" #include Q_DECLARE_METATYPE(QByteArray*) Q_DECLARE_METATYPE(ByteArray*) -/* -static qint32 toArrayIndex(const QString &str) { - QByteArray bytes = str.toUtf8(); - char *eptr; - - quint32 pos = strtoul(bytes.constData(), &eptr, 10); - if((eptr == bytes.constData() + bytes.size()) && - (QByteArray::number(pos) == bytes)) - { - return pos; - } - - return -1; -} -*/ - ByteArray::ByteArray(QScriptEngine *engine) : QObject(engine), QScriptClass(engine) { qScriptRegisterMetaType(engine, this->toScriptValue, this->fromScriptValue); this->length=engine->toStringHandle(QLatin1String("length")); this->proto=engine->newQObject(new ByteArrayPrototype(this), QScriptEngine::QtOwnership, QScriptEngine::SkipMethodsInEnumeration | QScriptEngine::ExcludeSuperClassMethods | QScriptEngine::ExcludeSuperClassProperties); QScriptValue global=engine->globalObject(); proto.setPrototype(global.property("Object").property("prototype")); this->ctor=engine->newFunction(this->construct,this->proto); this->ctor.setData(qScriptValueFromValue(engine,this)); } ByteArray::~ByteArray() {} QScriptClass::QueryFlags ByteArray::queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id) { QByteArray *ba=qscriptvalue_cast(object.data()); if(!ba) return 0; if(name!=this->length) { bool is_array_index; qint32 pos=name.toArrayIndex(&is_array_index); if(!is_array_index) return 0; *id=pos; if((flags & HandlesReadAccess) && (pos>=ba->size())) flags &= ~HandlesReadAccess; } return flags; } QScriptValue ByteArray::property(const QScriptValue &object, const QScriptString &name, uint id) { QByteArray *ba=qscriptvalue_cast(object.data()); if(!ba) return QScriptValue(); if(name==length) return ba->length(); else { qint32 pos=id; if((pos < 0) || (pos >= ba->size())) return QScriptValue(); return uint(ba->at(pos)) & 255; } return QScriptValue(); } void ByteArray::setProperty(QScriptValue &object, const QScriptString &name, uint id, const QScriptValue &value) { QByteArray *ba=qscriptvalue_cast(object.data()); if(!ba) return; if(name==length) this->resize(*ba,value.toInt32()); else { qint32 pos=id; if(pos<0) return; if(ba->size()<=pos) this->resize(*ba,pos + 1); (*ba)[pos]=char(value.toInt32()); } } QScriptValue::PropertyFlags ByteArray::propertyFlags(const QScriptValue &object, const QScriptString &name, uint id) { Q_UNUSED(object); Q_UNUSED(id); if(name==length) { return QScriptValue::Undeletable | QScriptValue::SkipInEnumeration; } return QScriptValue::Undeletable; } QScriptClassPropertyIterator *ByteArray::newIterator(const QScriptValue &object) { return new ByteArrayIterator(object); } QString ByteArray::name() const { return QLatin1String("ByteArray"); } QScriptValue ByteArray::prototype() const { return proto; } QScriptValue ByteArray::constructor() { return ctor; } QScriptValue ByteArray::newInstance(int size) { +#if QT_VERSION >= 0x040700 this->engine()->reportAdditionalMemoryCost(size); +#endif return newInstance(QByteArray(size,0)); } QScriptValue ByteArray::newInstance(const QByteArray &ba) { QScriptValue data=engine()->newVariant(qVariantFromValue(ba)); return engine()->newObject(this,data); } QScriptValue ByteArray::construct(QScriptContext *ctx, QScriptEngine *) { ByteArray *cls=qscriptvalue_cast(ctx->callee().data()); if(!cls) return QScriptValue(); QScriptValue arg=ctx->argument(0); if(arg.instanceOf(ctx->callee())) return cls->newInstance(qscriptvalue_cast(arg)); int size=arg.toInt32(); return cls->newInstance(size); } QScriptValue ByteArray::toScriptValue(QScriptEngine *eng, const QByteArray &ba) { QScriptValue ctor=eng->globalObject().property("ByteArray"); ByteArray *cls=qscriptvalue_cast(ctor.data()); if(!cls) return eng->newVariant(qVariantFromValue(ba)); return cls->newInstance(ba); } void ByteArray::fromScriptValue(const QScriptValue &obj, QByteArray &ba) { ba=qvariant_cast(obj.data().toVariant()); } void ByteArray::resize(QByteArray &ba, int newSize) { int oldSize=ba.size(); ba.resize(newSize); +#if QT_VERSION >= 0x040700 if(newSize>oldSize) this->engine()->reportAdditionalMemoryCost(newSize-oldSize); +#endif } diff --git a/trunk/report_templates/SAM_UserAccounts.qs b/trunk/report_templates/SAM_UserAccounts.qs index ba6d384..0f77c9c 100644 --- a/trunk/report_templates/SAM_UserAccounts.qs +++ b/trunk/report_templates/SAM_UserAccounts.qs @@ -1,64 +1,75 @@ // See http://windowsir.blogspot.com/2006/08/getting-user-info-from-image.html +function print_table_row(cell01,cell02) { + println(" ",cell01,"",cell02,""); +} + +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)); +} + println(""); println(" User Accounts"); println(" "); println("

User accounts

"); // Iterate over all user names var user_names=GetRegistryNodes("\\SAM\\Domains\\Account\\Users\\Names"); for(var i=0;i"); // Print user name println(" ",user_names[i],"
"); println(" "); // 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(""); + println(" "); // RegistryKeyTypeToString returns the rid prepended with "0x". We have to remove that for further processing user_rid=String(user_rid).substr(2); // Get user's V key and print various infos var v_key=GetRegistryKeyValue(String().concat("\\SAM\\Domains\\Account\\Users\\",user_rid),"V"); + 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"); - println(""); - println(""); - println(""); - println(""); - - println(""); - println(""); - + 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(""); - - - - - println("
RID:",Number(user_rid).toString(10)," (",user_rid,")","
RID:",Number(user_rid).toString(10)," (",user_rid,")","
Last login time:",RegistryKeyValueToVariant(f_key.value,"filetime",8),"
Last pw change:",RegistryKeyValueToVariant(f_key.value,"filetime",24),"
Last failed login:",RegistryKeyValueToVariant(f_key.value,"filetime",40),"
Account expires:",RegistryKeyValueToVariant(f_key.value,"filetime",32),"
Total logins:",RegistryKeyValueToVariant(f_key.value,"uint16",66),"
Failed logins:",RegistryKeyValueToVariant(f_key.value,"uint16",64),"
Account flags:"); + print("
Account flags:"); if(acc_flags&0x0001) print("Disabled "); if(acc_flags&0x0002) print("HomeDirReq "); if(acc_flags&0x0004) print("PwNotReq "); if(acc_flags&0x0008) print("TempDupAcc "); - // Don't think this would be useful to show + // 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 "); - println("
"); + println(""); + // TODO: User group membership + println(" "); println("

"); } println("");