如何符号化Objective-C调用栈

本文讲述的是符号化“残破”的栈,如果你有一个系统生成的crash日志,请交给Xcode自带的symbolicatecrash脚本。

Symbolicatecrash脚本的核心也是通过atos功能逐行符号化,但人家封装好了,比自己手动一行一行做快很多。

示例栈:

    0   XSQSymbolicateDemo                  0x00000001000ba530 XSQSymbolicateDemo + 25904
    1   XSQSymbolicateDemo                  0x00000001000ba4f0 XSQSymbolicateDemo + 25840
    2   XSQSymbolicateDemo                  0x00000001000ba4bc XSQSymbolicateDemo + 25788
    3   XSQSymbolicateDemo                  0x00000001000ba478 XSQSymbolicateDemo + 25720
    4   UIKit                               0x00000001966870ec <redacted> + 96
    5   UIKit                               0x000000019668706c <redacted> + 80
    6   UIKit                               0x00000001966715e0 <redacted> + 440
    7   UIKit                               0x0000000196686950 <redacted> + 576
    8   UIKit                               0x000000019668646c <redacted> + 2480
    9   UIKit                               0x0000000196681804 <redacted> + 3192
    10  UIKit                               0x0000000196652418 <redacted> + 340
    11  UIKit                               0x0000000196e4bf64 <redacted> + 2400

这是我写的一个demo app,并且在编译后期滤去了符号表,所以仅能看到一些奇怪的地址。

如何符号化第三方app内的符号

以第一行:

0   XSQSymbolicateDemo                  0x00000001000ba530 XSQSymbolicateDemo + 25904

为例

需要条件:

(1)atos工具(Xcode安装时一般会自带)

(2)确认app运行的架构(armv7、arm64)

(3)app对应的dSYM文件(出包时获得)

(4)app代码载入到内存的基地址(后文详细介绍)

方法:

在命令行中输入:

xcrun atos -arch arm64 -o ./XSQSymbolicateDemo.app.dSYM/Contents/Resources/DWARF/XSQSymbolicateDemo  -l  0x1000b4000 0x00000001000ba530

即可得到符号化后的结果:

-[ViewController helloWorld2] (in XSQSymbolicateDemo) (ViewController.m:100)
如何符号化系统动态库中的符号

以这一行为例:

4   UIKit                               0x00000001966870ec <redacted> + 96

需要条件:

(1)atos工具(Xcode安装时一般会自带)

(2)确认app运行的架构(armv7、arm64)

(2)该OS版本、该动态库的符号文件(将该手机连接到电脑的Xcode上,会自动同步系统符号文件)

(3)该动态库载入到内存的基地址(后文详细介绍)

方法:

在命令行中输入:

xcrun atos -arch arm64 -o ~/Library/Developer/Xcode/iOS\ DeviceSupport/10.3.1\ \(14E304\)/Symbols/System/Library/Frameworks/UIKit.framework/UIKit -l  0x196642000 0x00000001966870ec
-[UIApplication sendAction:to:from:forEvent:] (in UIKit) + 96

即可得到符号化后的结果:

-[UIApplication sendAction:to:from:forEvent:] (in UIKit) + 96
如何获取基地址

注意:基地址在进程每次启动时决定,所以重启进程后,符号化时必须使用当次启动的基地址

方案一:从iOS生成的crash日志中获取

在iOS系统生成的crash日志中的下半部分,有这样的一些信息:

蓝色框圈出来的部分,即为app代码载入到内存的基地址

红色框圈出来的部分,即为各个动态库载入到内存的基地址

方案二:在app运行时打印

可以在app中调用如下代码获取各个image的基地址:

void printAllImage()
{
    for (int i = 0; i < _dyld_image_count(); i++) {
        char *image_name = (char *)_dyld_get_image_name(i);
        const struct mach_header *mh = _dyld_get_image_header(i);
        intptr_t vmaddr_slide = _dyld_get_image_vmaddr_slide(i);
        
        NSLog(@"Image name %s at address 0x%llx and ASLR slide 0x%lx.\n",
               image_name, (mach_vm_address_t)mh, vmaddr_slide);
    }
}

得到如下输出:

Image name /var/containers/Bundle/Application/351121C8-CFE4-49AD-ACC0-A70C5BF1C4A6/XSQSymbolicateDemo.app/XSQSymbolicateDemo at address 0x1000b4000 and ASLR slide 0xb4000.
 Image name /System/Library/Frameworks/Foundation.framework/Foundation at address 0x190f0c000 and ASLR slide 0xeedc000.
 Image name /usr/lib/libarchive.2.dylib at address 0x190ee0000 and ASLR slide 0xeedc000.
 Image name /usr/lib/libbz2.1.0.dylib at address 0x190e9e000 and ASLR slide 0xeedc000.
 Image name /usr/lib/libSystem.B.dylib at address 0x18ef04000 and ASLR slide 0xeedc000.
 Image name /usr/lib/system/libcache.dylib at address 0x18f35a000 and ASLR slide 0xeedc000.
......

可以看到第一行代表的是app自身,之后的每一行是app载入的动态库们。

介绍加载和ASLR

大致理解:

在进程启动的时候,内核加载器或者dyld会将指令加载到内存中。

ASLR全名Address Space Layout Randomization,地址空间布局随机化,用于防范恶意程序对已知地址进行攻击

在ASLR引入之前,由于加载的规则是固定的,所以理论上,一个进程不管重启多少次,每条指令对应的内存中的地址都是一样的。而每条指令对应到内存中的哪个地址,可以通过分析Mach-O文件分析出来。这就容易产生安全漏洞。

ASLR引入后,在进程启动前期的加载阶段,会生成一个随机数offset,让加载形成的内存整体偏移一个offset。

这样一个进程多次启动,每次行程的内存空间布局都不完全一致。同一个指令,经过多次启动,每次都会被布局到一个新计算出来的地址。

所以仅仅凭借“一个指令在内存中的地址”和dSYM文件,是无法进行符号化的,因为这个“地址”同时依赖于ASLR生成的offset。

我理解其实只需要一个offset,配合已知的架构、加载方式等信息,应该就能推测出app自身的基地址和各个库的基地址。尝试后也证明,各个库的基地址-offset后的值在同个设备的多次启动上是一致的。
但是为了图省事,还是自己打印一下所有库的基地址吧(´・ω・`)

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

推荐阅读更多精彩内容