lldb+python让调试更简单

总所周知,砸壳之后的iOS应用动态调试一般都使用lldb,相较于Android通过AS动态调试smali界面化操作,lldb的命令行无疑显得操作繁琐许多。作为一个合格的懒人,追求简单是我的本能,经过多方资料的收集,了解到lldb+python可极大的提高lldb动态调试效率。简单整理出lldb+python提高iOS动态调试效率的几个函数。

lldb脚本桥接

LLDB的脚本桥接是调试器的一个Python接口。通过这个接口可以在LLDB中加载和执行Python代码。在Python代码中,你可以引入lldb模块来与调试器交互来获取各种信息(比如命令的参数等)。

首先可以通过script命令直接打开lldb中的python解释器,script命令添加各种参数即可进行桥接。

查看python版本

1
2
3
4
5
$ lldb
(lldb) script import sys
(lldb) script print (sys.version)
2.7.10 (default, Feb 22 2019, 21:17:52)
[GCC 4.2.1 Compatible Apple LLVM 10.0.1 (clang-1001.0.37.14)]

Helloword

首先新建一个目录存放你的lldb Python脚本,比如我把它放在~/lldb中,该目录下新建HelloWorld.py

1
2
def helloworld(debugger, command, result, internal_dict):
print("hello world!")

在lldb中输入以下命令即可使用上述Python代码

1
2
3
4
(lldb) command script import ~/lldb/HelloWorld.py
(lldb) command script add -f HelloWorld.helloworld hello
(lldb) hello
hello world!

但是每次输入这么繁琐的命令明显不是我们的初衷,llldb有个函数lldb_init_module,一旦Python模块被加载到LLDB中时它就会被调用。因此只要我们在这个函数里面将helloworld安装到LLDB里面去.

在HelloWorld.py中加入下面的代码

1
2
def __lldb_init_module(debugger, internal_dict):
command script add -f HelloWorld.helloworld hello

然后在~/.lldbinit中import这个脚本,如果没有.lldbinit这个文件,touch ~/.lldbinit新建一个即可

1
command script import ~/lldb/HelloWorld.py

这样在加载lldb之后输入hello直接会输出helloworld了。

分享脚本(持续更新)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# !/usr/bin/env python
# -*- coding: utf-8 -*-
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
def get_ASLR():
# 获取'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:
return match.group(1)
else:
return None
def process_conn(debugger, command, result, internal_dict):
# 获取'image list -o'命令的返回结果
interpreter = lldb.debugger.GetCommandInterpreter()
returnObject = lldb.SBCommandReturnObject()
interpreter.HandleCommand('process connect connect://127.0.0.1:12345', returnObject)
output = returnObject.GetOutput()
# Super breakpoint
def sbr(debugger, command, result, internal_dict):
#用户是否输入了地址参数
if not command:
print >>result, 'Please input the address!'
return
ASLR = get_ASLR()
if ASLR:
#如果找到了ASLR偏移,就设置断点
debugger.HandleCommand('br set -a "%s+0x%s"' % (ASLR, command))
else:
print >>result, 'ASLR not found!'
def get_base_add(debugger, command, result, internal_dict):
#用户是否输入了地址参数
if not command:
print >>result, 'Please input the address!'
return
ASLR = get_ASLR()
if ASLR:
#如果找到了ASLR偏移,就设置断点
print hex(int(command, 16) - int(ASLR, 16))
else:
print >>result, 'ASLR not found!'
def watch_point(debugger, command, result, internal_dict):
#用户是否输入了地址参数
if not command:
print >>result, 'Please input the address!'
return
debugger.HandleCommand('watchpoint set expression "%s"' % (command))
def watch_read_point(debugger, command, result, internal_dict):
#用户是否输入了地址参数
if not command:
print >>result, 'Please input the address!'
return
debugger.HandleCommand('watchpoint set expression -w read -- "%s"' % (command))
def __lldb_init_module(debugger, internal_dict):
#获取偏移地址
debugger.HandleCommand('command script add -f helloworld.fy_get_ASLR pianyi')
# 'command script add sbr' : 给lldb增加一个'sbr'命令
# '-f sbr.sbr' : 该命令调用了sbr文件的sbr函数
debugger.HandleCommand('command script add sbr -f helloworld.sbr')
#挂载进程连接
debugger.HandleCommand('command script add -f helloworld.process_conn pp')
#内存读断点
debugger.HandleCommand('command script add mw -f helloworld.watch_point')
#内存访问断点
debugger.HandleCommand('command script add mr -f helloworld.watch_read_point')
#获取实际地址
debugger.HandleCommand('command script add gba -f helloworld.get_base_add')
有钱的捧个钱场
0%