使用Python脚本强化LLDB调试器
LLDB是Xcode自带的调试器,作为一个iOS应用开发程序员,平时我在开发应用时会使用LLDB来调试代码。在逆向应用时,也会用到LLDB来跟踪应用的执行过程。
LLDB还内置了一个Python解析器,使用Python脚本可以方便LLDB的调试,比如自动化执行一些命令,或者自动化处理数据之类的,具体说明可以参考官方的文档:LLDB Python Reference。
以下就以一个具体的例子来演示一个Python脚本的编写过程:
一、获取方法的偏移地址
运行系统自带的计算器Calculator.app:
可以看到计算器的菜单里有一个“关于计算器”的选项:
如果我们要在点击“关于计算器”事件断下来的话,就要给这个方法设置一个断点。
先找到计算器的可执行文件的路径,路径为:/Applications/Calculator.app/Contents/MacOS/Calculator。
打开Hopper Disassembler反汇编调试器,将可执行文件拖进去,等待Hopper分析完成。
在左侧的搜索框输入”showabout”,会搜索到一个结果:
点击这个结果,会跳转到该方法的汇编代码处:
-[CalculatorController showAbout:]:
00000001000093dd push rbp ; Objective C Implementation defined at 0x1000188d0 (instance)
00000001000093de mov rbp, rsp
00000001000093e1 mov rdi, qword [ds:objc_cls_ref_NSDictionary] ; objc_cls_ref_NSDictionary, argument "instance" for method imp___got__objc_msgSend
00000001000093e8 mov rsi, qword [ds:0x10001b6f0] ; @selector(dictionaryWithObject:forKey:), argument "selector" for method imp___got__objc_msgSend
00000001000093ef lea rdx, qword [ds:cfstring_2000] ; @"2000"
00000001000093f6 lea rcx, qword [ds:cfstring_CopyrightStartYear] ; @"CopyrightStartYear"
00000001000093fd call qword [ds:imp___got__objc_msgSend]
0000000100009403 mov rdi, rax
0000000100009406 pop rbp
0000000100009407 jmp imp___stubs__NSShowSystemInfoPanel
; endp
由汇编代码可知[CalculatorController showAbout:]方法在文件中的偏移地址为0x00000001000093dd。
二、使用LLDB调试器设置断点
接下来运行终端,执行以下命令,让LLDB调试器依附计算器的进程:
Jobs: ~$ ps aux | grep Calculator
Jobs 79888 0.0 0.1 2781792 11620 ?? S 6:21下午 0:01.07 /Applications/Calculator.app/Contents/MacOS/Calculator
Jobs 80204 0.0 0.0 2432772 568 s002 R+ 6:26下午 0:00.00 grep Calculator
Jobs: ~$ lldb -p 79888
(lldb) process attach --pid 79888
Process 79888 stopped
* thread #1: tid = 0x6030af, 0x00007fff912d34de libsystem_kernel.dylib`mach_msg_trap + 10, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
frame #0: 0x00007fff912d34de libsystem_kernel.dylib`mach_msg_trap + 10
libsystem_kernel.dylib`mach_msg_trap:
-> 0x7fff912d34de <+10>: retq
0x7fff912d34df <+11>: nop
libsystem_kernel.dylib`mach_msg_overwrite_trap:
0x7fff912d34e0 <+0>: movq %rcx, %r10
0x7fff912d34e3 <+3>: movl $0x1000020, %eax
Executable module set to "/Applications/Calculator.app/Contents/MacOS/Calculator".
Architecture set to: x86_64h-apple-macosx.
(lldb) continue
Process 79888 resuming
(lldb)
接着执行以下命令获取应用的ASLR偏移地址:
(lldb) image list -o
[ 0] 0x000000000cafa000
[ 1] 0x00007fff93d51000
[ 2] 0x000000010cb1e000
......
(lldb)
第一行数据的16进制地址0x000000000cafa000就是应用的ASLR偏移地址,之前我们已经找到了[CalculatorController showAbout:]方法的偏移地址是0x00000001000093dd,那么该方法在内存中的地址就是0x000000000cafa000 + 0x00000001000093dd。
所以我们可以执行下面的命令来给这个方法设置断点,注意加号两边不要有空格:
(lldb) br set -a "0x000000000cafa000+0x00000001000093dd"
Breakpoint 1: where = Calculator`___lldb_unnamed_function161$$Calculator, address = 0x000000010cb033dd
(lldb)
这时点击菜单的“关于计算器”选项,程序就会断下来:
Process 79888 stopped
* thread #1: tid = 0x6709de, 0x000000010cb033dd Calculator`___lldb_unnamed_function161$$Calculator, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1
frame #0: 0x000000010cb033dd Calculator`___lldb_unnamed_function161$$Calculator
Calculator`___lldb_unnamed_function161$$Calculator:
-> 0x10cb033dd <+0>: pushq %rbp
0x10cb033de <+1>: movq %rsp, %rbp
0x10cb033e1 <+4>: movq 0x12b98(%rip), %rdi ; (void *)0x00007fff78684488: NSDictionary
0x10cb033e8 <+11>: movq 0x12301(%rip), %rsi ; "dictionaryWithObject:forKey:"
(lldb)
三、编写Python脚本
那么问题来了,我们每次调试应用都要先手动获取ASLR偏移地址,如果要给多个地址打断点的话,就要写很多遍”ASLR偏移地址+方法偏移地址”,操作比较繁琐。如果这些重复性的操作可以自动完成的话,在平时的使用过程中应该能节省不少时间。
用Python就可以很方便地实现这个功能,接下来我们就来写一个简单的脚本,以简化设置断点的操作。脚本的主要功能是自动获取应用的ASLR地址,用户设置断点时只需输入方法在文件中的的偏移地址,脚本会自动把ASLR偏移地址和方法偏移地址相加,再设置断点。
新建一个Python文件,保存至~/sbr.py,代码如下:
#!/usr/bin/python
#coding:utf-8
import lldb
import commands
import optparse
import shlex
import re
# 获取ASLR偏移地址
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
# 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+%s"' % (ASLR, command))
else:
print >>result, 'ASLR not found!'
# And the initialization code to add your commands
def __lldb_init_module(debugger, internal_dict):
# 'command script add sbr' : 给lldb增加一个'sbr'命令
# '-f sbr.sbr' : 该命令调用了sbr文件的sbr函数
debugger.HandleCommand('command script add sbr -f sbr.sbr')
print 'The "sbr" python command has been installed and is ready for use.'
然后在LLDB中执行下面的语句就可以把脚本导入到LLDB:
(lldb) command script import ~/sbr.py
The "sbr" python command has been installed and is ready for use.
(lldb)
输出结果表示名为sbr的Python命令已经装载好并可以使用了。sbr是Super breakpoint的意思,只需接收一个方法偏移地址作为参数。
接下来验证一下效果,先清除断点列表,再用sbr命令来设置断点。
(lldb) br delete
About to delete all breakpoints, do you want to do that?: [Y/n] y
All breakpoints removed. (1 breakpoint)
(lldb) sbr 0x00000001000093dd
Breakpoint 2: where = Calculator`___lldb_unnamed_function161$$Calculator, address = 0x000000010cb033dd
(lldb)
这时点击菜单的“关于计算器”选项,方法也成功断下来了。
四、启动LLDB时自动加载Python脚本
对于经常要使用到的脚本,可以在LLDB的初始化文件里添加命令加载脚本,这样LLDB启动后就能使用自定义的命令了。
修改~/.lldbinit文件,在文件里加入一行:
command script import ~/sbr.py
重新进入LLDB,可以看到脚本已经自动加载了:
Jobs: ~$ lldb
The "sbr" python command has been installed and is ready for use.
(lldb) command source -s 1 '/Users/Jobs/./.lldbinit'
The "sbr" python command has been installed and is ready for use.
(lldb)
使用Python脚本强化LLDB调试器的更多相关文章
- iOS LLDB调试器
随着Xcode 5的发布,LLDB调试器已经取代了GDB,成为了Xcode工程中默认的调试器.它与LLVM编译器一起,带给我们更丰富的流程控制和数据检测的调试功能.LLDB为Xcode提供了底层调试环 ...
- LLDB调试器
你是否曾经苦恼于理解你的代码,而去尝试打印一个变量的值? NSLog(@"%@", whatIsInsideThisThing); 或者跳过一个函数调用来简化程序的行为? NSNu ...
- lldb调试器知多少
lldb调试器简介 lldb 是一个有着 REPL 的特性和 C++ .Python 插件的开源调试器.lldb调试器的由来是伴随着Xcode的版本升级而来. Xcode4.3之前使用的默认调试器 ...
- python自带的调试器
python是自带调试器的. 比如你写了一个python程序,名叫test.py. 你想调试一下这个程序,你可以执行 python -m pdb test.py,就会进入test.py的调试. 想查看 ...
- 学习笔记之--认识Xcode中的重要成员:lldb调试器
之前对lldb调试器了解比较少,平时主要用来打印日志和暂定时用鼠标查看属性数据以及使用p po一些简单的命令语句. 今天看了一些关于lldb的文章,顿时觉得之前对它了解太少了,原来它还有那么多的功能. ...
- iOS LLDB调试器和断点调试
技巧一:运行时修改变量的值 你以前怎么验证是不是某个变量的值导致整段程序不能正常工作?修改代码中的变量的值,然后cmd+r重新启动app?现在你不需要这么做了,只需要设置一个断点,当程序在这进入调试模 ...
- iOS - 浅谈LLDB调试器
摘要 LLDB是Xcode默认的调试器,它与LLVM编译器一起,带给我们更丰富的流程控制和数据检测的调试功能.平时用Xcode运行程序,实际走的都是LLDB.熟练使用LLDB,可以让你debug事半功 ...
- iOS之LLDB调试器
LLDB被定位为下一代的高性能调试器,默认内置于Xcode IDE内, 支持在PC.iOS设备以及模拟器上调试C.Objective-C和C++. 关于LLDB的官方介绍:LLDB 常用命令: 1. ...
- lldb调试使用python脚本问题总结
lldb调试器可以使用python脚本实现功能增强,但也不是可以随心所欲的,在实际中有很多地方需要注意. 首先是对多线程环境调试使用python脚本,也要考虑python脚本有多线程安全,尤其是有许多 ...
随机推荐
- SQL语言笔记
字符串用单引号',判断用单等号=,两个单引号''转义为一个单引号' 不等号是<> 不区分大小写 []括起来的要不是关键字,要不是非法变量,比如空格隔起来的变量 创建与删除数据库 - ...
- 让站长在SEO时更得心应手的六个细节
分析一下SEO的心得,希望能对很多做网站优化和做网站推广的站长有帮助,现在做SEO的人越来网站推广越多,即使很多人在做,但不知道自己能否成功,自己的优化是否会见效,所以在这里还是来分享一下咱们在SEO ...
- 20160729noip模拟赛zld
首先显然有多少个奇数,就有多少个回文串是最优的(没有奇数时构造一个回文串 然后有了k个“核心”,把剩下的字符顺序安排到这些的两侧,最后最短的回文串长度就是答案 #include<map> ...
- select模式
在很多比较各种网络模型的文章中,但凡提到select模型时,都会说select受限于轮询的套接字数量,这个 数量也就是系统头文件中定义的FD_SETSIZE值(例如64).但事实上这个算不上真的限制. ...
- Web应用中的轻量级消息队列
Web应用中为什么会需要消息队列?主要原因是由于在高并发环境下,由于来不及同步处理,请求往往会发生堵塞,比如说,大量的insert,update之类的请求同时到达mysql,直接导致无数的行锁表锁,甚 ...
- java后台生成zip打包文件
/** * * @param zipFile 压缩包文件对象 * @param listKey 压缩的图片物理地址 * @return */ public static boolean package ...
- poj 3278 Catch That Cow (广搜,简单)
题目 以前做过,所以现在觉得很简单,需要剪枝,注意广搜的特性: 另外题目中,当人在牛的前方时,人只能后退. #define _CRT_SECURE_NO_WARNINGS //这是非一般的最短路,所以 ...
- Hibernate3中将指定的HQL语句转换成SQL语句
import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.hql.ast.QueryTranslatorI ...
- POJ 1062 昂贵的聘礼(Dijkstra)
题意 : 真真是做POJ第一次遇到中文题,好吧,虽然语言通了,我一开始也没看懂样例什么意思,题意的话就是说这个探险家想娶酋长的女儿,但是没有钱,酋长说他可以用祭司的水晶球或者皮袄来换取少花一部分钱,同 ...
- Bash 小知识点
变量定义的时候=两边不能有空格,例如: a='Hello World' 如果变量和其它字符相连,可以用{}把变量引起来,这样就可以和相连的字符隔离 除了在变量赋值和在FOR循环语句头中,BASH中的变 ...