Skip to content

Commit edcba92

Browse files
committed
[SharedCache] Split out symbol processing into own function
Split out from https://github.com/WeiN76LQh/binaryninja-api/tree/process-local-symbols
1 parent 9fa3dd7 commit edcba92

File tree

2 files changed

+164
-118
lines changed

2 files changed

+164
-118
lines changed

view/sharedcache/core/SharedCache.cpp

Lines changed: 160 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -2268,6 +2268,152 @@ std::optional<SharedCacheMachOHeader> SharedCache::LoadHeaderForAddress(std::sha
22682268
return header;
22692269
}
22702270

2271+
2272+
void SharedCache::ProcessSymbols(std::shared_ptr<MMappedFileAccessor> file, const SharedCacheMachOHeader& header, uint64_t stringsOffset, size_t stringsSize, uint64_t nlistEntriesOffset, uint32_t nlistCount, uint32_t nlistStartIndex)
2273+
{
2274+
auto addressSize = m_dscView->GetAddressSize();
2275+
auto strings = file->ReadBuffer(stringsOffset, stringsSize);
2276+
2277+
std::vector<Ref<Symbol>> symbolList;
2278+
for (uint64_t i = 0; i < nlistCount; i++)
2279+
{
2280+
uint64_t entryIndex = (nlistStartIndex + i);
2281+
2282+
nlist_64 nlist = {};
2283+
if (addressSize == 4)
2284+
{
2285+
// 32-bit DSC
2286+
struct nlist nlist32 = {};
2287+
file->Read(&nlist, nlistEntriesOffset + (entryIndex * sizeof(nlist32)), sizeof(nlist32));
2288+
nlist.n_strx = nlist32.n_strx;
2289+
nlist.n_type = nlist32.n_type;
2290+
nlist.n_sect = nlist32.n_sect;
2291+
nlist.n_desc = nlist32.n_desc;
2292+
nlist.n_value = nlist32.n_value;
2293+
}
2294+
else
2295+
{
2296+
// 64-bit DSC
2297+
file->Read(&nlist, nlistEntriesOffset + (entryIndex * sizeof(nlist)), sizeof(nlist));
2298+
}
2299+
2300+
auto symbolAddress = nlist.n_value;
2301+
if (((nlist.n_type & N_TYPE) == N_INDR) || symbolAddress == 0)
2302+
continue;
2303+
2304+
if (nlist.n_strx >= stringsSize)
2305+
{
2306+
m_logger->LogError("Symbol entry at index %llu has a string offset of %u which is outside the strings buffer of size %llu for file %s", entryIndex, nlist.n_strx, stringsSize, file->Path().c_str());
2307+
continue;
2308+
}
2309+
2310+
std::string symbolName((char*)strings.GetDataAt(nlist.n_strx));
2311+
if (symbolName == "<redacted>")
2312+
continue;
2313+
2314+
std::optional<BNSymbolType> symbolType;
2315+
if ((nlist.n_type & N_TYPE) == N_SECT && nlist.n_sect > 0 && (size_t)(nlist.n_sect - 1) < header.sections.size())
2316+
{
2317+
symbolType = DataSymbol;
2318+
}
2319+
else if ((nlist.n_type & N_TYPE) == N_ABS)
2320+
{
2321+
symbolType = DataSymbol;
2322+
}
2323+
else if ((nlist.n_type & N_EXT))
2324+
{
2325+
symbolType = ExternalSymbol;
2326+
}
2327+
2328+
if (!symbolType.has_value())
2329+
{
2330+
m_logger->LogError("Symbol %s at address %" PRIx64 " has unknown symbol type", symbolName.c_str(), symbolAddress);
2331+
continue;
2332+
}
2333+
2334+
std::optional<uint32_t> flags;
2335+
for (auto s : header.sections)
2336+
{
2337+
if (s.addr <= symbolAddress && symbolAddress < s.addr + s.size)
2338+
{
2339+
flags = s.flags;
2340+
}
2341+
}
2342+
2343+
if (symbolType != ExternalSymbol)
2344+
{
2345+
if (!flags.has_value())
2346+
{
2347+
m_logger->LogError("Symbol %s at address %" PRIx64 " is not in any section", symbolName.c_str(), symbolAddress);
2348+
continue;
2349+
}
2350+
2351+
if ((flags.value() & S_ATTR_PURE_INSTRUCTIONS) == S_ATTR_PURE_INSTRUCTIONS
2352+
|| (flags.value() & S_ATTR_SOME_INSTRUCTIONS) == S_ATTR_SOME_INSTRUCTIONS)
2353+
symbolType = FunctionSymbol;
2354+
else
2355+
symbolType = DataSymbol;
2356+
}
2357+
if ((nlist.n_desc & N_ARM_THUMB_DEF) == N_ARM_THUMB_DEF)
2358+
symbolAddress++;
2359+
2360+
Ref<Symbol> sym = new Symbol(symbolType.value(), symbolName, symbolAddress, GlobalBinding);
2361+
symbolList.emplace_back(sym);
2362+
}
2363+
2364+
auto symListPtr = std::make_shared<std::vector<Ref<Symbol>>>(symbolList);
2365+
m_modifiedState->symbolInfos.emplace(header.textBase, symListPtr);
2366+
}
2367+
2368+
void SharedCache::ApplySymbol(Ref<BinaryView> view, Ref<TypeLibrary> typeLib, Ref<Symbol> symbol)
2369+
{
2370+
Ref<Function> func = nullptr;
2371+
auto symbolAddress = symbol->GetAddress();
2372+
2373+
if (symbol->GetType() == FunctionSymbol)
2374+
{
2375+
Ref<Platform> targetPlatform = view->GetDefaultPlatform();
2376+
func = view->AddFunctionForAnalysis(targetPlatform, symbolAddress);
2377+
}
2378+
2379+
if (!typeLib)
2380+
{
2381+
// No type library just define the symbol.
2382+
view->DefineAutoSymbol(symbol);
2383+
return;
2384+
}
2385+
2386+
auto type = m_dscView->ImportTypeLibraryObject(typeLib, {symbol->GetFullName()});
2387+
if (type)
2388+
view->DefineAutoSymbolAndVariableOrFunction(view->GetDefaultPlatform(), symbol, type);
2389+
else
2390+
view->DefineAutoSymbol(symbol);
2391+
2392+
if (!func)
2393+
func = view->GetAnalysisFunction(view->GetDefaultPlatform(), symbolAddress);
2394+
if (func)
2395+
{
2396+
if (symbol->GetFullName() == "_objc_msgSend")
2397+
{
2398+
func->SetHasVariableArguments(false);
2399+
}
2400+
else if (symbol->GetFullName().find("_objc_retain_x") != std::string::npos || symbol->GetFullName().find("_objc_release_x") != std::string::npos)
2401+
{
2402+
auto x = symbol->GetFullName().rfind("x");
2403+
auto num = symbol->GetFullName().substr(x + 1);
2404+
2405+
std::vector<BinaryNinja::FunctionParameter> callTypeParams;
2406+
auto cc = m_dscView->GetDefaultArchitecture()->GetCallingConventionByName("apple-arm64-objc-fast-arc-" + num);
2407+
2408+
callTypeParams.push_back({"obj", m_dscView->GetTypeByName({ "id" }), true, BinaryNinja::Variable()});
2409+
2410+
auto funcType = BinaryNinja::Type::FunctionType(m_dscView->GetTypeByName({ "id" }), cc, callTypeParams);
2411+
func->SetUserType(funcType);
2412+
}
2413+
}
2414+
}
2415+
2416+
22712417
void SharedCache::InitializeHeader(
22722418
std::lock_guard<std::mutex>& lock,
22732419
Ref<BinaryView> view, VM* vm, const SharedCacheMachOHeader& header, std::vector<const MemoryRegion*> regionsToLoad)
@@ -2566,132 +2712,29 @@ void SharedCache::InitializeHeader(
25662712
{
25672713
// Mach-O View symtab processing with
25682714
// a ton of stuff cut out so it can work
2569-
25702715
auto reader = vm->MappingAtAddress(header.linkeditSegment.vmaddr).first.fileAccessor->lock();
2571-
// auto symtab = reader->ReadBuffer(header.symtab.symoff, header.symtab.nsyms * sizeof(nlist_64));
2572-
auto strtab = reader->ReadBuffer(header.symtab.stroff, header.symtab.strsize);
2573-
nlist_64 sym;
2574-
memset(&sym, 0, sizeof(sym));
2575-
auto N_TYPE = 0xE; // idk
2576-
std::vector<Ref<Symbol>> symbols;
2577-
symbols.reserve(header.symtab.nsyms);
2578-
2579-
for (size_t i = 0; i < header.symtab.nsyms; i++)
2580-
{
2581-
reader->Read(&sym, header.symtab.symoff + i * sizeof(nlist_64), sizeof(nlist_64));
2582-
if (sym.n_strx >= header.symtab.strsize || ((sym.n_type & N_TYPE) == N_INDR))
2583-
continue;
2584-
2585-
std::string symbol((char*)strtab.GetDataAt(sym.n_strx));
2586-
// BNLogError("%s: 0x%llx", symbol.c_str(), sym.n_value);
2587-
if (symbol == "<redacted>")
2588-
continue;
2589-
2590-
BNSymbolType type = DataSymbol;
2591-
uint32_t flags;
2592-
if ((sym.n_type & N_TYPE) == N_SECT && sym.n_sect > 0 && (size_t)(sym.n_sect - 1) < header.sections.size())
2593-
{}
2594-
else if ((sym.n_type & N_TYPE) == N_ABS)
2595-
{}
2596-
else if ((sym.n_type & 0x1))
2597-
{
2598-
type = ExternalSymbol;
2599-
}
2600-
else
2601-
continue;
2602-
2603-
for (auto s : header.sections)
2604-
{
2605-
if (s.addr < sym.n_value)
2606-
{
2607-
if (s.addr + s.size > sym.n_value)
2608-
{
2609-
flags = s.flags;
2610-
}
2611-
}
2612-
}
2613-
2614-
if (type != ExternalSymbol)
2615-
{
2616-
if ((flags & S_ATTR_PURE_INSTRUCTIONS) == S_ATTR_PURE_INSTRUCTIONS
2617-
|| (flags & S_ATTR_SOME_INSTRUCTIONS) == S_ATTR_SOME_INSTRUCTIONS)
2618-
type = FunctionSymbol;
2619-
else
2620-
type = DataSymbol;
2621-
}
2622-
if ((sym.n_desc & N_ARM_THUMB_DEF) == N_ARM_THUMB_DEF)
2623-
sym.n_value++;
2624-
2625-
Ref<Symbol> symbolObj = new Symbol(type, symbol, sym.n_value, GlobalBinding);
2626-
if (type == FunctionSymbol)
2627-
{
2628-
Ref<Platform> targetPlatform = view->GetDefaultPlatform();
2629-
view->AddFunctionForAnalysis(targetPlatform, sym.n_value);
2630-
}
2631-
if (typeLib)
2632-
{
2633-
auto _type = m_dscView->ImportTypeLibraryObject(typeLib, {symbolObj->GetFullName()});
2634-
if (_type)
2635-
{
2636-
view->DefineAutoSymbolAndVariableOrFunction(view->GetDefaultPlatform(), symbolObj, _type);
2637-
}
2638-
else
2639-
view->DefineAutoSymbol(symbolObj);
2640-
}
2641-
else
2642-
view->DefineAutoSymbol(symbolObj);
2643-
symbols.push_back(std::move(symbolObj));
2644-
}
2645-
m_modifiedState->symbolInfos[header.textBase] = std::make_shared<std::vector<Ref<Symbol>>>(std::move(symbols));
2716+
ProcessSymbols(
2717+
reader,
2718+
header,
2719+
header.symtab.stroff,
2720+
header.symtab.strsize,
2721+
header.symtab.symoff,
2722+
header.symtab.nsyms
2723+
);
26462724
}
26472725

2726+
view->BeginBulkModifySymbols();
2727+
for (const auto& symbol : *m_modifiedState->symbolInfos[header.textBase])
2728+
ApplySymbol(view, typeLib, symbol);
2729+
26482730
if (header.exportTriePresent && header.linkeditPresent && vm->AddressIsMapped(header.linkeditSegment.vmaddr))
26492731
{
26502732
auto symbols = GetExportListForHeader(lock, header, [&]() {
26512733
return vm->MappingAtAddress(header.linkeditSegment.vmaddr).first.fileAccessor->lock();
26522734
});
2653-
if (symbols)
2654-
{
2655-
for (const auto& [symbolAddress, symbol] : *symbols)
2656-
{
2657-
if (typeLib)
2658-
{
2659-
auto type = m_dscView->ImportTypeLibraryObject(typeLib, symbol->GetRawName());
2660-
2661-
if (type)
2662-
{
2663-
view->DefineAutoSymbolAndVariableOrFunction(view->GetDefaultPlatform(), symbol, type);
2664-
}
2665-
else
2666-
view->DefineAutoSymbol(symbol);
2667-
2668-
if (view->GetAnalysisFunction(view->GetDefaultPlatform(), symbolAddress))
2669-
{
2670-
auto func = view->GetAnalysisFunction(view->GetDefaultPlatform(), symbolAddress);
2671-
auto name = symbol->GetFullName();
2672-
if (name == "_objc_msgSend")
2673-
{
2674-
func->SetHasVariableArguments(false);
2675-
}
2676-
else if (name.find("_objc_retain_x") != std::string::npos || name.find("_objc_release_x") != std::string::npos)
2677-
{
2678-
auto x = name.rfind("x");
2679-
auto num = name.substr(x + 1);
26802735

2681-
std::vector<BinaryNinja::FunctionParameter> callTypeParams;
2682-
auto cc = m_dscView->GetDefaultArchitecture()->GetCallingConventionByName("apple-arm64-objc-fast-arc-" + num);
2683-
2684-
callTypeParams.push_back({"obj", m_dscView->GetTypeByName({ "id" }), true, BinaryNinja::Variable()});
2685-
2686-
auto funcType = BinaryNinja::Type::FunctionType(m_dscView->GetTypeByName({ "id" }), cc, callTypeParams);
2687-
func->SetUserType(funcType);
2688-
}
2689-
}
2690-
}
2691-
else
2692-
view->DefineAutoSymbol(symbol);
2693-
}
2694-
}
2736+
for (const auto& [symbolAddress, symbol] : *symbols)
2737+
ApplySymbol(view, typeLib, symbol);
26952738
}
26962739
view->EndBulkModifySymbols();
26972740

view/sharedcache/core/SharedCache.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -643,7 +643,10 @@ namespace SharedCacheCore {
643643
std::shared_ptr<MMappedFileAccessor> linkeditFile, const SharedCacheMachOHeader& header);
644644
std::shared_ptr<std::unordered_map<uint64_t, Ref<Symbol>>> GetExportListForHeader(std::lock_guard<std::mutex>&, const SharedCacheMachOHeader& header,
645645
std::function<std::shared_ptr<MMappedFileAccessor>()> provideLinkeditFile, bool* didModifyExportList = nullptr);
646-
std::shared_ptr<std::unordered_map<uint64_t, Ref<Symbol>>> GetExistingExportListForBaseAddress(std::lock_guard<std::mutex>&, uint64_t baseAddress) const;
646+
std::shared_ptr<std::unordered_map<uint64_t, Ref<Symbol>>> GetExistingExportListForBaseAddress(std::lock_guard<std::mutex>&, uint64_t baseAddress) const;
647+
void ProcessSymbols(std::shared_ptr<MMappedFileAccessor> file, const SharedCacheMachOHeader& header,
648+
uint64_t stringsOffset, size_t stringsSize, uint64_t nlistEntriesOffset, uint32_t nlistCount, uint32_t nlistStartIndex = 0);
649+
void ApplySymbol(Ref<BinaryView> view, Ref<TypeLibrary> typeLib, Ref<Symbol> symbol);
647650

648651
void ProcessAllObjCSections(std::lock_guard<std::mutex>&);
649652
bool LoadImageWithInstallName(std::lock_guard<std::mutex>&, std::string installName, bool skipObjC);

0 commit comments

Comments
 (0)