Skip to content
This repository was archived by the owner on Jul 11, 2022. It is now read-only.

Commit 7d4da27

Browse files
committed
Initial support for analyzing categories.
1 parent b983689 commit 7d4da27

6 files changed

Lines changed: 91 additions & 0 deletions

File tree

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ add_subdirectory(Vendor/BinaryNinjaAPI)
2626
# Core library -----------------------------------------------------------------
2727

2828
set(CORE_SOURCE
29+
Include/ObjectiveNinjaCore/Analyzers/CategoryAnalyzer.h
2930
Include/ObjectiveNinjaCore/Analyzers/CFStringAnalyzer.h
3031
Include/ObjectiveNinjaCore/Analyzers/ClassAnalyzer.h
3132
Include/ObjectiveNinjaCore/Analyzers/SelectorAnalyzer.h
@@ -36,6 +37,7 @@ set(CORE_SOURCE
3637
Include/ObjectiveNinjaCore/AnalysisProvider.h
3738
Include/ObjectiveNinjaCore/Analyzer.h
3839
Include/ObjectiveNinjaCore/TypeParser.h
40+
Core/Analyzers/CategoryAnalyzer.cpp
3941
Core/Analyzers/CFStringAnalyzer.cpp
4042
Core/Analyzers/ClassAnalyzer.cpp
4143
Core/Analyzers/SelectorAnalyzer.cpp

Core/AnalysisProvider.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include <ObjectiveNinjaCore/Analyzers/CFStringAnalyzer.h>
1111
#include <ObjectiveNinjaCore/Analyzers/ClassAnalyzer.h>
12+
#include <ObjectiveNinjaCore/Analyzers/CategoryAnalyzer.h>
1213
#include <ObjectiveNinjaCore/Analyzers/SelectorAnalyzer.h>
1314

1415
namespace ObjectiveNinja {
@@ -20,6 +21,7 @@ SharedAnalysisInfo AnalysisProvider::infoForFile(SharedAbstractFile file)
2021
std::vector<std::unique_ptr<ObjectiveNinja::Analyzer>> analyzers;
2122
analyzers.emplace_back(new SelectorAnalyzer(info, file));
2223
analyzers.emplace_back(new ClassAnalyzer(info, file));
24+
analyzers.emplace_back(new CategoryAnalyzer(info, file));
2325
analyzers.emplace_back(new CFStringAnalyzer(info, file));
2426

2527
for (const auto& analyzer : analyzers)

Include/ObjectiveNinjaCore/AnalysisInfo.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,21 @@ struct ClassInfo {
9292
uint64_t methodListAddress {};
9393
};
9494

95+
/**
96+
* A description of an Objective-C category.
97+
*/
98+
struct CategoryInfo {
99+
uint64_t address {};
100+
std::string name {};
101+
MethodListInfo instanceMethods {};
102+
MethodListInfo classMethods {};
103+
104+
uint64_t listPointer {};
105+
uint64_t nameAddress {};
106+
uint64_t instanceMethodListAddress {};
107+
uint64_t classMethodListAddress {};
108+
};
109+
95110
/**
96111
* Analysis info storage.
97112
*
@@ -106,6 +121,7 @@ struct AnalysisInfo {
106121
std::unordered_map<uint64_t, SharedSelectorRefInfo> selectorRefsByKey {};
107122

108123
std::vector<ClassInfo> classes {};
124+
std::vector<CategoryInfo> categories {};
109125
std::unordered_map<uint64_t, uint64_t> methodImpls;
110126

111127
std::string dump() const;
@@ -123,4 +139,8 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(MethodListInfo, address, flags, methods)
123139

124140
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(ClassInfo, listPointer, address, dataAddress,
125141
nameAddress, name, methodListAddress, methodList)
142+
143+
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CategoryInfo, listPointer, address, nameAddress,
144+
name, instanceMethodListAddress, instanceMethods, classMethodListAddress,
145+
classMethods)
126146
}

Plugin/CustomTypes.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,15 @@ struct objc_class_t {
7373
void* vtable;
7474
const fptr_t data;
7575
};
76+
77+
struct objc_category_t {
78+
const char* name;
79+
void* class;
80+
const tptr_t instance_methods;
81+
const tptr_t class_methods;
82+
const tptr_t protocols;
83+
const tptr_t instance_properties;
84+
}
7685
)";
7786

7887
namespace CustomTypes {

Plugin/CustomTypes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const std::string Method = "objc_method_t";
2828
const std::string MethodListEntry = "objc_method_entry_t";
2929
const std::string Class = "objc_class_t";
3030
const std::string ClassRO = "objc_class_ro_t";
31+
const std::string Category = "objc_category_t";
3132

3233
/**
3334
* Define all Objective-C-related types for a view.

Plugin/InfoHandler.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ void InfoHandler::applyInfoToView(SharedAnalysisInfo info, BinaryViewRef bv)
123123
BinaryReader reader(bv);
124124

125125
auto taggedPointerType = namedType(bv, CustomTypes::TaggedPointer);
126+
auto categoryType = namedType(bv, CustomTypes::Category);
126127
auto cfStringType = namedType(bv, CustomTypes::CFString);
127128
auto classType = namedType(bv, CustomTypes::Class);
128129
auto classDataType = namedType(bv, CustomTypes::ClassRO);
@@ -195,4 +196,60 @@ void InfoHandler::applyInfoToView(SharedAnalysisInfo info, BinaryViewRef bv)
195196
defineVariable(bv, ci.methodListAddress, methodListType);
196197
defineSymbol(bv, ci.methodListAddress, ci.name, "ml_");
197198
}
199+
200+
// Create data variables and symbols for the analyzed protocols.
201+
for (const auto& ci : info->categories) {
202+
defineVariable(bv, ci.listPointer, taggedPointerType);
203+
defineVariable(bv, ci.address, categoryType);
204+
205+
defineSymbol(bv, ci.listPointer, ci.name, "catp_");
206+
defineSymbol(bv, ci.address, ci.name, "cat_");
207+
208+
defineReference(bv, ci.listPointer, ci.address);
209+
210+
if (ci.instanceMethods.address && !ci.instanceMethods.methods.empty()) {
211+
auto methodType = ci.instanceMethods.hasRelativeOffsets()
212+
? bv->GetTypeByName(CustomTypes::MethodListEntry)
213+
: bv->GetTypeByName(CustomTypes::Method);
214+
215+
// Create data variables for each method in the method list.
216+
for (const auto& mi : ci.instanceMethods.methods) {
217+
defineVariable(bv, mi.address, methodType);
218+
defineSymbol(bv, mi.address, sanitizeSelector(mi.selector), "mt_");
219+
defineVariable(bv, mi.typeAddress, stringType(mi.type.size()));
220+
221+
defineReference(bv, ci.instanceMethods.address, mi.address);
222+
defineReference(bv, mi.address, mi.nameAddress);
223+
defineReference(bv, mi.address, mi.typeAddress);
224+
defineReference(bv, mi.address, mi.implAddress);
225+
}
226+
227+
// Create a data variable and symbol for the method list header.
228+
defineVariable(bv, ci.instanceMethodListAddress, methodListType);
229+
defineSymbol(bv, ci.instanceMethodListAddress, ci.name, "mli_");
230+
}
231+
232+
233+
if (ci.classMethods.address && !ci.classMethods.methods.empty()) {
234+
auto methodType = ci.classMethods.hasRelativeOffsets()
235+
? bv->GetTypeByName(CustomTypes::MethodListEntry)
236+
: bv->GetTypeByName(CustomTypes::Method);
237+
238+
// Create data variables for each method in the method list.
239+
for (const auto& mi : ci.classMethods.methods) {
240+
defineVariable(bv, mi.address, methodType);
241+
defineSymbol(bv, mi.address, sanitizeSelector(mi.selector), "mt_");
242+
defineVariable(bv, mi.typeAddress, stringType(mi.type.size()));
243+
244+
defineReference(bv, ci.classMethods.address, mi.address);
245+
defineReference(bv, mi.address, mi.nameAddress);
246+
defineReference(bv, mi.address, mi.typeAddress);
247+
defineReference(bv, mi.address, mi.implAddress);
248+
}
249+
250+
// Create a data variable and symbol for the method list header.
251+
defineVariable(bv, ci.classMethodListAddress, methodListType);
252+
defineSymbol(bv, ci.classMethodListAddress, ci.name, "mlc_");
253+
}
254+
}
198255
}

0 commit comments

Comments
 (0)