/* Copyright 2017 - 2026 R. Thomas
* Copyright 2017 - 2026 Quarkslab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <algorithm>
#include "LIEF/Visitor.hpp"
#include "LIEF/PE/EnumToString.hpp"
#include "LIEF/PE/Header.hpp"
#include "PE/Structures.hpp"
#include "frozen.hpp"
#include "internal_utils.hpp"
#include <spdlog/fmt/fmt.h>
#include <spdlog/fmt/ranges.h>
namespace LIEF::PE {
static constexpr std::array CHARACTERISTICS_LIST = {
Header::CHARACTERISTICS::RELOCS_STRIPPED,
Header::CHARACTERISTICS::EXECUTABLE_IMAGE,
Header::CHARACTERISTICS::LINE_NUMS_STRIPPED,
Header::CHARACTERISTICS::LOCAL_SYMS_STRIPPED,
Header::CHARACTERISTICS::AGGRESSIVE_WS_TRIM,
Header::CHARACTERISTICS::LARGE_ADDRESS_AWARE,
Header::CHARACTERISTICS::BYTES_REVERSED_LO,
Header::CHARACTERISTICS::NEED_32BIT_MACHINE,
Header::CHARACTERISTICS::DEBUG_STRIPPED,
Header::CHARACTERISTICS::REMOVABLE_RUN_FROM_SWAP,
Header::CHARACTERISTICS::NET_RUN_FROM_SWAP,
Header::CHARACTERISTICS::SYSTEM,
Header::CHARACTERISTICS::DLL,
Header::CHARACTERISTICS::UP_SYSTEM_ONLY,
Header::CHARACTERISTICS::BYTES_REVERSED_HI
};
bool Header::is_known_machine(uint16_t machine) {
return to_string((MACHINE_TYPES)machine) != std::string("UNKNOWN");
}
Header Header::create(PE_TYPE type) {
Header hdr;
const size_t sizeof_dirs = details::DEFAULT_NUMBER_DATA_DIRECTORIES *
sizeof(details::pe_data_directory);
hdr.signature({'P', 'E', '\0', '\0'});
hdr.sizeof_optional_header(type == PE_TYPE::PE32 ?
sizeof(details::pe32_optional_header) :
sizeof(details::pe64_optional_header) +
sizeof_dirs);
hdr.machine(MACHINE_TYPES::AMD64);
return hdr;
}
Header::Header(const details::pe_header& header) :
signature_{},
machine_(static_cast<MACHINE_TYPES>(header.Machine)),
nb_sections_(header.NumberOfSections),
timedatestamp_(header.TimeDateStamp),
pointerto_symtab_(header.PointerToSymbolTable),
nb_symbols_(header.NumberOfSymbols),
sizeof_opt_header_(header.SizeOfOptionalHeader),
characteristics_(header.Characteristics) {
std::copy(std::begin(header.signature), std::end(header.signature),
std::begin(signature_));
}
std::vector<Header::CHARACTERISTICS> Header::characteristics_list() const {
std::vector<Header::CHARACTERISTICS> list;
list.reserve(3);
std::copy_if(CHARACTERISTICS_LIST.begin(), CHARACTERISTICS_LIST.end(),
std::back_inserter(list),
[this](CHARACTERISTICS c) { return has_characteristic(c); });
return list;
}
void Header::accept(LIEF::Visitor& visitor) const {
visitor.visit(*this);
}
std::ostream& operator<<(std::ostream& os, const Header& entry) {
const Header::signature_t& sig = entry.signature();
const std::string& signature_str =
fmt::format("{:02x} {:02x} {:02x} {:02x}", sig[0], sig[1], sig[2], sig[3]);
const auto& list = entry.characteristics_list();
std::vector<std::string> list_str;
list_str.reserve(list.size());
std::transform(list.begin(), list.end(), std::back_inserter(list_str),
[](const auto c) { return to_string(c); });
os << fmt::format("Signature: {}\n", signature_str)
<< fmt::format("Machine: {}\n", to_string(entry.machine()))
<< fmt::format("Number of sections: {}\n", entry.numberof_sections())
<< fmt::format("Pointer to symbol table: {:#x}\n",
entry.pointerto_symbol_table())
<< fmt::format("Number of symbols: {}\n", entry.numberof_symbols())
<< fmt::format("Size of optional header: {:#x}\n",
entry.sizeof_optional_header())
<< fmt::format("Characteristics: {}\n", fmt::join(list_str, ", "))
<< fmt::format("Timestamp: {} ({})\n", entry.time_date_stamp(),
ts_to_str(entry.time_date_stamp()));
return os;
}
const char* to_string(Header::MACHINE_TYPES e) {
#define ENTRY(X) std::pair(Header::MACHINE_TYPES::X, #X)
STRING_MAP enums2str{
ENTRY(UNKNOWN), ENTRY(ALPHA), ENTRY(ALPHA64), ENTRY(AM33),
ENTRY(AMD64), ENTRY(ARM), ENTRY(ARMNT), ENTRY(ARM64),
ENTRY(EBC), ENTRY(I386), ENTRY(IA64), ENTRY(LOONGARCH32),
ENTRY(LOONGARCH64), ENTRY(M32R), ENTRY(MIPS16), ENTRY(MIPSFPU),
ENTRY(MIPSFPU16), ENTRY(POWERPC), ENTRY(POWERPCFP), ENTRY(POWERPCBE),
ENTRY(R4000), ENTRY(RISCV32), ENTRY(RISCV64), ENTRY(RISCV128),
ENTRY(SH3), ENTRY(SH3DSP), ENTRY(SH4), ENTRY(SH5),
ENTRY(THUMB), ENTRY(WCEMIPSV2), ENTRY(ARM64EC), ENTRY(ARM64X),
ENTRY(CHPE_X86),
};
#undef ENTRY
if (auto it = enums2str.find(e); it != enums2str.end()) {
return it->second;
}
return "UNKNOWN";
}
const char* to_string(Header::CHARACTERISTICS e) {
#define ENTRY(X) std::pair(Header::CHARACTERISTICS::X, #X)
STRING_MAP enums2str{
ENTRY(NONE),
ENTRY(RELOCS_STRIPPED),
ENTRY(EXECUTABLE_IMAGE),
ENTRY(LINE_NUMS_STRIPPED),
ENTRY(LOCAL_SYMS_STRIPPED),
ENTRY(AGGRESSIVE_WS_TRIM),
ENTRY(LARGE_ADDRESS_AWARE),
ENTRY(BYTES_REVERSED_LO),
ENTRY(NEED_32BIT_MACHINE),
ENTRY(DEBUG_STRIPPED),
ENTRY(REMOVABLE_RUN_FROM_SWAP),
ENTRY(NET_RUN_FROM_SWAP),
ENTRY(SYSTEM),
ENTRY(DLL),
ENTRY(UP_SYSTEM_ONLY),
ENTRY(BYTES_REVERSED_HI),
};
#undef ENTRY
if (auto it = enums2str.find(e); it != enums2str.end()) {
return it->second;
}
return "NONE";
}
}