目录

  • 绕过 iOS 代码验证
  • ldid
  • Homebrew


绕过 iOS 代码验证

iOS 的代码验证分为 2 个环节:

  1. 签名验证,用于确认代码是经过苹果授权的
  2. 有效验证,用于确认代码没有被修改过

以下内容是基于 saurik 在 Cydia 中编写的一个文档,他文章的另一个版本的名称为:Bypassing iPhone Code Signatures

苹果要求 iOS 设备上的所有代码都要经过苹果的签名。这主要是为了让通过苹果应用商店(Apple App Store)下载和安装的 App 不能再下载和运行未经苹果授权的其他 App(以让 Apple App Store 没有竞争对手)。为了解决这个问题(从而将我们自己的代码安装到 iOS 设备上),越狱工具在内核中添加了对签名验证的补丁

然而,代码验证的另一半问题是,MachO 二进制文件中包含了许多用于有效验证的 SHA1 哈希值,内核的许多位置都会对这些哈希值进行检查。在内核中对验证 MachO 二进制哈希值的所有位置添加补丁对我们来说是边际效益递减的:因为苹果在内核中的其他位置添加对 MachO 二进制文件的哈希值的验证是很容易的,而我们跟踪苹果在内核中做出的改变是很困难的

这意味着至少我们仍然需要在代码验证流程中,内核有效验证这一环节,为计算出用于应付内核有效验证的哈希值而付出努力。目前有三个可行的选项

  • 选项 1:自签名
    这种方法是最容易理解的:使用苹果的 codesign 工具对 MachO 二进制文件进行签名。因为位于内核中的签名验证检查已经被破解了,所以开发者可以使用任意证书来对 MachO 二进制文件进行签名,而不仅仅是由苹果所批准的开发者证书。有关如何制作自签名证书的说明,你可以从苹果的网站上阅读这篇文章:Obtaining a Signing Identity在 Mac 的终端执行以下命令:
codesign -fs "Name" Program
scp Program mobile@iphone:
  • 选项 2:伪签名
    如果你没有 Mac 电脑,则无法使用上一个选项。整个 codesign 的流程不仅需要 Mac,还需要桌面访问,因为在某种程度上,codesign 算是一个图形实用工具(codesign 通过 Keychain 获取签名证书时,Keychain 可能会提示输入密码的对话框)。为了解决这个问题,saurik 编写了一个名为 ldid 的工具,除了其他公功能之外,ldid 还可以生成供 Apple 的 iOS 内核进行有效性检查的 SHA1 哈希值。这个工具可以使用 Cydia 或 APT 轻松地安装在 iPhone 上
    在 iPhone 的终端执行以下命令:
apt-get install ldid
scp user@desktop:Program .
ldid -S Program
  • 选项 3:禁用检查
    最后,一个便于开发的选项就是禁用检查。从技术上讲,禁用检查不仅会禁用对代码验证的检查,也会禁用对其他一些安全机制的检查。虽然我(saurik)在这种状态下运行我的 iPhone 已经有一段时间了,但是我(saurik)听说在某些配置中它会导致问题:最大的问题就是无法连接到不安全的 WiFi 网络中。禁用检查是通过使用 sysctl 命令停用 enforcement 来实现的,并且可以通过重置变量或者重新启动手机来重新启用
    在 iPhone 的终端执行以下命令:
sysctl -w security.mac.proc_enforce=0 security.mac.vnode_enforce=0

ldid

  • 简介
    ldid 是由 saurik 制作的一个工具,用于方便地修改 iOS 二进制可执行文件的授权。ldid 还为 iOS 二进制可执行文件的签名生成 SHA1SHA256 的哈希值,以让 iPhone 内核执行修改后的 iOS 二进制可执行文件。ldid 在 Cydia 中的包名是 Link Identity Editor项目地址(https://git.saurik.com/ldid.git)
  • 用法
    ldid -e <binary>:转储 iOS 二进制可执行文件中的 entitlements 文件
    ldid -Sent.xml <binary>:设置 iOS 二进制可执行文件的授权,其中 ent.xml 是指 entitlements 文件的路径
    ldid -S <binary>:在不使用 entitlements 文件的情况下,对 iOS 二进制可执行文件进行伪签名
    例如,如果开发者想将桌面上名为 Entitlements.xml 的文件中的权限添加到当前目录的 debugserver 中,则开发者可以执行:
    ldid -S/Users/you/Desktop/Entitlements.xml ./debugserver
  • 帮助手册
LDID(1) 		FreeBSD General Commands Manual(FreeBSD 通用命令手册) 	       LDID(1)

NAME(名称)

	ldid – Link Identity Editor

SYNOPSIS(摘要)

	ldid [-aDdehMPqu] 
		 [-Acputype:subtype]
		 [-C[adhoc | enforcement | expires | hard | host | kill | library-validation | restrict | runtime]]
		 [-Kkey.p12] 
		 [-r | -Sfile | -s] 
		 [-Ttimestamp] 
		 file ...

DESCRIPTION(说明)

	ldid 将 SHA1 和 SHA256 哈希值添加到 Mach-O 文件中,这样 Mach-O 文件就可以运行在具有(有效验证)但没有(签名验证)的系统上

	-a			# 以十六进制的形式打印 CPU 类型和 CPU 子类型

	-Acputype:subtype 
				# 当与 -a, -D, -e, -h, -q, -u 一起使用时,只作用于 cputype 和 subtype 指定的片(slice)。cputype 和 subtype 都应该是整数

	-C[adhoc | enforcement | expires | hard | host | kill | library-validation | restrict | runtime]
				# 指定要嵌入到代码签名中的选项标志。有关这些选项的详细信息,请查看 codesign(1)

	-D			# 重置 cryptid

	-d			# 如果二进制可执行文件中存在 cryptid,则打印它。由于兼容性的原因,此指令也充当 -h 的功能,但这将在未来版本中被删除

	-e			# 用标准输出(stdout)打印每个片(slice)中的 entitlements,或者打印由 -A 指定的片(slice)中的 entitlements

	-h			# 用标准输出(stdout)打印与签名有关的信息,例如:hash types、flags、CDHash、CodeDirectory version

	-Kkey.p12	# 使用 key.p12 文件中的证书信息进行签名(.p12 文件中存储的是:开发者证书 + 对应的专用私钥)
				# 这将给二进制可执行文件一个有效的签名,以便它可以运行在具有签名验证的系统上。key.p12 文件必须不能有密码

	-M			# 当与 -S 一起使用时,将合并新的 entitlements 和现有的 entitlements,而不是用新的 entitlements 替换现有的 entitlements
				# 这对于向少数二进制可执行文件添加一些特定的权限很有用

	-P			# 将 Mach-O 文件标记为 platform binary

	-Qfile		# 向二进制可执行文件中嵌入在参数 file 所指定文件中所找到的 requirements 

	-q			# 打印嵌入在二进制可执行文件中的 requirements

	-r			# 删除 MachO 文件中的签名

	-S[file]	# 对 MachO 二进制文件进行伪签名。如果指定了 file 参数,则将在 file 参数所标识的文件中找到的 entitlements 嵌入到 MachO 文件中

	-s			# 对 MachO 二进制文件进行重签名,同时保留现有的 entitlements

	-Ttimestamp	# 当对 dylib 进行签名时,可以使用参数 -Ttimestamp 将指定的时间戳设置给 dylib 的 timestamp 字段
				# 参数 -Ttimestamp 指定的时间戳应该是一个以秒为单位的 UNIX 时间戳
				# 如果参数 -Ttimestamp 指定的时间戳是个破折号("-"),则 dylib 的 timestamp 字段将被设置为其 Mach-O header 的哈希值

	-u			# 如果二进制可执行文件有跟 UIKit.framework 进行链接,则打印与二进制可执行文件链接的 UIKit.framework 的版本

EXAMPLES(示例)

	命令:ldid -S file
	说明:在不使用 entitlements 的情况下,对参数 file 所指定的二进制可执行文件进行伪签名
	
	命令:ldid -Cadhoc -K/path/to/key.p12 -Sent.xml file
	说明:将使用(/path/to/key.p12 中的 key)和(在 ent.xml 中找到的 entitlements)对 file 参数所指定的二进制可执行文件进行签名,并将其标记为一个 adhoc 签名
	
	命令:ldid -Sent.xml -M file
	说明:将 ent.xml 中的 entitlements 添加到参数 file 所指定的二进制可执行文件的 entitlements 中

	命令:ldid -e file > ent.xml
	说明:将参数 file 所指定的二进制可执行文件中每个 CPU 片(slice)的 entitlements 保存到 ent.xml 中

SEE ALSO(请参考)

     codesign(1)

HISTORY(历史)

	ldid 是由 Jay Freeman (Saurik) 所编写的
	iPhoneOS 1.2.0 和 2.0 的支持是在 2008 年 4 月 6 日添加的
	-S 是在 2008 年 6 月 13 日增添加的
	对 SHA256 的支持是在 2016 年 8 月 25 日添加的,修复了对 iOS 11 的支持
	对 iOS 14 的支持是在 2020 年 7 月 31 日由 Kabir Oberai 添加的
	对 iOS 15 的支持是在 2021 年 6 月 11 日添加的

iPhoneDevWiki			October 8, 2021(2021 年 10 月 8 日) 		 iPhoneDevWiki
  • 安装
    通过 Homebrew、Fink 或者 source:
git clone https://github.com/sbingner/ldid
cd ldid
git submodule update --init
./make.sh
cp -f ./ldid $THEOS/bin/ldid

Homebrew

  • 简介
    Homebrew 是一款 macOS 平台下的软件包管理工具,拥有安装、卸载、更新、查看、搜索等很多实用的功能。简单的一条指令,就可以实现包管理,而不用开发者关心各种依赖和文件路径的情况,十分方便快捷
    官网地址
  • 安装 & 卸载
# Homebrew 安装脚本
/bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"
# Homebrew 卸载脚本
/bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/HomebrewUninstall.sh)"
  • 常用命令
# 更新 Homebrew
brew update

# 查询当前 Homebrew 版本
brew -v

# 查询 Homebrew 帮助信息
brew -h

# 安装给定的包
brew install <packageName>

# 卸载给定的包
brew uninstall <packageName>

# 更新给定的包
brew upgrade <packageName>

# 查询给定的包
brew search <packageName>

# 查询给定包的信息
brew info <packageName>

# 查询已安装的包的列表
brew list

# 查看可清理的旧版本包(仅查看,不执行清理)
brew cleanup -n

# 清理所有包的旧版本
brew cleanup
  • 更换阿里云镜像源进行加速
    执行 brew install <packageName> 命令安装软件包的时候,软件包的下载速度跟以下 3 个仓库的地址有关:
  1. brew.git
  2. homebrew-core.git
  3. homebrew-bottles

因为这 3 个仓库的默认地址都在国外,所以下载速度非常感人。建议将这 3 个仓库的地址切换到国内。以切换到阿里云镜像源为例:

① 更换 brew.git

cd "$(brew --repo)"
git remote set-url origin https://mirrors.aliyun.com/homebrew/brew.git

② 更换 homebrew-core.git

cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core"
git remote set-url origin https://mirrors.aliyun.com/homebrew/homebrew-core.git

③ 执行 brew update 命令,更新 Homebrew

④ 更换 homebrew-bottles

# 如果默认 shell 是 zsh,则执行以下两条命令
echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.aliyun.com/homebrew/homebrew-bottles' >> ~/.zshrc
source ~/.zshrc

# 如果默认 shell 是 bash,则执行以下两条命令
echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.aliyun.com/homebrew/homebrew-bottles' >> ~/.bash_profile
source ~/.bash_profile