iOS逆向學習之六(Theos實戰演練)

Theos

若是要去掉某個界面上的某個UIView,咱們能夠經過Cycript獲取到UIView對應的內存地址,經過執行[#內存地址 removeFromSuperview]命令就能夠去掉UIView,可是這種方式僅僅是去掉了內存中的UIView,下一次再次進入此頁面的時候,又會從新加載UIView。顯然,這不是咱們想要的結果,那麼怎麼永久的去掉UIView呢?這就要使用到了hook,經過hook UIView的指定方法改變成咱們本身寫的方法,而後將咱們本身的代碼注入到App中,就能實現永久去除UIView的效果。php

如何進入hook操做呢?這就要使用到Theos,經過Thoes就能夠建立tweak項目,添加須要hook的類以及方法,而後將tweak項目進行編譯、打包成deb插件,最終安裝到iPhone上。git

簽名工具ldid安裝

  • ldid須要經過brew安裝,若是mac上沒有安裝brew,能夠經過如下命令安裝HomeBrew
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
複製代碼
  • 安裝完brew以後,經過brew安裝ldid
brew install ldid
複製代碼

修改環境變量

Theos官方建議咱們將Theos克隆到~/theos目錄下,並且~/theos路徑以後須要屢次使用,因此將~/theos配置爲環境變量github

  • 首先,進入cd ~進入根目錄,在根目錄下有訪問.bash_profile文件
vim ~/.bash_profile
複製代碼
  • 在.bash_profile文件最後加入下面兩行
export THEOS=~/theos
export PATH=$THEOS/bin:$PATH
複製代碼

此處將~/theos/bin配置進PTAH中,PATH經過:來配置多個路徑,配置好Path以後,在終端輸入某一個指令時,會到PATH裏的全部目錄下去尋找可執行文件。注意:此處的:$PATH必定不能遺漏,不然PATH會被THEOS的目錄覆蓋。vim

  • 配置完成以後,在終端執行source命令,使.bash_profile文件的配置當即生效
source ~/bash_profile
複製代碼
  • 此時咱們經過$PATH來打印出PATH信息,就能夠看到THEOS目錄已經添加到了PATH中

下載Theos

經過如下命令將Theos下載到上面配置的$THEOS目錄中ruby

git clone --recursive https://github.com/theos/theos.git $THEOS
複製代碼

--recursive表示遞歸下載,由於Theos會依賴其它庫,使用此命令能夠遞歸的將全部依賴的庫都下載下來bash

tweak項目

建立tweak項目

  • cd到存放項目的目錄,執行nic.pl指令,選擇序號10,對應iphone/tweak
cd ~/Desktop/tweak
nic.pl
複製代碼

  • 填寫項目所須要的信息
#項目名稱
Project Name
#項目ID,按規則填寫便可
Package Name 
#做者名,直接按回車使用默認名
Author/Maintainer Name 
#須要hook的App的Bundle Identifier,可使用Cycript查看
[iphone/tweak] MobileSubstrate Bundle filter
#直接回車,使用默認配置就能夠
[iphone/tweak] List of applications to terminate upon installation
複製代碼

至此,tweak項目建立完畢微信

tweak項目配置

  • 編輯Makefile文件,須要在Makefile文件中增長如下環境變量,指明經過哪一個IP和端口號訪問手機,因爲以前使用的是USB的方式訪問,因此IP寫本機地址便可
export THEOS_DEVICE_IP=127.0.0.1 #本機IP地址
export THEOS_DEVICE_PORT=10088   #本機端口號

INSTALL_TARGET_PROCESSES = SpringBoard

include $(THEOS)/makefiles/common.mk

TWEAK_NAME = test_tweak

test_tweak_FILES = Tweak.x
test_tweak_CFLAGS = -fobjc-arc

include $(THEOS_MAKE_PATH)/tweak.mk

複製代碼
  • 上述方式配置的環境變量只能在當前的tweak項目中生效,之後若是有新的tweak項目,就須要從新配置。若是不但願每一個項目都要從新編寫IP和端口號的環境變量,能夠將這兩個變量配置到.bash_profile中
export THEOS=~/theos
export PATH=$THEOS/bin:$PATH
export THEOS_DEVICE_IP=127.0.0.1
export THEOS_DEVICE_PORT=10088
複製代碼

配置完成後,使用source讓配置生效app

source ~/.bash_profile
複製代碼

tweak項目編寫代碼

代碼編寫

tweak項目的攔截代碼編寫在Tweak.x文件中,代碼以下curl

%hook ClassName

// Hooking a class method
+ (id)sharedInstance {
	return %orig;
}

// Hooking an instance method with an argument.
- (void)messageName:(int)argument {
	%log; // Write a message about this call, including its class, name and arguments, to the system log.

	%orig; // Call through to the original function with its original arguments.
	%orig(nil); // Call through to the original function with a custom argument.

	// If you use %orig(), you MUST supply all arguments (except for self and _cmd, the automatically generated ones.)
}

// Hooking an instance method with no arguments.
- (id)noArguments {
	%log;
	id awesome = %orig;
	[awesome doSomethingElse];

	return awesome;
}

%end
複製代碼

語法簡介

  • tweak使用的Logos語法簡介,能夠點擊Logos官網查看完整的語法介紹。
%hook、%end :#表示hook一個類的開始和結束

%log#打印方法調用詳情,能夠經過Xcode -> Window -> Devices and Simulators

HBDebugLog : #和NSLog相似

%new :#添加一個新的方法

%c(className) : #生成一個Class對象,好比%c(NSObject),相似於NSStringFromClass()、objc_getClass()

%orig :#調用原先的方法邏輯

%ctor :#加載動態庫的時候調用

%dtor :#在程序退出時調用
複製代碼
  • logify.pl

此工具能夠將一個頭文件快速轉換成已經包含打印信息的x文件,這能夠爲咱們節省不少事,好比咱們要監聽一個頁面全部方法的調用,使用此工具就能自動將全部的OC方法轉換成Logos方法,而且在方法中爲咱們加上對應的log方法和返回值。具體轉換指令以下:iphone

logify.pl xx.h > xx.xm
複製代碼

可是使用這種自動轉換的方法轉換以後的代碼在編譯時會遇到不少問題。解決方法以下

  • 刪除__weak
  • 刪除inout
  • 刪除掉協議,或者使用@protocol XXTestDelegate聲明一下協議
  • 刪除掉- (void).cxx_destruct { %log; %orig; }方法
  • 刪除HBLogDebug(@" = 0x%x", (unsigned int)r)
  • 替換類名爲void,例如將XLPerson * 替換成void *,獲取在頭部聲明一下類名@class Person
  • 資源文件

若是有額外的資源文件,例如圖片等等,放在項目的layout文件夾中,對應手機的根目錄 /,一般開發中能夠將圖片存放在如下目錄中/Library/PreferenceLoader/preferences//Library/Caches下,具體的作法是在tweak項目的layout文件夾中依次建立LibraryCaches目錄,將圖片存放到此目錄下。加載圖片的時候使用全路徑便可

編譯->打包->安裝

#對項目進行編譯
make

#打包成deb文件
make package

#安裝,安裝過程當中會默認重啓SpringBoard
make install

#以上命令也可寫成以下格式
make && make package && make install

複製代碼

若是以前已經編譯過,須要再次從新編譯的話,執行make clean便可

去除hook程序

  • 若是咱們不想再hook別人的程序了,能夠經過iFunBox,在~/Library/MobileSubstrate/DynamicLibraries/目錄下找到咱們的deb插件生成的.dylib和.plist文件,通常是以咱們的tweak項目名命名的。刪除這兩個文件,而後重啓SpringBoard就能夠去除咱們的hook插件。

  • 第二種方式是經過Cydia來卸載,打開Cydia,在已安裝插件中找到咱們剛剛安裝好的插件,點擊卸載,完成以後重啓SpringBoard便可

tweak執行原理

  • 首先,當咱們建立好tweak項目,而且編寫好hook代碼後,執行make操做,在tweak項目目錄下會生成一個隱藏的文件夾.theos,在.theos/obj/debug/目錄下會生成動態庫.dylib文件
  • 執行make package時,項目目錄下的plist文件和第一步生成的.dylib文件打包成對應的deb文件,存放在packages目錄下
  • 執行make install時,首先會根據以前配置的THEOS_DEVICE_IPTHEOS_DEVICE_PORT兩個變量去遠程鏈接iPhone,而後經過iPhone上的Cydia來安裝對應的deb插件
  • 在App啓動以後,會同時將dylib加載到內存中,App中若是訪問被咱們hook的類中的方法,會直接執行dylib中的方法。

make package默認是debug模式,若是要發佈release版本的包,執行make package debug=0便可

tweak多文件開發

在tweak項目開發中,若是咱們須要Hook的方法過多,全部的hook方法都寫在同一個類裏,明顯不是一種好的方式。這個時候就須要多文件開發。tweak支持多文件開發

  • 首先在項目目錄下增長src文件夾,而後將Tweak.x文件移到src目錄下,這個時候執行make指令會提示
==> Error: File Tweak.x does not exist.
make[1]: *** [before-test_wechat-all] Error 1
make: *** [test_wechat.all.tweak.variables] Error 2
複製代碼
  • tweak在編譯時,會到Makefile中尋找可編譯的文件路徑,由於咱們改變的Tweak.x的路徑,相應的就要修改Makefile文件下的test_wechat_FILES,以下
INSTALL_TARGET_PROCESSES = SpringBoard

include $(THEOS)/makefiles/common.mk

TWEAK_NAME = test_wechat

test_wechat_FILES = src/Tweak.x
test_wechat_CFLAGS = -fobjc-arc

include $(THEOS_MAKE_PATH)/tweak.mk
複製代碼
  • tweak支持OC類,想tweak項目中的src目錄下導入Person類,在Tweak.x中#import "Person.h",而後執行make編譯,會出現如下錯誤
ndefined symbols for architecture armv7:
  "_OBJC_CLASS_$_Person", referenced from:
      objc-class-ref in Tweak.x.01c0bdf0.o
ld: symbol(s) not found for architecture armv7
複製代碼
  • 修改Makefile中的test_wechat_FILES,增長Person.m的路徑
INSTALL_TARGET_PROCESSES = SpringBoard

include $(THEOS)/makefiles/common.mk

TWEAK_NAME = test_wechat

test_wechat_FILES = src/Tweak.x src/*.m
test_wechat_CFLAGS = -fobjc-arc

include $(THEOS_MAKE_PATH)/tweak.mk
複製代碼

注意兩個路徑之間須要用空格分隔,Tweak支持通配符,可使用*.m指定目錄下的全部.m文件

實戰1、去掉喜馬拉雅音頻播放界面的廣告

  1. 若是iPhone上的喜馬拉雅App被加密的話,首先須要經過Clutch或者dumpdecrypted工具進行解密。獲得解密後的可執行文件。
DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib /var/mobile/Containers/Bundle/Application/14C4F899-BD7B-41A4-BC1A-61892E7B943B/ting.app/ting
複製代碼
  1. 使用class-dump導出喜馬拉雅可執行文件中全部頭文件備用
class-dump -H ~/Desktop/ting -o Headers
複製代碼
  1. 使用Cycript獲取喜馬拉雅App的bundle Identifier,後續建立tweak項目時須要用到
cy# [NSBundle mainBundle].bundleIdentifier
@"com.gemd.iting"
cy#
複製代碼
  1. 使用Reveal定位到廣告視圖的具體位置

  1. 獲取到廣告頁面的名稱爲XMSoundPatchImageView和XMAdAnimationViewThree,查看頭文件,找到XMSoundPatchImageView.h和XMAdAnimationViewThree.h,如下爲部分代碼
@interface XMSoundPatchImageView : UIView <CAAnimationDelegate, XMSoundPatchImageViewProtocol>
- (void)adImageShadowCreateIfNeeded;
- (void)defaultAnimationShowImage:(_Bool)arg1 withAnimation:(_Bool)arg2 andReoportAdShow:(_Bool)arg3 andReportOnce:(_Bool)arg4;
- (void)showImage:(_Bool)arg1 withAnimation:(_Bool)arg2 andReoportAdShow:(_Bool)arg3 andReportOnce:(_Bool)arg4;
- (void)showImage:(_Bool)arg1 withAnimation:(_Bool)arg2 andReoportAdShow:(_Bool)arg3;
- (void)initUI;
- (void)cleanWithAnimation:(_Bool)arg1;
- (void)clean;
- (void)dealloc;
- (id)initWithFrame:(struct CGRect)arg1;

@end
複製代碼

XMAdAnimationViewThree的初始化方法和XMSoundPatchImageView方法相同,喜馬拉雅App存在多種廣告View,這裏只列舉了其中兩種。

能夠看到整個View是經過initWithFrame方法進行初始化的。 6. 建立tweak項目,在Tweak.x中編寫攔截代碼,攔截XMSoundPatchImageView的initWithFrame方法,返回nil

%hook XMSoundPatchImageView

- (id)initWithFrame:(struct CGRect)arg1{
	return nil;
}

%end

%hook XMAdAnimationViewThree

- (id)initWithFrame:(struct CGRect)arg1{
	return nil;
}

%end

複製代碼
  1. 編譯,打包以及安裝
make && make package && make install
複製代碼
  1. 執行以上命令以後,iPhone桌面會重啓,再次打開喜馬拉雅App,點擊進入播放界面,就會發現不會再彈出廣告。至此,去除廣告的功能就完成了。

實戰2、去掉iPhone桌面上全部角標提示

其實iPhone的桌面也是一個應用,叫作SpringBoard。那麼怎麼驗證它是一個應用呢?經過Cycript指令

ps -A | grep SpringBpard
複製代碼
508SC:~ root# ps -A | grep SpringBoard
 1365 ??         0:26.56 /System/Library/CoreServices/SpringBoard.app/SpringBoard
 1425 ttys000    0:00.01 grep SpringBoard
508SC:~ root#
複製代碼

經過以上結果咱們能夠看出,SpringBoard其實就是一個App,安裝路徑爲/System/Library/CoreServices/,既然知道SpringBoard是本質是一個App,那麼,咱們就能夠爲SpringBoard建立一個tweak應用

  1. 首先,經過iFunBox,找到iPhone的/System/Library/CoreServices/目錄下的可執行文件SpringBoard,拖拽到Mac上
  2. 經過otool或者MachOView查看Mach-O文件是否被加密,結果發現SpringBoard可執行文件中,Load Commands中並無LC_ENCRYPTION_INFO,這也就說明SpringBoard沒有被加密。
  3. 經過class-dump導出SpringBoard全部頭文件備用
  4. 獲取微信的BundleIdentifier爲com.tencent.xin
  5. 由於Reveal只能調試安裝在SpringBoard上的應用,不能調試SpringBoard自己,因此想要查詢SpringBoard的UI界面,就要使用Cycript指令。
  6. 首先鏈接iPhone,經過Cycript監聽SpringBoard,找到SpringBoard主界面,經過主界面的內存地址打印出主界面的subViews
508SC:~ root# cycript -p SpringBoard
cy# MJRootVc ()
#"<SBHomeScreenViewController: 0x1308cc8d0>"
cy# MJSubviews (#0x1308cc8d0)
`<SBHomeScreenView: 0x1308c0aa0; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x1308d6ac0>>
   | <SBIconContentView: 0x1309f6150; frame = (0 0; 320 568); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x1309a3940>>
   |    | <SBRootFolderView: 0x130b68910; frame = (0 0; 320 568); layer = <CALayer: 0x130b6b230>>
   |    |    | <SBSearchBlurEffectView: 0x131d885c0; variant: static wallpaper; style: LightTintedBlur; frame = (0 0; 320 568); clipsToBounds = YES; alpha = 0; layer = <CALayer: 0x131b94ac0>>
   |    |    |    | <_SBFakeBlurView: 0x1330823c0; style: LightTintedBlur; frame = (0 0; 320 568); animations = { AlignFakeWallpaperToLayer-0x1308d4dc0=<CAMatchMoveAnimation: 0x1333904e0>; }; layer = <CALayer: 0x131a6d300>>
   
   ......
複製代碼
  1. 經過分析主界面的全部subViews,能夠找到SBIconView,經過拿到SBIconView的內存地址,經過設置hidden,最終肯定界面上每一個App圖標都是一個SBIconView。
cy# #0x130ec4ff0.hidden = 1
1
cy# #0x130ec4ff0.hidden = 0
0
cy#
複製代碼
  1. 經過查看SBIconView的subViews能夠肯定SBIconParallaxBadgeView就是咱們要找的角標View
  2. 查看SpringBoard全部頭文件,找到SBIconParallaxBadgeView.h文件以下
#import "SBIconBadgeView.h"

#import "_UISettingsKeyObserver.h"

@class NSString, SBFParallaxSettings;

@interface SBIconParallaxBadgeView : SBIconBadgeView <_UISettingsKeyObserver>
{
    SBFParallaxSettings *_parallaxSettings;
}

- (void)_applyParallaxSettings;
- (void)settings:(id)arg1 changedValueForKey:(id)arg2;
- (void)dealloc;
- (id)init;

// Remaining properties
@property(readonly, copy) NSString *debugDescription;
@property(readonly, copy) NSString *description;
@property(readonly) unsigned long long hash;
@property(readonly) Class superclass;

@end
複製代碼
  1. 建立tweak項目,在Tweak.x編寫攔截代碼,攔截SBIconParallaxBadgeView的init方法,返回nil
%hook SBIconParallaxBadgeView

- (id)init{
	return nil;
}

%end
複製代碼
  1. 編譯,打包以及安裝,等待SpringBoard重啓以後,就能夠看到整個桌面上的全部App,都沒有角標了。
make && make package && make install
複製代碼

實戰3、給微信的「發現界面」增長自動搶紅包、退出微信兩個功能,僅改變UI,不實現具體功能

  1. 首先經過ps -A指令找到微信的可執行文件路徑
/var/mobile/Containers/Bundle/Application/048B71C8-42E4-4EE0-8E50-EF262251DE17/WeChat.app/WeChat
複製代碼
  1. 使用Clutch或者dumpdecrypted工具進行解密。獲得解密後的可執行文件。若是已解密,則忽略此步驟

優先選擇dumpdecrypted工具,解密速度快,不易出錯

DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib /var/mobile/Containers/Bundle/Application/048B71C8-42E4-4EE0-8E50-EF262251DE17/WeChat.app/WeChat
複製代碼
  1. /var/root目錄下找到解密後的可執行文件,使用class-dump導出全部頭文件備用
class-dump -H ~/Desktop/WeChat -o Headers
複製代碼
  1. 使用Cycript獲取微信App的bundle Identifier,後續建立tweak項目時須要用到
cy# [NSBundle mainBundle].bundleIdentifier
@"com.tencent.xin"
cy#
複製代碼
  1. 經過Reveal分析微信UI界面,能夠得出微信的發現頁面是一個UITableView,類名爲MMMainTableView,咱們想要在UITableView上增長cell,必需要知道MMMainTableView的dataSource。經過Cycript能夠獲得MMMainTableView的dataSource就是FindFriendEntryViewController
cy# #0x13d20ae00.dataSource
#"delegate[0x13dadaa00], class[FindFriendEntryViewController]"
cy#
複製代碼
  1. 查找微信的頭文件,在FindFriendEntryViewController中找到咱們須要hook的幾個方法,以下
- (void)tableView:(id)arg1 didSelectRowAtIndexPath:(id)arg2;
- (id)tableView:(id)arg1 cellForRowAtIndexPath:(id)arg2;
- (double)tableView:(id)arg1 heightForRowAtIndexPath:(id)arg2;
- (long long)tableView:(id)arg1 numberOfRowsInSection:(long long)arg2;
- (long long)numberOfSectionsInTableView:(id)arg1;
複製代碼
  1. 建立tweak項目,在Tweak.x中編寫如下hook代碼
#define XLUserDefault [NSUserDefaults standardUserDefaults]
#define XLAutoSwitchKey @"xl_auto_switch_key"
#define XLFile(path) @"/Library/PreferenceLoader/Preferences/XLWeChat/" #path

/* 對FindFriendEntryViewController及numberOfSectionsInTableView方法作前向聲明。
 * 不然沒法調用[self numberOfSectionsInTableView:]方法
 */
@interface FindFriendEntryViewController

- (long long)numberOfSectionsInTableView:(id)tableView;

@end

%hook FindFriendEntryViewController

//當前tableView有幾組
- (long long)numberOfSectionsInTableView:(id)tableView
{	
	//調用微信原始的numberOfSectionsInTableView方法,獲取原始section,在此基礎上+1
	return %orig + 1;
}

//當前tableView每組對應多少row
- (long long)tableView:(id)tableView numberOfRowsInSection:(long long)section
{
	if (section == [self numberOfSectionsInTableView:tableView] - 1){
		return 2;
	}

	return %orig;
}

//返回每一個row對應的cell
- (id)tableView:(id)tableView cellForRowAtIndexPath:(id)indexPath
{
	//判斷是不是最後一組
	if ([indexPath section] == [self numberOfSectionsInTableView:tableView] - 1){
		NSString *cellId = [indexPath row] == 0 ? @"autoCellId" : @"exitCellId";
		UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
		if (!cell){
			cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault 
										  reuseIdentifier:cellId];
			cell.backgroundColor = [UIColor whiteColor];
			//設置圖片
			cell.imageView.image = [UIImage imageWithContentsOfFile:XLFile(icon.png)];
		}
		if ([indexPath row] == 0) {
	        cell.textLabel.text = @"自動搶紅包";
	        
	        UISwitch *switchView = [[UISwitch alloc] init];
	        switchView.on = [XLUserDefault boolForKey:XLAutoSwitchKey];
	        [switchView addTarget:self 
	        			   action:@selector(xl_switchChange:) 
	        	 forControlEvents:UIControlEventValueChanged];
	        cell.accessoryView = switchView;

	    }else if ([indexPath row] == 1){
	        cell.textLabel.text = @"退出微信";
	    }
	    return cell;
	}

	return %orig;
}

/* 
 * 特別注意:在%hook和%end內部所寫的方法,默認是覆蓋當前hook的類中的方法,若是在原類中沒有此方法,會崩潰
 * 		   若是想要在原類中增長新的方法,須要在方法前增長 %new 標識
 */
%new
- (void)xl_switchChange:(UISwitch *)switchView{
    [XLUserDefault setBool:switchView.isOn forKey:XLAutoSwitchKey];
    [XLUserDefault synchronize];
}


//cell的高度
- (double)tableView:(id)tableView heightForRowAtIndexPath:(id)indexPath
{
	//此處判斷當前是不是咱們新加的一組,若是是,返回cell的高度爲44
	if ([indexPath section] == [self numberOfSectionsInTableView:tableView] - 1)
	{
		return 44;
	}
	//若是不是最後一組,返回微信本身定義的高度
	return %orig;
}

//cell點擊事件
- (void)tableView:(id)tableView didSelectRowAtIndexPath:(id)indexPath
{
	if ([indexPath section] == [self numberOfSectionsInTableView:tableView] - 1){
		if ([indexPath row] == 0){
			[tableView deselectRowAtIndexPath:indexPath animated:YES];
		}else if([indexPath row] == 1){
			//調用此函數,直接退出App
			abort();
		}
		
	}else{
		%orig;
	}
}

%end
複製代碼

注意:

  • 在Theos中,使用%orig來調用原先的方法邏輯。因此咱們在編寫hook代碼時,會在原來方法的基礎上進行編寫。
  • %hook%end內部所寫的方法,默認是覆蓋當前hook的類中的方法,若是在原類中沒有此方法,會崩潰。若是想要在原類中增長新的方法,須要在方法前增長 %new 標識
  • 在宏定義中,#path表明在path先後拼接上"",獲得"path",使用以下調用方式XLFile(icon.png)便可
  • 在make編譯時可能會出現如下錯誤,緣由是self在此處會被認爲是id類型,而numberOfSectionsInTableView方法屬於FindFriendEntryViewController的方法,若是不對FindFriendEntryViewController進行前向聲明,是沒法調用numberOfSectionsInTableView的。具體前向聲明代碼如上
Tweak.x:37:30: error: receiver type 'FindFriendEntryViewController' for instance
      message is a forward declaration
        if ([indexPath section] == [self numberOfSectionsInTableView:tab...
                                    ^~~~
Tweak.x:34:8: note: forward declaration of class here
@class FindFriendEntryViewController;
複製代碼
  1. tweak項目中資源文件如何配置?
  • 首先須要在咱們的tweak項目下建立一個layout文件夾。layout目錄對應iPhone上的根目錄,若是咱們將圖片存放在layout目錄下,那麼打包tweak項目時,會將圖片存放到iPhone的根目錄下。
  • 一般咱們開發插件的資源文件都存放在iPhone的/Library/PreferenceLoader/Preferences/目錄下,因此咱們須要在layout目錄中依次建立Library、PreferenceLoader、Preferences目錄,爲防止資源重複,在Preferences目錄下再建立一個XLWeChat目錄,將咱們的資源文件存放在此目錄。
  • 在OC中咱們通常經過[UIImage imageNamed:]方法加載圖片,可是在tweak項目中,須要使用[UIImage imageWithContentsOfFile:]方法加載圖片,傳入圖片的全路徑,以下
[UIImage imageWithContentsOfFile:@"/Library/PreferenceLoader/Preferences/XLWeChat/icon.png"]
複製代碼
  1. 最後經過編譯、打包、安裝,等待SpringBoard重啓,打開微信就能夠看到在發現頁面增長了兩個功能,以下:

實戰4、去除騰訊視頻客戶端視頻播放時的廣告

  • 獲取騰訊視頻App的Bundle Identifier爲***com.tencent.live4iphone***
  • 獲取騰訊視頻客戶端的可執行文件路徑,經過dumpdecrypted工具進行脫殼
  • 找到脫殼的可執行文件,使用class-dump導出全部頭文件
  • 經過Reveal找到播放視頻時的廣告View爲***QNBPlayerVideoAdsView***,它所對應的UIViewController爲***QNBPlayerVideoAdsViewController***
  • 查找頭文件,找到***QNBPlayerVideoAdsViewController.h***,在新版本的騰訊視頻的可執行文件中,可能找不到***QNBPlayerVideoAdsViewController***對應的頭文件,我這邊用的是舊版本的ipa安裝包。
  • 找到***QNBPlayerVideoAdsViewController.h***裏的初始化方法
- (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withPageViewController:(id)arg4 withAddToParenViewControllerNow:(_Bool)arg5
- (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withParentEventViewController:(id)arg4 withAddToParenViewControllerNow:(_Bool)arg5
- (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withAddToParenViewControllerNow:(_Bool)arg4
- (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withParentEventViewController:(id)arg4
- (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3
複製代碼
  • 建立tweak項目,編寫tweak代碼,替換***QNBPlayerVideoAdsViewController.h***的全部初始化方法,返回nil
  • 執行編譯安裝後發現仍是存在廣告,繼續使用Reveal進行查看,找到***QNBPlayerImageAdsViewController***和***TADVideoAdController***,繼續hook這兩個類的初始化方法,最後發現廣告沒有了,完整的hook代碼以下
%hook QNBPlayerVideoAdsViewController

- (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withPageViewController:(id)arg4 withAddToParenViewControllerNow:(_Bool)arg5{
    return nil;
}
- (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withParentEventViewController:(id)arg4 withAddToParenViewControllerNow:(_Bool)arg5{
    return nil;
}
- (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withAddToParenViewControllerNow:(_Bool)arg4{
    return nil;
}
- (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withParentEventViewController:(id)arg4{
    return nil;
}
- (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3{
    return nil;
}
%end

%hook QNBPlayerImageAdsViewController

- (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withPageViewController:(id)arg4 withAddToParenViewControllerNow:(_Bool)arg5{
    return nil;
}
- (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withParentEventViewController:(id)arg4 withAddToParenViewControllerNow:(_Bool)arg5{
    return nil;
}
- (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withAddToParenViewControllerNow:(_Bool)arg4{
    return nil;
}
- (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3 withParentEventViewController:(id)arg4{
    return nil;
}
- (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 withParentViewController:(id)arg3{
    return nil;
}
%end

%hook TADVideoAdController
- (id)init{
    return nil;
}
%end
複製代碼

因爲我這裏用的是老版的騰訊視頻ipa,因此能夠成功去除廣告,新版的騰訊視頻改變了廣告的邏輯,因此沒法對新版的騰訊視頻進行去廣告的操做。

相關文章
相關標籤/搜索