编写目的
记录下自己的使用过程,给各位踩坑的提供一些参考,文档仅供学习参考
Unidbg项目介绍
git项目介绍
核心思想:总的来说通过基于Unicorn虚拟机来加载应用程序(包括安卓、iOS、Mac)
来达到应用程序分析的目的,项目的源码仓库里有一些应用,可以好好看看
本地环境、设备介绍
- macos 10.15.6
- xcode
- iphone7 越狱设备
clone代码
git clone https://github.com/zhkl0228/unidbg
由于版本更迭较快,可能部分文档落后于实际code
安装idea
好的生产工具可以帮助我们节约很多时间,下载安装idea
准备ipa
利用越狱设备+frida 脱壳自己要分析的ipa,项目代码demo中有个dy的例子,需要准备ipa文件
尝试iOS Demo
运行DyIpaTest,下面是日志输出
[main]
屏蔽敏感类名
@interface TaTaNetworkManager : NSObject {
_Bool _pureChannelForJSONResponseSerializer;
_Bool _isEncryptQuery;
_Bool _isEncryptQueryInHeader;
_Bool _isKeepPlainQuery;
_Bool _dontCallbackInMainThread;
Class _defaultJSONResponseSerializerClass;
Class _defaultResponseModelResponseSerializerClass;
Class _defaultBinaryResponseSerializerClass;
Class _defaultRequestSerializerClass;
Class _defaultResponseRreprocessorClass;
NSDictionary * _commonParams;
id _commonParamsblock;
id _urlTransformBlock;
id _urlHashBlock;
NSString * _ServerConfigHostFirst;
NSString * _ServerConfigHostSecond;
NSString * _ServerConfigHostThird;
NSString * _DomainBase;
NSString * _DomainLog;
NSString * _DomainMon;
NSString * _DomainSec;
NSString * _DomainChannel;
NSString * _DomainISub;
NSString * _getDomainDefaultJSON;
NSString * _TokenHost;
NSString * _StoreIdc;
NSString * _UserId;
NSString * _hostResolverRulesForTesting;
id _requestFilterBlock;
id _responseFilterBlock;
id _addSecurityFactorBlock;
}
@property (retain, nonatomic) Class defaultJSONResponseSerializerClass;
@property (retain, nonatomic) Class defaultResponseModelResponseSerializerClass;
@property (retain, nonatomic) Class defaultBinaryResponseSerializerClass;
@property (retain, nonatomic) Class defaultRequestSerializerClass;
@property (retain, nonatomic) Class defaultResponseRreprocessorClass;
@property (copy, nonatomic) NSDictionary * commonParams;
@property (copy, nonatomic) id commonParamsblock;
@property (copy, nonatomic) id urlTransformBlock;
@property (nonatomic) _Bool pureChannelForJSONResponseSerializer;
@property (nonatomic) _Bool isEncryptQuery;
@property (nonatomic) _Bool isEncryptQueryInHeader;
@property (nonatomic) _Bool isKeepPlainQuery;
@property (copy, nonatomic) id urlHashBlock;
@property (copy, nonatomic) NSString * ServerConfigHostFirst;
@property (copy, nonatomic) NSString * ServerConfigHostSecond;
@property (copy, nonatomic) NSString * ServerConfigHostThird;
@property (copy, nonatomic) NSString * DomainBase;
@property (copy, nonatomic) NSString * DomainLog;
@property (copy, nonatomic) NSString * DomainMon;
@property (copy, nonatomic) NSString * DomainSec;
@property (copy, nonatomic) NSString * DomainChannel;
@property (copy, nonatomic) NSString * DomainISub;
@property (copy, nonatomic) NSString * getDomainDefaultJSON;
@property (copy, nonatomic) NSString * TokenHost;
@property (copy, nonatomic) NSString * StoreIdc;
@property (copy, nonatomic) NSString * UserId;
@property (copy, nonatomic) NSString * hostResolverRulesForTesting;
@property (copy, nonatomic) id requestFilterBlock;
@property (copy, nonatomic) id responseFilterBlock;
@property (nonatomic) _Bool dontCallbackInMainThread;
@property (copy, nonatomic) id addSecurityFactorBlock;
+ (void)setMonitorBlock:(id)arg0;
+ (void)setLibraryImpl:(long)arg0;
+ (void)setGetDomainBlock:(id)arg0;
+ (void)setHttpDnsEnabled:(_Bool)arg0;
+ (void)setCityName:(id)arg0;
+ (long)getLibraryImpl;
+ (void)setFrontierUrlsCallbackBlock:(id)arg0;
+ (id)GetFrontierUrlsCallbackBlock;
+ (id)GetCityName;
+ (id)MonitorBlock;
+ (id)GetDomainBlock;
+ (_Bool)httpDnsEnabled;
+ (id)shareInstance;
- (void)setUserId:(id)arg0;
- (void)setDefaultJSONResponseSerializerClass:(Class)arg0;
- (void)setDefaultBinaryResponseSerializerClass:(Class)arg0;
- (void)setCommonParamsblock:(id)arg0;
- (void)setDefaultResponseRreprocessorClass:(Class)arg0;
- (void)setDefaultRequestSerializerClass:(Class)arg0;
- (void)setStoreIdc:(id)arg0;
- (void)setServerConfigHostFirst:(id)arg0;
- (void)setServerConfigHostSecond:(id)arg0;
- (void)setServerConfigHostThird:(id)arg0;
- (void)setDomainBase:(id)arg0;
- (void)setDomainLog:(id)arg0;
- (void)setDomainMon:(id)arg0;
- (void)setDomainSec:(id)arg0;
- (void)setDomainChannel:(id)arg0;
- (void)setDomainISub:(id)arg0;
- (void)setTokenHost:(id)arg0;
- (void)creatAppInfo;
- (void)setRequestFilterBlock:(id)arg0;
- (void)setResponseFilterBlock:(id)arg0;
- (void)setAddSecurityFactorBlock:(id)arg0;
- (void)setUrlTransformBlock:(id)arg0;
- (id)urlTransformBlock;
- (id)transferedURL:(id)arg0;
- (id)urlHashBlock;
- (_Bool)isEncryptQuery;
- (_Bool)isEncryptQueryInHeader;
- (_Bool)isKeepPlainQuery;
- (id)addSecurityFactorBlock;
- (id)requestFilterBlock;
- (id)responseFilterBlock;
- (void)setDefaultResponseModelResponseSerializerClass:(Class)arg0;
- (void)setCommonParams:(id)arg0;
- (void)setIsEncryptQuery:(_Bool)arg0;
- (void)setIsEncryptQueryInHeader:(_Bool)arg0;
- (void)setIsKeepPlainQuery:(_Bool)arg0;
- (void)setUrlHashBlock:(id)arg0;
- (void)setGetDomainDefaultJSON:(id)arg0;
- (void)setDontCallbackInMainThread:(_Bool)arg0;
- (id)commonParamsblock;
- (Class)defaultRequestSerializerClass;
- (Class)defaultResponseModelResponseSerializerClass;
- (Class)defaultResponseRreprocessorClass;
- (Class)defaultJSONResponseSerializerClass;
- (_Bool)pureChannelForJSONResponseSerializer;
- (void)setPureChannelForJSONResponseSerializer:(_Bool)arg0;
- (Class)defaultBinaryResponseSerializerClass;
- (_Bool)dontCallbackInMainThread;
- (id)getDomainDefaultJSON;
- (id)hostResolverRulesForTesting;
- (void)setHostResolverRulesForTesting:(id)arg0;
- (id)ServerConfigHostFirst;
- (id)ServerConfigHostSecond;
- (id)ServerConfigHostThird;
- (id)DomainBase;
- (id)DomainLog;
- (id)DomainISub;
- (id)DomainChannel;
- (id)DomainMon;
- (id)DomainSec;
- (id)TokenHost;
- (id)StoreIdc;
- (id)UserId;
- (void).cxx_destruct;
- (id)commonParams;
@end
运行过程
根据代码大致猜测ipa加载过程,这一部分比较考验阅读代码能力, 只能硬着头皮进去看实现,搜索相关的概念
- 初始化ipaloader 64位加载器,传入ipa 路径和应用启动后的沙盒目录
- 添加ipaloader的backend,这里的backend 应该是和unicorn相关的
- 调用 load,解压 ipa 加载应用程序,从可执行文件的elf header 遍历load command,递归加载依赖
- init
- call entry, 调用可执行文件的entry
Backend
这里先给一个backend的仓库地址dynarmic
可以从文章中大致猜测出来,backend起到的作用是将arm指令翻译成宿主机的指令,比如你的电脑是英特尔cpu,而你运行的程序是arm 程序, 这中间有个指令转换的过程才能正常运行。
SYSCall系统调用
这个也是虚拟机的核心,这里大家先了解svc 指令,以及svc handler,还有ios的系统调用号
当svc 0x80 指令执行时,触发操作系统系统调用,有个调用编号,在linux头文件中往往_NR开头,这里nr是指number的意思,部分app会调用svc 0x80 来直接调用系统调用,比如自己汇编实现ptrace,绕过libc等上层函数。
在unidbg 中检测到svc 指令时,会去读取x16寄存器的值,匹配遍历syscall调用号(NR),调用相关的处理函数
有空了就写点 ,关个注,评个论。