iOS代码签名是苹果生态中安全机制的核心组成部分,其目的在于:
确保应用来源可信;
保证应用在分发、安装、运行过程中未被篡改;
强化沙箱隔离与权限控制;
实现应用追踪、授权和安全限制(如调试权限、Entitlements 等);
iOS 系统是一个高度封闭的移动操作系统。苹果采用“强制签名”的机制:所有运行在设备上的应用、动态库、系统组件等,都必须被签名并被信任。这是苹果构建其安全生态(如 App Store 审核、企业分发限制、隐私保护等)的基础。
没有合法签名的应用无法在未越狱的设备上运行。
防止第三方恶意篡改应用(如注入、重打包)
防止未授权的调试、注入、越权操作
限制破解行为(如破解付费、注入钩子、动态修改)
iOS 签名依赖苹果颁发的证书链,主要包括:
类型
用途
签名是用私钥进行的;
设备和系统在运行时使用公钥验证签名的合法性。
是 .plist
格式的声明文件,告知系统你的应用需要使用哪些敏感能力(如 iCloud、Push、调试等);
这些权限需要与签名证书的能力匹配;
如果签名时声明了未授权的 Entitlements,运行会失败。
苹果使用一种称为 Code Signing Blob 的结构来封装签名信息,包含以下几个部分:
这是签名的核心结构,内容包括:
每个段(segment)或文件的哈希(Code Slot)
主可执行文件的哈希摘要(Main Executable Digest)
应用标识符(Identifier)
版本号、平台标识
Team ID(开发团队标识)
Entitlements hash(匹配授权)
包含:
证书链(Developer + WWDR + Root CA)
签名数据本身(对 Code Directory 的签名)
为了防止修改 Info.plist 中的关键字段(如 CFBundleIdentifier)
系统验证 Entitlements 的 hash 是否匹配签名时的声明。
在 Apple Developer 网站上创建 App ID;
使用 Xcode 或 Keychain 创建 CSR(证书请求);
苹果签发证书后下载并导入;
在 IOS APP的Macho文件中,LC_CODE_SIGNATURE类型的 load commands与代码签名相关,通过 MachoView打开这个文件可以看到:

签名数据位于文件偏移 0x2EBB200处,数据长度是0x1349E0

上述地址实际指向的是一个名为 SC_SuperBlob的结构体数据,数据定义如下:
第一个字段 magic是类型标记,固定为 0xfade0c00,第二个字段 length是这个 SC_SuperBlob数据的总长度,count是结构体中 CS_BlobIndex数据的个数。
CS_BlobIndex表示的是数据的类型和该类型数据在签名数据中的偏移,定义如下:
上图数据中共有 6 个 BlobIndex数据,如下图:

BlobIndex的 type 类型枚举如下:
BlobIndex偏移指向的是SC_GenericBlob结构体数据,定义如下:
第一个字段是类型标记,用于标记该数据类型。data字段才是实际的数据内容,长度通过 length 字段决定。
magic 字段的枚举值定义:
我们通过上面的 BlobIndex类型的排列顺序,逐个分析。
第一个 BlobIndex的 type 是 0,即 CSSLOT_CODEDIRECTORY_SHA1,表示存放的是 CodeDirectory数据,偏移地址是 3C,实际地址就是 0x2ebb23c.
CodeDirectory数据是签名的重要组成部分,里面包含了主 macho 文件代码段和数据段的哈希值,用于防止代码或数据被篡改。

这里 hashType = 0x1,以及 hashSize = 0x14,表示使用的是 sha1算法,哈希串长度是 20 个字节。
hashOffset值是 0x3A7B6,位于文件偏移 0x2ef59f2, 即地址 0x2ef59f2开始的 20 字节表示的是 TEXT段的第一个page的 sha1 哈希值

这里 TEXT段文件偏移是 0,从文件的第 0 个字节开始,计算连续 0x1000个字节的 sha1值

符合hashOffset中记录的哈希值:

nSpecialSlots字段记录特殊区域或者文件的哈希值,这个值是负数
CodeResources文件中保存了 APP中各种文件的哈希值,用于校验 APP中的资源文件是否被篡改。
entitlement数据定义了 APP运行时需要哪些权限。
代码检测签名内容中的 CodeDirectory数据:
1、检测 plist篡改
2、检测 CodeResources文件篡改
3、检测 entitlement篡改
4、检测代码段篡改
5、检测资源文件篡改:
上述代码可以检测资源数据或代码是否被篡改,那么如果同时篡改了CodeDirectory呢?(CMS签名中会检验CodeDirectory的哈希)
第二个 BlobIndex的 type 是 2,即 CSSLOT_REQUIREMENTS,用于说明签名对运行条件的要求。
结构体定义如下:
实际数据位于 0x2f300a2

上述数据中定义了一个 Requirement,位于地址 0x2f300b6,Requirement 的定义如下:
expr数据是 Requirement Language 编译后的二进制。
第三个 BlobIndex的 type 是 5,即 CSSLOT_ENTITLEMENTS,用于权限标记。地址位于 0x2f30102

实际数据位于 0x2f3010a,长度是 0x2d8
导出:

数据内容:

第四个 BlobIndex的 type 是 7,是 CSSLOT_DER_ENTITLEMENTS。应该是使用 asn1编码后的 ENTITLEMENTS数据。
导出:

解析 asn1数据:

第五个 BlobIndex的 type 是 0x1000,是 CSSLOT_CODEDIRECTORY_SHA256。同 CSSLOT_CODEDIRECTORY_SHA1,不再分析。
第六个 BlobIndex的 type 是 0x10000,是 CSSLOT_SIGNATURESLOT,是详细的 CMS 签名数据。地址位于 0x2feb590

实际 CMS签名数据位于 0x2feb598,长度是 0x1126,导出数据:

解析:

这是使用 asn1编码的详细数据,里面包含了签名的详细信息,包括证书链、签名时间、CodeDirectory 哈希等。
什么是 ASN1
ASN.1(Abstract Syntax Notation dotone),抽象语法标记。是定义抽象数据类型形式的标准,描绘了与任何表示数据的编码技术无关的通用数据结构。抽象语法使得人们能够定义数据类型,并指明这些类型的值。抽象语法只描述数据的结构形式,与具体的编码格式无关,同时也不涉及这些数据结构在计算机内如何存放。
cms签名结构解析
1、定义标签
cms签名数据以 ASN1_TAG_SEQUENCE类型的ContentInfo开始,这个 sequence 包含两个数据:ContentType 和 Content

解析的入口:
先解析 ContentType,支持 1.2.840.113549.1.7.2 和 1.2.840.113549.1.7.1 两种签名数据解析。然后通过 cms_parse_signData函数解析签名数据。
继续看 Content内部是什么结构:

Content里面只有一个 sequence 类型的 SignedData数据,SignedData里包含版本、签名算法、证书链以及签名信息。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2025-6-10 12:41
被CCTV果冻爽编辑
,原因: