Skip to content
KitploitKITPLOIT
ツールエクスプロイトブログ
Log in
提出
ツールエクスプロイトブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

フィードお問い合わせプライバシー© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
tvm-recover — Tencent VM の .tvm0 セクションを逆仮想化します。VM ハンドラをゲストレベルのリスティングと LLVM IR にリフトし、CFG とディスパッチを復元し、復元したコードを PE にパッチして戻します。 | Kitploit
ツール/GitHubGitHub/neurosaki987/tvm-recover
静的分析コード分析動的コード分析 (DAST)リバースエンジニアリングデバッガバイナリ解析論文と研究バイナリエクスプロイト
GitHubneurosaki987/tvm-recover

tvm-recover

Tencent VM の .tvm0 セクションを逆仮想化します。VM ハンドラをゲストレベルのリスティングと LLVM IR にリフトし、CFG とディスパッチを復元し、復元したコードを PE にパッチして戻します。

リポジトリを見る
147時間31分前未レビュー

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

tvm-recover

DOI

関連する Zenodo レコード: 10.5281/zenodo.23474767。

⚠️ 免責事項: 本プロジェクトは、許可されたセキュリティ研究、相互運用性分析、および教育のみを目的としています。商用アンチチートシステムのバイパス機能を含むものではなく、提供するものでもありません。対象バイナリを分析する法的権利を有していることを確認する責任は、ユーザー自身にあります。

Tencent VM 用の devirtualizer です。.tvm0 セクション内の仮想化されたコードを復元し、各 VM ハンドラがゲストのレジスタとメモリに対して行う処理をリフトし、復元された関数を通常の read+execute セクションとしてバイナリに書き戻すことができます。

これはツールです。モジュールを指定すれば、構造とコードを取り出せます。

.tvm0 section  ->  VM semantics  ->  guest-level listing  ->  LLVM IR  ->  patched PE

VMルートの逆仮想化されたリスティング。ゲストレジスタファイルがブロックをまたいでバインドされています。

逆仮想化の結果

ビルド

python -m venv .venv
source .venv/Scripts/activate      # Windows: .venv\Scripts\Activate.ps1
pip install -r requirements.txt

Python 3.13、capstone。バックエンドには llvmlite==0.50.0 と、Windows では MSVC の link.exe/cl.exe が必要です。z3-solver は任意です — これがない場合、パス条件付けは維持され、 有界ディスパッチ証明のみがスキップされます。

設定

.env.example を .env にコピーし、このマシンのパスを記入してください。.env は git で無視され、 すべての設定にはコマンドラインフラグもあるため、このファイルはデフォルト値を提供するだけです。

キー意味
TVM_MODULE解析対象のモジュール。位置引数なしで実行されるプローブ用
TVM_LISTINGSバックエンドが読み込むリスティングコーパス
TVM_OUTすべての出力のルート(デフォルト out/)
TVM_STEPSブロックが切り詰められるまでのブロックあたりのステップ数(デフォルト 900000)
TVM_BLOCKSルートあたりのブロック予算(デフォルト 512)
TVM_PAYLOAD_OPTペイロードコード生成レベル 0–3
TVM_PAYLOAD_MEMsealed | absolute ゲストメモリモード
TVM_MSVC_BINlink.exe/cl.exe を格納するディレクトリ。PATH に依存する代わりに使用

優先順位: コマンドラインフラグ → .env → 環境変数 → 組み込みデフォルト。

使用方法

エンジンコマンドは engine/ から、バックエンドコマンドはリポジトリルートから実行します。

仮想化されたコードを見つける

cd engine
python -m probe.scan_tvm0 /path/to/dir        # which files carry a .tvm0, and its roots
python -m probe.trampoline_forms input.exe    # what the entry trampolines look like
python -m probe.mnemonic_census input.exe     # what x86 the VM contains

逆仮想化

python -m core.devirt input.exe --out ../out/listings

関数ごとに1つの 0x<root>.txt リストと1つの 0x<root>.guest-state.json を出力します。オプション:

フラグデフォルト意味
--out=DIRstdoutリストとゲスト状態を書き出す
--root=0x…検出されたすべて1つのVMエントリに限定する
--show[=N]オフ最初のN行を表示する
--steps=N900000切り捨て前のブロックあたりのステップ数
--blocks=N512ルートあたりのブロック予算
--caller-entry=0x… --call-site=0x…オフエントリを呼び出し元に特化する

各リストのヘッダーには、実行が切り捨てられたかどうかが示されます。切り捨てられたリストは下限であり、関数そのものではありません。

1つの関数を理解する

python -m probe.cfg_run         input.exe 0x14015fc2e    # walk it, print the CFG
python -m probe.guest_effect    input.exe 0x14015fc2e    # what handlers do to guest registers
python -m probe.ctx_map         input.exe 0x14015fc2e    # which context slot holds which register

python -m probe.why_unresolved  input.exe 0x14015fc2e    # why a dispatch did not resolve
python -m probe.block_exits     input.exe 0x14015fc2e    # why a block has no successor
python -m probe.stop_debug      input.exe 0x14015fc2e    # why evaluation stopped
python -m probe.unresolved_detail input.exe 0x14015fc2e  # per-block detail

特定の値またはストアを掘り下げます:

python -m probe.trace_window    input.exe 0x14015fc2e 0x14015fc40 0x14015fc90
python -m probe.reg_history     input.exe 0x14015fc2e rax
python -m probe.who_wrote       input.exe 0x14015fc2e 0x18
python -m probe.flags_at        input.exe 0x14015fc2e 0x14015fc60
python -m probe.stack_at        input.exe 0x14015fc2e

バイナリに書き戻す

.\write-devirt.ps1 -Module 'C:\path\to\SGuardSvc64.exe'

ペイロードを実行 → 注入 → ロード → 差分検出の順に実行し、最初に失敗したステージで停止します。オプション: -Listings、-Out、-Opt 0..3、-Mem sealed|absolute、-SkipDifferential、-Force。

各ステージの個別実行:

cd llvm
python payload.py  --listings=../out/hard-cases-listings-final --out=../out/write-devirt --opt=0 --mem=sealed
python peinject.py --host=input.exe --payload=../out/write-devirt --out=../out/write-devirt/input.neko.exe
python miniload.py ../out/write-devirt/input.neko.exe
python diff_payload.py --payload=../out/write-devirt --patched=../out/write-devirt/input.neko.exe

diff_payload.py が重要なチェックです。これはパッチ適用済みイメージの内部でコードを実行し、同じリスティングに対してインタプリタとバイト単位で比較します。miniload.py はイメージがロードされ、そのエントリが実行されることだけを証明します。

VM の仕組み

ACE はネイティブ関数を VM ディスパッチャへのトランポリンに置き換えます。ディスパッチャはネイティブの x86 ハンドラを実行しますが、保護された関数のアーキテクチャ状態は VM コンテキスト内に存在します。

flowchart TB
    subgraph TOP[ ]
        direction LR

        subgraph TEXT[.text]
            ENTRY["<b>Function entry</b><br/>jump to VM entry"]
        end

        subgraph VM[.tvm0 section]
            direction LR
            CORE["<b>Shared dispatcher and handlers</b><br/>execute x86 - resolve next handler"]
            CTX["<b>Guest context</b><br/>GPRs - RFLAGS - VIP"]
            CORE <--> CTX
        end
    end

    subgraph NATIVE[Native execution outside the VM]
        direction LR
        BOXED["<b>Boxed instruction</b><br/>execute original x86"]
        CALL["<b>Guest call</b><br/>invoke native target"]
        EXIT["<b>Guest return or tail call</b><br/>resume native execution"]
        BOXED ~~~ CALL ~~~ EXIT
    end

    TEXT --> VM
    VM <--> NATIVE

    style TOP fill:transparent,stroke:transparent

一部の操作はVMの外で実行されます。ボックス化された命令は、VMが必要なレジスタを復元した後に元のx86エンコーディングを実行し、その効果をゲストコンテキストに返します。ゲストコールはネイティブターゲットを呼び出し、戻り値とWindows x64 ABIのクロバーをゲスト状態に反映して再開します。ゲストリターンとテールコールはディスパッチャを完全に離脱します。

コンテキストは、ゲストのRSPを含む16個すべてのゲスト汎用レジスタと、パックされたゲストフラグを保持します。そのレイアウトはプロテクタのビルドによって異なるため、想定するのではなくVMの保存/復元動作を観察することで特定されます — probe.ctx_mapはストア時に測定されたマッピングを報告し、出力される各リスティングはコンテキストアクセスをそのスロットオフセットで囲みます。

条件付き制御フローはディスパッチ演算です。ハンドラはゲストフラグまたは述語を抽出し、それを使って次の仮想プログラムカウンタを選択し、次のハンドラのアドレスを計算します。デバーチャライザはそれをシンボリックに評価し、選択が未解決のゲスト値に依存する場合にフォークします。ブロックの識別子は(handler, vip)のペアであり、ハンドラ単独ではありません。

リカバリは一つのルールに基づきます。値は、分析が与えた名前ではなく、マシンが行ったことによって識別する。 ブロック間のレジスタ伝播は、証拠としてではなく注釈としてリスティングに記録されます — リスティング内のすべてのレジスタバージョン番号を置換しても、解析された構造は変化してはなりません。

レイアウト

write-devirt.ps1   one command: payload -> patched PE -> differential
.env.example       configuration template; copy to .env
envfile.py         .env parser; bootenv.py loads it for llvm/, engine/envboot.py for probes
engine/core/       PE parsing, expression arena, x86-64 lifting, machine model,
                   guest context, CFG recovery, guest IR, guest-state programs
engine/probe/      28 probes - each answers one question about the target
engine/tests/      30 suites, all on synthetic fixtures or independent Python arithmetic
llvm/              listing grammar, IR -> LLVM IR, interpreter, differential,
                   payload builder, PE/PDB editor, injector, loader
llvm/runtime/      the code the payload calls: sealed memory, entry stub, __chkstk
out/               tool output (git-ignored)

スコープ

ゲストコンテキストのレイアウトは仮定ではなく計測によって導出される。probe.ctx_map は、どのコンテキストスロットがどのゲストレジスタを保持しているかを、ストアの時点で計測して報告する。ブロックの同一性は (handler, vip) の組であり、ハンドラ単体ではない。

出力が主張しないこと: リスティングは VM が行ったことの記録であり、逆コンパイルではない。未解決のディスパッチは推測せず、未解決として報告される。切り詰められた実行はファイルヘッダーに明示される。--caller-entry はその呼び出し元を条件とした結果を生成し、ペイロードはそれを一般的なリカバリへ昇格させることを拒否する。

クレジット

逆アセンブルに capstone、LLVM バックエンドに llvmlite を基盤としている。

ツールをダウンロード