diff options
Diffstat (limited to 'lang')
| -rw-r--r-- | lang/c/pseudoobjc.cpp | 106 | ||||
| -rw-r--r-- | lang/c/pseudoobjc.h | 2 |
2 files changed, 73 insertions, 35 deletions
diff --git a/lang/c/pseudoobjc.cpp b/lang/c/pseudoobjc.cpp index eccf10f1..4cb360a7 100644 --- a/lang/c/pseudoobjc.cpp +++ b/lang/c/pseudoobjc.cpp @@ -60,6 +60,43 @@ void SplitSelector(const std::string& selector, std::vector<std::string>& tokens tokens.push_back(token); } +std::optional<std::pair<uint64_t, Ref<Symbol>>> GetCallTargetInfo(const HighLevelILInstruction& callTarget, + const std::vector<HighLevelILInstruction>& parameterExprs, const Function& function) +{ + uint64_t constant = 0; + Ref<Symbol> symbol; + + switch (callTarget.operation) + { + case HLIL_CONST_PTR: + { + constant = callTarget.GetConstant<HLIL_CONST_PTR>(); + symbol = function.GetView()->GetSymbolByAddress(constant); + break; + } + case HLIL_IMPORT: + { + constant = callTarget.GetConstant<HLIL_IMPORT>(); + auto importAddressSymbol = function.GetView()->GetSymbolByAddress(constant); + if (!importAddressSymbol) + return std::nullopt; + + const auto symbolType = importAddressSymbol->GetType(); + if (symbolType != ImportedDataSymbol && symbolType != ImportAddressSymbol) + return std::nullopt; + + symbol = Symbol::ImportedFunctionFromImportAddressSymbol(importAddressSymbol, constant); + } + default: + break; + } + + if (!symbol) + return std::nullopt; + + return std::make_pair(constant, symbol); +} + struct RuntimeCall { enum Type @@ -78,6 +115,7 @@ struct RuntimeCall Type type; uint64_t address; + bool isRewritten = false; }; constexpr std::array RUNTIME_CALLS = { @@ -114,36 +152,10 @@ constexpr std::array RUNTIME_CALLS = { std::optional<RuntimeCall> DetectObjCRuntimeCall(const HighLevelILInstruction& callTarget, const std::vector<HighLevelILInstruction>& parameterExprs, const Function& function) { - uint64_t constant = 0; - Ref<Symbol> symbol; - - switch (callTarget.operation) - { - case HLIL_CONST_PTR: - { - constant = callTarget.GetConstant<HLIL_CONST_PTR>(); - symbol = function.GetView()->GetSymbolByAddress(constant); - break; - } - case HLIL_IMPORT: - { - constant = callTarget.GetConstant<HLIL_IMPORT>(); - auto importAddressSymbol = function.GetView()->GetSymbolByAddress(constant); - if (!importAddressSymbol) - return std::nullopt; - - const auto symbolType = importAddressSymbol->GetType(); - if (symbolType != ImportedDataSymbol && symbolType != ImportAddressSymbol) - return std::nullopt; - - symbol = Symbol::ImportedFunctionFromImportAddressSymbol(importAddressSymbol, constant); - } - default: - break; - } - - if (!symbol) + auto callTargetInfo = GetCallTargetInfo(callTarget, parameterExprs, function); + if (!callTargetInfo) return std::nullopt; + auto [constant, symbol] = callTargetInfo.value(); const auto symbolShortName = symbol->GetShortName(); auto it = std::find_if(RUNTIME_CALLS.begin(), RUNTIME_CALLS.end(), [&](const auto& pair) { @@ -155,6 +167,26 @@ std::optional<RuntimeCall> DetectObjCRuntimeCall(const HighLevelILInstruction& c return RuntimeCall {it->second, constant}; } +std::optional<RuntimeCall> DetectRewrittenDirectObjCMethodCall(const HighLevelILInstruction& callTarget, + const std::vector<HighLevelILInstruction>& parameterExprs, const Function& function) +{ + auto callTargetInfo = GetCallTargetInfo(callTarget, parameterExprs, function); + if (!callTargetInfo) + return std::nullopt; + auto [constant, symbol] = callTargetInfo.value(); + + const auto symbolShortName = symbol->GetShortName(); + if (symbolShortName.length() < 6) + return std::nullopt; + + // Look for the pattern -[ClassName methodName:] or +[ClassName methodName:] + if ((symbolShortName[0] != '-' && symbolShortName[0] != '+') || symbolShortName[1] != '[' + || symbolShortName.back() != ']' || symbolShortName.find(' ') == std::string::npos) + return std::nullopt; + + return RuntimeCall {RuntimeCall::MessageSend, constant, true}; +} + } // unnamed namespace PseudoObjCFunction::PseudoObjCFunction(LanguageRepresentationFunctionType* type, Architecture* arch, Function* owner, @@ -170,6 +202,9 @@ void PseudoObjCFunction::GetExpr_CALL_OR_TAILCALL(const BinaryNinja::HighLevelIL auto objCRuntimeCall = DetectObjCRuntimeCall(destExpr, parameterExprs, *GetFunction()); if (!objCRuntimeCall) + objCRuntimeCall = DetectRewrittenDirectObjCMethodCall(destExpr, parameterExprs, *GetFunction()); + + if (!objCRuntimeCall) return PseudoCFunction::GetExpr_CALL_OR_TAILCALL(instr, tokens, settings, precedence, statement); std::vector<std::string_view> runtimeCallTokens; @@ -177,7 +212,7 @@ void PseudoObjCFunction::GetExpr_CALL_OR_TAILCALL(const BinaryNinja::HighLevelIL { case RuntimeCall::MessageSend: case RuntimeCall::MessageSendSuper: - if (GetExpr_ObjCMsgSend(destExpr, tokens, settings, parameterExprs)) + if (GetExpr_ObjCMsgSend(objCRuntimeCall->address, objCRuntimeCall->isRewritten, destExpr, tokens, settings, parameterExprs)) { if (statement) tokens.AppendSemicolon(); @@ -224,8 +259,9 @@ void PseudoObjCFunction::GetExpr_CALL_OR_TAILCALL(const BinaryNinja::HighLevelIL return PseudoCFunction::GetExpr_CALL_OR_TAILCALL(instr, tokens, settings, precedence, statement); } -bool PseudoObjCFunction::GetExpr_ObjCMsgSend(const HighLevelILInstruction& instr, HighLevelILTokenEmitter& tokens, - DisassemblySettings* settings, const std::vector<HighLevelILInstruction>& parameterExprs) +bool PseudoObjCFunction::GetExpr_ObjCMsgSend(uint64_t msgSendAddress, bool isRewritten, + const HighLevelILInstruction& instr, HighLevelILTokenEmitter& tokens, DisassemblySettings* settings, + const std::vector<HighLevelILInstruction>& parameterExprs) { if (parameterExprs.size() < 2) return false; @@ -238,6 +274,8 @@ bool PseudoObjCFunction::GetExpr_ObjCMsgSend(const HighLevelILInstruction& instr std::vector<std::string> selectorTokens {2}; SplitSelector(selector, selectorTokens); + uint64_t referencedAddress = isRewritten ? msgSendAddress : selectorAddress; + tokens.AppendOpenBracket(); GetExprText(parameterExprs[0], tokens, settings); @@ -249,7 +287,7 @@ bool PseudoObjCFunction::GetExpr_ObjCMsgSend(const HighLevelILInstruction& instr if (index < selectorTokens.size()) { tokens.Append( - DataSymbolToken, StringReferenceTokenContext, selectorTokens[index], instr.address, selectorAddress); + DataSymbolToken, StringReferenceTokenContext, selectorTokens[index], instr.address, referencedAddress); tokens.Append(TextToken, ":"); } else @@ -264,7 +302,7 @@ bool PseudoObjCFunction::GetExpr_ObjCMsgSend(const HighLevelILInstruction& instr for (size_t index = parameterExprs.size(); index < selectorTokens.size(); index++) { tokens.Append( - DataSymbolToken, StringReferenceTokenContext, selectorTokens[index], instr.address, selectorAddress); + DataSymbolToken, StringReferenceTokenContext, selectorTokens[index], instr.address, referencedAddress); if (index != selectorTokens.size() - 1 || selector.back() == ':') tokens.Append(TextToken, ":"); } diff --git a/lang/c/pseudoobjc.h b/lang/c/pseudoobjc.h index 4b87c7d7..9910c4b8 100644 --- a/lang/c/pseudoobjc.h +++ b/lang/c/pseudoobjc.h @@ -22,7 +22,7 @@ protected: BNOperatorPrecedence precedence, bool statement) override; private: - bool GetExpr_ObjCMsgSend(const BinaryNinja::HighLevelILInstruction& expr, + bool GetExpr_ObjCMsgSend(uint64_t msgSendAddress, bool isRewritten, const BinaryNinja::HighLevelILInstruction& expr, BinaryNinja::HighLevelILTokenEmitter& tokens, BinaryNinja::DisassemblySettings* settings, const std::vector<BinaryNinja::HighLevelILInstruction>& parameterExprs); bool GetExpr_GenericObjCRuntimeCall(uint64_t address, const BinaryNinja::HighLevelILInstruction& expr, |
