RS Game Maker Community
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

 
Расширенный поиск
  Главная  Форум   Вики Блоги FAQ Игры Статьи Примеры Войти Регистрация  
Вики
Все желающие приглашаются редактировать вики. Можете писать о своих (или чужих) играх, размещать туториалы, постить статьи - главное навесить категорию.
Страниц: 1   Вниз
  Печать  
Декомпилятор для GameMaker:Studio
0 Пользователей и 1 Гость смотрят эту тему.
input.txt
Не очень
Активный участник
**

Репутация: 17
Offline Offline

Сообщений: 117


12.8 Gb

18 Июня 2017 в 15:10
В старые времена GML был интерпретируемым языком, и код хранился в исполняемом файле чуть ли не с комментариями, так что "декомпилятор" было написать крайне легко. С выходом GM:S хорошие времена для мамкиных хакеров закончились – теперь YoYoGames встроили в исполняемый файл виртуальную машину собственного изобретения и GML компилируется в байт-код для неё. При этом формат байт-кода и файла периодически заботливо меняют.
Насколько мне известно, на данный момент для GM:S не существует инструментов для декомпиляции. Есть конечно распаковщики ресурсов (типа Altar.NET), но они не производят никакого анализа и уж точно не генерируют код на GML. Таким образом, мой проект предназначен для того, чтобы закрыть эту нишу.

Итак, я сотворил прототип декомпилятора на С++. Все желающие могут скачать его с репозитория и оценить, как он не работает. Для удобства я также подготовил архив с тестовым проектом, на котором декомпилятор точно не падает.

Принцип работы
В основе лежит алгоритм структурного анализа. Программа разбивается на базовые блоки – участки кода, которые не содержат инструкций перехода. Из них потом строится граф потока управления (flowgraph), где узлы – это собственно базовые блоки (ББ), а дуги – переходы между ними.


* flow1.png (5.34 Кб. 214x300 - просмотрено 18 раз.)

Рис. 1. Граф потока управления.

Далее алгоритм просматривает поочередно все узлы, и если данный узел является точкой входа в один из шаблонов, то весь этот участок заменяется на абстрактный узел. Процесс заканчивается, когда на очередном проходе не удалось найти ни одного совпадения.
(При этом, если граф сводимый, то в нем останется только одна вершина).


* templates.png (13.23 Кб. 752x278 - просмотрено 18 раз.)

Рис. 2. Шаблоны конструкций.


* flowgraph_conv.png (39.78 Кб. 884x280 - просмотрено 21 раз.)

Рис. 3. Пример свертки.

Последний оставшийся узел содержит в себе дерево управления, оно же (в данной реализации) синтаксическое дерево. И на основе его уже генерируется код на GML.


* ctrl_tree.png (11.68 Кб. 450x359 - просмотрено 19 раз.)

Рис. 4. Дерево управления.

Основные проблемы
  • Невозможно создать шаблон для циклов, содержащих break и continue. Так что для их распознавания нужен другой метод.
  • Отсутствие какого-либо анализа потока данных не позволяет нормально обрабатывать инструкцию dup, так как в этом случае на стеке оказывается две версии одной переменной, и все ломается.

Текущие возможности
Сейчас декомпилятор может восстанавливать следующие конструкции:
  • if, if-else
  • while, for, repeat-until do-until (for превращается в эквивалентный while)
  • Арифметические выражения любой сложности, с операторами разного приоритета и вложенными скобками. Иногда код после декомпиляции выглядит лучше исходного
  • Аналогично, логические выражения (отдельный пункт, т.к. они представлены совершенно другим образом)
  • Вызовы функций (в смысле скриптов) с любым количеством аргументов.
  • +=, -=, *=, /=, …
  • Массивы, в том числе двумерные.
  • Обращение к полям объектов.
Все перечисленное может иметь любую сложность и глубину вложенности:
a.b.c[d.e || true, f.g.h && s[t, u && v]] = s || x && --lol;

Работа над проектом будет продолжаться, пока GMS2 не выйдет из беты. Так что даже есть шансы, что он будет закончен.

Прикреплённые файлы Графические миниатюры:
Последнее редактирование: 22 Августа 2017 в 14:36 от input.txt
 
tolich
to ne lich
Ветеран форума
*****

Репутация: 214
Online Online

Сообщений: 1 488


moonlite

Ответ № 1 19 Июня 2017 в 10:05
Что за repeat-until? Испокон веку было do-until.

input.txt
Не очень
Активный участник
**

Репутация: 17
Offline Offline

Сообщений: 117


12.8 Gb

Ответ № 2 19 Июня 2017 в 12:51
Do, конечно. Это я, видимо, с Lua его перепутал.
В любом случае, сейчас перепроверил - он тоже нормально восстанавливается.
Огион
Завсегдатай
****

Репутация: 132
Offline Offline

Сообщений: 960


Ответ № 3 20 Июня 2017 в 12:33
Круто.
Есть какая-нибудь интересная инфа о внутренней работе GM, которая может быть полезна простому разработчику?
input.txt
Не очень
Активный участник
**

Репутация: 17
Offline Offline

Сообщений: 117


12.8 Gb

Ответ № 4 20 Июня 2017 в 23:04
Подборка интересных фактов:
  • Аксессоры – это на самом деле функции, и их можно даже вызвать напрямую.
    a = list[| i ];<=>   ds_list_find_value( list, i );
    list[| i ] = a;<=>   ds_list_set( list, i, a );
    a = map[? key ];<=>   ds_map_find_value( map, key );
    map[? key ] = a;<=>   ds_map_set( map, key, a );
    a = arr[@ i ];<=>   array_get( arr, i );
    arr[@ i ] = a;<=>   array_set( arr, i, a );
    a = grid[# i, j ];<=>   ds_grid_get( grid, i, j );
    grid[# i, j ] = a;<=>   ds_grid_set( grid, i, j, a );

    Это может упростить работу со вложенными массивами
    inner[5] = "Hello";
    arr[1] = inner;

    // show_message( arr[1][5] );   // ERROR
    show_message( array_get( arr[1], 5 ) );   // "Hello"

    Так же, как и функции, не проверяют тип аргумента. Хотя его вообще нельзя проверить, потому что id структуры это просто число, так еще и для каждого типа отдельная нумерация.
    var map = ds_map_create();
    map[? 13 ] = "map";

    var list = ds_list_create();
    list[| 13 ] = "list";

    show_message( map[? 13 ] );  // "map"
    show_message( list[| 13 ] ); // "list"
    show_message( map[| 13 ] );  // "list" !!!
    show_message( list[? 13 ] ); // "map"  !!!
  • Двумерные массивы можно использовать как одномерные с размером до 32000*32000 = 1024000000.
    i = 5;
    j = 2;
    a[i, j] = 42;
    // a[i, j] == a[i*32000 + j] == a[5*32000 + 2] == a[160002] == 42;
    for( var i = 0; i < 1000000; ++i ) {
        a[i] = i + 1;
    }
    show_message( a[65535] ); // 65536
Последнее редактирование: 20 Июня 2017 в 23:16 от input.txt
Страниц: 1   Вверх
  Печать  
 
Перейти в:  

RSGMC (gmakers.ru) © 2007—2017
Счётчик–@Mail.ru