iOS 逆向编程(十四)Cycript 语法入门

简介: iOS 逆向编程(十四)Cycript 语法入门

一、Cycript 语法简介

  • 根据 上一篇文章 进入 Cycript 调试模式之后,就需要通过脚本语言来进行操作调试了,比如:获取页面控制器获取对象属性手动调用对象方法页面上添加自己的UI…等等。
  • Cycript 也是有语法例子的,可以进去参考,命令格式:
命令 结果
UIApp 获取当前 App 的 Appdelegate 对象
UIApp.keyWindow 获取当前的keyWindow对象
UIWindow.keyWindow 获取当前的keyWindow对象
var 定义一个对象
#内存地址 获得当前内存地址的对象
#内存地址 获得当前内存地址的对象
*对象 获得对象的所有成员变量
choose(UILabel) 查找当前界面的所有UILabel

  • 在进入cycript调试环境后,就可以直接写OCJS… 等支持的语法了,例如:
  • OC(其实也就是跟 OC 语法非常非常像的语法格式):
cy# [UIApp description]
@"<NMApplication: 0x113d4d710>"
  • UIApp 等于 UIApplication 对象,这两种写法都一样,脚本给与的缩写。
cy# UIApp
#"<NMApplication: 0x113d4d710>"
  • JS
cy# [for (x of [1,2,3]) x+1]
[2,3,4]

二、定义变量

  • 不支持 OC 里面那种 NSString *name = @"dzm" 这种写法
$ var 变量名 = 变量值
• 1
// 进入调试
iPhone:~ root# cycript -p neteasemusic
// 创建变量 window
cy# var window = UIApp.keyWindow
#"<OTTouchObservingWindow: 0x10a65b610; baseClass = UIWindow; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x28043da10>; layer = <UIWindowLayer: 0x280af58a0>>"
// 输出变量 window 跟上面的 UIApp.keyWindow 值一致
cy# window
#"<OTTouchObservingWindow: 0x10a65b610; baseClass = UIWindow; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x28043da10>; layer = <UIWindowLayer: 0x280af58a0>>"

三、获取常用对象(举例)

  • UIApp 等于 UIApplication 对象。
cy# [UIApp description]
@"<NMApplication: 0x113d4d710>"
cy# UIApp
#"<NMApplication: 0x113d4d710>"
  • 获取 keyWindow 对象(OTTouchObservingWindow 其实就是 UIWindow,只是编译之后 iOS 内部做了转换)。
cy# UIApp.keyWindow
#"<OTTouchObservingWindow: 0x10a65b610; baseClass = UIWindow; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x281ac01e0>; layer = <UIWindowLayer: 0x28146e0a0>>"
  • 获取 rootViewController
cy# UIApp.keyWindow.rootViewController
#"<NMRootNavigationController: 0x10a8cd400>"

四、内存地址访问对象

  • 获取到 keyWindow 的内存地址 0x10a65b610
cy# UIApp.keyWindow
#"<OTTouchObservingWindow: 0x10a65b610; baseClass = UIWindow; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x281ac01e0>; layer = <UIWindowLayer: 0x28146e0a0>>"
  • 可以通过 #0x10a65b610 这种方式通过内存地址访问这个对象,你会发现跟上面输出 的对象是一样的:
cy# #0x10a65b610
#"<OTTouchObservingWindow: 0x10a65b610; baseClass = UIWindow; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x28043da10>; layer = <UIWindowLayer: 0x280af58a0>>"
  • 也可以通过内存地址的方式获取该对象下面的其他属性值:
cy# #0x10a65b610.rootViewController
#"<NMRootNavigationController: 0x10a8cd400>"

五、ObjectiveC.classes 获取已加载的所有OC类

  • ObjectiveC.classes:你可以理解成获取列出来所有的 .h 头文件或者 class 对象,就是列出当前已经加载所有类。
cy# ObjectiveC.classes
{
 // 系统类 
 __NSGenericDeallocHandler:__NSGenericDeallocHandler,_NSZombie_:_NSZombie_,__NSMessageBuilder:__NSMessageBuilder,.....
 // 自定义类
 RMLog:RMLog,NMSearchShowCell,NMSearchPlaylistCell:NMSearchPlaylistCell,NMDjRadioPurchaseProgramCell:NMDjRadioPurchaseProgramCell,......
}
  • 这样一看做 iOS 都知道啥意思了,都是类名,自定义类,Cell 之类的。

六、查看对象的所有成员变量

  • 在后面经常会需要知道 某个对象 里面有哪些成员 变量 或者 属性
  • 只需要在对象前面加个 * 号即可,例如:*UIApp :
cy# *UIApp
{isa:NSKVONotifying_NMApplication,_hasOverrideClient:0,_hasOverrideHost:0,_hasInputAssistantItem:0,_delegate:#"<NMAppDelegate: 0x2838b2010>",_event:#"<UIEvent: 0x2804cdce0>",_motionEvent:#"<UIMotionEvent: 0x2831b4d00> timestamp: 0 subtype: 0",_remoteControlEvent:#"<UIRemoteControlEvent: 0x28149b1c0>",_remoteControlEventObservers:1,_topLevelNibObjects:null,_networkResourcesCurrentlyLoadingCount:0,_hideNetworkActivityIndicatorTimer:null,_editAlertController:null,_statusBar:#"<UIStatusBar: 0x10a863800; frame = (0 0; 320 20); opaque = NO; autoresize = W+BM; layer = <CALayer: 0x280a8ab20>>",_statusBarRequestedStyle:0,_statusBarWindow:#"<UIStatusBarWindow: 0x10a6561d0; frame = (0 0; 320 568); opaque = NO; gestureRecognizers = <NSArray: 0x280438930>; ......}
  • 上面的所有属性都是以 , 逗号分开,每一个逗号就是一个成员变量。
    挑个出来看看,比如 代理属性,前面是 属性名称,后面是
_delegate:#"<NMAppDelegate: 0x2838b2010>"

七、递归打印 View 的所有子控件

  • iOS开发中,可以通过控制台 LLDB打断点后po的方式递归输出指定视图的所有子控件。
  • 语法 po [self.view.window recursiveDescription]
(lldb) po [self.view.window recursiveDescription]
 <UIWindow: 0x7f9f8b618460; frame = (0 0; 375 667); gestureRecognizers = <NSArray: 0x60000077a1c0>; layer = <UIWindowLayer: 0x600000926de0>>
    | <UITransitionView: 0x7f9f8b719630; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x60000093b300>>
    |    | <UIDropShadowView: 0x7f9f8b71a060; frame = (0 0; 375 667); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x60000093b280>>
    |    |    | <UIView: 0x7f9f8b719ef0; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x60000093b2c0>>
 <UIWindow: 0x7f9f8b618460; frame = (0 0; 375 667); gestureRecognizers = <NSArray: 0x60000077a1c0>; layer = <UIWindowLayer: 0x600000926de0>>
    | <UITransitionView: 0x7f9f8b719630; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x60000093b300>>
    |    | <UIDropShadowView: 0x7f9f8b71a060; frame = (0 0; 375 667); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x60000093b280>>
    |    |    | <UIView: 0x7f9f8b719ef0; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x60000093b2c0>>
  • Cycript 里面递归输出子控件,其实也是使用 recursiveDescription
cy# [UIApp.keyWindow recursiveDescription]
......
cy# [UIApp.keyWindow recursiveDescription].toString()
......
  • 由于输出太多我就不贴了,跟上面 iOS 中一样,一层一层的列出来。一种是递归列出所有子控件,一种是将列出的子控件转成字符串输出,两者没什么区别,就是排版的区别,都可以。

七、choose 删选出指定类型的对象

  • 意思是:指定一个类,只要是继承或者等于这个类的都会被列出来,只会列出已加载到缓存中。
  • 例如 UIViewController,列出当前已加载到缓存是继承或者直接使用 UIViewController 的,网易云首页举例
cy# choose(UIViewController)
  • 输出:
    [#"<NMVoiceHomeViewController: 0x11a400200>",#"<NMSettingTabViewController: 0x11a404020>",#"<NMSingTabViewController: 0x11a407540>",#"<NMContainerViewController: 0x11a409ce0>",#"<NMContainerViewController: 0x11a414d60>",#"<NMMainViewController: 0x10a6d8780>",#"<NMContainerViewController: 0x10a5f5220>",#"<NMMineTabViewController: 0x10a5f6910>",#"<NMContainerViewController: 0x11a519390>",#"<NMContainerViewController: 0x11a52f3f0>",#"<NMTabBarController: 0x10b946000>",#"<NMNavigationController: 0x10b9a7000>",#"<NMNavigationController: 0x10b9cc400>",#"<NMNavigationController: 0x10b9d6c00>",#"<NMNavigationController: 0x10b9e0200>",#"<NMNavigationController: 0x10b9ea600>",#"<NMNavigationController: 0x10a83f400>",#"<NMRootNavigationController: 0x10a8cd400>",#"<NMNavigationController: 0x10a8e7200>",#"<NMNavigationController: 0x10a912a00>",#"<NMNavigationController: 0x10a919c00>",#"<NMNavigationController: 0x10a975800>"]
    上面这些就是当前软件已经加载到缓存的控制器,且都是继承或者等于 UIViewController
    如果一个都没有则为空数组,如果输出崩溃,则重新进入调试模式即可:
cy# choose(UITableViewCell)
[]
  • 现在只是语法大致了解一下,后面会通过 Cycript 写一些脚本用来快捷调试,比如:拿到当前正在显示的控制器,这个就可以充利用上面的属性获取方式以及 iOS 开发中的获取控制器方式配合来获取了。
  • 后面会写到封装这样一个脚本,毕竟这个会很方便的帮我们找到当前控制器,也就知道在哪个文件可以做调整了。

相关文章
|
2月前
|
移动开发 前端开发 数据安全/隐私保护
iOS代码混淆-从入门到放弃
iOS代码混淆-从入门到放弃
21 0
|
3月前
|
移动开发 前端开发 数据安全/隐私保护
iOS 代码混淆 - 从入门到放弃
iOS 代码混淆 - 从入门到放弃
|
6月前
|
iOS开发
实战编程·使用SwiftUI从0到1完成一款iOS笔记App(五)(3)
实战编程·使用SwiftUI从0到1完成一款iOS笔记App(五)
64 0
|
6月前
|
前端开发 数据处理 iOS开发
实战编程·使用SwiftUI从0到1完成一款iOS笔记App(五)(2)
实战编程·使用SwiftUI从0到1完成一款iOS笔记App(五)
51 0
|
6月前
|
iOS开发 Kotlin 容器
实战编程·使用SwiftUI从0到1完成一款iOS笔记App(五)(1)
实战编程·使用SwiftUI从0到1完成一款iOS笔记App(五)
55 0
|
6月前
|
存储 缓存 前端开发
实战编程·使用SwiftUI从0到1完成一款iOS笔记App(四)(2)
实战编程·使用SwiftUI从0到1完成一款iOS笔记App(四)
50 0
|
6月前
|
前端开发 Swift iOS开发
实战编程·使用SwiftUI从0到1完成一款iOS笔记App(四)(1)
实战编程·使用SwiftUI从0到1完成一款iOS笔记App(四)
98 0
|
6月前
|
存储 PHP Swift
实战编程·使用SwiftUI从0到1完成一款iOS笔记App(三)(2)
实战编程·使用SwiftUI从0到1完成一款iOS笔记App(三)
68 0
|
2月前
|
API 数据安全/隐私保护 iOS开发
利用uni-app 开发的iOS app 发布到App Store全流程
利用uni-app 开发的iOS app 发布到App Store全流程
95 3