В этом руководстве я расскажу как можно изменять код 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.
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(врагов).
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 записываются очки за убийства, деньги и ресурсы, а так же вычетаются промахи:
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".
Находим там такие строчки кода:
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
Так на языке ассемблера(код выше) выглядит, вот этот код в декомпиляторе:
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;
Отредактируем значения по-умолчанию и получим примерно такой код:
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 и откроем его для редактирования. Быстро пробегаемся по строчкам кода и... ненаходим структуру команд для поворота врага в сторону нашего кора***.
Находим такие строчки кода:
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 команд:
padding: 6px;
border: 1px inset;
width: 640px;
height: 34px;
text-align: left;
overflow: auto">pushdouble 0.3
И меняем их все на:
padding: 6px;
border: 1px inset;
width: 640px;
height: 34px;
text-align: left;
overflow: auto">pushdouble 0.0
Все, можно сохранять этот файл и закрывать "asasm Editor".
На последок открываем border_dead.class.asasm. Нужно найти такие строки в коде:
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")
Немного комментариев:
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 (просто заменить файл в папке с кешем и выставить галочку в трее "Использовать кеш")
Спасибо за внимание, надеюсь урок был полезен.
(#):
СКАЧАТЬ