1、前言git
2、注入思路github
3、動態庫注入實現xcode
4、分析實現按鈕監聽bash
在文章《應用簽名-腳本簽名》中介紹瞭如何在真機上運行破殼應用(抖音、微信、支付寶等ipa
包),來觀察應用視圖的層級結構,方法調用,類名稱等,以便學習參考。應用主要與後臺進行數據交互展現(數據拉取及提交數據),既然能對破殼應用重簽名並在真機上運行,那麼能不能修改應用數據和頁面展現呢,如監聽微信登陸按鈕,修改微信步數,下面就這兩個功能拓展一下思路。架構
在ipa
包中,主要包含了應用簽名、資源文件、Frameworks
文件、info.plist
配置文件及與ipa
包同名的可執行通用文件(這裏包含了具體的業務執行指令)。在《Mach-O》中咱們對Mach-O
文件有一個初步瞭解,主要有Header、Load commands、Data
三部分組成。app
Header:
包含Mach-O
文件的基本信息,字節順序、架構類型、加載指令的數量等;Load commands:
包含區域位置、符號表、動態符號表,加載Mach-O
文件時使用這裏的數據肯定內存分佈;Data:
數據段segement
,包含具體代碼、常量、類、方法等。函數
若是要向已有應用ipa
中加入本身的代碼,必須對Mach-O
進行修改重組。根據已有開發經驗有思路兩個:工具
一、修改功能代碼,向
Mach-O
中的Data
部分增刪改數據段; 二、另外一個是添加動態庫,利用runtime
對原始代碼進行方法替換,數據、UI
的修改。佈局
第一種方案須要分析Mach-O
對應的彙編代碼,來修改功能,操做較繁瑣;第二種方案,須要咱們向ipa
包下的Frameworks
中添加寫好的動態庫,並向Load commands
添加動態庫加載指令,同時還須要修改Header
中對應的基本信息,相對於第一種不用作彙編指令分析了。
以上只是我的的一些思考,這裏就不去研究具體的注入過程,直接使用一個第三方庫來完成動態庫的注入,先完成微信登陸按鈕的監聽,之後再對具體的操做進一步學習研究。
第三方動態庫注入工具:yololib
破殼
ipa
獲取: 一、經過越獄手機獲取破殼應用; 二、經過PP助手
獲取越獄應用。
在《應用簽名-腳本簽名》中實現了對破殼應用的重簽名,並運行在真機上可供調試。
一、建立新工程 常規建立,工程名InsertCode
(工程名隨意):
二、插入簽名腳本、獲取破殼ipa
包,放入app
文件中
app
內的ipa
包不建議導入工程,放在文件中便可(可能要加入其餘應用包)三、真機運行,執行要查看的ipa包
選擇證書,在真機上運行,ipa
會被安裝至手機上,注意這裏的ipa
必須是破殼的,並具備相同架構配置的ipa
不然安裝失敗。
四、建立Frameworks
文件
在動態庫文件下建立Insert類:
在
runtime
中一般會使用+load
方法,該方法會在編譯期被調用,所以在應用運行前,對應用內部方法動動手腳。下面先在load
方法中插入打印代碼,再向ipa
包中插入動態庫,看看是否可以插入到新包中。
代碼:
@implementation Insert
+ (void)load {
NSLog(@"插入成功");
}
@end
複製代碼
五、引入注入工具yololib
下載 yololib 並編譯(或直接拿到可執行文件),將可執行文件複製到工程中的tool
目錄下,注意給執行權限。
在SignApp.sh
腳本最後一行插入注入指令:
#注入
if [ -d "$BUILT_PRODUCTS_DIR/HBHook.framework" ]
then
${SRCROOT}/tool/yololib "$TARGET_APP_PATH/$APP_BINARY" "Frameworks/HBHook.framework/HBHook"
else
echo "沒有該文件"
fi
複製代碼
完整操做以下:
準備工做完成,運行工程:
打印「插入成功」,說明動態庫已成功插入到ipa
中,用 MachOView 打開.app中WeChat通用二進制文件,查看新的佈局以下:
在Load commands
中已經有了動態庫的加載指令,接下來就對原登陸按鈕的點擊方法作替換監聽。
替換原登陸方法,須要咱們知道對應的方法名稱。怎麼查找?以下:
Action onFirstViewLogin
,所屬類WCAccountLoginControlLogic
瞬間感受微信很友好😘!!!
那麼開始編寫方法替換代碼:
#import "Insert.h"
#import <objc/message.h>
@implementation Insert
+ (void)load {
NSLog(@"插入成功");
Method old_method = class_getInstanceMethod(objc_getClass("WCAccountLoginControlLogic"), sel_registerName("onFirstViewLogin"));
Method new_method = class_getInstanceMethod(self, sel_registerName("my_onFirstViewLogin"));
method_exchangeImplementations(old_method, new_method);
}
-(void)my_onFirstViewLogin {
NSLog(@"我來了");
[self my_onFirstViewLogin];
}
@end
複製代碼
imp
指向runtime
函數來獲取類及類方法my_onFirstViewLogin
被WCAccountLoginControlLogic
的實例調用,所以self
指的是WCAccountLoginControlLogic
的實例運行工程,點擊登陸按鈕,以下:
第一行打印了「我來了」,說明,咱們監聽到了按鈕的點擊事件,但後面出現崩潰,此處很好理解,在原控制器中並無找到對應的選擇器。回憶以前的方法替換,咱們是在對應類的分類中去替換,方法在編譯時會加入到該類的方法列表中,而此處並非原類的分類。
那麼如何解決呢,這裏有三種方法:
+ (void)load {
NSLog(@"插入成功");
Method old_method = class_getInstanceMethod(objc_getClass("WCAccountLoginControlLogic"), sel_registerName("onFirstViewLogin"));
BOOL result = class_addMethod(objc_getClass("WCAccountLoginControlLogic"),
sel_registerName("new_method"), (IMP)new_method, "v@:");//添加新的方法
NSLog(@"%@",result?@"添加成功":@"添加失敗");
method_exchangeImplementations(old_method, class_getInstanceMethod(objc_getClass("WCAccountLoginControlLogic"),sel_registerName("new_method")));
}
void new_method(id self, SEL _cmd){
NSLog(@"我來了");
[self performSelector:sel_registerName("new_method")];
}
複製代碼
imp
;imp
實現中經過performSelector
來調用原有類添加的方法,從而找到原方法對應的實現。class_addMethod(Class _Nullable cls, SEL _Nonnull name, IMP _Nonnull imp,
const char * _Nullable types)
複製代碼
cls:
爲哪一個類添加方法name:
設置方法名稱imp:
設置方法對應的imp
,此處imp
設置在當前類,以便調用types:
定義方法類型+ (void)load {
NSLog(@"插入成功");
old_imp = class_getMethodImplementation(objc_getClass("WCAccountLoginControlLogic"), sel_registerName("onFirstViewLogin"));
method_setImplementation(class_getInstanceMethod(objc_getClass("WCAccountLoginControlLogic"), sel_registerName("onFirstViewLogin")), (IMP)new_method);
}
IMP (*old_imp)(id self,SEL _cmd);
void new_method(id self, SEL _cmd){
NSLog(@"我來了");
old_imp(self,_cmd);
}
複製代碼
class_getMethodImplementation:
獲取原有方法對應的imp
;method_setImplementation:
給原有類的方法設置新的imp
指向;old_imp(self,_cmd):
執行保留原類方法實現繼續執行原有方法內部指令。+ (void)load {
NSLog(@"插入成功");
old_imp = class_getMethodImplementation(objc_getClass("WCAccountLoginControlLogic"), sel_registerName("onFirstViewLogin"));
old_imp = class_getMethodImplementation(objc_getClass("WCAccountLoginControlLogic"), sel_registerName("onFirstViewLogin"));
class_replaceMethod(objc_getClass("WCAccountLoginControlLogic"), sel_registerName("onFirstViewLogin"), (IMP)new_method, "v@:");
}
IMP (*old_imp)(id self,SEL _cmd);
void new_method(id self, SEL _cmd){
NSLog(@"我來了");
old_imp(self,_cmd);
}
複製代碼
以上方法都能完美解決找不到實例方法的問題,點擊登陸,後打印並跳轉到登陸頁面。
注意:方法與實現是兩個不一樣的概念,方法是SEL
(選擇器),實現是IMP
具體的函數。方法(SEL)指向實現(IMP)。
修改微信步數同上,經過替換方法,在微信上傳步數時,監聽方法,替換上傳數據。
首先介紹一個工具Class-dump
:
該方法利用runtime
特性可以提取MachO
文件中的信息,併產生原應用對應的全部頭文件信息,經過這些信息,可以快速定位目標類,目標方法。下載地址:stevenygard.com/projects/cl…
先使用該工具獲取.ipa
中對應的頭文件:
class-dump -H WeChat -o apph
複製代碼
目標WeChat
爲.app
包中的通用二進制文件,導出頭文件到apph
文件夾中。以下:
以上就是WX
的全部頭文件信息,有屬性,有方法,看到上面標註的就是前面經過頁面找到的類即方法。 這裏能夠運行查看微信運動頁面,找到相關的方法或屬性,進行修改。這裏就不運行查看了(懼怕封號😂)。直接定位到修改步數的類:
找到類即屬性名稱,這裏就直接替換原有的方法,直接返回相應的步數就行。代碼以下:
+ (void)load {
NSLog(@"插入成功");
[self modifyWxStep];
}
+(void)modifyWxStep{
//修改微信步數
Class class = objc_getClass("WCDeviceStepObject");
SEL select = sel_registerName("m7StepCount");
Method method = class_getInstanceMethod(class, select);
const char *typeEncoding = method_getTypeEncoding(method);
NSLog(@"typeEncoding:%s",typeEncoding);
class_replaceMethod(class, select, (IMP)my_m7StepCount, typeEncoding);
}
int my_m7StepCount(id self, SEL _cmd){
return 56382;
}
複製代碼
安裝後,中止xcode
運行,再手機上啓動應用,登陸帳號並來到微信運動公衆帳號,查看本身的步數,若是步數沒有修改,殺死應用從新進入便可。以下: