apk-reverse について
apk-reverse は、Android APK の解析とパッチ適用を行い、検証済みでインストール可能な成果物を目指す手順スキルです。対象のコード層の特定、制御された実験、ツール能力の確認、証拠の範囲を重視します。
主な機能
- 01対象とコードの担当層を分類
- 02成果物の条件を定め基準を記録
- 03インデクサーと層別ツールを活用
- 04観測、推論、未知の結果を区別
- 05パッチ済み成果物をインストールして検証
活用シーン
- 01パッチ前に APK 内のチェック箇所を特定
- 02パッチが効かない原因を調査
- 03デバイスで変更済み APK を検証
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ zzusec/ apk-reverse --skill apk-reverseインストール後、Claude Code で/apk-reverseを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
evals/evals.jsonevidence/capability-matrix.jsonknown-limitations.mdtested-tool-versions.jsonreferences/account-gates.mdad-removal.mdadvanced-unpacking.mdbyte-level-patching.mdcode-virtualization-and-custom-linkers.mdcoverage-and-limits.mddart-aot.mddesensitization-and-leak-scans.mddetection-and-anti-analysis.mddex-patching.mddexsql-sql-query-layer.mddynamic-frida.mdemulation-and-rpc.mdenvironment.mdete-diff-tracing.mdevidence-summary.mdframework-runtimes.mdhandoff-boundaries.mdhardware-sampling-and-crash.mdhardware-watchpoints.mdjava2c-and-jni-sinking.mdkernel-and-environment-hardening.mdkernel-event-injection.mdlong-task-discipline.mdlsposed-and-modules.mdreferences/coverage/route-inventory.md詳細
APK のリバースエンジニアリングとパッチ適用
目標:検証済みで、インストール可能かつ、引き続き正常に動作する成果物をすばやく作り、見た目にはまったく問題がないのに APK を壊してしまう一連のミスを避けます。
まずはこれを実行 — 何よりも先に、次の4つを行ってください
このファイルは手順とゲートを定めたものであり、背景説明ではありません。また、長いため途中が読み飛ばされがちです。そこで、まず4つの手順を示し、以下でその理由を説明します。
1. 手段を選ぶ前に分類してください。 §Start here の13個の質問に答えてください。R4によって、そもそも適切な層を編集しているかどうかが決まります。誤った分岐を選んでも、はっきりと失敗するとは限りません。ビルドできて、実行もできるのに、意図しない動作をする成果物ができあがります。
2. §Gates に記載された合格基準に従い、4つのゲートを順にクリアしてください。 G1 では作業を始める前に、成果物の形式を検証可能な一文で定めます。G2 では、このマシンで実際に何ができるかを確認します。G3 ではコードの場所を特定します。G4 ではベースラインと対照を記録します。「考え方は理解した」だけでは、ゲートをクリアしたことにはなりません。
3. 説明できない症状は、謎解きではなく停止の合図です。 次の試行をする前に、§Symptom index で症状の形を探し、その行で指定されたファイルを読み込んでください。各項目は、調査に何時間もかかった経験から記載されています。いくつかのケースでは、原因を再び突き止めようとする前に、すでに答えが書き残されていました。
4. 同じ形の試行で2回失敗したら、3つ目の方法を試すのではなく、分類に戻ってください(§Stop conditions)。また、§What "done" means にある6つの項目を満たさずに、完了したと報告することは絶対に避けてください。
このファイル自体に関する2つのルール。 失敗の原因が計画と合わない場合、次に行うべきことは症状インデックスを確認することであり、さらに考え続けることではありません。また、このファイルの記述と自分の推論が食い違う場合、覆す証拠が得られるまでは、このファイルに従ってください。ここにある各ルールは、何時間もの損失につながった失敗の積み重ねから得られたものです。いまの直感は、まだその失敗に遭遇していない人の直感です。
他のすべてに優先する4つのルール
R1 — 対象に手を加える前に、成果物を検証可能な一文で定義してください。
「動くこと」が目標ではありません。「指定された制約のもとで動くこと」が目標です。root 権限を使った方法、実行時インストルメンテーション、ホスト側プロキシ、パッチ適用済みデバイスでの結果は、通常のスマートフォンにインストールして動作する成果物という要件を満たさないことがよくあります。それでも、そのような結果を完成品として提示してしまいがちです。一文を書き、各チェックポイントで読み直してください。要件を満たせない場合は、率直に伝え、特権を必要とする回避策には、成果物ではなくフォールバックと明記してください。
→ references/long-task-discipline.md §the most expensive drift
R2 — 変数は一度に1つだけ変更し、対照ビルドを保持してください。
2つの要素を同時に切り替える実験は、失敗しても何も学べません。原因を特定できない失敗は、誤った原因に結び付けられてしまいます。「アプリが X を拒否する」という主張には、それぞれ個別の実行が必要です。また、すべてのパッチについて、同じパイプラインで作成し、以前と同じ失敗が続く対照が必要です。
→ references/long-task-discipline.md §single-variable discipline
R3 — 検証していない成果物を出荷したり、検証済みだと主張したりしないでください。
「組み立てられた」は「動く」と同じではありません。「プロセスが開始した」は「機能が動く」と同じではありません。「ログにエラーがない」は「チェックがなくなった」と同じではありません。インストールして起動し、変更した機能を実際に操作して、画面を確認してください。デバイスで実行中のビルドが自分の作成したものだと証明してください。ファイル名を信用せず、ハッシュを確認してください。
→ references/verification.md
R4 — パッチを適用する前に、該当する層を特定してください。実際の状況と食い違う場合は、分類し直してください。
広告、ペイウォール、機能ゲート、インテグリティチェック、アップデートゲートは、異なる層(Java、dex、ネイティブ、Dart/Unity、サーバー)に存在します。誤った層にパッチを適用すると、何も起きないか、アプリが壊れます。パッチが「効果なし」だった場合、診断が間違っています。パッチをさらに強めるのではなく、分類に戻ってください。
→ references/recon.md、次に症状インデックスで指定された層別ファイル
ツール選び — 適切なツールを使い、利用できないと判断する前に確認してください
この分野で無駄な試行錯誤の大半は、対象についての推論が誤っているからではありません。答えを出せないほど弱いツールに、適切な質問をしていることが原因です。インデックス化されたクエリを1回実行すれば済むのに、手動でエクスポートしたsmaliツリーをgrepで1時間調べたり、pip installですぐ使えるデコンパイラーがあるのにELFを手作業でたどったりします。弱い方法でも出力は得られるため、内側からは問題が見えません。
5つの義務。これは指示です。違反は好みの問題ではなく、不備です。
| 義務 | 実施すること | 無視した場合の代償 |
|---|---|---|
| エクスポートではなくインデクサーで全体を把握する | コードを読む前に、アーティファクトに質問する手段を整えます。droidasc findrefs / ddc findrefs(文字列/型/メソッドから、1秒未満ですべての参照箇所を検索)と、呼び出し元となるメソッド、数値定数を持つメソッド、デバッグ行テーブルなど、質問が結合または集計に関する場合はdexsql queryを使います。クラス一覧を取得するためのものではありません。デコンパイルで読めるのは、すでに場所を特定したクラスです。場所を特定する手段ではありません。jadxは最後の手段として使う読みやすいビューアーであり、信頼できる唯一の情報源でも、調査の出発点でもありません | 先に時間をかけてエクスポートしたものを対象に、質問のたびにgrepで何時間も費やすことになります |
| 不足しているツールをインストールする。それも作業の一部です | arm64用デコンパイラーがない場合、次の手順はインストールです。回避策を探す制約ではありません。インストールが本当に不可能な場合に限り、人に相談します | デコンパイラーなら数分で出せる結果を、手作業で何時間もかけて再導出することになります |
| その不足を補うために時間を使う前に、ギャップを明示する | 阻害要因を解消するために必要な機能と、このマシンにその機能があるかどうかをはっきりと述べます。これはG2の項目です | 10分でインストールできるツールを前提にせず、設計を進めることになります |
| スクリプトを書く前に、提供済みのスクリプトを使う | 解析、ハッシュ計算、アライメント、ホットプラグのプローブはすでに用意されています。scripts/dex_find_insn.pyの代わりに独自スクリプトを書くと、オフセットを計算せずに推測することになります | デコードは問題なくできても、誤った動作をするオフセットが得られます |
| 質問が扱うレイヤーに合ったツールを選ぶ | メモリ上のdexにはdex_mem_scan.py(検索と切り出し)に加えてdex_dump_validate.py(判定)が必要です。断片をデコンパイラーに渡すのではありません。呼び出すだけでよいアルゴリズムにはemulation-and-rpc.mdを使います。「このクラスは実行時にロードされるか」という質問には、発火するかどうかを確認するフックを使います | 重いツールがより安全とは限りません。もっともらしい答えが得られるため、答えが得られない場合よりも悪い結果になります |
利用できないと結論づける前に、python skills/apk-reverse/scripts/doctor.py --jsonを実行してください。
機能ごとの依存関係の充足状況、不足しているもの、インストールにかかるおおよその時間が報告されます。確認していない機能は、利用できない機能ではありません。**このツールは意図的にBLOCKEDを報告する場合があります。**JVMはあるもののzipalign/apksignerがないマシンでは再署名できません。ツールが存在するだけで機能があると推測せず、そのことをレポートに示します。詳細はreferences/toolchain.mdを参照してください。読み込むレジストリはscripts/capabilities.pyです。
対応範囲 — このスキルが主張すること、主張しないこと
このセクションが防ぐのは、知識不足による失敗ではありません。対象向けに書かれていない手順を、手近にあるというだけで適用し、自信たっぷりに誤答を出すことです。 ほぼ当てはまる文書化済みの手法は、計画と用語、そして安心感を与える数字を伴うため、手法がまったくない場合より危険です。
主張の確度 — これは見た目の問題ではなく、土台となる要件です。 このスキル内のすべての主張には4つのラベルのいずれかが付いています。自分の結果にも、同じようにラベルを付けてください。
| ラベル | 意味 | 判断の根拠にできるか |
|---|---|---|
observed | コマンドを実行し、その出力が存在する | はい |
inferred | 観測結果から導かれるが、その過程には推論が含まれる | 暫定的には可 |
unverified | 仮定されている、または別の場所で報告されているが、ここでは再現されていない | 検証対象としてのみ |
unknown | ここでは何も扱っていない。プローブを実行していないか、プローブの対象範囲が届いていない | いいえ — そして、決して「存在しない」という意味ではありません |
否定的な結果には3つの形があり、それらをひとまとめにすることこそ、このセクションが防ごうとしている失敗です。 unverified は、誰かが何かを主張したものの、ここでは裏付けを取っていないという意味です。unknown は、証拠をまったく集めていないという意味です。一方、実行したプローブの結果が空だった場合には、異なる意味が2つあり、そのうち発見と言えるのは一方だけです。
- absent — プローブの対象範囲がその問いに及んでおり、対象が実際に存在しない。
- present but unreadable — 対象は存在するが、この経路では読み取れない。たとえば、シェル内の暗号化されたペイロード、実行中の ABI が読み込まないライブラリ、フックの準備が整う前に発火するチェック、パーサーが拒否する型で存在するフィールドなどです。
危険なのはこちらです。前者とバイト単位で同一の出力になる一方、このスキルが対象とする強化済みターゲットでは通常はこちらが起きるからです。したがって、難読化された APK からクラスが4つ返ってきても、その APK にクラスが4つしかないという意味ではありません。「存在しない」と記録する前に、その問いを対象範囲に含むプローブを明示し、必ずヒットするはずの対照テストを実行してください。対照テストも無反応なら、正直に言えるのは「ターゲットに存在しない」ではなく、プローブについての unknown です。次にすべきことは、より強い結論を出すことではなく、別のプローブを使うことです。
推測に代わるインベントリ: 検証済みの仕組みと、文書化されているものの大半が推論に基づく経路について、経路ごとの対応範囲と非対応範囲をまとめた一覧は、references/coverage-and-limits.md にあります。「このスキルで実際に X ができるか」が問いであれば、これを読み込んでください。
過大解釈しやすい部分的な対応範囲 — これらは、このスキルに依存要素が含まれていない文書化済みの経路です。同じファイル内で、それぞれに制約が明記されています。Dart AOT の解析には別途入手する必要があるスナップショットダンプが必要で、フロントエンドの選択も重要です · 抽出シェルの復元は VMP の境界で止まります · すべてのデバイスで Stalker トレースが保証されるわけではありません · カーネル側の回答には、このスキルが足場だけを用意するモジュールが必要です。
非対応 — 即興で補わず、その旨を伝えてください: Unity / IL2CPP · React Native / Hermes / Cordova · iOS · サーバー側の権限による制御の回避 · 既製のアンパッカーやアンチ検出をめぐる競争 · カーネルモジュールのビルドと配布。理由と証拠の境界は references/coverage-and-limits.md にあります。この記録に記載がないことは、対応している証拠にはなりません。
代替手段を指示として示します — これは助言ではなく、規則です。 ターゲットが対応範囲の一覧に合わない場合、または症状インデックスのどの行にも当てはまらない場合は、いったん止まり、分岐先を選ぶ前に分類してください。13の質問(§Start here)に答えてください。それでも状況に当てはまらない場合 — 不明なランタイムや、名前を特定できない仕組みなど — そのまま明言し、特定に必要な最小コストの実験を提案してください。 最も近い文書化済みの経路を選んで、そのまま適用してはいけません。ここで誤った分岐を選んでも、エラーが明確に出るとは限りません。ビルドできて、実行できて、しかも誤った動作をする成果物ができあがります。
引き継ぎポイント — このスキルが終わり、別の視点が始まる場所
気づかないうちに踏み込みやすい境界が4つあります。それぞれ、同じ助言が2か所に書かれて食い違うのを避けるため、内容を繰り返すのではなく、もう一方が担当する内容を示しています。JNI の形式をまとめた表と、形式ごとの検証表は references/handoff-boundaries.md にあります。
- JNI — Java の
native宣言とその実装は、1つの関数を別々の視点から見たものです。このスキルでは、それぞれ異なるツールで確認します。動的登録では、シンボル検索は何も通知せずに失敗します。詳しい説明:java2c-and-jni-sinking.md§The JNI boundary — why a symbol search fails silently. - ハードニング — dex 側で観察したパッカーは、ネイティブ側の実装に関する問題です。dex 側の識別は
packers.mdが担当し、詳細な調査はもう一方に任せます。 - ネイティブの異常 — パッチが原因でクラッシュしたかどうかを判断するため、APK 側から確認します。シンボルの復元や OLLVM 関数のリバースエンジニアリングは、異なるツールチェーンを使う別の作業です。
native-and-so.mdの範囲を広げず、別の資料を案内してください。 - 成果物の形式 — 成果物が APK でなくなると、検証すべき内容も変わります。G1 の他の3つの形式では、それぞれ証拠の所在が別の場所に移ります。しかも失敗は静かに起きます。ビルド完了後の言葉で、特権的な結果が報告されます。
症状インデックス — 該当する項目があれば、そこで止まってください
ファイル名ではなく、症状からたどり着くことがあります。以下の各項目は、すでに代償を払った失敗です。観察している現象が1つでも該当するなら、次のコマンドを実行する前にそのファイルを読み込んでください。次の3回の試行の後ではありません。この段階で第一原理から考え直すと、同じ時間を二度費やすことになります。ここにある項目のいくつかは、答えがこのリポジトリで読まれないまま見つかるまで、人手で再発見された教訓です。
| 観察される現象 | 最初に読む項目 |
|---|---|
再パッケージ/再署名したビルドがコード実行前にクラッシュする。SIGSEGV、全レジスターがゼロ、pc=0、fault addr が 0x0 付近 | native-tamper-and-suicide.md(意図的なクラッシュ)、次に code-virtualization-and-custom-linkers.md |
| パッカーなし(アプリケーションはアプリ本来のもので、dex は読み取り可能)なのに、やはりクラッシュする | code-virtualization-and-custom-linkers.md §ローダーの可能性はまだあります。ただし、同じビルドが別の無関係なデバイスでもクラッシュするなら、強化されたものではなく、通常の起動時障害です |
パック済みかどうかにかかわらず、すべてのデバイスで起動時にアプリがクラッシュし、crash_dump が already traced、logcat が exited cleanly (0) と表示する一方で、tombstone がない | バンドルされたクラッシュレポーターがシグナルハンドラーを取得しているため、プラットフォーム独自の記録は残っていません。復旧手段は Frida の spawn-gating です |
Flutter アプリで最初のフレームが完了する前に、メインスレッドで FORTIFY: pthread_mutex_lock called on a destroyed mutex による abort が発生する | dart-aot.md — libapp.so が実際に読み込まれているか確認してください。ネイティブのライフサイクル障害が表面化する場所は、通常 Flutter のエンジンのブートストラップです |
| Java 層の署名/整合性チェックが成功したとログに出ているのに、プロセスがクラッシュする | code-virtualization-and-custom-linkers.md §Java 層の「署名キラー」はおとりです |
ライブラリーを削除すると検証は通るが、UnsatisfiedLinkError: dlopen failed: library "X" not found が発生する | code-virtualization-and-custom-linkers.md §何時間も費やすデッドロック |
クラス全体が、本体のない native 宣言として現れる | java2c-and-jni-sinking.md — メモリーをダンプする前に読んでください。これが Java2C なら、プロセスの実行中に DEX が見つかることはありません。通常の dex に native メソッドが少数あるだけなら、これは Java2C ではなく JNI sinking です |
強化されたライブラリーに対する Java_* 検索で何も見つからない | java2c-and-jni-sinking.md §JNI 境界 — シンボル検索が何も返さない理由 — 動的登録、または -fvisibility=hidden。有効な確認方法は「JNI_OnLoad をエクスポートし、Java_* はゼロ」です |
| 実際の作業を引用した証拠ファイル、トランスクリプト、README を公開しようとしている | references/desensitization-and-leak-scans.md — コミットする前に scripts/scan_leaks.py を実行してください。一致箇所の一覧は確認すべき行のリストであり、誤った抑制を見つけるには --show-exempt を使います |
| フッキングモジュールが実行されたように見えるのにログタグが出ず、「一度もロードされていない」と記録しようとしている | references/precedents/logd-broken-module-never-ran-case-3.md — logd が壊れていると logcat には何も届かず、モジュールの実行記録はすべて LSPosed のファイルログに残ります。両方の経路を確認してください |
| ライブラリーのSONAME がファイル名と一致しない | code-virtualization-and-custom-linkers.md、native-and-so.md |
| 編集してもまったく効果がなく、エラーもない | server-config-and-updates.md §3(値がサーバーから送信されている可能性があります)、次に packers.md §検証境界の特定 |
プロセスが記録なしにハングする、または uid 0 のキラーによって終了する | native-tamper-and-suicide.md §ルール(おそらく終了経路を復帰しないようにしてしまっています) |
| 強化されたライブラリー内で通常のヌルポインター参照のように見えるクラッシュ | native-tamper-and-suicide.md §意図的なクラッシュ用スタブ |
| アタッチ中/root 化中にだけアプリがクラッシュする | detection-and-anti-analysis.md。まず同じ条件で未変更のオリジナルを実行してください |
[-124] でインストールに失敗し、resources.arsc/アラインメントに言及する | repack-and-sign.md §2a — STORED かつ4 バイトアラインメントの両方が必要です |
INSTALL_FAILED_* がなく、裸の数値コード(例:[-99])でインストールに失敗する | repack-and-sign.md §ベンダーのインストール横取り — ビルドではなく、デバイス側のインターセプターです。root の pm install 経路を使ってください |
インストール後、am start が何もしない/スクリーンショットに別のアプリが映る/am start -W がハングする | repack-and-sign.md §インストーラーがまだ画面を占有している可能性があります |
Failure to verify dex file ...: Bad checksum というログと、通常のクラスに対する起動時の ClassNotFoundException が出る | byte-level-patching.md §dex ヘッダーには 2 つの整合性フィールドがある — 順序が重要です |
| インストールは「成功」したが何も変わらない、またはバージョンが変わらない | long-task-discipline.md §観察時間帯をクリーンに保つ |
| 証拠に矛盾がある、またはキャプチャに 2 つの状態が混在しているように見える | long-task-discipline.md §観察時間帯をクリーンに保つ |
| スクリーンショットを撮ったのに、ログやパッチ自体から結論を導き出した | long-task-discipline.md §見ていないキャプチャは証拠ではない |
| すでに結果を記録した実験を再実行しようとしている | long-task-discipline.md §長いコンテキストの劣化 |
| スクリプトが起動しない、またはツールが「見つからない」 | scripts/doctor.py、次に toolchain.md §「PATH にない」は「インストールされていない」ではない |
| フックやプローブがイベントをまったく報告せず、検出だと判断しようとしている | まず環境の自己報告を確認する scripts/anti_detect_probe.js、次に detection-and-anti-analysis.md §ステップ 3:チェックの特定 — ステージ 0 からの検索順序 |
プロセスがまだ ps に表示されている間に attach がハングして失敗する | detection-and-anti-analysis.md §ステップ 3 ステージ 0 — /proc/<pid>/stat の D を確認し、対象のせいにする前に、1 行の対照テストとして別の pid にアタッチしてください |
| tombstone、クラッシュ、ANR の記録なしにアプリが終了する | detection-and-anti-analysis.md §ステップ 3 — 正常な自己終了は、フックが存在する前にチェックが実行されたことを意味します。そこにある分岐条件から該当ステージを特定してください |
ダンプ領域の検証結果が別のものになる、または base.apk の r--s ビューが dex に見える | advanced-unpacking.md §この手法でできないことと、時間を費やす前にそれを見分ける方法 |
| 機能単位のネットワーク障害(ログイン/登録/決済)が起きる一方、ほかは正常に動作する | tls-and-cert.md — パッチが原因だと決めつけないでください |
| すべて正常に動作するが、再パッケージ後に署名付きリクエストがすべて失敗する | signature-derived-keys.md |
再署名したビルドが正常に実行され、UI 全体が表示され、エラーも記録されないのに、ある機能だけがひっそりと読み込まれない。さらに dumpsys/DNS/logcat にその機能へのリクエストがまったくない(リクエストが拒否されたのではなく、リクエストがない) | code-virtualization-and-custom-linkers.md §ネイティブチェックが実際に読み取るもの — リクエストの構築前に拒否されています。上の行とは異なり、「送信されたが拒否された」と「送信されなかった」では原因が異なります |
| 機能がないのは自分のパッチのせいか、対象本来の動作か判断できない | long-task-discipline.md §単一変数の原則。同じパイプラインで変更ゼロの対照テストを実行し、決定的なバリアントとして、同じデバイス、同じネットワークで、未変更のオリジナルにパッチをメモリー上だけで適用してください |
Frida の spawn 中に UI が表示されない — mCurrentFocus が null のまま、スクリーンショットが空白になり、Activity スタックが構築されない | dynamic-frida.md §spawn は Activity スタックを止める:パッチをメモリーに書き込み、detach してから Activity を通常どおり起動してください |
実験の途中で frida-server が何度も消える、または作業中にデバイスが再起動する | dynamic-frida.md §ROM が計測を探知する場合 |
| 広告を消すはずのパッチを適用した後も広告が表示される | server-config-and-updates.md §6(キャッシュされた設定/リモートからの再有効化)、次に ad-removal.md §ステップ 4(SDK 自身のログ行数を数える。n -> 0 であり、「見かけなかった」ではありません) |
| 強制アップデートまたは「アップデート必須」のゲートによってビルドがブロックされる | updates-and-forced-upgrade.md §ステップ 6 |
| ダイアログは消えたが、機能はまだロックされている | membership-and-limits.md / account-gates.md — 再びパッチを当てる前に、権限を決めるのがサーバーかクライアントか判断してください |
| 経路を「ブロックされている」として捨てようとしている | packers.md — 経路を断念する前に読み直してください。失敗原因の誤認により、実行可能な経路が何時間も失われた例があります |
| 作業が長引き、何がすでに証明されているか分からなくなっている | long-task-discipline.md §記録を常に更新する |
ダンプした dex は全体を解析でき、クラスもすべて揃っているが、ほとんどのメソッド本体が return-void のスタブか nop 埋めになっている | references/advanced-unpacking.md — 抽出シェルです。内容を信頼する前に scripts/dex_dump_validate.py で stub% を測定してください。本体の復元は別の経路だと理解しておきましょう |
frida のダンプが書き込み途中で終了する(script has been destroyed)、またはダンプ対象のプロセスの pid が変わり続ける | advanced-unpacking.md §frida が拒否された場合のダンプ — まずメモリー不足を除外してください。メモリーの回収と再起動には計測は不要です |
| 複数の独立したチェックによって再パッケージが拒否される、またはストアのアップデート後もビルドを動作させ続ける必要がある | references/lsposed-and-modules.md — APK の代わりにモジュールを提供してください。G1 のフォーム表に、どのような場合に使うかが示されています |
| フックモジュールがインストール、有効化、スコープ設定済みなのにログタグが出ず、一度も実行されていないと結論づけようとしている | lsposed-and-modules.md §デプロイ、有効化、検証 — ここでは logcat だけに基づく判断がすでに間違いだと判明しています。ある ROM では logd が壊れていて、出力は /data/adb/lspd/log/modules_<ts>.log にしか届きません |
| モジュールのエントリークラスが自身の dex に存在しないためロードできないのに、パッケージはインストールされ、有効化され、正常に見える | references/lsposed-and-modules.md — assets/xposed_init と dex の実際のクラスを照合してください。インストールされていることは、何かの証拠にはなりません |
| アプリを変更するのではなく、対象自身のルーチン(署名、トークン、暗号化)を呼び出すだけでよい | references/emulation-and-rpc.md — エミュレートするか、Frida RPC を介して実行中の関数をサービス化してください |
ネイティブ関数が数千行に及ぶ switch のステートマシンである、または逆コンパイラーの出力が意味をなさない | references/native-dbi-and-deobfuscation.md — OLLVM の構造、Stalker トレース、トレースで実際にどこまで分かるか |
Stalker.follow を設定できるがイベントが届かない、または頻繁に呼び出される libc エクスポートを追跡するとプロセスがクラッシュする | references/native-dbi-and-deobfuscation.md §6 失敗モード — このリポジトリーでは両方を計測しています |
コード変更なし、スレッド注入なし、TracerPid = 0で対象を観察または変更する必要がある — ページチェックサムによってすべてのフックが検出される | hardware-watchpoints.md — 正直なステルス性の記録を伴う ptrace 経由のハードウェアデバッグスロット、次にトレーサーが一切不要なカーネル設定経路として kernel-event-injection.md |
| クラッシュのバックトレースを信頼できない — 誤ったモジュール内や匿名領域のフレーム、平坦化/仮想化されたコード、または破壊されたスタック | hardware-sampling-and-crash.md — 実際の制御フローを示す BRBE 分岐レコード/ETE テール、次に scripts/trace_addr2sym.py で各 PC をシンボル化します |
| 実行時アドレス(ヒット、トレースの PC、分岐点)のリストがあり、16 進数ではなくシンボル/静的オフセットが必要 | hardware-sampling-and-crash.md §3 クラッシュループ — vaddr/ファイルオフセットの規則に従った scripts/trace_addr2sym.py |
| 仮想化された関数のトレースが、インタープリターループの繰り返しだけでノイズのように読める | scripts/vm_handler_slice.py — ディスパッチャーのエントリーでハンドラーセグメントを切り出し、シグネチャをクラスタリングし、ゲストオペコードの軌跡を復元します(xvmp で較正済み) |
目の前にある table[index]; br がVM ディスパッチャーか OLLVM ディスパッチャーか判断できない、または VM に読み取り可能な静的構造がまったくない | references/native-vm-recovery.md — 2 つの積層レイヤーを区別する動作テーブル、VM 存在の兆候、3 重検証によるレジスターのアンカー設定、ネストした VM のセグメントスタック、STORE からの逆方向オペランドスライス |
| トレースセグメント自体が破損しているように見える — ハンドラーの先頭が欠落し、末尾が誤ったセグメントに結合している | references/native-vm-recovery.md §7 ネストした VM — フラットなセグメントアキュムレーターでは外側のレベルが破棄されます。ネストしたスライスにはセグメントスタックが必要です(vm_handler_slice.py が症状を検出します) |
| 同じ操作(パスワード/ライセンス/キー)の 2 回の実行でどこが異なるかを知りたい。実行された内容だけでは不十分 | ete-diff-tracing.md — ETE ハードウェアトレースによるゲートと差分分析の手法。scripts/trace_diff.py では Stalker ログの差分も取れます |
| 生成された KPM/LKM テンプレートを目の前にしている、またはカーネル経路が計画の中心になっている | kernel-event-injection.md — プリミティブのマップ、組み合わせのレシピ、カーネル側の各ファイルを武器として使う前に通過しなければならないゲート |
| 通信が protobuf/gRPC/QUIC である、または Flutter アプリでプロキシが TLS を確認できるのにリクエストが失敗する | references/protocol-reverse.md — スキーマなしの protobuf、フレームキャプチャ、ネイティブ側のピンニング |
ユーザー空間のフックを仕掛けてもアプリがクラッシュする。チェックが raw svc を介して /proc/self/status を読み取る、または JNI_OnLoad より前に実行される | references/kernel-and-environment-hardening.md — 上下のレイヤーで実際にできることと、作業を打ち切るべきタイミング |
| 端末本体で APK の編集、再パッケージ、署名、検査をする必要がある | references/on-device-tooling.md、scripts/mt_mcp_probe.py |
| キャプチャした本文をデコードしても読める内容が出ない、または長さ区切りフィールドが文字列、ネストしたメッセージ、パック配列のどれか判断できない | protocol-reverse.md。ワイヤー上の protobuf(実測) — scripts/protobuf_decode_raw.py を実行してください。候補リストと tie: の行が答えです |
| メソッド本体はあるがプライベートオペコードとしてデコードされ、VMP が難しい理由の説明ではなく対応表が必要 | vmp-differential-analysis.md、次に構造の診断には advanced-unpacking.md |
ストアのビルドが base.apk + split_config.*.apk として届く、または各ファイル単独では検証できるのに、再構築したビルドがセットとして拒否される | split-apk.md — pm install-multiple ではすべての構成要素に同じキーストアを使い、結合した単一 APK を信頼する前に、結合が合法か確認してください |
ゲート — パッチを当てる前に、順番にクリアする
各ゲートは、合格基準を伴うアクションです。クリアしていないゲートを越えて先に進んではいけません。「考え方は理解した」ことをクリアとみなしてはいけません。ゲートを飛ばすのは近道ではありません。作業をやり直すことになる道です。
G1 · 成果物の形式 — およびそのコスト上限。 最終的にどのような成果物が存在すべきか、どのような制約があるか(root化が必要か、標準状態のデバイスにインストールできる必要があるか、アップデート後も動作する必要があるか、オンラインかオフラインか)を、誰かにそのまま伝えられる一文で述べてください。合格: その一文に、作業内容ではなく、検証可能な制約が含まれています。不合格: 成果物が使われることのない環境で問題を解決しようとしています。
次に、その一文が示す形式を選んでください。「再構築した自己完結型 APK」は4つの選択肢のうちの1つにすぎません。この選択をするのは、再パッケージに失敗した後ではありません。
| 形式 | 適切なケース | 必要なコスト |
|---|---|---|
| 再構築してインストール可能な APK | クライアントが動作を担っており、複数箇所での整合性チェックがなく、抽出シェルもない場合 | 再パッケージ、再署名、および検証用のデバイス |
| LSPosed / Xposed モジュール | ロジックはクライアント側にあるものの、アプリが再パッケージに対抗する場合(複数箇所での署名チェック、シェルによる自己検証など)、または管理下のroot化デバイスでのみ動作すればよい場合 | root化デバイス、モジュールの土台、およびフックフレームワークを検出してはならないアプリ → references/lsposed-and-modules.md |
| ローカル RPC / エミュレーションサービス | アプリを変更する必要はなく、署名ルーチン、トークン、暗号化関数などの呼び出しが必要な場合 | 稼働中のデバイス、またはエミュレートしたローダーと呼び出し用ハーネス → references/emulation-and-rpc.md |
| 境界を明示した解析レポート | 権限がサーバー側にある場合、または対象が本格的な VMP / 抽出シェルで、復旧コストが作業の価値を上回る場合 | 出荷するものはありません。それが正直な答えであり、失敗ではありません → references/advanced-unpacking.md、references/server-api.md |
最初の列から切り替える判断基準: 証拠から (a) すべて通過させる必要がある独立した整合性チェックが複数ある、(b) メソッド本体が呼び出し時にしか存在しない抽出シェルがある、または (c) プライベートオペコードとしてデコードされる本体がある、と分かった時点で、「再構築した APK」の選択をやめてください。その時点で再パッケージの手法は、単にコストが高いのではなく、実行不可能です。成果物を述べる文には、代わりに選んだ形式を明記してください。ここで選んだ形式を各チェックポイントで読み返すことが、このスキルで最もコストの高い軌道逸脱を防ぐ手段です(references/long-task-discipline.md)。
G2 · 環境の実態と機能の棚卸し。 scripts/doctor.py を実行してください(デバイスを使う場合は scripts/preflight.py も実行してください)。合格: この環境で実際に実行できるツールチェーンとスクリプトが分かり、環境に関する警告(時計のずれ、残存する adb forward / プロキシ、すでに実行中のデバイス側 frida プロセス、PATH 外にインストールされたツールなど)を確認し、この対象に必要な機能と、このマシンが持つ機能を比較して書き出しています。 タスクでほぼ確実に必要となる2~3のレイヤー(たとえば「arm64 ネイティブコードの逆コンパイル」「Dart AOT スナップショットのダンプ」「デバイス側 TLS の検査」「dex 全体の相互参照」)を挙げ、それぞれを利用可能/不足しているがインストール可能/実質的に利用不可能に分類してください。不合格: 自分の環境が原因の失敗を対象のせいにしようとしている、または10分でインストールできるツールを回避するために1日費やそうとしています。ツールが不足しているレイヤーはタスク項目であり、それを回避するよう設計するための制約ではありません。→ references/toolchain.md §機能不足の解消
G3 · コードの場所。 マニフェストと dex から、パッカーが存在するか、アプリ独自のコードがどこにあるか(dex/ネイティブ/Dart/Unity/サーバー)、またその一部がネイティブに仮想化されているかを回答してください。合格: 変更する予定の動作を担うクラスを特定できるか、見つけるための具体的な計画があること。不合格: まだ特定していないレイヤーにパッチを当てようとしていること。調査で「パッカーなし」と判断した場合も、仮想化の形態を確認してください。上記のインデックス行を参照してください。
G4 · ベースラインと対照。 合格: 対照実行(変更していないオリジナル、または同じパイプラインで変更を加えずに再パッケージしたもの)があり、観測された障害を記録していること(停止する場合は停止までの時間も含む)。不合格: パッチ適用後のビルドに不具合が起きたとき、比較対象がなく、それ以降の測定結果すべてが反証不可能になること。
まずはここから:13の質問で対象を分類する
ツールに触れる前に、13の質問すべてに順番に回答してください。回答を誤っても明白なエラーにはなりません。ビルドも実行もできるのに、意図しない動作をする成果物ができてしまいます。 回答欄には、実行する操作と、その詳細を記載したファイルの両方が示されています。質問に取りかかる前に、そのファイルを読み込んでください。
| # | 質問 | 回答によって変わること | 読み込む項目 |
|---|---|---|---|
| 1 | アプリはパックされている/強化されているか? マニフェストの application android:name を確認します | アプリ独自の Application ではなく、サードパーティ製のシェルクラスが指定されている場合はパッカーが使われています。まずその処理に対応する必要があります | recon.md |
| 2 | 実際に動作を担っているのはどこか? — 広告 SDK · クライアント側で UI を描画するためにサーバーから発行される設定 · メンバーシップ/VIP · 機能フラグまたはデバッグスイッチ · API レスポンスで決まるものなど | クライアント側にあり削除できるもの、クライアントが判断に使うサーバー提供データ、クライアント側のパッチでは見た目しか変わらないサーバー側で決定されるものを見分けます。早い段階で判断してください。存在しない広告 SDK を探すと何時間も無駄になり、サーバー設定の形式の場合は探すべき SDK がありません | ad-removal.md、server-config-and-updates.md、membership-and-limits.md、server-api.md |
| 3 | アプリ独自のコードは通常の dex にあるか、それともネイティブ/Flutter/Unity に移されているか? | タスク全体で使うツールチェーンが決まります。決める前に、手早くランタイムで確認してください。対象の UI に関係する明らかな Java クラスにフックを設定して、その UI を再現します。フックが発火すれば Java がその UI を担っています。UI が明らかに表示されているのにフックが一度も発火しない場合は、ランタイムまたはネイティブコードが描画しており、dex だけを対象にした計画では行き詰まります。発火がゼロなら、dex の調査を続けないでください。このスキルの履歴で最も高くついた誤った方向転換です | recon.md §アプリ独自のコードはどこにあるか、framework-runtimes.md |
| 4 | 成果物にどのような機能が必要か? テスト可能な一文で書き、各チェックポイントで読み返してください | このスキルで最も高くつくのは、要件からのずれです。ランタイムだけでの結果(データ編集、ライブフック、ホスト名のブロック、ホストプロキシ)が成功に見えても、要件を満たさないことがあります。判断軸は、権限(ルート化されていないか?)、変更形態(再構築した成果物か、ライブ計測か)、ABI/デバイスクラス、ネットワーク、永続性、配布形態(単体で完結するか?)です。深い抽出シェル、VMP、または独立した整合性チェックが複数あることがすでに証拠で示されている場合は、G1 の 4 つの形式に照らして再検討してください。再パッケージの列は、コストが高いのではなく、実行不可能な可能性があります | long-task-discipline.md §最も高くつくずれ |
| 5 | アプリは独自の署名を検証するか、それともサーバーが検証するか? | アプリ側で検証する場合は回避が必要です。サーバー側で検証する場合は、再署名すると後でアプリが気づかないうちに動かなくなります | repack-and-sign.md、server-api.md |
| 6 | デバイスの状況は? — ルート化済みの実機、ルート化済みのエミュレーター、またはデバイスなし | Frida がそもそも使えるか、そして成果物を実際に使う環境でテストできるかが決まります。最初の実験の前に scripts/preflight.py を実行し、予想外の失敗が起きるたびにもう一度実行してください。デバイスの状態、停止したデバイスサーバー、残っているプロキシ、時刻のずれは、いずれもパッチの不具合に見えることがあります | environment.md、pitfalls.md P9 |
| 7 | 実際に実行されているアーキテクチャはどれか? | getprop が示すのはデバイスが申告する値で、primaryCpuAbi が示すのはパッケージマネージャーが選んだ値です。どちらも実際に実行されるものではありません。真の根拠となるのは、ライブマッピングだけです。マッピングされていないライブラリ、使用中のトランスレーター、想定と異なる ABI は、どんなパッチよりも大きく計画を変えます | native-and-so.md §アーキテクチャ間の違い、scripts/lib_map.py |
| 8 | ほかは動作しているのに、実行時に失敗する特定の機能(ログイン、登録、支払い、API に依存する画面)があるか? | 特定機能に限られたネットワーク障害は、多くの場合、パッチの問題ではなく、特定のコードパスにおける TLS/証明書の問題です。アプリが独立した信頼チェーンを 2 つ持つこともあるため、「ほかのリクエストは動作する」ことは何の証明にもなりません。署名チェックの調査を始める前に、数分でこの可能性を除外してください | tls-and-cert.md |
| 9 | 入力は自分で作成していないビルド(流通している「クラック済み」/「改造済み」APK)だったか? | そのようなビルドは再保護されていることが多く、元のビルドよりも多くのレイヤーが含まれる場合もあります。また、注入されたコンポーネントやエンドポイントが含まれていることがあります。パッチ作業の土台として絶対に使わないでください | third-party-builds.md |
| 10 | クライアントは独自の署名証明書を使ってリクエストに署名するか? | 最初の再パッケージの前に toCharsString()/signatures[0]/getPackageInfo(..., 64) を grep してください。その値がネイティブの HMAC/DES ルーチンに渡される場合は、再構築した APK で、読み取り箇所すべてに元の証明書値をハードコードする必要があります。そうしないと、アプリは起動して正常に見える一方で、署名付きリクエストがすべて失敗します。再パッケージで最も高くつく、表面化しにくい失敗です。15 分の grep で防げます | signature-derived-keys.md |
| 11 | アプリがしばらくすると勝手に終了するか — Java スタックがない、またはバグのように見えるネイティブクラッシュが起きるか? | 強化されたライブラリが kill を呼び出すことはまれです。多くの場合、障害を意図的に発生させるよう仕向けます(小さな定数を読み込み、それをポインターとして使うなど)。そのため、終了が通常の欠陥のように見えます。手を加える前に守るべきルールは 2 つあります。実際に発生する仕組みを特定すること(シグナルと tombstone で切り分けます)。そして、戻らなくするのではなく、戻るように無効化することです。スタブをスピンさせるとプロセスがフリーズし、原因とは似ても似つかない症状が発生します | native-tamper-and-suicide.md |
| 12 | このビルドは 1 週間後も使えるか? | バージョンチェック、アップグレードのプロンプト、自己更新の経路がある場合、パッチを適用していないビルドは停止されたり、リモートから置き換えられたりする可能性があります。これは編集 1、2 回で対応でき、作業が長持ちするかどうかを左右します。後回しではなく、ビルドの一部です。バージョン変更なしで削除した動作を復元するホットアップデート/リモート設定の経路も確認してください | updates-and-forced-upgrade.md |
| 13 | リクエストはサインインや電話番号の紐付けに関係するか(「ログイン不要」、「紐付けをスキップ」、「ゲストでも可」) | クライアント側のゲート(パッチ可能)と、アカウントに紐付いたリソース(サーバーが応答するアカウントがないため画面が空になる。パッチ不可)を区別できます。まず分類してください。また、ゲートを通過するためにセッションを決して捏造しないでください。サインアウト状態より悪い状態になります | account-gates.md |
| **長時間タスクのルール(助言ではなく条件です):**時間がかかりそうな場合は、ただちに | |||
references/long-task-discipline.md を開き、作業を進める間、記録を更新し続けてください。実験を始める前に、「反証された結論」と「行き止まり」の各セクションを読み直してください。これまでの調査結果を失うことは、このスキルにおいて最も大きな損失であり、完全に防ぐことができます。 |
最初から最後までのワークフロー
手順には順序があります。明記されたスキップ条件を満たす場合に限り、手順をスキップしてください。「不要そうに思える」は条件ではありません。pitfalls.md に記載された失敗の大半は、これが原因で起きました。
2回失敗したら中止するルール。 同じ種類の試みが2回失敗したら、中止して分類に戻ってください。すでに2回失敗した仮説を、3回目に条件を変えて試してはいけません。同じパターンで2回失敗したなら、調整すべきなのはパラメーターではなく、モデルのほうが間違っています。3回目の試みでは、最初の2回ですでにわかっていたことを確認するために、ラウンド全体を費やすことになります。その時点で、症状インデックスを読み直してください。まさにこの場面のために用意されています。
- 事前確認を行い、その後に偵察する —
scripts/doctor.pyは、最初に実行するコマンドとして最も手軽です。この環境で実際に動作するツールチェーンとスクリプトを報告し、実験を台無しにする環境上の事実(時計のずれ、残存するadb forward/プロキシ、デバイス側で既に実行中の frida プロセス、PATH の外にインストールされたツールなど)を明らかにします。デバイスが関係する場合は、他の作業に取りかかる前にscripts/preflight.pyを実行します(数秒で済み、誤った結論につながる多くの要因を防げます)。その後、references/recon.mdを確認します。マニフェスト、パッケージ名、バージョン、ABI、dex の数、パッカー、組み込み SDK、アプリ独自のコードがある場所を調べます。ここでの10分が、後の数時間を節約します。パッカーが使われている場合は、他の作業に取りかかる前に展開します(references/recon.md§unpacking)。読み取れないコードにはパッチを適用できません。また、暗号化されたペイロードの長さから、ダンプした dex のどれがオリジナルかを判断できます。メモリダンプは、信頼する前にハッシュで重複を除去し、構造を検証する必要があります。 偵察でパッカーが見つからなかったのに、再署名したビルドが停止する場合は、references/code-virtualization-and-custom-linkers.mdが扱うレイヤーが原因です。「パッカーなし」は「編集可能」を意味すると決めつけて、作業を進めないでください。 アプリが何もしなくても停止する場合 — 特に起動後ほぼ一定の時間で停止する場合や、ネイティブクラッシュが発生する場合 — パッチを計画する前に、その仕組みを特定します(references/native-tamper-and-suicide.md、scripts/native_crash.py)。停止までにかかった時間を記録してください。これは後のすべての試行を比較する基準となります。これがなければ、実行が維持されたのか、停止スケジュールが変わったのかを判断できません。 スキップ条件: スキップ不可。§Gates の G2/G3 は、ここでクリアするか、まったくクリアできないかのいずれかです。 - 文字列とエンドポイントを抽出する — dex の文字列テーブルから、アプリの API サーフェスと SDK の一覧を把握します。デコンパイラーは不要で、処理も高速です。スクリプト:
scripts/dex_strings.py。 - 処理を担うクラスをたどる — 挙動をラップするクラスを見つけます(アプリはほぼ必ず、サードパーティ SDK を1つのヘルパーでラップしています)。逆引きの手順:
references/dex-patching.md§finding-the-call-site。 - パッチを適用するレイヤーを決める — クライアント SDK 呼び出し/クライアントのレンダリング/クライアントのデータ消費/サーバーとの契約。
references/ad-removal.mdの表を参照してください。 - 的を絞ってパッチを適用する —
references/dex-patching.mdとreferences/byte-level-patching.mdを参照してください。 手法は2つあります。どちらを選ぶかは好みではなく、判断が必要です。 変更が既存の命令スロットまたは定数に収まる場合は、同じ長さのバイト編集(scripts/dex_patch_bytes.py。scripts/dex_find_insn.pyで位置を特定)を使います。何も移動しないため、オフセット、try/catch ブロック、デバッグポインターが無効になりません。新しい命令が本当に必要な場合に限り、dexlib2 によるメソッドの書き換え(scripts/dexpatch/)を使います。smali のツリー全体を往復させると、R8 で最適化された dex に損傷を与え、その影響が実行時にしか現れないことがあります。メソッドの再構築によってファイルサイズも増加します(実測値:あるサンプルではdebug_infoが924 Bから22.8 KBに、dex が4.32 MBから7.73 MBに増加)。どちらの方法を使う場合も、dex ヘッダーの整合性フィールドを再計算します(署名が先、チェックサムが最後)。references/byte-level-patching.md§the dex header has two integrity fields を参照してください。 - 再パッケージ化して署名する —
references/repack-and-sign.mdを参照してください。META-INF/全体を削除しないでください。このたった1つのミスで、他は正しいビルドが台無しになります。 6b. ビルドを完了とする前に、更新経路を無効化する。 アプリが更新を確認する場合は、2層のパッチを適用します(references/updates-and-forced-upgrade.md)。更新ルーチンのエントリを no-op にし、バージョン比較を「更新なし」側に強制します。リモートから無効化または置き換えられるビルドは納品物になりません。後で再ビルドするより、今ここで対処するほうが数分で済みます。削除した挙動を復元できるリモート設定またはホットアップデートの経路についても、同様に対処します。 6c. アカウント関連のゲートは、分類してから扱う — 依頼にサインインまたはアカウント連携が含まれる場合は、references/account-gates.mdを適用し、利用可能になる保護対象画面と、コンテンツがアカウントに紐づいているため空のままになる画面を明確に説明します。 - デバイスで検証する —
references/environment.mdとreferences/verification.mdを参照してください。次の点を確認します。起動すること、変更対象の挙動が実際に変わっていること、無関係な機能が壊れていないこと、そしてブロッキングダイアログなしでアプリが通常の UI に到達すること。まず、デバイス上で実際に成果物が変更されたことを証明します。パッケージマネージャーが成功を報告しても、介在する確認画面で承認されたとは限りません(P18)。起動後最初の約20秒は継続してキャプチャし、そのキャプチャを確認してください。サンプリング間隔があるとブロッキングモーダルを見逃すことがあり(P20)、確認していない画像が大量にあっても証拠にはなりません。アクセシビリティツリーが空の場合、画像は代替手段ではなく主要な証拠です。 - 学んだことを記録する — 失敗によって30分を超える時間を費やした場合は、
references/pitfalls.mdに追加します。このファイルは、このスキルにおいて最も価値のある成果物です。
「完了」の意味 — それより早く主張してはいけません
完了を報告する前に、以下のすべての項目が真でなければなりません。それに満たないものはチェックポイントであり、残っている作業とともに、口に出してチェックポイントとして明示しなければなりません。早すぎる「完了」は、報告しうる中で最も有害なものです。なぜなら、ユーザーが問題は解決したと信じているうちに、調査を終わらせてしまうからです。
- 成果物が存在し、その同一性が記録されている — ファイル名ではなく、パスとハッシュです。
- 成果物の文言が名指しする環境でインストールされ、起動された(G1/R1)。その環境があなたにとって利用可能でなかった場合は、その旨を述べ、結果をそれに応じてラベル付けしてください。
- あなたが変更した挙動が変更されたと検証されている — エラーメッセージの不在によってではなく、その機能の直接的な観察によって。「ログはクリーンだ」は証拠ではありません。「画面に X が表示されている」が証拠です。
- それが触れる機能が依然として動作する。 あなたはそれらを実際に動かしました。起動するが、影響を受ける機能が死んでいるビルドは結果ではありません。
- 元の制約が残っている場合はそれが述べられている — それを引き起こす結合とともに。そうすれば次の担当者がそれを受け入れるかどうかを判断できます。
- あなたが行ったことのいずれも、それが目標であった場合を除き、ターゲットやデバイスを壊れた状態のままにしない。また、特権を要する回避策は、成果物ではなくフォールバックとしてラベル付けされます。
項目 1〜4 が成り立つのに環境が間違っていた場合、あなたが持っているのはプロトタイプであり、成果物ではありません。「プロトタイプ」と述べ、ギャップを名指ししてください。
停止条件 — 再試行せず、停止して再分類する
これらは、前進を押し続けることが誤った動きとなる瞬間です。それぞれがどこかで何時間ものコストを生んでいます。
- 同じ形の試みが二度失敗した。 上記のツーストライクルールを参照してください。
- あるパッチが効果を持たず、あなたがその第三の変種を試そうとしていた。 効果がないとは、パッチが運悪く外れたのではなく、診断が誤っていたということです。層を再分類してください。
- 新しい失敗があなたの現在のモデルに位置を持たない。 これが症状インデックスのトリガー条件です。
- あなたが、そのブロックがあなたのパイプラインのものではなくアプリのものだことを証明する対照ビルドなしに、あるルートを「ブロックされた」と書き捨てようとしている。 誤って帰属されたブロックは、実行可能なルートを消し去ってきました。
- あなたがエラーの不在をもって成功を主張しようとしている。 §「完了」の意味を参照してください。
- ある測定値が、あなたがすでに確定として記録した結論と一致しない。 結論を再び開いてください。測定値を説明で片付けないでください。
絶対に守るべき制約
違反した場合、これは好みの問題ではなく欠陥です。 各行には違反を検出するチェックが記載されているため、「守れたか」は自分で判断するのではなく、実行できるコマンドで確認できます。
| 制約 | 絶対に守るべき理由 | チェック |
|---|---|---|
| 入力は読み取り専用です。 コピーを使い、既知の正常なベースラインを保持してください | 編集した元ファイルは、差分を取るための唯一の基準を損ないます | 最初の編集前に元ファイルをgit/ハッシュで記録してください。エントリーレベルの証明にはscripts/apk_diff.pyを使用してください |
| 一度に変更する変数は1つだけにし、コントロールビルド(同じパイプラインで、パッチはゼロ)を用意してください | 変更を組み合わせて失敗しても何も学べず、失敗の原因を誤って特定することになります | コントロール実行が存在し、その結果が記録されていること |
| dexを編集するたびに構造を検証してください | パッチのアセンブルに成功しても、ロード時にクラッシュすれば、パッチが機能したように見えてしまいます | scripts/dex_classdiff.pyで、変更する意図のないクラスについてクラスセットとアクセスフラグの差分がゼロであることを確認してください |
| 広く共有されているメソッドにはパッチを当てないでください。 まず呼び出し元の数を数えてください | 呼び出し元が30個あるLong.valueOfのようなヘルパーは、広告専用のフックではありません | 変更しようとしているメソッドに対してscripts/find_refs.pyを実行してください |
| UI要素を抑制するためにAPIを失敗させないでください。 | そのエンドポイントの他の機能が依存する404/400は、画面全体を巻き添えにします。これは起動画面から先に進まないビルドとして確認できます | データの消費レイヤーまたは描画レイヤーで抑制してください。リクエストのパスが変わった場合、それが問題です |
| ネイティブの終了経路は、戻らなくするのではなく、戻ることで無効化してください。 | スピンするスタブは、ロックを保持したまま呼び出し元をフリーズさせます。無関係なスレッドも停止し、症状(ハング、外部からの強制終了、再起動ループ)は原因とは似ても似つかないものになり、クラッシュ記録も残りません | 無害な値を返してください。失敗を示す-1より成功を示す0を優先し、pthread_exit/exit/abort/snprintf/closedirには触れないでください。native-tamper-and-suicide.md |
| 結論を出す前に確認し、待っている間も確認してください。 | 実際の画面を見れば、座標を推測して5回試すよりも、1回で答えが得られます | キャプチャして内容を確認してください。同一バイト列のサンプルは、何も変わらないことを意味します。scripts/snap.py、environment.md §画面を確認する |
| すべてのコマンドに制限時間を設け、その制限を実測値に基づいて調整してください。 | 制限のない呼び出しでは、停止状態が「まだ処理中」に見え、進行中かどうかを区別できなくなります | 操作にかかる時間を一度計測して記録し、それに基づいて期限を設定してください。long-task-discipline.md §すべての待機に上限を設ける |
すべての主張にobserved、inferred、unverified、unknownのいずれかのラベルを付けてください。 | 「おそらく」「〜のはず」「理論上」は調査結果ではなく、ラベルのない推測は事実として広まります | observedにはコマンドとその出力が必要です。それ以外を確定事項として記載してはいけません。問いにたどり着かなかったプローブの結果はabsentではなく、unknownです |
| 「完了」とは、ユーザーに見える結果を指します。 | ブロック中のダイアログが画面に残っているなら、ログがどれほどきれいでもタスクは完了していません | §「完了」の意味にある6項目をすべて確認してください。ログ行がないことは、成功の証拠にはなりません |
| 複合的な根拠だけでルートを破棄しないでください。 | 2つの変更を同時に行った後に失敗した場合、原因の特定は仮説にすぎません。誤って原因を特定すると、実行可能なルートを何時間も失うことがあります | 断念したルートを記録する前に、変更を1つに絞って再実行してください |
| 測定を始める前に、デバイスが変更されたことを証明してください。 | インストールの成功が示すのはリクエストであり、ディスク上のアプリではありません | デバイス上の成果物のハッシュをビルドと照合してください。そうしないと、それ以降のすべての観察結果が前のビルドについてのものになります |
| 再度パッチを当てる前に、失敗がどのレイヤーで発生したかを特定してください。 | 特定の機能に限ったネットワーク障害は、アプリ自体のTLS/証明書の問題であることがよくあります。存在しない署名チェックを追いかけても、時間を無駄にするだけです | まず同じデバイスとネットワークで未変更の元ファイルを実行してください(tls-and-cert.md) |
リファレンス索引とスクリプト索引
両方の表は references/routing.md にあります。ここを一度読み込めば、読み込むタイミングを含むすべてのリファレンスファイルと、処理内容を含むすべてのスクリプトを確認できます。これらをここに重複して載せていないのは意図的です。このファイルはスキルが有効になるたびに全体が読み込まれますが、約140行ある2つの表の検索データは、何をするかをすでに決めるまでは必要ないためです。
上記の症状索引はそのまま残しています。症状からファイルまでは1ホップでたどれる必要があるからです。何かが失敗したときに選ぶのはファイルではなく、失敗を認識することです。その時点で2ホップの検索が必要になると、まさにその手順によって停止シグナルが見落とされます。
references/evidence-summary.md は、インストール済みのコピーから主張の強さに関する疑問に答える唯一のリファレンスです。機能 → 1行の結論 → observed/inferred/unverified → スキルに同梱された証拠、という構成です。主張の強さによって信頼するかどうかが決まり、実行記録が手元にない場合に読み込んでください。
python check_routing.py は、このファイルと references/routing.md の内容が引き続き一致していること、すべてのリファレンスファイルがそこに記載されていること、すべてのスクリプトがそこに記載されていることを確認します。CI で実行されます。