Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
dconstruct — Un desensamblador y decompilador experimental para scripts de TLOU2 DC. | Kitploit
Herramientas/GitHubGitHub/deepquantum/dconstruct
Análisis EstáticoIngeniería InversaDepuradoresAnálisis de BinariosAnálisis de Firmware
GitHubdeepquantum/dconstruct

dconstruct

Un desensamblador y decompilador experimental para scripts de TLOU2 DC.

Ver Repositorio
2324hace 1 mesRevisado por Kitploit

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

Version License: CC BY-NC-ND 4.0

dconstruct

Animación completa de desensamblado y descompilación

Abrir el MP4 fuente

dconstruct es una herramienta de ingeniería inversa para los archivos DC-Script utilizados en The Last of Us Part II. Incluye un desensamblador y un descompilador.

Genera archivos .asm que contienen las estructuras desensambladas y bytecode, así como archivos .dcpl (DC Pseudo Language) que contienen código pseudo similar a C.

También puede realizar ediciones en archivos mediante la línea de comandos, incluyendo reemplazar estructuras completas con poco esfuerzo. Esto hace que crear mods que simplemente cambien un par de valores dentro de los archivos .bin sea extremadamente fácil.

Características principales

[]= ``` - ``: La dirección de memoria de la estructura que deseas editar (en hexadecimal, comenzando con `0x`. Lo más fácil es copiarla y pegarla desde una versión desensamblada del archivo que deseas editar). - ``: El índice de la variable miembro dentro de la estructura. Equivalente al número que puedes ver a la izquierda del miembro. - ``: El nuevo valor a asignar a ese miembro. Debe ser del mismo tamaño. (los enteros y flotantes tienen tamaño 4, los sids/structs tienen tamaño 8). El programa NO comprobará que las estructuras sean del mismo tipo.
  • Optimizado para velocidad. Desensamblar y descompilar archivos es extremadamente rápido.
  • Reconstrucción precisa del código fuente original, especialmente el flujo de control
  • Interpretación automática precisa de todas las estructuras en el desensamblado
  • Desensamblar y descompilar múltiples archivos al mismo tiempo. Descompilar cada archivo .bin del juego solo toma unos segundos
  • Realizar ediciones mediante la bandera -e, creando nuevos archivos que puede usar para mods
  • Cargar sidbases personalizados para usar en el desensamblado

Cómo usar

Primero, se recomienda que mueva el directorio dconstruct descomprimido a una ubicación segura, como C:\Program Files.

Para que dconstruct sea lo más fácil de usar posible, se recomienda que agregue el directorio .\bin dentro de la carpeta dconstruct a su PATH. Puede obtener más información aquí, o seguir estos pasos rápidos:

  • Vaya a la barra de búsqueda de Windows y escriba "variables de entorno", debería aparecer una opción que dice "Editar las variables de entorno del sistema"
  • Después de seleccionar esa opción, debería aparecer una ventana con el título "Propiedades del sistema". Sobre los botones "Aceptar", "Cancelar" y "Aplicar", debería ver un botón que dice "Variables de entorno..."
  • Después de hacer clic en este botón, debería aparecer otra ventana. Aquí, vaya a la segunda tabla (titulada "Variables del sistema") y busque la entrada con el nombre de variable "Path". Haga doble clic en ella.
  • En este cuadro de diálogo, seleccione la opción "Nuevo" a la derecha. Ahora pegue la ruta al directorio .\bin. Debería verse algo así:

a

  • Asegúrese de que su ruta termine en "\bin" y NO en "\dconstruct".

  • Haga clic en 'Aceptar' en todos los cuadros de diálogo abiertos.

  • Para verificar que funcionó, abra un nuevo símbolo del sistema y escriba dconstruct --about. Debería ver alguna salida del programa y ningún mensaje de error.

Ejecute un comando como este en la línea de comandos para generar su primer archivo desensamblado:```shell dconstruct my_bin_file.bin

root@kitploit:~
Esto generará un archivo llamado `my_bin_file.bin.asm` en el mismo directorio que su archivo de entrada. Luego puede abrir ese archivo usando un editor de texto/código. Recomendaría usar algo como VSCode que ofrece funciones de búsqueda avanzada y es bueno para manejar archivos grandes. No se recomienda el Bloc de notas estándar de Windows.

Para descompilar un archivo, agregue la bandera `--decompile` al ejecutar el comando.

# Argumentos de línea de comandos

- `-i` - archivo o carpeta de entrada. Se puede omitir si se pasa la ruta de entrada como primer argumento.

- `-o` - ruta de salida. Si su ruta de entrada es una carpeta, esto no puede ser un archivo. Si no se especifica salida, el archivo .txt se colocará junto al archivo de entrada. Si la entrada es una carpeta y no se especifica salida, el programa creará un directorio "output" en el directorio de trabajo actual y colocará todos los archivos allí.

- La sidbase se carga desde `sidbase.bin` ubicado junto al ejecutable.

- `--no_decompile` - no emite código pseudo descompilado en un archivo .dcpl. El archivo se colocará junto al archivo .asm. Esto es falso por defecto.

- `--no_optimize` - no optimizar y limpiar el código dcpl. Implica la inserción en línea de llamadas a funciones, la eliminación de variables no utilizadas, la transformación de bucles for compatibles en bucles foreach, y la conversión de algunas cadenas if-else en expresiones match.

- `--pascal_case` - convierte los nombres de las funciones del juego a PascalCase en la salida dcpl, por ejemplo get-boolean -> GetBoolean.

- `--graphs` - genera archivos .svg que contienen gráficos de flujo de control para todas las funciones descompiladas. Cada archivo .bin obtiene su propia carpeta que contiene todos sus gráficos. Esto **ralentiza significativamente** la velocidad de descompilación, por lo que no se recomienda al descompilar un gran número de archivos al mismo tiempo.

- `--emit_once` - prohíbe que la misma estructura sea emitida dos veces en el desensamblado. Si una estructura aparece varias veces, solo la primera instancia se emitirá completamente, y todas las demás ocasiones serán reemplazadas por una etiqueta `ALREADY_EMITTED`. Esto puede reducir significativamente el tamaño del archivo.

- `-e` - realizar una edición. Más información en la sección siguiente.

- `--edit_file` - proporcionar un archivo de edición. Un archivo de edición contiene una edición por línea. Utiliza la misma sintaxis que la bandera -e.

# ¿Qué es un desensamblador?

Un [desensamblador](https://en.wikipedia.org/wiki/Disassembler) es una herramienta que lee instrucciones binarias (también conocido como [bytecode](https://en.wikipedia.org/wiki/Bytecode) o [código máquina](https://en.wikipedia.org/wiki/Machine_code)) y traduce cada una a una versión legible por humanos llamada [mnemónico](https://en.wikipedia.org/wiki/Assembly_language#Mnemonics). Los desensambladores generalmente no intentan interpretar mucho sobre el significado de estas instrucciones y simplemente las transforman 1-1 en sus versiones legibles. Por ejemplo, las instrucciones:```arm
15 00 00 00
4A 01 01 00
43 31 01 00
1C 00 00 01

se desmontan en las siguientes versiones legibles por humanos:```arm LookupPointer r0, 0 LoadStaticU64Imm r1, 1 Move r49, r1 CallFf r0, r0, 1

root@kitploit:~
Todos los números en el bytecode están escritos en [hexadecimal](https://en.wikipedia.org/wiki/hexadecimal). La primera columna de cada fila representa el `opcode`, o el tipo de instrucción a ejecutar. La siguiente columna es el registro de destino, donde se almacenará el resultado de la operación. Las últimas dos columnas son los operandos 1 y 2, que son registros o números literales sobre los cuales se realizará la operación. No todas las instrucciones utilizan los 4 bytes, por ejemplo, la primera instrucción `LookupPointer` solo necesita un operando.

El desensamblador dconstruct también agrega información adicional destinada a facilitar la lectura de las instrucciones. También inserta etiquetas (por ejemplo, `L_0`) para facilitar el seguimiento de las bifurcaciones en el código.```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

Esto es útil cuando quieres ver el contenido bruto del archivo sin que el programa haga demasiadas suposiciones. Pero puede ser difícil de leer para grandes bloques de código, ya que no hay estructura alguna. Aquí es donde entra un descompilador.

¿Qué es un descompilador?

Un descompilador es el inverso de un compilador. Un compilador es un programa que toma código escrito por humanos (como C, Java, C++, ...) y produce instrucciones de máquina. En el caso de TLOU2, y muchos otros juegos de ND, el lenguaje de scripting utilizado se llama 'DC', que es básicamente una versión del lenguaje de programación Racket>), y la "máquina" es el propio juego que ejecuta las instrucciones mientras el juego se está ejecutando. Esencialmente, los programadores escriben DC y usan un compilador para convertir ese código en los archivos .bin que se envían con el juego.

Un descompilador toma el código desensamblado de arriba y produce lo que se conoce como pseudocódigo. El pseudocódigo es un intento de reconstruir el código fuente original que se utilizó para generar las instrucciones brutas. Esto pretende hacer que la comprensión del código sea significativamente más fácil, sin embargo, el proceso de generar pseudocódigo es bastante complejo, ya que hay muchas versiones diferentes de código fuente que pueden generar el código de bytes final, así como optimizaciones que tienen lugar durante la compilación.

Actualmente, la salida del descompilador dconstruct no es sintácticamente similar al DC original. DC (es decir, Racket) es un lenguaje de programación funcional con una sintaxis única que es j*damente ilegible para los programadores que no están acostumbrados a ella. Por esta razón, he elegido hacer que el pseudocódigo se parezca más a C por ahora, lo que debería ser más fácil de leer para la mayoría de las personas. Sin embargo, está planeado crear más sintaxis, incluyendo Racket y una versión en Python.

Ejemplos

La función sqrt-sign()

Bytes originales```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:~
A partir de esto, es virtualmente imposible saber qué está haciendo el código.

## Código desensamblado con etiquetas y tabla de símbolos```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
}

El código es ahora mucho más legible, pero incluso la rama única es molesta de leer si no estás acostumbrado a leer ensamblador.

Gráfico de flujo de control

Sin entrar en demasiados detalles aquí, un gráfico de flujo de control (CFG) divide el código ensamblador en "nodos" a lo largo de las diversas instrucciones de bifurcación. Esto es crítico cuando analizamos el código para descubrir dónde el "flujo" del programa puede divergir en diferentes rutas, lo que podría requerir que emitamos variables, if statements, for-loops, etc.. Estos gráficos deben generarse en segundo plano, pero puedes imprimirlos en imágenes usando la bandera --graphs del programa.

Pseudocódigo final```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:~
El propósito de la función ahora es muy claro: tomamos el valor absoluto del argumento, calculamos la raíz cuadrada de ese valor y luego lo multiplicamos por el signo original del argumento. Por ejemplo, `sqrt-sign(-9) = -3`.

## Pasos de optimización

dconstruct aplica automáticamente pasos de optimización al pseudocódigo. Aquí hay algunos ejemplos:

### Inlineado de llamadas a funciones

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

Después```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:~
### Bucles foreach

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

Después```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:~
### Expresiones de coincidencia

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

Después```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:~
## Ejemplo de una estructura desensamblada```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
    }
  }
}

Edición

Editando archivos DC usando la bandera -e

Puede usar la bandera -e para aplicar ediciones a archivos DC. Estas ediciones se guardan en una copia nueva del archivo original, dejando el original intacto. Se pueden especificar múltiples banderas -e al mismo tiempo para realizar varias ediciones a la vez.

Alternativamente, puede proporcionar al programa una ruta a un archivo de edición. Un archivo de edición contiene una edición por línea. Usa la misma sintaxis que la bandera -e, pero debería ser un poco más fácil de usar si desea aplicar múltiples ediciones a la vez.

La edición ocurre antes del desensamblado y la descompilación, por lo que la edición aparecerá en los archivos generados.

Sintaxis para ediciones

Cada edición sigue esta sintaxis:```xml

Ejemplo

Supón que tienes una estructura como esta:```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:~
Para reemplazar la primera variable miembro (índice 0) con el valor flotante 0.5, el comando de edición sería:

`-e 0x11C28[0]=0.5`

La estructura que queremos editar está en `0x11C28`, y queremos la primera variable miembro (el 0 a la izquierda del flotante). Luego colocamos el nuevo valor después del `=`, 0.5 en este caso. Si la edición fue exitosa, el programa mostrará un mensaje indicando que el valor cambió de `0.7->0.5`.

Para un archivo de edición, simplemente omita el `-e` y ponga una edición por línea:

### edit_file.txt

0x11C28[0]=0.5

0x11C28[1]=0.2

...

## Tipos de Variables Miembro

Las estructuras pueden tener diferentes tipos de variables miembro:

- `float` - Especifica valores decimales con un punto (ej., 0.5).

- `int` - Especifica valores enteros sin punto (ej., 42).

- `sid` (identificador de cadena) - (más información abajo)

- `string` - no compatible actualmente para reemplazo

- `structure` - reemplazando un puntero (más información abajo)

### Reemplazo de sid por búsqueda de nombre:

`-e 0xABC[5]=ellie`

Esto busca el valor "ellie" en el sidbase actual. Si no existe, se emite una advertencia y no se aplica ninguna edición. Si se encuentra el valor, el valor hash real (un número grande) reemplazará el valor actual en la variable miembro.

### Reemplazo de sid por anulación manual directa de hash:

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

El # indica un valor hash bruto, que se aplicará directamente sin búsqueda.

### Reemplazo de estructuras miembro

Si una estructura contiene otra estructura como miembro, puedes reemplazar toda la estructura miembro asignándole la dirección de otra estructura.

Por ejemplo, supón que tienes lo siguiente:```c++
[4] weapon-gameplay-def [0x0C523] {
    ...
    [7] firearm-gameplay-def [0x11C28] {
        ...
    }
}

So weapon-gameplay-def contiene un firearm-gameplay-def. Para reemplazar el firearm-gameplay-def dentro del weapon-gameplay-def con un firearm-gameplay-def diferente ubicado en la dirección 0x0ABC, la edición será:

-e 0x11C28[7]=0x0ABC

Extensión del lenguaje DCPL para VS Code

VS Code permite crear extensiones personalizadas para agregar resaltado de sintaxis a lenguajes personalizados. dconstruct incluye un archivo .vsix que agrega este soporte para la extensión de archivo .dcpl. Debido a que es un lenguaje de un solo uso, no destinado realmente a la programación diaria, no estoy subiendo la extensión al marketplace, y en su lugar la distribuyo como un archivo .vsix sin procesar. Para instalar esta extensión en tu VS Code, ejecuta el siguiente comando:```shell code --install-extension <path/to/extension/dcpl-lint-0.0.1.vsix>

root@kitploit:~
o abre la paleta de comandos con CTRL+MAYÚS+P y escribe "Instalar extensión mediante VSIX" y selecciona el archivo .vsix.

Después de esto, tu código .dcpl debería verse algo así:

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

# Problemas conocidos

El descompilador actualmente no está completo al 100% y por lo tanto se encuentra en un estado "experimental". Si recibes advertencias durante la descompilación, no te preocupes, ya que estas funciones actualmente no son compatibles, pero con suerte lo serán en el futuro. Junto con estas, hay más problemas conocidos en este momento:

- funciones de expresión única con cortocircuito intenso (especialmente aquellas dentro de structs) aún no están implementadas. He comenzado a trabajar en el algoritmo para estas, pero no sé cuánto tiempo llevará terminarlo, aunque esto está en la parte alta de la lista de prioridades
- ciertos tipos son incorrectos, particularmente los tipos de argumentos
- los bloques if vacíos en sentencias if/else pueden causar una sangría extraña. Esto, de nuevo, no siempre es culpa mía, ya que hay ciertas ramas que en realidad no hacen ningún trabajo real, lo cual es difícil de detectar

Junto con estos, hay algunos problemas que probablemente no se solucionarán:

- devolver basura cuando no se sabe si una función es void o no
- toneladas de código redundante

# Funciones planificadas

- un formato de salida completo para Racket y Python

# Agradecimientos especiales

- **icemesh** – por proporcionar las [estructuras subyacentes para los archivos DC](https://github.com/icemesh/dc/tree/main/t2) y [su desensamblador](https://github.com/icemesh/t2-dc-disasm), que sirvió en gran medida como inspiración.

- **Specilizer** – por su DC-Tool, también una inspiración para este programa.

- **uxh** – por sus conocimientos de scripting.

- **bigdragon** y **Wedge** por las pruebas beta

- Toda la comunidad de modding de Discord – por ser amigable y servicial.

## Soporte

Todas mis herramientas y mods serán siempre 100% gratuitos, pero programas como este requieren mucho trabajo.

Si deseas apoyarme, puedes visitar mi Ko-fi:

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

## Licencia

Los archivos que crees usando este mod son completamente tuyos y eres libre de hacer con ellos lo que quieras. Se agradecería el crédito, pero no es estrictamente necesario.

El programa en sí está bajo la licencia
[Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License](https://creativecommons.org/licenses/by-nc-nd/4.0/).

Esto significa que puedes compartir el programa con otros si das crédito, pero actualmente no se permite modificarlo ni monetizarlo.
Descargar herramienta