逆向调试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:获取手机运行的进程信息
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.
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);