首页
社区
课程
招聘
[原创]黑科技:把第三方 iOS 应用转成动态库
发表于: 2017-7-5 23:14 10545

[原创]黑科技:把第三方 iOS 应用转成动态库

2017-7-5 23:14
10545

转自自己的博客 3c9K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3u0D9L8$3N6Q4x3X3g2A6L8h3A6#2L8W2)9J5k6h3&6W2N6q4)9J5c8Y4m8G2M7%4c8K6i4K6u0r3j5$3!0F1N6X3g2J5N6q4)9J5k6r3W2a6f1#2)9J5k6r3q4H3M7q4)9J5k6s2c8G2i4K6u0V1k6s2W2F1j5h3#2A6j5#2)9J5k6r3I4A6j5Y4u0S2M7Y4W2Q4x3V1k6Q4c8f1k6Q4b7V1y4Q4z5p5y4Q4c8e0g2Q4z5p5g2Q4b7V1u0Q4c8e0g2Q4b7U0W2Q4b7U0c8Q4c8e0N6Q4z5f1q4Q4z5o6c8Q4c8e0k6Q4z5e0k6Q4z5o6N6Q4c8e0N6Q4b7f1u0Q4b7e0m8Q4c8f1k6Q4b7V1y4Q4z5p5y4Q4c8e0k6Q4z5f1c8Q4b7e0g2Q4c8e0N6Q4z5f1y4Q4z5p5u0Q4c8e0W2Q4z5f1u0Q4b7f1q4Q4c8e0N6Q4z5e0g2Q4z5e0W2Q4c8e0c8Q4b7U0S2Q4b7f1q4Q4c8e0g2Q4b7V1q4Q4z5e0f1`.

本文会介绍一个自己写的工具,能够把第三方iOS应用转成动态库,并加载到自己的App中,文章最后会以支付宝为例,展示如何调用其中的C函数和OC方法。

工具开源地址:

5d3K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6@1L8$3u0W2k6Y4g2@1N6i4u0W2M7W2)9J5c8X3q4H3M7o6u0V1P5h3I4A6j5R3`.`.

为什么要把第三方应用转成动态库呢?与一般的注入动态库+重签名打包的手段有什么不一样呢?

好处主要有下面几点:

可以直接调用别人的算法

逆向分析别人的应用时,可能会遇到一些私有算法,如果搞不定的话,直接拿来用就好。

掌控程序的控制权

程序的主体是自己的App,第三方应用的代码只是以动态库的形式加载,主要的控制权还是在我们自己手里,所以可以直接绕过应用的检测代码(文章最后有关于这部分攻防的讨论)。

同个进程内加载多个应用

重签名打包毕竟只能是原来的应用,但是如果是动态库的话,可以同时加载多个应用到进程内了,比如你想同时把美图秀秀和饿了么加载进来也是可以的(秀秀不饿,想想去年大众点评那个APPmixer的软广 - -! )。

我们要把应用转成动态库,首先要知道这两者之前有什么相同与不同,有相同的才存在转换的可能,而不同之处就是我们要重点关注的了。

可执行文件和动态库都是标准的 Mach-O 文件格式,两者的文件头部结构非常类似,特别是其中的代码段(TEXT),和数据段(DATA)结构完全一致,这也是后面转换工作的基础。

不同点就是我们转换工作的重点了,主要有:

头部的文件类型
一个是 MH_EXECUTE 可执行文件, 一个是 MH_DYLIB 动态库, 还有各种头部的Flags,要特别留意下可执行文件中Flags部分的 MH_PIE 标志,后面再详细说。

动态库文件中多一个类型为 LC_ID_DYLIB 的 Load Command, 作用是动态库的标识符,一般为文件路径。路径可以随便填,但是这部分必须要有,是codesign的要求。

可执行文件会多出一个 PAGEZERO段,动态库中没有。这个段开始地址为0(NULL指针指向的位置),是一个不可读、不可写、不可执行的空间,能够在空指针访问时抛出异常。这个段的大小,32位上是0x4000,64位上是4G。这个段的处理也是转换工作的重点之一,之前有人尝试转换,不成功就是因为没有处理好 PAGEZERO.

第一步是修改文件的头部信息,把文件类型从可执行文件修改成动态库,同时把一些Flags修改好。

这里一个比较关键的Flag是可执行文件中的 MH_PIE 标志位,(position-independent executable)。

这个标志位,表明可执行文件能够在内存中任意位置正确地运行,而不受其绝对地址影响的特性,这一特性是动态库所必须的一个特性。没有这个标志位的可执行文件是没有办法转换成动态库的。iOS系统中,arm64架构下,目前这个标志位是必须的,不然程序无法运行(系统的安全性要求),但是armv7架构下,可以没有这个标志位,所以支付宝armv7版本的可执行文件是不能转成动态库的,就是这个原因。不过所有的arm64的应用都是可以转换的,后面演示时用的支付宝是arm64架构的。

直接在文件头部中按照文档格式插入一个Load Command,并填入合适的数据。这里要注意下插入内容的字节数必须是8字节对齐的。

这部分是最重要的一部分,因为arm64上这个段的大小有4G,直接往内存中加载,会提示没有足够的连续的地址空间,所以必须要调整这个段的大小,而要调整 PAGEZERO 这个段的大小, 又会引起一连串的地址空间的变化,所以不能盲目的直接改,必须结合dyld的源码来对应修改。(注意这里不能直接把 PAGEZERO 这个段给去掉,也不能直接把大小调成0,因为涉及到dyld的rebase操作,详细看后面)

单纯减少 PAGEZERO 段的占用空间,作用不大,因为dyld加载动态库的时候,要求是所有的段一起进行mmap(详细可以查看dyld源码的ImageLoaderMachO::assignSegmentAddresses函数),所以必须把接下来所有的段的地址都重新计算一次。

同时要保证,前后两个段没有地址空间重叠,并且每个段都是按0x4000对齐。因为 PAGEZERO 是所有段中的第一个,所以可以直接把 PAGEZERO 的大小调整到0x4000,然后后面每一个段都按顺序依次减少同样大小(0xFFFFC000 = 0x100000000 - 0x4000),同时能保证每个段在文件内的偏移量不变。

修改前:

修改后:

这里的rebase是系统为了解决动态库虚拟内存地址冲突,在加载动态库时进行的基地址重定位操作。

这一步操作是整个流程里最重要的,因为按照前面的操作,整个文件地址空间已经发生了变化,如果dyld依然按照原来的地址进行rebase,必然会失败。

那么rebase操作需要做哪些工作呢?

相关的信息储存在 Mach-O 文件的 LINKEDIT 段中, 并由 LC_DYLD_INFO_ONLY 指定 rebase info 在文件中的偏移量

详细的rebase信息:

红框里那些Pointer的意思是说,在内存地址为 0x367C698 的地方有一个指针,这个指针需要进行rebase操作, 操作的内容就是和前面调整地址空间一样,每个指针减去 0xFFFFC000。

这个原因要涉及到文件中rebase信息的储存格式,上面的图中,可以看出rebase要处理的是一个个指针,但是实际上这些信息在文件中并不是以指针数组的形式存在,而是以一连串rebase opcode的形式存在,上面看到的一个个指针其实是 Mach O View 这个软件帮我们将opcode整理得到的。

这些opcode中有一种操作比较关键,REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB。


[培训]传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 1
支持
分享
最新回复 (6)
雪    币: 290
活跃值: (43)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
2
江西人民发来贺电
2017-7-5 23:18
0
雪    币: 183
活跃值: (350)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
3
好帖,前排支持
2017-7-5 23:31
0
雪    币: 36
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
通过用这个工具是不是可以有这个思路:把一个程序打包到另一个程序里运行??比如我在微信里打开一个qq,然后在手机上做分屏,上半屏微信,下半屏qq?
2017-7-5 23:53
0
雪    币: 3907
活跃值: (6181)
能力值: ( LV12,RANK:200 )
在线值:
发帖
回帖
粉丝
5
通过老司机的带领,成功关注上了念茜女神的推
2017-7-6 08:40
0
雪    币: 30
活跃值: (41)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
6
君神...
2017-7-17 10:23
0
雪    币: 2
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
如果能appstore.dylib 
2017-7-17 22:34
0
游客
登录 | 注册 方可回帖
返回