mirror of
https://github.com/godotengine/godot.git
synced 2024-11-25 21:52:51 +00:00
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:
parent
d826b1db2a
commit
80e88c6a50
@ -31,7 +31,6 @@
|
||||
#endif
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
#include "pe_bliss/pe_bliss_godot.h"
|
||||
#include "platform/windows/export/export.h"
|
||||
#endif
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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')
|
||||
|
||||
|
@ -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
|
@ -1,5 +0,0 @@
|
||||
Import('env')
|
||||
|
||||
env.add_source_files(env.tool_sources,"*.cpp")
|
||||
|
||||
Export('env')
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
};
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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_;
|
||||
};
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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
@ -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);
|
||||
};
|
||||
}
|
@ -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"
|
@ -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());
|
||||
}
|
||||
}
|
@ -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);
|
@ -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"
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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_;
|
||||
};
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -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_;
|
||||
}
|
||||
}
|
@ -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_;
|
||||
};
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
};
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
};
|
||||
}
|
@ -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>;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
};
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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;
|
||||
};
|
||||
};
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -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_;
|
||||
}
|
||||
}
|
@ -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
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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_;
|
||||
};
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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_;
|
||||
};
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
};
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
};
|
||||
}
|
@ -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_;
|
||||
}
|
||||
}
|
@ -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_;
|
||||
};
|
||||
}
|
@ -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")
|
@ -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());
|
||||
}
|
||||
}
|
@ -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_;
|
||||
};
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
};
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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();
|
||||
};
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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_;
|
||||
};
|
||||
}
|
@ -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
|
@ -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));
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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_;
|
||||
};
|
||||
}
|
@ -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;
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
@ -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_;
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user