沒有越獄機的不用看了 該開發(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密碼 簽名和打包操作)

可能需要自定義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ù)覽插件的/