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

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

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

Сообщений: 151


12.8 Gb

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

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

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


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

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

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


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

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


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

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

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


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

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

История версий
1.0.0
  • Решена проблема с break/continue в циклах. Кроме нескольких исключительных ситуаций – задачу сломать анализатор оставим читателям в качестве упражнения
  • Решена проблема с префиксными/постфиксными инкрементами
  • Добавлена поддержка операторов switch, repeat, with
  • Добавлены параметры командной строки для управления декомпилятором
  • Улучшено форматирование при генерации кода

ПоказатьСтарые версии
0.1.0
Основные проблемы
  • Невозможно создать шаблон для циклов, содержащих 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 не выйдет из беты. Так что даже есть шансы, что он будет закончен.

Прикреплённые файлы Графические миниатюры:
Последнее редактирование: 19 Мая 2018 в 02:48 от input.txt
 
tolich
to ne lich
Ветеран форума
*****

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

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


moonlite

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

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

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

Сообщений: 151


12.8 Gb

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

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

Сообщений: 992


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

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

Сообщений: 151


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
input.txt
Не очень
Активный участник
**

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

Сообщений: 151


12.8 Gb

Ответ № 5 19 Мая 2018 в 02:48
EPIC UPDATE

Официально заявляю об анонсе S.T.A.L.K.E.R. 2 о релизе версии 1.0

Все конструкции GML, которые я только вспомнил, обрабатываются более-менее нормально. Остается, конечно, множество косяков и решений, захардкоженных под конкретные грабли. Но я запускал анализ на нескольких реальных проектах, и декомпилятор их успешно прожевал.

Дальнейшие планы – сделать распаковку .exe в проект для GMS 2, ну и чинить баги, очевидно.
Прикреплённые файлы
* Build_1.0.zip (5303.67 Кб - загружено 415 раз.)
Илья
Ветеран форума
*****

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

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

Ответ № 6 19 Мая 2018 в 12:58
Круто, че сказать. Давайте пилить open source GM.

Черный Думер
Треугольник будет выпит!
Новичок


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

Сообщений: 33


Ответ № 7 25 Мая 2019 в 15:03
Это очень круто. Репозиторий на BitBucket актуален?
Ну и посмотреть темы на других форумах было бы интересно, если есть. :)

Ещё кстати есть вот такая вот вещица:
https://github.com/krzys-h/UndertaleModTool

UPD: Показал эту тему разработчику UndertaleModTool, далее его ответ:
Krzysztof Haładyn: Thanks! We'll look through it to see if they figured out anything that we're still missing, but assuming the list of non-working stuff README is accurate, they had problems with exactly the same things we did but we already managed to implement most of these. Their code looks a lot cleaner than ours though.

Чёрный Думер, Черный Думер
С монстрами сражается.
Черный Думер, Черный Думер
Рокетланчер плавится.
input.txt
Не очень
Активный участник
**

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

Сообщений: 151


12.8 Gb

Ответ № 8 25 Мая 2019 в 20:58
Спасибо!
Да, теперь репозиторий точно актуален, в смысле это самая последняя версия. Потому что месяц назад у меня накрылся hdd и похоронил всё что там было. За исключением регулярных бэкапов самого дорогого, конечно.

Про UndertaleModTool не знал, крайне полезная информация. Особенно по бинарному формату, добавилось много всяких штук. Хотя в GMS2 я для спрайтов вычислил больше полей, лол.

Немного вводит в заблуждение то, что я своими кривыми руками наплодил веток. А в репозитории по умолчанию выбирается ветка defаult, тогда как актуальна ветка dev. Там я уже победил почти всё, кроме continue в for{}, и там немного другой readme.

Тем на других форумах нет) Я кажется даже на хелруме на зарегистрирован..
Черный Думер
Треугольник будет выпит!
Новичок


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

Сообщений: 33


Ответ № 9 25 Мая 2019 в 21:47
Потому что месяц назад у меня накрылся hdd и похоронил всё что там было. За исключением регулярных бэкапов самого дорогого, конечно.
А насколько примерно репозиторий отстаёт от сборки 1.0 из первого сообщения?
Что до диска - не пробовал R-Studio какой-нибудь? Меня он спасал даже в ситуациях с побившимися флешками.

Хотя в GMS2 я для спрайтов вычислил больше полей, лол.
Напиши поляку, пусть допилит. Чего добру пропадать.

Немного вводит в заблуждение то, что я своими кривыми руками наплодил веток. А в репозитории по умолчанию выбирается ветка defаult, тогда как актуальна ветка dev. Там я уже победил почти всё, кроме continue в for{}, и там немного другой readme.
А почему BitBucket кстати, почему не GitHub?

Тем на других форумах нет) Я кажется даже на хелруме на зарегистрирован..
Зря. Жаль.

Чёрный Думер, Черный Думер
С монстрами сражается.
Черный Думер, Черный Думер
Рокетланчер плавится.
input.txt
Не очень
Активный участник
**

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

Сообщений: 151


12.8 Gb

Ответ № 10 Вчера в 00:05
А насколько примерно репозиторий отстаёт от сборки 1.0 из первого сообщения?
Не отстает, а опережает. Там уже добавлены "типы" констант. Алгоритма по их расстановке правда нет – я как раз собирался его сделать, но вот не успел. (посмотрел, у поляков что-то такое уже запилено)

Что до диска - не пробовал R-Studio какой-нибудь?
Ну тут уже всё. Не проходит POST, мерзко пищит и не раскручивается.
Но бэкапы были – один даже всего двухнедельной давности. Интересно, что я не помню, чтоб сознательно их делал. Условный рефлекс с 00х и переустановок ШИНДОВС, не иначе.

А почему BitBucket кстати, почему не GitHub?
Когда начинал, тут делали очередной общий проект, Соор-3 что ли кстати где он. На битбакете, собственно.
А еще на гитхабе тогда бесплатных приватных репозиториев не было.

К сожалению, сейчас нет времени на всё это. Как вернусь к допиливанию (через ~2 недели?), так можно будет.
Ох лол, может создать тему на официальном форуме YoYo? И не забыть упомянуть, что у меня пиратская студия.
Черный Думер
Треугольник будет выпит!
Новичок


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

Сообщений: 33


Ответ № 11 Вчера в 01:29
Ох лол, может создать тему на официальном форуме YoYo? И не забыть упомянуть, что у меня пиратская студия.
Ну на официальном не надо, а вот на hellroom и каких-нибудь зарубежных - почему бы и нет.

Чёрный Думер, Черный Думер
С монстрами сражается.
Черный Думер, Черный Думер
Рокетланчер плавится.
input.txt
Не очень
Активный участник
**

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

Сообщений: 151


12.8 Gb

Ответ № 12 Вчера в 04:12
Скачал посмотреть, что там у них. Все-таки почти единственный действительно работающий проект.
Графический интерфейс и редактор это конечно плюс, но сама декомпиляция страдает, и местами сильно.
Вот например скрипт с двумерными массивами. Слева исходник (он же результат gmsdc), справа результат umt.
a[i, j] = 0;
a[b0 && b1, c0 || c1] = 10;
a.b.c[d.e || 1, f.g[i].h && s[t, u && v]] = s || x && --lol;
b[i, j] += 1;
c.d[i] += 1;
e.f[i, j] += 1;
g++.h.a[i++, ++j] += 1;

var _temp_local_var_1, _temp_local_var_2, _temp_local_var_3, _temp_local_var_4, _temp_local_var_5, _temp_local_var_6, _temp_local_var_7, _temp_local_var_8, _temp_local_var_9, _temp_local_var_10;
a[i, j] = o_main
_temp_local_var_1 = self
_temp_local_var_2 = 10
_temp_local_var_3 = (b0 && b1)
_temp_local_var_3 = (_temp_local_var_3 * 32000)
_temp_local_var_4 = (c0 || c1)
_temp_local_var_1.a[(_temp_local_var_3 + _temp_local_var_4)] = _temp_local_var_2
if s
    _temp_local_var_5 = 1
else if x
{
    lol = (lol - 1)
    _temp_local_var_5 = (lol - 1)
}
else
    _temp_local_var_5 = o_main
_temp_local_var_6 = a.b
_temp_local_var_7 = (d.e || 1)
_temp_local_var_7 = (_temp_local_var_7 * 32000)
if f.g[i].h
{
    _temp_local_var_8 = (t * 32000)
    _temp_local_var_9 = self
    _temp_local_var_10 = (u && v)
    _temp_local_var_9 = _temp_local_var_9.s[(_temp_local_var_8 + _temp_local_var_10)]
}
else
    _temp_local_var_9 = o_main
_temp_local_var_6.c[(_temp_local_var_7 + _temp_local_var_9)] = _temp_local_var_5
b[i, j] = (b[i, j] + 1)
c.d[i] = (c.d[i] + 1)
e.f[i, j] = (e.f[i, j] + 1)
g = (g + 1)
i = (i + 1)
j = (j + 1)
g.h.a[i, (j + 1)] = (g.h.a[i, (j + 1)] + 1)

Хотя семантически они, вероятно, одинаковы.
Страниц: 1   Вверх
  Печать  
 
Перейти в:  

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