上一篇文章 iOS 逆向 - LLDB 中讲述了 lldb
的一些基础用法 , 并无涉及太多其余内容 , 逆向过程当中经常使用的动态调试方法其实还有一些 , 本文针对上篇文章和实际逆向中的运用进行一个补充 .git
主要针对 Chisel
以及 Cycript
两个部分 .github
若是篇幅不长 , 咱们来说一讲自定义 cy
指令.shell
有部分同窗反应重签名微信应用被封号的状况 . 这里说明一下 , 微信 / 抖音 等应用是有防御和监测操做的 , 网上流传部分破解微信防御的 logos
代码 , 笔者测试效果不是百分百 , 有须要的小伙伴能够评论留言 .vim
调试别人应用自己是会形成相似问题的 , 所以尽可能不要登陆我的使用帐号 , 如非必须登陆 , 不要登陆帐号 .ruby
确实须要登陆 , 登陆一个小号 , 另外提早准备好另外一个帐户去解封 .bash
在越狱环境下 , 使用插件的方式调试 , 无须重签名 , 被封号的概率是很低的 .微信
最后再强调一次 : 玩逆向只是为了更好地防御 .app
Chisel 也是 Facebook
发布的一个 lldb
的插件 , 可以作到帮助调试和提供用户自定义指令集的功能 . 接下来会具体阐述 .函数
命令 : brew install chisel
工具
( 尚未安装 HomeBrew 的自行安装 )
安装后使用 : brew list
查看安装结果
如何配置 ?
cd /usr/local/Cellar/chisel
open .
, 找到 fblldb.py
脚本文件.
cmd + opt + c
拷贝文件路径..lldbinit
文件 , 请查阅上一篇文章 iOS 逆向 - LLDB 中最后讲自动启用加载指令所述 , 使用 vim
自行建立便可 .
vim .lldbinit
s
进入编辑模式command script import /usr/local/Cellar/chisel/1.8.1/libexec/fblldb.py
( 路径换成你本身的 )
ESC
, :wq
保存退出先来简单试一下配置成功了没 .
注意 : 若是是正在运行的工程 , 那你须要使用 command source ~/.lldbinit
, 来从新加载一下 lldb
配置文件 .
随便打开一个工程 , 进入断点模式 , 输入 pviews
.
pviews
就是 Chisel
提供的一个查看视图层级的命令 . 以上看到 , 咱们已经配置成功了 .
为了模拟逆向过程当中实际动态调试场景 . 我使用了我以前使用 MonkeyDev
重签名的微信应用来演示指令 , 对重签名不熟悉的同窗能够阅读一下 重签应用调试与代码修改 (Hook) , 与 shell 脚本自动重签名与代码注入 , 这两篇文章 .
MonkeyDev
的安装和使用咱们就很少赘述了 , 毕竟重签名原理理解了 , Monkey
其本质上也是利用脚本自动重签名 , 而后 代码注入 hook
部分集成了 Cydia Substrate
来作的.
咱们所须要作的只是把砸过壳的 ipa
或者 app
包 放到指定文件夹下便可完成重签名和代码注入 . 很是方便.
若是同窗们关于 MonkeyDev
使用有问题能够留言告知 .
运行工程 .
打开注册页面 , 暂停 . 进入断点模式 ,
pviews
pviews
能够帮助咱们很清楚的看出图层逻辑层级关系以及内存地址 .指令 : pvc
结果 :
说明 : pvc
能够帮助咱们很清楚的看出视图控制器层级关系以及内存地址 .
使用 pviews
, 随便找到一个按钮 , 复制其内存地址 .
pactions 0x10b06e5e0
pactions
能够拿到 button
的 target
以及 action
, 在逆向时须要方法 hook
常常会使用.使用 pviews
, 随便找到一个按钮 , 复制其内存地址 .
presbonder 0x10b06e5e0
presbonder
能够查看完整的响应链.使用 pclass
, 随便找到一个类 , 复制其内存地址 .
pclass 0x10b910600
pclass
能够查看完整的继承链.pclass 0x106b57bc0
pmethods
能够查看类完整的类方法和实例方法.pinternals 0x10b660df0
fvc -v 0x10b8fe000
fvc
, 视图用 fv
.fv + 类名
反之是同样的 , 回去工程搜索这个类 打印其内存地址 .taplog
taplog
输入后会退出断点模式 , 再点击屏幕上任何可响应视图 , 会自动进入 lldb
模式并打印按钮.flicker 0x11827c040
view
, 很是方便调试 , 以及肯定该内存地址是否为咱们想找到的那个视图 .vs 0x11827c040
(lldb) vs 0x1120f3390
Use the following and (q) to quit.
(w) move to superview // 来到当前视图的父视图
(s) move to first subview // 来到当前视图的第一个子视图
(a) move to previous sibling // 来到当前视图同级关系下的前一个视图
(d) move to next sibling // 来到当前视图同级关系下的后一个视图
(p) print the hierarchy // 打印当前视图的层级结构
<FixTitleColorButton: 0x1120f3390; baseClass = UIButton; frame = (20 112; 374 47); clipsToBounds = YES; opaque = NO; autoresize = W; layer = <CALayer: 0x1118c0900>>
复制代码
q
指令 .最后三条指令在逆向过程当中很是经常使用 , 你们多加练习与掌握 .
这个 LLDB
插件叫 lldb_commands
. 地址为 github.com/DerekSeland…
Clone
或者下载 , 把 lldb_commands
文件夹保存起来 , 我这边是放到 /usr/local/Cellar
里.lldbinit
, 添加一条指令 :command script import /usr/local/Cellar/lldb_commands/dslldb.py
复制代码
路径换成本身的 lldb_commands
文件夹路径便可 .
工程来到 lldb
模式下 , 输入 search UIView
, 便可测试有没有配置成功 .
找到视图控制器地址 , 使用 methods 查看其全部的实例方法和属性 .
注意 : 因为逆向时 方法的符号是没有恢复的 , 所以根据类名和方法名下断点会失败 .
因为符号并无恢复 , 所以 bt
指令查看函数调用栈时 , 会出现如下状况 .
( 后续会讲如何利用工具恢复 Mach-O 的符号 )
那么此时 , 利用 lldb_commands
提供的 sbt
指令 , 会帮助恢复一些符号 , 以便于查看方法名称 .
Section
指令可让咱们快速查看 Mach-O
有哪些 Section
段 .
Section
可添加其余指令来查看 Mach-O
具体内容 .# Dump the Mach-O segments to the main executable
(lldb) section
# Dump the Mach-O segments to UIKit
(lldb) section UIKit
# Dump the Mach-O sections of the __TEXT segment of UIKit
(lldb) section UIKit __TEXT
# Get the load address of all the hard-coded uint8_t * strings in the UIKit binary
(lldb) section UIKit __TEXT.__cstring -l
# Get the entitlements for the executable (simulator only, entitlements for actual app in __LINKEDIT)
(lldb) section __TEXT.__entitlements
# Get all the load address to the lazy symbol stubs in the main executable
(lldb) section __DATA.__la_symbol_ptr -l
复制代码
效果以下 , 你们能够结合 MachOView
来查看结果.
Cycript 是由 Cydia
( 熟悉越狱的同窗应该都很清楚 ) 创始人 Saurik
推出的一款脚本语言,Cycript
混合了 OC
、 JavaScript
语法的解释器,这意味着咱们可以在一个命令中使用 OC
或者 JavaScript
,甚至二者并用。
它可以挂钩 正在运行的进程,可以在运行时修改不少东西。
到官网点击 Download SDK
便可下载 .
/opt/
里便可 , 也能够自行选择位置 .
zsh
仍是 bash
去相应的资源文件配置 (家目录下的 .zshrc
/ .bash_profile
) ..zshrc
中也配置了 bash_profile
的引用 , 所以两处来配置这个环境变量都是能够的.
配置内容:
export CY=/opt/cycript_0.9.594/
, 换成你本身的路径.:$CY
重启 iTerm
, 输入 cycript
, 便可查看 .
若是有遇到 ruby
环境不对的同窗 , 去下载对应版本的便可 . /System/Library/Frameworks/Ruby.framework/Versions
在越狱环境下 , 是能够在 Cydia
直接安装 Cycript
插件的.
越狱手机截图上传有点麻烦 , 直接拍的.. 瑕疵请忽略 , 看个意思
那么非越狱环境下 , 就要借助 Cycript
提供的 iOS Framework
, 注入进去了 . 并且在 MonkeyDev
中 , 是默认已经作好了 Cycript
的注入的 .
并且添加了 默认 6666
端口号的监听 .
也就是说只要用 MonkeyDev
来重签跑起来的程序进程 , 6666
端口就能够附加使用了 ( 固然 , 在 Monkey
里代码能够本身定义端口号 ) .
好了 说了这么多 , 开始使用.
MonkeyDev
重签名程序 / 或者直接打开之前重签好的工程 , 无须 Xcode
运行也能够cycript -r 192.168.0.116:6666
ip
地址出现如下 , Congratulations , you're good to go !
使用 tab
键 , 写代码能够补全 .
查看当前 Window
.
指令 : [UIApplication sharedApplication ]
可简写为 UIApp
指令 : 本身 var
一个对象 , 然后咱们就可使用 .
另外注意 : 只要 APP
进程没有挂 , 这个变量是一直存在的 .
#
+ 对象地址 能够直接调用对象的方法
UIWindow.keyWindow().recursiveDescription().toString()
随便找一个 , 例如注册页面有一个 .text
为 +86
的 label
, 拿到其内存地址 ,
命令 :
#0x10b95d800.text = "hhh"
复制代码
显示结果
基于这种直接修改进程内存的方式 , 你们能够本身去玩一玩 . 好比登陆了修改一下钱包余额 , 而后改一改 frame
, 练习一下 .
如下指令结果我就不一一贴图了 , 文章太长 , 不便阅读 , 你们本身尝试 .
choose(UIButton)
choose(UILabel)
[UIApp setStatusBarHidden:YES]
[UIApp setApplicationIconBadgeNumber: 99]
APPID
结果 :
@"com.libin.LBMonkeyApp"
pviews()
pvcs()
pactions (#0x10b29da40)
结果 :
"<WCAccountRegisterViewController: 0x10b9d9800> onAgreementCheckBoxClick:"
复制代码
rp(#0x10b29da40)
control
+ d
pviews
/ pvc
/ pactions
/ rp
这些指令是 Monkey
在 MDConfig.plist
中额外封装了自定义的 cy
源的 . 也就是说使用越狱环境本来的 cycript
插件是没有这些指令可用的 .
那么咱们闲着也是闲着 , 咱们也来本身写一个 cy
源来玩一下 ?
在咱们的 monkey
工程主工程 target
中新建一个空文件, 我这里取名 lb.cy
.
Build Phases
- Copy Files
, 引入这个文件
在空文件添加咱们想本身定义的指令 . 能够参照 Monkey 本来提供的那两个来写 raw.githubusercontent.com/AloneMonkey…
这里我写了一些我经常使用的指令 , 好比获取 APPID
/ APPPATH
, 当前跟视图 , 当前页面 这些 , 我贴在下面供你们参考 , 也能够拿去直接用 .
从新运行工程 .
输入咱们自定义的指令 例如 : LBCurrentVC()
提示没找到指令 , 由于咱们尚未引入 , monkey
那两个在 config
中会自动引入.
@import lb
再次输入 LBCurrentVC()
, 获得结果.
//IIFE 匿名函数自执行表达式
(function(exports){
APPID = [NSBundle mainBundle].bundleIdentifier,
APPPATH = [NSBundle mainBundle].bundlePath,
//若是有变化,就用function去定义!!
LBRootvc = function(){
return UIApp.keyWindow.rootViewController;
};
LBKeyWindow = function(){
return UIApp.keyWindow;
};
LBGetCurrentVCFromRootVc = function(rootVC){
var currentVC;
if([rootVC presentedViewController]){
rootVC = [rootVC presentedViewController];
}
if([rootVC isKindOfClass:[UITabBarController class]]){
currentVC = LBGetCurrentVCFromRootVc(rootVC.selectedViewController);
}else if([rootVC isKindOfClass:[UINavigationController class]]){
currentVC = LBGetCurrentVCFromRootVc(rootVC.visibleViewController);
}else{
currentVC = rootVC;
}
return currentVC;
};
LBCurrentVC = function(){
return LBGetCurrentVCFromRootVc(LBRootvc());
};
})(exports);
复制代码
使用 cycript
某一个控件 / 对象 内存地址时 , 要注意其生命周期 , 例如用一个 label
的内存地址调试 , 你页面退出 , 又重进 , 是从新建立了对象的 , 之前的内存地址也会没法再使用 . 不要忘记这点 .
cycript
使用须要同局域网每次要链接 , 或者其余咱们须要自定义的初始化动做 , 咱们能够将其写到一个脚本中 , 配置到 zsh
/ bash
环境变量中便可 , 你们能够玩一玩 , 有问题你们一块儿探讨一下 .
逆向过程当中 , View Debug
和 cycript
调试界面是很是经常使用的手段 , 所以 , 但愿你们能熟练掌握这些技巧 .