Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Parse PE debug data directory as a list of debug entries
PE's DATA_DIRECTORY_DEBUG does not define a single debug entry, but
a list of struct pe_debug entries (the number of entries is determined
by the data directory's size).

This commit reflect this layout by returning a vector<> when calling
PE.debug()
  • Loading branch information
1orenz0 authored and romainthomas committed Nov 29, 2018
1 parent 3ac2067 commit fcc75dd
Show file tree
Hide file tree
Showing 14 changed files with 77 additions and 36 deletions.
8 changes: 5 additions & 3 deletions api/python/PE/objects/pyBinary.cpp
Expand Up @@ -135,6 +135,9 @@ void create<Binary>(py::module& m) {
.def_property_readonly("has_signature", &Binary::has_signature,
"``True`` if the binary is signed (" RST_CLASS_REF(lief.PE.Signature) ")")

.def_property_readonly("is_reproducible_build", &Binary::is_reproducible_build,
"``True`` if the binary was compiled with a reproducible build directive (" RST_CLASS_REF(lief.PE.Debug) ")")

.def_property_readonly("functions",
&Binary::functions,
"**All** " RST_CLASS_REF(lief.Function) " found in the binary")
Expand All @@ -153,10 +156,9 @@ void create<Binary>(py::module& m) {
"Return the " RST_CLASS_REF(lief.PE.Signature) " object",
py::return_value_policy::reference)


.def_property_readonly("debug",
static_cast<Debug& (Binary::*)(void)>(&Binary::debug),
"Return the " RST_CLASS_REF(lief.PE.Debug) " object",
static_cast<debug_entries_t& (Binary::*)(void)>(&Binary::debug),
"Return the " RST_CLASS_REF(lief.PE.Debug) "",
py::return_value_policy::reference)

.def_property_readonly("load_configuration",
Expand Down
7 changes: 6 additions & 1 deletion api/python/PE/pyEnums.cpp
Expand Up @@ -253,7 +253,12 @@ void init_enums(py::module& m) {
.value(PY_ENUM(LIEF::PE::DEBUG_TYPES::IMAGE_DEBUG_TYPE_OMAP_TO_SRC))
.value(PY_ENUM(LIEF::PE::DEBUG_TYPES::IMAGE_DEBUG_TYPE_OMAP_FROM_SRC))
.value(PY_ENUM(LIEF::PE::DEBUG_TYPES::IMAGE_DEBUG_TYPE_BORLAND))
.value(PY_ENUM(LIEF::PE::DEBUG_TYPES::IMAGE_DEBUG_TYPE_CLSID));
.value(PY_ENUM(LIEF::PE::DEBUG_TYPES::IMAGE_DEBUG_TYPE_CLSID))
.value(PY_ENUM(LIEF::PE::DEBUG_TYPES::IMAGE_DEBUG_TYPE_VC_FEATURE))
.value(PY_ENUM(LIEF::PE::DEBUG_TYPES::IMAGE_DEBUG_TYPE_POGO))
.value(PY_ENUM(LIEF::PE::DEBUG_TYPES::IMAGE_DEBUG_TYPE_ILTCG))
.value(PY_ENUM(LIEF::PE::DEBUG_TYPES::IMAGE_DEBUG_TYPE_MPX))
.value(PY_ENUM(LIEF::PE::DEBUG_TYPES::IMAGE_DEBUG_TYPE_REPRO));


LIEF::enum_<LIEF::PE::RESOURCE_TYPES>(m, "RESOURCE_TYPES")
Expand Down
4 changes: 3 additions & 1 deletion examples/cpp/pe_reader.cpp
Expand Up @@ -89,7 +89,9 @@ int main(int argc, char **argv) {

if (binary->has_debug()) {
std::cout << "== Debug ==" << std::endl;
std::cout << binary->debug() << std::endl;
for (const Debug& debug : binary->debug()) {
std::cout << debug << std::endl;
}
}


Expand Down
14 changes: 10 additions & 4 deletions include/LIEF/PE/Binary.hpp
Expand Up @@ -144,6 +144,11 @@ class LIEF_API Binary : public LIEF::Binary {
//! @brief Check if the current binary has a load configuration
bool has_configuration(void) const;

//! @brief Check if the current binary has been built has reproducible, replacing timestamps by a compile hash.
//!
//! @see Debug
bool is_reproducible_build(void) const;

//! @brief Return the Signature object if the bianry is signed
const Signature& signature(void) const;

Expand Down Expand Up @@ -237,9 +242,9 @@ class LIEF_API Binary : public LIEF::Binary {

bool has(DATA_DIRECTORY index) const;

//! @brief Return the Debug object
Debug& debug(void);
const Debug& debug(void) const;
//! @brief Return the debug_entries_t object
debug_entries_t& debug(void);
const debug_entries_t& debug(void) const;

//! @brief Retrun the LoadConfiguration object
const LoadConfiguration& load_configuration(void) const;
Expand Down Expand Up @@ -431,6 +436,7 @@ class LIEF_API Binary : public LIEF::Binary {
bool has_relocations_;
bool has_debug_;
bool has_configuration_;
bool is_reproducible_build_;

Signature signature_;
TLS tls_;
Expand All @@ -442,7 +448,7 @@ class LIEF_API Binary : public LIEF::Binary {
ResourceNode* resources_;
imports_t imports_;
Export export_;
Debug debug_;
debug_entries_t debug_;
std::vector<uint8_t> overlay_;
std::vector<uint8_t> dos_stub_;

Expand Down
2 changes: 1 addition & 1 deletion include/LIEF/PE/Parser.hpp
Expand Up @@ -85,7 +85,7 @@ class LIEF_API Parser : public LIEF::Parser {

void parse_export_table(void);
void parse_debug(void);
void parse_debug_code_view(void);
void parse_debug_code_view(Debug& debug_info);

template<typename PE_T>
void parse_tls(void);
Expand Down
1 change: 1 addition & 0 deletions include/LIEF/PE/enums.inc
Expand Up @@ -266,6 +266,7 @@ enum _LIEF_EN(DEBUG_TYPES) {
_LIEF_EI(IMAGE_DEBUG_TYPE_OMAP_TO_SRC) = 7, ///< The mapping from an RVA in image to an RVA in source image.
_LIEF_EI(IMAGE_DEBUG_TYPE_OMAP_FROM_SRC) = 8, ///< The mapping from an RVA in source image to an RVA in image.
_LIEF_EI(IMAGE_DEBUG_TYPE_BORLAND) = 9, ///< Reserved for Borland.
_LIEF_EI(IMAGE_DEBUG_TYPE_RESERVED10) = 10, ///< Reserved for future use.
_LIEF_EI(IMAGE_DEBUG_TYPE_CLSID) = 11,
_LIEF_EI(IMAGE_DEBUG_TYPE_VC_FEATURE) = 12,
_LIEF_EI(IMAGE_DEBUG_TYPE_POGO) = 13,
Expand Down
4 changes: 4 additions & 0 deletions include/LIEF/PE/type_traits.hpp
Expand Up @@ -65,6 +65,10 @@ using export_entries_t = std::vector<ExportEntry>;
using it_export_entries = ref_iterator<export_entries_t&>;
using it_const_export_entries = const_ref_iterator<const export_entries_t&>;

using debug_entries_t = std::vector<Debug>;
using it_debug_entries = ref_iterator<debug_entries_t&>;
using it_const_debug_entries = const_ref_iterator<const debug_entries_t&>;

using symbols_t = std::vector<Symbol>;
using it_symbols = ref_iterator<symbols_t&>;
using it_const_symbols = const_ref_iterator<const symbols_t&>;
Expand Down
1 change: 1 addition & 0 deletions include/LIEF/PE/undef.h
Expand Up @@ -242,6 +242,7 @@
#undef IMAGE_DEBUG_TYPE_OMAP_TO_SRC
#undef IMAGE_DEBUG_TYPE_OMAP_FROM_SRC
#undef IMAGE_DEBUG_TYPE_BORLAND
#undef IMAGE_DEBUG_TYPE_RESERVED10
#undef IMAGE_DEBUG_TYPE_CLSID
#undef IMAGE_DEBUG_TYPE_VC_FEATURE
#undef IMAGE_DEBUG_TYPE_POGO
Expand Down
14 changes: 10 additions & 4 deletions src/PE/Binary.cpp
Expand Up @@ -92,6 +92,7 @@ Binary::Binary(void) :
has_relocations_{false},
has_debug_{false},
has_configuration_{false},
is_reproducible_build_{false},
tls_{},
sections_{},
data_directories_{},
Expand Down Expand Up @@ -358,6 +359,9 @@ bool Binary::has_debug(void) const {
return this->has_debug_;
}

bool Binary::is_reproducible_build(void) const {
return this->is_reproducible_build_;
}

bool Binary::has_configuration(void) const {
return this->has_configuration_ and this->load_configuration_ != nullptr;
Expand Down Expand Up @@ -978,12 +982,12 @@ it_const_data_directories Binary::data_directories(void) const {
}


Debug& Binary::debug(void) {
return const_cast<Debug&>(static_cast<const Binary*>(this)->debug());
debug_entries_t& Binary::debug(void) {
return const_cast<debug_entries_t&>(static_cast<const Binary*>(this)->debug());
}


const Debug& Binary::debug(void) const {
const debug_entries_t& Binary::debug(void) const {
return this->debug_;
}

Expand Down Expand Up @@ -1410,7 +1414,9 @@ std::ostream& Binary::print(std::ostream& os) const {
if (this->has_debug()) {
os << "Debug" << std::endl;
os << "=====" << std::endl;
os << this->debug() << std::endl;
for (const Debug& debug : this->debug()) {
os << debug << std::endl;
}
os << std::endl;
}

Expand Down
3 changes: 2 additions & 1 deletion src/PE/EnumToString.cpp
Expand Up @@ -385,7 +385,7 @@ const char* to_string(RELOCATIONS_BASE_TYPES e) {


const char* to_string(DEBUG_TYPES e) {
CONST_MAP(DEBUG_TYPES, const char*, 16) enumStrings {
CONST_MAP(DEBUG_TYPES, const char*, 17) enumStrings {
{ DEBUG_TYPES::IMAGE_DEBUG_TYPE_UNKNOWN, "UNKNOWN" },
{ DEBUG_TYPES::IMAGE_DEBUG_TYPE_COFF, "COFF" },
{ DEBUG_TYPES::IMAGE_DEBUG_TYPE_CODEVIEW, "CODEVIEW" },
Expand All @@ -396,6 +396,7 @@ const char* to_string(DEBUG_TYPES e) {
{ DEBUG_TYPES::IMAGE_DEBUG_TYPE_OMAP_TO_SRC, "SRC" },
{ DEBUG_TYPES::IMAGE_DEBUG_TYPE_OMAP_FROM_SRC, "SRC" },
{ DEBUG_TYPES::IMAGE_DEBUG_TYPE_BORLAND, "BORLAND" },
{ DEBUG_TYPES::IMAGE_DEBUG_TYPE_RESERVED10, "RESERVED" },
{ DEBUG_TYPES::IMAGE_DEBUG_TYPE_CLSID, "CLSID" },
{ DEBUG_TYPES::IMAGE_DEBUG_TYPE_VC_FEATURE, "VC_FEATURE" },
{ DEBUG_TYPES::IMAGE_DEBUG_TYPE_POGO, "POGO" },
Expand Down
37 changes: 23 additions & 14 deletions src/PE/Parser.cpp
Expand Up @@ -565,28 +565,37 @@ void Parser::parse_debug(void) {

uint32_t debugRVA = this->binary_->data_directory(DATA_DIRECTORY::DEBUG).RVA();
uint32_t debugoffset = this->binary_->rva_to_offset(debugRVA);
//uint32_t debugsize = this->binary_->dataDirectories_[DATA_DIRECTORY::DEBUG]->size();
uint32_t debugsize = this->binary_->data_directory(DATA_DIRECTORY::DEBUG).size();

const pe_debug& debug_struct = this->stream_->peek<pe_debug>(debugoffset);
for (size_t i = 0; (i + 1) * sizeof(pe_debug) <= debugsize; i++) {

this->binary_->debug_ = &debug_struct;
const pe_debug& debug_struct = this->stream_->peek<pe_debug>(debugoffset + i * sizeof(pe_debug));
this->binary_->debug_.push_back(&debug_struct);

DEBUG_TYPES type = this->binary_->debug().type();
DEBUG_TYPES type = this->binary_->debug().back().type();

switch (type) {
case DEBUG_TYPES::IMAGE_DEBUG_TYPE_CODEVIEW:
{
this->parse_debug_code_view();
}
default:
{
}
switch (type) {
case DEBUG_TYPES::IMAGE_DEBUG_TYPE_CODEVIEW:
{
this->parse_debug_code_view(this->binary_->debug().back());
break;
}

case DEBUG_TYPES::IMAGE_DEBUG_TYPE_REPRO:
{
this->binary_->is_reproducible_build_ = true;
break;
}

default:
{}
}
}
}

void Parser::parse_debug_code_view() {
void Parser::parse_debug_code_view(Debug& debug_info) {
VLOG(VDEBUG) << "Parsing Debug Code View";
Debug& debug_info = this->binary_->debug();
//Debug& debug_info = this->binary_->debug();

const uint32_t debug_off = debug_info.pointerto_rawdata();
if (not this->stream_->can_read<uint32_t>(debug_off)) {
Expand Down
2 changes: 1 addition & 1 deletion src/PE/hash.cpp
Expand Up @@ -39,7 +39,7 @@ void Hash::visit(const Binary& binary) {
process(std::begin(binary.symbols()), std::end(binary.symbols()));

if (binary.has_debug()) {
process(binary.debug());
process(std::begin(binary.debug()), std::end(binary.debug()));
}

if (binary.has_exports()) {
Expand Down
10 changes: 7 additions & 3 deletions src/PE/json.cpp
Expand Up @@ -108,9 +108,13 @@ void JsonVisitor::visit(const Binary& binary) {

// Debug
if (binary.has_debug()) {
JsonVisitor visitor;
visitor(binary.debug());
this->node_["debug"] = visitor.get();
std::vector<json> debug_entries;
for (const Debug& debug : binary.debug()) {
JsonVisitor visitor;
visitor(debug);
debug_entries.emplace_back(visitor.get());
}
this->node_["debug"] = debug_entries;
}

// Imports
Expand Down
6 changes: 3 additions & 3 deletions tests/pe/test_pe.py
Expand Up @@ -41,10 +41,10 @@ def test_code_view_pdb(self):

self.assertTrue(sample.has_debug)

debug = sample.debug

self.assertTrue(debug.has_code_view)
debug_code_view = list(filter(lambda deb: deb.has_code_view, sample.debug))
self.assertTrue(len(debug_code_view) == 1)

debug = debug_code_view[0]
code_view = debug.code_view

self.assertEqual(code_view.cv_signature, lief.PE.CODE_VIEW_SIGNATURES.PDB_70)
Expand Down

0 comments on commit fcc75dd

Please sign in to comment.