一、Cycript
- Cycript是由Cydia创始人Saurik推出的一款脚本语言,Cycript混合了OC、JavaScript语法的解释器,这意味着我们能够在一个命令中使用OC或者JavaScript,甚至两者并用.它能够挂钩正在运行的进程,能够在运行时修改很多东西.
-
- 官网下载/ MonkeyDev自动配置下载
- 是一种脚本语言,混合了多种语法.(混合了多种语法的解释器),所以可以兼容
- Cycript可以附加到进程,动态调试应用的
1.1 安装
- 下载后使用Cycript可执行文件、MonkeyDev安装成功后可不用配置.bash_profile/.zshrc路径,因为MonkeyDev中有
1.2 基本使用
- cy文件
- Cycript是一门脚本语言,它可以加载封装好的.cy文件
- 将常用的Cycript功能封装到.cy文件中,便于调试
- 非越狱设备,导入.cy文件
- 利用MonkeyDev工具导入.cy文件
- MonkeyDev本身集成了Cycript.我们只需要将.cy文件,通过Xcode导入Frameworks目录即可
- 进入Cycript环境
$ cycript
cy#
-
- 退出环境: control +d
- MonkeyDev中集成了Cycript,使用MonkeyDev重签名应用,会自动注入libcycript.dylib相关文件
- 当Cycript注入到目标应用,应用进程就会调用Cycript的方法,开启相应的端口,以供第三方监听
- 第三方可通过端口链接进程,进入cy环境,HOOK当前进程中的内存数据
1.3 使用实战
- 附加进程
- 使用MonkeyDev的Demo安装并运行wx8.0.2.ipa
- 让手机与Mac处于同一网络环境,来到终端,使用设备ip+端口号(默认6666)附加进程
- 未链接成功时:
- cyConnect.sh脚本中代码: cycript -r 192.168.124.12:6666
sh cyConnect.sh
*** _syscall(connect(socket_, info->ai_addr, info->ai_addrlen)):/Users/monkey/Documents/Cycript_Project/src/Console.cpp(306):CYSocketRemote [errno=61]
-
- 如下显示则表明附加成功
$ cycript -r 192.168.124.12:6666
cy#
- 获取keyWindow
cy# UIWindow.keyWindow()
#"<iConsoleWindow: 0x111760ba0; baseClass = UIWindow; frame = (0 0; 414 736); gestureRecognizers = <NSArray: 0x28347a1f0>; layer = <UIWindowLayer: 0x283b5ed20>>"
- 获取UIApplication单例对象
cy# UIApp
#"<UIApplication: 0x1117241e0>"
- 设置当前附加程序App角标数量
cy# [UIApp setApplicationBadgeString: @"999"]
- 退出后台、设置完当前代码后、可以看到角标数量
- 但是回到前台时,该角标就会清零,因为修改的是内存中的代码.
- 再比如修改聊天界面上一个人的名字: “Gray皓白”
-
- 通过Cycript链接着运行中的App、
- 搜索当前界面的UILabel、然后根据关键字“Gray”找到这个label对象地址0x122907c40.
- 将text内容改为Gray
cy# choose(UILabel)
[#"<MMUILabel: 0x121253a10; baseClass = UILabel; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <_UILabelLayer: 0x28075f930>>",#"<MMUILabel: 0x12126eba0; baseClass = UILabel; frame = (0 0; 0 0); hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280747480>>",#"<MMUILabel: 0x121270a50; baseClass = UILabel; frame = (0 0; 0 0); hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280747660>>",#"<MMUILabel: 0x121272900; baseClass = UILabel; frame = (0 0; 0 0); hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280747700>>",#"<MMUILabel: 0x1212747b0; baseClass = UILabel; frame = (0 0; 0 0); hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280744730>>",#"<MMCPLabel: 0x1212b5e50; baseClass = UILabel; frame = (269 0; 414 16); hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280730cd0>>",#"<MMUILabel: 0x1212eb8f0; baseClass = UILabel; frame = (56 48; 0 0); text = ''; clipsToBounds = YES; hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x2807845a0>>",#"<MMUILabel: 0x1212f97e0; baseClass = UILabel; frame = (56 48; 0 0); text = ''; clipsToBounds = YES; hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280784c80>>",#"<MMUILabel: 0x110c4bce0; baseClass = UILabel; frame = (-22.6667 7.33333; 67 21); text = '\xe6\x94\xb6\xe5\x8f\x96\xe4\xb8\xad\xe2\x80\xa6'; hidden = YES; userInteractionEnabled = NO; tag = 102; layer = <_UILabelLayer: 0x2804feb20>>",#"<MMUILabel: 0x110c86ea0; baseClass = UILabel; frame = (11 7.5; 8 15); text = '7'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280483ac0>>",#"<MMUILabel: 0x110c89200; baseClass = UILabel; frame = (0 0; 0 0); hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x2804ac320>>",#"<MMUILabel: 0x110c8adb0; baseClass = UILabel; frame = (10.5 7.5; 9 15); text = '4'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x2804ac5f0>>",#"<MMCPLabel: 0x110ccf970; baseClass = UILabel; frame = (65 0; 200 16); text = '\xe5\xa4\xa9\xe6\xb4\xa5-\xe5\x88\x98\xe6\xb4\xaa\xe6\xb6\x9b'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x2807659f0>>",#"<MMUILabel: 0x110cecf00; baseClass = UILabel; frame = (184.667 40; 69 17); text = '\xe6\xad\xa3\xe5\x9c\xa8\xe5\x8a\xa0\xe8\xbd\xbd\xe2\x80\xa6'; hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x2804f16d0>>",#"<MMCPLabel: 0x123107700; baseClass = UILabel; frame = (65 0; 200 16); text = '\xe5\xa4\xa9\xe6\xb4\xa5-\xe5\x88\x98\xe6\xb4\xaa\xe6\xb6\x9b'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280730230>>",#"<MMCPLabel: 0x123108910; baseClass = UILabel; frame = (269 0; 414 16); hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280731cc0>>",#"<MMCPLabel: 0x12310d440; baseClass = UILabel; frame = (65 0; 200 16); text = '\xe7\xad\x94\xe7\x96\x91\xe2\x80\x94jz'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280730460>>",#"<MMCPLabel: 0x12310e650; baseClass = UILabel; frame = (269 0; 414 16); hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280730f00>>",#"<MMUILabel: 0x12318f140; baseClass = UILabel; frame = (-38 1.33333; 35 21); text = '\xe5\xba\x95\xe5\xb1\x82'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280732990>>",#"<MMUILabel: 0x12318f430; baseClass = UILabel; frame = (-33.3333 22.3333; 67 12); text = '\xe5\xa4\xa7\xe5\xb8\x88\xe7\x8f\xad\xe4\xb8\x89\xe6\x9c\x9f1\xe7\xbe\xa4'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280732c10>>",#"<MMCPLabel: 0x1231b1030; baseClass = UILabel; frame = (65 0; 200 16); text = '\xe7\xad\x94\xe7\x96\x91\xe2\x80\x94jz'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280731d60>>",#"<MMUILabel: 0x1231b8b30; baseClass = UILabel; frame = (0 0; 41 21); text = '(313)'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x2807329e0>>",#"<MMCPLabel: 0x122907640; baseClass = UILabel; frame = (65 0; 200 16); text = '\xe5\xa4\xa9\xe6\xb4\xa5-\xe5\x88\x98\xe6\xb4\xaa\xe6\xb6\x9b'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280795630>>",#"<MMCPLabel: 0x122907c40; baseClass = UILabel; frame = (65 0; 200 16); text = 'Gray\xe7\x9a\x93\xe7\x99\xbd'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280794be0>>",#"<MMCPLabel: 0x122908240; baseClass = UILabel; frame = (269 0; 414 16); hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280794d70>>",#"<MMUILabel: 0x122913840; baseClass = UILabel; frame = (56 48; 0 0); text = ''; clipsToBounds = YES; hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x2807b9860>>",#"<MMCPLabel: 0x122918230; baseClass = UILabel; frame = (65 0; 200 16); text = '\xe7\xad\x94\xe7\x96\x91\xe2\x80\x94jz'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280794410>>",#"<MMUILabel: 0x12292fd00; baseClass = UILabel; frame = (56 48; 0 0); text = ''; clipsToBounds = YES; hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x2807b9220>>",#"<MMCPLabel: 0x122933120; baseClass = UILabel; frame = (65 0; 200 16); text = '\xe7\xad\x94\xe7\x96\x91\xe2\x80\x94jz'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280794690>>",#"<MMCPLabel: 0x122938770; baseClass = UILabel; frame = (269 0; 414 16); hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280794910>>",#"<MMUILabel: 0x12295b160; baseClass = UILabel; frame = (56 48; 0 0); text = ''; clipsToBounds = YES; hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x2807b3d40>>",#"<MMCPLabel: 0x12295fc50; baseClass = UILabel; frame = (269 0; 414 16); hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x2807957c0>>",#"<MMUILabel: 0x1229780a0; baseClass = UILabel; frame = (56 48; 0 0); text = ''; clipsToBounds = YES; hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280760000>>",#"<MMUILabel: 0x12297a0c0; baseClass = UILabel; frame = (0 0; 0 0); hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280797ca0>>",#"<MMUILabel: 0x12297d350; baseClass = UILabel; frame = (56 48; 0 0); text = ''; clipsToBounds = YES; hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x2807605f0>>",#"<MMUILabel: 0x122981cb0; baseClass = UILabel; frame = (56 48; 0 0); text = ''; clipsToBounds = YES; hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280760af0>>",#"<MMUILabel: 0x1229868a0; baseClass = UILabel; frame = (56 48; 0 0); clipsToBounds = YES; hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280760e60>>",#"<MMCPLabel: 0x1229b1360; baseClass = UILabel; frame = (65 0; 200 16); text = '\xe5\xa4\xa9\xe6\xb4\xa5-\xe5\x88\x98\xe6\xb4\xaa\xe6\xb6\x9b'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280764320>>",#"<MMCPLabel: 0x1229b2570; baseClass = UILabel; frame = (269 0; 414 16); hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280764a00>>",#"<MMUILabel: 0x12116cb60; baseClass = UILabel; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <_UILabelLayer: 0x28048e990>>",#"<MMUILabel: 0x12118f9b0; baseClass = UILabel; frame = (0 0; 0 36); userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280747f20>>",#"<MMUILabel: 0x12119c430; baseClass = UILabel; frame = (-19 7.33333; 35 21); text = '\xe5\xbe\xae\xe4\xbf\xa1'; userInteractionEnabled = NO; tag = 104; layer = <_UILabelLayer: 0x2807b0820>>",#"<MMUILabel: 0x12119cfa0; baseClass = UILabel; frame = (56 48; 0 0); text = ''; clipsToBounds = YES; hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x2807b8a00>>",#"<MMUILabel: 0x1211a6970; baseClass = UILabel; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <_UILabelLayer: 0x2807b1130>>",#"<MMCPLabel: 0x1211b81f0; baseClass = UILabel; frame = (269 0; 414 16); hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x2807660d0>>",#"<MMUILabel: 0x1211d9090; baseClass = UILabel; frame = (12 4; 60 32); text = '\xe4\xbd\xa0\xe5\x8f\xaf\xe8\x83\xbd\xe8\xa6\x81\xe5\x8f\x91\xe9\x80\x81\xe7\x9a\x84\xe7\x85\xa7\xe7\x89\x87:'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280720c80>>",#"<MMCPLabel: 0x1211dad90; baseClass = UILabel; frame = (269 0; 414 16); hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280795090>>",#"<MMUILabel: 0x110d479a0; baseClass = UILabel; frame = (0 -1; 1 20); text = '\xe5\xbe\xae\xe4\xbf\xa1(\xe6\x9c\xaa\xe8\xbf\x9e\xe6\x8e\xa5)'; hidden = YES; userInteractionEnabled = NO; tag = 103; layer = <_UILabelLayer: 0x2804fc140>>",#"<MMUILabel: 0x110d68980; baseClass = UILabel; frame = (-17 0; 35 36); text = '\xe5\xbe\xae\xe4\xbf\xa1'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x2804ab2f0>>",#"<MMUILabel: 0x110d76ed0; baseClass = UILabel; frame = (0 0; 0 0); hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x2804b7980>>",#"<MMUILabel: 0x110d8bf20; baseClass = UILabel; frame = (-19 7.33333; 35 21); text = '\xe5\xbe\xae\xe4\xbf\xa1'; userInteractionEnabled = NO; tag = 104; layer = <_UILabelLayer: 0x2804fc320>>",#"<MMUILabel: 0x110dab3a0; baseClass = UILabel; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <_UILabelLayer: 0x28075d9a0>>",#"<MMUILabel: 0x110dce470; baseClass = UILabel; frame = (180.667 796; 53 15); text = '\xe6\x8c\x89\xe4\xbd\x8f \xe8\xaf\xb4\xe8\xaf\x9d'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x2804ff110>>",#"<MMUILabel: 0x110dcfde0; baseClass = UILabel; frame = (176 30; 62 18); text = '\xe5\x8a\xa0\xe8\xbd\xbd\xe6\x9b\xb4\xe5\xa4\x9a'; autoresize = W; userInteractionEnabled = NO; tag = 1680; layer = <_UILabelLayer: 0x2804ff340>>",#"<MMUILabel: 0x110dd7930; baseClass = UILabel; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <_UILabelLayer: 0x2804fd590>>",#"<MMUILabel: 0x110dda360; baseClass = UILabel; frame = (0 0; 0 36); userInteractionEnabled = NO; layer = <_UILabelLayer: 0x2804ff890>>",#"<MMUILabel: 0x110deb860; baseClass = UILabel; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <_UILabelLayer: 0x2807768f0>>",#"<MMUILabel: 0x122a00710; baseClass = UILabel; frame = (56 48; 0 0); text = ''; clipsToBounds = YES; hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280785720>>",#"<MMUILabel: 0x122a2c940; baseClass = UILabel; frame = (56 48; 0 0); text = ''; clipsToBounds = YES; hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280784870>>",#"<MMUILabel: 0x122a430f0; baseClass = UILabel; frame = (56 48; 0 0); text = ''; clipsToBounds = YES; hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280784c30>>",#"<MMUILabel: 0x122a43830; baseClass = UILabel; frame = (56 48; 0 0); text = ''; clipsToBounds = YES; hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280785090>>",#"<MMUILabel: 0x122a99eb0; baseClass = UILabel; frame = (24 -1; 90 36); text = '\xe8\xbf\x9e\xe6\x8e\xa5\xe4\xb8\xad\xe2\x80\xa6'; hidden = YES; userInteractionEnabled = NO; tag = 102; layer = <_UILabelLayer: 0x2807bd7c0>>",#"<MMUILabel: 0x122a9b040; baseClass = UILabel; frame = (0 -1; 1 20); text = '\xe5\xbe\xae\xe4\xbf\xa1(\xe6\x9c\xaa\xe8\xbf\x9e\xe6\x8e\xa5)'; hidden = YES; userInteractionEnabled = NO; tag = 103; layer = <_UILabelLayer: 0x2807bd860>>",#"<MMUILabel: 0x122ab0ba0; baseClass = UILabel; frame = (0 0; 0 0); hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280796580>>",#"<MMUILabel: 0x122ab6c70; baseClass = UILabel; frame = (184 12; 46 20); text = '17:40'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280796df0>>",#"<MMCPLabel: 0x122abc110; baseClass = UILabel; frame = (65 0; 200 16); text = '\xe7\xad\x94\xe7\x96\x91\xe2\x80\x94jz'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x280764500>>",#"<MMCPLabel: 0x127310960; baseClass = UILabel; frame = (269 0; 414 16); hidden = YES; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x2804d5090>>",#"<RichTextView: 0x1123eba00; baseClass = UILabel; frame = (12 10; 104 21); opaque = NO; layer = <YYAsyncLayer: 0x2837f1fb0>>",#"<RichTextView: 0x1125b8000; baseClass = UILabel; frame = (12 10; 21 21); opaque = NO; layer = <YYAsyncLayer: 0x2837f7570>>",#"<RichTextView: 0x112641c00; baseClass = UILabel; frame = (12 10; 70 21); opaque = NO; layer = <YYAsyncLayer: 0x283769590>>",#"<RichTextView: 0x112673a00; baseClass = UILabel; frame = (12 10; 161 21); opaque = NO; layer = <YYAsyncLayer: 0x283768510>>",#"<RichTextView: 0x112680600; baseClass = UILabel; frame = (12 10; 87 21); opaque = NO; layer = <YYAsyncLayer: 0x28376a6a0>>",#"<RichTextView: 0x111373800; baseClass = UILabel; frame = (12 10; 79 21); opaque = NO; layer = <YYAsyncLayer: 0x2837bcd20>>",#"<RichTextView: 0x1113f4600; baseClass = UILabel; frame = (12 10; 171 21); opaque = NO; layer = <YYAsyncLayer: 0x28376d860>>",#"<RichTextView: 0x1115d5200; baseClass = UILabel; frame = (12 10; 70 21); opaque = NO; layer = <YYAsyncLayer: 0x28376e310>>",#"<RichTextView: 0x11171dc00; baseClass = UILabel; frame = (12 10; 40 21); opaque = NO; layer = <YYAsyncLayer: 0x28376f300>>",#"<RichTextView: 0x111763c00; baseClass = UILabel; frame = (12 10; 84 21); opaque = NO; layer = <YYAsyncLayer: 0x283794240>>"]
cy# 0x122907c40.text = @"Gray"
@"Gray"
-
- 这个时候就可以看到界面上已经显示了 Gray
-
- 当退出当前群聊、再次进入、上次的修改也会消失.修改的是当时当刻、当前内存中的对象
- 综上: 我们采用Cycript去调试界面、但是这样步骤比较繁琐;
- 在Xcode中采用 Debug View Hierarchy直接对界面查找元素比较快.
- 或者通过Reveal查看元素
1.4 Cycript高级用法
- MonkeyDev中这些就是封装的高级语法
1.5 Cycript封装
//IIFE 匿名函数自执行表达式
(function(exports){
APPID = [NSBundle mainBundle].bundleIdentifier,
APPPATH = [NSBundle mainBundle].bundlePath,
APPHOME = NSHomeDirectory(),
//如果有变化,就用function去定义!!
HKRootvc = function(){
return UIApp.keyWindow.rootViewController;
};
HKKeyWindow = function(){
return UIApp.keyWindow;
};
HKGetCurrentVCFromRootVc = function(rootVC){
var currentVC;
if([rootVC presentedViewController]){
rootVC = [rootVC presentedViewController];
}
if([rootVC isKindOfClass:[UITabBarController class]]){
currentVC = HKGetCurrentVCFromRootVc(rootVC.selectedViewController);
}else if([rootVC isKindOfClass:[UINavigationController class]]){
currentVC = HKGetCurrentVCFromRootVc(rootVC.visibleViewController);
}else{
currentVC = rootVC;
}
return currentVC;
};
HKCurrentVC = function(){
return HKGetCurrentVCFromRootVc(HKRootvc());
};
})(exports);
- 将该文件拷贝进项目中、
- Build Phases --> Copy Files --> add
- 导入文件
$ sh cyConnect.sh
cy# @import hank
{}
cy# APPID //Bundle ID
cy# APPHOME //HomeDirectory
cy# HKCurrentVC() //当前控制器
cy# pvcs() //当前控制器层级结构
- 官网中有详细的使用语法案例:Cycript
二、Logos
- Logos是一个基于Perl正则表达式的预处理器,它使用优雅的类似Objective-C的语法简化了为OC方法和C函数创建挂钩所需的样板代码.它最常与Theos构建系统一起使用,该系统最初是为创建越狱调整而开发的.Logos曾经与Theos集成在同一个Git仓库中,但现在已经从Theos解耦到它自己的仓库中.
- Logos语法,其实是CydiaSubstrate框架提供的一组宏定义.便于开发者使用宏进行HOOK操作,语法简单,功能强大且稳定.
2.1 案例使用
- 创建一个普通项目的iOS LogosDemo、随便写点代码
- (void)loginButtonEvent:(UIButton *)sender {
[self postUID:self.uid.text PWD:self.pwd.text];
}
- (void)postUID:(NSString *)uid
PWD:(NSString *)pwd{
if ([uid isEqualToString:@"Holo"] && [pwd isEqualToString:@"123456"]) {
UIAlertController * alertVC = [UIAlertController alertControllerWithTitle:@"登录成功" message:nil preferredStyle:(UIAlertControllerStyleAlert)];
UIAlertAction * cancel = [UIAlertAction actionWithTitle:@"确定" style:(UIAlertActionStyleCancel) handler:nil];
[alertVC addAction:cancel];
[self showViewController:alertVC sender:nil];
}else{
UIAlertController * alertVC = [UIAlertController alertControllerWithTitle:@"登录失败" message:nil preferredStyle:(UIAlertControllerStyleAlert)];
UIAlertAction * cancel = [UIAlertAction actionWithTitle:@"确定" style:(UIAlertActionStyleCancel) handler:nil];
[alertVC addAction:cancel];
[self showViewController:alertVC sender:nil];
}
}
-
- 编译运行Demo、取出MachO文件、来到终端:
- 通过class-dump取出Headers
- 编译运行Demo、取出MachO文件、来到终端:
class-dump -H LogosDemo -o LogosDemoHeaders/
-
- 执行结果如下
-
- 这个时候我们需要对该LogosDemo进行重签名、对它进行方法的HOOK操作、
- HOOK的时候,需要注入一个动态库,load中写一堆HOOK代码
- 这个时候我们需要对该LogosDemo进行重签名、对它进行方法的HOOK操作、
- 然而回想到MonkeyDev的作用
- 1、重签名
- 2、代码注入
- 3、HOOK注入
- 此时此刻,我们创建一个MonkeyApp项目、然后将LogosDemo的包放入TargetApp文件夹下.运行LogosMonkey项目、
- 接下来,根据LogosDemo头文件,我们想要改变登录的状态、开始做HOOK操作
- 来到LogosMonkeyDylib.xm文件中、删除所有示例代码
- 接下来,根据LogosDemo头文件,我们想要改变登录的状态、开始做HOOK操作
-
-
- 稍微写点HOOK后的代码
-
//告诉当前,ViewController是继承于UIViewCotnroller的
@interface ViewController : UIViewController
@property (nonatomic,strong)UITextField *uid;
@property (nonatomic,strong)UITextField *pwd;
@end;
%hook ViewController
//HOOK的方法
- (void)loginButtonEvent:(id )sender {
NSString *str = [NSString stringWithFormat:@"%@-%@",self.uid.text,self.pwd.text];
UIAlertController * alertVC = [UIAlertController alertControllerWithTitle:@"HOOK Success!!!" message:str preferredStyle:(UIAlertControllerStyleAlert)];
UIAlertAction * cancel = [UIAlertAction actionWithTitle:@"确定" style:(UIAlertActionStyleCancel) handler:nil];
[alertVC addAction:cancel];
[self showViewController:alertVC sender:nil];
}
%end
- 运行项目、输入账号密码、点击登录、这个时候,我们可以看到我们自己写的HOOK弹窗.操作成功
- 综上: 这就是简单的利用MonkeyDev中的Logos进行HOOK的操作.
2.2 Logos语法
2.2.1 Logos Tips
- “LogosMonkeyDylib.xm”后缀名为
- .x 表示支持logos和C语法
- .xm表示支持logos、C以及C++语法
2.2.2 Logos语法分为三大类:
- Block level
- 这一类型的指令会开辟一个代码块,以 %end结束
- %group、%hook、%subclass、%end
- Top Level
- 这个TopLevel指令不放在BlockLevel中
- %config、%hookf、%ctor、%dtor
- Function Level
- 这一块的指令就放在方法中
- %init、%class、%c、%orig、%log
- 常用语法
- %hook: HOOK某个类里面的某个方法
%hook ClassName
-(void)instanceMethod { }
+(void)classMethod{ }
%end
-
- %new: 为某个类添加新方法,在%hook和%end中使用
%hook ClassName
// 添加一个类方法
%new
+(void)newClassMethod{}
//添加一个对象方法
%new
-(void)newInstanceMethod{}
%end
-
- %group用来将代码分组.开发中hook代码会很多,这样方便管理Logos代码
%group group1
%hook ClassName
%end
%end
-
- %ctor(constructor):构造函数、用于确定加载哪个组.和%init结合用
- %init: 用来初始化某个组
- %log: 能够输出日志,输出方法调用的详细信息
- %orig(original): 这个就是保持原有的方法实现,如果原来的方法有返回值,那么%orig就有返回值的
- %c: 类似getClass函数,获得一个类对象.一般用于调用类方法
2.2.3 Logos语法使用案例
案例1:
-
- 比如刚才的案例: 我们使用%group来做不同的事件、那么需要配合 %ctor来使用
#import <UIKit/UIKit.h>
//告诉当前,ViewController是继承于UIViewCotnroller的
@interface ViewController : UIViewController
@property (nonatomic,strong)UITextField *uid;
@property (nonatomic,strong)UITextField *pwd;
@end;
%group group1
%hook ViewController
//HOOK的方法
- (void)loginButtonEvent:(id )sender {
NSString *str = [NSString stringWithFormat:@"%@ - %@",self.uid.text,self.pwd.text];
UIAlertController * alertVC = [UIAlertController alertControllerWithTitle:@"HOOK Group1 Success!!!" message:str preferredStyle:(UIAlertControllerStyleAlert)];
UIAlertAction * cancel = [UIAlertAction actionWithTitle:@"确定" style:(UIAlertActionStyleCancel) handler:nil];
[alertVC addAction:cancel];
[self showViewController:alertVC sender:nil];
}
%end
%end
%group group2
%hook ViewController
//HOOK的方法
- (void)loginButtonEvent:(id )sender {
NSString *str = [NSString stringWithFormat:@"%@ - %@",self.uid.text,self.pwd.text];
UIAlertController * alertVC = [UIAlertController alertControllerWithTitle:@"HOOK Group2 Success!!!" message:str preferredStyle:(UIAlertControllerStyleAlert)];
UIAlertAction * cancel = [UIAlertAction actionWithTitle:@"确定" style:(UIAlertActionStyleCancel) handler:nil];
[alertVC addAction:cancel];
[self showViewController:alertVC sender:nil];
}
%end
%end
%ctor {
%init(group1)
}
-
- 编写代码如上、这个时候,运行得出错误
Preparing to run Xcode Build Phase for Logos Processor...
Logos Processor: LogosMonkeyDylib.xm -> LogosMonkeyDylib.mm...
Failed Logos Processor: ~/LogosMonkey/LogosMonkeyDylib/Logos/LogosMonkeyDylib.xm:45:
error: non-initialized hook group: group2
-
- 这里表示、group2没有进行初始化: 也就是一旦写了就要初始化
%ctor {
%init(group1) %init(group2)
}
-
-
- 运行后我们可以发现、起作用的是group2的代码: 也就是说代码会覆盖,执行最后一个分组
- 添加一个版本判断来单向执行
-
%ctor {
NSString *version = [UIDevice currentDevice].systemVersion;
if (version.doubleValue >= 13.0) {
%init(group2)
} else {
%init(group1)
}
}
- 注: logos中使用ctor 则也会有 dtor:析构函数,做一些收尾工作,比如应用挂起时的操作
案例2:
-
- 常用的语法: %log的使用
%group group1
%hook ViewController
//HOOK的方法
- (void)loginButtonEvent:(id )sender {
%log;
}
%end
%end
-
- 输出结果为
2023-04-11 21:30:19.813331+0800 LogosDemo[26917:903478] -[<ViewController: 0x127d131d0> loginButtonEvent:<UIButton: 0x127d16750; frame = (50 300; 200 50); clipsToBounds = YES; opaque = NO; layer = <CALayer: 0x28044a240>>]
-
- 控制器对象: 方法名称 : 方法参数: 调用者.
- 如此可见: %log相当于LLDB中的po.
案例3
- %orig: 这个就是保持原有的方法实现,如果原来的方法有返回值,那么%orig就有返回值的
- 如果原来的方法有返回值,我们用参数接收,在接收参数后对原始值进行操作.
id result = %orig;
result += 1;
案例4
- %new的使用: 为某个类添加新方法,在%hook和%end中使用
@interface ViewController : UIViewController
@property (nonatomic,strong)UITextField *uid;
@property (nonatomic,strong)UITextField *pwd;
@end;
%group group1
%hook ViewController
//HOOK的方法
- (void)loginButtonEvent:(id )sender {
NSString *str = [NSString stringWithFormat:@"%@ - %@",self.uid.text,self.pwd.text];
UIAlertController * alertVC = [UIAlertController alertControllerWithTitle:@"HOOK Group1 Success!!!" message:str preferredStyle:(UIAlertControllerStyleAlert)];
UIAlertAction * cancel = [UIAlertAction actionWithTitle:@"确定" style:(UIAlertActionStyleCancel) handler:nil];
[alertVC addAction:cancel];
[self showViewController:alertVC sender:nil];
}
%new
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self.view endEditing:YES];
}
%end
%end
-
- 键盘弹起后,点击空白区域,键盘回收.
案例5
- 当想创建一个类方法时,需要在类中声明及实现
@interface ViewController : UIViewController
@property (nonatomic,strong)UITextField *uid;
@property (nonatomic,strong)UITextField *pwd;
//新增声明的类方法
+ (void)hs_classMethod;
@end;
%group group1
%hook ViewController
%new
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self.view endEditing:YES];
//[self.class hs_classMethod];
//通过获取类名 调用类方法
[NSClassFromString(@"ViewController") hs_classMethod];
}
%new
+ (void)hs_classMethod{
NSLog(@"This is a class method");
}
%end
%end
-
- 获取类名: NSClassFromString(@"ViewController")
- 另外: 这个时候我们可以引入 %c 来替代上述的获取类名的方法
%new
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self.view endEditing:YES];
//通过获取类名 调用类方法
[%c(ViewController) hs_classMethod];
}
案例6
- %hookf官方案例
// Given the function prototype (only add it yourself if it's not declared in an included/imported header)
FILE *fopen(const char *path, const char *mode);
// The hook is thus made
%hookf(FILE *, fopen, const char *path, const char *mode) {
puts("Hey, we're hooking fopen to deny relative paths!");
if (path[0] != '/') {
return NULL;
}
return %orig; // Call the original implementation of this function
}
// functions can also be looked up at runtime, if, for example, the function is in a private framework
%hookf(BOOL, MGGetBoolAnswer, CFStringRef string) {
if (CFEqual(string, CFSTR("StarkCapability"))) {
return YES;
}
return %orig;
}
%ctor() {
%init(MGGetBoolAnswer = MSFindSymbol(NULL, "_MGGetBoolAnswer"));
}
三、总结
- Logos语法其实就是Cydia Substrate框架提供的一组宏定义
- 语法
- %hook、%end勾住某个类,在一个代码块中直接写需要勾住的方法
- %group,%end用于分组: 一般用于不同的系统中做不同的hook内容
- 每一组都需要 %ctor()函数初始化
- 通过%init(组名) 进行初始化
- %log输出方法的详细信息(调用者、方法名、方法参数)
- %orig调用原始方法.可以传递参数,接收返回值
- %c类似getClass函数,获得一个类对象
- %new添加某个方法
- 关于xm文件, .xm代表支持OC、C/C++语法
- 编译该文件时,我们需要导入一些头文件,以便编译通过.