移動App入侵與逆向破解技術(shù)

轉(zhuǎn)自 https://segmentfault.com/a/1190000005908458
以下為個人備忘學(xué)習(xí)使用,感謝原作者的付出

如果您有耐心看完這篇文章未荒,您將懂得如何著手進(jìn)行app的分析荧降、追蹤接箫、注入等實用的破解技術(shù),另外朵诫,通過“入侵”辛友,將幫助您理解如何規(guī)避常見的安全漏洞,文章大綱:

  • 簡單介紹ios二進(jìn)制文件結(jié)構(gòu)與入侵的原理
  • 介紹入侵常用的工具和方法剪返,包括pc端和手機(jī)端
  • 講解黑客技術(shù)中的靜態(tài)分析和動態(tài)分析法
  • 通過一個簡單的實例废累,來介紹如何綜合運用砸殼、尋找注入點脱盲、lldb遠(yuǎn)程調(diào)試邑滨、追蹤、反匯編技術(shù)來進(jìn)行黑客實戰(zhàn)
  • 講解越獄破解補丁和不需越獄的破解補丁制作方法和差別

黑客的素養(yǎng)

  • 敏銳的嗅覺

有時候通過一個函數(shù)名钱反,一個類名驼修,就能大致的判斷出它的作用,這就是嗅覺诈铛;功力已臻化境時,甚至可以使用第六感判斷出一些注入點

  • 面對失敗的勇氣

破解有時候很耗時墨礁,和程序開發(fā)正好相反幢竹,它耗時不是耗在寫代碼上,而是耗在尋找注入點和逆向工程上恩静,有可能你花了3天時間去找程序的破綻焕毫,但是最終的破解代碼可能就2行,不到一分鐘就搞定了驶乾;但是你也需要做好面對失敗的準(zhǔn)備邑飒,如果路選錯了,有可能你這3天完全是在浪費腦細(xì)胞

  • 洪荒之力

洪荒之力-即入侵過程中需要借助的各種工具级乐,工欲善其事疙咸,必先利其器,工具都是前人智慧的結(jié)晶风科,能用工具解決的撒轮,絕不要手動去搞

iOS黑客關(guān)鍵字

iOS的入侵離不開越獄開發(fā),一切的破解贼穆、入侵都是建立在越獄的基礎(chǔ)上的题山,如果沒有拿到系統(tǒng)級權(quán)限,一切的想法都是空談了故痊,當(dāng)然顶瞳,市面上存在免越獄的破解補丁,但是它的開發(fā)過程,也是基于越獄環(huán)境的

tweak

在iOS的黑客界慨菱,要做破解或越獄開發(fā)焰络,就必須了解tweak,它是各種破解補丁的統(tǒng)稱抡柿,在google上舔琅,如果你想搜索一些越獄開發(fā)資料或者開源的破解補丁代碼,它是最好的關(guān)鍵字洲劣。

iOS的tweak大致分為兩種:

  • 第一種是在cydia上發(fā)布的备蚓,需要越獄才能安裝,大部分是deb格式的安裝包囱稽,iOS在越獄后郊尝,會默認(rèn)安裝一個名叫mobilesubstrate的動態(tài)庫,它的作用是提供一個系統(tǒng)級的入侵管道战惊,所有的tweak都可以依賴它來進(jìn)行開發(fā)流昏,目前主流的開發(fā)工具有theos和iOSOpenDev,前者是采用makefile的一個編譯框架吞获,后者提供了一套xcode項目模版况凉,可以直接使用xcode開發(fā)可調(diào)試,但是這個項目已經(jīng)停止更新了各拷,對高版本的xcode支持不好刁绒,大家酌情選擇(本文中的例子全部采用theos)
  • 第二種是直接打包成ipa安裝包,并使用自己的開發(fā)證書或者企業(yè)證書簽名烤黍,不需越獄也可以安裝知市,可直接放到自己的網(wǎng)站上,可實現(xiàn)在線安裝速蕊;對于沒有越獄的手機(jī)嫂丙,由于權(quán)限的限制,我們是沒有辦法寫系統(tǒng)級的tweak的规哲,例如springboard的補丁是沒法運行的跟啤,這種tweak大多是針對某個app,把目標(biāo)app進(jìn)行修改注入處理唉锌,再重新簽名和發(fā)布腥光,有點類似于windows軟件的xxx破解版、xxx免注冊版

沒有越獄的機(jī)器由于系統(tǒng)中沒有mobilesubstrate這個庫糊秆,我們有二個選擇武福,第一個是直接把這個庫打包進(jìn)ipa當(dāng)中,使用它的api實現(xiàn)注入痘番,第二個是直接修改匯編代碼捉片;第一個適用于較為復(fù)雜的破解行為平痰,而且越獄tweak代碼可以復(fù)用,第二種適用于破解一些if...else...之類的條件語句

Mobilesubstrate

下面的圖展示的就是oc屆著名的method swizzling技術(shù)伍纫,他就是iOS的注入原理宗雇,類似于windows的鉤子,所以我們注入也稱為hook

3538084386-577f14714152b_articlex.jpeg

Mobilesubstrate為了方便tweak開發(fā)莹规,提供了三個重要的模塊:

  • MobileHooker 就是用來做上面所說的這件事的赔蒲,它定義一系列的宏和函數(shù),底層調(diào)用objc-runtime和fishhook來替換系統(tǒng)或者目標(biāo)應(yīng)用的函數(shù)
  • MobileLoader 用來在目標(biāo)程序啟動時根據(jù)規(guī)則把指定目錄的第三方的動態(tài)庫加載進(jìn)去良漱,第三方的動態(tài)庫也就是我們寫的破解程序舞虱,他的原理下面會簡單講解一下
  • Safe mode 類似于windows的安全模式,比如我們寫的一些系統(tǒng)級的hook代碼發(fā)生crash時母市,mobilesubstrate會自動進(jìn)入安全模式矾兜,安全模式下,會禁用所有的第三方動態(tài)庫

app注入原理

上面講到了mobileloader患久,他是怎么做到把第三方的lib注入進(jìn)目標(biāo)程序的呢椅寺?這個我們要從二進(jìn)制文件的結(jié)構(gòu)說起,從下面的圖來看蒋失,Mach-O文件的數(shù)據(jù)主體可分為三大部分返帕,分別是頭部(Header)、加載命令(Load commands)篙挽、和最終的數(shù)據(jù)(Data)荆萤。mobileloader會在目標(biāo)程序啟動時,會根據(jù)指定的規(guī)則檢查指定目錄是否存在第三方庫嫉髓,如果有,則會通過修改二進(jìn)制的loadCommands邑闲,來把自己注入進(jìn)所有的app當(dāng)中算行,然后加載第三方庫。

Mach-O.jpeg

為了讓大家看的更清楚苫耸,下面我用machoview來打開一個真實的二進(jìn)制文件給大家看看州邢,可以看出,二進(jìn)制當(dāng)中所有引用到的動態(tài)庫都放在Load commands段當(dāng)中褪子,所以量淌,通過給這個段增加記錄,就可以注入我們自己寫的動態(tài)庫了

machoview.jpeg

那么問題來了嫌褪,在這里插入我們自己的動態(tài)庫有什么用呀枢?我們自己寫的代碼沒有執(zhí)行的入口,我們一樣沒發(fā)干壞事笼痛,嗯裙秋,恭喜你問到點子上了琅拌,我們還需要一個"main"函數(shù)來執(zhí)行我們自己的代碼,這個"main"函數(shù)在oc里面稱為構(gòu)造函數(shù)摘刑,只要在函數(shù)前聲明 "attribute((constructor)) static" 即可进宝,有了它我們就可以發(fā)揮想象力,進(jìn)行偷天換日干點壞事了:

#import <CaptainHook/CaptainHook.h>

CHDeclareClass(AnAppClass);
CHMethod(1, void, AnAppClass, say, id, arg1)
{
    NSString* tmp=@"Hello, iOS!";
    CHSuper(1, AnAppClass, say, tmp);
}
__attribute__((constructor)) static void entry()
{
    NSLog(@"Hello, Ice And Fire!");
    CHLoadLateClass(AnAppClass);
    CHClassHook(1, AnAppClass,say);
}

到這里為止枷恕,我們已經(jīng)知道了怎么在目標(biāo)程序注入自己的代碼党晋,那么我們怎么知道需要hook哪些方法?怎么找到關(guān)鍵點進(jìn)行實際的破解呢徐块?下面講一下常見的app入侵分析方法

iOS逆向分析方法

逆向分析最常用的有三種方法:

1.網(wǎng)絡(luò)分析
通過分析和篡改接口數(shù)據(jù)未玻,可以有效的破解通過接口數(shù)據(jù)來控制客戶端行為的app,常用的抓包工具有Tcpdump, WireShark, Charles等蛹锰,windows平臺有fidller
2. 靜態(tài)分析
通過砸殼深胳、反匯編、classdump頭文件等技術(shù)來分析app行為铜犬,通過這種方式可以有效的分析出app實用的一些第三方庫舞终,甚至分析出app的架構(gòu)等內(nèi)容,常用的工具有dumpdecrypted(砸殼)癣猾、hopper disassembler(反匯編)敛劝、class_dump(導(dǎo)頭文件)
3. 動態(tài)分析
有靜就有動,萬物都是相生相克的纷宇,動態(tài)分析指的是通過分析app的運行時數(shù)據(jù)夸盟,來定位注入點或者獲取關(guān)鍵數(shù)據(jù),常用的工具有cycript(運行時控制臺)像捶、 lldb+debugserver(遠(yuǎn)程斷點調(diào)試)上陕、logify(追蹤)

Demo:微信搶紅包插件


上面講了很多原理性的東西,相信大家已經(jīng)看的不耐煩了拓春,下面我們一起動點真格的释簿,我們從頭開始,一步一步的做一個微信的自動搶紅包插件硼莽,當(dāng)然庶溶,網(wǎng)上可能已經(jīng)有相關(guān)的開源代碼了,但是我這里要講的是懂鸵,這些代碼是怎么得出來的偏螺,我么重點講一講分析過程

工欲善其事,必先利其器

一臺越獄的手機(jī)匆光,并裝有以下軟件

  • cycript

  • dumpdecrypted

  • debug server

  • openssh
    一臺蘋果電腦套像,并裝有以下軟件

  • class_dump

  • Theos

  • Hopper Disassembler v3

  • xcode

  • insert_dylib

  • pp助手

尋找注入點
砸殼

首先我們要做的就是把微信的殼砸掉,砸殼其實是為了把它的頭文件classdump出來终息,因為從appstore下載的app二進(jìn)制都是經(jīng)過加密的凉夯,直接進(jìn)行classdump操作是啥也看不出來的

  • 用pp助手把dumpdecrypted.dylib文件copy到微信的documents目錄
  • ssh到手機(jī)的終端货葬,cd到documents目錄中,執(zhí)行下面的命令進(jìn)行砸殼操作
xxx$ cp /usr/lib/dumpdecrypted.dylib /path/to/app/document
xxx$ DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib /path/to/WeChat
  • 最后砸殼完成后會在documents目錄生成砸了殼后的二進(jìn)制文件劲够,用pp助手copy出來并class-dump他的頭文件備用
動態(tài)分析-cycript

要想實現(xiàn)自動搶紅包震桶,我們必須找到收到紅包消息的handler方法,怎么入手呢征绎?我們先從界面出發(fā)蹲姐,進(jìn)入微信的消息首發(fā)窗口:

2287321906-577f147458bdf_articlex.jpeg
  • ssh進(jìn)手機(jī)的終端,輸入ps命令人柿,查找到微信的進(jìn)程id
ps aux | grep WeChat
  • 祭起神器cycript柴墩,根據(jù)上一步找到的pid注入到微信的進(jìn)程
cycript -p pidxxx
  • 在cycript的終端輸入這一串方法,作用就是打印出當(dāng)前界面的view層級凫岖,(cycript還有很多妙用江咳,大家可以上官網(wǎng)看文檔,這里不詳細(xì)介紹)
UIApp.keyWindow.recursiveDescription().toString()

最終的輸出如下哥放,內(nèi)容太多歼指,大家肯定看不清楚,不過沒關(guān)系甥雕,這個不是重點踩身,這里只是展示一下打印的結(jié)果形式:

323259611-577f147504a11_articlex.jpeg

我們可以隨機(jī)的選取一個節(jié)點不要太靠樹葉,也不要太靠樹根社露,例如我選的是標(biāo)紅的部分挟阻,把這個節(jié)點的內(nèi)存地址copy出來,這個內(nèi)存地址峭弟,就代表了這個節(jié)點的view對象附鸽,ios開發(fā)的老油條們都知道,通過view的nextResponder方法瞒瘸,可以找出它所屬的視圖控制器ViewController坷备,所以我么在cycript的控制臺中持續(xù)輸入如下的命令:

1004108792-577f1475ae97a_articlex.jpeg

看到?jīng)]有,通過四個nextResponder方法調(diào)用挨务,我么找到了當(dāng)前聊天窗口的ViewController類名击你,他就是BaseMsgContentViewController玉组,現(xiàn)在我們縮小了目標(biāo)范圍谎柄,下面我們還需要繼續(xù)縮小范圍,要找到具體的消息處理函數(shù)才行鲸湃。

動態(tài)分析-Logify

要繼續(xù)縮小范圍诫咱,就得祭起神器Logify了连躏,它是theos的一個模塊,作用就是根據(jù)頭文件自動生成tweak劈猿,生成的tweak會在頭文件的所有方法中注入NSLog來打印方法的入?yún)⒑统鰠⒆炯浅_m合追蹤方法的調(diào)用和數(shù)據(jù)傳遞

現(xiàn)在我們根據(jù)此前砸殼后class_dump出來的頭文件,找到BaseMsgContentViewController在pc終端執(zhí)行如下命令:

logify.pl /path/to/BaseMsgContentViewController.h > /out/to/Tweak.xm

輸出的tweak文件大概是這個樣子的:

3344737984-577f147662d73_articlex.jpeg

這里帶百分號的關(guān)鍵字揪荣,例如 %hook筷黔、%log、%orig 都是mobilesubstrate的MobileHooker模塊提供的宏仗颈,其實也就是把method swizzling相關(guān)的方法封裝成了各種宏標(biāo)記佛舱,使用起來更簡單,大家想要更深入了解各種標(biāo)記挨决,可以google一下logos語言

theos創(chuàng)建tweak

上面我們用logify生成了一個tweak代碼请祖,我們要把它安裝到手機(jī)上,首先需要使用theos進(jìn)行編譯脖祈,安裝了theos之后肆捕,在pc終端輸入nic.pl:

501240093-577f14773bb5f_articlex.jpeg

首先選擇項目模版當(dāng)然是tweak啦,然后是項目名稱盖高、作者慎陵,后面兩個選項要注意:

  • 首先是bundle filter,這個需要填你需要注入的目標(biāo)app的bundle id或舞,MobileLoader模塊會根據(jù)它來尋找你的tweak的注入目標(biāo)
  • 最后是list id applications to terminate upon installation荆姆,這里指定當(dāng)tweak安裝成功之后,需要kill的進(jìn)程映凳,我們要hook微信胆筒,這里就填微信的二進(jìn)制文件名就可以了,為什么要kill诈豌? 因為我么的插件是需要在app啟動時加載進(jìn)去的仆救,如果不重啟app,插件是不會生效的
    最后一切都完成后矫渔,在當(dāng)前目錄會生成下列文件:
2015792129-577f1477d475f_articlex.jpeg

把上面logify生成的tweak文件覆蓋到當(dāng)前目錄彤蔽,并用文本編輯器打開makefile文件,在文件的開頭增加你的ios設(shè)備的ip地址和ssh端口:

1042354455-577f1478605b9_articlex.jpeg

最后在pc終端進(jìn)入項目目錄庙洼,輸入 make package install 命令:

3421212493-577f1478e27b1_articlex.jpeg

期間會讓你輸入設(shè)備的ssh密碼顿痪,越獄機(jī)器的默認(rèn)ssh密碼是alpine,make命令會生成deb安裝包油够,放在debs目錄蚁袭,我們?nèi)绻雽ν獍l(fā)布自己的插件,可以把生成的安裝包上傳到cydia即可

安裝成功后再次進(jìn)入微信的聊天界面石咬,并使用另外一個微信在群里發(fā)個普通消息揩悄,連接xcode打開越獄機(jī)器控制臺,查看輸出鬼悠,會發(fā)現(xiàn)有類似下面的輸出:

Jun 7 09:56:13 Administratorde-iPhone WeChat[85972] <Notice>: [1;36m[WxMsgPreview] [m[0;36mTweak.xm:308[m [0;30;46mDEBUG:[m -[<BaseMsgContentViewController: 0x15e0c9a00> addMessageNode:{m_uiMesLocalID=2, m_ui64MesSvrID=0, m_nsFromUsr=ccg*675~9, m_nsToUsr=1037957572@chatroom, m_uiStatus=1, type=1, msgSource="(null)"} layout:1 addMoreMsg:0]

看出來了吧删性,消息處理函數(shù)是BaseMsgContentViewController的addMessageNode:layout:addMoreMsg:方法亏娜,大家可以看出,方法的參數(shù)內(nèi)容也打印出來了


動態(tài)分析-lldb

到目前為止蹬挺,我么已經(jīng)把范圍縮小到了具體的函數(shù)维贺,看起來注入點已經(jīng)找到了,但是請大家思考一下巴帮,如果我們在這個函數(shù)中注入搶紅包邏輯幸缕,那我們的tweak會不會有什么致命的缺陷?

是的晰韵,因為BaseMsgContentViewController這個類是微信群聊天窗口對應(yīng)的controller发乔,我么必須進(jìn)入到群的聊天界面,這個類才會創(chuàng)建雪猪,如果不進(jìn)入聊天窗口栏尚,我們的插件就不生效了,而且只恨,即使進(jìn)入聊天窗口译仗,也只是能自動槍當(dāng)前群的紅包而已,其他群就無能為力了官觅,是不是有點low纵菌?

所以為了使我們的插件顯得上流一些,我么還要繼續(xù)追根溯源休涤,尋找消息的源頭咱圆,這里就用到了lldb遠(yuǎn)程調(diào)試,使用lldb打斷點的方式功氨,通過調(diào)用棧序苏,我們可以就可以看到當(dāng)消息來到時,方法的調(diào)用順序捷凄,找到最先執(zhí)行的消息處理函數(shù)忱详。

要在剛剛追蹤到的addMessageNode:layout:addMoreMsg:方法中打斷點,首先我們得知道它在運行時的內(nèi)存地址跺涤,那么內(nèi)存地址怎么來呢匈睁?有這么一個公式:

  • 內(nèi)存地址=進(jìn)程內(nèi)存基地址+函數(shù)在二進(jìn)制中的偏移量

首先偏移量我們可以通過反匯編工具h(yuǎn)ooper來查,在pc上用hooper打開微信的二進(jìn)制文件(<font color=red>注意桶错,打開時會讓你選擇armv7或者arm64航唆,這需要根據(jù)你越獄手機(jī)的cpu類型來選,一定要和你的手機(jī)一致</font>)牛曹,hooper的界面非常簡潔佛点,左側(cè)有個搜索框醇滥,可以輸入函數(shù)名黎比,直接找到函數(shù)在二進(jìn)制中的位置

2256770925-577f14797d37b_articlex.jpeg

通過左側(cè)的搜索框搜addMessageNode關(guān)鍵字超营,找到它的偏移量是0x00000001017d7c6c

513840536-577f147a37b15_articlex.jpeg

找到了偏移量,還需要進(jìn)程的基地址阅虫,這個地址需要連lldb演闭,所以下面講一下如何連接lldb進(jìn)行遠(yuǎn)程調(diào)試,先ssh進(jìn)越獄手機(jī)的終端颓帝,在終端輸入如下命令(注意米碰,你的手機(jī)必須連xcode調(diào)試過才會有這個命令):

debugserver *:19999 -a WeChat

然后在pc端新起一個終端窗口,輸入如下命令來連接手機(jī)端進(jìn)行調(diào)試:

lldb -> process connect connect://deviceIP:19999

如果連接成功购城,會進(jìn)入lldb的控制臺吕座,我們在lldb的控制臺輸入如下命令來獲取微信進(jìn)程的基地址:

image list -o -f

執(zhí)行這個命令會打印很多行數(shù)據(jù),像下面圖中這樣瘪板,我么要找到微信的二進(jìn)制文件所在的行吴趴,記錄它的內(nèi)存地址0X00000000000E800:

1869229470-577f147baca2e_articlex.jpeg

到這里我們兩個地址都找到了,再通過br命令打斷點:

br s -a '0X00000000000E800+0x00000001017d7c6c'

打好斷點后繼續(xù)向群里面發(fā)消息侮攀,我們會發(fā)現(xiàn)進(jìn)程被斷掉了锣枝,這時輸入bt指令,就可以看到當(dāng)前的調(diào)用棧兰英,就像下圖這樣

704486873-577f147ababf4_articlex.jpeg

分析堆棧的時候撇叁,重點找出模塊時WeChat的項,這些都是微信模塊的方法調(diào)用畦贸,有了堆棧陨闹,我們需要根據(jù)堆棧的內(nèi)存地址找出它的具體函數(shù)名,思路還是先根據(jù)上面講到的公式來計算出棧地址在二進(jìn)制中的偏移量正林,然后用hooper找到偏移量對應(yīng)的函數(shù)名

  • 函數(shù)在二進(jìn)制中的偏移量=內(nèi)存地址 - 進(jìn)程內(nèi)存基地址
    例如根據(jù)箭頭所指的內(nèi)存地址和剛剛得到的進(jìn)程基地址,計算偏移量:
0x0000000101ad02f4 – 0x00000000000e8000 = 1019E82F4

然后在hooper中搜索這個地址颤殴,得到結(jié)果如下:

680997898-577f147c2eaeb_articlex.jpeg

最終把所有的棧都進(jìn)行還原觅廓,得出調(diào)用棧是這個樣子的:

-[CMessageMgr MainThreadNotifyToExt:]:
–>    
-[BaseMsgContentLogicController OnAddMsg:MsgWrap:]:
——>
-[RoomContentLogicController DidAddMsg:]
———->
-[BaseMsgContentLogicController DidAddMsg:]
—————->
-[BaseMsgContentViewController addMessageNode:layout:addMoreMsg:]:

CMessageMgr這個類浮出水面了,是時候發(fā)揮黑客的嗅覺了涵但,根據(jù)方法名我們能判斷出MainThreadNotifyToExt:這個方法僅僅是用來發(fā)送通知的杈绸,如果hook這個方法,我們是拿不到消息內(nèi)容的

由于這里可能是一個異步調(diào)用矮瘟,用斷點的方式瞳脓,可能已經(jīng)打印不出來棧信息了,所以還得使用logify來繼續(xù)追蹤C(jī)MessageMgr這個類澈侠,講過的內(nèi)容我就不重復(fù)了劫侧,直接得到最終的消息處理函數(shù):

-(void)AsyncOnAddMsg:(id)message MsgWrap:(CMessageWrap* )msgWrap
實現(xiàn)“搶”的動作

上一節(jié)我們已經(jīng)找到了hook的關(guān)鍵點,那么該如何去實現(xiàn)搶的動作?同樣我們需要結(jié)合動態(tài)分析和靜態(tài)分析烧栋,首先得到紅包消息體的數(shù)據(jù)特征写妥,然后再分析處理消息的關(guān)鍵點

數(shù)據(jù)包分析

首先我們的代碼需要分辨哪些才是紅包消息,方法很簡單审姓,用logify追蹤BaseMsgContentViewController珍特,然后向微信群發(fā)一個紅包,觀察手機(jī)日志輸出魔吐,我們可以看出消息的數(shù)據(jù)結(jié)構(gòu)中有個type字段扎筒,值是49酬姆,這個type應(yīng)該就是標(biāo)記消息類型的诱篷,如果不確定,可以再發(fā)個圖片或者文本之類的消息琳省,這個值是不同的:

Administratorde-iPhone WeChat[47410] <Notice>: [1;36m[WxMsgPreview] [m[0;36mTweak.xm:308[m [0;30;46mDEBUG:[m -[<BaseMsgContentViewController: 0x15e0c9a00> addMessageNode:{m_uiMesLocalID=16, m_ui64MesSvrID=1452438635530425509, m_nsFromUsr=1037957572@chatroom, m_nsToUsr=ccg*675~9, m_uiStatus=4, type=49, msgSource="<msgsource>
        <silence>0</silence>
        <membercount>3</membercount>
    </msgsource>
    "}  layout:1 addMoreMsg:0]

現(xiàn)在我們能分辨消息類型了躲撰,重點來了针贬,怎么實現(xiàn)搶這個事呢,可能聰明人已經(jīng)猜到了,從ui入手,先找到微信本身的搶紅包函數(shù),我們自己來給它構(gòu)造參數(shù)并調(diào)用他不就行了个从?

2414439757-577f147ccb60a_articlex.jpeg

把紅包點開后沪曙,用cycript打印出當(dāng)前view的層次,就像下面這個豆瘫,一眼就可以看到重點,WCRedEnvelopesReceiveHomeView就是開紅包彈框的類名

1191527012-577f147d50d87_articlex.jpeg

知道類名后菊值,用cycript追蹤它,點擊開紅包腻窒,在日志中找到了下圖中的內(nèi)容昵宇,從名字來看,這是一個事件處理函數(shù)儿子,我們現(xiàn)在要做的瓦哎,就是把他還原成oc代碼,真正實現(xiàn)搶紅包功能

Administratorde-iPhone WeChat[91173] <Notice>: [1;36m[WxMsgPreview] [m[0;36mTweak.xm:8[m [0;30;46mDEBUG:[m -[<WCRedEnvelopesReceiveHomeView: 0x13cdda8c0> OnOpenRedEnvelopes]

靜態(tài)分析法

怎么把他還原成oc代碼柔逼,真正實現(xiàn)搶紅包功能呢蒋譬?還得借助一點點匯編技能,只是一點點而已愉适,因為現(xiàn)在的反匯編工具已經(jīng)很強(qiáng)大了犯助,我們不需要挨個去看寄存器了

在pc上用hooper打開微信的二進(jìn)制文件,搜索OnOpenRedEnvelopes维咸,查看匯編代碼剂买,注意在圖片中最后一行調(diào)用了一個WCRedEnvelopesReceiveHomeViewOpenRedEnvelopes函數(shù)

3199193349-577f147e902bd_articlex.jpeg

繼續(xù)搜索WCRedEnvelopesReceiveHomeViewOpenRedEnvelopes這個方法,找到它的匯編代碼

  • 首先他不知道從哪里獲取了一個payinfoitem
  • 然后又獲取了payinfo的m_c2cNativeUrl屬性
  • 然后調(diào)用substringfromindex吧navtiveurl的前綴截斷癌蓖,并調(diào)用bizutil的一個方法把url參數(shù)轉(zhuǎn)換成了一個字典
768810550-577f147f2339f_articlex.jpeg

最終反解出的代碼如下瞬哼,是不是很簡單?

NSString *nativeUrl = [[msgWrap m_oWCPayInfoItem] m_c2cNativeUrl];
nativeUrl = [nativeUrl substringFromIndex:[@"wxpay://c2cbizmessagehandler/hongbao/receivehongbao?" length]];
NSDictionary *nativeUrlDict = [%c(WCBizUtil) dictionaryWithDecodedComponets:nativeUrl separator:@"&"];

繼續(xù)往下看, 在這里前面三行創(chuàng)建了一個mutable dictionary:

  • 緊接著下面三個框框處都是調(diào)用了setobject:forkey:向里面填東西租副,那填的東西是啥呢坐慰?
  • 其實這里已經(jīng)可以看的很清楚了,第一個key是msgtype用僧,值是字符串1讨越,第二個sendid,值是調(diào)用了一個objectforkey從另一個字典中取出來的永毅,很顯然把跨,另一個字典就是上面從url解析得到的,后面的channelid也是同樣的道理
2265620983-577f147fb12fb_articlex.jpeg

最終得到的代碼如下:

NSMutableDictionary *args = [[%c(NSMutableDictionary) alloc] init];
[args setObject:nativeUrlDict[@"msgtype"] forKey:@"msgType"];
[args setObject:nativeUrlDict[@"sendid"] forKey:@"sendId"];
[args setObject:nativeUrlDict[@"channelid"] forKey:@"channelId"];

繼續(xù)往下看從箭頭所指的幾處沼死,我們可以看見着逐,它的代碼是這樣的,共分為四步

  • 第一個箭頭調(diào)用了mmservicecenter的defaultcenter方法來獲取mmservicecenter實例
  • 第二個箭頭調(diào)用了CContactMgr的class方法
  • 第三個箭頭調(diào)用了第一步獲取的mmservicecenter實例的getservice方法,而這個方法是把第二步得到的class作為參數(shù)
  • 第四個箭頭很明白了吧耸别,第三步得到了CContactMgr實例健芭,這里就是調(diào)用CContactMgr實例的getselfcontact方法獲取自己的賬戶資料
1502474773-57c694e8a6fcb_articlex.jpeg

最終還原的到的代碼如下:

CContactMgr *contactManager = [[%c(MMServiceCenter) defaultCenter] getService:[%c(CContactMgr) class]];
CContact *selfContact = [contactManager getSelfContact];

繼續(xù)往下看,這里使用剛剛得到的selfcontact來獲取displayname和headimgurl秀姐,并把它們設(shè)置到剛剛的字典里面了慈迈,key分別是nickname和headimg

2259659429-577f20d6b2d9c_articlex.jpeg

最終的代碼:

[args setObject:[selfContact getContactDisplayName] forKey:@"nickName"];
[args setObject:[selfContact m_nsHeadImgUrl] forKey:@"headImg"];

接著看,接下來這兩段就比較蛋疼了省有,完全是從內(nèi)存地址里面取的值,我也不知道他從哪里來蠢沿,怎么辦呢?有沒有不懂匯編就能搞定它的捷徑呢恤磷,答案是有野宜!

  • 對于第一個,我可以通過它的key猜出來匈子,還記得最開始的時候我們?nèi)∵^payinfo的一個nativeurl屬性吧,我們姑且把他傳進(jìn)去
  • 對于第二個仿粹,我們可以猜測sessionUserName大概是會話名稱,也就是群名稱的意思原茅,從哪里取這個值呢吭历?我們先把也設(shè)置成偽代碼
3327967636-577f20d72e4e2_articlex.jpeg

最終的結(jié)果如下:

[args setObject:nativeUrl forKey:@"nativeUrl"];
[args setObject:xxx forKey:@"sessionUserName"];

繼續(xù)往下看,接下來這一段還是用mmservicecenter來獲取WCRedLogicMgr對象擂橘,然后調(diào)用WCRedLogicMgr的open方法來拆紅包晌区,可以想象open方法的參數(shù)就是上面我們辛苦組裝的字典

3951106727-57c694e8bc9cb_articlex.jpeg

代碼如下:

[[[%c(MMServiceCenter) defaultCenter] getService:[%c(WCRedEnvelopesLogicMgr) class]] OpenRedEnvelopesRequest:args];
領(lǐng)紅包邏輯

到這里,我們再總結(jié)一下我們上面分析的過程......

  • 得到m_oWCPayInfoItem屬性
  • 解析m_oWCPayInfoItem的m_c2cNativeUrl屬性
  • 得到selfcontact
  • 組裝相關(guān)參數(shù)
  • 調(diào)用OpenRedEnvelopesRequest:領(lǐng)取紅包

最終的搶紅包代碼合并起來如下:

#import "WxMsgPreview.h"

%hook CMessageMgr

-(void)AsyncOnAddMsg:(id)message MsgWrap:(CMessageWrap* )msgWrap {
    %log;
    %orig;
    if(msgWrap.m_uiMessageType == 49){
        CContactMgr *contactManager = [[%c(MMServiceCenter) defaultCenter] getService:[%c(CContactMgr) class]];
        CContact *selfContact = [contactManager getSelfContact];

        if ([msgWrap.m_nsContent rangeOfString:@"wxpay://c2cbizmessagehandler/hongbao/receivehongbao"].location != NSNotFound) { // 紅包

            NSString *nativeUrl = [[msgWrap m_oWCPayInfoItem] m_c2cNativeUrl];
            nativeUrl = [nativeUrl substringFromIndex:[@"wxpay://c2cbizmessagehandler/hongbao/receivehongbao?" length]];

            NSDictionary *nativeUrlDict = [%c(WCBizUtil) dictionaryWithDecodedComponets:nativeUrl separator:@"&"];

            NSMutableDictionary *args = [[%c(NSMutableDictionary) alloc] init];
            [args setObject:nativeUrlDict[@"msgtype"] forKey:@"msgType"];
            [args setObject:nativeUrlDict[@"sendid"] forKey:@"sendId"];
            [args setObject:nativeUrlDict[@"channelid"] forKey:@"channelId"];
            [args setObject:[selfContact getContactDisplayName] forKey:@"nickName"];
            [args setObject:[selfContact m_nsHeadImgUrl] forKey:@"headImg"];
            [args setObject:nativeUrl forKey:@"nativeUrl"];
            [args setObject:msgWrap.m_nsFromUsr forKey:@"sessionUserName"];

            [[[%c(MMServiceCenter) defaultCenter] getService:[%c(WCRedEnvelopesLogicMgr) class]] OpenRedEnvelopesRequest:args];
        }
    }
}

%end

剛才說了通贞,有兩個疑難點沒有解決:

  • 第一:我們不知道payinfo是哪里來的朗若,
  • 第二:sessionusername我們也不知道是哪里來的
這時候我們可以從我們注入點的參數(shù)入手,首先用logify打印出addmsg方法的參數(shù)信息昌罩,會發(fā)現(xiàn)哭懈,它的第二個參數(shù)剛好有一個payinfo的屬性,這樣第一個問題迎刃而解了

第二個我們已經(jīng)猜測到它代表群名稱茎用,所以我們從修改幾次群名稱遣总,然后再觀察logify打印出的參數(shù)值的變化睬罗,就可以確認(rèn)出從哪里取了

通過一番折騰,得出了搶紅包的核心代碼旭斥,再結(jié)合上面章節(jié)所講的theos制作tweak包的方法容达,打包并安裝到手機(jī),發(fā)個紅包試試垂券,是不是秒搶花盐?

免越獄插件

檢查依賴項

如果設(shè)備沒有越獄,是沒有mobilesubstrate等環(huán)境的菇爪,而且一些系統(tǒng)目錄是沒有讀寫權(quán)限的算芯,這時我么只能從目標(biāo)app的二進(jìn)制文件入手,通過手動修改load commands來加載自己的dylib娄帖,那么上面我們的插件又是使用theos基于mobilesubstrate編譯的也祠,有沒有辦法確定我們的dylib有沒有依賴其他的庫呢近速?

使用osx自帶的otool工具即可削葱,可以看出析砸,我們的lib是依賴于substrate庫的首繁,其他的都是系統(tǒng)庫弦疮,所以我們從越獄設(shè)備中把cydiasubstrate文件copy出來重命名為libsunstrate.dylib胁塞,和我們的dylib一起放入wechat.app目錄中

最后使用install_name_tool命令修改動態(tài)庫的路徑把它指向app二進(jìn)制文件的同級目錄

2403437607-577f20d889084_articlex.jpeg

制作安裝包

解決了依賴問題啸罢,然后要把我們的庫注入到二進(jìn)制weixin的二進(jìn)制文件扰才,這一步使用開源的insert_dylib即可 (@executable_path是一個環(huán)境變量累驮,指的是二進(jìn)制文件所在的路徑)

insert_dylib命令格式: ./insert_dylib 動態(tài)庫路徑 目標(biāo)二進(jìn)制文件
//注入動態(tài)庫
./insert_dylib @executable_path/wxmsgpreview.dylib WeChat
//打包成ipa
xcrun -sdk iphoneos PackageApplication -v WeChat.app -o ~/WeChat.ipa

最后使用用企業(yè)證書或者開發(fā)證書簽名對ipa重新簽名谤专,就可以放到自己的渠道進(jìn)行發(fā)布了置侍!


結(jié)語


通過綜合運用各種工具蜡坊,進(jìn)行靜態(tài)和動態(tài)分析秕衙,我們通過實戰(zhàn)破解了微信的搶紅包邏輯据忘,明白了入侵常用的工具勇吊,上面的搶紅包代碼還有很多改進(jìn)之處汉规,比如沒有判斷紅包的發(fā)送者是不是自己针史、也沒有判斷紅包里面的文字是不是搶錯三倍,有興趣的童鞋可以嘗試優(yōu)化一下篷就!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末智润,一起剝皮案震驚了整個濱河市窟绷,隨后出現(xiàn)的幾起案子兼蜈,更是在濱河造成了極大的恐慌为狸,老刑警劉巖辐棒,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泰涂,死亡現(xiàn)場離奇詭異逼蒙,居然都是意外死亡是牢,警方通過查閱死者的電腦和手機(jī)妖泄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來朋蔫,“玉大人驯妄,你說我怎么就攤上這事青扔∥⒉” “怎么了凛剥?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵逻炊,是天一觀的道長余素。 經(jīng)常有香客問我溺森,道長屏积,這世上最難降的妖魔是什么炊林? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任渣聚,我火速辦了婚禮奕枝,結(jié)果婚禮上隘道,老公的妹妹穿的比我還像新娘谭梗。我一直安慰自己激捏,他們只是感情好远舅,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著爆办,像睡著了一般距辆。 火紅的嫁衣襯著肌膚如雪跨算。 梳的紋絲不亂的頭發(fā)上诸蚕,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天坏瘩,我揣著相機(jī)與錄音倔矾,去河邊找鬼哪自。 笑死壤巷,一個胖子當(dāng)著我的面吹牛胧华,可吹牛的內(nèi)容都是我干的撑柔。 我是一名探鬼主播您访,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼享言!你這毒婦竟也來了览露?” 一聲冷哼從身側(cè)響起差牛,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤偏化,失蹤者是張志新(化名)和其女友劉穎侦讨,沒想到半個月后韵卤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體沈条,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡贴谎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年擅这,在試婚紗的時候發(fā)現(xiàn)自己被綠了仲翎。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片溯香。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡玫坛,死狀恐怖湿镀,靈堂內(nèi)的尸體忽然破棺而出勉痴,到底是詐尸還是另有隱情蒸矛,我是刑警寧澤雏掠,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布停忿,位于F島的核電站蚊伞,受9級特大地震影響时迫,放射性物質(zhì)發(fā)生泄漏掠拳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望芥牌。 院中可真熱鬧壁拉,春花似錦柏靶、人聲如沸屎蜓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽乎婿。三九已至捍靠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間磁携,已是汗流浹背谊迄。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工统诺, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留粮呢,地道東北人啄寡。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓这难,卻偏偏與公主長得像姻乓,于是被迫代替她去往敵國和親蹋岩。 傳聞我的和親對象是個殘疾皇子剪个,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容