mirror of
https://github.com/QuasarApp/LIEF.git
synced 2025-04-27 21:04:32 +00:00
parent
ab349aadc6
commit
eeddc38393
@ -33,7 +33,20 @@ using setter_t = void (ExportEntry::*)(T);
|
||||
|
||||
template<>
|
||||
void create<ExportEntry>(py::module& m) {
|
||||
py::class_<ExportEntry, LIEF::Object>(m, "ExportEntry")
|
||||
py::class_<ExportEntry, LIEF::Object> export_entry(m, "ExportEntry");
|
||||
|
||||
py::class_<ExportEntry::forward_information_t>(export_entry, "forward_information_t")
|
||||
.def_readwrite("library", &ExportEntry::forward_information_t::library)
|
||||
.def_readwrite("function", &ExportEntry::forward_information_t::function)
|
||||
|
||||
.def("__str__", [] (const ExportEntry::forward_information_t& info)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << info;
|
||||
return stream.str();
|
||||
});
|
||||
|
||||
export_entry
|
||||
.def(py::init<>())
|
||||
|
||||
.def_property("name",
|
||||
@ -54,6 +67,15 @@ void create<ExportEntry>(py::module& m) {
|
||||
static_cast<getter_t<bool>>(&ExportEntry::is_extern),
|
||||
static_cast<setter_t<bool>>(&ExportEntry::is_extern))
|
||||
|
||||
.def_property_readonly("is_forwarded",
|
||||
&ExportEntry::is_forwarded)
|
||||
|
||||
.def_property_readonly("forward_information",
|
||||
&ExportEntry::forward_information)
|
||||
|
||||
.def_property_readonly("function_rva",
|
||||
&ExportEntry::function_rva)
|
||||
|
||||
.def("__eq__", &ExportEntry::operator==)
|
||||
.def("__ne__", &ExportEntry::operator!=)
|
||||
.def("__hash__",
|
||||
|
@ -4,6 +4,7 @@ Changelog
|
||||
0.11.0 - Not Released
|
||||
---------------------
|
||||
|
||||
- Handle PE forwarded exports (`issues/307 <https://github.com/lief-project/LIEF/issues/307>`)
|
||||
- Add ``PT_GNU_PROPERTY`` enum
|
||||
|
||||
0.10.1 - November 29, 2019
|
||||
|
9
examples/python/pe_forwardinfo.py
Normal file
9
examples/python/pe_forwardinfo.py
Normal file
@ -0,0 +1,9 @@
|
||||
import lief
|
||||
import sys
|
||||
|
||||
pe = lief.parse(sys.argv[1])
|
||||
exports = pe.get_export()
|
||||
|
||||
for e in filter(lambda e: e.is_forwarded, exports.entries):
|
||||
fwd = e.forward_information
|
||||
print(f"{e.name:<35} -> {fwd.library}.{fwd.function}")
|
@ -38,6 +38,16 @@ class LIEF_API ExportEntry : public Object {
|
||||
friend class Builder;
|
||||
friend class Parser;
|
||||
|
||||
public:
|
||||
struct LIEF_API forward_information_t {
|
||||
std::string library;
|
||||
std::string function;
|
||||
|
||||
operator bool() const;
|
||||
|
||||
LIEF_API friend std::ostream& operator<<(std::ostream& os, const forward_information_t& info);
|
||||
};
|
||||
|
||||
public:
|
||||
ExportEntry(void);
|
||||
ExportEntry(const ExportEntry&);
|
||||
@ -48,6 +58,10 @@ class LIEF_API ExportEntry : public Object {
|
||||
uint16_t ordinal(void) const;
|
||||
uint32_t address(void) const;
|
||||
bool is_extern(void) const;
|
||||
bool is_forwarded(void) const;
|
||||
forward_information_t forward_information(void) const;
|
||||
|
||||
uint32_t function_rva(void) const;
|
||||
|
||||
void name(const std::string& name);
|
||||
void ordinal(uint16_t ordinal);
|
||||
@ -63,10 +77,13 @@ class LIEF_API ExportEntry : public Object {
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
uint32_t function_rva_;
|
||||
uint16_t ordinal_;
|
||||
uint32_t address_;
|
||||
bool is_extern_;
|
||||
|
||||
forward_information_t forward_info_;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -31,6 +31,10 @@ ExportEntry::ExportEntry(void) :
|
||||
is_extern_{false}
|
||||
{}
|
||||
|
||||
ExportEntry::forward_information_t::operator bool() const {
|
||||
return library.size() > 0 or function.size() > 0;
|
||||
}
|
||||
|
||||
|
||||
const std::string& ExportEntry::name(void) const {
|
||||
return this->name_;
|
||||
@ -48,6 +52,22 @@ bool ExportEntry::is_extern(void) const {
|
||||
return this->is_extern_;
|
||||
}
|
||||
|
||||
bool ExportEntry::is_forwarded(void) const {
|
||||
return this->forward_info_;
|
||||
}
|
||||
|
||||
ExportEntry::forward_information_t ExportEntry::forward_information(void) const {
|
||||
if (not this->is_forwarded()) {
|
||||
return {};
|
||||
}
|
||||
return this->forward_info_;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ExportEntry::function_rva(void) const {
|
||||
return this->function_rva_;
|
||||
}
|
||||
|
||||
void ExportEntry::name(const std::string& name) {
|
||||
this->name_ = name;
|
||||
}
|
||||
@ -78,14 +98,20 @@ bool ExportEntry::operator!=(const ExportEntry& rhs) const {
|
||||
return not (*this == rhs);
|
||||
}
|
||||
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const ExportEntry::forward_information_t& info) {
|
||||
os << info.library << "." << info.function;
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const ExportEntry& export_entry) {
|
||||
os << std::hex;
|
||||
os << std::left;
|
||||
std::string name = export_entry.name();
|
||||
if (name.size() > 20) {
|
||||
name = name.substr(0, 17) + "...";
|
||||
if (name.size() > 30) {
|
||||
name = name.substr(0, 27) + "... ";
|
||||
}
|
||||
os << std::setw(23) << name;
|
||||
os << std::setw(33) << name;
|
||||
os << std::setw(5) << export_entry.ordinal();
|
||||
|
||||
if (not export_entry.is_extern()) {
|
||||
@ -93,6 +119,10 @@ std::ostream& operator<<(std::ostream& os, const ExportEntry& export_entry) {
|
||||
} else {
|
||||
os << std::setw(10) << "[Extern]";
|
||||
}
|
||||
|
||||
if (export_entry.is_forwarded()) {
|
||||
os << " " << export_entry.forward_information();
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
|
@ -766,19 +766,21 @@ void Parser::parse_exports(void) {
|
||||
// If value is inside export directory => 'external' function
|
||||
if (value >= std::get<0>(range) and value < std::get<1>(range)) {
|
||||
uint32_t name_offset = this->binary_->rva_to_offset(value);
|
||||
|
||||
ExportEntry entry;
|
||||
entry.name_ = this->stream_->peek_string_at(name_offset);
|
||||
entry.address_ = 0;
|
||||
entry.is_extern_ = true;
|
||||
entry.ordinal_ = i + export_directory_table.OrdinalBase;
|
||||
entry.name_ = this->stream_->peek_string_at(name_offset);
|
||||
entry.address_ = 0;
|
||||
entry.is_extern_ = true;
|
||||
entry.ordinal_ = i + export_directory_table.OrdinalBase;
|
||||
entry.function_rva_ = value;
|
||||
|
||||
export_object.entries_.push_back(std::move(entry));
|
||||
} else {
|
||||
ExportEntry entry;
|
||||
entry.name_ = "";
|
||||
entry.address_ = value;
|
||||
entry.is_extern_ = false;
|
||||
entry.ordinal_ = i + export_directory_table.OrdinalBase;
|
||||
entry.name_ = "";
|
||||
entry.address_ = value;
|
||||
entry.is_extern_ = false;
|
||||
entry.ordinal_ = i + export_directory_table.OrdinalBase;
|
||||
entry.function_rva_ = value;
|
||||
|
||||
|
||||
if (value == 0) {
|
||||
@ -801,7 +803,29 @@ void Parser::parse_exports(void) {
|
||||
std::string name = this->stream_->peek_string_at(name_offset);
|
||||
|
||||
ExportEntry& entry = export_object.entries_[ordinal_table[i]];
|
||||
entry.name_ = name;
|
||||
|
||||
// Check if the entry is 'extern' and if the export name is already set
|
||||
if (entry.is_extern_ and not entry.name_.empty()) {
|
||||
std::string fwd_str = entry.name_;
|
||||
|
||||
std::string function = fwd_str;
|
||||
std::string library;
|
||||
|
||||
// Split on '.'
|
||||
const size_t dot_pos = fwd_str.find('.');
|
||||
if (dot_pos != std::string::npos) {
|
||||
library = fwd_str.substr(0, dot_pos);
|
||||
function = fwd_str.substr(dot_pos + 1);
|
||||
}
|
||||
|
||||
ExportEntry::forward_information_t finfo;
|
||||
finfo.library = library;
|
||||
finfo.function = function;
|
||||
|
||||
entry.forward_info_ = finfo;
|
||||
}
|
||||
|
||||
entry.name_ = name;
|
||||
|
||||
if (name.size() > MAX_EXPORT_NAME_SIZE) {
|
||||
corrupted_entries.insert(entry.ordinal_);
|
||||
|
@ -317,6 +317,14 @@ void JsonVisitor::visit(const ExportEntry& export_entry) {
|
||||
this->node_["ordinal"] = export_entry.ordinal();
|
||||
this->node_["address"] = export_entry.address();
|
||||
this->node_["is_extern"] = export_entry.is_extern();
|
||||
|
||||
if (export_entry.is_forwarded()) {
|
||||
const ExportEntry::forward_information_t& fwd_info = export_entry.forward_information();
|
||||
this->node_["forward_information"] = {
|
||||
{"library", fwd_info.library},
|
||||
{"function", fwd_info.function},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void JsonVisitor::visit(const TLS& tls) {
|
||||
|
@ -68,6 +68,10 @@ if (PYTHON_TESTS_ENABLED)
|
||||
${PYTHON_EXECUTABLE}
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/test_loadconfig.py")
|
||||
|
||||
ADD_PYTHON_TEST(PE_PYTHON_forwarded_exports
|
||||
${PYTHON_EXECUTABLE}
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/test_forward_information.py")
|
||||
|
||||
endif()
|
||||
|
||||
|
||||
|
41
tests/pe/test_forward_information.py
Normal file
41
tests/pe/test_forward_information.py
Normal file
@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
import lief
|
||||
import unittest
|
||||
import logging
|
||||
import json
|
||||
|
||||
|
||||
from unittest import TestCase
|
||||
from utils import get_sample
|
||||
|
||||
class TestForwardInfo(TestCase):
|
||||
def setUp(self):
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self.maxDiff = None
|
||||
|
||||
def test_basic(self):
|
||||
path = get_sample('PE/PE32_x86_library_kernel32.dll')
|
||||
sample = lief.parse(path)
|
||||
exports = sample.get_export()
|
||||
forwarded_exports = [exp for exp in exports.entries if exp.is_forwarded]
|
||||
self.assertTrue(len(forwarded_exports) == 82)
|
||||
|
||||
# Test JSON Serialization
|
||||
json_serialized = json.loads(lief.to_json(forwarded_exports[0]))
|
||||
|
||||
self.assertTrue("forward_information" in json_serialized)
|
||||
self.assertTrue(json_serialized["forward_information"]["library"] == "NTDLL")
|
||||
self.assertTrue(json_serialized["forward_information"]["function"] == "RtlInterlockedPushListSList")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
root_logger = logging.getLogger()
|
||||
root_logger.setLevel(logging.DEBUG)
|
||||
|
||||
ch = logging.StreamHandler()
|
||||
ch.setLevel(logging.DEBUG)
|
||||
root_logger.addHandler(ch)
|
||||
|
||||
unittest.main(verbosity=2)
|
Loading…
x
Reference in New Issue
Block a user