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命令已经装载好并可以使用了。
sbrSuper 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调试器的更多相关文章

  1. iOS LLDB调试器

    随着Xcode 5的发布,LLDB调试器已经取代了GDB,成为了Xcode工程中默认的调试器.它与LLVM编译器一起,带给我们更丰富的流程控制和数据检测的调试功能.LLDB为Xcode提供了底层调试环 ...

  2. LLDB调试器

    你是否曾经苦恼于理解你的代码,而去尝试打印一个变量的值? NSLog(@"%@", whatIsInsideThisThing); 或者跳过一个函数调用来简化程序的行为? NSNu ...

  3. lldb调试器知多少

    lldb调试器简介   lldb 是一个有着 REPL 的特性和 C++ .Python 插件的开源调试器.lldb调试器的由来是伴随着Xcode的版本升级而来. Xcode4.3之前使用的默认调试器 ...

  4. python自带的调试器

    python是自带调试器的. 比如你写了一个python程序,名叫test.py. 你想调试一下这个程序,你可以执行 python -m pdb test.py,就会进入test.py的调试. 想查看 ...

  5. 学习笔记之--认识Xcode中的重要成员:lldb调试器

    之前对lldb调试器了解比较少,平时主要用来打印日志和暂定时用鼠标查看属性数据以及使用p po一些简单的命令语句. 今天看了一些关于lldb的文章,顿时觉得之前对它了解太少了,原来它还有那么多的功能. ...

  6. iOS LLDB调试器和断点调试

    技巧一:运行时修改变量的值 你以前怎么验证是不是某个变量的值导致整段程序不能正常工作?修改代码中的变量的值,然后cmd+r重新启动app?现在你不需要这么做了,只需要设置一个断点,当程序在这进入调试模 ...

  7. iOS - 浅谈LLDB调试器

    摘要 LLDB是Xcode默认的调试器,它与LLVM编译器一起,带给我们更丰富的流程控制和数据检测的调试功能.平时用Xcode运行程序,实际走的都是LLDB.熟练使用LLDB,可以让你debug事半功 ...

  8. iOS之LLDB调试器

    LLDB被定位为下一代的高性能调试器,默认内置于Xcode IDE内, 支持在PC.iOS设备以及模拟器上调试C.Objective-C和C++. 关于LLDB的官方介绍:LLDB 常用命令: 1.  ...

  9. lldb调试使用python脚本问题总结

    lldb调试器可以使用python脚本实现功能增强,但也不是可以随心所欲的,在实际中有很多地方需要注意. 首先是对多线程环境调试使用python脚本,也要考虑python脚本有多线程安全,尤其是有许多 ...

随机推荐

  1. SVN--从本地检出项目至服务器报错--禁止访问

    错误描述: 原因:这是访问权限限制引起的. 查看/svn/test目录的权限--之前我修改过的 现在添加一个user就好了--这个添加的developer是我之前导入本地项目时已经验证过的,所以再导入 ...

  2. C# 客户端判断服务器连接已断开

    问题描述:        在C# Socket编程中,服务器端已经断开连接(发送数据方),客户端接收服务器端发送数据,在客户端使用client.Recieve()中,服务器端断开连接,客户端任然显示已 ...

  3. oracle——表修改语句集合

     alter table table_name modify column_name default 0; 

  4. 2012 Asia Hangzhou Regional Contest

    Friend Chains http://acm.hdu.edu.cn/showproblem.php?pid=4460 图的最远两点距离,任意选个点bfs,如果有不能到的点直接-1.然后对于所有距离 ...

  5. cf 359A 359B

    359A 如果有点在边上则最少两次 没有则最少操作4次 #include <cstdio> #include <cstring> #include <algorithm& ...

  6. jquery 实现层级下拉框联动效果 代码

    <select name="fCareId" id="fCareId"> <option selected="selected&qu ...

  7. 管道命令xargs

    在研究hadoop的过程中,遇到一个小难题. 问题描述:我需要将文件夹A下的文件拷贝到文件夹B中,但是以hadoop开头的文件不要拷贝. 问题解决:ls  A|grep -v hadoop|xargs ...

  8. MonthPicker

    可以只选择MMM-yyyy的样式,而不需要确定day. http://lucianocosta.info/jquery.mtz.monthpicker/

  9. Javascript 电子时钟源码

    <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...

  10. [SQL Server系] -- 视图

    1:定义 从用户角度来看,一个视图是从一个特定的角度来查看数据库中的数据. 从数据库系统内部来看,一个视图是由SELECT语句组成的查询定义的虚拟表. 从数据库系统内部来看,视图是由一张或多张表中的数 ...