Logos

使用 Cycript 的时候,安装了 Monkey Dev, 用 Monkey Dev 新建的工程后,文件夹 xxxDylib 下有一个 Logos 的文件夹,该文件夹下有一个后缀为 .xm 的文件,.xm 文件中所使用的就是 Logos 语法。

如果点击 .xm 文件无法显示其中代码,Xcode 做如下更改即可。

xm 文件格式修改

1、什么是 Logos?

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

2、Logos 语法说明

Logos的官网。

文件后缀名为 .xm 代表支持 Logos 语法、CC++,如果后缀名为 .x 代表支持 Logos 语法和 C

1、%hook

你要 Hook 哪个类。 %hook 后面接类名:%hook ViewController%end 结束,中间放的是需要 Hook 的方法

%hook ViewController

- (void)hookMethod {
  
} 

%end
2、%group

用于分组,比如在不同 iOS 系统版本上使用不同分组的代码,兼容性就会更好。

%group group1

%hook ViewController

- (void)hookMethod {
   NSLog(@"第一组Hook");
}

%end

%end


%group group2

%hook ViewController

- (void)hookMethod {
   NSLog(@"第二组Hook");
}

%end

%end

3、%init

初始化一个组。

%init(group1)
%init(group2)
4、%ctor

构造函数,如果有上述分组可以在这个方法里面去判断。

%ctor{
    NSString *version = [UIDevice currentDevice].systemVersion;
    if (version.floatValue >= 8.0) {
        %init(group1)
    } else {
        %init(group2)
    }
}
5、%dtor

析构函数。

%dtor {
    //释放一些东西...
}
6、%log

输出方法的一些详细信息,就类似于 LLDBframe variable

7、%orig

Hook到一个方法后,保持原来的方法的调用,如果该方法有返回值,也能接收返回值。

8、%new

动态添加方法

%new
- (void)addMethod {
    //一些方法实现...
}

%new
+ (void)classMethod {
    //一些方法实现...
}
9、%c

如果是添加了一个类方法,就需要使用类对象是调用,%c(类名) 就可以获取类对象。

3、Logos 语法使用

Xcode 新建一个普通工程命名为 LogosLoginText ,然后在 ViewController.m 中写入如下代码:

//
//  ViewController.m
//  LogosLoginText
//
//  Created by ABC on 2019/11/9.
//  Copyright © 2019 ABC. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
}


- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self postWithUID:@"ABC" pwd:@"123456"];
}

- (void) postWithUID:(NSString *)uid pwd:(NSString *)pwd {

    if ([uid isEqualToString:@"ABC"] && [pwd isEqualToString:@"123456"]) {
        
        //登录成功
        UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"登录成功" message:nil preferredStyle:(UIAlertControllerStyleAlert)];
        
        UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:(UIAlertActionStyleDefault) handler:nil];
        [alertController addAction:okAction];
        
        [self presentViewController:alertController animated:YES completion:nil];

    } else {
        
        //登录失败
        UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"登录失败" message:nil preferredStyle:(UIAlertControllerStyleAlert)];
        
        UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:(UIAlertActionStyleDefault) handler:nil];
        [alertController addAction:okAction];
        
        [self presentViewController:alertController animated:YES completion:nil];
    }
}

@end

上方代码就是简单的一个判断,目的是在使用 Logos 语法 Hook 的时候,改变了相应的值,会提示错误,以便于知道 Hook 到改方法并修改值成功了。

添加完了上述代码,真机编译一下就可以了,这里只是为了拿到生成的 LogosLoginText.app 包,以便于使用 Monkey Dev 重签而已,就相当于模拟其他 App

编译成功后找到 Xcode 工程里 Products 文件下的 LogosLoginText.appShow in Finder 拷贝出来。

新建 Monkey 工程,然后重签 LogosLoginText.app 成功后,使用 class-dump 导出LogosLoginText.MachO 的头文件,这样准备工作就完成了。

打开 LogosLoginText 的头文件,就是假装打开了其他 App 的头文件,然后分析一下:

分析头文件

假装看到了登录方法 - (void)postWithUID:(id)arg1 pwd:(id)arg2; 然后我们对这个方法进行 Hook,然后在注入库 MonkeyLoginDylib.libMonkeyLoginDylib.xm 中写要注入的代码。

// See http://iphonedevwiki.net/index.php/Logos

#import 

%hook ViewController

%hook ViewController

- (void)postWithUID:(id)arg1 pwd:(id)arg2 {
   NSLog(@"Hook到了登录");
}

%end

然后点击屏幕,发现控制台打印了:Hook到了登录,并没有弹出 AlertView 证明该方法被 Hook 成功了。

如果需要版本判断,就需要分组了。使用 %group%init 和 % ctor 了。

%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{
    NSString *version = [UIDevice currentDevice].systemVersion;
    if (version.floatValue >= 8.0) {
        %init(group1)
    } else {
        %init(group2)
    }
}

注意:组一定会有的,如果没有写组,那么Logos 会默认生成一个组 _ungrouped 并自己调用构造函数和 init 方法创建。

尝试输出一下当前方法的详细信息 %log,添加后运行一下,查看结果发现,输出了参数详细的值和方法的指针地址。

%hook ViewController

- (void)postWithUID:(id)arg1 pwd:(id)arg2 {
    %log;
    NSLog(@"Hook到了登录");
}

%end
%log 结果

因为 Hook 了这个方法导致,该方法没有执行原有的,现在通过 %orig 保持原来的调用。添加完成后重新运行,点击屏幕显示了 AlertView

%hook ViewController

- (void)postWithUID:(id)arg1 pwd:(id)arg2 {
    %log;
    %orig;
    NSLog(@"Hook到了登录");
}

%end

因为 - (void)postWithUID:(id)arg1 pwd:(id)arg2 是有参数的,所以可以通过 %orig 更改值:%orig(@"AAA",@"111111"),再出重新运行就发现,AlertView 提示登录失败了。

%hook ViewController

- (void)postWithUID:(id)arg1 pwd:(id)arg2 {
    %log;
    %orig(@"AAA",@"11111");
    NSLog(@"Hook到了登录");
}

%end
%orig 更改值

现在给 - (void)postWithUID:(id)arg1 pwd:(id)arg2 需要调用一个动态添加的方法 testMethod 就需要用到 %new 了。

当使用 [self testMethod] 会提示找不到 ViewController ,在逆向中如果找不到这个类,只需要将这个类和新添加的方法声明一下就可以,仅仅是为了让编译器编译能通过。

如果使用原来类里方法过多,可以把 class-dump 导出的头文件直接拖入 Logos文件夹下,在这个头文件里声明一下动态添加的方法名称。

代码如下:

@interface ViewController

- (void)testMethod;

@end

%hook ViewController

%new
- (void)testMethod {
    NSLog(@"调用了我动态添加的方法");
}

- (void)postWithUID:(id)arg1 pwd:(id)arg2 {
    %log;
    %orig(@"AAA",@"11111");
    NSLog(@"Hook到了登录");
    [self testMethod];
}

%end

重启运行,点击屏幕,控制台就打印了刚才添加方法中的 NSLog

动态添加方法

上方的代码使用的是实例方法,需要添加一个类方法,然后可以使用 %c(类名) 直接调用类方法。

@interface ViewController

- (void)testMethod;

@end

%hook ViewController

%new
- (void)testMethod {
    NSLog(@"调用了我动态添加的方法");
}

%new
+ (void)classMethod {
    NSLog(@"调用了我动态添加的类方法");
}

- (void)postWithUID:(id)arg1 pwd:(id)arg2 {
    %log;
    %orig(@"AAA",@"11111");
    NSLog(@"Hook到了登录");
    [self testMethod];
    [%c(ViewController) classMethod];
}

%end

以上就是 Logos 的介绍和基本用法了

你可能感兴趣的