@@ -60,6 +60,43 @@ void SplitSelector(const std::string& selector, std::vector<std::string>& tokens
60
60
tokens.push_back (token);
61
61
}
62
62
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
+
63
100
struct RuntimeCall
64
101
{
65
102
enum Type
@@ -78,6 +115,7 @@ struct RuntimeCall
78
115
79
116
Type type;
80
117
uint64_t address;
118
+ bool isRewritten = false ;
81
119
};
82
120
83
121
constexpr std::array RUNTIME_CALLS = {
@@ -114,36 +152,10 @@ constexpr std::array RUNTIME_CALLS = {
114
152
std::optional<RuntimeCall> DetectObjCRuntimeCall (const HighLevelILInstruction& callTarget,
115
153
const std::vector<HighLevelILInstruction>& parameterExprs, const Function& function)
116
154
{
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)
146
157
return std::nullopt;
158
+ auto [constant, symbol] = callTargetInfo.value ();
147
159
148
160
const auto symbolShortName = symbol->GetShortName ();
149
161
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
155
167
return RuntimeCall {it->second , constant};
156
168
}
157
169
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
+
158
190
} // unnamed namespace
159
191
160
192
PseudoObjCFunction::PseudoObjCFunction (LanguageRepresentationFunctionType* type, Architecture* arch, Function* owner,
@@ -169,6 +201,9 @@ void PseudoObjCFunction::GetExpr_CALL_OR_TAILCALL(const BinaryNinja::HighLevelIL
169
201
const auto parameterExprs = instr.GetParameterExprs ();
170
202
171
203
auto objCRuntimeCall = DetectObjCRuntimeCall (destExpr, parameterExprs, *GetFunction ());
204
+ if (!objCRuntimeCall)
205
+ objCRuntimeCall = DetectRewrittenDirectObjCMethodCall (destExpr, parameterExprs, *GetFunction ());
206
+
172
207
if (!objCRuntimeCall)
173
208
return PseudoCFunction::GetExpr_CALL_OR_TAILCALL (instr, tokens, settings, precedence, statement);
174
209
@@ -177,7 +212,7 @@ void PseudoObjCFunction::GetExpr_CALL_OR_TAILCALL(const BinaryNinja::HighLevelIL
177
212
{
178
213
case RuntimeCall::MessageSend:
179
214
case RuntimeCall::MessageSendSuper:
180
- if (GetExpr_ObjCMsgSend (destExpr, tokens, settings, parameterExprs))
215
+ if (GetExpr_ObjCMsgSend (objCRuntimeCall-> address , objCRuntimeCall-> isRewritten , destExpr, tokens, settings, parameterExprs))
181
216
{
182
217
if (statement)
183
218
tokens.AppendSemicolon ();
@@ -224,8 +259,9 @@ void PseudoObjCFunction::GetExpr_CALL_OR_TAILCALL(const BinaryNinja::HighLevelIL
224
259
return PseudoCFunction::GetExpr_CALL_OR_TAILCALL (instr, tokens, settings, precedence, statement);
225
260
}
226
261
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)
229
265
{
230
266
if (parameterExprs.size () < 2 )
231
267
return false ;
@@ -238,6 +274,8 @@ bool PseudoObjCFunction::GetExpr_ObjCMsgSend(const HighLevelILInstruction& instr
238
274
std::vector<std::string> selectorTokens {2 };
239
275
SplitSelector (selector, selectorTokens);
240
276
277
+ uint64_t referencedAddress = isRewritten ? msgSendAddress : selectorAddress;
278
+
241
279
tokens.AppendOpenBracket ();
242
280
243
281
GetExprText (parameterExprs[0 ], tokens, settings);
@@ -249,7 +287,7 @@ bool PseudoObjCFunction::GetExpr_ObjCMsgSend(const HighLevelILInstruction& instr
249
287
if (index < selectorTokens.size ())
250
288
{
251
289
tokens.Append (
252
- DataSymbolToken, StringReferenceTokenContext, selectorTokens[index ], instr.address , selectorAddress );
290
+ DataSymbolToken, StringReferenceTokenContext, selectorTokens[index ], instr.address , referencedAddress );
253
291
tokens.Append (TextToken, " :" );
254
292
}
255
293
else
@@ -264,7 +302,7 @@ bool PseudoObjCFunction::GetExpr_ObjCMsgSend(const HighLevelILInstruction& instr
264
302
for (size_t index = parameterExprs.size (); index < selectorTokens.size (); index ++)
265
303
{
266
304
tokens.Append (
267
- DataSymbolToken, StringReferenceTokenContext, selectorTokens[index ], instr.address , selectorAddress );
305
+ DataSymbolToken, StringReferenceTokenContext, selectorTokens[index ], instr.address , referencedAddress );
268
306
if (index != selectorTokens.size () - 1 || selector.back () == ' :' )
269
307
tokens.Append (TextToken, " :" );
270
308
}
0 commit comments