美文网首页逆向学习
逆向调试APP -- Cycript

逆向调试APP -- Cycript

作者: 风雨彩虹_123 | 来源:发表于2021-06-01 18:18 被阅读0次

    前言

    Cycript是混合OC,C++,JavaScript语法的脚本语言。所以我们能够在一个命令中使用OC,C++,JavaScript,甚至混合并用。它能够挂钩正在运行的进程,能够在运行时修改和调试程序。

    一、Cycript的安装与使用

    1.在越狱手机Cydia应用中下载安装Cycript;
    2.在越狱手机Cydia应用中下载安装adv-cmds;
    3.获取调试APP的进程ID或进程名称;
    ps -A:获取手机运行的进程信息

    截屏2021-05-31 下午6.17.32.png

    4.打开Cycript勾住淘票票进程,开始调试;

    //推荐使用进程名称,因一个应用的进程名称不会改变,进程ID会发生变化
    cycript -p 2542 或者  cycript -p MovieApp
    

    5.退出Cycript调试:ctrl + d

    二、Cycript常用语法

    //获取UIApplication单利对象
    UIApp : Cycript内置的快捷获取;
    [UIApplication sharedApplication]  : OC语法获取
    使用上面2个命令都可以获得"<DFApplication: 0x10af06060>",由此我们可以发现淘票票是基于UIApplication封装的DFApplication。
    
    //定义变量
    var app = UIApp.keyWindow  将Application的keyWindow赋值给app
    输入app 就可以得到UIWindow窗口,只要调试不退出,都可以使用app这个变量;
    
    //跟控制器
    UIApp.keyWindow.rootViewController
    
    //bundleid
    [NSBundle mainBundle].bundleIdentifier 
    
    //沙盒路径
    NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]
    
    //根据内存地址获取
    #0x10af06060  也可以获取到"<DFApplication: 0x10af06060>"
    
    //已加载的所用OC类
    ObjectiveC.classes   
    
    //查看对象的所有成员变量
    *UIApp
    
    //递归打印view的所有子控件(与LLDB调试相似)
    [UIApp.keyWindow recursiveDescription]  在控制台打印了很多view信息,看起来是比较凌乱的
    [UIApp.keyWindow recursiveDescription].toString()  现在是排版后打印信息。
    
    // 筛选出当前view上的所有控制器
    choose(UIViewController)
    

    三、封装Cycript调试工具

    1.使用sublime 创建LCLCycript.cy文件,设置编写格式为JavaScript;
    2.编写代码;

    //这个格式是固定的
    (function(exports){
          //加法函数封装
        exports sum = function (a, b){
            return a + b;
        }
    })(exports);
    

    3.将LCLCycript.cy文件拷贝到手机中;
    方式一:使用iFunBox工具,将文件直接拖拽到usr/lib/cycript0.9 目录下;
    方式二:scp -P 10010 ~/Desktop/LCLCycript.cy root@localhost:/usr/lib/cycript0.9
    4.使用Cycript调试淘票票时, 使用:@import LCLCycript 将封装的库导入;
    5.使用:LCLCycript.sum(10,20) ,在控制台打印30.

    截屏2021-06-01 下午6.18.12.png

    6.注意:每次LCLCycript.cy 变动后,要重复步骤3,步骤4(需要退出应用,重新勾住淘票票进程)

    (function(exports){
        //测试代码
        exports.sum = function (a, b){
            return a + b;
        }
        //对于不变的指,可以直接复制给变量。若值有变动需要用function函数
    
        //获取应用的bundleId(不变)
        exports.appId = [NSBundle mainBundle].bundleIdentifier;
    
        //获得根控制器(切换tabbar根控制器会变化)
        exports.rootVC = function(){
            return UIApp.keyWindow.rootViewController;
        };
    
        //获取document文件路径(不变)
        exports.docPath =  NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
    
        //找到显示在最前面的控制器
        var VC = function(vc){
            if (vc.presentedViewController) {
                return VC(vc.presentedViewController);
            }else if ([vc isKindOfClass:[UITabBarController class]]) {
                return VC(vc.selectedViewController);
            }else if ([vc isKindOfClass:[UINavigationController class]]) {
                return VC(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 = VC(childVC);
                        break;
                    }
                }
                return vc;
            }
        };
    
        exports.frontVC = function(){
            return VC(UIApp.keyWindow.rootViewController);
        };
    
        // 判断是否为字符串 "str" @"str"
        LCLIsString = function(str) {
            return typeof str == 'string' || str instanceof String;
        };
    
        var LCLClass = function(className) {
            if (!className) throw new Error(missingParamStr);
            if (LCLIsString(className)) {
                return NSClassFromString(className);
            } 
            if (!className) throw new Error(invalidParamStr);
            // 对象或者类
            return className.class();
        };
    
        // 打印所有的方法
        var LCLGetMethods = function(className, reg, clazz) {
            className = LCLClass(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 LCLMethods = function(className, reg, clazz) {
            return LCLGetMethods(className, reg, clazz)[0];
        };
    
        // 打印所有的方法名字
        var LCLMethodNames = function(className, reg, clazz) {
            return LCLGetMethods(className, reg, clazz)[1];
        };
    
        // 打印所有的对象方法
        exports.LCLInstanceMethods = function(className, reg) {
            return LCLMethods(className, reg);
        };
    
        // 打印所有的对象方法名字
        exports.LCLInstanceMethodNames = function(className, reg) {
            return LCLMethodNames(className, reg);
        };
    
        // 打印所有的类方法
        exports.LCLClassMethods = function(className, reg) {
            return LCLMethods(className, reg, true);
        };
    
        // 打印所有的类方法名字
        exports.LCLClassMethodNames = function(className, reg) {
            return LCLMethodNames(className, reg, true);
        };
    
        // 打印所有的成员变量
        exports.LCLIvars = 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; 
        };
    
        // 打印所有的成员变量名字
        exports.LCLIvarNames = 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);
    

    相关文章

      网友评论

        本文标题:逆向调试APP -- Cycript

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