Страницы

Поиск по вопросам

суббота, 30 ноября 2019 г.

Обфускатор Java байт-кода, способный не просто менять имена на “a.a.b”, а именно делать байт-код недекомпилируемым

#java #android #reverse_engineering #обфускация


Хотелось бы чтобы код именно невозможно было декомпилировать, то есть декомпилятор
при проходе по методу давал экскепшн, а еще лучше терял из виду какой-то блок кода
и вроде бы выдавал нормальный результат, но нужного блока в нем не было. В то же время,
код естественно должен быть валидным, не вызывать VerifyError.

Я думаю, что такое возможно, ведь в Java гораздо меньше свободы, чем в ее байт-коде,
поэтому не любой байт-код можно записать в виде кода Java.

Например, что, если в байт-коде получится вот так:

switch (test) {
case aaaa:
  break;
  :foo  <---------
  goto :foo2; ---|------
case bbbb:       |     |
  goto :foo; ----|     |
  break;               |
case cccc:             |
  break;               |
  :foo2  <--------------
  hidden_code();
}


Или вообще так:

switch (test) {
case aaaa:
  break;
  :foo3  <---------------
  hidden_code();        |
case bbbb:              |
  goto :foo -----|      |
  break;         |      |
case cccc:       |      |
  break;         |      |
  :foo  <---------      |
  goto :foo2 --------|  |
}                    |  |
                     |  |
switch (test2) {     |  |
case aaaa:           |  |
  break;             |  |
case bbbb:           |  |
  break;             |  |
case cccc:           |  |
  break;             |  |
  :foo2  <------------  |
  goto :foo3 -----------|
}


Ведь в Java нет goto, он есть только в опкодах JVM или DEX, и как такой байт-код
можно декомпилировать?

Важная деталь: if != switch в байт-коде Java.

Некоторые декомпиляторы просто не станут смотреть дальше break, все равно непонятно
куда девать этот блок.

А уж try-catch вообще прикольная штука.

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

Так вот есть ли обфускатор, который автоматически вставляет в любой байт-код такие
конструкции, чтобы он не декомпилировался?
    


Ответы

Ответ 1



SABLE описывает подобные подходы к обфускации в публикации о JBCO. Ссылка на публикацию (PDF, ~195KB). 6.7 Goto Instruction Augmentation (GIA) Java bytecode does have a goto instruction because it is necessary for simulating higher-level constructs such as loops. Therefore it is possible to insert an explicit goto within the bytecode. While it is very easily reversed using control flow graph analysis it can still cause many simple decompilers to fail. Также описывается ряд приемов, которые используют разницу между Java и байткодом в вызове конструкторов, switch и try/catch. В принципе, большинство обфускаторов Java производят байткод, который не полностью соответствует корректному коду. Даже при простом переименовании методов, возникают случаи когда метод переопределяется с разными возвращаемыми типами. Усиление безопасности от использования таких приемов имеет ограничения: Байткод остается в открытом виде. Даже если простой декомпилятор не справится с задачей, по инструкциям JVM можно отследить логику. Для большинства приложений достаточно рассмотреть ключевые классы/методы. Декомпиляторы (например, Dava от выше упомянутого SABLE) применяют анализ порядка выполнения и автоматизируют декомпиляцию. Стандартные классы не обфусцируются. При этом влияние модификаций байткода на производительность сложно оценить/предсказать. Подробный обзор подходов к защите Java-кода в статье Protect Your Java Code — Through Obfuscators And Beyond

Комментариев нет:

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