Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

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

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

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

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
dconstruct — TLOU2 DC スクリプト用の逆アセンブラ&実験的な逆コンパイラ | Kitploit
ツール/GitHubGitHub/deepquantum/dconstruct
静的分析リバースエンジニアリングデバッガバイナリ解析ファームウェア解析
GitHubdeepquantum/dconstruct

dconstruct

TLOU2 DC スクリプト用の逆アセンブラ&実験的な逆コンパイラ

リポジトリを見る
23241ヶ月前Kitploit レビュー済み

人気

すべて見る →

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

すべてのツールを探索

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

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

バージョン ライセンス: CC BY-NC-ND 4.0

dconstruct

完全逆アセンブルおよび逆コンパイルアニメーション

ソースMP4を開く

dconstruct は、The Last of Us Part II で使用されている DC-Script ファイルのためのリバースエンジニアリングツールです。逆アセンブラと逆コンパイラを備えています。

逆アセンブルされた構造体とバイトコードを含む.asmファイル、およびCライクな疑似コードを含む.dcpl(DC疑似言語)ファイルを出力します。

また、コマンドラインからファイルを編集することもでき、構造全体を簡単に置き換えることもできます。これにより、.binファイル内のいくつかの値を変更するだけのMODを非常に簡単に作成できます。

主な機能

  • 速度に最適化。ファイルの逆アセンブルと逆コンパイルが非常に高速です。
  • 元のソースコード、特に制御フローの正確な再構築
  • 逆アセンブル内のすべての構造の正確な自動解釈
  • 複数のファイルの同時逆アセンブルおよび逆コンパイル。ゲーム内のすべての.binファイルを逆コンパイルするのにわずか数秒しかかかりません
  • -e フラグを使用して編集を行い、MODに使用できる新しいファイルを作成
  • 逆アセンブルに使用するカスタム sidbases の読み込み

使用方法

まず、解凍した dconstruct ディレクトリを C:\Program Files などの安全な場所に移動することをお勧めします。

dconstruct をできるだけ使いやすくするために、dconstruct フォルダ内の .\bin ディレクトリを PATH に追加することをお勧めします。詳細はこちらをご覧いただくか、以下の簡単な手順に従ってください。

  • Windowsの検索バーに「環境変数」と入力し、「システム環境変数の編集」というオプションを選択します。
  • そのオプションを選択すると、「システムのプロパティ」というタイトルのウィンドウが表示されます。「OK」「キャンセル」「適用」ボタンの上に「環境変数」というボタンがあります。
  • このボタンをクリックすると、別のウィンドウが表示されます。ここで、2つ目のテーブル(「システム環境変数」というタイトル)に移動し、変数名「Path」のエントリを見つけてダブルクリックします。
  • このダイアログで、右側の「新規」オプションを選択します。次に、.\bin ディレクトリへのパスを貼り付けます。以下のようになるはずです:

a

  • パスが「\bin」で終わり、「\dconstruct」で終わっていないことを確認してください。
  • 開いているすべてのダイアログで「OK」をクリックします。
  • 動作を確認するには、新しいコマンドプロンプトを開き、dconstruct --about と入力します。プログラムからの出力が表示され、エラーメッセージが表示されないはずです。

以下のようなコマンドをコマンドラインで実行して、最初の逆アセンブルファイルを生成します:```shell dconstruct my_bin_file.bin

root@kitploit:~
これにより、入力ファイルと同じディレクトリに `my_bin_file.bin.asm` というファイルが出力されます。そのファイルはテキスト/コードエディタで開くことができます。VSCodeのような高度な検索機能を備え、大きなファイルの処理に優れたエディタをお勧めします。標準のWindowsメモ帳は推奨しません。

ファイルを逆コンパイルするには、コマンド実行時に `--decompile` フラグを追加します。

# コマンドライン引数

- `-i` - 入力ファイルまたはフォルダ。最初の引数として入力パスを渡す場合は省略可能。

- `-o` - 出力パス。入力パスがフォルダの場合、これはファイルにすることはできません。出力が指定されない場合、.txtファイルは入力ファイルの隣に配置されます。入力がフォルダで出力が指定されない場合、プログラムはカレントワーキングディレクトリに "output" ディレクトリを作成し、すべてのファイルをそこに配置します。

- サイドベースは実行ファイルの隣にある `sidbase.bin` から読み込まれます。

- `--no_decompile` - 逆コンパイルされた疑似コードを .dcpl ファイルに出力しない。ファイルは .asm ファイルの隣に配置されます。デフォルトは false です。

- `--no_optimize` - dcpl コードの最適化とクリーンアップを行わない。関数呼び出しのインライン化、未使用変数の削除、互換性のある for ループの foreach ループへの変換、一部の if-else チェーンの match 式への変換などが含まれます。

- `--pascal_case` - ゲームの関数名を dcpl 出力でパスカルケースに変換する。例: get-boolean -> GetBoolean。

- `--graphs` - 逆コンパイルされたすべての関数の制御フローグラフを含む .svg ファイルを出力する。各 .bin ファイルには、そのグラフのすべてを含む独自のフォルダが作成されます。これにより逆コンパイル速度が **大幅に** 低下するため、多数のファイルを同時に逆コンパイルする場合には推奨されません。

- `--emit_once` - 同じ構造が逆アセンブル内で二度出力されることを防ぎます。構造が複数回出現する場合、最初のインスタンスのみ完全に出力され、その他の箇所は `ALREADY_EMITTED` タグに置き換えられます。これによりファイルサイズを大幅に削減できます。

- `-e` - 編集を行う。詳細は以下のセクションを参照。

- `--edit_file` - 編集ファイルを指定する。編集ファイルには1行に1つの編集が含まれます。`-e` フラグと同じ構文を使用します。

# 逆アセンブラとは?

[逆アセンブラ](https://en.wikipedia.org/wiki/Disassembler) は、バイナリ命令(別名 [バイトコード](https://en.wikipedia.org/wiki/Bytecode) または [マシンコード](https://en.wikipedia.org/wiki/Machine_code))を読み取り、それぞれを [ニーモニック](https://en.wikipedia.org/wiki/Assembly_language#Mnemonics) と呼ばれる人間が読めるバージョンに変換するツールです。逆アセンブラは一般的に、これらの命令の意味についてはあまり解釈しようとせず、単に1対1で読み取り可能なバージョンに変換します。例えば、以下の命令は:```arm
15 00 00 00
4A 01 01 00
43 31 01 00
1C 00 00 01

は以下の人間が読めるバージョンに逆アセンブルされます:```arm LookupPointer r0, 0 LoadStaticU64Imm r1, 1 Move r49, r1 CallFf r0, r0, 1

root@kitploit:~
All numbers in the bytecode are written in [hexadecimal](https://en.wikipedia.org/wiki/hexadecimal). The first column in each row represents the `opcode`, or the type of instruction to be executed. The next column is the destination register, where the result of the operation will be stored. The last two columns are operands 1 and 2, which are either registers or literal numbers on which the operation will be performed. Not all instructions use all 4 bytes, for example, the first `LookupPointer` instruction only needs one operand.

The dconstruct disassembler also adds some additional information meant to make reading the instructions a bit easier. It also inserts labels (e.g. `L_0`) to make branches in the code easier to trace.```arm
15 00 00 00   LookupPointer        r0, 0         r0 = ST[0] -> <is-player-abby?>
4A 01 01 00   LoadStaticU64Imm     r1, 1         r1 = ST[1] -> <player>
43 31 01 00   Move                 r49, r1       r49 = player
1C 00 00 01   CallFf               r0, r0, 1     r0 = is-player-abby?(player)
2F 0D 00 00   BranchIfNot          r0, 0xD       IF NOT r0 => L_0

これにより、プログラムが過度な推測をせずにファイルの生の内容を確認したい場合に便利です。ただし、大規模なコードブロックの場合、構造がまったくないため読みにくくなることがあります。そこでデコンパイラの出番です。

デコンパイラとは?

デコンパイラはコンパイラの逆の機能を持ちます。コンパイラは、人間が書いたコード(C、Java、C++など)を受け取り、機械語命令を生成するプログラムです。TLOU2や他の多くのNDゲームでは、使用されるスクリプト言語は「DC」と呼ばれており、これは基本的にプログラミング言語Racket>)の一種です。そして「機械」とは、ゲーム自体が実行中に命令を実行するものです。基本的に、プログラマはDCを記述し、コンパイラを使ってそのコードをゲームに同梱される.binファイルに変換します。

デコンパイラは、上記の逆アセンブルされたコードを受け取り、疑似コードと呼ばれるものを生成します。疑似コードは、元のソースコードを再構築しようとする_試み_です。これによりコードの理解が大幅に容易になりますが、疑似コードの生成プロセスは非常に複雑です。なぜなら、最終的なバイトコードを生成できるソースコードのバージョンは多数あり、またコンパイル中に最適化が行われるからです。

現在、dconstructデコンパイラの出力は、元のDCと構文的には似ていません。DC(つまりRacket)は関数型プログラミング言語であり、独特の構文を持ち、それに慣れていないプログラマには非常に読みにくいものです。そのため、現時点では疑似コードをよりC言語に近い形にすることを選択しました。これにより、ほとんどの人にとって読みやすくなるはずです。ただし、Racket版やPython版など、さらに多くの構文を作成する計画があります。

例

sqrt-sign() 関数

元のバイト列```arm

43 00 31 00 15 01 00 00 43 02 00 00 43 31 02 00 1B 01 01 01 43 02 00 00 40 03 01 00 24 02 02 03 2F 0B 02 00 40 02 02 00 2D 0C 00 00 40 02 03 00 43 03 02 00 15 04 04 00 43 05 01 00 43 31 05 00 1C 04 04 01 07 03 03 04 43 01 03 00 00 01 01 00

root@kitploit:~
これでは、コードの動作をほぼ把握できません。

## ラベル&シンボルテーブル付きの逆アセンブルコード```arm
sqrt-sign = script-lambda [0x9A8D8] {
    [1 args]
    0000   0x09A928   43 00 31 00   Move                 r0, r49       r0 = arg_0
    0001   0x09A930   15 01 00 00   LookupPointer        r1, 0         r1 = ST[0] -> <absf>
    0002   0x09A938   43 02 00 00   Move                 r2, r0        r2 = arg_0
    0003   0x09A940   43 31 02 00   Move                 r49, r2       r49 = arg_0
    0004   0x09A948   1B 01 01 01   Call                 r1, r1, 1     r1 = absf(arg_0)
    0005   0x09A950   43 02 00 00   Move                 r2, r0        r2 = arg_0
    0006   0x09A958   40 03 01 00   LoadStaticFloatImm   r3, 1         r3 = ST[1] -> <0.000000>
    0007   0x09A960   24 02 02 03   FGreaterThanEqual    r2, r2, r3    r2 = r2 >= r3
    0008   0x09A968   2F 0B 02 00   BranchIfNot          r2, 0xB       IF NOT r2 => L_0
    0009   0x09A970   40 02 02 00   LoadStaticFloatImm   r2, 2         r2 = ST[2] -> <1.000000>
    000A   0x09A978   2D 0C 00 00   Branch               0xC           GOTO => L_1
  L_0:
    000B   0x09A980   40 02 03 00   LoadStaticFloatImm   r2, 3         r2 = ST[3] -> <-1.000000>
  L_1:
    000C   0x09A988   43 03 02 00   Move                 r3, r2        r3 = -1.000000
    000D   0x09A990   15 04 04 00   LookupPointer        r4, 4         r4 = ST[4] -> <sqrt>
    000E   0x09A998   43 05 01 00   Move                 r5, r1        r5 = RET_absf
    000F   0x09A9A0   43 31 05 00   Move                 r49, r5       r49 = RET_absf
    0010   0x09A9A8   1C 04 04 01   CallFf               r4, r4, 1     r4 = sqrt(RET_absf)
    0011   0x09A9B0   07 03 03 04   FMul                 r3, r3, r4    -1.000000 = -1.000000 * RET_sqrt
    0012   0x09A9B8   43 01 03 00   Move                 r1, r3        r1 = -1.000000
    0013   0x09A9C0   00 01 01 00   Return               r1            Return

    SYMBOL TABLE:
    0000   0x09A9C8    function: absf
    0001   0x09A9D0    float: 0.000000
    0002   0x09A9D8    float: 1.000000
    0003   0x09A9E0    float: -1.000000
    0004   0x09A9E8    function: sqrt
}

コードはだいぶ読みやすくなりましたが、それでも単一のブランチだけでも、アセンブリに慣れていないと読むのが面倒です。

制御フローグラフ

細かい説明は省きますが、制御フローグラフ(CFG)は、アセンブリコードをさまざまな分岐命令に沿って「ノード」に分割します。これは、プログラムの「流れ」がどのように異なる経路に分岐するかを解析する際に重要であり、変数、if文、forループなどの出力が必要になる可能性があります。これらのグラフはバックグラウンドで生成する必要がありますが、--graphs プログラムフラグを使用して画像として出力できます。

最終的な疑似コード```rust

u64? sqrt-sign(f32 arg_0) { f32 var_1; if (arg_0 >= 0.00) { var_1 = 1.00; } else { var_1 = -1.00; } return var_1 * sqrt(absf(arg_0)); }

root@kitploit:~
この関数の目的は非常に明確で、引数の絶対値を取り、その値の平方根を計算し、それを引数の元の符号と掛け合わせます。例えば、`sqrt-sign(-9) = -3` となります。

## 最適化パス

dconstructは擬似コードに自動的に最適化パスを適用します。以下にいくつかの例を示します。

### 関数呼び出しのインライン展開

#### 適用前```c
u64? set-arrow-explosive-handle-rootvars() {
    u64? var_0 = get-uint64(fx-handle, self);
    u64? var_1 = get-float(kill, self);
    set-effect-float(var_0, killradius, var_1);
    u64? var_2 = get-uint64(fx-handle, self);
    u64? var_3 = get-float(strong, self);
    set-effect-float(var_2, strongradius, var_3);
    u64? var_4 = get-uint64(fx-handle, self);
    u64? var_5 = get-float(weak, self);
    u64? var_6 = set-effect-float(var_4, weakradius, var_5);
    return var_6;
}

後```c

u64? set-arrow-explosive-handle-rootvars() { set-effect-float(get-uint64(fx-handle, self), killradius, get-float(kill, self)); set-effect-float(get-uint64(fx-handle, self), strongradius, get-float(strong, self)); return set-effect-float(get-uint64(fx-handle, self), weakradius, get-float(weak, self)); }

root@kitploit:~
### Foreach ループ

### 以前```c#
u64? bmm-deactivate-all(u64? arg_0) {
    u64? var_0 = darray-count(arg_0);
    begin-foreach();
    for (u64 i = 0; i < var_0; i++) {
        u64? var_1 = darray-at(arg_0, i);
        u16 var_2;
        if (var_1 && *(u16*)(var_1 + 12) == 7) {
            var_2 = *(u64*)var_1;
        } else if (var_1 && *(u16*)(var_1 + 12) == 5) {
            var_2 = *(u64*)var_1;
        } else if (var_1 && *(u16*)(var_1 + 12) == 4) {
            var_2 = *(u64*)var_1;
        } else {
            var_2 = 0;
        }
        net-send-event-all(deactivate, var_2);
    }
    u64? var_3 = end-foreach();
    return var_3;
}

後```c#

u64? bmm-deactivate-all(u64? arg_0) { foreach (u64? var_1 : arg_0) { u16 var_2; if (var_1 && (u16)(var_1 + 12) == 7) { var_2 = (u64)var_1; } else if (var_1 && (u16)(var_1 + 12) == 5) { var_2 = (u64)var_1; } else if (var_1 && (u16)(var_1 + 12) == 4) { var_2 = (u64)var_1; } else { var_2 = 0; } net-send-event-all(deactivate, var_2); } }

root@kitploit:~
### マッチ式

### 前```scala
string #C57EE0A64537AE8F(u16 arg_0) {
    string var_0;
    if (arg_0 == 0) {
        var_0 = "Militia";
    } else if (arg_0 == 1) {
        var_0 = "Scars";
    } else if (arg_0 == 2) {
        var_0 = "Rattlers";
    } else if (arg_0 == 3) {
        var_0 = "Infected";
    } else if (arg_0 == 4) {
        var_0 = "Max Num Factions";
    } else {
        var_0 = "Invalid";
    }
    return var_0;
}

後```scala

string #C57EE0A64537AE8F(u16 arg_0) { return match (arg_0) { 0 -> "Militia" 1 -> "Scars" 2 -> "Rattlers" 3 -> "Infected" 4 -> "Max Num Factions" else -> "Invalid" }; }

root@kitploit:~
## 逆アセンブル構造の例```c
*ellie-weapons* = symbol-array [0x00190] {
  [0] int: 6
  [1] int: 0
  [2] array [0x198] {size: 6} {
    [0] anonymous struct [0x780] {
      [0] sid: pistol-beretta
    }
    [1] anonymous struct [0x788] {
      [0] sid: pistol-revolver-taurus
    }
    [2] anonymous struct [0x790] {
      [0] sid: rifle-remington-bolt
    }
    [3] anonymous struct [0x798] {
      [0] sid: bow-ellie
    }
    [4] anonymous struct [0x7a0] {
      [0] sid: shotgun-remington-pump
    }
    [5] anonymous struct [0x7a8] {
      [0] sid: rifle-mpx5
    }
  }
}

Editing

-e フラグを使用した DC ファイルの編集

-e フラグを使用して、DC ファイルに編集を適用できます。これらの編集は元のファイルの新しいコピーに保存され、元のファイルは変更されません。複数の -e フラグを同時に指定して、複数の編集を一度に行うこともできます。

または、プログラムに編集ファイルへのパスを指定することもできます。編集ファイルには、1行に1つの編集が含まれています。これは -e フラグと同じ構文を使用しますが、一度に複数の編集を適用したい場合には少し使いやすいはずです。

編集は 逆アセンブルと逆コンパイルの前に行われる ため、編集内容は生成されたファイルに反映されます。

編集の構文

各編集は次の構文に従います:```xml

[]= ``` - ``: 編集したい構造体のメモリアドレス(先頭に `0x` が付いた16進数)。編集したいファイルの逆アセンブル版からコピーペーストするのが最も簡単です。 - ``: 構造体内部のメンバ変数のインデックス。メンバの左側に表示されている数字と同じです。 - ``: そのメンバに割り当てる新しい値。同じサイズでなければなりません(int と float はサイズ4、sid/struct はサイズ8)。プログラムは構造体が同じ型かどうかをチェックしません。

例

次のような構造体があるとします:```c++ [4] firearm-gameplay-def [0x11C28] { [0] float 0.7 // might represent the rate of fire, so i want to lower it for my mod ... }

root@kitploit:~
最初のメンバ変数(インデックス0)を浮動小数点値0.5に置き換える場合、編集コマンドは次のようになります:

`-e 0x11C28[0]=0.5`

編集したい構造体は`0x11C28`にあり、最初のメンバ変数(浮動小数点の左側の0)を指定します。次に`=`の後に新しい値(この場合は0.5)を記述します。編集が成功すると、プログラムは値が`0.7->0.5`に変更されたことを示すメッセージを表示します。

編集ファイルの場合、単に`-e`を省略し、1行に1つの編集を記述します:

### edit_file.txt

0x11C28[0]=0.5

0x11C28[1]=0.2

...

## メンバ変数の種類

構造体は異なる型のメンバ変数を持つことができます:

- `float` - 小数点を含む10進数値を指定します(例:0.5)。

- `int` - 小数点を含まない整数値を指定します(例:42)。

- `sid` (文字列識別子)- (詳細は以下)

- `string` - 現在、置換はサポートされていません

- `structure` - ポインタを置き換えることで実現(詳細は以下)

### 名前検索による sid の置換:

`-e 0xABC[5]=ellie`

現在の sidbase 内で値 "ellie" を検索します。存在しない場合は警告が発行され、編集は適用されません。値が見つかると、実際のハッシュ値(大きな数値)がメンバ変数の現在の値と置き換わります。

### 直接手動ハッシュ上書きによる sid の置換:

`-e 0xABC[5]=#XXXXXXXXXXXXXXXX`

`#`は生のハッシュ値を示し、検索なしで直接適用されます。

### メンバ構造体の置換

構造体が別の構造体をメンバとして含む場合、そのメンバ構造体全体を別の構造体のアドレスを割り当てることで置き換えることができます。

例えば、次のような場合を考えてみます:```c++
[4] weapon-gameplay-def [0x0C523] {
    ...
    [7] firearm-gameplay-def [0x11C28] {
        ...
    }
}

So weapon-gameplay-def には firearm-gameplay-def が含まれています。
weapon-gameplay-def 内の firearm-gameplay-def を、アドレス 0x0ABC にある別の firearm-gameplay-def に置き換える場合、編集は次のようになります。

-e 0x11C28[7]=0x0ABC

DCPL 言語の VS Code 拡張機能

VS Code はカスタム拡張機能を作成して、カスタム言語にシンタックスハイライトを追加することをサポートしています。dconstruct には .vsix ファイルが同梱されており、これにより .dcpl ファイル拡張子に対するサポートが追加されます。この言語は日常的なプログラミングを目的としたものではなく、単一用途の言語であるため、拡張機能をマーケットプレイスにアップロードせず、代わりに生の .vsix ファイルとして提供しています。この拡張機能を VS Code にインストールするには、次のコマンドを実行してください。```shell code --install-extension <path/to/extension/dcpl-lint-0.0.1.vsix>

root@kitploit:~
または、コマンドパレットをCTRL+SHIFT+Pで開き、「Install extension via VSIX」と入力し、.vsixファイルを選択します。

この後、.dcplコードは次のようになります。

![dcpl_code](https://assets.kitploit.com/production/public/readmes/13048/8b4ab26ab7952a91a015d1376d3101bcad17c65602ed9c2b5c1587cb1d1a9f3c.png)

# 既知の問題

デコンパイラは現在100%完成しておらず、「実験的」な状態です。デコンパイル中に警告が表示されても、これらの関数は現在サポートされていませんが、将来的にはサポートされる予定ですので、心配しないでください。これらに加えて、現時点ではさらに既知の問題があります。

- 単一式関数で短絡評価(特に構造体内のもの)が多用されているものはまだ実装されていません。これらのアルゴリズムの作業は開始しましたが、完了までにどれくらい時間がかかるかはわかりません。ただし、優先順位は高いです。
- 特定の型、特に引数の型が正しくありません。
- if/else文内の空のifブロックが奇妙なインデントを引き起こす可能性があります。これはまた、実際に何も仕事をしないブランチが存在するためであり、それを検出するのは難しいため、必ずしも私のせいではありません。

これらに加えて、おそらく修正されないであろう問題もあります。

- 関数がvoidかどうか不明な場合にゴミを返す
- 大量の冗長コード

# 計画中の機能

- 完全なRacketおよびPython出力形式

# 特別な感謝

- **icemesh** – DCファイルの基礎となる[構造](https://github.com/icemesh/dc/tree/main/t2)および[彼の逆アセンブラ](https://github.com/icemesh/t2-dc-disasm)を提供してくれたこと。これらは大きなインスピレーションとなりました。

- **Specilizer** – 彼のDC-Tool。これもこのプログラムのインスピレーションです。

- **uxh** – スクリプト知識を提供してくれたこと。

- **bigdragon** & **Wedge** – ベータテストをしてくれたこと。

- モデリングDiscordコミュニティ全体 – 友好的で助けになることに対して。

## サポート

私のツールとMODは常に100%無料ですが、このようなプログラムには多大な労力がかかります。

もし私を支援したい場合は、Ko-fiをご覧ください:

[![Ko-fi](https://img.shields.io/badge/Donate-Ko--fi-ff5f5f.svg)](https://ko-fi.com/deepquantum)

## ライセンス

このMODを使用して作成したファイルは完全にあなたのものであり、それらを自由に扱うことができます。クレジットをいただけるとありがたいですが、必須ではありません。

プログラム自体は、[クリエイティブ・コモンズ 表示 - 非営利 - 改変禁止 4.0 国際 ライセンス](https://creativecommons.org/licenses/by-nc-nd/4.0/)の下でライセンスされています。

これは、クレジットを表示すれば他の人とプログラムを共有することは許可されますが、現在のところ、改変や収益化は許可されていないことを意味します。
ツールをダウンロード