2015-11-08 22:54:41 +00:00
/*************************************************************************/
/* 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. */
/*************************************************************************/
2015-11-08 22:53:58 +00:00
# include <string>
# include <vector>
# include <istream>
# include <ostream>
# include <algorithm>
# include <cmath>
# include <set>
# include <string.h>
# include "pe_exception.h"
# include "pe_base.h"
namespace pe_bliss
{
using namespace pe_win ;
//Constructor
pe_base : : pe_base ( std : : istream & file , const pe_properties & props , bool read_debug_raw_data )
{
props_ = props . duplicate ( ) . release ( ) ;
//Save istream state
std : : ios_base : : iostate state = file . exceptions ( ) ;
std : : streamoff old_offset = file . tellg ( ) ;
try
{
file . exceptions ( std : : ios : : goodbit ) ;
//Read DOS header, PE headers and section data
read_dos_header ( file ) ;
read_pe ( file , read_debug_raw_data ) ;
}
catch ( const std : : exception & )
{
//If something went wrong, restore istream state
file . seekg ( old_offset ) ;
file . exceptions ( state ) ;
file . clear ( ) ;
//Rethrow
throw ;
}
//Restore istream state
file . seekg ( old_offset ) ;
file . exceptions ( state ) ;
file . clear ( ) ;
}
pe_base : : pe_base ( const pe_properties & props , uint32_t section_alignment , bool dll , uint16_t subsystem )
{
props_ = props . duplicate ( ) . release ( ) ;
props_ - > create_pe ( section_alignment , subsystem ) ;
has_overlay_ = false ;
memset ( & dos_header_ , 0 , sizeof ( dos_header_ ) ) ;
dos_header_ . e_magic = 0x5A4D ; //"MZ"
//Magic numbers from MSVC++ build
dos_header_ . e_maxalloc = 0xFFFF ;
dos_header_ . e_cblp = 0x90 ;
dos_header_ . e_cp = 3 ;
dos_header_ . e_cparhdr = 4 ;
dos_header_ . e_sp = 0xB8 ;
dos_header_ . e_lfarlc = 64 ;
set_characteristics ( image_file_executable_image | image_file_relocs_stripped ) ;
if ( get_pe_type ( ) = = pe_type_32 )
set_characteristics_flags ( image_file_32bit_machine ) ;
if ( dll )
set_characteristics_flags ( image_file_dll ) ;
set_subsystem_version ( 5 , 1 ) ; //WinXP
set_os_version ( 5 , 1 ) ; //WinXP
}
pe_base : : pe_base ( const pe_base & pe )
: dos_header_ ( pe . dos_header_ ) ,
rich_overlay_ ( pe . rich_overlay_ ) ,
sections_ ( pe . sections_ ) ,
has_overlay_ ( pe . has_overlay_ ) ,
full_headers_data_ ( pe . full_headers_data_ ) ,
debug_data_ ( pe . debug_data_ ) ,
props_ ( 0 )
{
props_ = pe . props_ - > duplicate ( ) . release ( ) ;
}
pe_base & pe_base : : operator = ( const pe_base & pe )
{
dos_header_ = pe . dos_header_ ;
rich_overlay_ = pe . rich_overlay_ ;
sections_ = pe . sections_ ;
has_overlay_ = pe . has_overlay_ ;
full_headers_data_ = pe . full_headers_data_ ;
debug_data_ = pe . debug_data_ ;
delete props_ ;
props_ = 0 ;
props_ = pe . props_ - > duplicate ( ) . release ( ) ;
return * this ;
}
pe_base : : ~ pe_base ( )
{
delete props_ ;
}
//Returns dos header
const image_dos_header & pe_base : : get_dos_header ( ) const
{
return dos_header_ ;
}
//Returns dos header
image_dos_header & pe_base : : get_dos_header ( )
{
return dos_header_ ;
}
//Returns PE headers start position (e_lfanew)
int32_t pe_base : : get_pe_header_start ( ) const
{
return dos_header_ . e_lfanew ;
}
//Strips MSVC stub overlay
void pe_base : : strip_stub_overlay ( )
{
rich_overlay_ . clear ( ) ;
}
//Fills MSVC stub overlay with character c
void pe_base : : fill_stub_overlay ( char c )
{
if ( rich_overlay_ . length ( ) )
rich_overlay_ . assign ( rich_overlay_ . length ( ) , c ) ;
}
//Sets stub MSVS overlay
void pe_base : : set_stub_overlay ( const std : : string & data )
{
rich_overlay_ = data ;
}
//Returns stub overlay
const std : : string & pe_base : : get_stub_overlay ( ) const
{
return rich_overlay_ ;
}
//Realigns all sections
void pe_base : : realign_all_sections ( )
{
for ( unsigned int i = 0 ; i < sections_ . size ( ) ; i + + )
realign_section ( i ) ;
}
//Returns number of sections from PE header
uint16_t pe_base : : get_number_of_sections ( ) const
{
return props_ - > get_number_of_sections ( ) ;
}
//Updates number of sections in PE header
uint16_t pe_base : : update_number_of_sections ( )
{
uint16_t new_number = static_cast < uint16_t > ( sections_ . size ( ) ) ;
props_ - > set_number_of_sections ( new_number ) ;
return new_number ;
}
//Returns section alignment
uint32_t pe_base : : get_section_alignment ( ) const
{
return props_ - > get_section_alignment ( ) ;
}
//Returns image sections list
section_list & pe_base : : get_image_sections ( )
{
return sections_ ;
}
//Returns image sections list
const section_list & pe_base : : get_image_sections ( ) const
{
return sections_ ;
}
//Realigns section by index
void pe_base : : realign_section ( uint32_t index )
{
//Check index
if ( sections_ . size ( ) < = index )
throw pe_exception ( " Section not found " , pe_exception : : section_not_found ) ;
//Get section iterator
section_list : : iterator it = sections_ . begin ( ) + index ;
section & s = * it ;
//Calculate, how many null bytes we have in the end of raw section data
std : : size_t strip = 0 ;
for ( std : : size_t i = ( * it ) . get_raw_data ( ) . length ( ) ; i > = 1 ; - - i )
{
if ( s . get_raw_data ( ) [ i - 1 ] = = 0 )
strip + + ;
else
break ;
}
if ( it = = sections_ . end ( ) - 1 ) //If we're realigning the last section
{
//We can strip ending null bytes
s . set_size_of_raw_data ( static_cast < uint32_t > ( s . get_raw_data ( ) . length ( ) - strip ) ) ;
s . get_raw_data ( ) . resize ( s . get_raw_data ( ) . length ( ) - strip , 0 ) ;
}
else
{
//Else just set size of raw data
uint32_t raw_size_aligned = s . get_aligned_raw_size ( get_file_alignment ( ) ) ;
s . set_size_of_raw_data ( raw_size_aligned ) ;
s . get_raw_data ( ) . resize ( raw_size_aligned , 0 ) ;
}
}
//Returns file alignment
uint32_t pe_base : : get_file_alignment ( ) const
{
return props_ - > get_file_alignment ( ) ;
}
//Sets file alignment
void pe_base : : set_file_alignment ( uint32_t alignment )
{
//Check alignment
if ( alignment < minimum_file_alignment )
throw pe_exception ( " File alignment can't be less than 512 " , pe_exception : : incorrect_file_alignment ) ;
if ( ! pe_utils : : is_power_of_2 ( alignment ) )
throw pe_exception ( " File alignment must be a power of 2 " , pe_exception : : incorrect_file_alignment ) ;
if ( alignment > get_section_alignment ( ) )
throw pe_exception ( " File alignment must be <= section alignment " , pe_exception : : incorrect_file_alignment ) ;
//Set file alignment without any additional checks
set_file_alignment_unchecked ( alignment ) ;
}
//Returns size of image
uint32_t pe_base : : get_size_of_image ( ) const
{
return props_ - > get_size_of_image ( ) ;
}
//Returns image entry point
uint32_t pe_base : : get_ep ( ) const
{
return props_ - > get_ep ( ) ;
}
//Sets image entry point (just a value of PE header)
void pe_base : : set_ep ( uint32_t new_ep )
{
props_ - > set_ep ( new_ep ) ;
}
//Returns number of RVA and sizes (number of DATA_DIRECTORY entries)
uint32_t pe_base : : get_number_of_rvas_and_sizes ( ) const
{
return props_ - > get_number_of_rvas_and_sizes ( ) ;
}
//Sets number of RVA and sizes (number of DATA_DIRECTORY entries)
void pe_base : : set_number_of_rvas_and_sizes ( uint32_t number )
{
props_ - > set_number_of_rvas_and_sizes ( number ) ;
}
//Returns PE characteristics
uint16_t pe_base : : get_characteristics ( ) const
{
return props_ - > get_characteristics ( ) ;
}
//Sets PE characteristics (a value inside header)
void pe_base : : set_characteristics ( uint16_t ch )
{
props_ - > set_characteristics ( ch ) ;
}
//Returns section from RVA
section & pe_base : : section_from_rva ( uint32_t rva )
{
//Search for section
for ( section_list : : iterator i = sections_ . begin ( ) ; i ! = sections_ . end ( ) ; + + i )
{
section & s = * i ;
//Return section if found
if ( rva > = s . get_virtual_address ( ) & & rva < s . get_virtual_address ( ) + s . get_aligned_virtual_size ( get_section_alignment ( ) ) )
return s ;
}
throw pe_exception ( " No section found by presented address " , pe_exception : : no_section_found ) ;
}
//Returns section from RVA
const section & pe_base : : section_from_rva ( uint32_t rva ) const
{
//Search for section
for ( section_list : : const_iterator i = sections_ . begin ( ) ; i ! = sections_ . end ( ) ; + + i )
{
const section & s = * i ;
//Return section if found
if ( rva > = s . get_virtual_address ( ) & & rva < s . get_virtual_address ( ) + s . get_aligned_virtual_size ( get_section_alignment ( ) ) )
return s ;
}
throw pe_exception ( " No section found by presented address " , pe_exception : : no_section_found ) ;
}
//Returns section from directory ID
section & pe_base : : section_from_directory ( uint32_t directory_id )
{
return section_from_rva ( get_directory_rva ( directory_id ) ) ;
}
//Returns section from directory ID
const section & pe_base : : section_from_directory ( uint32_t directory_id ) const
{
return section_from_rva ( get_directory_rva ( directory_id ) ) ;
}
//Sets section virtual size (actual for the last one of this PE or for unbound section)
void pe_base : : set_section_virtual_size ( section & s , uint32_t vsize )
{
//Check if we're changing virtual size of the last section
//Of course, we can change virtual size of section that's not bound to this PE file
if ( sections_ . empty ( ) | | std : : find_if ( sections_ . begin ( ) , sections_ . end ( ) - 1 , section_ptr_finder ( s ) ) ! = sections_ . end ( ) - 1 )
throw pe_exception ( " Can't change virtual size of any section, except last one " , pe_exception : : error_changing_section_virtual_size ) ;
//If we're setting virtual size to zero
if ( vsize = = 0 )
{
//Check if section is empty
if ( s . empty ( ) )
throw pe_exception ( " Cannot set virtual size of empty section to zero " , pe_exception : : error_changing_section_virtual_size ) ;
//Set virtual size equal to aligned size of raw data
s . set_virtual_size ( s . get_size_of_raw_data ( ) ) ;
}
else
{
s . set_virtual_size ( vsize ) ;
}
//Update image size if we're changing virtual size for the last section of this PE
if ( ! sections_ . empty ( ) | | & s = = & ( * ( sections_ . end ( ) - 1 ) ) )
update_image_size ( ) ;
}
//Expands section raw or virtual size to hold data from specified RVA with specified size
//Section must be free (not bound to any image)
//or the last section of this image
bool pe_base : : expand_section ( section & s , uint32_t needed_rva , uint32_t needed_size , section_expand_type expand )
{
//Check if we're changing the last section
//Of course, we can change the section that's not bound to this PE file
if ( sections_ . empty ( ) | | std : : find_if ( sections_ . begin ( ) , sections_ . end ( ) - 1 , section_ptr_finder ( s ) ) ! = sections_ . end ( ) - 1 )
throw pe_exception ( " Can't expand any section, except last one " , pe_exception : : error_expanding_section ) ;
//Check if we should expand our section
if ( expand = = expand_section_raw & & section_data_length_from_rva ( s , needed_rva , section_data_raw ) < needed_size )
{
//Expand section raw data
s . get_raw_data ( ) . resize ( needed_rva - s . get_virtual_address ( ) + needed_size ) ;
recalculate_section_sizes ( s , false ) ;
return true ;
}
else if ( expand = = expand_section_virtual & & section_data_length_from_rva ( s , needed_rva , section_data_virtual ) < needed_size )
{
//Expand section virtual data
set_section_virtual_size ( s , needed_rva - s . get_virtual_address ( ) + needed_size ) ;
return true ;
}
return false ;
}
//Updates image virtual size
void pe_base : : update_image_size ( )
{
//Write virtual size of image to headers
if ( ! sections_ . empty ( ) )
set_size_of_image ( sections_ . back ( ) . get_virtual_address ( ) + sections_ . back ( ) . get_aligned_virtual_size ( get_section_alignment ( ) ) ) ;
else
set_size_of_image ( get_size_of_headers ( ) ) ;
}
//Returns checksum of PE file from header
uint32_t pe_base : : get_checksum ( ) const
{
return props_ - > get_checksum ( ) ;
}
//Sets checksum of PE file
void pe_base : : set_checksum ( uint32_t checksum )
{
props_ - > set_checksum ( checksum ) ;
}
//Returns timestamp of PE file from header
uint32_t pe_base : : get_time_date_stamp ( ) const
{
return props_ - > get_time_date_stamp ( ) ;
}
//Sets timestamp of PE file
void pe_base : : set_time_date_stamp ( uint32_t timestamp )
{
props_ - > set_time_date_stamp ( timestamp ) ;
}
//Returns Machine field value of PE file from header
uint16_t pe_base : : get_machine ( ) const
{
return props_ - > get_machine ( ) ;
}
//Sets Machine field value of PE file
void pe_base : : set_machine ( uint16_t machine )
{
props_ - > set_machine ( machine ) ;
}
//Prepares section before attaching it
void pe_base : : prepare_section ( section & s )
{
//Calculate its size of raw data
s . set_size_of_raw_data ( static_cast < uint32_t > ( pe_utils : : align_up ( s . get_raw_data ( ) . length ( ) , get_file_alignment ( ) ) ) ) ;
//Check section virtual and raw size
if ( ! s . get_size_of_raw_data ( ) & & ! s . get_virtual_size ( ) )
throw pe_exception ( " Virtual and Physical sizes of section can't be 0 at the same time " , pe_exception : : zero_section_sizes ) ;
//If section virtual size is zero
if ( ! s . get_virtual_size ( ) )
{
s . set_virtual_size ( s . get_size_of_raw_data ( ) ) ;
}
else
{
//Else calculate its virtual size
s . set_virtual_size (
std : : max < uint32_t > ( pe_utils : : align_up ( s . get_size_of_raw_data ( ) , get_file_alignment ( ) ) ,
pe_utils : : align_up ( s . get_virtual_size ( ) , get_section_alignment ( ) ) ) ) ;
}
}
//Adds section to image
section & pe_base : : add_section ( section s )
{
if ( sections_ . size ( ) > = maximum_number_of_sections )
throw pe_exception ( " Maximum number of sections has been reached " , pe_exception : : no_more_sections_can_be_added ) ;
//Prepare section before adding it
prepare_section ( s ) ;
//Calculate section virtual address
if ( ! sections_ . empty ( ) )
{
s . set_virtual_address ( pe_utils : : align_up ( sections_ . back ( ) . get_virtual_address ( ) + sections_ . back ( ) . get_aligned_virtual_size ( get_section_alignment ( ) ) , get_section_alignment ( ) ) ) ;
//We should align last section raw size, if it wasn't aligned
section & last = sections_ . back ( ) ;
last . set_size_of_raw_data ( static_cast < uint32_t > ( pe_utils : : align_up ( last . get_raw_data ( ) . length ( ) , get_file_alignment ( ) ) ) ) ;
}
else
{
s . set_virtual_address (
s . get_virtual_address ( ) = = 0
? pe_utils : : align_up ( get_size_of_headers ( ) , get_section_alignment ( ) )
: pe_utils : : align_up ( s . get_virtual_address ( ) , get_section_alignment ( ) ) ) ;
}
//Add section to the end of section list
sections_ . push_back ( s ) ;
//Set number of sections in PE header
set_number_of_sections ( static_cast < uint16_t > ( sections_ . size ( ) ) ) ;
//Recalculate virtual size of image
set_size_of_image ( get_size_of_image ( ) + s . get_aligned_virtual_size ( get_section_alignment ( ) ) ) ;
//Return last section
return sections_ . back ( ) ;
}
//Returns true if sectios "s" is already attached to this PE file
bool pe_base : : section_attached ( const section & s ) const
{
return sections_ . end ( ) ! = std : : find_if ( sections_ . begin ( ) , sections_ . end ( ) , section_ptr_finder ( s ) ) ;
}
//Returns true if directory exists
bool pe_base : : directory_exists ( uint32_t id ) const
{
return props_ - > directory_exists ( id ) ;
}
//Removes directory
void pe_base : : remove_directory ( uint32_t id )
{
props_ - > remove_directory ( id ) ;
}
//Returns directory RVA
uint32_t pe_base : : get_directory_rva ( uint32_t id ) const
{
return props_ - > get_directory_rva ( id ) ;
}
//Returns directory size
uint32_t pe_base : : get_directory_size ( uint32_t id ) const
{
return props_ - > get_directory_size ( id ) ;
}
//Sets directory RVA (just a value of PE header, no moving occurs)
void pe_base : : set_directory_rva ( uint32_t id , uint32_t rva )
{
return props_ - > set_directory_rva ( id , rva ) ;
}
//Sets directory size (just a value of PE header, no moving occurs)
void pe_base : : set_directory_size ( uint32_t id , uint32_t size )
{
return props_ - > set_directory_size ( id , size ) ;
}
//Strips only zero DATA_DIRECTORY entries to count = min_count
//Returns resulting number of data directories
//strip_iat_directory - if true, even not empty IAT directory will be stripped
uint32_t pe_base : : strip_data_directories ( uint32_t min_count , bool strip_iat_directory )
{
return props_ - > strip_data_directories ( min_count , strip_iat_directory ) ;
}
//Returns true if image has import directory
bool pe_base : : has_imports ( ) const
{
return directory_exists ( image_directory_entry_import ) ;
}
//Returns true if image has export directory
bool pe_base : : has_exports ( ) const
{
return directory_exists ( image_directory_entry_export ) ;
}
//Returns true if image has resource directory
bool pe_base : : has_resources ( ) const
{
return directory_exists ( image_directory_entry_resource ) ;
}
//Returns true if image has security directory
bool pe_base : : has_security ( ) const
{
return directory_exists ( image_directory_entry_security ) ;
}
//Returns true if image has relocations
bool pe_base : : has_reloc ( ) const
{
return directory_exists ( image_directory_entry_basereloc ) & & ! ( get_characteristics ( ) & image_file_relocs_stripped ) ;
}
//Returns true if image has TLS directory
bool pe_base : : has_tls ( ) const
{
return directory_exists ( image_directory_entry_tls ) ;
}
//Returns true if image has config directory
bool pe_base : : has_config ( ) const
{
return directory_exists ( image_directory_entry_load_config ) ;
}
//Returns true if image has bound import directory
bool pe_base : : has_bound_import ( ) const
{
return directory_exists ( image_directory_entry_bound_import ) ;
}
//Returns true if image has delay import directory
bool pe_base : : has_delay_import ( ) const
{
return directory_exists ( image_directory_entry_delay_import ) ;
}
//Returns true if image has COM directory
bool pe_base : : is_dotnet ( ) const
{
return directory_exists ( image_directory_entry_com_descriptor ) ;
}
//Returns true if image has exception directory
bool pe_base : : has_exception_directory ( ) const
{
return directory_exists ( image_directory_entry_exception ) ;
}
//Returns true if image has debug directory
bool pe_base : : has_debug ( ) const
{
return directory_exists ( image_directory_entry_debug ) ;
}
//Returns corresponding section data pointer from RVA inside section "s" (checks bounds)
char * pe_base : : section_data_from_rva ( section & s , uint32_t rva )
{
//Check if RVA is inside section "s"
if ( rva > = s . get_virtual_address ( ) & & rva < s . get_virtual_address ( ) + s . get_aligned_virtual_size ( get_section_alignment ( ) ) )
{
if ( s . get_raw_data ( ) . empty ( ) )
throw pe_exception ( " Section raw data is empty and cannot be changed " , pe_exception : : section_is_empty ) ;
return & s . get_raw_data ( ) [ rva - s . get_virtual_address ( ) ] ;
}
throw pe_exception ( " RVA not found inside section " , pe_exception : : rva_not_exists ) ;
}
//Returns corresponding section data pointer from RVA inside section "s" (checks bounds)
const char * pe_base : : section_data_from_rva ( const section & s , uint32_t rva , section_data_type datatype ) const
{
//Check if RVA is inside section "s"
if ( rva > = s . get_virtual_address ( ) & & rva < s . get_virtual_address ( ) + s . get_aligned_virtual_size ( get_section_alignment ( ) ) )
return ( datatype = = section_data_raw ? s . get_raw_data ( ) . data ( ) : s . get_virtual_data ( get_section_alignment ( ) ) . c_str ( ) ) + rva - s . get_virtual_address ( ) ;
throw pe_exception ( " RVA not found inside section " , pe_exception : : rva_not_exists ) ;
}
//Returns section TOTAL RAW/VIRTUAL data length from RVA inside section
uint32_t pe_base : : section_data_length_from_rva ( uint32_t rva , section_data_type datatype , bool include_headers ) const
{
//if RVA is inside of headers and we're searching them too...
if ( include_headers & & rva < full_headers_data_ . length ( ) )
return static_cast < unsigned long > ( full_headers_data_ . length ( ) ) ;
const section & s = section_from_rva ( rva ) ;
return static_cast < unsigned long > ( datatype = = section_data_raw ? s . get_raw_data ( ) . length ( ) /* instead of SizeOfRawData */ : s . get_aligned_virtual_size ( get_section_alignment ( ) ) ) ;
}
//Returns section TOTAL RAW/VIRTUAL data length from VA inside section for PE32
uint32_t pe_base : : section_data_length_from_va ( uint32_t va , section_data_type datatype , bool include_headers ) const
{
return section_data_length_from_rva ( va_to_rva ( va ) , datatype , include_headers ) ;
}
//Returns section TOTAL RAW/VIRTUAL data length from VA inside section for PE32/PE64
uint32_t pe_base : : section_data_length_from_va ( uint64_t va , section_data_type datatype , bool include_headers ) const
{
return section_data_length_from_rva ( va_to_rva ( va ) , datatype , include_headers ) ;
}
//Returns section remaining RAW/VIRTUAL data length from RVA "rva_inside" to the end of section containing RVA "rva"
uint32_t pe_base : : section_data_length_from_rva ( uint32_t rva , uint32_t rva_inside , section_data_type datatype , bool include_headers ) const
{
//if RVAs are inside of headers and we're searching them too...
if ( include_headers & & rva < full_headers_data_ . length ( ) & & rva_inside < full_headers_data_ . length ( ) )
return static_cast < unsigned long > ( full_headers_data_ . length ( ) - rva_inside ) ;
const section & s = section_from_rva ( rva ) ;
if ( rva_inside < s . get_virtual_address ( ) )
throw pe_exception ( " RVA not found inside section " , pe_exception : : rva_not_exists ) ;
//Calculate remaining length of section data from "rva" address
long length = static_cast < long > ( datatype = = section_data_raw ? s . get_raw_data ( ) . length ( ) /* instead of SizeOfRawData */ : s . get_aligned_virtual_size ( get_section_alignment ( ) ) )
+ s . get_virtual_address ( ) - rva_inside ;
if ( length < 0 )
return 0 ;
return static_cast < unsigned long > ( length ) ;
}
//Returns section remaining RAW/VIRTUAL data length from VA "va_inside" to the end of section containing VA "va" for PE32
uint32_t pe_base : : section_data_length_from_va ( uint32_t va , uint32_t va_inside , section_data_type datatype , bool include_headers ) const
{
return section_data_length_from_rva ( va_to_rva ( va ) , va_to_rva ( va_inside ) , datatype , include_headers ) ;
}
//Returns section remaining RAW/VIRTUAL data length from VA "va_inside" to the end of section containing VA "va" for PE32/PE64
uint32_t pe_base : : section_data_length_from_va ( uint64_t va , uint64_t va_inside , section_data_type datatype , bool include_headers ) const
{
return section_data_length_from_rva ( va_to_rva ( va ) , va_to_rva ( va_inside ) , datatype , include_headers ) ;
}
//Returns section remaining RAW/VIRTUAL data length from RVA to the end of section "s" (checks bounds)
uint32_t pe_base : : section_data_length_from_rva ( const section & s , uint32_t rva_inside , section_data_type datatype ) const
{
//Check rva_inside
if ( rva_inside > = s . get_virtual_address ( ) & & rva_inside < s . get_virtual_address ( ) + s . get_aligned_virtual_size ( get_section_alignment ( ) ) )
{
//Calculate remaining length of section data from "rva" address
int32_t length = static_cast < int32_t > ( datatype = = section_data_raw ? s . get_raw_data ( ) . length ( ) /* instead of SizeOfRawData */ : s . get_aligned_virtual_size ( get_section_alignment ( ) ) )
+ s . get_virtual_address ( ) - rva_inside ;
if ( length < 0 )
return 0 ;
return static_cast < uint32_t > ( length ) ;
}
throw pe_exception ( " RVA not found inside section " , pe_exception : : rva_not_exists ) ;
}
//Returns section remaining RAW/VIRTUAL data length from VA to the end of section "s" for PE32 (checks bounds)
uint32_t pe_base : : section_data_length_from_va ( const section & s , uint32_t va_inside , section_data_type datatype ) const
{
return section_data_length_from_rva ( s , va_to_rva ( va_inside ) , datatype ) ;
}
//Returns section remaining RAW/VIRTUAL data length from VA to the end of section "s" for PE32/PE64 (checks bounds)
uint32_t pe_base : : section_data_length_from_va ( const section & s , uint64_t va_inside , section_data_type datatype ) const
{
return section_data_length_from_rva ( s , va_to_rva ( va_inside ) , datatype ) ;
}
//Returns corresponding section data pointer from RVA inside section
char * pe_base : : section_data_from_rva ( uint32_t rva , bool include_headers )
{
//if RVA is inside of headers and we're searching them too...
if ( include_headers & & rva < full_headers_data_ . length ( ) )
return & full_headers_data_ [ rva ] ;
section & s = section_from_rva ( rva ) ;
if ( s . get_raw_data ( ) . empty ( ) )
throw pe_exception ( " Section raw data is empty and cannot be changed " , pe_exception : : section_is_empty ) ;
return & s . get_raw_data ( ) [ rva - s . get_virtual_address ( ) ] ;
}
//Returns corresponding section data pointer from RVA inside section
const char * pe_base : : section_data_from_rva ( uint32_t rva , section_data_type datatype , bool include_headers ) const
{
//if RVA is inside of headers and we're searching them too...
if ( include_headers & & rva < full_headers_data_ . length ( ) )
return & full_headers_data_ [ rva ] ;
const section & s = section_from_rva ( rva ) ;
return ( datatype = = section_data_raw ? s . get_raw_data ( ) . data ( ) : s . get_virtual_data ( get_section_alignment ( ) ) . c_str ( ) ) + rva - s . get_virtual_address ( ) ;
}
//Reads DOS headers from istream
void pe_base : : read_dos_header ( std : : istream & file , image_dos_header & header )
{
//Check istream flags
if ( file . bad ( ) | | file . eof ( ) )
throw pe_exception ( " PE file stream is bad or closed. " , pe_exception : : bad_pe_file ) ;
//Read DOS header and check istream
file . read ( reinterpret_cast < char * > ( & header ) , sizeof ( image_dos_header ) ) ;
if ( file . bad ( ) | | file . eof ( ) )
throw pe_exception ( " Unable to read IMAGE_DOS_HEADER " , pe_exception : : bad_dos_header ) ;
//Check DOS header magic
if ( header . e_magic ! = 0x5a4d ) //"MZ"
throw pe_exception ( " IMAGE_DOS_HEADER signature is incorrect " , pe_exception : : bad_dos_header ) ;
}
//Reads DOS headers from istream
void pe_base : : read_dos_header ( std : : istream & file )
{
read_dos_header ( file , dos_header_ ) ;
}
//Reads PE image from istream
void pe_base : : read_pe ( std : : istream & file , bool read_debug_raw_data )
{
//Get istream size
std : : streamoff filesize = pe_utils : : get_file_size ( file ) ;
//Check if PE header is DWORD-aligned
if ( ( dos_header_ . e_lfanew % sizeof ( uint32_t ) ) ! = 0 )
throw pe_exception ( " PE header is not DWORD-aligned " , pe_exception : : bad_dos_header ) ;
//Seek to NT headers
file . seekg ( dos_header_ . e_lfanew ) ;
if ( file . bad ( ) | | file . fail ( ) )
throw pe_exception ( " Cannot reach IMAGE_NT_HEADERS " , pe_exception : : image_nt_headers_not_found ) ;
//Read NT headers
file . read ( get_nt_headers_ptr ( ) , get_sizeof_nt_header ( ) - sizeof ( image_data_directory ) * image_numberof_directory_entries ) ;
if ( file . bad ( ) | | file . eof ( ) )
throw pe_exception ( " Error reading IMAGE_NT_HEADERS " , pe_exception : : error_reading_image_nt_headers ) ;
//Check PE signature
if ( get_pe_signature ( ) ! = 0x4550 ) //"PE"
throw pe_exception ( " Incorrect PE signature " , pe_exception : : pe_signature_incorrect ) ;
//Check number of directories
if ( get_number_of_rvas_and_sizes ( ) > image_numberof_directory_entries )
set_number_of_rvas_and_sizes ( image_numberof_directory_entries ) ;
if ( get_number_of_rvas_and_sizes ( ) > 0 )
{
//Read data directory headers, if any
file . read ( get_nt_headers_ptr ( ) + ( get_sizeof_nt_header ( ) - sizeof ( image_data_directory ) * image_numberof_directory_entries ) , sizeof ( image_data_directory ) * get_number_of_rvas_and_sizes ( ) ) ;
if ( file . bad ( ) | | file . eof ( ) )
throw pe_exception ( " Error reading DATA_DIRECTORY headers " , pe_exception : : error_reading_data_directories ) ;
}
//Check section number
//Images with zero section number accepted
if ( get_number_of_sections ( ) > maximum_number_of_sections )
throw pe_exception ( " Incorrect number of sections " , pe_exception : : section_number_incorrect ) ;
//Check PE magic
if ( get_magic ( ) ! = get_needed_magic ( ) )
throw pe_exception ( " Incorrect PE signature " , pe_exception : : pe_signature_incorrect ) ;
//Check section alignment
if ( ! pe_utils : : is_power_of_2 ( get_section_alignment ( ) ) )
throw pe_exception ( " Incorrect section alignment " , pe_exception : : incorrect_section_alignment ) ;
//Check file alignment
if ( ! pe_utils : : is_power_of_2 ( get_file_alignment ( ) ) )
throw pe_exception ( " Incorrect file alignment " , pe_exception : : incorrect_file_alignment ) ;
if ( get_file_alignment ( ) ! = get_section_alignment ( ) & & ( get_file_alignment ( ) < minimum_file_alignment | | get_file_alignment ( ) > get_section_alignment ( ) ) )
throw pe_exception ( " Incorrect file alignment " , pe_exception : : incorrect_file_alignment ) ;
//Check size of image
if ( pe_utils : : align_up ( get_size_of_image ( ) , get_section_alignment ( ) ) = = 0 )
throw pe_exception ( " Incorrect size of image " , pe_exception : : incorrect_size_of_image ) ;
//Read rich data overlay / DOS stub (if any)
if ( static_cast < uint32_t > ( dos_header_ . e_lfanew ) > sizeof ( image_dos_header ) )
{
rich_overlay_ . resize ( dos_header_ . e_lfanew - sizeof ( image_dos_header ) ) ;
file . seekg ( sizeof ( image_dos_header ) ) ;
file . read ( & rich_overlay_ [ 0 ] , dos_header_ . e_lfanew - sizeof ( image_dos_header ) ) ;
if ( file . bad ( ) | | file . eof ( ) )
throw pe_exception ( " Error reading 'Rich' & 'DOS stub' overlay " , pe_exception : : error_reading_overlay ) ;
}
//Calculate first section raw position
//Sum is safe here
uint32_t first_section = dos_header_ . e_lfanew + get_size_of_optional_header ( ) + sizeof ( image_file_header ) + sizeof ( uint32_t ) /* Signature */ ;
if ( get_number_of_sections ( ) > 0 )
{
//Go to first section
file . seekg ( first_section ) ;
if ( file . bad ( ) | | file . fail ( ) )
throw pe_exception ( " Cannot reach section headers " , pe_exception : : image_section_headers_not_found ) ;
}
uint32_t last_raw_size = 0 ;
//Read all sections
for ( int i = 0 ; i < get_number_of_sections ( ) ; i + + )
{
section s ;
//Read section header
file . read ( reinterpret_cast < char * > ( & s . get_raw_header ( ) ) , sizeof ( image_section_header ) ) ;
if ( file . bad ( ) | | file . eof ( ) )
throw pe_exception ( " Error reading section header " , pe_exception : : error_reading_section_header ) ;
//Save next section header position
std : : streamoff next_sect = file . tellg ( ) ;
//Check section virtual and raw sizes
if ( ! s . get_size_of_raw_data ( ) & & ! s . get_virtual_size ( ) )
throw pe_exception ( " Virtual and Physical sizes of section can't be 0 at the same time " , pe_exception : : zero_section_sizes ) ;
//Check for adequate values of section fields
if ( ! pe_utils : : is_sum_safe ( s . get_virtual_address ( ) , s . get_virtual_size ( ) ) | | s . get_virtual_size ( ) > pe_utils : : two_gb
| | ! pe_utils : : is_sum_safe ( s . get_pointer_to_raw_data ( ) , s . get_size_of_raw_data ( ) ) | | s . get_size_of_raw_data ( ) > pe_utils : : two_gb )
throw pe_exception ( " Incorrect section address or size " , pe_exception : : section_incorrect_addr_or_size ) ;
if ( s . get_size_of_raw_data ( ) ! = 0 )
{
//If section has raw data
//If section raw data size is greater than virtual, fix it
last_raw_size = s . get_size_of_raw_data ( ) ;
if ( pe_utils : : align_up ( s . get_size_of_raw_data ( ) , get_file_alignment ( ) ) > pe_utils : : align_up ( s . get_virtual_size ( ) , get_section_alignment ( ) ) )
s . set_size_of_raw_data ( s . get_virtual_size ( ) ) ;
//Check virtual and raw section sizes and addresses
if ( s . get_virtual_address ( ) + pe_utils : : align_up ( s . get_virtual_size ( ) , get_section_alignment ( ) ) > pe_utils : : align_up ( get_size_of_image ( ) , get_section_alignment ( ) )
| |
pe_utils : : align_down ( s . get_pointer_to_raw_data ( ) , get_file_alignment ( ) ) + s . get_size_of_raw_data ( ) > static_cast < uint32_t > ( filesize ) )
throw pe_exception ( " Incorrect section address or size " , pe_exception : : section_incorrect_addr_or_size ) ;
//Seek to section raw data
file . seekg ( pe_utils : : align_down ( s . get_pointer_to_raw_data ( ) , get_file_alignment ( ) ) ) ;
if ( file . bad ( ) | | file . fail ( ) )
throw pe_exception ( " Cannot reach section data " , pe_exception : : image_section_data_not_found ) ;
//Read section raw data
s . get_raw_data ( ) . resize ( s . get_size_of_raw_data ( ) ) ;
file . read ( & s . get_raw_data ( ) [ 0 ] , s . get_size_of_raw_data ( ) ) ;
if ( file . bad ( ) | | file . fail ( ) )
throw pe_exception ( " Error reading section data " , pe_exception : : image_section_data_not_found ) ;
}
//Check virtual address and size of section
if ( s . get_virtual_address ( ) + s . get_aligned_virtual_size ( get_section_alignment ( ) ) > pe_utils : : align_up ( get_size_of_image ( ) , get_section_alignment ( ) ) )
throw pe_exception ( " Incorrect section address or size " , pe_exception : : section_incorrect_addr_or_size ) ;
//Save section
sections_ . push_back ( s ) ;
//Seek to the next section header
file . seekg ( next_sect ) ;
}
//Check size of headers: SizeOfHeaders can't be larger than first section VA
if ( ! sections_ . empty ( ) & & get_size_of_headers ( ) > sections_ . front ( ) . get_virtual_address ( ) )
throw pe_exception ( " Incorrect size of headers " , pe_exception : : incorrect_size_of_headers ) ;
//If image has more than two sections
if ( sections_ . size ( ) > = 2 )
{
//Check sections virtual sizes
for ( section_list : : const_iterator i = sections_ . begin ( ) + 1 ; i ! = sections_ . end ( ) ; + + i )
{
if ( ( * i ) . get_virtual_address ( ) ! = ( * ( i - 1 ) ) . get_virtual_address ( ) + ( * ( i - 1 ) ) . get_aligned_virtual_size ( get_section_alignment ( ) ) )
throw pe_exception ( " Section table is incorrect " , pe_exception : : image_section_table_incorrect ) ;
}
}
//Check if image has overlay in the end of file
has_overlay_ = ! sections_ . empty ( ) & & filesize > static_cast < std : : streamoff > ( sections_ . back ( ) . get_pointer_to_raw_data ( ) + last_raw_size ) ;
{
//Additionally, read data from the beginning of istream to size of headers
file . seekg ( 0 ) ;
uint32_t size_of_headers = std : : min < uint32_t > ( get_size_of_headers ( ) , static_cast < uint32_t > ( filesize ) ) ;
if ( ! sections_ . empty ( ) )
{
for ( section_list : : const_iterator i = sections_ . begin ( ) ; i ! = sections_ . end ( ) ; + + i )
{
if ( ! ( * i ) . empty ( ) )
{
size_of_headers = std : : min < uint32_t > ( get_size_of_headers ( ) , ( * i ) . get_pointer_to_raw_data ( ) ) ;
break ;
}
}
}
full_headers_data_ . resize ( size_of_headers ) ;
file . read ( & full_headers_data_ [ 0 ] , size_of_headers ) ;
if ( file . bad ( ) | | file . eof ( ) )
throw pe_exception ( " Error reading file " , pe_exception : : error_reading_file ) ;
}
//Moreover, if there's debug directory, read its raw data for some debug info types
while ( read_debug_raw_data & & has_debug ( ) )
{
try
{
//Check the length in bytes of the section containing debug directory
if ( section_data_length_from_rva ( get_directory_rva ( image_directory_entry_debug ) , get_directory_rva ( image_directory_entry_debug ) , section_data_virtual , true ) < sizeof ( image_debug_directory ) )
break ;
unsigned long current_pos = get_directory_rva ( image_directory_entry_debug ) ;
//First IMAGE_DEBUG_DIRECTORY table
image_debug_directory directory = section_data_from_rva < image_debug_directory > ( current_pos , section_data_virtual , true ) ;
//Iterate over all IMAGE_DEBUG_DIRECTORY directories
while ( directory . PointerToRawData
& & current_pos < get_directory_rva ( image_directory_entry_debug ) + get_directory_size ( image_directory_entry_debug ) )
{
//If we have something to read
if ( ( directory . Type = = image_debug_type_codeview
| | directory . Type = = image_debug_type_misc
| | directory . Type = = image_debug_type_coff )
& & directory . SizeOfData )
{
std : : string data ;
data . resize ( directory . SizeOfData ) ;
file . seekg ( directory . PointerToRawData ) ;
file . read ( & data [ 0 ] , directory . SizeOfData ) ;
if ( file . bad ( ) | | file . eof ( ) )
throw pe_exception ( " Error reading file " , pe_exception : : error_reading_file ) ;
debug_data_ . insert ( std : : make_pair ( directory . PointerToRawData , data ) ) ;
}
//Go to next debug entry
current_pos + = sizeof ( image_debug_directory ) ;
directory = section_data_from_rva < image_debug_directory > ( current_pos , section_data_virtual , true ) ;
}
break ;
}
catch ( const pe_exception & )
{
//Don't throw any exception here, if debug info is corrupted or incorrect
break ;
}
catch ( const std : : bad_alloc & )
{
//Don't throw any exception here, if debug info is corrupted or incorrect
break ;
}
}
}
//Returns PE type of this image
pe_type pe_base : : get_pe_type ( ) const
{
return props_ - > get_pe_type ( ) ;
}
//Returns PE type (PE or PE+) from pe_type enumeration (minimal correctness checks)
pe_type pe_base : : get_pe_type ( std : : istream & file )
{
//Save state of the istream
std : : ios_base : : iostate state = file . exceptions ( ) ;
std : : streamoff old_offset = file . tellg ( ) ;
image_nt_headers32 nt_headers ;
image_dos_header header ;
try
{
//Read dos header
file . exceptions ( std : : ios : : goodbit ) ;
read_dos_header ( file , header ) ;
//Seek to the NT headers start
file . seekg ( header . e_lfanew ) ;
if ( file . bad ( ) | | file . fail ( ) )
throw pe_exception ( " Cannot reach IMAGE_NT_HEADERS " , pe_exception : : image_nt_headers_not_found ) ;
//Read NT headers (we're using 32-bit version, because there's no significant differencies between 32 and 64 bit version structures)
file . read ( reinterpret_cast < char * > ( & nt_headers ) , sizeof ( image_nt_headers32 ) - sizeof ( image_data_directory ) * image_numberof_directory_entries ) ;
if ( file . bad ( ) | | file . eof ( ) )
throw pe_exception ( " Error reading IMAGE_NT_HEADERS " , pe_exception : : error_reading_image_nt_headers ) ;
//Check NT headers signature
if ( nt_headers . Signature ! = 0x4550 ) //"PE"
throw pe_exception ( " Incorrect PE signature " , pe_exception : : pe_signature_incorrect ) ;
//Check NT headers magic
if ( nt_headers . OptionalHeader . Magic ! = image_nt_optional_hdr32_magic & & nt_headers . OptionalHeader . Magic ! = image_nt_optional_hdr64_magic )
throw pe_exception ( " Incorrect PE signature " , pe_exception : : pe_signature_incorrect ) ;
}
catch ( const std : : exception & )
{
//If something went wrong, restore istream state
file . exceptions ( state ) ;
file . seekg ( old_offset ) ;
file . clear ( ) ;
//Retrhow exception
throw ;
}
//Restore stream state
file . exceptions ( state ) ;
file . seekg ( old_offset ) ;
file . clear ( ) ;
//Determine PE type and return it
return nt_headers . OptionalHeader . Magic = = image_nt_optional_hdr64_magic ? pe_type_64 : pe_type_32 ;
}
//Returns true if image has overlay data at the end of file
bool pe_base : : has_overlay ( ) const
{
return has_overlay_ ;
}
//Clears PE characteristics flag
void pe_base : : clear_characteristics_flags ( uint16_t flags )
{
set_characteristics ( get_characteristics ( ) & ~ flags ) ;
}
//Sets PE characteristics flag
void pe_base : : set_characteristics_flags ( uint16_t flags )
{
set_characteristics ( get_characteristics ( ) | flags ) ;
}
//Returns true if PE characteristics flag set
bool pe_base : : check_characteristics_flag ( uint16_t flag ) const
{
return ( get_characteristics ( ) & flag ) ? true : false ;
}
//Returns subsystem value
uint16_t pe_base : : get_subsystem ( ) const
{
return props_ - > get_subsystem ( ) ;
}
//Sets subsystem value
void pe_base : : set_subsystem ( uint16_t subsystem )
{
props_ - > set_subsystem ( subsystem ) ;
}
//Returns true if image has console subsystem
bool pe_base : : is_console ( ) const
{
return get_subsystem ( ) = = image_subsystem_windows_cui ;
}
//Returns true if image has Windows GUI subsystem
bool pe_base : : is_gui ( ) const
{
return get_subsystem ( ) = = image_subsystem_windows_gui ;
}
//Sets required operation system version
void pe_base : : set_os_version ( uint16_t major , uint16_t minor )
{
props_ - > set_os_version ( major , minor ) ;
}
//Returns required operation system version (minor word)
uint16_t pe_base : : get_minor_os_version ( ) const
{
return props_ - > get_minor_os_version ( ) ;
}
//Returns required operation system version (major word)
uint16_t pe_base : : get_major_os_version ( ) const
{
return props_ - > get_major_os_version ( ) ;
}
//Sets required subsystem version
void pe_base : : set_subsystem_version ( uint16_t major , uint16_t minor )
{
props_ - > set_subsystem_version ( major , minor ) ;
}
//Returns required subsystem version (minor word)
uint16_t pe_base : : get_minor_subsystem_version ( ) const
{
return props_ - > get_minor_subsystem_version ( ) ;
}
//Returns required subsystem version (major word)
uint16_t pe_base : : get_major_subsystem_version ( ) const
{
return props_ - > get_major_subsystem_version ( ) ;
}
//Returns corresponding section data pointer from VA inside section "s" for PE32 (checks bounds)
char * pe_base : : section_data_from_va ( section & s , uint32_t va ) //Always returns raw data
{
return section_data_from_rva ( s , va_to_rva ( va ) ) ;
}
//Returns corresponding section data pointer from VA inside section "s" for PE32 (checks bounds)
const char * pe_base : : section_data_from_va ( const section & s , uint32_t va , section_data_type datatype ) const
{
return section_data_from_rva ( s , va_to_rva ( va ) , datatype ) ;
}
//Returns corresponding section data pointer from VA inside section for PE32
char * pe_base : : section_data_from_va ( uint32_t va , bool include_headers ) //Always returns raw data
{
return section_data_from_rva ( va_to_rva ( va ) , include_headers ) ;
}
//Returns corresponding section data pointer from VA inside section for PE32
const char * pe_base : : section_data_from_va ( uint32_t va , section_data_type datatype , bool include_headers ) const
{
return section_data_from_rva ( va_to_rva ( va ) , datatype , include_headers ) ;
}
//Returns corresponding section data pointer from VA inside section "s" for PE32/PE64 (checks bounds)
char * pe_base : : section_data_from_va ( section & s , uint64_t va ) //Always returns raw data
{
return section_data_from_rva ( s , va_to_rva ( va ) ) ;
}
//Returns corresponding section data pointer from VA inside section "s" for PE32/PE64 (checks bounds)
const char * pe_base : : section_data_from_va ( const section & s , uint64_t va , section_data_type datatype ) const
{
return section_data_from_rva ( s , va_to_rva ( va ) , datatype ) ;
}
//Returns corresponding section data pointer from VA inside section for PE32/PE64
char * pe_base : : section_data_from_va ( uint64_t va , bool include_headers ) //Always returns raw data
{
return section_data_from_rva ( va_to_rva ( va ) , include_headers ) ;
}
//Returns corresponding section data pointer from VA inside section for PE32/PE64
const char * pe_base : : section_data_from_va ( uint64_t va , section_data_type datatype , bool include_headers ) const
{
return section_data_from_rva ( va_to_rva ( va ) , datatype , include_headers ) ;
}
//Returns section from VA inside it for PE32
section & pe_base : : section_from_va ( uint32_t va )
{
return section_from_rva ( va_to_rva ( va ) ) ;
}
//Returns section from VA inside it for PE32/PE64
section & pe_base : : section_from_va ( uint64_t va )
{
return section_from_rva ( va_to_rva ( va ) ) ;
}
//Returns section from RVA inside it for PE32
const section & pe_base : : section_from_va ( uint32_t va ) const
{
return section_from_rva ( va_to_rva ( va ) ) ;
}
//Returns section from RVA inside it for PE32/PE64
const section & pe_base : : section_from_va ( uint64_t va ) const
{
return section_from_rva ( va_to_rva ( va ) ) ;
}
uint32_t pe_base : : va_to_rva ( uint32_t va , bool bound_check ) const
{
return props_ - > va_to_rva ( va , bound_check ) ;
}
uint32_t pe_base : : va_to_rva ( uint64_t va , bool bound_check ) const
{
return props_ - > va_to_rva ( va , bound_check ) ;
}
uint32_t pe_base : : rva_to_va_32 ( uint32_t rva ) const
{
return props_ - > rva_to_va_32 ( rva ) ;
}
uint64_t pe_base : : rva_to_va_64 ( uint32_t rva ) const
{
return props_ - > rva_to_va_64 ( rva ) ;
}
//Relative Virtual Address (RVA) to Virtual Address (VA) convertion for PE32
void pe_base : : rva_to_va ( uint32_t rva , uint32_t & va ) const
{
va = rva_to_va_32 ( rva ) ;
}
//Relative Virtual Address (RVA) to Virtual Address (VA) convertions for PE32/PE64
void pe_base : : rva_to_va ( uint32_t rva , uint64_t & va ) const
{
va = rva_to_va_64 ( rva ) ;
}
//Returns section from file offset (4gb max)
section & pe_base : : section_from_file_offset ( uint32_t offset )
{
return * file_offset_to_section ( offset ) ;
}
//Returns section from file offset (4gb max)
const section & pe_base : : section_from_file_offset ( uint32_t offset ) const
{
return * file_offset_to_section ( offset ) ;
}
//Returns section and offset (raw data only) from its start from RVA
const std : : pair < uint32_t , const section * > pe_base : : section_and_offset_from_rva ( uint32_t rva ) const
{
const section & s = section_from_rva ( rva ) ;
return std : : make_pair ( rva - s . get_virtual_address ( ) , & s ) ;
}
//Returns DLL Characteristics
uint16_t pe_base : : get_dll_characteristics ( ) const
{
return props_ - > get_dll_characteristics ( ) ;
}
//Sets DLL Characteristics
void pe_base : : set_dll_characteristics ( uint16_t characteristics )
{
props_ - > set_dll_characteristics ( characteristics ) ;
}
//Returns size of headers
uint32_t pe_base : : get_size_of_headers ( ) const
{
return props_ - > get_size_of_headers ( ) ;
}
//Returns size of optional header
uint16_t pe_base : : get_size_of_optional_header ( ) const
{
return props_ - > get_size_of_optional_header ( ) ;
}
//Returns PE signature
uint32_t pe_base : : get_pe_signature ( ) const
{
return props_ - > get_pe_signature ( ) ;
}
//Returns magic value
uint32_t pe_base : : get_magic ( ) const
{
return props_ - > get_magic ( ) ;
}
//Returns image base for PE32
void pe_base : : get_image_base ( uint32_t & base ) const
{
base = get_image_base_32 ( ) ;
}
//Returns image base for PE32 and PE64 respectively
uint32_t pe_base : : get_image_base_32 ( ) const
{
return props_ - > get_image_base_32 ( ) ;
}
//Sets image base for PE32 and PE64 respectively
uint64_t pe_base : : get_image_base_64 ( ) const
{
return props_ - > get_image_base_64 ( ) ;
}
//RVA to RAW file offset convertion (4gb max)
uint32_t pe_base : : rva_to_file_offset ( uint32_t rva ) const
{
//Maybe, RVA is inside PE headers
if ( rva < get_size_of_headers ( ) )
return rva ;
const section & s = section_from_rva ( rva ) ;
return s . get_pointer_to_raw_data ( ) + rva - s . get_virtual_address ( ) ;
}
//RAW file offset to RVA convertion (4gb max)
uint32_t pe_base : : file_offset_to_rva ( uint32_t offset ) const
{
//Maybe, offset is inside PE headers
if ( offset < get_size_of_headers ( ) )
return offset ;
const section_list : : const_iterator it = file_offset_to_section ( offset ) ;
return offset - ( * it ) . get_pointer_to_raw_data ( ) + ( * it ) . get_virtual_address ( ) ;
}
//RAW file offset to section convertion helper (4gb max)
section_list : : const_iterator pe_base : : file_offset_to_section ( uint32_t offset ) const
{
section_list : : const_iterator it = std : : find_if ( sections_ . begin ( ) , sections_ . end ( ) , section_by_raw_offset ( offset ) ) ;
if ( it = = sections_ . end ( ) )
throw pe_exception ( " No section found by presented file offset " , pe_exception : : no_section_found ) ;
return it ;
}
//RAW file offset to section convertion helper (4gb max)
section_list : : iterator pe_base : : file_offset_to_section ( uint32_t offset )
{
section_list : : iterator it = std : : find_if ( sections_ . begin ( ) , sections_ . end ( ) , section_by_raw_offset ( offset ) ) ;
if ( it = = sections_ . end ( ) )
throw pe_exception ( " No section found by presented file offset " , pe_exception : : no_section_found ) ;
return it ;
}
//RVA from section raw data offset
uint32_t pe_base : : rva_from_section_offset ( const section & s , uint32_t raw_offset_from_section_start )
{
return s . get_virtual_address ( ) + raw_offset_from_section_start ;
}
//Returns image base for PE32/PE64
void pe_base : : get_image_base ( uint64_t & base ) const
{
base = get_image_base_64 ( ) ;
}
//Sets new image base
void pe_base : : set_image_base ( uint32_t base )
{
props_ - > set_image_base ( base ) ;
}
void pe_base : : set_image_base_64 ( uint64_t base )
{
props_ - > set_image_base_64 ( base ) ;
}
//Sets heap size commit for PE32 and PE64 respectively
void pe_base : : set_heap_size_commit ( uint32_t size )
{
props_ - > set_heap_size_commit ( size ) ;
}
void pe_base : : set_heap_size_commit ( uint64_t size )
{
props_ - > set_heap_size_commit ( size ) ;
}
//Sets heap size reserve for PE32 and PE64 respectively
void pe_base : : set_heap_size_reserve ( uint32_t size )
{
props_ - > set_heap_size_reserve ( size ) ;
}
void pe_base : : set_heap_size_reserve ( uint64_t size )
{
props_ - > set_heap_size_reserve ( size ) ;
}
//Sets stack size commit for PE32 and PE64 respectively
void pe_base : : set_stack_size_commit ( uint32_t size )
{
props_ - > set_stack_size_commit ( size ) ;
}
void pe_base : : set_stack_size_commit ( uint64_t size )
{
props_ - > set_stack_size_commit ( size ) ;
}
//Sets stack size reserve for PE32 and PE64 respectively
void pe_base : : set_stack_size_reserve ( uint32_t size )
{
props_ - > set_stack_size_reserve ( size ) ;
}
void pe_base : : set_stack_size_reserve ( uint64_t size )
{
props_ - > set_stack_size_reserve ( size ) ;
}
//Returns heap size commit for PE32 and PE64 respectively
uint32_t pe_base : : get_heap_size_commit_32 ( ) const
{
return props_ - > get_heap_size_commit_32 ( ) ;
}
uint64_t pe_base : : get_heap_size_commit_64 ( ) const
{
return props_ - > get_heap_size_commit_64 ( ) ;
}
//Returns heap size reserve for PE32 and PE64 respectively
uint32_t pe_base : : get_heap_size_reserve_32 ( ) const
{
return props_ - > get_heap_size_reserve_32 ( ) ;
}
uint64_t pe_base : : get_heap_size_reserve_64 ( ) const
{
return props_ - > get_heap_size_reserve_64 ( ) ;
}
//Returns stack size commit for PE32 and PE64 respectively
uint32_t pe_base : : get_stack_size_commit_32 ( ) const
{
return props_ - > get_stack_size_commit_32 ( ) ;
}
uint64_t pe_base : : get_stack_size_commit_64 ( ) const
{
return props_ - > get_stack_size_commit_64 ( ) ;
}
//Returns stack size reserve for PE32 and PE64 respectively
uint32_t pe_base : : get_stack_size_reserve_32 ( ) const
{
return props_ - > get_stack_size_reserve_32 ( ) ;
}
uint64_t pe_base : : get_stack_size_reserve_64 ( ) const
{
return props_ - > get_stack_size_reserve_64 ( ) ;
}
//Returns heap size commit for PE32
void pe_base : : get_heap_size_commit ( uint32_t & size ) const
{
size = get_heap_size_commit_32 ( ) ;
}
//Returns heap size commit for PE32/PE64
void pe_base : : get_heap_size_commit ( uint64_t & size ) const
{
size = get_heap_size_commit_64 ( ) ;
}
//Returns heap size reserve for PE32
void pe_base : : get_heap_size_reserve ( uint32_t & size ) const
{
size = get_heap_size_reserve_32 ( ) ;
}
//Returns heap size reserve for PE32/PE64
void pe_base : : get_heap_size_reserve ( uint64_t & size ) const
{
size = get_heap_size_reserve_64 ( ) ;
}
//Returns stack size commit for PE32
void pe_base : : get_stack_size_commit ( uint32_t & size ) const
{
size = get_stack_size_commit_32 ( ) ;
}
//Returns stack size commit for PE32/PE64
void pe_base : : get_stack_size_commit ( uint64_t & size ) const
{
size = get_stack_size_commit_64 ( ) ;
}
//Returns stack size reserve for PE32
void pe_base : : get_stack_size_reserve ( uint32_t & size ) const
{
size = get_stack_size_reserve_32 ( ) ;
}
//Returns stack size reserve for PE32/PE64
void pe_base : : get_stack_size_reserve ( uint64_t & size ) const
{
size = get_stack_size_reserve_64 ( ) ;
}
//Realigns file (changes file alignment)
void pe_base : : realign_file ( uint32_t new_file_alignment )
{
//Checks alignment for correctness
set_file_alignment ( new_file_alignment ) ;
realign_all_sections ( ) ;
}
//Helper function to recalculate RAW and virtual section sizes and strip it, if necessary
void pe_base : : recalculate_section_sizes ( section & s , bool auto_strip )
{
prepare_section ( s ) ; //Recalculate section raw addresses
//Strip RAW size of section, if it is the last one
//For all others it must be file-aligned and calculated by prepare_section() call
if ( auto_strip & & ! ( sections_ . empty ( ) | | & s = = & * ( sections_ . end ( ) - 1 ) ) )
{
//Strip ending raw data nullbytes to optimize size
std : : string & raw_data = s . get_raw_data ( ) ;
if ( ! raw_data . empty ( ) )
{
std : : string : : size_type i = raw_data . length ( ) ;
for ( ; i ! = 1 ; - - i )
{
if ( raw_data [ i - 1 ] ! = 0 )
break ;
}
raw_data . resize ( i ) ;
}
s . set_size_of_raw_data ( static_cast < uint32_t > ( raw_data . length ( ) ) ) ;
}
//Can occur only for last section
if ( pe_utils : : align_up ( s . get_virtual_size ( ) , get_section_alignment ( ) ) < pe_utils : : align_up ( s . get_size_of_raw_data ( ) , get_file_alignment ( ) ) )
set_section_virtual_size ( s , pe_utils : : align_up ( s . get_size_of_raw_data ( ) , get_section_alignment ( ) ) ) ; //Recalculate section virtual size
}
//Returns data from the beginning of image
//Size = SizeOfHeaders
const std : : string & pe_base : : get_full_headers_data ( ) const
{
return full_headers_data_ ;
}
const pe_base : : debug_data_list & pe_base : : get_raw_debug_data_list ( ) const
{
return debug_data_ ;
}
//Sets number of sections
void pe_base : : set_number_of_sections ( uint16_t number )
{
props_ - > set_number_of_sections ( number ) ;
}
//Sets size of image
void pe_base : : set_size_of_image ( uint32_t size )
{
props_ - > set_size_of_image ( size ) ;
}
//Sets size of headers
void pe_base : : set_size_of_headers ( uint32_t size )
{
props_ - > set_size_of_headers ( size ) ;
}
//Sets size of optional headers
void pe_base : : set_size_of_optional_header ( uint16_t size )
{
props_ - > set_size_of_optional_header ( size ) ;
}
//Returns nt headers data pointer
char * pe_base : : get_nt_headers_ptr ( )
{
return props_ - > get_nt_headers_ptr ( ) ;
}
//Returns nt headers data pointer
const char * pe_base : : get_nt_headers_ptr ( ) const
{
return props_ - > get_nt_headers_ptr ( ) ;
}
//Returns sizeof() nt headers
uint32_t pe_base : : get_sizeof_nt_header ( ) const
{
return props_ - > get_sizeof_nt_header ( ) ;
}
//Returns sizeof() optional headers
uint32_t pe_base : : get_sizeof_opt_headers ( ) const
{
return props_ - > get_sizeof_opt_headers ( ) ;
}
//Sets file alignment (no checks)
void pe_base : : set_file_alignment_unchecked ( uint32_t alignment )
{
props_ - > set_file_alignment_unchecked ( alignment ) ;
}
//Sets base of code
void pe_base : : set_base_of_code ( uint32_t base )
{
props_ - > set_base_of_code ( base ) ;
}
//Returns base of code
uint32_t pe_base : : get_base_of_code ( ) const
{
return props_ - > get_base_of_code ( ) ;
}
//Returns needed magic of image
uint32_t pe_base : : get_needed_magic ( ) const
{
return props_ - > get_needed_magic ( ) ;
}
}