865 lines
26 KiB
C++
865 lines
26 KiB
C++
/*************************************************************************/
|
|
/* 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;
|
|
}
|
|
}
|