Jump to content

C++ Library to work with Windows Portable Executable files


Tricker

Recommended Posts

Summary:

  • Read 32- and 64-bit PE files (PE, PE+) for Windows, work similar with both formats
  • Rebuild 32- and 64-bit PE files
  • Work with directories and headers
  • Convert addresses
  • Read and write PE sections
  • Read and write imports
  • Read and write exports
  • Read and write relocations
  • Read and write resources
  • Read and write TLS
  • Read and write image config
  • Read and write basic .NET information
  • Read bound imports
  • Read exception directory (PE+ only)
  • Read debug directory and extended debug information
  • Calculate entropy
  • Change file alignment
  • Change base address
  • Work with DOS Stub and Rich overlay
  • High-level resource reading: bitmaps, icons, cursors, version info, string and message tables
  • High-level resource editing: bitmaps, icons, cursors, version info

Library code is commented in English well. 25 samples included (with Russian comments) showing how to use different functions of library. MSVC++ 2008 and 2010 solutions included. There's no documentation, probably it will be written in the future.

Library doesn't use WinAPI and other libraries except STL. Crossplatform version can be released in the future, but it's not so easy at this time because of wchar_t type size differences on Windows and Linux (PE files have lots of UTF-16 strings) and some other problems.

Library code can be built for Windows x86 and x64, but x64 build is not necessary if you want to work with PE+, x86 is enough. Library doesn't use WinAPI and doesn't execute PE files, so it's safe to use it with suspicious binaries.

Repo and source download: http://code.google.c...utable-library/

Project page: https://kaimi.ru/201...utable-library/

Author's blog: https://kaimi.ru/

Usage example:


#include <iostream>
#include <fstream>
#include <pe_factory.h>
#include <pe_resource_manager.h>
#include "resource.h"
#include "lib.h"
//Sample showing how to edit PE resources
//Learn resource_viewer example first
//Example is compatible with x86 and x64 and will work in both variants
int main(int argc, char* argv[])
{
//Open file (ourselves)
std::ifstream pe_file(argv[0], std::ios::in | std::ios::binary);
if(!pe_file)
{
std::cout << "Cannot open " << argv[0] << std::endl;
return -1;
}
try
{
//Create PE or PE+ class object with the help of factory
std::auto_ptr<pe_base> image = pe_factory::create_pe(pe_file);
//The aim of this sample:
//This example binary file has an icon inside "CUSTOM" resource directory
//This icon has three different resolution bitmaps
//We will read this icon from CUSTOM directory and set is as main executable icon
//Then we will delete CUSTOM directory
//Finally, we will generate some version information for this binary
//Check if we have resource directory
if(!image->has_resources())
{
std::cout << "Image has no resources" << std::endl;
return 0;
}
//Get resource root directory
std::cout << "Reading PE resources..." << std::hex << std::showbase << std::endl << std::endl;
pe_base::resource_directory root = image->get_resources();
//To simplify reading and editing of resources there are some helper classes
//This class allows to edit and read any resources from root resource directory
//and has some high-level functions to read icons, cursors, bitmaps, string and message tables and version information
//and to write icons, cursors, bitmaps, string and message tables
pe_resource_manager res(root);
//Check CUSTOM directory existence
if(!res.resource_exists(L"CUSTOM"))
{
std::cout << "\"CUSTOM\" resource directory does not exist" << std::endl;
return -1;
}
//Get the icon from this directory: we know its ID=100 and it is the only one in this directory
//Get it by zero index (it is also possible to get it by language, but it is the only one, so no need for this)
const pe_resource_viewer::resource_data_info data = res.get_resource_data_by_id(L"CUSTOM", IDR_CUSTOM1);
//Now we add it as main executable icon
//Main icon is icon from the very first icon group
//Remember that named resources come first, and resources with ID next, and everything is sorted
//Create MAIN_ICON icon group
res.add_icon(data.get_data(), //Icon file data
L"MAIN_ICON", //Icon group name (all three icon bitmaps will be placed inside this group)
0, //Language - does not matter
pe_resource_manager::icon_place_after_max_icon_id, //Icon placement method - does not matter, because we are creating the new icon group
data.get_codepage(), //Keep Codepage
0 //Timestamp - does not matter
); //Remove CUSTOM directory, we do not need it anymore
res.remove_resource(L"CUSTOM"); //Now create version info
pe_resource_viewer::file_version_info file_info; //Basic file info
file_info.set_special_build(true); //Let this build be special
file_info.set_file_os(pe_resource_viewer::file_version_info::file_os_nt_win32); //OS
file_info.set_file_version_ms(0x00010002); //File version: 1.2.3.4
file_info.set_file_version_ls(0x00030004);
//Now create version strings and translations
pe_resource_viewer::lang_string_values_map strings;
pe_resource_viewer::translation_values_map translations;
//There is also helper class to work with this stuff
version_info_editor version(strings, translations);
//Add translation - default process language, UNICODE
//We also can specify language and codepage
version.add_translation(version_info_editor::default_language_translation);
//Strings will be added to default translation (default_language_translation)
//If there is no default one, then to the first existent
//If there is no translations, the default one will be added automatically (default_language_translation)
//So, add_translation call can be skipped here
//We can specify any version info strings like that:
version.set_company_name(L"Kaimi.ru DX");
version.set_file_description(L"Generated file version info");
version.set_internal_name(L"Tralala.exe");
version.set_legal_copyright(L"(C) DX Portable Executable Library");
version.set_original_filename(L"resource_editor.exe");
version.set_product_name(L"PE Resource Editor Example");
version.set_product_version(L"x.y.z");
//We can also add our very own string: it will be saved to version information
//but Windows Explorer will not show it
version.set_property(L"MyLittleProperty", L"Secret Value");
//Set version information
res.set_version_info(file_info, strings, translations, 1033); //1033 - Russian language //Now we are renaming old resource section
//(.rsrc)
//It is necessary to allow Windows Explorer read our icon from the new resource directory and section
image->section_from_directory(IMAGE_DIRECTORY_ENTRY_RESOURCE).set_name("oldres");
//Rebuild resources
//They will be bigger than used to be
//so we will create a new section for them
//(we cannot enlarge existing sections, apart from the very last section in PE file)
pe_base::section new_resources;
new_resources.get_raw_data().resize(1); //We cannot add empty sections, so let it have raw size 1
new_resources.set_name(".rsrc"); //Section name
new_resources.readable(true); //Readable only
pe_base::section& attached_section = image->add_section(new_resources); //Add section and get added and recalculated section //Rebuild resources, put it in the beginning of our new section, fix PE header
image->rebuild_resources(root, attached_section);
//Create new PE file
std::string base_file_name(argv[0]);
std::string::size_type slash_pos;
if((slash_pos = base_file_name.find_last_of("/\\")) != std::string::npos)
base_file_name = base_file_name.substr(slash_pos + 1);
base_file_name = "new_" + base_file_name;
std::ofstream new_pe_file(base_file_name.c_str(), std::ios::out | std::ios::binary | std::ios::trunc);
if(!new_pe_file)
{
std::cout << "Cannot create " << base_file_name << std::endl;
return -1;
}
//Rebuild PE file
image->rebuild_pe(new_pe_file);
std::cout << "PE was rebuilt and saved to " << base_file_name << std::endl;
}
catch(const pe_exception& e)
{
//On error
std::cout << "Error: " << e.what() << std::endl;
return -1;
}
return 0;
}
Edited by Tricker
Link to comment

* Copyright © 2004 - 2005 Sebastian Porst (webmaster@the-interweb.com)

* All rights reserved.

looks very much like pelib to me.
/>http://www.pelib.com/index.php

Link to comment

How is it better?

I love such questions. So, I need to provide comparison table cause it's easier to ask than to spent 10-15 mins to overlook available methods. OK, will be done...

Link to comment

yes.

it`s common practice that if you improve existing code you state what you improved, a simple "it`s better, believe me" wont do.

Also, no one will spent 15+ min going through two sources he doesn't even know to try to tell which one`s better.

that`s just the way it is. :)

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...