在導航欄上實時顯示備忘錄的字數.數組
編輯界面是一個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了.
設置白名單, 使得除了白名單外的全部郵件都設置爲已讀. 這裏隨便寫一個.
而後刪除一封郵件看看效果:
能夠看到當郵件數量改變時, 收件箱中不在白名單中郵件已變成了已讀.