@@ -60,6 +60,43 @@ void SplitSelector(const std::string& selector, std::vector<std::string>& tokens
6060 tokens.push_back (token);
6161}
6262
63+ std::optional<std::pair<uint64_t , Ref<Symbol>>> GetCallTargetInfo (const HighLevelILInstruction& callTarget,
64+ const std::vector<HighLevelILInstruction>& parameterExprs, const Function& function)
65+ {
66+ uint64_t constant = 0 ;
67+ Ref<Symbol> symbol;
68+
69+ switch (callTarget.operation )
70+ {
71+ case HLIL_CONST_PTR:
72+ {
73+ constant = callTarget.GetConstant <HLIL_CONST_PTR>();
74+ symbol = function.GetView ()->GetSymbolByAddress (constant);
75+ break ;
76+ }
77+ case HLIL_IMPORT:
78+ {
79+ constant = callTarget.GetConstant <HLIL_IMPORT>();
80+ auto importAddressSymbol = function.GetView ()->GetSymbolByAddress (constant);
81+ if (!importAddressSymbol)
82+ return std::nullopt ;
83+
84+ const auto symbolType = importAddressSymbol->GetType ();
85+ if (symbolType != ImportedDataSymbol && symbolType != ImportAddressSymbol)
86+ return std::nullopt ;
87+
88+ symbol = Symbol::ImportedFunctionFromImportAddressSymbol (importAddressSymbol, constant);
89+ }
90+ default :
91+ break ;
92+ }
93+
94+ if (!symbol)
95+ return std::nullopt ;
96+
97+ return std::make_pair (constant, symbol);
98+ }
99+
63100struct RuntimeCall
64101{
65102 enum Type
@@ -78,6 +115,7 @@ struct RuntimeCall
78115
79116 Type type;
80117 uint64_t address;
118+ bool isRewritten = false ;
81119};
82120
83121constexpr std::array RUNTIME_CALLS = {
@@ -114,36 +152,10 @@ constexpr std::array RUNTIME_CALLS = {
114152std::optional<RuntimeCall> DetectObjCRuntimeCall (const HighLevelILInstruction& callTarget,
115153 const std::vector<HighLevelILInstruction>& parameterExprs, const Function& function)
116154{
117- uint64_t constant = 0 ;
118- Ref<Symbol> symbol;
119-
120- switch (callTarget.operation )
121- {
122- case HLIL_CONST_PTR:
123- {
124- constant = callTarget.GetConstant <HLIL_CONST_PTR>();
125- symbol = function.GetView ()->GetSymbolByAddress (constant);
126- break ;
127- }
128- case HLIL_IMPORT:
129- {
130- constant = callTarget.GetConstant <HLIL_IMPORT>();
131- auto importAddressSymbol = function.GetView ()->GetSymbolByAddress (constant);
132- if (!importAddressSymbol)
133- return std::nullopt ;
134-
135- const auto symbolType = importAddressSymbol->GetType ();
136- if (symbolType != ImportedDataSymbol && symbolType != ImportAddressSymbol)
137- return std::nullopt ;
138-
139- symbol = Symbol::ImportedFunctionFromImportAddressSymbol (importAddressSymbol, constant);
140- }
141- default :
142- break ;
143- }
144-
145- if (!symbol)
155+ auto callTargetInfo = GetCallTargetInfo (callTarget, parameterExprs, function);
156+ if (!callTargetInfo)
146157 return std::nullopt ;
158+ auto [constant, symbol] = callTargetInfo.value ();
147159
148160 const auto symbolShortName = symbol->GetShortName ();
149161 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
155167 return RuntimeCall {it->second , constant};
156168}
157169
170+ std::optional<RuntimeCall> DetectRewrittenDirectObjCMethodCall (const HighLevelILInstruction& callTarget,
171+ const std::vector<HighLevelILInstruction>& parameterExprs, const Function& function)
172+ {
173+ auto callTargetInfo = GetCallTargetInfo (callTarget, parameterExprs, function);
174+ if (!callTargetInfo)
175+ return std::nullopt ;
176+ auto [constant, symbol] = callTargetInfo.value ();
177+
178+ const auto symbolShortName = symbol->GetShortName ();
179+ if (symbolShortName.length () < 6 )
180+ return std::nullopt ;
181+
182+ // Look for the pattern -[ClassName methodName:] or +[ClassName methodName:]
183+ if ((symbolShortName[0 ] != ' -' && symbolShortName[0 ] != ' +' ) || symbolShortName[1 ] != ' ['
184+ || symbolShortName.back () != ' ]' || symbolShortName.find (' ' ) == std::string::npos)
185+ return std::nullopt ;
186+
187+ return RuntimeCall {RuntimeCall::MessageSend, constant, true };
188+ }
189+
158190} // unnamed namespace
159191
160192PseudoObjCFunction::PseudoObjCFunction (LanguageRepresentationFunctionType* type, Architecture* arch, Function* owner,
@@ -169,6 +201,9 @@ void PseudoObjCFunction::GetExpr_CALL_OR_TAILCALL(const BinaryNinja::HighLevelIL
169201 const auto parameterExprs = instr.GetParameterExprs ();
170202
171203 auto objCRuntimeCall = DetectObjCRuntimeCall (destExpr, parameterExprs, *GetFunction ());
204+ if (!objCRuntimeCall)
205+ objCRuntimeCall = DetectRewrittenDirectObjCMethodCall (destExpr, parameterExprs, *GetFunction ());
206+
172207 if (!objCRuntimeCall)
173208 return PseudoCFunction::GetExpr_CALL_OR_TAILCALL (instr, tokens, settings, precedence, statement);
174209
@@ -177,7 +212,7 @@ void PseudoObjCFunction::GetExpr_CALL_OR_TAILCALL(const BinaryNinja::HighLevelIL
177212 {
178213 case RuntimeCall::MessageSend:
179214 case RuntimeCall::MessageSendSuper:
180- if (GetExpr_ObjCMsgSend (destExpr, tokens, settings, parameterExprs))
215+ if (GetExpr_ObjCMsgSend (objCRuntimeCall-> address , objCRuntimeCall-> isRewritten , destExpr, tokens, settings, parameterExprs))
181216 {
182217 if (statement)
183218 tokens.AppendSemicolon ();
@@ -224,8 +259,9 @@ void PseudoObjCFunction::GetExpr_CALL_OR_TAILCALL(const BinaryNinja::HighLevelIL
224259 return PseudoCFunction::GetExpr_CALL_OR_TAILCALL (instr, tokens, settings, precedence, statement);
225260}
226261
227- bool PseudoObjCFunction::GetExpr_ObjCMsgSend (const HighLevelILInstruction& instr, HighLevelILTokenEmitter& tokens,
228- DisassemblySettings* settings, const std::vector<HighLevelILInstruction>& parameterExprs)
262+ bool PseudoObjCFunction::GetExpr_ObjCMsgSend (uint64_t msgSendAddress, bool isRewritten,
263+ const HighLevelILInstruction& instr, HighLevelILTokenEmitter& tokens, DisassemblySettings* settings,
264+ const std::vector<HighLevelILInstruction>& parameterExprs)
229265{
230266 if (parameterExprs.size () < 2 )
231267 return false ;
@@ -238,6 +274,8 @@ bool PseudoObjCFunction::GetExpr_ObjCMsgSend(const HighLevelILInstruction& instr
238274 std::vector<std::string> selectorTokens {2 };
239275 SplitSelector (selector, selectorTokens);
240276
277+ uint64_t referencedAddress = isRewritten ? msgSendAddress : selectorAddress;
278+
241279 tokens.AppendOpenBracket ();
242280
243281 GetExprText (parameterExprs[0 ], tokens, settings);
@@ -249,7 +287,7 @@ bool PseudoObjCFunction::GetExpr_ObjCMsgSend(const HighLevelILInstruction& instr
249287 if (index < selectorTokens.size ())
250288 {
251289 tokens.Append (
252- DataSymbolToken, StringReferenceTokenContext, selectorTokens[index], instr.address , selectorAddress );
290+ DataSymbolToken, StringReferenceTokenContext, selectorTokens[index], instr.address , referencedAddress );
253291 tokens.Append (TextToken, " :" );
254292 }
255293 else
@@ -264,7 +302,7 @@ bool PseudoObjCFunction::GetExpr_ObjCMsgSend(const HighLevelILInstruction& instr
264302 for (size_t index = parameterExprs.size (); index < selectorTokens.size (); index++)
265303 {
266304 tokens.Append (
267- DataSymbolToken, StringReferenceTokenContext, selectorTokens[index], instr.address , selectorAddress );
305+ DataSymbolToken, StringReferenceTokenContext, selectorTokens[index], instr.address , referencedAddress );
268306 if (index != selectorTokens.size () - 1 || selector.back () == ' :' )
269307 tokens.Append (TextToken, " :" );
270308 }
0 commit comments