├── AAA git阅读效果不佳,还没整理,建议大家移步CSDN.md ├── LICENSE ├── iOS逆向(一):理论基础&工具篇.md ├── iOS逆向(三):强大的断点调试工具.md ├── iOS逆向(二):实践篇.md └── iOS逆向(四):还原符号表,再无障碍.md /AAA git阅读效果不佳,还没整理,建议大家移步CSDN.md: -------------------------------------------------------------------------------- 1 | github 阅读效果不佳,还没来得及整理。 2 | 为了更好地阅读体验,建议大家移步CSDN:https://blog.csdn.net/u012241552 3 | 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Allen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /iOS逆向(一):理论基础&工具篇.md: -------------------------------------------------------------------------------- 1 | ## 1、前言 2 | 提到iOS逆向,网上的文章铺天盖地,创作时间从2014年到2019年不等。绝大部分的工具或命令都过时了。书籍更不用说。 3 | 4 | 我刚刚结束了为期1月的零基础iOS逆向研究,现已经成功逆向了微信的一些复杂逻辑。现在分享一下我的一些学习路线和心得。 5 | 6 | * _郑重声明:本次逆向仅限于对iOS底层知识的学习,无任何恶意行为_ 7 | 8 | ## 2、工具篇 9 | #### 2.1 MonkeyDev 逆向集成环境 10 | _工欲善其事 必先利其器_ 11 | iOS后起之秀**AloneMonkey**在旧的逆向集成环境**iOSOpenDev**的基础上,进行了升级。变成了一款非越狱插件开发集成神器:**MonkeyDev**,它提供了我们一个像开发普通iOS应用一样简单的开发平台。 12 | [源码地址](https://github.com/AloneMonkey/MonkeyDev) 13 | [安装和使用方法请看这里](http://www.alonemonkey.com/2017/07/12/monkeydev-without-jailbreak/) 14 | 我们先看一眼项目的创建: 15 | ![跟创建其他iOS项目一样简单](https://img-blog.csdnimg.cn/20190912160625684.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTIyNDE1NTI=,size_16,color_FFFFFF,t_70) 16 | 再来看一眼**project**结构目录: 17 | ![拖入无壳的app即可](https://img-blog.csdnimg.cn/20190912160724779.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTIyNDE1NTI=,size_16,color_FFFFFF,t_70) 18 | 只需要拖入一个砸壳的应用即可。关于如何砸壳,这不是逆向的重点,所以本篇不教,有兴趣的同学可以自行查资料解决。可以先到**PP助手**的应用商店下载脱壳应用。 19 | 20 | **该平台集成了一下hook工具:** 21 | 22 | **CaptainHook:** 23 | 通过runtime hook OC函数. [CaptainHook基本原理](https://www.jianshu.com/p/8834b4ce8781) 24 | 25 | **fishhook:** 26 | FaceBook出品,通过修改**Mach-O**外部函数地址的方式,达到hook的功能 [fishhook原理 & Mach-O动态加载过程](https://www.jianshu.com/p/4d86de908721) 27 | 28 | **tweek:** 29 | 基于越狱设备,让App去加载对应的dylib,然后: 30 | 1.修改目标函数前N字节,跳转到自定义函数入口; 31 | 2.备份目标函数前N个字节,跳转回目标函数。 32 | [tweek基本原理](https://www.jianshu.com/p/00eb4eab36ef) 讲的比较浅,但是没找到详细的原理文章 33 | 34 | 35 | #### 2.2 iOS基础篇 36 | **A、初识 Mach-O** 37 | [什么是Mach-O 以及查看工具](https://www.jianshu.com/p/7040dd1396f7) 38 | 39 | **B、动态链接过程** 40 | 提到Mach-O就不得不提 _**动态链接**_ 41 | 因为看完这些资料,你可能会越来越懵逼,Mach-O是被谁加载的呢?Mach-O怎么跟我们的函数怎么关联上的呢?静态库和动态库的区别是什么呢? 42 | 别急 回头看看 [fishhook原理篇](https://www.jianshu.com/p/4d86de908721) ,这些问题基本就可以解答了, 43 | 如果你还是不满足,想要更深入的理解动态链接过程,请看阿里iOSer [刘坤的这篇博客](https://blog.cnbluebox.com/blog/2017/10/12/dyld2/) 44 | 45 | 如果你想对Mach-O有更深入、全面的了解,可以看看这些: 46 | [Mach-O分析:解析一个类](https://www.jianshu.com/p/ef8f7ed2e016) 该篇讲较基础,作为入门比也较合适 47 | [Mach-O 内存分布](https://wenghengcong.com/posts/f13a5377/) 48 | [Mach-O 文件格式探索](https://github.com/Desgard/iOS-Source-Probe/blob/master/C/mach-o/Mach-O%20%E6%96%87%E4%BB%B6%E6%A0%BC%E5%BC%8F%E6%8E%A2%E7%B4%A2.md) 49 | 50 | 51 | #### 2.3 必要辅助工具篇 52 | **1、class-dump** 分析mach-o 导出所有类的头文件(非开发中的头文件,它包括所有的属性、类方法、对象方法) 53 | [同样,这里是它的安装和使用说明](https://www.jianshu.com/p/ec62d78fe859) 54 | 导出来之后 长这样:(建议用sublime打开,如果你用xcode打开该文件夹,你就会知道我这条建议有多么感人了) 55 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190912175527209.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTIyNDE1NTI=,size_16,color_FFFFFF,t_70) 56 | 2、反汇编工具:**IDA** 或 **Hopper Disassembler** 57 | **Hopper**可以试用大约20分钟?分析比IDA较快(不过也需要近半小时),但试用版不能保存分析结果,下次打开又要等待半小时。网上的破解版都不好用。 58 | 所以我选择购买了**IDA 破解版:**[购买地址](https://www.macdown.com/mac/734.html) 59 | 当然,有钱的童鞋,还是建议支持买正版。也就¥900多。 60 | 汇编指令和二进制机器码是一一对应的,所以有了Mach-O二进制文件,反汇编回汇编代码 也是可行的。 61 | 至于为什么要使用反汇编工具,看看下面的图片就懂了。 62 | ![1、函数列表](https://img-blog.csdnimg.cn/20190912181013399.jpeg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTIyNDE1NTI=,size_16,color_FFFFFF,t_70) 63 | 1、函数列表。不过看起来还不如我们**class-dump**导出的头文件包,别急,一旦双击某个函数名,就可以看到该函数的汇编代码了。见下图: 64 | ![doSearch函数汇编位置](https://img-blog.csdnimg.cn/2019091218132846.jpeg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTIyNDE1NTI=,size_16,color_FFFFFF,t_70) 65 | 这是搜索好友的doSearch函数,如果你觉得汇编看不太懂,想要看点能看懂的,按**F5**,**IDA**会帮你转成伪代码,如下图: 66 | ![这是之前用hopper工具转化的伪代码,IDA的差不多,就不另行截图了](https://img-blog.csdnimg.cn/20190912181555770.jpeg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTIyNDE1NTI=,size_16,color_FFFFFF,t_70) 67 | 一个细节可以看出:函数地址在整个Mach-O中的偏移位置。 68 | 69 | 70 | 71 | **好了,前期的工具和理论基础,先准备这些就够了,迫不及待的小伙伴们 你们可以开始动手试验了,请移步:** [iOS逆向(二):实践篇](https://github.com/OPTJoker/iOS_Reverse/blob/master/iOS%E9%80%86%E5%90%91%EF%BC%88%E4%BA%8C%EF%BC%89%EF%BC%9A%E5%AE%9E%E8%B7%B5%E7%AF%87.md) 72 | -------------------------------------------------------------------------------- /iOS逆向(三):强大的断点调试工具.md: -------------------------------------------------------------------------------- 1 | ## 1、强大的lldb 2 | 上文我们说到了调试。在iOS逆向中,很多人推荐**debugserver** + **lldb** 其实调试只需要**lldb**就够了。 3 | **debugserver**配置的文章有很多,从14年到18年不等,但大部分都过时了。所以我也没用。那 只用**lldb**该怎么断点调试三方app呢?我们先来简单看下lldb的断点命令。 4 | 5 | #### 1.1 LLDB断点命令: 6 | **1.1.1 设置断点** 下断点命令我们只需要先会两个就够了: 7 | 8 | **a:** 给指定内存地址下断点: ```br set -a 0x00000000```全拼我记不住 9 | **b:** 给某方法下断点:`b -n "[ClassName methodName]"` 全拼同样记不住 10 | 关于**a**,怎么定位方法内存,一会再讲。 11 | 关于**b**,很多app打App Store包的时候,是去掉了符号表的编译配置项的。所以,我们暂时打不了三方app的方法断点。不过不用急,后面我们会教大家如何还原三方app的符号表。 12 | 13 | **1.1.2** 查看断点 14 | 15 | ```br list```这个全拼我能记住:breakpoint list 16 | 17 | **1.1.3** 删除断点 18 | `br del n` 这里的**n**是上一步`br list`列出的断点的序号。根据对应的序号删除想删的断点。当然你也可以直接`br del`,然后**lldb**会问你是否要删除全部断点。`[Y/n] ?` 输入Y即可。 19 | 20 | #### 1.2 如何定位函数地址 21 | 好 我们先来看看如何找到想断点的函数的地址。为了降低被黑客攻击的风险,操作系统大都采用**ASLR**(地址空间布局随机化) 技术: [详细解释请看这](https://www.jianshu.com/p/33c9883b647a) 这个人的内存管理讲的不错,一共7篇,建议大家有时间看看。 22 | 23 | **ASLR**是一种避免类似攻击的有效保护。进程每一次启动时,地址空间都会被简单地随机化:进行整体的地址偏移,而不是搅乱。通过内核将整个进程的内存空间“平移”某个随机数,进程的基本内存布局如程序文本、数据、库等相对位置仍然是一样的,但其具体的地址都不同了。 24 | 简单来说,**ASLR**会在进程启动时候随机一个**基地址**。 25 | 在**lldb**中的查看命令是`image list` 或`image list -o -f`。 26 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190915033936469.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTIyNDE1NTI=,size_16,color_FFFFFF,t_70) 27 | 如过命令后面不加参数,它打印的就是每个image(镜像)的虚拟内存地址。 28 | 如果加了-o参数,打印的就是image的偏移量(相对于谁,暂时还没研究)。 29 | 30 | 具体区别如下: 31 | `image list` 打印的基地址: 0x**1**02a94000 32 | `image list -o -f`的地址: 0x**0**02a94000 33 | 34 | 看出区别了么?第**9**位差了一个**1**。 35 | 这个**1**正好跟**IDA**工具中的0x **1** 0000 0000对上了。 36 | 原因我还没去探究,如果有知道的小伙伴,望告知。 37 | 38 | 这里我们提到的地址是虚拟地址,为什么不是物理地址? 39 | 原因是:操作系统将我们(程序猿)跟物理内存划分了一个安全界限,我们程序猿只需要用虚拟内存跟操作系统打交道即可,操作系统调用底层硬件api,跟物理内存打交道。如果程序猿直接跟物理内存交流,恐怕不是那么安全的。程序一旦出了bug,可能会导致系统瘫痪。 40 | 41 | **基地址**有了,在前面**ASLR**技术中我们提到内核将整个进程的内存“**平移**”,所以数据段、代码段等等内存的偏移量其实是固定的,他们相对于mach-o header部分的偏移量是个常亮,那既然如此,我们的**IDA**工具又派上用场了: 42 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190915024401205.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTIyNDE1NTI=,size_16,color_FFFFFF,t_70) 43 | 这里列出的偏移地址,就是函数相对于mach-o的起始地址的偏移量,所以: 44 | **虚拟地址 = 基地址 + 偏移地址**。 45 | 那么,我们就可以在**lldb**用`br set -a 0x102a94000`下断点了。 46 | 在这里在交给大家两个好用的命令: 47 | 读内存命令:`x 0x102a94000` 全拼是:`memory read 0x102a94000` 48 | 反汇编命令:`dis -s 0x102a94000` dis是dissamble的简写。 49 | 50 | 我们调试别人的app,是看不到源码的,只能看汇编。所以这里建议大家学一下汇编。我知道很多人听到汇编就头大,不过不要紧,找对了教材,汇编真的可以通俗易懂。比如这本:**《汇编语言第3版》王爽著**。学习时长**两三天**就够。不信你试试。 51 | 我是从网上下的影印版PDF,阅读效果不太好,大家可以买正版书或者正版PDF来学习。 52 | 53 | 学完了汇编,CPU工作原理你就基本了解了,再跟内存交流起来就方便多了。不过你可能还是看不懂**xcode**中出现的上古语言。因为两者的汇编指令集不一样,书里的CPU是古老的**8086**,是地址总线**20**位,数据总线**16**位的16位机器。而iPhone 5s之后都是**arm64** CPU,命令不太一样,总线位数也不一样,不过如果你理解了CPU的工作原理,**arm64**其实只是换了一种语法而已。而且CPU寻址操作也变得更简单。毕竟**arm64**数据总线跟地址总线位数相同(皆为64位),CPU不再需要地址加法器计算地址了。 54 | 55 | 这些都掌握了之后,我们可以看一下**runtime**源码,重点看一下**objc/message**部分。 56 | 目前苹果官方最新的是**objc4-762**版本,为了方便调试,我从**github**上下载了**objc4-750**版本,就差一个版本,不影响我们理解原理。 57 | [runtime 非官方Git地址](https://github.com/acBool/RuntimeSourceCode.git) 58 | 可以结合[这篇文章](https://www.jianshu.com/p/89713ed70653)进行理解。作者梳理的很好,从objc_msgSend的汇编代码入口开始,梳理到最终的**runtime**消息转发机制。 59 | 60 | 有了这些基础,下面我们再进行断点调试的时候,就会方便很多。 61 | 62 | 比如说,我们给没有隐藏符号表的app下断点: 63 | ![断点viewDidAppear:](https://img-blog.csdnimg.cn/2019091503312354.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTIyNDE1NTI=,size_16,color_FFFFFF,t_70) 64 | 65 | 未隐藏符号表的程序,断点的时候,函数名也会显示出来。 66 | 67 | 接下来我们将用到一个进阶命令:`register read` 查看寄存器信息: 68 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190915035205586.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTIyNDE1NTI=,size_16,color_FFFFFF,t_70) 69 | 前面如果你研究了runtime的objc_msgSend函数,你就会知道,该函数有两个默认参数`(receiver, cmd)`,第一个参数是消息接收者,第二个是函数地址。在**iOS arm64 CPU**中,通用寄存器中的`x0~x7`寄存器 用于参数传递。所已`x0`寄存器的值就是我们该函数的第一个参数:消息接收者,也就是DJHomeViewController类型的一个对象。结合po命令,我们就可以查看很多东西了。 70 | 第二个参数是函数地址,对应`x1`寄存器。 71 | objc_msgSend中第三个参数(`x2`寄存器),就是viewDidAppear:后面的传参了,我们看到这个值是0. 回头看看`class-dump`,可以看到这个参数要求传一个布尔值,那么 我们就可以猜出该函数被调用时候,入参是false。 72 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190915035829663.png) 73 | 74 | 有了对象和参数地址,你就拥有了一切。 75 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190915040155970.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTIyNDE1NTI=,size_16,color_FFFFFF,t_70 ) 76 | 77 | 比如,我们通过class-dump 看到该类有这么一个属性,那我们就可以直接访问! 78 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190915040558481.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTIyNDE1NTI=,size_16,color_FFFFFF,t_70) 79 | 我们可以用`p`命令 输出一下对象,该功能有点类似于`expression`命令。 80 | 此时会生成一个`$`符号开头的变量,这个变量可以在后续**lldb**中使用。 81 | 那么接下来我们就可以利用**kvc**进行访问任何内容了。也可以直接像写**OC**代码一样,在**lldb**中写方法调用。例如:`po [$10 class]`; 82 | **lldb**常用命令可以[看这里](https://www.jianshu.com/p/7fb43e0b956a)、[或这里](https://juejin.im/post/5b1cd870e51d4506dc0ac76c)。网上有很多这类文章,大家可以自行查找。 83 | 84 | 到这里,我们可以看到,假如调试的时候能看到函数名,那我们逆向就没有任何阻碍。所以,符号表是我们的必争之地! 85 | 如何还原符号表,请看下集:[iOS逆向(四):还原符号表,再无障碍](https://github.com/OPTJoker/iOS_Reverse/blob/master/iOS%E9%80%86%E5%90%91%EF%BC%88%E5%9B%9B%EF%BC%89%EF%BC%9A%E8%BF%98%E5%8E%9F%E7%AC%A6%E5%8F%B7%E8%A1%A8%EF%BC%8C%E5%86%8D%E6%97%A0%E9%9A%9C%E7%A2%8D.md)。 86 | -------------------------------------------------------------------------------- /iOS逆向(二):实践篇.md: -------------------------------------------------------------------------------- 1 | ## 1、先定一个小目标:修改查找好友功能 2 | 比如,我们想修改的功能是:在查找好友页面,输入特定字符串 (如: 0921),然后我们在请求发起之前,改成 "130 xxxx xxxx",再去进行真实的好友手机号请求。别问我为什么hook这个功能,问就是玄学(某些教育类公司就给招生老师装过有类似功能的wx)。 3 | 4 | #### 1.1 查找目标入口 5 | 通过XCode 自带的View Capture,我们可以查看UI层级:顺便根据类名,向要hook的目标类靠近。 6 | ![UI层级一目了然](https://img-blog.csdnimg.cn/20190913192228279.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTIyNDE1NTI=,size_16,color_FFFFFF,t_70) 7 | 8 | 首先看到的关键字,就是**WCSearchController**,貌似搜索逻辑是在这里进行的吧?移步**class-dump**导出的头文件,看看有没有相关功能的函数: 9 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190913192330840.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTIyNDE1NTI=,size_16,color_FFFFFF,t_70) 10 | 然而,看完函数名很失望。。显然wx的封装程度,和代码的优秀程度,不是那么简单的往VC里堆叠逻辑,他们有着复杂的设计。不要紧,我们还有两条线索: 11 | 1:**查看其他VC**:UI界面还有个VC叫**AddFriendEntryViewController** 12 | 2、**猜测** 函数名:搜索按钮被点击,应该有个**searchButtonClicked:** 类似的方法回调吧? 13 | 所以,两条路都试一下:先看AddFriendVC,再在头文件中全局搜searchButtonClicked关键字。 14 | 结果如下: 15 | ![AddFriendVC](https://img-blog.csdnimg.cn/20190912184912558.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTIyNDE1NTI=,size_16,color_FFFFFF,t_70) 16 | 在这个VC里,我们看到它引用了Class **FindContact...** 大致意思不就是:“**查找联系人**”嘛?先记住这个人。再去看关键字检索: 17 | ![关键字检索](https://img-blog.csdnimg.cn/20190912184929364.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTIyNDE1NTI=,size_16,color_FFFFFF,t_70) 18 | 哦吼~ 有点意思了,它实现了这个方法。 19 | 那我们就去好好看看 **FindContactSearchViewCellInfo**这个嫌疑类: 20 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190912190444284.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTIyNDE1NTI=,size_16,color_FFFFFF,t_70) 21 | 哇,在关键词search的帮助下,我们很快就找到了一些猎物。 22 | 23 | 像CPU命中了**cache**一样快乐,这个类里实现了搜索按钮点击回调、有搜索命令的实现、有get搜索框文案的实现。 24 | 25 | 猜的这么准,有什么根据么?有的,请看**杨潇玉**的博客:[如何在逆向工程中Hook得更准](http://yulingtianxia.com/blog/2017/03/06/How-to-hook-the-correct-method-in-reverse-engineering/) 26 | (**PS:** 该同学很厉害。上学期间,自学iOS,反汇编分析很多代码,runtime玩的相当6,其中苹果开源的代码故意隐藏掉一行很重要的函数调用,都被他发现了。后来拿到BAT所有offer,最终去了腾讯安全部门。然而他还是觉得自己当时(实习期间)向身边神一样的牛人们学到了很多东西。哦对了,他还是咱们逆向工具作者**AloneMonkey**的朋友,慢慢的你会发现,你读的很多优秀博客,他们之间都有着~~不可告人~~ 额不,是千丝万缕的联系) 27 | 28 | 言归正传,我们hook一下这个类试试: 29 | 哦对,我们上篇文章提到用CaptainHook,作者的demo里已经有使用方法和基本语法了。 30 | xxxDylib.h 就是声明hook类的地方 31 | xxxDylib.m 就是写你要hook方法的实现。 32 | 可以看出,我们的注入代码最终是以动态链接库的原理,注入到wx进程中,等dyld动态链接完成之后,生效的。 33 | 验证方法:`(lldb) image list `命令 可以查看镜像动态加载工程。 34 | 35 | 开始撸代码: 36 | ![头文件声明](https://img-blog.csdnimg.cn/20190912190730992.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTIyNDE1NTI=,size_16,color_FFFFFF,t_70) 37 | **doSearch**方法的复写:这里可以打断点调试,比如输出一下参数什么的 38 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190912191352831.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTIyNDE1NTI=,size_16,color_FFFFFF,t_70) 39 | Hook完以后运行,点击搜索按钮,真的走到了这里。证明了我们之前的所有猜测都是正确的,可以进行下一步尝试了——分析代码,修改代码。 40 | 41 | #### 1.2 分析并改造目标功能 42 | 上篇提到的IDA反汇编工具,在这里就派上了大用场。 43 | 查看**doSearch**伪代码: 44 | ![doSearch伪代码](https://img-blog.csdnimg.cn/20190913193939160.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTIyNDE1NTI=,size_16,color_FFFFFF,t_70) 45 | 在伪代码中,我们可以看到函数内部调用了:`[r19 getSearchBarText]`。感觉这就是我们要修改的地方啊! 46 | 47 | 那么我们就分析并重写这个函数吧。该函数大致做了这么几件事: 48 | 49 | - 创建**SearchRequest** 50 | - 创建**SKBuiltinString** 用于初始化上面的**Request**,初始化参数是从`[self getSearchBarText]`得到的。 51 | - 创建**ProtobufCGIWrap**(网络请求包) 52 | - 用之前的**request**初始化网络请求包 53 | - 创建**Service** 54 | - 用**Service**创建一个Event,传参是上面创建的**CGIWrap**和一个Flag(多次断点,看到这个值永远是69,猜测是用来区分event类型的枚举) 55 | - 最后一步,如果上面的**Event**创建成功,就添加监听。入参是一个**unsigned int**类型的ListItem和一个**id**类型的Value。 56 | 以上这些伪代码中方法名及参数类型,是在**class-dump**中找到的。 57 | 58 | OK分析完了,利用objc/message 和runtime的一些工具,我们开始重写doSearch。代码如下: 59 | ![重写doSearch](https://img-blog.csdnimg.cn/20190913200759713.jpeg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTIyNDE1NTI=,size_16,color_FFFFFF,t_70) 60 | Hook也Hook了,代码也重写了,那么接下来就到了见证奇迹的时刻——运行测试! 61 | 62 | 如果hook生效,那么输入框里输入"0921",就会搜所"wx_sunhonglei"(这里大家可以换成搜自己的微信,毕竟这个微信名是我自己乱写的,该用户不存在)。 63 | 64 | **Cmd+R**,wx起来后,进到添加好友页面, 65 | 1、先输入一个正常的微信号进行搜索测试,比如自己的微信号,**bingo**!逻辑走通了!证明我们重写的doSearch方法是没有问题的。 66 | 2、测试我们替换字符串的逻辑,输入0921,看看能不能搜索到自己的微信。 67 | 68 | **结果**。。。点击搜索以后,界面没有任何变化!甚至连代码中的showLoading貌似也没走!因为没看到loading的菊花。 69 | 70 | 百思不得其解!怎么办!!是我们doSearch方法写的有问题吗?!还是其他**逻辑**原因? 71 | 72 | **能不能看一下函数调用栈?** 73 | 74 | 恭喜你,问到了逆向的精髓之处。在此之前,我被卡了两星期。就是从这儿起,我开始沉下来学习了汇编原理和iOS的一些底层原理,最终越过山丘。 75 | 76 | 请继续收看下集: [**iOS逆向(三):强大的断点调试工具**](https://github.com/OPTJoker/iOS_Reverse/blob/master/iOS%E9%80%86%E5%90%91%EF%BC%88%E4%B8%89%EF%BC%89%EF%BC%9A%E5%BC%BA%E5%A4%A7%E7%9A%84%E6%96%AD%E7%82%B9%E8%B0%83%E8%AF%95%E5%B7%A5%E5%85%B7.md) 77 | 。 78 | -------------------------------------------------------------------------------- /iOS逆向(四):还原符号表,再无障碍.md: -------------------------------------------------------------------------------- 1 | 本文的部分理论支持,节选自[这里:iOS符号表恢复](http://blog.imjun.net/posts/restore-symbol-of-iOS-app/)。 2 | ## 前言 3 | 符号表历来是逆向工程中的“必争之地”,而iOS应用在上线前要裁去符号表,以避免被逆向分析。 4 | 5 | 这些可以通过配置xcode的编译选项来达到效果。具体操作请看这:[Xcode中和symbols有关的几个设置](https://www.jianshu.com/p/11710e7ab661)。 6 | 7 | Xcode显示调用堆栈中符号时,只会显示符号表中有的符号。为了我们调试过程的顺利,我们有必要把可执行文件中的符号表恢复回来。 8 | 9 | 先来看一眼无符号表和有符号表的可执行文件调试区别: 10 | ![无符号表](https://img-blog.csdnimg.cn/20190915131056870.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTIyNDE1NTI=,size_16,color_FFFFFF,t_70) 11 | ![有符号表](https://img-blog.csdnimg.cn/20190915131118132.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTIyNDE1NTI=,size_16,color_FFFFFF,t_70) 12 | 符号表有多好用,一目了然。 13 | 14 | ## 什么是符号表? 15 | 我们要恢复符号表,首先要知道符号表是什么,他是怎么存在于 Mach-O 文件中的?由于这块涉及到的知识较多,还原符号表的作者讲解的很好,所以希望大家认真研究一下[这篇文章](http://blog.imjun.net/posts/restore-symbol-of-iOS-app/)。对 就是开篇提到的链接。 16 | 17 | 这里是:[项目开源地址](https://github.com/tobefuturer/restore-symbol)。 18 | 工具的配置和使用说明,也在作者的博客中。 19 | 20 | 有了这些工具,再回过头来研究一下,为什么我们在[第二篇文章](https://blog.csdn.net/u012241552/article/details/100778740)中重写了**doSearch**方法,却没有生效的原因。 21 | 22 | 在**doSearch**打断点的时候,**showLoading**函数已经被执行了,但我们点击搜索没有反应,所以应该是后面调用了`stopLoading`函数。这个函数正好在`FindContactSearchViewCellInfo`类里实现了(在class-dump导出的头文件里看到的)。所以我们就大胆尝试一下,通过`br -n "[FindContactSearchViewCellInfo stopLoading]"`命令,断点该函数。 23 | 再次在输入框输入0921,bingo,断点执行了。 24 | 25 | 从函数堆栈调用顺序(图片出了点问题,就不贴图了,后面我会附上其他app的函数调用栈效果截图),我们可以看到`doSearch`之后,执行了另一个函数: 26 | `- (void)MessageReturn:(id)arg1 Event:(unsigned int)arg2`。 27 | 该函数也是`FindContactSearchViewCellInfo`类中的。 28 | 移步**IDA**工具,看该函数实现: 29 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/2019091513381093.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTIyNDE1NTI=,size_16,color_FFFFFF,t_70) 30 | 31 | 惊不惊喜,怪不得重写了网络请求的创建,依然搜不到想要的结果。而且我也曾试着重写过wx的`getSearchBarText`方法,仍然不起作用。 32 | 原来是消息回来之后,wx拿searchBar.text 跟 request的请求参数(userName就是)做了比对,最终丢掉了这次的请求包。最后又stopLoading了。 33 | 34 | 我怀疑这是wx来了一个新人,不知道该类有`getSearchBarText`方法,所以直接自己手动取值了。导致正常的微信用起来会有一个bug:点击搜索的瞬间,删除一位搜索框的内容。loading就停不下了。 35 | 36 | 哦对了,附上别人的符号表还原效果图: 37 | ![符号表还原效果](https://img-blog.csdnimg.cn/20190915134436814.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTIyNDE1NTI=,size_16,color_FFFFFF,t_70) 38 | 39 | 我们断点到`stopLoading`以后,也是这种效果。 40 | 41 | 至此,调试三方app就跟调试自己的app一样了。 42 | 43 | 这篇可能有点烂尾,实在是符号表还原的理论知识太多,而且作者讲的我无法超越,只能虚心引用了。 44 | 45 | **那么,加油吧!** 46 | 47 | --------------------------------------------------------------------------------