使用
Cycript
的时候,安装了Monkey Dev
, 用Monkey Dev
新建的工程后,文件夹xxxDylib
下有一个Logos
的文件夹,该文件夹下有一个后缀为.xm
的文件,.xm
文件中所使用的就是Logos
语法。
如果点击.xm
文件无法显示其中代码,Xcode
做如下更改即可。
1、什么是 Logos?
Logos
是一种语法,该语法其实是CydiaSubstruct
框架提供的一组宏定义。便于开发者使用宏进行HOOK
操作。语法简单,功能强大且稳定。
2、Logos 语法说明
Logos的官网。
文件后缀名为
.xm
代表支持Logos
语法、C
和C++
,如果后缀名为.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
输出方法的一些详细信息,就类似于
LLDB
的frame 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.app
,Show in Finder
拷贝出来。
新建 Monkey
工程,然后重签 LogosLoginText.app
成功后,使用 class-dump
导出LogosLoginText.MachO
的头文件,这样准备工作就完成了。
打开 LogosLoginText
的头文件,就是假装打开了其他 App
的头文件,然后分析一下:
假装看到了登录方法 - (void)postWithUID:(id)arg1 pwd:(id)arg2;
然后我们对这个方法进行 Hook
,然后在注入库 MonkeyLoginDylib.lib
的 MonkeyLoginDylib.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
因为 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
现在给 - (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
的介绍和基本用法了。
来自:有梦想的程序员
链接:https://www.jianshu.com/p/8405693fea08