iOS逆向(3)-APP重签名

转载:原文地址
本文将从原理分析,到利用原理的漏洞,再到具体过程,最后利用脚本全自动实现。
作为一名iOS开发者肯定知道iOS开发证书,那么证书具体是什么呢?为什么到我们本地的不是证书本身,而是一个称之为描述文件的东西。而这「描述文件」又具体是什么呢?
在知道这「描述文件」后,我们是不是可以通过将「描述文件」替换为我们自己的「描述文件」进行一些有意思的事情呢?比如这篇文章的主题,对一个APP进行重签名,让他在我们的XCode中运行起来,运用我们强大的LLDB进行调试,分析其UI和部分逻辑。当然作为一个正直的开发者,我们在这片文章肯定不会对她进「代码注入」这样让人不(兴)齿(奋)的事情的(下一篇就会 O(∩_∩)O哈哈~)。
片头先给福利:点击下载Demo:AppReSign,使用方法详见demo的Readme
接下来我们会从以下几点来玩一玩「APP重签名」
  • 分析Apple对App加密的需求
  • 什么是双层签名
  • 手动对APP进行重签名
  • 使用Shell脚本进行重签
1、分析Apple对App加密的需求 首先明确一点,对App加密肯定是用要非对称加密而不是对称加密!这我默认大家都懂了,应该不用解释。
Step 1 安装App到手机的渠道分析 如果所有的APP都是从App Store下载的那么,这就简单了,只需要对APP进行一层RSA加密就可以了,App Store持有私钥,我们iPhone持有公钥。那么问题就解决了。但事实上肯定不是这样,我们已知的渠道除了App Store就包括XCode打包,ADHOC证书分发,企业证书分发等等。为了解决这个问题,我们就得先了解Apple的具体需求是什么。
Step 2 分析需求
  • App Store下载
  • XCode直接安装
  • 限制ADHoc打包的APP安装设备
  • ...等等
2、什么是双层签名 【iOS逆向(3)-APP重签名】针对以上三种(包括但不只)场景,苹果给出「双层签名」的机制。
什么是「双层签名」,先上一张PPT。
iOS逆向(3)-APP重签名
文章图片
双层签名流程图 看不懂?没关系,下面会一步步,详细的接受双层签名的始末。
1、向服务器申请证书
  • 什么是CSR文件
    申请过开发者证书的都知道,要申请证书,都有「Mac本地通过CSR文件向服务器」这样的一步。那么这一步到底做了写什么呢?
    先看看什么是CSR
CSR是Certificate Signing Request的英文缩写,即证书请求文件,也就是证书申请者在申请数字证书时由CSP(加密服务提供者)在生成私钥的同时也生成证书请求文件,证书申请者只要把CSR文件提交给证书颁发机构后,证书颁发机构使用其根证书私钥签名就生成了证书公钥文件,也就是颁发给用户的证书。
通俗一点,就是Mac本地有一对公钥(公钥M)和私钥(私钥M)(什么是公钥私钥?),在Mac上对公钥M进行了一层包装,这包装后的新东西就是CSR。
  • 服务器通过CSR返回证书
    本地有了CSR文件之后,将CSR上传到Apple的服务器。
    Apple服务器其实也是有一对公钥(公钥A)和私钥(私钥A),在收到Mac上传过来的的CSR文件之后,取出其中的公钥M,用Apple服务器的私钥A对公钥M进行一次数字签名(什么是数字签名?)得到开发证书,然后将开发证书附入描述文件(描述文件还有哪些东西下文会有讲到),最后将描述文件传回给我们的Mac电脑。
2、描述文件
配置描述文件是 XML 文件,包含以下内容:设备的安全策略和限制、VPN 配置信息、无线局域网设置、电子邮件帐户和日历帐户以及可允许 iPhone、iPod touch 和 iPad 配合您的企业系统使用的鉴定凭证。配置描述文件能快速地将设置和授权信息载入到设备上。有些 VPN 和无线局域网设置只能使用配置描述文件来设定,而且如果您使用的不是 Microsoft Exchange,则将需要使用配置描述文件来设定设备密码策略。
描述文件包括的东西,如:
  • 开发证书
  • APP的Bundle Id
  • 证书所信任的Device Id
  • 还有一些权限文件(如:Apple Pay,通知,VPN,iCloud)
3、Mac打包APP 在Mac本地有了描述文件之后,就可以对APP进行打包了,打包这个过程除了对APP的压缩之外,更重要的其实是指对APP的加密。
之前本地把公钥M发送给Apple服务器,本地剩下的私钥M就是用来加密APP的,得到一个APP的签名文件,再将上一步得到的描述文件,以及MachO文件一起打包压缩,最终就得到了我们的ipa包了。
所以ipa其实包含以下三种东西
  • MachO文件
  • APP的签名文件
  • 描述文件
4、iPhone验证ipa文件 上文提到的私钥A是用来加密了公钥M,与之对应的公钥A其实在我们激活iPhone的同时已经下载好了,一直躺在我们的iPhone里面。
有了公钥M,那么一切就简单了,
  • 公钥A解开ipa中携带的描述文件中的证书得到公钥M
  • 对公钥M进行Hash,对比证书中的Hash
  • 对比通过之后,用公钥M对加密的APP进行解密,得到最终APP。
3、手动对APP进行重签名 (如果不想看具体过程,可以跳到本节末尾,有流程总结) 从上面可以得知,双层签名其实本质就是如下三个步骤:
  • APP的Bundle id的验证
  • 描述文件本身的验证
  • 对APP签名的验证
注:对APP进行重新签名,前提是这个APP已经被砸壳了。
下载已经砸壳成功的APP,以下例子用微信举例:越狱版本微信7.0.2 提取码: 2w87
具体步骤:
Step 1 进入WeChat目录 解压出 Wechat7.0.2越狱 ,进入WeChat目录
// 进入WeChat的目录 cd /Users/dengbin/Desktop/分享/主目录/资料/Wechat7.0.2越狱/Payload

Step 2 查看APP的证书情况
codesign -d -vv「WeChat.app路径」

iOS逆向(3)-APP重签名
文章图片
查看APP证书情况 Step 3 查看验证APP是否被加密 进入APP的包内容可以看到其中有一个WeChat的可执行文件,也就是是MachO文件,就是要查看这个MachO文件时候被加密
iOS逆向(3)-APP重签名
文章图片
WeChat目录 iOS逆向(3)-APP重签名
文章图片
WeChat_MachO
otool -l WeChat | grep cryp

其中cryptid0代表已经砸壳,即解密,为1或者2表示以第1类或者第2类加密方案加密。
有些老铁回复说复制代码运行后会报错,有两种情况:
1、电脑里没有Xcode-select,应该先去装一次,很简单,自行百度。
2、如果还不行,代码不要复制,自己敲一遍,就可以。(为何有些人复制不行就不得而知了)。
Step 4 查看本地证书并记录需要用到的证书
security find-identity -v -p codesigning

iOS逆向(3)-APP重签名
文章图片
本地证书列表 Step 5 删除不可签名的插件(还有Watch中的插件) 由于本地存在一些插件,这些插件是不可被我们重签,并且这个过程我们用不着,所以我们索性就删掉。
其中包括:整个目录PlugIns目录和整个Watch目录(因为Watch.app中也有个PlugIns)
iOS逆向(3)-APP重签名
文章图片
PlugIns iOS逆向(3)-APP重签名
文章图片
Watch Step 6 Framework重签名 这一步就是比较繁琐的了,需要将Frameworks下的所有Framework进行重签名,运用到XCode提供的codesign指令,参数中的证书就是Step 4中的一个。具体使用哪个就看个人了
codesign –fs 「证书串」 「文件名」

iOS逆向(3)-APP重签名
文章图片
Frameworks iOS逆向(3)-APP重签名
文章图片
Frameworks证书重签 Step 7 给MachO添加可执行权限 由于MachO本身就有可执行权限,所以这一步跳过。
Step 8 App重签名
  • 新建一个WeChat同名工程(下文称NewWeChat,原来的微信APP称之为WeChat)
  • Build NewWeChat工程,进入被编译出的WeChat.App目录,找到其中的embedded.mobileprovision文件,将其复制到WeChat.App(越狱微信)中
    iOS逆向(3)-APP重签名
    文章图片
    Build后的WeChat iOS逆向(3)-APP重签名
    文章图片
    embedded.mobileprovision文件 iOS逆向(3)-APP重签名
    文章图片
    复制后的结果
  • 在WeChat.App找到info.plist,并修改其中的BundleId为NewWeChat的BundleId
    iOS逆向(3)-APP重签名
    文章图片
    更改BundleId
  • 查看embedded文件
security cms -D -i 「 embedded文件路径」

找到其中的entitlements字段,并且复制entitlements字段和其中的内容
iOS逆向(3)-APP重签名
文章图片
查看embedded iOS逆向(3)-APP重签名
文章图片
entitlements字段
  • 在NewWeChat中新建entitlements.plist文件,将上一步复制得到的「entitlements字段内容」拷贝入新的entitlements.plist文件,然后将entitlements.plist复制到WeChat.app的同级目录下。
    iOS逆向(3)-APP重签名
    文章图片
    拷贝entitlements iOS逆向(3)-APP重签名
    文章图片
    复制entitlements
  • 对APP重新签名
    进入WeChat目录,对APP使用新的描述文件进行重签
codesign -fs 「证书串」 --no-strict --entitlements=entitlements.plist

iOS逆向(3)-APP重签名
文章图片
对App进行重签
  • 压缩Playload
zip –ry 「输出文件名」 「输入文件名」

iOS逆向(3)-APP重签名
文章图片
压缩Playload Step 9 安装新的ipa 可以通过各种途径安装ipa,如Xcode,PP助手,fir,iTunes等等, 如果手机上有正版的微信,在安装完我们重签名的ipa包后会发现手机上就有两个微信啦!!!
如果想用LLDB调试微信,可以将重签后的WeChat.app替换NewWeChat Build后的WeChat.app,然后直接运行(Run)项目,就会发现我们可以用LLDB了。
Step 10 再次验证新的ipa是否真的重签成功 这一步其实是重复Step 3
codesign -d -vv「WeChat.app路径」

步骤总结:
1、cd WeChat // 进入WeChat的目录 2、codesign -d -vv「WeChat.app路径」 // 查看APP的证书情况 3、otool –l WeChat | grep cryp // 查看APP是否被加密 4、security find-identity -v -p codesigning // 查看本地证书 5、删除不可签名的插件(还有Watch中的插件) 6、codesign –fs 「证书串」 「文件名」 // Framework重签名 7、chmod +x 可执行文件// 给文件添加权限 8、App重签名 ① 新建一个项目并且命名为 WeChat(下文称NewWeChat,原来的微信APP称之为WeChat) -> Build -> 找到APP中的权限文件 embedded.mobileprovision ② 复制embedded.mobileprovision到WeChat.app中 ③ 修改WeChat.app中info.plist的BundleId ④ security cms -D -i 「 embedded文件路径」 //查看WeChat中的embedded文件,复制WeChat中entitlements.plist文件的entitlements字段 ⑤ 在NewWeChat中新建entitlements.plist文件,将上一步复制得到的「entitlements字段和其中的内容」拷贝入新的entitlements.plist文件 ⑥ codesign -fs 「证书串」 --no-strict --entitlements=entitlements.plist //复制新的entitlements到WeChat.app的同级目录,并且对APP重新签名 ⑦ zip –ry 「输出文件名」 「输入文件名」 // 压缩Playload 9、安装ipa 10、再次验证新的ipa是否真的重签成功

  • 注意:有些人会安装失败,或者安装成功会有Crash的问题,这是因为当前描述文件在我们的手机还不受信任,用新工程NewWeChat在手机上跑一遍,然后删除NewWeChat,在尝试安装新的ipa,问题可以解决。
4、使用Shell脚本进行重签 上面所有的步骤其实是固定不变的,而且所有需要操作的文件相对于ipa文件的「相对地址」也是固定的,所以就可以用脚本来代替所有的操作。
以下脚本适用于适用XCode直接调试,点击下载Demo:AppReSign,使用方法详见demo的Readme
附上脚本代码
# ${SRCROOT} 它是工程文件所在的目录 TEMP_PATH="${SRCROOT}/Temp" #资源文件夹,我们提前在工程目录下新建一个APP文件夹,里面放ipa包 ASSETS_PATH="${SRCROOT}/APP" #目标ipa包路径 TARGET_IPA_PATH="${ASSETS_PATH}/*.ipa" #清空Temp文件夹 rm -rf "${SRCROOT}/Temp" mkdir -p "${SRCROOT}/Temp"#---------------------------------------- # 1\. 解压IPA到Temp下 unzip -oqq "$TARGET_IPA_PATH" -d "$TEMP_PATH" # 拿到解压的临时的APP的路径 TEMP_APP_PATH=$(set -- "$TEMP_PATH/Payload/"*.app; echo "$1") # echo "路径是:$TEMP_APP_PATH"#---------------------------------------- # 2\. 将解压出来的.app拷贝进入工程下 # BUILT_PRODUCTS_DIR 工程生成的APP包的路径 # TARGET_NAME target名称 TARGET_APP_PATH="$BUILT_PRODUCTS_DIR/$TARGET_NAME.app" echo "app路径:$TARGET_APP_PATH"rm -rf "$TARGET_APP_PATH" mkdir -p "$TARGET_APP_PATH" cp -rf "$TEMP_APP_PATH/" "$TARGET_APP_PATH"#---------------------------------------- # 3\. 删除extension和WatchAPP.个人证书没法签名Extention rm -rf "$TARGET_APP_PATH/PlugIns" rm -rf "$TARGET_APP_PATH/Watch"#---------------------------------------- # 4\. 更新info.plist文件 CFBundleIdentifier #设置:"Set : KEY Value" "目标文件路径" /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $PRODUCT_BUNDLE_IDENTIFIER" "$TARGET_APP_PATH/Info.plist" #----------------------------------------# 5\. 给MachO文件上执行权限 # 拿到MachO文件的路径 APP_BINARY=`plutil -convert xml1 -o - $TARGET_APP_PATH/Info.plist|grep -A1 Exec|tail -n1|cut -f2 -d\>|cut -f1 -d\<` #上可执行权限 chmod +x "$TARGET_APP_PATH/$APP_BINARY"#---------------------------------------- # 6\. 重签名第三方 FrameWorks TARGET_APP_FRAMEWORKS_PATH="$TARGET_APP_PATH/Frameworks" if [ -d "$TARGET_APP_FRAMEWORKS_PATH" ]; then for FRAMEWORK in "$TARGET_APP_FRAMEWORKS_PATH/"* do# 签名 /usr/bin/codesign --force --sign "$EXPANDED_CODE_SIGN_IDENTITY" "$FRAMEWORK" done fi

这边文章主要讲了关于双层签名的原理,已经利用双层签名的原理对APP(已越狱)进行重签,但其实其中有一点非常非常重要的内容在这片文章知识被一笔带过,那就是LLDB,能够用LLDB调试我们的APP意味着无限的可能。
所以对LLDB运用,也是咱们逆向的必经之路。后续文章也会提到,待更新。
注意!!!
警告!!!
警告!!!
警告!!!
重签后不要用自己的账号登录,有封号的危险!!!
推荐文集
* 抖音效果实现 * BAT—最新iOS面试题总结

    推荐阅读