iOS逆向工程整理 HOOK微信抢红包
原理
Objective-C 是一門動(dòng)態(tài)語言,我們可以利用OC的Runtime動(dòng)態(tài)的替換App原有的函數(shù),來達(dá)到我們(不可告人)的目的。OC 中對某個(gè)對象的方法的調(diào)用并不像 C++ 一樣直接取得方法的實(shí)現(xiàn)的偏移值來調(diào)用,所以 C++ 方法與實(shí)現(xiàn)的關(guān)系在編譯時(shí)就可確定。而 OC 中方法和實(shí)現(xiàn)的關(guān)系是在運(yùn)行時(shí)決定的。在調(diào)用某個(gè)對象的方法時(shí),實(shí)際上是調(diào)用了 obj_msgsend 向?qū)ο蟀l(fā)送一個(gè)名稱為方法名的消息,而我們可以替換這個(gè)響應(yīng)這個(gè)消息的實(shí)現(xiàn)內(nèi)容。OC 中比較有力的動(dòng)態(tài)特性 Method Swizzing 就是建立在這個(gè)基礎(chǔ)之上。
簡單來說就是以下三句代碼:
- 1
- 2
- 3
這樣一來,原來調(diào)用originalSelector函數(shù),都會(huì)指向我們的newSelector函數(shù),以此實(shí)現(xiàn)HOOK。
工欲善其事,必先利其器
要進(jìn)行iOS的HOOK開發(fā),首先要準(zhǔn)備一臺(tái)Mac電腦(廢話),一臺(tái)越獄的iphone或者ipad。針對這類的需求,大神們開發(fā)了很多NB的工具,專門幫我們更好的去HOOK,我們都是站在大神的肩膀上。?
先介紹以下越獄開發(fā)常見的工具OpenSSH,Dumpdecrypted,class-dump、Theos、Reveal、IDA,Hopper
OpenSSH
這個(gè)工具是通過命令行工具訪問蘋果手機(jī),執(zhí)行命令行腳本。在Cydia中搜索openssh,安裝。具體用法如下:?
1、打開mac下的terminal,輸入命令ssh root@192.168.2.2(越獄設(shè)備ip地址)?
2、接下來會(huì)提示輸入超級管理員賬號密碼,默認(rèn)是alpine?
3、回車確認(rèn),即可root登錄設(shè)備?
你也可以將你mac的公鑰導(dǎo)入設(shè)備的/var/root/.ssh/authorized_keys文件,這樣就可以免密登錄root了。
Cycript
Cycript是大神saurik開發(fā)的一個(gè)非常強(qiáng)大的工具,可以讓開發(fā)者在命令行下和應(yīng)用交互,在運(yùn)行時(shí)查看和修改應(yīng)用。它可以幫助你HOOK一個(gè)App。Cycript最為貼心和實(shí)用的功能是它可以幫助我們輕松測試函數(shù)效果,整個(gè)過程安全無副作用,效果十分顯著,實(shí)乃業(yè)界良心!?
安裝方式:在Cydia中搜索Cycript安裝?
使用方法:?
1、root登錄越獄設(shè)備?
2、cycript-p 你想要測試的進(jìn)程名?
3、隨便玩,完全兼容OC語法比如cy# [#0x235b4fb1 hidden]?
Cycript有幾條非常有用的命令:?
choose:如果知道一個(gè)類對象存在于當(dāng)前的進(jìn)程中,卻不知道它的地址,不能通過“#”操作符來獲取它,此時(shí)可以使用choose命令獲取到該類的所有對象的內(nèi)存地址?
打印一個(gè)對象的所有屬性 [obj _ivarDescription].toString()?
打印一個(gè)對象的所有方法[obj _methodDescription].toString()?
動(dòng)態(tài)添加屬性 objc_setAssociatedObject(obj,@”isAdd”, [NSNumbernumberWithBool:YES], 0);?
獲取動(dòng)態(tài)添加的屬性 objc_getAssociatedObject(self, @”isAdd”)
Reveal
Reveal是由ITTY BITTY出品的UI分析工具,可以直觀地查看App的UI布局,我們可以用來研究別人的App界面是怎么做的,有哪些元素。更重要的是,可以直接找到你要HOOK的那個(gè)ViewController,賊方便不用瞎貓抓耗子一樣到處去找是哪個(gè)ViewController了。?
安裝方法:?
1、下載安裝Mac版的Reveal?
2、iOS安裝Reveal Loader,在Cydia中搜索并安裝Reveal Loader?
在安裝Reveal Loader的時(shí)候,它會(huì)自動(dòng)從Reveal的官網(wǎng)下載一個(gè)必須的文件libReveal.dylib。如果網(wǎng)絡(luò)狀況不太好,不一定能夠成功下載這個(gè)dylib文件,所以在下載完Reveal Loader后,檢查iOS上的“/Library/RHRevealLoader/”目錄下有沒有一個(gè)名為“l(fā)ibReveal.dylib”的文件。如果沒有就打開mac Reveal,在它標(biāo)題欄的“Help”選項(xiàng)下,選中其中的“Show Reveal Library in Finder”,找到libReveal.dylib文件,使用scp拷貝到 iOS的/Library/RHRevealLoader/目錄下。至此Reveal安裝完畢!
Dumpdecrypted
Dumpdecrypted就是著名的砸殼工具,所謂砸殼,就是對 ipa 文件進(jìn)行解密。因?yàn)樵谏蟼鞯?AppStore 之后,AppStore自動(dòng)給所有的 ipa 進(jìn)行了加密處理。而對于加密后的文件,直接使用 class-dump 是得不到什么東西的,或者是空文件,或者是一堆加密后的方法/類名。?
使用步驟如下:?
1、設(shè)備中打開需要砸殼的APP。?
2、SSH連接到手機(jī),找到ipa包的位置并記錄下來。?
3、Cycript到該ipa的進(jìn)程,找到App的Documents文件夾位置并記錄下來。?
4、拷貝dumpdecrypted.dylib到App的Documents 的目錄。?
5、執(zhí)行砸殼后,并拷貝出砸殼后的二進(jìn)制文件。?
具體執(zhí)行命令:?
1、ssh root@192.168.2.2 (iP地址為越獄設(shè)備的iP地址)?
2、 ps -e (查看進(jìn)程,把進(jìn)程對應(yīng)的二進(jìn)制文件地址記下來)?
3、cycript -p 進(jìn)程名?
4、 [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory?
inDomains:NSUserDomainMask][0] (找到程序的documents目錄)?
5、scp ~/dumpdecrypted.dylib root@192.168.2.2:/var/mobile/Containers/Data/Application/XXXXXX/Documents?
6、DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib /var/mobile/Containers/Bundle/?
Application/XXXXXX/xxx.app/xxx?
然后就會(huì)生成.decrypted的文件,這個(gè)就是砸殼后的文件。接下來各種工具都隨便上了class-dump、IDA、Hopper Disassembler
class-dump
class-dump就是用來dump二進(jìn)制運(yùn)行文件里面的class信息的工具。它利用Objective-C語言的runtime特性,將存儲(chǔ)在Mach-O文件中的頭文件信息提取出來,并生成對應(yīng)的.h文件,這個(gè)工具非常有用,有了這個(gè)工具我們就像四維世界里面看三維物體,一切架構(gòu)盡收眼底。?
class-dump用法:?
class-dump –arch armv7 -s -S -H 二進(jìn)制文件路徑 -o 頭文件保存路徑
IDA
IDA是大名鼎鼎的反編譯工具,它乃逆向工程中最負(fù)盛名的神器之一。支持Windows、Linux和Mac OS X的多平臺(tái)反匯編器/調(diào)試器,它的功能非常強(qiáng)大。class-dump可以幫我們羅列出要分析的頭文件,IDA能夠深入各個(gè)函數(shù)的具體實(shí)現(xiàn),無論的C,C++,OC的函數(shù)都可以反編譯出來。不過反編譯出來的是匯編代碼,你需要有一定的匯編基礎(chǔ)才能讀的懂。?
IDA很吃機(jī)器性能(我的機(jī)器經(jīng)常卡住不動(dòng)),還有另外一個(gè)反編譯工具Hopper,對機(jī)器性能要求沒那么高,也很好用,殺人越貨的利器。
LLDB
LLDB是由蘋果出品,內(nèi)置于Xcode中的動(dòng)態(tài)調(diào)試工具,可以調(diào)試C、C++、Objective-C,還全盤支持OSX、iOS,以及iOS模擬器。LLDB要配合debugserver來使用。常見的LLDB命令有:?
p命令:首先p是打印非對象的值。如果使用它打印對象的話,那么它會(huì)打印出對象的地址,如果打印非對象它一般會(huì)打印出基本變量類型的值。當(dāng)然用它也可以申明一個(gè)變量譬如 p int a=10;(注lldb使用a = 10; (注lldb使用在變量前來聲明為lldb內(nèi)的命名空間的)?
po 命令:po 命令是我們最常用的命令因?yàn)樵趇os開發(fā)中,我們時(shí)刻面臨著對象,所以我們在絕大部分時(shí)候都會(huì)使用po。首先po這個(gè)命令會(huì)打印出對象的description描述。?
bt [all] 打印調(diào)用堆棧,是thread backtrace的簡寫,加all可打印所有thread的堆棧。?
br l 是breakpoint list的簡寫,列出所有的斷點(diǎn)?
image list -o -f 列出模塊和ASLR偏移,以及偏移后的地址,可以通過偏移后的地址-ASLR偏移來得出模塊的基地址。?
b NSLog給函數(shù)設(shè)置斷點(diǎn)?
br s -a IDA中偏移前的地址+ASLR偏移量 給內(nèi)存地址設(shè)置斷點(diǎn)?
p (char *)$r1打印函數(shù)名稱?
br dis、br en和br del表示禁用、啟用和刪除斷點(diǎn)?
nexti(ni)跳過一行?
stepi(si)跳入函數(shù)?
c繼續(xù)執(zhí)行直到斷點(diǎn)?
register write r0 1修改寄存器的值
usbmuxd
很多人都是通過WiFi連接使用SSH服務(wù)的,因?yàn)闊o線網(wǎng)絡(luò)的不穩(wěn)定性及傳輸速度的限制,在復(fù)制文件或用LLDB遠(yuǎn)程調(diào)試時(shí),iOS的響應(yīng)很慢,效率不高。iOS越獄社區(qū)的知名人士Nikias Bassen開發(fā)了一款可以把本地OSX/Windows端口轉(zhuǎn)發(fā)到遠(yuǎn)程iOS端口的工具usbmuxd,使我們能夠通過USB連接線ssh到iOS中,大大增加了ssh連接的速度,也方便了那些沒有WiFi的朋友。使用usbmuxd能極大提升ssh的速度,用LLDB遠(yuǎn)程連接debugserver的時(shí)間被縮短至15秒以內(nèi),強(qiáng)烈建議大家把usbmuxd作為ssh連接的首選方案
Theos
以上都是App的分析工具,而Theos是一個(gè)越獄開發(fā)工具包(具體寫代碼),由iOS越獄界知名人士Dustin Howett開發(fā)并分享到GitHub上。Theos與其他越獄開發(fā)工具相比,最大的特點(diǎn)就是簡單:下載安裝簡單、Logos語法簡單、編譯發(fā)布簡單,可以讓使用者把精力都放在開發(fā)工作上去。就是讓你省去了繁瑣的原始代碼編寫,簡化了編譯和安裝過程。同樣有一款工具iOSOpenDev是整合在Xcode里的,可以直接在Xcode中配置開發(fā)、運(yùn)行越獄程序,不過iOSOpenDev的安裝,過程真的是讓人要吐血(我有一臺(tái)mac死活都裝不上)。?
用法,theos有多種模板可以選擇,最常用的就是tweak插件了:/opt/theos/bin/nic.pl
NIC 2.0 - New Instance Creator
[1.] iphone/application?
[2.] iphone/library?
[3.] iphone/preference_bundle?
[4.] iphone/tool?
[5.] iphone/tweak?
打包編譯安裝,需要按照固定格式編寫Makefile文件,然后執(zhí)行命令?
make package install,自動(dòng)編譯打包安裝到iOS設(shè)備。?
如果你用的是IOSOpenDev就更簡單了,配置好iOS設(shè)備ip地址,直接執(zhí)行product->Bulid for->profiling,自動(dòng)打包安裝好。
原理上篇已經(jīng)說過了,利用iOS的runtime特效,替換方法的實(shí)現(xiàn)來達(dá)到HOOK的目的。本篇是一個(gè)實(shí)戰(zhàn)教程,講解怎么來Hook微信的自動(dòng)搶紅包。
第1步:砸殼
首先ssh連上越獄iOS設(shè)備,執(zhí)行ps -e查找微信的app地址
這里的app路徑是/var/mobile/Containers/Bundle/Application/690828B8-B63F-4FAC-B7CC-DEFD8E23AF46/WeChat.app/WeChat,記下來先。
然后進(jìn)入Cycript,查找出微信的Documents目錄
把這個(gè)路徑記下來/var/mobile/Containers/Data/Application/2B65DCC1-9FAD-41C8-A5EC-C3D9326EE3D6/Documents/
然后退出cycript,cd到documents目錄下,執(zhí)行以下命令:
WeChat.decrypted文件就是我們砸殼后的二進(jìn)制文件,我們可以拷貝到Mac上,各種工具都可以用上了。
第2步:導(dǎo)出頭文件
使用class-dump,將我們砸殼出來的二進(jìn)制文件的頭文件導(dǎo)出來:
admindeMac-mini:微信6.5.5 admin$ class-dump --arch armv7 -s -S -H WeChat.decrypted -o headers/ admindeMac-mini:微信6.5.5 admin$ ls headers/ AAAlertItem.h AACloseNotifyReq.h AACloseNotifyRes.h AACloseReq.h AACloseRes.h AALaunchByMoneyReq.h AALaunchByMoneyRes.h AALaunchByPersonReq.h AALaunchByPersonRes.h AALaunchItem.h AAListRecord.h AAOperationReq.h AAOperationRes.h AAPayReq.h AAPayRes.h可以看到微信的頭文件有8500多個(gè)(汗),如此茫茫代碼海出如何找出我們需要的那一部分呢?
第2步:精準(zhǔn)定位我們想要HOOK的代碼
iOS開發(fā)是遵循MVC模式的,所以我們需要找到這個(gè)M模型層來找到我需要的業(yè)務(wù)邏輯代碼。搶紅包的原理是通過截取微信收到了紅包消息,然后直接調(diào)用打開紅包的接口來實(shí)現(xiàn)自動(dòng)搶紅包。
通過查找發(fā)現(xiàn)CMessageMgr這個(gè)類就是用來管理各種消息的,查看CMessageMgr.h頭文件
通過猜想假設(shè),再加上編寫Tweak腳本測試,發(fā)現(xiàn)我們想要的接受消息的函數(shù)是AsyncOnAddMsg這個(gè)函數(shù)。找到接受消息的函數(shù)后接下來,我們要找打開紅包的函數(shù)。
在頭文件目錄下搜索OpenRedEnvelope
我們猜想WCRedEnvelopesLogicMgr.h里面的OpenRedEnvelopesRequest函數(shù)就是我們要找的目標(biāo)函數(shù),經(jīng)常反復(fù)的測試和驗(yàn)證,這個(gè)函數(shù)確實(shí)是我們要的打開紅包的函數(shù)。
第3步:寫代碼完成開發(fā)
經(jīng)歷了以上分析和驗(yàn)證的過程,寫代碼對于HOOK來說反而是很簡單的水到渠成。具體搶紅包的代碼如下:
@class CMessageMgr;CHDeclareClass(CMessageMgr);CHOptimizedMethod(2, self, void, CMessageMgr, AsyncOnAddMsg, id, arg1, MsgWrap, id, arg2) {CHSuper(2, CMessageMgr, AsyncOnAddMsg, arg1, MsgWrap, arg2);Ivar uiMessageTypeIvar = class_getInstanceVariable(objc_getClass("CMessageWrap"), "m_uiMessageType");ptrdiff_t offset = ivar_getOffset(uiMessageTypeIvar);unsigned char *stuffBytes = (unsigned char *)(__bridge void *)arg2;NSUInteger m_uiMessageType = * ((NSUInteger *)(stuffBytes + offset));Ivar nsFromUsrIvar = class_getInstanceVariable(objc_getClass("CMessageWrap"), "m_nsFromUsr");id m_nsFromUsr = object_getIvar(arg2, nsFromUsrIvar);Ivar nsContentIvar = class_getInstanceVariable(objc_getClass("CMessageWrap"), "m_nsContent");id m_nsContent = object_getIvar(arg2, nsContentIvar);switch(m_uiMessageType) {case 1: {}break;case 49: {// 49=紅包//微信的服務(wù)中心Method methodMMServiceCenter = class_getClassMethod(objc_getClass("MMServiceCenter"), @selector(defaultCenter));IMP impMMSC = method_getImplementation(methodMMServiceCenter);id MMServiceCenter = impMMSC(objc_getClass("MMServiceCenter"), @selector(defaultCenter));//紅包控制器id logicMgr = ((id (*)(id, SEL, Class))objc_msgSend)(MMServiceCenter, @selector(getService:), objc_getClass("WCRedEnvelopesLogicMgr"));//通訊錄管理器id contactManager = ((id (*)(id, SEL, Class))objc_msgSend)(MMServiceCenter, @selector(getService:),objc_getClass("CContactMgr"));Method methodGetSelfContact = class_getInstanceMethod(objc_getClass("CContactMgr"), @selector(getSelfContact));IMP impGS = method_getImplementation(methodGetSelfContact);id selfContact = impGS(contactManager, @selector(getSelfContact));if ([m_nsContent rangeOfString:@"wxpay://"].location != NSNotFound){NSString *nativeUrl = m_nsContent;NSRange rangeStart = [m_nsContent rangeOfString:@"wxpay://c2cbizmessagehandler/hongbao"];if (rangeStart.location != NSNotFound){NSUInteger locationStart = rangeStart.location;nativeUrl = [nativeUrl substringFromIndex:locationStart];}NSRange rangeEnd = [nativeUrl rangeOfString:@"]]"];if (rangeEnd.location != NSNotFound){NSUInteger locationEnd = rangeEnd.location;nativeUrl = [nativeUrl substringToIndex:locationEnd];}NSString *naUrl = [nativeUrl substringFromIndex:[@"wxpay://c2cbizmessagehandler/hongbao/receivehongbao?" length]];NSArray *parameterPairs =[naUrl componentsSeparatedByString:@"&"];NSMutableDictionary *parameters = [NSMutableDictionary dictionaryWithCapacity:[parameterPairs count]];for (NSString *currentPair in parameterPairs) {NSRange range = [currentPair rangeOfString:@"="];if(range.location == NSNotFound)continue;NSString *key = [currentPair substringToIndex:range.location];NSString *value =[currentPair substringFromIndex:range.location + 1];[parameters setObject:value forKey:key];}//紅包參數(shù)NSMutableDictionary *params = [@{} mutableCopy];[params setObject:parameters[@"msgtypes"]?:@"null" forKey:@"msgType"];[params setObject:parameters[@"sendid"]?:@"null" forKey:@"sendId"];[params setObject:parameters[@"channelid"]?:@"null" forKey:@"channelId"];id getContactDisplayName = objc_msgSend(selfContact, @selector(getContactDisplayName));id m_nsHeadImgUrl = objc_msgSend(selfContact, @selector(m_nsHeadImgUrl));[params setObject:getContactDisplayName forKey:@"nickName"];[params setObject:m_nsHeadImgUrl forKey:@"headImg"];[params setObject:[NSString stringWithFormat:@"%@", nativeUrl]?:@"null" forKey:@"nativeUrl"];[params setObject:m_nsFromUsr?:@"null" forKey:@"sessionUserName"];((void (*)(id, SEL, NSMutableDictionary*))objc_msgSend)(logicMgr, @selector(OpenRedEnvelopesRequest:), params);return;}break;}default:break;} }以上就是微信搶紅包的分析和代碼過程,才有的是越獄方式開發(fā),打包的dylib動(dòng)態(tài)鏈接庫文件是直接放入到系統(tǒng)文件目錄里面的。至于非越獄開發(fā),要更復(fù)雜一點(diǎn),涉及到原始app文件的解包,修改,添加動(dòng)態(tài)鏈接庫,然后再簽名打包的一系列復(fù)雜過程。僅供參考和學(xué)習(xí)用,請勿用于商業(yè)用途,否則后果自負(fù)!
轉(zhuǎn)自: http://blog.csdn.net/dlmlzz09/article/details/62232254總結(jié)
以上是生活随笔為你收集整理的iOS逆向工程整理 HOOK微信抢红包的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: P2548 [AHOI2004]智能探险
- 下一篇: 类和继承