使用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脚本有多线程安全,尤其是有许多 ...
随机推荐
- ELF
http://www.360doc.com/content/11/0826/13/7588214_143424472.shtml 链接,装载都是基于数据结构ELF.
- 【转】并查集&MST题集
转自:http://blog.csdn.net/shahdza/article/details/7779230 [HDU]1213 How Many Tables 基础并查集★1272 小希的迷宫 基 ...
- 初尝backbone
backbone的基础知识在此将不再进行介绍.自己后续应该会整理出来,不过今天先把这几天学的成果用一个demo进行展示. 后续可运行demo将会在sinaapp上分享,不过近期在整理sinaapp上d ...
- 汇编语言中"[]"的用法
"[]"的用法在"常见问题"已经有所说明,引用如下: 1.push dword ptr [024c1100] 压栈024c1100值的双字 2.cmp eax, ...
- (一)、http原理
谣言粉碎机前些日子发布的<用公共WiFi上网会危害银行账户安全吗?>,文中介绍了在使用HTTPS进行网络加密传输的一些情况,从回复来看,争议还是有的.随着网络越来越普及,应用越来越广泛,一 ...
- java 中 ==和equals 的区别
Java中equals和==的区别 java中的数据类型,可分为两类: 1.基本数据类型,也称原始数据类型.byte,short,char,int,long,float,double,boolea ...
- Javascript的动态运动(1)
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...
- POJ 1062 昂贵的聘礼(Dijkstra)
题意 : 真真是做POJ第一次遇到中文题,好吧,虽然语言通了,我一开始也没看懂样例什么意思,题意的话就是说这个探险家想娶酋长的女儿,但是没有钱,酋长说他可以用祭司的水晶球或者皮袄来换取少花一部分钱,同 ...
- DJANGO问题--Error: ‘ManyRelatedManager’ object is not iterable
http://www.itblah.com/django-error-manyrelatedmanager-object-iterable/ Django: Error: ‘ManyRelatedMa ...
- 【POJ3358】
题目描述: 题意: 就是给定一个a/b,求a/b的结果变成二进制之后的小数.这个小数后面会有一段循环节,只要求输出循环节开始循环的位置和循环长度. 分析: 这题我是这么想的,比如说样例中的1/5,我们 ...