iOS应用签名

一、签名原理

签名就设计到了加密,加密有对称、非对称、hash等,iOS这里主要使用了hash+非对称,两者结合使用来对应用进行加密的。

HASH加密

将任意大小的数据通过散列算法变换成固定长度的字符,通常为32位的固定字符,又称hash值。

特点:算法公开、不可逆、结果定长,常见的MD5加密。

非对称加密

公钥加密,私钥解密,加密过程复杂,需要进行大量计算,因此效率很低。明文->公钥->密文    密文->私钥->明文。支付宝,微信等支付过程需要的签名也是非对称加密过程。数字签名流程如下:

sign.png

iOS签名

为避免垃圾应用的安装,破坏应用生态,苹果采用更高级的加密,对应用进行双层代码签名。

1、首先在Mac端生成一对公私钥(Xcode自动生成)为公钥M私钥M

2、苹果有一对固定的公私钥,私钥在苹果后台,公钥在每个iOS系统中,称公钥A,私钥A

3、把公钥M和开发者信息,上传到苹果后台(CSR文件),用苹果后台里的私钥A去签名公钥M,得到一个含有公钥M签名的数据包,该包即为证书

4、iPhone中的公钥A可解密用苹果服务器私钥A加密的公钥M,通过公钥M可以对加密的APP进行解密。

描述文件:包含证书、APPID、设备id、打包后用来证明我们的程序的安全性和合法性。如常用的测试包,需要添加测试人员的udid,苹果需要对其验证后,相应的设备才能安装。签名原理如图:

appsign.png

二、手动签名

手动签名是通过自定义权限文件,通过权限文件和签名工具对破壳应用进行重签名,让三方应用在我们的xcode上运行。

获取破壳ipa

  1. 通过越狱手机获取破壳应用,参考《iOS砸壳》;
  2. 通过爱思助手获取越狱应用。

将砸壳应用放到桌面或其他方便操作的地方,当前使用的是微信应用:

app.png

签名步骤

1、创建一个WeChat工程,本测试中使用的是xcode自动生成的证书和描述文件,也可以使用手动创建的证书和描述文件,都是从苹果服务器申请获取的,所以能对APP进行手动签名。接入真机并编译,获取.app中的描述文件。如下图:

create.png

2、右键.app显示包内容复制embedded.mobileprovision到桌面备用,使用命令查看描述文件中的权限配置(Entitlements下的为权限配置):

1
security cms -D -i embedded.mobileprovision

权限文件部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
<key>Entitlements</key>
<dict>
<key>application-identifier</key>
<string>48HJPW679W.com.yahibo.WeChat</string>
<key>keychain-access-groups</key>
<array>
<string>48HJPW679W.*</string>
</array>
<key>get-task-allow</key>
<true/>
<key>com.apple.developer.team-identifier</key>
<string>48HJPW679W</string>
</dict>

3、创建一个plist权限文件,并将embedded.mobileprovision中的权限文件复制到plist中,用来对砸壳应用重签名。

Entitlements.png

4、将权限文件移动到桌面或其他方便操作的地方,并将embedded.mobileprovision文件加入到砸壳应用包中(.app右键显示包内容)。如下图:

mobileprovision.png

5、修改砸壳应用中包中info.plist的唯一标识:

info.png

6、给可执行文件执行权限

1
chmod +x WeChat

7、进入到桌面砸壳应用,因为对Watch中的app无法签名,所以直接删除,Plugins中插件无法被验证不能使用,所以需要删除。
Watch文件(删除):

Watch.png

PlugIns文件(删除):

PlugIns.png

8、进入Frameworks.app中的文件)文件中对所有库重签名。
1)查看当前安装的证书

1
security find-identity -v -p codesigning

2)使用可用证书对每一个库签名

1
codesign -fs "iPhone Developer: yahibo@qq.com (64R6BCB698)" ProtobufLite.framework

注意:签名证书要与工程中使用的证书保持一致

签名使用的证书:

sign1.png

Frameworks下的所有库重签名:

sign2.png

9、签名APP,返回桌面,用已经创建好的权限文件对.app重新签名

1
codesign -fs "iPhone Developer: yahibo@qq.com (64R6BCB698)" --no-strict --entitlements=Entitlements.plist Payload/WeChat.app

在创建工程时自动生成的描述文件中已经包含了测试设备id,签名后app即可安装到测试设备上;如果想添加多台设备,可以自己创建证书,创建描述文件时添加需要安装的设备,重签名使用该证书即可。

安装:
1、签名完之后可以放在xcode中替换原有的.app,直接运行;如下图:

xcode.png

2、打包APP,通过Xcode->window devices安装ipa包。打包命令如下:

1
zip -ry WeChat.ipa Payload

安装ipa

install.png

总结

应用签名步骤如下:

  1. 爱思助手越狱手机中获取解密ipa包
  2. 创建新应用,并安装至手机,获取.app包中的描述文件;
  3. 从描述文件中获取权限配置,并创建en.plist权限文件;
  4. 进入解密ipa包中的.app文件,移除Plugin插件及Watch文件;
  5. 使用上面创建工程的证书,对解密的.app/Frameworks文件下的库进行重签名;
  6. 将第2步获取的描述文件放入解密的.app包下;
  7. 使用第3步en.plist权限文件对整个.app包进行重签名;
  8. 向手机安装.app包或者打包为.ipa包

注意

在操作过程中发现以下问题:
1、通过越狱手机获取到的破壳应用,由于手机CPU架构不同(测试用iPhone5),会导致安装失败;
2、创建的工程获取描述文件时注意,要使用一手描述文件(重新编译描述文件会发生变化,签名APP验证不通过)。

三、脚本签名

熟悉了签名原理和签名流程,那么就可以把手动签名过程一步步改写为脚本,通过脚本来对三方应用进行签名。xcode调试中会对.ipa做权限管理,因此脚本中可以省略权限签名。

获取破壳ipa

  1. 通过越狱手机获取破壳应用,参考《iOS砸壳》;
  2. 通过爱思助手获取越狱应用。

新建xcode工程,在工程文件中新建两个文件夹toolapp

  1. tool文件存放签名脚本;
  2. app文件存放要启动的.ipa破壳应用。

签名脚本:

shell.png

脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#定义目录路径 ${SRCROOT}为当前工程的根目录
#定义临时目录变量,存放解.ipa后产生的临时文件
TEMP_PATH="${SRCROOT}/temp"
#tool路径
TOOL_PATH="${SRCROOT}/tool"
#定义APP资源目录变量,存放要重签名的APP
APP_PATH="${SRCROOT}/app"
#定义ipa包路径
IPA_PATH="${APP_PATH}/*.ipa"

#移除临时文件,并重新创建文件夹
rm -rf "${TEMP_PATH}"
mkdir -p "${TEMP_PATH}"

###########1、解压ipa到指定的文件下###########
unzip -o "$IPA_PATH" -d "$TEMP_PATH"
#获取临时app路径
TEMP_APP_PATH=$(set -- "$TEMP_PATH/Payload/"*.app;echo "$1")
echo ".app文件路径:$TEMP_APP_PATH"

###########2、修改应用info.plist的BundleId###########
# 设置 "Set :KEY Value" "Info.plist"
/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $PRODUCT_BUNDLE_IDENTIFIER" "$TEMP_APP_PATH/Info.plist"

###########3、删除扩展应用及插件###########
echo "Removing PlugIns and Watch"
rm -rf "$TEMP_APP_PATH/PlugIns"
rm -rf "$TEMP_APP_PATH/Watch"

###########4、给可执行文件执行权限###########
#获取可执行文件路径
APP_BINARY=`plutil -convert xml1 -o - $TEMP_APP_PATH/Info.plist|grep -A1 Exec|tail -n1|cut -f2 -d\>|cut -f1 -d\<`
#给可执行文件权限
chmod +x "$TEMP_APP_PATH/$APP_BINARY"

###########5、重新签名Frameworks下的所有动态库###########
#获取动态库路径
APP_FRAMEWORKS_PATH="$TEMP_APP_PATH/Frameworks"
#判断文件是否存在
if [ -d "$APP_FRAMEWORKS_PATH" ]
then
#遍历所有动态库
for FRAMEWORK in "$APP_FRAMEWORKS_PATH/"*
do
echo "framework: $FRAMEWORK"
#对动态库签名 $EXPANDED_CODE_SIGN_IDENTITY xcode上的证书
/usr/bin/codesign -fs "$EXPANDED_CODE_SIGN_IDENTITY" "$FRAMEWORK"
done
fi

###########6、将修改后的.app移动到xcode对应的Products下###########
#BUILT_PRODUCTS_DIR xcode生成的.app包路径
#TARGET_NAME 应用名称
TARGET_APP_PATH="$BUILT_PRODUCTS_DIR/$TARGET_NAME.app"
echo "目标代码路径:$TARGET_APP_PATH"
rm -rf "$TARGET_APP_PATH"
mkdir -p "$TARGET_APP_PATH"
cp -rf "$TEMP_APP_PATH/" "$TARGET_APP_PATH/"
  • Run Script中添加脚本路径
  • 注意:在工程中需要给SignApp.sh脚本可执行权限:chmod +x SignApp.sh

shell.png

需要安装的应用:

ipa.png

以上步骤结束后,运行工程即可,编译完后会执行脚本,脚本来帮助我们重签名。

运行安装如下:

iPhone.png

Xcode调试:

dy.png

通过这种方法就更方便了,新建工程,放入签名脚本和三方破壳ipa,直接运行即可,通过xcode可进行应用调试,查看页面布局。