iOS逆向?qū)崙?zhàn)--027:自動搶紅包UI搭建

使用MokeyDevWeChat進行重簽名并安裝篷角,在設(shè)置頁焊刹,增加自動搶紅包的UI,包含是否啟用自動搶紅包功能的開關(guān)恳蹲,以及搶紅包時的手速設(shè)置

界面分析

使用class-dump導(dǎo)出全部頭文件

./class-dump -H WeChat -o ./header/

使用MokeyDev重簽名wx8.0.2.ipa

真機運行項目虐块,使用Debug Viwe找到設(shè)置頁的控制器名稱

使用Debug Viwe時,如果經(jīng)臣卫伲卡死贺奠,可以先將其暫停/繼續(xù)一次

使用Cycript附加進程

使用pvcs()找到設(shè)置頁的控制器

打印控制器View下的所有視圖,從中找到UITableView错忱,并找到對應(yīng)的數(shù)據(jù)源

打開WCTableViewManager.h文件儡率,找到數(shù)據(jù)源和關(guān)鍵方法

后續(xù)對關(guān)鍵方法進行HOOK

精準(zhǔn)定位注入點

找到影響UITableView展示行數(shù)的數(shù)據(jù)源

WCTableViewManager中的numberOfSectionsInTableView方法進行HOOK挂据,打印數(shù)組總數(shù)和Section數(shù)

#import <UIKit/UIKit.h>

@interface WCTableViewManager : NSObject
@property(retain, nonatomic) NSMutableArray *sections;
@end

%hook WCTableViewManager

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
   NSLog(@"數(shù)據(jù)源:%ld,Sections:%ld", (long)self.sections.count, (long)[tableView numberOfSections]);
   return %orig;
}

%end

真機運行項目儿普,查看HOOK之后的打印結(jié)果

從打印結(jié)果來看崎逃,UITableView的顯示行數(shù)和數(shù)組總數(shù)是一致的。但也打印出其他頁面的內(nèi)容眉孩,證明WCTableViewManager在項目中是通用的个绍。如果想對其HOOK,需要精準(zhǔn)定位在設(shè)置頁浪汪,不能影響其他功能

想要精準(zhǔn)定位巴柿,需要在WCTableViewManager中,對所屬控制器進行判斷

我們要找到WCTableViewManager和控制器的關(guān)聯(lián)

找到WCTableViewManager

#0x280bfe5e0
-------------------------
#"<WCTableViewManager: 0x280bfe5e0>"

找到UITableView吟宦,通過響應(yīng)鏈條,向下找一層

#0x280bfe5e0.tableView.nextResponder
-------------------------
#"<UIView: 0x1157e38f0; frame = (0 0; 414 736); autoresize = W+H; layer = <CALayer: 0x281edca00>>"

通過響應(yīng)鏈條涩维,再向下找一層

#0x280bfe5e0.tableView.nextResponder.nextResponder
-------------------------
#"<NewSettingViewController: 0x116cb8400>"

通過響應(yīng)鏈條殃姓,成功找到NewSettingViewController

修改代碼,增加判斷條件瓦阐,保證HOOK代碼僅在設(shè)置頁有效

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
   
   if([tableView.nextResponder.nextResponder isKindOfClass:%c(NewSettingViewController)]){
       NSLog(@"數(shù)據(jù)源:%ld蜗侈,Sections:%ld", (long)self.sections.count, (long)[tableView numberOfSections]);
   }

   return %orig;
}

真機運行項目,查看HOOK之后的打印結(jié)果

僅在NewSettingViewController中打印結(jié)果

修改界面

確保代碼僅在NewSettingViewController中生效睡蟋,接下來對幾個關(guān)鍵方法進行HOOK踏幻,將界面修改成我們預(yù)期的樣子

增加Section

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
   
   if([tableView.nextResponder.nextResponder isKindOfClass:%c(NewSettingViewController)]){
       return %orig+1;
   }

   return %orig;
}

最后Section下面的Rows,固定為2

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
   
   if([tableView.nextResponder.nextResponder isKindOfClass:%c(NewSettingViewController)] && (section==[self numberOfSectionsInTableView:tableView]-1)){
       return 2;
   }
   
   return %orig;
}

為了編譯通過戳杀,需要在WCTableViewManager中该面,聲明numberOfSectionsInTableView:方法

@interface WCTableViewManager : NSObject <UITextFieldDelegate>
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
@end

自定義Cell的高度,固定為60

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
   
   if([tableView.nextResponder.nextResponder isKindOfClass:%c(NewSettingViewController)] && (indexPath.section==[self numberOfSectionsInTableView:tableView]-1)){
       return 60;
   }
   
   return %orig;
}

自定義Cell信卡,只設(shè)置背景色隔缀,看一下運行后的結(jié)果,確認(rèn)HOOK代碼的有效性

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
   
   if([tableView.nextResponder.nextResponder isKindOfClass:%c(NewSettingViewController)] && (indexPath.section==[self numberOfSectionsInTableView:tableView]-1)){

       NSString *strIdentifier=[NSString stringWithFormat:@"HookCell_%i",(int)indexPath.row];
       UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:strIdentifier];

       if (cell == nil) {
           cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:strIdentifier];
       }

       if(indexPath.row==0){
           cell.backgroundColor=[UIColor redColor];
       }
       else{
           cell.backgroundColor=[UIColor blueColor];
       }

       return cell;
   }
   
   return %orig;
}

真機運行項目傍菇,查看UI效果

修改NewSettingViewController成功猾瘸,在原有界面的下方,增加了自定義Cell

完善界面

確認(rèn)HOOK代碼是有效的丢习,下面完善自定義Cell的界面

將自定義圖標(biāo)牵触,導(dǎo)入WeChat

完善tableView:cellForRowAtIndexPath:方法

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
   
   if([tableView.nextResponder.nextResponder isKindOfClass:%c(NewSettingViewController)] && (indexPath.section==[self numberOfSectionsInTableView:tableView]-1)){

       NSString *strIdentifier=[NSString stringWithFormat:@"HookCell_%i",(int)indexPath.row];
       UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:strIdentifier];
       
       if (cell == nil) {
           cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:strIdentifier];
       }
       
       cell.backgroundColor = [UIColor whiteColor];
       cell.selectionStyle = UITableViewCellSelectionStyleNone;
       
       if(indexPath.row==0){
           BOOL isAutoEnable = NO;
           cell.imageView.image = [UIImage imageNamed:(isAutoEnable ? @"hook_auto_en" : @"hook_auto_dis")];
           cell.textLabel.text = @"自動搶紅包";
           
           UISwitch *switchAuto = [[UISwitch alloc] init];
           [switchAuto addTarget:self action:@selector(hookAutoAction:) forControlEvents:UIControlEventValueChanged];
           switchAuto.on=isAutoEnable;
           cell.accessoryView = switchAuto;
       }
       else{
           
           cell.imageView.image = [UIImage imageNamed:@"hook_wait"];
           cell.textLabel.text = @"等待時間(秒)";
           
           UITextField *txtWait=[[UITextField alloc] initWithFrame:CGRectMake(0, 0, 150, 40)];
           txtWait.borderStyle = UITextBorderStyleRoundedRect;
           txtWait.backgroundColor = [UIColor whiteColor];
           txtWait.keyboardType = UIKeyboardTypeNumberPad;
           txtWait.returnKeyType = UIReturnKeyDone;
           cell.accessoryView = txtWait;
       }

       return cell;
   }
   
   return %orig;
}

增加UISwitch切換時,觸發(fā)的hookAutoAction:方法

%new
-(void)hookAutoAction:(UISwitch *)sender{
   NSLog(@"自動搶紅包:%@", (sender.isOn ? @"啟用" : @"禁用"));
}

真機運行項目咐低,查看UI效果

實現(xiàn)功能

UI搭建完成后揽思,還差最后一步,實現(xiàn)功能

自動搶紅包功能的啟用/禁用標(biāo)識见擦,以及搶紅包時的手速設(shè)置绰更,都要進行本地化保存

增加宏定義

#define HOOKAUTOVALUE @"HookAutoValue"
#define HOOKWAITVALUE @"HookWaitValue"

實現(xiàn)UISwitch切換的邏輯

%new
-(void)hookAutoAction:(UISwitch *)sender{

   [[NSUserDefaults standardUserDefaults] setBool:sender.isOn forKey:HOOKAUTOVALUE];
   [[NSUserDefaults standardUserDefaults] synchronize];
   [MSHookIvar<UITableView *>(self,"_tableView") reloadData];
}

修改tableView:cellForRowAtIndexPath:方法瞧挤,將UI和功能進行關(guān)聯(lián)

BOOL isAutoEnable = [[NSUserDefaults standardUserDefaults] boolForKey:HOOKAUTOVALUE];
cell.imageView.image = [UIImage imageNamed:(isAutoEnable ? @"hook_auto_en" : @"hook_auto_dis")];
cell.textLabel.text = @"自動搶紅包";

UISwitch *switchAuto = [[UISwitch alloc] init];
[switchAuto addTarget:self action:@selector(hookAutoAction:) >forControlEvents:UIControlEventValueChanged];
switchAuto.on=isAutoEnable;
cell.accessoryView = switchAuto;

完成搶紅包時的手速設(shè)置邏輯

添加UITextFieldDelegate

@interface WCTableViewManager : NSObject <UITextFieldDelegate>
@property(retain, nonatomic) NSMutableArray *sections;
@end

增加textField:shouldChangeCharactersInRange:replacementString:方法,文本框內(nèi)輸入\n儡湾,視為輸入完成特恬,自動收起鍵盤

%new
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
   
   if ([string isEqualToString:@"\n"]) {
       [textField resignFirstResponder];
       return NO;
   }
   
   return YES;
}

增加textFieldDidEndEditing:方法,輸入完成徐钠,將文本框內(nèi)存本地化保存

%new
-(void)textFieldDidEndEditing:(UITextField *)textField {
   [[NSUserDefaults standardUserDefaults] setObject:textField.text forKey:HOOKWAITVALUE];
   [[NSUserDefaults standardUserDefaults] synchronize];
}

修改tableView:cellForRowAtIndexPath:方法癌刽,將UI和功能進行關(guān)聯(lián)

cell.imageView.image = [UIImage imageNamed:@"hook_wait"];
cell.textLabel.text = @"等待時間(秒)";

UITextField *txtWait=[[UITextField alloc] initWithFrame:CGRectMake(0, 0, 150, 40)];
txtWait.borderStyle = UITextBorderStyleRoundedRect;
txtWait.backgroundColor = [UIColor whiteColor];
txtWait.keyboardType = UIKeyboardTypeNumberPad;
txtWait.returnKeyType = UIReturnKeyDone;
txtWait.delegate = self;
txtWait.text = [[NSUserDefaults standardUserDefaults] objectForKey:HOOKWAITVALUE];
cell.accessoryView = txtWait;

真機運行項目,查看UI效果

優(yōu)化

整體的界面和功能都已經(jīng)完成尝丐,還有兩個小問題需要優(yōu)化

  • 觸發(fā)文本框显拜,鍵盤彈出,會遮擋底部的功能區(qū)域
  • 設(shè)置頁的列表滑動時爹袁,鍵盤無法自動收起远荠,影響體驗

解決遮擋問題

NewSettingViewController進行HOOK,對鍵盤的通知進行監(jiān)聽和銷毀


%hook NewSettingViewController

- (void)viewDidLoad{
   
   %orig;

   [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
   [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}

- (void)dealloc{
   [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
   [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}

%end

實現(xiàn)鍵盤彈出方法

%new
- (void)keyboardWillShow:(NSNotification *)notification {
   CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
   CGSize viewSize = self.view.frame.size;
   self.view.frame = CGRectMake(0, -keyboardSize.height, viewSize.width, viewSize.height);
}

實現(xiàn)鍵盤收起方法

%new
- (void)keyboardWillHide:(NSNotification *)notification {
   CGSize viewSize = self.view.frame.size;
   self.view.frame = CGRectMake(0, 0, viewSize.width, viewSize.height);
}

解決列表滑動失息,自動收起鍵盤問題

NewSettingViewController進行HOOK譬淳,修改viewDidLoad方法

增加UITableView.keyboardDismissMode屬性的設(shè)置

- (void)viewDidLoad{
   
   %orig;

   [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
   [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
   
   WCTableViewManager *m_tableViewMgr = MSHookIvar<WCTableViewManager *>(self, "m_tableViewMgr");
   [MSHookIvar<UITableView *>(m_tableViewMgr, "_tableView") setKeyboardDismissMode:UIScrollViewKeyboardDismissModeOnDrag];
}

真機運行項目,優(yōu)化后的UI效果

總結(jié)

自動搶紅包UI搭建

  • 使用class-dump盹兢,導(dǎo)出目標(biāo)App的頭文件
  • 使用MokeyDev重簽名并運行App
  • 使用Debug Viwe邻梆,快速定位目標(biāo)控制器
  • 使用Cycript,分析控制器中的視圖绎秒、對象浦妄、數(shù)據(jù)源
  • 在對應(yīng)的頭文件中,找到關(guān)鍵的方法和屬性
  • 需要精準(zhǔn)定位到注入點见芹,不能影響其他功能
  • 可以使用響應(yīng)鏈條剂娄,找到控件與所屬控制器的關(guān)聯(lián)
  • 需要自定義圖標(biāo),直接將圖片導(dǎo)入App包即可
  • 添加的方法玄呛,方法名稱加上自定義前綴宜咒,保證命名唯一
  • HOOK關(guān)鍵方法,完成界面與功能
  • MSHookIvar:獲取對象下的成員變量
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末把鉴,一起剝皮案震驚了整個濱河市故黑,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌庭砍,老刑警劉巖场晶,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異怠缸,居然都是意外死亡诗轻,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門揭北,熙熙樓的掌柜王于貴愁眉苦臉地迎上來扳炬,“玉大人吏颖,你說我怎么就攤上這事『拚粒” “怎么了半醉?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長劝术。 經(jīng)常有香客問我缩多,道長,這世上最難降的妖魔是什么养晋? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任衬吆,我火速辦了婚禮,結(jié)果婚禮上绳泉,老公的妹妹穿的比我還像新娘逊抡。我一直安慰自己,他們只是感情好零酪,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布冒嫡。 她就那樣靜靜地躺著,像睡著了一般蛾娶。 火紅的嫁衣襯著肌膚如雪灯谣。 梳的紋絲不亂的頭發(fā)上潜秋,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天蛔琅,我揣著相機與錄音,去河邊找鬼峻呛。 笑死罗售,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的钩述。 我是一名探鬼主播寨躁,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼牙勘!你這毒婦竟也來了职恳?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤方面,失蹤者是張志新(化名)和其女友劉穎放钦,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體恭金,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡操禀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了横腿。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片颓屑。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡斤寂,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出揪惦,到底是詐尸還是另有隱情遍搞,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布丹擎,位于F島的核電站尾抑,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏蒂培。R本人自食惡果不足惜再愈,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望护戳。 院中可真熱鬧翎冲,春花似錦、人聲如沸媳荒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽钳枕。三九已至缴渊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鱼炒,已是汗流浹背衔沼。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留昔瞧,地道東北人指蚁。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像自晰,于是被迫代替她去往敵國和親凝化。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容