Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement predict_function_rva by ordinal #1021

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions api/python/lief/PE.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ class Binary(lief.Binary):
def has_delay_import(self, import_name: str) -> bool: ...
def has_import(self, import_name: str) -> bool: ...
def predict_function_rva(self, library: str, function: str) -> int: ...
def predict_function_rva(self, library: str, function: int) -> int: ...
def remove(self, section: lief.PE.Section, clear: bool = ...) -> None: ...
def remove_all_libraries(self) -> None: ...
def remove_all_relocations(self) -> None: ...
Expand Down
5 changes: 5 additions & 0 deletions api/python/src/PE/objects/pyBinary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,11 @@ void create<Binary>(nb::module_& m) {
nb::overload_cast<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"_doc,
"library"_a, "function"_a)

.def("predict_function_rva",
nb::overload_cast<const std::string&, const uint16_t&>(&Binary::predict_function_rva),
"Try to predict the RVA of the given function ordinal in the given import library name"_doc,
"library"_a, "ordinal"_a)

.def_prop_ro("signatures",
nb::overload_cast<>(&Binary::signatures, nb::const_),
Expand Down
18 changes: 16 additions & 2 deletions include/LIEF/PE/Binary.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ class LIEF_API Binary : public LIEF::Binary {
//! Try to predict the RVA of the function `function` in the import library `library`
//!
//! @warning
//! The value could be chang if imports change
//! The value could be changed if imports change
//!
//! @note
//! It should be used with:
Expand All @@ -339,7 +339,21 @@ class LIEF_API Binary : public LIEF::Binary {
//! @param[in] function Function name
//! @return The address of the function (``IAT``) in the new import table
uint32_t predict_function_rva(const std::string& library, const std::string& function);


//! Try to predict the RVA of the ordinal `ordinal` in the import library `library`
//!
//! @warning
//! The value could be changed if imports change
//!
//! @note
//! It should be used with:
//! LIEF::PE::Builder::build_imports set to ``true``
//!
//! @param[in] library Library name in which the function is located
//! @param[in] ordinal Function ordinal
//! @return The address of the function (``IAT``) in the new import table
uint32_t predict_function_rva(const std::string& library, const uint16_t& ordinal);

//! Return the Export object
Export* get_export() {
return export_.get();
Expand Down
81 changes: 81 additions & 0 deletions src/PE/Binary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,87 @@ uint32_t Binary::predict_function_rva(const std::string& library, const std::str
return next_virtual_address + address;
}

uint32_t Binary::predict_function_rva(const std::string& library, const uint16_t& ordinal) {
const auto it_import = std::find_if(imports_.cbegin(), imports_.cend(),
[&library](const Import& imp) {
return imp.name() == library;
});

if (it_import == std::end(imports_)) {
LIEF_ERR("Unable to find library {}", library);
return 0;
}

Import::it_const_entries entries = it_import->entries();

// Some weird library define a function twice
size_t nb_functions = std::count_if(entries.cbegin(), entries.cend(),
[&ordinal](const ImportEntry& entry) {
return entry.is_ordinal() && entry.ordinal() == ordinal;
});

if (nb_functions == 0) {
LIEF_ERR("Unable to find the ordinal '{}' in '{}'", ordinal, library);
return 0;
}

if (nb_functions > 1) {
LIEF_ERR("{} is defined #{:d} times in {}", ordinal, nb_functions, library);
return 0;
}

uint32_t import_table_size = static_cast<uint32_t>((imports().size() + 1) * sizeof(details::pe_import)); // +1 for the null entry

uint32_t address = import_table_size;

uint32_t lookup_table_size = 0;
for (const Import& f : imports_) {
if (type_ == PE_TYPE::PE32) {
lookup_table_size += (f.entries().size() + 1) * sizeof(uint32_t);
}
else {
lookup_table_size += (f.entries().size() + 1) * sizeof(uint64_t);
}
}

address += lookup_table_size;

for (auto it_imp = imports_.cbegin();
(it_imp->name() != library && it_imp != imports_.cend());
++it_imp) {
if (type_ == PE_TYPE::PE32) {
address += sizeof(uint32_t) * (it_imp->entries().size() + 1);
}
else {
address += sizeof(uint64_t) * (it_imp->entries().size() + 1);
}
}


for (auto it_func = entries.cbegin();
(it_func->ordinal() != ordinal && it_func != entries.cend());
++it_func) {
if (type_ == PE_TYPE::PE32) {
address += sizeof(uint32_t);
}
else {
address += sizeof(uint64_t);
}
}


// We assume the the idata section will be the last section
const auto section_align = static_cast<uint64_t>(optional_header().section_alignment());
const uint64_t next_virtual_address = align(std::accumulate(
std::begin(sections_),
std::end(sections_), section_align,
[](uint64_t va, const std::unique_ptr<Section>& s) {
return std::max<uint64_t>(s->virtual_address() + s->virtual_size(), va);
}), section_align);

return next_virtual_address + address;
}

Import* Binary::get_import(const std::string& import_name) {
return const_cast<Import*>(static_cast<const Binary*>(this)->get_import(import_name));
}
Expand Down