2逆向 - Cycript

 

想知道当前运行的App的布局、实例方法、都是啥

想动态给当前App增加一些羞羞的东东?

...

嗯呐,就是这一节,你来对了!

概述

文档:Cycript

是Objective-C++、ES6、Java等语法的混合物

用途:探索、修改、调试正在运行的mac/iOS App

安装:Cydia安装

退出:ctl + D

一般会通过Cycript测试函数,确定函数的作用之后,再编写Tweak修改程序


基本用法

调试进程

cycript -p 进程ID(或名称)

获取进程ID和进程名称方法
ps指令(process status)  需Cydia安装adv-cmds
用法
ps -A 列出所有进程
ps -A|grep 关键词

示例:cycript -p momo_ios

此时已经在监听这个app了

常用语法

[UIApplication shareApplication] // 获取application对象内存地址  等价 UIApp

var app = UIApp.keyWindow // 获取keyWindow并赋值给变量app

UIApp.keyWindow.rootViewController // 获取rootViewController

var redView = [[UIView alloc] initWithFrame:CGRectMake(0,0,100,100)]; // 暂时报错,之后解决

// 获取对象 - 通过内存地址来访问
#内存地址.rootViewController

// ObjectiveC.classes - 当前App加载的要用到的所有类


// 查看对象的所有成员变量(示例:查看UIApp的)
*UIApp

//  递归打印view的所有子控件(同LLDB)
// po self.view
// po [self.view recursiveDescription] // 递归打印所有子View
// [UIApp.keyWindow recursiveDescription].toString // 转为String格式
终极格式:UIApp.keyWindow.recursiveDescription().toString()

// choose(UIViewController)  - 挑选内存中的所有控制器对象

封装cy文件

用法举例 - MJTool

gayhub地址

mjcript.cy

放置脚本到/usr/lib/cycript0.9/MJTool.cy

导入库:@import MJTool

问题:希望找到当前登录界面

一般方法需要一层一层拿

封装方法:MJTopVc() - 直接拿到最前面的VC

想知道点击登录的时候调用了那个方法

打印所有的对象方法名  MJInstanceMethodNames(控制器)

拿到方法名之后,可以直接调用这个控制器的方法

想在登录之前做些事情,可以Hook出这个函数,注入一些方法

希望找出文本框是谁,做些处理

先在文本框中输入一些东东

MJSubviews(目标View) - 拿到所有子View,通过输入的东东定位到是哪一个

用法演示

Yoe:~ root# cycript -p QuickMud-mobile
cy# @import mjcript
{}
cy# MJAppId
@"com.mkjump.mud"
cy# MJDocPath
@"/var/mobile/Containers/Data/Application/E5CA2CEA-CF2F-4D39-8684-6762EA60D1F6/Documents"
cy# MJCachesPath
@"/var/mobile/Containers/Data/Application/E5CA2CEA-CF2F-4D39-8684-6762EA60D1F6/Library/Caches"
cy# MJAppPath
@"/var/containers/Bundle/Application/BE34C307-5FBE-4707-A502-7AEDEA4F74BD/QuickMud-mobile.app"
cy# MJKeyWin
function (){return UIApp.keyWindow}
cy# MJKeyWin()
#"<UIWindow: 0x146db14d0; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x146ec7810>; layer = <UIWindowLayer: 0x146db1410>>"
cy# MJRootVc()
#"<RootViewController: 0x146ed47a0>"
cy# MJFrontVc()
#"<RootViewController: 0x146ed47a0>"
cy# var mapView = [[MKMapView alloc] init]
#"<MKMapView: 0x148ea1c80; frame = (0 0; 0 0); clipsToBounds = YES; layer = <CALayer: 0x14b223910>>"
cy# mapView.frame = MJRectMake(50,50,100,100)
{0:{0:50,1:50},1:{0:100,1:100}}
cy# [#0x146ed47a0.view addSubview:mapView]
cy# MJLoadFramework('MapKit')   # 如果当前App木有导入某动态库,可以通过这个东东加载进来
#"NSBundle </System/Library/Frameworks/MapKit.framework> (loaded)"


// 找所有的子VC们
#"<RootViewController: 0x146ed47a0>"
cy# MJChildVcs(#0x146ed47a0)
"<RootViewController 0x146ed47a0>, state: appeared, view: <CCEAGLView 0x146ed1300>"
cy# MJChildVcs(MJRootVc())
"<RootViewController 0x146ed47a0>, state: appeared, view: <CCEAGLView 0x146ed1300>"


封装举例

基本写法

// test.cy

(function(exports) {
  // 函数内部定义的函数是私有的,需要导出
  // function sum(a, b) {
  //   return a + b;
  // }
  // function minus(a, b) {
  //   return a - b;
  // }

  // 利用exports导出方法
  // 之后,可以使用 文件名.方法名() 使用这个脚本的方法
  exports.sum = function sum(a, b) {
      return a + b;
  };

  exports.minus = function minus(a, b) {
      return a - b;
  };


  //  这样写,是定义了一个全局的函数。
  //  调用的时候不用exports.docPath(), 直接docPath()即可
  docPath = functino() {
	return NSSearchPathForDirectoriesInDomains(NSMocumentDirectory, NSUserDomainMask, YES)[0];
  }
})(exports);

基本用法

把写好的脚本文件拷贝到iOS中路径: 

cy环境下,@import test.cy

封装总结

  1. .cy是Cycript的脚本文件
  2. exports用于向外提供一个接口

脚本放置封装路径

作者的脚本放置路径: 

原因:用域名来起文件夹,保证文件是唯一的

引用方式: @import com.azen.test 每一个.之间都是一个文件夹 如果放在了cycript0.9中,直接import就好

使用技巧


场景API示例备注
1知道对象在内存中,但不知道地址choose指令choose(SBScreenShotter)并非每次都一定能找到