iOS重签名


苹果IPA包的重签名可以解决跟换一个包名、logo和IP地址后进行重新打包的工作,也避免了因为人为原因修改代码后忘记处理而导致打出的包无法使用的问题。目前市面上有的超级app或者蒲公英上宣传的企业……签名所用到的就是重签名技术。 iOS签名机制 先来看一下数字签名的图 苹果的签名机制如果简化,那也就是数字签名的流程。图的上半部分就是签名的过程,下半部分就是用户安装应用验证的过程。苹果为了控制应用的……包含在列表内; 所有的验证通过后用户才能使用。苹果签名 IPA包的分析 IPA包解压后是Payload文件夹,然后显示文件夹内的包内容,可以发现(企业证书打的包)包内有一个_CodeSignature……,4,0,0,苹果IPA包的重签名可以解决跟换一个包名、logo和IP地址后进行重新打包的工作,也避免了因为人为原因修改代码后忘记处理而导致打出的包无法使用的问题。目前市面上有的超级app或者蒲公英上宣传的企业签名所用到的就是重签名技术。

iOS签名机制

先来看一下数字签名的图

数字签名

苹果的签名机制如果简化,那也就是数字签名的流程。图的上半部分就是签名的过程,下半部分就是用户安装应用验证的过程。

苹果为了控制应用的安装和发布,除了公私钥对,还增加了Provisioning Profile(包含了APP ID、手机UDID列表、配置的功能权限信息表Entitlements以及证书),验证的流程也增加了好多层级:

先用公钥验证provisioning Profile 的签名和证书的签名;

认证通过后,再使用证书内的公钥验证APP的签名,APP ID和Entitlements验证APP,手机UDID列表验证手机是否包含在列表内;

所有的验证通过后用户才能使用。

苹果签名

IPA包的分析

IPA包解压后是Payload文件夹,然后显示文件夹内的包内容,可以发现(企业证书打的包)包内有一个_CodeSignature文件夹和.mobileprovision文件还有一些已经加密后的文件。其实_CodeSignature就是APP的签名文件,哪些已经加密的文件中也保存了APP的签名文件。如果有framework,它的文件内容和主文件下的差不多。

重签名

需要使用到的文件:

开发者证书

配置文件(entitlements)

Provisioning Profile文件(embedded.mobileprovision)

APP

步骤

找到开发者证书,可以在keychain我的证书中查找,找到证书后右键选择显示简介,拉到最底下选择SHA-1设置为常量,在重签名的时候可以通过这个哈希值找到对应的证书。

CERT_FILE = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'

使用embedded.mobileprovision文件生成entitlements.plist文件:

def gen_entitlements(out_file_name):
os.system('security cms -D -i "%s" > entitlement_full.plist ' % (get_mobile_provision_file()))
os.system('/usr/libexec/PlistBuddy -x -c \'Print:Entitlements\' entitlement_full.plist > "%s" ' % (out_file_name))

解压APP的IPA包

def unzip_app(original_ipa):
os.system('unzip -qo ./%s -d ./' % (original_ipa))
print('unzip_app %s done!' % (original_ipa))

移除XX.app文件夹下所有_CodeSignature包括frameworks里面的

def del_code_signature():
os.system("rm -rf ./Payload/iVMS-7880.app/_CodeSignature")
for file in os.listdir("./Payload/iVMS-7880.app/Frameworks"):
if os.path.splitext(file)[1] == '.framework':
os.system('rm -rf ./Payload/iVMS-7880.app/"%s"/_CodeSignature' % (file))
print('del_code_signature done!')

把准备好的embedded.mobileprovision复制到XX.app文件夹下

def replace_provision_file():
for file in os.listdir("./"):
if os.path.splitext(file)[1] == '.mobileprovision':
os.system('cp "%s" ./Payload/iVMS-7880.app/embedded.mobileprovision' % (file))

重签名framework

def resign_framework():
for file in os.listdir("./Payload/iVMS-7880.app/Frameworks"):
if os.path.splitext(file)[1] == '.framework':
os.system('/usr/bin/codesign --force --sign "%s" --entitlements "%s" "%s"' % (CERT_FILE, './entitlement.plist', './Payload/iVMS-7880.app/frameworks/"%s"' % (file)))
print('resign_framework "%s" done!' % (file))

重签名app执行文件

def resign_app():
os.system('/usr/bin/codesign --force --sign "%s" --entitlements "%s" "%s"' % (CERT_FILE, './entitlement.plist', './Payload/iVMS-7880.app/iVMS-7880'))
print('resign_app done!')

压缩Payload文件,重命名压缩文件为XX.ipa

def zip_app(f_ipa):
os.system('zip -r %s ./Payload' % (f_ipa))
print('zip_app done!')

到此就会有一个新的IPA包生成了,可以通过手机助手或者上传平台进行手机安装验证。

代码

#!/usr/bin/python
# -*- coding: utf-8 -*-

import os
import sys
import json

CERT_FILE = '6BF988FC0D4993B3D48810E4D67419A2B1E81DC1'

def get_mobile_provision_file():
file_path = ""
for file in os.listdir("./"):
if os.path.splitext(file)[1] == '.mobileprovision':
file_path = os.path.join(os.getcwd(),"%s" % (file))
return file_path

def reset_bundle_identifier(bundle_identifier):
os.system('/usr/libexec/PlistBuddy -c \'Set:CFBundleIdentifier "%s"\' Payload/iVMS-7880.app/Info.plist' % (bundle_identifier))

def reset_bundle_version(build):
os.system('/usr/libexec/PlistBuddy -c \'Set:CFBundleVersion "%s"\' Payload/iVMS-7880.app/Info.plist' % (build))

def unzip_app(original_ipa):
os.system('unzip -qo ./%s -d ./' % (original_ipa))
print('unzip_app %s done!' % (original_ipa))

def del_code_signature():
os.system("rm -rf ./Payload/iVMS-7880.app/_CodeSignature")
for file in os.listdir("./Payload/iVMS-7880.app/Frameworks"):
if os.path.splitext(file)[1] == '.framework':
os.system('rm -rf ./Payload/iVMS-7880.app/"%s"/_CodeSignature' % (file))
print('del_code_signature done!')

def resign_app():
os.system('/usr/bin/codesign --force --sign "%s" --entitlements "%s" "%s"' % (CERT_FILE, './entitlement.plist', './Payload/iVMS-7880.app/iVMS-7880'))
print('resign_app done!')

def resign_framework():
for file in os.listdir("./Payload/iVMS-7880.app/Frameworks"):
if os.path.splitext(file)[1] == '.framework':
os.system('/usr/bin/codesign --force --sign "%s" --entitlements "%s" "%s"' % (CERT_FILE, './entitlement.plist', './Payload/iVMS-7880.app/frameworks/"%s"' % (file)))
print('resign_framework "%s" done!' % (file))

def zip_app(f_ipa):
os.system('zip -r %s ./Payload' % (f_ipa))
print('zip_app done!')

def del_payload():
os.system('rm -r ./Payload')

def gen_entitlements(out_file_name):
os.system('security cms -D -i "%s" > entitlement_full.plist ' % (get_mobile_provision_file()))
os.system('/usr/libexec/PlistBuddy -x -c \'Print:Entitlements\' entitlement_full.plist > "%s" ' % (out_file_name))

def rep_emb_file():
os.system('cp "%s" ./Payload/iVMS-7880/embedded.mobileprovision' % (get_mobile_provision_file()))

def replace_provision_file():
for file in os.listdir("./"):
if os.path.splitext(file)[1] == '.mobileprovision':
os.system('cp "%s" ./Payload/iVMS-7880.app/embedded.mobileprovision' % (file))

if __name__ == '__main__':
gen_entitlements("entitlement.plist")

original_ipa = input("original_ipa:")
unzip_app(original_ipa)

bundle_identifier = input("bundle_identifier:")
reset_bundle_identifier(bundle_identifier)

build = input("build_version:")
reset_bundle_version(build)

del_code_signature()
replace_provision_file()
resign_framework()
resign_app()
newName = input("newName:")
zip_app(newName)
del_payload()

复制代码存储为python文件,之前准备的文件和该文件需要在同一个根目录下,然后在终端中执行该文件,输入对应信息后就可以得到新的IPA包。输入的信息都为字符串需要用引号,否则将会没有效果。
一个存在11年的签名验证漏洞允许恶意软件绕过多款Mac安全产品,https://www.jianshu.com/p/bc73a38d04c0,乖巧小墨宝,1 年前,……安全检查,并导致数百万苹果用户更加容易遭受黑客攻击。 Pitts表示,他在第三方安全产品对代码签名API的解释中找到了一个旁路,使未签名的恶意代码看起来像是由苹果官方签署的。这意味着,某些安全产品可能会……,代码签名专注于Mach-O二进制文件和应用程序包,以确保只有受信任的代码在内存中执行。 然而,Pitts指出,大多数产品用于检查代码签名的机制都存在被绕过的风险,它允许恶意代码与合法的苹果签名代码捆绑在……实现苹果的代码签名API有关的漏洞。 Universal/Fat文件是一种二进制格式,它包含多个Mach-O(可执行文件、dyld或bundle)文件,每个文件都针对特定的本机CPU体系结构(例如……,68,0,0,来自身份管理软件公司Okta的研究与开发工程师 Josh Pitts在本周二(6月12日)公开披露了一个在苹果macOS系统中存在了长达11 年之久的安全漏洞,该漏洞可能使得恶意软件能够更容易地绕过安全检查,并导致数百万苹果用户更加容易遭受黑客攻击。

Pitts表示,他在第三方安全产品对代码签名API的解释中找到了一个旁路,使未签名的恶意代码看起来像是由苹果官方签署的。这意味着,某些安全产品可能会因遭受“欺骗”而误以为恶意软件是由苹果签署的,进而允许恶意软件绕过其检测,从而感染用户设备。

可能遭受“欺骗”的几款第三方安全产品包括:Little Snitch、F-Secure xFence、VirusTotal、Google Santa和Facebook OSQuery。这个漏洞最早可以追溯到2007年推出的OS X Leopard 系统,并且至今一直存在。对苹果用户来说,相对而言较好的消息是,漏洞仅会影响到macOS和OSX的旧版本。

代码签名是一种安全机制,它使用公钥基础结构对编译后的代码甚至脚本语言进行数字签名,以确保来源可信以及已部署的代码没有被修改。在macOS或者iOS上,代码签名专注于Mach-O二进制文件和应用程序包,以确保只有受信任的代码在内存中执行。

然而,Pitts指出,大多数产品用于检查代码签名的机制都存在被绕过的风险,它允许恶意代码与合法的苹果签名代码捆绑在一起,从而有效地让恶意软件看起来像是苹果官方签署的。

应该指出的是,这个漏洞与macOS本身无关。相反,应该算是一个与第三方安全产品在处理Mac的可执行文件(Universal /Fat文件)时如何实现苹果的代码签名API有关的漏洞。

Universal/Fat文件是一种二进制格式,它包含多个Mach-O(可执行文件、dyld或bundle)文件,每个文件都针对特定的本机CPU体系结构(例如:i386,x86_64或PPC)。

“这个漏洞存在于Mach-O加载程序加载已签名代码的方式与代码签名API检查已签名代码的方式之间的差异,并且通过格式不正确的Universal /Fat Binary来利用。”Pitts解释说。

Pitts为此还创建了几个特定的PoC Universal/Fat文件以供第三方安全产品的开发人员使用,用于测试他们的产品是否存在此漏洞。

Pitts表示,在某些情况下,利用这种技术的成功攻击可以让攻击者获得用户的个人数据、财务细节,甚至是敏感的内部信息。

以下列出了具体受影响的供应商及其相关的安全产品和漏洞CVE编号:

VirusTotal – CVE-2018-10408

Google – Santa, molcodesignchecker – CVE-2018-10405

Facebook – OSQuery - CVE-2018-6336

Objective Development – LittleSnitch – CVE-2018-10470

F-Secure - xFence (also LittleFlocker) CVE-2018-10403Objective-See –WhatsYourSign, ProcInfo, KnockKnock, LuLu, TaskExplorer (and others). –CVE-2018-10404

Yelp - OSXCollector – CVE-2018-10406

Carbon Black – Cb Response – CVE-2018-10407

Okta公司在今年3月首次向苹果通报了这一漏洞,但该公司表示,他们并不认为这应该是属于由他们直接来解决的安全问题。

因此,在收到苹果的回复后,Okta公司联系了美国计算机紧急事件响应小组协调中心(CERT/CC),然后通知了所有已知的受影响的第三方安全产品厂商,这些公司目前正在开发用于解决问题的安全补丁。

目前,Facebook也已经在OSquery的最新版本中解决了这个问题。同时,F-Secure也向xFENCE用户推出了自动更新,以修补漏洞。

企业签名QQ:281442504

分享到