diff options
Diffstat (limited to 'core/objc.cc')
-rw-r--r-- | core/objc.cc | 1435 |
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 §ion_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 |