From a6c5c22f08032374481aa060b59ef3492d124200 Mon Sep 17 00:00:00 2001 From: Mark Rowe Date: Wed, 19 Feb 2025 15:54:58 -0800 Subject: [SharedCache] Apply objc_msgSend call type overrides in more places `fixObjCCallTypes` is updated to handle tail calls as well as regular calls. Additionally, if the selector address is not valid it now looks for the `sel_` symbols that `DSCObjCProcessor::ReadMethodList` adds for selectors whose names reside in regions that are not yet mapped. This allows call type overrides to be applied even when a selector's name is defined in a different image. --- view/sharedcache/workflow/ObjCActivity.cpp | 37 +++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 8 deletions(-) (limited to 'view/sharedcache/workflow/ObjCActivity.cpp') diff --git a/view/sharedcache/workflow/ObjCActivity.cpp b/view/sharedcache/workflow/ObjCActivity.cpp index f620de85..cc1b2256 100644 --- a/view/sharedcache/workflow/ObjCActivity.cpp +++ b/view/sharedcache/workflow/ObjCActivity.cpp @@ -42,6 +42,7 @@ void ObjCActivity::AdjustCallType(Ref ctx) const auto func = ctx->GetFunction(); const auto arch = func->GetArchitecture(); const auto bv = func->GetView(); + const auto baseAddr = bv->GetStart(); const auto llil = ctx->GetLowLevelILFunction(); if (!llil) { @@ -52,9 +53,9 @@ void ObjCActivity::AdjustCallType(Ref ctx) return; } - const auto rewriteIfEligible = [bv, ssa](size_t insnIndex) { + const auto rewriteIfEligible = [bv, ssa, baseAddr](size_t insnIndex) { auto insn = ssa->GetInstruction(insnIndex); - if (insn.operation != LLIL_CALL_SSA) + if (insn.operation != LLIL_CALL_SSA && insn.operation != LLIL_TAILCALL_SSA) return; enum class MessageSendType { @@ -64,7 +65,7 @@ void ObjCActivity::AdjustCallType(Ref ctx) MessageSendType messageSendType = MessageSendType::Normal; // Filter out calls that aren't to `objc_msgSend`, `objc_msgSendSuper`, or `objc_msgSendSuper2`. - auto callExpr = insn.GetDestExpr(); + auto callExpr = insn.GetDestExpr(); if (auto symbol = bv->GetSymbolByAddress(callExpr.GetValue().value)) { std::string_view symbolName = symbol->GetRawNameRef(); @@ -76,7 +77,7 @@ void ObjCActivity::AdjustCallType(Ref ctx) return; } - const auto params = insn.GetParameterExprs(); + const auto params = insn.GetParameterExprs(); // 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. @@ -95,13 +96,33 @@ void ObjCActivity::AdjustCallType(Ref ctx) const auto selectorRegister = params[0].GetParameterExprs()[1].GetSourceSSARegister(); rawSelector = ssa->GetSSARegisterValue(selectorRegister).value; } - if (!rawSelector || !bv->IsValidOffset(rawSelector)) + + // Skip if we don't have a + if (!rawSelector || rawSelector < baseAddr) return; + std::string selector; + if (bv->IsValidOffset(rawSelector)) { + BinaryReader reader(bv); + reader.Seek(rawSelector); + selector = reader.ReadCString(500); + } else { + // Look for the `sel_` symbols that ObjCProcessor adds to represent selectors + // whose backing regions have not yet been loaded into the view. + constexpr std::string_view SelectorPrefix = "sel_"; + + auto symbol = bv->GetSymbolByAddress(rawSelector); + if (!symbol) + return; + + std::string_view name = symbol->GetRawNameRef(); + if (name.find(SelectorPrefix) != 0) + return; + + selector = name.substr(SelectorPrefix.length()); + } + // -- Do callsite override - auto reader = BinaryReader(bv); - reader.Seek(rawSelector); - auto selector = reader.ReadCString(500); auto additionalArgumentCount = std::count(selector.begin(), selector.end(), ':'); auto retType = bv->GetTypeByName({ "id" }); -- cgit v1.3.1