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'.
This commit is contained in:
masoud bh 2015-11-09 02:23:58 +03:30
parent 3fcfdfec0a
commit 24f3f43457
103 changed files with 17091 additions and 11 deletions

View File

@ -322,7 +322,7 @@ void Image::set_pallete(const DVector<uint8_t>& p_data) {
DVector<uint8_t>::Write wp = data.write();
unsigned char *dst=wp.ptr() + pal_ofs;
DVector<uint8_t>::Read r = data.read();
DVector<uint8_t>::Read r = p_data.read();
const unsigned char *src=r.ptr();
copymem(dst, src, len);

View File

@ -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")

61
drivers/pe_bliss/README Normal file
View File

@ -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

5
drivers/pe_bliss/SCsub Normal file
View File

@ -0,0 +1,5 @@
Import('env')
env.add_source_files(env.drivers_sources,"*.cpp")
Export('env')

View File

@ -0,0 +1,90 @@
#include <cmath>
#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<unsigned char>(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<unsigned char>(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<unsigned char>(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<double>(byte_count[i]) / total_length;
if(temp > 0.)
entropy += std::abs(temp * (std::log(temp) * pe_utils::log_2));
}
return entropy;
}
}

View File

@ -0,0 +1,30 @@
#pragma once
#include <istream>
#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);
};
}

View File

@ -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;
}
}

View File

@ -0,0 +1,178 @@
#pragma once
#include <string>
#include <map>
#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<typename T>
const std::basic_string<T> get_file_version_string() const
{
return get_version_string<T>(file_version_ms_, file_version_ls_);
}
//Returns product version string
template<typename T>
const std::basic_string<T> get_product_version_string() const
{
return get_version_string<T>(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<typename T>
static const std::basic_string<T> get_version_string(uint32_t ms, uint32_t ls)
{
std::basic_stringstream<T> ss;
ss << (ms >> 16) << static_cast<T>(L'.')
<< (ms & 0xFFFF) << static_cast<T>(L'.')
<< (ls >> 16) << static_cast<T>(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_;
};
}

View File

@ -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;
}
}

View File

@ -0,0 +1,35 @@
#pragma once
#include <string>
#include <map>
#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_;
};
}

1659
drivers/pe_bliss/pe_base.cpp Normal file

File diff suppressed because it is too large Load Diff

523
drivers/pe_bliss/pe_base.h Normal file
View File

@ -0,0 +1,523 @@
#pragma once
#include <string>
#include <vector>
#include <istream>
#include <ostream>
#include <map>
#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<uint32_t, std::string> 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<typename T>
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<const T*>(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<typename T>
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<const T*>(&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<const T*>(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<typename T>
T section_data_from_va(const section& s, uint32_t va, section_data_type datatype = section_data_raw) const
{
return section_data_from_rva<T>(s, va_to_rva(va), datatype);
}
template<typename T>
T section_data_from_va(const section& s, uint64_t va, section_data_type datatype = section_data_raw) const
{
return section_data_from_rva<T>(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<typename T>
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<T>(va_to_rva(va), datatype, include_headers);
}
template<typename T>
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<T>(va_to_rva(va), datatype, include_headers);
}
//Returns section and offset (raw data only) from its start from RVA
const std::pair<uint32_t, const section*> 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);
};
}

View File

@ -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"

View File

@ -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<uint8_t>& 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<uint8_t> 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<uint8_t>::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; i<icon_content.size(); i++)
{
icon[i] = icon_content[i];
}
resource_cursor_icon_writer(res).add_icon(icon, L"MAIN_ICON", 1033);
}
if(image.has_resources())
{
rebuild_resources(image, root, image.section_from_directory(pe_win::image_directory_entry_resource));
} else {
section new_resources;
new_resources.get_raw_data().resize(1);
new_resources.set_name(".rsrc");
new_resources.readable(true);
section& attached_section = image.add_section(new_resources);
rebuild_resources(image, root, attached_section);
}
rebuild_pe(image, p_path);
if(image.has_overlay() && end_of_pe) {
dst=FileAccess::open(p_path,FileAccess::READ_WRITE);
if (dst) {
dst->seek_end();
DVector<uint8_t>::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());
}
}

View File

@ -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<uint8_t>& icon_content);

View File

@ -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"

View File

@ -0,0 +1,290 @@
#include <string.h>
#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<const image_bound_import_descriptor*>(&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<const image_bound_forwarder_ref*>(&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<const image_bound_import_descriptor*>(&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<uint32_t>((*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<uint32_t>((*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<uint16_t>(import.get_module_ref_list().size());
descriptor.OffsetModuleName = static_cast<uint16_t>(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<uint32_t>(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<uint16_t>(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<uint32_t>(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;
}
}

View File

@ -0,0 +1,87 @@
#pragma once
#include <vector>
#include <string>
#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<bound_import_ref> 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> 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);
}

View File

@ -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<char*>(&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<unsigned long>(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<uint32_t>(checksum);
}
}

View File

@ -0,0 +1,9 @@
#pragma once
#include <istream>
#include "stdint_defs.h"
namespace pe_bliss
{
//Calculate checksum of image (performs no checks on PE structures)
uint32_t calculate_checksum(std::istream& file);
}

View File

@ -0,0 +1,844 @@
#include <string.h>
#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<pdb_7_0_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<pdb_2_0_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<misc_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<coff_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<const char*>(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<const char*>(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<const wchar_t*>(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<const unicode16_t*>(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<const char*>(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<image_debug_directory>(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<const image_coff_symbols_header*>(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<const image_symbol*>(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<const char*>(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<const OMFSignature*>(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<const CV_INFO_PDB70*>(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<const CV_INFO_PDB20*>(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<const image_debug_misc*>(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<image_debug_directory>(current_pos, section_data_virtual, true);
}
return ret;
}
}

303
drivers/pe_bliss/pe_debug.h Normal file
View File

@ -0,0 +1,303 @@
#pragma once
#include <vector>
#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_symbol> 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<typename AdvancedInfo>
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> debug_info_list;
//Returns debug information list
const debug_info_list get_debug_information(const pe_base& pe);
}

View File

@ -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;
}
}

View File

@ -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_;
};
}

View File

@ -0,0 +1,165 @@
#include <string.h>
#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<image_cor20_header>(pe.get_directory_rva(image_directory_entry_com_descriptor), section_data_virtual, true));
}
}

View File

@ -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);
}

View File

@ -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_;
}
}

View File

@ -0,0 +1,109 @@
#pragma once
#include <exception>
#include <stdexcept>
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_;
};
}

View File

@ -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<image_runtime_function_entry>(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<unwind_info>(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<image_runtime_function_entry>(current_pos, section_data_virtual, true);
}
return ret;
}
}

View File

@ -0,0 +1,67 @@
#pragma once
#include <vector>
#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> 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);
}

View File

@ -0,0 +1,679 @@
#include <set>
#include <algorithm>
#include <string.h>
#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<exported_function> 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<image_export_directory>(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<uint32_t>(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<uint16_t>(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<uint16_t>(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<uint32_t>(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: <ordinal base for supplied functions; maximum ordinal value for supplied functions>
const std::pair<uint16_t, uint16_t> 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<uint16_t>(max_ordinal, func.get_ordinal());
ordinal_base = std::min<uint16_t>(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<uint32_t>(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<uint32_t>(-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<std::string> used_function_names;
std::set<uint16_t> 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<uint32_t>(max_ordinal, func.get_ordinal());
ordinal_base = std::min<uint32_t>(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<uint32_t>(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<uint32_t>(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<uint32_t>(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<std::string, uint16_t> 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<uint16_t>(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<uint32_t>(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<uint32_t>((*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;
}
}

View File

@ -0,0 +1,163 @@
#pragma once
#include <vector>
#include <string>
#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_function> 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: <ordinal base for supplied functions; maximum ordinal value for supplied functions>
const std::pair<uint16_t, uint16_t> 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);
}

View File

@ -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);
}
}

View File

@ -0,0 +1,18 @@
#pragma once
#include <memory>
#include <istream>
#include <fstream>
#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);
};
}

View File

@ -0,0 +1,756 @@
#include <string.h>
#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_types_class_32>(pe)
: get_imported_functions_base<pe_types_class_64>(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_types_class_32>(pe, imports, import_section, import_settings)
: rebuild_imports_base<pe_types_class_64>(pe, imports, import_section, import_settings));
}
//Returns imported functions list with related libraries info
template<typename PEClassType>
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<image_import_descriptor>(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<typename PEClassType::BaseSize>(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<typename PEClassType::BaseSize>(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<typename PEClassType::BaseSize>(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<typename PEClassType::BaseSize>(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<uint16_t>(lookup & 0xffff));
}
else
{
//Get byte count that we have for function name
if(lookup > static_cast<uint32_t>(-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<uint32_t>(lookup + sizeof(uint16_t)), static_cast<uint32_t>(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<uint32_t>(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<uint16_t>(static_cast<uint32_t>(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<image_import_descriptor>(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<typename PEClassType>
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<uint32_t>((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<uint32_t>((*it).get_name().length() + 1 /* nullbyte */);
const import_library::imported_list& funcs = (*it).get_imported_functions();
//IMAGE_THUNK_DATA
size_of_iat += static_cast<uint32_t>(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<uint32_t>((*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<uint32_t>(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<uint32_t>((*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<typename PEClassType::BaseSize>((*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<uint32_t>((*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<typename PEClassType::BaseSize>((*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;
}
}

View File

@ -0,0 +1,187 @@
#pragma once
#include <vector>
#include <string>
#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_function> 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<import_library> imported_functions_list;
//Returns imported functions list with related libraries info
const imported_functions_list get_imported_functions(const pe_base& pe);
template<typename PEClassType>
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<typename PEClassType>
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());
}

View File

@ -0,0 +1,536 @@
#include <algorithm>
#include <string.h>
#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<typename ConfigStructure>
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_types_class_32>(pe)
: get_image_config_base<pe_types_class_64>(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_types_class_32>(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_types_class_64>(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<typename PEClassType>
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<typename PEClassType::ConfigStruct>(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<typename PEClassType::BaseSize>(-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<uint32_t>(static_cast<typename PEClassType::BaseSize>(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<typename PEClassType::BaseSize>(static_cast<typename PEClassType::BaseSize>(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<typename PEClassType>
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<uint32_t>(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<uint32_t>((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<typename PEClassType::BaseSize>(info.get_decommit_free_block_threshold());
image_config_section_struct.DeCommitTotalFreeThreshold = static_cast<typename PEClassType::BaseSize>(info.get_decommit_total_free_threshold());
image_config_section_struct.MaximumAllocationSize = static_cast<typename PEClassType::BaseSize>(info.get_max_allocation_size());
image_config_section_struct.VirtualMemoryThreshold = static_cast<typename PEClassType::BaseSize>(info.get_virtual_memory_threshold());
image_config_section_struct.ProcessHeapFlags = info.get_process_heap_flags();
image_config_section_struct.ProcessAffinityMask = static_cast<typename PEClassType::BaseSize>(info.get_process_affinity_mask());
image_config_section_struct.CSDVersion = info.get_service_pack_version();
image_config_section_struct.EditList = static_cast<typename PEClassType::BaseSize>(info.get_edit_list_va());
image_config_section_struct.SecurityCookie = static_cast<typename PEClassType::BaseSize>(info.get_security_cookie_va());
image_config_section_struct.SEHandlerCount = static_cast<typename PEClassType::BaseSize>(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<typename PEClassType::BaseSize>(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<typename PEClassType::BaseSize>(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;
}
}

View File

@ -0,0 +1,163 @@
#pragma once
#include <vector>
#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<uint32_t> se_handler_list;
typedef std::vector<uint32_t> lock_prefix_rva_list;
public:
//Default constructor
image_config_info();
//Constructors from PE structures (no checks)
template<typename ConfigStructure>
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<typename PEClassType>
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<typename PEClassType>
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);
}

View File

@ -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);
}
}

View File

@ -0,0 +1,215 @@
#pragma once
#include <memory>
#include "pe_structures.h"
namespace pe_bliss
{
class pe_properties
{
public: //Constructors
virtual std::auto_ptr<pe_properties> 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;
};
}

View File

@ -0,0 +1,624 @@
#include <string.h>
#include "pe_properties_generic.h"
#include "pe_exception.h"
#include "utils.h"
namespace pe_bliss
{
using namespace pe_win;
//Constructor
template<typename PEClassType>
std::auto_ptr<pe_properties> pe_properties_generic<PEClassType>::duplicate() const
{
return std::auto_ptr<pe_properties>(new pe_properties_generic<PEClassType>(*this));
}
//Fills properly PE structures
template<typename PEClassType>
void pe_properties_generic<PEClassType>::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<typename PEClassType>
pe_properties_generic<PEClassType>::~pe_properties_generic()
{}
//Returns true if directory exists
template<typename PEClassType>
bool pe_properties_generic<PEClassType>::directory_exists(uint32_t id) const
{
return (nt_headers_.OptionalHeader.NumberOfRvaAndSizes - 1) >= id &&
nt_headers_.OptionalHeader.DataDirectory[id].VirtualAddress;
}
//Removes directory
template<typename PEClassType>
void pe_properties_generic<PEClassType>::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<typename PEClassType>
uint32_t pe_properties_generic<PEClassType>::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<typename PEClassType>
void pe_properties_generic<PEClassType>::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<typename PEClassType>
void pe_properties_generic<PEClassType>::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<typename PEClassType>
uint32_t pe_properties_generic<PEClassType>::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<typename PEClassType>
uint32_t pe_properties_generic<PEClassType>::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<uint32_t>(i) != image_directory_entry_iat || !strip_iat_directory))
break;
if(i <= static_cast<int>(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<typename PEClassType>
uint32_t pe_properties_generic<PEClassType>::get_image_base_32() const
{
return static_cast<uint32_t>(nt_headers_.OptionalHeader.ImageBase);
}
//Returns image base for PE32/PE64
template<typename PEClassType>
uint64_t pe_properties_generic<PEClassType>::get_image_base_64() const
{
return static_cast<uint64_t>(nt_headers_.OptionalHeader.ImageBase);
}
//Sets new image base
template<typename PEClassType>
void pe_properties_generic<PEClassType>::set_image_base(uint32_t base)
{
nt_headers_.OptionalHeader.ImageBase = base;
}
//Sets new image base
template<typename PEClassType>
void pe_properties_generic<PEClassType>::set_image_base_64(uint64_t base)
{
nt_headers_.OptionalHeader.ImageBase = static_cast<typename PEClassType::BaseSize>(base);
}
//Returns image entry point
template<typename PEClassType>
uint32_t pe_properties_generic<PEClassType>::get_ep() const
{
return nt_headers_.OptionalHeader.AddressOfEntryPoint;
}
//Sets image entry point
template<typename PEClassType>
void pe_properties_generic<PEClassType>::set_ep(uint32_t new_ep)
{
nt_headers_.OptionalHeader.AddressOfEntryPoint = new_ep;
}
//Returns file alignment
template<typename PEClassType>
uint32_t pe_properties_generic<PEClassType>::get_file_alignment() const
{
return nt_headers_.OptionalHeader.FileAlignment;
}
//Returns section alignment
template<typename PEClassType>
uint32_t pe_properties_generic<PEClassType>::get_section_alignment() const
{
return nt_headers_.OptionalHeader.SectionAlignment;
}
//Sets heap size commit for PE32
template<typename PEClassType>
void pe_properties_generic<PEClassType>::set_heap_size_commit(uint32_t size)
{
nt_headers_.OptionalHeader.SizeOfHeapCommit = static_cast<typename PEClassType::BaseSize>(size);
}
//Sets heap size commit for PE32/PE64
template<typename PEClassType>
void pe_properties_generic<PEClassType>::set_heap_size_commit(uint64_t size)
{
nt_headers_.OptionalHeader.SizeOfHeapCommit = static_cast<typename PEClassType::BaseSize>(size);
}
//Sets heap size reserve for PE32
template<typename PEClassType>
void pe_properties_generic<PEClassType>::set_heap_size_reserve(uint32_t size)
{
nt_headers_.OptionalHeader.SizeOfHeapReserve = static_cast<typename PEClassType::BaseSize>(size);
}
//Sets heap size reserve for PE32/PE64
template<typename PEClassType>
void pe_properties_generic<PEClassType>::set_heap_size_reserve(uint64_t size)
{
nt_headers_.OptionalHeader.SizeOfHeapReserve = static_cast<typename PEClassType::BaseSize>(size);
}
//Sets stack size commit for PE32
template<typename PEClassType>
void pe_properties_generic<PEClassType>::set_stack_size_commit(uint32_t size)
{
nt_headers_.OptionalHeader.SizeOfStackCommit = static_cast<typename PEClassType::BaseSize>(size);
}
//Sets stack size commit for PE32/PE64
template<typename PEClassType>
void pe_properties_generic<PEClassType>::set_stack_size_commit(uint64_t size)
{
nt_headers_.OptionalHeader.SizeOfStackCommit = static_cast<typename PEClassType::BaseSize>(size);
}
//Sets stack size reserve for PE32
template<typename PEClassType>
void pe_properties_generic<PEClassType>::set_stack_size_reserve(uint32_t size)
{
nt_headers_.OptionalHeader.SizeOfStackReserve = static_cast<typename PEClassType::BaseSize>(size);
}
//Sets stack size reserve for PE32/PE64
template<typename PEClassType>
void pe_properties_generic<PEClassType>::set_stack_size_reserve(uint64_t size)
{
nt_headers_.OptionalHeader.SizeOfStackReserve = static_cast<typename PEClassType::BaseSize>(size);
}
//Returns heap size commit for PE32
template<typename PEClassType>
uint32_t pe_properties_generic<PEClassType>::get_heap_size_commit_32() const
{
return static_cast<uint32_t>(nt_headers_.OptionalHeader.SizeOfHeapCommit);
}
//Returns heap size commit for PE32/PE64
template<typename PEClassType>
uint64_t pe_properties_generic<PEClassType>::get_heap_size_commit_64() const
{
return static_cast<uint64_t>(nt_headers_.OptionalHeader.SizeOfHeapCommit);
}
//Returns heap size reserve for PE32
template<typename PEClassType>
uint32_t pe_properties_generic<PEClassType>::get_heap_size_reserve_32() const
{
return static_cast<uint32_t>(nt_headers_.OptionalHeader.SizeOfHeapReserve);
}
//Returns heap size reserve for PE32/PE64
template<typename PEClassType>
uint64_t pe_properties_generic<PEClassType>::get_heap_size_reserve_64() const
{
return static_cast<uint64_t>(nt_headers_.OptionalHeader.SizeOfHeapReserve);
}
//Returns stack size commit for PE32
template<typename PEClassType>
uint32_t pe_properties_generic<PEClassType>::get_stack_size_commit_32() const
{
return static_cast<uint32_t>(nt_headers_.OptionalHeader.SizeOfStackCommit);
}
//Returns stack size commit for PE32/PE64
template<typename PEClassType>
uint64_t pe_properties_generic<PEClassType>::get_stack_size_commit_64() const
{
return static_cast<uint64_t>(nt_headers_.OptionalHeader.SizeOfStackCommit);
}
//Returns stack size reserve for PE32
template<typename PEClassType>
uint32_t pe_properties_generic<PEClassType>::get_stack_size_reserve_32() const
{
return static_cast<uint32_t>(nt_headers_.OptionalHeader.SizeOfStackReserve);
}
//Returns stack size reserve for PE32/PE64
template<typename PEClassType>
uint64_t pe_properties_generic<PEClassType>::get_stack_size_reserve_64() const
{
return static_cast<uint64_t>(nt_headers_.OptionalHeader.SizeOfStackReserve);
}
//Returns virtual size of image
template<typename PEClassType>
uint32_t pe_properties_generic<PEClassType>::get_size_of_image() const
{
return nt_headers_.OptionalHeader.SizeOfImage;
}
//Returns number of RVA and sizes (number of DATA_DIRECTORY entries)
template<typename PEClassType>
uint32_t pe_properties_generic<PEClassType>::get_number_of_rvas_and_sizes() const
{
return nt_headers_.OptionalHeader.NumberOfRvaAndSizes;
}
//Sets number of RVA and sizes (number of DATA_DIRECTORY entries)
template<typename PEClassType>
void pe_properties_generic<PEClassType>::set_number_of_rvas_and_sizes(uint32_t number)
{
nt_headers_.OptionalHeader.NumberOfRvaAndSizes = number;
}
//Returns PE characteristics
template<typename PEClassType>
uint16_t pe_properties_generic<PEClassType>::get_characteristics() const
{
return nt_headers_.FileHeader.Characteristics;
}
//Returns checksum of PE file from header
template<typename PEClassType>
uint32_t pe_properties_generic<PEClassType>::get_checksum() const
{
return nt_headers_.OptionalHeader.CheckSum;
}
//Sets checksum of PE file
template<typename PEClassType>
void pe_properties_generic<PEClassType>::set_checksum(uint32_t checksum)
{
nt_headers_.OptionalHeader.CheckSum = checksum;
}
//Returns DLL Characteristics
template<typename PEClassType>
uint16_t pe_properties_generic<PEClassType>::get_dll_characteristics() const
{
return nt_headers_.OptionalHeader.DllCharacteristics;
}
//Returns timestamp of PE file from header
template<typename PEClassType>
uint32_t pe_properties_generic<PEClassType>::get_time_date_stamp() const
{
return nt_headers_.FileHeader.TimeDateStamp;
}
//Sets timestamp of PE file
template<typename PEClassType>
void pe_properties_generic<PEClassType>::set_time_date_stamp(uint32_t timestamp)
{
nt_headers_.FileHeader.TimeDateStamp = timestamp;
}
//Sets DLL Characteristics
template<typename PEClassType>
void pe_properties_generic<PEClassType>::set_dll_characteristics(uint16_t characteristics)
{
nt_headers_.OptionalHeader.DllCharacteristics = characteristics;
}
//Returns Machine field value of PE file from header
template<typename PEClassType>
uint16_t pe_properties_generic<PEClassType>::get_machine() const
{
return nt_headers_.FileHeader.Machine;
}
//Sets Machine field value of PE file
template<typename PEClassType>
void pe_properties_generic<PEClassType>::set_machine(uint16_t machine)
{
nt_headers_.FileHeader.Machine = machine;
}
//Sets PE characteristics
template<typename PEClassType>
void pe_properties_generic<PEClassType>::set_characteristics(uint16_t ch)
{
nt_headers_.FileHeader.Characteristics = ch;
}
//Returns size of headers
template<typename PEClassType>
uint32_t pe_properties_generic<PEClassType>::get_size_of_headers() const
{
return nt_headers_.OptionalHeader.SizeOfHeaders;
}
//Returns subsystem
template<typename PEClassType>
uint16_t pe_properties_generic<PEClassType>::get_subsystem() const
{
return nt_headers_.OptionalHeader.Subsystem;
}
//Sets subsystem
template<typename PEClassType>
void pe_properties_generic<PEClassType>::set_subsystem(uint16_t subsystem)
{
nt_headers_.OptionalHeader.Subsystem = subsystem;
}
//Returns size of optional header
template<typename PEClassType>
uint16_t pe_properties_generic<PEClassType>::get_size_of_optional_header() const
{
return nt_headers_.FileHeader.SizeOfOptionalHeader;
}
//Returns PE signature
template<typename PEClassType>
uint32_t pe_properties_generic<PEClassType>::get_pe_signature() const
{
return nt_headers_.Signature;
}
//Returns PE magic value
template<typename PEClassType>
uint32_t pe_properties_generic<PEClassType>::get_magic() const
{
return nt_headers_.OptionalHeader.Magic;
}
//Sets required operation system version
template<typename PEClassType>
void pe_properties_generic<PEClassType>::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<typename PEClassType>
uint16_t pe_properties_generic<PEClassType>::get_minor_os_version() const
{
return nt_headers_.OptionalHeader.MinorOperatingSystemVersion;
}
//Returns required operation system version (major word)
template<typename PEClassType>
uint16_t pe_properties_generic<PEClassType>::get_major_os_version() const
{
return nt_headers_.OptionalHeader.MajorOperatingSystemVersion;
}
//Sets required subsystem version
template<typename PEClassType>
void pe_properties_generic<PEClassType>::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<typename PEClassType>
uint16_t pe_properties_generic<PEClassType>::get_minor_subsystem_version() const
{
return nt_headers_.OptionalHeader.MinorSubsystemVersion;
}
//Returns required subsystem version (major word)
template<typename PEClassType>
uint16_t pe_properties_generic<PEClassType>::get_major_subsystem_version() const
{
return nt_headers_.OptionalHeader.MajorSubsystemVersion;
}
//Virtual Address (VA) to Relative Virtual Address (RVA) convertions for PE32
template<typename PEClassType>
uint32_t pe_properties_generic<PEClassType>::va_to_rva(uint32_t va, bool bound_check) const
{
if(bound_check && static_cast<uint64_t>(va) - nt_headers_.OptionalHeader.ImageBase > pe_utils::max_dword)
throw pe_exception("Incorrect address conversion", pe_exception::incorrect_address_conversion);
return static_cast<uint32_t>(va - nt_headers_.OptionalHeader.ImageBase);
}
//Virtual Address (VA) to Relative Virtual Address (RVA) convertions for PE32/PE64
template<typename PEClassType>
uint32_t pe_properties_generic<PEClassType>::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<uint32_t>(va - nt_headers_.OptionalHeader.ImageBase);
}
//Relative Virtual Address (RVA) to Virtual Address (VA) convertions for PE32
template<typename PEClassType>
uint32_t pe_properties_generic<PEClassType>::rva_to_va_32(uint32_t rva) const
{
if(!pe_utils::is_sum_safe(rva, static_cast<uint32_t>(nt_headers_.OptionalHeader.ImageBase)))
throw pe_exception("Incorrect address conversion", pe_exception::incorrect_address_conversion);
return static_cast<uint32_t>(rva + nt_headers_.OptionalHeader.ImageBase);
}
//Relative Virtual Address (RVA) to Virtual Address (VA) convertions for PE32/PE64
template<typename PEClassType>
uint64_t pe_properties_generic<PEClassType>::rva_to_va_64(uint32_t rva) const
{
return static_cast<uint64_t>(rva) + nt_headers_.OptionalHeader.ImageBase;
}
//Returns number of sections
template<typename PEClassType>
uint16_t pe_properties_generic<PEClassType>::get_number_of_sections() const
{
return nt_headers_.FileHeader.NumberOfSections;
}
//Sets number of sections
template<typename PEClassType>
void pe_properties_generic<PEClassType>::set_number_of_sections(uint16_t number)
{
nt_headers_.FileHeader.NumberOfSections = number;
}
//Sets virtual size of image
template<typename PEClassType>
void pe_properties_generic<PEClassType>::set_size_of_image(uint32_t size)
{
nt_headers_.OptionalHeader.SizeOfImage = size;
}
//Sets size of headers
template<typename PEClassType>
void pe_properties_generic<PEClassType>::set_size_of_headers(uint32_t size)
{
nt_headers_.OptionalHeader.SizeOfHeaders = size;
}
//Sets size of optional headers
template<typename PEClassType>
void pe_properties_generic<PEClassType>::set_size_of_optional_header(uint16_t size)
{
nt_headers_.FileHeader.SizeOfOptionalHeader = size;
}
//Returns nt headers data pointer
template<typename PEClassType>
char* pe_properties_generic<PEClassType>::get_nt_headers_ptr()
{
return reinterpret_cast<char*>(&nt_headers_);
}
//Returns nt headers data pointer
template<typename PEClassType>
const char* pe_properties_generic<PEClassType>::get_nt_headers_ptr() const
{
return reinterpret_cast<const char*>(&nt_headers_);
}
//Returns size of NT header
template<typename PEClassType>
uint32_t pe_properties_generic<PEClassType>::get_sizeof_nt_header() const
{
return sizeof(typename PEClassType::NtHeaders);
}
//Returns size of optional headers
template<typename PEClassType>
uint32_t pe_properties_generic<PEClassType>::get_sizeof_opt_headers() const
{
return sizeof(typename PEClassType::OptHeaders);
}
//Sets file alignment (no checks)
template<typename PEClassType>
void pe_properties_generic<PEClassType>::set_file_alignment_unchecked(uint32_t alignment)
{
nt_headers_.OptionalHeader.FileAlignment = alignment;
}
//Sets base of code
template<typename PEClassType>
void pe_properties_generic<PEClassType>::set_base_of_code(uint32_t base)
{
nt_headers_.OptionalHeader.BaseOfCode = base;
}
//Returns base of code
template<typename PEClassType>
uint32_t pe_properties_generic<PEClassType>::get_base_of_code() const
{
return nt_headers_.OptionalHeader.BaseOfCode;
}
//Returns needed PE magic for PE or PE+ (from template parameters)
template<typename PEClassType>
uint32_t pe_properties_generic<PEClassType>::get_needed_magic() const
{
return PEClassType::Id;
}
//Returns PE type of this image
template<typename PEClassType>
pe_type pe_properties_generic<PEClassType>::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<pe_types_class_32>;
template class pe_properties_generic<pe_types_class_64>;
}

View File

@ -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<typename PEClassType>
class pe_properties_generic : public pe_properties
{
public: //Constructor
virtual std::auto_ptr<pe_properties> 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_win::image_nt_headers32,
pe_win::image_optional_header32,
pe_win::image_nt_optional_hdr32_magic,
uint32_t,
pe_win::image_ordinal_flag32,
pe_win::image_tls_directory32,
pe_win::image_load_config_directory32> pe_types_class_32;
typedef pe_types<pe_win::image_nt_headers64,
pe_win::image_optional_header64,
pe_win::image_nt_optional_hdr64_magic,
uint64_t,
pe_win::image_ordinal_flag64,
pe_win::image_tls_directory64,
pe_win::image_load_config_directory64> pe_types_class_64;
typedef pe_properties_generic<pe_types_class_32> pe_properties_32;
typedef pe_properties_generic<pe_types_class_64> pe_properties_64;
}

View File

@ -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<uint32_t>(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<uint32_t>(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<uint32_t>(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<uint32_t>(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<uint16_t>(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<uint32_t>(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<const char*>(&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<const pe_base&>(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<uint32_t>((*it).get_raw_data().length()); //Set non-aligned actual data length for it
out.write(reinterpret_cast<const char*>(&header), sizeof(image_section_header));
}
else
{
out.write(reinterpret_cast<const char*>(&(*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);
}
}

View File

@ -0,0 +1,19 @@
#pragma once
#include <ostream>
#include <fstream>
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);
}

View File

@ -0,0 +1,299 @@
#include <string.h>
#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<image_base_relocation>(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<uint16_t>(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<image_base_relocation>(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<uint32_t>((*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<uint32_t>(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_types_class_32>(pe, tables, new_base)
: rebase_image_base<pe_types_class_64>(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<typename PEClassType>
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<typename PEClassType::BaseSize>(static_cast<int64_t>(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<typename PEClassType::BaseSize>(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);
}
}

View File

@ -0,0 +1,101 @@
#pragma once
#include <vector>
#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_entry> 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> 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<typename PEClassType>
void rebase_image_base(pe_base& pe, const relocation_table_list& tables, uint64_t new_base);
}

View File

@ -0,0 +1,265 @@
#include <algorithm>
#include <sstream>
#include <iomanip>
#include <math.h>
#include <string.h>
#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);
}
}

View File

@ -0,0 +1,92 @@
#pragma once
#include <map>
#include <sstream>
#include <string>
#include <memory>
#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);
};
}

View File

@ -0,0 +1,361 @@
#include <algorithm>
#include <cmath>
#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<unsigned long>(
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<unsigned long>(
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<unsigned long>(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<unsigned long>(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<unsigned long>(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<unsigned long>(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
}
}

View File

@ -0,0 +1,132 @@
#pragma once
#include <map>
#include <string>
#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<uint32_t> resource_type_list;
typedef std::vector<uint32_t> resource_id_list;
typedef std::vector<std::wstring> resource_name_list;
typedef std::vector<uint32_t> 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;
};
};
}

View File

@ -0,0 +1,705 @@
#include <algorithm>
#include <string.h>
#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<uint32_t>& 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<image_resource_directory>(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<unsigned long>(directory.NumberOfIdEntries) + directory.NumberOfNamedEntries; ++i)
{
//Read directory entries one by one
image_resource_directory_entry dir_entry = pe.section_data_from_rva<image_resource_directory_entry>(
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<uint16_t>(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<const wchar_t*>(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<const unicode16_t*>(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<image_resource_data_entry>(
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<uint32_t>(((*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<uint32_t>((*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<uint16_t>((*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<unsigned long>((*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<uint32_t>((*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<uint32_t> 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;
}
}

View File

@ -0,0 +1,224 @@
#pragma once
#include <vector>
#include <string>
#include <set>
#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<resource_directory_entry> 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);
}

View File

@ -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<const uint32_t*>(begin) == rich_overlay_id)
{
found = true; //We've found it!
break;
}
}
//If we found it
if(found)
{
//Check remaining length
if(static_cast<size_t>(end - begin) < sizeof(uint32_t))
return ret;
//The XOR key is after "Rich" word, we should get it
uint32_t xorkey = *reinterpret_cast<const uint32_t*>(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<const uint32_t*>(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<const uint32_t*>(begin) == rich_overlay_id)
break;
//Create rich_data structure
rich_data data;
data.set_number((*reinterpret_cast<const uint32_t*>(begin) ^ xorkey) >> 16);
data.set_version((*reinterpret_cast<const uint32_t*>(begin) ^ xorkey) & 0xFFFF);
begin += sizeof(uint32_t);
if(begin >= end)
break;
data.set_times(*reinterpret_cast<const uint32_t*>(begin) ^ xorkey);
//Save rich data structure
ret.push_back(data);
}
}
}
//Return rich data structures list
return ret;
}
}

View File

@ -0,0 +1,37 @@
#pragma once
#include <vector>
#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> rich_data_list;
//Returns a vector with rich data (stub overlay)
const rich_data_list get_rich_data(const pe_base& pe);
}

View File

@ -0,0 +1,281 @@
#include <string.h>
#include "utils.h"
#include "pe_section.h"
namespace pe_bliss
{
using namespace pe_win;
//Section structure default constructor
section::section()
:old_size_(static_cast<size_t>(-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<size_t>(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<size_t>(-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<size_t>(-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<size_t>(-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<size_t>(-1))
{
raw_data_.resize(old_size_, 0);
old_size_ = static_cast<size_t>(-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_;
}
}

View File

@ -0,0 +1,137 @@
#pragma once
#include <string>
#include <vector>
#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> section_list;
}

File diff suppressed because it is too large Load Diff

375
drivers/pe_bliss/pe_tls.cpp Normal file
View File

@ -0,0 +1,375 @@
#include <string.h>
#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<uint32_t>(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_types_class_32>(pe)
: get_tls_info_base<pe_types_class_64>(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_types_class_32>(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_types_class_64>(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<typename PEClassType>
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<typename PEClassType::TLSStruct>(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<typename PEClassType::BaseSize>(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<typename PEClassType::BaseSize>(tls_directory_data.StartAddressOfRawData),
static_cast<typename PEClassType::BaseSize>(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<typename PEClassType::BaseSize>(tls_directory_data.StartAddressOfRawData)) : 0);
ret.set_raw_data_end_rva(tls_directory_data.EndAddressOfRawData ? pe.va_to_rva(static_cast<typename PEClassType::BaseSize>(tls_directory_data.EndAddressOfRawData)) : 0);
ret.set_index_rva(tls_directory_data.AddressOfIndex ? pe.va_to_rva(static_cast<typename PEClassType::BaseSize>(tls_directory_data.AddressOfIndex)) : 0);
ret.set_callbacks_rva(tls_directory_data.AddressOfCallBacks ? pe.va_to_rva(static_cast<typename PEClassType::BaseSize>(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<typename PEClassType::BaseSize>(tls_directory_data.StartAddressOfRawData), section_data_virtual, true),
static_cast<uint32_t>(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<typename PEClassType::BaseSize>(static_cast<typename PEClassType::BaseSize>(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<typename PEClassType>
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<unsigned long>((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<typename PEClassType::BaseSize> 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;
}
}

101
drivers/pe_bliss/pe_tls.h Normal file
View File

@ -0,0 +1,101 @@
#pragma once
#include <memory>
#include <istream>
#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<uint32_t> 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<typename PEClassType>
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<typename PEClassType>
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);
}

View File

@ -0,0 +1,65 @@
#include <cmath>
#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<uint32_t>(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<const bitmapinfoheader*>(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<uint32_t>(std::pow(2.f, info->biBitCount)); //Add this size to offset to bitmap bits
}
//Return final bitmap data
return std::string(reinterpret_cast<const char*>(&header), sizeof(bitmapfileheader)) + resource_data;
}
}

View File

@ -0,0 +1,29 @@
#pragma once
#include <string>
#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_;
};
}

View File

@ -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);
}
}

View File

@ -0,0 +1,26 @@
#pragma once
#include <string>
#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_;
};
}

View File

@ -0,0 +1,500 @@
#include <algorithm>
#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<const ico_header*>(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<const char*>(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<const icon_group*>(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<const char*>(&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<const icon_group*>(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<const icon_group*>(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<const icon_group*>(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<const icon_group*>(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<const ico_header*>(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<const icon_group*>(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<const char*>(&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<const char*>(&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<const cursor_header*>(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<const char*>(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<const cursor_group*>(resource_data.data() + sizeof(cursor_header) + i * sizeof(cursor_group));
//Fill cursor info
cursordirentry direntry;
direntry.ColorCount = 0; //OK
direntry.Width = static_cast<uint8_t>(group->Width);
direntry.Height = static_cast<uint8_t>(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<const uint16_t*>(cursor.data());
direntry.HotspotY = *reinterpret_cast<const uint16_t*>(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<const char*>(&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<const cursor_group*>(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<const cursor_group*>(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<const cursor_group*>(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<const cursor_group*>(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<const cursor_header*>(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<const cursor_group*>(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<const char*>(&new_header), sizeof(cursor_header));
//Fill cursor info
cursordirentry direntry;
direntry.ColorCount = 0; //OK
direntry.Width = static_cast<uint8_t>(group->Width);
direntry.Height = static_cast<uint8_t>(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<const uint16_t*>(raw_cursor_data.data());
direntry.HotspotY = *reinterpret_cast<const uint16_t*>(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<const char*>(&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);
}
}

View File

@ -0,0 +1,63 @@
#pragma once
#include <string>
#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);
};
}

View File

@ -0,0 +1,426 @@
#include <algorithm>
#include <string.h>
#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<const ico_header*>(&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<const icondirentry*>(&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<ico_header*>(&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<ico_header*>(&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<uint16_t> 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<const icondirentry*>(&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<uint16_t> 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<uint16_t> icon_cursor_id_list;
try
{
//If any icon exists
//List icon IDs
std::vector<uint32_t> 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<uint32_t>::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<uint16_t>(*(it - 1) + 1); i != static_cast<uint16_t>(*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<uint32_t>(icon_cursor_id_list.size()); i != count; ++i)
icon_cursor_id_list.push_back(static_cast<uint16_t>(++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<const cursor_header*>(&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<const cursordirentry*>(&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_header*>(&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_header*>(&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<uint16_t> 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<const cursordirentry*>(&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<resource_data_info> 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<resource_data_info> 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<resource_data_info> 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<resource_data_info> 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<const ico_header*>(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<const icon_group*>(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<const cursor_header*>(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<const icon_group*>(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);
}
}

View File

@ -0,0 +1,73 @@
#pragma once
#include <string>
#include <vector>
#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<uint16_t> get_icon_or_cursor_free_id_list(pe_resource_manager::resource_type type, icon_place_mode mode, uint32_t count);
};
}

View File

@ -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_;
}
}

View File

@ -0,0 +1,27 @@
#pragma once
#include <string>
#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_;
};
}

View File

@ -0,0 +1,13 @@
#pragma once
#define U16TEXT(t) reinterpret_cast<const unicode16_t*>( 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")

View File

@ -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<const message_resource_data*>(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<const message_resource_block*>(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<const message_resource_entry*>(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<const wchar_t*>(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<const unicode16_t*>(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());
}
}

View File

@ -0,0 +1,28 @@
#pragma once
#include "message_table.h"
namespace pe_bliss
{
class pe_resource_viewer;
//ID; message_table_item
typedef std::map<uint32_t, message_table_item> 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_;
};
}

View File

@ -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<const uint16_t*>(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<uint16_t>(((id - 1) << 4) + i), //ID of string is calculated such way
std::wstring(reinterpret_cast<const wchar_t*>(resource_data.data() + passed_bytes), string_length)));
#else
ret.insert(
std::make_pair(static_cast<uint16_t>(((id - 1) << 4) + i), //ID of string is calculated such way
pe_utils::from_ucs2(u16string(reinterpret_cast<const unicode16_t*>(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;
}
}

View File

@ -0,0 +1,36 @@
#pragma once
#include <string>
#include <map>
#include "stdint_defs.h"
namespace pe_bliss
{
class pe_resource_viewer;
//ID; string
typedef std::map<uint16_t, std::wstring> 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);
};
}

View File

@ -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<uint32_t>(u16string(key).length());
uint32_t ret = pe_utils::align_up(static_cast<uint32_t>(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<uint32_t>(u16string(key).length());
uint32_t ret = pe_utils::align_up(static_cast<uint32_t>(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<const version_info_block*>(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<const unicode16_t*>(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<const unicode16_t*>(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<const vs_fixedfileinfo*>(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<const unicode16_t*>(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<const version_info_block*>(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<const unicode16_t*>(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<const unicode16_t*>(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<const version_info_block*>(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<const unicode16_t*>(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<const version_info_block*>(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<const unicode16_t*>(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<const unicode16_t*>(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<const unicode16_t*>(string_block->Key), data));
#else
new_values.insert(std::make_pair(pe_utils::from_ucs2(reinterpret_cast<const unicode16_t*>(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<const unicode16_t*>(string_table->Key), new_values));
#else
string_values.insert(std::make_pair(pe_utils::from_ucs2(reinterpret_cast<const unicode16_t*>(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<const unicode16_t*>(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<const version_info_block*>(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<const unicode16_t*>(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<const unicode16_t*>(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<const uint16_t*>(resource_data.data() + value_pos + i);
uint16_t codepage_id = *reinterpret_cast<const uint16_t*>(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
}
}

View File

@ -0,0 +1,46 @@
#pragma once
#include <map>
#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();
};
}

View File

@ -0,0 +1,262 @@
#include <string.h>
#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<uint32_t>(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<uint32_t>(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<uint32_t>(sizeof(uint16_t) * 3 + ((*it).first.length() + 1) * 2), sizeof(uint32_t));
total_version_info_length += pe_utils::align_up(static_cast<uint32_t>(((*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<uint32_t>(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<uint16_t>(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<uint32_t>((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_info_block*>(&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_info_block*>(&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<uint32_t>(((*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<uint16_t>((*it).second.length() + 1);
uint32_t key_length = static_cast<uint32_t>(((*it).first.length() + 1) * sizeof(uint16_t));
//Calculate length of block
string_block.Length = static_cast<uint16_t>(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<uint16_t>(data_ptr - old_ptr2 + sizeof(uint16_t) * 3);
}
string_file_info_block_ptr->Length = static_cast<uint16_t>(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_info_block*>(&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_info_block*>(&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<uint16_t>(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<uint16_t>(data_ptr - old_ptr2 + sizeof(uint16_t) * 3);
var_file_info_block_ptr->Length = static_cast<uint16_t>(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);
}
}

View File

@ -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_;
};
}

View File

@ -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 <stdint.h>
#endif
#else
#include <stdint.h>
#endif

View File

@ -0,0 +1,86 @@
#include <string.h>
#include "utils.h"
#include "pe_exception.h"
#ifndef PE_BLISS_WINDOWS
#include <iconv.h>
#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<iconv_t>(-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<char**>(reinterpret_cast<const char**>(&in_pos)), &inbytesleft, reinterpret_cast<char**>(&out_pos), &outbytesleft);
iconv_close(conv);
if(result == static_cast<size_t>(-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<iconv_t>(-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<char**>(reinterpret_cast<const char**>(&in_pos)), &inbytesleft, reinterpret_cast<char**>(&out_pos), &outbytesleft);
iconv_close(conv);
if(result == static_cast<size_t>(-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));
}
}

84
drivers/pe_bliss/utils.h Normal file
View File

@ -0,0 +1,84 @@
#pragma once
#include <istream>
#include <string>
#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<typename T>
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<T>(L'\0'))
return true;
}
return false;
}
//Helper template function to strip nullbytes in the end of string
template<typename T>
static void strip_nullbytes(std::basic_string<T>& str)
{
while(!*(str.end() - 1) && !str.empty())
str.erase(str.length() - 1);
}
//Helper function to determine if number is power of 2
template<typename T>
static inline bool is_power_of_2(T x)
{
return !(x & (x - 1));
}
//Helper function to align number down
template<typename T>
static inline T align_down(T x, uint32_t align)
{
return x & ~(static_cast<T>(align) - 1);
}
//Helper function to align number up
template<typename T>
static inline T align_up(T x, uint32_t align)
{
return (x & static_cast<T>(align - 1)) ? align_down(x, align) + static_cast<T>(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<uint32_t>(-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);
}

View File

@ -0,0 +1,163 @@
#include <sstream>
#include <iomanip>
#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<uint16_t, uint16_t> 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<translation_values_map::const_iterator, translation_values_map::const_iterator>
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<uint16_t, uint16_t> 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<translation_values_map::iterator, translation_values_map::iterator>
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;
}
}
}
}

View File

@ -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_;
};
}

View File

@ -0,0 +1,17 @@
#pragma once
#include <map>
#include <string>
#include "stdint_defs.h"
namespace pe_bliss
{
//Typedef for version info functions: Name - Value
typedef std::map<std::wstring, std::wstring> 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<std::wstring, string_values_map> lang_string_values_map;
//Typedef for version info functions: Language - Character Set
typedef std::multimap<uint16_t, uint16_t> translation_values_map;
}

View File

@ -0,0 +1,159 @@
#include <iomanip>
#include <sstream>
#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<uint16_t>(translation_id >> 16), static_cast<uint16_t>(translation_id & 0xFFFF));
}
}

View File

@ -0,0 +1,68 @@
#pragma once
#include <map>
#include <vector>
#include <string>
#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<uint16_t, uint16_t> translation_pair;
typedef std::vector<std::wstring> 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_;
};
}

View File

@ -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();
}

BIN
godot_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

133
godot_icon.svg Normal file
View File

@ -0,0 +1,133 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1024"
height="1024"
id="svg3030"
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="godot_icon.svg">
<defs
id="defs3032" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.24748737"
inkscape:cx="340.91041"
inkscape:cy="224.06536"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1366"
inkscape:window-height="748"
inkscape:window-x="-2"
inkscape:window-y="-3"
inkscape:window-maximized="1" />
<metadata
id="metadata3035">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-28.362183)">
<rect
style="fill:#a39f9f;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="rect4009"
width="990"
height="990"
x="20"
y="47.362183"
ry="187.81349" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:none"
d="m 116.99388,715.36604 43.13957,-74.51381 75.99672,-171.42666 271.088,-13.63746 282.06373,14.1696 138.45065,255.56931 -25.0756,66.96734 -376.12685,53.39482 -367.70391,-40.32222 z"
id="path3239"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccc" />
<g
id="g3412"
transform="matrix(12.995388,0,0,-12.995388,898.37246,704.73082)">
<path
inkscape:connector-curvature="0"
d="m 0,0 0,-3.942 c 0,-0.39 -0.25,-0.734 -0.621,-0.852 L -6.835,-6.8 c -0.273,-0.091 -0.57,-0.042 -0.8,0.128 -0.232,0.168 -0.37,0.437 -0.37,0.721 l 0,4.305 -5.818,-1.108 0,-4.381 c 0,-0.447 -0.332,-0.824 -0.775,-0.885 l -8.41,-1.152 c -0.039,-0.003 -0.081,-0.008 -0.121,-0.008 -0.214,0 -0.424,0.078 -0.588,0.22 -0.195,0.172 -0.306,0.416 -0.306,0.676 l 0,4.638 -4.341,-0.018 0,-10e-4 -0.318,10e-4 -0.319,-10e-4 0,10e-4 -4.34,0.018 0,-4.638 c 0,-0.26 -0.112,-0.504 -0.307,-0.676 -0.164,-0.142 -0.374,-0.22 -0.587,-0.22 -0.041,0 -0.082,0.005 -0.123,0.008 l -8.41,1.152 c -0.442,0.061 -0.774,0.438 -0.774,0.885 l 0,4.381 -5.819,1.108 0,-4.305 c 0,-0.284 -0.137,-0.553 -0.368,-0.721 -0.232,-0.17 -0.529,-0.219 -0.802,-0.128 l -6.215,2.006 c -0.369,0.118 -0.619,0.462 -0.619,0.852 l 0,3.942 -3.837,1.29 c -0.19,-0.811 -0.295,-1.642 -0.295,-2.481 0,-10.301 14.512,-18.252 32.448,-18.309 l 0.022,0 0.023,0 c 17.936,0.057 32.448,8.008 32.448,18.309 0,0.766 -0.088,1.521 -0.247,2.266 L 0,0 z"
style="fill:#478cbf;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3414" />
</g>
<g
id="g3416"
transform="matrix(12.995388,0,0,-12.995388,140.10982,467.34929)">
<path
inkscape:connector-curvature="0"
d="m 0,0 0,-16.047 2.163,-0.729 c 0.364,-0.122 0.61,-0.462 0.61,-0.847 l 0,-3.936 4.426,-1.428 0,4.154 c 0,0.27 0.118,0.52 0.323,0.689 0.206,0.172 0.474,0.241 0.739,0.192 l 7.608,-1.452 c 0.422,-0.079 0.728,-0.448 0.728,-0.877 l 0,-4.338 6.62,-0.904 0,4.509 c 0,0.241 0.096,0.467 0.264,0.635 0.167,0.166 0.394,0.259 0.633,0.259 l 0.002,0 5.551,-0.022 5.549,0.022 c 0.245,-10e-4 0.468,-0.093 0.635,-0.259 0.169,-0.168 0.264,-0.394 0.264,-0.635 l 0,-4.509 6.621,0.904 0,4.338 c 0,0.429 0.304,0.798 0.726,0.877 l 7.609,1.452 c 0.262,0.049 0.533,-0.02 0.738,-0.192 0.205,-0.169 0.325,-0.419 0.325,-0.689 l 0,-4.154 4.425,1.428 0,3.936 c 0,0.385 0.245,0.725 0.609,0.847 l 1.475,0.497 0,16.279 0.04,0 c 1.437,1.834 2.767,3.767 4.042,5.828 -1.694,2.883 -3.768,5.459 -5.986,7.846 -2.057,-1.035 -4.055,-2.208 -5.942,-3.456 -0.944,0.938 -2.008,1.706 -3.052,2.509 -1.027,0.824 -2.183,1.428 -3.281,2.132 0.327,2.433 0.489,4.828 0.554,7.327 -2.831,1.424 -5.85,2.369 -8.903,3.047 -1.219,-2.048 -2.334,-4.267 -3.304,-6.436 -1.152,0.192 -2.309,0.264 -3.467,0.277 l 0,0.002 c -0.008,0 -0.015,-0.002 -0.022,-0.002 -0.008,0 -0.015,0.002 -0.022,0.002 l 0,-0.002 c -1.16,-0.013 -2.316,-0.085 -3.468,-0.277 -0.97,2.169 -2.084,4.388 -3.305,6.436 C 19.475,24.555 16.456,23.61 13.626,22.186 13.69,19.687 13.852,17.292 14.18,14.859 13.081,14.155 11.925,13.551 10.898,12.727 9.855,11.924 8.79,11.156 7.846,10.218 5.958,11.466 3.961,12.639 1.904,13.674 -0.314,11.287 -2.388,8.711 -4.082,5.828 -2.807,3.767 -1.477,1.834 -0.04,0 L 0,0 z"
style="fill:#478cbf;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3418" />
</g>
<g
id="g3420"
transform="matrix(12.995388,0,0,-12.995388,411.4457,567.42812)">
<path
inkscape:connector-curvature="0"
d="m 0,0 c 0,-3.611 -2.926,-6.537 -6.537,-6.537 -3.608,0 -6.535,2.926 -6.535,6.537 0,3.609 2.927,6.533 6.535,6.533 C -2.926,6.533 0,3.609 0,0"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3422" />
</g>
<g
id="g3424"
transform="matrix(12.995388,0,0,-12.995388,391.00655,572.46636)">
<path
inkscape:connector-curvature="0"
d="m 0,0 c 0,-2.396 -1.941,-4.337 -4.339,-4.337 -2.396,0 -4.339,1.941 -4.339,4.337 0,2.396 1.943,4.339 4.339,4.339 C -1.941,4.339 0,2.396 0,0"
style="fill:#414042;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3426" />
</g>
<g
id="g3428"
transform="matrix(12.995388,0,0,-12.995388,526.30933,660.10985)">
<path
inkscape:connector-curvature="0"
d="m 0,0 c -1.162,0 -2.104,0.856 -2.104,1.912 l 0,6.018 c 0,1.054 0.942,1.912 2.104,1.912 1.162,0 2.106,-0.858 2.106,-1.912 l 0,-6.018 C 2.106,0.856 1.162,0 0,0"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3430" />
</g>
<g
id="g3432"
transform="matrix(12.995388,0,0,-12.995388,641.18731,567.42812)">
<path
inkscape:connector-curvature="0"
d="m 0,0 c 0,-3.611 2.926,-6.537 6.537,-6.537 3.609,0 6.535,2.926 6.535,6.537 0,3.609 -2.926,6.533 -6.535,6.533 C 2.926,6.533 0,3.609 0,0"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3434" />
</g>
<g
id="g3436"
transform="matrix(12.995388,0,0,-12.995388,661.63165,572.46636)">
<path
inkscape:connector-curvature="0"
d="m 0,0 c 0,-2.396 1.941,-4.337 4.336,-4.337 2.398,0 4.339,1.941 4.339,4.337 0,2.396 -1.941,4.339 -4.339,4.339 C 1.941,4.339 0,2.396 0,0"
style="fill:#414042;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3438" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.1 KiB

File diff suppressed because one or more lines are too long

View File

@ -1098,6 +1098,8 @@ def update_version():
f.write("#define VERSION_MINOR "+str(version.minor)+"\n")
f.write("#define VERSION_REVISION "+str(rev)+"\n")
f.write("#define VERSION_STATUS "+str(version.status)+"\n")
import datetime
f.write("#define VERSION_YEAR "+str(datetime.datetime.now().year)+"\n")
def parse_cg_file(fname, uniforms, sizes, conditionals):

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 850 B

After

Width:  |  Height:  |  Size: 828 B

View File

@ -11,9 +11,15 @@ common_win=[
"stream_peer_winsock.cpp",
]
env.RES('godot_res.rc')
if env["is_mingw"]:
common_win.append("godot_res.o")
else:
common_win.append("godot_res.res")
env.Program('#bin/godot',['godot_win.cpp']+common_win,PROGSUFFIX=env["PROGSUFFIX"])
# Microsoft Visual Studio Project Generation
# Microsoft Visual Studio Project Generation
if (env['vsproj'])=="yes":
env.vs_srcs = env.vs_srcs + ["platform/windows/godot_win.cpp"]
for x in common_win:

View File

@ -88,7 +88,7 @@
import os
import sys
import sys
def is_active():
@ -173,13 +173,30 @@ def get_flags():
('theora','no'),
]
def build_res_file( target, source, env ):
cmdbase = ""
if (env["bits"] == "32"):
cmdbase = env['mingw_prefix']
else:
cmdbase = env['mingw_prefix_64']
CPPPATH = env['CPPPATH']
cmdbase = cmdbase + 'windres --include-dir . '
import subprocess
for x in range(len(source)):
cmd = cmdbase + '-i ' + str(source[x]) + ' -o ' + str(target[x])
try:
out = subprocess.Popen(cmd,shell = True,stderr = subprocess.PIPE).communicate()
if len(out[1]):
return 1
except:
return 1
return 0
def configure(env):
env.Append(CPPPATH=['#platform/windows'])
env['is_mingw']=False
if (os.name=="nt" and os.getenv("VSINSTALLDIR")!=None):
#build using visual studio
env['ENV']['TMP'] = os.environ['TMP']
@ -354,7 +371,7 @@ def configure(env):
env.Append(LIBS=['mingw32','opengl32', 'dsound', 'ole32', 'd3d9','winmm','gdi32','iphlpapi','shlwapi','wsock32','kernel32'])
# if (env["bits"]=="32"):
# # env.Append(LIBS=['gcc_s'])
# env.Append(LIBS=['gcc_s'])
# #--with-arch=i686
# env.Append(CPPFLAGS=['-march=i686'])
# env.Append(LINKFLAGS=['-march=i686'])
@ -366,6 +383,10 @@ def configure(env):
env.Append(CPPFLAGS=['-DMINGW_ENABLED'])
env.Append(LINKFLAGS=['-g'])
# resrc
env['is_mingw']=True
env.Append( BUILDERS = { 'RES' : env.Builder(action = build_res_file, suffix = '.o',src_suffix = '.rc') } )
import methods
env.Append( BUILDERS = { 'GLSL120' : env.Builder(action = methods.build_legacygl_headers, suffix = 'glsl.h',src_suffix = '.glsl') } )
env.Append( BUILDERS = { 'GLSL' : env.Builder(action = methods.build_glsl_headers, suffix = 'glsl.h',src_suffix = '.glsl') } )
@ -373,4 +394,3 @@ def configure(env):
env.Append( BUILDERS = { 'GLSL120GLES' : env.Builder(action = methods.build_gles2_headers, suffix = 'glsl.h',src_suffix = '.glsl') } )

View File

@ -1,6 +1,351 @@
/*************************************************************************/
/* export.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "export.h"
#include "platform/windows/logo.h"
#include "tools/editor/editor_import_export.h"
#include "os/os.h"
#include "globals.h"
#include "tools/editor/editor_node.h"
/**
@author Masoud BaniHashemian <masoudbh3@gmail.com>
*/
String (*EditorExportPlatformWindows::_add_resrc_func)(const char* ,int ,int ,String& ,
String& ,String& ,String& , String& ,String& , DVector<uint8_t>& )=NULL;
void EditorExportPlatformWindows::store_16(DVector<uint8_t>& vector, uint16_t value) {
const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&value);
int size = vector.size();
vector.resize( size + 2 );
DVector<uint8_t>::Write w = vector.write();
w[size]=bytes[0];
w[size+1]=bytes[1];
}
void EditorExportPlatformWindows::store_32(DVector<uint8_t>& vector, uint32_t value) {
const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&value);
int size = vector.size();
vector.resize( size + 4 );
DVector<uint8_t>::Write w = vector.write();
w[size]=bytes[0];
w[size+1]=bytes[1];
w[size+2]=bytes[2];
w[size+3]=bytes[3];
}
bool EditorExportPlatformWindows::_set(const StringName& p_name, const Variant& p_value) {
String n = p_name;
if (n=="icon/icon_ico") {
icon_ico=p_value;
} else if (n=="icon/icon_png") {
icon_png=p_value;
} else if (n=="icon/icon_png16x16") {
icon16=p_value;
} else if (n=="icon/icon_png32x32") {
icon32=p_value;
} else if (n=="icon/icon_png48x48") {
icon48=p_value;
} else if (n=="icon/icon_png64x64") {
icon64=p_value;
} else if (n=="icon/icon_png128x128") {
icon128=p_value;
} else if (n=="icon/icon_png256x256") {
icon256=p_value;
} else if (n=="version_info/version_major") {
version_major=p_value;
} else if (n=="version_info/version_minor") {
version_minor=p_value;
} else if (n=="version_info/version_text") {
version_text=p_value;
} else if (n=="version_info/company_name") {
company_name=p_value;
} else if (n=="version_info/file_description") {
file_description=p_value;
} else if (n=="version_info/product_name") {
product_name=p_value;
} else if (n=="version_info/legal_copyright") {
legal_copyright=p_value;
} else if (n=="version_info/add_godot_version") {
set_godot_version=p_value;
} else
return false;
return true;
}
bool EditorExportPlatformWindows::_get(const StringName& p_name,Variant &r_ret) const {
String n = p_name;
if (n=="icon/icon_ico") {
r_ret=icon_ico;
} else if (n=="icon/icon_png") {
r_ret=icon_png;
} else if (n=="icon/icon_png16x16") {
r_ret=icon16;
} else if (n=="icon/icon_png32x32") {
r_ret=icon32;
} else if (n=="icon/icon_png48x48") {
r_ret=icon48;
} else if (n=="icon/icon_png64x64") {
r_ret=icon64;
} else if (n=="icon/icon_png128x128") {
r_ret=icon128;
} else if (n=="icon/icon_png256x256") {
r_ret=icon256;
} else if (n=="version_info/version_major") {
r_ret=version_major;
} else if (n=="version_info/version_minor") {
r_ret=version_minor;
} else if (n=="version_info/version_text") {
r_ret=version_text;
} else if (n=="version_info/company_name") {
r_ret=company_name;
} else if (n=="version_info/file_description") {
r_ret=file_description;
} else if (n=="version_info/product_name") {
r_ret=product_name;
} else if (n=="version_info/legal_copyright") {
r_ret=legal_copyright;
} else if (n=="version_info/add_godot_version") {
r_ret=set_godot_version;
} else
return false;
return true;
}
void EditorExportPlatformWindows::_get_property_list( List<PropertyInfo> *p_list) const {
p_list->push_back( PropertyInfo( Variant::STRING, "icon/icon_ico",PROPERTY_HINT_FILE,"ico") );
p_list->push_back( PropertyInfo( Variant::STRING, "icon/icon_png",PROPERTY_HINT_FILE,"png") );
p_list->push_back( PropertyInfo( Variant::BOOL, "icon/icon_png16x16") );
p_list->push_back( PropertyInfo( Variant::BOOL, "icon/icon_png32x32") );
p_list->push_back( PropertyInfo( Variant::BOOL, "icon/icon_png48x48") );
p_list->push_back( PropertyInfo( Variant::BOOL, "icon/icon_png64x64") );
p_list->push_back( PropertyInfo( Variant::BOOL, "icon/icon_png128x128") );
p_list->push_back( PropertyInfo( Variant::BOOL, "icon/icon_png256x256") );
p_list->push_back( PropertyInfo( Variant::INT, "version_info/version_major", PROPERTY_HINT_RANGE,"0,65535,1"));
p_list->push_back( PropertyInfo( Variant::INT, "version_info/version_minor", PROPERTY_HINT_RANGE,"0,65535,0"));
p_list->push_back( PropertyInfo( Variant::STRING, "version_info/version_text") );
p_list->push_back( PropertyInfo( Variant::STRING, "version_info/company_name") );
p_list->push_back( PropertyInfo( Variant::STRING, "version_info/file_description") );
p_list->push_back( PropertyInfo( Variant::STRING, "version_info/product_name") );
p_list->push_back( PropertyInfo( Variant::STRING, "version_info/legal_copyright") );
p_list->push_back( PropertyInfo( Variant::BOOL, "version_info/add_godot_version") );
}
Error EditorExportPlatformWindows::export_project(const String& p_path, bool p_debug, bool p_dumb,bool p_remote_debug) {
Error err = EditorExportPlatformPC::export_project(p_path, p_debug, p_dumb, p_remote_debug);
if(err != OK)
{
return err;
}
if(!_add_resrc_func) {
return err;
} else {
EditorProgress ep("editexe","Edit EXE File",102);
ep.step("Create ico file..",0);
DVector<uint8_t> icon_content;
if (this->icon_ico!="" && this->icon_ico.ends_with(".ico")) {
FileAccess *f = FileAccess::open(this->icon_ico,FileAccess::READ);
if (f) {
icon_content.resize(f->get_len());
DVector<uint8_t>::Write write = icon_content.write();
f->get_buffer(write.ptr(),icon_content.size());
f->close();
memdelete(f);
}
} else if (this->icon_png!="" && this->icon_png.ends_with(".png") && (icon16 || icon32 || icon48 || icon64 || icon128 || icon256)) {
#ifdef PNG_ENABLED
Vector<Image> pngs;
Image png;
Error err_png = png.load(this->icon_png);
if (err_png==OK && !png.empty()) {
if(icon256) {
Image icon_256(png);
if(!(png.get_height()==256 && png.get_width()==256)) icon_256.resize(256,256);
pngs.push_back(icon_256);
}
if(icon128) {
Image icon_128(png);
if(!(png.get_height()==128 && png.get_width()==128)) icon_128.resize(128,128);
pngs.push_back(icon_128);
}
if(icon64) {
Image icon_64(png);
if(!(png.get_height()==64 && png.get_width()==64)) icon_64.resize(64,64);
pngs.push_back(icon_64);
}
if(icon48) {
Image icon_48(png);
if(!(png.get_height()==48 && png.get_width()==48)) icon_48.resize(48,48);
pngs.push_back(icon_48);
}
if(icon32) {
Image icon_32(png);
if(!(png.get_height()==32 && png.get_width()==32)) icon_32.resize(32,32);
pngs.push_back(icon_32);
}
if(icon16) {
Image icon_16(png);
if(!(png.get_height()==16 && png.get_width()==16)) icon_16.resize(16,16);
pngs.push_back(icon_16);
}
// create icon according to https://www.daubnet.com/en/file-format-ico
store_16(icon_content,0); //Reserved
store_16(icon_content,1); //Type
store_16(icon_content,pngs.size()); //Count
int offset = 6+pngs.size()*16;
//List of bitmaps
for(int i=0;i<pngs.size();i++) {
int w = pngs[i].get_width();
int h = pngs[i].get_height();
icon_content.push_back(w<256?w:0); //width
icon_content.push_back(h<256?h:0); //height
icon_content.push_back(0); //ColorCount = 0
icon_content.push_back(0); //Reserved
store_16(icon_content,1); //Planes
store_16(icon_content,32); //BitCount (bit per pixel)
int size = 40 + (w * h * 4) + (w * h / 8);
store_32(icon_content,size); //Size of (InfoHeader + ANDbitmap + XORbitmap)
store_32(icon_content,offset); //FileOffset
offset += size;
}
//Write bmp files.
for(int i=0;i<pngs.size();i++) {
int w = pngs[i].get_width();
int h = pngs[i].get_height();
store_32(icon_content,40); //Size of InfoHeader structure = 40
store_32(icon_content,w); //Width
store_32(icon_content,h*2); //Height
store_16(icon_content,1); //Planes
store_16(icon_content,32); //BitCount
store_32(icon_content,0); //Compression
store_32(icon_content,w*h*4); //ImageSize = Size of Image in Bytes
store_32(icon_content,0); //unused = 0
store_32(icon_content,0); //unused = 0
store_32(icon_content,0); //unused = 0
store_32(icon_content,0); //unused = 0
//XORBitmap
for(int y=h-1;y>=0;y--) {
for(int x=0;x<w;x++) {
store_32(icon_content,pngs[i].get_pixel(x,y).to_32());
}
}
//ANDBitmap
for(int m=0;m<(w * h / 8);m+=4) store_32(icon_content,0x00000000); // Add empty ANDBitmap , TODO create full ANDBitmap Structure if need.
}
}
#endif
}
ep.step("Add rsrc..",50);
String basename = Globals::get_singleton()->get("application/name");
product_name=product_name.replace("$genname",basename);
String godot_version;
if(set_godot_version) godot_version = String( VERSION_MKSTRING );
String ret = EditorExportPlatformWindows::_add_resrc_func(p_path.utf8(), version_major, version_minor,
company_name, file_description, legal_copyright, version_text,
product_name, godot_version, icon_content);
if (ret.empty()) {
return OK;
} else {
EditorNode::add_io_error(ret);
return ERR_FILE_CANT_WRITE;
}
}
}
EditorExportPlatformWindows::EditorExportPlatformWindows() {
icon16=true;
icon32=true;
icon48=true;
icon64=true;
icon128=true;
icon256=true;
product_name="$genname";
company_name="Okam Studio";
file_description="Created With Godot Engine";
version_text="1.0";
OS::Date date = OS::get_singleton()->get_date();
legal_copyright="Copyright (c) 2007-";
legal_copyright+=String::num(date.year);
legal_copyright+=" Juan Linietsky, Ariel Manzur";
version_major=1;
version_minor=0;
set_godot_version=true;
}
void register_windows_exporter() {
@ -9,7 +354,7 @@ void register_windows_exporter() {
logo->create_from_image(img);
{
Ref<EditorExportPlatformPC> exporter = Ref<EditorExportPlatformPC>( memnew(EditorExportPlatformPC) );
Ref<EditorExportPlatformWindows> exporter = Ref<EditorExportPlatformWindows>( memnew(EditorExportPlatformWindows) );
exporter->set_binary_extension("exe");
exporter->set_release_binary32("windows_32_release.exe");
exporter->set_debug_binary32("windows_32_debug.exe");

View File

@ -1,3 +1,38 @@
#include "tools/editor/editor_import_export.h"
class EditorExportPlatformWindows : public EditorExportPlatformPC {
OBJ_TYPE( EditorExportPlatformWindows,EditorExportPlatformPC );
private:
String icon_ico;
String icon_png;
bool icon16;
bool icon32;
bool icon48;
bool icon64;
bool icon128;
bool icon256;
String company_name;
String file_description;
String product_name;
String legal_copyright;
String version_text;
int version_major;
int version_minor;
bool set_godot_version;
void store_16(DVector<uint8_t>& vector, uint16_t value); ///< store 16 bits uint
void store_32(DVector<uint8_t>& vector, uint32_t value); ///< store 32 bits uint
protected:
bool _set(const StringName& p_name, const Variant& p_value);
bool _get(const StringName& p_name,Variant &r_ret) const;
void _get_property_list( List<PropertyInfo> *p_list) const;
public:
static String (*_add_resrc_func)(const char*,int,int,String&,String&,String&,String&,String&,String&,DVector<uint8_t>&);
Error export_project(const String& p_path, bool p_debug, bool p_dumb=false, bool p_remote_debug=false);
EditorExportPlatformWindows();
};
void register_windows_exporter();

BIN
platform/windows/godot.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 KiB

View File

@ -0,0 +1,33 @@
#include "core/version.h"
#ifndef _STR
#define _STR(m_x) #m_x
#define _MKSTR(m_x) _STR(m_x)
#endif
GODOT_ICON ICON platform/windows/godot.ico
1 VERSIONINFO
FILEVERSION VERSION_MAJOR,VERSION_MINOR,0
PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,0
FILEOS 4
FILETYPE 1
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "Okam Studio"
VALUE "FileDescription", _MKSTR(VERSION_NAME) " Editor (" _MKSTR(VERSION_STATUS) ")"
VALUE "FileVersion", _MKSTR(VERSION_MAJOR) "." _MKSTR(VERSION_MINOR) "."_MKSTR(VERSION_REVISION)
VALUE "ProductName", _MKSTR(VERSION_NAME)
VALUE "Licence", "MIT"
VALUE "LegalCopyright", "Copyright (c) 2007-" _MKSTR(VERSION_YEAR) " Juan Linietsky, Ariel Manzur"
VALUE "Info", "http://www.godotengine.org"
VALUE "ProductVersion", _MKSTR(VERSION_MAJOR) "." _MKSTR(VERSION_MINOR) "."_MKSTR(VERSION_REVISION)
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END

Some files were not shown because too many files have changed in this diff Show More