summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMason Reed <mason@vector35.com>2025-04-08 13:17:30 -0400
committerMason Reed <mason@vector35.com>2025-04-08 13:21:48 -0400
commita45466fc3227c615c72e77eb7368d7e83220b325 (patch)
tree7a1060a6e98a0faa6fe81324553f65f4cafdbfed
parenta6c5c22f08032374481aa060b59ef3492d124200 (diff)
Remove notion of image name from objective-c processor
This made the macho objective-c processor aware of images and was passed around everywhere, instead we have an overridable section getter that gives the control over the section retrieval to the derived processor. In the case of shared cache this means we can store the image to be processed and then use the header to locate the relevant sections. Fixes: https://github.com/Vector35/binaryninja-api/issues/6594
-rw-r--r--objectivec/objc.cpp43
-rw-r--r--objectivec/objc.h9
-rw-r--r--view/macho/machoview.cpp4
-rw-r--r--view/sharedcache/core/ObjC.cpp25
-rw-r--r--view/sharedcache/core/ObjC.h5
-rw-r--r--view/sharedcache/core/SharedCacheController.cpp8
6 files changed, 54 insertions, 40 deletions
diff --git a/objectivec/objc.cpp b/objectivec/objc.cpp
index 6f9c3cde..7d110450 100644
--- a/objectivec/objc.cpp
+++ b/objectivec/objc.cpp
@@ -1119,28 +1119,21 @@ void ObjCProcessor::ApplyMethodTypes(Class& cls)
}
}
-Ref<Section> ObjCProcessor::GetSectionForImage(std::optional<std::string> imageName, const char* sectionName)
+Ref<Section> ObjCProcessor::GetSectionWithName(const char* sectionName)
{
- if (imageName)
- {
- return m_data->GetSectionByName(*imageName + "::" + sectionName);
- }
- else
- {
- return m_data->GetSectionByName(sectionName);
- }
+ return m_data->GetSectionByName(sectionName);
}
-void ObjCProcessor::PostProcessObjCSections(ObjCReader* reader, std::optional<std::string> imageName)
+void ObjCProcessor::PostProcessObjCSections(ObjCReader* reader)
{
auto ptrSize = m_data->GetAddressSize();
- if (auto imageInfo = GetSectionForImage(imageName, "__objc_imageinfo"))
+ if (auto imageInfo = GetSectionWithName("__objc_imageinfo"))
{
auto start = imageInfo->GetStart();
auto type = Type::NamedType(m_data, m_typeNames.imageInfo);
m_data->DefineDataVariable(start, type);
}
- if (auto selrefs = GetSectionForImage(imageName, "__objc_selrefs"))
+ if (auto selrefs = GetSectionWithName("__objc_selrefs"))
{
auto start = selrefs->GetStart();
auto end = selrefs->GetEnd();
@@ -1163,7 +1156,7 @@ void ObjCProcessor::PostProcessObjCSections(ObjCReader* reader, std::optional<st
DefineObjCSymbol(DataSymbol, type, "selRef_" + sel, i, true);
}
}
- if (auto superRefs = GetSectionForImage(imageName, "__objc_classrefs"))
+ if (auto superRefs = GetSectionWithName("__objc_classrefs"))
{
auto start = superRefs->GetStart();
auto end = superRefs->GetEnd();
@@ -1181,7 +1174,7 @@ void ObjCProcessor::PostProcessObjCSections(ObjCReader* reader, std::optional<st
}
}
}
- if (auto superRefs = GetSectionForImage(imageName, "__objc_superrefs"))
+ if (auto superRefs = GetSectionWithName("__objc_superrefs"))
{
auto start = superRefs->GetStart();
auto end = superRefs->GetEnd();
@@ -1199,7 +1192,7 @@ void ObjCProcessor::PostProcessObjCSections(ObjCReader* reader, std::optional<st
}
}
}
- if (auto protoRefs = GetSectionForImage(imageName, "__objc_protorefs"))
+ if (auto protoRefs = GetSectionWithName("__objc_protorefs"))
{
auto start = protoRefs->GetStart();
auto end = protoRefs->GetEnd();
@@ -1217,7 +1210,7 @@ void ObjCProcessor::PostProcessObjCSections(ObjCReader* reader, std::optional<st
}
}
}
- if (auto ivars = GetSectionForImage(imageName, "__objc_ivar"))
+ if (auto ivars = GetSectionWithName("__objc_ivar"))
{
auto start = ivars->GetStart();
auto end = ivars->GetEnd();
@@ -1258,7 +1251,7 @@ Ref<Symbol> ObjCProcessor::GetSymbol(uint64_t address)
return m_data->GetSymbolByAddress(address);
}
-void ObjCProcessor::ProcessObjCData(std::optional<std::string> imageName)
+void ObjCProcessor::ProcessObjCData()
{
m_symbolQueue = new SymbolQueue();
auto addrSize = m_data->GetAddressSize();
@@ -1426,26 +1419,26 @@ void ObjCProcessor::ProcessObjCData(std::optional<std::string> imageName)
m_typeNames.protocol = finalizeStructureBuilder(m_data, protocolBuilder, "objc_protocol_t").first;
m_data->BeginBulkModifySymbols();
- if (auto classList = GetSectionForImage(imageName, "__objc_classlist"))
+ if (auto classList = GetSectionWithName("__objc_classlist"))
LoadClasses(reader.get(), classList);
- if (auto nonLazyClassList = GetSectionForImage(imageName, "__objc_nlclslist"))
+ if (auto nonLazyClassList = GetSectionWithName("__objc_nlclslist"))
LoadClasses(reader.get(), nonLazyClassList); // See: https://stackoverflow.com/a/15318325
GenerateClassTypes();
for (auto& [_, cls] : m_classes)
ApplyMethodTypes(cls);
- if (auto catList = GetSectionForImage(imageName, "__objc_catlist")) // Do this after loading class type data.
+ if (auto catList = GetSectionWithName("__objc_catlist")) // Do this after loading class type data.
LoadCategories(reader.get(), catList);
- if (auto nonLazyCatList = GetSectionForImage(imageName, "__objc_nlcatlist")) // Do this after loading class type data.
+ if (auto nonLazyCatList = GetSectionWithName("__objc_nlcatlist")) // Do this after loading class type data.
LoadCategories(reader.get(), nonLazyCatList);
for (auto& [_, cat] : m_categories)
ApplyMethodTypes(cat);
- if (auto protoList = GetSectionForImage(imageName, "__objc_protolist"))
+ if (auto protoList = GetSectionWithName("__objc_protolist"))
LoadProtocols(reader.get(), protoList);
- PostProcessObjCSections(reader.get(), imageName);
+ PostProcessObjCSections(reader.get());
auto id = m_data->BeginUndoActions();
m_symbolQueue->Process();
@@ -1460,7 +1453,7 @@ void ObjCProcessor::ProcessObjCData(std::optional<std::string> imageName)
}
-void ObjCProcessor::ProcessCFStrings(std::optional<std::string> imageName)
+void ObjCProcessor::ProcessCFStrings()
{
m_symbolQueue = new SymbolQueue();
uint64_t ptrSize = m_data->GetAddressSize();
@@ -1495,7 +1488,7 @@ void ObjCProcessor::ProcessCFStrings(std::optional<std::string> imageName)
m_typeNames.cfStringUTF16 = type.first;
auto reader = GetReader();
- if (auto cfstrings = GetSectionForImage(imageName, "__cfstring"))
+ if (auto cfstrings = GetSectionWithName("__cfstring"))
{
auto start = cfstrings->GetStart();
auto end = cfstrings->GetEnd();
diff --git a/objectivec/objc.h b/objectivec/objc.h
index 935773c1..dad86f08 100644
--- a/objectivec/objc.h
+++ b/objectivec/objc.h
@@ -314,8 +314,7 @@ namespace BinaryNinja {
bool ApplyMethodType(Class& cls, Method& method, bool isInstanceMethod);
void ApplyMethodTypes(Class& cls);
- Ref<Section> GetSectionForImage(std::optional<std::string> imageName, const char* sectionName);
- void PostProcessObjCSections(ObjCReader* reader, std::optional<std::string> imageName);
+ void PostProcessObjCSections(ObjCReader* reader);
protected:
Ref<BinaryView> m_data;
@@ -327,13 +326,15 @@ namespace BinaryNinja {
// Because an objective-c processor might have access to other non-view symbols that we want to retrieve.
// By default, this will just get symbol at the address in the view.
virtual Ref<Symbol> GetSymbol(uint64_t address);
+ virtual Ref<Section> GetSectionWithName(const char* sectionName);
public:
virtual ~ObjCProcessor() = default;
ObjCProcessor(BinaryView* data, const char* loggerName, bool isBackedByDatabase, bool skipClassBaseProtocols = false);
- void ProcessObjCData(std::optional<std::string> imageName);
- void ProcessCFStrings(std::optional<std::string> imageName);
+ // TODO: Instead of passing in image name the processor must be given section refs in a structure that outlines all objc sections.
+ void ProcessObjCData();
+ void ProcessCFStrings();
void AddRelocatedPointer(uint64_t location, uint64_t rewrite);
};
}
diff --git a/view/macho/machoview.cpp b/view/macho/machoview.cpp
index 86deee1d..cda602ad 100644
--- a/view/macho/machoview.cpp
+++ b/view/macho/machoview.cpp
@@ -2336,7 +2336,7 @@ bool MachoView::InitializeHeader(MachOHeader& header, bool isMainHeader, uint64_
if (parseCFStrings)
{
try {
- m_objcProcessor->ProcessCFStrings(std::nullopt);
+ m_objcProcessor->ProcessCFStrings();
}
catch (std::exception& ex)
{
@@ -2348,7 +2348,7 @@ bool MachoView::InitializeHeader(MachOHeader& header, bool isMainHeader, uint64_
if (parseObjCStructs)
{
try {
- m_objcProcessor->ProcessObjCData(std::nullopt);
+ m_objcProcessor->ProcessObjCData();
}
catch (std::exception& ex)
{
diff --git a/view/sharedcache/core/ObjC.cpp b/view/sharedcache/core/ObjC.cpp
index 9fee4628..dc5c3856 100644
--- a/view/sharedcache/core/ObjC.cpp
+++ b/view/sharedcache/core/ObjC.cpp
@@ -170,6 +170,25 @@ Ref<Symbol> SharedCacheObjCProcessor::GetSymbol(uint64_t address)
return symbol;
}
-SharedCacheObjCProcessor::SharedCacheObjCProcessor(BinaryView* data, bool isBackedByDatabase) :
- ObjCProcessor(data, "SharedCache.ObjC", isBackedByDatabase, true)
-{}
+Ref<Section> SharedCacheObjCProcessor::GetSectionWithName(const char *sectionName)
+{
+ const auto controller = DSC::SharedCacheController::FromView(*m_data);
+ if (!controller)
+ return nullptr;
+
+ const auto image = controller->GetCache().GetImageAt(m_imageAddress);
+ if (!image)
+ return nullptr;
+
+ for (const auto& section : image->header->sectionNames)
+ if (section.find(sectionName) != std::string::npos)
+ return m_data->GetSectionByName(section);
+
+ return nullptr;
+}
+
+SharedCacheObjCProcessor::SharedCacheObjCProcessor(BinaryView *data, bool isBackedByDatabase, uint64_t imageAddress)
+ : ObjCProcessor(data, "SharedCache.ObjC", isBackedByDatabase, true)
+{
+ m_imageAddress = imageAddress;
+}
diff --git a/view/sharedcache/core/ObjC.h b/view/sharedcache/core/ObjC.h
index 81e98f54..f44323d6 100644
--- a/view/sharedcache/core/ObjC.h
+++ b/view/sharedcache/core/ObjC.h
@@ -58,6 +58,7 @@ namespace DSCObjC {
class SharedCacheObjCProcessor : public BinaryNinja::ObjCProcessor
{
std::optional<uint64_t> m_customRelativeMethodSelectorBase = std::nullopt;
+ uint64_t m_imageAddress;
std::shared_ptr<BinaryNinja::ObjCReader> GetReader() override;
@@ -65,8 +66,10 @@ namespace DSCObjC {
BinaryNinja::Ref<BinaryNinja::Symbol> GetSymbol(uint64_t address) override;
+ BinaryNinja::Ref<BinaryNinja::Section> GetSectionWithName(const char *sectionName) override;
+
public:
- SharedCacheObjCProcessor(BinaryNinja::BinaryView* data, bool isBackedByDatabase);
+ SharedCacheObjCProcessor(BinaryNinja::BinaryView* data, bool isBackedByDatabase, uint64_t imageAddress);
uint64_t GetObjCRelativeMethodBaseAddress(BinaryNinja::ObjCReader* reader) override;
};
diff --git a/view/sharedcache/core/SharedCacheController.cpp b/view/sharedcache/core/SharedCacheController.cpp
index 13afb476..8d036b4a 100644
--- a/view/sharedcache/core/SharedCacheController.cpp
+++ b/view/sharedcache/core/SharedCacheController.cpp
@@ -215,16 +215,14 @@ bool SharedCacheController::ApplyImage(BinaryView& view, const CacheImage& image
machoProcessor.ApplyHeader(*image.header);
view.SetFunctionAnalysisUpdateDisabled(prevDisabledState);
- // TODO: Passing in an image name here is weird considering this is shared with the MACHO view.
- // TODO: We should abstract out the "image" into an objc image type that represents what is required, which ig is the name?
// Load objective-c information.
- auto objcProcessor = DSCObjC::SharedCacheObjCProcessor(&view, false);
+ auto objcProcessor = DSCObjC::SharedCacheObjCProcessor(&view, false, image.headerAddress);
try
{
if (m_processObjC)
- objcProcessor.ProcessObjCData(image.GetName());
+ objcProcessor.ProcessObjCData();
if (m_processCFStrings)
- objcProcessor.ProcessCFStrings(image.GetName());
+ objcProcessor.ProcessCFStrings();
}
catch (std::exception& e)
{