
Виртуальная машина Android и деобфускатор
Simplify виртуально исполняет приложение, чтобы понять его поведение, а затем пытается оптимизировать код так, чтобы он вел себя идентично, но был понятнее для человека. Каждый тип оптимизации прост и универсален, поэтому не имеет значения, какой именно тип обфускации используется.
Код слева — это декомпиляция обфусцированного приложения, а код справа — после деобфускации.
Проект состоит из трех частей: smalivm, simplify и демонстрационное приложение.
if или switch с неизвестным значением приводит к выполнению обеих ветвей.usage: java -jar simplify.jar <input> [options]
deobfuscates a dalvik executable
-et,--exclude-types <pattern> Exclude classes and methods which include REGEX, eg: "com/android", applied after include-types
-h,--help Display this message
-ie,--ignore-errors Ignore errors while executing and optimizing methods. This may lead to unexpected behavior.
--include-support Attempt to execute and optimize classes in Android support library packages, default: false
-it,--include-types <pattern> Limit execution to classes and methods which include REGEX, eg: ";->targetMethod\("
--max-address-visits <N> Give up executing a method after visiting the same address N times, limits loops, default: 10000
--max-call-depth <N> Do not call methods after reaching a call depth of N, limits recursion and long method chains, default: 50
--max-execution-time <N> Give up executing a method after N seconds, default: 300
--max-method-visits <N> Give up executing a method after executing N instructions in that method, default: 1000000
--max-passes <N> Do not run optimizers on a method more than N times, default: 100
-o,--output <file> Output simplified input to FILE
--output-api-level <LEVEL> Set output DEX API compatibility to LEVEL, default: 15
-q,--quiet Be quiet
--remove-weak Remove code even if there are weak side effects, default: true
-v,--verbose <LEVEL> Set verbosity to LEVEL, default: 0
Для сборки требуется установленный Java Development Kit 8 (JDK).
Поскольку проект содержит подмодули для Android-фреймворков, клонируйте с --recursive:
git clone --recursive https://github.com/CalebFenton/simplify.git
Или обновите подмодули в любое время с помощью:
git submodule update --init --recursive
Затем, чтобы собрать единый jar-файл, содержащий все зависимости:
./gradlew fatjar
Jar-файл Simplify будет находиться в simplify/build/libs/. Вы можете проверить его работу, упрощая предоставленное обфусцированное демонстрационное приложение. Вот как его запустить (возможно, потребуется изменить путь к simplify.jar):
java -jar simplify/build/libs/simplify.jar -it "org/cf/obfuscated" -et "MainActivity" simplify/obfuscated-app.apk
Чтобы понять, что именно деобфусцируется, ознакомьтесь с README обфусцированного приложения.
Если Simplify не работает, попробуйте следующие рекомендации по порядку:
-it.--max-address-visits, --max-call-depth и --max-method-visits.-v или -v 2 и сообщите о проблеме, приложив логи и хеш DEX или APK.Если сборка на Windows завершается ошибкой, похожей на:
Could not find tools.jar. Please check that C:\Program Files\Java\jre1.8.0_151 contains a valid JDK installation.
Это означает, что Gradle не может найти корректный путь к JDK. Убедитесь, что JDK установлен, задайте переменную окружения JAVA_HOME с путем к JDK и обязательно закройте и снова откройте командную строку, которую используете для сборки.
Не стесняйтесь. Я считаю, что виртуальное выполнение и деобфускация — увлекательные задачи. Любой, кто интересуется, автоматически крут, и вклад приветствуется, даже если это просто исправление опечатки. Не стесняйтесь задавать вопросы в issues и отправлять pull request'ы.
Пожалуйста, приложите ссылку на APK или DEX и полную используемую команду. Это значительно облегчает воспроизведение (и, следовательно, исправление) вашей проблемы.
Если вы не можете поделиться образцом, пожалуйста, укажите хеш файла (SHA1, SHA256 и т.д.).
Если операция помещает значение типа, которое может быть преобразовано в константу (например, строка, число или булево), эта оптимизация заменяет такую операцию на константу. Например:
const-string v0, "VGVsbCBtZSBvZiB5b3VyIGhvbWV3b3JsZCwgVXN1bC4="
invoke-static {v0}, Lmy/string/Decryptor;->decrypt(Ljava/lang/String;)Ljava/lang/String;
# Decrypts to: "Tell me of your homeworld, Usul."
move-result v0
В этом примере зашифрованная строка расшифровывается и помещается в v0. Поскольку строки "константизируемы", move-result v0 можно заменить на const-string:
const-string v0, "VGVsbCBtZSBvZiB5b3VyIGhvbWV3b3JsZCwgVXN1bC4="
invoke-static {v0}, Lmy/string/Decryptor;->decrypt(Ljava/lang/String;)Ljava/lang/String;
const-string v0, "Tell me of your homeworld, Usul."