IDA + Hopper 逆向開發近期學習

前言

近期實戰了一次 IDA + Hopper 逆向破解。講真,第一次體驗了一回把別人“衣服”扒光了的快感~簡直 High 翻~所以,特此,利用 AlipayWallet 總結分享一下 IDA 和 Hopper 的基本使用。希望對大家有幫助。

先回顧一下,之前兩篇文章已經學習的內容:

獲得一臺越獄設備

利用 SSH 連接訪問越獄設備

利用 Clutch 解密砸殼

利用 class-dump 導出應用頭文件

利用 Cycript 進行應用運行時的動態分析與修改

這么一看確實學了不少技能,而接下來這篇文章,會簡單介紹兩個反編譯的利器 IDA 和 Hopper 的使用。

注,本次實驗利用的并不是最新版本的支付寶 Mach-O 文件,因此可能本次實驗中涉及的函數方法在最新版本中無法找到,但由于本文章只作為學習,所以,只提供具體的方法。如果有需要,可自行砸殼獲得。

動態分析與靜態分析

動態分析

我們前兩篇學習的 Cycript ,就是典型的動態分析工具。Cycript 可以在應用進行運行時方法分析,視圖層級分析等操作。而動態分析除了 Cycript 以外,常用的工具還有 lldb & debugserver 遠程斷點調試,logify 追蹤等,以后一起慢慢學習這些技能方法。

靜態分析

Static program analysis is the analysis of computer software that is performed without actually executing programs (analysis performed on executing programs is known as dynamic analysis).[1] In most cases the analysis is performed on some version of the source code, and in the other cases, some form of the object code.

以上是 Wikipedia 對靜態分析的英文介紹,中文翻譯如下。

靜態程序分析是指,沒有實際執行程序的電腦軟件分析方法(與之相對的是,被人們所知的實際執行軟件的動態分析)。在絕大部分的例子中,分析是運行在源代碼的某些版本,而其余則是運行在目標代碼中。

之前學習的 class-dump 工具導出 Mach-O 頭文件,就是對軟件應用進行靜態分析。而今天我們要學習的兩個工具,IDA 和 Hopper 反匯編二進制文件同樣也是靜態分析的方法。

IDA 的基本使用

什么是 IDA

IDA is the Interactive DisAssembler: the world’s smartest and most feature-full disassembler, which many software security specialists are familiar with.

IDA 是世界上最敏捷和多功能的反編譯工具,被眾多軟件安全專家所熟知的交互的反匯編工具。

安裝 IDA

IDA 的官方網站是https://www.hex-rays.com/。在網頁上可以看到 IDA 的插件、SDK 等內容。IDA 會在官網提供 Demo 版的下載https://www.hex-rays.com/products/ida/support/download_demo.shtml。然而, Demo 版沒有 IDA 最強大的反匯編功能,神器 F5~!如果自己學習使用正版,很難承擔巨額的證書費用,所以一般情況是在網上找破解版(囧。。并不推薦,土豪還是建議買證書)。很不幸的是 IDA Pro 的 Mac 版非常難找(我是沒找到)。所以,本文是在 Windows 下找破解 IDA Pro 來學習。

IDA Pro 的使用

打開 IDA 會出現AboutSupport message等提示對話框,點擊OK繼續后彈出Quick Start對話框,在這個對話框里可以看到之前打開過的 IDA 反匯編二進制文件,也可以新建一個新的反匯編文件。這里我們點擊New新建一個反匯編,這次以支付寶為例。


準備 Mach-O

回顧之前的內容,先進行 Clutch 砸殼,然后 scp AlipayWallet 到 Mac 目錄下,再利用 class-dump 導出頭文件。

導入 IDA

這里可以直接將 Mach-O 文件拖拽進 IDA 的工作區,也可以點擊打開文件夾的圖標將 Mach-O 導入。檢測到 Objective-C 2.0 代碼時會提示,點擊OK繼續即可。

之后就是漫長的等待~~~(Hopper 相對于 IDA 等待的時間會短一些,但是反編譯結果沒有 IDA 更接近真實的 C 語言代碼,會包含很多寄存器變量)

認識 IDA 工作區

當 IDA 對 Mach-O 解析完成后,會默認出現 6 個選項卡視圖,分別是匯編視圖,16 進制字節視圖,結構體視圖,枚舉類型視圖,導入的函數視圖,導出的函數視圖

另外,紅框標注的是工具欄,藍框標注的是二進制文件解析的進度,在藍框下面,用不同顏色區分庫函數、數據、常規函數等不同類型的解析數據。


靜態分析:還原源代碼

使用 IDA 反匯編二進制文件的目的是,利用工具得到反匯編之后的偽代碼,還原出真正的程序源碼。比如,我們如果要看一下登錄方法是如何寫的,可以在已經導出的 AlipayWallet.h 中查詢login關鍵字,并查找相關代碼,我們發現會有LoginProtocol協議和LoginAdapter類的相關代碼,那我們不妨就拿LoginAdapter這個類作為實戰研究對象。

@protocol LoginProtocol NSObject>

+ (id)sharedInstantce;

- (NSDictionary *)currentSession;

- (void)loginWithLoginOption:(int)arg1 extraInfo:(NSDictionary *)arg2 completionHandler:(void (^)(BOOL, NSDictionary *))arg3 cancelationHandler:(void (^)(void))arg4;

- (void)loginWithLoginOption:(int)arg1 completionHandler:(void (^)(BOOL, NSDictionary *))arg2 cancelationHandler:(void (^)(void))arg3;

- (BOOL)isValidLogin;

@optional

- (void)logout;

- (void)markInvalidLogin;

- (BOOL)isProcessingLogin;

@end

@interface LoginAdapter : NSObject LoginProtocol>

{

int _is_login_doing;

int _is_processing_pending;

id _network_config;

id _login_service;

NSMutableArray *_loginPendingRequests;

NSRecursiveLock *_pending_lock;

}

+ (id)sharedInstantce;

@property(retain, nonatomic) NSRecursiveLock *pending_lock; // @synthesize pending_lock=_pending_lock;

@property(retain, nonatomic) NSMutableArray *loginPendingRequests; // @synthesize loginPendingRequests=_loginPendingRequests;

@property(retain, nonatomic) id login_service; // @synthesize login_service=_login_service;

@property(retain, nonatomic) id network_config; // @synthesize network_config=_network_config;

- (void).cxx_destruct;

- (void)storeSessionWithLoginResult:(id)arg1;

- (id)currentUserId;

- (void)notifyNetworkSDK:(id)arg1;

- (void)logout:(id)arg1;

- (void)logined:(id)arg1;

- (void)loadAlu:(Class)arg1;

- (void)loadLoginModule;

- (void)loadNetworSDKConfig;

- (void)failedPendingLoginRequests;

- (void)redoPendingLoginRequests;

- (void)pendingLoginRequest:(id)arg1;

- (void)releasePendingLock;

- (void)accquirePendingLock;

- (void)releaseLoginLock;

- (BOOL)accquireLoginLock;

- (int)tryLogin:(id)arg1 isForce:(BOOL)arg2;

- (int)tryLogin:(id)arg1;

- (void)logout;

- (id)currentSession;

- (int)loginWithLoginOption:(int)arg1 isForce:(BOOL)arg2 extraInfo:(id)arg3 completionHandler:(CDUnknownBlockType)arg4 cancelationHandler:(CDUnknownBlockType)arg5 request:(id)arg6;

- (void)loginWithLoginOption:(int)arg1 extraInfo:(id)arg2 completionHandler:(CDUnknownBlockType)arg3 cancelationHandler:(CDUnknownBlockType)arg4;

- (void)loginWithLoginOption:(int)arg1 completionHandler:(CDUnknownBlockType)arg2 cancelationHandler:(CDUnknownBlockType)arg3;

- (BOOL)isValidLogin;

- (BOOL)isProcessingLogin;

- (void)markInvalidLogin;

- (id)setCustomLoginModule:(id)arg1;

- (void)dealloc;

- (id)init;

// Remaining properties

@property(readonly, copy) NSString *debugDescription;

@property(readonly, copy) NSString *description;

@property(readonly) unsigned int hash;

@property(readonly) Class superclass;

@end

在頭文件里查找可以得到上面結果,以LoginAdapter為例。我們可以在 function 窗口中按住 Ctrl+F 鍵查找LoginAdapter的相關函數。


雙擊[LoginAdapter sharedInstan]到達這個函數在二進制文件中的內存地址,按F5可以就查看這個反編譯的偽碼。

這里可以看一下登錄方法 Alipay 是如何寫的,雙擊[LoginAdapter loginWithLoginOption:isForce:extraInfo:completionHandler:cancelationHandler:request:],按F5鍵查看這個方法的反編譯偽代碼。偽代碼如下。

#import"LoginAdapter.h

#import"LogAdapter.h"

#import"MtopExtRequest.h"

@implementation LoginAdapter

- (NSInteger)loginWithLoginOption:(int)option

isForce:(BOOL)isForce

extraInfo:(NSDictionary *)extraInfo

completionHandler:(AlipayCompletionHandler)completionHandler

cancelationHandler:(AlipayCancelationHandler)cancelationHandler

request:(MtopExtRequest *)request {

// self是當前實例指針,a2對應方法選擇器,a3對應方法參數option; a4對應方法參數isForce; a5對應方法參數extraInfo;

// a6對應方法參數completionHandler; a7對應方法參數cancelationHandler; a8對應方法參數request

NSInteger returnValue =0;// v18

if(!self.login_service) {

returnValue =0;

}

if(request) {

[self accquirePendingLock];

}

if([self accquireLoginLock]) {

if(extraInfo || ![self isValidLogin]) {

if(request) {

[self pendingLoginRequest:request];

}

LogAdapter *logAdapter = [LogAdapter getInstance];

NSString *apiName = [request getApiName];

NSString *apiVersion = [request getApiVersion];

NSString *logString = [NSString stringWithFormat:@"[LoginAdapter] apiName: %@, apiVersion: %@ pull login module", apiName, apiVersion];

[logAdapter warn:logString];

[self.login_service loginWithLoginOption:option

extraInfo:extraInfo

completionHandler:completionHandler

cancelationHandler:cancelationHandler];

}// extraInfo || ![self isValidLogin] end

[self releaseLoginLock];

if(completionHandler) {

NSDictionary *currentSession = [self.login_service currentSession];

completionHandler(1, currentSession);

}else{

// v38 = v8即,對self進行retain操作,無需翻譯成oc代碼

}

returnValue =3;

}else{

if(request) {

if(self.loginPendingRequests.count) {

returnValue =0;

}else{

[self pendingLoginRequest:request];

returnValue =1;

}

}else{

returnValue =0;

}

if(completionHandler) {

completionHandler(0, [NSDictionary dictionary]);

}else{

completionHandler = nil;

}

}

if(request) {

[self releaseLoginLock];

}

returnreturnValue;

}

@end


Hopper 的基本使用

對于 Hopper 的學習,依然使用 AlipayWallet 這個文件進行分析,與 IDA 做比較,類比進行。

什么是 Hopper

Hopper Disassembler, the reverse engineering tool that lets you disassemble, decompile and debug your applications.

Hopper 反匯編工具,是逆向工程的工具,能夠讓你進行反匯編、反編譯并且調試你的應用。

安裝 Hopper

Hopper 的官網是https://www.hopperapp.com/,與 IDA 相同,官網也提供了 Demo 的試用版。試用版也可以進行反匯編,但是不能保存 *.hop 文件。所以,用于學習的話 Hopper 的 Demo 版就足夠了。

Hopper 的使用

導入 Hopper

與 IDA 不同, Hopper 不能直接將 Mach-O 文件導入工作區,需要下載應用的 *.ipa 文件,并將文件后綴改為 *.zip,解壓該 zip 文件后就可看到 Payload 文件目錄,在該目錄下就存有對應應用的 package 包文件。右擊該 package 出現菜單,選擇Show Package Contents選項,就可看到包內容。


認識 Hopper 工作區

與 IDA 類似, Hopper 也有二進制文件的解析進度條,左邊是符號 Label 等區域,中間是 ARM 的匯編代碼,右邊是相關信息欄。


靜態分析:Hopper 反匯編的偽代碼

如圖,在最左列的搜索欄中輸入loginWithLoginOption關鍵字,雙擊選擇[LoginAdapter loginWithLoginOption:isForce:extraInfo:completionHandler:cancelationHandler:request:]方法,在中間的匯編代碼區域,光標就會跳到該方法的內存地址處。

當 Hopper 分析完全部二進制后,按住Option + Enter鍵,就可看到 Hopper 反編譯后的偽代碼,如下所示。

int -[LoginAdapter loginWithLoginOption:isForce:extraInfo:completionHandler:cancelationHandler:request:](void * self, void * _cmd, int arg2, char arg3, void * arg4, void * arg5, void * arg6, void * arg7) {

stack[2048] = arg4;

r7 = (sp - 0x14) + 0xc;

sp = sp - 0x74;

r8 = self;

r5 = arg3;

stack[2051] = arg2;

stack[2053] = [arg4 retain];

r6 = [arg5 retain];

r11 = [arg6 retain];

r10 = [arg7 retain];

if (r8->_login_service == 0x0) goto loc_2aaee0a;

loc_2aaed6c:

stack[2054] = r6;

if (r10 != 0x0) {

[r8 accquirePendingLock];

}

if (([r8 accquireLoginLock] & 0xff) == 0x0) goto loc_2aaefa8;

loc_2aaeda0:

if (((r5 & 0xff) != 0x0) || (([r8 isValidLogin] & 0xff) == 0x0)) goto loc_2aaee10;

loc_2aaedbe:

[r8 releaseLoginLock];

r6 = stack[2054];

if (r6 != 0x0) {

stack[2052] = r8;

r5 = [[r8->_login_service currentSession] retain];

(*(r6 + 0xc))(r6, 0x1, r5, *(r6 + 0xc));

[r5 release];

}

else {

stack[2052] = r8;

}

r5 = 0x3;

goto loc_2aaf044;

loc_2aaf044:

r4 = stack[2053];

goto loc_2aaf046;

loc_2aaf046:

if (r10 != 0x0) {

[stack[2052] releasePendingLock];

}

r6 = stack[2054];

goto loc_2aaf060;

loc_2aaf060:

[r10 release];

[r11 release];

[r6 release];

[r4 release];

r0 = r5;

return r0;

loc_2aaee10:

stack[2050] = r11;

if (r10 != 0x0) {

[r8 pendingLoginRequest:r10];

}

r6 = [[LogAdapter getInstance] retain];

stack[2052] = r8;

r8 = [[r10 getApiName] retain];

r11 = [[r10 getApiVersion] retain];

r5 = [[NSString stringWithFormat:@"[LoginAdapter] apiName: %@, apiVersion: %@ pull login module", r8, r11] retain];

[r6 warn:r5];

[r5 release];

[r11 release];

[r8 release];

[r6 release];

r5 = [stack[2052] retain];

stack[2068] = [stack[2054] retain];

r11 = stack[2050];

stack[2060] = [r5 retain];

r4 = stack[2053];

stack[2061] = [r11 retain];

[stack[2052]->_login_service loginWithLoginOption:stack[2051] extraInfo:r4 completionHandler:sp + 0x38 cancelationHandler:sp + 0x1c, stack[2050], stack[2051], stack[2052], stack[2053], stack[2054], __NSConcreteStackBlock, 0xc2000000, 0x0];

[stack[2061] release];

[stack[2060] release];

[stack[2068] release];

[r5 release];

r5 = 0x2;

goto loc_2aaf046;

loc_2aaefa8:

if (r10 != 0x0) {

r6 = stack[2054];

if ([r8->_loginPendingRequests count] <= 0xff) {

stack[2052] = r8;

[r8 pendingLoginRequest:r10];

r5 = 0x1;

}

else {

stack[2052] = r8;

r5 = 0x0;

}

}

else {

stack[2052] = r8;

r5 = 0x0;

r6 = stack[2054];

}

if (r6 != 0x0) {

r4 = [[NSDictionary dictionary] retain];

stack[2054] = r6;

(*(r6 + 0xc))(r6, 0x0, r4, *(r6 + 0xc), stack[2048]);

[r4 release];

}

else {

stack[2054] = r6;

}

goto loc_2aaf044;

loc_2aaee0a:

r5 = 0x0;

r4 = stack[2053];

goto loc_2aaf060;

}

與 IDA 相比, Hopper 反編譯后的偽代碼的邏輯與 IDA 反編譯得到的偽代碼邏輯類似,但多了 r0~r8 等寄存器,閱讀性相較而言差一些,但是,仍然可以根據偽代碼還原出源代碼。

其實我們可以用這個偽代碼來檢查我們之前還原的源代碼,保證還原代碼的正確性。

以上,便是 Hopper 的簡單使用。 Hopper 除了可以查看匯編代碼以外,還可以直接對 Mach-O 文件進行修改,然后重新生成二進制文件(Demo 版沒有這個功能)。

感興趣的同學可以閱讀這篇文章學習, 《如何讓 Mac 版微信客戶端防撤回》http://t.cn/RxzeMIx

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,362評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,577評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,486評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,852評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,600評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,944評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,944評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,108評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,652評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,385評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,616評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,111評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,798評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,205評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,537評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,334評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,570評論 2 379

推薦閱讀更多精彩內容