動態庫注入

dylib.png

一、前言
二、注入思路
三、動態庫注入實現
四、分析實現按鈕監聽
五、實戰修改微信步數

一、前言

在文章《應用簽名-腳本簽名》中介紹瞭如何在真機上運行破殼應用(抖音、微信、支付寶等ipa包),來觀察應用視圖的層級結構,方法調用,類名稱等,以便學習參考。應用主要與後臺進行數據交互展示(數據拉取及提交數據),既然能對破殼應用重簽名並在真機上運行,那麼能不能修改應用數據和頁面展示呢,如監聽微信登錄按鈕,修改微信步數,下面就這兩個功能拓展一下思路。

二、注入思路

ipa包中,主要包含了應用簽名、資源文件、Frameworks文件、info.plist配置文件及與ipa包同名的可執行通用文件(這裏包含了具體的業務執行指令)。在《Mach-O》中我們對Mach-O文件有一個初步瞭解,主要有Header、Load commands、Data三部分組成。

Header:包含Mach-O文件的基本信息,字節順序、架構類型、加載指令的數量等;
Load commands:包含區域位置、符號表、動態符號表,加載Mach-O文件時使用這裏的數據確定內存分佈;
Data:數據段segement,包含具體代碼、常量、類、方法等。

如果要向已有應用ipa中加入自己的代碼,必須對Mach-O進行修改重組。根據已有開發經驗有思路兩個:

1、修改功能代碼,向Mach-O中的Data部分增刪改數據段;
2、另一個是添加動態庫,利用runtime對原始代碼進行方法替換,數據、UI的修改。

第一種方案需要分析Mach-O對應的彙編代碼,來修改功能,操作較繁瑣;第二種方案,需要我們向ipa包下的Frameworks中添加寫好的動態庫,並向Load commands添加動態庫加載指令,同時還需要修改Header中對應的基本信息,相對於第一種不用做彙編指令分析了。

以上只是個人的一些思考,這裏就不去研究具體的注入過程,直接使用一個第三方庫來完成動態庫的注入,先完成微信登錄按鈕的監聽,以後再對具體的操作進一步學習研究。

第三方動態庫注入工具:yololib

三、動態庫注入實現

破殼ipa獲取:
1、通過越獄手機獲取破殼應用;
2、通過PP助手獲取越獄應用。

《應用簽名-腳本簽名》中實現了對破殼應用的重簽名,並運行在真機上可供調試。

1、創建新工程
常規創建,工程名InsertCode(工程名隨意):

project.png

2、插入簽名腳本、獲取破殼ipa包,放入app文件中

file.png

3、真機運行,執行要查看的ipa包

選擇證書,在真機上運行,ipa會被安裝至手機上,注意這裏的ipa必須是破殼的,並具有相同架構配置的ipa否則安裝失敗。

4、創建Frameworks文件

framework.png

在動態庫文件下創建Insert類:

create.png

  • 創建動態庫文件,用來做方法替換

runtime中通常會使用+load方法,該方法會在編譯期被調用,因此在應用運行前,對應用內部方法動動手腳。下面先在load方法中插入打印代碼,再向ipa包中插入動態庫,看看是否能夠插入到新包中。

代碼:

@implementation Insert
+ (void)load {
    NSLog(@"插入成功");
}
@end

5、引入注入工具yololib

下載 yololib 並編譯(或直接拿到可執行文件),將可執行文件複製到工程中的tool目錄下,注意給執行權限。

yololib.png

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

完整操作如下:

yololib.png

準備工作完成,運行工程:

insert.png

打印“插入成功”,說明動態庫已成功插入到ipa中,用 MachOView 打開.app中WeChat通用二進制文件,查看新的佈局如下:

MachO.png

Load commands中已經有了動態庫的加載指令,接下來就對原登錄按鈕的點擊方法做替換監聽。

四、分析實現按鈕監聽

替換原登錄方法,需要我們知道對應的方法名稱。怎麼查找?如下:

view.png

  • 通過層級關係立刻定位到了登錄方法信息,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_onFirstViewLoginWCAccountLoginControlLogic的實例調用,因此self指的是WCAccountLoginControlLogic的實例

運行工程,點擊登錄按鈕,如下:

login.png

第一行打印了“我來了”,說明,我們監聽到了按鈕的點擊事件,但後面出現崩潰,此處很好理解,在原控制器中並沒有找到對應的選擇器。回憶之前的方法替換,我們是在對應類的分類中去替換,方法在編譯時會加入到該類的方法列表中,而此處並不是原類的分類。

那麼如何解決呢,這裏有三種方法:

1、給原類添加方法

+ (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")];
}
  1. 添加方法並替換方法的imp
  2. imp實現中通過performSelector來調用原有類添加的方法,從而找到原方法對應的實現。
class_addMethod(Class _Nullable cls, SEL _Nonnull name, IMP _Nonnull imp, 
                const char * _Nullable types) 
  • cls:爲哪個類添加方法
  • name:設置方法名稱
  • imp:設置方法對應的imp,此處imp設置在當前類,以便調用
  • types:定義方法類型

2、設置原方法實現

+ (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);
}
  1. class_getMethodImplementation:獲取原有方法對應的imp
  2. method_setImplementation:給原有類的方法設置新的imp指向;
  3. old_imp(self,_cmd):執行保留原類方法實現繼續執行原有方法內部指令。

3、 替換原方法實現

+ (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);
}
  1. 保留原有方法的實現;
  2. 替換原方法的實現,當觸發按鈕,將調用該函數;
  3. 在新函數中,執行原方法實現。

以上方法都能完美解決找不到實例方法的問題,點擊登錄,後打印並跳轉到登錄頁面。

注意:方法與實現是兩個不同的概念,方法是SEL(選擇器),實現是IMP具體的函數。方法(SEL)指向實現(IMP)。

五、實戰修改微信步數

修改微信步數同上,通過替換方法,在微信上傳步數時,監聽方法,替換上傳數據。

首先介紹一個工具Class-dump:

該方法利用runtime特性能夠提取MachO文件中的信息,併產生原應用對應的所有頭文件信息,通過這些信息,能夠快速定位目標類,目標方法。下載地址:http://stevenygard.com/projects/class-dump

先使用該工具獲取.ipa中對應的頭文件:

class-dump -H WeChat -o apph

目標WeChat.app包中的通用二進制文件,導出頭文件到apph文件夾中。如下:

login.png

以上就是WX的所有頭文件信息,有屬性,有方法,看到上面標註的就是前面通過頁面找到的類即方法。
這裏可以運行查看微信運動頁面,找到相關的方法或屬性,進行修改。這裏就不運行查看了(害怕封號😂)。直接定位到修改步數的類:

modify.png

找到類即屬性名稱,這裏就直接替換原有的方法,直接返回相應的步數就行。代碼如下:

+ (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運行,再手機上啓動應用,登錄賬號並來到微信運動公衆賬號,查看自己的步數,如果步數沒有修改,殺死應用重新進入即可。如下:

step.png

完整工程:https://gitee.com/yahibo/InsertCode.git

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章