/* 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 "MachO/json_internal.hpp"
#include "LIEF/MachO/BinaryParser.hpp"
#include "LIEF/MachO/BindingInfo.hpp"
#include "LIEF/MachO/BindingInfoIterator.hpp"
#include "LIEF/MachO/BuildToolVersion.hpp"
#include "LIEF/MachO/BuildVersion.hpp"
#include "LIEF/MachO/Builder.hpp"
#include "LIEF/MachO/ChainedBindingInfo.hpp"
#include "LIEF/MachO/CodeSignature.hpp"
#include "LIEF/MachO/CodeSignatureDir.hpp"
#include "LIEF/MachO/DataCodeEntry.hpp"
#include "LIEF/MachO/DataInCode.hpp"
#include "LIEF/MachO/DyldBindingInfo.hpp"
#include "LIEF/MachO/DyldChainedFixups.hpp"
#include "LIEF/MachO/DyldChainedFixupsCreator.hpp"
#include "LIEF/MachO/DyldEnvironment.hpp"
#include "LIEF/MachO/DyldExportsTrie.hpp"
#include "LIEF/MachO/DyldInfo.hpp"
#include "LIEF/MachO/DylibCommand.hpp"
#include "LIEF/MachO/DylinkerCommand.hpp"
#include "LIEF/MachO/DynamicSymbolCommand.hpp"
#include "LIEF/MachO/EncryptionInfo.hpp"
#include "LIEF/MachO/ExportInfo.hpp"
#include "LIEF/MachO/FatBinary.hpp"
#include "LIEF/MachO/FilesetCommand.hpp"
#include "LIEF/MachO/FunctionStarts.hpp"
#include "LIEF/MachO/Header.hpp"
#include "LIEF/MachO/LinkEdit.hpp"
#include "LIEF/MachO/LinkerOptHint.hpp"
#include "LIEF/MachO/LoadCommand.hpp"
#include "LIEF/MachO/MainCommand.hpp"
#include "LIEF/MachO/NoteCommand.hpp"
#include "LIEF/MachO/Parser.hpp"
#include "LIEF/MachO/RPathCommand.hpp"
#include "LIEF/MachO/Relocation.hpp"
#include "LIEF/MachO/RelocationDyld.hpp"
#include "LIEF/MachO/RelocationFixup.hpp"
#include "LIEF/MachO/RelocationObject.hpp"
#include "LIEF/MachO/Routine.hpp"
#include "LIEF/MachO/Section.hpp"
#include "LIEF/MachO/SegmentCommand.hpp"
#include "LIEF/MachO/SegmentSplitInfo.hpp"
#include "LIEF/MachO/SourceVersion.hpp"
#include "LIEF/MachO/Stub.hpp"
#include "LIEF/MachO/SubFramework.hpp"
#include "LIEF/MachO/Symbol.hpp"
#include "LIEF/MachO/SymbolCommand.hpp"
#include "LIEF/MachO/ThreadCommand.hpp"
#include "LIEF/MachO/TwoLevelHints.hpp"
#include "LIEF/MachO/UUIDCommand.hpp"
#include "LIEF/MachO/UnknownCommand.hpp"
#include "LIEF/MachO/VersionMin.hpp"
#include "LIEF/MachO/hash.hpp"
#include "LIEF/MachO/utils.hpp"
#include "LIEF/MachO/EnumToString.hpp"
#include "Object.tcc"
#include "MachO/Binary.tcc"
namespace LIEF::MachO {
template<class T>
inline void process_command(json& node, const Binary& bin, const char* key) {
auto* cmd = bin.command<T>();
if (cmd != nullptr) {
JsonVisitor v;
v(*cmd);
node[key] = v.get();
}
}
void JsonVisitor::visit(const Binary& binary) {
JsonVisitor header_visitor;
header_visitor(binary.header());
// Sections
std::vector<json> sections;
for (const Section& section : binary.sections()) {
JsonVisitor visitor;
visitor(section);
sections.emplace_back(visitor.get());
}
// Segments
std::vector<json> segments;
for (const SegmentCommand& segment : binary.segments()) {
JsonVisitor visitor;
visitor(segment);
segments.emplace_back(visitor.get());
}
// Symbols
std::vector<json> symbols;
for (const Symbol& sym : binary.symbols()) {
JsonVisitor visitor;
visitor(sym);
symbols.emplace_back(visitor.get());
}
// Relocations
std::vector<json> relocations;
for (const Relocation& r : binary.relocations()) {
JsonVisitor visitor;
visitor(r);
relocations.emplace_back(visitor.get());
}
std::vector<json> libraries;
for (const DylibCommand& lib : binary.libraries()) {
JsonVisitor visitor;
visitor(lib);
libraries.emplace_back(visitor.get());
}
node_["header"] = header_visitor.get();
node_["sections"] = sections;
node_["segments"] = segments;
node_["symbols"] = symbols;
node_["relocations"] = relocations;
node_["libraries"] = libraries;
process_command<UUIDCommand>(node_, binary, "uuid");
process_command<MainCommand>(node_, binary, "main_command");
process_command<DylinkerCommand>(node_, binary, "dylinker");
process_command<DyldInfo>(node_, binary, "dyld_info");
process_command<FunctionStarts>(node_, binary, "function_starts");
process_command<SourceVersion>(node_, binary, "source_version");
process_command<VersionMin>(node_, binary, "version_min");
process_command<ThreadCommand>(node_, binary, "thread_command");
process_command<RPathCommand>(node_, binary, "rpath");
process_command<Routine>(node_, binary, "routine");
process_command<SymbolCommand>(node_, binary, "symbol_command");
process_command<DynamicSymbolCommand>(node_, binary, "dynamic_symbol_command");
process_command<CodeSignature>(node_, binary, "code_signature");
process_command<DataInCode>(node_, binary, "data_in_code");
process_command<EncryptionInfo>(node_, binary, "encryption_info");
process_command<BuildVersion>(node_, binary, "build_verison");
}
void JsonVisitor::visit(const Header& header) {
std::vector<json> flags;
for (Header::FLAGS f : header.flags_list()) {
flags.emplace_back(to_string(f));
}
node_["magic"] = to_string(header.magic());
node_["cpu_type"] = to_string(header.cpu_type());
node_["cpu_subtype"] = header.cpu_subtype();
node_["file_type"] = to_string(header.file_type());
node_["nb_cmds"] = header.nb_cmds();
node_["sizeof_cmds"] = header.sizeof_cmds();
node_["reserved"] = header.reserved();
node_["flags"] = flags;
}
void JsonVisitor::visit(const LoadCommand& cmd) {
node_["command"] = to_string(cmd.command());
node_["command_size"] = cmd.size();
node_["command_offset"] = cmd.command_offset();
node_["data_hash"] = LIEF::hash(cmd.data());
}
void JsonVisitor::visit(const UUIDCommand& uuid) {
visit(*uuid.as<LoadCommand>());
node_["uuid"] = uuid.uuid();
}
void JsonVisitor::visit(const SymbolCommand& symbol) {
visit(*symbol.as<LoadCommand>());
node_["symbol_offset"] = symbol.symbol_offset();
node_["numberof_symbols"] = symbol.numberof_symbols();
node_["strings_offset"] = symbol.strings_offset();
node_["strings_size"] = symbol.strings_size();
}
void JsonVisitor::visit(const SegmentCommand& segment) {
std::vector<json> sections;
for (const Section& section : segment.sections()) {
sections.emplace_back(section.name());
}
visit(*segment.as<LoadCommand>());
node_["virtual_address"] = segment.virtual_address();
node_["virtual_size"] = segment.virtual_size();
node_["file_size"] = segment.file_size();
node_["file_offset"] = segment.file_offset();
node_["max_protection"] = segment.max_protection();
node_["init_protection"] = segment.init_protection();
node_["numberof_sections"] = segment.numberof_sections();
node_["flags"] = segment.flags();
node_["sections"] = sections;
node_["content_hash"] = LIEF::hash(segment.content());
}
void JsonVisitor::visit(const Section& section) {
std::vector<json> flags;
for (Section::FLAGS f : section.flags_list()) {
flags.emplace_back(to_string(f));
}
node_["name"] = section.name();
node_["virtual_address"] = section.virtual_address();
node_["offset"] = section.offset();
node_["size"] = section.size();
node_["alignment"] = section.alignment();
node_["relocation_offset"] = section.relocation_offset();
node_["numberof_relocations"] = section.numberof_relocations();
node_["flags"] = section.flags();
node_["type"] = to_string(section.type());
node_["reserved1"] = section.reserved1();
node_["reserved2"] = section.reserved2();
node_["reserved3"] = section.reserved3();
node_["content_hash"] = LIEF::hash(section.content());
}
void JsonVisitor::visit(const MainCommand& maincmd) {
visit(*maincmd.as<LoadCommand>());
node_["entrypoint"] = maincmd.entrypoint();
node_["stack_size"] = maincmd.stack_size();
}
void JsonVisitor::visit(const NoteCommand& note) {
visit(*note.as<LoadCommand>());
}
void JsonVisitor::visit(const DynamicSymbolCommand& dynamic_symbol) {
visit(*dynamic_symbol.as<LoadCommand>());
node_["idx_local_symbol"] = dynamic_symbol.idx_local_symbol();
node_["nb_local_symbols"] = dynamic_symbol.nb_local_symbols();
node_["idx_external_define_symbol"] =
dynamic_symbol.idx_external_define_symbol();
node_["nb_external_define_symbols"] =
dynamic_symbol.nb_external_define_symbols();
node_["idx_undefined_symbol"] = dynamic_symbol.idx_undefined_symbol();
node_["nb_undefined_symbols"] = dynamic_symbol.nb_undefined_symbols();
node_["toc_offset"] = dynamic_symbol.toc_offset();
node_["nb_toc"] = dynamic_symbol.nb_toc();
node_["module_table_offset"] = dynamic_symbol.module_table_offset();
node_["nb_module_table"] = dynamic_symbol.nb_module_table();
node_["external_reference_symbol_offset"] =
dynamic_symbol.external_reference_symbol_offset();
node_["nb_external_reference_symbols"] =
dynamic_symbol.nb_external_reference_symbols();
node_["indirect_symbol_offset"] = dynamic_symbol.indirect_symbol_offset();
node_["nb_indirect_symbols"] = dynamic_symbol.nb_indirect_symbols();
node_["external_relocation_offset"] =
dynamic_symbol.external_relocation_offset();
node_["nb_external_relocations"] = dynamic_symbol.nb_external_relocations();
node_["local_relocation_offset"] = dynamic_symbol.local_relocation_offset();
node_["nb_local_relocations"] = dynamic_symbol.nb_local_relocations();
}
void JsonVisitor::visit(const DylinkerCommand& dylinker) {
visit(*dylinker.as<LoadCommand>());
node_["name"] = dylinker.name();
}
void JsonVisitor::visit(const DylibCommand& dylib) {
visit(*dylib.as<LoadCommand>());
node_["name"] = dylib.name();
node_["timestamp"] = dylib.timestamp();
node_["current_version"] = dylib.current_version();
node_["compatibility_version"] = dylib.compatibility_version();
}
void JsonVisitor::visit(const ThreadCommand& threadcmd) {
visit(*threadcmd.as<LoadCommand>());
node_["flavor"] = threadcmd.flavor();
node_["count"] = threadcmd.count();
node_["pc"] = threadcmd.pc();
}
void JsonVisitor::visit(const RPathCommand& rpath) {
visit(*rpath.as<LoadCommand>());
node_["path"] = rpath.path();
}
void JsonVisitor::visit(const Routine& routine) {
visit(*routine.as<LoadCommand>());
node_["init_address"] = routine.init_address();
node_["init_module"] = routine.init_module();
node_["reserved1"] = routine.reserved1();
node_["reserved2"] = routine.reserved2();
node_["reserved3"] = routine.reserved3();
node_["reserved4"] = routine.reserved4();
node_["reserved5"] = routine.reserved5();
node_["reserved6"] = routine.reserved6();
}
void JsonVisitor::visit(const Symbol& symbol) {
node_["value"] = symbol.value();
node_["size"] = symbol.size();
node_["name"] = symbol.name();
node_["type"] = symbol.type();
node_["numberof_sections"] = symbol.numberof_sections();
node_["description"] = symbol.description();
node_["origin"] = to_string(symbol.origin());
node_["is_external"] = symbol.is_external();
if (symbol.has_export_info()) {
JsonVisitor v;
v(*symbol.export_info());
node_["export_info"] = v.get();
}
if (symbol.has_binding_info()) {
JsonVisitor v;
v(*symbol.binding_info());
node_["binding_info"] = v.get();
}
}
void JsonVisitor::visit(const Relocation& relocation) {
node_["is_pc_relative"] = relocation.is_pc_relative();
node_["architecture"] = to_string(relocation.architecture());
node_["origin"] = to_string(relocation.origin());
if (relocation.has_symbol()) {
node_["symbol"] = relocation.symbol()->name();
}
if (relocation.has_section()) {
node_["section"] = relocation.section()->name();
}
if (relocation.has_segment()) {
node_["segment"] = relocation.segment()->name();
}
}
void JsonVisitor::visit(const RelocationObject& robject) {
visit(*robject.as<Relocation>());
node_["value"] = robject.value();
node_["is_scattered"] = robject.is_scattered();
}
void JsonVisitor::visit(const RelocationDyld& rdyld) {
visit(*rdyld.as<Relocation>());
}
void JsonVisitor::visit(const RelocationFixup& fixup) {
visit(*fixup.as<Relocation>());
node_["target"] = fixup.target();
}
void JsonVisitor::visit(const BindingInfo& binding) {
node_["address"] = binding.address();
node_["library_ordinal"] = binding.library_ordinal();
node_["addend"] = binding.addend();
node_["is_weak_import"] = binding.is_weak_import();
if (binding.has_symbol()) {
node_["symbol"] = binding.symbol()->name();
}
if (binding.has_segment()) {
node_["segment"] = binding.segment()->name();
}
if (binding.has_library()) {
node_["library"] = binding.library()->name();
}
}
void JsonVisitor::visit(const DyldBindingInfo& binding) {
visit(*binding.as<BindingInfo>());
node_["binding_class"] = to_string(binding.binding_class());
node_["binding_type"] = to_string(binding.binding_type());
node_["original_offset"] = binding.original_offset();
}
void JsonVisitor::visit(const ChainedBindingInfo& binding) {
visit(*binding.as<BindingInfo>());
node_["format"] = to_string(binding.format());
}
void JsonVisitor::visit(const DyldExportsTrie& trie) {
visit(*trie.as<LoadCommand>());
node_["data_offset"] = trie.data_offset();
node_["data_size"] = trie.data_size();
}
void JsonVisitor::visit(const ExportInfo& einfo) {
node_["flags"] = einfo.flags();
node_["address"] = einfo.address();
if (einfo.has_symbol()) {
node_["symbol"] = einfo.symbol()->name();
}
}
void JsonVisitor::visit(const FunctionStarts& fs) {
visit(*fs.as<LoadCommand>());
node_["data_offset"] = fs.data_offset();
node_["data_size"] = fs.data_size();
node_["functions"] = fs.functions();
}
void JsonVisitor::visit(const CodeSignature& cs) {
visit(*cs.as<LoadCommand>());
node_["data_offset"] = cs.data_offset();
node_["data_size"] = cs.data_size();
}
void JsonVisitor::visit(const DataInCode& dic) {
visit(*dic.as<LoadCommand>());
std::vector<json> entries;
for (const DataCodeEntry& e : dic.entries()) {
JsonVisitor v;
v(e);
entries.emplace_back(v.get());
}
node_["data_offset"] = dic.data_offset();
node_["data_size"] = dic.data_size();
node_["entries"] = entries;
}
void JsonVisitor::visit(const DataCodeEntry& dce) {
node_["offset"] = dce.offset();
node_["length"] = dce.length();
node_["type"] = to_string(dce.type());
}
void JsonVisitor::visit(const SourceVersion& sv) {
visit(*sv.as<LoadCommand>());
node_["version"] = sv.version();
}
void JsonVisitor::visit(const VersionMin& vmin) {
visit(*vmin.as<LoadCommand>());
node_["version"] = vmin.version();
node_["sdk"] = vmin.sdk();
}
void JsonVisitor::visit(const UnknownCommand& ukn) {
visit(*ukn.as<LoadCommand>());
node_["original_command"] = ukn.original_command();
}
void JsonVisitor::visit(const SegmentSplitInfo& ssi) {
visit(*ssi.as<LoadCommand>());
node_["data_offset"] = ssi.data_offset();
node_["data_size"] = ssi.data_size();
}
void JsonVisitor::visit(const SubFramework& sf) {
visit(*sf.as<LoadCommand>());
node_["umbrella"] = sf.umbrella();
}
void JsonVisitor::visit(const DyldEnvironment& dv) {
visit(*dv.as<LoadCommand>());
node_["value"] = dv.value();
}
void JsonVisitor::visit(const EncryptionInfo& e) {
visit(*e.as<LoadCommand>());
node_["crypt_offset"] = e.crypt_offset();
node_["crypt_size"] = e.crypt_size();
node_["crypt_id"] = e.crypt_id();
}
void JsonVisitor::visit(const BuildVersion& e) {
visit(*e.as<LoadCommand>());
node_["platform"] = to_string(e.platform());
node_["minos"] = e.minos();
node_["sdk"] = e.sdk();
std::vector<json> tools;
for (const BuildToolVersion& toolv : e.tools()) {
JsonVisitor v;
v(toolv);
tools.emplace_back(v.get());
}
node_["tools"] = tools;
}
void JsonVisitor::visit(const BuildToolVersion& e) {
node_["tool"] = to_string(e.tool());
node_["version"] = e.version();
}
void JsonVisitor::visit(const FilesetCommand& e) {
node_["name"] = e.name();
node_["file_offset"] = e.file_offset();
node_["virtual_address"] = e.virtual_address();
}
void JsonVisitor::visit(const CodeSignatureDir& e) {
node_["data_size"] = e.data_size();
node_["data_offset"] = e.data_offset();
}
void JsonVisitor::visit(const LinkerOptHint& e) {
node_["data_size"] = e.data_size();
node_["data_offset"] = e.data_offset();
}
void JsonVisitor::visit(const TwoLevelHints& e) {
auto it_hints = e.hints();
std::vector<uint32_t> hints = {it_hints.begin(), it_hints.end()};
node_["offset"] = e.offset();
node_["hints"] = hints;
}
} // namespace LIEF::MachO