re-tee について
re-teeは、TrustZone、OP-TEE、Trusted Appを対象とするリバースエンジニアリングスキルです。ファームウェアの構造、TAのコマンド分岐、ホスト側の呼び出しを関連付け、セキュアストレージや信頼の起点のデータフローを調べます。
主な機能
- 01TEE構成とSMC呼び出しの特定
- 02TAヘッダーとELFペイロードの解析
- 03TAコマンド分岐の復元
- 04セキュアストレージのオブジェクトとデータフローの追跡
- 05ホスト側ioctlとTAインターフェースの照合
- 06独自TEEとの差異の特定
活用シーン
- 01Trusted Appのインターフェース露出評価
- 02デバイス鍵とセキュアストレージ経路の追跡
- 03Linuxホスト側のTEE呼び出し分析
- 04ファームウェア内のTEE実装の調査
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ dslsdzc/ rev-skills --skill re-teeインストール後、Claude Code で/re-teeを入力して読み込まれたか確認します。
同梱ファイルreferences/decision-tree.mdreferences/gotchas.md
詳細
TEE / TrustZone 逆向(OP-TEE / Trusted App / secure storage)
何时使用 / 何时不用
- 用:TrustZone/OP-TEE 类 TEE 分析——可信应用(Trusted App)逆向、命令分发表还原、secure storage(安全存储/设备密钥)对象与数据流
- 用:设备密钥/信任根方向——DRM 硬件信任根([[re-drm]] 的 L1 类)、设备密钥提取与保护机制(授权研究)
- 用:TEE 接口面——SMC 调用、主机侧 TEE 驱动 ioctl、client 库调用序列还原
- 用:固件安全评估——评估目标设备 TEE 实现的接口暴露面、存储保护强度与信任根边界
- 不用:普通 App 层(走 [[re-mobile]]);Windows 内核/驱动(走 [[re-kernel]],TEE 侧是 Linux/ARM 域)
- 不用:纯固件提取解包(先走 [[re-fw-extract]],本技能在其后分析 TEE 组件)
- 不用:目标只是普通加密数据(走 [[re-crypto-*]] 系列,无 TEE 组件时不必进本技能)
- 不用:仅需判定「设备是否用了 TEE」(无镜像、无调用面可分析)——特征级证据即可,不进深度流程
- 不用:EL2 hypervisor/虚拟化域(走 [[re-hypervisor]],TEE 是 EL1/EL3 域)
- 注意:secure world 内动态调试通常不可行(见坑 3)——默认静态分析 + 主机侧观察;主机侧动态执行按 [[re-analyze/platform-tips]] 最高原则在沙箱内进行
工具准备
静态分析(镜像解析/反编译)免沙箱;主机侧动态(跑 client、hook ioctl)按 [[re-analyze/platform-tips]] 最高原则进沙箱;secure world 内动态不做(见坑 3),默认以静态 + 主机侧观察为主。
反编译工作台([[re-ghidra]] / [[re-ida]],ARM64)
- [[re-ghidra]](默认):导入 TEE OS 镜像与 TA(.ta 需先切掉签名头,见步骤 2 与坑 5)
- [[re-ida]]:备选;两者均需 ARM64 支持
- 验证: 能反编译 ARM64 代码,定位
smc指令调用点与TA_InvokeCommandEntryPoint类分发表
固件提取工具链([[re-fw-extract]])
- binwalk/unblob、magic 扫描、字节序判断——从 bootrom/启动链/设备固件中定位并提取 TEE OS 与 TA 镜像
- 验证:
binwalk --version(安装命令见 [[re-fw-extract]]「工具准备」)
python3(二进制解析/脚本)
- Linux:
apt install python3/dnf install python3/pacman -S python;macOS: 自带;Windows: 官方安装器或choco install python - 验证:
python3 --version - 用途: 签名头/ELF 载荷切分解析、结构字段标注、解密还原脚本(衔接 [[re-crypto-decrypt]])
参考实现(OP-TEE 官方开源,理解结构用)
- 官方仓库 optee_os / optee_client / optee_examples(与 qemu 仿真环境)提供 TEE 结构与调用序列的权威参照——分析目标与 OP-TEE 差异时按官方源码核对,不凭经验值
- qemu 仿真环境可跑通 client → TA 全链路调用,用于对照调用序列与参数布局;仿真与真机的差异(真实驱动/中断/存储介质)以真机为准
frida / 主机侧观察([[re-frida]])
- 主机侧动态:hook client 库调用序列与 ioctl 参数(frida 安装与沙箱原则见 [[re-frida]],动态执行默认沙箱)
- 验证:
frida --version
操作手順
順番に実行し、各ステップの成果物(イメージの特定、ヘッダー構造の注釈、コマンド番号一覧)には証拠のパスと sha256 を記録します([[re-triage]] を参照)。報告書から引用できるようにします。
-
アーキテクチャの特定(world の区分/SMC/TEE OS のエントリーポイント):
- TrustZone は normal world(通常世界、NS)と secure world(セキュア世界、S)に分かれます。ARMv8-A では、TEE OS は通常 secure EL1 で動作し、信頼できるアプリケーションは secure EL0 で動作します。EL3 の監視層(monitor)はセキュリティ監視ファームウェア(ATF BL31 系の起動ファームウェアなど、一般化したもの)を担います。
- SMC 命令は、normal world から secure world に入るための経路です。AArch64 では
smc #imm(AArch32 ではsmc)を使用し、EL1/EL2 から実行すると EL3 の監視層にトラップされ、監視層から TEE OS に振り分けられます。逆アセンブル結果でsmc命令を検索すれば、呼び出し箇所を特定できます。 - SMC パラメーターの規約(SMCCC):機能番号は w0(サービス/呼び出し規約の識別ビットを含む)、パラメーターは w1-w7(SMC32)または x1-x17(SMC64。SMCCC ≥1.2 で初めて x1-x17 に拡張され、1.0/1.1 では x1-x7 のみ)、戻り値は w0 から格納されます。呼び出し箇所に注釈を付ける際は、通常の ABI から推測せず、規約表に従ってレジスターを読み取ります(落とし穴 4 を参照)。
- 特徴の調査:まずバージョン文字列、エクスポート API 文字列テーブル、SMC 機能番号の定数テーブルを grep で特定します。文字列テーブルから TEE OS の種類とバージョンが直接判明することも多く、個別に逆アセンブルするより速く特定できます。
- TEE OS のロードエントリーポイントを特定します:bootrom → 起動ファームウェア → TEE OS イメージ(イメージヘッダーの magic、ロード/署名検証コード)。起動チェーンをたどり、TEE イメージの特徴(イメージヘッダーのマジックナンバー、バージョン文字列、エクスポート API 文字列テーブル)を検索します。TEE OS がデバイスのファームウェアパーティションに内蔵されている場合もあります([[re-fw-extract]] で抽出してから特定します)。
- 成果物:world/EL の区分図 + TEE OS イメージの位置とロードエントリーポイント
-
OP-TEE の構造(core と TA の分離、.ta 形式):
- core(信頼できる OS カーネル、secure world 側のシステムサービス)と TA(信頼できるアプリケーション、secure world のユーザー空間)は分離されています。core は TA に
TEE_*内部 API(暗号、セキュアストレージ、時刻など)を提供し、TA はその API に依存してビジネスロジックを実装します。TA を分析する前に、core と TA の境界(誰が API を提供し、誰が API を呼び出すか)を確認します。 - .ta ファイル形式(REE ファイルシステムの TA):ファイル = 署名ヘッダー + ELF ペイロード。署名ヘッダー(
struct shdr、公式の core/include/signed_hdr.h)は、magic(0x4f545348= "OTSH")、img_type、img_size、algo、hash_size、sig_size で構成され、その後に hash と署名が続きます。img_type の値は、0 が平文署名 TA、1 が bootstrap TA(UUID + バージョンのサブヘッダー付き)、2 が暗号化 TA、3 がサブキーの連鎖ヘッダーです。暗号化されたバリアント(img_type=2)にはshdr_encrypted_taサブヘッダー(enc_algo、flags、iv_size、tag_size + iv + tag)が続き、暗号文は AES-GCM です。 - 解析手順:ファイルヘッダーの magic で署名ヘッダーを特定 → img_size に従って ELF ペイロードを切り出す → [[re-format-elf]] でセクションテーブル/セグメントを解析 →
ta_head(UUID、バージョン、flags など)に注釈を付けます。UUID は TA インターフェースの識別子で、ホスト側から呼び出す UUID に対応します。 - 拡張子を判断根拠にしないでください。一部のデバイスでは .tos/.trusted 系の拡張子で TEE OS/TA を配布しています。必ず magic に基づいて形式を判断し、拡張子でパーサーを選ばないでください。
- 成果物:署名ヘッダーのフィールド注釈 + 切り出した ELF ペイロード + ta_head/UUID の記録
- core(信頼できる OS カーネル、secure world 側のシステムサービス)と TA(信頼できるアプリケーション、secure world のユーザー空間)は分離されています。core は TA に
-
TA の分析(エントリーポイント/コマンドの振り分け/セキュアストレージ):
- エントリーチェーン:
TA_CreateEntryPoint(初期化)→TA_OpenSessionEntryPoint(セッション確立)→TA_InvokeCommandEntryPoint(コマンドの振り分け、cmd_id による switch)。コマンド振り分け表は TA の外部インターフェース一覧です。分岐ごとにコマンド番号と動作を記録します。 - パラメーターモデル:invoke にはパラメーター型の記述と、最大 4 個の
TEE_Param(value スカラーのペア/memref メモリー参照の 2 種類)が含まれます。memref は共有メモリーを指し、入出力の主要な経路です。各コマンド分岐にパラメーター型と構造を記録します。 - セッションのライフサイクル:OpenSession/CloseSession とコマンド呼び出しの対応関係から、オブジェクト(誰がセッションを確立し、どのタイミングで、どのような初期パラメーターを渡すか)を復元します。セッション確立時のパラメーターには、初期化用の鍵素材が含まれることがよくあります。
- コマンド番号の列挙:switch の各分岐に番号を付けます(不正なコマンド/デフォルト分岐を含む)。ホスト側の呼び出し面(手順 4)と照合し、どのコマンドが実際に到達可能か、どれが内部使用かを確認します。到達可能なコマンドはインターフェース面/攻撃面の主体となるため、優先して記録します。
- セキュアストレージのオブジェクト操作:
TEE_*ストレージ API の呼び出し箇所(オブジェクトの作成/オープン/読み取り/書き込み/シーク/削除など)を特定し、オブジェクト ID(UUID + オブジェクト名/インデックスから派生することが多い)とデータフローを復元します。セキュアストレージの暗号文は最終的に通常世界のファイルシステム(tee-supplicant 経由)またはハードウェアストレージ(RPMB 系。ハードウェア側は [[re-hw-chip]] を参照)に保存されます。暗号文ファイルの復号経路を見つければ、オブジェクトデータを特定できます。 - 保存形式:REE ファイルシステム側では通常、インデックスファイルとデータブロックファイルの組み合わせ(オブジェクトディレクトリのマッピング)です。インデックスからオブジェクトを探し、ブロックから暗号文の位置を特定して、オブジェクトの内容を復元します。
- 成果物:コマンド番号 → 動作の一覧 + パラメーター構造の注釈 + セキュアストレージのオブジェクト一覧
- エントリーチェーン:
-
ホスト側の呼び出し面(ioctl/client ライブラリー、両側から挟み込む):
- Linux 側の TEE サブシステム:クライアントの libteec が使用する
/dev/tee0上のTEE_IOC_*ioctl(セッションのオープン、invoke、セッションのクローズ、共有メモリーの割り当て/登録など)。/dev/teepriv0は tee-supplicant(特権デーモン)が使用するもので、クライアントからは呼び出しません。teepriv0 を「プライベートセッション」用の経路と誤認しないでください([[gotchas]] を参照)。 - ユーザー空間の client ライブラリーの呼び出しシーケンス(GlobalPlatform TEE Client API):
TEEC_InitializeContext→TEEC_OpenSession(UUID とパラメーターを指定)→TEEC_InvokeCommand(コマンド番号と TEEC_Operation を指定)→TEEC_CloseSession→TEEC_FinalizeContext - 挟み込み手法:ホスト側で ioctl パラメーター(UUID、コマンド番号、パラメーターのレイアウト、共有メモリーの内容)を読み取り、TA 側の振り分け表(手順 3)と照合します。両側に注釈を付ければ、TA の入出力形式を完全に把握できます。一方の情報が欠けている場合は、もう一方から逆算します(落とし穴 2 を参照)。
- 動的観察(サンドボックス内):frida で client ライブラリーの呼び出しと ioctl パラメーターをフックし([[re-frida]])、セッションのオープン、コマンド呼び出しのシーケンス、バッファーの内容を記録します。
- ログ側:
dmesgの tee ドライバーと OP-TEE の初期化ログ(ドライバーのバージョン、割り込み番号、supplicant の状態)を、フィンガープリントとバージョンの判定に役立てます。 - 補足観察:tee-supplicant プロセスの動作(ストレージへの保存/周辺機器へのアクセス)を確認します。これはセキュアストレージのデータフローにおける REE 側の到達点です。
- 成果物:ホスト側の呼び出しシーケンス + TA インターフェース対照表(UUID/コマンド番号/パラメーターのレイアウトをそれぞれ対応付けます)
- Linux 側の TEE サブシステム:クライアントの libteec が使用する
-
ベンダーごとの差異への対応(カスタム TEE、一般化):
- カスタム TEE の差異として、SMC 機能番号体系、TA イメージ形式(ヘッダー構造/署名/暗号化方式)、セキュアストレージのレイアウト、エクスポート API の命名と意味などが挙げられます。これらは OP-TEE と異なる可能性があります。
- 方針:まず TEE の種類をフィンガープリントで識別します(イメージヘッダーの特徴、文字列/エクスポート API の特徴、SMC 機能番号のパターン)。次に OP-TEE 系かカスタム実装かを確認し、一般的な手順(アーキテクチャの特定 → 形式の解析 → インターフェースの列挙 → 呼び出し面からの挟み込み)を順に適用します。OP-TEE の詳細は参考テンプレートとして扱い、デフォルト値とは見なさないでください。
- 差異への対応:構造が一致しない箇所は、まず「カスタム拡張」(フィールドの追加/並べ替え/異なるマジックナンバー)を疑い、無理に当てはめず差異を記録します。形式のドキュメントを入手できない場合は、「フィールドの長さ + 一般的な値(UUID/バージョン/サイズ)」からレイアウトを逆算します([[re-proto-rev]] の考え方)。
- 逆算による照合:コマンド番号と動作の対応は、「戻りコード + 出力バッファーの内容」を1つずつ比較して確認できます。エラーコードの意味から、パラメーターの検証順序や権限の境界が明らかになることもよくあります。
- 成果物:TEE の種類のフィンガープリント + 差異の一覧
クロスドメイン連携
- [[re-fw-extract]]:TEE OS/TA イメージの抽出と展開に先立つ処理(bootrom/起動チェーン/ファームウェアパーティション)
- [[re-binary-core]]:イメージ逆コンパイルの基盤([[re-format-elf]] で TA ELF を解析、[[re-ghidra]]/[[re-ida]] ワークベンチ)
- [[re-kernel]]:ホスト側 TEE ドライバーの分析(ioctl ディスパッチ、ドライバーの読み込み、Linux カーネル側)
- [[re-mobile]]:モバイル端末側 TEE の統合面(アプリ内 TEE 呼び出し、DRM 統合、ホスト側呼び出し面との連携)
- [[re-hw-chip]]:セキュアストレージのハードウェア側(RPMB 系ストレージ、信頼のルート、物理的保護機構)
- [[re-frida]]:ホスト側での動的観察(client ライブラリ/ioctl の計装、サンドボックスの原則)
- [[re-drm]]:デバイスキー/ハードウェアの信頼のルートの方向(DRM L1 系の信頼のルートは TEE 内)
- [[re-crypto-decrypt]]:暗号化された TA ペイロード/セキュアストレージの暗号文の復号と復元
- [[re-sandbox]]/[[re-analyze/platform-tips]]:ホスト側で動的実行を隔離するための最優先原則
よくある落とし穴
- TA は署名(+暗号化)されたイメージのため、そのまま分析すると失敗します:現象――.ta を入手してそのまま逆コンパイラーに渡すと、インポートに失敗するか、文字化けだらけになります。原因――.ta は署名ヘッダー+ELF ペイロードで構成され(暗号化された形式では AES-GCM 暗号文です)、ファイルヘッダーは ELF ヘッダーではありません。対処――まず署名ヘッダーの magic(例:"OTSH")を基準にペイロードを特定して切り出し(手順 2)、暗号化された形式では復号プロセス([[re-crypto-decrypt]])を復元して平文 ELF を取得してから分析します。署名検証/復号プロセス自体も分析対象です(信頼のルート/キーは core 側にあります)
- secure world のコードを入手できない場合は、ホスト側から推定します:現象――TEE OS/TA ファームウェアを抽出できず(SoC 内部 ROM/保護されたストレージ)、secure world の動的分析に着手できません。原因――TEE OS は組み込みまたは保護されていることが多く、ユーザー領域のファームウェアと一緒には配布されません。対処――ホスト側の ioctl(
TEE_IOC_*)呼び出し面と client ライブラリの呼び出しシーケンスを記録し、UUID/コマンド番号/パラメーターのレイアウトを確認します(手順 4)。戻り値の挙動と組み合わせて TA インターフェースと内部ロジックを推定し、静的な証拠が不十分な場合は呼び出し面の証拠を優先します - secure world のダンプ防止/監視機構:現象――デバッグをアタッチしても効果がない、メモリダンプを取得できない、または内容が異常、実行時の挙動が静的分析と一致しません。原因――TEE 側にアンチデバッグと完全性保護があります(デバッグポートのヒューズ切断、安全監視、ダンプ防止機構など。一般化した説明です)。対処――secure world の動的デバッグは行わず、静的分析とホスト側の観察を中心にします。挙動の差異は「TEE 側の監視が作動した」証拠として記録し、確信度を明記して、無理に原因を特定しません
- SMC パラメーターの規約を誤ると読み違えます:現象――SMC 呼び出し箇所を通常の関数呼び出しとして扱い、通常の ABI に基づいてレジスター引数を推測した結果、推定したインターフェース構造がすべて誤ります。原因――SMC は SMCCC の規約に従います(機能番号は w0、パラメーターは w1-w7/x1-x17。SMC64 の x1-x17 は SMCCC 1.2 以降。戻り値は w0 から)。通常の ABI とは異なるため、解釈のずれによってデータフロー全体が乱れます。対処――まず公開されている呼び出し規約に基づいて表を作成し(機能番号のエンコード、パラメーターレジスターのレイアウト、戻り値の規約)、その後、逆コンパイル結果の
smc呼び出し箇所に注釈を付けます。パラメーターの意味は推測せず、規約表に従って判断します([[gotchas]] の呼び出し規約グループを参照) - 署名ヘッダー/ta_head を ELF ヘッダーとして解析してしまう:現象――ELF ヘッダーとして .ta を解析すると失敗する(e_ident が一致しない)、または ta_head の UUID を文字列テーブルとして扱ってしまいます。原因――.ta ファイルのヘッダーは署名ヘッダーであり(ELF ヘッダーはペイロード内にあります)、ta_head は ELF 内部の先頭構造であってファイルヘッダーではありません。対処――まず署名ヘッダーのフィールド(magic/img_size)に基づいて ELF ペイロードを切り出してから、[[re-format-elf]] の手順に進みます。Ghidra/IDA にインポートする前にスクリプトで署名ヘッダーを除去し(手順 2 の生成物を保存)、記録します
- 独自 TEE に OP-TEE の詳細を当てはめてしまう:現象――OP-TEE のヘッダー構造/コマンドモデルに基づいて独自 TEE を分析すると、フィールドがすべてずれてインターフェースも一致しません。原因――独自 TEE では形式と規約が異なります(イメージヘッダー、SMC 機能番号、ストレージのレイアウトはそれぞれ異なります)。対処――まず TEE の種類を指紋分析し(手順 5)、体系を確認してから分析テンプレートを選びます。差異は「フィールド長+一般的な値(UUID/バージョン/サイズ)からレイアウトを推定する」方法で扱います([[re-proto-rev]] の考え方)。OP-TEE の構造はあくまで参考にとどめます
- UUID が一致しない場合、無理に合わせないでください:現象――ホスト側から呼び出す UUID が TA のディスパッチテーブルに見つかりません。原因――ファームウェアパッケージ内に複数の TA バージョンが共存しているか、TA イメージのバージョンがシステムと一致していません(UUID はインターフェース識別子であり、バージョンの進化に伴って UUID が変わることがあります)。対処――ファームウェアパッケージ内の TA 一覧/ディレクトリーでバージョンを確認し、候補となる TA を一つずつ UUID とコマンド番号に照らして確認します
- セキュアストレージの暗号文が見つからないからといって、データがないと判断しないでください:現象――REE ファイルシステム側でセキュアストレージの暗号文が見つかりません。原因――ストレージ媒体が RPMB/ハードウェア側にあるか、書き込み先のパスがデフォルトと異なります(tee-supplicant の設定)。対処――まずストレージ媒体と supplicant の設定(REE FS と RPMB のどちらか)を確認します。RPMB 側の場合は [[re-hw-chip]] の考え方を参照し、「見つからない」ことを根拠にデータがないと結論づけないでください
- 判断分岐(イメージ形式/インターフェース面/証拠のレベル)は [[decision-tree]] を、形式と呼び出し規約の境界は [[gotchas]] を参照してください
コメント
Markdown 対応