Почему декомпилированные Java-программы не всегда могут быть скомпилированы напрямую, а какие части нет? - PullRequest
4 голосов
/ 03 августа 2011

Поэтому я пытаюсь внести небольшие допустимые правовые изменения в скомпилированную Java-программу.Я декомпилирую его, используя JD-GUI для Mac.По большей части декомпилированный код не содержит ошибок, но есть некоторые странные вещи, такие как необъявленные переменные, множественные идентичные объявления переменных и просто некоторые странные операторы, которые нельзя легко скомпилировать.Некоторые из странных утверждений в декомпилированном коде действительно озадачивают.У меня были проблемы с одним оператором switch, в частности:

    switch ($SWITCH_TABLE$PackageName$ClassName$InnerEnumName()[getPlatform().ordinal()])

Где PackageName.ClassName - это класс, в котором находится этот оператор, а InnerEnumName - это внутреннее перечисление в ClassName.Также обратите внимание, что getPlatform () - это метод в ClassName, который возвращает перечисление типа InnerEnumName

. Странная часть - когда я просто удалил этот класс проблемных операторов, скомпилировал его и вставил обратно в программу,это начало работать, но было несколько странных ошибок.Например, когда я изменил оператор switch на

    switch (getPlatform().ordinal())

, он начал попадать в случай 3 (третий случай и случай для значения 3), когда он должен достигнуть случая 4 (еще раз четвертый случай такжекак случай для значения 4)

Ответы [ 3 ]

2 голосов
/ 04 августа 2011

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

В случае $ names это имена, сгенерированные внутренне в процессе «фальсификации» внутренних классов (поскольку JVM фактически не поддерживает внутренние классы). Декомпилятор, очевидно, выполняет несовершенную работу по выяснению того, что представляют собой внутренние классы, и, соответственно, присваивая им имена и объекты, созданные компилятором, чтобы имитировать вещи. Кто-то, знакомый с форматом байт-кода, вероятно, мог бы разобраться довольно быстро, но, как и все остальное, это нетривиально.

(В данном конкретном случае создается впечатление, что компилятор по какой-то причине создал таблицу сопоставления из внутренних значений перечисления для некоторых других значений, а когда вы «обрезали» оператор, вы потеряли это сопоставление.)

[Я добавлю, что одна большая проблема, с которой сталкиваются декомпиляторы, заключается в том, что javac является такой движущейся целью. В частности, такие вещи, как реализации внутреннего класса, постоянно изменяются, поэтому то, что сработало одну неделю, может потерпеть неудачу на следующей, со следующей версией +.001 компилятора.]

1 голос
/ 27 сентября 2013

С риском воскрешения древнего вопроса - путем удаления косвенности массива по порядковому номеру, значение первоначального переключателя изменяется.

Я написал это здесь: http://www.benf.org/other/cfr/switch-on-enum.html

Значимый бит:

Первая функция enum -> integer, которая приходит на ум, - это .ordinal (). Однако есть несколько проблем с этим:

Класс enum, который мы включаем, не является фиксированным - мы не можем взять копию целевых ординалов для операторов case - кто-то может изменить определение enum! Кто-то может даже удалить поле, которое мы используем в качестве метки регистра.

Итак, нам нужна функция поиска, которая не зависит от порядкового номера фиксированного значения перечисления (то есть разрешает его во время выполнения) и может справиться с полем удаляемого перечисления.

Следовательно, массив, который вы удалили, - это карта времени выполнения между порядковыми числами в операторе enum и местоположением в вашем операторе switch.

Что действительно интересно здесь, так это то, что это означает, что Javac создает дополнительный внутренний класс для каждого перечисления - Fun!

1 голос
/ 04 августа 2011

JD-GUI (JD?), Похоже, имеет проблемы.Попробуйте найти лучший декомпилятор?Жаль, что древний джад - это было хорошо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...