@@ -188,6 +188,46 @@ std::optional<RuntimeCall> DetectRewrittenDirectObjCMethodCall(const HighLevelIL
188188 return RuntimeCall {RuntimeCall::MessageSend, constant, true };
189189}
190190
191+ bool VariableIsObjCSuperStruct (const Variable& variable, Function& function)
192+ {
193+ auto variableName = function.GetVariableName (variable);
194+ if (variableName != " super" )
195+ return false ;
196+
197+ const auto variableType = function.GetVariableType (variable);
198+ if (!variableType || !variableType->IsNamedTypeRefer ())
199+ return false ;
200+
201+ const auto namedType = function.GetView ()->GetTypeByRef (variableType->GetNamedTypeReference ());
202+ if (!namedType || namedType->GetClass () != StructureTypeClass)
203+ return false ;
204+
205+ if (namedType->GetStructureName ().GetString () != " objc_super" )
206+ return false ;
207+
208+ return true ;
209+ }
210+
211+ bool IsAssignmentToObjCSuperStructField (const HighLevelILInstruction& assignInstr, Function& function)
212+ {
213+ // Check if this is an assignment to a field of the objc_super struct
214+ // Pattern: HLIL_ASSIGN { dest = HLIL_STRUCT_FIELD { source = HLIL_VAR { super }, }, field = ... }
215+
216+ if (assignInstr.operation != HLIL_ASSIGN)
217+ return false ;
218+
219+ const auto destExpr = assignInstr.GetDestExpr ();
220+ if (destExpr.operation != HLIL_STRUCT_FIELD)
221+ return false ;
222+
223+ const auto sourceExpr = destExpr.GetSourceExpr ();
224+ if (sourceExpr.operation != HLIL_VAR)
225+ return false ;
226+
227+ auto variable = sourceExpr.GetVariable <HLIL_VAR>();
228+ return VariableIsObjCSuperStruct (variable, function);
229+ }
230+
191231} // unnamed namespace
192232
193233PseudoObjCFunction::PseudoObjCFunction (LanguageRepresentationFunctionType* type, Architecture* arch, Function* owner,
@@ -213,7 +253,8 @@ void PseudoObjCFunction::GetExpr_CALL_OR_TAILCALL(const BinaryNinja::HighLevelIL
213253 {
214254 case RuntimeCall::MessageSend:
215255 case RuntimeCall::MessageSendSuper:
216- if (GetExpr_ObjCMsgSend (objCRuntimeCall->address , objCRuntimeCall->isRewritten , destExpr, tokens, settings, parameterExprs))
256+ if (GetExpr_ObjCMsgSend (objCRuntimeCall->address , objCRuntimeCall->type == RuntimeCall::MessageSendSuper,
257+ objCRuntimeCall->isRewritten , destExpr, tokens, settings, parameterExprs))
217258 {
218259 if (statement)
219260 tokens.AppendSemicolon ();
@@ -260,7 +301,7 @@ void PseudoObjCFunction::GetExpr_CALL_OR_TAILCALL(const BinaryNinja::HighLevelIL
260301 return PseudoCFunction::GetExpr_CALL_OR_TAILCALL (instr, tokens, settings, precedence, statement);
261302}
262303
263- bool PseudoObjCFunction::GetExpr_ObjCMsgSend (uint64_t msgSendAddress, bool isRewritten,
304+ bool PseudoObjCFunction::GetExpr_ObjCMsgSend (uint64_t msgSendAddress, bool isSuper, bool isRewritten,
264305 const HighLevelILInstruction& instr, HighLevelILTokenEmitter& tokens, DisassemblySettings* settings,
265306 const std::vector<HighLevelILInstruction>& parameterExprs)
266307{
@@ -279,7 +320,10 @@ bool PseudoObjCFunction::GetExpr_ObjCMsgSend(uint64_t msgSendAddress, bool isRew
279320
280321 tokens.AppendOpenBracket ();
281322
282- GetExprText (parameterExprs[0 ], tokens, settings);
323+ if (isSuper)
324+ tokens.Append (LocalVariableToken, " super" , instr.address );
325+ else
326+ GetExprText (parameterExprs[0 ], tokens, settings);
283327
284328 for (size_t index = 2 ; index < parameterExprs.size (); index++)
285329 {
@@ -428,7 +472,7 @@ void PseudoObjCFunction::GetExpr_IMPORT(const BinaryNinja::HighLevelILInstructio
428472 BNOperatorPrecedence precedence, bool statement)
429473{
430474 const auto constant = instr.GetConstant <HLIL_IMPORT>();
431- auto symbol = GetHighLevelILFunction ()-> GetFunction ()->GetView ()->GetSymbolByAddress (constant);
475+ auto symbol = GetFunction ()->GetView ()->GetSymbolByAddress (constant);
432476 const auto symbolType = symbol->GetType ();
433477
434478 if (symbol && (symbolType == ImportedDataSymbol || symbolType == ImportAddressSymbol))
@@ -450,6 +494,28 @@ void PseudoObjCFunction::GetExpr_IMPORT(const BinaryNinja::HighLevelILInstructio
450494 PseudoCFunction::GetExpr_IMPORT (instr, tokens, settings, precedence, statement);
451495}
452496
497+ bool PseudoObjCFunction::ShouldSkipStatement (const BinaryNinja::HighLevelILInstruction& instr)
498+ {
499+ // Skip statements that are compiler-generated artifacts of Objective-C runtime calls
500+ // For now this is limited to the declaration / initialization of the `objc_super` variable
501+ // used for `objc_msgSendSuper` calls.
502+ switch (instr.operation )
503+ {
504+ case HLIL_VAR_DECLARE:
505+ if (VariableIsObjCSuperStruct (instr.GetVariable <HLIL_VAR_DECLARE>(), *GetFunction ()))
506+ return true ;
507+ break ;
508+ case HLIL_ASSIGN:
509+ if (IsAssignmentToObjCSuperStructField (instr, *GetFunction ()))
510+ return true ;
511+ break ;
512+ default :
513+ break ;
514+ }
515+
516+ return PseudoCFunction::ShouldSkipStatement (instr);
517+ }
518+
453519
454520PseudoObjCFunctionType::PseudoObjCFunctionType () : PseudoCFunctionType(" Pseudo Objective-C" ) {}
455521
0 commit comments