mirror of
https://github.com/QuasarApp/LIEF.git
synced 2025-05-03 07:39:34 +00:00
Major changes (features): * Enable adding multiple sections/segments - Executable (PIE or not), Library * Enable adding multiple dynamic entries (DT_NEEDED, DT_INIT etc) * Enable adding multiple relocations * Enable adding multiple dynamic symbols * Enable segment replacement Major changes (API): * Getters Binary::get_*name*() has been renamed to "name()" * Binary::add(const DynamicEntry& entry) - To add an entry in the dynamic table * Section& Binary::add(const Section& section, bool loaded = true) - To add a section(s) * Segment& Binary::add(const Segment& segment, uint64_t base = 0) - To add segments * Segment& replace(const Segment& new_segment, const Segment& original_segment, uint64_t base = 0) * Binary's last_offset_section(), last_offset_segment(), next_virtual_address() to have information about offset * Binary's add_library(), get_library(), has_library() to handle DT_NEEDED entries Other changes: * Binary::insert_content() - Use add(const Section&) or add(const Segment&) instead * ELF's DataHandler has been cleaned * Through LIEF::Section one can look for integers, strings, data within the section (see LIEF::Section::search, LIEF::Section::search_all) * Through LIEF::Binary one can get *xref* of a number (or address) see LIEF::Binary::xref function * To access to the Abstract binary in Python, one can now use the 'abstract' attribute. (e.g. binary.abstract.header.is_32) Resolve: #83 Resolve: #66 Resolve: #48
191 lines
7.6 KiB
C++
191 lines
7.6 KiB
C++
/* Copyright 2017 R. Thomas
|
|
* Copyright 2017 Quarkslab
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
#define CATCH_CONFIG_MAIN
|
|
#include <catch.hpp>
|
|
#include <yaml-cpp/yaml.h>
|
|
|
|
#include <LIEF/ELF.hpp>
|
|
|
|
#include "utils.hpp"
|
|
|
|
extern const YAML::Node config = YAML::LoadFile(std::string(PATH_TO_CONFIG) + "/config.yaml");
|
|
|
|
using namespace LIEF::ELF;
|
|
|
|
TEST_CASE("Test parse", "[elf][parser]")
|
|
{
|
|
|
|
using namespace Catch::Generators;
|
|
// Get test cases
|
|
std::vector<std::string> elf_test_cases = Test::get_test_cases();
|
|
|
|
// Get one
|
|
std::vector<std::string>::iterator test_case = between(
|
|
std::begin(elf_test_cases),
|
|
std::prev(std::end(elf_test_cases)));
|
|
|
|
|
|
YAML::Node parameters = YAML::LoadFile(config[*test_case]["config_file"].as<std::string>());
|
|
|
|
DYNSYM_COUNT_METHODS mtd = DYNSYM_COUNT_METHODS::COUNT_AUTO;
|
|
if (*test_case == "test_gcc_32") {
|
|
mtd = DYNSYM_COUNT_METHODS::COUNT_SECTION;
|
|
}
|
|
// Parse binary
|
|
std::unique_ptr<const Binary> binary{Parser::parse(config[*test_case]["binary_path"].as<std::string>(), mtd)};
|
|
|
|
INFO("Binary used: " << binary->name());
|
|
|
|
// Raw data
|
|
std::ifstream binfile(config[*test_case]["binary_path"].as<std::string>(), std::ios::in | std::ios::binary);
|
|
REQUIRE(binfile);
|
|
std::vector<uint8_t> raw = {std::istreambuf_iterator<char>(binfile), std::istreambuf_iterator<char>()};
|
|
|
|
// Header
|
|
// ======
|
|
SECTION("Header") {
|
|
const Header& header = binary->header();
|
|
REQUIRE(header.numberof_sections() == parameters["Header"]["nbShdr"].as<unsigned int>());
|
|
REQUIRE(header.numberof_segments() == parameters["Header"]["nbPhdr"].as<unsigned int>());
|
|
REQUIRE(header.entrypoint() == parameters["Header"]["entryPoint"].as<unsigned long long>());
|
|
REQUIRE(header.program_headers_offset() == parameters["Header"]["offsetToPhdr"].as<unsigned long long>());
|
|
REQUIRE(header.section_headers_offset() == parameters["Header"]["offsetToShdr"].as<unsigned long long>());
|
|
}
|
|
|
|
// Sections
|
|
// ========
|
|
SECTION("Sections") {
|
|
|
|
REQUIRE(binary->sections().size() == parameters["Header"]["nbShdr"].as<unsigned int>());
|
|
|
|
if (parameters["Sections"]) {
|
|
it_const_sections sections = binary->sections();
|
|
for (size_t i = 0; i < parameters["Sections"].size(); ++i) {
|
|
const Section& section = sections[i];
|
|
//name[:17] because readelf provide only the first 16 char
|
|
REQUIRE(parameters["Sections"][i]["name"].as<std::string>() == section.name().substr(0,17));
|
|
|
|
REQUIRE(parameters["Sections"][i]["offset"].as<unsigned long long>() == section.file_offset());
|
|
|
|
REQUIRE(parameters["Sections"][i]["address"].as<unsigned long long>() == section.virtual_address());
|
|
|
|
REQUIRE(parameters["Sections"][i]["size"].as<unsigned long long>() == section.size());
|
|
|
|
REQUIRE(parameters["Sections"][i]["nb"].as<unsigned int>() == i);
|
|
|
|
if (parameters["Sections"][i]["size"].as<unsigned long long>() > 0 and
|
|
section.type() != LIEF::ELF::ELF_SECTION_TYPES::SHT_NOBITS) {
|
|
REQUIRE(
|
|
std::vector<uint8_t>(
|
|
raw.data() + parameters["Sections"][i]["offset"].as<unsigned long long>(),
|
|
raw.data() + parameters["Sections"][i]["offset"].as<unsigned long long>() + parameters["Sections"][i]["size"].as<unsigned long long>()) ==
|
|
section.content()
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Segments
|
|
// ========
|
|
SECTION("Segments") {
|
|
REQUIRE(binary->segments().size() == parameters["Header"]["nbPhdr"].as<unsigned int>());
|
|
if (parameters["Segments"]) {
|
|
it_const_segments segments = binary->segments();
|
|
for (size_t i = 0; i < parameters["Segments"].size(); ++i) {
|
|
const Segment& segment = segments[i];
|
|
REQUIRE(parameters["Segments"][i]["fSize"].as<unsigned long long>() == segment.physical_size());
|
|
REQUIRE(parameters["Segments"][i]["offset"].as<unsigned long long>() == segment.file_offset());
|
|
REQUIRE(parameters["Segments"][i]["pAddress"].as<unsigned long long>() == segment.physical_address());
|
|
REQUIRE(parameters["Segments"][i]["vAddress"].as<unsigned long long>() == segment.virtual_address());
|
|
REQUIRE(parameters["Segments"][i]["fSize"].as<unsigned long long>() == segment.physical_size());
|
|
REQUIRE(parameters["Segments"][i]["vSize"].as<unsigned long long>() == segment.virtual_size());
|
|
if (parameters["Segments"][i]["fSize"].as<unsigned long long>() > 0) {
|
|
REQUIRE(
|
|
std::vector<uint8_t>(
|
|
raw.data() + parameters["Segments"][i]["offset"].as<unsigned long long>(),
|
|
raw.data() + parameters["Segments"][i]["offset"].as<unsigned long long>() + parameters["Segments"][i]["fSize"].as<unsigned long long>()) ==
|
|
segment.content());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Dynamic symbols
|
|
// ===============
|
|
SECTION("Dynamic Symbols") {
|
|
if (parameters["DynamicSymbols"]) {
|
|
// +1 for the null entry
|
|
REQUIRE(parameters["DynamicSymbols"].size() == binary->dynamic_symbols().size());
|
|
|
|
it_const_symbols dynamic_symbols = binary->dynamic_symbols();
|
|
for (size_t i = 0; i < parameters["DynamicSymbols"].size(); ++i) {
|
|
const Symbol& symbol = dynamic_symbols[i];
|
|
REQUIRE(parameters["DynamicSymbols"][i]["name"].as<std::string>() == symbol.name().substr(0, 25));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Static symbols
|
|
// ===============
|
|
SECTION("Static Symbols") {
|
|
if (parameters["StaticSymbols"]) {
|
|
it_const_symbols static_symbols = binary->static_symbols();
|
|
for (size_t i = 0; i < parameters["StaticSymbols"].size(); ++i) {
|
|
const Symbol& symbol = static_symbols[parameters["StaticSymbols"][i]["num"].as<size_t>()];
|
|
REQUIRE(parameters["StaticSymbols"][i]["name"].as<std::string>() == symbol.name().substr(0, 25));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Dynamic relocations
|
|
// ===================
|
|
SECTION("Dynamic relocations") {
|
|
if (parameters["DynamicReloc"]) {
|
|
REQUIRE(parameters["DynamicReloc"].size() == binary->dynamic_relocations().size());
|
|
it_const_dynamic_relocations relocations = binary->dynamic_relocations();
|
|
for (size_t i = 0; i < parameters["DynamicReloc"].size(); ++i) {
|
|
const Relocation& relocation = relocations[i];
|
|
REQUIRE(parameters["DynamicReloc"][i]["name"].as<std::string>() == relocation.symbol().name().substr(0, 22));
|
|
REQUIRE(parameters["DynamicReloc"][i]["offset"].as<uint64_t>() == relocation.address());
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// .plt.got relocations
|
|
// ====================
|
|
SECTION(".plt.got relocations") {
|
|
if (parameters["PltGotReloc"]) {
|
|
REQUIRE(parameters["PltGotReloc"].size() == binary->pltgot_relocations().size());
|
|
it_const_pltgot_relocations relocations = binary->pltgot_relocations();
|
|
for (size_t i = 0; i < parameters["PltGotReloc"].size(); ++i) {
|
|
const Relocation& relocation = relocations[i];
|
|
if (parameters["PltGotReloc"][i]["name"].as<std::string>().size() > 0) {
|
|
REQUIRE(parameters["PltGotReloc"][i]["name"].as<std::string>() == relocation.symbol().name().substr(0, 22));
|
|
}
|
|
REQUIRE(parameters["PltGotReloc"][i]["offset"].as<uint64_t>() == relocation.address());
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|