logos语法

本文介绍了Logos语法,它是CydiaSubstruct框架提供的宏定义,便于开发者进行HOOK操作,分为Block level、Top level、Function level三类。还阐述了常用语法,如%group、%ctor等。最后展示了如何使用Logos语法改变微信cell样式,包括添加cell、本地化数据储存等操作。

1.logos语法简介

1.1logos语法简介

Logos语法其实是CydiaSubstruct框架提供的一组宏定义。便于开发者使用宏进行HOOK操作。语法简单,功能强大且稳定。
logos语法官网

1.2logos语法分类

Logos语法分为三大类:
Block level
这一类型的指令会开辟一个代码块,以%end结束。
%group、%hook、% subclass 、 %end
Top level
这个TopLevel指令不放在BlockLevel中。
%config、%hookf、%ctor、%dtor
Function level
这一块的指令就放在方法中。
%init、%class、 %c、 %orig、%log

2.logos常用语法

2.1HOOK 某个类里面的某个方法

在这里插入图片描述

2.2HOOK 某个类里面的某个方法 为某个类添加新方法

在这里插入图片描述

2.3%group

用来将代码分组。开发中hook代码会很多,这样方便管理Logos代码。
在这里插入图片描述

2.4%ctor(constructor)

构造函数,用于确定加载那个组。和%init结合用

2.5%init

用来初始化某个组。

2.6%log

能够输出日志!! 输出方法调用的详细信息

2.7%orig(original)

这个就是保持原有的方法实现,如果原来的方法有返回值,那么%orig 就有返回值的。

2.8%new

给某个类添加方法,在%hook 和 %end 中使用。

2.9%c

类似getClass函数,获得一个类对象。一般用于调用类方法。

如下是我的示例代码

%group group1
%hook ViewController
- (void)postWithUID:(id)arg1 PWD:(id)arg2
{
    NSLog(@"hook到了,第一组");
}
%end
%end

%group group2
%hook ViewController
- (void)postWithUID:(id)arg1 PWD:(id)arg2
{
    NSLog(@"hook到了,第二组");
}
%end
%end

%ctor{%init(group1)  %init(group2)}

%hook ViewController
%new
-(void)test
{
    NSLog(@"打印test");
}
%new
+(void)calss_test
{
    NSLog(@"打印类test");
}
- (void)postWithUID:(id)arg1 PWD:(id)arg2
{
    %log;
    NSLog(@"hook到了,第一组");
    %orig;
    %orig(@"hank",@"123");
    [self test];
    [%c(ViewController) calss_test];
}
%end

3.logos语法使用,改变微信cell样式

我们monkey完微信的越狱版本后,进入我的设置页面,viewDubug中,如图所示,我们可以看到这个页面中的tableview是一个叫WCtableView的,我们的需求是在这个设置页面中添加2个cell,一个叫抢红包的,一个叫等待时间的,我们需要找到该tableview的datasource,一般你放在controller中,我们找到该MCtableview的上层控制器为NewSettingViewController,我们dump下微信的头文件,在subline中打开,我们找到NewSettingViewController,可以看到代理中没有datasource的数据源代理,如下代码中所示,:
在这里插入图片描述

@interface NewSettingViewController : MMUIViewController <WCAccountSwitchLogicDelegate, WCAccountLogoutLogicDelegate, MMTipsViewControllerDelegate>
{
    MMTableViewInfo *m_tableViewInfo;
    _Bool m_bFromSetting;
    WCAccountSwitchLogic *m_switchLogic;
    WCAccountLogoutLogic *m_logoutLogic;
    MMTipsViewController *m_introView;
    WCTableViewManager *m_tableViewMgr;
}

所以用终端登录cycript,前面我们讲过CyCript的登录了,所以这里我们直接登录cycript,利用cycript的强大功能动态调试微信,我们上面的viewdubug中看到WCTableView的内存地址,#+地址.dataSoucrce,查看dataSource数据源,如下图所示,找到为“WCTableViewManager,我们中subline中查看该文件,有成员变量tableView,也有section,我们看一下tableview的变量,可以看到为WCtableview,刚好验证我们上面提到的tableView的数据源为WCTableViewManager,查看sections也如下,有6个,同时我在手机上的附加登录微信也可以看到有6组的section,在这里插入图片描述
我们看一看到WCTableViewManager中如下cell的代理方法,如下图所示
在这里插入图片描述
我们便是hook这些方法来修改自己定义添加的cell,但是WCTableViewManager可能是一个微信中用到的公共类,这点我们hookcell的代理方法,在方法中nslog,然后变化微信页面,看打印就可以验证,所以为了我们只修改设置界面中的样式我们需要添加限制条件,因为我们在刚才的viewDebug中可以看到tbaleView的上一层是View,view的上一层才是Controller,所以我们用如下的代码判断,

if([tableView.nextResponder.nextResponder isKindOfClass:%c(NewSettingViewController)]){

下面是我们改变微信cell样式的代码:
在这里插入图片描述

//-------------------界面代码
@interface WCTableViewManager
- (long long)numberOfSectionsInTableView:(id)arg1;
@end

%hook WCTableViewManager
%new
- (void)textFieldDidChangeValue:(NSNotification *)notification{
    
    UITextField *sender = (UITextField *)[notification object];
    [HKDefaults setValue:sender.text forKey:HKTIMEKEY];
    [HKDefaults synchronize];
}

%new
-(void)switchChang:(UISwitch *)switchView{
    [HKDefaults setBool:switchView.isOn forKey:HKSWITCHKEY];
    [HKDefaults synchronize];
    [MSHookIvar <UITableView *>(self,"_tableView") reloadData];
}


//监听滚动
- (void)scrollViewWillBeginDragging:(id)arg1{
    %orig;
    //退出编辑
    [MSHookIvar <UITableView *>(self,"_tableView") endEditing:YES];
}

//返回高度
- (double)tableView:(UITableView *)tableView heightForRowAtIndexPath:(id)indexPath{
    //定位设置界面,并且是最后一组
    if([tableView.nextResponder.nextResponder isKindOfClass:%c(NewSettingViewController)]
       &&([indexPath section] == [self numberOfSectionsInTableView:tableView] - 1)){
        return 44;
    }
    return %orig;
}


//返回每一个Cell
- (id)tableView:(UITableView *)tableView cellForRowAtIndexPath:(id)indexPath{
    //定位设置界面,并且是最后一组
    if([tableView.nextResponder.nextResponder isKindOfClass:%c(NewSettingViewController)]
       &&([indexPath section] == [self numberOfSectionsInTableView:tableView] - 1)){
        //创建Cell
        UITableViewCell * cell = [[UITableViewCell alloc] initWithStyle:(UITableViewCellStyleDefault) reuseIdentifier:nil];
        cell.backgroundColor = [UIColor whiteColor];
        
        if([indexPath row] == 0){//设置开关
            cell.textLabel.text = @"自动抢红包";
            UISwitch * switchView = [[UISwitch alloc] init];
            switchView.on = [HKDefaults boolForKey:HKSWITCHKEY];//记录开关状态
            //添加开关监听
            [switchView addTarget:self action:@selector(switchChang:) forControlEvents:(UIControlEventValueChanged)];
            cell.accessoryView = switchView;
            cell.imageView.image =
            [UIImage imageNamed:([HKDefaults boolForKey:HKSWITCHKEY] == 1)?@"unlocked":@"locked"];
        }else if([indexPath row] == 1){//设置时间
            cell.textLabel.text = @"等待的时间(秒)";
            UITextField * textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 100, 40)];
            //监听键盘输入
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textFieldDidChangeValue:) name:UITextFieldTextDidChangeNotification object:textField];
            textField.text = [HKDefaults valueForKey:HKTIMEKEY];
            textField.borderStyle = UITextBorderStyleRoundedRect;
            cell.imageView.image = [UIImage imageNamed:@"clock"];
            cell.accessoryView = textField;
        }
        
        return cell;
    }
    
    return %orig;
}


//每一组多少行
- (long long)tableView:(UITableView *)tableView numberOfRowsInSection:(long long)section{
    //定位设置界面,并且是最后一组
    if([tableView.nextResponder.nextResponder isKindOfClass:%c(NewSettingViewController)]
       &&(section == [self numberOfSectionsInTableView:tableView] - 1)){
        return 2;//添加的这一组才会返回2行!
    }
    
    return %orig;
}


//多少组
- (long long)numberOfSectionsInTableView:(UITableView *)tableView{
    //定义到设置页面
    if([tableView.nextResponder.nextResponder isKindOfClass:%c(NewSettingViewController)]){
        //多搞一组
        return %orig+1;
    }
    return %orig;
}

%end

@interface NewSettingViewController : UIViewController

@end

%hook NewSettingViewController

%new
-(void)keyboardWillShow:(NSNotification*)note{
    UIView * view = self.view;
    CGRect keyBoardRect=[note.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
    view.frame = CGRectMake(0, -keyBoardRect.size.height, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height );
}

%new
-(void)keyboardWillhide:(NSNotification*)note{
    UIView * view = self.view;
    view.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);
    
}


- (void)viewDidLoad{
    //监听键盘弹出和消失
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillhide:) name:UIKeyboardWillHideNotification object:nil];
    %orig;
}
%end

这里我大体说一下代码功能和思路:
如上图我们先从hook到的cell的代理来说起,

先从方法:
1.numberOfSectionsInTableView看,限制条件中加多一个section,
2.numberOfRowsInSection 我们是要在设置中加多2个cell,所以最后一组添加2个cell。
3.cellForRowAtIndexPath中,新建cell,cell的label设置,添加一个switchView开关到cell的accessoryView,由于我们想要退出设置界面再次进入时候能保持上次开关的设置,所以我们做了一些本地化数据储存处理,[indexPath row] == 0),我们用KVO监听了开关的状态变化,并保存本地持久化,代码如下,

这里我们有些这样的宏的设置,

#define HKDefaults [NSUserDefaults standardUserDefaults]
#define HKSWITCHKEY @“HKSWITCHKEY”
#define HKTIMEKEY @“HKTIMEKEY”

这里有一个hook获取属性的方法,如下所示:
在这里插入图片描述
4.本地资源的注入,

cell.imageView.image =
            [UIImage imageNamed:([HKDefaults boolForKey:HKSWITCHKEY] == 1)?@"unlocked":@"locked"];

如代码所示,我们要在app中加入图片,那我们图片要加在什么地方呢?,我们需要加在targetapp文件夹中注入的ipa包中,显示包内容,我们可以看到原来项目中拥有的资源文件,我们同样也把图片放在这个地方,下次targetapp注入的时候,也会把我们添加进入的图片一起注入,如下图:
在这里插入图片描述

在这里插入图片描述
在[indexPath row] == 1中,我们accessoryView加入的是textfield,如下:

 //监听键盘输入
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textFieldDidChangeValue:) name:UITextFieldTextDidChangeNotification object:textField];
            textField.text = [HKDefaults valueForKey:HKTIMEKEY];
            textField.borderStyle = UITextBorderStyleRoundedRect;
            cell.imageView.image = [UIImage imageNamed:@"clock"];

我们要添加和保持textfield的数据,我们需要添加textfield改变系统的通知,

%new
- (void)textFieldDidChangeValue:(NSNotification *)notification{
    
    UITextField *sender = (UITextField *)[notification object];
    [HKDefaults setValue:sender.text forKey:HKTIMEKEY];
    [HKDefaults synchronize];
}

在WCTableViewManager,
监听tableview滚动后收起键盘

//监听滚动
- (void)scrollViewWillBeginDragging:(id)arg1{
    %orig;
    //退出编辑
    [MSHookIvar <UITableView *>(self,"_tableView") endEditing:YES];
}

在NewSettingViewController添加监控键盘的弹出收起

%hook NewSettingViewController

%new
-(void)keyboardWillShow:(NSNotification*)note{
    UIView * view = self.view;
    CGRect keyBoardRect=[note.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
    view.frame = CGRectMake(0, -keyBoardRect.size.height, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height );
}

%new
-(void)keyboardWillhide:(NSNotification*)note{
    UIView * view = self.view;
    view.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);
    
}


- (void)viewDidLoad{
    //监听键盘弹出和消失
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillhide:) name:UIKeyboardWillHideNotification object:nil];
    %orig;
}
%end
### Markdown 语法详解 #### 基本概念 Markdown 是一种轻量级标记语言,旨在通过简单的符号让纯文本格式化变得容易[^1]。这种语言允许作者使用易于阅读和书写的纯文本格式来编写文档,并将其转换为结构化的HTML (超文本标记语言)[^2]。 #### 文档历史与发展 该语言在2004年由约翰·格鲁伯(John Gruber)创建,自那时起便迅速流行起来,成为撰写README文件和其他技术文档的事实标准之一。 #### 文件扩展名 通常情况下,Markdown 文件会以 `.md` 或者 `.markdown` 结尾。 #### 兼容性 值得注意的是,Markdown 完全支持 HTML 的语法规则,在必要时可以直接嵌入 HTML 标签进行更复杂的页面布局或样式设置。 #### 主要功能特性 ##### 创建标题 利用井号(#) 来定义不同级别的标题,数量越多表示级别越低: ```markdown # 这是一级标题 ## 这是二级标题 ### 这是三级标题 ``` ##### 列表项 无序列表可以使用星号(*)、加号(+)或者减号(-),而有序列表则是数字加上英文句点(.): ```markdown * 苹果 + 香蕉 - 草莓 1. 第一步骤 2. 第二步骤 3. 第三步骤 ``` ##### 强调文字 为了强调某些部分的内容,可以用单个星号(*)包裹单词实现斜体效果;双星号(**)用于粗体显示: ```markdown 这是一个 *斜体字* 和 **粗体字** 的例子。 ``` ##### 插入链接与图片 对于外部资源的引用,采用方括号[]内放置描述文本,紧接其后的圆括号()里输入URL地址的方式构建超链接;同样地,只需额外添加感叹号(!)前缀即可插入一张网络图片: ```markdown 访问 [Google](https://www.google.com) ![GitHub Logo](https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png) ``` ##### 添加代码片段 当需要展示编程源码或其他预格式化的数据时,可借助反引号(``)包围相应区域完成行内编码高亮;多行代码块则需连续三个反引号并指定编程语言名称作为开头结束标志: ```python def hello_world(): print("Hello, world!") ``` #### 导出选项 除了基本的文字处理外,Markdown 编辑器还提供了丰富的导出能力,能够将最终成果保存成 HTML 页面、Word 文档、PDF 文件等多种形式供进一步分享交流之用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值