mcpField
R
re-format-macho

re-format-macho

github.com/dslsdzc開発20650 回インストール2 週間前に更新
リポジトリ

re-format-macho について

re-format-machoは、macOSやiOSのMach-Oバイナリを調べるリバースエンジニアリングスキルです。構造、依存関係、エントリーポイント、署名、ライブラリ注入の確認手順を示します。

主な機能

  1. 01ファイル形式とアーキテクチャの特定
  2. 02ヘッダーとロードコマンドの確認
  3. 03動的ライブラリ依存関係の追跡
  4. 04シンボルとエントリーポイントの確認
  5. 05コード署名と注入の検査

活用シーン

  1. 01macOS実行ファイルやdylibの分析
  2. 02iOSバイナリ構造の確認
  3. 03不審なライブラリ読み込みの調査
  4. 04署名と依存情報の比較

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/dslsdzc/rev-skills --skill re-format-macho

インストール後、Claude Code で/re-format-machoを入力して読み込まれたか確認します。

同梱ファイルreferences/examples.mdreferences/layout.md

詳細

Mach-O フォーマット解析

使用する場合/しない場合

  • 使用する:対象が macOS/iOS の Mach-O バイナリ(実行ファイル/.dylib/.bundle/Framework)で、構造、load commands、エントリーポイント、コード署名、動的ライブラリの依存関係を理解する必要がある場合
  • 使用する:dylib のインジェクション(異常な LC_LOAD_DYLIB エントリ)、署名/公証の状態、ユニバーサルバイナリのマルチアーキテクチャスライスを調べる場合
  • 使用しない:PE([[re-format-pe]] を使用)、ELF([[re-format-elf]] を使用)
  • 使用しない:関数のロジックだけが必要な場合(直接、逆コンパイルのスキルを使用);iOS の脱獄環境に関する問題は [[re-mobile]] の領域です

ツールの準備

[[re-analyze/platform-tips]] の macOS ブランチを参照してください。attach/デバッグは SIP と TCC による制限を受けますが、静的解析には影響しません。

otool(Apple 標準搭載)
  • macOS:Xcode Command Line Tools:xcode-select --install
  • 検証:otool --version
  • Linux での代替:llvm-otool(apt install llvm / brew install llvm / pacman -S llvm)。otool の一般的なサブコマンドをカバーしています
llvm-objdump(クロスプラットフォーム)
  • macOS:brew install llvm;Linux:apt install llvm / dnf install llvm / pacman -S llvm
  • 検証:llvm-objdump --version
  • 使用方法:llvm-objdump --macho --private-headers sample(Linux でも Mach-O を直接解析でき、出力は macOS と同じです)
jtool2(Mach-O 構造の詳細解析、macOS)
  • macOS:GitHub(intezer/jtool2)から clone して make を実行するか、release バイナリをダウンロードします
  • 検証:jtool2 -h sample で load commands が出力されます
codesign / lipo(macOS 標準搭載)
  • 検証:codesign --version;lipo -info sample
  • Linux での代替:llvm-lipo -info sample(llvm に同梱)
dyld_shared_cache_util(macOS)
  • システム標準搭載(/usr/bin/dyld_shared_cache_util);用途:dyld 共有キャッシュ内のシステム dylib を解析する際に、個別のライブラリを取り出します

操作手順

  1. 初期確認(まず種類とアーキテクチャを確認):

    file sample                  # 可执行文件 / dylib / 通用二进制 / 字节序
    lipo -info sample            # 通用二进制列出各架构片;单架构提示 "non-fat file"
    xxd -l 16 sample             # 魔数: cffaedfe=64位小端, feedfacf=64位大端, cebafaed=32位小端, cafebabe=fat
    

    マジックナンバー(ファイル内で確認できるバイト列):cffa edfe(MH_MAGIC_64)、cefa edfe(MH_MAGIC、32 ビット)、cafe babe(FAT。その後に 4 バイトのアーキテクチャ数が続きます)。ユニバーサルバイナリは、まず lipo -thin <arch> -output piece sample でスライスを抽出してから解析します。

  2. mach_header と load commands(中核):

    otool -h sample                 # magic/cputype/filetype/ncmds/flag 一行全出
    otool -l sample | head -80      # 全部 load commands
    

    64 ビットの mach_header は固定長 32 バイト(32 ビットでは 28 バイト)です:magic(4) + cputype(4) + cpusubtype(4) + filetype(4) + ncmds(4) + sizeofcmds(4) + flags(4) + reserved(4、64 ビットのみ)。load commands は Mach-O の「セクションテーブル+インポートテーブル+エントリーポイント+署名」を統合したものです。先頭から末尾まで cmdsize の順に走査します。ncmds は個数、sizeofcmds は合計バイト数で、相互に検証できます。filetype:2=MH_EXECUTE、6=MH_DYLIB、8=MH_BUNDLE。一般的な LC 値とフィールドの表は [[layout]] を参照してください。

  3. セグメントとセクション(__TEXT/__DATA/__LINKEDIT):

    otool -l sample | grep -A8 'segname __TEXT'
    otool -l sample | grep -A8 'segname __DATA'
    llvm-objdump --macho --section-headers sample
    

    各セグメントの vmaddr/vmsize/fileoff を記録します。__TEXT,__text はコード、__DATA,__data は書き込み可能なデータ、GOT は __DATA_CONST,__got(読み取り専用の定数セグメント。古いバイナリでは __DATA,__got)にあります。__LINKEDIT はvmaddr/vmsize を持つ通常のセグメントで、通常は読み取り専用領域としてマッピングされ(vmmap で確認できます)、シンボルテーブル/文字列テーブル/再配置/署名などのリンクメタデータを格納します。具体的な格納形式は dyld と shared cache の影響を受けます。

  4. エントリーポイント(LC_MAIN / LC_UNIXTHREAD):

    otool -l sample | grep -A6 LC_MAIN
    

    entryoff はファイルヘッダーからのエントリーポイントの相対オフセットです。エントリー VA = __TEXT セグメントの vmaddr + entryoff(64 ビットでは __TEXT のベースアドレスは通常 0x100000000)。古いバイナリでは LC_UNIXTHREAD を使用します(レジスター state にエントリーポイントが含まれます)。実行ファイルに LC_MAIN も LC_UNIXTHREAD もない場合は不正な形式であり、重点的に調査してください。

  5. dyld 情報(LC_DYLD_INFO_ONLY / エクスポート trie):

    otool -l sample | grep -A9 LC_DYLD_INFO_ONLY
    llvm-objdump --macho --exports-trie sample   # 导出符号(trie 解码)
    

    offset+size の組が 5 つ、合計 48 バイトあり、すべて LC_DYLD_INFO_ONLY に含まれます:rebase(ベースアドレス修正ポイント)、bind(外部シンボルのバインド、非遅延)、weak_bind(弱シンボルのバインド。弱シンボルの統合セマンティクスは独立しており、bind に含めてはいけません)、lazy_bind(遅延バインド)、export(エクスポート trie)。新しいバイナリでは LC_DYLD_CHAINED_FIXUPS(チェーン形式の修正、iOS 13 以降のデフォルト)を使用します。dylib のエクスポートシンボルは trie 内にあり、nm -gU と同じ結果が得られます。

  6. 動的ライブラリの依存関係(インジェクション検出):

    otool -L sample                 # LC_LOAD_DYLIB 列表(依赖库 + install name)
    otool -l sample | grep -A4 LC_LOAD_DYLIB
    

    各 LC_LOAD_DYLIB:name(絶対パス、または @rpath/@executable_path からの相対パス)+ timestamp/current_version。悪意のある dylib の永続化 = LC_LOAD_DYLIB エントリの追加です。署名時の一覧との不一致は重要な警告です(詳しくは「注意点」を参照)。two-level namespace ではシンボル検索が(ライブラリ、シンボル)の二つ組に基づき、インポートが厳密に解決されます。

  7. シンボルテーブル(nlist_64):

    llvm-nm -m sample                # 含段归属与 N_EXT 标记;undefined = 导入
    llvm-nm -gU sample               # 仅外部定义符号(导出)
    otool -l sample | grep -A3 LC_SYMTAB   # symoff/nsyms/stroff/strsize 定位表
    

    nlist_64 は各エントリが 16 バイトです:n_strx(文字列テーブル内のオフセット)+ n_type(N_EXT/N_SECT など)+ n_sect + n_desc + n_value。strip 後は .symtab がなくなり、LC_DYLD_INFO のエクスポート trie と動的バインド情報だけが残ります。復元方法は ELF と同様です([[re-imports]] のシグネチャ照合 + 文字列の相互参照)。

  8. コード署名の確認:

    codesign -dv sample 2>&1          # 签名类型(adhoc / Apple Development / not signed)
    codesign --verify --deep sample   # 完整性验证
    jtool2 --sig sample | head -20    # LC_CODE_SIGNATURE 细节(CodeDirectory/哈希)
    
    • adhoc:アドホック署名。変更後に再署名できます(codesign -f -s - sample)
    • Apple 署名:1 バイトでも変更すると無効になります。Library Validation が有効な場合、dylib のインジェクションは失敗します
    • LC_CODE_SIGNATURE がない = 未署名(iOS では直接実行できません)
  9. 手動解析と検証:load command の出力に異常がある場合やヘッダーフィールドが偽装されている場合は、xxd + Python struct を使い、オフセットを指定して mach_header と各 LC を直接解析します(実行可能な最小サンプルとバイト列の例は [[examples]] を参照)。解析に失敗したからといって「破損ファイル」と判断して破棄しないでください。

分野横断の連携

  • [[re-binary-core]]:ワークフローの第 3 ステップ、Mach-O の対象フォーマット解析
  • [[re-mobile]]:iOS App/脱獄環境の解析に先立つ準備(arm64 Mach-O のメインバイナリと dylib)
  • [[re-ios]] / [[re-macos]]:エコシステムとの連携(App 層、署名と公証、TCC/SIP による制限)
  • [[re-cracking]]:macOS のクラック関連タスク(パッチ適用後の再署名手順は本スキルの手順 8 を参照)
  • [[re-imports]]:dylib 依存関係とエクスポートシンボルのハイジャック対象の分析
  • 動的デバッグでは [[re-lldb]] を併用(SIP/TCC による制限は [[re-analyze/platform-tips]] を参照)

常见坑与陷阱

  • 签名验证会拦调试/注入:修改过的二进制 codesign 校验失败无法运行——先 codesign -f -s - 重签(仅限自签/adhoc 场景);Library Validation 开启时 DYLD_INSERT_LIBRARIES 失效
  • iOS 上需越狱环境:真机调试要开发者证书或越狱,模拟器进程受沙盒限制——静态解析可先行,动态部分交给 [[re-mobile]]
  • LC_LOAD_DYLIB 注入检测:恶意 dylib 通过新增 LC_LOAD_DYLIB 实现持久化——otool -L 列表与签名时列表不一致是重要告警
  • 通用二进制含多架构片:先 lipo -info 确认架构再 lipo -thin 提取,别对全片解析;fat 头里各片 offset 是绝对文件偏移,按 (offset, size) 切出单片
  • GOT 位置随版本迁移:新产物 GOT 在 __DATA_CONST,__got(只读,装载后重定位一次);旧产物在 __DATA,__got(可写)——找 GOT 先 otool -l 看段名,别假设
  • dyld 共享缓存里没有独立 dylib 文件:系统库(libSystem.dylib 等)实际在 /System/Library/dyld/ 缓存内,文件系统里只有 stub——分析系统库用 dyld_shared_cache_util -extract 抽出
  • load command 遍历错位:现象——otool -l 输出中途乱码/报错;原因——ncmds 与 sizeofcmds 被伪造或某条 LC 的 cmdsize 异常;对策——所有 LC 至少 8 字节(load_command 头本身 cmd+cmdsize),64 位下 cmdsize 须为 8 的倍数、32 位为 4 的倍数,再按具体 cmd 校验其结构最小尺寸与尾随 section/字符串,累计不超 sizeofcmds
  • __LINKEDIT 是映射段,但内容可能被 dyld 加工:它有自己的 vmaddr/vmsize,通常以只读映射存在(vmmap 可见);不过 shared cache 共享库的链接元数据驻留在共享缓存里,直接从进程内存按文件偏移找符号表常常对不上——定位符号表优先用 nm/dyldinfo/MachOView 等按 LC_SYMTAB 解析,而不是照抄文件偏移

コメント