- 一、iOS逆向--加密算法
- 二、iOS逆向--通过Xcode安装ipa包
- 三、iOS逆向 - 脚本自动重签名ipa和代码注入
- 四、iOS逆向--方法交换的几种方式以及破坏微信注册
- 五、iOS逆向--MachoO文件
- 六、iOS逆向--dyld加载过程
- 七、iOS逆向-- fishhook原理分析
- 八、iOS逆向--fishHook源码分析
- 九、iOS逆向--LLDB调试
- 十、iOS逆向--chisel、LLDB、Cycript、MonkeyDev
- 十一、iOS逆向--Logos语法学习
对页面进行针对性的调试
由于公司自己的项目页面不够复杂,所以我们拿到优酷砸完壳的ipa,拖到我们新创建的monkey工程里面,我们要实现将优酷的设置页面的tableView增加两项功能
然后运行,跳转到设置页面
我们可以打开debugView来拿到当前tabelView的内存地址,但是在控制台里面没法输出tableView的dataSource值,只能打开我们的cycript动态调试,登录进去,用指令打印出tableView的dataSource:
我们发现tableView的dataSource是SettingViewController,我们就去这个类里面去看看它的属性。
首先从ipa里面拿到可执行文件,然后用class-dump命令拿到所有头文件
class-dump -H Youkui4Phone -o ./headers/
再打开subLime工具,找到这个类
我们发现这个类里面有个tableView和一个_datasource,我们猜测这个就是数据源,我们通过Cycript来看一下这个数据源
我们发现是一个数组,数组里元素个数跟页面的分区个数相同,,并且元素是一个字典,字典里面有每行的数据,数据类型是SettingModel,我们再找一下SettingModel类,看看结构
我们看到两个关键属性就是title和subTitle,我们可以先试着hook代理类SettingViewController,给数据源添加数据,并且我们也看到它实现了tableView的代理方法
我们先给他增加一个区,所以只需要hook它的numberOfSectionsInTableView方法就行了,不过我们要获取到数据源datasource,如果直接通过self。datasource是获取不到的,这时候就需要Logos的函数MSHookIvar()
// See http://iphonedevwiki.net/index.php/Logos
#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)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
运行后,
跟之前的对比:
我们发现最后一个分区,已经被我们改过来了
注意点
- 1、在Logos里面是不能使用项目中自定义的类创建对象,只能通过运行时形式调用,因为Logos是通过framework形式进行注入的,而framework加载比类加载的快,所以在framework里面是无法调用到类的,所以在framework里面只能调用动态库或者静态库里面的类
- 2、在Logos里面调用类的属性时候需要在xm文件里通过@interface声明一下
- 3、在修改页面时候,可能一个页面在多个地方使用,这个时候就需要进行判断