在导航栏上实时显示备忘录的字数.数组
编辑界面是一个View, 能够经过nextResponder找到它的Controller, 再经过Controller访问备忘录数据, 能够在初始化编辑界面的时候初始化标题字数.xcode
咱们要作到标题字数随着内容的编辑而改变. 因此咱们要实时注意protocol中的方法有没有这类方法.服务器
最后经过Controller的title属性设置标题.app
关闭无用App, 打开备忘录, ssh到iOS, 利用ps命令看看当前的进程. 由于是系统App, 因此在/Applications/路径下查询, 以便咱们查找.ssh
ps -e | grep /Applications/
复制代码
能够看到MobileNotes这个App貌似是咱们的备忘录. 咱们验证一下, 经过killall掉它, 看看打开的备忘录会不会关闭. 经过验证MobileNotes果真关闭了.工具
咱们把MobileNotes的可执行文件/Applications/MobileNotes.app/MobileNotes 拷贝到电脑中.测试
由于MobileNotes不是从App Store下载的App, 没有加壳, 因此能够直接使用 class-dumpspa
而后咱们经过cycript验证ICTextViewController是否是咱们的目标Controller. 这里咱们能够经过设置Controller的Title属性来观察变化.3d
执行后并无发现界面的标题有任何变化.代理
咱们经过FLEXLoader的views功能查看UI层级, 选择当前控件的上一层控件的小图标点进去.
能够看到当前选中控件的Controller是ICNoteEditorViewController, 我想咱们应该试试它. 一样执行上面设置title代码, 观察标题.
能够看到当前的标题发生了改变. 因此当前的Controller是 ICNoteEditorViewController.
既然找到了咱们要hook的类, 那么咱们就能够打开ICNoteEditorViewController这个.h文件.
观察.h文件, 寻找咱们的目标信息.
发现了咱们的目标控件 textView. 而后经过textView便可以获取当前输入内容的长度. 而后设置到title上.
咱们在继续看发现了textView的代理方法.
这个方法咱们很熟悉, 就是当textView的内容改变的时候会走到这里, 而后咱们在这个方法内根据textView的长度去设置title便可. 这里验证当输入内容的时候走不走这个方法能够经过不少方式验证, 这里我是经过简单的hook方法并打印, 而后经过xcode查看打印的值确认的. 还有经过lldb和IDA打断点到目标方法上, 而后触发断点也是能够判断的.不事后一种方法稍微要求高一些.这里咱们没有用.
以上是我分析后的结果.
这个例子很简单, 全部操做都在一个类中完成.
上面的111是我手速快输入错了, 因此从新输入便可.
tweak的代码
这个.h文件的目的仅仅是为了让tweak经过编译不报错. 存放在工程里便可.
这个是Makefile 的内容:
图中和建立工程的名字不同是由于时间缘由, 我没有把以前的图换掉, 直接用的老图. 不过不影响流程.
接下来咱们安装这个tweak
而后打开备忘录
能够看到咱们的tweak生效了. title随着咱们的内容增减而变化.
因为时间问题分析过程可能少了不少, 我的感受作逆向开发, 最重要的就是分析过程, 因此后面有时间会补上分析过程.
若是不想用这个tweak, 能够到这里把它干掉!
在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了.
设置白名单, 使得除了白名单外的全部邮件都设置为已读. 这里随便写一个.
而后删除一封邮件看看效果:
能够看到当邮件数量改变时, 收件箱中不在白名单中邮件已变成了已读.