逆向学习

逆向调试APP -- Cycript

2021-06-01  本文已影响0人  风雨彩虹_123

前言

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);
上一篇下一篇

猜你喜欢

热点阅读