Cycript
是由Cydia
创始人Saurik
推出的一款脚本语言,Cycript
混合了OC
、JavaScript
语法的解释器,这意味着我们能够在一个命令中使用OC
或者JavaScript
,甚至两者并用。它能够挂钩正在运行的进程,能够在运行时修改程序。
一、Cycript安装
Cycript官网,目前最新版本0.9.594
。直接下载SDK
解压放在/opt
目录中:
验证./cycript
:
➜ ./cycript
dyld: Library not loaded: /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/libruby.2.0.0.dylib
Referenced from: /opt/cycript_0.9.594/./Cycript.lib/cycript-apl
Reason: image not found
[1] 45603 abort ./cycript
出现image not found
发现需要Ruby 2.0
,进入目录只有2.6
:
将
2.6
拷贝一份改名为2.0
就可以了,在某些版本的MAC OSX
在该目录不能修改则将Monkey/bin
中的cycript
拷贝到cycript
中替换cycript
文件。
再次执行就可以了:
➜ ./cycript
cy#
进入cy#
表示配置成功。
接着配置环境变量:
export CY=/opt/cycript_0.9.594/
export PATH=/opt/MonkeyDev/bin:$PATH:$CY
配置环境变量后在任意路径输入cycript
就可以进入cycript
了。如果已经安装了Monkey
则不需要配置和安装cycript
了。(monkey
自带)。
二、Cycript常用命令
只要将cycript
注入到应用中,我们就可以调用其中的命令了,Monkey
重签名注入的时候帮我们注入了:
相当于开启端口,可以监听。
进入Cycript环境
直接在终端输入cycript
就进入cycript
环境了:
➜ ~ cycript
cy#
附加进程
连接进程进入Cycript
环境
➜ ~ cycript -r 192.168.3.127:6666
cy#
这里手机和电脑要在同一wifi
,并且进入应用程序进程。ip
为手机的ip
。
退出cycript环境
control + d
cycript调试命令
UIWindow.keyWindow()获取keyWindow
cy# UIWindow.keyWindow()
#"; layer = >"
这个时候进程并没有被中断。为了方便我们可以定义变量keyWd
:
cy# var keyWd = UIWindow.keyWindow()
#"; layer = >"
后续直接调用keyWd
就能拿到keyWindow
。即使control + d
/ 退出终端下次进入这个变量仍然有效。应用程序重启就失效了。
UIApp获取单类对象
cy# UIApp
#""
获取rootVC
cy# [keyWd rootViewController]
#" ChildViewControllers:(\n \"\"\n)"
#对象地址
拿到该对象,可用于调用方法。
cy# #0x1140d4800
#" ChildViewControllers:(\n \"\"\n)"
*对象地址
可以取出对象的成员变量。
recursiveDescription() 循环打印子视图
cy# keyWd.recursiveDescription()
toString() 格式化打印(遇到\n
换行)
cy# keyWd.recursiveDescription().toString()
`; layer = >
| >
| | >
| | | ; layer = >
| | | | >
| | | | | >
| | | | | | >
| | | | | | | >
| | | | | | | | >
| | | | | | | >
| | | | | | | | >
| | | | | | | | | >
| | | | | | | | >
| | | | | | | | | >
| | | | | | | >
| | | | | | | | >
| | | | >
| | | | | <_UIBarBackground: 0x113456b90; frame = (0 -20; 375 64); userInteractionEnabled = NO; layer = >
| | | | | | >
| | | | | | <_UIBarBackgroundShadowView: 0x113458380; frame = (0 64; 375 0); layer = > clientRequestedContentView effect=none
| | | | | | | <_UIBarBackgroundShadowContentImageView: 0x1134586f0; frame = (0 0; 375 0); opaque = NO; autoresize = W+H; userInteractionEnabled = NO; layer = >
| | | | | <_UINavigationBarContentView: 0x113456d70; frame = (0 0; 375 44); layer = > layout=0x113456ff0
| | | | | | <_UITAMICAdaptorView: 0x11346ce60; frame = (187 4; 1 36); autoresizesSubviews = NO; layer = >
| | | | | | | >
| | | | | | | | >
| | | | | >
| | | | | >`
choose(类名)
查询当前进程中该类型的对象。
cy# choose(UIButton)
">,>,>"
和LLDB
中search
很像。
三、脚本自动连接
创建一个脚本cyConnect.sh
,填入一下内容:
cycript -r 192.168.3.127:6666
配置环境变量:
export HPShell=/Users/zaizai/HPShell/
export PATH=/opt/MonkeyDev/bin:$HPShell:$PATH
使用:
➜ ~ cyConnect.sh
cy#
这样就能自动连接了。
四、Cycript 修改内存
修改角标
cy# [UIApp setApplicationBadgeString: @"999"]
修改红包金额
正常内容如下:
首先通过choose(UILabel)
找到红包金额
choose(UILabel).toString()
搜索1.00
得到地址0x149eaef00
:
修改金额:
cy# #0x149eaef00.text = @"¥88888888.00"
@"\xef\xbf\xa588888888.00"
接着同样的方式找到红包中借款
地址0x14c33b460
cy# #0x14c33b460.text = @"还款"
@"\xe8\xbf\x98\xe6\xac\xbe"
修改完成后内容如下:
修改聊天内容
我们可以直接通过cycript
搜索控件进行修改,也可以通过Xcode view debug
找到控件进行修改。
可以看到内容在
accessibility
的description
中:
这个时候通过修改
text
已经无效了,Hook
下代码调试下:
%hook RichTextView
- (_Bool)setPrefixContent:(id)arg1 TargetContent:(id)arg2 TargetParserString:(id)arg3 SuffixContent:(id)arg4 {
// arg2 为文案
return %orig;
}
%end
经过排查发现arg2
为文案,所以直接在这里写死试试:
%hook RichTextView
- (_Bool)setPrefixContent:(id)arg1 TargetContent:(NSString *)arg2 TargetParserString:(id)arg3 SuffixContent:(id)arg4 {
// arg2 为文案
if([arg2 isEqualToString:@"钱已经借给你了。"]) {
arg2 = @"钱已经换给你了,请查收!";
}
return %orig;
}
%end
确认可以修改。
至此整个内容就修改完成了:
所以微信截图什么的一个字也不能信。随便修改,想要什么样的内容都可以。
五、Cycript高级用法
APPID获取bundle identifier
cy# APPID
@"com.guaizai.MonkeyDemo"
pviews()
获取视图层级
`; layer = >
| >
| | >
| | | ; layer = >
| | | | >
| | | | | >
| | | | | | >
| | | | | | | >
| | | | | | | | >
| | | | | | | >
| | | | | | | | >
| | | | | | | | | >
| | | | | | | | >
| | | | | | | | | >
| | | | | | | >
| | | | | | | | >
| | | | >
| | | | | <_UIBarBackground: 0x113794170; frame = (0 -20; 375 64); userInteractionEnabled = NO; layer = >
| | | | | | >
| | | | | | <_UIBarBackgroundShadowView: 0x1137957a0; frame = (0 64; 375 0); layer = > clientRequestedContentView effect=none
| | | | | | | <_UIBarBackgroundShadowContentImageView: 0x113795b10; frame = (0 0; 375 0); opaque = NO; autoresize = W+H; userInteractionEnabled = NO; layer = >
| | | | | <_UINavigationBarContentView: 0x113794350; frame = (0 0; 375 44); layer = > layout=0x1137945d0
| | | | | | <_UITAMICAdaptorView: 0x11378e920; frame = (187 4; 1 36); autoresizesSubviews = NO; layer = >
| | | | | | | >
| | | | | | | | >
| | | | | >
| | | | | >`
pvcs()
获取视图控制器
cy# pvcs()
", state: appeared, view: \n | , state: appeared, view: "
这些命令并不是cycript
自带的,那么这些命令哪里来的呢?
在Monkey
工程我们可以在Config->MDConfig.plist
中发现Cycript
下有ms
和md
两个.cy
文件。
这些命令就封装在这两个文件中(工程运行的时候自动从网络上下载)。
ms.cy
md.cy
六、封装cy文件
Cycript
是一门脚本语言,它可以加载封装好的.cy
文件。我们会将常见的Cycript
常用功能封装到.cy
文件中,便于调试。
创建一个HotpotCat.cy
文件:
//IIFE 匿名函数自执行表达式
(function(exports){
//不变的内容使用常量
APPID = [NSBundle mainBundle].bundleIdentifier,
APPPATH = [NSBundle mainBundle].bundlePath,
APPHOME = NSHomeDirectory(),
//变化的内容,就用function去定义!!
HPRootVC = function(){
return UIApp.keyWindow.rootViewController;
};
HPKeyWindow = function(){
return UIApp.keyWindow;
};
HPGetCurrentVCFromRootVc = function(rootVC){
var currentVC;
if([rootVC presentedViewController]){
rootVC = [rootVC presentedViewController];
}
if([rootVC isKindOfClass:[UITabBarController class]]){
currentVC = HPGetCurrentVCFromRootVc(rootVC.selectedViewController);
}else if([rootVC isKindOfClass:[UINavigationController class]]){
currentVC = HPGetCurrentVCFromRootVc(rootVC.visibleViewController);
}else{
currentVC = rootVC;
}
return currentVC;
};
HPCurrentVC = function(){
return HPGetCurrentVCFromRootVc(HPRootVC());
};
})(exports);
- 对于不变的内容使用常量。
- 变化的内容,用
function
定义。
七 导入.cy文件
7.1 非越狱环境导入cy文件
- 通过Framworks导入
利用MonkeyDev
工具导入.cy
文件,MonkeyDev
本身集成了Cycript
,只需要将.cy
文件通过xcode
导入Framworks
目录即可。
- 将
HotpotCat.cy
拖入工程。 - 在
Copy Files
中添加HotpotCat.cy
。
这个时候编译完工程后在Frameworks
中就能找到HotpotCat.cy
文件了:
- 通过配置文件导入
这里可以参考NSLog
的方式:
-
LoadAtLaunch
:启动的时候是否加载脚本。 -
priority
:优先级。数字越小优先级越高,适用于有依赖关系的脚本。 -
content/url
:脚本可以直接写到content
里面,也可以是网络的url
会自动下载下来。
7.1.1 使用自定义.cy
内容
➜ ~ cyConnect.sh
cy# @import HotpotCat
{}
cy# HPCurrentVC()
#""
cy# APPHOME
@"/var/mobile/Containers/Data/Application/A3FC3D2B-03D5-436F-BD35-5560BDE37ADD"
cy# APPPATH
@"/private/var/containers/Bundle/Application/A2E20EBA-7AF7-4825-B693-13A19F626174/MonkeyDemo.app"
- 首先进入
cycript
环境。 - 导入
.cy
文件,这里不需要后缀。如果是通过config
配置并且默认启动加载则不需要。 - 调用定义的常量或者方法。
HotpotCat.cy
是通过libcycript.dylib
加载的。
7.2 越狱手机中使用Cycript
-
越狱手机安装
Cycript
插件
安装后手机环境下就有了Cycript
。 -
安装手机终端命令插件
adv-cmds
adv-cmds
是手机终端命令插件,比如clear
等命令。能够帮助我们更好的使用手机终端。 手机终端使用
cycript
zaizai:~ root# ps -A | grep WeChat
21890 ?? 0:01.80 /var/containers/Bundle/Application/8F382114-BBA7-4D81-AA3E-3CD02E03E23E/WeChat.app/WeChat
21896 ttys000 0:00.01 grep WeChat
zaizai:~ root# cycript -p 21890
cy#
- 找到进程id。
- 通过
cycript -p 进程id/进程名字
进入cycript
环境。如果有同名进程那么只能通过id。
cy# UIApp
#""
zaizai:~ root# cycript -p AlipayWallet
cy# UIApp
#""
这个时候就附加了微信了,可以直接在手机终端动态调试正版微信了。
7.2.1 手机越狱环境使用Cy文件
那么怎么导入cy
文件呢?非越狱环境是导入到App
里面的,越狱环境可以直接导入到手机中。
在手机端有一个目录cd /usr/lib/cycript0.9/
,我们的cy
文件需要放入这个路径下才行。
在这个目录下有文件目录如下:
可以看到
MS.cy
是在saurik
目录下的。这么做是为了规范 避免冲突,有点像BundleId
。那么我们自己的脚本也应该建立自己的目录com/HotpotCat
。
zaizai:/usr/lib/cycript0.9 root# cd com
zaizai:/usr/lib/cycript0.9/com root# ls
saurik/
zaizai:/usr/lib/cycript0.9/com root# mkdir HotpotCat
zaizai:/usr/lib/cycript0.9/com root# cd HotpotCat
zaizai:/usr/lib/cycript0.9/com/HotpotCat root# pwd
/usr/lib/cycript0.9/com/HotpotCat
zaizai:/usr/lib/cycript0.9/com/HotpotCat root#
接着将自己的脚本拷贝到这个目录/usr/lib/cycript0.9/com/HotpotCat/
:
scp -P 12345 HotpotCat.cy root@localhost:/usr/lib/cycript0.9/com/HotpotCat/
使用脚本
导入:
@import com.saurik.substrate.MS
@import com.HotpotCat.HotpotCat
总结
-
cycript
是一种脚本语言,混合了多种语法。(混合了多种语法的解释器),所以可以兼容。 - 越狱手机安装
cycript
插件(依赖adv-cmds插件)。 -
cycript
可以附加到进程,动态调试应用。cycript -p 进程iD/名称
-
cy
文件-
/usr/lib/cycript0.9
目录中 - 为了不重名放入
com
目录中,创建自己的组织文件夹。 - 加载的时候
@import com.组织名称.文件名称
-