From 25cc02431b61097b2adfc2fbc493b648b0300c3b Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Mon, 10 Mar 2025 11:05:40 -0400 Subject: [SharedCache] Refactor Shared Cache In absence of a better name, this commit refactors the shared cache code. --- view/sharedcache/workflow/SharedCacheWorkflow.cpp | 570 ++++++++++------------ 1 file changed, 259 insertions(+), 311 deletions(-) (limited to 'view/sharedcache/workflow/SharedCacheWorkflow.cpp') diff --git a/view/sharedcache/workflow/SharedCacheWorkflow.cpp b/view/sharedcache/workflow/SharedCacheWorkflow.cpp index c1ee45b7..6587abfe 100644 --- a/view/sharedcache/workflow/SharedCacheWorkflow.cpp +++ b/view/sharedcache/workflow/SharedCacheWorkflow.cpp @@ -15,22 +15,26 @@ #include "thread" #include +#include "ObjCActivity.h" + +using namespace BinaryNinja; using namespace SharedCacheAPI; struct GlobalWorkflowState { - std::mutex imageLoadMutex; + // Mutex to guard against duplicate region/image loads that cause reanalysis. + std::mutex loadMutex; bool autoLoadStubsAndDyldData = true; bool autoLoadObjCStubRequirements = true; }; -static std::unordered_map> globalWorkflowState; -std::shared_mutex globalWorkflowStateMutex; - std::shared_ptr GetGlobalWorkflowState(Ref view) { + static std::shared_mutex globalWorkflowStateMutex; + static std::unordered_map> globalWorkflowState; + std::shared_lock readLock(globalWorkflowStateMutex); - uint64_t viewId = view->GetFile()->GetSessionId(); + const uint64_t viewId = view->GetFile()->GetSessionId(); auto foundState = globalWorkflowState.find(viewId); if (foundState != globalWorkflowState.end()) return foundState->second; @@ -39,398 +43,342 @@ std::shared_ptr GetGlobalWorkflowState(Ref view std::unique_lock writeLock(globalWorkflowStateMutex); globalWorkflowState[viewId] = std::make_shared(); Ref settings = view->GetLoadSettings(VIEW_NAME); + bool autoLoadStubsAndDyldData = true; if (settings && settings->Contains("loader.dsc.autoLoadStubsAndDyldData")) - { autoLoadStubsAndDyldData = settings->Get("loader.dsc.autoLoadStubsAndDyldData", view); - } globalWorkflowState[viewId]->autoLoadStubsAndDyldData = autoLoadStubsAndDyldData; + bool autoLoadObjC = true; if (settings && settings->Contains("loader.dsc.autoLoadObjCStubRequirements")) - { autoLoadObjC = settings->Get("loader.dsc.autoLoadObjCStubRequirements", view); - } globalWorkflowState[viewId]->autoLoadObjCStubRequirements = autoLoadObjC; - return globalWorkflowState[viewId]; -} - -std::vector splitSelector(const std::string& selector) { - std::vector components; - std::istringstream stream(selector); - std::string component; - - while (std::getline(stream, component, ':')) { - if (!component.empty()) { - components.push_back(component); - } - } - - return components; + return globalWorkflowState[viewId]; } -std::vector generateArgumentNames(const std::vector& components) { - std::vector argumentNames; - - for (const std::string& component : components) { - size_t startPos = component.find_last_of(" "); - std::string argumentName = (startPos == std::string::npos) ? component : component.substr(startPos + 1); - argumentNames.push_back(argumentName); - } - - return argumentNames; +// TODO: Add a type library cache to this workflow. (so we dont take global file lock) +Ref TypeLibraryFromName(BinaryView& view, const std::string& name) { + // Check to see if we have already loaded the type library. + if (auto typeLib = view.GetTypeLibrary(name)) + return typeLib; + + // TODO: Use the functions platform instead. + auto typeLibs = view.GetDefaultPlatform()->GetTypeLibrariesByName(name); + if (!typeLibs.empty()) + return typeLibs.front(); + return nullptr; } +void IdentifyStub(BinaryView& view, const SharedCacheController& controller, uint64_t stubFuncAddr, uint64_t symbolAddr) { + static const char* STUB_PREFIX = "j_"; + // TODO: Just check for if there is a user symbol instead? + // TODO: ^ well we really should be using an auto symbol no? + // Check to see if there is a symbol already at the target. If so we should just stop. + if (symbolAddr == stubFuncAddr) + if (const auto targetSymbol = view.GetSymbolByAddress(stubFuncAddr)) + if (targetSymbol->GetShortName().find(STUB_PREFIX) != std::string::npos) + return; -void ProcessStubImageCall(const std::shared_ptr &workflowState, Ref cache, Ref func, - const Ref
& section, uint64_t target) -{ - if (!workflowState->imageLoadMutex.try_lock()) - return; - - auto view = func->GetView(); - if (!view->IsValidOffset(target)) + // Try and apply a version of the symbol address to the target address + if (symbolAddr != stubFuncAddr) { - if (!cache->GetImageNameForAddress(target).empty()) - cache->LoadImageContainingAddress(target); - else - cache->LoadSectionAtAddress(target); - - // Check to see if there are any functions inside the newly added image. - bool newFunctions = false; - for (const auto §Func : view->GetAnalysisFunctionList()) + if (const auto symbol = view.GetSymbolByAddress(symbolAddr)) { - if (section->GetStart() <= sectFunc->GetStart() && sectFunc->GetStart() < section->GetEnd()) - newFunctions = true; + // A symbol already exists at the source location. Add a stub symbol at `targetLocation` based on the existing symbol. + const auto id = view.BeginUndoActions(); + if (auto targetFunc = view.GetAnalysisFunction(view.GetDefaultPlatform(), stubFuncAddr)) + view.DefineUserSymbol(new Symbol(FunctionSymbol, STUB_PREFIX + symbol->GetShortName(), stubFuncAddr)); + else + view.DefineUserSymbol(new Symbol(symbol->GetType(), STUB_PREFIX + symbol->GetShortName(), stubFuncAddr)); + view.ForgetUndoActions(id); + return; } - - // If there are any new functions we should re-analyze the current function. - if (newFunctions) - func->Reanalyze(); } - workflowState->imageLoadMutex.unlock(); -} - - -void SharedCacheWorkflow::ProcessOffImageCall(Ref ctx, Ref cache, Ref func, - Ref mssa, const MediumLevelILInstruction dest, - bool applySymbolIfFoundToCurrentFunction) -{ - auto bv = func->GetView(); - WorkerPriorityEnqueue([bv=std::move(bv), cache=std::move(cache), dest=dest, func=func, applySymbolIfFoundToCurrentFunction](){ - auto workflowState = GetGlobalWorkflowState(bv); - if (dest.operation != MLIL_CONST_PTR && dest.operation != MLIL_CONST) - return; - if (workflowState->autoLoadStubsAndDyldData && - (cache->GetNameForAddress(dest.GetConstant()).find("dyld_shared_cache_branch_islands") != std::string::npos - || cache->GetNameForAddress(dest.GetConstant()).find("::_stubs") != std::string::npos - ) - ) + // No existing symbol located, try and search through the symbols of the cache. + auto symbol = controller.GetSymbolAt(symbolAddr); + if (!symbol.has_value()) + return; - { - if (cache->LoadSectionAtAddress(dest.GetConstant())) - { - func->Reanalyze(); - } - } - else - { - if (applySymbolIfFoundToCurrentFunction) - cache->FindSymbolAtAddrAndApplyToAddr(dest.GetConstant(), func->GetStart(), false); - else - cache->FindSymbolAtAddrAndApplyToAddr(dest.GetConstant(), dest.GetConstant(), false); - } - }); + // NOTE: The type library name is expected to be the image name currently. + // Try and pull the type from the associated type library (if there is one) + Ref type = nullptr; + if (const auto image = controller.GetImageContaining(symbolAddr)) + if (auto typeLib = TypeLibraryFromName(view, image->name)) + type = view.ImportTypeLibraryObject(typeLib, {symbol->name}); + + // Define the symbol and type (if found) + auto targetFunc = view.GetAnalysisFunction(view.GetDefaultPlatform(), stubFuncAddr); + if (type && targetFunc) + targetFunc->SetUserType(type); + // TODO: When to reanalysis function (mark updates required?) + view.DefineUserSymbol(new Symbol(symbol->type, STUB_PREFIX + symbol->name, stubFuncAddr)); } +// Loads the associated image or region for the specified target address. Returning if it was loaded or not. +bool TryLoadTarget(BinaryView& view, SharedCacheController& controller, const uint64_t target) { + if (const auto image = controller.GetImageContaining(target)) + return controller.ApplyImage(view, *image); + // Failed to find image, try and apply region instead. + if (const auto region = controller.GetRegionContaining(target)) + return controller.ApplyRegion(view, *region); + return false; +}; -void SharedCacheWorkflow::FixupStubs(Ref ctx) +void FixupStubs(Ref ctx) { - try - { - const auto func = ctx->GetFunction(); - const auto arch = func->GetArchitecture(); + const auto func = ctx->GetFunction(); + const auto view = func->GetView(); + const auto mlil = ctx->GetMediumLevelILFunction(); + if (!mlil) + return; + const auto mssa = mlil->GetSSAForm(); + if (!mssa) + return; - const auto bv = func->GetView(); + auto workflowState = GetGlobalWorkflowState(view); + auto controller = SharedCacheController::GetController(*view); + if (!controller) + return; - auto workflowState = GetGlobalWorkflowState(bv); + // Get the containing section for section specific tasks. + auto funcStart = func->GetStart(); + auto sections = view->GetSectionsAt(funcStart); + if (sections.empty()) + return; + const auto& section = sections.front(); + const auto sectionName = section->GetName(); - auto funcStart = func->GetStart(); - auto sections = bv->GetSectionsAt(funcStart); - if (sections.empty()) + // Load the target region if applicable and then trigger re-analysis for all functions in our section. + auto processStubImageCall = [&](const uint64_t target) { + // TODO: If this fails that doesn't necessarily mean we are duplicating work and thus allowing early return... + if (!workflowState->loadMutex.try_lock()) return; - // Just get the first section - const auto& section = sections.front(); - const auto mlil = ctx->GetMediumLevelILFunction(); - if (!mlil) - return; - const auto mssa = mlil->GetSSAForm(); - if (!mssa) - return; + if (!view->IsValidOffset(target) && TryLoadTarget(*view, *controller, target)) + { + // Update all the functions inside our current activities function section. + for (const auto §Func : view->GetAnalysisFunctionList()) + if (section->GetStart() <= sectFunc->GetStart() && sectFunc->GetStart() < section->GetEnd()) + sectFunc->Reanalyze(); + } - Ref cache = new SharedCache(bv); - if (cache->m_object == nullptr) - return; + workflowState->loadMutex.unlock(); + }; - // Processor that automatically loads the libObjC image when it encounters a stub (so we can do inlining). - if (workflowState->autoLoadObjCStubRequirements && section->GetName().find("__objc_stubs") != std::string::npos) + // TODO: Split this out into another function. + // Processor that automatically loads the libObjC image when it encounters a stub (so we can do inlining). + if (workflowState->autoLoadObjCStubRequirements && sectionName.find("__objc_stubs") != std::string::npos) + { + auto firstInstruction = mlil->GetInstruction(0); + if (firstInstruction.operation == MLIL_TAILCALL) { - auto firstInstruction = mlil->GetInstruction(0); - if (firstInstruction.operation == MLIL_TAILCALL) - { - auto dest = firstInstruction.GetDestExpr(); - if (dest.operation == MLIL_CONST_PTR) - { - // We're ready, everything is here - func->SetAutoInlinedDuringAnalysis(true); - return; - } - } - for (const auto& block : mssa->GetBasicBlocks()) + auto dest = firstInstruction.GetDestExpr(); + if (dest.operation == MLIL_CONST_PTR) { - for (size_t i = block->GetStart(), end = block->GetEnd(); i < end; ++i) - { - auto instr = mssa->GetInstruction(i); - if (instr.operation == MLIL_JUMP) - { - if (instr.GetDestExpr().operation == MLIL_VAR_SSA) - { - auto dest = instr.GetDestExpr(); - auto value = mssa->GetSSAVarValue(dest.GetSourceSSAVariable()); - if (value.state == UndeterminedValue) - { - auto def = mssa->GetSSAVarDefinition(dest.GetSourceSSAVariable()); - auto defInstr = mssa->GetInstruction(def); - auto targetOffset = defInstr.GetSourceExpr().GetSourceExpr().GetConstant(); - ProcessStubImageCall(workflowState, cache, func, section, targetOffset); - } - } - else if (instr.GetDestExpr().operation == MLIL_CONST_PTR) - { - auto dest = instr.GetDestExpr(); - auto targetOffset = dest.GetConstant(); - ProcessStubImageCall(workflowState, cache, func, section, targetOffset); - } - } - } + // We're ready, everything is here + func->SetAutoInlinedDuringAnalysis(true); + return; } - - return; } - if (section->GetName().find("::_stubs") != std::string::npos // Branch Islands (iOS 16) - || section->GetName().find("dyld_shared_cache_branch_islands") != std::string::npos // Branch Islands (iOS 11-?) - || section->GetName().find("::__stubs") != std::string::npos // Stubs (non arm64e) - || section->GetName().find("::__auth_stubs") != std::string::npos // Stubs (arm64e) - ) + for (const auto& block : mssa->GetBasicBlocks()) { - auto firstInstruction = mlil->GetInstruction(0); - if (firstInstruction.operation == MLIL_TAILCALL) - { - auto dest = firstInstruction.GetDestExpr(); - if (dest.operation == MLIL_CONST_PTR) - { - if (auto symbol = bv->GetSymbolByAddress(dest.GetConstant())) - { - auto newSymbol = new Symbol(FunctionSymbol, "j_" + symbol->GetRawName(), func->GetStart()); - bv->DefineUserSymbol(newSymbol); - } - } - } - else if (firstInstruction.operation == MLIL_JUMP) + for (size_t i = block->GetStart(), end = block->GetEnd(); i < end; ++i) { - auto dest = firstInstruction.GetDestExpr(); - if (dest.operation == MLIL_CONST_PTR) - { - if (!bv->IsValidOffset(dest.GetConstant())) - { - ProcessOffImageCall(ctx, cache, func, mssa, dest, true); - } - } - - else if (dest.operation == MLIL_LOAD) + auto instr = mssa->GetInstruction(i); + if (instr.operation == MLIL_JUMP) { - if (dest.GetSourceExpr().operation == MLIL_CONST_PTR) + if (instr.GetDestExpr().operation == MLIL_VAR_SSA) { - dest = dest.GetSourceExpr(); - if (!bv->IsValidOffset(dest.GetConstant())) + auto dest = instr.GetDestExpr(); + auto value = mssa->GetSSAVarValue(dest.GetSourceSSAVariable()); + if (value.state == UndeterminedValue) { - ProcessOffImageCall(ctx, cache, func, mssa, dest); + auto def = mssa->GetSSAVarDefinition(dest.GetSourceSSAVariable()); + auto defInstr = mssa->GetInstruction(def); + auto targetOffset = defInstr.GetSourceExpr().GetSourceExpr().GetConstant(); + processStubImageCall(targetOffset); } } - } - } - else - { - for (const auto& block : mssa->GetBasicBlocks()) - { - for (size_t i = block->GetStart(), end = block->GetEnd(); i < end; ++i) + else if (instr.GetDestExpr().operation == MLIL_CONST_PTR) { - auto instr = mssa->GetInstruction(i); - if (instr.operation == MLIL_JUMP) - { - if (instr.GetDestExpr().operation == MLIL_VAR_SSA) - { - auto dest = instr.GetDestExpr(); - auto value = mssa->GetSSAVarValue(dest.GetSourceSSAVariable()); - if (value.state == UndeterminedValue) - { - auto def = mssa->GetSSAVarDefinition(dest.GetSourceSSAVariable()); - auto defInstr = mssa->GetInstruction(def); - auto targetOffset = defInstr.GetSourceExpr().GetSourceExpr().GetConstant(); - ProcessStubImageCall(workflowState, cache, func, section, targetOffset); - } - } - } + auto dest = instr.GetDestExpr(); + auto targetOffset = dest.GetConstant(); + processStubImageCall(targetOffset); } } } - - return; } + return; + } + + // TODO: Split this out into another function. + // If this is a stub function we should map in the called region / image. + // NOTE: We cant use the region type here as these sections will be found under larger image region + // "_stubs" => Branch Islands / Stubs (iOS 16 / macOs) + // "dyld_shared_cache_branch_islands" => Branch Islands (iOS 11-?) + if (sectionName.rfind("_stubs") != std::string::npos || sectionName.rfind("dyld_shared_cache_branch_islands") != std::string::npos) + { + // Stage 0: Load the jumped to region, so that x16 is resolved. + // 0 @ 180359b58 (MLIL_SET_VAR.q x16 = (MLIL_LOAD.q [(MLIL_CONST_PTR.q &data_1eacf40f8)].q)) + // 1 @ 180359b5c (MLIL_JUMP jump((MLIL_VAR.q x16))) for (const auto& block : mssa->GetBasicBlocks()) { for (size_t i = block->GetStart(), end = block->GetEnd(); i < end; ++i) { auto instr = mssa->GetInstruction(i); - if (instr.operation == MLIL_CALL_SSA) + if (instr.operation == MLIL_JUMP) { - if (instr.GetDestExpr().operation == MLIL_CONST_PTR) + if (instr.GetDestExpr().operation == MLIL_VAR_SSA) { - auto dest = instr.GetDestExpr(); - if (!bv->IsValidOffset(dest.GetConstant())) + auto dest = instr.GetDestExpr(); + auto value = mssa->GetSSAVarValue(dest.GetSourceSSAVariable()); + if (value.state == UndeterminedValue) { - ProcessOffImageCall(ctx, cache, func, mssa, dest); + auto def = mssa->GetSSAVarDefinition(dest.GetSourceSSAVariable()); + auto defInstr = mssa->GetInstruction(def); + auto targetOffset = defInstr.GetSourceExpr().GetSourceExpr().GetConstant(); + processStubImageCall(targetOffset); } } } } } } - catch (...) - {} } - -static constexpr auto workflowInfo = R"({ - "title": "Shared Cache Workflow", - "description": "Shared Cache Workflow", - "capabilities": [] -})"; - - -void fixObjCCallTypes(Ref ctx) +// TODO: FixupOffImageAccess +void FixupOffImageCalls(Ref ctx) { const auto func = ctx->GetFunction(); - const auto arch = func->GetArchitecture(); - const auto bv = func->GetView(); - - const auto llil = ctx->GetLowLevelILFunction(); - if (!llil) { + const auto view = func->GetView(); + const auto mlil = ctx->GetMediumLevelILFunction(); + if (!mlil) return; - } - const auto ssa = llil->GetSSAForm(); - if (!ssa) { + const auto mssa = mlil->GetSSAForm(); + if (!mssa) return; - } - const auto rewriteIfEligible = [bv, ssa](size_t insnIndex) { - auto insn = ssa->GetInstruction(insnIndex); + auto workflowState = GetGlobalWorkflowState(view); + auto controller = SharedCacheController::GetController(*view); + if (!controller) + return; - if (insn.operation == LLIL_CALL_SSA) - { - // Filter out calls that aren't to `objc_msgSend`. - auto callExpr = insn.GetDestExpr(); - bool isMessageSend = false; - if (auto symbol = bv->GetSymbolByAddress(callExpr.GetValue().value)) - isMessageSend = symbol->GetRawName() == "_objc_msgSend"; - if (!isMessageSend) - return; + auto processOffImageCall = [&](const uint64_t stubFuncAddr, const uint64_t symbolAddr) { + const auto region = controller->GetRegionContaining(symbolAddr); + if (!region.has_value()) + return; - const auto llil = ssa->GetNonSSAForm(); - const auto insn = ssa->GetInstruction(insnIndex); - const auto params = insn.GetParameterExprs(); + // Load stub region if not already loaded and reanalyze the function (to pickup stub functions) + if (workflowState->autoLoadStubsAndDyldData && region->type == SharedCacheRegionTypeStubIsland) + if (controller->ApplyRegion(*view, *region)) + func->Reanalyze(); // TODO: Call mark updates required instead??? Use incremental update type instead??? - // The second parameter passed to the objc_msgSend call is the address of - // either the selector reference or the method's name, which in both cases - // is dereferenced to retrieve a selector. - if (params.size() < 2) - return; - uint64_t rawSelector = 0; - if (params[1].operation == LLIL_REG_SSA) - { - const auto selectorRegister = params[1].GetSourceSSARegister(); - rawSelector = ssa->GetSSARegisterValue(selectorRegister).value; - } - else if (params[0].operation == LLIL_SEPARATE_PARAM_LIST_SSA) + // TODO: Is there a point to this at all???? + // TODO: is there a point to calling this if workflowState->autoLoadStubsAndDyldData is not on??? + // Apply symbols (and possibly a type) to the relevant stub functions + IdentifyStub(*view, *controller, stubFuncAddr, symbolAddr); + }; + + // Load all unmapped STUB regions / images that are called in this function. + for (const auto& block : mssa->GetBasicBlocks()) + { + for (size_t i = block->GetStart(), end = block->GetEnd(); i < end; ++i) + { + auto instr = mssa->GetInstruction(i); + if (instr.operation == MLIL_CALL_SSA) { - if (params[0].GetParameterExprs().size() == 0) + if (instr.GetDestExpr().operation == MLIL_CONST_PTR) { - return; + auto targetAddr = instr.GetDestExpr().GetConstant(); + if (!view->IsValidOffset(targetAddr)) + { + processOffImageCall(targetAddr, targetAddr); + } } - const auto selectorRegister = params[0].GetParameterExprs()[1].GetSourceSSARegister(); - rawSelector = ssa->GetSSARegisterValue(selectorRegister).value; } - if (!rawSelector || !bv->IsValidOffset(rawSelector)) - return; - - // -- Do callsite override - auto reader = BinaryNinja::BinaryReader(bv); - reader.Seek(rawSelector); - auto selector = reader.ReadCString(500); - auto additionalArgumentCount = std::count(selector.begin(), selector.end(), ':'); - - auto retType = bv->GetTypeByName({ "id" }); - if (!retType) - retType = BinaryNinja::Type::PointerType(ssa->GetArchitecture(), BinaryNinja::Type::VoidType()); - - std::vector callTypeParams; - auto cc = bv->GetDefaultPlatform()->GetDefaultCallingConvention(); - - callTypeParams.push_back({"self", retType, true, BinaryNinja::Variable()}); - - auto selType = bv->GetTypeByName({ "SEL" }); - if (!selType) - selType = BinaryNinja::Type::PointerType(ssa->GetArchitecture(), BinaryNinja::Type::IntegerType(1, true)); - callTypeParams.push_back({"sel", selType, true, BinaryNinja::Variable()}); - - std::vector selectorComponents = splitSelector(selector); - std::vector argumentNames = generateArgumentNames(selectorComponents); - - for (size_t i = 0; i < additionalArgumentCount; i++) + else if (instr.operation == MLIL_JUMP) { - auto argType = BinaryNinja::Type::IntegerType(bv->GetAddressSize(), true); - if (argumentNames.size() > i && !argumentNames[i].empty()) - callTypeParams.push_back({argumentNames[i], argType, true, BinaryNinja::Variable()}); - else - callTypeParams.push_back({"arg" + std::to_string(i), argType, true, BinaryNinja::Variable()}); + auto destExpr = instr.GetDestExpr(); + if (destExpr.operation == MLIL_VAR_SSA) + { + // 1 @ 180359b5c (MLIL_JUMP jump((MLIL_VAR.q x16))) + auto dest = instr.GetDestExpr(); + auto value = mssa->GetSSAVarValue(dest.GetSourceSSAVariable()); + if (value.state == UndeterminedValue) + { + auto def = mssa->GetSSAVarDefinition(dest.GetSourceSSAVariable()); + auto defInstr = mssa->GetInstruction(def); + if (defInstr.operation == MLIL_SET_VAR_SSA) + { + // 0 @ 180359b58 (MLIL_SET_VAR.q x16 = (MLIL_LOAD.q [(MLIL_CONST_PTR.q &data_1eacf40f8)].q)) + auto loadExpr = defInstr.GetSourceExpr(); + if (loadExpr.operation == MLIL_LOAD_SSA) + { + auto ptrExpr = loadExpr.GetSourceExpr(); + if (ptrExpr.operation == MLIL_CONST_PTR) + { + auto targetAddr = ptrExpr.GetConstant(); + if (!view->IsValidOffset(targetAddr)) + { + processOffImageCall(targetAddr, targetAddr); + } + } + } + } + } + else if (destExpr.operation == MLIL_CONST_PTR) + { + // 4 @ 18aa08208 (MLIL_JUMP jump((MLIL_CONST_PTR.q 0x18c1369f0))) + auto targetAddr = destExpr.GetConstant(); + if (!view->IsValidOffset(targetAddr)) + { + processOffImageCall(targetAddr, targetAddr); + } + } + else if (destExpr.operation == MLIL_LOAD_SSA) + { + auto ptrExpr = destExpr.GetSourceExpr(); + if (ptrExpr.operation == MLIL_CONST_PTR) + { + auto targetAddr = ptrExpr.GetConstant(); + if (!view->IsValidOffset(targetAddr)) + { + processOffImageCall(targetAddr, targetAddr); + } + } + } + } } - - auto funcType = BinaryNinja::Type::FunctionType(retType, cc, callTypeParams); - ssa->GetFunction()->SetAutoCallTypeAdjustment(ssa->GetFunction()->GetArchitecture(), insn.address, {funcType, BN_DEFAULT_CONFIDENCE}); - // -- + // TODO: Check all instructions for accesses to select region types (stub etc...) + // TODO: ^ we actually dont really need to do this, the other type of access cont.. + // TODO: the other two types of accesses (load & save) we dont want to load their regions, just + // TODO: their symbol information if available. } - }; - - for (const auto& block : ssa->GetBasicBlocks()) - for (size_t i = block->GetStart(), end = block->GetEnd(); i < end; ++i) - rewriteIfEligible(i); + } } - +static constexpr auto WORKFLOW_DESCRIPTION = R"({ + "title": "Shared Cache Workflow", + "description": "Shared Cache Workflow", + "capabilities": [] +})"; void SharedCacheWorkflow::Register() { - Ref wf = BinaryNinja::Workflow::Instance("core.function.baseAnalysis")->Clone("core.function.dsc"); - wf->RegisterActivity(new BinaryNinja::Activity("core.analysis.dscstubs", &SharedCacheWorkflow::FixupStubs)); - wf->RegisterActivity(new BinaryNinja::Activity("core.analysis.fixObjCCallTypes", &fixObjCCallTypes)); - wf->Insert("core.function.analyzeTailCalls", "core.analysis.fixObjCCallTypes"); - wf->Insert("core.function.analyzeTailCalls", "core.analysis.dscstubs"); + Ref workflow = Workflow::Instance("core.function.baseAnalysis")->Clone("core.function.sharedCache"); + + // Register and insert activities here. + ObjCActivity::Register(*workflow); + workflow->RegisterActivity(new Activity("core.analysis.sharedCache.stubs", &FixupStubs)); + workflow->RegisterActivity(new Activity("core.analysis.sharedCache.calls", &FixupOffImageCalls)); + workflow->Insert("core.function.analyzeTailCalls", "core.analysis.sharedCache.stubs"); + workflow->Insert("core.function.analyzeTailCalls", "core.analysis.sharedCache.calls"); - BinaryNinja::Workflow::RegisterWorkflow(wf, workflowInfo); + Workflow::RegisterWorkflow(workflow, WORKFLOW_DESCRIPTION); } extern "C" -- cgit v1.3.1