Skip to content

Commit b055631

Browse files
committed
[Objective-C] Parse protocol information.
1 parent 42fe51a commit b055631

File tree

2 files changed

+196
-2
lines changed

2 files changed

+196
-2
lines changed

view/macho/objc.cpp

Lines changed: 181 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,8 @@ void ObjCProcessor::LoadClasses(BinaryReader* reader, Ref<Section> classPtrSecti
340340
auto size = classPtrSection->GetEnd() - classPtrSection->GetStart();
341341
if (size == 0)
342342
return;
343-
auto ptrCount = size / m_data->GetAddressSize();
343+
auto ptrSize = m_data->GetAddressSize();
344+
auto ptrCount = size / ptrSize;
344345

345346
auto classPtrSectionStart = classPtrSection->GetStart();
346347
for (size_t i = 0; i < ptrCount; i++)
@@ -433,6 +434,19 @@ void ObjCProcessor::LoadClasses(BinaryReader* reader, Ref<Section> classPtrSecti
433434
DefineObjCSymbol(BNSymbolType::DataSymbol, m_typeNames.cls, "cls_" + name, classPtr, true);
434435
DefineObjCSymbol(BNSymbolType::DataSymbol, m_typeNames.classRO, "cls_ro_" + name, classROPtr, true);
435436
DefineObjCSymbol(BNSymbolType::DataSymbol, Type::ArrayType(Type::IntegerType(1, true), name.size()+1), "clsName_" + name, classRO.name, true);
437+
if (classRO.baseProtocols)
438+
{
439+
DefineObjCSymbol(BNSymbolType::DataSymbol, Type::NamedType(m_data, m_typeNames.protocolList),
440+
"clsProtocols_" + name, classRO.baseProtocols, true);
441+
reader->Seek(classRO.baseProtocols);
442+
uint32_t count = reader->Read64();
443+
view_ptr_t addr = reader->GetOffset();
444+
for (uint32_t j = 0; j < count; j++)
445+
{
446+
m_data->DefineDataVariable(addr, Type::PointerType(ptrSize, Type::NamedType(m_data, m_typeNames.protocol)));
447+
addr += ptrSize;
448+
}
449+
}
436450

437451
if (clsStruct.isa)
438452
{
@@ -631,6 +645,130 @@ void ObjCProcessor::LoadCategories(BinaryReader* reader, Ref<Section> classPtrSe
631645
}
632646
}
633647

648+
void ObjCProcessor::LoadProtocols(BinaryReader* reader, Ref<Section> listSection)
649+
{
650+
if (!listSection)
651+
return;
652+
auto size = listSection->GetEnd() - listSection->GetStart();
653+
if (size == 0)
654+
return;
655+
auto ptrSize = m_data->GetAddressSize();
656+
657+
auto listSectionStart = listSection->GetStart();
658+
auto listSectionEnd = listSection->GetEnd();
659+
660+
auto protocolType = Type::NamedType(m_data, m_typeNames.protocol);
661+
auto ptrType = Type::PointerType(m_data->GetDefaultArchitecture(), protocolType);
662+
for (size_t i = listSectionStart; i < listSectionEnd; i += ptrSize)
663+
{
664+
protocol_t protocol;
665+
reader->Seek(i);
666+
auto protocolLocation = ReadPointerAccountingForRelocations(reader);
667+
reader->Seek(protocolLocation);
668+
669+
try
670+
{
671+
protocol.isa = ReadPointerAccountingForRelocations(reader);
672+
protocol.mangledName = ReadPointerAccountingForRelocations(reader);
673+
protocol.protocols = ReadPointerAccountingForRelocations(reader);
674+
protocol.instanceMethods = ReadPointerAccountingForRelocations(reader);
675+
protocol.classMethods = ReadPointerAccountingForRelocations(reader);
676+
protocol.optionalInstanceMethods = ReadPointerAccountingForRelocations(reader);
677+
protocol.optionalClassMethods = ReadPointerAccountingForRelocations(reader);
678+
protocol.instanceProperties = ReadPointerAccountingForRelocations(reader);
679+
}
680+
catch (ReadException& ex)
681+
{
682+
m_logger->LogError("Failed to read protocol pointed to by 0x%llx", i);
683+
continue;
684+
}
685+
686+
std::string protocolName;
687+
try
688+
{
689+
reader->Seek(protocol.mangledName);
690+
protocolName = reader->ReadCString();
691+
DefineObjCSymbol(BNSymbolType::DataSymbol, Type::ArrayType(Type::IntegerType(1, true), protocolName.size() + 1),
692+
"protocolName_" + protocolName, protocol.mangledName, true);
693+
}
694+
catch (ReadException& ex)
695+
{
696+
m_logger->LogError(
697+
"Failed to read protocol name for protocol at 0x%llx. Using base address as stand-in protocol name",
698+
protocolLocation);
699+
protocolName = std::to_string(protocolLocation);
700+
}
701+
702+
Protocol protocolClass;
703+
protocolClass.name = protocolName;
704+
DefineObjCSymbol(BNSymbolType::DataSymbol, ptrType, "protocolPtr_" + protocolName, i, true);
705+
DefineObjCSymbol(BNSymbolType::DataSymbol, protocolType, "protocol_" + protocolName, protocolLocation, true);
706+
if (protocol.protocols)
707+
{
708+
DefineObjCSymbol(BNSymbolType::DataSymbol, Type::NamedType(m_data, m_typeNames.protocolList),
709+
"protoProtocols_" + protocolName, protocol.protocols, true);
710+
reader->Seek(protocol.protocols);
711+
uint32_t count = reader->Read64();
712+
view_ptr_t addr = reader->GetOffset();
713+
for (uint32_t j = 0; j < count; j++)
714+
{
715+
m_data->DefineDataVariable(addr, Type::PointerType(ptrSize, Type::NamedType(m_data, m_typeNames.protocol)));
716+
addr += ptrSize;
717+
}
718+
}
719+
720+
if (protocol.instanceMethods)
721+
{
722+
try
723+
{
724+
ReadMethodList(reader, protocolClass.instanceMethods, protocolName, protocol.instanceMethods);
725+
}
726+
catch (ReadException& ex)
727+
{
728+
m_logger->LogError(
729+
"Failed to read the instance method list for protocol pointed to by 0x%llx", protocolLocation);
730+
}
731+
}
732+
if (protocol.classMethods)
733+
{
734+
try
735+
{
736+
ReadMethodList(reader, protocolClass.classMethods, protocolName, protocol.classMethods);
737+
}
738+
catch (ReadException& ex)
739+
{
740+
m_logger->LogError(
741+
"Failed to read the class method list for protocol pointed to by 0x%llx", protocolLocation);
742+
}
743+
}
744+
if (protocol.optionalInstanceMethods)
745+
{
746+
try
747+
{
748+
ReadMethodList(reader, protocolClass.optionalInstanceMethods, protocolName, protocol.optionalInstanceMethods);
749+
}
750+
catch (ReadException& ex)
751+
{
752+
m_logger->LogError(
753+
"Failed to read the optional instance method list for protocol pointed to by 0x%llx", protocolLocation);
754+
}
755+
}
756+
if (protocol.optionalClassMethods)
757+
{
758+
try
759+
{
760+
ReadMethodList(reader, protocolClass.optionalClassMethods, protocolName, protocol.optionalClassMethods);
761+
}
762+
catch (ReadException& ex)
763+
{
764+
m_logger->LogError(
765+
"Failed to read the optional class method list for protocol pointed to by 0x%llx", protocolLocation);
766+
}
767+
}
768+
m_protocols[protocolLocation] = protocolClass;
769+
}
770+
}
771+
634772
void ObjCProcessor::ReadMethodList(BinaryReader* reader, ClassBase& cls, std::string name, view_ptr_t start)
635773
{
636774
reader->Seek(start);
@@ -755,6 +893,10 @@ void ObjCProcessor::ReadIvarList(BinaryReader* reader, ClassBase& cls, std::stri
755893
ivar.type = reader->ReadCString();
756894

757895
DefineObjCSymbol(DataSymbol, m_typeNames.ivar, "ivar_" + ivar.name, cursor, true);
896+
DefineObjCSymbol(DataSymbol, Type::ArrayType(Type::IntegerType(1, true), ivar.name.size() + 1),
897+
"ivarName_" + ivar.name, ivarStruct.name, true);
898+
DefineObjCSymbol(DataSymbol, Type::ArrayType(Type::IntegerType(1, true), ivar.type.size() + 1),
899+
"ivarType_" + ivar.name, ivarStruct.type, true);
758900

759901
cls.ivarList[cursor] = ivar;
760902
}
@@ -996,6 +1138,24 @@ void ObjCProcessor::PostProcessObjCSections(BinaryReader* reader)
9961138
}
9971139
}
9981140
}
1141+
if (auto protoRefs = m_data->GetSectionByName("__objc_protorefs"))
1142+
{
1143+
auto start = protoRefs->GetStart();
1144+
auto end = protoRefs->GetEnd();
1145+
auto type = Type::PointerType(ptrSize, Type::NamedType(m_data, m_typeNames.protocol));
1146+
for (view_ptr_t i = start; i < end; i += ptrSize)
1147+
{
1148+
reader->Seek(i);
1149+
auto protoLoc = ReadPointerAccountingForRelocations(reader);
1150+
if (const auto& it = m_protocols.find(protoLoc); it != m_protocols.end())
1151+
{
1152+
auto& proto = it->second;
1153+
std::string name = proto.name;
1154+
if (!name.empty())
1155+
DefineObjCSymbol(DataSymbol, type, "protoRef_" + name, i, true);
1156+
}
1157+
}
1158+
}
9991159
if (auto ivars = m_data->GetSectionByName("__objc_ivar"))
10001160
{
10011161
auto start = ivars->GetStart();
@@ -1189,6 +1349,10 @@ void ObjCProcessor::ProcessObjCData()
11891349
type = finalizeStructureBuilder(m_data, ivarList, "objc_ivar_list_t");
11901350
m_typeNames.ivarList = type.first;
11911351

1352+
StructureBuilder protocolListBuilder;
1353+
protocolListBuilder.AddMember(Type::IntegerType(addrSize, false), "count");
1354+
m_typeNames.protocolList = finalizeStructureBuilder(m_data, protocolListBuilder, "objc_protocol_list_t").first;
1355+
11921356
StructureBuilder classROBuilder;
11931357
classROBuilder.AddMember(Type::IntegerType(4, false), "flags");
11941358
classROBuilder.AddMember(Type::IntegerType(4, false), "start");
@@ -1198,7 +1362,7 @@ void ObjCProcessor::ProcessObjCData()
11981362
classROBuilder.AddMember(Type::PointerType(addrSize, Type::VoidType()), "ivar_layout");
11991363
classROBuilder.AddMember(Type::PointerType(addrSize, Type::IntegerType(1, true)), "name");
12001364
classROBuilder.AddMember(Type::PointerType(addrSize, Type::NamedType(m_data, m_typeNames.methodList)), "methods");
1201-
classROBuilder.AddMember(Type::PointerType(addrSize, Type::VoidType()), "protocols");
1365+
classROBuilder.AddMember(Type::PointerType(addrSize, Type::NamedType(m_data, m_typeNames.protocolList)), "protocols");
12021366
classROBuilder.AddMember(Type::PointerType(addrSize, Type::NamedType(m_data, m_typeNames.ivarList)), "ivars");
12031367
classROBuilder.AddMember(Type::PointerType(addrSize, Type::VoidType()), "weak_ivar_layout");
12041368
classROBuilder.AddMember(Type::PointerType(addrSize, Type::VoidType()), "properties");
@@ -1236,6 +1400,18 @@ void ObjCProcessor::ProcessObjCData()
12361400
categoryBuilder.AddMember(Type::PointerType(addrSize, Type::VoidType()), "properties");
12371401
m_typeNames.category = finalizeStructureBuilder(m_data, categoryBuilder, "objc_category_t").first;
12381402

1403+
StructureBuilder protocolBuilder;
1404+
protocolBuilder.AddMember(Type::PointerType(addrSize, Type::VoidType()), "isa");
1405+
protocolBuilder.AddMember(Type::PointerType(addrSize, Type::IntegerType(1, true)), "mangledName");
1406+
protocolBuilder.AddMember(Type::PointerType(addrSize, Type::NamedType(m_data, m_typeNames.protocolList)), "protocols");
1407+
protocolBuilder.AddMember(Type::PointerType(addrSize, Type::NamedType(m_data, m_typeNames.methodList)), "instanceMethods");
1408+
protocolBuilder.AddMember(Type::PointerType(addrSize, Type::NamedType(m_data, m_typeNames.methodList)), "classMethods");
1409+
protocolBuilder.AddMember(Type::PointerType(addrSize, Type::NamedType(m_data, m_typeNames.methodList)), "optionalInstanceMethods");
1410+
protocolBuilder.AddMember(Type::PointerType(addrSize, Type::NamedType(m_data, m_typeNames.methodList)), "optionalClassMethods");
1411+
protocolBuilder.AddMember(Type::PointerType(addrSize, Type::VoidType()), "instanceProperties");
1412+
protocolBuilder.AddMember(Type::IntegerType(4, false), "size");
1413+
protocolBuilder.AddMember(Type::IntegerType(4, false), "flags");
1414+
m_typeNames.protocol = finalizeStructureBuilder(m_data, protocolBuilder, "objc_protocol_t").first;
12391415

12401416
auto reader = BinaryReader(m_data);
12411417
m_data->BeginBulkModifySymbols();
@@ -1253,6 +1429,9 @@ void ObjCProcessor::ProcessObjCData()
12531429
for (auto& [_, cat] : m_categories)
12541430
ApplyMethodTypes(cat);
12551431

1432+
if (auto protoList = m_data->GetSectionByName("__objc_protolist"))
1433+
LoadProtocols(&reader, protoList);
1434+
12561435
PostProcessObjCSections(&reader);
12571436

12581437
m_symbolQueue->Process();

view/macho/objc.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ namespace BinaryNinja {
4848
uint64_t count;
4949
} protocol_list_t;
5050
typedef struct {
51+
view_ptr_t isa;
5152
view_ptr_t mangledName;
5253
view_ptr_t protocols;
5354
view_ptr_t instanceMethods;
@@ -128,6 +129,16 @@ namespace BinaryNinja {
128129
QualifiedName associatedName;
129130
};
130131

132+
class Protocol {
133+
public:
134+
std::string name;
135+
std::vector<QualifiedName> protocols;
136+
ClassBase instanceMethods;
137+
ClassBase classMethods;
138+
ClassBase optionalInstanceMethods;
139+
ClassBase optionalClassMethods;
140+
};
141+
131142
struct QualifiedNameOrType {
132143
BinaryNinja::Ref<BinaryNinja::Type> type = nullptr;
133144
BinaryNinja::QualifiedName name;
@@ -155,6 +166,8 @@ namespace BinaryNinja {
155166
QualifiedName classRO;
156167
QualifiedName cls;
157168
QualifiedName category;
169+
QualifiedName protocol;
170+
QualifiedName protocolList;
158171
QualifiedName ivar;
159172
QualifiedName ivarList;
160173
} m_typeNames;
@@ -166,6 +179,7 @@ namespace BinaryNinja {
166179
Ref<Logger> m_logger;
167180
std::map<uint64_t, Class> m_classes;
168181
std::map<uint64_t, Class> m_categories;
182+
std::map<uint64_t, Protocol> m_protocols;
169183
std::unordered_map<uint64_t, std::string> m_selectorCache;
170184
std::unordered_map<uint64_t, Method> m_localMethods;
171185

@@ -189,6 +203,7 @@ namespace BinaryNinja {
189203
void ReadMethodList(BinaryReader* reader, ClassBase& cls, std::string name, view_ptr_t start);
190204
void LoadClasses(BinaryReader* reader, Ref<Section> listSection);
191205
void LoadCategories(BinaryReader* reader, Ref<Section> listSection);
206+
void LoadProtocols(BinaryReader* reader, Ref<Section> listSection);
192207
void GenerateClassTypes();
193208
bool ApplyMethodType(Class& cls, Method& method, bool isInstanceMethod);
194209
void ApplyMethodTypes(Class& cls);

0 commit comments

Comments
 (0)