Translated ['src/generic-methodologies-and-resources/basic-forensic-meth

This commit is contained in:
Translator 2025-10-01 01:53:25 +00:00
parent 146d2beb0c
commit 2b14cbd281
5 changed files with 401 additions and 172 deletions

View File

@ -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)

View File

@ -1,4 +1,4 @@
# Truques Específicos de Software/Tipos de Arquivo
# Truques específicos para tipos de arquivo/software
{{#include ../../../banners/hacktricks-training.md}}
@ -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}}

View File

@ -0,0 +1,213 @@
# Extração de Entitlements de Mach-O & Indexação de IPSW
{{#include ../../../banners/hacktricks-training.md}}
## Visão geral
Esta página explica como extrair entitlements de binários Mach-O programaticamente percorrendo LC_CODE_SIGNATURE e analisando o code signing SuperBlob, e como escalar isso em firmwares IPSW da Apple montando e indexando seus conteúdos para busca/diff forense.
Se precisar de uma revisão sobre o formato Mach-O e code signing, veja também: macOS code signing and SuperBlob internals.
- Consulte os detalhes de macOS code signing (SuperBlob, Code Directory, special slots): [macOS Code Signing](../../../macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-code-signing.md)
- Consulte estruturas gerais do Mach-O / 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 no Mach-O: onde residem
Entitlements são armazenados dentro dos dados de code signature referenciados pelo load command LC_CODE_SIGNATURE e colocados no segmento __LINKEDIT. A assinatura é um CS_SuperBlob contendo múltiplos blobs (code directory, requirements, entitlements, CMS, etc.). O blob de entitlements é um CS_GenericBlob cujo dado é um Apple Binary Property List (bplist00) que mapeia chaves de entitlements para valores.
Key structures (from 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;
```
Constantes importantes:
- 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
Nota: Binários multi-arch (fat) contêm múltiplos Mach-O slices. Você deve escolher o slice da arquitetura que quer inspecionar e então percorrer seus load commands.
## Etapas de extração (genéricas, praticamente sem perda)
1) Analise o cabeçalho Mach-O; itere pelos registros load_command conforme ncmds.
2) Localize LC_CODE_SIGNATURE; leia linkedit_data_command.dataoff/datasize para mapear o Code Signing SuperBlob colocado em __LINKEDIT.
3) Valide CS_SuperBlob.magic == 0xfade0cc0; itere pelas count entradas de CS_BlobIndex.
4) Localize index.type == 0xfade7171 (embedded entitlements). Leia o CS_GenericBlob apontado e parseie seus dados como um plist binário Apple (bplist00) para chaves/valores de entitlements.
Notas de implementação:
- As estruturas de code signature usam campos big-endian; troque a ordem de bytes ao parsear em hosts little-endian.
- Os dados do GenericBlob de entitlements em si são um plist binário (tratado por bibliotecas padrão de plist).
- Alguns binários iOS podem conter DER entitlements; também alguns stores/slots diferem entre plataformas/versões. Verifique tanto os entitlements padrão quanto os DER conforme necessário.
- Para binários fat, use os fat headers (FAT_MAGIC/FAT_MAGIC_64) para localizar o slice e offset corretos antes de percorrer os Mach-O load commands.
## Esboço mínimo de parsing (Python)
O seguinte é um esboço compacto mostrando o fluxo de controle para encontrar e decodificar entitlements. Intencionalmente omite verificações robustas de limites e suporte completo a fat binaries por brevidade.
```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("<I", macho_bytes, 0)
is64 = magic in (0xfeedfacf,)
if is64:
ncmds = struct.unpack_from("<I", macho_bytes, 0x10)[0]
sizeofcmds = struct.unpack_from("<I", macho_bytes, 0x14)[0]
off = 0x20
else:
# 32-bit not shown
return None
code_sig_off = code_sig_size = None
for _ in range(ncmds):
cmd, cmdsize = struct.unpack_from("<II", macho_bytes, off)
if cmd == LC_CODE_SIGNATURE:
# struct linkedit_data_command is little-endian in file
_, _, dataoff, datasize = struct.unpack_from("<IIII", macho_bytes, off)
code_sig_off, code_sig_size = dataoff, datasize
off += cmdsize
if code_sig_off is None:
return None
blob = macho_bytes[code_sig_off: code_sig_off + code_sig_size]
if be32(blob, 0x0) != CSMAGIC_EMBEDDED_SIGNATURE:
return None
count = be32(blob, 0x8)
# iterate BlobIndex entries (8 bytes each after 12-byte header)
for i in range(count):
idx_off = 12 + i*8
btype = be32(blob, idx_off)
boff = be32(blob, idx_off+4)
if btype == CSMAGIC_EMBEDDED_ENTITLEMENTS:
# GenericBlob is big-endian header followed by bplist
glen = be32(blob, boff+4)
data = blob[boff+8: boff+glen]
return plistlib.loads(data)
return None
```
Dicas de uso:
- Para lidar com fat binaries, primeiro leia struct fat_header/fat_arch, escolha o slice de arquitetura desejado, então passe o subrange para parse_entitlements.
- No macOS você pode validar os resultados com: codesign -d --entitlements :- /path/to/binary
## Exemplos de descobertas
Binários de plataforma privilegiados frequentemente solicitam entitlements sensíveis como:
- com.apple.security.network.server = true
- com.apple.rootless.storage.early_boot_mount = true
- com.apple.private.kernel.system-override = true
- com.apple.private.pmap.load-trust-cache = ["cryptex1.boot.os", "cryptex1.boot.app", "cryptex1.safari-downlevel"]
Pesquisar esses em escala através de imagens de firmware é extremamente valioso para mapeamento da superfície de ataque e diffing entre releases/dispositivos.
## Escalando através de IPSWs (montagem e indexação)
Para enumerar executáveis e extrair entitlements em escala sem armazenar imagens completas:
- Use the ipsw tool by @blacktop para baixar e montar filesystems de firmware. A montagem aproveita apfs-fuse, então você pode percorrer volumes APFS sem extração completa.
```bash
# Download latest IPSW for iPhone11,2 (iPhone XS)
ipsw download ipsw -y --device iPhone11,2 --latest
# Mount IPSW filesystem (uses underlying apfs-fuse)
ipsw mount fs <IPSW_FILE>
```
- Percorra volumes montados para localizar arquivos Mach-O (verifique magic e/ou use file/otool) e, em seguida, analise entitlements e frameworks importados.
- Persista uma visão normalizada em um banco de dados relacional para evitar crescimento linear através de milhares de IPSWs:
- executables, operating_system_versions, entitlements, frameworks
- many-to-many: executable↔OS version, executable↔entitlement, executable↔framework
Exemplo de query para listar todas as versões do OS que contenham um determinado nome de executável:
```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";
```
Notas sobre portabilidade de DB (se você implementar seu próprio indexador):
- Use um ORM/abstraction (e.g., SeaORM) para manter o código DB-agnostic (SQLite/PostgreSQL).
- SQLite requer AUTOINCREMENT apenas em um INTEGER PRIMARY KEY; se você quiser i64 PKs em Rust, gere entidades como i32 e converta tipos, SQLite armazena INTEGER como inteiro com sinal de 8 bytes internamente.
## Open-source tooling and references for entitlement hunting
- Firmware mount/download: https://github.com/blacktop/ipsw
- Entitlement databases and references:
- Jonathan Levins entitlement DB: https://newosxbook.com/ent.php
- entdb: https://github.com/ChiChou/entdb
- Large-scale indexer (Rust, self-hosted Web UI + OpenAPI): https://github.com/synacktiv/appledb_rs
- Apple headers for structures and constants:
- loader.h (Mach-O headers, load commands)
- cs_blobs.h (SuperBlob, GenericBlob, CodeDirectory)
For more on code signing internals (Code Directory, special slots, DER entitlements), see: [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 Levins 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}}

View File

@ -2,47 +2,47 @@
{{#include ../../../banners/hacktricks-training.md}}
## Informações Básicas
## Basic Information
Os binários do Mac OS geralmente são compilados como **universal binaries**. Um **universal binary** pode **suportar múltiplas arquiteturas no mesmo arquivo**.
Binários do macOS geralmente são compilados como **universal binaries**. Um **universal binary** pode **suportar múltiplas arquiteturas no mesmo arquivo**.
Esses binários seguem a **estrutura Mach-O**, que é basicamente composta por:
Esses binários seguem a **estrutura Mach-O** que basicamente é composta por:
- Cabeçalho
- Comandos de Carregamento
- Comandos de carregamento
- Dados
![https://alexdremov.me/content/images/2022/10/6XLCD.gif](<../../../images/image (470).png>)
## Cabeçalho Fat
## Fat Header
Procure pelo arquivo com: `mdfind fat.h | grep -i mach-o | grep -E "fat.h$"`
Procure o arquivo com: `mdfind fat.h | grep -i mach-o | grep -E "fat.h$"`
<pre class="language-c"><code class="lang-c"><strong>#define FAT_MAGIC 0xcafebabe
</strong><strong>#define FAT_CIGAM 0xbebafeca /* NXSwapLong(FAT_MAGIC) */
</strong>
struct fat_header {
<strong> uint32_t magic; /* FAT_MAGIC ou FAT_MAGIC_64 */
</strong><strong> uint32_t nfat_arch; /* número de structs que seguem */
<strong> uint32_t magic; /* FAT_MAGIC or FAT_MAGIC_64 */
</strong><strong> uint32_t nfat_arch; /* number of structs that follow */
</strong>};
struct fat_arch {
cpu_type_t cputype; /* especificador de cpu (int) */
cpu_subtype_t cpusubtype; /* especificador de máquina (int) */
uint32_t offset; /* deslocamento do arquivo para este arquivo objeto */
uint32_t size; /* tamanho deste arquivo objeto */
uint32_t align; /* alinhamento como uma potência de 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 */
};
</code></pre>
O cabeçalho tem os bytes **mágicos** seguidos pelo **número** de **arquiteturas** que o arquivo **contém** (`nfat_arch`) e cada arquitetura terá uma struct `fat_arch`.
O header tem os bytes **magic** seguidos pelo **número** de **archs** que o arquivo **contém** (`nfat_arch`) e cada arch terá uma struct `fat_arch`.
Verifique com:
<pre class="language-shell-session"><code class="lang-shell-session">% file /bin/ls
/bin/ls: Mach-O universal binary com 2 arquiteturas: [x86_64:Mach-O 64-bit executable x86_64] [arm64e:Mach-O 64-bit executable arm64e]
/bin/ls (para arquitetura x86_64): Mach-O 64-bit executable x86_64
/bin/ls (para arquitetura arm64e): Mach-O 64-bit executable arm64e
/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]
/bin/ls (for architecture x86_64): Mach-O 64-bit executable x86_64
/bin/ls (for architecture arm64e): Mach-O 64-bit executable arm64e
% otool -f -v /bin/ls
Fat headers
@ -68,11 +68,11 @@ ou usando a ferramenta [Mach-O View](https://sourceforge.net/projects/machoview/
<figure><img src="../../../images/image (1094).png" alt=""><figcaption></figcaption></figure>
Como você pode estar pensando, geralmente um universal binary compilado para 2 arquiteturas **dobra o tamanho** de um compilado para apenas 1 arquitetura.
Como você pode imaginar, geralmente um universal binary compilado para 2 arquiteturas **dobra o tamanho** de um compilado para apenas 1 arch.
## **Cabeçalho Mach-O**
## **Mach-O Header**
O cabeçalho contém informações básicas sobre o arquivo, como bytes mágicos para identificá-lo como um arquivo Mach-O e informações sobre a arquitetura de destino. Você pode encontrá-lo em: `mdfind loader.h | grep -i mach-o | grep -E "loader.h$"`
O header contém informações básicas sobre o arquivo, como bytes magic para identificá-lo como um arquivo Mach-O e informações sobre a arquitetura alvo. Você pode encontrá-lo em: `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) */
@ -99,19 +99,19 @@ uint32_t flags; /* flags */
uint32_t reserved; /* reserved */
};
```
### Tipos de Arquivo Mach-O
### Mach-O File Types
Existem diferentes tipos de arquivos, que podem ser encontrados definidos no [**código-fonte, por exemplo aqui**](https://opensource.apple.com/source/xnu/xnu-2050.18.24/EXTERNAL_HEADERS/mach-o/loader.h). Os mais importantes são:
Existem diferentes tipos de arquivo — você pode encontrá-los definidos no [**source code for example here**](https://opensource.apple.com/source/xnu/xnu-2050.18.24/EXTERNAL_HEADERS/mach-o/loader.h). Os mais importantes são:
- `MH_OBJECT`: Arquivo objeto relocável (produtos intermediários da compilação, ainda não executáveis).
- `MH_EXECUTE`: Arquivos executáveis.
- `MH_FVMLIB`: Arquivo de biblioteca VM fixa.
- `MH_CORE`: Dumps de código.
- `MH_PRELOAD`: Arquivo executável pré-carregado (não mais suportado no XNU).
- `MH_DYLIB`: Bibliotecas dinâmicas.
- `MH_DYLINKER`: Linker dinâmico.
- `MH_BUNDLE`: "Arquivos de plugin". Gerados usando -bundle no gcc e carregados explicitamente por `NSBundle` ou `dlopen`.
- `MH_DYSM`: Arquivo companion `.dSym` (arquivo com símbolos para depuração).
- `MH_FVMLIB`: Arquivo de biblioteca de VM fixa.
- `MH_CORE`: Despejos de código
- `MH_PRELOAD`: Arquivo executável pré-carregado (não é mais suportado no XNU)
- `MH_DYLIB`: Bibliotecas dinâmicas
- `MH_DYLINKER`: Ligador dinâmico
- `MH_BUNDLE`: "Plugin files". Gerados usando -bundle no gcc e carregados explicitamente por `NSBundle` ou `dlopen`.
- `MH_DYSM`: Arquivo acompanhante `.dSym` (arquivo com símbolos para depuração).
- `MH_KEXT_BUNDLE`: Extensões do Kernel.
```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
```
Ou usando [Mach-O View](https://sourceforge.net/projects/machoview/):
Or using [Mach-O View](https://sourceforge.net/projects/machoview/):
<figure><img src="../../../images/image (1133).png" alt=""><figcaption></figcaption></figure>
## **Flags Mach-O**
## **Flags do Mach-O**
O código-fonte também define várias flags úteis para carregar bibliotecas:
- `MH_NOUNDEFS`: Sem referências indefinidas (totalmente vinculado)
- `MH_DYLDLINK`: Vinculação Dyld
- `MH_NOUNDEFS`: Sem referências indefinidas (totalmente vinculadas)
- `MH_DYLDLINK`: Ligação pelo dyld
- `MH_PREBOUND`: Referências dinâmicas pré-vinculadas.
- `MH_SPLIT_SEGS`: O arquivo divide segmentos r/o e r/w.
- `MH_WEAK_DEFINES`: O binário tem símbolos definidos fracos
- `MH_BINDS_TO_WEAK`: O binário usa símbolos fracos
- `MH_ALLOW_STACK_EXECUTION`: Torna a pilha executável
- `MH_NO_REEXPORTED_DYLIBS`: Biblioteca não possui comandos LC_REEXPORT
- `MH_PIE`: Executável Independente de Posição
- `MH_HAS_TLV_DESCRIPTORS`: Há uma seção com variáveis locais de thread
- `MH_SPLIT_SEGS`: Arquivo divide segmentos r/o e r/w.
- `MH_WEAK_DEFINES`: Binário possui símbolos definidos fracos
- `MH_BINDS_TO_WEAK`: Binário usa símbolos fracos
- `MH_ALLOW_STACK_EXECUTION`: Tornar a pilha executável
- `MH_NO_REEXPORTED_DYLIBS`: Biblioteca sem comandos LC_REEXPORT
- `MH_PIE`: Executável independente de posição
- `MH_HAS_TLV_DESCRIPTORS`: Há uma seção com variáveis thread-local
- `MH_NO_HEAP_EXECUTION`: Sem execução para páginas de heap/dados
- `MH_HAS_OBJC`: O binário tem seções oBject-C
- `MH_SIM_SUPPORT`: Suporte a simulador
- `MH_DYLIB_IN_CACHE`: Usado em dylibs/frameworks no cache de biblioteca compartilhada.
- `MH_HAS_OBJC`: Binário possui seções oBject-C
- `MH_SIM_SUPPORT`: Suporte ao simulador
- `MH_DYLIB_IN_CACHE`: Usado em dylibs/frameworks no cache de bibliotecas compartilhadas.
## **Comandos de carregamento Mach-O**
## **Comandos de carregamento do Mach-O**
O **layout do arquivo na memória** é especificado aqui, detalhando a **localização da tabela de símbolos**, o contexto da thread principal no início da execução e as **bibliotecas compartilhadas** necessárias. Instruções são fornecidas ao carregador dinâmico **(dyld)** sobre o processo de carregamento do binário na memória.
A **disposição do arquivo na memória** é especificada aqui, detalhando a **localização da tabela de símbolos**, o contexto da thread principal no início da execução e as **bibliotecas compartilhadas** necessárias. São fornecidas instruções para o loader dinâmico **(dyld)** sobre o processo de carregamento do binário na memória.
O utiliza a estrutura **load_command**, definida no mencionado **`loader.h`**:
Ele usa a estrutura **load_command**, definida no mencionado **`loader.h`**:
```objectivec
struct load_command {
uint32_t cmd; /* type of load command */
uint32_t cmdsize; /* total size of command in bytes */
};
```
Existem cerca de **50 tipos diferentes de comandos de carga** que o sistema trata de maneira diferente. Os mais comuns são: `LC_SEGMENT_64`, `LC_LOAD_DYLINKER`, `LC_MAIN`, `LC_LOAD_DYLIB` e `LC_CODE_SIGNATURE`.
Existem cerca de **50 tipos diferentes de comandos de carregamento** que o sistema trata de forma diferente. Os mais comuns são: `LC_SEGMENT_64`, `LC_LOAD_DYLINKER`, `LC_MAIN`, `LC_LOAD_DYLIB`, and `LC_CODE_SIGNATURE`.
### **LC_SEGMENT/LC_SEGMENT_64**
> [!TIP]
> Basicamente, este tipo de Comando de Carga define **como carregar o \_\_TEXT** (código executável) **e \_\_DATA** (dados para o processo) **segmentos** de acordo com os **offsets indicados na seção de Dados** quando o binário é executado.
> Basicamente, esse tipo de Comando de carregamento define **como carregar os \_\_TEXT** (código executável) **e \_\_DATA** (dados do processo) **segmentos** de acordo com os **offsets indicados na seção de dados** quando o binário é executado.
Esses comandos **definem segmentos** que são **mapeados** no **espaço de memória virtual** de um processo quando ele é executado.
Existem **diferentes tipos** de segmentos, como o **\_\_TEXT** segmento, que contém o código executável de um programa, e o **\_\_DATA** segmento, que contém dados usados pelo processo. Esses **segmentos estão localizados na seção de dados** do arquivo Mach-O.
Existem **diferentes tipos** de segmentos, como o segmento **\_\_TEXT**, que contém o código executável de um programa, e o segmento **\_\_DATA**, que contém dados usados pelo processo. Esses **segmentos estão localizados na seção de dados** do arquivo Mach-O.
**Cada segmento** pode ser ainda **dividido** em múltiplas **seções**. A **estrutura do comando de carga** contém **informações** sobre **essas seções** dentro do respectivo segmento.
**Cada segmento** pode ser ainda **dividido** em múltiplas **seções**. A **estrutura do load command** contém **informações** sobre **essas seções** dentro do respectivo segmento.
No cabeçalho, primeiro você encontra o **cabeçalho do segmento**:
No cabeçalho, primeiro você encontra o **segment header**:
<pre class="language-c"><code class="lang-c">struct segment_command_64 { /* for 64-bit architectures */
uint32_t cmd; /* LC_SEGMENT_64 */
@ -184,11 +184,11 @@ int32_t initprot; /* initial VM protection */
};
</code></pre>
Exemplo de cabeçalho de segmento:
Exemplo de segment header:
<figure><img src="../../../images/image (1126).png" alt=""><figcaption></figcaption></figure>
Este cabeçalho define o **número de seções cujos cabeçalhos aparecem depois** dele:
Esse cabeçalho define o **número de seções cujos cabeçalhos aparecem após** ele:
```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 */
};
```
Exemplo de **cabeçalho de seção**:
Exemplo de **section header**:
<figure><img src="../../../images/image (1108).png" alt=""><figcaption></figcaption></figure>
Se você **adicionar** o **deslocamento da seção** (0x37DC) + o **deslocamento** onde a **arquitetura começa**, neste caso `0x18000` --> `0x37DC + 0x18000 = 0x1B7DC`
Se você **somar** o **section offset** (0x37DC) + o **offset** onde a **arch** começa, neste caso `0x18000` --> `0x37DC + 0x18000 = 0x1B7DC`
<figure><img src="../../../images/image (701).png" alt=""><figcaption></figcaption></figure>
Também é possível obter **informações de cabeçalhos** a partir da **linha de comando** com:
Também é possível obter **headers information** pela **command line** com:
```bash
otool -lv /bin/ls
```
Segmentos comuns carregados por este cmd:
Common segments loaded by this cmd:
- **`__PAGEZERO`:** Instruí o kernel a **mapear** o **endereço zero** para que **não possa ser lido, escrito ou executado**. As variáveis maxprot e minprot na estrutura são definidas como zero para indicar que **não há direitos de leitura-gravação-execução nesta página**.
- Esta alocação é importante para **mitigar vulnerabilidades de desreferência de ponteiro NULL**. Isso ocorre porque o XNU impõe uma página zero rígida que garante que a primeira página (apenas a primeira) da memória seja inacessível (exceto em i386). Um binário poderia atender a esses requisitos criando um pequeno \_\_PAGEZERO (usando o `-pagezero_size`) para cobrir os primeiros 4k e tendo o restante da memória de 32 bits acessível tanto em modo de usuário quanto em modo kernel.
- **`__TEXT`**: Contém **código** **executável** com permissões de **leitura** e **execução** (sem permissões de escrita)**.** Seções comuns deste segmento:
- **`__PAGEZERO`:** Instrui o kernel a **mapear** o **endereço zero** de modo que **não possa ser lido, escrito ou executado**. As variáveis `maxprot` e `minprot` na estrutura são definidas como zero para indicar que **não há permissões de leitura-escrita-execução nesta página**.
- Esta alocação é importante para **mitigar vulnerabilidades de desreferência de ponteiro NULL**. Isso porque XNU aplica uma hard page zero que garante que a primeira página (apenas a primeira) da memória seja inacessível (exceto em i386). Um binário poderia satisfazer esse requisito criando um pequeno \_\_PAGEZERO (usando o `-pagezero_size`) para cobrir os primeiros 4k e deixando o restante da memória 32bit acessível tanto em modo usuário quanto em modo kernel.
- **`__TEXT`**: Contém **código** **executável** com permissões de **leitura** e **execução** (não gravável). Seções comuns deste segmento:
- `__text`: Código binário compilado
- `__const`: Dados constantes (somente leitura)
- `__[c/u/os_log]string`: Constantes de string C, Unicode ou logs do os
- `__stubs` e `__stubs_helper`: Envolvidos durante o processo de carregamento da biblioteca dinâmica
- `__unwind_info`: Dados de desempilhamento.
- Note que todo esse conteúdo é assinado, mas também marcado como executável (criando mais opções para exploração de seções que não necessariamente precisam desse privilégio, como seções dedicadas a strings).
- **`__DATA`**: Contém dados que são **legíveis** e **graváveis** (sem executável)**.**
- `__got:` Tabela de Deslocamento Global
- `__nl_symbol_ptr`: Ponteiro de símbolo não preguiçoso (vinculado na carga)
- `__la_symbol_ptr`: Ponteiro de símbolo preguiçoso (vinculado no uso)
- `__const`: Deve ser dados somente leitura (não realmente)
- `__[c/u/os_log]string`: Constantes de string C, Unicode ou de logs do os
- `__stubs` and `__stubs_helper`: Envolvidas durante o processo de carregamento de bibliotecas dinâmicas
- `__unwind_info`: Dados de unwind da pilha
- Note que todo esse conteúdo é assinado, mas também marcado como executável (criando mais opções para exploração de seções que nem necessariamente precisam desse privilégio, como seções dedicadas a strings).
- **`__DATA`**: Contém dados que são **legíveis** e **graváveis** (não executáveis).
- `__got:` Global Offset Table
- `__nl_symbol_ptr`: Ponteiro de símbolo non-lazy (bind at load)
- `__la_symbol_ptr`: Ponteiro de símbolo lazy (bind on use)
- `__const`: Deveria ser dados somente leitura (na prática não é)
- `__cfstring`: Strings do CoreFoundation
- `__data`: Variáveis globais (que foram inicializadas)
- `__bss`: Variáveis estáticas (que não foram inicializadas)
- `__objc_*` (\_\_objc_classlist, \_\_objc_protolist, etc): Informações usadas pelo runtime do Objective-C
- **`__DATA_CONST`**: \_\_DATA.\_\_const não é garantido que seja constante (permissões de escrita), nem outros ponteiros e a GOT. Esta seção torna `__const`, alguns inicializadores e a tabela GOT (uma vez resolvida) **somente leitura** usando `mprotect`.
- **`__LINKEDIT`**: Contém informações para o linker (dyld), como entradas de tabela de símbolos, strings e relocação. É um contêiner genérico para conteúdos que não estão em `__TEXT` ou `__DATA` e seu conteúdo é descrito em outros comandos de carregamento.
- Informações do dyld: Rebase, opcodes de vinculação não preguiçosa/preguiçosa/fraca e informações de exportação
- Inícios de funções: Tabela de endereços de início de funções
- Dados em Código: Ilhas de dados em \_\_text
- Tabela de Símbolos: Símbolos no binário
- Tabela de Símbolos Indiretos: Símbolos de ponteiro/stub
- Tabela de Strings
- Assinatura de Código
- **`__OBJC`**: Contém informações usadas pelo runtime do Objective-C. Embora essas informações também possam ser encontradas no segmento \_\_DATA, dentro de várias seções em \_\_objc\_\*.
- **`__RESTRICT`**: Um segmento sem conteúdo com uma única seção chamada **`__restrict`** (também vazia) que garante que, ao executar o binário, ele ignorará variáveis de ambiente DYLD.
- `__objc_*` (\_\_objc_classlist, \_\_objc_protolist, etc): Informações usadas pelo runtime Objective-C
- **`__DATA_CONST`**: \_\_DATA.\_\_const não é garantidamente constante (tem permissões de escrita), nem outros ponteiros e o GOT. Esta seção torna `__const`, alguns inicializadores e a tabela GOT (uma vez resolvida) **somente leitura** usando `mprotect`.
- **`__LINKEDIT`**: Contém informações para o linker (dyld) tais como entradas de tabelas de símbolos, strings e relocação. É um contêiner genérico para conteúdos que não estão em `__TEXT` ou `__DATA` e seu conteúdo é descrito em outros load commands.
- Informação do dyld: Rebase, opcodes de binding Non-lazy/lazy/weak e informações de exportação
- Functions starts: Tabela de endereços iniciais das funções
- Data In Code: Ilhas de dados em \_\_text
- Symbol Table: Símbolos no binário
- Indirect Symbol Table: Símbolos de ponteiro/stub
- String Table
- Code Signature
- **`__OBJC`**: Contém informações usadas pelo runtime Objective-C. Embora essas informações também possam ser encontradas no segmento \_\_DATA, dentro de várias seções \_\_objc\_\*.
- **`__RESTRICT`**: Um segmento sem conteúdo com uma única seção chamada **`__restrict`** (também vazia) que assegura que, ao executar o binário, ele irá ignorar as variáveis de ambiente do DYLD.
Como foi possível ver no código, **os segmentos também suportam flags** (embora não sejam muito usadas):
As it was possible to see in the code, **segments also support flags** (although they aren't used very much):
- `SG_HIGHVM`: Apenas núcleo (não usado)
- `SG_HIGHVM`: Somente core (não usado)
- `SG_FVMLIB`: Não usado
- `SG_NORELOC`: O segmento não tem relocação
- `SG_PROTECTED_VERSION_1`: Criptografia. Usado, por exemplo, pelo Finder para criptografar o segmento `__TEXT`.
- `SG_NORELOC`: Segment has no relocation
- `SG_PROTECTED_VERSION_1`: Encryption. Used for example by Finder to encrypt text `__TEXT` segment.
### **`LC_UNIXTHREAD/LC_MAIN`**
**`LC_MAIN`** contém o ponto de entrada no **atributo entryoff.** No momento do carregamento, **dyld** simplesmente **adiciona** esse valor à (em memória) **base do binário**, então **salta** para essa instrução para iniciar a execução do código do binário.
**`LC_MAIN`** contains the entrypoint in the **entryoff attribute.** At load time, **dyld** simply **adds** this value to the (in-memory) **base of the binary**, then **jumps** to this instruction to start execution of the binarys code.
**`LC_UNIXTHREAD`** contém os valores que o registrador deve ter ao iniciar a thread principal. Isso já foi descontinuado, mas **`dyld`** ainda o utiliza. É possível ver os valores dos registradores definidos por isso com:
**`LC_UNIXTHREAD`** contains the values the register must have when starting the main thread. This was already deprecated but **`dyld`** still uses it. It's possible to see the vlaues of the registers set by this with:
```bash
otool -l /usr/lib/dyld
[...]
@ -286,34 +286,39 @@ cpsr 0x00000000
```
### **`LC_CODE_SIGNATURE`**
Contém informações sobre a **assinatura de código do arquivo Macho-O**. Ele contém apenas um **offset** que **aponta** para o **blob de assinatura**. Isso geralmente está no final do arquivo.\
No entanto, você pode encontrar algumas informações sobre esta seção em [**este post do blog**](https://davedelong.com/blog/2018/01/10/reading-your-own-entitlements/) e este [**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}}
Contains information about the **code signature of the Macho-O file**. It only contains an **offset** that **points** to the **signature blob**. This is typically at the very end of the file.\
However, you can find some information about this section in [**this blog post**](https://davedelong.com/blog/2018/01/10/reading-your-own-entitlements/) and this [**gists**](https://gist.github.com/carlospolop/ef26f8eb9fafd4bc22e69e1a32b81da4).
### **`LC_ENCRYPTION_INFO[_64]`**
Suporte para criptografia binária. No entanto, claro, se um atacante conseguir comprometer o processo, ele poderá despejar a memória sem criptografia.
Suporte para criptografia de binários. No entanto, claro, se um atacante conseguir comprometer o processo, ele poderá extrair a memória sem criptografia.
### **`LC_LOAD_DYLINKER`**
Contém o **caminho para o executável do linker dinâmico** que mapeia bibliotecas compartilhadas no espaço de endereço do processo. O **valor é sempre definido como `/usr/lib/dyld`**. É importante notar que no macOS, o mapeamento de dylib acontece em **modo de usuário**, não em modo de kernel.
Contém o **caminho para o executável do dynamic linker** que mapeia bibliotecas compartilhadas no espaço de endereços do processo. O **valor é sempre definido para `/usr/lib/dyld`**. É importante notar que no macOS, o mapeamento de dylib ocorre em **modo de usuário**, não em modo kernel.
### **`LC_IDENT`**
Obsoleto, mas quando configurado para gerar dumps em pânico, um core dump Mach-O é criado e a versão do kernel é definida no comando `LC_IDENT`.
Obsoleto, mas quando configurado para gerar dumps em panic, um core dump Mach-O é criado e a versão do kernel é definida no comando `LC_IDENT`.
### **`LC_UUID`**
UUID aleatório. É útil para qualquer coisa diretamente, mas o XNU o armazena em cache com o resto das informações do processo. Pode ser usado em relatórios de falhas.
UUID aleatório. Não é útil diretamente para muita coisa, mas o XNU o armazena em cache com o resto das informações do processo. Pode ser usado em crash reports.
### **`LC_DYLD_ENVIRONMENT`**
Permite indicar variáveis de ambiente para o dyld antes que o processo seja executado. Isso pode ser muito perigoso, pois pode permitir a execução de código arbitrário dentro do processo, então este comando de carga é usado apenas em dyld construído com `#define SUPPORT_LC_DYLD_ENVIRONMENT` e restringe ainda mais o processamento apenas para variáveis da forma `DYLD_..._PATH` especificando caminhos de carga.
Permite indicar variáveis de ambiente para o dyld antes do processo ser executado. Isso pode ser muito perigoso, pois pode permitir executar código arbitrário dentro do processo, então esse load command é usado apenas em builds do dyld com `#define SUPPORT_LC_DYLD_ENVIRONMENT` e restringe o processamento apenas às variáveis da forma `DYLD_..._PATH` que especificam caminhos de carregamento.
### **`LC_LOAD_DYLIB`**
Este comando de carga descreve uma **dependência de biblioteca** **dinâmica** que **instrui** o **loader** (dyld) a **carregar e vincular a referida biblioteca**. Há um comando de carga `LC_LOAD_DYLIB` **para cada biblioteca** que o binário Mach-O requer.
This load command describes a **dynamic** **library** dependency which **instructs** the **loader** (dyld) to **load and link said library**. There is a `LC_LOAD_DYLIB` load command **for each library** that the Mach-O binary requires.
- Este comando de carga é uma estrutura do tipo **`dylib_command`** (que contém uma struct dylib, descrevendo a biblioteca dinâmica dependente real):
- This load command is a structure of type **`dylib_command`** (which contains a struct dylib, describing the actual dependent dynamic library):
```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>)
Você também pode obter essas informações pelo cli com:
Você também pode obter essa informação pelo cli com:
```bash
otool -L /bin/ls
/bin/ls:
@ -338,54 +343,54 @@ 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)
```
Algumas bibliotecas potenciais relacionadas a malware são:
Algumas bibliotecas potencialmente relacionadas a malware são:
- **DiskArbitration**: Monitoramento de drives USB
- **DiskArbitration**: Monitoramento de unidades USB
- **AVFoundation:** Captura de áudio e vídeo
- **CoreWLAN**: Scans de Wifi.
> [!NOTE]
> Um binário Mach-O pode conter um ou **mais** **construtores**, que serão **executados** **antes** do endereço especificado em **LC_MAIN**.\
> Os offsets de quaisquer construtores são mantidos na seção **\_\_mod_init_func** do segmento **\_\_DATA_CONST**.
## **Dados Mach-O**
No núcleo do arquivo está a região de dados, que é composta por vários segmentos conforme definido na região de comandos de carregamento. **Uma variedade de seções de dados pode ser abrigada dentro de cada segmento**, com cada seção **mantendo código ou dados** específicos a um tipo.
- **CoreWLAN**: Varreduras Wifi.
> [!TIP]
> Os dados são basicamente a parte que contém todas as **informações** que são carregadas pelos comandos de carregamento **LC_SEGMENTS_64**
> Um binário Mach-O pode conter um ou **mais** **constructors**, que serão **executados** **antes** do endereço especificado em **LC_MAIN**.\
> Os offsets de quaisquer constructors são mantidos na seção **\_\_mod_init_func** do segmento **\_\_DATA_CONST**.
## **Mach-O Data**
No núcleo do arquivo encontra-se a região de dados, que é composta por vários segmentos conforme definidos na região de load-commands. **Uma variedade de seções de dados pode ser alojada em cada segmento**, com cada seção **contendo código ou dados** específicos a um tipo.
> [!TIP]
> Os dados são basicamente a parte que contém todas as **informações** que são carregadas pelos load commands **LC_SEGMENTS_64**
![https://www.oreilly.com/api/v2/epubs/9781785883378/files/graphics/B05055_02_38.jpg](<../../../images/image (507) (3).png>)
Isso inclui:
Isto inclui:
- **Tabela de funções:** Que contém informações sobre as funções do programa.
- **Tabela de símbolos**: Que contém informações sobre a função externa usada pelo binário
- **Function table:** Que armazena informações sobre as funções do programa.
- **Symbol table**: Que contém informações sobre as funções externas usadas pelo binário
- Também pode conter nomes de funções internas, variáveis e mais.
Para verificar, você pode usar a ferramenta [**Mach-O View**](https://sourceforge.net/projects/machoview/):
Para verificar isso você pode usar a ferramenta [**Mach-O View**](https://sourceforge.net/projects/machoview/):
<figure><img src="../../../images/image (1120).png" alt=""><figcaption></figcaption></figure>
Ou a partir da cli:
Ou pelo cli:
```bash
size -m /bin/ls
```
## Seções Comuns do Objective-C
## Seções comuns do Objective-C
No segmento `__TEXT` (r-x):
- `__objc_classname`: Nomes de classes (strings)
- `__objc_methname`: Nomes de métodos (strings)
- `__objc_methtype`: Tipos de métodos (strings)
- `__objc_methtype`: Tipos de método (strings)
No segmento `__DATA` (rw-):
- `__objc_classlist`: Ponteiros para todas as classes Objective-C
- `__objc_nlclslist`: Ponteiros para classes Objective-C Não-Lazy
- `__objc_catlist`: Ponteiro para Categorias
- `__objc_nlcatlist`: Ponteiro para Categorias Não-Lazy
- `__objc_protolist`: Lista de Protocolos
- `__objc_nlclslist`: Ponteiros para classes Objective-C Non-Lazy
- `__objc_catlist`: Ponteiro para Categories
- `__objc_nlcatlist`: Ponteiro para Categories Non-Lazy
- `__objc_protolist`: Lista de protocolos
- `__objc_const`: Dados constantes
- `__objc_imageinfo`, `__objc_selrefs`, `objc__protorefs`...

View File

@ -1,15 +1,20 @@
# macOS Code Signing
# Assinatura de Código do macOS
{{#include ../../../banners/hacktricks-training.md}}
## Informações Básicas
Binaries Mach-o contêm um comando de carregamento chamado **`LC_CODE_SIGNATURE`** que indica o **offset** e **tamanho** das assinaturas dentro do binário. Na verdade, usando a ferramenta GUI MachOView, é possível encontrar no final do binário uma seção chamada **Code Signature** com essas informações:
{{#ref}}
../../../generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/mach-o-entitlements-and-ipsw-indexing.md
{{#endref}}
Binários Mach-O contêm um load command chamado **`LC_CODE_SIGNATURE`** que indica o **offset** e o **size** das assinaturas dentro do binário. Na prática, usando a ferramenta GUI MachOView, é possível encontrar no fim do binário uma seção chamada **Code Signature** com essa informação:
<figure><img src="../../../images/image (1) (1) (1) (1).png" alt="" width="431"><figcaption></figcaption></figure>
O cabeçalho mágico da Code Signature é **`0xFADE0CC0`**. Então você tem informações como o comprimento e o número de blobs do superBlob que os contém.\
É possível encontrar essas informações no [código-fonte aqui](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/osfmk/kern/cs_blobs.h#L276):
O magic header da Code Signature é **`0xFADE0CC0`**. Em seguida há informações como o comprimento e o número de blobs do superBlob que os contém.\
É possível encontrar essa informação no [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)));
```
Blobs comuns contidos são Diretório de Código, Requisitos e Direitos e uma Sintaxe de Mensagem Criptográfica (CMS).\
Os blobs comuns contêm Code Directory, Requirements and Entitlements e uma Sintaxe de Mensagem Criptográfica (CMS).\
Além disso, note como os dados codificados nos blobs são codificados em **Big Endian.**
Além disso, assinaturas podem ser destacadas dos binários e armazenadas em `/var/db/DetachedSignatures` (usado pelo iOS).
## Blob do Diretório de Código
## Code Directory Blob
É possível encontrar a declaração do [Blob do Diretório de Código no código](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/osfmk/kern/cs_blobs.h#L104):
É possível encontrar a declaração do [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)));
```
Note que existem diferentes versões desta estrutura onde as antigas podem conter menos informações.
Observe que existem diferentes versões desta struct onde as antigas podem conter menos informação.
## Páginas de Assinatura de Código
## Assinando Páginas de Código
Hashing o binário completo seria ineficiente e até inútil se ele for carregado na memória apenas parcialmente. Portanto, a assinatura do código é na verdade um hash de hashes onde cada página binária é hashada individualmente.\
Na verdade, no código anterior do **Diretório de Código**, você pode ver que o **tamanho da página é especificado** em um de seus campos. Além disso, se o tamanho do binário não for um múltiplo do tamanho de uma página, o campo **CodeLimit** especifica onde está o final da assinatura.
Calcular o hash do binário completo seria ineficiente e até inútil se ele for carregado em memória apenas parcialmente. Portanto, a assinatura de código é, na verdade, um hash de hashes onde cada página do binário é hasheada individualmente.\
Na verdade, no código anterior do **Code Directory** você pode ver que o **tamanho da página é especificado** em um de seus campos. Além disso, se o tamanho do binário não for múltiplo do tamanho de uma página, o campo **CodeLimit** especifica onde termina a assinatura.
```bash
# Get all hashes of /bin/ps
codesign -d -vvvvvv /bin/ps
@ -144,25 +149,25 @@ openssl sha256 /tmp/*.page.*
```
## Entitlements Blob
Note que as aplicações também podem conter um **entitlement blob** onde todos os direitos são definidos. Além disso, alguns binários do iOS podem ter seus direitos específicos no slot especial -7 (em vez de no slot especial -5).
Note que aplicações podem também conter um **entitlement blob** onde todos os entitlements são definidos. Além disso, alguns binários iOS podem ter seus entitlements específicos no special slot -7 (em vez do special slot -5 de entitlements).
## Special Slots
As aplicações do MacOS não têm tudo o que precisam para executar dentro do binário, mas também usam **recursos externos** (geralmente dentro do **bundle** das aplicações). Portanto, existem alguns slots dentro do binário que conterão os hashes de alguns recursos externos interessantes para verificar se não foram modificados.
Aplicações macOS não têm tudo o que precisam para executar dentro do binário; elas também usam **external resources** (normalmente dentro do **bundle** da aplicação). Portanto, existem alguns slots dentro do binário que conterão os hashes de alguns recursos externos interessantes para verificar se não foram modificados.
Na verdade, é possível ver nas estruturas do Code Directory um parâmetro chamado **`nSpecialSlots`** indicando o número dos slots especiais. Não existe um slot especial 0 e os mais comuns (de -1 a -6) são:
Na verdade, é possível ver nas structs do Code Directory um parâmetro chamado **`nSpecialSlots`** indicando o número de special slots. Não existe um special slot 0 e os mais comuns (de -1 a -6) são:
- Hash de `info.plist` (ou o que está dentro de `__TEXT.__info__plist`).
- Hash dos Requisitos
- Hash do Resource Directory (hash do arquivo `_CodeSignature/CodeResources` dentro do bundle).
- Específico da aplicação (não utilizado)
- Hash dos direitos
- Assinaturas de código DMG apenas
- Direitos DER
- Hash of `info.plist` (ou o que está dentro de `__TEXT.__info__plist`).
- Has of the Requirements
- Hash of the Resource Directory (hash do arquivo `_CodeSignature/CodeResources` dentro do bundle).
- Application specific (unused)
- Hash of the entitlements
- DMG code signatures only
- DER Entitlements
## Code Signing Flags
Cada processo tem um bitmask relacionado conhecido como `status`, que é iniciado pelo kernel e alguns deles podem ser substituídos pela **assinatura de código**. Essas flags que podem ser incluídas na assinatura de código são [definidas no código](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/osfmk/kern/cs_blobs.h#L36):
Cada processo tem associada uma bitmask conhecida como `status`, que é iniciada pelo kernel e alguns bits podem ser sobrescritos pela **code signature**. Essas flags que podem ser incluídas na code signing estão [definidas no código](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)
```
Note que a função [**exec_mach_imgact**](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/bsd/kern/kern_exec.c#L1420) também pode adicionar os flags `CS_EXEC_*` dinamicamente ao iniciar a execução.
Note que a função [**exec_mach_imgact**](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/bsd/kern/kern_exec.c#L1420) também pode adicionar as flags `CS_EXEC_*` dinamicamente ao iniciar a execução.
## Requisitos de Assinatura de Código
Cada aplicativo armazena alguns **requisitos** que deve **satisfazer** para poder ser executado. Se os **requisitos do aplicativo não forem satisfeitos**, ele não será executado (pois provavelmente foi alterado).
Cada aplicação armazena alguns **requisitos** que deve **satisfazer** para poder ser executada. Se os **requisitos contidos na aplicação não forem satisfeitos**, ela não será executada (pois provavelmente foi alterada).
Os requisitos de um binário usam uma **gramática especial** que é um fluxo de **expressões** e são codificados como blobs usando `0xfade0c00` como o mágico cujo **hash é armazenado em um slot de código especial**.
Os requisitos de um binário usam uma **gramática especial**, que é um fluxo de **expressões**, e são codificados como blobs usando `0xfade0c00` como número mágico, cujo **hash é armazenado em um slot de código especial**.
Os requisitos de um binário podem ser vistos executando:
Os requisitos de um binário podem ser vistos ao executar:
```bash
codesign -d -r- /bin/ls
Executable=/bin/ls
@ -225,8 +230,8 @@ 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]
> Observe como essas assinaturas podem verificar coisas como informações de certificação, TeamID, IDs, direitos e muitos outros dados.
> [!TIP]
> Observe como essas assinaturas podem verificar coisas como informações de certificação, TeamID, IDs, entitlements e muitos outros dados.
Além disso, é possível gerar alguns requisitos compilados usando a ferramenta `csreq`:
```bash
@ -242,55 +247,55 @@ od -A x -t x1 /tmp/output.csreq
```
É possível acessar essas informações e criar ou modificar requisitos com algumas APIs do `Security.framework`, como:
#### **Verificando a Validade**
#### **Verificação de Validade**
- **`Sec[Static]CodeCheckValidity`**: Verifica a validade de SecCodeRef por Requisito.
- **`SecRequirementEvaluate`**: Valida o requisito no contexto do certificado.
- **`SecTaskValidateForRequirement`**: Valida um SecTask em execução contra o requisito `CFString`.
- **`Sec[Static]CodeCheckValidity`**: Verifica a validade de SecCodeRef por Requirement.
- **`SecRequirementEvaluate`**: Valida um requirement no contexto de certificados.
- **`SecTaskValidateForRequirement`**: Valida um SecTask em execução contra um requirement em `CFString`.
#### **Criando e Gerenciando Requisitos de Código**
#### **Criação e Gerenciamento de Requisitos de Código**
- **`SecRequirementCreateWithData`:** Cria um `SecRequirementRef` a partir de dados binários representando o requisito.
- **`SecRequirementCreateWithString`:** Cria um `SecRequirementRef` a partir de uma expressão de string do requisito.
- **`SecRequirementCopy[Data/String]`**: Recupera a representação de dados binários de um `SecRequirementRef`.
- **`SecRequirementCreateGroup`**: Cria um requisito para a associação de grupo de aplicativos.
- **`SecRequirementCreateWithData`:** Cria um `SecRequirementRef` a partir de dados binários que representam o requirement.
- **`SecRequirementCreateWithString`:** Cria um `SecRequirementRef` a partir de uma expressão string do requirement.
- **`SecRequirementCopy[Data/String]`**: Recupera a representação em dados binários de um `SecRequirementRef`.
- **`SecRequirementCreateGroup`**: Cria um requirement para membership de app-group.
#### **Acessando Informações de Assinatura de Código**
- **`SecStaticCodeCreateWithPath`**: Inicializa um objeto `SecStaticCodeRef` a partir de um caminho do sistema de arquivos para inspecionar assinaturas de código.
- **`SecStaticCodeCreateWithPath`**: Inicializa um objeto `SecStaticCodeRef` a partir de um caminho no sistema de arquivos para inspecionar assinaturas de código.
- **`SecCodeCopySigningInformation`**: Obtém informações de assinatura de um `SecCodeRef` ou `SecStaticCodeRef`.
#### **Modificando Requisitos de Código**
- **`SecCodeSignerCreate`**: Cria um objeto `SecCodeSignerRef` para realizar operações de assinatura de código.
- **`SecCodeSignerSetRequirement`**: Define um novo requisito para o signatário de código aplicar durante a assinatura.
- **`SecCodeSignerAddSignature`**: Adiciona uma assinatura ao código que está sendo assinado com o signatário especificado.
- **`SecCodeSignerCreate`**: Cria um objeto `SecCodeSignerRef` para realizar operações de code signing.
- **`SecCodeSignerSetRequirement`**: Define um novo requirement para o signer aplicar durante o signing.
- **`SecCodeSignerAddSignature`**: Adiciona uma assinatura ao código sendo assinado com o signer especificado.
#### **Validando Código com Requisitos**
- **`SecStaticCodeCheckValidity`**: Valida um objeto de código estático contra requisitos especificados.
#### **APIs Úteis Adicionais**
#### **APIs Adicionais Úteis**
- **`SecCodeCopy[Internal/Designated]Requirement`: Obter SecRequirementRef de SecCodeRef**
- **`SecCodeCopyGuestWithAttributes`**: Cria um `SecCodeRef` representando um objeto de código com base em atributos específicos, útil para sandboxing.
- **`SecCodeCopyPath`**: Recupera o caminho do sistema de arquivos associado a um `SecCodeRef`.
- **`SecCodeCopySigningIdentifier`**: Obtém o identificador de assinatura (por exemplo, Team ID) de um `SecCodeRef`.
- **`SecCodeGetTypeID`**: Retorna o identificador de tipo para objetos `SecCodeRef`.
- **`SecCodeCopy[Internal/Designated]Requirement`: Get SecRequirementRef from SecCodeRef**
- **`SecCodeCopyGuestWithAttributes`**: Cria um `SecCodeRef` representando um objeto de código baseado em atributos específicos, útil para sandboxing.
- **`SecCodeCopyPath`**: Recupera o caminho no sistema de arquivos associado a um `SecCodeRef`.
- **`SecCodeCopySigningIdentifier`**: Obtém o signing identifier (ex.: Team ID) de um `SecCodeRef`.
- **`SecCodeGetTypeID`**: Retorna o type identifier para objetos `SecCodeRef`.
- **`SecRequirementGetTypeID`**: Obtém um CFTypeID de um `SecRequirementRef`.
#### **Flags e Constantes de Assinatura de Código**
- **`kSecCSDefaultFlags`**: Flags padrão usadas em muitas funções do Security.framework para operações de assinatura de código.
- **`kSecCSSigningInformation`**: Flag usada para especificar que as informações de assinatura devem ser recuperadas.
- **`kSecCSSigningInformation`**: Flag usada para especificar que informações de signing devem ser recuperadas.
## Aplicação de Assinatura de Código
## Aplicação da Assinatura de Código
O **kernel** é quem **verifica a assinatura do código** antes de permitir que o código do aplicativo seja executado. Além disso, uma maneira de conseguir escrever e executar novo código na memória é abusar do JIT se `mprotect` for chamado com a flag `MAP_JIT`. Note que a aplicação precisa de um direito especial para poder fazer isso.
O **kernel** é quem **verifica a assinatura de código** antes de permitir que o código do app seja executado. Além disso, uma forma de conseguir escrever e executar novo código em memória é abusar do JIT se `mprotect` for chamado com a flag `MAP_JIT`. Note que a aplicação precisa de um entitlement especial para poder fazer isso.
## `cs_blobs` & `cs_blob`
[**cs_blob**](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/bsd/sys/ubc_internal.h#L106) a struct contém as informações sobre o direito do processo em execução sobre ele. `csb_platform_binary` também informa se a aplicação é um binário de plataforma (o que é verificado em diferentes momentos pelo OS para aplicar mecanismos de segurança, como proteger os direitos de SEND para as portas de tarefa desses processos).
[**cs_blob**](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/bsd/sys/ubc_internal.h#L106) struct contém as informações sobre o entitlement do processo em execução armazenadas nele. `csb_platform_binary` também indica se a aplicação é um binário de plataforma (o que é verificado em diferentes momentos pelo OS para aplicar mecanismos de segurança, como proteger os SEND rights aos task ports desses processos).
```c
struct cs_blob {
struct cs_blob *csb_next;