
Дисассемблер и экспериментальный декомпилятор для скриптов TLOU2 DC.

dconstruct — это инструмент реверс-инжиниринга для файлов DC-Script, используемых в The Last of Us Part II. Он включает дизассемблер и декомпилятор.
Он выводит файлы .asm, содержащие дизассемблированные структуры и байт-код, а также файлы .dcpl (DC Pseudo Language) с C-подобным псевдокодом.
Вы также можете вносить изменения в файлы через командную строку, включая замену целых структур с минимальными усилиями. Это делает создание модов, которые просто изменяют пару значений внутри файлов .bin, чрезвычайно простым.
-e, создание новых файлов для использования в модах.Сначала рекомендуется переместить распакованную директорию dconstruct в безопасное место, например C:\Program Files.
Чтобы сделать dconstruct максимально удобным в использовании, рекомендуется добавить каталог .\bin внутри папки dconstruct в ваш PATH. Подробнее можно узнать здесь или выполнить следующие быстрые шаги:

Убедитесь, что ваш путь заканчивается на "\bin", а не на "\dconstruct".
Нажмите «ОК» во всех открытых диалогах.
Чтобы проверить, что всё сработало, откройте новую командную строку и введите dconstruct --about. Вы должны увидеть вывод программы и никаких сообщений об ошибках.
Выполните в командной строке команду, подобную этой, чтобы сгенерировать первый дизассемблированный файл:```shell dconstruct my_bin_file.bin
Затем это создаст файл с именем `my_bin_file.bin.asm` в той же директории, что и ваш входной файл. Вы можете открыть этот файл с помощью текстового/кодового редактора. Я рекомендую использовать что-то вроде VSCode, который предлагает расширенные возможности поиска и хорошо справляется с большими файлами. Стандартный блокнот Windows не рекомендуется.
Чтобы декомпилировать файл, добавьте флаг `--decompile` при выполнении команды.
# Аргументы командной строки
- `-i` - входной файл или папка. Может быть опущен, если передать путь к входным данным в качестве первого аргумента.
- `-o` - путь вывода. Если ваш входной путь - это папка, то этот параметр не может быть файлом. Если вывод не указан, файл .txt будет помещен рядом с входным файлом. Если входной файл является папкой и вывод не указан, программа создаст директорию 'output' в текущей рабочей директории и поместит туда все файлы.
- sidbase загружается из `sidbase.bin`, расположенного рядом с исполняемым файлом.
- `--no_decompile` - не создавать декомпилированный псевдокод в файл .dcpl. Файл будет помещен рядом с файлом .asm. По умолчанию этот параметр равен false.
- `--no_optimize` - не оптимизировать и не чистить код dcpl. Включает в себя встраивание вызовов функций, удаление неиспользуемых переменных, преобразование совместимых циклов for в циклы foreach и преобразование некоторых цепочек if-else в выражения match.
- `--pascal_case` - преобразовывать имена функций игры в Pascal Case в выводе dcpl, например, get-boolean -> GetBoolean.
- `--graphs` - создавать файлы .svg, содержащие графы потоков управления для всех декомпилированных функций. Каждый файл .bin получает свою собственную папку, содержащую все его графы. Это **значительно** замедляет скорость декомпиляции, поэтому не рекомендуется при декомпиляции большого количества файлов одновременно.
- `--emit_once` - запрещает повторное испускание одной и той же структуры в дизассемблированном коде. Если структура встречается несколько раз, только первый экземпляр будет полностью испущен, а все остальные вхождения будут заменены тегом `ALREADY_EMITTED`. Это может значительно уменьшить размер файла.
- `-e` - внести правку. Подробнее в разделе ниже.
- `--edit_file` - указать файл правок. Файл правок содержит одну правку на строку. Он использует тот же синтаксис, что и флаг -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
Все числа в байт-коде записаны в [шестнадцатеричной системе](https://en.wikipedia.org/wiki/hexadecimal). Первый столбец в каждой строке представляет `opcode`, или тип выполняемой инструкции. Следующий столбец — регистр назначения, куда будет сохранён результат операции. Последние два столбца — операнды 1 и 2, которые являются либо регистрами, либо литеральными числами, над которыми выполняется операция. Не все инструкции используют все 4 байта; например, первая инструкция `LookupPointer` требует только одного операнда.
Дисассемблер dconstruct также добавляет некоторую дополнительную информацию, призванную немного упростить чтение инструкций. Он также вставляет метки (например, `L_0`), чтобы облегчить отслеживание ветвлений в коде.```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
Это полезно, когда вы хотите просмотреть необработанное содержимое файла, не позволяя программе делать слишком много предположений. Но это может быть трудночитаемо для больших блоков кода, так как отсутствует какая-либо структура. Здесь на помощь приходит декомпилятор.