iOS应用程序的脱壳实现原理浅析

应用程序加载过程

对于诸多逆向爱好者来说,给一个app脱壳是一项必做的事情。基于安全性的考虑,苹果对上架到appstore的应用都会进行加密处理,所以如果直接逆向一个从appstore下载的应用程序时,所能看到的“源代码”将非常的晦涩难懂。为了能看懂应用程序的“源代码”,就必须对应用程序进行解密,也就是所谓的脱壳。脱壳后的目的是可以分析应用程序的一些技术实现原理,或者利用一些漏洞进行攻击和测试。

这篇文章不是一篇介绍如何利用工具去进行脱壳的教程,而只是简单的分析这些常用脱壳工具的实现原理。要想了解脱壳原理,就要先去了解一个被加密的应用程序是如何被运行的。下面一张图片简单的介绍了一个被加壳后的应用程序被加载和运行的过程:

程序脱壳过程

脱壳原理以及常见的工具

要对一个壳应用进行脱壳处理,无非就是采用静态脱壳动态脱壳两种方法:静态脱壳就是在已经掌握和了解到了壳应用的加密算法和逻辑后在不运行壳应用程序的前提下将壳应用程序进行解密处理。静态脱壳的方法难度大,而且加密方发现应用被破解后就可能会改用更加高级和复杂的加密技术;动态脱壳就是从运行在进程内存空间中的可执行程序映像(image)入手,来将内存中的内容进行转储(dump)处理来实现脱壳处理。这种方法实现起来相对简单,且不必关心使用的是何种加密技术。从上面的壳应用程序运行的过程就可以看出无论壳程序如何被加密处理,最终运行后在进程中的代码映像(image)始终是被解密后的原始程序二进制。所以只要一个进程内存空间中的代码映像(image)能被读取和访问就可以实现动态脱壳。下面要介绍的两个工具就是巧妙的运用了两种不同的访问技巧来实现动态脱壳的。

一、利用动态库注入来实现脱壳的dumpdecrypted/frida-ios-dump

dumpdecrypted和frida-ios-dump都是在github上开源的项目,下载地址分别为:https://github.com/stefanesser/dumpdecryptedhttps://github.com/AloneMonkey/frida-ios-dump。关于使用这两个工具来进行脱壳的文档非常之多。我们知道一个应用除了有一个可执行程序外,还会链接非常多的动态库。动态库加载后和可执行程序共享相同的进程内存空间,而且动态库中的代码是可以访问整个进程内存空间中的有权限的区域的,包括可执行程序的image被加载到进程中的内存区域。因此只要想办法让应用程序加载某个特定的第三方动态库,也就是让这个第三方动态库注入到应用程序的进程中去就可以实现将被解密过后的可执行程序在进程内存中的image信息转储到文件中去从而实现脱壳处理。对于一个越狱后的设备来说主要可以通过两种方法来实现第三方动态库的注入:

  1. 设置环境变量DYLD_INSERT_LIBRARIES的值指向这个第三方动态库的路径。然后运行要脱壳的应用程序即可。 DYLD_INSERT_LIBRARIES环境变量的设置是一个操作系统提供的特性,所有运行的程序都会加载这个环境变量中所指向的动态库文件。

  2. 将第三方动态库文件保存在越狱设备的/Library/MobileSubstrate/DynamicLibraries/目录下并编写对应的库的同名plist文件,所有plist中指定的可执行程序一旦运行就会加载对应的动态库(此目录即Tweak插件所在的目录)。

还有一种直接修改对应mach-o格式的可执行文件内容来实现动态库注入。

动态库加载的问题解决后就需要解决动态库中代码运行的时机问题了。要想让一个被加载的动态库在加载后自动运行某一段代码可以有四种方法:

  1. 建立一个C++全局对象,并在对象所属类的构造函数中添加特定代码。

  2. 建立一个OC类,并在OC类的+load方法中添加特定的代码。

  3. 生成动态库时指定一个初始化init入口函数,并在入口函数中添加特定的代码。

  4. 在动态库中定义一个带有_attribute_((constructor))声明的函数,并在函数内添加特定的代码。

如果你想更进一步的了解上述那些方法的加载的原理,请参考我的文章:深入解构iOS系统下的全局对象和初始化函数

dumpdecrypted这个工具就是通过建立一个名为dumpdecrypted.dylib的动态库并在库内部定义了一个

__attribute__((constructor))
void dumptofile(int argc, const char **argv, const char **envp, const char **apple, struct ProgramVars *pvars)

函数来实现脱壳的。这个函数的大体实现会在后面继续介绍。

二、利用父子进程关系来实现脱壳的Clutch

Clutch也是一个在github上开源的项目,下载地址为:https://github.com/KJCracks/Clutch。关于这个工具的使用教程也非常之多。我们知道在unix系列的操作系统中父进程可以通过fork或者posix_spawnp两个函数来运行或者建立一个子进程的,这两个函数都会返回对应的子进程ID(PID)。iOS系统则可以通过task_for_pid函数来从进程ID获取进程在mach内核子系统中的mach port标识。得到mach port 标识后,就可以借助mach_vm_read_overwrite函数来读取指定进程空间中的任意虚拟内存区域中所存储的内容。因此Clutch内部的实现就是Clutch这个程序对将要进行脱壳的程序文件路径调用posix_spawnp函数来运行从而成为其子进程,然后借助task_for_pid以及mach_vm_read_overwrite函数来读取脱壳程序子进程在内存中已经被解密后的可执行程序的image所映射的内存空间来达到脱壳的目的的。

一个思考:可能在实际中并不一定要求是父子进程关系,是否只要某个具有特权的程序或者运行在root用户上的程序只要拿到了对应进程的PID就可以通过mach子系统提供的API来读取其他进程内存空间中的信息呢?

上述的两种方法中不管是dumpdecrypted还是Clutch最终都是将被解密后的可执行程序的image在内存中的映射写入到一个文件中去来保存脱壳后的内容。参考dumpdecrypted中的dumptofile函数实现以及Clutch中的Dumpers目录下的实现代码就可以看出:一个可执行程序image在内存中映射的内容的结构和mach-o格式的可执行文件结构基本上是保持一致的。都是有一个mach_header结构体头还有诸多的load_command结构体组成。因此所谓的dump处理就是将内存中的这些结构和数据原封不动的写入到文件中去即完成了脱壳中的最核心的部分。如果想仔细的阅读这部分代码的实现,建议先了解一下mach-o文件格式的组成。

后记

当你了解了这些内部实现后,也许你会发觉其实它的原理很简单。而且有可能你也能很快的去实现。可问题的关键是为什么这些方法总是别人能想到,而我们却想不到呢?这是否和国人的思维以及解决问题的方式相关呢?在我们的教育和实践体系中更多的是拿来主义和实用主义,往往很少人会对问题进行深入的探索研究以及进行问题的关联性思考。但愿这种情况在未来能够得到改进,尤其作为一个程序员,更加应该秉持探索求知的强烈意愿而不是简单复制和应用就满足了。

最后还是要感谢《iOS应用逆向与安全》的作者:刘培庆。向他咨询了逆向相关的一些知识后才得以写出这篇文章。并推荐逆向的爱好者阅读这本书。

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

推荐阅读更多精彩内容