Parse PE Rich Header (resolve #15)

This commit is contained in:
Romain Thomas 2017-06-16 17:10:39 +02:00
parent f01eae3f73
commit 8ddc71d337
28 changed files with 750 additions and 55 deletions

View File

@ -20,6 +20,8 @@ set(LIEF_PYTHON_PE_SRC
"${CMAKE_CURRENT_LIST_DIR}/objects/pyDataDirectory.cpp"
"${CMAKE_CURRENT_LIST_DIR}/objects/pyDosHeader.cpp"
"${CMAKE_CURRENT_LIST_DIR}/objects/pyRichHeader.cpp"
"${CMAKE_CURRENT_LIST_DIR}/objects/pyRichEntry.cpp"
"${CMAKE_CURRENT_LIST_DIR}/objects/pyBuilder.cpp"
"${CMAKE_CURRENT_LIST_DIR}/objects/pyOptionalHeader.cpp"
"${CMAKE_CURRENT_LIST_DIR}/objects/pyRelocationEntry.cpp"

View File

@ -93,6 +93,15 @@ void init_PE_Binary_class(py::module& m) {
"" RST_CLASS_REF(lief.PE.TLS) " object (if present)",
py::return_value_policy::reference)
.def_property("rich_header",
static_cast<RichHeader& (Binary::*)(void)>(&Binary::rich_header),
static_cast<void (Binary::*)(const RichHeader&)>(&Binary::rich_header),
"" RST_CLASS_REF(lief.PE.RichHeader) " object (if present)",
py::return_value_policy::reference)
.def_property_readonly("has_rich_header", &Binary::has_rich_header,
"``True`` if the current binary has a " RST_CLASS_REF(lief.PE.RichHeader) " object")
.def_property_readonly("has_debug", &Binary::has_debug,
"``True`` if the current binary has a " RST_CLASS_REF(lief.PE.Debug) " object")

View File

@ -0,0 +1,67 @@
/* Copyright 2017 R. Thomas
* Copyright 2017 Quarkslab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "pyPE.hpp"
#include "LIEF/visitors/Hash.hpp"
#include "LIEF/PE/RichEntry.hpp"
#include <string>
#include <sstream>
template<class T>
using getter_t = T (RichEntry::*)(void) const;
template<class T>
using setter_t = void (RichEntry::*)(T);
void init_PE_RichEntry_class(py::module& m) {
py::class_<RichEntry>(m, "RichEntry")
.def(py::init<>())
.def(py::init<uint16_t, uint16_t, uint32_t>())
.def_property("id",
static_cast<getter_t<uint16_t>>(&RichEntry::id),
static_cast<setter_t<uint16_t>>(&RichEntry::id),
"Type of the entry")
.def_property("build_id",
static_cast<getter_t<uint16_t>>(&RichEntry::build_id),
static_cast<setter_t<uint16_t>>(&RichEntry::build_id),
"Builder number of the tool (if any)")
.def_property("count",
static_cast<getter_t<uint32_t>>(&RichEntry::count),
static_cast<setter_t<uint32_t>>(&RichEntry::count),
"*Occurrence* count")
.def("__eq__", &RichEntry::operator==)
.def("__ne__", &RichEntry::operator!=)
.def("__hash__",
[] (const RichEntry& entry) {
return LIEF::Hash::hash(entry);
})
.def("__str__", [] (const RichEntry& entry)
{
std::ostringstream stream;
stream << entry;
std::string str = stream.str();
return str;
});
}

View File

@ -0,0 +1,76 @@
/* Copyright 2017 R. Thomas
* Copyright 2017 Quarkslab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "pyPE.hpp"
#include "LIEF/visitors/Hash.hpp"
#include "LIEF/PE/RichHeader.hpp"
#include <string>
#include <sstream>
template<class T>
using getter_t = T (RichHeader::*)(void) const;
template<class T>
using setter_t = void (RichHeader::*)(T);
template<class T>
using no_const_getter = T (RichHeader::*)(void);
void init_PE_RichHeader_class(py::module& m) {
py::class_<RichHeader>(m, "RichHeader")
.def(py::init<>())
.def_property("key",
static_cast<getter_t<uint32_t>>(&RichHeader::key),
static_cast<setter_t<uint32_t>>(&RichHeader::key),
"Key used to encode the header (xor operation)")
.def_property_readonly("entries",
static_cast<no_const_getter<it_rich_entries>>(&RichHeader::entries),
"Return binary's " RST_CLASS_REF(lief.PE.RichEntry) " within the header",
py::return_value_policy::reference)
.def("add_entry",
static_cast<void (RichHeader::*)(const RichEntry&)>(&RichHeader::add_entry),
"Add a new " RST_CLASS_REF(lief.PE.RichEntry) "",
"entry"_a)
.def("add_entry",
static_cast<void (RichHeader::*)(uint16_t, uint16_t, uint32_t)>(&RichHeader::add_entry),
"Add a new " RST_CLASS_REF(lief.PE.RichEntry) " given its "
":attr:`~lief.PE.RichEntry.id`, "
":attr:`~lief.PE.RichEntry.build_id`, "
":attr:`~lief.PE.RichEntry.count`",
"id"_a, "build_id"_a, "count"_a)
.def("__eq__", &RichHeader::operator==)
.def("__ne__", &RichHeader::operator!=)
.def("__hash__",
[] (const RichHeader& rich_header) {
return LIEF::Hash::hash(rich_header);
})
.def("__str__", [] (const RichHeader& rich_header)
{
std::ostringstream stream;
stream << rich_header;
std::string str = stream.str();
return str;
});
}

View File

@ -37,6 +37,8 @@ void init_PE_module(py::module& m) {
init_PE_DataDirectory_class(LIEF_PE_module);
init_PE_Header_class(LIEF_PE_module);
init_PE_DosHeader_class(LIEF_PE_module);
init_PE_RichHeader_class(LIEF_PE_module);
init_PE_RichEntry_class(LIEF_PE_module);
init_PE_OptionalHeader_class(LIEF_PE_module);
init_PE_Section_class(LIEF_PE_module);
init_PE_Import_class(LIEF_PE_module);

View File

@ -31,6 +31,8 @@ void init_PE_Binary_class(py::module&);
void init_PE_DataDirectory_class(py::module&);
void init_PE_Header_class(py::module&);
void init_PE_DosHeader_class(py::module&);
void init_PE_RichHeader_class(py::module&);
void init_PE_RichEntry_class(py::module&);
void init_PE_Section_class(py::module&);
void init_PE_OptionalHeader_class(py::module&);
void init_PE_Import_class(py::module&);

View File

@ -53,6 +53,7 @@ void init_LIEF_iterators(py::module& m) {
init_ref_iterator<LIEF::PE::it_symbols>(m);
init_ref_iterator<LIEF::PE::it_const_crt>(m);
init_ref_iterator<LIEF::PE::it_childs>(m);
init_ref_iterator<LIEF::PE::it_rich_entries>(m);
#endif

View File

@ -46,6 +46,8 @@ void init_json_functions(py::module& m) {
#if defined(LIEF_PE_MODULE)
m.def("to_json", &LIEF::to_json_str<LIEF::PE::Binary, LIEF::PE::JsonVisitor>);
m.def("to_json", &LIEF::to_json_str<LIEF::PE::DosHeader, LIEF::PE::JsonVisitor>);
m.def("to_json", &LIEF::to_json_str<LIEF::PE::RichHeader, LIEF::PE::JsonVisitor>);
m.def("to_json", &LIEF::to_json_str<LIEF::PE::RichEntry, LIEF::PE::JsonVisitor>);
m.def("to_json", &LIEF::to_json_str<LIEF::PE::Header, LIEF::PE::JsonVisitor>);
m.def("to_json", &LIEF::to_json_str<LIEF::PE::OptionalHeader, LIEF::PE::JsonVisitor>);
m.def("to_json", &LIEF::to_json_str<LIEF::PE::DataDirectory, LIEF::PE::JsonVisitor>);

View File

@ -288,6 +288,21 @@ Lang code item
----------
Rich Header
***********
.. doxygenclass:: LIEF::PE::RichHeader
:project: lief
----------
Rich Entry
**********
.. doxygenclass:: LIEF::PE::RichEntry
:project: lief
----------
Enums
*****

View File

@ -341,6 +341,26 @@ Lang code item
----------
Rich Header
***********
.. autoclass:: lief.PE.RichHeader
:members:
:inherited-members:
:undoc-members:
----------
Rich Entry
**********
.. autoclass:: lief.PE.RichEntry
:members:
:inherited-members:
:undoc-members:
----------
Enums
*****

View File

@ -38,6 +38,10 @@ int main(int argc, char **argv) {
std::cout << "== Optional Header ==" << std::endl;
std::cout << binary->optional_header() << std::endl;
if (binary->has_rich_header()) {
std::cout << "== Rich Header ==" << std::endl;
std::cout << binary->rich_header() << std::endl;
}
std::cout << "== Data Directories ==" << std::endl;
for (const DataDirectory& directory : binary->data_directories()) {

View File

@ -153,24 +153,21 @@ def print_symbols(binary):
str(symbol.storage_class).split(".")[-1]))
def print_imports(binary):
if binary.has_imports:
print("== Imports ==")
imports = binary.imports
print("== Imports ==")
imports = binary.imports
for import_ in imports:
print(import_.name)
entries = import_.entries
f_value = " {:<33} 0x{:<14x} 0x{:<14x} 0x{:<16x}"
for entry in entries:
print(f_value.format(entry.name, entry.data, entry.iat_value, entry.hint))
print("")
for import_ in imports:
print(import_.name)
entries = import_.entries
f_value = " {:<33} 0x{:<14x} 0x{:<14x} 0x{:<16x}"
for entry in entries:
print(f_value.format(entry.name, entry.data, entry.iat_value, entry.hint))
print("")
def print_tls(binary):
format_str = "{:<33} {:<30}"
format_hex = "{:<33} 0x{:<28x}"
format_dec = "{:<33} {:<30d}"
if not binary.has_tls:
return
print("== TLS ==")
tls = binary.tls
@ -192,27 +189,25 @@ def print_tls(binary):
print("")
def print_relocations(binary):
if binary.has_relocations:
relocations = binary.relocations
print("== Relocations ==")
for relocation in relocations:
entries = relocation.entries
print(hex(relocation.virtual_address))
for entry in entries:
print(" 0x{:<8x} {:<8}".format(entry.position, str(entry.type).split(".")[-1]))
print("")
relocations = binary.relocations
print("== Relocations ==")
for relocation in relocations:
entries = relocation.entries
print(hex(relocation.virtual_address))
for entry in entries:
print(" 0x{:<8x} {:<8}".format(entry.position, str(entry.type).split(".")[-1]))
print("")
def print_export(binary):
if binary.has_exports:
print("== Exports ==")
exports = binary.get_export()
entries = exports.entries
f_value = "{:<20} 0x{:<10x} 0x{:<10x} 0x{:<6x} 0x{:<6x} 0x{:<10x}"
print(f_value.format(exports.name, exports.export_flags, exports.timestamp, exports.major_version, exports.minor_version, exports.ordinal_base))
for entry in entries:
extern = "[EXTERN]" if entry.is_extern else ""
print(" {:<20} 0x{:<6x} 0x{:<10x} {:<13}".format(entry.name[:20], entry.ordinal, entry.address, extern))
print("")
print("== Exports ==")
exports = binary.get_export()
entries = exports.entries
f_value = "{:<20} 0x{:<10x} 0x{:<10x} 0x{:<6x} 0x{:<6x} 0x{:<10x}"
print(f_value.format(exports.name, exports.export_flags, exports.timestamp, exports.major_version, exports.minor_version, exports.ordinal_base))
for entry in entries:
extern = "[EXTERN]" if entry.is_extern else ""
print(" {:<20} 0x{:<6x} 0x{:<10x} {:<13}".format(entry.name[:20], entry.ordinal, entry.address, extern))
print("")
def print_debug(binary):
@ -220,27 +215,23 @@ def print_debug(binary):
format_hex = "{:<33} 0x{:<28x}"
format_dec = "{:<33} {:<30d}"
if binary.has_debug:
debug = binary.debug
print("== Debug ==")
print(format_hex.format("Characteristics:", debug.characteristics))
print(format_hex.format("Timestamp:", debug.timestamp))
print(format_dec.format("Major version:", debug.major_version))
print(format_dec.format("Minor version:", debug.minor_version))
print(format_str.format("type:", str(debug.type).split(".")[-1]))
print(format_hex.format("Size of data:", debug.sizeof_data))
print(format_hex.format("Address of raw data:", debug.addressof_rawdata))
print(format_hex.format("Pointer to raw data:", debug.pointerto_rawdata))
print("")
debug = binary.debug
print("== Debug ==")
print(format_hex.format("Characteristics:", debug.characteristics))
print(format_hex.format("Timestamp:", debug.timestamp))
print(format_dec.format("Major version:", debug.major_version))
print(format_dec.format("Minor version:", debug.minor_version))
print(format_str.format("type:", str(debug.type).split(".")[-1]))
print(format_hex.format("Size of data:", debug.sizeof_data))
print(format_hex.format("Address of raw data:", debug.addressof_rawdata))
print(format_hex.format("Pointer to raw data:", debug.pointerto_rawdata))
print("")
def print_signature(binary):
format_str = "{:<33} {:<30}"
format_hex = "{:<33} 0x{:<28x}"
format_dec = "{:<33} {:<30d}"
if not binary.has_signature:
return
signature = binary.signature
print("== Signature ==")
print(format_dec.format("Version:", signature.version))
@ -277,10 +268,18 @@ def print_signature(binary):
print(format_str.format("Issuer:", issuer_str))
print(format_str.format("Digest Algorithm:", oid_to_string(signer_info.digest_algorithm)))
print(format_str.format("Signature algorithm:", oid_to_string(signer_info.signature_algorithm)))
#print(format_str.format("Program name:", signer_info.authenticated_attributes.program_name))
print(format_str.format("Program name:", signer_info.authenticated_attributes.program_name))
print(format_str.format("Url:", signer_info.authenticated_attributes.more_info))
print("")
def print_rich_header(binary):
print("== Rich Header ==")
header = binary.rich_header
print("Key: 0x{:08x}".format(header.key))
for entry in header.entries:
print(" - ID: {:04x} Build ID: {:04x} Count: {:d}".format(entry.id, entry.build_id, entry.count))
def main():
optparser = OptionParser(
@ -316,6 +315,10 @@ def main():
action='store_true', dest='show_relocs',
help='Display the relocations (if present)')
optparser.add_option('-R', '--rich-header',
action='store_true', dest='show_richheader',
help='Display the Rich Header')
optparser.add_option('-S', '--section-headers', '--sections',
action='store_true', dest='show_section_header',
help="Display the sections' headers")
@ -354,10 +357,10 @@ def main():
if options.show_headers or options.show_all:
print_header(binary)
if options.show_imports or options.show_all:
if (options.show_imports or options.show_all) and binary.has_imports:
print_imports(binary)
if options.show_relocs or options.show_all:
if (options.show_relocs or options.show_all) and binary.has_relocations:
print_relocations(binary)
if options.show_section_header or options.show_all:
@ -366,17 +369,20 @@ def main():
if options.show_symbols or options.show_all:
print_symbols(binary)
if options.show_tls or options.show_all:
if (options.show_tls or options.show_all) and binary.has_tls:
print_tls(binary)
if options.show_export or options.show_all:
if (options.show_export or options.show_all) and binary.has_exports:
print_export(binary)
if options.show_debug or options.show_all:
if (options.show_debug or options.show_all) and binary.has_debug:
print_debug(binary)
if options.show_signature or options.show_all:
if (options.show_signature or options.show_all) and binary.has_signature:
print_signature(binary)
if (options.show_richheader or options.show_all) and binary.has_rich_header:
print_rich_header(binary)
if __name__ == "__main__":
main()

View File

@ -22,6 +22,7 @@
#include "LIEF/PE/Header.hpp"
#include "LIEF/PE/OptionalHeader.hpp"
#include "LIEF/PE/DosHeader.hpp"
#include "LIEF/PE/RichHeader.hpp"
#include "LIEF/PE/Section.hpp"
#include "LIEF/PE/Import.hpp"
#include "LIEF/PE/DataDirectory.hpp"
@ -102,7 +103,6 @@ class DLL_PUBLIC Binary : public LIEF::Binary {
//! @brief Compute the size of all headers
uint32_t get_sizeof_headers(void) const;
//! @brief Return a reference to the TLS object
TLS& tls(void);
const TLS& tls(void) const;
@ -254,6 +254,19 @@ class DLL_PUBLIC Binary : public LIEF::Binary {
//! @brief Update the DOS stub content
void dos_stub(const std::vector<uint8_t>& content);
// Rich Header
// -----------
//! @brief Return a reference to the RichHeader object
RichHeader& rich_header(void);
const RichHeader& rich_header(void) const;
//! @brief Set a RichHeader object in the current Binary
void rich_header(const RichHeader& rich_header);
//! @brief Check if the current binary has a RichHeader object
bool has_rich_header(void) const;
// =========================
// Methods to manage Imports
// =========================
@ -365,9 +378,11 @@ class DLL_PUBLIC Binary : public LIEF::Binary {
PE_TYPE type_;
DosHeader dos_header_;
RichHeader rich_header_;
Header header_;
OptionalHeader optional_header_;
bool has_rich_header_;
bool has_tls_;
bool has_imports_;
bool has_signature_;

View File

@ -85,6 +85,7 @@ class DLL_PUBLIC Parser : public LIEF::Parser {
void build_signature(void);
void build_overlay(void);
void build_dos_stub(void);
void build_rich_header(void);
ResourceNode* build_resource_node(
const pe_resource_directory_table *directory_table,

View File

@ -0,0 +1,68 @@
/* Copyright 2017 R. Thomas
* Copyright 2017 Quarkslab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef LIEF_PE_RICH_ENTRY_H_
#define LIEF_PE_RICH_ENTRY_H_
#include <array>
#include <iostream>
#include "LIEF/Visitable.hpp"
#include "LIEF/visibility.h"
#include "LIEF/PE/Structures.hpp"
namespace LIEF {
namespace PE {
class DLL_PUBLIC RichEntry : public Visitable {
public:
RichEntry(void);
RichEntry(uint16_t id, uint16_t build_id, uint32_t count);
RichEntry(const RichEntry& copy);
RichEntry& operator=(const RichEntry& copy);
virtual ~RichEntry(void);
//! @brief Entry type
uint16_t id(void) const;
//! @brief Builder number of the tool (if any)
uint16_t build_id(void) const;
//! @brief *Occurrence* count.
uint32_t count(void) const;
void id(uint16_t id);
void build_id(uint16_t build_id);
void count(uint32_t count);
virtual void accept(Visitor& visitor) const override;
bool operator==(const RichEntry& rhs) const;
bool operator!=(const RichEntry& rhs) const;
DLL_PUBLIC friend std::ostream& operator<<(std::ostream& os, const RichEntry& rich_entry);
private:
uint16_t id_;
uint16_t build_id_;
uint32_t count_;
};
}
}
#endif

View File

@ -0,0 +1,70 @@
/* Copyright 2017 R. Thomas
* Copyright 2017 Quarkslab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef LIEF_PE_RICH_HEADER_H_
#define LIEF_PE_RICH_HEADER_H_
#include <array>
#include <iostream>
#include "LIEF/Visitable.hpp"
#include "LIEF/visibility.h"
#include "LIEF/PE/Structures.hpp"
#include "LIEF/PE/type_traits.hpp"
#include "LIEF/PE/RichEntry.hpp"
namespace LIEF {
namespace PE {
class DLL_PUBLIC RichHeader : public Visitable {
public:
RichHeader(void);
RichHeader(const RichHeader& copy);
RichHeader& operator=(const RichHeader& copy);
virtual ~RichHeader(void);
//! @brief Key used to encode the header (xor operation)
uint32_t key(void) const;
//! @brief Return an iterator on the PE::RichEntry within the header
it_rich_entries entries(void);
it_const_rich_entries entries(void) const;
void key(uint32_t key);
//! @brief Add a new PE::RichEntry
void add_entry(const RichEntry& entry);
void add_entry(uint16_t id, uint16_t build_id, uint32_t count);
virtual void accept(Visitor& visitor) const override;
bool operator==(const RichHeader& rhs) const;
bool operator!=(const RichHeader& rhs) const;
DLL_PUBLIC friend std::ostream& operator<<(std::ostream& os, const RichHeader& rich_header);
private:
uint32_t key_;
rich_entries_t entries_;
};
}
}
#endif

View File

@ -4,6 +4,11 @@ static const int32_t MaxNumberOfSections16 = 65279;
//! The PE signature bytes that follows the DOS stub header.
static const char PE_Magic[] = { 'P', 'E', '\0', '\0' };
static const char Rich_Magic[] = {'R', 'i', 'c', 'h'};
static const char DanS_Magic[] = {'D', 'a', 'n', 'S'};
static const uint32_t DanS_Magic_number = 0x536E6144;
static const char BigObjMagic[] = {
'\xc7', '\xa1', '\xba', '\xd1', '\xee', '\xba', '\xa9', '\x4b',
'\xaf', '\x20', '\xfa', '\xf6', '\x6a', '\xa4', '\xdc', '\xb8',

View File

@ -25,6 +25,7 @@ class DataDirectory;
class Relocation;
class Symbol;
class ExportEntry;
class RichEntry;
class Import;
class ImportEntry;
@ -73,6 +74,10 @@ using dialog_items_t = std::vector<ResourceDialogItem>;
using it_dialog_items = ref_iterator<dialog_items_t&>;
using it_const_dialog_items = const_ref_iterator<const dialog_items_t&>;
using rich_entries_t = std::vector<RichEntry>;
using it_rich_entries = ref_iterator<rich_entries_t&>;
using it_const_rich_entries = const_ref_iterator<const rich_entries_t&>;
}
}

View File

@ -69,6 +69,8 @@ class Binary;
class DosHeader;
class Header;
class OptionalHeader;
class RichHeader;
class RichEntry;
class DataDirectory;
class Section;
@ -252,6 +254,12 @@ class DLL_PUBLIC Visitor {
//! @brief Method to visit a LIEF::PE::DosHeader
virtual void visit(const PE::DosHeader& dos_header);
//! @brief Method to visit a LIEF::PE:RichHeader
virtual void visit(const PE::RichHeader& rich_header);
//! @brief Method to visit a LIEF::PE:RichEntry
virtual void visit(const PE::RichEntry& rich_entry);
//! @brief Method to visit a LIEF::PE::Header
virtual void visit(const PE::Header& header);

View File

@ -30,6 +30,8 @@ class DLL_PUBLIC JsonVisitor : public LIEF::JsonVisitor {
virtual void visit(const Binary& Binary) override;
virtual void visit(const DosHeader& dos_header) override;
virtual void visit(const RichHeader& rich_header) override;
virtual void visit(const RichEntry& rich_entry) override;
virtual void visit(const Header& header) override;
virtual void visit(const OptionalHeader& optional_header) override;
virtual void visit(const DataDirectory& data_directory) override;

View File

@ -49,8 +49,10 @@ static const std::map<MACHINE_TYPES, std::pair<ARCHITECTURES, std::set<MODES>>>
Binary::Binary(void) :
dos_header_{},
rich_header_{},
header_{},
optional_header_{},
has_rich_header_{false},
has_tls_{false},
has_imports_{false},
has_signature_{false},
@ -266,6 +268,10 @@ const DataDirectory& Binary::data_directory(DATA_DIRECTORY index) const {
}
}
bool Binary::has_rich_header(void) const {
return this->has_rich_header_;
}
bool Binary::has_tls(void) const {
return this->has_tls_;
}
@ -1034,6 +1040,24 @@ void Binary::dos_stub(const std::vector<uint8_t>& content) {
this->dos_stub_ = content;
}
// Rich Header
// -----------
RichHeader& Binary::rich_header(void) {
return const_cast<RichHeader&>(static_cast<const Binary*>(this)->rich_header());
}
const RichHeader& Binary::rich_header(void) const {
if (not this->has_rich_header()) {
throw not_found("Rich Header not found");
}
return this->rich_header_;
}
void Binary::rich_header(const RichHeader& rich_header) {
this->rich_header_ = rich_header;
this->has_rich_header_ = true;
}
// Resource manager
// ===============
@ -1088,6 +1112,10 @@ void Binary::accept(Visitor& visitor) const {
visitor(this->tls());
}
if (this->has_rich_header()) {
visitor(this->rich_header());
}
}
@ -1111,6 +1139,14 @@ std::ostream& Binary::print(std::ostream& os) const {
os << std::endl;
if (this->has_rich_header()) {
os << "Rich Header" << std::endl;
os << "===========" << std::endl;
os << this->rich_header() << std::endl;
os << std::endl;
}
os << "Header" << std::endl;
os << "======" << std::endl;

View File

@ -6,6 +6,8 @@ set(LIEF_PE_SRC
"${CMAKE_CURRENT_LIST_DIR}/EnumToString.cpp"
"${CMAKE_CURRENT_LIST_DIR}/Header.cpp"
"${CMAKE_CURRENT_LIST_DIR}/DosHeader.cpp"
"${CMAKE_CURRENT_LIST_DIR}/RichHeader.cpp"
"${CMAKE_CURRENT_LIST_DIR}/RichEntry.cpp"
"${CMAKE_CURRENT_LIST_DIR}/ResourceDirectory.cpp"
"${CMAKE_CURRENT_LIST_DIR}/Import.cpp"
"${CMAKE_CURRENT_LIST_DIR}/ResourceNode.cpp"
@ -64,6 +66,8 @@ set(LIEF_PE_INCLUDE_FILES
"${CMAKE_CURRENT_SOURCE_DIR}/include/LIEF/PE/DataDirectory.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/include/LIEF/PE/Debug.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/include/LIEF/PE/DosHeader.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/include/LIEF/PE/RichHeader.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/include/LIEF/PE/RichEntry.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/include/LIEF/PE/EnumToString.hpp"
"${CMAKE_CURRENT_BINARY_DIR}/include/LIEF/PE/enums.hpp" # Do we want to do this since it's autogenerated?
"${CMAKE_CURRENT_SOURCE_DIR}/include/LIEF/PE/Export.hpp"

View File

@ -96,6 +96,66 @@ void Parser::build_dos_stub(void) {
}
void Parser::build_rich_header(void) {
LOG(DEBUG) << "Parsing Rich Header";
const std::vector<uint8_t>& dos_stub = this->binary_->dos_stub();
VectorStream stream{dos_stub};
auto&& it_rich = std::search(
std::begin(dos_stub),
std::end(dos_stub),
std::begin(Rich_Magic),
std::end(Rich_Magic));
if (it_rich == std::end(dos_stub)) {
LOG(DEBUG) << "Rich header not found";
return;
}
this->binary_->has_rich_header_ = true;
const uint64_t end_offset_rich_header = std::distance(std::begin(dos_stub), it_rich);
LOG(DEBUG) << "Offset to rich header: " << std::hex << end_offset_rich_header;
const uint32_t xor_key = stream.read_integer<uint32_t>(end_offset_rich_header + sizeof(Rich_Magic));
this->binary_->rich_header().key(xor_key);
LOG(DEBUG) << "XOR Key: " << std::hex << xor_key;
uint64_t curent_offset = end_offset_rich_header - sizeof(Rich_Magic);
std::vector<uint32_t> values;
values.reserve(dos_stub.size() / sizeof(uint32_t));
uint32_t count = 0;
uint32_t value = 0;
while (value != DanS_Magic_number and count != DanS_Magic_number) {
count = stream.read_integer<uint32_t>(curent_offset) ^ xor_key;
curent_offset -= sizeof(uint32_t);
value = stream.read_integer<uint32_t>(curent_offset) ^ xor_key;
curent_offset -= sizeof(uint32_t);
if (value == DanS_Magic_number or count == DanS_Magic_number) {
break;
}
uint16_t build_number = value & 0xFFFF;
uint16_t id = (value >> 16) & 0xFFFF;
LOG(DEBUG) << "ID: " << std::hex << id << " "
<< "Build Number: " << std::hex << build_number << " "
<< "Count: " << std::dec << count;
this->binary_->rich_header().add_entry(id, build_number, count);
}
LOG(DEBUG) << this->binary_->rich_header();
}
//

View File

@ -31,6 +31,12 @@ void Parser::build(void) {
this->build_dos_stub();
try {
this->build_rich_header();
} catch (const corrupted& e) {
LOG(WARNING) << e.what();
}
LOG(DEBUG) << "[+] Decomposing Sections";
try {

91
src/PE/RichEntry.cpp Normal file
View File

@ -0,0 +1,91 @@
/* Copyright 2017 R. Thomas
* Copyright 2017 Quarkslab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <iomanip>
#include "LIEF/visitors/Hash.hpp"
#include "LIEF/PE/RichEntry.hpp"
namespace LIEF {
namespace PE {
RichEntry::~RichEntry(void) = default;
RichEntry::RichEntry(const RichEntry& copy) = default;
RichEntry& RichEntry::operator=(const RichEntry& copy) = default;
RichEntry::RichEntry(void) :
id_{0},
build_id_{0},
count_{0}
{}
RichEntry::RichEntry(uint16_t id, uint16_t build_id, uint32_t count) :
id_{id},
build_id_{build_id},
count_{count}
{}
uint16_t RichEntry::id(void) const {
return this->id_;
}
uint16_t RichEntry::build_id(void) const {
return this->build_id_;
}
uint32_t RichEntry::count(void) const {
return this->count_;
}
void RichEntry::id(uint16_t id) {
this->id_ = id;
}
void RichEntry::build_id(uint16_t build_id) {
this->build_id_ = build_id;
}
void RichEntry::count(uint32_t count) {
this->count_ = count;
}
void RichEntry::accept(LIEF::Visitor& visitor) const {
visitor.visit(this->id());
visitor.visit(this->build_id());
visitor.visit(this->count());
}
bool RichEntry::operator==(const RichEntry& rhs) const {
size_t hash_lhs = Hash::hash(*this);
size_t hash_rhs = Hash::hash(rhs);
return hash_lhs == hash_rhs;
}
bool RichEntry::operator!=(const RichEntry& rhs) const {
return not (*this == rhs);
}
std::ostream& operator<<(std::ostream& os, const RichEntry& rich_entry) {
os << "ID: 0x" << std::hex << std::setw(4) << std::setfill('0') << rich_entry.id() << " ";
os << "Build ID: 0x" << std::hex << std::setw(4) << std::setfill('0') << rich_entry.build_id() << " ";
os << "Count: " << std::dec << std::setw(0) << rich_entry.count();
return os;
}
}
}

85
src/PE/RichHeader.cpp Normal file
View File

@ -0,0 +1,85 @@
/* Copyright 2017 R. Thomas
* Copyright 2017 Quarkslab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <iomanip>
#include "LIEF/visitors/Hash.hpp"
#include "LIEF/PE/RichHeader.hpp"
namespace LIEF {
namespace PE {
RichHeader::~RichHeader(void) = default;
RichHeader::RichHeader(const RichHeader& copy) = default;
RichHeader& RichHeader::operator=(const RichHeader& copy) = default;
RichHeader::RichHeader(void) :
key_{0},
entries_{}
{}
uint32_t RichHeader::key(void) const {
return this->key_;
}
it_rich_entries RichHeader::entries(void) {
return {this->entries_};
}
it_const_rich_entries RichHeader::entries(void) const {
return {this->entries_};
}
void RichHeader::key(uint32_t key) {
this->key_ = key;
}
void RichHeader::add_entry(const RichEntry& entry) {
this->entries_.push_back(entry);
}
void RichHeader::add_entry(uint16_t id, uint16_t build_id, uint32_t count) {
this->entries_.emplace_back(id, build_id, count);
}
void RichHeader::accept(LIEF::Visitor& visitor) const {
visitor.visit(this->key());
for (const RichEntry& entry : this->entries()) {
visitor(entry);
}
}
bool RichHeader::operator==(const RichHeader& rhs) const {
size_t hash_lhs = Hash::hash(*this);
size_t hash_rhs = Hash::hash(rhs);
return hash_lhs == hash_rhs;
}
bool RichHeader::operator!=(const RichHeader& rhs) const {
return not (*this == rhs);
}
std::ostream& operator<<(std::ostream& os, const RichHeader& rich_header) {
os << "Key: " << std::hex << rich_header.key() << std::endl;
for (const RichEntry& entry : rich_header.entries()) {
os << " - " << entry << std::endl;
}
return os;
}
}
}

View File

@ -158,6 +158,14 @@ void Visitor::visit(const PE::DosHeader& dos_header) {
dos_header.accept(*this);
}
void Visitor::visit(const PE::RichHeader& rich_header) {
rich_header.accept(*this);
}
void Visitor::visit(const PE::RichEntry& rich_entry) {
rich_entry.accept(*this);
}
void Visitor::visit(const PE::Header& header) {
header.accept(*this);
}

View File

@ -29,6 +29,13 @@ void JsonVisitor::visit(const Binary& binary) {
JsonVisitor dos_header_visitor;
dos_header_visitor(binary.dos_header());
// Rich Header
if (binary.has_rich_header()) {
JsonVisitor visitor;
visitor(binary.rich_header());
this->node_["rich_header"] = visitor.get();
}
// PE header
JsonVisitor header_visitor;
header_visitor(binary.header());
@ -121,7 +128,7 @@ void JsonVisitor::visit(const Binary& binary) {
// Signature
if (binary.has_signature()) {
JsonVisitor visitor;
binary.signature().accept(visitor);
visitor(binary.signature());
this->node_["signature"] = visitor.get();
}
@ -151,6 +158,24 @@ void JsonVisitor::visit(const DosHeader& dos_header) {
this->node_["addressof_new_exeheader"] = dos_header.addressof_new_exeheader();
}
void JsonVisitor::visit(const RichHeader& rich_header) {
std::vector<json> entries;
for (const RichEntry& entry : rich_header.entries()) {
JsonVisitor visitor;
visitor(entry);
entries.emplace_back(visitor.get());
}
this->node_["key"] = rich_header.key();
this->node_["entries"] = entries;
}
void JsonVisitor::visit(const RichEntry& rich_entry) {
this->node_["id"] = rich_entry.id();
this->node_["build_id"] = rich_entry.build_id();
this->node_["count"] = rich_entry.count();
}
void JsonVisitor::visit(const Header& header) {
this->node_["signature"] = header.signature();
this->node_["machine"] = to_string(header.machine());