diff --git a/Plugin.cpp b/Plugin.cpp index dccb4fa..e10a93d 100644 --- a/Plugin.cpp +++ b/Plugin.cpp @@ -41,6 +41,15 @@ BINARYNINJAPLUGIN bool CorePluginInit() BinaryNinja::LogRegistry::CreateLogger(PluginLoggerName); + auto settings = BinaryNinja::Settings::Instance(); + settings->RegisterSetting("core.function.objectiveC.rewriteMessageSendTarget", + R"({ + "title" : "Rewrite objc_msgSend calls in IL", + "type" : "boolean", + "default" : false, + "description" : "Message sends of selectors with any visible implementation are replaced with a direct call to the first visible implementation. Note that this can produce false positives if the selector is implemented by more than one class, or shares a name with a method from a system framework." + })"); + return true; } } diff --git a/Workflow.cpp b/Workflow.cpp index 15120fc..24a42e2 100644 --- a/Workflow.cpp +++ b/Workflow.cpp @@ -147,6 +147,8 @@ bool Workflow::rewriteMethodCall(LLILFunctionRef ssa, size_t insnIndex) ssa->GetFunction()->SetAutoCallTypeAdjustment(ssa->GetFunction()->GetArchitecture(), insn.address, {funcType, BN_DEFAULT_CONFIDENCE}); // -- + if (!BinaryNinja::Settings::Instance()->Get("core.function.objectiveC.rewriteMessageSendTarget", bv)) + return false; // Check the analysis info for a selector reference corresponding to the // current selector. It is possible no such selector reference exists, for @@ -158,6 +160,10 @@ bool Workflow::rewriteMethodCall(LLILFunctionRef ssa, size_t insnIndex) const auto info = GlobalState::analysisInfo(bv); if (!info) return false; + + // Attempt to look up the implementation for the given selector, first by + // using the raw selector, then by the address of the selector reference. If + // the lookup fails in both cases, abort. std::vector imps; if (const auto& it = info->selRefToImp.find(rawSelector); it != info->selRefToImp.end()) imps = it->second; @@ -167,10 +173,6 @@ bool Workflow::rewriteMethodCall(LLILFunctionRef ssa, size_t insnIndex) if (imps.empty()) return false; - // Attempt to look up the implementation for the given selector, first by - // using the raw selector, then by the address of the selector reference. If - // the lookup fails in both cases, abort. - // k: This is the same behavior as before, however it is more apparent now by implementation // that we are effectively just guessing which method this hits. This has _obvious_ drawbacks, // but until we have more robust typing and objective-c type libraries, fixing this would