iOS逆向工程实战篇

1. 备忘录增加字数统计功能

实现的功能:

在导航栏上实时显示备忘录的字数.

功能分析:
  • 编辑界面是一个View, 可以通过nextResponder找到它的Controller, 再通过Controller访问备忘录数据, 可以在初始化编辑界面的时候初始化标题字数.

  • 我们要做到标题字数随着内容的编辑而改变. 所以我们要实时注意protocol中的方法有没有这类方法.

  • 最后通过Controller的title属性设置标题.

功能实现:
  1. 首先定位备忘录的可执行文件

关闭无用App, 打开备忘录, ssh到iOS, 利用ps命令看看当前的进程. 因为是系统App, 所以在/Applications/路径下查询, 以便我们查找.

ps -e | grep /Applications/
复制代码

可以看到MobileNotes这个App貌似是我们的备忘录. 我们验证一下, 通过killall掉它, 看看打开的备忘录会不会关闭. 通过验证MobileNotes果然关闭了.

我们把MobileNotes的可执行文件/Applications/MobileNotes.app/MobileNotes 拷贝到电脑中.

  1. 导出MobileNotes的头文件

因为MobileNotes不是从App Store下载的App, 没有加壳, 所以可以直接使用 class-dump

  1. 这次我们用可视化工具FLEXLoader找到我们备忘录界面的Controller;

然后我们通过cycript验证ICTextViewController是不是我们的目标Controller. 这里我们可以通过设置Controller的Title属性来观察变化.

执行后并没有发现界面的标题有任何变化.

我们通过FLEXLoader的views功能查看UI层级, 选择当前控件的上一层控件的小图标点进去.

可以看到当前选中控件的Controller是ICNoteEditorViewController, 我想我们应该试试它. 同样执行上面设置title代码, 观察标题.

可以看到当前的标题发生了改变. 所以当前的Controller是 ICNoteEditorViewController.

既然找到了我们要hook的类, 那么我们就可以打开ICNoteEditorViewController这个.h文件.

观察.h文件, 寻找我们的目标信息.

发现了我们的目标控件 textView. 然后通过textView即可以获取当前输入内容的长度. 然后设置到title上.

我们在继续看发现了textView的代理方法.

这个方法我们很熟悉, 就是当textView的内容改变的时候会走到这里, 然后我们在这个方法内根据textView的长度去设置title即可. 这里验证当输入内容的时候走不走这个方法可以通过很多方式验证, 这里我是通过简单的hook方法并打印, 然后通过xcode查看打印的值确认的. 还有通过lldb和IDA打断点到目标方法上, 然后触发断点也是可以判断的.不过后一种方法稍微要求高一些.这里我们没有用.

以上是我分析后的结果.

编写Tweak:

这个例子很简单, 所有操作都在一个类中完成.

上面的111是我手速快输入错了, 所以重新输入即可.

tweak的代码

这个.h文件的目的仅仅是为了让tweak通过编译不报错. 存放在工程里即可.

这个是Makefile 的内容:

图中和创建工程的名字不一样是因为时间原因, 我没有把之前的图换掉, 直接用的老图. 不过不影响流程.

安装使用:

接下来我们安装这个tweak

然后打开备忘录

可以看到我们的tweak生效了. title随着我们的内容增减而变化.

由于时间问题分析过程可能少了很多, 个人感觉做逆向开发, 最重要的就是分析过程, 所以后面有时间会补上分析过程.

如果不想用这个tweak, 可以到这里把它干掉!


2. 将目标电子邮件标记为已读

实现的功能:

在Mail界面上增加编辑白名单的按钮.

每次当Mail的收件箱收到新邮件时, 就会自动把白名单外的邮件标记为已读.

功能分析:
功能实现:

首先定位到Mail的可执行文件并class-dump它.

还是老样子通过ps命令很简单的就定位到了Mail的可执行文件

然后导出它的头文件:

接下来就是寻找到我们安放编辑按钮的位置:

我们把这个编辑白名单的按钮加到上图的位置.

这次我们通过Reveal查找上图的Controller.

首先定位到最好找到的TableView, 然后查看右侧 MailboxPickerController即是我们要找的Controller, 为了保险起见, 我们通过cycript测试一下.

首先注入到 MobileMail 进程. 然后通过Reveal上提供的Controller地址设置rightBarButtonItems. 设置成功后出现如我们上图的那样:

接下来我们用相同的方法寻找收件箱列表的Controller.

MailboxContentViewController

然后用同样的方法测试下MailboxContentViewController 是不是我们的目标Controller.

然后我们去MailboxContentViewController这个头文件查找我们需要的信息.

和之前一样, 首先查看协议中有没有蛛丝马迹. 很快我发现了MessageMiniMallObserver 这个协议有我们需要的东西.

从方法名字上看LoadMessages FinishedFetch MessageCountDidChanged 方法可能会在刷新完成前后调用.

为什么选择这三个方法呢?

因为我们做开发的时候一般获取的页面数据, 在刷新中是可以获取到的. 所以我们重点测试下这个三个方法, 有没有我们想要的东西.

然后我们利用LLDB在这个三个方法上打断点.

通过IDA查看三个方法的基地址, 然后加上ASLR, 过程之前做过, 这里就不一一写出来了.

打完断点之后, 我们下拉刷新来触发断点:

可以看到触发的断点地址正是 FinishedFetch方法ASLR偏移后的地址, 而且每次都是只走这个方法.

然后我删除一封邮件马上就触发了断点, 正是方法MessageCountDidChanged:

通过测试发现 :

  • FinishedFetch方法每次刷新完成的时候都会走. 也就是在服务器成功取得邮件后得到调用.

  • MessageCountDidChanged方法每次有删除邮件或者有新邮件的时候才会触发.

  • 这里我们选择MessageCountDidChanged方法作为寻找所有邮件的方法.

设置断点到MessageCountDidChanged方法, 删除已有的一封邮件触发断点:

然后我们看看它的参数:

可以发现参数的类型的NSConcreteNotification 自定义的抽象通知类, 继承自Notification.

而name是MiniMallMessageCountDidChange, object是MessageMiniMall对象. userInfo是一些改动的信息.

然后我们寻找MessageMiniMall的头文件继续寻找我们需要的信息.

这里文件内容有些多, 就不全部截取了. 可以发现MessageMiniMall类继承自NSObject, 然后结合名字很容易就猜出来当前类是负责处理数据的M.

经过查找发现 - (id)copyAllMessages; 方法很有可能是获取全部邮件的方法.

这里我们测试下:

可以看到执行了copyAllMessages方法的返回值是一个集合类型并且集合中的元素是MFLibraryMessage类型的对象.

可以看到集合中有4个元素, 正是我们邮箱中的四封邮件. 因此copyAllMessages就是拿到所有邮件的方法.

同时我们在头文件中发现方法 - (void)markMessagesAsViewed:(id)arg1; 通过语义可知道应该是设置消息为已读的方法. 而参数也应该是含有MFLibraryMessage类型对象的数组.

到目前为止我们知道一封邮件就是一个MFLibraryMessage对象. 我们在头文件中没有找到这个类文件. 所以它应该来自一个外部的dylib.(Message.framework)

通过MFLibraryMessage.h头文件并没有发现发件人地址等信息. 不过发现了- (id)copyMessageInfo; 这个方法. 试一下看看他返回什么.

一个MFMessageInfo对象. 我们感觉去这个头文件中看看. 但是经过查找发现并没有我们想要的信息. 我们继续查看MFLibraryMessage.h发现它继承自MFMailMessage这个类, 我们赶紧打开看看这个类.

通过观察发现这个类中有我们邮件中常用的词汇.summary subject sender cc bcc 等. 不过有的属性确没见到getter. 我们继续查找它的父类MFMessage文件看看, MFMessage是MIME.framework的类.

可以看到这里有我们需要的信息, 然后我们通过LLDB查看一下具体的值.

可以确定这个类里面有我们需要的信息.

然后验证一下之前寻找的 markMessagesAsViewed 是不是我们要找的标记邮件为已读的方法.

通过IDA查找markMessagesAsViewed的地址.然后打断点.在把邮箱中的邮件设置为已读试试这个断点有没有触发.

可以看到确实触发了断点, 说明这个方法就是我们要找的.然后我们看看这个方法的参数:

没错就是MFLibraryMessage对象组成的NSSet.

下面就可以开始编写我们的Tweak了.

编写Tweak:

安装使用:

设置白名单, 使得除了白名单外的所有邮件都设置为已读. 这里随便写一个.

然后删除一封邮件看看效果:

可以看到当邮件数量改变时, 收件箱中不在白名单中邮件已变成了已读.

转载于:https://juejin.im/post/5b3495c5518825749864b7b9

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值