基本原理
Contents of (__DATA,__objc_classrefs) section
和Contents of (__DATA,__objc_superrefs) section
中的类是已经被引用的类,Contents of (__DATA,__objc_classlist) section
中的类是整个应用未启动时已经定义好的类列表,那么从后者剔除前者而剩余的类就是应用未启动时没有使用的类;同时考虑到Objective-C的运行时特性,所以还需要人工确认下。
基本过程如下:
解压ipa包
本质是zip包,修改后缀解压就可以了
otool 符号格式化
在mac os shell中运行命令(otool 为Xcode工具包中的工具)
otool -arch armv7 -ov 应用解压后的目录/Payload/应用名/应用二进制文件 > otool.txt
上述命令中指定armv7
架构,其假设是ipa包一定会有armv7
的二进制文件
解析获取 __objc_classlist 类列表
打开 otool.txt
文件,搜索__objc_classlist
,找到一个class数据,其基本格式如下
025afc00 0x28b2a24 # 第二个,地址0x28b2a24,是class的唯一地址
isa 0x28b2a38
superclass 0x28b4194 # 父类的地址
cache 0x0 __objc_empty_cache
vtable 0x0
data 0x25b5e0c
flags 0x194 RO_HAS_CXX_STRUCTORS
instanceStart 4
instanceSize 20
ivarLayout 0x2123649
layout map 0x13
name 0x2123610 BCCallMultiVideoController #类名字
baseMethods 0x25b5a88
。。。
我们需要重点关注类地址
、superclass 父类地址
,name 类名
,按照这样的格式解析所有的__objc_classlist
从而获得所有定义好的类集合。
搜索__objc_classrefs
和__objc_superrefs
,其基本格式如下
02896b94 0x0 _OBJC_CLASS_$_UIView
02896b98 0x0 _OBJC_CLASS_$_UIScrollView
02896b9c 0x0 _OBJC_CLASS_$_UIColor
02896ba0 0x0 _OBJC_CLASS_$_NSNumber
02896ba4 0x0 _OBJC_CLASS_$_UIImage
02896ba8 0x0 _OBJC_CLASS_$_NSMutableArray
02896bac 0x28b2a24 # 第二个地址,0x28b2a24,是引用的类
这样我们就获得了应用未启动时所有已经引用的类(从里面剔除系统类)
然后,就是获取__objc_classrefs
、__objc_superrefs
和__objc_classlist
的差集,需要注意下因为继承而间接被引用的情况。例如__objc_classrefs
集合中有一个0x28b2a24
,而这个地址在__objc_classlist
中对应BCCallMultiVideoController
,所以BCCallMultiVideoController
被引用了,而BCCallMultiVideoController
的父类是0x28b4194
,那么类0x28b4194
也被引用了,这样追溯直到父类未空或者父类未系统类。