iOS逆向之从砸壳到重签名

10,711 阅读9分钟

一、概述

笔者做了多年的业务开发,以前对逆向知之甚少,好像我们做iOS的开发者对应用本身的安全问题总不是那么上心,总以为Apple自身的加密签名机制足够安全了,我们除了关心业务网络安全,对自身App包的安全重视度总是不够。然而一旦我们的包被有心人破解,那么无论是对自身业务还是用户数据都是致命的。真正开始研究逆向,才发现我们App是如此的不堪一击。所以研究逆向其实是研究Hacker是如何攻破我们的应用,从而更好地保护自身应用安全。

研究逆向,首当其冲的就是重签名,重签名就是用自己的证书签名别人的应用,从而进行分发。重签名说白了就是套壳别人的应用,挺火的微信双开,其实就是对微信进行了重签名。而重签名首先要做的就是对应用砸壳。

二、手机越狱与应用砸壳

我们从App store 下载的应用是经过苹果加密签名过的,是无法进行重签名的。所以重签名首先要做的就是对应用进行砸壳,而砸壳需要你有一台越狱手机。

1. 手机越狱

目前主流的越狱平台有PP助手、爱思助手做到比较好,提供一键越狱功能。我自己使用的爱思助手,下载爱思助手电脑版,选择【工具箱】-【一键越狱】,此时会匹配你当前手机版本的越狱工具,选择工具进行越狱。 我使用的是 iphone SE,系统版本是14.4,按照提示完成越狱就OK了。

需要注意,这种越狱方式是不完美的越狱,当你重启手机后会重新变回非越狱状态,需要重新走一遍越狱流程。不过对于我们研究逆向足够了。

还没完,越狱完成后需要安装一个插件:Apple File Conduit"2",安装这个插件的目的是,让我们的电脑端能访问设备的根文件目录,安装方式也很简单,可以参考这篇文章Apple File Conduit"2"安装,这里不再赘述。当我们安装完成后,爱思助手连接手机,可以看到在【文件管理】中多了个栏目【文件系统(越狱)】,这就是越狱状态下的系统根目录。

2. ipa应用砸壳

首先了解什么是应用砸壳:我们提交到App Store发布的App都是经过Apple加密的,这样可以确保安装到我们手机的应用都是苹果审核授权的,当然通过企业级证书或者开发者证书生成的App是不需要砸壳的。对于App Store加密的应用,我们无法通过Hopper等反编译静态分析,也无法class-dump,在逆向分析过程中,需要对加密的二进制文件进行解密才可以进行静态分析,这一过程就是大家熟知的砸壳。 砸壳主要有两种方式:

  • 静态砸壳 静态砸壳就是在已经掌握和了解到了壳应用的加密算法和逻辑后,在不运行壳应用程序的前提下将壳应用程序进行解密处理。静态脱壳的方法难度大,而且加密方发现应用被破解后,就可能会改用更加高级和复杂的加密技术。
  • 动态砸壳 动态砸壳就是从运行在进程内存空间中的可执行程序映像(image)入手,来将内存中的内容进行转储(dump)处理来实现脱壳处理。这种方法实现起来相对简单,且不必关心使用的是何种加密技术。所以目前市面上的砸壳工具都是基于动态砸壳进行的。动态砸壳有多种工具:ClutchdumpdecryptedCrackerXI App,前两种对系统要求较严格,而且年久失修很容易砸壳失败,我们直接介绍最方便的第三种方式:利用CrackerXI App进行砸壳。

(1) 在Cydia中下载CrackerXI App

Cydia类似于越狱前的App Store,越狱后我们所有的软件都是通过Cydia来进行安装。打开Cydia后,选择【软件源】-右上角【编辑】-点击【添加】,输入http://apt.wxhbts.com/,【添加源】等待添加完成。添加软件源完成后,搜索CrackerXI App,点击安装完成后【重启springboard】,回到桌面,可以看到桌面上安装完成了CrackerXI+App.

(2) 砸壳

提前在App Store 下载好你要砸壳的App,打开CrackerXI+,选择【AppList】然后点击你要砸壳的应用,在弹框中选择【YES,Full IPA】,此时会打开我们要砸壳的应用进行砸壳,完成后会看到一个砸壳后的文件地址/var/mobile/Documents/CrackerXI/*****.ipa,这个文件就是我们砸壳后的ipa包。

这个路径怎么查找相信聪明的你已经知道了,去爱思助手-【文件管理】-【文件系统(越狱)】查找到这个ipa,导出到桌面目录就完成了。

(3) 验证

完成上面的操作后,我们需要验证一下拿到的ipa是否是被砸壳的。把.ipa包扩展名改为.zip,解压后得到Payload文件夹,右键【显示包内容】- 找到可执行文件.

终端输入

otool -l 执行文件名 | grep crypt

可以看到cryptid的值为0,说明砸壳成功。

三、重新签名

Apple 应用的分发一般有以下几种方式:

  • 最常用的是从App store下载应用。这种下发方式不受设备数的限制,只要上线App store 的应用,都会被Apple进行签名加密.
  • 第二种方式是申请企业账号,把我们的应用通过企业账号进行签名,从而绕过App store恼人的审核机制,达到分发应用的目的。这种方法分发数目也不受限制.
  • 第三种是通过TestFlight进行测试版本的分发,他分为内部测试人员与外部测试人员。通过分发外部测试人员,最多能给1万名用户进行分发安装.
  • 第四种开发人员通过添加设备ID安装应用,最多可以注册100台设备.

不同的开发者账号对应着App不同的分发方式,我们申请完成开发者账号后,创建应用Id,然后创建其对应证书,描述文件等一系列动作,实际已经决定了它的分发方式了。可以这样理解:每一个应用Id后面对应一套证书,这套证书决定了你应用的分发方式。重签名就是为当前的应用换一套应用Id与证书,从而达到分发应用的目的。现实的需求是,如果你上线App Store的应用,想通过企业账号的形式进行分发,而你又没有源码,或是想探究一下应用双开,那么重签名就派上用场了。我们介绍两种重签名的方式:

1.Xcode 重签名

(1) 新建同名的工程文件

注意这里的同名并不是Bundle Identifier 相同,而是跟你砸壳解压ipa文件,Payload里面的包相同的名称

还需要注意,如果你重签名的工程中是通过AppDelegate来监听App的生命周期的话,那么需要在新版的Xcode中移除SceneDelegate这个类,重新使用AppDelegate来监听App的生命周期。重新配置完成工程后,真机运行,把描述文件安装到手机里。

(2) 替换编译的App包

找到我们砸壳过的Payload文件夹中包,对我们编译的包进行替换

(3) 对二进制文件中的FrameWork进行重签名

其实在这一步之前还需要对包内的PlugIns插件以及Watch相关组件进行删除,我们逆向包里面没有这些组件,所以省略了。

进入Framework 文件夹,利用CodeSign对Framework进行证书签名,注意要对所有FrameWork进行重签名。

codesign -fs "复制的你自己的证书名字" 要重签的FrameWork名称

证书的名字就是你真机测试的证书的名称,如果不知道可以去钥匙串中查看

iPhone Developer: *** ** (********) 就是证书名称

(4) 重签名后运行

这样我们就在没有源码的情况下,完成了对应用的重签名。

2. 使用脚本文件重签名

利用shell脚本进行重签名的原理,跟上面的签名原理相同,只不过把重签步骤给脚本化了。

(1) 创建空工程(工程名随便),并且进行真机运行

(2) 在工程根目录下创建APP文件夹,在文件中放入我们砸壳后的ipa包

(3) 在工程中添加脚本

在工程Build Phases中新建脚本文件

Run Script中添加脚本

# Type a script or drag a script file from your workspace to insert its path.
# Type a script or drag a script file from your workspace to insert its path.
# ${SRCROOT} 为工程文件所在的目录
TEMP_PATH="${SRCROOT}/Temp"
#资源文件夹,放三方APP的
ASSETS_PATH="${SRCROOT}/APP"
#ipa包路径
TARGET_IPA_PATH="${ASSETS_PATH}/*.ipa"

#新建Temp文件夹
rm -rf "$TEMP_PATH"
mkdir -p "$TEMP_PATH"

# --------------------------------------
# 1. 解压IPA 到Temp下
unzip -oqq "$TARGET_IPA_PATH" -d "$TEMP_PATH"
# 拿到解压的临时APP的路径
TEMP_APP_PATH=$(set -- "$TEMP_PATH/Payload/"*.app;echo "$1")
# 这里显示打印一下 TEMP_APP_PATH变量
echo "TEMP_APP_PATH: $TEMP_APP_PATH"

# -------------------------------------
# 2. 把解压出来的.app拷贝进去
#BUILT_PRODUCTS_DIR 工程生成的APP包路径
#TARGET_NAME target名称
TARGET_APP_PATH="$BUILT_PRODUCTS_DIR/$TARGET_NAME.app"
echo "TARGET_APP_PATH: $TARGET_APP_PATH"

rm -rf "$TARGET_APP_PATH"
mkdir -p "$TARGET_APP_PATH"
cp -rf "$TEMP_APP_PATH/" "$TARGET_APP_PATH/"

# -------------------------------------
# 3. 为了是重签过程简化,移走extension和watchAPP. 此外个人免费的证书没办法签extension

echo "Removing AppExtensions"
rm -rf "$TARGET_APP_PATH/PlugIns"
rm -rf "$TARGET_APP_PATH/Watch"

# -------------------------------------
# 4. 更新 Info.plist 里的BundleId
#  设置 "Set :KEY Value" "目标文件路径.plist"
/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $PRODUCT_BUNDLE_IDENTIFIER" "$TARGET_APP_PATH/Info.plist"

# 5.给可执行文件上权限
#添加ipa二进制的执行权限,否则xcode会告知无法运行
#这个操作是要找到第三方app包里的可执行文件名称,因为info.plist的 'Executable file' key对应的是可执行文件的名称
#我们grep 一下,然后取最后一行, 然后以cut 命令分割,取出想要的关键信息。存到APP_BINARY变量里
APP_BINARY=`plutil -convert xml1 -o - $TARGET_APP_PATH/Info.plist|grep -A1 Exec|tail -n1|cut -f2 -d\>|cut -f1 -d\<`

#这个为二进制文件加上可执行权限 +X
chmod +x "$TARGET_APP_PATH/$APP_BINARY"

# -------------------------------------
# 6. 重签第三方app Frameworks下已存在的动态库
TARGET_APP_FRAMEWORKS_PATH="$TARGET_APP_PATH/Frameworks"
if [ -d "$TARGET_APP_FRAMEWORKS_PATH" ];
then
#遍历出所有动态库的路径
for FRAMEWORK in "$TARGET_APP_FRAMEWORKS_PATH/"*
do
echo "FRAMEWORK : $FRAMEWORK"
#签名
/usr/bin/codesign --force --sign "$EXPANDED_CODE_SIGN_IDENTITY" "$FRAMEWORK"
done
fi

运行后完成对其重签名.

四、总结

对应用的砸壳和重签名仅仅是逆向的入门,后面我们会继续探讨关于逆向的其他技术。再次声明:研究逆向的目的是为了更好的保护我们的应用,而不是用在非法用途上。

参考文献:

blog.cnbang.net/tech/3386/ www.i4.cn/news_3.html www.i4.cn/news_detail…