From 31a9d1ddca710d05e9b040ebbb7f2b27bfb2d04c Mon Sep 17 00:00:00 2001 From: Obriv Mostov Date: Thu, 3 Apr 2025 23:35:59 +0700 Subject: [PATCH] [MachoView] Add support of __init_offsets --- view/macho/machoview.cpp | 73 ++++++++++++++++++++++++++++------------ view/macho/machoview.h | 1 + 2 files changed, 52 insertions(+), 22 deletions(-) diff --git a/view/macho/machoview.cpp b/view/macho/machoview.cpp index 4b932b5ab..42893445f 100644 --- a/view/macho/machoview.cpp +++ b/view/macho/machoview.cpp @@ -448,7 +448,7 @@ MachOHeader MachoView::HeaderForAddress(BinaryView* data, uint64_t address, bool sect.flags, sect.reserved1, sect.reserved2); - if (!strncmp(sect.sectname, "__mod_init_func", 15)) + if (!strncmp(sect.sectname, "__mod_init_func", 15) || !strncmp(sect.sectname, "__init_offsets", 14)) header.moduleInitSections.push_back(sect); if ((sect.flags & (S_ATTR_SELF_MODIFYING_CODE | S_SYMBOL_STUBS)) == (S_ATTR_SELF_MODIFYING_CODE | S_SYMBOL_STUBS)) header.symbolStubSections.push_back(sect); @@ -551,7 +551,7 @@ MachOHeader MachoView::HeaderForAddress(BinaryView* data, uint64_t address, bool sect.reserved1, sect.reserved2, sect.reserved3); - if (!strncmp(sect.sectname, "__mod_init_func", 15)) + if (!strncmp(sect.sectname, "__mod_init_func", 15) || !strncmp(sect.sectname, "__init_offsets", 14)) header.moduleInitSections.push_back(sect); if ((sect.flags & (S_ATTR_SELF_MODIFYING_CODE | S_SYMBOL_STUBS)) == (S_ATTR_SELF_MODIFYING_CODE | S_SYMBOL_STUBS)) header.symbolStubSections.push_back(sect); @@ -1640,7 +1640,7 @@ bool MachoView::InitializeHeader(MachOHeader& header, bool isMainHeader, uint64_ string type; BNSectionSemantics semantics = DefaultSectionSemantics; - switch (header.sections[i].flags & 0xff) + switch (header.sections[i].flags & SECTION_TYPE) { case S_REGULAR: if (header.sections[i].flags & S_ATTR_PURE_INSTRUCTIONS) @@ -1731,6 +1731,10 @@ bool MachoView::InitializeHeader(MachOHeader& header, bool isMainHeader, uint64_ case S_THREAD_LOCAL_INIT_FUNCTION_POINTERS: type = "THREAD_LOCAL_INIT_FUNCTION_POINTERS"; break; + case S_INIT_FUNC_OFFSETS: + type = "INIT_FUNC_OFFSETS"; + semantics = ReadOnlyDataSectionSemantics; + break; default: type = "UNKNOWN"; break; @@ -1897,30 +1901,55 @@ bool MachoView::InitializeHeader(MachOHeader& header, bool isMainHeader, uint64_ if (find(threadStarts.begin(), threadStarts.end(), moduleInitSection.offset) != threadStarts.end()) continue; - // The mod_init section contains a list of function pointers called at initialization - // if we don't have a defined entrypoint then use the first one in the list as the entrypoint size_t i = 0; reader.Seek(moduleInitSection.offset); - for (; i < (moduleInitSection.size / m_addressSize); i++) + + if (!strncmp(moduleInitSection.sectname, "__mod_init_func", 15)) + { + // The mod_init section contains a list of function pointers called at initialization + // if we don't have a defined entrypoint then use the first one in the list as the entrypoint + for (; i < (moduleInitSection.size / m_addressSize); i++) + { + uint64_t target = (m_addressSize == 4) ? reader.Read32() : reader.Read64(); + target += m_imageBaseAdjustment; + if (m_header.ident.filetype == MH_FILESET) + { + // FIXME: This isn't a super robust way of detagging, + // should look into xnu source and the tools used to build this cache (if they're public) + // and see if anything better can be done + + // mask out top 8 bits + uint64_t tag = 0xFFFFFFFF00000000 & header.textBase; + // and combine them with bottom 8 of the original entry + target = tag | (target & 0xFFFFFFFF); + } + Ref targetPlatform = GetDefaultPlatform()->GetAssociatedPlatformByAddress(target); + auto name = "mod_init_func_" + to_string(modInitFuncCnt++); + AddEntryPointForAnalysis(targetPlatform, target); + auto symbol = new Symbol(FunctionSymbol, name, target, GlobalBinding); + DefineAutoSymbol(symbol); + } + } + else if (!strncmp(moduleInitSection.sectname, "__init_offsets", 14)) { - uint64_t target = (m_addressSize == 4) ? reader.Read32() : reader.Read64(); - target += m_imageBaseAdjustment; - if (m_header.ident.filetype == MH_FILESET) + // The init_offsets section contains a list of 32-bit RVA offsets to functions called at initialization + // if we don't have a defined entrypoint then use the first one in the list as the entrypoint + for (; i < (moduleInitSection.size / 4); i++) { - // FIXME: This isn't a super robust way of detagging, - // should look into xnu source and the tools used to build this cache (if they're public) - // and see if anything better can be done - - // mask out top 8 bits - uint64_t tag = 0xFFFFFFFF00000000 & header.textBase; - // and combine them with bottom 8 of the original entry - target = tag | (target & 0xFFFFFFFF); + uint64_t target = reader.Read32(); + target += header.textBase; + Ref targetPlatform = GetDefaultPlatform()->GetAssociatedPlatformByAddress(target); + auto name = "mod_init_func_" + to_string(modInitFuncCnt++); + AddEntryPointForAnalysis(targetPlatform, target); + auto symbol = new Symbol(FunctionSymbol, name, target, GlobalBinding); + DefineAutoSymbol(symbol); + + // FIXME: i don't know how to define proper pointer type at this stage of analysis + Ref pointerVar = TypeBuilder::PointerType(4, Type::VoidType()) + .SetPointerBase(RelativeToConstantPointerBaseType, header.textBase) + .Finalize(); + DefineDataVariable(GetStart() + reader.GetOffset() - 4, pointerVar); } - Ref targetPlatform = GetDefaultPlatform()->GetAssociatedPlatformByAddress(target); - auto name = "mod_init_func_" + to_string(modInitFuncCnt++); - AddEntryPointForAnalysis(targetPlatform, target); - auto symbol = new Symbol(FunctionSymbol, name, target, GlobalBinding); - DefineAutoSymbol(symbol); } } diff --git a/view/macho/machoview.h b/view/macho/machoview.h index 787ae36bf..2e467eb00 100644 --- a/view/macho/machoview.h +++ b/view/macho/machoview.h @@ -144,6 +144,7 @@ typedef int vm_prot_t; #define S_THREAD_LOCAL_VARIABLES 0x13 #define S_THREAD_LOCAL_VARIABLE_POINTERS 0x14 #define S_THREAD_LOCAL_INIT_FUNCTION_POINTERS 0x15 +#define S_INIT_FUNC_OFFSETS 0x16 //Mach-O Commands #define LC_REQ_DYLD 0x80000000