diff --git a/trunk/dlgaddkey.cpp b/trunk/dlgaddkey.cpp index 96a408c..f291c91 100644 --- a/trunk/dlgaddkey.cpp +++ b/trunk/dlgaddkey.cpp @@ -1,239 +1,379 @@ -#include "dlgaddkey.h" -#include "ui_dlgaddkey.h" - -#include "registryhive.h" +/******************************************************************************* +* fred Copyright (c) 2011-2013 by Gillen Daniel * +* * +* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * +* with special feautures useful during forensic analysis. * +* * +* This program is free software: you can redistribute it and/or modify it * +* under the terms of the GNU General Public License as published by the Free * +* Software Foundation, either version 3 of the License, or (at your option) * +* any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * +* more details. * +* * +* You should have received a copy of the GNU General Public License along with * +* this program. If not, see . * +*******************************************************************************/ #include #include +#include +#include +#include #include +#include "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); // 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() -{ +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."), + 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), + 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), + 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_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_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->setContentsMargins(0,0,0,0); this->p_binary_widget_layout->setContentsMargins(0,0,0,0); } void DlgAddKey::DestroyValueWidgets() { 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_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") { - p_line_widget_line_edit->setText( + 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: How should text be splitted? Ascii, utfxx ?????? - // p_text_widget_text_edit + // TODO: Identify if this is UTF16 or UTF8 and remember it + QStringList strings=RegistryHive::KeyValueToStringList(key_value, + key_value_type); + this->p_text_widget_text_edit->setPlainText(strings.join("\n")); } else if(key_value_type=="REG_DWORD") { - p_number_widget_line_edit->setText( + this->p_number_widget_line_edit->setText( RegistryHive::KeyValueToString(key_value,"int32")); } else if(key_value_type=="REG_DWORD_BIG_ENDIAN") { - p_number_widget_line_edit->setText( + this->p_number_widget_line_edit->setText( RegistryHive::KeyValueToString(key_value,"int32",0,0,false)); } else if(key_value_type=="REG_QWORD") { - p_number_widget_line_edit->setText( + 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") { // TODO: Set binary data } } QByteArray DlgAddKey::GetValueWidgetData() { QString key_value_type=this->KeyType(); if(key_value_type=="REG_SZ" || key_value_type=="REG_EXPAND_SZ") { - // TODO: Won't work! Normally UTF16_LE, but?????? - return QByteArray(p_line_widget_line_edit->text().toLocal8Bit().constData()); + // 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: How should text be concatenated? Ascii, utfxx ?????? - // p_text_widget_text_edit - return QByteArray(); - } else if(key_value_type=="REG_DWORD") { - // TODO: When pressing ok, we need to check if conversion to number works! - // TODO: We need host_to_le32 here! + // 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: Do we need to check for \r\n on Windows?? + for(int i=0;iisChecked()) { - val=p_number_widget_line_edit->text().toInt(); + if(this->p_number_widget_rb_decimal->isChecked()) { + val=this->p_number_widget_line_edit->text().toInt(); } else { - val=p_number_widget_line_edit->text().toInt(0,16); + 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_DWORD_BIG_ENDIAN") { - // TODO: Convert to big endian - return QByteArray(); } else if(key_value_type=="REG_QWORD") { - // TODO: We need host_to_le64 here! int64_t val; - if(p_number_widget_rb_decimal->isChecked()) { - val=p_number_widget_line_edit->text().toLongLong(); + if(this->p_number_widget_rb_decimal->isChecked()) { + val=this->p_number_widget_line_edit->text().toLongLong(); } else { - val=p_number_widget_line_edit->text().toLongLong(0,16); + 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") { // TODO: Return binary data return QByteArray(); } 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 * +* * +* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * +* with special feautures useful during forensic analysis. * +* * +* This program is free software: you can redistribute it and/or modify it * +* under the terms of the GNU General Public License as published by the Free * +* Software Foundation, either version 3 of the License, or (at your option) * +* any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * +* more details. * +* * +* You should have received a copy of the GNU General Public License along with * +* this program. If not, see . * +*******************************************************************************/ + #ifndef DLGADDKEY_H #define DLGADDKEY_H #include #include #include #include #include #include +#include + 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; 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; 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