Skip to content

Commit 37da709

Browse files
committed
[MachO] Improve library tracking for imported symbols
1 parent 877b01a commit 37da709

2 files changed

Lines changed: 59 additions & 22 deletions

File tree

view/macho/machoview.cpp

Lines changed: 56 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ static MachoViewType* g_machoViewType = nullptr;
2626

2727
namespace {
2828

29+
// Pseudo-library names used when an import's two-level-namespace ordinal refers to a special
30+
// dyld lookup mode rather than a concrete LC_LOAD_DYLIB entry.
31+
constexpr std::string_view kPseudoLibraryMainExecutable = "<main executable>";
32+
constexpr std::string_view kPseudoLibraryFlatLookup = "<flat lookup>";
33+
constexpr std::string_view kPseudoLibraryWeakLookup = "<weak lookup>";
34+
2935
string CommandToString(uint32_t lcCommand)
3036
{
3137
switch(lcCommand)
@@ -2286,11 +2292,13 @@ bool MachoView::InitializeHeader(MachOHeader& header, bool isMainHeader, uint64_
22862292
BulkSymbolModification bulkSymbolModification(this);
22872293
m_symbolQueue = new SymbolQueue();
22882294

2295+
std::unordered_map<std::string, std::string> symbolLibraryMapping;
2296+
22892297
try
22902298
{
22912299
// Add functions for all function symbols
22922300
m_logger->LogDebug("Parsing symbol table\n");
2293-
ParseSymbolTable(reader, header, header.symtab, indirectSymbols, objcProcessor.get());
2301+
ParseSymbolTable(reader, header, header.symtab, indirectSymbols, objcProcessor.get(), symbolLibraryMapping);
22942302
}
22952303
catch (std::exception&)
22962304
{
@@ -2314,7 +2322,6 @@ bool MachoView::InitializeHeader(MachOHeader& header, bool isMainHeader, uint64_
23142322
objcProcessor->AddRelocatedPointer(relocationLocation, slidTarget);
23152323
}
23162324

2317-
Ref<Metadata> symbolToLibraryMapping = new Metadata(KeyValueDataType);
23182325
for (auto& [relocation, name, ordinal] : header.bindingRelocations)
23192326
{
23202327
if (auto symbol = ResolveBindSymbol(this, header, name, ordinal); symbol)
@@ -2328,10 +2335,27 @@ bool MachoView::InitializeHeader(MachOHeader& header, bool isMainHeader, uint64_
23282335
m_logger->LogErrorF("Failed to find symbol {:?} for bind at {:#x} (ordinal: {})", name, relocation.address, ordinal);
23292336
}
23302337

2338+
string libName;
23312339
if (ordinal > 0 && ordinal - 1 < header.dylibs.size())
2332-
symbolToLibraryMapping->SetValueForKey(name, new Metadata(header.dylibs[ordinal - 1].first));
2340+
libName = header.dylibs[ordinal - 1].first;
2341+
else if (ordinal == BindSpecialDylibMainExecutable)
2342+
libName = kPseudoLibraryMainExecutable;
2343+
else if (ordinal == BindSpecialDylibFlatLookup)
2344+
libName = kPseudoLibraryFlatLookup;
2345+
else if (ordinal == BindSpecialDylibWeakLookup)
2346+
libName = kPseudoLibraryWeakLookup;
2347+
2348+
if (!libName.empty())
2349+
{
2350+
if (!GetExternalLibrary(libName))
2351+
AddExternalLibrary(libName, {}, true);
2352+
symbolLibraryMapping[name] = libName;
2353+
}
23332354
}
23342355

2356+
Ref<Metadata> symbolToLibraryMapping = new Metadata(KeyValueDataType);
2357+
for (const auto& [name, libName] : symbolLibraryMapping)
2358+
symbolToLibraryMapping->SetValueForKey(name, new Metadata(libName));
23352359
StoreMetadata("SymbolExternalLibraryMapping", std::move(symbolToLibraryMapping), true);
23362360

23372361
auto relocationHandler = m_arch->GetRelocationHandler("Mach-O");
@@ -3220,7 +3244,8 @@ void MachoView::ParseDynamicTable(BinaryReader& reader, MachOHeader& header, BNS
32203244

32213245

32223246
void MachoView::ParseSymbolTable(BinaryReader& reader, MachOHeader& header, const symtab_command& symtab,
3223-
const vector<uint32_t>& indirectSymbols, MachoObjCProcessor* objcProcessor)
3247+
const vector<uint32_t>& indirectSymbols, MachoObjCProcessor* objcProcessor,
3248+
std::unordered_map<std::string, std::string>& symbolLibraryMapping)
32243249
{
32253250
if (header.ident.filetype == MH_DSYM)
32263251
{
@@ -3359,6 +3384,25 @@ void MachoView::ParseSymbolTable(BinaryReader& reader, MachOHeader& header, cons
33593384
else if ((sym.n_type & N_EXT))
33603385
{
33613386
type = ExternalSymbol;
3387+
3388+
// Record the owning library from the two-level-namespace ordinal in the high
3389+
// byte of n_desc. See GET_LIBRARY_ORDINAL in <mach-o/nlist.h>.
3390+
unsigned libraryOrdinal = (unsigned)(sym.n_desc >> 8) & 0xff;
3391+
string libName;
3392+
if (libraryOrdinal >= 1 && libraryOrdinal <= 0xfd
3393+
&& (size_t)(libraryOrdinal - 1) < header.dylibs.size())
3394+
libName = header.dylibs[libraryOrdinal - 1].first;
3395+
else if (libraryOrdinal == 0xfe) // DYNAMIC_LOOKUP_ORDINAL
3396+
libName = kPseudoLibraryFlatLookup;
3397+
else if (libraryOrdinal == 0xff) // EXECUTABLE_ORDINAL
3398+
libName = kPseudoLibraryMainExecutable;
3399+
3400+
if (!libName.empty())
3401+
{
3402+
if (!GetExternalLibrary(libName))
3403+
AddExternalLibrary(libName, {}, true);
3404+
symbolLibraryMapping[symbol] = libName;
3405+
}
33623406
}
33633407
else
33643408
continue;
@@ -3378,23 +3422,14 @@ void MachoView::ParseSymbolTable(BinaryReader& reader, MachOHeader& header, cons
33783422
auto pointerSymbolIter = pointerSymbols.find(i);
33793423
bool deferred = stubSymbolIter == stubSymbols.end() && pointerSymbolIter == pointerSymbols.end();
33803424

3381-
Ref<Symbol> symbolObj;
3382-
if(header.dysymtab.nlocalsym && i >= header.dysymtab.ilocalsym && i < header.dysymtab.ilocalsym + header.dysymtab.nlocalsym)
3383-
{
3384-
symbolObj = DefineMachoSymbol(type, symbol, sym.n_value, LocalBinding, deferred);
3385-
}
3386-
else if (header.dysymtab.nextdefsym && i >= header.dysymtab.iextdefsym && i < header.dysymtab.iextdefsym + header.dysymtab.nextdefsym)
3387-
{
3388-
symbolObj = DefineMachoSymbol(type, symbol, sym.n_value, GlobalBinding, deferred);
3389-
}
3390-
else if (header.dysymtab.nundefsym && i >= header.dysymtab.iundefsym && i < header.dysymtab.iundefsym + header.dysymtab.nundefsym)
3391-
{
3392-
symbolObj = DefineMachoSymbol(type, symbol, sym.n_value, GlobalBinding, deferred);
3393-
}
3394-
else
3395-
{
3396-
symbolObj = DefineMachoSymbol(type, symbol, sym.n_value, GlobalBinding, deferred);
3397-
}
3425+
BNSymbolBinding binding = GlobalBinding;
3426+
if (header.dysymtab.nlocalsym && i >= header.dysymtab.ilocalsym
3427+
&& i < header.dysymtab.ilocalsym + header.dysymtab.nlocalsym)
3428+
binding = LocalBinding;
3429+
else if (type == ExternalSymbol && (sym.n_desc & N_WEAK_REF))
3430+
binding = WeakBinding;
3431+
3432+
Ref<Symbol> symbolObj = DefineMachoSymbol(type, symbol, sym.n_value, binding, deferred);
33983433

33993434
if (!symbolObj)
34003435
{

view/macho/machoview.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1502,7 +1502,9 @@ namespace BinaryNinja
15021502
void RebaseThreadStarts(BinaryReader& virtualReader, std::vector<uint32_t>& threadStarts, uint64_t stepMultiplier);
15031503
Ref<Symbol> DefineMachoSymbol(
15041504
BNSymbolType type, const std::string& name, uint64_t addr, BNSymbolBinding binding, bool deferred);
1505-
void ParseSymbolTable(BinaryReader& reader, MachOHeader& header, const symtab_command& symtab, const std::vector<uint32_t>& symbolStubsList, MachoObjCProcessor*);
1505+
void ParseSymbolTable(BinaryReader& reader, MachOHeader& header, const symtab_command& symtab,
1506+
const std::vector<uint32_t>& symbolStubsList, MachoObjCProcessor*,
1507+
std::unordered_map<std::string, std::string>& symbolLibraryMapping);
15061508
bool IsValidFunctionStart(uint64_t addr);
15071509
void ParseFunctionStarts(Platform* platform, uint64_t textBase, function_starts_command functionStarts);
15081510
bool ParseRelocationEntry(const relocation_info& info, uint64_t start, BNRelocationInfo& result);

0 commit comments

Comments
 (0)