使用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脚本有多线程安全,尤其是有许多 ...
随机推荐
- ios 框架学习笔记
ios主要的系统层次: 一.Cocoa Touch 层:创建应用程序主要使用的框架. 1.关键技术: AirDrop:实现应用间通信. Text Kit:处理文本和排版. UIKit Dynamics ...
- 中国餐馆过程(CRP)
查如何事先确定聚类簇数目发现的,是对狄利克雷过程的(DP)的一种解释. 假设一个中国餐馆有无限的桌子,第一个顾客到来之后坐在第一张桌子上.第二个顾客来到可以选择坐在第一张桌子上,也可以选择坐在一张新的 ...
- jsp自定义标签分析
jsp自定义标签的优势体现在于jsp页面上面减少了java代码. jsp自定义标签有三大部分组成,首先是类继承TagSupport,实现doStartTag方法. public int doStart ...
- crawler
# !/usr/bin/env python# encoding:UTF-8from util import request_urlimport reimport osimport sys#from ...
- spark在eclipse上配置
环境:spark1.4.0,hadoop2.6.0 1.安装好jdk 2.在spark的conf目录下找到spark-env.sh.template,打开,在后面加上 export SCALA_HOM ...
- Asp.net 上传图片添加半透明图片或者文字水印的方法
主要用到System.Drawing 命名空间下的相关类,如Brush.Image.Bitmap.Graphics等等类 Image类可以从图片文件创建Image的实例,Bitmap可以从文件也可以从 ...
- hdu 4465 Candy 数学
思路:易知结果为 ∑(n-k)*C(n+k,k)*(p^(n+1)*q^k+q^(n+1)*p^k). 注意不能直接算,注意点技巧!!!看代码 代码如下: #include<iostream&g ...
- String类的使用 Part1
String类的属性 1:Chars属性 获取当前 String 对象中位于指定位置的 Char 对象. 2:Length属性 获取当前 String 对象中的字符数. eg:获取字符串中 字母, ...
- ssh 公钥
以前做ssh key登录方式时都是用的root帐号,基本都是无往不利的,权限采用默认即可.今天实验中两台机器帐号都是nianzong,一个普通的帐号.按照如下步骤: A机器:ssh-keygen -t ...
- linux 踢出用户方法
linux系统root用户可强制踢制其它登录用户, 首先以root登录以便查看全部的在线用户信息,可用w命令查看登录用户信息 强制踢人命令格式:pkill -kill -t tty 解释: pkill ...