
Защита своими руками
Всем привет.
Итак. Нам бы не хотелось, чтоб нашу флешку распотрошили какие-нибудь школьники и запустили под своим именем, что-нибудь внутри поменяв :-) Да и вообще чтоб кто-то там ковырялся.
Какие наши варианты? Пойти и купить защиту. Если есть лишняя сотка баксов, так и делайте. Только непробиваемых защит не бывает, не забывайте.
Я пошел другим путем. По двум причинам: во-первых лишней сотки не было под рукой, во-вторых и мысли защищать флешку у меня не было.
Но возникли два обстоятельства: киндисофт на fgl мою игру защитил так, что она перестала запускаться, хотя ничего такого в ней нет сложноустроенного. А чуть позже я читал ради любопытства статьи на haxe.org и вот здесь haxe.org/com/libs/format/abc увидел такой код: (приводится с сокращениями)
Я когда его читал, еще помнил про облом с киндисофтом. И подумал: ведь так можно реализовать защиту самому.
Ну и сразу шашки в руки и вперед. Базовый вариант, которым я с вами тут и делюсь, был готов часа за полтора. Вот скриншот того, что получилось:

На всякий случай: то, что у меня получилось, это очень простая защита только от школьников.
Используемые инструменты: голова, руки, flashdevelop и flexsdk, а также любой язык, на котором можно написать утилиту командной строки, в моем случае — питон, кстати не лучший выбор, т.к. на нем сложно работать с бинарными данными.
Общая идея:
1. Портим нашу флешку, но так чтоб можно было починить :-)
2. Эмбедим ее в новую флешку как просто бинарный файл
3. В новой флешке получаем как БайтАррэй
4. Чиним испорченное
5. Загружаем лоадером и вуаля
Теперь код. Самое главное:
Прелоадер:
Ну и код на питоне:
Теперь немного про организацию всего этого дела.
Прямо в той же папке что и проект создаем новый проект as3. Ему в пребилд степ ставим вызов питоновского скрипта. В аутпут нэйм — нормальное имя для флешки с игрой. Кроме того не забываем поменть размеры флешки, фпс, цвет бэкграунда, чтобы совпадал с исходным проектом. В аутпут нэйм исходного проекта ставим unprotected.swf. И еще у исходного проекта выкидываем все прелоадеры.
Готово. Теперь компилируем игру, потом протектор. Всё должно работать.
Расширять идею можно до бесконечности.
Итак. Нам бы не хотелось, чтоб нашу флешку распотрошили какие-нибудь школьники и запустили под своим именем, что-нибудь внутри поменяв :-) Да и вообще чтоб кто-то там ковырялся.
Какие наши варианты? Пойти и купить защиту. Если есть лишняя сотка баксов, так и делайте. Только непробиваемых защит не бывает, не забывайте.
Я пошел другим путем. По двум причинам: во-первых лишней сотки не было под рукой, во-вторых и мысли защищать флешку у меня не было.
Но возникли два обстоятельства: киндисофт на fgl мою игру защитил так, что она перестала запускаться, хотя ничего такого в ней нет сложноустроенного. А чуть позже я читал ради любопытства статьи на haxe.org и вот здесь haxe.org/com/libs/format/abc увидел такой код: (приводится с сокращениями)
loader = new flash.display.Loader();
loader.contentLoaderInfo.addEventListener(flash.events.Event.COMPLETE, onLoaded);
loader.loadBytes(swfBytes.getData());
public static function onLoaded(e) {
var m = loader.contentLoaderInfo.applicationDomain.getDefinition("Main");
var inst : Dynamic = Type.createInstance(m,[]);
trace(inst.test());
}
Я когда его читал, еще помнил про облом с киндисофтом. И подумал: ведь так можно реализовать защиту самому.
Ну и сразу шашки в руки и вперед. Базовый вариант, которым я с вами тут и делюсь, был готов часа за полтора. Вот скриншот того, что получилось:

На всякий случай: то, что у меня получилось, это очень простая защита только от школьников.
Используемые инструменты: голова, руки, flashdevelop и flexsdk, а также любой язык, на котором можно написать утилиту командной строки, в моем случае — питон, кстати не лучший выбор, т.к. на нем сложно работать с бинарными данными.
Общая идея:
1. Портим нашу флешку, но так чтоб можно было починить :-)
2. Эмбедим ее в новую флешку как просто бинарный файл
3. В новой флешке получаем как БайтАррэй
4. Чиним испорченное
5. Загружаем лоадером и вуаля
Теперь код. Самое главное:
//ProtectorMain.as
package
{
import flash.display.Loader;
import flash.display.Stage;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.utils.ByteArray;
public class ProtectorMain
{
private var myLoader:Loader;
private var myStage:Stage;
public function ProtectorMain (st:Stage):void
{
myStage = st;
[Embed(source = '../bin/file.bin', mimeType = "application/octet-stream")]
const fileClass:Class;
var bytes:ByteArray = new fileClass as ByteArray;
// восстанавливаем данные. Каждый как умеет :-)
myLoader = new Loader();
myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaded);
myLoader.loadBytes(bytes);
}
private function loaded(e:Event):void
{
myLoader.contentLoaderInfo.removeEventListener(Event.COMPLETE, loaded);
myStage.addChild(myLoader.content);
}
}
}
Прелоадер:
// ProtectorPreloader.as
package
{
import flash.display.DisplayObject;
import flash.display.MovieClip;
import flash.display.Stage;
import flash.events.Event;
import flash.events.ProgressEvent;
import flash.utils.getDefinitionByName;
public class ProtectorPreloader extends MovieClip
{
public function ProtectorPreloader ()
{
addEventListener(Event.ENTER_FRAME, checkFrame);
loaderInfo.addEventListener(ProgressEvent.PROGRESS, progress);
// show loader
// тут каждый сам за себя
}
private function progress(e:ProgressEvent):void
{
// update loader
// и тут тоже каждый сам за себя
}
private function checkFrame(e:Event):void
{
if (currentFrame == totalFrames)
{
removeEventListener(Event.ENTER_FRAME, checkFrame);
startup();
}
}
private function startup():void
{
// hide loader
stop();
loaderInfo.removeEventListener(ProgressEvent.PROGRESS, progress);
var st:Stage = stage;
stage.removeChild(this);
var mainClass:Class = getDefinitionByName("ProtectorMain") as Class;
new mainClass(st);
}
}
}
Ну и код на питоне:
import sys, os
def main():
#paths
inputPath = os.path.join(os.path.dirname(sys.argv[0]), "bin", "unprotected.swf")
outputPath = os.path.join(os.path.dirname(inputPath), "file.bin")
print '"encrypting"', inputPath, "to", outputPath
#read file
inFile = open(inputPath, "rb")
data = inFile.read()
inFile.close()
#corrupt data
#всё сами!
#write files
outFile = open(outputPath, "wb")
outFile.write(data)
outFile.close()
if __name__ == "__main__":
main()
Теперь немного про организацию всего этого дела.
Прямо в той же папке что и проект создаем новый проект as3. Ему в пребилд степ ставим вызов питоновского скрипта. В аутпут нэйм — нормальное имя для флешки с игрой. Кроме того не забываем поменть размеры флешки, фпс, цвет бэкграунда, чтобы совпадал с исходным проектом. В аутпут нэйм исходного проекта ставим unprotected.swf. И еще у исходного проекта выкидываем все прелоадеры.
Готово. Теперь компилируем игру, потом протектор. Всё должно работать.
Расширять идею можно до бесконечности.
- +9
- romamik
Комментарии (33)
Спасибо за пост. Плюсанул.
Можно еще трюк сделать: при компиляции релиза указывать в качестве основного класс, который ничего не делает. И вызывать из протектора совсем другой класс. Тогда собранная swf не будет запускаться.
Кроме того никто не мешает еще и обфускатором игру обработать.
А главное уже и так школьники идут мимо. Туда, где попроще.
2. Скопипастить кусок кода, который восстанавливает данные, не разбираясь.
3. Вставить в свою swf, которая прогоняет восстановление и сохраняет рабочий файл на диск или сервер.
Если не сложно, можешь сделать тестовую защищенную флэшку? Интересно поковырять.
Криптование файла я оставил на совести читателя. Впрочем и у себя не криптовал особо.
А так да, даже если закриптовать, то декриптор будет видно. И что делать? Если флешку может проиграть флеш-плеер, то и человек сможет ее достать и проиграть.
Отличие от обфускации, что прячет не только код, но и арт :-) И обфускации не отменяет, т.е. применять по идее в комплексе. Тут была ссылка на бесплатный обфускатор, кстати.
А что за криптование важных строк? Это что? Каких строк?
Был неправ, признаю. Взлом занял полтора часа :)
Основная проблема заключалась в том, что коммерческие декомпиляторы (как, впрочем, и бесплатные) не умеют выдергивать «эмбеденные байтэрреи» из флэшки. Они их просто не видят.
Пришлось найти исходники простенького парсера swf и заточить под задачу.
Если приделать виртуальную машину для декриптора, то смысла ломать уже не будет, слишком дорого получится.
Будет время — надо будет заняться.
Но вручную не трудно вытащить его из флешки, загрузить в свою и восстановить, если известен алгоритм.
Хотя часть народа отсеется.
Например, сделать декриптор на брейнфаке, и пускай разбираются.
Или я чего-то не понял?
В прелоадере будет интерпретатор этого языка (он маленький, 1-2 килобайта) и сама программка на нем (++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++...).
Чтобы понять, как расшифровывается файл — надо разобрать, что делает программка.
Чтобы заставить разбираться — завязаться внутри декриптора на контрольную сумму флэшки или что-то подобное.
Как-то так.
А сделать это имея программу хоть бы и на брейнфаке — не вопрос.
Я же написал, «завязываемся на контрольную сумму флэшки или что-то подобное».
Если выдрать декриптор и зашифрованный кусок, контрольная сумма будет другая и у нас расшифруется мусор.
Считает — программка на брейнфаке(к примеру).
На вход ей подается вся загруженная флэшка, полностью stage.loaderInfo.bytes, она считает ключ и декриптует (ксорит, в простейшем случае) этим ключом внутреннюю.
Тут получается «бесконечный» цикл, криптование внутренней флешки изменяет ключ внешней, но это можно обруливать.
Вообще, очень интересная тема, давно хотел заняться, все руки не доходят.
Ее изменение ничего не даст (она просто распакуется неверно), а остальная часть (внешняя) — останется защищенной.
Для того, чтобы узнать ключ, надо разобраться с алгоритмом расчета, а он у нас на «брейнфаке».
Против снятия дампов поможет постепенная расшифровка. Каждый уровень отдельно.
А, как я уже писал, абсолютной защиты здесь быть не может.
Просто вырезают алгоритм и пропускают через него же.
Кстати тут что-то похожее делалось
groups.google.com/group/ruflash/browse_thread/thread/63bbed92692d037?hl=ru