美文网首页
Cycript使用技巧(包含MJTool的使用介绍)

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

作者: sws1314 | 来源:发表于2023-09-21 11:20 被阅读0次

    Cycript使用技巧

    iproxy 2222 22   #转发端口
    ssh -p 2222 root@127.0.0.1 # 登录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()
    #"<NMPhoneLoginViewController: 0x129c57f60>"
    
    // 筛选带有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的使用介绍)

          本文链接:https://www.haomeiwen.com/subject/uthzvdtx.html