老文重發(fā)蔑匣。
使用工具: class-dump, Hopper Disassembler足删。
CMM試用版的限制是:只能清理最多500MB的垃圾眷昆。這里要做的是在試用版下也能突破這個限制芹枷。
首先用class-dump導(dǎo)出所有頭文件備參考允悦,用Hopper打開可執(zhí)行文件膝擂,應(yīng)該就是CMM:
當(dāng)超過500MB以后,每次點(diǎn)清理按鈕會彈出下面的窗口:
在Hopper中搜索窗口中字符串"I already have a license":
得到變量名cfstring_I_already_have_a_licens隙弛,然后繼續(xù)搜索該變量:
可以看到[CMPurchaseViewController loadView]中引用到了它架馋,從名字判斷這個controller應(yīng)該對應(yīng)了彈出來的窗口。應(yīng)該是點(diǎn)了按鈕后什么東西初始化了這個controller全闷,之前的探索方向可能有點(diǎn)問題叉寂,應(yīng)該去找button的處理函數(shù)。于是在Hopper搜索框里猜測buttonHandler总珠,buttonTapped办绝,buttonClick等等之類,最后發(fā)現(xiàn)有個叫ubiquitousButtonPurchaseClicked的函數(shù)很可疑:
在0x1006dec58的位置引用到了它姚淆,于是順藤摸瓜到這個地址:
是被這個函數(shù)給引用了:-[CMUbiquitousButtonView performActionOnDelegate]
打開它的頭文件孕蝉,發(fā)現(xiàn)里面有個mouseDown: 函數(shù),應(yīng)該就是按鈕處理函數(shù)腌逢,但是是不是清理按鈕現(xiàn)在還不知道降淮,總之先來看看mouseDown:的實現(xiàn)。 用Hopper找到它,查看偽代碼:
可以看到最后還是調(diào)用了performActionOnDelegate佳鳖,看來是在這個函數(shù)里決定怎么處理接下來的邏輯霍殴,那么就繼續(xù)看看performActionOnDelegate的實現(xiàn):
哈哈,在這個函數(shù)里很驚喜的看到了疑似開始清理過程的ubiquitousButtonStartCleanProcess:函數(shù)系吩,迫不及待的打開看看:
有兩個類有這個函數(shù)来庭,這里可以通過打斷點(diǎn)判斷得出是CMModuleViewController調(diào)用了〈┌ぃ看到實現(xiàn):
于是痛苦開始了月弛,關(guān)鍵部分做了代碼混淆, 函數(shù)名變成了:JwUMdSW7rENEEIgVEGUtnns7cx3JNc9UTOuabo1ThwTJyDSydBKrFyvIIyTL6IgTvp9KwMqg1pF1VqvBEF8tC8YjbebfGbCBzIiRHQiX1wgasjtB0yneXyLo8vUGJhOmWNxu6FDurz8vOBkOSCpGfyGpMC8S1eJS8VWY9JRKfv7dahJuH0MAth7SwKv48LilHi63doAFcf1WDN2c7aJErpPKXKh3n08CPwiOcQxI888pDSR6K4XcjiWsYV3zHreX
姑且稱為加密函數(shù)A科盛,是屬于CMMainWindowController的某個敏感函數(shù)帽衙,看看它的實現(xiàn)如下:
忍不住吐血,里面又調(diào)了一個加密函數(shù)B贞绵。不管了厉萝,繼續(xù)看B的實現(xiàn),由于太長了就不貼出來了榨崩,總之里面又調(diào)了一堆加密函數(shù)谴垫。這段時間比較痛苦,一度想放棄母蛛,嘗試著去理清程序執(zhí)行的順序翩剪,但又沒有g(shù)et到Hopper其實可以單步調(diào)試的技能,一度都是用下面的手段讓程序掛掉來得知程序的執(zhí)行流程:
MOV AX, 4C00H
INT 21H
注意到偽代碼里經(jīng)常出現(xiàn)一個類似下面的代碼片段:
猜測是block調(diào)用溯祸,于是寫了段代碼用Hopper反匯編一下驗證了果然是肢专。
對于加密函數(shù)B舞肆,通過修改匯編的判斷條件焦辅,讓程序避過了彈出警告框的邏輯,最后發(fā)現(xiàn)這個函數(shù)其實沒做什么實質(zhì)的清理工作椿胯,只不過是在各種判斷用戶有沒有權(quán)限進(jìn)行清理筷登。最實質(zhì)性的調(diào)用是這一句:
這其實是一句block調(diào)用,參數(shù)是1哩盲,block是外面?zhèn)鬟M(jìn)來的前方。接下來就在函數(shù)開始合適的地方加上它的匯編代碼,匯編代碼如下:
mov qword [ss:rbp + var_D8], r15
mov esi, 0x1
mov rdi, qword [ss:rbp + var_D8]
call qword [ds:rdi+0x10]
jmp 0x100207266
這里有個插曲廉油,直接加上如上的代碼會讓Hopper掛掉惠险。查了下原因是Hopper這個版本還不支持編輯的時候引用var_開頭的變量,嘗試換了種辦法抒线,D8==十進(jìn)制的216班巩,所以上面的匯編代碼等價于:
mov qword [ss:rbp - 216], r15
mov esi, 0x1
mov rdi, qword [ss:rbp - 216]
call qword [ds:rdi+0x10]
jmp 0x100207266
這里又要看到之前的ubiquitousButtonStartCleanProcess:函數(shù),然后結(jié)合加密函數(shù)A和B可以知道嘶炭,ubiquitousButtonStartCleanProcess里有個block抱慌,然后把block丟給加密函數(shù)A逊桦,加密函數(shù)A又把block丟給加密函數(shù)B,由B執(zhí)行到最后再調(diào)用了這個block抑进。這種執(zhí)行流程很像是這個block就叫onAuthorizeSuccess强经,兩個加密函數(shù)做了點(diǎn)能否執(zhí)行清理的判斷,如果成功的話執(zhí)行onAuthorizeSuccess block寺渗。 那么這里就應(yīng)該看到ubiquitousButtonStartCleanProcess: 里的block執(zhí)行體匿情,也就是sub_1000dd914函數(shù):
接下來一路順藤摸瓜,從-[CMModuleViewController startClean]:到-[CMGroupScanner startClean]:到sub_100090e3a到-[CMGroupScanner cleanWithSession]: 到 -[CMScanner cleanWithSession]到 -[CMScanner cleanThreadWithSession] 到 -[CMScanner recursivelyCleanNode:parentNode:session:]: 都比較順利户秤,最后在-[CMScanner recursivelyCleanNode:parentNode:session:]: 里發(fā)現(xiàn)有很多-[shouldScanner:pauseCleaningWithNextNodeToClean:]: 函數(shù)码秉,這個函數(shù)有好幾個類里都有,一一把它們直接返回false鸡号。
以為大功告成了转砖,跑一下程序,發(fā)現(xiàn)掛了鲸伴。幸好Hopper的debugger給出了exception的位置府蔗,發(fā)現(xiàn)是加密函數(shù)B中由于改變了程序執(zhí)行流程,導(dǎo)致最后某個不需要release的變量被release了汞窗,于是把這局操作置空就行姓赤。
以為接下來肯定大功告成了,結(jié)果發(fā)現(xiàn)清理系統(tǒng)垃圾的時候需要管理員權(quán)限仲吏,而被patch過的程序始終無法成功不铆。這里牽涉到了SMJobBless和privileged helper tool等mac上的獲取系統(tǒng)權(quán)限接口,搞了兩天沒搞定裹唆。 最后只能簡單粗暴的讓-[CMAgentController install] 返回false來跳過所有需要系統(tǒng)權(quán)限的垃圾的清理誓斥。
有大神知道怎么搞定SMJobBless的歡迎補(bǔ)充。