代码签名
代码签名 是对可执行文件或脚本进行数字签名。用来确认软件在签名后未被修改或损坏的措施。和数字签名原理一样,只不过签名的数据是代码而已。
苹果的需求
- 安装包不需要上传到App Store,可以直接安装到手机上
- 苹果味了保证系统的安全性,又必须对安装的APP有绝对的控制权
- 经过苹果允许才可以安装
-
不能被滥用导致非开发APP也能被安装
为了实现这些需求,iOS签名的复杂度也开始增加,苹果采取的措施是双层签名
image.png
双层代码签名
- 在Mac系统中生成非对称加密算法的一对公钥\私钥(Xcode代办了),这里成为公钥M,私钥M M=Mac
- 苹果自己有固定的一对公私钥,跟之前AppStore原理一样,私钥在苹果后台,公钥在每个iOS系统当中,这里成为公钥A,私钥A,A=Apple
-把公钥与及一些开发者信息传到苹果后台(这就是CSR文件),用苹果后台里的私钥A去签名公钥M。得到一份数据包含了公钥M与及其签名,把这份数据称为证书。
描述文件
描述文件(Provisioning profile)一般包括三样东西:证书,App ID,设备,当我们在真机运行或者打包一个项目的时候,证书用来证明我们程序的合法性。
苹果为了解决应用滥用的问题,所以苹果又加了两个限制
- 第一限制在苹果后台注册过的设备才可以安装
- 第二限制只能针对某一个具体的APP
并且苹果还想控制App里面的iCloud、PUSH、后台、调试器附加这些权限,所以苹果把这些权限开关同意成为Entitlements(授权文件),并把这个文件放在一个叫做Provisioning Profile描述文件中,描述文件是在AppleDevelop网站创建的(在Xcode中填上AppID会自动创建),Xcode运行时会打包进入app内,所以我们使用CSR申请证书的时候,我们还需要申请一个东西就是描述文件。在开发时,编译完一个APP后,用本地的私钥M对这个App进行签名,同时把苹果服务器得到的Provisioning Profile文件打包进入App里,文件名为embeded。mobileprovision,把App安装到手机,最后系统进行验证。
应用重签名
在原有的基础之上破坏原签名,之后使用合法的证书再进行重签
codesign
Xcode提供了签名工具:codesign,我们可以通过几个命令就可以完成重签名
//列出钥匙串里可签名的证书
$security find -identity -v -p codesigning
//强制替换签名
$Codesign -fs "证书串" 文件名 强制替换签名
//给文件添加权限
$Chmod +x 可执行文件 给文件添加权限
//查看描述文件
$security cms -D -i ../embeded.mobileprovision 查看描述文件
// APP包
codesign -fs "证书串" --no-strict --entitlements=权限文件.plist APP 包
//将输入文件压缩为输出文件
Zip -ry 输出文件 输入文件
重签名步骤
- 1.删除插件和带有插件的.app 包(比如Watch)
- 2.对Frameworks里面的库进行重签名(动态库)
- 3.给可执行文件+x(可执行)权限
-4 添加描述文件(新建工程,真机编译得到)
-5.替换BundleID
-6.通过授权文件(Entilements)重签名.app包
SHELL脚本
部分linux指令解释
$source FileName:在当前shell环境中读取并执行FileName中的命令
特点:命令可以强行让一个脚本去立即影响当前的环境(一般用于加载配置文件)。命令会强制执行脚本中的全部命令,而忽略文件的全向
$base FileName、$zsh FileName:重新建立一个子shell,在子shell中执行脚本里面的句子
$./FileName:读取并执行文件中的命令,但前提是脚本必须有可执行权限,也就是x
用户组&文件权限
Unix和Linux都是多用户,多任务的系统,所以这样的系统里面就拥有了用户,组的概念。那么同样文件的权限也就有相应的所属用户和所属组了。
➜ ~ ls -l
total 0
drwxr-xr-x 7 apple staff 224 Apr 16 09:50 DarkModeAdjust
drwx------@ 13 apple staff 416 Apr 18 09:42 Desktop
drwx------@ 23 apple staff 736 Apr 18 17:32 Documents
drwx------@ 28 apple staff 896 Apr 18 17:07 Downloads
drwxr-xr-x 24 apple staff 768 Apr 13 11:59 work
- 第一列:[ 权限 ]
d:文件类型,代表目录(- 代表文件)
r:read 读,w:write 写,x:excute 执行
这三个权限的位置不会变,依次次rwx,出现-在对应位置,代表没有这个权限
一个文件的完整权限,总共分为三组
- 第一组:文件所有者的权限
- 第二组:这一组其他用户的权限
- 第三组:非本组用户的权限
- 第二列:[ 连接 ]
- 第三列:[ 所属组 ]
- 第四列:[ 文件大小 ]
- 第五列:[ 最后修改日期 ]
- 第六列:[ 文件名称 ]
改变权限:chmod指令
文件权限的改变使用chmod命令,设置的方法有两种:数字类型改变和符号类型改变,由于文件权限分为三种身份:[user][group][other] 三个权限:[read][write][execute]
- 数字类型:
各个权限数字对照:r:4 w:2 x:1,举个例子说明一下,如果一个文件权限为[-rwxr-xr-x],那么久分别是对应着User:4+2+1=7,Group:4+0+1=5,Other:4+0+1=5;命令:chmod 755 文件名
权限操作符 | 对应解释 |
---|---|
--- | 0 |
--x | 1 |
-w- | 2 |
-wx | 3 |
r-- | 4 |
r-x | 5 |
rw- | 6 |
rwx | 7 |
符号类型
chmod [u、g、o、a] [+(加入)、-(除去)、=(设置) [r、w、x] 文件名称
重签名的demo
1.Xcode 结合脚本重签
Snip20200424_71.png
目录架构大致如上
- APP目录 负责放置需要重签名的ipa
- Temp 临时目录,负责放置解压的文档
配置好bundleID和相关描述文件,让Xcode首先能真机编译,然后再在Xcode Build Phases添加一个Run Script脚本,内容大致如下
# ${SRCROOT} 它是工程文件所在的目录
TEMP_PATH="${SRCROOT}/Temp"
ASSETS_PATH="${SRCROOT}/APP"
TARGET_IPA_PATH="${ASSETS_PATH}/*.ipa"
#清空Temp文件夹
rm -rf "$TEMP_PATH"
mkdir "$TEMP_PATH"
#1.1将IPA解压到Temp下
unzip -oqq "$TARGET_IPA_PATH" -d "$TEMP_PATH"
#1.2拿到解压临时的APP路径
TEMP_APP_PATH=$(set -- "$TEMP_PATH/Payload/"*.app;echo "$1")
echo "TEMP:🍺$TEMP_APP_PATH"
#2拷贝APP
#2.1拿到当前工程下的APP路径
TARGET_APP_PATH="$BUILT_PRODUCTS_DIR/$TARGET_NAME.app"
echo "TARGET_APP_PATH🍺:$TARGET_APP_PATH"
#2.2拷贝三方APP到我们的工程下
cp -rf "$TEMP_APP_PATH/" "$TARGET_APP_PATH"
#3干掉多余的部分
rm -rf "$TARGET_APP_PATH/PlugIns"
rm -rf "$TARGET_APP_PATH/Watch"
#4修改info.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\<`
echo "🍺: $APP_BINARY"
chmod +x "$TARGET_APP_PATH/$APP_BINARY"
#6.重签名三方FrameWorks
TARGET_APP_FRAMEWORKS_PATH="$TARGET_APP_PATH/Frameworks"
for FRAMEWORK in "$TARGET_APP_FRAMEWORKS_PATH/"*
do
#echo "🍺FRAMEWORK:$FRAMEWORK"
/usr/bin/codesign --force --sign "$EXPANDED_CODE_SIGN_IDENTITY" "$FRAMEWORK"
done
Snip20200424_72.png
然后运行Xcode,会发现编译完毕,需要重签的app已经可以运行到自己的手机上面来了(我这里运行的是微信)
Snip20200424_73.png
使用纯脚本重签
param_mobileprovision="/Users/forest/Documents/develop/forest.mobileprovision"
param_cerName="iPhone Developer: Polly Wilbur (R2N9CWGB83)"
unzip -qo "$param_ipa" -d extracted
APPLICATION=$(ls extracted/Payload/)
cp "$param_mobileprovision" "extracted/Payload/$APPLICATION/embedded.mobileprovision"
echo "Resigning with certificate: $param_cerName" >&2
find -d extracted \( -name "*.app" -o -name "*.appex" -o -name "*.framework" -o -name "*.dylib" \) > directories.txt
security cms -D -i "extracted/Payload/$APPLICATION/embedded.mobileprovision" > t_entitlements_full.plist
/usr/libexec/PlistBuddy -x -c 'Print:Entitlements' t_entitlements_full.plist > t_entitlements.plist
while IFS='' read -r line || [[ -n "$line" ]]; do
/usr/bin/codesign --continue -f -s "$param_cerName" --entitlements "t_entitlements.plist" "$line"
echo "line: ${line}"
done < directories.txt
/usr/bin/codesign --continue -f -s "$param_cerName" --entitlements "t_entitlements.plist" "extracted/Payload/$APPLICATION"
echo "Creating the Signed IPA"
cd extracted
zip -qry ../extracted.ipa *
cd ..
ls_date=`date +%Y%m%d-%H%M%S`
# ls_date=`date +%Y%m%d`
# mv extracted.ipa "/Users/forest/Desktop/ReasignIPAProduct/${ls_date}_Signed.ipa"
mv extracted.ipa "/Users/forest/Desktop/ReasignIPAProduct/${ls_date}_Signed.ipa"
echo ${ls_date}_Signed.ipa
rm -rf "extracted"
rm directories.txt
rm t_entitlements.plist
rm d_full.plist
这里需要事先提供描述文件,和证书,确认提供完毕之后,可以
$sh sign.sh xxx.ipa
执行完之后会在指定的路径生成一个重签后的ipa,这个ipa可以直接通过itools pro直接安装到手机上面去
网友评论