# macOSのUniversalバイナリとMach-Oフォーマット
htARTE(HackTricks AWS Red Team Expert) でAWSハッキングをゼロからヒーローまで学びましょう!
HackTricksをサポートする他の方法:
- **HackTricksで企業を宣伝したい**または**HackTricksをPDFでダウンロードしたい**場合は、[**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)をチェックしてください!
- [**公式PEASS&HackTricksのグッズ**](https://peass.creator-spring.com)を入手する
- [**The PEASS Family**](https://opensea.io/collection/the-peass-family)を発見し、独占的な[**NFTs**](https://opensea.io/collection/the-peass-family)のコレクションを見つける
- **💬 [Discordグループ](https://discord.gg/hRep4RUj7f)**に参加するか、[telegramグループ](https://t.me/peass)に参加するか、**Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)をフォローする
- **HackTricks**および**HackTricks Cloud**のGitHubリポジトリにPRを提出して、あなたのハッキングテクニックを共有する
#define FAT_MAGIC 0xcafebabe
#define FAT_CIGAM 0xbebafeca /* NXSwapLong(FAT_MAGIC) */
struct fat_header {
uint32_t magic; /* FAT_MAGIC or FAT_MAGIC_64 */
uint32_t nfat_arch; /* 後続する構造体の数 */
};
struct fat_arch {
cpu_type_t cputype; /* CPU指定子(int) */
cpu_subtype_t cpusubtype; /* マシン指定子(int) */
uint32_t offset; /* このオブジェクトファイルへのファイルオフセット */
uint32_t size; /* このオブジェクトファイルのサイズ */
uint32_t align; /* 2の累乗としてのアライメント */
};
ヘッダーには**magic**バイトが続き、ファイルが含む**archs**の数(`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]
/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
fat_magic FAT_MAGIC
nfat_arch 2
architecture x86_64
cputype CPU_TYPE_X86_64
cpusubtype CPU_SUBTYPE_X86_64_ALL
capabilities 0x0
offset 16384
size 72896
align 2^14 (16384)
architecture arm64e
cputype CPU_TYPE_ARM64
cpusubtype CPU_SUBTYPE_ARM64E
capabilities PTR_AUTH_VERSION USERSPACE 0
offset 98304
size 88816
align 2^14 (16384)
または[Mach-O View](https://sourceforge.net/projects/machoview/)ツールを使用する:
通常、2つのアーキテクチャ向けにコンパイルされたuniversal binaryは、1つのアーキテクチャ向けにコンパイルされたものの**サイズを倍に**します。
## **Mach-Oヘッダー**
ヘッダーには、ファイルを識別するためのマジックバイトや対象アーキテクチャに関する情報など、ファイルに関する基本情報が含まれています。次のコマンドで確認できます:`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) */
struct mach_header {
uint32_t magic; /* mach magic number identifier */
cpu_type_t cputype; /* cpu specifier (e.g. I386) */
cpu_subtype_t cpusubtype; /* machine specifier */
uint32_t filetype; /* type of file (usage and alignment for the file) */
uint32_t ncmds; /* number of load commands */
uint32_t sizeofcmds; /* the size of all the load commands */
uint32_t flags; /* flags */
};
#define MH_MAGIC_64 0xfeedfacf /* the 64-bit mach magic number */
#define MH_CIGAM_64 0xcffaedfe /* NXSwapInt(MH_MAGIC_64) */
struct mach_header_64 {
uint32_t magic; /* mach magic number identifier */
int32_t cputype; /* cpu specifier */
int32_t cpusubtype; /* machine specifier */
uint32_t filetype; /* type of file */
uint32_t ncmds; /* number of load commands */
uint32_t sizeofcmds; /* the size of all the load commands */
uint32_t flags; /* flags */
uint32_t reserved; /* reserved */
};
```
**ファイルタイプ**:
* MH\_EXECUTE (0x2): 標準のMach-O実行ファイル
* MH\_DYLIB (0x6): Mach-Oダイナミックリンクライブラリ(.dylib)
* MH\_BUNDLE (0x8): Mach-Oバンドル(.bundle)
```bash
# Checking the mac header of a binary
otool -arch arm64e -hv /bin/ls
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 ロードコマンド**
**メモリ内のファイルのレイアウト**がここで指定され、**シンボルテーブルの場所**、実行開始時のメインスレッドのコンテキスト、および必要な**共有ライブラリ**が詳細に説明されています。動的ローダー**(dyld)**には、バイナリのメモリへの読み込みプロセスに関する指示が提供されます。
これには、**`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`です。
### **LC\_SEGMENT/LC\_SEGMENT\_64**
{% hint style="success" %}
基本的に、このタイプのロードコマンドは、バイナリが実行されるときに、**\_\_TEXT**(実行コード)および**\_\_DATA**(プロセス用のデータ)**セグメントをどのようにロードするか**を、データセクションで示されたオフセットに従って定義します。
{% endhint %}
これらのコマンドは、プロセスの**仮想メモリ空間にマップされるセグメント**を**定義**します。
**異なる種類**のセグメントがあり、プログラムの実行コードを保持する**\_\_TEXT**セグメントや、プロセスで使用されるデータを含む**\_\_DATA**セグメントなどがあります。これらの**セグメントは、Mach-Oファイルのデータセクションに配置**されています。
**各セグメント**は、さらに複数の**セクション**に**分割**できます。**ロードコマンド構造**には、それぞれのセグメント内の**これらのセクションに関する情報**が含まれています。
ヘッダー内にはまず、**セグメントヘッダー**があります:
struct segment_command_64 { /* for 64-bit architectures */
uint32_t cmd; /* LC_SEGMENT_64 */
uint32_t cmdsize; /* includes sizeof section_64 structs */
char segname[16]; /* segment name */
uint64_t vmaddr; /* memory address of this segment */
uint64_t vmsize; /* memory size of this segment */
uint64_t fileoff; /* file offset of this segment */
uint64_t filesize; /* amount to map from the file */
int32_t maxprot; /* maximum VM protection */
int32_t initprot; /* initial VM protection */
uint32_t nsects; /* number of sections in segment */
uint32_t flags; /* flags */
};
セグメントヘッダーの例:
このヘッダーは、**その後に表示されるセクションヘッダーの数を定義**しています。
```c
struct section_64 { /* for 64-bit architectures */
char sectname[16]; /* name of this section */
char segname[16]; /* segment this section goes in */
uint64_t addr; /* memory address of this section */
uint64_t size; /* size in bytes of this section */
uint32_t offset; /* file offset of this section */
uint32_t align; /* section alignment (power of 2) */
uint32_t reloff; /* file offset of relocation entries */
uint32_t nreloc; /* number of relocation entries */
uint32_t flags; /* flags (section type and attributes)*/
uint32_t reserved1; /* reserved (for offset or index) */
uint32_t reserved2; /* reserved (for count or sizeof) */
uint32_t reserved3; /* reserved */
};
```
例: **セクションヘッダー**の例:
もし**セクションオフセット**(0x37DC)に**アーキテクチャが始まるオフセット**(この場合 `0x18000`)を**追加**すると、`0x37DC + 0x18000 = 0x1B7DC` となります。
また、**コマンドライン**からも**ヘッダー情報**を取得することが可能です。
```bash
otool -lv /bin/ls
```
このコマンドによってロードされる一般的なセグメント:
- **`__PAGEZERO`:** カーネルに**アドレスゼロ**を**読み取り、書き込み、実行**できないように**マップ**するよう指示します。この構造体内のmaxprotとminprot変数は、このページに**読み取り書き込み実行権限がない**ことを示すためにゼロに設定されています。
- この割り当ては**NULLポインターのデリファレンス脆弱性を緩和**するために重要です。
- **`__TEXT`**: **読み取り**および**実行**権限(書き込み権限なし)を持つ**実行可能なコード**を含みます。このセグメントの一般的なセクション:
- `__text`: コンパイルされたバイナリコード
- `__const`: 定数データ
- `__cstring`: 文字列定数
- `__stubs`および`__stubs_helper`: ダイナミックライブラリの読み込みプロセス中に関与します
- **`__DATA`**: **読み取り書き込み可能**なデータを含みます(実行権限なし)。
- `__data`: 初期化されたグローバル変数
- `__bss`: 初期化されていない静的変数
- `__objc_*`(\_\_objc\_classlist、\_\_objc\_protolistなど): Objective-Cランタイムで使用される情報
- **`__LINKEDIT`**: リンカー(dyld)のための情報を含みます。「シンボル、文字列、および再配置テーブルエントリー」など。
- **`__OBJC`**: Objective-Cランタイムで使用される情報を含みます。ただし、この情報は\_\_DATAセグメント内のさまざまな\_\_objc\_\*セクションでも見つけることができます。
### **`LC_MAIN`**
**entryoff属性**にエントリーポイントを含みます。ロード時に、**dyld**は単にこの値を(メモリ内の)**バイナリのベースに追加**し、その後この命令に**ジャンプ**してバイナリのコードの実行を開始します。
### **LC\_CODE\_SIGNATURE**
Macho-Oファイルの**コード署名に関する情報**を含みます。**署名ブロブ**を指す**オフセット**のみを含みます。通常、これはファイルの最後にあります。\
ただし、このセクションに関する情報は、[**このブログ投稿**](https://davedelong.com/blog/2018/01/10/reading-your-own-entitlements/)やこの[**gists**](https://gist.github.com/carlospolop/ef26f8eb9fafd4bc22e69e1a32b81da4)で見つけることができます。
### **LC\_LOAD\_DYLINKER**
プロセスのアドレス空間に共有ライブラリをマップする**動的リンカー実行ファイルへのパス**を含みます。**値は常に`/usr/lib/dyld`**に設定されます。macOSでは、dylibのマッピングが**カーネルモードではなくユーザーモード**で行われることに注意することが重要です。
### **`LC_LOAD_DYLIB`**
このロードコマンドは、**ローダー**(dyld)に**ライブラリのロードとリンクを指示**する**動的ライブラリ**の依存関係を記述します。Mach-Oバイナリが必要とする**各ライブラリ**に対してLC\_LOAD\_DYLIBロードコマンドがあります。
- このロードコマンドは、**実際の依存する動的ライブラリを記述するstruct dylibを含む`dylib_command`**型の構造体です。
```objectivec
struct dylib_command {
uint32_t cmd; /* LC_LOAD_{,WEAK_}DYLIB */
uint32_t cmdsize; /* includes pathname string */
struct dylib dylib; /* the library identification */
};
struct dylib {
union lc_str name; /* library's path name */
uint32_t timestamp; /* library's build time stamp */
uint32_t current_version; /* library's current version number */
uint32_t compatibility_version; /* library's compatibility vers number*/
};
```
以下のコマンドでもこの情報を取得できます:
```bash
otool -l /path/to/binary | grep -A 3 LC_VERSION_MIN_MACOSX
```
```bash
otool -L /bin/ls
/bin/ls:
/usr/lib/libutil.dylib (compatibility version 1.0.0, current version 1.0.0)
/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)
```
いくつかの潜在的なマルウェア関連ライブラリは次のとおりです:
- **DiskArbitration**:USBドライブの監視
- **AVFoundation**:オーディオとビデオのキャプチャ
- **CoreWLAN**:Wifiスキャン
{% hint style="info" %}
Mach-Oバイナリには、**LC\_MAIN**で指定されたアドレスの**前に実行される**1つ以上の**コンストラクタ**が含まれる可能性があります。\
任意のコンストラクタのオフセットは、**\_\_DATA\_CONST**セグメントの**\_\_mod\_init\_func**セクションに保持されます。
{% endhint %}
## **Mach-Oデータ**
ファイルの中心には、ロードコマンド領域で定義された複数のセグメントで構成されるデータ領域があります。**各セグメントにはさまざまなデータセクションが収容され、各セクションには特定のタイプに固有のコードまたはデータが含まれます**。
{% hint style="success" %}
データは基本的に、ロードコマンド**LC\_SEGMENTS\_64**によって読み込まれる**すべての情報**を含む部分です。
{% endhint %}
![https://www.oreilly.com/api/v2/epubs/9781785883378/files/graphics/B05055_02_38.jpg](<../../../.gitbook/assets/image (507) (3).png>)
これには次のものが含まれます:
- **関数テーブル**:プログラム関数に関する情報を保持します。
- **シンボルテーブル**:バイナリで使用される外部関数に関する情報を含みます。
- 内部関数、変数名なども含まれる可能性があります。
確認するには、[**Mach-O View**](https://sourceforge.net/projects/machoview/)ツールを使用できます:
または、CLIから:
```bash
size -m /bin/ls
```