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
-------------------------
<UIWindow: 0x104b08cd0; frame = (0 0; 414 736); gestureRecognizers = <NSArray: 0x280429830>; layer = <UIWindowLayer: 0x280a5ac00>>
  | <UITransitionView: 0x104a0bfa0; frame = (0 0; 414 736); autoresize = W+H; layer = <CALayer: 0x280a4e8e0>>
  |    | <UIDropShadowView: 0x104b0b870; frame = (0 0; 414 736); autoresize = W+H; layer = <CALayer: 0x280a5ffc0>>
  |    |    | <UIView: 0x104a06750; frame = (0 0; 414 736); autoresize = W+H; layer = <CALayer: 0x280a4ede0>>
  |    |    |    | <UIButton: 0x104a0b710; frame = (94 350; 31 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x280a4eea0>>
  |    |    |    |    | <UIButtonLabel: 0x104b26050; frame = (0 6; 31 18); text = ''; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x282960e10>>
  |    |    |    | <UIButton: 0x104b0b040; frame = (192 350; 31 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x280a5d000>>
  |    |    |    |    | <UIButtonLabel: 0x104b248c0; frame = (0 6; 31 18); text = ''; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x282960910>>
  |    |    |    | <UIButton: 0x104b0b450; frame = (302 350; 31 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x280a5dd80>>
  |    |    |    |    | <UIButtonLabel: 0x104b10c60; frame = (0 6; 31 18); text = ''; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x282960280>>

指定View下的视图结构

pviews self.view

指定View的上层视图结构

pviews -u self.view

案例2:

查看控制器的视图结构

lldb中,使用pvc指令

pvc
-------------------------
<ViewController 0x104a09fd0>, state: appeared, view: <UIView 0x104a06750>

案例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.
<ViewController: 0x104a09fd0>

案例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

<UIButton: 0x113e0ad60; frame = (94 350; 31 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x282601d60>>
  • 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
-------------------------
<UIWindow: 0x104b09930; frame = (0 0; 414 736); gestureRecognizers = <NSArray: 0x280b8db00>; layer = <UIWindowLayer: 0x2805c6780>>

<UIButton: 0x104b0d9e0; frame = (192 350; 31 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x2805c7dc0>>

<UIButtonLabel: 0x104b1efb0; frame = (0 6; 31 18); text = '保存'; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x2826f3750>>

<UIButtonLabel: 0x104b0f800; frame = (0 6; 31 18); text = '继续'; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x2826f3700>>

<UIDimmingView: 0x104b0a9c0; frame = (0 0; 0 0); opaque = NO; gestureRecognizers = <NSArray: 0x280bbd1d0>; layer = <CALayer: 0x2805c6dc0>>

<UIButtonLabel: 0x104c11180; frame = (0 6; 31 18); text = '暂停'; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x2826e7890>>

<UIButton: 0x104b0de20; frame = (302 350; 31 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x2805c7ea0>>

<UIDropShadowView: 0x104b0e300; frame = (0 0; 414 736); autoresize = W+H; layer = <CALayer: 0x2805f4460>>

<UIView: 0x104b07520; frame = (0 0; 414 736); autoresize = W+H; layer = <CALayer: 0x2805c7720>>

<UIButton: 0x104b09c20; frame = (94 350; 31 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x2805c74a0>>

<UIDimmingView: 0x104c07ed0; frame = (0 0; 0 0); opaque = NO; gestureRecognizers = <NSArray: 0x280bbd200>; layer = <CALayer: 0x2805da380>>

<UITransitionView: 0x104b09730; frame = (0 0; 414 736); autoresize = W+H; layer = <CALayer: 0x2805f4d40>>

案例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脚本
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,193评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,306评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,130评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,110评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,118评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,085评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,007评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,844评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,283评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,508评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,395评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,985评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,630评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,797评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,653评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,553评论 2 352

推荐阅读更多精彩内容