Tweak 及動態(tài)庫創(chuàng)建

沒有越獄機的不用看了 該開發(fā)過程基于越獄環(huán)境

Tweak

下載Theos 越獄開發(fā)環(huán)境
1. export THEOS=/opt/theos
2. rm -rf $THEOS
3. sudo git clone --recursive https://github.com/theos/theos.git $THEOS
下載LDID 簽名工具
1 cd <下載ldid的目錄>
2 sudo mv ldid /opt/theos/bin(移動到 /opt/theos/bin 目錄下)
3 sudo chmod 777 /opt/theos/bin/ldid(然后設(shè)置可執(zhí)行權(quán)限)
下載dpkg-deb 打包工具
//注意: 拷貝一個無格式的文件用txt打開將內(nèi)容拷貝并保存為dpkg-deb且不要有格式后綴
//放到 “/opt/theos/bin/“ 目錄下后再給其授予可執(zhí)行權(quán)限。
1 cd <dpkg-deb的目錄>
2 sudo mv dpkg-deb /opt/theos/bin(移動到 /opt/theos/bin 目錄下)
3 sudo chmod 777 /opt/theos/bin/dpkg-deb(然后設(shè)置可執(zhí)行權(quán)限)
創(chuàng)建Tweak

可能用到 Logos語法

1 export THEOS=/opt/theos(聲明臨時變量THEOS)
2 $THEOS/bin/nic.pl (生成一個tweak的模板)
3 選擇11 創(chuàng)建Tweak
4 MyFirstTweakkOO (Project Name (required): 自定義創(chuàng)建的工程名)
5 com.appplee.first(Package Name [com.yourcompany.myfirsttweakkoo]: 自定義創(chuàng)建的工程包名 小寫就行)
6 Pandar (Author/Maintainer Name [UCSAPP]: 作者)
7 可回車默認springboard或者自定義如com.tencent.xin([iphone/tweak] MobileSubstrate Bundle filter [com.apple.springboard]:  tweak要hook的對象,若要對某一個app進行hook,則填入該app的bundleID。 如微信:com.tencent.xin。如果回車則默認是整個系統(tǒng) SpringBoard。后面也可在工程同名的plist文件中Filter的Bundles字段中進行修改)
8 可回車默認springboard或者自定義如com.tencent.xin([iphone/tweak] List of applications to terminate upon installation (space-separated, '-' for none) [SpringBoard]:  tweak或hook完后要重啟應(yīng)用或系統(tǒng)才能生效,默認是SpringBoard即系統(tǒng),若只是對app進行hook則重啟該app即可,填入對應(yīng)的bundleID 如:com.tencent.xin)
9 make package (目錄下會生成packages文件夾 包含.deb格式的包文件)
10 修改Tweak.xm,注入你想要hook的具體代碼。語言規(guī)則參考Logos語法。
11 make package install(安裝到手機:修改Tweak工程目錄中的 Makefile文件 最上面添加一句代表你的越獄機的IP地址 THEOS_DEVICE_IP = 172.00.00.000,執(zhí)行命令后需輸入兩次ssh密碼 簽名和打包操作)
選擇11 Tweak創(chuàng)建

可能需要自定義OC文件 可以直接將相關(guān).h .m放到tweak的工程目錄后,在Tweak.xm中像OC文件一樣正常import自定義的類。但需要將.m文件在MakeFile中聲明即編譯時要包含該自定義文件。

//MakeFile中的XXXX__FILES文件表示要編譯的文件數(shù)組 多個可直接拼接在后面
WeChatRedEnvelop_FILES = Tweak.xm MyDefinedViewController.m
WeChatRedEnvelop_FRAMEWORKS = UIKit

Tweak.xm 示例

1 App啟動后彈框提示 plist里filter的bundle為app的bundleid terminate里也對應(yīng)的是App的Name

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

%hook AppDelegate//需要hook的類名
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions //需要hook的消息名
{   
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Welcome" message:@"WelcomeToMyApp!" delegate:nil cancelButtonTitle:@"Thanks" otherButtonTitles:nil];
    [alert show];
    [alert release];
    return %orig; //執(zhí)行原方法
}

%end//結(jié)束標(biāo)志

2 系統(tǒng)啟動后鎖屏或桌面就彈框提示 plist里filter的bundle為com.apple.springboard terminate里也對應(yīng)的是SpringBoard

%hook SpringBoard//需要hook的類名
-(void)applicationDidFinishLaunching:(id)application //需要hook的消息名
{%orig; //執(zhí)行原方法
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Welcome" message:@"WelcomeBrandon!" delegate:self cancelButtonTitle:@"Thanks" otherButtonTitles:nil];
    [alert show];
    [alert release];
}
%end//結(jié)束標(biāo)志

Dylib創(chuàng)建 和 腳本調(diào)試動態(tài)庫

結(jié)合需求,加入需要hook的是微信消息通知Method,聊天界面ViewController,網(wǎng)頁ViewController。  
利用工具class-dump, Hopper Disassembler很快定位出需要hook的微信代碼,  
-[CMessageMgr AsyncOnAddMsg:MsgWrap:]   
-[BaseMsgContentViewController viewDidLoad]   
-[MMWebViewController viewDidLoad]
(iOSOpenDev,是一個越獄開發(fā)環(huán)境,生成的動態(tài)庫直接就是.dylib文件。)  
Xcode現(xiàn)在支持建立動態(tài)庫工程,但生成的是framework,可以通過修改工程文件show contents后打開里面的    
project.pbxproj 并修改為 productType = "com.apple.product-type.framework"; => productType = "com.apple.product-type.library.dynamic"之后run一下就變成為.dylib ,  
Xcode如果是動態(tài)庫轉(zhuǎn)成靜態(tài)庫只要修改個Mach-O type參數(shù)為static library再run一下就行。

#define CBHookInstanceMethod(classname, ori_sel, new_sel) \
\
{ \
Class class = objc_getClass(#classname); \
Method ori_method = class_getInstanceMethod(class, ori_sel); \
Method new_method = class_getInstanceMethod(class, new_sel); \
method_exchangeImplementations(ori_method, new_method); \
} \
\
static void __attribute__((constructor)) initialize(void) {
    CBHookInstanceMethod(CMessageMgr, @selector(AsyncOnAddMsg:MsgWrap:), @selector(cb_AsyncOnAddMsg:MsgWrap:));
    CBHookInstanceMethod(BaseMsgContentViewController, @selector(viewDidLoad), @selector(cb_msgContentViewControllerViewDidLoad));
    CBHookInstanceMethod(MMWebViewController, @selector(viewDidLoad), @selector(cb_webViewControllerViewDidLoad));
}


- (void)cb_AsyncOnAddMsg:(NSString *)msg MsgWrap:(CMessageWrap *)wrap {
    [self cb_AsyncOnAddMsg:msg MsgWrap:wrap];
    
    [CBNewestMsgManager sharedInstance].username = msg;
    [CBNewestMsgManager sharedInstance].content = wrap.m_nsContent;
    
    [[NSNotificationCenter defaultCenter] postNotificationName:CBWeChatNewMessageNotification object:nil];
}
- (void)cb_msgContentViewControllerViewDidLoad {
    [self cb_msgContentViewControllerViewDidLoad];
    
    UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(self.view.frame.size.width - 40, 74, 40, 40)];
    UIImage *image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"WeChatMsgPreview_safari@2x" ofType:@"png"]];
    [button setImage:image forState:UIControlStateNormal];
    [button addTarget:self action:@selector(backToWebViewController) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];
}
- (void)cb_webViewControllerViewDidLoad {
    [self cb_webViewControllerViewDidLoad];
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(cb_didReceiveNewMessage) name:CBWeChatNewMessageNotification object:nil];
}
- (void)cb_didReceiveNewMessage {
    NSString *username = [CBNewestMsgManager sharedInstance].username;
    NSString *content = [CBNewestMsgManager sharedInstance].content;
    CContactMgr *contactMgr = [[objc_getClass("MMServiceCenter") defaultCenter] getService:[objc_getClass("CContactMgr") class]];
    CContact *contact = [contactMgr getContactByName:username];
    
    dispatch_async(dispatch_get_main_queue(), ^{
        NSString *text = [NSString stringWithFormat:@"  %@: %@  ", contact.m_nsNickName, content];
        [CBMessageHud showHUDInView:self.view text:text target:self action:@selector(backToMsgContentViewController)];
    });
}
- (void)backToWebViewController {
    NSArray *webViewViewControllers = [CBNewestMsgManager sharedInstance].webViewViewControllers;
    if (webViewViewControllers) {
        [[objc_getClass("CAppViewControllerManager") getCurrentNavigationController] setViewControllers:webViewViewControllers animated:YES];
    }
}
- (void)backToMsgContentViewController {
    // 返回聊天界面ViewController前記錄當(dāng)前navigationController的VC堆棧,以便快速返回
    NSArray *webViewViewControllers = [objc_getClass("CAppViewControllerManager") getCurrentNavigationController].viewControllers;
    [CBNewestMsgManager sharedInstance].webViewViewControllers = webViewViewControllers;
    
    // 返回rootViewController
    UINavigationController *navVC = [objc_getClass("CAppViewControllerManager") getCurrentNavigationController];
    [navVC popToRootViewControllerAnimated:NO];
    
    // 進入聊天界面ViewController
    NSString *username = [CBNewestMsgManager sharedInstance].username;
    CContactMgr *contactMgr = [[objc_getClass("MMServiceCenter") defaultCenter] getService:[objc_getClass("CContactMgr") class]];
    CContact *contact = [contactMgr getContactByName:username];
    MMMsgLogicManager *logicMgr = [[objc_getClass("MMServiceCenter") defaultCenter] getService:[objc_getClass("MMMsgLogicManager") class]];
    [logicMgr PushOtherBaseMsgControllerByContact:contact navigationController:navVC animated:YES];
}

之后build生成.dylib動態(tài)庫文件,因為Application編譯后都會在drivedData文件夾里生成一個.app的文件, 于是我們加一個target給這個framework工程,并在buildPhases中添加對該framework的依賴,(并拷貝該framework生成的.dylib文件到WeChat.app目錄下?)。并增加Run Script,以在編譯工程后執(zhí)行自定義腳本方便我們動態(tài)庫調(diào)試,腳本包含修改微信可執(zhí)行文件,重簽名,生成新的app并替換原來的。*****這里有涉及到一個自動創(chuàng)建模板的,會自動包含framework及app的target,創(chuàng)建這個模板后將要hook的app放在工程文件夾中,注意這里的文件名要與上一步中的Target app name一致,并執(zhí)行命令pod install.******

#!/bin/bash
BUNDLEIDENTIFIER=com.tencent.xin
APPLICATIONIDENTIFIER=***.${BUNDLEIDENTIFIER}
WECHATFILEPATH=***/apps/WeChat
LIBNAME=$(find *.dylib)
TEMPDIR=$(mktemp -d)
ORIGINDIR=$(pwd)
# 0.get argv
if [ x$1 != x ]
then
    BUNDLEIDENTIFIER=$1
fi
# 1.unzip ipa
if [ $arch == "arm64" ]
then
unzip -qo ${WECHATFILEPATH}/WeChat-dump-arm64.ipa -d $TEMPDIR
else
unzip -qo ${WECHATFILEPATH}/WeChat-dump-armv7.ipa -d $TEMPDIR
fi
# 2.copy files
cp ${WECHATFILEPATH}/embedded.mobileprovision $TEMPDIR/
cp ${WECHATFILEPATH}/entitlements.plist $TEMPDIR/
cp ${LIBNAME} $TEMPDIR/
# 3.resign
cd $TEMPDIR
plutil -replace application-identifier -string ${APPLICATIONIDENTIFIER} entitlements.plist
plutil -replace CFBundleIdentifier -string ${BUNDLEIDENTIFIER} Payload/WeChat.app/Info.plist
mv ${LIBNAME} Payload/WeChat.app/
insert_dylib --all-yes @executable_path/${LIBNAME} Payload/WeChat.app/WeChat
mv Payload/WeChat.app/WeChat_patched Payload/WeChat.app/WeChat
chmod +x Payload/WeChat.app/WeChat
rm -rf Payload/WeChat.app/_CodeSignature
rm -rf Payload/WeChat.app/PlugIns
rm -rf Payload/WeChat.app/Watch
cp embedded.mobileprovision Payload/WeChat.app/
codesign -fs "iPhone Developer: *** (***)" --no-strict --entitlements=entitlements.plist Payload/WeChat.app/${LIBNAME}
codesign -fs "iPhone Developer: *** (***)" --no-strict --entitlements=entitlements.plist Payload/WeChat.app
# 4.end
mv Payload/WeChat.app ${ORIGINDIR}
rm -rf ${TEMPDIR}

這個主要參考:
https://github.com/AlayshChen/XcodeAppPluginTemplate
http://alayshchen.github.io/2016/02/26/我是如何利用Xcode調(diào)試開發(fā)微信消息預(yù)覽插件的/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容