diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 27f33cff3..2062b6f9d 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -61,6 +61,7 @@ - [Deofuscation vbs (cscript.exe)](generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/desofuscation-vbs-cscript.exe.md) - [Discord Cache Forensics](generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/discord-cache-forensics.md) - [Local Cloud Storage](generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/local-cloud-storage.md) + - [Mach O Entitlements And Ipsw Indexing](generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/mach-o-entitlements-and-ipsw-indexing.md) - [Office file analysis](generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/office-file-analysis.md) - [PDF File analysis](generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/pdf-file-analysis.md) - [PNG tricks](generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/png-tricks.md) diff --git a/src/generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/README.md b/src/generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/README.md index 0d60c0d6f..6e0e8786b 100644 --- a/src/generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/README.md +++ b/src/generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/README.md @@ -2,7 +2,7 @@ {{#include ../../../banners/hacktricks-training.md}} -这里你可以找到针对特定文件类型和/或软件的有趣技巧: +在这里你可以找到针对特定文件类型和/或软件的有趣技巧: {{#ref}} @@ -54,4 +54,9 @@ video-and-audio-file-analysis.md zips-tricks.md {{#endref}} + +{{#ref}} +mach-o-entitlements-and-ipsw-indexing.md +{{#endref}} + {{#include ../../../banners/hacktricks-training.md}} diff --git a/src/generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/mach-o-entitlements-and-ipsw-indexing.md b/src/generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/mach-o-entitlements-and-ipsw-indexing.md new file mode 100644 index 000000000..fb0588b5b --- /dev/null +++ b/src/generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/mach-o-entitlements-and-ipsw-indexing.md @@ -0,0 +1,213 @@ +# Mach-O 权限提取与 IPSW 索引 + +{{#include ../../../banners/hacktricks-training.md}} + +## 概述 + +本页介绍如何通过遍历 LC_CODE_SIGNATURE 并解析 code signing SuperBlob,编程式地从 Mach-O 二进制中提取 entitlements,以及如何通过挂载并索引 Apple IPSW 固件的内容,以便进行取证搜索/差异比较,从而实现规模化处理。 + +如果你需要复习 Mach-O 格式和 code signing,可以参考:macOS code signing 和 SuperBlob 内部结构。 +- Check macOS code signing details (SuperBlob, Code Directory, special slots): [macOS Code Signing](../../../macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-code-signing.md) +- Check general Mach-O structures/load commands: [Universal binaries & Mach-O Format](../../../macos-hardening/macos-security-and-privilege-escalation/macos-files-folders-and-binaries/universal-binaries-and-mach-o-format.md) + + +## Entitlements in Mach-O: where they live + +Entitlements 存储在由 LC_CODE_SIGNATURE 加载命令引用的 code signature 数据中,并放置在 __LINKEDIT 段。该签名是一个 CS_SuperBlob,包含多个 blob(code directory、requirements、entitlements、CMS 等)。entitlements blob 是一个 CS_GenericBlob,其数据是一个 Apple Binary Property List (bplist00),将 entitlement 键映射到值。 + +关键结构(来自 xnu): +```c +/* mach-o/loader.h */ +struct mach_header_64 { +uint32_t magic; +cpu_type_t cputype; +cpu_subtype_t cpusubtype; +uint32_t filetype; +uint32_t ncmds; +uint32_t sizeofcmds; +uint32_t flags; +uint32_t reserved; +}; + +struct load_command { +uint32_t cmd; +uint32_t cmdsize; +}; + +/* Entitlements live behind LC_CODE_SIGNATURE (cmd=0x1d) */ +struct linkedit_data_command { +uint32_t cmd; /* LC_CODE_SIGNATURE */ +uint32_t cmdsize; /* sizeof(struct linkedit_data_command) */ +uint32_t dataoff; /* file offset of data in __LINKEDIT */ +uint32_t datasize; /* file size of data in __LINKEDIT */ +}; + +/* osfmk/kern/cs_blobs.h */ +typedef struct __SC_SuperBlob { +uint32_t magic; /* CSMAGIC_EMBEDDED_SIGNATURE = 0xfade0cc0 */ +uint32_t length; +uint32_t count; +CS_BlobIndex index[]; +} CS_SuperBlob; + +typedef struct __BlobIndex { +uint32_t type; /* e.g., CSMAGIC_EMBEDDED_ENTITLEMENTS = 0xfade7171 */ +uint32_t offset; /* offset of entry */ +} CS_BlobIndex; + +typedef struct __SC_GenericBlob { +uint32_t magic; /* same as type when standalone */ +uint32_t length; +char data[]; /* Apple Binary Plist containing entitlements */ +} CS_GenericBlob; +``` +重要常量: +- LC_CODE_SIGNATURE cmd = 0x1d +- CS SuperBlob magic = 0xfade0cc0 +- Entitlements blob type (CSMAGIC_EMBEDDED_ENTITLEMENTS) = 0xfade7171 +- DER entitlements may be present via special slot (e.g., -7), see the macOS Code Signing page for special slots and DER entitlements notes + +注意:多架构(fat)二进制包含多个 Mach-O slices。你必须选择要检查的架构对应的 slice,然后遍历其 load commands。 + + +## Extraction steps (generic, lossless-enough) + +1) Parse Mach-O header; iterate ncmds worth of load_command records. +2) Locate LC_CODE_SIGNATURE; read linkedit_data_command.dataoff/datasize to map the Code Signing SuperBlob placed in __LINKEDIT. +3) Validate CS_SuperBlob.magic == 0xfade0cc0; iterate count entries of CS_BlobIndex. +4) Locate index.type == 0xfade7171 (embedded entitlements). Read the pointed CS_GenericBlob and parse its data as an Apple binary plist (bplist00) to key/value entitlements. + +Implementation notes: +- Code signature structures use big-endian fields; swap byte order when parsing on little-endian hosts. +- The entitlements GenericBlob data itself is a binary plist (handled by standard plist libraries). +- Some iOS binaries may carry DER entitlements; also some stores/slots differ across platforms/versions. Cross-check both standard and DER entitlements as needed. +- For fat binaries, use the fat headers (FAT_MAGIC/FAT_MAGIC_64) to locate the correct slice and offset before walking Mach-O load commands. + + +## Minimal parsing outline (Python) + +The following is a compact outline showing the control flow to find and decode entitlements. It intentionally omits robust bounds checks and full fat binary support for brevity. +```python +import plistlib, struct + +LC_CODE_SIGNATURE = 0x1d +CSMAGIC_EMBEDDED_SIGNATURE = 0xfade0cc0 +CSMAGIC_EMBEDDED_ENTITLEMENTS = 0xfade7171 + +# all code-signing integers are big-endian per cs_blobs.h +be32 = lambda b, off: struct.unpack_from(">I", b, off)[0] + +def parse_entitlements(macho_bytes): +# assume already positioned at a single-arch Mach-O slice +magic, = struct.unpack_from(" +``` +- 遍历已挂载卷以定位 Mach-O 文件(检查 magic 和/或使用 file/otool),然后解析 entitlements 和导入的 frameworks。 +- 将标准化视图持久化到关系型数据库,以避免在成千上万个 IPSWs 中线性增长: +- executables, operating_system_versions, entitlements, frameworks +- many-to-many: executable↔OS version, executable↔entitlement, executable↔framework + +示例查询:列出包含给定 executable 名称的所有 OS versions: +```sql +SELECT osv.version AS "Versions" +FROM device d +LEFT JOIN operating_system_version osv ON osv.device_id = d.id +LEFT JOIN executable_operating_system_version eosv ON eosv.operating_system_version_id = osv.id +LEFT JOIN executable e ON e.id = eosv.executable_id +WHERE e.name = "launchd"; +``` +数据库可移植性说明(如果你实现自己的索引器): +- 使用 ORM/抽象层(例如 SeaORM)以保持代码与数据库无关(SQLite/PostgreSQL)。 +- SQLite 仅在 INTEGER PRIMARY KEY 上需要 AUTOINCREMENT;如果在 Rust 中希望使用 i64 作为主键,可生成实体为 i32 然后转换类型,SQLite 在内部将 INTEGER 以 8 字节有符号整数存储。 + + +## Open-source tooling and references for entitlement hunting + +- 固件 挂载/下载: https://github.com/blacktop/ipsw +- Entitlement 数据库与参考: +- Jonathan Levin’s entitlement DB: https://newosxbook.com/ent.php +- entdb: https://github.com/ChiChou/entdb +- 大规模索引器(Rust,self-hosted Web UI + OpenAPI): https://github.com/synacktiv/appledb_rs +- Apple 头文件(用于结构体和常量): +- loader.h (Mach-O headers, load commands) +- cs_blobs.h (SuperBlob, GenericBlob, CodeDirectory) + +有关代码签名内部机制(Code Directory、special slots、DER entitlements)的更多信息,请参见: [macOS Code Signing](../../../macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-code-signing.md) + + +## References + +- [appledb_rs: a research support tool for Apple platforms](https://www.synacktiv.com/publications/appledbrs-un-outil-daide-a-la-recherche-sur-plateformes-apple.html) +- [synacktiv/appledb_rs](https://github.com/synacktiv/appledb_rs) +- [blacktop/ipsw](https://github.com/blacktop/ipsw) +- [Jonathan Levin’s entitlement DB](https://newosxbook.com/ent.php) +- [ChiChou/entdb](https://github.com/ChiChou/entdb) +- [XNU cs_blobs.h](https://github.com/apple-oss-distributions/xnu/blob/main/osfmk/kern/cs_blobs.h) +- [XNU mach-o/loader.h](https://github.com/apple-oss-distributions/xnu/blob/main/EXTERNAL_HEADERS/mach-o/loader.h) +- [SQLite Datatypes](https://sqlite.org/datatype3.html) + +{{#include ../../../banners/hacktricks-training.md}} diff --git a/src/macos-hardening/macos-security-and-privilege-escalation/macos-files-folders-and-binaries/universal-binaries-and-mach-o-format.md b/src/macos-hardening/macos-security-and-privilege-escalation/macos-files-folders-and-binaries/universal-binaries-and-mach-o-format.md index 06f225e06..d10519445 100644 --- a/src/macos-hardening/macos-security-and-privilege-escalation/macos-files-folders-and-binaries/universal-binaries-and-mach-o-format.md +++ b/src/macos-hardening/macos-security-and-privilege-escalation/macos-files-folders-and-binaries/universal-binaries-and-mach-o-format.md @@ -1,43 +1,43 @@ -# macOS Universal binaries & Mach-O Format +# macOS 通用二进制 & Mach-O 格式 {{#include ../../../banners/hacktricks-training.md}} ## 基本信息 -Mac OS 二进制文件通常被编译为 **universal binaries**。一个 **universal binary** 可以 **在同一个文件中支持多个架构**。 +Mac OS 二进制通常被编译为 **universal binaries**。一个 **universal binary** 可以在同一文件中 **支持多个架构**。 -这些二进制文件遵循 **Mach-O 结构**,基本由以下部分组成: +这些二进制遵循 **Mach-O 结构**,基本由以下部分组成: -- 头部 -- 加载命令 -- 数据 +- Header +- Load Commands +- Data ![https://alexdremov.me/content/images/2022/10/6XLCD.gif](<../../../images/image (470).png>) ## Fat Header -使用以下命令搜索文件: `mdfind fat.h | grep -i mach-o | grep -E "fat.h$"` +使用以下命令搜索文件:`mdfind fat.h | grep -i mach-o | grep -E "fat.h$"`
#define FAT_MAGIC	0xcafebabe
 #define FAT_CIGAM	0xbebafeca	/* NXSwapLong(FAT_MAGIC) */
 
 struct fat_header {
-	uint32_t	magic;		/* FAT_MAGIC 或 FAT_MAGIC_64 */
-	uint32_t	nfat_arch;	/* 后续结构的数量 */
+	uint32_t	magic;		/* FAT_MAGIC or FAT_MAGIC_64 */
+	uint32_t	nfat_arch;	/* number of structs that follow */
 };
 
 struct fat_arch {
-cpu_type_t	cputype;	/* cpu 说明符 (int) */
-cpu_subtype_t	cpusubtype;	/* 机器说明符 (int) */
-uint32_t	offset;		/* 文件偏移到此目标文件 */
-uint32_t	size;		/* 此目标文件的大小 */
-uint32_t	align;		/* 以 2 的幂为单位的对齐 */
+cpu_type_t	cputype;	/* cpu specifier (int) */
+cpu_subtype_t	cpusubtype;	/* machine specifier (int) */
+uint32_t	offset;		/* file offset to this object file */
+uint32_t	size;		/* size of this object file */
+uint32_t	align;		/* alignment as a power of 2 */
 };
 
-头部包含 **magic** 字节,后面是文件 **包含** 的 **archs** 的 **数量** (`nfat_arch`),每个架构将有一个 `fat_arch` 结构。 +该 header 包含 **magic** 字节,后跟文件包含的 **架构数量** (`nfat_arch`),每个架构都会有一个 `fat_arch` 结构。 -使用以下命令检查: +检查示例:
% file /bin/ls
 /bin/ls: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64e:Mach-O 64-bit executable arm64e]
@@ -68,11 +68,11 @@ capabilities PTR_AUTH_VERSION USERSPACE 0
 
 
-正如你所想,通常为 2 个架构编译的 universal binary **会使文件大小翻倍**,而为 1 个架构编译的文件则不会。 +正如你可能想到的,通常为 2 个架构编译的 universal binary 的大小会是只为 1 个架构编译的 **两倍**。 ## **Mach-O Header** -头部包含有关文件的基本信息,例如用于识别它为 Mach-O 文件的 magic 字节和有关目标架构的信息。你可以在以下路径找到它: `mdfind loader.h | grep -i mach-o | grep -E "loader.h$"` +该 header 包含关于文件的基本信息,例如用于识别为 Mach-O 文件的 magic 字节以及目标架构的信息。你可以在以下位置找到它:`mdfind loader.h | grep -i mach-o | grep -E "loader.h$"` ```c #define MH_MAGIC 0xfeedface /* the mach magic number */ #define MH_CIGAM 0xcefaedfe /* NXSwapInt(MH_MAGIC) */ @@ -101,17 +101,17 @@ uint32_t reserved; /* reserved */ ``` ### Mach-O 文件类型 -有不同的文件类型,可以在[**源代码中找到定义,例如这里**](https://opensource.apple.com/source/xnu/xnu-2050.18.24/EXTERNAL_HEADERS/mach-o/loader.h)。最重要的类型有: +存在不同的文件类型,你可以在 [**source code for example here**](https://opensource.apple.com/source/xnu/xnu-2050.18.24/EXTERNAL_HEADERS/mach-o/loader.h) 中找到它们的定义。最重要的有: -- `MH_OBJECT`: 可重定位目标文件(编译的中间产品,尚未成为可执行文件)。 +- `MH_OBJECT`: 可重定位目标文件(编译的中间产物,尚非可执行文件)。 - `MH_EXECUTE`: 可执行文件。 -- `MH_FVMLIB`: 固定虚拟机库文件。 -- `MH_CORE`: 代码转储 -- `MH_PRELOAD`: 预加载的可执行文件(在 XNU 中不再支持) -- `MH_DYLIB`: 动态库 -- `MH_DYLINKER`: 动态链接器 -- `MH_BUNDLE`: “插件文件”。使用 gcc 的 -bundle 生成,并由 `NSBundle` 或 `dlopen` 显式加载。 -- `MH_DYSM`: 伴随的 `.dSym` 文件(用于调试的符号文件)。 +- `MH_FVMLIB`: 固定 VM 库文件。 +- `MH_CORE`: 代码转储。 +- `MH_PRELOAD`: 预加载的可执行文件(XNU 不再支持)。 +- `MH_DYLIB`: 动态库。 +- `MH_DYLINKER`: 动态链接器。 +- `MH_BUNDLE`: "插件文件"。使用 gcc 的 `-bundle` 生成,并由 `NSBundle` 或 `dlopen` 显式加载。 +- `MH_DYSM`: 配套的 `.dSym` 文件(包含调试符号)。 - `MH_KEXT_BUNDLE`: 内核扩展。 ```bash # Checking the mac header of a binary @@ -120,54 +120,54 @@ Mach header magic cputype cpusubtype caps filetype ncmds sizeofcmds flags MH_MAGIC_64 ARM64 E USR00 EXECUTE 19 1728 NOUNDEFS DYLDLINK TWOLEVEL PIE ``` -或使用 [Mach-O View](https://sourceforge.net/projects/machoview/): +或者使用 [Mach-O View](https://sourceforge.net/projects/machoview/):
## **Mach-O 标志** -源代码还定义了几个用于加载库的标志: +源代码还定义了若干对加载库有用的标志: -- `MH_NOUNDEFS`:没有未定义的引用(完全链接) -- `MH_DYLDLINK`:Dyld 链接 -- `MH_PREBOUND`:动态引用预绑定。 -- `MH_SPLIT_SEGS`:文件分割 r/o 和 r/w 段。 -- `MH_WEAK_DEFINES`:二进制文件具有弱定义符号 -- `MH_BINDS_TO_WEAK`:二进制文件使用弱符号 -- `MH_ALLOW_STACK_EXECUTION`:使堆栈可执行 -- `MH_NO_REEXPORTED_DYLIBS`:库没有 LC_REEXPORT 命令 -- `MH_PIE`:位置无关可执行文件 -- `MH_HAS_TLV_DESCRIPTORS`:有一个包含线程局部变量的部分 -- `MH_NO_HEAP_EXECUTION`:堆/数据页面不执行 -- `MH_HAS_OBJC`:二进制文件具有 oBject-C 部分 -- `MH_SIM_SUPPORT`:模拟器支持 -- `MH_DYLIB_IN_CACHE`:用于共享库缓存中的 dylibs/frameworks。 +- `MH_NOUNDEFS`: 没有未定义引用(完全链接) +- `MH_DYLDLINK`: Dyld 链接 +- `MH_PREBOUND`: 动态引用预绑定 +- `MH_SPLIT_SEGS`: 文件将只读与读写段分离 +- `MH_WEAK_DEFINES`: 二进制包含弱定义符号 +- `MH_BINDS_TO_WEAK`: 二进制使用弱符号 +- `MH_ALLOW_STACK_EXECUTION`: 使栈可执行 +- `MH_NO_REEXPORTED_DYLIBS`: 库不包含 LC_REEXPORT 命令 +- `MH_PIE`: 位置无关可执行(PIE) +- `MH_HAS_TLV_DESCRIPTORS`: 包含线程局部变量(TLV)段 +- `MH_NO_HEAP_EXECUTION`: 堆/数据页不可执行 +- `MH_HAS_OBJC`: 二进制包含 Objective-C 段 +- `MH_SIM_SUPPORT`: 模拟器支持 +- `MH_DYLIB_IN_CACHE`: 用于位于共享库缓存中的 dylibs/frameworks ## **Mach-O 加载命令** -**文件在内存中的布局**在这里指定,详细说明了 **符号表的位置**、执行开始时主线程的上下文以及所需的 **共享库**。向动态加载器 **(dyld)** 提供了有关二进制文件加载到内存中的过程的指令。 +这里指定了文件在内存中的布局,说明了符号表的位置、执行开始时主线程的上下文以及所需的共享库。还向动态加载器(dyld)提供了如何将二进制加载到内存的指示。 -使用 **load_command** 结构,该结构在提到的 **`loader.h`** 中定义: +该文件使用在提到的 `loader.h` 中定义的 **load_command** 结构: ```objectivec struct load_command { uint32_t cmd; /* type of load command */ uint32_t cmdsize; /* total size of command in bytes */ }; ``` -有大约 **50 种不同类型的加载命令**,系统以不同方式处理它们。最常见的有: `LC_SEGMENT_64`、`LC_LOAD_DYLINKER`、`LC_MAIN`、`LC_LOAD_DYLIB` 和 `LC_CODE_SIGNATURE`。 +有大约 **50 种不同类型的 load commands**,系统会以不同方式处理。最常见的有:`LC_SEGMENT_64`、`LC_LOAD_DYLINKER`、`LC_MAIN`、`LC_LOAD_DYLIB` 和 `LC_CODE_SIGNATURE`。 ### **LC_SEGMENT/LC_SEGMENT_64** > [!TIP] -> 基本上,这种类型的加载命令定义了 **如何加载 \_\_TEXT**(可执行代码)**和 \_\_DATA**(进程数据)**段**,根据二进制文件执行时在数据部分中指示的 **偏移量**。 +> 基本上,这种类型的加载命令定义了在二进制被执行时**如何根据 Data 部分中指示的偏移量加载 \_\_TEXT**(可执行代码)**和 \_\_DATA**(进程数据)**段**。 -这些命令 **定义了段**,在执行进程时被 **映射** 到 **虚拟内存空间** 中。 +这些命令**定义了段(segments)**,在进程执行时会被**映射(mapped)**到进程的**虚拟内存空间**中。 -有 **不同类型** 的段,例如 **\_\_TEXT** 段,它包含程序的可执行代码,以及 **\_\_DATA** 段,它包含进程使用的数据。这些 **段位于 Mach-O 文件的数据部分** 中。 +存在不同类型的段,例如包含程序可执行代码的 **\_\_TEXT** 段,以及包含进程使用数据的 **\_\_DATA** 段。这些**段位于 Mach-O 文件的数据节**中。 -**每个段** 可以进一步 **划分** 为多个 **节**。**加载命令结构** 包含关于 **这些节** 在各自段中的 **信息**。 +**每个段**还可以进一步**划分为多个节(sections)**。load command 的结构包含关于该段中**这些节**的信息。 -在头部,首先找到 **段头**: +在头部首先可以找到**段头(segment header)**:
struct segment_command_64 { /* for 64-bit architectures */
 uint32_t	cmd;		/* LC_SEGMENT_64 */
@@ -184,11 +184,11 @@ int32_t		initprot;	/* initial VM protection */
 };
 
-段头的示例: +Example of segment header:
-该头部定义了 **其后出现的节头的数量**: +该头部定义了其后出现的**节头数量**: ```c struct section_64 { /* for 64-bit architectures */ char sectname[16]; /* name of this section */ @@ -205,62 +205,62 @@ uint32_t reserved2; /* reserved (for count or sizeof) */ uint32_t reserved3; /* reserved */ }; ``` -示例 **节标题**: +关于 **节标题** 的示例:
-如果你 **添加** **节偏移** (0x37DC) + **架构开始的偏移**,在这种情况下 `0x18000` --> `0x37DC + 0x18000 = 0x1B7DC` +如果你把 **section 偏移量** (0x37DC) 与 **arch 起始处的偏移量** 相加,在本例中 `0x18000` --> `0x37DC + 0x18000 = 0x1B7DC`
-也可以通过 **命令行** 获取 **头信息**: +还可以通过 **命令行** 获取 **头部信息**: ```bash otool -lv /bin/ls ``` -常见的由此命令加载的段: +Common segments loaded by this cmd: -- **`__PAGEZERO`:** 它指示内核**映射** **地址零**,以便**无法读取、写入或执行**。结构中的maxprot和minprot变量设置为零,以指示此页面上**没有读写执行权限**。 -- 此分配对于**缓解NULL指针解引用漏洞**非常重要。这是因为XNU强制实施一个硬页面零,确保内存的第一页(仅第一页)不可访问(在i386中除外)。一个二进制文件可以通过制作一个小的\_\_PAGEZERO(使用`-pagezero_size`)来满足这些要求,以覆盖前4k,并使其余的32位内存在用户模式和内核模式下可访问。 -- **`__TEXT`**:包含**可执行** **代码**,具有**读取**和**执行**权限(不可写)。此段的常见部分: -- `__text`:编译的二进制代码 -- `__const`:常量数据(只读) -- `__ [c/u/os_log]string`:C、Unicode或os日志字符串常量 -- `__stubs`和`__stubs_helper`:在动态库加载过程中涉及 -- `__unwind_info`:堆栈展开数据。 -- 请注意,所有这些内容都是签名的,但也被标记为可执行(为不一定需要此权限的部分(如专用字符串部分)创建更多的利用选项)。 -- **`__DATA`**:包含**可读**和**可写**的数据(不可执行)。 +- **`__PAGEZERO`:** 它指示内核 **映射** **地址零**,因此**无法被读取、写入或执行**。结构中的 maxprot 和 minprot 变量被设置为零,以表示该页**没有读写执行权限**。 +- 这种分配对于**缓解 NULL 指针解引用 漏洞**非常重要。因为 XNU 强制实施一个硬性的 page zero,确保内存的第一页(仅第一页)不可访问(i386 除外)。一个二进制可以通过构造一个小的 \_\_PAGEZERO(使用 `-pagezero_size`)以覆盖前 4k,并使剩余的 32 位内存在用户态和内核态都可访问,从而满足这一要求。 +- **`__TEXT`**: 包含具有**读取**和**执行**权限的**可执行****代码**(不可写)。此段的常见节: +- `__text`: 已编译的二进制代码 +- `__const`: 常量数据(只读) +- `__[c/u/os_log]string`: C、Unicode 或 os 日志字符串常量 +- `__stubs` and `__stubs_helper`: 在动态库加载过程中参与 +- `__unwind_info`: 栈展开(unwind)数据 +- 注意所有这些内容都已签名且被标记为可执行(这为某些并不一定需要此权限的节(例如专用于字符串的节)提供了更多利用途径)。 +- **`__DATA`**: 包含**可读**且**可写**的数据(不可执行)。 - `__got:` 全局偏移表 -- `__nl_symbol_ptr`:非惰性(加载时绑定)符号指针 -- `__la_symbol_ptr`:惰性(使用时绑定)符号指针 -- `__const`:应为只读数据(实际上不是) -- `__cfstring`:CoreFoundation字符串 -- `__data`:全局变量(已初始化) -- `__bss`:静态变量(未初始化) -- `__objc_*`(\_\_objc_classlist,\_\_objc_protolist等):由Objective-C运行时使用的信息 -- **`__DATA_CONST`**:\_\_DATA.\_\_const不保证是常量(写权限),其他指针和GOT也是如此。此部分使用`mprotect`使`__const`、一些初始化程序和GOT表(解析后)**只读**。 -- **`__LINKEDIT`**:包含链接器(dyld)所需的信息,例如符号、字符串和重定位表条目。它是一个通用容器,包含不在`__TEXT`或`__DATA`中的内容,其内容在其他加载命令中描述。 -- dyld信息:重定位、非惰性/惰性/弱绑定操作码和导出信息 -- 函数开始:函数的起始地址表 -- 代码中的数据:\_\_text中的数据岛 -- 符号表:二进制中的符号 -- 间接符号表:指针/存根符号 -- 字符串表 -- 代码签名 -- **`__OBJC`**:包含由Objective-C运行时使用的信息。尽管这些信息也可能在\_\_DATA段中找到,在各种\_\_objc\_\*部分中。 -- **`__RESTRICT`**:一个没有内容的段,只有一个名为**`__restrict`**(也为空)的单一部分,确保在运行二进制文件时,它将忽略DYLD环境变量。 +- `__nl_symbol_ptr`: 非懒(在加载时绑定)符号指针 +- `__la_symbol_ptr`: 懒(按需绑定)符号指针 +- `__const`: 应为只读数据(但实际上并非如此) +- `__cfstring`: CoreFoundation 字符串 +- `__data`: 已初始化的全局变量 +- `__bss`: 未初始化的静态变量 +- `__objc_*` (\_\_objc_classlist, \_\_objc_protolist, etc): 由 Objective-C 运行时使用的信息 +- **`__DATA_CONST`**: \_\_DATA.\_\_const 并不保证是常量(存在写权限),其他指针和 GOT 也一样。此段使用 `mprotect` 将 `__const`、一些初始化器和 GOT 表(解析后)设置为**只读**。 +- **`__LINKEDIT`**: 包含链路器(dyld)所需的信息,例如符号、字符串和重定位表条目。它是一个通用容器,用于存放既不在 `__TEXT` 也不在 `__DATA` 中的内容,其内容在其它加载命令中有描述。 +- dyld 信息:Rebase、Non-lazy/lazy/weak binding opcodes 和导出信息 +- Functions starts:函数起始地址表 +- Data In Code:\_\_text 中的数据岛 +- SYmbol Table:二进制中的符号 +- Indirect Symbol Table:指针/存根符号 +- String Table:字符串表 +- Code Signature:代码签名 +- **`__OBJC`**: 包含由 Objective-C 运行时使用的信息。尽管这些信息也可能出现在 \_\_DATA 段内的各种 \_\_objc\_\* 节中。 +- **`__RESTRICT`**: 一个没有内容的段,只有一个名为 **`__restrict`**(同样为空)的节,确保在运行二进制时会忽略 DYLD 环境变量。 -正如在代码中所看到的,**段也支持标志**(尽管它们并不常用): +As it was possible to see in the code, **segments also support flags** (although they aren't used very much): -- `SG_HIGHVM`:仅核心(未使用) -- `SG_FVMLIB`:未使用 -- `SG_NORELOC`:段没有重定位 -- `SG_PROTECTED_VERSION_1`:加密。例如,Finder用于加密文本`__TEXT`段。 +- `SG_HIGHVM`: 仅限内核(未使用) +- `SG_FVMLIB`: 未使用 +- `SG_NORELOC`: 段没有重定位 +- `SG_PROTECTED_VERSION_1`: 加密。例如 Finder 使用它来加密 `__TEXT` 段的文本。 ### **`LC_UNIXTHREAD/LC_MAIN`** -**`LC_MAIN`**包含**entryoff属性**中的入口点。在加载时,**dyld**简单地**将**此值添加到(内存中的)**二进制文件基址**,然后**跳转**到此指令以开始执行二进制代码。 +**`LC_MAIN`** 包含入口点于 **entryoff 属性**。在加载时,**dyld** 简单地**将该值添加到**(二进制在内存中的)**基地址**,然后**跳转**到该指令以开始执行二进制的代码。 -**`LC_UNIXTHREAD`**包含启动主线程时寄存器必须具有的值。这已经被弃用,但**`dyld`**仍在使用它。可以通过以下方式查看寄存器设置的值: +**`LC_UNIXTHREAD`** 包含启动主线程时寄存器应具有的值。它已被弃用,但 **`dyld`** 仍在使用它。可以通过下面的方法查看由此设置的寄存器值: ```bash otool -l /usr/lib/dyld [...] @@ -286,34 +286,39 @@ cpsr 0x00000000 ``` ### **`LC_CODE_SIGNATURE`** -包含关于 **Macho-O 文件的代码签名** 的信息。它仅包含一个 **偏移量**,指向 **签名 blob**。这通常位于文件的最末尾。\ -然而,您可以在 [**这篇博客文章**](https://davedelong.com/blog/2018/01/10/reading-your-own_entitlements/) 和这个 [**gists**](https://gist.github.com/carlospolop/ef26f8eb9fafd4bc22e69e1a32b81da4) 中找到一些关于此部分的信息。 +{{#ref}} +../../../generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/mach-o-entitlements-and-ipsw-indexing.md +{{#endref}} + + +包含有关 Mach-O 文件**代码签名**的信息。它仅包含一个**偏移量(offset)**,指向**签名 blob**。该偏移通常位于文件的末尾。\ +你可以在[**this blog post**](https://davedelong.com/blog/2018/01/10/reading-your-own-entitlements/) 和 [**gists**](https://gist.github.com/carlospolop/ef26f8eb9fafd4bc22e69e1a32b81da4) 中找到关于该段的一些信息。 ### **`LC_ENCRYPTION_INFO[_64]`** -支持二进制加密。然而,当然,如果攻击者设法破坏了进程,他将能够以未加密的方式转储内存。 +支持二进制加密。不过,如果攻击者成功攻陷进程,当然可以将内存以未加密形式 dump 出来。 ### **`LC_LOAD_DYLINKER`** -包含 **动态链接器可执行文件的路径**,该文件将共享库映射到进程地址空间。**值始终设置为 `/usr/lib/dyld`**。重要的是要注意,在 macOS 中,dylib 映射发生在 **用户模式**,而不是内核模式。 +包含将共享库映射到进程地址空间的动态链接器可执行文件的路径。该值**始终设置为 `/usr/lib/dyld`**。需要注意的是,在 macOS 中,dylib 的映射发生在**user mode**,而不是内核态(kernel mode)。 ### **`LC_IDENT`** -过时,但当配置为在崩溃时生成转储时,会创建一个 Mach-O 核心转储,并在 `LC_IDENT` 命令中设置内核版本。 +已废弃,但当配置为在 panic 时生成转储时,会创建 Mach-O core dump,并且内核版本会在 `LC_IDENT` 命令中设置。 ### **`LC_UUID`** -随机 UUID。它对任何直接的事情都很有用,但 XNU 将其与其他进程信息一起缓存。它可以在崩溃报告中使用。 +随机 UUID。本身直接用途有限,但 XNU 会将其与其他进程信息一起缓存,可用于崩溃报告。 ### **`LC_DYLD_ENVIRONMENT`** -允许在进程执行之前向 dyld 指示环境变量。这可能非常危险,因为它可能允许在进程内部执行任意代码,因此此加载命令仅在使用 `#define SUPPORT_LC_DYLD_ENVIRONMENT` 构建的 dyld 中使用,并进一步限制处理仅限于形式为 `DYLD_..._PATH` 的变量,指定加载路径。 +允许在进程执行前向 dyld 指定环境变量。这可能非常危险,因为它可能允许在进程内执行任意代码,因此该 load command 仅在 dyld 使用 `#define SUPPORT_LC_DYLD_ENVIRONMENT` 构建时使用,并且进一步将处理限制为形如 `DYLD_..._PATH` 的变量(用于指定加载路径)。 ### **`LC_LOAD_DYLIB`** -此加载命令描述了一个 **动态** **库** 依赖关系,**指示** **加载器** (dyld) **加载和链接该库**。每个 Mach-O 二进制文件所需的库都有一个 `LC_LOAD_DYLIB` 加载命令。 +该 load command 描述了一个**动态库(dynamic library)**依赖,指示 loader(dyld)去加载并链接该库。对于 Mach-O 二进制所需的每个库,都会有一个 `LC_LOAD_DYLIB` load command。 -- 此加载命令是 **`dylib_command`** 类型的结构(其中包含一个描述实际依赖动态库的 struct dylib): +- 该 load command 的结构类型为 **`dylib_command`**(其中包含一个 struct dylib,描述实际的依赖动态库): ```objectivec struct dylib_command { uint32_t cmd; /* LC_LOAD_{,WEAK_}DYLIB */ @@ -330,7 +335,7 @@ uint32_t compatibility_version; /* library's compatibility vers number*/ ``` ![](<../../../images/image (486).png>) -您还可以通过命令行获取此信息: +你也可以通过 cli 使用以下命令获取这些信息: ```bash otool -L /bin/ls /bin/ls: @@ -338,53 +343,53 @@ otool -L /bin/ls /usr/lib/libncurses.5.4.dylib (compatibility version 5.4.0, current version 5.4.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1319.0.0) ``` -一些潜在的与恶意软件相关的库包括: +一些可能与 malware 相关的库有: -- **DiskArbitration**: 监控 USB 驱动器 +- **DiskArbitration**:监控 USB 驱动器 - **AVFoundation:** 捕获音频和视频 -- **CoreWLAN**: Wifi 扫描。 +- **CoreWLAN**:Wi‑Fi 扫描。 -> [!NOTE] -> Mach-O 二进制文件可以包含一个或 **多个** **构造函数**,这些构造函数将在 **LC_MAIN** 指定的地址 **之前** 被 **执行**。\ -> 任何构造函数的偏移量保存在 **\_\_mod_init_func** 段的 **\_\_DATA_CONST** 部分中。 +> [!TIP] +> 一个 Mach-O 二进制可以包含一个或多个 **构造函数**,这些函数会在 **LC_MAIN** 指定的地址之前被 **执行**。\ +> 任何构造函数的偏移量保存在 **__mod_init_func** section 的 **__DATA_CONST** segment。 ## **Mach-O 数据** -文件的核心是数据区域,由加载命令区域中定义的多个段组成。**每个段中可以包含多种数据部分**,每个部分 **保存特定类型的代码或数据**。 +在文件的核心是数据区域,该区域由 load-commands 区域定义的多个段组成。**每个段中可以包含多种数据节**,每个节都**包含特定类型的代码或数据**。 > [!TIP] -> 数据基本上是包含所有由加载命令 **LC_SEGMENTS_64** 加载的 **信息** 的部分。 +> 数据基本上是由 load commands **LC_SEGMENTS_64** 加载的包含所有**信息**的部分 ![https://www.oreilly.com/api/v2/epubs/9781785883378/files/graphics/B05055_02_38.jpg](<../../../images/image (507) (3).png>) 这包括: -- **函数表:** 包含有关程序函数的信息。 -- **符号表**: 包含有关二进制文件使用的外部函数的信息 -- 还可能包含内部函数、变量名称等。 +- **函数表:** 保存关于程序函数的信息。 +- **符号表:** 包含二进制使用的外部函数的信息 +- 它还可以包含内部函数、变量名等信息。 -要检查它,您可以使用 [**Mach-O View**](https://sourceforge.net/projects/machoview/) 工具: +要检查它,你可以使用 [**Mach-O View**](https://sourceforge.net/projects/machoview/) 工具:
-或者从命令行: +或在命令行中: ```bash size -m /bin/ls ``` -## Objetive-C 常见部分 +## Objetive-C 常见节 在 `__TEXT` 段 (r-x): -- `__objc_classname`: 类名 (字符串) -- `__objc_methname`: 方法名 (字符串) -- `__objc_methtype`: 方法类型 (字符串) +- `__objc_classname`: 类名(字符串) +- `__objc_methname`: 方法名(字符串) +- `__objc_methtype`: 方法类型(字符串) 在 `__DATA` 段 (rw-): -- `__objc_classlist`: 所有 Objective-C 类的指针 -- `__objc_nlclslist`: 非懒加载 Objective-C 类的指针 -- `__objc_catlist`: 类别的指针 -- `__objc_nlcatlist`: 非懒加载类别的指针 +- `__objc_classlist`: 指向所有 Objetive-C 类的指针 +- `__objc_nlclslist`: 指向非延迟 Objective-C 类的指针 +- `__objc_catlist`: 指向类别的指针 +- `__objc_nlcatlist`: 指向非延迟类别的指针 - `__objc_protolist`: 协议列表 - `__objc_const`: 常量数据 - `__objc_imageinfo`, `__objc_selrefs`, `objc__protorefs`... diff --git a/src/macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-code-signing.md b/src/macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-code-signing.md index 7e79abe7b..131d7ebad 100644 --- a/src/macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-code-signing.md +++ b/src/macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-code-signing.md @@ -4,12 +4,17 @@ ## 基本信息 -Mach-o 二进制文件包含一个称为 **`LC_CODE_SIGNATURE`** 的加载命令,指示二进制文件内部签名的 **偏移量** 和 **大小**。实际上,使用 GUI 工具 MachOView,可以在二进制文件的末尾找到一个名为 **Code Signature** 的部分,其中包含这些信息: +{{#ref}} +../../../generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/mach-o-entitlements-and-ipsw-indexing.md +{{#endref}} + + +Mach-o 二进制包含一个名为 **`LC_CODE_SIGNATURE`** 的 load command,指示二进制中签名的 **offset** 和 **size**。事实上,使用 GUI 工具 MachOView,可以在二进制末尾找到一个名为 **Code Signature** 的区段,其中包含这些信息:
-代码签名的魔术头是 **`0xFADE0CC0`**。然后你会得到一些信息,例如 superBlob 的长度和 blob 的数量。\ -可以在 [源代码这里](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/osfmk/kern/cs_blobs.h#L276) 找到这些信息: +Code Signature 的 magic header 是 **`0xFADE0CC0`**。然后你会看到诸如 length 和 superBlob 中包含它们的 blobs 数量等信息。\ +可以在 [source code here](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/osfmk/kern/cs_blobs.h#L276) 中找到这些信息: ```c /* * Structure of an embedded-signature SuperBlob @@ -38,14 +43,14 @@ char data[]; } CS_GenericBlob __attribute__ ((aligned(1))); ``` -常见的 blob 包含代码目录、要求和权限以及加密消息语法 (CMS)。\ -此外,请注意 blob 中编码的数据是以 **大端字节序** 编码的。 +常见的 blobs 包括 Code Directory、Requirements 和 Entitlements,以及 Cryptographic Message Syntax (CMS).\ +此外,请注意 blobs 中的数据是以 **Big Endian.** 编码的。 此外,签名可以从二进制文件中分离并存储在 `/var/db/DetachedSignatures`(iOS 使用)。 -## 代码目录 Blob +## Code Directory Blob -可以在代码中找到 [代码目录 Blob 的声明](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/osfmk/kern/cs_blobs.h#L104): +可以在代码中找到 [Code Directory Blob in the code](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/osfmk/kern/cs_blobs.h#L104): ```c typedef struct __CodeDirectory { uint32_t magic; /* magic number (CSMAGIC_CODEDIRECTORY) */ @@ -101,12 +106,12 @@ char end_withLinkage[0]; } CS_CodeDirectory __attribute__ ((aligned(1))); ``` -注意,这个结构有不同的版本,旧版本可能包含较少的信息。 +注意该 struct 有不同版本,旧版本可能包含较少信息。 -## 签名代码页面 +## 签名代码页 -对整个二进制文件进行哈希计算效率低下,如果它仅部分加载到内存中甚至是无用的。因此,代码签名实际上是一个哈希的哈希,其中每个二进制页面都是单独哈希的。\ -实际上,在之前的 **Code Directory** 代码中,您可以看到 **页面大小在其字段中被指定**。此外,如果二进制文件的大小不是页面大小的倍数,字段 **CodeLimit** 指定了签名的结束位置。 +对整个二进制文件进行哈希既低效,在只部分加载到内存时甚至无用。因此,代码签名实际上是哈希的哈希,每个二进制页面分别进行哈希。\ +实际上,在前面的 **Code Directory** 代码中,你可以看到 **页面大小在其字段之一中指定**。此外,如果二进制的大小不是页面大小的整数倍,字段 **CodeLimit** 指定了签名的结束位置。 ```bash # Get all hashes of /bin/ps codesign -d -vvvvvv /bin/ps @@ -142,27 +147,27 @@ dd if=$BINARY of=/tmp/`basename $BINARY`.page.$i bs=$PAGESIZE skip=$i count=1 done openssl sha256 /tmp/*.page.* ``` -## Entitlements Blob +## 权限 blob -请注意,应用程序可能还包含一个**entitlement blob**,其中定义了所有的权限。此外,一些iOS二进制文件可能在特殊槽-7中具体定义其权限(而不是在-5权限特殊槽中)。 +注意,应用程序可能还包含一个定义了所有权限的**权限 blob**。此外,一些 iOS 二进制文件可能会把它们的权限放在特殊槽位 -7(而不是常见的 -5 entitlements 特殊槽位)。 -## Special Slots +## 特殊槽位 -MacOS应用程序并不具备执行所需的所有内容,而是还使用**外部资源**(通常在应用程序的**bundle**内)。因此,二进制文件中有一些槽将包含一些有趣的外部资源的哈希,以检查它们是否被修改。 +MacOS 应用并非把执行所需的所有内容都包含在二进制内,它们也使用 **external resources**(通常位于应用的 **bundle** 内)。因此,二进制中存在一些槽位,用于存放某些重要外部资源的哈希,以便验证它们未被修改。 -实际上,可以在代码目录结构中看到一个名为**`nSpecialSlots`**的参数,指示特殊槽的数量。没有特殊槽0,最常见的槽(从-1到-6)是: +事实上,可以在 Code Directory 结构体中看到一个名为 **`nSpecialSlots`** 的参数,用来指示特殊槽位的数量。注意没有特殊槽位 0,最常见的槽位是(从 -1 到 -6): -- `info.plist`的哈希(或在`__TEXT.__info__plist`中的哈希)。 -- 需求的哈希 -- 资源目录的哈希(在bundle内的`_CodeSignature/CodeResources`文件的哈希)。 +- `info.plist` 的哈希(或位于 `__TEXT.__info__plist` 中的那个)。 +- Requirements 的哈希 +- 资源目录的哈希(位于 bundle 内的 `_CodeSignature/CodeResources` 文件的哈希)。 - 应用程序特定(未使用) - 权限的哈希 -- 仅DMG代码签名 -- DER权限 +- 仅针对 DMG 的代码签名 +- DER 权限 -## Code Signing Flags +## 代码签名标志 -每个进程都有一个相关的位掩码,称为`status`,由内核启动,其中一些可以被**代码签名**覆盖。这些可以包含在代码签名中的标志在[代码中定义](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/osfmk/kern/cs_blobs.h#L36): +每个进程都有一个关联的位掩码,称为 `status`,由内核设置,其中一些位可以被**代码签名**覆盖。这些可以包含在代码签名中的标志在代码中有定义: [defined in the code](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/osfmk/kern/cs_blobs.h#L36): ```c /* code signing attributes of a process */ #define CS_VALID 0x00000001 /* dynamically valid */ @@ -207,15 +212,15 @@ CS_RESTRICT | CS_ENFORCEMENT | CS_REQUIRE_LV | CS_RUNTIME | CS_LINKER_SIGNED) #define CS_ENTITLEMENT_FLAGS (CS_GET_TASK_ALLOW | CS_INSTALLER | CS_DATAVAULT_CONTROLLER | CS_NVRAM_UNRESTRICTED) ``` -注意,函数 [**exec_mach_imgact**](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/bsd/kern/kern_exec.c#L1420) 在启动执行时也可以动态添加 `CS_EXEC_*` 标志。 +注意函数 [**exec_mach_imgact**](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/bsd/kern/kern_exec.c#L1420) 在启动执行时也可以动态添加 `CS_EXEC_*` 标志。 ## 代码签名要求 -每个应用程序存储一些 **要求**,必须 **满足** 这些要求才能被执行。如果 **应用程序包含的要求未被应用程序满足**,则不会执行(因为它可能已被更改)。 +每个应用会存储一些必须**满足**的**要求**,以便能够被执行。如果应用包含的这些**要求**没有被满足,应用将不会被执行(因为它可能已被篡改)。 -二进制文件的要求使用 **特殊语法**,这是一个 **表达式** 的流,并使用 `0xfade0c00` 作为魔法编码为 blobs,其 **哈希存储在特殊代码槽中**。 +二进制的这些要求使用一种**特殊语法**,是由一系列**表达式**组成,并以 blob 的形式编码,使用 `0xfade0c00` 作为魔数,其**哈希存储在一个特殊的 code slot 中**。 -可以通过运行来查看二进制文件的要求: +可以通过运行以下命令查看二进制的要求: ```bash codesign -d -r- /bin/ls Executable=/bin/ls @@ -225,10 +230,10 @@ codesign -d -r- /Applications/Signal.app/ Executable=/Applications/Signal.app/Contents/MacOS/Signal designated => identifier "org.whispersystems.signal-desktop" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = U68MSDN6DR ``` -> [!NOTE] -> 注意这些签名可以检查诸如认证信息、TeamID、ID、权限以及许多其他数据。 +> [!TIP] +> 注意这些签名如何检查诸如证书信息、TeamID、IDs、entitlements 等多种数据。 -此外,可以使用 `csreq` 工具生成一些编译的要求: +此外,可以使用 `csreq` 工具生成一些已编译的 requirements: ```bash # Generate compiled requirements csreq -b /tmp/output.csreq -r='identifier "org.whispersystems.signal-desktop" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = U68MSDN6DR' @@ -240,20 +245,20 @@ od -A x -t x1 /tmp/output.csreq 0000020 00 00 00 21 6f 72 67 2e 77 68 69 73 70 65 72 73 [...] ``` -可以通过 `Security.framework` 中的一些 API 访问此信息并创建或修改要求,例如: +可以通过 `Security.framework` 的一些 API 访问这些信息并创建或修改要求,如: #### **检查有效性** -- **`Sec[Static]CodeCheckValidity`**: 根据要求检查 SecCodeRef 的有效性。 -- **`SecRequirementEvaluate`**: 在证书上下文中验证要求。 -- **`SecTaskValidateForRequirement`**: 验证正在运行的 SecTask 是否符合 `CFString` 要求。 +- **`Sec[Static]CodeCheckValidity`**:根据要求检查 SecCodeRef 的有效性。 +- **`SecRequirementEvaluate`**:在证书上下文中验证要求。 +- **`SecTaskValidateForRequirement`**:根据 `CFString` 要求验证正在运行的 SecTask。 #### **创建和管理代码要求** - **`SecRequirementCreateWithData`:** 从表示要求的二进制数据创建 `SecRequirementRef`。 - **`SecRequirementCreateWithString`:** 从要求的字符串表达式创建 `SecRequirementRef`。 - **`SecRequirementCopy[Data/String]`**: 检索 `SecRequirementRef` 的二进制数据表示。 -- **`SecRequirementCreateGroup`**: 为应用程序组成员资格创建要求。 +- **`SecRequirementCreateGroup`**: 为 app-group 成员资格创建要求 #### **访问代码签名信息** @@ -262,35 +267,35 @@ od -A x -t x1 /tmp/output.csreq #### **修改代码要求** -- **`SecCodeSignerCreate`**: 创建 `SecCodeSignerRef` 对象以执行代码签名操作。 -- **`SecCodeSignerSetRequirement`**: 为代码签名者设置在签名期间应用的新要求。 -- **`SecCodeSignerAddSignature`**: 将签名添加到使用指定签名者签名的代码中。 +- **`SecCodeSignerCreate`**: 创建用于执行代码签名操作的 `SecCodeSignerRef` 对象。 +- **`SecCodeSignerSetRequirement`**: 为签名器设置在签名期间应用的新要求。 +- **`SecCodeSignerAddSignature`**: 使用指定签名器向正在签名的代码添加签名。 #### **使用要求验证代码** - **`SecStaticCodeCheckValidity`**: 根据指定要求验证静态代码对象。 -#### **其他有用的 API** +#### **其他有用的 APIs** -- **`SecCodeCopy[Internal/Designated]Requirement`: 从 SecCodeRef 获取 SecRequirementRef** -- **`SecCodeCopyGuestWithAttributes`**: 创建一个基于特定属性的代码对象的 `SecCodeRef`,适用于沙箱。 +- **`SecCodeCopy[Internal/Designated]Requirement`: Get SecRequirementRef from SecCodeRef** +- **`SecCodeCopyGuestWithAttributes`**: 基于特定属性创建表示代码对象的 `SecCodeRef`,可用于沙箱化。 - **`SecCodeCopyPath`**: 检索与 `SecCodeRef` 关联的文件系统路径。 -- **`SecCodeCopySigningIdentifier`**: 从 `SecCodeRef` 获取签名标识符(例如,团队 ID)。 +- **`SecCodeCopySigningIdentifier`**: 从 `SecCodeRef` 获取签名标识符(例如 Team ID)。 - **`SecCodeGetTypeID`**: 返回 `SecCodeRef` 对象的类型标识符。 -- **`SecRequirementGetTypeID`**: 获取 `SecRequirementRef` 的 CFTypeID。 +- **`SecRequirementGetTypeID`**: 获取 `SecRequirementRef` 的 CFTypeID #### **代码签名标志和常量** -- **`kSecCSDefaultFlags`**: 在许多 Security.framework 函数中用于代码签名操作的默认标志。 +- **`kSecCSDefaultFlags`**: 在许多 `Security.framework` 函数中用于代码签名操作的默认标志。 - **`kSecCSSigningInformation`**: 用于指定应检索签名信息的标志。 -## 代码签名强制执行 +## 代码签名强制 -**内核**是在允许应用程序代码执行之前**检查代码签名**的。此外,能够在内存中写入和执行新代码的一种方法是滥用 JIT,如果 `mprotect` 被调用时带有 `MAP_JIT` 标志。请注意,应用程序需要特殊的权限才能做到这一点。 +内核负责在允许应用代码执行之前检查代码签名。此外,如果 `mprotect` 使用 `MAP_JIT` 标志被调用,滥用 JIT 是在内存中写入并执行新代码的一种方式。注意,应用需要特殊的 entitlement 才能这样做。 ## `cs_blobs` & `cs_blob` -[**cs_blob**](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/bsd/sys/ubc_internal.h#L106) 结构包含有关正在运行的进程的权限信息。 `csb_platform_binary` 还指示应用程序是否为平台二进制文件(操作系统在不同时间检查这一点,以应用安全机制,例如保护这些进程的任务端口的 SEND 权限)。 +[**cs_blob**](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/bsd/sys/ubc_internal.h#L106) 结构包含关于运行进程 entitlement 的信息。`csb_platform_binary` 还表明应用是否为 platform binary(操作系统在不同阶段检查该标志以应用安全机制,例如保护这些进程的任务端口的 SEND 权限)。 ```c struct cs_blob { struct cs_blob *csb_next; @@ -349,7 +354,7 @@ bool csb_csm_managed; #endif }; ``` -## 参考文献 +## 参考资料 - [**\*OS Internals Volume III**](https://newosxbook.com/home.html)