因爲最近微信大佬發飆,罰了紅包外掛5000萬大洋,這就讓人很慌了,別說罰我5000萬,5000塊我都吃不消。因此筆者決定之後不用微信作例子了。換成優酷了😈。php
本文會對優酷的設置頁面增長一個開啓/關閉屏蔽廣告的Cell(僅UI)。效果可見下文配圖。git
在以前的幾篇文章裏已經介紹了APP重簽名,代碼注入,Hook原理,能夠發現,將工程建好,腳本寫好,咱們就能夠以代價很是小的方式對一個第三方的APP進行分析。 那麼是否一種工具,能夠將重簽名,代碼注入,Hook源代碼,class-dump,Cydia Substrate,甚至是恢復符號表這些功能,集成在一個工程裏面,讓真正的逆向小白也能享受逆向的樂趣呢?
答案是確定的,Monkey
就是這樣的一個非越獄插件開發集成神器!github
老規矩,片頭先上福利:點擊下載demo。 這篇文章會用到的工具備:xcode
什麼是Monkey? 原有iOSOpenDev的升級,非越獄插件開發集成神器!bash
可使用Xcode開發CaptainHook Tweak、Logos Tweak 和 Command-line Tool,在越獄機器開發插件,這是原來iOSOpenDev功能的遷移和改進。微信
使用工具前確保以下幾點:架構
sudo git clone --recursive https://github.com/theos/theos.git /opt/theos
複製代碼
brew install ldid
複製代碼
你能夠經過如下命令選擇指定的Xcode進行安裝:app
sudo xcode-select -s /Applications/Xcode-beta.app
複製代碼
默認安裝的Xcode爲:框架
xcode-select -p
複製代碼
執行安裝命令:curl
sudo /bin/sh -c "$(curl -fsSL https://raw.githubusercontent.com/AloneMonkey/MonkeyDev/master/bin/md-install)"
複製代碼
sudo /bin/sh -c "$(curl -fsSL https://raw.githubusercontent.com/AloneMonkey/MonkeyDev/master/bin/md-uninstall)"
複製代碼
若是沒有發佈特殊說明,使用以下命令更新便可:
sudo /bin/sh -c "$(curl -fsSL https://raw.githubusercontent.com/AloneMonkey/MonkeyDev/master/bin/md-update)"
複製代碼
安裝/更新以後重啓下Xcode再新建項目。若是看到以下選項,即表明安裝成功,若是沒有,重複上面步驟再來一遍。
具體使用方法能夠直接查看官網,固然下文也會對其部分的實用用法進行介紹。
Logos是Thoes開發的一套組件,可很是方便用於的Hook OC代碼。
接下來咱們就介紹下Logos的簡單用法,最後運用Monkey和Logos給優酷增長一點UI。
建立工程SimpleAppDemo
,裏面只有一個按鈕,點擊按鈕彈出一個Alert。 點擊下載:SimpleAppDemo 按鈕對應的方法爲:
- (IBAction)tapAction:(id)sender {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"來啦" message:@"老弟😁😁😁" delegate:nil cancelButtonTitle:@"我知道了" otherButtonTitles:nil, nil];
[alert show];
}
複製代碼
對SimpleAppDemo參數的ipa文件進行砸殼,砸殼過程就不在這詳細描述了,這裏有筆者已經砸殼好的ipa:SimpleAppDemo.ipa 提取碼: afnc
取名LogosDemo
,將下面下載好的SimpleAppDemo.ipa
,放到工程對應的目錄下:
配好證書(隨意一個能在手機上運行的證書便可),Run。運行成功~
在上一步建好的Monkey工程中,能夠發如今目錄有一個Logos目錄:
默認有兩個文件LogosDemoDylib.xm
和LogosDemoDylib.mm
。
其中Logos語句就是寫在LogosDemoDylib.xm
中的,LogosDemoDylib.mm
是根據LogosDemoDylib.xm
中的內容自動生成的。
接下來,我們根據幾個需求來介紹Logos的一些經常使用的用法。
UIKit
框架。#import <UIKit/UIKit.h>
複製代碼
因爲我們手上有源碼,因此能夠直接跳過動態分析的這一步,直接就知道按鈕所處的頁面是叫作ViewController
,按鈕的響應方法是:
- (IBAction)tapAction:(id)sender
複製代碼
利用hook
命令:
#import <UIKit/UIKit.h>
// hook + 類名
%hook ViewController
// IBAction == void
- (void)tapAction:(id)sender {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"來什麼來" message:@"😡😡😡" delegate:nil cancelButtonTitle:@"我知道了" otherButtonTitles:nil, nil];
[alert show];
}
%end
複製代碼
運行項目,發現按鈕已經被成功hook了。
#import <UIKit/UIKit.h>
%hook ViewController
- (void)tapAction:(id)sender {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"來什麼來" message:@"😡😡😡" delegate:nil cancelButtonTitle:@"我知道了" otherButtonTitles:nil, nil];
[alert show];
// 調用原方法
%orig;
}
%end
複製代碼
interface
申明每個方法。#import <UIKit/UIKit.h>
// 這裏只是爲了申明
@interface ViewController
- (void)newFunC;
@end
%hook ViewController
// 新增方法關鍵字new
%new
- (void)newFunC{
NSLog(@"newFunC");
}
// IBAction == void
- (void)tapAction:(id)sender {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"來什麼來" message:@"😡😡😡" delegate:nil cancelButtonTitle:@"我知道了" otherButtonTitles:nil, nil];
[alert show];
[self newFunC];
// 調用原方法關鍵字orig
%orig;
}
%end
複製代碼
文中全部的Demo都在這能夠下載到:Dmoe
Logos除了以上hook
,end
,orig
,new
這幾種關鍵字,還有:
%subclass:增長一個類
%log:打印,相似NSLog
%group: 給代碼分組,能夠用於在不一樣環境加載不一樣的代碼,好比iOS8加載group1
,iOS9加載group2
,若是部分中,默認全部代碼在名爲「_ungrouped」的隱藏分組中。
...
全部的Logos語法均可以在官方文檔中查詢獲得。
首先在這裏下載筆者本身砸殼後優酷ipa包(arm64架構的):優酷(砸殼).ipa 提取碼: xtua
一樣的新建一個Monkey工程,取名YouKu,將下載好的ipa包放入工程對應的TargetApp目錄下。Run。一樣是重簽名成功。
在上面的Demo中,咱們是對咱們直接的工程進行HOOK,因爲咱們手上有源碼,因此咱們越過了最難的一個步驟:動態分析。
而咱們如今要對優酷進行Hook,但咱們手上是沒有優酷的源碼的,因此此時此刻就須要對其進行動態分析了。 下面我將結合Xcode和class dump對優酷的設置頁面簡單的進行分析。
class-dump is a command-line utility for examining the Objective-C segment of Mach-O files. It generates declarations for the classes, categories and protocols. This is the same information provided by using 'otool -ov', but presented as normal Objective-C declarations.
簡單說就是一個能夠導出一個MachO文件的全部頭文件信息(包括Extension)
在文首有提到Monkey除了重簽名,還集成了class dump
的功能,因此咱們須要作的就僅僅是開啓這個功能:
Run!成功以後能夠發如今工程目錄下多了一個文件夾Youkui4Phone_Headers
,其中就是優酷的全部的頭文件了。
工程Run成功後,點擊進入設置頁面(不用登陸),以下圖:
咱們如今要作的就是在這個頁面的TableView的最後一行加上Cell,裏面有個Switch,用於打開/關閉屏蔽廣告功能(只是UI,這篇文章不牽扯到屏蔽廣告的具體實現,若是你須要,點個當心心,持續關注我哦😀😀😀)。
利用偉大的Xcode咱們能夠很是清晰的看到,設置頁面的DataSource
和Delegate
都是在SettingViewController
中,
我們就找到Hook的類名:SettingViewController 須要Hook的方法天然就是TableView的那些DataSource
和Delegate
了。
這裏須要額外提到的一點是,在文章開始的時候就說了Monkey已經將Cydia Substrate集成進去了,因此咱們能夠直接使用Cydia Substrate的相關功能了。
在這裏咱們須要拿到這個頁面TableView的對應的變量,咱們就須要使用到Cydia Substrate的功能了。打開上文中獲取到優酷的全部的頭文件,全部SettingViewController
,發現其只有一個TableView變量:_tabview
。
那麼毫無疑問,就是他了!
而獲取它的方法是:
MSHookIvar <UITableView *>(self,"_tabview")
複製代碼
一個reloadData的簡單使用:
[MSHookIvar <UITableView *>(self,"_tabview") reloadData];
複製代碼
其餘的UI代碼在這裏就不一一解釋了,所有代碼以下,固然在Demo中也是有的,其中包括了數據的簡單持久化功能:
#import <UIKit/UIKit.h>
#define FYDefaults [NSUserDefaults standardUserDefaults]
#define FYSwitchUserDefaultsKey @"FYSwitchUserDefaultsKey"
@interface SettingViewController
- (long long)numberOfSectionsInTableView:(id)arg1;
@end
%hook SettingViewController
%new
-(void)switchChangeAction:(UISwitch *)switchView{
[FYDefaults setBool:switchView.isOn forKey:FYSwitchUserDefaultsKey];
[FYDefaults synchronize];
[MSHookIvar <UITableView *>(self,"_tabview") reloadData];
}
//多少組
- (long long)numberOfSectionsInTableView:(id)arg1{
UITableView * tableView = MSHookIvar <UITableView *>(self,"_tabview");
NSLog(@"fy_numberOfSectionsInTableView:");
// 額外增長一個
return %orig+1;
}
//每組多少行
- (long long)tableView:(UITableView *)tableView numberOfRowsInSection:(long long)section{
NSLog(@"fy_numberOfRowsInSection:");
//定位設置界面,而且是最後一個
if(section == [self numberOfSectionsInTableView:tableView]-1){
return 1;
}
else{
return %orig;
}
}
//返回高度
- (double)tableView:
(UITableView *)tableView heightForRowAtIndexPath:(id)indexPath{
NSLog(@"fy_heightForRowAtIndexPath:");
//定位設置界面,而且是最後一個
if([indexPath section] ==[self numberOfSectionsInTableView:tableView]-1){
return 44;
}
else{
return %orig;
}
}
//每個Cell
- (id)tableView:(UITableView *)tableView cellForRowAtIndexPath:(id)indexPath{
NSLog(@"fy_cellForRowAtIndexPath:");
//定位設置界面,而且是最後一組
if([indexPath section] == [self numberOfSectionsInTableView:tableView]-1){
UITableViewCell * cell = nil;
if([indexPath row] == 0){
static NSString *swCell = @"SwCellIdentifier";
cell = [tableView dequeueReusableCellWithIdentifier:swCell];
if(!cell){
cell = [[UITableViewCell alloc] initWithStyle:(UITableViewCellStyleDefault) reuseIdentifier:nil];
}
cell.textLabel.text = @"免廣告";
// 免廣告開關
UISwitch *switchView = [[UISwitch alloc] init];
switchView.on = [FYDefaults boolForKey:FYSwitchUserDefaultsKey];
[switchView addTarget:self action:@selector(switchChangeAction:) forControlEvents:(UIControlEventValueChanged)];
cell.accessoryView = switchView;
cell.imageView.image = [UIImage imageNamed:([FYDefaults boolForKey:FYSwitchUserDefaultsKey] == 1) ? @"unlocked" : @"locked"];
}
cell.backgroundColor = [UIColor whiteColor];
return cell;
}else{
return %orig;
}
}
%end
複製代碼
最後的效果
查看從新編譯後的app文件,能夠發現其中的Framework多了不少東西:
在這片文章中主要介紹了Monkey的一些用法已經Logos的基本語法。而在上一篇其實留了一個小尾巴,就是Cycript,筆者將要在下一篇文章中重點講解Cycript的安裝,基礎用法和高級用法。之因此放在下一篇,是由於Cycript配合Monkey將會有事半功倍的效果。