19-Cycript

前言

本篇文章将介绍逆向实战中经常使用的一门语言 Cycript,它是由Cydia创始人Saurik推出的一款脚本语言Cycript混合了OC、JavaScript语法的解释器,这意味着我们能够在一个命令中使用OC或者JavaScript,甚至两者并用。它能够挂钩正在运行的进程,能够在运行时修改很多东西。

一、Cycript安装

Cycript官网,目前最新版本0.9.594。直接下载SDK解压放在/opt目录中

接着在~/.bash_profile~/.zshrc中配置环境变量

export PATH=/opt/cycript_0.9.594/cycript

接着验证一下

cycript

进入cy#表示配置成功。

⚠️注意:如果已经安装了Monkey不需要配置和安装cycript了。因为monkey自带了cycript,并且配置环境变量应改为

export CY=/opt/cycript_0.9.594/
export PATH=/opt/MonkeyDev/bin:$PATH:$CY

二、基本使用

只要将cycript注入到应用中,我们就可以调用其中的命令了,Monkey重签名注入的时候帮我们注入了,例如我们之前文章15-Hook原理(二)反Hook防护 & MokeyDev
中的例子MonKeyDemo

app包里面就包含了libcycript.dylib,当Cycript注入到目标应用,应用进程就会调用Cycript的方法,开启相应的端口,以供第三方监听。第三方可通过端口链接进程,进入cy环境,HOOK当前进程中的内存数据

2.1 进入Cycript环境

cycript

2.2 退出Cycript环境

control + d

2.3 附加进程

连接进程进入Cycript环境,例如

cycript -r 192.168.3.127:6666

这里手机和电脑要在同一wifi,并且进入应用程序进程。ip为手机的ip。端口号默认为6666

2.4 cycript调试命令

以上附加进程链接好了后,就可以使用cycript调试命令查看信息了,例如

  • 获取keyWindow
UIWindow.keyWindow()
-------------------------
#"; layer = >"
  • 获取UIApplication单例对象
UIApp
-------------------------
#""
  • 定义变量并赋值
var keyWd = UIWindow.keyWindow()
-------------------------
#"; layer = >"
keyWd.rootViewController
-------------------------
#" ChildViewControllers:(\n    \"\"\n)"

当程序的进程结束,定义的所有变量一起释放

  1. #对象地址 拿到该对象,可用于调用方法
#0x1270e9200
-------------------------
#" ChildViewControllers:(\n    \"\"\n)"
  1. *对象 可以取出对象的成员变量
*keyWd
-------------------------
{isa:iConsoleWindow,_responderFlags:@error,_constraintsExceptingSubviewAutoresizingConstraints:null,...
  • 查看视图结构
keyWd.recursiveDescription()
-------------------------
@"; layer = >\n   | >\n...

也可格式化打印,遇\n换行

keyWd.recursiveDescription().toString()
-------------------------
`; layer = >
  | >
  |    | >
  |    |    | ; layer = >
  |    |    |    | >
  |    |    |    |    | >
...
  • 查询当前进程指定类型对象
choose (UIButton)
-------------------------
[#">",#">",...

这和LLDBsearch很像。

三、进阶

3.1 脚本自动连接

  1. 创建cyShell目录
  2. cyShell目录下,创建cyConnect.sh脚本
  3. 打开cyConnect.sh脚本,写入以下代码
cycript -r 10.165.44.19:6666
  1. 增加可执行权限
chmod +x cyConnect.sh
  1. 配置环境变量
export cyShell=/Users/Aron/cyShell/
export PATH=/opt/MonkeyDev/bin:$cyShell:$PATH

这样能全局使用

cyConnect.sh
cy#

直接就能自动连接了。

3.2 Cycript 修改内存

接下来通过几个案例,使用Cycript脚本,看看如何修改内存。

案例一:修改应用图标的红点数
  1. 使用MonkeyDev安装并运行wx8.0.2.ipa
  2. 使用cyConnect.sh附加进程
  3. 修改BadgeString
[UIApp setApplicationBadgeString: @"999"]

⚠️注意:修改当前内存中的数据,应用重复挂起唤醒,数据就会被刷新。

案例二:修改红包金额

例如:正常的红包内容如下

  1. 首先通过choose(UILabel)找到红包金额
choose(UILabel).toString()

搜索1.00得到地址0x149eaef00

  1. 修改红包的金额
cy# #0x149eaef00.text = @"¥88888888.00"

同样的方式,找到借款UILabel的地址 0x14c33b460,将text改为还款

cy# #0x14c33b460.text = @"还款"
  1. 修改后的内容
案例三:修改聊天内容

有2种方式

  1. 通过cycript搜索控件进行修改
  2. 通过Xcodeview debug找到控件进行修改

可以看到内容在accessibilitydescription

接着我们在logos文件夹下的.xm文件中,使用logos语法hook方法,代码如下

%hook RichTextView

- (_Bool)setPrefixContent:(id)arg1 TargetContent:(NSString *)arg2 TargetParserString:(id)arg3 SuffixContent:(id)arg4 {
//    arg2 为文案
    if([arg2 isEqualToString:@"钱已经借给你了。"]) {
        arg2 = @"钱已经换给你了,请查收!";
    }
    return %orig;
}

%end

至此整个内容就修改完成了

3.3 高级用法

  • 获取bundle identifier
    使用APPID命令
cy# APPID
-------------------------
@"com.xxxxxx.MonKeyDemo"
  • 获取视图层级
    使用pviews()命令
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 = >
   |    |    |    |    |    |    | >
   |    |    |    |    |    |    |    | >
   |    |    |    |    | 

也可以查看pviews方法代码实现

pviews
-------------------------
function (){return UIApp.keyWindow.recursiveDescription().toString()}
  • 获取视图控制器
    使用pvcs()命令
cy# pvcs()
-------------------------
", state: appeared, view: \n   | , state: appeared, view: "

pvcs方法的代码实现

pvcs
-------------------------
function (){return UIWindow.keyWindow().rootViewController._printHierarchy().toString()}

上面这些功能,Cycript脚本也有,但是这些命令却不是Cycript自带的,那么它们是哪里来的呢?

在Monkey工程我们可以在Config->MDConfig.plist中发现Cycript下有msmd两个.cy文件

这些命令就封装在这两个文件中(工程运行的时候自动从网络上下载)。
ms.cy
md.cy

使用Cycript找到指定控制器某个控件,过程比较繁琐
更好的方式 在非越狱设备上,使用应用重签名,通过Debug View Hierarchy快速定位控件,找到对应的地址,然后使用Cycript对其进行修改

四、cy文件的封装

案例一:封装简单案例
  1. MokeyDemo项目中,创建test.cy文件
  2. 打开test.cy文件,写入以下代码
sum = function(a,b){
   return a + b;
}
  1. test.cy文件拖入项目,在MokeyDemo项目中,使用Copy Files添加test.cy

⚠️注意:test.cy是脚本文件,不是MachO不需要勾选签名

  1. 重新运行项目,使用cyConnect.sh附加进程

  2. 导入脚本

@import test
-------------------------
{}

调用sum方法

sum(10,20)
-------------------------
30
案例二:实现获取当前控制器
  1. 修改test.cy文件的代码
(function(exports){
   APPID = [NSBundle mainBundle].bundleIdentifier,
   APPPATH = [NSBundle mainBundle].bundlePath,
   APPHOME = NSHomeDirectory(),

   rootVC = function(){
       return UIApp.keyWindow.rootViewController;
   };

   keyWindow = function(){
       return UIApp.keyWindow;
   };

   getCurrentVC = function(rootVC){

       var currentVC;
       if([rootVC presentedViewController]){
           rootVC = [rootVC presentedViewController];
       }

       if([rootVC isKindOfClass:[UITabBarController class]]){
           currentVC = getCurrentVC(rootVC.selectedViewController);
       }
       else if([rootVC isKindOfClass:[UINavigationController class]]){
           currentVC = getCurrentVC(rootVC.visibleViewController);
       }
       else{
           currentVC = rootVC;
       }

       return currentVC;
   };

   currentVC = function(){
       return getCurrentVC(rootVC());
   };

})(exports);

  1. 重新运行项目,使用cyConnect.sh附加进程
  2. 同样导入脚本
@import test
-------------------------
{}
  1. 调用方法
  • 获取APPID
APPID
-------------------------
@"com.xxxxxx.MokeyDemo"
  • 获取APPPATH
APPPATH
-------------------------
@"/private/var/containers/Bundle/Application/D620C178-5030-48E4-9276-981150FF7299/MokeyDemo.app"
  • 获取APPHOME
APPHOME
-------------------------
@"/var/mobile/Containers/Data/Application/C2ED1E99-47C4-4C29-8AE6-9C5C136CEE04"
  • 调用currentVC()
currentVC()
-------------------------
#""

总结

  • Cycipt
    • 是一种脚本语言,兼容了多种语法(支持多种语法的解释器
    • Cycipt可以附加到进程,用来动态调试
      • 也可自定义脚本配置环境变量中,方便执行
    • 将常用功能封装为.cy文件

你可能感兴趣的:(19-Cycript)