18 KiB
macOSのUniversalバイナリとMach-Oフォーマット
htARTE(HackTricks AWS Red Team Expert) でAWSハッキングをゼロからヒーローまで学びましょう!
HackTricksをサポートする他の方法:
- HackTricksで企業を宣伝したいまたはHackTricksをPDFでダウンロードしたい場合は、SUBSCRIPTION PLANSをチェックしてください!
- 公式PEASS&HackTricksのグッズを入手する
- The PEASS Familyを発見し、独占的なNFTsのコレクションを見つける
- **💬 Discordグループ**に参加するか、telegramグループに参加するか、Twitter 🐦 @carlospolopmをフォローする
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出して、あなたのハッキングテクニックを共有する
基本情報
Mac OSのバイナリは通常、universal binariesとしてコンパイルされます。Universal binaryは同じファイル内で複数のアーキテクチャをサポートできます。
これらのバイナリは、基本的に以下のようなMach-O構造に従います:
- ヘッダー
- ロードコマンド
- データ
Fatヘッダー
次のコマンドでファイルを検索します: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 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ツールを使用する:
通常、2つのアーキテクチャ向けにコンパイルされたuniversal binaryは、1つのアーキテクチャ向けにコンパイルされたもののサイズを倍にします。
Mach-Oヘッダー
ヘッダーには、ファイルを識別するためのマジックバイトや対象アーキテクチャに関する情報など、ファイルに関する基本情報が含まれています。次のコマンドで確認できます:mdfind loader.h | grep -i mach-o | grep -E "loader.h$"
#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)
# 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を使用します:
Mach-O ロードコマンド
メモリ内のファイルのレイアウトがここで指定され、シンボルテーブルの場所、実行開始時のメインスレッドのコンテキスト、および必要な共有ライブラリが詳細に説明されています。動的ローダー**(dyld)**には、バイナリのメモリへの読み込みプロセスに関する指示が提供されます。
これには、loader.h
で定義されたload_command構造が使用されます。
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 */
};
セグメントヘッダーの例:
このヘッダーは、その後に表示されるセクションヘッダーの数を定義しています。
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
となります。
また、コマンドラインからもヘッダー情報を取得することが可能です。
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ファイルのコード署名に関する情報を含みます。署名ブロブを指すオフセットのみを含みます。通常、これはファイルの最後にあります。
ただし、このセクションに関する情報は、このブログ投稿やこのgistsで見つけることができます。
LC_LOAD_DYLINKER
プロセスのアドレス空間に共有ライブラリをマップする動的リンカー実行ファイルへのパスを含みます。値は常に/usr/lib/dyld
に設定されます。macOSでは、dylibのマッピングがカーネルモードではなくユーザーモードで行われることに注意することが重要です。
LC_LOAD_DYLIB
このロードコマンドは、ローダー(dyld)にライブラリのロードとリンクを指示する動的ライブラリの依存関係を記述します。Mach-Oバイナリが必要とする各ライブラリに対してLC_LOAD_DYLIBロードコマンドがあります。
- このロードコマンドは、**実際の依存する動的ライブラリを記述するstruct dylibを含む
dylib_command
**型の構造体です。
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*/
};
以下のコマンドでもこの情報を取得できます:
otool -l /path/to/binary | grep -A 3 LC_VERSION_MIN_MACOSX
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 %}
これには次のものが含まれます:
- 関数テーブル:プログラム関数に関する情報を保持します。
- シンボルテーブル:バイナリで使用される外部関数に関する情報を含みます。
- 内部関数、変数名なども含まれる可能性があります。
確認するには、Mach-O Viewツールを使用できます:
または、CLIから:
size -m /bin/ls
ゼロからヒーローまでAWSハッキングを学ぶ htARTE(HackTricks AWS Red Team Expert)!
HackTricksをサポートする他の方法:
- HackTricksで企業を宣伝したいまたはHackTricksをPDFでダウンロードしたい場合は、SUBSCRIPTION PLANSをチェックしてください!
- 公式PEASS&HackTricksスワッグを入手する
- The PEASS Familyを発見し、独占的なNFTsコレクションを見つける
- 💬 Discordグループまたはtelegramグループに参加するか、Twitter 🐦 @carlospolopmでフォロー**する。
- ハッキングトリックを共有するために、PRを HackTricks および HackTricks Cloud のGitHubリポジトリに提出してください。