4
0
mirror of https://github.com/QuasarApp/LIEF.git synced 2025-05-04 08:09:33 +00:00

Enhance BinaryStream Interface

This commit is contained in:
Romain Thomas 2018-04-15 08:55:23 +02:00
parent a16e1c4d13
commit 4ef839c3d8
33 changed files with 1466 additions and 2000 deletions

@ -130,9 +130,10 @@ void init_PE_Binary_class(py::module& m) {
.def_property_readonly("has_signature", &Binary::has_signature,
"``True`` if the binary is signed (" RST_CLASS_REF(lief.PE.Signature) ")")
.def("predict_function_rva", &Binary::predict_function_rva,
.def("predict_function_rva",
static_cast<uint32_t(Binary::*)(const std::string&, const std::string&)>(&Binary::predict_function_rva),
"Try to predict the RVA of the given function name in the given import library name",
py::arg("library"), py::arg("function"))
"library"_a, "function"_a)
.def_property_readonly("signature",
static_cast<const Signature& (Binary::*)(void) const>(&Binary::signature),

@ -24,7 +24,7 @@ using namespace LIEF::ELF;
int main(int argc, char **argv) {
LIEF::Logger::set_level(LIEF::LOGGING_LEVEL::LOG_INFO);
LIEF::Logger::set_level(LIEF::LOGGING_LEVEL::LOG_DEBUG);
if (argc != 2) {
std::cerr << "Usage: " << argv[0] << " <ELF binary>" << std::endl;
return EXIT_FAILURE;

@ -14,7 +14,7 @@ import traceback
import textwrap
from lief import Logger
Logger.set_level(lief.LOGGING_LEVEL.INFO)
Logger.set_level(lief.LOGGING_LEVEL.FATAL)
from optparse import OptionParser
terminal_rows, terminal_columns = 100, 100

@ -9,7 +9,7 @@ from lief import PE
from lief.PE import oid_to_string
from lief import Logger
Logger.set_level(lief.LOGGING_LEVEL.INFO)
Logger.set_level(lief.LOGGING_LEVEL.FATAL)
from optparse import OptionParser
import sys

@ -24,31 +24,65 @@
class BinaryStream {
public:
virtual ~BinaryStream();
virtual uint64_t size(void) const = 0;
virtual const void* read(uint64_t offset, uint64_t size) const = 0;
virtual const char* read_string(uint64_t offset, uint64_t size) const = 0;
virtual std::string get_string(uint64_t offset, uint64_t size) const = 0;
BinaryStream(void);
virtual ~BinaryStream();
virtual uint64_t size(void) const = 0;
template<typename T>
T read_integer(uint64_t offset, bool swap = false) const;
uint64_t read_uleb128(void) const;
uint64_t read_sleb128(void) const;
std::pair<uint64_t, uint64_t> read_uleb128(uint64_t offset) const;
std::pair<int64_t, uint64_t> read_sleb128(uint64_t offset) const;
std::string read_string(size_t maxsize = -1u) const;
std::string peek_string(size_t maxsize = -1u) const;
std::string peek_string_at(size_t offset, size_t maxsize = -1u) const;
template<typename T>
static T swap_endian(T u);
std::u16string read_u16string(void) const;
std::u16string peek_u16string(void) const;
std::u16string read_u16string(size_t length) const;
std::u16string peek_u16string(size_t length) const;
std::u16string peek_u16string_at(size_t offset, size_t length) const;
void setpos(size_t pos) const;
void increment_pos(size_t value) const;
size_t pos(void) const;
operator bool() const;
template<class T>
const T* read_array(size_t size) const;
template<class T>
const T& peek(void) const;
template<class T>
const T& peek(size_t offset) const;
template<class T>
const T* peek_array(size_t size) const;
template<class T>
const T* peek_array(size_t offset, size_t size) const;
template<class T>
const T& read(void) const;
template<typename T>
static T swap_endian(T u);
template<typename T>
bool can_read(void) const;
template<typename T>
bool can_read(size_t offset) const;
size_t align(size_t align_on) const;
protected:
virtual const void* read_at(uint64_t offset, uint64_t size) const = 0;
mutable size_t pos_{0};
};
template<typename T>
T BinaryStream::read_integer(uint64_t offset, bool swap) const {
static_assert(std::is_integral<T>::value, "Interger required");
const T* value = reinterpret_cast<const T*>(this->read(offset, sizeof(T)));
return swap ? swap_endian(*value) : *value;
}
template<typename T>
T BinaryStream::swap_endian(T u) {
// From http://stackoverflow.com/a/4956493
@ -69,5 +103,67 @@ T BinaryStream::swap_endian(T u) {
}
template<class T>
const T& BinaryStream::read(void) const {
const T& tmp = this->peek<T>();
this->increment_pos(sizeof(T));
return tmp;
}
template<class T>
const T& BinaryStream::peek(void) const {
const void* raw = this->read_at(this->pos(), sizeof(T));
return *reinterpret_cast<const T*>(raw);
}
template<class T>
const T& BinaryStream::peek(size_t offset) const {
size_t saved_offset = this->pos();
this->setpos(offset);
const T& r = this->peek<T>();
this->setpos(saved_offset);
return r;
}
template<class T>
const T* BinaryStream::peek_array(size_t size) const {
const void* raw = this->read_at(this->pos(), sizeof(T) * size);
return reinterpret_cast<const T*>(raw);
}
template<class T>
const T* BinaryStream::peek_array(size_t offset, size_t size) const {
size_t saved_offset = this->pos();
this->setpos(offset);
const T* r = this->peek_array<T>(size);
this->setpos(saved_offset);
return r;
}
template<typename T>
bool BinaryStream::can_read(void) const {
const void* raw = this->read_at(this->pos_, sizeof(T));
return raw != nullptr;
}
template<typename T>
bool BinaryStream::can_read(size_t offset) const {
const void* raw = this->read_at(offset, sizeof(T));
return raw != nullptr;
}
template<class T>
const T* BinaryStream::read_array(size_t size) const {
const T* tmp = this->peek_array<T>(size);
this->increment_pos(sizeof(T) * size);
return tmp;
}
#endif

@ -23,20 +23,18 @@
class VectorStream : public BinaryStream {
public:
//using BinaryStream::read_integer;
VectorStream(const std::string& filename);
VectorStream(const std::vector<uint8_t>& data);
//using BinaryStream::read_integer;
VectorStream(const std::string& filename);
VectorStream(const std::vector<uint8_t>& data);
virtual uint64_t size(void) const override;
virtual const void* read(uint64_t offset, uint64_t size) const override;
virtual const char* read_string(uint64_t offset, uint64_t size = 0) const override;
virtual std::string get_string(uint64_t offset, uint64_t size = 0) const override;
virtual uint64_t size(void) const override;
const std::vector<uint8_t>& content(void) const;
const std::vector<uint8_t>& content(void) const;
private:
std::vector<uint8_t> binary_;
uint64_t size_;
protected:
virtual const void* read_at(uint64_t offset, uint64_t size) const override;
std::vector<uint8_t> binary_;
uint64_t size_;
};

@ -56,6 +56,8 @@ class LIEF_API Parser : public LIEF::Parser {
static constexpr uint32_t NB_MAX_DYNAMIC_ENTRIES = 1000;
static constexpr uint32_t NB_MAX_MASKWORD = 512;
static constexpr uint32_t MAX_NOTE_DESCRIPTION = 1_MB;
static constexpr uint32_t MAX_SECTION_SIZE = 100_MB;
static constexpr uint32_t MAX_SEGMENT_SIZE = MAX_SECTION_SIZE;
//! @brief Parse an ELF file an return a LIEF::ELF::Binary object
@ -96,7 +98,7 @@ class LIEF_API Parser : public LIEF::Parser {
void parse_binary(void);
template<typename ELF_T>
void parse_header(void);
bool parse_header(void);
//! @brief Parse binary's Section
//!

@ -117,7 +117,7 @@ class LIEF_API BinaryParser : public LIEF::Parser {
// -------
void parse_dyldinfo_export(void);
void parse_export_trie(uint64_t start, uint64_t current_offset, uint64_t end, const std::string& prefix);
void parse_export_trie(uint64_t start, uint64_t end, const std::string& prefix);
std::unique_ptr<VectorStream> stream_;
Binary* binary_ ;

@ -238,7 +238,7 @@ class LIEF_API DyldInfo : public LoadCommand {
private:
void show_bindings(std::ostream& os, const buffer_t& buffer, bool is_lazy = false) const;
void show_trie(std::ostream& output, std::string output_prefix, VectorStream& stream, uint64_t start, uint64_t current_offset, uint64_t end, const std::string& prefix) const;
void show_trie(std::ostream& output, std::string output_prefix, VectorStream& stream, uint64_t start, uint64_t end, const std::string& prefix) const;
info_t rebase_;
buffer_t rebase_opcodes_;

@ -529,6 +529,22 @@ struct arm_thread_state64_t {
uint32_t cpsr; // cpsr
};
struct code_directory {
uint32_t version;
uint32_t flags;
uint32_t hash_offset;
uint32_t ident_offset;
uint32_t nb_special_slots;
uint32_t nb_code_slots;
uint32_t code_limit;
uint8_t hash_size;
uint8_t hash_type;
uint8_t reserved;
uint8_t page_size;
uint32_t reserved2;
uint32_t scatter_offset;
};

@ -73,7 +73,7 @@ class LIEF_API Parser : public LIEF::Parser {
void parse_sections(void);
template<typename PE_T>
void parse_headers(void);
bool parse_headers(void);
void parse_configuration(void);

@ -137,10 +137,10 @@ class LIEF_API ResourcesManager : public Object {
uint32_t max_depth) const;
//! @brief Build the ResourceStringFileInfo from the RT_VERSION node
ResourceStringFileInfo get_string_file_info(const VectorStream& stream, uint64_t& offset) const;
ResourceStringFileInfo get_string_file_info(const VectorStream& stream, uint16_t type, std::u16string key, size_t start, size_t struct_length) const;
//! @brief Build the ResourceVarFileInfo from the RT_VERSION node
ResourceVarFileInfo get_var_file_info(const VectorStream& stream, uint64_t& offset) const;
ResourceVarFileInfo get_var_file_info(const VectorStream& stream, uint16_t type, std::u16string key, size_t start, size_t struct_length) const;
ResourceNode *resources_;

@ -42,7 +42,7 @@ LIEF_API PE_TYPE get_type(const std::string& file);
LIEF_API PE_TYPE get_type(const std::vector<uint8_t>& raw);
//! @brief Convert a UTF-16 string to a UTF-8 one
LIEF_API std::string u16tou8(const std::u16string& string);
LIEF_API std::string u16tou8(const std::u16string& string, bool remove_null_char = false);
//! @brief Convert a UTF-8 string to a UTF-16 one
LIEF_API std::u16string u8tou16(const std::string& string);

@ -9,6 +9,22 @@
#define VLOG(...) NULL_STREAM
#define LOG(...) NULL_STREAM
#define LOG_IF(...) NULL_STREAM
#define CHECK(...)
#define CHECK_EQ(...)
#define CHECK_NE(...)
#define CHECK_LT(...)
#define CHECK_LE(...)
#define CHECK_GE(...)
#define CHECK_GT(...)
#define DCHECK(...)
#define DCHECK_EQ(...)
#define DCHECK_NE(...)
#define DCHECK_LT(...)
#define DCHECK_LE(...)
#define DCHECK_GE(...)
#define DCHECK_GT(...)
#endif
#endif

@ -23,29 +23,21 @@
#include "LIEF/json.hpp"
#include "LIEF/visitors/json.hpp"
#ifdef LIEF_ELF_SUPPORT
#include "LIEF/ELF/json.hpp"
#endif
#ifdef LIEF_PE_SUPPORT
#include "LIEF/PE/json.hpp"
#endif
#include "LIEF/Abstract/json.hpp"
#include "LIEF/Abstract.hpp"
#include "LIEF/ELF.hpp"
#include "LIEF/PE.hpp"
namespace LIEF {
//template<class T, class VISITOR = JsonVisitor>
//json to_json(const T& obj) {
// VISITOR visitor;
// visitor(obj);
// return visitor.get();
//}
//
//template<class T, class VISITOR = JsonVisitor>
//std::string to_json_str(const T& obj) {
// return to_json<T, VISITOR>(obj).dump();
//}
} // namespace LIEF
#endif // LIEF_JSON_SUPPORT
#endif

@ -16,33 +16,49 @@
#include "LIEF/BinaryStream/BinaryStream.hpp"
BinaryStream::~BinaryStream(void) = default;
BinaryStream::BinaryStream(void) = default;
void BinaryStream::setpos(size_t pos) const {
this->pos_ = pos;
}
std::pair<uint64_t, uint64_t> BinaryStream::read_uleb128(uint64_t offset) const {
uint64_t value = 0;
unsigned shift = 0;
uint64_t current_offset = offset - sizeof(uint8_t);
do {
current_offset += sizeof(uint8_t);
value += static_cast<uint64_t>(this->read_integer<uint8_t>(current_offset) & 0x7f) << shift;
shift += 7;
} while (this->read_integer<uint8_t>(current_offset) >= 128);
uint64_t delta = current_offset - offset;
delta++;
return {value, delta};
void BinaryStream::increment_pos(size_t value) const {
this->pos_ += value;
}
std::pair<int64_t, uint64_t> BinaryStream::read_sleb128(uint64_t offset) const {
BinaryStream::operator bool() const {
return this->pos_ < this->size();
}
size_t BinaryStream::pos(void) const {
return this->pos_;
}
uint64_t BinaryStream::read_uleb128(void) const {
uint64_t value = 0;
unsigned shift = 0;
uint8_t byte_read;
do {
byte_read = this->read<uint8_t>();
value += static_cast<uint64_t>(byte_read & 0x7f) << shift;
shift += 7;
} while (byte_read >= 128);
return value;
}
uint64_t BinaryStream::read_sleb128(void) const {
int64_t value = 0;
unsigned shift = 0;
uint64_t current_offset = offset - sizeof(uint8_t);
uint8_t byte_read;
do {
current_offset += sizeof(uint8_t);
value += static_cast<uint64_t>(this->read_integer<uint8_t>(current_offset) & 0x7f) << shift;
byte_read = this->read<uint8_t>();
value += static_cast<uint64_t>(byte_read & 0x7f) << shift;
shift += 7;
} while (this->read_integer<uint8_t>(current_offset) >= 128);
} while (byte_read >= 128);
// Sign extend
@ -50,9 +66,106 @@ std::pair<int64_t, uint64_t> BinaryStream::read_sleb128(uint64_t offset) const {
value |= static_cast<int64_t>(-1) << shift;
}
uint64_t delta = current_offset - offset;
delta++;
return {value, delta};
return value;
}
std::string BinaryStream::read_string(size_t maxsize) const {
std::string str = this->peek_string(maxsize);
this->increment_pos(str.size() + 1); // +1 for'\0'
return str;
}
std::string BinaryStream::peek_string(size_t maxsize) const {
std::string result;
result.reserve(10);
char c = '\0';
size_t off = this->pos();
if (not this->can_read<char>()) {
return result.c_str();
}
size_t count = 0;
do {
c = this->peek<char>(off);
off += sizeof(char);
result.push_back(c);
++count;
} while (count < maxsize and c != '\0' and this->pos() < this->size());
result.back() = '\0';
return result.c_str();
}
std::string BinaryStream::peek_string_at(size_t offset, size_t maxsize) const {
size_t saved_offset = this->pos();
this->setpos(offset);
std::string tmp = this->peek_string(maxsize);
this->setpos(saved_offset);
return tmp;
}
std::u16string BinaryStream::read_u16string(void) const {
std::u16string str = this->peek_u16string();
this->increment_pos((str.size() + 1) * sizeof(uint16_t)); // +1 for'\0'
return str;
}
std::u16string BinaryStream::peek_u16string(void) const {
std::u16string result;
result.reserve(10);
char16_t c = '\0';
size_t off = this->pos();
if (not this->can_read<char16_t>()) {
return result;
}
size_t count = 0;
do {
c = this->peek<char16_t>(off);
off += sizeof(char16_t);
result.push_back(c);
++count;
} while (c != 0 and this->pos() < this->size());
result.back() = '\0';
return result.c_str();
}
std::u16string BinaryStream::read_u16string(size_t length) const {
std::u16string str = this->peek_u16string(length);
this->increment_pos(length * sizeof(uint16_t)); // +1 for'\0'
return str;
}
std::u16string BinaryStream::peek_u16string(size_t length) const {
if (length == static_cast<size_t>(-1u)) {
return this->peek_u16string();
}
const char16_t* raw = this->peek_array<char16_t>(this->pos(), length);
if (raw == nullptr) {
return {};
}
return {raw, length};
}
std::u16string BinaryStream::peek_u16string_at(size_t offset, size_t length) const {
size_t saved_offset = this->pos();
this->setpos(offset);
std::u16string tmp = this->peek_u16string(length);
this->setpos(saved_offset);
return tmp;
}
size_t BinaryStream::align(size_t align_on) const {
if (align_on == 0 or (this->pos() % align_on) == 0) {
return 0;
}
size_t padding = align_on - (this->pos() % align_on);
this->increment_pos(padding);
return padding;
}

@ -19,7 +19,7 @@
#include <fstream>
#include <cassert>
#include <sstream>
#include <algorithm>
#include <algorithm>
#include "LIEF/logging++.hpp"
@ -61,61 +61,21 @@ uint64_t VectorStream::size(void) const {
}
const void* VectorStream::read(uint64_t offset, uint64_t size) const {
const void* VectorStream::read_at(uint64_t offset, uint64_t size) const {
if (offset > this->size() or (offset + size) > this->size()) {
VLOG(VDEBUG) << "Offset: " << std::hex << offset;
VLOG(VDEBUG) << "Size: " << std::hex << size;
VLOG(VDEBUG) << "Binary Size: " << std::hex << this->size();
if (offset > this->size()) {
throw LIEF::read_out_of_bound(offset);
}
if ((offset + size) > this->size()) {
throw LIEF::read_out_of_bound(offset, size);
}
size_t out_size = (offset + size) - this->size();
LOG(ERROR) << "Can't read "
<< std::dec << size << " bytes at "
<< std::hex << std::showbase << offset
<< " (" << std::hex << (out_size) << " bytes out of bound)";
//throw LIEF::read_out_of_bound(offset, size);
return nullptr;
}
return this->binary_.data() + offset;
}
const char* VectorStream::read_string(uint64_t offset, uint64_t size) const {
if ((offset + size) > this->size()) {
throw LIEF::read_out_of_bound(offset);
}
uint64_t max_size = this->size() - (offset + size);
if (size > 0) {
max_size = std::min<uint64_t>(max_size, size);
}
return reinterpret_cast<const char*>(this->read(offset, max_size));
}
std::string VectorStream::get_string(uint64_t offset, uint64_t size) const {
if ((offset + size) > this->size()) {
throw LIEF::read_out_of_bound(offset);
}
size_t max_size = static_cast<size_t>(this->size() - (offset + size));
if (size > 0) {
max_size = std::min<size_t>(max_size, size);
}
const char* str = this->read_string(offset);
const char* end = str + max_size;
const char* it_null = std::find(str, end, '\0');
if (it_null == end) {
throw LIEF::read_out_of_bound(offset);
}
std::string tmp{str, it_null};
tmp.push_back('\0');
return tmp.c_str();
}
const std::vector<uint8_t>& VectorStream::content(void) const {

@ -699,9 +699,9 @@ void Builder::build_symbol_hash(void) {
std::vector<uint8_t> content = (*it_hash_section)->content();
VectorStream hashtable_stream{content};
uint32_t nbucket = hashtable_stream.read_integer<uint32_t>(0);
uint32_t nchain = hashtable_stream.read_integer<uint32_t>(0 + sizeof(uint32_t));
hashtable_stream.setpos(0);
uint32_t nbucket = hashtable_stream.read<uint32_t>();
uint32_t nchain = hashtable_stream.read<uint32_t>();
std::vector<uint8_t> new_hash_table((nbucket + nchain + 2) * sizeof(uint32_t), 0);

@ -82,10 +82,10 @@ void Parser::init(const std::string& name) {
this->binary_->name(name);
this->binary_->datahandler_ = new DataHandler::Handler{this->stream_->content()};
uint32_t type = reinterpret_cast<const Elf32_Ehdr*>(
this->stream_->read(0, sizeof(Elf32_Ehdr)))->e_ident[static_cast<size_t>(IDENTITY::EI_CLASS)];
uint32_t type = this->stream_->peek<Elf32_Ehdr>(0).e_ident[static_cast<size_t>(IDENTITY::EI_CLASS)];
this->binary_->type_ = static_cast<ELF_CLASS>(type);
this->type_ = static_cast<ELF_CLASS>(type);
switch (this->binary_->type_) {
case ELF_CLASS::ELFCLASS32:
{
@ -112,7 +112,8 @@ void Parser::init(const std::string& name) {
Binary* Parser::parse(const std::string& filename, DYNSYM_COUNT_METHODS count_mtd) {
if (not is_elf(filename)) {
throw LIEF::bad_format("'" + filename + "' is not an ELF");
LOG(ERROR) << filename << " is not an ELF";
return nullptr;
}
Parser parser{filename, count_mtd};
@ -125,7 +126,8 @@ Binary* Parser::parse(
DYNSYM_COUNT_METHODS count_mtd) {
if (not is_elf(data)) {
throw LIEF::bad_format("'" + name + "' is not an ELF");
LOG(ERROR) << "'" << name << "' is not an ELF";
return nullptr;
}
Parser parser{data, name, count_mtd};
@ -139,11 +141,13 @@ void Parser::parse_symbol_version(uint64_t symbol_version_offset) {
VLOG(VDEBUG) << "Symbol version offset: 0x" << std::hex << symbol_version_offset << std::endl;
const uint32_t nb_entries = static_cast<uint32_t>(this->binary_->dynamic_symbols_.size());
const uint16_t* array = reinterpret_cast<const uint16_t*>(
this->stream_->read(symbol_version_offset, nb_entries * sizeof(uint16_t)));
this->stream_->setpos(symbol_version_offset);
for (size_t i = 0; i < nb_entries; ++i) {
this->binary_->symbol_version_table_.push_back(new SymbolVersion{array[i]});
if (not this->stream_->can_read<uint16_t>()) {
break;
}
this->binary_->symbol_version_table_.push_back(new SymbolVersion{this->stream_->read<uint16_t>()});
}
}
@ -158,42 +162,47 @@ uint64_t Parser::get_dynamic_string_table_from_segments(void) const {
return segment != nullptr and segment->type() == SEGMENT_TYPES::PT_DYNAMIC;
});
if (it_segment_dynamic == std::end(this->binary_->segments_)) {
return 0;
}
uint64_t va_offset = 0;
if (it_segment_dynamic != std::end(this->binary_->segments_)) {
uint64_t offset = (*it_segment_dynamic)->file_offset();
uint64_t size = (*it_segment_dynamic)->physical_size();
uint64_t offset = (*it_segment_dynamic)->file_offset();
uint64_t size = (*it_segment_dynamic)->physical_size();
if (this->type_ == ELF_CLASS::ELFCLASS32) {
this->stream_->setpos(offset);
size_t nb_entries = size / sizeof(Elf32_Dyn);
const Elf32_Dyn* entries = reinterpret_cast<const Elf32_Dyn*>(
this->stream_->read(offset, size));
for (size_t i = 0; i < nb_entries; ++i) {
if (static_cast<DYNAMIC_TAGS>(entries[i].d_tag) ==
DYNAMIC_TAGS::DT_STRTAB) {
va_offset = this->binary_->virtual_address_to_offset(entries[i].d_un.d_val);
}
if (this->binary_->type_ == ELF_CLASS::ELFCLASS32) {
size_t nb_entries = size / sizeof(Elf32_Dyn);
for (size_t i = 0; i < nb_entries; ++i) {
if (not this->stream_->can_read<Elf32_Dyn>()) {
return 0;
}
const Elf32_Dyn& e = this->stream_->read<Elf32_Dyn>();
} else {
const Elf64_Dyn* entries = reinterpret_cast<const Elf64_Dyn*>(
this->stream_->read(offset, size));
size_t nb_entries = size / sizeof(Elf64_Dyn);
for (size_t i = 0; i < nb_entries; ++i) {
if (static_cast<DYNAMIC_TAGS>(entries[i].d_tag) ==
DYNAMIC_TAGS::DT_STRTAB) {
va_offset = this->binary_->virtual_address_to_offset(entries[i].d_un.d_val);
}
if (static_cast<DYNAMIC_TAGS>(e.d_tag) == DYNAMIC_TAGS::DT_STRTAB) {
return this->binary_->virtual_address_to_offset(e.d_un.d_val);
}
}
} else {
size_t nb_entries = size / sizeof(Elf64_Dyn);
for (size_t i = 0; i < nb_entries; ++i) {
if (not this->stream_->can_read<Elf64_Dyn>()) {
return 0;
}
const Elf64_Dyn& e = this->stream_->read<Elf64_Dyn>();
if (static_cast<DYNAMIC_TAGS>(e.d_tag) == DYNAMIC_TAGS::DT_STRTAB) {
return this->binary_->virtual_address_to_offset(e.d_un.d_val);
}
}
}
if (va_offset > 0) {
return va_offset;
} else {
throw LIEF::conversion_error("Unable to convert VA to offset from segments");
}
return 0;
}
uint64_t Parser::get_dynamic_string_table_from_sections(void) const {
@ -212,21 +221,15 @@ uint64_t Parser::get_dynamic_string_table_from_sections(void) const {
va_offset = (*it_dynamic_string_section)->file_offset();
}
if (va_offset > 0) {
return va_offset;
} else {
throw LIEF::conversion_error("Unable to convert VA to offset from sections");
}
return va_offset;
}
uint64_t Parser::get_dynamic_string_table(void) const {
uint64_t offset = 0;
try {
offset = this->get_dynamic_string_table_from_segments();
} catch (const LIEF::conversion_error&) {
uint64_t offset = this->get_dynamic_string_table_from_segments();
if (offset == 0) {
offset = this->get_dynamic_string_table_from_sections();
}
CHECK_NE(offset, 0);
return offset;
}
@ -244,49 +247,38 @@ void Parser::parse_symbol_sysv_hash(uint64_t offset) {
VLOG(VDEBUG) << "[+] Parse symbol SYSV hash";
SysvHash sysvhash;
uint64_t current_offset = offset;
this->stream_->setpos(offset);
const uint32_t* header = this->stream_->read_array<uint32_t>(2);
const uint32_t* header = reinterpret_cast<const uint32_t*>(
this->stream_->read(current_offset, 2 * sizeof(uint32_t)));
current_offset += 2 * sizeof(uint32_t);
if (header == nullptr) {
LOG(ERROR) << "Can't read SYSV Hash header";
return;
}
const uint32_t nbuckets = std::min<uint32_t>(header[0], Parser::NB_MAX_BUCKETS);
const uint32_t nchain = std::min<uint32_t>(header[1], Parser::NB_MAX_CHAINS);
try {
std::vector<uint32_t> buckets(nbuckets);
std::vector<uint32_t> buckets(nbuckets);
for (size_t i = 0; i < nbuckets; ++i) {
buckets[i] = this->stream_->read_integer<uint32_t>(current_offset);
current_offset += sizeof(uint32_t);
for (size_t i = 0; i < nbuckets; ++i) {
if (not this->stream_->can_read<uint32_t>()) {
break;
}
sysvhash.buckets_ = std::move(buckets);
}
catch (const read_out_of_bound&) {
throw corrupted("SYSV Hash, nbuckets corrupted");
}
catch (const std::bad_alloc&) {
throw corrupted("SYSV Hash, nbuckets corrupted");
buckets[i] = this->stream_->read<uint32_t>();
}
try {
std::vector<uint32_t> chains(nchain);
sysvhash.buckets_ = std::move(buckets);
for (size_t i = 0; i < nchain; ++i) {
chains[i] = this->stream_->read_integer<uint32_t>(current_offset);
current_offset += sizeof(uint32_t);
std::vector<uint32_t> chains(nchain);
for (size_t i = 0; i < nchain; ++i) {
if (not this->stream_->can_read<uint32_t>()) {
break;
}
chains[i] = this->stream_->read<uint32_t>();
}
sysvhash.chains_ = std::move(chains);
}
catch (const read_out_of_bound&) {
throw corrupted("SYSV Hash, nchain corrupted");
}
catch (const std::bad_alloc&) {
throw corrupted("SYSV Hash, nchain corrupted");
}
sysvhash.chains_ = std::move(chains);
this->binary_->sysv_hash_ = std::move(sysvhash);
@ -294,41 +286,46 @@ void Parser::parse_symbol_sysv_hash(uint64_t offset) {
void Parser::parse_notes(uint64_t offset, uint64_t size) {
VLOG(VDEBUG) << "Parsing Note segment";
uint64_t current_offset = offset;
this->stream_->setpos(offset);
uint64_t last_offset = offset + size;
while(current_offset < last_offset) {
uint32_t namesz = this->stream_->read_integer<uint32_t>(current_offset);
current_offset += sizeof(uint32_t);
while(this->stream_->pos() < last_offset) {
if (not this->stream_->can_read<uint32_t>()) {
break;
}
uint32_t namesz = this->stream_->read<uint32_t>();
VLOG(VDEBUG) << "Name size: " << std::hex << namesz;
uint32_t descsz = std::min(this->stream_->read_integer<uint32_t>(current_offset), Parser::MAX_NOTE_DESCRIPTION);
current_offset += sizeof(uint32_t);
if (not this->stream_->can_read<uint32_t>()) {
break;
}
uint32_t descsz = std::min(this->stream_->read<uint32_t>(), Parser::MAX_NOTE_DESCRIPTION);
VLOG(VDEBUG) << "Description size: " << std::hex << descsz;
NOTE_TYPES type = static_cast<NOTE_TYPES>(this->stream_->read_integer<uint32_t>(current_offset));
current_offset += sizeof(uint32_t);
if (not this->stream_->can_read<uint32_t>()) {
break;
}
NOTE_TYPES type = static_cast<NOTE_TYPES>(this->stream_->read<uint32_t>());
VLOG(VDEBUG) << "Type: " << std::hex << static_cast<size_t>(type);
if (namesz == 0) { // System reserves
break;
}
std::string name = this->stream_->get_string(current_offset, namesz);
std::string name = this->stream_->read_string(namesz);
VLOG(VDEBUG) << "Name: " << name << std::endl;
current_offset += namesz;
current_offset = align(current_offset, sizeof(uint32_t));
this->stream_->align(sizeof(uint32_t));
std::vector<uint8_t> description;
if (descsz > 0) {
const uint8_t* desc_ptr = reinterpret_cast<const uint8_t*>(
this->stream_->read(current_offset, descsz));
description = {desc_ptr, desc_ptr + descsz};
current_offset += descsz;
current_offset = align(current_offset, sizeof(uint32_t));
const uint8_t* desc_ptr = this->stream_->read_array<uint8_t>(descsz);
if (desc_ptr != nullptr) {
description = {desc_ptr, desc_ptr + descsz};
}
this->stream_->align(sizeof(uint32_t));
}
std::unique_ptr<Note> note;

File diff suppressed because it is too large Load Diff

@ -20,6 +20,8 @@
#include <functional>
#include <iterator>
#include "LIEF/ELF/Parser.hpp"
#include "LIEF/logging++.hpp"
#include "LIEF/ELF/hash.hpp"
@ -246,16 +248,19 @@ void Section::offset(uint64_t offset) {
std::vector<uint8_t> Section::content(void) const {
if (this->size() == 0) {
VLOG(VDEBUG) << "Section '" << this->name() << "' is empty";
//VLOG(VDEBUG) << "Section '" << this->name() << "' is empty";
return {};
}
if (this->datahandler_ == nullptr) {
VLOG(VDEBUG) << "Content from cache";
//VLOG(VDEBUG) << "Content from cache";
return this->content_c_;
}
VLOG(VDEBUG) << std::hex << "Content from Data Handler [0x" << this->offset_ << ", 0x" << this->size_ << "]";
//VLOG(VDEBUG) << std::hex << "Content from Data Handler [0x" << this->offset_ << ", 0x" << this->size_ << "]";
if (this->size() > Parser::MAX_SECTION_SIZE) {
return {};
}
DataHandler::Node& node = this->datahandler_->get(this->offset(), this->size(), DataHandler::Node::SECTION);
const std::vector<uint8_t>& binary_content = this->datahandler_->content();

@ -90,8 +90,7 @@ BinaryParser::BinaryParser(const std::string& file, const ParserConfig& conf) :
void BinaryParser::init(void) {
VLOG(VDEBUG) << "Parsing MachO" << std::endl;
try {
MACHO_TYPES type = static_cast<MACHO_TYPES>(
*reinterpret_cast<const uint32_t*>(this->stream_->read(0, sizeof(uint32_t))));
MACHO_TYPES type = static_cast<MACHO_TYPES>(this->stream_->peek<uint32_t>(0));
if (type == MACHO_TYPES::MH_MAGIC_64 or
type == MACHO_TYPES::MH_CIGAM_64 )
@ -118,31 +117,23 @@ void BinaryParser::init(void) {
}
void BinaryParser::parse_export_trie(uint64_t start, uint64_t current_offset, uint64_t end, const std::string& prefix) {
std::pair<uint64_t, uint64_t> value_delta = {0, 0};
if (current_offset >= end) {
void BinaryParser::parse_export_trie(uint64_t start, uint64_t end, const std::string& prefix) {
if (this->stream_->pos() >= end) {
return;
}
if (start > current_offset) {
if (start > this->stream_->pos()) {
return;
}
const uint8_t terminal_size = this->stream_->read_integer<uint8_t>(current_offset);
current_offset += sizeof(uint8_t);
uint64_t children_offset = current_offset + terminal_size;
const uint8_t terminal_size = this->stream_->read<uint8_t>();
uint64_t children_offset = this->stream_->pos() + terminal_size;
if (terminal_size != 0) {
uint64_t offset = current_offset - start;
uint64_t offset = this->stream_->pos() - start;
value_delta = this->stream_->read_uleb128(current_offset);
uint64_t flags = std::get<0>(value_delta);
current_offset += std::get<1>(value_delta);
value_delta = this->stream_->read_uleb128(current_offset);
uint64_t address = std::get<0>(value_delta);
current_offset += std::get<1>(value_delta);
uint64_t flags = this->stream_->read_uleb128();
uint64_t address = this->stream_->read_uleb128();
const std::string& symbol_name = prefix;
std::unique_ptr<ExportInfo> export_info{new ExportInfo{address, flags, offset}};
@ -167,22 +158,21 @@ void BinaryParser::parse_export_trie(uint64_t start, uint64_t current_offset, ui
this->binary_->dyld_info().export_info_.push_back(export_info.release());
}
const uint8_t nb_children = this->stream_->read_integer<uint8_t>(children_offset);
children_offset += sizeof(uint8_t);
this->stream_->setpos(children_offset);
const uint8_t nb_children = this->stream_->read<uint8_t>();
for (size_t i = 0; i < nb_children; ++i) {
std::string suffix = this->stream_->get_string(children_offset);
std::string suffix = this->stream_->read_string();
std::string name = prefix + suffix;
children_offset += suffix.size() + 1;
uint32_t child_node_offet = static_cast<uint32_t>(this->stream_->read_uleb128());
value_delta = this->stream_->read_uleb128(children_offset);
uint32_t child_node_offet = static_cast<uint32_t>(std::get<0>(value_delta));
children_offset += std::get<1>(value_delta);
if (start + child_node_offet == start) {
if (child_node_offet == 0) {
break;
}
this->parse_export_trie(start, start + child_node_offet, end, name);
size_t current_pos = this->stream_->pos();
this->stream_->setpos(start + child_node_offet);
this->parse_export_trie(start, end, name);
this->stream_->setpos(current_pos);
}
}
@ -198,17 +188,17 @@ void BinaryParser::parse_dyldinfo_export(void) {
return;
}
uint64_t current_offset = offset;
uint64_t end_offset = offset + size;
uint64_t end_offset = offset + size;
try {
const uint8_t* raw_trie = reinterpret_cast<const uint8_t*>(this->stream_->read(offset, size));
const uint8_t* raw_trie = this->stream_->peek_array<uint8_t>(offset, size);
dyldinfo.export_trie({raw_trie, raw_trie + size});
} catch (const exception& e) {
LOG(WARNING) << e.what();
}
this->parse_export_trie(offset, current_offset, end_offset, "");
this->stream_->setpos(offset);
this->parse_export_trie(offset, end_offset, "");
}
Binary* BinaryParser::get_binary(void) {

@ -71,7 +71,7 @@ void BinaryParser::parse(void) {
template<class MACHO_T>
void BinaryParser::parse_header(void) {
using header_t = typename MACHO_T::header;
this->binary_->header_ = {reinterpret_cast<const header_t*>(this->stream_->read(0, sizeof(header_t)))};
this->binary_->header_ = &this->stream_->peek<header_t>(0);
}
@ -98,11 +98,13 @@ void BinaryParser::parse_load_commands(void) {
}
for (size_t i = 0; i < nbcmds; ++i) {
const load_command* command = reinterpret_cast<const load_command*>(
this->stream_->read(loadcommands_offset, sizeof(load_command)));
if (not this->stream_->can_read<load_command>(loadcommands_offset)) {
break;
}
const load_command& command = this->stream_->peek<load_command>(loadcommands_offset);
std::unique_ptr<LoadCommand> load_command{nullptr};
switch (static_cast<LOAD_COMMAND_TYPES>(command->cmd)) {
switch (static_cast<LOAD_COMMAND_TYPES>(command.cmd)) {
// ===============
// Segment command
@ -111,16 +113,13 @@ void BinaryParser::parse_load_commands(void) {
case LOAD_COMMAND_TYPES::LC_SEGMENT:
{
uint64_t local_offset = loadcommands_offset;
load_command = std::unique_ptr<SegmentCommand>{new SegmentCommand{
reinterpret_cast<const segment_command_t*>(
this->stream_->read(loadcommands_offset, sizeof(segment_command_t)))}};
load_command = std::unique_ptr<SegmentCommand>{new SegmentCommand{&this->stream_->peek<segment_command_t>(loadcommands_offset)}};
local_offset += sizeof(segment_command_t);
SegmentCommand* segment = dynamic_cast<SegmentCommand*>(load_command.get());
const uint8_t* content = static_cast<const uint8_t*>(
this->stream_->read(segment->file_offset(), segment->file_size()));
const uint8_t* content = this->stream_->peek_array<uint8_t>(segment->file_offset(), segment->file_size());
segment->content({
content,
@ -131,7 +130,7 @@ void BinaryParser::parse_load_commands(void) {
// Sections
// --------
for (size_t j = 0; j < segment->numberof_sections(); ++j) {
const section_t* section_header = reinterpret_cast<const section_t*>(this->stream_->read(local_offset, sizeof(section_t)));
const section_t* section_header = &this->stream_->peek<section_t>(local_offset);
std::unique_ptr<Section> section{new Section{section_header}};
section->segment_ = segment;
segment->sections_.push_back(section.release());
@ -148,13 +147,11 @@ void BinaryParser::parse_load_commands(void) {
case LOAD_COMMAND_TYPES::LC_ID_DYLIB:
case LOAD_COMMAND_TYPES::LC_LOAD_DYLIB:
{
const dylib_command* cmd =
reinterpret_cast<const dylib_command*>(
this->stream_->read(loadcommands_offset, sizeof(dylib_command)));
const dylib_command* cmd = &this->stream_->peek<dylib_command>(loadcommands_offset);
load_command = std::unique_ptr<DylibCommand>{new DylibCommand{cmd}};
const uint32_t str_name_offset = cmd->dylib.name;
std::string name = this->stream_->get_string(loadcommands_offset + str_name_offset);
std::string name = this->stream_->peek_string_at(loadcommands_offset + str_name_offset);
dynamic_cast<DylibCommand*>(load_command.get())->name(name);
break;
@ -165,13 +162,11 @@ void BinaryParser::parse_load_commands(void) {
// =============
case LOAD_COMMAND_TYPES::LC_RPATH:
{
const rpath_command* cmd =
reinterpret_cast<const rpath_command*>(
this->stream_->read(loadcommands_offset, sizeof(rpath_command)));
const rpath_command* cmd = &this->stream_->peek<rpath_command>(loadcommands_offset);
load_command = std::unique_ptr<RPathCommand>{new RPathCommand{cmd}};
const uint32_t str_path_offset = cmd->path;
std::string path = this->stream_->get_string(loadcommands_offset + str_path_offset);
std::string path = this->stream_->peek_string_at(loadcommands_offset + str_path_offset);
dynamic_cast<RPathCommand*>(load_command.get())->path(path);
break;
@ -183,9 +178,7 @@ void BinaryParser::parse_load_commands(void) {
case LOAD_COMMAND_TYPES::LC_UUID:
{
VLOG(VDEBUG) << "[+] Building UUID";
const uuid_command* cmd =
reinterpret_cast<const uuid_command*>(
this->stream_->read(loadcommands_offset, sizeof(uuid_command)));
const uuid_command* cmd = &this->stream_->peek<uuid_command>(loadcommands_offset);
load_command = std::unique_ptr<UUIDCommand>{new UUIDCommand{cmd}};
break;
}
@ -196,12 +189,10 @@ void BinaryParser::parse_load_commands(void) {
case LOAD_COMMAND_TYPES::LC_LOAD_DYLINKER:
case LOAD_COMMAND_TYPES::LC_ID_DYLINKER:
{
const dylinker_command* cmd =
reinterpret_cast<const dylinker_command*>(
this->stream_->read(loadcommands_offset, sizeof(dylinker_command)));
const dylinker_command* cmd = &this->stream_->peek<dylinker_command>(loadcommands_offset);
const uint32_t linker_name_offset = cmd->name;
std::string name = this->stream_->get_string(
std::string name = this->stream_->peek_string_at(
loadcommands_offset +
linker_name_offset);
@ -217,13 +208,11 @@ void BinaryParser::parse_load_commands(void) {
{
VLOG(VDEBUG) << "[+] Parsing LC_PREBOUND_DYLIB";
load_command = std::unique_ptr<LoadCommand>{new LoadCommand{command}};
const prebound_dylib_command* cmd =
reinterpret_cast<const prebound_dylib_command*>(
this->stream_->read(loadcommands_offset, sizeof(prebound_dylib_command)));
load_command = std::unique_ptr<LoadCommand>{new LoadCommand{&command}};
const prebound_dylib_command* cmd = &this->stream_->peek<prebound_dylib_command>(loadcommands_offset);
std::string name = this->stream_->get_string(
std::string name = this->stream_->peek_string_at(
loadcommands_offset +
cmd->name);
@ -240,9 +229,7 @@ void BinaryParser::parse_load_commands(void) {
{
VLOG(VDEBUG) << "[+] Parsing LC_THREAD";
const thread_command* cmd =
reinterpret_cast<const thread_command*>(
this->stream_->read(loadcommands_offset, sizeof(thread_command)));
const thread_command* cmd = &this->stream_->peek<thread_command>(loadcommands_offset);
load_command = std::unique_ptr<ThreadCommand>{new ThreadCommand{cmd}};
ThreadCommand* thread = dynamic_cast<ThreadCommand*>(load_command.get());
@ -252,8 +239,7 @@ void BinaryParser::parse_load_commands(void) {
switch(this->binary_->header().cpu_type()) {
case CPU_TYPES::CPU_TYPE_X86:
{
const uint8_t* pstart = reinterpret_cast<const uint8_t*>(
this->stream_->read(loadcommands_offset + sizeof(thread_command), sizeof(x86_thread_state_t)));
const uint8_t* pstart = this->stream_->peek_array<uint8_t>(loadcommands_offset + sizeof(thread_command), sizeof(x86_thread_state_t));
thread->state_ = {pstart, pstart + sizeof(x86_thread_state_t)};
break;
@ -261,24 +247,21 @@ void BinaryParser::parse_load_commands(void) {
case CPU_TYPES::CPU_TYPE_X86_64:
{
const uint8_t* pstart = reinterpret_cast<const uint8_t*>(
this->stream_->read(loadcommands_offset + sizeof(thread_command), sizeof(x86_thread_state64_t)));
const uint8_t* pstart = this->stream_->peek_array<uint8_t>(loadcommands_offset + sizeof(thread_command), sizeof(x86_thread_state64_t));
thread->state_ = {pstart, pstart + sizeof(x86_thread_state64_t)};
break;
}
case CPU_TYPES::CPU_TYPE_ARM:
{
const uint8_t* pstart = reinterpret_cast<const uint8_t*>(
this->stream_->read(loadcommands_offset + sizeof(thread_command), sizeof(arm_thread_state_t)));
const uint8_t* pstart = this->stream_->peek_array<uint8_t>(loadcommands_offset + sizeof(thread_command), sizeof(arm_thread_state_t));
thread->state_ = {pstart, pstart + sizeof(arm_thread_state_t)};
break;
}
case CPU_TYPES::CPU_TYPE_ARM64:
{
const uint8_t* pstart = reinterpret_cast<const uint8_t*>(
this->stream_->read(loadcommands_offset + sizeof(thread_command), sizeof(arm_thread_state64_t)));
const uint8_t* pstart = this->stream_->peek_array<uint8_t>(loadcommands_offset + sizeof(thread_command), sizeof(arm_thread_state64_t));
thread->state_ = {pstart, pstart + sizeof(arm_thread_state64_t)};
break;
}
@ -299,7 +282,7 @@ void BinaryParser::parse_load_commands(void) {
VLOG(VDEBUG) << "[+] Parsing LC_ROUTINE";
load_command = std::unique_ptr<LoadCommand>{new LoadCommand{command}};
load_command = std::unique_ptr<LoadCommand>{new LoadCommand{&command}};
break;
}
@ -311,23 +294,20 @@ void BinaryParser::parse_load_commands(void) {
using nlist_t = typename MACHO_T::nlist;
VLOG(VDEBUG) << "[+] Parsing symbols";
const symtab_command* cmd =
reinterpret_cast<const symtab_command*>(
this->stream_->read(loadcommands_offset, sizeof(symtab_command)));
const symtab_command* cmd = &this->stream_->peek<symtab_command>(loadcommands_offset);
load_command = std::unique_ptr<SymbolCommand>{new SymbolCommand{cmd}};
const nlist_t* nlist = reinterpret_cast<const nlist_t*>(
this->stream_->read(cmd->symoff, sizeof(nlist_t)));
const nlist_t* nlist = this->stream_->peek_array<nlist_t>(cmd->symoff, cmd->nsyms);
for (size_t j = 0; j < cmd->nsyms; ++j) {
std::unique_ptr<Symbol> symbol{new Symbol{&nlist[j]}};
uint32_t idx = nlist[j].n_strx;
if (idx > 0) {
symbol->name(
this->stream_->get_string(cmd->stroff + idx));
this->stream_->peek_string_at(cmd->stroff + idx));
}
this->binary_->symbols_.push_back(symbol.release());
}
@ -341,9 +321,7 @@ void BinaryParser::parse_load_commands(void) {
case LOAD_COMMAND_TYPES::LC_DYSYMTAB:
{
VLOG(VDEBUG) << "[+] Parsing dynamic symbols";
const dysymtab_command* cmd =
reinterpret_cast<const dysymtab_command*>(
this->stream_->read(loadcommands_offset, sizeof(dysymtab_command)));
const dysymtab_command* cmd = &this->stream_->peek<dysymtab_command>(loadcommands_offset);
load_command = std::unique_ptr<DynamicSymbolCommand>{new DynamicSymbolCommand{cmd}};
break;
@ -356,9 +334,7 @@ void BinaryParser::parse_load_commands(void) {
case LOAD_COMMAND_TYPES::LC_DYLD_INFO_ONLY:
{
VLOG(VDEBUG) << "[+] Parsing dyld information";
const dyld_info_command* cmd =
reinterpret_cast<const dyld_info_command*>(
this->stream_->read(loadcommands_offset, sizeof(dyld_info_command)));
const dyld_info_command* cmd = &this->stream_->peek<dyld_info_command>(loadcommands_offset);
load_command = std::unique_ptr<DyldInfo>{new DyldInfo{cmd}};
dynamic_cast<DyldInfo*>(load_command.get())->binary_ = this->binary_;
@ -372,9 +348,7 @@ void BinaryParser::parse_load_commands(void) {
{
VLOG(VDEBUG) << "[+] Parsing LC_SOURCE_VERSION";
const source_version_command* cmd =
reinterpret_cast<const source_version_command*>(
this->stream_->read(loadcommands_offset, sizeof(version_min_command)));
const source_version_command* cmd = &this->stream_->peek<source_version_command>(loadcommands_offset);
load_command = std::unique_ptr<SourceVersion>{new SourceVersion{cmd}};
VLOG(VDEBUG) << "Version: " << std::hex << cmd->version;
@ -384,11 +358,9 @@ void BinaryParser::parse_load_commands(void) {
case LOAD_COMMAND_TYPES::LC_VERSION_MIN_MACOSX:
case LOAD_COMMAND_TYPES::LC_VERSION_MIN_IPHONEOS:
{
VLOG(VDEBUG) << "[+] Parsing " << to_string(static_cast<LOAD_COMMAND_TYPES>(command->cmd));
VLOG(VDEBUG) << "[+] Parsing " << to_string(static_cast<LOAD_COMMAND_TYPES>(command.cmd));
const version_min_command* cmd =
reinterpret_cast<const version_min_command*>(
this->stream_->read(loadcommands_offset, sizeof(version_min_command)));
const version_min_command* cmd = &this->stream_->peek<version_min_command>(loadcommands_offset);
VLOG(VDEBUG) << "Version: " << std::hex << cmd->version;
VLOG(VDEBUG) << "SDK: " << std::hex << cmd->sdk;
@ -399,13 +371,11 @@ void BinaryParser::parse_load_commands(void) {
case LOAD_COMMAND_TYPES::LC_CODE_SIGNATURE:
{
const linkedit_data_command* cmd =
reinterpret_cast<const linkedit_data_command*>(
this->stream_->read(loadcommands_offset, sizeof(linkedit_data_command)));
const linkedit_data_command* cmd = &this->stream_->peek<linkedit_data_command>(loadcommands_offset);
load_command = std::unique_ptr<CodeSignature>{new CodeSignature{cmd}};
CodeSignature* sig = load_command.get()->as<CodeSignature>();
const uint8_t* content = reinterpret_cast<const uint8_t*>(this->stream_->read(sig->data_offset(), sig->data_size()));
const uint8_t* content = this->stream_->peek_array<uint8_t>(sig->data_offset(), sig->data_size());
sig->raw_signature_ = {content, content + sig->data_size()};
break;
@ -414,14 +384,12 @@ void BinaryParser::parse_load_commands(void) {
case LOAD_COMMAND_TYPES::LC_DATA_IN_CODE:
{
const linkedit_data_command* cmd =
reinterpret_cast<const linkedit_data_command*>(
this->stream_->read(loadcommands_offset, sizeof(linkedit_data_command)));
const linkedit_data_command* cmd = &this->stream_->peek<linkedit_data_command>(loadcommands_offset);
load_command = std::unique_ptr<DataInCode>{new DataInCode{cmd}};
DataInCode* datacode = load_command.get()->as<DataInCode>();
const data_in_code_entry* entries = reinterpret_cast<const data_in_code_entry*>(this->stream_->read(datacode->data_offset(), datacode->data_size()));
const size_t nb_entries = datacode->data_size() / sizeof(data_in_code_entry);
const data_in_code_entry* entries = this->stream_->peek_array<data_in_code_entry>(datacode->data_offset(), nb_entries);
for (size_t i = 0; i < nb_entries; ++i) {
datacode->add(&entries[i]);
}
@ -478,9 +446,7 @@ void BinaryParser::parse_load_commands(void) {
{
VLOG(VDEBUG) << "[+] Parsing LC_MAIN";
const entry_point_command* cmd =
reinterpret_cast<const entry_point_command*>(
this->stream_->read(loadcommands_offset, sizeof(entry_point_command)));
const entry_point_command* cmd = &this->stream_->peek<entry_point_command>(loadcommands_offset);
load_command = std::unique_ptr<MainCommand>{new MainCommand{cmd}};
break;
@ -492,26 +458,23 @@ void BinaryParser::parse_load_commands(void) {
case LOAD_COMMAND_TYPES::LC_FUNCTION_STARTS:
{
VLOG(VDEBUG) << "[+] Parsing LC_FUNCTION_STARTS";
const linkedit_data_command* cmd =
reinterpret_cast<const linkedit_data_command*>(
this->stream_->read(loadcommands_offset, sizeof(linkedit_data_command)));
const linkedit_data_command* cmd = &this->stream_->peek<linkedit_data_command>(loadcommands_offset);
load_command = std::unique_ptr<FunctionStarts>{new FunctionStarts{cmd}};
uint64_t offset = cmd->dataoff;
std::pair<uint64_t, uint64_t> value_delta;
uint64_t value = 0;
FunctionStarts* fstart = dynamic_cast<FunctionStarts*>(load_command.get());
this->stream_->setpos(cmd->dataoff);
do {
value_delta = this->stream_->read_uleb128(offset);
if (std::get<0>(value_delta) == 0) {
uint64_t val = this->stream_->read_uleb128();
if (val == 0) {
break;
}
value += std::get<0>(value_delta);
offset += std::get<1>(value_delta);
value += val;
VLOG(VDEBUG) << "Value: " << std::hex << value;
fstart->add_function(value);
} while(offset < (cmd->dataoff + cmd->datasize) and std::get<0>(value_delta) > 0);
} while(this->stream_->pos() < (cmd->dataoff + cmd->datasize));
break;
}
@ -525,26 +488,25 @@ void BinaryParser::parse_load_commands(void) {
default:
{
LOG(WARNING) << "Command '" << to_string(static_cast<LOAD_COMMAND_TYPES>(command->cmd))
LOG(WARNING) << "Command '" << to_string(static_cast<LOAD_COMMAND_TYPES>(command.cmd))
<< "' not parsed";
load_command = std::unique_ptr<LoadCommand>{new LoadCommand{command}};
load_command = std::unique_ptr<LoadCommand>{new LoadCommand{&command}};
}
}
if (load_command != nullptr) {
const uint8_t* content = static_cast<const uint8_t*>(
this->stream_->read(loadcommands_offset, command->cmdsize));
const uint8_t* content = this->stream_->peek_array<uint8_t>(loadcommands_offset, command.cmdsize);
load_command->data({
content,
content + command->cmdsize
content + command.cmdsize
});
load_command->command_offset(loadcommands_offset);
this->binary_->commands_.push_back(load_command.release());
}
loadcommands_offset += command->cmdsize;
loadcommands_offset += command.cmdsize;
}
}
@ -573,17 +535,15 @@ void BinaryParser::parse_relocations(Section& section) {
std::unique_ptr<RelocationObject> reloc{nullptr};
for (size_t i = 0; i < numberof_relocations; ++i) {
int32_t address = this->stream_->read_integer<int32_t>(current_reloc_offset);
int32_t address = this->stream_->peek<int32_t>(current_reloc_offset);
bool is_scattered = static_cast<bool>(address & R_SCATTERED);
if (is_scattered) {
const scattered_relocation_info* reloc_info = reinterpret_cast<const scattered_relocation_info*>(
this->stream_->read(current_reloc_offset, sizeof(scattered_relocation_info)));
const scattered_relocation_info* reloc_info = &this->stream_->peek<scattered_relocation_info>(current_reloc_offset);
reloc = std::unique_ptr<RelocationObject>{new RelocationObject{reloc_info}};
reloc->section_ = &section;
} else {
const relocation_info* reloc_info = reinterpret_cast<const relocation_info*>(
this->stream_->read(current_reloc_offset, sizeof(relocation_info)));
const relocation_info* reloc_info = &this->stream_->peek<relocation_info>(current_reloc_offset);
reloc = std::unique_ptr<RelocationObject>{new RelocationObject{reloc_info}};
reloc->section_ = &section;
@ -640,13 +600,12 @@ void BinaryParser::parse_dyldinfo_rebases() {
}
try {
const uint8_t* raw_rebase = reinterpret_cast<const uint8_t*>(this->stream_->read(offset, size));
const uint8_t* raw_rebase = this->stream_->peek_array<uint8_t>(offset, size);
dyldinfo.rebase_opcodes({raw_rebase, raw_rebase + size});
} catch (const exception& e) {
LOG(WARNING) << e.what();
}
uint64_t current_offset = offset;
uint64_t end_offset = offset + size;
bool done = false;
@ -655,12 +614,13 @@ void BinaryParser::parse_dyldinfo_rebases() {
uint64_t segment_offset = 0;
uint32_t count = 0;
uint32_t skip = 0;
std::pair<uint64_t, uint64_t> value_delta = {0, 0};
while (not done and current_offset < end_offset) {
uint8_t imm = this->stream_->read_integer<uint8_t>(current_offset) & REBASE_IMMEDIATE_MASK;
uint8_t opcode = this->stream_->read_integer<uint8_t>(current_offset) & REBASE_OPCODE_MASK;
current_offset += sizeof(uint8_t);
this->stream_->setpos(offset);
while (not done and this->stream_->pos() < end_offset) {
uint8_t imm = this->stream_->peek<uint8_t>() & REBASE_IMMEDIATE_MASK;
uint8_t opcode = this->stream_->read<uint8_t>() & REBASE_OPCODE_MASK;
switch(static_cast<REBASE_OPCODES>(opcode)) {
case REBASE_OPCODES::REBASE_OPCODE_DONE:
{
@ -676,23 +636,16 @@ void BinaryParser::parse_dyldinfo_rebases() {
case REBASE_OPCODES::REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
{
value_delta = this->stream_->read_uleb128(current_offset);
segment_index = imm;
segment_offset = std::get<0>(value_delta);
current_offset += std::get<1>(value_delta);
segment_offset = this->stream_->read_uleb128();
break;
}
case REBASE_OPCODES::REBASE_OPCODE_ADD_ADDR_ULEB:
{
value_delta = this->stream_->read_uleb128(current_offset);
segment_offset += this->stream_->read_uleb128();
segment_offset += std::get<0>(value_delta);
current_offset += std::get<1>(value_delta);
break;
}
@ -713,12 +666,7 @@ void BinaryParser::parse_dyldinfo_rebases() {
case REBASE_OPCODES::REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
{
value_delta = this->stream_->read_uleb128(current_offset);
count = std::get<0>(value_delta);
current_offset += std::get<1>(value_delta);
count = this->stream_->read_uleb128();
for (size_t i = 0; i < count; ++i) {
this->do_rebase<MACHO_T>(type, segment_index, segment_offset);
segment_offset += sizeof(pint_t);
@ -731,29 +679,19 @@ void BinaryParser::parse_dyldinfo_rebases() {
this->do_rebase<MACHO_T>(type, segment_index, segment_offset);
value_delta = this->stream_->read_uleb128(current_offset);
segment_offset += this->stream_->read_uleb128() + sizeof(pint_t);
segment_offset += std::get<0>(value_delta) + sizeof(pint_t);
current_offset += std::get<1>(value_delta);
break;
}
case REBASE_OPCODES::REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
{
// Count
value_delta = this->stream_->read_uleb128(current_offset);
count += std::get<0>(value_delta);
current_offset += std::get<1>(value_delta);
count += this->stream_->read_uleb128();
// Skip
value_delta = this->stream_->read_uleb128(current_offset);
skip += this->stream_->read_uleb128();
skip += std::get<0>(value_delta);
current_offset += std::get<1>(value_delta);
for (size_t i = 0; i < count; ++i) {
this->do_rebase<MACHO_T>(type, segment_index, segment_offset);
@ -863,13 +801,12 @@ void BinaryParser::parse_dyldinfo_generic_bind() {
}
try {
const uint8_t* raw_binding = reinterpret_cast<const uint8_t*>(this->stream_->read(offset, size));
const uint8_t* raw_binding = this->stream_->peek_array<uint8_t>(offset, size);
dyldinfo.bind_opcodes({raw_binding, raw_binding + size});
} catch (const exception& e) {
LOG(WARNING) << e.what();
}
uint64_t current_offset = offset;
uint64_t end_offset = offset + size;
uint8_t type = 0;
@ -885,14 +822,12 @@ void BinaryParser::parse_dyldinfo_generic_bind() {
bool is_weak_import = false;
bool done = false;
std::pair<uint64_t, uint64_t> value_delta = {0, 0};
std::pair<int64_t, uint64_t> svalue_delta = {0, 0};
it_segments segments = this->binary_->segments();
while (not done and current_offset < end_offset) {
uint8_t imm = this->stream_->read_integer<uint8_t>(current_offset) & BIND_IMMEDIATE_MASK;
BIND_OPCODES opcode = static_cast<BIND_OPCODES>(this->stream_->read_integer<uint8_t>(current_offset) & BIND_OPCODE_MASK);
current_offset += sizeof(uint8_t);
this->stream_->setpos(offset);
while (not done and this->stream_->pos() < end_offset) {
uint8_t imm = this->stream_->peek<uint8_t>() & BIND_IMMEDIATE_MASK;
BIND_OPCODES opcode = static_cast<BIND_OPCODES>(this->stream_->read<uint8_t>() & BIND_OPCODE_MASK);
switch (opcode) {
case BIND_OPCODES::BIND_OPCODE_DONE:
@ -910,9 +845,7 @@ void BinaryParser::parse_dyldinfo_generic_bind() {
case BIND_OPCODES::BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
{
value_delta = this->stream_->read_uleb128(current_offset);
library_ordinal = std::get<0>(value_delta);
current_offset += std::get<1>(value_delta);
library_ordinal = this->stream_->read_uleb128();
break;
}
@ -931,8 +864,7 @@ void BinaryParser::parse_dyldinfo_generic_bind() {
case BIND_OPCODES::BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
{
symbol_name = this->stream_->get_string(current_offset);
current_offset += symbol_name.size() + 1;
symbol_name = this->stream_->read_string();
if ((imm & BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0) {
is_weak_import = true;
@ -950,28 +882,21 @@ void BinaryParser::parse_dyldinfo_generic_bind() {
case BIND_OPCODES::BIND_OPCODE_SET_ADDEND_SLEB:
{
svalue_delta = this->stream_->read_sleb128(current_offset);
addend = std::get<0>(svalue_delta);
current_offset += std::get<1>(svalue_delta);
addend = this->stream_->read_sleb128();
break;
}
case BIND_OPCODES::BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
{
segment_idx = imm;
value_delta = this->stream_->read_uleb128(current_offset);
segment_offset = std::get<0>(value_delta);
current_offset += std::get<1>(value_delta);
segment_idx = imm;
segment_offset = this->stream_->read_uleb128();
break;
}
case BIND_OPCODES::BIND_OPCODE_ADD_ADDR_ULEB:
{
value_delta = this->stream_->read_uleb128(current_offset);
segment_offset += std::get<0>(value_delta);
current_offset += std::get<1>(value_delta);
segment_offset += this->stream_->read_uleb128();
break;
}
@ -1003,9 +928,7 @@ void BinaryParser::parse_dyldinfo_generic_bind() {
addend,
is_weak_import,
segments);
value_delta = this->stream_->read_uleb128(current_offset);
segment_offset += std::get<0>(value_delta) + sizeof(pint_t);
current_offset += std::get<1>(value_delta);
segment_offset += this->stream_->read_uleb128() + sizeof(pint_t);
break;
}
@ -1029,14 +952,10 @@ void BinaryParser::parse_dyldinfo_generic_bind() {
{
// Count
value_delta = this->stream_->read_uleb128(current_offset);
count = std::get<0>(value_delta);
current_offset += std::get<1>(value_delta);
count = this->stream_->read_uleb128();
// Skip
value_delta = this->stream_->read_uleb128(current_offset);
skip = std::get<0>(value_delta);
current_offset += std::get<1>(value_delta);
skip = this->stream_->read_uleb128();
for (size_t i = 0; i < count; ++i) {
this->do_bind<MACHO_T>(
@ -1080,13 +999,12 @@ void BinaryParser::parse_dyldinfo_weak_bind() {
}
try {
const uint8_t* raw_binding = reinterpret_cast<const uint8_t*>(this->stream_->read(offset, size));
const uint8_t* raw_binding = this->stream_->peek_array<uint8_t>(offset, size);
dyldinfo.weak_bind_opcodes({raw_binding, raw_binding + size});
} catch (const exception& e) {
LOG(WARNING) << e.what();
}
uint64_t current_offset = offset;
uint64_t end_offset = offset + size;
uint8_t type = 0;
@ -1101,15 +1019,13 @@ void BinaryParser::parse_dyldinfo_weak_bind() {
bool is_weak_import = true;
bool done = false;
std::pair<uint64_t, uint64_t> value_delta = {0, 0};
std::pair<int64_t, uint64_t> svalue_delta = {0, 0};
it_segments segments = this->binary_->segments();
while (not done and current_offset < end_offset) {
uint8_t imm = this->stream_->read_integer<uint8_t>(current_offset) & BIND_IMMEDIATE_MASK;
BIND_OPCODES opcode = static_cast<BIND_OPCODES>(this->stream_->read_integer<uint8_t>(current_offset) & BIND_OPCODE_MASK);
current_offset += sizeof(uint8_t);
this->stream_->setpos(offset);
while (not done and this->stream_->pos() < end_offset) {
uint8_t imm = this->stream_->peek<uint8_t>() & BIND_IMMEDIATE_MASK;
BIND_OPCODES opcode = static_cast<BIND_OPCODES>(this->stream_->read<uint8_t>() & BIND_OPCODE_MASK);
switch (opcode) {
case BIND_OPCODES::BIND_OPCODE_DONE:
@ -1121,8 +1037,7 @@ void BinaryParser::parse_dyldinfo_weak_bind() {
case BIND_OPCODES::BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
{
symbol_name = this->stream_->get_string(current_offset);
current_offset += symbol_name.size() + 1;
symbol_name = this->stream_->read_string();
if ((imm & BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) != 0) {
// TODO: STRONG
@ -1139,20 +1054,15 @@ void BinaryParser::parse_dyldinfo_weak_bind() {
case BIND_OPCODES::BIND_OPCODE_SET_ADDEND_SLEB:
{
svalue_delta = this->stream_->read_sleb128(current_offset);
addend = std::get<0>(svalue_delta);
current_offset += std::get<1>(svalue_delta);
addend = this->stream_->read_sleb128();
break;
}
case BIND_OPCODES::BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
{
segment_idx = imm;
value_delta = this->stream_->read_uleb128(current_offset);
segment_offset = std::get<0>(value_delta);
current_offset += std::get<1>(value_delta);
segment_idx = imm;
segment_offset = this->stream_->read_uleb128();
break;
}
@ -1160,9 +1070,7 @@ void BinaryParser::parse_dyldinfo_weak_bind() {
case BIND_OPCODES::BIND_OPCODE_ADD_ADDR_ULEB:
{
value_delta = this->stream_->read_uleb128(current_offset);
segment_offset += std::get<0>(value_delta);
current_offset += std::get<1>(value_delta);
segment_offset += this->stream_->read_uleb128();
break;
}
@ -1196,9 +1104,7 @@ void BinaryParser::parse_dyldinfo_weak_bind() {
addend,
is_weak_import,
segments);
value_delta = this->stream_->read_uleb128(current_offset);
segment_offset += std::get<0>(value_delta) + sizeof(pint_t);
current_offset += std::get<1>(value_delta);
segment_offset += this->stream_->read_uleb128() + sizeof(pint_t);
break;
}
@ -1224,14 +1130,10 @@ void BinaryParser::parse_dyldinfo_weak_bind() {
{
// Count
value_delta = this->stream_->read_uleb128(current_offset);
count = std::get<0>(value_delta);
current_offset += std::get<1>(value_delta);
count = this->stream_->read_uleb128();
// Skip
value_delta = this->stream_->read_uleb128(current_offset);
skip = std::get<0>(value_delta);
current_offset += std::get<1>(value_delta);
skip = this->stream_->read_uleb128();
for (size_t i = 0; i < count; ++i) {
this->do_bind<MACHO_T>(
@ -1277,7 +1179,7 @@ void BinaryParser::parse_dyldinfo_lazy_bind() {
}
try {
const uint8_t* raw_binding = reinterpret_cast<const uint8_t*>(this->stream_->read(offset, size));
const uint8_t* raw_binding = this->stream_->peek_array<uint8_t>(offset, size);
dyldinfo.lazy_bind_opcodes({raw_binding, raw_binding + size});
} catch (const exception& e) {
LOG(WARNING) << e.what();
@ -1286,7 +1188,7 @@ void BinaryParser::parse_dyldinfo_lazy_bind() {
uint64_t current_offset = offset;
uint64_t end_offset = offset + size;
uint32_t lazy_offset = 0;
//uint32_t lazy_offset = 0;
uint8_t segment_idx = 0;
uint64_t segment_offset = 0;
std::string symbol_name = "";
@ -1294,20 +1196,17 @@ void BinaryParser::parse_dyldinfo_lazy_bind() {
int64_t addend = 0;
bool is_weak_import = false;
std::pair<uint64_t, uint64_t> value_delta = {0, 0};
std::pair< int64_t, uint64_t> svalue_delta = {0, 0};
it_segments segments = this->binary_->segments();
while (current_offset < end_offset) {
uint8_t imm = this->stream_->read_integer<uint8_t>(current_offset) & BIND_IMMEDIATE_MASK;
BIND_OPCODES opcode = static_cast<BIND_OPCODES>(this->stream_->read_integer<uint8_t>(current_offset) & BIND_OPCODE_MASK);
this->stream_->setpos(offset);
while (this->stream_->pos() < end_offset) {
uint8_t imm = this->stream_->peek<uint8_t>() & BIND_IMMEDIATE_MASK;
BIND_OPCODES opcode = static_cast<BIND_OPCODES>(this->stream_->read<uint8_t>() & BIND_OPCODE_MASK);
current_offset += sizeof(uint8_t);
switch (opcode) {
case BIND_OPCODES::BIND_OPCODE_DONE:
{
lazy_offset = current_offset - offset;
//lazy_offset = current_offset - offset;
break;
}
@ -1319,11 +1218,7 @@ void BinaryParser::parse_dyldinfo_lazy_bind() {
case BIND_OPCODES::BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
{
value_delta = this->stream_->read_uleb128(current_offset);
library_ordinal = std::get<0>(value_delta);
current_offset += std::get<1>(value_delta);
library_ordinal = this->stream_->read_uleb128();
break;
}
@ -1341,8 +1236,7 @@ void BinaryParser::parse_dyldinfo_lazy_bind() {
case BIND_OPCODES::BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
{
symbol_name = this->stream_->get_string(current_offset);
current_offset += symbol_name.size() + 1;
symbol_name = this->stream_->read_string();
if ((imm & BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0) {
is_weak_import = true;
@ -1354,19 +1248,14 @@ void BinaryParser::parse_dyldinfo_lazy_bind() {
case BIND_OPCODES::BIND_OPCODE_SET_ADDEND_SLEB:
{
svalue_delta = this->stream_->read_sleb128(current_offset);
addend = std::get<0>(svalue_delta);
current_offset += std::get<1>(svalue_delta);
addend = this->stream_->read_sleb128();;
break;
}
case BIND_OPCODES::BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
{
segment_idx = imm;
value_delta = this->stream_->read_uleb128(current_offset);
segment_offset = std::get<0>(value_delta);
current_offset += std::get<1>(value_delta);
segment_idx = imm;
segment_offset = this->stream_->read_uleb128();
break;
}

@ -156,9 +156,6 @@ std::string DyldInfo::show_rebases_opcodes(void) const {
std::ostringstream output;
const buffer_t& rebase_opcodes = this->rebase_opcodes();
uint64_t current_offset = 0;
uint64_t end_offset = rebase_opcodes.size();
bool done = false;
uint8_t type = 0;
uint32_t segment_index = 0;
@ -166,15 +163,13 @@ std::string DyldInfo::show_rebases_opcodes(void) const {
uint32_t count = 0;
uint32_t skip = 0;
VectorStream rebase_stream{rebase_opcodes};
std::pair<uint64_t, uint64_t> value_delta = {0, 0};
const std::string tab = " ";
it_segments segments = this->binary_->segments();
while (not done and current_offset < end_offset) {
uint8_t imm = rebase_stream.read_integer<uint8_t>(current_offset) & REBASE_IMMEDIATE_MASK;
uint8_t opcode = rebase_stream.read_integer<uint8_t>(current_offset) & REBASE_OPCODE_MASK;
current_offset += sizeof(uint8_t);
while (not done and rebase_stream.pos() < rebase_opcodes.size()) {
uint8_t imm = rebase_stream.peek<uint8_t>() & REBASE_IMMEDIATE_MASK;
uint8_t opcode = rebase_stream.read<uint8_t>() & REBASE_OPCODE_MASK;
switch(static_cast<REBASE_OPCODES>(opcode)) {
case REBASE_OPCODES::REBASE_OPCODE_DONE:
@ -195,12 +190,10 @@ std::string DyldInfo::show_rebases_opcodes(void) const {
case REBASE_OPCODES::REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
{
value_delta = rebase_stream.read_uleb128(current_offset);
segment_index = imm;
segment_offset = std::get<0>(value_delta);
segment_offset = rebase_stream.read_uleb128();
current_offset += std::get<1>(value_delta);
output << "[" << to_string(static_cast<REBASE_OPCODES>(opcode)) << "] ";
output << "Segment Index := " << std::dec << segment_index << " (" << segments[segment_index].name() << ") ";
@ -212,14 +205,12 @@ std::string DyldInfo::show_rebases_opcodes(void) const {
case REBASE_OPCODES::REBASE_OPCODE_ADD_ADDR_ULEB:
{
value_delta = rebase_stream.read_uleb128(current_offset);
segment_offset += std::get<0>(value_delta);
current_offset += std::get<1>(value_delta);
uint64_t val = rebase_stream.read_uleb128();
segment_offset += val;
output << "[" << to_string(static_cast<REBASE_OPCODES>(opcode)) << "] ";
output << "Segment Offset += " << std::hex << std::showbase << std::get<0>(value_delta) << " (" << segment_offset << ")";
output << "Segment Offset += " << std::hex << std::showbase << val << " (" << segment_offset << ")";
output << std::endl;
break;
}
@ -260,12 +251,7 @@ std::string DyldInfo::show_rebases_opcodes(void) const {
case REBASE_OPCODES::REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
{
value_delta = rebase_stream.read_uleb128(current_offset);
count = std::get<0>(value_delta);
current_offset += std::get<1>(value_delta);
count = rebase_stream.read_uleb128();
output << "[" << to_string(static_cast<REBASE_OPCODES>(opcode)) << "]" << std::endl;
@ -305,14 +291,12 @@ std::string DyldInfo::show_rebases_opcodes(void) const {
output << std::hex << std::showbase << segment_offset;
output << ")" << std::endl;
value_delta = rebase_stream.read_uleb128(current_offset);
uint64_t val = rebase_stream.read_uleb128();
segment_offset += val + pint_v;
segment_offset += std::get<0>(value_delta) + pint_v;
current_offset += std::get<1>(value_delta);
output << tab;
output << "Segment Offset += " << std::hex << std::showbase << (std::get<0>(value_delta) + pint_v) << " (" << segment_offset << ")";
output << "Segment Offset += " << std::hex << std::showbase << (val + pint_v) << " (" << segment_offset << ")";
output << std::endl;
break;
@ -324,18 +308,10 @@ std::string DyldInfo::show_rebases_opcodes(void) const {
output << "[" << to_string(static_cast<REBASE_OPCODES>(opcode)) << "]" << std::endl;
// Count
value_delta = rebase_stream.read_uleb128(current_offset);
count += std::get<0>(value_delta);
current_offset += std::get<1>(value_delta);
count += rebase_stream.read_uleb128();
// Skip
value_delta = rebase_stream.read_uleb128(current_offset);
skip += std::get<0>(value_delta);
current_offset += std::get<1>(value_delta);
skip += rebase_stream.read_uleb128();
output << tab << "for i in range(" << std::dec << static_cast<uint32_t>(count) << "):" << std::endl;
for (size_t i = 0; i < count; ++i) {
@ -411,9 +387,6 @@ void DyldInfo::show_bindings(std::ostream& output, const buffer_t& bind_opcodes,
size_t pint_v = static_cast<LIEF::Binary*>(this->binary_)->header().is_64() ? sizeof(uint64_t) : sizeof(uint32_t);
uint64_t current_offset = 0;
uint64_t end_offset = bind_opcodes.size();
uint8_t type = is_lazy ? static_cast<uint8_t>(BIND_TYPES::BIND_TYPE_POINTER) : 0;
uint8_t segment_idx = 0;
uint64_t segment_offset = 0;
@ -427,9 +400,6 @@ void DyldInfo::show_bindings(std::ostream& output, const buffer_t& bind_opcodes,
bool is_weak_import = false;
bool done = false;
std::pair<uint64_t, uint64_t> value_delta = {0, 0};
std::pair<int64_t, uint64_t> svalue_delta = {0, 0};
it_segments segments = this->binary_->segments();
it_libraries libraries = this->binary_->libraries();
@ -437,12 +407,9 @@ void DyldInfo::show_bindings(std::ostream& output, const buffer_t& bind_opcodes,
VectorStream bind_stream{bind_opcodes};
while (not done and current_offset < end_offset) {
uint8_t imm = bind_stream.read_integer<uint8_t>(current_offset) & BIND_IMMEDIATE_MASK;
BIND_OPCODES opcode = static_cast<BIND_OPCODES>(
bind_stream.read_integer<uint8_t>(current_offset) & BIND_OPCODE_MASK);
current_offset += sizeof(uint8_t);
while (not done and bind_stream.pos() < bind_opcodes.size()) {
uint8_t imm = bind_stream.peek<uint8_t>() & BIND_IMMEDIATE_MASK;
BIND_OPCODES opcode = static_cast<BIND_OPCODES>(bind_stream.read<uint8_t>() & BIND_OPCODE_MASK);
switch (opcode) {
case BIND_OPCODES::BIND_OPCODE_DONE:
@ -469,9 +436,7 @@ void DyldInfo::show_bindings(std::ostream& output, const buffer_t& bind_opcodes,
output << "[" << to_string(static_cast<BIND_OPCODES>(opcode)) << "]" << std::endl;
value_delta = bind_stream.read_uleb128(current_offset);
library_ordinal = std::get<0>(value_delta);
current_offset += std::get<1>(value_delta);
library_ordinal = bind_stream.read_uleb128();
output << tab << "Library Ordinal := " << std::dec << library_ordinal << std::endl;
@ -498,8 +463,7 @@ void DyldInfo::show_bindings(std::ostream& output, const buffer_t& bind_opcodes,
{
output << "[" << to_string(static_cast<BIND_OPCODES>(opcode)) << "]" << std::endl;
symbol_name = bind_stream.get_string(current_offset);
current_offset += symbol_name.size() + 1;
symbol_name = bind_stream.read_string();
if ((imm & BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0) {
is_weak_import = true;
@ -527,9 +491,7 @@ void DyldInfo::show_bindings(std::ostream& output, const buffer_t& bind_opcodes,
{
output << "[" << to_string(static_cast<BIND_OPCODES>(opcode)) << "]" << std::endl;
svalue_delta = bind_stream.read_sleb128(current_offset);
addend = std::get<0>(svalue_delta);
current_offset += std::get<1>(svalue_delta);
addend = bind_stream.read_sleb128();
output << tab << "Addend := " << std::dec << addend << std::endl;
break;
@ -541,9 +503,7 @@ void DyldInfo::show_bindings(std::ostream& output, const buffer_t& bind_opcodes,
output << "[" << to_string(static_cast<BIND_OPCODES>(opcode)) << "]" << std::endl;
segment_idx = imm;
value_delta = bind_stream.read_uleb128(current_offset);
segment_offset = std::get<0>(value_delta);
current_offset += std::get<1>(value_delta);
segment_offset = bind_stream.read_uleb128();
output << tab << "Segment := " << segments[segment_idx].name() << std::endl;
output << tab << "Segment Offset := " << std::hex << std::showbase << segment_offset << std::endl;
@ -556,11 +516,10 @@ void DyldInfo::show_bindings(std::ostream& output, const buffer_t& bind_opcodes,
output << "[" << to_string(static_cast<BIND_OPCODES>(opcode)) << "]" << std::endl;
value_delta = bind_stream.read_uleb128(current_offset);
segment_offset += std::get<0>(value_delta);
current_offset += std::get<1>(value_delta);
uint64_t val = bind_stream.read_uleb128();
segment_offset += val;
output << tab << "Segment Offset += " << std::hex << std::showbase << std::get<0>(value_delta) << " (" << segment_offset << ")" << std::endl;
output << tab << "Segment Offset += " << std::hex << std::showbase << val << " (" << segment_offset << ")" << std::endl;
break;
}
@ -616,11 +575,10 @@ void DyldInfo::show_bindings(std::ostream& output, const buffer_t& bind_opcodes,
output << std::boolalpha << is_weak_import;
output << ")" << std::endl;
value_delta = bind_stream.read_uleb128(current_offset);
segment_offset += std::get<0>(value_delta) + pint_v;
current_offset += std::get<1>(value_delta);
uint64_t v = bind_stream.read_uleb128();
segment_offset += v + pint_v;
output << tab << "Segment Offset += " << std::hex << std::showbase << std::get<0>(value_delta) + pint_v << " (" << segment_offset << ")" << std::endl;
output << tab << "Segment Offset += " << std::hex << std::showbase << v + pint_v << " (" << segment_offset << ")" << std::endl;
break;
}
@ -658,14 +616,10 @@ void DyldInfo::show_bindings(std::ostream& output, const buffer_t& bind_opcodes,
output << "[" << to_string(static_cast<BIND_OPCODES>(opcode)) << "]" << std::endl;
// Count
value_delta = bind_stream.read_uleb128(current_offset);
count = std::get<0>(value_delta);
current_offset += std::get<1>(value_delta);
count = bind_stream.read_uleb128();
// Skip
value_delta = bind_stream.read_uleb128(current_offset);
skip = std::get<0>(value_delta);
current_offset += std::get<1>(value_delta);
skip = bind_stream.read_uleb128();;
output << tab << "for i in range(" << std::dec << static_cast<uint32_t>(count) << "):" << std::endl;
for (size_t i = 0; i < count; ++i) {
@ -790,38 +744,30 @@ std::string DyldInfo::show_export_trie(void) const {
VectorStream stream{buffer};
this->show_trie(output, "", stream, 0, 0, end_offset, "");
this->show_trie(output, "", stream, 0, end_offset, "");
return output.str();
}
void DyldInfo::show_trie(std::ostream& output, std::string output_prefix, VectorStream& stream, uint64_t start, uint64_t current_offset, uint64_t end, const std::string& prefix) const {
void DyldInfo::show_trie(std::ostream& output, std::string output_prefix, VectorStream& stream, uint64_t start, uint64_t end, const std::string& prefix) const {
std::pair<uint64_t, uint64_t> value_delta = {0, 0};
if (current_offset >= end) {
if (stream.pos() >= end) {
return;
}
if (start > current_offset) {
if (start > stream.pos()) {
return;
}
const uint64_t saved_offset = current_offset;
const uint8_t terminal_size = stream.read_integer<uint8_t>(current_offset);
current_offset += sizeof(uint8_t);
uint64_t children_offset = current_offset + terminal_size;
const uint8_t terminal_size = stream.read<uint8_t>();
uint64_t children_offset = stream.pos() + terminal_size;
if (terminal_size != 0) {
uint64_t offset = current_offset - start;
value_delta = stream.read_uleb128(current_offset);
uint64_t flags = std::get<0>(value_delta);
current_offset += std::get<1>(value_delta);
value_delta = stream.read_uleb128(current_offset);
uint64_t address = std::get<0>(value_delta);
current_offset += std::get<1>(value_delta);
uint64_t flags = stream.read_uleb128();
uint64_t address = stream.read_uleb128();
const std::string& symbol_name = prefix;
output << output_prefix;
@ -838,25 +784,26 @@ void DyldInfo::show_trie(std::ostream& output, std::string output_prefix, Vector
output << std::endl;
}
const uint8_t nb_children = stream.read_integer<uint8_t>(children_offset);
children_offset += sizeof(uint8_t);
stream.setpos(children_offset);
const uint8_t nb_children = stream.read<uint8_t>();
output_prefix += " ";
for (size_t i = 0; i < nb_children; ++i) {
std::string suffix = stream.get_string(children_offset);
std::string suffix = stream.read_string();
std::string name = prefix + suffix;
children_offset += suffix.size() + 1;
uint32_t child_node_offet = static_cast<uint32_t>(stream.read_uleb128());
value_delta = stream.read_uleb128(children_offset);
uint32_t child_node_offet = static_cast<uint32_t>(std::get<0>(value_delta));
children_offset += std::get<1>(value_delta);
if (start + child_node_offet == start) {
if (child_node_offet == 0) {
break;
}
output << output_prefix << name << "@off." << std::hex << std::showbase << children_offset << std::endl;
this->show_trie(output, output_prefix, stream, start, start + child_node_offet, end, name);
output << output_prefix << name << "@off." << std::hex << std::showbase << stream.pos() << std::endl;
size_t current_pos = stream.pos();
stream.setpos(start + child_node_offet);
this->show_trie(output, output_prefix, stream, start, end, name);
stream.setpos(current_pos);
}
}

@ -88,8 +88,7 @@ FatBinary* Parser::parse(const std::vector<uint8_t>& data, const std::string& na
void Parser::build_fat(void) {
const fat_header *header = reinterpret_cast<const fat_header*>(
this->stream_->read(0, sizeof(fat_header)));
const fat_header *header = &this->stream_->peek<fat_header>(0);
uint32_t nb_arch = Swap4Bytes(header->nfat_arch);
VLOG(VDEBUG) << "In this Fat binary there is " << std::dec << nb_arch << " archs" << std::endl;
@ -97,8 +96,7 @@ void Parser::build_fat(void) {
throw parser_error("Too much architectures");
}
const fat_arch* arch = reinterpret_cast<const fat_arch*>(
this->stream_->read(sizeof(fat_header), sizeof(fat_arch)));
const fat_arch* arch = &this->stream_->peek<fat_arch>(sizeof(fat_header));
for (size_t i = 0; i < nb_arch; ++i) {
@ -109,8 +107,7 @@ void Parser::build_fat(void) {
VLOG(VDEBUG) << "[" << std::dec << i << "] offset: 0x" << std::hex << offset << std::endl;
VLOG(VDEBUG) << "[" << std::dec << i << "] size: 0x" << std::hex << size << std::endl;
const uint8_t* raw = reinterpret_cast<const uint8_t*>(
this->stream_->read(offset, size));
const uint8_t* raw = this->stream_->peek_array<uint8_t>(offset, size);
std::vector<uint8_t> data = {raw, raw + size};
@ -121,8 +118,7 @@ void Parser::build_fat(void) {
void Parser::build(void) {
try {
MACHO_TYPES type = static_cast<MACHO_TYPES>(
*reinterpret_cast<const uint32_t*>(this->stream_->read(0, sizeof(uint32_t))));
MACHO_TYPES type = static_cast<MACHO_TYPES>(this->stream_->peek<uint32_t>(0));
// Fat binary
if (type == MACHO_TYPES::FAT_MAGIC or

@ -767,7 +767,8 @@ uint32_t Binary::predict_function_rva(const std::string& library, const std::str
});
if (it_import == std::end(this->imports_)) {
throw not_found("Unable to find library '" + library + "'");
LOG(ERROR) << "Unable to find library '" << library << "'";
return 0;
}
it_const_import_entries entries = it_import->entries();
@ -782,11 +783,13 @@ uint32_t Binary::predict_function_rva(const std::string& library, const std::str
});
if (nb_functions == 0) {
throw not_found("Unable to find the function '" + function + "' in '" + library + "'.");
LOG(ERROR) << "Unable to find the function '" << function << "' in '" << library + "'.";
return 0;
}
if (nb_functions > 1) {
throw not_supported("'" + function + "' is defined " + std::to_string(nb_functions) + " in '" + library + "'.");
LOG(ERROR) << "'" << function << "' is defined " << std::to_string(nb_functions) << " in '" << library << "'.";
return 0;
}
uint32_t import_table_size = static_cast<uint32_t>((this->imports().size() + 1) * sizeof(pe_import)); // +1 for the null entry
@ -878,11 +881,7 @@ Export& Binary::get_export(void) {
const Export& Binary::get_export(void) const {
if (this->has_exports()) {
return this->export_;
} else {
throw not_found("The binary doesn't have exports");
}
return this->export_;
}
/////////////////////////////////////
@ -892,14 +891,12 @@ const Export& Binary::get_export(void) const {
/////////////////////////////////////
void Binary::set_resources(const ResourceDirectory& resource) {
// TODO: DELETE !!!!!!!!!
delete this->resources_;
this->resources_ = new ResourceDirectory{resource};
}
void Binary::set_resources(const ResourceData& resource) {
// TODO: DELETE !!!!!!!!!
delete this->resources_;
this->resources_ = new ResourceData{resource};
}
@ -947,9 +944,6 @@ const Debug& Binary::debug(void) const {
/////////////////////
const Signature& Binary::signature(void) const {
if (not this->has_signature()) {
throw not_found("Signature not found");
}
return this->signature_;
}
@ -1045,7 +1039,7 @@ void Binary::hook_function(const std::string& function, uint64_t address) {
}
}
throw not_found("Unable to find library associated with function '" + function + "'");
LOG(WARNING) << "Unable to find library associated with function '" << function << "'";
}
@ -1083,7 +1077,8 @@ void Binary::patch_address(uint64_t address, const std::vector<uint8_t>& patch_v
void Binary::patch_address(uint64_t address, uint64_t patch_value, size_t size, LIEF::Binary::VA_TYPES addr_type) {
if (size > sizeof(patch_value)) {
throw std::runtime_error("Invalid size (" + std::to_string(size) + ")");
LOG(ERROR) << "Invalid size (" << std::to_string(size) << ")";
return;
}
uint64_t rva = address;
@ -1171,9 +1166,6 @@ RichHeader& Binary::rich_header(void) {
}
const RichHeader& Binary::rich_header(void) const {
if (not this->has_rich_header()) {
throw not_found("Rich Header not found");
}
return this->rich_header_;
}

File diff suppressed because it is too large Load Diff

@ -24,21 +24,15 @@ namespace PE {
template<typename PE_T>
void Parser::parse(void) {
try {
this->parse_headers<PE_T>();
} catch (const corrupted& e) {
LOG(WARNING) << e.what();
if (not this->parse_headers<PE_T>()) {
return;
}
VLOG(VDEBUG) << "[+] Retreive Dos stub";
this->parse_dos_stub();
try {
this->parse_rich_header();
} catch (const corrupted& e) {
LOG(WARNING) << e.what();
}
this->parse_rich_header();
VLOG(VDEBUG) << "[+] Decomposing Sections";
@ -65,38 +59,37 @@ void Parser::parse(void) {
}
template<typename PE_T>
void Parser::parse_headers(void) {
bool Parser::parse_headers(void) {
using pe_optional_header = typename PE_T::pe_optional_header;
//DOS Header
try {
this->binary_->dos_header_ = {reinterpret_cast<const pe_dos_header*>(
this->stream_->read(0, sizeof(pe_dos_header)))};
} catch (const read_out_of_bound&) {
throw corrupted("Dos Header corrupted");
if (this->stream_->can_read<pe_dos_header>(0)) {
this->binary_->dos_header_ = &this->stream_->peek<pe_dos_header>(0);
} else {
LOG(FATAL) << "Dos Header corrupted";
return false;
}
//PE32 Header
try {
this->binary_->header_ = {reinterpret_cast<const pe_header*>(
this->stream_->read(
this->binary_->dos_header().addressof_new_exeheader(),
sizeof(pe_header)))};
} catch (const read_out_of_bound&) {
throw corrupted("PE32 Header corrupted");
const size_t pe32_header_off = this->binary_->dos_header().addressof_new_exeheader();
if (this->stream_->can_read<pe_header>(pe32_header_off)) {
this->binary_->header_ = &this->stream_->peek<pe_header>(pe32_header_off);
} else {
LOG(FATAL) << "PE32 Header corrupted";
return false;
}
// Optional Header
try {
this->binary_->optional_header_ = {reinterpret_cast<const pe_optional_header*>(
this->stream_->read(
this->binary_->dos_header().addressof_new_exeheader() + sizeof(pe_header),
sizeof(pe_optional_header)))};
} catch (const read_out_of_bound&) {
throw corrupted("Optional header corrupted");
const size_t optional_header_off = this->binary_->dos_header().addressof_new_exeheader() + sizeof(pe_header);
if (this->stream_->can_read<pe_optional_header>(optional_header_off)) {
this->binary_->optional_header_ = &this->stream_->peek<pe_optional_header>(optional_header_off);
} else {
LOG(FATAL) << "Optional header corrupted";
return false;
}
return true;
}
template<typename PE_T>
@ -105,28 +98,25 @@ void Parser::parse_data_directories(void) {
VLOG(VDEBUG) << "[+] Parsing data directories";
const uint32_t dirOffset =
const uint32_t directories_offset =
this->binary_->dos_header().addressof_new_exeheader() +
sizeof(pe_header) +
sizeof(pe_optional_header);
const uint32_t nbof_datadir = static_cast<uint32_t>(DATA_DIRECTORY::NUM_DATA_DIRECTORIES);
const pe_data_directory* dataDirectory = [&] () {
try {
return reinterpret_cast<const pe_data_directory*>(
this->stream_->read(dirOffset, nbof_datadir * sizeof(pe_data_directory)));
} catch (const read_out_of_bound&) {
throw corrupted("Data directories corrupted");
}
}();
const pe_data_directory* data_directory = this->stream_->peek_array<pe_data_directory>(directories_offset, nbof_datadir);
if (data_directory == nullptr) {
LOG(ERROR) << "Data Directories corrupted!";
return;
}
this->binary_->data_directories_.reserve(nbof_datadir);
for (size_t i = 0; i < nbof_datadir; ++i) {
std::unique_ptr<DataDirectory> directory{new DataDirectory{&dataDirectory[i], static_cast<DATA_DIRECTORY>(i)}};
std::unique_ptr<DataDirectory> directory{new DataDirectory{&data_directory[i], static_cast<DATA_DIRECTORY>(i)}};
VLOG(VDEBUG) << "Processing directory: " << to_string(static_cast<DATA_DIRECTORY>(i));
VLOG(VDEBUG) << "- RVA: 0x" << std::hex << dataDirectory[i].RelativeVirtualAddress;
VLOG(VDEBUG) << "- Size: 0x" << std::hex << dataDirectory[i].Size;
VLOG(VDEBUG) << "- RVA: 0x" << std::hex << data_directory[i].RelativeVirtualAddress;
VLOG(VDEBUG) << "- Size: 0x" << std::hex << data_directory[i].Size;
if (directory->RVA() > 0) {
// Data directory is not always associated with section
const uint64_t offset = this->binary_->rva_to_offset(directory->RVA());
@ -273,25 +263,31 @@ template<typename PE_T>
void Parser::parse_import_table(void) {
using uint__ = typename PE_T::uint;
this->binary_->has_imports_ = true;
const uint32_t import_rva = this->binary_->data_directory(DATA_DIRECTORY::IMPORT_TABLE).RVA();
const uint64_t offset = this->binary_->rva_to_offset(import_rva);
const uint32_t import_rva = this->binary_->data_directory(DATA_DIRECTORY::IMPORT_TABLE).RVA();
const uint64_t import_offset = this->binary_->rva_to_offset(import_rva);
const pe_import* header = reinterpret_cast<const pe_import*>(
this->stream_->read(offset, sizeof(pe_import)));
if (not this->stream_->can_read<pe_import>(import_offset)) {
return;
}
while (header->ImportAddressTableRVA != 0) {
Import import = {header};
this->stream_->setpos(import_offset);
while (this->stream_->can_read<pe_import>()) {
pe_import header = this->stream_->read<pe_import>();
Import import = &header;
import.directory_ = &(this->binary_->data_directory(DATA_DIRECTORY::IMPORT_TABLE));
import.iat_directory_ = &(this->binary_->data_directory(DATA_DIRECTORY::IAT));
import.type_ = this->type_;
if (import.name_RVA_ == 0) {
throw parser_error("Name's RVA is null");
LOG(ERROR) << "Name's RVA is null";
break;
}
// Offset to the Import (Library) name
const uint64_t offsetName = this->binary_->rva_to_offset(import.name_RVA_);
import.name_ = this->stream_->get_string(offsetName);
import.name_ = this->stream_->peek_string_at(offsetName);
// We assume that a DLL name should be at least 4 length size and "printable
@ -301,71 +297,71 @@ void Parser::parse_import_table(void) {
std::end(import.name()),
std::bind(std::isprint<char>, std::placeholders::_1, std::locale("C"))))
{
header++;
continue; // skip
}
// Offset to import lookup table
uint64_t LT_offset = 0;
uint64_t LT_offset = 0;
if (import.import_lookup_table_RVA_ > 0) {
LT_offset = this->binary_->rva_to_offset(import.import_lookup_table_RVA_);
}
// Offset to the import address table
uint64_t IAT_offset = 0;
uint64_t IAT_offset = 0;
if (import.import_address_table_RVA_ > 0) {
IAT_offset = this->binary_->rva_to_offset(import.import_address_table_RVA_);
}
const uint__ *lookupTable = nullptr, *IAT = nullptr, *table = nullptr;
uint__ IAT = 0, table = 0;
if (IAT_offset > 0) {
try {
IAT = reinterpret_cast<const uint__*>(
this->stream_->read(IAT_offset, sizeof(uint__)));
table = IAT;
} catch (const LIEF::exception&) {
}
if (IAT_offset > 0 and this->stream_->can_read<uint__>(IAT_offset)) {
IAT = this->stream_->peek<uint__>(IAT_offset);
table = IAT;
IAT_offset += sizeof(uint__);
}
if (LT_offset > 0) {
try {
lookupTable = reinterpret_cast<const uint__*>(
this->stream_->read(LT_offset, sizeof(uint__)));
table = lookupTable;
} catch (const LIEF::exception&) {
}
if (LT_offset > 0 and this->stream_->can_read<uint__>(LT_offset)) {
table = this->stream_->peek<uint__>(LT_offset);;
LT_offset += sizeof(uint__);
}
size_t idx = 0;
while (table != nullptr and *table != 0) {
while (table != 0) {
ImportEntry entry;
entry.iat_value_ = IAT != nullptr ? *(IAT++) : 0;
entry.data_ = *table;
entry.iat_value_ = IAT;
entry.data_ = table;
entry.type_ = this->type_;
entry.rva_ = import.import_address_table_RVA_ + sizeof(uint__) * (idx++);
if(not entry.is_ordinal()) {
entry.name_ = this->stream_->get_string(
this->binary_->rva_to_offset(entry.hint_name_rva()) + sizeof(uint16_t));
entry.hint_ = *reinterpret_cast<const uint16_t*>(
this->stream_->read(
this->binary_->rva_to_offset(entry.hint_name_rva()),
sizeof(uint16_t)));
const size_t hint_off = this->binary_->rva_to_offset(entry.hint_name_rva());
const size_t name_off = hint_off + sizeof(uint16_t);
entry.name_ = this->stream_->peek_string_at(name_off);
if (this->stream_->can_read<uint16_t>(hint_off)) {
entry.hint_ = this->stream_->peek<uint16_t>(hint_off);
}
}
import.entries_.push_back(std::move(entry));
table++;
if (IAT_offset > 0 and this->stream_->can_read<uint__>(IAT_offset)) {
IAT = this->stream_->peek<uint__>(IAT_offset);
IAT_offset += sizeof(uint__);
} else {
IAT = 0;
}
if (LT_offset > 0 and this->stream_->can_read<uint__>(LT_offset)) {
table = this->stream_->peek<uint__>(LT_offset);
LT_offset += sizeof(uint__);
} else {
table = 0;
}
}
this->binary_->imports_.push_back(std::move(import));
header++;
}
this->binary_->has_imports_ = this->binary_->imports_.size() > 0;
}
template<typename PE_T>
@ -375,58 +371,59 @@ void Parser::parse_tls(void) {
VLOG(VDEBUG) << "[+] Parsing TLS";
this->binary_->has_tls_ = true;
const uint32_t tls_rva = this->binary_->data_directory(DATA_DIRECTORY::TLS_TABLE).RVA();
const uint64_t offset = this->binary_->rva_to_offset(tls_rva);
const pe_tls *tls_header = reinterpret_cast<const pe_tls*>(
this->stream_->read(offset, sizeof(pe_tls)));
this->stream_->setpos(offset);
if (not this->stream_->can_read<pe_tls>()) {
return;
}
const pe_tls& tls_header = this->stream_->read<pe_tls>();
this->binary_->tls_ = {tls_header};
TLS& tls = this->binary_->tls_;
tls = &tls_header;
const uint64_t imagebase = this->binary_->optional_header().imagebase();
if (tls_header->RawDataStartVA > 0 and tls_header->RawDataEndVA > tls_header->RawDataStartVA) {
const uint64_t start_data_rva = tls_header->RawDataStartVA - imagebase;
const uint64_t stop_data_rva = tls_header->RawDataEndVA - imagebase;
if (tls_header.RawDataStartVA >= imagebase and tls_header.RawDataEndVA > tls_header.RawDataStartVA) {
CHECK(tls_header.RawDataStartVA >= imagebase);
CHECK(tls_header.RawDataEndVA >= imagebase);
const uint64_t start_data_rva = tls_header.RawDataStartVA - imagebase;
const uint64_t stop_data_rva = tls_header.RawDataEndVA - imagebase;
const uint__ start_template_offset = this->binary_->rva_to_offset(start_data_rva);
const uint__ end_template_offset = this->binary_->rva_to_offset(stop_data_rva);
const size_t size_to_read = end_template_offset - start_template_offset;
try {
if (size_to_read > Parser::MAX_DATA_SIZE) {
LOG(WARNING) << "TLS's template is too large!";
if (size_to_read > Parser::MAX_DATA_SIZE) {
LOG(WARNING) << "TLS's template is too large!";
} else {
const uint8_t* template_ptr = this->stream_->peek_array<uint8_t>(start_template_offset, size_to_read);
if (template_ptr == nullptr) {
LOG(WARNING) << "TLS's template corrupted";
} else {
const uint8_t* template_ptr = reinterpret_cast<const uint8_t*>(
this->stream_->read(start_template_offset, size_to_read));
std::vector<uint8_t> template_data = {
template_ptr,
template_ptr + size_to_read
};
tls.data_template(std::move(template_data));
tls.data_template({
template_ptr,
template_ptr + size_to_read
});
}
} catch (const read_out_of_bound&) {
LOG(WARNING) << "TLS corrupted (data template)";
} catch (const std::bad_alloc&) {
LOG(WARNING) << "TLS corrupted (data template)";
}
}
uint64_t callbacks_offset = this->binary_->rva_to_offset(tls.addressof_callbacks() - imagebase);
uint__ callback_rva = this->stream_->read_integer<uint__>(callbacks_offset);
callbacks_offset += sizeof(uint__);
size_t count = 0;
while (static_cast<uint32_t>(callback_rva) > 0 and count < Parser::MAX_TLS_CALLBACKS) {
tls.callbacks_.push_back(static_cast<uint64_t>(callback_rva));
callback_rva = this->stream_->read_integer<uint__>(callbacks_offset);
callbacks_offset += sizeof(uint__);
if (tls.addressof_callbacks() > imagebase) {
uint64_t callbacks_offset = this->binary_->rva_to_offset(tls.addressof_callbacks() - imagebase);
this->stream_->setpos(callbacks_offset);
size_t count = 0;
while (this->stream_->can_read<uint__>() and count++ < Parser::MAX_TLS_CALLBACKS) {
uint__ callback_rva = this->stream_->read<uint__>();
if (static_cast<uint32_t>(callback_rva) == 0) {
break;
}
tls.callbacks_.push_back(callback_rva);
}
}
tls.directory_ = &(this->binary_->data_directory(DATA_DIRECTORY::TLS_TABLE));
@ -437,6 +434,8 @@ void Parser::parse_tls(void) {
} catch (const not_found&) {
LOG(WARNING) << "No section associated with TLS";
}
this->binary_->has_tls_ = true;
}
@ -459,7 +458,10 @@ void Parser::parse_load_config(void) {
const uint32_t ldc_rva = this->binary_->data_directory(DATA_DIRECTORY::LOAD_CONFIG_TABLE).RVA();
const uint64_t offset = this->binary_->rva_to_offset(ldc_rva);
const uint32_t size_from_header = this->stream_->read_integer<uint32_t>(offset);
if (not this->stream_->can_read<uint32_t>(offset)) {
return;
}
const uint32_t size_from_header = this->stream_->peek<uint32_t>(offset);
if (directory_size != size_from_header) {
LOG(WARNING) << "The size of directory '" << to_string(DATA_DIRECTORY::LOAD_CONFIG_TABLE)
@ -481,93 +483,110 @@ void Parser::parse_load_config(void) {
case WIN_VERSION::WIN_SEH:
{
if (not this->stream_->can_read<load_configuration_v0_t>(offset)) {
break;
}
const load_configuration_v0_t* header = reinterpret_cast<const load_configuration_v0_t*>(
this->stream_->read(offset, sizeof(load_configuration_v0_t)));
ld_conf = std::unique_ptr<LoadConfigurationV0>{new LoadConfigurationV0{header}};
const load_configuration_v0_t& header = this->stream_->peek<load_configuration_v0_t>(offset);
ld_conf = std::unique_ptr<LoadConfigurationV0>{new LoadConfigurationV0{&header}};
break;
}
case WIN_VERSION::WIN8_1:
{
const load_configuration_v1_t* header = reinterpret_cast<const load_configuration_v1_t*>(
this->stream_->read(offset, sizeof(load_configuration_v1_t)));
ld_conf = std::unique_ptr<LoadConfigurationV1>{new LoadConfigurationV1{header}};
if (not this->stream_->can_read<load_configuration_v1_t>(offset)) {
break;
}
const load_configuration_v1_t& header = this->stream_->peek<load_configuration_v1_t>(offset);
ld_conf = std::unique_ptr<LoadConfigurationV1>{new LoadConfigurationV1{&header}};
break;
}
case WIN_VERSION::WIN10_0_9879:
{
const load_configuration_v2_t* header = reinterpret_cast<const load_configuration_v2_t*>(
this->stream_->read(offset, sizeof(load_configuration_v2_t)));
ld_conf = std::unique_ptr<LoadConfigurationV2>{new LoadConfigurationV2{header}};
if (not this->stream_->can_read<load_configuration_v2_t>(offset)) {
break;
}
const load_configuration_v2_t& header = this->stream_->peek<load_configuration_v2_t>(offset);
ld_conf = std::unique_ptr<LoadConfigurationV2>{new LoadConfigurationV2{&header}};
break;
}
case WIN_VERSION::WIN10_0_14286:
{
const load_configuration_v3_t* header = reinterpret_cast<const load_configuration_v3_t*>(
this->stream_->read(offset, sizeof(load_configuration_v3_t)));
if (not this->stream_->can_read<load_configuration_v3_t>(offset)) {
break;
}
const load_configuration_v3_t& header = this->stream_->peek<load_configuration_v3_t>(offset);
ld_conf = std::unique_ptr<LoadConfigurationV3>{new LoadConfigurationV3{header}};
ld_conf = std::unique_ptr<LoadConfigurationV3>{new LoadConfigurationV3{&header}};
break;
}
case WIN_VERSION::WIN10_0_14383:
{
const load_configuration_v4_t* header = reinterpret_cast<const load_configuration_v4_t*>(
this->stream_->read(offset, sizeof(load_configuration_v4_t)));
if (not this->stream_->can_read<load_configuration_v4_t>(offset)) {
break;
}
const load_configuration_v4_t& header = this->stream_->peek<load_configuration_v4_t>(offset);
ld_conf = std::unique_ptr<LoadConfigurationV4>{new LoadConfigurationV4{header}};
ld_conf = std::unique_ptr<LoadConfigurationV4>{new LoadConfigurationV4{&header}};
break;
}
case WIN_VERSION::WIN10_0_14901:
{
const load_configuration_v5_t* header = reinterpret_cast<const load_configuration_v5_t*>(
this->stream_->read(offset, sizeof(load_configuration_v5_t)));
if (not this->stream_->can_read<load_configuration_v5_t>(offset)) {
break;
}
const load_configuration_v5_t& header = this->stream_->peek<load_configuration_v5_t>(offset);
ld_conf = std::unique_ptr<LoadConfigurationV5>{new LoadConfigurationV5{header}};
ld_conf = std::unique_ptr<LoadConfigurationV5>{new LoadConfigurationV5{&header}};
break;
}
case WIN_VERSION::WIN10_0_15002:
{
const load_configuration_v6_t* header = reinterpret_cast<const load_configuration_v6_t*>(
this->stream_->read(offset, sizeof(load_configuration_v6_t)));
if (not this->stream_->can_read<load_configuration_v6_t>(offset)) {
break;
}
const load_configuration_v6_t& header = this->stream_->peek<load_configuration_v6_t>(offset);
ld_conf = std::unique_ptr<LoadConfigurationV6>{new LoadConfigurationV6{header}};
ld_conf = std::unique_ptr<LoadConfigurationV6>{new LoadConfigurationV6{&header}};
break;
}
case WIN_VERSION::WIN10_0_16237:
{
const load_configuration_v7_t* header = reinterpret_cast<const load_configuration_v7_t*>(
this->stream_->read(offset, sizeof(load_configuration_v7_t)));
if (not this->stream_->can_read<load_configuration_v7_t>(offset)) {
break;
}
const load_configuration_v7_t& header = this->stream_->peek<load_configuration_v7_t>(offset);
ld_conf = std::unique_ptr<LoadConfigurationV7>{new LoadConfigurationV7{header}};
ld_conf = std::unique_ptr<LoadConfigurationV7>{new LoadConfigurationV7{&header}};
break;
}
case WIN_VERSION::WIN_UNKNOWN:
default:
{
const load_configuration_t* header = reinterpret_cast<const load_configuration_t*>(
this->stream_->read(offset, sizeof(load_configuration_t)));
ld_conf = std::unique_ptr<LoadConfiguration>{new LoadConfiguration{header}};
if (not this->stream_->can_read<load_configuration_t>(offset)) {
break;
}
const load_configuration_t& header = this->stream_->peek<load_configuration_t>(offset);
ld_conf = std::unique_ptr<LoadConfiguration>{new LoadConfiguration{&header}};
}
}
this->binary_->has_configuration_ = static_cast<bool>(ld_conf);
this->binary_->load_configuration_ = ld_conf.release();
this->binary_->has_configuration_ = true;

@ -401,23 +401,19 @@ ResourceVersion ResourcesManager::version(void) const {
VectorStream stream{content};
ResourceVersion version;
uint64_t offset = 0;
stream.setpos(0);
// Size of the current "struct"
const uint16_t length = *reinterpret_cast<const uint16_t*>(stream.read(offset, sizeof(uint16_t)));
offset += sizeof(uint16_t);
const uint16_t length = stream.read<uint16_t>();
VLOG(VDEBUG) << "Lenght of the struct: 0x" << std::hex << length;
// Size of the fixed file info struct
const uint16_t value_length = *reinterpret_cast<const uint16_t*>(stream.read(offset, sizeof(uint16_t)));
offset += sizeof(uint16_t);
const uint16_t value_length = stream.read<uint16_t>();
VLOG(VDEBUG) << "Size of the 'FixedFileInfo' struct" << std::hex << value_length;
// Type of the data in the version resource
// 1: Text data
// 0: Binary data
const uint16_t type = *reinterpret_cast<const uint16_t*>(stream.read(offset, sizeof(uint16_t)));
offset += sizeof(uint16_t);
const uint16_t type = stream.read<uint16_t>();
version.type_ = type;
if (type != 0 and type != 1) {
LOG(WARNING) << "\"type\" of the resource version should be equal to 0 or 1 (" << std::dec << type << ")";
@ -425,18 +421,17 @@ ResourceVersion ResourcesManager::version(void) const {
// Magic key: VS_VERSION_INFO
std::u16string key = {reinterpret_cast<const char16_t*>(content.data() + offset)};
if (u16tou8(key) != "VS_VERSION_INFO") {
std::u16string key = stream.read_u16string();
if (u16tou8(key, true) != "VS_VERSION_INFO") {
LOG(WARNING) << "\"key\" of the resource version should be equal to 'VS_VERSION_INFO' (" << u16tou8(key) << ")";
}
version.key_ = key;
offset += (key.size() + 1) * sizeof(char16_t);
offset = align(offset, sizeof(uint32_t));
stream.align(sizeof(uint32_t));
if (value_length > 0) {
if (value_length == sizeof(pe_resource_fixed_file_info)) {
const pe_resource_fixed_file_info* fixed_file_info_header = reinterpret_cast<const pe_resource_fixed_file_info*>(stream.read(offset, sizeof(pe_resource_fixed_file_info)));
const pe_resource_fixed_file_info* fixed_file_info_header = &stream.peek<pe_resource_fixed_file_info>();
if (fixed_file_info_header->signature != 0xFEEF04BD) {
LOG(WARNING) << "Bad magic value for the Fixed file info structure";
} else {
@ -446,42 +441,41 @@ ResourceVersion ResourcesManager::version(void) const {
} else {
LOG(WARNING) << "The 'value' member contains an unknown structure";
}
offset += value_length * sizeof(uint8_t);
stream.increment_pos(value_length * sizeof(uint8_t));
}
offset = align(offset, sizeof(uint32_t));
stream.align(sizeof(uint32_t));
{ // First entry
VLOG(VDEBUG) << "Parsing first entry";
const uint16_t struct_file_info_length = *reinterpret_cast<const uint16_t*>(stream.read(offset, sizeof(uint16_t)));
uint64_t local_offset = offset;
const uint16_t struct_file_info_length = stream.peek<uint16_t>();
VLOG(VDEBUG) << "Length: " << std::hex << struct_file_info_length;
if (struct_file_info_length > 0) {
local_offset += sizeof(uint16_t);
const uint16_t struct_length = *reinterpret_cast<const uint16_t*>(stream.read(local_offset, sizeof(uint16_t)));
local_offset += sizeof(uint16_t);
const size_t start = stream.pos();
if (struct_file_info_length > 0) {
stream.increment_pos(sizeof(uint16_t));
const uint16_t struct_length = stream.read<uint16_t>();
VLOG(VDEBUG) << "Lenght of the struct: 0x" << std::hex << struct_length;
const uint16_t type = *reinterpret_cast<const uint16_t*>(stream.read(local_offset, sizeof(uint16_t)));
local_offset += sizeof(uint16_t);
const uint16_t type = stream.read<uint16_t>();
VLOG(VDEBUG) << "Type of the struct: " << std::dec << type;
std::u16string key = {reinterpret_cast<const char16_t*>(content.data() + local_offset)};
std::u16string key = stream.read_u16string();
VLOG(VDEBUG) << "First entry (key) " << u16tou8(key);
if (u16tou8(key) == "StringFileInfo") {
if (u16tou8(key, true) == "StringFileInfo") {
try {
version.string_file_info_ = this->get_string_file_info(stream, offset);
version.string_file_info_ = this->get_string_file_info(stream, type, key, start, struct_file_info_length);
version.has_string_file_info_ = true;
} catch (const LIEF::exception& e) {
LOG(ERROR) << e.what();
}
}
if (u16tou8(key) == "VarFileInfo") {
if (u16tou8(key, true) == "VarFileInfo") {
try {
version.var_file_info_ = this->get_var_file_info(stream, offset);
version.var_file_info_ = this->get_var_file_info(stream, type, key, start, struct_file_info_length);
version.has_var_file_info_ = true;
} catch (const LIEF::exception& e) {
LOG(ERROR) << e.what();
@ -494,36 +488,36 @@ ResourceVersion ResourcesManager::version(void) const {
{ // Second entry
VLOG(VDEBUG) << "Parsing second entry";
const uint16_t struct_file_info_length = *reinterpret_cast<const uint16_t*>(stream.read(offset, sizeof(uint16_t)));
uint64_t local_offset = offset;
const uint16_t struct_file_info_length = stream.peek<uint16_t>();
VLOG(VDEBUG) << "Length: " << std::hex << struct_file_info_length;
if (struct_file_info_length > 0) {
local_offset += sizeof(uint16_t);
const size_t start = stream.pos();
const uint16_t struct_length = *reinterpret_cast<const uint16_t*>(stream.read(local_offset, sizeof(uint16_t)));
local_offset += sizeof(uint16_t);
if (struct_file_info_length > 0) {
stream.increment_pos(sizeof(uint16_t));
const uint16_t struct_length = stream.read<uint16_t>();
VLOG(VDEBUG) << "Lenght of the struct: 0x" << std::hex << struct_length;
const uint16_t type = *reinterpret_cast<const uint16_t*>(stream.read(local_offset, sizeof(uint16_t)));
local_offset += sizeof(uint16_t);
const uint16_t type = stream.read<uint16_t>();
VLOG(VDEBUG) << "Type of the struct: " << std::dec << type;
std::u16string key = {reinterpret_cast<const char16_t*>(content.data() + local_offset)};
std::u16string key = stream.read_u16string();
stream.align(sizeof(uint32_t));
VLOG(VDEBUG) << "Second entry (key) " << u16tou8(key);
if (u16tou8(key) == "StringFileInfo") {
if (u16tou8(key, true) == "StringFileInfo") {
try {
version.string_file_info_ = this->get_string_file_info(stream, offset);
version.string_file_info_ = this->get_string_file_info(stream, type, key, start, struct_file_info_length);
version.has_string_file_info_ = true;
} catch (const LIEF::exception& e) {
LOG(ERROR) << e.what();
}
}
if (u16tou8(key) == "VarFileInfo") {
if (u16tou8(key, true) == "VarFileInfo") {
try {
version.var_file_info_ = this->get_var_file_info(stream, offset);
version.var_file_info_ = this->get_var_file_info(stream, type, key, start, struct_file_info_length);
version.has_var_file_info_ = true;
} catch (const LIEF::exception& e) {
LOG(ERROR) << e.what();
@ -536,186 +530,129 @@ ResourceVersion ResourcesManager::version(void) const {
}
ResourceStringFileInfo ResourcesManager::get_string_file_info(const VectorStream& stream, uint64_t& offset) const {
ResourceStringFileInfo ResourcesManager::get_string_file_info(const VectorStream& stream, uint16_t type, std::u16string key, size_t start, size_t struct_length) const {
VLOG(VDEBUG) << "Getting StringFileInfo object";
// String File Info
// ================
ResourceStringFileInfo string_file_info;
const uint16_t string_file_info_length = *reinterpret_cast<const uint16_t*>(stream.read(offset, sizeof(uint16_t)));
uint64_t str_local_offset = offset;
if (string_file_info_length > 0) {
str_local_offset += sizeof(uint16_t);
const uint16_t value_length = *reinterpret_cast<const uint16_t*>(stream.read(str_local_offset, sizeof(uint16_t)));
str_local_offset += sizeof(uint16_t);
VLOG(VDEBUG) << "Value length: " << std::dec << value_length << " (should be 0)";
string_file_info.type_ = type;
string_file_info.key_ = key;
const uint16_t type = *reinterpret_cast<const uint16_t*>(stream.read(str_local_offset, sizeof(uint16_t)));
VLOG(VDEBUG) << "Type: " << std::dec << type;
str_local_offset += sizeof(uint16_t);
string_file_info.type_ = type;
// Parse 'StringTable' childs
// ==========================
VLOG(VDEBUG) << "Parsing 'StringTable' struct";
const size_t end_string_stable = start + struct_length * sizeof(uint8_t);
std::u16string key = {reinterpret_cast<const char16_t*>(stream.content().data() + str_local_offset)};
if (u16tou8(key) != "StringFileInfo") {
LOG(WARNING) << "\"key\" of the resource version should be equal to 'StringFileInfo' (" << u16tou8(key) << ")";
while (stream.pos() < end_string_stable) {
LangCodeItem lang_code_item;
const uint16_t stringtable_length = stream.peek<uint16_t>();
// End of the structure including childs
const uint64_t end_offset = stream.pos() + stringtable_length * sizeof(uint8_t);
stream.increment_pos(sizeof(uint16_t));
const uint16_t stringtable_value_length = stream.read<uint16_t>();
VLOG(VDEBUG) << "Value length: " << std::dec << stringtable_value_length << " (should be 0)";
const uint16_t stringtable_type = stream.read<uint16_t>();
VLOG(VDEBUG) << "Type: " << std::dec << stringtable_type;
// 1: Text data
// 0: Binary data
if (type != 0 and type != 1) {
LOG(WARNING) << "\"type\" of the StringTable should be equal to 0 or 1 (" << std::dec << type << ")";
}
string_file_info.key_ = key;
str_local_offset += (key.size() + 1) * sizeof(char16_t);
str_local_offset = align(str_local_offset, sizeof(uint32_t));
// Parse 'StringTable' childs
// ==========================
VLOG(VDEBUG) << "Parsing 'StringTable' struct";
while (str_local_offset < offset + string_file_info_length * sizeof(uint8_t)) {
LangCodeItem lang_code_item;
const uint16_t stringtable_length = *reinterpret_cast<const uint16_t*>(stream.read(str_local_offset, sizeof(uint16_t)));
// End of the structure including childs
const uint64_t end_offset = str_local_offset + stringtable_length * sizeof(uint8_t);
str_local_offset += sizeof(uint16_t);
const uint16_t stringtable_value_length = *reinterpret_cast<const uint16_t*>(stream.read(str_local_offset, sizeof(uint16_t)));
str_local_offset += sizeof(uint16_t);
VLOG(VDEBUG) << "Value length: " << std::dec << stringtable_value_length << " (should be 0)";
const uint16_t stringtable_type = *reinterpret_cast<const uint16_t*>(stream.read(str_local_offset, sizeof(uint16_t)));
VLOG(VDEBUG) << "Type: " << std::dec << stringtable_type;
str_local_offset += sizeof(uint16_t);
// 1: Text data
// 0: Binary data
if (type != 0 and type != 1) {
LOG(WARNING) << "\"type\" of the StringTable should be equal to 0 or 1 (" << std::dec << type << ")";
}
lang_code_item.type_ = type;
lang_code_item.type_ = type;
std::u16string key = {reinterpret_cast<const char16_t*>(stream.content().data() + str_local_offset)};
lang_code_item.key_ = key;
VLOG(VDEBUG) << "ID: " << u16tou8(key);
std::u16string key = stream.read_u16string();
lang_code_item.key_ = key;
VLOG(VDEBUG) << "ID: " << u16tou8(key);
std::string key_str = u16tou8(key);
std::string key_str = u16tou8(key);
if (key.length() != 8) {
LOG(ERROR) << "Corrupted key (" << u16tou8(key) << key_str << ")";
} else {
uint64_t lang_id = std::stoul(u16tou8(key.substr(0, 4)), 0, 16);
uint64_t code_page = std::stoul(u16tou8(key.substr(4, 8)), 0, 16);
VLOG(VDEBUG) << "Lang ID: " << std::dec << lang_id;
VLOG(VDEBUG) << "Code page: " << std::hex << code_page;
}
str_local_offset += (key.size() + 1) * sizeof(char16_t);
str_local_offset = align(str_local_offset, sizeof(uint32_t));
// Parse 'String'
// ==============
while (str_local_offset < end_offset) {
const uint16_t string_length = *reinterpret_cast<const uint16_t*>(stream.read(str_local_offset, sizeof(uint16_t)));
str_local_offset += sizeof(uint16_t);
VLOG(VDEBUG) << "Length of the 'string' struct: 0x" << std::hex << string_length;
const uint16_t string_value_length = *reinterpret_cast<const uint16_t*>(stream.read(str_local_offset, sizeof(uint16_t)));
str_local_offset += sizeof(uint16_t);
VLOG(VDEBUG) << "Size of the 'value' member: 0x" << std::hex << string_value_length;
const uint16_t string_type = *reinterpret_cast<const uint16_t*>(stream.read(str_local_offset, sizeof(uint16_t)));
str_local_offset += sizeof(uint16_t);
VLOG(VDEBUG) << "Type of the 'string' struct: " << std::dec << string_type;
std::u16string key = {reinterpret_cast<const char16_t*>(stream.content().data() + str_local_offset)};
VLOG(VDEBUG) << "Key: " << u16tou8(key);
str_local_offset += (key.size() + 1) * sizeof(char16_t);
str_local_offset = align(str_local_offset, sizeof(uint32_t));
std::u16string value = {reinterpret_cast<const char16_t*>(stream.content().data() + str_local_offset)};
VLOG(VDEBUG) << "Value: " << u16tou8(value);
str_local_offset += (value.size() + 1) * sizeof(char16_t);
str_local_offset = align(str_local_offset, sizeof(uint32_t));
lang_code_item.items_.emplace(key, value);
}
string_file_info.childs_.push_back(std::move(lang_code_item));
if (key.length() != 8) {
LOG(ERROR) << "Corrupted key (" << u16tou8(key) << key_str << ")";
} else {
uint64_t lang_id = std::stoul(u16tou8(key.substr(0, 4)), 0, 16);
uint64_t code_page = std::stoul(u16tou8(key.substr(4, 8)), 0, 16);
VLOG(VDEBUG) << "Lang ID: " << std::dec << lang_id;
VLOG(VDEBUG) << "Code page: " << std::hex << code_page;
}
stream.align(sizeof(uint32_t));
// Parse 'String'
// ==============
while (stream.pos() < end_offset) {
const uint16_t string_length = stream.read<uint16_t>();
VLOG(VDEBUG) << "Length of the 'string' struct: 0x" << std::hex << string_length;
const uint16_t string_value_length = stream.read<uint16_t>();
VLOG(VDEBUG) << "Size of the 'value' member: 0x" << std::hex << string_value_length;
const uint16_t string_type = stream.read<uint16_t>();
VLOG(VDEBUG) << "Type of the 'string' struct: " << std::dec << string_type;
std::u16string key = stream.read_u16string();
VLOG(VDEBUG) << "Key: " << u16tou8(key);
stream.align(sizeof(uint32_t));
std::u16string value = stream.read_u16string();
VLOG(VDEBUG) << "Value: " << u16tou8(value);
stream.align(sizeof(uint32_t));
lang_code_item.items_.emplace(key, value);
}
string_file_info.childs_.push_back(std::move(lang_code_item));
}
//offset += string_file_info_length * sizeof(uint8_t);
offset = str_local_offset;
//stream.setpos(end_string_stable);
return string_file_info;
}
ResourceVarFileInfo ResourcesManager::get_var_file_info(const VectorStream& stream, uint64_t& offset) const {
ResourceVarFileInfo ResourcesManager::get_var_file_info(const VectorStream& stream, uint16_t type, std::u16string key, size_t start, size_t struct_length) const {
VLOG(VDEBUG) << "Getting VarFileInfo object";
// Var file info
// =============
ResourceVarFileInfo var_file_info;
const uint16_t var_file_info_length = *reinterpret_cast<const uint16_t*>(stream.read(offset, sizeof(uint16_t)));
uint64_t var_local_offset = offset;
if (var_file_info_length > 0) {
var_local_offset += sizeof(uint16_t);
var_file_info.type_ = type;
var_file_info.key_ = key;
const uint16_t value_length = *reinterpret_cast<const uint16_t*>(stream.read(var_local_offset, sizeof(uint16_t)));
var_local_offset += sizeof(uint16_t);
VLOG(VDEBUG) << "Value length: " << std::dec << value_length << " (should be 0)";
// Parse 'Var' childs
// ==================
VLOG(VDEBUG) << "Parsing 'Var' childs";
const size_t end_var_file_info = start + struct_length * sizeof(uint8_t);
while (stream.pos() < end_var_file_info) {
const uint16_t var_length = stream.read<uint16_t>();
VLOG(VDEBUG) << "Size of the 'Var' struct: 0x" << std::hex << var_length;
const uint16_t type = *reinterpret_cast<const uint16_t*>(stream.read(var_local_offset, sizeof(uint16_t)));
var_local_offset += sizeof(uint16_t);
var_file_info.type_ = type;
VLOG(VDEBUG) << "Type: " << std::dec << type;
const uint16_t var_value_length = stream.read<uint16_t>();
VLOG(VDEBUG) << "Size of the 'Value' member: 0x" << std::hex << var_value_length;
std::u16string key = {reinterpret_cast<const char16_t*>(stream.content().data() + var_local_offset)};
if (u16tou8(key) != "VarFileInfo") {
LOG(WARNING) << "\"key\" of the resource version should be equal to 'VarFileInfo' (" << u16tou8(key) << ")";
const uint16_t var_type = stream.read<uint16_t>();
VLOG(VDEBUG) << "Type: " << std::dec << var_type;
std::u16string key = stream.read_u16string();
if (u16tou8(key) != "Translation") {
LOG(WARNING) << "\"key\" of the var key should be equal to 'Translation' (" << u16tou8(key) << ")";
}
var_file_info.key_ = key;
stream.align(sizeof(uint32_t));
var_local_offset += (key.size() + 1) * sizeof(char16_t);
var_local_offset = align(var_local_offset, sizeof(uint32_t));
// Parse 'Var' childs
// ==================
VLOG(VDEBUG) << "Parsing 'Var' childs";
while (var_local_offset < offset + var_file_info_length * sizeof(uint8_t)) {
const uint16_t var_length = *reinterpret_cast<const uint16_t*>(stream.read(var_local_offset, sizeof(uint16_t)));
var_local_offset += sizeof(uint16_t);
VLOG(VDEBUG) << "Size of the 'Var' struct: 0x" << std::hex << var_length;
const uint16_t var_value_length = *reinterpret_cast<const uint16_t*>(stream.read(var_local_offset, sizeof(uint16_t)));
var_local_offset += sizeof(uint16_t);
VLOG(VDEBUG) << "Size of the 'Value' member: 0x" << std::hex << var_value_length;
const uint16_t var_type = *reinterpret_cast<const uint16_t*>(stream.read(var_local_offset, sizeof(uint16_t)));
var_local_offset += sizeof(uint16_t);
VLOG(VDEBUG) << "Type: " << std::dec << var_type;
std::u16string key = {reinterpret_cast<const char16_t*>(stream.content().data() + var_local_offset)};
if (u16tou8(key) != "Translation") {
LOG(WARNING) << "\"key\" of the var key should be equal to 'Translation' (" << u16tou8(key) << ")";
}
var_local_offset += (key.size() + 1) * sizeof(char16_t);
var_local_offset = align(var_local_offset, sizeof(uint32_t));
const uint32_t *value_array = reinterpret_cast<const uint32_t*>(stream.read(var_local_offset, var_value_length * sizeof(uint8_t)));
const size_t nb_items = var_value_length / sizeof(uint32_t);
for (size_t i = 0; i < nb_items; ++i) {
VLOG(VDEBUG) << "item[" << std::dec << i << "] = " << std::hex << value_array[i];
var_file_info.translations_.push_back(value_array[i]);
}
var_local_offset += var_value_length;
const size_t nb_items = var_value_length / sizeof(uint32_t);
const uint32_t *value_array = stream.read_array<uint32_t>(nb_items);
for (size_t i = 0; i < nb_items; ++i) {
VLOG(VDEBUG) << "item[" << std::dec << i << "] = " << std::hex << value_array[i];
var_file_info.translations_.push_back(value_array[i]);
}
}
// offset += var_file_info_length * sizeof(uint8_t);
offset = var_local_offset;
stream.setpos(end_var_file_info);
return var_file_info;
}
// Icons
@ -1007,7 +944,7 @@ std::vector<ResourceDialog> ResourcesManager::dialogs(void) const {
const ResourceData* data_node = dynamic_cast<const ResourceData*>(&langs[j]);
const std::vector<uint8_t>& content = data_node->content();
VectorStream stream{content};
stream.setpos(0);
if (content.size() < std::min(sizeof(pe_dialog_template_ext), sizeof(pe_dialog_template))) {
LOG(WARNING) << "Dialog is corrupted!";
@ -1021,18 +958,15 @@ std::vector<ResourceDialog> ResourcesManager::dialogs(void) const {
return {};
}
const pe_dialog_template_ext* header = reinterpret_cast<const pe_dialog_template_ext*>(stream.read(0, sizeof(pe_dialog_template_ext)));
const pe_dialog_template_ext* header = &stream.read<pe_dialog_template_ext>();
ResourceDialog new_dialog{header};
new_dialog.lang(ResourcesManager::lang_from_id(data_node->id()));
new_dialog.sub_lang(ResourcesManager::sublang_from_id(data_node->id()));
size_t offset = sizeof(pe_dialog_template_ext);
// Menu
// ====
const uint16_t menu_hint = *reinterpret_cast<const uint16_t*>(stream.read(offset, sizeof(uint16_t)));
offset += sizeof(uint16_t);
const uint16_t menu_hint = stream.read<uint16_t>();
switch(menu_hint) {
case 0x0000:
{
@ -1042,8 +976,7 @@ std::vector<ResourceDialog> ResourcesManager::dialogs(void) const {
case 0xFFFF:
{
const uint16_t menu_ordinal = *reinterpret_cast<const uint16_t*>(stream.read(offset, sizeof(uint16_t)));
offset += sizeof(uint16_t);
const uint16_t menu_ordinal = stream.read<uint16_t>();
VLOG(VDEBUG) << "Menu uses ordinal number " << std::dec << menu_ordinal;
break;
}
@ -1051,15 +984,17 @@ std::vector<ResourceDialog> ResourcesManager::dialogs(void) const {
default:
{
VLOG(VDEBUG) << "Menu uses unicode string";
std::u16string menu_name = {reinterpret_cast<const char16_t*>(content.data() + offset)};
offset += (menu_name.size() + 1)* sizeof(char16_t);
std::u16string menu_name = stream.read_u16string();
}
}
// Window Class
// ============
const uint16_t window_class_hint = *reinterpret_cast<const uint16_t*>(stream.read(offset, sizeof(uint16_t)));
offset += sizeof(uint16_t);
stream.align(sizeof(uint16_t));
const uint16_t window_class_hint = stream.read<uint16_t>();
switch(window_class_hint) {
case 0x0000:
{
@ -1069,112 +1004,97 @@ std::vector<ResourceDialog> ResourcesManager::dialogs(void) const {
case 0xFFFF:
{
const uint16_t windows_class_ordinal = *reinterpret_cast<const uint16_t*>(stream.read(offset, sizeof(uint16_t)));
const uint16_t windows_class_ordinal = stream.read<uint16_t>();
VLOG(VDEBUG) << "Windows class uses ordinal number " << std::dec << windows_class_ordinal;
offset += sizeof(uint16_t);
break;
}
default:
{
VLOG(VDEBUG) << "Windows class uses unicode string";
std::u16string window_class_name = {reinterpret_cast<const char16_t*>(content.data() + offset)};
offset += (window_class_name.size() + 1) * sizeof(char16_t);
std::u16string window_class_name = stream.read_u16string();
}
}
// Title
// =====
VLOG(VDEBUG) << "Title offset: " << std::hex << offset;
new_dialog.title_ = std::u16string{reinterpret_cast<const char16_t*>(content.data() + offset)};
offset += sizeof(uint16_t) * (new_dialog.title().size() + 1);
stream.align(sizeof(uint16_t));
VLOG(VDEBUG) << "Title offset: " << std::hex << stream.pos();
new_dialog.title_ = stream.read_u16string();
// 2nd part
// ========
const std::set<DIALOG_BOX_STYLES>& dialogbox_styles = new_dialog.dialogbox_style_list();
if (dialogbox_styles.count(DIALOG_BOX_STYLES::DS_SHELLFONT) > 0 or dialogbox_styles.count(DIALOG_BOX_STYLES::DS_SETFONT) > 0) {
const uint16_t point_size = *reinterpret_cast<const uint16_t*>(stream.read(offset, sizeof(uint16_t)));
offset += sizeof(uint16_t);
const uint16_t point_size = stream.read<uint16_t>();
new_dialog.point_size_ = point_size;
const uint16_t weight = *reinterpret_cast<const uint16_t*>(stream.read(offset, sizeof(uint16_t)));
offset += sizeof(uint16_t);
const uint16_t weight = stream.read<uint16_t>();
new_dialog.weight_ = weight;
const uint8_t is_italic = *reinterpret_cast<const uint16_t*>(stream.read(offset, sizeof(uint16_t)));
offset += sizeof(uint8_t);
const uint8_t is_italic = stream.read<uint8_t>();
new_dialog.italic_ = static_cast<bool>(is_italic);
const uint8_t charset = *reinterpret_cast<const uint16_t*>(stream.read(offset, sizeof(uint16_t)));
offset += sizeof(uint8_t);
const uint8_t charset = stream.read<uint8_t>();
new_dialog.charset_ = static_cast<bool>(charset);
new_dialog.typeface_ = std::u16string{reinterpret_cast<const char16_t*>(content.data() + offset)};
offset += (new_dialog.typeface().size() + 1) * sizeof(char16_t);
new_dialog.typeface_ = stream.read_u16string();
}
VLOG(VDEBUG) << "Offset to the items: 0x" << std::hex << offset;
VLOG(VDEBUG) << "Offset to the items: 0x" << std::hex << stream.pos();
VLOG(VDEBUG) << std::endl << std::endl << "####### Items #######" << std::endl;
// Items
// =====
for (size_t i = 0; i < header->nbof_items; ++i) {
offset = align(offset, sizeof(uint32_t));
VLOG(VDEBUG) << "item[" << std::dec << i << "] offset: 0x" << std::hex << offset;
stream.align(sizeof(uint32_t));
VLOG(VDEBUG) << "item[" << std::dec << i << "] offset: 0x" << std::hex << stream.pos();
ResourceDialogItem dialog_item;
if (new_dialog.is_extended()) {
const pe_dialog_item_template_ext* item_header = reinterpret_cast<const pe_dialog_item_template_ext*>(stream.read(offset, sizeof(pe_dialog_item_template_ext)));
offset += sizeof(pe_dialog_item_template_ext);
dialog_item = {item_header};
const pe_dialog_item_template_ext* item_header = &stream.read<pe_dialog_item_template_ext>();
dialog_item = item_header;
VLOG(VDEBUG) << "Item ID: " << std::dec << item_header->id;
} else {
const pe_dialog_item_template* item_header = reinterpret_cast<const pe_dialog_item_template*>(stream.read(offset, sizeof(pe_dialog_item_template)));
offset += sizeof(pe_dialog_item_template);
const pe_dialog_item_template* item_header = &stream.read<pe_dialog_item_template>();
new_dialog.items_.emplace_back(item_header);
continue;
}
// window class
// ------------
offset = align(offset, sizeof(uint32_t));
const uint16_t window_class_hint = *reinterpret_cast<const uint16_t*>(stream.read(offset, sizeof(uint16_t)));
offset += sizeof(uint16_t);
stream.align(sizeof(uint32_t));
const uint16_t window_class_hint = stream.read<uint16_t>();
if (window_class_hint == 0xFFFF) {
const uint16_t windows_class_ordinal = *reinterpret_cast<const uint16_t*>(stream.read(offset, sizeof(uint16_t)));
const uint16_t windows_class_ordinal = stream.read<uint16_t>();
VLOG(VDEBUG) << "Windows class uses ordinal number " << std::dec << windows_class_ordinal;
offset += sizeof(uint16_t);
} else {
VLOG(VDEBUG) << "Windows class uses unicode string";
std::u16string window_class_name = {reinterpret_cast<const char16_t*>(stream.read(offset, sizeof(uint16_t)))};
offset += (window_class_name.size() + 1) * sizeof(char16_t);
std::u16string window_class_name = stream.read_u16string();
}
// Title
// -----
offset = align(offset, sizeof(uint32_t));
const uint16_t title_hint = *reinterpret_cast<const uint16_t*>(stream.read(offset, sizeof(uint16_t)));
stream.align(sizeof(uint32_t));
const uint16_t title_hint = stream.peek<uint16_t>();
if (title_hint == 0xFFFF) {
offset += sizeof(uint16_t);
const uint16_t title_ordinal = *reinterpret_cast<const uint16_t*>(stream.read(offset, sizeof(uint16_t)));
stream.increment_pos(sizeof(uint16_t));
const uint16_t title_ordinal = stream.read<uint16_t>();
VLOG(VDEBUG) << "Title uses ordinal number " << std::dec << title_ordinal;
offset += sizeof(uint16_t);
} else {
std::u16string title_name = {reinterpret_cast<const char16_t*>(content.data() + offset)};
offset += (title_name.size() + 1) * sizeof(char16_t);
std::u16string title_name = stream.read_u16string();
VLOG(VDEBUG) << "Title uses unicode string: \"" << u16tou8(title_name) << "\"";
dialog_item.title_ = std::u16string{title_name};
dialog_item.title_ = title_name;
}
// Extra count
// -----------
const uint16_t extra_count = *reinterpret_cast<const uint16_t*>(stream.read(offset, sizeof(uint16_t)));
offset += sizeof(uint16_t);
const uint16_t extra_count = stream.read<uint16_t>();
VLOG(VDEBUG) << "Extra count: " << std::hex << extra_count << std::endl;
dialog_item.extra_count_ = extra_count;
offset += extra_count * sizeof(uint8_t);
stream.increment_pos(extra_count * sizeof(uint8_t));
new_dialog.items_.push_back(std::move(dialog_item));
}

@ -48,7 +48,7 @@ SignatureParser::SignatureParser(const std::vector<uint8_t>& data) :
stream_{std::unique_ptr<VectorStream>(new VectorStream{data})}
{
this->signature_ptr_ = reinterpret_cast<const uint8_t*>(this->stream_->read(8, this->stream_->size() - 8));
this->signature_ptr_ = this->stream_->peek_array<uint8_t>(8, this->stream_->size() - 8);
this->end_ = this->signature_ptr_ + this->stream_->size() - 8;
this->p_ = const_cast<uint8_t*>(this->signature_ptr_);
try {

@ -150,9 +150,13 @@ PE_TYPE get_type(const std::vector<uint8_t>& raw) {
}
std::string u16tou8(const std::u16string& string) {
std::string u16tou8(const std::u16string& string, bool remove_null_char) {
std::string name;
utf8::utf16to8(std::begin(string), std::end(string), std::back_inserter(name));
if (remove_null_char) {
return std::string{name.c_str()};
}
return name;
}

@ -17,8 +17,13 @@
#include "LIEF/visitors/json.hpp"
#include "LIEF/Abstract/EnumToString.hpp"
#if defined(LIEF_PE_SUPPORT)
#include "LIEF/PE/json.hpp"
#endif
#if defined(LIEF_ELF_SUPPORT)
#include "LIEF/ELF/json.hpp"
#endif
#include "LIEF/config.h"

@ -96,12 +96,9 @@ TEST_CASE("Test parse", "[pe][parser]")
for (size_t j = 0; j < entries_lhs.size(); ++j) {
if (not entries_lhs[j].is_ordinal()) {
INFO("Library: " << imports_lhs[i].name() << ". Function: " << entries_lhs[j].name());
try {
uint64_t address = binary_original->predict_function_rva(imports_lhs[i].name(), entries_lhs[j].name());
uint64_t address = binary_original->predict_function_rva(imports_lhs[i].name(), entries_lhs[j].name());
if (address > 0) {
CHECK(address == entries_rhs[j].iat_address());
} catch (const LIEF::not_supported& e) {
WARN(e.what());
}
}
}