Как удалить метод из скомпилированного файла класса/jar Java?

У меня есть файл JAR и есть статический класс, я не могу его декомпилировать, он портится. В нем есть один метод, который возвращает несуществующий класс. Не знаю как, но я получаю NoClassDefFoundError. Хотя я не использую этот метод, он все равно падает. Поэтому мне нужно как-то просто удалить его, и он должен работать нормально. Я знаю, что можно использовать Reflection или Javassist, но не знаю, как.

Обратите внимание, что это явно не для производственной версии, а просто какой-то хакерский взлом.


person Gintas_    schedule 19.09.2016    source источник
comment
Связано ли это с stackoverflow.com/questions/39579166/ да, вы могли бы продолжить обсуждение там.. :-)   -  person Ankit Tripathi    schedule 19.09.2016


Ответы (2)


Я думаю, вы ошибаетесь: если этот метод никогда не будет вызываться, то JVM скорее всего, не попытается загрузить этот класс.

Понимаешь, весь смысл загрузки класса - он бывает ленивым; когда вы загружаете класс X, а X нуждается в Y, Z... тогда Y и Z загружаются только тогда, когда выполняется некоторый код, требующий загрузки Y, Z.

Другими словами: эта ошибка NoClassDefFound на самом деле говорит вам, что что-то (возможно, статическая инициализация где-то в вашем JAR) вызывает этот метод.

Таким образом, решение состоит не в том, чтобы «вырезать» этот метод (это просто приведет к другому исключению, например, MethodNotFound!). Вместо этого вы должны попытаться создать класс dummy, чтобы вообще не столкнуться с этим исключением. Или: в вашем JAR отсутствует по крайней мере одна из его зависимостей. Вы можете попытаться разрешить эту зависимость — возможно, вы сможете найти этот класс где-нибудь или «создать» свою собственную версию (вторая идея может быть сложной для реализации). получить правильно).

person GhostCat    schedule 19.09.2016
comment
Хм, не знал об этом... Создание моей собственной версии сработало, но мне пришлось использовать параметр JVM -noverify. Черт возьми, это был мошеннический беспорядок, но спасибо, братан - person Gintas_; 19.09.2016
comment
Не стесняйтесь выражать свою благодарность, принимая то. И/или проголосовать за этот другой ответ main. Я почти исчерпал дневной лимит; и мне нравится бить эту стену ;-) - person GhostCat; 19.09.2016
comment
«никогда» — это слишком сильно, учитывая, что вы не указали конкретную JVM. В спецификации существует большая свобода в отношении времени, когда JVM пытается разрешить класс. Ленивая загрузка классов не предусмотрена спецификацией, ее часто путают с ленивой инициализацией, которая гарантирована. Для Oracle/OpenJDK верно то, что он не пытается разрешить тип возвращаемого значения метода, который никогда не вызывается, но наличие (условного) пути кода, который может вызвать его, уже может вызвать загрузка класса во время проверки. - person Holger; 20.09.2016
comment
@Holger Спасибо за ваш вклад. Соответственно я изменил формулировку. - person GhostCat; 20.09.2016
comment
Я бы изменил «вызывает этот метод» на «потенциально вызывает этот метод», тогда он включает сценарий загрузки с помощью верификатора, не вдаваясь в подробности. - person Holger; 20.09.2016

GhostCat уже объяснил, почему ваша проблема не в удалении метода. Но я решил, что должен ответить на исходный вопрос, если кому-то еще интересно.

Лучший способ удалить метод из файла класса — разобрать его с помощью Krakatau, удалить нужный метод из файл .j и соберите его заново. Этот метод позволяет редактировать любой classfile, как бы странно это ни было. (Если вы обнаружите допустимые файлы классов, которые не может обработать дизассемблер Krakatau, отправьте сообщение об ошибке).

При дизассемблировании вы также можете передать параметр -roundtrip. Это не требуется для корректности, но предотвращает переупорядочивание пула констант, уменьшая двоичный diff результирующего classfile. С другой стороны, -roundtrip также значительно усложняет поиск нужного метода в файле .j.

person Antimony    schedule 20.09.2016