#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 §ion_name) { std::set 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 &address_list) const { for (size_t i = 0; i < count(); i++) { item(i)->GetLoadMethodReferences(address_list); } } void BaseObjcMethodList::GetStringReferences(std::set &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 &address_list) const { for (size_t i = 0; i < count(); i++) { item(i)->GetLoadMethodReferences(address_list); } } void BaseObjcClassList::GetStringReferences(std::set &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::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 &address_list) const { for (size_t i = 0; i < count(); i++) { item(i)->GetLoadMethodReferences(address_list); } } void BaseObjcCategoryList::GetStringReferences(std::set &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 &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 &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 &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 &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(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 &address_list) const { method_list_->GetLoadMethodReferences(address_list); } void ObjcClass::GetStringReferences(std::set &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(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 &address_list) const { method_list_->GetLoadMethodReferences(address_list); } void ObjcCategory::GetStringReferences(std::set &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(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 &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(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 &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(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(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 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(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 &address_list) const { class_list_->GetLoadMethodReferences(address_list); category_list_->GetLoadMethodReferences(address_list); } void ObjcStorage::GetStringReferences(std::set &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 &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 &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(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 &address_list) const { method_list_->GetLoadMethodReferences(address_list); } void Objc2Class::GetStringReferences(std::set &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(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(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 &address_list) const { method_list_->GetLoadMethodReferences(address_list); class_method_list_->GetStringReferences(address_list); } void Objc2Category::GetStringReferences(std::set &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(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(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(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 &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(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(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 &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 &address_list) const { address_list.insert(address_ + ((size_ == osDWord) ? offsetof(objc2_message, name) : offsetof(objc2_message_64, name))); } /** * Objc2MessageList */ Objc2MessageList::Objc2MessageList() : ObjectList() { } 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(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 &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 &address_list) const { class_list_->GetLoadMethodReferences(address_list); category_list_->GetLoadMethodReferences(address_list); } void Objc2Storage::GetStringReferences(std::set &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 &address_list) const { address_list.clear(); if (storage_) storage_->GetLoadMethodReferences(address_list); } void Objc::GetStringReferences(std::set &address_list) const { address_list.clear(); if (storage_) storage_->GetStringReferences(address_list); } std::vector Objc::segment_list() const { if (storage_) return storage_->segment_list(); return std::vector(); }