Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
dconstruct — Un disassemblatore e decompilatore sperimentale per script TLOU2 DC. | Kitploit
Strumenti/GitHubGitHub/deepquantum/dconstruct
Analisi StaticaReverse EngineeringDebuggerAnalisi di BinariAnalisi del Firmware
GitHubdeepquantum/dconstruct

dconstruct

Un disassemblatore e decompilatore sperimentale per script TLOU2 DC.

Vedi Repository
23241 mese faRevisionato da Kitploit

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

Versione Licenza: CC BY-NC-ND 4.0

dconstruct

Animazione di disassemblaggio e decompilazione completa

Apri il file MP4 sorgente

dconstruct è uno strumento di reverse engineering per i file DC-Script utilizzati in The Last of Us Parte II. Dispone di un disassemblatore e di un decompilatore.

Produce file .asm contenenti le strutture disassemblate e il bytecode, oltre a file .dcpl (DC Pseudo Language) contenenti pseudo-codice simile al C.

Puoi anche apportare modifiche ai file tramite la riga di comando, inclusa la sostituzione di intere strutture con poco sforzo. Ciò rende estremamente semplice la creazione di mod che modificano semplicemente un paio di valori all'interno dei file .bin.

Caratteristiche principali

[]= ``` - ``: L'indirizzo di memoria della struttura che si desidera modificare (in esadecimale, iniziando con `0x`. È più semplice copiarlo e incollarlo da una versione disassemblata del file che si desidera modificare). - ``: L'indice della variabile membro all'interno della struttura. Equivalente al numero che si vede a sinistra del membro. - ``: Il nuovo valore da assegnare a quel membro. Deve essere della stessa dimensione. (int e float sono di dimensione 4, sid/struct sono di dimensione 8). Il programma NON verificherà che le strutture siano dello stesso tipo.
Scarica lo strumento
  • Ottimizzato per la velocità. Disassemblare e decompilare i file è estremamente veloce.
  • Ricostruzione accurata del codice sorgente originale, specialmente il flusso di controllo
  • Interpretazione automatica accurata di tutte le strutture nel disassemblaggio
  • Disassemblare e decompilare più file contemporaneamente. Decompilare ogni singolo file .bin nel gioco richiede solo un paio di secondi
  • Apportare modifiche tramite il flag -e, creando nuovi file che puoi utilizzare per le mod
  • Caricare sidbase personalizzati da utilizzare per il disassemblaggio

Come usare

Prima di tutto, si consiglia di spostare la directory dconstruct decompressa in una posizione sicura, ad esempio C:\Program Files.

Per rendere dconstruct il più facile possibile da usare, si consiglia di aggiungere la directory .\bin all'interno della cartella dconstruct al tuo PATH. Puoi scoprire di più qui, oppure seguire questi rapidi passaggi:

  • Vai nella barra di ricerca di Windows e digita 'variabili d'ambiente', dovresti ottenere un'opzione che dice 'Modifica le variabili d'ambiente di sistema'
  • Dopo aver selezionato questa opzione, dovresti ottenere una finestra con il titolo 'Proprietà del sistema'. Sopra i pulsanti 'Ok', 'Annulla' e 'Applica', dovresti vedere un pulsante che dice 'Variabili d'ambiente...'
  • Dopo aver cliccato questo pulsante, dovrebbe apparire un'altra finestra. Qui, vai nella seconda tabella (intitolata 'Variabili di sistema') e trova la voce con il nome della variabile 'Path'. Fai doppio clic.
  • In questa finestra di dialogo, seleziona l'opzione 'Nuovo' a destra. Ora incolla il percorso della directory .\bin. Dovrebbe apparire qualcosa del genere:

a

  • Assicurati che il percorso termini con '\bin' e NON con '\dconstruct'.

  • Fai clic su 'OK' su tutte le finestre di dialogo aperte.

  • Per verificare che abbia funzionato, apri un nuovo prompt dei comandi e digita dconstruct --about. Dovresti vedere un output dal programma e nessun messaggio di errore.

Esegui un comando come questo nella riga di comando per generare il tuo primo file disassemblato:```shell dconstruct my_bin_file.bin

root@kitploit:~
Questo produrrà un file chiamato `my_bin_file.bin.asm` nella stessa directory del file di input. Puoi quindi aprire quel file con un editor di testo/codice. Raccomando di usare qualcosa come VSCode, che offre funzionalità avanzate di ricerca ed è adatto a gestire file di grandi dimensioni. Il Blocco note standard di Windows non è consigliato.

Per decompilare un file, aggiungi il flag `--decompile` quando esegui il comando.

# Argomenti della riga di comando

- `-i` - file o cartella di input. Può essere omesso se si passa il percorso di input come primo argomento.

- `-o` - percorso di output. Se il percorso di input è una cartella, questo non può essere un file. Se non viene specificato alcun output, il file .txt verrà posizionato accanto al file di input. Se l'input è una cartella e nessun output è specificato, il programma creerà una directory "output" nella directory di lavoro corrente e metterà tutti i file lì.

- Il sidbase viene caricato da `sidbase.bin` situato accanto all'eseguibile.

- `--no_decompile` - non emettere pseudo codice decompilato in un file .dcpl. Il file verrà posizionato accanto al file .asm. Questo è falso per impostazione predefinita.

- `--no_optimize` - non ottimizzare e pulire il codice dcpl. Implica l'inlining delle chiamate di funzione, la rimozione di variabili inutilizzate, la trasformazione di cicli for compatibili in cicli foreach e la conversione di alcune catene if-else in espressioni match.

- `--pascal_case` - convertire i nomi delle funzioni dei giochi in pascal case nell'output dcpl, ad esempio get-boolean -> GetBoolean.

- `--graphs` - emettere file .svg contenenti i grafi di flusso di controllo per tutte le funzioni decompilate. Ogni file .bin ottiene la propria cartella contenente tutti i suoi grafi. Questo **rallenta significativamente** la velocità di decompilazione, quindi non è consigliato quando si decompila un gran numero di file contemporaneamente.

- `--emit_once` - impedisce che la stessa struttura venga emessa due volte nel disassemblaggio. Se una struttura appare più volte, solo la prima istanza verrà completamente emessa, e tutte le altre occorrenze saranno sostituite da un tag `ALREADY_EMITTED`. Questo può ridurre significativamente la dimensione del file.

- `-e` - effettuare una modifica. Maggiori informazioni nella sezione seguente.

- `--edit_file` - fornire un file di modifica. Un file di modifica contiene una modifica per riga. Utilizza la stessa sintassi del flag -e.

# Cos'è un disassemblatore?

Un [disassemblatore](https://en.wikipedia.org/wiki/Disassembler) è uno strumento che legge istruzioni binarie (note anche come [bytecode](https://en.wikipedia.org/wiki/Bytecode) o [codice macchina](https://en.wikipedia.org/wiki/Machine_code)) e traduce ciascuna in una versione leggibile dall'uomo chiamata [mnemonico](https://en.wikipedia.org/wiki/Assembly_language#Mnemonics). I disassemblatori generalmente non cercano di interpretare molto il significato di queste istruzioni e le trasformano semplicemente 1-1 nelle loro versioni leggibili. Ad esempio, le istruzioni:```arm
15 00 00 00
4A 01 01 00
43 31 01 00
1C 00 00 01

vengono disassemblate nelle seguenti versioni leggibili dall'uomo:```arm LookupPointer r0, 0 LoadStaticU64Imm r1, 1 Move r49, r1 CallFf r0, r0, 1

root@kitploit:~
Tutti i numeri nel bytecode sono scritti in [esadecimale](https://en.wikipedia.org/wiki/hexadecimal). La prima colonna in ogni riga rappresenta l'`opcode`, ovvero il tipo di istruzione da eseguire. La colonna successiva è il registro di destinazione, dove verrà memorizzato il risultato dell'operazione. Le ultime due colonne sono gli operandi 1 e 2, che sono registri o numeri letterali su cui verrà eseguita l'operazione. Non tutte le istruzioni utilizzano tutti e 4 i byte; ad esempio, la prima istruzione `LookupPointer` richiede un solo operando.

Il disassembler dconstruct aggiunge anche alcune informazioni aggiuntive pensate per rendere la lettura delle istruzioni un po' più facile. Inserisce anche etichette (ad es. `L_0`) per rendere più agevole tracciare i rami nel codice.```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

Questo è utile quando si vogliono vedere i contenuti grezzi del file senza che il programma faccia troppe supposizioni. Ma può essere difficile da leggere per blocchi di codice grandi, poiché non c'è alcuna struttura. È qui che entra in gioco un decompilatore.

Che cos'è un decompilatore?

Un decompilatore è l'inverso di un compilatore. Un compilatore è un programma che prende codice scritto da esseri umani (come C, Java, C++, ...) e produce istruzioni macchina. Nel caso di TLOU2, e molti altri giochi ND, il linguaggio di scripting utilizzato si chiama 'DC', che è fondamentalmente una versione del linguaggio di programmazione Racket>), e la "macchina" è semplicemente il gioco stesso che esegue le istruzioni mentre il gioco è in esecuzione. In sostanza, i programmatori scrivono DC e usano un compilatore per trasformare quel codice nei file .bin che vengono distribuiti con il gioco.

Un decompilatore prende il codice disassemblato di cui sopra e produce quello che è noto come pseudo codice. Lo pseudo codice è un tentativo di ricostruire il codice sorgente originale che è stato usato per generare le istruzioni grezze. Questo ha lo scopo di rendere la comprensione del codice significativamente più facile, tuttavia, il processo di generazione dello pseudo codice è piuttosto complesso poiché esistono molte versioni diverse del codice sorgente che possono generare il byte code finale, così come le ottimizzazioni che avvengono durante la compilazione.

Attualmente, l'output del decompilatore dconstruct non è sintatticamente simile al DC originale. DC (cioè Racket) è un linguaggio di programmazione funzionale con una sintassi unica che è f*cking illeggibile per i programmatori che non ci sono abituati. Per questo motivo, ho scelto di rendere lo pseudo codice più simile al C per ora, il che dovrebbe essere più facile da leggere per la maggior parte delle persone. Tuttavia, è in programma la creazione di altre sintassi, inclusa quella di Racket e una versione Python.

Esempi

La funzione sqrt-sign()

Byte originali```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:~
Da questo, è praticamente impossibile capire cosa stia facendo il codice.

## Codice disassemblato con etichette e tabella dei simboli```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
}

Il codice è ora molto più leggibile, ma anche il singolo ramo è fastidioso da leggere se non si è abituati a leggere assembly.

Grafo di flusso di controllo

Senza entrare troppo nei dettagli, un Grafo di flusso di controllo (CFG) suddivide il codice assembly in "nodi" lungo le varie istruzioni di salto. Questo è fondamentale quando analizziamo il codice per scoprire dove il "flusso" del programma può divergere in percorsi diversi, cosa che potrebbe richiedere l'emissione di variabili, istruzioni if, cicli for, ecc.. Questi grafi devono essere generati in background, ma è possibile stamparli sotto forma di immagini utilizzando il flag --graphs del programma.

Pseudocodice finale```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:~
Lo scopo della funzione è ora molto chiaro: prendiamo il valore assoluto dell'argomento, ne calcoliamo la radice quadrata e poi lo moltiplichiamo per il segno originale dell'argomento. Quindi, ad esempio, `sqrt-sign(-9) = -3`.

## Passaggi di ottimizzazione

dconstruct applica automaticamente passaggi di ottimizzazione al pseudocodice. Ecco alcuni esempi:

### Inline di chiamate di funzione

#### Before```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;
}

Dopo```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:~
### Cicli foreach

### Prima```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;
}

Dopo```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:~
### Espressioni di corrispondenza

### Prima```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;
}

Dopo```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:~
## Esempio di una struttura disassemblata```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
    }
  }
}

Modifica

Modifica dei file DC utilizzando il flag -e

Puoi usare il flag -e per applicare modifiche ai file DC. Queste modifiche vengono salvate in una nuova copia del file originale, lasciando intatto l'originale. È possibile specificare più flag -e contemporaneamente per effettuare più modifiche in una volta sola.

In alternativa, puoi fornire al programma il percorso di un file di modifica. Un file di modifica contiene una modifica per riga. Utilizza la stessa sintassi del flag -e, ma dovrebbe essere un po' più facile da usare se desideri applicare più modifiche contemporaneamente.

La modifica avviene prima del disassemblaggio e della decompilazione, quindi la modifica apparirà nei file generati.

Sintassi delle modifiche

Ogni modifica segue questa sintassi:```xml

Esempio

Supponiamo di avere una struttura come questa:```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:~
Per sostituire la prima variabile membro (indice 0) con il valore float 0.5, il comando di modifica sarebbe:

`-e 0x11C28[0]=0.5`

La struttura che vogliamo modificare è a `0x11C28`, e vogliamo la prima variabile membro (lo 0 a sinistra del float). Inseriamo quindi il nuovo valore dopo `=`, in questo caso 0.5. Se la modifica ha avuto successo, il programma mostrerà un messaggio che indica che il valore è stato cambiato da `0.7->0.5`.

Per un file di modifica, basta rimuovere il `-e` e inserire una modifica per riga:

### edit_file.txt

0x11C28[0]=0.5

0x11C28[1]=0.2

...

## Tipi di Variabili Membro

Le strutture possono avere diversi tipi di variabili membro:

- `float` - Specifica valori decimali con un punto (es. 0.5).

- `int` - Specifica valori interi senza punto (es. 42).

- `sid` (identificatore di stringa) - (maggiori informazioni di seguito)

- `string` - attualmente non supportato per la sostituzione

- `structure` - sostituendo un puntatore (maggiori informazioni di seguito)

### Sostituzione di sid tramite ricerca per nome:

`-e 0xABC[5]=ellie`

Questo cerca il valore "ellie" nel sidbase corrente. Se non esiste, viene emesso un avviso e nessuna modifica viene applicata. Se il valore viene trovato, il valore hash effettivo (un numero grande) sostituirà il valore corrente nella variabile membro.

### Sostituzione di sid tramite override manuale diretto dell'hash:

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

Il # indica un valore hash grezzo, che verrà applicato direttamente senza una ricerca.

### Sostituzione di strutture membro

Se una struttura contiene un'altra struttura come membro, puoi sostituire l'intera struttura membro assegnandole l'indirizzo di un'altra struttura.

Per esempio, supponiamo di avere quanto segue:```c++
[4] weapon-gameplay-def [0x0C523] {
    ...
    [7] firearm-gameplay-def [0x11C28] {
        ...
    }
}

Quindi weapon-gameplay-def contiene un firearm-gameplay-def. Per sostituire il firearm-gameplay-def all'interno del weapon-gameplay-def con un diverso firearm-gameplay-def situato all'indirizzo 0x0ABC, la modifica sarà:

-e 0x11C28[7]=0x0ABC

Estensione linguaggio DCPL per VS Code

VS Code supporta la creazione di estensioni personalizzate per aggiungere l'evidenziazione della sintassi a linguaggi personalizzati. dconstruct include un file .vsix che aggiunge questo supporto per l'estensione di file .dcpl. Poiché si tratta di un linguaggio monouso non realmente pensato per la programmazione quotidiana, non carico l'estensione sul marketplace, ma la distribuisco come file .vsix grezzo. Per installare questa estensione in VS Code, esegui il seguente comando:```shell code --install-extension <path/to/extension/dcpl-lint-0.0.1.vsix>

root@kitploit:~
oppure apri la palette dei comandi con CTRL+MAIUSC+P e digita "Installa estensione tramite VSIX" e seleziona il file .vsix.

Dopo questo, il tuo codice .dcpl dovrebbe apparire così:

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

# Problemi noti

Il decompilatore attualmente non è completo al 100% e quindi si trova in uno stato "sperimentale". Se ricevi avvisi durante la decompilazione, non preoccuparti poiché queste funzioni non sono attualmente supportate, ma si spera lo saranno in futuro. Insieme a questi, ci sono altri problemi noti al momento:

- le funzioni a singola espressione con cortocircuiti pesanti (in particolare quelle all'interno di struct) non sono ancora implementate. Ho iniziato a lavorare sull'algoritmo per queste ma non so quanto tempo ci vorrà per finire, anche se questo è in cima alla lista delle priorità
- alcuni tipi sono errati, in particolare i tipi degli argomenti
- blocchi if vuoti nelle dichiarazioni if/else possono causare indentazioni strane. anche questo non è sempre colpa mia, poiché ci sono alcuni rami che in realtà non svolgono alcun lavoro reale, il che è difficile da rilevare

Insieme a questi, ci sono alcuni problemi che probabilmente non verranno risolti:

- restituire spazzatura quando non è noto se una funzione è void o meno
- tonnellate di codice ridondante

# Funzionalità pianificate

- un formato di output completo per Racket e Python

# Ringraziamenti speciali

- **icemesh** – per aver fornito le [strutture sottostanti per i file DC](https://github.com/icemesh/dc/tree/main/t2) e [il suo disassemblatore](https://github.com/icemesh/t2-dc-disasm), che hanno ampiamente ispirato questo lavoro.

- **Specilizer** – per il suo DC-Tool, anche ispirazione per questo programma.

- **uxh** – per le conoscenze di scripting.

- **bigdragon** e **Wedge** per i test beta

- L'intera community modding su Discord – per essere stata amichevole e disponibile.

## Supporto

Tutti i miei strumenti e mod saranno sempre gratuiti al 100%, ma programmi come questo richiedono molto lavoro.

Se desideri supportarmi, puoi visitare il mio Ko-fi:

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

## Licenza

I file che crei utilizzando questa mod sono interamente tuoi e sei libero di farne ciò che vuoi. Un credito sarebbe apprezzato ma non è strettamente richiesto.

Il programma in sé è concesso in licenza secondo la
[Creative Commons Attribuzione-NonCommerciale-NonOpereDerivate 4.0 Internazionale](https://creativecommons.org/licenses/by-nc-nd/4.0/).

Ciò significa che puoi condividere il programma con altri se dai credito, ma attualmente non ti è permesso modificarlo né trarne profitto.