11#include " MessageHandler.h"
2+ #include " mediumlevelilinstruction.h"
23
34using namespace BinaryNinja ;
45
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+
515MessageHandler::MessageHandler (Ref<BinaryView> data)
16+ : m_data(data)
617{
18+ m_authStubsSection = data->GetSectionByName (" __auth_stubs" );
19+ m_stubsSection = data->GetSectionByName (" __stubs" );
20+
721 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+ }
879}
980
1081std::set<uint64_t > MessageHandler::findMsgSendFunctions (BinaryNinja::Ref<BinaryNinja::BinaryView> data)
1182{
83+ std::unique_lock<std::mutex> lock (m_stubMutex);
1284 std::set<uint64_t > results;
13-
14- const auto authStubsSection = data->GetSectionByName (" __auth_stubs" );
15- const auto stubsSection = data->GetSectionByName (" __stubs" );
1685 const auto authGotSection = data->GetSectionByName (" __auth_got" );
1786 const auto gotSection = data->GetSectionByName (" __got" );
1887 const auto laSymbolPtrSection = data->GetSectionByName (" __la_symbol_ptr" );
@@ -26,38 +95,95 @@ std::set<uint64_t> MessageHandler::findMsgSendFunctions(BinaryNinja::Ref<BinaryN
2695 return (uint64_t )(address - start) <= length;
2796 };
2897
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.
4698 const auto candidates = data->GetSymbolsByName (" _objc_msgSend" );
4799 for (const auto & c : candidates) {
48- if ((authStubsSection && sectionContains (authStubsSection, c))
49- || (stubsSection && sectionContains (stubsSection, c))
100+ if ((m_stubsSection && sectionContains (m_stubsSection, c))
50101 || (authGotSection && sectionContains (authGotSection, c))
51102 || (gotSection && sectionContains (gotSection, c))
52103 || (laSymbolPtrSection && sectionContains (laSymbolPtrSection, c))) {
53104 results.insert (c->GetAddress ());
54105 }
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+ }
55111 }
112+ m_presentRequiredStubs.insert (" _objc_msgSend" );
56113
57114 return results;
58115}
59116
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+
60167bool MessageHandler::isMessageSend (uint64_t functionAddress)
61168{
169+ std::unique_lock<std::mutex> lock (m_stubMutex);
62170 return m_msgSendFunctions.count (functionAddress);
63171}
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