iOS逆向学习-007应用重新签名及原理

2,816 阅读7分钟

应用签名原理

苹果采用了双层签名的原理,这里讲个大概,还有很多细节

image.png

  1. 苹果服务器会生成一对秘钥,私钥自己留着,公钥拷贝给所有的远程设备
  2. 本地会生成一对秘钥,私钥自己留着,公钥生成CSR文件去苹果开发者网站请求证书,证书的本质就是苹果服务器拿自己的私钥,给你的公钥签名
  3. 拿到证书后,可以继续去苹果开发者网站添加描述文件,描述文件中包含了APPID(Bundle ID)、可以安装APP的设备序列号,以及刚才申请到的证书,申请日期、到期日期等。
  4. 把描述文件放进你的APP包内,然后用本地私钥给APP签名
  5. 签完名给手机设备安装,设备开始验证APP的有效性,首先验证描述文件的有效性,描述文件和证书一样,也是签过名的,所以拿手机中的公钥验证有效性。当描述文件是有效的,同理认证证书也是有效的,然后拿证书中的公钥验证APP本身也是有效的,这样就能知道APP的确是开发者发布的。最后在判断下设备序列号,到期日期等,让APP能否在手机上打开,如果你的APP闪退了,通常是你的描述文件的某块失效了。

应用重新签名

查看签名信息

随便找个应用的IPA包,自己砸壳或者从三方获取(比如爱思助手等)

把IPA包的后缀改成zip后,可以解压出来,得到一个Payload的文件夹,里面可以看到应用包,如图:

image.png

然后在终端到应用包所在路径,输入如下命令:

codesign -vv -d 应用名.app

我们就可以看到APP的签名信息:

image.png

列出钥匙串里可签名的证书

在命令行输入如下命令,可以查看钥匙串里可签名的证书:

security find-identity -v -p codesigning

image.png

查看可执行文件的信息及是否加密

找到刚才应用包,右键点开包内容,找到可执行文件,名字应该和应用宝名字一样的:

image.png

终端进入该目录输入如下命令:

otool -l 迷你军团
// 如果觉得太长,可以输出到文件
otool -l 迷你军团 > content.txt

我们看到文件里有很多Load commandSection等内容,这个后面会讲

我们找下我们关心的是否加密:

otool -l 迷你军团 | grep crypt

image.png

cryptid为0,说明没有加密,否则就是加密的。我们所说的砸壳就是指这个,一般三方平台得到的IPA包都是砸完壳的,也就是解密的,如果是在App Store上下下来,或者简单的从越狱手机里拷贝出来,那么都是没有砸壳的,也就是加密的,关于如何砸壳后面文章会讲。

APP手动重签

应用包显示包内容

删除Plugins&Watch

删除Plugins&Watch(有些应用本来就没有),除非你就是要研究该应用的Extension或者手表应用,否则没用,而且签名带有Plugins&Watch的证书也要相应的权限,比较繁琐,删了并不影响我们运行应用在手机上

对Frameworks文件夹里的所有的动态库进行重签名

我们先来看下Framework的签名信息:

image.png

我们用如下命令替换证书,实现重签名:

codesign -fs "证书名" SVProgressHUD.framework

我们再次看签名信息,发现签名已经被替换了:

image.png

我们按照这个流程,依次把所有的动态库全部签名

给可执行文件赋予可执行权限

一般来说,可执行文件都是有可执行权限的,具体可以命令看:

ls -l | grep 迷你军团

image.png

我们看到user组少了一个可执行权限x,添加可执行权限:

chmod 755 迷你军团

加完后再看下:

image.png

这样我们就加完了可执行权限了,如果不加,后面签名会报错

获取描述文件

获取描述文件(mobileprovision后缀的文件),这个文件可以从苹果开发者网站下载,但必须是你刚重签名Framework证书的账号,描述文件和证书必须要保持一致。

还有一个简单的方法获取描述文件,利用Xcode帮我们获取,新建一个空项目在手机上跑起来,然后在Product文件夹中找到APP应用包

image.png

我们在对应的路径找到该文件,然后右键显示包内容,就能看到描述文件了:

image.png

拿到描述文件后,将文件拷贝到包内容就行了

info.plist文件中替换BundleID

我们找到描述文件中的APPID,也就是Bundle ID

image.png

然后把info.plist文件中的Bundle identifier改成与描述文件一致就行,不过我的描述文件是通配符的,所以不用改

image.png

info.plist文件中去掉Supported Devices

在info.plist文件中找下有没有UISupportedDevices,一般在文件末尾,如果有,把整项去掉。这个值是你应用包安装所支持的设备,如果你是在低版本的手机上砸壳,那么支持的手机型号会比较少。如果不去掉此项,那么最后安装的时候会显示无法安装。

获取配置权限文件

在最后签名前,我们还需要一个配置权限的文件,有两种办法获取:

  1. 在你刚才空项目运行真机成功的记录里,点开签名的详细代码

image.png

image.png

我们看到跟在--entitlements后面的地址文件,就是我们想要的权限文件,虽然格式是xcent,我们并不熟悉,但是拖到文本编辑器一看:

image.png

本质上就是一个plist文件

  1. 另外一种获取权限文件,我们自己建一个plist文件,文件一般叫entitlements.plist,找到刚才的描述文件,输入如下命令:
security cms -D -i embedded.mobileprovision

会出现一大堆信息,翻找下Entitlements段的内容:

image.png

我们这段复制到entitlements.plist中就行了。

个人更推荐第二种方式,肯定不会错,如果是第一种方式,自己看下内容有没有需要调整的

重签名及安装

拿到权限文件entitlements.plist后,把它拷贝到应用包的同级目录,执行如下代码

codesign -fs 证书名 --no-strict --entitlements=entitlements.plist 迷你军团.app

image.png

上面给出了两种写证书的方式,都可以,最后我们验证证书,已经改成我们自己的了,最后打开Xcode中的Devices and Simulators,点击加号安装:

image.png

不出意外,你应该已经安装上了。(如果有同bundle id,证书却不一样的,可以先删除手机上的老版本)

利用Xcode重签

  1. 新建一个和应用包名字一样的项目
  2. 把应用包的bundleid改成和项目一样
  3. 删除插件及watch内容等
  4. 把应用包的framework重新签名
  5. 把空项目运行起来
  6. 把项目包替换成应用包重新运行

总体来说,比手动更方便一点,在接下来就是写脚本了:

# ${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

先执行一遍空项目到手机,在加入脚本运行就行了。

其他

IPA解压和生成的命令:

# 解压
unzip -oqq "$TARGET_IPA_PATH" -d "$TEMP_PATH"
# 压缩成IPA
zip -ry WeChat.ipa Payload