Removed PE-bliss, win32 binares so far remain without icon, had many issues with it:

-corrupted 32 binaries without reason
-does not support upx binaries
-forces dependency o libstdc++
This commit is contained in:
Juan Linietsky 2016-02-04 20:03:03 -03:00
parent d826b1db2a
commit 80e88c6a50
88 changed files with 2 additions and 18502 deletions

View File

@ -31,7 +31,6 @@
#endif
#ifdef TOOLS_ENABLED
#include "pe_bliss/pe_bliss_godot.h"
#include "platform/windows/export/export.h"
#endif

View File

@ -1,345 +1,6 @@
/*************************************************************************/
/* export.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2016 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 "os/os.h"
#include "globals.h"
#include "tools/editor/editor_node.h"
#include "tools/pe_bliss/pe_bliss_godot.h"
/**
@author Masoud BaniHashemian <masoudbh3@gmail.com>
*/
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, int p_flags) {
Error err = EditorExportPlatformPC::export_project(p_path, p_debug, p_flags);
if(err != OK)
{
return err;
}
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 = pe_bliss_add_resrc(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="Godot Engine";
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;
}
#include "tools/editor/editor_import_export.h"
void register_windows_exporter() {
@ -348,7 +9,7 @@ void register_windows_exporter() {
logo->create_from_image(img);
{
Ref<EditorExportPlatformWindows> exporter = Ref<EditorExportPlatformWindows>( memnew(EditorExportPlatformWindows) );
Ref<EditorExportPlatformPC> exporter = Ref<EditorExportPlatformPC>( memnew(EditorExportPlatformPC) );
exporter->set_binary_extension("exe");
exporter->set_release_binary32("windows_32_release.exe");
exporter->set_debug_binary32("windows_32_debug.exe");

View File

@ -1,37 +1,4 @@
#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:
Error export_project(const String& p_path, bool p_debug,int p_flags=0);
EditorExportPlatformWindows();
};
void register_windows_exporter();

View File

@ -11,7 +11,6 @@ if (env["tools"]!="no"):
SConscript('collada/SCsub');
SConscript('docdump/SCsub');
SConscript('freetype/SCsub');
SConscript('pe_bliss/SCsub');
SConscript('doc/SCsub')
SConscript('pck/SCsub')

View File

@ -1,84 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
Открытая бесплатная библиотека для работы с 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

View File

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

View File

@ -1,111 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 <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

@ -1,51 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,440 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 "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

@ -1,199 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,81 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 "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

@ -1,56 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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_;
};
}

File diff suppressed because it is too large Load Diff

View File

@ -1,544 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,39 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,118 +0,0 @@
#include "pe_bliss/pe_bliss.h"
#include "pe_bliss/pe_bliss_resources.h"
#include "core/ustring.h"
#include "core/dvector.h"
#include "os/file_access.h"
using namespace pe_bliss;
String pe_bliss_add_resrc(const char* p_path, int version_major, int version_minor,
String& company_name, String& file_description,
String& legal_copyright, String& version_text,
String& product_name, String& godot_version,
DVector<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

@ -1,7 +0,0 @@
String pe_bliss_add_resrc(const char* p_path, int version_major, int version_minor,
String& company_name, String& file_description,
String& legal_copyright, String& version_text,
String& product_name, String& godot_version,
DVector<uint8_t>& icon_content);

View File

@ -1,36 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,311 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 <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

@ -1,108 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,103 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 "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

@ -1,30 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,865 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 <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;
}
}

View File

@ -1,324 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,59 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 "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

@ -1,50 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,186 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 <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

@ -1,97 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,40 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 "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

@ -1,130 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,177 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 "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

@ -1,88 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,700 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 <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

@ -1,184 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,43 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 "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

@ -1,39 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,777 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 <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

@ -1,208 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,557 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 <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

@ -1,184 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,41 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 "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

@ -1,236 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,645 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 <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

@ -1,277 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 "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

@ -1,214 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 "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

@ -1,40 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,320 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 <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

@ -1,122 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,286 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 <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

@ -1,113 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,382 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 <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

@ -1,153 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,726 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 <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

@ -1,245 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,152 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 "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

@ -1,58 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,303 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 <algorithm>
#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

@ -1,158 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

View File

@ -1,396 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 <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;
}
}

View File

@ -1,122 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,86 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 <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

@ -1,50 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,75 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 "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

@ -1,47 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,521 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 <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

@ -1,84 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,447 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 <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

@ -1,94 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,48 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 "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

@ -1,48 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,34 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,131 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 "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

@ -1,49 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,109 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 "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

@ -1,57 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,311 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 "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

@ -1,67 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,283 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 <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

@ -1,52 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,45 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,85 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 <string.h>
#include "utils.h"
#include "pe_exception.h"
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;
int len = str.length();
ret.resize(len);
for(int i=0;i<len;i++) {
ret[i]=str[i]&0xFFFF;
}
return ret;
}
const std::wstring pe_utils::from_ucs2(const u16string& str)
{
std::wstring ret;
if(str.empty())
return ret;
int len = str.length();
ret.resize(str.length());
for(int i=0;i<len;i++) {
ret[i]=str[i];
}
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));
}
}

View File

@ -1,105 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,184 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 <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

@ -1,79 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,38 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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

@ -1,180 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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 <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

@ -1,89 +0,0 @@
/*************************************************************************/
/* Copyright (c) 2015 dx, http://kaimi.ru */
/* */
/* 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. */
/*************************************************************************/
#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_;
};
}