Обфускация и ее преодоление

         

листинг "вычищенный" в ручную


Основную проблему создают циклы. Трассер разворачивает их в длинный многокилометровый многократно повторяющий код. Запаришься его пролистывать! Так что без фильтра, распознающего и "сворачивающего" повторяющие конструкции нам не обойтись.

Хорошая идея — пропустить протокол трассера через оптимизирующий компилятор, использующий системы графов для устранения лишних операций присвоения (внимание! пропускать именно протокол трассера, а не дизассемблерный листинг, поскольку последний неверен, неполон и вообще никуда неканает!). Математических преобразований в стиле sin(x)2+cos(x)2 он, конечно же, распознать не сможет, но выбросит значительную часть "инструкций с нулевым эффектом", а нам не придется реализовывать систему графов и писать то, что было написано задолго до нас. К тому же, превзойти создателей оптимизирующих компиляторов нам все равно не удастся, правда, здесь есть одно "но". Компиляторы с большой осторожностью оптимизируют обращения к памяти, поэтому "ложные" расшифровщики типа листинга 7 компилятором оптимизированы не будут, не смотря на их очевидную "нулевую эффективность". Эту часть работы мы будем должны выполнить самостоятельно или же… просто смириться с тем, что из листинга вычищен не весь мусор. (Но ведь нам и не нужен "идеальный" листинг, правда? Будем есть, что даеют).

За основу лучше всего взять компилятор gcc, поскольку его исходные тексты открыты. Разумеется, просто взять и "оптимизировать" протокол трассера не получится, ведь он "написан" на языке ассемблера! У нас есть два пути: написать сравнительно простой транслятор, превращающий дизассемблерный протокол трассера в программу на Си (и тогда ее будет можно оптимизировать любым компилятором, а не только gcc), но лучше оттранслировать протокол трассера в промежуточный язык gcc (описанный в документации), пропустив его через "гнутый" оптимизатор. В этом случае мы получаем возможность сообщить оптимизатору некоторую дополнительную информацию о структуре программы, выловленную нашим трассером. Эффективность "чистки" кода от этого только повыситься. Короче говоря, наш трассер (и программы-фильтры) будут работать с оптимизатором в связке.

А там уже и до метадо-декомпилятора недалеко, тем более что работы в этом направлении ведутся не только в хакерских, но и "академических" кругах. Так что анализ "запутанного" кода — не такая уж сложная задача.

Кстати говоря, процедуры, обработанные обфускатором, резко отличаются от всех остальных и могут быть найдены простым статистическим анализом процентного содержания различных машинных команд. У "запутанных" процедур оно будет уж очень специфичным. К тому же, такие процедуры как правило до неприличия длинны. Логично, если код процедуры кем-то запутан, то это не просто так! Здесь явно прячется защитный механизм! Процедура проверки регистрационного номера или что-то типа того. Обфускация в этом случае только на пользу хакеру!



Содержание раздела