aboutsummaryrefslogtreecommitdiff
path: root/core/objc.cc
diff options
context:
space:
mode:
Diffstat (limited to 'core/objc.cc')
-rw-r--r--core/objc.cc1435
1 files changed, 1435 insertions, 0 deletions
diff --git a/core/objc.cc b/core/objc.cc
new file mode 100644
index 0000000..b28daa0
--- /dev/null
+++ b/core/objc.cc
@@ -0,0 +1,1435 @@
+#include "objects.h"
+#include "osutils.h"
+#include "files.h"
+#include "macfile.h"
+#include "objc.h"
+
+MacSection *GetObjcSection(MacArchitecture &file, uint8_t version, const std::string &section_name)
+{
+ std::set<std::string> segment_list;
+ switch (version) {
+ case 1:
+ segment_list.insert(SEG_OBJC);
+ break;
+ case 2:
+ segment_list.insert(SEG_DATA);
+ segment_list.insert("__DATA_CONST");
+ break;
+ }
+
+ for (size_t i = 0; i < file.section_list()->count(); i++) {
+ MacSection *section = file.section_list()->item(i);
+ if (section->parent() && segment_list.find(section->parent()->name()) != segment_list.end() && section->name() == section_name)
+ return section;
+ }
+ return NULL;
+}
+
+/**
+ * BaseObjcMethod
+ */
+
+BaseObjcMethod::BaseObjcMethod(IObjcMethodList *owner, uint64_t address)
+ : IObjcMethod(), owner_(owner), address_(address)
+{
+
+}
+
+BaseObjcMethod::~BaseObjcMethod()
+{
+ if (owner_)
+ owner_->RemoveObject(this);
+}
+
+/**
+ * BaseObjcMethodList
+ */
+
+void BaseObjcMethodList::GetLoadMethodReferences(std::set<uint64_t> &address_list) const
+{
+ for (size_t i = 0; i < count(); i++) {
+ item(i)->GetLoadMethodReferences(address_list);
+ }
+}
+
+void BaseObjcMethodList::GetStringReferences(std::set<uint64_t> &address_list) const
+{
+ for (size_t i = 0; i < count(); i++) {
+ item(i)->GetStringReferences(address_list);
+ }
+}
+
+/**
+ * BaseObjcCLass
+ */
+
+BaseObjcClass::BaseObjcClass(IObjcClassList *owner, uint64_t address)
+ : IObjcClass(), owner_(owner), address_(address)
+{
+
+}
+
+BaseObjcClass::~BaseObjcClass()
+{
+ if (owner_)
+ owner_->RemoveObject(this);
+}
+
+/**
+ * BaseObjcClassList
+ */
+
+void BaseObjcClassList::AddObject(IObjcClass *object)
+{
+ IObjcClassList::AddObject(object);
+ if (object->address())
+ map_[object->address()] = object;
+}
+
+void BaseObjcClassList::GetLoadMethodReferences(std::set<uint64_t> &address_list) const
+{
+ for (size_t i = 0; i < count(); i++) {
+ item(i)->GetLoadMethodReferences(address_list);
+ }
+}
+
+void BaseObjcClassList::GetStringReferences(std::set<uint64_t> &address_list) const
+{
+ for (size_t i = 0; i < count(); i++) {
+ item(i)->GetStringReferences(address_list);
+ }
+}
+
+IObjcClass *BaseObjcClassList::GetClassByAddress(uint64_t address) const
+{
+ std::map<uint64_t, IObjcClass *>::const_iterator it = map_.find(address);
+ if (it != map_.end())
+ return it->second;
+
+ return NULL;
+}
+
+/**
+ * BaseObjcCategory
+ */
+
+BaseObjcCategory::BaseObjcCategory(IObjcCategoryList *owner, uint64_t address)
+ : IObjcCategory(), owner_(owner), address_(address)
+{
+
+}
+
+BaseObjcCategory::~BaseObjcCategory()
+{
+ if (owner_)
+ owner_->RemoveObject(this);
+}
+
+/**
+ * BaseObjcCategoryList
+ */
+
+void BaseObjcCategoryList::GetLoadMethodReferences(std::set<uint64_t> &address_list) const
+{
+ for (size_t i = 0; i < count(); i++) {
+ item(i)->GetLoadMethodReferences(address_list);
+ }
+}
+
+void BaseObjcCategoryList::GetStringReferences(std::set<uint64_t> &address_list) const
+{
+ for (size_t i = 0; i < count(); i++) {
+ item(i)->GetStringReferences(address_list);
+ }
+}
+
+/**
+ * BaseObjcSelector
+ */
+
+BaseObjcSelector::BaseObjcSelector(IObjcSelectorList *owner, uint64_t address)
+ : IObjcSelector(), owner_(owner), address_(address)
+{
+
+}
+
+BaseObjcSelector::~BaseObjcSelector()
+{
+ if (owner_)
+ owner_->RemoveObject(this);
+}
+
+/**
+ * BaseObjcSelectorList
+ */
+
+void BaseObjcSelectorList::GetStringReferences(std::set<uint64_t> &address_list) const
+{
+ for (size_t i = 0; i < count(); i++) {
+ item(i)->GetStringReferences(address_list);
+ }
+}
+
+/**
+ * BaseObjcProtocol
+ */
+
+BaseObjcProtocol::BaseObjcProtocol(IObjcProtocolList *owner, uint64_t address)
+ : IObjcProtocol(), owner_(owner), address_(address)
+{
+
+}
+
+BaseObjcProtocol::~BaseObjcProtocol()
+{
+ if (owner_)
+ owner_->RemoveObject(this);
+}
+
+/**
+ * BaseObjcProtocolList
+ */
+
+IObjcProtocol *BaseObjcProtocolList::GetProtocolByAddress(uint64_t address) const
+{
+ for (size_t i = 0; i < count(); i++) {
+ IObjcProtocol *prot = item(i);
+ if (prot->address() == address)
+ return prot;
+ }
+ return NULL;
+}
+
+void BaseObjcProtocolList::GetStringReferences(std::set<uint64_t> &address_list) const
+{
+ for (size_t i = 0; i < count(); i++) {
+ item(i)->GetStringReferences(address_list);
+ }
+}
+
+/**
+ * ObjcMethod
+ */
+
+ObjcMethod::ObjcMethod(IObjcMethodList *owner, uint64_t address)
+ : BaseObjcMethod(owner, address)
+{
+ size_ = osDWord;
+ name_ = 0;
+ types_ = 0;
+ imp_ = 0;
+ type_ = mtUnknown;
+}
+
+void ObjcMethod::ReadFromFile(MacArchitecture &file)
+{
+ if (!file.AddressSeek(address()))
+ return;
+
+ size_ = file.cpu_address_size();
+ if (file.cpu_address_size() == osDWord) {
+ objc_method method;
+ file.Read(&method, sizeof(method));
+ name_ = method.name;
+ types_ = method.types;
+ imp_ = method.imp;
+ } else {
+ objc_method_64 method;
+ file.Read(&method, sizeof(method));
+ name_ = method.name;
+ types_ = method.types;
+ imp_ = method.imp;
+ }
+
+ if (name_ && file.AddressSeek(name_)) {
+ std::string name = file.ReadString();
+ if (name == "load")
+ type_ = mtLoad;
+ }
+}
+
+void ObjcMethod::GetLoadMethodReferences(std::set<uint64_t> &address_list) const
+{
+ if (type_ == mtLoad && imp_)
+ address_list.insert(address() + ((size_ == osDWord) ? offsetof(objc_method, imp) : offsetof(objc_method_64, imp)));
+}
+
+void ObjcMethod::GetStringReferences(std::set<uint64_t> &address_list) const
+{
+ if (name_)
+ address_list.insert(address() + ((size_ == osDWord) ? offsetof(objc_method, name) : offsetof(objc_method_64, name)));
+ if (types_)
+ address_list.insert(address() + ((size_ == osDWord) ? offsetof(objc_method, types) : offsetof(objc_method_64, types)));
+}
+
+/**
+ * ObjcMethodList
+ */
+
+ObjcMethodList::ObjcMethodList()
+ : BaseObjcMethodList()
+{
+
+}
+
+ObjcMethod *ObjcMethodList::Add(uint64_t address)
+{
+ ObjcMethod *objc_method = new ObjcMethod(this, address);
+ AddObject(objc_method);
+ return objc_method;
+}
+
+ObjcMethod *ObjcMethodList::item(size_t index) const
+{
+ return reinterpret_cast<ObjcMethod *>(BaseObjcMethodList::item(index));
+}
+
+void ObjcMethodList::ReadFromFile(MacArchitecture &file, uint64_t address)
+{
+ if (!file.AddressSeek(address))
+ return;
+
+ size_t method_size = file.cpu_address_size() == osDWord ? sizeof(objc_method) : sizeof(objc_method_64);
+ objc_method_list list;
+
+ file.Read(&list, sizeof(list));
+
+ address += sizeof(list);
+ for (size_t i = 0; i < list.count; i++) {
+ Add(address);
+ address += method_size;
+ }
+
+ for (size_t i = 0; i < count(); i++) {
+ item(i)->ReadFromFile(file);
+ }
+}
+
+/**
+ * ObjcClass
+ */
+
+ObjcClass::ObjcClass(IObjcClassList *owner, uint64_t address)
+ : BaseObjcClass(owner, address), size_(osDWord), isa_(0), super_class_(0), name_(0),
+ version_(0), info_(0), instance_size_(0), ivars_(0), methods_(0), cache_(0), protocols_(0)
+{
+ method_list_ = new ObjcMethodList();
+}
+
+ObjcClass::~ObjcClass()
+{
+ delete method_list_;
+}
+
+void ObjcClass::ReadFromFile(MacArchitecture &file)
+{
+ if (!file.AddressSeek(address()))
+ return;
+
+ size_ = file.cpu_address_size();
+ if (file.cpu_address_size() == osDWord) {
+ objc_class klass;
+ file.Read(&klass, sizeof(klass));
+ isa_ = klass.isa;
+ super_class_ = klass.super_class;
+ name_ = klass.name;
+ version_ = klass.version;
+ info_ = klass.info;
+ instance_size_ = klass.instance_size;
+ ivars_ = klass.ivars;
+ methods_ = klass.methods;
+ cache_ = klass.cache;
+ protocols_ = klass.protocols;
+ } else {
+ objc_class_64 klass;
+ file.Read(&klass, sizeof(klass));
+ isa_ = klass.isa;
+ super_class_ = klass.super_class;
+ name_ = klass.name;
+ version_ = klass.version;
+ info_ = klass.info;
+ instance_size_ = klass.instance_size;
+ ivars_ = klass.ivars;
+ methods_ = klass.methods;
+ cache_ = klass.cache;
+ protocols_ = klass.protocols;
+ }
+
+ if (methods_)
+ method_list_->ReadFromFile(file, methods_);
+}
+
+void ObjcClass::GetLoadMethodReferences(std::set<uint64_t> &address_list) const
+{
+ method_list_->GetLoadMethodReferences(address_list);
+}
+
+void ObjcClass::GetStringReferences(std::set<uint64_t> &address_list) const
+{
+ if (isa_ && (info_ & (CLS_CLASS | CLS_META)) == CLS_META)
+ address_list.insert(address() + ((size_ == osDWord) ? offsetof(objc_class, isa) : offsetof(objc_class_64, isa)));
+ if (super_class_)
+ address_list.insert(address() + ((size_ == osDWord) ? offsetof(objc_class, super_class) : offsetof(objc_class_64, super_class)));
+ if (name_)
+ address_list.insert(address() + ((size_ == osDWord) ? offsetof(objc_class, name) : offsetof(objc_class_64, name)));
+
+ method_list_->GetStringReferences(address_list);
+}
+
+/**
+ * ObjcClassList
+ */
+
+ObjcClassList::ObjcClassList()
+ : BaseObjcClassList()
+{
+
+}
+
+ObjcClass *ObjcClassList::Add(uint64_t address)
+{
+ ObjcClass *objc_class = new ObjcClass(this, address);
+ AddObject(objc_class);
+ return objc_class;
+}
+
+ObjcClass *ObjcClassList::item(size_t index) const
+{
+ return reinterpret_cast<ObjcClass *>(BaseObjcClassList::item(index));
+}
+
+void ObjcClassList::ReadFromFile(MacArchitecture &file, size_t class_count)
+{
+ size_t i, old_count;
+ size_t value_size = OperandSizeToValue(file.cpu_address_size());
+ uint64_t value = 0;
+ old_count = count();
+ for (i = 0; i < class_count; i++) {
+ assert(sizeof(value) >= value_size);
+ file.Read(&value, value_size);
+ if (!GetClassByAddress(value))
+ Add(value);
+ }
+
+ uint64_t pos = file.Tell();
+ for (i = old_count; i < count(); i++) {
+ ObjcClass *obj_class = item(i);
+ obj_class->ReadFromFile(file);
+ if (obj_class->isa() && (obj_class->info() & CLS_CLASS) && !GetClassByAddress(obj_class->isa()))
+ Add(obj_class->isa());
+ }
+ file.Seek(pos);
+}
+
+/**
+ * ObjcCategory
+ */
+
+ObjcCategory::ObjcCategory(IObjcCategoryList *owner, uint64_t address)
+ : BaseObjcCategory(owner, address), size_(osDWord), category_name_(0), class_name_(0), instance_methods_(0), class_methods_(0), protocols_(0)
+{
+ method_list_ = new ObjcMethodList();
+ class_method_list_ = new ObjcMethodList();
+}
+
+ObjcCategory::~ObjcCategory()
+{
+ delete method_list_;
+ delete class_method_list_;
+}
+
+void ObjcCategory::ReadFromFile(MacArchitecture &file)
+{
+ if (!file.AddressSeek(address()))
+ return;
+
+ size_ = file.cpu_address_size();
+ if (file.cpu_address_size() == osDWord) {
+ objc_category category;
+ file.Read(&category, sizeof(category));
+ category_name_ = category.category_name;
+ class_name_ = category.class_name;
+ instance_methods_ = category.instance_methods;
+ class_methods_ = category.class_methods;
+ protocols_ = category.protocols;
+ } else {
+ objc_category_64 category;
+ file.Read(&category, sizeof(category));
+ category_name_ = category.category_name;
+ class_name_ = category.class_name;
+ instance_methods_ = category.instance_methods;
+ class_methods_ = category.class_methods;
+ protocols_ = category.protocols;
+ }
+
+ if (instance_methods_)
+ method_list_->ReadFromFile(file, instance_methods_);
+ if (class_methods_)
+ class_method_list_->ReadFromFile(file, class_methods_);
+}
+
+void ObjcCategory::GetLoadMethodReferences(std::set<uint64_t> &address_list) const
+{
+ method_list_->GetLoadMethodReferences(address_list);
+}
+
+void ObjcCategory::GetStringReferences(std::set<uint64_t> &address_list) const
+{
+ if (category_name_)
+ address_list.insert(address() + ((size_ == osDWord) ? offsetof(objc_category, category_name) : offsetof(objc_category_64, category_name)));
+ if (class_name_)
+ address_list.insert(address() + ((size_ == osDWord) ? offsetof(objc_category, class_name) : offsetof(objc_category_64, class_name)));
+
+ method_list_->GetStringReferences(address_list);
+ class_method_list_->GetStringReferences(address_list);
+}
+
+/**
+ * ObjcCategoryList
+ */
+
+ObjcCategoryList::ObjcCategoryList()
+ : BaseObjcCategoryList()
+{
+
+}
+
+ObjcCategory *ObjcCategoryList::Add(uint64_t address)
+{
+ ObjcCategory *objc_category = new ObjcCategory(this, address);
+ AddObject(objc_category);
+ return objc_category;
+}
+
+ObjcCategory *ObjcCategoryList::item(size_t index) const
+{
+ return reinterpret_cast<ObjcCategory *>(BaseObjcCategoryList::item(index));
+}
+
+void ObjcCategoryList::ReadFromFile(MacArchitecture &file, size_t count)
+{
+ size_t i;
+ size_t value_size = OperandSizeToValue(file.cpu_address_size());
+ uint64_t value = 0;
+ for (i = 0; i < count; i++) {
+ assert(sizeof(value) >= value_size);
+ file.Read(&value, value_size);
+ Add(value);
+ }
+ for (i = 0; i < count; i++) {
+ item(i)->ReadFromFile(file);
+ }
+}
+
+/**
+ * ObjcSelector
+ */
+
+ObjcSelector::ObjcSelector(IObjcSelectorList *owner, uint64_t address)
+ : BaseObjcSelector(owner, address)
+{
+
+}
+
+void ObjcSelector::GetStringReferences(std::set<uint64_t> &address_list) const
+{
+ address_list.insert(address());
+}
+
+/**
+ * ObjcSelectorList
+ */
+
+ObjcSelectorList::ObjcSelectorList()
+ : BaseObjcSelectorList()
+{
+
+}
+
+void ObjcSelectorList::ReadFromFile(MacArchitecture &file)
+{
+ MacSection *section = GetObjcSection(file, 1, "__message_refs");
+ if (section && file.AddressSeek(section->address())) {
+ size_t value_size = OperandSizeToValue(file.cpu_address_size());
+ size_t count = static_cast<size_t>(section->size() / OperandSizeToValue(file.cpu_address_size()));
+ uint64_t address = section->address();
+ for (size_t i = 0; i < count; i++) {
+ Add(address);
+ address += value_size;
+ }
+ }
+}
+
+ObjcSelector *ObjcSelectorList::Add(uint64_t address)
+{
+ ObjcSelector *sel = new ObjcSelector(this, address);
+ AddObject(sel);
+ return sel;
+}
+
+/**
+ * ObjcProtocol
+ */
+
+ObjcProtocol::ObjcProtocol(ObjcProtocolList *owner, uint64_t address)
+ : BaseObjcProtocol(owner, address)
+{
+ size_ = osDWord;
+ isa_ = 0;
+ name_ = 0;
+ protocols_ = 0;
+ instance_methods_ = 0;
+ class_methods_ = 0;
+}
+
+void ObjcProtocol::GetStringReferences(std::set<uint64_t> &address_list) const
+{
+ address_list.insert(address() + ((size_ == osDWord) ? offsetof(objc_protocol, name) : offsetof(objc_protocol_64, name)));
+}
+
+void ObjcProtocol::ReadFromFile(MacArchitecture &file)
+{
+ if (!file.AddressSeek(address()))
+ return;
+
+ size_ = file.cpu_address_size();
+ if (file.cpu_address_size() == osDWord) {
+ objc_protocol protocol;
+ file.Read(&protocol, sizeof(protocol));
+ isa_ = protocol.isa;
+ name_ = protocol.name;
+ protocols_ = protocol.protocols;
+ instance_methods_ = protocol.instance_methods;
+ class_methods_ = protocol.class_methods;
+ } else {
+ objc_protocol_64 protocol;
+ file.Read(&protocol, sizeof(protocol));
+ isa_ = protocol.isa;
+ name_ = protocol.name;
+ protocols_ = protocol.protocols;
+ instance_methods_ = protocol.instance_methods;
+ class_methods_ = protocol.class_methods;
+ }
+}
+
+/**
+ * ObjcProtocolList
+ */
+
+ObjcProtocolList::ObjcProtocolList()
+ : BaseObjcProtocolList()
+{
+
+}
+
+ObjcProtocol *ObjcProtocolList::item(size_t index) const
+{
+ return reinterpret_cast<ObjcProtocol *>(BaseObjcProtocolList::item(index));
+}
+
+void ObjcProtocolList::ReadFromFile(MacArchitecture &file)
+{
+ MacSection *section = GetObjcSection(file, 1, "__protocol");
+ if (section && file.AddressSeek(section->address())) {
+ size_t protocol_size = (file.cpu_address_size() == osDWord) ? sizeof(objc_protocol) : sizeof(objc_protocol_64);
+ size_t count = static_cast<size_t>(section->size() / protocol_size);
+ uint64_t address = section->address();
+ for (size_t i = 0; i < count; i++) {
+ Add(address);
+ address += protocol_size;
+ }
+ }
+ for (size_t i = 0; i < count(); i++) {
+ item(i)->ReadFromFile(file);
+ }
+}
+
+ObjcProtocol *ObjcProtocolList::Add(uint64_t address)
+{
+ ObjcProtocol *prot = new ObjcProtocol(this, address);
+ AddObject(prot);
+ return prot;
+}
+
+/**
+ * ObjcStorage
+ */
+
+ObjcStorage::ObjcStorage()
+ : IObjcStorage()
+{
+ class_list_ = new ObjcClassList();
+ category_list_ = new ObjcCategoryList();
+ selector_list_ = new ObjcSelectorList();
+ protocol_list_ = new ObjcProtocolList();
+}
+
+ObjcStorage::~ObjcStorage()
+{
+ delete class_list_;
+ delete category_list_;
+ delete selector_list_;
+ delete protocol_list_;
+}
+
+void ObjcStorage::ReadFromFile(MacArchitecture &file)
+{
+ size_t i;
+ std::vector<uint64_t> symtab_list;
+
+ MacSection *section = GetObjcSection(file, 1, SECT_OBJC_MODULES);
+ if (section && file.AddressSeek(section->address())) {
+ size_t module_size = (file.cpu_address_size() == osDWord) ? sizeof(objc_module) : sizeof(objc_module_64);
+ size_t module_count = static_cast<size_t>(section->size() / module_size);
+ for (i = 0; i < module_count; i++) {
+ uint64_t symtab;
+ if (file.cpu_address_size() == osDWord) {
+ objc_module module;
+ file.Read(&module, sizeof(module));
+ symtab = module.symtab;
+ } else {
+ objc_module_64 module;
+ file.Read(&module, sizeof(module));
+ symtab = module.symtab;
+ }
+ if (symtab)
+ symtab_list.push_back(symtab);
+ }
+ }
+
+ for (i = 0; i < symtab_list.size(); i++) {
+ if (file.AddressSeek(symtab_list[i])) {
+ uint16_t cls_def_cnt;
+ uint16_t cat_def_cnt;
+
+ if (file.cpu_address_size() == osDWord) {
+ objc_symtab symtab;
+ file.Read(&symtab, sizeof(symtab));
+ cls_def_cnt = symtab.cls_def_cnt;
+ cat_def_cnt = symtab.cat_def_cnt;
+ } else {
+ objc_symtab_64 symtab;
+ file.Read(&symtab, sizeof(symtab));
+ cls_def_cnt = symtab.cls_def_cnt;
+ cat_def_cnt = symtab.cat_def_cnt;
+ }
+
+ class_list_->ReadFromFile(file, cls_def_cnt);
+ category_list_->ReadFromFile(file, cat_def_cnt);
+ }
+ }
+ selector_list_->ReadFromFile(file);
+ protocol_list_->ReadFromFile(file);
+
+ MacSegment *segment = file.segment_list()->GetSectionByName(SEG_OBJC);
+ if (segment)
+ segment_list_.push_back(segment);
+}
+
+void ObjcStorage::GetLoadMethodReferences(std::set<uint64_t> &address_list) const
+{
+ class_list_->GetLoadMethodReferences(address_list);
+ category_list_->GetLoadMethodReferences(address_list);
+}
+
+void ObjcStorage::GetStringReferences(std::set<uint64_t> &address_list) const
+{
+ class_list_->GetStringReferences(address_list);
+ category_list_->GetStringReferences(address_list);
+ selector_list_->GetStringReferences(address_list);
+ protocol_list_->GetStringReferences(address_list);
+}
+
+/**
+ * Objc2Method
+ */
+
+Objc2Method::Objc2Method(IObjcMethodList *owner, uint64_t address)
+ : BaseObjcMethod(owner, address), size_(osDWord), name_(0), types_(0), imp_(0), type_(mtUnknown)
+{
+
+}
+
+void Objc2Method::ReadFromFile(MacArchitecture &file)
+{
+ if (!file.AddressSeek(address()))
+ return;
+
+ size_ = file.cpu_address_size();
+ if (file.cpu_address_size() == osDWord) {
+ objc2_method method;
+ file.Read(&method, sizeof(method));
+ name_ = method.name;
+ types_ = method.types;
+ imp_ = method.imp;
+ } else {
+ objc2_method_64 method;
+ file.Read(&method, sizeof(method));
+ name_ = method.name;
+ types_ = method.types;
+ imp_ = method.imp;
+ }
+
+ if (name_ && file.AddressSeek(name_)) {
+ std::string name = file.ReadString();
+ if (name == "load")
+ type_ = mtLoad;
+ }
+}
+
+void Objc2Method::GetLoadMethodReferences(std::set<uint64_t> &address_list) const
+{
+ if (type_ == mtLoad && imp_)
+ address_list.insert(address() + ((size_ == osDWord) ? offsetof(objc2_method, imp) : offsetof(objc2_method_64, imp)));
+}
+
+void Objc2Method::GetStringReferences(std::set<uint64_t> &address_list) const
+{
+ if (name_)
+ address_list.insert(address() + ((size_ == osDWord) ? offsetof(objc2_method, name) : offsetof(objc2_method_64, name)));
+ if (types_)
+ address_list.insert(address() + ((size_ == osDWord) ? offsetof(objc2_method, types) : offsetof(objc2_method_64, types)));
+}
+
+/**
+ * Objc2MethodList
+ */
+
+Objc2MethodList::Objc2MethodList()
+ : BaseObjcMethodList()
+{
+
+}
+
+Objc2Method *Objc2MethodList::Add(uint64_t address)
+{
+ Objc2Method *objc_method = new Objc2Method(this, address);
+ AddObject(objc_method);
+ return objc_method;
+}
+
+Objc2Method *Objc2MethodList::item(size_t index) const
+{
+ return reinterpret_cast<Objc2Method *>(BaseObjcMethodList::item(index));
+}
+
+void Objc2MethodList::ReadFromFile(MacArchitecture &file, uint64_t address)
+{
+ if (!file.AddressSeek(address))
+ return;
+
+ size_t value_size = OperandSizeToValue(file.cpu_address_size());
+ size_t method_size = file.cpu_address_size() == osDWord ? sizeof(objc_method) : sizeof(objc_method_64);
+ /*uint32_t entsize =*/ file.ReadDWord();
+ uint32_t method_count = file.ReadDWord();
+ address += sizeof(uint32_t)/*entsize*/ + sizeof(method_count);
+ for (size_t i = 0; i < method_count; i++) {
+ Add(address);
+ address += method_size;
+ }
+
+ for (size_t i = 0; i < count(); i++) {
+ item(i)->ReadFromFile(file);
+ }
+}
+
+/**
+ * Objc2Class
+ */
+
+Objc2Class::Objc2Class(IObjcClassList *owner, uint64_t address)
+ : BaseObjcClass(owner, address)
+{
+ size_ = osDWord;
+ flags_ = 0;
+ isa_ = 0;
+ super_class_ = 0;
+ cache_ = 0;
+ vtable_ = 0;
+ data_ = 0;
+ ivar_layout_ = 0;
+ name_ = 0;
+ base_methods_ = 0;
+ base_protocols_ = 0;
+ ivars_ = 0;
+ protocols_ = 0;
+ weak_ivar_layout_ = 0;
+ base_properties_ = 0;
+ instance_start_ = 0;
+ instance_size_ = 0;
+ method_list_ = new Objc2MethodList();
+}
+
+Objc2Class::~Objc2Class()
+{
+ delete method_list_;
+}
+
+void Objc2Class::ReadFromFile(MacArchitecture &file)
+{
+ if (!file.AddressSeek(address()))
+ return;
+
+ size_ = file.cpu_address_size();
+
+ if (file.cpu_address_size() == osDWord) {
+ objc2_class klass;
+ file.Read(&klass, sizeof(klass));
+ isa_ = klass.isa;
+ super_class_ = klass.super_class;
+ cache_ = klass.cache;
+ vtable_ = klass.vtable;
+ data_ = klass.data;
+ } else {
+ objc2_class_64 klass;
+ file.Read(&klass, sizeof(klass));
+ isa_ = klass.isa;
+ super_class_ = klass.super_class;
+ cache_ = klass.cache;
+ vtable_ = klass.vtable;
+ data_ = klass.data;
+ }
+
+ if (!file.AddressSeek(data_))
+ return;
+
+ if (file.cpu_address_size() == osDWord) {
+ objc2_class_data data;
+ file.Read(&data, sizeof(data));
+ flags_ = data.flags;
+ instance_start_ = data.instance_start;
+ instance_size_ = data.instance_size;
+ ivar_layout_ = data.ivar_layout;
+ name_ = data.name;
+ base_methods_ = data.base_methods;
+ base_protocols_ = data.base_protocols;
+ ivars_ = data.ivars;
+ weak_ivar_layout_ = data.weak_ivar_layout;
+ base_properties_ = data.base_properties;
+ } else {
+ objc2_class_data_64 data;
+ file.Read(&data, sizeof(data));
+ flags_ = data.flags;
+ instance_start_ = data.instance_start;
+ instance_size_ = data.instance_size;
+ ivar_layout_ = data.ivar_layout;
+ name_ = data.name;
+ base_methods_ = data.base_methods;
+ base_protocols_ = data.base_protocols;
+ ivars_ = data.ivars;
+ weak_ivar_layout_ = data.weak_ivar_layout;
+ base_properties_ = data.base_properties;
+ }
+
+ if (base_methods_)
+ method_list_->ReadFromFile(file, base_methods_);
+};
+
+void Objc2Class::GetLoadMethodReferences(std::set<uint64_t> &address_list) const
+{
+ method_list_->GetLoadMethodReferences(address_list);
+}
+
+void Objc2Class::GetStringReferences(std::set<uint64_t> &address_list) const
+{
+ if (name_)
+ address_list.insert(data_ + ((size_ == osDWord) ? offsetof(objc2_class_data, name) : offsetof(objc2_class_data_64, name)));
+
+ method_list_->GetStringReferences(address_list);
+}
+
+/**
+ * Objc2ClassList
+ */
+
+Objc2ClassList::Objc2ClassList()
+ : BaseObjcClassList()
+{
+
+}
+
+Objc2Class *Objc2ClassList::Add(uint64_t address)
+{
+ Objc2Class *objc_class = new Objc2Class(this, address);
+ AddObject(objc_class);
+ return objc_class;
+}
+
+Objc2Class *Objc2ClassList::item(size_t index) const
+{
+ return reinterpret_cast<Objc2Class *>(BaseObjcClassList::item(index));
+}
+
+void Objc2ClassList::ReadFromFile(MacArchitecture &file)
+{
+ const char *classlist_section_name[] = {
+ "__objc_nlclslist",
+ "__objc_classlist"
+ };
+
+ for (size_t j = 0; j < _countof(classlist_section_name); j++) {
+ MacSection *section = GetObjcSection(file, 2, classlist_section_name[j]);
+ if (section && file.AddressSeek(section->address())) {
+ size_t count = static_cast<size_t>(section->size() / OperandSizeToValue(file.cpu_address_size()));
+ size_t value_size = OperandSizeToValue(file.cpu_address_size());
+ uint64_t value = 0;
+ for (size_t i = 0; i < count; i++) {
+ assert(sizeof(value) >= value_size);
+ file.Read(&value, value_size);
+ if (!GetClassByAddress(value))
+ Add(value);
+ }
+ }
+ }
+ for (size_t i = 0; i < count(); i++) {
+ Objc2Class *obj_class = item(i);
+ obj_class->ReadFromFile(file);
+ if (obj_class->isa() && !GetClassByAddress(obj_class->isa()))
+ Add(obj_class->isa());
+ if (obj_class->super_class() && !GetClassByAddress(obj_class->super_class()))
+ Add(obj_class->super_class());
+ }
+}
+
+/**
+ * ObjcCategory
+ */
+
+Objc2Category::Objc2Category(IObjcCategoryList *owner, uint64_t address)
+ : BaseObjcCategory(owner, address), name_(0), cls_(0), instance_methods_(0), class_methods_(0), protocols_(0), instance_properties_(0), size_(osDWord)
+{
+ method_list_ = new Objc2MethodList();
+ class_method_list_ = new Objc2MethodList();
+}
+
+Objc2Category::~Objc2Category()
+{
+ delete method_list_;
+ delete class_method_list_;
+}
+
+void Objc2Category::ReadFromFile(MacArchitecture &file)
+{
+ if (!file.AddressSeek(address()))
+ return;
+
+ size_ = file.cpu_address_size();
+ if (file.cpu_address_size() == osDWord) {
+ objc2_category category;
+ file.Read(&category, sizeof(category));
+ name_ = category.name;
+ cls_ = category.cls;
+ instance_methods_ = category.instance_methods;
+ class_methods_ = category.class_methods;
+ protocols_ = category.protocols;
+ instance_properties_ = category.instance_properties;
+ } else {
+ objc2_category_64 category;
+ file.Read(&category, sizeof(category));
+ name_ = category.name;
+ cls_ = category.cls;
+ instance_methods_ = category.instance_methods;
+ class_methods_ = category.class_methods;
+ protocols_ = category.protocols;
+ instance_properties_ = category.instance_properties;
+ }
+
+ if (instance_methods_)
+ method_list_->ReadFromFile(file, instance_methods_);
+ if (class_methods_)
+ class_method_list_->ReadFromFile(file, class_methods_);
+}
+
+void Objc2Category::GetLoadMethodReferences(std::set<uint64_t> &address_list) const
+{
+ method_list_->GetLoadMethodReferences(address_list);
+ class_method_list_->GetStringReferences(address_list);
+}
+
+void Objc2Category::GetStringReferences(std::set<uint64_t> &address_list) const
+{
+ if (name_)
+ address_list.insert(address() + ((size_ == osDWord) ? offsetof(objc2_category, name) : offsetof(objc2_category_64, name)));
+
+ method_list_->GetStringReferences(address_list);
+ class_method_list_->GetStringReferences(address_list);
+}
+
+/**
+ * Objc2CategoryList
+ */
+
+Objc2CategoryList::Objc2CategoryList()
+ : BaseObjcCategoryList()
+{
+
+}
+
+Objc2Category *Objc2CategoryList::Add(uint64_t address)
+{
+ Objc2Category *objc_category = new Objc2Category(this, address);
+ AddObject(objc_category);
+ return objc_category;
+}
+
+Objc2Category *Objc2CategoryList::item(size_t index) const
+{
+ return reinterpret_cast<Objc2Category *>(BaseObjcCategoryList::item(index));
+}
+
+void Objc2CategoryList::ReadFromFile(MacArchitecture &file)
+{
+ const char *catlist_section_name[] = {
+ "__objc_nlcatlist",
+ "__objc_catlist"
+ };
+
+ size_t value_size = OperandSizeToValue(file.cpu_address_size());
+ uint64_t value = 0;
+ assert(sizeof(value) >= value_size);
+ for (size_t j = 0; j < _countof(catlist_section_name); j++) {
+ MacSection *section = GetObjcSection(file, 2, catlist_section_name[j]);
+ if (section && file.AddressSeek(section->address())) {
+ size_t count = static_cast<size_t>(section->size()) / OperandSizeToValue(file.cpu_address_size());
+ for (size_t i = 0; i < count; i++) {
+ file.Read(&value, value_size);
+ Add(value);
+ }
+ }
+ }
+ for (size_t i = 0; i < count(); i++) {
+ item(i)->ReadFromFile(file);
+ }
+}
+
+/**
+ * Objc2SelectorList
+ */
+
+Objc2SelectorList::Objc2SelectorList()
+ : BaseObjcSelectorList()
+{
+
+}
+
+void Objc2SelectorList::ReadFromFile(MacArchitecture &file)
+{
+ MacSection *section = GetObjcSection(file, 2, "__objc_selrefs");
+ if (section && file.AddressSeek(section->address())) {
+ size_t value_size = OperandSizeToValue(file.cpu_address_size());
+ size_t count = static_cast<size_t>(section->size() / OperandSizeToValue(file.cpu_address_size()));
+ uint64_t address = section->address();
+ for (size_t i = 0; i < count; i++) {
+ Add(address);
+ address += value_size;
+ }
+ }
+}
+
+ObjcSelector *Objc2SelectorList::Add(uint64_t address)
+{
+ ObjcSelector *sel = new ObjcSelector(this, address);
+ AddObject(sel);
+ return sel;
+}
+
+/**
+ * Objc2Protocol
+ */
+
+Objc2Protocol::Objc2Protocol(Objc2ProtocolList *owner, uint64_t address)
+ : BaseObjcProtocol(owner, address), size_(osDWord)
+{
+ method_list_ = new Objc2MethodList();
+}
+
+Objc2Protocol::~Objc2Protocol()
+{
+ delete method_list_;
+}
+
+void Objc2Protocol::GetStringReferences(std::set<uint64_t> &address_list) const
+{
+ address_list.insert(address() + ((size_ == osDWord) ? offsetof(objc2_protocol, name) : offsetof(objc2_protocol_64, name)));
+ method_list_->GetStringReferences(address_list);
+}
+
+void Objc2Protocol::ReadFromFile(MacArchitecture &file)
+{
+ if (!file.AddressSeek(address()))
+ return;
+
+ size_ = file.cpu_address_size();
+ if (file.cpu_address_size() == osDWord) {
+ objc2_protocol protocol;
+ file.Read(&protocol, sizeof(protocol));
+ isa_ = protocol.isa;
+ name_ = protocol.name;
+ protocols_ = protocol.protocols;
+ instance_methods_ = protocol.instance_methods;
+ class_methods_ = protocol.class_methods;
+ optional_instance_methods_ = protocol.optional_instance_methods;
+ optional_class_methods_ = protocol.optional_class_methods;
+ instance_properties_ = protocol.instance_properties;
+ } else {
+ objc2_protocol_64 protocol;
+ file.Read(&protocol, sizeof(protocol));
+ isa_ = protocol.isa;
+ name_ = protocol.name;
+ protocols_ = protocol.protocols;
+ instance_methods_ = protocol.instance_methods;
+ class_methods_ = protocol.class_methods;
+ optional_instance_methods_ = protocol.optional_instance_methods;
+ optional_class_methods_ = protocol.optional_class_methods;
+ instance_properties_ = protocol.instance_properties;
+ }
+
+ if (instance_methods_)
+ method_list_->ReadFromFile(file, instance_methods_);
+}
+
+/**
+ * Objc2ProtocolList
+ */
+
+Objc2ProtocolList::Objc2ProtocolList()
+ : BaseObjcProtocolList()
+{
+
+}
+
+Objc2Protocol *Objc2ProtocolList::item(size_t index) const
+{
+ return reinterpret_cast<Objc2Protocol *>(BaseObjcProtocolList::item(index));
+}
+
+void Objc2ProtocolList::ReadFromFile(MacArchitecture &file)
+{
+ const char *protolist_section_name[] = {
+ "__objc_protolist",
+ "__objc_protorefs"
+ };
+
+ size_t value_size = OperandSizeToValue(file.cpu_address_size());
+ for (size_t j = 0; j < _countof(protolist_section_name); j++) {
+ MacSection *section = GetObjcSection(file, 2, protolist_section_name[j]);
+ if (section && file.AddressSeek(section->address())) {
+ size_t count = static_cast<size_t>(section->size() / OperandSizeToValue(file.cpu_address_size()));
+ uint64_t value = 0;
+ for (size_t i = 0; i < count; i++) {
+ file.Read(&value, value_size);
+ if (!GetProtocolByAddress(value))
+ Add(value);
+ }
+ }
+ }
+ for (size_t i = 0; i < count(); i++) {
+ item(i)->ReadFromFile(file);
+ }
+}
+
+Objc2Protocol *Objc2ProtocolList::Add(uint64_t address)
+{
+ Objc2Protocol *prot = new Objc2Protocol(this, address);
+ AddObject(prot);
+ return prot;
+}
+
+void Objc2ProtocolList::GetStringReferences(std::set<uint64_t> &address_list) const
+{
+ for (size_t i = 0; i < count(); i++) {
+ item(i)->GetStringReferences(address_list);
+ }
+}
+
+/**
+ * Objc2Message
+ */
+
+Objc2Message::Objc2Message(Objc2MessageList *owner, uint64_t address)
+ : IObject(), owner_(owner), address_(address), size_(osDefault), imp_(0), name_(0)
+{
+
+}
+
+Objc2Message::~Objc2Message()
+{
+ if (owner_)
+ owner_->RemoveObject(this);
+}
+
+void Objc2Message::ReadFromFile(MacArchitecture &file)
+{
+ if (!file.AddressSeek(address_))
+ return;
+
+ size_ = file.cpu_address_size();
+ if (file.cpu_address_size() == osDWord) {
+ objc2_message message;
+ file.Read(&message, sizeof(message));
+ imp_ = message.imp;
+ name_ = message.name;
+ } else {
+ objc2_message_64 message;
+ file.Read(&message, sizeof(message));
+ imp_ = message.imp;
+ name_ = message.name;
+ }
+}
+
+void Objc2Message::GetStringReferences(std::set<uint64_t> &address_list) const
+{
+ address_list.insert(address_ + ((size_ == osDWord) ? offsetof(objc2_message, name) : offsetof(objc2_message_64, name)));
+}
+
+/**
+ * Objc2MessageList
+ */
+
+Objc2MessageList::Objc2MessageList()
+ : ObjectList<Objc2Message>()
+{
+
+}
+
+void Objc2MessageList::ReadFromFile(MacArchitecture &file)
+{
+ MacSection *section = GetObjcSection(file, 2, "__objc_msgrefs");
+ if (section && file.AddressSeek(section->address())) {
+ size_t value_size = file.cpu_address_size() == osDWord ? sizeof(objc2_message) : sizeof(objc2_message_64);
+ size_t count = static_cast<size_t>(section->size() / OperandSizeToValue(file.cpu_address_size()));
+ uint64_t address = section->address();
+ for (size_t i = 0; i < count; i++) {
+ Add(address);
+ address += value_size;
+ }
+ }
+ for (size_t i = 0; i < count(); i++) {
+ item(i)->ReadFromFile(file);
+ }
+}
+
+Objc2Message *Objc2MessageList::Add(uint64_t address)
+{
+ Objc2Message *message = new Objc2Message(this, address);
+ AddObject(message);
+ return message;
+}
+
+void Objc2MessageList::GetStringReferences(std::set<uint64_t> &address_list) const
+{
+ for (size_t i = 0; i < count(); i++) {
+ item(i)->GetStringReferences(address_list);
+ }
+}
+
+/**
+ * Objc2Storage
+ */
+
+Objc2Storage::Objc2Storage()
+ : IObjcStorage()
+{
+ class_list_ = new Objc2ClassList();
+ category_list_ = new Objc2CategoryList();
+ selector_list_ = new Objc2SelectorList();
+ protocol_list_ = new Objc2ProtocolList();
+ message_list_ = new Objc2MessageList();
+}
+
+Objc2Storage::~Objc2Storage()
+{
+ delete class_list_;
+ delete category_list_;
+ delete selector_list_;
+ delete protocol_list_;
+ delete message_list_;
+}
+
+void Objc2Storage::ReadFromFile(MacArchitecture &file)
+{
+ class_list_->ReadFromFile(file);
+ category_list_->ReadFromFile(file);
+ selector_list_->ReadFromFile(file);
+ protocol_list_->ReadFromFile(file);
+ message_list_->ReadFromFile(file);
+
+ for (size_t i = 0; i < file.section_list()->count(); i++) {
+ MacSection *section = file.section_list()->item(i);
+ if (!section->parent() || find(segment_list_.begin(), segment_list_.end(), section->parent()) != segment_list_.end())
+ continue;
+
+ if (section->name().substr(0, 7) == "__objc_" && GetObjcSection(file, 2, section->name()))
+ segment_list_.push_back(section->parent());
+ }
+}
+
+void Objc2Storage::GetLoadMethodReferences(std::set<uint64_t> &address_list) const
+{
+ class_list_->GetLoadMethodReferences(address_list);
+ category_list_->GetLoadMethodReferences(address_list);
+}
+
+void Objc2Storage::GetStringReferences(std::set<uint64_t> &address_list) const
+{
+ class_list_->GetStringReferences(address_list);
+ category_list_->GetStringReferences(address_list);
+ selector_list_->GetStringReferences(address_list);
+ protocol_list_->GetStringReferences(address_list);
+ message_list_->GetStringReferences(address_list);
+}
+
+/**
+ * Objc
+ */
+
+Objc::Objc()
+ : IObject(), storage_(NULL)
+{
+
+}
+
+Objc::~Objc()
+{
+ delete storage_;
+}
+
+bool Objc::ReadFromFile(MacArchitecture &file)
+{
+ delete storage_;
+ storage_ = NULL;
+
+ if (GetObjcSection(file, 1, "__image_info"))
+ storage_ = new ObjcStorage();
+ else if (GetObjcSection(file, 2, "__objc_imageinfo"))
+ storage_ = new Objc2Storage();
+
+ if (storage_) {
+ storage_->ReadFromFile(file);
+ return true;
+ }
+
+ return false;
+}
+
+void Objc::GetLoadMethodReferences(std::set<uint64_t> &address_list) const
+{
+ address_list.clear();
+ if (storage_)
+ storage_->GetLoadMethodReferences(address_list);
+}
+
+void Objc::GetStringReferences(std::set<uint64_t> &address_list) const
+{
+ address_list.clear();
+ if (storage_)
+ storage_->GetStringReferences(address_list);
+}
+
+std::vector<MacSegment *> Objc::segment_list() const
+{
+ if (storage_)
+ return storage_->segment_list();
+
+ return std::vector<MacSegment *>();
+} \ No newline at end of file