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 root@192.168.2.6:/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
相关推荐
匹马夕阳4 分钟前
Vue 3中导航守卫(Navigation Guard)结合Axios实现token认证机制
前端·javascript·vue.js
你熬夜了吗?6 分钟前
日历热力图,月度数据可视化图表(日活跃图、格子图)vue组件
前端·vue.js·信息可视化
桂月二二6 小时前
探索前端开发中的 Web Vitals —— 提升用户体验的关键技术
前端·ux
hunter2062068 小时前
ubuntu向一个pc主机通过web发送数据,pc端通过工具直接查看收到的数据
linux·前端·ubuntu
qzhqbb8 小时前
web服务器 网站部署的架构
服务器·前端·架构
刻刻帝的海角8 小时前
CSS 颜色
前端·css
九酒8 小时前
从UI稿到代码优化,看Trae AI 编辑器如何帮助开发者提效
前端·trae
浪浪山小白兔9 小时前
HTML5 新表单属性详解
前端·html·html5
lee5769 小时前
npm run dev 时直接打开Chrome浏览器
前端·chrome·npm
2401_897579659 小时前
AI赋能Flutter开发:ScriptEcho助你高效构建跨端应用
前端·人工智能·flutter