作者:一缕清风扬万里
原文地址:https://juejin.im/post/5caad5d6f265da251d4b875a
在上篇文章从fishhook看runtime,hook系统C函数中已经提到了利用LLDB的部分命令。在我们玩逆向的时候在大多数时候其实是拿不到源码的。所以了解一些LLDB来辅助我对别人APP的学(破)习(坏),是非常有必要的。
自从开始玩逆向,总是会有一些大佬给我发一些转账信息(为什么不是发红包?红包金额有限制,拿不出手),金额还挺大。 都是类似于这样的。
那么道友们想不想都收到这样的红包呢?看完这篇文章,你就可以。如果没有人转给你,评论区告诉我,我给你转,说到做到!
废话不多说,这篇文章内容很简单,非常容易理解,但是需要记的东西比较多,理财师强烈推荐点个小心心,以备不时之需 O(∩_∩)O哈哈~。
今天的DEMO也比较简单,可以在点击这里下载到: LLDB
本文将介绍的内容如下:
- LLDB
- 自制LLDB脚本
- chisel
- DerekSelander-LLDB
- 实操窜改微信红包
一、LLDB
默认内置于Xcode中的动态调试工具。标准的 LLDB 提供了一组广泛的命令,旨在与老版本的 GDB 命令兼容。 除了使用标准配置外,还可以很容易地自定义 LLDB 以满足实际需要。
命令格式如下
[ [...]] + + [-options [option-value]] + [argument [argument...]]
- []表示命令是可选的,可以有也可以没有
(命令)和 (子命令):LLDB调试命令的名称。命令和子命令按层级结构来排列:一个命令对象为跟随其的子命令对象创建一个上下文,子命令又为其子命令创建一个上下文,依此类推。 :我们想在前面的命令序列的上下文中执行的一些操作。 :行为修改器(action modifiers)。通常带有一些值。 :根据使用的命令的上下文来表示各种不同的东西。
The full lldb command names are often long, but any unique short form can be used. Instead of "breakpoint set", "br se" is also acceptable.
一般lldb的命令会很长,但是只要能够想出足够断,并且又能代表唯一性的缩写,那么缩写命令也是同一生效的如:breakpoint set == br se
LLDB的所有命令在 LLVM官网或者Apple官网 都可以查询到。笔者会在这篇文章中列举一些比较常用的命令。
1、断点设置
命令名称 | 命令参样例 |
---|---|
使用名称设置断点 | breakpoint set --name main |
使用内存地址设置断点 | breakpoint -a 0xXXXXXXXX |
删除断点 | breakpoint delete 1 |
使断点失效/生效 | breakpoint disable/enable 2 |
查看所有断点 | breakpoint list |
OC中所有命名中包含为Test4的方法设置断点 | breakpoint set -r Test4 |
随意上两张样式图:
附带一张官网截图,这些命令都可以在 这 找到
2、断点命令
命令名称 | 命令参样例 |
---|---|
给某一个断点增加命令 | breakpoint command add 1 |
查看所有断点命令 | breakpoint command list |
删除断点命令 | breakpoint command delete 1 |
使某个断点命令生效/失效 | breakpoint command enable/disable |
给某一个断点增加命令 | breakpoint command delete |
给某一处断点加上一段代码,使其每次被断住的时候都可以自动执行终端代码,如下图:
3、执行代码
expression就是执行代码的命令,也就是常用的p,按照官网所说的缩写唯一性原则e、expr,也是可以的。 如图:
4、查看堆栈,流程控制
命令名称 | 命令参样例 |
---|---|
查看当前所有堆栈 | bt |
返回上一步堆栈 | up |
查看某一条堆栈 | frame select 1 |
查看当前堆栈的参数 | frame variable |
堆栈回滚到上一条 | thread return |
程序继续执行 | c |
单步下一步 | n |
进入下一个函数(方法) | s |
汇编级别的单步下一步 | ni |
汇编级别的进入下一个函数(方法) | si |
同样是一张样式图:
5、内存断点
某个属性地址只要有改变,就触发断点。相当于对某个属性设置了KVO。
命令名称 | 命令参样例 |
---|---|
直接观察一个变量 | watchpoint set variable global_var |
直接观察一个变量的地址 | watchpoint set expression -- 0xxxxxx |
删除断点 | watchpoint delete 1 |
使断点失效/生效 | watchpoint disable/enable 2 |
查看所有断点 | watchpoint list |
6、库文件image
命令名称 | 命令参样例 |
---|---|
查看工程中使用的库(包括MachO自己) | image list |
查找可执行文件或共享库的原始地址 | image lookup --address 0x0000000100000de0 |
输出NSURL的成员变量及属性信息。 | image lookup --type NSURL |
导出可执行文件和共享库的所有符号表 | image dump symtab |
7、HOOK每个断点
给每个断点,都执行一段代码。
命令名称 | 命令参样例 |
---|---|
增加一个HOOK | target stop-hook add -o "frame variable" |
直接所有HOOK | target stop-hook list |
删除HOOK | target stop-hook disable 1 |
使HOOK失效/生效 | target stop-hook disable/enable 2 |
8、寄存器&&内存
命令名称 | 命令参样例 |
---|---|
显示当前线程所有寄存器的值 | register read --all |
将0x01写入x2寄存器 | register write x2 0x01 |
读取内存0x0002A8A2D中的的值 | memory read 0x0002A8A2D (缩写x 0x0002A8A2D ) |
9、支持Python
例如:
script print "Here is some text"
二、自制LLDB脚本
1、.lldbinit
LLDB本质上就跟一个程序(或者说进程)一样,每次启动LLDB的时候都会主动加载一个初始化文件,这个文件就是.lldbinit,他的地址位于根目录下:
~/
如果你的根目录没有这个文件,那就只用touch创建一个吧
// 创建.lldbinit
touch ~/.lldbinit
// 写入
vi ~/.lldbinit
// 查看
cat ~/.lldbinit
在.lldbinit中写入如下代码
target stop-hook add -o "frame variable"
重启Xcode,运行工程,在任意一个地方加上断点。
会发现当断点断住的时候,自动执行了frame variable
读到这就有一个很有意思的事情了:
.lldbinit可以帮我们预加载部分命令,LLDB又支持Python语法,那么是不是可以将部分Python的代码封装起来,再利用.lldbinit的机制,进而就可以实现用我们自己的封装好的代码,让我们更方便的使用LLDB?
说干就干。
2、脚本实操
之前我们使用过命令image list命令查看,查看App运行后再内存中的首地址(ASLR),这个地址其实是加上了pagezero的值,其实使用命令image list -o可以直接查看ASLR,如图:
然而我们每次只需要取的是第一个值,却打印出这么多的信息,有点烦人。这就可以写一个脚本每次取出第一个值,并且打印出来,就是我们要的结果:
代码如下很短,当然也可以在这下载到:lldbPyDemo.py
import lldb
import re
# 获取ASLR偏移地址
def fy_get_ASLR(debugger, command, result, internal_dict):
# 获取'image list -o'命令的返回结果
interpreter = lldb.debugger.GetCommandInterpreter()
returnObject = lldb.SBCommandReturnObject()
interpreter.HandleCommand('image list -o', returnObject)
output = returnObject.GetOutput();
# 正则匹配出第一个0x开头的16进制地址
match = re.match(r'.+(0x[0-9a-fA-F]+)', output)
if match:
print match.group(1)
else:
return None
# And the initialization code to add your commands
def __lldb_init_module(debugger, internal_dict):
# 'command script add fy_get_ASLR' : 给lldb增加一个'fy_get_ASLR'命令
# '-f lldbPyDemo.fy_get_ASLR' : 该命令调用了lldbPyDemo文件的fy_get_ASLR函数
debugger.HandleCommand('command script add fy_get_ASLR -f lldbPyDemo.fy_get_ASLR')
print 'The "fy_get_ASLR" python command has been installed and is ready for use.'
同样的,每次都主动加载lldbPyDemo.py也有点烦,将其路径加入.lldbinit中,即可实现每次自动加载。
LLDB所有开放出来的接口都可以在 官方网站中找到,有兴趣的同学可以研究研究。
三、chisel
Chisel is a collection of LLDB commands to assist in the debugging of iOS apps. Chisel是一个用户Debug iOS Apps 的LLDB命令集合
以上介绍来自chisel官网。
由于其支持brew,安装使用的方法很简单:
brew update
brew install chisel
如果本地没有.lldbinit文件,先在根目录创建再打开,否则直接打开
// 创建.lldbinit文件
touch .lldbinit
// 打开.lldbinit文件
open .lldbinit
然后在.lldbinit文件中追加如下命令
command script import /path/to/fblldb.py
重启Xcode即可使用。
以下挑了一些实用的命令:
命令名称 | 命令描述 | iOS | OS X |
---|---|---|---|
pviews | 打印当前KeyWindow的所有View | Yes | Yes |
pvc | 打印当前KeyWindow的所有VC | Yes | No |
fv | 根据正则表达式打印查找并打印View | Yes | No |
fvc | 根据正则表达式打印查找并打印VC | Yes | No |
show/hide | 在不需要continue的情况下显示/隐藏View或者Layer | Yes | Yes |
bmessage | 在类的方法或实例的方法上设置符号断点,就算没有实现显示的实现该刚发,也会触发。如viewWillAppear这个方法,在当前控制器中没有实现它,但是又想在调用它的时机触发中断。 | Yes | Yes |
wivar | 相当于watchpoint | Yes | Yes |
下图是pviews和pvc的用例图:
四、DerekSelander-LLDB
DerekSelander-LLDB
同chisel
一样是一个LLDB的脚本集合,大部分功能一致,但DerekSelander-LLDB
有一个非常好用的功能:
sbt
:查看当前堆栈,并且尽可能的恢复符号表!
这就很牛逼了,要知道在我们逆向的过程中,大部分研究的APP都是已经去符号的!
具体使用同样也可以参照官网: DerekSelander-LLDB
DerekSelander-LLDB
的安装过程没有chisel
那么花哨,不需要用到brew,安装过程如下(官网复制的,我就不翻译了):
1、 To Install, copy the lldb_commands folder to a dir of your choosing.
2、 Open up (or create) ~/.lldbinit
3、 Add the following command to your ~/.lldbinit file: command script import /path/to/lldb_commands/dslldb.py
五、实操窜改微信红包
LLDB既然这么好用,那么我们就利用LLDB来继续分析一下我们可爱的微信,O(∩_∩)O哈哈~。
利用之前文章iOS逆向(4)-代码注入,窃取微信密码讲到的方法,直接利用Xcode将微信运行在手机上。
随意让一个小伙伴自己的微信号发一个最大的红包(0.01元),进入聊天页面如下图:
在这个地方断住程序,进入LLDB的调试页面。
输入上文提到的Chisel命令pviews,会发现终端打印出了非常多的视图结构。直接搜索红包金额0.01,找到对应的Label,如下图:
从上图可以发现显示金额的控件是MMUILabel,很像一个UILabel,而且地址为0x10e6c7d00。 在根据LLDB的p命令执行更改文本的代码,如下:
p ((UILabel *)0x10e6c7d00).text = @"¥88888.88"
然后程序继续运行。可以看到微信的金额已经被改!
此时的金额只是一个静态被改变的字符串而已,实际上并不会让我们多一分钱或者少一分钱。
在普通的生活中,逆向其实是一件非常有意思的事情,在增加自己的知识面的同时,也能给予我们很多的欢乐,想想看这样一张截图往朋友圈一放是不是贼有面子。哈哈,也许你的朋友圈中各种红包转账截图也是这样来的呢?尤其是经常发这样的转账信息的代购们。
六、总结
这片文章的内容其实非常简单,首先介绍了一下LLDB的一下基本用法,从而得知其可以支持Python语法,又有.lldbinit文件可以帮我们自动加载脚本,所有就有了一个简单的LLDB脚本案例,之后又引出facebook出品的Chiesl和DerekSelander-LLDB两个脚本集合。最后就是利用LLDB进行一些简单的UI分析和执行简单的代码了。
但是,每次使用LLDB都需要断住程序,体验不是很好。那是不是有一种能力,可以让程序在正常运行的时候,我们也可以对APP进行实时的动态分析呢?
答案是肯定的,神器Cycript就是这么一个存在,在下一篇文章中,将会围绕Cycript讲解一些逆向工程中非常非常重要的内容!
系列文章列表!
iOS逆向(1)-密码学(RSA)
iOS逆向(2)-密码学(Hash&对称加密)
iOS逆向(3)-APP重签名
iOS逆向(4)-代码注入,非越狱窃取微信密码
iOS逆向(5)-不知MachO怎敢说自己懂DYLD
iOS逆向(6)-从fishhook看Runtime,Hook系统函数
iOS逆向(7)-LLDB,自制LLDB脚本,窜改微信红包金额
iOS逆向(8)-Monkey、Logos
iOS逆向(9)-Cycript,动态分析APP利器
iOS逆向(10)-越狱!越狱!远程连接登录手机
iOSSir公众号技术交流微信群!
需要进群可以添加公众号助理“kele22558!”