Перейти к содержимому


Фотография
- - - - -

Edit ActionScript или как взломать flash игры


  • Авторизуйтесь для ответа в теме
В этой теме нет ответов

#1 Grender

Grender

    Командор

  • Пользователи
  • PipPipPipPipPipPipPipPipPipPipPipPipPipPipPip
  • Репутация
    353
  • 142 сообщений
  • 146 тем

Отправлено 15 Июль 2013 - 21:23

В этом руководстве я расскажу как можно изменять код swf игры.
Статья расчитана не на всех, в основном для профи, которые хоть немного, но знакомы с программированием и с самим Flash'ом и ActionScript'ом. Способ не нова, вобще возможность изменять байт-код flash файла давно известна, но ограниченному кругу людей. Я расширю этот круг и дам некоторое описание данного способа редактирования кода.

Программы, нужные нам для работы:

Пожалуйста Войдите или Зарегистрируйтесь чтобы увидеть скрытый текст


Пожалуйста Войдите или Зарегистрируйтесь чтобы увидеть скрытый текст


Пожалуйста Войдите или Зарегистрируйтесь чтобы увидеть скрытый текст




 

Предисловие

Sothink SWF Decompiler позволяет нам декомпилировать flash файлы, просматривать код и другие объекты(картинки, MovieClip'ы, звуки и т.д.). Нам он нужен будет только для изучения кода игры.
Минусы: иногда дает сбой при декомпилировании *.as файла и просто вылетает, тогда остается изучать и редактировать код через Flash Scalpel; платный, хотя найти ключ вроде не такая проблема.

Flash Scalpel позволяет редактировать байт-код flash файла. Через него мы будет редактировать код для взлома. Эту программу написал Admin сайта forum333.com на основе RABCDASM и добавил к нему редактор для просмотра и редактирования кода, аналогия MiDIDE.
Минусы: не нашел пока что.

ASDec позволяет просматривать код в AS2/3, а так же редактировать байт-код flash файла. Т.е. можно сказать так ASDec = Sothink SWF Decompiler + Flash Scalpel.
Минусы: так же как и Sothink SWF Decompiler может дать сбой при декомпиляции кода, и тогда вы не сможете просмотреть и отредактировать код, и останется только Flash Scalpel.

AVM2(ActionScript Virtual Machine 2) - виртуальная машина Flash Player'а, которая выполняет байт-код swf файла.


Разбирать будем мою flash игру, которую я делал на конкурс нашего одного института, и на это есть весомые причины:
1) Я очень зол на то, что мы заняли 3-е место, нас обогнали 2 игры: "Крестики-нолики" 2-е место, "Жизнь студента" 1-ое место. Не знаю по каким критериям оценивали игры, может даже по количеству человек работавших над игрой. Над нашей работал я и 2 моих одноклассники, над "К.-н." и "Ж. с." работало по 1-му человеку.
2) Раз уж я делал(я писал код, а друзья работали над дизайном) эту игру, то и мне лучше знать все слабые для взлома места в коде.

Пока что нам понадобятся: Sothink SWF Decompiler и Flash Scalpel.



Изучаем "пациента"

Прежде чем ринуться ломать игру, нужно ее как-то изучить. Изучение игры один из сложных задач перед взломо, нужно определить слабые места приложения. Ну, а если приложения представляет из себя целый проект связанных между собой swf файлов, то это задача усложниться.

Сейчас ничего сложного не будет, потому что объяснять уязвимости своей игры буду я.

Ссылка на мою игру:

Пожалуйста Войдите или Зарегистрируйтесь чтобы увидеть скрытый текст




Начнем с разбора класса player.as. Откройте мою игру через Sothink SWF Decompiler. Раскройте директорию Actions в верхнем-правом углу и выберите файл player.

Пожалуйста Войдите или Зарегистрируйтесь чтобы увидеть скрытый текст


 

Код:
        margin: 0px;
        padding: 6px;
        border: 1px inset;
        width: 640px;
        height: 162px;
        text-align: left;
        overflow: auto">public var delayConst:uint = 50; // число максимальной задержки между выстрелами
public var delayAt:uint = 50; // текущие число задержки для выстрела, когда delayAt==delayConst можно стрелять
public var typeLaser:uint = 1; // тип лазера, максимум у меня 6
public var speedLaser:uint = 5; // скорость полета лазера
public var strength:int = 50; // текущая прочность
public var strengthMax:uint = 50; // максимальная прочность
public var speedX:int = 10; // скорость полета вперед-назад(по экрану влево и вправо)
public var speedY:int = 0; // текущая скорость полете в боковые стороны(по экрану вверх и вниз)
public var speedYCon:uint = 30; // максимальная скорость в боковые стороны

Если изменить значение:
- delayConst и delayAt на меньшее число, можно добиться хорошей скорострельности лазером;
- typeLaser на 6, можно будет использовать максимальный лазер в игре(урон будет равен typeLaser*10);
- speedLaser на 8(к примеру), то лазер будет лететь быстрее, но советую слишком большое значение не ставить, иначе лазер пролетит сквозь врага;
- strength и strengthMax на любое большое значение(но не превосходящие максимального значение Integer), можно будет иметь хорошу прочность кора***;
- speedX и speedYCon на любое значение(но не слишком большое, чтобы не улететь за экран), то корабль будет лететь с такой скоростью с какой вы зададите.

Следующим на очереди будет класс enemies(врагов).
 

Код:
        margin: 0px;
        padding: 6px;
        border: 1px inset;
        width: 640px;
        height: 114px;
        text-align: left;
        overflow: auto">public var score:uint = 0; // Значения всех переменных
public var speed:uint = 3; // изменять бесполезно
public var strength:int = 10; // при создание каждого врага
public var typeLaser:uint = 1; // я их корректирую
public var delayAtack:uint = 100;
public var delayAtCon:uint = 100;

В игре есть враги, которые летят на игрока и стреляют лазером в его сторону. Для них действует код внутри if(exat){..}, позволяющий по тригонометрической формуле поворачиваться в сторону другого объекта.

Команды типа:
e.target.rotation = e.target.rotation +/- 0.3;
позволяют плавно поворачивать врага к кораблю игрока. Если их изменить на:
e.target.rotation = e.target.rotation;
или вобще удалить, то эти "особые" враги будут лететь вперед как и все остальные.

Класс upgrade, который содержит логику для апгрейда частей кора***.
this.buy = [..] - массив, который содержит число ресурсов и денег требуемых для апгрейда, а так же число на которое нужно повысить. Разбирать его и этот класс не будем, поэтому оставляю это удовольствие вам.

Ну и на последок разберем класс border_dead, в нем нас будет интересовать подсчет очков для рекордов.

В total записываются очки за убийства, деньги и ресурсы, а так же вычетаются промахи:

Код:
        margin: 0px;
        padding: 6px;
        border: 1px inset;
        width: 640px;
        height: 130px;
        text-align: left;
        overflow: auto">this.total = this.total + this.kills * 4;
this.total = this.total + this.money;
this.total = this.total + this.numsAl * 3;
this.total = this.total + this.numsCu * 2;
this.total = this.total + this.numsFe;
this.total = this.total + this.numsZn * 3;
this.total = this.total - this.miss * 2;

Надеюсь расшифровка имен переменных и логических действий не нужна, если что, сразу к Google.

Игра содержит еще некоторую часть уязвимостей, поэтому для практике можете найти и разобрать их на досуге.

 

Приступаем к "хирургическим" операциям

Запустите asAsmGUI.exe(Flash scalpel) и откройте мою игру: File -> Load swf.

Пожалуйста Войдите или Зарегистрируйтесь чтобы увидеть скрытый текст



Выберите строчку с названием "000" и нажмите кнопку "dissasembler", после у вас заполнится список файлами *.class.asasm и *.script.asasm.

Пожалуйста Войдите или Зарегистрируйтесь чтобы увидеть скрытый текст



Найдите в списке файл player.class.asasm и нажмите кнопку "Edit File".

Пожалуйста Войдите или Зарегистрируйтесь чтобы увидеть скрытый текст



Находим там такие строчки кода:

Код:
        margin: 0px;
        padding: 6px;
        border: 1px inset;
        width: 640px;
        height: 162px;
        text-align: left;
        overflow: auto">trait slot QName(PackageNamespace(""), "delayConst") type QName(PackageNamespace(""), "uint") value Integer(50) end
trait slot QName(PackageNamespace(""), "delayAt") type QName(PackageNamespace(""), "uint") value Integer(50) end
trait slot QName(PackageNamespace(""), "typeLaser") type QName(PackageNamespace(""), "uint") value Integer(1) end
trait slot QName(PackageNamespace(""), "speedLaser") type QName(PackageNamespace(""), "uint") value Integer(5) end
trait slot QName(PackageNamespace(""), "strength") type QName(PackageNamespace(""), "int") value Integer(50) end
trait slot QName(PackageNamespace(""), "strengthMax") type QName(PackageNamespace(""), "uint") value Integer(50) end
trait slot QName(PackageNamespace(""), "speedX") type QName(PackageNamespace(""), "int") value Integer(10) end
trait slot QName(PackageNamespace(""), "speedY") type QName(PackageNamespace(""), "int") value Integer(0) end
trait slot QName(PackageNamespace(""), "speedYCon") type QName(PackageNamespace(""), "uint") value Integer(30) end

Так на языке ассемблера(код выше) выглядит, вот этот код в декомпиляторе:

Код:
        margin: 0px;
        padding: 6px;
        border: 1px inset;
        width: 640px;
        height: 162px;
        text-align: left;
        overflow: auto">public var delayConst:uint = 50;
public var delayAt:uint = 50;
public var typeLaser:uint = 1;
public var speedLaser:uint = 5;
public var strength:int = 50;
public var strengthMax:uint = 50;
public var speedX:int = 10;
public var speedY:int = 0;
public var speedYCon:uint = 30;

Отредактируем значения по-умолчанию и получим примерно такой код:

Код:
        margin: 0px;
        padding: 6px;
        border: 1px inset;
        width: 640px;
        height: 162px;
        text-align: left;
        overflow: auto">trait slot QName(PackageNamespace(""), "delayConst") type QName(PackageNamespace(""), "uint") value Integer(10) end
trait slot QName(PackageNamespace(""), "delayAt") type QName(PackageNamespace(""), "uint") value Integer(10) end
trait slot QName(PackageNamespace(""), "typeLaser") type QName(PackageNamespace(""), "uint") value Integer(6) end
trait slot QName(PackageNamespace(""), "speedLaser") type QName(PackageNamespace(""), "uint") value Integer(8) end
trait slot QName(PackageNamespace(""), "strength") type QName(PackageNamespace(""), "int") value Integer(5000) end
trait slot QName(PackageNamespace(""), "strengthMax") type QName(PackageNamespace(""), "uint") value Integer(5000) end
trait slot QName(PackageNamespace(""), "speedX") type QName(PackageNamespace(""), "int") value Integer(20) end
trait slot QName(PackageNamespace(""), "speedY") type QName(PackageNamespace(""), "int") value Integer(0) end
trait slot QName(PackageNamespace(""), "speedYCon") type QName(PackageNamespace(""), "uint") value Integer(40) end

Сохраним файл(Ctrl+S) и закроем окно "asasm Editor".

Найдем теперь в списке файл player.class.asasm и откроем его для редактирования. Быстро пробегаемся по строчкам кода и... ненаходим структуру команд для поворота врага в сторону нашего кора***.

Находим такие строчки кода:

Код:
        margin: 0px;
        padding: 6px;
        border: 1px inset;
        width: 640px;
        height: 82px;
        text-align: left;
        overflow: auto">getscopeobject 1
newfunction "enemies/iinit/inline_method"
coerce QName(PackageNamespace(""), "Function")
setslot 1

Нас интересует это - newfunction "enemies/iinit/inline_method", а точнее адрес до описания тела функции. Пришла пора увидеться кучу файлов кода, рядом с файлом игры(там, где вы ее распаковали) должна появится папочка "abc_0". В ней у нас хранятся файлы *.class.asasm и *.script.asasm. Бывает так, что все файлы не помещаются в список, поэтому их можно найти и здесь.

Откройте эту папку "abc_0".

Пожалуйста Войдите или Зарегистрируйтесь чтобы увидеть скрытый текст



Продолжаем поиск функции поворота врага: открываем директорию "enemies/iinit", там должен быть один файл "inline_method.method.asasm".

Пожалуйста Войдите или Зарегистрируйтесь чтобы увидеть скрытый текст



Вернитесь к "asasm Editor" и откройте этот файл "inline_method.method.asasm" File -> Open File.

Находим в этом коде целых 6 команд:

Код:
        margin: 0px;
        padding: 6px;
        border: 1px inset;
        width: 640px;
        height: 34px;
        text-align: left;
        overflow: auto">pushdouble 0.3

И меняем их все на:

Код:
        margin: 0px;
        padding: 6px;
        border: 1px inset;
        width: 640px;
        height: 34px;
        text-align: left;
        overflow: auto">pushdouble 0.0

Все, можно сохранять этот файл и закрывать "asasm Editor".

На последок открываем border_dead.class.asasm. Нужно найти такие строки в коде:

Код:
        margin: 0px;
        padding: 6px;
        border: 1px inset;
        width: 640px;
        height: 322px;
        text-align: left;
        overflow: auto">getlocal0
getlocal0
getproperty QName(PackageNamespace(""), "total")
getlocal0
getproperty QName(PackageNamespace(""), "numsZn")
pushbyte 3
multiply
add
initproperty QName(PackageNamespace(""), "total")

getlocal0
getlocal0
getproperty QName(PackageNamespace(""), "total")
getlocal0
getproperty QName(PackageNamespace(""), "miss")
pushbyte 2
multiply
subtract
initproperty QName(PackageNamespace(""), "total")

Немного комментариев:

Код:
        margin: 0px;
        padding: 6px;
        border: 1px inset;
        width: 640px;
        height: 130px;
        text-align: left;
        overflow: auto">pushbyte 3 // ложим число 3
multiply            // умножаем на него
add                // и прибавляем

pushbyte 2 // ложим число 2
multiply            // умножаем на него
subtract            // и вычетаем

Давайте сделаем, чтобы у нас очки за промахи не вычитались, а наооборот прибавлялись - меняем команду subtract на add.

Кстати, вы можете прочитать справку про многие команды ассемблера, для этого достаточно выделить нужную команду и нажать F1. К примеру так выглядит пояснение к команде subtract.

Пожалуйста Войдите или Зарегистрируйтесь чтобы увидеть скрытый текст



Сохраняем файл так же, как это делали уже несколько раз. "asasm Editor" тоже можете закрыть.

Теперь надо бы все собрать весь код и упаковать в один файл *.swf.

Нажимаем кнопку "assembler" и смотрим в лог.

Пожалуйста Войдите или Зарегистрируйтесь чтобы увидеть скрытый текст



Если у вас будет написано "Assembler abc_0: Ok", значит вы не допустили ни одной грубой ошибки и компилятор успешно все скомпоновал. Теперь сохраните файл File -> Save swf.

Если решили использовать только ASDec, то вам для редактирования байт-кода нужно будет кликать в область декомпилированного кода, редактировать байт-код и нажать кнопку "Save trait". Дизассемблированный код выглядит в этой программе немного по-другому. Вот пример для изменения значения переменной:

Пожалуйста Войдите или Зарегистрируйтесь чтобы увидеть скрытый текст



Сохраняем swf файл File -> Save.
 

Практика и еще раз практика

Есть еще один хороший способ изучения байт-кода AVM2. Пишем, к примеру на FlashDevelop, простой код на AS3 и компилируем свою flash'ку. А дальше открываем через дизассемблер и изучаем код, можно и попробывать его немного отредактировать.

Дополнительная литература:

Пожалуйста Войдите или Зарегистрируйтесь чтобы увидеть скрытый текст


Пожалуйста Войдите или Зарегистрируйтесь чтобы увидеть скрытый текст

(это то, что во Flash scalpel -> Help)

Пожалуйста Войдите или Зарегистрируйтесь чтобы увидеть скрытый текст


Пожалуйста Войдите или Зарегистрируйтесь чтобы увидеть скрытый текст


 

А что дальше?

Нужно подменить оригинальный *.swf файл на наш измененный. К примеру для этого подойдут такие программы:
- Charles (через Map local)
- HandyCache (просто заменить файл в папке с кешем и выставить галочку в трее "Использовать кеш")

Спасибо за внимание, надеюсь урок был полезен.

(#):

Пожалуйста Войдите или Зарегистрируйтесь чтобы увидеть скрытый текст

 


  • 0




Количество пользователей, читающих эту тему: 0

0 пользователей, 0 гостей, 0 анонимных