Skip to content

Commit 7240294

Browse files
committed
Implement a Pseudo Objective-C language representation
This is implemented in the Pseudo C plug-in as it shares 99% of the logic. The Objective-C support is implemented in a subclass of `PseudoCFunction`. The handling of instruction types that the Objective-C representation needs to customize is extracted into virtual functions that the Objective-C subclass overrides. This currently supports: * Rewriting `objc_msgSend` / `objc_msgSendSuper2` with constant selectors to `[receiver message]` notation. * Rewriting calls to `objc_alloc` / `objc_alloc_init` / `objc_new` to the equivalent message send notation. * Rewriting `objc_retain` / `objc_release` and friends to the equivalent message send notation. * Displaying Objective-C class references as their class names rather than `_OBJC_CLASS_$_` symbol names. * Displaying Objective-C string literals as `@"..."`. This works best when used in conjunction with https://github.com/bdash/bn-objc-extras as the reference counting runtime calls add so much clutter.
1 parent f9ac749 commit 7240294

File tree

5 files changed

+593
-102
lines changed

5 files changed

+593
-102
lines changed

lang/c/plugin.cpp

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#include "binaryninjaapi.h"
2+
#include "pseudoc.h"
3+
#include "pseudoobjc.h"
4+
5+
using namespace BinaryNinja;
6+
7+
extern "C"
8+
{
9+
BN_DECLARE_CORE_ABI_VERSION
10+
11+
#ifndef DEMO_EDITION
12+
BINARYNINJAPLUGIN void CorePluginDependencies()
13+
{
14+
}
15+
#endif
16+
17+
#ifdef DEMO_EDITION
18+
bool PseudoCPluginInit()
19+
#else
20+
BINARYNINJAPLUGIN bool CorePluginInit()
21+
#endif
22+
{
23+
LanguageRepresentationFunctionType* type = new PseudoCFunctionType();
24+
LanguageRepresentationFunctionType::Register(type);
25+
26+
type = new PseudoObjCFunctionType();
27+
LanguageRepresentationFunctionType::Register(type);
28+
return true;
29+
}
30+
}

lang/c/pseudoc.cpp

+88-102
Original file line numberDiff line numberDiff line change
@@ -976,73 +976,11 @@ void PseudoCFunction::GetExprTextInternal(const HighLevelILInstruction& instr, H
976976
break;
977977

978978
case HLIL_CALL:
979-
[&]() {
980-
const auto destExpr = instr.GetDestExpr<HLIL_CALL>();
981-
const auto parameterExprs = instr.GetParameterExprs<HLIL_CALL>();
982-
983-
GetExprTextInternal(destExpr, tokens, settings, MemberAndFunctionOperatorPrecedence);
984-
tokens.AppendOpenParen();
985-
986-
vector<FunctionParameter> namedParams;
987-
Ref<Type> functionType = instr.GetDestExpr<HLIL_CALL>().GetType();
988-
if (functionType && (functionType->GetClass() == PointerTypeClass)
989-
&& (functionType->GetChildType()->GetClass() == FunctionTypeClass))
990-
namedParams = functionType->GetChildType()->GetParameters();
991-
992-
for (size_t index{}; index < parameterExprs.size(); index++)
993-
{
994-
const auto& parameterExpr = parameterExprs[index];
995-
if (index != 0) tokens.Append(TextToken, ", ");
996-
997-
// If the type of the parameter is known to be a pointer to a string, then we directly render it as a
998-
// string, regardless of its length
999-
bool renderedAsString = false;
1000-
if (index < namedParams.size() && parameterExprs[index].operation == HLIL_CONST_PTR)
1001-
{
1002-
auto exprType = namedParams[index].type;
1003-
if (exprType && (exprType->GetClass() == PointerTypeClass))
1004-
{
1005-
if (auto child = exprType->GetChildType(); child)
1006-
{
1007-
if ((child->IsInteger() && child->IsSigned() && child->GetWidth() == 1)
1008-
|| child->IsWideChar())
1009-
{
1010-
tokens.AppendPointerTextToken(parameterExprs[index],
1011-
parameterExprs[index].GetConstant<HLIL_CONST_PTR>(), settings, AddressOfDataSymbols,
1012-
precedence, true);
1013-
renderedAsString = true;
1014-
}
1015-
}
1016-
}
1017-
}
1018-
1019-
if (!renderedAsString)
1020-
GetExprText(parameterExpr, tokens, settings);
1021-
}
1022-
tokens.AppendCloseParen();
1023-
if (statement)
1024-
tokens.AppendSemicolon();
1025-
}();
979+
GetExpr_CALL_OR_TAILCALL(instr, tokens, settings, precedence, statement);
1026980
break;
1027981

1028982
case HLIL_IMPORT:
1029-
[&]() {
1030-
const auto constant = instr.GetConstant<HLIL_IMPORT>();
1031-
auto symbol = GetHighLevelILFunction()->GetFunction()->GetView()->GetSymbolByAddress(constant);
1032-
const auto symbolType = symbol->GetType();
1033-
1034-
if (symbol && (symbolType == ImportedDataSymbol || symbolType == ImportAddressSymbol))
1035-
{
1036-
symbol = Symbol::ImportedFunctionFromImportAddressSymbol(symbol, constant);
1037-
const auto symbolShortName = symbol->GetShortName();
1038-
tokens.Append(IndirectImportToken, NoTokenContext, symbolShortName, instr.address, constant, instr.size, instr.sourceOperand);
1039-
return;
1040-
}
1041-
1042-
tokens.AppendPointerTextToken(instr, constant, settings, DereferenceNonDataSymbols, precedence);
1043-
if (statement)
1044-
tokens.AppendSemicolon();
1045-
}();
983+
GetExpr_IMPORT(instr, tokens, settings, precedence, statement);
1046984
break;
1047985

1048986
case HLIL_ARRAY_INDEX:
@@ -1288,12 +1226,7 @@ void PseudoCFunction::GetExprTextInternal(const HighLevelILInstruction& instr, H
12881226
break;
12891227

12901228
case HLIL_CONST_PTR:
1291-
[&]() {
1292-
tokens.AppendPointerTextToken(
1293-
instr, instr.GetConstant<HLIL_CONST_PTR>(), settings, AddressOfDataSymbols, precedence);
1294-
if (statement)
1295-
tokens.AppendSemicolon();
1296-
}();
1229+
GetExpr_CONST_PTR(instr, tokens, settings, precedence, statement);
12971230
break;
12981231

12991232
case HLIL_VAR:
@@ -1766,17 +1699,8 @@ void PseudoCFunction::GetExprTextInternal(const HighLevelILInstruction& instr, H
17661699
tokens.Append(AnnotationToken, "/* tailcall */");
17671700
tokens.NewLine();
17681701
tokens.Append(KeywordToken, "return ");
1769-
GetExprTextInternal(destExpr, tokens, settings, MemberAndFunctionOperatorPrecedence);
1770-
tokens.AppendOpenParen();
1771-
for (size_t index{}; index < parameterExprs.size(); index++)
1772-
{
1773-
const auto& parameterExpr = parameterExprs[index];
1774-
if (index != 0) tokens.Append(TextToken, ", ");
1775-
GetExprTextInternal(parameterExpr, tokens, settings);
1776-
}
1777-
tokens.AppendCloseParen();
1778-
if (statement)
1779-
tokens.AppendSemicolon();
1702+
1703+
GetExpr_CALL_OR_TAILCALL(instr, tokens, settings, precedence, statement);
17801704
}();
17811705
break;
17821706

@@ -2800,6 +2724,88 @@ void PseudoCFunction::GetExprTextInternal(const HighLevelILInstruction& instr, H
28002724
}
28012725
}
28022726

2727+
void PseudoCFunction::GetExpr_CALL_OR_TAILCALL(const BinaryNinja::HighLevelILInstruction& instr,
2728+
BinaryNinja::HighLevelILTokenEmitter& tokens, BinaryNinja::DisassemblySettings* settings,
2729+
BNOperatorPrecedence precedence, bool statement)
2730+
{
2731+
const auto destExpr = instr.GetDestExpr();
2732+
const auto parameterExprs = instr.GetParameterExprs();
2733+
2734+
vector<FunctionParameter> namedParams;
2735+
Ref<Type> functionType = destExpr.GetType();
2736+
if (functionType && (functionType->GetClass() == PointerTypeClass)
2737+
&& (functionType->GetChildType()->GetClass() == FunctionTypeClass))
2738+
namedParams = functionType->GetChildType()->GetParameters();
2739+
2740+
GetExprTextInternal(destExpr, tokens, settings, MemberAndFunctionOperatorPrecedence);
2741+
tokens.AppendOpenParen();
2742+
2743+
for (size_t index {}; index < parameterExprs.size(); index++)
2744+
{
2745+
const auto& parameterExpr = parameterExprs[index];
2746+
if (index != 0)
2747+
tokens.Append(TextToken, ", ");
2748+
2749+
// If the type of the parameter is known to be a pointer to a string, then we directly render it as a
2750+
// string, regardless of its length
2751+
bool renderedAsString = false;
2752+
if (index < namedParams.size() && parameterExprs[index].operation == HLIL_CONST_PTR)
2753+
{
2754+
auto exprType = namedParams[index].type;
2755+
if (exprType && (exprType->GetClass() == PointerTypeClass))
2756+
{
2757+
if (auto child = exprType->GetChildType(); child)
2758+
{
2759+
if ((child->IsInteger() && child->IsSigned() && child->GetWidth() == 1) || child->IsWideChar())
2760+
{
2761+
tokens.AppendPointerTextToken(parameterExprs[index],
2762+
parameterExprs[index].GetConstant<HLIL_CONST_PTR>(), settings, AddressOfDataSymbols,
2763+
precedence, true);
2764+
renderedAsString = true;
2765+
}
2766+
}
2767+
}
2768+
}
2769+
2770+
if (!renderedAsString)
2771+
GetExprText(parameterExpr, tokens, settings);
2772+
}
2773+
tokens.AppendCloseParen();
2774+
if (statement)
2775+
tokens.AppendSemicolon();
2776+
}
2777+
2778+
void PseudoCFunction::GetExpr_CONST_PTR(const BinaryNinja::HighLevelILInstruction& instr,
2779+
BinaryNinja::HighLevelILTokenEmitter& tokens, BinaryNinja::DisassemblySettings* settings,
2780+
BNOperatorPrecedence precedence, bool statement)
2781+
{
2782+
auto constant = instr.GetConstant<HLIL_CONST_PTR>();
2783+
tokens.AppendPointerTextToken(
2784+
instr, instr.GetConstant<HLIL_CONST_PTR>(), settings, AddressOfDataSymbols, precedence);
2785+
if (statement)
2786+
tokens.AppendSemicolon();
2787+
}
2788+
2789+
void PseudoCFunction::GetExpr_IMPORT(const BinaryNinja::HighLevelILInstruction& instr,
2790+
BinaryNinja::HighLevelILTokenEmitter& tokens, BinaryNinja::DisassemblySettings* settings,
2791+
BNOperatorPrecedence precedence, bool statement)
2792+
{
2793+
const auto constant = instr.GetConstant<HLIL_IMPORT>();
2794+
auto symbol = GetHighLevelILFunction()->GetFunction()->GetView()->GetSymbolByAddress(constant);
2795+
const auto symbolType = symbol->GetType();
2796+
2797+
if (symbol && (symbolType == ImportedDataSymbol || symbolType == ImportAddressSymbol))
2798+
{
2799+
symbol = Symbol::ImportedFunctionFromImportAddressSymbol(symbol, constant);
2800+
const auto symbolShortName = symbol->GetShortName();
2801+
tokens.Append(IndirectImportToken, NoTokenContext, symbolShortName, instr.address, constant, instr.size, instr.sourceOperand);
2802+
return;
2803+
}
2804+
2805+
tokens.AppendPointerTextToken(instr, constant, settings, DereferenceNonDataSymbols, precedence);
2806+
if (statement)
2807+
tokens.AppendSemicolon();
2808+
}
28032809

28042810
string PseudoCFunction::GetAnnotationStartString() const
28052811
{
@@ -2819,32 +2825,12 @@ PseudoCFunctionType::PseudoCFunctionType(): LanguageRepresentationFunctionType("
28192825
{
28202826
}
28212827

2828+
PseudoCFunctionType::PseudoCFunctionType(const string& name) : LanguageRepresentationFunctionType(name) {}
28222829

28232830
Ref<LanguageRepresentationFunction> PseudoCFunctionType::Create(Architecture* arch, Function* owner,
28242831
HighLevelILFunction* highLevelILFunction)
28252832
{
28262833
return new PseudoCFunction(this, arch, owner, highLevelILFunction);
28272834
}
28282835

2829-
2830-
extern "C"
28312836
{
2832-
BN_DECLARE_CORE_ABI_VERSION
2833-
2834-
#ifndef DEMO_EDITION
2835-
BINARYNINJAPLUGIN void CorePluginDependencies()
2836-
{
2837-
}
2838-
#endif
2839-
2840-
#ifdef DEMO_EDITION
2841-
bool PseudoCPluginInit()
2842-
#else
2843-
BINARYNINJAPLUGIN bool CorePluginInit()
2844-
#endif
2845-
{
2846-
LanguageRepresentationFunctionType* type = new PseudoCFunctionType();
2847-
LanguageRepresentationFunctionType::Register(type);
2848-
return true;
2849-
}
2850-
}

lang/c/pseudoc.h

+13
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,16 @@ class PseudoCFunction: public BinaryNinja::LanguageRepresentationFunction
5252
void EndLines(
5353
const BinaryNinja::HighLevelILInstruction& instr, BinaryNinja::HighLevelILTokenEmitter& tokens) override;
5454

55+
virtual void GetExpr_CALL_OR_TAILCALL(const BinaryNinja::HighLevelILInstruction& instr,
56+
BinaryNinja::HighLevelILTokenEmitter& tokens, BinaryNinja::DisassemblySettings* settings,
57+
BNOperatorPrecedence precedence, bool statement);
58+
virtual void GetExpr_CONST_PTR(const BinaryNinja::HighLevelILInstruction& instr,
59+
BinaryNinja::HighLevelILTokenEmitter& tokens, BinaryNinja::DisassemblySettings* settings,
60+
BNOperatorPrecedence precedence, bool statement);
61+
virtual void GetExpr_IMPORT(const BinaryNinja::HighLevelILInstruction& instr,
62+
BinaryNinja::HighLevelILTokenEmitter& tokens, BinaryNinja::DisassemblySettings* settings,
63+
BNOperatorPrecedence precedence, bool statement);
64+
5565
public:
5666
PseudoCFunction(BinaryNinja::LanguageRepresentationFunctionType* type, BinaryNinja::Architecture* arch,
5767
BinaryNinja::Function* owner, BinaryNinja::HighLevelILFunction* highLevelILFunction);
@@ -66,4 +76,7 @@ class PseudoCFunctionType: public BinaryNinja::LanguageRepresentationFunctionTyp
6676
PseudoCFunctionType();
6777
BinaryNinja::Ref<BinaryNinja::LanguageRepresentationFunction> Create(BinaryNinja::Architecture* arch,
6878
BinaryNinja::Function* owner, BinaryNinja::HighLevelILFunction* highLevelILFunction) override;
79+
80+
protected:
81+
PseudoCFunctionType(const std::string& name);
6982
};

0 commit comments

Comments
 (0)