本文由 简悦 SimpRead转码,原文地址 jon-gabilondo-angulo-7635.medium.com
在第一部分中,我们看到了在 Mac 应用程序(从计算器到 Mail)中注入代码是多么容易,甚至更简单......。
动态代码注入技术
Microsoft Word 2018中的Organismo-App-inspector
更新!
本文是在寻找将 Organismo 框架或任何其他库注入加固应用程序的解决方案时撰写的。文章描述了克服阻止代码注入的限制的历程,直到我们绊倒在 AMFI 和 Gatekeeper 的最后一关。
值得庆幸的是,对 AMFI 稍加研究后,我们找到了令人惊喜的解决方案。您可以跳转到文章末尾,找到在任何 Mac 应用程序上自由注入代码的解决方案。不过,如果你对 OS X(和 iOS)系统安全的细节感兴趣,那么在此之前的内容都非常有趣。
在第一部分中,我们看到了向 Mac 应用程序(从计算器到邮件)注入代码是多么容易,更令人惊讶的是,向 Word 2018 等微软应用程序注入代码也是如此容易。如此重要的应用程序为何没有简单的保护措施(加固)来防止外部代码注入,这一点并不容易理解。平心而论,我们必须指出,在第一部分中,我们的工作条件是禁用系统完整性保护(SIP),这是 OS X 上的一个重要安全层。
在第一部分中,我们使用了一种动态代码注入技术,即使用 DYLD_INSERT_LIBRARIES 环境变量(动态链接器 "dyld "的一个旧属性)来加载外部库。
然而,正如我们所预料的那样,第一部分中使用的简单动态代码注入技术在 iTunes、Xcode、Photos......等(重要)应用程序中无法奏效。这些应用程序都经过了加固,以指示 "dyld "禁用环境变量定义的注入,并拒绝不符合应用程序代码签名的代码。
在本故事中,我们将寻找一种解决方案,将外部代码注入 iTunes 和 Xcode 等加固应用程序。
Hardened Runtime
加固运行时与系统完整性保护(SIP)一起,通过防止代码注入、动态链接库(DLL)劫持和进程内存空间篡改等特定类别的漏洞利用,保护软件的运行时完整性。
加固应用程序有两种方法,一种是官方的使用权限,另一种是在 Mach-O 二进制文件中创建一个 __RESTRICT 段。
要以 Apple 官方方式加固应用程序,请在 Xcode 中导航到目标的签名与权限信息,然后单击 + 按钮。在出现的窗口中,选择 Hardened Runtime。
然后添加 "Hardened Runtime "功能。在 "Build Settings(构建设置)"中检查是否启用了 "Hardened Runtime"。
点击此处查看 Apple 文档:
developer.apple.com/documentati…
developer.apple.com/videos/play…
Hardening by Entitlements
我们已经看到,Xcode 允许以一种简单的方式加固应用程序,但如何将它们应用到二进制文件中,以及它们保存在二进制文件的何处呢?
让我们从检索任何应用程序二进制文件的权限开始,这可以使用 codesign 来完成, 让我们在 Music.app 上完成它:
$ codesign -d --entitlements :- /System/Applications/Music.appExecutable=/System/Applications/Music.app/Contents/MacOS/Music
这是 codesign 命令的输出结果,其中包含 Music.app 权限的 xml 列表:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.PairingManager.Read</key>
<true/>
<key>com.apple.PairingManager.RemovePeer</key>
<true/>
<key>com.apple.PairingManager.Write</key>
<true/>
<key>com.apple.amp.artwork.client</key>
<true/>
<key>com.apple.amp.devices.client</key>
<true/>
<key>com.apple.amp.library.client</key>
<true/>
<key>com.apple.application-identifier</key>
<string>com.apple.Music</string>
<key>com.apple.authkit.client.internal</key>
<true/>
<key>com.apple.avfoundation.allow-system-wide-context</key>
<true/>
<key>com.apple.avfoundation.allows-access-to-device-list</key>
<true/>
<key>com.apple.avfoundation.allows-set-output-device</key>
<true/>
<key>com.apple.cdp.recoverykey</key>
<true/>
<key>com.apple.mediaremote.allow</key>
<array>
<string>TVPairing</string>
</array>
<key>com.apple.private.accounts.allaccounts</key>
<true/>
<key>com.apple.private.applemediaservices</key>
<true/>
<key>com.apple.private.aps-connection-initiate</key>
<true/>
<key>com.apple.private.audio.notification-wake-audio</key>
<true/>
<key>com.apple.private.bmk.allow</key>
<true/>
<key>com.apple.private.commerce</key>
<array>
<string>Accounts</string>
</array>
<key>com.apple.private.fpsd.client</key>
<true/>
<key>com.apple.private.notificationcenter-system</key>
<array>
<dict>
<key>identifier</key>
<string>com.apple.appstoreagent</string>
</dict>
</array>
<key>com.apple.private.rtcreportingd</key>
<true/>
<key>com.apple.private.security.storage.mobilesync.heritable</key>
<true/>
<key>com.apple.private.sqlite.sqlite-encryption</key>
<true/>
<key>com.apple.private.tcc.allow</key>
<array>
<string>kTCCServiceAddressBook</string>
<string>kTCCServicePhotos</string>
<string>kTCCServiceAppleEvents</string>
<string>kTCCServiceSystemPolicyAllFiles</string>
<string>kTCCServiceCamera</string>
</array>
<key>keychain-access-groups</key>
<array>
<string>com.apple.pairing</string>
<string>com.apple.airplay</string>
<string>apple</string>
</array>
</dict>
</plist>
在运行时,OSX/iOS 需要验证可执行文件访问的操作和资源,为此,它需要通过权限了解应用程序已验证的内容。权限保存在二进制 Mach-O 结构本身的 "代码签名 "设置中。
Music.app 二进制文件中的代码签名部分。
因此,Music.app 二进制文件中的 "权利"(Entitlements)代码签名部分是一个简单的 xml 列表,其中的键定义了权利及其属性。虽然苹果公司为程序员记录并提供了少量权限,但内部可能有数百个。
在 codesign 命令中定义应享权利 xml 文件,就可以为应用程序分配应享权利:
$ codesign --entitlements entitlements.xml -f -s "iPhone Distribution: Company (XYZ)" Payload/Example.app
An interesting option when resigning an App that has already the entitlements set use the flag: --preserve-metadata=entitlements
Hardened by __RESTRICT
__RESTRICT 段是 Mach-O 二进制文件中的一个部分,可以在链接时创建。该段没有内容。它就像一个标志,指示 "dyld "对加载到进程中的所有代码执行代码签名验证。
请看下面 iTunes 中的 __RESTRICT 部分:
iTunes 中的 __RESTRICT 部分。
在 Xcode 中创建 __RESTRICT 段其实非常简单。只需在 "Other Linker Flags"(其他链接器标志)中添加以下标志即可:
-Wl,-sectcreate,__RESTRICT,__restrict,/dev/null
为什么拒绝注入
__RESTRICT 段标记"dyld'",以激活所有要加载的库的代码签名验证。
我们在第一部分中看到了 iTunes 中的注入是如何失败的,并出现了以下信息:
"dyld warning: could not load inserted library into hardened process because no suitable image found."(dyld 警告:由于没有找到合适的图像,无法将插入的库加载到加固进程中。框架中的代码签名无效,无法在使用库验证的进程中使用"。
如果我们分析 iTunes 和 Organismo 的代码签名,就会发现它们的代码签名值(证书)明显不同:
iTunes 代码签名值。
Organismo 代码签名值。
Approaches to Overcome Hardening
为了克服硬化障碍,我想到了这些办法。从愚蠢到现实,它们是
- 构建我们自己的经过调整的 "dyld",并指示应用程序使用它,而不是默认的"/usr/lib/dyld"。
- 使用自己的证书对所有软件组件进行代码设计。
- 删除 __RESTRICT 段。
Option 1. Create a Custom dyld
这无疑是一个大胆的想法。建立一个定制的 "dyld",去掉所有不关心 SIP 或__RESTRICT 的安全措施,听起来令人兴奋。这种选择的动机有两个 "合理 "的事实。首先,"dyld "代码是开源的:
opensource.apple.com/release/mac…
其次,正如我们在第一部分中看到的,每个应用程序的 Mach-O 二进制文件都指定了必须使用的动态链接器。在 Mac OS X 中总是"/usr/lib/dyld":
截至目前,macOS 10.14.5 开放源代码 网站已有一百多个项目。OS X 和 iOS 的动态链接器就在这里。令人印象深刻。
好吧,第一个问题:
Base SDK MacOSX.internal (SDK not found)
MacOSX.internal ......好吧......我明白了,苹果有自己的 SDK,有道理。我能得到它吗?显然不行。所以我们把基础 SDK 设置为默认的 "macOS"。
从那时起,编译过程就再也没有停止过: _simple.h、Block_private.h、coreSymbolicationDyldSupport.h、CrashReporterClient.h、cs_blobs、objc-shared-cache 等等等等。
我们可以煞费苦心地从不同的开源软件包中查找缺失的包含内容,直到找不到为止。一定有更好的办法,但现在还找不到。
这个方案到此为止。我们不禁要问,苹果公司是如何理解开源的?
Option 2. Re-Codesigning with Your Certificate
我们认为,Organismo 框架之所以被 "dyld "拒绝,是因为它的代码签名证书与 iTunes 的不同。Organismo 使用的是开发者证书,而 iTunes 使用的是苹果的私人证书。
因此,我们假设使用我们的开发者证书对 iTunes 进行代码签名,"dyld "将在加载 Organismo 时通过代码完整性验证。
重新设计任何应用程序都非常简单(请记住要在应用程序的副本上操作!):
$ codesign --deep --force --preserve-metadata=entitlements -s ‘Mac Developer: Jon Gabilondo (HSU……MR)’ /Users/jongabilondo/Desktop/iTunes.app
Notice the --preserve-metadata=entitlements
使用 "codesign -dvvv "检查签名,我们可以看到签名现在是 "Jon Gabilondo",这正是我们想要的。在尝试注入之前,让我们运行一下修改后的 iTunes,看看它是否能正常运行:
$ DYLD_INSERT_LIBRARIES=/path_to/Organismo-mac.framework/Versions/A/Organismo-mac /Users/jongabilondo/Desktop/iTunes.app/Contents/MacOS/iTunes
拥有相同代码签名的假设部分是正确的。但它并没有考虑到 dylib 依赖关系的影响,因为这些依赖关系最终总是会出现在带有 Apple 签名的 Apple 系统 dylib 中。就像我们在修改后的 iTunes 的错误报告中看到的那样,iTunes 的 dylibs 有 Jon 的签名,但它的依赖项最终总是在 Apple 的 OSX /usr/lib dylibs 中。
方案 2 也不好。
Error loading dylib because binary is restricted.
阅读苹果公司的代码签名深度:总是非常有用的。
developer.apple.com/library/arc…
Option 3. Removing the __RESTRICT segment
我只剩下最后一项了。如果 __RESTRICT 段是激活代码签名验证的标志,我们可以直接从 Mach-O 二进制文件中删除它。
这种方法需要修改静态代码,这显然会导致二进制文件(校验和)失效。但我们知道如何使用开发证书重新设计应用程序,所以应该没有问题。
删除 __RESTRICT 段
有几种工具可以用来修改 Mach-O 二进制文件,你可以选择自己喜欢的。这里我将使用 iHex 编辑器。找到 __RESTRICT 段并将其重命名,例如改为 例如:__XESTRICT。保存文件并用你的开发证书进行代码设计。
重命名 iTunes Mach-O 二进制文件中的 __RESTRICT 段。
现在,让我们将 Organismo 注入 iTunes:
$ DYLD_INSERT_LIBRARIES=/path-to/Organismo-mac.framework/Versions/A/Organismo-mac /Users/jongabilondo/Desktop/iTunes.app/Contents/MacOS/iTunes
这次 Organismo 框架成功载入 iTunes。
Update for Catalina!
Mac OSX Catalina 添加了新的系统保护措施。更改应用程序的 RESTRICT 部分并使用开发证书重新编码后,确实会导致应用程序无效。
Music.app 启动时会崩溃。日志提示taskgated-helper和amfid进程: 禁止使用 com.apple.Music,因为未找到符合条件的配置文件。
下面是控制台日志:
error 11:06:47.743379+0200 taskgated-helper Disallowing com.apple.Music because no eligible provisioning profiles found
error 11:06:47.743805+0200 amfid CPValidateProvisioningDictionariesExtViaBridge returned invalid result: {
success = 0;
}
default 11:06:47.743834+0200 amfid Failure validating against provisioning profiles: No eligible provisioning profiles found
default 11:06:47.743870+0200 amfid Requirements for restricted entitlements failed to validate, error -67671, requirements: ‘<private>’, error: (null)
default 11:06:47.743884+0200 amfid Restricted entitlements not validated, bailing out. Error: (null)
default 11:06:47.744097+0200 amfid /Users/jongabilondo/Desktop/Music.app/Contents/MacOS/Music signature not valid: -67671
default 11:06:47.744129+0200 kernel AMFI: code signature validation failed.
default 11:06:47.744136+0200 kernel AMFI: bailing out because of restricted entitlements.
default 11:06:47.744201+0200 kernel proc 1418: load code signature error 4 for file “Music”
该taskgated进程属于一个守护进程,可以在以下目录中找到:
/System/Library/LaunchDaemons/com.apple.taskgated.plist
and the related:
/System/Library/LaunchDaemons/com.apple.taskgated-helper.plist
可执行文件是 : /usr/libexec/taskgated 和 /usr/libexec/tasgated-helper
amfid 是苹果移动文件完整性的守护进程,位于 /System/Library/LaunchDaemons/com.apple.MobileFileIntegrity.plist,可启动 /usr/libexec/amfi。
这是一篇关于 AMFI 的非常有趣的文章:
我们可以假定,这两个 Apple 安全守护进程拒绝接受我们编码的 Music.app,是因为我们的 Dev 证书不接受它所需的权限。为了确认这一点,我们可以根据 Music.app 的权限创建一个权限文件,并删除以 com.apple.private.*. 开头的条目。这样生成的 Music.app 将通过 AMFI 和 Gatekeeper 安全验证,并可以启动,但在需要这些权限的操作中会失败。
这是一段关于 Gatekeeper 和其他 Catalina 安全更新的精彩 WWDC 视频:
developer.apple.com/videos/play…
The Solution
第一版文章的结尾是这样的:
为了让 Organismo App Inspector 仍能在 Catalina 及其后续版本中正常工作,我们的方向是让 dyld、AMFI 和 Gatekeeper "不碍事",即禁用它们的完整性验证。
"让它们别碍事" 这一表述是最有预见性的。请参阅 iphonewiki上有关 AMFI 的条目。
The amfi kext recognizes quite a few boot-args, including:
amfi_unrestrict_task_for_pid — Allowing the above to proceed even without entitlement
amfi_allow_any_signature — Allowing any digital signature on code, not just Apple’s
amfi_get_out_of_my_way — disable amfi
cs_enforcement_disable — Disable code signing enforcement
cs_debug — Debug code signing
我们可以设置一个引导参数来完全禁用 AMFI 守护进程!
% sudo nvram boot-args="amfi_get_out_of_my_way=0x1"
(careful with the quotes if you copy-paste.)
重新启动。AMFI 将从系统中消失。Organismo 可以自由注入任何应用程序。
% DYLD_INSERT_LIBRARIES=/path/to/Organismo-mac.framework/Versions/A/Organismo-mac /System/Applications/Music.app/Contents/MacOS/Music
Organismo 已注入 Music.app
Thanks !
希望您喜欢。您可以使用 Organismo 自行探索。