使用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脚本有多线程安全,尤其是有许多 ...
随机推荐
- Linux命令zip和unzip
问题描述: 使用Linux中命令zip和unzip 问题解决: 命令名: zip 功能说明:压缩文件. 语 法:zip [-AcdDfFghjJKlLmoqrSTuvVwXyz$][- ...
- 【CodeForces】【148D】Bag of mice
概率DP kuangbin总结中的第9题 啊……题目给的数据只有白鼠和黑鼠的数量,所以我们只能在这个上面做(gao)文(D)章(P)了…… 明显可以用两种老鼠的数量来作为状态= = 我的WA做法: 令 ...
- Unit Test Generator
- TensorFlow 基本使用
使用 TensorFlow, 你必须明白 TensorFlow: 使用图 (graph) 来表示计算任务. 在被称之为 会话 (Session) 的上下文 (context) 中执行图. 使用 ten ...
- 01-08-03【Nhibernate (版本3.3.1.4000) 出入江湖】二级缓存:NHibernate自带的HashtableProvider之缓存管理
http://www.cnblogs.com/lyj/archive/2008/11/28/1343418.html 管理NHibernate二级缓存 NHibernate二级缓存由ISessionF ...
- 趣味Python入门(一):初识Python
[编者按]本文作者是 Abhishek Jaiswal ,擅长 .NET.C#.Python 等多种语言的技术控.本文中,作者通过活泼有趣的口吻向大家介绍了 Python 语言的基础知识,后期多学习历 ...
- 【redis】05Redis的常用命令及高级应用
Redis常用命令 Redis提供了非常丰富的命令,对数据库和个中数据类型进行操作, 这些命令呢,可以在Linux终端使用. 分为两大类的命令,一种是键值相关的命令,一种是服务器相关的命令, ...
- HDU2594 Simpsons’ Hidden Talents 字符串哈希
最近在学习字符串的知识,在字符串上我跟大一的时候是没什么区别的,所以恶补了很多基础的算法,今天补了一下字符串哈希,看的是大一新生的课件学的,以前觉得字符串哈希无非就是跟普通的哈希没什么区别,倒也没觉得 ...
- 【leetcode】Add Two Numbers(middle) ☆
You are given two linked lists representing two non-negative numbers. The digits are stored in rever ...
- My_Plan part1 小结
数位DP AC十道题目以上 成就达成 八月份!三个月!想想就令人兴奋呢 开始写总结啦 貌似简单的数位DP只需要改改模板就可以啦 就按照我的做题顺序开始总结吧 先是学习了一发模板:http://www. ...