Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Свой обфускатор as3 кода (http://www.flasher.ru/forum/showthread.php?t=181653)

vizgl 28.06.2012 20:25

Свой обфускатор as3 кода
 
Написал свой обфускатор as3 кода.
Используются 2 библиотеки: работа с тегами swf файла as3swf, работа с байтокодом as3abc. Последнюю библиотеку дополнил возможностью сохранять измененный байткод, т.к. она позволяла только получить данные о классах, методах и т.д.
Обфускатор умеет обфусцировать: неймспейсы, классы, переменные, методы, геттеры/сеттеры, и константы.

Для проверки на возможность переименовывания методов/переменных/констант, я написал анализатор байткода. Он ищет во всех функциях опкоды которые обрабатывают строки и запоминает эти строки, чтобы в дальнейшем не сломать их, если вдруг будет переменная с таким же именем, при её обфускации.
Т.е. если в коде где-нибудь встречается строка "Update" и метод Update, то этот метод не переименуется, т.к. в таблице строк тега abc, хранится один экземпляр строки Update, который соответствует и строке и имени метода.

Теперь вылез вот такой случай, например есть такой код:
Код:
Код AS3:

var obj: Object;
function Foo(): void
{
  obj.Foo();
}

Когда мы обфусцируем метод Foo, вместе с ним обфусцируется и свойство Foo у obj, но это не правильно, т.к. это свойство динамическое, то в рантайме вылезет ошибка. Так вот выходом было добавление в анализатор, обработки таких случаев.
Если опкод один из этих GetProperty, SetProperty, CallProperty, CallPropVoid то добавляем в игнорлист его значение. В примере это свойство Foo обьекта obj.
Так все работает, но только если обфусцировать приложения скомпилированное в Flex Sdk, если приложение скомпилированное во Flash, то получается что все, выше перечисленные опкоды, применяются когда класс обращается к своему члену, а не как обращение к динамическому методу обьекта. И получается ни один метод не переименовывается, т.к. находится в игнор листе.

Посоветуйте как это лучше сделать.

Aquahawk 28.06.2012 21:06

офигеть, дайте две! as3abc я так и не полез дописывать сборщик на место. Вы опубликовали или собираетесь ли опубликовать сырцы этого дополнения?
Действительно есть над чем подумать.
А что вы делаете с jmp в коде? все пересчитываете на новые адреса?

vizgl 28.06.2012 21:39

Сам обфускатор открывать не буду, а дописанную либу могу опубликовать. В репозитории последний коммит 2 года назад, не думаю что автор еще собирается поддерживать проект.
На счет jmp, я не заморачивался, автор библиотеки не дописал этот функционал, я тоже не писал. Сам то не использую метки в коде.
К тому же код я не меняю, а только таблицу констант, в таком случае не приходится пересчитывать смещения для меток свича, джампов и т.д.

vizgl 28.06.2012 21:49

Вложений: 1
Вот дополненная библиотека. Еще многое нужно тестировать, т.к. думаю багов полно будет, если изменять само байткод.
Есть еще такая библиотека AS3 Commons Bytecode но она у меня что-то плохо собирала файл обратно.

maxkar 28.06.2012 22:18

Цитата:

Посоветуйте как это лучше сделать.
Вариантов два. Менять все динамические GetProperty, на нужные вам классические getlex и т.п.. Или править имена в GetProperty, etc....

В первом случае придется разбирать либо один вариант GetProperty (если там multiname) или пару getpropertystrict + getproperty (если во втором multinameL). Также придется смотреть на тип obj в динамическом вызове и проверять, есть ли у этого тип соответствующие методы или нет (на этапе анализа, исходя из типов аргументов функции, например). Ну и при выполнении всех условий заменять опкод (или два) на один "строгий" вызов.

Во втором случае все примерно так же. В этом случае одна из констант переименовывается вместе с именем метода/свойства.

Но в исходном подходе "маскирования" свойств есть большая проблема. Как вы обрабатываете multinameL? Пример:
Код AS3:

trace(obj[a==3 ? 'a' : 'b']);

multinameL скорее всего будут, например, при работе со внешним миром (что-то по сети прочитали, распарсили, сложили в map). По идее в качестве значения может быть все, что угодно, и это автоматически запретит переименования везде. Так что нужно определять набор классов, к каким допустимо переименование, а к каким - нет. И при этом учитывать, что запрет переименования в родителе не всегда должен приводить к невозможности переименования в детях (иначе обычный динамический доступ к Object опять убъет все переименования). Это тоже делается, для каждой переменной нужно строить список классов, значения которых могут храниться в этой переменной (не то, что заявлено типами, а то, что туда может придти через program flow).

vizgl 28.06.2012 23:11

Цитата:

Сообщение от maxkar (Сообщение 1086490)
Как вы обрабатываете multinameL? Пример:
Код AS3:

trace(obj[a==3 ? 'a' : 'b']);


Так 'a' и 'b' отметятся как строки и не будут переименованы.

А действительно некоторые опкоды выполняют разные задачи при компиляции flex sdk и в flash ide? Или это я где-то натупил?

maxkar 28.06.2012 23:23

А кто их как строки то отметит? Если бы там было
Код:

trace(a==3 ? obj['a'] : obj['b']);
тогда да.
А мой код эквивалентен
Код:

const tmp : String = a== 3 ? 'a' : 'b';
trace(obj[tmp]);

Вы же, наверное, не все "строки" из пула строк помечаете как невалидные. Но даже это не поможет против multinameL, имена могут быть не в пуле:
Код:

for (var i : int = 0; i < 10; i++)
  trace(obj['field' + i]);

В этом случае у вас в процессе вычисления на стек будет класться значение 'field' + i. Не выполняя выполнения кода (или какого-то сложного анализа) вы просто не узнаете все возможные строки.

Код:

действительно некоторые опкоды выполняют разные задачи при компиляции flex sdk и в flash ide?
Это вряд ли, для этого придется усложнять плеер. А вот то, что одна и та же AS3-конструкция компилируется по-разному flex и flash вполне возможно.

vizgl 28.06.2012 23:35

Цитата:

Сообщение от maxkar (Сообщение 1086497)
А кто их как строки то отметит? Если бы там было
Код:

trace(a==3 ? obj['a'] : obj['b']);
тогда да.

Упс, забыл добавить, что анализируются все опкоды, которые работают со строками:
IntStringIntIntOperation
StringOperation

Ну и multiname операции
GetProperty
SetProperty
CallProperty
CallPropVoid

Так, то все ваши примеры будут работать нормально. Обфускатор уже тестировался на 2 зарелизиных игрушках, просто собирались они под flex sdk. Вот решил обфусцировать свою первую игру на flash и вылезли такие косяки с динамическими свойствами.

wvxvw 28.06.2012 23:50

Я бы шел по такому пути: искал бы только пользовательские классы, не динамические, и переименовывал их свойства тогда когда из кода понятно, что обращаются именно к экземпляру этого класса. То, что обращаются именно к экземпляру нужного класса всегда можно понять в самом месте вызова, так что даже далеко ходить не нужно. Остальное не трогал бы. Самое худшее, что в таком случае может произойти - пользовательский ввод интерпретируется как имя свойства - но от этого вы никак не застрахуетесь, так что прийдется смирится, т.как если какой-нибудь паблик-морозов в коде есть, то таким образом можно даже к приватным свойствам обратиться.

vizgl 28.06.2012 23:58

Цитата:

Сообщение от wvxvw (Сообщение 1086505)
Я бы шел по такому пути: искал бы только пользовательские классы, не динамические

Любой "пользовательский" класс может иметь динамические свойства.

Update: с ключевым словом dynamic

dimarik 29.06.2012 00:17

Цитата:

Сообщение от vizgl (Сообщение 1086477)
Написал свой обфускатор as3 кода.

Советую ознакомиться с понятием AST. Все встанет на свои места.

Добавлено через 1 минуту
Цитата:

Сообщение от vizgl (Сообщение 1086507)
Любой "пользовательский" класс может иметь динамические свойства.

Минус тут вам в карму.

maxkar 29.06.2012 00:23

Код:

Упс, забыл добавить, что анализируются все опкоды, которые работают со строками:
Хм... Ваш обфускатор вычислит, что поля "field1", "field2", ... "field10" нигде менять нельзя? Это при том, что ни строки "field2"-"field10", ни даже числа 2-10 в операциях не участвуют? Мне действительно интересно, как вы вычисляете множество допустимых строк. Вас же не только "входные" аргументы опкодов интересуют, но и результат выполнения опкодов. Ну и
Код AS3:

trace(myMessages[loader.data])

никто не отменял.

Собственно, вопрос не в том, что обфускатор не будет работать (а всегда можно придумать ситуацию, когда он не будет работать), а какие именно ограничения он накладывает на код. Плюс я интересуюсь анализом программ (в более общем смысле), так что вдруг здесь будут какие-то интересные идеи :)

Цитата:

Обфускатор уже тестировался на 2 зарелизиных игрушках,
В это охотно верю. Вполне возможно, что на вашем коде (даже большом) обфускатор работает, так как мои примеры сильно специфические.

wvxvw
Цитата:

То, что обращаются именно к экземпляру нужного класса всегда можно понять в самом месте вызова, так что даже далеко ходить не нужно.
Нет, нельзя.
Код AS3:

public class Test {
  public var someValue : int = 15;
}
 
public static function cheat(arg : Object) {
  arg['someValue'] = 10;
}

Вопрос: к экземпляру какого класса идет обращение? Можно ли переименовать someValue?

Все зависит от вызывающего кода. Если в cheat может попасть Test, значит, у него someValue переименовывать нельзя. Если не может - значит, переименовывать можно. Если запрещать у класса и наследников, то это будет почти эквивалентно тому, что у ТС (любой динамический доступ к строкам), любой честный map (который через object реализуется) будет автоматически портить вообще все классы (так как они являются его наследниками). Если делать точно, то нужно делать глобальный анализ (хотя в большинстве мест анализ каждого аргумента будет затрагивать небольшое количество методов/классов). Фактически, это будет другая типизация программы (более точная, чем в AS-коде).

dimarik 29.06.2012 00:35

Цитата:

Сообщение от maxkar (Сообщение 1086518)
Хм... Ваш обфускатор вычислит, что поля "field1", "field2", ... "field10" нигде менять нельзя? Это при том, что ни строки "field2"-"field10", ни даже числа 2-10 в операциях не участвуют? Мне действительно интересно, как вы вычисляете множество допустимых строк. Вас же не только "входные" аргументы опкодов интересуют, но и результат выполнения опкодов.

Я сильно намекаю, что байткод относится к контекстно-зависимым грамматикам, хотя бы поэтому следует устраивать ему семантический анализ, с построением дерева AST. Иначе — это поделка из журнала "Юный техник".

vizgl 29.06.2012 00:44

Цитата:

Сообщение от maxkar (Сообщение 1086518)
Нет, нельзя.
Код AS3:

public class Test {
  public var someValue : int = 15;
}
 
public static function cheat(arg : Object) {
  arg['someValue'] = 10;
}

Вопрос: к экземпляру какого класса идет обращение? Можно ли переименовать someValue?

Все зависит от вызывающего кода. Если в cheat может попасть Test, значит, у него someValue переименовывать нельзя. Если не может - значит, переименовывать можно.

Программа просмотрит все методы всех классов и составит список строк, которые где-либо встречаются. В таблице констант, все строки хранятся в единственном экземпляре в целях оптимизации. Так вот поле someValue и строка 'someValue' будут завязаны на одну ячейку в таблице строк. В таком случае, такая строка не будет переименована.

Цитата:

Сообщение от maxkar (Сообщение 1086518)
Хм... Ваш обфускатор вычислит, что поля "field1", "field2", ... "field10" нигде менять нельзя? Это при том, что ни строки "field2"-"field10", ни даже числа 2-10 в операциях не участвуют? Мне действительно интересно, как вы вычисляете множество допустимых строк. Вас же не только "входные" аргументы опкодов интересуют, но и результат выполнения опкодов.

А кто Вам сказал, что в таблице строк хранятся "field1", "field2", ... "field10"? Там хранится только 'field'. Программа найдет эту строку, и пропустит её, а точнее занесет в список игнорируемых. Теперь если встретится метод или поле field, то они тоже останутся неизменными.

Цитата:

Сообщение от maxkar (Сообщение 1086518)
Ну и
Код AS3:

trace(myMessages[loader.data])

никто не отменял.

Это я не понял, тут все нормально. В дополнение ко всему у меня есть список ключевых слов, которые нельзя переименовывать. data туда тоже входит. Список состоит из 1777 слов, где взял уже не помню.


Цитата:

Сообщение от dimarik (Сообщение 1086525)
Я сильно намекаю, что байткод относится к контекстно-зависимым грамматикам, хотя бы поэтому следует устраивать ему семантический анализ, с построением дерева AST. Иначе — это поделка из журнала "Юный техник".

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

dimarik 29.06.2012 00:50

Цитата:

Сообщение от vizgl (Сообщение 1086527)
Вы наверно не уловили суть. Причем тут семантический анализ, я же не изменяю байт код, я всего лишь изменяю таблицу строковых констант.

Это Вы, вероятно, не уловили суть. Напомните мне, к чему относится таблица строковых констант, если не к байткоду. И, кстати, ее модификацией обфускация в широком смысле не ограничивается.

PS "Причем" пишется раздельно в данном контексте в русском, КЗ-зависимом.

vizgl 29.06.2012 00:56

dimarik
Я не пойму, что вы хотите доказать своими наездами? Что вы тут царь и бог?
Я понимаю, что людей у которых мало сообщений на форуме, считают глупыми, но нужно знать меру!

maxkar 29.06.2012 01:00

У вас с someValue все понятно было изначально. Это было для wvxvw по поводу "локальности проверки".

Цитата:

Теперь если встретится метод или поле field, то они тоже останутся неизменными.
О, супер. Продолжаем этот пример. Цикл остался. Еще где-то в коде есть
Код AS3:

public class WithFields {
  public var field1 : int = 1;
  public var field2 : int = 2;
  ....
  public var field10 : int = 10;
}
 
//Где-то в совсем другом месте
for (var i : int = 0; i < 10; i++)
  trace(obj['field' + i]);

Вот по вашему подходу field1-field10 могут быть переименованы (их имена не встречаются, вы запрещаете только field). Но на самом деле как раз к ним может идти обращение в том цикле.

С loader.data нужно смотреть на myMessages а не на loader. Какие поля в нем вы запрещаете переименовывать и почему? По-хорошему в myMessages вообще ничего нельзя переименовывать без дополнительной информации - мало ли что сервер пришлет и к чему будет доступ.

dimarik
Цитата:

Я сильно намекаю, что байткод относится к контекстно-зависимым грамматикам, хотя бы поэтому следует устраивать ему семантический анализ, с построением дерева AST.
А зачем AST-то? Любой более-менее интересный анализ работает не с AST а с соответствующими графами. Data flow, control flow и т.п. Да, они строятся по AST. Но нужные графы можно строить и без AST. Для анализа байт-кода AST в чистом виде не нужен, в процессе чтения можно сразу слинковать и подставить в нужные места константы из пула, а не ссылки на пул. Уже такая подстановка испортит "АСТ" и будет строить модель данных. Для типичных языков программирования построение моделей из AST действительно удобно (плюс там решается еще ряд задач вроде восстановления после ошибок, которые в байткоде решать не нужно), а вот для парсинга байткода я необходимости в нем не вижу. А вот идею необходимости семантического анализа программы полностью поддерживаю.

dimarik 29.06.2012 01:00

Со мной проще согласиться, чем вступать в дискуссию, не имея багажа знаний. Вы сами начали. Так к чему относится таблица строковых констант? Вы утверждаете, что не модифицируете байткод. Продолжаем разговор.

vizgl 29.06.2012 01:13

Цитата:

Сообщение от maxkar (Сообщение 1086533)
У вас с someValue все понятно было изначально. Это было для wvxvw по поводу "локальности проверки".


О, супер. Продолжаем этот пример. Цикл остался. Еще где-то в коде есть
Код AS3:

public class WithFields {
  public var field1 : int = 1;
  public var field2 : int = 2;
  ....
  public var field10 : int = 10;
}
 
//Где-то в совсем другом месте
for (var i : int = 0; i < 10; i++)
  trace(obj['field' + i]);

Вот по вашему подходу field1-field10 могут быть переименованы (их имена не встречаются, вы запрещаете только field). Но на самом деле как раз к ним может идти обращение в том цикле.

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

dimarik 29.06.2012 01:25

О! Уже начали понимать разницу между compile time и run time. Продолжайте.


Часовой пояс GMT +4, время: 17:30.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.