iOS逆向篇——Cycript调试App

现在越狱后的手机都是自带安装了Cycriptadv-cmds,如果没有即添加软件源https://apt.bingner.com安装好。 先通过SSH登录到服务器(iPhone

ps 命令

  • 列出所有进程 ps -A(当前手机打开了腾讯动漫) 可以从上图找到11095腾讯动漫的进程idpid),ComicReader腾讯动漫的进程名称
  • 搜索进程:ps --A | grep 关键词
ruby 复制代码
i-57:~ root# ps -A | grep ComicReader
11095 ??         0:05.50 /var/containers/Bundle/Application/015C9AB9-4440-492F-911B-6DEC6915FBFC/ComicReader.app/ComicReader
11121 ttys000    0:00.01 grep ComicReader
i-57:~ root#
  • 附加App直接调试 cycript -p 进程名称/进程的编号
css 复制代码
cycript -p 11095
或者
cycript -p ComicReader
cy#
  • 获取BundleIdentifier
objectivec 复制代码
i-57:~ root# cycript -p 1369
cy# [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleIdentifier"]

启动和退出

  • 启动:cycript -p 进程名称
  • 退出:control + d
  • 清屏:command + r

Cycript 常用语法

  • UIApp = UIApplication.sharedApplication()
shell 复制代码
cy# UIApp
#"<UIApplication: 0x104f04470>"
  • 用内存地址获取对象:#内存地址
shell 复制代码
cy# #0x104f04470
#"<UIApplication: 0x104f04470>"
  • 查看对象的所有成员变量:*对象
java 复制代码
cy# *UIApp
{isa:UIApplication,_responderFlags:@error,_delegate:#"<TencentXGPushAppDelegate: 0x280e46cc0>",_remoteControlEventObservers:0,_topLevelNibObjects:null,_networkResourcesCurrentlyLoadingCount:0,_hideNetworkActivityIndicatorTimer:null,_statusBar:null,_statusBarRequestedStyle:0,_statusBarWindow:null,_observerBlocks:@[],_postCommitActions:@[],_postCommitActionsNeedToSynchronize:false,_mainStoryboardName:null,_idleModeController:null,_displayLayoutMonitor:null,_systemUserInterfaceStyle:0,_eventFetcher:#"<UIEventFetcher: 0x282264540>",_eventDispatcher:#"<UIEventDispatcher: 0x281569620>",_applicationFlags:@error,_keyCommandToken:#"<BSSimpleAssertion: 0x281445110; identifier: com.apple.backboard.hid.delivery; reason: 2-keycmds; valid: YES>",_physicalKeyCommandMap:@{},_physicalKeycodeMap:[NSOrderedSet orderedSetWithArray:@[]]],_alwaysHitTestsForMainScreen:false,_backgroundHitTestWindow:null,_appInfo:#"<_UIApplicationInfoParser: 0x2830656c0>",_actionsPendingInitialization:null,_idleTimerDisabledReasons:[NSSet setWithArray:@[]]],_keyRepeatAction:null,_currentTimestampWhenFirstTouchCameDown:0,_currentLocationWhereFirstTouchCameDown:{x:0,y:0},_saveStateRestorationArchiveWithFileProtectionCompleteUntilFirstUserAuthentication:false,_fenceTaskAssertion:null,_cachedSystemAnimationFence:null,_systemNavigationAction:null,_activityContinuationManager:#"<UIActivityContinuationManager: 0x28156e310>",__gestureEnvironment:#"<UIGestureEnvironment: 0x283061d50>",_forceStageObservable:null,_HIDGameControllerEventObserver:null,_HIDGameControllerEventQueue:null,_motionNotificationGenerator:null,_appState:#"<UISApplicationState: 0x281b633c0>",_applicationPushRegistry:#"<PKPushRegistry: 0x2838401e0>",_storyboardInitialMenu:null,_endpointMonitor:#"<BSServiceConnectionEndpointMonitor: 0x283861ef0; service: com.apple.frontboard.open; active>",optOutOfRTL:false,_isDisplayingActivityContinuationUI:false,_applicationWantsGESEvents:false,_shortcutService:null,___queuedOrientationChange:null,__expectedViewOrientation:1}
  • 递归打印view的所有子控件:view.recursiveDescription().toString()
scss 复制代码
UIApp.keyWindow.recursiveDescription().toString()
  • 定义变量:var 变量名 = 变量值
css 复制代码
cy# var window = UIApp.keyWindow
#"<UIWindow: 0x104f1be40; frame = (0 0; 375 667); gestureRecognizers = <NSArray: 0x281552d30>; layer = <UIWindowLayer: 0x281b753e0>>"
  • 定义函数:function 函数名(...) { ... }
shell 复制代码
cy# function sum(a, b) {return a+b;}
cy# sum(2,3)
5
  • 筛选出某种类型的对象:choose(类型)
scss 复制代码
cy# choose(UIViewController)
[#"<UISystemInputAssistantViewController: 0x106468630>",#"<UIEditingOverlayViewController: 0x10649e1d0>",#"<ComicHomeViewController: 0x105843000>",#"<ComicNavgationController: 0x105849000>",#"<VPlaygoundViewController: 0x10584e200>",#"<ComicNavgationController: 0x105850200>",#"<WaitHomeViewController: 0x105853a00>",#"<BookShelfViewController: 0x10585aa00>",#"<ComicNavgationController: 0x10585b000>",#"<MyViewController: 0x10585b600>",#"<ComicNavgationController: 0x10585bc00>",#"<ComicNavgationController: 0x105867400>",#"<UpdateChannelViewController: 0x105883a00>",#"<UpdateChannelSubViewController: 0x1058ee400>",#"<UpdateChannelSubViewController: 0x1058f5000>",#"<UIInputWindowController: 0x10595b000>",#"<ADWebViewController: 0x105972a00>",#"<ComicTabBarController: 0x105040400>",#"<ADWebViewController: 0x105137000>",#"<GenderSelectionViewController: 0x1051e8000>"]

.cy文件的应用

.cy文件是对Cycript的封装,方便提供一些比较常用的函数。

ini 复制代码
(function(exports) {
	var invalidParamStr = 'Invalid parameter';
	var missingParamStr = 'Missing parameter';

	// app id
	LBAppId = [NSBundle mainBundle].bundleIdentifier;
	// mainBundlePath
	LBAppPath = [NSBundle mainBundle].bundlePath;
	// document path
	LBDocPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
	// caches path
	LBCachesPath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0]; 

	// 加载系统动态库
	LBLoadFramework = 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
	LBKeyWin = function() {
		return UIApp.keyWindow;
	};

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

	// 找到显示在最前面的控制器
	var _LBFrontVc = function(vc) {
		if (vc.presentedViewController) {
        	return _LBFrontVc(vc.presentedViewController);
	    }else if ([vc isKindOfClass:[UITabBarController class]]) {
	        return _LBFrontVc(vc.selectedViewController);
	    } else if ([vc isKindOfClass:[UINavigationController class]]) {
	        return _LBFrontVc(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 = _LBFrontVc(childVc);
    				break;
    			}
    		}
	        return vc;
    	}
	};

	LBFrontVc = function() {
		return _LBFrontVc(UIApp.keyWindow.rootViewController);
	};

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

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

	// 获取按钮绑定的所有TouchUpInside事件的方法名
	LBBtnTouchUpEvent = 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函数
	LBPointMake = function(x, y) { 
		return {0 : x, 1 : y}; 
	};

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

	LBRectMake = function(x, y, w, h) { 
		return {0 : LBPointMake(x, y), 1 : LBSizeMake(w, h)}; 
	};

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

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

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

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

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

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

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

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

	// 打印所有的方法
	var _LBGetMethods = function(className, reg, clazz) {
		className = _LBClass(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 _LBMethods = function(className, reg, clazz) {
		return _LBGetMethods(className, reg, clazz)[0];
	};

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

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

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

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

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

	// 打印所有的成员变量
	LBIvars = 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; 
	};

	// 打印所有的成员变量名字
	LBIvarNames = 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);

lbtool.cy文件拷贝到iPhone/usr/lib/cycript0.9目录下

ruby 复制代码
scp /Users/mac/Desktop/lbtool.cy [email protected]:/usr/lib/cycript0.9
lbtool.cy                                     100% 6178   760.8KB/s   00:00
  • lbtool.cy文件用法 用@import + 文件名导入文件
ruby 复制代码
i-57:~ root# cycript -p 11424
cy# @import lbtool
{}

获取当前显示的控制器

shell 复制代码
cy# LBFrontVc()
#"<ACReaderViewController: 0x1048ae600>"

获取view的层级结构

xml 复制代码
cy# LBSubviews(LBFrontVc().view)
`<UIView: 0x117c54a40; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x283adab00>>
   | <ACReaderEngineView: 0x117c4b850; frame = (0 0; 375 667); autoresize = W+H; gestureRecognizers = <NSArray: 0x283483720>; layer = <CALayer: 0x283acd3c0>>
   |    | <ACZoomScrollView: 0x105b15600; baseClass = UIScrollView; frame = (0 0; 375 667); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x2834be790>; layer = <CALayer: 0x283acd660>; contentOffset: {0, 0}; contentSize: {0, 0}; adjustedContentInset: {0, 0, 0, 0}>
   |    |    | <UICollectionView: 0x105b19600; frame = (0 0; 375 667); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x283491920>; layer = <CALayer: 0x283acdbe0>; contentOffset: {0, 10}; contentSize: {375, 2130}; adjustedContentInset: {0, 0, 0, 0}; layout: <UICollectionViewFlowLayout: 0x11bf46e50>; dataSource: <ACReaderEngineView: 0x117c4b850; frame = (0 0; 375 667); autoresize = W+H; gestureRecognizers = <NSArray: 0x283483720>; layer = <CALayer: 0x283acd3c0>>>
最后小试牛刀把腾讯动漫底部充值view隐藏
bash 复制代码
cy# #0x11bfeb950.hidden = YES
true
相关推荐
疾风铸境7 分钟前
Qt5.14.2+mingw64编译OpenCV3.4.14一次成功记录
前端·webpack·node.js
晓风伴月11 分钟前
Css:overflow: hidden截断条件‌及如何避免截断
前端·css·overflow截断条件
最新资讯动态14 分钟前
使用“一次开发,多端部署”,实现Pura X阔折叠的全新设计
前端
爱泡脚的鸡腿29 分钟前
HTML CSS 第二次笔记
前端·css
灯火不休ᝰ1 小时前
前端处理pdf文件流,展示pdf
前端·pdf
智践行1 小时前
Trae开发实战之转盘小程序
前端·trae
最新资讯动态1 小时前
DialogHub上线OpenHarmony开源社区,高效开发鸿蒙应用弹窗
前端
lvbb661 小时前
框架修改思路
前端·javascript·vue.js
树上有只程序猿1 小时前
Java程序员需要掌握的技术
前端
从零开始学安卓1 小时前
Kotlin(三) 协程
前端