前言

Cycript 是一个能够理解Objective-C语法的javascript解释器, 它能够挂钩正在运行的进程, 以在运行时修改很多东西, 一般我们用于动态调试应用, 一般来说如果要调试的代码是用OC编写的,用cycript调试会很方便, 如果是用C编写的,通过lldb来调试了.

  • 安装Cycript

官网地址:
Github地址:

  • @import Substrate, so we can use MS.hookFunction
cy# @import com.saurik.substrate.MS
iPhone:/usr/lib/cycript0.9/com/saurik/substrate root# ls -lrt
total 4
-rw-r--r-- 1 root staff 1968 Jan 11  2016 MS.cy

刚开始分析逆向的时候,常常利用它进行控制器class的定位,完成类似功能的工具有AFlexLoader

注入方式

cycript注入

cycript注入动态库的方式,这必须要在越狱环境下才能实现。

cycript的原理是动态库注入,但是其动态库注入的原理,与我们常见的通过LC_LOAD_DYLIB在可执行文件中注入动态库不同. cycript的操作是 : 抓取到要挂载的应用, 由于越狱机上拥有权限,所以直接在挂载的进程上创建一个挂起的线程, 然后在这个线程里申请一片用于加载动态库的内存,然后恢复线程,动态库就被注入。
  • 二次打包动态库的注入

二次打包动态库的注入,是通过修改可执行文件的Load Commands来实现的. 在Load Commands中增加一个LC_LOAD_DYLIB , 写入dylib路径,这样程序执行的时候, 就会编译这个 LC_LOAD_DYLIB 找到要注入的 dylib,加载动态库 .

Powerful private methods

  • _ivarDescription
  • _shortMethodDescription
  • nextResponder
  • _autolayoutTrace
  • recursiveDescription
  • _methodDescription

cycript的常用命令

  • 格式化
.toString()
  • 根据地址获取对象。
#address
cy# [#0x1031f9b0]
[#"<UILabel: 0x1031f9b0; frame = (32.5 236.738; 255 20.4378); text = '\xe5\xbc\x80\xe9\x80\x9a\xe6\x8c\x87\xe7\xba\xb9\xe6\x94\xaf\xe4\xbb\x98\xef\xbc\x8c\xe8\xae\xa9\xe4\xbb\x98\xe6\xac\xbe\xe6\x9b\xb4\xe5\xae\x89\xe5\x85\xa8\xe4\xbe\xbf\xe6\x8d\xb7'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x1031f900>>"]
  • bundleIdentifier
 [[NSBundle mainBundle] bundleIdentifier]
  • 可执行文件
[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask][0]
  • 先查找进程名称
iPhone:~ root# ps -e |grep  /var/mobile*
  • Inject Into Processes
iPhone:~ root# cycript -p Moon
  • Objective-C Messages
cy# [UIApp description]
@"<DFApplication: 0x4870560>"
cy# [#0x4870560 _ivarDescription].toString()
`<DFApplication: 0x4870560>:
in DFApplication:
in UIApplication:
\t_delegate (<UIApplicationDelegate>*): <DFClientDelegate: 0x4878510>
  • JavaScript Extensions
cy# [for (x of [1,2,3]) x+1]
[2,3,4]
  • Bridged Object Model
cy# choose(CALayer) instanceof Array
true
  • Foreign Function Calls
cy# var a = malloc(128)
(typedef void*)(0x8b00b90)
  • Magical Tab-Complete
cy# a = ({m: 4, b: 5})
{m:4,b:5}
cy# a["m"]
4
  • C++11 Lambda Syntax
cy#  [&](int a)->int{return a}
(extern "C" int 80904192(int))

打印出当前界面的view层级

cy# UIApp.keyWindow.recursiveDescription().toString()
`<UIWindow: 0x16df0a70; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x16ec15a0>; layer = <UIWindowLayer: 0x16df0db0>>
   | <UILayoutContainerView: 0x16ecea00; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x16e0a3e0>>
   |    | <UITransitionView: 0x16e09400; frame = (0 0; 320 568); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x16e09270>>
   |    |    | <UIViewControllerWrapperView: 0x1804b890; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x1802a180>>
   |    |    |    | <UILayoutContainerView: 0x16f550d0; frame = (0 0; 320 568); autoresize = W+H; gestureRecognizers = <NSArray: 0x1803b010>; layer = <CALayer: 0x16f55180>>
   |    |    |    |    | <UINavigationTransitionView: 0x18037850; frame = (0 0; 320 568); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x180379a0>>
   |    |    |    |    |    | <UIViewControllerWrapperView: 0x18075800; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x180758a0>>
   |    |    |    |    |    |    | <UIView: 0x181009f0; frame = (0 64; 320 504); autoresize = W+H; layer = <CALayer: 0x18100a80>>
   |    |    |    |    |    |    |    | <UIView: 0x19316d10; frame = (0 0; 320 504); autoresize = W+H; layer = <CALayer: 0x19316ca0>>
   |    |    |    |    |    |    |    |    | <WXRootView: 0x182de340; frame = (0 0; 320 504); layer = <CALayer: 0x182dfcd0>>
   |    |    |    |    |    |    |    |    |    | <WXView: 0x182ddb10; frame = (0 0; 320 504); layer = <WXLayer: 0x16deb050>>
   |    |    |    |    |    |    |    |    |    |    | <WXView: 0x182f8ae0; frame = (0 0; 320 0); layer = <WXLayer: 0x182db010>>
   |    |    |    |    |    |    |    |    |    |    | <WXView: 0x182dbc10; frame = (0 0; 320 29.5); layer = <WXLayer: 0x182e2c40>>
   |    |    |    |    |    |    |    |    |    |    |    | <WXImageView: 0x182133a0; baseClass = UIImageView; frame = (13 6; 17 17); clipsToBounds = YES; opaque = NO; layer = <WXLayer: 0x182de5e0>>
   |    |    |    |    |    |    |    |    |    |    |    | <WXText: 0x193435b0; text
cy# 

通过view的nextResponder方法,可以找出它所属的视图控制器ViewController

cy# [#0x181009f0 nextResponder]
#"<MoonWXParentViewController: 0x18100e30>"

接下来就可以对MoonWXParentViewController 进行hook分析

Powerful private methods for debugging in Cycript & LLDB

_printHierarchy

Shortcut to find the ViewController’s class name on the keyWindow

快捷的获取 ViewController 的方法。

cy# [[[UIWindow keyWindow] rootViewController] _printHierarchy].toString()
`<DFNavigationController 0x5857400>, state: appeared, view: <UILayoutContainerView 0x8c1aa10>
   | <ALPLauncherController 0x876f370>, state: disappeared, view: <UILayoutContainerView 0x876f700> not in the window
   |    | <HPHomeWidgetGroup 0x58a0800>, state: disappeared, view: <DTBaseView 0x87b1390> not in the window
   |    |    | <HCHomeCardViewController 0x592b000>, state: disappeared, view: <DTBaseView 0xc32ceb0> not in the window
   |    | <O2OIndexViewController 0x4891a00>, state: disappeared, view: <DTBaseView 0x8ca2ed0> not in the window
   |    | <APContactRecentViewController 0x4871e00>, state: disappeared, view: <DTBaseView 0x477c790> not in the window
   |    | <WWAssetsViewController 0x58ad600>, state: disappeared, view: <DTBaseView 0x87c1820> not in the window
   | <H5WebViewController 0x5b3e400>, state: disappeared, view: <DTBaseView 0xfafb810> not in the window
   | <H5WebViewController 0x5b9d800>, state: disappeared, view: <DTBaseView 0x1104c140> not in the window
   | <H5WebViewController 0x5822600>, state: appeared, view: <DTBaseView 0xd8e9180>`

支持iOS8之后

_ivarDescription

Prints all names and values of instance variables of a specified object

比一个一个打印属性方便多了

cy# [#0x5822600 _ivarDescription].toString()
cy# [#0x5822600 _ivarDescription].toString()
`<H5WebViewController: 0x5822600>:
in H5WebViewController:
\t_fontScale (NSString*): @"100%"<__NSCFConstantString: 0x338132c>
\t_is3DTouchPeek (BOOL): 0
\t_is3DTouchPop (BOOL): 0
\t_gestureBack (BOOL): 0
\t_isFromNavigationBarHidden (BOOL): 0
\t_webPageLoadSuccess (BOOL): 1
\t_isBackProcessing (BOOL): 0
\t_isBackProcessed (BOOL): 0
\t_hideLeftButtonsByJs (BOOL): 0
\t_isDefaultOptionMenu (BOOL): 0
\t_isWebViewBackgroundColorSetted (BOOL): 1
\t_pullRefreshing (BOOL): 1
\t_isFromStatusBarHidden (BOOL): 0
\t_isInitAsSubView (BOOL): 0
\t_isDissmissProcess (BOOL): 0
\t_isAphaOverLimit (BOOL): 0
\t_isWebLoading (BOOL): 0
\t_isWebFinishLoad (BOOL): 1
\t_isViewAppeared (BOOL): 1
\t_isViewAppearAgain (BOOL): 0
\t_isViewWillDisAppear (BOOL): 0
\t_isViewDidDisAppear (BOOL): 0
\t_isAlipaySchemeWillRedirect (BOOL): 0
\t_isAlipaySchemeDidRedirect (BOOL): 0
\t_isAddObserver (BOOL): 0
\t_isFromStartApp (BOOL): 0
\tname (NSString*): nil
\t_serviceDelegate (<H5ServiceDelegate>*): nil
\t_contentView (PSDView*): nil
\t_delegate (<PSDViewControllerDelegate>*): <PSDScene: 0x11067380>
\t_statesView (UIView*): <UIView: 0xd9fa5d0>
\t_customPreviewActionItems (NSArray*): nil
\t_interceptUrl (NSString*): nil
\t_appConfig (NSDictionary*): nil
\t_url (NSURL*): https://render.alipay.com/p/f/fd-j6lzqrgm/addressbook.html
\t_lastPageId (NSString*): nil
\t_refreshHeaderView (AUPullLoadingView*): nil
\t_stickyBouncer (H5StickyBouncer*): nil
\t_backDate (NSDate*): nil
\t_backBtnPressCount (int): 0
\t_serverErrorView (APExceptionView*): nil
\t_fontBar (H5AdjustFontControl*): nil
\t_statusBarStyle (int): 0
\t_htmlZoomValue (NSString*): @"1"<__NSCFString: 0x11130b50>
\t_lastMainRequest (NSURLRequest*): <NSMutableURLRequest: 0x11064ac0>
\t_failureNumber (int): 0
\t_webviewDomainLabel (UILabel*): <UILabel: 0xfb63630>
\t_delayExecList (NSMutableArray*): <__NSArrayM: 0x110794a0>
\t_paddingBottom (float): 0
\t_externNativeApiManager (H5ExternNativeApiManager*): <H5ExternNativeApiManager: 0x11089e10>
\t_startLoadTime (NSDate*): <__NSDate: 0x11102510>
\t_co
cy# [#0x5822600 url]
#"https://render.alipay.com/p/f/fd-j6lzqrgm/addressbook.html"

_autolayoutTrace

展示的架构是基于layout

cy# [[UIApp keyWindow] _autolayoutTrace].toString()
`
UIWindow:0x46c54d0
|   UILayoutContainerView:0x8c1aa10
|   |   UINavigationTransitionView:0x8757090
|   |   |   UIViewControllerWrapperView:0xb68c2d0
|   |   |   |   DTBaseView:0xd8e9180
|   |   |   |   |   H5WebView:0x46ba350
|   |   |   |   |   |   UILabel:0xfb63630'\u7f51\u9875\u7531 render.alipay.com \u63d0\u4f9b'
|   |   |   |   |   |   _UIWebViewScrollView:0xfaaacf0
|   |   |   |   |   |   |   UIWebBrowserView:0x5984a00
|   |   |   |   |   |   |   UIImageView:0xfaa4850
|   |   |   |   |   |   |   UIImageView:0xfaaa940
|   |   |   |   |   UIView:0xd9fa5d0
|   |   |   |   |   NBProgressView:0x1108ae60
|   |   |   |   |   |   UIView:0x1108c790
|   |   APNavigationBar:0x8734d50
|   |   |   _UINavigationBarBackground:0x8735800
|   |   |   |   _UIBackdropView:0x11106fd0
|   |   |   |   |   _UIBackdropEffectView:0x111018d0
|   |   |   |   |   UIView:0x11111bb0
|   |   |   |   UIImageView:0x8735c20
|   |   |   H5NavigationTitleView:0x1114f680
|   |   |   |   UIControl_mainTitleConten...:0xfbf7f70
|   |   |   |   |   UILabel:0x11100e30'\u901a\u8baf\u5f55\u670b\u53cb'
|   |   |   |   UIControl_subtitleContent...:0xfbf7a90
|   |   |   |   |   UILabel:0xb6f4050
|   |   |   |   UIControl_rightIconConten...:0xb681ca0
|   |   |   |   |   UIImageView:0xfbfa810
|   |   |   UIView:0x46a0090
|   |   |   AUBarButtonItemButton_bac...:0x11146fb0
|   |   |   |   UIImageView:0x1112ffe0
|   |   |   |   UILabel:0xfb8a8c0'\u8fd4\u56de'
|   |   |   _UINavigationBarBackIndicatorView:0x8c0a660`

查看安装的app进程

iPhone:~ root# ps -e |grep  /var/mobile*
  333 ??         0:13.39 /var/mobile/Containers/Bundle/Application/DB9E7889-BC60-4B5C-91BD-E59D08204958/WeChat.app/WeChat
  552 ??         0:34.13 /var/mobile/Containers/Bundle/Application/239A0B7E-AA8C-4E43-873D-16254934321A/Taobao4iPhone.app/Taobao4iPhone
  635 ??         5:42.15 /var/mobile/Containers/Bundle/Application/3FDB82B6-8D3A-47BF-A27C-184D1E052854/AlipayWallet.app/AlipayWallet
  923 ??         0:01.37 /var/mobile/Containers/Bundle/Application/3A5795F5-1E2B-42B6-A904-D7BF2178D5EB/KillOneMosquito.app/KillOneMosquito
  928 ttys000    0:00.01 grep /var/mobile

cycript @import

  • MS
/usr/lib/cycript0.9/com

MS.cy 位于/usr/lib/cycript0.9/com/saurik/substrate 因此可以使用`cy# @import com.saurik.substrate.MS
`进行导入。

Install to utils.cy to /usr/lib/cycript0.9/com/tyilo:

mkdir -p /usr/lib/cycript0.9/com
git clone https://github.com/Tyilo/cycript-utils.git /usr/lib/cycript0.9/com/tyilo
Then in cycript:

cy# @import com.tyilo.utils; 0
  • 此时可以借助apt 进行安装git
iPhone:~ root# apt-get install git
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following extra packages will be installed:
  curl expat
The following NEW packages will be installed:
  curl expat git
0 upgraded, 3 newly installed, 0 to remove and 16 not upgraded.
Need to get 3065kB of archives.
After this operation, 21.1MB of additional disk space will be used.
Do you want to continue [Y/n]? y
WARNING: The following packages cannot be authenticated!
  curl expat git
Install these packages without verification [y/N]? y
Get:1 http://apt.saurik.com ios/1141.14/main curl 7.33.0-9 [276kB]
Get:2 http://apt.saurik.com ios/1141.14/main expat 2.0.1-3 [69.3kB]
Get:3 http://apt.saurik.com ios/1141.14/main git 2.8.1-5 [2720kB]
Fetched 3065kB in 25s (120kB/s)                                                                                                                                           
Selecting previously unselected package curl.
(Reading database ... 1926 files and directories currently installed.)
Preparing to unpack .../curl_7.33.0-9_iphoneos-arm.deb ...
Unpacking curl (7.33.0-9) ...
Selecting previously unselected package expat.
Preparing to unpack .../expat_2.0.1-3_iphoneos-arm.deb ...
Unpacking expat (2.0.1-3) ...
Selecting previously unselected package git.
Preparing to unpack .../git_2.8.1-5_iphoneos-arm.deb ...
Unpacking git (2.8.1-5) ...
Setting up curl (7.33.0-9) ...
Setting up expat (2.0.1-3) ...
Setting up git (2.8.1-5) ...

apt-get 第一次通过Lydia下载“APT0.6 Transitional" 之后可以先update

iPhone:~ root#  git -c http.sslVerify=false clone https://github.com/zhangkn/cycript-utils.git /usr/lib/cycript0.9/com/tyilo
Cloning into '/usr/lib/cycript0.9/com/tyilo'...
remote: Counting objects: 46, done.
remote: Total 46 (delta 0), reused 0 (delta 0), pack-reused 46
Unpacking objects: 100% (46/46), done.
Checking connectivity... done.

choose : a = choose(MyClass) 当前堆栈中查找到特定类的对象数据 Effortless Exploration

返回值是一个 数组,表示在当前堆栈中查找到的所有MyClass类的对象数据。

  • Effortless Exploration
cy# a = choose(UILabel).toString()
"<UILabel: 0x1031f9b0; frame = (32.5 236.738; 255 20.4378); text = '\u5f00\u901a\u6307\u7eb9\u652f\u4ed8\uff0c\u8ba9\u4ed8\u6b3e\u66f4\u5b89\u5168\u4fbf\u6377'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x1031f900>>,<UILabel: 0x10321c70; frame = (13.2267 349.997; 255 19.1604); text = '\u6211\u5df2\u9605\u8bfb\u5e76\u540c\u610f\u300a\u6307\u7eb9\u652f\u4ed8\u76f8\u5173\u534f\u8bae\u300b'; gestureRecognizers = <NSArray: 0x103224d0>; layer = <_UILabelLayer: 0x10321d30>>,<UILabel: 0x1032c0e0; frame = (0 0; 0 0); text = ''; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x1032c1a0>>,<UILabel: 0x10338a60; frame = (62 0; 34 47); text = '\u8d26\u5355'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0xe2eeb30>>,<UILabel: 0x10338ee0; frame = (0 58; 90 15.509); text = '\u52a0\u8f7d\u4e2d'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x1ad6cde0>>,<VZFTextNodeBackingView: 0x10344f10; baseClass = UILabel; frame = (6 74.5; 82.5 15.5); text = '\u798f\u5eb7\u4fdd\u5065\u4e2d\u5fc3(\u97f6\u5c71\u5357\u8def\u5e97)'; userInteractionEnabled = NO; layer = <VZFTextNodeBackingLayer: 0x10385e00>>,<UILabel: 0x103d5100; frame = (0 105; 0 0); text = ''; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x10307af0>>,<UILabel: 0x103e3790; frame = (62 0; 34 47); text = '\u4f59\u989d'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x103e73a0>>,<UILabel: 0x103e3970; frame = (98 0; 191 47); text = '13.09 \u5143'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x103e3a30>>,<UILabel: 0xc40b010; frame = (2.5 36.4385; 75 13.123); text = '\u5145\u503c\u4e2d\u5fc3'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x8bf21a0>>,<UILabel: 0xc40bbe0; frame = (2.5 36.4385; 75 13.123); text = '\u751f\u6d3b\u7f34\u8d39'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x8be6bb0>>,<UILabel: 0xc4156a0; frame = (2.5 36.4385; 75 13.123); text = '\u829d\u9ebb\u4fe1\u7528'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x8beb6d0>>,<UILabel: 0xc416fe0; frame = (0 0; 0 0); userInteractionE
cy# a

hook OC函数

MS.HookMessage : 这个函数的实现是调用MSHookMessageEx ,用法如下 :

osx cycript image not found

devzkndeMacBook-Pro:lib devzkn$ /Users/devzkn/Downloads/cycript_0.9.594/cycript 
dyld: Library not loaded: /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/libruby.2.0.0.dylib
  Referenced from: /Users/devzkn/Downloads/cycript_0.9.594/Cycript.lib/cycript-apl
  Reason: image not found
Abort trap: 6
  • 关掉sip创建个符号链接即可
devzkndeMacBook-Pro:.ssh devzkn$ sudo mkdir -p /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/
Password:
mkdir: /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/: Operation not permitted

先关闭系统的SIP,然后运行如下命令,把原来引用的位置创建符号链接到现在新版本的位置:


sudo mkdir -p /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/
sudo ln -s /System/Library/Frameworks/Ruby.framework/Versions/2.3/usr/lib/libruby.2.3.0.dylib /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/libruby.2.0.0.dylib
  • 处理方法也很简单,直接把2.3的复制一份,改为2.0即可
/System/Library/Frameworks/Ruby.framework/Versions/Current/usr/lib

iOS逆向
44 声望15 粉丝