Прелести байткода или зачем нужен обфускатор

10 мар. 2011 г. | | |

Прекрасная идея портируемости приложений, кроссплатформенности родила языки, использующие виртуальные машины, компилирующие промежуточный платформенно-независимый код (байт-код) в платформенно-специфичный код. Яркие примеры таких языков - Java, C#, VB, ActionScript etc. История, которую я хочу рассказать, будет именно о последнем, но общие моменты касаются всех языков, компилирующихся в промежуточный код.

Учеба - такое дело.... Экзамены - не самая любимая часть учебы :) И преподаватель решил устроить тесты. А тесты были хитрые. У него была оболочка на Adobe AIR, а вопросы к тестам брались из шифрованного xml файла ( более 600 вопросов). Для сдачи экзамена выбиралось 30 вопросов, менялись местами варианты ответов, чтобы студенты не могли механически вычислить, где какой правильный ответ. Надо было что-то делать. Удалось раздобыть оболочку. Что ж, здорово. Оказалось, что эйр - это обычный zip-архив. Распаковав его, обнаружилась  file.swf, который вызвал дикое желание декомпильнуть его :) Гуглим Выбираем декомпилятор, открываем файл и ... как разработчика меня огорчило увиденное. Как злостного сообщника студентов-лодырей - порадовало. Чистый, ничем не тронутый ActionScript. Логика выбора вопросов из файла, перемешивания вариантов ответов, криптование и декриптование файла вопросов, подсчет реузльтатов...  Даже контрольный пример для криптора имелся в коде, что позволило написать тест для декриптора (декриптор на С#):

[Fact]
public static void DectriptString_Test(){
            var k1 = "x73bvs";
            var k2 = "ma";
            var k3 = "qrx9v";           
            var loc1 = new XorDecriptor(
                k1 + k1.Length.ToString() + "XQAWDbsd7%#jsd"
                + k2 + k2.Length.ToString() + "gyVsd34R$sd"
                + k3 + k3.Length.ToString() + "jhJLwNe@$gaSd"
                + (k1.Length * k2.Length + k3.Length + 23).ToString()
                );
            var loc2 = "4X%5D%06%19%1D%161%22arg%03S%07VUJ%1EE@%0C%0D%12%08%1Fv4%16VU%12PS%26%03%1B%0CX%1F%14%04";
            loc2 = loc1.xor_unescape(loc2);
            Assert.Equal("London is %#a capit6$al of Grea@t Britai!n", loc2);
        }

Обратите внимание, все строки, использующиеся при инициализации декриптора, хранились в коде в открытом виде. Для дешифровки файла с вопросами к тесту используется пароль из трех частей (k1, k2, k3). Правильность пароля проверяется приведенным выше тестом.
Вот такие пироги. Чем мог помочь обфускатор? Обфускация - процесс затруднения анализа исходного кода. Среди методик обфускации есть сокрытие строк, переименование методов, классов и тд - применил бы разработчик хоть что-то из этого и хоть как-то да усложнил и запутал злостных взломщиков. При правильном подходе можно было вобще сделать код нечитабельным. Нужно хоть как-то защищать свой труд.
Как-то при просмотре .net сборки в декомпиляторе попался не менее замечательный кусок кода:

static private string BuildConnectionString(string path)
        {
            return ("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + path + ";User Id=Admin;Jet OLEDB:Database Password=securepasswrd1023!");
        }

Не знаю, насколько трудно написать хотя бы так:

static private string BuildConnectionString(string path)
        {
            return ("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + path + ";User Id="+Encoding.Default.GetString( Convert.FromBase64String("QWRtaW4=") )+";Jet OLEDB:Database Password=
"+Encoding.Default.GetString( Convert.FromBase64String("c2VjdXJlcGFzc3dyZDEwMjMh")));
        }

А еще можно строки, предварительно отконвертированные в Base64, в ресурсы запрятать. А еще... Вариантов много, главное, не хранить в открытом виде такую информацию. Но, к сожалению, и такое встречается.
Полезные ссылки:
Способы защиты Flash-приложений
Статья на хабре про обфускаторы для .net

0 коммент.:

Отправить комментарий