diff options
| author | Mason Reed <mason@vector35.com> | 2025-04-13 00:47:36 -0400 |
|---|---|---|
| committer | Mason Reed <mason@vector35.com> | 2025-04-14 03:20:51 -0400 |
| commit | ea47d4c85e78533ea7e88adc442159414feb3f7f (patch) | |
| tree | 801cd657bf7872d02cb783f8ee0f25b3f5ecad1c /view/sharedcache/core/MachOProcessor.cpp | |
| parent | 83dc0ef0eea5face59d8a58251f78f32f3e6c914 (diff) | |
[SharedCache] Apply .symbols file information when applying an image
This improves symbol recovery drastically on newer shared caches
Related PR: https://github.com/Vector35/binaryninja-api/pull/6210
Diffstat (limited to 'view/sharedcache/core/MachOProcessor.cpp')
| -rw-r--r-- | view/sharedcache/core/MachOProcessor.cpp | 67 |
1 files changed, 57 insertions, 10 deletions
diff --git a/view/sharedcache/core/MachOProcessor.cpp b/view/sharedcache/core/MachOProcessor.cpp index fdb56516..c6e2c288 100644 --- a/view/sharedcache/core/MachOProcessor.cpp +++ b/view/sharedcache/core/MachOProcessor.cpp @@ -17,7 +17,7 @@ SharedCacheMachOProcessor::SharedCacheMachOProcessor(Ref<BinaryView> view, std:: } } -void SharedCacheMachOProcessor::ApplyHeader(SharedCacheMachOHeader& header) +void SharedCacheMachOProcessor::ApplyHeader(const SharedCache& cache, SharedCacheMachOHeader& header) { auto typeLibraryFromName = [&](const std::string& name) -> Ref<TypeLibrary> { // Check to see if we have already loaded the type library. @@ -32,13 +32,16 @@ void SharedCacheMachOProcessor::ApplyHeader(SharedCacheMachOHeader& header) // Add a section for the header itself. std::string headerSection = fmt::format("{}::__macho_header", header.identifierPrefix); - // TODO: Support mach_header (non 64bit) - uint64_t headerSectionSize = sizeof(mach_header_64) + header.ident.sizeofcmds; + uint64_t machHeaderSize = m_vm->GetAddressSize() == 8 ? sizeof(mach_header_64) : sizeof(mach_header); + uint64_t headerSectionSize = machHeaderSize + header.ident.sizeofcmds; m_view->AddUserSection(headerSection, header.textBase, headerSectionSize, ReadOnlyDataSectionSemantics); ApplyHeaderSections(header); ApplyHeaderDataVariables(header); + // Pull the available type library for the image we are loading, so we can apply known types. + auto typeLib = typeLibraryFromName(header.installName); + if (header.linkeditPresent && m_vm->IsAddressMapped(header.linkeditSegment.vmaddr)) { if (m_applyFunctions && header.functionStartsPresent) @@ -49,18 +52,16 @@ void SharedCacheMachOProcessor::ApplyHeader(SharedCacheMachOHeader& header) m_view->AddFunctionForAnalysis(targetPlatform, func, false); } - // Pull the available type library for the image we are loading, so we can apply known types. - auto typeLib = typeLibraryFromName(header.installName); m_view->BeginBulkModifySymbols(); - // TODO: Why does this need to only happen in linkeditSegment? // Apply symbols from symbol table. if (header.symtab.symoff != 0) { - // Mach-O View symtab processing with - // a ton of stuff cut out so it can work // NOTE: This table is read relative to the link edit segment file base. - const auto symbols = header.ReadSymbolTable(*m_view, *m_vm); + // NOTE: This does not handle the shared .symbols cache entry symbols, that is the responsibility of the caller. + TableInfo symbolInfo = { header.GetLinkEditFileBase() + header.symtab.symoff, header.symtab.nsyms }; + TableInfo stringInfo = { header.GetLinkEditFileBase() + header.symtab.stroff, header.symtab.strsize }; + const auto symbols = header.ReadSymbolTable(*m_vm, symbolInfo, stringInfo); for (const auto& sym : symbols) { auto [symbol, symbolType] = sym.GetBNSymbolAndType(*m_view); @@ -72,7 +73,6 @@ void SharedCacheMachOProcessor::ApplyHeader(SharedCacheMachOHeader& header) if (header.exportTriePresent) { // NOTE: This table is read relative to the link edit segment file base. - // TODO: Remove this and use the m_symbols in the cache? const auto exportSymbols = header.ReadExportSymbolTrie(*m_vm); for (const auto& sym : exportSymbols) { @@ -82,6 +82,53 @@ void SharedCacheMachOProcessor::ApplyHeader(SharedCacheMachOHeader& header) } m_view->EndBulkModifySymbols(); } + + // Apply symbols from the .symbols cache files. + for (const auto &entry: cache.GetEntries()) + { + // NOTE: We check addr size as we only support 64bit .symbols files currently. + if (entry.GetType() != CacheEntryType::Symbols && m_vm->GetAddressSize() == 8) + continue; + const auto& entryHeader = entry.GetHeader(); + + // This is where we get the symbol and string table information from in the .symbols file. + dyld_cache_local_symbols_info localSymbolsInfo = {}; + auto localSymbolsInfoAddr = entry.GetMappedAddress(entryHeader.localSymbolsOffset); + if (!localSymbolsInfoAddr.has_value()) + continue; + m_vm->Read(&localSymbolsInfo, *localSymbolsInfoAddr, sizeof(dyld_cache_local_symbols_info)); + + // Read each symbols entry, looking for the current image entry. + uint64_t localEntriesAddr = *localSymbolsInfoAddr + localSymbolsInfo.entriesOffset; + uint64_t localSymbolsAddr = *localSymbolsInfoAddr + localSymbolsInfo.nlistOffset; + uint64_t localStringsAddr = *localSymbolsInfoAddr + localSymbolsInfo.stringsOffset; + + dyld_cache_local_symbols_entry_64 localSymbolsEntry = {}; + for (uint32_t i = 0; i < localSymbolsInfo.entriesCount; i++) + { + m_vm->Read(&localSymbolsEntry, localEntriesAddr + i * sizeof(dyld_cache_local_symbols_entry_64), + sizeof(dyld_cache_local_symbols_entry_64)); + // The dylibOffset is the offset from the cache base address to the image header. + const auto imageAddr = cache.GetBaseAddress() + localSymbolsEntry.dylibOffset; + if (imageAddr == header.textBase) + { + // We have found the entry to read! + // TODO: Support 32bit nlist + uint64_t symbolTableStart = localSymbolsAddr + (localSymbolsEntry.nlistStartIndex * sizeof(nlist_64)); + TableInfo symbolInfo = {symbolTableStart, localSymbolsEntry.nlistCount}; + TableInfo stringInfo = {localStringsAddr, localSymbolsInfo.stringsSize}; + m_view->BeginBulkModifySymbols(); + const auto symbols = header.ReadSymbolTable(*m_vm, symbolInfo, stringInfo); + for (const auto &sym: symbols) + { + auto [symbol, symbolType] = sym.GetBNSymbolAndType(*m_view); + ApplySymbol(m_view, typeLib, symbol, symbolType); + } + m_view->EndBulkModifySymbols(); + break; + } + } + } } uint64_t SharedCacheMachOProcessor::ApplyHeaderSections(SharedCacheMachOHeader& header) |
