Cycript使用技巧(包含MJTool的使用介绍)

Cycript使用技巧

iproxy 2222 22   #转发端口
ssh -p 2222 [email protected] # 登录iphone, 输入密码
ps -A 或 ps aux 列出所有的进程
ps -A | grep `关键词` 搜索关键词


# 开启Cycript监听(进入iPhone服务端操作)
cycript
cycript -p 进程ID # [不推荐, 进程ID每次都会变]
cycript -p 进程名称  # 推荐使用, 进程名不会变


# cycript的语法
Ctrl + C : 取消输入
Ctrl + D : 退出Cycript监听
Common + R : 清屏
UIApp :[UIApplication sharedApplication]
var 变量名 = 变量值 :定义变量
#内存地址 :用内存地址获取对象
ObjectiveC.classes :当前app已加载的所有OC类
*对象 :查看对象的所有成员变量
view.recursiveDescription().toString() :递归打印view的所有子控件(跟LLDB一样的函数)
choose(UIViewController) :查看当前界面中,存在内中的UIViewController类型的对象
choose(UITableViewCell):筛选出UITableViewCell类型的对象

MJTool的安装及使用

  1. 先从Mac端拷贝个MJ的cy封装文件到iPhone端,scp -P 10011 [文件] root@localhost:/usr/lib/cycript0.9/MJTool.cy
  2. 连接登录到iPhone端,cycript监听网易云音乐进程(注意保持网易云音乐app是开启状态)
  3. 导入封装文件,查看当前界面
@import MJTool
MJFrontVc() #查看当前界面的控制器
MJInstanceMethodNames(#0x129c57f60)   # 打印控制器的所有方法
[#0x129c57f60 loginButtonClicked:nil] # 调用登录方法
  1. 找到账号框和密码框

  2. app账号框输入: 6666

     密码框输入: 8888
    

打印控制器的子view: 找到6666和8888, 即找到了账号框和密码框:

验证: 拿到账号框, 账号框输入7777, app的输入框数字也变为7777, 说明这个账号框是对的,

  1. 用MJTool.cy 看下该控制器的其他东西:

    6.1 类方法: MJClassMethodNames(#0x129c57f60)

    6.2 对象方法: MJInstanceMethodNames(#0x129c57f60)

  2. 删除登录按钮, 通过'登录转为unicode编码: \u767b\u5f55, 找到控件后执行删除操作:

[#0x129c4c6c0 removeFromSuperview]
  1. 添加个红色的view, 用到MJTool

    MJFrontVc()  # 找到当前界面的vc
    var redV = [[UIView alloc] init]
    redV.backgroundColor = [UIColor redColor]
    redV.frame = MJRectMake(10, 100, 100, 100)
    [#0x129c57f60.view addSubview:redV]
    
  2. MJTool工具中正则表达式使用-----筛选

cy# MJFrontVc()
#""

// 筛选带有login的对象方法,注意是匹配大小写的
cy# MJInstanceMethodNames(#0x129c57f60,/login/)
[&"loginButtonClicked:",&"loginView"]

// 筛选以View结尾的对象方法,注意大小写
cy# MJInstanceMethodNames(#0x129c57f60,/View$/)
[&"loginView",&"loadView"]

想知道当前view是如何划分结构的——使用MJTool.cy:

image.png

10、想知道控制器有哪些对象方法——使用MJTool.cy:
MJInstanceMethodNames(#0x12324432)
MJInstanceMethodNames(#0x12324432,/click/) // 筛选出带有click的

11、控制器有哪些成员变量——使用MJTool.cy:
MJIvarNames(#0x12324432)
MJIvarNames(#0x12324432,/click/) // 筛选出带有click的

12、获取某个类的所有子类——使用MJTool.cy:

//当前app有哪些UIViewController的子类
MJSubclasses(UIViewController)
MJSubclasses("UIViewController",/NMR/)

//查看app有哪些自定义导航控制器
MJSubclasses(UINavigationController)
MJSubclasses("UINavigationController")
MJSubclasses("UINavigationController",/NMR/)

13、改微信钱包零钱

大致步骤:

  1. 连接登录iPhone服务端,打开微信,进入微信钱包页面,搜索进程ps -A,监视微信进程cycript -p WeChat,导入工具@import MJTool
  2. MJFrontVc():当前控制器
  3. MJVcSubviews(#0x13e90c200):当前控制器的所有子view
  4. command + F 搜索零钱的数字,确定是哪个对象
  5. (#0x14065f880).text = '\xa5848,340.00',修改零钱
  6. (#0x14065f880).backgroundColor = [UIColor redColor],修改背景
  7. (#0x14065f880).frame = MJRectMake(0,85,320,13),修改宽高

14、修改变量:

cy# QLVipManager.prototype['isVipOrVipVisitor'] =  function(){return YES};
function (){return YES}
cy# QLVipManager.prototype['isValid'] =  function(){return YES};
function (){return YES}
cy# QLVipManager.prototype['isAnnualVipWithCache'] =  function(){return YES};
function (){return YES}
cy# QLVipManager.prototype['isVipOrVipVisitorWithCache'] =  function(){return YES};
function (){return YES}
cy# QLVipManager.prototype['isVipVisitorWithCache'] =  function(){return YES};
function (){return YES}
cy# QLVipManager.prototype['isVipWithCache'] =  function(){return YES};
function (){return YES}

MJTool.cy的代码

(function(exports) {
    var invalidParamStr = 'Invalid parameter';
    var missingParamStr = 'Missing parameter';

    // app id
    MJAppId = [NSBundle mainBundle].bundleIdentifier;

    // mainBundlePath
    MJAppPath = [NSBundle mainBundle].bundlePath;

    // document path
    MJDocPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];

    // caches path
    MJCachesPath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0]; 

    // 加载系统动态库
    MJLoadFramework = function(name) {
        var head = "/System/Library/";
        var foot = "Frameworks/" + name + ".framework";
        var bundle = [NSBundle bundleWithPath:head + foot] || [NSBundle bundleWithPath:head + "Private" + foot];
        [bundle load];
        return bundle;
    };

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

    // 根控制器
    MJRootVc =  function() {
        return UIApp.keyWindow.rootViewController;
    };

    // 找到显示在最前面的控制器
    var _MJFrontVc = function(vc) {
        if (vc.presentedViewController) {
            return _MJFrontVc(vc.presentedViewController);
        }else if ([vc isKindOfClass:[UITabBarController class]]) {
            return _MJFrontVc(vc.selectedViewController);
        } else if ([vc isKindOfClass:[UINavigationController class]]) {
            return _MJFrontVc(vc.visibleViewController);
        } else {
            var count = vc.childViewControllers.count;
            for (var i = count - 1; i >= 0; i--) {
                var childVc = vc.childViewControllers[i];
                if (childVc && childVc.view.window) {
                    vc = _MJFrontVc(childVc);
                    break;
                }
            }
            return vc;
        }
    };

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

    // 递归打印UIViewController view的层级结构
    MJVcSubviews = function(vc) { 
        if (![vc isKindOfClass:[UIViewController class]]) throw new Error(invalidParamStr);
        return vc.view.recursiveDescription().toString(); 
    };

    // 递归打印最上层UIViewController view的层级结构
    MJFrontVcSubViews = function() {
        return MJVcSubviews(_MJFrontVc(UIApp.keyWindow.rootViewController));
    };

    // 获取按钮绑定的所有TouchUpInside事件的方法名
    MJBtnTouchUpEvent = function(btn) { 
        var events = [];
        var allTargets = btn.allTargets().allObjects()
        var count = allTargets.count;
        for (var i = count - 1; i >= 0; i--) { 
            if (btn != allTargets[i]) {
                var e = [btn actionsForTarget:allTargets[i] forControlEvent:UIControlEventTouchUpInside];
                events.push(e);
            }
        }
       return events;
    };

    // CG函数
    MJPointMake = function(x, y) { 
        return {0 : x, 1 : y}; 
    };

    MJSizeMake = function(w, h) { 
        return {0 : w, 1 : h}; 
    };

    MJRectMake = function(x, y, w, h) { 
        return {0 : MJPointMake(x, y), 1 : MJSizeMake(w, h)}; 
    };

    // 递归打印controller的层级结构
    MJChildVcs = function(vc) {
        if (![vc isKindOfClass:[UIViewController class]]) throw new Error(invalidParamStr);
        return [vc _printHierarchy].toString();
    };

    


    // 递归打印view的层级结构
    MJSubviews = function(view) { 
        if (![view isKindOfClass:[UIView class]]) throw new Error(invalidParamStr);
        return view.recursiveDescription().toString(); 
    };

    // 判断是否为字符串 "str" @"str"
    MJIsString = function(str) {
        return typeof str == 'string' || str instanceof String;
    };

    // 判断是否为数组 []、@[]
    MJIsArray = function(arr) {
        return arr instanceof Array;
    };

    // 判断是否为数字 666 @666
    MJIsNumber = function(num) {
        return typeof num == 'number' || num instanceof Number;
    };

    var _MJClass = function(className) {
        if (!className) throw new Error(missingParamStr);
        if (MJIsString(className)) {
            return NSClassFromString(className);
        } 
        if (!className) throw new Error(invalidParamStr);
        // 对象或者类
        return className.class();
    };

    // 打印所有的子类
    MJSubclasses = function(className, reg) {
        className = _MJClass(className);

        return [c for each (c in ObjectiveC.classes) 
        if (c != className 
            && class_getSuperclass(c) 
            && [c isSubclassOfClass:className] 
            && (!reg || reg.test(c)))
            ];
    };

    // 打印所有的方法
    var _MJGetMethods = function(className, reg, clazz) {
        className = _MJClass(className);

        var count = new new Type('I');
        var classObj = clazz ? className.constructor : className;
        var methodList = class_copyMethodList(classObj, count);
        var methodsArray = [];
        var methodNamesArray = [];
        for(var i = 0; i < *count; i++) {
            var method = methodList[i];
            var selector = method_getName(method);
            var name = sel_getName(selector);
            if (reg && !reg.test(name)) continue;
            methodsArray.push({
                selector : selector, 
                type : method_getTypeEncoding(method)
            });
            methodNamesArray.push(name);
        }
        free(methodList);
        return [methodsArray, methodNamesArray];
    };

    var _MJMethods = function(className, reg, clazz) {
        return _MJGetMethods(className, reg, clazz)[0];
    };

    // 打印所有的方法名字
    var _MJMethodNames = function(className, reg, clazz) {
        return _MJGetMethods(className, reg, clazz)[1];
    };

    // 打印所有的对象方法
    MJInstanceMethods = function(className, reg) {
        return _MJMethods(className, reg);
    };

    // 打印所有的对象方法名字
    MJInstanceMethodNames = function(className, reg) {
        return _MJMethodNames(className, reg);
    };

    // 打印所有的类方法
    MJClassMethods = function(className, reg) {
        return _MJMethods(className, reg, true);
    };

    // 打印所有的类方法名字
    MJClassMethodNames = function(className, reg) {
        return _MJMethodNames(className, reg, true);
    };

    // 打印所有的成员变量
    MJIvars = function(obj, reg){ 
        if (!obj) throw new Error(missingParamStr);
        var x = {}; 
        for(var i in *obj) { 
            try { 
                var value = (*obj)[i];
                if (reg && !reg.test(i) && !reg.test(value)) continue;
                x[i] = value; 
            } catch(e){} 
        } 
        return x; 
    };

    // 打印所有的成员变量名字
    MJIvarNames = function(obj, reg) {
        if (!obj) throw new Error(missingParamStr);
        var array = [];
        for(var name in *obj) { 
            if (reg && !reg.test(name)) continue;
            array.push(name);
        }
        return array;
    };
})(exports);

到这里为止,都还只是借用cycript的封装,修改调试内存中的东西,还不能达到永久修改的目的。

参考文章: https://www.jianshu.com/p/c6c5571d871d

你可能感兴趣的:(Cycript使用技巧(包含MJTool的使用介绍))