iOS逆向实战--024:lldb高级调式

虚拟内存

早期的操作系统

早期的操作系统,并没有虚拟内存的概念。系统由进程直接访问内存中的物理地址,这种方式存在严重的安全隐患。内存中的不同进程,可以计算出它们的物理地址,可以跨进程访问,可以随意进行数据的篡改

早期的程序也比较小,在运行时,会将整个程序全部加载到内存中。但随着软件的发展,程序越来越大,而且还有大型游戏的诞生,导致内存越来越吃紧。这就是早期系统中,为什么经常可以到内存不足提示框

虚拟内存系统

而现代的操作系统都引入了虚拟内存,进程持有的虚拟地址(Virtual Address)会经过内存管理单元(Memory Mangament Unit)的转换变成物理地址,然后再通过物理地址访问内存

操作系统以页为单位管理内存,在iOS系统中,一页为16KB。所以虚拟地址和物理地址的映射表,也称之为页表。页表存储在内存中,有了页表,就可以将程序和物理内存完全阻隔开

早期的系统,将程序全部加载到内存中。程序越大,它的功能越多,这会造成一些并未使用到的功能,也被加载进内存,造成内存的大量浪费

现代的操作系统进行了更合理的优化,例如iOS系统中,当进程被加载时,虚拟内存中会开辟4G的空间(假空间),用于存放MachO、堆区、栈区。但物理内存中,并未真的分配。当数据加载到页表中,系统会配合CPU进行地址翻译,然后载入到物理内存中。地址翻译的过程,由CPU上的内存管理单元(MMU)完成

页表中记录了内存页的状态、虚拟内存和物理内存的对应关系。其中状态分为:未分配(Unallocated)、未缓存(Uncached)和已缓存(Cached

  • 未分配的内存页,是没有被进程申请使用的,也就是空闲的虚拟内存,不占用虚拟内存磁盘的任何空间
  • 未缓存的内存页,仅在虚拟内存中,没有被物理内存缓存
  • 已缓存的内存页,同时存在于虚拟内存和物理内存中

缺页中断

当程序访问未被缓存的内存页时,就会触发缺页中断

  • 部分情况下,被访问的页面已经加载到物理内存中,但页表中并不存在该对应关系,这时只需要在页表中建立虚拟内存到物理内存的关系即可
  • 其他情况下,操作系统需要将磁盘上未被缓存的虚拟页加载到物理内存中

页面替换

物理内存的空间是有限的,当内存中没有空间时,操作系统会从选择合适的物理内存页驱逐回磁盘,为新的内存页让出位置,选择待驱逐页的过程在操作系统中叫做页面替换

虚拟内存解决的问题

数据存储在虚拟内存中,地址是连续的。但在实际的物理内存中,地址是随机存储的。虚拟内存的出现,将程序和物理内存完全阻隔开,解决了安全问题。页表中只加载程序所使用到的部分功能,避免内存浪费的现象,也解决了内存不足问题

虚拟内存引发的问题

程序的代码在不修改的情况下,每次加载到虚拟内存中的地址都是一样的,这样的方式并不安全。为了解决地址固定的问题,出现了ASLR技术

ASLR

ASLRAddress space layout randomization):是一种针对缓冲区溢出的安全保护技术,通过对堆、栈、共享库映射等线性区布局的随机化,通过增加攻击者预测目的地址的难度,防止攻击者直接定位攻击代码位置,达到阻止溢出攻击的目的

大部分主流的操作系统已经实现了ASLR

  • LinuxLinux已在内核版本2.6.12中添加ASLR
  • WindowsWindows Server 2008Windows 7Windows VistaWindows Server 2008 R2,默认情况下启用ASLR,但它仅适用于动态链接库和可执行文件
  • Mac OS XAppleMac OS X Leopard10.52007年十月发行)中某些库导入了随机地址偏移,但其实现并没有提供ASLR所定义的完整保护能力。而Mac OS X Lion10.7则对所有的应用程序均提供了ASLR支持。Apple宣称为应用程序改善了这项技术的支持,能让3264位的应用程序避开更多此类攻击。从OS X Mountain Lion10.8开始,核心及核心扩充(kext)与zones在系统启动时也会随机配置
  • iOSiPhoneiPod touchiPad):AppleiOS4.3内导入了ASLR
  • AndroidAndroid 4.0提供地址空间配置随机加载(ASLR),以帮助保护系统和第三方应用程序免受由于内存管理问题的攻击,在Android 4.1中加入地址无关代码(position-independent code)的支持
Chisel

Chisellldb的指令集合,可帮助开发者调试iOS应用程序。详情可查看 官方文档

安装chisel

brew update
brew install chisel

打开~/.lldbinit,添加以下指令:

command script import /usr/local/opt/chisel/libexec/fbchisellldb.py

案例1:

查看View的视图结构

lldb中,使用pviews指令

pviews
-------------------------
; layer = >
  | >
  |    | >
  |    |    | >
  |    |    |    | >
  |    |    |    |    | >
  |    |    |    | >
  |    |    |    |    | >
  |    |    |    | >
  |    |    |    |    | >

指定View下的视图结构

pviews self.view

指定View的上层视图结构

pviews -u self.view

案例2:

查看控制器的视图结构

lldb中,使用pvc指令

pvc
-------------------------
, state: appeared, view: 

案例3:

查看指定类的结构

lldb中,使用pclass指令

pclass self
-------------------------
ViewController
  | UIViewController
  |    | UIResponder
  |    |    | NSObject

案例4:

查看指定对象的方法列表

lldb中,使用pmethod指令

pmethod self
-------------------------
Class Methods:
No methods were found

Instance Methods:
- (void)setModels:(id)arg0 
- (void)viewDidLoad
- (void)touchesBegan:(id)arg0 withEvent:(id)arg1 
- (void).cxx_destruct
- (id)models

案例5:

查看指定对象的成员属性

lldb中,使用pinternals指令

pinternals self
-------------------------
(ViewController) $41 = {
 UIViewController = {
   UIResponder = {
     NSObject = {
       isa = ViewController
     }
   }
 }
 _models = nil
}

案例6:

寻找视图的所属控制器

lldb中,使用fvc指令

fvc -v 0x104b26050
-------------------------
Found the owning view controller.

案例7:

寻找指定控件

lldb中,使用fv指令

fv UIButton
-------------------------
0x104a0b710 UIButton
0x104b26050 UIButtonLabel
0x104b0b040 UIButton
0x104b248c0 UIButtonLabel
0x104b0b450 UIButton
0x104b10c60 UIButtonLabel

案例8:

指令的使用帮助

pviews --help
-------------------------
Usage:  [options]

Options:
 -h, --help            show this help message and exit
 -u, --up              Print only the hierarchy directly above the view, up
                       to its window.
 -d DEPTH, --depth=DEPTH
                       Print only to a given depth. 0 indicates infinite
                       depth.
 -w WINDOW, --window=WINDOW
                       Specify the window to print a description of. Check
                       which windows exist with "po (id)[[UIApplication
                       sharedApplication] windows]".
 -s, --short           Print a short description of the view
 -m, --medium          Print a medium description of the view

案例9:

让指定控件闪烁,可快速找到视图的位置

lldb中,使用flicker指令

flicker 0x113e0ad60 

案例10:

交互式搜索视图

lldb中,使用vs指令

vs 0x113e0ad60
-------------------------
Use the following and (q) to quit.
(w) move to superview
(s) move to first subview
(a) move to previous sibling
(d) move to next sibling
(p) print the hierarchy

>
  • w:移动到父视图
  • s:移动到第一个子视图
  • a:移动到上一个同级
  • d:移动到下一个同级
  • p:打印视图结构
  • q:退出调试状态
LLDB

LLDBaliases/regexesPython的脚本集合,可帮助开发者进行调试。详情可查看 官方文档

克隆LLDB

git clone https://github.com/DerekSelander/LLDB.git

打开~/.lldbinit,添加以下指令:

command script import /Users/LLDB/lldb_commands/dslldb.py

案例1:

查找UIView的所有实例和子类

lldb中,使用search指令

search UIView
-------------------------
; layer = >

>

>

>

; layer = >

>

>

>

>

>

; layer = >

>

案例2:

找到指定类的方法列表

lldb中,使用methods指令

methods UIViewController
-------------------------
in UIViewController:
  Class Methods:
      + (id) fallback_debugHierarchyChildGroupingID; (0x1047fcae4)
      + (id) fallback_debugHierarchyAdditionalGroupingIDs; (0x1047fcaf0)
      + (id) fallback_debugHierarchyObjectsInGroupWithID:(id)arg1 onObject:(id)arg2 outOptions:(id*)arg3; (0x1047fcb64)
      + (id) fallback_debugHierarchyPropertyDescriptions; (0x1047fcca4)
      + (id) fallback_debugHierarchyValueForPropertyWithName:(id)arg1 onObject:(id)arg2 outOptions:(id*)arg3 outError:(id*)arg4; (0x1047fdd98)
      + (void) initialize; (0x1a0433148)
...

找到方法地址,可以对其设置断点

b -a 0x1a0433148
-------------------------
Breakpoint 2: where = UIKitCore`+[UIViewController initialize], address = 0x00000001a0433148

案例3:

找回方法的符号

lldb中,使用sbt指令

sbt
-------------------------
frame #0 : 0x1c8afd8c4 libsystem_kernel.dylib`mach_msg_trap + 8
frame #1 : 0x1c8afccc8 libsystem_kernel.dylib`mach_msg + 72
frame #2 : 0x19e23774c CoreFoundation`__CFRunLoopServiceMachPort + 376
frame #3 : 0x19e231bd0 CoreFoundation`__CFRunLoopRun + 1176
frame #4 : 0x19e231200 CoreFoundation`CFRunLoopRunSpecific + 572
frame #5 : 0x1b432c598 GraphicsServices`GSEventRunModal + 160
frame #6 : 0x1a0af7004 UIKitCore`-[UIApplication _run] + 1052
frame #7 : 0x1a0afc5d8 UIKitCore`UIApplicationMain + 164
frame #8 : 0x10270e088 001--LLDB调试`___lldb_unnamed_symbol15$$001--LLDB调试 ... unresolved womp womp + 140
frame #9 : 0x19df10598 libdyld.dylib`start + 4
总结

虚拟内存

  • 所有程序的内存访问,都是通过虚拟地址访问的
  • 页表存储在内存中,记录状态、虚拟地址和物理地址的映射关系
  • 数据以页为单位加载,iOS系统一页为16KB

ASLR

  • 一种保护技术,在每次加载应用时,系统给一个随机的偏移值
  • 定位方法地址:
    lldb中,使用image list指令,找到MachO的首地址,包含ASLR
    ◦ 找到方法在文件中的虚拟地址或文件中的偏移地址
    ◦ 可以使用MachO首地址 + 文件中的偏移地址
    ◦ 或者使用文件中的虚拟地址 + ASLR

lldb插件

  • Chisellldb的指令集合,可帮助开发者调试iOS应用程序。详情可查看 官方文档
  • LLDBaliases/regexesPython的脚本集合,可帮助开发者进行调试。详情可查看 官方文档
  • 通过Python脚本自定义命令
  • 通过.lldbinit文件加载插件,使用command script import脚本

你可能感兴趣的:(iOS逆向实战--024:lldb高级调式)