iOS逆向(7)-LLDB,自制LLDB脚本,窜改微信红包金额

在上篇文章从fishhook看runtime,hook系统C函数中已经提到了利用LLDB的部分命令。在我们玩逆向的时候在大多数时候其实是拿不到源码的。所以了解一些LLDB来辅助我对别人APP的学(破)习(坏),是非常有必要的。

自从开始玩逆向,总是会有一些大佬给我发一些转账信息(为什么不是发红包?红包金额有限制,拿不出手),金额还挺大。
都是类似于这样的。

88888.88.png

那么道友们想不想都收到这样的红包呢?看完这篇文章,你就可以。如果没有人转给你,评论区告诉我,我给你转,说到做到!

废话不多说,这篇文章内容很简单,非常容易理解,但是需要记的东西比较多,理财师强烈推荐点个小心心,以备不时之需 O(∩_∩)O哈哈~。

今天的DEMO也比较简单,可以在点击这里下载到: LLDB

本文将介绍的内容如下:

  • LLDB
  • 自制LLDB脚本
  • chisel
  • DerekSelander-LLDB
  • 实操窜改微信红包

一、LLDB

默认内置于Xcode中的动态调试工具。标准的 LLDB 提供了一组广泛的命令,旨在与老版本的 GDB 命令兼容。 除了使用标准配置外,还可以很容易地自定义 LLDB 以满足实际需要。

命令格式如下

<command> [<subcommand> [<subcommand>...]] + <action> + [-options [option-value]] + [argument [argument...]]
  • []表示命令是可选的,可以有也可以没有
  • <command>(命令)和<subcommand>(子命令):LLDB调试命令的名称。命令和子命令按层级结构来排列:一个命令对象为跟随其的子命令对象创建一个上下文,子命令又为其子命令创建一个上下文,依此类推。
  • <action>:我们想在前面的命令序列的上下文中执行的一些操作。
  • <options>:行为修改器(action modifiers)。通常带有一些值。
  • <argument>:根据使用的命令的上下文来表示各种不同的东西。

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
# 给所有名为xx的函数设置一个断点
breakpoint set —name xx
br s -n xx
b xx
​
# 在文件F指定行L设置断点
breakpoint set —file F —line L
br s -f F -l L
b F:L
​
# 当执行到该线程时,调试器才会断下来。
# 一段代码可能开了多线程,要在不同线程之间切来切去。这时就可以使用线程断点了
breakPoint set –f 文件名 –l 行号 –t 线程id
​
# 条件断点
breakpoint set -f viewController.m -l 362 -c "width > 68"
​
# 给所有名为xx的C++函数设置一个断点(希望没有同名的C函数)
breakpoint set —method xxx
br s -M xxx
​
# 给一个OC函数[objc msgSend:]设置一个断点
breakpoint set —name "-[objc msgSend:]"
b -n "-[objc msgSend:]"
​
# 给所有名为xx的OC方法设置一个断点(希望没有名为xx的C或者C++函数)
breakpoint set —selector xx
br s -S count
​
# 给所有函数名正则匹配成功的函数设置一个断点(留个正则熟练的同学尝试)
breakpoint set --func-regex regular-expression
br s -r regular-expression
​
# 给指定函数地址func_addr的位置设置一个断点
br set -a xxx
​
# 一次性断点
# -- 是命令选项结束符,如果没有选项,可以省略
breakpoint set --one-shot true --name "-[objc msgSend:]"
​
# 断点列表
breakpoint list
br l
​
# 断点删除
breakpoint delete xxx # index指明断点的序号,如果为空则删除所有断点
breakpoint delete xxx -f # 强制删除(不需要确认)
br del index
​
# 断点触发时自动执行下去
--auto-continue # 参数
(lldb) b CCCryptorCreate
Breakpoint 1: where = libcommonCrypto.dylib`CCCryptorCreate, address = 0x000000011047e1b7
(lldb) breakpoint modify --auto-continue true 1
(lldb) br list
Current breakpoints:
1: name = 'CCCryptorCreate', locations = 1, resolved = 1, hit count = 0 Options: enabled auto-continue 
  1.1: where = libcommonCrypto.dylib`CCCryptorCreate, address = 0x000000011047e1b7, resolved, hit count = 0 
(lldb) breakpoint command add -s python 1
Enter your Python command(s). Type 'DONE' to end.
    print "Hit this breakpoint!"
    DONE

# 跳过次数
-i <count> (--ignore -count <count>)
breakpoint set -F viewDidLoad -i 3

-o <boolean>只断住一次
breakpoint set -F viewDidLoad: -o yes

随意上两张样式图:


Breakpoint_1.png

Breakpoint_2.png

附带一张官网截图,这些命令都可以在 找到

12B131A8-D3DC-4256-ADA1-604932CB0071.png

2、断点命令

命令名称 命令参样例
给某一个断点增加命令 breakpoint command add 1
查看所有断点命令 breakpoint command list
删除断点命令 breakpoint command delete 1
使某个断点命令生效/失效 breakpoint command enable/disable
给某一个断点增加命令 breakpoint command delete

给某一处断点加上一段代码,使其每次被断住的时候都可以自动执行终端代码,如下图:


breakpoint command add.png

3、执行代码

expression就是执行代码的命令,也就是常用的p,按照官网所说的缩写唯一性原则eexpr,也是可以的。
如图:

expression_2.png

expression_2.png

4、查看堆栈,流程控制

命令名称 命令参样例
查看当前所有堆栈 bt
返回上一步堆栈 up
查看某一条堆栈 frame select 1
查看当前堆栈的参数 frame variable
堆栈回滚到上一条 thread return
程序继续执行 c
单步下一步 n
进入下一个函数(方法) s
汇编级别的单步下一步 ni
汇编级别的进入下一个函数(方法) si

同样是一张样式图:


bt.png

5、内存断点

某个属性地址只要有改变,就触发断点。相当于对某个属性设置了KVO。

命令名称 命令参样例
直接观察一个变量 watchpoint set variable global_var
直接观察一个变量的地址 watchpoint set expression -- 0xxxxxx
删除断点 watchpoint delete 1
使断点失效/生效 watchpoint disable/enable 2
查看所有断点 watchpoint list
06BE6F9B-09CD-4CCA-89B4-0CD068B5FC0B.png

5、库文件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
stop-hook.png

8、寄存器&&内存

命令名称 命令参样例
显示当前线程所有寄存器的值 register read --all
将0x01写入x2寄存器 register write x2 0x01
读取内存0x0002A8A2D中的的值 memory read 0x0002A8A2D (缩写x 0x0002A8A2D )

9、支持Python

例如:

script print "Here is some text"
Python.png

二、自制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效果.png

读到这就有一个很有意思的事情了:
.lldbinit可以帮我们预加载部分命令,LLDB又支持Python语法,那么是不是可以将部分Python的代码封装起来,再利用.lldbinit的机制,进而就可以实现用我们自己的封装好的代码,让我们更方便的使用LLDB

说干就干。

2、脚本实操

之前我们使用过命令image list命令查看,查看App运行后再内存中的首地址(ASLR),这个地址其实是加上了pagezero的值,其实使用命令image list -o可以直接查看ASLR,如图:

ASLR.png

然而我们每次只需要取的是第一个值,却打印出这么多的信息,有点烦人。这就可以写一个脚本每次取出第一个值,并且打印出来,就是我们要的结果:
fy_get_ASLR.png

代码如下很短,当然也可以在这下载到: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中,即可实现每次自动加载。

lldbinit_2.png

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 /usr/local/opt/chisel/libexec/fblldb.py

重启Xcode即可使用。

以下挑了一些实用的命令:

命令名称 命令描述 iOS OS X
pviews 打印当前KeyWindow的所有View Yes Yes
pvc 打印当前KeyWindow的所有VC Yes No
fv 根据正则表达式打印查找并打印View Yes No
fvc 根据正则表达式打印查找并打印VC Yes No
pactions 事件查找 Yes No
presbonder 响应链 Yes No
pclass 继承链 Yes No
pmethods 查看类方法 / 实例方法 Yes No
pinternals 查看成员变量 Yes No
taplog 输入后会退出断点模式 , 再点击屏幕上任何可响应视图 , 会自动进入 lldb 模式并打印按钮. Yes No
flicker 通过内存地址 , 在断点模式下调用该指令会闪烁 view Yes No
vs 通过内存地址 , 进入调试模式 , 当前view会变成红色 Yes No
show/hide 在不需要continue的情况下显示/隐藏View或者Layer Yes Yes
bmessage 在类的方法或实例的方法上设置符号断点,就算没有实现显示的实现该刚发,也会触发。如viewWillAppear这个方法,在当前控制器中没有实现它,但是又想在调用它的时机触发中断。 Yes Yes
wivar 相当于watchpoint Yes Yes

下图是pviews和pvc的用例图:

pviews&&pvc.png

四、DerekSelander-LLDB

DerekSelander-LLDBchisel一样是一个LLDB的脚本集合,大部分功能一致,但DerekSelander-LLDB有一个非常好用的功能:
sbt:查看当前堆栈,并且尽可能的恢复符号表!
这就很牛逼了,要知道在我们逆向的过程中,大部分研究的APP都是已经去符号的!
[图片上传失败...(image-57c79-1554654483282)]

具体使用同样也可以参照官网: 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元),进入聊天页面如下图:

红包_1.png

在这个地方断住程序,进入LLDB的调试页面。

Stop.png

输入上文提到的Chisel命令pviews,会发现终端打印出了非常多的视图结构。直接搜索红包金额0.01,找到对应的Label,如下图:
pviews.png

0.01.png

从上图可以发现显示金额的控件是MMUILabel,很像一个UILabel,而且地址为0x10e6c7d00
在根据LLDB的p命令执行更改文本的代码,如下:

p ((UILabel *)0x10e6c7d00).text = @"¥88888.88"

改金额.png

然后程序继续运行。可以看到微信的金额已经被改!
金额被改.png

此时的金额只是一个静态被改变的字符串而已,实际上并不会让我们多一分钱或者少一分钱。

在普通的生活中,逆向其实是一件非常有意思的事情,在增加自己的知识面的同时,也能给予我们很多的欢乐,想想看这样一张截图往朋友圈一放是不是贼有面子。哈哈,也许你的朋友圈中各种红包转账截图也是这样来的呢?尤其是经常发这样的转账信息的代购们。

六、总结

这片文章的内容其实非常简单,首先介绍了一下LLDB的一下基本用法,从而得知其可以支持Python语法,又有.lldbinit文件可以帮我们自动加载脚本,所有就有了一个简单的LLDB脚本案例,之后又引出facebook出品的ChieslDerekSelander-LLDB两个脚本集合。最后就是利用LLDB进行一些简单的UI分析和执行简单的代码了。

但是,每次使用LLDB都需要断住程序,体验不是很好。那是不是有一种能力,可以让程序在正常运行的时候,我们也可以对APP进行实时的动态分析呢?
答案是肯定的,神器Cycript就是这么一个存在,在下一篇文章中,将会围绕Cycript讲解一些逆向工程中非常非常重要的内容!

参考:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345

推荐阅读更多精彩内容

  • 你是否曾经苦恼于理解你的代码,而去尝试打印一个变量的值? NSLog(@"%@", whatIsInsideThi...
    F麦子阅读 1,249评论 1 2
  • 转载 与调试器共舞 - LLDB 的华尔兹: https://objccn.io/issue-19-2/ 推荐:i...
    F麦子阅读 3,327评论 0 10
  • 你是否曾经苦恼于理解你的代码,而去尝试打印一个变量的值? NSLog(@"%@", whatIsInsideThi...
    木易林1阅读 954评论 0 4
  • 你是否曾经苦恼于理解你的代码,而去尝试打印一个变量的值? NSLog(@"%@", whatIsInsideThi...
    paraneaeee阅读 1,181评论 0 7
  • 你是否曾经苦恼于理解你的代码,而去尝试打印一个变量的值? NSLog(@"%@", whatIsInsideThi...
    我是啊梁阅读 801评论 1 1