summaryrefslogtreecommitdiff
path: root/view/sharedcache/workflow/SharedCacheWorkflow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'view/sharedcache/workflow/SharedCacheWorkflow.cpp')
-rw-r--r--view/sharedcache/workflow/SharedCacheWorkflow.cpp566
1 files changed, 257 insertions, 309 deletions
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 <shared_mutex>
+#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<uint64_t, std::shared_ptr<GlobalWorkflowState>> globalWorkflowState;
-std::shared_mutex globalWorkflowStateMutex;
-
std::shared_ptr<GlobalWorkflowState> GetGlobalWorkflowState(Ref<BinaryView> view)
{
+ static std::shared_mutex globalWorkflowStateMutex;
+ static std::unordered_map<uint64_t, std::shared_ptr<GlobalWorkflowState>> globalWorkflowState;
+
std::shared_lock<std::shared_mutex> 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<GlobalWorkflowState> GetGlobalWorkflowState(Ref<BinaryView> view
std::unique_lock<std::shared_mutex> writeLock(globalWorkflowStateMutex);
globalWorkflowState[viewId] = std::make_shared<GlobalWorkflowState>();
Ref<Settings> settings = view->GetLoadSettings(VIEW_NAME);
+
bool autoLoadStubsAndDyldData = true;
if (settings && settings->Contains("loader.dsc.autoLoadStubsAndDyldData"))
- {
autoLoadStubsAndDyldData = settings->Get<bool>("loader.dsc.autoLoadStubsAndDyldData", view);
- }
globalWorkflowState[viewId]->autoLoadStubsAndDyldData = autoLoadStubsAndDyldData;
+
bool autoLoadObjC = true;
if (settings && settings->Contains("loader.dsc.autoLoadObjCStubRequirements"))
- {
autoLoadObjC = settings->Get<bool>("loader.dsc.autoLoadObjCStubRequirements", view);
- }
globalWorkflowState[viewId]->autoLoadObjCStubRequirements = autoLoadObjC;
- return globalWorkflowState[viewId];
-}
-
-std::vector<std::string> splitSelector(const std::string& selector) {
- std::vector<std::string> 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<std::string> generateArgumentNames(const std::vector<std::string>& components) {
- std::vector<std::string> 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);
- }
+// TODO: Add a type library cache to this workflow. (so we dont take global file lock)
+Ref<TypeLibrary> 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;
- return argumentNames;
+ // 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<GlobalWorkflowState> &workflowState, Ref<SharedCache> cache, Ref<Function> func,
- const Ref<Section>& 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 &sectFunc : 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();
-}
-
+ // No existing symbol located, try and search through the symbols of the cache.
+ auto symbol = controller.GetSymbolAt(symbolAddr);
+ if (!symbol.has_value())
+ return;
-void SharedCacheWorkflow::ProcessOffImageCall(Ref<AnalysisContext> ctx, Ref<SharedCache> cache, Ref<Function> func,
- Ref<MediumLevelILFunction> 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
- )
- )
+ // 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> type = nullptr;
+ if (const auto image = controller.GetImageContaining(symbolAddr))
+ if (auto typeLib = TypeLibraryFromName(view, image->name))
+ type = view.ImportTypeLibraryObject(typeLib, {symbol->name});
- {
- 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);
- }
- });
+ // 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<AnalysisContext> ctx)
+void FixupStubs(Ref<AnalysisContext> 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 &sectFunc : view->GetAnalysisFunctionList())
+ if (section->GetStart() <= sectFunc->GetStart() && sectFunc->GetStart() < section->GetEnd())
+ sectFunc->Reanalyze();
+ }
- Ref<SharedCache> 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<MLIL_TAILCALL>();
- 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<MLIL_TAILCALL>();
+ 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<MLIL_JUMP>().operation == MLIL_VAR_SSA)
- {
- auto dest = instr.GetDestExpr<MLIL_JUMP>();
- 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<MLIL_JUMP>().operation == MLIL_CONST_PTR)
- {
- auto dest = instr.GetDestExpr<MLIL_JUMP>();
- 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<MLIL_TAILCALL>();
- 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<MLIL_JUMP>();
- 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<MLIL_JUMP>().operation == MLIL_VAR_SSA)
{
- dest = dest.GetSourceExpr();
- if (!bv->IsValidOffset(dest.GetConstant()))
+ auto dest = instr.GetDestExpr<MLIL_JUMP>();
+ 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<MLIL_JUMP>().operation == MLIL_CONST_PTR)
{
- auto instr = mssa->GetInstruction(i);
- if (instr.operation == MLIL_JUMP)
- {
- if (instr.GetDestExpr<MLIL_JUMP>().operation == MLIL_VAR_SSA)
- {
- auto dest = instr.GetDestExpr<MLIL_JUMP>();
- 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<MLIL_JUMP>();
+ 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<MLIL_CALL_SSA>().operation == MLIL_CONST_PTR)
+ if (instr.GetDestExpr<MLIL_JUMP>().operation == MLIL_VAR_SSA)
{
- auto dest = instr.GetDestExpr<MLIL_CALL_SSA>();
- if (!bv->IsValidOffset(dest.GetConstant()))
+ auto dest = instr.GetDestExpr<MLIL_JUMP>();
+ 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<AnalysisContext> ctx)
+// TODO: FixupOffImageAccess
+void FixupOffImageCalls(Ref<AnalysisContext> 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<LLIL_CALL_SSA>();
- 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<LLIL_CALL_SSA>();
+ // 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<LLIL_REG_SSA>();
- 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<LLIL_SEPARATE_PARAM_LIST_SSA>().size() == 0)
+ if (instr.GetDestExpr<MLIL_CALL_SSA>().operation == MLIL_CONST_PTR)
{
- return;
+ auto targetAddr = instr.GetDestExpr<MLIL_CALL_SSA>().GetConstant();
+ if (!view->IsValidOffset(targetAddr))
+ {
+ processOffImageCall(targetAddr, targetAddr);
+ }
}
- const auto selectorRegister = params[0].GetParameterExprs<LLIL_SEPARATE_PARAM_LIST_SSA>()[1].GetSourceSSARegister<LLIL_REG_SSA>();
- 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<BinaryNinja::FunctionParameter> 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<std::string> selectorComponents = splitSelector(selector);
- std::vector<std::string> 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<MLIL_JUMP>();
+ if (destExpr.operation == MLIL_VAR_SSA)
+ {
+ // 1 @ 180359b5c (MLIL_JUMP jump((MLIL_VAR.q x16)))
+ auto dest = instr.GetDestExpr<MLIL_JUMP>();
+ 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<MLIL_SET_VAR_SSA>();
+ if (loadExpr.operation == MLIL_LOAD_SSA)
+ {
+ auto ptrExpr = loadExpr.GetSourceExpr<MLIL_LOAD_SSA>();
+ 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<MLIL_LOAD_SSA>();
+ 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<Workflow> 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 = 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"