From 24f3f43457ac6bdeed95c1ed0a882387a509078a Mon Sep 17 00:00:00 2001 From: masoud bh Date: Mon, 9 Nov 2015 02:23:58 +0330 Subject: Add icon to exe file in windows export add version_info and icon sections in "export to windows platform". add version_info and icon to godot exe file (editor & template exe). fix an problem in image class. change all default icons to android export icon (a little more rounded). create an python script for convert file to cpp byte array for use in 'splash.h'. --- drivers/SCsub | 1 + drivers/pe_bliss/README | 61 + drivers/pe_bliss/SCsub | 5 + drivers/pe_bliss/entropy.cpp | 90 ++ drivers/pe_bliss/entropy.h | 30 + drivers/pe_bliss/file_version_info.cpp | 419 ++++++ drivers/pe_bliss/file_version_info.h | 178 +++ drivers/pe_bliss/message_table.cpp | 60 + drivers/pe_bliss/message_table.h | 35 + drivers/pe_bliss/pe_base.cpp | 1659 +++++++++++++++++++++ drivers/pe_bliss/pe_base.h | 523 +++++++ drivers/pe_bliss/pe_bliss.h | 18 + drivers/pe_bliss/pe_bliss_godot.cpp | 118 ++ drivers/pe_bliss/pe_bliss_godot.h | 7 + drivers/pe_bliss/pe_bliss_resources.h | 15 + drivers/pe_bliss/pe_bound_import.cpp | 290 ++++ drivers/pe_bliss/pe_bound_import.h | 87 ++ drivers/pe_bliss/pe_checksum.cpp | 82 + drivers/pe_bliss/pe_checksum.h | 9 + drivers/pe_bliss/pe_debug.cpp | 844 +++++++++++ drivers/pe_bliss/pe_debug.h | 303 ++++ drivers/pe_bliss/pe_directory.cpp | 38 + drivers/pe_bliss/pe_directory.h | 29 + drivers/pe_bliss/pe_dotnet.cpp | 165 ++ drivers/pe_bliss/pe_dotnet.h | 76 + drivers/pe_bliss/pe_exception.cpp | 19 + drivers/pe_bliss/pe_exception.h | 109 ++ drivers/pe_bliss/pe_exception_directory.cpp | 156 ++ drivers/pe_bliss/pe_exception_directory.h | 67 + drivers/pe_bliss/pe_exports.cpp | 679 +++++++++ drivers/pe_bliss/pe_exports.h | 163 ++ drivers/pe_bliss/pe_factory.cpp | 22 + drivers/pe_bliss/pe_factory.h | 18 + drivers/pe_bliss/pe_imports.cpp | 756 ++++++++++ drivers/pe_bliss/pe_imports.h | 187 +++ drivers/pe_bliss/pe_load_config.cpp | 536 +++++++ drivers/pe_bliss/pe_load_config.h | 163 ++ drivers/pe_bliss/pe_properties.cpp | 20 + drivers/pe_bliss/pe_properties.h | 215 +++ drivers/pe_bliss/pe_properties_generic.cpp | 624 ++++++++ drivers/pe_bliss/pe_properties_generic.h | 256 ++++ drivers/pe_bliss/pe_rebuilder.cpp | 193 +++ drivers/pe_bliss/pe_rebuilder.h | 19 + drivers/pe_bliss/pe_relocations.cpp | 299 ++++ drivers/pe_bliss/pe_relocations.h | 101 ++ drivers/pe_bliss/pe_resource_manager.cpp | 265 ++++ drivers/pe_bliss/pe_resource_manager.h | 92 ++ drivers/pe_bliss/pe_resource_viewer.cpp | 361 +++++ drivers/pe_bliss/pe_resource_viewer.h | 132 ++ drivers/pe_bliss/pe_resources.cpp | 705 +++++++++ drivers/pe_bliss/pe_resources.h | 224 +++ drivers/pe_bliss/pe_rich_data.cpp | 131 ++ drivers/pe_bliss/pe_rich_data.h | 37 + drivers/pe_bliss/pe_section.cpp | 281 ++++ drivers/pe_bliss/pe_section.h | 137 ++ drivers/pe_bliss/pe_structures.h | 1007 +++++++++++++ drivers/pe_bliss/pe_tls.cpp | 375 +++++ drivers/pe_bliss/pe_tls.h | 101 ++ drivers/pe_bliss/resource_bitmap_reader.cpp | 65 + drivers/pe_bliss/resource_bitmap_reader.h | 29 + drivers/pe_bliss/resource_bitmap_writer.cpp | 54 + drivers/pe_bliss/resource_bitmap_writer.h | 26 + drivers/pe_bliss/resource_cursor_icon_reader.cpp | 500 +++++++ drivers/pe_bliss/resource_cursor_icon_reader.h | 63 + drivers/pe_bliss/resource_cursor_icon_writer.cpp | 426 ++++++ drivers/pe_bliss/resource_cursor_icon_writer.h | 73 + drivers/pe_bliss/resource_data_info.cpp | 27 + drivers/pe_bliss/resource_data_info.h | 27 + drivers/pe_bliss/resource_internal.h | 13 + drivers/pe_bliss/resource_message_list_reader.cpp | 110 ++ drivers/pe_bliss/resource_message_list_reader.h | 28 + drivers/pe_bliss/resource_string_table_reader.cpp | 88 ++ drivers/pe_bliss/resource_string_table_reader.h | 36 + drivers/pe_bliss/resource_version_info_reader.cpp | 290 ++++ drivers/pe_bliss/resource_version_info_reader.h | 46 + drivers/pe_bliss/resource_version_info_writer.cpp | 262 ++++ drivers/pe_bliss/resource_version_info_writer.h | 31 + drivers/pe_bliss/stdint_defs.h | 24 + drivers/pe_bliss/utils.cpp | 86 ++ drivers/pe_bliss/utils.h | 84 ++ drivers/pe_bliss/version_info_editor.cpp | 163 ++ drivers/pe_bliss/version_info_editor.h | 58 + drivers/pe_bliss/version_info_types.h | 17 + drivers/pe_bliss/version_info_viewer.cpp | 159 ++ drivers/pe_bliss/version_info_viewer.h | 68 + drivers/register_driver_types.cpp | 11 +- 86 files changed, 16455 insertions(+), 1 deletion(-) create mode 100644 drivers/pe_bliss/README create mode 100644 drivers/pe_bliss/SCsub create mode 100644 drivers/pe_bliss/entropy.cpp create mode 100644 drivers/pe_bliss/entropy.h create mode 100644 drivers/pe_bliss/file_version_info.cpp create mode 100644 drivers/pe_bliss/file_version_info.h create mode 100644 drivers/pe_bliss/message_table.cpp create mode 100644 drivers/pe_bliss/message_table.h create mode 100644 drivers/pe_bliss/pe_base.cpp create mode 100644 drivers/pe_bliss/pe_base.h create mode 100644 drivers/pe_bliss/pe_bliss.h create mode 100644 drivers/pe_bliss/pe_bliss_godot.cpp create mode 100644 drivers/pe_bliss/pe_bliss_godot.h create mode 100644 drivers/pe_bliss/pe_bliss_resources.h create mode 100644 drivers/pe_bliss/pe_bound_import.cpp create mode 100644 drivers/pe_bliss/pe_bound_import.h create mode 100644 drivers/pe_bliss/pe_checksum.cpp create mode 100644 drivers/pe_bliss/pe_checksum.h create mode 100644 drivers/pe_bliss/pe_debug.cpp create mode 100644 drivers/pe_bliss/pe_debug.h create mode 100644 drivers/pe_bliss/pe_directory.cpp create mode 100644 drivers/pe_bliss/pe_directory.h create mode 100644 drivers/pe_bliss/pe_dotnet.cpp create mode 100644 drivers/pe_bliss/pe_dotnet.h create mode 100644 drivers/pe_bliss/pe_exception.cpp create mode 100644 drivers/pe_bliss/pe_exception.h create mode 100644 drivers/pe_bliss/pe_exception_directory.cpp create mode 100644 drivers/pe_bliss/pe_exception_directory.h create mode 100644 drivers/pe_bliss/pe_exports.cpp create mode 100644 drivers/pe_bliss/pe_exports.h create mode 100644 drivers/pe_bliss/pe_factory.cpp create mode 100644 drivers/pe_bliss/pe_factory.h create mode 100644 drivers/pe_bliss/pe_imports.cpp create mode 100644 drivers/pe_bliss/pe_imports.h create mode 100644 drivers/pe_bliss/pe_load_config.cpp create mode 100644 drivers/pe_bliss/pe_load_config.h create mode 100644 drivers/pe_bliss/pe_properties.cpp create mode 100644 drivers/pe_bliss/pe_properties.h create mode 100644 drivers/pe_bliss/pe_properties_generic.cpp create mode 100644 drivers/pe_bliss/pe_properties_generic.h create mode 100644 drivers/pe_bliss/pe_rebuilder.cpp create mode 100644 drivers/pe_bliss/pe_rebuilder.h create mode 100644 drivers/pe_bliss/pe_relocations.cpp create mode 100644 drivers/pe_bliss/pe_relocations.h create mode 100644 drivers/pe_bliss/pe_resource_manager.cpp create mode 100644 drivers/pe_bliss/pe_resource_manager.h create mode 100644 drivers/pe_bliss/pe_resource_viewer.cpp create mode 100644 drivers/pe_bliss/pe_resource_viewer.h create mode 100644 drivers/pe_bliss/pe_resources.cpp create mode 100644 drivers/pe_bliss/pe_resources.h create mode 100644 drivers/pe_bliss/pe_rich_data.cpp create mode 100644 drivers/pe_bliss/pe_rich_data.h create mode 100644 drivers/pe_bliss/pe_section.cpp create mode 100644 drivers/pe_bliss/pe_section.h create mode 100644 drivers/pe_bliss/pe_structures.h create mode 100644 drivers/pe_bliss/pe_tls.cpp create mode 100644 drivers/pe_bliss/pe_tls.h create mode 100644 drivers/pe_bliss/resource_bitmap_reader.cpp create mode 100644 drivers/pe_bliss/resource_bitmap_reader.h create mode 100644 drivers/pe_bliss/resource_bitmap_writer.cpp create mode 100644 drivers/pe_bliss/resource_bitmap_writer.h create mode 100644 drivers/pe_bliss/resource_cursor_icon_reader.cpp create mode 100644 drivers/pe_bliss/resource_cursor_icon_reader.h create mode 100644 drivers/pe_bliss/resource_cursor_icon_writer.cpp create mode 100644 drivers/pe_bliss/resource_cursor_icon_writer.h create mode 100644 drivers/pe_bliss/resource_data_info.cpp create mode 100644 drivers/pe_bliss/resource_data_info.h create mode 100644 drivers/pe_bliss/resource_internal.h create mode 100644 drivers/pe_bliss/resource_message_list_reader.cpp create mode 100644 drivers/pe_bliss/resource_message_list_reader.h create mode 100644 drivers/pe_bliss/resource_string_table_reader.cpp create mode 100644 drivers/pe_bliss/resource_string_table_reader.h create mode 100644 drivers/pe_bliss/resource_version_info_reader.cpp create mode 100644 drivers/pe_bliss/resource_version_info_reader.h create mode 100644 drivers/pe_bliss/resource_version_info_writer.cpp create mode 100644 drivers/pe_bliss/resource_version_info_writer.h create mode 100644 drivers/pe_bliss/stdint_defs.h create mode 100644 drivers/pe_bliss/utils.cpp create mode 100644 drivers/pe_bliss/utils.h create mode 100644 drivers/pe_bliss/version_info_editor.cpp create mode 100644 drivers/pe_bliss/version_info_editor.h create mode 100644 drivers/pe_bliss/version_info_types.h create mode 100644 drivers/pe_bliss/version_info_viewer.cpp create mode 100644 drivers/pe_bliss/version_info_viewer.h (limited to 'drivers') diff --git a/drivers/SCsub b/drivers/SCsub index bc46bf2cec..a7ed29e8e9 100644 --- a/drivers/SCsub +++ b/drivers/SCsub @@ -39,6 +39,7 @@ if (env["opus"]=="yes"): SConscript('opus/SCsub'); if (env["tools"]=="yes"): SConscript("convex_decomp/SCsub"); + SConscript('pe_bliss/SCsub'); #if env["theora"]=="yes": # SConscript("theoraplayer/SCsub") diff --git a/drivers/pe_bliss/README b/drivers/pe_bliss/README new file mode 100644 index 0000000000..8a8c0b4df9 --- /dev/null +++ b/drivers/pe_bliss/README @@ -0,0 +1,61 @@ +Открытая бесплатная библиотека для работы с PE-файлами PE Bliss. +Бесплатна к использованию, модификации и распространению. +Автор: DX +(c) DX 2011-2012, kaimi.ru + +Совместимость: Windows, Linux + +Возможности: +[+] Создание PE или PE+ файла с нуля +[+] Чтение 32-разрядных и 64-разрядных PE-файлов (PE, PE+) и единообразная работа с ними +[+] Пересборка 32-разрядных и 64-разрядных PE-файлов +[+] Работа с директориями и заголовками +[+] Конвертирование адресов +[+] Чтение и редактирование секций PE-файла +[+] Чтение и редактирование таблицы импортов +[+] Чтение и редактирование таблицы экспортов +[+] Чтение и редактирование таблиц релокаций +[+] Чтение и редактирование ресурсов +[+] Чтение и редактирование TLS +[+] Чтение и редактирование конфигурации образа (image config) +[+] Чтение базовой информации .NET +[+] Чтение и редактирование информации о привязанном импорте +[+] Чтение директории исключений (только PE+) +[+] Чтение отладочной директории с расширенной информацией +[+] Вычисление энтропии +[+] Изменение файлового выравнивания +[+] Изменение базового адреса загрузки +[+] Работа с DOS Stub'ом и Rich overlay +[+] Высокоуровневое чтение ресурсов: картинки, иконки, курсоры, информация о версии, строковые таблицы, таблицы сообщений +[+] Высокоуровневое редактирование ресурсов: картинки, иконки, курсоры, информация о версии + +[English] +Open a free library for working with PE-file PE Bliss. +Free to use, modify, and distribute. +Author: DX +(c) DX 2011-2012, kaimi.ru +Compatibility: Windows, Linux + +### Capabilities: +[+] Creation of PE or PE + file from scratch +[+] Reading the 32-bit and 64-bit PE-file (PE, PE +) and uniform working with them +[+] Rebuild 32-bit and 64-bit PE-files +[+] Working with the directors and titles +[+] Converting addresses +[+] Reading and editing sections of PE-file +[+] Reading and editing the import table +[+] Reading and editing tables exports +[+] Reading and editing tables relocations +[+] Reading and editing resources +[+] Reading and editing TLS +[+] Reading and editing the configuration of the image (image config) +[+] Reading data base .NET +[+] Reading and editing information about tethered import +[+] Read the directory exceptions (only PE +) +[+] Read debug directories with extended information +[+] The calculation of entropy +[+] Changing file alignment +[+] Change the base load address +[+] Support of DOS Stub'om and Rich overlay +[+] High-level reading resources: images, icons, cursors, version information, string tables, message table +[+] High-level editing resources: images, icons, cursors, version information \ No newline at end of file diff --git a/drivers/pe_bliss/SCsub b/drivers/pe_bliss/SCsub new file mode 100644 index 0000000000..9fbb467baa --- /dev/null +++ b/drivers/pe_bliss/SCsub @@ -0,0 +1,5 @@ +Import('env') + +env.add_source_files(env.drivers_sources,"*.cpp") + +Export('env') diff --git a/drivers/pe_bliss/entropy.cpp b/drivers/pe_bliss/entropy.cpp new file mode 100644 index 0000000000..cdd8efb8a9 --- /dev/null +++ b/drivers/pe_bliss/entropy.cpp @@ -0,0 +1,90 @@ +#include +#include "entropy.h" +#include "utils.h" + +namespace pe_bliss +{ +//Calculates entropy for PE image section +double entropy_calculator::calculate_entropy(const section& s) +{ + if(s.get_raw_data().empty()) //Don't count entropy for empty sections + throw pe_exception("Section is empty", pe_exception::section_is_empty); + + return calculate_entropy(s.get_raw_data().data(), s.get_raw_data().length()); +} + +//Calculates entropy for istream (from current position of stream) +double entropy_calculator::calculate_entropy(std::istream& file) +{ + uint32_t byte_count[256] = {0}; //Byte count for each of 255 bytes + + if(file.bad()) + throw pe_exception("Stream is bad", pe_exception::stream_is_bad); + + std::streamoff pos = file.tellg(); + + std::streamoff length = pe_utils::get_file_size(file); + length -= file.tellg(); + + if(!length) //Don't calculate entropy for empty buffers + throw pe_exception("Data length is zero", pe_exception::data_is_empty); + + //Count bytes + for(std::streamoff i = 0; i != length; ++i) + ++byte_count[static_cast(file.get())]; + + file.seekg(pos); + + return calculate_entropy(byte_count, length); +} + +//Calculates entropy for data block +double entropy_calculator::calculate_entropy(const char* data, size_t length) +{ + uint32_t byte_count[256] = {0}; //Byte count for each of 255 bytes + + if(!length) //Don't calculate entropy for empty buffers + throw pe_exception("Data length is zero", pe_exception::data_is_empty); + + //Count bytes + for(size_t i = 0; i != length; ++i) + ++byte_count[static_cast(data[i])]; + + return calculate_entropy(byte_count, length); +} + +//Calculates entropy for this PE file (only section data) +double entropy_calculator::calculate_entropy(const pe_base& pe) +{ + uint32_t byte_count[256] = {0}; //Byte count for each of 255 bytes + + size_t total_data_length = 0; + + //Count bytes for each section + for(section_list::const_iterator it = pe.get_image_sections().begin(); it != pe.get_image_sections().end(); ++it) + { + const std::string& data = (*it).get_raw_data(); + size_t length = data.length(); + total_data_length += length; + for(size_t i = 0; i != length; ++i) + ++byte_count[static_cast(data[i])]; + } + + return calculate_entropy(byte_count, total_data_length); +} + +//Calculates entropy from bytes count +double entropy_calculator::calculate_entropy(const uint32_t byte_count[256], std::streamoff total_length) +{ + double entropy = 0.; //Entropy result value + //Calculate entropy + for(uint32_t i = 0; i < 256; ++i) + { + double temp = static_cast(byte_count[i]) / total_length; + if(temp > 0.) + entropy += std::abs(temp * (std::log(temp) * pe_utils::log_2)); + } + + return entropy; +} +} diff --git a/drivers/pe_bliss/entropy.h b/drivers/pe_bliss/entropy.h new file mode 100644 index 0000000000..d49d0f7e9b --- /dev/null +++ b/drivers/pe_bliss/entropy.h @@ -0,0 +1,30 @@ +#pragma once +#include +#include "pe_base.h" + +namespace pe_bliss +{ +class entropy_calculator +{ +public: + //Calculates entropy for PE image section + static double calculate_entropy(const section& s); + + //Calculates entropy for istream (from current position of stream) + static double calculate_entropy(std::istream& file); + + //Calculates entropy for data block + static double calculate_entropy(const char* data, size_t length); + + //Calculates entropy for this PE file (only section data) + static double calculate_entropy(const pe_base& pe); + +private: + entropy_calculator(); + entropy_calculator(const entropy_calculator&); + entropy_calculator& operator=(const entropy_calculator&); + + //Calculates entropy from bytes count + static double calculate_entropy(const uint32_t byte_count[256], std::streamoff total_length); +}; +} diff --git a/drivers/pe_bliss/file_version_info.cpp b/drivers/pe_bliss/file_version_info.cpp new file mode 100644 index 0000000000..50a02f8908 --- /dev/null +++ b/drivers/pe_bliss/file_version_info.cpp @@ -0,0 +1,419 @@ +#include "file_version_info.h" +#include "pe_structures.h" + +namespace pe_bliss +{ +using namespace pe_win; + +//Default constructor +file_version_info::file_version_info() + :file_version_ms_(0), file_version_ls_(0), + product_version_ms_(0), product_version_ls_(0), + file_flags_(0), + file_os_(0), + file_type_(0), file_subtype_(0), + file_date_ms_(0), file_date_ls_(0) +{} + +//Constructor from Windows fixed version info structure +file_version_info::file_version_info(const vs_fixedfileinfo& info) + :file_version_ms_(info.dwFileVersionMS), file_version_ls_(info.dwFileVersionLS), + product_version_ms_(info.dwProductVersionMS), product_version_ls_(info.dwProductVersionLS), + file_flags_(info.dwFileFlags), + file_os_(info.dwFileOS), + file_type_(info.dwFileType), file_subtype_(info.dwFileSubtype), + file_date_ms_(info.dwFileDateMS), file_date_ls_(info.dwFileDateLS) +{} + +//Returns true if file is debug-built +bool file_version_info::is_debug() const +{ + return file_flags_ & vs_ff_debug ? true : false; +} + +//Returns true if file is release-built +bool file_version_info::is_prerelease() const +{ + return file_flags_ & vs_ff_prerelease ? true : false; +} + +//Returns true if file is patched +bool file_version_info::is_patched() const +{ + return file_flags_ & vs_ff_patched ? true : false; +} + +//Returns true if private build +bool file_version_info::is_private_build() const +{ + return file_flags_ & vs_ff_privatebuild ? true : false; +} + +//Returns true if special build +bool file_version_info::is_special_build() const +{ + return file_flags_ & vs_ff_specialbuild ? true : false; +} + +//Returns true if info inferred +bool file_version_info::is_info_inferred() const +{ + return file_flags_ & vs_ff_infoinferred ? true : false; +} + +//Retuens file flags (raw DWORD) +uint32_t file_version_info::get_file_flags() const +{ + return file_flags_; +} + +//Returns file version most significant DWORD +uint32_t file_version_info::get_file_version_ms() const +{ + return file_version_ms_; +} + +//Returns file version least significant DWORD +uint32_t file_version_info::get_file_version_ls() const +{ + return file_version_ls_; +} + +//Returns product version most significant DWORD +uint32_t file_version_info::get_product_version_ms() const +{ + return product_version_ms_; +} + +//Returns product version least significant DWORD +uint32_t file_version_info::get_product_version_ls() const +{ + return product_version_ls_; +} + +//Returns file OS type (raw DWORD) +uint32_t file_version_info::get_file_os_raw() const +{ + return file_os_; +} + +//Returns file OS type +file_version_info::file_os_type file_version_info::get_file_os() const +{ + //Determine file operation system type + switch(file_os_) + { + case vos_dos: + return file_os_dos; + + case vos_os216: + return file_os_os216; + + case vos_os232: + return file_os_os232; + + case vos_nt: + return file_os_nt; + + case vos_wince: + return file_os_wince; + + case vos__windows16: + return file_os_win16; + + case vos__pm16: + return file_os_pm16; + + case vos__pm32: + return file_os_pm32; + + case vos__windows32: + return file_os_win32; + + case vos_dos_windows16: + return file_os_dos_win16; + + case vos_dos_windows32: + return file_os_dos_win32; + + case vos_os216_pm16: + return file_os_os216_pm16; + + case vos_os232_pm32: + return file_os_os232_pm32; + + case vos_nt_windows32: + return file_os_nt_win32; + } + + return file_os_unknown; +} + +//Returns file type (raw DWORD) +uint32_t file_version_info::get_file_type_raw() const +{ + return file_type_; +} + +//Returns file type +file_version_info::file_type file_version_info::get_file_type() const +{ + //Determine file type + switch(file_type_) + { + case vft_app: + return file_type_application; + + case vft_dll: + return file_type_dll; + + case vft_drv: + return file_type_driver; + + case vft_font: + return file_type_font; + + case vft_vxd: + return file_type_vxd; + + case vft_static_lib: + return file_type_static_lib; + } + + return file_type_unknown; +} + +//Returns file subtype (usually non-zero for drivers and fonts) +uint32_t file_version_info::get_file_subtype() const +{ + return file_subtype_; +} + +//Returns file date most significant DWORD +uint32_t file_version_info::get_file_date_ms() const +{ + return file_date_ms_; +} + +//Returns file date least significant DWORD +uint32_t file_version_info::get_file_date_ls() const +{ + return file_date_ls_; +} + +//Helper to set file flag +void file_version_info::set_file_flag(uint32_t flag) +{ + file_flags_ |= flag; +} + +//Helper to clear file flag +void file_version_info::clear_file_flag(uint32_t flag) +{ + file_flags_ &= ~flag; +} + +//Helper to set or clear file flag +void file_version_info::set_file_flag(uint32_t flag, bool set_flag) +{ + set_flag ? set_file_flag(flag) : clear_file_flag(flag); +} + +//Sets if file is debug-built +void file_version_info::set_debug(bool debug) +{ + set_file_flag(vs_ff_debug, debug); +} + +//Sets if file is prerelease +void file_version_info::set_prerelease(bool prerelease) +{ + set_file_flag(vs_ff_prerelease, prerelease); +} + +//Sets if file is patched +void file_version_info::set_patched(bool patched) +{ + set_file_flag(vs_ff_patched, patched); +} + +//Sets if private build +void file_version_info::set_private_build(bool private_build) +{ + set_file_flag(vs_ff_privatebuild, private_build); +} + +//Sets if special build +void file_version_info::set_special_build(bool special_build) +{ + set_file_flag(vs_ff_specialbuild, special_build); +} + +//Sets if info inferred +void file_version_info::set_info_inferred(bool info_inferred) +{ + set_file_flag(vs_ff_infoinferred, info_inferred); +} + +//Sets flags (raw DWORD) +void file_version_info::set_file_flags(uint32_t file_flags) +{ + file_flags_ = file_flags; +} + +//Sets file version most significant DWORD +void file_version_info::set_file_version_ms(uint32_t file_version_ms) +{ + file_version_ms_ = file_version_ms; +} + +//Sets file version least significant DWORD +void file_version_info::set_file_version_ls(uint32_t file_version_ls) +{ + file_version_ls_ = file_version_ls; +} + +//Sets product version most significant DWORD +void file_version_info::set_product_version_ms(uint32_t product_version_ms) +{ + product_version_ms_ = product_version_ms; +} + +//Sets product version least significant DWORD +void file_version_info::set_product_version_ls(uint32_t product_version_ls) +{ + product_version_ls_ = product_version_ls; +} + +//Sets file OS type (raw DWORD) +void file_version_info::set_file_os_raw(uint32_t file_os) +{ + file_os_ = file_os; +} + +//Sets file OS type +void file_version_info::set_file_os(file_os_type file_os) +{ + //Determine file operation system type + switch(file_os) + { + case file_os_dos: + file_os_ = vos_dos; + return; + + case file_os_os216: + file_os_ = vos_os216; + return; + + case file_os_os232: + file_os_ = vos_os232; + return; + + case file_os_nt: + file_os_ = vos_nt; + return; + + case file_os_wince: + file_os_ = vos_wince; + return; + + case file_os_win16: + file_os_ = vos__windows16; + return; + + case file_os_pm16: + file_os_ = vos__pm16; + return; + + case file_os_pm32: + file_os_ = vos__pm32; + return; + + case file_os_win32: + file_os_ = vos__windows32; + return; + + case file_os_dos_win16: + file_os_ = vos_dos_windows16; + return; + + case file_os_dos_win32: + file_os_ = vos_dos_windows32; + return; + + case file_os_os216_pm16: + file_os_ = vos_os216_pm16; + return; + + case file_os_os232_pm32: + file_os_ = vos_os232_pm32; + return; + + case file_os_nt_win32: + file_os_ = vos_nt_windows32; + return; + + default: + return; + } +} + +//Sets file type (raw DWORD) +void file_version_info::set_file_type_raw(uint32_t file_type) +{ + file_type_ = file_type; +} + +//Sets file type +void file_version_info::set_file_type(file_type file_type) +{ + //Determine file type + switch(file_type) + { + case file_type_application: + file_type_ = vft_app; + return; + + case file_type_dll: + file_type_ = vft_dll; + return; + + case file_type_driver: + file_type_ = vft_drv; + return; + + case file_type_font: + file_type_ = vft_font; + return; + + case file_type_vxd: + file_type_ = vft_vxd; + return; + + case file_type_static_lib: + file_type_ = vft_static_lib; + return; + + default: + return; + } +} + +//Sets file subtype (usually non-zero for drivers and fonts) +void file_version_info::set_file_subtype(uint32_t file_subtype) +{ + file_subtype_ = file_subtype; +} + +//Sets file date most significant DWORD +void file_version_info::set_file_date_ms(uint32_t file_date_ms) +{ + file_date_ms_ = file_date_ms; +} + +//Sets file date least significant DWORD +void file_version_info::set_file_date_ls(uint32_t file_date_ls) +{ + file_date_ls_ = file_date_ls; +} +} diff --git a/drivers/pe_bliss/file_version_info.h b/drivers/pe_bliss/file_version_info.h new file mode 100644 index 0000000000..8a469dbb8d --- /dev/null +++ b/drivers/pe_bliss/file_version_info.h @@ -0,0 +1,178 @@ +#pragma once +#include +#include +#include "stdint_defs.h" +#include "pe_structures.h" + +namespace pe_bliss +{ +//Structure representing fixed file version info +class file_version_info +{ +public: + //Enumeration of file operating system types + enum file_os_type + { + file_os_unknown, + file_os_dos, + file_os_os216, + file_os_os232, + file_os_nt, + file_os_wince, + file_os_win16, + file_os_pm16, + file_os_pm32, + file_os_win32, + file_os_dos_win16, + file_os_dos_win32, + file_os_os216_pm16, + file_os_os232_pm32, + file_os_nt_win32 + }; + + //Enumeration of file types + enum file_type + { + file_type_unknown, + file_type_application, + file_type_dll, + file_type_driver, + file_type_font, + file_type_vxd, + file_type_static_lib + }; + +public: + //Default constructor + file_version_info(); + //Constructor from Windows fixed version info structure + explicit file_version_info(const pe_win::vs_fixedfileinfo& info); + +public: //Getters + //Returns true if file is debug-built + bool is_debug() const; + //Returns true if file is prerelease + bool is_prerelease() const; + //Returns true if file is patched + bool is_patched() const; + //Returns true if private build + bool is_private_build() const; + //Returns true if special build + bool is_special_build() const; + //Returns true if info inferred + bool is_info_inferred() const; + //Retuens file flags (raw DWORD) + uint32_t get_file_flags() const; + + //Returns file version most significant DWORD + uint32_t get_file_version_ms() const; + //Returns file version least significant DWORD + uint32_t get_file_version_ls() const; + //Returns product version most significant DWORD + uint32_t get_product_version_ms() const; + //Returns product version least significant DWORD + uint32_t get_product_version_ls() const; + + //Returns file OS type (raw DWORD) + uint32_t get_file_os_raw() const; + //Returns file OS type + file_os_type get_file_os() const; + + //Returns file type (raw DWORD) + uint32_t get_file_type_raw() const; + //Returns file type + file_type get_file_type() const; + + //Returns file subtype (usually non-zero for drivers and fonts) + uint32_t get_file_subtype() const; + + //Returns file date most significant DWORD + uint32_t get_file_date_ms() const; + //Returns file date least significant DWORD + uint32_t get_file_date_ls() const; + + //Returns file version string + template + const std::basic_string get_file_version_string() const + { + return get_version_string(file_version_ms_, file_version_ls_); + } + + //Returns product version string + template + const std::basic_string get_product_version_string() const + { + return get_version_string(product_version_ms_, product_version_ls_); + } + +public: //Setters + //Sets if file is debug-built + void set_debug(bool debug); + //Sets if file is prerelease + void set_prerelease(bool prerelease); + //Sets if file is patched + void set_patched(bool patched); + //Sets if private build + void set_private_build(bool private_build); + //Sets if special build + void set_special_build(bool special_build); + //Sets if info inferred + void set_info_inferred(bool info_inferred); + //Sets flags (raw DWORD) + void set_file_flags(uint32_t file_flags); + + //Sets file version most significant DWORD + void set_file_version_ms(uint32_t file_version_ms); + //Sets file version least significant DWORD + void set_file_version_ls(uint32_t file_version_ls); + //Sets product version most significant DWORD + void set_product_version_ms(uint32_t product_version_ms); + //Sets product version least significant DWORD + void set_product_version_ls(uint32_t product_version_ls); + + //Sets file OS type (raw DWORD) + void set_file_os_raw(uint32_t file_os); + //Sets file OS type + void set_file_os(file_os_type file_os); + + //Sets file type (raw DWORD) + void set_file_type_raw(uint32_t file_type); + //Sets file type + void set_file_type(file_type file_type); + + //Sets file subtype (usually non-zero for drivers and fonts) + void set_file_subtype(uint32_t file_subtype); + + //Sets file date most significant DWORD + void set_file_date_ms(uint32_t file_date_ms); + //Sets file date least significant DWORD + void set_file_date_ls(uint32_t file_date_ls); + +private: + //Helper to convert version DWORDs to string + template + static const std::basic_string get_version_string(uint32_t ms, uint32_t ls) + { + std::basic_stringstream ss; + ss << (ms >> 16) << static_cast(L'.') + << (ms & 0xFFFF) << static_cast(L'.') + << (ls >> 16) << static_cast(L'.') + << (ls & 0xFFFF); + return ss.str(); + } + + //Helper to set file flag + void set_file_flag(uint32_t flag); + //Helper to clear file flag + void clear_file_flag(uint32_t flag); + //Helper to set or clear file flag + void set_file_flag(uint32_t flag, bool set_flag); + + uint32_t file_version_ms_, file_version_ls_, + product_version_ms_, product_version_ls_; + uint32_t file_flags_; + uint32_t file_os_; + uint32_t file_type_, file_subtype_; + uint32_t file_date_ms_, file_date_ls_; +}; +} diff --git a/drivers/pe_bliss/message_table.cpp b/drivers/pe_bliss/message_table.cpp new file mode 100644 index 0000000000..940387dd28 --- /dev/null +++ b/drivers/pe_bliss/message_table.cpp @@ -0,0 +1,60 @@ +#include "message_table.h" +#include "utils.h" + +namespace pe_bliss +{ +//Default constructor +message_table_item::message_table_item() + :unicode_(false) +{} + +//Constructor from ANSI string +message_table_item::message_table_item(const std::string& str) + :unicode_(false), ansi_str_(str) +{ + pe_utils::strip_nullbytes(ansi_str_); +} + +//Constructor from UNICODE string +message_table_item::message_table_item(const std::wstring& str) + :unicode_(true), unicode_str_(str) +{ + pe_utils::strip_nullbytes(unicode_str_); +} + +//Returns true if contained string is unicode +bool message_table_item::is_unicode() const +{ + return unicode_; +} + +//Returns ANSI string +const std::string& message_table_item::get_ansi_string() const +{ + return ansi_str_; +} + +//Returns UNICODE string +const std::wstring& message_table_item::get_unicode_string() const +{ + return unicode_str_; +} + +//Sets ANSI string (clears UNICODE one) +void message_table_item::set_string(const std::string& str) +{ + ansi_str_ = str; + pe_utils::strip_nullbytes(ansi_str_); + unicode_str_.clear(); + unicode_ = false; +} + +//Sets UNICODE string (clears ANSI one) +void message_table_item::set_string(const std::wstring& str) +{ + unicode_str_ = str; + pe_utils::strip_nullbytes(unicode_str_); + ansi_str_.clear(); + unicode_ = true; +} +} diff --git a/drivers/pe_bliss/message_table.h b/drivers/pe_bliss/message_table.h new file mode 100644 index 0000000000..d437f511b2 --- /dev/null +++ b/drivers/pe_bliss/message_table.h @@ -0,0 +1,35 @@ +#pragma once +#include +#include +#include "stdint_defs.h" + +namespace pe_bliss +{ +//Structure representing message table string +class message_table_item +{ +public: + //Default constructor + message_table_item(); + //Constructors from ANSI and UNICODE strings + explicit message_table_item(const std::string& str); + explicit message_table_item(const std::wstring& str); + + //Returns true if string is UNICODE + bool is_unicode() const; + //Returns ANSI string + const std::string& get_ansi_string() const; + //Returns UNICODE string + const std::wstring& get_unicode_string() const; + +public: + //Sets ANSI or UNICODE string + void set_string(const std::string& str); + void set_string(const std::wstring& str); + +private: + bool unicode_; + std::string ansi_str_; + std::wstring unicode_str_; +}; +} diff --git a/drivers/pe_bliss/pe_base.cpp b/drivers/pe_bliss/pe_base.cpp new file mode 100644 index 0000000000..bdce0977cb --- /dev/null +++ b/drivers/pe_bliss/pe_base.cpp @@ -0,0 +1,1659 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "pe_exception.h" +#include "pe_base.h" + +namespace pe_bliss +{ +using namespace pe_win; + +//Constructor +pe_base::pe_base(std::istream& file, const pe_properties& props, bool read_debug_raw_data) +{ + props_ = props.duplicate().release(); + + //Save istream state + std::ios_base::iostate state = file.exceptions(); + std::streamoff old_offset = file.tellg(); + + try + { + file.exceptions(std::ios::goodbit); + //Read DOS header, PE headers and section data + read_dos_header(file); + read_pe(file, read_debug_raw_data); + } + catch(const std::exception&) + { + //If something went wrong, restore istream state + file.seekg(old_offset); + file.exceptions(state); + file.clear(); + //Rethrow + throw; + } + + //Restore istream state + file.seekg(old_offset); + file.exceptions(state); + file.clear(); +} + +pe_base::pe_base(const pe_properties& props, uint32_t section_alignment, bool dll, uint16_t subsystem) +{ + props_ = props.duplicate().release(); + props_->create_pe(section_alignment, subsystem); + + has_overlay_ = false; + memset(&dos_header_, 0, sizeof(dos_header_)); + + dos_header_.e_magic = 0x5A4D; //"MZ" + //Magic numbers from MSVC++ build + dos_header_.e_maxalloc = 0xFFFF; + dos_header_.e_cblp = 0x90; + dos_header_.e_cp = 3; + dos_header_.e_cparhdr = 4; + dos_header_.e_sp = 0xB8; + dos_header_.e_lfarlc = 64; + + set_characteristics(image_file_executable_image | image_file_relocs_stripped); + + if(get_pe_type() == pe_type_32) + set_characteristics_flags(image_file_32bit_machine); + + if(dll) + set_characteristics_flags(image_file_dll); + + set_subsystem_version(5, 1); //WinXP + set_os_version(5, 1); //WinXP +} + +pe_base::pe_base(const pe_base& pe) + :dos_header_(pe.dos_header_), + rich_overlay_(pe.rich_overlay_), + sections_(pe.sections_), + has_overlay_(pe.has_overlay_), + full_headers_data_(pe.full_headers_data_), + debug_data_(pe.debug_data_), + props_(0) +{ + props_ = pe.props_->duplicate().release(); +} + +pe_base& pe_base::operator=(const pe_base& pe) +{ + dos_header_ = pe.dos_header_; + rich_overlay_ = pe.rich_overlay_; + sections_ = pe.sections_; + has_overlay_ = pe.has_overlay_; + full_headers_data_ = pe.full_headers_data_; + debug_data_ = pe.debug_data_; + delete props_; + props_ = 0; + props_ = pe.props_->duplicate().release(); + + return *this; +} + +pe_base::~pe_base() +{ + delete props_; +} + +//Returns dos header +const image_dos_header& pe_base::get_dos_header() const +{ + return dos_header_; +} + +//Returns dos header +image_dos_header& pe_base::get_dos_header() +{ + return dos_header_; +} + +//Returns PE headers start position (e_lfanew) +int32_t pe_base::get_pe_header_start() const +{ + return dos_header_.e_lfanew; +} + +//Strips MSVC stub overlay +void pe_base::strip_stub_overlay() +{ + rich_overlay_.clear(); +} + +//Fills MSVC stub overlay with character c +void pe_base::fill_stub_overlay(char c) +{ + if(rich_overlay_.length()) + rich_overlay_.assign(rich_overlay_.length(), c); +} + +//Sets stub MSVS overlay +void pe_base::set_stub_overlay(const std::string& data) +{ + rich_overlay_ = data; +} + +//Returns stub overlay +const std::string& pe_base::get_stub_overlay() const +{ + return rich_overlay_; +} + +//Realigns all sections +void pe_base::realign_all_sections() +{ + for(unsigned int i = 0; i < sections_.size(); i++) + realign_section(i); +} + +//Returns number of sections from PE header +uint16_t pe_base::get_number_of_sections() const +{ + return props_->get_number_of_sections(); +} + +//Updates number of sections in PE header +uint16_t pe_base::update_number_of_sections() +{ + uint16_t new_number = static_cast(sections_.size()); + props_->set_number_of_sections(new_number); + return new_number; +} + +//Returns section alignment +uint32_t pe_base::get_section_alignment() const +{ + return props_->get_section_alignment(); +} + +//Returns image sections list +section_list& pe_base::get_image_sections() +{ + return sections_; +} + +//Returns image sections list +const section_list& pe_base::get_image_sections() const +{ + return sections_; +} + +//Realigns section by index +void pe_base::realign_section(uint32_t index) +{ + //Check index + if(sections_.size() <= index) + throw pe_exception("Section not found", pe_exception::section_not_found); + + //Get section iterator + section_list::iterator it = sections_.begin() + index; + section& s = *it; + + //Calculate, how many null bytes we have in the end of raw section data + std::size_t strip = 0; + for(std::size_t i = (*it).get_raw_data().length(); i >= 1; --i) + { + if(s.get_raw_data()[i - 1] == 0) + strip++; + else + break; + } + + if(it == sections_.end() - 1) //If we're realigning the last section + { + //We can strip ending null bytes + s.set_size_of_raw_data(static_cast(s.get_raw_data().length() - strip)); + s.get_raw_data().resize(s.get_raw_data().length() - strip, 0); + } + else + { + //Else just set size of raw data + uint32_t raw_size_aligned = s.get_aligned_raw_size(get_file_alignment()); + s.set_size_of_raw_data(raw_size_aligned); + s.get_raw_data().resize(raw_size_aligned, 0); + } +} + +//Returns file alignment +uint32_t pe_base::get_file_alignment() const +{ + return props_->get_file_alignment(); +} + +//Sets file alignment +void pe_base::set_file_alignment(uint32_t alignment) +{ + //Check alignment + if(alignment < minimum_file_alignment) + throw pe_exception("File alignment can't be less than 512", pe_exception::incorrect_file_alignment); + + if(!pe_utils::is_power_of_2(alignment)) + throw pe_exception("File alignment must be a power of 2", pe_exception::incorrect_file_alignment); + + if(alignment > get_section_alignment()) + throw pe_exception("File alignment must be <= section alignment", pe_exception::incorrect_file_alignment); + + //Set file alignment without any additional checks + set_file_alignment_unchecked(alignment); +} + +//Returns size of image +uint32_t pe_base::get_size_of_image() const +{ + return props_->get_size_of_image(); +} + +//Returns image entry point +uint32_t pe_base::get_ep() const +{ + return props_->get_ep(); +} + +//Sets image entry point (just a value of PE header) +void pe_base::set_ep(uint32_t new_ep) +{ + props_->set_ep(new_ep); +} + +//Returns number of RVA and sizes (number of DATA_DIRECTORY entries) +uint32_t pe_base::get_number_of_rvas_and_sizes() const +{ + return props_->get_number_of_rvas_and_sizes(); +} + +//Sets number of RVA and sizes (number of DATA_DIRECTORY entries) +void pe_base::set_number_of_rvas_and_sizes(uint32_t number) +{ + props_->set_number_of_rvas_and_sizes(number); +} + +//Returns PE characteristics +uint16_t pe_base::get_characteristics() const +{ + return props_->get_characteristics(); +} + +//Sets PE characteristics (a value inside header) +void pe_base::set_characteristics(uint16_t ch) +{ + props_->set_characteristics(ch); +} + +//Returns section from RVA +section& pe_base::section_from_rva(uint32_t rva) +{ + //Search for section + for(section_list::iterator i = sections_.begin(); i != sections_.end(); ++i) + { + section& s = *i; + //Return section if found + if(rva >= s.get_virtual_address() && rva < s.get_virtual_address() + s.get_aligned_virtual_size(get_section_alignment())) + return s; + } + + throw pe_exception("No section found by presented address", pe_exception::no_section_found); +} + +//Returns section from RVA +const section& pe_base::section_from_rva(uint32_t rva) const +{ + //Search for section + for(section_list::const_iterator i = sections_.begin(); i != sections_.end(); ++i) + { + const section& s = *i; + //Return section if found + if(rva >= s.get_virtual_address() && rva < s.get_virtual_address() + s.get_aligned_virtual_size(get_section_alignment())) + return s; + } + + throw pe_exception("No section found by presented address", pe_exception::no_section_found); +} + +//Returns section from directory ID +section& pe_base::section_from_directory(uint32_t directory_id) +{ + return section_from_rva(get_directory_rva(directory_id)); +} + +//Returns section from directory ID +const section& pe_base::section_from_directory(uint32_t directory_id) const +{ + return section_from_rva(get_directory_rva(directory_id)); +} + +//Sets section virtual size (actual for the last one of this PE or for unbound section) +void pe_base::set_section_virtual_size(section& s, uint32_t vsize) +{ + //Check if we're changing virtual size of the last section + //Of course, we can change virtual size of section that's not bound to this PE file + if(sections_.empty() || std::find_if(sections_.begin(), sections_.end() - 1, section_ptr_finder(s)) != sections_.end() - 1) + throw pe_exception("Can't change virtual size of any section, except last one", pe_exception::error_changing_section_virtual_size); + + //If we're setting virtual size to zero + if(vsize == 0) + { + //Check if section is empty + if(s.empty()) + throw pe_exception("Cannot set virtual size of empty section to zero", pe_exception::error_changing_section_virtual_size); + + //Set virtual size equal to aligned size of raw data + s.set_virtual_size(s.get_size_of_raw_data()); + } + else + { + s.set_virtual_size(vsize); + } + + //Update image size if we're changing virtual size for the last section of this PE + if(!sections_.empty() || &s == &(*(sections_.end() - 1))) + update_image_size(); +} + +//Expands section raw or virtual size to hold data from specified RVA with specified size +//Section must be free (not bound to any image) +//or the last section of this image +bool pe_base::expand_section(section& s, uint32_t needed_rva, uint32_t needed_size, section_expand_type expand) +{ + //Check if we're changing the last section + //Of course, we can change the section that's not bound to this PE file + if(sections_.empty() || std::find_if(sections_.begin(), sections_.end() - 1, section_ptr_finder(s)) != sections_.end() - 1) + throw pe_exception("Can't expand any section, except last one", pe_exception::error_expanding_section); + + //Check if we should expand our section + if(expand == expand_section_raw && section_data_length_from_rva(s, needed_rva, section_data_raw) < needed_size) + { + //Expand section raw data + s.get_raw_data().resize(needed_rva - s.get_virtual_address() + needed_size); + recalculate_section_sizes(s, false); + return true; + } + else if(expand == expand_section_virtual && section_data_length_from_rva(s, needed_rva, section_data_virtual) < needed_size) + { + //Expand section virtual data + set_section_virtual_size(s, needed_rva - s.get_virtual_address() + needed_size); + return true; + } + + return false; +} + +//Updates image virtual size +void pe_base::update_image_size() +{ + //Write virtual size of image to headers + if(!sections_.empty()) + set_size_of_image(sections_.back().get_virtual_address() + sections_.back().get_aligned_virtual_size(get_section_alignment())); + else + set_size_of_image(get_size_of_headers()); +} + +//Returns checksum of PE file from header +uint32_t pe_base::get_checksum() const +{ + return props_->get_checksum(); +} + +//Sets checksum of PE file +void pe_base::set_checksum(uint32_t checksum) +{ + props_->set_checksum(checksum); +} + +//Returns timestamp of PE file from header +uint32_t pe_base::get_time_date_stamp() const +{ + return props_->get_time_date_stamp(); +} + +//Sets timestamp of PE file +void pe_base::set_time_date_stamp(uint32_t timestamp) +{ + props_->set_time_date_stamp(timestamp); +} + +//Returns Machine field value of PE file from header +uint16_t pe_base::get_machine() const +{ + return props_->get_machine(); +} + +//Sets Machine field value of PE file +void pe_base::set_machine(uint16_t machine) +{ + props_->set_machine(machine); +} + +//Prepares section before attaching it +void pe_base::prepare_section(section& s) +{ + //Calculate its size of raw data + s.set_size_of_raw_data(static_cast(pe_utils::align_up(s.get_raw_data().length(), get_file_alignment()))); + + //Check section virtual and raw size + if(!s.get_size_of_raw_data() && !s.get_virtual_size()) + throw pe_exception("Virtual and Physical sizes of section can't be 0 at the same time", pe_exception::zero_section_sizes); + + //If section virtual size is zero + if(!s.get_virtual_size()) + { + s.set_virtual_size(s.get_size_of_raw_data()); + } + else + { + //Else calculate its virtual size + s.set_virtual_size( + std::max(pe_utils::align_up(s.get_size_of_raw_data(), get_file_alignment()), + pe_utils::align_up(s.get_virtual_size(), get_section_alignment()))); + } +} + +//Adds section to image +section& pe_base::add_section(section s) +{ + if(sections_.size() >= maximum_number_of_sections) + throw pe_exception("Maximum number of sections has been reached", pe_exception::no_more_sections_can_be_added); + + //Prepare section before adding it + prepare_section(s); + + //Calculate section virtual address + if(!sections_.empty()) + { + s.set_virtual_address(pe_utils::align_up(sections_.back().get_virtual_address() + sections_.back().get_aligned_virtual_size(get_section_alignment()), get_section_alignment())); + + //We should align last section raw size, if it wasn't aligned + section& last = sections_.back(); + last.set_size_of_raw_data(static_cast(pe_utils::align_up(last.get_raw_data().length(), get_file_alignment()))); + } + else + { + s.set_virtual_address( + s.get_virtual_address() == 0 + ? pe_utils::align_up(get_size_of_headers(), get_section_alignment()) + : pe_utils::align_up(s.get_virtual_address(), get_section_alignment())); + } + + //Add section to the end of section list + sections_.push_back(s); + //Set number of sections in PE header + set_number_of_sections(static_cast(sections_.size())); + //Recalculate virtual size of image + set_size_of_image(get_size_of_image() + s.get_aligned_virtual_size(get_section_alignment())); + //Return last section + return sections_.back(); +} + +//Returns true if sectios "s" is already attached to this PE file +bool pe_base::section_attached(const section& s) const +{ + return sections_.end() != std::find_if(sections_.begin(), sections_.end(), section_ptr_finder(s)); +} + +//Returns true if directory exists +bool pe_base::directory_exists(uint32_t id) const +{ + return props_->directory_exists(id); +} + +//Removes directory +void pe_base::remove_directory(uint32_t id) +{ + props_->remove_directory(id); +} + +//Returns directory RVA +uint32_t pe_base::get_directory_rva(uint32_t id) const +{ + return props_->get_directory_rva(id); +} + +//Returns directory size +uint32_t pe_base::get_directory_size(uint32_t id) const +{ + return props_->get_directory_size(id); +} + +//Sets directory RVA (just a value of PE header, no moving occurs) +void pe_base::set_directory_rva(uint32_t id, uint32_t rva) +{ + return props_->set_directory_rva(id, rva); +} + +//Sets directory size (just a value of PE header, no moving occurs) +void pe_base::set_directory_size(uint32_t id, uint32_t size) +{ + return props_->set_directory_size(id, size); +} + +//Strips only zero DATA_DIRECTORY entries to count = min_count +//Returns resulting number of data directories +//strip_iat_directory - if true, even not empty IAT directory will be stripped +uint32_t pe_base::strip_data_directories(uint32_t min_count, bool strip_iat_directory) +{ + return props_->strip_data_directories(min_count, strip_iat_directory); +} + +//Returns true if image has import directory +bool pe_base::has_imports() const +{ + return directory_exists(image_directory_entry_import); +} + +//Returns true if image has export directory +bool pe_base::has_exports() const +{ + return directory_exists(image_directory_entry_export); +} + +//Returns true if image has resource directory +bool pe_base::has_resources() const +{ + return directory_exists(image_directory_entry_resource); +} + +//Returns true if image has security directory +bool pe_base::has_security() const +{ + return directory_exists(image_directory_entry_security); +} + +//Returns true if image has relocations +bool pe_base::has_reloc() const +{ + return directory_exists(image_directory_entry_basereloc) && !(get_characteristics() & image_file_relocs_stripped); +} + +//Returns true if image has TLS directory +bool pe_base::has_tls() const +{ + return directory_exists(image_directory_entry_tls); +} + +//Returns true if image has config directory +bool pe_base::has_config() const +{ + return directory_exists(image_directory_entry_load_config); +} + +//Returns true if image has bound import directory +bool pe_base::has_bound_import() const +{ + return directory_exists(image_directory_entry_bound_import); +} + +//Returns true if image has delay import directory +bool pe_base::has_delay_import() const +{ + return directory_exists(image_directory_entry_delay_import); +} + +//Returns true if image has COM directory +bool pe_base::is_dotnet() const +{ + return directory_exists(image_directory_entry_com_descriptor); +} + +//Returns true if image has exception directory +bool pe_base::has_exception_directory() const +{ + return directory_exists(image_directory_entry_exception); +} + +//Returns true if image has debug directory +bool pe_base::has_debug() const +{ + return directory_exists(image_directory_entry_debug); +} + +//Returns corresponding section data pointer from RVA inside section "s" (checks bounds) +char* pe_base::section_data_from_rva(section& s, uint32_t rva) +{ + //Check if RVA is inside section "s" + if(rva >= s.get_virtual_address() && rva < s.get_virtual_address() + s.get_aligned_virtual_size(get_section_alignment())) + { + if(s.get_raw_data().empty()) + throw pe_exception("Section raw data is empty and cannot be changed", pe_exception::section_is_empty); + + return &s.get_raw_data()[rva - s.get_virtual_address()]; + } + + throw pe_exception("RVA not found inside section", pe_exception::rva_not_exists); +} + +//Returns corresponding section data pointer from RVA inside section "s" (checks bounds) +const char* pe_base::section_data_from_rva(const section& s, uint32_t rva, section_data_type datatype) const +{ + //Check if RVA is inside section "s" + if(rva >= s.get_virtual_address() && rva < s.get_virtual_address() + s.get_aligned_virtual_size(get_section_alignment())) + return (datatype == section_data_raw ? s.get_raw_data().data() : s.get_virtual_data(get_section_alignment()).c_str()) + rva - s.get_virtual_address(); + + throw pe_exception("RVA not found inside section", pe_exception::rva_not_exists); +} + +//Returns section TOTAL RAW/VIRTUAL data length from RVA inside section +uint32_t pe_base::section_data_length_from_rva(uint32_t rva, section_data_type datatype, bool include_headers) const +{ + //if RVA is inside of headers and we're searching them too... + if(include_headers && rva < full_headers_data_.length()) + return static_cast(full_headers_data_.length()); + + const section& s = section_from_rva(rva); + return static_cast(datatype == section_data_raw ? s.get_raw_data().length() /* instead of SizeOfRawData */ : s.get_aligned_virtual_size(get_section_alignment())); +} + +//Returns section TOTAL RAW/VIRTUAL data length from VA inside section for PE32 +uint32_t pe_base::section_data_length_from_va(uint32_t va, section_data_type datatype, bool include_headers) const +{ + return section_data_length_from_rva(va_to_rva(va), datatype, include_headers); +} + +//Returns section TOTAL RAW/VIRTUAL data length from VA inside section for PE32/PE64 +uint32_t pe_base::section_data_length_from_va(uint64_t va, section_data_type datatype, bool include_headers) const +{ + return section_data_length_from_rva(va_to_rva(va), datatype, include_headers); +} + +//Returns section remaining RAW/VIRTUAL data length from RVA "rva_inside" to the end of section containing RVA "rva" +uint32_t pe_base::section_data_length_from_rva(uint32_t rva, uint32_t rva_inside, section_data_type datatype, bool include_headers) const +{ + //if RVAs are inside of headers and we're searching them too... + if(include_headers && rva < full_headers_data_.length() && rva_inside < full_headers_data_.length()) + return static_cast(full_headers_data_.length() - rva_inside); + + const section& s = section_from_rva(rva); + if(rva_inside < s.get_virtual_address()) + throw pe_exception("RVA not found inside section", pe_exception::rva_not_exists); + + //Calculate remaining length of section data from "rva" address + long length = static_cast(datatype == section_data_raw ? s.get_raw_data().length() /* instead of SizeOfRawData */ : s.get_aligned_virtual_size(get_section_alignment())) + + s.get_virtual_address() - rva_inside; + + if(length < 0) + return 0; + + return static_cast(length); +} + +//Returns section remaining RAW/VIRTUAL data length from VA "va_inside" to the end of section containing VA "va" for PE32 +uint32_t pe_base::section_data_length_from_va(uint32_t va, uint32_t va_inside, section_data_type datatype, bool include_headers) const +{ + return section_data_length_from_rva(va_to_rva(va), va_to_rva(va_inside), datatype, include_headers); +} + +//Returns section remaining RAW/VIRTUAL data length from VA "va_inside" to the end of section containing VA "va" for PE32/PE64 +uint32_t pe_base::section_data_length_from_va(uint64_t va, uint64_t va_inside, section_data_type datatype, bool include_headers) const +{ + return section_data_length_from_rva(va_to_rva(va), va_to_rva(va_inside), datatype, include_headers); +} + +//Returns section remaining RAW/VIRTUAL data length from RVA to the end of section "s" (checks bounds) +uint32_t pe_base::section_data_length_from_rva(const section& s, uint32_t rva_inside, section_data_type datatype) const +{ + //Check rva_inside + if(rva_inside >= s.get_virtual_address() && rva_inside < s.get_virtual_address() + s.get_aligned_virtual_size(get_section_alignment())) + { + //Calculate remaining length of section data from "rva" address + int32_t length = static_cast(datatype == section_data_raw ? s.get_raw_data().length() /* instead of SizeOfRawData */ : s.get_aligned_virtual_size(get_section_alignment())) + + s.get_virtual_address() - rva_inside; + + if(length < 0) + return 0; + + return static_cast(length); + } + + throw pe_exception("RVA not found inside section", pe_exception::rva_not_exists); +} + +//Returns section remaining RAW/VIRTUAL data length from VA to the end of section "s" for PE32 (checks bounds) +uint32_t pe_base::section_data_length_from_va(const section& s, uint32_t va_inside, section_data_type datatype) const +{ + return section_data_length_from_rva(s, va_to_rva(va_inside), datatype); +} + +//Returns section remaining RAW/VIRTUAL data length from VA to the end of section "s" for PE32/PE64 (checks bounds) +uint32_t pe_base::section_data_length_from_va(const section& s, uint64_t va_inside, section_data_type datatype) const +{ + return section_data_length_from_rva(s, va_to_rva(va_inside), datatype); +} + +//Returns corresponding section data pointer from RVA inside section +char* pe_base::section_data_from_rva(uint32_t rva, bool include_headers) +{ + //if RVA is inside of headers and we're searching them too... + if(include_headers && rva < full_headers_data_.length()) + return &full_headers_data_[rva]; + + section& s = section_from_rva(rva); + + if(s.get_raw_data().empty()) + throw pe_exception("Section raw data is empty and cannot be changed", pe_exception::section_is_empty); + + return &s.get_raw_data()[rva - s.get_virtual_address()]; +} + +//Returns corresponding section data pointer from RVA inside section +const char* pe_base::section_data_from_rva(uint32_t rva, section_data_type datatype, bool include_headers) const +{ + //if RVA is inside of headers and we're searching them too... + if(include_headers && rva < full_headers_data_.length()) + return &full_headers_data_[rva]; + + const section& s = section_from_rva(rva); + return (datatype == section_data_raw ? s.get_raw_data().data() : s.get_virtual_data(get_section_alignment()).c_str()) + rva - s.get_virtual_address(); +} + +//Reads DOS headers from istream +void pe_base::read_dos_header(std::istream& file, image_dos_header& header) +{ + //Check istream flags + if(file.bad() || file.eof()) + throw pe_exception("PE file stream is bad or closed.", pe_exception::bad_pe_file); + + //Read DOS header and check istream + file.read(reinterpret_cast(&header), sizeof(image_dos_header)); + if(file.bad() || file.eof()) + throw pe_exception("Unable to read IMAGE_DOS_HEADER", pe_exception::bad_dos_header); + + //Check DOS header magic + if(header.e_magic != 0x5a4d) //"MZ" + throw pe_exception("IMAGE_DOS_HEADER signature is incorrect", pe_exception::bad_dos_header); +} + +//Reads DOS headers from istream +void pe_base::read_dos_header(std::istream& file) +{ + read_dos_header(file, dos_header_); +} + +//Reads PE image from istream +void pe_base::read_pe(std::istream& file, bool read_debug_raw_data) +{ + //Get istream size + std::streamoff filesize = pe_utils::get_file_size(file); + + //Check if PE header is DWORD-aligned + if((dos_header_.e_lfanew % sizeof(uint32_t)) != 0) + throw pe_exception("PE header is not DWORD-aligned", pe_exception::bad_dos_header); + + //Seek to NT headers + file.seekg(dos_header_.e_lfanew); + if(file.bad() || file.fail()) + throw pe_exception("Cannot reach IMAGE_NT_HEADERS", pe_exception::image_nt_headers_not_found); + + //Read NT headers + file.read(get_nt_headers_ptr(), get_sizeof_nt_header() - sizeof(image_data_directory) * image_numberof_directory_entries); + if(file.bad() || file.eof()) + throw pe_exception("Error reading IMAGE_NT_HEADERS", pe_exception::error_reading_image_nt_headers); + + //Check PE signature + if(get_pe_signature() != 0x4550) //"PE" + throw pe_exception("Incorrect PE signature", pe_exception::pe_signature_incorrect); + + //Check number of directories + if(get_number_of_rvas_and_sizes() > image_numberof_directory_entries) + set_number_of_rvas_and_sizes(image_numberof_directory_entries); + + if(get_number_of_rvas_and_sizes() > 0) + { + //Read data directory headers, if any + file.read(get_nt_headers_ptr() + (get_sizeof_nt_header() - sizeof(image_data_directory) * image_numberof_directory_entries), sizeof(image_data_directory) * get_number_of_rvas_and_sizes()); + if(file.bad() || file.eof()) + throw pe_exception("Error reading DATA_DIRECTORY headers", pe_exception::error_reading_data_directories); + } + + //Check section number + //Images with zero section number accepted + if(get_number_of_sections() > maximum_number_of_sections) + throw pe_exception("Incorrect number of sections", pe_exception::section_number_incorrect); + + //Check PE magic + if(get_magic() != get_needed_magic()) + throw pe_exception("Incorrect PE signature", pe_exception::pe_signature_incorrect); + + //Check section alignment + if(!pe_utils::is_power_of_2(get_section_alignment())) + throw pe_exception("Incorrect section alignment", pe_exception::incorrect_section_alignment); + + //Check file alignment + if(!pe_utils::is_power_of_2(get_file_alignment())) + throw pe_exception("Incorrect file alignment", pe_exception::incorrect_file_alignment); + + if(get_file_alignment() != get_section_alignment() && (get_file_alignment() < minimum_file_alignment || get_file_alignment() > get_section_alignment())) + throw pe_exception("Incorrect file alignment", pe_exception::incorrect_file_alignment); + + //Check size of image + if(pe_utils::align_up(get_size_of_image(), get_section_alignment()) == 0) + throw pe_exception("Incorrect size of image", pe_exception::incorrect_size_of_image); + + //Read rich data overlay / DOS stub (if any) + if(static_cast(dos_header_.e_lfanew) > sizeof(image_dos_header)) + { + rich_overlay_.resize(dos_header_.e_lfanew - sizeof(image_dos_header)); + file.seekg(sizeof(image_dos_header)); + file.read(&rich_overlay_[0], dos_header_.e_lfanew - sizeof(image_dos_header)); + if(file.bad() || file.eof()) + throw pe_exception("Error reading 'Rich' & 'DOS stub' overlay", pe_exception::error_reading_overlay); + } + + //Calculate first section raw position + //Sum is safe here + uint32_t first_section = dos_header_.e_lfanew + get_size_of_optional_header() + sizeof(image_file_header) + sizeof(uint32_t) /* Signature */; + + if(get_number_of_sections() > 0) + { + //Go to first section + file.seekg(first_section); + if(file.bad() || file.fail()) + throw pe_exception("Cannot reach section headers", pe_exception::image_section_headers_not_found); + } + + uint32_t last_raw_size = 0; + + //Read all sections + for(int i = 0; i < get_number_of_sections(); i++) + { + section s; + //Read section header + file.read(reinterpret_cast(&s.get_raw_header()), sizeof(image_section_header)); + if(file.bad() || file.eof()) + throw pe_exception("Error reading section header", pe_exception::error_reading_section_header); + + //Save next section header position + std::streamoff next_sect = file.tellg(); + + //Check section virtual and raw sizes + if(!s.get_size_of_raw_data() && !s.get_virtual_size()) + throw pe_exception("Virtual and Physical sizes of section can't be 0 at the same time", pe_exception::zero_section_sizes); + + //Check for adequate values of section fields + if(!pe_utils::is_sum_safe(s.get_virtual_address(), s.get_virtual_size()) || s.get_virtual_size() > pe_utils::two_gb + || !pe_utils::is_sum_safe(s.get_pointer_to_raw_data(), s.get_size_of_raw_data()) || s.get_size_of_raw_data() > pe_utils::two_gb) + throw pe_exception("Incorrect section address or size", pe_exception::section_incorrect_addr_or_size); + + if(s.get_size_of_raw_data() != 0) + { + //If section has raw data + + //If section raw data size is greater than virtual, fix it + last_raw_size = s.get_size_of_raw_data(); + if(pe_utils::align_up(s.get_size_of_raw_data(), get_file_alignment()) > pe_utils::align_up(s.get_virtual_size(), get_section_alignment())) + s.set_size_of_raw_data(s.get_virtual_size()); + + //Check virtual and raw section sizes and addresses + if(s.get_virtual_address() + pe_utils::align_up(s.get_virtual_size(), get_section_alignment()) > pe_utils::align_up(get_size_of_image(), get_section_alignment()) + || + pe_utils::align_down(s.get_pointer_to_raw_data(), get_file_alignment()) + s.get_size_of_raw_data() > static_cast(filesize)) + throw pe_exception("Incorrect section address or size", pe_exception::section_incorrect_addr_or_size); + + //Seek to section raw data + file.seekg(pe_utils::align_down(s.get_pointer_to_raw_data(), get_file_alignment())); + if(file.bad() || file.fail()) + throw pe_exception("Cannot reach section data", pe_exception::image_section_data_not_found); + + //Read section raw data + s.get_raw_data().resize(s.get_size_of_raw_data()); + file.read(&s.get_raw_data()[0], s.get_size_of_raw_data()); + if(file.bad() || file.fail()) + throw pe_exception("Error reading section data", pe_exception::image_section_data_not_found); + } + + //Check virtual address and size of section + if(s.get_virtual_address() + s.get_aligned_virtual_size(get_section_alignment()) > pe_utils::align_up(get_size_of_image(), get_section_alignment())) + throw pe_exception("Incorrect section address or size", pe_exception::section_incorrect_addr_or_size); + + //Save section + sections_.push_back(s); + + //Seek to the next section header + file.seekg(next_sect); + } + + //Check size of headers: SizeOfHeaders can't be larger than first section VA + if(!sections_.empty() && get_size_of_headers() > sections_.front().get_virtual_address()) + throw pe_exception("Incorrect size of headers", pe_exception::incorrect_size_of_headers); + + //If image has more than two sections + if(sections_.size() >= 2) + { + //Check sections virtual sizes + for(section_list::const_iterator i = sections_.begin() + 1; i != sections_.end(); ++i) + { + if((*i).get_virtual_address() != (*(i - 1)).get_virtual_address() + (*(i - 1)).get_aligned_virtual_size(get_section_alignment())) + throw pe_exception("Section table is incorrect", pe_exception::image_section_table_incorrect); + } + } + + //Check if image has overlay in the end of file + has_overlay_ = !sections_.empty() && filesize > static_cast(sections_.back().get_pointer_to_raw_data() + last_raw_size); + + { + //Additionally, read data from the beginning of istream to size of headers + file.seekg(0); + uint32_t size_of_headers = std::min(get_size_of_headers(), static_cast(filesize)); + + if(!sections_.empty()) + { + for(section_list::const_iterator i = sections_.begin(); i != sections_.end(); ++i) + { + if(!(*i).empty()) + { + size_of_headers = std::min(get_size_of_headers(), (*i).get_pointer_to_raw_data()); + break; + } + } + } + + full_headers_data_.resize(size_of_headers); + file.read(&full_headers_data_[0], size_of_headers); + if(file.bad() || file.eof()) + throw pe_exception("Error reading file", pe_exception::error_reading_file); + } + + //Moreover, if there's debug directory, read its raw data for some debug info types + while(read_debug_raw_data && has_debug()) + { + try + { + //Check the length in bytes of the section containing debug directory + if(section_data_length_from_rva(get_directory_rva(image_directory_entry_debug), get_directory_rva(image_directory_entry_debug), section_data_virtual, true) < sizeof(image_debug_directory)) + break; + + unsigned long current_pos = get_directory_rva(image_directory_entry_debug); + + //First IMAGE_DEBUG_DIRECTORY table + image_debug_directory directory = section_data_from_rva(current_pos, section_data_virtual, true); + + //Iterate over all IMAGE_DEBUG_DIRECTORY directories + while(directory.PointerToRawData + && current_pos < get_directory_rva(image_directory_entry_debug) + get_directory_size(image_directory_entry_debug)) + { + //If we have something to read + if((directory.Type == image_debug_type_codeview + || directory.Type == image_debug_type_misc + || directory.Type == image_debug_type_coff) + && directory.SizeOfData) + { + std::string data; + data.resize(directory.SizeOfData); + file.seekg(directory.PointerToRawData); + file.read(&data[0], directory.SizeOfData); + if(file.bad() || file.eof()) + throw pe_exception("Error reading file", pe_exception::error_reading_file); + + debug_data_.insert(std::make_pair(directory.PointerToRawData, data)); + } + + //Go to next debug entry + current_pos += sizeof(image_debug_directory); + directory = section_data_from_rva(current_pos, section_data_virtual, true); + } + + break; + } + catch(const pe_exception&) + { + //Don't throw any exception here, if debug info is corrupted or incorrect + break; + } + catch(const std::bad_alloc&) + { + //Don't throw any exception here, if debug info is corrupted or incorrect + break; + } + } +} + +//Returns PE type of this image +pe_type pe_base::get_pe_type() const +{ + return props_->get_pe_type(); +} + +//Returns PE type (PE or PE+) from pe_type enumeration (minimal correctness checks) +pe_type pe_base::get_pe_type(std::istream& file) +{ + //Save state of the istream + std::ios_base::iostate state = file.exceptions(); + std::streamoff old_offset = file.tellg(); + image_nt_headers32 nt_headers; + image_dos_header header; + + try + { + //Read dos header + file.exceptions(std::ios::goodbit); + read_dos_header(file, header); + + //Seek to the NT headers start + file.seekg(header.e_lfanew); + if(file.bad() || file.fail()) + throw pe_exception("Cannot reach IMAGE_NT_HEADERS", pe_exception::image_nt_headers_not_found); + + //Read NT headers (we're using 32-bit version, because there's no significant differencies between 32 and 64 bit version structures) + file.read(reinterpret_cast(&nt_headers), sizeof(image_nt_headers32) - sizeof(image_data_directory) * image_numberof_directory_entries); + if(file.bad() || file.eof()) + throw pe_exception("Error reading IMAGE_NT_HEADERS", pe_exception::error_reading_image_nt_headers); + + //Check NT headers signature + if(nt_headers.Signature != 0x4550) //"PE" + throw pe_exception("Incorrect PE signature", pe_exception::pe_signature_incorrect); + + //Check NT headers magic + if(nt_headers.OptionalHeader.Magic != image_nt_optional_hdr32_magic && nt_headers.OptionalHeader.Magic != image_nt_optional_hdr64_magic) + throw pe_exception("Incorrect PE signature", pe_exception::pe_signature_incorrect); + } + catch(const std::exception&) + { + //If something went wrong, restore istream state + file.exceptions(state); + file.seekg(old_offset); + file.clear(); + //Retrhow exception + throw; + } + + //Restore stream state + file.exceptions(state); + file.seekg(old_offset); + file.clear(); + + //Determine PE type and return it + return nt_headers.OptionalHeader.Magic == image_nt_optional_hdr64_magic ? pe_type_64 : pe_type_32; +} + +//Returns true if image has overlay data at the end of file +bool pe_base::has_overlay() const +{ + return has_overlay_; +} + +//Clears PE characteristics flag +void pe_base::clear_characteristics_flags(uint16_t flags) +{ + set_characteristics(get_characteristics() & ~flags); +} + +//Sets PE characteristics flag +void pe_base::set_characteristics_flags(uint16_t flags) +{ + set_characteristics(get_characteristics() | flags); +} + +//Returns true if PE characteristics flag set +bool pe_base::check_characteristics_flag(uint16_t flag) const +{ + return (get_characteristics() & flag) ? true : false; +} + +//Returns subsystem value +uint16_t pe_base::get_subsystem() const +{ + return props_->get_subsystem(); +} + +//Sets subsystem value +void pe_base::set_subsystem(uint16_t subsystem) +{ + props_->set_subsystem(subsystem); +} + +//Returns true if image has console subsystem +bool pe_base::is_console() const +{ + return get_subsystem() == image_subsystem_windows_cui; +} + +//Returns true if image has Windows GUI subsystem +bool pe_base::is_gui() const +{ + return get_subsystem() == image_subsystem_windows_gui; +} + +//Sets required operation system version +void pe_base::set_os_version(uint16_t major, uint16_t minor) +{ + props_->set_os_version(major, minor); +} + +//Returns required operation system version (minor word) +uint16_t pe_base::get_minor_os_version() const +{ + return props_->get_minor_os_version(); +} + +//Returns required operation system version (major word) +uint16_t pe_base::get_major_os_version() const +{ + return props_->get_major_os_version(); +} + +//Sets required subsystem version +void pe_base::set_subsystem_version(uint16_t major, uint16_t minor) +{ + props_->set_subsystem_version(major, minor); +} + +//Returns required subsystem version (minor word) +uint16_t pe_base::get_minor_subsystem_version() const +{ + return props_->get_minor_subsystem_version(); +} + +//Returns required subsystem version (major word) +uint16_t pe_base::get_major_subsystem_version() const +{ + return props_->get_major_subsystem_version(); +} + +//Returns corresponding section data pointer from VA inside section "s" for PE32 (checks bounds) +char* pe_base::section_data_from_va(section& s, uint32_t va) //Always returns raw data +{ + return section_data_from_rva(s, va_to_rva(va)); +} + +//Returns corresponding section data pointer from VA inside section "s" for PE32 (checks bounds) +const char* pe_base::section_data_from_va(const section& s, uint32_t va, section_data_type datatype) const +{ + return section_data_from_rva(s, va_to_rva(va), datatype); +} + +//Returns corresponding section data pointer from VA inside section for PE32 +char* pe_base::section_data_from_va(uint32_t va, bool include_headers) //Always returns raw data +{ + return section_data_from_rva(va_to_rva(va), include_headers); +} + +//Returns corresponding section data pointer from VA inside section for PE32 +const char* pe_base::section_data_from_va(uint32_t va, section_data_type datatype, bool include_headers) const +{ + return section_data_from_rva(va_to_rva(va), datatype, include_headers); +} + +//Returns corresponding section data pointer from VA inside section "s" for PE32/PE64 (checks bounds) +char* pe_base::section_data_from_va(section& s, uint64_t va) //Always returns raw data +{ + return section_data_from_rva(s, va_to_rva(va)); +} + +//Returns corresponding section data pointer from VA inside section "s" for PE32/PE64 (checks bounds) +const char* pe_base::section_data_from_va(const section& s, uint64_t va, section_data_type datatype) const +{ + return section_data_from_rva(s, va_to_rva(va), datatype); +} + +//Returns corresponding section data pointer from VA inside section for PE32/PE64 +char* pe_base::section_data_from_va(uint64_t va, bool include_headers) //Always returns raw data +{ + return section_data_from_rva(va_to_rva(va), include_headers); +} + +//Returns corresponding section data pointer from VA inside section for PE32/PE64 +const char* pe_base::section_data_from_va(uint64_t va, section_data_type datatype, bool include_headers) const +{ + return section_data_from_rva(va_to_rva(va), datatype, include_headers); +} + +//Returns section from VA inside it for PE32 +section& pe_base::section_from_va(uint32_t va) +{ + return section_from_rva(va_to_rva(va)); +} + +//Returns section from VA inside it for PE32/PE64 +section& pe_base::section_from_va(uint64_t va) +{ + return section_from_rva(va_to_rva(va)); +} + +//Returns section from RVA inside it for PE32 +const section& pe_base::section_from_va(uint32_t va) const +{ + return section_from_rva(va_to_rva(va)); +} + +//Returns section from RVA inside it for PE32/PE64 +const section& pe_base::section_from_va(uint64_t va) const +{ + return section_from_rva(va_to_rva(va)); +} + +uint32_t pe_base::va_to_rva(uint32_t va, bool bound_check) const +{ + return props_->va_to_rva(va, bound_check); +} + +uint32_t pe_base::va_to_rva(uint64_t va, bool bound_check) const +{ + return props_->va_to_rva(va, bound_check); +} + +uint32_t pe_base::rva_to_va_32(uint32_t rva) const +{ + return props_->rva_to_va_32(rva); +} + +uint64_t pe_base::rva_to_va_64(uint32_t rva) const +{ + return props_->rva_to_va_64(rva); +} + +//Relative Virtual Address (RVA) to Virtual Address (VA) convertion for PE32 +void pe_base::rva_to_va(uint32_t rva, uint32_t& va) const +{ + va = rva_to_va_32(rva); +} + +//Relative Virtual Address (RVA) to Virtual Address (VA) convertions for PE32/PE64 +void pe_base::rva_to_va(uint32_t rva, uint64_t& va) const +{ + va = rva_to_va_64(rva); +} + +//Returns section from file offset (4gb max) +section& pe_base::section_from_file_offset(uint32_t offset) +{ + return *file_offset_to_section(offset); +} + +//Returns section from file offset (4gb max) +const section& pe_base::section_from_file_offset(uint32_t offset) const +{ + return *file_offset_to_section(offset); +} + +//Returns section and offset (raw data only) from its start from RVA +const std::pair pe_base::section_and_offset_from_rva(uint32_t rva) const +{ + const section& s = section_from_rva(rva); + return std::make_pair(rva - s.get_virtual_address(), &s); +} + +//Returns DLL Characteristics +uint16_t pe_base::get_dll_characteristics() const +{ + return props_->get_dll_characteristics(); +} + +//Sets DLL Characteristics +void pe_base::set_dll_characteristics(uint16_t characteristics) +{ + props_->set_dll_characteristics(characteristics); +} + +//Returns size of headers +uint32_t pe_base::get_size_of_headers() const +{ + return props_->get_size_of_headers(); +} + +//Returns size of optional header +uint16_t pe_base::get_size_of_optional_header() const +{ + return props_->get_size_of_optional_header(); +} + +//Returns PE signature +uint32_t pe_base::get_pe_signature() const +{ + return props_->get_pe_signature(); +} + +//Returns magic value +uint32_t pe_base::get_magic() const +{ + return props_->get_magic(); +} + +//Returns image base for PE32 +void pe_base::get_image_base(uint32_t& base) const +{ + base = get_image_base_32(); +} + +//Returns image base for PE32 and PE64 respectively +uint32_t pe_base::get_image_base_32() const +{ + return props_->get_image_base_32(); +} + +//Sets image base for PE32 and PE64 respectively +uint64_t pe_base::get_image_base_64() const +{ + return props_->get_image_base_64(); +} + +//RVA to RAW file offset convertion (4gb max) +uint32_t pe_base::rva_to_file_offset(uint32_t rva) const +{ + //Maybe, RVA is inside PE headers + if(rva < get_size_of_headers()) + return rva; + + const section& s = section_from_rva(rva); + return s.get_pointer_to_raw_data() + rva - s.get_virtual_address(); +} + +//RAW file offset to RVA convertion (4gb max) +uint32_t pe_base::file_offset_to_rva(uint32_t offset) const +{ + //Maybe, offset is inside PE headers + if(offset < get_size_of_headers()) + return offset; + + const section_list::const_iterator it = file_offset_to_section(offset); + return offset - (*it).get_pointer_to_raw_data() + (*it).get_virtual_address(); +} + +//RAW file offset to section convertion helper (4gb max) +section_list::const_iterator pe_base::file_offset_to_section(uint32_t offset) const +{ + section_list::const_iterator it = std::find_if(sections_.begin(), sections_.end(), section_by_raw_offset(offset)); + if(it == sections_.end()) + throw pe_exception("No section found by presented file offset", pe_exception::no_section_found); + + return it; +} + +//RAW file offset to section convertion helper (4gb max) +section_list::iterator pe_base::file_offset_to_section(uint32_t offset) +{ + section_list::iterator it = std::find_if(sections_.begin(), sections_.end(), section_by_raw_offset(offset)); + if(it == sections_.end()) + throw pe_exception("No section found by presented file offset", pe_exception::no_section_found); + + return it; +} + +//RVA from section raw data offset +uint32_t pe_base::rva_from_section_offset(const section& s, uint32_t raw_offset_from_section_start) +{ + return s.get_virtual_address() + raw_offset_from_section_start; +} + +//Returns image base for PE32/PE64 +void pe_base::get_image_base(uint64_t& base) const +{ + base = get_image_base_64(); +} + +//Sets new image base +void pe_base::set_image_base(uint32_t base) +{ + props_->set_image_base(base); +} + +void pe_base::set_image_base_64(uint64_t base) +{ + props_->set_image_base_64(base); +} + +//Sets heap size commit for PE32 and PE64 respectively +void pe_base::set_heap_size_commit(uint32_t size) +{ + props_->set_heap_size_commit(size); +} + +void pe_base::set_heap_size_commit(uint64_t size) +{ + props_->set_heap_size_commit(size); +} + +//Sets heap size reserve for PE32 and PE64 respectively +void pe_base::set_heap_size_reserve(uint32_t size) +{ + props_->set_heap_size_reserve(size); +} + +void pe_base::set_heap_size_reserve(uint64_t size) +{ + props_->set_heap_size_reserve(size); +} + +//Sets stack size commit for PE32 and PE64 respectively +void pe_base::set_stack_size_commit(uint32_t size) +{ + props_->set_stack_size_commit(size); +} + +void pe_base::set_stack_size_commit(uint64_t size) +{ + props_->set_stack_size_commit(size); +} + +//Sets stack size reserve for PE32 and PE64 respectively +void pe_base::set_stack_size_reserve(uint32_t size) +{ + props_->set_stack_size_reserve(size); +} + +void pe_base::set_stack_size_reserve(uint64_t size) +{ + props_->set_stack_size_reserve(size); +} + +//Returns heap size commit for PE32 and PE64 respectively +uint32_t pe_base::get_heap_size_commit_32() const +{ + return props_->get_heap_size_commit_32(); +} + +uint64_t pe_base::get_heap_size_commit_64() const +{ + return props_->get_heap_size_commit_64(); +} + +//Returns heap size reserve for PE32 and PE64 respectively +uint32_t pe_base::get_heap_size_reserve_32() const +{ + return props_->get_heap_size_reserve_32(); +} + +uint64_t pe_base::get_heap_size_reserve_64() const +{ + return props_->get_heap_size_reserve_64(); +} + +//Returns stack size commit for PE32 and PE64 respectively +uint32_t pe_base::get_stack_size_commit_32() const +{ + return props_->get_stack_size_commit_32(); +} + +uint64_t pe_base::get_stack_size_commit_64() const +{ + return props_->get_stack_size_commit_64(); +} + +//Returns stack size reserve for PE32 and PE64 respectively +uint32_t pe_base::get_stack_size_reserve_32() const +{ + return props_->get_stack_size_reserve_32(); +} + +uint64_t pe_base::get_stack_size_reserve_64() const +{ + return props_->get_stack_size_reserve_64(); +} + +//Returns heap size commit for PE32 +void pe_base::get_heap_size_commit(uint32_t& size) const +{ + size = get_heap_size_commit_32(); +} + +//Returns heap size commit for PE32/PE64 +void pe_base::get_heap_size_commit(uint64_t& size) const +{ + size = get_heap_size_commit_64(); +} + +//Returns heap size reserve for PE32 +void pe_base::get_heap_size_reserve(uint32_t& size) const +{ + size = get_heap_size_reserve_32(); +} + +//Returns heap size reserve for PE32/PE64 +void pe_base::get_heap_size_reserve(uint64_t& size) const +{ + size = get_heap_size_reserve_64(); +} + +//Returns stack size commit for PE32 +void pe_base::get_stack_size_commit(uint32_t& size) const +{ + size = get_stack_size_commit_32(); +} + +//Returns stack size commit for PE32/PE64 +void pe_base::get_stack_size_commit(uint64_t& size) const +{ + size = get_stack_size_commit_64(); +} + +//Returns stack size reserve for PE32 +void pe_base::get_stack_size_reserve(uint32_t& size) const +{ + size = get_stack_size_reserve_32(); +} + +//Returns stack size reserve for PE32/PE64 +void pe_base::get_stack_size_reserve(uint64_t& size) const +{ + size = get_stack_size_reserve_64(); +} + +//Realigns file (changes file alignment) +void pe_base::realign_file(uint32_t new_file_alignment) +{ + //Checks alignment for correctness + set_file_alignment(new_file_alignment); + realign_all_sections(); +} + +//Helper function to recalculate RAW and virtual section sizes and strip it, if necessary +void pe_base::recalculate_section_sizes(section& s, bool auto_strip) +{ + prepare_section(s); //Recalculate section raw addresses + + //Strip RAW size of section, if it is the last one + //For all others it must be file-aligned and calculated by prepare_section() call + if(auto_strip && !(sections_.empty() || &s == &*(sections_.end() - 1))) + { + //Strip ending raw data nullbytes to optimize size + std::string& raw_data = s.get_raw_data(); + if(!raw_data.empty()) + { + std::string::size_type i = raw_data.length(); + for(; i != 1; --i) + { + if(raw_data[i - 1] != 0) + break; + } + + raw_data.resize(i); + } + + s.set_size_of_raw_data(static_cast(raw_data.length())); + } + + //Can occur only for last section + if(pe_utils::align_up(s.get_virtual_size(), get_section_alignment()) < pe_utils::align_up(s.get_size_of_raw_data(), get_file_alignment())) + set_section_virtual_size(s, pe_utils::align_up(s.get_size_of_raw_data(), get_section_alignment())); //Recalculate section virtual size +} + +//Returns data from the beginning of image +//Size = SizeOfHeaders +const std::string& pe_base::get_full_headers_data() const +{ + return full_headers_data_; +} + +const pe_base::debug_data_list& pe_base::get_raw_debug_data_list() const +{ + return debug_data_; +} + +//Sets number of sections +void pe_base::set_number_of_sections(uint16_t number) +{ + props_->set_number_of_sections(number); +} + +//Sets size of image +void pe_base::set_size_of_image(uint32_t size) +{ + props_->set_size_of_image(size); +} + +//Sets size of headers +void pe_base::set_size_of_headers(uint32_t size) +{ + props_->set_size_of_headers(size); +} + +//Sets size of optional headers +void pe_base::set_size_of_optional_header(uint16_t size) +{ + props_->set_size_of_optional_header(size); +} + +//Returns nt headers data pointer +char* pe_base::get_nt_headers_ptr() +{ + return props_->get_nt_headers_ptr(); +} + +//Returns nt headers data pointer +const char* pe_base::get_nt_headers_ptr() const +{ + return props_->get_nt_headers_ptr(); +} + +//Returns sizeof() nt headers +uint32_t pe_base::get_sizeof_nt_header() const +{ + return props_->get_sizeof_nt_header(); +} + +//Returns sizeof() optional headers +uint32_t pe_base::get_sizeof_opt_headers() const +{ + return props_->get_sizeof_opt_headers(); +} + +//Sets file alignment (no checks) +void pe_base::set_file_alignment_unchecked(uint32_t alignment) +{ + props_->set_file_alignment_unchecked(alignment); +} + +//Sets base of code +void pe_base::set_base_of_code(uint32_t base) +{ + props_->set_base_of_code(base); +} + +//Returns base of code +uint32_t pe_base::get_base_of_code() const +{ + return props_->get_base_of_code(); +} + +//Returns needed magic of image +uint32_t pe_base::get_needed_magic() const +{ + return props_->get_needed_magic(); +} +} diff --git a/drivers/pe_bliss/pe_base.h b/drivers/pe_bliss/pe_base.h new file mode 100644 index 0000000000..a84faf547c --- /dev/null +++ b/drivers/pe_bliss/pe_base.h @@ -0,0 +1,523 @@ +#pragma once +#include +#include +#include +#include +#include +#include "pe_exception.h" +#include "pe_structures.h" +#include "utils.h" +#include "pe_section.h" +#include "pe_properties.h" + +//Please don't remove this information from header +//PEBliss 1.0.0 +//(c) DX 2011 - 2012, http://kaimi.ru +//Free to use for commertial and non-commertial purposes, modification and distribution + +// == more important == +//TODO: compact import rebuilder +//TODO: remove sections in the middle +//== less important == +//TODO: relocations that take more than one element (seems to be not possible in Windows PE, but anyway) +//TODO: delay import directory +//TODO: write message tables +//TODO: write string tables +//TODO: read security information +//TODO: read full .NET information + +namespace pe_bliss +{ +//Portable executable class +class pe_base +{ +public: //CONSTRUCTORS + //Constructor from stream + pe_base(std::istream& file, const pe_properties& props, bool read_debug_raw_data = true); + + //Constructor of empty PE-file + explicit pe_base(const pe_properties& props, uint32_t section_alignment = 0x1000, bool dll = false, uint16_t subsystem = pe_win::image_subsystem_windows_gui); + + pe_base(const pe_base& pe); + pe_base& operator=(const pe_base& pe); + +public: + ~pe_base(); + +public: //STUB + //Strips stub MSVS overlay, if any + void strip_stub_overlay(); + //Fills stub MSVS overlay with specified byte + void fill_stub_overlay(char c); + //Sets stub MSVS overlay + void set_stub_overlay(const std::string& data); + //Returns stub overlay contents + const std::string& get_stub_overlay() const; + + +public: //DIRECTORIES + //Returns true if directory exists + bool directory_exists(uint32_t id) const; + //Removes directory + void remove_directory(uint32_t id); + + //Returns directory RVA + uint32_t get_directory_rva(uint32_t id) const; + //Returns directory size + uint32_t get_directory_size(uint32_t id) const; + + //Sets directory RVA (just a value of PE header, no moving occurs) + void set_directory_rva(uint32_t id, uint32_t rva); + //Sets directory size (just a value of PE header, no moving occurs) + void set_directory_size(uint32_t id, uint32_t size); + + //Strips only zero DATA_DIRECTORY entries to count = min_count + //Returns resulting number of data directories + //strip_iat_directory - if true, even not empty IAT directory will be stripped + uint32_t strip_data_directories(uint32_t min_count = 1, bool strip_iat_directory = true); + + //Returns true if image has import directory + bool has_imports() const; + //Returns true if image has export directory + bool has_exports() const; + //Returns true if image has resource directory + bool has_resources() const; + //Returns true if image has security directory + bool has_security() const; + //Returns true if image has relocations + bool has_reloc() const; + //Returns true if image has TLS directory + bool has_tls() const; + //Returns true if image has config directory + bool has_config() const; + //Returns true if image has bound import directory + bool has_bound_import() const; + //Returns true if image has delay import directory + bool has_delay_import() const; + //Returns true if image has COM directory + bool is_dotnet() const; + //Returns true if image has exception directory + bool has_exception_directory() const; + //Returns true if image has debug directory + bool has_debug() const; + + //Returns subsystem value + uint16_t get_subsystem() const; + //Sets subsystem value + void set_subsystem(uint16_t subsystem); + //Returns true if image has console subsystem + bool is_console() const; + //Returns true if image has Windows GUI subsystem + bool is_gui() const; + + //Sets required operation system version + void set_os_version(uint16_t major, uint16_t minor); + //Returns required operation system version (minor word) + uint16_t get_minor_os_version() const; + //Returns required operation system version (major word) + uint16_t get_major_os_version() const; + + //Sets required subsystem version + void set_subsystem_version(uint16_t major, uint16_t minor); + //Returns required subsystem version (minor word) + uint16_t get_minor_subsystem_version() const; + //Returns required subsystem version (major word) + uint16_t get_major_subsystem_version() const; + +public: //PE HEADER + //Returns DOS header + const pe_win::image_dos_header& get_dos_header() const; + pe_win::image_dos_header& get_dos_header(); + + //Returns PE header start (e_lfanew) + int32_t get_pe_header_start() const; + + //Returns file alignment + uint32_t get_file_alignment() const; + //Sets file alignment, checking the correctness of its value + void set_file_alignment(uint32_t alignment); + + //Returns size of image + uint32_t get_size_of_image() const; + + //Returns image entry point + uint32_t get_ep() const; + //Sets image entry point (just a value of PE header) + void set_ep(uint32_t new_ep); + + //Returns number of RVA and sizes (number of DATA_DIRECTORY entries) + uint32_t get_number_of_rvas_and_sizes() const; + //Sets number of RVA and sizes (number of DATA_DIRECTORY entries) + void set_number_of_rvas_and_sizes(uint32_t number); + + //Returns PE characteristics + uint16_t get_characteristics() const; + //Sets PE characteristics (a value inside header) + void set_characteristics(uint16_t ch); + //Clears PE characteristics flag + void clear_characteristics_flags(uint16_t flags); + //Sets PE characteristics flag + void set_characteristics_flags(uint16_t flags); + //Returns true if PE characteristics flag set + bool check_characteristics_flag(uint16_t flag) const; + + //Returns DLL Characteristics + uint16_t get_dll_characteristics() const; + //Sets DLL Characteristics + void set_dll_characteristics(uint16_t characteristics); + + //Returns size of headers + uint32_t get_size_of_headers() const; + //Returns size of optional header + uint16_t get_size_of_optional_header() const; + + //Returns PE signature + uint32_t get_pe_signature() const; + + //Returns magic value + uint32_t get_magic() const; + + //Returns image base for PE32 and PE64 respectively + uint32_t get_image_base_32() const; + void get_image_base(uint32_t& base) const; + //Sets image base for PE32 and PE64 respectively + uint64_t get_image_base_64() const; + void get_image_base(uint64_t& base) const; + + //Sets new image base + void set_image_base(uint32_t base); + void set_image_base_64(uint64_t base); + + //Sets heap size commit for PE32 and PE64 respectively + void set_heap_size_commit(uint32_t size); + void set_heap_size_commit(uint64_t size); + //Sets heap size reserve for PE32 and PE64 respectively + void set_heap_size_reserve(uint32_t size); + void set_heap_size_reserve(uint64_t size); + //Sets stack size commit for PE32 and PE64 respectively + void set_stack_size_commit(uint32_t size); + void set_stack_size_commit(uint64_t size); + //Sets stack size reserve for PE32 and PE64 respectively + void set_stack_size_reserve(uint32_t size); + void set_stack_size_reserve(uint64_t size); + + //Returns heap size commit for PE32 and PE64 respectively + uint32_t get_heap_size_commit_32() const; + void get_heap_size_commit(uint32_t& size) const; + uint64_t get_heap_size_commit_64() const; + void get_heap_size_commit(uint64_t& size) const; + //Returns heap size reserve for PE32 and PE64 respectively + uint32_t get_heap_size_reserve_32() const; + void get_heap_size_reserve(uint32_t& size) const; + uint64_t get_heap_size_reserve_64() const; + void get_heap_size_reserve(uint64_t& size) const; + //Returns stack size commit for PE32 and PE64 respectively + uint32_t get_stack_size_commit_32() const; + void get_stack_size_commit(uint32_t& size) const; + uint64_t get_stack_size_commit_64() const; + void get_stack_size_commit(uint64_t& size) const; + //Returns stack size reserve for PE32 and PE64 respectively + uint32_t get_stack_size_reserve_32() const; + void get_stack_size_reserve(uint32_t& size) const; + uint64_t get_stack_size_reserve_64() const; + void get_stack_size_reserve(uint64_t& size) const; + + //Updates virtual size of image corresponding to section virtual sizes + void update_image_size(); + + //Returns checksum of PE file from header + uint32_t get_checksum() const; + //Sets checksum of PE file + void set_checksum(uint32_t checksum); + + //Returns timestamp of PE file from header + uint32_t get_time_date_stamp() const; + //Sets timestamp of PE file + void set_time_date_stamp(uint32_t timestamp); + + //Returns Machine field value of PE file from header + uint16_t get_machine() const; + //Sets Machine field value of PE file + void set_machine(uint16_t machine); + + //Returns data from the beginning of image + //Size = SizeOfHeaders + const std::string& get_full_headers_data() const; + + typedef std::multimap debug_data_list; + //Returns raw list of debug data + const debug_data_list& get_raw_debug_data_list() const; + + //Reads and checks DOS header + static void read_dos_header(std::istream& file, pe_win::image_dos_header& header); + + //Returns sizeof() nt headers + uint32_t get_sizeof_nt_header() const; + //Returns sizeof() optional headers + uint32_t get_sizeof_opt_headers() const; + //Returns raw nt headers data pointer + const char* get_nt_headers_ptr() const; + + //Sets size of headers (to NT headers) + void set_size_of_headers(uint32_t size); + //Sets size of optional headers (to NT headers) + void set_size_of_optional_header(uint16_t size); + + //Sets base of code + void set_base_of_code(uint32_t base); + //Returns base of code + uint32_t get_base_of_code() const; + +public: //ADDRESS CONVERTIONS + //Virtual Address (VA) to Relative Virtual Address (RVA) convertions + //for PE32 and PE64 respectively + //bound_check checks integer overflow + uint32_t va_to_rva(uint32_t va, bool bound_check = true) const; + uint32_t va_to_rva(uint64_t va, bool bound_check = true) const; + + //Relative Virtual Address (RVA) to Virtual Address (VA) convertions + //for PE32 and PE64 respectively + uint32_t rva_to_va_32(uint32_t rva) const; + void rva_to_va(uint32_t rva, uint32_t& va) const; + uint64_t rva_to_va_64(uint32_t rva) const; + void rva_to_va(uint32_t rva, uint64_t& va) const; + + //RVA to RAW file offset convertion (4gb max) + uint32_t rva_to_file_offset(uint32_t rva) const; + //RAW file offset to RVA convertion (4gb max) + uint32_t file_offset_to_rva(uint32_t offset) const; + + //RVA from section raw data offset + static uint32_t rva_from_section_offset(const section& s, uint32_t raw_offset_from_section_start); + +public: //IMAGE SECTIONS + //Returns number of sections from PE header + uint16_t get_number_of_sections() const; + + //Updates number of sections in PE header + uint16_t update_number_of_sections(); + + //Returns section alignment + uint32_t get_section_alignment() const; + + //Returns section list + section_list& get_image_sections(); + const section_list& get_image_sections() const; + + //Realigns all sections, if you made any changes to sections or alignments + void realign_all_sections(); + //Resligns section with specified index + void realign_section(uint32_t index); + + //Returns section from RVA inside it + section& section_from_rva(uint32_t rva); + const section& section_from_rva(uint32_t rva) const; + //Returns section from directory ID + section& section_from_directory(uint32_t directory_id); + const section& section_from_directory(uint32_t directory_id) const; + //Returns section from VA inside it for PE32 and PE64 respectively + section& section_from_va(uint32_t va); + const section& section_from_va(uint32_t va) const; + section& section_from_va(uint64_t va); + const section& section_from_va(uint64_t va) const; + //Returns section from file offset (4gb max) + section& section_from_file_offset(uint32_t offset); + const section& section_from_file_offset(uint32_t offset) const; + + //Returns section TOTAL RAW/VIRTUAL data length from RVA inside section + //If include_headers = true, data from the beginning of PE file to SizeOfHeaders will be searched, too + uint32_t section_data_length_from_rva(uint32_t rva, section_data_type datatype = section_data_raw, bool include_headers = false) const; + //Returns section TOTAL RAW/VIRTUAL data length from VA inside section for PE32 and PE64 respectively + //If include_headers = true, data from the beginning of PE file to SizeOfHeaders will be searched, too + uint32_t section_data_length_from_va(uint32_t va, section_data_type datatype = section_data_raw, bool include_headers = false) const; + uint32_t section_data_length_from_va(uint64_t va, section_data_type datatype = section_data_raw, bool include_headers = false) const; + + //Returns section remaining RAW/VIRTUAL data length from RVA to the end of section "s" (checks bounds) + uint32_t section_data_length_from_rva(const section& s, uint32_t rva_inside, section_data_type datatype = section_data_raw) const; + //Returns section remaining RAW/VIRTUAL data length from VA to the end of section "s" for PE32 and PE64 respectively (checks bounds) + uint32_t section_data_length_from_va(const section& s, uint64_t va_inside, section_data_type datatype = section_data_raw) const; + uint32_t section_data_length_from_va(const section& s, uint32_t va_inside, section_data_type datatype = section_data_raw) const; + + //Returns section remaining RAW/VIRTUAL data length from RVA "rva_inside" to the end of section containing RVA "rva" + //If include_headers = true, data from the beginning of PE file to SizeOfHeaders will be searched, too + uint32_t section_data_length_from_rva(uint32_t rva, uint32_t rva_inside, section_data_type datatype = section_data_raw, bool include_headers = false) const; + //Returns section remaining RAW/VIRTUAL data length from VA "va_inside" to the end of section containing VA "va" for PE32 and PE64 respectively + //If include_headers = true, data from the beginning of PE file to SizeOfHeaders will be searched, too + uint32_t section_data_length_from_va(uint32_t va, uint32_t va_inside, section_data_type datatype = section_data_raw, bool include_headers = false) const; + uint32_t section_data_length_from_va(uint64_t va, uint64_t va_inside, section_data_type datatype = section_data_raw, bool include_headers = false) const; + + //If include_headers = true, data from the beginning of PE file to SizeOfHeaders will be searched, too + //Returns corresponding section data pointer from RVA inside section + char* section_data_from_rva(uint32_t rva, bool include_headers = false); + const char* section_data_from_rva(uint32_t rva, section_data_type datatype = section_data_raw, bool include_headers = false) const; + //Returns corresponding section data pointer from VA inside section for PE32 and PE64 respectively + char* section_data_from_va(uint32_t va, bool include_headers = false); + const char* section_data_from_va(uint32_t va, section_data_type datatype = section_data_raw, bool include_headers = false) const; + char* section_data_from_va(uint64_t va, bool include_headers = false); + const char* section_data_from_va(uint64_t va, section_data_type datatype = section_data_raw, bool include_headers = false) const; + + //Returns corresponding section data pointer from RVA inside section "s" (checks bounds) + char* section_data_from_rva(section& s, uint32_t rva); + const char* section_data_from_rva(const section& s, uint32_t rva, section_data_type datatype = section_data_raw) const; + //Returns corresponding section data pointer from VA inside section "s" for PE32 and PE64 respectively (checks bounds) + char* section_data_from_va(section& s, uint32_t va); //Always returns raw data + const char* section_data_from_va(const section& s, uint32_t va, section_data_type datatype = section_data_raw) const; + char* section_data_from_va(section& s, uint64_t va); //Always returns raw data + const char* section_data_from_va(const section& s, uint64_t va, section_data_type datatype = section_data_raw) const; + + //Returns corresponding section data pointer from RVA inside section "s" (checks bounds, checks sizes, the most safe function) + template + T section_data_from_rva(const section& s, uint32_t rva, section_data_type datatype = section_data_raw) const + { + if(rva >= s.get_virtual_address() && rva < s.get_virtual_address() + s.get_aligned_virtual_size(get_section_alignment()) && pe_utils::is_sum_safe(rva, sizeof(T))) + { + const std::string& data = datatype == section_data_raw ? s.get_raw_data() : s.get_virtual_data(get_section_alignment()); + //Don't check for underflow here, comparsion is unsigned + if(data.size() < rva - s.get_virtual_address() + sizeof(T)) + throw pe_exception("RVA and requested data size does not exist inside section", pe_exception::rva_not_exists); + + return *reinterpret_cast(data.data() + rva - s.get_virtual_address()); + } + + throw pe_exception("RVA not found inside section", pe_exception::rva_not_exists); + } + + //Returns corresponding section data pointer from RVA inside section (checks rva, checks sizes, the most safe function) + //If include_headers = true, data from the beginning of PE file to SizeOfHeaders will be searched, too + template + T section_data_from_rva(uint32_t rva, section_data_type datatype = section_data_raw, bool include_headers = false) const + { + //if RVA is inside of headers and we're searching them too... + if(include_headers && pe_utils::is_sum_safe(rva, sizeof(T)) && (rva + sizeof(T) < full_headers_data_.length())) + return *reinterpret_cast(&full_headers_data_[rva]); + + const section& s = section_from_rva(rva); + const std::string& data = datatype == section_data_raw ? s.get_raw_data() : s.get_virtual_data(get_section_alignment()); + //Don't check for underflow here, comparsion is unsigned + if(data.size() < rva - s.get_virtual_address() + sizeof(T)) + throw pe_exception("RVA and requested data size does not exist inside section", pe_exception::rva_not_exists); + + return *reinterpret_cast(data.data() + rva - s.get_virtual_address()); + } + + //Returns corresponding section data pointer from VA inside section "s" (checks bounds, checks sizes, the most safe function) + template + T section_data_from_va(const section& s, uint32_t va, section_data_type datatype = section_data_raw) const + { + return section_data_from_rva(s, va_to_rva(va), datatype); + } + + template + T section_data_from_va(const section& s, uint64_t va, section_data_type datatype = section_data_raw) const + { + return section_data_from_rva(s, va_to_rva(va), datatype); + } + + //Returns corresponding section data pointer from VA inside section (checks rva, checks sizes, the most safe function) + //If include_headers = true, data from the beginning of PE file to SizeOfHeaders will be searched, too + template + T section_data_from_va(uint32_t va, section_data_type datatype = section_data_raw, bool include_headers = false) const + { + return section_data_from_rva(va_to_rva(va), datatype, include_headers); + } + + template + T section_data_from_va(uint64_t va, section_data_type datatype = section_data_raw, bool include_headers = false) const + { + return section_data_from_rva(va_to_rva(va), datatype, include_headers); + } + + //Returns section and offset (raw data only) from its start from RVA + const std::pair section_and_offset_from_rva(uint32_t rva) const; + + //Sets virtual size of section "s" + //Section must be free (not bound to any image) + //or the last section of this image + //Function calls update_image_size automatically in second case + void set_section_virtual_size(section& s, uint32_t vsize); + + //Represents section expand type for expand_section function + enum section_expand_type + { + expand_section_raw, //Section raw data size will be expanded + expand_section_virtual //Section virtual data size will be expanded + }; + + //Expands section raw or virtual size to hold data from specified RVA with specified size + //Section must be free (not bound to any image) + //or the last section of this image + //Returns true if section was expanded + bool expand_section(section& s, uint32_t needed_rva, uint32_t needed_size, section_expand_type expand); + + //Adds section to image + //Returns last section + section& add_section(section s); + //Prepares section to later add it to image (checks and recalculates virtual and raw section size) + //Section must be prepared by this function before calling add_section + void prepare_section(section& s); + + //Returns true if sectios "s" is already attached to this PE file + bool section_attached(const section& s) const; + + +public: //IMAGE + //Returns PE type (PE or PE+) from pe_type enumeration (minimal correctness checks) + static pe_type get_pe_type(std::istream& file); + //Returns PE type of this image + pe_type get_pe_type() const; + + //Returns true if image has overlay data at the end of file + bool has_overlay() const; + + //Realigns file (changes file alignment) + void realign_file(uint32_t new_file_alignment); + + //Helper function to recalculate RAW and virtual section sizes and strip it, if necessary + //auto_strip = strip section, if necessary + void recalculate_section_sizes(section& s, bool auto_strip); + + // ========== END OF PUBLIC MEMBERS AND STRUCTURES ========== // +private: + //Image DOS header + pe_win::image_dos_header dos_header_; + //Rich (stub) overlay data (for MSVS) + std::string rich_overlay_; + //List of image sections + section_list sections_; + //True if image has overlay + bool has_overlay_; + //Raw SizeOfHeaders-sized data from the beginning of image + std::string full_headers_data_; + //Raw debug data for all directories + //PointerToRawData; Data + debug_data_list debug_data_; + //PE or PE+ related properties + pe_properties* props_; + + //Reads and checks DOS header + void read_dos_header(std::istream& file); + + //Reads and checks PE headers and section headers, data + void read_pe(std::istream& file, bool read_debug_raw_data); + + //Sets number of sections + void set_number_of_sections(uint16_t number); + //Sets size of image + void set_size_of_image(uint32_t size); + //Sets file alignment (no checks) + void set_file_alignment_unchecked(uint32_t alignment); + //Returns needed magic of image + uint32_t get_needed_magic() const; + //Returns nt headers data pointer + char* get_nt_headers_ptr(); + +private: + static const uint16_t maximum_number_of_sections = 0x60; + static const uint32_t minimum_file_alignment = 512; + +private: + //RAW file offset to section convertion helpers (4gb max) + section_list::const_iterator file_offset_to_section(uint32_t offset) const; + section_list::iterator file_offset_to_section(uint32_t offset); +}; +} diff --git a/drivers/pe_bliss/pe_bliss.h b/drivers/pe_bliss/pe_bliss.h new file mode 100644 index 0000000000..82dfd67cf5 --- /dev/null +++ b/drivers/pe_bliss/pe_bliss.h @@ -0,0 +1,18 @@ +#pragma once +#include "pe_base.h" +#include "pe_rebuilder.h" +#include "pe_factory.h" +#include "pe_bound_import.h" +#include "pe_debug.h" +#include "pe_dotnet.h" +#include "pe_exception_directory.h" +#include "pe_exports.h" +#include "pe_imports.h" +#include "pe_load_config.h" +#include "pe_relocations.h" +#include "pe_resources.h" +#include "pe_rich_data.h" +#include "pe_tls.h" +#include "pe_properties_generic.h" +#include "pe_checksum.h" +#include "entropy.h" diff --git a/drivers/pe_bliss/pe_bliss_godot.cpp b/drivers/pe_bliss/pe_bliss_godot.cpp new file mode 100644 index 0000000000..8297aa1045 --- /dev/null +++ b/drivers/pe_bliss/pe_bliss_godot.cpp @@ -0,0 +1,118 @@ +#include "pe_bliss/pe_bliss.h" +#include "pe_bliss/pe_bliss_resources.h" +#include "core/ustring.h" +#include "core/dvector.h" +#include "os/file_access.h" + +using namespace pe_bliss; + +String pe_bliss_add_resrc(const char* p_path, int version_major, int version_minor, + String& company_name, String& file_description, + String& legal_copyright, String& version_text, + String& product_name, String& godot_version, + DVector& icon_content) { + try + { + pe_base image(pe_factory::create_pe(p_path)); + + const section_list& pe_sections = image.get_image_sections(); + uint32_t end_of_pe = 0; + FileAccess *dst; + DVector overlay_data; + if(image.has_overlay()) + { + end_of_pe = pe_sections.back().get_pointer_to_raw_data() + pe_sections.back().get_size_of_raw_data(); + dst=FileAccess::open(p_path,FileAccess::READ); + if (dst) { + overlay_data.resize(dst->get_len()-end_of_pe); + dst->seek(end_of_pe); + DVector::Write overlay_data_write = overlay_data.write(); + dst->get_buffer(overlay_data_write.ptr(),overlay_data.size()); + dst->close(); + memdelete(dst); + } + } + resource_directory root; + if(image.has_resources()) + { + root = resource_directory(get_resources(image)); + } + pe_resource_manager res(root); + if(image.has_resources()) + { + if(icon_content.size()) { + if(res.resource_exists(pe_resource_viewer::resource_icon)) + { + res.remove_resource_type(pe_resource_viewer::resource_icon); + } + if(res.resource_exists(pe_resource_viewer::resource_icon_group)) + { + res.remove_resource_type(pe_resource_viewer::resource_icon_group); + } + } + if(res.resource_exists(pe_resource_viewer::resource_version)) + { + res.remove_resource_type(pe_resource_viewer::resource_version); + } + } + file_version_info file_info; + file_info.set_file_os(file_version_info::file_os_nt_win32); + file_info.set_file_type(file_version_info::file_type_application); + unsigned int ver = version_major << 16; + ver = ver + version_minor; + file_info.set_file_version_ms(ver); + file_info.set_file_version_ls(0x00000000); + file_info.set_product_version_ms(ver); + file_info.set_product_version_ls(0x00000000); + lang_string_values_map strings; + translation_values_map translations; + version_info_editor version(strings, translations); + version.add_translation(version_info_editor::default_language_translation); + version.set_company_name(company_name.c_str()); + version.set_file_description(file_description.c_str()); + if (!product_name.empty()) { + version.set_internal_name((product_name+String(".exe")).c_str()); + version.set_original_filename((product_name+String(".exe")).c_str()); + version.set_product_name(product_name.c_str()); + } + version.set_legal_copyright(legal_copyright.c_str()); + version.set_product_version(version_text.c_str()); + if(!godot_version.empty()) version.set_property(L"Godot Engine Version", godot_version.c_str() ); + resource_version_info_writer(res).set_version_info(file_info, strings, translations, 1033, 1200); + if(icon_content.size()) { + std::string icon; + icon.resize(icon_content.size()); + for(int i=0; iseek_end(); + DVector::Read overlay_data_read = overlay_data.read(); + dst->store_buffer(overlay_data_read.ptr(),overlay_data.size()); + dst->close(); + memdelete(dst); + } + } + return String(); + } catch(const pe_exception& e) { + String ret("Error In Add rsrc Section : "); + return ret + String(e.what()); + } +} diff --git a/drivers/pe_bliss/pe_bliss_godot.h b/drivers/pe_bliss/pe_bliss_godot.h new file mode 100644 index 0000000000..0365ca9eaf --- /dev/null +++ b/drivers/pe_bliss/pe_bliss_godot.h @@ -0,0 +1,7 @@ + + +String pe_bliss_add_resrc(const char* p_path, int version_major, int version_minor, + String& company_name, String& file_description, + String& legal_copyright, String& version_text, + String& product_name, String& godot_version, + DVector& icon_content); diff --git a/drivers/pe_bliss/pe_bliss_resources.h b/drivers/pe_bliss/pe_bliss_resources.h new file mode 100644 index 0000000000..7c07b7c4bb --- /dev/null +++ b/drivers/pe_bliss/pe_bliss_resources.h @@ -0,0 +1,15 @@ +#pragma once +#include "file_version_info.h" +#include "message_table.h" +#include "pe_resource_manager.h" +#include "pe_resource_viewer.h" +#include "version_info_editor.h" +#include "version_info_viewer.h" +#include "resource_bitmap_reader.h" +#include "resource_bitmap_writer.h" +#include "resource_cursor_icon_reader.h" +#include "resource_cursor_icon_writer.h" +#include "resource_version_info_reader.h" +#include "resource_version_info_writer.h" +#include "resource_string_table_reader.h" +#include "resource_message_list_reader.h" diff --git a/drivers/pe_bliss/pe_bound_import.cpp b/drivers/pe_bliss/pe_bound_import.cpp new file mode 100644 index 0000000000..605cf229b4 --- /dev/null +++ b/drivers/pe_bliss/pe_bound_import.cpp @@ -0,0 +1,290 @@ +#include +#include "pe_bound_import.h" +#include "utils.h" + +namespace pe_bliss +{ +using namespace pe_win; + +//BOUND IMPORT +//Default constructor +bound_import_ref::bound_import_ref() + :timestamp_(0) +{} + +//Constructor from data +bound_import_ref::bound_import_ref(const std::string& module_name, uint32_t timestamp) + :module_name_(module_name), timestamp_(timestamp) +{} + +//Returns imported module name +const std::string& bound_import_ref::get_module_name() const +{ + return module_name_; +} + +//Returns bound import date and time stamp +uint32_t bound_import_ref::get_timestamp() const +{ + return timestamp_; +} + +//Sets module name +void bound_import_ref::set_module_name(const std::string& module_name) +{ + module_name_ = module_name; +} + +//Sets timestamp +void bound_import_ref::set_timestamp(uint32_t timestamp) +{ + timestamp_ = timestamp; +} + +//Default constructor +bound_import::bound_import() + :timestamp_(0) +{} + +//Constructor from data +bound_import::bound_import(const std::string& module_name, uint32_t timestamp) + :module_name_(module_name), timestamp_(timestamp) +{} + +//Returns imported module name +const std::string& bound_import::get_module_name() const +{ + return module_name_; +} + +//Returns bound import date and time stamp +uint32_t bound_import::get_timestamp() const +{ + return timestamp_; +} + +//Returns bound references cound +size_t bound_import::get_module_ref_count() const +{ + return refs_.size(); +} + +//Returns module references +const bound_import::ref_list& bound_import::get_module_ref_list() const +{ + return refs_; +} + +//Adds module reference +void bound_import::add_module_ref(const bound_import_ref& ref) +{ + refs_.push_back(ref); +} + +//Clears module references list +void bound_import::clear_module_refs() +{ + refs_.clear(); +} + +//Returns module references +bound_import::ref_list& bound_import::get_module_ref_list() +{ + return refs_; +} + +//Sets module name +void bound_import::set_module_name(const std::string& module_name) +{ + module_name_ = module_name; +} + +//Sets timestamp +void bound_import::set_timestamp(uint32_t timestamp) +{ + timestamp_ = timestamp; +} + +const bound_import_module_list get_bound_import_module_list(const pe_base& pe) +{ + //Returned bound import modules list + bound_import_module_list ret; + + //If image has no bound imports + if(!pe.has_bound_import()) + return ret; + + uint32_t bound_import_data_len = + pe.section_data_length_from_rva(pe.get_directory_rva(image_directory_entry_bound_import), pe.get_directory_rva(image_directory_entry_bound_import), section_data_raw, true); + + if(bound_import_data_len < pe.get_directory_size(image_directory_entry_bound_import)) + throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory); + + const char* bound_import_data = pe.section_data_from_rva(pe.get_directory_rva(image_directory_entry_bound_import), section_data_raw, true); + + //Check read in "read_pe" function raw bound import data size + if(bound_import_data_len < sizeof(image_bound_import_descriptor)) + throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory); + + //current bound_import_data_ in-string position + unsigned long current_pos = 0; + //first bound import descriptor + //so, we're working with raw data here, no section helpers available + const image_bound_import_descriptor* descriptor = reinterpret_cast(&bound_import_data[current_pos]); + + //Enumerate until zero + while(descriptor->OffsetModuleName) + { + //Check module name offset + if(descriptor->OffsetModuleName >= bound_import_data_len) + throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory); + + //Check module name for null-termination + if(!pe_utils::is_null_terminated(&bound_import_data[descriptor->OffsetModuleName], bound_import_data_len - descriptor->OffsetModuleName)) + throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory); + + //Create bound import descriptor structure + bound_import elem(&bound_import_data[descriptor->OffsetModuleName], descriptor->TimeDateStamp); + + //Check DWORDs + if(descriptor->NumberOfModuleForwarderRefs >= pe_utils::max_dword / sizeof(image_bound_forwarder_ref) + || !pe_utils::is_sum_safe(current_pos, 2 /* this descriptor and the next one */ * sizeof(image_bound_import_descriptor) + descriptor->NumberOfModuleForwarderRefs * sizeof(image_bound_forwarder_ref))) + throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory); + + //Move after current descriptor + current_pos += sizeof(image_bound_import_descriptor); + + //Enumerate referenced bound import descriptors + for(unsigned long i = 0; i != descriptor->NumberOfModuleForwarderRefs; ++i) + { + //They're just after parent descriptor + //Check size of structure + if(current_pos + sizeof(image_bound_forwarder_ref) > bound_import_data_len) + throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory); + + //Get IMAGE_BOUND_FORWARDER_REF pointer + const image_bound_forwarder_ref* ref_descriptor = reinterpret_cast(&bound_import_data[current_pos]); + + //Check referenced module name + if(ref_descriptor->OffsetModuleName >= bound_import_data_len) + throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory); + + //And its null-termination + if(!pe_utils::is_null_terminated(&bound_import_data[ref_descriptor->OffsetModuleName], bound_import_data_len - ref_descriptor->OffsetModuleName)) + throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory); + + //Add referenced module to current bound import structure + elem.add_module_ref(bound_import_ref(&bound_import_data[ref_descriptor->OffsetModuleName], ref_descriptor->TimeDateStamp)); + + //Move after referenced bound import descriptor + current_pos += sizeof(image_bound_forwarder_ref); + } + + //Check structure size + if(current_pos + sizeof(image_bound_import_descriptor) > bound_import_data_len) + throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory); + + //Move to next bound import descriptor + descriptor = reinterpret_cast(&bound_import_data[current_pos]); + + //Save created descriptor structure and references + ret.push_back(elem); + } + + //Return result + return ret; +} + +//imports - bound imported modules list +//imports_section - section where export directory will be placed (must be attached to PE image) +//offset_from_section_start - offset from imports_section raw data start +//save_to_pe_headers - if true, new bound import directory information will be saved to PE image headers +//auto_strip_last_section - if true and bound imports are placed in the last section, it will be automatically stripped +const image_directory rebuild_bound_imports(pe_base& pe, const bound_import_module_list& imports, section& imports_section, uint32_t offset_from_section_start, bool save_to_pe_header, bool auto_strip_last_section) +{ + //Check that exports_section is attached to this PE image + if(!pe.section_attached(imports_section)) + throw pe_exception("Bound import section must be attached to PE file", pe_exception::section_is_not_attached); + + uint32_t directory_pos = pe_utils::align_up(offset_from_section_start, sizeof(uint32_t)); + uint32_t needed_size = sizeof(image_bound_import_descriptor) /* Ending null descriptor */; + uint32_t needed_size_for_strings = 0; + + //Calculate needed size for bound import data + for(bound_import_module_list::const_iterator it = imports.begin(); it != imports.end(); ++it) + { + const bound_import& import = *it; + needed_size += sizeof(image_bound_import_descriptor); + needed_size_for_strings += static_cast((*it).get_module_name().length()) + 1 /* nullbyte */; + + const bound_import::ref_list& refs = import.get_module_ref_list(); + for(bound_import::ref_list::const_iterator ref_it = refs.begin(); ref_it != refs.end(); ++ref_it) + { + needed_size_for_strings += static_cast((*ref_it).get_module_name().length()) + 1 /* nullbyte */; + needed_size += sizeof(image_bound_forwarder_ref); + } + } + + needed_size += needed_size_for_strings; + + //Check if imports_section is last one. If it's not, check if there's enough place for bound import data + if(&imports_section != &*(pe.get_image_sections().end() - 1) && + (imports_section.empty() || pe_utils::align_up(imports_section.get_size_of_raw_data(), pe.get_file_alignment()) < needed_size + directory_pos)) + throw pe_exception("Insufficient space for bound import directory", pe_exception::insufficient_space); + + std::string& raw_data = imports_section.get_raw_data(); + + //This will be done only if imports_section is the last section of image or for section with unaligned raw length of data + if(raw_data.length() < needed_size + directory_pos) + raw_data.resize(needed_size + directory_pos); //Expand section raw data + + uint32_t current_pos_for_structures = directory_pos; + uint32_t current_pos_for_strings = current_pos_for_structures + needed_size - needed_size_for_strings; + + for(bound_import_module_list::const_iterator it = imports.begin(); it != imports.end(); ++it) + { + const bound_import& import = *it; + image_bound_import_descriptor descriptor; + descriptor.NumberOfModuleForwarderRefs = static_cast(import.get_module_ref_list().size()); + descriptor.OffsetModuleName = static_cast(current_pos_for_strings - directory_pos); + descriptor.TimeDateStamp = import.get_timestamp(); + + memcpy(&raw_data[current_pos_for_structures], &descriptor, sizeof(descriptor)); + current_pos_for_structures += sizeof(descriptor); + + size_t length = import.get_module_name().length() + 1 /* nullbyte */; + memcpy(&raw_data[current_pos_for_strings], import.get_module_name().c_str(), length); + current_pos_for_strings += static_cast(length); + + const bound_import::ref_list& refs = import.get_module_ref_list(); + for(bound_import::ref_list::const_iterator ref_it = refs.begin(); ref_it != refs.end(); ++ref_it) + { + const bound_import_ref& ref = *ref_it; + image_bound_forwarder_ref ref_descriptor = {0}; + ref_descriptor.OffsetModuleName = static_cast(current_pos_for_strings - directory_pos); + ref_descriptor.TimeDateStamp = ref.get_timestamp(); + + memcpy(&raw_data[current_pos_for_structures], &ref_descriptor, sizeof(ref_descriptor)); + current_pos_for_structures += sizeof(ref_descriptor); + + length = ref.get_module_name().length() + 1 /* nullbyte */; + memcpy(&raw_data[current_pos_for_strings], ref.get_module_name().c_str(), length); + current_pos_for_strings += static_cast(length); + } + } + + //Adjust section raw and virtual sizes + pe.recalculate_section_sizes(imports_section, auto_strip_last_section); + + image_directory ret(pe.rva_from_section_offset(imports_section, directory_pos), needed_size); + + //If auto-rewrite of PE headers is required + if(save_to_pe_header) + { + pe.set_directory_rva(image_directory_entry_bound_import, ret.get_rva()); + pe.set_directory_size(image_directory_entry_bound_import, ret.get_size()); + } + + return ret; +} +} diff --git a/drivers/pe_bliss/pe_bound_import.h b/drivers/pe_bliss/pe_bound_import.h new file mode 100644 index 0000000000..5c27eba06b --- /dev/null +++ b/drivers/pe_bliss/pe_bound_import.h @@ -0,0 +1,87 @@ +#pragma once +#include +#include +#include "pe_structures.h" +#include "pe_base.h" +#include "pe_directory.h" + +namespace pe_bliss +{ +//Class representing bound import reference +class bound_import_ref +{ +public: + //Default constructor + bound_import_ref(); + //Constructor from data + bound_import_ref(const std::string& module_name, uint32_t timestamp); + + //Returns imported module name + const std::string& get_module_name() const; + //Returns bound import date and time stamp + uint32_t get_timestamp() const; + +public: //Setters + //Sets module name + void set_module_name(const std::string& module_name); + //Sets timestamp + void set_timestamp(uint32_t timestamp); + +private: + std::string module_name_; //Imported module name + uint32_t timestamp_; //Bound import timestamp +}; + +//Class representing image bound import information +class bound_import +{ +public: + typedef std::vector ref_list; + +public: + //Default constructor + bound_import(); + //Constructor from data + bound_import(const std::string& module_name, uint32_t timestamp); + + //Returns imported module name + const std::string& get_module_name() const; + //Returns bound import date and time stamp + uint32_t get_timestamp() const; + + //Returns bound references cound + size_t get_module_ref_count() const; + //Returns module references + const ref_list& get_module_ref_list() const; + +public: //Setters + //Sets module name + void set_module_name(const std::string& module_name); + //Sets timestamp + void set_timestamp(uint32_t timestamp); + + //Adds module reference + void add_module_ref(const bound_import_ref& ref); + //Clears module references list + void clear_module_refs(); + //Returns module references + ref_list& get_module_ref_list(); + +private: + std::string module_name_; //Imported module name + uint32_t timestamp_; //Bound import timestamp + ref_list refs_; //Module references list +}; + +typedef std::vector bound_import_module_list; + +//Returns bound import information +const bound_import_module_list get_bound_import_module_list(const pe_base& pe);//Export directory rebuilder + +//imports - bound imported modules list +//imports_section - section where export directory will be placed (must be attached to PE image) +//offset_from_section_start - offset from imports_section raw data start +//save_to_pe_headers - if true, new bound import directory information will be saved to PE image headers +//auto_strip_last_section - if true and bound imports are placed in the last section, it will be automatically stripped +const image_directory rebuild_bound_imports(pe_base& pe, const bound_import_module_list& imports, section& imports_section, uint32_t offset_from_section_start = 0, bool save_to_pe_header = true, bool auto_strip_last_section = true); +} diff --git a/drivers/pe_bliss/pe_checksum.cpp b/drivers/pe_bliss/pe_checksum.cpp new file mode 100644 index 0000000000..f6d23f0e10 --- /dev/null +++ b/drivers/pe_bliss/pe_checksum.cpp @@ -0,0 +1,82 @@ +#include "pe_checksum.h" +#include "pe_structures.h" +#include "pe_base.h" + +namespace pe_bliss +{ +using namespace pe_win; + +//Calculate checksum of image +uint32_t calculate_checksum(std::istream& file) +{ + //Save istream state + std::ios_base::iostate state = file.exceptions(); + std::streamoff old_offset = file.tellg(); + + //Checksum value + unsigned long long checksum = 0; + + try + { + image_dos_header header; + + file.exceptions(std::ios::goodbit); + + //Read DOS header + pe_base::read_dos_header(file, header); + + //Calculate PE checksum + file.seekg(0); + unsigned long long top = 0xFFFFFFFF; + top++; + + //"CheckSum" field position in optional PE headers - it's always 64 for PE and PE+ + static const unsigned long checksum_pos_in_optional_headers = 64; + //Calculate real PE headers "CheckSum" field position + //Sum is safe here + unsigned long pe_checksum_pos = header.e_lfanew + sizeof(image_file_header) + sizeof(uint32_t) + checksum_pos_in_optional_headers; + + //Calculate checksum for each byte of file + std::streamoff filesize = pe_utils::get_file_size(file); + for(long long i = 0; i < filesize; i += 4) + { + unsigned long dw = 0; + + //Read DWORD from file + file.read(reinterpret_cast(&dw), sizeof(unsigned long)); + //Skip "CheckSum" DWORD + if(i == pe_checksum_pos) + continue; + + //Calculate checksum + checksum = (checksum & 0xffffffff) + dw + (checksum >> 32); + if(checksum > top) + checksum = (checksum & 0xffffffff) + (checksum >> 32); + } + + //Finish checksum + checksum = (checksum & 0xffff) + (checksum >> 16); + checksum = (checksum) + (checksum >> 16); + checksum = checksum & 0xffff; + + checksum += static_cast(filesize); + } + catch(const std::exception&) + { + //If something went wrong, restore istream state + file.exceptions(state); + file.seekg(old_offset); + file.clear(); + //Rethrow + throw; + } + + //Restore istream state + file.exceptions(state); + file.seekg(old_offset); + file.clear(); + + //Return checksum + return static_cast(checksum); +} +} diff --git a/drivers/pe_bliss/pe_checksum.h b/drivers/pe_bliss/pe_checksum.h new file mode 100644 index 0000000000..892a2854ba --- /dev/null +++ b/drivers/pe_bliss/pe_checksum.h @@ -0,0 +1,9 @@ +#pragma once +#include +#include "stdint_defs.h" + +namespace pe_bliss +{ +//Calculate checksum of image (performs no checks on PE structures) +uint32_t calculate_checksum(std::istream& file); +} diff --git a/drivers/pe_bliss/pe_debug.cpp b/drivers/pe_bliss/pe_debug.cpp new file mode 100644 index 0000000000..f077f29fb8 --- /dev/null +++ b/drivers/pe_bliss/pe_debug.cpp @@ -0,0 +1,844 @@ +#include +#include "pe_debug.h" +#include "utils.h" + +namespace pe_bliss +{ +using namespace pe_win; +//DEBUG +//Default constructor +debug_info::debug_info() + :characteristics_(0), + time_stamp_(0), + major_version_(0), minor_version_(0), + type_(0), + size_of_data_(0), + address_of_raw_data_(0), + pointer_to_raw_data_(0), + advanced_info_type_(advanced_info_none) +{} + +//Constructor from data +debug_info::debug_info(const image_debug_directory& debug) + :characteristics_(debug.Characteristics), + time_stamp_(debug.TimeDateStamp), + major_version_(debug.MajorVersion), minor_version_(debug.MinorVersion), + type_(debug.Type), + size_of_data_(debug.SizeOfData), + address_of_raw_data_(debug.AddressOfRawData), + pointer_to_raw_data_(debug.PointerToRawData), + advanced_info_type_(advanced_info_none) +{} + +//Returns debug characteristics +uint32_t debug_info::get_characteristics() const +{ + return characteristics_; +} + +//Returns debug datetimestamp +uint32_t debug_info::get_time_stamp() const +{ + return time_stamp_; +} + +//Returns major version +uint32_t debug_info::get_major_version() const +{ + return major_version_; +} + +//Returns minor version +uint32_t debug_info::get_minor_version() const +{ + return minor_version_; +} + +//Returns type of debug info (unchecked) +uint32_t debug_info::get_type_raw() const +{ + return type_; +} + +//Returns type of debug info from debug_info_type enumeration +debug_info::debug_info_type debug_info::get_type() const +{ + //Determine debug type + switch(type_) + { + case image_debug_type_coff: + return debug_type_coff; + + case image_debug_type_codeview: + return debug_type_codeview; + + case image_debug_type_fpo: + return debug_type_fpo; + + case image_debug_type_misc: + return debug_type_misc; + + case image_debug_type_exception: + return debug_type_exception; + + case image_debug_type_fixup: + return debug_type_fixup; + + case image_debug_type_omap_to_src: + return debug_type_omap_to_src; + + case image_debug_type_omap_from_src: + return debug_type_omap_from_src; + + case image_debug_type_borland: + return debug_type_borland; + + case image_debug_type_clsid: + return debug_type_clsid; + + case image_debug_type_reserved10: + return debug_type_reserved10; + } + + return debug_type_unknown; +} + +//Returns size of debug data (internal, .pdb or other file doesn't count) +uint32_t debug_info::get_size_of_data() const +{ + return size_of_data_; +} + +//Returns RVA of debug info when mapped to memory or zero, if info is not mapped +uint32_t debug_info::get_rva_of_raw_data() const +{ + return address_of_raw_data_; +} + +//Returns raw file pointer to raw data +uint32_t debug_info::get_pointer_to_raw_data() const +{ + return pointer_to_raw_data_; +} + +//Copy constructor +debug_info::debug_info(const debug_info& info) + :characteristics_(info.characteristics_), + time_stamp_(info.time_stamp_), + major_version_(info.major_version_), minor_version_(info.minor_version_), + type_(info.type_), + size_of_data_(info.size_of_data_), + address_of_raw_data_(info.address_of_raw_data_), + pointer_to_raw_data_(info.pointer_to_raw_data_), + advanced_info_type_(info.advanced_info_type_) +{ + copy_advanced_info(info); +} + +//Copy assignment operator +debug_info& debug_info::operator=(const debug_info& info) +{ + copy_advanced_info(info); + + characteristics_ = info.characteristics_; + time_stamp_ = info.time_stamp_; + major_version_ = info.major_version_; + minor_version_ = info.minor_version_; + type_ = info.type_; + size_of_data_ = info.size_of_data_; + address_of_raw_data_ = info.address_of_raw_data_; + pointer_to_raw_data_ = info.pointer_to_raw_data_; + advanced_info_type_ = info.advanced_info_type_; + + return *this; +} + +//Default constructor +debug_info::advanced_info::advanced_info() + :adv_pdb_7_0_info(0) //Zero pointer to advanced data +{} + +//Returns true if advanced debug info is present +bool debug_info::advanced_info::is_present() const +{ + return adv_pdb_7_0_info != 0; +} + +//Helper for advanced debug information copying +void debug_info::copy_advanced_info(const debug_info& info) +{ + free_present_advanced_info(); + + switch(info.advanced_info_type_) + { + case advanced_info_pdb_7_0: + advanced_debug_info_.adv_pdb_7_0_info = new pdb_7_0_info(*info.advanced_debug_info_.adv_pdb_7_0_info); + break; + case advanced_info_pdb_2_0: + advanced_debug_info_.adv_pdb_2_0_info = new pdb_2_0_info(*info.advanced_debug_info_.adv_pdb_2_0_info); + break; + case advanced_info_misc: + advanced_debug_info_.adv_misc_info = new misc_debug_info(*info.advanced_debug_info_.adv_misc_info); + break; + case advanced_info_coff: + advanced_debug_info_.adv_coff_info = new coff_debug_info(*info.advanced_debug_info_.adv_coff_info); + break; + default: + break; + } + + advanced_info_type_ = info.advanced_info_type_; +} + +//Helper for clearing any present advanced debug information +void debug_info::free_present_advanced_info() +{ + switch(advanced_info_type_) + { + case advanced_info_pdb_7_0: + delete advanced_debug_info_.adv_pdb_7_0_info; + break; + case advanced_info_pdb_2_0: + delete advanced_debug_info_.adv_pdb_2_0_info; + break; + case advanced_info_misc: + delete advanced_debug_info_.adv_misc_info; + break; + case advanced_info_coff: + delete advanced_debug_info_.adv_coff_info; + break; + default: + break; + } + + advanced_debug_info_.adv_pdb_7_0_info = 0; + advanced_info_type_ = advanced_info_none; +} + +//Destructor +debug_info::~debug_info() +{ + free_present_advanced_info(); +} + +//Sets advanced debug information +void debug_info::set_advanced_debug_info(const pdb_7_0_info& info) +{ + free_present_advanced_info(); + advanced_debug_info_.adv_pdb_7_0_info = new pdb_7_0_info(info); + advanced_info_type_ = advanced_info_pdb_7_0; +} + +void debug_info::set_advanced_debug_info(const pdb_2_0_info& info) +{ + free_present_advanced_info(); + advanced_debug_info_.adv_pdb_2_0_info = new pdb_2_0_info(info); + advanced_info_type_ = advanced_info_pdb_2_0; +} + +void debug_info::set_advanced_debug_info(const misc_debug_info& info) +{ + free_present_advanced_info(); + advanced_debug_info_.adv_misc_info = new misc_debug_info(info); + advanced_info_type_ = advanced_info_misc; +} + +void debug_info::set_advanced_debug_info(const coff_debug_info& info) +{ + free_present_advanced_info(); + advanced_debug_info_.adv_coff_info = new coff_debug_info(info); + advanced_info_type_ = advanced_info_coff; +} + +//Returns advanced debug information type +debug_info::advanced_info_type debug_info::get_advanced_info_type() const +{ + return advanced_info_type_; +} + +//Returns advanced debug information or throws an exception, +//if requested information type is not contained by structure +template<> +const pdb_7_0_info debug_info::get_advanced_debug_info() const +{ + if(advanced_info_type_ != advanced_info_pdb_7_0) + throw pe_exception("Debug info structure does not contain PDB 7.0 data", pe_exception::advanced_debug_information_request_error); + + return *advanced_debug_info_.adv_pdb_7_0_info; +} + +template<> +const pdb_2_0_info debug_info::get_advanced_debug_info() const +{ + if(advanced_info_type_ != advanced_info_pdb_2_0) + throw pe_exception("Debug info structure does not contain PDB 2.0 data", pe_exception::advanced_debug_information_request_error); + + return *advanced_debug_info_.adv_pdb_2_0_info; +} + +template<> +const misc_debug_info debug_info::get_advanced_debug_info() const +{ + if(advanced_info_type_ != advanced_info_misc) + throw pe_exception("Debug info structure does not contain MISC data", pe_exception::advanced_debug_information_request_error); + + return *advanced_debug_info_.adv_misc_info; +} + +template<> +const coff_debug_info debug_info::get_advanced_debug_info() const +{ + if(advanced_info_type_ != advanced_info_coff) + throw pe_exception("Debug info structure does not contain COFF data", pe_exception::advanced_debug_information_request_error); + + return *advanced_debug_info_.adv_coff_info; +} + +//Sets advanced debug information type, if no advanced info structure available +void debug_info::set_advanced_info_type(advanced_info_type type) +{ + free_present_advanced_info(); + if(advanced_info_type_ >= advanced_info_codeview_4_0) //Don't set info type for those types, which have advanced info structures + advanced_info_type_ = type; +} + +//Default constructor +pdb_7_0_info::pdb_7_0_info() + :age_(0) +{ + memset(&guid_, 0, sizeof(guid_)); +} + +//Constructor from data +pdb_7_0_info::pdb_7_0_info(const CV_INFO_PDB70* info) + :age_(info->Age), guid_(info->Signature), + pdb_file_name_(reinterpret_cast(info->PdbFileName)) //Must be checked before for null-termination +{} + +//Returns debug PDB 7.0 structure GUID +const guid pdb_7_0_info::get_guid() const +{ + return guid_; +} + +//Returns age of build +uint32_t pdb_7_0_info::get_age() const +{ + return age_; +} + +//Returns PDB file name / path +const std::string& pdb_7_0_info::get_pdb_file_name() const +{ + return pdb_file_name_; +} + +//Default constructor +pdb_2_0_info::pdb_2_0_info() + :age_(0), signature_(0) +{} + +//Constructor from data +pdb_2_0_info::pdb_2_0_info(const CV_INFO_PDB20* info) + :age_(info->Age), signature_(info->Signature), + pdb_file_name_(reinterpret_cast(info->PdbFileName)) //Must be checked before for null-termination +{} + +//Returns debug PDB 2.0 structure signature +uint32_t pdb_2_0_info::get_signature() const +{ + return signature_; +} + +//Returns age of build +uint32_t pdb_2_0_info::get_age() const +{ + return age_; +} + +//Returns PDB file name / path +const std::string& pdb_2_0_info::get_pdb_file_name() const +{ + return pdb_file_name_; +} + +//Default constructor +misc_debug_info::misc_debug_info() + :data_type_(0), unicode_(false) +{} + +//Constructor from data +misc_debug_info::misc_debug_info(const image_debug_misc* info) + :data_type_(info->DataType), unicode_(info->Unicode ? true : false) +{ + //IMAGE_DEBUG_MISC::Data must be checked before! + if(info->Unicode) + { +#ifdef PE_BLISS_WINDOWS + debug_data_unicode_ = std::wstring(reinterpret_cast(info->Data), (info->Length - sizeof(image_debug_misc) + 1 /* BYTE[1] in the end of structure */) / 2); +#else + debug_data_unicode_ = pe_utils::from_ucs2(u16string(reinterpret_cast(info->Data), (info->Length - sizeof(image_debug_misc) + 1 /* BYTE[1] in the end of structure */) / 2)); +#endif + + pe_utils::strip_nullbytes(debug_data_unicode_); //Strip nullbytes in the end of string + } + else + { + debug_data_ansi_ = std::string(reinterpret_cast(info->Data), info->Length - sizeof(image_debug_misc) + 1 /* BYTE[1] in the end of structure */); + pe_utils::strip_nullbytes(debug_data_ansi_); //Strip nullbytes in the end of string + } +} + +//Returns debug data type +uint32_t misc_debug_info::get_data_type() const +{ + return data_type_; +} + +//Returns true if data type is exe name +bool misc_debug_info::is_exe_name() const +{ + return data_type_ == image_debug_misc_exename; +} + +//Returns true if debug data is UNICODE +bool misc_debug_info::is_unicode() const +{ + return unicode_; +} + +//Returns debug data (ANSI) +const std::string& misc_debug_info::get_data_ansi() const +{ + return debug_data_ansi_; +} + +//Returns debug data (UNICODE) +const std::wstring& misc_debug_info::get_data_unicode() const +{ + return debug_data_unicode_; +} + +//Default constructor +coff_debug_info::coff_debug_info() + :number_of_symbols_(0), + lva_to_first_symbol_(0), + number_of_line_numbers_(0), + lva_to_first_line_number_(0), + rva_to_first_byte_of_code_(0), + rva_to_last_byte_of_code_(0), + rva_to_first_byte_of_data_(0), + rva_to_last_byte_of_data_(0) +{} + +//Constructor from data +coff_debug_info::coff_debug_info(const image_coff_symbols_header* info) + :number_of_symbols_(info->NumberOfSymbols), + lva_to_first_symbol_(info->LvaToFirstSymbol), + number_of_line_numbers_(info->NumberOfLinenumbers), + lva_to_first_line_number_(info->LvaToFirstLinenumber), + rva_to_first_byte_of_code_(info->RvaToFirstByteOfCode), + rva_to_last_byte_of_code_(info->RvaToLastByteOfCode), + rva_to_first_byte_of_data_(info->RvaToFirstByteOfData), + rva_to_last_byte_of_data_(info->RvaToLastByteOfData) +{} + +//Returns number of symbols +uint32_t coff_debug_info::get_number_of_symbols() const +{ + return number_of_symbols_; +} + +//Returns virtual address of the first symbol +uint32_t coff_debug_info::get_lva_to_first_symbol() const +{ + return lva_to_first_symbol_; +} + +//Returns number of line-number entries +uint32_t coff_debug_info::get_number_of_line_numbers() const +{ + return number_of_line_numbers_; +} + +//Returns virtual address of the first line-number entry +uint32_t coff_debug_info::get_lva_to_first_line_number() const +{ + return lva_to_first_line_number_; +} + +//Returns relative virtual address of the first byte of code +uint32_t coff_debug_info::get_rva_to_first_byte_of_code() const +{ + return rva_to_first_byte_of_code_; +} + +//Returns relative virtual address of the last byte of code +uint32_t coff_debug_info::get_rva_to_last_byte_of_code() const +{ + return rva_to_last_byte_of_code_; +} + +//Returns relative virtual address of the first byte of data +uint32_t coff_debug_info::get_rva_to_first_byte_of_data() const +{ + return rva_to_first_byte_of_data_; +} + +//Returns relative virtual address of the last byte of data +uint32_t coff_debug_info::get_rva_to_last_byte_of_data() const +{ + return rva_to_last_byte_of_data_; +} + +//Returns COFF symbols list +const coff_debug_info::coff_symbols_list& coff_debug_info::get_symbols() const +{ + return symbols_; +} + +//Adds COFF symbol +void coff_debug_info::add_symbol(const coff_symbol& sym) +{ + symbols_.push_back(sym); +} + +//Default constructor +coff_debug_info::coff_symbol::coff_symbol() + :storage_class_(0), + index_(0), + section_number_(0), rva_(0), + type_(0), + is_filename_(false) +{} + +//Returns storage class +uint32_t coff_debug_info::coff_symbol::get_storage_class() const +{ + return storage_class_; +} + +//Returns symbol index +uint32_t coff_debug_info::coff_symbol::get_index() const +{ + return index_; +} + +//Returns section number +uint32_t coff_debug_info::coff_symbol::get_section_number() const +{ + return section_number_; +} + +//Returns RVA +uint32_t coff_debug_info::coff_symbol::get_rva() const +{ + return rva_; +} + +//Returns true if structure contains file name +bool coff_debug_info::coff_symbol::is_file() const +{ + return is_filename_; +} + +//Returns text data (symbol or file name) +const std::string& coff_debug_info::coff_symbol::get_symbol() const +{ + return name_; +} + +//Sets storage class +void coff_debug_info::coff_symbol::set_storage_class(uint32_t storage_class) +{ + storage_class_ = storage_class; +} + +//Sets symbol index +void coff_debug_info::coff_symbol::set_index(uint32_t index) +{ + index_ = index; +} + +//Sets section number +void coff_debug_info::coff_symbol::set_section_number(uint32_t section_number) +{ + section_number_ = section_number; +} + +//Sets RVA +void coff_debug_info::coff_symbol::set_rva(uint32_t rva) +{ + rva_ = rva; +} + +//Sets file name +void coff_debug_info::coff_symbol::set_file_name(const std::string& file_name) +{ + name_ = file_name; + is_filename_ = true; +} + +//Sets symbol name +void coff_debug_info::coff_symbol::set_symbol_name(const std::string& symbol_name) +{ + name_ = symbol_name; + is_filename_ = false; +} + +//Returns type +uint16_t coff_debug_info::coff_symbol::get_type() const +{ + return type_; +} + +//Sets type +void coff_debug_info::coff_symbol::set_type(uint16_t type) +{ + type_ = type; +} + +//Returns debug information list +const debug_info_list get_debug_information(const pe_base& pe) +{ + debug_info_list ret; + + //If there's no debug directory, return empty list + if(!pe.has_debug()) + return ret; + + //Check the length in bytes of the section containing debug directory + if(pe.section_data_length_from_rva(pe.get_directory_rva(image_directory_entry_debug), pe.get_directory_rva(image_directory_entry_debug), section_data_virtual, true) + < sizeof(image_debug_directory)) + throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); + + unsigned long current_pos = pe.get_directory_rva(image_directory_entry_debug); + + //First IMAGE_DEBUG_DIRECTORY table + image_debug_directory directory = pe.section_data_from_rva(current_pos, section_data_virtual, true); + + if(!pe_utils::is_sum_safe(pe.get_directory_rva(image_directory_entry_debug), pe.get_directory_size(image_directory_entry_debug))) + throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); + + //Iterate over all IMAGE_DEBUG_DIRECTORY directories + while(directory.PointerToRawData + && current_pos < pe.get_directory_rva(image_directory_entry_debug) + pe.get_directory_size(image_directory_entry_debug)) + { + //Create debug information structure + debug_info info(directory); + + //Find raw debug data + const pe_base::debug_data_list& debug_datas = pe.get_raw_debug_data_list(); + pe_base::debug_data_list::const_iterator it = debug_datas.find(directory.PointerToRawData); + if(it != debug_datas.end()) //If it exists, we'll do some detailed debug info research + { + const std::string& debug_data = (*it).second; + switch(directory.Type) + { + case image_debug_type_coff: + { + //Check data length + if(debug_data.length() < sizeof(image_coff_symbols_header)) + throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); + + //Get coff header structure pointer + const image_coff_symbols_header* coff = reinterpret_cast(debug_data.data()); + + //Check possible overflows + if(coff->NumberOfSymbols >= pe_utils::max_dword / sizeof(image_symbol) + || !pe_utils::is_sum_safe(coff->NumberOfSymbols * sizeof(image_symbol), coff->LvaToFirstSymbol)) + throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); + + //Check data length again + if(debug_data.length() < coff->NumberOfSymbols * sizeof(image_symbol) + coff->LvaToFirstSymbol) + throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); + + //Create COFF debug info structure + coff_debug_info coff_info(coff); + + //Enumerate debug symbols data + for(uint32_t i = 0; i < coff->NumberOfSymbols; ++i) + { + //Safe sum (checked above) + const image_symbol* sym = reinterpret_cast(debug_data.data() + i * sizeof(image_symbol) + coff->LvaToFirstSymbol); + + coff_debug_info::coff_symbol symbol; + symbol.set_index(i); //Save symbol index + symbol.set_storage_class(sym->StorageClass); //Save storage class + symbol.set_type(sym->Type); //Save storage class + + //Check data length again + if(!pe_utils::is_sum_safe(i, sym->NumberOfAuxSymbols) + || (i + sym->NumberOfAuxSymbols) > coff->NumberOfSymbols + || debug_data.length() < (i + 1) * sizeof(image_symbol) + coff->LvaToFirstSymbol + sym->NumberOfAuxSymbols * sizeof(image_symbol)) + throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); + + //If symbol is filename + if(sym->StorageClass == image_sym_class_file) + { + //Save file name, it is situated just after this IMAGE_SYMBOL structure + std::string file_name(reinterpret_cast(debug_data.data() + (i + 1) * sizeof(image_symbol)), sym->NumberOfAuxSymbols * sizeof(image_symbol)); + pe_utils::strip_nullbytes(file_name); + symbol.set_file_name(file_name); + + //Save symbol info + coff_info.add_symbol(symbol); + + //Move to next symbol + i += sym->NumberOfAuxSymbols; + continue; + } + + //Dump some other symbols + if(((sym->StorageClass == image_sym_class_static) + && (sym->NumberOfAuxSymbols == 0) + && (sym->SectionNumber == 1)) + || + ((sym->StorageClass == image_sym_class_external) + && ISFCN(sym->Type) + && (sym->SectionNumber > 0)) + ) + { + //Save RVA and section number + symbol.set_section_number(sym->SectionNumber); + symbol.set_rva(sym->Value); + + //If symbol has short name + if(sym->N.Name.Short) + { + //Copy and save symbol name + char name_buff[9]; + memcpy(name_buff, sym->N.ShortName, 8); + name_buff[8] = '\0'; + symbol.set_symbol_name(name_buff); + } + else + { + //Symbol has long name + + //Check possible overflows + if(!pe_utils::is_sum_safe(coff->LvaToFirstSymbol + coff->NumberOfSymbols * sizeof(image_symbol), sym->N.Name.Long)) + throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); + + //Here we have an offset to the string table + uint32_t symbol_offset = coff->LvaToFirstSymbol + coff->NumberOfSymbols * sizeof(image_symbol) + sym->N.Name.Long; + + //Check data length + if(debug_data.length() < symbol_offset) + throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); + + //Check symbol name for null-termination + if(!pe_utils::is_null_terminated(debug_data.data() + symbol_offset, debug_data.length() - symbol_offset)) + throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); + + //Save symbol name + symbol.set_symbol_name(debug_data.data() + symbol_offset); + } + + //Save symbol info + coff_info.add_symbol(symbol); + + //Move to next symbol + i += sym->NumberOfAuxSymbols; + continue; + } + } + + info.set_advanced_debug_info(coff_info); + } + break; + + case image_debug_type_codeview: + { + //Check data length + if(debug_data.length() < sizeof(OMFSignature*)) + throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); + + //Get POMFSignature structure pointer from the very beginning of debug data + const OMFSignature* sig = reinterpret_cast(debug_data.data()); + if(!memcmp(sig->Signature, "RSDS", 4)) + { + //Signature is "RSDS" - PDB 7.0 + + //Check data length + if(debug_data.length() < sizeof(CV_INFO_PDB70)) + throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); + + const CV_INFO_PDB70* pdb_data = reinterpret_cast(debug_data.data()); + + //Check PDB file name null-termination + if(!pe_utils::is_null_terminated(pdb_data->PdbFileName, debug_data.length() - (sizeof(CV_INFO_PDB70) - 1 /* BYTE of filename in structure */))) + throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); + + info.set_advanced_debug_info(pdb_7_0_info(pdb_data)); + } + else if(!memcmp(sig->Signature, "NB10", 4)) + { + //Signature is "NB10" - PDB 2.0 + + //Check data length + if(debug_data.length() < sizeof(CV_INFO_PDB20)) + throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); + + const CV_INFO_PDB20* pdb_data = reinterpret_cast(debug_data.data()); + + //Check PDB file name null-termination + if(!pe_utils::is_null_terminated(pdb_data->PdbFileName, debug_data.length() - (sizeof(CV_INFO_PDB20) - 1 /* BYTE of filename in structure */))) + throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); + + info.set_advanced_debug_info(pdb_2_0_info(pdb_data)); + } + else if(!memcmp(sig->Signature, "NB09", 4)) + { + //CodeView 4.0, no structures available + info.set_advanced_info_type(debug_info::advanced_info_codeview_4_0); + } + else if(!memcmp(sig->Signature, "NB11", 4)) + { + //CodeView 5.0, no structures available + info.set_advanced_info_type(debug_info::advanced_info_codeview_5_0); + } + else if(!memcmp(sig->Signature, "NB05", 4)) + { + //Other CodeView, no structures available + info.set_advanced_info_type(debug_info::advanced_info_codeview); + } + } + + break; + + case image_debug_type_misc: + { + //Check data length + if(debug_data.length() < sizeof(image_debug_misc)) + throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); + + //Get misc structure pointer + const image_debug_misc* misc_data = reinterpret_cast(debug_data.data()); + + //Check misc data length + if(debug_data.length() < misc_data->Length /* Total length of record */) + throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); + + //Save advanced information + info.set_advanced_debug_info(misc_debug_info(misc_data)); + } + break; + } + } + + //Save debug information structure + ret.push_back(info); + + //Check possible overflow + if(!pe_utils::is_sum_safe(current_pos, sizeof(image_debug_directory))) + throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); + + //Go to next debug entry + current_pos += sizeof(image_debug_directory); + directory = pe.section_data_from_rva(current_pos, section_data_virtual, true); + } + + return ret; +} +} diff --git a/drivers/pe_bliss/pe_debug.h b/drivers/pe_bliss/pe_debug.h new file mode 100644 index 0000000000..13fef663c3 --- /dev/null +++ b/drivers/pe_bliss/pe_debug.h @@ -0,0 +1,303 @@ +#pragma once +#include +#include "pe_structures.h" +#include "pe_base.h" + +namespace pe_bliss +{ +//Class representing advanced RSDS (PDB 7.0) information +class pdb_7_0_info +{ +public: + //Default constructor + pdb_7_0_info(); + //Constructor from data + explicit pdb_7_0_info(const pe_win::CV_INFO_PDB70* info); + + //Returns debug PDB 7.0 structure GUID + const pe_win::guid get_guid() const; + //Returns age of build + uint32_t get_age() const; + //Returns PDB file name / path + const std::string& get_pdb_file_name() const; + +private: + uint32_t age_; + pe_win::guid guid_; + std::string pdb_file_name_; +}; + +//Class representing advanced NB10 (PDB 2.0) information +class pdb_2_0_info +{ +public: + //Default constructor + pdb_2_0_info(); + //Constructor from data + explicit pdb_2_0_info(const pe_win::CV_INFO_PDB20* info); + + //Returns debug PDB 2.0 structure signature + uint32_t get_signature() const; + //Returns age of build + uint32_t get_age() const; + //Returns PDB file name / path + const std::string& get_pdb_file_name() const; + +private: + uint32_t age_; + uint32_t signature_; + std::string pdb_file_name_; +}; + +//Class representing advanced misc (IMAGE_DEBUG_TYPE_MISC) info +class misc_debug_info +{ +public: + //Default constructor + misc_debug_info(); + //Constructor from data + explicit misc_debug_info(const pe_win::image_debug_misc* info); + + //Returns debug data type + uint32_t get_data_type() const; + //Returns true if data type is exe name + bool is_exe_name() const; + + //Returns true if debug data is UNICODE + bool is_unicode() const; + //Returns debug data (ANSI or UNICODE) + const std::string& get_data_ansi() const; + const std::wstring& get_data_unicode() const; + +private: + uint32_t data_type_; + bool unicode_; + std::string debug_data_ansi_; + std::wstring debug_data_unicode_; +}; + +//Class representing COFF (IMAGE_DEBUG_TYPE_COFF) debug info +class coff_debug_info +{ +public: + //Structure representing COFF symbol + struct coff_symbol + { + public: + //Default constructor + coff_symbol(); + + //Returns storage class + uint32_t get_storage_class() const; + //Returns symbol index + uint32_t get_index() const; + //Returns section number + uint32_t get_section_number() const; + //Returns RVA + uint32_t get_rva() const; + //Returns type + uint16_t get_type() const; + + //Returns true if structure contains file name + bool is_file() const; + //Returns text data (symbol or file name) + const std::string& get_symbol() const; + + public: //These functions do not change everything inside image, they are used by PE class + //Sets storage class + void set_storage_class(uint32_t storage_class); + //Sets symbol index + void set_index(uint32_t index); + //Sets section number + void set_section_number(uint32_t section_number); + //Sets RVA + void set_rva(uint32_t rva); + //Sets type + void set_type(uint16_t type); + + //Sets file name + void set_file_name(const std::string& file_name); + //Sets symbol name + void set_symbol_name(const std::string& symbol_name); + + private: + uint32_t storage_class_; + uint32_t index_; + uint32_t section_number_, rva_; + uint16_t type_; + bool is_filename_; + std::string name_; + }; + +public: + typedef std::vector coff_symbols_list; + +public: + //Default constructor + coff_debug_info(); + //Constructor from data + explicit coff_debug_info(const pe_win::image_coff_symbols_header* info); + + //Returns number of symbols + uint32_t get_number_of_symbols() const; + //Returns virtual address of the first symbol + uint32_t get_lva_to_first_symbol() const; + //Returns number of line-number entries + uint32_t get_number_of_line_numbers() const; + //Returns virtual address of the first line-number entry + uint32_t get_lva_to_first_line_number() const; + //Returns relative virtual address of the first byte of code + uint32_t get_rva_to_first_byte_of_code() const; + //Returns relative virtual address of the last byte of code + uint32_t get_rva_to_last_byte_of_code() const; + //Returns relative virtual address of the first byte of data + uint32_t get_rva_to_first_byte_of_data() const; + //Returns relative virtual address of the last byte of data + uint32_t get_rva_to_last_byte_of_data() const; + + //Returns COFF symbols list + const coff_symbols_list& get_symbols() const; + +public: //These functions do not change everything inside image, they are used by PE class + //Adds COFF symbol + void add_symbol(const coff_symbol& sym); + +private: + uint32_t number_of_symbols_; + uint32_t lva_to_first_symbol_; + uint32_t number_of_line_numbers_; + uint32_t lva_to_first_line_number_; + uint32_t rva_to_first_byte_of_code_; + uint32_t rva_to_last_byte_of_code_; + uint32_t rva_to_first_byte_of_data_; + uint32_t rva_to_last_byte_of_data_; + +private: + coff_symbols_list symbols_; +}; + +//Class representing debug information +class debug_info +{ +public: + //Enumeration of debug information types + enum debug_info_type + { + debug_type_unknown, + debug_type_coff, + debug_type_codeview, + debug_type_fpo, + debug_type_misc, + debug_type_exception, + debug_type_fixup, + debug_type_omap_to_src, + debug_type_omap_from_src, + debug_type_borland, + debug_type_reserved10, + debug_type_clsid + }; + +public: + //Enumeration of advanced debug information types + enum advanced_info_type + { + advanced_info_none, //No advanced info + advanced_info_pdb_7_0, //PDB 7.0 + advanced_info_pdb_2_0, //PDB 2.0 + advanced_info_misc, //MISC debug info + advanced_info_coff, //COFF debug info + //No advanced info structures available for types below + advanced_info_codeview_4_0, //CodeView 4.0 + advanced_info_codeview_5_0, //CodeView 5.0 + advanced_info_codeview //CodeView + }; + +public: + //Default constructor + debug_info(); + //Constructor from data + explicit debug_info(const pe_win::image_debug_directory& debug); + //Copy constructor + debug_info(const debug_info& info); + //Copy assignment operator + debug_info& operator=(const debug_info& info); + //Destructor + ~debug_info(); + + //Returns debug characteristics + uint32_t get_characteristics() const; + //Returns debug datetimestamp + uint32_t get_time_stamp() const; + //Returns major version + uint32_t get_major_version() const; + //Returns minor version + uint32_t get_minor_version() const; + //Returns type of debug info (unchecked) + uint32_t get_type_raw() const; + //Returns type of debug info from debug_info_type enumeration + debug_info_type get_type() const; + //Returns size of debug data (internal, .pdb or other file doesn't count) + uint32_t get_size_of_data() const; + //Returns RVA of debug info when mapped to memory or zero, if info is not mapped + uint32_t get_rva_of_raw_data() const; + //Returns raw file pointer to raw data + uint32_t get_pointer_to_raw_data() const; + + //Returns advanced debug information type + advanced_info_type get_advanced_info_type() const; + //Returns advanced debug information or throws an exception, + //if requested information type is not contained by structure + template + const AdvancedInfo get_advanced_debug_info() const; + +public: //These functions do not change everything inside image, they are used by PE class + //Sets advanced debug information + void set_advanced_debug_info(const pdb_7_0_info& info); + void set_advanced_debug_info(const pdb_2_0_info& info); + void set_advanced_debug_info(const misc_debug_info& info); + void set_advanced_debug_info(const coff_debug_info& info); + + //Sets advanced debug information type, if no advanced info structure available + void set_advanced_info_type(advanced_info_type type); + +private: + uint32_t characteristics_; + uint32_t time_stamp_; + uint32_t major_version_, minor_version_; + uint32_t type_; + uint32_t size_of_data_; + uint32_t address_of_raw_data_; //RVA when mapped or 0 + uint32_t pointer_to_raw_data_; //RAW file offset + + //Union containing advanced debug information pointer + union advanced_info + { + public: + //Default constructor + advanced_info(); + + //Returns true if advanced debug info is present + bool is_present() const; + + public: + pdb_7_0_info* adv_pdb_7_0_info; + pdb_2_0_info* adv_pdb_2_0_info; + misc_debug_info* adv_misc_info; + coff_debug_info* adv_coff_info; + }; + + //Helper for advanced debug information copying + void copy_advanced_info(const debug_info& info); + //Helper for clearing any present advanced debug information + void free_present_advanced_info(); + + advanced_info advanced_debug_info_; + //Advanced information type + advanced_info_type advanced_info_type_; +}; + +typedef std::vector debug_info_list; + +//Returns debug information list +const debug_info_list get_debug_information(const pe_base& pe); +} diff --git a/drivers/pe_bliss/pe_directory.cpp b/drivers/pe_bliss/pe_directory.cpp new file mode 100644 index 0000000000..57ea2212a6 --- /dev/null +++ b/drivers/pe_bliss/pe_directory.cpp @@ -0,0 +1,38 @@ +#include "pe_directory.h" + +namespace pe_bliss +{ +//Default constructor +image_directory::image_directory() + :rva_(0), size_(0) +{} + +//Constructor from data +image_directory::image_directory(uint32_t rva, uint32_t size) + :rva_(rva), size_(size) +{} + +//Returns RVA +uint32_t image_directory::get_rva() const +{ + return rva_; +} + +//Returns size +uint32_t image_directory::get_size() const +{ + return size_; +} + +//Sets RVA +void image_directory::set_rva(uint32_t rva) +{ + rva_ = rva; +} + +//Sets size +void image_directory::set_size(uint32_t size) +{ + size_ = size; +} +} diff --git a/drivers/pe_bliss/pe_directory.h b/drivers/pe_bliss/pe_directory.h new file mode 100644 index 0000000000..77567f9488 --- /dev/null +++ b/drivers/pe_bliss/pe_directory.h @@ -0,0 +1,29 @@ +#pragma once +#include "stdint_defs.h" + +namespace pe_bliss +{ +//Class representing image directory data +class image_directory +{ +public: + //Default constructor + image_directory(); + //Constructor from data + image_directory(uint32_t rva, uint32_t size); + + //Returns RVA + uint32_t get_rva() const; + //Returns size + uint32_t get_size() const; + + //Sets RVA + void set_rva(uint32_t rva); + //Sets size + void set_size(uint32_t size); + +private: + uint32_t rva_; + uint32_t size_; +}; +} diff --git a/drivers/pe_bliss/pe_dotnet.cpp b/drivers/pe_bliss/pe_dotnet.cpp new file mode 100644 index 0000000000..5d9e483e3f --- /dev/null +++ b/drivers/pe_bliss/pe_dotnet.cpp @@ -0,0 +1,165 @@ +#include +#include "pe_dotnet.h" + +namespace pe_bliss +{ +using namespace pe_win; + +//.NET +basic_dotnet_info::basic_dotnet_info() +{ + memset(&header_, 0, sizeof(header_)); +} + +//Constructor from data +basic_dotnet_info::basic_dotnet_info(const image_cor20_header& header) + :header_(header) +{} + +//Returns major runtime version +uint16_t basic_dotnet_info::get_major_runtime_version() const +{ + return header_.MajorRuntimeVersion; +} + +//Returns minor runtime version +uint16_t basic_dotnet_info::get_minor_runtime_version() const +{ + return header_.MinorRuntimeVersion; +} + +//Returns RVA of metadata (symbol table and startup information) +uint32_t basic_dotnet_info::get_rva_of_metadata() const +{ + return header_.MetaData.VirtualAddress; +} + +//Returns size of metadata (symbol table and startup information) +uint32_t basic_dotnet_info::get_size_of_metadata() const +{ + return header_.MetaData.Size; +} + +//Returns flags +uint32_t basic_dotnet_info::get_flags() const +{ + return header_.Flags; +} + +//Returns true if entry point is native +bool basic_dotnet_info::is_native_entry_point() const +{ + return (header_.Flags & comimage_flags_native_entrypoint) ? true : false; +} + +//Returns true if 32 bit required +bool basic_dotnet_info::is_32bit_required() const +{ + return (header_.Flags & comimage_flags_32bitrequired) ? true : false; +} + +//Returns true if image is IL library +bool basic_dotnet_info::is_il_library() const +{ + return (header_.Flags & comimage_flags_il_library) ? true : false; +} + +//Returns true if image uses IL only +bool basic_dotnet_info::is_il_only() const +{ + return (header_.Flags & comimage_flags_ilonly) ? true : false; +} + +//Returns entry point RVA (if entry point is native) +//Returns entry point managed token (if entry point is managed) +uint32_t basic_dotnet_info::get_entry_point_rva_or_token() const +{ + return header_.EntryPointToken; +} + +//Returns RVA of managed resources +uint32_t basic_dotnet_info::get_rva_of_resources() const +{ + return header_.Resources.VirtualAddress; +} + +//Returns size of managed resources +uint32_t basic_dotnet_info::get_size_of_resources() const +{ + return header_.Resources.Size; +} + +//Returns RVA of strong name signature +uint32_t basic_dotnet_info::get_rva_of_strong_name_signature() const +{ + return header_.StrongNameSignature.VirtualAddress; +} + +//Returns size of strong name signature +uint32_t basic_dotnet_info::get_size_of_strong_name_signature() const +{ + return header_.StrongNameSignature.Size; +} + +//Returns RVA of code manager table +uint32_t basic_dotnet_info::get_rva_of_code_manager_table() const +{ + return header_.CodeManagerTable.VirtualAddress; +} + +//Returns size of code manager table +uint32_t basic_dotnet_info::get_size_of_code_manager_table() const +{ + return header_.CodeManagerTable.Size; +} + +//Returns RVA of VTable fixups +uint32_t basic_dotnet_info::get_rva_of_vtable_fixups() const +{ + return header_.VTableFixups.VirtualAddress; +} + +//Returns size of VTable fixups +uint32_t basic_dotnet_info::get_size_of_vtable_fixups() const +{ + return header_.VTableFixups.Size; +} + +//Returns RVA of export address table jumps +uint32_t basic_dotnet_info::get_rva_of_export_address_table_jumps() const +{ + return header_.ExportAddressTableJumps.VirtualAddress; +} + +//Returns size of export address table jumps +uint32_t basic_dotnet_info::get_size_of_export_address_table_jumps() const +{ + return header_.ExportAddressTableJumps.Size; +} + +//Returns RVA of managed native header +//(precompiled header info, usually set to zero, for internal use) +uint32_t basic_dotnet_info::get_rva_of_managed_native_header() const +{ + return header_.ManagedNativeHeader.VirtualAddress; +} + +//Returns size of managed native header +//(precompiled header info, usually set to zero, for internal use) +uint32_t basic_dotnet_info::get_size_of_managed_native_header() const +{ + return header_.ManagedNativeHeader.Size; +} + +//Returns basic .NET information +//If image is not native, throws an exception +const basic_dotnet_info get_basic_dotnet_info(const pe_base& pe) +{ + //If there's no debug directory, return empty list + if(!pe.is_dotnet()) + throw pe_exception("Image does not have managed code", pe_exception::image_does_not_have_managed_code); + + //Return basic .NET information + return basic_dotnet_info(pe.section_data_from_rva(pe.get_directory_rva(image_directory_entry_com_descriptor), section_data_virtual, true)); +} +} diff --git a/drivers/pe_bliss/pe_dotnet.h b/drivers/pe_bliss/pe_dotnet.h new file mode 100644 index 0000000000..e0dad3a721 --- /dev/null +++ b/drivers/pe_bliss/pe_dotnet.h @@ -0,0 +1,76 @@ +#pragma once +#include "pe_structures.h" +#include "pe_base.h" + +namespace pe_bliss +{ +//Class representing basic .NET header information +class basic_dotnet_info +{ +public: + //Default constructor + basic_dotnet_info(); + //Constructor from data + explicit basic_dotnet_info(const pe_win::image_cor20_header& header); + + //Returns major runtime version + uint16_t get_major_runtime_version() const; + //Returns minor runtime version + uint16_t get_minor_runtime_version() const; + + //Returns RVA of metadata (symbol table and startup information) + uint32_t get_rva_of_metadata() const; + //Returns size of metadata (symbol table and startup information) + uint32_t get_size_of_metadata() const; + + //Returns flags + uint32_t get_flags() const; + + //Returns true if entry point is native + bool is_native_entry_point() const; + //Returns true if 32 bit required + bool is_32bit_required() const; + //Returns true if image is IL library + bool is_il_library() const; + //Returns true if image uses IL only + bool is_il_only() const; + + //Returns entry point RVA (if entry point is native) + //Returns entry point managed token (if entry point is managed) + uint32_t get_entry_point_rva_or_token() const; + + //Returns RVA of managed resources + uint32_t get_rva_of_resources() const; + //Returns size of managed resources + uint32_t get_size_of_resources() const; + //Returns RVA of strong name signature + uint32_t get_rva_of_strong_name_signature() const; + //Returns size of strong name signature + uint32_t get_size_of_strong_name_signature() const; + //Returns RVA of code manager table + uint32_t get_rva_of_code_manager_table() const; + //Returns size of code manager table + uint32_t get_size_of_code_manager_table() const; + //Returns RVA of VTable fixups + uint32_t get_rva_of_vtable_fixups() const; + //Returns size of VTable fixups + uint32_t get_size_of_vtable_fixups() const; + //Returns RVA of export address table jumps + uint32_t get_rva_of_export_address_table_jumps() const; + //Returns size of export address table jumps + uint32_t get_size_of_export_address_table_jumps() const; + //Returns RVA of managed native header + //(precompiled header info, usually set to zero, for internal use) + uint32_t get_rva_of_managed_native_header() const; + //Returns size of managed native header + //(precompiled header info, usually set to zero, for internal use) + uint32_t get_size_of_managed_native_header() const; + +private: + pe_win::image_cor20_header header_; +}; + +//Returns basic .NET information +//If image is not native, throws an exception +const basic_dotnet_info get_basic_dotnet_info(const pe_base& pe); +} diff --git a/drivers/pe_bliss/pe_exception.cpp b/drivers/pe_bliss/pe_exception.cpp new file mode 100644 index 0000000000..eb76f28a35 --- /dev/null +++ b/drivers/pe_bliss/pe_exception.cpp @@ -0,0 +1,19 @@ +#include "pe_exception.h" + +namespace pe_bliss +{ +//PE exception class constructors +pe_exception::pe_exception(const char* text, exception_id id) + :std::runtime_error(text), id_(id) +{} + +pe_exception::pe_exception(const std::string& text, exception_id id) + :std::runtime_error(text), id_(id) +{} + +//Returns exception ID +pe_exception::exception_id pe_exception::get_id() const +{ + return id_; +} +} diff --git a/drivers/pe_bliss/pe_exception.h b/drivers/pe_bliss/pe_exception.h new file mode 100644 index 0000000000..a51eba7d73 --- /dev/null +++ b/drivers/pe_bliss/pe_exception.h @@ -0,0 +1,109 @@ +#pragma once +#include +#include + +namespace pe_bliss +{ +//PE exception class +class pe_exception : public std::runtime_error +{ +public: + //Exception IDs + enum exception_id + { + unknown_error, + bad_pe_file, + bad_dos_header, + image_nt_headers_not_found, + error_reading_image_nt_headers, + error_reading_data_directories, + error_reading_file, + pe_signature_incorrect, + incorrect_number_of_rva_and_sizes, + error_changing_section_virtual_size, + section_number_incorrect, + section_table_incorrect, + incorrect_section_alignment, + incorrect_file_alignment, + incorrect_size_of_image, + incorrect_size_of_headers, + image_section_headers_not_found, + zero_section_sizes, + section_incorrect_addr_or_size, + section_not_found, + image_section_data_not_found, + no_section_found, + image_section_table_incorrect, + directory_does_not_exist, + rva_not_exists, + error_reading_section_header, + error_reading_overlay, + incorrect_address_conversion, + + incorrect_export_directory, + incorrect_import_directory, + incorrect_relocation_directory, + incorrect_tls_directory, + incorrect_config_directory, + incorrect_bound_import_directory, + incorrect_resource_directory, + incorrect_exception_directory, + incorrect_debug_directory, + + resource_directory_entry_error, + resource_directory_entry_not_found, + resource_data_entry_not_found, + resource_incorrect_bitmap, + resource_incorrect_icon, + resource_incorrect_cursor, + resource_incorrect_string_table, + resource_string_not_found, + resource_incorrect_message_table, + resource_incorrect_version_info, + + advanced_debug_information_request_error, + image_does_not_have_managed_code, + + section_is_empty, + data_is_empty, + stream_is_bad, + + section_is_not_attached, + insufficient_space, + + cannot_rebase_relocations, + + exports_list_is_empty, + duplicate_exported_function_ordinal, + duplicate_exported_function_name, + + version_info_string_does_not_exist, + + no_more_sections_can_be_added, + + no_icon_group_found, + no_cursor_group_found, + + encoding_convertion_error, + + error_expanding_section, + + cannot_rebuild_image + }; + +public: + //Class constructors + explicit pe_exception(const char* text, exception_id id = unknown_error); + explicit pe_exception(const std::string& text, exception_id id = unknown_error); + + //Returns exception ID from exception_id enumeration + exception_id get_id() const; + + //Destructor + virtual ~pe_exception() throw() + {} + +private: + exception_id id_; +}; +} diff --git a/drivers/pe_bliss/pe_exception_directory.cpp b/drivers/pe_bliss/pe_exception_directory.cpp new file mode 100644 index 0000000000..3447e5bd7a --- /dev/null +++ b/drivers/pe_bliss/pe_exception_directory.cpp @@ -0,0 +1,156 @@ +#include "pe_exception_directory.h" + +namespace pe_bliss +{ +using namespace pe_win; + +//EXCEPTION DIRECTORY (exists on PE+ only) +//Default constructor +exception_entry::exception_entry() + :begin_address_(0), end_address_(0), unwind_info_address_(0), + unwind_info_version_(0), + flags_(0), + size_of_prolog_(0), + count_of_codes_(0), + frame_register_(0), + frame_offset_(0) +{} + +//Constructor from data +exception_entry::exception_entry(const image_runtime_function_entry& entry, const unwind_info& unwind_info) + :begin_address_(entry.BeginAddress), end_address_(entry.EndAddress), unwind_info_address_(entry.UnwindInfoAddress), + unwind_info_version_(unwind_info.Version), + flags_(unwind_info.Flags), + size_of_prolog_(unwind_info.SizeOfProlog), + count_of_codes_(unwind_info.CountOfCodes), + frame_register_(unwind_info.FrameRegister), + frame_offset_(unwind_info.FrameOffset) +{} + +//Returns starting address of function, affected by exception unwinding +uint32_t exception_entry::get_begin_address() const +{ + return begin_address_; +} + +//Returns ending address of function, affected by exception unwinding +uint32_t exception_entry::get_end_address() const +{ + return end_address_; +} + +//Returns unwind info address +uint32_t exception_entry::get_unwind_info_address() const +{ + return unwind_info_address_; +} + +//Returns UNWIND_INFO structure version +uint8_t exception_entry::get_unwind_info_version() const +{ + return unwind_info_version_; +} + +//Returns unwind info flags +uint8_t exception_entry::get_flags() const +{ + return flags_; +} + +//The function has an exception handler that should be called +//when looking for functions that need to examine exceptions +bool exception_entry::has_exception_handler() const +{ + return (flags_ & unw_flag_ehandler) ? true : false; +} + +//The function has a termination handler that should be called +//when unwinding an exception +bool exception_entry::has_termination_handler() const +{ + return (flags_ & unw_flag_uhandler) ? true : false; +} + +//The unwind info structure is not the primary one for the procedure +bool exception_entry::is_chaininfo() const +{ + return (flags_ & unw_flag_chaininfo) ? true : false; +} + +//Returns size of function prolog +uint8_t exception_entry::get_size_of_prolog() const +{ + return size_of_prolog_; +} + +//Returns number of unwind slots +uint8_t exception_entry::get_number_of_unwind_slots() const +{ + return count_of_codes_; +} + +//If the function uses frame pointer +bool exception_entry::uses_frame_pointer() const +{ + return frame_register_ != 0; +} + +//Number of the nonvolatile register used as the frame pointer, +//using the same encoding for the operation info field of UNWIND_CODE nodes +uint8_t exception_entry::get_frame_pointer_register_number() const +{ + return frame_register_; +} + +//The scaled offset from RSP that is applied to the FP reg when it is established. +//The actual FP reg is set to RSP + 16 * this number, allowing offsets from 0 to 240 +uint8_t exception_entry::get_scaled_rsp_offset() const +{ + return frame_offset_; +} + +//Returns exception directory data (exists on PE+ only) +//Unwind opcodes are not listed, because their format and list are subject to change +const exception_entry_list get_exception_directory_data(const pe_base& pe) +{ + exception_entry_list ret; + + //If image doesn't have exception directory, return empty list + if(!pe.has_exception_directory()) + return ret; + + //Check the length in bytes of the section containing exception directory + if(pe.section_data_length_from_rva(pe.get_directory_rva(image_directory_entry_exception), pe.get_directory_rva(image_directory_entry_exception), section_data_virtual, true) + < sizeof(image_runtime_function_entry)) + throw pe_exception("Incorrect exception directory", pe_exception::incorrect_exception_directory); + + unsigned long current_pos = pe.get_directory_rva(image_directory_entry_exception); + + //Check if structures are DWORD-aligned + if(current_pos % sizeof(uint32_t)) + throw pe_exception("Incorrect exception directory", pe_exception::incorrect_exception_directory); + + //First IMAGE_RUNTIME_FUNCTION_ENTRY table + image_runtime_function_entry exception_table = pe.section_data_from_rva(current_pos, section_data_virtual, true); + + //todo: virtual addresses BeginAddress and EndAddress are not checked to be inside image + while(exception_table.BeginAddress) + { + //Check addresses + if(exception_table.BeginAddress > exception_table.EndAddress) + throw pe_exception("Incorrect exception directory", pe_exception::incorrect_exception_directory); + + //Get unwind information + unwind_info info = pe.section_data_from_rva(exception_table.UnwindInfoAddress, section_data_virtual, true); + + //Create exception entry and save it + ret.push_back(exception_entry(exception_table, info)); + + //Go to next exception entry + current_pos += sizeof(image_runtime_function_entry); + exception_table = pe.section_data_from_rva(current_pos, section_data_virtual, true); + } + + return ret; +} +} diff --git a/drivers/pe_bliss/pe_exception_directory.h b/drivers/pe_bliss/pe_exception_directory.h new file mode 100644 index 0000000000..9f9ee14cae --- /dev/null +++ b/drivers/pe_bliss/pe_exception_directory.h @@ -0,0 +1,67 @@ +#pragma once +#include +#include "pe_structures.h" +#include "pe_base.h" + +namespace pe_bliss +{ +//Class representing exception directory entry +class exception_entry +{ +public: + //Default constructor + exception_entry(); + //Constructor from data + exception_entry(const pe_win::image_runtime_function_entry& entry, const pe_win::unwind_info& unwind_info); + + //Returns starting address of function, affected by exception unwinding + uint32_t get_begin_address() const; + //Returns ending address of function, affected by exception unwinding + uint32_t get_end_address() const; + //Returns unwind info address + uint32_t get_unwind_info_address() const; + + //Returns UNWIND_INFO structure version + uint8_t get_unwind_info_version() const; + + //Returns unwind info flags + uint8_t get_flags() const; + //The function has an exception handler that should be called + //when looking for functions that need to examine exceptions + bool has_exception_handler() const; + //The function has a termination handler that should be called + //when unwinding an exception + bool has_termination_handler() const; + //The unwind info structure is not the primary one for the procedure + bool is_chaininfo() const; + + //Returns size of function prolog + uint8_t get_size_of_prolog() const; + + //Returns number of unwind slots + uint8_t get_number_of_unwind_slots() const; + + //If the function uses frame pointer + bool uses_frame_pointer() const; + //Number of the nonvolatile register used as the frame pointer, + //using the same encoding for the operation info field of UNWIND_CODE nodes + uint8_t get_frame_pointer_register_number() const; + //The scaled offset from RSP that is applied to the FP reg when it is established. + //The actual FP reg is set to RSP + 16 * this number, allowing offsets from 0 to 240 + uint8_t get_scaled_rsp_offset() const; + +private: + uint32_t begin_address_, end_address_, unwind_info_address_; + uint8_t unwind_info_version_; + uint8_t flags_; + uint8_t size_of_prolog_; + uint8_t count_of_codes_; + uint8_t frame_register_, frame_offset_; +}; + +typedef std::vector exception_entry_list; + +//Returns exception directory data (exists on PE+ only) +//Unwind opcodes are not listed, because their format and list are subject to change +const exception_entry_list get_exception_directory_data(const pe_base& pe); +} diff --git a/drivers/pe_bliss/pe_exports.cpp b/drivers/pe_bliss/pe_exports.cpp new file mode 100644 index 0000000000..4a1bc1d82f --- /dev/null +++ b/drivers/pe_bliss/pe_exports.cpp @@ -0,0 +1,679 @@ +#include +#include +#include +#include "pe_exports.h" +#include "utils.h" + +namespace pe_bliss +{ +using namespace pe_win; + +//EXPORTS +//Default constructor +exported_function::exported_function() + :ordinal_(0), rva_(0), has_name_(false), name_ordinal_(0), forward_(false) +{} + +//Returns ordinal of function (actually, ordinal = hint + ordinal base) +uint16_t exported_function::get_ordinal() const +{ + return ordinal_; +} + +//Returns RVA of function +uint32_t exported_function::get_rva() const +{ + return rva_; +} + +//Returns name of function +const std::string& exported_function::get_name() const +{ + return name_; +} + +//Returns true if function has name and name ordinal +bool exported_function::has_name() const +{ + return has_name_; +} + +//Returns name ordinal of function +uint16_t exported_function::get_name_ordinal() const +{ + return name_ordinal_; +} + +//Returns true if function is forwarded to other library +bool exported_function::is_forwarded() const +{ + return forward_; +} + +//Returns the name of forwarded function +const std::string& exported_function::get_forwarded_name() const +{ + return forward_name_; +} + +//Sets ordinal of function +void exported_function::set_ordinal(uint16_t ordinal) +{ + ordinal_ = ordinal; +} + +//Sets RVA of function +void exported_function::set_rva(uint32_t rva) +{ + rva_ = rva; +} + +//Sets name of function (or clears it, if empty name is passed) +void exported_function::set_name(const std::string& name) +{ + name_ = name; + has_name_ = !name.empty(); +} + +//Sets name ordinal +void exported_function::set_name_ordinal(uint16_t name_ordinal) +{ + name_ordinal_ = name_ordinal; +} + +//Sets forwarded function name (or clears it, if empty name is passed) +void exported_function::set_forwarded_name(const std::string& name) +{ + forward_name_ = name; + forward_ = !name.empty(); +} + +//Default constructor +export_info::export_info() + :characteristics_(0), + timestamp_(0), + major_version_(0), + minor_version_(0), + ordinal_base_(0), + number_of_functions_(0), + number_of_names_(0), + address_of_functions_(0), + address_of_names_(0), + address_of_name_ordinals_(0) +{} + +//Returns characteristics +uint32_t export_info::get_characteristics() const +{ + return characteristics_; +} + +//Returns timestamp +uint32_t export_info::get_timestamp() const +{ + return timestamp_; +} + +//Returns major version +uint16_t export_info::get_major_version() const +{ + return major_version_; +} + +//Returns minor version +uint16_t export_info::get_minor_version() const +{ + return minor_version_; +} + +//Returns DLL name +const std::string& export_info::get_name() const +{ + return name_; +} + +//Returns ordinal base +uint32_t export_info::get_ordinal_base() const +{ + return ordinal_base_; +} + +//Returns number of functions +uint32_t export_info::get_number_of_functions() const +{ + return number_of_functions_; +} + +//Returns number of function names +uint32_t export_info::get_number_of_names() const +{ + return number_of_names_; +} + +//Returns RVA of function address table +uint32_t export_info::get_rva_of_functions() const +{ + return address_of_functions_; +} + +//Returns RVA of function name address table +uint32_t export_info::get_rva_of_names() const +{ + return address_of_names_; +} + +//Returns RVA of name ordinals table +uint32_t export_info::get_rva_of_name_ordinals() const +{ + return address_of_name_ordinals_; +} + +//Sets characteristics +void export_info::set_characteristics(uint32_t characteristics) +{ + characteristics_ = characteristics; +} + +//Sets timestamp +void export_info::set_timestamp(uint32_t timestamp) +{ + timestamp_ = timestamp; +} + +//Sets major version +void export_info::set_major_version(uint16_t major_version) +{ + major_version_ = major_version; +} + +//Sets minor version +void export_info::set_minor_version(uint16_t minor_version) +{ + minor_version_ = minor_version; +} + +//Sets DLL name +void export_info::set_name(const std::string& name) +{ + name_ = name; +} + +//Sets ordinal base +void export_info::set_ordinal_base(uint32_t ordinal_base) +{ + ordinal_base_ = ordinal_base; +} + +//Sets number of functions +void export_info::set_number_of_functions(uint32_t number_of_functions) +{ + number_of_functions_ = number_of_functions; +} + +//Sets number of function names +void export_info::set_number_of_names(uint32_t number_of_names) +{ + number_of_names_ = number_of_names; +} + +//Sets RVA of function address table +void export_info::set_rva_of_functions(uint32_t rva_of_functions) +{ + address_of_functions_ = rva_of_functions; +} + +//Sets RVA of function name address table +void export_info::set_rva_of_names(uint32_t rva_of_names) +{ + address_of_names_ = rva_of_names; +} + +//Sets RVA of name ordinals table +void export_info::set_rva_of_name_ordinals(uint32_t rva_of_name_ordinals) +{ + address_of_name_ordinals_ = rva_of_name_ordinals; +} + +const exported_functions_list get_exported_functions(const pe_base& pe, export_info* info); + +//Returns array of exported functions +const exported_functions_list get_exported_functions(const pe_base& pe) +{ + return get_exported_functions(pe, 0); +} + +//Returns array of exported functions and information about export +const exported_functions_list get_exported_functions(const pe_base& pe, export_info& info) +{ + return get_exported_functions(pe, &info); +} + +//Helper: sorts exported function list by ordinals +struct ordinal_sorter +{ +public: + bool operator()(const exported_function& func1, const exported_function& func2) const; +}; + +//Returns array of exported functions and information about export (if info != 0) +const exported_functions_list get_exported_functions(const pe_base& pe, export_info* info) +{ + //Returned exported functions info array + std::vector ret; + + if(pe.has_exports()) + { + //Check the length in bytes of the section containing export directory + if(pe.section_data_length_from_rva(pe.get_directory_rva(image_directory_entry_export), + pe.get_directory_rva(image_directory_entry_export), section_data_virtual, true) + < sizeof(image_export_directory)) + throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory); + + image_export_directory exports = pe.section_data_from_rva(pe.get_directory_rva(image_directory_entry_export), section_data_virtual, true); + + unsigned long max_name_length; + + if(info) + { + //Save some export info data + info->set_characteristics(exports.Characteristics); + info->set_major_version(exports.MajorVersion); + info->set_minor_version(exports.MinorVersion); + + //Get byte count that we have for dll name + if((max_name_length = pe.section_data_length_from_rva(exports.Name, exports.Name, section_data_virtual, true)) < 2) + throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory); + + //Get dll name pointer + const char* dll_name = pe.section_data_from_rva(exports.Name, section_data_virtual, true); + + //Check for null-termination + if(!pe_utils::is_null_terminated(dll_name, max_name_length)) + throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory); + + //Save the rest of export information data + info->set_name(dll_name); + info->set_number_of_functions(exports.NumberOfFunctions); + info->set_number_of_names(exports.NumberOfNames); + info->set_ordinal_base(exports.Base); + info->set_rva_of_functions(exports.AddressOfFunctions); + info->set_rva_of_names(exports.AddressOfNames); + info->set_rva_of_name_ordinals(exports.AddressOfNameOrdinals); + info->set_timestamp(exports.TimeDateStamp); + } + + if(!exports.NumberOfFunctions) + return ret; + + //Check IMAGE_EXPORT_DIRECTORY fields + if(exports.NumberOfNames > exports.NumberOfFunctions) + throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory); + + //Check some export directory fields + if((!exports.AddressOfNameOrdinals && exports.AddressOfNames) || + (exports.AddressOfNameOrdinals && !exports.AddressOfNames) || + !exports.AddressOfFunctions + || exports.NumberOfFunctions >= pe_utils::max_dword / sizeof(uint32_t) + || exports.NumberOfNames > pe_utils::max_dword / sizeof(uint32_t) + || !pe_utils::is_sum_safe(exports.AddressOfFunctions, exports.NumberOfFunctions * sizeof(uint32_t)) + || !pe_utils::is_sum_safe(exports.AddressOfNames, exports.NumberOfNames * sizeof(uint32_t)) + || !pe_utils::is_sum_safe(exports.AddressOfNameOrdinals, exports.NumberOfFunctions * sizeof(uint32_t)) + || !pe_utils::is_sum_safe(pe.get_directory_rva(image_directory_entry_export), pe.get_directory_size(image_directory_entry_export))) + throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory); + + //Check if it is enough bytes to hold AddressOfFunctions table + if(pe.section_data_length_from_rva(exports.AddressOfFunctions, exports.AddressOfFunctions, section_data_virtual, true) + < exports.NumberOfFunctions * sizeof(uint32_t)) + throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory); + + if(exports.AddressOfNames) + { + //Check if it is enough bytes to hold name and ordinal tables + if(pe.section_data_length_from_rva(exports.AddressOfNameOrdinals, exports.AddressOfNameOrdinals, section_data_virtual, true) + < exports.NumberOfNames * sizeof(uint16_t)) + throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory); + + if(pe.section_data_length_from_rva(exports.AddressOfNames, exports.AddressOfNames, section_data_virtual, true) + < exports.NumberOfNames * sizeof(uint32_t)) + throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory); + } + + for(uint32_t ordinal = 0; ordinal < exports.NumberOfFunctions; ordinal++) + { + //Get function address + //Sum and multiplication are safe (checked above) + uint32_t rva = pe.section_data_from_rva(exports.AddressOfFunctions + ordinal * sizeof(uint32_t), section_data_virtual, true); + + //If we have a skip + if(!rva) + continue; + + exported_function func; + func.set_rva(rva); + + if(!pe_utils::is_sum_safe(exports.Base, ordinal) || exports.Base + ordinal > pe_utils::max_word) + throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory); + + func.set_ordinal(static_cast(ordinal + exports.Base)); + + //Scan for function name ordinal + for(uint32_t i = 0; i < exports.NumberOfNames; i++) + { + uint16_t ordinal2 = pe.section_data_from_rva(exports.AddressOfNameOrdinals + i * sizeof(uint16_t), section_data_virtual, true); + + //If function has name (and name ordinal) + if(ordinal == ordinal2) + { + //Get function name + //Sum and multiplication are safe (checked above) + uint32_t function_name_rva = pe.section_data_from_rva(exports.AddressOfNames + i * sizeof(uint32_t), section_data_virtual, true); + + //Get byte count that we have for function name + if((max_name_length = pe.section_data_length_from_rva(function_name_rva, function_name_rva, section_data_virtual, true)) < 2) + throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory); + + //Get function name pointer + const char* func_name = pe.section_data_from_rva(function_name_rva, section_data_virtual, true); + + //Check for null-termination + if(!pe_utils::is_null_terminated(func_name, max_name_length)) + throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory); + + //Save function info + func.set_name(func_name); + func.set_name_ordinal(ordinal2); + + //If the function is just a redirect, save its name + if(rva >= pe.get_directory_rva(image_directory_entry_export) + sizeof(image_directory_entry_export) && + rva < pe.get_directory_rva(image_directory_entry_export) + pe.get_directory_size(image_directory_entry_export)) + { + if((max_name_length = pe.section_data_length_from_rva(rva, rva, section_data_virtual, true)) < 2) + throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory); + + //Get forwarded function name pointer + const char* forwarded_func_name = pe.section_data_from_rva(rva, section_data_virtual, true); + + //Check for null-termination + if(!pe_utils::is_null_terminated(forwarded_func_name, max_name_length)) + throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory); + + //Set the name of forwarded function + func.set_forwarded_name(forwarded_func_name); + } + + break; + } + } + + //Add function info to output array + ret.push_back(func); + } + } + + return ret; +} + +//Helper export functions +//Returns pair: +const std::pair get_export_ordinal_limits(const exported_functions_list& exports) +{ + if(exports.empty()) + return std::make_pair(0, 0); + + uint16_t max_ordinal = 0; //Maximum ordinal number + uint16_t ordinal_base = pe_utils::max_word; //Minimum ordinal value + for(exported_functions_list::const_iterator it = exports.begin(); it != exports.end(); ++it) + { + const exported_function& func = (*it); + + //Calculate maximum and minimum ordinal numbers + max_ordinal = std::max(max_ordinal, func.get_ordinal()); + ordinal_base = std::min(ordinal_base, func.get_ordinal()); + } + + return std::make_pair(ordinal_base, max_ordinal); +} + +//Checks if exported function name already exists +bool exported_name_exists(const std::string& function_name, const exported_functions_list& exports) +{ + for(exported_functions_list::const_iterator it = exports.begin(); it != exports.end(); ++it) + { + if((*it).has_name() && (*it).get_name() == function_name) + return true; + } + + return false; +} + +//Checks if exported function name already exists +bool exported_ordinal_exists(uint16_t ordinal, const exported_functions_list& exports) +{ + for(exported_functions_list::const_iterator it = exports.begin(); it != exports.end(); ++it) + { + if((*it).get_ordinal() == ordinal) + return true; + } + + return false; +} + +//Helper: sorts exported function list by ordinals +bool ordinal_sorter::operator()(const exported_function& func1, const exported_function& func2) const +{ + return func1.get_ordinal() < func2.get_ordinal(); +} + +//Export directory rebuilder +//info - export information +//exported_functions_list - list of exported functions +//exports_section - section where export directory will be placed (must be attached to PE image) +//offset_from_section_start - offset from exports_section raw data start +//save_to_pe_headers - if true, new export directory information will be saved to PE image headers +//auto_strip_last_section - if true and exports are placed in the last section, it will be automatically stripped +//number_of_functions and number_of_names parameters don't matter in "info" when rebuilding, they're calculated independently +//characteristics, major_version, minor_version, timestamp and name are the only used members of "info" structure +//Returns new export directory information +//exported_functions_list is copied intentionally to be sorted by ordinal values later +//Name ordinals in exported function don't matter, they will be recalculated +const image_directory rebuild_exports(pe_base& pe, const export_info& info, exported_functions_list exports, section& exports_section, uint32_t offset_from_section_start, bool save_to_pe_header, bool auto_strip_last_section) +{ + //Check that exports_section is attached to this PE image + if(!pe.section_attached(exports_section)) + throw pe_exception("Exports section must be attached to PE file", pe_exception::section_is_not_attached); + + //Needed space for strings + uint32_t needed_size_for_strings = static_cast(info.get_name().length() + 1); + uint32_t number_of_names = 0; //Number of named functions + uint32_t max_ordinal = 0; //Maximum ordinal number + uint32_t ordinal_base = static_cast(-1); //Minimum ordinal value + + if(exports.empty()) + ordinal_base = info.get_ordinal_base(); + + uint32_t needed_size_for_function_names = 0; //Needed space for function name strings + uint32_t needed_size_for_function_forwards = 0; //Needed space for function forwards names + + //List all exported functions + //Calculate needed size for function list + { + //Also check that there're no duplicate names and ordinals + std::set used_function_names; + std::set used_function_ordinals; + + for(exported_functions_list::const_iterator it = exports.begin(); it != exports.end(); ++it) + { + const exported_function& func = (*it); + //Calculate maximum and minimum ordinal numbers + max_ordinal = std::max(max_ordinal, func.get_ordinal()); + ordinal_base = std::min(ordinal_base, func.get_ordinal()); + + //Check if ordinal is unique + if(!used_function_ordinals.insert(func.get_ordinal()).second) + throw pe_exception("Duplicate exported function ordinal", pe_exception::duplicate_exported_function_ordinal); + + if(func.has_name()) + { + //If function is named + ++number_of_names; + needed_size_for_function_names += static_cast(func.get_name().length() + 1); + + //Check if it's name and name ordinal are unique + if(!used_function_names.insert(func.get_name()).second) + throw pe_exception("Duplicate exported function name", pe_exception::duplicate_exported_function_name); + } + + //If function is forwarded to another DLL + if(func.is_forwarded()) + needed_size_for_function_forwards += static_cast(func.get_forwarded_name().length() + 1); + } + } + + //Sort functions by ordinal value + std::sort(exports.begin(), exports.end(), ordinal_sorter()); + + //Calculate needed space for different things... + needed_size_for_strings += needed_size_for_function_names; + needed_size_for_strings += needed_size_for_function_forwards; + uint32_t needed_size_for_function_name_ordinals = number_of_names * sizeof(uint16_t); + uint32_t needed_size_for_function_name_rvas = number_of_names * sizeof(uint32_t); + uint32_t needed_size_for_function_addresses = (max_ordinal - ordinal_base + 1) * sizeof(uint32_t); + + //Export directory header will be placed first + uint32_t directory_pos = pe_utils::align_up(offset_from_section_start, sizeof(uint32_t)); + + uint32_t needed_size = sizeof(image_export_directory); //Calculate needed size for export tables and strings + //sizeof(IMAGE_EXPORT_DIRECTORY) = export directory header + + //Total needed space... + needed_size += needed_size_for_function_name_ordinals; //For list of names ordinals + needed_size += needed_size_for_function_addresses; //For function RVAs + needed_size += needed_size_for_strings; //For all strings + needed_size += needed_size_for_function_name_rvas; //For function name strings RVAs + + //Check if exports_section is last one. If it's not, check if there's enough place for exports data + if(&exports_section != &*(pe.get_image_sections().end() - 1) && + (exports_section.empty() || pe_utils::align_up(exports_section.get_size_of_raw_data(), pe.get_file_alignment()) < needed_size + directory_pos)) + throw pe_exception("Insufficient space for export directory", pe_exception::insufficient_space); + + std::string& raw_data = exports_section.get_raw_data(); + + //This will be done only if exports_section is the last section of image or for section with unaligned raw length of data + if(raw_data.length() < needed_size + directory_pos) + raw_data.resize(needed_size + directory_pos); //Expand section raw data + + //Library name will be placed after it + uint32_t current_pos_of_function_names = static_cast(info.get_name().length() + 1 + directory_pos + sizeof(image_export_directory)); + //Next - function names + uint32_t current_pos_of_function_name_ordinals = current_pos_of_function_names + needed_size_for_function_names; + //Next - function name ordinals + uint32_t current_pos_of_function_forwards = current_pos_of_function_name_ordinals + needed_size_for_function_name_ordinals; + //Finally - function addresses + uint32_t current_pos_of_function_addresses = current_pos_of_function_forwards + needed_size_for_function_forwards; + //Next - function names RVAs + uint32_t current_pos_of_function_names_rvas = current_pos_of_function_addresses + needed_size_for_function_addresses; + + { + //Create export directory and fill it + image_export_directory dir = {0}; + dir.Characteristics = info.get_characteristics(); + dir.MajorVersion = info.get_major_version(); + dir.MinorVersion = info.get_minor_version(); + dir.TimeDateStamp = info.get_timestamp(); + dir.NumberOfFunctions = max_ordinal - ordinal_base + 1; + dir.NumberOfNames = number_of_names; + dir.Base = ordinal_base; + dir.AddressOfFunctions = pe.rva_from_section_offset(exports_section, current_pos_of_function_addresses); + dir.AddressOfNameOrdinals = pe.rva_from_section_offset(exports_section, current_pos_of_function_name_ordinals); + dir.AddressOfNames = pe.rva_from_section_offset(exports_section, current_pos_of_function_names_rvas); + dir.Name = pe.rva_from_section_offset(exports_section, directory_pos + sizeof(image_export_directory)); + + //Save it + memcpy(&raw_data[directory_pos], &dir, sizeof(dir)); + } + + //Sve library name + memcpy(&raw_data[directory_pos + sizeof(image_export_directory)], info.get_name().c_str(), info.get_name().length() + 1); + + //A map to sort function names alphabetically + typedef std::map funclist; //function name; function name ordinal + funclist funcs; + + uint32_t last_ordinal = ordinal_base; + //Enumerate all exported functions + for(exported_functions_list::const_iterator it = exports.begin(); it != exports.end(); ++it) + { + const exported_function& func = (*it); + + //If we're skipping some ordinals... + if(func.get_ordinal() > last_ordinal) + { + //Fill this function RVAs data with zeros + uint32_t len = sizeof(uint32_t) * (func.get_ordinal() - last_ordinal - 1); + if(len) + { + memset(&raw_data[current_pos_of_function_addresses], 0, len); + current_pos_of_function_addresses += len; + } + + //Save last encountered ordinal + last_ordinal = func.get_ordinal(); + } + + //If function is named, save its name ordinal and name in sorted alphabetically order + if(func.has_name()) + funcs.insert(std::make_pair(func.get_name(), static_cast(func.get_ordinal() - ordinal_base))); //Calculate name ordinal + + //If function is forwarded to another DLL + if(func.is_forwarded()) + { + //Write its forwarded name and its RVA + uint32_t function_rva = pe.rva_from_section_offset(exports_section, current_pos_of_function_forwards); + memcpy(&raw_data[current_pos_of_function_addresses], &function_rva, sizeof(function_rva)); + current_pos_of_function_addresses += sizeof(function_rva); + + memcpy(&raw_data[current_pos_of_function_forwards], func.get_forwarded_name().c_str(), func.get_forwarded_name().length() + 1); + current_pos_of_function_forwards += static_cast(func.get_forwarded_name().length() + 1); + } + else + { + //Write actual function RVA + uint32_t function_rva = func.get_rva(); + memcpy(&raw_data[current_pos_of_function_addresses], &function_rva, sizeof(function_rva)); + current_pos_of_function_addresses += sizeof(function_rva); + } + } + + //Enumerate sorted function names + for(funclist::const_iterator it = funcs.begin(); it != funcs.end(); ++it) + { + //Save function name RVA + uint32_t function_name_rva = pe.rva_from_section_offset(exports_section, current_pos_of_function_names); + memcpy(&raw_data[current_pos_of_function_names_rvas], &function_name_rva, sizeof(function_name_rva)); + current_pos_of_function_names_rvas += sizeof(function_name_rva); + + //Save function name + memcpy(&raw_data[current_pos_of_function_names], (*it).first.c_str(), (*it).first.length() + 1); + current_pos_of_function_names += static_cast((*it).first.length() + 1); + + //Save function name ordinal + uint16_t name_ordinal = (*it).second; + memcpy(&raw_data[current_pos_of_function_name_ordinals], &name_ordinal, sizeof(name_ordinal)); + current_pos_of_function_name_ordinals += sizeof(name_ordinal); + } + + //Adjust section raw and virtual sizes + pe.recalculate_section_sizes(exports_section, auto_strip_last_section); + + image_directory ret(pe.rva_from_section_offset(exports_section, directory_pos), needed_size); + + //If auto-rewrite of PE headers is required + if(save_to_pe_header) + { + pe.set_directory_rva(image_directory_entry_export, ret.get_rva()); + pe.set_directory_size(image_directory_entry_export, ret.get_size()); + } + + return ret; +} +} diff --git a/drivers/pe_bliss/pe_exports.h b/drivers/pe_bliss/pe_exports.h new file mode 100644 index 0000000000..7e2d64813d --- /dev/null +++ b/drivers/pe_bliss/pe_exports.h @@ -0,0 +1,163 @@ +#pragma once +#include +#include +#include "pe_structures.h" +#include "pe_base.h" +#include "pe_directory.h" + +namespace pe_bliss +{ +//Class representing exported function +class exported_function +{ +public: + //Default constructor + exported_function(); + + //Returns ordinal of function (actually, ordinal = hint + ordinal base) + uint16_t get_ordinal() const; + + //Returns RVA of function + uint32_t get_rva() const; + + //Returns true if function has name and name ordinal + bool has_name() const; + //Returns name of function + const std::string& get_name() const; + //Returns name ordinal of function + uint16_t get_name_ordinal() const; + + //Returns true if function is forwarded to other library + bool is_forwarded() const; + //Returns the name of forwarded function + const std::string& get_forwarded_name() const; + +public: //Setters do not change everything inside image, they are used by PE class + //You can also use them to rebuild export directory + + //Sets ordinal of function + void set_ordinal(uint16_t ordinal); + + //Sets RVA of function + void set_rva(uint32_t rva); + + //Sets name of function (or clears it, if empty name is passed) + void set_name(const std::string& name); + //Sets name ordinal + void set_name_ordinal(uint16_t name_ordinal); + + //Sets forwarded function name (or clears it, if empty name is passed) + void set_forwarded_name(const std::string& name); + +private: + uint16_t ordinal_; //Function ordinal + uint32_t rva_; //Function RVA + std::string name_; //Function name + bool has_name_; //true == function has name + uint16_t name_ordinal_; //Function name ordinal + bool forward_; //true == function is forwarded + std::string forward_name_; //Name of forwarded function +}; + +//Class representing export information +class export_info +{ +public: + //Default constructor + export_info(); + + //Returns characteristics + uint32_t get_characteristics() const; + //Returns timestamp + uint32_t get_timestamp() const; + //Returns major version + uint16_t get_major_version() const; + //Returns minor version + uint16_t get_minor_version() const; + //Returns DLL name + const std::string& get_name() const; + //Returns ordinal base + uint32_t get_ordinal_base() const; + //Returns number of functions + uint32_t get_number_of_functions() const; + //Returns number of function names + uint32_t get_number_of_names() const; + //Returns RVA of function address table + uint32_t get_rva_of_functions() const; + //Returns RVA of function name address table + uint32_t get_rva_of_names() const; + //Returns RVA of name ordinals table + uint32_t get_rva_of_name_ordinals() const; + +public: //Setters do not change everything inside image, they are used by PE class + //You can also use them to rebuild export directory using rebuild_exports + + //Sets characteristics + void set_characteristics(uint32_t characteristics); + //Sets timestamp + void set_timestamp(uint32_t timestamp); + //Sets major version + void set_major_version(uint16_t major_version); + //Sets minor version + void set_minor_version(uint16_t minor_version); + //Sets DLL name + void set_name(const std::string& name); + //Sets ordinal base + void set_ordinal_base(uint32_t ordinal_base); + //Sets number of functions + void set_number_of_functions(uint32_t number_of_functions); + //Sets number of function names + void set_number_of_names(uint32_t number_of_names); + //Sets RVA of function address table + void set_rva_of_functions(uint32_t rva_of_functions); + //Sets RVA of function name address table + void set_rva_of_names(uint32_t rva_of_names); + //Sets RVA of name ordinals table + void set_rva_of_name_ordinals(uint32_t rva_of_name_ordinals); + +private: + uint32_t characteristics_; + uint32_t timestamp_; + uint16_t major_version_; + uint16_t minor_version_; + std::string name_; + uint32_t ordinal_base_; + uint32_t number_of_functions_; + uint32_t number_of_names_; + uint32_t address_of_functions_; + uint32_t address_of_names_; + uint32_t address_of_name_ordinals_; +}; + +//Exported functions list typedef +typedef std::vector exported_functions_list; + +//Returns array of exported functions +const exported_functions_list get_exported_functions(const pe_base& pe); +//Returns array of exported functions and information about export +const exported_functions_list get_exported_functions(const pe_base& pe, export_info& info); + +//Helper export functions +//Returns pair: +const std::pair get_export_ordinal_limits(const exported_functions_list& exports); + +//Checks if exported function name already exists +bool exported_name_exists(const std::string& function_name, const exported_functions_list& exports); + +//Checks if exported function ordinal already exists +bool exported_ordinal_exists(uint16_t ordinal, const exported_functions_list& exports); + +//Export directory rebuilder +//info - export information +//exported_functions_list - list of exported functions +//exports_section - section where export directory will be placed (must be attached to PE image) +//offset_from_section_start - offset from exports_section raw data start +//save_to_pe_headers - if true, new export directory information will be saved to PE image headers +//auto_strip_last_section - if true and exports are placed in the last section, it will be automatically stripped +//number_of_functions and number_of_names parameters don't matter in "info" when rebuilding, they're calculated independently +//characteristics, major_version, minor_version, timestamp and name are the only used members of "info" structure +//Returns new export directory information +//exported_functions_list is copied intentionally to be sorted by ordinal values later +//Name ordinals in exported function don't matter, they will be recalculated +const image_directory rebuild_exports(pe_base& pe, const export_info& info, exported_functions_list exports, section& exports_section, uint32_t offset_from_section_start = 0, bool save_to_pe_header = true, bool auto_strip_last_section = true); +} diff --git a/drivers/pe_bliss/pe_factory.cpp b/drivers/pe_bliss/pe_factory.cpp new file mode 100644 index 0000000000..677503ef03 --- /dev/null +++ b/drivers/pe_bliss/pe_factory.cpp @@ -0,0 +1,22 @@ +#include "pe_factory.h" +#include "pe_properties_generic.h" + +namespace pe_bliss +{ +pe_base pe_factory::create_pe(std::istream& file, bool read_debug_raw_data) +{ + return pe_base::get_pe_type(file) == pe_type_32 + ? pe_base(file, pe_properties_32(), read_debug_raw_data) + : pe_base(file, pe_properties_64(), read_debug_raw_data); +} + +pe_base pe_factory::create_pe(const char* file_path, bool read_debug_raw_data) +{ + std::ifstream pe_file(file_path, std::ios::in | std::ios::binary); + if(!pe_file) + { + throw pe_exception("Error in open file.", pe_exception::stream_is_bad); + } + return pe_factory::create_pe(pe_file,read_debug_raw_data); +} +} diff --git a/drivers/pe_bliss/pe_factory.h b/drivers/pe_bliss/pe_factory.h new file mode 100644 index 0000000000..ac0332e5ba --- /dev/null +++ b/drivers/pe_bliss/pe_factory.h @@ -0,0 +1,18 @@ +#pragma once +#include +#include +#include +#include "pe_base.h" + +namespace pe_bliss +{ +class pe_factory +{ +public: + //Creates pe_base class instance from PE or PE+ istream + //If read_bound_import_raw_data, raw bound import data will be read (used to get bound import info) + //If read_debug_raw_data, raw debug data will be read (used to get image debug info) + static pe_base create_pe(std::istream& file, bool read_debug_raw_data = true); + static pe_base create_pe(const char* file_path, bool read_debug_raw_data = true); +}; +} diff --git a/drivers/pe_bliss/pe_imports.cpp b/drivers/pe_bliss/pe_imports.cpp new file mode 100644 index 0000000000..704d5fca99 --- /dev/null +++ b/drivers/pe_bliss/pe_imports.cpp @@ -0,0 +1,756 @@ +#include +#include "pe_imports.h" +#include "pe_properties_generic.h" + +namespace pe_bliss +{ +using namespace pe_win; + +//IMPORTS +//Default constructor +//If set_to_pe_headers = true, IMAGE_DIRECTORY_ENTRY_IMPORT entry will be reset +//to new value after import rebuilding +//If auto_zero_directory_entry_iat = true, IMAGE_DIRECTORY_ENTRY_IAT will be set to zero +//IMAGE_DIRECTORY_ENTRY_IAT is used by loader to temporarily make section, where IMAGE_DIRECTORY_ENTRY_IAT RVA points, writeable +//to be able to modify IAT thunks +import_rebuilder_settings::import_rebuilder_settings(bool set_to_pe_headers, bool auto_zero_directory_entry_iat) + :offset_from_section_start_(0), + build_original_iat_(true), + save_iat_and_original_iat_rvas_(true), + fill_missing_original_iats_(false), + set_to_pe_headers_(set_to_pe_headers), + zero_directory_entry_iat_(auto_zero_directory_entry_iat), + rewrite_iat_and_original_iat_contents_(false), + auto_strip_last_section_(true) +{} + +//Returns offset from section start where import directory data will be placed +uint32_t import_rebuilder_settings::get_offset_from_section_start() const +{ + return offset_from_section_start_; +} + +//Returns true if Original import address table (IAT) will be rebuilt +bool import_rebuilder_settings::build_original_iat() const +{ + return build_original_iat_; +} + +//Returns true if Original import address and import address tables will not be rebuilt, +//works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero +bool import_rebuilder_settings::save_iat_and_original_iat_rvas() const +{ + return save_iat_and_original_iat_rvas_; +} + +//Returns true if Original import address and import address tables contents will be rewritten +//works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero +//and save_iat_and_original_iat_rvas is true +bool import_rebuilder_settings::rewrite_iat_and_original_iat_contents() const +{ + return rewrite_iat_and_original_iat_contents_; +} + +//Returns true if original missing IATs will be rebuilt +//(only if IATs are saved) +bool import_rebuilder_settings::fill_missing_original_iats() const +{ + return fill_missing_original_iats_; +} + +//Returns true if PE headers should be updated automatically after rebuilding of imports +bool import_rebuilder_settings::auto_set_to_pe_headers() const +{ + return set_to_pe_headers_; +} + +//Returns true if IMAGE_DIRECTORY_ENTRY_IAT must be zeroed, works only if auto_set_to_pe_headers = true +bool import_rebuilder_settings::zero_directory_entry_iat() const +{ + return zero_directory_entry_iat_; +} + +//Returns true if the last section should be stripped automatically, if imports are inside it +bool import_rebuilder_settings::auto_strip_last_section_enabled() const +{ + return auto_strip_last_section_; +} + +//Sets offset from section start where import directory data will be placed +void import_rebuilder_settings::set_offset_from_section_start(uint32_t offset) +{ + offset_from_section_start_ = offset; +} + +//Sets if Original import address table (IAT) will be rebuilt +void import_rebuilder_settings::build_original_iat(bool enable) +{ + build_original_iat_ = enable; +} + +//Sets if Original import address and import address tables will not be rebuilt, +//works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero +void import_rebuilder_settings::save_iat_and_original_iat_rvas(bool enable, bool enable_rewrite_iat_and_original_iat_contents) +{ + save_iat_and_original_iat_rvas_ = enable; + if(save_iat_and_original_iat_rvas_) + rewrite_iat_and_original_iat_contents_ = enable_rewrite_iat_and_original_iat_contents; + else + rewrite_iat_and_original_iat_contents_ = false; +} + +//Sets if original missing IATs will be rebuilt +//(only if IATs are saved) +void import_rebuilder_settings::fill_missing_original_iats(bool enable) +{ + fill_missing_original_iats_ = enable; +} + +//Sets if PE headers should be updated automatically after rebuilding of imports +void import_rebuilder_settings::auto_set_to_pe_headers(bool enable) +{ + set_to_pe_headers_ = enable; +} + +//Sets if IMAGE_DIRECTORY_ENTRY_IAT must be zeroed, works only if auto_set_to_pe_headers = true +void import_rebuilder_settings::zero_directory_entry_iat(bool enable) +{ + zero_directory_entry_iat_ = enable; +} + +//Sets if the last section should be stripped automatically, if imports are inside it, default true +void import_rebuilder_settings::enable_auto_strip_last_section(bool enable) +{ + auto_strip_last_section_ = enable; +} + +//Default constructor +imported_function::imported_function() + :hint_(0), ordinal_(0), iat_va_(0) +{} + +//Returns name of function +const std::string& imported_function::get_name() const +{ + return name_; +} + +//Returns true if imported function has name (and hint) +bool imported_function::has_name() const +{ + return !name_.empty(); +} + +//Returns hint +uint16_t imported_function::get_hint() const +{ + return hint_; +} + +//Returns ordinal of function +uint16_t imported_function::get_ordinal() const +{ + return ordinal_; +} + +//Returns IAT entry VA (usable if image has both IAT and original IAT and is bound) +uint64_t imported_function::get_iat_va() const +{ + return iat_va_; +} + +//Sets name of function +void imported_function::set_name(const std::string& name) +{ + name_ = name; +} + +//Sets hint +void imported_function::set_hint(uint16_t hint) +{ + hint_ = hint; +} + +//Sets ordinal +void imported_function::set_ordinal(uint16_t ordinal) +{ + ordinal_ = ordinal; +} + +//Sets IAT entry VA (usable if image has both IAT and original IAT and is bound) +void imported_function::set_iat_va(uint64_t va) +{ + iat_va_ = va; +} + +//Default constructor +import_library::import_library() + :rva_to_iat_(0), rva_to_original_iat_(0), timestamp_(0) +{} + +//Returns name of library +const std::string& import_library::get_name() const +{ + return name_; +} + +//Returns RVA to Import Address Table (IAT) +uint32_t import_library::get_rva_to_iat() const +{ + return rva_to_iat_; +} + +//Returns RVA to Original Import Address Table (Original IAT) +uint32_t import_library::get_rva_to_original_iat() const +{ + return rva_to_original_iat_; +} + +//Returns timestamp +uint32_t import_library::get_timestamp() const +{ + return timestamp_; +} + +//Sets name of library +void import_library::set_name(const std::string& name) +{ + name_ = name; +} + +//Sets RVA to Import Address Table (IAT) +void import_library::set_rva_to_iat(uint32_t rva_to_iat) +{ + rva_to_iat_ = rva_to_iat; +} + +//Sets RVA to Original Import Address Table (Original IAT) +void import_library::set_rva_to_original_iat(uint32_t rva_to_original_iat) +{ + rva_to_original_iat_ = rva_to_original_iat; +} + +//Sets timestamp +void import_library::set_timestamp(uint32_t timestamp) +{ + timestamp_ = timestamp; +} + +//Returns imported functions list +const import_library::imported_list& import_library::get_imported_functions() const +{ + return imports_; +} + +//Adds imported function +void import_library::add_import(const imported_function& func) +{ + imports_.push_back(func); +} + +//Clears imported functions list +void import_library::clear_imports() +{ + imports_.clear(); +} + +const imported_functions_list get_imported_functions(const pe_base& pe) +{ + return (pe.get_pe_type() == pe_type_32 ? + get_imported_functions_base(pe) + : get_imported_functions_base(pe)); +} + +const image_directory rebuild_imports(pe_base& pe, const imported_functions_list& imports, section& import_section, const import_rebuilder_settings& import_settings) +{ + return (pe.get_pe_type() == pe_type_32 ? + rebuild_imports_base(pe, imports, import_section, import_settings) + : rebuild_imports_base(pe, imports, import_section, import_settings)); +} + +//Returns imported functions list with related libraries info +template +const imported_functions_list get_imported_functions_base(const pe_base& pe) +{ + imported_functions_list ret; + + //If image has no imports, return empty array + if(!pe.has_imports()) + return ret; + + unsigned long current_descriptor_pos = pe.get_directory_rva(image_directory_entry_import); + //Get first IMAGE_IMPORT_DESCRIPTOR + image_import_descriptor import_descriptor = pe.section_data_from_rva(current_descriptor_pos, section_data_virtual, true); + + //Iterate them until we reach zero-element + //We don't need to check correctness of this, because exception will be thrown + //inside of loop if we go outsize of section + while(import_descriptor.Name) + { + //Get imported library information + import_library lib; + + unsigned long max_name_length; + //Get byte count that we have for library name + if((max_name_length = pe.section_data_length_from_rva(import_descriptor.Name, import_descriptor.Name, section_data_virtual, true)) < 2) + throw pe_exception("Incorrect import directory", pe_exception::incorrect_import_directory); + + //Get DLL name pointer + const char* dll_name = pe.section_data_from_rva(import_descriptor.Name, section_data_virtual, true); + + //Check for null-termination + if(!pe_utils::is_null_terminated(dll_name, max_name_length)) + throw pe_exception("Incorrect import directory", pe_exception::incorrect_import_directory); + + //Set library name + lib.set_name(dll_name); + //Set library timestamp + lib.set_timestamp(import_descriptor.TimeDateStamp); + //Set library RVA to IAT and original IAT + lib.set_rva_to_iat(import_descriptor.FirstThunk); + lib.set_rva_to_original_iat(import_descriptor.OriginalFirstThunk); + + //Get RVA to IAT (it must be filled by loader when loading PE) + uint32_t current_thunk_rva = import_descriptor.FirstThunk; + typename PEClassType::BaseSize import_address_table = pe.section_data_from_rva(current_thunk_rva, section_data_virtual, true); + + //Get RVA to original IAT (lookup table), which must handle imported functions names + //Some linkers leave this pointer zero-filled + //Such image is valid, but it is not possible to restore imported functions names + //afted image was loaded, because IAT becomes the only one table + //containing both function names and function RVAs after loading + uint32_t current_original_thunk_rva = import_descriptor.OriginalFirstThunk; + typename PEClassType::BaseSize import_lookup_table = current_original_thunk_rva == 0 ? import_address_table : pe.section_data_from_rva(current_original_thunk_rva, section_data_virtual, true); + if(current_original_thunk_rva == 0) + current_original_thunk_rva = current_thunk_rva; + + //List all imported functions for current DLL + if(import_lookup_table != 0 && import_address_table != 0) + { + while(true) + { + //Imported function description + imported_function func; + + //Get VA from IAT + typename PEClassType::BaseSize address = pe.section_data_from_rva(current_thunk_rva, section_data_virtual, true); + //Move pointer + current_thunk_rva += sizeof(typename PEClassType::BaseSize); + + //Jump to next DLL if we finished with this one + if(!address) + break; + + func.set_iat_va(address); + + //Get VA from original IAT + typename PEClassType::BaseSize lookup = pe.section_data_from_rva(current_original_thunk_rva, section_data_virtual, true); + //Move pointer + current_original_thunk_rva += sizeof(typename PEClassType::BaseSize); + + //Check if function is imported by ordinal + if((lookup & PEClassType::ImportSnapFlag) != 0) + { + //Set function ordinal + func.set_ordinal(static_cast(lookup & 0xffff)); + } + else + { + //Get byte count that we have for function name + if(lookup > static_cast(-1) - sizeof(uint16_t)) + throw pe_exception("Incorrect import directory", pe_exception::incorrect_import_directory); + + //Get maximum available length of function name + if((max_name_length = pe.section_data_length_from_rva(static_cast(lookup + sizeof(uint16_t)), static_cast(lookup + sizeof(uint16_t)), section_data_virtual, true)) < 2) + throw pe_exception("Incorrect import directory", pe_exception::incorrect_import_directory); + + //Get imported function name + const char* func_name = pe.section_data_from_rva(static_cast(lookup + sizeof(uint16_t)), section_data_virtual, true); + + //Check for null-termination + if(!pe_utils::is_null_terminated(func_name, max_name_length)) + throw pe_exception("Incorrect import directory", pe_exception::incorrect_import_directory); + + //HINT in import table is ORDINAL in export table + uint16_t hint = pe.section_data_from_rva(static_cast(lookup), section_data_virtual, true); + + //Save hint and name + func.set_name(func_name); + func.set_hint(hint); + } + + //Add function to list + lib.add_import(func); + } + } + + //Check possible overflow + if(!pe_utils::is_sum_safe(current_descriptor_pos, sizeof(image_import_descriptor))) + throw pe_exception("Incorrect import directory", pe_exception::incorrect_import_directory); + + //Go to next library + current_descriptor_pos += sizeof(image_import_descriptor); + import_descriptor = pe.section_data_from_rva(current_descriptor_pos, section_data_virtual, true); + + //Save import information + ret.push_back(lib); + } + + //Return resulting list + return ret; +} + + +//Simple import directory rebuilder +//You can get all image imports with get_imported_functions() function +//You can use returned value to, for example, add new imported library with some functions +//to the end of list of imported libraries +//To keep PE file working, rebuild its imports with save_iat_and_original_iat_rvas = true (default) +//Don't add new imported functions to existing imported library entries, because this can cause +//rewriting of some used memory (or other IAT/orig.IAT fields) by system loader +//The safest way is just adding import libraries with functions to the end of imported_functions_list array +template +const image_directory rebuild_imports_base(pe_base& pe, const imported_functions_list& imports, section& import_section, const import_rebuilder_settings& import_settings) +{ + //Check that import_section is attached to this PE image + if(!pe.section_attached(import_section)) + throw pe_exception("Import section must be attached to PE file", pe_exception::section_is_not_attached); + + uint32_t needed_size = 0; //Calculate needed size for import structures and strings + uint32_t needed_size_for_strings = 0; //Calculate needed size for import strings (library and function names and hints) + uint32_t size_of_iat = 0; //Size of IAT structures + + needed_size += static_cast((1 /* ending null descriptor */ + imports.size()) * sizeof(image_import_descriptor)); + + //Enumerate imported functions + for(imported_functions_list::const_iterator it = imports.begin(); it != imports.end(); ++it) + { + needed_size_for_strings += static_cast((*it).get_name().length() + 1 /* nullbyte */); + + const import_library::imported_list& funcs = (*it).get_imported_functions(); + + //IMAGE_THUNK_DATA + size_of_iat += static_cast(sizeof(typename PEClassType::BaseSize) * (1 /*ending null */ + funcs.size())); + + //Enumerate all imported functions in library + for(import_library::imported_list::const_iterator f = funcs.begin(); f != funcs.end(); ++f) + { + if((*f).has_name()) + needed_size_for_strings += static_cast((*f).get_name().length() + 1 /* nullbyte */ + sizeof(uint16_t) /* hint */); + } + } + + if(import_settings.build_original_iat() || import_settings.fill_missing_original_iats()) + needed_size += size_of_iat * 2; //We'll have two similar-sized IATs if we're building original IAT + else + needed_size += size_of_iat; + + needed_size += sizeof(typename PEClassType::BaseSize); //Maximum align for IAT and original IAT + + //Total needed size for import structures and strings + needed_size += needed_size_for_strings; + + //Check if import_section is last one. If it's not, check if there's enough place for import data + if(&import_section != &*(pe.get_image_sections().end() - 1) && + (import_section.empty() || pe_utils::align_up(import_section.get_size_of_raw_data(), pe.get_file_alignment()) < needed_size + import_settings.get_offset_from_section_start())) + throw pe_exception("Insufficient space for import directory", pe_exception::insufficient_space); + + std::string& raw_data = import_section.get_raw_data(); + + //This will be done only if image_section is the last section of image or for section with unaligned raw length of data + if(raw_data.length() < needed_size + import_settings.get_offset_from_section_start()) + raw_data.resize(needed_size + import_settings.get_offset_from_section_start()); //Expand section raw data + + uint32_t current_string_pointer = import_settings.get_offset_from_section_start();/* we will paste structures after strings */ + + //Position for IAT + uint32_t current_pos_for_iat = pe_utils::align_up(static_cast(needed_size_for_strings + import_settings.get_offset_from_section_start() + (1 + imports.size()) * sizeof(image_import_descriptor)), sizeof(typename PEClassType::BaseSize)); + //Position for original IAT + uint32_t current_pos_for_original_iat = current_pos_for_iat + size_of_iat; + //Position for import descriptors + uint32_t current_pos_for_descriptors = needed_size_for_strings + import_settings.get_offset_from_section_start(); + + //Build imports + for(imported_functions_list::const_iterator it = imports.begin(); it != imports.end(); ++it) + { + //Create import descriptor + image_import_descriptor descr; + memset(&descr, 0, sizeof(descr)); + descr.TimeDateStamp = (*it).get_timestamp(); //Restore timestamp + descr.Name = pe.rva_from_section_offset(import_section, current_string_pointer); //Library name RVA + + //If we should save IAT for current import descriptor + bool save_iats_for_this_descriptor = import_settings.save_iat_and_original_iat_rvas() && (*it).get_rva_to_iat() != 0; + //If we should write original IAT + bool write_original_iat = (!save_iats_for_this_descriptor && import_settings.build_original_iat()) || import_settings.fill_missing_original_iats(); + + //If we should rewrite saved original IAT for current import descriptor (without changing its position) + bool rewrite_saved_original_iat = save_iats_for_this_descriptor && import_settings.rewrite_iat_and_original_iat_contents() && import_settings.build_original_iat(); + //If we should rewrite saved IAT for current import descriptor (without changing its position) + bool rewrite_saved_iat = save_iats_for_this_descriptor && import_settings.rewrite_iat_and_original_iat_contents() && (*it).get_rva_to_iat() != 0; + + //Helper values if we're rewriting existing IAT or orig.IAT + uint32_t original_first_thunk = 0; + uint32_t first_thunk = 0; + + if(save_iats_for_this_descriptor) + { + //If there's no original IAT and we're asked to rebuild missing original IATs + if(!(*it).get_rva_to_original_iat() && import_settings.fill_missing_original_iats()) + descr.OriginalFirstThunk = import_settings.build_original_iat() ? pe.rva_from_section_offset(import_section, current_pos_for_original_iat) : 0; + else + descr.OriginalFirstThunk = import_settings.build_original_iat() ? (*it).get_rva_to_original_iat() : 0; + + descr.FirstThunk = (*it).get_rva_to_iat(); + + original_first_thunk = descr.OriginalFirstThunk; + first_thunk = descr.FirstThunk; + + if(rewrite_saved_original_iat) + { + if((*it).get_rva_to_original_iat()) + write_original_iat = true; + else + rewrite_saved_original_iat = false; + } + + if(rewrite_saved_iat) + save_iats_for_this_descriptor = false; + } + else + { + //We are creating new IAT and original IAT (if needed) + descr.OriginalFirstThunk = import_settings.build_original_iat() ? pe.rva_from_section_offset(import_section, current_pos_for_original_iat) : 0; + descr.FirstThunk = pe.rva_from_section_offset(import_section, current_pos_for_iat); + } + + //Save import descriptor + memcpy(&raw_data[current_pos_for_descriptors], &descr, sizeof(descr)); + current_pos_for_descriptors += sizeof(descr); + + //Save library name + memcpy(&raw_data[current_string_pointer], (*it).get_name().c_str(), (*it).get_name().length() + 1 /* nullbyte */); + current_string_pointer += static_cast((*it).get_name().length() + 1 /* nullbyte */); + + //List all imported functions + const import_library::imported_list& funcs = (*it).get_imported_functions(); + for(import_library::imported_list::const_iterator f = funcs.begin(); f != funcs.end(); ++f) + { + if((*f).has_name()) //If function is imported by name + { + //Get RVA of IMAGE_IMPORT_BY_NAME + typename PEClassType::BaseSize rva_of_named_import = pe.rva_from_section_offset(import_section, current_string_pointer); + + if(!save_iats_for_this_descriptor) + { + if(write_original_iat) + { + //We're creating original IATs - so we can write to IAT saved VA (because IMAGE_IMPORT_BY_NAME will be read + //by PE loader from original IAT) + typename PEClassType::BaseSize iat_value = static_cast((*f).get_iat_va()); + + if(rewrite_saved_iat) + { + if(pe.section_data_length_from_rva(first_thunk, first_thunk, section_data_raw, true) <= sizeof(iat_value)) + throw pe_exception("Insufficient space inside initial IAT", pe_exception::insufficient_space); + + memcpy(pe.section_data_from_rva(first_thunk, true), &iat_value, sizeof(iat_value)); + + first_thunk += sizeof(iat_value); + } + else + { + memcpy(&raw_data[current_pos_for_iat], &iat_value, sizeof(iat_value)); + current_pos_for_iat += sizeof(rva_of_named_import); + } + } + else + { + //Else - write to IAT RVA of IMAGE_IMPORT_BY_NAME + if(rewrite_saved_iat) + { + if(pe.section_data_length_from_rva(first_thunk, first_thunk, section_data_raw, true) <= sizeof(rva_of_named_import)) + throw pe_exception("Insufficient space inside initial IAT", pe_exception::insufficient_space); + + memcpy(pe.section_data_from_rva(first_thunk, true), &rva_of_named_import, sizeof(rva_of_named_import)); + + first_thunk += sizeof(rva_of_named_import); + } + else + { + memcpy(&raw_data[current_pos_for_iat], &rva_of_named_import, sizeof(rva_of_named_import)); + current_pos_for_iat += sizeof(rva_of_named_import); + } + } + } + + if(write_original_iat) + { + if(rewrite_saved_original_iat) + { + if(pe.section_data_length_from_rva(original_first_thunk, original_first_thunk, section_data_raw, true) <= sizeof(rva_of_named_import)) + throw pe_exception("Insufficient space inside initial original IAT", pe_exception::insufficient_space); + + memcpy(pe.section_data_from_rva(original_first_thunk, true), &rva_of_named_import, sizeof(rva_of_named_import)); + + original_first_thunk += sizeof(rva_of_named_import); + } + else + { + //We're creating original IATs + memcpy(&raw_data[current_pos_for_original_iat], &rva_of_named_import, sizeof(rva_of_named_import)); + current_pos_for_original_iat += sizeof(rva_of_named_import); + } + } + + //Write IMAGE_IMPORT_BY_NAME (WORD hint + string function name) + uint16_t hint = (*f).get_hint(); + memcpy(&raw_data[current_string_pointer], &hint, sizeof(hint)); + memcpy(&raw_data[current_string_pointer + sizeof(uint16_t)], (*f).get_name().c_str(), (*f).get_name().length() + 1 /* nullbyte */); + current_string_pointer += static_cast((*f).get_name().length() + 1 /* nullbyte */ + sizeof(uint16_t) /* hint */); + } + else //Function is imported by ordinal + { + uint16_t ordinal = (*f).get_ordinal(); + typename PEClassType::BaseSize thunk_value = ordinal; + thunk_value |= PEClassType::ImportSnapFlag; //Imported by ordinal + + if(!save_iats_for_this_descriptor) + { + if(write_original_iat) + { + //We're creating original IATs - so we can wtire to IAT saved VA (because ordinal will be read + //by PE loader from original IAT) + typename PEClassType::BaseSize iat_value = static_cast((*f).get_iat_va()); + if(rewrite_saved_iat) + { + if(pe.section_data_length_from_rva(first_thunk, first_thunk, section_data_raw, true) <= sizeof(iat_value)) + throw pe_exception("Insufficient space inside initial IAT", pe_exception::insufficient_space); + + memcpy(pe.section_data_from_rva(first_thunk, true), &iat_value, sizeof(iat_value)); + + first_thunk += sizeof(iat_value); + } + else + { + memcpy(&raw_data[current_pos_for_iat], &iat_value, sizeof(iat_value)); + current_pos_for_iat += sizeof(thunk_value); + } + } + else + { + //Else - write ordinal to IAT + if(rewrite_saved_iat) + { + if(pe.section_data_length_from_rva(first_thunk, first_thunk, section_data_raw, true) <= sizeof(thunk_value)) + throw pe_exception("Insufficient space inside initial IAT", pe_exception::insufficient_space); + + memcpy(pe.section_data_from_rva(first_thunk, true), &thunk_value, sizeof(thunk_value)); + + first_thunk += sizeof(thunk_value); + } + else + { + memcpy(&raw_data[current_pos_for_iat], &thunk_value, sizeof(thunk_value)); + } + } + } + + //We're writing ordinal to original IAT slot + if(write_original_iat) + { + if(rewrite_saved_original_iat) + { + if(pe.section_data_length_from_rva(original_first_thunk, original_first_thunk, section_data_raw, true) <= sizeof(thunk_value)) + throw pe_exception("Insufficient space inside initial original IAT", pe_exception::insufficient_space); + + memcpy(pe.section_data_from_rva(original_first_thunk, true), &thunk_value, sizeof(thunk_value)); + + original_first_thunk += sizeof(thunk_value); + } + else + { + memcpy(&raw_data[current_pos_for_original_iat], &thunk_value, sizeof(thunk_value)); + current_pos_for_original_iat += sizeof(thunk_value); + } + } + } + } + + if(!save_iats_for_this_descriptor) + { + //Ending null thunks + typename PEClassType::BaseSize thunk_value = 0; + + if(rewrite_saved_iat) + { + if(pe.section_data_length_from_rva(first_thunk, first_thunk, section_data_raw, true) <= sizeof(thunk_value)) + throw pe_exception("Insufficient space inside initial IAT", pe_exception::insufficient_space); + + memcpy(pe.section_data_from_rva(first_thunk, true), &thunk_value, sizeof(thunk_value)); + + first_thunk += sizeof(thunk_value); + } + else + { + memcpy(&raw_data[current_pos_for_iat], &thunk_value, sizeof(thunk_value)); + current_pos_for_iat += sizeof(thunk_value); + } + } + + if(write_original_iat) + { + //Ending null thunks + typename PEClassType::BaseSize thunk_value = 0; + + if(rewrite_saved_original_iat) + { + if(pe.section_data_length_from_rva(original_first_thunk, original_first_thunk, section_data_raw, true) <= sizeof(thunk_value)) + throw pe_exception("Insufficient space inside initial original IAT", pe_exception::insufficient_space); + + memcpy(pe.section_data_from_rva(original_first_thunk, true), &thunk_value, sizeof(thunk_value)); + + original_first_thunk += sizeof(thunk_value); + } + else + { + memcpy(&raw_data[current_pos_for_original_iat], &thunk_value, sizeof(thunk_value)); + current_pos_for_original_iat += sizeof(thunk_value); + } + } + } + + { + //Null ending descriptor + image_import_descriptor descr; + memset(&descr, 0, sizeof(descr)); + memcpy(&raw_data[current_pos_for_descriptors], &descr, sizeof(descr)); + } + + //Strip data a little, if we saved some place + //We're allocating more space than needed, if present original IAT and IAT are saved + raw_data.resize(current_pos_for_original_iat); + + //Adjust section raw and virtual sizes + pe.recalculate_section_sizes(import_section, import_settings.auto_strip_last_section_enabled()); + + //Return information about rebuilt import directory + image_directory ret(pe.rva_from_section_offset(import_section, import_settings.get_offset_from_section_start() + needed_size_for_strings), needed_size - needed_size_for_strings); + + //If auto-rewrite of PE headers is required + if(import_settings.auto_set_to_pe_headers()) + { + pe.set_directory_rva(image_directory_entry_import, ret.get_rva()); + pe.set_directory_size(image_directory_entry_import, ret.get_size()); + + //If we are requested to zero IMAGE_DIRECTORY_ENTRY_IAT also + if(import_settings.zero_directory_entry_iat()) + { + pe.set_directory_rva(image_directory_entry_iat, 0); + pe.set_directory_size(image_directory_entry_iat, 0); + } + } + + return ret; +} +} diff --git a/drivers/pe_bliss/pe_imports.h b/drivers/pe_bliss/pe_imports.h new file mode 100644 index 0000000000..713be13e42 --- /dev/null +++ b/drivers/pe_bliss/pe_imports.h @@ -0,0 +1,187 @@ +#pragma once +#include +#include +#include "pe_structures.h" +#include "pe_directory.h" +#include "pe_base.h" + +namespace pe_bliss +{ +//Class representing imported function +class imported_function +{ +public: + //Default constructor + imported_function(); + + //Returns true if imported function has name (and hint) + bool has_name() const; + //Returns name of function + const std::string& get_name() const; + //Returns hint + uint16_t get_hint() const; + //Returns ordinal of function + uint16_t get_ordinal() const; + + //Returns IAT entry VA (usable if image has both IAT and original IAT and is bound) + uint64_t get_iat_va() const; + +public: //Setters do not change everything inside image, they are used by PE class + //You also can use them to rebuild image imports + //Sets name of function + void set_name(const std::string& name); + //Sets hint + void set_hint(uint16_t hint); + //Sets ordinal + void set_ordinal(uint16_t ordinal); + + //Sets IAT entry VA (usable if image has both IAT and original IAT and is bound) + void set_iat_va(uint64_t rva); + +private: + std::string name_; //Function name + uint16_t hint_; //Hint + uint16_t ordinal_; //Ordinal + uint64_t iat_va_; +}; + +//Class representing imported library information +class import_library +{ +public: + typedef std::vector imported_list; + +public: + //Default constructor + import_library(); + + //Returns name of library + const std::string& get_name() const; + //Returns RVA to Import Address Table (IAT) + uint32_t get_rva_to_iat() const; + //Returns RVA to Original Import Address Table (Original IAT) + uint32_t get_rva_to_original_iat() const; + //Returns timestamp + uint32_t get_timestamp() const; + + //Returns imported functions list + const imported_list& get_imported_functions() const; + +public: //Setters do not change everything inside image, they are used by PE class + //You also can use them to rebuild image imports + //Sets name of library + void set_name(const std::string& name); + //Sets RVA to Import Address Table (IAT) + void set_rva_to_iat(uint32_t rva_to_iat); + //Sets RVA to Original Import Address Table (Original IAT) + void set_rva_to_original_iat(uint32_t rva_to_original_iat); + //Sets timestamp + void set_timestamp(uint32_t timestamp); + + //Adds imported function + void add_import(const imported_function& func); + //Clears imported functions list + void clear_imports(); + +private: + std::string name_; //Library name + uint32_t rva_to_iat_; //RVA to IAT + uint32_t rva_to_original_iat_; //RVA to original IAT + uint32_t timestamp_; //DLL TimeStamp + + imported_list imports_; +}; + +//Simple import directory rebuilder +//Class representing import rebuilder advanced settings +class import_rebuilder_settings +{ +public: + //Default constructor + //Default constructor + //If set_to_pe_headers = true, IMAGE_DIRECTORY_ENTRY_IMPORT entry will be reset + //to new value after import rebuilding + //If auto_zero_directory_entry_iat = true, IMAGE_DIRECTORY_ENTRY_IAT will be set to zero + //IMAGE_DIRECTORY_ENTRY_IAT is used by loader to temporarily make section, where IMAGE_DIRECTORY_ENTRY_IAT RVA points, writeable + //to be able to modify IAT thunks + explicit import_rebuilder_settings(bool set_to_pe_headers = true, bool auto_zero_directory_entry_iat = false); + + //Returns offset from section start where import directory data will be placed + uint32_t get_offset_from_section_start() const; + //Returns true if Original import address table (IAT) will be rebuilt + bool build_original_iat() const; + + //Returns true if Original import address and import address tables will not be rebuilt, + //works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero + bool save_iat_and_original_iat_rvas() const; + //Returns true if Original import address and import address tables contents will be rewritten + //works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero + //and save_iat_and_original_iat_rvas is true + bool rewrite_iat_and_original_iat_contents() const; + + //Returns true if original missing IATs will be rebuilt + //(only if IATs are saved) + bool fill_missing_original_iats() const; + //Returns true if PE headers should be updated automatically after rebuilding of imports + bool auto_set_to_pe_headers() const; + //Returns true if IMAGE_DIRECTORY_ENTRY_IAT must be zeroed, works only if auto_set_to_pe_headers = true + bool zero_directory_entry_iat() const; + + //Returns true if the last section should be stripped automatically, if imports are inside it + bool auto_strip_last_section_enabled() const; + +public: //Setters + //Sets offset from section start where import directory data will be placed + void set_offset_from_section_start(uint32_t offset); + //Sets if Original import address table (IAT) will be rebuilt + void build_original_iat(bool enable); + //Sets if Original import address and import address tables will not be rebuilt, + //works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero + //enable_rewrite_iat_and_original_iat_contents sets if Original import address and import address tables contents will be rewritten + //works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero + //and save_iat_and_original_iat_rvas is true + void save_iat_and_original_iat_rvas(bool enable, bool enable_rewrite_iat_and_original_iat_contents = false); + //Sets if original missing IATs will be rebuilt + //(only if IATs are saved) + void fill_missing_original_iats(bool enable); + //Sets if PE headers should be updated automatically after rebuilding of imports + void auto_set_to_pe_headers(bool enable); + //Sets if IMAGE_DIRECTORY_ENTRY_IAT must be zeroed, works only if auto_set_to_pe_headers = true + void zero_directory_entry_iat(bool enable); + + //Sets if the last section should be stripped automatically, if imports are inside it, default true + void enable_auto_strip_last_section(bool enable); + +private: + uint32_t offset_from_section_start_; + bool build_original_iat_; + bool save_iat_and_original_iat_rvas_; + bool fill_missing_original_iats_; + bool set_to_pe_headers_; + bool zero_directory_entry_iat_; + bool rewrite_iat_and_original_iat_contents_; + bool auto_strip_last_section_; +}; + +typedef std::vector imported_functions_list; + + +//Returns imported functions list with related libraries info +const imported_functions_list get_imported_functions(const pe_base& pe); + +template +const imported_functions_list get_imported_functions_base(const pe_base& pe); + + +//You can get all image imports with get_imported_functions() function +//You can use returned value to, for example, add new imported library with some functions +//to the end of list of imported libraries +//To keep PE file working, rebuild its imports with save_iat_and_original_iat_rvas = true (default) +//Don't add new imported functions to existing imported library entries, because this can cause +//rewriting of some used memory (or other IAT/orig.IAT fields) by system loader +//The safest way is just adding import libraries with functions to the end of imported_functions_list array +const image_directory rebuild_imports(pe_base& pe, const imported_functions_list& imports, section& import_section, const import_rebuilder_settings& import_settings = import_rebuilder_settings()); + +template +const image_directory rebuild_imports_base(pe_base& pe, const imported_functions_list& imports, section& import_section, const import_rebuilder_settings& import_settings = import_rebuilder_settings()); +} diff --git a/drivers/pe_bliss/pe_load_config.cpp b/drivers/pe_bliss/pe_load_config.cpp new file mode 100644 index 0000000000..dedb2a61a1 --- /dev/null +++ b/drivers/pe_bliss/pe_load_config.cpp @@ -0,0 +1,536 @@ +#include +#include +#include "pe_load_config.h" +#include "pe_properties_generic.h" + +namespace pe_bliss +{ +using namespace pe_win; + +//IMAGE CONFIG +//Default constructor +image_config_info::image_config_info() + :time_stamp_(0), + major_version_(0), minor_version_(0), + global_flags_clear_(0), global_flags_set_(0), + critical_section_default_timeout_(0), + decommit_free_block_threshold_(0), decommit_total_free_threshold_(0), + lock_prefix_table_va_(0), + max_allocation_size_(0), + virtual_memory_threshold_(0), + process_affinity_mask_(0), + process_heap_flags_(0), + service_pack_version_(0), + edit_list_va_(0), + security_cookie_va_(0), + se_handler_table_va_(0), + se_handler_count_(0) +{} + +//Constructors from PE structures +template +image_config_info::image_config_info(const ConfigStructure& info) + :time_stamp_(info.TimeDateStamp), + major_version_(info.MajorVersion), minor_version_(info.MinorVersion), + global_flags_clear_(info.GlobalFlagsClear), global_flags_set_(info.GlobalFlagsSet), + critical_section_default_timeout_(info.CriticalSectionDefaultTimeout), + decommit_free_block_threshold_(info.DeCommitFreeBlockThreshold), decommit_total_free_threshold_(info.DeCommitTotalFreeThreshold), + lock_prefix_table_va_(info.LockPrefixTable), + max_allocation_size_(info.MaximumAllocationSize), + virtual_memory_threshold_(info.VirtualMemoryThreshold), + process_affinity_mask_(info.ProcessAffinityMask), + process_heap_flags_(info.ProcessHeapFlags), + service_pack_version_(info.CSDVersion), + edit_list_va_(info.EditList), + security_cookie_va_(info.SecurityCookie), + se_handler_table_va_(info.SEHandlerTable), + se_handler_count_(info.SEHandlerCount) +{} + +//Instantiate template constructor with needed structures +template image_config_info::image_config_info(const image_load_config_directory32& info); +template image_config_info::image_config_info(const image_load_config_directory64& info); + +//Returns the date and time stamp value +uint32_t image_config_info::get_time_stamp() const +{ + return time_stamp_; +} + +//Returns major version number +uint16_t image_config_info::get_major_version() const +{ + return major_version_; +} + +//Returns minor version number +uint16_t image_config_info::get_minor_version() const +{ + return minor_version_; +} + +//Returns clear global flags +uint32_t image_config_info::get_global_flags_clear() const +{ + return global_flags_clear_; +} + +//Returns set global flags +uint32_t image_config_info::get_global_flags_set() const +{ + return global_flags_set_; +} + +//Returns critical section default timeout +uint32_t image_config_info::get_critical_section_default_timeout() const +{ + return critical_section_default_timeout_; +} + +//Get the size of the minimum block that +//must be freed before it is freed (de-committed), in bytes +uint64_t image_config_info::get_decommit_free_block_threshold() const +{ + return decommit_free_block_threshold_; +} + +//Returns the size of the minimum total memory +//that must be freed in the process heap before it is freed (de-committed), in bytes +uint64_t image_config_info::get_decommit_total_free_threshold() const +{ + return decommit_total_free_threshold_; +} + +//Returns VA of a list of addresses where the LOCK prefix is used +uint64_t image_config_info::get_lock_prefix_table_va() const +{ + return lock_prefix_table_va_; +} + +//Returns the maximum allocation size, in bytes +uint64_t image_config_info::get_max_allocation_size() const +{ + return max_allocation_size_; +} + +//Returns the maximum block size that can be allocated from heap segments, in bytes +uint64_t image_config_info::get_virtual_memory_threshold() const +{ + return virtual_memory_threshold_; +} + +//Returns process affinity mask +uint64_t image_config_info::get_process_affinity_mask() const +{ + return process_affinity_mask_; +} + +//Returns process heap flags +uint32_t image_config_info::get_process_heap_flags() const +{ + return process_heap_flags_; +} + +//Returns service pack version (CSDVersion) +uint16_t image_config_info::get_service_pack_version() const +{ + return service_pack_version_; +} + +//Returns VA of edit list (reserved by system) +uint64_t image_config_info::get_edit_list_va() const +{ + return edit_list_va_; +} + +//Returns a pointer to a cookie that is used by Visual C++ or GS implementation +uint64_t image_config_info::get_security_cookie_va() const +{ + return security_cookie_va_; +} + +//Returns VA of the sorted table of RVAs of each valid, unique handler in the image +uint64_t image_config_info::get_se_handler_table_va() const +{ + return se_handler_table_va_; +} + +//Returns the count of unique handlers in the table +uint64_t image_config_info::get_se_handler_count() const +{ + return se_handler_count_; +} + +//Returns SE Handler RVA list +const image_config_info::se_handler_list& image_config_info::get_se_handler_rvas() const +{ + return se_handlers_; +} + +//Returns Lock Prefix RVA list +const image_config_info::lock_prefix_rva_list& image_config_info::get_lock_prefix_rvas() const +{ + return lock_prefixes_; +} + +//Adds SE Handler RVA to list +void image_config_info::add_se_handler_rva(uint32_t rva) +{ + se_handlers_.push_back(rva); +} + +//Clears SE Handler list +void image_config_info::clear_se_handler_list() +{ + se_handlers_.clear(); +} + +//Adds Lock Prefix RVA to list +void image_config_info::add_lock_prefix_rva(uint32_t rva) +{ + lock_prefixes_.push_back(rva); +} + +//Clears Lock Prefix list +void image_config_info::clear_lock_prefix_list() +{ + lock_prefixes_.clear(); +} + +//Sets the date and time stamp value +void image_config_info::set_time_stamp(uint32_t time_stamp) +{ + time_stamp_ = time_stamp; +} + +//Sets major version number +void image_config_info::set_major_version(uint16_t major_version) +{ + major_version_ = major_version; +} + +//Sets minor version number +void image_config_info::set_minor_version(uint16_t minor_version) +{ + minor_version_ = minor_version; +} + +//Sets clear global flags +void image_config_info::set_global_flags_clear(uint32_t global_flags_clear) +{ + global_flags_clear_ = global_flags_clear; +} + +//Sets set global flags +void image_config_info::set_global_flags_set(uint32_t global_flags_set) +{ + global_flags_set_ = global_flags_set; +} + +//Sets critical section default timeout +void image_config_info::set_critical_section_default_timeout(uint32_t critical_section_default_timeout) +{ + critical_section_default_timeout_ = critical_section_default_timeout; +} + +//Sets the size of the minimum block that +//must be freed before it is freed (de-committed), in bytes +void image_config_info::set_decommit_free_block_threshold(uint64_t decommit_free_block_threshold) +{ + decommit_free_block_threshold_ = decommit_free_block_threshold; +} + +//Sets the size of the minimum total memory +//that must be freed in the process heap before it is freed (de-committed), in bytes +void image_config_info::set_decommit_total_free_threshold(uint64_t decommit_total_free_threshold) +{ + decommit_total_free_threshold_ = decommit_total_free_threshold; +} + +//Sets VA of a list of addresses where the LOCK prefix is used +//If you rebuild this list, VA will be re-assigned automatically +void image_config_info::set_lock_prefix_table_va(uint64_t lock_prefix_table_va) +{ + lock_prefix_table_va_ = lock_prefix_table_va; +} + +//Sets the maximum allocation size, in bytes +void image_config_info::set_max_allocation_size(uint64_t max_allocation_size) +{ + max_allocation_size_ = max_allocation_size; +} + +//Sets the maximum block size that can be allocated from heap segments, in bytes +void image_config_info::set_virtual_memory_threshold(uint64_t virtual_memory_threshold) +{ + virtual_memory_threshold_ = virtual_memory_threshold; +} + +//Sets process affinity mask +void image_config_info::set_process_affinity_mask(uint64_t process_affinity_mask) +{ + process_affinity_mask_ = process_affinity_mask; +} + +//Sets process heap flags +void image_config_info::set_process_heap_flags(uint32_t process_heap_flags) +{ + process_heap_flags_ = process_heap_flags; +} + +//Sets service pack version (CSDVersion) +void image_config_info::set_service_pack_version(uint16_t service_pack_version) +{ + service_pack_version_ = service_pack_version; +} + +//Sets VA of edit list (reserved by system) +void image_config_info::set_edit_list_va(uint64_t edit_list_va) +{ + edit_list_va_ = edit_list_va; +} + +//Sets a pointer to a cookie that is used by Visual C++ or GS implementation +void image_config_info::set_security_cookie_va(uint64_t security_cookie_va) +{ + security_cookie_va_ = security_cookie_va; +} + +//Sets VA of the sorted table of RVAs of each valid, unique handler in the image +//If you rebuild this list, VA will be re-assigned automatically +void image_config_info::set_se_handler_table_va(uint64_t se_handler_table_va) +{ + se_handler_table_va_ = se_handler_table_va; +} + +//Returns SE Handler RVA list +image_config_info::se_handler_list& image_config_info::get_se_handler_rvas() +{ + return se_handlers_; +} + +//Returns Lock Prefix RVA list +image_config_info::lock_prefix_rva_list& image_config_info::get_lock_prefix_rvas() +{ + return lock_prefixes_; +} + +//Returns image config info +//If image does not have config info, throws an exception +const image_config_info get_image_config(const pe_base& pe) +{ + return pe.get_pe_type() == pe_type_32 + ? get_image_config_base(pe) + : get_image_config_base(pe); +} + +//Image config rebuilder +const image_directory rebuild_image_config(pe_base& pe, const image_config_info& info, section& image_config_section, uint32_t offset_from_section_start, bool write_se_handlers, bool write_lock_prefixes, bool save_to_pe_header, bool auto_strip_last_section) +{ + return pe.get_pe_type() == pe_type_32 + ? rebuild_image_config_base(pe, info, image_config_section, offset_from_section_start, write_se_handlers, write_lock_prefixes, save_to_pe_header, auto_strip_last_section) + : rebuild_image_config_base(pe, info, image_config_section, offset_from_section_start, write_se_handlers, write_lock_prefixes, save_to_pe_header, auto_strip_last_section); +} + + +//Returns image config info +//If image does not have config info, throws an exception +template +const image_config_info get_image_config_base(const pe_base& pe) +{ + //Check if image has config directory + if(!pe.has_config()) + throw pe_exception("Image does not have load config directory", pe_exception::directory_does_not_exist); + + //Get load config structure + typename PEClassType::ConfigStruct config_info = pe.section_data_from_rva(pe.get_directory_rva(image_directory_entry_load_config), section_data_virtual); + + //Check size of config directory + if(config_info.Size != sizeof(config_info)) + throw pe_exception("Incorrect (or old) load config directory", pe_exception::incorrect_config_directory); + + //Fill return structure + image_config_info ret(config_info); + + //Check possible overflow + if(config_info.SEHandlerCount >= pe_utils::max_dword / sizeof(uint32_t) + || config_info.SEHandlerTable >= static_cast(-1) - config_info.SEHandlerCount * sizeof(uint32_t)) + throw pe_exception("Incorrect load config directory", pe_exception::incorrect_config_directory); + + //Read sorted SE handler RVA list (if any) + for(typename PEClassType::BaseSize i = 0; i != config_info.SEHandlerCount; ++i) + ret.add_se_handler_rva(pe.section_data_from_va(static_cast(config_info.SEHandlerTable + i * sizeof(uint32_t)))); + + if(config_info.LockPrefixTable) + { + //Read Lock Prefix VA list (if any) + unsigned long current = 0; + while(true) + { + typename PEClassType::BaseSize lock_prefix_va = pe.section_data_from_va(static_cast(config_info.LockPrefixTable + current * sizeof(typename PEClassType::BaseSize))); + if(!lock_prefix_va) + break; + + ret.add_lock_prefix_rva(pe.va_to_rva(lock_prefix_va)); + + ++current; + } + } + + return ret; +} + +//Image config directory rebuilder +//auto_strip_last_section - if true and TLS are placed in the last section, it will be automatically stripped +//If write_se_handlers = true, SE Handlers list will be written just after image config directory structure +//If write_lock_prefixes = true, Lock Prefixes address list will be written just after image config directory structure +template +const image_directory rebuild_image_config_base(pe_base& pe, const image_config_info& info, section& image_config_section, uint32_t offset_from_section_start, bool write_se_handlers, bool write_lock_prefixes, bool save_to_pe_header, bool auto_strip_last_section) +{ + //Check that image_config_section is attached to this PE image + if(!pe.section_attached(image_config_section)) + throw pe_exception("Image Config section must be attached to PE file", pe_exception::section_is_not_attached); + + uint32_t alignment = pe_utils::align_up(offset_from_section_start, sizeof(typename PEClassType::BaseSize)) - offset_from_section_start; + + uint32_t needed_size = sizeof(typename PEClassType::ConfigStruct); //Calculate needed size for Image Config table + + uint32_t image_config_data_pos = offset_from_section_start + alignment; + + uint32_t current_pos_of_se_handlers = 0; + uint32_t current_pos_of_lock_prefixes = 0; + + if(write_se_handlers) + { + current_pos_of_se_handlers = needed_size + image_config_data_pos; + needed_size += static_cast(info.get_se_handler_rvas().size()) * sizeof(uint32_t); //RVAs of SE Handlers + } + + if(write_lock_prefixes) + { + current_pos_of_lock_prefixes = needed_size + image_config_data_pos; + needed_size += static_cast((info.get_lock_prefix_rvas().size() + 1) * sizeof(typename PEClassType::BaseSize)); //VAs of Lock Prefixes (and ending null element) + } + + //Check if image_config_section is last one. If it's not, check if there's enough place for Image Config data + if(&image_config_section != &*(pe.get_image_sections().end() - 1) && + (image_config_section.empty() || pe_utils::align_up(image_config_section.get_size_of_raw_data(), pe.get_file_alignment()) < needed_size + image_config_data_pos)) + throw pe_exception("Insufficient space for TLS directory", pe_exception::insufficient_space); + + std::string& raw_data = image_config_section.get_raw_data(); + + //This will be done only if image_config_section is the last section of image or for section with unaligned raw length of data + if(raw_data.length() < needed_size + image_config_data_pos) + raw_data.resize(needed_size + image_config_data_pos); //Expand section raw data + + //Create and fill Image Config structure + typename PEClassType::ConfigStruct image_config_section_struct = {0}; + image_config_section_struct.Size = sizeof(image_config_section_struct); + image_config_section_struct.TimeDateStamp = info.get_time_stamp(); + image_config_section_struct.MajorVersion = info.get_major_version(); + image_config_section_struct.MinorVersion = info.get_minor_version(); + image_config_section_struct.GlobalFlagsClear = info.get_global_flags_clear(); + image_config_section_struct.GlobalFlagsSet = info.get_global_flags_set(); + image_config_section_struct.CriticalSectionDefaultTimeout = info.get_critical_section_default_timeout(); + image_config_section_struct.DeCommitFreeBlockThreshold = static_cast(info.get_decommit_free_block_threshold()); + image_config_section_struct.DeCommitTotalFreeThreshold = static_cast(info.get_decommit_total_free_threshold()); + image_config_section_struct.MaximumAllocationSize = static_cast(info.get_max_allocation_size()); + image_config_section_struct.VirtualMemoryThreshold = static_cast(info.get_virtual_memory_threshold()); + image_config_section_struct.ProcessHeapFlags = info.get_process_heap_flags(); + image_config_section_struct.ProcessAffinityMask = static_cast(info.get_process_affinity_mask()); + image_config_section_struct.CSDVersion = info.get_service_pack_version(); + image_config_section_struct.EditList = static_cast(info.get_edit_list_va()); + image_config_section_struct.SecurityCookie = static_cast(info.get_security_cookie_va()); + image_config_section_struct.SEHandlerCount = static_cast(info.get_se_handler_rvas().size()); + + + if(write_se_handlers) + { + if(info.get_se_handler_rvas().empty()) + { + write_se_handlers = false; + image_config_section_struct.SEHandlerTable = 0; + } + else + { + typename PEClassType::BaseSize va; + pe.rva_to_va(pe.rva_from_section_offset(image_config_section, current_pos_of_se_handlers), va); + image_config_section_struct.SEHandlerTable = va; + } + } + else + { + image_config_section_struct.SEHandlerTable = static_cast(info.get_se_handler_table_va()); + } + + if(write_lock_prefixes) + { + if(info.get_lock_prefix_rvas().empty()) + { + write_lock_prefixes = false; + image_config_section_struct.LockPrefixTable = 0; + } + else + { + typename PEClassType::BaseSize va; + pe.rva_to_va(pe.rva_from_section_offset(image_config_section, current_pos_of_lock_prefixes), va); + image_config_section_struct.LockPrefixTable = va; + } + } + else + { + image_config_section_struct.LockPrefixTable = static_cast(info.get_lock_prefix_table_va()); + } + + //Write image config section + memcpy(&raw_data[image_config_data_pos], &image_config_section_struct, sizeof(image_config_section_struct)); + + if(write_se_handlers) + { + //Sort SE Handlers list + image_config_info::se_handler_list sorted_list = info.get_se_handler_rvas(); + std::sort(sorted_list.begin(), sorted_list.end()); + + //Write SE Handlers table + for(image_config_info::se_handler_list::const_iterator it = sorted_list.begin(); it != sorted_list.end(); ++it) + { + uint32_t se_handler_rva = *it; + memcpy(&raw_data[current_pos_of_se_handlers], &se_handler_rva, sizeof(se_handler_rva)); + current_pos_of_se_handlers += sizeof(se_handler_rva); + } + } + + if(write_lock_prefixes) + { + //Write Lock Prefixes VA list + for(image_config_info::lock_prefix_rva_list::const_iterator it = info.get_lock_prefix_rvas().begin(); it != info.get_lock_prefix_rvas().end(); ++it) + { + typename PEClassType::BaseSize lock_prefix_va; + pe.rva_to_va(*it, lock_prefix_va); + memcpy(&raw_data[current_pos_of_lock_prefixes], &lock_prefix_va, sizeof(lock_prefix_va)); + current_pos_of_lock_prefixes += sizeof(lock_prefix_va); + } + + { + //Ending null VA + typename PEClassType::BaseSize lock_prefix_va = 0; + memcpy(&raw_data[current_pos_of_lock_prefixes], &lock_prefix_va, sizeof(lock_prefix_va)); + } + } + + //Adjust section raw and virtual sizes + pe.recalculate_section_sizes(image_config_section, auto_strip_last_section); + + image_directory ret(pe.rva_from_section_offset(image_config_section, image_config_data_pos), sizeof(typename PEClassType::ConfigStruct)); + + //If auto-rewrite of PE headers is required + if(save_to_pe_header) + { + pe.set_directory_rva(image_directory_entry_load_config, ret.get_rva()); + pe.set_directory_size(image_directory_entry_load_config, ret.get_size()); + } + + return ret; +} + +} diff --git a/drivers/pe_bliss/pe_load_config.h b/drivers/pe_bliss/pe_load_config.h new file mode 100644 index 0000000000..6e1aab25ad --- /dev/null +++ b/drivers/pe_bliss/pe_load_config.h @@ -0,0 +1,163 @@ +#pragma once +#include +#include "pe_structures.h" +#include "pe_base.h" +#include "pe_directory.h" + +namespace pe_bliss +{ +//Class representing image configuration information +class image_config_info +{ +public: + typedef std::vector se_handler_list; + typedef std::vector lock_prefix_rva_list; + +public: + //Default constructor + image_config_info(); + //Constructors from PE structures (no checks) + template + explicit image_config_info(const ConfigStructure& info); + + //Returns the date and time stamp value + uint32_t get_time_stamp() const; + //Returns major version number + uint16_t get_major_version() const; + //Returns minor version number + uint16_t get_minor_version() const; + //Returns clear global flags + uint32_t get_global_flags_clear() const; + //Returns set global flags + uint32_t get_global_flags_set() const; + //Returns critical section default timeout + uint32_t get_critical_section_default_timeout() const; + //Get the size of the minimum block that + //must be freed before it is freed (de-committed), in bytes + uint64_t get_decommit_free_block_threshold() const; + //Returns the size of the minimum total memory + //that must be freed in the process heap before it is freed (de-committed), in bytes + uint64_t get_decommit_total_free_threshold() const; + //Returns VA of a list of addresses where the LOCK prefix is used + uint64_t get_lock_prefix_table_va() const; + //Returns the maximum allocation size, in bytes + uint64_t get_max_allocation_size() const; + //Returns the maximum block size that can be allocated from heap segments, in bytes + uint64_t get_virtual_memory_threshold() const; + //Returns process affinity mask + uint64_t get_process_affinity_mask() const; + //Returns process heap flags + uint32_t get_process_heap_flags() const; + //Returns service pack version (CSDVersion) + uint16_t get_service_pack_version() const; + //Returns VA of edit list (reserved by system) + uint64_t get_edit_list_va() const; + //Returns a pointer to a cookie that is used by Visual C++ or GS implementation + uint64_t get_security_cookie_va() const; + //Returns VA of the sorted table of RVAs of each valid, unique handler in the image + uint64_t get_se_handler_table_va() const; + //Returns the count of unique handlers in the table + uint64_t get_se_handler_count() const; + + //Returns SE Handler RVA list + const se_handler_list& get_se_handler_rvas() const; + + //Returns Lock Prefix RVA list + const lock_prefix_rva_list& get_lock_prefix_rvas() const; + +public: //These functions do not change everything inside image, they are used by PE class + //Also you can use these functions to rebuild image config directory + + //Adds SE Handler RVA to list + void add_se_handler_rva(uint32_t rva); + //Clears SE Handler list + void clear_se_handler_list(); + + //Adds Lock Prefix RVA to list + void add_lock_prefix_rva(uint32_t rva); + //Clears Lock Prefix list + void clear_lock_prefix_list(); + + //Sets the date and time stamp value + void set_time_stamp(uint32_t time_stamp); + //Sets major version number + void set_major_version(uint16_t major_version); + //Sets minor version number + void set_minor_version(uint16_t minor_version); + //Sets clear global flags + void set_global_flags_clear(uint32_t global_flags_clear); + //Sets set global flags + void set_global_flags_set(uint32_t global_flags_set); + //Sets critical section default timeout + void set_critical_section_default_timeout(uint32_t critical_section_default_timeout); + //Sets the size of the minimum block that + //must be freed before it is freed (de-committed), in bytes + void set_decommit_free_block_threshold(uint64_t decommit_free_block_threshold); + //Sets the size of the minimum total memory + //that must be freed in the process heap before it is freed (de-committed), in bytes + void set_decommit_total_free_threshold(uint64_t decommit_total_free_threshold); + //Sets VA of a list of addresses where the LOCK prefix is used + //If you rebuild this list, VA will be re-assigned automatically + void set_lock_prefix_table_va(uint64_t lock_prefix_table_va); + //Sets the maximum allocation size, in bytes + void set_max_allocation_size(uint64_t max_allocation_size); + //Sets the maximum block size that can be allocated from heap segments, in bytes + void set_virtual_memory_threshold(uint64_t virtual_memory_threshold); + //Sets process affinity mask + void set_process_affinity_mask(uint64_t process_affinity_mask); + //Sets process heap flags + void set_process_heap_flags(uint32_t process_heap_flags); + //Sets service pack version (CSDVersion) + void set_service_pack_version(uint16_t service_pack_version); + //Sets VA of edit list (reserved by system) + void set_edit_list_va(uint64_t edit_list_va); + //Sets a pointer to a cookie that is used by Visual C++ or GS implementation + void set_security_cookie_va(uint64_t security_cookie_va); + //Sets VA of the sorted table of RVAs of each valid, unique handler in the image + //If you rebuild this list, VA will be re-assigned automatically + void set_se_handler_table_va(uint64_t se_handler_table_va); + + //Returns SE Handler RVA list + se_handler_list& get_se_handler_rvas(); + + //Returns Lock Prefix RVA list + lock_prefix_rva_list& get_lock_prefix_rvas(); + +private: + uint32_t time_stamp_; + uint16_t major_version_, minor_version_; + uint32_t global_flags_clear_, global_flags_set_; + uint32_t critical_section_default_timeout_; + uint64_t decommit_free_block_threshold_, decommit_total_free_threshold_; + uint64_t lock_prefix_table_va_; + uint64_t max_allocation_size_; + uint64_t virtual_memory_threshold_; + uint64_t process_affinity_mask_; + uint32_t process_heap_flags_; + uint16_t service_pack_version_; + uint64_t edit_list_va_; + uint64_t security_cookie_va_; + uint64_t se_handler_table_va_; + uint64_t se_handler_count_; + + se_handler_list se_handlers_; + lock_prefix_rva_list lock_prefixes_; +}; + +//Returns image config info +//If image does not have config info, throws an exception +const image_config_info get_image_config(const pe_base& pe); + +template +const image_config_info get_image_config_base(const pe_base& pe); + + +//Image config directory rebuilder +//auto_strip_last_section - if true and TLS are placed in the last section, it will be automatically stripped +//If write_se_handlers = true, SE Handlers list will be written just after image config directory structure +//If write_lock_prefixes = true, Lock Prefixes address list will be written just after image config directory structure +const image_directory rebuild_image_config(pe_base& pe, const image_config_info& info, section& image_config_section, uint32_t offset_from_section_start = 0, bool write_se_handlers = true, bool write_lock_prefixes = true, bool save_to_pe_header = true, bool auto_strip_last_section = true); + +template +const image_directory rebuild_image_config_base(pe_base& pe, const image_config_info& info, section& image_config_section, uint32_t offset_from_section_start = 0, bool write_se_handlers = true, bool write_lock_prefixes = true, bool save_to_pe_header = true, bool auto_strip_last_section = true); +} diff --git a/drivers/pe_bliss/pe_properties.cpp b/drivers/pe_bliss/pe_properties.cpp new file mode 100644 index 0000000000..134bf29caf --- /dev/null +++ b/drivers/pe_bliss/pe_properties.cpp @@ -0,0 +1,20 @@ +#include "pe_properties.h" + +namespace pe_bliss +{ +//Destructor +pe_properties::~pe_properties() +{} + +//Clears PE characteristics flag +void pe_properties::clear_characteristics_flags(uint16_t flags) +{ + set_characteristics(get_characteristics() & ~flags); +} + +//Sets PE characteristics flag +void pe_properties::set_characteristics_flags(uint16_t flags) +{ + set_characteristics(get_characteristics() | flags); +} +} diff --git a/drivers/pe_bliss/pe_properties.h b/drivers/pe_bliss/pe_properties.h new file mode 100644 index 0000000000..b10d803b92 --- /dev/null +++ b/drivers/pe_bliss/pe_properties.h @@ -0,0 +1,215 @@ +#pragma once +#include +#include "pe_structures.h" + +namespace pe_bliss +{ +class pe_properties +{ +public: //Constructors + virtual std::auto_ptr duplicate() const = 0; + + //Fills properly PE structures + virtual void create_pe(uint32_t section_alignment, uint16_t subsystem) = 0; + +public: + //Destructor + virtual ~pe_properties(); + + +public: //DIRECTORIES + //Returns true if directory exists + virtual bool directory_exists(uint32_t id) const = 0; + + //Removes directory + virtual void remove_directory(uint32_t id) = 0; + + //Returns directory RVA + virtual uint32_t get_directory_rva(uint32_t id) const = 0; + //Returns directory size + virtual uint32_t get_directory_size(uint32_t id) const = 0; + + //Sets directory RVA (just a value of PE header, no moving occurs) + virtual void set_directory_rva(uint32_t id, uint32_t rva) = 0; + //Sets directory size (just a value of PE header, no moving occurs) + virtual void set_directory_size(uint32_t id, uint32_t size) = 0; + + //Strips only zero DATA_DIRECTORY entries to count = min_count + //Returns resulting number of data directories + //strip_iat_directory - if true, even not empty IAT directory will be stripped + virtual uint32_t strip_data_directories(uint32_t min_count = 1, bool strip_iat_directory = true) = 0; + + +public: //IMAGE + //Returns PE type of this image + virtual pe_type get_pe_type() const = 0; + + +public: //PE HEADER + //Returns image base for PE32 and PE64 respectively + virtual uint32_t get_image_base_32() const = 0; + virtual uint64_t get_image_base_64() const = 0; + + //Sets new image base for PE32 + virtual void set_image_base(uint32_t base) = 0; + //Sets new image base for PE32/PE+ + virtual void set_image_base_64(uint64_t base) = 0; + + //Returns image entry point + virtual uint32_t get_ep() const = 0; + //Sets image entry point + virtual void set_ep(uint32_t new_ep) = 0; + + //Returns file alignment + virtual uint32_t get_file_alignment() const = 0; + //Returns section alignment + virtual uint32_t get_section_alignment() const = 0; + + //Sets heap size commit for PE32 and PE64 respectively + virtual void set_heap_size_commit(uint32_t size) = 0; + virtual void set_heap_size_commit(uint64_t size) = 0; + //Sets heap size reserve for PE32 and PE64 respectively + virtual void set_heap_size_reserve(uint32_t size) = 0; + virtual void set_heap_size_reserve(uint64_t size) = 0; + //Sets stack size commit for PE32 and PE64 respectively + virtual void set_stack_size_commit(uint32_t size) = 0; + virtual void set_stack_size_commit(uint64_t size) = 0; + //Sets stack size reserve for PE32 and PE64 respectively + virtual void set_stack_size_reserve(uint32_t size) = 0; + virtual void set_stack_size_reserve(uint64_t size) = 0; + + //Returns heap size commit for PE32 and PE64 respectively + virtual uint32_t get_heap_size_commit_32() const = 0; + virtual uint64_t get_heap_size_commit_64() const = 0; + //Returns heap size reserve for PE32 and PE64 respectively + virtual uint32_t get_heap_size_reserve_32() const = 0; + virtual uint64_t get_heap_size_reserve_64() const = 0; + //Returns stack size commit for PE32 and PE64 respectively + virtual uint32_t get_stack_size_commit_32() const = 0; + virtual uint64_t get_stack_size_commit_64() const = 0; + //Returns stack size reserve for PE32 and PE64 respectively + virtual uint32_t get_stack_size_reserve_32() const = 0; + virtual uint64_t get_stack_size_reserve_64() const = 0; + + //Returns virtual size of image + virtual uint32_t get_size_of_image() const = 0; + + //Returns number of RVA and sizes (number of DATA_DIRECTORY entries) + virtual uint32_t get_number_of_rvas_and_sizes() const = 0; + //Sets number of RVA and sizes (number of DATA_DIRECTORY entries) + virtual void set_number_of_rvas_and_sizes(uint32_t number) = 0; + + //Returns PE characteristics + virtual uint16_t get_characteristics() const = 0; + //Sets PE characteristics + virtual void set_characteristics(uint16_t ch) = 0; + + //Clears PE characteristics flag + void clear_characteristics_flags(uint16_t flags); + //Sets PE characteristics flag + void set_characteristics_flags(uint16_t flags); + + //Returns size of headers + virtual uint32_t get_size_of_headers() const = 0; + + //Returns subsystem + virtual uint16_t get_subsystem() const = 0; + + //Sets subsystem + virtual void set_subsystem(uint16_t subsystem) = 0; + + //Returns size of optional header + virtual uint16_t get_size_of_optional_header() const = 0; + + //Returns PE signature + virtual uint32_t get_pe_signature() const = 0; + + //Returns PE magic value + virtual uint32_t get_magic() const = 0; + + //Returns checksum of PE file from header + virtual uint32_t get_checksum() const = 0; + + //Sets checksum of PE file + virtual void set_checksum(uint32_t checksum) = 0; + + //Returns timestamp of PE file from header + virtual uint32_t get_time_date_stamp() const = 0; + + //Sets timestamp of PE file + virtual void set_time_date_stamp(uint32_t timestamp) = 0; + + //Returns Machine field value of PE file from header + virtual uint16_t get_machine() const = 0; + + //Sets Machine field value of PE file + virtual void set_machine(uint16_t machine) = 0; + + //Returns DLL Characteristics + virtual uint16_t get_dll_characteristics() const = 0; + + //Sets DLL Characteristics + virtual void set_dll_characteristics(uint16_t characteristics) = 0; + + //Sets required operation system version + virtual void set_os_version(uint16_t major, uint16_t minor) = 0; + + //Returns required operation system version (minor word) + virtual uint16_t get_minor_os_version() const = 0; + + //Returns required operation system version (major word) + virtual uint16_t get_major_os_version() const = 0; + + //Sets required subsystem version + virtual void set_subsystem_version(uint16_t major, uint16_t minor) = 0; + + //Returns required subsystem version (minor word) + virtual uint16_t get_minor_subsystem_version() const = 0; + + //Returns required subsystem version (major word) + virtual uint16_t get_major_subsystem_version() const = 0; + +public: //ADDRESS CONVERTIONS + //Virtual Address (VA) to Relative Virtual Address (RVA) convertions + //for PE32 and PE64 respectively + //bound_check checks integer overflow + virtual uint32_t va_to_rva(uint32_t va, bool bound_check = true) const = 0; + virtual uint32_t va_to_rva(uint64_t va, bool bound_check = true) const = 0; + + //Relative Virtual Address (RVA) to Virtual Address (VA) convertions + //for PE32 and PE64 respectively + virtual uint32_t rva_to_va_32(uint32_t rva) const = 0; + virtual uint64_t rva_to_va_64(uint32_t rva) const = 0; + + +public: //SECTIONS + //Returns number of sections + virtual uint16_t get_number_of_sections() const = 0; + +public: + //Sets number of sections + virtual void set_number_of_sections(uint16_t number) = 0; + //Sets virtual size of image + virtual void set_size_of_image(uint32_t size) = 0; + //Sets size of headers + virtual void set_size_of_headers(uint32_t size) = 0; + //Sets size of optional headers + virtual void set_size_of_optional_header(uint16_t size) = 0; + //Returns nt headers data pointer + virtual char* get_nt_headers_ptr() = 0; + //Returns nt headers data pointer + virtual const char* get_nt_headers_ptr() const = 0; + //Returns size of NT header + virtual uint32_t get_sizeof_nt_header() const = 0; + //Returns size of optional headers + virtual uint32_t get_sizeof_opt_headers() const = 0; + //Sets file alignment (no checks) + virtual void set_file_alignment_unchecked(uint32_t alignment) = 0; + //Sets base of code + virtual void set_base_of_code(uint32_t base) = 0; + //Returns base of code + virtual uint32_t get_base_of_code() const = 0; + //Returns needed PE magic for PE or PE+ (from template parameters) + virtual uint32_t get_needed_magic() const = 0; +}; +} diff --git a/drivers/pe_bliss/pe_properties_generic.cpp b/drivers/pe_bliss/pe_properties_generic.cpp new file mode 100644 index 0000000000..3b1dadd0f9 --- /dev/null +++ b/drivers/pe_bliss/pe_properties_generic.cpp @@ -0,0 +1,624 @@ +#include +#include "pe_properties_generic.h" +#include "pe_exception.h" +#include "utils.h" + +namespace pe_bliss +{ +using namespace pe_win; + +//Constructor +template +std::auto_ptr pe_properties_generic::duplicate() const +{ + return std::auto_ptr(new pe_properties_generic(*this)); +} + +//Fills properly PE structures +template +void pe_properties_generic::create_pe(uint32_t section_alignment, uint16_t subsystem) +{ + memset(&nt_headers_, 0, sizeof(nt_headers_)); + nt_headers_.Signature = 0x4550; //"PE" + nt_headers_.FileHeader.Machine = 0x14C; //i386 + nt_headers_.FileHeader.SizeOfOptionalHeader = sizeof(nt_headers_.OptionalHeader); + nt_headers_.OptionalHeader.Magic = PEClassType::Id; + nt_headers_.OptionalHeader.ImageBase = 0x400000; + nt_headers_.OptionalHeader.SectionAlignment = section_alignment; + nt_headers_.OptionalHeader.FileAlignment = 0x200; + nt_headers_.OptionalHeader.SizeOfHeaders = 1024; + nt_headers_.OptionalHeader.Subsystem = subsystem; + nt_headers_.OptionalHeader.SizeOfHeapReserve = 0x100000; + nt_headers_.OptionalHeader.SizeOfHeapCommit = 0x1000; + nt_headers_.OptionalHeader.SizeOfStackReserve = 0x100000; + nt_headers_.OptionalHeader.SizeOfStackCommit = 0x1000; + nt_headers_.OptionalHeader.NumberOfRvaAndSizes = 0x10; +} + +//Duplicate +template +pe_properties_generic::~pe_properties_generic() +{} + +//Returns true if directory exists +template +bool pe_properties_generic::directory_exists(uint32_t id) const +{ + return (nt_headers_.OptionalHeader.NumberOfRvaAndSizes - 1) >= id && + nt_headers_.OptionalHeader.DataDirectory[id].VirtualAddress; +} + +//Removes directory +template +void pe_properties_generic::remove_directory(uint32_t id) +{ + if(directory_exists(id)) + { + nt_headers_.OptionalHeader.DataDirectory[id].VirtualAddress = 0; + nt_headers_.OptionalHeader.DataDirectory[id].Size = 0; + + if(id == image_directory_entry_basereloc) + { + set_characteristics_flags(image_file_relocs_stripped); + set_dll_characteristics(get_dll_characteristics() & ~image_dllcharacteristics_dynamic_base); + } + else if(id == image_directory_entry_export) + { + clear_characteristics_flags(image_file_dll); + } + } +} + +//Returns directory RVA +template +uint32_t pe_properties_generic::get_directory_rva(uint32_t id) const +{ + //Check if directory exists + if(nt_headers_.OptionalHeader.NumberOfRvaAndSizes <= id) + throw pe_exception("Specified directory does not exist", pe_exception::directory_does_not_exist); + + return nt_headers_.OptionalHeader.DataDirectory[id].VirtualAddress; +} + +//Returns directory size +template +void pe_properties_generic::set_directory_rva(uint32_t id, uint32_t va) +{ + //Check if directory exists + if(nt_headers_.OptionalHeader.NumberOfRvaAndSizes <= id) + throw pe_exception("Specified directory does not exist", pe_exception::directory_does_not_exist); + + nt_headers_.OptionalHeader.DataDirectory[id].VirtualAddress = va; +} + +template +void pe_properties_generic::set_directory_size(uint32_t id, uint32_t size) +{ + //Check if directory exists + if(nt_headers_.OptionalHeader.NumberOfRvaAndSizes <= id) + throw pe_exception("Specified directory does not exist", pe_exception::directory_does_not_exist); + + nt_headers_.OptionalHeader.DataDirectory[id].Size = size; +} + +//Returns directory size +template +uint32_t pe_properties_generic::get_directory_size(uint32_t id) const +{ + //Check if directory exists + if(nt_headers_.OptionalHeader.NumberOfRvaAndSizes <= id) + throw pe_exception("Specified directory does not exist", pe_exception::directory_does_not_exist); + + return nt_headers_.OptionalHeader.DataDirectory[id].Size; +} + +//Strips only zero DATA_DIRECTORY entries to count = min_count +//Returns resulting number of data directories +//strip_iat_directory - if true, even not empty IAT directory will be stripped +template +uint32_t pe_properties_generic::strip_data_directories(uint32_t min_count, bool strip_iat_directory) +{ + int i = nt_headers_.OptionalHeader.NumberOfRvaAndSizes - 1; + + //Enumerate all data directories from the end + for(; i >= 0; i--) + { + //If directory exists, break + if(nt_headers_.OptionalHeader.DataDirectory[i].VirtualAddress && (static_cast(i) != image_directory_entry_iat || !strip_iat_directory)) + break; + + if(i <= static_cast(min_count) - 2) + break; + } + + if(i == image_numberof_directory_entries - 1) + return image_numberof_directory_entries; + + //Return new number of data directories + return nt_headers_.OptionalHeader.NumberOfRvaAndSizes = i + 1; +} + +//Returns image base for PE32 +template +uint32_t pe_properties_generic::get_image_base_32() const +{ + return static_cast(nt_headers_.OptionalHeader.ImageBase); +} + +//Returns image base for PE32/PE64 +template +uint64_t pe_properties_generic::get_image_base_64() const +{ + return static_cast(nt_headers_.OptionalHeader.ImageBase); +} + +//Sets new image base +template +void pe_properties_generic::set_image_base(uint32_t base) +{ + nt_headers_.OptionalHeader.ImageBase = base; +} + +//Sets new image base +template +void pe_properties_generic::set_image_base_64(uint64_t base) +{ + nt_headers_.OptionalHeader.ImageBase = static_cast(base); +} + +//Returns image entry point +template +uint32_t pe_properties_generic::get_ep() const +{ + return nt_headers_.OptionalHeader.AddressOfEntryPoint; +} + +//Sets image entry point +template +void pe_properties_generic::set_ep(uint32_t new_ep) +{ + nt_headers_.OptionalHeader.AddressOfEntryPoint = new_ep; +} + +//Returns file alignment +template +uint32_t pe_properties_generic::get_file_alignment() const +{ + return nt_headers_.OptionalHeader.FileAlignment; +} + +//Returns section alignment +template +uint32_t pe_properties_generic::get_section_alignment() const +{ + return nt_headers_.OptionalHeader.SectionAlignment; +} + +//Sets heap size commit for PE32 +template +void pe_properties_generic::set_heap_size_commit(uint32_t size) +{ + nt_headers_.OptionalHeader.SizeOfHeapCommit = static_cast(size); +} + +//Sets heap size commit for PE32/PE64 +template +void pe_properties_generic::set_heap_size_commit(uint64_t size) +{ + nt_headers_.OptionalHeader.SizeOfHeapCommit = static_cast(size); +} + +//Sets heap size reserve for PE32 +template +void pe_properties_generic::set_heap_size_reserve(uint32_t size) +{ + nt_headers_.OptionalHeader.SizeOfHeapReserve = static_cast(size); +} + +//Sets heap size reserve for PE32/PE64 +template +void pe_properties_generic::set_heap_size_reserve(uint64_t size) +{ + nt_headers_.OptionalHeader.SizeOfHeapReserve = static_cast(size); +} + +//Sets stack size commit for PE32 +template +void pe_properties_generic::set_stack_size_commit(uint32_t size) +{ + nt_headers_.OptionalHeader.SizeOfStackCommit = static_cast(size); +} + +//Sets stack size commit for PE32/PE64 +template +void pe_properties_generic::set_stack_size_commit(uint64_t size) +{ + nt_headers_.OptionalHeader.SizeOfStackCommit = static_cast(size); +} + +//Sets stack size reserve for PE32 +template +void pe_properties_generic::set_stack_size_reserve(uint32_t size) +{ + nt_headers_.OptionalHeader.SizeOfStackReserve = static_cast(size); +} + +//Sets stack size reserve for PE32/PE64 +template +void pe_properties_generic::set_stack_size_reserve(uint64_t size) +{ + nt_headers_.OptionalHeader.SizeOfStackReserve = static_cast(size); +} + +//Returns heap size commit for PE32 +template +uint32_t pe_properties_generic::get_heap_size_commit_32() const +{ + return static_cast(nt_headers_.OptionalHeader.SizeOfHeapCommit); +} + +//Returns heap size commit for PE32/PE64 +template +uint64_t pe_properties_generic::get_heap_size_commit_64() const +{ + return static_cast(nt_headers_.OptionalHeader.SizeOfHeapCommit); +} + +//Returns heap size reserve for PE32 +template +uint32_t pe_properties_generic::get_heap_size_reserve_32() const +{ + return static_cast(nt_headers_.OptionalHeader.SizeOfHeapReserve); +} + +//Returns heap size reserve for PE32/PE64 +template +uint64_t pe_properties_generic::get_heap_size_reserve_64() const +{ + return static_cast(nt_headers_.OptionalHeader.SizeOfHeapReserve); +} + +//Returns stack size commit for PE32 +template +uint32_t pe_properties_generic::get_stack_size_commit_32() const +{ + return static_cast(nt_headers_.OptionalHeader.SizeOfStackCommit); +} + +//Returns stack size commit for PE32/PE64 +template +uint64_t pe_properties_generic::get_stack_size_commit_64() const +{ + return static_cast(nt_headers_.OptionalHeader.SizeOfStackCommit); +} + +//Returns stack size reserve for PE32 +template +uint32_t pe_properties_generic::get_stack_size_reserve_32() const +{ + return static_cast(nt_headers_.OptionalHeader.SizeOfStackReserve); +} + +//Returns stack size reserve for PE32/PE64 +template +uint64_t pe_properties_generic::get_stack_size_reserve_64() const +{ + return static_cast(nt_headers_.OptionalHeader.SizeOfStackReserve); +} + +//Returns virtual size of image +template +uint32_t pe_properties_generic::get_size_of_image() const +{ + return nt_headers_.OptionalHeader.SizeOfImage; +} + +//Returns number of RVA and sizes (number of DATA_DIRECTORY entries) +template +uint32_t pe_properties_generic::get_number_of_rvas_and_sizes() const +{ + return nt_headers_.OptionalHeader.NumberOfRvaAndSizes; +} + +//Sets number of RVA and sizes (number of DATA_DIRECTORY entries) +template +void pe_properties_generic::set_number_of_rvas_and_sizes(uint32_t number) +{ + nt_headers_.OptionalHeader.NumberOfRvaAndSizes = number; +} + +//Returns PE characteristics +template +uint16_t pe_properties_generic::get_characteristics() const +{ + return nt_headers_.FileHeader.Characteristics; +} + +//Returns checksum of PE file from header +template +uint32_t pe_properties_generic::get_checksum() const +{ + return nt_headers_.OptionalHeader.CheckSum; +} + +//Sets checksum of PE file +template +void pe_properties_generic::set_checksum(uint32_t checksum) +{ + nt_headers_.OptionalHeader.CheckSum = checksum; +} + +//Returns DLL Characteristics +template +uint16_t pe_properties_generic::get_dll_characteristics() const +{ + return nt_headers_.OptionalHeader.DllCharacteristics; +} + +//Returns timestamp of PE file from header +template +uint32_t pe_properties_generic::get_time_date_stamp() const +{ + return nt_headers_.FileHeader.TimeDateStamp; +} + +//Sets timestamp of PE file +template +void pe_properties_generic::set_time_date_stamp(uint32_t timestamp) +{ + nt_headers_.FileHeader.TimeDateStamp = timestamp; +} + +//Sets DLL Characteristics +template +void pe_properties_generic::set_dll_characteristics(uint16_t characteristics) +{ + nt_headers_.OptionalHeader.DllCharacteristics = characteristics; +} + +//Returns Machine field value of PE file from header +template +uint16_t pe_properties_generic::get_machine() const +{ + return nt_headers_.FileHeader.Machine; +} + +//Sets Machine field value of PE file +template +void pe_properties_generic::set_machine(uint16_t machine) +{ + nt_headers_.FileHeader.Machine = machine; +} + +//Sets PE characteristics +template +void pe_properties_generic::set_characteristics(uint16_t ch) +{ + nt_headers_.FileHeader.Characteristics = ch; +} + +//Returns size of headers +template +uint32_t pe_properties_generic::get_size_of_headers() const +{ + return nt_headers_.OptionalHeader.SizeOfHeaders; +} + +//Returns subsystem +template +uint16_t pe_properties_generic::get_subsystem() const +{ + return nt_headers_.OptionalHeader.Subsystem; +} + +//Sets subsystem +template +void pe_properties_generic::set_subsystem(uint16_t subsystem) +{ + nt_headers_.OptionalHeader.Subsystem = subsystem; +} + +//Returns size of optional header +template +uint16_t pe_properties_generic::get_size_of_optional_header() const +{ + return nt_headers_.FileHeader.SizeOfOptionalHeader; +} + +//Returns PE signature +template +uint32_t pe_properties_generic::get_pe_signature() const +{ + return nt_headers_.Signature; +} + +//Returns PE magic value +template +uint32_t pe_properties_generic::get_magic() const +{ + return nt_headers_.OptionalHeader.Magic; +} + +//Sets required operation system version +template +void pe_properties_generic::set_os_version(uint16_t major, uint16_t minor) +{ + nt_headers_.OptionalHeader.MinorOperatingSystemVersion = minor; + nt_headers_.OptionalHeader.MajorOperatingSystemVersion = major; +} + +//Returns required operation system version (minor word) +template +uint16_t pe_properties_generic::get_minor_os_version() const +{ + return nt_headers_.OptionalHeader.MinorOperatingSystemVersion; +} + +//Returns required operation system version (major word) +template +uint16_t pe_properties_generic::get_major_os_version() const +{ + return nt_headers_.OptionalHeader.MajorOperatingSystemVersion; +} + +//Sets required subsystem version +template +void pe_properties_generic::set_subsystem_version(uint16_t major, uint16_t minor) +{ + nt_headers_.OptionalHeader.MinorSubsystemVersion = minor; + nt_headers_.OptionalHeader.MajorSubsystemVersion = major; +} + +//Returns required subsystem version (minor word) +template +uint16_t pe_properties_generic::get_minor_subsystem_version() const +{ + return nt_headers_.OptionalHeader.MinorSubsystemVersion; +} + +//Returns required subsystem version (major word) +template +uint16_t pe_properties_generic::get_major_subsystem_version() const +{ + return nt_headers_.OptionalHeader.MajorSubsystemVersion; +} + +//Virtual Address (VA) to Relative Virtual Address (RVA) convertions for PE32 +template +uint32_t pe_properties_generic::va_to_rva(uint32_t va, bool bound_check) const +{ + if(bound_check && static_cast(va) - nt_headers_.OptionalHeader.ImageBase > pe_utils::max_dword) + throw pe_exception("Incorrect address conversion", pe_exception::incorrect_address_conversion); + + return static_cast(va - nt_headers_.OptionalHeader.ImageBase); +} + +//Virtual Address (VA) to Relative Virtual Address (RVA) convertions for PE32/PE64 +template +uint32_t pe_properties_generic::va_to_rva(uint64_t va, bool bound_check) const +{ + if(bound_check && va - nt_headers_.OptionalHeader.ImageBase > pe_utils::max_dword) + throw pe_exception("Incorrect address conversion", pe_exception::incorrect_address_conversion); + + return static_cast(va - nt_headers_.OptionalHeader.ImageBase); +} + +//Relative Virtual Address (RVA) to Virtual Address (VA) convertions for PE32 +template +uint32_t pe_properties_generic::rva_to_va_32(uint32_t rva) const +{ + if(!pe_utils::is_sum_safe(rva, static_cast(nt_headers_.OptionalHeader.ImageBase))) + throw pe_exception("Incorrect address conversion", pe_exception::incorrect_address_conversion); + + return static_cast(rva + nt_headers_.OptionalHeader.ImageBase); +} + +//Relative Virtual Address (RVA) to Virtual Address (VA) convertions for PE32/PE64 +template +uint64_t pe_properties_generic::rva_to_va_64(uint32_t rva) const +{ + return static_cast(rva) + nt_headers_.OptionalHeader.ImageBase; +} + +//Returns number of sections +template +uint16_t pe_properties_generic::get_number_of_sections() const +{ + return nt_headers_.FileHeader.NumberOfSections; +} + +//Sets number of sections +template +void pe_properties_generic::set_number_of_sections(uint16_t number) +{ + nt_headers_.FileHeader.NumberOfSections = number; +} + +//Sets virtual size of image +template +void pe_properties_generic::set_size_of_image(uint32_t size) +{ + nt_headers_.OptionalHeader.SizeOfImage = size; +} + +//Sets size of headers +template +void pe_properties_generic::set_size_of_headers(uint32_t size) +{ + nt_headers_.OptionalHeader.SizeOfHeaders = size; +} + +//Sets size of optional headers +template +void pe_properties_generic::set_size_of_optional_header(uint16_t size) +{ + nt_headers_.FileHeader.SizeOfOptionalHeader = size; +} + +//Returns nt headers data pointer +template +char* pe_properties_generic::get_nt_headers_ptr() +{ + return reinterpret_cast(&nt_headers_); +} + +//Returns nt headers data pointer +template +const char* pe_properties_generic::get_nt_headers_ptr() const +{ + return reinterpret_cast(&nt_headers_); +} + +//Returns size of NT header +template +uint32_t pe_properties_generic::get_sizeof_nt_header() const +{ + return sizeof(typename PEClassType::NtHeaders); +} + +//Returns size of optional headers +template +uint32_t pe_properties_generic::get_sizeof_opt_headers() const +{ + return sizeof(typename PEClassType::OptHeaders); +} + +//Sets file alignment (no checks) +template +void pe_properties_generic::set_file_alignment_unchecked(uint32_t alignment) +{ + nt_headers_.OptionalHeader.FileAlignment = alignment; +} + +//Sets base of code +template +void pe_properties_generic::set_base_of_code(uint32_t base) +{ + nt_headers_.OptionalHeader.BaseOfCode = base; +} + +//Returns base of code +template +uint32_t pe_properties_generic::get_base_of_code() const +{ + return nt_headers_.OptionalHeader.BaseOfCode; +} + +//Returns needed PE magic for PE or PE+ (from template parameters) +template +uint32_t pe_properties_generic::get_needed_magic() const +{ + return PEClassType::Id; +} + +//Returns PE type of this image +template +pe_type pe_properties_generic::get_pe_type() const +{ + return PEClassType::Id == image_nt_optional_hdr32_magic ? pe_type_32 : pe_type_64; +} + +//Two used instantiations for PE32 (PE) and PE64 (PE+) +template class pe_properties_generic; +template class pe_properties_generic; +} diff --git a/drivers/pe_bliss/pe_properties_generic.h b/drivers/pe_bliss/pe_properties_generic.h new file mode 100644 index 0000000000..2b4a0e3c2e --- /dev/null +++ b/drivers/pe_bliss/pe_properties_generic.h @@ -0,0 +1,256 @@ +#include "pe_properties.h" + +namespace pe_bliss +{ +//Helper class to reduce code size and ease its editing +template< + typename NtHeadersType, + typename OptHeadersType, + uint16_t IdVal, + typename BaseSizeType, + BaseSizeType ImportSnapFlagVal, + typename TLSStructType, + typename ConfigStructType> +class pe_types +{ +public: + typedef NtHeadersType NtHeaders; //NT HEADERS type + typedef OptHeadersType OptHeaders; //NT OPTIONAL HEADER type + typedef BaseSizeType BaseSize; //Base size of different values: DWORD or ULONGLONG + typedef TLSStructType TLSStruct; //TLS structure type + typedef ConfigStructType ConfigStruct; //Configuration structure type + + static const uint16_t Id = IdVal; //Magic of PE or PE+ + static const BaseSize ImportSnapFlag = ImportSnapFlagVal; //Import snap flag value +}; + +//Portable Executable derived class for PE and PE+ +//Describes PE/PE+ dependent things +template +class pe_properties_generic : public pe_properties +{ +public: //Constructor + virtual std::auto_ptr duplicate() const; + + //Fills properly PE structures + virtual void create_pe(uint32_t section_alignment, uint16_t subsystem); + +public: + //Destructor + virtual ~pe_properties_generic(); + + +public: //DIRECTORIES + //Returns true if directory exists + virtual bool directory_exists(uint32_t id) const; + + //Removes directory + virtual void remove_directory(uint32_t id); + + //Returns directory RVA + virtual uint32_t get_directory_rva(uint32_t id) const; + //Returns directory size + virtual uint32_t get_directory_size(uint32_t id) const; + + //Sets directory RVA (just a value of PE header, no moving occurs) + virtual void set_directory_rva(uint32_t id, uint32_t rva); + //Sets directory size (just a value of PE header, no moving occurs) + virtual void set_directory_size(uint32_t id, uint32_t size); + + //Strips only zero DATA_DIRECTORY entries to count = min_count + //Returns resulting number of data directories + //strip_iat_directory - if true, even not empty IAT directory will be stripped + virtual uint32_t strip_data_directories(uint32_t min_count = 1, bool strip_iat_directory = true); + + +public: //IMAGE + //Returns PE type of this image + virtual pe_type get_pe_type() const; + + +public: //PE HEADER + //Returns image base for PE32 and PE64 respectively + virtual uint32_t get_image_base_32() const; + virtual uint64_t get_image_base_64() const; + + //Sets new image base for PE32 + virtual void set_image_base(uint32_t base); + //Sets new image base for PE32/PE+ + virtual void set_image_base_64(uint64_t base); + + //Returns image entry point + virtual uint32_t get_ep() const; + //Sets image entry point + virtual void set_ep(uint32_t new_ep); + + //Returns file alignment + virtual uint32_t get_file_alignment() const; + //Returns section alignment + virtual uint32_t get_section_alignment() const; + + //Sets heap size commit for PE32 and PE64 respectively + virtual void set_heap_size_commit(uint32_t size); + virtual void set_heap_size_commit(uint64_t size); + //Sets heap size reserve for PE32 and PE64 respectively + virtual void set_heap_size_reserve(uint32_t size); + virtual void set_heap_size_reserve(uint64_t size); + //Sets stack size commit for PE32 and PE64 respectively + virtual void set_stack_size_commit(uint32_t size); + virtual void set_stack_size_commit(uint64_t size); + //Sets stack size reserve for PE32 and PE64 respectively + virtual void set_stack_size_reserve(uint32_t size); + virtual void set_stack_size_reserve(uint64_t size); + + //Returns heap size commit for PE32 and PE64 respectively + virtual uint32_t get_heap_size_commit_32() const; + virtual uint64_t get_heap_size_commit_64() const; + //Returns heap size reserve for PE32 and PE64 respectively + virtual uint32_t get_heap_size_reserve_32() const; + virtual uint64_t get_heap_size_reserve_64() const; + //Returns stack size commit for PE32 and PE64 respectively + virtual uint32_t get_stack_size_commit_32() const; + virtual uint64_t get_stack_size_commit_64() const; + //Returns stack size reserve for PE32 and PE64 respectively + virtual uint32_t get_stack_size_reserve_32() const; + virtual uint64_t get_stack_size_reserve_64() const; + + //Returns virtual size of image + virtual uint32_t get_size_of_image() const; + + //Returns number of RVA and sizes (number of DATA_DIRECTORY entries) + virtual uint32_t get_number_of_rvas_and_sizes() const; + //Sets number of RVA and sizes (number of DATA_DIRECTORY entries) + virtual void set_number_of_rvas_and_sizes(uint32_t number); + + //Returns PE characteristics + virtual uint16_t get_characteristics() const; + //Sets PE characteristics + virtual void set_characteristics(uint16_t ch); + + //Returns size of headers + virtual uint32_t get_size_of_headers() const; + + //Returns subsystem + virtual uint16_t get_subsystem() const; + + //Sets subsystem + virtual void set_subsystem(uint16_t subsystem); + + //Returns size of optional header + virtual uint16_t get_size_of_optional_header() const; + + //Returns PE signature + virtual uint32_t get_pe_signature() const; + + //Returns PE magic value + virtual uint32_t get_magic() const; + + //Returns checksum of PE file from header + virtual uint32_t get_checksum() const; + + //Sets checksum of PE file + virtual void set_checksum(uint32_t checksum); + + //Returns timestamp of PE file from header + virtual uint32_t get_time_date_stamp() const; + + //Sets timestamp of PE file + virtual void set_time_date_stamp(uint32_t timestamp); + + //Returns Machine field value of PE file from header + virtual uint16_t get_machine() const; + + //Sets Machine field value of PE file + virtual void set_machine(uint16_t machine); + + //Returns DLL Characteristics + virtual uint16_t get_dll_characteristics() const; + + //Sets DLL Characteristics + virtual void set_dll_characteristics(uint16_t characteristics); + + //Sets required operation system version + virtual void set_os_version(uint16_t major, uint16_t minor); + + //Returns required operation system version (minor word) + virtual uint16_t get_minor_os_version() const; + + //Returns required operation system version (major word) + virtual uint16_t get_major_os_version() const; + + //Sets required subsystem version + virtual void set_subsystem_version(uint16_t major, uint16_t minor); + + //Returns required subsystem version (minor word) + virtual uint16_t get_minor_subsystem_version() const; + + //Returns required subsystem version (major word) + virtual uint16_t get_major_subsystem_version() const; + +public: //ADDRESS CONVERTIONS + //Virtual Address (VA) to Relative Virtual Address (RVA) convertions + //for PE32 and PE64 respectively + //bound_check checks integer overflow + virtual uint32_t va_to_rva(uint32_t va, bool bound_check = true) const; + virtual uint32_t va_to_rva(uint64_t va, bool bound_check = true) const; + + //Relative Virtual Address (RVA) to Virtual Address (VA) convertions + //for PE32 and PE64 respectively + virtual uint32_t rva_to_va_32(uint32_t rva) const; + virtual uint64_t rva_to_va_64(uint32_t rva) const; + + +public: //SECTIONS + //Returns number of sections + virtual uint16_t get_number_of_sections() const; + +protected: + typename PEClassType::NtHeaders nt_headers_; //NT headers (PE32 or PE64) + +public: + //Sets number of sections + virtual void set_number_of_sections(uint16_t number); + //Sets virtual size of image + virtual void set_size_of_image(uint32_t size); + //Sets size of headers + virtual void set_size_of_headers(uint32_t size); + //Sets size of optional headers + virtual void set_size_of_optional_header(uint16_t size); + //Returns nt headers data pointer + virtual char* get_nt_headers_ptr(); + //Returns nt headers data pointer + virtual const char* get_nt_headers_ptr() const; + //Returns size of NT header + virtual uint32_t get_sizeof_nt_header() const; + //Returns size of optional headers + virtual uint32_t get_sizeof_opt_headers() const; + //Sets file alignment (no checks) + virtual void set_file_alignment_unchecked(uint32_t alignment); + //Sets base of code + virtual void set_base_of_code(uint32_t base); + //Returns base of code + virtual uint32_t get_base_of_code() const; + //Returns needed PE magic for PE or PE+ (from template parameters) + virtual uint32_t get_needed_magic() const; +}; + +//Two used typedefs for PE32 (PE) and PE64 (PE+) +typedef pe_types pe_types_class_32; + +typedef pe_types pe_types_class_64; + +typedef pe_properties_generic pe_properties_32; +typedef pe_properties_generic pe_properties_64; +} diff --git a/drivers/pe_bliss/pe_rebuilder.cpp b/drivers/pe_bliss/pe_rebuilder.cpp new file mode 100644 index 0000000000..4d7a94fe3b --- /dev/null +++ b/drivers/pe_bliss/pe_rebuilder.cpp @@ -0,0 +1,193 @@ +#include "pe_rebuilder.h" +#include "pe_base.h" +#include "pe_structures.h" +#include "pe_exception.h" + +namespace pe_bliss +{ +using namespace pe_win; + +//Rebuilds PE image headers +//If strip_dos_header is true, DOS headers partially will be used for PE headers +//If change_size_of_headers == true, SizeOfHeaders will be recalculated automatically +//If save_bound_import == true, existing bound import directory will be saved correctly (because some compilers and bind.exe put it to PE headers) +void rebuild_pe(pe_base& pe, image_dos_header& dos_header, bool strip_dos_header, bool change_size_of_headers, bool save_bound_import) +{ + dos_header = pe.get_dos_header(); + + if(strip_dos_header) + { + //Strip stub overlay + pe.strip_stub_overlay(); + //BaseOfCode NT Headers field now overlaps + //e_lfanew field, so we're acrually setting + //e_lfanew with this call + pe.set_base_of_code(8 * sizeof(uint16_t)); + } + else + { + //Set start of PE headers + dos_header.e_lfanew = sizeof(image_dos_header) + + pe_utils::align_up(static_cast(pe.get_stub_overlay().size()), sizeof(uint32_t)); + } + + section_list& sections = pe.get_image_sections(); + + //Calculate pointer to section data + size_t ptr_to_section_data = (strip_dos_header ? 8 * sizeof(uint16_t) : sizeof(image_dos_header)) + pe.get_sizeof_nt_header() + + pe_utils::align_up(pe.get_stub_overlay().size(), sizeof(uint32_t)) + - sizeof(image_data_directory) * (image_numberof_directory_entries - pe.get_number_of_rvas_and_sizes()) + + sections.size() * sizeof(image_section_header); + + if(save_bound_import && pe.has_bound_import()) + { + //It will be aligned to DWORD, because we're aligning to DWORD everything above it + pe.set_directory_rva(image_directory_entry_bound_import, static_cast(ptr_to_section_data)); + ptr_to_section_data += pe.get_directory_size(image_directory_entry_bound_import); + } + + ptr_to_section_data = pe_utils::align_up(ptr_to_section_data, pe.get_file_alignment()); + + //Set size of headers and size of optional header + if(change_size_of_headers) + { + if(!pe.get_image_sections().empty()) + { + if(static_cast(ptr_to_section_data) > (*sections.begin()).get_virtual_address()) + throw pe_exception("Headers of PE file are too long. Try to strip STUB or don't build bound import", pe_exception::cannot_rebuild_image); + } + + pe.set_size_of_headers(static_cast(ptr_to_section_data)); + } + + //Set number of sections in PE header + pe.update_number_of_sections(); + + pe.update_image_size(); + + pe.set_size_of_optional_header(static_cast(pe.get_sizeof_opt_headers() + - sizeof(image_data_directory) * (image_numberof_directory_entries - pe.get_number_of_rvas_and_sizes()))); + + //Recalculate pointer to raw data according to section list + for(section_list::iterator it = sections.begin(); it != sections.end(); ++it) + { + //Save section headers PointerToRawData + (*it).set_pointer_to_raw_data(static_cast(ptr_to_section_data)); + ptr_to_section_data += (*it).get_aligned_raw_size(pe.get_file_alignment()); + } +} + +//Rebuild PE image and write it to "out" ostream +//If strip_dos_header is true, DOS headers partially will be used for PE headers +//If change_size_of_headers == true, SizeOfHeaders will be recalculated automatically +//If save_bound_import == true, existing bound import directory will be saved correctly (because some compilers and bind.exe put it to PE headers) +void rebuild_pe(pe_base& pe, std::ostream& out, bool strip_dos_header, bool change_size_of_headers, bool save_bound_import) +{ + if(out.bad()) + throw pe_exception("Stream is bad", pe_exception::stream_is_bad); + + if(save_bound_import && pe.has_bound_import()) + { + if(pe.section_data_length_from_rva(pe.get_directory_rva(image_directory_entry_bound_import), pe.get_directory_rva(image_directory_entry_bound_import), section_data_raw, true) + < pe.get_directory_size(image_directory_entry_bound_import)) + throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory); + } + + //Change ostream state + out.exceptions(std::ios::goodbit); + out.clear(); + + uint32_t original_bound_import_rva = pe.has_bound_import() ? pe.get_directory_rva(image_directory_entry_bound_import) : 0; + if(original_bound_import_rva && original_bound_import_rva > pe.get_size_of_headers()) + { + //No need to do anything with bound import directory + //if it is placed inside of any section, not headers + original_bound_import_rva = 0; + save_bound_import = false; + } + + { + image_dos_header dos_header; + + //Rebuild PE image headers + rebuild_pe(pe, dos_header, strip_dos_header, change_size_of_headers, save_bound_import); + + //Write DOS header + out.write(reinterpret_cast(&dos_header), strip_dos_header ? 8 * sizeof(uint16_t) : sizeof(image_dos_header)); + } + + //If we have stub overlay, write it too + { + const std::string& stub = pe.get_stub_overlay(); + if(stub.size()) + { + out.write(stub.data(), stub.size()); + size_t aligned_size = pe_utils::align_up(stub.size(), sizeof(uint32_t)); + //Align PE header, which is right after rich overlay + while(aligned_size > stub.size()) + { + out.put('\0'); + --aligned_size; + } + } + } + + //Write NT headers + out.write(static_cast(pe).get_nt_headers_ptr(), pe.get_sizeof_nt_header() + - sizeof(image_data_directory) * (image_numberof_directory_entries - pe.get_number_of_rvas_and_sizes())); + + //Write section headers + const section_list& sections = pe.get_image_sections(); + for(section_list::const_iterator it = sections.begin(); it != sections.end(); ++it) + { + if(it == sections.end() - 1) //If last section encountered + { + image_section_header header((*it).get_raw_header()); + header.SizeOfRawData = static_cast((*it).get_raw_data().length()); //Set non-aligned actual data length for it + out.write(reinterpret_cast(&header), sizeof(image_section_header)); + } + else + { + out.write(reinterpret_cast(&(*it).get_raw_header()), sizeof(image_section_header)); + } + } + + //Write bound import data if requested + if(save_bound_import && pe.has_bound_import()) + { + out.write(pe.section_data_from_rva(original_bound_import_rva, section_data_raw, true), + pe.get_directory_size(image_directory_entry_bound_import)); + } + + //Write section data finally + for(section_list::const_iterator it = sections.begin(); it != sections.end(); ++it) + { + const section& s = *it; + + std::streamoff wpos = out.tellp(); + + //Fill unused overlay data between sections with null bytes + for(unsigned int i = 0; i < s.get_pointer_to_raw_data() - wpos; i++) + out.put(0); + + //Write raw section data + out.write(s.get_raw_data().data(), s.get_raw_data().length()); + } +} + +//Rebuild PE image and write it to "out" file +//If strip_dos_header is true, DOS headers partially will be used for PE headers +//If change_size_of_headers == true, SizeOfHeaders will be recalculated automatically +//If save_bound_import == true, existing bound import directory will be saved correctly (because some compilers and bind.exe put it to PE headers) +void rebuild_pe(pe_base& pe, const char* out, bool strip_dos_header, bool change_size_of_headers, bool save_bound_import) +{ + std::ofstream pe_file(out, std::ios::out | std::ios::binary | std::ios::trunc); + if(!pe_file) + { + throw pe_exception("Error in open file.", pe_exception::stream_is_bad); + } + rebuild_pe(pe, pe_file, strip_dos_header, change_size_of_headers, save_bound_import); +} + + +} diff --git a/drivers/pe_bliss/pe_rebuilder.h b/drivers/pe_bliss/pe_rebuilder.h new file mode 100644 index 0000000000..1cd10299d1 --- /dev/null +++ b/drivers/pe_bliss/pe_rebuilder.h @@ -0,0 +1,19 @@ +#pragma once +#include +#include + +namespace pe_bliss +{ +class pe_base; +//Rebuilds PE image, writes resulting image to ostream "out". If strip_dos_header == true, DOS header will be stripped a little +//If change_size_of_headers == true, SizeOfHeaders will be recalculated automatically +//If save_bound_import == true, existing bound import directory will be saved correctly (because some compilers and bind.exe put it to PE headers) +void rebuild_pe(pe_base& pe, std::ostream& out, bool strip_dos_header = false, bool change_size_of_headers = true, bool save_bound_import = true); + +//Rebuild PE image and write it to "out" file +//If strip_dos_header is true, DOS headers partially will be used for PE headers +//If change_size_of_headers == true, SizeOfHeaders will be recalculated automatically +//If save_bound_import == true, existing bound import directory will be saved correctly (because some compilers and bind.exe put it to PE headers) +void rebuild_pe(pe_base& pe, const char* out, bool strip_dos_header = false, bool change_size_of_headers = true, bool save_bound_import = true); + +} diff --git a/drivers/pe_bliss/pe_relocations.cpp b/drivers/pe_bliss/pe_relocations.cpp new file mode 100644 index 0000000000..2d674e1346 --- /dev/null +++ b/drivers/pe_bliss/pe_relocations.cpp @@ -0,0 +1,299 @@ +#include +#include "pe_relocations.h" +#include "pe_properties_generic.h" + +namespace pe_bliss +{ +using namespace pe_win; + +//RELOCATIONS +//Default constructor +relocation_entry::relocation_entry() + :rva_(0), type_(0) +{} + +//Constructor from relocation item (WORD) +relocation_entry::relocation_entry(uint16_t relocation_value) + :rva_(relocation_value & ((1 << 12) - 1)), type_(relocation_value >> 12) +{} + +//Constructor from relative rva and relocation type +relocation_entry::relocation_entry(uint16_t rrva, uint16_t type) + :rva_(rrva), type_(type) +{} + +//Returns RVA of relocation +uint16_t relocation_entry::get_rva() const +{ + return rva_; +} + +//Returns type of relocation +uint16_t relocation_entry::get_type() const +{ + return type_; +} + +//Sets RVA of relocation +void relocation_entry::set_rva(uint16_t rva) +{ + rva_ = rva; +} + +//Sets type of relocation +void relocation_entry::set_type(uint16_t type) +{ + type_ = type; +} + +//Returns relocation item (rrva + type) +uint16_t relocation_entry::get_item() const +{ + return rva_ | (type_ << 12); +} + +//Sets relocation item (rrva + type) +void relocation_entry::set_item(uint16_t item) +{ + rva_ = item & ((1 << 12) - 1); + type_ = item >> 12; +} + +//Returns relocation list +const relocation_table::relocation_list& relocation_table::get_relocations() const +{ + return relocations_; +} + +//Adds relocation to table +void relocation_table::add_relocation(const relocation_entry& entry) +{ + relocations_.push_back(entry); +} + +//Default constructor +relocation_table::relocation_table() + :rva_(0) +{} + +//Constructor from RVA of relocation table +relocation_table::relocation_table(uint32_t rva) + :rva_(rva) +{} + +//Returns RVA of block +uint32_t relocation_table::get_rva() const +{ + return rva_; +} + +//Sets RVA of block +void relocation_table::set_rva(uint32_t rva) +{ + rva_ = rva; +} + +//Returns changeable relocation list +relocation_table::relocation_list& relocation_table::get_relocations() +{ + return relocations_; +} + +//Get relocation list of pe file, supports one-word sized relocations only +//If list_absolute_entries = true, IMAGE_REL_BASED_ABSOLUTE will be listed +const relocation_table_list get_relocations(const pe_base& pe, bool list_absolute_entries) +{ + relocation_table_list ret; + + //If image does not have relocations + if(!pe.has_reloc()) + return ret; + + //Check the length in bytes of the section containing relocation directory + if(pe.section_data_length_from_rva(pe.get_directory_rva(image_directory_entry_basereloc), + pe.get_directory_rva(image_directory_entry_basereloc), section_data_virtual, true) + < sizeof(image_base_relocation)) + throw pe_exception("Incorrect relocation directory", pe_exception::incorrect_relocation_directory); + + unsigned long current_pos = pe.get_directory_rva(image_directory_entry_basereloc); + //First IMAGE_BASE_RELOCATION table + image_base_relocation reloc_table = pe.section_data_from_rva(current_pos, section_data_virtual, true); + + if(reloc_table.SizeOfBlock % 2) + throw pe_exception("Incorrect relocation directory", pe_exception::incorrect_relocation_directory); + + unsigned long reloc_size = pe.get_directory_size(image_directory_entry_basereloc); + unsigned long read_size = 0; + + //reloc_table.VirtualAddress is not checked (not so important) + while(reloc_table.SizeOfBlock && read_size < reloc_size) + { + //Create relocation table + relocation_table table; + //Save RVA + table.set_rva(reloc_table.VirtualAddress); + + if(!pe_utils::is_sum_safe(current_pos, reloc_table.SizeOfBlock)) + throw pe_exception("Incorrect relocation directory", pe_exception::incorrect_relocation_directory); + + //List all relocations + for(unsigned long i = sizeof(image_base_relocation); i < reloc_table.SizeOfBlock; i += sizeof(uint16_t)) + { + relocation_entry entry(pe.section_data_from_rva(current_pos + i, section_data_virtual, true)); + if(list_absolute_entries || entry.get_type() != image_rel_based_absolute) + table.add_relocation(entry); + } + + //Save table + ret.push_back(table); + + //Go to next relocation block + if(!pe_utils::is_sum_safe(current_pos, reloc_table.SizeOfBlock)) + throw pe_exception("Incorrect relocation directory", pe_exception::incorrect_relocation_directory); + + current_pos += reloc_table.SizeOfBlock; + read_size += reloc_table.SizeOfBlock; + reloc_table = pe.section_data_from_rva(current_pos, section_data_virtual, true); + } + + return ret; +} + +//Simple relocations rebuilder +//To keep PE file working, don't remove any of existing relocations in +//relocation_table_list returned by a call to get_relocations() function +//auto_strip_last_section - if true and relocations are placed in the last section, it will be automatically stripped +//offset_from_section_start - offset from the beginning of reloc_section, where relocations data will be situated +//If save_to_pe_header is true, PE header will be modified automatically +const image_directory rebuild_relocations(pe_base& pe, const relocation_table_list& relocs, section& reloc_section, uint32_t offset_from_section_start, bool save_to_pe_header, bool auto_strip_last_section) +{ + //Check that reloc_section is attached to this PE image + if(!pe.section_attached(reloc_section)) + throw pe_exception("Relocations section must be attached to PE file", pe_exception::section_is_not_attached); + + uint32_t current_reloc_data_pos = pe_utils::align_up(offset_from_section_start, sizeof(uint32_t)); + + uint32_t needed_size = current_reloc_data_pos - offset_from_section_start; //Calculate needed size for relocation tables + uint32_t size_delta = needed_size; + + uint32_t start_reloc_pos = current_reloc_data_pos; + + //Enumerate relocation tables + for(relocation_table_list::const_iterator it = relocs.begin(); it != relocs.end(); ++it) + { + needed_size += static_cast((*it).get_relocations().size() * sizeof(uint16_t) /* relocations */ + sizeof(image_base_relocation) /* table header */); + //End of each table will be DWORD-aligned + if((start_reloc_pos + needed_size - size_delta) % sizeof(uint32_t)) + needed_size += sizeof(uint16_t); //Align it with IMAGE_REL_BASED_ABSOLUTE relocation + } + + //Check if reloc_section is last one. If it's not, check if there's enough place for relocations data + if(&reloc_section != &*(pe.get_image_sections().end() - 1) && + (reloc_section.empty() || pe_utils::align_up(reloc_section.get_size_of_raw_data(), pe.get_file_alignment()) < needed_size + current_reloc_data_pos)) + throw pe_exception("Insufficient space for relocations directory", pe_exception::insufficient_space); + + std::string& raw_data = reloc_section.get_raw_data(); + + //This will be done only if reloc_section is the last section of image or for section with unaligned raw length of data + if(raw_data.length() < needed_size + current_reloc_data_pos) + raw_data.resize(needed_size + current_reloc_data_pos); //Expand section raw data + + //Enumerate relocation tables + for(relocation_table_list::const_iterator it = relocs.begin(); it != relocs.end(); ++it) + { + //Create relocation table header + image_base_relocation reloc; + reloc.VirtualAddress = (*it).get_rva(); + const relocation_table::relocation_list& reloc_list = (*it).get_relocations(); + reloc.SizeOfBlock = static_cast(sizeof(image_base_relocation) + sizeof(uint16_t) * reloc_list.size()); + if((reloc_list.size() * sizeof(uint16_t)) % sizeof(uint32_t)) //If we must align end of relocation table + reloc.SizeOfBlock += sizeof(uint16_t); + + memcpy(&raw_data[current_reloc_data_pos], &reloc, sizeof(reloc)); + current_reloc_data_pos += sizeof(reloc); + + //Enumerate relocations in table + for(relocation_table::relocation_list::const_iterator r = reloc_list.begin(); r != reloc_list.end(); ++r) + { + //Save relocations + uint16_t reloc_value = (*r).get_item(); + memcpy(&raw_data[current_reloc_data_pos], &reloc_value, sizeof(reloc_value)); + current_reloc_data_pos += sizeof(reloc_value); + } + + if(current_reloc_data_pos % sizeof(uint32_t)) //If end of table is not DWORD-aligned + { + memset(&raw_data[current_reloc_data_pos], 0, sizeof(uint16_t)); //Align it with IMAGE_REL_BASED_ABSOLUTE relocation + current_reloc_data_pos += sizeof(uint16_t); + } + } + + image_directory ret(pe.rva_from_section_offset(reloc_section, start_reloc_pos), needed_size - size_delta); + + //Adjust section raw and virtual sizes + pe.recalculate_section_sizes(reloc_section, auto_strip_last_section); + + //If auto-rewrite of PE headers is required + if(save_to_pe_header) + { + pe.set_directory_rva(image_directory_entry_basereloc, ret.get_rva()); + pe.set_directory_size(image_directory_entry_basereloc, ret.get_size()); + + pe.clear_characteristics_flags(image_file_relocs_stripped); + pe.set_dll_characteristics(pe.get_dll_characteristics() | image_dllcharacteristics_dynamic_base); + } + + return ret; +} + +//Recalculates image base with the help of relocation tables +void rebase_image(pe_base& pe, const relocation_table_list& tables, uint64_t new_base) +{ + pe.get_pe_type() == pe_type_32 + ? rebase_image_base(pe, tables, new_base) + : rebase_image_base(pe, tables, new_base); +} + +//RELOCATIONS +//Recalculates image base with the help of relocation tables +//Recalculates VAs of DWORDS/QWORDS in image according to relocations +//Notice: if you move some critical structures like TLS, image relocations will not fix new +//positions of TLS VAs. Instead, some bytes that now doesn't belong to TLS will be fixed. +//It is recommended to rebase image in the very beginning and move all structures afterwards. +template +void rebase_image_base(pe_base& pe, const relocation_table_list& tables, uint64_t new_base) +{ + //Get current image base value + typename PEClassType::BaseSize image_base; + pe.get_image_base(image_base); + + //ImageBase difference + typename PEClassType::BaseSize base_rel = static_cast(static_cast(new_base) - image_base); + + //We need to fix addresses from relocation tables + //Enumerate relocation tables + for(relocation_table_list::const_iterator it = tables.begin(); it != tables.end(); ++it) + { + const relocation_table::relocation_list& relocs = (*it).get_relocations(); + + uint32_t base_rva = (*it).get_rva(); + + //Enumerate relocations + for(relocation_table::relocation_list::const_iterator rel = relocs.begin(); rel != relocs.end(); ++rel) + { + //Skip ABSOLUTE entries + if((*rel).get_type() == pe_win::image_rel_based_absolute) + continue; + + //Recalculate value by RVA and rewrite it + uint32_t current_rva = base_rva + (*rel).get_rva(); + typename PEClassType::BaseSize value = pe.section_data_from_rva(current_rva, section_data_raw, true); + value += base_rel; + memcpy(pe.section_data_from_rva(current_rva, true), &value, sizeof(value)); + } + } + + //Finally, save new image base + pe.set_image_base_64(new_base); +} +} diff --git a/drivers/pe_bliss/pe_relocations.h b/drivers/pe_bliss/pe_relocations.h new file mode 100644 index 0000000000..d4c7b19230 --- /dev/null +++ b/drivers/pe_bliss/pe_relocations.h @@ -0,0 +1,101 @@ +#pragma once +#include +#include "pe_structures.h" +#include "pe_base.h" +#include "pe_directory.h" + +namespace pe_bliss +{ +//Class representing relocation entry +//RVA of relocation is not actually RVA, but +//(real RVA) - (RVA of table) +class relocation_entry +{ +public: + //Default constructor + relocation_entry(); + //Constructor from relocation item (WORD) + explicit relocation_entry(uint16_t relocation_value); + //Constructor from relative rva and relocation type + relocation_entry(uint16_t rrva, uint16_t type); + + //Returns RVA of relocation (actually, relative RVA from relocation table RVA) + uint16_t get_rva() const; + //Returns type of relocation + uint16_t get_type() const; + + //Returns relocation item (rrva + type) + uint16_t get_item() const; + +public: //Setters do not change everything inside image, they are used by PE class + //You can also use them to rebuild relocations using rebuild_relocations() + + //Sets RVA of relocation (actually, relative RVA from relocation table RVA) + void set_rva(uint16_t rva); + //Sets type of relocation + void set_type(uint16_t type); + + //Sets relocation item (rrva + type) + void set_item(uint16_t item); + +private: + uint16_t rva_; + uint16_t type_; +}; + +//Class representing relocation table +class relocation_table +{ +public: + typedef std::vector relocation_list; + +public: + //Default constructor + relocation_table(); + //Constructor from RVA of relocation table + explicit relocation_table(uint32_t rva); + + //Returns relocation list + const relocation_list& get_relocations() const; + //Returns RVA of block + uint32_t get_rva() const; + +public: //These functions do not change everything inside image, they are used by PE class + //You can also use them to rebuild relocations using rebuild_relocations() + + //Adds relocation to table + void add_relocation(const relocation_entry& entry); + //Returns changeable relocation list + relocation_list& get_relocations(); + //Sets RVA of block + void set_rva(uint32_t rva); + +private: + uint32_t rva_; + relocation_list relocations_; +}; + +typedef std::vector relocation_table_list; + +//Get relocation list of pe file, supports one-word sized relocations only +//If list_absolute_entries = true, IMAGE_REL_BASED_ABSOLUTE will be listed +const relocation_table_list get_relocations(const pe_base& pe, bool list_absolute_entries = false); + +//Simple relocations rebuilder +//To keep PE file working, don't remove any of existing relocations in +//relocation_table_list returned by a call to get_relocations() function +//auto_strip_last_section - if true and relocations are placed in the last section, it will be automatically stripped +//offset_from_section_start - offset from the beginning of reloc_section, where relocations data will be situated +//If save_to_pe_header is true, PE header will be modified automatically +const image_directory rebuild_relocations(pe_base& pe, const relocation_table_list& relocs, section& reloc_section, uint32_t offset_from_section_start = 0, bool save_to_pe_header = true, bool auto_strip_last_section = true); + +//Recalculates image base with the help of relocation tables +//Recalculates VAs of DWORDS/QWORDS in image according to relocations +//Notice: if you move some critical structures like TLS, image relocations will not fix new +//positions of TLS VAs. Instead, some bytes that now doesn't belong to TLS will be fixed. +//It is recommended to rebase image in the very beginning and move all structures afterwards. +void rebase_image(pe_base& pe, const relocation_table_list& tables, uint64_t new_base); + +template +void rebase_image_base(pe_base& pe, const relocation_table_list& tables, uint64_t new_base); +} diff --git a/drivers/pe_bliss/pe_resource_manager.cpp b/drivers/pe_bliss/pe_resource_manager.cpp new file mode 100644 index 0000000000..1db952efcb --- /dev/null +++ b/drivers/pe_bliss/pe_resource_manager.cpp @@ -0,0 +1,265 @@ +#include +#include +#include +#include +#include +#include "pe_resource_manager.h" +#include "resource_internal.h" + +namespace pe_bliss +{ +using namespace pe_win; + +//Constructor from root resource directory +pe_resource_manager::pe_resource_manager(resource_directory& root_directory) + :pe_resource_viewer(root_directory), root_dir_edit_(root_directory) +{} + +resource_directory& pe_resource_manager::get_root_directory() +{ + return root_dir_edit_; +} + +//Removes all resources of given type or root name +//If there's more than one directory entry of a given type, only the +//first one will be deleted (that's an unusual situation) +//Returns true if resource was deleted +bool pe_resource_manager::remove_resource_type(resource_type type) +{ + //Search for resource type + resource_directory::entry_list& entries = root_dir_edit_.get_entry_list(); + resource_directory::entry_list::iterator it = std::find_if(entries.begin(), entries.end(), resource_directory::id_entry_finder(type)); + if(it != entries.end()) + { + //Remove it, if found + entries.erase(it); + return true; + } + + return false; +} + +bool pe_resource_manager::remove_resource(const std::wstring& root_name) +{ + //Search for resource type + resource_directory::entry_list& entries = root_dir_edit_.get_entry_list(); + resource_directory::entry_list::iterator it = std::find_if(entries.begin(), entries.end(), resource_directory::name_entry_finder(root_name)); + if(it != entries.end()) + { + //Remove it, if found + entries.erase(it); + return true; + } + + return false; +} + +//Helper to remove resource +bool pe_resource_manager::remove_resource(const resource_directory::entry_finder& root_finder, const resource_directory::entry_finder& finder) +{ + //Search for resource type + resource_directory::entry_list& entries_type = root_dir_edit_.get_entry_list(); + resource_directory::entry_list::iterator it_type = std::find_if(entries_type.begin(), entries_type.end(), root_finder); + if(it_type != entries_type.end()) + { + //Search for resource name/ID with "finder" + resource_directory::entry_list& entries_name = (*it_type).get_resource_directory().get_entry_list(); + resource_directory::entry_list::iterator it_name = std::find_if(entries_name.begin(), entries_name.end(), finder); + if(it_name != entries_name.end()) + { + //Erase resource, if found + entries_name.erase(it_name); + if(entries_name.empty()) + entries_type.erase(it_type); + + return true; + } + } + + return false; +} + +//Removes all resource languages by resource type/root name and name +//Deletes only one entry of given type and name +//Returns true if resource was deleted +bool pe_resource_manager::remove_resource(resource_type type, const std::wstring& name) +{ + return remove_resource(resource_directory::entry_finder(type), resource_directory::entry_finder(name)); +} + +bool pe_resource_manager::remove_resource(const std::wstring& root_name, const std::wstring& name) +{ + return remove_resource(resource_directory::entry_finder(root_name), resource_directory::entry_finder(name)); +} + +//Removes all resource languages by resource type/root name and ID +//Deletes only one entry of given type and ID +//Returns true if resource was deleted +bool pe_resource_manager::remove_resource(resource_type type, uint32_t id) +{ + return remove_resource(resource_directory::entry_finder(type), resource_directory::entry_finder(id)); +} + +bool pe_resource_manager::remove_resource(const std::wstring& root_name, uint32_t id) +{ + return remove_resource(resource_directory::entry_finder(root_name), resource_directory::entry_finder(id)); +} + +//Helper to remove resource +bool pe_resource_manager::remove_resource(const resource_directory::entry_finder& root_finder, const resource_directory::entry_finder& finder, uint32_t language) +{ + //Search for resource type + resource_directory::entry_list& entries_type = root_dir_edit_.get_entry_list(); + resource_directory::entry_list::iterator it_type = std::find_if(entries_type.begin(), entries_type.end(), root_finder); + if(it_type != entries_type.end()) + { + //Search for resource name/ID with "finder" + resource_directory::entry_list& entries_name = (*it_type).get_resource_directory().get_entry_list(); + resource_directory::entry_list::iterator it_name = std::find_if(entries_name.begin(), entries_name.end(), finder); + if(it_name != entries_name.end()) + { + //Search for resource language + resource_directory::entry_list& entries_lang = (*it_name).get_resource_directory().get_entry_list(); + resource_directory::entry_list::iterator it_lang = std::find_if(entries_lang.begin(), entries_lang.end(), resource_directory::id_entry_finder(language)); + if(it_lang != entries_lang.end()) + { + //Erase resource, if found + entries_lang.erase(it_lang); + if(entries_lang.empty()) + { + entries_name.erase(it_name); + if(entries_name.empty()) + entries_type.erase(it_type); + } + + return true; + } + } + } + + return false; +} + +//Removes resource language by resource type/root name and name +//Deletes only one entry of given type, name and language +//Returns true if resource was deleted +bool pe_resource_manager::remove_resource(resource_type type, const std::wstring& name, uint32_t language) +{ + return remove_resource(resource_directory::entry_finder(type), resource_directory::entry_finder(name), language); +} + +bool pe_resource_manager::remove_resource(const std::wstring& root_name, const std::wstring& name, uint32_t language) +{ + return remove_resource(resource_directory::entry_finder(root_name), resource_directory::entry_finder(name), language); +} + +//Removes recource language by resource type/root name and ID +//Deletes only one entry of given type, ID and language +//Returns true if resource was deleted +bool pe_resource_manager::remove_resource(resource_type type, uint32_t id, uint32_t language) +{ + return remove_resource(resource_directory::entry_finder(type), resource_directory::entry_finder(id), language); +} + +bool pe_resource_manager::remove_resource(const std::wstring& root_name, uint32_t id, uint32_t language) +{ + return remove_resource(resource_directory::entry_finder(root_name), resource_directory::entry_finder(id), language); +} + +//Helper to add/replace resource +void pe_resource_manager::add_resource(const std::string& data, resource_type type, resource_directory_entry& new_entry, const resource_directory::entry_finder& finder, uint32_t language, uint32_t codepage, uint32_t timestamp) +{ + resource_directory_entry new_type_entry; + new_type_entry.set_id(type); + + add_resource(data, new_type_entry, resource_directory::entry_finder(type), new_entry, finder, language, codepage, timestamp); +} + +//Helper to add/replace resource +void pe_resource_manager::add_resource(const std::string& data, const std::wstring& root_name, resource_directory_entry& new_entry, const resource_directory::entry_finder& finder, uint32_t language, uint32_t codepage, uint32_t timestamp) +{ + resource_directory_entry new_type_entry; + new_type_entry.set_name(root_name); + + add_resource(data, new_type_entry, resource_directory::entry_finder(root_name), new_entry, finder, language, codepage, timestamp); +} + +//Helper to add/replace resource +void pe_resource_manager::add_resource(const std::string& data, resource_directory_entry& new_root_entry, const resource_directory::entry_finder& root_finder, resource_directory_entry& new_entry, const resource_directory::entry_finder& finder, uint32_t language, uint32_t codepage, uint32_t timestamp) +{ + //Search for resource type + resource_directory::entry_list* entries = &root_dir_edit_.get_entry_list(); + resource_directory::entry_list::iterator it = std::find_if(entries->begin(), entries->end(), root_finder); + if(it == entries->end()) + { + //Add resource type directory, if it was not found + resource_directory dir; + dir.set_timestamp(timestamp); + new_root_entry.add_resource_directory(dir); + entries->push_back(new_root_entry); + it = entries->end() - 1; + } + + //Search for resource name/ID directory with "finder" + entries = &(*it).get_resource_directory().get_entry_list(); + it = std::find_if(entries->begin(), entries->end(), finder); + if(it == entries->end()) + { + //Add resource name/ID directory, if it was not found + resource_directory dir; + dir.set_timestamp(timestamp); + new_entry.add_resource_directory(dir); + entries->push_back(new_entry); + it = entries->end() - 1; + } + + //Search for data resource entry by language + entries = &(*it).get_resource_directory().get_entry_list(); + it = std::find_if(entries->begin(), entries->end(), resource_directory::id_entry_finder(language)); + if(it != entries->end()) + entries->erase(it); //Erase it, if found + + //Add new data entry + resource_directory_entry new_dir_data_entry; + resource_data_entry data_dir(data, codepage); + new_dir_data_entry.add_data_entry(data_dir); + new_dir_data_entry.set_id(language); + entries->push_back(new_dir_data_entry); +} + +//Adds resource. If resource already exists, replaces it +void pe_resource_manager::add_resource(const std::string& data, resource_type type, const std::wstring& name, uint32_t language, uint32_t codepage, uint32_t timestamp) +{ + resource_directory_entry new_entry; + new_entry.set_name(name); + + add_resource(data, type, new_entry, resource_directory::entry_finder(name), language, codepage, timestamp); +} + +//Adds resource. If resource already exists, replaces it +void pe_resource_manager::add_resource(const std::string& data, const std::wstring& root_name, const std::wstring& name, uint32_t language, uint32_t codepage, uint32_t timestamp) +{ + resource_directory_entry new_entry; + new_entry.set_name(name); + + add_resource(data, root_name, new_entry, resource_directory::entry_finder(name), language, codepage, timestamp); +} + +//Adds resource. If resource already exists, replaces it +void pe_resource_manager::add_resource(const std::string& data, resource_type type, uint32_t id, uint32_t language, uint32_t codepage, uint32_t timestamp) +{ + resource_directory_entry new_entry; + new_entry.set_id(id); + + add_resource(data, type, new_entry, resource_directory::entry_finder(id), language, codepage, timestamp); +} + +//Adds resource. If resource already exists, replaces it +void pe_resource_manager::add_resource(const std::string& data, const std::wstring& root_name, uint32_t id, uint32_t language, uint32_t codepage, uint32_t timestamp) +{ + resource_directory_entry new_entry; + new_entry.set_id(id); + + add_resource(data, root_name, new_entry, resource_directory::entry_finder(id), language, codepage, timestamp); +} +} diff --git a/drivers/pe_bliss/pe_resource_manager.h b/drivers/pe_bliss/pe_resource_manager.h new file mode 100644 index 0000000000..a12f140cfe --- /dev/null +++ b/drivers/pe_bliss/pe_resource_manager.h @@ -0,0 +1,92 @@ +#pragma once +#include +#include +#include +#include +#include "pe_base.h" +#include "pe_structures.h" +#include "pe_resources.h" +#include "message_table.h" +#include "file_version_info.h" +#include "pe_resource_viewer.h" +#include "resource_data_info.h" + +namespace pe_bliss +{ +//Derived class to edit PE resources +class pe_resource_manager : public pe_resource_viewer +{ +public: + //Constructor from root resource directory + explicit pe_resource_manager(resource_directory& root_directory); + + resource_directory& get_root_directory(); + +public: //Resource editing + //Removes all resources of given type or root name + //If there's more than one directory entry of a given type, only the + //first one will be deleted (that's an unusual situation) + //Returns true if resource was deleted + bool remove_resource_type(resource_type type); + bool remove_resource(const std::wstring& root_name); + + //Removes all resource languages by resource type/root name and name + //Deletes only one entry of given type and name + //Returns true if resource was deleted + bool remove_resource(resource_type type, const std::wstring& name); + bool remove_resource(const std::wstring& root_name, const std::wstring& name); + //Removes all resource languages by resource type/root name and ID + //Deletes only one entry of given type and ID + //Returns true if resource was deleted + bool remove_resource(resource_type type, uint32_t id); + bool remove_resource(const std::wstring& root_name, uint32_t id); + + //Removes resource language by resource type/root name and name + //Deletes only one entry of given type, name and language + //Returns true if resource was deleted + bool remove_resource(resource_type type, const std::wstring& name, uint32_t language); + bool remove_resource(const std::wstring& root_name, const std::wstring& name, uint32_t language); + //Removes recource language by resource type/root name and ID + //Deletes only one entry of given type, ID and language + //Returns true if resource was deleted + bool remove_resource(resource_type type, uint32_t id, uint32_t language); + bool remove_resource(const std::wstring& root_name, uint32_t id, uint32_t language); + + //Adds resource. If resource already exists, replaces it + //timestamp will be used for directories that will be added + void add_resource(const std::string& data, resource_type type, const std::wstring& name, uint32_t language, uint32_t codepage = 0, uint32_t timestamp = 0); + void add_resource(const std::string& data, const std::wstring& root_name, const std::wstring& name, uint32_t language, uint32_t codepage = 0, uint32_t timestamp = 0); + //Adds resource. If resource already exists, replaces it + //timestamp will be used for directories that will be added + void add_resource(const std::string& data, resource_type type, uint32_t id, uint32_t language, uint32_t codepage = 0, uint32_t timestamp = 0); + void add_resource(const std::string& data, const std::wstring& root_name, uint32_t id, uint32_t language, uint32_t codepage = 0, uint32_t timestamp = 0); + +public: + //Helpers to add/replace resource + void add_resource(const std::string& data, resource_type type, + resource_directory_entry& new_entry, + const resource_directory::entry_finder& finder, + uint32_t language, uint32_t codepage, uint32_t timestamp); + + void add_resource(const std::string& data, const std::wstring& root_name, + resource_directory_entry& new_entry, + const resource_directory::entry_finder& finder, + uint32_t language, uint32_t codepage, uint32_t timestamp); + + void add_resource(const std::string& data, resource_directory_entry& new_root_entry, + const resource_directory::entry_finder& root_finder, + resource_directory_entry& new_entry, + const resource_directory::entry_finder& finder, + uint32_t language, uint32_t codepage, uint32_t timestamp); + +private: + //Root resource directory. We're not copying it, because it might be heavy + resource_directory& root_dir_edit_; + + //Helper to remove resource + bool remove_resource(const resource_directory::entry_finder& root_finder, const resource_directory::entry_finder& finder); + + //Helper to remove resource + bool remove_resource(const resource_directory::entry_finder& root_finder, const resource_directory::entry_finder& finder, uint32_t language); +}; +} diff --git a/drivers/pe_bliss/pe_resource_viewer.cpp b/drivers/pe_bliss/pe_resource_viewer.cpp new file mode 100644 index 0000000000..1414c33fed --- /dev/null +++ b/drivers/pe_bliss/pe_resource_viewer.cpp @@ -0,0 +1,361 @@ +#include +#include +#include "pe_resource_viewer.h" +#include "pe_structures.h" + +namespace pe_bliss +{ +using namespace pe_win; + +//Constructor from root resource_directory +pe_resource_viewer::pe_resource_viewer(const resource_directory& root_directory) + :root_dir_(root_directory) +{} + +const resource_directory& pe_resource_viewer::get_root_directory() const +{ + return root_dir_; +} + +//Finder helpers +bool pe_resource_viewer::has_name::operator()(const resource_directory_entry& entry) const +{ + return entry.is_named(); +} + +bool pe_resource_viewer::has_id::operator()(const resource_directory_entry& entry) const +{ + return !entry.is_named(); +} + +//Lists resource types existing in PE file (non-named only) +const pe_resource_viewer::resource_type_list pe_resource_viewer::list_resource_types() const +{ + resource_type_list ret; + + //Get root directory entries list + const resource_directory::entry_list& entries = root_dir_.get_entry_list(); + for(resource_directory::entry_list::const_iterator it = entries.begin(); it != entries.end(); ++it) + { + //List all non-named items + if(!(*it).is_named()) + ret.push_back((*it).get_id()); + } + + return ret; +} + +//Returns true if resource type exists +bool pe_resource_viewer::resource_exists(resource_type type) const +{ + const resource_directory::entry_list& entries = root_dir_.get_entry_list(); + return std::find_if(entries.begin(), entries.end(), resource_directory::id_entry_finder(type)) != entries.end(); +} + +//Returns true if resource name exists +bool pe_resource_viewer::resource_exists(const std::wstring& root_name) const +{ + const resource_directory::entry_list& entries = root_dir_.get_entry_list(); + return std::find_if(entries.begin(), entries.end(), resource_directory::name_entry_finder(root_name)) != entries.end(); +} + +//Helper function to get name list from entry list +const pe_resource_viewer::resource_name_list pe_resource_viewer::get_name_list(const resource_directory::entry_list& entries) +{ + resource_name_list ret; + + for(resource_directory::entry_list::const_iterator it = entries.begin(); it != entries.end(); ++it) + { + //List all named items + if((*it).is_named()) + ret.push_back((*it).get_name()); + } + + return ret; +} + +//Helper function to get ID list from entry list +const pe_resource_viewer::resource_id_list pe_resource_viewer::get_id_list(const resource_directory::entry_list& entries) +{ + resource_id_list ret; + + for(resource_directory::entry_list::const_iterator it = entries.begin(); it != entries.end(); ++it) + { + //List all non-named items + if(!(*it).is_named()) + ret.push_back((*it).get_id()); + } + + return ret; +} + +//Lists resource names existing in PE file by resource type +const pe_resource_viewer::resource_name_list pe_resource_viewer::list_resource_names(resource_type type) const +{ + return get_name_list(root_dir_.entry_by_id(type).get_resource_directory().get_entry_list()); +} + +//Lists resource names existing in PE file by resource name +const pe_resource_viewer::resource_name_list pe_resource_viewer::list_resource_names(const std::wstring& root_name) const +{ + return get_name_list(root_dir_.entry_by_name(root_name).get_resource_directory().get_entry_list()); +} + +//Lists resource IDs existing in PE file by resource type +const pe_resource_viewer::resource_id_list pe_resource_viewer::list_resource_ids(resource_type type) const +{ + return get_id_list(root_dir_.entry_by_id(type).get_resource_directory().get_entry_list()); +} + +//Lists resource IDs existing in PE file by resource name +const pe_resource_viewer::resource_id_list pe_resource_viewer::list_resource_ids(const std::wstring& root_name) const +{ + return get_id_list(root_dir_.entry_by_name(root_name).get_resource_directory().get_entry_list()); +} + +//Returns resource count by type +unsigned long pe_resource_viewer::get_resource_count(resource_type type) const +{ + return static_cast( + root_dir_ //Type directory + .entry_by_id(type) + .get_resource_directory() //Name/ID directory + .get_entry_list() + .size()); +} + +//Returns resource count by name +unsigned long pe_resource_viewer::get_resource_count(const std::wstring& root_name) const +{ + return static_cast( + root_dir_ //Type directory + .entry_by_name(root_name) + .get_resource_directory() //Name/ID directory + .get_entry_list() + .size()); +} + +//Returns language count of resource by resource type and name +unsigned long pe_resource_viewer::get_language_count(resource_type type, const std::wstring& name) const +{ + const resource_directory::entry_list& entries = + root_dir_ //Type directory + .entry_by_id(type) + .get_resource_directory() //Name/ID directory + .entry_by_name(name) + .get_resource_directory() //Language directory + .get_entry_list(); + + return static_cast(std::count_if(entries.begin(), entries.end(), has_id())); +} + +//Returns language count of resource by resource names +unsigned long pe_resource_viewer::get_language_count(const std::wstring& root_name, const std::wstring& name) const +{ + const resource_directory::entry_list& entries = + root_dir_ //Type directory + .entry_by_name(root_name) + .get_resource_directory() //Name/ID directory + .entry_by_name(name) + .get_resource_directory() //Language directory + .get_entry_list(); + + return static_cast(std::count_if(entries.begin(), entries.end(), has_id())); +} + +//Returns language count of resource by resource type and ID +unsigned long pe_resource_viewer::get_language_count(resource_type type, uint32_t id) const +{ + const resource_directory::entry_list& entries = + root_dir_ //Type directory + .entry_by_id(type) + .get_resource_directory() //Name/ID directory + .entry_by_id(id) + .get_resource_directory() //Language directory + .get_entry_list(); + + return static_cast(std::count_if(entries.begin(), entries.end(), has_id())); +} + +//Returns language count of resource by resource name and ID +unsigned long pe_resource_viewer::get_language_count(const std::wstring& root_name, uint32_t id) const +{ + const resource_directory::entry_list& entries = + root_dir_ //Type directory + .entry_by_name(root_name) + .get_resource_directory() //Name/ID directory + .entry_by_id(id) + .get_resource_directory() //Language directory + .get_entry_list(); + + return static_cast(std::count_if(entries.begin(), entries.end(), has_id())); +} + +//Lists resource languages by resource type and name +const pe_resource_viewer::resource_language_list pe_resource_viewer::list_resource_languages(resource_type type, const std::wstring& name) const +{ + const resource_directory::entry_list& entries = + root_dir_ //Type directory + .entry_by_id(type) + .get_resource_directory() //Name/ID directory + .entry_by_name(name) + .get_resource_directory() //Language directory + .get_entry_list(); + + return get_id_list(entries); +} + +//Lists resource languages by resource names +const pe_resource_viewer::resource_language_list pe_resource_viewer::list_resource_languages(const std::wstring& root_name, const std::wstring& name) const +{ + const resource_directory::entry_list& entries = + root_dir_ //Type directory + .entry_by_name(root_name) + .get_resource_directory() //Name/ID directory + .entry_by_name(name) + .get_resource_directory() //Language directory + .get_entry_list(); + + return get_id_list(entries); +} + +//Lists resource languages by resource type and ID +const pe_resource_viewer::resource_language_list pe_resource_viewer::list_resource_languages(resource_type type, uint32_t id) const +{ + const resource_directory::entry_list& entries = + root_dir_ //Type directory + .entry_by_id(type) + .get_resource_directory() //Name/ID directory + .entry_by_id(id) + .get_resource_directory() //Language directory + .get_entry_list(); + + return get_id_list(entries); +} + +//Lists resource languages by resource name and ID +const pe_resource_viewer::resource_language_list pe_resource_viewer::list_resource_languages(const std::wstring& root_name, uint32_t id) const +{ + const resource_directory::entry_list& entries = + root_dir_ //Type directory + .entry_by_name(root_name) + .get_resource_directory() //Name/ID directory + .entry_by_id(id) + .get_resource_directory() //Language directory + .get_entry_list(); + + return get_id_list(entries); +} + +//Returns raw resource data by type, name and language +const resource_data_info pe_resource_viewer::get_resource_data_by_name(uint32_t language, resource_type type, const std::wstring& name) const +{ + return resource_data_info(root_dir_ //Type directory + .entry_by_id(type) + .get_resource_directory() //Name/ID directory + .entry_by_name(name) + .get_resource_directory() //Language directory + .entry_by_id(language) + .get_data_entry()); //Data directory +} + +//Returns raw resource data by root name, name and language +const resource_data_info pe_resource_viewer::get_resource_data_by_name(uint32_t language, const std::wstring& root_name, const std::wstring& name) const +{ + return resource_data_info(root_dir_ //Type directory + .entry_by_name(root_name) + .get_resource_directory() //Name/ID directory + .entry_by_name(name) + .get_resource_directory() //Language directory + .entry_by_id(language) + .get_data_entry()); //Data directory +} + +//Returns raw resource data by type, ID and language +const resource_data_info pe_resource_viewer::get_resource_data_by_id(uint32_t language, resource_type type, uint32_t id) const +{ + return resource_data_info(root_dir_ //Type directory + .entry_by_id(type) + .get_resource_directory() //Name/ID directory + .entry_by_id(id) + .get_resource_directory() //Language directory + .entry_by_id(language) + .get_data_entry()); //Data directory +} + +//Returns raw resource data by root name, ID and language +const resource_data_info pe_resource_viewer::get_resource_data_by_id(uint32_t language, const std::wstring& root_name, uint32_t id) const +{ + return resource_data_info(root_dir_ //Type directory + .entry_by_name(root_name) + .get_resource_directory() //Name/ID directory + .entry_by_id(id) + .get_resource_directory() //Language directory + .entry_by_id(language) + .get_data_entry()); //Data directory +} + +//Returns raw resource data by type, name and index in language directory (instead of language) +const resource_data_info pe_resource_viewer::get_resource_data_by_name(resource_type type, const std::wstring& name, uint32_t index) const +{ + const resource_directory::entry_list& entries = root_dir_ //Type directory + .entry_by_id(type) + .get_resource_directory() //Name/ID directory + .entry_by_name(name) + .get_resource_directory() //Language directory + .get_entry_list(); + + if(entries.size() <= index) + throw pe_exception("Resource data entry not found", pe_exception::resource_data_entry_not_found); + + return resource_data_info(entries.at(index).get_data_entry()); //Data directory +} + +//Returns raw resource data by root name, name and index in language directory (instead of language) +const resource_data_info pe_resource_viewer::get_resource_data_by_name(const std::wstring& root_name, const std::wstring& name, uint32_t index) const +{ + const resource_directory::entry_list& entries = root_dir_ //Type directory + .entry_by_name(root_name) + .get_resource_directory() //Name/ID directory + .entry_by_name(name) + .get_resource_directory() //Language directory + .get_entry_list(); + + if(entries.size() <= index) + throw pe_exception("Resource data entry not found", pe_exception::resource_data_entry_not_found); + + return resource_data_info(entries.at(index).get_data_entry()); //Data directory +} + +//Returns raw resource data by type, ID and index in language directory (instead of language) +const resource_data_info pe_resource_viewer::get_resource_data_by_id(resource_type type, uint32_t id, uint32_t index) const +{ + const resource_directory::entry_list& entries = root_dir_ //Type directory + .entry_by_id(type) + .get_resource_directory() //Name/ID directory + .entry_by_id(id) + .get_resource_directory() //Language directory + .get_entry_list(); + + if(entries.size() <= index) + throw pe_exception("Resource data entry not found", pe_exception::resource_data_entry_not_found); + + return resource_data_info(entries.at(index).get_data_entry()); //Data directory +} + +//Returns raw resource data by root name, ID and index in language directory (instead of language) +const resource_data_info pe_resource_viewer::get_resource_data_by_id(const std::wstring& root_name, uint32_t id, uint32_t index) const +{ + const resource_directory::entry_list& entries = root_dir_ //Type directory + .entry_by_name(root_name) + .get_resource_directory() //Name/ID directory + .entry_by_id(id) + .get_resource_directory() //Language directory + .get_entry_list(); + + if(entries.size() <= index) + throw pe_exception("Resource data entry not found", pe_exception::resource_data_entry_not_found); + + return resource_data_info(entries.at(index).get_data_entry()); //Data directory +} +} diff --git a/drivers/pe_bliss/pe_resource_viewer.h b/drivers/pe_bliss/pe_resource_viewer.h new file mode 100644 index 0000000000..f469d59143 --- /dev/null +++ b/drivers/pe_bliss/pe_resource_viewer.h @@ -0,0 +1,132 @@ +#pragma once +#include +#include +#include "pe_structures.h" +#include "pe_resources.h" +#include "message_table.h" +#include "resource_data_info.h" + +namespace pe_bliss +{ + //PE resource manager allows to read resources from PE files +class pe_resource_viewer +{ +public: + //Resource type enumeration + enum resource_type + { + resource_cursor = 1, + resource_bitmap = 2, + resource_icon = 3, + resource_menu = 4, + resource_dialog = 5, + resource_string = 6, + resource_fontdir = 7, + resource_font = 8, + resource_accelerator = 9, + resource_rcdata = 10, + resource_message_table = 11, + resource_cursor_group = 12, + resource_icon_group = 14, + resource_version = 16, + resource_dlginclude = 17, + resource_plugplay = 19, + resource_vxd = 20, + resource_anicursor = 21, + resource_aniicon = 22, + resource_html = 23, + resource_manifest = 24 + }; + +public: + //Some useful typedefs + typedef std::vector resource_type_list; + typedef std::vector resource_id_list; + typedef std::vector resource_name_list; + typedef std::vector resource_language_list; + +public: + //Constructor from root resource_directory from PE file + explicit pe_resource_viewer(const resource_directory& root_directory); + + const resource_directory& get_root_directory() const; + + //Lists resource types existing in PE file (non-named only) + const resource_type_list list_resource_types() const; + //Returns true if resource type exists + bool resource_exists(resource_type type) const; + //Returns true if resource name exists + bool resource_exists(const std::wstring& root_name) const; + + //Lists resource names existing in PE file by resource type + const resource_name_list list_resource_names(resource_type type) const; + //Lists resource names existing in PE file by resource name + const resource_name_list list_resource_names(const std::wstring& root_name) const; + //Lists resource IDs existing in PE file by resource type + const resource_id_list list_resource_ids(resource_type type) const; + //Lists resource IDs existing in PE file by resource name + const resource_id_list list_resource_ids(const std::wstring& root_name) const; + //Returns resource count by type + unsigned long get_resource_count(resource_type type) const; + //Returns resource count by name + unsigned long get_resource_count(const std::wstring& root_name) const; + + //Returns language count of resource by resource type and name + unsigned long get_language_count(resource_type type, const std::wstring& name) const; + //Returns language count of resource by resource names + unsigned long get_language_count(const std::wstring& root_name, const std::wstring& name) const; + //Returns language count of resource by resource type and ID + unsigned long get_language_count(resource_type type, uint32_t id) const; + //Returns language count of resource by resource name and ID + unsigned long get_language_count(const std::wstring& root_name, uint32_t id) const; + //Lists resource languages by resource type and name + const resource_language_list list_resource_languages(resource_type type, const std::wstring& name) const; + //Lists resource languages by resource names + const resource_language_list list_resource_languages(const std::wstring& root_name, const std::wstring& name) const; + //Lists resource languages by resource type and ID + const resource_language_list list_resource_languages(resource_type type, uint32_t id) const; + //Lists resource languages by resource name and ID + const resource_language_list list_resource_languages(const std::wstring& root_name, uint32_t id) const; + + //Returns raw resource data by type, name and language + const resource_data_info get_resource_data_by_name(uint32_t language, resource_type type, const std::wstring& name) const; + //Returns raw resource data by root name, name and language + const resource_data_info get_resource_data_by_name(uint32_t language, const std::wstring& root_name, const std::wstring& name) const; + //Returns raw resource data by type, ID and language + const resource_data_info get_resource_data_by_id(uint32_t language, resource_type type, uint32_t id) const; + //Returns raw resource data by root name, ID and language + const resource_data_info get_resource_data_by_id(uint32_t language, const std::wstring& root_name, uint32_t id) const; + //Returns raw resource data by type, name and index in language directory (instead of language) + const resource_data_info get_resource_data_by_name(resource_type type, const std::wstring& name, uint32_t index = 0) const; + //Returns raw resource data by root name, name and index in language directory (instead of language) + const resource_data_info get_resource_data_by_name(const std::wstring& root_name, const std::wstring& name, uint32_t index = 0) const; + //Returns raw resource data by type, ID and index in language directory (instead of language) + const resource_data_info get_resource_data_by_id(resource_type type, uint32_t id, uint32_t index = 0) const; + //Returns raw resource data by root name, ID and index in language directory (instead of language) + const resource_data_info get_resource_data_by_id(const std::wstring& root_name, uint32_t id, uint32_t index = 0) const; + +protected: + //Root resource directory. We're not copying it, because it might be heavy + const resource_directory& root_dir_; + + //Helper function to get ID list from entry list + static const resource_id_list get_id_list(const resource_directory::entry_list& entries); + //Helper function to get name list from entry list + static const resource_name_list get_name_list(const resource_directory::entry_list& entries); + +protected: + //Helper structure - finder of resource_directory_entry that is named + struct has_name + { + public: + bool operator()(const resource_directory_entry& entry) const; + }; + + //Helper structure - finder of resource_directory_entry that is not named (has id) + struct has_id + { + public: + bool operator()(const resource_directory_entry& entry) const; + }; +}; +} diff --git a/drivers/pe_bliss/pe_resources.cpp b/drivers/pe_bliss/pe_resources.cpp new file mode 100644 index 0000000000..a819c7bb71 --- /dev/null +++ b/drivers/pe_bliss/pe_resources.cpp @@ -0,0 +1,705 @@ +#include +#include +#include "pe_resources.h" + +namespace pe_bliss +{ +using namespace pe_win; + +//RESOURCES +//Default constructor +resource_data_entry::resource_data_entry() + :codepage_(0) +{} + +//Constructor from data +resource_data_entry::resource_data_entry(const std::string& data, uint32_t codepage) + :codepage_(codepage), data_(data) +{} + +//Returns resource data codepage +uint32_t resource_data_entry::get_codepage() const +{ + return codepage_; +} + +//Returns resource data +const std::string& resource_data_entry::get_data() const +{ + return data_; +} + +//Sets resource data codepage +void resource_data_entry::set_codepage(uint32_t codepage) +{ + codepage_ = codepage; +} + +//Sets resource data +void resource_data_entry::set_data(const std::string& data) +{ + data_ = data; +} + +//Default constructor +resource_directory_entry::includes::includes() + :data_(0) +{} + +//Default constructor +resource_directory_entry::resource_directory_entry() + :id_(0), includes_data_(false), named_(false) +{} + +//Copy constructor +resource_directory_entry::resource_directory_entry(const resource_directory_entry& other) + :id_(other.id_), name_(other.name_), includes_data_(other.includes_data_), named_(other.named_) +{ + //If union'ed pointer is not zero + if(other.ptr_.data_) + { + if(other.includes_data()) + ptr_.data_ = new resource_data_entry(*other.ptr_.data_); + else + ptr_.dir_ = new resource_directory(*other.ptr_.dir_); + } +} + +//Copy assignment operator +resource_directory_entry& resource_directory_entry::operator=(const resource_directory_entry& other) +{ + release(); + + id_ = other.id_; + name_ = other.name_; + includes_data_ = other.includes_data_; + named_ = other.named_; + + //If other union'ed pointer is not zero + if(other.ptr_.data_) + { + if(other.includes_data()) + ptr_.data_ = new resource_data_entry(*other.ptr_.data_); + else + ptr_.dir_ = new resource_directory(*other.ptr_.dir_); + } + + return *this; +} + +//Destroys included data +void resource_directory_entry::release() +{ + //If union'ed pointer is not zero + if(ptr_.data_) + { + if(includes_data()) + delete ptr_.data_; + else + delete ptr_.dir_; + + ptr_.data_ = 0; + } +} + +//Destructor +resource_directory_entry::~resource_directory_entry() +{ + release(); +} + +//Returns entry ID +uint32_t resource_directory_entry::get_id() const +{ + return id_; +} + +//Returns entry name +const std::wstring& resource_directory_entry::get_name() const +{ + return name_; +} + +//Returns true, if entry has name +//Returns false, if entry has ID +bool resource_directory_entry::is_named() const +{ + return named_; +} + +//Returns true, if entry includes resource_data_entry +//Returns false, if entry includes resource_directory +bool resource_directory_entry::includes_data() const +{ + return includes_data_; +} + +//Returns resource_directory if entry includes it, otherwise throws an exception +const resource_directory& resource_directory_entry::get_resource_directory() const +{ + if(!ptr_.dir_ || includes_data_) + throw pe_exception("Resource directory entry does not contain resource directory", pe_exception::resource_directory_entry_error); + + return *ptr_.dir_; +} + +//Returns resource_data_entry if entry includes it, otherwise throws an exception +const resource_data_entry& resource_directory_entry::get_data_entry() const +{ + if(!ptr_.data_ || !includes_data_) + throw pe_exception("Resource directory entry does not contain resource data entry", pe_exception::resource_directory_entry_error); + + return *ptr_.data_; +} + +//Returns resource_directory if entry includes it, otherwise throws an exception +resource_directory& resource_directory_entry::get_resource_directory() +{ + if(!ptr_.dir_ || includes_data_) + throw pe_exception("Resource directory entry does not contain resource directory", pe_exception::resource_directory_entry_error); + + return *ptr_.dir_; +} + +//Returns resource_data_entry if entry includes it, otherwise throws an exception +resource_data_entry& resource_directory_entry::get_data_entry() +{ + if(!ptr_.data_ || !includes_data_) + throw pe_exception("Resource directory entry does not contain resource data entry", pe_exception::resource_directory_entry_error); + + return *ptr_.data_; +} + +//Sets entry name +void resource_directory_entry::set_name(const std::wstring& name) +{ + name_ = name; + named_ = true; + id_ = 0; +} + +//Sets entry ID +void resource_directory_entry::set_id(uint32_t id) +{ + id_ = id; + named_ = false; + name_.clear(); +} + +//Adds resource_data_entry +void resource_directory_entry::add_data_entry(const resource_data_entry& entry) +{ + release(); + ptr_.data_ = new resource_data_entry(entry); + includes_data_ = true; +} + +//Adds resource_directory +void resource_directory_entry::add_resource_directory(const resource_directory& dir) +{ + release(); + ptr_.dir_ = new resource_directory(dir); + includes_data_ = false; +} + +//Default constructor +resource_directory::resource_directory() + :characteristics_(0), + timestamp_(0), + major_version_(0), minor_version_(0), + number_of_named_entries_(0), number_of_id_entries_(0) +{} + +//Constructor from data +resource_directory::resource_directory(const image_resource_directory& dir) + :characteristics_(dir.Characteristics), + timestamp_(dir.TimeDateStamp), + major_version_(dir.MajorVersion), minor_version_(dir.MinorVersion), + number_of_named_entries_(0), number_of_id_entries_(0) //Set to zero here, calculate on add +{} + +//Returns characteristics of directory +uint32_t resource_directory::get_characteristics() const +{ + return characteristics_; +} + +//Returns date and time stamp of directory +uint32_t resource_directory::get_timestamp() const +{ + return timestamp_; +} + +//Returns major version of directory +uint16_t resource_directory::get_major_version() const +{ + return major_version_; +} + +//Returns minor version of directory +uint16_t resource_directory::get_minor_version() const +{ + return minor_version_; +} + +//Returns number of named entries +uint32_t resource_directory::get_number_of_named_entries() const +{ + return number_of_named_entries_; +} + +//Returns number of ID entries +uint32_t resource_directory::get_number_of_id_entries() const +{ + return number_of_id_entries_; +} + +//Returns resource_directory_entry array +const resource_directory::entry_list& resource_directory::get_entry_list() const +{ + return entries_; +} + +//Returns resource_directory_entry array +resource_directory::entry_list& resource_directory::get_entry_list() +{ + return entries_; +} + +//Adds resource_directory_entry +void resource_directory::add_resource_directory_entry(const resource_directory_entry& entry) +{ + entries_.push_back(entry); + if(entry.is_named()) + ++number_of_named_entries_; + else + ++number_of_id_entries_; +} + +//Clears resource_directory_entry array +void resource_directory::clear_resource_directory_entry_list() +{ + entries_.clear(); + number_of_named_entries_ = 0; + number_of_id_entries_ = 0; +} + +//Sets characteristics of directory +void resource_directory::set_characteristics(uint32_t characteristics) +{ + characteristics_ = characteristics; +} + +//Sets date and time stamp of directory +void resource_directory::set_timestamp(uint32_t timestamp) +{ + timestamp_ = timestamp; +} + +//Sets number of named entries +void resource_directory::set_number_of_named_entries(uint32_t number) +{ + number_of_named_entries_ = number; +} + +//Sets number of ID entries +void resource_directory::set_number_of_id_entries(uint32_t number) +{ + number_of_id_entries_ = number; +} + +//Sets major version of directory +void resource_directory::set_major_version(uint16_t major_version) +{ + major_version_ = major_version; +} + +//Sets minor version of directory +void resource_directory::get_minor_version(uint16_t minor_version) +{ + minor_version_ = minor_version; +} + +//Processes resource directory +const resource_directory process_resource_directory(const pe_base& pe, uint32_t res_rva, uint32_t offset_to_directory, std::set& processed) +{ + resource_directory ret; + + //Check for resource loops + if(!processed.insert(offset_to_directory).second) + throw pe_exception("Incorrect resource directory", pe_exception::incorrect_resource_directory); + + if(!pe_utils::is_sum_safe(res_rva, offset_to_directory)) + throw pe_exception("Incorrect resource directory", pe_exception::incorrect_resource_directory); + + //Get root IMAGE_RESOURCE_DIRECTORY + image_resource_directory directory = pe.section_data_from_rva(res_rva + offset_to_directory, section_data_virtual, true); + + ret = resource_directory(directory); + + //Check DWORDs for possible overflows + if(!pe_utils::is_sum_safe(directory.NumberOfIdEntries, directory.NumberOfNamedEntries) + || directory.NumberOfIdEntries + directory.NumberOfNamedEntries >= pe_utils::max_dword / sizeof(image_resource_directory_entry) + sizeof(image_resource_directory)) + throw pe_exception("Incorrect resource directory", pe_exception::incorrect_resource_directory); + + if(!pe_utils::is_sum_safe(offset_to_directory, sizeof(image_resource_directory) + (directory.NumberOfIdEntries + directory.NumberOfNamedEntries) * sizeof(image_resource_directory_entry)) + || !pe_utils::is_sum_safe(res_rva, offset_to_directory + sizeof(image_resource_directory) + (directory.NumberOfIdEntries + directory.NumberOfNamedEntries) * sizeof(image_resource_directory_entry))) + throw pe_exception("Incorrect resource directory", pe_exception::incorrect_resource_directory); + + for(unsigned long i = 0; i != static_cast(directory.NumberOfIdEntries) + directory.NumberOfNamedEntries; ++i) + { + //Read directory entries one by one + image_resource_directory_entry dir_entry = pe.section_data_from_rva( + res_rva + sizeof(image_resource_directory) + i * sizeof(image_resource_directory_entry) + offset_to_directory, section_data_virtual, true); + + //Create directory entry structure + resource_directory_entry entry; + + //If directory is named + if(dir_entry.NameIsString) + { + if(!pe_utils::is_sum_safe(res_rva + sizeof(uint16_t) /* safe */, dir_entry.NameOffset)) + throw pe_exception("Incorrect resource directory", pe_exception::incorrect_resource_directory); + + //get directory name length + uint16_t directory_name_length = pe.section_data_from_rva(res_rva + dir_entry.NameOffset, section_data_virtual, true); + + //Check name length + if(pe.section_data_length_from_rva(res_rva + dir_entry.NameOffset + sizeof(uint16_t), res_rva + dir_entry.NameOffset + sizeof(uint16_t), section_data_virtual, true) + < directory_name_length) + throw pe_exception("Incorrect resource directory", pe_exception::incorrect_resource_directory); + +#ifdef PE_BLISS_WINDOWS + //Set entry UNICODE name + entry.set_name(std::wstring( + reinterpret_cast(pe.section_data_from_rva(res_rva + dir_entry.NameOffset + sizeof(uint16_t), section_data_virtual, true)), + directory_name_length)); +#else + //Set entry UNICODE name + entry.set_name(pe_utils::from_ucs2(u16string( + reinterpret_cast(pe.section_data_from_rva(res_rva + dir_entry.NameOffset + sizeof(uint16_t), section_data_virtual, true)), + directory_name_length))); +#endif + } + else + { + //Else - set directory ID + entry.set_id(dir_entry.Id); + } + + //If directory entry has another resource directory + if(dir_entry.DataIsDirectory) + { + entry.add_resource_directory(process_resource_directory(pe, res_rva, dir_entry.OffsetToDirectory, processed)); + } + else + { + //If directory entry has data + image_resource_data_entry data_entry = pe.section_data_from_rva( + res_rva + dir_entry.OffsetToData, section_data_virtual, true); + + //Check byte count that stated by data entry + if(pe.section_data_length_from_rva(data_entry.OffsetToData, data_entry.OffsetToData, section_data_virtual, true) < data_entry.Size) + throw pe_exception("Incorrect resource directory", pe_exception::incorrect_resource_directory); + + //Add data entry to directory entry + entry.add_data_entry(resource_data_entry( + std::string(pe.section_data_from_rva(data_entry.OffsetToData, section_data_virtual, true), data_entry.Size), + data_entry.CodePage)); + } + + //Save directory entry + ret.add_resource_directory_entry(entry); + } + + //Return resource directory + return ret; +} + +//Helper function to calculate needed space for resource data +void calculate_resource_data_space(const resource_directory& root, uint32_t aligned_offset_from_section_start, uint32_t& needed_size_for_structures, uint32_t& needed_size_for_strings) +{ + needed_size_for_structures += sizeof(image_resource_directory); + for(resource_directory::entry_list::const_iterator it = root.get_entry_list().begin(); it != root.get_entry_list().end(); ++it) + { + needed_size_for_structures += sizeof(image_resource_directory_entry); + + if((*it).is_named()) + needed_size_for_strings += static_cast(((*it).get_name().length() + 1) * 2 /* unicode */ + sizeof(uint16_t) /* for string length */); + + if(!(*it).includes_data()) + calculate_resource_data_space((*it).get_resource_directory(), aligned_offset_from_section_start, needed_size_for_structures, needed_size_for_strings); + } +} + +//Helper function to calculate needed space for resource data +void calculate_resource_data_space(const resource_directory& root, uint32_t needed_size_for_structures, uint32_t needed_size_for_strings, uint32_t& needed_size_for_data, uint32_t& current_data_pos) +{ + for(resource_directory::entry_list::const_iterator it = root.get_entry_list().begin(); it != root.get_entry_list().end(); ++it) + { + if((*it).includes_data()) + { + uint32_t data_size = static_cast((*it).get_data_entry().get_data().length() + + sizeof(image_resource_data_entry) + + (pe_utils::align_up(current_data_pos, sizeof(uint32_t)) - current_data_pos) /* alignment */); + needed_size_for_data += data_size; + current_data_pos += data_size; + } + else + { + calculate_resource_data_space((*it).get_resource_directory(), needed_size_for_structures, needed_size_for_strings, needed_size_for_data, current_data_pos); + } + } +} + +//Helper: sorts resource directory entries +struct entry_sorter +{ +public: + bool operator()(const resource_directory_entry& entry1, const resource_directory_entry& entry2) const; +}; + +//Helper function to rebuild resource directory +void rebuild_resource_directory(pe_base& pe, section& resource_section, resource_directory& root, uint32_t& current_structures_pos, uint32_t& current_data_pos, uint32_t& current_strings_pos, uint32_t offset_from_section_start) +{ + //Create resource directory + image_resource_directory dir = {0}; + dir.Characteristics = root.get_characteristics(); + dir.MajorVersion = root.get_major_version(); + dir.MinorVersion = root.get_minor_version(); + dir.TimeDateStamp = root.get_timestamp(); + + { + resource_directory::entry_list& entries = root.get_entry_list(); + std::sort(entries.begin(), entries.end(), entry_sorter()); + } + + //Calculate number of named and ID entries + for(resource_directory::entry_list::const_iterator it = root.get_entry_list().begin(); it != root.get_entry_list().end(); ++it) + { + if((*it).is_named()) + ++dir.NumberOfNamedEntries; + else + ++dir.NumberOfIdEntries; + } + + std::string& raw_data = resource_section.get_raw_data(); + + //Save resource directory + memcpy(&raw_data[current_structures_pos], &dir, sizeof(dir)); + current_structures_pos += sizeof(dir); + + uint32_t this_current_structures_pos = current_structures_pos; + + current_structures_pos += sizeof(image_resource_directory_entry) * (dir.NumberOfNamedEntries + dir.NumberOfIdEntries); + + //Create all resource directory entries + for(resource_directory::entry_list::iterator it = root.get_entry_list().begin(); it != root.get_entry_list().end(); ++it) + { + image_resource_directory_entry entry; + if((*it).is_named()) + { + entry.Name = 0x80000000 | (current_strings_pos - offset_from_section_start); + uint16_t unicode_length = static_cast((*it).get_name().length()); + memcpy(&raw_data[current_strings_pos], &unicode_length, sizeof(unicode_length)); + current_strings_pos += sizeof(unicode_length); + +#ifdef PE_BLISS_WINDOWS + memcpy(&raw_data[current_strings_pos], (*it).get_name().c_str(), (*it).get_name().length() * sizeof(uint16_t) + sizeof(uint16_t) /* unicode */); +#else + { + u16string str(pe_utils::to_ucs2((*it).get_name())); + memcpy(&raw_data[current_strings_pos], str.c_str(), (*it).get_name().length() * sizeof(uint16_t) + sizeof(uint16_t) /* unicode */); + } +#endif + + current_strings_pos += static_cast((*it).get_name().length() * sizeof(uint16_t) + sizeof(uint16_t) /* unicode */); + } + else + { + entry.Name = (*it).get_id(); + } + + if((*it).includes_data()) + { + current_data_pos = pe_utils::align_up(current_data_pos, sizeof(uint32_t)); + image_resource_data_entry data_entry = {0}; + data_entry.CodePage = (*it).get_data_entry().get_codepage(); + data_entry.Size = static_cast((*it).get_data_entry().get_data().length()); + data_entry.OffsetToData = pe.rva_from_section_offset(resource_section, current_data_pos + sizeof(data_entry)); + + entry.OffsetToData = current_data_pos - offset_from_section_start; + + memcpy(&raw_data[current_data_pos], &data_entry, sizeof(data_entry)); + current_data_pos += sizeof(data_entry); + + memcpy(&raw_data[current_data_pos], (*it).get_data_entry().get_data().data(), data_entry.Size); + current_data_pos += data_entry.Size; + + memcpy(&raw_data[this_current_structures_pos], &entry, sizeof(entry)); + this_current_structures_pos += sizeof(entry); + } + else + { + entry.OffsetToData = 0x80000000 | (current_structures_pos - offset_from_section_start); + + memcpy(&raw_data[this_current_structures_pos], &entry, sizeof(entry)); + this_current_structures_pos += sizeof(entry); + + rebuild_resource_directory(pe, resource_section, (*it).get_resource_directory(), current_structures_pos, current_data_pos, current_strings_pos, offset_from_section_start); + } + } +} + +//Helper function to rebuild resource directory +bool entry_sorter::operator()(const resource_directory_entry& entry1, const resource_directory_entry& entry2) const +{ + if(entry1.is_named() && entry2.is_named()) + return entry1.get_name() < entry2.get_name(); + else if(!entry1.is_named() && !entry2.is_named()) + return entry1.get_id() < entry2.get_id(); + else + return entry1.is_named(); +} + +//Resources rebuilder +//resource_directory - root resource directory +//resources_section - section where resource directory will be placed (must be attached to PE image) +//offset_from_section_start - offset from resources_section raw data start +//resource_directory is non-constant, because it will be sorted +//save_to_pe_headers - if true, new resource directory information will be saved to PE image headers +//auto_strip_last_section - if true and resources are placed in the last section, it will be automatically stripped +//number_of_id_entries and number_of_named_entries for resource directories are recalculated and not used +const image_directory rebuild_resources(pe_base& pe, resource_directory& info, section& resources_section, uint32_t offset_from_section_start, bool save_to_pe_header, bool auto_strip_last_section) +{ + //Check that resources_section is attached to this PE image + if(!pe.section_attached(resources_section)) + throw pe_exception("Resource section must be attached to PE file", pe_exception::section_is_not_attached); + + //Check resource directory correctness + if(info.get_entry_list().empty()) + throw pe_exception("Empty resource directory", pe_exception::incorrect_resource_directory); + + uint32_t aligned_offset_from_section_start = pe_utils::align_up(offset_from_section_start, sizeof(uint32_t)); + uint32_t needed_size_for_structures = aligned_offset_from_section_start - offset_from_section_start; //Calculate needed size for resource tables and data + uint32_t needed_size_for_strings = 0; + uint32_t needed_size_for_data = 0; + + calculate_resource_data_space(info, aligned_offset_from_section_start, needed_size_for_structures, needed_size_for_strings); + + { + uint32_t current_data_pos = aligned_offset_from_section_start + needed_size_for_structures + needed_size_for_strings; + calculate_resource_data_space(info, needed_size_for_structures, needed_size_for_strings, needed_size_for_data, current_data_pos); + } + + uint32_t needed_size = needed_size_for_structures + needed_size_for_strings + needed_size_for_data; + + //Check if resources_section is last one. If it's not, check if there's enough place for resource data + if(&resources_section != &*(pe.get_image_sections().end() - 1) && + (resources_section.empty() || pe_utils::align_up(resources_section.get_size_of_raw_data(), pe.get_file_alignment()) + < needed_size + aligned_offset_from_section_start)) + throw pe_exception("Insufficient space for resource directory", pe_exception::insufficient_space); + + std::string& raw_data = resources_section.get_raw_data(); + + //This will be done only if resources_section is the last section of image or for section with unaligned raw length of data + if(raw_data.length() < needed_size + aligned_offset_from_section_start) + raw_data.resize(needed_size + aligned_offset_from_section_start); //Expand section raw data + + uint32_t current_structures_pos = aligned_offset_from_section_start; + uint32_t current_strings_pos = current_structures_pos + needed_size_for_structures; + uint32_t current_data_pos = current_strings_pos + needed_size_for_strings; + rebuild_resource_directory(pe, resources_section, info, current_structures_pos, current_data_pos, current_strings_pos, aligned_offset_from_section_start); + + //Adjust section raw and virtual sizes + pe.recalculate_section_sizes(resources_section, auto_strip_last_section); + + image_directory ret(pe.rva_from_section_offset(resources_section, aligned_offset_from_section_start), needed_size); + + //If auto-rewrite of PE headers is required + if(save_to_pe_header) + { + pe.set_directory_rva(image_directory_entry_resource, ret.get_rva()); + pe.set_directory_size(image_directory_entry_resource, ret.get_size()); + } + + return ret; +} + +//Returns resources from PE file +const resource_directory get_resources(const pe_base& pe) +{ + resource_directory ret; + + if(!pe.has_resources()) + return ret; + + //Get resource directory RVA + uint32_t res_rva = pe.get_directory_rva(image_directory_entry_resource); + + //Store already processed directories to avoid resource loops + std::set processed; + + //Process all directories (recursion) + ret = process_resource_directory(pe, res_rva, 0, processed); + + return ret; +} + +//Finds resource_directory_entry by ID +resource_directory::id_entry_finder::id_entry_finder(uint32_t id) + :id_(id) +{} + +bool resource_directory::id_entry_finder::operator()(const resource_directory_entry& entry) const +{ + return !entry.is_named() && entry.get_id() == id_; +} + +//Finds resource_directory_entry by name +resource_directory::name_entry_finder::name_entry_finder(const std::wstring& name) + :name_(name) +{} + +bool resource_directory::name_entry_finder::operator()(const resource_directory_entry& entry) const +{ + return entry.is_named() && entry.get_name() == name_; +} + +//Finds resource_directory_entry by name or ID (universal) +resource_directory::entry_finder::entry_finder(const std::wstring& name) + :name_(name), named_(true) +{} + +resource_directory::entry_finder::entry_finder(uint32_t id) + :id_(id), named_(false) +{} + +bool resource_directory::entry_finder::operator()(const resource_directory_entry& entry) const +{ + if(named_) + return entry.is_named() && entry.get_name() == name_; + else + return !entry.is_named() && entry.get_id() == id_; +} + +//Returns resource_directory_entry by ID. If not found - throws an exception +const resource_directory_entry& resource_directory::entry_by_id(uint32_t id) const +{ + entry_list::const_iterator i = std::find_if(entries_.begin(), entries_.end(), id_entry_finder(id)); + if(i == entries_.end()) + throw pe_exception("Resource directory entry not found", pe_exception::resource_directory_entry_not_found); + + return *i; +} + +//Returns resource_directory_entry by name. If not found - throws an exception +const resource_directory_entry& resource_directory::entry_by_name(const std::wstring& name) const +{ + entry_list::const_iterator i = std::find_if(entries_.begin(), entries_.end(), name_entry_finder(name)); + if(i == entries_.end()) + throw pe_exception("Resource directory entry not found", pe_exception::resource_directory_entry_not_found); + + return *i; +} +} diff --git a/drivers/pe_bliss/pe_resources.h b/drivers/pe_bliss/pe_resources.h new file mode 100644 index 0000000000..0f7f32768d --- /dev/null +++ b/drivers/pe_bliss/pe_resources.h @@ -0,0 +1,224 @@ +#pragma once +#include +#include +#include +#include "pe_structures.h" +#include "pe_base.h" +#include "pe_directory.h" + +namespace pe_bliss +{ +//Class representing resource data entry +class resource_data_entry +{ +public: + //Default constructor + resource_data_entry(); + //Constructor from data + resource_data_entry(const std::string& data, uint32_t codepage); + + //Returns resource data codepage + uint32_t get_codepage() const; + //Returns resource data + const std::string& get_data() const; + +public: //These functions do not change everything inside image, they are used by PE class + //You can also use them to rebuild resource directory + + //Sets resource data codepage + void set_codepage(uint32_t codepage); + //Sets resource data + void set_data(const std::string& data); + +private: + uint32_t codepage_; //Resource data codepage + std::string data_; //Resource data +}; + +//Forward declaration +class resource_directory; + +//Class representing resource directory entry +class resource_directory_entry +{ +public: + //Default constructor + resource_directory_entry(); + //Copy constructor + resource_directory_entry(const resource_directory_entry& other); + //Copy assignment operator + resource_directory_entry& operator=(const resource_directory_entry& other); + + //Returns entry ID + uint32_t get_id() const; + //Returns entry name + const std::wstring& get_name() const; + //Returns true, if entry has name + //Returns false, if entry has ID + bool is_named() const; + + //Returns true, if entry includes resource_data_entry + //Returns false, if entry includes resource_directory + bool includes_data() const; + //Returns resource_directory if entry includes it, otherwise throws an exception + const resource_directory& get_resource_directory() const; + //Returns resource_data_entry if entry includes it, otherwise throws an exception + const resource_data_entry& get_data_entry() const; + + //Destructor + ~resource_directory_entry(); + +public: //These functions do not change everything inside image, they are used by PE class + //You can also use them to rebuild resource directory + + //Sets entry name + void set_name(const std::wstring& name); + //Sets entry ID + void set_id(uint32_t id); + + //Returns resource_directory if entry includes it, otherwise throws an exception + resource_directory& get_resource_directory(); + //Returns resource_data_entry if entry includes it, otherwise throws an exception + resource_data_entry& get_data_entry(); + + //Adds resource_data_entry + void add_data_entry(const resource_data_entry& entry); + //Adds resource_directory + void add_resource_directory(const resource_directory& dir); + +private: + //Destroys included data + void release(); + +private: + uint32_t id_; + std::wstring name_; + + union includes + { + //Default constructor + includes(); + + //We use pointers, we're doing manual copying here + class resource_data_entry* data_; + class resource_directory* dir_; //We use pointer, because structs include each other + }; + + includes ptr_; + + bool includes_data_, named_; +}; + +//Class representing resource directory +class resource_directory +{ +public: + typedef std::vector entry_list; + +public: + //Default constructor + resource_directory(); + //Constructor from data + explicit resource_directory(const pe_win::image_resource_directory& dir); + + //Returns characteristics of directory + uint32_t get_characteristics() const; + //Returns date and time stamp of directory + uint32_t get_timestamp() const; + //Returns number of named entries + uint32_t get_number_of_named_entries() const; + //Returns number of ID entries + uint32_t get_number_of_id_entries() const; + //Returns major version of directory + uint16_t get_major_version() const; + //Returns minor version of directory + uint16_t get_minor_version() const; + //Returns resource_directory_entry array + const entry_list& get_entry_list() const; + //Returns resource_directory_entry by ID. If not found - throws an exception + const resource_directory_entry& entry_by_id(uint32_t id) const; + //Returns resource_directory_entry by name. If not found - throws an exception + const resource_directory_entry& entry_by_name(const std::wstring& name) const; + +public: //These functions do not change everything inside image, they are used by PE class + //You can also use them to rebuild resource directory + + //Adds resource_directory_entry + void add_resource_directory_entry(const resource_directory_entry& entry); + //Clears resource_directory_entry array + void clear_resource_directory_entry_list(); + + //Sets characteristics of directory + void set_characteristics(uint32_t characteristics); + //Sets date and time stamp of directory + void set_timestamp(uint32_t timestamp); + //Sets number of named entries + void set_number_of_named_entries(uint32_t number); + //Sets number of ID entries + void set_number_of_id_entries(uint32_t number); + //Sets major version of directory + void set_major_version(uint16_t major_version); + //Sets minor version of directory + void get_minor_version(uint16_t minor_version); + + //Returns resource_directory_entry array + entry_list& get_entry_list(); + +private: + uint32_t characteristics_; + uint32_t timestamp_; + uint16_t major_version_, minor_version_; + uint32_t number_of_named_entries_, number_of_id_entries_; + entry_list entries_; + +public: //Finder helpers + //Finds resource_directory_entry by ID + struct id_entry_finder + { + public: + explicit id_entry_finder(uint32_t id); + bool operator()(const resource_directory_entry& entry) const; + + private: + uint32_t id_; + }; + + //Finds resource_directory_entry by name + struct name_entry_finder + { + public: + explicit name_entry_finder(const std::wstring& name); + bool operator()(const resource_directory_entry& entry) const; + + private: + std::wstring name_; + }; + + //Finds resource_directory_entry by name or ID (universal) + struct entry_finder + { + public: + explicit entry_finder(const std::wstring& name); + explicit entry_finder(uint32_t id); + bool operator()(const resource_directory_entry& entry) const; + + private: + std::wstring name_; + uint32_t id_; + bool named_; + }; +}; + +//Returns resources (root resource_directory) from PE file +const resource_directory get_resources(const pe_base& pe); + +//Resources rebuilder +//resource_directory - root resource directory +//resources_section - section where resource directory will be placed (must be attached to PE image) +//resource_directory is non-constant, because it will be sorted +//offset_from_section_start - offset from resources_section raw data start +//save_to_pe_headers - if true, new resource directory information will be saved to PE image headers +//auto_strip_last_section - if true and resources are placed in the last section, it will be automatically stripped +//number_of_id_entries and number_of_named_entries for resource directories are recalculated and not used +const image_directory rebuild_resources(pe_base& pe, resource_directory& info, section& resources_section, uint32_t offset_from_section_start = 0, bool save_to_pe_header = true, bool auto_strip_last_section = true); +} diff --git a/drivers/pe_bliss/pe_rich_data.cpp b/drivers/pe_bliss/pe_rich_data.cpp new file mode 100644 index 0000000000..0497fa6469 --- /dev/null +++ b/drivers/pe_bliss/pe_rich_data.cpp @@ -0,0 +1,131 @@ +#include "pe_rich_data.h" + +namespace pe_bliss +{ +//STUB OVERLAY +//Default constructor +rich_data::rich_data() + :number_(0), version_(0), times_(0) +{} + +//Who knows, what these fields mean... +uint32_t rich_data::get_number() const +{ + return number_; +} + +uint32_t rich_data::get_version() const +{ + return version_; +} + +uint32_t rich_data::get_times() const +{ + return times_; +} + +void rich_data::set_number(uint32_t number) +{ + number_ = number; +} + +void rich_data::set_version(uint32_t version) +{ + version_ = version; +} + +void rich_data::set_times(uint32_t times) +{ + times_ = times; +} + +//Returns MSVC rich data +const rich_data_list get_rich_data(const pe_base& pe) +{ + //Returned value + rich_data_list ret; + + const std::string& rich_overlay = pe.get_stub_overlay(); + + //If there's no rich overlay, return empty vector + if(rich_overlay.size() < sizeof(uint32_t)) + return ret; + + //True if rich data was found + bool found = false; + + //Rich overlay ID ("Rich" word) + static const uint32_t rich_overlay_id = 0x68636952; + + //Search for rich data overlay ID + const char* begin = &rich_overlay[0]; + const char* end = begin + rich_overlay.length(); + for(; begin != end; ++begin) + { + if(*reinterpret_cast(begin) == rich_overlay_id) + { + found = true; //We've found it! + break; + } + } + + //If we found it + if(found) + { + //Check remaining length + if(static_cast(end - begin) < sizeof(uint32_t)) + return ret; + + //The XOR key is after "Rich" word, we should get it + uint32_t xorkey = *reinterpret_cast(begin + sizeof(uint32_t)); + + //True if rich data was found + found = false; + + //Second search for signature "DanS" + begin = &rich_overlay[0]; + for(; begin != end; ++begin) + { + if((*reinterpret_cast(begin) ^ xorkey) == 0x536e6144) //"DanS" + { + found = true; + break; + } + } + + //If second signature is found + if(found) + { + begin += sizeof(uint32_t) * 3; + //List all rich data structures + while(begin < end) + { + begin += sizeof(uint32_t); + if(begin >= end) + break; + + //Check for rich overlay data end ("Rich" word reached) + if(*reinterpret_cast(begin) == rich_overlay_id) + break; + + //Create rich_data structure + rich_data data; + data.set_number((*reinterpret_cast(begin) ^ xorkey) >> 16); + data.set_version((*reinterpret_cast(begin) ^ xorkey) & 0xFFFF); + + begin += sizeof(uint32_t); + if(begin >= end) + break; + + data.set_times(*reinterpret_cast(begin) ^ xorkey); + + //Save rich data structure + ret.push_back(data); + } + } + } + + //Return rich data structures list + return ret; +} +} diff --git a/drivers/pe_bliss/pe_rich_data.h b/drivers/pe_bliss/pe_rich_data.h new file mode 100644 index 0000000000..3d7622c680 --- /dev/null +++ b/drivers/pe_bliss/pe_rich_data.h @@ -0,0 +1,37 @@ +#pragma once +#include +#include "pe_structures.h" +#include "pe_base.h" + +namespace pe_bliss +{ +//Rich data overlay class of Microsoft Visual Studio +class rich_data +{ +public: + //Default constructor + rich_data(); + +public: //Getters + //Who knows, what these fields mean... + uint32_t get_number() const; + uint32_t get_version() const; + uint32_t get_times() const; + +public: //Setters, used by PE library only + void set_number(uint32_t number); + void set_version(uint32_t version); + void set_times(uint32_t times); + +private: + uint32_t number_; + uint32_t version_; + uint32_t times_; +}; + +//Rich data list typedef +typedef std::vector rich_data_list; + +//Returns a vector with rich data (stub overlay) +const rich_data_list get_rich_data(const pe_base& pe); +} diff --git a/drivers/pe_bliss/pe_section.cpp b/drivers/pe_bliss/pe_section.cpp new file mode 100644 index 0000000000..e7def185cb --- /dev/null +++ b/drivers/pe_bliss/pe_section.cpp @@ -0,0 +1,281 @@ +#include +#include "utils.h" +#include "pe_section.h" + +namespace pe_bliss +{ +using namespace pe_win; + +//Section structure default constructor +section::section() + :old_size_(static_cast(-1)) +{ + memset(&header_, 0, sizeof(image_section_header)); +} + +//Sets the name of section (8 characters maximum) +void section::set_name(const std::string& name) +{ + memset(header_.Name, 0, sizeof(header_.Name)); + memcpy(header_.Name, name.c_str(), std::min(name.length(), sizeof(header_.Name))); +} + +//Returns section name +const std::string section::get_name() const +{ + char buf[9] = {0}; + memcpy(buf, header_.Name, 8); + return std::string(buf); +} + +//Set flag (attribute) of section +section& section::set_flag(uint32_t flag, bool setflag) +{ + if(setflag) + header_.Characteristics |= flag; + else + header_.Characteristics &= ~flag; + + return *this; +} + +//Sets "readable" attribute of section +section& section::readable(bool readable) +{ + return set_flag(image_scn_mem_read, readable); +} + +//Sets "writeable" attribute of section +section& section::writeable(bool writeable) +{ + return set_flag(image_scn_mem_write, writeable); +} + +//Sets "executable" attribute of section +section& section::executable(bool executable) +{ + return set_flag(image_scn_mem_execute, executable); +} + +//Sets "shared" attribute of section +section& section::shared(bool shared) +{ + return set_flag(image_scn_mem_shared, shared); +} + +//Sets "discardable" attribute of section +section& section::discardable(bool discardable) +{ + return set_flag(image_scn_mem_discardable, discardable); +} + +//Returns true if section is readable +bool section::readable() const +{ + return (header_.Characteristics & image_scn_mem_read) != 0; +} + +//Returns true if section is writeable +bool section::writeable() const +{ + return (header_.Characteristics & image_scn_mem_write) != 0; +} + +//Returns true if section is executable +bool section::executable() const +{ + return (header_.Characteristics & image_scn_mem_execute) != 0; +} + +bool section::shared() const +{ + return (header_.Characteristics & image_scn_mem_shared) != 0; +} + +bool section::discardable() const +{ + return (header_.Characteristics & image_scn_mem_discardable) != 0; +} + +//Returns true if section has no RAW data +bool section::empty() const +{ + if(old_size_ != static_cast(-1)) //If virtual memory is mapped, check raw data length (old_size_) + return old_size_ == 0; + else + return raw_data_.empty(); +} + +//Returns raw section data from file image +std::string& section::get_raw_data() +{ + unmap_virtual(); + return raw_data_; +} + +//Sets raw section data from file image +void section::set_raw_data(const std::string& data) +{ + old_size_ = static_cast(-1); + raw_data_ = data; +} + +//Returns raw section data from file image +const std::string& section::get_raw_data() const +{ + unmap_virtual(); + return raw_data_; +} + +//Returns mapped virtual section data +const std::string& section::get_virtual_data(uint32_t section_alignment) const +{ + map_virtual(section_alignment); + return raw_data_; +} + +//Returns mapped virtual section data +std::string& section::get_virtual_data(uint32_t section_alignment) +{ + map_virtual(section_alignment); + return raw_data_; +} + +//Maps virtual section data +void section::map_virtual(uint32_t section_alignment) const +{ + uint32_t aligned_virtual_size = get_aligned_virtual_size(section_alignment); + if(old_size_ == static_cast(-1) && aligned_virtual_size && aligned_virtual_size > raw_data_.length()) + { + old_size_ = raw_data_.length(); + raw_data_.resize(aligned_virtual_size, 0); + } +} + +//Unmaps virtual section data +void section::unmap_virtual() const +{ + if(old_size_ != static_cast(-1)) + { + raw_data_.resize(old_size_, 0); + old_size_ = static_cast(-1); + } +} + +//Returns section virtual size +uint32_t section::get_virtual_size() const +{ + return header_.Misc.VirtualSize; +} + +//Returns section virtual address +uint32_t section::get_virtual_address() const +{ + return header_.VirtualAddress; +} + +//Returns size of section raw data +uint32_t section::get_size_of_raw_data() const +{ + return header_.SizeOfRawData; +} + +//Returns pointer to raw section data in PE file +uint32_t section::get_pointer_to_raw_data() const +{ + return header_.PointerToRawData; +} + +//Returns section characteristics +uint32_t section::get_characteristics() const +{ + return header_.Characteristics; +} + +//Returns raw image section header +const pe_win::image_section_header& section::get_raw_header() const +{ + return header_; +} + +//Returns raw image section header +pe_win::image_section_header& section::get_raw_header() +{ + return header_; +} + +//Calculates aligned virtual section size +uint32_t section::get_aligned_virtual_size(uint32_t section_alignment) const +{ + if(get_size_of_raw_data()) + { + if(!get_virtual_size()) + { + //If section virtual size is zero + //Set aligned virtual size of section as aligned raw size + return pe_utils::align_up(get_size_of_raw_data(), section_alignment); + } + } + + return pe_utils::align_up(get_virtual_size(), section_alignment); +} + +//Calculates aligned raw section size +uint32_t section::get_aligned_raw_size(uint32_t file_alignment) const +{ + if(get_size_of_raw_data()) + return pe_utils::align_up(get_size_of_raw_data(), file_alignment); + else + return 0; +} + +//Sets size of raw section data +void section::set_size_of_raw_data(uint32_t size_of_raw_data) +{ + header_.SizeOfRawData = size_of_raw_data; +} + +//Sets pointer to section raw data +void section::set_pointer_to_raw_data(uint32_t pointer_to_raw_data) +{ + header_.PointerToRawData = pointer_to_raw_data; +} + +//Sets section characteristics +void section::set_characteristics(uint32_t characteristics) +{ + header_.Characteristics = characteristics; +} + +//Sets section virtual size +void section::set_virtual_size(uint32_t virtual_size) +{ + header_.Misc.VirtualSize = virtual_size; +} + +//Sets section virtual address +void section::set_virtual_address(uint32_t virtual_address) +{ + header_.VirtualAddress = virtual_address; +} + +//Section by file offset finder helper (4gb max) +section_by_raw_offset::section_by_raw_offset(uint32_t offset) + :offset_(offset) +{} + +bool section_by_raw_offset::operator()(const section& s) const +{ + return (s.get_pointer_to_raw_data() <= offset_) + && (s.get_pointer_to_raw_data() + s.get_size_of_raw_data() > offset_); +} + +section_ptr_finder::section_ptr_finder(const section& s) + :s_(s) +{} + +bool section_ptr_finder::operator()(const section& s) const +{ + return &s == &s_; +} +} diff --git a/drivers/pe_bliss/pe_section.h b/drivers/pe_bliss/pe_section.h new file mode 100644 index 0000000000..8d8e2371ee --- /dev/null +++ b/drivers/pe_bliss/pe_section.h @@ -0,0 +1,137 @@ +#pragma once +#include +#include +#include "pe_structures.h" + +namespace pe_bliss +{ +//Enumeration of section data types, used in functions below +enum section_data_type +{ + section_data_raw, + section_data_virtual +}; + +//Class representing image section +class section +{ +public: + //Default constructor + section(); + + //Sets the name of section (stripped to 8 characters) + void set_name(const std::string& name); + + //Returns the name of section + const std::string get_name() const; + + //Changes attributes of section + section& readable(bool readable); + section& writeable(bool writeable); + section& executable(bool executable); + section& shared(bool shared); + section& discardable(bool discardable); + + //Returns attributes of section + bool readable() const; + bool writeable() const; + bool executable() const; + bool shared() const; + bool discardable() const; + + //Returns true if section has no RAW data + bool empty() const; + + //Returns raw section data from file image + std::string& get_raw_data(); + //Returns raw section data from file image + const std::string& get_raw_data() const; + //Returns mapped virtual section data + const std::string& get_virtual_data(uint32_t section_alignment) const; + //Returns mapped virtual section data + std::string& get_virtual_data(uint32_t section_alignment); + +public: //Header getters + //Returns section virtual size + uint32_t get_virtual_size() const; + //Returns section virtual address (RVA) + uint32_t get_virtual_address() const; + //Returns size of section raw data + uint32_t get_size_of_raw_data() const; + //Returns pointer to raw section data in PE file + uint32_t get_pointer_to_raw_data() const; + //Returns section characteristics + uint32_t get_characteristics() const; + + //Returns raw image section header + const pe_win::image_section_header& get_raw_header() const; + +public: //Aligned sizes calculation + //Calculates aligned virtual section size + uint32_t get_aligned_virtual_size(uint32_t section_alignment) const; + //Calculates aligned raw section size + uint32_t get_aligned_raw_size(uint32_t file_alignment) const; + +public: //Setters + //Sets size of raw section data + void set_size_of_raw_data(uint32_t size_of_raw_data); + //Sets pointer to section raw data + void set_pointer_to_raw_data(uint32_t pointer_to_raw_data); + //Sets section characteristics + void set_characteristics(uint32_t characteristics); + //Sets raw section data from file image + void set_raw_data(const std::string& data); + +public: //Setters, be careful + //Sets section virtual size (doesn't set internal aligned virtual size, changes only header value) + //Better use pe_base::set_section_virtual_size + void set_virtual_size(uint32_t virtual_size); + //Sets section virtual address + void set_virtual_address(uint32_t virtual_address); + //Returns raw image section header + pe_win::image_section_header& get_raw_header(); + +private: + //Section header + pe_win::image_section_header header_; + + //Maps virtual section data + void map_virtual(uint32_t section_alignment) const; + + //Unmaps virtual section data + void unmap_virtual() const; + + //Set flag (attribute) of section + section& set_flag(uint32_t flag, bool setflag); + + //Old size of section (stored after mapping of virtual section memory) + mutable std::size_t old_size_; + + //Section raw/virtual data + mutable std::string raw_data_; +}; + +//Section by file offset finder helper (4gb max) +struct section_by_raw_offset +{ +public: + explicit section_by_raw_offset(uint32_t offset); + bool operator()(const section& s) const; + +private: + uint32_t offset_; +}; + +//Helper: finder of section* in sections list +struct section_ptr_finder +{ +public: + explicit section_ptr_finder(const section& s); + bool operator()(const section& s) const; + +private: + const section& s_; +}; + +typedef std::vector
section_list; +} diff --git a/drivers/pe_bliss/pe_structures.h b/drivers/pe_bliss/pe_structures.h new file mode 100644 index 0000000000..9008536ab1 --- /dev/null +++ b/drivers/pe_bliss/pe_structures.h @@ -0,0 +1,1007 @@ +#pragma once +#include +#include +#include "stdint_defs.h" +#if defined(_MSC_VER) or defined(__MINGW32__) +#define PE_BLISS_WINDOWS +#endif + +namespace pe_bliss +{ +//Enumeration of PE types +enum pe_type +{ + pe_type_32, + pe_type_64 +}; + +namespace pe_win +{ +const uint32_t image_numberof_directory_entries = 16; +const uint32_t image_nt_optional_hdr32_magic = 0x10b; +const uint32_t image_nt_optional_hdr64_magic = 0x20b; +const uint32_t image_resource_name_is_string = 0x80000000; +const uint32_t image_resource_data_is_directory = 0x80000000; + +const uint32_t image_dllcharacteristics_dynamic_base = 0x0040; // DLL can move. +const uint32_t image_dllcharacteristics_force_integrity = 0x0080; // Code Integrity Image +const uint32_t image_dllcharacteristics_nx_compat = 0x0100; // Image is NX compatible +const uint32_t image_dllcharacteristics_no_isolation = 0x0200; // Image understands isolation and doesn't want it +const uint32_t image_dllcharacteristics_no_seh = 0x0400; // Image does not use SEH. No SE handler may reside in this image +const uint32_t image_dllcharacteristics_no_bind = 0x0800; // Do not bind this image. +const uint32_t image_dllcharacteristics_wdm_driver = 0x2000; // Driver uses WDM model +const uint32_t image_dllcharacteristics_terminal_server_aware = 0x8000; + +const uint32_t image_sizeof_file_header = 20; + +const uint32_t image_file_relocs_stripped = 0x0001; // Relocation info stripped from file. +const uint32_t image_file_executable_image = 0x0002; // File is executable (i.e. no unresolved externel references). +const uint32_t image_file_line_nums_stripped = 0x0004; // Line nunbers stripped from file. +const uint32_t image_file_local_syms_stripped = 0x0008; // Local symbols stripped from file. +const uint32_t image_file_aggresive_ws_trim = 0x0010; // Agressively trim working set +const uint32_t image_file_large_address_aware = 0x0020; // App can handle >2gb addresses +const uint32_t image_file_bytes_reversed_lo = 0x0080; // Bytes of machine word are reversed. +const uint32_t image_file_32bit_machine = 0x0100; // 32 bit word machine. +const uint32_t image_file_debug_stripped = 0x0200; // Debugging info stripped from file in .DBG file +const uint32_t image_file_removable_run_from_swap = 0x0400; // If Image is on removable media, copy and run from the swap file. +const uint32_t image_file_net_run_from_swap = 0x0800; // If Image is on Net, copy and run from the swap file. +const uint32_t image_file_system = 0x1000; // System File. +const uint32_t image_file_dll = 0x2000; // File is a DLL. +const uint32_t image_file_up_system_only = 0x4000; // File should only be run on a UP machine +const uint32_t image_file_bytes_reversed_hi = 0x8000; // Bytes of machine word are reversed. + +const uint32_t image_scn_lnk_nreloc_ovfl = 0x01000000; // Section contains extended relocations. +const uint32_t image_scn_mem_discardable = 0x02000000; // Section can be discarded. +const uint32_t image_scn_mem_not_cached = 0x04000000; // Section is not cachable. +const uint32_t image_scn_mem_not_paged = 0x08000000; // Section is not pageable. +const uint32_t image_scn_mem_shared = 0x10000000; // Section is shareable. +const uint32_t image_scn_mem_execute = 0x20000000; // Section is executable. +const uint32_t image_scn_mem_read = 0x40000000; // Section is readable. +const uint32_t image_scn_mem_write = 0x80000000; // Section is writeable. + +const uint32_t image_scn_cnt_code = 0x00000020; // Section contains code. +const uint32_t image_scn_cnt_initialized_data = 0x00000040; // Section contains initialized data. +const uint32_t image_scn_cnt_uninitialized_data = 0x00000080; // Section contains uninitialized data. + +//Directory Entries +const uint32_t image_directory_entry_export = 0; // Export Directory +const uint32_t image_directory_entry_import = 1; // Import Directory +const uint32_t image_directory_entry_resource = 2; // Resource Directory +const uint32_t image_directory_entry_exception = 3; // Exception Directory +const uint32_t image_directory_entry_security = 4; // Security Directory +const uint32_t image_directory_entry_basereloc = 5; // Base Relocation Table +const uint32_t image_directory_entry_debug = 6; // Debug Directory +const uint32_t image_directory_entry_architecture = 7; // Architecture Specific Data +const uint32_t image_directory_entry_globalptr = 8; // RVA of GP +const uint32_t image_directory_entry_tls = 9; // TLS Directory +const uint32_t image_directory_entry_load_config = 10; // Load Configuration Directory +const uint32_t image_directory_entry_bound_import = 11; // Bound Import Directory in headers +const uint32_t image_directory_entry_iat = 12; // Import Address Table +const uint32_t image_directory_entry_delay_import = 13; // Delay Load Import Descriptors +const uint32_t image_directory_entry_com_descriptor = 14; // COM Runtime descriptor + +//Subsystem Values +const uint32_t image_subsystem_unknown = 0; // Unknown subsystem. +const uint32_t image_subsystem_native = 1; // Image doesn't require a subsystem. +const uint32_t image_subsystem_windows_gui = 2; // Image runs in the Windows GUI subsystem. +const uint32_t image_subsystem_windows_cui = 3; // Image runs in the Windows character subsystem. +const uint32_t image_subsystem_os2_cui = 5; // image runs in the OS/2 character subsystem. +const uint32_t image_subsystem_posix_cui = 7; // image runs in the Posix character subsystem. +const uint32_t image_subsystem_native_windows = 8; // image is a native Win9x driver. +const uint32_t image_subsystem_windows_ce_gui = 9; // Image runs in the Windows CE subsystem. +const uint32_t image_subsystem_efi_application = 10; // +const uint32_t image_subsystem_efi_boot_service_driver = 11; // +const uint32_t image_subsystem_efi_runtime_driver = 12; // +const uint32_t image_subsystem_efi_rom = 13; +const uint32_t image_subsystem_xbox = 14; +const uint32_t image_subsystem_windows_boot_application = 16; + +//Imports +const uint64_t image_ordinal_flag64 = 0x8000000000000000ull; +const uint32_t image_ordinal_flag32 = 0x80000000; + +//Based relocation types +const uint32_t image_rel_based_absolute = 0; +const uint32_t image_rel_based_high = 1; +const uint32_t image_rel_based_low = 2; +const uint32_t image_rel_based_highlow = 3; +const uint32_t image_rel_based_highadj = 4; +const uint32_t image_rel_based_mips_jmpaddr = 5; +const uint32_t image_rel_based_mips_jmpaddr16 = 9; +const uint32_t image_rel_based_ia64_imm64 = 9; +const uint32_t image_rel_based_dir64 = 10; + +//Exception directory +//The function has an exception handler that should be called when looking for functions that need to examine exceptions +const uint32_t unw_flag_ehandler = 0x01; +//The function has a termination handler that should be called when unwinding an exception +const uint32_t unw_flag_uhandler = 0x02; +//This unwind info structure is not the primary one for the procedure. +//Instead, the chained unwind info entry is the contents of a previous RUNTIME_FUNCTION entry. +//If this flag is set, then the UNW_FLAG_EHANDLER and UNW_FLAG_UHANDLER flags must be cleared. +//Also, the frame register and fixed-stack allocation fields must have the same values as in the primary unwind info +const uint32_t unw_flag_chaininfo = 0x04; + +//Debug +const uint32_t image_debug_misc_exename = 1; +const uint32_t image_debug_type_unknown = 0; +const uint32_t image_debug_type_coff = 1; +const uint32_t image_debug_type_codeview = 2; +const uint32_t image_debug_type_fpo = 3; +const uint32_t image_debug_type_misc = 4; +const uint32_t image_debug_type_exception = 5; +const uint32_t image_debug_type_fixup = 6; +const uint32_t image_debug_type_omap_to_src = 7; +const uint32_t image_debug_type_omap_from_src = 8; +const uint32_t image_debug_type_borland = 9; +const uint32_t image_debug_type_reserved10 = 10; +const uint32_t image_debug_type_clsid = 11; + + +//Storage classes +const uint32_t image_sym_class_end_of_function = static_cast(-1); +const uint32_t image_sym_class_null = 0x0000; +const uint32_t image_sym_class_automatic = 0x0001; +const uint32_t image_sym_class_external = 0x0002; +const uint32_t image_sym_class_static = 0x0003; +const uint32_t image_sym_class_register = 0x0004; +const uint32_t image_sym_class_external_def = 0x0005; +const uint32_t image_sym_class_label = 0x0006; +const uint32_t image_sym_class_undefined_label = 0x0007; +const uint32_t image_sym_class_member_of_struct = 0x0008; +const uint32_t image_sym_class_argument = 0x0009; +const uint32_t image_sym_class_struct_tag = 0x000a; +const uint32_t image_sym_class_member_of_union = 0x000b; +const uint32_t image_sym_class_union_tag = 0x000c; +const uint32_t image_sym_class_type_definition = 0x000d; +const uint32_t image_sym_class_undefined_static = 0x000e; +const uint32_t image_sym_class_enum_tag = 0x000f; +const uint32_t image_sym_class_member_of_enum = 0x0010; +const uint32_t image_sym_class_register_param = 0x0011; +const uint32_t image_sym_class_bit_field = 0x0012; + +const uint32_t image_sym_class_far_external = 0x0044; + +const uint32_t image_sym_class_block = 0x0064; +const uint32_t image_sym_class_function = 0x0065; +const uint32_t image_sym_class_end_of_struct = 0x0066; +const uint32_t image_sym_class_file = 0x0067; + +const uint32_t image_sym_class_section = 0x0068; +const uint32_t image_sym_class_weak_external = 0x0069; + +const uint32_t image_sym_class_clr_token = 0x006b; + +//type packing constants +const uint32_t n_btmask = 0x000f; +const uint32_t n_tmask = 0x0030; +const uint32_t n_tmask1 = 0x00c0; +const uint32_t n_tmask2 = 0x00f0; +const uint32_t n_btshft = 4; +const uint32_t n_tshift = 2; + +//Type (derived) values. +const uint32_t image_sym_dtype_null = 0; // no derived type. +const uint32_t image_sym_dtype_pointer = 1; // pointer. +const uint32_t image_sym_dtype_function = 2; // function. +const uint32_t image_sym_dtype_array = 3; // array. + +// Is x a function? +//TODO +#ifndef ISFCN +#define ISFCN(x) (((x) & n_tmask) == (image_sym_dtype_function << n_btshft)) +#endif + +//Version info +const uint32_t vs_ffi_fileflagsmask = 0x0000003FL; + +const uint32_t vs_ffi_signature = 0xFEEF04BDL; +const uint32_t vs_ffi_strucversion = 0x00010000L; + +/* ----- VS_VERSION.dwFileFlags ----- */ +const uint32_t vs_ff_debug = 0x00000001L; +const uint32_t vs_ff_prerelease = 0x00000002L; +const uint32_t vs_ff_patched = 0x00000004L; +const uint32_t vs_ff_privatebuild = 0x00000008L; +const uint32_t vs_ff_infoinferred = 0x00000010L; +const uint32_t vs_ff_specialbuild = 0x00000020L; + +/* ----- VS_VERSION.dwFileOS ----- */ +const uint32_t vos_unknown = 0x00000000L; +const uint32_t vos_dos = 0x00010000L; +const uint32_t vos_os216 = 0x00020000L; +const uint32_t vos_os232 = 0x00030000L; +const uint32_t vos_nt = 0x00040000L; +const uint32_t vos_wince = 0x00050000L; + +const uint32_t vos__base = 0x00000000L; +const uint32_t vos__windows16 = 0x00000001L; +const uint32_t vos__pm16 = 0x00000002L; +const uint32_t vos__pm32 = 0x00000003L; +const uint32_t vos__windows32 = 0x00000004L; + +const uint32_t vos_dos_windows16 = 0x00010001L; +const uint32_t vos_dos_windows32 = 0x00010004L; +const uint32_t vos_os216_pm16 = 0x00020002L; +const uint32_t vos_os232_pm32 = 0x00030003L; +const uint32_t vos_nt_windows32 = 0x00040004L; + +/* ----- VS_VERSION.dwFileType ----- */ +const uint32_t vft_unknown = 0x00000000L; +const uint32_t vft_app = 0x00000001L; +const uint32_t vft_dll = 0x00000002L; +const uint32_t vft_drv = 0x00000003L; +const uint32_t vft_font = 0x00000004L; +const uint32_t vft_vxd = 0x00000005L; +const uint32_t vft_static_lib = 0x00000007L; + +const uint32_t message_resource_unicode = 0x0001; + +#pragma pack(push, 1) + +//Windows GUID structure +struct guid +{ + uint32_t Data1; + uint16_t Data2; + uint16_t Data3; + uint8_t Data4[8]; +}; + +//DOS .EXE header +struct image_dos_header +{ + uint16_t e_magic; // Magic number + uint16_t e_cblp; // Bytes on last page of file + uint16_t e_cp; // Pages in file + uint16_t e_crlc; // Relocations + uint16_t e_cparhdr; // Size of header in paragraphs + uint16_t e_minalloc; // Minimum extra paragraphs needed + uint16_t e_maxalloc; // Maximum extra paragraphs needed + uint16_t e_ss; // Initial (relative) SS value + uint16_t e_sp; // Initial SP value + uint16_t e_csum; // Checksum + uint16_t e_ip; // Initial IP value + uint16_t e_cs; // Initial (relative) CS value + uint16_t e_lfarlc; // File address of relocation table + uint16_t e_ovno; // Overlay number + uint16_t e_res[4]; // Reserved words + uint16_t e_oemid; // OEM identifier (for e_oeminfo) + uint16_t e_oeminfo; // OEM information; e_oemid specific + uint16_t e_res2[10]; // Reserved words + int32_t e_lfanew; // File address of new exe header +}; + +//Directory format +struct image_data_directory +{ + uint32_t VirtualAddress; + uint32_t Size; +}; + +//Optional header format +struct image_optional_header32 +{ + //Standard fields + uint16_t Magic; + uint8_t MajorLinkerVersion; + uint8_t MinorLinkerVersion; + uint32_t SizeOfCode; + uint32_t SizeOfInitializedData; + uint32_t SizeOfUninitializedData; + uint32_t AddressOfEntryPoint; + uint32_t BaseOfCode; + uint32_t BaseOfData; + + //NT additional fields + uint32_t ImageBase; + uint32_t SectionAlignment; + uint32_t FileAlignment; + uint16_t MajorOperatingSystemVersion; + uint16_t MinorOperatingSystemVersion; + uint16_t MajorImageVersion; + uint16_t MinorImageVersion; + uint16_t MajorSubsystemVersion; + uint16_t MinorSubsystemVersion; + uint32_t Win32VersionValue; + uint32_t SizeOfImage; + uint32_t SizeOfHeaders; + uint32_t CheckSum; + uint16_t Subsystem; + uint16_t DllCharacteristics; + uint32_t SizeOfStackReserve; + uint32_t SizeOfStackCommit; + uint32_t SizeOfHeapReserve; + uint32_t SizeOfHeapCommit; + uint32_t LoaderFlags; + uint32_t NumberOfRvaAndSizes; + image_data_directory DataDirectory[image_numberof_directory_entries]; +}; + +struct image_optional_header64 +{ + uint16_t Magic; + uint8_t MajorLinkerVersion; + uint8_t MinorLinkerVersion; + uint32_t SizeOfCode; + uint32_t SizeOfInitializedData; + uint32_t SizeOfUninitializedData; + uint32_t AddressOfEntryPoint; + uint32_t BaseOfCode; + uint64_t ImageBase; + uint32_t SectionAlignment; + uint32_t FileAlignment; + uint16_t MajorOperatingSystemVersion; + uint16_t MinorOperatingSystemVersion; + uint16_t MajorImageVersion; + uint16_t MinorImageVersion; + uint16_t MajorSubsystemVersion; + uint16_t MinorSubsystemVersion; + uint32_t Win32VersionValue; + uint32_t SizeOfImage; + uint32_t SizeOfHeaders; + uint32_t CheckSum; + uint16_t Subsystem; + uint16_t DllCharacteristics; + uint64_t SizeOfStackReserve; + uint64_t SizeOfStackCommit; + uint64_t SizeOfHeapReserve; + uint64_t SizeOfHeapCommit; + uint32_t LoaderFlags; + uint32_t NumberOfRvaAndSizes; + image_data_directory DataDirectory[image_numberof_directory_entries]; +}; + +struct image_file_header +{ + uint16_t Machine; + uint16_t NumberOfSections; + uint32_t TimeDateStamp; + uint32_t PointerToSymbolTable; + uint32_t NumberOfSymbols; + uint16_t SizeOfOptionalHeader; + uint16_t Characteristics; +}; + +struct image_nt_headers64 +{ + uint32_t Signature; + image_file_header FileHeader; + image_optional_header64 OptionalHeader; +}; + +struct image_nt_headers32 +{ + uint32_t Signature; + image_file_header FileHeader; + image_optional_header32 OptionalHeader; +}; + +//Section header format +struct image_section_header +{ + uint8_t Name[8]; + union + { + uint32_t PhysicalAddress; + uint32_t VirtualSize; + } Misc; + + uint32_t VirtualAddress; + uint32_t SizeOfRawData; + uint32_t PointerToRawData; + uint32_t PointerToRelocations; + uint32_t PointerToLinenumbers; + uint16_t NumberOfRelocations; + uint16_t NumberOfLinenumbers; + uint32_t Characteristics; +}; + + +/// RESOURCES /// +struct image_resource_directory +{ + uint32_t Characteristics; + uint32_t TimeDateStamp; + uint16_t MajorVersion; + uint16_t MinorVersion; + uint16_t NumberOfNamedEntries; + uint16_t NumberOfIdEntries; + // IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[]; +}; + +struct vs_fixedfileinfo +{ + uint32_t dwSignature; /* e.g. 0xfeef04bd */ + uint32_t dwStrucVersion; /* e.g. 0x00000042 = "0.42" */ + uint32_t dwFileVersionMS; /* e.g. 0x00030075 = "3.75" */ + uint32_t dwFileVersionLS; /* e.g. 0x00000031 = "0.31" */ + uint32_t dwProductVersionMS; /* e.g. 0x00030010 = "3.10" */ + uint32_t dwProductVersionLS; /* e.g. 0x00000031 = "0.31" */ + uint32_t dwFileFlagsMask; /* = 0x3F for version "0.42" */ + uint32_t dwFileFlags; /* e.g. VFF_DEBUG | VFF_PRERELEASE */ + uint32_t dwFileOS; /* e.g. VOS_DOS_WINDOWS16 */ + uint32_t dwFileType; /* e.g. VFT_DRIVER */ + uint32_t dwFileSubtype; /* e.g. VFT2_DRV_KEYBOARD */ + uint32_t dwFileDateMS; /* e.g. 0 */ + uint32_t dwFileDateLS; /* e.g. 0 */ +}; + +struct bitmapinfoheader +{ + uint32_t biSize; + int32_t biWidth; + int32_t biHeight; + uint16_t biPlanes; + uint16_t biBitCount; + uint32_t biCompression; + uint32_t biSizeImage; + int32_t biXPelsPerMeter; + int32_t biYPelsPerMeter; + uint32_t biClrUsed; + uint32_t biClrImportant; +}; + +struct message_resource_entry +{ + uint16_t Length; + uint16_t Flags; + uint8_t Text[1]; +}; + +struct message_resource_block +{ + uint32_t LowId; + uint32_t HighId; + uint32_t OffsetToEntries; +}; + +struct message_resource_data +{ + uint32_t NumberOfBlocks; + message_resource_block Blocks[1]; +}; + +struct image_resource_directory_entry +{ + union + { + struct + { + uint32_t NameOffset:31; + uint32_t NameIsString:1; + }; + uint32_t Name; + uint16_t Id; + }; + + union + { + uint32_t OffsetToData; + struct + { + uint32_t OffsetToDirectory:31; + uint32_t DataIsDirectory:1; + }; + }; +}; + +struct image_resource_data_entry +{ + uint32_t OffsetToData; + uint32_t Size; + uint32_t CodePage; + uint32_t Reserved; +}; + +#pragma pack(push, 2) +struct bitmapfileheader +{ + uint16_t bfType; + uint32_t bfSize; + uint16_t bfReserved1; + uint16_t bfReserved2; + uint32_t bfOffBits; +}; +#pragma pack(pop) + + + +//Structure representing ICON file header +struct ico_header +{ + uint16_t Reserved; + uint16_t Type; //1 + uint16_t Count; //Count of icons included in icon group +}; + +//Structure that is stored in icon group directory in PE resources +struct icon_group +{ + uint8_t Width; + uint8_t Height; + uint8_t ColorCount; + uint8_t Reserved; + uint16_t Planes; + uint16_t BitCount; + uint32_t SizeInBytes; + uint16_t Number; //Represents resource ID in PE icon list +}; + +//Structure representing ICON directory entry inside ICON file +struct icondirentry +{ + uint8_t Width; + uint8_t Height; + uint8_t ColorCount; + uint8_t Reserved; + uint16_t Planes; + uint16_t BitCount; + uint32_t SizeInBytes; + uint32_t ImageOffset; //Offset from start of header to the image +}; + +//Structure representing CURSOR file header +struct cursor_header +{ + uint16_t Reserved; + uint16_t Type; //2 + uint16_t Count; //Count of cursors included in cursor group +}; + +struct cursor_group +{ + uint16_t Width; + uint16_t Height; //Divide by 2 to get the actual height. + uint16_t Planes; + uint16_t BitCount; + uint32_t SizeInBytes; + uint16_t Number; //Represents resource ID in PE icon list +}; + +//Structure representing CURSOR directory entry inside CURSOR file +struct cursordirentry +{ + uint8_t Width; //Set to CURSOR_GROUP::Height/2. + uint8_t Height; + uint8_t ColorCount; + uint8_t Reserved; + uint16_t HotspotX; + uint16_t HotspotY; + uint32_t SizeInBytes; + uint32_t ImageOffset; //Offset from start of header to the image +}; + +//Structure representing BLOCK in version info resource +struct version_info_block //(always aligned on 32-bit (DWORD) boundary) +{ + uint16_t Length; //Length of this block (doesn't include padding) + uint16_t ValueLength; //Value length (if any) + uint16_t Type; //Value type (0 = binary, 1 = text) + uint16_t Key[1]; //Value name (block key) (always NULL terminated) + + ////////// + //WORD padding1[]; //Padding, if any (ALIGNMENT) + //xxxxx Value[]; //Value data, if any (*ALIGNED*) + //WORD padding2[]; //Padding, if any (ALIGNMENT) + //xxxxx Child[]; //Child block(s), if any (*ALIGNED*) + ////////// +}; + + +/// IMPORTS /// +#pragma pack(push, 8) +struct image_thunk_data64 +{ + union + { + uint64_t ForwarderString; // PBYTE + uint64_t Function; // PDWORD + uint64_t Ordinal; + uint64_t AddressOfData; // PIMAGE_IMPORT_BY_NAME + } u1; +}; +#pragma pack(pop) + +struct image_thunk_data32 +{ + union + { + uint32_t ForwarderString; // PBYTE + uint32_t Function; // PDWORD + uint32_t Ordinal; + uint32_t AddressOfData; // PIMAGE_IMPORT_BY_NAME + } u1; +}; + +struct image_import_descriptor +{ + union + { + uint32_t Characteristics; // 0 for terminating null import descriptor + uint32_t OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA) + }; + + uint32_t TimeDateStamp; // 0 if not bound, + // -1 if bound, and real date\time stamp + // in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND) + // O.W. date/time stamp of DLL bound to (Old BIND) + + uint32_t ForwarderChain; // -1 if no forwarders + uint32_t Name; + uint32_t FirstThunk; // RVA to IAT (if bound this IAT has actual addresses) +}; + + +/// TLS /// +struct image_tls_directory64 +{ + uint64_t StartAddressOfRawData; + uint64_t EndAddressOfRawData; + uint64_t AddressOfIndex; // PDWORD + uint64_t AddressOfCallBacks; // PIMAGE_TLS_CALLBACK *; + uint32_t SizeOfZeroFill; + uint32_t Characteristics; +}; + +struct image_tls_directory32 +{ + uint32_t StartAddressOfRawData; + uint32_t EndAddressOfRawData; + uint32_t AddressOfIndex; // PDWORD + uint32_t AddressOfCallBacks; // PIMAGE_TLS_CALLBACK * + uint32_t SizeOfZeroFill; + uint32_t Characteristics; +}; + + +/// Export Format /// +struct image_export_directory +{ + uint32_t Characteristics; + uint32_t TimeDateStamp; + uint16_t MajorVersion; + uint16_t MinorVersion; + uint32_t Name; + uint32_t Base; + uint32_t NumberOfFunctions; + uint32_t NumberOfNames; + uint32_t AddressOfFunctions; // RVA from base of image + uint32_t AddressOfNames; // RVA from base of image + uint32_t AddressOfNameOrdinals; // RVA from base of image +}; + + +/// Based relocation format /// +struct image_base_relocation +{ + uint32_t VirtualAddress; + uint32_t SizeOfBlock; + // uint16_t TypeOffset[1]; +}; + + +/// New format import descriptors pointed to by DataDirectory[ IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT ] /// +struct image_bound_import_descriptor +{ + uint32_t TimeDateStamp; + uint16_t OffsetModuleName; + uint16_t NumberOfModuleForwarderRefs; + // Array of zero or more IMAGE_BOUND_FORWARDER_REF follows +}; + +struct image_bound_forwarder_ref +{ + uint32_t TimeDateStamp; + uint16_t OffsetModuleName; + uint16_t Reserved; +}; + + +/// Exception directory /// +struct image_runtime_function_entry +{ + uint32_t BeginAddress; + uint32_t EndAddress; + uint32_t UnwindInfoAddress; +}; + +enum unwind_op_codes +{ + uwop_push_nonvol = 0, /* info == register number */ + uwop_alloc_large, /* no info, alloc size in next 2 slots */ + uwop_alloc_small, /* info == size of allocation / 8 - 1 */ + uwop_set_fpreg, /* no info, FP = RSP + UNWIND_INFO.FPRegOffset*16 */ + uwop_save_nonvol, /* info == register number, offset in next slot */ + uwop_save_nonvol_far, /* info == register number, offset in next 2 slots */ + uwop_save_xmm128, /* info == XMM reg number, offset in next slot */ + uwop_save_xmm128_far, /* info == XMM reg number, offset in next 2 slots */ + uwop_push_machframe /* info == 0: no error-code, 1: error-code */ +}; + +union unwind_code +{ + struct s + { + uint8_t CodeOffset; + uint8_t UnwindOp : 4; + uint8_t OpInfo : 4; + }; + + uint16_t FrameOffset; +}; + +struct unwind_info +{ + uint8_t Version : 3; + uint8_t Flags : 5; + uint8_t SizeOfProlog; + uint8_t CountOfCodes; + uint8_t FrameRegister : 4; + uint8_t FrameOffset : 4; + unwind_code UnwindCode[1]; + /* unwind_code MoreUnwindCode[((CountOfCodes + 1) & ~1) - 1]; + * union { + * OPTIONAL ULONG ExceptionHandler; + * OPTIONAL ULONG FunctionEntry; + * }; + * OPTIONAL ULONG ExceptionData[]; */ +}; + + + +/// Debug /// +struct image_debug_misc +{ + uint32_t DataType; // type of misc data, see defines + uint32_t Length; // total length of record, rounded to four + // byte multiple. + uint8_t Unicode; // TRUE if data is unicode string + uint8_t Reserved[3]; + uint8_t Data[1]; // Actual data +}; + +struct image_coff_symbols_header +{ + uint32_t NumberOfSymbols; + uint32_t LvaToFirstSymbol; + uint32_t NumberOfLinenumbers; + uint32_t LvaToFirstLinenumber; + uint32_t RvaToFirstByteOfCode; + uint32_t RvaToLastByteOfCode; + uint32_t RvaToFirstByteOfData; + uint32_t RvaToLastByteOfData; +}; + +struct image_debug_directory +{ + uint32_t Characteristics; + uint32_t TimeDateStamp; + uint16_t MajorVersion; + uint16_t MinorVersion; + uint32_t Type; + uint32_t SizeOfData; + uint32_t AddressOfRawData; + uint32_t PointerToRawData; +}; + + +#pragma pack(push, 2) +struct image_symbol +{ + union + { + uint8_t ShortName[8]; + struct + { + uint32_t Short; // if 0, use LongName + uint32_t Long; // offset into string table + } Name; + uint32_t LongName[2]; // PBYTE [2] + } N; + uint32_t Value; + int16_t SectionNumber; + uint16_t Type; + uint8_t StorageClass; + uint8_t NumberOfAuxSymbols; +}; +#pragma pack(pop) + +//CodeView Debug OMF signature. The signature at the end of the file is +//a negative offset from the end of the file to another signature. At +//the negative offset (base address) is another signature whose filepos +//field points to the first OMFDirHeader in a chain of directories. +//The NB05 signature is used by the link utility to indicated a completely +//unpacked file. The NB06 signature is used by ilink to indicate that the +//executable has had CodeView information from an incremental link appended +//to the executable. The NB08 signature is used by cvpack to indicate that +//the CodeView Debug OMF has been packed. CodeView will only process +//executables with the NB08 signature. +struct OMFSignature +{ + char Signature[4]; // "NBxx" + uint32_t filepos; // offset in file +}; + +struct CV_INFO_PDB20 +{ + OMFSignature CvHeader; + uint32_t Signature; + uint32_t Age; + uint8_t PdbFileName[1]; +}; + +struct CV_INFO_PDB70 +{ + uint32_t CvSignature; + guid Signature; + uint32_t Age; + uint8_t PdbFileName[1]; +}; + +// directory information structure +// This structure contains the information describing the directory. +// It is pointed to by the signature at the base address or the directory +// link field of a preceeding directory. The directory entries immediately +// follow this structure. +struct OMFDirHeader +{ + uint16_t cbDirHeader; // length of this structure + uint16_t cbDirEntry; // number of bytes in each directory entry + uint32_t cDir; // number of directorie entries + int32_t lfoNextDir; // offset from base of next directory + uint32_t flags; // status flags +}; + +// directory structure +// The data in this structure is used to reference the data for each +// subsection of the CodeView Debug OMF information. Tables that are +// not associated with a specific module will have a module index of +// oxffff. These tables are the global types table, the global symbol +// table, the global public table and the library table. +struct OMFDirEntry +{ + uint16_t SubSection; // subsection type (sst...) + uint16_t iMod; // module index + int32_t lfo; // large file offset of subsection + uint32_t cb; // number of bytes in subsection +}; + + +/// CLR 2.0 header structure /// +struct image_cor20_header +{ + //Header versioning + uint32_t cb; + uint16_t MajorRuntimeVersion; + uint16_t MinorRuntimeVersion; + + // Symbol table and startup information + image_data_directory MetaData; + uint32_t Flags; + + // If COMIMAGE_FLAGS_NATIVE_ENTRYPOINT is not set, EntryPointToken represents a managed entrypoint. + // If COMIMAGE_FLAGS_NATIVE_ENTRYPOINT is set, EntryPointRVA represents an RVA to a native entrypoint. + union + { + uint32_t EntryPointToken; + uint32_t EntryPointRVA; + }; + + // Binding information + image_data_directory Resources; + image_data_directory StrongNameSignature; + + // Regular fixup and binding information + image_data_directory CodeManagerTable; + image_data_directory VTableFixups; + image_data_directory ExportAddressTableJumps; + + // Precompiled image info (internal use only - set to zero) + image_data_directory ManagedNativeHeader; +}; + +enum replaces_cor_hdr_numeric_defines +{ + // COM+ Header entry point flags. + comimage_flags_ilonly =0x00000001, + comimage_flags_32bitrequired =0x00000002, + comimage_flags_il_library =0x00000004, + comimage_flags_strongnamesigned =0x00000008, + comimage_flags_native_entrypoint =0x00000010, + comimage_flags_trackdebugdata =0x00010000, + + // Version flags for image. + cor_version_major_v2 =2, + cor_version_major =cor_version_major_v2, + cor_version_minor =0, + cor_deleted_name_length =8, + cor_vtablegap_name_length =8, + + // Maximum size of a NativeType descriptor. + native_type_max_cb =1, + cor_ilmethod_sect_small_max_datasize=0xff, + + // #defines for the MIH FLAGS + image_cor_mih_methodrva =0x01, + image_cor_mih_ehrva =0x02, + image_cor_mih_basicblock =0x08, + + // V-table constants + cor_vtable_32bit =0x01, // V-table slots are 32-bits in size. + cor_vtable_64bit =0x02, // V-table slots are 64-bits in size. + cor_vtable_from_unmanaged =0x04, // If set, transition from unmanaged. + cor_vtable_from_unmanaged_retain_appdomain =0x08, // If set, transition from unmanaged with keeping the current appdomain. + cor_vtable_call_most_derived =0x10, // Call most derived method described by + + // EATJ constants + image_cor_eatj_thunk_size =32, // Size of a jump thunk reserved range. + + // Max name lengths + //@todo: Change to unlimited name lengths. + max_class_name =1024, + max_package_name =1024 +}; + +/// Load Configuration Directory Entry /// +struct image_load_config_directory32 +{ + uint32_t Size; + uint32_t TimeDateStamp; + uint16_t MajorVersion; + uint16_t MinorVersion; + uint32_t GlobalFlagsClear; + uint32_t GlobalFlagsSet; + uint32_t CriticalSectionDefaultTimeout; + uint32_t DeCommitFreeBlockThreshold; + uint32_t DeCommitTotalFreeThreshold; + uint32_t LockPrefixTable; // VA + uint32_t MaximumAllocationSize; + uint32_t VirtualMemoryThreshold; + uint32_t ProcessHeapFlags; + uint32_t ProcessAffinityMask; + uint16_t CSDVersion; + uint16_t Reserved1; + uint32_t EditList; // VA + uint32_t SecurityCookie; // VA + uint32_t SEHandlerTable; // VA + uint32_t SEHandlerCount; +}; + +struct image_load_config_directory64 +{ + uint32_t Size; + uint32_t TimeDateStamp; + uint16_t MajorVersion; + uint16_t MinorVersion; + uint32_t GlobalFlagsClear; + uint32_t GlobalFlagsSet; + uint32_t CriticalSectionDefaultTimeout; + uint64_t DeCommitFreeBlockThreshold; + uint64_t DeCommitTotalFreeThreshold; + uint64_t LockPrefixTable; // VA + uint64_t MaximumAllocationSize; + uint64_t VirtualMemoryThreshold; + uint64_t ProcessAffinityMask; + uint32_t ProcessHeapFlags; + uint16_t CSDVersion; + uint16_t Reserved1; + uint64_t EditList; // VA + uint64_t SecurityCookie; // VA + uint64_t SEHandlerTable; // VA + uint64_t SEHandlerCount; +}; + +#pragma pack(pop) +} //namespace pe_win + +#ifdef PE_BLISS_WINDOWS +typedef wchar_t unicode16_t; +typedef std::basic_string u16string; +#else +//Instead of wchar_t for windows +typedef unsigned short unicode16_t; +typedef std::basic_string u16string; +#endif + +} //namespace pe_bliss diff --git a/drivers/pe_bliss/pe_tls.cpp b/drivers/pe_bliss/pe_tls.cpp new file mode 100644 index 0000000000..182859f1bf --- /dev/null +++ b/drivers/pe_bliss/pe_tls.cpp @@ -0,0 +1,375 @@ +#include +#include "pe_tls.h" +#include "pe_properties_generic.h" + +namespace pe_bliss +{ +using namespace pe_win; + +//TLS +//Default constructor +tls_info::tls_info() + :start_rva_(0), end_rva_(0), index_rva_(0), callbacks_rva_(0), + size_of_zero_fill_(0), characteristics_(0) +{} + +//Returns start RVA of TLS raw data +uint32_t tls_info::get_raw_data_start_rva() const +{ + return start_rva_; +} + +//Returns end RVA of TLS raw data +uint32_t tls_info::get_raw_data_end_rva() const +{ + return end_rva_; +} + +//Returns TLS index RVA +uint32_t tls_info::get_index_rva() const +{ + return index_rva_; +} + +//Returns TLS callbacks RVA +uint32_t tls_info::get_callbacks_rva() const +{ + return callbacks_rva_; +} + +//Returns size of zero fill +uint32_t tls_info::get_size_of_zero_fill() const +{ + return size_of_zero_fill_; +} + +//Returns characteristics +uint32_t tls_info::get_characteristics() const +{ + return characteristics_; +} + +//Returns raw TLS data +const std::string& tls_info::get_raw_data() const +{ + return raw_data_; +} + +//Returns TLS callbacks addresses +const tls_info::tls_callback_list& tls_info::get_tls_callbacks() const +{ + return callbacks_; +} + +//Returns TLS callbacks addresses +tls_info::tls_callback_list& tls_info::get_tls_callbacks() +{ + return callbacks_; +} + +//Adds TLS callback +void tls_info::add_tls_callback(uint32_t rva) +{ + callbacks_.push_back(rva); +} + +//Clears TLS callbacks list +void tls_info::clear_tls_callbacks() +{ + callbacks_.clear(); +} + +//Recalculates end address of raw TLS data +void tls_info::recalc_raw_data_end_rva() +{ + end_rva_ = static_cast(start_rva_ + raw_data_.length()); +} + +//Sets start RVA of TLS raw data +void tls_info::set_raw_data_start_rva(uint32_t rva) +{ + start_rva_ = rva; +} + +//Sets end RVA of TLS raw data +void tls_info::set_raw_data_end_rva(uint32_t rva) +{ + end_rva_ = rva; +} + +//Sets TLS index RVA +void tls_info::set_index_rva(uint32_t rva) +{ + index_rva_ = rva; +} + +//Sets TLS callbacks RVA +void tls_info::set_callbacks_rva(uint32_t rva) +{ + callbacks_rva_ = rva; +} + +//Sets size of zero fill +void tls_info::set_size_of_zero_fill(uint32_t size) +{ + size_of_zero_fill_ = size; +} + +//Sets characteristics +void tls_info::set_characteristics(uint32_t characteristics) +{ + characteristics_ = characteristics; +} + +//Sets raw TLS data +void tls_info::set_raw_data(const std::string& data) +{ + raw_data_ = data; +} + +//If image does not have TLS, throws an exception +const tls_info get_tls_info(const pe_base& pe) +{ + return pe.get_pe_type() == pe_type_32 + ? get_tls_info_base(pe) + : get_tls_info_base(pe); +} + +//TLS Rebuilder +const image_directory rebuild_tls(pe_base& pe, const tls_info& info, section& tls_section, uint32_t offset_from_section_start, bool write_tls_callbacks, bool write_tls_data, tls_data_expand_type expand, bool save_to_pe_header, bool auto_strip_last_section) +{ + return pe.get_pe_type() == pe_type_32 + ? rebuild_tls_base(pe, info, tls_section, offset_from_section_start, write_tls_callbacks, write_tls_data, expand, save_to_pe_header, auto_strip_last_section) + : rebuild_tls_base(pe, info, tls_section, offset_from_section_start, write_tls_callbacks, write_tls_data, expand, save_to_pe_header, auto_strip_last_section); +} + +//Get TLS info +//If image does not have TLS, throws an exception +template +const tls_info get_tls_info_base(const pe_base& pe) +{ + tls_info ret; + + //If there's no TLS directory, throw an exception + if(!pe.has_tls()) + throw pe_exception("Image does not have TLS directory", pe_exception::directory_does_not_exist); + + //Get TLS directory data + typename PEClassType::TLSStruct tls_directory_data = pe.section_data_from_rva(pe.get_directory_rva(image_directory_entry_tls), section_data_virtual, true); + + //Check data addresses + if(tls_directory_data.EndAddressOfRawData == tls_directory_data.StartAddressOfRawData) + { + try + { + pe.va_to_rva(static_cast(tls_directory_data.EndAddressOfRawData)); + } + catch(const pe_exception&) + { + //Fix addressess on incorrect conversion + tls_directory_data.EndAddressOfRawData = tls_directory_data.StartAddressOfRawData = 0; + } + } + + if(tls_directory_data.StartAddressOfRawData && + pe.section_data_length_from_va(static_cast(tls_directory_data.StartAddressOfRawData), + static_cast(tls_directory_data.StartAddressOfRawData), section_data_virtual, true) + < (tls_directory_data.EndAddressOfRawData - tls_directory_data.StartAddressOfRawData)) + throw pe_exception("Incorrect TLS directory", pe_exception::incorrect_tls_directory); + + //Fill TLS info + //VAs are not checked + ret.set_raw_data_start_rva(tls_directory_data.StartAddressOfRawData ? pe.va_to_rva(static_cast(tls_directory_data.StartAddressOfRawData)) : 0); + ret.set_raw_data_end_rva(tls_directory_data.EndAddressOfRawData ? pe.va_to_rva(static_cast(tls_directory_data.EndAddressOfRawData)) : 0); + ret.set_index_rva(tls_directory_data.AddressOfIndex ? pe.va_to_rva(static_cast(tls_directory_data.AddressOfIndex)) : 0); + ret.set_callbacks_rva(tls_directory_data.AddressOfCallBacks ? pe.va_to_rva(static_cast(tls_directory_data.AddressOfCallBacks)) : 0); + ret.set_size_of_zero_fill(tls_directory_data.SizeOfZeroFill); + ret.set_characteristics(tls_directory_data.Characteristics); + + if(tls_directory_data.StartAddressOfRawData && tls_directory_data.StartAddressOfRawData != tls_directory_data.EndAddressOfRawData) + { + //Read and save TLS RAW data + ret.set_raw_data(std::string( + pe.section_data_from_va(static_cast(tls_directory_data.StartAddressOfRawData), section_data_virtual, true), + static_cast(tls_directory_data.EndAddressOfRawData - tls_directory_data.StartAddressOfRawData))); + } + + //If file has TLS callbacks + if(ret.get_callbacks_rva()) + { + //Read callbacks VAs + uint32_t current_tls_callback = 0; + + while(true) + { + //Read TLS callback VA + typename PEClassType::BaseSize va = pe.section_data_from_va(static_cast(tls_directory_data.AddressOfCallBacks + current_tls_callback), section_data_virtual, true); + if(va == 0) + break; + + //Save it + ret.add_tls_callback(pe.va_to_rva(va, false)); + + //Move to next callback VA + current_tls_callback += sizeof(va); + } + } + + return ret; +} + +//Rebuilder of TLS structures +//If write_tls_callbacks = true, TLS callbacks VAs will be written to their place +//If write_tls_data = true, TLS data will be written to its place +//If you have chosen to rewrite raw data, only (EndAddressOfRawData - StartAddressOfRawData) bytes will be written, not the full length of string +//representing raw data content +//auto_strip_last_section - if true and TLS are placed in the last section, it will be automatically stripped +//Note/TODO: TLS Callbacks array is not DWORD-aligned (seems to work on WinXP - Win7) +template +const image_directory rebuild_tls_base(pe_base& pe, const tls_info& info, section& tls_section, uint32_t offset_from_section_start, bool write_tls_callbacks, bool write_tls_data, tls_data_expand_type expand, bool save_to_pe_header, bool auto_strip_last_section) +{ + //Check that tls_section is attached to this PE image + if(!pe.section_attached(tls_section)) + throw pe_exception("TLS section must be attached to PE file", pe_exception::section_is_not_attached); + + uint32_t tls_data_pos = pe_utils::align_up(offset_from_section_start, sizeof(typename PEClassType::BaseSize)); + uint32_t needed_size = sizeof(typename PEClassType::TLSStruct); //Calculate needed size for TLS table + + //Check if tls_section is last one. If it's not, check if there's enough place for TLS data + if(&tls_section != &*(pe.get_image_sections().end() - 1) && + (tls_section.empty() || pe_utils::align_up(tls_section.get_size_of_raw_data(), pe.get_file_alignment()) < needed_size + tls_data_pos)) + throw pe_exception("Insufficient space for TLS directory", pe_exception::insufficient_space); + + //Check raw data positions + if(info.get_raw_data_end_rva() < info.get_raw_data_start_rva() || info.get_index_rva() == 0) + throw pe_exception("Incorrect TLS directory", pe_exception::incorrect_tls_directory); + + std::string& raw_data = tls_section.get_raw_data(); + + //This will be done only if tls_section is the last section of image or for section with unaligned raw length of data + if(raw_data.length() < needed_size + tls_data_pos) + raw_data.resize(needed_size + tls_data_pos); //Expand section raw data + + //Create and fill TLS structure + typename PEClassType::TLSStruct tls_struct = {0}; + + typename PEClassType::BaseSize va; + if(info.get_raw_data_start_rva()) + { + pe.rva_to_va(info.get_raw_data_start_rva(), va); + tls_struct.StartAddressOfRawData = va; + tls_struct.SizeOfZeroFill = info.get_size_of_zero_fill(); + } + + if(info.get_raw_data_end_rva()) + { + pe.rva_to_va(info.get_raw_data_end_rva(), va); + tls_struct.EndAddressOfRawData = va; + } + + pe.rva_to_va(info.get_index_rva(), va); + tls_struct.AddressOfIndex = va; + + if(info.get_callbacks_rva()) + { + pe.rva_to_va(info.get_callbacks_rva(), va); + tls_struct.AddressOfCallBacks = va; + } + + tls_struct.Characteristics = info.get_characteristics(); + + //Save TLS structure + memcpy(&raw_data[tls_data_pos], &tls_struct, sizeof(tls_struct)); + + //If we are asked to rewrite TLS raw data + if(write_tls_data && info.get_raw_data_start_rva() && info.get_raw_data_start_rva() != info.get_raw_data_end_rva()) + { + try + { + //Check if we're going to write TLS raw data to an existing section (not to PE headers) + section& raw_data_section = pe.section_from_rva(info.get_raw_data_start_rva()); + pe.expand_section(raw_data_section, info.get_raw_data_start_rva(), info.get_raw_data_end_rva() - info.get_raw_data_start_rva(), expand == tls_data_expand_raw ? pe_base::expand_section_raw : pe_base::expand_section_virtual); + } + catch(const pe_exception&) + { + //If no section is presented by StartAddressOfRawData, just go to next step + } + + unsigned long write_raw_data_size = info.get_raw_data_end_rva() - info.get_raw_data_start_rva(); + unsigned long available_raw_length = 0; + + //Check if there's enough RAW space to write raw TLS data... + if((available_raw_length = pe.section_data_length_from_rva(info.get_raw_data_start_rva(), info.get_raw_data_start_rva(), section_data_raw, true)) + < info.get_raw_data_end_rva() - info.get_raw_data_start_rva()) + { + //Check if there's enough virtual space for it... + if(pe.section_data_length_from_rva(info.get_raw_data_start_rva(), info.get_raw_data_start_rva(), section_data_virtual, true) + < info.get_raw_data_end_rva() - info.get_raw_data_start_rva()) + throw pe_exception("Insufficient space for TLS raw data", pe_exception::insufficient_space); + else + write_raw_data_size = available_raw_length; //We'll write just a part of full raw data + } + + //Write raw TLS data, if any + if(write_raw_data_size != 0) + memcpy(pe.section_data_from_rva(info.get_raw_data_start_rva(), true), info.get_raw_data().data(), write_raw_data_size); + } + + //If we are asked to rewrite TLS callbacks addresses + if(write_tls_callbacks && info.get_callbacks_rva()) + { + unsigned long needed_callback_size = static_cast((info.get_tls_callbacks().size() + 1 /* last null element */) * sizeof(typename PEClassType::BaseSize)); + + try + { + //Check if we're going to write TLS callbacks VAs to an existing section (not to PE headers) + section& raw_data_section = pe.section_from_rva(info.get_callbacks_rva()); + pe.expand_section(raw_data_section, info.get_callbacks_rva(), needed_callback_size, pe_base::expand_section_raw); + } + catch(const pe_exception&) + { + //If no section is presented by RVA of callbacks, just go to next step + } + + //Check if there's enough space to write callbacks TLS data... + if(pe.section_data_length_from_rva(info.get_callbacks_rva(), info.get_callbacks_rva(), section_data_raw, true) + < needed_callback_size - sizeof(typename PEClassType::BaseSize) /* last zero element can be virtual only */) + throw pe_exception("Insufficient space for TLS callbacks data", pe_exception::insufficient_space); + + if(pe.section_data_length_from_rva(info.get_callbacks_rva(), info.get_callbacks_rva(), section_data_virtual, true) + < needed_callback_size /* check here full virtual data length available */) + throw pe_exception("Insufficient space for TLS callbacks data", pe_exception::insufficient_space); + + std::vector callbacks_virtual_addresses; + callbacks_virtual_addresses.reserve(info.get_tls_callbacks().size() + 1 /* last null element */); + + //Convert TLS RVAs to VAs + for(tls_info::tls_callback_list::const_iterator it = info.get_tls_callbacks().begin(); it != info.get_tls_callbacks().end(); ++it) + { + typename PEClassType::BaseSize cb_va = 0; + pe.rva_to_va(*it, cb_va); + callbacks_virtual_addresses.push_back(cb_va); + } + + //Ending null element + callbacks_virtual_addresses.push_back(0); + + //Write callbacks TLS data + memcpy(pe.section_data_from_rva(info.get_callbacks_rva(), true), &callbacks_virtual_addresses[0], needed_callback_size); + } + + //Adjust section raw and virtual sizes + pe.recalculate_section_sizes(tls_section, auto_strip_last_section); + + image_directory ret(pe.rva_from_section_offset(tls_section, tls_data_pos), needed_size); + + //If auto-rewrite of PE headers is required + if(save_to_pe_header) + { + pe.set_directory_rva(image_directory_entry_tls, ret.get_rva()); + pe.set_directory_size(image_directory_entry_tls, ret.get_size()); + } + + return ret; +} +} diff --git a/drivers/pe_bliss/pe_tls.h b/drivers/pe_bliss/pe_tls.h new file mode 100644 index 0000000000..8740de83ec --- /dev/null +++ b/drivers/pe_bliss/pe_tls.h @@ -0,0 +1,101 @@ +#pragma once +#include +#include +#include "pe_base.h" +#include "pe_directory.h" + +namespace pe_bliss +{ +//Class representing TLS info +//We use "DWORD" type to represent RVAs, because RVA is +//always 32bit even in PE+ +class tls_info +{ +public: + typedef std::vector tls_callback_list; + +public: + //Default constructor + tls_info(); + + //Returns start RVA of TLS raw data + uint32_t get_raw_data_start_rva() const; + //Returns end RVA of TLS raw data + uint32_t get_raw_data_end_rva() const; + //Returns TLS index RVA + uint32_t get_index_rva() const; + //Returns TLS callbacks RVA + uint32_t get_callbacks_rva() const; + //Returns size of zero fill + uint32_t get_size_of_zero_fill() const; + //Returns characteristics + uint32_t get_characteristics() const; + //Returns raw TLS data + const std::string& get_raw_data() const; + //Returns TLS callbacks addresses + const tls_callback_list& get_tls_callbacks() const; + +public: //These functions do not change everything inside image, they are used by PE class + //You can also use them to rebuild TLS directory + + //Sets start RVA of TLS raw data + void set_raw_data_start_rva(uint32_t rva); + //Sets end RVA of TLS raw data + void set_raw_data_end_rva(uint32_t rva); + //Sets TLS index RVA + void set_index_rva(uint32_t rva); + //Sets TLS callbacks RVA + void set_callbacks_rva(uint32_t rva); + //Sets size of zero fill + void set_size_of_zero_fill(uint32_t size); + //Sets characteristics + void set_characteristics(uint32_t characteristics); + //Sets raw TLS data + void set_raw_data(const std::string& data); + //Returns TLS callbacks addresses + tls_callback_list& get_tls_callbacks(); + //Adds TLS callback + void add_tls_callback(uint32_t rva); + //Clears TLS callbacks list + void clear_tls_callbacks(); + //Recalculates end address of raw TLS data + void recalc_raw_data_end_rva(); + +private: + uint32_t start_rva_, end_rva_, index_rva_, callbacks_rva_; + uint32_t size_of_zero_fill_, characteristics_; + + //Raw TLS data + std::string raw_data_; + + //TLS callback RVAs + tls_callback_list callbacks_; +}; + +//Represents type of expanding of TLS section containing raw data +//(Works only if you are writing TLS raw data to tls_section and it is the last one in the PE image on the moment of TLS rebuild) +enum tls_data_expand_type +{ + tls_data_expand_raw, //If there is not enough raw space for raw TLS data, it can be expanded + tls_data_expand_virtual //If there is not enough virtual place for raw TLS data, it can be expanded +}; + + +//Get TLS info +//If image does not have TLS, throws an exception +const tls_info get_tls_info(const pe_base& pe); + +template +const tls_info get_tls_info_base(const pe_base& pe); + +//Rebuilder of TLS structures +//If write_tls_callbacks = true, TLS callbacks VAs will be written to their place +//If write_tls_data = true, TLS data will be written to its place +//If you have chosen to rewrite raw data, only (EndAddressOfRawData - StartAddressOfRawData) bytes will be written, not the full length of string +//representing raw data content +//auto_strip_last_section - if true and TLS are placed in the last section, it will be automatically stripped +const image_directory rebuild_tls(pe_base& pe, const tls_info& info, section& tls_section, uint32_t offset_from_section_start = 0, bool write_tls_callbacks = true, bool write_tls_data = true, tls_data_expand_type expand = tls_data_expand_raw, bool save_to_pe_header = true, bool auto_strip_last_section = true); + +template +const image_directory rebuild_tls_base(pe_base& pe, const tls_info& info, section& tls_section, uint32_t offset_from_section_start = 0, bool write_tls_callbacks = true, bool write_tls_data = true, tls_data_expand_type expand = tls_data_expand_raw, bool save_to_pe_header = true, bool auto_strip_last_section = true); +} diff --git a/drivers/pe_bliss/resource_bitmap_reader.cpp b/drivers/pe_bliss/resource_bitmap_reader.cpp new file mode 100644 index 0000000000..29eff549db --- /dev/null +++ b/drivers/pe_bliss/resource_bitmap_reader.cpp @@ -0,0 +1,65 @@ +#include +#include "resource_bitmap_reader.h" +#include "pe_resource_viewer.h" +#include "pe_structures.h" + +namespace pe_bliss +{ +using namespace pe_win; + +resource_bitmap_reader::resource_bitmap_reader(const pe_resource_viewer& res) + :res_(res) +{} + +//Returns bitmap data by name and index in language directory (instead of language) (minimum checks of format correctness) +const std::string resource_bitmap_reader::get_bitmap_by_name(const std::wstring& name, uint32_t index) const +{ + return create_bitmap(res_.get_resource_data_by_name(pe_resource_viewer::resource_bitmap, name, index).get_data()); +} + +//Returns bitmap data by name and language (minimum checks of format correctness) +const std::string resource_bitmap_reader::get_bitmap_by_name(uint32_t language, const std::wstring& name) const +{ + return create_bitmap(res_.get_resource_data_by_name(language, pe_resource_viewer::resource_bitmap, name).get_data()); +} + +//Returns bitmap data by ID and language (minimum checks of format correctness) +const std::string resource_bitmap_reader::get_bitmap_by_id_lang(uint32_t language, uint32_t id) const +{ + return create_bitmap(res_.get_resource_data_by_id(language, pe_resource_viewer::resource_bitmap, id).get_data()); +} + +//Returns bitmap data by ID and index in language directory (instead of language) (minimum checks of format correctness) +const std::string resource_bitmap_reader::get_bitmap_by_id(uint32_t id, uint32_t index) const +{ + return create_bitmap(res_.get_resource_data_by_id(pe_resource_viewer::resource_bitmap, id, index).get_data()); +} + +//Helper function of creating bitmap header +const std::string resource_bitmap_reader::create_bitmap(const std::string& resource_data) +{ + //Create bitmap file header + bitmapfileheader header = {0}; + header.bfType = 0x4d42; //Signature "BM" + header.bfOffBits = sizeof(bitmapfileheader) + sizeof(bitmapinfoheader); //Offset to bitmap bits + header.bfSize = static_cast(sizeof(bitmapfileheader) + resource_data.length()); //Size of bitmap + + //Check size of resource data + if(resource_data.length() < sizeof(bitmapinfoheader)) + throw pe_exception("Incorrect resource bitmap", pe_exception::resource_incorrect_bitmap); + + { + //Get bitmap info header + const bitmapinfoheader* info = reinterpret_cast(resource_data.data()); + + //If color table is present, skip it + if(info->biClrUsed != 0) + header.bfOffBits += 4 * info->biClrUsed; //Add this size to offset to bitmap bits + else if(info->biBitCount <= 8) + header.bfOffBits += 4 * static_cast(std::pow(2.f, info->biBitCount)); //Add this size to offset to bitmap bits + } + + //Return final bitmap data + return std::string(reinterpret_cast(&header), sizeof(bitmapfileheader)) + resource_data; +} +} diff --git a/drivers/pe_bliss/resource_bitmap_reader.h b/drivers/pe_bliss/resource_bitmap_reader.h new file mode 100644 index 0000000000..2e99571cab --- /dev/null +++ b/drivers/pe_bliss/resource_bitmap_reader.h @@ -0,0 +1,29 @@ +#pragma once +#include +#include "stdint_defs.h" + +namespace pe_bliss +{ +class pe_resource_viewer; + +class resource_bitmap_reader +{ +public: + resource_bitmap_reader(const pe_resource_viewer& res); + + //Returns bitmap data by name and language (minimum checks of format correctness) + const std::string get_bitmap_by_name(uint32_t language, const std::wstring& name) const; + //Returns bitmap data by name and index in language directory (instead of language) (minimum checks of format correctness) + const std::string get_bitmap_by_name(const std::wstring& name, uint32_t index = 0) const; + //Returns bitmap data by ID and language (minimum checks of format correctness) + const std::string get_bitmap_by_id_lang(uint32_t language, uint32_t id) const; + //Returns bitmap data by ID and index in language directory (instead of language) (minimum checks of format correctness) + const std::string get_bitmap_by_id(uint32_t id, uint32_t index = 0) const; + +private: + //Helper function of creating bitmap header + static const std::string create_bitmap(const std::string& resource_data); + + const pe_resource_viewer& res_; +}; +} diff --git a/drivers/pe_bliss/resource_bitmap_writer.cpp b/drivers/pe_bliss/resource_bitmap_writer.cpp new file mode 100644 index 0000000000..2a28ff6e68 --- /dev/null +++ b/drivers/pe_bliss/resource_bitmap_writer.cpp @@ -0,0 +1,54 @@ +#include "resource_bitmap_writer.h" +#include "pe_resource_manager.h" +#include "pe_structures.h" + +namespace pe_bliss +{ +using namespace pe_win; + +resource_bitmap_writer::resource_bitmap_writer(pe_resource_manager& res) + :res_(res) +{} + +//Adds bitmap from bitmap file data. If bitmap already exists, replaces it +//timestamp will be used for directories that will be added +void resource_bitmap_writer::add_bitmap(const std::string& bitmap_file, uint32_t id, uint32_t language, uint32_t codepage, uint32_t timestamp) +{ + //Check bitmap data a little + if(bitmap_file.length() < sizeof(bitmapfileheader)) + throw pe_exception("Incorrect resource bitmap", pe_exception::resource_incorrect_bitmap); + + resource_directory_entry new_entry; + new_entry.set_id(id); + + //Add bitmap + res_.add_resource(bitmap_file.substr(sizeof(bitmapfileheader)), pe_resource_viewer::resource_bitmap, new_entry, resource_directory::entry_finder(id), language, codepage, timestamp); +} + +//Adds bitmap from bitmap file data. If bitmap already exists, replaces it +//timestamp will be used for directories that will be added +void resource_bitmap_writer::add_bitmap(const std::string& bitmap_file, const std::wstring& name, uint32_t language, uint32_t codepage, uint32_t timestamp) +{ + //Check bitmap data a little + if(bitmap_file.length() < sizeof(bitmapfileheader)) + throw pe_exception("Incorrect resource bitmap", pe_exception::resource_incorrect_bitmap); + + resource_directory_entry new_entry; + new_entry.set_name(name); + + //Add bitmap + res_.add_resource(bitmap_file.substr(sizeof(bitmapfileheader)), pe_resource_viewer::resource_bitmap, new_entry, resource_directory::entry_finder(name), language, codepage, timestamp); +} + +//Removes bitmap by name/ID and language +bool resource_bitmap_writer::remove_bitmap(const std::wstring& name, uint32_t language) +{ + return res_.remove_resource(pe_resource_viewer::resource_bitmap, name, language); +} + +//Removes bitmap by name/ID and language +bool resource_bitmap_writer::remove_bitmap(uint32_t id, uint32_t language) +{ + return res_.remove_resource(pe_resource_viewer::resource_bitmap, id, language); +} +} diff --git a/drivers/pe_bliss/resource_bitmap_writer.h b/drivers/pe_bliss/resource_bitmap_writer.h new file mode 100644 index 0000000000..a5a2a4abd4 --- /dev/null +++ b/drivers/pe_bliss/resource_bitmap_writer.h @@ -0,0 +1,26 @@ +#pragma once +#include +#include "stdint_defs.h" + +namespace pe_bliss +{ +class pe_resource_manager; + +class resource_bitmap_writer +{ +public: + resource_bitmap_writer(pe_resource_manager& res); + + //Adds bitmap from bitmap file data. If bitmap already exists, replaces it + //timestamp will be used for directories that will be added + void add_bitmap(const std::string& bitmap_file, uint32_t id, uint32_t language, uint32_t codepage = 0, uint32_t timestamp = 0); + void add_bitmap(const std::string& bitmap_file, const std::wstring& name, uint32_t language, uint32_t codepage = 0, uint32_t timestamp = 0); + + //Removes bitmap by name/ID and language + bool remove_bitmap(const std::wstring& name, uint32_t language); + bool remove_bitmap(uint32_t id, uint32_t language); + +private: + pe_resource_manager& res_; +}; +} diff --git a/drivers/pe_bliss/resource_cursor_icon_reader.cpp b/drivers/pe_bliss/resource_cursor_icon_reader.cpp new file mode 100644 index 0000000000..514e288c22 --- /dev/null +++ b/drivers/pe_bliss/resource_cursor_icon_reader.cpp @@ -0,0 +1,500 @@ +#include +#include "resource_cursor_icon_reader.h" +#include "pe_structures.h" +#include "pe_resource_viewer.h" + +namespace pe_bliss +{ +using namespace pe_win; + +resource_cursor_icon_reader::resource_cursor_icon_reader(const pe_resource_viewer& res) + :res_(res) +{} + +//Helper function of creating icon headers from ICON_GROUP resource data +//Returns icon count +uint16_t resource_cursor_icon_reader::format_icon_headers(std::string& ico_data, const std::string& resource_data) +{ + //Check resource data size + if(resource_data.length() < sizeof(ico_header)) + throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon); + + //Get icon header + const ico_header* info = reinterpret_cast(resource_data.data()); + + //Check resource data size + if(resource_data.length() < sizeof(ico_header) + info->Count * sizeof(icon_group)) + throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon); + + //Reserve memory to speed up a little + ico_data.reserve(sizeof(ico_header) + info->Count * sizeof(icondirentry)); + ico_data.append(reinterpret_cast(info), sizeof(ico_header)); + + //Iterate over all listed icons + uint32_t offset = sizeof(ico_header) + sizeof(icondirentry) * info->Count; + for(uint16_t i = 0; i != info->Count; ++i) + { + const icon_group* group = reinterpret_cast(resource_data.data() + sizeof(ico_header) + i * sizeof(icon_group)); + + //Fill icon data + icondirentry direntry; + direntry.BitCount = group->BitCount; + direntry.ColorCount = group->ColorCount; + direntry.Height = group->Height; + direntry.Planes = group->Planes; + direntry.Reserved = group->Reserved; + direntry.SizeInBytes = group->SizeInBytes; + direntry.Width = group->Width; + direntry.ImageOffset = offset; + + //Add icon header to returned value + ico_data.append(reinterpret_cast(&direntry), sizeof(icondirentry)); + + offset += group->SizeInBytes; + } + + //Return icon count + return info->Count; +} + +//Returns single icon data by ID and language (minimum checks of format correctness) +const std::string resource_cursor_icon_reader::get_single_icon_by_id_lang(uint32_t language, uint32_t id) const +{ + //Get icon headers + std::string icon_data(lookup_icon_group_data_by_icon(id, language)); + //Append icon data + icon_data.append(res_.get_resource_data_by_id(language, pe_resource_viewer::resource_icon, id).get_data()); + return icon_data; +} + +//Returns single icon data by ID and index in language directory (instead of language) (minimum checks of format correctness) +const std::string resource_cursor_icon_reader::get_single_icon_by_id(uint32_t id, uint32_t index) const +{ + pe_resource_viewer::resource_language_list languages(res_.list_resource_languages(pe_resource_viewer::resource_icon, id)); + if(languages.size() <= index) + throw pe_exception("Resource data entry not found", pe_exception::resource_data_entry_not_found); + + //Get icon headers + std::string icon_data(lookup_icon_group_data_by_icon(id, languages.at(index))); + //Append icon data + icon_data.append(res_.get_resource_data_by_id(pe_resource_viewer::resource_icon, id, index).get_data()); + return icon_data; +} + +//Returns icon data by name and index in language directory (instead of language) (minimum checks of format correctness) +const std::string resource_cursor_icon_reader::get_icon_by_name(const std::wstring& name, uint32_t index) const +{ + std::string ret; + + //Get resource by name and index + const std::string data = res_.get_resource_data_by_name(pe_resource_viewer::resource_icon_group, name, index).get_data(); + + //Create icon headers + uint16_t icon_count = format_icon_headers(ret, data); + + //Append icon data + for(uint16_t i = 0; i != icon_count; ++i) + { + const icon_group* group = reinterpret_cast(data.data() + sizeof(ico_header) + i * sizeof(icon_group)); + ret += res_.get_resource_data_by_id(pe_resource_viewer::resource_icon, group->Number, index).get_data(); + } + + return ret; +} + +//Returns icon data by name and language (minimum checks of format correctness) +const std::string resource_cursor_icon_reader::get_icon_by_name(uint32_t language, const std::wstring& name) const +{ + std::string ret; + + //Get resource by name and language + const std::string data = res_.get_resource_data_by_name(language, pe_resource_viewer::resource_icon_group, name).get_data(); + + //Create icon headers + uint16_t icon_count = format_icon_headers(ret, data); + + //Append icon data + for(uint16_t i = 0; i != icon_count; ++i) + { + const icon_group* group = reinterpret_cast(data.data() + sizeof(ico_header) + i * sizeof(icon_group)); + ret += res_.get_resource_data_by_id(language, pe_resource_viewer::resource_icon, group->Number).get_data(); + } + + return ret; +} + +//Returns icon data by ID and language (minimum checks of format correctness) +const std::string resource_cursor_icon_reader::get_icon_by_id_lang(uint32_t language, uint32_t id) const +{ + std::string ret; + + //Get resource by language and id + const std::string data = res_.get_resource_data_by_id(language, pe_resource_viewer::resource_icon_group, id).get_data(); + + //Create icon headers + uint16_t icon_count = format_icon_headers(ret, data); + + //Append icon data + for(uint16_t i = 0; i != icon_count; ++i) + { + const icon_group* group = reinterpret_cast(data.data() + sizeof(ico_header) + i * sizeof(icon_group)); + ret += res_.get_resource_data_by_id(language, pe_resource_viewer::resource_icon, group->Number).get_data(); + } + + return ret; +} + +//Returns icon data by ID and index in language directory (instead of language) (minimum checks of format correctness) +const std::string resource_cursor_icon_reader::get_icon_by_id(uint32_t id, uint32_t index) const +{ + std::string ret; + + //Get resource by id and index + const std::string data = res_.get_resource_data_by_id(pe_resource_viewer::resource_icon_group, id, index).get_data(); + + //Create icon headers + uint16_t icon_count = format_icon_headers(ret, data); + + //Append icon data + for(uint16_t i = 0; i != icon_count; ++i) + { + const icon_group* group = reinterpret_cast(data.data() + sizeof(ico_header) + i * sizeof(icon_group)); + ret += res_.get_resource_data_by_id(pe_resource_viewer::resource_icon, group->Number, index).get_data(); + } + + return ret; +} + +//Checks for icon presence inside icon group, fills icon headers if found +bool resource_cursor_icon_reader::check_icon_presence(const std::string& icon_group_resource_data, uint32_t icon_id, std::string& ico_data) +{ + //Check resource data size + if(icon_group_resource_data.length() < sizeof(ico_header)) + throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon); + + //Get icon header + const ico_header* info = reinterpret_cast(icon_group_resource_data.data()); + + //Check resource data size + if(icon_group_resource_data.length() < sizeof(ico_header) + info->Count * sizeof(icon_group)) + throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon); + + for(uint16_t i = 0; i != info->Count; ++i) + { + const icon_group* group = reinterpret_cast(icon_group_resource_data.data() + sizeof(ico_header) + i * sizeof(icon_group)); + if(group->Number == icon_id) + { + //Reserve memory to speed up a little + ico_data.reserve(sizeof(ico_header) + sizeof(icondirentry)); + //Write single-icon icon header + ico_header new_header = *info; + new_header.Count = 1; + ico_data.append(reinterpret_cast(&new_header), sizeof(ico_header)); + + //Fill icon data + icondirentry direntry; + direntry.BitCount = group->BitCount; + direntry.ColorCount = group->ColorCount; + direntry.Height = group->Height; + direntry.Planes = group->Planes; + direntry.Reserved = group->Reserved; + direntry.SizeInBytes = group->SizeInBytes; + direntry.Width = group->Width; + direntry.ImageOffset = sizeof(ico_header) + sizeof(icondirentry); + ico_data.append(reinterpret_cast(&direntry), sizeof(direntry)); + + return true; + } + } + + return false; +} + +//Looks up icon group by icon id and returns full icon headers if found +const std::string resource_cursor_icon_reader::lookup_icon_group_data_by_icon(uint32_t icon_id, uint32_t language) const +{ + std::string icon_header_data; + + { + //List all ID-resources + pe_resource_viewer::resource_id_list ids(res_.list_resource_ids(pe_resource_viewer::resource_icon_group)); + + for(pe_resource_viewer::resource_id_list::const_iterator it = ids.begin(); it != ids.end(); ++it) + { + pe_resource_viewer::resource_language_list group_languages(res_.list_resource_languages(pe_resource_viewer::resource_icon_group, *it)); + if(std::find(group_languages.begin(), group_languages.end(), language) != group_languages.end() + && check_icon_presence(res_.get_resource_data_by_id(language, pe_resource_viewer::resource_icon_group, *it).get_data(), icon_id, icon_header_data)) + return icon_header_data; + } + } + + { + //List all named resources + pe_resource_viewer::resource_name_list names(res_.list_resource_names(pe_resource_viewer::resource_icon_group)); + for(pe_resource_viewer::resource_name_list::const_iterator it = names.begin(); it != names.end(); ++it) + { + pe_resource_viewer::resource_language_list group_languages(res_.list_resource_languages(pe_resource_viewer::resource_icon_group, *it)); + if(std::find(group_languages.begin(), group_languages.end(), language) != group_languages.end() + && check_icon_presence(res_.get_resource_data_by_name(language, pe_resource_viewer::resource_icon_group, *it).get_data(), icon_id, icon_header_data)) + return icon_header_data; + } + } + + throw pe_exception("No icon group find for requested icon", pe_exception::no_icon_group_found); +} + +//Returns single cursor data by ID and language (minimum checks of format correctness) +const std::string resource_cursor_icon_reader::get_single_cursor_by_id_lang(uint32_t language, uint32_t id) const +{ + std::string raw_cursor_data(res_.get_resource_data_by_id(language, pe_resource_viewer::resource_cursor, id).get_data()); + //Get cursor headers + std::string cursor_data(lookup_cursor_group_data_by_cursor(id, language, raw_cursor_data)); + //Append cursor data + cursor_data.append(raw_cursor_data.substr(sizeof(uint16_t) * 2 /* hotspot position */)); + return cursor_data; +} + +//Returns single cursor data by ID and index in language directory (instead of language) (minimum checks of format correctness) +const std::string resource_cursor_icon_reader::get_single_cursor_by_id(uint32_t id, uint32_t index) const +{ + pe_resource_viewer::resource_language_list languages(res_.list_resource_languages(pe_resource_viewer::resource_cursor, id)); + if(languages.size() <= index) + throw pe_exception("Resource data entry not found", pe_exception::resource_data_entry_not_found); + + std::string raw_cursor_data(res_.get_resource_data_by_id(pe_resource_viewer::resource_cursor, id, index).get_data()); + //Get cursor headers + std::string cursor_data(lookup_cursor_group_data_by_cursor(id, languages.at(index), raw_cursor_data)); + //Append cursor data + cursor_data.append(raw_cursor_data.substr(sizeof(uint16_t) * 2 /* hotspot position */)); + return cursor_data; +} + +//Helper function of creating cursor headers +//Returns cursor count +uint16_t resource_cursor_icon_reader::format_cursor_headers(std::string& cur_data, const std::string& resource_data, uint32_t language, uint32_t index) const +{ + //Check resource data length + if(resource_data.length() < sizeof(cursor_header)) + throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor); + + const cursor_header* info = reinterpret_cast(resource_data.data()); + + //Check resource data length + if(resource_data.length() < sizeof(cursor_header) + sizeof(cursor_group) * info->Count) + throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor); + + //Reserve needed space to speed up a little + cur_data.reserve(sizeof(cursor_header) + info->Count * sizeof(cursordirentry)); + //Add cursor header + cur_data.append(reinterpret_cast(info), sizeof(cursor_header)); + + //Iterate over all cursors listed in cursor group + uint32_t offset = sizeof(cursor_header) + sizeof(cursordirentry) * info->Count; + for(uint16_t i = 0; i != info->Count; ++i) + { + const cursor_group* group = reinterpret_cast(resource_data.data() + sizeof(cursor_header) + i * sizeof(cursor_group)); + + //Fill cursor info + cursordirentry direntry; + direntry.ColorCount = 0; //OK + direntry.Width = static_cast(group->Width); + direntry.Height = static_cast(group->Height) / 2; + direntry.Reserved = 0; + + //Now read hotspot data from cursor data directory + const std::string cursor = index == 0xFFFFFFFF + ? res_.get_resource_data_by_id(language, pe_resource_viewer::resource_cursor, group->Number).get_data() + : res_.get_resource_data_by_id(pe_resource_viewer::resource_cursor, group->Number, index).get_data(); + if(cursor.length() < 2 * sizeof(uint16_t)) + throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor); + + //Here it is - two words in the very beginning of cursor data + direntry.HotspotX = *reinterpret_cast(cursor.data()); + direntry.HotspotY = *reinterpret_cast(cursor.data() + sizeof(uint16_t)); + + //Fill the rest data + direntry.SizeInBytes = group->SizeInBytes - 2 * sizeof(uint16_t); + direntry.ImageOffset = offset; + + //Add cursor header + cur_data.append(reinterpret_cast(&direntry), sizeof(cursordirentry)); + + offset += direntry.SizeInBytes; + } + + //Return cursor count + return info->Count; +} + +//Returns cursor data by name and language (minimum checks of format correctness) +const std::string resource_cursor_icon_reader::get_cursor_by_name(uint32_t language, const std::wstring& name) const +{ + std::string ret; + + //Get resource by name and language + const std::string resource_data = res_.get_resource_data_by_name(language, pe_resource_viewer::resource_cursor_group, name).get_data(); + + //Create cursor headers + uint16_t cursor_count = format_cursor_headers(ret, resource_data, language); + + //Add cursor data + for(uint16_t i = 0; i != cursor_count; ++i) + { + const cursor_group* group = reinterpret_cast(resource_data.data() + sizeof(cursor_header) + i * sizeof(cursor_group)); + ret += res_.get_resource_data_by_id(language, pe_resource_viewer::resource_cursor, group->Number).get_data().substr(2 * sizeof(uint16_t)); + } + + return ret; +} + +//Returns cursor data by name and index in language directory (instead of language) (minimum checks of format correctness) +const std::string resource_cursor_icon_reader::get_cursor_by_name(const std::wstring& name, uint32_t index) const +{ + std::string ret; + + //Get resource by name and index + const std::string resource_data = res_.get_resource_data_by_name(pe_resource_viewer::resource_cursor_group, name, index).get_data(); + + //Create cursor headers + uint16_t cursor_count = format_cursor_headers(ret, resource_data, 0, index); + + //Add cursor data + for(uint16_t i = 0; i != cursor_count; ++i) + { + const cursor_group* group = reinterpret_cast(resource_data.data() + sizeof(cursor_header) + i * sizeof(cursor_group)); + ret += res_.get_resource_data_by_id(pe_resource_viewer::resource_cursor, group->Number, index).get_data().substr(2 * sizeof(uint16_t)); + } + + return ret; +} + +//Returns cursor data by ID and language (minimum checks of format correctness) +const std::string resource_cursor_icon_reader::get_cursor_by_id_lang(uint32_t language, uint32_t id) const +{ + std::string ret; + + //Get resource by ID and language + const std::string resource_data = res_.get_resource_data_by_id(language, pe_resource_viewer::resource_cursor_group, id).get_data(); + + //Create cursor headers + uint16_t cursor_count = format_cursor_headers(ret, resource_data, language); + + //Add cursor data + for(uint16_t i = 0; i != cursor_count; ++i) + { + const cursor_group* group = reinterpret_cast(resource_data.data() + sizeof(cursor_header) + i * sizeof(cursor_group)); + ret += res_.get_resource_data_by_id(language, pe_resource_viewer::resource_cursor, group->Number).get_data().substr(2 * sizeof(uint16_t)); + } + + return ret; +} + +//Returns cursor data by ID and index in language directory (instead of language) (minimum checks of format correctness) +const std::string resource_cursor_icon_reader::get_cursor_by_id(uint32_t id, uint32_t index) const +{ + std::string ret; + + //Get resource by ID and index + const std::string resource_data = res_.get_resource_data_by_id(pe_resource_viewer::resource_cursor_group, id, index).get_data(); + + //Create cursor headers + uint16_t cursor_count = format_cursor_headers(ret, resource_data, 0, index); + + //Add cursor data + for(uint16_t i = 0; i != cursor_count; ++i) + { + const cursor_group* group = reinterpret_cast(resource_data.data() + sizeof(cursor_header) + i * sizeof(cursor_group)); + ret += res_.get_resource_data_by_id(pe_resource_viewer::resource_cursor, group->Number, index).get_data().substr(2 * sizeof(uint16_t)); + } + + return ret; +} + +//Checks for cursor presence inside cursor group, fills cursor headers if found +bool resource_cursor_icon_reader::check_cursor_presence(const std::string& cursor_group_resource_data, uint32_t cursor_id, std::string& cur_header_data, const std::string& raw_cursor_data) +{ + //Check resource data length + if(cursor_group_resource_data.length() < sizeof(cursor_header)) + throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor); + + const cursor_header* info = reinterpret_cast(cursor_group_resource_data.data()); + + //Check resource data length + if(cursor_group_resource_data.length() < sizeof(cursor_header) + sizeof(cursor_group)) + throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor); + + //Iterate over all cursors listed in cursor group + for(uint16_t i = 0; i != info->Count; ++i) + { + const cursor_group* group = reinterpret_cast(cursor_group_resource_data.data() + sizeof(cursor_header) + i * sizeof(cursor_group)); + + if(group->Number == cursor_id) + { + //Reserve needed space to speed up a little + cur_header_data.reserve(sizeof(cursor_header) + sizeof(cursordirentry)); + //Write single-cursor cursor header + cursor_header new_header = *info; + new_header.Count = 1; + cur_header_data.append(reinterpret_cast(&new_header), sizeof(cursor_header)); + + //Fill cursor info + cursordirentry direntry; + direntry.ColorCount = 0; //OK + direntry.Width = static_cast(group->Width); + direntry.Height = static_cast(group->Height) / 2; + direntry.Reserved = 0; + + if(raw_cursor_data.length() < 2 * sizeof(uint16_t)) + throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor); + + //Here it is - two words in the very beginning of cursor data + direntry.HotspotX = *reinterpret_cast(raw_cursor_data.data()); + direntry.HotspotY = *reinterpret_cast(raw_cursor_data.data() + sizeof(uint16_t)); + + //Fill the rest data + direntry.SizeInBytes = group->SizeInBytes - 2 * sizeof(uint16_t); + direntry.ImageOffset = sizeof(cursor_header) + sizeof(cursordirentry); + + //Add cursor header + cur_header_data.append(reinterpret_cast(&direntry), sizeof(cursordirentry)); + + return true; + } + } + + return false; +} + +//Looks up cursor group by cursor id and returns full cursor headers if found +const std::string resource_cursor_icon_reader::lookup_cursor_group_data_by_cursor(uint32_t cursor_id, uint32_t language, const std::string& raw_cursor_data) const +{ + std::string cursor_header_data; + + { + //List all ID-resources + pe_resource_viewer::resource_id_list ids(res_.list_resource_ids(pe_resource_viewer::resource_cursor_group)); + + for(pe_resource_viewer::resource_id_list::const_iterator it = ids.begin(); it != ids.end(); ++it) + { + pe_resource_viewer::resource_language_list group_languages(res_.list_resource_languages(pe_resource_viewer::resource_cursor_group, *it)); + if(std::find(group_languages.begin(), group_languages.end(), language) != group_languages.end() + && check_cursor_presence(res_.get_resource_data_by_id(language, pe_resource_viewer::resource_cursor_group, *it).get_data(), cursor_id, cursor_header_data, raw_cursor_data)) + return cursor_header_data; + } + } + + { + //List all named resources + pe_resource_viewer::resource_name_list names(res_.list_resource_names(pe_resource_viewer::resource_cursor_group)); + for(pe_resource_viewer::resource_name_list::const_iterator it = names.begin(); it != names.end(); ++it) + { + pe_resource_viewer::resource_language_list group_languages(res_.list_resource_languages(pe_resource_viewer::resource_cursor_group, *it)); + if(std::find(group_languages.begin(), group_languages.end(), language) != group_languages.end() + && check_cursor_presence(res_.get_resource_data_by_name(language, pe_resource_viewer::resource_cursor_group, *it).get_data(), cursor_id, cursor_header_data, raw_cursor_data)) + return cursor_header_data; + } + } + + throw pe_exception("No cursor group find for requested icon", pe_exception::no_cursor_group_found); +} +} diff --git a/drivers/pe_bliss/resource_cursor_icon_reader.h b/drivers/pe_bliss/resource_cursor_icon_reader.h new file mode 100644 index 0000000000..25a59baa27 --- /dev/null +++ b/drivers/pe_bliss/resource_cursor_icon_reader.h @@ -0,0 +1,63 @@ +#pragma once +#include +#include "stdint_defs.h" + +namespace pe_bliss +{ +class pe_resource_viewer; + +class resource_cursor_icon_reader +{ +public: + resource_cursor_icon_reader(const pe_resource_viewer& res); + + //Returns single icon data by ID and language (minimum checks of format correctness) + const std::string get_single_icon_by_id_lang(uint32_t language, uint32_t id) const; + //Returns single icon data by ID and index in language directory (instead of language) (minimum checks of format correctness) + const std::string get_single_icon_by_id(uint32_t id, uint32_t index = 0) const; + + //Returns icon data of group of icons by name and language (minimum checks of format correctness) + const std::string get_icon_by_name(uint32_t language, const std::wstring& icon_group_name) const; + //Returns icon data of group of icons by name and index in language directory (instead of language) (minimum checks of format correctness) + const std::string get_icon_by_name(const std::wstring& icon_group_name, uint32_t index = 0) const; + //Returns icon data of group of icons by ID and language (minimum checks of format correctness) + const std::string get_icon_by_id_lang(uint32_t language, uint32_t icon_group_id) const; + //Returns icon data of group of icons by ID and index in language directory (instead of language) (minimum checks of format correctness) + const std::string get_icon_by_id(uint32_t icon_group_id, uint32_t index = 0) const; + + //Returns single cursor data by ID and language (minimum checks of format correctness) + const std::string get_single_cursor_by_id_lang(uint32_t language, uint32_t id) const; + //Returns single cursor data by ID and index in language directory (instead of language) (minimum checks of format correctness) + const std::string get_single_cursor_by_id(uint32_t id, uint32_t index = 0) const; + + //Returns cursor data by name and language (minimum checks of format correctness) + const std::string get_cursor_by_name(uint32_t language, const std::wstring& cursor_group_name) const; + //Returns cursor data by name and index in language directory (instead of language) (minimum checks of format correctness) + const std::string get_cursor_by_name(const std::wstring& cursor_group_name, uint32_t index = 0) const; + //Returns cursor data by ID and language (minimum checks of format correctness) + const std::string get_cursor_by_id_lang(uint32_t language, uint32_t cursor_group_id) const; + //Returns cursor data by ID and index in language directory (instead of language) (minimum checks of format correctness) + const std::string get_cursor_by_id(uint32_t cursor_group_id, uint32_t index = 0) const; + +private: + const pe_resource_viewer& res_; + + //Helper function of creating icon headers from ICON_GROUP resource data + //Returns icon count + static uint16_t format_icon_headers(std::string& ico_data, const std::string& resource_data); + + //Helper function of creating cursor headers from CURSOR_GROUP resource data + //Returns cursor count + uint16_t format_cursor_headers(std::string& cur_data, const std::string& resource_data, uint32_t language, uint32_t index = 0xFFFFFFFF) const; + + //Looks up icon group by icon id and returns full icon headers if found + const std::string lookup_icon_group_data_by_icon(uint32_t icon_id, uint32_t language) const; + //Checks for icon presence inside icon group, fills icon headers if found + static bool check_icon_presence(const std::string& icon_group_resource_data, uint32_t icon_id, std::string& ico_data); + + //Looks up cursor group by cursor id and returns full cursor headers if found + const std::string lookup_cursor_group_data_by_cursor(uint32_t cursor_id, uint32_t language, const std::string& raw_cursor_data) const; + //Checks for cursor presence inside cursor group, fills cursor headers if found + static bool check_cursor_presence(const std::string& icon_group_resource_data, uint32_t cursor_id, std::string& cur_header_data, const std::string& raw_cursor_data); +}; +} diff --git a/drivers/pe_bliss/resource_cursor_icon_writer.cpp b/drivers/pe_bliss/resource_cursor_icon_writer.cpp new file mode 100644 index 0000000000..ce52c6cbdf --- /dev/null +++ b/drivers/pe_bliss/resource_cursor_icon_writer.cpp @@ -0,0 +1,426 @@ +#include +#include +#include "resource_cursor_icon_writer.h" + +namespace pe_bliss +{ +using namespace pe_win; + +resource_cursor_icon_writer::resource_cursor_icon_writer(pe_resource_manager& res) + :res_(res) +{} + +//Add icon helper +void resource_cursor_icon_writer::add_icon(const std::string& icon_file, const resource_data_info* group_icon_info /* or zero */, resource_directory_entry& new_icon_group_entry, const resource_directory::entry_finder& finder, uint32_t language, icon_place_mode mode, uint32_t codepage, uint32_t timestamp) +{ + //Check icon for correctness + if(icon_file.length() < sizeof(ico_header)) + throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon); + + const ico_header* icon_header = reinterpret_cast(&icon_file[0]); + + unsigned long size_of_headers = sizeof(ico_header) + icon_header->Count * sizeof(icondirentry); + if(icon_file.length() < size_of_headers || icon_header->Count == 0) + throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon); + + //Enumerate all icons in file + for(uint16_t i = 0; i != icon_header->Count; ++i) + { + //Check icon entries + const icondirentry* icon_entry = reinterpret_cast(&icon_file[sizeof(ico_header) + i * sizeof(icondirentry)]); + if(icon_entry->SizeInBytes == 0 + || icon_entry->ImageOffset < size_of_headers + || !pe_utils::is_sum_safe(icon_entry->ImageOffset, icon_entry->SizeInBytes) + || icon_entry->ImageOffset + icon_entry->SizeInBytes > icon_file.length()) + throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon); + } + + std::string icon_group_data; + ico_header* info = 0; + + if(group_icon_info) + { + //If icon group already exists + { + icon_group_data = group_icon_info->get_data(); + codepage = group_icon_info->get_codepage(); //Don't change codepage of icon group entry + } + + //Check resource data size + if(icon_group_data.length() < sizeof(ico_header)) + throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon); + + //Get icon header + info = reinterpret_cast(&icon_group_data[0]); + + //Check resource data size + if(icon_group_data.length() < sizeof(ico_header) + info->Count * sizeof(icon_group)) + throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon); + + icon_group_data.resize(sizeof(ico_header) + (info->Count + icon_header->Count) * sizeof(icon_group)); + info = reinterpret_cast(&icon_group_data[0]); //In case if memory was reallocated + } + else //Entry not found - icon group doesn't exist + { + icon_group_data.resize(sizeof(ico_header) + icon_header->Count * sizeof(icon_group)); + memcpy(&icon_group_data[0], icon_header, sizeof(ico_header)); + } + + //Search for available icon IDs + std::vector icon_id_list(get_icon_or_cursor_free_id_list(pe_resource_viewer::resource_icon, mode, icon_header->Count)); + + //Enumerate all icons in file + for(uint16_t i = 0; i != icon_header->Count; ++i) + { + const icondirentry* icon_entry = reinterpret_cast(&icon_file[sizeof(ico_header) + i * sizeof(icondirentry)]); + icon_group group = {0}; + + //Fill icon resource header + group.BitCount = icon_entry->BitCount; + group.ColorCount = icon_entry->ColorCount; + group.Height = icon_entry->Height; + group.Planes = icon_entry->Planes; + group.Reserved = icon_entry->Reserved; + group.SizeInBytes = icon_entry->SizeInBytes; + group.Width = icon_entry->Width; + group.Number = icon_id_list.at(i); + + memcpy(&icon_group_data[sizeof(ico_header) + ((info ? info->Count : 0) + i) * sizeof(icon_group)], &group, sizeof(group)); + + //Add icon to resources + resource_directory_entry new_entry; + new_entry.set_id(group.Number); + res_.add_resource(icon_file.substr(icon_entry->ImageOffset, icon_entry->SizeInBytes), pe_resource_viewer::resource_icon, new_entry, resource_directory::entry_finder(group.Number), language, codepage, timestamp); + } + + if(info) + info->Count += icon_header->Count; //Increase icon count, if we're adding icon to existing group + + { + //Add or replace icon group data entry + res_.add_resource(icon_group_data, pe_resource_viewer::resource_icon_group, new_icon_group_entry, finder, language, codepage, timestamp); + } +} + +//Returns free icon or cursor ID list depending on icon_place_mode +const std::vector resource_cursor_icon_writer::get_icon_or_cursor_free_id_list(pe_resource_viewer::resource_type type, icon_place_mode mode, uint32_t count) +{ + //Search for available icon/cursor IDs + std::vector icon_cursor_id_list; + + try + { + //If any icon exists + //List icon IDs + std::vector id_list(res_.list_resource_ids(type)); + std::sort(id_list.begin(), id_list.end()); + + //If we are placing icon on free spaces + //I.e., icon IDs 1, 3, 4, 7, 8 already exist + //We'll place five icons on IDs 2, 5, 6, 9, 10 + if(mode != icon_place_after_max_icon_id) + { + if(!id_list.empty()) + { + //Determine and list free icon IDs + for(std::vector::const_iterator it = id_list.begin(); it != id_list.end(); ++it) + { + if(it == id_list.begin()) + { + if(*it > 1) + { + for(uint16_t i = 1; i != *it; ++i) + { + icon_cursor_id_list.push_back(i); + if(icon_cursor_id_list.size() == count) + break; + } + } + } + else if(*(it - 1) - *it > 1) + { + for(uint16_t i = static_cast(*(it - 1) + 1); i != static_cast(*it); ++i) + { + icon_cursor_id_list.push_back(i); + if(icon_cursor_id_list.size() == count) + break; + } + } + + if(icon_cursor_id_list.size() == count) + break; + } + } + } + + uint32_t max_id = id_list.empty() ? 0 : *std::max_element(id_list.begin(), id_list.end()); + for(uint32_t i = static_cast(icon_cursor_id_list.size()); i != count; ++i) + icon_cursor_id_list.push_back(static_cast(++max_id)); + } + catch(const pe_exception&) //Entry not found + { + for(uint16_t i = 1; i != count + 1; ++i) + icon_cursor_id_list.push_back(i); + } + + return icon_cursor_id_list; +} + +//Add cursor helper +void resource_cursor_icon_writer::add_cursor(const std::string& cursor_file, const resource_data_info* group_cursor_info /* or zero */, resource_directory_entry& new_cursor_group_entry, const resource_directory::entry_finder& finder, uint32_t language, icon_place_mode mode, uint32_t codepage, uint32_t timestamp) +{ + //Check cursor for correctness + if(cursor_file.length() < sizeof(cursor_header)) + throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor); + + const cursor_header* cur_header = reinterpret_cast(&cursor_file[0]); + + unsigned long size_of_headers = sizeof(cursor_header) + cur_header->Count * sizeof(cursordirentry); + if(cursor_file.length() < size_of_headers || cur_header->Count == 0) + throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor); + + //Enumerate all cursors in file + for(uint16_t i = 0; i != cur_header->Count; ++i) + { + //Check cursor entries + const cursordirentry* cursor_entry = reinterpret_cast(&cursor_file[sizeof(cursor_header) + i * sizeof(cursordirentry)]); + if(cursor_entry->SizeInBytes == 0 + || cursor_entry->ImageOffset < size_of_headers + || !pe_utils::is_sum_safe(cursor_entry->ImageOffset, cursor_entry->SizeInBytes) + || cursor_entry->ImageOffset + cursor_entry->SizeInBytes > cursor_file.length()) + throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor); + } + + std::string cursor_group_data; + cursor_header* info = 0; + + if(group_cursor_info) + { + //If cursor group already exists + { + cursor_group_data = group_cursor_info->get_data(); + codepage = group_cursor_info->get_codepage(); //Don't change codepage of cursor group entry + } + + //Check resource data size + if(cursor_group_data.length() < sizeof(cursor_header)) + throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor); + + //Get cursor header + info = reinterpret_cast(&cursor_group_data[0]); + + //Check resource data size + if(cursor_group_data.length() < sizeof(cursor_header) + info->Count * sizeof(cursor_group)) + throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor); + + cursor_group_data.resize(sizeof(cursor_header) + (info->Count + cur_header->Count) * sizeof(cursor_group)); + info = reinterpret_cast(&cursor_group_data[0]); //In case if memory was reallocated + } + else //Entry not found - cursor group doesn't exist + { + cursor_group_data.resize(sizeof(cursor_header) + cur_header->Count * sizeof(cursor_group)); + memcpy(&cursor_group_data[0], cur_header, sizeof(cursor_header)); + } + + //Search for available cursor IDs + std::vector cursor_id_list(get_icon_or_cursor_free_id_list(pe_resource_viewer::resource_cursor, mode, cur_header->Count)); + + //Enumerate all cursors in file + for(uint16_t i = 0; i != cur_header->Count; ++i) + { + const cursordirentry* cursor_entry = reinterpret_cast(&cursor_file[sizeof(cursor_header) + i * sizeof(cursordirentry)]); + cursor_group group = {0}; + + //Fill cursor resource header + group.Height = cursor_entry->Height * 2; + group.SizeInBytes = cursor_entry->SizeInBytes + 2 * sizeof(uint16_t) /* hotspot coordinates */; + group.Width = cursor_entry->Width; + group.Number = cursor_id_list.at(i); + + memcpy(&cursor_group_data[sizeof(cursor_header) + ((info ? info->Count : 0) + i) * sizeof(cursor_group)], &group, sizeof(group)); + + //Add cursor to resources + resource_directory_entry new_entry; + new_entry.set_id(group.Number); + + //Fill resource data (two WORDs for hotspot of cursor, and cursor bitmap data) + std::string cur_data; + cur_data.resize(sizeof(uint16_t) * 2); + memcpy(&cur_data[0], &cursor_entry->HotspotX, sizeof(uint16_t)); + memcpy(&cur_data[sizeof(uint16_t)], &cursor_entry->HotspotY, sizeof(uint16_t)); + cur_data.append(cursor_file.substr(cursor_entry->ImageOffset, cursor_entry->SizeInBytes)); + + res_.add_resource(cur_data, pe_resource_viewer::resource_cursor, new_entry, resource_directory::entry_finder(group.Number), language, codepage, timestamp); + } + + if(info) + info->Count += cur_header->Count; //Increase cursor count, if we're adding cursor to existing group + + { + //Add or replace cursor group data entry + res_.add_resource(cursor_group_data, pe_resource_viewer::resource_cursor_group, new_cursor_group_entry, finder, language, codepage, timestamp); + } +} + +//Adds icon(s) from icon file data +//timestamp will be used for directories that will be added +//If icon group with name "icon_group_name" or ID "icon_group_id" already exists, it will be appended with new icon(s) +//(Codepage of icon group and icons will not be changed in this case) +//icon_place_mode determines, how new icon(s) will be placed +void resource_cursor_icon_writer::add_icon(const std::string& icon_file, const std::wstring& icon_group_name, uint32_t language, icon_place_mode mode, uint32_t codepage, uint32_t timestamp) +{ + resource_directory_entry new_icon_group_entry; + new_icon_group_entry.set_name(icon_group_name); + std::auto_ptr data_info; + + try + { + data_info.reset(new resource_data_info(res_.get_resource_data_by_name(language, pe_resource_viewer::resource_icon_group, icon_group_name))); + } + catch(const pe_exception&) //Entry not found + { + } + + add_icon(icon_file, data_info.get(), new_icon_group_entry, resource_directory::entry_finder(icon_group_name), language, mode, codepage, timestamp); +} + +void resource_cursor_icon_writer::add_icon(const std::string& icon_file, uint32_t icon_group_id, uint32_t language, icon_place_mode mode, uint32_t codepage, uint32_t timestamp) +{ + resource_directory_entry new_icon_group_entry; + new_icon_group_entry.set_id(icon_group_id); + std::auto_ptr data_info; + + try + { + data_info.reset(new resource_data_info(res_.get_resource_data_by_id(language, pe_resource_viewer::resource_icon_group, icon_group_id))); + } + catch(const pe_exception&) //Entry not found + { + } + + add_icon(icon_file, data_info.get(), new_icon_group_entry, resource_directory::entry_finder(icon_group_id), language, mode, codepage, timestamp); +} + +//Adds cursor(s) from cursor file data +//timestamp will be used for directories that will be added +//If cursor group with name "cursor_group_name" or ID "cursor_group_id" already exists, it will be appended with new cursor(s) +//(Codepage of cursor group and cursors will not be changed in this case) +//icon_place_mode determines, how new cursor(s) will be placed +void resource_cursor_icon_writer::add_cursor(const std::string& cursor_file, const std::wstring& cursor_group_name, uint32_t language, icon_place_mode mode, uint32_t codepage, uint32_t timestamp) +{ + resource_directory_entry new_cursor_group_entry; + new_cursor_group_entry.set_name(cursor_group_name); + std::auto_ptr data_info; + + try + { + data_info.reset(new resource_data_info(res_.get_resource_data_by_name(language, pe_resource_viewer::resource_cursor_group, cursor_group_name))); + } + catch(const pe_exception&) //Entry not found + { + } + + add_cursor(cursor_file, data_info.get(), new_cursor_group_entry, resource_directory::entry_finder(cursor_group_name), language, mode, codepage, timestamp); +} + +void resource_cursor_icon_writer::add_cursor(const std::string& cursor_file, uint32_t cursor_group_id, uint32_t language, icon_place_mode mode, uint32_t codepage, uint32_t timestamp) +{ + resource_directory_entry new_cursor_group_entry; + new_cursor_group_entry.set_id(cursor_group_id); + std::auto_ptr data_info; + + try + { + data_info.reset(new resource_data_info(res_.get_resource_data_by_id(language, pe_resource_viewer::resource_cursor_group, cursor_group_id))); + } + catch(const pe_exception&) //Entry not found + { + } + + add_cursor(cursor_file, data_info.get(), new_cursor_group_entry, resource_directory::entry_finder(cursor_group_id), language, mode, codepage, timestamp); +} + +//Remove icon group helper +void resource_cursor_icon_writer::remove_icons_from_icon_group(const std::string& icon_group_data, uint32_t language) +{ + //Check resource data size + if(icon_group_data.length() < sizeof(ico_header)) + throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon); + + //Get icon header + const ico_header* info = reinterpret_cast(icon_group_data.data()); + + uint16_t icon_count = info->Count; + + //Check resource data size + if(icon_group_data.length() < sizeof(ico_header) + icon_count * sizeof(icon_group)) + throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon); + + //Remove icon data + for(uint16_t i = 0; i != icon_count; ++i) + { + const icon_group* group = reinterpret_cast(icon_group_data.data() + sizeof(ico_header) + i * sizeof(icon_group)); + res_.remove_resource(pe_resource_viewer::resource_icon, group->Number, language); + } +} + +//Remove cursor group helper +void resource_cursor_icon_writer::remove_cursors_from_cursor_group(const std::string& cursor_group_data, uint32_t language) +{ + //Check resource data size + if(cursor_group_data.length() < sizeof(cursor_header)) + throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor); + + //Get icon header + const cursor_header* info = reinterpret_cast(cursor_group_data.data()); + + uint16_t cursor_count = info->Count; + + //Check resource data size + if(cursor_group_data.length() < sizeof(cursor_header) + cursor_count * sizeof(cursor_group)) + throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor); + + //Remove icon data + for(uint16_t i = 0; i != cursor_count; ++i) + { + const icon_group* group = reinterpret_cast(cursor_group_data.data() + sizeof(cursor_header) + i * sizeof(cursor_group)); + res_.remove_resource(pe_resource_viewer::resource_cursor, group->Number, language); + } +} + +//Removes cursor group and all its cursors by name/ID and language +bool resource_cursor_icon_writer::remove_cursor_group(const std::wstring& cursor_group_name, uint32_t language) +{ + //Get resource by name and language + const std::string data = res_.get_resource_data_by_name(language, pe_resource_viewer::resource_cursor_group, cursor_group_name).get_data(); + remove_cursors_from_cursor_group(data, language); + return res_.remove_resource(pe_resource_viewer::resource_cursor_group, cursor_group_name, language); +} + +//Removes cursor group and all its cursors by name/ID and language +bool resource_cursor_icon_writer::remove_cursor_group(uint32_t cursor_group_id, uint32_t language) +{ + //Get resource by name and language + const std::string data = res_.get_resource_data_by_id(language, pe_resource_viewer::resource_cursor_group, cursor_group_id).get_data(); + remove_cursors_from_cursor_group(data, language); + return res_.remove_resource(pe_resource_viewer::resource_cursor_group, cursor_group_id, language); +} + +//Removes icon group and all its icons by name/ID and language +bool resource_cursor_icon_writer::remove_icon_group(const std::wstring& icon_group_name, uint32_t language) +{ + //Get resource by name and language + const std::string data = res_.get_resource_data_by_name(language, pe_resource_viewer::resource_icon_group, icon_group_name).get_data(); + remove_icons_from_icon_group(data, language); + return res_.remove_resource(pe_resource_viewer::resource_icon_group, icon_group_name, language); +} + +//Removes icon group and all its icons by name/ID and language +bool resource_cursor_icon_writer::remove_icon_group(uint32_t icon_group_id, uint32_t language) +{ + //Get resource by name and language + const std::string data = res_.get_resource_data_by_id(language, pe_resource_viewer::resource_icon_group, icon_group_id).get_data(); + remove_icons_from_icon_group(data, language); + return res_.remove_resource(pe_resource_viewer::resource_icon_group, icon_group_id, language); +} +} diff --git a/drivers/pe_bliss/resource_cursor_icon_writer.h b/drivers/pe_bliss/resource_cursor_icon_writer.h new file mode 100644 index 0000000000..2503dd7d0e --- /dev/null +++ b/drivers/pe_bliss/resource_cursor_icon_writer.h @@ -0,0 +1,73 @@ +#pragma once +#include +#include +#include "stdint_defs.h" +#include "pe_resource_manager.h" + +namespace pe_bliss +{ +class pe_resource_manager; + +class resource_cursor_icon_writer +{ +public: + //Determines, how new icon(s) or cursor(s) will be placed + enum icon_place_mode + { + icon_place_after_max_icon_id, //Icon(s) will be placed after all existing + icon_place_free_ids //New icon(s) will take all free IDs between existing icons + }; + +public: + resource_cursor_icon_writer(pe_resource_manager& res); + + //Removes icon group and all its icons by name/ID and language + bool remove_icon_group(const std::wstring& icon_group_name, uint32_t language); + bool remove_icon_group(uint32_t icon_group_id, uint32_t language); + + //Adds icon(s) from icon file data + //timestamp will be used for directories that will be added + //If icon group with name "icon_group_name" or ID "icon_group_id" already exists, it will be appended with new icon(s) + //(Codepage of icon group and icons will not be changed in this case) + //icon_place_mode determines, how new icon(s) will be placed + void add_icon(const std::string& icon_file, + const std::wstring& icon_group_name, + uint32_t language, icon_place_mode mode = icon_place_after_max_icon_id, + uint32_t codepage = 0, uint32_t timestamp = 0); + + void add_icon(const std::string& icon_file, + uint32_t icon_group_id, + uint32_t language, icon_place_mode mode = icon_place_after_max_icon_id, + uint32_t codepage = 0, uint32_t timestamp = 0); + + //Removes cursor group and all its cursors by name/ID and language + bool remove_cursor_group(const std::wstring& cursor_group_name, uint32_t language); + bool remove_cursor_group(uint32_t cursor_group_id, uint32_t language); + + //Adds cursor(s) from cursor file data + //timestamp will be used for directories that will be added + //If cursor group with name "cursor_group_name" or ID "cursor_group_id" already exists, it will be appended with new cursor(s) + //(Codepage of cursor group and cursors will not be changed in this case) + //icon_place_mode determines, how new cursor(s) will be placed + void add_cursor(const std::string& cursor_file, const std::wstring& cursor_group_name, uint32_t language, icon_place_mode mode = icon_place_after_max_icon_id, uint32_t codepage = 0, uint32_t timestamp = 0); + void add_cursor(const std::string& cursor_file, uint32_t cursor_group_id, uint32_t language, icon_place_mode mode = icon_place_after_max_icon_id, uint32_t codepage = 0, uint32_t timestamp = 0); + +private: + pe_resource_manager& res_; + + //Add icon helper + void add_icon(const std::string& icon_file, const resource_data_info* group_icon_info /* or zero */, resource_directory_entry& new_icon_group_entry, const resource_directory::entry_finder& finder, uint32_t language, icon_place_mode mode, uint32_t codepage, uint32_t timestamp); + + //Remove icon group helper + void remove_icons_from_icon_group(const std::string& icon_group_data, uint32_t language); + + //Add cursor helper + void add_cursor(const std::string& cursor_file, const resource_data_info* group_cursor_info /* or zero */, resource_directory_entry& new_cursor_group_entry, const resource_directory::entry_finder& finder, uint32_t language, icon_place_mode mode, uint32_t codepage, uint32_t timestamp); + + //Remove cursor group helper + void remove_cursors_from_cursor_group(const std::string& cursor_group_data, uint32_t language); + + //Returns free icon or cursor ID list depending on icon_place_mode + const std::vector get_icon_or_cursor_free_id_list(pe_resource_manager::resource_type type, icon_place_mode mode, uint32_t count); +}; +} diff --git a/drivers/pe_bliss/resource_data_info.cpp b/drivers/pe_bliss/resource_data_info.cpp new file mode 100644 index 0000000000..bc7b3abd7d --- /dev/null +++ b/drivers/pe_bliss/resource_data_info.cpp @@ -0,0 +1,27 @@ +#include "resource_data_info.h" +#include "pe_resource_viewer.h" + +namespace pe_bliss +{ +//Default constructor +resource_data_info::resource_data_info(const std::string& data, uint32_t codepage) + :data_(data), codepage_(codepage) +{} + +//Constructor from data +resource_data_info::resource_data_info(const resource_data_entry& data) + :data_(data.get_data()), codepage_(data.get_codepage()) +{} + +//Returns resource data +const std::string& resource_data_info::get_data() const +{ + return data_; +} + +//Returns resource codepage +uint32_t resource_data_info::get_codepage() const +{ + return codepage_; +} +} diff --git a/drivers/pe_bliss/resource_data_info.h b/drivers/pe_bliss/resource_data_info.h new file mode 100644 index 0000000000..65953e708e --- /dev/null +++ b/drivers/pe_bliss/resource_data_info.h @@ -0,0 +1,27 @@ +#pragma once +#include +#include "stdint_defs.h" + +namespace pe_bliss +{ +class resource_data_entry; + +//Class representing resource data +class resource_data_info +{ +public: + //Constructor from data + resource_data_info(const std::string& data, uint32_t codepage); + //Constructor from data + explicit resource_data_info(const resource_data_entry& data); + + //Returns resource data + const std::string& get_data() const; + //Returns resource codepage + uint32_t get_codepage() const; + +private: + std::string data_; + uint32_t codepage_; +}; +} diff --git a/drivers/pe_bliss/resource_internal.h b/drivers/pe_bliss/resource_internal.h new file mode 100644 index 0000000000..fd5ff95248 --- /dev/null +++ b/drivers/pe_bliss/resource_internal.h @@ -0,0 +1,13 @@ +#pragma once + +#define U16TEXT(t) reinterpret_cast( t ) + +#define StringFileInfo U16TEXT("S\0t\0r\0i\0n\0g\0F\0i\0l\0e\0I\0n\0f\0o\0\0") +#define SizeofStringFileInfo sizeof("S\0t\0r\0i\0n\0g\0F\0i\0l\0e\0I\0n\0f\0o\0\0") +#define VarFileInfo U16TEXT("V\0a\0r\0F\0i\0l\0e\0I\0n\0f\0o\0\0") +#define Translation U16TEXT("T\0r\0a\0n\0s\0l\0a\0t\0i\0o\0n\0\0") + +#define VarFileInfoAligned U16TEXT("V\0a\0r\0F\0i\0l\0e\0I\0n\0f\0o\0\0\0\0") +#define TranslationAligned U16TEXT("T\0r\0a\0n\0s\0l\0a\0t\0i\0o\0n\0\0\0\0") +#define SizeofVarFileInfoAligned sizeof("V\0a\0r\0F\0i\0l\0e\0I\0n\0f\0o\0\0\0\0") +#define SizeofTranslationAligned sizeof("T\0r\0a\0n\0s\0l\0a\0t\0i\0o\0n\0\0\0\0") diff --git a/drivers/pe_bliss/resource_message_list_reader.cpp b/drivers/pe_bliss/resource_message_list_reader.cpp new file mode 100644 index 0000000000..ff9a5dd861 --- /dev/null +++ b/drivers/pe_bliss/resource_message_list_reader.cpp @@ -0,0 +1,110 @@ +#include "resource_message_list_reader.h" +#include "pe_resource_viewer.h" + +namespace pe_bliss +{ +using namespace pe_win; + +resource_message_list_reader::resource_message_list_reader(const pe_resource_viewer& res) + :res_(res) +{} + +//Helper function of parsing message list table +const resource_message_list resource_message_list_reader::parse_message_list(const std::string& resource_data) +{ + resource_message_list ret; + + //Check resource data length + if(resource_data.length() < sizeof(message_resource_data)) + throw pe_exception("Incorrect resource message table", pe_exception::resource_incorrect_message_table); + + const message_resource_data* message_data = reinterpret_cast(resource_data.data()); + + //Check resource data length more carefully and some possible overflows + if(message_data->NumberOfBlocks >= pe_utils::max_dword / sizeof(message_resource_block) + || !pe_utils::is_sum_safe(message_data->NumberOfBlocks * sizeof(message_resource_block), sizeof(message_resource_data)) + || resource_data.length() < message_data->NumberOfBlocks * sizeof(message_resource_block) + sizeof(message_resource_data)) + throw pe_exception("Incorrect resource message table", pe_exception::resource_incorrect_message_table); + + //Iterate over all message resource blocks + for(unsigned long i = 0; i != message_data->NumberOfBlocks; ++i) + { + //Get block + const message_resource_block* block = + reinterpret_cast(resource_data.data() + sizeof(message_resource_data) - sizeof(message_resource_block) + sizeof(message_resource_block) * i); + + //Check resource data length and IDs + if(resource_data.length() < block->OffsetToEntries || block->LowId > block->HighId) + throw pe_exception("Incorrect resource message table", pe_exception::resource_incorrect_message_table); + + unsigned long current_pos = 0; + static const unsigned long size_of_entry_headers = 4; + //List all message resource entries in block + for(uint32_t curr_id = block->LowId; curr_id <= block->HighId; curr_id++) + { + //Check resource data length and some possible overflows + if(!pe_utils::is_sum_safe(block->OffsetToEntries, current_pos) + || !pe_utils::is_sum_safe(block->OffsetToEntries + current_pos, size_of_entry_headers) + || resource_data.length() < block->OffsetToEntries + current_pos + size_of_entry_headers) + throw pe_exception("Incorrect resource message table", pe_exception::resource_incorrect_message_table); + + //Get entry + const message_resource_entry* entry = reinterpret_cast(resource_data.data() + block->OffsetToEntries + current_pos); + + //Check resource data length and entry length and some possible overflows + if(entry->Length < size_of_entry_headers + || !pe_utils::is_sum_safe(block->OffsetToEntries + current_pos, entry->Length) + || resource_data.length() < block->OffsetToEntries + current_pos + entry->Length + || entry->Length < size_of_entry_headers) + throw pe_exception("Incorrect resource message table", pe_exception::resource_incorrect_message_table); + + if(entry->Flags & message_resource_unicode) + { + //If string is UNICODE + //Check its length + if(entry->Length % 2) + throw pe_exception("Incorrect resource message table", pe_exception::resource_incorrect_message_table); + + //Add ID and string to message table +#ifdef PE_BLISS_WINDOWS + ret.insert(std::make_pair(curr_id, message_table_item( + std::wstring(reinterpret_cast(resource_data.data() + block->OffsetToEntries + current_pos + size_of_entry_headers), + (entry->Length - size_of_entry_headers) / 2) + ))); +#else + ret.insert(std::make_pair(curr_id, message_table_item( + pe_utils::from_ucs2(u16string(reinterpret_cast(resource_data.data() + block->OffsetToEntries + current_pos + size_of_entry_headers), + (entry->Length - size_of_entry_headers) / 2)) + ))); +#endif + } + else + { + //If string is ANSI + //Add ID and string to message table + ret.insert(std::make_pair(curr_id, message_table_item( + std::string(resource_data.data() + block->OffsetToEntries + current_pos + size_of_entry_headers, + entry->Length - size_of_entry_headers) + ))); + } + + //Go to next entry + current_pos += entry->Length; + } + } + + return ret; +} + +//Returns message table data by ID and index in language directory (instead of language) +const resource_message_list resource_message_list_reader::get_message_table_by_id(uint32_t id, uint32_t index) const +{ + return parse_message_list(res_.get_resource_data_by_id(pe_resource_viewer::resource_message_table, id, index).get_data()); +} + +//Returns message table data by ID and language +const resource_message_list resource_message_list_reader::get_message_table_by_id_lang(uint32_t language, uint32_t id) const +{ + return parse_message_list(res_.get_resource_data_by_id(language, pe_resource_viewer::resource_message_table, id).get_data()); +} +} diff --git a/drivers/pe_bliss/resource_message_list_reader.h b/drivers/pe_bliss/resource_message_list_reader.h new file mode 100644 index 0000000000..aacd738cc2 --- /dev/null +++ b/drivers/pe_bliss/resource_message_list_reader.h @@ -0,0 +1,28 @@ +#pragma once +#include "message_table.h" + +namespace pe_bliss +{ +class pe_resource_viewer; + +//ID; message_table_item +typedef std::map resource_message_list; + +class resource_message_list_reader +{ +public: + resource_message_list_reader(const pe_resource_viewer& res); + + //Returns message table data by ID and language + const resource_message_list get_message_table_by_id_lang(uint32_t language, uint32_t id) const; + //Returns message table data by ID and index in language directory (instead of language) + const resource_message_list get_message_table_by_id(uint32_t id, uint32_t index = 0) const; + + //Helper function of parsing message list table + //resource_data - raw message table resource data + static const resource_message_list parse_message_list(const std::string& resource_data); + +private: + const pe_resource_viewer& res_; +}; +} diff --git a/drivers/pe_bliss/resource_string_table_reader.cpp b/drivers/pe_bliss/resource_string_table_reader.cpp new file mode 100644 index 0000000000..33eace1935 --- /dev/null +++ b/drivers/pe_bliss/resource_string_table_reader.cpp @@ -0,0 +1,88 @@ +#include "resource_string_table_reader.h" +#include "pe_resource_viewer.h" + +namespace pe_bliss +{ +resource_string_table_reader::resource_string_table_reader(const pe_resource_viewer& res) + :res_(res) +{} + +//Returns string table data by ID and index in language directory (instead of language) +const resource_string_list resource_string_table_reader::get_string_table_by_id(uint32_t id, uint32_t index) const +{ + return parse_string_list(id, res_.get_resource_data_by_id(pe_resource_viewer::resource_string, id, index).get_data()); +} + +//Returns string table data by ID and language +const resource_string_list resource_string_table_reader::get_string_table_by_id_lang(uint32_t language, uint32_t id) const +{ + return parse_string_list(id, res_.get_resource_data_by_id(language, pe_resource_viewer::resource_string, id).get_data()); +} + +//Helper function of parsing string list table +const resource_string_list resource_string_table_reader::parse_string_list(uint32_t id, const std::string& resource_data) +{ + resource_string_list ret; + + //16 is maximum count of strings in a string table + static const unsigned long max_string_list_entries = 16; + unsigned long passed_bytes = 0; + for(unsigned long i = 0; i != max_string_list_entries; ++i) + { + //Check resource data length + if(resource_data.length() < sizeof(uint16_t) + passed_bytes) + throw pe_exception("Incorrect resource string table", pe_exception::resource_incorrect_string_table); + + //Get string length - the first WORD + uint16_t string_length = *reinterpret_cast(resource_data.data() + passed_bytes); + passed_bytes += sizeof(uint16_t); //WORD containing string length + + //Check resource data length again + if(resource_data.length() < string_length + passed_bytes) + throw pe_exception("Incorrect resource string table", pe_exception::resource_incorrect_string_table); + + if(string_length) + { + //Create and save string (UNICODE) +#ifdef PE_BLISS_WINDOWS + ret.insert( + std::make_pair(static_cast(((id - 1) << 4) + i), //ID of string is calculated such way + std::wstring(reinterpret_cast(resource_data.data() + passed_bytes), string_length))); +#else + ret.insert( + std::make_pair(static_cast(((id - 1) << 4) + i), //ID of string is calculated such way + pe_utils::from_ucs2(u16string(reinterpret_cast(resource_data.data() + passed_bytes), string_length)))); +#endif + } + + //Go to next string + passed_bytes += string_length * 2; + } + + return ret; +} + +//Returns string from string table by ID and language +const std::wstring resource_string_table_reader::get_string_by_id_lang(uint32_t language, uint16_t id) const +{ + //List strings by string table id and language + const resource_string_list strings(get_string_table_by_id_lang(language, (id >> 4) + 1)); + resource_string_list::const_iterator it = strings.find(id); //Find string by id + if(it == strings.end()) + throw pe_exception("Resource string not found", pe_exception::resource_string_not_found); + + return (*it).second; +} + +//Returns string from string table by ID and index in language directory (instead of language) +const std::wstring resource_string_table_reader::get_string_by_id(uint16_t id, uint32_t index) const +{ + //List strings by string table id and index + const resource_string_list strings(get_string_table_by_id((id >> 4) + 1, index)); + resource_string_list::const_iterator it = strings.find(id); //Find string by id + if(it == strings.end()) + throw pe_exception("Resource string not found", pe_exception::resource_string_not_found); + + return (*it).second; +} +} diff --git a/drivers/pe_bliss/resource_string_table_reader.h b/drivers/pe_bliss/resource_string_table_reader.h new file mode 100644 index 0000000000..34628ec71c --- /dev/null +++ b/drivers/pe_bliss/resource_string_table_reader.h @@ -0,0 +1,36 @@ +#pragma once +#include +#include +#include "stdint_defs.h" + +namespace pe_bliss +{ +class pe_resource_viewer; + +//ID; string +typedef std::map resource_string_list; + +class resource_string_table_reader +{ +public: + resource_string_table_reader(const pe_resource_viewer& res); + +public: + //Returns string table data by ID and language + const resource_string_list get_string_table_by_id_lang(uint32_t language, uint32_t id) const; + //Returns string table data by ID and index in language directory (instead of language) + const resource_string_list get_string_table_by_id(uint32_t id, uint32_t index = 0) const; + //Returns string from string table by ID and language + const std::wstring get_string_by_id_lang(uint32_t language, uint16_t id) const; + //Returns string from string table by ID and index in language directory (instead of language) + const std::wstring get_string_by_id(uint16_t id, uint32_t index = 0) const; + +private: + const pe_resource_viewer& res_; + + //Helper function of parsing string list table + //Id of resource is needed to calculate string IDs correctly + //resource_data is raw string table resource data + static const resource_string_list parse_string_list(uint32_t id, const std::string& resource_data); +}; +} diff --git a/drivers/pe_bliss/resource_version_info_reader.cpp b/drivers/pe_bliss/resource_version_info_reader.cpp new file mode 100644 index 0000000000..4a8a2723e6 --- /dev/null +++ b/drivers/pe_bliss/resource_version_info_reader.cpp @@ -0,0 +1,290 @@ +#include "resource_version_info_reader.h" +#include "utils.h" +#include "pe_exception.h" +#include "resource_internal.h" +#include "pe_resource_viewer.h" + +namespace pe_bliss +{ +using namespace pe_win; + +//Root version info block key value +const u16string resource_version_info_reader::version_info_key(U16TEXT("V\0S\0_\0V\0E\0R\0S\0I\0O\0N\0_\0I\0N\0F\0O\0\0")); + +resource_version_info_reader::resource_version_info_reader(const pe_resource_viewer& res) + :res_(res) +{} + +//Returns aligned version block value position +uint32_t resource_version_info_reader::get_version_block_value_pos(uint32_t base_pos, const unicode16_t* key) +{ + uint32_t string_length = static_cast(u16string(key).length()); + uint32_t ret = pe_utils::align_up(static_cast(sizeof(uint16_t) * 3 /* headers before Key data */ + + base_pos + + (string_length + 1 /* nullbyte */) * 2), + sizeof(uint32_t)); + + //Check possible overflows + if(ret < base_pos || ret < sizeof(uint16_t) * 3 || ret < (string_length + 1) * 2) + throw_incorrect_version_info(); + + return ret; +} + +//Returns aligned version block first child position +uint32_t resource_version_info_reader::get_version_block_first_child_pos(uint32_t base_pos, uint32_t value_length, const unicode16_t* key) +{ + uint32_t string_length = static_cast(u16string(key).length()); + uint32_t ret = pe_utils::align_up(static_cast(sizeof(uint16_t) * 3 /* headers before Key data */ + + base_pos + + (string_length + 1 /* nullbyte */) * 2), + sizeof(uint32_t)) + + pe_utils::align_up(value_length, sizeof(uint32_t)); + + //Check possible overflows + if(ret < base_pos || ret < value_length || ret < sizeof(uint16_t) * 3 || ret < (string_length + 1) * 2) + throw_incorrect_version_info(); + + return ret; +} + +//Throws an exception (id = resource_incorrect_version_info) +void resource_version_info_reader::throw_incorrect_version_info() +{ + throw pe_exception("Incorrect resource version info", pe_exception::resource_incorrect_version_info); +} + +//Returns full version information: +//file_version_info: versions and file info +//lang_string_values_map: map of version info strings with encodings +//translation_values_map: map of translations +const file_version_info resource_version_info_reader::get_version_info(lang_string_values_map& string_values, translation_values_map& translations, const std::string& resource_data) const +{ + //Fixed file version info + file_version_info ret; + + //Check resource data length + if(resource_data.length() < sizeof(version_info_block)) + throw_incorrect_version_info(); + + //Root version info block + const version_info_block* root_block = reinterpret_cast(resource_data.data()); + + //Check root block key for null-termination and its name + if(!pe_utils::is_null_terminated(root_block->Key, resource_data.length() - sizeof(uint16_t) * 3 /* headers before Key data */) + || version_info_key != reinterpret_cast(root_block->Key)) + throw_incorrect_version_info(); + + //If file has fixed version info + if(root_block->ValueLength) + { + //Get root block value position + uint32_t value_pos = get_version_block_value_pos(0, reinterpret_cast(root_block->Key)); + //Check value length + if(resource_data.length() < value_pos + sizeof(vs_fixedfileinfo)) + throw_incorrect_version_info(); + + //Get VS_FIXEDFILEINFO structure pointer + const vs_fixedfileinfo* file_info = reinterpret_cast(resource_data.data() + value_pos); + //Check its signature and some other fields + if(file_info->dwSignature != vs_ffi_signature || file_info->dwStrucVersion != vs_ffi_strucversion) //Don't check if file_info->dwFileFlagsMask == VS_FFI_FILEFLAGSMASK + throw_incorrect_version_info(); + + //Save fixed version info + ret = file_version_info(*file_info); + } + + //Iterate over child elements of VS_VERSIONINFO (StringFileInfo or VarFileInfo) + for(uint32_t child_pos = get_version_block_first_child_pos(0, root_block->ValueLength, reinterpret_cast(root_block->Key)); + child_pos < root_block->Length;) + { + //Check block position + if(!pe_utils::is_sum_safe(child_pos, sizeof(version_info_block)) + || resource_data.length() < child_pos + sizeof(version_info_block)) + throw_incorrect_version_info(); + + //Get VERSION_INFO_BLOCK structure pointer + const version_info_block* block = reinterpret_cast(resource_data.data() + child_pos); + + //Check its length + if(block->Length == 0) + throw_incorrect_version_info(); + + //Check block key for null-termination + if(!pe_utils::is_null_terminated(block->Key, resource_data.length() - child_pos - sizeof(uint16_t) * 3 /* headers before Key data */)) + throw_incorrect_version_info(); + + u16string info_type(reinterpret_cast(block->Key)); + //If we encountered StringFileInfo... + if(info_type == StringFileInfo) + { + //Enumerate all string tables + for(uint32_t string_table_pos = get_version_block_first_child_pos(child_pos, block->ValueLength, reinterpret_cast(block->Key)); + string_table_pos - child_pos < block->Length;) + { + //Check string table block position + if(resource_data.length() < string_table_pos + sizeof(version_info_block)) + throw_incorrect_version_info(); + + //Get VERSION_INFO_BLOCK structure pointer for string table + const version_info_block* string_table = reinterpret_cast(resource_data.data() + string_table_pos); + + //Check its length + if(string_table->Length == 0) + throw_incorrect_version_info(); + + //Check string table key for null-termination + if(!pe_utils::is_null_terminated(string_table->Key, resource_data.length() - string_table_pos - sizeof(uint16_t) * 3 /* headers before Key data */)) + throw_incorrect_version_info(); + + string_values_map new_values; + + //Enumerate all strings in the string table + for(uint32_t string_pos = get_version_block_first_child_pos(string_table_pos, string_table->ValueLength, reinterpret_cast(string_table->Key)); + string_pos - string_table_pos < string_table->Length;) + { + //Check string block position + if(resource_data.length() < string_pos + sizeof(version_info_block)) + throw_incorrect_version_info(); + + //Get VERSION_INFO_BLOCK structure pointer for string block + const version_info_block* string_block = reinterpret_cast(resource_data.data() + string_pos); + + //Check its length + if(string_block->Length == 0) + throw_incorrect_version_info(); + + //Check string block key for null-termination + if(!pe_utils::is_null_terminated(string_block->Key, resource_data.length() - string_pos - sizeof(uint16_t) * 3 /* headers before Key data */)) + throw_incorrect_version_info(); + + u16string data; + //If string block has value + if(string_block->ValueLength != 0) + { + //Get value position + uint32_t value_pos = get_version_block_value_pos(string_pos, reinterpret_cast(string_block->Key)); + //Check it + if(resource_data.length() < value_pos + string_block->ValueLength) + throw pe_exception("Incorrect resource version info", pe_exception::resource_incorrect_version_info); + + //Get UNICODE string value + data = u16string(reinterpret_cast(resource_data.data() + value_pos), string_block->ValueLength); + pe_utils::strip_nullbytes(data); + } + + //Save name-value pair +#ifdef PE_BLISS_WINDOWS + new_values.insert(std::make_pair(reinterpret_cast(string_block->Key), data)); +#else + new_values.insert(std::make_pair(pe_utils::from_ucs2(reinterpret_cast(string_block->Key)), + pe_utils::from_ucs2(data))); +#endif + + //Navigate to next string block + string_pos += pe_utils::align_up(string_block->Length, sizeof(uint32_t)); + } + +#ifdef PE_BLISS_WINDOWS + string_values.insert(std::make_pair(reinterpret_cast(string_table->Key), new_values)); +#else + string_values.insert(std::make_pair(pe_utils::from_ucs2(reinterpret_cast(string_table->Key)), new_values)); +#endif + + //Navigate to next string table block + string_table_pos += pe_utils::align_up(string_table->Length, sizeof(uint32_t)); + } + } + else if(info_type == VarFileInfo) //If we encountered VarFileInfo + { + for(uint32_t var_table_pos = get_version_block_first_child_pos(child_pos, block->ValueLength, reinterpret_cast(block->Key)); + var_table_pos - child_pos < block->Length;) + { + //Check var block position + if(resource_data.length() < var_table_pos + sizeof(version_info_block)) + throw_incorrect_version_info(); + + //Get VERSION_INFO_BLOCK structure pointer for var block + const version_info_block* var_table = reinterpret_cast(resource_data.data() + var_table_pos); + + //Check its length + if(var_table->Length == 0) + throw_incorrect_version_info(); + + //Check its key for null-termination + if(!pe_utils::is_null_terminated(var_table->Key, resource_data.length() - var_table_pos - sizeof(uint16_t) * 3 /* headers before Key data */)) + throw_incorrect_version_info(); + + //If block is "Translation" (actually, there's no other types possible in VarFileInfo) and it has value + if(u16string(reinterpret_cast(var_table->Key)) == Translation && var_table->ValueLength) + { + //Get its value position + uint32_t value_pos = get_version_block_value_pos(var_table_pos, reinterpret_cast(var_table->Key)); + //Cherck value length + if(resource_data.length() < value_pos + var_table->ValueLength) + throw_incorrect_version_info(); + + //Get list of translations: pairs of LANGUAGE_ID - CODEPAGE_ID + for(unsigned long i = 0; i < var_table->ValueLength; i += sizeof(uint16_t) * 2) + { + //Pair of WORDs + uint16_t lang_id = *reinterpret_cast(resource_data.data() + value_pos + i); + uint16_t codepage_id = *reinterpret_cast(resource_data.data() + value_pos + sizeof(uint16_t) + i); + //Save translation + translations.insert(std::make_pair(lang_id, codepage_id)); + } + } + + //Navigate to next var block + var_table_pos += pe_utils::align_up(var_table->Length, sizeof(uint32_t)); + } + } + else + { + throw_incorrect_version_info(); + } + + //Navigate to next element in root block + child_pos += pe_utils::align_up(block->Length, sizeof(uint32_t)); + } + + return ret; +} + +//Returns full version information: +//file_version info: versions and file info +//lang_string_values_map: map of version info strings with encodings +//translation_values_map: map of translations +const file_version_info resource_version_info_reader::get_version_info_by_lang(lang_string_values_map& string_values, translation_values_map& translations, uint32_t language) const +{ + const std::string& resource_data = res_.get_root_directory() //Type directory + .entry_by_id(pe_resource_viewer::resource_version) + .get_resource_directory() //Name/ID directory + .entry_by_id(1) + .get_resource_directory() //Language directory + .entry_by_id(language) + .get_data_entry() //Data directory + .get_data(); + + return get_version_info(string_values, translations, resource_data); +} + +//Returns full version information: +//file_version_info: versions and file info +//lang_string_values_map: map of version info strings with encodings +//translation_values_map: map of translations +const file_version_info resource_version_info_reader::get_version_info(lang_string_values_map& string_values, translation_values_map& translations, uint32_t index) const +{ + const resource_directory::entry_list& entries = res_.get_root_directory() //Type directory + .entry_by_id(pe_resource_viewer::resource_version) + .get_resource_directory() //Name/ID directory + .entry_by_id(1) + .get_resource_directory() //Language directory + .get_entry_list(); + + if(entries.size() <= index) + throw pe_exception("Resource data entry not found", pe_exception::resource_data_entry_not_found); + + return get_version_info(string_values, translations, entries.at(index).get_data_entry().get_data()); //Data directory +} +} diff --git a/drivers/pe_bliss/resource_version_info_reader.h b/drivers/pe_bliss/resource_version_info_reader.h new file mode 100644 index 0000000000..4a14ddc4a5 --- /dev/null +++ b/drivers/pe_bliss/resource_version_info_reader.h @@ -0,0 +1,46 @@ +#pragma once +#include +#include "file_version_info.h" +#include "pe_structures.h" +#include "version_info_types.h" + +namespace pe_bliss +{ +class pe_resource_viewer; + +class resource_version_info_reader +{ +public: //VERSION INFO + resource_version_info_reader(const pe_resource_viewer& res); + + //Returns full version information: + //file_version_info: versions and file info + //lang_lang_string_values_map: map of version info strings with encodings with encodings + //translation_values_map: map of translations + const file_version_info get_version_info(lang_string_values_map& string_values, translation_values_map& translations, uint32_t index = 0) const; + const file_version_info get_version_info_by_lang(lang_string_values_map& string_values, translation_values_map& translations, uint32_t language) const; + +public: + //L"VS_VERSION_INFO" key of root version info block + static const u16string version_info_key; + +private: + const pe_resource_viewer& res_; + + //VERSION INFO helpers + //Returns aligned version block value position + static uint32_t get_version_block_value_pos(uint32_t base_pos, const unicode16_t* key); + + //Returns aligned version block first child position + static uint32_t get_version_block_first_child_pos(uint32_t base_pos, uint32_t value_length, const unicode16_t* key); + + //Returns full version information: + //file_version_info: versions and file info + //lang_string_values_map: map of version info strings with encodings + //translation_values_map: map of translations + const file_version_info get_version_info(lang_string_values_map& string_values, translation_values_map& translations, const std::string& resource_data) const; + + //Throws an exception (id = resource_incorrect_version_info) + static void throw_incorrect_version_info(); +}; +} diff --git a/drivers/pe_bliss/resource_version_info_writer.cpp b/drivers/pe_bliss/resource_version_info_writer.cpp new file mode 100644 index 0000000000..34f21c4a37 --- /dev/null +++ b/drivers/pe_bliss/resource_version_info_writer.cpp @@ -0,0 +1,262 @@ +#include +#include "resource_version_info_writer.h" +#include "pe_structures.h" +#include "resource_internal.h" +#include "utils.h" +#include "pe_resource_manager.h" +#include "resource_version_info_reader.h" + +namespace pe_bliss +{ +using namespace pe_win; + +resource_version_info_writer::resource_version_info_writer(pe_resource_manager& res) + :res_(res) +{} + +//Sets/replaces full version information: +//file_version_info: versions and file info +//lang_string_values_map: map of version info strings with encodings +//translation_values_map: map of translations +void resource_version_info_writer::set_version_info(const file_version_info& file_info, + const lang_string_values_map& string_values, + const translation_values_map& translations, + uint32_t language, + uint32_t codepage, + uint32_t timestamp) +{ + std::string version_data; + + //Calculate total size of version resource data + uint32_t total_version_info_length = + static_cast(sizeof(version_info_block) - sizeof(uint16_t) + sizeof(uint16_t) /* pading */ + + (resource_version_info_reader::version_info_key.length() + 1) * 2 + + sizeof(vs_fixedfileinfo)); + + //If we have any strings values + if(!string_values.empty()) + { + total_version_info_length += sizeof(version_info_block) - sizeof(uint16_t); //StringFileInfo block + total_version_info_length += SizeofStringFileInfo; //Name of block (key) + + //Add required size for version strings + for(lang_string_values_map::const_iterator table_it = string_values.begin(); table_it != string_values.end(); ++table_it) + { + total_version_info_length += pe_utils::align_up(static_cast(sizeof(uint16_t) * 3 + ((*table_it).first.length() + 1) * 2), sizeof(uint32_t)); //Name of child block and block size (key of string table block) + + const string_values_map& values = (*table_it).second; + for(string_values_map::const_iterator it = values.begin(); it != values.end(); ++it) + { + total_version_info_length += pe_utils::align_up(static_cast(sizeof(uint16_t) * 3 + ((*it).first.length() + 1) * 2), sizeof(uint32_t)); + total_version_info_length += pe_utils::align_up(static_cast(((*it).second.length() + 1) * 2), sizeof(uint32_t)); + } + } + } + + //If we have translations + if(!translations.empty()) + { + total_version_info_length += (sizeof(version_info_block) - sizeof(uint16_t)) * 2; //VarFileInfo and Translation blocks + total_version_info_length += SizeofVarFileInfoAligned; //DWORD-aligned VarFileInfo block name + total_version_info_length += SizeofTranslationAligned; //DWORD-aligned Translation block name + total_version_info_length += static_cast(translations.size() * sizeof(uint16_t) * 2); + } + + //Resize version data buffer + version_data.resize(total_version_info_length); + + //Create root version block + version_info_block root_block = {0}; + root_block.ValueLength = sizeof(vs_fixedfileinfo); + root_block.Length = static_cast(total_version_info_length); + + //Fill fixed file info + vs_fixedfileinfo fixed_info = {0}; + fixed_info.dwFileDateLS = file_info.get_file_date_ls(); + fixed_info.dwFileDateMS = file_info.get_file_date_ms(); + fixed_info.dwFileFlags = file_info.get_file_flags(); + fixed_info.dwFileFlagsMask = vs_ffi_fileflagsmask; + fixed_info.dwFileOS = file_info.get_file_os_raw(); + fixed_info.dwFileSubtype = file_info.get_file_subtype(); + fixed_info.dwFileType = file_info.get_file_type_raw(); + fixed_info.dwFileVersionLS = file_info.get_file_version_ls(); + fixed_info.dwFileVersionMS = file_info.get_file_version_ms(); + fixed_info.dwSignature = vs_ffi_signature; + fixed_info.dwStrucVersion = vs_ffi_strucversion; + fixed_info.dwProductVersionLS = file_info.get_product_version_ls(); + fixed_info.dwProductVersionMS = file_info.get_product_version_ms(); + + //Write root block and fixed file info to buffer + uint32_t data_ptr = 0; + memcpy(&version_data[data_ptr], &root_block, sizeof(version_info_block) - sizeof(uint16_t)); + data_ptr += sizeof(version_info_block) - sizeof(uint16_t); + memcpy(&version_data[data_ptr], resource_version_info_reader::version_info_key.c_str(), (resource_version_info_reader::version_info_key.length() + 1) * sizeof(uint16_t)); + data_ptr += static_cast((resource_version_info_reader::version_info_key.length() + 1) * sizeof(uint16_t)); + memset(&version_data[data_ptr], 0, sizeof(uint16_t)); + data_ptr += sizeof(uint16_t); + memcpy(&version_data[data_ptr], &fixed_info, sizeof(fixed_info)); + data_ptr += sizeof(fixed_info); + + //Write string values, if any + if(!string_values.empty()) + { + //Create string file info root block + version_info_block string_file_info_block = {0}; + string_file_info_block.Type = 1; //Block type is string + memcpy(&version_data[data_ptr], &string_file_info_block, sizeof(version_info_block) - sizeof(uint16_t)); + //We will calculate its length later + version_info_block* string_file_info_block_ptr = reinterpret_cast(&version_data[data_ptr]); + data_ptr += sizeof(version_info_block) - sizeof(uint16_t); + + uint32_t old_ptr1 = data_ptr; //Used to calculate string file info block length later + memcpy(&version_data[data_ptr], StringFileInfo, SizeofStringFileInfo); //Write block name + data_ptr += SizeofStringFileInfo; + + //Create string table root block (child of string file info) + version_info_block string_table_block = {0}; + string_table_block.Type = 1; //Block type is string + + for(lang_string_values_map::const_iterator table_it = string_values.begin(); table_it != string_values.end(); ++table_it) + { + const string_values_map& values = (*table_it).second; + + memcpy(&version_data[data_ptr], &string_table_block, sizeof(version_info_block) - sizeof(uint16_t)); + //We will calculate its length later + version_info_block* string_table_block_ptr = reinterpret_cast(&version_data[data_ptr]); + data_ptr += sizeof(version_info_block) - sizeof(uint16_t); + + uint32_t old_ptr2 = data_ptr; //Used to calculate string table block length later + uint32_t lang_key_length = static_cast(((*table_it).first.length() + 1) * sizeof(uint16_t)); + +#ifdef PE_BLISS_WINDOWS + memcpy(&version_data[data_ptr], (*table_it).first.c_str(), lang_key_length); //Write block key +#else + { + u16string str(pe_utils::to_ucs2((*table_it).first)); + memcpy(&version_data[data_ptr], str.c_str(), lang_key_length); //Write block key + } +#endif + + data_ptr += lang_key_length; + //Align key if necessary + if((sizeof(uint16_t) * 3 + lang_key_length) % sizeof(uint32_t)) + { + memset(&version_data[data_ptr], 0, sizeof(uint16_t)); + data_ptr += sizeof(uint16_t); + } + + //Create string block (child of string table block) + version_info_block string_block = {0}; + string_block.Type = 1; //Block type is string + for(string_values_map::const_iterator it = values.begin(); it != values.end(); ++it) + { + //Calculate value length and key length of string block + string_block.ValueLength = static_cast((*it).second.length() + 1); + uint32_t key_length = static_cast(((*it).first.length() + 1) * sizeof(uint16_t)); + //Calculate length of block + string_block.Length = static_cast(pe_utils::align_up(sizeof(uint16_t) * 3 + key_length, sizeof(uint32_t)) + string_block.ValueLength * sizeof(uint16_t)); + + //Write string block + memcpy(&version_data[data_ptr], &string_block, sizeof(version_info_block) - sizeof(uint16_t)); + data_ptr += sizeof(version_info_block) - sizeof(uint16_t); + +#ifdef PE_BLISS_WINDOWS + memcpy(&version_data[data_ptr], (*it).first.c_str(), key_length); //Write block key +#else + { + u16string str(pe_utils::to_ucs2((*it).first)); + memcpy(&version_data[data_ptr], str.c_str(), key_length); //Write block key + } +#endif + + data_ptr += key_length; + //Align key if necessary + if((sizeof(uint16_t) * 3 + key_length) % sizeof(uint32_t)) + { + memset(&version_data[data_ptr], 0, sizeof(uint16_t)); + data_ptr += sizeof(uint16_t); + } + + //Write block data (value) +#ifdef PE_BLISS_WINDOWS + memcpy(&version_data[data_ptr], (*it).second.c_str(), string_block.ValueLength * sizeof(uint16_t)); +#else + { + u16string str(pe_utils::to_ucs2((*it).second)); + memcpy(&version_data[data_ptr], str.c_str(), string_block.ValueLength * sizeof(uint16_t)); + } +#endif + + data_ptr += string_block.ValueLength * 2; + //Align data if necessary + if((string_block.ValueLength * 2) % sizeof(uint32_t)) + { + memset(&version_data[data_ptr], 0, sizeof(uint16_t)); + data_ptr += sizeof(uint16_t); + } + } + + //Calculate string table and string file info blocks lengths + string_table_block_ptr->Length = static_cast(data_ptr - old_ptr2 + sizeof(uint16_t) * 3); + } + + string_file_info_block_ptr->Length = static_cast(data_ptr - old_ptr1 + sizeof(uint16_t) * 3); + } + + //If we have transactions + if(!translations.empty()) + { + //Create root var file info block + version_info_block var_file_info_block = {0}; + var_file_info_block.Type = 1; //Type of block is string + //Write block header + memcpy(&version_data[data_ptr], &var_file_info_block, sizeof(version_info_block) - sizeof(uint16_t)); + //We will calculate its length later + version_info_block* var_file_info_block_ptr = reinterpret_cast(&version_data[data_ptr]); + data_ptr += sizeof(version_info_block) - sizeof(uint16_t); + + uint32_t old_ptr1 = data_ptr; //Used to calculate var file info block length later + memcpy(&version_data[data_ptr], VarFileInfoAligned, SizeofVarFileInfoAligned); //Write block key (aligned) + data_ptr += SizeofVarFileInfoAligned; + + //Create root translation block (child of var file info block) + version_info_block translation_block = {0}; + //Write block header + memcpy(&version_data[data_ptr], &translation_block, sizeof(version_info_block) - sizeof(uint16_t)); + //We will calculate its length later + version_info_block* translation_block_ptr = reinterpret_cast(&version_data[data_ptr]); + data_ptr += sizeof(version_info_block) - sizeof(uint16_t); + + uint32_t old_ptr2 = data_ptr; //Used to calculate var file info block length later + memcpy(&version_data[data_ptr], TranslationAligned, SizeofTranslationAligned); //Write block key (aligned) + data_ptr += SizeofTranslationAligned; + + //Calculate translation block value length + translation_block_ptr->ValueLength = static_cast(sizeof(uint16_t) * 2 * translations.size()); + + //Write translation values to block + for(translation_values_map::const_iterator it = translations.begin(); it != translations.end(); ++it) + { + uint16_t lang_id = (*it).first; //Language ID + uint16_t codepage_id = (*it).second; //Codepage ID + memcpy(&version_data[data_ptr], &lang_id, sizeof(lang_id)); + data_ptr += sizeof(lang_id); + memcpy(&version_data[data_ptr], &codepage_id, sizeof(codepage_id)); + data_ptr += sizeof(codepage_id); + } + + //Calculate Translation and VarFileInfo blocks lengths + translation_block_ptr->Length = static_cast(data_ptr - old_ptr2 + sizeof(uint16_t) * 3); + var_file_info_block_ptr->Length = static_cast(data_ptr - old_ptr1 + sizeof(uint16_t) * 3); + } + + //Add/replace version info resource + res_.add_resource(version_data, pe_resource_viewer::resource_version, 1, language, codepage, timestamp); +} + +//Removes version info by language (ID = 1) +bool resource_version_info_writer::remove_version_info(uint32_t language) +{ + return res_.remove_resource(pe_resource_viewer::resource_version, 1, language); +} +} diff --git a/drivers/pe_bliss/resource_version_info_writer.h b/drivers/pe_bliss/resource_version_info_writer.h new file mode 100644 index 0000000000..cab7e925ee --- /dev/null +++ b/drivers/pe_bliss/resource_version_info_writer.h @@ -0,0 +1,31 @@ +#pragma once +#include "version_info_types.h" +#include "file_version_info.h" + +namespace pe_bliss +{ +class pe_resource_manager; + +class resource_version_info_writer +{ +public: + resource_version_info_writer(pe_resource_manager& res); + + //Sets/replaces full version information: + //file_version_info: versions and file info + //lang_string_values_map: map of version info strings with encodings + //translation_values_map: map of translations + void set_version_info(const file_version_info& file_info, + const lang_string_values_map& string_values, + const translation_values_map& translations, + uint32_t language, + uint32_t codepage = 0, + uint32_t timestamp = 0); + + //Removes version info by language (ID = 1) + bool remove_version_info(uint32_t language); + +private: + pe_resource_manager& res_; +}; +} diff --git a/drivers/pe_bliss/stdint_defs.h b/drivers/pe_bliss/stdint_defs.h new file mode 100644 index 0000000000..309cf3d762 --- /dev/null +++ b/drivers/pe_bliss/stdint_defs.h @@ -0,0 +1,24 @@ +#pragma once +#ifdef _MSC_VER +#if _MSC_VER < 1600 +namespace pe_bliss +{ + //stdint.h definitions for MSVC 2008 and earlier, as + //it doesn't have them + typedef signed char int8_t; + typedef short int16_t; + typedef int int32_t; + + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; + + typedef long long int64_t; + typedef unsigned long long uint64_t; +} +#else +#include +#endif +#else +#include +#endif diff --git a/drivers/pe_bliss/utils.cpp b/drivers/pe_bliss/utils.cpp new file mode 100644 index 0000000000..69f013098f --- /dev/null +++ b/drivers/pe_bliss/utils.cpp @@ -0,0 +1,86 @@ +#include +#include "utils.h" +#include "pe_exception.h" + +#ifndef PE_BLISS_WINDOWS +#include +#endif + +namespace pe_bliss +{ +const double pe_utils::log_2 = 1.44269504088896340736; //instead of using M_LOG2E + +//Returns stream size +std::streamoff pe_utils::get_file_size(std::istream& file) +{ + //Get old istream offset + std::streamoff old_offset = file.tellg(); + file.seekg(0, std::ios::end); + std::streamoff filesize = file.tellg(); + //Set old istream offset + file.seekg(old_offset); + return filesize; +} + +#ifndef PE_BLISS_WINDOWS +const u16string pe_utils::to_ucs2(const std::wstring& str) +{ + u16string ret; + if(str.empty()) + return ret; + + ret.resize(str.length()); + + iconv_t conv = iconv_open("UCS-2", "WCHAR_T"); + if(conv == reinterpret_cast(-1)) + throw pe_exception("Error opening iconv", pe_exception::encoding_convertion_error); + + size_t inbytesleft = str.length() * sizeof(wchar_t); + size_t outbytesleft = ret.length() * sizeof(unicode16_t); + const wchar_t* in_pos = str.c_str(); + unicode16_t* out_pos = &ret[0]; + + size_t result = iconv(conv, const_cast(reinterpret_cast(&in_pos)), &inbytesleft, reinterpret_cast(&out_pos), &outbytesleft); + iconv_close(conv); + + if(result == static_cast(-1)) + throw pe_exception("Iconv error", pe_exception::encoding_convertion_error); + + return ret; +} + +const std::wstring pe_utils::from_ucs2(const u16string& str) +{ + std::wstring ret; + if(str.empty()) + return ret; + + ret.resize(str.length()); + + iconv_t conv = iconv_open("WCHAR_T", "UCS-2"); + if(conv == reinterpret_cast(-1)) + throw pe_exception("Error opening iconv", pe_exception::encoding_convertion_error); + + size_t inbytesleft = str.length() * sizeof(unicode16_t); + size_t outbytesleft = ret.length() * sizeof(wchar_t); + const unicode16_t* in_pos = str.c_str(); + wchar_t* out_pos = &ret[0]; + + size_t result = iconv(conv, const_cast(reinterpret_cast(&in_pos)), &inbytesleft, reinterpret_cast(&out_pos), &outbytesleft); + iconv_close(conv); + + if(result == static_cast(-1)) + throw pe_exception("Iconv error", pe_exception::encoding_convertion_error); + + return ret; +} +#endif + +bool operator==(const pe_win::guid& guid1, const pe_win::guid& guid2) +{ + return guid1.Data1 == guid2.Data1 + && guid1.Data2 == guid2.Data2 + && guid1.Data3 == guid2.Data3 + && !memcmp(guid1.Data4, guid2.Data4, sizeof(guid1.Data4)); +} +} diff --git a/drivers/pe_bliss/utils.h b/drivers/pe_bliss/utils.h new file mode 100644 index 0000000000..c090121595 --- /dev/null +++ b/drivers/pe_bliss/utils.h @@ -0,0 +1,84 @@ +#pragma once +#include +#include +#include "stdint_defs.h" +#include "pe_structures.h" + +namespace pe_bliss +{ +class pe_utils +{ +public: + //Returns true if string "data" with maximum length "raw_length" is null-terminated + template + static bool is_null_terminated(const T* data, size_t raw_length) + { + raw_length /= sizeof(T); + for(size_t l = 0; l < raw_length; l++) + { + if(data[l] == static_cast(L'\0')) + return true; + } + + return false; + } + + //Helper template function to strip nullbytes in the end of string + template + static void strip_nullbytes(std::basic_string& str) + { + while(!*(str.end() - 1) && !str.empty()) + str.erase(str.length() - 1); + } + + //Helper function to determine if number is power of 2 + template + static inline bool is_power_of_2(T x) + { + return !(x & (x - 1)); + } + + //Helper function to align number down + template + static inline T align_down(T x, uint32_t align) + { + return x & ~(static_cast(align) - 1); + } + + //Helper function to align number up + template + static inline T align_up(T x, uint32_t align) + { + return (x & static_cast(align - 1)) ? align_down(x, align) + static_cast(align) : x; + } + + //Returns true if sum of two unsigned integers is safe (no overflow occurs) + static inline bool is_sum_safe(uint32_t a, uint32_t b) + { + return a <= static_cast(-1) - b; + } + + //Two gigabytes value in bytes + static const uint32_t two_gb = 0x80000000; + static const uint32_t max_dword = 0xFFFFFFFF; + static const uint32_t max_word = 0x0000FFFF; + static const double log_2; //instead of using M_LOG2E + + //Returns stream size + static std::streamoff get_file_size(std::istream& file); + +#ifndef PE_BLISS_WINDOWS +public: + static const u16string to_ucs2(const std::wstring& str); + static const std::wstring from_ucs2(const u16string& str); +#endif + +private: + pe_utils(); + pe_utils(pe_utils&); + pe_utils& operator=(const pe_utils&); +}; + +//Windows GUID comparison +bool operator==(const pe_win::guid& guid1, const pe_win::guid& guid2); +} diff --git a/drivers/pe_bliss/version_info_editor.cpp b/drivers/pe_bliss/version_info_editor.cpp new file mode 100644 index 0000000000..9e5c9b7a1c --- /dev/null +++ b/drivers/pe_bliss/version_info_editor.cpp @@ -0,0 +1,163 @@ +#include +#include +#include "version_info_types.h" +#include "version_info_editor.h" +#include "version_info_viewer.h" + +namespace pe_bliss +{ +//Default constructor +//strings - version info strings with charsets +//translations - version info translations map +version_info_editor::version_info_editor(lang_string_values_map& strings, translation_values_map& translations) + :version_info_viewer(strings, translations), + strings_edit_(strings), + translations_edit_(translations) +{} + +//Below functions have parameter translation +//If it's empty, the default language translation will be taken +//If there's no default language translation, the first one will be taken + +//Sets company name +void version_info_editor::set_company_name(const std::wstring& value, const std::wstring& translation) +{ + set_property(L"CompanyName", value, translation); +} + +//Sets file description +void version_info_editor::set_file_description(const std::wstring& value, const std::wstring& translation) +{ + set_property(L"FileDescription", value, translation); +} + +//Sets file version +void version_info_editor::set_file_version(const std::wstring& value, const std::wstring& translation) +{ + set_property(L"FileVersion", value, translation); +} + +//Sets internal file name +void version_info_editor::set_internal_name(const std::wstring& value, const std::wstring& translation) +{ + set_property(L"InternalName", value, translation); +} + +//Sets legal copyright +void version_info_editor::set_legal_copyright(const std::wstring& value, const std::wstring& translation) +{ + set_property(L"LegalCopyright", value, translation); +} + +//Sets original file name +void version_info_editor::set_original_filename(const std::wstring& value, const std::wstring& translation) +{ + set_property(L"OriginalFilename", value, translation); +} + +//Sets product name +void version_info_editor::set_product_name(const std::wstring& value, const std::wstring& translation) +{ + set_property(L"ProductName", value, translation); +} + +//Sets product version +void version_info_editor::set_product_version(const std::wstring& value, const std::wstring& translation) +{ + set_property(L"ProductVersion", value, translation); +} + +//Sets version info property value +//property_name - property name +//value - property value +//If translation does not exist, it will be added +//If property does not exist, it will be added +void version_info_editor::set_property(const std::wstring& property_name, const std::wstring& value, const std::wstring& translation) +{ + lang_string_values_map::iterator it = strings_edit_.begin(); + + if(translation.empty()) + { + //If no translation was specified + it = strings_edit_.find(default_language_translation); //Find default translation table + if(it == strings_edit_.end()) //If there's no default translation table, take the first one + { + it = strings_edit_.begin(); + if(it == strings_edit_.end()) //If there's no any translation table, add default one + { + it = strings_edit_.insert(std::make_pair(default_language_translation, string_values_map())).first; + //Also add it to translations list + add_translation(default_language_translation); + } + } + } + else + { + it = strings_edit_.find(translation); //Find specified translation table + if(it == strings_edit_.end()) //If there's no translation, add it + { + it = strings_edit_.insert(std::make_pair(translation, string_values_map())).first; + //Also add it to translations list + add_translation(translation); + } + } + + //Change value of the required property + ((*it).second)[property_name] = value; +} + +//Adds translation to translation list +void version_info_editor::add_translation(const std::wstring& translation) +{ + std::pair translation_ids(translation_from_string(translation)); + add_translation(translation_ids.first, translation_ids.second); +} + +void version_info_editor::add_translation(uint16_t language_id, uint16_t codepage_id) +{ + std::pair + range(translations_edit_.equal_range(language_id)); + + //If translation already exists + for(translation_values_map::const_iterator it = range.first; it != range.second; ++it) + { + if((*it).second == codepage_id) + return; + } + + translations_edit_.insert(std::make_pair(language_id, codepage_id)); +} + +//Removes translation from translations and strings lists +void version_info_editor::remove_translation(const std::wstring& translation) +{ + std::pair translation_ids(translation_from_string(translation)); + remove_translation(translation_ids.first, translation_ids.second); +} + +void version_info_editor::remove_translation(uint16_t language_id, uint16_t codepage_id) +{ + { + //Erase string table (if exists) + std::wstringstream ss; + ss << std::hex + << std::setw(4) << std::setfill(L'0') << language_id + << std::setw(4) << std::setfill(L'0') << codepage_id; + + strings_edit_.erase(ss.str()); + } + + //Find and erase translation from translations table + std::pair + it_pair = translations_edit_.equal_range(language_id); + + for(translation_values_map::iterator it = it_pair.first; it != it_pair.second; ++it) + { + if((*it).second == codepage_id) + { + translations_edit_.erase(it); + break; + } + } +} +} diff --git a/drivers/pe_bliss/version_info_editor.h b/drivers/pe_bliss/version_info_editor.h new file mode 100644 index 0000000000..9bef6a01b8 --- /dev/null +++ b/drivers/pe_bliss/version_info_editor.h @@ -0,0 +1,58 @@ +#pragma once +#include "version_info_types.h" +#include "version_info_viewer.h" + +namespace pe_bliss +{ + //Helper class to read and edit version information + //lang_string_values_map: map of version info strings with encodings + //translation_values_map: map of translations + class version_info_editor : public version_info_viewer + { + public: + //Default constructor + //strings - version info strings with charsets + //translations - version info translations map + version_info_editor(lang_string_values_map& strings, translation_values_map& translations); + + //Below functions have parameter translation + //If it's empty, the default language translation will be taken + //If there's no default language translation, the first one will be taken + + //Sets company name + void set_company_name(const std::wstring& value, const std::wstring& translation = std::wstring()); + //Sets file description + void set_file_description(const std::wstring& value, const std::wstring& translation = std::wstring()); + //Sets file version + void set_file_version(const std::wstring& value, const std::wstring& translation = std::wstring()); + //Sets internal file name + void set_internal_name(const std::wstring& value, const std::wstring& translation = std::wstring()); + //Sets legal copyright + void set_legal_copyright(const std::wstring& value, const std::wstring& translation = std::wstring()); + //Sets original file name + void set_original_filename(const std::wstring& value, const std::wstring& translation = std::wstring()); + //Sets product name + void set_product_name(const std::wstring& value, const std::wstring& translation = std::wstring()); + //Sets product version + void set_product_version(const std::wstring& value, const std::wstring& translation = std::wstring()); + + //Sets version info property value + //property_name - property name + //value - property value + //If translation does not exist, it will be added to strings and translations lists + //If property does not exist, it will be added + void set_property(const std::wstring& property_name, const std::wstring& value, const std::wstring& translation = std::wstring()); + + //Adds translation to translation list + void add_translation(const std::wstring& translation); + void add_translation(uint16_t language_id, uint16_t codepage_id); + + //Removes translation from translations and strings lists + void remove_translation(const std::wstring& translation); + void remove_translation(uint16_t language_id, uint16_t codepage_id); + + private: + lang_string_values_map& strings_edit_; + translation_values_map& translations_edit_; + }; +} diff --git a/drivers/pe_bliss/version_info_types.h b/drivers/pe_bliss/version_info_types.h new file mode 100644 index 0000000000..e289f40663 --- /dev/null +++ b/drivers/pe_bliss/version_info_types.h @@ -0,0 +1,17 @@ +#pragma once +#include +#include +#include "stdint_defs.h" + +namespace pe_bliss +{ + //Typedef for version info functions: Name - Value + typedef std::map string_values_map; + //Typedef for version info functions: Language string - String Values Map + //Language String consists of LangID and CharsetID + //E.g. 041904b0 for Russian UNICODE, 040004b0 for Process Default Language UNICODE + typedef std::map lang_string_values_map; + + //Typedef for version info functions: Language - Character Set + typedef std::multimap translation_values_map; +} diff --git a/drivers/pe_bliss/version_info_viewer.cpp b/drivers/pe_bliss/version_info_viewer.cpp new file mode 100644 index 0000000000..7881c4b96d --- /dev/null +++ b/drivers/pe_bliss/version_info_viewer.cpp @@ -0,0 +1,159 @@ +#include +#include +#include "pe_exception.h" +#include "version_info_viewer.h" + +namespace pe_bliss +{ +//Default process language, UNICODE +const std::wstring version_info_viewer::default_language_translation(L"040904b0"); + +//Default constructor +//strings - version info strings with charsets +//translations - version info translations map +version_info_viewer::version_info_viewer(const lang_string_values_map& strings, const translation_values_map& translations) + :strings_(strings), translations_(translations) +{} + +//Below functions have parameter translation +//If it's empty, the default language translation will be taken +//If there's no default language translation, the first one will be taken + +//Returns company name +const std::wstring version_info_viewer::get_company_name(const std::wstring& translation) const +{ + return get_property(L"CompanyName", translation); +} + +//Returns file description +const std::wstring version_info_viewer::get_file_description(const std::wstring& translation) const +{ + return get_property(L"FileDescription", translation); +} + +//Returns file version +const std::wstring version_info_viewer::get_file_version(const std::wstring& translation) const +{ + return get_property(L"FileVersion", translation); +} + +//Returns internal file name +const std::wstring version_info_viewer::get_internal_name(const std::wstring& translation) const +{ + return get_property(L"InternalName", translation); +} + +//Returns legal copyright +const std::wstring version_info_viewer::get_legal_copyright(const std::wstring& translation) const +{ + return get_property(L"LegalCopyright", translation); +} + +//Returns original file name +const std::wstring version_info_viewer::get_original_filename(const std::wstring& translation) const +{ + return get_property(L"OriginalFilename", translation); +} + +//Returns product name +const std::wstring version_info_viewer::get_product_name(const std::wstring& translation) const +{ + return get_property(L"ProductName", translation); +} + +//Returns product version +const std::wstring version_info_viewer::get_product_version(const std::wstring& translation) const +{ + return get_property(L"ProductVersion", translation); +} + +//Returns list of translations in string representation +const version_info_viewer::translation_list version_info_viewer::get_translation_list() const +{ + translation_list ret; + + //Enumerate all translations + for(translation_values_map::const_iterator it = translations_.begin(); it != translations_.end(); ++it) + { + //Create string representation of translation value + std::wstringstream ss; + ss << std::hex + << std::setw(4) << std::setfill(L'0') << (*it).first + << std::setw(4) << std::setfill(L'0') << (*it).second; + + //Save it + ret.push_back(ss.str()); + } + + return ret; +} + +//Returns version info property value +//property_name - required property name +//If throw_if_absent = true, will throw exception if property does not exist +//If throw_if_absent = false, will return empty string if property does not exist +const std::wstring version_info_viewer::get_property(const std::wstring& property_name, const std::wstring& translation, bool throw_if_absent) const +{ + std::wstring ret; + + //If there're no strings + if(strings_.empty()) + { + if(throw_if_absent) + throw pe_exception("Version info string does not exist", pe_exception::version_info_string_does_not_exist); + + return ret; + } + + lang_string_values_map::const_iterator it = strings_.begin(); + + if(translation.empty()) + { + //If no translation was specified + it = strings_.find(default_language_translation); //Find default translation table + if(it == strings_.end()) //If there's no default translation table, take the first one + it = strings_.begin(); + } + else + { + it = strings_.find(translation); //Find specified translation table + if(it == strings_.end()) + { + if(throw_if_absent) + throw pe_exception("Version info string does not exist", pe_exception::version_info_string_does_not_exist); + + return ret; + } + } + + //Find value of the required property + string_values_map::const_iterator str_it = (*it).second.find(property_name); + + if(str_it == (*it).second.end()) + { + if(throw_if_absent) + throw pe_exception("Version info string does not exist", pe_exception::version_info_string_does_not_exist); + + return ret; + } + + ret = (*str_it).second; + + return ret; +} + +//Converts translation HEX-string to pair of language ID and codepage ID +const version_info_viewer::translation_pair version_info_viewer::translation_from_string(const std::wstring& translation) +{ + uint32_t translation_id = 0; + + { + //Convert string to DWORD + std::wstringstream ss; + ss << std::hex << translation; + ss >> translation_id; + } + + return std::make_pair(static_cast(translation_id >> 16), static_cast(translation_id & 0xFFFF)); +} +} diff --git a/drivers/pe_bliss/version_info_viewer.h b/drivers/pe_bliss/version_info_viewer.h new file mode 100644 index 0000000000..a4a757bc32 --- /dev/null +++ b/drivers/pe_bliss/version_info_viewer.h @@ -0,0 +1,68 @@ +#pragma once +#include +#include +#include +#include "pe_resource_viewer.h" +#include "pe_structures.h" +#include "version_info_types.h" + +namespace pe_bliss +{ +//Helper class to read version information +//lang_string_values_map: map of version info strings with encodings +//translation_values_map: map of translations +class version_info_viewer +{ +public: + //Useful typedefs + typedef std::pair translation_pair; + typedef std::vector translation_list; + +public: + //Default constructor + //strings - version info strings with charsets + //translations - version info translations map + version_info_viewer(const lang_string_values_map& strings, const translation_values_map& translations); + + //Below functions have parameter translation + //If it's empty, the default language translation will be taken + //If there's no default language translation, the first one will be taken + + //Returns company name + const std::wstring get_company_name(const std::wstring& translation = std::wstring()) const; + //Returns file description + const std::wstring get_file_description(const std::wstring& translation = std::wstring()) const; + //Returns file version + const std::wstring get_file_version(const std::wstring& translation = std::wstring()) const; + //Returns internal file name + const std::wstring get_internal_name(const std::wstring& translation = std::wstring()) const; + //Returns legal copyright + const std::wstring get_legal_copyright(const std::wstring& translation = std::wstring()) const; + //Returns original file name + const std::wstring get_original_filename(const std::wstring& translation = std::wstring()) const; + //Returns product name + const std::wstring get_product_name(const std::wstring& translation = std::wstring()) const; + //Returns product version + const std::wstring get_product_version(const std::wstring& translation = std::wstring()) const; + + //Returns list of translations in string representation + const translation_list get_translation_list() const; + + //Returns version info property value + //property_name - required property name + //If throw_if_absent = true, will throw exception if property does not exist + //If throw_if_absent = false, will return empty string if property does not exist + const std::wstring get_property(const std::wstring& property_name, const std::wstring& translation = std::wstring(), bool throw_if_absent = false) const; + + //Converts translation HEX-string to pair of language ID and codepage ID + static const translation_pair translation_from_string(const std::wstring& translation); + +public: + //Default process language, UNICODE + static const std::wstring default_language_translation; + +private: + const lang_string_values_map& strings_; + const translation_values_map& translations_; +}; +} diff --git a/drivers/register_driver_types.cpp b/drivers/register_driver_types.cpp index 2647d23011..d832b2c1f5 100644 --- a/drivers/register_driver_types.cpp +++ b/drivers/register_driver_types.cpp @@ -29,6 +29,11 @@ #include "convex_decomp/b2d_decompose.h" #endif +#ifdef TOOLS_ENABLED +#include "pe_bliss/pe_bliss_godot.h" +#include "platform/windows/export/export.h" +#endif + #ifdef TREMOR_ENABLED #include "teora/audio_stream_ogg.h" #endif @@ -246,7 +251,11 @@ void register_driver_types() { #ifdef ETC1_ENABLED _register_etc1_compress_func(); #endif - + +#ifdef TOOLS_ENABLED + EditorExportPlatformWindows::_add_resrc_func=pe_bliss_add_resrc; +#endif + initialize_chibi(); } -- cgit v1.2.3 From 55b8c3ee48b690e0b801351ef0819b08b038b9d6 Mon Sep 17 00:00:00 2001 From: masoud bh Date: Thu, 24 Sep 2015 02:39:26 +0330 Subject: change pe_bliss parent directory from /drivers to /tools --- drivers/SCsub | 1 - drivers/pe_bliss/README | 61 - drivers/pe_bliss/SCsub | 5 - drivers/pe_bliss/entropy.cpp | 90 -- drivers/pe_bliss/entropy.h | 30 - drivers/pe_bliss/file_version_info.cpp | 419 ------ drivers/pe_bliss/file_version_info.h | 178 --- drivers/pe_bliss/message_table.cpp | 60 - drivers/pe_bliss/message_table.h | 35 - drivers/pe_bliss/pe_base.cpp | 1659 --------------------- drivers/pe_bliss/pe_base.h | 523 ------- drivers/pe_bliss/pe_bliss.h | 18 - drivers/pe_bliss/pe_bliss_godot.cpp | 118 -- drivers/pe_bliss/pe_bliss_godot.h | 7 - drivers/pe_bliss/pe_bliss_resources.h | 15 - drivers/pe_bliss/pe_bound_import.cpp | 290 ---- drivers/pe_bliss/pe_bound_import.h | 87 -- drivers/pe_bliss/pe_checksum.cpp | 82 - drivers/pe_bliss/pe_checksum.h | 9 - drivers/pe_bliss/pe_debug.cpp | 844 ----------- drivers/pe_bliss/pe_debug.h | 303 ---- drivers/pe_bliss/pe_directory.cpp | 38 - drivers/pe_bliss/pe_directory.h | 29 - drivers/pe_bliss/pe_dotnet.cpp | 165 -- drivers/pe_bliss/pe_dotnet.h | 76 - drivers/pe_bliss/pe_exception.cpp | 19 - drivers/pe_bliss/pe_exception.h | 109 -- drivers/pe_bliss/pe_exception_directory.cpp | 156 -- drivers/pe_bliss/pe_exception_directory.h | 67 - drivers/pe_bliss/pe_exports.cpp | 679 --------- drivers/pe_bliss/pe_exports.h | 163 -- drivers/pe_bliss/pe_factory.cpp | 22 - drivers/pe_bliss/pe_factory.h | 18 - drivers/pe_bliss/pe_imports.cpp | 756 ---------- drivers/pe_bliss/pe_imports.h | 187 --- drivers/pe_bliss/pe_load_config.cpp | 536 ------- drivers/pe_bliss/pe_load_config.h | 163 -- drivers/pe_bliss/pe_properties.cpp | 20 - drivers/pe_bliss/pe_properties.h | 215 --- drivers/pe_bliss/pe_properties_generic.cpp | 624 -------- drivers/pe_bliss/pe_properties_generic.h | 256 ---- drivers/pe_bliss/pe_rebuilder.cpp | 193 --- drivers/pe_bliss/pe_rebuilder.h | 19 - drivers/pe_bliss/pe_relocations.cpp | 299 ---- drivers/pe_bliss/pe_relocations.h | 101 -- drivers/pe_bliss/pe_resource_manager.cpp | 265 ---- drivers/pe_bliss/pe_resource_manager.h | 92 -- drivers/pe_bliss/pe_resource_viewer.cpp | 361 ----- drivers/pe_bliss/pe_resource_viewer.h | 132 -- drivers/pe_bliss/pe_resources.cpp | 705 --------- drivers/pe_bliss/pe_resources.h | 224 --- drivers/pe_bliss/pe_rich_data.cpp | 131 -- drivers/pe_bliss/pe_rich_data.h | 37 - drivers/pe_bliss/pe_section.cpp | 281 ---- drivers/pe_bliss/pe_section.h | 137 -- drivers/pe_bliss/pe_structures.h | 1007 ------------- drivers/pe_bliss/pe_tls.cpp | 375 ----- drivers/pe_bliss/pe_tls.h | 101 -- drivers/pe_bliss/resource_bitmap_reader.cpp | 65 - drivers/pe_bliss/resource_bitmap_reader.h | 29 - drivers/pe_bliss/resource_bitmap_writer.cpp | 54 - drivers/pe_bliss/resource_bitmap_writer.h | 26 - drivers/pe_bliss/resource_cursor_icon_reader.cpp | 500 ------- drivers/pe_bliss/resource_cursor_icon_reader.h | 63 - drivers/pe_bliss/resource_cursor_icon_writer.cpp | 426 ------ drivers/pe_bliss/resource_cursor_icon_writer.h | 73 - drivers/pe_bliss/resource_data_info.cpp | 27 - drivers/pe_bliss/resource_data_info.h | 27 - drivers/pe_bliss/resource_internal.h | 13 - drivers/pe_bliss/resource_message_list_reader.cpp | 110 -- drivers/pe_bliss/resource_message_list_reader.h | 28 - drivers/pe_bliss/resource_string_table_reader.cpp | 88 -- drivers/pe_bliss/resource_string_table_reader.h | 36 - drivers/pe_bliss/resource_version_info_reader.cpp | 290 ---- drivers/pe_bliss/resource_version_info_reader.h | 46 - drivers/pe_bliss/resource_version_info_writer.cpp | 262 ---- drivers/pe_bliss/resource_version_info_writer.h | 31 - drivers/pe_bliss/stdint_defs.h | 24 - drivers/pe_bliss/utils.cpp | 86 -- drivers/pe_bliss/utils.h | 84 -- drivers/pe_bliss/version_info_editor.cpp | 163 -- drivers/pe_bliss/version_info_editor.h | 58 - drivers/pe_bliss/version_info_types.h | 17 - drivers/pe_bliss/version_info_viewer.cpp | 159 -- drivers/pe_bliss/version_info_viewer.h | 68 - drivers/register_driver_types.cpp | 4 - 86 files changed, 16449 deletions(-) delete mode 100644 drivers/pe_bliss/README delete mode 100644 drivers/pe_bliss/SCsub delete mode 100644 drivers/pe_bliss/entropy.cpp delete mode 100644 drivers/pe_bliss/entropy.h delete mode 100644 drivers/pe_bliss/file_version_info.cpp delete mode 100644 drivers/pe_bliss/file_version_info.h delete mode 100644 drivers/pe_bliss/message_table.cpp delete mode 100644 drivers/pe_bliss/message_table.h delete mode 100644 drivers/pe_bliss/pe_base.cpp delete mode 100644 drivers/pe_bliss/pe_base.h delete mode 100644 drivers/pe_bliss/pe_bliss.h delete mode 100644 drivers/pe_bliss/pe_bliss_godot.cpp delete mode 100644 drivers/pe_bliss/pe_bliss_godot.h delete mode 100644 drivers/pe_bliss/pe_bliss_resources.h delete mode 100644 drivers/pe_bliss/pe_bound_import.cpp delete mode 100644 drivers/pe_bliss/pe_bound_import.h delete mode 100644 drivers/pe_bliss/pe_checksum.cpp delete mode 100644 drivers/pe_bliss/pe_checksum.h delete mode 100644 drivers/pe_bliss/pe_debug.cpp delete mode 100644 drivers/pe_bliss/pe_debug.h delete mode 100644 drivers/pe_bliss/pe_directory.cpp delete mode 100644 drivers/pe_bliss/pe_directory.h delete mode 100644 drivers/pe_bliss/pe_dotnet.cpp delete mode 100644 drivers/pe_bliss/pe_dotnet.h delete mode 100644 drivers/pe_bliss/pe_exception.cpp delete mode 100644 drivers/pe_bliss/pe_exception.h delete mode 100644 drivers/pe_bliss/pe_exception_directory.cpp delete mode 100644 drivers/pe_bliss/pe_exception_directory.h delete mode 100644 drivers/pe_bliss/pe_exports.cpp delete mode 100644 drivers/pe_bliss/pe_exports.h delete mode 100644 drivers/pe_bliss/pe_factory.cpp delete mode 100644 drivers/pe_bliss/pe_factory.h delete mode 100644 drivers/pe_bliss/pe_imports.cpp delete mode 100644 drivers/pe_bliss/pe_imports.h delete mode 100644 drivers/pe_bliss/pe_load_config.cpp delete mode 100644 drivers/pe_bliss/pe_load_config.h delete mode 100644 drivers/pe_bliss/pe_properties.cpp delete mode 100644 drivers/pe_bliss/pe_properties.h delete mode 100644 drivers/pe_bliss/pe_properties_generic.cpp delete mode 100644 drivers/pe_bliss/pe_properties_generic.h delete mode 100644 drivers/pe_bliss/pe_rebuilder.cpp delete mode 100644 drivers/pe_bliss/pe_rebuilder.h delete mode 100644 drivers/pe_bliss/pe_relocations.cpp delete mode 100644 drivers/pe_bliss/pe_relocations.h delete mode 100644 drivers/pe_bliss/pe_resource_manager.cpp delete mode 100644 drivers/pe_bliss/pe_resource_manager.h delete mode 100644 drivers/pe_bliss/pe_resource_viewer.cpp delete mode 100644 drivers/pe_bliss/pe_resource_viewer.h delete mode 100644 drivers/pe_bliss/pe_resources.cpp delete mode 100644 drivers/pe_bliss/pe_resources.h delete mode 100644 drivers/pe_bliss/pe_rich_data.cpp delete mode 100644 drivers/pe_bliss/pe_rich_data.h delete mode 100644 drivers/pe_bliss/pe_section.cpp delete mode 100644 drivers/pe_bliss/pe_section.h delete mode 100644 drivers/pe_bliss/pe_structures.h delete mode 100644 drivers/pe_bliss/pe_tls.cpp delete mode 100644 drivers/pe_bliss/pe_tls.h delete mode 100644 drivers/pe_bliss/resource_bitmap_reader.cpp delete mode 100644 drivers/pe_bliss/resource_bitmap_reader.h delete mode 100644 drivers/pe_bliss/resource_bitmap_writer.cpp delete mode 100644 drivers/pe_bliss/resource_bitmap_writer.h delete mode 100644 drivers/pe_bliss/resource_cursor_icon_reader.cpp delete mode 100644 drivers/pe_bliss/resource_cursor_icon_reader.h delete mode 100644 drivers/pe_bliss/resource_cursor_icon_writer.cpp delete mode 100644 drivers/pe_bliss/resource_cursor_icon_writer.h delete mode 100644 drivers/pe_bliss/resource_data_info.cpp delete mode 100644 drivers/pe_bliss/resource_data_info.h delete mode 100644 drivers/pe_bliss/resource_internal.h delete mode 100644 drivers/pe_bliss/resource_message_list_reader.cpp delete mode 100644 drivers/pe_bliss/resource_message_list_reader.h delete mode 100644 drivers/pe_bliss/resource_string_table_reader.cpp delete mode 100644 drivers/pe_bliss/resource_string_table_reader.h delete mode 100644 drivers/pe_bliss/resource_version_info_reader.cpp delete mode 100644 drivers/pe_bliss/resource_version_info_reader.h delete mode 100644 drivers/pe_bliss/resource_version_info_writer.cpp delete mode 100644 drivers/pe_bliss/resource_version_info_writer.h delete mode 100644 drivers/pe_bliss/stdint_defs.h delete mode 100644 drivers/pe_bliss/utils.cpp delete mode 100644 drivers/pe_bliss/utils.h delete mode 100644 drivers/pe_bliss/version_info_editor.cpp delete mode 100644 drivers/pe_bliss/version_info_editor.h delete mode 100644 drivers/pe_bliss/version_info_types.h delete mode 100644 drivers/pe_bliss/version_info_viewer.cpp delete mode 100644 drivers/pe_bliss/version_info_viewer.h (limited to 'drivers') diff --git a/drivers/SCsub b/drivers/SCsub index a7ed29e8e9..bc46bf2cec 100644 --- a/drivers/SCsub +++ b/drivers/SCsub @@ -39,7 +39,6 @@ if (env["opus"]=="yes"): SConscript('opus/SCsub'); if (env["tools"]=="yes"): SConscript("convex_decomp/SCsub"); - SConscript('pe_bliss/SCsub'); #if env["theora"]=="yes": # SConscript("theoraplayer/SCsub") diff --git a/drivers/pe_bliss/README b/drivers/pe_bliss/README deleted file mode 100644 index 8a8c0b4df9..0000000000 --- a/drivers/pe_bliss/README +++ /dev/null @@ -1,61 +0,0 @@ -Открытая бесплатная библиотека для работы с PE-файлами PE Bliss. -Бесплатна к использованию, модификации и распространению. -Автор: DX -(c) DX 2011-2012, kaimi.ru - -Совместимость: Windows, Linux - -Возможности: -[+] Создание PE или PE+ файла с нуля -[+] Чтение 32-разрядных и 64-разрядных PE-файлов (PE, PE+) и единообразная работа с ними -[+] Пересборка 32-разрядных и 64-разрядных PE-файлов -[+] Работа с директориями и заголовками -[+] Конвертирование адресов -[+] Чтение и редактирование секций PE-файла -[+] Чтение и редактирование таблицы импортов -[+] Чтение и редактирование таблицы экспортов -[+] Чтение и редактирование таблиц релокаций -[+] Чтение и редактирование ресурсов -[+] Чтение и редактирование TLS -[+] Чтение и редактирование конфигурации образа (image config) -[+] Чтение базовой информации .NET -[+] Чтение и редактирование информации о привязанном импорте -[+] Чтение директории исключений (только PE+) -[+] Чтение отладочной директории с расширенной информацией -[+] Вычисление энтропии -[+] Изменение файлового выравнивания -[+] Изменение базового адреса загрузки -[+] Работа с DOS Stub'ом и Rich overlay -[+] Высокоуровневое чтение ресурсов: картинки, иконки, курсоры, информация о версии, строковые таблицы, таблицы сообщений -[+] Высокоуровневое редактирование ресурсов: картинки, иконки, курсоры, информация о версии - -[English] -Open a free library for working with PE-file PE Bliss. -Free to use, modify, and distribute. -Author: DX -(c) DX 2011-2012, kaimi.ru -Compatibility: Windows, Linux - -### Capabilities: -[+] Creation of PE or PE + file from scratch -[+] Reading the 32-bit and 64-bit PE-file (PE, PE +) and uniform working with them -[+] Rebuild 32-bit and 64-bit PE-files -[+] Working with the directors and titles -[+] Converting addresses -[+] Reading and editing sections of PE-file -[+] Reading and editing the import table -[+] Reading and editing tables exports -[+] Reading and editing tables relocations -[+] Reading and editing resources -[+] Reading and editing TLS -[+] Reading and editing the configuration of the image (image config) -[+] Reading data base .NET -[+] Reading and editing information about tethered import -[+] Read the directory exceptions (only PE +) -[+] Read debug directories with extended information -[+] The calculation of entropy -[+] Changing file alignment -[+] Change the base load address -[+] Support of DOS Stub'om and Rich overlay -[+] High-level reading resources: images, icons, cursors, version information, string tables, message table -[+] High-level editing resources: images, icons, cursors, version information \ No newline at end of file diff --git a/drivers/pe_bliss/SCsub b/drivers/pe_bliss/SCsub deleted file mode 100644 index 9fbb467baa..0000000000 --- a/drivers/pe_bliss/SCsub +++ /dev/null @@ -1,5 +0,0 @@ -Import('env') - -env.add_source_files(env.drivers_sources,"*.cpp") - -Export('env') diff --git a/drivers/pe_bliss/entropy.cpp b/drivers/pe_bliss/entropy.cpp deleted file mode 100644 index cdd8efb8a9..0000000000 --- a/drivers/pe_bliss/entropy.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include -#include "entropy.h" -#include "utils.h" - -namespace pe_bliss -{ -//Calculates entropy for PE image section -double entropy_calculator::calculate_entropy(const section& s) -{ - if(s.get_raw_data().empty()) //Don't count entropy for empty sections - throw pe_exception("Section is empty", pe_exception::section_is_empty); - - return calculate_entropy(s.get_raw_data().data(), s.get_raw_data().length()); -} - -//Calculates entropy for istream (from current position of stream) -double entropy_calculator::calculate_entropy(std::istream& file) -{ - uint32_t byte_count[256] = {0}; //Byte count for each of 255 bytes - - if(file.bad()) - throw pe_exception("Stream is bad", pe_exception::stream_is_bad); - - std::streamoff pos = file.tellg(); - - std::streamoff length = pe_utils::get_file_size(file); - length -= file.tellg(); - - if(!length) //Don't calculate entropy for empty buffers - throw pe_exception("Data length is zero", pe_exception::data_is_empty); - - //Count bytes - for(std::streamoff i = 0; i != length; ++i) - ++byte_count[static_cast(file.get())]; - - file.seekg(pos); - - return calculate_entropy(byte_count, length); -} - -//Calculates entropy for data block -double entropy_calculator::calculate_entropy(const char* data, size_t length) -{ - uint32_t byte_count[256] = {0}; //Byte count for each of 255 bytes - - if(!length) //Don't calculate entropy for empty buffers - throw pe_exception("Data length is zero", pe_exception::data_is_empty); - - //Count bytes - for(size_t i = 0; i != length; ++i) - ++byte_count[static_cast(data[i])]; - - return calculate_entropy(byte_count, length); -} - -//Calculates entropy for this PE file (only section data) -double entropy_calculator::calculate_entropy(const pe_base& pe) -{ - uint32_t byte_count[256] = {0}; //Byte count for each of 255 bytes - - size_t total_data_length = 0; - - //Count bytes for each section - for(section_list::const_iterator it = pe.get_image_sections().begin(); it != pe.get_image_sections().end(); ++it) - { - const std::string& data = (*it).get_raw_data(); - size_t length = data.length(); - total_data_length += length; - for(size_t i = 0; i != length; ++i) - ++byte_count[static_cast(data[i])]; - } - - return calculate_entropy(byte_count, total_data_length); -} - -//Calculates entropy from bytes count -double entropy_calculator::calculate_entropy(const uint32_t byte_count[256], std::streamoff total_length) -{ - double entropy = 0.; //Entropy result value - //Calculate entropy - for(uint32_t i = 0; i < 256; ++i) - { - double temp = static_cast(byte_count[i]) / total_length; - if(temp > 0.) - entropy += std::abs(temp * (std::log(temp) * pe_utils::log_2)); - } - - return entropy; -} -} diff --git a/drivers/pe_bliss/entropy.h b/drivers/pe_bliss/entropy.h deleted file mode 100644 index d49d0f7e9b..0000000000 --- a/drivers/pe_bliss/entropy.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once -#include -#include "pe_base.h" - -namespace pe_bliss -{ -class entropy_calculator -{ -public: - //Calculates entropy for PE image section - static double calculate_entropy(const section& s); - - //Calculates entropy for istream (from current position of stream) - static double calculate_entropy(std::istream& file); - - //Calculates entropy for data block - static double calculate_entropy(const char* data, size_t length); - - //Calculates entropy for this PE file (only section data) - static double calculate_entropy(const pe_base& pe); - -private: - entropy_calculator(); - entropy_calculator(const entropy_calculator&); - entropy_calculator& operator=(const entropy_calculator&); - - //Calculates entropy from bytes count - static double calculate_entropy(const uint32_t byte_count[256], std::streamoff total_length); -}; -} diff --git a/drivers/pe_bliss/file_version_info.cpp b/drivers/pe_bliss/file_version_info.cpp deleted file mode 100644 index 50a02f8908..0000000000 --- a/drivers/pe_bliss/file_version_info.cpp +++ /dev/null @@ -1,419 +0,0 @@ -#include "file_version_info.h" -#include "pe_structures.h" - -namespace pe_bliss -{ -using namespace pe_win; - -//Default constructor -file_version_info::file_version_info() - :file_version_ms_(0), file_version_ls_(0), - product_version_ms_(0), product_version_ls_(0), - file_flags_(0), - file_os_(0), - file_type_(0), file_subtype_(0), - file_date_ms_(0), file_date_ls_(0) -{} - -//Constructor from Windows fixed version info structure -file_version_info::file_version_info(const vs_fixedfileinfo& info) - :file_version_ms_(info.dwFileVersionMS), file_version_ls_(info.dwFileVersionLS), - product_version_ms_(info.dwProductVersionMS), product_version_ls_(info.dwProductVersionLS), - file_flags_(info.dwFileFlags), - file_os_(info.dwFileOS), - file_type_(info.dwFileType), file_subtype_(info.dwFileSubtype), - file_date_ms_(info.dwFileDateMS), file_date_ls_(info.dwFileDateLS) -{} - -//Returns true if file is debug-built -bool file_version_info::is_debug() const -{ - return file_flags_ & vs_ff_debug ? true : false; -} - -//Returns true if file is release-built -bool file_version_info::is_prerelease() const -{ - return file_flags_ & vs_ff_prerelease ? true : false; -} - -//Returns true if file is patched -bool file_version_info::is_patched() const -{ - return file_flags_ & vs_ff_patched ? true : false; -} - -//Returns true if private build -bool file_version_info::is_private_build() const -{ - return file_flags_ & vs_ff_privatebuild ? true : false; -} - -//Returns true if special build -bool file_version_info::is_special_build() const -{ - return file_flags_ & vs_ff_specialbuild ? true : false; -} - -//Returns true if info inferred -bool file_version_info::is_info_inferred() const -{ - return file_flags_ & vs_ff_infoinferred ? true : false; -} - -//Retuens file flags (raw DWORD) -uint32_t file_version_info::get_file_flags() const -{ - return file_flags_; -} - -//Returns file version most significant DWORD -uint32_t file_version_info::get_file_version_ms() const -{ - return file_version_ms_; -} - -//Returns file version least significant DWORD -uint32_t file_version_info::get_file_version_ls() const -{ - return file_version_ls_; -} - -//Returns product version most significant DWORD -uint32_t file_version_info::get_product_version_ms() const -{ - return product_version_ms_; -} - -//Returns product version least significant DWORD -uint32_t file_version_info::get_product_version_ls() const -{ - return product_version_ls_; -} - -//Returns file OS type (raw DWORD) -uint32_t file_version_info::get_file_os_raw() const -{ - return file_os_; -} - -//Returns file OS type -file_version_info::file_os_type file_version_info::get_file_os() const -{ - //Determine file operation system type - switch(file_os_) - { - case vos_dos: - return file_os_dos; - - case vos_os216: - return file_os_os216; - - case vos_os232: - return file_os_os232; - - case vos_nt: - return file_os_nt; - - case vos_wince: - return file_os_wince; - - case vos__windows16: - return file_os_win16; - - case vos__pm16: - return file_os_pm16; - - case vos__pm32: - return file_os_pm32; - - case vos__windows32: - return file_os_win32; - - case vos_dos_windows16: - return file_os_dos_win16; - - case vos_dos_windows32: - return file_os_dos_win32; - - case vos_os216_pm16: - return file_os_os216_pm16; - - case vos_os232_pm32: - return file_os_os232_pm32; - - case vos_nt_windows32: - return file_os_nt_win32; - } - - return file_os_unknown; -} - -//Returns file type (raw DWORD) -uint32_t file_version_info::get_file_type_raw() const -{ - return file_type_; -} - -//Returns file type -file_version_info::file_type file_version_info::get_file_type() const -{ - //Determine file type - switch(file_type_) - { - case vft_app: - return file_type_application; - - case vft_dll: - return file_type_dll; - - case vft_drv: - return file_type_driver; - - case vft_font: - return file_type_font; - - case vft_vxd: - return file_type_vxd; - - case vft_static_lib: - return file_type_static_lib; - } - - return file_type_unknown; -} - -//Returns file subtype (usually non-zero for drivers and fonts) -uint32_t file_version_info::get_file_subtype() const -{ - return file_subtype_; -} - -//Returns file date most significant DWORD -uint32_t file_version_info::get_file_date_ms() const -{ - return file_date_ms_; -} - -//Returns file date least significant DWORD -uint32_t file_version_info::get_file_date_ls() const -{ - return file_date_ls_; -} - -//Helper to set file flag -void file_version_info::set_file_flag(uint32_t flag) -{ - file_flags_ |= flag; -} - -//Helper to clear file flag -void file_version_info::clear_file_flag(uint32_t flag) -{ - file_flags_ &= ~flag; -} - -//Helper to set or clear file flag -void file_version_info::set_file_flag(uint32_t flag, bool set_flag) -{ - set_flag ? set_file_flag(flag) : clear_file_flag(flag); -} - -//Sets if file is debug-built -void file_version_info::set_debug(bool debug) -{ - set_file_flag(vs_ff_debug, debug); -} - -//Sets if file is prerelease -void file_version_info::set_prerelease(bool prerelease) -{ - set_file_flag(vs_ff_prerelease, prerelease); -} - -//Sets if file is patched -void file_version_info::set_patched(bool patched) -{ - set_file_flag(vs_ff_patched, patched); -} - -//Sets if private build -void file_version_info::set_private_build(bool private_build) -{ - set_file_flag(vs_ff_privatebuild, private_build); -} - -//Sets if special build -void file_version_info::set_special_build(bool special_build) -{ - set_file_flag(vs_ff_specialbuild, special_build); -} - -//Sets if info inferred -void file_version_info::set_info_inferred(bool info_inferred) -{ - set_file_flag(vs_ff_infoinferred, info_inferred); -} - -//Sets flags (raw DWORD) -void file_version_info::set_file_flags(uint32_t file_flags) -{ - file_flags_ = file_flags; -} - -//Sets file version most significant DWORD -void file_version_info::set_file_version_ms(uint32_t file_version_ms) -{ - file_version_ms_ = file_version_ms; -} - -//Sets file version least significant DWORD -void file_version_info::set_file_version_ls(uint32_t file_version_ls) -{ - file_version_ls_ = file_version_ls; -} - -//Sets product version most significant DWORD -void file_version_info::set_product_version_ms(uint32_t product_version_ms) -{ - product_version_ms_ = product_version_ms; -} - -//Sets product version least significant DWORD -void file_version_info::set_product_version_ls(uint32_t product_version_ls) -{ - product_version_ls_ = product_version_ls; -} - -//Sets file OS type (raw DWORD) -void file_version_info::set_file_os_raw(uint32_t file_os) -{ - file_os_ = file_os; -} - -//Sets file OS type -void file_version_info::set_file_os(file_os_type file_os) -{ - //Determine file operation system type - switch(file_os) - { - case file_os_dos: - file_os_ = vos_dos; - return; - - case file_os_os216: - file_os_ = vos_os216; - return; - - case file_os_os232: - file_os_ = vos_os232; - return; - - case file_os_nt: - file_os_ = vos_nt; - return; - - case file_os_wince: - file_os_ = vos_wince; - return; - - case file_os_win16: - file_os_ = vos__windows16; - return; - - case file_os_pm16: - file_os_ = vos__pm16; - return; - - case file_os_pm32: - file_os_ = vos__pm32; - return; - - case file_os_win32: - file_os_ = vos__windows32; - return; - - case file_os_dos_win16: - file_os_ = vos_dos_windows16; - return; - - case file_os_dos_win32: - file_os_ = vos_dos_windows32; - return; - - case file_os_os216_pm16: - file_os_ = vos_os216_pm16; - return; - - case file_os_os232_pm32: - file_os_ = vos_os232_pm32; - return; - - case file_os_nt_win32: - file_os_ = vos_nt_windows32; - return; - - default: - return; - } -} - -//Sets file type (raw DWORD) -void file_version_info::set_file_type_raw(uint32_t file_type) -{ - file_type_ = file_type; -} - -//Sets file type -void file_version_info::set_file_type(file_type file_type) -{ - //Determine file type - switch(file_type) - { - case file_type_application: - file_type_ = vft_app; - return; - - case file_type_dll: - file_type_ = vft_dll; - return; - - case file_type_driver: - file_type_ = vft_drv; - return; - - case file_type_font: - file_type_ = vft_font; - return; - - case file_type_vxd: - file_type_ = vft_vxd; - return; - - case file_type_static_lib: - file_type_ = vft_static_lib; - return; - - default: - return; - } -} - -//Sets file subtype (usually non-zero for drivers and fonts) -void file_version_info::set_file_subtype(uint32_t file_subtype) -{ - file_subtype_ = file_subtype; -} - -//Sets file date most significant DWORD -void file_version_info::set_file_date_ms(uint32_t file_date_ms) -{ - file_date_ms_ = file_date_ms; -} - -//Sets file date least significant DWORD -void file_version_info::set_file_date_ls(uint32_t file_date_ls) -{ - file_date_ls_ = file_date_ls; -} -} diff --git a/drivers/pe_bliss/file_version_info.h b/drivers/pe_bliss/file_version_info.h deleted file mode 100644 index 8a469dbb8d..0000000000 --- a/drivers/pe_bliss/file_version_info.h +++ /dev/null @@ -1,178 +0,0 @@ -#pragma once -#include -#include -#include "stdint_defs.h" -#include "pe_structures.h" - -namespace pe_bliss -{ -//Structure representing fixed file version info -class file_version_info -{ -public: - //Enumeration of file operating system types - enum file_os_type - { - file_os_unknown, - file_os_dos, - file_os_os216, - file_os_os232, - file_os_nt, - file_os_wince, - file_os_win16, - file_os_pm16, - file_os_pm32, - file_os_win32, - file_os_dos_win16, - file_os_dos_win32, - file_os_os216_pm16, - file_os_os232_pm32, - file_os_nt_win32 - }; - - //Enumeration of file types - enum file_type - { - file_type_unknown, - file_type_application, - file_type_dll, - file_type_driver, - file_type_font, - file_type_vxd, - file_type_static_lib - }; - -public: - //Default constructor - file_version_info(); - //Constructor from Windows fixed version info structure - explicit file_version_info(const pe_win::vs_fixedfileinfo& info); - -public: //Getters - //Returns true if file is debug-built - bool is_debug() const; - //Returns true if file is prerelease - bool is_prerelease() const; - //Returns true if file is patched - bool is_patched() const; - //Returns true if private build - bool is_private_build() const; - //Returns true if special build - bool is_special_build() const; - //Returns true if info inferred - bool is_info_inferred() const; - //Retuens file flags (raw DWORD) - uint32_t get_file_flags() const; - - //Returns file version most significant DWORD - uint32_t get_file_version_ms() const; - //Returns file version least significant DWORD - uint32_t get_file_version_ls() const; - //Returns product version most significant DWORD - uint32_t get_product_version_ms() const; - //Returns product version least significant DWORD - uint32_t get_product_version_ls() const; - - //Returns file OS type (raw DWORD) - uint32_t get_file_os_raw() const; - //Returns file OS type - file_os_type get_file_os() const; - - //Returns file type (raw DWORD) - uint32_t get_file_type_raw() const; - //Returns file type - file_type get_file_type() const; - - //Returns file subtype (usually non-zero for drivers and fonts) - uint32_t get_file_subtype() const; - - //Returns file date most significant DWORD - uint32_t get_file_date_ms() const; - //Returns file date least significant DWORD - uint32_t get_file_date_ls() const; - - //Returns file version string - template - const std::basic_string get_file_version_string() const - { - return get_version_string(file_version_ms_, file_version_ls_); - } - - //Returns product version string - template - const std::basic_string get_product_version_string() const - { - return get_version_string(product_version_ms_, product_version_ls_); - } - -public: //Setters - //Sets if file is debug-built - void set_debug(bool debug); - //Sets if file is prerelease - void set_prerelease(bool prerelease); - //Sets if file is patched - void set_patched(bool patched); - //Sets if private build - void set_private_build(bool private_build); - //Sets if special build - void set_special_build(bool special_build); - //Sets if info inferred - void set_info_inferred(bool info_inferred); - //Sets flags (raw DWORD) - void set_file_flags(uint32_t file_flags); - - //Sets file version most significant DWORD - void set_file_version_ms(uint32_t file_version_ms); - //Sets file version least significant DWORD - void set_file_version_ls(uint32_t file_version_ls); - //Sets product version most significant DWORD - void set_product_version_ms(uint32_t product_version_ms); - //Sets product version least significant DWORD - void set_product_version_ls(uint32_t product_version_ls); - - //Sets file OS type (raw DWORD) - void set_file_os_raw(uint32_t file_os); - //Sets file OS type - void set_file_os(file_os_type file_os); - - //Sets file type (raw DWORD) - void set_file_type_raw(uint32_t file_type); - //Sets file type - void set_file_type(file_type file_type); - - //Sets file subtype (usually non-zero for drivers and fonts) - void set_file_subtype(uint32_t file_subtype); - - //Sets file date most significant DWORD - void set_file_date_ms(uint32_t file_date_ms); - //Sets file date least significant DWORD - void set_file_date_ls(uint32_t file_date_ls); - -private: - //Helper to convert version DWORDs to string - template - static const std::basic_string get_version_string(uint32_t ms, uint32_t ls) - { - std::basic_stringstream ss; - ss << (ms >> 16) << static_cast(L'.') - << (ms & 0xFFFF) << static_cast(L'.') - << (ls >> 16) << static_cast(L'.') - << (ls & 0xFFFF); - return ss.str(); - } - - //Helper to set file flag - void set_file_flag(uint32_t flag); - //Helper to clear file flag - void clear_file_flag(uint32_t flag); - //Helper to set or clear file flag - void set_file_flag(uint32_t flag, bool set_flag); - - uint32_t file_version_ms_, file_version_ls_, - product_version_ms_, product_version_ls_; - uint32_t file_flags_; - uint32_t file_os_; - uint32_t file_type_, file_subtype_; - uint32_t file_date_ms_, file_date_ls_; -}; -} diff --git a/drivers/pe_bliss/message_table.cpp b/drivers/pe_bliss/message_table.cpp deleted file mode 100644 index 940387dd28..0000000000 --- a/drivers/pe_bliss/message_table.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include "message_table.h" -#include "utils.h" - -namespace pe_bliss -{ -//Default constructor -message_table_item::message_table_item() - :unicode_(false) -{} - -//Constructor from ANSI string -message_table_item::message_table_item(const std::string& str) - :unicode_(false), ansi_str_(str) -{ - pe_utils::strip_nullbytes(ansi_str_); -} - -//Constructor from UNICODE string -message_table_item::message_table_item(const std::wstring& str) - :unicode_(true), unicode_str_(str) -{ - pe_utils::strip_nullbytes(unicode_str_); -} - -//Returns true if contained string is unicode -bool message_table_item::is_unicode() const -{ - return unicode_; -} - -//Returns ANSI string -const std::string& message_table_item::get_ansi_string() const -{ - return ansi_str_; -} - -//Returns UNICODE string -const std::wstring& message_table_item::get_unicode_string() const -{ - return unicode_str_; -} - -//Sets ANSI string (clears UNICODE one) -void message_table_item::set_string(const std::string& str) -{ - ansi_str_ = str; - pe_utils::strip_nullbytes(ansi_str_); - unicode_str_.clear(); - unicode_ = false; -} - -//Sets UNICODE string (clears ANSI one) -void message_table_item::set_string(const std::wstring& str) -{ - unicode_str_ = str; - pe_utils::strip_nullbytes(unicode_str_); - ansi_str_.clear(); - unicode_ = true; -} -} diff --git a/drivers/pe_bliss/message_table.h b/drivers/pe_bliss/message_table.h deleted file mode 100644 index d437f511b2..0000000000 --- a/drivers/pe_bliss/message_table.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once -#include -#include -#include "stdint_defs.h" - -namespace pe_bliss -{ -//Structure representing message table string -class message_table_item -{ -public: - //Default constructor - message_table_item(); - //Constructors from ANSI and UNICODE strings - explicit message_table_item(const std::string& str); - explicit message_table_item(const std::wstring& str); - - //Returns true if string is UNICODE - bool is_unicode() const; - //Returns ANSI string - const std::string& get_ansi_string() const; - //Returns UNICODE string - const std::wstring& get_unicode_string() const; - -public: - //Sets ANSI or UNICODE string - void set_string(const std::string& str); - void set_string(const std::wstring& str); - -private: - bool unicode_; - std::string ansi_str_; - std::wstring unicode_str_; -}; -} diff --git a/drivers/pe_bliss/pe_base.cpp b/drivers/pe_bliss/pe_base.cpp deleted file mode 100644 index bdce0977cb..0000000000 --- a/drivers/pe_bliss/pe_base.cpp +++ /dev/null @@ -1,1659 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include "pe_exception.h" -#include "pe_base.h" - -namespace pe_bliss -{ -using namespace pe_win; - -//Constructor -pe_base::pe_base(std::istream& file, const pe_properties& props, bool read_debug_raw_data) -{ - props_ = props.duplicate().release(); - - //Save istream state - std::ios_base::iostate state = file.exceptions(); - std::streamoff old_offset = file.tellg(); - - try - { - file.exceptions(std::ios::goodbit); - //Read DOS header, PE headers and section data - read_dos_header(file); - read_pe(file, read_debug_raw_data); - } - catch(const std::exception&) - { - //If something went wrong, restore istream state - file.seekg(old_offset); - file.exceptions(state); - file.clear(); - //Rethrow - throw; - } - - //Restore istream state - file.seekg(old_offset); - file.exceptions(state); - file.clear(); -} - -pe_base::pe_base(const pe_properties& props, uint32_t section_alignment, bool dll, uint16_t subsystem) -{ - props_ = props.duplicate().release(); - props_->create_pe(section_alignment, subsystem); - - has_overlay_ = false; - memset(&dos_header_, 0, sizeof(dos_header_)); - - dos_header_.e_magic = 0x5A4D; //"MZ" - //Magic numbers from MSVC++ build - dos_header_.e_maxalloc = 0xFFFF; - dos_header_.e_cblp = 0x90; - dos_header_.e_cp = 3; - dos_header_.e_cparhdr = 4; - dos_header_.e_sp = 0xB8; - dos_header_.e_lfarlc = 64; - - set_characteristics(image_file_executable_image | image_file_relocs_stripped); - - if(get_pe_type() == pe_type_32) - set_characteristics_flags(image_file_32bit_machine); - - if(dll) - set_characteristics_flags(image_file_dll); - - set_subsystem_version(5, 1); //WinXP - set_os_version(5, 1); //WinXP -} - -pe_base::pe_base(const pe_base& pe) - :dos_header_(pe.dos_header_), - rich_overlay_(pe.rich_overlay_), - sections_(pe.sections_), - has_overlay_(pe.has_overlay_), - full_headers_data_(pe.full_headers_data_), - debug_data_(pe.debug_data_), - props_(0) -{ - props_ = pe.props_->duplicate().release(); -} - -pe_base& pe_base::operator=(const pe_base& pe) -{ - dos_header_ = pe.dos_header_; - rich_overlay_ = pe.rich_overlay_; - sections_ = pe.sections_; - has_overlay_ = pe.has_overlay_; - full_headers_data_ = pe.full_headers_data_; - debug_data_ = pe.debug_data_; - delete props_; - props_ = 0; - props_ = pe.props_->duplicate().release(); - - return *this; -} - -pe_base::~pe_base() -{ - delete props_; -} - -//Returns dos header -const image_dos_header& pe_base::get_dos_header() const -{ - return dos_header_; -} - -//Returns dos header -image_dos_header& pe_base::get_dos_header() -{ - return dos_header_; -} - -//Returns PE headers start position (e_lfanew) -int32_t pe_base::get_pe_header_start() const -{ - return dos_header_.e_lfanew; -} - -//Strips MSVC stub overlay -void pe_base::strip_stub_overlay() -{ - rich_overlay_.clear(); -} - -//Fills MSVC stub overlay with character c -void pe_base::fill_stub_overlay(char c) -{ - if(rich_overlay_.length()) - rich_overlay_.assign(rich_overlay_.length(), c); -} - -//Sets stub MSVS overlay -void pe_base::set_stub_overlay(const std::string& data) -{ - rich_overlay_ = data; -} - -//Returns stub overlay -const std::string& pe_base::get_stub_overlay() const -{ - return rich_overlay_; -} - -//Realigns all sections -void pe_base::realign_all_sections() -{ - for(unsigned int i = 0; i < sections_.size(); i++) - realign_section(i); -} - -//Returns number of sections from PE header -uint16_t pe_base::get_number_of_sections() const -{ - return props_->get_number_of_sections(); -} - -//Updates number of sections in PE header -uint16_t pe_base::update_number_of_sections() -{ - uint16_t new_number = static_cast(sections_.size()); - props_->set_number_of_sections(new_number); - return new_number; -} - -//Returns section alignment -uint32_t pe_base::get_section_alignment() const -{ - return props_->get_section_alignment(); -} - -//Returns image sections list -section_list& pe_base::get_image_sections() -{ - return sections_; -} - -//Returns image sections list -const section_list& pe_base::get_image_sections() const -{ - return sections_; -} - -//Realigns section by index -void pe_base::realign_section(uint32_t index) -{ - //Check index - if(sections_.size() <= index) - throw pe_exception("Section not found", pe_exception::section_not_found); - - //Get section iterator - section_list::iterator it = sections_.begin() + index; - section& s = *it; - - //Calculate, how many null bytes we have in the end of raw section data - std::size_t strip = 0; - for(std::size_t i = (*it).get_raw_data().length(); i >= 1; --i) - { - if(s.get_raw_data()[i - 1] == 0) - strip++; - else - break; - } - - if(it == sections_.end() - 1) //If we're realigning the last section - { - //We can strip ending null bytes - s.set_size_of_raw_data(static_cast(s.get_raw_data().length() - strip)); - s.get_raw_data().resize(s.get_raw_data().length() - strip, 0); - } - else - { - //Else just set size of raw data - uint32_t raw_size_aligned = s.get_aligned_raw_size(get_file_alignment()); - s.set_size_of_raw_data(raw_size_aligned); - s.get_raw_data().resize(raw_size_aligned, 0); - } -} - -//Returns file alignment -uint32_t pe_base::get_file_alignment() const -{ - return props_->get_file_alignment(); -} - -//Sets file alignment -void pe_base::set_file_alignment(uint32_t alignment) -{ - //Check alignment - if(alignment < minimum_file_alignment) - throw pe_exception("File alignment can't be less than 512", pe_exception::incorrect_file_alignment); - - if(!pe_utils::is_power_of_2(alignment)) - throw pe_exception("File alignment must be a power of 2", pe_exception::incorrect_file_alignment); - - if(alignment > get_section_alignment()) - throw pe_exception("File alignment must be <= section alignment", pe_exception::incorrect_file_alignment); - - //Set file alignment without any additional checks - set_file_alignment_unchecked(alignment); -} - -//Returns size of image -uint32_t pe_base::get_size_of_image() const -{ - return props_->get_size_of_image(); -} - -//Returns image entry point -uint32_t pe_base::get_ep() const -{ - return props_->get_ep(); -} - -//Sets image entry point (just a value of PE header) -void pe_base::set_ep(uint32_t new_ep) -{ - props_->set_ep(new_ep); -} - -//Returns number of RVA and sizes (number of DATA_DIRECTORY entries) -uint32_t pe_base::get_number_of_rvas_and_sizes() const -{ - return props_->get_number_of_rvas_and_sizes(); -} - -//Sets number of RVA and sizes (number of DATA_DIRECTORY entries) -void pe_base::set_number_of_rvas_and_sizes(uint32_t number) -{ - props_->set_number_of_rvas_and_sizes(number); -} - -//Returns PE characteristics -uint16_t pe_base::get_characteristics() const -{ - return props_->get_characteristics(); -} - -//Sets PE characteristics (a value inside header) -void pe_base::set_characteristics(uint16_t ch) -{ - props_->set_characteristics(ch); -} - -//Returns section from RVA -section& pe_base::section_from_rva(uint32_t rva) -{ - //Search for section - for(section_list::iterator i = sections_.begin(); i != sections_.end(); ++i) - { - section& s = *i; - //Return section if found - if(rva >= s.get_virtual_address() && rva < s.get_virtual_address() + s.get_aligned_virtual_size(get_section_alignment())) - return s; - } - - throw pe_exception("No section found by presented address", pe_exception::no_section_found); -} - -//Returns section from RVA -const section& pe_base::section_from_rva(uint32_t rva) const -{ - //Search for section - for(section_list::const_iterator i = sections_.begin(); i != sections_.end(); ++i) - { - const section& s = *i; - //Return section if found - if(rva >= s.get_virtual_address() && rva < s.get_virtual_address() + s.get_aligned_virtual_size(get_section_alignment())) - return s; - } - - throw pe_exception("No section found by presented address", pe_exception::no_section_found); -} - -//Returns section from directory ID -section& pe_base::section_from_directory(uint32_t directory_id) -{ - return section_from_rva(get_directory_rva(directory_id)); -} - -//Returns section from directory ID -const section& pe_base::section_from_directory(uint32_t directory_id) const -{ - return section_from_rva(get_directory_rva(directory_id)); -} - -//Sets section virtual size (actual for the last one of this PE or for unbound section) -void pe_base::set_section_virtual_size(section& s, uint32_t vsize) -{ - //Check if we're changing virtual size of the last section - //Of course, we can change virtual size of section that's not bound to this PE file - if(sections_.empty() || std::find_if(sections_.begin(), sections_.end() - 1, section_ptr_finder(s)) != sections_.end() - 1) - throw pe_exception("Can't change virtual size of any section, except last one", pe_exception::error_changing_section_virtual_size); - - //If we're setting virtual size to zero - if(vsize == 0) - { - //Check if section is empty - if(s.empty()) - throw pe_exception("Cannot set virtual size of empty section to zero", pe_exception::error_changing_section_virtual_size); - - //Set virtual size equal to aligned size of raw data - s.set_virtual_size(s.get_size_of_raw_data()); - } - else - { - s.set_virtual_size(vsize); - } - - //Update image size if we're changing virtual size for the last section of this PE - if(!sections_.empty() || &s == &(*(sections_.end() - 1))) - update_image_size(); -} - -//Expands section raw or virtual size to hold data from specified RVA with specified size -//Section must be free (not bound to any image) -//or the last section of this image -bool pe_base::expand_section(section& s, uint32_t needed_rva, uint32_t needed_size, section_expand_type expand) -{ - //Check if we're changing the last section - //Of course, we can change the section that's not bound to this PE file - if(sections_.empty() || std::find_if(sections_.begin(), sections_.end() - 1, section_ptr_finder(s)) != sections_.end() - 1) - throw pe_exception("Can't expand any section, except last one", pe_exception::error_expanding_section); - - //Check if we should expand our section - if(expand == expand_section_raw && section_data_length_from_rva(s, needed_rva, section_data_raw) < needed_size) - { - //Expand section raw data - s.get_raw_data().resize(needed_rva - s.get_virtual_address() + needed_size); - recalculate_section_sizes(s, false); - return true; - } - else if(expand == expand_section_virtual && section_data_length_from_rva(s, needed_rva, section_data_virtual) < needed_size) - { - //Expand section virtual data - set_section_virtual_size(s, needed_rva - s.get_virtual_address() + needed_size); - return true; - } - - return false; -} - -//Updates image virtual size -void pe_base::update_image_size() -{ - //Write virtual size of image to headers - if(!sections_.empty()) - set_size_of_image(sections_.back().get_virtual_address() + sections_.back().get_aligned_virtual_size(get_section_alignment())); - else - set_size_of_image(get_size_of_headers()); -} - -//Returns checksum of PE file from header -uint32_t pe_base::get_checksum() const -{ - return props_->get_checksum(); -} - -//Sets checksum of PE file -void pe_base::set_checksum(uint32_t checksum) -{ - props_->set_checksum(checksum); -} - -//Returns timestamp of PE file from header -uint32_t pe_base::get_time_date_stamp() const -{ - return props_->get_time_date_stamp(); -} - -//Sets timestamp of PE file -void pe_base::set_time_date_stamp(uint32_t timestamp) -{ - props_->set_time_date_stamp(timestamp); -} - -//Returns Machine field value of PE file from header -uint16_t pe_base::get_machine() const -{ - return props_->get_machine(); -} - -//Sets Machine field value of PE file -void pe_base::set_machine(uint16_t machine) -{ - props_->set_machine(machine); -} - -//Prepares section before attaching it -void pe_base::prepare_section(section& s) -{ - //Calculate its size of raw data - s.set_size_of_raw_data(static_cast(pe_utils::align_up(s.get_raw_data().length(), get_file_alignment()))); - - //Check section virtual and raw size - if(!s.get_size_of_raw_data() && !s.get_virtual_size()) - throw pe_exception("Virtual and Physical sizes of section can't be 0 at the same time", pe_exception::zero_section_sizes); - - //If section virtual size is zero - if(!s.get_virtual_size()) - { - s.set_virtual_size(s.get_size_of_raw_data()); - } - else - { - //Else calculate its virtual size - s.set_virtual_size( - std::max(pe_utils::align_up(s.get_size_of_raw_data(), get_file_alignment()), - pe_utils::align_up(s.get_virtual_size(), get_section_alignment()))); - } -} - -//Adds section to image -section& pe_base::add_section(section s) -{ - if(sections_.size() >= maximum_number_of_sections) - throw pe_exception("Maximum number of sections has been reached", pe_exception::no_more_sections_can_be_added); - - //Prepare section before adding it - prepare_section(s); - - //Calculate section virtual address - if(!sections_.empty()) - { - s.set_virtual_address(pe_utils::align_up(sections_.back().get_virtual_address() + sections_.back().get_aligned_virtual_size(get_section_alignment()), get_section_alignment())); - - //We should align last section raw size, if it wasn't aligned - section& last = sections_.back(); - last.set_size_of_raw_data(static_cast(pe_utils::align_up(last.get_raw_data().length(), get_file_alignment()))); - } - else - { - s.set_virtual_address( - s.get_virtual_address() == 0 - ? pe_utils::align_up(get_size_of_headers(), get_section_alignment()) - : pe_utils::align_up(s.get_virtual_address(), get_section_alignment())); - } - - //Add section to the end of section list - sections_.push_back(s); - //Set number of sections in PE header - set_number_of_sections(static_cast(sections_.size())); - //Recalculate virtual size of image - set_size_of_image(get_size_of_image() + s.get_aligned_virtual_size(get_section_alignment())); - //Return last section - return sections_.back(); -} - -//Returns true if sectios "s" is already attached to this PE file -bool pe_base::section_attached(const section& s) const -{ - return sections_.end() != std::find_if(sections_.begin(), sections_.end(), section_ptr_finder(s)); -} - -//Returns true if directory exists -bool pe_base::directory_exists(uint32_t id) const -{ - return props_->directory_exists(id); -} - -//Removes directory -void pe_base::remove_directory(uint32_t id) -{ - props_->remove_directory(id); -} - -//Returns directory RVA -uint32_t pe_base::get_directory_rva(uint32_t id) const -{ - return props_->get_directory_rva(id); -} - -//Returns directory size -uint32_t pe_base::get_directory_size(uint32_t id) const -{ - return props_->get_directory_size(id); -} - -//Sets directory RVA (just a value of PE header, no moving occurs) -void pe_base::set_directory_rva(uint32_t id, uint32_t rva) -{ - return props_->set_directory_rva(id, rva); -} - -//Sets directory size (just a value of PE header, no moving occurs) -void pe_base::set_directory_size(uint32_t id, uint32_t size) -{ - return props_->set_directory_size(id, size); -} - -//Strips only zero DATA_DIRECTORY entries to count = min_count -//Returns resulting number of data directories -//strip_iat_directory - if true, even not empty IAT directory will be stripped -uint32_t pe_base::strip_data_directories(uint32_t min_count, bool strip_iat_directory) -{ - return props_->strip_data_directories(min_count, strip_iat_directory); -} - -//Returns true if image has import directory -bool pe_base::has_imports() const -{ - return directory_exists(image_directory_entry_import); -} - -//Returns true if image has export directory -bool pe_base::has_exports() const -{ - return directory_exists(image_directory_entry_export); -} - -//Returns true if image has resource directory -bool pe_base::has_resources() const -{ - return directory_exists(image_directory_entry_resource); -} - -//Returns true if image has security directory -bool pe_base::has_security() const -{ - return directory_exists(image_directory_entry_security); -} - -//Returns true if image has relocations -bool pe_base::has_reloc() const -{ - return directory_exists(image_directory_entry_basereloc) && !(get_characteristics() & image_file_relocs_stripped); -} - -//Returns true if image has TLS directory -bool pe_base::has_tls() const -{ - return directory_exists(image_directory_entry_tls); -} - -//Returns true if image has config directory -bool pe_base::has_config() const -{ - return directory_exists(image_directory_entry_load_config); -} - -//Returns true if image has bound import directory -bool pe_base::has_bound_import() const -{ - return directory_exists(image_directory_entry_bound_import); -} - -//Returns true if image has delay import directory -bool pe_base::has_delay_import() const -{ - return directory_exists(image_directory_entry_delay_import); -} - -//Returns true if image has COM directory -bool pe_base::is_dotnet() const -{ - return directory_exists(image_directory_entry_com_descriptor); -} - -//Returns true if image has exception directory -bool pe_base::has_exception_directory() const -{ - return directory_exists(image_directory_entry_exception); -} - -//Returns true if image has debug directory -bool pe_base::has_debug() const -{ - return directory_exists(image_directory_entry_debug); -} - -//Returns corresponding section data pointer from RVA inside section "s" (checks bounds) -char* pe_base::section_data_from_rva(section& s, uint32_t rva) -{ - //Check if RVA is inside section "s" - if(rva >= s.get_virtual_address() && rva < s.get_virtual_address() + s.get_aligned_virtual_size(get_section_alignment())) - { - if(s.get_raw_data().empty()) - throw pe_exception("Section raw data is empty and cannot be changed", pe_exception::section_is_empty); - - return &s.get_raw_data()[rva - s.get_virtual_address()]; - } - - throw pe_exception("RVA not found inside section", pe_exception::rva_not_exists); -} - -//Returns corresponding section data pointer from RVA inside section "s" (checks bounds) -const char* pe_base::section_data_from_rva(const section& s, uint32_t rva, section_data_type datatype) const -{ - //Check if RVA is inside section "s" - if(rva >= s.get_virtual_address() && rva < s.get_virtual_address() + s.get_aligned_virtual_size(get_section_alignment())) - return (datatype == section_data_raw ? s.get_raw_data().data() : s.get_virtual_data(get_section_alignment()).c_str()) + rva - s.get_virtual_address(); - - throw pe_exception("RVA not found inside section", pe_exception::rva_not_exists); -} - -//Returns section TOTAL RAW/VIRTUAL data length from RVA inside section -uint32_t pe_base::section_data_length_from_rva(uint32_t rva, section_data_type datatype, bool include_headers) const -{ - //if RVA is inside of headers and we're searching them too... - if(include_headers && rva < full_headers_data_.length()) - return static_cast(full_headers_data_.length()); - - const section& s = section_from_rva(rva); - return static_cast(datatype == section_data_raw ? s.get_raw_data().length() /* instead of SizeOfRawData */ : s.get_aligned_virtual_size(get_section_alignment())); -} - -//Returns section TOTAL RAW/VIRTUAL data length from VA inside section for PE32 -uint32_t pe_base::section_data_length_from_va(uint32_t va, section_data_type datatype, bool include_headers) const -{ - return section_data_length_from_rva(va_to_rva(va), datatype, include_headers); -} - -//Returns section TOTAL RAW/VIRTUAL data length from VA inside section for PE32/PE64 -uint32_t pe_base::section_data_length_from_va(uint64_t va, section_data_type datatype, bool include_headers) const -{ - return section_data_length_from_rva(va_to_rva(va), datatype, include_headers); -} - -//Returns section remaining RAW/VIRTUAL data length from RVA "rva_inside" to the end of section containing RVA "rva" -uint32_t pe_base::section_data_length_from_rva(uint32_t rva, uint32_t rva_inside, section_data_type datatype, bool include_headers) const -{ - //if RVAs are inside of headers and we're searching them too... - if(include_headers && rva < full_headers_data_.length() && rva_inside < full_headers_data_.length()) - return static_cast(full_headers_data_.length() - rva_inside); - - const section& s = section_from_rva(rva); - if(rva_inside < s.get_virtual_address()) - throw pe_exception("RVA not found inside section", pe_exception::rva_not_exists); - - //Calculate remaining length of section data from "rva" address - long length = static_cast(datatype == section_data_raw ? s.get_raw_data().length() /* instead of SizeOfRawData */ : s.get_aligned_virtual_size(get_section_alignment())) - + s.get_virtual_address() - rva_inside; - - if(length < 0) - return 0; - - return static_cast(length); -} - -//Returns section remaining RAW/VIRTUAL data length from VA "va_inside" to the end of section containing VA "va" for PE32 -uint32_t pe_base::section_data_length_from_va(uint32_t va, uint32_t va_inside, section_data_type datatype, bool include_headers) const -{ - return section_data_length_from_rva(va_to_rva(va), va_to_rva(va_inside), datatype, include_headers); -} - -//Returns section remaining RAW/VIRTUAL data length from VA "va_inside" to the end of section containing VA "va" for PE32/PE64 -uint32_t pe_base::section_data_length_from_va(uint64_t va, uint64_t va_inside, section_data_type datatype, bool include_headers) const -{ - return section_data_length_from_rva(va_to_rva(va), va_to_rva(va_inside), datatype, include_headers); -} - -//Returns section remaining RAW/VIRTUAL data length from RVA to the end of section "s" (checks bounds) -uint32_t pe_base::section_data_length_from_rva(const section& s, uint32_t rva_inside, section_data_type datatype) const -{ - //Check rva_inside - if(rva_inside >= s.get_virtual_address() && rva_inside < s.get_virtual_address() + s.get_aligned_virtual_size(get_section_alignment())) - { - //Calculate remaining length of section data from "rva" address - int32_t length = static_cast(datatype == section_data_raw ? s.get_raw_data().length() /* instead of SizeOfRawData */ : s.get_aligned_virtual_size(get_section_alignment())) - + s.get_virtual_address() - rva_inside; - - if(length < 0) - return 0; - - return static_cast(length); - } - - throw pe_exception("RVA not found inside section", pe_exception::rva_not_exists); -} - -//Returns section remaining RAW/VIRTUAL data length from VA to the end of section "s" for PE32 (checks bounds) -uint32_t pe_base::section_data_length_from_va(const section& s, uint32_t va_inside, section_data_type datatype) const -{ - return section_data_length_from_rva(s, va_to_rva(va_inside), datatype); -} - -//Returns section remaining RAW/VIRTUAL data length from VA to the end of section "s" for PE32/PE64 (checks bounds) -uint32_t pe_base::section_data_length_from_va(const section& s, uint64_t va_inside, section_data_type datatype) const -{ - return section_data_length_from_rva(s, va_to_rva(va_inside), datatype); -} - -//Returns corresponding section data pointer from RVA inside section -char* pe_base::section_data_from_rva(uint32_t rva, bool include_headers) -{ - //if RVA is inside of headers and we're searching them too... - if(include_headers && rva < full_headers_data_.length()) - return &full_headers_data_[rva]; - - section& s = section_from_rva(rva); - - if(s.get_raw_data().empty()) - throw pe_exception("Section raw data is empty and cannot be changed", pe_exception::section_is_empty); - - return &s.get_raw_data()[rva - s.get_virtual_address()]; -} - -//Returns corresponding section data pointer from RVA inside section -const char* pe_base::section_data_from_rva(uint32_t rva, section_data_type datatype, bool include_headers) const -{ - //if RVA is inside of headers and we're searching them too... - if(include_headers && rva < full_headers_data_.length()) - return &full_headers_data_[rva]; - - const section& s = section_from_rva(rva); - return (datatype == section_data_raw ? s.get_raw_data().data() : s.get_virtual_data(get_section_alignment()).c_str()) + rva - s.get_virtual_address(); -} - -//Reads DOS headers from istream -void pe_base::read_dos_header(std::istream& file, image_dos_header& header) -{ - //Check istream flags - if(file.bad() || file.eof()) - throw pe_exception("PE file stream is bad or closed.", pe_exception::bad_pe_file); - - //Read DOS header and check istream - file.read(reinterpret_cast(&header), sizeof(image_dos_header)); - if(file.bad() || file.eof()) - throw pe_exception("Unable to read IMAGE_DOS_HEADER", pe_exception::bad_dos_header); - - //Check DOS header magic - if(header.e_magic != 0x5a4d) //"MZ" - throw pe_exception("IMAGE_DOS_HEADER signature is incorrect", pe_exception::bad_dos_header); -} - -//Reads DOS headers from istream -void pe_base::read_dos_header(std::istream& file) -{ - read_dos_header(file, dos_header_); -} - -//Reads PE image from istream -void pe_base::read_pe(std::istream& file, bool read_debug_raw_data) -{ - //Get istream size - std::streamoff filesize = pe_utils::get_file_size(file); - - //Check if PE header is DWORD-aligned - if((dos_header_.e_lfanew % sizeof(uint32_t)) != 0) - throw pe_exception("PE header is not DWORD-aligned", pe_exception::bad_dos_header); - - //Seek to NT headers - file.seekg(dos_header_.e_lfanew); - if(file.bad() || file.fail()) - throw pe_exception("Cannot reach IMAGE_NT_HEADERS", pe_exception::image_nt_headers_not_found); - - //Read NT headers - file.read(get_nt_headers_ptr(), get_sizeof_nt_header() - sizeof(image_data_directory) * image_numberof_directory_entries); - if(file.bad() || file.eof()) - throw pe_exception("Error reading IMAGE_NT_HEADERS", pe_exception::error_reading_image_nt_headers); - - //Check PE signature - if(get_pe_signature() != 0x4550) //"PE" - throw pe_exception("Incorrect PE signature", pe_exception::pe_signature_incorrect); - - //Check number of directories - if(get_number_of_rvas_and_sizes() > image_numberof_directory_entries) - set_number_of_rvas_and_sizes(image_numberof_directory_entries); - - if(get_number_of_rvas_and_sizes() > 0) - { - //Read data directory headers, if any - file.read(get_nt_headers_ptr() + (get_sizeof_nt_header() - sizeof(image_data_directory) * image_numberof_directory_entries), sizeof(image_data_directory) * get_number_of_rvas_and_sizes()); - if(file.bad() || file.eof()) - throw pe_exception("Error reading DATA_DIRECTORY headers", pe_exception::error_reading_data_directories); - } - - //Check section number - //Images with zero section number accepted - if(get_number_of_sections() > maximum_number_of_sections) - throw pe_exception("Incorrect number of sections", pe_exception::section_number_incorrect); - - //Check PE magic - if(get_magic() != get_needed_magic()) - throw pe_exception("Incorrect PE signature", pe_exception::pe_signature_incorrect); - - //Check section alignment - if(!pe_utils::is_power_of_2(get_section_alignment())) - throw pe_exception("Incorrect section alignment", pe_exception::incorrect_section_alignment); - - //Check file alignment - if(!pe_utils::is_power_of_2(get_file_alignment())) - throw pe_exception("Incorrect file alignment", pe_exception::incorrect_file_alignment); - - if(get_file_alignment() != get_section_alignment() && (get_file_alignment() < minimum_file_alignment || get_file_alignment() > get_section_alignment())) - throw pe_exception("Incorrect file alignment", pe_exception::incorrect_file_alignment); - - //Check size of image - if(pe_utils::align_up(get_size_of_image(), get_section_alignment()) == 0) - throw pe_exception("Incorrect size of image", pe_exception::incorrect_size_of_image); - - //Read rich data overlay / DOS stub (if any) - if(static_cast(dos_header_.e_lfanew) > sizeof(image_dos_header)) - { - rich_overlay_.resize(dos_header_.e_lfanew - sizeof(image_dos_header)); - file.seekg(sizeof(image_dos_header)); - file.read(&rich_overlay_[0], dos_header_.e_lfanew - sizeof(image_dos_header)); - if(file.bad() || file.eof()) - throw pe_exception("Error reading 'Rich' & 'DOS stub' overlay", pe_exception::error_reading_overlay); - } - - //Calculate first section raw position - //Sum is safe here - uint32_t first_section = dos_header_.e_lfanew + get_size_of_optional_header() + sizeof(image_file_header) + sizeof(uint32_t) /* Signature */; - - if(get_number_of_sections() > 0) - { - //Go to first section - file.seekg(first_section); - if(file.bad() || file.fail()) - throw pe_exception("Cannot reach section headers", pe_exception::image_section_headers_not_found); - } - - uint32_t last_raw_size = 0; - - //Read all sections - for(int i = 0; i < get_number_of_sections(); i++) - { - section s; - //Read section header - file.read(reinterpret_cast(&s.get_raw_header()), sizeof(image_section_header)); - if(file.bad() || file.eof()) - throw pe_exception("Error reading section header", pe_exception::error_reading_section_header); - - //Save next section header position - std::streamoff next_sect = file.tellg(); - - //Check section virtual and raw sizes - if(!s.get_size_of_raw_data() && !s.get_virtual_size()) - throw pe_exception("Virtual and Physical sizes of section can't be 0 at the same time", pe_exception::zero_section_sizes); - - //Check for adequate values of section fields - if(!pe_utils::is_sum_safe(s.get_virtual_address(), s.get_virtual_size()) || s.get_virtual_size() > pe_utils::two_gb - || !pe_utils::is_sum_safe(s.get_pointer_to_raw_data(), s.get_size_of_raw_data()) || s.get_size_of_raw_data() > pe_utils::two_gb) - throw pe_exception("Incorrect section address or size", pe_exception::section_incorrect_addr_or_size); - - if(s.get_size_of_raw_data() != 0) - { - //If section has raw data - - //If section raw data size is greater than virtual, fix it - last_raw_size = s.get_size_of_raw_data(); - if(pe_utils::align_up(s.get_size_of_raw_data(), get_file_alignment()) > pe_utils::align_up(s.get_virtual_size(), get_section_alignment())) - s.set_size_of_raw_data(s.get_virtual_size()); - - //Check virtual and raw section sizes and addresses - if(s.get_virtual_address() + pe_utils::align_up(s.get_virtual_size(), get_section_alignment()) > pe_utils::align_up(get_size_of_image(), get_section_alignment()) - || - pe_utils::align_down(s.get_pointer_to_raw_data(), get_file_alignment()) + s.get_size_of_raw_data() > static_cast(filesize)) - throw pe_exception("Incorrect section address or size", pe_exception::section_incorrect_addr_or_size); - - //Seek to section raw data - file.seekg(pe_utils::align_down(s.get_pointer_to_raw_data(), get_file_alignment())); - if(file.bad() || file.fail()) - throw pe_exception("Cannot reach section data", pe_exception::image_section_data_not_found); - - //Read section raw data - s.get_raw_data().resize(s.get_size_of_raw_data()); - file.read(&s.get_raw_data()[0], s.get_size_of_raw_data()); - if(file.bad() || file.fail()) - throw pe_exception("Error reading section data", pe_exception::image_section_data_not_found); - } - - //Check virtual address and size of section - if(s.get_virtual_address() + s.get_aligned_virtual_size(get_section_alignment()) > pe_utils::align_up(get_size_of_image(), get_section_alignment())) - throw pe_exception("Incorrect section address or size", pe_exception::section_incorrect_addr_or_size); - - //Save section - sections_.push_back(s); - - //Seek to the next section header - file.seekg(next_sect); - } - - //Check size of headers: SizeOfHeaders can't be larger than first section VA - if(!sections_.empty() && get_size_of_headers() > sections_.front().get_virtual_address()) - throw pe_exception("Incorrect size of headers", pe_exception::incorrect_size_of_headers); - - //If image has more than two sections - if(sections_.size() >= 2) - { - //Check sections virtual sizes - for(section_list::const_iterator i = sections_.begin() + 1; i != sections_.end(); ++i) - { - if((*i).get_virtual_address() != (*(i - 1)).get_virtual_address() + (*(i - 1)).get_aligned_virtual_size(get_section_alignment())) - throw pe_exception("Section table is incorrect", pe_exception::image_section_table_incorrect); - } - } - - //Check if image has overlay in the end of file - has_overlay_ = !sections_.empty() && filesize > static_cast(sections_.back().get_pointer_to_raw_data() + last_raw_size); - - { - //Additionally, read data from the beginning of istream to size of headers - file.seekg(0); - uint32_t size_of_headers = std::min(get_size_of_headers(), static_cast(filesize)); - - if(!sections_.empty()) - { - for(section_list::const_iterator i = sections_.begin(); i != sections_.end(); ++i) - { - if(!(*i).empty()) - { - size_of_headers = std::min(get_size_of_headers(), (*i).get_pointer_to_raw_data()); - break; - } - } - } - - full_headers_data_.resize(size_of_headers); - file.read(&full_headers_data_[0], size_of_headers); - if(file.bad() || file.eof()) - throw pe_exception("Error reading file", pe_exception::error_reading_file); - } - - //Moreover, if there's debug directory, read its raw data for some debug info types - while(read_debug_raw_data && has_debug()) - { - try - { - //Check the length in bytes of the section containing debug directory - if(section_data_length_from_rva(get_directory_rva(image_directory_entry_debug), get_directory_rva(image_directory_entry_debug), section_data_virtual, true) < sizeof(image_debug_directory)) - break; - - unsigned long current_pos = get_directory_rva(image_directory_entry_debug); - - //First IMAGE_DEBUG_DIRECTORY table - image_debug_directory directory = section_data_from_rva(current_pos, section_data_virtual, true); - - //Iterate over all IMAGE_DEBUG_DIRECTORY directories - while(directory.PointerToRawData - && current_pos < get_directory_rva(image_directory_entry_debug) + get_directory_size(image_directory_entry_debug)) - { - //If we have something to read - if((directory.Type == image_debug_type_codeview - || directory.Type == image_debug_type_misc - || directory.Type == image_debug_type_coff) - && directory.SizeOfData) - { - std::string data; - data.resize(directory.SizeOfData); - file.seekg(directory.PointerToRawData); - file.read(&data[0], directory.SizeOfData); - if(file.bad() || file.eof()) - throw pe_exception("Error reading file", pe_exception::error_reading_file); - - debug_data_.insert(std::make_pair(directory.PointerToRawData, data)); - } - - //Go to next debug entry - current_pos += sizeof(image_debug_directory); - directory = section_data_from_rva(current_pos, section_data_virtual, true); - } - - break; - } - catch(const pe_exception&) - { - //Don't throw any exception here, if debug info is corrupted or incorrect - break; - } - catch(const std::bad_alloc&) - { - //Don't throw any exception here, if debug info is corrupted or incorrect - break; - } - } -} - -//Returns PE type of this image -pe_type pe_base::get_pe_type() const -{ - return props_->get_pe_type(); -} - -//Returns PE type (PE or PE+) from pe_type enumeration (minimal correctness checks) -pe_type pe_base::get_pe_type(std::istream& file) -{ - //Save state of the istream - std::ios_base::iostate state = file.exceptions(); - std::streamoff old_offset = file.tellg(); - image_nt_headers32 nt_headers; - image_dos_header header; - - try - { - //Read dos header - file.exceptions(std::ios::goodbit); - read_dos_header(file, header); - - //Seek to the NT headers start - file.seekg(header.e_lfanew); - if(file.bad() || file.fail()) - throw pe_exception("Cannot reach IMAGE_NT_HEADERS", pe_exception::image_nt_headers_not_found); - - //Read NT headers (we're using 32-bit version, because there's no significant differencies between 32 and 64 bit version structures) - file.read(reinterpret_cast(&nt_headers), sizeof(image_nt_headers32) - sizeof(image_data_directory) * image_numberof_directory_entries); - if(file.bad() || file.eof()) - throw pe_exception("Error reading IMAGE_NT_HEADERS", pe_exception::error_reading_image_nt_headers); - - //Check NT headers signature - if(nt_headers.Signature != 0x4550) //"PE" - throw pe_exception("Incorrect PE signature", pe_exception::pe_signature_incorrect); - - //Check NT headers magic - if(nt_headers.OptionalHeader.Magic != image_nt_optional_hdr32_magic && nt_headers.OptionalHeader.Magic != image_nt_optional_hdr64_magic) - throw pe_exception("Incorrect PE signature", pe_exception::pe_signature_incorrect); - } - catch(const std::exception&) - { - //If something went wrong, restore istream state - file.exceptions(state); - file.seekg(old_offset); - file.clear(); - //Retrhow exception - throw; - } - - //Restore stream state - file.exceptions(state); - file.seekg(old_offset); - file.clear(); - - //Determine PE type and return it - return nt_headers.OptionalHeader.Magic == image_nt_optional_hdr64_magic ? pe_type_64 : pe_type_32; -} - -//Returns true if image has overlay data at the end of file -bool pe_base::has_overlay() const -{ - return has_overlay_; -} - -//Clears PE characteristics flag -void pe_base::clear_characteristics_flags(uint16_t flags) -{ - set_characteristics(get_characteristics() & ~flags); -} - -//Sets PE characteristics flag -void pe_base::set_characteristics_flags(uint16_t flags) -{ - set_characteristics(get_characteristics() | flags); -} - -//Returns true if PE characteristics flag set -bool pe_base::check_characteristics_flag(uint16_t flag) const -{ - return (get_characteristics() & flag) ? true : false; -} - -//Returns subsystem value -uint16_t pe_base::get_subsystem() const -{ - return props_->get_subsystem(); -} - -//Sets subsystem value -void pe_base::set_subsystem(uint16_t subsystem) -{ - props_->set_subsystem(subsystem); -} - -//Returns true if image has console subsystem -bool pe_base::is_console() const -{ - return get_subsystem() == image_subsystem_windows_cui; -} - -//Returns true if image has Windows GUI subsystem -bool pe_base::is_gui() const -{ - return get_subsystem() == image_subsystem_windows_gui; -} - -//Sets required operation system version -void pe_base::set_os_version(uint16_t major, uint16_t minor) -{ - props_->set_os_version(major, minor); -} - -//Returns required operation system version (minor word) -uint16_t pe_base::get_minor_os_version() const -{ - return props_->get_minor_os_version(); -} - -//Returns required operation system version (major word) -uint16_t pe_base::get_major_os_version() const -{ - return props_->get_major_os_version(); -} - -//Sets required subsystem version -void pe_base::set_subsystem_version(uint16_t major, uint16_t minor) -{ - props_->set_subsystem_version(major, minor); -} - -//Returns required subsystem version (minor word) -uint16_t pe_base::get_minor_subsystem_version() const -{ - return props_->get_minor_subsystem_version(); -} - -//Returns required subsystem version (major word) -uint16_t pe_base::get_major_subsystem_version() const -{ - return props_->get_major_subsystem_version(); -} - -//Returns corresponding section data pointer from VA inside section "s" for PE32 (checks bounds) -char* pe_base::section_data_from_va(section& s, uint32_t va) //Always returns raw data -{ - return section_data_from_rva(s, va_to_rva(va)); -} - -//Returns corresponding section data pointer from VA inside section "s" for PE32 (checks bounds) -const char* pe_base::section_data_from_va(const section& s, uint32_t va, section_data_type datatype) const -{ - return section_data_from_rva(s, va_to_rva(va), datatype); -} - -//Returns corresponding section data pointer from VA inside section for PE32 -char* pe_base::section_data_from_va(uint32_t va, bool include_headers) //Always returns raw data -{ - return section_data_from_rva(va_to_rva(va), include_headers); -} - -//Returns corresponding section data pointer from VA inside section for PE32 -const char* pe_base::section_data_from_va(uint32_t va, section_data_type datatype, bool include_headers) const -{ - return section_data_from_rva(va_to_rva(va), datatype, include_headers); -} - -//Returns corresponding section data pointer from VA inside section "s" for PE32/PE64 (checks bounds) -char* pe_base::section_data_from_va(section& s, uint64_t va) //Always returns raw data -{ - return section_data_from_rva(s, va_to_rva(va)); -} - -//Returns corresponding section data pointer from VA inside section "s" for PE32/PE64 (checks bounds) -const char* pe_base::section_data_from_va(const section& s, uint64_t va, section_data_type datatype) const -{ - return section_data_from_rva(s, va_to_rva(va), datatype); -} - -//Returns corresponding section data pointer from VA inside section for PE32/PE64 -char* pe_base::section_data_from_va(uint64_t va, bool include_headers) //Always returns raw data -{ - return section_data_from_rva(va_to_rva(va), include_headers); -} - -//Returns corresponding section data pointer from VA inside section for PE32/PE64 -const char* pe_base::section_data_from_va(uint64_t va, section_data_type datatype, bool include_headers) const -{ - return section_data_from_rva(va_to_rva(va), datatype, include_headers); -} - -//Returns section from VA inside it for PE32 -section& pe_base::section_from_va(uint32_t va) -{ - return section_from_rva(va_to_rva(va)); -} - -//Returns section from VA inside it for PE32/PE64 -section& pe_base::section_from_va(uint64_t va) -{ - return section_from_rva(va_to_rva(va)); -} - -//Returns section from RVA inside it for PE32 -const section& pe_base::section_from_va(uint32_t va) const -{ - return section_from_rva(va_to_rva(va)); -} - -//Returns section from RVA inside it for PE32/PE64 -const section& pe_base::section_from_va(uint64_t va) const -{ - return section_from_rva(va_to_rva(va)); -} - -uint32_t pe_base::va_to_rva(uint32_t va, bool bound_check) const -{ - return props_->va_to_rva(va, bound_check); -} - -uint32_t pe_base::va_to_rva(uint64_t va, bool bound_check) const -{ - return props_->va_to_rva(va, bound_check); -} - -uint32_t pe_base::rva_to_va_32(uint32_t rva) const -{ - return props_->rva_to_va_32(rva); -} - -uint64_t pe_base::rva_to_va_64(uint32_t rva) const -{ - return props_->rva_to_va_64(rva); -} - -//Relative Virtual Address (RVA) to Virtual Address (VA) convertion for PE32 -void pe_base::rva_to_va(uint32_t rva, uint32_t& va) const -{ - va = rva_to_va_32(rva); -} - -//Relative Virtual Address (RVA) to Virtual Address (VA) convertions for PE32/PE64 -void pe_base::rva_to_va(uint32_t rva, uint64_t& va) const -{ - va = rva_to_va_64(rva); -} - -//Returns section from file offset (4gb max) -section& pe_base::section_from_file_offset(uint32_t offset) -{ - return *file_offset_to_section(offset); -} - -//Returns section from file offset (4gb max) -const section& pe_base::section_from_file_offset(uint32_t offset) const -{ - return *file_offset_to_section(offset); -} - -//Returns section and offset (raw data only) from its start from RVA -const std::pair pe_base::section_and_offset_from_rva(uint32_t rva) const -{ - const section& s = section_from_rva(rva); - return std::make_pair(rva - s.get_virtual_address(), &s); -} - -//Returns DLL Characteristics -uint16_t pe_base::get_dll_characteristics() const -{ - return props_->get_dll_characteristics(); -} - -//Sets DLL Characteristics -void pe_base::set_dll_characteristics(uint16_t characteristics) -{ - props_->set_dll_characteristics(characteristics); -} - -//Returns size of headers -uint32_t pe_base::get_size_of_headers() const -{ - return props_->get_size_of_headers(); -} - -//Returns size of optional header -uint16_t pe_base::get_size_of_optional_header() const -{ - return props_->get_size_of_optional_header(); -} - -//Returns PE signature -uint32_t pe_base::get_pe_signature() const -{ - return props_->get_pe_signature(); -} - -//Returns magic value -uint32_t pe_base::get_magic() const -{ - return props_->get_magic(); -} - -//Returns image base for PE32 -void pe_base::get_image_base(uint32_t& base) const -{ - base = get_image_base_32(); -} - -//Returns image base for PE32 and PE64 respectively -uint32_t pe_base::get_image_base_32() const -{ - return props_->get_image_base_32(); -} - -//Sets image base for PE32 and PE64 respectively -uint64_t pe_base::get_image_base_64() const -{ - return props_->get_image_base_64(); -} - -//RVA to RAW file offset convertion (4gb max) -uint32_t pe_base::rva_to_file_offset(uint32_t rva) const -{ - //Maybe, RVA is inside PE headers - if(rva < get_size_of_headers()) - return rva; - - const section& s = section_from_rva(rva); - return s.get_pointer_to_raw_data() + rva - s.get_virtual_address(); -} - -//RAW file offset to RVA convertion (4gb max) -uint32_t pe_base::file_offset_to_rva(uint32_t offset) const -{ - //Maybe, offset is inside PE headers - if(offset < get_size_of_headers()) - return offset; - - const section_list::const_iterator it = file_offset_to_section(offset); - return offset - (*it).get_pointer_to_raw_data() + (*it).get_virtual_address(); -} - -//RAW file offset to section convertion helper (4gb max) -section_list::const_iterator pe_base::file_offset_to_section(uint32_t offset) const -{ - section_list::const_iterator it = std::find_if(sections_.begin(), sections_.end(), section_by_raw_offset(offset)); - if(it == sections_.end()) - throw pe_exception("No section found by presented file offset", pe_exception::no_section_found); - - return it; -} - -//RAW file offset to section convertion helper (4gb max) -section_list::iterator pe_base::file_offset_to_section(uint32_t offset) -{ - section_list::iterator it = std::find_if(sections_.begin(), sections_.end(), section_by_raw_offset(offset)); - if(it == sections_.end()) - throw pe_exception("No section found by presented file offset", pe_exception::no_section_found); - - return it; -} - -//RVA from section raw data offset -uint32_t pe_base::rva_from_section_offset(const section& s, uint32_t raw_offset_from_section_start) -{ - return s.get_virtual_address() + raw_offset_from_section_start; -} - -//Returns image base for PE32/PE64 -void pe_base::get_image_base(uint64_t& base) const -{ - base = get_image_base_64(); -} - -//Sets new image base -void pe_base::set_image_base(uint32_t base) -{ - props_->set_image_base(base); -} - -void pe_base::set_image_base_64(uint64_t base) -{ - props_->set_image_base_64(base); -} - -//Sets heap size commit for PE32 and PE64 respectively -void pe_base::set_heap_size_commit(uint32_t size) -{ - props_->set_heap_size_commit(size); -} - -void pe_base::set_heap_size_commit(uint64_t size) -{ - props_->set_heap_size_commit(size); -} - -//Sets heap size reserve for PE32 and PE64 respectively -void pe_base::set_heap_size_reserve(uint32_t size) -{ - props_->set_heap_size_reserve(size); -} - -void pe_base::set_heap_size_reserve(uint64_t size) -{ - props_->set_heap_size_reserve(size); -} - -//Sets stack size commit for PE32 and PE64 respectively -void pe_base::set_stack_size_commit(uint32_t size) -{ - props_->set_stack_size_commit(size); -} - -void pe_base::set_stack_size_commit(uint64_t size) -{ - props_->set_stack_size_commit(size); -} - -//Sets stack size reserve for PE32 and PE64 respectively -void pe_base::set_stack_size_reserve(uint32_t size) -{ - props_->set_stack_size_reserve(size); -} - -void pe_base::set_stack_size_reserve(uint64_t size) -{ - props_->set_stack_size_reserve(size); -} - -//Returns heap size commit for PE32 and PE64 respectively -uint32_t pe_base::get_heap_size_commit_32() const -{ - return props_->get_heap_size_commit_32(); -} - -uint64_t pe_base::get_heap_size_commit_64() const -{ - return props_->get_heap_size_commit_64(); -} - -//Returns heap size reserve for PE32 and PE64 respectively -uint32_t pe_base::get_heap_size_reserve_32() const -{ - return props_->get_heap_size_reserve_32(); -} - -uint64_t pe_base::get_heap_size_reserve_64() const -{ - return props_->get_heap_size_reserve_64(); -} - -//Returns stack size commit for PE32 and PE64 respectively -uint32_t pe_base::get_stack_size_commit_32() const -{ - return props_->get_stack_size_commit_32(); -} - -uint64_t pe_base::get_stack_size_commit_64() const -{ - return props_->get_stack_size_commit_64(); -} - -//Returns stack size reserve for PE32 and PE64 respectively -uint32_t pe_base::get_stack_size_reserve_32() const -{ - return props_->get_stack_size_reserve_32(); -} - -uint64_t pe_base::get_stack_size_reserve_64() const -{ - return props_->get_stack_size_reserve_64(); -} - -//Returns heap size commit for PE32 -void pe_base::get_heap_size_commit(uint32_t& size) const -{ - size = get_heap_size_commit_32(); -} - -//Returns heap size commit for PE32/PE64 -void pe_base::get_heap_size_commit(uint64_t& size) const -{ - size = get_heap_size_commit_64(); -} - -//Returns heap size reserve for PE32 -void pe_base::get_heap_size_reserve(uint32_t& size) const -{ - size = get_heap_size_reserve_32(); -} - -//Returns heap size reserve for PE32/PE64 -void pe_base::get_heap_size_reserve(uint64_t& size) const -{ - size = get_heap_size_reserve_64(); -} - -//Returns stack size commit for PE32 -void pe_base::get_stack_size_commit(uint32_t& size) const -{ - size = get_stack_size_commit_32(); -} - -//Returns stack size commit for PE32/PE64 -void pe_base::get_stack_size_commit(uint64_t& size) const -{ - size = get_stack_size_commit_64(); -} - -//Returns stack size reserve for PE32 -void pe_base::get_stack_size_reserve(uint32_t& size) const -{ - size = get_stack_size_reserve_32(); -} - -//Returns stack size reserve for PE32/PE64 -void pe_base::get_stack_size_reserve(uint64_t& size) const -{ - size = get_stack_size_reserve_64(); -} - -//Realigns file (changes file alignment) -void pe_base::realign_file(uint32_t new_file_alignment) -{ - //Checks alignment for correctness - set_file_alignment(new_file_alignment); - realign_all_sections(); -} - -//Helper function to recalculate RAW and virtual section sizes and strip it, if necessary -void pe_base::recalculate_section_sizes(section& s, bool auto_strip) -{ - prepare_section(s); //Recalculate section raw addresses - - //Strip RAW size of section, if it is the last one - //For all others it must be file-aligned and calculated by prepare_section() call - if(auto_strip && !(sections_.empty() || &s == &*(sections_.end() - 1))) - { - //Strip ending raw data nullbytes to optimize size - std::string& raw_data = s.get_raw_data(); - if(!raw_data.empty()) - { - std::string::size_type i = raw_data.length(); - for(; i != 1; --i) - { - if(raw_data[i - 1] != 0) - break; - } - - raw_data.resize(i); - } - - s.set_size_of_raw_data(static_cast(raw_data.length())); - } - - //Can occur only for last section - if(pe_utils::align_up(s.get_virtual_size(), get_section_alignment()) < pe_utils::align_up(s.get_size_of_raw_data(), get_file_alignment())) - set_section_virtual_size(s, pe_utils::align_up(s.get_size_of_raw_data(), get_section_alignment())); //Recalculate section virtual size -} - -//Returns data from the beginning of image -//Size = SizeOfHeaders -const std::string& pe_base::get_full_headers_data() const -{ - return full_headers_data_; -} - -const pe_base::debug_data_list& pe_base::get_raw_debug_data_list() const -{ - return debug_data_; -} - -//Sets number of sections -void pe_base::set_number_of_sections(uint16_t number) -{ - props_->set_number_of_sections(number); -} - -//Sets size of image -void pe_base::set_size_of_image(uint32_t size) -{ - props_->set_size_of_image(size); -} - -//Sets size of headers -void pe_base::set_size_of_headers(uint32_t size) -{ - props_->set_size_of_headers(size); -} - -//Sets size of optional headers -void pe_base::set_size_of_optional_header(uint16_t size) -{ - props_->set_size_of_optional_header(size); -} - -//Returns nt headers data pointer -char* pe_base::get_nt_headers_ptr() -{ - return props_->get_nt_headers_ptr(); -} - -//Returns nt headers data pointer -const char* pe_base::get_nt_headers_ptr() const -{ - return props_->get_nt_headers_ptr(); -} - -//Returns sizeof() nt headers -uint32_t pe_base::get_sizeof_nt_header() const -{ - return props_->get_sizeof_nt_header(); -} - -//Returns sizeof() optional headers -uint32_t pe_base::get_sizeof_opt_headers() const -{ - return props_->get_sizeof_opt_headers(); -} - -//Sets file alignment (no checks) -void pe_base::set_file_alignment_unchecked(uint32_t alignment) -{ - props_->set_file_alignment_unchecked(alignment); -} - -//Sets base of code -void pe_base::set_base_of_code(uint32_t base) -{ - props_->set_base_of_code(base); -} - -//Returns base of code -uint32_t pe_base::get_base_of_code() const -{ - return props_->get_base_of_code(); -} - -//Returns needed magic of image -uint32_t pe_base::get_needed_magic() const -{ - return props_->get_needed_magic(); -} -} diff --git a/drivers/pe_bliss/pe_base.h b/drivers/pe_bliss/pe_base.h deleted file mode 100644 index a84faf547c..0000000000 --- a/drivers/pe_bliss/pe_base.h +++ /dev/null @@ -1,523 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include "pe_exception.h" -#include "pe_structures.h" -#include "utils.h" -#include "pe_section.h" -#include "pe_properties.h" - -//Please don't remove this information from header -//PEBliss 1.0.0 -//(c) DX 2011 - 2012, http://kaimi.ru -//Free to use for commertial and non-commertial purposes, modification and distribution - -// == more important == -//TODO: compact import rebuilder -//TODO: remove sections in the middle -//== less important == -//TODO: relocations that take more than one element (seems to be not possible in Windows PE, but anyway) -//TODO: delay import directory -//TODO: write message tables -//TODO: write string tables -//TODO: read security information -//TODO: read full .NET information - -namespace pe_bliss -{ -//Portable executable class -class pe_base -{ -public: //CONSTRUCTORS - //Constructor from stream - pe_base(std::istream& file, const pe_properties& props, bool read_debug_raw_data = true); - - //Constructor of empty PE-file - explicit pe_base(const pe_properties& props, uint32_t section_alignment = 0x1000, bool dll = false, uint16_t subsystem = pe_win::image_subsystem_windows_gui); - - pe_base(const pe_base& pe); - pe_base& operator=(const pe_base& pe); - -public: - ~pe_base(); - -public: //STUB - //Strips stub MSVS overlay, if any - void strip_stub_overlay(); - //Fills stub MSVS overlay with specified byte - void fill_stub_overlay(char c); - //Sets stub MSVS overlay - void set_stub_overlay(const std::string& data); - //Returns stub overlay contents - const std::string& get_stub_overlay() const; - - -public: //DIRECTORIES - //Returns true if directory exists - bool directory_exists(uint32_t id) const; - //Removes directory - void remove_directory(uint32_t id); - - //Returns directory RVA - uint32_t get_directory_rva(uint32_t id) const; - //Returns directory size - uint32_t get_directory_size(uint32_t id) const; - - //Sets directory RVA (just a value of PE header, no moving occurs) - void set_directory_rva(uint32_t id, uint32_t rva); - //Sets directory size (just a value of PE header, no moving occurs) - void set_directory_size(uint32_t id, uint32_t size); - - //Strips only zero DATA_DIRECTORY entries to count = min_count - //Returns resulting number of data directories - //strip_iat_directory - if true, even not empty IAT directory will be stripped - uint32_t strip_data_directories(uint32_t min_count = 1, bool strip_iat_directory = true); - - //Returns true if image has import directory - bool has_imports() const; - //Returns true if image has export directory - bool has_exports() const; - //Returns true if image has resource directory - bool has_resources() const; - //Returns true if image has security directory - bool has_security() const; - //Returns true if image has relocations - bool has_reloc() const; - //Returns true if image has TLS directory - bool has_tls() const; - //Returns true if image has config directory - bool has_config() const; - //Returns true if image has bound import directory - bool has_bound_import() const; - //Returns true if image has delay import directory - bool has_delay_import() const; - //Returns true if image has COM directory - bool is_dotnet() const; - //Returns true if image has exception directory - bool has_exception_directory() const; - //Returns true if image has debug directory - bool has_debug() const; - - //Returns subsystem value - uint16_t get_subsystem() const; - //Sets subsystem value - void set_subsystem(uint16_t subsystem); - //Returns true if image has console subsystem - bool is_console() const; - //Returns true if image has Windows GUI subsystem - bool is_gui() const; - - //Sets required operation system version - void set_os_version(uint16_t major, uint16_t minor); - //Returns required operation system version (minor word) - uint16_t get_minor_os_version() const; - //Returns required operation system version (major word) - uint16_t get_major_os_version() const; - - //Sets required subsystem version - void set_subsystem_version(uint16_t major, uint16_t minor); - //Returns required subsystem version (minor word) - uint16_t get_minor_subsystem_version() const; - //Returns required subsystem version (major word) - uint16_t get_major_subsystem_version() const; - -public: //PE HEADER - //Returns DOS header - const pe_win::image_dos_header& get_dos_header() const; - pe_win::image_dos_header& get_dos_header(); - - //Returns PE header start (e_lfanew) - int32_t get_pe_header_start() const; - - //Returns file alignment - uint32_t get_file_alignment() const; - //Sets file alignment, checking the correctness of its value - void set_file_alignment(uint32_t alignment); - - //Returns size of image - uint32_t get_size_of_image() const; - - //Returns image entry point - uint32_t get_ep() const; - //Sets image entry point (just a value of PE header) - void set_ep(uint32_t new_ep); - - //Returns number of RVA and sizes (number of DATA_DIRECTORY entries) - uint32_t get_number_of_rvas_and_sizes() const; - //Sets number of RVA and sizes (number of DATA_DIRECTORY entries) - void set_number_of_rvas_and_sizes(uint32_t number); - - //Returns PE characteristics - uint16_t get_characteristics() const; - //Sets PE characteristics (a value inside header) - void set_characteristics(uint16_t ch); - //Clears PE characteristics flag - void clear_characteristics_flags(uint16_t flags); - //Sets PE characteristics flag - void set_characteristics_flags(uint16_t flags); - //Returns true if PE characteristics flag set - bool check_characteristics_flag(uint16_t flag) const; - - //Returns DLL Characteristics - uint16_t get_dll_characteristics() const; - //Sets DLL Characteristics - void set_dll_characteristics(uint16_t characteristics); - - //Returns size of headers - uint32_t get_size_of_headers() const; - //Returns size of optional header - uint16_t get_size_of_optional_header() const; - - //Returns PE signature - uint32_t get_pe_signature() const; - - //Returns magic value - uint32_t get_magic() const; - - //Returns image base for PE32 and PE64 respectively - uint32_t get_image_base_32() const; - void get_image_base(uint32_t& base) const; - //Sets image base for PE32 and PE64 respectively - uint64_t get_image_base_64() const; - void get_image_base(uint64_t& base) const; - - //Sets new image base - void set_image_base(uint32_t base); - void set_image_base_64(uint64_t base); - - //Sets heap size commit for PE32 and PE64 respectively - void set_heap_size_commit(uint32_t size); - void set_heap_size_commit(uint64_t size); - //Sets heap size reserve for PE32 and PE64 respectively - void set_heap_size_reserve(uint32_t size); - void set_heap_size_reserve(uint64_t size); - //Sets stack size commit for PE32 and PE64 respectively - void set_stack_size_commit(uint32_t size); - void set_stack_size_commit(uint64_t size); - //Sets stack size reserve for PE32 and PE64 respectively - void set_stack_size_reserve(uint32_t size); - void set_stack_size_reserve(uint64_t size); - - //Returns heap size commit for PE32 and PE64 respectively - uint32_t get_heap_size_commit_32() const; - void get_heap_size_commit(uint32_t& size) const; - uint64_t get_heap_size_commit_64() const; - void get_heap_size_commit(uint64_t& size) const; - //Returns heap size reserve for PE32 and PE64 respectively - uint32_t get_heap_size_reserve_32() const; - void get_heap_size_reserve(uint32_t& size) const; - uint64_t get_heap_size_reserve_64() const; - void get_heap_size_reserve(uint64_t& size) const; - //Returns stack size commit for PE32 and PE64 respectively - uint32_t get_stack_size_commit_32() const; - void get_stack_size_commit(uint32_t& size) const; - uint64_t get_stack_size_commit_64() const; - void get_stack_size_commit(uint64_t& size) const; - //Returns stack size reserve for PE32 and PE64 respectively - uint32_t get_stack_size_reserve_32() const; - void get_stack_size_reserve(uint32_t& size) const; - uint64_t get_stack_size_reserve_64() const; - void get_stack_size_reserve(uint64_t& size) const; - - //Updates virtual size of image corresponding to section virtual sizes - void update_image_size(); - - //Returns checksum of PE file from header - uint32_t get_checksum() const; - //Sets checksum of PE file - void set_checksum(uint32_t checksum); - - //Returns timestamp of PE file from header - uint32_t get_time_date_stamp() const; - //Sets timestamp of PE file - void set_time_date_stamp(uint32_t timestamp); - - //Returns Machine field value of PE file from header - uint16_t get_machine() const; - //Sets Machine field value of PE file - void set_machine(uint16_t machine); - - //Returns data from the beginning of image - //Size = SizeOfHeaders - const std::string& get_full_headers_data() const; - - typedef std::multimap debug_data_list; - //Returns raw list of debug data - const debug_data_list& get_raw_debug_data_list() const; - - //Reads and checks DOS header - static void read_dos_header(std::istream& file, pe_win::image_dos_header& header); - - //Returns sizeof() nt headers - uint32_t get_sizeof_nt_header() const; - //Returns sizeof() optional headers - uint32_t get_sizeof_opt_headers() const; - //Returns raw nt headers data pointer - const char* get_nt_headers_ptr() const; - - //Sets size of headers (to NT headers) - void set_size_of_headers(uint32_t size); - //Sets size of optional headers (to NT headers) - void set_size_of_optional_header(uint16_t size); - - //Sets base of code - void set_base_of_code(uint32_t base); - //Returns base of code - uint32_t get_base_of_code() const; - -public: //ADDRESS CONVERTIONS - //Virtual Address (VA) to Relative Virtual Address (RVA) convertions - //for PE32 and PE64 respectively - //bound_check checks integer overflow - uint32_t va_to_rva(uint32_t va, bool bound_check = true) const; - uint32_t va_to_rva(uint64_t va, bool bound_check = true) const; - - //Relative Virtual Address (RVA) to Virtual Address (VA) convertions - //for PE32 and PE64 respectively - uint32_t rva_to_va_32(uint32_t rva) const; - void rva_to_va(uint32_t rva, uint32_t& va) const; - uint64_t rva_to_va_64(uint32_t rva) const; - void rva_to_va(uint32_t rva, uint64_t& va) const; - - //RVA to RAW file offset convertion (4gb max) - uint32_t rva_to_file_offset(uint32_t rva) const; - //RAW file offset to RVA convertion (4gb max) - uint32_t file_offset_to_rva(uint32_t offset) const; - - //RVA from section raw data offset - static uint32_t rva_from_section_offset(const section& s, uint32_t raw_offset_from_section_start); - -public: //IMAGE SECTIONS - //Returns number of sections from PE header - uint16_t get_number_of_sections() const; - - //Updates number of sections in PE header - uint16_t update_number_of_sections(); - - //Returns section alignment - uint32_t get_section_alignment() const; - - //Returns section list - section_list& get_image_sections(); - const section_list& get_image_sections() const; - - //Realigns all sections, if you made any changes to sections or alignments - void realign_all_sections(); - //Resligns section with specified index - void realign_section(uint32_t index); - - //Returns section from RVA inside it - section& section_from_rva(uint32_t rva); - const section& section_from_rva(uint32_t rva) const; - //Returns section from directory ID - section& section_from_directory(uint32_t directory_id); - const section& section_from_directory(uint32_t directory_id) const; - //Returns section from VA inside it for PE32 and PE64 respectively - section& section_from_va(uint32_t va); - const section& section_from_va(uint32_t va) const; - section& section_from_va(uint64_t va); - const section& section_from_va(uint64_t va) const; - //Returns section from file offset (4gb max) - section& section_from_file_offset(uint32_t offset); - const section& section_from_file_offset(uint32_t offset) const; - - //Returns section TOTAL RAW/VIRTUAL data length from RVA inside section - //If include_headers = true, data from the beginning of PE file to SizeOfHeaders will be searched, too - uint32_t section_data_length_from_rva(uint32_t rva, section_data_type datatype = section_data_raw, bool include_headers = false) const; - //Returns section TOTAL RAW/VIRTUAL data length from VA inside section for PE32 and PE64 respectively - //If include_headers = true, data from the beginning of PE file to SizeOfHeaders will be searched, too - uint32_t section_data_length_from_va(uint32_t va, section_data_type datatype = section_data_raw, bool include_headers = false) const; - uint32_t section_data_length_from_va(uint64_t va, section_data_type datatype = section_data_raw, bool include_headers = false) const; - - //Returns section remaining RAW/VIRTUAL data length from RVA to the end of section "s" (checks bounds) - uint32_t section_data_length_from_rva(const section& s, uint32_t rva_inside, section_data_type datatype = section_data_raw) const; - //Returns section remaining RAW/VIRTUAL data length from VA to the end of section "s" for PE32 and PE64 respectively (checks bounds) - uint32_t section_data_length_from_va(const section& s, uint64_t va_inside, section_data_type datatype = section_data_raw) const; - uint32_t section_data_length_from_va(const section& s, uint32_t va_inside, section_data_type datatype = section_data_raw) const; - - //Returns section remaining RAW/VIRTUAL data length from RVA "rva_inside" to the end of section containing RVA "rva" - //If include_headers = true, data from the beginning of PE file to SizeOfHeaders will be searched, too - uint32_t section_data_length_from_rva(uint32_t rva, uint32_t rva_inside, section_data_type datatype = section_data_raw, bool include_headers = false) const; - //Returns section remaining RAW/VIRTUAL data length from VA "va_inside" to the end of section containing VA "va" for PE32 and PE64 respectively - //If include_headers = true, data from the beginning of PE file to SizeOfHeaders will be searched, too - uint32_t section_data_length_from_va(uint32_t va, uint32_t va_inside, section_data_type datatype = section_data_raw, bool include_headers = false) const; - uint32_t section_data_length_from_va(uint64_t va, uint64_t va_inside, section_data_type datatype = section_data_raw, bool include_headers = false) const; - - //If include_headers = true, data from the beginning of PE file to SizeOfHeaders will be searched, too - //Returns corresponding section data pointer from RVA inside section - char* section_data_from_rva(uint32_t rva, bool include_headers = false); - const char* section_data_from_rva(uint32_t rva, section_data_type datatype = section_data_raw, bool include_headers = false) const; - //Returns corresponding section data pointer from VA inside section for PE32 and PE64 respectively - char* section_data_from_va(uint32_t va, bool include_headers = false); - const char* section_data_from_va(uint32_t va, section_data_type datatype = section_data_raw, bool include_headers = false) const; - char* section_data_from_va(uint64_t va, bool include_headers = false); - const char* section_data_from_va(uint64_t va, section_data_type datatype = section_data_raw, bool include_headers = false) const; - - //Returns corresponding section data pointer from RVA inside section "s" (checks bounds) - char* section_data_from_rva(section& s, uint32_t rva); - const char* section_data_from_rva(const section& s, uint32_t rva, section_data_type datatype = section_data_raw) const; - //Returns corresponding section data pointer from VA inside section "s" for PE32 and PE64 respectively (checks bounds) - char* section_data_from_va(section& s, uint32_t va); //Always returns raw data - const char* section_data_from_va(const section& s, uint32_t va, section_data_type datatype = section_data_raw) const; - char* section_data_from_va(section& s, uint64_t va); //Always returns raw data - const char* section_data_from_va(const section& s, uint64_t va, section_data_type datatype = section_data_raw) const; - - //Returns corresponding section data pointer from RVA inside section "s" (checks bounds, checks sizes, the most safe function) - template - T section_data_from_rva(const section& s, uint32_t rva, section_data_type datatype = section_data_raw) const - { - if(rva >= s.get_virtual_address() && rva < s.get_virtual_address() + s.get_aligned_virtual_size(get_section_alignment()) && pe_utils::is_sum_safe(rva, sizeof(T))) - { - const std::string& data = datatype == section_data_raw ? s.get_raw_data() : s.get_virtual_data(get_section_alignment()); - //Don't check for underflow here, comparsion is unsigned - if(data.size() < rva - s.get_virtual_address() + sizeof(T)) - throw pe_exception("RVA and requested data size does not exist inside section", pe_exception::rva_not_exists); - - return *reinterpret_cast(data.data() + rva - s.get_virtual_address()); - } - - throw pe_exception("RVA not found inside section", pe_exception::rva_not_exists); - } - - //Returns corresponding section data pointer from RVA inside section (checks rva, checks sizes, the most safe function) - //If include_headers = true, data from the beginning of PE file to SizeOfHeaders will be searched, too - template - T section_data_from_rva(uint32_t rva, section_data_type datatype = section_data_raw, bool include_headers = false) const - { - //if RVA is inside of headers and we're searching them too... - if(include_headers && pe_utils::is_sum_safe(rva, sizeof(T)) && (rva + sizeof(T) < full_headers_data_.length())) - return *reinterpret_cast(&full_headers_data_[rva]); - - const section& s = section_from_rva(rva); - const std::string& data = datatype == section_data_raw ? s.get_raw_data() : s.get_virtual_data(get_section_alignment()); - //Don't check for underflow here, comparsion is unsigned - if(data.size() < rva - s.get_virtual_address() + sizeof(T)) - throw pe_exception("RVA and requested data size does not exist inside section", pe_exception::rva_not_exists); - - return *reinterpret_cast(data.data() + rva - s.get_virtual_address()); - } - - //Returns corresponding section data pointer from VA inside section "s" (checks bounds, checks sizes, the most safe function) - template - T section_data_from_va(const section& s, uint32_t va, section_data_type datatype = section_data_raw) const - { - return section_data_from_rva(s, va_to_rva(va), datatype); - } - - template - T section_data_from_va(const section& s, uint64_t va, section_data_type datatype = section_data_raw) const - { - return section_data_from_rva(s, va_to_rva(va), datatype); - } - - //Returns corresponding section data pointer from VA inside section (checks rva, checks sizes, the most safe function) - //If include_headers = true, data from the beginning of PE file to SizeOfHeaders will be searched, too - template - T section_data_from_va(uint32_t va, section_data_type datatype = section_data_raw, bool include_headers = false) const - { - return section_data_from_rva(va_to_rva(va), datatype, include_headers); - } - - template - T section_data_from_va(uint64_t va, section_data_type datatype = section_data_raw, bool include_headers = false) const - { - return section_data_from_rva(va_to_rva(va), datatype, include_headers); - } - - //Returns section and offset (raw data only) from its start from RVA - const std::pair section_and_offset_from_rva(uint32_t rva) const; - - //Sets virtual size of section "s" - //Section must be free (not bound to any image) - //or the last section of this image - //Function calls update_image_size automatically in second case - void set_section_virtual_size(section& s, uint32_t vsize); - - //Represents section expand type for expand_section function - enum section_expand_type - { - expand_section_raw, //Section raw data size will be expanded - expand_section_virtual //Section virtual data size will be expanded - }; - - //Expands section raw or virtual size to hold data from specified RVA with specified size - //Section must be free (not bound to any image) - //or the last section of this image - //Returns true if section was expanded - bool expand_section(section& s, uint32_t needed_rva, uint32_t needed_size, section_expand_type expand); - - //Adds section to image - //Returns last section - section& add_section(section s); - //Prepares section to later add it to image (checks and recalculates virtual and raw section size) - //Section must be prepared by this function before calling add_section - void prepare_section(section& s); - - //Returns true if sectios "s" is already attached to this PE file - bool section_attached(const section& s) const; - - -public: //IMAGE - //Returns PE type (PE or PE+) from pe_type enumeration (minimal correctness checks) - static pe_type get_pe_type(std::istream& file); - //Returns PE type of this image - pe_type get_pe_type() const; - - //Returns true if image has overlay data at the end of file - bool has_overlay() const; - - //Realigns file (changes file alignment) - void realign_file(uint32_t new_file_alignment); - - //Helper function to recalculate RAW and virtual section sizes and strip it, if necessary - //auto_strip = strip section, if necessary - void recalculate_section_sizes(section& s, bool auto_strip); - - // ========== END OF PUBLIC MEMBERS AND STRUCTURES ========== // -private: - //Image DOS header - pe_win::image_dos_header dos_header_; - //Rich (stub) overlay data (for MSVS) - std::string rich_overlay_; - //List of image sections - section_list sections_; - //True if image has overlay - bool has_overlay_; - //Raw SizeOfHeaders-sized data from the beginning of image - std::string full_headers_data_; - //Raw debug data for all directories - //PointerToRawData; Data - debug_data_list debug_data_; - //PE or PE+ related properties - pe_properties* props_; - - //Reads and checks DOS header - void read_dos_header(std::istream& file); - - //Reads and checks PE headers and section headers, data - void read_pe(std::istream& file, bool read_debug_raw_data); - - //Sets number of sections - void set_number_of_sections(uint16_t number); - //Sets size of image - void set_size_of_image(uint32_t size); - //Sets file alignment (no checks) - void set_file_alignment_unchecked(uint32_t alignment); - //Returns needed magic of image - uint32_t get_needed_magic() const; - //Returns nt headers data pointer - char* get_nt_headers_ptr(); - -private: - static const uint16_t maximum_number_of_sections = 0x60; - static const uint32_t minimum_file_alignment = 512; - -private: - //RAW file offset to section convertion helpers (4gb max) - section_list::const_iterator file_offset_to_section(uint32_t offset) const; - section_list::iterator file_offset_to_section(uint32_t offset); -}; -} diff --git a/drivers/pe_bliss/pe_bliss.h b/drivers/pe_bliss/pe_bliss.h deleted file mode 100644 index 82dfd67cf5..0000000000 --- a/drivers/pe_bliss/pe_bliss.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once -#include "pe_base.h" -#include "pe_rebuilder.h" -#include "pe_factory.h" -#include "pe_bound_import.h" -#include "pe_debug.h" -#include "pe_dotnet.h" -#include "pe_exception_directory.h" -#include "pe_exports.h" -#include "pe_imports.h" -#include "pe_load_config.h" -#include "pe_relocations.h" -#include "pe_resources.h" -#include "pe_rich_data.h" -#include "pe_tls.h" -#include "pe_properties_generic.h" -#include "pe_checksum.h" -#include "entropy.h" diff --git a/drivers/pe_bliss/pe_bliss_godot.cpp b/drivers/pe_bliss/pe_bliss_godot.cpp deleted file mode 100644 index 8297aa1045..0000000000 --- a/drivers/pe_bliss/pe_bliss_godot.cpp +++ /dev/null @@ -1,118 +0,0 @@ -#include "pe_bliss/pe_bliss.h" -#include "pe_bliss/pe_bliss_resources.h" -#include "core/ustring.h" -#include "core/dvector.h" -#include "os/file_access.h" - -using namespace pe_bliss; - -String pe_bliss_add_resrc(const char* p_path, int version_major, int version_minor, - String& company_name, String& file_description, - String& legal_copyright, String& version_text, - String& product_name, String& godot_version, - DVector& icon_content) { - try - { - pe_base image(pe_factory::create_pe(p_path)); - - const section_list& pe_sections = image.get_image_sections(); - uint32_t end_of_pe = 0; - FileAccess *dst; - DVector overlay_data; - if(image.has_overlay()) - { - end_of_pe = pe_sections.back().get_pointer_to_raw_data() + pe_sections.back().get_size_of_raw_data(); - dst=FileAccess::open(p_path,FileAccess::READ); - if (dst) { - overlay_data.resize(dst->get_len()-end_of_pe); - dst->seek(end_of_pe); - DVector::Write overlay_data_write = overlay_data.write(); - dst->get_buffer(overlay_data_write.ptr(),overlay_data.size()); - dst->close(); - memdelete(dst); - } - } - resource_directory root; - if(image.has_resources()) - { - root = resource_directory(get_resources(image)); - } - pe_resource_manager res(root); - if(image.has_resources()) - { - if(icon_content.size()) { - if(res.resource_exists(pe_resource_viewer::resource_icon)) - { - res.remove_resource_type(pe_resource_viewer::resource_icon); - } - if(res.resource_exists(pe_resource_viewer::resource_icon_group)) - { - res.remove_resource_type(pe_resource_viewer::resource_icon_group); - } - } - if(res.resource_exists(pe_resource_viewer::resource_version)) - { - res.remove_resource_type(pe_resource_viewer::resource_version); - } - } - file_version_info file_info; - file_info.set_file_os(file_version_info::file_os_nt_win32); - file_info.set_file_type(file_version_info::file_type_application); - unsigned int ver = version_major << 16; - ver = ver + version_minor; - file_info.set_file_version_ms(ver); - file_info.set_file_version_ls(0x00000000); - file_info.set_product_version_ms(ver); - file_info.set_product_version_ls(0x00000000); - lang_string_values_map strings; - translation_values_map translations; - version_info_editor version(strings, translations); - version.add_translation(version_info_editor::default_language_translation); - version.set_company_name(company_name.c_str()); - version.set_file_description(file_description.c_str()); - if (!product_name.empty()) { - version.set_internal_name((product_name+String(".exe")).c_str()); - version.set_original_filename((product_name+String(".exe")).c_str()); - version.set_product_name(product_name.c_str()); - } - version.set_legal_copyright(legal_copyright.c_str()); - version.set_product_version(version_text.c_str()); - if(!godot_version.empty()) version.set_property(L"Godot Engine Version", godot_version.c_str() ); - resource_version_info_writer(res).set_version_info(file_info, strings, translations, 1033, 1200); - if(icon_content.size()) { - std::string icon; - icon.resize(icon_content.size()); - for(int i=0; iseek_end(); - DVector::Read overlay_data_read = overlay_data.read(); - dst->store_buffer(overlay_data_read.ptr(),overlay_data.size()); - dst->close(); - memdelete(dst); - } - } - return String(); - } catch(const pe_exception& e) { - String ret("Error In Add rsrc Section : "); - return ret + String(e.what()); - } -} diff --git a/drivers/pe_bliss/pe_bliss_godot.h b/drivers/pe_bliss/pe_bliss_godot.h deleted file mode 100644 index 0365ca9eaf..0000000000 --- a/drivers/pe_bliss/pe_bliss_godot.h +++ /dev/null @@ -1,7 +0,0 @@ - - -String pe_bliss_add_resrc(const char* p_path, int version_major, int version_minor, - String& company_name, String& file_description, - String& legal_copyright, String& version_text, - String& product_name, String& godot_version, - DVector& icon_content); diff --git a/drivers/pe_bliss/pe_bliss_resources.h b/drivers/pe_bliss/pe_bliss_resources.h deleted file mode 100644 index 7c07b7c4bb..0000000000 --- a/drivers/pe_bliss/pe_bliss_resources.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include "file_version_info.h" -#include "message_table.h" -#include "pe_resource_manager.h" -#include "pe_resource_viewer.h" -#include "version_info_editor.h" -#include "version_info_viewer.h" -#include "resource_bitmap_reader.h" -#include "resource_bitmap_writer.h" -#include "resource_cursor_icon_reader.h" -#include "resource_cursor_icon_writer.h" -#include "resource_version_info_reader.h" -#include "resource_version_info_writer.h" -#include "resource_string_table_reader.h" -#include "resource_message_list_reader.h" diff --git a/drivers/pe_bliss/pe_bound_import.cpp b/drivers/pe_bliss/pe_bound_import.cpp deleted file mode 100644 index 605cf229b4..0000000000 --- a/drivers/pe_bliss/pe_bound_import.cpp +++ /dev/null @@ -1,290 +0,0 @@ -#include -#include "pe_bound_import.h" -#include "utils.h" - -namespace pe_bliss -{ -using namespace pe_win; - -//BOUND IMPORT -//Default constructor -bound_import_ref::bound_import_ref() - :timestamp_(0) -{} - -//Constructor from data -bound_import_ref::bound_import_ref(const std::string& module_name, uint32_t timestamp) - :module_name_(module_name), timestamp_(timestamp) -{} - -//Returns imported module name -const std::string& bound_import_ref::get_module_name() const -{ - return module_name_; -} - -//Returns bound import date and time stamp -uint32_t bound_import_ref::get_timestamp() const -{ - return timestamp_; -} - -//Sets module name -void bound_import_ref::set_module_name(const std::string& module_name) -{ - module_name_ = module_name; -} - -//Sets timestamp -void bound_import_ref::set_timestamp(uint32_t timestamp) -{ - timestamp_ = timestamp; -} - -//Default constructor -bound_import::bound_import() - :timestamp_(0) -{} - -//Constructor from data -bound_import::bound_import(const std::string& module_name, uint32_t timestamp) - :module_name_(module_name), timestamp_(timestamp) -{} - -//Returns imported module name -const std::string& bound_import::get_module_name() const -{ - return module_name_; -} - -//Returns bound import date and time stamp -uint32_t bound_import::get_timestamp() const -{ - return timestamp_; -} - -//Returns bound references cound -size_t bound_import::get_module_ref_count() const -{ - return refs_.size(); -} - -//Returns module references -const bound_import::ref_list& bound_import::get_module_ref_list() const -{ - return refs_; -} - -//Adds module reference -void bound_import::add_module_ref(const bound_import_ref& ref) -{ - refs_.push_back(ref); -} - -//Clears module references list -void bound_import::clear_module_refs() -{ - refs_.clear(); -} - -//Returns module references -bound_import::ref_list& bound_import::get_module_ref_list() -{ - return refs_; -} - -//Sets module name -void bound_import::set_module_name(const std::string& module_name) -{ - module_name_ = module_name; -} - -//Sets timestamp -void bound_import::set_timestamp(uint32_t timestamp) -{ - timestamp_ = timestamp; -} - -const bound_import_module_list get_bound_import_module_list(const pe_base& pe) -{ - //Returned bound import modules list - bound_import_module_list ret; - - //If image has no bound imports - if(!pe.has_bound_import()) - return ret; - - uint32_t bound_import_data_len = - pe.section_data_length_from_rva(pe.get_directory_rva(image_directory_entry_bound_import), pe.get_directory_rva(image_directory_entry_bound_import), section_data_raw, true); - - if(bound_import_data_len < pe.get_directory_size(image_directory_entry_bound_import)) - throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory); - - const char* bound_import_data = pe.section_data_from_rva(pe.get_directory_rva(image_directory_entry_bound_import), section_data_raw, true); - - //Check read in "read_pe" function raw bound import data size - if(bound_import_data_len < sizeof(image_bound_import_descriptor)) - throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory); - - //current bound_import_data_ in-string position - unsigned long current_pos = 0; - //first bound import descriptor - //so, we're working with raw data here, no section helpers available - const image_bound_import_descriptor* descriptor = reinterpret_cast(&bound_import_data[current_pos]); - - //Enumerate until zero - while(descriptor->OffsetModuleName) - { - //Check module name offset - if(descriptor->OffsetModuleName >= bound_import_data_len) - throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory); - - //Check module name for null-termination - if(!pe_utils::is_null_terminated(&bound_import_data[descriptor->OffsetModuleName], bound_import_data_len - descriptor->OffsetModuleName)) - throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory); - - //Create bound import descriptor structure - bound_import elem(&bound_import_data[descriptor->OffsetModuleName], descriptor->TimeDateStamp); - - //Check DWORDs - if(descriptor->NumberOfModuleForwarderRefs >= pe_utils::max_dword / sizeof(image_bound_forwarder_ref) - || !pe_utils::is_sum_safe(current_pos, 2 /* this descriptor and the next one */ * sizeof(image_bound_import_descriptor) + descriptor->NumberOfModuleForwarderRefs * sizeof(image_bound_forwarder_ref))) - throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory); - - //Move after current descriptor - current_pos += sizeof(image_bound_import_descriptor); - - //Enumerate referenced bound import descriptors - for(unsigned long i = 0; i != descriptor->NumberOfModuleForwarderRefs; ++i) - { - //They're just after parent descriptor - //Check size of structure - if(current_pos + sizeof(image_bound_forwarder_ref) > bound_import_data_len) - throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory); - - //Get IMAGE_BOUND_FORWARDER_REF pointer - const image_bound_forwarder_ref* ref_descriptor = reinterpret_cast(&bound_import_data[current_pos]); - - //Check referenced module name - if(ref_descriptor->OffsetModuleName >= bound_import_data_len) - throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory); - - //And its null-termination - if(!pe_utils::is_null_terminated(&bound_import_data[ref_descriptor->OffsetModuleName], bound_import_data_len - ref_descriptor->OffsetModuleName)) - throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory); - - //Add referenced module to current bound import structure - elem.add_module_ref(bound_import_ref(&bound_import_data[ref_descriptor->OffsetModuleName], ref_descriptor->TimeDateStamp)); - - //Move after referenced bound import descriptor - current_pos += sizeof(image_bound_forwarder_ref); - } - - //Check structure size - if(current_pos + sizeof(image_bound_import_descriptor) > bound_import_data_len) - throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory); - - //Move to next bound import descriptor - descriptor = reinterpret_cast(&bound_import_data[current_pos]); - - //Save created descriptor structure and references - ret.push_back(elem); - } - - //Return result - return ret; -} - -//imports - bound imported modules list -//imports_section - section where export directory will be placed (must be attached to PE image) -//offset_from_section_start - offset from imports_section raw data start -//save_to_pe_headers - if true, new bound import directory information will be saved to PE image headers -//auto_strip_last_section - if true and bound imports are placed in the last section, it will be automatically stripped -const image_directory rebuild_bound_imports(pe_base& pe, const bound_import_module_list& imports, section& imports_section, uint32_t offset_from_section_start, bool save_to_pe_header, bool auto_strip_last_section) -{ - //Check that exports_section is attached to this PE image - if(!pe.section_attached(imports_section)) - throw pe_exception("Bound import section must be attached to PE file", pe_exception::section_is_not_attached); - - uint32_t directory_pos = pe_utils::align_up(offset_from_section_start, sizeof(uint32_t)); - uint32_t needed_size = sizeof(image_bound_import_descriptor) /* Ending null descriptor */; - uint32_t needed_size_for_strings = 0; - - //Calculate needed size for bound import data - for(bound_import_module_list::const_iterator it = imports.begin(); it != imports.end(); ++it) - { - const bound_import& import = *it; - needed_size += sizeof(image_bound_import_descriptor); - needed_size_for_strings += static_cast((*it).get_module_name().length()) + 1 /* nullbyte */; - - const bound_import::ref_list& refs = import.get_module_ref_list(); - for(bound_import::ref_list::const_iterator ref_it = refs.begin(); ref_it != refs.end(); ++ref_it) - { - needed_size_for_strings += static_cast((*ref_it).get_module_name().length()) + 1 /* nullbyte */; - needed_size += sizeof(image_bound_forwarder_ref); - } - } - - needed_size += needed_size_for_strings; - - //Check if imports_section is last one. If it's not, check if there's enough place for bound import data - if(&imports_section != &*(pe.get_image_sections().end() - 1) && - (imports_section.empty() || pe_utils::align_up(imports_section.get_size_of_raw_data(), pe.get_file_alignment()) < needed_size + directory_pos)) - throw pe_exception("Insufficient space for bound import directory", pe_exception::insufficient_space); - - std::string& raw_data = imports_section.get_raw_data(); - - //This will be done only if imports_section is the last section of image or for section with unaligned raw length of data - if(raw_data.length() < needed_size + directory_pos) - raw_data.resize(needed_size + directory_pos); //Expand section raw data - - uint32_t current_pos_for_structures = directory_pos; - uint32_t current_pos_for_strings = current_pos_for_structures + needed_size - needed_size_for_strings; - - for(bound_import_module_list::const_iterator it = imports.begin(); it != imports.end(); ++it) - { - const bound_import& import = *it; - image_bound_import_descriptor descriptor; - descriptor.NumberOfModuleForwarderRefs = static_cast(import.get_module_ref_list().size()); - descriptor.OffsetModuleName = static_cast(current_pos_for_strings - directory_pos); - descriptor.TimeDateStamp = import.get_timestamp(); - - memcpy(&raw_data[current_pos_for_structures], &descriptor, sizeof(descriptor)); - current_pos_for_structures += sizeof(descriptor); - - size_t length = import.get_module_name().length() + 1 /* nullbyte */; - memcpy(&raw_data[current_pos_for_strings], import.get_module_name().c_str(), length); - current_pos_for_strings += static_cast(length); - - const bound_import::ref_list& refs = import.get_module_ref_list(); - for(bound_import::ref_list::const_iterator ref_it = refs.begin(); ref_it != refs.end(); ++ref_it) - { - const bound_import_ref& ref = *ref_it; - image_bound_forwarder_ref ref_descriptor = {0}; - ref_descriptor.OffsetModuleName = static_cast(current_pos_for_strings - directory_pos); - ref_descriptor.TimeDateStamp = ref.get_timestamp(); - - memcpy(&raw_data[current_pos_for_structures], &ref_descriptor, sizeof(ref_descriptor)); - current_pos_for_structures += sizeof(ref_descriptor); - - length = ref.get_module_name().length() + 1 /* nullbyte */; - memcpy(&raw_data[current_pos_for_strings], ref.get_module_name().c_str(), length); - current_pos_for_strings += static_cast(length); - } - } - - //Adjust section raw and virtual sizes - pe.recalculate_section_sizes(imports_section, auto_strip_last_section); - - image_directory ret(pe.rva_from_section_offset(imports_section, directory_pos), needed_size); - - //If auto-rewrite of PE headers is required - if(save_to_pe_header) - { - pe.set_directory_rva(image_directory_entry_bound_import, ret.get_rva()); - pe.set_directory_size(image_directory_entry_bound_import, ret.get_size()); - } - - return ret; -} -} diff --git a/drivers/pe_bliss/pe_bound_import.h b/drivers/pe_bliss/pe_bound_import.h deleted file mode 100644 index 5c27eba06b..0000000000 --- a/drivers/pe_bliss/pe_bound_import.h +++ /dev/null @@ -1,87 +0,0 @@ -#pragma once -#include -#include -#include "pe_structures.h" -#include "pe_base.h" -#include "pe_directory.h" - -namespace pe_bliss -{ -//Class representing bound import reference -class bound_import_ref -{ -public: - //Default constructor - bound_import_ref(); - //Constructor from data - bound_import_ref(const std::string& module_name, uint32_t timestamp); - - //Returns imported module name - const std::string& get_module_name() const; - //Returns bound import date and time stamp - uint32_t get_timestamp() const; - -public: //Setters - //Sets module name - void set_module_name(const std::string& module_name); - //Sets timestamp - void set_timestamp(uint32_t timestamp); - -private: - std::string module_name_; //Imported module name - uint32_t timestamp_; //Bound import timestamp -}; - -//Class representing image bound import information -class bound_import -{ -public: - typedef std::vector ref_list; - -public: - //Default constructor - bound_import(); - //Constructor from data - bound_import(const std::string& module_name, uint32_t timestamp); - - //Returns imported module name - const std::string& get_module_name() const; - //Returns bound import date and time stamp - uint32_t get_timestamp() const; - - //Returns bound references cound - size_t get_module_ref_count() const; - //Returns module references - const ref_list& get_module_ref_list() const; - -public: //Setters - //Sets module name - void set_module_name(const std::string& module_name); - //Sets timestamp - void set_timestamp(uint32_t timestamp); - - //Adds module reference - void add_module_ref(const bound_import_ref& ref); - //Clears module references list - void clear_module_refs(); - //Returns module references - ref_list& get_module_ref_list(); - -private: - std::string module_name_; //Imported module name - uint32_t timestamp_; //Bound import timestamp - ref_list refs_; //Module references list -}; - -typedef std::vector bound_import_module_list; - -//Returns bound import information -const bound_import_module_list get_bound_import_module_list(const pe_base& pe);//Export directory rebuilder - -//imports - bound imported modules list -//imports_section - section where export directory will be placed (must be attached to PE image) -//offset_from_section_start - offset from imports_section raw data start -//save_to_pe_headers - if true, new bound import directory information will be saved to PE image headers -//auto_strip_last_section - if true and bound imports are placed in the last section, it will be automatically stripped -const image_directory rebuild_bound_imports(pe_base& pe, const bound_import_module_list& imports, section& imports_section, uint32_t offset_from_section_start = 0, bool save_to_pe_header = true, bool auto_strip_last_section = true); -} diff --git a/drivers/pe_bliss/pe_checksum.cpp b/drivers/pe_bliss/pe_checksum.cpp deleted file mode 100644 index f6d23f0e10..0000000000 --- a/drivers/pe_bliss/pe_checksum.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include "pe_checksum.h" -#include "pe_structures.h" -#include "pe_base.h" - -namespace pe_bliss -{ -using namespace pe_win; - -//Calculate checksum of image -uint32_t calculate_checksum(std::istream& file) -{ - //Save istream state - std::ios_base::iostate state = file.exceptions(); - std::streamoff old_offset = file.tellg(); - - //Checksum value - unsigned long long checksum = 0; - - try - { - image_dos_header header; - - file.exceptions(std::ios::goodbit); - - //Read DOS header - pe_base::read_dos_header(file, header); - - //Calculate PE checksum - file.seekg(0); - unsigned long long top = 0xFFFFFFFF; - top++; - - //"CheckSum" field position in optional PE headers - it's always 64 for PE and PE+ - static const unsigned long checksum_pos_in_optional_headers = 64; - //Calculate real PE headers "CheckSum" field position - //Sum is safe here - unsigned long pe_checksum_pos = header.e_lfanew + sizeof(image_file_header) + sizeof(uint32_t) + checksum_pos_in_optional_headers; - - //Calculate checksum for each byte of file - std::streamoff filesize = pe_utils::get_file_size(file); - for(long long i = 0; i < filesize; i += 4) - { - unsigned long dw = 0; - - //Read DWORD from file - file.read(reinterpret_cast(&dw), sizeof(unsigned long)); - //Skip "CheckSum" DWORD - if(i == pe_checksum_pos) - continue; - - //Calculate checksum - checksum = (checksum & 0xffffffff) + dw + (checksum >> 32); - if(checksum > top) - checksum = (checksum & 0xffffffff) + (checksum >> 32); - } - - //Finish checksum - checksum = (checksum & 0xffff) + (checksum >> 16); - checksum = (checksum) + (checksum >> 16); - checksum = checksum & 0xffff; - - checksum += static_cast(filesize); - } - catch(const std::exception&) - { - //If something went wrong, restore istream state - file.exceptions(state); - file.seekg(old_offset); - file.clear(); - //Rethrow - throw; - } - - //Restore istream state - file.exceptions(state); - file.seekg(old_offset); - file.clear(); - - //Return checksum - return static_cast(checksum); -} -} diff --git a/drivers/pe_bliss/pe_checksum.h b/drivers/pe_bliss/pe_checksum.h deleted file mode 100644 index 892a2854ba..0000000000 --- a/drivers/pe_bliss/pe_checksum.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include -#include "stdint_defs.h" - -namespace pe_bliss -{ -//Calculate checksum of image (performs no checks on PE structures) -uint32_t calculate_checksum(std::istream& file); -} diff --git a/drivers/pe_bliss/pe_debug.cpp b/drivers/pe_bliss/pe_debug.cpp deleted file mode 100644 index f077f29fb8..0000000000 --- a/drivers/pe_bliss/pe_debug.cpp +++ /dev/null @@ -1,844 +0,0 @@ -#include -#include "pe_debug.h" -#include "utils.h" - -namespace pe_bliss -{ -using namespace pe_win; -//DEBUG -//Default constructor -debug_info::debug_info() - :characteristics_(0), - time_stamp_(0), - major_version_(0), minor_version_(0), - type_(0), - size_of_data_(0), - address_of_raw_data_(0), - pointer_to_raw_data_(0), - advanced_info_type_(advanced_info_none) -{} - -//Constructor from data -debug_info::debug_info(const image_debug_directory& debug) - :characteristics_(debug.Characteristics), - time_stamp_(debug.TimeDateStamp), - major_version_(debug.MajorVersion), minor_version_(debug.MinorVersion), - type_(debug.Type), - size_of_data_(debug.SizeOfData), - address_of_raw_data_(debug.AddressOfRawData), - pointer_to_raw_data_(debug.PointerToRawData), - advanced_info_type_(advanced_info_none) -{} - -//Returns debug characteristics -uint32_t debug_info::get_characteristics() const -{ - return characteristics_; -} - -//Returns debug datetimestamp -uint32_t debug_info::get_time_stamp() const -{ - return time_stamp_; -} - -//Returns major version -uint32_t debug_info::get_major_version() const -{ - return major_version_; -} - -//Returns minor version -uint32_t debug_info::get_minor_version() const -{ - return minor_version_; -} - -//Returns type of debug info (unchecked) -uint32_t debug_info::get_type_raw() const -{ - return type_; -} - -//Returns type of debug info from debug_info_type enumeration -debug_info::debug_info_type debug_info::get_type() const -{ - //Determine debug type - switch(type_) - { - case image_debug_type_coff: - return debug_type_coff; - - case image_debug_type_codeview: - return debug_type_codeview; - - case image_debug_type_fpo: - return debug_type_fpo; - - case image_debug_type_misc: - return debug_type_misc; - - case image_debug_type_exception: - return debug_type_exception; - - case image_debug_type_fixup: - return debug_type_fixup; - - case image_debug_type_omap_to_src: - return debug_type_omap_to_src; - - case image_debug_type_omap_from_src: - return debug_type_omap_from_src; - - case image_debug_type_borland: - return debug_type_borland; - - case image_debug_type_clsid: - return debug_type_clsid; - - case image_debug_type_reserved10: - return debug_type_reserved10; - } - - return debug_type_unknown; -} - -//Returns size of debug data (internal, .pdb or other file doesn't count) -uint32_t debug_info::get_size_of_data() const -{ - return size_of_data_; -} - -//Returns RVA of debug info when mapped to memory or zero, if info is not mapped -uint32_t debug_info::get_rva_of_raw_data() const -{ - return address_of_raw_data_; -} - -//Returns raw file pointer to raw data -uint32_t debug_info::get_pointer_to_raw_data() const -{ - return pointer_to_raw_data_; -} - -//Copy constructor -debug_info::debug_info(const debug_info& info) - :characteristics_(info.characteristics_), - time_stamp_(info.time_stamp_), - major_version_(info.major_version_), minor_version_(info.minor_version_), - type_(info.type_), - size_of_data_(info.size_of_data_), - address_of_raw_data_(info.address_of_raw_data_), - pointer_to_raw_data_(info.pointer_to_raw_data_), - advanced_info_type_(info.advanced_info_type_) -{ - copy_advanced_info(info); -} - -//Copy assignment operator -debug_info& debug_info::operator=(const debug_info& info) -{ - copy_advanced_info(info); - - characteristics_ = info.characteristics_; - time_stamp_ = info.time_stamp_; - major_version_ = info.major_version_; - minor_version_ = info.minor_version_; - type_ = info.type_; - size_of_data_ = info.size_of_data_; - address_of_raw_data_ = info.address_of_raw_data_; - pointer_to_raw_data_ = info.pointer_to_raw_data_; - advanced_info_type_ = info.advanced_info_type_; - - return *this; -} - -//Default constructor -debug_info::advanced_info::advanced_info() - :adv_pdb_7_0_info(0) //Zero pointer to advanced data -{} - -//Returns true if advanced debug info is present -bool debug_info::advanced_info::is_present() const -{ - return adv_pdb_7_0_info != 0; -} - -//Helper for advanced debug information copying -void debug_info::copy_advanced_info(const debug_info& info) -{ - free_present_advanced_info(); - - switch(info.advanced_info_type_) - { - case advanced_info_pdb_7_0: - advanced_debug_info_.adv_pdb_7_0_info = new pdb_7_0_info(*info.advanced_debug_info_.adv_pdb_7_0_info); - break; - case advanced_info_pdb_2_0: - advanced_debug_info_.adv_pdb_2_0_info = new pdb_2_0_info(*info.advanced_debug_info_.adv_pdb_2_0_info); - break; - case advanced_info_misc: - advanced_debug_info_.adv_misc_info = new misc_debug_info(*info.advanced_debug_info_.adv_misc_info); - break; - case advanced_info_coff: - advanced_debug_info_.adv_coff_info = new coff_debug_info(*info.advanced_debug_info_.adv_coff_info); - break; - default: - break; - } - - advanced_info_type_ = info.advanced_info_type_; -} - -//Helper for clearing any present advanced debug information -void debug_info::free_present_advanced_info() -{ - switch(advanced_info_type_) - { - case advanced_info_pdb_7_0: - delete advanced_debug_info_.adv_pdb_7_0_info; - break; - case advanced_info_pdb_2_0: - delete advanced_debug_info_.adv_pdb_2_0_info; - break; - case advanced_info_misc: - delete advanced_debug_info_.adv_misc_info; - break; - case advanced_info_coff: - delete advanced_debug_info_.adv_coff_info; - break; - default: - break; - } - - advanced_debug_info_.adv_pdb_7_0_info = 0; - advanced_info_type_ = advanced_info_none; -} - -//Destructor -debug_info::~debug_info() -{ - free_present_advanced_info(); -} - -//Sets advanced debug information -void debug_info::set_advanced_debug_info(const pdb_7_0_info& info) -{ - free_present_advanced_info(); - advanced_debug_info_.adv_pdb_7_0_info = new pdb_7_0_info(info); - advanced_info_type_ = advanced_info_pdb_7_0; -} - -void debug_info::set_advanced_debug_info(const pdb_2_0_info& info) -{ - free_present_advanced_info(); - advanced_debug_info_.adv_pdb_2_0_info = new pdb_2_0_info(info); - advanced_info_type_ = advanced_info_pdb_2_0; -} - -void debug_info::set_advanced_debug_info(const misc_debug_info& info) -{ - free_present_advanced_info(); - advanced_debug_info_.adv_misc_info = new misc_debug_info(info); - advanced_info_type_ = advanced_info_misc; -} - -void debug_info::set_advanced_debug_info(const coff_debug_info& info) -{ - free_present_advanced_info(); - advanced_debug_info_.adv_coff_info = new coff_debug_info(info); - advanced_info_type_ = advanced_info_coff; -} - -//Returns advanced debug information type -debug_info::advanced_info_type debug_info::get_advanced_info_type() const -{ - return advanced_info_type_; -} - -//Returns advanced debug information or throws an exception, -//if requested information type is not contained by structure -template<> -const pdb_7_0_info debug_info::get_advanced_debug_info() const -{ - if(advanced_info_type_ != advanced_info_pdb_7_0) - throw pe_exception("Debug info structure does not contain PDB 7.0 data", pe_exception::advanced_debug_information_request_error); - - return *advanced_debug_info_.adv_pdb_7_0_info; -} - -template<> -const pdb_2_0_info debug_info::get_advanced_debug_info() const -{ - if(advanced_info_type_ != advanced_info_pdb_2_0) - throw pe_exception("Debug info structure does not contain PDB 2.0 data", pe_exception::advanced_debug_information_request_error); - - return *advanced_debug_info_.adv_pdb_2_0_info; -} - -template<> -const misc_debug_info debug_info::get_advanced_debug_info() const -{ - if(advanced_info_type_ != advanced_info_misc) - throw pe_exception("Debug info structure does not contain MISC data", pe_exception::advanced_debug_information_request_error); - - return *advanced_debug_info_.adv_misc_info; -} - -template<> -const coff_debug_info debug_info::get_advanced_debug_info() const -{ - if(advanced_info_type_ != advanced_info_coff) - throw pe_exception("Debug info structure does not contain COFF data", pe_exception::advanced_debug_information_request_error); - - return *advanced_debug_info_.adv_coff_info; -} - -//Sets advanced debug information type, if no advanced info structure available -void debug_info::set_advanced_info_type(advanced_info_type type) -{ - free_present_advanced_info(); - if(advanced_info_type_ >= advanced_info_codeview_4_0) //Don't set info type for those types, which have advanced info structures - advanced_info_type_ = type; -} - -//Default constructor -pdb_7_0_info::pdb_7_0_info() - :age_(0) -{ - memset(&guid_, 0, sizeof(guid_)); -} - -//Constructor from data -pdb_7_0_info::pdb_7_0_info(const CV_INFO_PDB70* info) - :age_(info->Age), guid_(info->Signature), - pdb_file_name_(reinterpret_cast(info->PdbFileName)) //Must be checked before for null-termination -{} - -//Returns debug PDB 7.0 structure GUID -const guid pdb_7_0_info::get_guid() const -{ - return guid_; -} - -//Returns age of build -uint32_t pdb_7_0_info::get_age() const -{ - return age_; -} - -//Returns PDB file name / path -const std::string& pdb_7_0_info::get_pdb_file_name() const -{ - return pdb_file_name_; -} - -//Default constructor -pdb_2_0_info::pdb_2_0_info() - :age_(0), signature_(0) -{} - -//Constructor from data -pdb_2_0_info::pdb_2_0_info(const CV_INFO_PDB20* info) - :age_(info->Age), signature_(info->Signature), - pdb_file_name_(reinterpret_cast(info->PdbFileName)) //Must be checked before for null-termination -{} - -//Returns debug PDB 2.0 structure signature -uint32_t pdb_2_0_info::get_signature() const -{ - return signature_; -} - -//Returns age of build -uint32_t pdb_2_0_info::get_age() const -{ - return age_; -} - -//Returns PDB file name / path -const std::string& pdb_2_0_info::get_pdb_file_name() const -{ - return pdb_file_name_; -} - -//Default constructor -misc_debug_info::misc_debug_info() - :data_type_(0), unicode_(false) -{} - -//Constructor from data -misc_debug_info::misc_debug_info(const image_debug_misc* info) - :data_type_(info->DataType), unicode_(info->Unicode ? true : false) -{ - //IMAGE_DEBUG_MISC::Data must be checked before! - if(info->Unicode) - { -#ifdef PE_BLISS_WINDOWS - debug_data_unicode_ = std::wstring(reinterpret_cast(info->Data), (info->Length - sizeof(image_debug_misc) + 1 /* BYTE[1] in the end of structure */) / 2); -#else - debug_data_unicode_ = pe_utils::from_ucs2(u16string(reinterpret_cast(info->Data), (info->Length - sizeof(image_debug_misc) + 1 /* BYTE[1] in the end of structure */) / 2)); -#endif - - pe_utils::strip_nullbytes(debug_data_unicode_); //Strip nullbytes in the end of string - } - else - { - debug_data_ansi_ = std::string(reinterpret_cast(info->Data), info->Length - sizeof(image_debug_misc) + 1 /* BYTE[1] in the end of structure */); - pe_utils::strip_nullbytes(debug_data_ansi_); //Strip nullbytes in the end of string - } -} - -//Returns debug data type -uint32_t misc_debug_info::get_data_type() const -{ - return data_type_; -} - -//Returns true if data type is exe name -bool misc_debug_info::is_exe_name() const -{ - return data_type_ == image_debug_misc_exename; -} - -//Returns true if debug data is UNICODE -bool misc_debug_info::is_unicode() const -{ - return unicode_; -} - -//Returns debug data (ANSI) -const std::string& misc_debug_info::get_data_ansi() const -{ - return debug_data_ansi_; -} - -//Returns debug data (UNICODE) -const std::wstring& misc_debug_info::get_data_unicode() const -{ - return debug_data_unicode_; -} - -//Default constructor -coff_debug_info::coff_debug_info() - :number_of_symbols_(0), - lva_to_first_symbol_(0), - number_of_line_numbers_(0), - lva_to_first_line_number_(0), - rva_to_first_byte_of_code_(0), - rva_to_last_byte_of_code_(0), - rva_to_first_byte_of_data_(0), - rva_to_last_byte_of_data_(0) -{} - -//Constructor from data -coff_debug_info::coff_debug_info(const image_coff_symbols_header* info) - :number_of_symbols_(info->NumberOfSymbols), - lva_to_first_symbol_(info->LvaToFirstSymbol), - number_of_line_numbers_(info->NumberOfLinenumbers), - lva_to_first_line_number_(info->LvaToFirstLinenumber), - rva_to_first_byte_of_code_(info->RvaToFirstByteOfCode), - rva_to_last_byte_of_code_(info->RvaToLastByteOfCode), - rva_to_first_byte_of_data_(info->RvaToFirstByteOfData), - rva_to_last_byte_of_data_(info->RvaToLastByteOfData) -{} - -//Returns number of symbols -uint32_t coff_debug_info::get_number_of_symbols() const -{ - return number_of_symbols_; -} - -//Returns virtual address of the first symbol -uint32_t coff_debug_info::get_lva_to_first_symbol() const -{ - return lva_to_first_symbol_; -} - -//Returns number of line-number entries -uint32_t coff_debug_info::get_number_of_line_numbers() const -{ - return number_of_line_numbers_; -} - -//Returns virtual address of the first line-number entry -uint32_t coff_debug_info::get_lva_to_first_line_number() const -{ - return lva_to_first_line_number_; -} - -//Returns relative virtual address of the first byte of code -uint32_t coff_debug_info::get_rva_to_first_byte_of_code() const -{ - return rva_to_first_byte_of_code_; -} - -//Returns relative virtual address of the last byte of code -uint32_t coff_debug_info::get_rva_to_last_byte_of_code() const -{ - return rva_to_last_byte_of_code_; -} - -//Returns relative virtual address of the first byte of data -uint32_t coff_debug_info::get_rva_to_first_byte_of_data() const -{ - return rva_to_first_byte_of_data_; -} - -//Returns relative virtual address of the last byte of data -uint32_t coff_debug_info::get_rva_to_last_byte_of_data() const -{ - return rva_to_last_byte_of_data_; -} - -//Returns COFF symbols list -const coff_debug_info::coff_symbols_list& coff_debug_info::get_symbols() const -{ - return symbols_; -} - -//Adds COFF symbol -void coff_debug_info::add_symbol(const coff_symbol& sym) -{ - symbols_.push_back(sym); -} - -//Default constructor -coff_debug_info::coff_symbol::coff_symbol() - :storage_class_(0), - index_(0), - section_number_(0), rva_(0), - type_(0), - is_filename_(false) -{} - -//Returns storage class -uint32_t coff_debug_info::coff_symbol::get_storage_class() const -{ - return storage_class_; -} - -//Returns symbol index -uint32_t coff_debug_info::coff_symbol::get_index() const -{ - return index_; -} - -//Returns section number -uint32_t coff_debug_info::coff_symbol::get_section_number() const -{ - return section_number_; -} - -//Returns RVA -uint32_t coff_debug_info::coff_symbol::get_rva() const -{ - return rva_; -} - -//Returns true if structure contains file name -bool coff_debug_info::coff_symbol::is_file() const -{ - return is_filename_; -} - -//Returns text data (symbol or file name) -const std::string& coff_debug_info::coff_symbol::get_symbol() const -{ - return name_; -} - -//Sets storage class -void coff_debug_info::coff_symbol::set_storage_class(uint32_t storage_class) -{ - storage_class_ = storage_class; -} - -//Sets symbol index -void coff_debug_info::coff_symbol::set_index(uint32_t index) -{ - index_ = index; -} - -//Sets section number -void coff_debug_info::coff_symbol::set_section_number(uint32_t section_number) -{ - section_number_ = section_number; -} - -//Sets RVA -void coff_debug_info::coff_symbol::set_rva(uint32_t rva) -{ - rva_ = rva; -} - -//Sets file name -void coff_debug_info::coff_symbol::set_file_name(const std::string& file_name) -{ - name_ = file_name; - is_filename_ = true; -} - -//Sets symbol name -void coff_debug_info::coff_symbol::set_symbol_name(const std::string& symbol_name) -{ - name_ = symbol_name; - is_filename_ = false; -} - -//Returns type -uint16_t coff_debug_info::coff_symbol::get_type() const -{ - return type_; -} - -//Sets type -void coff_debug_info::coff_symbol::set_type(uint16_t type) -{ - type_ = type; -} - -//Returns debug information list -const debug_info_list get_debug_information(const pe_base& pe) -{ - debug_info_list ret; - - //If there's no debug directory, return empty list - if(!pe.has_debug()) - return ret; - - //Check the length in bytes of the section containing debug directory - if(pe.section_data_length_from_rva(pe.get_directory_rva(image_directory_entry_debug), pe.get_directory_rva(image_directory_entry_debug), section_data_virtual, true) - < sizeof(image_debug_directory)) - throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); - - unsigned long current_pos = pe.get_directory_rva(image_directory_entry_debug); - - //First IMAGE_DEBUG_DIRECTORY table - image_debug_directory directory = pe.section_data_from_rva(current_pos, section_data_virtual, true); - - if(!pe_utils::is_sum_safe(pe.get_directory_rva(image_directory_entry_debug), pe.get_directory_size(image_directory_entry_debug))) - throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); - - //Iterate over all IMAGE_DEBUG_DIRECTORY directories - while(directory.PointerToRawData - && current_pos < pe.get_directory_rva(image_directory_entry_debug) + pe.get_directory_size(image_directory_entry_debug)) - { - //Create debug information structure - debug_info info(directory); - - //Find raw debug data - const pe_base::debug_data_list& debug_datas = pe.get_raw_debug_data_list(); - pe_base::debug_data_list::const_iterator it = debug_datas.find(directory.PointerToRawData); - if(it != debug_datas.end()) //If it exists, we'll do some detailed debug info research - { - const std::string& debug_data = (*it).second; - switch(directory.Type) - { - case image_debug_type_coff: - { - //Check data length - if(debug_data.length() < sizeof(image_coff_symbols_header)) - throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); - - //Get coff header structure pointer - const image_coff_symbols_header* coff = reinterpret_cast(debug_data.data()); - - //Check possible overflows - if(coff->NumberOfSymbols >= pe_utils::max_dword / sizeof(image_symbol) - || !pe_utils::is_sum_safe(coff->NumberOfSymbols * sizeof(image_symbol), coff->LvaToFirstSymbol)) - throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); - - //Check data length again - if(debug_data.length() < coff->NumberOfSymbols * sizeof(image_symbol) + coff->LvaToFirstSymbol) - throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); - - //Create COFF debug info structure - coff_debug_info coff_info(coff); - - //Enumerate debug symbols data - for(uint32_t i = 0; i < coff->NumberOfSymbols; ++i) - { - //Safe sum (checked above) - const image_symbol* sym = reinterpret_cast(debug_data.data() + i * sizeof(image_symbol) + coff->LvaToFirstSymbol); - - coff_debug_info::coff_symbol symbol; - symbol.set_index(i); //Save symbol index - symbol.set_storage_class(sym->StorageClass); //Save storage class - symbol.set_type(sym->Type); //Save storage class - - //Check data length again - if(!pe_utils::is_sum_safe(i, sym->NumberOfAuxSymbols) - || (i + sym->NumberOfAuxSymbols) > coff->NumberOfSymbols - || debug_data.length() < (i + 1) * sizeof(image_symbol) + coff->LvaToFirstSymbol + sym->NumberOfAuxSymbols * sizeof(image_symbol)) - throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); - - //If symbol is filename - if(sym->StorageClass == image_sym_class_file) - { - //Save file name, it is situated just after this IMAGE_SYMBOL structure - std::string file_name(reinterpret_cast(debug_data.data() + (i + 1) * sizeof(image_symbol)), sym->NumberOfAuxSymbols * sizeof(image_symbol)); - pe_utils::strip_nullbytes(file_name); - symbol.set_file_name(file_name); - - //Save symbol info - coff_info.add_symbol(symbol); - - //Move to next symbol - i += sym->NumberOfAuxSymbols; - continue; - } - - //Dump some other symbols - if(((sym->StorageClass == image_sym_class_static) - && (sym->NumberOfAuxSymbols == 0) - && (sym->SectionNumber == 1)) - || - ((sym->StorageClass == image_sym_class_external) - && ISFCN(sym->Type) - && (sym->SectionNumber > 0)) - ) - { - //Save RVA and section number - symbol.set_section_number(sym->SectionNumber); - symbol.set_rva(sym->Value); - - //If symbol has short name - if(sym->N.Name.Short) - { - //Copy and save symbol name - char name_buff[9]; - memcpy(name_buff, sym->N.ShortName, 8); - name_buff[8] = '\0'; - symbol.set_symbol_name(name_buff); - } - else - { - //Symbol has long name - - //Check possible overflows - if(!pe_utils::is_sum_safe(coff->LvaToFirstSymbol + coff->NumberOfSymbols * sizeof(image_symbol), sym->N.Name.Long)) - throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); - - //Here we have an offset to the string table - uint32_t symbol_offset = coff->LvaToFirstSymbol + coff->NumberOfSymbols * sizeof(image_symbol) + sym->N.Name.Long; - - //Check data length - if(debug_data.length() < symbol_offset) - throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); - - //Check symbol name for null-termination - if(!pe_utils::is_null_terminated(debug_data.data() + symbol_offset, debug_data.length() - symbol_offset)) - throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); - - //Save symbol name - symbol.set_symbol_name(debug_data.data() + symbol_offset); - } - - //Save symbol info - coff_info.add_symbol(symbol); - - //Move to next symbol - i += sym->NumberOfAuxSymbols; - continue; - } - } - - info.set_advanced_debug_info(coff_info); - } - break; - - case image_debug_type_codeview: - { - //Check data length - if(debug_data.length() < sizeof(OMFSignature*)) - throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); - - //Get POMFSignature structure pointer from the very beginning of debug data - const OMFSignature* sig = reinterpret_cast(debug_data.data()); - if(!memcmp(sig->Signature, "RSDS", 4)) - { - //Signature is "RSDS" - PDB 7.0 - - //Check data length - if(debug_data.length() < sizeof(CV_INFO_PDB70)) - throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); - - const CV_INFO_PDB70* pdb_data = reinterpret_cast(debug_data.data()); - - //Check PDB file name null-termination - if(!pe_utils::is_null_terminated(pdb_data->PdbFileName, debug_data.length() - (sizeof(CV_INFO_PDB70) - 1 /* BYTE of filename in structure */))) - throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); - - info.set_advanced_debug_info(pdb_7_0_info(pdb_data)); - } - else if(!memcmp(sig->Signature, "NB10", 4)) - { - //Signature is "NB10" - PDB 2.0 - - //Check data length - if(debug_data.length() < sizeof(CV_INFO_PDB20)) - throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); - - const CV_INFO_PDB20* pdb_data = reinterpret_cast(debug_data.data()); - - //Check PDB file name null-termination - if(!pe_utils::is_null_terminated(pdb_data->PdbFileName, debug_data.length() - (sizeof(CV_INFO_PDB20) - 1 /* BYTE of filename in structure */))) - throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); - - info.set_advanced_debug_info(pdb_2_0_info(pdb_data)); - } - else if(!memcmp(sig->Signature, "NB09", 4)) - { - //CodeView 4.0, no structures available - info.set_advanced_info_type(debug_info::advanced_info_codeview_4_0); - } - else if(!memcmp(sig->Signature, "NB11", 4)) - { - //CodeView 5.0, no structures available - info.set_advanced_info_type(debug_info::advanced_info_codeview_5_0); - } - else if(!memcmp(sig->Signature, "NB05", 4)) - { - //Other CodeView, no structures available - info.set_advanced_info_type(debug_info::advanced_info_codeview); - } - } - - break; - - case image_debug_type_misc: - { - //Check data length - if(debug_data.length() < sizeof(image_debug_misc)) - throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); - - //Get misc structure pointer - const image_debug_misc* misc_data = reinterpret_cast(debug_data.data()); - - //Check misc data length - if(debug_data.length() < misc_data->Length /* Total length of record */) - throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); - - //Save advanced information - info.set_advanced_debug_info(misc_debug_info(misc_data)); - } - break; - } - } - - //Save debug information structure - ret.push_back(info); - - //Check possible overflow - if(!pe_utils::is_sum_safe(current_pos, sizeof(image_debug_directory))) - throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory); - - //Go to next debug entry - current_pos += sizeof(image_debug_directory); - directory = pe.section_data_from_rva(current_pos, section_data_virtual, true); - } - - return ret; -} -} diff --git a/drivers/pe_bliss/pe_debug.h b/drivers/pe_bliss/pe_debug.h deleted file mode 100644 index 13fef663c3..0000000000 --- a/drivers/pe_bliss/pe_debug.h +++ /dev/null @@ -1,303 +0,0 @@ -#pragma once -#include -#include "pe_structures.h" -#include "pe_base.h" - -namespace pe_bliss -{ -//Class representing advanced RSDS (PDB 7.0) information -class pdb_7_0_info -{ -public: - //Default constructor - pdb_7_0_info(); - //Constructor from data - explicit pdb_7_0_info(const pe_win::CV_INFO_PDB70* info); - - //Returns debug PDB 7.0 structure GUID - const pe_win::guid get_guid() const; - //Returns age of build - uint32_t get_age() const; - //Returns PDB file name / path - const std::string& get_pdb_file_name() const; - -private: - uint32_t age_; - pe_win::guid guid_; - std::string pdb_file_name_; -}; - -//Class representing advanced NB10 (PDB 2.0) information -class pdb_2_0_info -{ -public: - //Default constructor - pdb_2_0_info(); - //Constructor from data - explicit pdb_2_0_info(const pe_win::CV_INFO_PDB20* info); - - //Returns debug PDB 2.0 structure signature - uint32_t get_signature() const; - //Returns age of build - uint32_t get_age() const; - //Returns PDB file name / path - const std::string& get_pdb_file_name() const; - -private: - uint32_t age_; - uint32_t signature_; - std::string pdb_file_name_; -}; - -//Class representing advanced misc (IMAGE_DEBUG_TYPE_MISC) info -class misc_debug_info -{ -public: - //Default constructor - misc_debug_info(); - //Constructor from data - explicit misc_debug_info(const pe_win::image_debug_misc* info); - - //Returns debug data type - uint32_t get_data_type() const; - //Returns true if data type is exe name - bool is_exe_name() const; - - //Returns true if debug data is UNICODE - bool is_unicode() const; - //Returns debug data (ANSI or UNICODE) - const std::string& get_data_ansi() const; - const std::wstring& get_data_unicode() const; - -private: - uint32_t data_type_; - bool unicode_; - std::string debug_data_ansi_; - std::wstring debug_data_unicode_; -}; - -//Class representing COFF (IMAGE_DEBUG_TYPE_COFF) debug info -class coff_debug_info -{ -public: - //Structure representing COFF symbol - struct coff_symbol - { - public: - //Default constructor - coff_symbol(); - - //Returns storage class - uint32_t get_storage_class() const; - //Returns symbol index - uint32_t get_index() const; - //Returns section number - uint32_t get_section_number() const; - //Returns RVA - uint32_t get_rva() const; - //Returns type - uint16_t get_type() const; - - //Returns true if structure contains file name - bool is_file() const; - //Returns text data (symbol or file name) - const std::string& get_symbol() const; - - public: //These functions do not change everything inside image, they are used by PE class - //Sets storage class - void set_storage_class(uint32_t storage_class); - //Sets symbol index - void set_index(uint32_t index); - //Sets section number - void set_section_number(uint32_t section_number); - //Sets RVA - void set_rva(uint32_t rva); - //Sets type - void set_type(uint16_t type); - - //Sets file name - void set_file_name(const std::string& file_name); - //Sets symbol name - void set_symbol_name(const std::string& symbol_name); - - private: - uint32_t storage_class_; - uint32_t index_; - uint32_t section_number_, rva_; - uint16_t type_; - bool is_filename_; - std::string name_; - }; - -public: - typedef std::vector coff_symbols_list; - -public: - //Default constructor - coff_debug_info(); - //Constructor from data - explicit coff_debug_info(const pe_win::image_coff_symbols_header* info); - - //Returns number of symbols - uint32_t get_number_of_symbols() const; - //Returns virtual address of the first symbol - uint32_t get_lva_to_first_symbol() const; - //Returns number of line-number entries - uint32_t get_number_of_line_numbers() const; - //Returns virtual address of the first line-number entry - uint32_t get_lva_to_first_line_number() const; - //Returns relative virtual address of the first byte of code - uint32_t get_rva_to_first_byte_of_code() const; - //Returns relative virtual address of the last byte of code - uint32_t get_rva_to_last_byte_of_code() const; - //Returns relative virtual address of the first byte of data - uint32_t get_rva_to_first_byte_of_data() const; - //Returns relative virtual address of the last byte of data - uint32_t get_rva_to_last_byte_of_data() const; - - //Returns COFF symbols list - const coff_symbols_list& get_symbols() const; - -public: //These functions do not change everything inside image, they are used by PE class - //Adds COFF symbol - void add_symbol(const coff_symbol& sym); - -private: - uint32_t number_of_symbols_; - uint32_t lva_to_first_symbol_; - uint32_t number_of_line_numbers_; - uint32_t lva_to_first_line_number_; - uint32_t rva_to_first_byte_of_code_; - uint32_t rva_to_last_byte_of_code_; - uint32_t rva_to_first_byte_of_data_; - uint32_t rva_to_last_byte_of_data_; - -private: - coff_symbols_list symbols_; -}; - -//Class representing debug information -class debug_info -{ -public: - //Enumeration of debug information types - enum debug_info_type - { - debug_type_unknown, - debug_type_coff, - debug_type_codeview, - debug_type_fpo, - debug_type_misc, - debug_type_exception, - debug_type_fixup, - debug_type_omap_to_src, - debug_type_omap_from_src, - debug_type_borland, - debug_type_reserved10, - debug_type_clsid - }; - -public: - //Enumeration of advanced debug information types - enum advanced_info_type - { - advanced_info_none, //No advanced info - advanced_info_pdb_7_0, //PDB 7.0 - advanced_info_pdb_2_0, //PDB 2.0 - advanced_info_misc, //MISC debug info - advanced_info_coff, //COFF debug info - //No advanced info structures available for types below - advanced_info_codeview_4_0, //CodeView 4.0 - advanced_info_codeview_5_0, //CodeView 5.0 - advanced_info_codeview //CodeView - }; - -public: - //Default constructor - debug_info(); - //Constructor from data - explicit debug_info(const pe_win::image_debug_directory& debug); - //Copy constructor - debug_info(const debug_info& info); - //Copy assignment operator - debug_info& operator=(const debug_info& info); - //Destructor - ~debug_info(); - - //Returns debug characteristics - uint32_t get_characteristics() const; - //Returns debug datetimestamp - uint32_t get_time_stamp() const; - //Returns major version - uint32_t get_major_version() const; - //Returns minor version - uint32_t get_minor_version() const; - //Returns type of debug info (unchecked) - uint32_t get_type_raw() const; - //Returns type of debug info from debug_info_type enumeration - debug_info_type get_type() const; - //Returns size of debug data (internal, .pdb or other file doesn't count) - uint32_t get_size_of_data() const; - //Returns RVA of debug info when mapped to memory or zero, if info is not mapped - uint32_t get_rva_of_raw_data() const; - //Returns raw file pointer to raw data - uint32_t get_pointer_to_raw_data() const; - - //Returns advanced debug information type - advanced_info_type get_advanced_info_type() const; - //Returns advanced debug information or throws an exception, - //if requested information type is not contained by structure - template - const AdvancedInfo get_advanced_debug_info() const; - -public: //These functions do not change everything inside image, they are used by PE class - //Sets advanced debug information - void set_advanced_debug_info(const pdb_7_0_info& info); - void set_advanced_debug_info(const pdb_2_0_info& info); - void set_advanced_debug_info(const misc_debug_info& info); - void set_advanced_debug_info(const coff_debug_info& info); - - //Sets advanced debug information type, if no advanced info structure available - void set_advanced_info_type(advanced_info_type type); - -private: - uint32_t characteristics_; - uint32_t time_stamp_; - uint32_t major_version_, minor_version_; - uint32_t type_; - uint32_t size_of_data_; - uint32_t address_of_raw_data_; //RVA when mapped or 0 - uint32_t pointer_to_raw_data_; //RAW file offset - - //Union containing advanced debug information pointer - union advanced_info - { - public: - //Default constructor - advanced_info(); - - //Returns true if advanced debug info is present - bool is_present() const; - - public: - pdb_7_0_info* adv_pdb_7_0_info; - pdb_2_0_info* adv_pdb_2_0_info; - misc_debug_info* adv_misc_info; - coff_debug_info* adv_coff_info; - }; - - //Helper for advanced debug information copying - void copy_advanced_info(const debug_info& info); - //Helper for clearing any present advanced debug information - void free_present_advanced_info(); - - advanced_info advanced_debug_info_; - //Advanced information type - advanced_info_type advanced_info_type_; -}; - -typedef std::vector debug_info_list; - -//Returns debug information list -const debug_info_list get_debug_information(const pe_base& pe); -} diff --git a/drivers/pe_bliss/pe_directory.cpp b/drivers/pe_bliss/pe_directory.cpp deleted file mode 100644 index 57ea2212a6..0000000000 --- a/drivers/pe_bliss/pe_directory.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "pe_directory.h" - -namespace pe_bliss -{ -//Default constructor -image_directory::image_directory() - :rva_(0), size_(0) -{} - -//Constructor from data -image_directory::image_directory(uint32_t rva, uint32_t size) - :rva_(rva), size_(size) -{} - -//Returns RVA -uint32_t image_directory::get_rva() const -{ - return rva_; -} - -//Returns size -uint32_t image_directory::get_size() const -{ - return size_; -} - -//Sets RVA -void image_directory::set_rva(uint32_t rva) -{ - rva_ = rva; -} - -//Sets size -void image_directory::set_size(uint32_t size) -{ - size_ = size; -} -} diff --git a/drivers/pe_bliss/pe_directory.h b/drivers/pe_bliss/pe_directory.h deleted file mode 100644 index 77567f9488..0000000000 --- a/drivers/pe_bliss/pe_directory.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once -#include "stdint_defs.h" - -namespace pe_bliss -{ -//Class representing image directory data -class image_directory -{ -public: - //Default constructor - image_directory(); - //Constructor from data - image_directory(uint32_t rva, uint32_t size); - - //Returns RVA - uint32_t get_rva() const; - //Returns size - uint32_t get_size() const; - - //Sets RVA - void set_rva(uint32_t rva); - //Sets size - void set_size(uint32_t size); - -private: - uint32_t rva_; - uint32_t size_; -}; -} diff --git a/drivers/pe_bliss/pe_dotnet.cpp b/drivers/pe_bliss/pe_dotnet.cpp deleted file mode 100644 index 5d9e483e3f..0000000000 --- a/drivers/pe_bliss/pe_dotnet.cpp +++ /dev/null @@ -1,165 +0,0 @@ -#include -#include "pe_dotnet.h" - -namespace pe_bliss -{ -using namespace pe_win; - -//.NET -basic_dotnet_info::basic_dotnet_info() -{ - memset(&header_, 0, sizeof(header_)); -} - -//Constructor from data -basic_dotnet_info::basic_dotnet_info(const image_cor20_header& header) - :header_(header) -{} - -//Returns major runtime version -uint16_t basic_dotnet_info::get_major_runtime_version() const -{ - return header_.MajorRuntimeVersion; -} - -//Returns minor runtime version -uint16_t basic_dotnet_info::get_minor_runtime_version() const -{ - return header_.MinorRuntimeVersion; -} - -//Returns RVA of metadata (symbol table and startup information) -uint32_t basic_dotnet_info::get_rva_of_metadata() const -{ - return header_.MetaData.VirtualAddress; -} - -//Returns size of metadata (symbol table and startup information) -uint32_t basic_dotnet_info::get_size_of_metadata() const -{ - return header_.MetaData.Size; -} - -//Returns flags -uint32_t basic_dotnet_info::get_flags() const -{ - return header_.Flags; -} - -//Returns true if entry point is native -bool basic_dotnet_info::is_native_entry_point() const -{ - return (header_.Flags & comimage_flags_native_entrypoint) ? true : false; -} - -//Returns true if 32 bit required -bool basic_dotnet_info::is_32bit_required() const -{ - return (header_.Flags & comimage_flags_32bitrequired) ? true : false; -} - -//Returns true if image is IL library -bool basic_dotnet_info::is_il_library() const -{ - return (header_.Flags & comimage_flags_il_library) ? true : false; -} - -//Returns true if image uses IL only -bool basic_dotnet_info::is_il_only() const -{ - return (header_.Flags & comimage_flags_ilonly) ? true : false; -} - -//Returns entry point RVA (if entry point is native) -//Returns entry point managed token (if entry point is managed) -uint32_t basic_dotnet_info::get_entry_point_rva_or_token() const -{ - return header_.EntryPointToken; -} - -//Returns RVA of managed resources -uint32_t basic_dotnet_info::get_rva_of_resources() const -{ - return header_.Resources.VirtualAddress; -} - -//Returns size of managed resources -uint32_t basic_dotnet_info::get_size_of_resources() const -{ - return header_.Resources.Size; -} - -//Returns RVA of strong name signature -uint32_t basic_dotnet_info::get_rva_of_strong_name_signature() const -{ - return header_.StrongNameSignature.VirtualAddress; -} - -//Returns size of strong name signature -uint32_t basic_dotnet_info::get_size_of_strong_name_signature() const -{ - return header_.StrongNameSignature.Size; -} - -//Returns RVA of code manager table -uint32_t basic_dotnet_info::get_rva_of_code_manager_table() const -{ - return header_.CodeManagerTable.VirtualAddress; -} - -//Returns size of code manager table -uint32_t basic_dotnet_info::get_size_of_code_manager_table() const -{ - return header_.CodeManagerTable.Size; -} - -//Returns RVA of VTable fixups -uint32_t basic_dotnet_info::get_rva_of_vtable_fixups() const -{ - return header_.VTableFixups.VirtualAddress; -} - -//Returns size of VTable fixups -uint32_t basic_dotnet_info::get_size_of_vtable_fixups() const -{ - return header_.VTableFixups.Size; -} - -//Returns RVA of export address table jumps -uint32_t basic_dotnet_info::get_rva_of_export_address_table_jumps() const -{ - return header_.ExportAddressTableJumps.VirtualAddress; -} - -//Returns size of export address table jumps -uint32_t basic_dotnet_info::get_size_of_export_address_table_jumps() const -{ - return header_.ExportAddressTableJumps.Size; -} - -//Returns RVA of managed native header -//(precompiled header info, usually set to zero, for internal use) -uint32_t basic_dotnet_info::get_rva_of_managed_native_header() const -{ - return header_.ManagedNativeHeader.VirtualAddress; -} - -//Returns size of managed native header -//(precompiled header info, usually set to zero, for internal use) -uint32_t basic_dotnet_info::get_size_of_managed_native_header() const -{ - return header_.ManagedNativeHeader.Size; -} - -//Returns basic .NET information -//If image is not native, throws an exception -const basic_dotnet_info get_basic_dotnet_info(const pe_base& pe) -{ - //If there's no debug directory, return empty list - if(!pe.is_dotnet()) - throw pe_exception("Image does not have managed code", pe_exception::image_does_not_have_managed_code); - - //Return basic .NET information - return basic_dotnet_info(pe.section_data_from_rva(pe.get_directory_rva(image_directory_entry_com_descriptor), section_data_virtual, true)); -} -} diff --git a/drivers/pe_bliss/pe_dotnet.h b/drivers/pe_bliss/pe_dotnet.h deleted file mode 100644 index e0dad3a721..0000000000 --- a/drivers/pe_bliss/pe_dotnet.h +++ /dev/null @@ -1,76 +0,0 @@ -#pragma once -#include "pe_structures.h" -#include "pe_base.h" - -namespace pe_bliss -{ -//Class representing basic .NET header information -class basic_dotnet_info -{ -public: - //Default constructor - basic_dotnet_info(); - //Constructor from data - explicit basic_dotnet_info(const pe_win::image_cor20_header& header); - - //Returns major runtime version - uint16_t get_major_runtime_version() const; - //Returns minor runtime version - uint16_t get_minor_runtime_version() const; - - //Returns RVA of metadata (symbol table and startup information) - uint32_t get_rva_of_metadata() const; - //Returns size of metadata (symbol table and startup information) - uint32_t get_size_of_metadata() const; - - //Returns flags - uint32_t get_flags() const; - - //Returns true if entry point is native - bool is_native_entry_point() const; - //Returns true if 32 bit required - bool is_32bit_required() const; - //Returns true if image is IL library - bool is_il_library() const; - //Returns true if image uses IL only - bool is_il_only() const; - - //Returns entry point RVA (if entry point is native) - //Returns entry point managed token (if entry point is managed) - uint32_t get_entry_point_rva_or_token() const; - - //Returns RVA of managed resources - uint32_t get_rva_of_resources() const; - //Returns size of managed resources - uint32_t get_size_of_resources() const; - //Returns RVA of strong name signature - uint32_t get_rva_of_strong_name_signature() const; - //Returns size of strong name signature - uint32_t get_size_of_strong_name_signature() const; - //Returns RVA of code manager table - uint32_t get_rva_of_code_manager_table() const; - //Returns size of code manager table - uint32_t get_size_of_code_manager_table() const; - //Returns RVA of VTable fixups - uint32_t get_rva_of_vtable_fixups() const; - //Returns size of VTable fixups - uint32_t get_size_of_vtable_fixups() const; - //Returns RVA of export address table jumps - uint32_t get_rva_of_export_address_table_jumps() const; - //Returns size of export address table jumps - uint32_t get_size_of_export_address_table_jumps() const; - //Returns RVA of managed native header - //(precompiled header info, usually set to zero, for internal use) - uint32_t get_rva_of_managed_native_header() const; - //Returns size of managed native header - //(precompiled header info, usually set to zero, for internal use) - uint32_t get_size_of_managed_native_header() const; - -private: - pe_win::image_cor20_header header_; -}; - -//Returns basic .NET information -//If image is not native, throws an exception -const basic_dotnet_info get_basic_dotnet_info(const pe_base& pe); -} diff --git a/drivers/pe_bliss/pe_exception.cpp b/drivers/pe_bliss/pe_exception.cpp deleted file mode 100644 index eb76f28a35..0000000000 --- a/drivers/pe_bliss/pe_exception.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "pe_exception.h" - -namespace pe_bliss -{ -//PE exception class constructors -pe_exception::pe_exception(const char* text, exception_id id) - :std::runtime_error(text), id_(id) -{} - -pe_exception::pe_exception(const std::string& text, exception_id id) - :std::runtime_error(text), id_(id) -{} - -//Returns exception ID -pe_exception::exception_id pe_exception::get_id() const -{ - return id_; -} -} diff --git a/drivers/pe_bliss/pe_exception.h b/drivers/pe_bliss/pe_exception.h deleted file mode 100644 index a51eba7d73..0000000000 --- a/drivers/pe_bliss/pe_exception.h +++ /dev/null @@ -1,109 +0,0 @@ -#pragma once -#include -#include - -namespace pe_bliss -{ -//PE exception class -class pe_exception : public std::runtime_error -{ -public: - //Exception IDs - enum exception_id - { - unknown_error, - bad_pe_file, - bad_dos_header, - image_nt_headers_not_found, - error_reading_image_nt_headers, - error_reading_data_directories, - error_reading_file, - pe_signature_incorrect, - incorrect_number_of_rva_and_sizes, - error_changing_section_virtual_size, - section_number_incorrect, - section_table_incorrect, - incorrect_section_alignment, - incorrect_file_alignment, - incorrect_size_of_image, - incorrect_size_of_headers, - image_section_headers_not_found, - zero_section_sizes, - section_incorrect_addr_or_size, - section_not_found, - image_section_data_not_found, - no_section_found, - image_section_table_incorrect, - directory_does_not_exist, - rva_not_exists, - error_reading_section_header, - error_reading_overlay, - incorrect_address_conversion, - - incorrect_export_directory, - incorrect_import_directory, - incorrect_relocation_directory, - incorrect_tls_directory, - incorrect_config_directory, - incorrect_bound_import_directory, - incorrect_resource_directory, - incorrect_exception_directory, - incorrect_debug_directory, - - resource_directory_entry_error, - resource_directory_entry_not_found, - resource_data_entry_not_found, - resource_incorrect_bitmap, - resource_incorrect_icon, - resource_incorrect_cursor, - resource_incorrect_string_table, - resource_string_not_found, - resource_incorrect_message_table, - resource_incorrect_version_info, - - advanced_debug_information_request_error, - image_does_not_have_managed_code, - - section_is_empty, - data_is_empty, - stream_is_bad, - - section_is_not_attached, - insufficient_space, - - cannot_rebase_relocations, - - exports_list_is_empty, - duplicate_exported_function_ordinal, - duplicate_exported_function_name, - - version_info_string_does_not_exist, - - no_more_sections_can_be_added, - - no_icon_group_found, - no_cursor_group_found, - - encoding_convertion_error, - - error_expanding_section, - - cannot_rebuild_image - }; - -public: - //Class constructors - explicit pe_exception(const char* text, exception_id id = unknown_error); - explicit pe_exception(const std::string& text, exception_id id = unknown_error); - - //Returns exception ID from exception_id enumeration - exception_id get_id() const; - - //Destructor - virtual ~pe_exception() throw() - {} - -private: - exception_id id_; -}; -} diff --git a/drivers/pe_bliss/pe_exception_directory.cpp b/drivers/pe_bliss/pe_exception_directory.cpp deleted file mode 100644 index 3447e5bd7a..0000000000 --- a/drivers/pe_bliss/pe_exception_directory.cpp +++ /dev/null @@ -1,156 +0,0 @@ -#include "pe_exception_directory.h" - -namespace pe_bliss -{ -using namespace pe_win; - -//EXCEPTION DIRECTORY (exists on PE+ only) -//Default constructor -exception_entry::exception_entry() - :begin_address_(0), end_address_(0), unwind_info_address_(0), - unwind_info_version_(0), - flags_(0), - size_of_prolog_(0), - count_of_codes_(0), - frame_register_(0), - frame_offset_(0) -{} - -//Constructor from data -exception_entry::exception_entry(const image_runtime_function_entry& entry, const unwind_info& unwind_info) - :begin_address_(entry.BeginAddress), end_address_(entry.EndAddress), unwind_info_address_(entry.UnwindInfoAddress), - unwind_info_version_(unwind_info.Version), - flags_(unwind_info.Flags), - size_of_prolog_(unwind_info.SizeOfProlog), - count_of_codes_(unwind_info.CountOfCodes), - frame_register_(unwind_info.FrameRegister), - frame_offset_(unwind_info.FrameOffset) -{} - -//Returns starting address of function, affected by exception unwinding -uint32_t exception_entry::get_begin_address() const -{ - return begin_address_; -} - -//Returns ending address of function, affected by exception unwinding -uint32_t exception_entry::get_end_address() const -{ - return end_address_; -} - -//Returns unwind info address -uint32_t exception_entry::get_unwind_info_address() const -{ - return unwind_info_address_; -} - -//Returns UNWIND_INFO structure version -uint8_t exception_entry::get_unwind_info_version() const -{ - return unwind_info_version_; -} - -//Returns unwind info flags -uint8_t exception_entry::get_flags() const -{ - return flags_; -} - -//The function has an exception handler that should be called -//when looking for functions that need to examine exceptions -bool exception_entry::has_exception_handler() const -{ - return (flags_ & unw_flag_ehandler) ? true : false; -} - -//The function has a termination handler that should be called -//when unwinding an exception -bool exception_entry::has_termination_handler() const -{ - return (flags_ & unw_flag_uhandler) ? true : false; -} - -//The unwind info structure is not the primary one for the procedure -bool exception_entry::is_chaininfo() const -{ - return (flags_ & unw_flag_chaininfo) ? true : false; -} - -//Returns size of function prolog -uint8_t exception_entry::get_size_of_prolog() const -{ - return size_of_prolog_; -} - -//Returns number of unwind slots -uint8_t exception_entry::get_number_of_unwind_slots() const -{ - return count_of_codes_; -} - -//If the function uses frame pointer -bool exception_entry::uses_frame_pointer() const -{ - return frame_register_ != 0; -} - -//Number of the nonvolatile register used as the frame pointer, -//using the same encoding for the operation info field of UNWIND_CODE nodes -uint8_t exception_entry::get_frame_pointer_register_number() const -{ - return frame_register_; -} - -//The scaled offset from RSP that is applied to the FP reg when it is established. -//The actual FP reg is set to RSP + 16 * this number, allowing offsets from 0 to 240 -uint8_t exception_entry::get_scaled_rsp_offset() const -{ - return frame_offset_; -} - -//Returns exception directory data (exists on PE+ only) -//Unwind opcodes are not listed, because their format and list are subject to change -const exception_entry_list get_exception_directory_data(const pe_base& pe) -{ - exception_entry_list ret; - - //If image doesn't have exception directory, return empty list - if(!pe.has_exception_directory()) - return ret; - - //Check the length in bytes of the section containing exception directory - if(pe.section_data_length_from_rva(pe.get_directory_rva(image_directory_entry_exception), pe.get_directory_rva(image_directory_entry_exception), section_data_virtual, true) - < sizeof(image_runtime_function_entry)) - throw pe_exception("Incorrect exception directory", pe_exception::incorrect_exception_directory); - - unsigned long current_pos = pe.get_directory_rva(image_directory_entry_exception); - - //Check if structures are DWORD-aligned - if(current_pos % sizeof(uint32_t)) - throw pe_exception("Incorrect exception directory", pe_exception::incorrect_exception_directory); - - //First IMAGE_RUNTIME_FUNCTION_ENTRY table - image_runtime_function_entry exception_table = pe.section_data_from_rva(current_pos, section_data_virtual, true); - - //todo: virtual addresses BeginAddress and EndAddress are not checked to be inside image - while(exception_table.BeginAddress) - { - //Check addresses - if(exception_table.BeginAddress > exception_table.EndAddress) - throw pe_exception("Incorrect exception directory", pe_exception::incorrect_exception_directory); - - //Get unwind information - unwind_info info = pe.section_data_from_rva(exception_table.UnwindInfoAddress, section_data_virtual, true); - - //Create exception entry and save it - ret.push_back(exception_entry(exception_table, info)); - - //Go to next exception entry - current_pos += sizeof(image_runtime_function_entry); - exception_table = pe.section_data_from_rva(current_pos, section_data_virtual, true); - } - - return ret; -} -} diff --git a/drivers/pe_bliss/pe_exception_directory.h b/drivers/pe_bliss/pe_exception_directory.h deleted file mode 100644 index 9f9ee14cae..0000000000 --- a/drivers/pe_bliss/pe_exception_directory.h +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once -#include -#include "pe_structures.h" -#include "pe_base.h" - -namespace pe_bliss -{ -//Class representing exception directory entry -class exception_entry -{ -public: - //Default constructor - exception_entry(); - //Constructor from data - exception_entry(const pe_win::image_runtime_function_entry& entry, const pe_win::unwind_info& unwind_info); - - //Returns starting address of function, affected by exception unwinding - uint32_t get_begin_address() const; - //Returns ending address of function, affected by exception unwinding - uint32_t get_end_address() const; - //Returns unwind info address - uint32_t get_unwind_info_address() const; - - //Returns UNWIND_INFO structure version - uint8_t get_unwind_info_version() const; - - //Returns unwind info flags - uint8_t get_flags() const; - //The function has an exception handler that should be called - //when looking for functions that need to examine exceptions - bool has_exception_handler() const; - //The function has a termination handler that should be called - //when unwinding an exception - bool has_termination_handler() const; - //The unwind info structure is not the primary one for the procedure - bool is_chaininfo() const; - - //Returns size of function prolog - uint8_t get_size_of_prolog() const; - - //Returns number of unwind slots - uint8_t get_number_of_unwind_slots() const; - - //If the function uses frame pointer - bool uses_frame_pointer() const; - //Number of the nonvolatile register used as the frame pointer, - //using the same encoding for the operation info field of UNWIND_CODE nodes - uint8_t get_frame_pointer_register_number() const; - //The scaled offset from RSP that is applied to the FP reg when it is established. - //The actual FP reg is set to RSP + 16 * this number, allowing offsets from 0 to 240 - uint8_t get_scaled_rsp_offset() const; - -private: - uint32_t begin_address_, end_address_, unwind_info_address_; - uint8_t unwind_info_version_; - uint8_t flags_; - uint8_t size_of_prolog_; - uint8_t count_of_codes_; - uint8_t frame_register_, frame_offset_; -}; - -typedef std::vector exception_entry_list; - -//Returns exception directory data (exists on PE+ only) -//Unwind opcodes are not listed, because their format and list are subject to change -const exception_entry_list get_exception_directory_data(const pe_base& pe); -} diff --git a/drivers/pe_bliss/pe_exports.cpp b/drivers/pe_bliss/pe_exports.cpp deleted file mode 100644 index 4a1bc1d82f..0000000000 --- a/drivers/pe_bliss/pe_exports.cpp +++ /dev/null @@ -1,679 +0,0 @@ -#include -#include -#include -#include "pe_exports.h" -#include "utils.h" - -namespace pe_bliss -{ -using namespace pe_win; - -//EXPORTS -//Default constructor -exported_function::exported_function() - :ordinal_(0), rva_(0), has_name_(false), name_ordinal_(0), forward_(false) -{} - -//Returns ordinal of function (actually, ordinal = hint + ordinal base) -uint16_t exported_function::get_ordinal() const -{ - return ordinal_; -} - -//Returns RVA of function -uint32_t exported_function::get_rva() const -{ - return rva_; -} - -//Returns name of function -const std::string& exported_function::get_name() const -{ - return name_; -} - -//Returns true if function has name and name ordinal -bool exported_function::has_name() const -{ - return has_name_; -} - -//Returns name ordinal of function -uint16_t exported_function::get_name_ordinal() const -{ - return name_ordinal_; -} - -//Returns true if function is forwarded to other library -bool exported_function::is_forwarded() const -{ - return forward_; -} - -//Returns the name of forwarded function -const std::string& exported_function::get_forwarded_name() const -{ - return forward_name_; -} - -//Sets ordinal of function -void exported_function::set_ordinal(uint16_t ordinal) -{ - ordinal_ = ordinal; -} - -//Sets RVA of function -void exported_function::set_rva(uint32_t rva) -{ - rva_ = rva; -} - -//Sets name of function (or clears it, if empty name is passed) -void exported_function::set_name(const std::string& name) -{ - name_ = name; - has_name_ = !name.empty(); -} - -//Sets name ordinal -void exported_function::set_name_ordinal(uint16_t name_ordinal) -{ - name_ordinal_ = name_ordinal; -} - -//Sets forwarded function name (or clears it, if empty name is passed) -void exported_function::set_forwarded_name(const std::string& name) -{ - forward_name_ = name; - forward_ = !name.empty(); -} - -//Default constructor -export_info::export_info() - :characteristics_(0), - timestamp_(0), - major_version_(0), - minor_version_(0), - ordinal_base_(0), - number_of_functions_(0), - number_of_names_(0), - address_of_functions_(0), - address_of_names_(0), - address_of_name_ordinals_(0) -{} - -//Returns characteristics -uint32_t export_info::get_characteristics() const -{ - return characteristics_; -} - -//Returns timestamp -uint32_t export_info::get_timestamp() const -{ - return timestamp_; -} - -//Returns major version -uint16_t export_info::get_major_version() const -{ - return major_version_; -} - -//Returns minor version -uint16_t export_info::get_minor_version() const -{ - return minor_version_; -} - -//Returns DLL name -const std::string& export_info::get_name() const -{ - return name_; -} - -//Returns ordinal base -uint32_t export_info::get_ordinal_base() const -{ - return ordinal_base_; -} - -//Returns number of functions -uint32_t export_info::get_number_of_functions() const -{ - return number_of_functions_; -} - -//Returns number of function names -uint32_t export_info::get_number_of_names() const -{ - return number_of_names_; -} - -//Returns RVA of function address table -uint32_t export_info::get_rva_of_functions() const -{ - return address_of_functions_; -} - -//Returns RVA of function name address table -uint32_t export_info::get_rva_of_names() const -{ - return address_of_names_; -} - -//Returns RVA of name ordinals table -uint32_t export_info::get_rva_of_name_ordinals() const -{ - return address_of_name_ordinals_; -} - -//Sets characteristics -void export_info::set_characteristics(uint32_t characteristics) -{ - characteristics_ = characteristics; -} - -//Sets timestamp -void export_info::set_timestamp(uint32_t timestamp) -{ - timestamp_ = timestamp; -} - -//Sets major version -void export_info::set_major_version(uint16_t major_version) -{ - major_version_ = major_version; -} - -//Sets minor version -void export_info::set_minor_version(uint16_t minor_version) -{ - minor_version_ = minor_version; -} - -//Sets DLL name -void export_info::set_name(const std::string& name) -{ - name_ = name; -} - -//Sets ordinal base -void export_info::set_ordinal_base(uint32_t ordinal_base) -{ - ordinal_base_ = ordinal_base; -} - -//Sets number of functions -void export_info::set_number_of_functions(uint32_t number_of_functions) -{ - number_of_functions_ = number_of_functions; -} - -//Sets number of function names -void export_info::set_number_of_names(uint32_t number_of_names) -{ - number_of_names_ = number_of_names; -} - -//Sets RVA of function address table -void export_info::set_rva_of_functions(uint32_t rva_of_functions) -{ - address_of_functions_ = rva_of_functions; -} - -//Sets RVA of function name address table -void export_info::set_rva_of_names(uint32_t rva_of_names) -{ - address_of_names_ = rva_of_names; -} - -//Sets RVA of name ordinals table -void export_info::set_rva_of_name_ordinals(uint32_t rva_of_name_ordinals) -{ - address_of_name_ordinals_ = rva_of_name_ordinals; -} - -const exported_functions_list get_exported_functions(const pe_base& pe, export_info* info); - -//Returns array of exported functions -const exported_functions_list get_exported_functions(const pe_base& pe) -{ - return get_exported_functions(pe, 0); -} - -//Returns array of exported functions and information about export -const exported_functions_list get_exported_functions(const pe_base& pe, export_info& info) -{ - return get_exported_functions(pe, &info); -} - -//Helper: sorts exported function list by ordinals -struct ordinal_sorter -{ -public: - bool operator()(const exported_function& func1, const exported_function& func2) const; -}; - -//Returns array of exported functions and information about export (if info != 0) -const exported_functions_list get_exported_functions(const pe_base& pe, export_info* info) -{ - //Returned exported functions info array - std::vector ret; - - if(pe.has_exports()) - { - //Check the length in bytes of the section containing export directory - if(pe.section_data_length_from_rva(pe.get_directory_rva(image_directory_entry_export), - pe.get_directory_rva(image_directory_entry_export), section_data_virtual, true) - < sizeof(image_export_directory)) - throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory); - - image_export_directory exports = pe.section_data_from_rva(pe.get_directory_rva(image_directory_entry_export), section_data_virtual, true); - - unsigned long max_name_length; - - if(info) - { - //Save some export info data - info->set_characteristics(exports.Characteristics); - info->set_major_version(exports.MajorVersion); - info->set_minor_version(exports.MinorVersion); - - //Get byte count that we have for dll name - if((max_name_length = pe.section_data_length_from_rva(exports.Name, exports.Name, section_data_virtual, true)) < 2) - throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory); - - //Get dll name pointer - const char* dll_name = pe.section_data_from_rva(exports.Name, section_data_virtual, true); - - //Check for null-termination - if(!pe_utils::is_null_terminated(dll_name, max_name_length)) - throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory); - - //Save the rest of export information data - info->set_name(dll_name); - info->set_number_of_functions(exports.NumberOfFunctions); - info->set_number_of_names(exports.NumberOfNames); - info->set_ordinal_base(exports.Base); - info->set_rva_of_functions(exports.AddressOfFunctions); - info->set_rva_of_names(exports.AddressOfNames); - info->set_rva_of_name_ordinals(exports.AddressOfNameOrdinals); - info->set_timestamp(exports.TimeDateStamp); - } - - if(!exports.NumberOfFunctions) - return ret; - - //Check IMAGE_EXPORT_DIRECTORY fields - if(exports.NumberOfNames > exports.NumberOfFunctions) - throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory); - - //Check some export directory fields - if((!exports.AddressOfNameOrdinals && exports.AddressOfNames) || - (exports.AddressOfNameOrdinals && !exports.AddressOfNames) || - !exports.AddressOfFunctions - || exports.NumberOfFunctions >= pe_utils::max_dword / sizeof(uint32_t) - || exports.NumberOfNames > pe_utils::max_dword / sizeof(uint32_t) - || !pe_utils::is_sum_safe(exports.AddressOfFunctions, exports.NumberOfFunctions * sizeof(uint32_t)) - || !pe_utils::is_sum_safe(exports.AddressOfNames, exports.NumberOfNames * sizeof(uint32_t)) - || !pe_utils::is_sum_safe(exports.AddressOfNameOrdinals, exports.NumberOfFunctions * sizeof(uint32_t)) - || !pe_utils::is_sum_safe(pe.get_directory_rva(image_directory_entry_export), pe.get_directory_size(image_directory_entry_export))) - throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory); - - //Check if it is enough bytes to hold AddressOfFunctions table - if(pe.section_data_length_from_rva(exports.AddressOfFunctions, exports.AddressOfFunctions, section_data_virtual, true) - < exports.NumberOfFunctions * sizeof(uint32_t)) - throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory); - - if(exports.AddressOfNames) - { - //Check if it is enough bytes to hold name and ordinal tables - if(pe.section_data_length_from_rva(exports.AddressOfNameOrdinals, exports.AddressOfNameOrdinals, section_data_virtual, true) - < exports.NumberOfNames * sizeof(uint16_t)) - throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory); - - if(pe.section_data_length_from_rva(exports.AddressOfNames, exports.AddressOfNames, section_data_virtual, true) - < exports.NumberOfNames * sizeof(uint32_t)) - throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory); - } - - for(uint32_t ordinal = 0; ordinal < exports.NumberOfFunctions; ordinal++) - { - //Get function address - //Sum and multiplication are safe (checked above) - uint32_t rva = pe.section_data_from_rva(exports.AddressOfFunctions + ordinal * sizeof(uint32_t), section_data_virtual, true); - - //If we have a skip - if(!rva) - continue; - - exported_function func; - func.set_rva(rva); - - if(!pe_utils::is_sum_safe(exports.Base, ordinal) || exports.Base + ordinal > pe_utils::max_word) - throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory); - - func.set_ordinal(static_cast(ordinal + exports.Base)); - - //Scan for function name ordinal - for(uint32_t i = 0; i < exports.NumberOfNames; i++) - { - uint16_t ordinal2 = pe.section_data_from_rva(exports.AddressOfNameOrdinals + i * sizeof(uint16_t), section_data_virtual, true); - - //If function has name (and name ordinal) - if(ordinal == ordinal2) - { - //Get function name - //Sum and multiplication are safe (checked above) - uint32_t function_name_rva = pe.section_data_from_rva(exports.AddressOfNames + i * sizeof(uint32_t), section_data_virtual, true); - - //Get byte count that we have for function name - if((max_name_length = pe.section_data_length_from_rva(function_name_rva, function_name_rva, section_data_virtual, true)) < 2) - throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory); - - //Get function name pointer - const char* func_name = pe.section_data_from_rva(function_name_rva, section_data_virtual, true); - - //Check for null-termination - if(!pe_utils::is_null_terminated(func_name, max_name_length)) - throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory); - - //Save function info - func.set_name(func_name); - func.set_name_ordinal(ordinal2); - - //If the function is just a redirect, save its name - if(rva >= pe.get_directory_rva(image_directory_entry_export) + sizeof(image_directory_entry_export) && - rva < pe.get_directory_rva(image_directory_entry_export) + pe.get_directory_size(image_directory_entry_export)) - { - if((max_name_length = pe.section_data_length_from_rva(rva, rva, section_data_virtual, true)) < 2) - throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory); - - //Get forwarded function name pointer - const char* forwarded_func_name = pe.section_data_from_rva(rva, section_data_virtual, true); - - //Check for null-termination - if(!pe_utils::is_null_terminated(forwarded_func_name, max_name_length)) - throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory); - - //Set the name of forwarded function - func.set_forwarded_name(forwarded_func_name); - } - - break; - } - } - - //Add function info to output array - ret.push_back(func); - } - } - - return ret; -} - -//Helper export functions -//Returns pair: -const std::pair get_export_ordinal_limits(const exported_functions_list& exports) -{ - if(exports.empty()) - return std::make_pair(0, 0); - - uint16_t max_ordinal = 0; //Maximum ordinal number - uint16_t ordinal_base = pe_utils::max_word; //Minimum ordinal value - for(exported_functions_list::const_iterator it = exports.begin(); it != exports.end(); ++it) - { - const exported_function& func = (*it); - - //Calculate maximum and minimum ordinal numbers - max_ordinal = std::max(max_ordinal, func.get_ordinal()); - ordinal_base = std::min(ordinal_base, func.get_ordinal()); - } - - return std::make_pair(ordinal_base, max_ordinal); -} - -//Checks if exported function name already exists -bool exported_name_exists(const std::string& function_name, const exported_functions_list& exports) -{ - for(exported_functions_list::const_iterator it = exports.begin(); it != exports.end(); ++it) - { - if((*it).has_name() && (*it).get_name() == function_name) - return true; - } - - return false; -} - -//Checks if exported function name already exists -bool exported_ordinal_exists(uint16_t ordinal, const exported_functions_list& exports) -{ - for(exported_functions_list::const_iterator it = exports.begin(); it != exports.end(); ++it) - { - if((*it).get_ordinal() == ordinal) - return true; - } - - return false; -} - -//Helper: sorts exported function list by ordinals -bool ordinal_sorter::operator()(const exported_function& func1, const exported_function& func2) const -{ - return func1.get_ordinal() < func2.get_ordinal(); -} - -//Export directory rebuilder -//info - export information -//exported_functions_list - list of exported functions -//exports_section - section where export directory will be placed (must be attached to PE image) -//offset_from_section_start - offset from exports_section raw data start -//save_to_pe_headers - if true, new export directory information will be saved to PE image headers -//auto_strip_last_section - if true and exports are placed in the last section, it will be automatically stripped -//number_of_functions and number_of_names parameters don't matter in "info" when rebuilding, they're calculated independently -//characteristics, major_version, minor_version, timestamp and name are the only used members of "info" structure -//Returns new export directory information -//exported_functions_list is copied intentionally to be sorted by ordinal values later -//Name ordinals in exported function don't matter, they will be recalculated -const image_directory rebuild_exports(pe_base& pe, const export_info& info, exported_functions_list exports, section& exports_section, uint32_t offset_from_section_start, bool save_to_pe_header, bool auto_strip_last_section) -{ - //Check that exports_section is attached to this PE image - if(!pe.section_attached(exports_section)) - throw pe_exception("Exports section must be attached to PE file", pe_exception::section_is_not_attached); - - //Needed space for strings - uint32_t needed_size_for_strings = static_cast(info.get_name().length() + 1); - uint32_t number_of_names = 0; //Number of named functions - uint32_t max_ordinal = 0; //Maximum ordinal number - uint32_t ordinal_base = static_cast(-1); //Minimum ordinal value - - if(exports.empty()) - ordinal_base = info.get_ordinal_base(); - - uint32_t needed_size_for_function_names = 0; //Needed space for function name strings - uint32_t needed_size_for_function_forwards = 0; //Needed space for function forwards names - - //List all exported functions - //Calculate needed size for function list - { - //Also check that there're no duplicate names and ordinals - std::set used_function_names; - std::set used_function_ordinals; - - for(exported_functions_list::const_iterator it = exports.begin(); it != exports.end(); ++it) - { - const exported_function& func = (*it); - //Calculate maximum and minimum ordinal numbers - max_ordinal = std::max(max_ordinal, func.get_ordinal()); - ordinal_base = std::min(ordinal_base, func.get_ordinal()); - - //Check if ordinal is unique - if(!used_function_ordinals.insert(func.get_ordinal()).second) - throw pe_exception("Duplicate exported function ordinal", pe_exception::duplicate_exported_function_ordinal); - - if(func.has_name()) - { - //If function is named - ++number_of_names; - needed_size_for_function_names += static_cast(func.get_name().length() + 1); - - //Check if it's name and name ordinal are unique - if(!used_function_names.insert(func.get_name()).second) - throw pe_exception("Duplicate exported function name", pe_exception::duplicate_exported_function_name); - } - - //If function is forwarded to another DLL - if(func.is_forwarded()) - needed_size_for_function_forwards += static_cast(func.get_forwarded_name().length() + 1); - } - } - - //Sort functions by ordinal value - std::sort(exports.begin(), exports.end(), ordinal_sorter()); - - //Calculate needed space for different things... - needed_size_for_strings += needed_size_for_function_names; - needed_size_for_strings += needed_size_for_function_forwards; - uint32_t needed_size_for_function_name_ordinals = number_of_names * sizeof(uint16_t); - uint32_t needed_size_for_function_name_rvas = number_of_names * sizeof(uint32_t); - uint32_t needed_size_for_function_addresses = (max_ordinal - ordinal_base + 1) * sizeof(uint32_t); - - //Export directory header will be placed first - uint32_t directory_pos = pe_utils::align_up(offset_from_section_start, sizeof(uint32_t)); - - uint32_t needed_size = sizeof(image_export_directory); //Calculate needed size for export tables and strings - //sizeof(IMAGE_EXPORT_DIRECTORY) = export directory header - - //Total needed space... - needed_size += needed_size_for_function_name_ordinals; //For list of names ordinals - needed_size += needed_size_for_function_addresses; //For function RVAs - needed_size += needed_size_for_strings; //For all strings - needed_size += needed_size_for_function_name_rvas; //For function name strings RVAs - - //Check if exports_section is last one. If it's not, check if there's enough place for exports data - if(&exports_section != &*(pe.get_image_sections().end() - 1) && - (exports_section.empty() || pe_utils::align_up(exports_section.get_size_of_raw_data(), pe.get_file_alignment()) < needed_size + directory_pos)) - throw pe_exception("Insufficient space for export directory", pe_exception::insufficient_space); - - std::string& raw_data = exports_section.get_raw_data(); - - //This will be done only if exports_section is the last section of image or for section with unaligned raw length of data - if(raw_data.length() < needed_size + directory_pos) - raw_data.resize(needed_size + directory_pos); //Expand section raw data - - //Library name will be placed after it - uint32_t current_pos_of_function_names = static_cast(info.get_name().length() + 1 + directory_pos + sizeof(image_export_directory)); - //Next - function names - uint32_t current_pos_of_function_name_ordinals = current_pos_of_function_names + needed_size_for_function_names; - //Next - function name ordinals - uint32_t current_pos_of_function_forwards = current_pos_of_function_name_ordinals + needed_size_for_function_name_ordinals; - //Finally - function addresses - uint32_t current_pos_of_function_addresses = current_pos_of_function_forwards + needed_size_for_function_forwards; - //Next - function names RVAs - uint32_t current_pos_of_function_names_rvas = current_pos_of_function_addresses + needed_size_for_function_addresses; - - { - //Create export directory and fill it - image_export_directory dir = {0}; - dir.Characteristics = info.get_characteristics(); - dir.MajorVersion = info.get_major_version(); - dir.MinorVersion = info.get_minor_version(); - dir.TimeDateStamp = info.get_timestamp(); - dir.NumberOfFunctions = max_ordinal - ordinal_base + 1; - dir.NumberOfNames = number_of_names; - dir.Base = ordinal_base; - dir.AddressOfFunctions = pe.rva_from_section_offset(exports_section, current_pos_of_function_addresses); - dir.AddressOfNameOrdinals = pe.rva_from_section_offset(exports_section, current_pos_of_function_name_ordinals); - dir.AddressOfNames = pe.rva_from_section_offset(exports_section, current_pos_of_function_names_rvas); - dir.Name = pe.rva_from_section_offset(exports_section, directory_pos + sizeof(image_export_directory)); - - //Save it - memcpy(&raw_data[directory_pos], &dir, sizeof(dir)); - } - - //Sve library name - memcpy(&raw_data[directory_pos + sizeof(image_export_directory)], info.get_name().c_str(), info.get_name().length() + 1); - - //A map to sort function names alphabetically - typedef std::map funclist; //function name; function name ordinal - funclist funcs; - - uint32_t last_ordinal = ordinal_base; - //Enumerate all exported functions - for(exported_functions_list::const_iterator it = exports.begin(); it != exports.end(); ++it) - { - const exported_function& func = (*it); - - //If we're skipping some ordinals... - if(func.get_ordinal() > last_ordinal) - { - //Fill this function RVAs data with zeros - uint32_t len = sizeof(uint32_t) * (func.get_ordinal() - last_ordinal - 1); - if(len) - { - memset(&raw_data[current_pos_of_function_addresses], 0, len); - current_pos_of_function_addresses += len; - } - - //Save last encountered ordinal - last_ordinal = func.get_ordinal(); - } - - //If function is named, save its name ordinal and name in sorted alphabetically order - if(func.has_name()) - funcs.insert(std::make_pair(func.get_name(), static_cast(func.get_ordinal() - ordinal_base))); //Calculate name ordinal - - //If function is forwarded to another DLL - if(func.is_forwarded()) - { - //Write its forwarded name and its RVA - uint32_t function_rva = pe.rva_from_section_offset(exports_section, current_pos_of_function_forwards); - memcpy(&raw_data[current_pos_of_function_addresses], &function_rva, sizeof(function_rva)); - current_pos_of_function_addresses += sizeof(function_rva); - - memcpy(&raw_data[current_pos_of_function_forwards], func.get_forwarded_name().c_str(), func.get_forwarded_name().length() + 1); - current_pos_of_function_forwards += static_cast(func.get_forwarded_name().length() + 1); - } - else - { - //Write actual function RVA - uint32_t function_rva = func.get_rva(); - memcpy(&raw_data[current_pos_of_function_addresses], &function_rva, sizeof(function_rva)); - current_pos_of_function_addresses += sizeof(function_rva); - } - } - - //Enumerate sorted function names - for(funclist::const_iterator it = funcs.begin(); it != funcs.end(); ++it) - { - //Save function name RVA - uint32_t function_name_rva = pe.rva_from_section_offset(exports_section, current_pos_of_function_names); - memcpy(&raw_data[current_pos_of_function_names_rvas], &function_name_rva, sizeof(function_name_rva)); - current_pos_of_function_names_rvas += sizeof(function_name_rva); - - //Save function name - memcpy(&raw_data[current_pos_of_function_names], (*it).first.c_str(), (*it).first.length() + 1); - current_pos_of_function_names += static_cast((*it).first.length() + 1); - - //Save function name ordinal - uint16_t name_ordinal = (*it).second; - memcpy(&raw_data[current_pos_of_function_name_ordinals], &name_ordinal, sizeof(name_ordinal)); - current_pos_of_function_name_ordinals += sizeof(name_ordinal); - } - - //Adjust section raw and virtual sizes - pe.recalculate_section_sizes(exports_section, auto_strip_last_section); - - image_directory ret(pe.rva_from_section_offset(exports_section, directory_pos), needed_size); - - //If auto-rewrite of PE headers is required - if(save_to_pe_header) - { - pe.set_directory_rva(image_directory_entry_export, ret.get_rva()); - pe.set_directory_size(image_directory_entry_export, ret.get_size()); - } - - return ret; -} -} diff --git a/drivers/pe_bliss/pe_exports.h b/drivers/pe_bliss/pe_exports.h deleted file mode 100644 index 7e2d64813d..0000000000 --- a/drivers/pe_bliss/pe_exports.h +++ /dev/null @@ -1,163 +0,0 @@ -#pragma once -#include -#include -#include "pe_structures.h" -#include "pe_base.h" -#include "pe_directory.h" - -namespace pe_bliss -{ -//Class representing exported function -class exported_function -{ -public: - //Default constructor - exported_function(); - - //Returns ordinal of function (actually, ordinal = hint + ordinal base) - uint16_t get_ordinal() const; - - //Returns RVA of function - uint32_t get_rva() const; - - //Returns true if function has name and name ordinal - bool has_name() const; - //Returns name of function - const std::string& get_name() const; - //Returns name ordinal of function - uint16_t get_name_ordinal() const; - - //Returns true if function is forwarded to other library - bool is_forwarded() const; - //Returns the name of forwarded function - const std::string& get_forwarded_name() const; - -public: //Setters do not change everything inside image, they are used by PE class - //You can also use them to rebuild export directory - - //Sets ordinal of function - void set_ordinal(uint16_t ordinal); - - //Sets RVA of function - void set_rva(uint32_t rva); - - //Sets name of function (or clears it, if empty name is passed) - void set_name(const std::string& name); - //Sets name ordinal - void set_name_ordinal(uint16_t name_ordinal); - - //Sets forwarded function name (or clears it, if empty name is passed) - void set_forwarded_name(const std::string& name); - -private: - uint16_t ordinal_; //Function ordinal - uint32_t rva_; //Function RVA - std::string name_; //Function name - bool has_name_; //true == function has name - uint16_t name_ordinal_; //Function name ordinal - bool forward_; //true == function is forwarded - std::string forward_name_; //Name of forwarded function -}; - -//Class representing export information -class export_info -{ -public: - //Default constructor - export_info(); - - //Returns characteristics - uint32_t get_characteristics() const; - //Returns timestamp - uint32_t get_timestamp() const; - //Returns major version - uint16_t get_major_version() const; - //Returns minor version - uint16_t get_minor_version() const; - //Returns DLL name - const std::string& get_name() const; - //Returns ordinal base - uint32_t get_ordinal_base() const; - //Returns number of functions - uint32_t get_number_of_functions() const; - //Returns number of function names - uint32_t get_number_of_names() const; - //Returns RVA of function address table - uint32_t get_rva_of_functions() const; - //Returns RVA of function name address table - uint32_t get_rva_of_names() const; - //Returns RVA of name ordinals table - uint32_t get_rva_of_name_ordinals() const; - -public: //Setters do not change everything inside image, they are used by PE class - //You can also use them to rebuild export directory using rebuild_exports - - //Sets characteristics - void set_characteristics(uint32_t characteristics); - //Sets timestamp - void set_timestamp(uint32_t timestamp); - //Sets major version - void set_major_version(uint16_t major_version); - //Sets minor version - void set_minor_version(uint16_t minor_version); - //Sets DLL name - void set_name(const std::string& name); - //Sets ordinal base - void set_ordinal_base(uint32_t ordinal_base); - //Sets number of functions - void set_number_of_functions(uint32_t number_of_functions); - //Sets number of function names - void set_number_of_names(uint32_t number_of_names); - //Sets RVA of function address table - void set_rva_of_functions(uint32_t rva_of_functions); - //Sets RVA of function name address table - void set_rva_of_names(uint32_t rva_of_names); - //Sets RVA of name ordinals table - void set_rva_of_name_ordinals(uint32_t rva_of_name_ordinals); - -private: - uint32_t characteristics_; - uint32_t timestamp_; - uint16_t major_version_; - uint16_t minor_version_; - std::string name_; - uint32_t ordinal_base_; - uint32_t number_of_functions_; - uint32_t number_of_names_; - uint32_t address_of_functions_; - uint32_t address_of_names_; - uint32_t address_of_name_ordinals_; -}; - -//Exported functions list typedef -typedef std::vector exported_functions_list; - -//Returns array of exported functions -const exported_functions_list get_exported_functions(const pe_base& pe); -//Returns array of exported functions and information about export -const exported_functions_list get_exported_functions(const pe_base& pe, export_info& info); - -//Helper export functions -//Returns pair: -const std::pair get_export_ordinal_limits(const exported_functions_list& exports); - -//Checks if exported function name already exists -bool exported_name_exists(const std::string& function_name, const exported_functions_list& exports); - -//Checks if exported function ordinal already exists -bool exported_ordinal_exists(uint16_t ordinal, const exported_functions_list& exports); - -//Export directory rebuilder -//info - export information -//exported_functions_list - list of exported functions -//exports_section - section where export directory will be placed (must be attached to PE image) -//offset_from_section_start - offset from exports_section raw data start -//save_to_pe_headers - if true, new export directory information will be saved to PE image headers -//auto_strip_last_section - if true and exports are placed in the last section, it will be automatically stripped -//number_of_functions and number_of_names parameters don't matter in "info" when rebuilding, they're calculated independently -//characteristics, major_version, minor_version, timestamp and name are the only used members of "info" structure -//Returns new export directory information -//exported_functions_list is copied intentionally to be sorted by ordinal values later -//Name ordinals in exported function don't matter, they will be recalculated -const image_directory rebuild_exports(pe_base& pe, const export_info& info, exported_functions_list exports, section& exports_section, uint32_t offset_from_section_start = 0, bool save_to_pe_header = true, bool auto_strip_last_section = true); -} diff --git a/drivers/pe_bliss/pe_factory.cpp b/drivers/pe_bliss/pe_factory.cpp deleted file mode 100644 index 677503ef03..0000000000 --- a/drivers/pe_bliss/pe_factory.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "pe_factory.h" -#include "pe_properties_generic.h" - -namespace pe_bliss -{ -pe_base pe_factory::create_pe(std::istream& file, bool read_debug_raw_data) -{ - return pe_base::get_pe_type(file) == pe_type_32 - ? pe_base(file, pe_properties_32(), read_debug_raw_data) - : pe_base(file, pe_properties_64(), read_debug_raw_data); -} - -pe_base pe_factory::create_pe(const char* file_path, bool read_debug_raw_data) -{ - std::ifstream pe_file(file_path, std::ios::in | std::ios::binary); - if(!pe_file) - { - throw pe_exception("Error in open file.", pe_exception::stream_is_bad); - } - return pe_factory::create_pe(pe_file,read_debug_raw_data); -} -} diff --git a/drivers/pe_bliss/pe_factory.h b/drivers/pe_bliss/pe_factory.h deleted file mode 100644 index ac0332e5ba..0000000000 --- a/drivers/pe_bliss/pe_factory.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once -#include -#include -#include -#include "pe_base.h" - -namespace pe_bliss -{ -class pe_factory -{ -public: - //Creates pe_base class instance from PE or PE+ istream - //If read_bound_import_raw_data, raw bound import data will be read (used to get bound import info) - //If read_debug_raw_data, raw debug data will be read (used to get image debug info) - static pe_base create_pe(std::istream& file, bool read_debug_raw_data = true); - static pe_base create_pe(const char* file_path, bool read_debug_raw_data = true); -}; -} diff --git a/drivers/pe_bliss/pe_imports.cpp b/drivers/pe_bliss/pe_imports.cpp deleted file mode 100644 index 704d5fca99..0000000000 --- a/drivers/pe_bliss/pe_imports.cpp +++ /dev/null @@ -1,756 +0,0 @@ -#include -#include "pe_imports.h" -#include "pe_properties_generic.h" - -namespace pe_bliss -{ -using namespace pe_win; - -//IMPORTS -//Default constructor -//If set_to_pe_headers = true, IMAGE_DIRECTORY_ENTRY_IMPORT entry will be reset -//to new value after import rebuilding -//If auto_zero_directory_entry_iat = true, IMAGE_DIRECTORY_ENTRY_IAT will be set to zero -//IMAGE_DIRECTORY_ENTRY_IAT is used by loader to temporarily make section, where IMAGE_DIRECTORY_ENTRY_IAT RVA points, writeable -//to be able to modify IAT thunks -import_rebuilder_settings::import_rebuilder_settings(bool set_to_pe_headers, bool auto_zero_directory_entry_iat) - :offset_from_section_start_(0), - build_original_iat_(true), - save_iat_and_original_iat_rvas_(true), - fill_missing_original_iats_(false), - set_to_pe_headers_(set_to_pe_headers), - zero_directory_entry_iat_(auto_zero_directory_entry_iat), - rewrite_iat_and_original_iat_contents_(false), - auto_strip_last_section_(true) -{} - -//Returns offset from section start where import directory data will be placed -uint32_t import_rebuilder_settings::get_offset_from_section_start() const -{ - return offset_from_section_start_; -} - -//Returns true if Original import address table (IAT) will be rebuilt -bool import_rebuilder_settings::build_original_iat() const -{ - return build_original_iat_; -} - -//Returns true if Original import address and import address tables will not be rebuilt, -//works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero -bool import_rebuilder_settings::save_iat_and_original_iat_rvas() const -{ - return save_iat_and_original_iat_rvas_; -} - -//Returns true if Original import address and import address tables contents will be rewritten -//works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero -//and save_iat_and_original_iat_rvas is true -bool import_rebuilder_settings::rewrite_iat_and_original_iat_contents() const -{ - return rewrite_iat_and_original_iat_contents_; -} - -//Returns true if original missing IATs will be rebuilt -//(only if IATs are saved) -bool import_rebuilder_settings::fill_missing_original_iats() const -{ - return fill_missing_original_iats_; -} - -//Returns true if PE headers should be updated automatically after rebuilding of imports -bool import_rebuilder_settings::auto_set_to_pe_headers() const -{ - return set_to_pe_headers_; -} - -//Returns true if IMAGE_DIRECTORY_ENTRY_IAT must be zeroed, works only if auto_set_to_pe_headers = true -bool import_rebuilder_settings::zero_directory_entry_iat() const -{ - return zero_directory_entry_iat_; -} - -//Returns true if the last section should be stripped automatically, if imports are inside it -bool import_rebuilder_settings::auto_strip_last_section_enabled() const -{ - return auto_strip_last_section_; -} - -//Sets offset from section start where import directory data will be placed -void import_rebuilder_settings::set_offset_from_section_start(uint32_t offset) -{ - offset_from_section_start_ = offset; -} - -//Sets if Original import address table (IAT) will be rebuilt -void import_rebuilder_settings::build_original_iat(bool enable) -{ - build_original_iat_ = enable; -} - -//Sets if Original import address and import address tables will not be rebuilt, -//works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero -void import_rebuilder_settings::save_iat_and_original_iat_rvas(bool enable, bool enable_rewrite_iat_and_original_iat_contents) -{ - save_iat_and_original_iat_rvas_ = enable; - if(save_iat_and_original_iat_rvas_) - rewrite_iat_and_original_iat_contents_ = enable_rewrite_iat_and_original_iat_contents; - else - rewrite_iat_and_original_iat_contents_ = false; -} - -//Sets if original missing IATs will be rebuilt -//(only if IATs are saved) -void import_rebuilder_settings::fill_missing_original_iats(bool enable) -{ - fill_missing_original_iats_ = enable; -} - -//Sets if PE headers should be updated automatically after rebuilding of imports -void import_rebuilder_settings::auto_set_to_pe_headers(bool enable) -{ - set_to_pe_headers_ = enable; -} - -//Sets if IMAGE_DIRECTORY_ENTRY_IAT must be zeroed, works only if auto_set_to_pe_headers = true -void import_rebuilder_settings::zero_directory_entry_iat(bool enable) -{ - zero_directory_entry_iat_ = enable; -} - -//Sets if the last section should be stripped automatically, if imports are inside it, default true -void import_rebuilder_settings::enable_auto_strip_last_section(bool enable) -{ - auto_strip_last_section_ = enable; -} - -//Default constructor -imported_function::imported_function() - :hint_(0), ordinal_(0), iat_va_(0) -{} - -//Returns name of function -const std::string& imported_function::get_name() const -{ - return name_; -} - -//Returns true if imported function has name (and hint) -bool imported_function::has_name() const -{ - return !name_.empty(); -} - -//Returns hint -uint16_t imported_function::get_hint() const -{ - return hint_; -} - -//Returns ordinal of function -uint16_t imported_function::get_ordinal() const -{ - return ordinal_; -} - -//Returns IAT entry VA (usable if image has both IAT and original IAT and is bound) -uint64_t imported_function::get_iat_va() const -{ - return iat_va_; -} - -//Sets name of function -void imported_function::set_name(const std::string& name) -{ - name_ = name; -} - -//Sets hint -void imported_function::set_hint(uint16_t hint) -{ - hint_ = hint; -} - -//Sets ordinal -void imported_function::set_ordinal(uint16_t ordinal) -{ - ordinal_ = ordinal; -} - -//Sets IAT entry VA (usable if image has both IAT and original IAT and is bound) -void imported_function::set_iat_va(uint64_t va) -{ - iat_va_ = va; -} - -//Default constructor -import_library::import_library() - :rva_to_iat_(0), rva_to_original_iat_(0), timestamp_(0) -{} - -//Returns name of library -const std::string& import_library::get_name() const -{ - return name_; -} - -//Returns RVA to Import Address Table (IAT) -uint32_t import_library::get_rva_to_iat() const -{ - return rva_to_iat_; -} - -//Returns RVA to Original Import Address Table (Original IAT) -uint32_t import_library::get_rva_to_original_iat() const -{ - return rva_to_original_iat_; -} - -//Returns timestamp -uint32_t import_library::get_timestamp() const -{ - return timestamp_; -} - -//Sets name of library -void import_library::set_name(const std::string& name) -{ - name_ = name; -} - -//Sets RVA to Import Address Table (IAT) -void import_library::set_rva_to_iat(uint32_t rva_to_iat) -{ - rva_to_iat_ = rva_to_iat; -} - -//Sets RVA to Original Import Address Table (Original IAT) -void import_library::set_rva_to_original_iat(uint32_t rva_to_original_iat) -{ - rva_to_original_iat_ = rva_to_original_iat; -} - -//Sets timestamp -void import_library::set_timestamp(uint32_t timestamp) -{ - timestamp_ = timestamp; -} - -//Returns imported functions list -const import_library::imported_list& import_library::get_imported_functions() const -{ - return imports_; -} - -//Adds imported function -void import_library::add_import(const imported_function& func) -{ - imports_.push_back(func); -} - -//Clears imported functions list -void import_library::clear_imports() -{ - imports_.clear(); -} - -const imported_functions_list get_imported_functions(const pe_base& pe) -{ - return (pe.get_pe_type() == pe_type_32 ? - get_imported_functions_base(pe) - : get_imported_functions_base(pe)); -} - -const image_directory rebuild_imports(pe_base& pe, const imported_functions_list& imports, section& import_section, const import_rebuilder_settings& import_settings) -{ - return (pe.get_pe_type() == pe_type_32 ? - rebuild_imports_base(pe, imports, import_section, import_settings) - : rebuild_imports_base(pe, imports, import_section, import_settings)); -} - -//Returns imported functions list with related libraries info -template -const imported_functions_list get_imported_functions_base(const pe_base& pe) -{ - imported_functions_list ret; - - //If image has no imports, return empty array - if(!pe.has_imports()) - return ret; - - unsigned long current_descriptor_pos = pe.get_directory_rva(image_directory_entry_import); - //Get first IMAGE_IMPORT_DESCRIPTOR - image_import_descriptor import_descriptor = pe.section_data_from_rva(current_descriptor_pos, section_data_virtual, true); - - //Iterate them until we reach zero-element - //We don't need to check correctness of this, because exception will be thrown - //inside of loop if we go outsize of section - while(import_descriptor.Name) - { - //Get imported library information - import_library lib; - - unsigned long max_name_length; - //Get byte count that we have for library name - if((max_name_length = pe.section_data_length_from_rva(import_descriptor.Name, import_descriptor.Name, section_data_virtual, true)) < 2) - throw pe_exception("Incorrect import directory", pe_exception::incorrect_import_directory); - - //Get DLL name pointer - const char* dll_name = pe.section_data_from_rva(import_descriptor.Name, section_data_virtual, true); - - //Check for null-termination - if(!pe_utils::is_null_terminated(dll_name, max_name_length)) - throw pe_exception("Incorrect import directory", pe_exception::incorrect_import_directory); - - //Set library name - lib.set_name(dll_name); - //Set library timestamp - lib.set_timestamp(import_descriptor.TimeDateStamp); - //Set library RVA to IAT and original IAT - lib.set_rva_to_iat(import_descriptor.FirstThunk); - lib.set_rva_to_original_iat(import_descriptor.OriginalFirstThunk); - - //Get RVA to IAT (it must be filled by loader when loading PE) - uint32_t current_thunk_rva = import_descriptor.FirstThunk; - typename PEClassType::BaseSize import_address_table = pe.section_data_from_rva(current_thunk_rva, section_data_virtual, true); - - //Get RVA to original IAT (lookup table), which must handle imported functions names - //Some linkers leave this pointer zero-filled - //Such image is valid, but it is not possible to restore imported functions names - //afted image was loaded, because IAT becomes the only one table - //containing both function names and function RVAs after loading - uint32_t current_original_thunk_rva = import_descriptor.OriginalFirstThunk; - typename PEClassType::BaseSize import_lookup_table = current_original_thunk_rva == 0 ? import_address_table : pe.section_data_from_rva(current_original_thunk_rva, section_data_virtual, true); - if(current_original_thunk_rva == 0) - current_original_thunk_rva = current_thunk_rva; - - //List all imported functions for current DLL - if(import_lookup_table != 0 && import_address_table != 0) - { - while(true) - { - //Imported function description - imported_function func; - - //Get VA from IAT - typename PEClassType::BaseSize address = pe.section_data_from_rva(current_thunk_rva, section_data_virtual, true); - //Move pointer - current_thunk_rva += sizeof(typename PEClassType::BaseSize); - - //Jump to next DLL if we finished with this one - if(!address) - break; - - func.set_iat_va(address); - - //Get VA from original IAT - typename PEClassType::BaseSize lookup = pe.section_data_from_rva(current_original_thunk_rva, section_data_virtual, true); - //Move pointer - current_original_thunk_rva += sizeof(typename PEClassType::BaseSize); - - //Check if function is imported by ordinal - if((lookup & PEClassType::ImportSnapFlag) != 0) - { - //Set function ordinal - func.set_ordinal(static_cast(lookup & 0xffff)); - } - else - { - //Get byte count that we have for function name - if(lookup > static_cast(-1) - sizeof(uint16_t)) - throw pe_exception("Incorrect import directory", pe_exception::incorrect_import_directory); - - //Get maximum available length of function name - if((max_name_length = pe.section_data_length_from_rva(static_cast(lookup + sizeof(uint16_t)), static_cast(lookup + sizeof(uint16_t)), section_data_virtual, true)) < 2) - throw pe_exception("Incorrect import directory", pe_exception::incorrect_import_directory); - - //Get imported function name - const char* func_name = pe.section_data_from_rva(static_cast(lookup + sizeof(uint16_t)), section_data_virtual, true); - - //Check for null-termination - if(!pe_utils::is_null_terminated(func_name, max_name_length)) - throw pe_exception("Incorrect import directory", pe_exception::incorrect_import_directory); - - //HINT in import table is ORDINAL in export table - uint16_t hint = pe.section_data_from_rva(static_cast(lookup), section_data_virtual, true); - - //Save hint and name - func.set_name(func_name); - func.set_hint(hint); - } - - //Add function to list - lib.add_import(func); - } - } - - //Check possible overflow - if(!pe_utils::is_sum_safe(current_descriptor_pos, sizeof(image_import_descriptor))) - throw pe_exception("Incorrect import directory", pe_exception::incorrect_import_directory); - - //Go to next library - current_descriptor_pos += sizeof(image_import_descriptor); - import_descriptor = pe.section_data_from_rva(current_descriptor_pos, section_data_virtual, true); - - //Save import information - ret.push_back(lib); - } - - //Return resulting list - return ret; -} - - -//Simple import directory rebuilder -//You can get all image imports with get_imported_functions() function -//You can use returned value to, for example, add new imported library with some functions -//to the end of list of imported libraries -//To keep PE file working, rebuild its imports with save_iat_and_original_iat_rvas = true (default) -//Don't add new imported functions to existing imported library entries, because this can cause -//rewriting of some used memory (or other IAT/orig.IAT fields) by system loader -//The safest way is just adding import libraries with functions to the end of imported_functions_list array -template -const image_directory rebuild_imports_base(pe_base& pe, const imported_functions_list& imports, section& import_section, const import_rebuilder_settings& import_settings) -{ - //Check that import_section is attached to this PE image - if(!pe.section_attached(import_section)) - throw pe_exception("Import section must be attached to PE file", pe_exception::section_is_not_attached); - - uint32_t needed_size = 0; //Calculate needed size for import structures and strings - uint32_t needed_size_for_strings = 0; //Calculate needed size for import strings (library and function names and hints) - uint32_t size_of_iat = 0; //Size of IAT structures - - needed_size += static_cast((1 /* ending null descriptor */ + imports.size()) * sizeof(image_import_descriptor)); - - //Enumerate imported functions - for(imported_functions_list::const_iterator it = imports.begin(); it != imports.end(); ++it) - { - needed_size_for_strings += static_cast((*it).get_name().length() + 1 /* nullbyte */); - - const import_library::imported_list& funcs = (*it).get_imported_functions(); - - //IMAGE_THUNK_DATA - size_of_iat += static_cast(sizeof(typename PEClassType::BaseSize) * (1 /*ending null */ + funcs.size())); - - //Enumerate all imported functions in library - for(import_library::imported_list::const_iterator f = funcs.begin(); f != funcs.end(); ++f) - { - if((*f).has_name()) - needed_size_for_strings += static_cast((*f).get_name().length() + 1 /* nullbyte */ + sizeof(uint16_t) /* hint */); - } - } - - if(import_settings.build_original_iat() || import_settings.fill_missing_original_iats()) - needed_size += size_of_iat * 2; //We'll have two similar-sized IATs if we're building original IAT - else - needed_size += size_of_iat; - - needed_size += sizeof(typename PEClassType::BaseSize); //Maximum align for IAT and original IAT - - //Total needed size for import structures and strings - needed_size += needed_size_for_strings; - - //Check if import_section is last one. If it's not, check if there's enough place for import data - if(&import_section != &*(pe.get_image_sections().end() - 1) && - (import_section.empty() || pe_utils::align_up(import_section.get_size_of_raw_data(), pe.get_file_alignment()) < needed_size + import_settings.get_offset_from_section_start())) - throw pe_exception("Insufficient space for import directory", pe_exception::insufficient_space); - - std::string& raw_data = import_section.get_raw_data(); - - //This will be done only if image_section is the last section of image or for section with unaligned raw length of data - if(raw_data.length() < needed_size + import_settings.get_offset_from_section_start()) - raw_data.resize(needed_size + import_settings.get_offset_from_section_start()); //Expand section raw data - - uint32_t current_string_pointer = import_settings.get_offset_from_section_start();/* we will paste structures after strings */ - - //Position for IAT - uint32_t current_pos_for_iat = pe_utils::align_up(static_cast(needed_size_for_strings + import_settings.get_offset_from_section_start() + (1 + imports.size()) * sizeof(image_import_descriptor)), sizeof(typename PEClassType::BaseSize)); - //Position for original IAT - uint32_t current_pos_for_original_iat = current_pos_for_iat + size_of_iat; - //Position for import descriptors - uint32_t current_pos_for_descriptors = needed_size_for_strings + import_settings.get_offset_from_section_start(); - - //Build imports - for(imported_functions_list::const_iterator it = imports.begin(); it != imports.end(); ++it) - { - //Create import descriptor - image_import_descriptor descr; - memset(&descr, 0, sizeof(descr)); - descr.TimeDateStamp = (*it).get_timestamp(); //Restore timestamp - descr.Name = pe.rva_from_section_offset(import_section, current_string_pointer); //Library name RVA - - //If we should save IAT for current import descriptor - bool save_iats_for_this_descriptor = import_settings.save_iat_and_original_iat_rvas() && (*it).get_rva_to_iat() != 0; - //If we should write original IAT - bool write_original_iat = (!save_iats_for_this_descriptor && import_settings.build_original_iat()) || import_settings.fill_missing_original_iats(); - - //If we should rewrite saved original IAT for current import descriptor (without changing its position) - bool rewrite_saved_original_iat = save_iats_for_this_descriptor && import_settings.rewrite_iat_and_original_iat_contents() && import_settings.build_original_iat(); - //If we should rewrite saved IAT for current import descriptor (without changing its position) - bool rewrite_saved_iat = save_iats_for_this_descriptor && import_settings.rewrite_iat_and_original_iat_contents() && (*it).get_rva_to_iat() != 0; - - //Helper values if we're rewriting existing IAT or orig.IAT - uint32_t original_first_thunk = 0; - uint32_t first_thunk = 0; - - if(save_iats_for_this_descriptor) - { - //If there's no original IAT and we're asked to rebuild missing original IATs - if(!(*it).get_rva_to_original_iat() && import_settings.fill_missing_original_iats()) - descr.OriginalFirstThunk = import_settings.build_original_iat() ? pe.rva_from_section_offset(import_section, current_pos_for_original_iat) : 0; - else - descr.OriginalFirstThunk = import_settings.build_original_iat() ? (*it).get_rva_to_original_iat() : 0; - - descr.FirstThunk = (*it).get_rva_to_iat(); - - original_first_thunk = descr.OriginalFirstThunk; - first_thunk = descr.FirstThunk; - - if(rewrite_saved_original_iat) - { - if((*it).get_rva_to_original_iat()) - write_original_iat = true; - else - rewrite_saved_original_iat = false; - } - - if(rewrite_saved_iat) - save_iats_for_this_descriptor = false; - } - else - { - //We are creating new IAT and original IAT (if needed) - descr.OriginalFirstThunk = import_settings.build_original_iat() ? pe.rva_from_section_offset(import_section, current_pos_for_original_iat) : 0; - descr.FirstThunk = pe.rva_from_section_offset(import_section, current_pos_for_iat); - } - - //Save import descriptor - memcpy(&raw_data[current_pos_for_descriptors], &descr, sizeof(descr)); - current_pos_for_descriptors += sizeof(descr); - - //Save library name - memcpy(&raw_data[current_string_pointer], (*it).get_name().c_str(), (*it).get_name().length() + 1 /* nullbyte */); - current_string_pointer += static_cast((*it).get_name().length() + 1 /* nullbyte */); - - //List all imported functions - const import_library::imported_list& funcs = (*it).get_imported_functions(); - for(import_library::imported_list::const_iterator f = funcs.begin(); f != funcs.end(); ++f) - { - if((*f).has_name()) //If function is imported by name - { - //Get RVA of IMAGE_IMPORT_BY_NAME - typename PEClassType::BaseSize rva_of_named_import = pe.rva_from_section_offset(import_section, current_string_pointer); - - if(!save_iats_for_this_descriptor) - { - if(write_original_iat) - { - //We're creating original IATs - so we can write to IAT saved VA (because IMAGE_IMPORT_BY_NAME will be read - //by PE loader from original IAT) - typename PEClassType::BaseSize iat_value = static_cast((*f).get_iat_va()); - - if(rewrite_saved_iat) - { - if(pe.section_data_length_from_rva(first_thunk, first_thunk, section_data_raw, true) <= sizeof(iat_value)) - throw pe_exception("Insufficient space inside initial IAT", pe_exception::insufficient_space); - - memcpy(pe.section_data_from_rva(first_thunk, true), &iat_value, sizeof(iat_value)); - - first_thunk += sizeof(iat_value); - } - else - { - memcpy(&raw_data[current_pos_for_iat], &iat_value, sizeof(iat_value)); - current_pos_for_iat += sizeof(rva_of_named_import); - } - } - else - { - //Else - write to IAT RVA of IMAGE_IMPORT_BY_NAME - if(rewrite_saved_iat) - { - if(pe.section_data_length_from_rva(first_thunk, first_thunk, section_data_raw, true) <= sizeof(rva_of_named_import)) - throw pe_exception("Insufficient space inside initial IAT", pe_exception::insufficient_space); - - memcpy(pe.section_data_from_rva(first_thunk, true), &rva_of_named_import, sizeof(rva_of_named_import)); - - first_thunk += sizeof(rva_of_named_import); - } - else - { - memcpy(&raw_data[current_pos_for_iat], &rva_of_named_import, sizeof(rva_of_named_import)); - current_pos_for_iat += sizeof(rva_of_named_import); - } - } - } - - if(write_original_iat) - { - if(rewrite_saved_original_iat) - { - if(pe.section_data_length_from_rva(original_first_thunk, original_first_thunk, section_data_raw, true) <= sizeof(rva_of_named_import)) - throw pe_exception("Insufficient space inside initial original IAT", pe_exception::insufficient_space); - - memcpy(pe.section_data_from_rva(original_first_thunk, true), &rva_of_named_import, sizeof(rva_of_named_import)); - - original_first_thunk += sizeof(rva_of_named_import); - } - else - { - //We're creating original IATs - memcpy(&raw_data[current_pos_for_original_iat], &rva_of_named_import, sizeof(rva_of_named_import)); - current_pos_for_original_iat += sizeof(rva_of_named_import); - } - } - - //Write IMAGE_IMPORT_BY_NAME (WORD hint + string function name) - uint16_t hint = (*f).get_hint(); - memcpy(&raw_data[current_string_pointer], &hint, sizeof(hint)); - memcpy(&raw_data[current_string_pointer + sizeof(uint16_t)], (*f).get_name().c_str(), (*f).get_name().length() + 1 /* nullbyte */); - current_string_pointer += static_cast((*f).get_name().length() + 1 /* nullbyte */ + sizeof(uint16_t) /* hint */); - } - else //Function is imported by ordinal - { - uint16_t ordinal = (*f).get_ordinal(); - typename PEClassType::BaseSize thunk_value = ordinal; - thunk_value |= PEClassType::ImportSnapFlag; //Imported by ordinal - - if(!save_iats_for_this_descriptor) - { - if(write_original_iat) - { - //We're creating original IATs - so we can wtire to IAT saved VA (because ordinal will be read - //by PE loader from original IAT) - typename PEClassType::BaseSize iat_value = static_cast((*f).get_iat_va()); - if(rewrite_saved_iat) - { - if(pe.section_data_length_from_rva(first_thunk, first_thunk, section_data_raw, true) <= sizeof(iat_value)) - throw pe_exception("Insufficient space inside initial IAT", pe_exception::insufficient_space); - - memcpy(pe.section_data_from_rva(first_thunk, true), &iat_value, sizeof(iat_value)); - - first_thunk += sizeof(iat_value); - } - else - { - memcpy(&raw_data[current_pos_for_iat], &iat_value, sizeof(iat_value)); - current_pos_for_iat += sizeof(thunk_value); - } - } - else - { - //Else - write ordinal to IAT - if(rewrite_saved_iat) - { - if(pe.section_data_length_from_rva(first_thunk, first_thunk, section_data_raw, true) <= sizeof(thunk_value)) - throw pe_exception("Insufficient space inside initial IAT", pe_exception::insufficient_space); - - memcpy(pe.section_data_from_rva(first_thunk, true), &thunk_value, sizeof(thunk_value)); - - first_thunk += sizeof(thunk_value); - } - else - { - memcpy(&raw_data[current_pos_for_iat], &thunk_value, sizeof(thunk_value)); - } - } - } - - //We're writing ordinal to original IAT slot - if(write_original_iat) - { - if(rewrite_saved_original_iat) - { - if(pe.section_data_length_from_rva(original_first_thunk, original_first_thunk, section_data_raw, true) <= sizeof(thunk_value)) - throw pe_exception("Insufficient space inside initial original IAT", pe_exception::insufficient_space); - - memcpy(pe.section_data_from_rva(original_first_thunk, true), &thunk_value, sizeof(thunk_value)); - - original_first_thunk += sizeof(thunk_value); - } - else - { - memcpy(&raw_data[current_pos_for_original_iat], &thunk_value, sizeof(thunk_value)); - current_pos_for_original_iat += sizeof(thunk_value); - } - } - } - } - - if(!save_iats_for_this_descriptor) - { - //Ending null thunks - typename PEClassType::BaseSize thunk_value = 0; - - if(rewrite_saved_iat) - { - if(pe.section_data_length_from_rva(first_thunk, first_thunk, section_data_raw, true) <= sizeof(thunk_value)) - throw pe_exception("Insufficient space inside initial IAT", pe_exception::insufficient_space); - - memcpy(pe.section_data_from_rva(first_thunk, true), &thunk_value, sizeof(thunk_value)); - - first_thunk += sizeof(thunk_value); - } - else - { - memcpy(&raw_data[current_pos_for_iat], &thunk_value, sizeof(thunk_value)); - current_pos_for_iat += sizeof(thunk_value); - } - } - - if(write_original_iat) - { - //Ending null thunks - typename PEClassType::BaseSize thunk_value = 0; - - if(rewrite_saved_original_iat) - { - if(pe.section_data_length_from_rva(original_first_thunk, original_first_thunk, section_data_raw, true) <= sizeof(thunk_value)) - throw pe_exception("Insufficient space inside initial original IAT", pe_exception::insufficient_space); - - memcpy(pe.section_data_from_rva(original_first_thunk, true), &thunk_value, sizeof(thunk_value)); - - original_first_thunk += sizeof(thunk_value); - } - else - { - memcpy(&raw_data[current_pos_for_original_iat], &thunk_value, sizeof(thunk_value)); - current_pos_for_original_iat += sizeof(thunk_value); - } - } - } - - { - //Null ending descriptor - image_import_descriptor descr; - memset(&descr, 0, sizeof(descr)); - memcpy(&raw_data[current_pos_for_descriptors], &descr, sizeof(descr)); - } - - //Strip data a little, if we saved some place - //We're allocating more space than needed, if present original IAT and IAT are saved - raw_data.resize(current_pos_for_original_iat); - - //Adjust section raw and virtual sizes - pe.recalculate_section_sizes(import_section, import_settings.auto_strip_last_section_enabled()); - - //Return information about rebuilt import directory - image_directory ret(pe.rva_from_section_offset(import_section, import_settings.get_offset_from_section_start() + needed_size_for_strings), needed_size - needed_size_for_strings); - - //If auto-rewrite of PE headers is required - if(import_settings.auto_set_to_pe_headers()) - { - pe.set_directory_rva(image_directory_entry_import, ret.get_rva()); - pe.set_directory_size(image_directory_entry_import, ret.get_size()); - - //If we are requested to zero IMAGE_DIRECTORY_ENTRY_IAT also - if(import_settings.zero_directory_entry_iat()) - { - pe.set_directory_rva(image_directory_entry_iat, 0); - pe.set_directory_size(image_directory_entry_iat, 0); - } - } - - return ret; -} -} diff --git a/drivers/pe_bliss/pe_imports.h b/drivers/pe_bliss/pe_imports.h deleted file mode 100644 index 713be13e42..0000000000 --- a/drivers/pe_bliss/pe_imports.h +++ /dev/null @@ -1,187 +0,0 @@ -#pragma once -#include -#include -#include "pe_structures.h" -#include "pe_directory.h" -#include "pe_base.h" - -namespace pe_bliss -{ -//Class representing imported function -class imported_function -{ -public: - //Default constructor - imported_function(); - - //Returns true if imported function has name (and hint) - bool has_name() const; - //Returns name of function - const std::string& get_name() const; - //Returns hint - uint16_t get_hint() const; - //Returns ordinal of function - uint16_t get_ordinal() const; - - //Returns IAT entry VA (usable if image has both IAT and original IAT and is bound) - uint64_t get_iat_va() const; - -public: //Setters do not change everything inside image, they are used by PE class - //You also can use them to rebuild image imports - //Sets name of function - void set_name(const std::string& name); - //Sets hint - void set_hint(uint16_t hint); - //Sets ordinal - void set_ordinal(uint16_t ordinal); - - //Sets IAT entry VA (usable if image has both IAT and original IAT and is bound) - void set_iat_va(uint64_t rva); - -private: - std::string name_; //Function name - uint16_t hint_; //Hint - uint16_t ordinal_; //Ordinal - uint64_t iat_va_; -}; - -//Class representing imported library information -class import_library -{ -public: - typedef std::vector imported_list; - -public: - //Default constructor - import_library(); - - //Returns name of library - const std::string& get_name() const; - //Returns RVA to Import Address Table (IAT) - uint32_t get_rva_to_iat() const; - //Returns RVA to Original Import Address Table (Original IAT) - uint32_t get_rva_to_original_iat() const; - //Returns timestamp - uint32_t get_timestamp() const; - - //Returns imported functions list - const imported_list& get_imported_functions() const; - -public: //Setters do not change everything inside image, they are used by PE class - //You also can use them to rebuild image imports - //Sets name of library - void set_name(const std::string& name); - //Sets RVA to Import Address Table (IAT) - void set_rva_to_iat(uint32_t rva_to_iat); - //Sets RVA to Original Import Address Table (Original IAT) - void set_rva_to_original_iat(uint32_t rva_to_original_iat); - //Sets timestamp - void set_timestamp(uint32_t timestamp); - - //Adds imported function - void add_import(const imported_function& func); - //Clears imported functions list - void clear_imports(); - -private: - std::string name_; //Library name - uint32_t rva_to_iat_; //RVA to IAT - uint32_t rva_to_original_iat_; //RVA to original IAT - uint32_t timestamp_; //DLL TimeStamp - - imported_list imports_; -}; - -//Simple import directory rebuilder -//Class representing import rebuilder advanced settings -class import_rebuilder_settings -{ -public: - //Default constructor - //Default constructor - //If set_to_pe_headers = true, IMAGE_DIRECTORY_ENTRY_IMPORT entry will be reset - //to new value after import rebuilding - //If auto_zero_directory_entry_iat = true, IMAGE_DIRECTORY_ENTRY_IAT will be set to zero - //IMAGE_DIRECTORY_ENTRY_IAT is used by loader to temporarily make section, where IMAGE_DIRECTORY_ENTRY_IAT RVA points, writeable - //to be able to modify IAT thunks - explicit import_rebuilder_settings(bool set_to_pe_headers = true, bool auto_zero_directory_entry_iat = false); - - //Returns offset from section start where import directory data will be placed - uint32_t get_offset_from_section_start() const; - //Returns true if Original import address table (IAT) will be rebuilt - bool build_original_iat() const; - - //Returns true if Original import address and import address tables will not be rebuilt, - //works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero - bool save_iat_and_original_iat_rvas() const; - //Returns true if Original import address and import address tables contents will be rewritten - //works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero - //and save_iat_and_original_iat_rvas is true - bool rewrite_iat_and_original_iat_contents() const; - - //Returns true if original missing IATs will be rebuilt - //(only if IATs are saved) - bool fill_missing_original_iats() const; - //Returns true if PE headers should be updated automatically after rebuilding of imports - bool auto_set_to_pe_headers() const; - //Returns true if IMAGE_DIRECTORY_ENTRY_IAT must be zeroed, works only if auto_set_to_pe_headers = true - bool zero_directory_entry_iat() const; - - //Returns true if the last section should be stripped automatically, if imports are inside it - bool auto_strip_last_section_enabled() const; - -public: //Setters - //Sets offset from section start where import directory data will be placed - void set_offset_from_section_start(uint32_t offset); - //Sets if Original import address table (IAT) will be rebuilt - void build_original_iat(bool enable); - //Sets if Original import address and import address tables will not be rebuilt, - //works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero - //enable_rewrite_iat_and_original_iat_contents sets if Original import address and import address tables contents will be rewritten - //works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero - //and save_iat_and_original_iat_rvas is true - void save_iat_and_original_iat_rvas(bool enable, bool enable_rewrite_iat_and_original_iat_contents = false); - //Sets if original missing IATs will be rebuilt - //(only if IATs are saved) - void fill_missing_original_iats(bool enable); - //Sets if PE headers should be updated automatically after rebuilding of imports - void auto_set_to_pe_headers(bool enable); - //Sets if IMAGE_DIRECTORY_ENTRY_IAT must be zeroed, works only if auto_set_to_pe_headers = true - void zero_directory_entry_iat(bool enable); - - //Sets if the last section should be stripped automatically, if imports are inside it, default true - void enable_auto_strip_last_section(bool enable); - -private: - uint32_t offset_from_section_start_; - bool build_original_iat_; - bool save_iat_and_original_iat_rvas_; - bool fill_missing_original_iats_; - bool set_to_pe_headers_; - bool zero_directory_entry_iat_; - bool rewrite_iat_and_original_iat_contents_; - bool auto_strip_last_section_; -}; - -typedef std::vector imported_functions_list; - - -//Returns imported functions list with related libraries info -const imported_functions_list get_imported_functions(const pe_base& pe); - -template -const imported_functions_list get_imported_functions_base(const pe_base& pe); - - -//You can get all image imports with get_imported_functions() function -//You can use returned value to, for example, add new imported library with some functions -//to the end of list of imported libraries -//To keep PE file working, rebuild its imports with save_iat_and_original_iat_rvas = true (default) -//Don't add new imported functions to existing imported library entries, because this can cause -//rewriting of some used memory (or other IAT/orig.IAT fields) by system loader -//The safest way is just adding import libraries with functions to the end of imported_functions_list array -const image_directory rebuild_imports(pe_base& pe, const imported_functions_list& imports, section& import_section, const import_rebuilder_settings& import_settings = import_rebuilder_settings()); - -template -const image_directory rebuild_imports_base(pe_base& pe, const imported_functions_list& imports, section& import_section, const import_rebuilder_settings& import_settings = import_rebuilder_settings()); -} diff --git a/drivers/pe_bliss/pe_load_config.cpp b/drivers/pe_bliss/pe_load_config.cpp deleted file mode 100644 index dedb2a61a1..0000000000 --- a/drivers/pe_bliss/pe_load_config.cpp +++ /dev/null @@ -1,536 +0,0 @@ -#include -#include -#include "pe_load_config.h" -#include "pe_properties_generic.h" - -namespace pe_bliss -{ -using namespace pe_win; - -//IMAGE CONFIG -//Default constructor -image_config_info::image_config_info() - :time_stamp_(0), - major_version_(0), minor_version_(0), - global_flags_clear_(0), global_flags_set_(0), - critical_section_default_timeout_(0), - decommit_free_block_threshold_(0), decommit_total_free_threshold_(0), - lock_prefix_table_va_(0), - max_allocation_size_(0), - virtual_memory_threshold_(0), - process_affinity_mask_(0), - process_heap_flags_(0), - service_pack_version_(0), - edit_list_va_(0), - security_cookie_va_(0), - se_handler_table_va_(0), - se_handler_count_(0) -{} - -//Constructors from PE structures -template -image_config_info::image_config_info(const ConfigStructure& info) - :time_stamp_(info.TimeDateStamp), - major_version_(info.MajorVersion), minor_version_(info.MinorVersion), - global_flags_clear_(info.GlobalFlagsClear), global_flags_set_(info.GlobalFlagsSet), - critical_section_default_timeout_(info.CriticalSectionDefaultTimeout), - decommit_free_block_threshold_(info.DeCommitFreeBlockThreshold), decommit_total_free_threshold_(info.DeCommitTotalFreeThreshold), - lock_prefix_table_va_(info.LockPrefixTable), - max_allocation_size_(info.MaximumAllocationSize), - virtual_memory_threshold_(info.VirtualMemoryThreshold), - process_affinity_mask_(info.ProcessAffinityMask), - process_heap_flags_(info.ProcessHeapFlags), - service_pack_version_(info.CSDVersion), - edit_list_va_(info.EditList), - security_cookie_va_(info.SecurityCookie), - se_handler_table_va_(info.SEHandlerTable), - se_handler_count_(info.SEHandlerCount) -{} - -//Instantiate template constructor with needed structures -template image_config_info::image_config_info(const image_load_config_directory32& info); -template image_config_info::image_config_info(const image_load_config_directory64& info); - -//Returns the date and time stamp value -uint32_t image_config_info::get_time_stamp() const -{ - return time_stamp_; -} - -//Returns major version number -uint16_t image_config_info::get_major_version() const -{ - return major_version_; -} - -//Returns minor version number -uint16_t image_config_info::get_minor_version() const -{ - return minor_version_; -} - -//Returns clear global flags -uint32_t image_config_info::get_global_flags_clear() const -{ - return global_flags_clear_; -} - -//Returns set global flags -uint32_t image_config_info::get_global_flags_set() const -{ - return global_flags_set_; -} - -//Returns critical section default timeout -uint32_t image_config_info::get_critical_section_default_timeout() const -{ - return critical_section_default_timeout_; -} - -//Get the size of the minimum block that -//must be freed before it is freed (de-committed), in bytes -uint64_t image_config_info::get_decommit_free_block_threshold() const -{ - return decommit_free_block_threshold_; -} - -//Returns the size of the minimum total memory -//that must be freed in the process heap before it is freed (de-committed), in bytes -uint64_t image_config_info::get_decommit_total_free_threshold() const -{ - return decommit_total_free_threshold_; -} - -//Returns VA of a list of addresses where the LOCK prefix is used -uint64_t image_config_info::get_lock_prefix_table_va() const -{ - return lock_prefix_table_va_; -} - -//Returns the maximum allocation size, in bytes -uint64_t image_config_info::get_max_allocation_size() const -{ - return max_allocation_size_; -} - -//Returns the maximum block size that can be allocated from heap segments, in bytes -uint64_t image_config_info::get_virtual_memory_threshold() const -{ - return virtual_memory_threshold_; -} - -//Returns process affinity mask -uint64_t image_config_info::get_process_affinity_mask() const -{ - return process_affinity_mask_; -} - -//Returns process heap flags -uint32_t image_config_info::get_process_heap_flags() const -{ - return process_heap_flags_; -} - -//Returns service pack version (CSDVersion) -uint16_t image_config_info::get_service_pack_version() const -{ - return service_pack_version_; -} - -//Returns VA of edit list (reserved by system) -uint64_t image_config_info::get_edit_list_va() const -{ - return edit_list_va_; -} - -//Returns a pointer to a cookie that is used by Visual C++ or GS implementation -uint64_t image_config_info::get_security_cookie_va() const -{ - return security_cookie_va_; -} - -//Returns VA of the sorted table of RVAs of each valid, unique handler in the image -uint64_t image_config_info::get_se_handler_table_va() const -{ - return se_handler_table_va_; -} - -//Returns the count of unique handlers in the table -uint64_t image_config_info::get_se_handler_count() const -{ - return se_handler_count_; -} - -//Returns SE Handler RVA list -const image_config_info::se_handler_list& image_config_info::get_se_handler_rvas() const -{ - return se_handlers_; -} - -//Returns Lock Prefix RVA list -const image_config_info::lock_prefix_rva_list& image_config_info::get_lock_prefix_rvas() const -{ - return lock_prefixes_; -} - -//Adds SE Handler RVA to list -void image_config_info::add_se_handler_rva(uint32_t rva) -{ - se_handlers_.push_back(rva); -} - -//Clears SE Handler list -void image_config_info::clear_se_handler_list() -{ - se_handlers_.clear(); -} - -//Adds Lock Prefix RVA to list -void image_config_info::add_lock_prefix_rva(uint32_t rva) -{ - lock_prefixes_.push_back(rva); -} - -//Clears Lock Prefix list -void image_config_info::clear_lock_prefix_list() -{ - lock_prefixes_.clear(); -} - -//Sets the date and time stamp value -void image_config_info::set_time_stamp(uint32_t time_stamp) -{ - time_stamp_ = time_stamp; -} - -//Sets major version number -void image_config_info::set_major_version(uint16_t major_version) -{ - major_version_ = major_version; -} - -//Sets minor version number -void image_config_info::set_minor_version(uint16_t minor_version) -{ - minor_version_ = minor_version; -} - -//Sets clear global flags -void image_config_info::set_global_flags_clear(uint32_t global_flags_clear) -{ - global_flags_clear_ = global_flags_clear; -} - -//Sets set global flags -void image_config_info::set_global_flags_set(uint32_t global_flags_set) -{ - global_flags_set_ = global_flags_set; -} - -//Sets critical section default timeout -void image_config_info::set_critical_section_default_timeout(uint32_t critical_section_default_timeout) -{ - critical_section_default_timeout_ = critical_section_default_timeout; -} - -//Sets the size of the minimum block that -//must be freed before it is freed (de-committed), in bytes -void image_config_info::set_decommit_free_block_threshold(uint64_t decommit_free_block_threshold) -{ - decommit_free_block_threshold_ = decommit_free_block_threshold; -} - -//Sets the size of the minimum total memory -//that must be freed in the process heap before it is freed (de-committed), in bytes -void image_config_info::set_decommit_total_free_threshold(uint64_t decommit_total_free_threshold) -{ - decommit_total_free_threshold_ = decommit_total_free_threshold; -} - -//Sets VA of a list of addresses where the LOCK prefix is used -//If you rebuild this list, VA will be re-assigned automatically -void image_config_info::set_lock_prefix_table_va(uint64_t lock_prefix_table_va) -{ - lock_prefix_table_va_ = lock_prefix_table_va; -} - -//Sets the maximum allocation size, in bytes -void image_config_info::set_max_allocation_size(uint64_t max_allocation_size) -{ - max_allocation_size_ = max_allocation_size; -} - -//Sets the maximum block size that can be allocated from heap segments, in bytes -void image_config_info::set_virtual_memory_threshold(uint64_t virtual_memory_threshold) -{ - virtual_memory_threshold_ = virtual_memory_threshold; -} - -//Sets process affinity mask -void image_config_info::set_process_affinity_mask(uint64_t process_affinity_mask) -{ - process_affinity_mask_ = process_affinity_mask; -} - -//Sets process heap flags -void image_config_info::set_process_heap_flags(uint32_t process_heap_flags) -{ - process_heap_flags_ = process_heap_flags; -} - -//Sets service pack version (CSDVersion) -void image_config_info::set_service_pack_version(uint16_t service_pack_version) -{ - service_pack_version_ = service_pack_version; -} - -//Sets VA of edit list (reserved by system) -void image_config_info::set_edit_list_va(uint64_t edit_list_va) -{ - edit_list_va_ = edit_list_va; -} - -//Sets a pointer to a cookie that is used by Visual C++ or GS implementation -void image_config_info::set_security_cookie_va(uint64_t security_cookie_va) -{ - security_cookie_va_ = security_cookie_va; -} - -//Sets VA of the sorted table of RVAs of each valid, unique handler in the image -//If you rebuild this list, VA will be re-assigned automatically -void image_config_info::set_se_handler_table_va(uint64_t se_handler_table_va) -{ - se_handler_table_va_ = se_handler_table_va; -} - -//Returns SE Handler RVA list -image_config_info::se_handler_list& image_config_info::get_se_handler_rvas() -{ - return se_handlers_; -} - -//Returns Lock Prefix RVA list -image_config_info::lock_prefix_rva_list& image_config_info::get_lock_prefix_rvas() -{ - return lock_prefixes_; -} - -//Returns image config info -//If image does not have config info, throws an exception -const image_config_info get_image_config(const pe_base& pe) -{ - return pe.get_pe_type() == pe_type_32 - ? get_image_config_base(pe) - : get_image_config_base(pe); -} - -//Image config rebuilder -const image_directory rebuild_image_config(pe_base& pe, const image_config_info& info, section& image_config_section, uint32_t offset_from_section_start, bool write_se_handlers, bool write_lock_prefixes, bool save_to_pe_header, bool auto_strip_last_section) -{ - return pe.get_pe_type() == pe_type_32 - ? rebuild_image_config_base(pe, info, image_config_section, offset_from_section_start, write_se_handlers, write_lock_prefixes, save_to_pe_header, auto_strip_last_section) - : rebuild_image_config_base(pe, info, image_config_section, offset_from_section_start, write_se_handlers, write_lock_prefixes, save_to_pe_header, auto_strip_last_section); -} - - -//Returns image config info -//If image does not have config info, throws an exception -template -const image_config_info get_image_config_base(const pe_base& pe) -{ - //Check if image has config directory - if(!pe.has_config()) - throw pe_exception("Image does not have load config directory", pe_exception::directory_does_not_exist); - - //Get load config structure - typename PEClassType::ConfigStruct config_info = pe.section_data_from_rva(pe.get_directory_rva(image_directory_entry_load_config), section_data_virtual); - - //Check size of config directory - if(config_info.Size != sizeof(config_info)) - throw pe_exception("Incorrect (or old) load config directory", pe_exception::incorrect_config_directory); - - //Fill return structure - image_config_info ret(config_info); - - //Check possible overflow - if(config_info.SEHandlerCount >= pe_utils::max_dword / sizeof(uint32_t) - || config_info.SEHandlerTable >= static_cast(-1) - config_info.SEHandlerCount * sizeof(uint32_t)) - throw pe_exception("Incorrect load config directory", pe_exception::incorrect_config_directory); - - //Read sorted SE handler RVA list (if any) - for(typename PEClassType::BaseSize i = 0; i != config_info.SEHandlerCount; ++i) - ret.add_se_handler_rva(pe.section_data_from_va(static_cast(config_info.SEHandlerTable + i * sizeof(uint32_t)))); - - if(config_info.LockPrefixTable) - { - //Read Lock Prefix VA list (if any) - unsigned long current = 0; - while(true) - { - typename PEClassType::BaseSize lock_prefix_va = pe.section_data_from_va(static_cast(config_info.LockPrefixTable + current * sizeof(typename PEClassType::BaseSize))); - if(!lock_prefix_va) - break; - - ret.add_lock_prefix_rva(pe.va_to_rva(lock_prefix_va)); - - ++current; - } - } - - return ret; -} - -//Image config directory rebuilder -//auto_strip_last_section - if true and TLS are placed in the last section, it will be automatically stripped -//If write_se_handlers = true, SE Handlers list will be written just after image config directory structure -//If write_lock_prefixes = true, Lock Prefixes address list will be written just after image config directory structure -template -const image_directory rebuild_image_config_base(pe_base& pe, const image_config_info& info, section& image_config_section, uint32_t offset_from_section_start, bool write_se_handlers, bool write_lock_prefixes, bool save_to_pe_header, bool auto_strip_last_section) -{ - //Check that image_config_section is attached to this PE image - if(!pe.section_attached(image_config_section)) - throw pe_exception("Image Config section must be attached to PE file", pe_exception::section_is_not_attached); - - uint32_t alignment = pe_utils::align_up(offset_from_section_start, sizeof(typename PEClassType::BaseSize)) - offset_from_section_start; - - uint32_t needed_size = sizeof(typename PEClassType::ConfigStruct); //Calculate needed size for Image Config table - - uint32_t image_config_data_pos = offset_from_section_start + alignment; - - uint32_t current_pos_of_se_handlers = 0; - uint32_t current_pos_of_lock_prefixes = 0; - - if(write_se_handlers) - { - current_pos_of_se_handlers = needed_size + image_config_data_pos; - needed_size += static_cast(info.get_se_handler_rvas().size()) * sizeof(uint32_t); //RVAs of SE Handlers - } - - if(write_lock_prefixes) - { - current_pos_of_lock_prefixes = needed_size + image_config_data_pos; - needed_size += static_cast((info.get_lock_prefix_rvas().size() + 1) * sizeof(typename PEClassType::BaseSize)); //VAs of Lock Prefixes (and ending null element) - } - - //Check if image_config_section is last one. If it's not, check if there's enough place for Image Config data - if(&image_config_section != &*(pe.get_image_sections().end() - 1) && - (image_config_section.empty() || pe_utils::align_up(image_config_section.get_size_of_raw_data(), pe.get_file_alignment()) < needed_size + image_config_data_pos)) - throw pe_exception("Insufficient space for TLS directory", pe_exception::insufficient_space); - - std::string& raw_data = image_config_section.get_raw_data(); - - //This will be done only if image_config_section is the last section of image or for section with unaligned raw length of data - if(raw_data.length() < needed_size + image_config_data_pos) - raw_data.resize(needed_size + image_config_data_pos); //Expand section raw data - - //Create and fill Image Config structure - typename PEClassType::ConfigStruct image_config_section_struct = {0}; - image_config_section_struct.Size = sizeof(image_config_section_struct); - image_config_section_struct.TimeDateStamp = info.get_time_stamp(); - image_config_section_struct.MajorVersion = info.get_major_version(); - image_config_section_struct.MinorVersion = info.get_minor_version(); - image_config_section_struct.GlobalFlagsClear = info.get_global_flags_clear(); - image_config_section_struct.GlobalFlagsSet = info.get_global_flags_set(); - image_config_section_struct.CriticalSectionDefaultTimeout = info.get_critical_section_default_timeout(); - image_config_section_struct.DeCommitFreeBlockThreshold = static_cast(info.get_decommit_free_block_threshold()); - image_config_section_struct.DeCommitTotalFreeThreshold = static_cast(info.get_decommit_total_free_threshold()); - image_config_section_struct.MaximumAllocationSize = static_cast(info.get_max_allocation_size()); - image_config_section_struct.VirtualMemoryThreshold = static_cast(info.get_virtual_memory_threshold()); - image_config_section_struct.ProcessHeapFlags = info.get_process_heap_flags(); - image_config_section_struct.ProcessAffinityMask = static_cast(info.get_process_affinity_mask()); - image_config_section_struct.CSDVersion = info.get_service_pack_version(); - image_config_section_struct.EditList = static_cast(info.get_edit_list_va()); - image_config_section_struct.SecurityCookie = static_cast(info.get_security_cookie_va()); - image_config_section_struct.SEHandlerCount = static_cast(info.get_se_handler_rvas().size()); - - - if(write_se_handlers) - { - if(info.get_se_handler_rvas().empty()) - { - write_se_handlers = false; - image_config_section_struct.SEHandlerTable = 0; - } - else - { - typename PEClassType::BaseSize va; - pe.rva_to_va(pe.rva_from_section_offset(image_config_section, current_pos_of_se_handlers), va); - image_config_section_struct.SEHandlerTable = va; - } - } - else - { - image_config_section_struct.SEHandlerTable = static_cast(info.get_se_handler_table_va()); - } - - if(write_lock_prefixes) - { - if(info.get_lock_prefix_rvas().empty()) - { - write_lock_prefixes = false; - image_config_section_struct.LockPrefixTable = 0; - } - else - { - typename PEClassType::BaseSize va; - pe.rva_to_va(pe.rva_from_section_offset(image_config_section, current_pos_of_lock_prefixes), va); - image_config_section_struct.LockPrefixTable = va; - } - } - else - { - image_config_section_struct.LockPrefixTable = static_cast(info.get_lock_prefix_table_va()); - } - - //Write image config section - memcpy(&raw_data[image_config_data_pos], &image_config_section_struct, sizeof(image_config_section_struct)); - - if(write_se_handlers) - { - //Sort SE Handlers list - image_config_info::se_handler_list sorted_list = info.get_se_handler_rvas(); - std::sort(sorted_list.begin(), sorted_list.end()); - - //Write SE Handlers table - for(image_config_info::se_handler_list::const_iterator it = sorted_list.begin(); it != sorted_list.end(); ++it) - { - uint32_t se_handler_rva = *it; - memcpy(&raw_data[current_pos_of_se_handlers], &se_handler_rva, sizeof(se_handler_rva)); - current_pos_of_se_handlers += sizeof(se_handler_rva); - } - } - - if(write_lock_prefixes) - { - //Write Lock Prefixes VA list - for(image_config_info::lock_prefix_rva_list::const_iterator it = info.get_lock_prefix_rvas().begin(); it != info.get_lock_prefix_rvas().end(); ++it) - { - typename PEClassType::BaseSize lock_prefix_va; - pe.rva_to_va(*it, lock_prefix_va); - memcpy(&raw_data[current_pos_of_lock_prefixes], &lock_prefix_va, sizeof(lock_prefix_va)); - current_pos_of_lock_prefixes += sizeof(lock_prefix_va); - } - - { - //Ending null VA - typename PEClassType::BaseSize lock_prefix_va = 0; - memcpy(&raw_data[current_pos_of_lock_prefixes], &lock_prefix_va, sizeof(lock_prefix_va)); - } - } - - //Adjust section raw and virtual sizes - pe.recalculate_section_sizes(image_config_section, auto_strip_last_section); - - image_directory ret(pe.rva_from_section_offset(image_config_section, image_config_data_pos), sizeof(typename PEClassType::ConfigStruct)); - - //If auto-rewrite of PE headers is required - if(save_to_pe_header) - { - pe.set_directory_rva(image_directory_entry_load_config, ret.get_rva()); - pe.set_directory_size(image_directory_entry_load_config, ret.get_size()); - } - - return ret; -} - -} diff --git a/drivers/pe_bliss/pe_load_config.h b/drivers/pe_bliss/pe_load_config.h deleted file mode 100644 index 6e1aab25ad..0000000000 --- a/drivers/pe_bliss/pe_load_config.h +++ /dev/null @@ -1,163 +0,0 @@ -#pragma once -#include -#include "pe_structures.h" -#include "pe_base.h" -#include "pe_directory.h" - -namespace pe_bliss -{ -//Class representing image configuration information -class image_config_info -{ -public: - typedef std::vector se_handler_list; - typedef std::vector lock_prefix_rva_list; - -public: - //Default constructor - image_config_info(); - //Constructors from PE structures (no checks) - template - explicit image_config_info(const ConfigStructure& info); - - //Returns the date and time stamp value - uint32_t get_time_stamp() const; - //Returns major version number - uint16_t get_major_version() const; - //Returns minor version number - uint16_t get_minor_version() const; - //Returns clear global flags - uint32_t get_global_flags_clear() const; - //Returns set global flags - uint32_t get_global_flags_set() const; - //Returns critical section default timeout - uint32_t get_critical_section_default_timeout() const; - //Get the size of the minimum block that - //must be freed before it is freed (de-committed), in bytes - uint64_t get_decommit_free_block_threshold() const; - //Returns the size of the minimum total memory - //that must be freed in the process heap before it is freed (de-committed), in bytes - uint64_t get_decommit_total_free_threshold() const; - //Returns VA of a list of addresses where the LOCK prefix is used - uint64_t get_lock_prefix_table_va() const; - //Returns the maximum allocation size, in bytes - uint64_t get_max_allocation_size() const; - //Returns the maximum block size that can be allocated from heap segments, in bytes - uint64_t get_virtual_memory_threshold() const; - //Returns process affinity mask - uint64_t get_process_affinity_mask() const; - //Returns process heap flags - uint32_t get_process_heap_flags() const; - //Returns service pack version (CSDVersion) - uint16_t get_service_pack_version() const; - //Returns VA of edit list (reserved by system) - uint64_t get_edit_list_va() const; - //Returns a pointer to a cookie that is used by Visual C++ or GS implementation - uint64_t get_security_cookie_va() const; - //Returns VA of the sorted table of RVAs of each valid, unique handler in the image - uint64_t get_se_handler_table_va() const; - //Returns the count of unique handlers in the table - uint64_t get_se_handler_count() const; - - //Returns SE Handler RVA list - const se_handler_list& get_se_handler_rvas() const; - - //Returns Lock Prefix RVA list - const lock_prefix_rva_list& get_lock_prefix_rvas() const; - -public: //These functions do not change everything inside image, they are used by PE class - //Also you can use these functions to rebuild image config directory - - //Adds SE Handler RVA to list - void add_se_handler_rva(uint32_t rva); - //Clears SE Handler list - void clear_se_handler_list(); - - //Adds Lock Prefix RVA to list - void add_lock_prefix_rva(uint32_t rva); - //Clears Lock Prefix list - void clear_lock_prefix_list(); - - //Sets the date and time stamp value - void set_time_stamp(uint32_t time_stamp); - //Sets major version number - void set_major_version(uint16_t major_version); - //Sets minor version number - void set_minor_version(uint16_t minor_version); - //Sets clear global flags - void set_global_flags_clear(uint32_t global_flags_clear); - //Sets set global flags - void set_global_flags_set(uint32_t global_flags_set); - //Sets critical section default timeout - void set_critical_section_default_timeout(uint32_t critical_section_default_timeout); - //Sets the size of the minimum block that - //must be freed before it is freed (de-committed), in bytes - void set_decommit_free_block_threshold(uint64_t decommit_free_block_threshold); - //Sets the size of the minimum total memory - //that must be freed in the process heap before it is freed (de-committed), in bytes - void set_decommit_total_free_threshold(uint64_t decommit_total_free_threshold); - //Sets VA of a list of addresses where the LOCK prefix is used - //If you rebuild this list, VA will be re-assigned automatically - void set_lock_prefix_table_va(uint64_t lock_prefix_table_va); - //Sets the maximum allocation size, in bytes - void set_max_allocation_size(uint64_t max_allocation_size); - //Sets the maximum block size that can be allocated from heap segments, in bytes - void set_virtual_memory_threshold(uint64_t virtual_memory_threshold); - //Sets process affinity mask - void set_process_affinity_mask(uint64_t process_affinity_mask); - //Sets process heap flags - void set_process_heap_flags(uint32_t process_heap_flags); - //Sets service pack version (CSDVersion) - void set_service_pack_version(uint16_t service_pack_version); - //Sets VA of edit list (reserved by system) - void set_edit_list_va(uint64_t edit_list_va); - //Sets a pointer to a cookie that is used by Visual C++ or GS implementation - void set_security_cookie_va(uint64_t security_cookie_va); - //Sets VA of the sorted table of RVAs of each valid, unique handler in the image - //If you rebuild this list, VA will be re-assigned automatically - void set_se_handler_table_va(uint64_t se_handler_table_va); - - //Returns SE Handler RVA list - se_handler_list& get_se_handler_rvas(); - - //Returns Lock Prefix RVA list - lock_prefix_rva_list& get_lock_prefix_rvas(); - -private: - uint32_t time_stamp_; - uint16_t major_version_, minor_version_; - uint32_t global_flags_clear_, global_flags_set_; - uint32_t critical_section_default_timeout_; - uint64_t decommit_free_block_threshold_, decommit_total_free_threshold_; - uint64_t lock_prefix_table_va_; - uint64_t max_allocation_size_; - uint64_t virtual_memory_threshold_; - uint64_t process_affinity_mask_; - uint32_t process_heap_flags_; - uint16_t service_pack_version_; - uint64_t edit_list_va_; - uint64_t security_cookie_va_; - uint64_t se_handler_table_va_; - uint64_t se_handler_count_; - - se_handler_list se_handlers_; - lock_prefix_rva_list lock_prefixes_; -}; - -//Returns image config info -//If image does not have config info, throws an exception -const image_config_info get_image_config(const pe_base& pe); - -template -const image_config_info get_image_config_base(const pe_base& pe); - - -//Image config directory rebuilder -//auto_strip_last_section - if true and TLS are placed in the last section, it will be automatically stripped -//If write_se_handlers = true, SE Handlers list will be written just after image config directory structure -//If write_lock_prefixes = true, Lock Prefixes address list will be written just after image config directory structure -const image_directory rebuild_image_config(pe_base& pe, const image_config_info& info, section& image_config_section, uint32_t offset_from_section_start = 0, bool write_se_handlers = true, bool write_lock_prefixes = true, bool save_to_pe_header = true, bool auto_strip_last_section = true); - -template -const image_directory rebuild_image_config_base(pe_base& pe, const image_config_info& info, section& image_config_section, uint32_t offset_from_section_start = 0, bool write_se_handlers = true, bool write_lock_prefixes = true, bool save_to_pe_header = true, bool auto_strip_last_section = true); -} diff --git a/drivers/pe_bliss/pe_properties.cpp b/drivers/pe_bliss/pe_properties.cpp deleted file mode 100644 index 134bf29caf..0000000000 --- a/drivers/pe_bliss/pe_properties.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "pe_properties.h" - -namespace pe_bliss -{ -//Destructor -pe_properties::~pe_properties() -{} - -//Clears PE characteristics flag -void pe_properties::clear_characteristics_flags(uint16_t flags) -{ - set_characteristics(get_characteristics() & ~flags); -} - -//Sets PE characteristics flag -void pe_properties::set_characteristics_flags(uint16_t flags) -{ - set_characteristics(get_characteristics() | flags); -} -} diff --git a/drivers/pe_bliss/pe_properties.h b/drivers/pe_bliss/pe_properties.h deleted file mode 100644 index b10d803b92..0000000000 --- a/drivers/pe_bliss/pe_properties.h +++ /dev/null @@ -1,215 +0,0 @@ -#pragma once -#include -#include "pe_structures.h" - -namespace pe_bliss -{ -class pe_properties -{ -public: //Constructors - virtual std::auto_ptr duplicate() const = 0; - - //Fills properly PE structures - virtual void create_pe(uint32_t section_alignment, uint16_t subsystem) = 0; - -public: - //Destructor - virtual ~pe_properties(); - - -public: //DIRECTORIES - //Returns true if directory exists - virtual bool directory_exists(uint32_t id) const = 0; - - //Removes directory - virtual void remove_directory(uint32_t id) = 0; - - //Returns directory RVA - virtual uint32_t get_directory_rva(uint32_t id) const = 0; - //Returns directory size - virtual uint32_t get_directory_size(uint32_t id) const = 0; - - //Sets directory RVA (just a value of PE header, no moving occurs) - virtual void set_directory_rva(uint32_t id, uint32_t rva) = 0; - //Sets directory size (just a value of PE header, no moving occurs) - virtual void set_directory_size(uint32_t id, uint32_t size) = 0; - - //Strips only zero DATA_DIRECTORY entries to count = min_count - //Returns resulting number of data directories - //strip_iat_directory - if true, even not empty IAT directory will be stripped - virtual uint32_t strip_data_directories(uint32_t min_count = 1, bool strip_iat_directory = true) = 0; - - -public: //IMAGE - //Returns PE type of this image - virtual pe_type get_pe_type() const = 0; - - -public: //PE HEADER - //Returns image base for PE32 and PE64 respectively - virtual uint32_t get_image_base_32() const = 0; - virtual uint64_t get_image_base_64() const = 0; - - //Sets new image base for PE32 - virtual void set_image_base(uint32_t base) = 0; - //Sets new image base for PE32/PE+ - virtual void set_image_base_64(uint64_t base) = 0; - - //Returns image entry point - virtual uint32_t get_ep() const = 0; - //Sets image entry point - virtual void set_ep(uint32_t new_ep) = 0; - - //Returns file alignment - virtual uint32_t get_file_alignment() const = 0; - //Returns section alignment - virtual uint32_t get_section_alignment() const = 0; - - //Sets heap size commit for PE32 and PE64 respectively - virtual void set_heap_size_commit(uint32_t size) = 0; - virtual void set_heap_size_commit(uint64_t size) = 0; - //Sets heap size reserve for PE32 and PE64 respectively - virtual void set_heap_size_reserve(uint32_t size) = 0; - virtual void set_heap_size_reserve(uint64_t size) = 0; - //Sets stack size commit for PE32 and PE64 respectively - virtual void set_stack_size_commit(uint32_t size) = 0; - virtual void set_stack_size_commit(uint64_t size) = 0; - //Sets stack size reserve for PE32 and PE64 respectively - virtual void set_stack_size_reserve(uint32_t size) = 0; - virtual void set_stack_size_reserve(uint64_t size) = 0; - - //Returns heap size commit for PE32 and PE64 respectively - virtual uint32_t get_heap_size_commit_32() const = 0; - virtual uint64_t get_heap_size_commit_64() const = 0; - //Returns heap size reserve for PE32 and PE64 respectively - virtual uint32_t get_heap_size_reserve_32() const = 0; - virtual uint64_t get_heap_size_reserve_64() const = 0; - //Returns stack size commit for PE32 and PE64 respectively - virtual uint32_t get_stack_size_commit_32() const = 0; - virtual uint64_t get_stack_size_commit_64() const = 0; - //Returns stack size reserve for PE32 and PE64 respectively - virtual uint32_t get_stack_size_reserve_32() const = 0; - virtual uint64_t get_stack_size_reserve_64() const = 0; - - //Returns virtual size of image - virtual uint32_t get_size_of_image() const = 0; - - //Returns number of RVA and sizes (number of DATA_DIRECTORY entries) - virtual uint32_t get_number_of_rvas_and_sizes() const = 0; - //Sets number of RVA and sizes (number of DATA_DIRECTORY entries) - virtual void set_number_of_rvas_and_sizes(uint32_t number) = 0; - - //Returns PE characteristics - virtual uint16_t get_characteristics() const = 0; - //Sets PE characteristics - virtual void set_characteristics(uint16_t ch) = 0; - - //Clears PE characteristics flag - void clear_characteristics_flags(uint16_t flags); - //Sets PE characteristics flag - void set_characteristics_flags(uint16_t flags); - - //Returns size of headers - virtual uint32_t get_size_of_headers() const = 0; - - //Returns subsystem - virtual uint16_t get_subsystem() const = 0; - - //Sets subsystem - virtual void set_subsystem(uint16_t subsystem) = 0; - - //Returns size of optional header - virtual uint16_t get_size_of_optional_header() const = 0; - - //Returns PE signature - virtual uint32_t get_pe_signature() const = 0; - - //Returns PE magic value - virtual uint32_t get_magic() const = 0; - - //Returns checksum of PE file from header - virtual uint32_t get_checksum() const = 0; - - //Sets checksum of PE file - virtual void set_checksum(uint32_t checksum) = 0; - - //Returns timestamp of PE file from header - virtual uint32_t get_time_date_stamp() const = 0; - - //Sets timestamp of PE file - virtual void set_time_date_stamp(uint32_t timestamp) = 0; - - //Returns Machine field value of PE file from header - virtual uint16_t get_machine() const = 0; - - //Sets Machine field value of PE file - virtual void set_machine(uint16_t machine) = 0; - - //Returns DLL Characteristics - virtual uint16_t get_dll_characteristics() const = 0; - - //Sets DLL Characteristics - virtual void set_dll_characteristics(uint16_t characteristics) = 0; - - //Sets required operation system version - virtual void set_os_version(uint16_t major, uint16_t minor) = 0; - - //Returns required operation system version (minor word) - virtual uint16_t get_minor_os_version() const = 0; - - //Returns required operation system version (major word) - virtual uint16_t get_major_os_version() const = 0; - - //Sets required subsystem version - virtual void set_subsystem_version(uint16_t major, uint16_t minor) = 0; - - //Returns required subsystem version (minor word) - virtual uint16_t get_minor_subsystem_version() const = 0; - - //Returns required subsystem version (major word) - virtual uint16_t get_major_subsystem_version() const = 0; - -public: //ADDRESS CONVERTIONS - //Virtual Address (VA) to Relative Virtual Address (RVA) convertions - //for PE32 and PE64 respectively - //bound_check checks integer overflow - virtual uint32_t va_to_rva(uint32_t va, bool bound_check = true) const = 0; - virtual uint32_t va_to_rva(uint64_t va, bool bound_check = true) const = 0; - - //Relative Virtual Address (RVA) to Virtual Address (VA) convertions - //for PE32 and PE64 respectively - virtual uint32_t rva_to_va_32(uint32_t rva) const = 0; - virtual uint64_t rva_to_va_64(uint32_t rva) const = 0; - - -public: //SECTIONS - //Returns number of sections - virtual uint16_t get_number_of_sections() const = 0; - -public: - //Sets number of sections - virtual void set_number_of_sections(uint16_t number) = 0; - //Sets virtual size of image - virtual void set_size_of_image(uint32_t size) = 0; - //Sets size of headers - virtual void set_size_of_headers(uint32_t size) = 0; - //Sets size of optional headers - virtual void set_size_of_optional_header(uint16_t size) = 0; - //Returns nt headers data pointer - virtual char* get_nt_headers_ptr() = 0; - //Returns nt headers data pointer - virtual const char* get_nt_headers_ptr() const = 0; - //Returns size of NT header - virtual uint32_t get_sizeof_nt_header() const = 0; - //Returns size of optional headers - virtual uint32_t get_sizeof_opt_headers() const = 0; - //Sets file alignment (no checks) - virtual void set_file_alignment_unchecked(uint32_t alignment) = 0; - //Sets base of code - virtual void set_base_of_code(uint32_t base) = 0; - //Returns base of code - virtual uint32_t get_base_of_code() const = 0; - //Returns needed PE magic for PE or PE+ (from template parameters) - virtual uint32_t get_needed_magic() const = 0; -}; -} diff --git a/drivers/pe_bliss/pe_properties_generic.cpp b/drivers/pe_bliss/pe_properties_generic.cpp deleted file mode 100644 index 3b1dadd0f9..0000000000 --- a/drivers/pe_bliss/pe_properties_generic.cpp +++ /dev/null @@ -1,624 +0,0 @@ -#include -#include "pe_properties_generic.h" -#include "pe_exception.h" -#include "utils.h" - -namespace pe_bliss -{ -using namespace pe_win; - -//Constructor -template -std::auto_ptr pe_properties_generic::duplicate() const -{ - return std::auto_ptr(new pe_properties_generic(*this)); -} - -//Fills properly PE structures -template -void pe_properties_generic::create_pe(uint32_t section_alignment, uint16_t subsystem) -{ - memset(&nt_headers_, 0, sizeof(nt_headers_)); - nt_headers_.Signature = 0x4550; //"PE" - nt_headers_.FileHeader.Machine = 0x14C; //i386 - nt_headers_.FileHeader.SizeOfOptionalHeader = sizeof(nt_headers_.OptionalHeader); - nt_headers_.OptionalHeader.Magic = PEClassType::Id; - nt_headers_.OptionalHeader.ImageBase = 0x400000; - nt_headers_.OptionalHeader.SectionAlignment = section_alignment; - nt_headers_.OptionalHeader.FileAlignment = 0x200; - nt_headers_.OptionalHeader.SizeOfHeaders = 1024; - nt_headers_.OptionalHeader.Subsystem = subsystem; - nt_headers_.OptionalHeader.SizeOfHeapReserve = 0x100000; - nt_headers_.OptionalHeader.SizeOfHeapCommit = 0x1000; - nt_headers_.OptionalHeader.SizeOfStackReserve = 0x100000; - nt_headers_.OptionalHeader.SizeOfStackCommit = 0x1000; - nt_headers_.OptionalHeader.NumberOfRvaAndSizes = 0x10; -} - -//Duplicate -template -pe_properties_generic::~pe_properties_generic() -{} - -//Returns true if directory exists -template -bool pe_properties_generic::directory_exists(uint32_t id) const -{ - return (nt_headers_.OptionalHeader.NumberOfRvaAndSizes - 1) >= id && - nt_headers_.OptionalHeader.DataDirectory[id].VirtualAddress; -} - -//Removes directory -template -void pe_properties_generic::remove_directory(uint32_t id) -{ - if(directory_exists(id)) - { - nt_headers_.OptionalHeader.DataDirectory[id].VirtualAddress = 0; - nt_headers_.OptionalHeader.DataDirectory[id].Size = 0; - - if(id == image_directory_entry_basereloc) - { - set_characteristics_flags(image_file_relocs_stripped); - set_dll_characteristics(get_dll_characteristics() & ~image_dllcharacteristics_dynamic_base); - } - else if(id == image_directory_entry_export) - { - clear_characteristics_flags(image_file_dll); - } - } -} - -//Returns directory RVA -template -uint32_t pe_properties_generic::get_directory_rva(uint32_t id) const -{ - //Check if directory exists - if(nt_headers_.OptionalHeader.NumberOfRvaAndSizes <= id) - throw pe_exception("Specified directory does not exist", pe_exception::directory_does_not_exist); - - return nt_headers_.OptionalHeader.DataDirectory[id].VirtualAddress; -} - -//Returns directory size -template -void pe_properties_generic::set_directory_rva(uint32_t id, uint32_t va) -{ - //Check if directory exists - if(nt_headers_.OptionalHeader.NumberOfRvaAndSizes <= id) - throw pe_exception("Specified directory does not exist", pe_exception::directory_does_not_exist); - - nt_headers_.OptionalHeader.DataDirectory[id].VirtualAddress = va; -} - -template -void pe_properties_generic::set_directory_size(uint32_t id, uint32_t size) -{ - //Check if directory exists - if(nt_headers_.OptionalHeader.NumberOfRvaAndSizes <= id) - throw pe_exception("Specified directory does not exist", pe_exception::directory_does_not_exist); - - nt_headers_.OptionalHeader.DataDirectory[id].Size = size; -} - -//Returns directory size -template -uint32_t pe_properties_generic::get_directory_size(uint32_t id) const -{ - //Check if directory exists - if(nt_headers_.OptionalHeader.NumberOfRvaAndSizes <= id) - throw pe_exception("Specified directory does not exist", pe_exception::directory_does_not_exist); - - return nt_headers_.OptionalHeader.DataDirectory[id].Size; -} - -//Strips only zero DATA_DIRECTORY entries to count = min_count -//Returns resulting number of data directories -//strip_iat_directory - if true, even not empty IAT directory will be stripped -template -uint32_t pe_properties_generic::strip_data_directories(uint32_t min_count, bool strip_iat_directory) -{ - int i = nt_headers_.OptionalHeader.NumberOfRvaAndSizes - 1; - - //Enumerate all data directories from the end - for(; i >= 0; i--) - { - //If directory exists, break - if(nt_headers_.OptionalHeader.DataDirectory[i].VirtualAddress && (static_cast(i) != image_directory_entry_iat || !strip_iat_directory)) - break; - - if(i <= static_cast(min_count) - 2) - break; - } - - if(i == image_numberof_directory_entries - 1) - return image_numberof_directory_entries; - - //Return new number of data directories - return nt_headers_.OptionalHeader.NumberOfRvaAndSizes = i + 1; -} - -//Returns image base for PE32 -template -uint32_t pe_properties_generic::get_image_base_32() const -{ - return static_cast(nt_headers_.OptionalHeader.ImageBase); -} - -//Returns image base for PE32/PE64 -template -uint64_t pe_properties_generic::get_image_base_64() const -{ - return static_cast(nt_headers_.OptionalHeader.ImageBase); -} - -//Sets new image base -template -void pe_properties_generic::set_image_base(uint32_t base) -{ - nt_headers_.OptionalHeader.ImageBase = base; -} - -//Sets new image base -template -void pe_properties_generic::set_image_base_64(uint64_t base) -{ - nt_headers_.OptionalHeader.ImageBase = static_cast(base); -} - -//Returns image entry point -template -uint32_t pe_properties_generic::get_ep() const -{ - return nt_headers_.OptionalHeader.AddressOfEntryPoint; -} - -//Sets image entry point -template -void pe_properties_generic::set_ep(uint32_t new_ep) -{ - nt_headers_.OptionalHeader.AddressOfEntryPoint = new_ep; -} - -//Returns file alignment -template -uint32_t pe_properties_generic::get_file_alignment() const -{ - return nt_headers_.OptionalHeader.FileAlignment; -} - -//Returns section alignment -template -uint32_t pe_properties_generic::get_section_alignment() const -{ - return nt_headers_.OptionalHeader.SectionAlignment; -} - -//Sets heap size commit for PE32 -template -void pe_properties_generic::set_heap_size_commit(uint32_t size) -{ - nt_headers_.OptionalHeader.SizeOfHeapCommit = static_cast(size); -} - -//Sets heap size commit for PE32/PE64 -template -void pe_properties_generic::set_heap_size_commit(uint64_t size) -{ - nt_headers_.OptionalHeader.SizeOfHeapCommit = static_cast(size); -} - -//Sets heap size reserve for PE32 -template -void pe_properties_generic::set_heap_size_reserve(uint32_t size) -{ - nt_headers_.OptionalHeader.SizeOfHeapReserve = static_cast(size); -} - -//Sets heap size reserve for PE32/PE64 -template -void pe_properties_generic::set_heap_size_reserve(uint64_t size) -{ - nt_headers_.OptionalHeader.SizeOfHeapReserve = static_cast(size); -} - -//Sets stack size commit for PE32 -template -void pe_properties_generic::set_stack_size_commit(uint32_t size) -{ - nt_headers_.OptionalHeader.SizeOfStackCommit = static_cast(size); -} - -//Sets stack size commit for PE32/PE64 -template -void pe_properties_generic::set_stack_size_commit(uint64_t size) -{ - nt_headers_.OptionalHeader.SizeOfStackCommit = static_cast(size); -} - -//Sets stack size reserve for PE32 -template -void pe_properties_generic::set_stack_size_reserve(uint32_t size) -{ - nt_headers_.OptionalHeader.SizeOfStackReserve = static_cast(size); -} - -//Sets stack size reserve for PE32/PE64 -template -void pe_properties_generic::set_stack_size_reserve(uint64_t size) -{ - nt_headers_.OptionalHeader.SizeOfStackReserve = static_cast(size); -} - -//Returns heap size commit for PE32 -template -uint32_t pe_properties_generic::get_heap_size_commit_32() const -{ - return static_cast(nt_headers_.OptionalHeader.SizeOfHeapCommit); -} - -//Returns heap size commit for PE32/PE64 -template -uint64_t pe_properties_generic::get_heap_size_commit_64() const -{ - return static_cast(nt_headers_.OptionalHeader.SizeOfHeapCommit); -} - -//Returns heap size reserve for PE32 -template -uint32_t pe_properties_generic::get_heap_size_reserve_32() const -{ - return static_cast(nt_headers_.OptionalHeader.SizeOfHeapReserve); -} - -//Returns heap size reserve for PE32/PE64 -template -uint64_t pe_properties_generic::get_heap_size_reserve_64() const -{ - return static_cast(nt_headers_.OptionalHeader.SizeOfHeapReserve); -} - -//Returns stack size commit for PE32 -template -uint32_t pe_properties_generic::get_stack_size_commit_32() const -{ - return static_cast(nt_headers_.OptionalHeader.SizeOfStackCommit); -} - -//Returns stack size commit for PE32/PE64 -template -uint64_t pe_properties_generic::get_stack_size_commit_64() const -{ - return static_cast(nt_headers_.OptionalHeader.SizeOfStackCommit); -} - -//Returns stack size reserve for PE32 -template -uint32_t pe_properties_generic::get_stack_size_reserve_32() const -{ - return static_cast(nt_headers_.OptionalHeader.SizeOfStackReserve); -} - -//Returns stack size reserve for PE32/PE64 -template -uint64_t pe_properties_generic::get_stack_size_reserve_64() const -{ - return static_cast(nt_headers_.OptionalHeader.SizeOfStackReserve); -} - -//Returns virtual size of image -template -uint32_t pe_properties_generic::get_size_of_image() const -{ - return nt_headers_.OptionalHeader.SizeOfImage; -} - -//Returns number of RVA and sizes (number of DATA_DIRECTORY entries) -template -uint32_t pe_properties_generic::get_number_of_rvas_and_sizes() const -{ - return nt_headers_.OptionalHeader.NumberOfRvaAndSizes; -} - -//Sets number of RVA and sizes (number of DATA_DIRECTORY entries) -template -void pe_properties_generic::set_number_of_rvas_and_sizes(uint32_t number) -{ - nt_headers_.OptionalHeader.NumberOfRvaAndSizes = number; -} - -//Returns PE characteristics -template -uint16_t pe_properties_generic::get_characteristics() const -{ - return nt_headers_.FileHeader.Characteristics; -} - -//Returns checksum of PE file from header -template -uint32_t pe_properties_generic::get_checksum() const -{ - return nt_headers_.OptionalHeader.CheckSum; -} - -//Sets checksum of PE file -template -void pe_properties_generic::set_checksum(uint32_t checksum) -{ - nt_headers_.OptionalHeader.CheckSum = checksum; -} - -//Returns DLL Characteristics -template -uint16_t pe_properties_generic::get_dll_characteristics() const -{ - return nt_headers_.OptionalHeader.DllCharacteristics; -} - -//Returns timestamp of PE file from header -template -uint32_t pe_properties_generic::get_time_date_stamp() const -{ - return nt_headers_.FileHeader.TimeDateStamp; -} - -//Sets timestamp of PE file -template -void pe_properties_generic::set_time_date_stamp(uint32_t timestamp) -{ - nt_headers_.FileHeader.TimeDateStamp = timestamp; -} - -//Sets DLL Characteristics -template -void pe_properties_generic::set_dll_characteristics(uint16_t characteristics) -{ - nt_headers_.OptionalHeader.DllCharacteristics = characteristics; -} - -//Returns Machine field value of PE file from header -template -uint16_t pe_properties_generic::get_machine() const -{ - return nt_headers_.FileHeader.Machine; -} - -//Sets Machine field value of PE file -template -void pe_properties_generic::set_machine(uint16_t machine) -{ - nt_headers_.FileHeader.Machine = machine; -} - -//Sets PE characteristics -template -void pe_properties_generic::set_characteristics(uint16_t ch) -{ - nt_headers_.FileHeader.Characteristics = ch; -} - -//Returns size of headers -template -uint32_t pe_properties_generic::get_size_of_headers() const -{ - return nt_headers_.OptionalHeader.SizeOfHeaders; -} - -//Returns subsystem -template -uint16_t pe_properties_generic::get_subsystem() const -{ - return nt_headers_.OptionalHeader.Subsystem; -} - -//Sets subsystem -template -void pe_properties_generic::set_subsystem(uint16_t subsystem) -{ - nt_headers_.OptionalHeader.Subsystem = subsystem; -} - -//Returns size of optional header -template -uint16_t pe_properties_generic::get_size_of_optional_header() const -{ - return nt_headers_.FileHeader.SizeOfOptionalHeader; -} - -//Returns PE signature -template -uint32_t pe_properties_generic::get_pe_signature() const -{ - return nt_headers_.Signature; -} - -//Returns PE magic value -template -uint32_t pe_properties_generic::get_magic() const -{ - return nt_headers_.OptionalHeader.Magic; -} - -//Sets required operation system version -template -void pe_properties_generic::set_os_version(uint16_t major, uint16_t minor) -{ - nt_headers_.OptionalHeader.MinorOperatingSystemVersion = minor; - nt_headers_.OptionalHeader.MajorOperatingSystemVersion = major; -} - -//Returns required operation system version (minor word) -template -uint16_t pe_properties_generic::get_minor_os_version() const -{ - return nt_headers_.OptionalHeader.MinorOperatingSystemVersion; -} - -//Returns required operation system version (major word) -template -uint16_t pe_properties_generic::get_major_os_version() const -{ - return nt_headers_.OptionalHeader.MajorOperatingSystemVersion; -} - -//Sets required subsystem version -template -void pe_properties_generic::set_subsystem_version(uint16_t major, uint16_t minor) -{ - nt_headers_.OptionalHeader.MinorSubsystemVersion = minor; - nt_headers_.OptionalHeader.MajorSubsystemVersion = major; -} - -//Returns required subsystem version (minor word) -template -uint16_t pe_properties_generic::get_minor_subsystem_version() const -{ - return nt_headers_.OptionalHeader.MinorSubsystemVersion; -} - -//Returns required subsystem version (major word) -template -uint16_t pe_properties_generic::get_major_subsystem_version() const -{ - return nt_headers_.OptionalHeader.MajorSubsystemVersion; -} - -//Virtual Address (VA) to Relative Virtual Address (RVA) convertions for PE32 -template -uint32_t pe_properties_generic::va_to_rva(uint32_t va, bool bound_check) const -{ - if(bound_check && static_cast(va) - nt_headers_.OptionalHeader.ImageBase > pe_utils::max_dword) - throw pe_exception("Incorrect address conversion", pe_exception::incorrect_address_conversion); - - return static_cast(va - nt_headers_.OptionalHeader.ImageBase); -} - -//Virtual Address (VA) to Relative Virtual Address (RVA) convertions for PE32/PE64 -template -uint32_t pe_properties_generic::va_to_rva(uint64_t va, bool bound_check) const -{ - if(bound_check && va - nt_headers_.OptionalHeader.ImageBase > pe_utils::max_dword) - throw pe_exception("Incorrect address conversion", pe_exception::incorrect_address_conversion); - - return static_cast(va - nt_headers_.OptionalHeader.ImageBase); -} - -//Relative Virtual Address (RVA) to Virtual Address (VA) convertions for PE32 -template -uint32_t pe_properties_generic::rva_to_va_32(uint32_t rva) const -{ - if(!pe_utils::is_sum_safe(rva, static_cast(nt_headers_.OptionalHeader.ImageBase))) - throw pe_exception("Incorrect address conversion", pe_exception::incorrect_address_conversion); - - return static_cast(rva + nt_headers_.OptionalHeader.ImageBase); -} - -//Relative Virtual Address (RVA) to Virtual Address (VA) convertions for PE32/PE64 -template -uint64_t pe_properties_generic::rva_to_va_64(uint32_t rva) const -{ - return static_cast(rva) + nt_headers_.OptionalHeader.ImageBase; -} - -//Returns number of sections -template -uint16_t pe_properties_generic::get_number_of_sections() const -{ - return nt_headers_.FileHeader.NumberOfSections; -} - -//Sets number of sections -template -void pe_properties_generic::set_number_of_sections(uint16_t number) -{ - nt_headers_.FileHeader.NumberOfSections = number; -} - -//Sets virtual size of image -template -void pe_properties_generic::set_size_of_image(uint32_t size) -{ - nt_headers_.OptionalHeader.SizeOfImage = size; -} - -//Sets size of headers -template -void pe_properties_generic::set_size_of_headers(uint32_t size) -{ - nt_headers_.OptionalHeader.SizeOfHeaders = size; -} - -//Sets size of optional headers -template -void pe_properties_generic::set_size_of_optional_header(uint16_t size) -{ - nt_headers_.FileHeader.SizeOfOptionalHeader = size; -} - -//Returns nt headers data pointer -template -char* pe_properties_generic::get_nt_headers_ptr() -{ - return reinterpret_cast(&nt_headers_); -} - -//Returns nt headers data pointer -template -const char* pe_properties_generic::get_nt_headers_ptr() const -{ - return reinterpret_cast(&nt_headers_); -} - -//Returns size of NT header -template -uint32_t pe_properties_generic::get_sizeof_nt_header() const -{ - return sizeof(typename PEClassType::NtHeaders); -} - -//Returns size of optional headers -template -uint32_t pe_properties_generic::get_sizeof_opt_headers() const -{ - return sizeof(typename PEClassType::OptHeaders); -} - -//Sets file alignment (no checks) -template -void pe_properties_generic::set_file_alignment_unchecked(uint32_t alignment) -{ - nt_headers_.OptionalHeader.FileAlignment = alignment; -} - -//Sets base of code -template -void pe_properties_generic::set_base_of_code(uint32_t base) -{ - nt_headers_.OptionalHeader.BaseOfCode = base; -} - -//Returns base of code -template -uint32_t pe_properties_generic::get_base_of_code() const -{ - return nt_headers_.OptionalHeader.BaseOfCode; -} - -//Returns needed PE magic for PE or PE+ (from template parameters) -template -uint32_t pe_properties_generic::get_needed_magic() const -{ - return PEClassType::Id; -} - -//Returns PE type of this image -template -pe_type pe_properties_generic::get_pe_type() const -{ - return PEClassType::Id == image_nt_optional_hdr32_magic ? pe_type_32 : pe_type_64; -} - -//Two used instantiations for PE32 (PE) and PE64 (PE+) -template class pe_properties_generic; -template class pe_properties_generic; -} diff --git a/drivers/pe_bliss/pe_properties_generic.h b/drivers/pe_bliss/pe_properties_generic.h deleted file mode 100644 index 2b4a0e3c2e..0000000000 --- a/drivers/pe_bliss/pe_properties_generic.h +++ /dev/null @@ -1,256 +0,0 @@ -#include "pe_properties.h" - -namespace pe_bliss -{ -//Helper class to reduce code size and ease its editing -template< - typename NtHeadersType, - typename OptHeadersType, - uint16_t IdVal, - typename BaseSizeType, - BaseSizeType ImportSnapFlagVal, - typename TLSStructType, - typename ConfigStructType> -class pe_types -{ -public: - typedef NtHeadersType NtHeaders; //NT HEADERS type - typedef OptHeadersType OptHeaders; //NT OPTIONAL HEADER type - typedef BaseSizeType BaseSize; //Base size of different values: DWORD or ULONGLONG - typedef TLSStructType TLSStruct; //TLS structure type - typedef ConfigStructType ConfigStruct; //Configuration structure type - - static const uint16_t Id = IdVal; //Magic of PE or PE+ - static const BaseSize ImportSnapFlag = ImportSnapFlagVal; //Import snap flag value -}; - -//Portable Executable derived class for PE and PE+ -//Describes PE/PE+ dependent things -template -class pe_properties_generic : public pe_properties -{ -public: //Constructor - virtual std::auto_ptr duplicate() const; - - //Fills properly PE structures - virtual void create_pe(uint32_t section_alignment, uint16_t subsystem); - -public: - //Destructor - virtual ~pe_properties_generic(); - - -public: //DIRECTORIES - //Returns true if directory exists - virtual bool directory_exists(uint32_t id) const; - - //Removes directory - virtual void remove_directory(uint32_t id); - - //Returns directory RVA - virtual uint32_t get_directory_rva(uint32_t id) const; - //Returns directory size - virtual uint32_t get_directory_size(uint32_t id) const; - - //Sets directory RVA (just a value of PE header, no moving occurs) - virtual void set_directory_rva(uint32_t id, uint32_t rva); - //Sets directory size (just a value of PE header, no moving occurs) - virtual void set_directory_size(uint32_t id, uint32_t size); - - //Strips only zero DATA_DIRECTORY entries to count = min_count - //Returns resulting number of data directories - //strip_iat_directory - if true, even not empty IAT directory will be stripped - virtual uint32_t strip_data_directories(uint32_t min_count = 1, bool strip_iat_directory = true); - - -public: //IMAGE - //Returns PE type of this image - virtual pe_type get_pe_type() const; - - -public: //PE HEADER - //Returns image base for PE32 and PE64 respectively - virtual uint32_t get_image_base_32() const; - virtual uint64_t get_image_base_64() const; - - //Sets new image base for PE32 - virtual void set_image_base(uint32_t base); - //Sets new image base for PE32/PE+ - virtual void set_image_base_64(uint64_t base); - - //Returns image entry point - virtual uint32_t get_ep() const; - //Sets image entry point - virtual void set_ep(uint32_t new_ep); - - //Returns file alignment - virtual uint32_t get_file_alignment() const; - //Returns section alignment - virtual uint32_t get_section_alignment() const; - - //Sets heap size commit for PE32 and PE64 respectively - virtual void set_heap_size_commit(uint32_t size); - virtual void set_heap_size_commit(uint64_t size); - //Sets heap size reserve for PE32 and PE64 respectively - virtual void set_heap_size_reserve(uint32_t size); - virtual void set_heap_size_reserve(uint64_t size); - //Sets stack size commit for PE32 and PE64 respectively - virtual void set_stack_size_commit(uint32_t size); - virtual void set_stack_size_commit(uint64_t size); - //Sets stack size reserve for PE32 and PE64 respectively - virtual void set_stack_size_reserve(uint32_t size); - virtual void set_stack_size_reserve(uint64_t size); - - //Returns heap size commit for PE32 and PE64 respectively - virtual uint32_t get_heap_size_commit_32() const; - virtual uint64_t get_heap_size_commit_64() const; - //Returns heap size reserve for PE32 and PE64 respectively - virtual uint32_t get_heap_size_reserve_32() const; - virtual uint64_t get_heap_size_reserve_64() const; - //Returns stack size commit for PE32 and PE64 respectively - virtual uint32_t get_stack_size_commit_32() const; - virtual uint64_t get_stack_size_commit_64() const; - //Returns stack size reserve for PE32 and PE64 respectively - virtual uint32_t get_stack_size_reserve_32() const; - virtual uint64_t get_stack_size_reserve_64() const; - - //Returns virtual size of image - virtual uint32_t get_size_of_image() const; - - //Returns number of RVA and sizes (number of DATA_DIRECTORY entries) - virtual uint32_t get_number_of_rvas_and_sizes() const; - //Sets number of RVA and sizes (number of DATA_DIRECTORY entries) - virtual void set_number_of_rvas_and_sizes(uint32_t number); - - //Returns PE characteristics - virtual uint16_t get_characteristics() const; - //Sets PE characteristics - virtual void set_characteristics(uint16_t ch); - - //Returns size of headers - virtual uint32_t get_size_of_headers() const; - - //Returns subsystem - virtual uint16_t get_subsystem() const; - - //Sets subsystem - virtual void set_subsystem(uint16_t subsystem); - - //Returns size of optional header - virtual uint16_t get_size_of_optional_header() const; - - //Returns PE signature - virtual uint32_t get_pe_signature() const; - - //Returns PE magic value - virtual uint32_t get_magic() const; - - //Returns checksum of PE file from header - virtual uint32_t get_checksum() const; - - //Sets checksum of PE file - virtual void set_checksum(uint32_t checksum); - - //Returns timestamp of PE file from header - virtual uint32_t get_time_date_stamp() const; - - //Sets timestamp of PE file - virtual void set_time_date_stamp(uint32_t timestamp); - - //Returns Machine field value of PE file from header - virtual uint16_t get_machine() const; - - //Sets Machine field value of PE file - virtual void set_machine(uint16_t machine); - - //Returns DLL Characteristics - virtual uint16_t get_dll_characteristics() const; - - //Sets DLL Characteristics - virtual void set_dll_characteristics(uint16_t characteristics); - - //Sets required operation system version - virtual void set_os_version(uint16_t major, uint16_t minor); - - //Returns required operation system version (minor word) - virtual uint16_t get_minor_os_version() const; - - //Returns required operation system version (major word) - virtual uint16_t get_major_os_version() const; - - //Sets required subsystem version - virtual void set_subsystem_version(uint16_t major, uint16_t minor); - - //Returns required subsystem version (minor word) - virtual uint16_t get_minor_subsystem_version() const; - - //Returns required subsystem version (major word) - virtual uint16_t get_major_subsystem_version() const; - -public: //ADDRESS CONVERTIONS - //Virtual Address (VA) to Relative Virtual Address (RVA) convertions - //for PE32 and PE64 respectively - //bound_check checks integer overflow - virtual uint32_t va_to_rva(uint32_t va, bool bound_check = true) const; - virtual uint32_t va_to_rva(uint64_t va, bool bound_check = true) const; - - //Relative Virtual Address (RVA) to Virtual Address (VA) convertions - //for PE32 and PE64 respectively - virtual uint32_t rva_to_va_32(uint32_t rva) const; - virtual uint64_t rva_to_va_64(uint32_t rva) const; - - -public: //SECTIONS - //Returns number of sections - virtual uint16_t get_number_of_sections() const; - -protected: - typename PEClassType::NtHeaders nt_headers_; //NT headers (PE32 or PE64) - -public: - //Sets number of sections - virtual void set_number_of_sections(uint16_t number); - //Sets virtual size of image - virtual void set_size_of_image(uint32_t size); - //Sets size of headers - virtual void set_size_of_headers(uint32_t size); - //Sets size of optional headers - virtual void set_size_of_optional_header(uint16_t size); - //Returns nt headers data pointer - virtual char* get_nt_headers_ptr(); - //Returns nt headers data pointer - virtual const char* get_nt_headers_ptr() const; - //Returns size of NT header - virtual uint32_t get_sizeof_nt_header() const; - //Returns size of optional headers - virtual uint32_t get_sizeof_opt_headers() const; - //Sets file alignment (no checks) - virtual void set_file_alignment_unchecked(uint32_t alignment); - //Sets base of code - virtual void set_base_of_code(uint32_t base); - //Returns base of code - virtual uint32_t get_base_of_code() const; - //Returns needed PE magic for PE or PE+ (from template parameters) - virtual uint32_t get_needed_magic() const; -}; - -//Two used typedefs for PE32 (PE) and PE64 (PE+) -typedef pe_types pe_types_class_32; - -typedef pe_types pe_types_class_64; - -typedef pe_properties_generic pe_properties_32; -typedef pe_properties_generic pe_properties_64; -} diff --git a/drivers/pe_bliss/pe_rebuilder.cpp b/drivers/pe_bliss/pe_rebuilder.cpp deleted file mode 100644 index 4d7a94fe3b..0000000000 --- a/drivers/pe_bliss/pe_rebuilder.cpp +++ /dev/null @@ -1,193 +0,0 @@ -#include "pe_rebuilder.h" -#include "pe_base.h" -#include "pe_structures.h" -#include "pe_exception.h" - -namespace pe_bliss -{ -using namespace pe_win; - -//Rebuilds PE image headers -//If strip_dos_header is true, DOS headers partially will be used for PE headers -//If change_size_of_headers == true, SizeOfHeaders will be recalculated automatically -//If save_bound_import == true, existing bound import directory will be saved correctly (because some compilers and bind.exe put it to PE headers) -void rebuild_pe(pe_base& pe, image_dos_header& dos_header, bool strip_dos_header, bool change_size_of_headers, bool save_bound_import) -{ - dos_header = pe.get_dos_header(); - - if(strip_dos_header) - { - //Strip stub overlay - pe.strip_stub_overlay(); - //BaseOfCode NT Headers field now overlaps - //e_lfanew field, so we're acrually setting - //e_lfanew with this call - pe.set_base_of_code(8 * sizeof(uint16_t)); - } - else - { - //Set start of PE headers - dos_header.e_lfanew = sizeof(image_dos_header) - + pe_utils::align_up(static_cast(pe.get_stub_overlay().size()), sizeof(uint32_t)); - } - - section_list& sections = pe.get_image_sections(); - - //Calculate pointer to section data - size_t ptr_to_section_data = (strip_dos_header ? 8 * sizeof(uint16_t) : sizeof(image_dos_header)) + pe.get_sizeof_nt_header() - + pe_utils::align_up(pe.get_stub_overlay().size(), sizeof(uint32_t)) - - sizeof(image_data_directory) * (image_numberof_directory_entries - pe.get_number_of_rvas_and_sizes()) - + sections.size() * sizeof(image_section_header); - - if(save_bound_import && pe.has_bound_import()) - { - //It will be aligned to DWORD, because we're aligning to DWORD everything above it - pe.set_directory_rva(image_directory_entry_bound_import, static_cast(ptr_to_section_data)); - ptr_to_section_data += pe.get_directory_size(image_directory_entry_bound_import); - } - - ptr_to_section_data = pe_utils::align_up(ptr_to_section_data, pe.get_file_alignment()); - - //Set size of headers and size of optional header - if(change_size_of_headers) - { - if(!pe.get_image_sections().empty()) - { - if(static_cast(ptr_to_section_data) > (*sections.begin()).get_virtual_address()) - throw pe_exception("Headers of PE file are too long. Try to strip STUB or don't build bound import", pe_exception::cannot_rebuild_image); - } - - pe.set_size_of_headers(static_cast(ptr_to_section_data)); - } - - //Set number of sections in PE header - pe.update_number_of_sections(); - - pe.update_image_size(); - - pe.set_size_of_optional_header(static_cast(pe.get_sizeof_opt_headers() - - sizeof(image_data_directory) * (image_numberof_directory_entries - pe.get_number_of_rvas_and_sizes()))); - - //Recalculate pointer to raw data according to section list - for(section_list::iterator it = sections.begin(); it != sections.end(); ++it) - { - //Save section headers PointerToRawData - (*it).set_pointer_to_raw_data(static_cast(ptr_to_section_data)); - ptr_to_section_data += (*it).get_aligned_raw_size(pe.get_file_alignment()); - } -} - -//Rebuild PE image and write it to "out" ostream -//If strip_dos_header is true, DOS headers partially will be used for PE headers -//If change_size_of_headers == true, SizeOfHeaders will be recalculated automatically -//If save_bound_import == true, existing bound import directory will be saved correctly (because some compilers and bind.exe put it to PE headers) -void rebuild_pe(pe_base& pe, std::ostream& out, bool strip_dos_header, bool change_size_of_headers, bool save_bound_import) -{ - if(out.bad()) - throw pe_exception("Stream is bad", pe_exception::stream_is_bad); - - if(save_bound_import && pe.has_bound_import()) - { - if(pe.section_data_length_from_rva(pe.get_directory_rva(image_directory_entry_bound_import), pe.get_directory_rva(image_directory_entry_bound_import), section_data_raw, true) - < pe.get_directory_size(image_directory_entry_bound_import)) - throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory); - } - - //Change ostream state - out.exceptions(std::ios::goodbit); - out.clear(); - - uint32_t original_bound_import_rva = pe.has_bound_import() ? pe.get_directory_rva(image_directory_entry_bound_import) : 0; - if(original_bound_import_rva && original_bound_import_rva > pe.get_size_of_headers()) - { - //No need to do anything with bound import directory - //if it is placed inside of any section, not headers - original_bound_import_rva = 0; - save_bound_import = false; - } - - { - image_dos_header dos_header; - - //Rebuild PE image headers - rebuild_pe(pe, dos_header, strip_dos_header, change_size_of_headers, save_bound_import); - - //Write DOS header - out.write(reinterpret_cast(&dos_header), strip_dos_header ? 8 * sizeof(uint16_t) : sizeof(image_dos_header)); - } - - //If we have stub overlay, write it too - { - const std::string& stub = pe.get_stub_overlay(); - if(stub.size()) - { - out.write(stub.data(), stub.size()); - size_t aligned_size = pe_utils::align_up(stub.size(), sizeof(uint32_t)); - //Align PE header, which is right after rich overlay - while(aligned_size > stub.size()) - { - out.put('\0'); - --aligned_size; - } - } - } - - //Write NT headers - out.write(static_cast(pe).get_nt_headers_ptr(), pe.get_sizeof_nt_header() - - sizeof(image_data_directory) * (image_numberof_directory_entries - pe.get_number_of_rvas_and_sizes())); - - //Write section headers - const section_list& sections = pe.get_image_sections(); - for(section_list::const_iterator it = sections.begin(); it != sections.end(); ++it) - { - if(it == sections.end() - 1) //If last section encountered - { - image_section_header header((*it).get_raw_header()); - header.SizeOfRawData = static_cast((*it).get_raw_data().length()); //Set non-aligned actual data length for it - out.write(reinterpret_cast(&header), sizeof(image_section_header)); - } - else - { - out.write(reinterpret_cast(&(*it).get_raw_header()), sizeof(image_section_header)); - } - } - - //Write bound import data if requested - if(save_bound_import && pe.has_bound_import()) - { - out.write(pe.section_data_from_rva(original_bound_import_rva, section_data_raw, true), - pe.get_directory_size(image_directory_entry_bound_import)); - } - - //Write section data finally - for(section_list::const_iterator it = sections.begin(); it != sections.end(); ++it) - { - const section& s = *it; - - std::streamoff wpos = out.tellp(); - - //Fill unused overlay data between sections with null bytes - for(unsigned int i = 0; i < s.get_pointer_to_raw_data() - wpos; i++) - out.put(0); - - //Write raw section data - out.write(s.get_raw_data().data(), s.get_raw_data().length()); - } -} - -//Rebuild PE image and write it to "out" file -//If strip_dos_header is true, DOS headers partially will be used for PE headers -//If change_size_of_headers == true, SizeOfHeaders will be recalculated automatically -//If save_bound_import == true, existing bound import directory will be saved correctly (because some compilers and bind.exe put it to PE headers) -void rebuild_pe(pe_base& pe, const char* out, bool strip_dos_header, bool change_size_of_headers, bool save_bound_import) -{ - std::ofstream pe_file(out, std::ios::out | std::ios::binary | std::ios::trunc); - if(!pe_file) - { - throw pe_exception("Error in open file.", pe_exception::stream_is_bad); - } - rebuild_pe(pe, pe_file, strip_dos_header, change_size_of_headers, save_bound_import); -} - - -} diff --git a/drivers/pe_bliss/pe_rebuilder.h b/drivers/pe_bliss/pe_rebuilder.h deleted file mode 100644 index 1cd10299d1..0000000000 --- a/drivers/pe_bliss/pe_rebuilder.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -#include -#include - -namespace pe_bliss -{ -class pe_base; -//Rebuilds PE image, writes resulting image to ostream "out". If strip_dos_header == true, DOS header will be stripped a little -//If change_size_of_headers == true, SizeOfHeaders will be recalculated automatically -//If save_bound_import == true, existing bound import directory will be saved correctly (because some compilers and bind.exe put it to PE headers) -void rebuild_pe(pe_base& pe, std::ostream& out, bool strip_dos_header = false, bool change_size_of_headers = true, bool save_bound_import = true); - -//Rebuild PE image and write it to "out" file -//If strip_dos_header is true, DOS headers partially will be used for PE headers -//If change_size_of_headers == true, SizeOfHeaders will be recalculated automatically -//If save_bound_import == true, existing bound import directory will be saved correctly (because some compilers and bind.exe put it to PE headers) -void rebuild_pe(pe_base& pe, const char* out, bool strip_dos_header = false, bool change_size_of_headers = true, bool save_bound_import = true); - -} diff --git a/drivers/pe_bliss/pe_relocations.cpp b/drivers/pe_bliss/pe_relocations.cpp deleted file mode 100644 index 2d674e1346..0000000000 --- a/drivers/pe_bliss/pe_relocations.cpp +++ /dev/null @@ -1,299 +0,0 @@ -#include -#include "pe_relocations.h" -#include "pe_properties_generic.h" - -namespace pe_bliss -{ -using namespace pe_win; - -//RELOCATIONS -//Default constructor -relocation_entry::relocation_entry() - :rva_(0), type_(0) -{} - -//Constructor from relocation item (WORD) -relocation_entry::relocation_entry(uint16_t relocation_value) - :rva_(relocation_value & ((1 << 12) - 1)), type_(relocation_value >> 12) -{} - -//Constructor from relative rva and relocation type -relocation_entry::relocation_entry(uint16_t rrva, uint16_t type) - :rva_(rrva), type_(type) -{} - -//Returns RVA of relocation -uint16_t relocation_entry::get_rva() const -{ - return rva_; -} - -//Returns type of relocation -uint16_t relocation_entry::get_type() const -{ - return type_; -} - -//Sets RVA of relocation -void relocation_entry::set_rva(uint16_t rva) -{ - rva_ = rva; -} - -//Sets type of relocation -void relocation_entry::set_type(uint16_t type) -{ - type_ = type; -} - -//Returns relocation item (rrva + type) -uint16_t relocation_entry::get_item() const -{ - return rva_ | (type_ << 12); -} - -//Sets relocation item (rrva + type) -void relocation_entry::set_item(uint16_t item) -{ - rva_ = item & ((1 << 12) - 1); - type_ = item >> 12; -} - -//Returns relocation list -const relocation_table::relocation_list& relocation_table::get_relocations() const -{ - return relocations_; -} - -//Adds relocation to table -void relocation_table::add_relocation(const relocation_entry& entry) -{ - relocations_.push_back(entry); -} - -//Default constructor -relocation_table::relocation_table() - :rva_(0) -{} - -//Constructor from RVA of relocation table -relocation_table::relocation_table(uint32_t rva) - :rva_(rva) -{} - -//Returns RVA of block -uint32_t relocation_table::get_rva() const -{ - return rva_; -} - -//Sets RVA of block -void relocation_table::set_rva(uint32_t rva) -{ - rva_ = rva; -} - -//Returns changeable relocation list -relocation_table::relocation_list& relocation_table::get_relocations() -{ - return relocations_; -} - -//Get relocation list of pe file, supports one-word sized relocations only -//If list_absolute_entries = true, IMAGE_REL_BASED_ABSOLUTE will be listed -const relocation_table_list get_relocations(const pe_base& pe, bool list_absolute_entries) -{ - relocation_table_list ret; - - //If image does not have relocations - if(!pe.has_reloc()) - return ret; - - //Check the length in bytes of the section containing relocation directory - if(pe.section_data_length_from_rva(pe.get_directory_rva(image_directory_entry_basereloc), - pe.get_directory_rva(image_directory_entry_basereloc), section_data_virtual, true) - < sizeof(image_base_relocation)) - throw pe_exception("Incorrect relocation directory", pe_exception::incorrect_relocation_directory); - - unsigned long current_pos = pe.get_directory_rva(image_directory_entry_basereloc); - //First IMAGE_BASE_RELOCATION table - image_base_relocation reloc_table = pe.section_data_from_rva(current_pos, section_data_virtual, true); - - if(reloc_table.SizeOfBlock % 2) - throw pe_exception("Incorrect relocation directory", pe_exception::incorrect_relocation_directory); - - unsigned long reloc_size = pe.get_directory_size(image_directory_entry_basereloc); - unsigned long read_size = 0; - - //reloc_table.VirtualAddress is not checked (not so important) - while(reloc_table.SizeOfBlock && read_size < reloc_size) - { - //Create relocation table - relocation_table table; - //Save RVA - table.set_rva(reloc_table.VirtualAddress); - - if(!pe_utils::is_sum_safe(current_pos, reloc_table.SizeOfBlock)) - throw pe_exception("Incorrect relocation directory", pe_exception::incorrect_relocation_directory); - - //List all relocations - for(unsigned long i = sizeof(image_base_relocation); i < reloc_table.SizeOfBlock; i += sizeof(uint16_t)) - { - relocation_entry entry(pe.section_data_from_rva(current_pos + i, section_data_virtual, true)); - if(list_absolute_entries || entry.get_type() != image_rel_based_absolute) - table.add_relocation(entry); - } - - //Save table - ret.push_back(table); - - //Go to next relocation block - if(!pe_utils::is_sum_safe(current_pos, reloc_table.SizeOfBlock)) - throw pe_exception("Incorrect relocation directory", pe_exception::incorrect_relocation_directory); - - current_pos += reloc_table.SizeOfBlock; - read_size += reloc_table.SizeOfBlock; - reloc_table = pe.section_data_from_rva(current_pos, section_data_virtual, true); - } - - return ret; -} - -//Simple relocations rebuilder -//To keep PE file working, don't remove any of existing relocations in -//relocation_table_list returned by a call to get_relocations() function -//auto_strip_last_section - if true and relocations are placed in the last section, it will be automatically stripped -//offset_from_section_start - offset from the beginning of reloc_section, where relocations data will be situated -//If save_to_pe_header is true, PE header will be modified automatically -const image_directory rebuild_relocations(pe_base& pe, const relocation_table_list& relocs, section& reloc_section, uint32_t offset_from_section_start, bool save_to_pe_header, bool auto_strip_last_section) -{ - //Check that reloc_section is attached to this PE image - if(!pe.section_attached(reloc_section)) - throw pe_exception("Relocations section must be attached to PE file", pe_exception::section_is_not_attached); - - uint32_t current_reloc_data_pos = pe_utils::align_up(offset_from_section_start, sizeof(uint32_t)); - - uint32_t needed_size = current_reloc_data_pos - offset_from_section_start; //Calculate needed size for relocation tables - uint32_t size_delta = needed_size; - - uint32_t start_reloc_pos = current_reloc_data_pos; - - //Enumerate relocation tables - for(relocation_table_list::const_iterator it = relocs.begin(); it != relocs.end(); ++it) - { - needed_size += static_cast((*it).get_relocations().size() * sizeof(uint16_t) /* relocations */ + sizeof(image_base_relocation) /* table header */); - //End of each table will be DWORD-aligned - if((start_reloc_pos + needed_size - size_delta) % sizeof(uint32_t)) - needed_size += sizeof(uint16_t); //Align it with IMAGE_REL_BASED_ABSOLUTE relocation - } - - //Check if reloc_section is last one. If it's not, check if there's enough place for relocations data - if(&reloc_section != &*(pe.get_image_sections().end() - 1) && - (reloc_section.empty() || pe_utils::align_up(reloc_section.get_size_of_raw_data(), pe.get_file_alignment()) < needed_size + current_reloc_data_pos)) - throw pe_exception("Insufficient space for relocations directory", pe_exception::insufficient_space); - - std::string& raw_data = reloc_section.get_raw_data(); - - //This will be done only if reloc_section is the last section of image or for section with unaligned raw length of data - if(raw_data.length() < needed_size + current_reloc_data_pos) - raw_data.resize(needed_size + current_reloc_data_pos); //Expand section raw data - - //Enumerate relocation tables - for(relocation_table_list::const_iterator it = relocs.begin(); it != relocs.end(); ++it) - { - //Create relocation table header - image_base_relocation reloc; - reloc.VirtualAddress = (*it).get_rva(); - const relocation_table::relocation_list& reloc_list = (*it).get_relocations(); - reloc.SizeOfBlock = static_cast(sizeof(image_base_relocation) + sizeof(uint16_t) * reloc_list.size()); - if((reloc_list.size() * sizeof(uint16_t)) % sizeof(uint32_t)) //If we must align end of relocation table - reloc.SizeOfBlock += sizeof(uint16_t); - - memcpy(&raw_data[current_reloc_data_pos], &reloc, sizeof(reloc)); - current_reloc_data_pos += sizeof(reloc); - - //Enumerate relocations in table - for(relocation_table::relocation_list::const_iterator r = reloc_list.begin(); r != reloc_list.end(); ++r) - { - //Save relocations - uint16_t reloc_value = (*r).get_item(); - memcpy(&raw_data[current_reloc_data_pos], &reloc_value, sizeof(reloc_value)); - current_reloc_data_pos += sizeof(reloc_value); - } - - if(current_reloc_data_pos % sizeof(uint32_t)) //If end of table is not DWORD-aligned - { - memset(&raw_data[current_reloc_data_pos], 0, sizeof(uint16_t)); //Align it with IMAGE_REL_BASED_ABSOLUTE relocation - current_reloc_data_pos += sizeof(uint16_t); - } - } - - image_directory ret(pe.rva_from_section_offset(reloc_section, start_reloc_pos), needed_size - size_delta); - - //Adjust section raw and virtual sizes - pe.recalculate_section_sizes(reloc_section, auto_strip_last_section); - - //If auto-rewrite of PE headers is required - if(save_to_pe_header) - { - pe.set_directory_rva(image_directory_entry_basereloc, ret.get_rva()); - pe.set_directory_size(image_directory_entry_basereloc, ret.get_size()); - - pe.clear_characteristics_flags(image_file_relocs_stripped); - pe.set_dll_characteristics(pe.get_dll_characteristics() | image_dllcharacteristics_dynamic_base); - } - - return ret; -} - -//Recalculates image base with the help of relocation tables -void rebase_image(pe_base& pe, const relocation_table_list& tables, uint64_t new_base) -{ - pe.get_pe_type() == pe_type_32 - ? rebase_image_base(pe, tables, new_base) - : rebase_image_base(pe, tables, new_base); -} - -//RELOCATIONS -//Recalculates image base with the help of relocation tables -//Recalculates VAs of DWORDS/QWORDS in image according to relocations -//Notice: if you move some critical structures like TLS, image relocations will not fix new -//positions of TLS VAs. Instead, some bytes that now doesn't belong to TLS will be fixed. -//It is recommended to rebase image in the very beginning and move all structures afterwards. -template -void rebase_image_base(pe_base& pe, const relocation_table_list& tables, uint64_t new_base) -{ - //Get current image base value - typename PEClassType::BaseSize image_base; - pe.get_image_base(image_base); - - //ImageBase difference - typename PEClassType::BaseSize base_rel = static_cast(static_cast(new_base) - image_base); - - //We need to fix addresses from relocation tables - //Enumerate relocation tables - for(relocation_table_list::const_iterator it = tables.begin(); it != tables.end(); ++it) - { - const relocation_table::relocation_list& relocs = (*it).get_relocations(); - - uint32_t base_rva = (*it).get_rva(); - - //Enumerate relocations - for(relocation_table::relocation_list::const_iterator rel = relocs.begin(); rel != relocs.end(); ++rel) - { - //Skip ABSOLUTE entries - if((*rel).get_type() == pe_win::image_rel_based_absolute) - continue; - - //Recalculate value by RVA and rewrite it - uint32_t current_rva = base_rva + (*rel).get_rva(); - typename PEClassType::BaseSize value = pe.section_data_from_rva(current_rva, section_data_raw, true); - value += base_rel; - memcpy(pe.section_data_from_rva(current_rva, true), &value, sizeof(value)); - } - } - - //Finally, save new image base - pe.set_image_base_64(new_base); -} -} diff --git a/drivers/pe_bliss/pe_relocations.h b/drivers/pe_bliss/pe_relocations.h deleted file mode 100644 index d4c7b19230..0000000000 --- a/drivers/pe_bliss/pe_relocations.h +++ /dev/null @@ -1,101 +0,0 @@ -#pragma once -#include -#include "pe_structures.h" -#include "pe_base.h" -#include "pe_directory.h" - -namespace pe_bliss -{ -//Class representing relocation entry -//RVA of relocation is not actually RVA, but -//(real RVA) - (RVA of table) -class relocation_entry -{ -public: - //Default constructor - relocation_entry(); - //Constructor from relocation item (WORD) - explicit relocation_entry(uint16_t relocation_value); - //Constructor from relative rva and relocation type - relocation_entry(uint16_t rrva, uint16_t type); - - //Returns RVA of relocation (actually, relative RVA from relocation table RVA) - uint16_t get_rva() const; - //Returns type of relocation - uint16_t get_type() const; - - //Returns relocation item (rrva + type) - uint16_t get_item() const; - -public: //Setters do not change everything inside image, they are used by PE class - //You can also use them to rebuild relocations using rebuild_relocations() - - //Sets RVA of relocation (actually, relative RVA from relocation table RVA) - void set_rva(uint16_t rva); - //Sets type of relocation - void set_type(uint16_t type); - - //Sets relocation item (rrva + type) - void set_item(uint16_t item); - -private: - uint16_t rva_; - uint16_t type_; -}; - -//Class representing relocation table -class relocation_table -{ -public: - typedef std::vector relocation_list; - -public: - //Default constructor - relocation_table(); - //Constructor from RVA of relocation table - explicit relocation_table(uint32_t rva); - - //Returns relocation list - const relocation_list& get_relocations() const; - //Returns RVA of block - uint32_t get_rva() const; - -public: //These functions do not change everything inside image, they are used by PE class - //You can also use them to rebuild relocations using rebuild_relocations() - - //Adds relocation to table - void add_relocation(const relocation_entry& entry); - //Returns changeable relocation list - relocation_list& get_relocations(); - //Sets RVA of block - void set_rva(uint32_t rva); - -private: - uint32_t rva_; - relocation_list relocations_; -}; - -typedef std::vector relocation_table_list; - -//Get relocation list of pe file, supports one-word sized relocations only -//If list_absolute_entries = true, IMAGE_REL_BASED_ABSOLUTE will be listed -const relocation_table_list get_relocations(const pe_base& pe, bool list_absolute_entries = false); - -//Simple relocations rebuilder -//To keep PE file working, don't remove any of existing relocations in -//relocation_table_list returned by a call to get_relocations() function -//auto_strip_last_section - if true and relocations are placed in the last section, it will be automatically stripped -//offset_from_section_start - offset from the beginning of reloc_section, where relocations data will be situated -//If save_to_pe_header is true, PE header will be modified automatically -const image_directory rebuild_relocations(pe_base& pe, const relocation_table_list& relocs, section& reloc_section, uint32_t offset_from_section_start = 0, bool save_to_pe_header = true, bool auto_strip_last_section = true); - -//Recalculates image base with the help of relocation tables -//Recalculates VAs of DWORDS/QWORDS in image according to relocations -//Notice: if you move some critical structures like TLS, image relocations will not fix new -//positions of TLS VAs. Instead, some bytes that now doesn't belong to TLS will be fixed. -//It is recommended to rebase image in the very beginning and move all structures afterwards. -void rebase_image(pe_base& pe, const relocation_table_list& tables, uint64_t new_base); - -template -void rebase_image_base(pe_base& pe, const relocation_table_list& tables, uint64_t new_base); -} diff --git a/drivers/pe_bliss/pe_resource_manager.cpp b/drivers/pe_bliss/pe_resource_manager.cpp deleted file mode 100644 index 1db952efcb..0000000000 --- a/drivers/pe_bliss/pe_resource_manager.cpp +++ /dev/null @@ -1,265 +0,0 @@ -#include -#include -#include -#include -#include -#include "pe_resource_manager.h" -#include "resource_internal.h" - -namespace pe_bliss -{ -using namespace pe_win; - -//Constructor from root resource directory -pe_resource_manager::pe_resource_manager(resource_directory& root_directory) - :pe_resource_viewer(root_directory), root_dir_edit_(root_directory) -{} - -resource_directory& pe_resource_manager::get_root_directory() -{ - return root_dir_edit_; -} - -//Removes all resources of given type or root name -//If there's more than one directory entry of a given type, only the -//first one will be deleted (that's an unusual situation) -//Returns true if resource was deleted -bool pe_resource_manager::remove_resource_type(resource_type type) -{ - //Search for resource type - resource_directory::entry_list& entries = root_dir_edit_.get_entry_list(); - resource_directory::entry_list::iterator it = std::find_if(entries.begin(), entries.end(), resource_directory::id_entry_finder(type)); - if(it != entries.end()) - { - //Remove it, if found - entries.erase(it); - return true; - } - - return false; -} - -bool pe_resource_manager::remove_resource(const std::wstring& root_name) -{ - //Search for resource type - resource_directory::entry_list& entries = root_dir_edit_.get_entry_list(); - resource_directory::entry_list::iterator it = std::find_if(entries.begin(), entries.end(), resource_directory::name_entry_finder(root_name)); - if(it != entries.end()) - { - //Remove it, if found - entries.erase(it); - return true; - } - - return false; -} - -//Helper to remove resource -bool pe_resource_manager::remove_resource(const resource_directory::entry_finder& root_finder, const resource_directory::entry_finder& finder) -{ - //Search for resource type - resource_directory::entry_list& entries_type = root_dir_edit_.get_entry_list(); - resource_directory::entry_list::iterator it_type = std::find_if(entries_type.begin(), entries_type.end(), root_finder); - if(it_type != entries_type.end()) - { - //Search for resource name/ID with "finder" - resource_directory::entry_list& entries_name = (*it_type).get_resource_directory().get_entry_list(); - resource_directory::entry_list::iterator it_name = std::find_if(entries_name.begin(), entries_name.end(), finder); - if(it_name != entries_name.end()) - { - //Erase resource, if found - entries_name.erase(it_name); - if(entries_name.empty()) - entries_type.erase(it_type); - - return true; - } - } - - return false; -} - -//Removes all resource languages by resource type/root name and name -//Deletes only one entry of given type and name -//Returns true if resource was deleted -bool pe_resource_manager::remove_resource(resource_type type, const std::wstring& name) -{ - return remove_resource(resource_directory::entry_finder(type), resource_directory::entry_finder(name)); -} - -bool pe_resource_manager::remove_resource(const std::wstring& root_name, const std::wstring& name) -{ - return remove_resource(resource_directory::entry_finder(root_name), resource_directory::entry_finder(name)); -} - -//Removes all resource languages by resource type/root name and ID -//Deletes only one entry of given type and ID -//Returns true if resource was deleted -bool pe_resource_manager::remove_resource(resource_type type, uint32_t id) -{ - return remove_resource(resource_directory::entry_finder(type), resource_directory::entry_finder(id)); -} - -bool pe_resource_manager::remove_resource(const std::wstring& root_name, uint32_t id) -{ - return remove_resource(resource_directory::entry_finder(root_name), resource_directory::entry_finder(id)); -} - -//Helper to remove resource -bool pe_resource_manager::remove_resource(const resource_directory::entry_finder& root_finder, const resource_directory::entry_finder& finder, uint32_t language) -{ - //Search for resource type - resource_directory::entry_list& entries_type = root_dir_edit_.get_entry_list(); - resource_directory::entry_list::iterator it_type = std::find_if(entries_type.begin(), entries_type.end(), root_finder); - if(it_type != entries_type.end()) - { - //Search for resource name/ID with "finder" - resource_directory::entry_list& entries_name = (*it_type).get_resource_directory().get_entry_list(); - resource_directory::entry_list::iterator it_name = std::find_if(entries_name.begin(), entries_name.end(), finder); - if(it_name != entries_name.end()) - { - //Search for resource language - resource_directory::entry_list& entries_lang = (*it_name).get_resource_directory().get_entry_list(); - resource_directory::entry_list::iterator it_lang = std::find_if(entries_lang.begin(), entries_lang.end(), resource_directory::id_entry_finder(language)); - if(it_lang != entries_lang.end()) - { - //Erase resource, if found - entries_lang.erase(it_lang); - if(entries_lang.empty()) - { - entries_name.erase(it_name); - if(entries_name.empty()) - entries_type.erase(it_type); - } - - return true; - } - } - } - - return false; -} - -//Removes resource language by resource type/root name and name -//Deletes only one entry of given type, name and language -//Returns true if resource was deleted -bool pe_resource_manager::remove_resource(resource_type type, const std::wstring& name, uint32_t language) -{ - return remove_resource(resource_directory::entry_finder(type), resource_directory::entry_finder(name), language); -} - -bool pe_resource_manager::remove_resource(const std::wstring& root_name, const std::wstring& name, uint32_t language) -{ - return remove_resource(resource_directory::entry_finder(root_name), resource_directory::entry_finder(name), language); -} - -//Removes recource language by resource type/root name and ID -//Deletes only one entry of given type, ID and language -//Returns true if resource was deleted -bool pe_resource_manager::remove_resource(resource_type type, uint32_t id, uint32_t language) -{ - return remove_resource(resource_directory::entry_finder(type), resource_directory::entry_finder(id), language); -} - -bool pe_resource_manager::remove_resource(const std::wstring& root_name, uint32_t id, uint32_t language) -{ - return remove_resource(resource_directory::entry_finder(root_name), resource_directory::entry_finder(id), language); -} - -//Helper to add/replace resource -void pe_resource_manager::add_resource(const std::string& data, resource_type type, resource_directory_entry& new_entry, const resource_directory::entry_finder& finder, uint32_t language, uint32_t codepage, uint32_t timestamp) -{ - resource_directory_entry new_type_entry; - new_type_entry.set_id(type); - - add_resource(data, new_type_entry, resource_directory::entry_finder(type), new_entry, finder, language, codepage, timestamp); -} - -//Helper to add/replace resource -void pe_resource_manager::add_resource(const std::string& data, const std::wstring& root_name, resource_directory_entry& new_entry, const resource_directory::entry_finder& finder, uint32_t language, uint32_t codepage, uint32_t timestamp) -{ - resource_directory_entry new_type_entry; - new_type_entry.set_name(root_name); - - add_resource(data, new_type_entry, resource_directory::entry_finder(root_name), new_entry, finder, language, codepage, timestamp); -} - -//Helper to add/replace resource -void pe_resource_manager::add_resource(const std::string& data, resource_directory_entry& new_root_entry, const resource_directory::entry_finder& root_finder, resource_directory_entry& new_entry, const resource_directory::entry_finder& finder, uint32_t language, uint32_t codepage, uint32_t timestamp) -{ - //Search for resource type - resource_directory::entry_list* entries = &root_dir_edit_.get_entry_list(); - resource_directory::entry_list::iterator it = std::find_if(entries->begin(), entries->end(), root_finder); - if(it == entries->end()) - { - //Add resource type directory, if it was not found - resource_directory dir; - dir.set_timestamp(timestamp); - new_root_entry.add_resource_directory(dir); - entries->push_back(new_root_entry); - it = entries->end() - 1; - } - - //Search for resource name/ID directory with "finder" - entries = &(*it).get_resource_directory().get_entry_list(); - it = std::find_if(entries->begin(), entries->end(), finder); - if(it == entries->end()) - { - //Add resource name/ID directory, if it was not found - resource_directory dir; - dir.set_timestamp(timestamp); - new_entry.add_resource_directory(dir); - entries->push_back(new_entry); - it = entries->end() - 1; - } - - //Search for data resource entry by language - entries = &(*it).get_resource_directory().get_entry_list(); - it = std::find_if(entries->begin(), entries->end(), resource_directory::id_entry_finder(language)); - if(it != entries->end()) - entries->erase(it); //Erase it, if found - - //Add new data entry - resource_directory_entry new_dir_data_entry; - resource_data_entry data_dir(data, codepage); - new_dir_data_entry.add_data_entry(data_dir); - new_dir_data_entry.set_id(language); - entries->push_back(new_dir_data_entry); -} - -//Adds resource. If resource already exists, replaces it -void pe_resource_manager::add_resource(const std::string& data, resource_type type, const std::wstring& name, uint32_t language, uint32_t codepage, uint32_t timestamp) -{ - resource_directory_entry new_entry; - new_entry.set_name(name); - - add_resource(data, type, new_entry, resource_directory::entry_finder(name), language, codepage, timestamp); -} - -//Adds resource. If resource already exists, replaces it -void pe_resource_manager::add_resource(const std::string& data, const std::wstring& root_name, const std::wstring& name, uint32_t language, uint32_t codepage, uint32_t timestamp) -{ - resource_directory_entry new_entry; - new_entry.set_name(name); - - add_resource(data, root_name, new_entry, resource_directory::entry_finder(name), language, codepage, timestamp); -} - -//Adds resource. If resource already exists, replaces it -void pe_resource_manager::add_resource(const std::string& data, resource_type type, uint32_t id, uint32_t language, uint32_t codepage, uint32_t timestamp) -{ - resource_directory_entry new_entry; - new_entry.set_id(id); - - add_resource(data, type, new_entry, resource_directory::entry_finder(id), language, codepage, timestamp); -} - -//Adds resource. If resource already exists, replaces it -void pe_resource_manager::add_resource(const std::string& data, const std::wstring& root_name, uint32_t id, uint32_t language, uint32_t codepage, uint32_t timestamp) -{ - resource_directory_entry new_entry; - new_entry.set_id(id); - - add_resource(data, root_name, new_entry, resource_directory::entry_finder(id), language, codepage, timestamp); -} -} diff --git a/drivers/pe_bliss/pe_resource_manager.h b/drivers/pe_bliss/pe_resource_manager.h deleted file mode 100644 index a12f140cfe..0000000000 --- a/drivers/pe_bliss/pe_resource_manager.h +++ /dev/null @@ -1,92 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include "pe_base.h" -#include "pe_structures.h" -#include "pe_resources.h" -#include "message_table.h" -#include "file_version_info.h" -#include "pe_resource_viewer.h" -#include "resource_data_info.h" - -namespace pe_bliss -{ -//Derived class to edit PE resources -class pe_resource_manager : public pe_resource_viewer -{ -public: - //Constructor from root resource directory - explicit pe_resource_manager(resource_directory& root_directory); - - resource_directory& get_root_directory(); - -public: //Resource editing - //Removes all resources of given type or root name - //If there's more than one directory entry of a given type, only the - //first one will be deleted (that's an unusual situation) - //Returns true if resource was deleted - bool remove_resource_type(resource_type type); - bool remove_resource(const std::wstring& root_name); - - //Removes all resource languages by resource type/root name and name - //Deletes only one entry of given type and name - //Returns true if resource was deleted - bool remove_resource(resource_type type, const std::wstring& name); - bool remove_resource(const std::wstring& root_name, const std::wstring& name); - //Removes all resource languages by resource type/root name and ID - //Deletes only one entry of given type and ID - //Returns true if resource was deleted - bool remove_resource(resource_type type, uint32_t id); - bool remove_resource(const std::wstring& root_name, uint32_t id); - - //Removes resource language by resource type/root name and name - //Deletes only one entry of given type, name and language - //Returns true if resource was deleted - bool remove_resource(resource_type type, const std::wstring& name, uint32_t language); - bool remove_resource(const std::wstring& root_name, const std::wstring& name, uint32_t language); - //Removes recource language by resource type/root name and ID - //Deletes only one entry of given type, ID and language - //Returns true if resource was deleted - bool remove_resource(resource_type type, uint32_t id, uint32_t language); - bool remove_resource(const std::wstring& root_name, uint32_t id, uint32_t language); - - //Adds resource. If resource already exists, replaces it - //timestamp will be used for directories that will be added - void add_resource(const std::string& data, resource_type type, const std::wstring& name, uint32_t language, uint32_t codepage = 0, uint32_t timestamp = 0); - void add_resource(const std::string& data, const std::wstring& root_name, const std::wstring& name, uint32_t language, uint32_t codepage = 0, uint32_t timestamp = 0); - //Adds resource. If resource already exists, replaces it - //timestamp will be used for directories that will be added - void add_resource(const std::string& data, resource_type type, uint32_t id, uint32_t language, uint32_t codepage = 0, uint32_t timestamp = 0); - void add_resource(const std::string& data, const std::wstring& root_name, uint32_t id, uint32_t language, uint32_t codepage = 0, uint32_t timestamp = 0); - -public: - //Helpers to add/replace resource - void add_resource(const std::string& data, resource_type type, - resource_directory_entry& new_entry, - const resource_directory::entry_finder& finder, - uint32_t language, uint32_t codepage, uint32_t timestamp); - - void add_resource(const std::string& data, const std::wstring& root_name, - resource_directory_entry& new_entry, - const resource_directory::entry_finder& finder, - uint32_t language, uint32_t codepage, uint32_t timestamp); - - void add_resource(const std::string& data, resource_directory_entry& new_root_entry, - const resource_directory::entry_finder& root_finder, - resource_directory_entry& new_entry, - const resource_directory::entry_finder& finder, - uint32_t language, uint32_t codepage, uint32_t timestamp); - -private: - //Root resource directory. We're not copying it, because it might be heavy - resource_directory& root_dir_edit_; - - //Helper to remove resource - bool remove_resource(const resource_directory::entry_finder& root_finder, const resource_directory::entry_finder& finder); - - //Helper to remove resource - bool remove_resource(const resource_directory::entry_finder& root_finder, const resource_directory::entry_finder& finder, uint32_t language); -}; -} diff --git a/drivers/pe_bliss/pe_resource_viewer.cpp b/drivers/pe_bliss/pe_resource_viewer.cpp deleted file mode 100644 index 1414c33fed..0000000000 --- a/drivers/pe_bliss/pe_resource_viewer.cpp +++ /dev/null @@ -1,361 +0,0 @@ -#include -#include -#include "pe_resource_viewer.h" -#include "pe_structures.h" - -namespace pe_bliss -{ -using namespace pe_win; - -//Constructor from root resource_directory -pe_resource_viewer::pe_resource_viewer(const resource_directory& root_directory) - :root_dir_(root_directory) -{} - -const resource_directory& pe_resource_viewer::get_root_directory() const -{ - return root_dir_; -} - -//Finder helpers -bool pe_resource_viewer::has_name::operator()(const resource_directory_entry& entry) const -{ - return entry.is_named(); -} - -bool pe_resource_viewer::has_id::operator()(const resource_directory_entry& entry) const -{ - return !entry.is_named(); -} - -//Lists resource types existing in PE file (non-named only) -const pe_resource_viewer::resource_type_list pe_resource_viewer::list_resource_types() const -{ - resource_type_list ret; - - //Get root directory entries list - const resource_directory::entry_list& entries = root_dir_.get_entry_list(); - for(resource_directory::entry_list::const_iterator it = entries.begin(); it != entries.end(); ++it) - { - //List all non-named items - if(!(*it).is_named()) - ret.push_back((*it).get_id()); - } - - return ret; -} - -//Returns true if resource type exists -bool pe_resource_viewer::resource_exists(resource_type type) const -{ - const resource_directory::entry_list& entries = root_dir_.get_entry_list(); - return std::find_if(entries.begin(), entries.end(), resource_directory::id_entry_finder(type)) != entries.end(); -} - -//Returns true if resource name exists -bool pe_resource_viewer::resource_exists(const std::wstring& root_name) const -{ - const resource_directory::entry_list& entries = root_dir_.get_entry_list(); - return std::find_if(entries.begin(), entries.end(), resource_directory::name_entry_finder(root_name)) != entries.end(); -} - -//Helper function to get name list from entry list -const pe_resource_viewer::resource_name_list pe_resource_viewer::get_name_list(const resource_directory::entry_list& entries) -{ - resource_name_list ret; - - for(resource_directory::entry_list::const_iterator it = entries.begin(); it != entries.end(); ++it) - { - //List all named items - if((*it).is_named()) - ret.push_back((*it).get_name()); - } - - return ret; -} - -//Helper function to get ID list from entry list -const pe_resource_viewer::resource_id_list pe_resource_viewer::get_id_list(const resource_directory::entry_list& entries) -{ - resource_id_list ret; - - for(resource_directory::entry_list::const_iterator it = entries.begin(); it != entries.end(); ++it) - { - //List all non-named items - if(!(*it).is_named()) - ret.push_back((*it).get_id()); - } - - return ret; -} - -//Lists resource names existing in PE file by resource type -const pe_resource_viewer::resource_name_list pe_resource_viewer::list_resource_names(resource_type type) const -{ - return get_name_list(root_dir_.entry_by_id(type).get_resource_directory().get_entry_list()); -} - -//Lists resource names existing in PE file by resource name -const pe_resource_viewer::resource_name_list pe_resource_viewer::list_resource_names(const std::wstring& root_name) const -{ - return get_name_list(root_dir_.entry_by_name(root_name).get_resource_directory().get_entry_list()); -} - -//Lists resource IDs existing in PE file by resource type -const pe_resource_viewer::resource_id_list pe_resource_viewer::list_resource_ids(resource_type type) const -{ - return get_id_list(root_dir_.entry_by_id(type).get_resource_directory().get_entry_list()); -} - -//Lists resource IDs existing in PE file by resource name -const pe_resource_viewer::resource_id_list pe_resource_viewer::list_resource_ids(const std::wstring& root_name) const -{ - return get_id_list(root_dir_.entry_by_name(root_name).get_resource_directory().get_entry_list()); -} - -//Returns resource count by type -unsigned long pe_resource_viewer::get_resource_count(resource_type type) const -{ - return static_cast( - root_dir_ //Type directory - .entry_by_id(type) - .get_resource_directory() //Name/ID directory - .get_entry_list() - .size()); -} - -//Returns resource count by name -unsigned long pe_resource_viewer::get_resource_count(const std::wstring& root_name) const -{ - return static_cast( - root_dir_ //Type directory - .entry_by_name(root_name) - .get_resource_directory() //Name/ID directory - .get_entry_list() - .size()); -} - -//Returns language count of resource by resource type and name -unsigned long pe_resource_viewer::get_language_count(resource_type type, const std::wstring& name) const -{ - const resource_directory::entry_list& entries = - root_dir_ //Type directory - .entry_by_id(type) - .get_resource_directory() //Name/ID directory - .entry_by_name(name) - .get_resource_directory() //Language directory - .get_entry_list(); - - return static_cast(std::count_if(entries.begin(), entries.end(), has_id())); -} - -//Returns language count of resource by resource names -unsigned long pe_resource_viewer::get_language_count(const std::wstring& root_name, const std::wstring& name) const -{ - const resource_directory::entry_list& entries = - root_dir_ //Type directory - .entry_by_name(root_name) - .get_resource_directory() //Name/ID directory - .entry_by_name(name) - .get_resource_directory() //Language directory - .get_entry_list(); - - return static_cast(std::count_if(entries.begin(), entries.end(), has_id())); -} - -//Returns language count of resource by resource type and ID -unsigned long pe_resource_viewer::get_language_count(resource_type type, uint32_t id) const -{ - const resource_directory::entry_list& entries = - root_dir_ //Type directory - .entry_by_id(type) - .get_resource_directory() //Name/ID directory - .entry_by_id(id) - .get_resource_directory() //Language directory - .get_entry_list(); - - return static_cast(std::count_if(entries.begin(), entries.end(), has_id())); -} - -//Returns language count of resource by resource name and ID -unsigned long pe_resource_viewer::get_language_count(const std::wstring& root_name, uint32_t id) const -{ - const resource_directory::entry_list& entries = - root_dir_ //Type directory - .entry_by_name(root_name) - .get_resource_directory() //Name/ID directory - .entry_by_id(id) - .get_resource_directory() //Language directory - .get_entry_list(); - - return static_cast(std::count_if(entries.begin(), entries.end(), has_id())); -} - -//Lists resource languages by resource type and name -const pe_resource_viewer::resource_language_list pe_resource_viewer::list_resource_languages(resource_type type, const std::wstring& name) const -{ - const resource_directory::entry_list& entries = - root_dir_ //Type directory - .entry_by_id(type) - .get_resource_directory() //Name/ID directory - .entry_by_name(name) - .get_resource_directory() //Language directory - .get_entry_list(); - - return get_id_list(entries); -} - -//Lists resource languages by resource names -const pe_resource_viewer::resource_language_list pe_resource_viewer::list_resource_languages(const std::wstring& root_name, const std::wstring& name) const -{ - const resource_directory::entry_list& entries = - root_dir_ //Type directory - .entry_by_name(root_name) - .get_resource_directory() //Name/ID directory - .entry_by_name(name) - .get_resource_directory() //Language directory - .get_entry_list(); - - return get_id_list(entries); -} - -//Lists resource languages by resource type and ID -const pe_resource_viewer::resource_language_list pe_resource_viewer::list_resource_languages(resource_type type, uint32_t id) const -{ - const resource_directory::entry_list& entries = - root_dir_ //Type directory - .entry_by_id(type) - .get_resource_directory() //Name/ID directory - .entry_by_id(id) - .get_resource_directory() //Language directory - .get_entry_list(); - - return get_id_list(entries); -} - -//Lists resource languages by resource name and ID -const pe_resource_viewer::resource_language_list pe_resource_viewer::list_resource_languages(const std::wstring& root_name, uint32_t id) const -{ - const resource_directory::entry_list& entries = - root_dir_ //Type directory - .entry_by_name(root_name) - .get_resource_directory() //Name/ID directory - .entry_by_id(id) - .get_resource_directory() //Language directory - .get_entry_list(); - - return get_id_list(entries); -} - -//Returns raw resource data by type, name and language -const resource_data_info pe_resource_viewer::get_resource_data_by_name(uint32_t language, resource_type type, const std::wstring& name) const -{ - return resource_data_info(root_dir_ //Type directory - .entry_by_id(type) - .get_resource_directory() //Name/ID directory - .entry_by_name(name) - .get_resource_directory() //Language directory - .entry_by_id(language) - .get_data_entry()); //Data directory -} - -//Returns raw resource data by root name, name and language -const resource_data_info pe_resource_viewer::get_resource_data_by_name(uint32_t language, const std::wstring& root_name, const std::wstring& name) const -{ - return resource_data_info(root_dir_ //Type directory - .entry_by_name(root_name) - .get_resource_directory() //Name/ID directory - .entry_by_name(name) - .get_resource_directory() //Language directory - .entry_by_id(language) - .get_data_entry()); //Data directory -} - -//Returns raw resource data by type, ID and language -const resource_data_info pe_resource_viewer::get_resource_data_by_id(uint32_t language, resource_type type, uint32_t id) const -{ - return resource_data_info(root_dir_ //Type directory - .entry_by_id(type) - .get_resource_directory() //Name/ID directory - .entry_by_id(id) - .get_resource_directory() //Language directory - .entry_by_id(language) - .get_data_entry()); //Data directory -} - -//Returns raw resource data by root name, ID and language -const resource_data_info pe_resource_viewer::get_resource_data_by_id(uint32_t language, const std::wstring& root_name, uint32_t id) const -{ - return resource_data_info(root_dir_ //Type directory - .entry_by_name(root_name) - .get_resource_directory() //Name/ID directory - .entry_by_id(id) - .get_resource_directory() //Language directory - .entry_by_id(language) - .get_data_entry()); //Data directory -} - -//Returns raw resource data by type, name and index in language directory (instead of language) -const resource_data_info pe_resource_viewer::get_resource_data_by_name(resource_type type, const std::wstring& name, uint32_t index) const -{ - const resource_directory::entry_list& entries = root_dir_ //Type directory - .entry_by_id(type) - .get_resource_directory() //Name/ID directory - .entry_by_name(name) - .get_resource_directory() //Language directory - .get_entry_list(); - - if(entries.size() <= index) - throw pe_exception("Resource data entry not found", pe_exception::resource_data_entry_not_found); - - return resource_data_info(entries.at(index).get_data_entry()); //Data directory -} - -//Returns raw resource data by root name, name and index in language directory (instead of language) -const resource_data_info pe_resource_viewer::get_resource_data_by_name(const std::wstring& root_name, const std::wstring& name, uint32_t index) const -{ - const resource_directory::entry_list& entries = root_dir_ //Type directory - .entry_by_name(root_name) - .get_resource_directory() //Name/ID directory - .entry_by_name(name) - .get_resource_directory() //Language directory - .get_entry_list(); - - if(entries.size() <= index) - throw pe_exception("Resource data entry not found", pe_exception::resource_data_entry_not_found); - - return resource_data_info(entries.at(index).get_data_entry()); //Data directory -} - -//Returns raw resource data by type, ID and index in language directory (instead of language) -const resource_data_info pe_resource_viewer::get_resource_data_by_id(resource_type type, uint32_t id, uint32_t index) const -{ - const resource_directory::entry_list& entries = root_dir_ //Type directory - .entry_by_id(type) - .get_resource_directory() //Name/ID directory - .entry_by_id(id) - .get_resource_directory() //Language directory - .get_entry_list(); - - if(entries.size() <= index) - throw pe_exception("Resource data entry not found", pe_exception::resource_data_entry_not_found); - - return resource_data_info(entries.at(index).get_data_entry()); //Data directory -} - -//Returns raw resource data by root name, ID and index in language directory (instead of language) -const resource_data_info pe_resource_viewer::get_resource_data_by_id(const std::wstring& root_name, uint32_t id, uint32_t index) const -{ - const resource_directory::entry_list& entries = root_dir_ //Type directory - .entry_by_name(root_name) - .get_resource_directory() //Name/ID directory - .entry_by_id(id) - .get_resource_directory() //Language directory - .get_entry_list(); - - if(entries.size() <= index) - throw pe_exception("Resource data entry not found", pe_exception::resource_data_entry_not_found); - - return resource_data_info(entries.at(index).get_data_entry()); //Data directory -} -} diff --git a/drivers/pe_bliss/pe_resource_viewer.h b/drivers/pe_bliss/pe_resource_viewer.h deleted file mode 100644 index f469d59143..0000000000 --- a/drivers/pe_bliss/pe_resource_viewer.h +++ /dev/null @@ -1,132 +0,0 @@ -#pragma once -#include -#include -#include "pe_structures.h" -#include "pe_resources.h" -#include "message_table.h" -#include "resource_data_info.h" - -namespace pe_bliss -{ - //PE resource manager allows to read resources from PE files -class pe_resource_viewer -{ -public: - //Resource type enumeration - enum resource_type - { - resource_cursor = 1, - resource_bitmap = 2, - resource_icon = 3, - resource_menu = 4, - resource_dialog = 5, - resource_string = 6, - resource_fontdir = 7, - resource_font = 8, - resource_accelerator = 9, - resource_rcdata = 10, - resource_message_table = 11, - resource_cursor_group = 12, - resource_icon_group = 14, - resource_version = 16, - resource_dlginclude = 17, - resource_plugplay = 19, - resource_vxd = 20, - resource_anicursor = 21, - resource_aniicon = 22, - resource_html = 23, - resource_manifest = 24 - }; - -public: - //Some useful typedefs - typedef std::vector resource_type_list; - typedef std::vector resource_id_list; - typedef std::vector resource_name_list; - typedef std::vector resource_language_list; - -public: - //Constructor from root resource_directory from PE file - explicit pe_resource_viewer(const resource_directory& root_directory); - - const resource_directory& get_root_directory() const; - - //Lists resource types existing in PE file (non-named only) - const resource_type_list list_resource_types() const; - //Returns true if resource type exists - bool resource_exists(resource_type type) const; - //Returns true if resource name exists - bool resource_exists(const std::wstring& root_name) const; - - //Lists resource names existing in PE file by resource type - const resource_name_list list_resource_names(resource_type type) const; - //Lists resource names existing in PE file by resource name - const resource_name_list list_resource_names(const std::wstring& root_name) const; - //Lists resource IDs existing in PE file by resource type - const resource_id_list list_resource_ids(resource_type type) const; - //Lists resource IDs existing in PE file by resource name - const resource_id_list list_resource_ids(const std::wstring& root_name) const; - //Returns resource count by type - unsigned long get_resource_count(resource_type type) const; - //Returns resource count by name - unsigned long get_resource_count(const std::wstring& root_name) const; - - //Returns language count of resource by resource type and name - unsigned long get_language_count(resource_type type, const std::wstring& name) const; - //Returns language count of resource by resource names - unsigned long get_language_count(const std::wstring& root_name, const std::wstring& name) const; - //Returns language count of resource by resource type and ID - unsigned long get_language_count(resource_type type, uint32_t id) const; - //Returns language count of resource by resource name and ID - unsigned long get_language_count(const std::wstring& root_name, uint32_t id) const; - //Lists resource languages by resource type and name - const resource_language_list list_resource_languages(resource_type type, const std::wstring& name) const; - //Lists resource languages by resource names - const resource_language_list list_resource_languages(const std::wstring& root_name, const std::wstring& name) const; - //Lists resource languages by resource type and ID - const resource_language_list list_resource_languages(resource_type type, uint32_t id) const; - //Lists resource languages by resource name and ID - const resource_language_list list_resource_languages(const std::wstring& root_name, uint32_t id) const; - - //Returns raw resource data by type, name and language - const resource_data_info get_resource_data_by_name(uint32_t language, resource_type type, const std::wstring& name) const; - //Returns raw resource data by root name, name and language - const resource_data_info get_resource_data_by_name(uint32_t language, const std::wstring& root_name, const std::wstring& name) const; - //Returns raw resource data by type, ID and language - const resource_data_info get_resource_data_by_id(uint32_t language, resource_type type, uint32_t id) const; - //Returns raw resource data by root name, ID and language - const resource_data_info get_resource_data_by_id(uint32_t language, const std::wstring& root_name, uint32_t id) const; - //Returns raw resource data by type, name and index in language directory (instead of language) - const resource_data_info get_resource_data_by_name(resource_type type, const std::wstring& name, uint32_t index = 0) const; - //Returns raw resource data by root name, name and index in language directory (instead of language) - const resource_data_info get_resource_data_by_name(const std::wstring& root_name, const std::wstring& name, uint32_t index = 0) const; - //Returns raw resource data by type, ID and index in language directory (instead of language) - const resource_data_info get_resource_data_by_id(resource_type type, uint32_t id, uint32_t index = 0) const; - //Returns raw resource data by root name, ID and index in language directory (instead of language) - const resource_data_info get_resource_data_by_id(const std::wstring& root_name, uint32_t id, uint32_t index = 0) const; - -protected: - //Root resource directory. We're not copying it, because it might be heavy - const resource_directory& root_dir_; - - //Helper function to get ID list from entry list - static const resource_id_list get_id_list(const resource_directory::entry_list& entries); - //Helper function to get name list from entry list - static const resource_name_list get_name_list(const resource_directory::entry_list& entries); - -protected: - //Helper structure - finder of resource_directory_entry that is named - struct has_name - { - public: - bool operator()(const resource_directory_entry& entry) const; - }; - - //Helper structure - finder of resource_directory_entry that is not named (has id) - struct has_id - { - public: - bool operator()(const resource_directory_entry& entry) const; - }; -}; -} diff --git a/drivers/pe_bliss/pe_resources.cpp b/drivers/pe_bliss/pe_resources.cpp deleted file mode 100644 index a819c7bb71..0000000000 --- a/drivers/pe_bliss/pe_resources.cpp +++ /dev/null @@ -1,705 +0,0 @@ -#include -#include -#include "pe_resources.h" - -namespace pe_bliss -{ -using namespace pe_win; - -//RESOURCES -//Default constructor -resource_data_entry::resource_data_entry() - :codepage_(0) -{} - -//Constructor from data -resource_data_entry::resource_data_entry(const std::string& data, uint32_t codepage) - :codepage_(codepage), data_(data) -{} - -//Returns resource data codepage -uint32_t resource_data_entry::get_codepage() const -{ - return codepage_; -} - -//Returns resource data -const std::string& resource_data_entry::get_data() const -{ - return data_; -} - -//Sets resource data codepage -void resource_data_entry::set_codepage(uint32_t codepage) -{ - codepage_ = codepage; -} - -//Sets resource data -void resource_data_entry::set_data(const std::string& data) -{ - data_ = data; -} - -//Default constructor -resource_directory_entry::includes::includes() - :data_(0) -{} - -//Default constructor -resource_directory_entry::resource_directory_entry() - :id_(0), includes_data_(false), named_(false) -{} - -//Copy constructor -resource_directory_entry::resource_directory_entry(const resource_directory_entry& other) - :id_(other.id_), name_(other.name_), includes_data_(other.includes_data_), named_(other.named_) -{ - //If union'ed pointer is not zero - if(other.ptr_.data_) - { - if(other.includes_data()) - ptr_.data_ = new resource_data_entry(*other.ptr_.data_); - else - ptr_.dir_ = new resource_directory(*other.ptr_.dir_); - } -} - -//Copy assignment operator -resource_directory_entry& resource_directory_entry::operator=(const resource_directory_entry& other) -{ - release(); - - id_ = other.id_; - name_ = other.name_; - includes_data_ = other.includes_data_; - named_ = other.named_; - - //If other union'ed pointer is not zero - if(other.ptr_.data_) - { - if(other.includes_data()) - ptr_.data_ = new resource_data_entry(*other.ptr_.data_); - else - ptr_.dir_ = new resource_directory(*other.ptr_.dir_); - } - - return *this; -} - -//Destroys included data -void resource_directory_entry::release() -{ - //If union'ed pointer is not zero - if(ptr_.data_) - { - if(includes_data()) - delete ptr_.data_; - else - delete ptr_.dir_; - - ptr_.data_ = 0; - } -} - -//Destructor -resource_directory_entry::~resource_directory_entry() -{ - release(); -} - -//Returns entry ID -uint32_t resource_directory_entry::get_id() const -{ - return id_; -} - -//Returns entry name -const std::wstring& resource_directory_entry::get_name() const -{ - return name_; -} - -//Returns true, if entry has name -//Returns false, if entry has ID -bool resource_directory_entry::is_named() const -{ - return named_; -} - -//Returns true, if entry includes resource_data_entry -//Returns false, if entry includes resource_directory -bool resource_directory_entry::includes_data() const -{ - return includes_data_; -} - -//Returns resource_directory if entry includes it, otherwise throws an exception -const resource_directory& resource_directory_entry::get_resource_directory() const -{ - if(!ptr_.dir_ || includes_data_) - throw pe_exception("Resource directory entry does not contain resource directory", pe_exception::resource_directory_entry_error); - - return *ptr_.dir_; -} - -//Returns resource_data_entry if entry includes it, otherwise throws an exception -const resource_data_entry& resource_directory_entry::get_data_entry() const -{ - if(!ptr_.data_ || !includes_data_) - throw pe_exception("Resource directory entry does not contain resource data entry", pe_exception::resource_directory_entry_error); - - return *ptr_.data_; -} - -//Returns resource_directory if entry includes it, otherwise throws an exception -resource_directory& resource_directory_entry::get_resource_directory() -{ - if(!ptr_.dir_ || includes_data_) - throw pe_exception("Resource directory entry does not contain resource directory", pe_exception::resource_directory_entry_error); - - return *ptr_.dir_; -} - -//Returns resource_data_entry if entry includes it, otherwise throws an exception -resource_data_entry& resource_directory_entry::get_data_entry() -{ - if(!ptr_.data_ || !includes_data_) - throw pe_exception("Resource directory entry does not contain resource data entry", pe_exception::resource_directory_entry_error); - - return *ptr_.data_; -} - -//Sets entry name -void resource_directory_entry::set_name(const std::wstring& name) -{ - name_ = name; - named_ = true; - id_ = 0; -} - -//Sets entry ID -void resource_directory_entry::set_id(uint32_t id) -{ - id_ = id; - named_ = false; - name_.clear(); -} - -//Adds resource_data_entry -void resource_directory_entry::add_data_entry(const resource_data_entry& entry) -{ - release(); - ptr_.data_ = new resource_data_entry(entry); - includes_data_ = true; -} - -//Adds resource_directory -void resource_directory_entry::add_resource_directory(const resource_directory& dir) -{ - release(); - ptr_.dir_ = new resource_directory(dir); - includes_data_ = false; -} - -//Default constructor -resource_directory::resource_directory() - :characteristics_(0), - timestamp_(0), - major_version_(0), minor_version_(0), - number_of_named_entries_(0), number_of_id_entries_(0) -{} - -//Constructor from data -resource_directory::resource_directory(const image_resource_directory& dir) - :characteristics_(dir.Characteristics), - timestamp_(dir.TimeDateStamp), - major_version_(dir.MajorVersion), minor_version_(dir.MinorVersion), - number_of_named_entries_(0), number_of_id_entries_(0) //Set to zero here, calculate on add -{} - -//Returns characteristics of directory -uint32_t resource_directory::get_characteristics() const -{ - return characteristics_; -} - -//Returns date and time stamp of directory -uint32_t resource_directory::get_timestamp() const -{ - return timestamp_; -} - -//Returns major version of directory -uint16_t resource_directory::get_major_version() const -{ - return major_version_; -} - -//Returns minor version of directory -uint16_t resource_directory::get_minor_version() const -{ - return minor_version_; -} - -//Returns number of named entries -uint32_t resource_directory::get_number_of_named_entries() const -{ - return number_of_named_entries_; -} - -//Returns number of ID entries -uint32_t resource_directory::get_number_of_id_entries() const -{ - return number_of_id_entries_; -} - -//Returns resource_directory_entry array -const resource_directory::entry_list& resource_directory::get_entry_list() const -{ - return entries_; -} - -//Returns resource_directory_entry array -resource_directory::entry_list& resource_directory::get_entry_list() -{ - return entries_; -} - -//Adds resource_directory_entry -void resource_directory::add_resource_directory_entry(const resource_directory_entry& entry) -{ - entries_.push_back(entry); - if(entry.is_named()) - ++number_of_named_entries_; - else - ++number_of_id_entries_; -} - -//Clears resource_directory_entry array -void resource_directory::clear_resource_directory_entry_list() -{ - entries_.clear(); - number_of_named_entries_ = 0; - number_of_id_entries_ = 0; -} - -//Sets characteristics of directory -void resource_directory::set_characteristics(uint32_t characteristics) -{ - characteristics_ = characteristics; -} - -//Sets date and time stamp of directory -void resource_directory::set_timestamp(uint32_t timestamp) -{ - timestamp_ = timestamp; -} - -//Sets number of named entries -void resource_directory::set_number_of_named_entries(uint32_t number) -{ - number_of_named_entries_ = number; -} - -//Sets number of ID entries -void resource_directory::set_number_of_id_entries(uint32_t number) -{ - number_of_id_entries_ = number; -} - -//Sets major version of directory -void resource_directory::set_major_version(uint16_t major_version) -{ - major_version_ = major_version; -} - -//Sets minor version of directory -void resource_directory::get_minor_version(uint16_t minor_version) -{ - minor_version_ = minor_version; -} - -//Processes resource directory -const resource_directory process_resource_directory(const pe_base& pe, uint32_t res_rva, uint32_t offset_to_directory, std::set& processed) -{ - resource_directory ret; - - //Check for resource loops - if(!processed.insert(offset_to_directory).second) - throw pe_exception("Incorrect resource directory", pe_exception::incorrect_resource_directory); - - if(!pe_utils::is_sum_safe(res_rva, offset_to_directory)) - throw pe_exception("Incorrect resource directory", pe_exception::incorrect_resource_directory); - - //Get root IMAGE_RESOURCE_DIRECTORY - image_resource_directory directory = pe.section_data_from_rva(res_rva + offset_to_directory, section_data_virtual, true); - - ret = resource_directory(directory); - - //Check DWORDs for possible overflows - if(!pe_utils::is_sum_safe(directory.NumberOfIdEntries, directory.NumberOfNamedEntries) - || directory.NumberOfIdEntries + directory.NumberOfNamedEntries >= pe_utils::max_dword / sizeof(image_resource_directory_entry) + sizeof(image_resource_directory)) - throw pe_exception("Incorrect resource directory", pe_exception::incorrect_resource_directory); - - if(!pe_utils::is_sum_safe(offset_to_directory, sizeof(image_resource_directory) + (directory.NumberOfIdEntries + directory.NumberOfNamedEntries) * sizeof(image_resource_directory_entry)) - || !pe_utils::is_sum_safe(res_rva, offset_to_directory + sizeof(image_resource_directory) + (directory.NumberOfIdEntries + directory.NumberOfNamedEntries) * sizeof(image_resource_directory_entry))) - throw pe_exception("Incorrect resource directory", pe_exception::incorrect_resource_directory); - - for(unsigned long i = 0; i != static_cast(directory.NumberOfIdEntries) + directory.NumberOfNamedEntries; ++i) - { - //Read directory entries one by one - image_resource_directory_entry dir_entry = pe.section_data_from_rva( - res_rva + sizeof(image_resource_directory) + i * sizeof(image_resource_directory_entry) + offset_to_directory, section_data_virtual, true); - - //Create directory entry structure - resource_directory_entry entry; - - //If directory is named - if(dir_entry.NameIsString) - { - if(!pe_utils::is_sum_safe(res_rva + sizeof(uint16_t) /* safe */, dir_entry.NameOffset)) - throw pe_exception("Incorrect resource directory", pe_exception::incorrect_resource_directory); - - //get directory name length - uint16_t directory_name_length = pe.section_data_from_rva(res_rva + dir_entry.NameOffset, section_data_virtual, true); - - //Check name length - if(pe.section_data_length_from_rva(res_rva + dir_entry.NameOffset + sizeof(uint16_t), res_rva + dir_entry.NameOffset + sizeof(uint16_t), section_data_virtual, true) - < directory_name_length) - throw pe_exception("Incorrect resource directory", pe_exception::incorrect_resource_directory); - -#ifdef PE_BLISS_WINDOWS - //Set entry UNICODE name - entry.set_name(std::wstring( - reinterpret_cast(pe.section_data_from_rva(res_rva + dir_entry.NameOffset + sizeof(uint16_t), section_data_virtual, true)), - directory_name_length)); -#else - //Set entry UNICODE name - entry.set_name(pe_utils::from_ucs2(u16string( - reinterpret_cast(pe.section_data_from_rva(res_rva + dir_entry.NameOffset + sizeof(uint16_t), section_data_virtual, true)), - directory_name_length))); -#endif - } - else - { - //Else - set directory ID - entry.set_id(dir_entry.Id); - } - - //If directory entry has another resource directory - if(dir_entry.DataIsDirectory) - { - entry.add_resource_directory(process_resource_directory(pe, res_rva, dir_entry.OffsetToDirectory, processed)); - } - else - { - //If directory entry has data - image_resource_data_entry data_entry = pe.section_data_from_rva( - res_rva + dir_entry.OffsetToData, section_data_virtual, true); - - //Check byte count that stated by data entry - if(pe.section_data_length_from_rva(data_entry.OffsetToData, data_entry.OffsetToData, section_data_virtual, true) < data_entry.Size) - throw pe_exception("Incorrect resource directory", pe_exception::incorrect_resource_directory); - - //Add data entry to directory entry - entry.add_data_entry(resource_data_entry( - std::string(pe.section_data_from_rva(data_entry.OffsetToData, section_data_virtual, true), data_entry.Size), - data_entry.CodePage)); - } - - //Save directory entry - ret.add_resource_directory_entry(entry); - } - - //Return resource directory - return ret; -} - -//Helper function to calculate needed space for resource data -void calculate_resource_data_space(const resource_directory& root, uint32_t aligned_offset_from_section_start, uint32_t& needed_size_for_structures, uint32_t& needed_size_for_strings) -{ - needed_size_for_structures += sizeof(image_resource_directory); - for(resource_directory::entry_list::const_iterator it = root.get_entry_list().begin(); it != root.get_entry_list().end(); ++it) - { - needed_size_for_structures += sizeof(image_resource_directory_entry); - - if((*it).is_named()) - needed_size_for_strings += static_cast(((*it).get_name().length() + 1) * 2 /* unicode */ + sizeof(uint16_t) /* for string length */); - - if(!(*it).includes_data()) - calculate_resource_data_space((*it).get_resource_directory(), aligned_offset_from_section_start, needed_size_for_structures, needed_size_for_strings); - } -} - -//Helper function to calculate needed space for resource data -void calculate_resource_data_space(const resource_directory& root, uint32_t needed_size_for_structures, uint32_t needed_size_for_strings, uint32_t& needed_size_for_data, uint32_t& current_data_pos) -{ - for(resource_directory::entry_list::const_iterator it = root.get_entry_list().begin(); it != root.get_entry_list().end(); ++it) - { - if((*it).includes_data()) - { - uint32_t data_size = static_cast((*it).get_data_entry().get_data().length() - + sizeof(image_resource_data_entry) - + (pe_utils::align_up(current_data_pos, sizeof(uint32_t)) - current_data_pos) /* alignment */); - needed_size_for_data += data_size; - current_data_pos += data_size; - } - else - { - calculate_resource_data_space((*it).get_resource_directory(), needed_size_for_structures, needed_size_for_strings, needed_size_for_data, current_data_pos); - } - } -} - -//Helper: sorts resource directory entries -struct entry_sorter -{ -public: - bool operator()(const resource_directory_entry& entry1, const resource_directory_entry& entry2) const; -}; - -//Helper function to rebuild resource directory -void rebuild_resource_directory(pe_base& pe, section& resource_section, resource_directory& root, uint32_t& current_structures_pos, uint32_t& current_data_pos, uint32_t& current_strings_pos, uint32_t offset_from_section_start) -{ - //Create resource directory - image_resource_directory dir = {0}; - dir.Characteristics = root.get_characteristics(); - dir.MajorVersion = root.get_major_version(); - dir.MinorVersion = root.get_minor_version(); - dir.TimeDateStamp = root.get_timestamp(); - - { - resource_directory::entry_list& entries = root.get_entry_list(); - std::sort(entries.begin(), entries.end(), entry_sorter()); - } - - //Calculate number of named and ID entries - for(resource_directory::entry_list::const_iterator it = root.get_entry_list().begin(); it != root.get_entry_list().end(); ++it) - { - if((*it).is_named()) - ++dir.NumberOfNamedEntries; - else - ++dir.NumberOfIdEntries; - } - - std::string& raw_data = resource_section.get_raw_data(); - - //Save resource directory - memcpy(&raw_data[current_structures_pos], &dir, sizeof(dir)); - current_structures_pos += sizeof(dir); - - uint32_t this_current_structures_pos = current_structures_pos; - - current_structures_pos += sizeof(image_resource_directory_entry) * (dir.NumberOfNamedEntries + dir.NumberOfIdEntries); - - //Create all resource directory entries - for(resource_directory::entry_list::iterator it = root.get_entry_list().begin(); it != root.get_entry_list().end(); ++it) - { - image_resource_directory_entry entry; - if((*it).is_named()) - { - entry.Name = 0x80000000 | (current_strings_pos - offset_from_section_start); - uint16_t unicode_length = static_cast((*it).get_name().length()); - memcpy(&raw_data[current_strings_pos], &unicode_length, sizeof(unicode_length)); - current_strings_pos += sizeof(unicode_length); - -#ifdef PE_BLISS_WINDOWS - memcpy(&raw_data[current_strings_pos], (*it).get_name().c_str(), (*it).get_name().length() * sizeof(uint16_t) + sizeof(uint16_t) /* unicode */); -#else - { - u16string str(pe_utils::to_ucs2((*it).get_name())); - memcpy(&raw_data[current_strings_pos], str.c_str(), (*it).get_name().length() * sizeof(uint16_t) + sizeof(uint16_t) /* unicode */); - } -#endif - - current_strings_pos += static_cast((*it).get_name().length() * sizeof(uint16_t) + sizeof(uint16_t) /* unicode */); - } - else - { - entry.Name = (*it).get_id(); - } - - if((*it).includes_data()) - { - current_data_pos = pe_utils::align_up(current_data_pos, sizeof(uint32_t)); - image_resource_data_entry data_entry = {0}; - data_entry.CodePage = (*it).get_data_entry().get_codepage(); - data_entry.Size = static_cast((*it).get_data_entry().get_data().length()); - data_entry.OffsetToData = pe.rva_from_section_offset(resource_section, current_data_pos + sizeof(data_entry)); - - entry.OffsetToData = current_data_pos - offset_from_section_start; - - memcpy(&raw_data[current_data_pos], &data_entry, sizeof(data_entry)); - current_data_pos += sizeof(data_entry); - - memcpy(&raw_data[current_data_pos], (*it).get_data_entry().get_data().data(), data_entry.Size); - current_data_pos += data_entry.Size; - - memcpy(&raw_data[this_current_structures_pos], &entry, sizeof(entry)); - this_current_structures_pos += sizeof(entry); - } - else - { - entry.OffsetToData = 0x80000000 | (current_structures_pos - offset_from_section_start); - - memcpy(&raw_data[this_current_structures_pos], &entry, sizeof(entry)); - this_current_structures_pos += sizeof(entry); - - rebuild_resource_directory(pe, resource_section, (*it).get_resource_directory(), current_structures_pos, current_data_pos, current_strings_pos, offset_from_section_start); - } - } -} - -//Helper function to rebuild resource directory -bool entry_sorter::operator()(const resource_directory_entry& entry1, const resource_directory_entry& entry2) const -{ - if(entry1.is_named() && entry2.is_named()) - return entry1.get_name() < entry2.get_name(); - else if(!entry1.is_named() && !entry2.is_named()) - return entry1.get_id() < entry2.get_id(); - else - return entry1.is_named(); -} - -//Resources rebuilder -//resource_directory - root resource directory -//resources_section - section where resource directory will be placed (must be attached to PE image) -//offset_from_section_start - offset from resources_section raw data start -//resource_directory is non-constant, because it will be sorted -//save_to_pe_headers - if true, new resource directory information will be saved to PE image headers -//auto_strip_last_section - if true and resources are placed in the last section, it will be automatically stripped -//number_of_id_entries and number_of_named_entries for resource directories are recalculated and not used -const image_directory rebuild_resources(pe_base& pe, resource_directory& info, section& resources_section, uint32_t offset_from_section_start, bool save_to_pe_header, bool auto_strip_last_section) -{ - //Check that resources_section is attached to this PE image - if(!pe.section_attached(resources_section)) - throw pe_exception("Resource section must be attached to PE file", pe_exception::section_is_not_attached); - - //Check resource directory correctness - if(info.get_entry_list().empty()) - throw pe_exception("Empty resource directory", pe_exception::incorrect_resource_directory); - - uint32_t aligned_offset_from_section_start = pe_utils::align_up(offset_from_section_start, sizeof(uint32_t)); - uint32_t needed_size_for_structures = aligned_offset_from_section_start - offset_from_section_start; //Calculate needed size for resource tables and data - uint32_t needed_size_for_strings = 0; - uint32_t needed_size_for_data = 0; - - calculate_resource_data_space(info, aligned_offset_from_section_start, needed_size_for_structures, needed_size_for_strings); - - { - uint32_t current_data_pos = aligned_offset_from_section_start + needed_size_for_structures + needed_size_for_strings; - calculate_resource_data_space(info, needed_size_for_structures, needed_size_for_strings, needed_size_for_data, current_data_pos); - } - - uint32_t needed_size = needed_size_for_structures + needed_size_for_strings + needed_size_for_data; - - //Check if resources_section is last one. If it's not, check if there's enough place for resource data - if(&resources_section != &*(pe.get_image_sections().end() - 1) && - (resources_section.empty() || pe_utils::align_up(resources_section.get_size_of_raw_data(), pe.get_file_alignment()) - < needed_size + aligned_offset_from_section_start)) - throw pe_exception("Insufficient space for resource directory", pe_exception::insufficient_space); - - std::string& raw_data = resources_section.get_raw_data(); - - //This will be done only if resources_section is the last section of image or for section with unaligned raw length of data - if(raw_data.length() < needed_size + aligned_offset_from_section_start) - raw_data.resize(needed_size + aligned_offset_from_section_start); //Expand section raw data - - uint32_t current_structures_pos = aligned_offset_from_section_start; - uint32_t current_strings_pos = current_structures_pos + needed_size_for_structures; - uint32_t current_data_pos = current_strings_pos + needed_size_for_strings; - rebuild_resource_directory(pe, resources_section, info, current_structures_pos, current_data_pos, current_strings_pos, aligned_offset_from_section_start); - - //Adjust section raw and virtual sizes - pe.recalculate_section_sizes(resources_section, auto_strip_last_section); - - image_directory ret(pe.rva_from_section_offset(resources_section, aligned_offset_from_section_start), needed_size); - - //If auto-rewrite of PE headers is required - if(save_to_pe_header) - { - pe.set_directory_rva(image_directory_entry_resource, ret.get_rva()); - pe.set_directory_size(image_directory_entry_resource, ret.get_size()); - } - - return ret; -} - -//Returns resources from PE file -const resource_directory get_resources(const pe_base& pe) -{ - resource_directory ret; - - if(!pe.has_resources()) - return ret; - - //Get resource directory RVA - uint32_t res_rva = pe.get_directory_rva(image_directory_entry_resource); - - //Store already processed directories to avoid resource loops - std::set processed; - - //Process all directories (recursion) - ret = process_resource_directory(pe, res_rva, 0, processed); - - return ret; -} - -//Finds resource_directory_entry by ID -resource_directory::id_entry_finder::id_entry_finder(uint32_t id) - :id_(id) -{} - -bool resource_directory::id_entry_finder::operator()(const resource_directory_entry& entry) const -{ - return !entry.is_named() && entry.get_id() == id_; -} - -//Finds resource_directory_entry by name -resource_directory::name_entry_finder::name_entry_finder(const std::wstring& name) - :name_(name) -{} - -bool resource_directory::name_entry_finder::operator()(const resource_directory_entry& entry) const -{ - return entry.is_named() && entry.get_name() == name_; -} - -//Finds resource_directory_entry by name or ID (universal) -resource_directory::entry_finder::entry_finder(const std::wstring& name) - :name_(name), named_(true) -{} - -resource_directory::entry_finder::entry_finder(uint32_t id) - :id_(id), named_(false) -{} - -bool resource_directory::entry_finder::operator()(const resource_directory_entry& entry) const -{ - if(named_) - return entry.is_named() && entry.get_name() == name_; - else - return !entry.is_named() && entry.get_id() == id_; -} - -//Returns resource_directory_entry by ID. If not found - throws an exception -const resource_directory_entry& resource_directory::entry_by_id(uint32_t id) const -{ - entry_list::const_iterator i = std::find_if(entries_.begin(), entries_.end(), id_entry_finder(id)); - if(i == entries_.end()) - throw pe_exception("Resource directory entry not found", pe_exception::resource_directory_entry_not_found); - - return *i; -} - -//Returns resource_directory_entry by name. If not found - throws an exception -const resource_directory_entry& resource_directory::entry_by_name(const std::wstring& name) const -{ - entry_list::const_iterator i = std::find_if(entries_.begin(), entries_.end(), name_entry_finder(name)); - if(i == entries_.end()) - throw pe_exception("Resource directory entry not found", pe_exception::resource_directory_entry_not_found); - - return *i; -} -} diff --git a/drivers/pe_bliss/pe_resources.h b/drivers/pe_bliss/pe_resources.h deleted file mode 100644 index 0f7f32768d..0000000000 --- a/drivers/pe_bliss/pe_resources.h +++ /dev/null @@ -1,224 +0,0 @@ -#pragma once -#include -#include -#include -#include "pe_structures.h" -#include "pe_base.h" -#include "pe_directory.h" - -namespace pe_bliss -{ -//Class representing resource data entry -class resource_data_entry -{ -public: - //Default constructor - resource_data_entry(); - //Constructor from data - resource_data_entry(const std::string& data, uint32_t codepage); - - //Returns resource data codepage - uint32_t get_codepage() const; - //Returns resource data - const std::string& get_data() const; - -public: //These functions do not change everything inside image, they are used by PE class - //You can also use them to rebuild resource directory - - //Sets resource data codepage - void set_codepage(uint32_t codepage); - //Sets resource data - void set_data(const std::string& data); - -private: - uint32_t codepage_; //Resource data codepage - std::string data_; //Resource data -}; - -//Forward declaration -class resource_directory; - -//Class representing resource directory entry -class resource_directory_entry -{ -public: - //Default constructor - resource_directory_entry(); - //Copy constructor - resource_directory_entry(const resource_directory_entry& other); - //Copy assignment operator - resource_directory_entry& operator=(const resource_directory_entry& other); - - //Returns entry ID - uint32_t get_id() const; - //Returns entry name - const std::wstring& get_name() const; - //Returns true, if entry has name - //Returns false, if entry has ID - bool is_named() const; - - //Returns true, if entry includes resource_data_entry - //Returns false, if entry includes resource_directory - bool includes_data() const; - //Returns resource_directory if entry includes it, otherwise throws an exception - const resource_directory& get_resource_directory() const; - //Returns resource_data_entry if entry includes it, otherwise throws an exception - const resource_data_entry& get_data_entry() const; - - //Destructor - ~resource_directory_entry(); - -public: //These functions do not change everything inside image, they are used by PE class - //You can also use them to rebuild resource directory - - //Sets entry name - void set_name(const std::wstring& name); - //Sets entry ID - void set_id(uint32_t id); - - //Returns resource_directory if entry includes it, otherwise throws an exception - resource_directory& get_resource_directory(); - //Returns resource_data_entry if entry includes it, otherwise throws an exception - resource_data_entry& get_data_entry(); - - //Adds resource_data_entry - void add_data_entry(const resource_data_entry& entry); - //Adds resource_directory - void add_resource_directory(const resource_directory& dir); - -private: - //Destroys included data - void release(); - -private: - uint32_t id_; - std::wstring name_; - - union includes - { - //Default constructor - includes(); - - //We use pointers, we're doing manual copying here - class resource_data_entry* data_; - class resource_directory* dir_; //We use pointer, because structs include each other - }; - - includes ptr_; - - bool includes_data_, named_; -}; - -//Class representing resource directory -class resource_directory -{ -public: - typedef std::vector entry_list; - -public: - //Default constructor - resource_directory(); - //Constructor from data - explicit resource_directory(const pe_win::image_resource_directory& dir); - - //Returns characteristics of directory - uint32_t get_characteristics() const; - //Returns date and time stamp of directory - uint32_t get_timestamp() const; - //Returns number of named entries - uint32_t get_number_of_named_entries() const; - //Returns number of ID entries - uint32_t get_number_of_id_entries() const; - //Returns major version of directory - uint16_t get_major_version() const; - //Returns minor version of directory - uint16_t get_minor_version() const; - //Returns resource_directory_entry array - const entry_list& get_entry_list() const; - //Returns resource_directory_entry by ID. If not found - throws an exception - const resource_directory_entry& entry_by_id(uint32_t id) const; - //Returns resource_directory_entry by name. If not found - throws an exception - const resource_directory_entry& entry_by_name(const std::wstring& name) const; - -public: //These functions do not change everything inside image, they are used by PE class - //You can also use them to rebuild resource directory - - //Adds resource_directory_entry - void add_resource_directory_entry(const resource_directory_entry& entry); - //Clears resource_directory_entry array - void clear_resource_directory_entry_list(); - - //Sets characteristics of directory - void set_characteristics(uint32_t characteristics); - //Sets date and time stamp of directory - void set_timestamp(uint32_t timestamp); - //Sets number of named entries - void set_number_of_named_entries(uint32_t number); - //Sets number of ID entries - void set_number_of_id_entries(uint32_t number); - //Sets major version of directory - void set_major_version(uint16_t major_version); - //Sets minor version of directory - void get_minor_version(uint16_t minor_version); - - //Returns resource_directory_entry array - entry_list& get_entry_list(); - -private: - uint32_t characteristics_; - uint32_t timestamp_; - uint16_t major_version_, minor_version_; - uint32_t number_of_named_entries_, number_of_id_entries_; - entry_list entries_; - -public: //Finder helpers - //Finds resource_directory_entry by ID - struct id_entry_finder - { - public: - explicit id_entry_finder(uint32_t id); - bool operator()(const resource_directory_entry& entry) const; - - private: - uint32_t id_; - }; - - //Finds resource_directory_entry by name - struct name_entry_finder - { - public: - explicit name_entry_finder(const std::wstring& name); - bool operator()(const resource_directory_entry& entry) const; - - private: - std::wstring name_; - }; - - //Finds resource_directory_entry by name or ID (universal) - struct entry_finder - { - public: - explicit entry_finder(const std::wstring& name); - explicit entry_finder(uint32_t id); - bool operator()(const resource_directory_entry& entry) const; - - private: - std::wstring name_; - uint32_t id_; - bool named_; - }; -}; - -//Returns resources (root resource_directory) from PE file -const resource_directory get_resources(const pe_base& pe); - -//Resources rebuilder -//resource_directory - root resource directory -//resources_section - section where resource directory will be placed (must be attached to PE image) -//resource_directory is non-constant, because it will be sorted -//offset_from_section_start - offset from resources_section raw data start -//save_to_pe_headers - if true, new resource directory information will be saved to PE image headers -//auto_strip_last_section - if true and resources are placed in the last section, it will be automatically stripped -//number_of_id_entries and number_of_named_entries for resource directories are recalculated and not used -const image_directory rebuild_resources(pe_base& pe, resource_directory& info, section& resources_section, uint32_t offset_from_section_start = 0, bool save_to_pe_header = true, bool auto_strip_last_section = true); -} diff --git a/drivers/pe_bliss/pe_rich_data.cpp b/drivers/pe_bliss/pe_rich_data.cpp deleted file mode 100644 index 0497fa6469..0000000000 --- a/drivers/pe_bliss/pe_rich_data.cpp +++ /dev/null @@ -1,131 +0,0 @@ -#include "pe_rich_data.h" - -namespace pe_bliss -{ -//STUB OVERLAY -//Default constructor -rich_data::rich_data() - :number_(0), version_(0), times_(0) -{} - -//Who knows, what these fields mean... -uint32_t rich_data::get_number() const -{ - return number_; -} - -uint32_t rich_data::get_version() const -{ - return version_; -} - -uint32_t rich_data::get_times() const -{ - return times_; -} - -void rich_data::set_number(uint32_t number) -{ - number_ = number; -} - -void rich_data::set_version(uint32_t version) -{ - version_ = version; -} - -void rich_data::set_times(uint32_t times) -{ - times_ = times; -} - -//Returns MSVC rich data -const rich_data_list get_rich_data(const pe_base& pe) -{ - //Returned value - rich_data_list ret; - - const std::string& rich_overlay = pe.get_stub_overlay(); - - //If there's no rich overlay, return empty vector - if(rich_overlay.size() < sizeof(uint32_t)) - return ret; - - //True if rich data was found - bool found = false; - - //Rich overlay ID ("Rich" word) - static const uint32_t rich_overlay_id = 0x68636952; - - //Search for rich data overlay ID - const char* begin = &rich_overlay[0]; - const char* end = begin + rich_overlay.length(); - for(; begin != end; ++begin) - { - if(*reinterpret_cast(begin) == rich_overlay_id) - { - found = true; //We've found it! - break; - } - } - - //If we found it - if(found) - { - //Check remaining length - if(static_cast(end - begin) < sizeof(uint32_t)) - return ret; - - //The XOR key is after "Rich" word, we should get it - uint32_t xorkey = *reinterpret_cast(begin + sizeof(uint32_t)); - - //True if rich data was found - found = false; - - //Second search for signature "DanS" - begin = &rich_overlay[0]; - for(; begin != end; ++begin) - { - if((*reinterpret_cast(begin) ^ xorkey) == 0x536e6144) //"DanS" - { - found = true; - break; - } - } - - //If second signature is found - if(found) - { - begin += sizeof(uint32_t) * 3; - //List all rich data structures - while(begin < end) - { - begin += sizeof(uint32_t); - if(begin >= end) - break; - - //Check for rich overlay data end ("Rich" word reached) - if(*reinterpret_cast(begin) == rich_overlay_id) - break; - - //Create rich_data structure - rich_data data; - data.set_number((*reinterpret_cast(begin) ^ xorkey) >> 16); - data.set_version((*reinterpret_cast(begin) ^ xorkey) & 0xFFFF); - - begin += sizeof(uint32_t); - if(begin >= end) - break; - - data.set_times(*reinterpret_cast(begin) ^ xorkey); - - //Save rich data structure - ret.push_back(data); - } - } - } - - //Return rich data structures list - return ret; -} -} diff --git a/drivers/pe_bliss/pe_rich_data.h b/drivers/pe_bliss/pe_rich_data.h deleted file mode 100644 index 3d7622c680..0000000000 --- a/drivers/pe_bliss/pe_rich_data.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once -#include -#include "pe_structures.h" -#include "pe_base.h" - -namespace pe_bliss -{ -//Rich data overlay class of Microsoft Visual Studio -class rich_data -{ -public: - //Default constructor - rich_data(); - -public: //Getters - //Who knows, what these fields mean... - uint32_t get_number() const; - uint32_t get_version() const; - uint32_t get_times() const; - -public: //Setters, used by PE library only - void set_number(uint32_t number); - void set_version(uint32_t version); - void set_times(uint32_t times); - -private: - uint32_t number_; - uint32_t version_; - uint32_t times_; -}; - -//Rich data list typedef -typedef std::vector rich_data_list; - -//Returns a vector with rich data (stub overlay) -const rich_data_list get_rich_data(const pe_base& pe); -} diff --git a/drivers/pe_bliss/pe_section.cpp b/drivers/pe_bliss/pe_section.cpp deleted file mode 100644 index e7def185cb..0000000000 --- a/drivers/pe_bliss/pe_section.cpp +++ /dev/null @@ -1,281 +0,0 @@ -#include -#include "utils.h" -#include "pe_section.h" - -namespace pe_bliss -{ -using namespace pe_win; - -//Section structure default constructor -section::section() - :old_size_(static_cast(-1)) -{ - memset(&header_, 0, sizeof(image_section_header)); -} - -//Sets the name of section (8 characters maximum) -void section::set_name(const std::string& name) -{ - memset(header_.Name, 0, sizeof(header_.Name)); - memcpy(header_.Name, name.c_str(), std::min(name.length(), sizeof(header_.Name))); -} - -//Returns section name -const std::string section::get_name() const -{ - char buf[9] = {0}; - memcpy(buf, header_.Name, 8); - return std::string(buf); -} - -//Set flag (attribute) of section -section& section::set_flag(uint32_t flag, bool setflag) -{ - if(setflag) - header_.Characteristics |= flag; - else - header_.Characteristics &= ~flag; - - return *this; -} - -//Sets "readable" attribute of section -section& section::readable(bool readable) -{ - return set_flag(image_scn_mem_read, readable); -} - -//Sets "writeable" attribute of section -section& section::writeable(bool writeable) -{ - return set_flag(image_scn_mem_write, writeable); -} - -//Sets "executable" attribute of section -section& section::executable(bool executable) -{ - return set_flag(image_scn_mem_execute, executable); -} - -//Sets "shared" attribute of section -section& section::shared(bool shared) -{ - return set_flag(image_scn_mem_shared, shared); -} - -//Sets "discardable" attribute of section -section& section::discardable(bool discardable) -{ - return set_flag(image_scn_mem_discardable, discardable); -} - -//Returns true if section is readable -bool section::readable() const -{ - return (header_.Characteristics & image_scn_mem_read) != 0; -} - -//Returns true if section is writeable -bool section::writeable() const -{ - return (header_.Characteristics & image_scn_mem_write) != 0; -} - -//Returns true if section is executable -bool section::executable() const -{ - return (header_.Characteristics & image_scn_mem_execute) != 0; -} - -bool section::shared() const -{ - return (header_.Characteristics & image_scn_mem_shared) != 0; -} - -bool section::discardable() const -{ - return (header_.Characteristics & image_scn_mem_discardable) != 0; -} - -//Returns true if section has no RAW data -bool section::empty() const -{ - if(old_size_ != static_cast(-1)) //If virtual memory is mapped, check raw data length (old_size_) - return old_size_ == 0; - else - return raw_data_.empty(); -} - -//Returns raw section data from file image -std::string& section::get_raw_data() -{ - unmap_virtual(); - return raw_data_; -} - -//Sets raw section data from file image -void section::set_raw_data(const std::string& data) -{ - old_size_ = static_cast(-1); - raw_data_ = data; -} - -//Returns raw section data from file image -const std::string& section::get_raw_data() const -{ - unmap_virtual(); - return raw_data_; -} - -//Returns mapped virtual section data -const std::string& section::get_virtual_data(uint32_t section_alignment) const -{ - map_virtual(section_alignment); - return raw_data_; -} - -//Returns mapped virtual section data -std::string& section::get_virtual_data(uint32_t section_alignment) -{ - map_virtual(section_alignment); - return raw_data_; -} - -//Maps virtual section data -void section::map_virtual(uint32_t section_alignment) const -{ - uint32_t aligned_virtual_size = get_aligned_virtual_size(section_alignment); - if(old_size_ == static_cast(-1) && aligned_virtual_size && aligned_virtual_size > raw_data_.length()) - { - old_size_ = raw_data_.length(); - raw_data_.resize(aligned_virtual_size, 0); - } -} - -//Unmaps virtual section data -void section::unmap_virtual() const -{ - if(old_size_ != static_cast(-1)) - { - raw_data_.resize(old_size_, 0); - old_size_ = static_cast(-1); - } -} - -//Returns section virtual size -uint32_t section::get_virtual_size() const -{ - return header_.Misc.VirtualSize; -} - -//Returns section virtual address -uint32_t section::get_virtual_address() const -{ - return header_.VirtualAddress; -} - -//Returns size of section raw data -uint32_t section::get_size_of_raw_data() const -{ - return header_.SizeOfRawData; -} - -//Returns pointer to raw section data in PE file -uint32_t section::get_pointer_to_raw_data() const -{ - return header_.PointerToRawData; -} - -//Returns section characteristics -uint32_t section::get_characteristics() const -{ - return header_.Characteristics; -} - -//Returns raw image section header -const pe_win::image_section_header& section::get_raw_header() const -{ - return header_; -} - -//Returns raw image section header -pe_win::image_section_header& section::get_raw_header() -{ - return header_; -} - -//Calculates aligned virtual section size -uint32_t section::get_aligned_virtual_size(uint32_t section_alignment) const -{ - if(get_size_of_raw_data()) - { - if(!get_virtual_size()) - { - //If section virtual size is zero - //Set aligned virtual size of section as aligned raw size - return pe_utils::align_up(get_size_of_raw_data(), section_alignment); - } - } - - return pe_utils::align_up(get_virtual_size(), section_alignment); -} - -//Calculates aligned raw section size -uint32_t section::get_aligned_raw_size(uint32_t file_alignment) const -{ - if(get_size_of_raw_data()) - return pe_utils::align_up(get_size_of_raw_data(), file_alignment); - else - return 0; -} - -//Sets size of raw section data -void section::set_size_of_raw_data(uint32_t size_of_raw_data) -{ - header_.SizeOfRawData = size_of_raw_data; -} - -//Sets pointer to section raw data -void section::set_pointer_to_raw_data(uint32_t pointer_to_raw_data) -{ - header_.PointerToRawData = pointer_to_raw_data; -} - -//Sets section characteristics -void section::set_characteristics(uint32_t characteristics) -{ - header_.Characteristics = characteristics; -} - -//Sets section virtual size -void section::set_virtual_size(uint32_t virtual_size) -{ - header_.Misc.VirtualSize = virtual_size; -} - -//Sets section virtual address -void section::set_virtual_address(uint32_t virtual_address) -{ - header_.VirtualAddress = virtual_address; -} - -//Section by file offset finder helper (4gb max) -section_by_raw_offset::section_by_raw_offset(uint32_t offset) - :offset_(offset) -{} - -bool section_by_raw_offset::operator()(const section& s) const -{ - return (s.get_pointer_to_raw_data() <= offset_) - && (s.get_pointer_to_raw_data() + s.get_size_of_raw_data() > offset_); -} - -section_ptr_finder::section_ptr_finder(const section& s) - :s_(s) -{} - -bool section_ptr_finder::operator()(const section& s) const -{ - return &s == &s_; -} -} diff --git a/drivers/pe_bliss/pe_section.h b/drivers/pe_bliss/pe_section.h deleted file mode 100644 index 8d8e2371ee..0000000000 --- a/drivers/pe_bliss/pe_section.h +++ /dev/null @@ -1,137 +0,0 @@ -#pragma once -#include -#include -#include "pe_structures.h" - -namespace pe_bliss -{ -//Enumeration of section data types, used in functions below -enum section_data_type -{ - section_data_raw, - section_data_virtual -}; - -//Class representing image section -class section -{ -public: - //Default constructor - section(); - - //Sets the name of section (stripped to 8 characters) - void set_name(const std::string& name); - - //Returns the name of section - const std::string get_name() const; - - //Changes attributes of section - section& readable(bool readable); - section& writeable(bool writeable); - section& executable(bool executable); - section& shared(bool shared); - section& discardable(bool discardable); - - //Returns attributes of section - bool readable() const; - bool writeable() const; - bool executable() const; - bool shared() const; - bool discardable() const; - - //Returns true if section has no RAW data - bool empty() const; - - //Returns raw section data from file image - std::string& get_raw_data(); - //Returns raw section data from file image - const std::string& get_raw_data() const; - //Returns mapped virtual section data - const std::string& get_virtual_data(uint32_t section_alignment) const; - //Returns mapped virtual section data - std::string& get_virtual_data(uint32_t section_alignment); - -public: //Header getters - //Returns section virtual size - uint32_t get_virtual_size() const; - //Returns section virtual address (RVA) - uint32_t get_virtual_address() const; - //Returns size of section raw data - uint32_t get_size_of_raw_data() const; - //Returns pointer to raw section data in PE file - uint32_t get_pointer_to_raw_data() const; - //Returns section characteristics - uint32_t get_characteristics() const; - - //Returns raw image section header - const pe_win::image_section_header& get_raw_header() const; - -public: //Aligned sizes calculation - //Calculates aligned virtual section size - uint32_t get_aligned_virtual_size(uint32_t section_alignment) const; - //Calculates aligned raw section size - uint32_t get_aligned_raw_size(uint32_t file_alignment) const; - -public: //Setters - //Sets size of raw section data - void set_size_of_raw_data(uint32_t size_of_raw_data); - //Sets pointer to section raw data - void set_pointer_to_raw_data(uint32_t pointer_to_raw_data); - //Sets section characteristics - void set_characteristics(uint32_t characteristics); - //Sets raw section data from file image - void set_raw_data(const std::string& data); - -public: //Setters, be careful - //Sets section virtual size (doesn't set internal aligned virtual size, changes only header value) - //Better use pe_base::set_section_virtual_size - void set_virtual_size(uint32_t virtual_size); - //Sets section virtual address - void set_virtual_address(uint32_t virtual_address); - //Returns raw image section header - pe_win::image_section_header& get_raw_header(); - -private: - //Section header - pe_win::image_section_header header_; - - //Maps virtual section data - void map_virtual(uint32_t section_alignment) const; - - //Unmaps virtual section data - void unmap_virtual() const; - - //Set flag (attribute) of section - section& set_flag(uint32_t flag, bool setflag); - - //Old size of section (stored after mapping of virtual section memory) - mutable std::size_t old_size_; - - //Section raw/virtual data - mutable std::string raw_data_; -}; - -//Section by file offset finder helper (4gb max) -struct section_by_raw_offset -{ -public: - explicit section_by_raw_offset(uint32_t offset); - bool operator()(const section& s) const; - -private: - uint32_t offset_; -}; - -//Helper: finder of section* in sections list -struct section_ptr_finder -{ -public: - explicit section_ptr_finder(const section& s); - bool operator()(const section& s) const; - -private: - const section& s_; -}; - -typedef std::vector
section_list; -} diff --git a/drivers/pe_bliss/pe_structures.h b/drivers/pe_bliss/pe_structures.h deleted file mode 100644 index 9008536ab1..0000000000 --- a/drivers/pe_bliss/pe_structures.h +++ /dev/null @@ -1,1007 +0,0 @@ -#pragma once -#include -#include -#include "stdint_defs.h" -#if defined(_MSC_VER) or defined(__MINGW32__) -#define PE_BLISS_WINDOWS -#endif - -namespace pe_bliss -{ -//Enumeration of PE types -enum pe_type -{ - pe_type_32, - pe_type_64 -}; - -namespace pe_win -{ -const uint32_t image_numberof_directory_entries = 16; -const uint32_t image_nt_optional_hdr32_magic = 0x10b; -const uint32_t image_nt_optional_hdr64_magic = 0x20b; -const uint32_t image_resource_name_is_string = 0x80000000; -const uint32_t image_resource_data_is_directory = 0x80000000; - -const uint32_t image_dllcharacteristics_dynamic_base = 0x0040; // DLL can move. -const uint32_t image_dllcharacteristics_force_integrity = 0x0080; // Code Integrity Image -const uint32_t image_dllcharacteristics_nx_compat = 0x0100; // Image is NX compatible -const uint32_t image_dllcharacteristics_no_isolation = 0x0200; // Image understands isolation and doesn't want it -const uint32_t image_dllcharacteristics_no_seh = 0x0400; // Image does not use SEH. No SE handler may reside in this image -const uint32_t image_dllcharacteristics_no_bind = 0x0800; // Do not bind this image. -const uint32_t image_dllcharacteristics_wdm_driver = 0x2000; // Driver uses WDM model -const uint32_t image_dllcharacteristics_terminal_server_aware = 0x8000; - -const uint32_t image_sizeof_file_header = 20; - -const uint32_t image_file_relocs_stripped = 0x0001; // Relocation info stripped from file. -const uint32_t image_file_executable_image = 0x0002; // File is executable (i.e. no unresolved externel references). -const uint32_t image_file_line_nums_stripped = 0x0004; // Line nunbers stripped from file. -const uint32_t image_file_local_syms_stripped = 0x0008; // Local symbols stripped from file. -const uint32_t image_file_aggresive_ws_trim = 0x0010; // Agressively trim working set -const uint32_t image_file_large_address_aware = 0x0020; // App can handle >2gb addresses -const uint32_t image_file_bytes_reversed_lo = 0x0080; // Bytes of machine word are reversed. -const uint32_t image_file_32bit_machine = 0x0100; // 32 bit word machine. -const uint32_t image_file_debug_stripped = 0x0200; // Debugging info stripped from file in .DBG file -const uint32_t image_file_removable_run_from_swap = 0x0400; // If Image is on removable media, copy and run from the swap file. -const uint32_t image_file_net_run_from_swap = 0x0800; // If Image is on Net, copy and run from the swap file. -const uint32_t image_file_system = 0x1000; // System File. -const uint32_t image_file_dll = 0x2000; // File is a DLL. -const uint32_t image_file_up_system_only = 0x4000; // File should only be run on a UP machine -const uint32_t image_file_bytes_reversed_hi = 0x8000; // Bytes of machine word are reversed. - -const uint32_t image_scn_lnk_nreloc_ovfl = 0x01000000; // Section contains extended relocations. -const uint32_t image_scn_mem_discardable = 0x02000000; // Section can be discarded. -const uint32_t image_scn_mem_not_cached = 0x04000000; // Section is not cachable. -const uint32_t image_scn_mem_not_paged = 0x08000000; // Section is not pageable. -const uint32_t image_scn_mem_shared = 0x10000000; // Section is shareable. -const uint32_t image_scn_mem_execute = 0x20000000; // Section is executable. -const uint32_t image_scn_mem_read = 0x40000000; // Section is readable. -const uint32_t image_scn_mem_write = 0x80000000; // Section is writeable. - -const uint32_t image_scn_cnt_code = 0x00000020; // Section contains code. -const uint32_t image_scn_cnt_initialized_data = 0x00000040; // Section contains initialized data. -const uint32_t image_scn_cnt_uninitialized_data = 0x00000080; // Section contains uninitialized data. - -//Directory Entries -const uint32_t image_directory_entry_export = 0; // Export Directory -const uint32_t image_directory_entry_import = 1; // Import Directory -const uint32_t image_directory_entry_resource = 2; // Resource Directory -const uint32_t image_directory_entry_exception = 3; // Exception Directory -const uint32_t image_directory_entry_security = 4; // Security Directory -const uint32_t image_directory_entry_basereloc = 5; // Base Relocation Table -const uint32_t image_directory_entry_debug = 6; // Debug Directory -const uint32_t image_directory_entry_architecture = 7; // Architecture Specific Data -const uint32_t image_directory_entry_globalptr = 8; // RVA of GP -const uint32_t image_directory_entry_tls = 9; // TLS Directory -const uint32_t image_directory_entry_load_config = 10; // Load Configuration Directory -const uint32_t image_directory_entry_bound_import = 11; // Bound Import Directory in headers -const uint32_t image_directory_entry_iat = 12; // Import Address Table -const uint32_t image_directory_entry_delay_import = 13; // Delay Load Import Descriptors -const uint32_t image_directory_entry_com_descriptor = 14; // COM Runtime descriptor - -//Subsystem Values -const uint32_t image_subsystem_unknown = 0; // Unknown subsystem. -const uint32_t image_subsystem_native = 1; // Image doesn't require a subsystem. -const uint32_t image_subsystem_windows_gui = 2; // Image runs in the Windows GUI subsystem. -const uint32_t image_subsystem_windows_cui = 3; // Image runs in the Windows character subsystem. -const uint32_t image_subsystem_os2_cui = 5; // image runs in the OS/2 character subsystem. -const uint32_t image_subsystem_posix_cui = 7; // image runs in the Posix character subsystem. -const uint32_t image_subsystem_native_windows = 8; // image is a native Win9x driver. -const uint32_t image_subsystem_windows_ce_gui = 9; // Image runs in the Windows CE subsystem. -const uint32_t image_subsystem_efi_application = 10; // -const uint32_t image_subsystem_efi_boot_service_driver = 11; // -const uint32_t image_subsystem_efi_runtime_driver = 12; // -const uint32_t image_subsystem_efi_rom = 13; -const uint32_t image_subsystem_xbox = 14; -const uint32_t image_subsystem_windows_boot_application = 16; - -//Imports -const uint64_t image_ordinal_flag64 = 0x8000000000000000ull; -const uint32_t image_ordinal_flag32 = 0x80000000; - -//Based relocation types -const uint32_t image_rel_based_absolute = 0; -const uint32_t image_rel_based_high = 1; -const uint32_t image_rel_based_low = 2; -const uint32_t image_rel_based_highlow = 3; -const uint32_t image_rel_based_highadj = 4; -const uint32_t image_rel_based_mips_jmpaddr = 5; -const uint32_t image_rel_based_mips_jmpaddr16 = 9; -const uint32_t image_rel_based_ia64_imm64 = 9; -const uint32_t image_rel_based_dir64 = 10; - -//Exception directory -//The function has an exception handler that should be called when looking for functions that need to examine exceptions -const uint32_t unw_flag_ehandler = 0x01; -//The function has a termination handler that should be called when unwinding an exception -const uint32_t unw_flag_uhandler = 0x02; -//This unwind info structure is not the primary one for the procedure. -//Instead, the chained unwind info entry is the contents of a previous RUNTIME_FUNCTION entry. -//If this flag is set, then the UNW_FLAG_EHANDLER and UNW_FLAG_UHANDLER flags must be cleared. -//Also, the frame register and fixed-stack allocation fields must have the same values as in the primary unwind info -const uint32_t unw_flag_chaininfo = 0x04; - -//Debug -const uint32_t image_debug_misc_exename = 1; -const uint32_t image_debug_type_unknown = 0; -const uint32_t image_debug_type_coff = 1; -const uint32_t image_debug_type_codeview = 2; -const uint32_t image_debug_type_fpo = 3; -const uint32_t image_debug_type_misc = 4; -const uint32_t image_debug_type_exception = 5; -const uint32_t image_debug_type_fixup = 6; -const uint32_t image_debug_type_omap_to_src = 7; -const uint32_t image_debug_type_omap_from_src = 8; -const uint32_t image_debug_type_borland = 9; -const uint32_t image_debug_type_reserved10 = 10; -const uint32_t image_debug_type_clsid = 11; - - -//Storage classes -const uint32_t image_sym_class_end_of_function = static_cast(-1); -const uint32_t image_sym_class_null = 0x0000; -const uint32_t image_sym_class_automatic = 0x0001; -const uint32_t image_sym_class_external = 0x0002; -const uint32_t image_sym_class_static = 0x0003; -const uint32_t image_sym_class_register = 0x0004; -const uint32_t image_sym_class_external_def = 0x0005; -const uint32_t image_sym_class_label = 0x0006; -const uint32_t image_sym_class_undefined_label = 0x0007; -const uint32_t image_sym_class_member_of_struct = 0x0008; -const uint32_t image_sym_class_argument = 0x0009; -const uint32_t image_sym_class_struct_tag = 0x000a; -const uint32_t image_sym_class_member_of_union = 0x000b; -const uint32_t image_sym_class_union_tag = 0x000c; -const uint32_t image_sym_class_type_definition = 0x000d; -const uint32_t image_sym_class_undefined_static = 0x000e; -const uint32_t image_sym_class_enum_tag = 0x000f; -const uint32_t image_sym_class_member_of_enum = 0x0010; -const uint32_t image_sym_class_register_param = 0x0011; -const uint32_t image_sym_class_bit_field = 0x0012; - -const uint32_t image_sym_class_far_external = 0x0044; - -const uint32_t image_sym_class_block = 0x0064; -const uint32_t image_sym_class_function = 0x0065; -const uint32_t image_sym_class_end_of_struct = 0x0066; -const uint32_t image_sym_class_file = 0x0067; - -const uint32_t image_sym_class_section = 0x0068; -const uint32_t image_sym_class_weak_external = 0x0069; - -const uint32_t image_sym_class_clr_token = 0x006b; - -//type packing constants -const uint32_t n_btmask = 0x000f; -const uint32_t n_tmask = 0x0030; -const uint32_t n_tmask1 = 0x00c0; -const uint32_t n_tmask2 = 0x00f0; -const uint32_t n_btshft = 4; -const uint32_t n_tshift = 2; - -//Type (derived) values. -const uint32_t image_sym_dtype_null = 0; // no derived type. -const uint32_t image_sym_dtype_pointer = 1; // pointer. -const uint32_t image_sym_dtype_function = 2; // function. -const uint32_t image_sym_dtype_array = 3; // array. - -// Is x a function? -//TODO -#ifndef ISFCN -#define ISFCN(x) (((x) & n_tmask) == (image_sym_dtype_function << n_btshft)) -#endif - -//Version info -const uint32_t vs_ffi_fileflagsmask = 0x0000003FL; - -const uint32_t vs_ffi_signature = 0xFEEF04BDL; -const uint32_t vs_ffi_strucversion = 0x00010000L; - -/* ----- VS_VERSION.dwFileFlags ----- */ -const uint32_t vs_ff_debug = 0x00000001L; -const uint32_t vs_ff_prerelease = 0x00000002L; -const uint32_t vs_ff_patched = 0x00000004L; -const uint32_t vs_ff_privatebuild = 0x00000008L; -const uint32_t vs_ff_infoinferred = 0x00000010L; -const uint32_t vs_ff_specialbuild = 0x00000020L; - -/* ----- VS_VERSION.dwFileOS ----- */ -const uint32_t vos_unknown = 0x00000000L; -const uint32_t vos_dos = 0x00010000L; -const uint32_t vos_os216 = 0x00020000L; -const uint32_t vos_os232 = 0x00030000L; -const uint32_t vos_nt = 0x00040000L; -const uint32_t vos_wince = 0x00050000L; - -const uint32_t vos__base = 0x00000000L; -const uint32_t vos__windows16 = 0x00000001L; -const uint32_t vos__pm16 = 0x00000002L; -const uint32_t vos__pm32 = 0x00000003L; -const uint32_t vos__windows32 = 0x00000004L; - -const uint32_t vos_dos_windows16 = 0x00010001L; -const uint32_t vos_dos_windows32 = 0x00010004L; -const uint32_t vos_os216_pm16 = 0x00020002L; -const uint32_t vos_os232_pm32 = 0x00030003L; -const uint32_t vos_nt_windows32 = 0x00040004L; - -/* ----- VS_VERSION.dwFileType ----- */ -const uint32_t vft_unknown = 0x00000000L; -const uint32_t vft_app = 0x00000001L; -const uint32_t vft_dll = 0x00000002L; -const uint32_t vft_drv = 0x00000003L; -const uint32_t vft_font = 0x00000004L; -const uint32_t vft_vxd = 0x00000005L; -const uint32_t vft_static_lib = 0x00000007L; - -const uint32_t message_resource_unicode = 0x0001; - -#pragma pack(push, 1) - -//Windows GUID structure -struct guid -{ - uint32_t Data1; - uint16_t Data2; - uint16_t Data3; - uint8_t Data4[8]; -}; - -//DOS .EXE header -struct image_dos_header -{ - uint16_t e_magic; // Magic number - uint16_t e_cblp; // Bytes on last page of file - uint16_t e_cp; // Pages in file - uint16_t e_crlc; // Relocations - uint16_t e_cparhdr; // Size of header in paragraphs - uint16_t e_minalloc; // Minimum extra paragraphs needed - uint16_t e_maxalloc; // Maximum extra paragraphs needed - uint16_t e_ss; // Initial (relative) SS value - uint16_t e_sp; // Initial SP value - uint16_t e_csum; // Checksum - uint16_t e_ip; // Initial IP value - uint16_t e_cs; // Initial (relative) CS value - uint16_t e_lfarlc; // File address of relocation table - uint16_t e_ovno; // Overlay number - uint16_t e_res[4]; // Reserved words - uint16_t e_oemid; // OEM identifier (for e_oeminfo) - uint16_t e_oeminfo; // OEM information; e_oemid specific - uint16_t e_res2[10]; // Reserved words - int32_t e_lfanew; // File address of new exe header -}; - -//Directory format -struct image_data_directory -{ - uint32_t VirtualAddress; - uint32_t Size; -}; - -//Optional header format -struct image_optional_header32 -{ - //Standard fields - uint16_t Magic; - uint8_t MajorLinkerVersion; - uint8_t MinorLinkerVersion; - uint32_t SizeOfCode; - uint32_t SizeOfInitializedData; - uint32_t SizeOfUninitializedData; - uint32_t AddressOfEntryPoint; - uint32_t BaseOfCode; - uint32_t BaseOfData; - - //NT additional fields - uint32_t ImageBase; - uint32_t SectionAlignment; - uint32_t FileAlignment; - uint16_t MajorOperatingSystemVersion; - uint16_t MinorOperatingSystemVersion; - uint16_t MajorImageVersion; - uint16_t MinorImageVersion; - uint16_t MajorSubsystemVersion; - uint16_t MinorSubsystemVersion; - uint32_t Win32VersionValue; - uint32_t SizeOfImage; - uint32_t SizeOfHeaders; - uint32_t CheckSum; - uint16_t Subsystem; - uint16_t DllCharacteristics; - uint32_t SizeOfStackReserve; - uint32_t SizeOfStackCommit; - uint32_t SizeOfHeapReserve; - uint32_t SizeOfHeapCommit; - uint32_t LoaderFlags; - uint32_t NumberOfRvaAndSizes; - image_data_directory DataDirectory[image_numberof_directory_entries]; -}; - -struct image_optional_header64 -{ - uint16_t Magic; - uint8_t MajorLinkerVersion; - uint8_t MinorLinkerVersion; - uint32_t SizeOfCode; - uint32_t SizeOfInitializedData; - uint32_t SizeOfUninitializedData; - uint32_t AddressOfEntryPoint; - uint32_t BaseOfCode; - uint64_t ImageBase; - uint32_t SectionAlignment; - uint32_t FileAlignment; - uint16_t MajorOperatingSystemVersion; - uint16_t MinorOperatingSystemVersion; - uint16_t MajorImageVersion; - uint16_t MinorImageVersion; - uint16_t MajorSubsystemVersion; - uint16_t MinorSubsystemVersion; - uint32_t Win32VersionValue; - uint32_t SizeOfImage; - uint32_t SizeOfHeaders; - uint32_t CheckSum; - uint16_t Subsystem; - uint16_t DllCharacteristics; - uint64_t SizeOfStackReserve; - uint64_t SizeOfStackCommit; - uint64_t SizeOfHeapReserve; - uint64_t SizeOfHeapCommit; - uint32_t LoaderFlags; - uint32_t NumberOfRvaAndSizes; - image_data_directory DataDirectory[image_numberof_directory_entries]; -}; - -struct image_file_header -{ - uint16_t Machine; - uint16_t NumberOfSections; - uint32_t TimeDateStamp; - uint32_t PointerToSymbolTable; - uint32_t NumberOfSymbols; - uint16_t SizeOfOptionalHeader; - uint16_t Characteristics; -}; - -struct image_nt_headers64 -{ - uint32_t Signature; - image_file_header FileHeader; - image_optional_header64 OptionalHeader; -}; - -struct image_nt_headers32 -{ - uint32_t Signature; - image_file_header FileHeader; - image_optional_header32 OptionalHeader; -}; - -//Section header format -struct image_section_header -{ - uint8_t Name[8]; - union - { - uint32_t PhysicalAddress; - uint32_t VirtualSize; - } Misc; - - uint32_t VirtualAddress; - uint32_t SizeOfRawData; - uint32_t PointerToRawData; - uint32_t PointerToRelocations; - uint32_t PointerToLinenumbers; - uint16_t NumberOfRelocations; - uint16_t NumberOfLinenumbers; - uint32_t Characteristics; -}; - - -/// RESOURCES /// -struct image_resource_directory -{ - uint32_t Characteristics; - uint32_t TimeDateStamp; - uint16_t MajorVersion; - uint16_t MinorVersion; - uint16_t NumberOfNamedEntries; - uint16_t NumberOfIdEntries; - // IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[]; -}; - -struct vs_fixedfileinfo -{ - uint32_t dwSignature; /* e.g. 0xfeef04bd */ - uint32_t dwStrucVersion; /* e.g. 0x00000042 = "0.42" */ - uint32_t dwFileVersionMS; /* e.g. 0x00030075 = "3.75" */ - uint32_t dwFileVersionLS; /* e.g. 0x00000031 = "0.31" */ - uint32_t dwProductVersionMS; /* e.g. 0x00030010 = "3.10" */ - uint32_t dwProductVersionLS; /* e.g. 0x00000031 = "0.31" */ - uint32_t dwFileFlagsMask; /* = 0x3F for version "0.42" */ - uint32_t dwFileFlags; /* e.g. VFF_DEBUG | VFF_PRERELEASE */ - uint32_t dwFileOS; /* e.g. VOS_DOS_WINDOWS16 */ - uint32_t dwFileType; /* e.g. VFT_DRIVER */ - uint32_t dwFileSubtype; /* e.g. VFT2_DRV_KEYBOARD */ - uint32_t dwFileDateMS; /* e.g. 0 */ - uint32_t dwFileDateLS; /* e.g. 0 */ -}; - -struct bitmapinfoheader -{ - uint32_t biSize; - int32_t biWidth; - int32_t biHeight; - uint16_t biPlanes; - uint16_t biBitCount; - uint32_t biCompression; - uint32_t biSizeImage; - int32_t biXPelsPerMeter; - int32_t biYPelsPerMeter; - uint32_t biClrUsed; - uint32_t biClrImportant; -}; - -struct message_resource_entry -{ - uint16_t Length; - uint16_t Flags; - uint8_t Text[1]; -}; - -struct message_resource_block -{ - uint32_t LowId; - uint32_t HighId; - uint32_t OffsetToEntries; -}; - -struct message_resource_data -{ - uint32_t NumberOfBlocks; - message_resource_block Blocks[1]; -}; - -struct image_resource_directory_entry -{ - union - { - struct - { - uint32_t NameOffset:31; - uint32_t NameIsString:1; - }; - uint32_t Name; - uint16_t Id; - }; - - union - { - uint32_t OffsetToData; - struct - { - uint32_t OffsetToDirectory:31; - uint32_t DataIsDirectory:1; - }; - }; -}; - -struct image_resource_data_entry -{ - uint32_t OffsetToData; - uint32_t Size; - uint32_t CodePage; - uint32_t Reserved; -}; - -#pragma pack(push, 2) -struct bitmapfileheader -{ - uint16_t bfType; - uint32_t bfSize; - uint16_t bfReserved1; - uint16_t bfReserved2; - uint32_t bfOffBits; -}; -#pragma pack(pop) - - - -//Structure representing ICON file header -struct ico_header -{ - uint16_t Reserved; - uint16_t Type; //1 - uint16_t Count; //Count of icons included in icon group -}; - -//Structure that is stored in icon group directory in PE resources -struct icon_group -{ - uint8_t Width; - uint8_t Height; - uint8_t ColorCount; - uint8_t Reserved; - uint16_t Planes; - uint16_t BitCount; - uint32_t SizeInBytes; - uint16_t Number; //Represents resource ID in PE icon list -}; - -//Structure representing ICON directory entry inside ICON file -struct icondirentry -{ - uint8_t Width; - uint8_t Height; - uint8_t ColorCount; - uint8_t Reserved; - uint16_t Planes; - uint16_t BitCount; - uint32_t SizeInBytes; - uint32_t ImageOffset; //Offset from start of header to the image -}; - -//Structure representing CURSOR file header -struct cursor_header -{ - uint16_t Reserved; - uint16_t Type; //2 - uint16_t Count; //Count of cursors included in cursor group -}; - -struct cursor_group -{ - uint16_t Width; - uint16_t Height; //Divide by 2 to get the actual height. - uint16_t Planes; - uint16_t BitCount; - uint32_t SizeInBytes; - uint16_t Number; //Represents resource ID in PE icon list -}; - -//Structure representing CURSOR directory entry inside CURSOR file -struct cursordirentry -{ - uint8_t Width; //Set to CURSOR_GROUP::Height/2. - uint8_t Height; - uint8_t ColorCount; - uint8_t Reserved; - uint16_t HotspotX; - uint16_t HotspotY; - uint32_t SizeInBytes; - uint32_t ImageOffset; //Offset from start of header to the image -}; - -//Structure representing BLOCK in version info resource -struct version_info_block //(always aligned on 32-bit (DWORD) boundary) -{ - uint16_t Length; //Length of this block (doesn't include padding) - uint16_t ValueLength; //Value length (if any) - uint16_t Type; //Value type (0 = binary, 1 = text) - uint16_t Key[1]; //Value name (block key) (always NULL terminated) - - ////////// - //WORD padding1[]; //Padding, if any (ALIGNMENT) - //xxxxx Value[]; //Value data, if any (*ALIGNED*) - //WORD padding2[]; //Padding, if any (ALIGNMENT) - //xxxxx Child[]; //Child block(s), if any (*ALIGNED*) - ////////// -}; - - -/// IMPORTS /// -#pragma pack(push, 8) -struct image_thunk_data64 -{ - union - { - uint64_t ForwarderString; // PBYTE - uint64_t Function; // PDWORD - uint64_t Ordinal; - uint64_t AddressOfData; // PIMAGE_IMPORT_BY_NAME - } u1; -}; -#pragma pack(pop) - -struct image_thunk_data32 -{ - union - { - uint32_t ForwarderString; // PBYTE - uint32_t Function; // PDWORD - uint32_t Ordinal; - uint32_t AddressOfData; // PIMAGE_IMPORT_BY_NAME - } u1; -}; - -struct image_import_descriptor -{ - union - { - uint32_t Characteristics; // 0 for terminating null import descriptor - uint32_t OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA) - }; - - uint32_t TimeDateStamp; // 0 if not bound, - // -1 if bound, and real date\time stamp - // in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND) - // O.W. date/time stamp of DLL bound to (Old BIND) - - uint32_t ForwarderChain; // -1 if no forwarders - uint32_t Name; - uint32_t FirstThunk; // RVA to IAT (if bound this IAT has actual addresses) -}; - - -/// TLS /// -struct image_tls_directory64 -{ - uint64_t StartAddressOfRawData; - uint64_t EndAddressOfRawData; - uint64_t AddressOfIndex; // PDWORD - uint64_t AddressOfCallBacks; // PIMAGE_TLS_CALLBACK *; - uint32_t SizeOfZeroFill; - uint32_t Characteristics; -}; - -struct image_tls_directory32 -{ - uint32_t StartAddressOfRawData; - uint32_t EndAddressOfRawData; - uint32_t AddressOfIndex; // PDWORD - uint32_t AddressOfCallBacks; // PIMAGE_TLS_CALLBACK * - uint32_t SizeOfZeroFill; - uint32_t Characteristics; -}; - - -/// Export Format /// -struct image_export_directory -{ - uint32_t Characteristics; - uint32_t TimeDateStamp; - uint16_t MajorVersion; - uint16_t MinorVersion; - uint32_t Name; - uint32_t Base; - uint32_t NumberOfFunctions; - uint32_t NumberOfNames; - uint32_t AddressOfFunctions; // RVA from base of image - uint32_t AddressOfNames; // RVA from base of image - uint32_t AddressOfNameOrdinals; // RVA from base of image -}; - - -/// Based relocation format /// -struct image_base_relocation -{ - uint32_t VirtualAddress; - uint32_t SizeOfBlock; - // uint16_t TypeOffset[1]; -}; - - -/// New format import descriptors pointed to by DataDirectory[ IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT ] /// -struct image_bound_import_descriptor -{ - uint32_t TimeDateStamp; - uint16_t OffsetModuleName; - uint16_t NumberOfModuleForwarderRefs; - // Array of zero or more IMAGE_BOUND_FORWARDER_REF follows -}; - -struct image_bound_forwarder_ref -{ - uint32_t TimeDateStamp; - uint16_t OffsetModuleName; - uint16_t Reserved; -}; - - -/// Exception directory /// -struct image_runtime_function_entry -{ - uint32_t BeginAddress; - uint32_t EndAddress; - uint32_t UnwindInfoAddress; -}; - -enum unwind_op_codes -{ - uwop_push_nonvol = 0, /* info == register number */ - uwop_alloc_large, /* no info, alloc size in next 2 slots */ - uwop_alloc_small, /* info == size of allocation / 8 - 1 */ - uwop_set_fpreg, /* no info, FP = RSP + UNWIND_INFO.FPRegOffset*16 */ - uwop_save_nonvol, /* info == register number, offset in next slot */ - uwop_save_nonvol_far, /* info == register number, offset in next 2 slots */ - uwop_save_xmm128, /* info == XMM reg number, offset in next slot */ - uwop_save_xmm128_far, /* info == XMM reg number, offset in next 2 slots */ - uwop_push_machframe /* info == 0: no error-code, 1: error-code */ -}; - -union unwind_code -{ - struct s - { - uint8_t CodeOffset; - uint8_t UnwindOp : 4; - uint8_t OpInfo : 4; - }; - - uint16_t FrameOffset; -}; - -struct unwind_info -{ - uint8_t Version : 3; - uint8_t Flags : 5; - uint8_t SizeOfProlog; - uint8_t CountOfCodes; - uint8_t FrameRegister : 4; - uint8_t FrameOffset : 4; - unwind_code UnwindCode[1]; - /* unwind_code MoreUnwindCode[((CountOfCodes + 1) & ~1) - 1]; - * union { - * OPTIONAL ULONG ExceptionHandler; - * OPTIONAL ULONG FunctionEntry; - * }; - * OPTIONAL ULONG ExceptionData[]; */ -}; - - - -/// Debug /// -struct image_debug_misc -{ - uint32_t DataType; // type of misc data, see defines - uint32_t Length; // total length of record, rounded to four - // byte multiple. - uint8_t Unicode; // TRUE if data is unicode string - uint8_t Reserved[3]; - uint8_t Data[1]; // Actual data -}; - -struct image_coff_symbols_header -{ - uint32_t NumberOfSymbols; - uint32_t LvaToFirstSymbol; - uint32_t NumberOfLinenumbers; - uint32_t LvaToFirstLinenumber; - uint32_t RvaToFirstByteOfCode; - uint32_t RvaToLastByteOfCode; - uint32_t RvaToFirstByteOfData; - uint32_t RvaToLastByteOfData; -}; - -struct image_debug_directory -{ - uint32_t Characteristics; - uint32_t TimeDateStamp; - uint16_t MajorVersion; - uint16_t MinorVersion; - uint32_t Type; - uint32_t SizeOfData; - uint32_t AddressOfRawData; - uint32_t PointerToRawData; -}; - - -#pragma pack(push, 2) -struct image_symbol -{ - union - { - uint8_t ShortName[8]; - struct - { - uint32_t Short; // if 0, use LongName - uint32_t Long; // offset into string table - } Name; - uint32_t LongName[2]; // PBYTE [2] - } N; - uint32_t Value; - int16_t SectionNumber; - uint16_t Type; - uint8_t StorageClass; - uint8_t NumberOfAuxSymbols; -}; -#pragma pack(pop) - -//CodeView Debug OMF signature. The signature at the end of the file is -//a negative offset from the end of the file to another signature. At -//the negative offset (base address) is another signature whose filepos -//field points to the first OMFDirHeader in a chain of directories. -//The NB05 signature is used by the link utility to indicated a completely -//unpacked file. The NB06 signature is used by ilink to indicate that the -//executable has had CodeView information from an incremental link appended -//to the executable. The NB08 signature is used by cvpack to indicate that -//the CodeView Debug OMF has been packed. CodeView will only process -//executables with the NB08 signature. -struct OMFSignature -{ - char Signature[4]; // "NBxx" - uint32_t filepos; // offset in file -}; - -struct CV_INFO_PDB20 -{ - OMFSignature CvHeader; - uint32_t Signature; - uint32_t Age; - uint8_t PdbFileName[1]; -}; - -struct CV_INFO_PDB70 -{ - uint32_t CvSignature; - guid Signature; - uint32_t Age; - uint8_t PdbFileName[1]; -}; - -// directory information structure -// This structure contains the information describing the directory. -// It is pointed to by the signature at the base address or the directory -// link field of a preceeding directory. The directory entries immediately -// follow this structure. -struct OMFDirHeader -{ - uint16_t cbDirHeader; // length of this structure - uint16_t cbDirEntry; // number of bytes in each directory entry - uint32_t cDir; // number of directorie entries - int32_t lfoNextDir; // offset from base of next directory - uint32_t flags; // status flags -}; - -// directory structure -// The data in this structure is used to reference the data for each -// subsection of the CodeView Debug OMF information. Tables that are -// not associated with a specific module will have a module index of -// oxffff. These tables are the global types table, the global symbol -// table, the global public table and the library table. -struct OMFDirEntry -{ - uint16_t SubSection; // subsection type (sst...) - uint16_t iMod; // module index - int32_t lfo; // large file offset of subsection - uint32_t cb; // number of bytes in subsection -}; - - -/// CLR 2.0 header structure /// -struct image_cor20_header -{ - //Header versioning - uint32_t cb; - uint16_t MajorRuntimeVersion; - uint16_t MinorRuntimeVersion; - - // Symbol table and startup information - image_data_directory MetaData; - uint32_t Flags; - - // If COMIMAGE_FLAGS_NATIVE_ENTRYPOINT is not set, EntryPointToken represents a managed entrypoint. - // If COMIMAGE_FLAGS_NATIVE_ENTRYPOINT is set, EntryPointRVA represents an RVA to a native entrypoint. - union - { - uint32_t EntryPointToken; - uint32_t EntryPointRVA; - }; - - // Binding information - image_data_directory Resources; - image_data_directory StrongNameSignature; - - // Regular fixup and binding information - image_data_directory CodeManagerTable; - image_data_directory VTableFixups; - image_data_directory ExportAddressTableJumps; - - // Precompiled image info (internal use only - set to zero) - image_data_directory ManagedNativeHeader; -}; - -enum replaces_cor_hdr_numeric_defines -{ - // COM+ Header entry point flags. - comimage_flags_ilonly =0x00000001, - comimage_flags_32bitrequired =0x00000002, - comimage_flags_il_library =0x00000004, - comimage_flags_strongnamesigned =0x00000008, - comimage_flags_native_entrypoint =0x00000010, - comimage_flags_trackdebugdata =0x00010000, - - // Version flags for image. - cor_version_major_v2 =2, - cor_version_major =cor_version_major_v2, - cor_version_minor =0, - cor_deleted_name_length =8, - cor_vtablegap_name_length =8, - - // Maximum size of a NativeType descriptor. - native_type_max_cb =1, - cor_ilmethod_sect_small_max_datasize=0xff, - - // #defines for the MIH FLAGS - image_cor_mih_methodrva =0x01, - image_cor_mih_ehrva =0x02, - image_cor_mih_basicblock =0x08, - - // V-table constants - cor_vtable_32bit =0x01, // V-table slots are 32-bits in size. - cor_vtable_64bit =0x02, // V-table slots are 64-bits in size. - cor_vtable_from_unmanaged =0x04, // If set, transition from unmanaged. - cor_vtable_from_unmanaged_retain_appdomain =0x08, // If set, transition from unmanaged with keeping the current appdomain. - cor_vtable_call_most_derived =0x10, // Call most derived method described by - - // EATJ constants - image_cor_eatj_thunk_size =32, // Size of a jump thunk reserved range. - - // Max name lengths - //@todo: Change to unlimited name lengths. - max_class_name =1024, - max_package_name =1024 -}; - -/// Load Configuration Directory Entry /// -struct image_load_config_directory32 -{ - uint32_t Size; - uint32_t TimeDateStamp; - uint16_t MajorVersion; - uint16_t MinorVersion; - uint32_t GlobalFlagsClear; - uint32_t GlobalFlagsSet; - uint32_t CriticalSectionDefaultTimeout; - uint32_t DeCommitFreeBlockThreshold; - uint32_t DeCommitTotalFreeThreshold; - uint32_t LockPrefixTable; // VA - uint32_t MaximumAllocationSize; - uint32_t VirtualMemoryThreshold; - uint32_t ProcessHeapFlags; - uint32_t ProcessAffinityMask; - uint16_t CSDVersion; - uint16_t Reserved1; - uint32_t EditList; // VA - uint32_t SecurityCookie; // VA - uint32_t SEHandlerTable; // VA - uint32_t SEHandlerCount; -}; - -struct image_load_config_directory64 -{ - uint32_t Size; - uint32_t TimeDateStamp; - uint16_t MajorVersion; - uint16_t MinorVersion; - uint32_t GlobalFlagsClear; - uint32_t GlobalFlagsSet; - uint32_t CriticalSectionDefaultTimeout; - uint64_t DeCommitFreeBlockThreshold; - uint64_t DeCommitTotalFreeThreshold; - uint64_t LockPrefixTable; // VA - uint64_t MaximumAllocationSize; - uint64_t VirtualMemoryThreshold; - uint64_t ProcessAffinityMask; - uint32_t ProcessHeapFlags; - uint16_t CSDVersion; - uint16_t Reserved1; - uint64_t EditList; // VA - uint64_t SecurityCookie; // VA - uint64_t SEHandlerTable; // VA - uint64_t SEHandlerCount; -}; - -#pragma pack(pop) -} //namespace pe_win - -#ifdef PE_BLISS_WINDOWS -typedef wchar_t unicode16_t; -typedef std::basic_string u16string; -#else -//Instead of wchar_t for windows -typedef unsigned short unicode16_t; -typedef std::basic_string u16string; -#endif - -} //namespace pe_bliss diff --git a/drivers/pe_bliss/pe_tls.cpp b/drivers/pe_bliss/pe_tls.cpp deleted file mode 100644 index 182859f1bf..0000000000 --- a/drivers/pe_bliss/pe_tls.cpp +++ /dev/null @@ -1,375 +0,0 @@ -#include -#include "pe_tls.h" -#include "pe_properties_generic.h" - -namespace pe_bliss -{ -using namespace pe_win; - -//TLS -//Default constructor -tls_info::tls_info() - :start_rva_(0), end_rva_(0), index_rva_(0), callbacks_rva_(0), - size_of_zero_fill_(0), characteristics_(0) -{} - -//Returns start RVA of TLS raw data -uint32_t tls_info::get_raw_data_start_rva() const -{ - return start_rva_; -} - -//Returns end RVA of TLS raw data -uint32_t tls_info::get_raw_data_end_rva() const -{ - return end_rva_; -} - -//Returns TLS index RVA -uint32_t tls_info::get_index_rva() const -{ - return index_rva_; -} - -//Returns TLS callbacks RVA -uint32_t tls_info::get_callbacks_rva() const -{ - return callbacks_rva_; -} - -//Returns size of zero fill -uint32_t tls_info::get_size_of_zero_fill() const -{ - return size_of_zero_fill_; -} - -//Returns characteristics -uint32_t tls_info::get_characteristics() const -{ - return characteristics_; -} - -//Returns raw TLS data -const std::string& tls_info::get_raw_data() const -{ - return raw_data_; -} - -//Returns TLS callbacks addresses -const tls_info::tls_callback_list& tls_info::get_tls_callbacks() const -{ - return callbacks_; -} - -//Returns TLS callbacks addresses -tls_info::tls_callback_list& tls_info::get_tls_callbacks() -{ - return callbacks_; -} - -//Adds TLS callback -void tls_info::add_tls_callback(uint32_t rva) -{ - callbacks_.push_back(rva); -} - -//Clears TLS callbacks list -void tls_info::clear_tls_callbacks() -{ - callbacks_.clear(); -} - -//Recalculates end address of raw TLS data -void tls_info::recalc_raw_data_end_rva() -{ - end_rva_ = static_cast(start_rva_ + raw_data_.length()); -} - -//Sets start RVA of TLS raw data -void tls_info::set_raw_data_start_rva(uint32_t rva) -{ - start_rva_ = rva; -} - -//Sets end RVA of TLS raw data -void tls_info::set_raw_data_end_rva(uint32_t rva) -{ - end_rva_ = rva; -} - -//Sets TLS index RVA -void tls_info::set_index_rva(uint32_t rva) -{ - index_rva_ = rva; -} - -//Sets TLS callbacks RVA -void tls_info::set_callbacks_rva(uint32_t rva) -{ - callbacks_rva_ = rva; -} - -//Sets size of zero fill -void tls_info::set_size_of_zero_fill(uint32_t size) -{ - size_of_zero_fill_ = size; -} - -//Sets characteristics -void tls_info::set_characteristics(uint32_t characteristics) -{ - characteristics_ = characteristics; -} - -//Sets raw TLS data -void tls_info::set_raw_data(const std::string& data) -{ - raw_data_ = data; -} - -//If image does not have TLS, throws an exception -const tls_info get_tls_info(const pe_base& pe) -{ - return pe.get_pe_type() == pe_type_32 - ? get_tls_info_base(pe) - : get_tls_info_base(pe); -} - -//TLS Rebuilder -const image_directory rebuild_tls(pe_base& pe, const tls_info& info, section& tls_section, uint32_t offset_from_section_start, bool write_tls_callbacks, bool write_tls_data, tls_data_expand_type expand, bool save_to_pe_header, bool auto_strip_last_section) -{ - return pe.get_pe_type() == pe_type_32 - ? rebuild_tls_base(pe, info, tls_section, offset_from_section_start, write_tls_callbacks, write_tls_data, expand, save_to_pe_header, auto_strip_last_section) - : rebuild_tls_base(pe, info, tls_section, offset_from_section_start, write_tls_callbacks, write_tls_data, expand, save_to_pe_header, auto_strip_last_section); -} - -//Get TLS info -//If image does not have TLS, throws an exception -template -const tls_info get_tls_info_base(const pe_base& pe) -{ - tls_info ret; - - //If there's no TLS directory, throw an exception - if(!pe.has_tls()) - throw pe_exception("Image does not have TLS directory", pe_exception::directory_does_not_exist); - - //Get TLS directory data - typename PEClassType::TLSStruct tls_directory_data = pe.section_data_from_rva(pe.get_directory_rva(image_directory_entry_tls), section_data_virtual, true); - - //Check data addresses - if(tls_directory_data.EndAddressOfRawData == tls_directory_data.StartAddressOfRawData) - { - try - { - pe.va_to_rva(static_cast(tls_directory_data.EndAddressOfRawData)); - } - catch(const pe_exception&) - { - //Fix addressess on incorrect conversion - tls_directory_data.EndAddressOfRawData = tls_directory_data.StartAddressOfRawData = 0; - } - } - - if(tls_directory_data.StartAddressOfRawData && - pe.section_data_length_from_va(static_cast(tls_directory_data.StartAddressOfRawData), - static_cast(tls_directory_data.StartAddressOfRawData), section_data_virtual, true) - < (tls_directory_data.EndAddressOfRawData - tls_directory_data.StartAddressOfRawData)) - throw pe_exception("Incorrect TLS directory", pe_exception::incorrect_tls_directory); - - //Fill TLS info - //VAs are not checked - ret.set_raw_data_start_rva(tls_directory_data.StartAddressOfRawData ? pe.va_to_rva(static_cast(tls_directory_data.StartAddressOfRawData)) : 0); - ret.set_raw_data_end_rva(tls_directory_data.EndAddressOfRawData ? pe.va_to_rva(static_cast(tls_directory_data.EndAddressOfRawData)) : 0); - ret.set_index_rva(tls_directory_data.AddressOfIndex ? pe.va_to_rva(static_cast(tls_directory_data.AddressOfIndex)) : 0); - ret.set_callbacks_rva(tls_directory_data.AddressOfCallBacks ? pe.va_to_rva(static_cast(tls_directory_data.AddressOfCallBacks)) : 0); - ret.set_size_of_zero_fill(tls_directory_data.SizeOfZeroFill); - ret.set_characteristics(tls_directory_data.Characteristics); - - if(tls_directory_data.StartAddressOfRawData && tls_directory_data.StartAddressOfRawData != tls_directory_data.EndAddressOfRawData) - { - //Read and save TLS RAW data - ret.set_raw_data(std::string( - pe.section_data_from_va(static_cast(tls_directory_data.StartAddressOfRawData), section_data_virtual, true), - static_cast(tls_directory_data.EndAddressOfRawData - tls_directory_data.StartAddressOfRawData))); - } - - //If file has TLS callbacks - if(ret.get_callbacks_rva()) - { - //Read callbacks VAs - uint32_t current_tls_callback = 0; - - while(true) - { - //Read TLS callback VA - typename PEClassType::BaseSize va = pe.section_data_from_va(static_cast(tls_directory_data.AddressOfCallBacks + current_tls_callback), section_data_virtual, true); - if(va == 0) - break; - - //Save it - ret.add_tls_callback(pe.va_to_rva(va, false)); - - //Move to next callback VA - current_tls_callback += sizeof(va); - } - } - - return ret; -} - -//Rebuilder of TLS structures -//If write_tls_callbacks = true, TLS callbacks VAs will be written to their place -//If write_tls_data = true, TLS data will be written to its place -//If you have chosen to rewrite raw data, only (EndAddressOfRawData - StartAddressOfRawData) bytes will be written, not the full length of string -//representing raw data content -//auto_strip_last_section - if true and TLS are placed in the last section, it will be automatically stripped -//Note/TODO: TLS Callbacks array is not DWORD-aligned (seems to work on WinXP - Win7) -template -const image_directory rebuild_tls_base(pe_base& pe, const tls_info& info, section& tls_section, uint32_t offset_from_section_start, bool write_tls_callbacks, bool write_tls_data, tls_data_expand_type expand, bool save_to_pe_header, bool auto_strip_last_section) -{ - //Check that tls_section is attached to this PE image - if(!pe.section_attached(tls_section)) - throw pe_exception("TLS section must be attached to PE file", pe_exception::section_is_not_attached); - - uint32_t tls_data_pos = pe_utils::align_up(offset_from_section_start, sizeof(typename PEClassType::BaseSize)); - uint32_t needed_size = sizeof(typename PEClassType::TLSStruct); //Calculate needed size for TLS table - - //Check if tls_section is last one. If it's not, check if there's enough place for TLS data - if(&tls_section != &*(pe.get_image_sections().end() - 1) && - (tls_section.empty() || pe_utils::align_up(tls_section.get_size_of_raw_data(), pe.get_file_alignment()) < needed_size + tls_data_pos)) - throw pe_exception("Insufficient space for TLS directory", pe_exception::insufficient_space); - - //Check raw data positions - if(info.get_raw_data_end_rva() < info.get_raw_data_start_rva() || info.get_index_rva() == 0) - throw pe_exception("Incorrect TLS directory", pe_exception::incorrect_tls_directory); - - std::string& raw_data = tls_section.get_raw_data(); - - //This will be done only if tls_section is the last section of image or for section with unaligned raw length of data - if(raw_data.length() < needed_size + tls_data_pos) - raw_data.resize(needed_size + tls_data_pos); //Expand section raw data - - //Create and fill TLS structure - typename PEClassType::TLSStruct tls_struct = {0}; - - typename PEClassType::BaseSize va; - if(info.get_raw_data_start_rva()) - { - pe.rva_to_va(info.get_raw_data_start_rva(), va); - tls_struct.StartAddressOfRawData = va; - tls_struct.SizeOfZeroFill = info.get_size_of_zero_fill(); - } - - if(info.get_raw_data_end_rva()) - { - pe.rva_to_va(info.get_raw_data_end_rva(), va); - tls_struct.EndAddressOfRawData = va; - } - - pe.rva_to_va(info.get_index_rva(), va); - tls_struct.AddressOfIndex = va; - - if(info.get_callbacks_rva()) - { - pe.rva_to_va(info.get_callbacks_rva(), va); - tls_struct.AddressOfCallBacks = va; - } - - tls_struct.Characteristics = info.get_characteristics(); - - //Save TLS structure - memcpy(&raw_data[tls_data_pos], &tls_struct, sizeof(tls_struct)); - - //If we are asked to rewrite TLS raw data - if(write_tls_data && info.get_raw_data_start_rva() && info.get_raw_data_start_rva() != info.get_raw_data_end_rva()) - { - try - { - //Check if we're going to write TLS raw data to an existing section (not to PE headers) - section& raw_data_section = pe.section_from_rva(info.get_raw_data_start_rva()); - pe.expand_section(raw_data_section, info.get_raw_data_start_rva(), info.get_raw_data_end_rva() - info.get_raw_data_start_rva(), expand == tls_data_expand_raw ? pe_base::expand_section_raw : pe_base::expand_section_virtual); - } - catch(const pe_exception&) - { - //If no section is presented by StartAddressOfRawData, just go to next step - } - - unsigned long write_raw_data_size = info.get_raw_data_end_rva() - info.get_raw_data_start_rva(); - unsigned long available_raw_length = 0; - - //Check if there's enough RAW space to write raw TLS data... - if((available_raw_length = pe.section_data_length_from_rva(info.get_raw_data_start_rva(), info.get_raw_data_start_rva(), section_data_raw, true)) - < info.get_raw_data_end_rva() - info.get_raw_data_start_rva()) - { - //Check if there's enough virtual space for it... - if(pe.section_data_length_from_rva(info.get_raw_data_start_rva(), info.get_raw_data_start_rva(), section_data_virtual, true) - < info.get_raw_data_end_rva() - info.get_raw_data_start_rva()) - throw pe_exception("Insufficient space for TLS raw data", pe_exception::insufficient_space); - else - write_raw_data_size = available_raw_length; //We'll write just a part of full raw data - } - - //Write raw TLS data, if any - if(write_raw_data_size != 0) - memcpy(pe.section_data_from_rva(info.get_raw_data_start_rva(), true), info.get_raw_data().data(), write_raw_data_size); - } - - //If we are asked to rewrite TLS callbacks addresses - if(write_tls_callbacks && info.get_callbacks_rva()) - { - unsigned long needed_callback_size = static_cast((info.get_tls_callbacks().size() + 1 /* last null element */) * sizeof(typename PEClassType::BaseSize)); - - try - { - //Check if we're going to write TLS callbacks VAs to an existing section (not to PE headers) - section& raw_data_section = pe.section_from_rva(info.get_callbacks_rva()); - pe.expand_section(raw_data_section, info.get_callbacks_rva(), needed_callback_size, pe_base::expand_section_raw); - } - catch(const pe_exception&) - { - //If no section is presented by RVA of callbacks, just go to next step - } - - //Check if there's enough space to write callbacks TLS data... - if(pe.section_data_length_from_rva(info.get_callbacks_rva(), info.get_callbacks_rva(), section_data_raw, true) - < needed_callback_size - sizeof(typename PEClassType::BaseSize) /* last zero element can be virtual only */) - throw pe_exception("Insufficient space for TLS callbacks data", pe_exception::insufficient_space); - - if(pe.section_data_length_from_rva(info.get_callbacks_rva(), info.get_callbacks_rva(), section_data_virtual, true) - < needed_callback_size /* check here full virtual data length available */) - throw pe_exception("Insufficient space for TLS callbacks data", pe_exception::insufficient_space); - - std::vector callbacks_virtual_addresses; - callbacks_virtual_addresses.reserve(info.get_tls_callbacks().size() + 1 /* last null element */); - - //Convert TLS RVAs to VAs - for(tls_info::tls_callback_list::const_iterator it = info.get_tls_callbacks().begin(); it != info.get_tls_callbacks().end(); ++it) - { - typename PEClassType::BaseSize cb_va = 0; - pe.rva_to_va(*it, cb_va); - callbacks_virtual_addresses.push_back(cb_va); - } - - //Ending null element - callbacks_virtual_addresses.push_back(0); - - //Write callbacks TLS data - memcpy(pe.section_data_from_rva(info.get_callbacks_rva(), true), &callbacks_virtual_addresses[0], needed_callback_size); - } - - //Adjust section raw and virtual sizes - pe.recalculate_section_sizes(tls_section, auto_strip_last_section); - - image_directory ret(pe.rva_from_section_offset(tls_section, tls_data_pos), needed_size); - - //If auto-rewrite of PE headers is required - if(save_to_pe_header) - { - pe.set_directory_rva(image_directory_entry_tls, ret.get_rva()); - pe.set_directory_size(image_directory_entry_tls, ret.get_size()); - } - - return ret; -} -} diff --git a/drivers/pe_bliss/pe_tls.h b/drivers/pe_bliss/pe_tls.h deleted file mode 100644 index 8740de83ec..0000000000 --- a/drivers/pe_bliss/pe_tls.h +++ /dev/null @@ -1,101 +0,0 @@ -#pragma once -#include -#include -#include "pe_base.h" -#include "pe_directory.h" - -namespace pe_bliss -{ -//Class representing TLS info -//We use "DWORD" type to represent RVAs, because RVA is -//always 32bit even in PE+ -class tls_info -{ -public: - typedef std::vector tls_callback_list; - -public: - //Default constructor - tls_info(); - - //Returns start RVA of TLS raw data - uint32_t get_raw_data_start_rva() const; - //Returns end RVA of TLS raw data - uint32_t get_raw_data_end_rva() const; - //Returns TLS index RVA - uint32_t get_index_rva() const; - //Returns TLS callbacks RVA - uint32_t get_callbacks_rva() const; - //Returns size of zero fill - uint32_t get_size_of_zero_fill() const; - //Returns characteristics - uint32_t get_characteristics() const; - //Returns raw TLS data - const std::string& get_raw_data() const; - //Returns TLS callbacks addresses - const tls_callback_list& get_tls_callbacks() const; - -public: //These functions do not change everything inside image, they are used by PE class - //You can also use them to rebuild TLS directory - - //Sets start RVA of TLS raw data - void set_raw_data_start_rva(uint32_t rva); - //Sets end RVA of TLS raw data - void set_raw_data_end_rva(uint32_t rva); - //Sets TLS index RVA - void set_index_rva(uint32_t rva); - //Sets TLS callbacks RVA - void set_callbacks_rva(uint32_t rva); - //Sets size of zero fill - void set_size_of_zero_fill(uint32_t size); - //Sets characteristics - void set_characteristics(uint32_t characteristics); - //Sets raw TLS data - void set_raw_data(const std::string& data); - //Returns TLS callbacks addresses - tls_callback_list& get_tls_callbacks(); - //Adds TLS callback - void add_tls_callback(uint32_t rva); - //Clears TLS callbacks list - void clear_tls_callbacks(); - //Recalculates end address of raw TLS data - void recalc_raw_data_end_rva(); - -private: - uint32_t start_rva_, end_rva_, index_rva_, callbacks_rva_; - uint32_t size_of_zero_fill_, characteristics_; - - //Raw TLS data - std::string raw_data_; - - //TLS callback RVAs - tls_callback_list callbacks_; -}; - -//Represents type of expanding of TLS section containing raw data -//(Works only if you are writing TLS raw data to tls_section and it is the last one in the PE image on the moment of TLS rebuild) -enum tls_data_expand_type -{ - tls_data_expand_raw, //If there is not enough raw space for raw TLS data, it can be expanded - tls_data_expand_virtual //If there is not enough virtual place for raw TLS data, it can be expanded -}; - - -//Get TLS info -//If image does not have TLS, throws an exception -const tls_info get_tls_info(const pe_base& pe); - -template -const tls_info get_tls_info_base(const pe_base& pe); - -//Rebuilder of TLS structures -//If write_tls_callbacks = true, TLS callbacks VAs will be written to their place -//If write_tls_data = true, TLS data will be written to its place -//If you have chosen to rewrite raw data, only (EndAddressOfRawData - StartAddressOfRawData) bytes will be written, not the full length of string -//representing raw data content -//auto_strip_last_section - if true and TLS are placed in the last section, it will be automatically stripped -const image_directory rebuild_tls(pe_base& pe, const tls_info& info, section& tls_section, uint32_t offset_from_section_start = 0, bool write_tls_callbacks = true, bool write_tls_data = true, tls_data_expand_type expand = tls_data_expand_raw, bool save_to_pe_header = true, bool auto_strip_last_section = true); - -template -const image_directory rebuild_tls_base(pe_base& pe, const tls_info& info, section& tls_section, uint32_t offset_from_section_start = 0, bool write_tls_callbacks = true, bool write_tls_data = true, tls_data_expand_type expand = tls_data_expand_raw, bool save_to_pe_header = true, bool auto_strip_last_section = true); -} diff --git a/drivers/pe_bliss/resource_bitmap_reader.cpp b/drivers/pe_bliss/resource_bitmap_reader.cpp deleted file mode 100644 index 29eff549db..0000000000 --- a/drivers/pe_bliss/resource_bitmap_reader.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include -#include "resource_bitmap_reader.h" -#include "pe_resource_viewer.h" -#include "pe_structures.h" - -namespace pe_bliss -{ -using namespace pe_win; - -resource_bitmap_reader::resource_bitmap_reader(const pe_resource_viewer& res) - :res_(res) -{} - -//Returns bitmap data by name and index in language directory (instead of language) (minimum checks of format correctness) -const std::string resource_bitmap_reader::get_bitmap_by_name(const std::wstring& name, uint32_t index) const -{ - return create_bitmap(res_.get_resource_data_by_name(pe_resource_viewer::resource_bitmap, name, index).get_data()); -} - -//Returns bitmap data by name and language (minimum checks of format correctness) -const std::string resource_bitmap_reader::get_bitmap_by_name(uint32_t language, const std::wstring& name) const -{ - return create_bitmap(res_.get_resource_data_by_name(language, pe_resource_viewer::resource_bitmap, name).get_data()); -} - -//Returns bitmap data by ID and language (minimum checks of format correctness) -const std::string resource_bitmap_reader::get_bitmap_by_id_lang(uint32_t language, uint32_t id) const -{ - return create_bitmap(res_.get_resource_data_by_id(language, pe_resource_viewer::resource_bitmap, id).get_data()); -} - -//Returns bitmap data by ID and index in language directory (instead of language) (minimum checks of format correctness) -const std::string resource_bitmap_reader::get_bitmap_by_id(uint32_t id, uint32_t index) const -{ - return create_bitmap(res_.get_resource_data_by_id(pe_resource_viewer::resource_bitmap, id, index).get_data()); -} - -//Helper function of creating bitmap header -const std::string resource_bitmap_reader::create_bitmap(const std::string& resource_data) -{ - //Create bitmap file header - bitmapfileheader header = {0}; - header.bfType = 0x4d42; //Signature "BM" - header.bfOffBits = sizeof(bitmapfileheader) + sizeof(bitmapinfoheader); //Offset to bitmap bits - header.bfSize = static_cast(sizeof(bitmapfileheader) + resource_data.length()); //Size of bitmap - - //Check size of resource data - if(resource_data.length() < sizeof(bitmapinfoheader)) - throw pe_exception("Incorrect resource bitmap", pe_exception::resource_incorrect_bitmap); - - { - //Get bitmap info header - const bitmapinfoheader* info = reinterpret_cast(resource_data.data()); - - //If color table is present, skip it - if(info->biClrUsed != 0) - header.bfOffBits += 4 * info->biClrUsed; //Add this size to offset to bitmap bits - else if(info->biBitCount <= 8) - header.bfOffBits += 4 * static_cast(std::pow(2.f, info->biBitCount)); //Add this size to offset to bitmap bits - } - - //Return final bitmap data - return std::string(reinterpret_cast(&header), sizeof(bitmapfileheader)) + resource_data; -} -} diff --git a/drivers/pe_bliss/resource_bitmap_reader.h b/drivers/pe_bliss/resource_bitmap_reader.h deleted file mode 100644 index 2e99571cab..0000000000 --- a/drivers/pe_bliss/resource_bitmap_reader.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once -#include -#include "stdint_defs.h" - -namespace pe_bliss -{ -class pe_resource_viewer; - -class resource_bitmap_reader -{ -public: - resource_bitmap_reader(const pe_resource_viewer& res); - - //Returns bitmap data by name and language (minimum checks of format correctness) - const std::string get_bitmap_by_name(uint32_t language, const std::wstring& name) const; - //Returns bitmap data by name and index in language directory (instead of language) (minimum checks of format correctness) - const std::string get_bitmap_by_name(const std::wstring& name, uint32_t index = 0) const; - //Returns bitmap data by ID and language (minimum checks of format correctness) - const std::string get_bitmap_by_id_lang(uint32_t language, uint32_t id) const; - //Returns bitmap data by ID and index in language directory (instead of language) (minimum checks of format correctness) - const std::string get_bitmap_by_id(uint32_t id, uint32_t index = 0) const; - -private: - //Helper function of creating bitmap header - static const std::string create_bitmap(const std::string& resource_data); - - const pe_resource_viewer& res_; -}; -} diff --git a/drivers/pe_bliss/resource_bitmap_writer.cpp b/drivers/pe_bliss/resource_bitmap_writer.cpp deleted file mode 100644 index 2a28ff6e68..0000000000 --- a/drivers/pe_bliss/resource_bitmap_writer.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "resource_bitmap_writer.h" -#include "pe_resource_manager.h" -#include "pe_structures.h" - -namespace pe_bliss -{ -using namespace pe_win; - -resource_bitmap_writer::resource_bitmap_writer(pe_resource_manager& res) - :res_(res) -{} - -//Adds bitmap from bitmap file data. If bitmap already exists, replaces it -//timestamp will be used for directories that will be added -void resource_bitmap_writer::add_bitmap(const std::string& bitmap_file, uint32_t id, uint32_t language, uint32_t codepage, uint32_t timestamp) -{ - //Check bitmap data a little - if(bitmap_file.length() < sizeof(bitmapfileheader)) - throw pe_exception("Incorrect resource bitmap", pe_exception::resource_incorrect_bitmap); - - resource_directory_entry new_entry; - new_entry.set_id(id); - - //Add bitmap - res_.add_resource(bitmap_file.substr(sizeof(bitmapfileheader)), pe_resource_viewer::resource_bitmap, new_entry, resource_directory::entry_finder(id), language, codepage, timestamp); -} - -//Adds bitmap from bitmap file data. If bitmap already exists, replaces it -//timestamp will be used for directories that will be added -void resource_bitmap_writer::add_bitmap(const std::string& bitmap_file, const std::wstring& name, uint32_t language, uint32_t codepage, uint32_t timestamp) -{ - //Check bitmap data a little - if(bitmap_file.length() < sizeof(bitmapfileheader)) - throw pe_exception("Incorrect resource bitmap", pe_exception::resource_incorrect_bitmap); - - resource_directory_entry new_entry; - new_entry.set_name(name); - - //Add bitmap - res_.add_resource(bitmap_file.substr(sizeof(bitmapfileheader)), pe_resource_viewer::resource_bitmap, new_entry, resource_directory::entry_finder(name), language, codepage, timestamp); -} - -//Removes bitmap by name/ID and language -bool resource_bitmap_writer::remove_bitmap(const std::wstring& name, uint32_t language) -{ - return res_.remove_resource(pe_resource_viewer::resource_bitmap, name, language); -} - -//Removes bitmap by name/ID and language -bool resource_bitmap_writer::remove_bitmap(uint32_t id, uint32_t language) -{ - return res_.remove_resource(pe_resource_viewer::resource_bitmap, id, language); -} -} diff --git a/drivers/pe_bliss/resource_bitmap_writer.h b/drivers/pe_bliss/resource_bitmap_writer.h deleted file mode 100644 index a5a2a4abd4..0000000000 --- a/drivers/pe_bliss/resource_bitmap_writer.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once -#include -#include "stdint_defs.h" - -namespace pe_bliss -{ -class pe_resource_manager; - -class resource_bitmap_writer -{ -public: - resource_bitmap_writer(pe_resource_manager& res); - - //Adds bitmap from bitmap file data. If bitmap already exists, replaces it - //timestamp will be used for directories that will be added - void add_bitmap(const std::string& bitmap_file, uint32_t id, uint32_t language, uint32_t codepage = 0, uint32_t timestamp = 0); - void add_bitmap(const std::string& bitmap_file, const std::wstring& name, uint32_t language, uint32_t codepage = 0, uint32_t timestamp = 0); - - //Removes bitmap by name/ID and language - bool remove_bitmap(const std::wstring& name, uint32_t language); - bool remove_bitmap(uint32_t id, uint32_t language); - -private: - pe_resource_manager& res_; -}; -} diff --git a/drivers/pe_bliss/resource_cursor_icon_reader.cpp b/drivers/pe_bliss/resource_cursor_icon_reader.cpp deleted file mode 100644 index 514e288c22..0000000000 --- a/drivers/pe_bliss/resource_cursor_icon_reader.cpp +++ /dev/null @@ -1,500 +0,0 @@ -#include -#include "resource_cursor_icon_reader.h" -#include "pe_structures.h" -#include "pe_resource_viewer.h" - -namespace pe_bliss -{ -using namespace pe_win; - -resource_cursor_icon_reader::resource_cursor_icon_reader(const pe_resource_viewer& res) - :res_(res) -{} - -//Helper function of creating icon headers from ICON_GROUP resource data -//Returns icon count -uint16_t resource_cursor_icon_reader::format_icon_headers(std::string& ico_data, const std::string& resource_data) -{ - //Check resource data size - if(resource_data.length() < sizeof(ico_header)) - throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon); - - //Get icon header - const ico_header* info = reinterpret_cast(resource_data.data()); - - //Check resource data size - if(resource_data.length() < sizeof(ico_header) + info->Count * sizeof(icon_group)) - throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon); - - //Reserve memory to speed up a little - ico_data.reserve(sizeof(ico_header) + info->Count * sizeof(icondirentry)); - ico_data.append(reinterpret_cast(info), sizeof(ico_header)); - - //Iterate over all listed icons - uint32_t offset = sizeof(ico_header) + sizeof(icondirentry) * info->Count; - for(uint16_t i = 0; i != info->Count; ++i) - { - const icon_group* group = reinterpret_cast(resource_data.data() + sizeof(ico_header) + i * sizeof(icon_group)); - - //Fill icon data - icondirentry direntry; - direntry.BitCount = group->BitCount; - direntry.ColorCount = group->ColorCount; - direntry.Height = group->Height; - direntry.Planes = group->Planes; - direntry.Reserved = group->Reserved; - direntry.SizeInBytes = group->SizeInBytes; - direntry.Width = group->Width; - direntry.ImageOffset = offset; - - //Add icon header to returned value - ico_data.append(reinterpret_cast(&direntry), sizeof(icondirentry)); - - offset += group->SizeInBytes; - } - - //Return icon count - return info->Count; -} - -//Returns single icon data by ID and language (minimum checks of format correctness) -const std::string resource_cursor_icon_reader::get_single_icon_by_id_lang(uint32_t language, uint32_t id) const -{ - //Get icon headers - std::string icon_data(lookup_icon_group_data_by_icon(id, language)); - //Append icon data - icon_data.append(res_.get_resource_data_by_id(language, pe_resource_viewer::resource_icon, id).get_data()); - return icon_data; -} - -//Returns single icon data by ID and index in language directory (instead of language) (minimum checks of format correctness) -const std::string resource_cursor_icon_reader::get_single_icon_by_id(uint32_t id, uint32_t index) const -{ - pe_resource_viewer::resource_language_list languages(res_.list_resource_languages(pe_resource_viewer::resource_icon, id)); - if(languages.size() <= index) - throw pe_exception("Resource data entry not found", pe_exception::resource_data_entry_not_found); - - //Get icon headers - std::string icon_data(lookup_icon_group_data_by_icon(id, languages.at(index))); - //Append icon data - icon_data.append(res_.get_resource_data_by_id(pe_resource_viewer::resource_icon, id, index).get_data()); - return icon_data; -} - -//Returns icon data by name and index in language directory (instead of language) (minimum checks of format correctness) -const std::string resource_cursor_icon_reader::get_icon_by_name(const std::wstring& name, uint32_t index) const -{ - std::string ret; - - //Get resource by name and index - const std::string data = res_.get_resource_data_by_name(pe_resource_viewer::resource_icon_group, name, index).get_data(); - - //Create icon headers - uint16_t icon_count = format_icon_headers(ret, data); - - //Append icon data - for(uint16_t i = 0; i != icon_count; ++i) - { - const icon_group* group = reinterpret_cast(data.data() + sizeof(ico_header) + i * sizeof(icon_group)); - ret += res_.get_resource_data_by_id(pe_resource_viewer::resource_icon, group->Number, index).get_data(); - } - - return ret; -} - -//Returns icon data by name and language (minimum checks of format correctness) -const std::string resource_cursor_icon_reader::get_icon_by_name(uint32_t language, const std::wstring& name) const -{ - std::string ret; - - //Get resource by name and language - const std::string data = res_.get_resource_data_by_name(language, pe_resource_viewer::resource_icon_group, name).get_data(); - - //Create icon headers - uint16_t icon_count = format_icon_headers(ret, data); - - //Append icon data - for(uint16_t i = 0; i != icon_count; ++i) - { - const icon_group* group = reinterpret_cast(data.data() + sizeof(ico_header) + i * sizeof(icon_group)); - ret += res_.get_resource_data_by_id(language, pe_resource_viewer::resource_icon, group->Number).get_data(); - } - - return ret; -} - -//Returns icon data by ID and language (minimum checks of format correctness) -const std::string resource_cursor_icon_reader::get_icon_by_id_lang(uint32_t language, uint32_t id) const -{ - std::string ret; - - //Get resource by language and id - const std::string data = res_.get_resource_data_by_id(language, pe_resource_viewer::resource_icon_group, id).get_data(); - - //Create icon headers - uint16_t icon_count = format_icon_headers(ret, data); - - //Append icon data - for(uint16_t i = 0; i != icon_count; ++i) - { - const icon_group* group = reinterpret_cast(data.data() + sizeof(ico_header) + i * sizeof(icon_group)); - ret += res_.get_resource_data_by_id(language, pe_resource_viewer::resource_icon, group->Number).get_data(); - } - - return ret; -} - -//Returns icon data by ID and index in language directory (instead of language) (minimum checks of format correctness) -const std::string resource_cursor_icon_reader::get_icon_by_id(uint32_t id, uint32_t index) const -{ - std::string ret; - - //Get resource by id and index - const std::string data = res_.get_resource_data_by_id(pe_resource_viewer::resource_icon_group, id, index).get_data(); - - //Create icon headers - uint16_t icon_count = format_icon_headers(ret, data); - - //Append icon data - for(uint16_t i = 0; i != icon_count; ++i) - { - const icon_group* group = reinterpret_cast(data.data() + sizeof(ico_header) + i * sizeof(icon_group)); - ret += res_.get_resource_data_by_id(pe_resource_viewer::resource_icon, group->Number, index).get_data(); - } - - return ret; -} - -//Checks for icon presence inside icon group, fills icon headers if found -bool resource_cursor_icon_reader::check_icon_presence(const std::string& icon_group_resource_data, uint32_t icon_id, std::string& ico_data) -{ - //Check resource data size - if(icon_group_resource_data.length() < sizeof(ico_header)) - throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon); - - //Get icon header - const ico_header* info = reinterpret_cast(icon_group_resource_data.data()); - - //Check resource data size - if(icon_group_resource_data.length() < sizeof(ico_header) + info->Count * sizeof(icon_group)) - throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon); - - for(uint16_t i = 0; i != info->Count; ++i) - { - const icon_group* group = reinterpret_cast(icon_group_resource_data.data() + sizeof(ico_header) + i * sizeof(icon_group)); - if(group->Number == icon_id) - { - //Reserve memory to speed up a little - ico_data.reserve(sizeof(ico_header) + sizeof(icondirentry)); - //Write single-icon icon header - ico_header new_header = *info; - new_header.Count = 1; - ico_data.append(reinterpret_cast(&new_header), sizeof(ico_header)); - - //Fill icon data - icondirentry direntry; - direntry.BitCount = group->BitCount; - direntry.ColorCount = group->ColorCount; - direntry.Height = group->Height; - direntry.Planes = group->Planes; - direntry.Reserved = group->Reserved; - direntry.SizeInBytes = group->SizeInBytes; - direntry.Width = group->Width; - direntry.ImageOffset = sizeof(ico_header) + sizeof(icondirentry); - ico_data.append(reinterpret_cast(&direntry), sizeof(direntry)); - - return true; - } - } - - return false; -} - -//Looks up icon group by icon id and returns full icon headers if found -const std::string resource_cursor_icon_reader::lookup_icon_group_data_by_icon(uint32_t icon_id, uint32_t language) const -{ - std::string icon_header_data; - - { - //List all ID-resources - pe_resource_viewer::resource_id_list ids(res_.list_resource_ids(pe_resource_viewer::resource_icon_group)); - - for(pe_resource_viewer::resource_id_list::const_iterator it = ids.begin(); it != ids.end(); ++it) - { - pe_resource_viewer::resource_language_list group_languages(res_.list_resource_languages(pe_resource_viewer::resource_icon_group, *it)); - if(std::find(group_languages.begin(), group_languages.end(), language) != group_languages.end() - && check_icon_presence(res_.get_resource_data_by_id(language, pe_resource_viewer::resource_icon_group, *it).get_data(), icon_id, icon_header_data)) - return icon_header_data; - } - } - - { - //List all named resources - pe_resource_viewer::resource_name_list names(res_.list_resource_names(pe_resource_viewer::resource_icon_group)); - for(pe_resource_viewer::resource_name_list::const_iterator it = names.begin(); it != names.end(); ++it) - { - pe_resource_viewer::resource_language_list group_languages(res_.list_resource_languages(pe_resource_viewer::resource_icon_group, *it)); - if(std::find(group_languages.begin(), group_languages.end(), language) != group_languages.end() - && check_icon_presence(res_.get_resource_data_by_name(language, pe_resource_viewer::resource_icon_group, *it).get_data(), icon_id, icon_header_data)) - return icon_header_data; - } - } - - throw pe_exception("No icon group find for requested icon", pe_exception::no_icon_group_found); -} - -//Returns single cursor data by ID and language (minimum checks of format correctness) -const std::string resource_cursor_icon_reader::get_single_cursor_by_id_lang(uint32_t language, uint32_t id) const -{ - std::string raw_cursor_data(res_.get_resource_data_by_id(language, pe_resource_viewer::resource_cursor, id).get_data()); - //Get cursor headers - std::string cursor_data(lookup_cursor_group_data_by_cursor(id, language, raw_cursor_data)); - //Append cursor data - cursor_data.append(raw_cursor_data.substr(sizeof(uint16_t) * 2 /* hotspot position */)); - return cursor_data; -} - -//Returns single cursor data by ID and index in language directory (instead of language) (minimum checks of format correctness) -const std::string resource_cursor_icon_reader::get_single_cursor_by_id(uint32_t id, uint32_t index) const -{ - pe_resource_viewer::resource_language_list languages(res_.list_resource_languages(pe_resource_viewer::resource_cursor, id)); - if(languages.size() <= index) - throw pe_exception("Resource data entry not found", pe_exception::resource_data_entry_not_found); - - std::string raw_cursor_data(res_.get_resource_data_by_id(pe_resource_viewer::resource_cursor, id, index).get_data()); - //Get cursor headers - std::string cursor_data(lookup_cursor_group_data_by_cursor(id, languages.at(index), raw_cursor_data)); - //Append cursor data - cursor_data.append(raw_cursor_data.substr(sizeof(uint16_t) * 2 /* hotspot position */)); - return cursor_data; -} - -//Helper function of creating cursor headers -//Returns cursor count -uint16_t resource_cursor_icon_reader::format_cursor_headers(std::string& cur_data, const std::string& resource_data, uint32_t language, uint32_t index) const -{ - //Check resource data length - if(resource_data.length() < sizeof(cursor_header)) - throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor); - - const cursor_header* info = reinterpret_cast(resource_data.data()); - - //Check resource data length - if(resource_data.length() < sizeof(cursor_header) + sizeof(cursor_group) * info->Count) - throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor); - - //Reserve needed space to speed up a little - cur_data.reserve(sizeof(cursor_header) + info->Count * sizeof(cursordirentry)); - //Add cursor header - cur_data.append(reinterpret_cast(info), sizeof(cursor_header)); - - //Iterate over all cursors listed in cursor group - uint32_t offset = sizeof(cursor_header) + sizeof(cursordirentry) * info->Count; - for(uint16_t i = 0; i != info->Count; ++i) - { - const cursor_group* group = reinterpret_cast(resource_data.data() + sizeof(cursor_header) + i * sizeof(cursor_group)); - - //Fill cursor info - cursordirentry direntry; - direntry.ColorCount = 0; //OK - direntry.Width = static_cast(group->Width); - direntry.Height = static_cast(group->Height) / 2; - direntry.Reserved = 0; - - //Now read hotspot data from cursor data directory - const std::string cursor = index == 0xFFFFFFFF - ? res_.get_resource_data_by_id(language, pe_resource_viewer::resource_cursor, group->Number).get_data() - : res_.get_resource_data_by_id(pe_resource_viewer::resource_cursor, group->Number, index).get_data(); - if(cursor.length() < 2 * sizeof(uint16_t)) - throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor); - - //Here it is - two words in the very beginning of cursor data - direntry.HotspotX = *reinterpret_cast(cursor.data()); - direntry.HotspotY = *reinterpret_cast(cursor.data() + sizeof(uint16_t)); - - //Fill the rest data - direntry.SizeInBytes = group->SizeInBytes - 2 * sizeof(uint16_t); - direntry.ImageOffset = offset; - - //Add cursor header - cur_data.append(reinterpret_cast(&direntry), sizeof(cursordirentry)); - - offset += direntry.SizeInBytes; - } - - //Return cursor count - return info->Count; -} - -//Returns cursor data by name and language (minimum checks of format correctness) -const std::string resource_cursor_icon_reader::get_cursor_by_name(uint32_t language, const std::wstring& name) const -{ - std::string ret; - - //Get resource by name and language - const std::string resource_data = res_.get_resource_data_by_name(language, pe_resource_viewer::resource_cursor_group, name).get_data(); - - //Create cursor headers - uint16_t cursor_count = format_cursor_headers(ret, resource_data, language); - - //Add cursor data - for(uint16_t i = 0; i != cursor_count; ++i) - { - const cursor_group* group = reinterpret_cast(resource_data.data() + sizeof(cursor_header) + i * sizeof(cursor_group)); - ret += res_.get_resource_data_by_id(language, pe_resource_viewer::resource_cursor, group->Number).get_data().substr(2 * sizeof(uint16_t)); - } - - return ret; -} - -//Returns cursor data by name and index in language directory (instead of language) (minimum checks of format correctness) -const std::string resource_cursor_icon_reader::get_cursor_by_name(const std::wstring& name, uint32_t index) const -{ - std::string ret; - - //Get resource by name and index - const std::string resource_data = res_.get_resource_data_by_name(pe_resource_viewer::resource_cursor_group, name, index).get_data(); - - //Create cursor headers - uint16_t cursor_count = format_cursor_headers(ret, resource_data, 0, index); - - //Add cursor data - for(uint16_t i = 0; i != cursor_count; ++i) - { - const cursor_group* group = reinterpret_cast(resource_data.data() + sizeof(cursor_header) + i * sizeof(cursor_group)); - ret += res_.get_resource_data_by_id(pe_resource_viewer::resource_cursor, group->Number, index).get_data().substr(2 * sizeof(uint16_t)); - } - - return ret; -} - -//Returns cursor data by ID and language (minimum checks of format correctness) -const std::string resource_cursor_icon_reader::get_cursor_by_id_lang(uint32_t language, uint32_t id) const -{ - std::string ret; - - //Get resource by ID and language - const std::string resource_data = res_.get_resource_data_by_id(language, pe_resource_viewer::resource_cursor_group, id).get_data(); - - //Create cursor headers - uint16_t cursor_count = format_cursor_headers(ret, resource_data, language); - - //Add cursor data - for(uint16_t i = 0; i != cursor_count; ++i) - { - const cursor_group* group = reinterpret_cast(resource_data.data() + sizeof(cursor_header) + i * sizeof(cursor_group)); - ret += res_.get_resource_data_by_id(language, pe_resource_viewer::resource_cursor, group->Number).get_data().substr(2 * sizeof(uint16_t)); - } - - return ret; -} - -//Returns cursor data by ID and index in language directory (instead of language) (minimum checks of format correctness) -const std::string resource_cursor_icon_reader::get_cursor_by_id(uint32_t id, uint32_t index) const -{ - std::string ret; - - //Get resource by ID and index - const std::string resource_data = res_.get_resource_data_by_id(pe_resource_viewer::resource_cursor_group, id, index).get_data(); - - //Create cursor headers - uint16_t cursor_count = format_cursor_headers(ret, resource_data, 0, index); - - //Add cursor data - for(uint16_t i = 0; i != cursor_count; ++i) - { - const cursor_group* group = reinterpret_cast(resource_data.data() + sizeof(cursor_header) + i * sizeof(cursor_group)); - ret += res_.get_resource_data_by_id(pe_resource_viewer::resource_cursor, group->Number, index).get_data().substr(2 * sizeof(uint16_t)); - } - - return ret; -} - -//Checks for cursor presence inside cursor group, fills cursor headers if found -bool resource_cursor_icon_reader::check_cursor_presence(const std::string& cursor_group_resource_data, uint32_t cursor_id, std::string& cur_header_data, const std::string& raw_cursor_data) -{ - //Check resource data length - if(cursor_group_resource_data.length() < sizeof(cursor_header)) - throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor); - - const cursor_header* info = reinterpret_cast(cursor_group_resource_data.data()); - - //Check resource data length - if(cursor_group_resource_data.length() < sizeof(cursor_header) + sizeof(cursor_group)) - throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor); - - //Iterate over all cursors listed in cursor group - for(uint16_t i = 0; i != info->Count; ++i) - { - const cursor_group* group = reinterpret_cast(cursor_group_resource_data.data() + sizeof(cursor_header) + i * sizeof(cursor_group)); - - if(group->Number == cursor_id) - { - //Reserve needed space to speed up a little - cur_header_data.reserve(sizeof(cursor_header) + sizeof(cursordirentry)); - //Write single-cursor cursor header - cursor_header new_header = *info; - new_header.Count = 1; - cur_header_data.append(reinterpret_cast(&new_header), sizeof(cursor_header)); - - //Fill cursor info - cursordirentry direntry; - direntry.ColorCount = 0; //OK - direntry.Width = static_cast(group->Width); - direntry.Height = static_cast(group->Height) / 2; - direntry.Reserved = 0; - - if(raw_cursor_data.length() < 2 * sizeof(uint16_t)) - throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor); - - //Here it is - two words in the very beginning of cursor data - direntry.HotspotX = *reinterpret_cast(raw_cursor_data.data()); - direntry.HotspotY = *reinterpret_cast(raw_cursor_data.data() + sizeof(uint16_t)); - - //Fill the rest data - direntry.SizeInBytes = group->SizeInBytes - 2 * sizeof(uint16_t); - direntry.ImageOffset = sizeof(cursor_header) + sizeof(cursordirentry); - - //Add cursor header - cur_header_data.append(reinterpret_cast(&direntry), sizeof(cursordirentry)); - - return true; - } - } - - return false; -} - -//Looks up cursor group by cursor id and returns full cursor headers if found -const std::string resource_cursor_icon_reader::lookup_cursor_group_data_by_cursor(uint32_t cursor_id, uint32_t language, const std::string& raw_cursor_data) const -{ - std::string cursor_header_data; - - { - //List all ID-resources - pe_resource_viewer::resource_id_list ids(res_.list_resource_ids(pe_resource_viewer::resource_cursor_group)); - - for(pe_resource_viewer::resource_id_list::const_iterator it = ids.begin(); it != ids.end(); ++it) - { - pe_resource_viewer::resource_language_list group_languages(res_.list_resource_languages(pe_resource_viewer::resource_cursor_group, *it)); - if(std::find(group_languages.begin(), group_languages.end(), language) != group_languages.end() - && check_cursor_presence(res_.get_resource_data_by_id(language, pe_resource_viewer::resource_cursor_group, *it).get_data(), cursor_id, cursor_header_data, raw_cursor_data)) - return cursor_header_data; - } - } - - { - //List all named resources - pe_resource_viewer::resource_name_list names(res_.list_resource_names(pe_resource_viewer::resource_cursor_group)); - for(pe_resource_viewer::resource_name_list::const_iterator it = names.begin(); it != names.end(); ++it) - { - pe_resource_viewer::resource_language_list group_languages(res_.list_resource_languages(pe_resource_viewer::resource_cursor_group, *it)); - if(std::find(group_languages.begin(), group_languages.end(), language) != group_languages.end() - && check_cursor_presence(res_.get_resource_data_by_name(language, pe_resource_viewer::resource_cursor_group, *it).get_data(), cursor_id, cursor_header_data, raw_cursor_data)) - return cursor_header_data; - } - } - - throw pe_exception("No cursor group find for requested icon", pe_exception::no_cursor_group_found); -} -} diff --git a/drivers/pe_bliss/resource_cursor_icon_reader.h b/drivers/pe_bliss/resource_cursor_icon_reader.h deleted file mode 100644 index 25a59baa27..0000000000 --- a/drivers/pe_bliss/resource_cursor_icon_reader.h +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once -#include -#include "stdint_defs.h" - -namespace pe_bliss -{ -class pe_resource_viewer; - -class resource_cursor_icon_reader -{ -public: - resource_cursor_icon_reader(const pe_resource_viewer& res); - - //Returns single icon data by ID and language (minimum checks of format correctness) - const std::string get_single_icon_by_id_lang(uint32_t language, uint32_t id) const; - //Returns single icon data by ID and index in language directory (instead of language) (minimum checks of format correctness) - const std::string get_single_icon_by_id(uint32_t id, uint32_t index = 0) const; - - //Returns icon data of group of icons by name and language (minimum checks of format correctness) - const std::string get_icon_by_name(uint32_t language, const std::wstring& icon_group_name) const; - //Returns icon data of group of icons by name and index in language directory (instead of language) (minimum checks of format correctness) - const std::string get_icon_by_name(const std::wstring& icon_group_name, uint32_t index = 0) const; - //Returns icon data of group of icons by ID and language (minimum checks of format correctness) - const std::string get_icon_by_id_lang(uint32_t language, uint32_t icon_group_id) const; - //Returns icon data of group of icons by ID and index in language directory (instead of language) (minimum checks of format correctness) - const std::string get_icon_by_id(uint32_t icon_group_id, uint32_t index = 0) const; - - //Returns single cursor data by ID and language (minimum checks of format correctness) - const std::string get_single_cursor_by_id_lang(uint32_t language, uint32_t id) const; - //Returns single cursor data by ID and index in language directory (instead of language) (minimum checks of format correctness) - const std::string get_single_cursor_by_id(uint32_t id, uint32_t index = 0) const; - - //Returns cursor data by name and language (minimum checks of format correctness) - const std::string get_cursor_by_name(uint32_t language, const std::wstring& cursor_group_name) const; - //Returns cursor data by name and index in language directory (instead of language) (minimum checks of format correctness) - const std::string get_cursor_by_name(const std::wstring& cursor_group_name, uint32_t index = 0) const; - //Returns cursor data by ID and language (minimum checks of format correctness) - const std::string get_cursor_by_id_lang(uint32_t language, uint32_t cursor_group_id) const; - //Returns cursor data by ID and index in language directory (instead of language) (minimum checks of format correctness) - const std::string get_cursor_by_id(uint32_t cursor_group_id, uint32_t index = 0) const; - -private: - const pe_resource_viewer& res_; - - //Helper function of creating icon headers from ICON_GROUP resource data - //Returns icon count - static uint16_t format_icon_headers(std::string& ico_data, const std::string& resource_data); - - //Helper function of creating cursor headers from CURSOR_GROUP resource data - //Returns cursor count - uint16_t format_cursor_headers(std::string& cur_data, const std::string& resource_data, uint32_t language, uint32_t index = 0xFFFFFFFF) const; - - //Looks up icon group by icon id and returns full icon headers if found - const std::string lookup_icon_group_data_by_icon(uint32_t icon_id, uint32_t language) const; - //Checks for icon presence inside icon group, fills icon headers if found - static bool check_icon_presence(const std::string& icon_group_resource_data, uint32_t icon_id, std::string& ico_data); - - //Looks up cursor group by cursor id and returns full cursor headers if found - const std::string lookup_cursor_group_data_by_cursor(uint32_t cursor_id, uint32_t language, const std::string& raw_cursor_data) const; - //Checks for cursor presence inside cursor group, fills cursor headers if found - static bool check_cursor_presence(const std::string& icon_group_resource_data, uint32_t cursor_id, std::string& cur_header_data, const std::string& raw_cursor_data); -}; -} diff --git a/drivers/pe_bliss/resource_cursor_icon_writer.cpp b/drivers/pe_bliss/resource_cursor_icon_writer.cpp deleted file mode 100644 index ce52c6cbdf..0000000000 --- a/drivers/pe_bliss/resource_cursor_icon_writer.cpp +++ /dev/null @@ -1,426 +0,0 @@ -#include -#include -#include "resource_cursor_icon_writer.h" - -namespace pe_bliss -{ -using namespace pe_win; - -resource_cursor_icon_writer::resource_cursor_icon_writer(pe_resource_manager& res) - :res_(res) -{} - -//Add icon helper -void resource_cursor_icon_writer::add_icon(const std::string& icon_file, const resource_data_info* group_icon_info /* or zero */, resource_directory_entry& new_icon_group_entry, const resource_directory::entry_finder& finder, uint32_t language, icon_place_mode mode, uint32_t codepage, uint32_t timestamp) -{ - //Check icon for correctness - if(icon_file.length() < sizeof(ico_header)) - throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon); - - const ico_header* icon_header = reinterpret_cast(&icon_file[0]); - - unsigned long size_of_headers = sizeof(ico_header) + icon_header->Count * sizeof(icondirentry); - if(icon_file.length() < size_of_headers || icon_header->Count == 0) - throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon); - - //Enumerate all icons in file - for(uint16_t i = 0; i != icon_header->Count; ++i) - { - //Check icon entries - const icondirentry* icon_entry = reinterpret_cast(&icon_file[sizeof(ico_header) + i * sizeof(icondirentry)]); - if(icon_entry->SizeInBytes == 0 - || icon_entry->ImageOffset < size_of_headers - || !pe_utils::is_sum_safe(icon_entry->ImageOffset, icon_entry->SizeInBytes) - || icon_entry->ImageOffset + icon_entry->SizeInBytes > icon_file.length()) - throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon); - } - - std::string icon_group_data; - ico_header* info = 0; - - if(group_icon_info) - { - //If icon group already exists - { - icon_group_data = group_icon_info->get_data(); - codepage = group_icon_info->get_codepage(); //Don't change codepage of icon group entry - } - - //Check resource data size - if(icon_group_data.length() < sizeof(ico_header)) - throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon); - - //Get icon header - info = reinterpret_cast(&icon_group_data[0]); - - //Check resource data size - if(icon_group_data.length() < sizeof(ico_header) + info->Count * sizeof(icon_group)) - throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon); - - icon_group_data.resize(sizeof(ico_header) + (info->Count + icon_header->Count) * sizeof(icon_group)); - info = reinterpret_cast(&icon_group_data[0]); //In case if memory was reallocated - } - else //Entry not found - icon group doesn't exist - { - icon_group_data.resize(sizeof(ico_header) + icon_header->Count * sizeof(icon_group)); - memcpy(&icon_group_data[0], icon_header, sizeof(ico_header)); - } - - //Search for available icon IDs - std::vector icon_id_list(get_icon_or_cursor_free_id_list(pe_resource_viewer::resource_icon, mode, icon_header->Count)); - - //Enumerate all icons in file - for(uint16_t i = 0; i != icon_header->Count; ++i) - { - const icondirentry* icon_entry = reinterpret_cast(&icon_file[sizeof(ico_header) + i * sizeof(icondirentry)]); - icon_group group = {0}; - - //Fill icon resource header - group.BitCount = icon_entry->BitCount; - group.ColorCount = icon_entry->ColorCount; - group.Height = icon_entry->Height; - group.Planes = icon_entry->Planes; - group.Reserved = icon_entry->Reserved; - group.SizeInBytes = icon_entry->SizeInBytes; - group.Width = icon_entry->Width; - group.Number = icon_id_list.at(i); - - memcpy(&icon_group_data[sizeof(ico_header) + ((info ? info->Count : 0) + i) * sizeof(icon_group)], &group, sizeof(group)); - - //Add icon to resources - resource_directory_entry new_entry; - new_entry.set_id(group.Number); - res_.add_resource(icon_file.substr(icon_entry->ImageOffset, icon_entry->SizeInBytes), pe_resource_viewer::resource_icon, new_entry, resource_directory::entry_finder(group.Number), language, codepage, timestamp); - } - - if(info) - info->Count += icon_header->Count; //Increase icon count, if we're adding icon to existing group - - { - //Add or replace icon group data entry - res_.add_resource(icon_group_data, pe_resource_viewer::resource_icon_group, new_icon_group_entry, finder, language, codepage, timestamp); - } -} - -//Returns free icon or cursor ID list depending on icon_place_mode -const std::vector resource_cursor_icon_writer::get_icon_or_cursor_free_id_list(pe_resource_viewer::resource_type type, icon_place_mode mode, uint32_t count) -{ - //Search for available icon/cursor IDs - std::vector icon_cursor_id_list; - - try - { - //If any icon exists - //List icon IDs - std::vector id_list(res_.list_resource_ids(type)); - std::sort(id_list.begin(), id_list.end()); - - //If we are placing icon on free spaces - //I.e., icon IDs 1, 3, 4, 7, 8 already exist - //We'll place five icons on IDs 2, 5, 6, 9, 10 - if(mode != icon_place_after_max_icon_id) - { - if(!id_list.empty()) - { - //Determine and list free icon IDs - for(std::vector::const_iterator it = id_list.begin(); it != id_list.end(); ++it) - { - if(it == id_list.begin()) - { - if(*it > 1) - { - for(uint16_t i = 1; i != *it; ++i) - { - icon_cursor_id_list.push_back(i); - if(icon_cursor_id_list.size() == count) - break; - } - } - } - else if(*(it - 1) - *it > 1) - { - for(uint16_t i = static_cast(*(it - 1) + 1); i != static_cast(*it); ++i) - { - icon_cursor_id_list.push_back(i); - if(icon_cursor_id_list.size() == count) - break; - } - } - - if(icon_cursor_id_list.size() == count) - break; - } - } - } - - uint32_t max_id = id_list.empty() ? 0 : *std::max_element(id_list.begin(), id_list.end()); - for(uint32_t i = static_cast(icon_cursor_id_list.size()); i != count; ++i) - icon_cursor_id_list.push_back(static_cast(++max_id)); - } - catch(const pe_exception&) //Entry not found - { - for(uint16_t i = 1; i != count + 1; ++i) - icon_cursor_id_list.push_back(i); - } - - return icon_cursor_id_list; -} - -//Add cursor helper -void resource_cursor_icon_writer::add_cursor(const std::string& cursor_file, const resource_data_info* group_cursor_info /* or zero */, resource_directory_entry& new_cursor_group_entry, const resource_directory::entry_finder& finder, uint32_t language, icon_place_mode mode, uint32_t codepage, uint32_t timestamp) -{ - //Check cursor for correctness - if(cursor_file.length() < sizeof(cursor_header)) - throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor); - - const cursor_header* cur_header = reinterpret_cast(&cursor_file[0]); - - unsigned long size_of_headers = sizeof(cursor_header) + cur_header->Count * sizeof(cursordirentry); - if(cursor_file.length() < size_of_headers || cur_header->Count == 0) - throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor); - - //Enumerate all cursors in file - for(uint16_t i = 0; i != cur_header->Count; ++i) - { - //Check cursor entries - const cursordirentry* cursor_entry = reinterpret_cast(&cursor_file[sizeof(cursor_header) + i * sizeof(cursordirentry)]); - if(cursor_entry->SizeInBytes == 0 - || cursor_entry->ImageOffset < size_of_headers - || !pe_utils::is_sum_safe(cursor_entry->ImageOffset, cursor_entry->SizeInBytes) - || cursor_entry->ImageOffset + cursor_entry->SizeInBytes > cursor_file.length()) - throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor); - } - - std::string cursor_group_data; - cursor_header* info = 0; - - if(group_cursor_info) - { - //If cursor group already exists - { - cursor_group_data = group_cursor_info->get_data(); - codepage = group_cursor_info->get_codepage(); //Don't change codepage of cursor group entry - } - - //Check resource data size - if(cursor_group_data.length() < sizeof(cursor_header)) - throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor); - - //Get cursor header - info = reinterpret_cast(&cursor_group_data[0]); - - //Check resource data size - if(cursor_group_data.length() < sizeof(cursor_header) + info->Count * sizeof(cursor_group)) - throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor); - - cursor_group_data.resize(sizeof(cursor_header) + (info->Count + cur_header->Count) * sizeof(cursor_group)); - info = reinterpret_cast(&cursor_group_data[0]); //In case if memory was reallocated - } - else //Entry not found - cursor group doesn't exist - { - cursor_group_data.resize(sizeof(cursor_header) + cur_header->Count * sizeof(cursor_group)); - memcpy(&cursor_group_data[0], cur_header, sizeof(cursor_header)); - } - - //Search for available cursor IDs - std::vector cursor_id_list(get_icon_or_cursor_free_id_list(pe_resource_viewer::resource_cursor, mode, cur_header->Count)); - - //Enumerate all cursors in file - for(uint16_t i = 0; i != cur_header->Count; ++i) - { - const cursordirentry* cursor_entry = reinterpret_cast(&cursor_file[sizeof(cursor_header) + i * sizeof(cursordirentry)]); - cursor_group group = {0}; - - //Fill cursor resource header - group.Height = cursor_entry->Height * 2; - group.SizeInBytes = cursor_entry->SizeInBytes + 2 * sizeof(uint16_t) /* hotspot coordinates */; - group.Width = cursor_entry->Width; - group.Number = cursor_id_list.at(i); - - memcpy(&cursor_group_data[sizeof(cursor_header) + ((info ? info->Count : 0) + i) * sizeof(cursor_group)], &group, sizeof(group)); - - //Add cursor to resources - resource_directory_entry new_entry; - new_entry.set_id(group.Number); - - //Fill resource data (two WORDs for hotspot of cursor, and cursor bitmap data) - std::string cur_data; - cur_data.resize(sizeof(uint16_t) * 2); - memcpy(&cur_data[0], &cursor_entry->HotspotX, sizeof(uint16_t)); - memcpy(&cur_data[sizeof(uint16_t)], &cursor_entry->HotspotY, sizeof(uint16_t)); - cur_data.append(cursor_file.substr(cursor_entry->ImageOffset, cursor_entry->SizeInBytes)); - - res_.add_resource(cur_data, pe_resource_viewer::resource_cursor, new_entry, resource_directory::entry_finder(group.Number), language, codepage, timestamp); - } - - if(info) - info->Count += cur_header->Count; //Increase cursor count, if we're adding cursor to existing group - - { - //Add or replace cursor group data entry - res_.add_resource(cursor_group_data, pe_resource_viewer::resource_cursor_group, new_cursor_group_entry, finder, language, codepage, timestamp); - } -} - -//Adds icon(s) from icon file data -//timestamp will be used for directories that will be added -//If icon group with name "icon_group_name" or ID "icon_group_id" already exists, it will be appended with new icon(s) -//(Codepage of icon group and icons will not be changed in this case) -//icon_place_mode determines, how new icon(s) will be placed -void resource_cursor_icon_writer::add_icon(const std::string& icon_file, const std::wstring& icon_group_name, uint32_t language, icon_place_mode mode, uint32_t codepage, uint32_t timestamp) -{ - resource_directory_entry new_icon_group_entry; - new_icon_group_entry.set_name(icon_group_name); - std::auto_ptr data_info; - - try - { - data_info.reset(new resource_data_info(res_.get_resource_data_by_name(language, pe_resource_viewer::resource_icon_group, icon_group_name))); - } - catch(const pe_exception&) //Entry not found - { - } - - add_icon(icon_file, data_info.get(), new_icon_group_entry, resource_directory::entry_finder(icon_group_name), language, mode, codepage, timestamp); -} - -void resource_cursor_icon_writer::add_icon(const std::string& icon_file, uint32_t icon_group_id, uint32_t language, icon_place_mode mode, uint32_t codepage, uint32_t timestamp) -{ - resource_directory_entry new_icon_group_entry; - new_icon_group_entry.set_id(icon_group_id); - std::auto_ptr data_info; - - try - { - data_info.reset(new resource_data_info(res_.get_resource_data_by_id(language, pe_resource_viewer::resource_icon_group, icon_group_id))); - } - catch(const pe_exception&) //Entry not found - { - } - - add_icon(icon_file, data_info.get(), new_icon_group_entry, resource_directory::entry_finder(icon_group_id), language, mode, codepage, timestamp); -} - -//Adds cursor(s) from cursor file data -//timestamp will be used for directories that will be added -//If cursor group with name "cursor_group_name" or ID "cursor_group_id" already exists, it will be appended with new cursor(s) -//(Codepage of cursor group and cursors will not be changed in this case) -//icon_place_mode determines, how new cursor(s) will be placed -void resource_cursor_icon_writer::add_cursor(const std::string& cursor_file, const std::wstring& cursor_group_name, uint32_t language, icon_place_mode mode, uint32_t codepage, uint32_t timestamp) -{ - resource_directory_entry new_cursor_group_entry; - new_cursor_group_entry.set_name(cursor_group_name); - std::auto_ptr data_info; - - try - { - data_info.reset(new resource_data_info(res_.get_resource_data_by_name(language, pe_resource_viewer::resource_cursor_group, cursor_group_name))); - } - catch(const pe_exception&) //Entry not found - { - } - - add_cursor(cursor_file, data_info.get(), new_cursor_group_entry, resource_directory::entry_finder(cursor_group_name), language, mode, codepage, timestamp); -} - -void resource_cursor_icon_writer::add_cursor(const std::string& cursor_file, uint32_t cursor_group_id, uint32_t language, icon_place_mode mode, uint32_t codepage, uint32_t timestamp) -{ - resource_directory_entry new_cursor_group_entry; - new_cursor_group_entry.set_id(cursor_group_id); - std::auto_ptr data_info; - - try - { - data_info.reset(new resource_data_info(res_.get_resource_data_by_id(language, pe_resource_viewer::resource_cursor_group, cursor_group_id))); - } - catch(const pe_exception&) //Entry not found - { - } - - add_cursor(cursor_file, data_info.get(), new_cursor_group_entry, resource_directory::entry_finder(cursor_group_id), language, mode, codepage, timestamp); -} - -//Remove icon group helper -void resource_cursor_icon_writer::remove_icons_from_icon_group(const std::string& icon_group_data, uint32_t language) -{ - //Check resource data size - if(icon_group_data.length() < sizeof(ico_header)) - throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon); - - //Get icon header - const ico_header* info = reinterpret_cast(icon_group_data.data()); - - uint16_t icon_count = info->Count; - - //Check resource data size - if(icon_group_data.length() < sizeof(ico_header) + icon_count * sizeof(icon_group)) - throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon); - - //Remove icon data - for(uint16_t i = 0; i != icon_count; ++i) - { - const icon_group* group = reinterpret_cast(icon_group_data.data() + sizeof(ico_header) + i * sizeof(icon_group)); - res_.remove_resource(pe_resource_viewer::resource_icon, group->Number, language); - } -} - -//Remove cursor group helper -void resource_cursor_icon_writer::remove_cursors_from_cursor_group(const std::string& cursor_group_data, uint32_t language) -{ - //Check resource data size - if(cursor_group_data.length() < sizeof(cursor_header)) - throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor); - - //Get icon header - const cursor_header* info = reinterpret_cast(cursor_group_data.data()); - - uint16_t cursor_count = info->Count; - - //Check resource data size - if(cursor_group_data.length() < sizeof(cursor_header) + cursor_count * sizeof(cursor_group)) - throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor); - - //Remove icon data - for(uint16_t i = 0; i != cursor_count; ++i) - { - const icon_group* group = reinterpret_cast(cursor_group_data.data() + sizeof(cursor_header) + i * sizeof(cursor_group)); - res_.remove_resource(pe_resource_viewer::resource_cursor, group->Number, language); - } -} - -//Removes cursor group and all its cursors by name/ID and language -bool resource_cursor_icon_writer::remove_cursor_group(const std::wstring& cursor_group_name, uint32_t language) -{ - //Get resource by name and language - const std::string data = res_.get_resource_data_by_name(language, pe_resource_viewer::resource_cursor_group, cursor_group_name).get_data(); - remove_cursors_from_cursor_group(data, language); - return res_.remove_resource(pe_resource_viewer::resource_cursor_group, cursor_group_name, language); -} - -//Removes cursor group and all its cursors by name/ID and language -bool resource_cursor_icon_writer::remove_cursor_group(uint32_t cursor_group_id, uint32_t language) -{ - //Get resource by name and language - const std::string data = res_.get_resource_data_by_id(language, pe_resource_viewer::resource_cursor_group, cursor_group_id).get_data(); - remove_cursors_from_cursor_group(data, language); - return res_.remove_resource(pe_resource_viewer::resource_cursor_group, cursor_group_id, language); -} - -//Removes icon group and all its icons by name/ID and language -bool resource_cursor_icon_writer::remove_icon_group(const std::wstring& icon_group_name, uint32_t language) -{ - //Get resource by name and language - const std::string data = res_.get_resource_data_by_name(language, pe_resource_viewer::resource_icon_group, icon_group_name).get_data(); - remove_icons_from_icon_group(data, language); - return res_.remove_resource(pe_resource_viewer::resource_icon_group, icon_group_name, language); -} - -//Removes icon group and all its icons by name/ID and language -bool resource_cursor_icon_writer::remove_icon_group(uint32_t icon_group_id, uint32_t language) -{ - //Get resource by name and language - const std::string data = res_.get_resource_data_by_id(language, pe_resource_viewer::resource_icon_group, icon_group_id).get_data(); - remove_icons_from_icon_group(data, language); - return res_.remove_resource(pe_resource_viewer::resource_icon_group, icon_group_id, language); -} -} diff --git a/drivers/pe_bliss/resource_cursor_icon_writer.h b/drivers/pe_bliss/resource_cursor_icon_writer.h deleted file mode 100644 index 2503dd7d0e..0000000000 --- a/drivers/pe_bliss/resource_cursor_icon_writer.h +++ /dev/null @@ -1,73 +0,0 @@ -#pragma once -#include -#include -#include "stdint_defs.h" -#include "pe_resource_manager.h" - -namespace pe_bliss -{ -class pe_resource_manager; - -class resource_cursor_icon_writer -{ -public: - //Determines, how new icon(s) or cursor(s) will be placed - enum icon_place_mode - { - icon_place_after_max_icon_id, //Icon(s) will be placed after all existing - icon_place_free_ids //New icon(s) will take all free IDs between existing icons - }; - -public: - resource_cursor_icon_writer(pe_resource_manager& res); - - //Removes icon group and all its icons by name/ID and language - bool remove_icon_group(const std::wstring& icon_group_name, uint32_t language); - bool remove_icon_group(uint32_t icon_group_id, uint32_t language); - - //Adds icon(s) from icon file data - //timestamp will be used for directories that will be added - //If icon group with name "icon_group_name" or ID "icon_group_id" already exists, it will be appended with new icon(s) - //(Codepage of icon group and icons will not be changed in this case) - //icon_place_mode determines, how new icon(s) will be placed - void add_icon(const std::string& icon_file, - const std::wstring& icon_group_name, - uint32_t language, icon_place_mode mode = icon_place_after_max_icon_id, - uint32_t codepage = 0, uint32_t timestamp = 0); - - void add_icon(const std::string& icon_file, - uint32_t icon_group_id, - uint32_t language, icon_place_mode mode = icon_place_after_max_icon_id, - uint32_t codepage = 0, uint32_t timestamp = 0); - - //Removes cursor group and all its cursors by name/ID and language - bool remove_cursor_group(const std::wstring& cursor_group_name, uint32_t language); - bool remove_cursor_group(uint32_t cursor_group_id, uint32_t language); - - //Adds cursor(s) from cursor file data - //timestamp will be used for directories that will be added - //If cursor group with name "cursor_group_name" or ID "cursor_group_id" already exists, it will be appended with new cursor(s) - //(Codepage of cursor group and cursors will not be changed in this case) - //icon_place_mode determines, how new cursor(s) will be placed - void add_cursor(const std::string& cursor_file, const std::wstring& cursor_group_name, uint32_t language, icon_place_mode mode = icon_place_after_max_icon_id, uint32_t codepage = 0, uint32_t timestamp = 0); - void add_cursor(const std::string& cursor_file, uint32_t cursor_group_id, uint32_t language, icon_place_mode mode = icon_place_after_max_icon_id, uint32_t codepage = 0, uint32_t timestamp = 0); - -private: - pe_resource_manager& res_; - - //Add icon helper - void add_icon(const std::string& icon_file, const resource_data_info* group_icon_info /* or zero */, resource_directory_entry& new_icon_group_entry, const resource_directory::entry_finder& finder, uint32_t language, icon_place_mode mode, uint32_t codepage, uint32_t timestamp); - - //Remove icon group helper - void remove_icons_from_icon_group(const std::string& icon_group_data, uint32_t language); - - //Add cursor helper - void add_cursor(const std::string& cursor_file, const resource_data_info* group_cursor_info /* or zero */, resource_directory_entry& new_cursor_group_entry, const resource_directory::entry_finder& finder, uint32_t language, icon_place_mode mode, uint32_t codepage, uint32_t timestamp); - - //Remove cursor group helper - void remove_cursors_from_cursor_group(const std::string& cursor_group_data, uint32_t language); - - //Returns free icon or cursor ID list depending on icon_place_mode - const std::vector get_icon_or_cursor_free_id_list(pe_resource_manager::resource_type type, icon_place_mode mode, uint32_t count); -}; -} diff --git a/drivers/pe_bliss/resource_data_info.cpp b/drivers/pe_bliss/resource_data_info.cpp deleted file mode 100644 index bc7b3abd7d..0000000000 --- a/drivers/pe_bliss/resource_data_info.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "resource_data_info.h" -#include "pe_resource_viewer.h" - -namespace pe_bliss -{ -//Default constructor -resource_data_info::resource_data_info(const std::string& data, uint32_t codepage) - :data_(data), codepage_(codepage) -{} - -//Constructor from data -resource_data_info::resource_data_info(const resource_data_entry& data) - :data_(data.get_data()), codepage_(data.get_codepage()) -{} - -//Returns resource data -const std::string& resource_data_info::get_data() const -{ - return data_; -} - -//Returns resource codepage -uint32_t resource_data_info::get_codepage() const -{ - return codepage_; -} -} diff --git a/drivers/pe_bliss/resource_data_info.h b/drivers/pe_bliss/resource_data_info.h deleted file mode 100644 index 65953e708e..0000000000 --- a/drivers/pe_bliss/resource_data_info.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once -#include -#include "stdint_defs.h" - -namespace pe_bliss -{ -class resource_data_entry; - -//Class representing resource data -class resource_data_info -{ -public: - //Constructor from data - resource_data_info(const std::string& data, uint32_t codepage); - //Constructor from data - explicit resource_data_info(const resource_data_entry& data); - - //Returns resource data - const std::string& get_data() const; - //Returns resource codepage - uint32_t get_codepage() const; - -private: - std::string data_; - uint32_t codepage_; -}; -} diff --git a/drivers/pe_bliss/resource_internal.h b/drivers/pe_bliss/resource_internal.h deleted file mode 100644 index fd5ff95248..0000000000 --- a/drivers/pe_bliss/resource_internal.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#define U16TEXT(t) reinterpret_cast( t ) - -#define StringFileInfo U16TEXT("S\0t\0r\0i\0n\0g\0F\0i\0l\0e\0I\0n\0f\0o\0\0") -#define SizeofStringFileInfo sizeof("S\0t\0r\0i\0n\0g\0F\0i\0l\0e\0I\0n\0f\0o\0\0") -#define VarFileInfo U16TEXT("V\0a\0r\0F\0i\0l\0e\0I\0n\0f\0o\0\0") -#define Translation U16TEXT("T\0r\0a\0n\0s\0l\0a\0t\0i\0o\0n\0\0") - -#define VarFileInfoAligned U16TEXT("V\0a\0r\0F\0i\0l\0e\0I\0n\0f\0o\0\0\0\0") -#define TranslationAligned U16TEXT("T\0r\0a\0n\0s\0l\0a\0t\0i\0o\0n\0\0\0\0") -#define SizeofVarFileInfoAligned sizeof("V\0a\0r\0F\0i\0l\0e\0I\0n\0f\0o\0\0\0\0") -#define SizeofTranslationAligned sizeof("T\0r\0a\0n\0s\0l\0a\0t\0i\0o\0n\0\0\0\0") diff --git a/drivers/pe_bliss/resource_message_list_reader.cpp b/drivers/pe_bliss/resource_message_list_reader.cpp deleted file mode 100644 index ff9a5dd861..0000000000 --- a/drivers/pe_bliss/resource_message_list_reader.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include "resource_message_list_reader.h" -#include "pe_resource_viewer.h" - -namespace pe_bliss -{ -using namespace pe_win; - -resource_message_list_reader::resource_message_list_reader(const pe_resource_viewer& res) - :res_(res) -{} - -//Helper function of parsing message list table -const resource_message_list resource_message_list_reader::parse_message_list(const std::string& resource_data) -{ - resource_message_list ret; - - //Check resource data length - if(resource_data.length() < sizeof(message_resource_data)) - throw pe_exception("Incorrect resource message table", pe_exception::resource_incorrect_message_table); - - const message_resource_data* message_data = reinterpret_cast(resource_data.data()); - - //Check resource data length more carefully and some possible overflows - if(message_data->NumberOfBlocks >= pe_utils::max_dword / sizeof(message_resource_block) - || !pe_utils::is_sum_safe(message_data->NumberOfBlocks * sizeof(message_resource_block), sizeof(message_resource_data)) - || resource_data.length() < message_data->NumberOfBlocks * sizeof(message_resource_block) + sizeof(message_resource_data)) - throw pe_exception("Incorrect resource message table", pe_exception::resource_incorrect_message_table); - - //Iterate over all message resource blocks - for(unsigned long i = 0; i != message_data->NumberOfBlocks; ++i) - { - //Get block - const message_resource_block* block = - reinterpret_cast(resource_data.data() + sizeof(message_resource_data) - sizeof(message_resource_block) + sizeof(message_resource_block) * i); - - //Check resource data length and IDs - if(resource_data.length() < block->OffsetToEntries || block->LowId > block->HighId) - throw pe_exception("Incorrect resource message table", pe_exception::resource_incorrect_message_table); - - unsigned long current_pos = 0; - static const unsigned long size_of_entry_headers = 4; - //List all message resource entries in block - for(uint32_t curr_id = block->LowId; curr_id <= block->HighId; curr_id++) - { - //Check resource data length and some possible overflows - if(!pe_utils::is_sum_safe(block->OffsetToEntries, current_pos) - || !pe_utils::is_sum_safe(block->OffsetToEntries + current_pos, size_of_entry_headers) - || resource_data.length() < block->OffsetToEntries + current_pos + size_of_entry_headers) - throw pe_exception("Incorrect resource message table", pe_exception::resource_incorrect_message_table); - - //Get entry - const message_resource_entry* entry = reinterpret_cast(resource_data.data() + block->OffsetToEntries + current_pos); - - //Check resource data length and entry length and some possible overflows - if(entry->Length < size_of_entry_headers - || !pe_utils::is_sum_safe(block->OffsetToEntries + current_pos, entry->Length) - || resource_data.length() < block->OffsetToEntries + current_pos + entry->Length - || entry->Length < size_of_entry_headers) - throw pe_exception("Incorrect resource message table", pe_exception::resource_incorrect_message_table); - - if(entry->Flags & message_resource_unicode) - { - //If string is UNICODE - //Check its length - if(entry->Length % 2) - throw pe_exception("Incorrect resource message table", pe_exception::resource_incorrect_message_table); - - //Add ID and string to message table -#ifdef PE_BLISS_WINDOWS - ret.insert(std::make_pair(curr_id, message_table_item( - std::wstring(reinterpret_cast(resource_data.data() + block->OffsetToEntries + current_pos + size_of_entry_headers), - (entry->Length - size_of_entry_headers) / 2) - ))); -#else - ret.insert(std::make_pair(curr_id, message_table_item( - pe_utils::from_ucs2(u16string(reinterpret_cast(resource_data.data() + block->OffsetToEntries + current_pos + size_of_entry_headers), - (entry->Length - size_of_entry_headers) / 2)) - ))); -#endif - } - else - { - //If string is ANSI - //Add ID and string to message table - ret.insert(std::make_pair(curr_id, message_table_item( - std::string(resource_data.data() + block->OffsetToEntries + current_pos + size_of_entry_headers, - entry->Length - size_of_entry_headers) - ))); - } - - //Go to next entry - current_pos += entry->Length; - } - } - - return ret; -} - -//Returns message table data by ID and index in language directory (instead of language) -const resource_message_list resource_message_list_reader::get_message_table_by_id(uint32_t id, uint32_t index) const -{ - return parse_message_list(res_.get_resource_data_by_id(pe_resource_viewer::resource_message_table, id, index).get_data()); -} - -//Returns message table data by ID and language -const resource_message_list resource_message_list_reader::get_message_table_by_id_lang(uint32_t language, uint32_t id) const -{ - return parse_message_list(res_.get_resource_data_by_id(language, pe_resource_viewer::resource_message_table, id).get_data()); -} -} diff --git a/drivers/pe_bliss/resource_message_list_reader.h b/drivers/pe_bliss/resource_message_list_reader.h deleted file mode 100644 index aacd738cc2..0000000000 --- a/drivers/pe_bliss/resource_message_list_reader.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once -#include "message_table.h" - -namespace pe_bliss -{ -class pe_resource_viewer; - -//ID; message_table_item -typedef std::map resource_message_list; - -class resource_message_list_reader -{ -public: - resource_message_list_reader(const pe_resource_viewer& res); - - //Returns message table data by ID and language - const resource_message_list get_message_table_by_id_lang(uint32_t language, uint32_t id) const; - //Returns message table data by ID and index in language directory (instead of language) - const resource_message_list get_message_table_by_id(uint32_t id, uint32_t index = 0) const; - - //Helper function of parsing message list table - //resource_data - raw message table resource data - static const resource_message_list parse_message_list(const std::string& resource_data); - -private: - const pe_resource_viewer& res_; -}; -} diff --git a/drivers/pe_bliss/resource_string_table_reader.cpp b/drivers/pe_bliss/resource_string_table_reader.cpp deleted file mode 100644 index 33eace1935..0000000000 --- a/drivers/pe_bliss/resource_string_table_reader.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "resource_string_table_reader.h" -#include "pe_resource_viewer.h" - -namespace pe_bliss -{ -resource_string_table_reader::resource_string_table_reader(const pe_resource_viewer& res) - :res_(res) -{} - -//Returns string table data by ID and index in language directory (instead of language) -const resource_string_list resource_string_table_reader::get_string_table_by_id(uint32_t id, uint32_t index) const -{ - return parse_string_list(id, res_.get_resource_data_by_id(pe_resource_viewer::resource_string, id, index).get_data()); -} - -//Returns string table data by ID and language -const resource_string_list resource_string_table_reader::get_string_table_by_id_lang(uint32_t language, uint32_t id) const -{ - return parse_string_list(id, res_.get_resource_data_by_id(language, pe_resource_viewer::resource_string, id).get_data()); -} - -//Helper function of parsing string list table -const resource_string_list resource_string_table_reader::parse_string_list(uint32_t id, const std::string& resource_data) -{ - resource_string_list ret; - - //16 is maximum count of strings in a string table - static const unsigned long max_string_list_entries = 16; - unsigned long passed_bytes = 0; - for(unsigned long i = 0; i != max_string_list_entries; ++i) - { - //Check resource data length - if(resource_data.length() < sizeof(uint16_t) + passed_bytes) - throw pe_exception("Incorrect resource string table", pe_exception::resource_incorrect_string_table); - - //Get string length - the first WORD - uint16_t string_length = *reinterpret_cast(resource_data.data() + passed_bytes); - passed_bytes += sizeof(uint16_t); //WORD containing string length - - //Check resource data length again - if(resource_data.length() < string_length + passed_bytes) - throw pe_exception("Incorrect resource string table", pe_exception::resource_incorrect_string_table); - - if(string_length) - { - //Create and save string (UNICODE) -#ifdef PE_BLISS_WINDOWS - ret.insert( - std::make_pair(static_cast(((id - 1) << 4) + i), //ID of string is calculated such way - std::wstring(reinterpret_cast(resource_data.data() + passed_bytes), string_length))); -#else - ret.insert( - std::make_pair(static_cast(((id - 1) << 4) + i), //ID of string is calculated such way - pe_utils::from_ucs2(u16string(reinterpret_cast(resource_data.data() + passed_bytes), string_length)))); -#endif - } - - //Go to next string - passed_bytes += string_length * 2; - } - - return ret; -} - -//Returns string from string table by ID and language -const std::wstring resource_string_table_reader::get_string_by_id_lang(uint32_t language, uint16_t id) const -{ - //List strings by string table id and language - const resource_string_list strings(get_string_table_by_id_lang(language, (id >> 4) + 1)); - resource_string_list::const_iterator it = strings.find(id); //Find string by id - if(it == strings.end()) - throw pe_exception("Resource string not found", pe_exception::resource_string_not_found); - - return (*it).second; -} - -//Returns string from string table by ID and index in language directory (instead of language) -const std::wstring resource_string_table_reader::get_string_by_id(uint16_t id, uint32_t index) const -{ - //List strings by string table id and index - const resource_string_list strings(get_string_table_by_id((id >> 4) + 1, index)); - resource_string_list::const_iterator it = strings.find(id); //Find string by id - if(it == strings.end()) - throw pe_exception("Resource string not found", pe_exception::resource_string_not_found); - - return (*it).second; -} -} diff --git a/drivers/pe_bliss/resource_string_table_reader.h b/drivers/pe_bliss/resource_string_table_reader.h deleted file mode 100644 index 34628ec71c..0000000000 --- a/drivers/pe_bliss/resource_string_table_reader.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once -#include -#include -#include "stdint_defs.h" - -namespace pe_bliss -{ -class pe_resource_viewer; - -//ID; string -typedef std::map resource_string_list; - -class resource_string_table_reader -{ -public: - resource_string_table_reader(const pe_resource_viewer& res); - -public: - //Returns string table data by ID and language - const resource_string_list get_string_table_by_id_lang(uint32_t language, uint32_t id) const; - //Returns string table data by ID and index in language directory (instead of language) - const resource_string_list get_string_table_by_id(uint32_t id, uint32_t index = 0) const; - //Returns string from string table by ID and language - const std::wstring get_string_by_id_lang(uint32_t language, uint16_t id) const; - //Returns string from string table by ID and index in language directory (instead of language) - const std::wstring get_string_by_id(uint16_t id, uint32_t index = 0) const; - -private: - const pe_resource_viewer& res_; - - //Helper function of parsing string list table - //Id of resource is needed to calculate string IDs correctly - //resource_data is raw string table resource data - static const resource_string_list parse_string_list(uint32_t id, const std::string& resource_data); -}; -} diff --git a/drivers/pe_bliss/resource_version_info_reader.cpp b/drivers/pe_bliss/resource_version_info_reader.cpp deleted file mode 100644 index 4a8a2723e6..0000000000 --- a/drivers/pe_bliss/resource_version_info_reader.cpp +++ /dev/null @@ -1,290 +0,0 @@ -#include "resource_version_info_reader.h" -#include "utils.h" -#include "pe_exception.h" -#include "resource_internal.h" -#include "pe_resource_viewer.h" - -namespace pe_bliss -{ -using namespace pe_win; - -//Root version info block key value -const u16string resource_version_info_reader::version_info_key(U16TEXT("V\0S\0_\0V\0E\0R\0S\0I\0O\0N\0_\0I\0N\0F\0O\0\0")); - -resource_version_info_reader::resource_version_info_reader(const pe_resource_viewer& res) - :res_(res) -{} - -//Returns aligned version block value position -uint32_t resource_version_info_reader::get_version_block_value_pos(uint32_t base_pos, const unicode16_t* key) -{ - uint32_t string_length = static_cast(u16string(key).length()); - uint32_t ret = pe_utils::align_up(static_cast(sizeof(uint16_t) * 3 /* headers before Key data */ - + base_pos - + (string_length + 1 /* nullbyte */) * 2), - sizeof(uint32_t)); - - //Check possible overflows - if(ret < base_pos || ret < sizeof(uint16_t) * 3 || ret < (string_length + 1) * 2) - throw_incorrect_version_info(); - - return ret; -} - -//Returns aligned version block first child position -uint32_t resource_version_info_reader::get_version_block_first_child_pos(uint32_t base_pos, uint32_t value_length, const unicode16_t* key) -{ - uint32_t string_length = static_cast(u16string(key).length()); - uint32_t ret = pe_utils::align_up(static_cast(sizeof(uint16_t) * 3 /* headers before Key data */ - + base_pos - + (string_length + 1 /* nullbyte */) * 2), - sizeof(uint32_t)) - + pe_utils::align_up(value_length, sizeof(uint32_t)); - - //Check possible overflows - if(ret < base_pos || ret < value_length || ret < sizeof(uint16_t) * 3 || ret < (string_length + 1) * 2) - throw_incorrect_version_info(); - - return ret; -} - -//Throws an exception (id = resource_incorrect_version_info) -void resource_version_info_reader::throw_incorrect_version_info() -{ - throw pe_exception("Incorrect resource version info", pe_exception::resource_incorrect_version_info); -} - -//Returns full version information: -//file_version_info: versions and file info -//lang_string_values_map: map of version info strings with encodings -//translation_values_map: map of translations -const file_version_info resource_version_info_reader::get_version_info(lang_string_values_map& string_values, translation_values_map& translations, const std::string& resource_data) const -{ - //Fixed file version info - file_version_info ret; - - //Check resource data length - if(resource_data.length() < sizeof(version_info_block)) - throw_incorrect_version_info(); - - //Root version info block - const version_info_block* root_block = reinterpret_cast(resource_data.data()); - - //Check root block key for null-termination and its name - if(!pe_utils::is_null_terminated(root_block->Key, resource_data.length() - sizeof(uint16_t) * 3 /* headers before Key data */) - || version_info_key != reinterpret_cast(root_block->Key)) - throw_incorrect_version_info(); - - //If file has fixed version info - if(root_block->ValueLength) - { - //Get root block value position - uint32_t value_pos = get_version_block_value_pos(0, reinterpret_cast(root_block->Key)); - //Check value length - if(resource_data.length() < value_pos + sizeof(vs_fixedfileinfo)) - throw_incorrect_version_info(); - - //Get VS_FIXEDFILEINFO structure pointer - const vs_fixedfileinfo* file_info = reinterpret_cast(resource_data.data() + value_pos); - //Check its signature and some other fields - if(file_info->dwSignature != vs_ffi_signature || file_info->dwStrucVersion != vs_ffi_strucversion) //Don't check if file_info->dwFileFlagsMask == VS_FFI_FILEFLAGSMASK - throw_incorrect_version_info(); - - //Save fixed version info - ret = file_version_info(*file_info); - } - - //Iterate over child elements of VS_VERSIONINFO (StringFileInfo or VarFileInfo) - for(uint32_t child_pos = get_version_block_first_child_pos(0, root_block->ValueLength, reinterpret_cast(root_block->Key)); - child_pos < root_block->Length;) - { - //Check block position - if(!pe_utils::is_sum_safe(child_pos, sizeof(version_info_block)) - || resource_data.length() < child_pos + sizeof(version_info_block)) - throw_incorrect_version_info(); - - //Get VERSION_INFO_BLOCK structure pointer - const version_info_block* block = reinterpret_cast(resource_data.data() + child_pos); - - //Check its length - if(block->Length == 0) - throw_incorrect_version_info(); - - //Check block key for null-termination - if(!pe_utils::is_null_terminated(block->Key, resource_data.length() - child_pos - sizeof(uint16_t) * 3 /* headers before Key data */)) - throw_incorrect_version_info(); - - u16string info_type(reinterpret_cast(block->Key)); - //If we encountered StringFileInfo... - if(info_type == StringFileInfo) - { - //Enumerate all string tables - for(uint32_t string_table_pos = get_version_block_first_child_pos(child_pos, block->ValueLength, reinterpret_cast(block->Key)); - string_table_pos - child_pos < block->Length;) - { - //Check string table block position - if(resource_data.length() < string_table_pos + sizeof(version_info_block)) - throw_incorrect_version_info(); - - //Get VERSION_INFO_BLOCK structure pointer for string table - const version_info_block* string_table = reinterpret_cast(resource_data.data() + string_table_pos); - - //Check its length - if(string_table->Length == 0) - throw_incorrect_version_info(); - - //Check string table key for null-termination - if(!pe_utils::is_null_terminated(string_table->Key, resource_data.length() - string_table_pos - sizeof(uint16_t) * 3 /* headers before Key data */)) - throw_incorrect_version_info(); - - string_values_map new_values; - - //Enumerate all strings in the string table - for(uint32_t string_pos = get_version_block_first_child_pos(string_table_pos, string_table->ValueLength, reinterpret_cast(string_table->Key)); - string_pos - string_table_pos < string_table->Length;) - { - //Check string block position - if(resource_data.length() < string_pos + sizeof(version_info_block)) - throw_incorrect_version_info(); - - //Get VERSION_INFO_BLOCK structure pointer for string block - const version_info_block* string_block = reinterpret_cast(resource_data.data() + string_pos); - - //Check its length - if(string_block->Length == 0) - throw_incorrect_version_info(); - - //Check string block key for null-termination - if(!pe_utils::is_null_terminated(string_block->Key, resource_data.length() - string_pos - sizeof(uint16_t) * 3 /* headers before Key data */)) - throw_incorrect_version_info(); - - u16string data; - //If string block has value - if(string_block->ValueLength != 0) - { - //Get value position - uint32_t value_pos = get_version_block_value_pos(string_pos, reinterpret_cast(string_block->Key)); - //Check it - if(resource_data.length() < value_pos + string_block->ValueLength) - throw pe_exception("Incorrect resource version info", pe_exception::resource_incorrect_version_info); - - //Get UNICODE string value - data = u16string(reinterpret_cast(resource_data.data() + value_pos), string_block->ValueLength); - pe_utils::strip_nullbytes(data); - } - - //Save name-value pair -#ifdef PE_BLISS_WINDOWS - new_values.insert(std::make_pair(reinterpret_cast(string_block->Key), data)); -#else - new_values.insert(std::make_pair(pe_utils::from_ucs2(reinterpret_cast(string_block->Key)), - pe_utils::from_ucs2(data))); -#endif - - //Navigate to next string block - string_pos += pe_utils::align_up(string_block->Length, sizeof(uint32_t)); - } - -#ifdef PE_BLISS_WINDOWS - string_values.insert(std::make_pair(reinterpret_cast(string_table->Key), new_values)); -#else - string_values.insert(std::make_pair(pe_utils::from_ucs2(reinterpret_cast(string_table->Key)), new_values)); -#endif - - //Navigate to next string table block - string_table_pos += pe_utils::align_up(string_table->Length, sizeof(uint32_t)); - } - } - else if(info_type == VarFileInfo) //If we encountered VarFileInfo - { - for(uint32_t var_table_pos = get_version_block_first_child_pos(child_pos, block->ValueLength, reinterpret_cast(block->Key)); - var_table_pos - child_pos < block->Length;) - { - //Check var block position - if(resource_data.length() < var_table_pos + sizeof(version_info_block)) - throw_incorrect_version_info(); - - //Get VERSION_INFO_BLOCK structure pointer for var block - const version_info_block* var_table = reinterpret_cast(resource_data.data() + var_table_pos); - - //Check its length - if(var_table->Length == 0) - throw_incorrect_version_info(); - - //Check its key for null-termination - if(!pe_utils::is_null_terminated(var_table->Key, resource_data.length() - var_table_pos - sizeof(uint16_t) * 3 /* headers before Key data */)) - throw_incorrect_version_info(); - - //If block is "Translation" (actually, there's no other types possible in VarFileInfo) and it has value - if(u16string(reinterpret_cast(var_table->Key)) == Translation && var_table->ValueLength) - { - //Get its value position - uint32_t value_pos = get_version_block_value_pos(var_table_pos, reinterpret_cast(var_table->Key)); - //Cherck value length - if(resource_data.length() < value_pos + var_table->ValueLength) - throw_incorrect_version_info(); - - //Get list of translations: pairs of LANGUAGE_ID - CODEPAGE_ID - for(unsigned long i = 0; i < var_table->ValueLength; i += sizeof(uint16_t) * 2) - { - //Pair of WORDs - uint16_t lang_id = *reinterpret_cast(resource_data.data() + value_pos + i); - uint16_t codepage_id = *reinterpret_cast(resource_data.data() + value_pos + sizeof(uint16_t) + i); - //Save translation - translations.insert(std::make_pair(lang_id, codepage_id)); - } - } - - //Navigate to next var block - var_table_pos += pe_utils::align_up(var_table->Length, sizeof(uint32_t)); - } - } - else - { - throw_incorrect_version_info(); - } - - //Navigate to next element in root block - child_pos += pe_utils::align_up(block->Length, sizeof(uint32_t)); - } - - return ret; -} - -//Returns full version information: -//file_version info: versions and file info -//lang_string_values_map: map of version info strings with encodings -//translation_values_map: map of translations -const file_version_info resource_version_info_reader::get_version_info_by_lang(lang_string_values_map& string_values, translation_values_map& translations, uint32_t language) const -{ - const std::string& resource_data = res_.get_root_directory() //Type directory - .entry_by_id(pe_resource_viewer::resource_version) - .get_resource_directory() //Name/ID directory - .entry_by_id(1) - .get_resource_directory() //Language directory - .entry_by_id(language) - .get_data_entry() //Data directory - .get_data(); - - return get_version_info(string_values, translations, resource_data); -} - -//Returns full version information: -//file_version_info: versions and file info -//lang_string_values_map: map of version info strings with encodings -//translation_values_map: map of translations -const file_version_info resource_version_info_reader::get_version_info(lang_string_values_map& string_values, translation_values_map& translations, uint32_t index) const -{ - const resource_directory::entry_list& entries = res_.get_root_directory() //Type directory - .entry_by_id(pe_resource_viewer::resource_version) - .get_resource_directory() //Name/ID directory - .entry_by_id(1) - .get_resource_directory() //Language directory - .get_entry_list(); - - if(entries.size() <= index) - throw pe_exception("Resource data entry not found", pe_exception::resource_data_entry_not_found); - - return get_version_info(string_values, translations, entries.at(index).get_data_entry().get_data()); //Data directory -} -} diff --git a/drivers/pe_bliss/resource_version_info_reader.h b/drivers/pe_bliss/resource_version_info_reader.h deleted file mode 100644 index 4a14ddc4a5..0000000000 --- a/drivers/pe_bliss/resource_version_info_reader.h +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once -#include -#include "file_version_info.h" -#include "pe_structures.h" -#include "version_info_types.h" - -namespace pe_bliss -{ -class pe_resource_viewer; - -class resource_version_info_reader -{ -public: //VERSION INFO - resource_version_info_reader(const pe_resource_viewer& res); - - //Returns full version information: - //file_version_info: versions and file info - //lang_lang_string_values_map: map of version info strings with encodings with encodings - //translation_values_map: map of translations - const file_version_info get_version_info(lang_string_values_map& string_values, translation_values_map& translations, uint32_t index = 0) const; - const file_version_info get_version_info_by_lang(lang_string_values_map& string_values, translation_values_map& translations, uint32_t language) const; - -public: - //L"VS_VERSION_INFO" key of root version info block - static const u16string version_info_key; - -private: - const pe_resource_viewer& res_; - - //VERSION INFO helpers - //Returns aligned version block value position - static uint32_t get_version_block_value_pos(uint32_t base_pos, const unicode16_t* key); - - //Returns aligned version block first child position - static uint32_t get_version_block_first_child_pos(uint32_t base_pos, uint32_t value_length, const unicode16_t* key); - - //Returns full version information: - //file_version_info: versions and file info - //lang_string_values_map: map of version info strings with encodings - //translation_values_map: map of translations - const file_version_info get_version_info(lang_string_values_map& string_values, translation_values_map& translations, const std::string& resource_data) const; - - //Throws an exception (id = resource_incorrect_version_info) - static void throw_incorrect_version_info(); -}; -} diff --git a/drivers/pe_bliss/resource_version_info_writer.cpp b/drivers/pe_bliss/resource_version_info_writer.cpp deleted file mode 100644 index 34f21c4a37..0000000000 --- a/drivers/pe_bliss/resource_version_info_writer.cpp +++ /dev/null @@ -1,262 +0,0 @@ -#include -#include "resource_version_info_writer.h" -#include "pe_structures.h" -#include "resource_internal.h" -#include "utils.h" -#include "pe_resource_manager.h" -#include "resource_version_info_reader.h" - -namespace pe_bliss -{ -using namespace pe_win; - -resource_version_info_writer::resource_version_info_writer(pe_resource_manager& res) - :res_(res) -{} - -//Sets/replaces full version information: -//file_version_info: versions and file info -//lang_string_values_map: map of version info strings with encodings -//translation_values_map: map of translations -void resource_version_info_writer::set_version_info(const file_version_info& file_info, - const lang_string_values_map& string_values, - const translation_values_map& translations, - uint32_t language, - uint32_t codepage, - uint32_t timestamp) -{ - std::string version_data; - - //Calculate total size of version resource data - uint32_t total_version_info_length = - static_cast(sizeof(version_info_block) - sizeof(uint16_t) + sizeof(uint16_t) /* pading */ - + (resource_version_info_reader::version_info_key.length() + 1) * 2 - + sizeof(vs_fixedfileinfo)); - - //If we have any strings values - if(!string_values.empty()) - { - total_version_info_length += sizeof(version_info_block) - sizeof(uint16_t); //StringFileInfo block - total_version_info_length += SizeofStringFileInfo; //Name of block (key) - - //Add required size for version strings - for(lang_string_values_map::const_iterator table_it = string_values.begin(); table_it != string_values.end(); ++table_it) - { - total_version_info_length += pe_utils::align_up(static_cast(sizeof(uint16_t) * 3 + ((*table_it).first.length() + 1) * 2), sizeof(uint32_t)); //Name of child block and block size (key of string table block) - - const string_values_map& values = (*table_it).second; - for(string_values_map::const_iterator it = values.begin(); it != values.end(); ++it) - { - total_version_info_length += pe_utils::align_up(static_cast(sizeof(uint16_t) * 3 + ((*it).first.length() + 1) * 2), sizeof(uint32_t)); - total_version_info_length += pe_utils::align_up(static_cast(((*it).second.length() + 1) * 2), sizeof(uint32_t)); - } - } - } - - //If we have translations - if(!translations.empty()) - { - total_version_info_length += (sizeof(version_info_block) - sizeof(uint16_t)) * 2; //VarFileInfo and Translation blocks - total_version_info_length += SizeofVarFileInfoAligned; //DWORD-aligned VarFileInfo block name - total_version_info_length += SizeofTranslationAligned; //DWORD-aligned Translation block name - total_version_info_length += static_cast(translations.size() * sizeof(uint16_t) * 2); - } - - //Resize version data buffer - version_data.resize(total_version_info_length); - - //Create root version block - version_info_block root_block = {0}; - root_block.ValueLength = sizeof(vs_fixedfileinfo); - root_block.Length = static_cast(total_version_info_length); - - //Fill fixed file info - vs_fixedfileinfo fixed_info = {0}; - fixed_info.dwFileDateLS = file_info.get_file_date_ls(); - fixed_info.dwFileDateMS = file_info.get_file_date_ms(); - fixed_info.dwFileFlags = file_info.get_file_flags(); - fixed_info.dwFileFlagsMask = vs_ffi_fileflagsmask; - fixed_info.dwFileOS = file_info.get_file_os_raw(); - fixed_info.dwFileSubtype = file_info.get_file_subtype(); - fixed_info.dwFileType = file_info.get_file_type_raw(); - fixed_info.dwFileVersionLS = file_info.get_file_version_ls(); - fixed_info.dwFileVersionMS = file_info.get_file_version_ms(); - fixed_info.dwSignature = vs_ffi_signature; - fixed_info.dwStrucVersion = vs_ffi_strucversion; - fixed_info.dwProductVersionLS = file_info.get_product_version_ls(); - fixed_info.dwProductVersionMS = file_info.get_product_version_ms(); - - //Write root block and fixed file info to buffer - uint32_t data_ptr = 0; - memcpy(&version_data[data_ptr], &root_block, sizeof(version_info_block) - sizeof(uint16_t)); - data_ptr += sizeof(version_info_block) - sizeof(uint16_t); - memcpy(&version_data[data_ptr], resource_version_info_reader::version_info_key.c_str(), (resource_version_info_reader::version_info_key.length() + 1) * sizeof(uint16_t)); - data_ptr += static_cast((resource_version_info_reader::version_info_key.length() + 1) * sizeof(uint16_t)); - memset(&version_data[data_ptr], 0, sizeof(uint16_t)); - data_ptr += sizeof(uint16_t); - memcpy(&version_data[data_ptr], &fixed_info, sizeof(fixed_info)); - data_ptr += sizeof(fixed_info); - - //Write string values, if any - if(!string_values.empty()) - { - //Create string file info root block - version_info_block string_file_info_block = {0}; - string_file_info_block.Type = 1; //Block type is string - memcpy(&version_data[data_ptr], &string_file_info_block, sizeof(version_info_block) - sizeof(uint16_t)); - //We will calculate its length later - version_info_block* string_file_info_block_ptr = reinterpret_cast(&version_data[data_ptr]); - data_ptr += sizeof(version_info_block) - sizeof(uint16_t); - - uint32_t old_ptr1 = data_ptr; //Used to calculate string file info block length later - memcpy(&version_data[data_ptr], StringFileInfo, SizeofStringFileInfo); //Write block name - data_ptr += SizeofStringFileInfo; - - //Create string table root block (child of string file info) - version_info_block string_table_block = {0}; - string_table_block.Type = 1; //Block type is string - - for(lang_string_values_map::const_iterator table_it = string_values.begin(); table_it != string_values.end(); ++table_it) - { - const string_values_map& values = (*table_it).second; - - memcpy(&version_data[data_ptr], &string_table_block, sizeof(version_info_block) - sizeof(uint16_t)); - //We will calculate its length later - version_info_block* string_table_block_ptr = reinterpret_cast(&version_data[data_ptr]); - data_ptr += sizeof(version_info_block) - sizeof(uint16_t); - - uint32_t old_ptr2 = data_ptr; //Used to calculate string table block length later - uint32_t lang_key_length = static_cast(((*table_it).first.length() + 1) * sizeof(uint16_t)); - -#ifdef PE_BLISS_WINDOWS - memcpy(&version_data[data_ptr], (*table_it).first.c_str(), lang_key_length); //Write block key -#else - { - u16string str(pe_utils::to_ucs2((*table_it).first)); - memcpy(&version_data[data_ptr], str.c_str(), lang_key_length); //Write block key - } -#endif - - data_ptr += lang_key_length; - //Align key if necessary - if((sizeof(uint16_t) * 3 + lang_key_length) % sizeof(uint32_t)) - { - memset(&version_data[data_ptr], 0, sizeof(uint16_t)); - data_ptr += sizeof(uint16_t); - } - - //Create string block (child of string table block) - version_info_block string_block = {0}; - string_block.Type = 1; //Block type is string - for(string_values_map::const_iterator it = values.begin(); it != values.end(); ++it) - { - //Calculate value length and key length of string block - string_block.ValueLength = static_cast((*it).second.length() + 1); - uint32_t key_length = static_cast(((*it).first.length() + 1) * sizeof(uint16_t)); - //Calculate length of block - string_block.Length = static_cast(pe_utils::align_up(sizeof(uint16_t) * 3 + key_length, sizeof(uint32_t)) + string_block.ValueLength * sizeof(uint16_t)); - - //Write string block - memcpy(&version_data[data_ptr], &string_block, sizeof(version_info_block) - sizeof(uint16_t)); - data_ptr += sizeof(version_info_block) - sizeof(uint16_t); - -#ifdef PE_BLISS_WINDOWS - memcpy(&version_data[data_ptr], (*it).first.c_str(), key_length); //Write block key -#else - { - u16string str(pe_utils::to_ucs2((*it).first)); - memcpy(&version_data[data_ptr], str.c_str(), key_length); //Write block key - } -#endif - - data_ptr += key_length; - //Align key if necessary - if((sizeof(uint16_t) * 3 + key_length) % sizeof(uint32_t)) - { - memset(&version_data[data_ptr], 0, sizeof(uint16_t)); - data_ptr += sizeof(uint16_t); - } - - //Write block data (value) -#ifdef PE_BLISS_WINDOWS - memcpy(&version_data[data_ptr], (*it).second.c_str(), string_block.ValueLength * sizeof(uint16_t)); -#else - { - u16string str(pe_utils::to_ucs2((*it).second)); - memcpy(&version_data[data_ptr], str.c_str(), string_block.ValueLength * sizeof(uint16_t)); - } -#endif - - data_ptr += string_block.ValueLength * 2; - //Align data if necessary - if((string_block.ValueLength * 2) % sizeof(uint32_t)) - { - memset(&version_data[data_ptr], 0, sizeof(uint16_t)); - data_ptr += sizeof(uint16_t); - } - } - - //Calculate string table and string file info blocks lengths - string_table_block_ptr->Length = static_cast(data_ptr - old_ptr2 + sizeof(uint16_t) * 3); - } - - string_file_info_block_ptr->Length = static_cast(data_ptr - old_ptr1 + sizeof(uint16_t) * 3); - } - - //If we have transactions - if(!translations.empty()) - { - //Create root var file info block - version_info_block var_file_info_block = {0}; - var_file_info_block.Type = 1; //Type of block is string - //Write block header - memcpy(&version_data[data_ptr], &var_file_info_block, sizeof(version_info_block) - sizeof(uint16_t)); - //We will calculate its length later - version_info_block* var_file_info_block_ptr = reinterpret_cast(&version_data[data_ptr]); - data_ptr += sizeof(version_info_block) - sizeof(uint16_t); - - uint32_t old_ptr1 = data_ptr; //Used to calculate var file info block length later - memcpy(&version_data[data_ptr], VarFileInfoAligned, SizeofVarFileInfoAligned); //Write block key (aligned) - data_ptr += SizeofVarFileInfoAligned; - - //Create root translation block (child of var file info block) - version_info_block translation_block = {0}; - //Write block header - memcpy(&version_data[data_ptr], &translation_block, sizeof(version_info_block) - sizeof(uint16_t)); - //We will calculate its length later - version_info_block* translation_block_ptr = reinterpret_cast(&version_data[data_ptr]); - data_ptr += sizeof(version_info_block) - sizeof(uint16_t); - - uint32_t old_ptr2 = data_ptr; //Used to calculate var file info block length later - memcpy(&version_data[data_ptr], TranslationAligned, SizeofTranslationAligned); //Write block key (aligned) - data_ptr += SizeofTranslationAligned; - - //Calculate translation block value length - translation_block_ptr->ValueLength = static_cast(sizeof(uint16_t) * 2 * translations.size()); - - //Write translation values to block - for(translation_values_map::const_iterator it = translations.begin(); it != translations.end(); ++it) - { - uint16_t lang_id = (*it).first; //Language ID - uint16_t codepage_id = (*it).second; //Codepage ID - memcpy(&version_data[data_ptr], &lang_id, sizeof(lang_id)); - data_ptr += sizeof(lang_id); - memcpy(&version_data[data_ptr], &codepage_id, sizeof(codepage_id)); - data_ptr += sizeof(codepage_id); - } - - //Calculate Translation and VarFileInfo blocks lengths - translation_block_ptr->Length = static_cast(data_ptr - old_ptr2 + sizeof(uint16_t) * 3); - var_file_info_block_ptr->Length = static_cast(data_ptr - old_ptr1 + sizeof(uint16_t) * 3); - } - - //Add/replace version info resource - res_.add_resource(version_data, pe_resource_viewer::resource_version, 1, language, codepage, timestamp); -} - -//Removes version info by language (ID = 1) -bool resource_version_info_writer::remove_version_info(uint32_t language) -{ - return res_.remove_resource(pe_resource_viewer::resource_version, 1, language); -} -} diff --git a/drivers/pe_bliss/resource_version_info_writer.h b/drivers/pe_bliss/resource_version_info_writer.h deleted file mode 100644 index cab7e925ee..0000000000 --- a/drivers/pe_bliss/resource_version_info_writer.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once -#include "version_info_types.h" -#include "file_version_info.h" - -namespace pe_bliss -{ -class pe_resource_manager; - -class resource_version_info_writer -{ -public: - resource_version_info_writer(pe_resource_manager& res); - - //Sets/replaces full version information: - //file_version_info: versions and file info - //lang_string_values_map: map of version info strings with encodings - //translation_values_map: map of translations - void set_version_info(const file_version_info& file_info, - const lang_string_values_map& string_values, - const translation_values_map& translations, - uint32_t language, - uint32_t codepage = 0, - uint32_t timestamp = 0); - - //Removes version info by language (ID = 1) - bool remove_version_info(uint32_t language); - -private: - pe_resource_manager& res_; -}; -} diff --git a/drivers/pe_bliss/stdint_defs.h b/drivers/pe_bliss/stdint_defs.h deleted file mode 100644 index 309cf3d762..0000000000 --- a/drivers/pe_bliss/stdint_defs.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once -#ifdef _MSC_VER -#if _MSC_VER < 1600 -namespace pe_bliss -{ - //stdint.h definitions for MSVC 2008 and earlier, as - //it doesn't have them - typedef signed char int8_t; - typedef short int16_t; - typedef int int32_t; - - typedef unsigned char uint8_t; - typedef unsigned short uint16_t; - typedef unsigned int uint32_t; - - typedef long long int64_t; - typedef unsigned long long uint64_t; -} -#else -#include -#endif -#else -#include -#endif diff --git a/drivers/pe_bliss/utils.cpp b/drivers/pe_bliss/utils.cpp deleted file mode 100644 index 69f013098f..0000000000 --- a/drivers/pe_bliss/utils.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include -#include "utils.h" -#include "pe_exception.h" - -#ifndef PE_BLISS_WINDOWS -#include -#endif - -namespace pe_bliss -{ -const double pe_utils::log_2 = 1.44269504088896340736; //instead of using M_LOG2E - -//Returns stream size -std::streamoff pe_utils::get_file_size(std::istream& file) -{ - //Get old istream offset - std::streamoff old_offset = file.tellg(); - file.seekg(0, std::ios::end); - std::streamoff filesize = file.tellg(); - //Set old istream offset - file.seekg(old_offset); - return filesize; -} - -#ifndef PE_BLISS_WINDOWS -const u16string pe_utils::to_ucs2(const std::wstring& str) -{ - u16string ret; - if(str.empty()) - return ret; - - ret.resize(str.length()); - - iconv_t conv = iconv_open("UCS-2", "WCHAR_T"); - if(conv == reinterpret_cast(-1)) - throw pe_exception("Error opening iconv", pe_exception::encoding_convertion_error); - - size_t inbytesleft = str.length() * sizeof(wchar_t); - size_t outbytesleft = ret.length() * sizeof(unicode16_t); - const wchar_t* in_pos = str.c_str(); - unicode16_t* out_pos = &ret[0]; - - size_t result = iconv(conv, const_cast(reinterpret_cast(&in_pos)), &inbytesleft, reinterpret_cast(&out_pos), &outbytesleft); - iconv_close(conv); - - if(result == static_cast(-1)) - throw pe_exception("Iconv error", pe_exception::encoding_convertion_error); - - return ret; -} - -const std::wstring pe_utils::from_ucs2(const u16string& str) -{ - std::wstring ret; - if(str.empty()) - return ret; - - ret.resize(str.length()); - - iconv_t conv = iconv_open("WCHAR_T", "UCS-2"); - if(conv == reinterpret_cast(-1)) - throw pe_exception("Error opening iconv", pe_exception::encoding_convertion_error); - - size_t inbytesleft = str.length() * sizeof(unicode16_t); - size_t outbytesleft = ret.length() * sizeof(wchar_t); - const unicode16_t* in_pos = str.c_str(); - wchar_t* out_pos = &ret[0]; - - size_t result = iconv(conv, const_cast(reinterpret_cast(&in_pos)), &inbytesleft, reinterpret_cast(&out_pos), &outbytesleft); - iconv_close(conv); - - if(result == static_cast(-1)) - throw pe_exception("Iconv error", pe_exception::encoding_convertion_error); - - return ret; -} -#endif - -bool operator==(const pe_win::guid& guid1, const pe_win::guid& guid2) -{ - return guid1.Data1 == guid2.Data1 - && guid1.Data2 == guid2.Data2 - && guid1.Data3 == guid2.Data3 - && !memcmp(guid1.Data4, guid2.Data4, sizeof(guid1.Data4)); -} -} diff --git a/drivers/pe_bliss/utils.h b/drivers/pe_bliss/utils.h deleted file mode 100644 index c090121595..0000000000 --- a/drivers/pe_bliss/utils.h +++ /dev/null @@ -1,84 +0,0 @@ -#pragma once -#include -#include -#include "stdint_defs.h" -#include "pe_structures.h" - -namespace pe_bliss -{ -class pe_utils -{ -public: - //Returns true if string "data" with maximum length "raw_length" is null-terminated - template - static bool is_null_terminated(const T* data, size_t raw_length) - { - raw_length /= sizeof(T); - for(size_t l = 0; l < raw_length; l++) - { - if(data[l] == static_cast(L'\0')) - return true; - } - - return false; - } - - //Helper template function to strip nullbytes in the end of string - template - static void strip_nullbytes(std::basic_string& str) - { - while(!*(str.end() - 1) && !str.empty()) - str.erase(str.length() - 1); - } - - //Helper function to determine if number is power of 2 - template - static inline bool is_power_of_2(T x) - { - return !(x & (x - 1)); - } - - //Helper function to align number down - template - static inline T align_down(T x, uint32_t align) - { - return x & ~(static_cast(align) - 1); - } - - //Helper function to align number up - template - static inline T align_up(T x, uint32_t align) - { - return (x & static_cast(align - 1)) ? align_down(x, align) + static_cast(align) : x; - } - - //Returns true if sum of two unsigned integers is safe (no overflow occurs) - static inline bool is_sum_safe(uint32_t a, uint32_t b) - { - return a <= static_cast(-1) - b; - } - - //Two gigabytes value in bytes - static const uint32_t two_gb = 0x80000000; - static const uint32_t max_dword = 0xFFFFFFFF; - static const uint32_t max_word = 0x0000FFFF; - static const double log_2; //instead of using M_LOG2E - - //Returns stream size - static std::streamoff get_file_size(std::istream& file); - -#ifndef PE_BLISS_WINDOWS -public: - static const u16string to_ucs2(const std::wstring& str); - static const std::wstring from_ucs2(const u16string& str); -#endif - -private: - pe_utils(); - pe_utils(pe_utils&); - pe_utils& operator=(const pe_utils&); -}; - -//Windows GUID comparison -bool operator==(const pe_win::guid& guid1, const pe_win::guid& guid2); -} diff --git a/drivers/pe_bliss/version_info_editor.cpp b/drivers/pe_bliss/version_info_editor.cpp deleted file mode 100644 index 9e5c9b7a1c..0000000000 --- a/drivers/pe_bliss/version_info_editor.cpp +++ /dev/null @@ -1,163 +0,0 @@ -#include -#include -#include "version_info_types.h" -#include "version_info_editor.h" -#include "version_info_viewer.h" - -namespace pe_bliss -{ -//Default constructor -//strings - version info strings with charsets -//translations - version info translations map -version_info_editor::version_info_editor(lang_string_values_map& strings, translation_values_map& translations) - :version_info_viewer(strings, translations), - strings_edit_(strings), - translations_edit_(translations) -{} - -//Below functions have parameter translation -//If it's empty, the default language translation will be taken -//If there's no default language translation, the first one will be taken - -//Sets company name -void version_info_editor::set_company_name(const std::wstring& value, const std::wstring& translation) -{ - set_property(L"CompanyName", value, translation); -} - -//Sets file description -void version_info_editor::set_file_description(const std::wstring& value, const std::wstring& translation) -{ - set_property(L"FileDescription", value, translation); -} - -//Sets file version -void version_info_editor::set_file_version(const std::wstring& value, const std::wstring& translation) -{ - set_property(L"FileVersion", value, translation); -} - -//Sets internal file name -void version_info_editor::set_internal_name(const std::wstring& value, const std::wstring& translation) -{ - set_property(L"InternalName", value, translation); -} - -//Sets legal copyright -void version_info_editor::set_legal_copyright(const std::wstring& value, const std::wstring& translation) -{ - set_property(L"LegalCopyright", value, translation); -} - -//Sets original file name -void version_info_editor::set_original_filename(const std::wstring& value, const std::wstring& translation) -{ - set_property(L"OriginalFilename", value, translation); -} - -//Sets product name -void version_info_editor::set_product_name(const std::wstring& value, const std::wstring& translation) -{ - set_property(L"ProductName", value, translation); -} - -//Sets product version -void version_info_editor::set_product_version(const std::wstring& value, const std::wstring& translation) -{ - set_property(L"ProductVersion", value, translation); -} - -//Sets version info property value -//property_name - property name -//value - property value -//If translation does not exist, it will be added -//If property does not exist, it will be added -void version_info_editor::set_property(const std::wstring& property_name, const std::wstring& value, const std::wstring& translation) -{ - lang_string_values_map::iterator it = strings_edit_.begin(); - - if(translation.empty()) - { - //If no translation was specified - it = strings_edit_.find(default_language_translation); //Find default translation table - if(it == strings_edit_.end()) //If there's no default translation table, take the first one - { - it = strings_edit_.begin(); - if(it == strings_edit_.end()) //If there's no any translation table, add default one - { - it = strings_edit_.insert(std::make_pair(default_language_translation, string_values_map())).first; - //Also add it to translations list - add_translation(default_language_translation); - } - } - } - else - { - it = strings_edit_.find(translation); //Find specified translation table - if(it == strings_edit_.end()) //If there's no translation, add it - { - it = strings_edit_.insert(std::make_pair(translation, string_values_map())).first; - //Also add it to translations list - add_translation(translation); - } - } - - //Change value of the required property - ((*it).second)[property_name] = value; -} - -//Adds translation to translation list -void version_info_editor::add_translation(const std::wstring& translation) -{ - std::pair translation_ids(translation_from_string(translation)); - add_translation(translation_ids.first, translation_ids.second); -} - -void version_info_editor::add_translation(uint16_t language_id, uint16_t codepage_id) -{ - std::pair - range(translations_edit_.equal_range(language_id)); - - //If translation already exists - for(translation_values_map::const_iterator it = range.first; it != range.second; ++it) - { - if((*it).second == codepage_id) - return; - } - - translations_edit_.insert(std::make_pair(language_id, codepage_id)); -} - -//Removes translation from translations and strings lists -void version_info_editor::remove_translation(const std::wstring& translation) -{ - std::pair translation_ids(translation_from_string(translation)); - remove_translation(translation_ids.first, translation_ids.second); -} - -void version_info_editor::remove_translation(uint16_t language_id, uint16_t codepage_id) -{ - { - //Erase string table (if exists) - std::wstringstream ss; - ss << std::hex - << std::setw(4) << std::setfill(L'0') << language_id - << std::setw(4) << std::setfill(L'0') << codepage_id; - - strings_edit_.erase(ss.str()); - } - - //Find and erase translation from translations table - std::pair - it_pair = translations_edit_.equal_range(language_id); - - for(translation_values_map::iterator it = it_pair.first; it != it_pair.second; ++it) - { - if((*it).second == codepage_id) - { - translations_edit_.erase(it); - break; - } - } -} -} diff --git a/drivers/pe_bliss/version_info_editor.h b/drivers/pe_bliss/version_info_editor.h deleted file mode 100644 index 9bef6a01b8..0000000000 --- a/drivers/pe_bliss/version_info_editor.h +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once -#include "version_info_types.h" -#include "version_info_viewer.h" - -namespace pe_bliss -{ - //Helper class to read and edit version information - //lang_string_values_map: map of version info strings with encodings - //translation_values_map: map of translations - class version_info_editor : public version_info_viewer - { - public: - //Default constructor - //strings - version info strings with charsets - //translations - version info translations map - version_info_editor(lang_string_values_map& strings, translation_values_map& translations); - - //Below functions have parameter translation - //If it's empty, the default language translation will be taken - //If there's no default language translation, the first one will be taken - - //Sets company name - void set_company_name(const std::wstring& value, const std::wstring& translation = std::wstring()); - //Sets file description - void set_file_description(const std::wstring& value, const std::wstring& translation = std::wstring()); - //Sets file version - void set_file_version(const std::wstring& value, const std::wstring& translation = std::wstring()); - //Sets internal file name - void set_internal_name(const std::wstring& value, const std::wstring& translation = std::wstring()); - //Sets legal copyright - void set_legal_copyright(const std::wstring& value, const std::wstring& translation = std::wstring()); - //Sets original file name - void set_original_filename(const std::wstring& value, const std::wstring& translation = std::wstring()); - //Sets product name - void set_product_name(const std::wstring& value, const std::wstring& translation = std::wstring()); - //Sets product version - void set_product_version(const std::wstring& value, const std::wstring& translation = std::wstring()); - - //Sets version info property value - //property_name - property name - //value - property value - //If translation does not exist, it will be added to strings and translations lists - //If property does not exist, it will be added - void set_property(const std::wstring& property_name, const std::wstring& value, const std::wstring& translation = std::wstring()); - - //Adds translation to translation list - void add_translation(const std::wstring& translation); - void add_translation(uint16_t language_id, uint16_t codepage_id); - - //Removes translation from translations and strings lists - void remove_translation(const std::wstring& translation); - void remove_translation(uint16_t language_id, uint16_t codepage_id); - - private: - lang_string_values_map& strings_edit_; - translation_values_map& translations_edit_; - }; -} diff --git a/drivers/pe_bliss/version_info_types.h b/drivers/pe_bliss/version_info_types.h deleted file mode 100644 index e289f40663..0000000000 --- a/drivers/pe_bliss/version_info_types.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include -#include -#include "stdint_defs.h" - -namespace pe_bliss -{ - //Typedef for version info functions: Name - Value - typedef std::map string_values_map; - //Typedef for version info functions: Language string - String Values Map - //Language String consists of LangID and CharsetID - //E.g. 041904b0 for Russian UNICODE, 040004b0 for Process Default Language UNICODE - typedef std::map lang_string_values_map; - - //Typedef for version info functions: Language - Character Set - typedef std::multimap translation_values_map; -} diff --git a/drivers/pe_bliss/version_info_viewer.cpp b/drivers/pe_bliss/version_info_viewer.cpp deleted file mode 100644 index 7881c4b96d..0000000000 --- a/drivers/pe_bliss/version_info_viewer.cpp +++ /dev/null @@ -1,159 +0,0 @@ -#include -#include -#include "pe_exception.h" -#include "version_info_viewer.h" - -namespace pe_bliss -{ -//Default process language, UNICODE -const std::wstring version_info_viewer::default_language_translation(L"040904b0"); - -//Default constructor -//strings - version info strings with charsets -//translations - version info translations map -version_info_viewer::version_info_viewer(const lang_string_values_map& strings, const translation_values_map& translations) - :strings_(strings), translations_(translations) -{} - -//Below functions have parameter translation -//If it's empty, the default language translation will be taken -//If there's no default language translation, the first one will be taken - -//Returns company name -const std::wstring version_info_viewer::get_company_name(const std::wstring& translation) const -{ - return get_property(L"CompanyName", translation); -} - -//Returns file description -const std::wstring version_info_viewer::get_file_description(const std::wstring& translation) const -{ - return get_property(L"FileDescription", translation); -} - -//Returns file version -const std::wstring version_info_viewer::get_file_version(const std::wstring& translation) const -{ - return get_property(L"FileVersion", translation); -} - -//Returns internal file name -const std::wstring version_info_viewer::get_internal_name(const std::wstring& translation) const -{ - return get_property(L"InternalName", translation); -} - -//Returns legal copyright -const std::wstring version_info_viewer::get_legal_copyright(const std::wstring& translation) const -{ - return get_property(L"LegalCopyright", translation); -} - -//Returns original file name -const std::wstring version_info_viewer::get_original_filename(const std::wstring& translation) const -{ - return get_property(L"OriginalFilename", translation); -} - -//Returns product name -const std::wstring version_info_viewer::get_product_name(const std::wstring& translation) const -{ - return get_property(L"ProductName", translation); -} - -//Returns product version -const std::wstring version_info_viewer::get_product_version(const std::wstring& translation) const -{ - return get_property(L"ProductVersion", translation); -} - -//Returns list of translations in string representation -const version_info_viewer::translation_list version_info_viewer::get_translation_list() const -{ - translation_list ret; - - //Enumerate all translations - for(translation_values_map::const_iterator it = translations_.begin(); it != translations_.end(); ++it) - { - //Create string representation of translation value - std::wstringstream ss; - ss << std::hex - << std::setw(4) << std::setfill(L'0') << (*it).first - << std::setw(4) << std::setfill(L'0') << (*it).second; - - //Save it - ret.push_back(ss.str()); - } - - return ret; -} - -//Returns version info property value -//property_name - required property name -//If throw_if_absent = true, will throw exception if property does not exist -//If throw_if_absent = false, will return empty string if property does not exist -const std::wstring version_info_viewer::get_property(const std::wstring& property_name, const std::wstring& translation, bool throw_if_absent) const -{ - std::wstring ret; - - //If there're no strings - if(strings_.empty()) - { - if(throw_if_absent) - throw pe_exception("Version info string does not exist", pe_exception::version_info_string_does_not_exist); - - return ret; - } - - lang_string_values_map::const_iterator it = strings_.begin(); - - if(translation.empty()) - { - //If no translation was specified - it = strings_.find(default_language_translation); //Find default translation table - if(it == strings_.end()) //If there's no default translation table, take the first one - it = strings_.begin(); - } - else - { - it = strings_.find(translation); //Find specified translation table - if(it == strings_.end()) - { - if(throw_if_absent) - throw pe_exception("Version info string does not exist", pe_exception::version_info_string_does_not_exist); - - return ret; - } - } - - //Find value of the required property - string_values_map::const_iterator str_it = (*it).second.find(property_name); - - if(str_it == (*it).second.end()) - { - if(throw_if_absent) - throw pe_exception("Version info string does not exist", pe_exception::version_info_string_does_not_exist); - - return ret; - } - - ret = (*str_it).second; - - return ret; -} - -//Converts translation HEX-string to pair of language ID and codepage ID -const version_info_viewer::translation_pair version_info_viewer::translation_from_string(const std::wstring& translation) -{ - uint32_t translation_id = 0; - - { - //Convert string to DWORD - std::wstringstream ss; - ss << std::hex << translation; - ss >> translation_id; - } - - return std::make_pair(static_cast(translation_id >> 16), static_cast(translation_id & 0xFFFF)); -} -} diff --git a/drivers/pe_bliss/version_info_viewer.h b/drivers/pe_bliss/version_info_viewer.h deleted file mode 100644 index a4a757bc32..0000000000 --- a/drivers/pe_bliss/version_info_viewer.h +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once -#include -#include -#include -#include "pe_resource_viewer.h" -#include "pe_structures.h" -#include "version_info_types.h" - -namespace pe_bliss -{ -//Helper class to read version information -//lang_string_values_map: map of version info strings with encodings -//translation_values_map: map of translations -class version_info_viewer -{ -public: - //Useful typedefs - typedef std::pair translation_pair; - typedef std::vector translation_list; - -public: - //Default constructor - //strings - version info strings with charsets - //translations - version info translations map - version_info_viewer(const lang_string_values_map& strings, const translation_values_map& translations); - - //Below functions have parameter translation - //If it's empty, the default language translation will be taken - //If there's no default language translation, the first one will be taken - - //Returns company name - const std::wstring get_company_name(const std::wstring& translation = std::wstring()) const; - //Returns file description - const std::wstring get_file_description(const std::wstring& translation = std::wstring()) const; - //Returns file version - const std::wstring get_file_version(const std::wstring& translation = std::wstring()) const; - //Returns internal file name - const std::wstring get_internal_name(const std::wstring& translation = std::wstring()) const; - //Returns legal copyright - const std::wstring get_legal_copyright(const std::wstring& translation = std::wstring()) const; - //Returns original file name - const std::wstring get_original_filename(const std::wstring& translation = std::wstring()) const; - //Returns product name - const std::wstring get_product_name(const std::wstring& translation = std::wstring()) const; - //Returns product version - const std::wstring get_product_version(const std::wstring& translation = std::wstring()) const; - - //Returns list of translations in string representation - const translation_list get_translation_list() const; - - //Returns version info property value - //property_name - required property name - //If throw_if_absent = true, will throw exception if property does not exist - //If throw_if_absent = false, will return empty string if property does not exist - const std::wstring get_property(const std::wstring& property_name, const std::wstring& translation = std::wstring(), bool throw_if_absent = false) const; - - //Converts translation HEX-string to pair of language ID and codepage ID - static const translation_pair translation_from_string(const std::wstring& translation); - -public: - //Default process language, UNICODE - static const std::wstring default_language_translation; - -private: - const lang_string_values_map& strings_; - const translation_values_map& translations_; -}; -} diff --git a/drivers/register_driver_types.cpp b/drivers/register_driver_types.cpp index d832b2c1f5..c4ab54d102 100644 --- a/drivers/register_driver_types.cpp +++ b/drivers/register_driver_types.cpp @@ -252,10 +252,6 @@ void register_driver_types() { _register_etc1_compress_func(); #endif -#ifdef TOOLS_ENABLED - EditorExportPlatformWindows::_add_resrc_func=pe_bliss_add_resrc; -#endif - initialize_chibi(); } -- cgit v1.2.3