Skip to content

Commit 4ea37e1

Browse files
bdash0cyn
authored andcommitted
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 c55c604 commit 4ea37e1

File tree

5 files changed

+596
-104
lines changed

5 files changed

+596
-104
lines changed

lang/c/plugin.cpp

Lines changed: 30 additions & 0 deletions
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

Lines changed: 88 additions & 104 deletions
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

@@ -2829,6 +2753,88 @@ void PseudoCFunction::GetExprTextInternal(const HighLevelILInstruction& instr, H
28292753
}
28302754
}
28312755

2756+
void PseudoCFunction::GetExpr_CALL_OR_TAILCALL(const BinaryNinja::HighLevelILInstruction& instr,
2757+
BinaryNinja::HighLevelILTokenEmitter& tokens, BinaryNinja::DisassemblySettings* settings,
2758+
BNOperatorPrecedence precedence, bool statement)
2759+
{
2760+
const auto destExpr = instr.GetDestExpr();
2761+
const auto parameterExprs = instr.GetParameterExprs();
2762+
2763+
vector<FunctionParameter> namedParams;
2764+
Ref<Type> functionType = destExpr.GetType();
2765+
if (functionType && (functionType->GetClass() == PointerTypeClass)
2766+
&& (functionType->GetChildType()->GetClass() == FunctionTypeClass))
2767+
namedParams = functionType->GetChildType()->GetParameters();
2768+
2769+
GetExprTextInternal(destExpr, tokens, settings, MemberAndFunctionOperatorPrecedence);
2770+
tokens.AppendOpenParen();
2771+
2772+
for (size_t index {}; index < parameterExprs.size(); index++)
2773+
{
2774+
const auto& parameterExpr = parameterExprs[index];
2775+
if (index != 0)
2776+
tokens.Append(TextToken, ", ");
2777+
2778+
// If the type of the parameter is known to be a pointer to a string, then we directly render it as a
2779+
// string, regardless of its length
2780+
bool renderedAsString = false;
2781+
if (index < namedParams.size() && parameterExprs[index].operation == HLIL_CONST_PTR)
2782+
{
2783+
auto exprType = namedParams[index].type;
2784+
if (exprType && (exprType->GetClass() == PointerTypeClass))
2785+
{
2786+
if (auto child = exprType->GetChildType(); child)
2787+
{
2788+
if ((child->IsInteger() && child->IsSigned() && child->GetWidth() == 1) || child->IsWideChar())
2789+
{
2790+
tokens.AppendPointerTextToken(parameterExprs[index],
2791+
parameterExprs[index].GetConstant<HLIL_CONST_PTR>(), settings, AddressOfDataSymbols,
2792+
precedence, true);
2793+
renderedAsString = true;
2794+
}
2795+
}
2796+
}
2797+
}
2798+
2799+
if (!renderedAsString)
2800+
GetExprText(parameterExpr, tokens, settings);
2801+
}
2802+
tokens.AppendCloseParen();
2803+
if (statement)
2804+
tokens.AppendSemicolon();
2805+
}
2806+
2807+
void PseudoCFunction::GetExpr_CONST_PTR(const BinaryNinja::HighLevelILInstruction& instr,
2808+
BinaryNinja::HighLevelILTokenEmitter& tokens, BinaryNinja::DisassemblySettings* settings,
2809+
BNOperatorPrecedence precedence, bool statement)
2810+
{
2811+
auto constant = instr.GetConstant<HLIL_CONST_PTR>();
2812+
tokens.AppendPointerTextToken(
2813+
instr, instr.GetConstant<HLIL_CONST_PTR>(), settings, AddressOfDataSymbols, precedence);
2814+
if (statement)
2815+
tokens.AppendSemicolon();
2816+
}
2817+
2818+
void PseudoCFunction::GetExpr_IMPORT(const BinaryNinja::HighLevelILInstruction& instr,
2819+
BinaryNinja::HighLevelILTokenEmitter& tokens, BinaryNinja::DisassemblySettings* settings,
2820+
BNOperatorPrecedence precedence, bool statement)
2821+
{
2822+
const auto constant = instr.GetConstant<HLIL_IMPORT>();
2823+
auto symbol = GetHighLevelILFunction()->GetFunction()->GetView()->GetSymbolByAddress(constant);
2824+
const auto symbolType = symbol->GetType();
2825+
2826+
if (symbol && (symbolType == ImportedDataSymbol || symbolType == ImportAddressSymbol))
2827+
{
2828+
symbol = Symbol::ImportedFunctionFromImportAddressSymbol(symbol, constant);
2829+
const auto symbolShortName = symbol->GetShortName();
2830+
tokens.Append(IndirectImportToken, NoTokenContext, symbolShortName, instr.address, constant, instr.size, instr.sourceOperand);
2831+
return;
2832+
}
2833+
2834+
tokens.AppendPointerTextToken(instr, constant, settings, DereferenceNonDataSymbols, precedence);
2835+
if (statement)
2836+
tokens.AppendSemicolon();
2837+
}
28322838

28332839
string PseudoCFunction::GetAnnotationStartString() const
28342840
{
@@ -2848,32 +2854,10 @@ PseudoCFunctionType::PseudoCFunctionType(): LanguageRepresentationFunctionType("
28482854
{
28492855
}
28502856

2857+
PseudoCFunctionType::PseudoCFunctionType(const string& name) : LanguageRepresentationFunctionType(name) {}
28512858

28522859
Ref<LanguageRepresentationFunction> PseudoCFunctionType::Create(Architecture* arch, Function* owner,
28532860
HighLevelILFunction* highLevelILFunction)
28542861
{
28552862
return new PseudoCFunction(this, arch, owner, highLevelILFunction);
28562863
}
2857-
2858-
2859-
extern "C"
2860-
{
2861-
BN_DECLARE_CORE_ABI_VERSION
2862-
2863-
#ifndef DEMO_EDITION
2864-
BINARYNINJAPLUGIN void CorePluginDependencies()
2865-
{
2866-
}
2867-
#endif
2868-
2869-
#ifdef DEMO_EDITION
2870-
bool PseudoCPluginInit()
2871-
#else
2872-
BINARYNINJAPLUGIN bool CorePluginInit()
2873-
#endif
2874-
{
2875-
LanguageRepresentationFunctionType* type = new PseudoCFunctionType();
2876-
LanguageRepresentationFunctionType::Register(type);
2877-
return true;
2878-
}
2879-
}

lang/c/pseudoc.h

Lines changed: 13 additions & 0 deletions
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)