iOS应用重签名

代码重签名

签名机制

iOS签名需要用到codesign这个命令,了解这个命令的用法可以增加我们对签名机制的了解

最简单的情况是用可签名的证书对文件进行签名

codesign -s "iPhone Distribution: Xiaoxuan Chen (CXJ8TF54LW)" mix.sh 

使用证书签名可以确认身份和代码的完整性,但是应用运行还会受到其他的一些限制,在签名的时候可以指定应用的权限。

codesign -fs "iPhone Distribution: Qinda Zhuang (287VV6UT6R)" --entitlements=/Users/wangxuefeng/Desktop/CITest/entitlements.plist Live.app

在entitlements.plist中存放了应用的权限。

我们没有直接创建entitlements.plist,但是当我们修改应用的权限的时候,比如开启推送,entitlements会随之更改。entitlements信息保存在provisioning profiles中,

  1. codesign 通过codesign可以对OS X 和 iOS系统中任何可执行二进制文件设置签名,设置签名需要证书和密钥,保证文件不被篡改
  2. entitlements entitlements授权机制决定了哪些系统资源在什么情况下允许被一个应用使用,比如可以使用推送、可以调试,针对沙盒配置
  3. provisioning profiles 在整个代码签名和沙盒机制中有一个组成部分将签名,授权和沙盒联系了起来,那就是配置文件。

重签名

  1. 准备新的证书和provisioning profiles

签名会用到证书和密钥,授权机制会用到entitlements.plist,和证书相匹配的provisioning profiles当然也少不了。
entitlements.plist可以从provisioning profiles中导出,所以准备一个可签名的证书和相应的provisioning profiles就可以。

  1. 删除旧的签名

iOS 应用的签名是针对.app进行的,因此签名相关的文件都存放在.app里面。

移除已有文件签名:应用程序的签名都放在一个文件里面 _CodeSignatue/CodeResources,由于这个文件在签名过程中会重新生成,因此不移除也是可以的。
移除provisioning profiles: provisioning profiles会被copy到应用中,名称为embedded.mobileprovision,删除这个文件

CFBundleIdentifier

# 修改 Plist,Plist路径必须为绝对路径
defaults write /Users/wangxuefeng/Desktop/ci/Live.app/info.plist "CFBundleName" "小爱Top"
defaults write /Users/wangxuefeng/Desktop/ci/Live.app/info.plist "CFBundleDisplayName" "小爱Top"
defaults write /Users/wangxuefeng/Desktop/ci/Live.app/info.plist "CFBundleIdentifier" "com.fungo.loveshowtop"

# 重签名 iPhone Distribution: Qinda Zhuang (287VV6UT6R) 在钥匙串中对应的证书只有一个,否则不能这么写
codesign -f -s "iPhone Distribution: Qinda Zhuang (287VV6UT6R)" --entitlements entitlements.plist Live.app

#验证签名
codesign --verify Live.app

#获取签名详情
codesign -vv -d Live.app

#获取主机上所有可用于签名的证书
security find-identity -v -p codesigning

#导出entitlements.plist
security cms -D -i Live.app/embedded.mobileprovision > t_entitlements_full.plist 
/usr/libexec/PlistBuddy -x -c 'Print:Entitlements' t_entitlements_full.plist > entitlements.plist

resign.sh

workspace=~/Desktop/CITest

payloadDirectory=${workspace}/Payload
entitlementsPlistPath=${workspace}/entitlements.plist

rm -rf payloadDirectory
mkdir payloadDirectory

cp -r $1 Payload

provisioningFile=$3

appName=Live.app

appBundlePath=${payloadDirectory}/${appName}
appBundleInfoPlist=${appBundlePath}/Info.plist
appBundleProvisioningFilePath=${appBundlePath}/embedded.mobileprovision

#删除info.plist中的CFBundleResourceSpecification这一项
defaults delete $appBundleInfoPlist "CFBundleResourceSpecification"

#删除原有的embedded.mobileprovision
rm $appBundleProvisioningFilePath

#将新的embedded.mobileprovision复制到app中
cp -R "${3}" $appBundleProvisioningFilePath

#解析新的embedded.mobileprovision
security cms -D -i $appBundleProvisioningFilePath > ${workspace}/t_entitlements_full.plist 
/usr/libexec/PlistBuddy -x -c 'Print:Entitlements' ${workspace}/t_entitlements_full.plist > ${entitlementsPlistPath}

#解析appID
applicationIdentifier=`defaults read ${entitlementsPlistPath} "application-identifier"`
newBundleId=${applicationIdentifier#*.}

#确保文件可执行
bundleExecutable=`defaults read $appBundleInfoPlist "CFBundleExecutable"`
chmod 755 ${appBundlePath}/${bundleExecutable}

#改变bundleid,以.app .appex结尾的文件中的info.plist都需要修改
oldBundleId=`defaults read ${appBundleInfoPlist} "CFBundleIdentifier"`

# if $newBundleId != $oldBundleId then
    echo changing Bundle id $appBundleInfoPlist $newBundleId
    defaults write $appBundleInfoPlist "CFBundleIdentifier" $newBundleId
# fi

#签名
for file in `ls $appBundlePath/Frameworks` 
do
     codesign -vvv -fs "$2" --no-strict --entitlements=${entitlementsPlistPath} $appBundlePath/Frameworks/$file
done

codesign -vvv -fs "$2" --no-strict --entitlements=${entitlementsPlistPath} $appBundlePath

#测试签名结果
codesign -v $appBundlePath

调用

sh resign.sh /Users/wangxuefeng/Desktop/ci/Release-iphones/Live.app "iPhone Distribution: Qinda Zhuang (287VV6UT6R)" /Users/wangxuefeng/Library/MobileDevice/Provisioning\ Profiles/1fb19f15-021a-40ac-9f4f-d33fe1a1d138.mobileprovision

推荐阅读更多精彩内容