1
1
#include " MessageHandler.h"
2
+ #include " mediumlevelilinstruction.h"
2
3
3
4
using namespace BinaryNinja ;
4
5
6
+ const std::set<std::string> arcFunctionNames = {
7
+ " _objc_retain" ,
8
+ " _objc_release" ,
9
+ " _objc_autorelease" ,
10
+ " _objc_autoreleaseReturnValue" ,
11
+ " _objc_retainAutoreleasedReturnValue" ,
12
+ " _objc_unsafeClaimAutoreleasedReturnValue"
13
+ };
14
+
5
15
MessageHandler::MessageHandler (Ref<BinaryView> data)
16
+ : m_data(data)
6
17
{
18
+ m_authStubsSection = data->GetSectionByName (" __auth_stubs" );
19
+ m_stubsSection = data->GetSectionByName (" __stubs" );
20
+
7
21
m_msgSendFunctions = findMsgSendFunctions (data);
22
+ m_arcFunctions = findARCFunctions (data);
23
+
24
+ if (!m_authStubsSection && !m_stubsSection)
25
+ m_readyForRealAnalysisPass = true ;
26
+ else
27
+ data->RegisterNotification (this );
28
+ }
29
+
30
+ void MessageHandler::OnSymbolAdded (BinaryNinja::BinaryView* view, BinaryNinja::Symbol* sym)
31
+ {
32
+ std::unique_lock<std::mutex> lock (m_stubMutex);
33
+
34
+ if (m_readyForRealAnalysisPass)
35
+ return ;
36
+ if (sym->GetType () != ImportedFunctionSymbol)
37
+ return ;
38
+ if (!m_presentRequiredStubs.count (sym->GetShortName ()))
39
+ return ;
40
+
41
+ m_locatedRequiredStubs.insert (sym->GetShortName ());
42
+ if (arcFunctionNames.count (sym->GetShortName ()))
43
+ m_arcFunctions.insert (sym->GetAddress ());
44
+ else if (sym->GetShortName () == " _objc_msgSend" ) {
45
+ auto f = m_data->GetAnalysisFunction (m_data->GetDefaultPlatform (), sym->GetAddress ());
46
+ if (!f)
47
+ return ;
48
+ auto retType = BinaryNinja::Confidence<BinaryNinja::Ref<BinaryNinja::Type>>(
49
+ BinaryNinja::Type::PointerType (m_data->GetAddressSize (), BinaryNinja::Type::VoidType (),
50
+ 0 ));
51
+
52
+ std::vector<BinaryNinja::FunctionParameter> params;
53
+ auto cc = m_data->GetDefaultPlatform ()->GetDefaultCallingConvention ();
54
+
55
+ params.push_back ({ " self" ,
56
+ BinaryNinja::Type::NamedType (m_data, { " id" }),
57
+ true ,
58
+ BinaryNinja::Variable () });
59
+ params.push_back ({ " sel" ,
60
+ BinaryNinja::Type::PointerType (m_data->GetAddressSize (), BinaryNinja::Type::IntegerType (1 , false )),
61
+ true ,
62
+ BinaryNinja::Variable () });
63
+
64
+ auto funcType = BinaryNinja::Type::FunctionType (retType, cc, params, true );
65
+ f->SetUserType (funcType);
66
+
67
+ m_msgSendFunctions.insert (f->GetStart ());
68
+ }
69
+
70
+ if (m_locatedRequiredStubs.size () == m_presentRequiredStubs.size ()) {
71
+ m_readyForRealAnalysisPass = true ;
72
+
73
+ for (auto fAddr : m_reAnalysisRequiredFunctions)
74
+ for (auto f : m_data->GetAnalysisFunctionsForAddress (fAddr ))
75
+ f->Reanalyze ();
76
+
77
+ m_data->UnregisterNotification (this );
78
+ }
8
79
}
9
80
10
81
std::set<uint64_t > MessageHandler::findMsgSendFunctions (BinaryNinja::Ref<BinaryNinja::BinaryView> data)
11
82
{
83
+ std::unique_lock<std::mutex> lock (m_stubMutex);
12
84
std::set<uint64_t > results;
13
-
14
- const auto authStubsSection = data->GetSectionByName (" __auth_stubs" );
15
- const auto stubsSection = data->GetSectionByName (" __stubs" );
16
85
const auto authGotSection = data->GetSectionByName (" __auth_got" );
17
86
const auto gotSection = data->GetSectionByName (" __got" );
18
87
const auto laSymbolPtrSection = data->GetSectionByName (" __la_symbol_ptr" );
@@ -26,38 +95,95 @@ std::set<uint64_t> MessageHandler::findMsgSendFunctions(BinaryNinja::Ref<BinaryN
26
95
return (uint64_t )(address - start) <= length;
27
96
};
28
97
29
- // There can be multiple `_objc_msgSend` symbols in the same binary; there
30
- // may even be lots. Some of them are valid, others aren't. In order of
31
- // preference, `_objc_msgSend` symbols in the following sections are
32
- // preferred:
33
- //
34
- // 1. __auth_stubs
35
- // 2. __stubs
36
- // 3. __auth_got
37
- // 4. __got
38
- // ?. __la_symbol_ptr
39
- //
40
- // There is often an `_objc_msgSend` symbol that is a stub function, found
41
- // in the `__stubs` section, which will come with an imported symbol of the
42
- // same name in the `__got` section. Not all `__objc_msgSend` calls will be
43
- // routed through the stub function, making it important to make note of
44
- // both symbols' addresses. Furthermore, on ARM64, the `__auth{stubs,got}`
45
- // sections are preferred over their unauthenticated counterparts.
46
98
const auto candidates = data->GetSymbolsByName (" _objc_msgSend" );
47
99
for (const auto & c : candidates) {
48
- if ((authStubsSection && sectionContains (authStubsSection, c))
49
- || (stubsSection && sectionContains (stubsSection, c))
100
+ if ((m_stubsSection && sectionContains (m_stubsSection, c))
50
101
|| (authGotSection && sectionContains (authGotSection, c))
51
102
|| (gotSection && sectionContains (gotSection, c))
52
103
|| (laSymbolPtrSection && sectionContains (laSymbolPtrSection, c))) {
53
104
results.insert (c->GetAddress ());
54
105
}
106
+ if ((m_authStubsSection && sectionContains (m_authStubsSection, c))
107
+ || (m_stubsSection && sectionContains (gotSection, c))) {
108
+ results.insert (c->GetAddress ());
109
+ m_locatedRequiredStubs.insert (c->GetShortName ());
110
+ }
55
111
}
112
+ m_presentRequiredStubs.insert (" _objc_msgSend" );
56
113
57
114
return results;
58
115
}
59
116
117
+ std::set<uint64_t > MessageHandler::findARCFunctions (BinaryNinja::Ref<BinaryNinja::BinaryView> data)
118
+ {
119
+ std::unique_lock<std::mutex> lock (m_stubMutex);
120
+ std::set<uint64_t > results;
121
+ const auto authStubsSection = data->GetSectionByName (" __auth_stubs" );
122
+ const auto stubsSection = data->GetSectionByName (" __stubs" );
123
+ const auto authGotSection = data->GetSectionByName (" __auth_got" );
124
+ const auto gotSection = data->GetSectionByName (" __got" );
125
+ const auto laSymbolPtrSection = data->GetSectionByName (" __la_symbol_ptr" );
126
+
127
+ // Shorthand to check if a symbol lies in a given section.
128
+ auto sectionContains = [](Ref<Section> section, Ref<Symbol> symbol) {
129
+ const auto start = section->GetStart ();
130
+ const auto length = section->GetLength ();
131
+ const auto address = symbol->GetAddress ();
132
+
133
+ return (uint64_t )(address - start) <= length;
134
+ };
135
+
136
+ std::vector<BinaryNinja::Ref<BinaryNinja::Symbol>> candidates;
137
+ std::vector<BinaryNinja::Ref<BinaryNinja::Symbol>> next;
138
+ for (auto name : arcFunctionNames) {
139
+ next = data->GetSymbolsByName (name);
140
+ candidates.insert (candidates.end (), next.begin (), next.end ());
141
+ }
142
+ for (auto & c : candidates) {
143
+ if ((authGotSection && sectionContains (authGotSection, c))
144
+ || (gotSection && sectionContains (gotSection, c))
145
+ || (laSymbolPtrSection && sectionContains (laSymbolPtrSection, c))) {
146
+ {
147
+ results.insert (c->GetAddress ());
148
+ m_presentRequiredStubs.insert (c->GetShortName ());
149
+ }
150
+ }
151
+ if ((m_authStubsSection && sectionContains (m_authStubsSection, c))
152
+ || (m_stubsSection && sectionContains (m_stubsSection, c))) {
153
+ m_locatedRequiredStubs.insert (c->GetShortName ());
154
+ results.insert (c->GetAddress ());
155
+ }
156
+ }
157
+
158
+ return results;
159
+ }
160
+
161
+ void MessageHandler::functionWasAnalyzed (uint64_t addr)
162
+ {
163
+ if (!m_readyForRealAnalysisPass)
164
+ m_reAnalysisRequiredFunctions.insert (addr);
165
+ }
166
+
60
167
bool MessageHandler::isMessageSend (uint64_t functionAddress)
61
168
{
169
+ std::unique_lock<std::mutex> lock (m_stubMutex);
62
170
return m_msgSendFunctions.count (functionAddress);
63
171
}
172
+
173
+ bool MessageHandler::isARCFunction (uint64_t functionAddress)
174
+ {
175
+ std::unique_lock<std::mutex> lock (m_stubMutex);
176
+ return m_arcFunctions.count (functionAddress);
177
+ }
178
+
179
+ bool MessageHandler::isFunctionLocatedInStubSection (uint64_t addr)
180
+ {
181
+ if (m_stubsSection && m_stubsSection->GetStart () < addr
182
+ && m_stubsSection->GetStart () + m_stubsSection->GetLength () > addr)
183
+ return true ;
184
+ else if (m_authStubsSection && m_authStubsSection->GetStart () < addr
185
+ && m_authStubsSection->GetStart () + m_authStubsSection->GetLength () > addr)
186
+ return true ;
187
+
188
+ return false ;
189
+ }
0 commit comments