ctf-rev について
ctf-revは、コンパイル済みプログラムを対象とするCTFリバースエンジニアリング用スキルです。入力と検証処理の追跡、パターン認識、静的・動的・複合分析の選択を通じて、フラグやキーの特定を支援します。
主な機能
- 01静的・動的分析の手順
- 02入力から検証までのデータフロー追跡
- 03アルゴリズムとパターンの認識
- 04制約の求解と解の検証
活用シーン
- 01バイナリの入力検査を追ってフラグを探す
- 02難読化コードに適した分析方法の選択
- 03制約で表されたキー検査の求解
MCP 対応
ReVaのMCPツールを使ったプログラムの確認、逆コンパイル、クロスリファレンス分析、調査結果の記録方法を説明します。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ cyberkaida/ reverse-engineering-assistant --skill ctf-revインストール後、Claude Code で/ctf-revを入力して読み込まれたか確認します。
同梱ファイルpatterns.md
詳細
CTF リバースエンジニアリング
目的
あなたは CTF のリバースエンジニアリングを解く人です。目標は、体系的な分析を通じて プログラムの動作を理解し、フラグ/キー/パスワードを抽出することです。
CTF のリバースエンジニアリングの本質は、制約下での理解です。
- 限られた時間(競技のプレッシャー)
- 問題の構造が不明(どの手法が問われているのか?)
- 最小限のドキュメント(それこそが課題です!)
- 目標重視(完璧な理解ではなく、フラグを見つけること)
マルウェア分析や脆弱性調査とは異なり、CTF のリバースエンジニアリングでは、次の能力が試されます。
- 課題の核心をすばやく特定する(暗号?難読化?アルゴリズムの復元?)
- 重要なデータフローを追跡する(入力はどこへ進むのか?どのように検証されるのか?)
- パターンを認識する(標準的なアルゴリズム、よくあるトリック)
- アプローチを適応させる(静的か動的か、トップダウンかボトムアップか)
概念的なフレームワーク
3 つの問い
リバースエンジニアリングの課題はすべて、次の問いに答えることに集約されます。
1. プログラムは何を期待しているのか?
- 入力形式(文字列、数値、バイナリデータ?)
- 入力構造(長さ、形式、エンコーディング?)
- 検証条件(チェック、比較、制約?)
2. プログラムは何をするのか?
- 変換(暗号化、ハッシュ化、エンコード、計算?)
- 比較(ハードコードされた値、導出された値との比較?)
- アルゴリズム(標準的な暗号、独自のロジック、数学的処理?)
3. どうすれば逆算できるのか?
- 処理は可逆か?(暗号化かハッシュ化か)
- ブルートフォースできるか?(キー空間のサイズ、性能)
- 答えを導き出せるか?(方程式を解く、逆方向に追跡する)
- 回避できるか?(パッチ適用、デバッグ、状態の操作)
理解することと解くこと
すべてを理解する必要はありません。フラグの取得につながる部分に集中しましょう。
完全な理解(多くの場合、不要です):
- すべての関数の目的
- プログラム全体のフロー
- すべての境界ケースとエラー処理
- ライブラリの実装詳細
必要十分な理解(必要なのはこれです):
- エントリーポイントからフラグ検証まで
- 中核となる変換ロジック
- 入力と出力の関係
- 比較方法または成功条件
例:
Program has 50 functions. You identify:
- main() calls validate_key()
- validate_key() calls transform_input() then compare_result()
- transform_input() does AES encryption
- compare_result() checks against hardcoded bytes
Sufficient understanding: "Input is AES-encrypted and compared to constant"
You don't need to reverse the other 45 functions!
中核となる手法
静的解析:コードの理解
目標: 逆コンパイル/逆アセンブルされたコードを読んで、プログラムのロジックを理解する
使用する場面:
- 小規模で目的が絞られたプログラム(クラックミー、キージェネレーター)
- アルゴリズムの特定が課題となる場合
- 動的解析が妨げられる場合(アンチデバッグ、複雑な状態)
- 変換ロジックを理解する必要がある場合
アプローチ:
- 重要な経路を見つける - エントリーポイント → フラグ検証 → 成功
- 入力の流れを追跡する - ユーザー入力はどこへ進むのか?どのように使用されるのか?
- 処理を特定する - どのような変換が行われるのか?(XOR、ループ、比較)
- パターンを認識する - 既知のアルゴリズムに一致するか?(patterns.md を参照)
ReVa のワークフロー:
1. get-decompilation of entry/main function
- includeIncomingReferences=true to see program structure
2. Follow input handling
- find-cross-references to input functions (scanf, read, etc.)
- Trace data flow from input to validation
3. Analyze transformations
- rename-variables to clarify data flow
- change-variable-datatypes to understand operations
- set-decompilation-comment to document logic
4. Identify success criteria
- Find comparison or validation logic
- Extract expected values or patterns
動的解析:実行時の観察
目標: プログラムの実行中の動作を観察する
使用する場面:
- 制御フローが複雑な場合(静的解析では追いにくい)
- コードが難読化またはパッキングされている場合
- 中間値を確認する必要がある場合
- 時間依存または環境依存のチェックがある場合
アプローチ:
-
重要な箇所にブレークポイントを設定する
- 入力処理
- 変換処理
- 比較処理
- 成功/失敗の分岐
-
状態の変化を観察する
- レジスター/変数の値
- メモリの内容
- 関数の引数/戻り値
-
仮説を検証する
- 「X を入力すると、Y が起きるか?」
- 「ここではどの値が比較されているのか?」
注: ReVa は静的解析に重点を置いています。動的解析には、外部デバッガー(gdb、x64dbg など)を使用してください。
ハイブリッドアプローチ:両方の利点を活用する
CTF の課題で最も効果的です
ワークフロー:
- 静的解析:構造を特定する(検証関数と成功経路を見つける)
- 動的解析:実行時の動作を観察する(検証箇所にブレークポイントを設定し、期待値を確認する)
- 静的解析:変換処理を理解する(アルゴリズムを逆算する)
- 動的解析:解答を検証する(導き出したキー/フラグを試す)
例:
Static: "Input is transformed by function sub_401234 then compared"
Dynamic: Run with test input, breakpoint at comparison → see expected value
Static: Decompile sub_401234 → recognize as base64 encoding
Solve: base64_decode(expected_value) = flag
Dynamic: Verify flag works
問題解決の戦略
戦略 1:トップダウン(目標指向)
成功条件から始め、逆方向にたどります
使用する場面:
- 成功/失敗の指標が明確(「Correct!」または「Wrong!」と表示される)
- プログラムの構造が単純
- 必要最小限の理解を目指す場合
ワークフロー:
1. Find success message/function
2. find-cross-references direction="to" → What calls this?
3. get-decompilation of validation function
4. Identify what conditions lead to success
5. Work backwards to understand required input
例:
1. String "Congratulations!" at 0x402000
2. Referenced by function validate_flag at 0x401500
3. Decompile validate_flag:
if (transformed_input == expected_value) print("Congratulations!");
4. Now focus on: What's expected_value? How is input transformed?
戦略 2:ボトムアップ(データフロー)
入力から始め、検証まで順方向にたどります
使用する場面:
- プログラムの構造が複雑(関数が多数ある)
- 成功条件が不明確
- 変換処理を理解したい場合
ワークフロー:
1. get-strings regexPattern="(scanf|read|fgets|input)"
2. find-cross-references to input function
3. Trace data flow: input → storage → transformation → usage
4. Follow transformations until you reach comparison/validation
例:
1. scanf at 0x401000 reads into buffer
2. buffer passed to process_input(buffer)
3. process_input calls encrypt(buffer, key)
4. Encrypted result compared to hardcoded bytes
5. Now analyze: What's the encryption? Can we reverse it?
戦略 3:パターン認識
標準的なアルゴリズムや一般的な手法を特定します
使用する場面:
- 暗号チャレンジ(暗号化、ハッシュ化)
- エンコードチャレンジ(base64、独自エンコーディング)
- アルゴリズム実装のチャレンジ
ワークフロー:
1. Look for algorithmic patterns (see patterns.md):
- Loop structures (rounds, iterations)
- Constant arrays (S-boxes, tables)
- Characteristic operations (XOR, rotations, substitutions)
2. Compare to known implementations:
- read-memory at constant arrays → compare to standard tables
- Count loop iterations → indicates algorithm variant
- search-decompilation for crypto patterns
3. Once identified, apply standard solutions:
- AES → decrypt with known/derived key
- RC4 → decrypt with extracted key
- Custom XOR → reverse the XOR operation
戦略 4:制約充足
問題を数学的な制約として定式化します
使用する場面:
- シリアル/キーの検証(入力が方程式を満たす必要がある)
- 数学パズル
- 相互に関連する複数のチェック
ワークフロー:
1. Identify all constraints on input:
input[0] + input[1] == 0x42
input[0] ^ input[2] == 0x13
input[1] * 2 == input[3]
2. Extract to external solver (z3, constraint solver)
3. Solve for input values
4. Verify solution in program
例:
Decompiled validation:
if (flag[0] + flag[1] != 100) return 0;
if (flag[0] - flag[1] != 20) return 0;
if (flag[2] ^ 0x42 != 0x33) return 0;
Solve:
flag[0] + flag[1] = 100
flag[0] - flag[1] = 20
→ flag[0] = 60, flag[1] = 40
flag[2] ^ 0x42 = 0x33
→ flag[2] = 0x33 ^ 0x42 = 0x71 = 'q'
柔軟なワークフロー
CTF チャレンジは多種多様です。アプローチを適宜調整してください。
初期評価(5~10 分)
チャレンジを把握します:
- 何が提供されていますか?(バイナリ、ソース、説明?)
- 目標は何ですか?(フラグの発見、キーの生成、チェックの回避?)
- 制約は何ですか?(時間制限、ブラックボックス?)
ReVa の偵察:
1. get-current-program or list-project-files
2. get-strings-count and sample strings (100-200)
- Look for: flag format, hints, library names
3. get-symbols with includeExternal=true
- Check for suspicious imports (crypto APIs, anti-debug)
4. get-function-count to gauge complexity
集中的な調査(15~45 分)
最も有望な手掛かりを追います:
文字列からフラグ形式を見つけた場合: → フラグ文字列からトップダウンで調査
暗号 API を見つけた場合: → パターン認識(アルゴリズムを特定)
入力検証を見つけた場合: → データフローの追跡(入力から検証まで)
プログラムが単純(関数が 10 個未満)の場合: → 包括的な静的解析
プログラムが複雑、または難読化されている場合: → ハイブリッドアプローチ(動的解析で重要な箇所を見つけ、静的解析で理解する)
解決方法の抽出(10~20 分)
仕組みを理解したら:
-
逆変換できますか?
- 復号、デコード、数学的な逆演算
-
導出できますか?
- 制約を解く、比較から抽出する
-
総当たりできますか?
- キースペースが小さい、検証が高速
-
回避できますか?
- 比較をパッチする、状態を操作する
解決方法を検証します:
- 可能であれば、実際のプログラムでテストします
- フラグ形式を確認します(通常は flag{...} または CTF{...})
パターン認識
CTF チャレンジでは、標準的なパターンの認識が試されることがよくあります。詳しいガイドについては patterns.md を参照してください。
暗号パターン:
- ブロック暗号(AES、DES、独自方式)
- ストリーム暗号(RC4、独自方式)
- ハッシュ関数(MD5、SHA、独自方式)
- XOR による難読化
アルゴリズムパターン:
- エンコーディング方式(base64、独自アルファベット)
- 数学的演算(剰余演算、行列演算)
- 状態機械(状態を介した入力検証)
コードパターン:
- 入力検証ループ
- 文字ごとの比較
- 変換と比較の構造
- アンチデバッグの仕掛け(CTF の文脈において)
データ構造パターン:
- ルックアップテーブル(換字式暗号)
- ハードコードされた配列(期待値)
- バッファー変換
CTF での ReVa ツールの使用
検出ツール
興味深い箇所をすばやく見つけます:
get-strings regexPattern="(flag|key|password|correct|wrong|success)"
→ Find win/lose conditions
search-decompilation pattern="(scanf|read|input|strcmp|memcmp)"
→ Find input/comparison functions
get-functions-by-similarity searchString="check"
→ Find validation functions
解析ツール
中核となるロジックを理解します:
get-decompilation with includeIncomingReferences=true, includeReferenceContext=true
→ Get full context of validation logic
find-cross-references direction="both" includeContext=true
→ Trace data flow and function relationships
read-memory to extract constants, tables, expected values
→ Get hardcoded comparison targets
改善ツール
作業を進めながら、コードを読みやすくします:
rename-variables to track data flow
→ input_buffer, encrypted_data, expected_hash
change-variable-datatypes to clarify operations
→ uint8_t* for byte buffers, uint32_t for crypto state
set-decompilation-comment to document findings
→ "AES round function", "Compares against flag"
set-bookmark for important locations
→ type="Analysis" for key findings
→ type="TODO" for things to investigate
主な原則
1. 目標に集中
すべてを解析するのではなく、フラグの取得に集中します
- 重要な経路(入力 → 検証 → 成功)を特定します
- 関係のない関数は無視します
- 完全な理解より、十分な理解を優先します
2. すばやく切り替える
行き詰まったら、戦略を切り替えます
- 静的解析でうまくいかない場合は、動的解析を試します
- 複雑すぎる場合は、より簡単な方法(回避、総当たり)を探します
- パターンが一致しない場合は、独自のアルゴリズムかもしれません
3. 知識を活用する
CTF の課題では、概念が繰り返し使われます
- 標準的な暗号アルゴリズム
- よくある難読化の手法
- 典型的な検証パターン
- 既知の解法を認識して適用する
4. 進捗を記録する
学んだことを記録する
set-bookmark type="Analysis" category="Finding"
→ Document what you've confirmed
set-bookmark type="TODO" category="Investigate"
→ Track unanswered questions
set-decompilation-comment
→ Preserve understanding for later reference
5. 段階的に検証する
理解できているかを進めながら確認する
- 「これが AES なら、S-box 定数が見つかるはず」→ 確認する
- 「入力が 0x42 と XOR されているなら、output[0] は……になるはず」→ 例を使って検証する
- 「これがフラグの比較なら、このバイトを変更すると……になるはず」→ 仮説を検証する
よくある CTF の課題タイプ
Crackme / シリアル検証
課題: 検証を通過する入力を見つける アプローチ: データフローを追跡する(入力 → 検証ロジック) 重要なポイント: 検証関数に注目し、制約を抽出する
アルゴリズムの復元
課題: 不明なアルゴリズムを実装、またはリバースする アプローチ: パターンを認識し、処理を理解する 重要なポイント: 数学的なパターンを探し、変換を追跡する
暗号の課題
課題: 暗号文を復号する、または鍵を見つける アプローチ: アルゴリズムを特定し、鍵や IV を抽出して復号する 重要なポイント: 標準的な暗号のパターンを認識する(patterns.md を参照)
コードの難読化
課題: 難読化またはパックされたコードを理解する アプローチ: 動的解析を使って、難読化が解除された状態を観察する 重要なポイント: プログラムに処理させ、その結果を観察する
バイナリボム
課題: 各フェーズに正しい入力を与えて「爆弾」を解除する アプローチ: フェーズごとに解析し、静的解析と動的解析を組み合わせる 重要なポイント: 各フェーズでは通常、異なる概念が試される
独自のエンコーディング
課題: エンコードされたフラグをデコードする、または入力を正しくエンコードする アプローチ: エンコーディング方式を特定し、逆変換するか再現する 重要なポイント: 変換ループや文字マッピングを探す
他のスキルとの連携
バイナリのトリアージ後
トリアージで疑わしい領域を特定したら、CTF に焦点を当てて深く調査します
From triage bookmarks:
- "Crypto function at 0x401234" → Identify algorithm, extract key
- "Input validation at 0x402000" → Understand constraints, solve
- "Suspicious string XOR" → Decode to find flag or hint
詳細な解析の利用
関数を詳しく理解する必要がある場合
CTF skill identifies: "Validation at validate_key function"
Deep analysis answers: "What exactly does validate_key do?"
CTF skill uses result: Apply findings to extract flag
ワークフロー:
- CTF スキル:大局的な戦略を立て、重要な関数を特定する
- 詳細な解析:特定の関数を詳しく調査する
- CTF スキル:調査結果をまとめ、解法を導き出す
成功の基準
次のことができれば、課題を解いたことになります:
-
理解を示す:
- 入力がどのように出力になるか説明する
- 検証の仕組みを特定する
- 中核となるアルゴリズムや手法を認識する
-
解答を導き出す:
- フラグ、鍵、パスワードを提示する
- どのように導き出したか説明する
- 動作を確認する(テスト可能な場合)
-
調査の過程を記録する:
- 重要な関数とアドレス
- 重要な変換や比較
- 解法(逆変換、導出、総当たり、回避)
覚えておくこと
CTF のリバースエンジニアリングは、制約下での問題解決です:
- 時間は限られています
- 完璧な理解ではなく、十分な理解が必要です
- 目標はフラグであり、網羅的な解析ではありません
- 見つかったものに応じて戦略を調整します
- パターンや既存の知識を活用します
- 必要に応じて静的解析と動的解析を切り替えます
次の問いに答えることに集中します:
- プログラムは何を想定しているか?(入力の形式や構造)
- プログラムは何をするか?(変換や検証)
- どうすれば逆算できるか?(導出、復号、解法の特定、回避)
この3つの問いに答えれば、フラグが見つかります。