1. 背景介绍和概念简介
1.1 背景介绍
iOS逆向工程主要有两个作用:
- 攻破目标程序,拿到关键信息,可以归类于与安全相关的逆向工程。
- 借鉴他人的程序功能来开发自己的软件,可以归类于与开发相关的逆向工程。
1.2 概念简介
1.2.1 砸壳
为什么要砸壳
开发者提交给AppStore发布的App,都经过FairPlay作为版权保护而加密,这样可以保证机器上跑的应用是苹果审核过的,也可以管理软件授权,起到DRM的作用。经过AppStore加密的App无法使用Hopper等反编译静态分析,无法Class-Dump。
在逆向分析过程中需要对加密的二进制文件进行解密才可以进行静态分析,这一过程就是大家熟知的砸壳(脱壳)。
砸壳工具
砸壳工具有很多,比较常用的有Stefanesser的 Dumpdecrypted
,也有Monkey的 frida-ios-dump
砸壳原理
那么这些工具解密的原理是什么呢?iOS/macOS 系统中,可执行文件、动态库等,都使用 DYLD 加载执行。在 iOS 系统中使用 DYLD 载入 App 时,会先进行 DRM 检查,检查通过则从 App 的可执行文件中,选择适合当前设备架构的 Mach-O 镜像进行解密,然后载入内存执行,这个程序并没有解密的逻辑,当他被执行时,其实加载器已经完成了目标mach-o文件的装载工作,对应的解密工作也已经完成。解密工具本身并不做解密,这些工具所做的工作是,遍历loadcommand中所有LC_ENCRYPTION_INFO或LC_ENCRYPTION_INFO_64的信息,将对应解密后的数据从内存中dump出来,复写到mach-o文件中,生成新的镜像文件,从而达到解密的效果。
简单来说,就是在App运行的过程中,将内存中的已经解密的二进制文件拷贝出来,生成新的镜像文件。
2. 工具介绍
工具主要分为四大类。具体安装参见另一文章 iOS逆向工程之工具安装。
2.1 监测工具
比如监测网络活动、文件访问等,工具有 Charles
、 Reveal
等。
2.2 开发工具
进行代码分析,有 XCode
、Theos
。
2.2.1 MonkeyDev
如果是非越狱机器或者使用Xcode调试第三方应用的时候,需要很多集成步骤,注入dylib,集成Reveal、Cycript等等,这些步骤其实都是重复性的工作。
使用 MonkeyDev
工具,则可以一步到位,帮你自动完成以上打包和运行app等工作。
安装了MonkeyDev
后,可以在XCode下新建MonkeyDev
相关的项目,只需要在项目里放入已砸壳的ipa文件,则可以自动打包、运行,然后就可以使用XCode进行UI调试了。
2.2.2 Thoes
Theos
是一款跨平台的独立于 Xcode 的用于管理,开发,部署 iOS 应用的开发工具,其主要用于越狱 iOS 平台的扩展(tweaks) 开发。
最初由DHowett进行开发,但由于DHwoett去了微软,没有时间维护,所以之后由Adam Demasi(kirb)接手了他的工作,并且添加了很多全新的功能。
2.2.3 dpkg和ldid
ldid
是越狱开发中的签名工具,是越狱祖师爷Saurik开发的一款二进制授权管理软件,可以对越狱应用进行SHA1运算生成授权,让软件包可以在iPhone上执行。
dpkg
则是 Theos
用来将工程打包成 deb 文件的工具包。
2.3 反编译器(disassembler)
进阶工具,主要有 IDA
、Hopper
。
2.3.1 class-dump
顾名思义,class-dump
就是用来dump目标对象的class信息的工具。它利用Objective-C语言的runtime特性,将存储在Mach-O文件中的头文件信息提取出来,并生成对应的.h文件。class-dump
可以帮助我们理解应用程序的结构,并选择我们想要的目标位置。
使用class-dump
class-dump -H TargetAppPath -o DumpPath
TargetAppPath
是要dump的App所在路径, DumpPath
是输出头文件的路径
2.3.2 Hopper Disassembler
超级强大的反编译软件,不仅可以把机器码解析成汇编,还能解析出与Objc相似的伪代码。可以搜索方法,或者代码里包含的字符串,等等。
使用Hopper
流程如下:
ipa文件 -> 解压 -> Payload -> 应用程序 -> 显示包内容 -> 找到体积最大的同名文件 -> 拷贝出来 -> 使用Hopper -> File -> Read Executable To Disassemble
由此,便得到反编译后的所有文件列表。
2.4 调试器(debugger)
XCode的单步调试,UI调试等。
3. 案例讲解(干货 & 福利)
下面,为大家带来干货和福利,简单演示下,腾讯视频App和爱奇艺App的去广告。
3.1 腾讯视频App iOS版 去广告
3.1.1 新建项目
MonkeyApp介绍
如下图,选择 MonkeyApp
-MonkeyDev.png)
MonkeyDev
主要包含四个模块:
Logos Tweak
使用theos提供的logify.pl工具将.xm文件转成.mm文件进行编译,集成了CydiaSubstrate,可以使用MSHookMessageEx和MSHookFunction来Hook OC函数和指定地址。
CaptainHook Tweak
使用CaptainHook提供的头文件进行OC 函数的Hook以及属性的获取。
Command-line Tool
可以直接创建运行于越狱设备的命令行工具。
MonkeyApp
这是自动给第三方应用集成Reveal、Cycript和注入dylib的模块,支持调试dylib和第三方应用,支持Pod给第三放应用集成SDK,只需要准备一个砸壳后的ipa或者app文件即可。
MonkeyApp项目结构分析
新建的项目,结构如下
xx代表XCode里新建的项目名称
xxMonkeyAppDylib
这个目录是将被注入目标App的动态库,你自己要hook的代码可以在 xxDylib.m
文件里面写,自带一些Demo代码,支持OC runtime的HOOK,C函数的fishhook。
Logos
目录,Logos
是 Theos
的一个组件,在 xxDylib.xm
文件里面,也可以写要hook的代码。
AntiAntiDebug
这个里面是反反调试的代码。
fishhook
这个是自动集成的fishhook模块,fishhook是facebook提供的一个动态修改链接Mach-O符号表的开源工具。
Framewroks
目录已经自动集成了Reveal.framework和Cycript.framework。
3.1.2 获取已经砸壳的的ipa安装包
获取途径有两种:
一是自己砸壳,有一键砸壳工具可以使用,但要求手上有一部已经越狱的机器。
二是去第三方应用商店下载已经砸壳的ipa安装包。比如PP助手。
推荐后者,但是如果要逆向的App比较冷门,第三方商店没有提供下载,则没办法,需要自己去砸壳了。
3.1.3 分析App的UI
将获取到的ipa安装包,放到项目里的 TargetApp
目录下,然后运行。
进入到视频播放界面,如果正在展示广告,则可以使用XCode的界面调试工具,查看UI的层级结构,然后找到广告播放界面,从而确定要hook的类名。
腾讯视频的UI层级结构比较清晰,归功于良好的视图架构吧,但却也方便了我们的逆向工程。
如果遇到一些UI比较杂乱的情况,这时就需要结合 class-dump
工具,反编译出来伪代码,再进一步确定是否需要hook其它的类或方法。
3.1.4 分析逻辑
从上一步UI分析可以看到,KKAdsViewController
在最上层,于是我们可以尝试,直接去除这个类,是否就可以去除广告呢?
于是,我们就开始尝试 hook 这个类了,并让这个类返回空。
3.1.5 添加要hook的代码
一般步骤
在这里,先介绍一下使用 MonkeyDev
进行hook操作的步骤:
- 声明要hook的类,使用 CHDeclareClass()
- hook方法,使用 CHOptimizedMethod()
- 加载类,在 CHConstructor 里使用 CHLoadClass() 或者 CHLoadLateClass()
- 注册hook,在 CHConstructor 里使用 CHHook()
- (可选)调用旧的方法,使用 CHSuper()
开始hook
于是,我们就可以开始真正的hook了。只需要在 xxDylib.h
和 xxDylib.m
文件里,按照上述步骤添加代码即可。
代码比较简单,在 xxDylib.m
类里,添加如下代码:
//声明要hook的类
CHDeclareClass(KKAdsViewController);
//hook方法
CHOptimizedMethod(0, self, KKAdsViewController *, KKAdsViewController, init)
{
return nil;
}
CHConstructor{
//加载类
CHLoadLateClass(KKAdsViewController);
//注册hook
CHClassHook(0, KKAdsViewController, init);
}
运行后,大功告成,成功去除了广告。
3.2 爱奇艺App iOS版 去广告
这个App的逆向过程比较复杂,需要分析反编译的伪代码甚至汇编。
这里,只演示添加hook的代码,不演示分析过程。
在 xxDylib.xm
文件里,添加如下代码即可完成去除广告的hook。这也是与上一节不同的两种hook方式的另外一种,主要借助于 Theos
工具的 Logos
组件,会自动将.xm文件转成.mm文件进行编译。
%hook AdsProxy
+ (id)GetAdExtraInfoWithAdId_oc:(unsigned int)arg1{return nil;} // IMP=0x00000001020d3ba8
+ (id)GetExportLog_oc{return nil;} // IMP=0x00000001020d3c68
+ (id)GetSdkVersion_oc{return nil;}
+ (unsigned int)InitCupidEpisode_oc:(id)arg1{return 0;} // IMP=0x00000001020d389c
+ (void)OnAdEventWithAdId_oc:(unsigned int)arg1 event:(int)arg2{} // IMP=0x00000001020d3a28
+ (void)OnAdEventWithAdId_oc:(unsigned int)arg1 event:(int)arg2 properties:(id)arg3{} // IMP=0x00000001020d3a3c
+ (void)OnCreativeEventWithAdId_oc:(unsigned int)arg1 event:(int)arg2 index:(int)arg3 url:(id)arg4{} // IMP=0x00000001020d3b94
+ (void)OnVVEventWithVVId_oc:(unsigned int)arg1 event:(int)arg2{} // IMP=0x00000001020d3c04
+ (void)RegisterJsonDelegateWithVVId_oc:(unsigned int)arg1 slotType:(int)arg2 delegate:(id)arg3{} // IMP=0x00000001020d39d8
+ (void)RegisterObjectAppDelegateWithVVId_oc:(unsigned int)arg1 slotType:(int)arg2 delegate:(id)arg3{} // IMP=0x00000001020d3a00
+ (void)SetMemberStatus_oc:(id)arg1{} // IMP=0x00000001020d3940
+ (void)SetSdkStatus_oc:(id)arg1{} // IMP=0x00000001020d3c18
+ (void)ShutDownCupidEpisode_oc:(unsigned int)arg1{} // IMP=0x00000001020d3c40
+ (void)UpdateAdProgress:(unsigned int)arg1 progress:(unsigned int)arg2{} // IMP=0x00000001020d3b80
+ (void)onPlayCardShow:(unsigned int)arg1 event:(int)arg2{}
%end
%hook AdsClient
- (id)initWithUserId:(id)arg1 appVersion:(id)arg2 cupidUserId:(id)arg3 mobileKey:(id)arg4{
return nil;
}
%end
4. 总结
这篇文章,主要介绍了非越狱环境下的逆向工程,需要借助 MonkeyDev 这一强大的工具,并结合两个有实际意义的实例,进行实操,
hook代码的过程比较简单,难点是在hook之前的分析过程,需要结合 class-dump 和 hopper 这两个工具,进行代码的跟踪,分析逻辑,确定目标。
微信的逆向,也比较经典,比如修改步数、修改UI等,有需要、有兴趣的可以找我。