时时勤拂拭,勿使惹尘埃

TOC

Categories

iOS(十七) AppStore App砸壳/解密方法总结


0x0 前言

(ps:去年的一篇文章)

对于iOS安全研究而言,无论是恶意代码检测、还是漏洞挖掘,免不了需要对iOS App进行逆向分析、classdump、动态调试、hook等操作。

如下图,iOS的程序可以分为非越狱的ipa文件和越狱专用的deb文件。ipa文件使用Apple Bundle封装,运行会验证程序签名,常见有AppStore证书、企业证书、开发者证书三类;而deb文件使用Debian的程序封装格式,只适用于越狱后的Cydia及Apt-get包管理器安装方式。

上述几种iOS应用中,从AppStore下载的App都使用了AppStore的证书统一签名,使用codesign获取到的Authority都是Apple官方的信息,而TeamIdentifier字段则用于标记不同的开发者id:

此外,由于AppStore下载的App全都是经过苹果加密过的ipa包,无法对其进行反编译,也无法class-dump,需要对其进行解密才能反编译。如下图,使用IDA pro反编译未解密的AppStore App,解析出来的几乎都是乱码:

0x1 AppStore App加密过程

从App Store下载的iOS App都会受到Apple FairPlay DRM的保护,这利用iTunes的FairPlay Streaming (FPS)流媒体数字版权管理技术,主要用于在线流媒体的防盗版拷贝。FairPlay DRM技术最初是于2003年4月与iTunes Store在线音乐商店共同出现,在听音乐仅限购买CD/磁带以及盗版泛滥的时期,无疑是划时代的改变。

图 iTunes 4.0 with Music Store

在从iTunes商店购买内容之前,用户必须在苹果的服务器上创建一个帐户,然后授权一台PC或Mac运行iTunes。在授权过程中,iTunes为它所运行的计算机创建一个全球唯一的ID号,然后将其发送到苹果的服务器,然后分配给用户的iTunes帐户。当用户从iTunes商店购买歌曲时,会为购买的文件创建一个“用户密钥”。(参考:How FairPlay Works: Apple’s iTunes DRM Dilemma

在iTunes Store中,受FairPlay保护的音乐文件是常规的MPGE 4格式,会在该基础上使用AES算法加密为AAC音频文件。解密AAC音频所需的主密钥以加密的形式存储在MPGE 4容器文件中,解密主密钥所需的密钥即“用户密钥”。 过程大致如下图:

图iTunes FairPlay工作流程

而在iOS上,也是使用与iTunes音乐类似的流程。当从App Store下载应用程序时,Apple会将已签名的二进制文件与App Store帐户关联的公钥加密,并注入相关头信息。此处加密的密钥对在创建AppStore帐户时生成,并在使用AppStore帐户或Apple ID登录时转移到iOS设备上。

若在未登陆相应AppStore帐户或Apple ID的iOS设备上安装运行从AppStore下载的App,设备系统log会输出如下错误信息:

kernel[0] <Notice>: AppleFairplayTextCrypterSession::fairplayOpen() failed, error -42004 com.apple.xpc.launchd[1] 
(UIKitApplication:THE_APP_PACKAGE_NAME[0xdc32][203]) <Warning>: FairPlay decryption failed on binary.

0x2 Dyld加载App启动流程

在macOS和iOS上,可执行程序的启动依赖于xnu内核进程运作和动态链接加载器dyld,dyld可执行文件在设备上的路径为/usr/lib/dyld。

Dyld源码可从如下url获取:https://opensource.apple.com/source/dyld/

系统内核在加载Mach-O文件时,会调用dyld进行加载,然后调用到__dyld_start,后者会执行_main()函数,dyld加载动态库的代码就是从_main()开始执行。Dyld::_main会进行如下图8个操作,从而进入到App主程序的入口main函数:


图 dyld加载App流程图

由于dyld流程过于复杂,本文暂不细述,不过从上面dyld加载App流程图中可以发现,其中有两处可以获取到解密后的AppStore App,即“registerEncryption解密AppStore App”和“getEntryFromLC_MAIN进入程序入口”两部分,简单整理如下图:

“registerEncryption解密AppStore App”部分代码位于/dyld-733.6/src/ImageLoaderMachOCompressed.cpp文件,该部分是加载插入的动态库时执行,从注释可知是用于在内核中解密受FairPlay保护的加密App文件:

registerEncryption代码如下,实际是调用mreamp_encrypted函数进行解密:

mreamp_encrypted函数定义在xnu/bsd/kern中:

而“getEntryFromLC_MAIN进入程序入口”代码位于/dyld-733.6/src/dyld2.cpp,用于直接进入解密后的Mach-O文件的入口点,即通过registerEncryption在内核中解密出来的可执行文件入口点,如果getEntryFromLC_MAIN获取入口点失败,则会执行getEntryFromLC_UNIXTHREAD来获取:

getEntryFromLC_MAIN位于/dyld-733.6/src/ImageLoaderMachO.cpp,会把entryoff+ MachO头地址的和,作为程序的入口点进行加载:

0x3 解密AppStore App方法

通常而言,解密一个加密数据/文件,可以使用如下方式:

静态解密:分析加密过程,编写解密代码;
动态解密:

  1. 在物理设备上运行程序,然后从内存中转储解密后的数据;
  2. 在模拟器中运行程序,然后从内存中转储解密后的数据。

第一种静态解密的方式,需要花费大量的时间和精力去分析加密过程并编写解密代码,尤其Apple的FairPlay DRM保护技术属于商业机密,分析起来更为困难。

从上文dyld加载App启动流程中分析可知,App程序运行起来都会直接在内存中解密出原始代码,所以可以通过内存dump方式提取解密后的程序,这种解密又称为砸壳。不过由于iOS系统的沙盒限制,这些过程都需要越狱后才能进行。详情可以参考之前的文章:
iOS(九)内存dump应用&手动解密
iOS(十三)使用 bfinject 注入iOS 11_cycript & 砸壳
iOS(十五)几种App砸壳工具对比

0x31 内存dump

由于APP程序运行起来都会直接在内存中解密出原始代码,所以通过内存dump方式提取解密后的程序是普遍使用的方式。

一、ptrace手动内存dump

Ptrace是在Unix和类Unix的操作系统中使用的系统调用。通过使用ptrace(“ process trace”的缩写),一个进程可以控制另一个进程,从而使控制器能够检查和操纵目标的内部状态。常用的gdb和lldb调试器都是基于ptrace ,主要是作为软件开发调试的辅助工具。

使用Ptrace手动内存dump需要对Mach-O文件结构、gdb调试等有所熟悉,过程较为复杂:

  1. 使用otool指令解析AppStore下载的加密App获取应用Mach-O头信息:
    otool -l *.bin | grep crypt -3

    关注App的Mach-O头信息中LC_ENCRYPTION_INFO字段,其中cryptoff为加密代码在文件中的偏移,cryptsize为加密代码的大小,cryptid为1表示该部分代码为加密数据,为0则为未加密数据。
  2. 使用gdb/lldb调试器附加进程:
    先获取应用pid:ps aux | grep coyote

    再gdb附加进程:gdb -p pid
  3. 获取进程基址:
    由于iOS系统中,通常都会开启ASLR等漏洞缓解措施,进程加载的基址每次启动都会不同,所以每次dump时都要先获取进程的基址:
    gdb中使用:info sh
    获取到coyote基址为:0xe0000
  4. 计算解密后应用内存位置
    起始位置:基址+cryptoff偏移=0xe0000+hex(16384)=0xe4000
    终止位置:基址+cryptoff偏移+cryptsize混淆代码大小=0xe0000+hex(16384+5357568)=0x600000
  5. dump解密后的应用
    dump binary memory dump.bin 0xe4000 0x600000
    解密之后的dump.bin文件由于缺少头信息因此不能直接使用,还需要手动恢复Mach-O头信息才行。
  6. 恢复Mach-O头信息
    利用dd指令将Dump出的二进制文件重写如原来的MachO文件中:
    // dd seek=文件偏移地址 bs=单位为1子节 conv=转换方式(保留未被截取部分的内容) if=输入文件地址 of=输出文件地址
    dd seek=16384 bs=1 conv=notrunc if=./dump.bin of=./dump
  7. 更改MachO文件中的cryptid为0
    此时该MachO其实已经被解密成功了,但是MachO的cryptid字段还未被更改,所以cryptid此时还是1。可以直接打开MachOView,手动更改Crypt ID字段的Data值为0。

二、dumpdecrypted三方动态库注入

dumpdecrypted是最早出现也是最基础的砸壳方式,使用稍微复杂,通过手工注入动态dylib三方库文件方式来实现,绕过方式较多,比如添加编译参数禁用动态加载dylib库(dumpdecrypted也已经5年多未曾更新了)。

dumpdecrypted源码地址:https://github.com/stefanesser/dumpdecrypted

1.dumpdecrypted使用方式

  1. 编译dumpdecrypted
    由于dumpdecrypted未提供release版本,故需要自行下载编译:
    $ git clone https://github.com/stefanesser/dumpdecrypted.git
    $ cd dumpdecrypted
    $ make
    
    编译完成后会在当前目录下生成dumpdecrypted.dylib文件。
  2. 签名dumpdecrypted
    由于iOS系统限制,未签名程序无法直接执行,故编译好的dumpdecrypted.dylib文件需要签名后才能使用:
    首先获取macOS上的证书信息:
    $ security find-identity -v -p codesigning
    1) EBB2D**********E606F54704AF1C "Apple Development: *******@gmail.com (*******)"
      1 valid identities found
     再使用codesign给dumpdecrypted.dylib进行签名
    $ codesign -fs EBB2D**********E606F54704AF1C dumpdecrypted.dylib
    
  3. 添加Apple开发者证书
    如果macOS设备上没有Apple开发者证书,则需要通过Apple开发者网站注册账号(免费)。如果想要提交app到appstore,还需要缴费加入开发者计划才行。
    拥有Apple开发者账号后,在 Xcode -> Preferences -> Acounts 登陆账号,之后点击Manager Certificates即可添加开发者证书。

    添加完成后如下方式使用:
    # 列出可签名证书, 找到 mac 上面已经安装的证书
    $ security find-identity -v -p codesigning
    # 使用本机安装的开发者证书为 dumpecrypted.dylib 签名
    $ codesign --force --verify --verbose --sign "iPhone Developer: xxx xxxx (xxxxxxxxxx)" dumpdecrypted.dylib
    # 如果有Entitlements文件,可以签名程序并添加Entitlements
    $ codesign --force --verify --verbose --sign <自签名证书> --entitlements <资格文件> dumpdecrypted.dylib
    
    4.dumpdecrypted App
    #scp拷贝进越狱设备
    $ scp dumpdecrypted.dylib [email protected]:~/
    #连接设备
    $ ssh [email protected]
    #寻找目标App路径
    # ps -A
    7279 ??         0:00.94 /var/containers/Bundle/Application/C438C976-2657-46F1-83BE-07F2DFBAF5A7/**.app/**
    # DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib /var/containers/Bundle/Application/C438C976-2657-46F1-83BE-07F2DFBAF5A7/**.app/SYHDAppPayProject
    
    砸壳成功后会在目标目录下生成**.decrypted文件。
    如下图在iPhone SE iOS 13.1.2 with checkra1n设备中,依然可以成功砸壳。

2.dumpdecrypted源码简析

Dumpdecrypted通过lyld的DYLD_INSERT_LIBRARIES环境变量来注入App中。Dumpdecrypted解密方式与手动内存dump基本一致,都是先获取Mach-O文件头信息中的LC_ENCRYPTION_INFO、cryptoff、 cryptsize、 cryptid信息,再计算需要dump的地址并写入解密文件中:

三、Clutch posix_spawnp创建子进程dump

Clutch是继dumpdecrypted之后出现的全自动化砸壳工具,通过posix_spawnp系统调用来创建子进程,以父子进程关系来实现内存dump。
使用简单方便,高版本使用需重新编译签名后才能使用。

Clutch源码:https://github.com/KJCracks/Clutch

1.Clutch使用方式

  1. Clutch提供了编译好并签名的release版本:
    https://github.com/KJCracks/Clutch/releases
    当然也可以自行下载源码编译,部分iOS版本中不支持Fat Mach-O结构,故需要lipo指令对其瘦身并签名,如:
    lipo -thin arm64 Clutch -output clutch

  2. 下载源码编译
    Clutch源码:https://github.com/KJCracks/Clutch/
    按照说明使用以下指令编译:

    mkdir build
    cd build
    cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=../cmake/iphoneos.toolchain.cmake ..
    make -j$(sysctl -n hw.logicalcpu)
    
  3. 签名Clutch
    与dumpdecrypted一样,Clutch需要签名后才能使用,首先获取macOS上的证书信息:
    $ security find-identity -v -p codesigning
    1) EBB2D**********E606F54704AF1C "Apple Development: *******@gmail.com (*******)"
    1 valid identities found
    
    再使用codesign给dumpdecrypted.dylib进行签名
    $ codesign -fs EBB2D**********E606F54704AF1C dumpdecrypted.dylib
  4. 添加Entitlements资格文件
    Clutch的Entitlements资格文件位于:./Clutch/build/Clutch/Clutch.entitlements
    $ codesign --force --verify --verbose --sign <自签名证书> --entitlements <资格文件> Clutch
  5. 将clutch执行文件拷贝到手机里
    scp Clutch [email protected]:/usr/bin
  6. 查看当前手机程序未砸壳的应用
    Clutch -i
  7. 对列出的正版应用砸壳
    使用对应列表号或bundleID进行砸壳
    Clutch -d <com.diary.mood>
    或者
    Clutch -d 12

    如下图,在iPhone 7 iOS 13.2.2 with checkra1n系统中,Clutch经重新编译添加证书和Entitlements资格文件后,依然可以正常使用:

2.Clutch源码简析

Clutch需要以root权限运行,由此可以直接对所有App进行读写操作:

通过MobileInstallationLookup私有API获取App列表:

调用posix_spawnp创建需解密App的子进程:

与dumpdecrypted一样,通过Mach-O文件头信息中的LC_ENCRYPTION_INFO字段,获取cryptoff、 cryptsize、 cryptid信息,再计算需要dump的地址并写入解密文件中:

四、frida hook框架

frida-ios-dump是基于frida开发的一键砸壳工具,需要配置frida环境,源码下载:https://github.com/AloneMonkey/frida-ios-dump

1.frida-ios-dump使用方式

  1. 安装frida
    macOS:
    $ sudo pip install frida $ sudo pip install frida-tools
  2. iOS设备植入frida-server
    下载地址:https://github.com/frida/frida/releases
    选择对应firda版本和iOS设备cpu型号的frida-server,如本次为frida-server-12.6.0-ios-arm64.xz
    将frida-server拷贝到iOS设备的/usr/bin目录下,并chmod a+x frida-server后启动frida-server(frida-server已经签名过)
  3. 配置frida-ios-dump
    执行sudo pip install -r requirements.txt --upgrade即可,会自动安装依赖
    如果设备上的module版本不对,可以手动指定版本安装,如:pip install frida==12.6.0 --user
  4. 使用frida-ios-dump砸壳
    1)启动iOS设备上的frida-server
    2)修改frida-ios-dump的dump.py文件,指定iOS设备ip、端口、账号名、密码
    3)打开目标app
    4)mac上执行`python dump.py -l`查看ios app list
    5)mac上执行`python dump.py [BundleID]`即可一键砸壳
    

2.frida-ios-dump源码简析

frida-ios-dump使用frida hook框架注入到App程序中,同样通过Mach-O文件头信息中的LC_ENCRYPTION_INFO字段,获取cryptoffcryptsizecryptid信息,再计算需要dump的地址并写入解密文件中:

五、bfinject hook框架

1.bfdecrypt

由于Cydia越狱框架早已经停止更新,在一些高版本中已经无法使用,比如iOS 11通常使用Electra越狱,基于此出现了bfinject hook框架,以及对应的bfdecrypt砸壳工具。
更多信息参考:iOS(十三)使用 bfinject 注入iOS 11_cycript & 砸壳

1.1 bfdecrypt工具使用

1、 bfinject安装使用
bfinject的安装使用比较简单,参考github源码:https://github.com/BishopFox/bfinject

$ wget https://github.com/BishopFox/bfinject/raw/master/bfinject.tar .
$ scp bfinject.tar [email protected]:~/
$ ssh [email protected]
iPhone:~/bfinject root# mkdir bfinject
iPhone:~/bfinject root# mv bfinject.tar ./bfinject
iPhone:~/bfinject root# cd bfinject
iPhone:~/bfinject root# tar xvf bfinject.tar

使用bfinject,可以看到bfinject内置了注入工具cycript和砸壳工具decrypt,且支持其他dylib的注入:

iPhone:~/bfinject root# bash bfinject
Syntax: bfinject [-p PID | -P appname] [-l /path/to/yourdylib | -L feature]

For example:
   bfinject -P Reddit.app -l /path/to/evil.dylib   # Injects evil.dylib into the Reddit app
     or
   bfinject -p 1234 -L cycript                     # Inject Cycript into PID
     or
   bfinject -p 4566 -l /path/to/evil.dylib         # Injects the .dylib of your choice into PID

Instead of specifying the PID with -p, bfinject can search for the correct PID based on the app name.
Just enter "-P identifier" where "identifier" is a string unique to your app, e.g. "fing.app".

Available features:
  cycript    - Inject and run Cycript
  decrypt    - Create a decrypted copy of the target app
  test       - Inject a simple .dylib to make an entry in the console log
  ispy       - Inject iSpy. Browse to http://<DEVICE_IP>:31337/

2、使用bfdecrypt砸壳

iPhone:~/bfinject root# bash bfinject -P SYHDAppPayProject -L decrypt
[+] Electra detected.
[+] Injecting into '/var/containers/Bundle/Application/C438C976-2657-46F1-83BE-07F2DFBAF5A7/SYHDAppPayProject.app/SYHDAppPayProject'
[+] Getting Team ID from target application...
[+] Thinning dylib into non-fat arm64 image
[+] Signing injectable .dylib with Team ID MLP6RB876U and platform entitlements...
[bfinject4realz] Calling task_for_pid() for PID 378.
[bfinject4realz] Calling thread_create() on PID 378
[bfinject4realz] Looking for ROP gadget... found at 0x1843594e0
[bfinject4realz] Fake stack frame at 0x12e63c000
[bfinject4realz] Calling _pthread_set_self() at 0x18459b778...
[bfinject4realz] Returned from '_pthread_set_self'
[bfinject4realz] Calling dlopen() at 0x184359460...
[bfinject4realz] Returned from 'dlopen'
[bfinject4realz] Success! Library was loaded at 0x1c01f0a00
[+] So long and thanks for all the fish.

执行完成后会在App的数据目录(可以通过cycript获取App数据目录路径)下生成脱壳ipa文件:

iPhone:/var/mobile/Containers/Data/Application/BB2EB568-851B-42F4-AD1F-B9B4D5295755/Documents root# ls -al
total 17772
drwxr-xr-x 5 mobile mobile      160 May 30 13:14 ./
drwxr-xr-x 8 mobile mobile      256 May 27 09:48 ../
drwxr-xr-x 3 mobile mobile       96 May 27 10:37 .UTSystemConfig/
-rw-r--r-- 1 mobile mobile 17670111 May 30 13:09 decrypted-app.ipa
-rw-r--r-- 1 mobile mobile     1466 May 30 10:33 user.arch
1.2 bfdecrypt源码简析
Bfdecrypt源码与dumpdecrypted几乎一样,应该是基于dumpdecrypted二次开发:

2.crackerxi

CrackerXI+是GUI界面的iOS砸壳工具,未找到开源项目,发布在iphonecake社区:CrackerXI+

2.1 CrackerXI+工具使用

cydia源添加:https://cydia.iphonecake.com/

再从iphonecake源中添加CrackerXI+即可:

打开CrackerXI+App,Setting中打开Hook:

在AppList中点击想要脱壳的app,解密后生成的文件默认存储路径为:
/var/mobile/Documents/CrackerXI/

但由于测试设备为iOS 13.1.2 with checkra1n,缺少CrackerXI+依赖的hook框架,故提示hook失败:

2.2 CrackerXI+工具简析

/Applications/crackerxi.app/crackerxi启动即检查是否存在/bootstrap/inject_criticald文件,该文件是Electra越狱后框架文件:

/Applications/crackerxi.app/crackerxihook.dylib代码中有大量bfdecrypt相关的log:

再对比crackerxihook.dylib和bfdecrypt.dylib,发现主要代码基本一致:


最后使用bindiff对比crackerxihook.dylib和bfdecrypt.dylib,可以发现只有少量函数有差异,其他几乎完全一样。故可以确定CrackerXI+是复用了bfdecrypt的代码,并封装成了iOS GUI App。

0x32 mremap_encrypted内核私有API

mremap_encrypted是iOS 内核中的方法,用于解密iOS App,开发者John Coates通过分析dyld源码开发了该方式的利用工具flexdecrypt。

参考:Decrypting Apps on iOS
Github: https://github.com/JohnCoates/flexdecrypt

1、flexdecrypt工具使用

  1. flexdecrypt下载&安装
    Flexdecrypt提供了编译好的二进制文件,其deb文件下载地址:
    https://github.com/JohnCoates/flexdecrypt/releases/latest
    scp导入iOS设备中,通过dpkg指令安装:
    dpkg -i flexdecrypt.deb
    如果使用iOS 12.1或更低版本,可能还需要安装相关依赖:
    apt-get -f -y --allow-unauthenticated install
  2. 使用flexdecrypt砸壳
    flexdecrypt安装完成后,在iOS设备的shell中即可直接执行,flexdecrypt -h查看相关使用信息。
    flexdecrypt使用没有clutch、frida等工具方便,需要先获取文件路径,可启动APP后通过ps -A查看对应进程绝对路径,再flexdecrypt 即可完成解密,并在/tmp目录下生成对应文件:

2、mremap_encrypted源码分析

mremap_encrypted方法位于xnu/bsd/kern/kern_mman.c文件中,参考:
https://opensource.apple.com/source/xnu/xnu-6153.81.5/bsd/kern/kern_mman.c.auto.html

mremap_encrypted方法属于iOS 内核中的方法,功能用于解密iOS App,这里可以当作私有API来使用,使用的前提需要确定mremap_encrypted方法的用法、每个参数的意义。

下图为mremap_encrypted方法在/bsd/sys/mman.h中的声明,可以看到mremap_encrypted方法共有5个参数,但参数意义不明:

而mremap_encrypted方法在/bsd/kern/syscalls.master中的系统调用信息如下,可以看到mremap_encrypted方法5个参数的实际意义,分别是address、length、cryptId、cpuType、cpuSubType:

另外Flexdecrypt工具的FLXPrivateApi.h文件中也是使用/bsd/kern/syscalls.master中同样的声明:

mremap_encrypted方法在 /bsd/kern/kern_mman.c中声明如下:

在Flexdecrypt工具的MachOFile+Decrypt.swift文件中, mremap_encrypted方法的参数实际使用的也是cryptoff、cryptsize、cryptid,与手动内存dump基本一样,只不过此处直接调用内核私有API进行解密:

mremap_encrypted方法在 /bsd/kern/kern_mman.c中最终调用vm_map_apple_protected方法在内存中提取解密后的数据:

vm_map_apple_protected方法位于/osfmk/vm/vm_map.c,直接从虚拟内存页面提取解密后的数据:

0x33 小结

本文对比总结了目前常见的iOS App解密/砸壳工具,从手动内存dump,到各类工具的使用以及相关源码分析,初步展示了iOS App解密/砸壳的技术细节,希望对感兴趣的读者有所帮助。
下表列举了各个工具的对比:

解密工具 解密方式 操作复杂度 适用版本 最近更新时间 使用参考
ptrace内存dump 内存dump/ptrace注入 复杂 通用 内存dump应用&手动解密
dumpdecrypted 内存dump/三方动态库注入 较复杂 通用/但需重新编译 2014.2.13 几种App砸壳工具对比
Clutch 内存dump/子进程dump 简单 通用/需重新编译 2016.8.23 几种App砸壳工具对比
frida-ios-dump 内存dump/Frida hook框架 使用简单/环境配置麻烦 依赖frida hook框架 2020.6.1 几种App砸壳工具对比
bfdecrypt 内存dump/bfinject hook 框架 简单 依赖bfinject&Electra hook框架 2018.2.18 使用 bfinject 注入iOS 11_cycript & 砸壳
CrackerXI+ 内存dump/bfinject hook 框架 简单 依赖bfinject&Electra hook框架 2019.9.13 本文
flexdecrypt mremap_encrypted内核私有API 简单 通用 2020.7.2 本文

0x4 后续工作展望

0x41 OLLVM代码混淆

上文中,分析了iOS AppStore App的加密过程和目前常用的几种解密方式,可见AppStore的保护方式并不太理想。鉴于此,此外瑞士西北应用科技大学安全实验室于2010年6月份发起了OLLVM(Obfuscator-LLVM)项目,旨在提供一套开源针对LLVM的代码混淆工具,以增加对逆向工程的难度。但开源版本仅更新到llvm的4.0,2017年开始就不再更新了。

源码为:https://github.com/obfuscator-llvm/obfuscator

OLLVM提供了3种混淆方式分别是控制流扁平化,指令替换,虚假控制流程:

  1. 控制流扁平化:主要将if-else语句,嵌套成do-while语句;
  2. 指令替换:用功能上等效但更复杂的指令序列替换;
  3. 虚假控制流程:会在简单运算外嵌套几层虚假逻辑判断;

以一段简单代码为例,经过这些操作,即可将一段简单的代码混淆成逻辑复杂且繁琐,极大的增加了逆向分析的难度:


因此对于企业和个人开发者而言,仅AppStore的保护是不够的,还需要使用类似OLLVM的代码混淆工具对iOS App进行保护。另外,由于OLLVM未添加基础字符串/函数名等混淆,以及反OLLVM混淆技术的发展,所以还有更多工作需要后续来完成。

0x42 AppStore 样本采集

不过上述这些内容更偏向研究性质,对于公司或者团队而言,其实应该在工程化中作为前置实现更多功能,如针对AppStore可以做自动样本采集并解密,之后即可用于检测发现已知和未知恶意代码,或者反编译后进行二进制代码审计漏洞挖掘: