逆向的大门已经打开,就算过敏体质也值了

最近小半个月的研究,终于有了一点点收货。在此记录一下整个系统学习的过程

丢掉了过去浮躁的自己,静下心来,重新开始学习计算机和编程。
删掉了所有之前写的辣鸡博客,不仅一文不值,还可能误人子弟,而且增加了其他同学信息检索的难度。

不多说了,开始正题吧。
本文共分为两部分:技术篇 和 成长篇(或者叫学习之路or废话篇)。
那么 开始吧~

(一)技术篇

问题描述

warning: failed to set breakpoint site at 0x206f43600 for breakpoint 1.1: error: 0 sending the breakpoint request

已知条件

Wechat 模块基地址:0x0000000102a94000

image.png

IDA工具中 函数偏移量:00000001044AF668

image.png

so 理论上最终虚拟内存地址: 0x102a94000 + 0x1044AF668 = 0x206f43600

断点该地址:br s -a 0x206f43600
控制台输出:

warning: failed to set breakpoint site at 0x206f43600 for breakpoint 1.1: error: 0 sending the breakpoint request 

WTF ??而且 尝试用 x 0x206f43600 命令访问内存内容也失败了。这是为什么呢?

解决过程

百思不得其解的时候,就百度了一下:(还木有买VPN呐)http://bbs.iosre.com/t/debugserver-lldb/6399
在这里,笔者提到了一句话对我很有帮助:

image.png

下面的问题思路很对:那怎么查看正确的偏移量呢?虽然没人回答他,但我突然想到了点什么。。。

如下图,我用IDA静态分析Wechat Mach-O文件的时候,隐约记得Mach-O Header的起始地址好像不是0啊!这就不应该了,单cpu架构Mach-O文件,最开始的内容就是Mach-O Header,所以 IDA工具分析出的地址值应该减掉这个偏移数值才对。


image.png

所以,我重新计算并设置了一下断点位置(如下图):

(进程基址)0x102a94000 + (函数offset)0x1044AF668-0x100000000 = 0x106f43668

最终虚拟地址 = 0x106f43668

(lldb) dis -s 0x106f43668

image.png

该断点断的函数是微信首次启动 右上角的语言切换按钮。点击按钮应该可以触发断点。(纯属学习和测试~ )

测试了一下,bingo!

目标函数断点成功
至此 结合lldb寄存器相关指令(register -[]),就可以愉快的调试三方app的函数了呢~

PS: 发现了一个坑,需要注意一下

使用image list命令时候,加参数跟不加参数,打印的地址是不一样的。区别如下:
image list 列出的WeChat地址: 0x102a94000
image list -o -fWeChat地址: 0x002a94000
看出区别了么?第9位差了一个1
这个1正好跟IDA工具中的0x 1 0000 0000对上了。

至于第9位为1的原因,终于找到了。在杨潇玉大哥的这篇文章中。main()调用之前会调用exec()exec() 是一个系统调用。系统内核把应用映射到新的地址空间,且每次起始位置都是随机的(因为使用 ASLR)。并将起始位置到 0x000000 这段范围的进程权限都标记为不可读写不可执行。如果是 32 位进程,这个范围至少是 4KB;对于 64 位进程则至少是4GB。NULL 指针引用和指针截断误差都是会被它捕获。4GB = 232,用二进制表示就是:第32+1位为1,剩下的32位为0。而4位二进制位可以表示一个十六进制位,所以十六进制表示就是:0x 1 0000 0000。这样就满足了64位进程至少4GB的最小偏移范围了。

(二)成长篇

关于逆向,我是用MonkeyDev的集成工具,手机不越狱也行。
该集成工具是AloneMonkey集成的。有人评价他“后起之秀”,看了他首页的介绍:"写过驱动,研究过文件系统…",我一开始以为这是个八零后大哥。后来看他github才发现,是个93年的弟弟。。。


Alonemonkey博客

想想自己是91年的,唉。。走了太多弯路。
这次有幸因为需求太神奇,总之我需要研究逆向,来搞定一些事情。为此我才了解了MonKeyDev。然而在真正进行逆向的时候,发现只有逆向工具是远远不够的,看不懂汇编,看不懂内存地址,看不懂runtime代码...

什么也看不懂,还搞什么逆向!

在接这个任务之前,我正沉浸在flutter的世界中无法自拔。
虽然才调研了3天,但我已经学会了dart语言,熟悉了flutter开发完全不同于native开发的思想(状态管理、weight树),了解了flutter跟iOS如何通信,开始写点简单项目了。
一想到学习近期学习能力还不错,就对逆向很不服气!
于是我不再浮躁,开始从最底层入手:汇编语言

网上查了很多资料,各种CPU架构的汇编语言,就算arm指令集也有好多文章资料,越看越头大!怎么办?静下心,从头开始。知乎找到一本大家公认的学习汇编很好的书籍:《汇编语言第3版》-王爽著
前言里提到这本书的一个特点——“通俗易懂”,我觉得作者在吹。汇编语言能通俗易懂???
反正我不信,于是带着不相信的心情开始了汇编语言学习。
可能是因为作者水平太高,我只用了周末一天半的时间,就学完了。

作者真的做到了像自己说的:从外层入手,一层层讲解CPU工作原理,一点点剖析,逐渐深入计算机内部,而且作者还在合适的位置告诉读者应该避免一些思想误区,真的很贴心啊!!感动到哭!

能看懂和写点简单汇编程序了,觉得自己屌屌的,于是又开始重新踏上iOS逆向之路。
但是又被打脸了。arm64架构的指令集跟8086架构完全不同啊。。

Xcode打印的汇编和寄存器信息跟王爽讲的8086汇编完全不一样!好像从iPhone5s一代起,苹果开始用arm64架构了。
于是我又踏上了计算机和iOS底层学习之路:

  • [x] 调研arm64指令集
  • [x] 调研反汇编工具
  • [x] 重温操作系统内存分配
  • [x] 下载runtime源码阅读、做实验
终于 走火入魔,浆糊了!

什么虚拟内存、物理内存、缺页中断、内存换算。。
什么寄存器基地址、内存偏移地址。。

什么进程基地址、函数偏移地址。。
什么Mach-O addr字段、offset字段!

这么多偏移量!这么多内存的概念!什么跟什么!想要放弃了!
在放弃和不服气的边缘挣扎,于是不小心发现了下图中的一行文字:


image.png

就是这行计算地址的文字,让我把之前学的所有东西 融会贯通了!

原来lldb打印的地址就是我们讲的函数或数据在进程内存空间中的虚拟地址,通过lldb直接访问xcode打印的地址,就可以看到我们想要的内容。那么 这个地址怎么计算呢?

app二进制程序(即Mach-O文件)在进程中基地址(进行启动时系统随机分配的偏移地址) + 目标函数或数据相对于Mach-O Header的偏移量。

操作系统讲的虚拟内存、物理内存跟我们进程讲的虚拟地址 不是一回事,在此处可以先不用去深究。

寄存器相关的 偏移地址、基地址 也不用理会了。 因为8086 CPU是16位机,有16位数据总线,却有20位地址总线,20位数据明显比16位数据携带的信息范围大,所以一次16位数据读写指令 没法读写完整的20位地址数据,所以20位地址数据被分成了两部分:基地址 + 偏移地址22021616倍,所以以前CPU里有个地址加法器,需要用段基址寄存器的值*****16 + 偏移地址的值 才得出 最终物理地址

现在都是CPU寄存器都是64位了,数据总线是64位,260
啊,这么大的一个数值!
232 就是4G(因为硬件存储单位是字节,所以不用除8)
2424T
264 是。。。您自个儿算一下有多大吧!

计算机根本没有这么大的内存,读写地址值的时候根本不用再偏移了,所以也就不用考虑寄存器如何计算地址了。

也正因此 在runtime中 iOS对象的64位地址只用了其中33位,剩下的位数用来做别的标记位,且还没用完。。这样既节省了内存空间,也提高了一些逻辑运算效率

地址搞定了,断点搞定了,逆向的大门终于向我们打开。

感谢自己这段时间的努力

虽然 可能因为这段时间的压力 得了过敏体质,但我还是很开心的。
抵抗力下降的信号来的也很友好,让我知道自己该强身健体了,比很多猝掉的程序猿幸运很多了。
总之 加油吧。

你可能感兴趣的:(逆向的大门已经打开,就算过敏体质也值了)