Java. Декомпиляция

UnisonUnison
3 min read

Пришлось мне заниматься декомпиляцией java программы. Декомпиляторов в java достаточно много, но надо было определиться с самым подходящим для меня. Надо отметить, что многие декомпиляторы очень медленно развиваются или вообще находятся в застойном положении.

Да, я долго выбирал подходящий мне декомпилятор и по итогу выбрал декомпилятор CFR. Данный декомпилятор максимально безошибочно декомпилирует многие java-программы, написанные в версиях 11 и выше. Несколько ошибок пришлось мне подкорректировать вручную, но это было не критично.

Но я тут не буду оценивать работу различных декомпиляторов. Цель у меня другая: указать параметр декомпилятора CFR который сэкономить другим время. Что означает параметр --aexagg в CFR? Запустим помощь:


java -jar cfr.jar --help --aexagg

выдает:

--aexagg - Try to extend and merge exceptions more aggressively

bytecodeviewer - поддерживает несколько декомпиляторов, выбрал CFR и декомпилировал клас используя try... with resource... (параметр --aexagg включен). Вот результат декомпиляции:

    @Cacheable(value={"templates"}, key="{#profile, #range, #template}", unless="#result == null")
    public Optional<Template> load(String profile, String range, String template) {
        Set<String> locations = this.calculateAllLocations(profile, range, template);
        Iterator<String> iterator = locations.iterator();
        while (iterator.hasNext()) {
            String location = iterator.next();
            Resource resource = this.resourceLoader.getResource(this.templatesPath + File.separator + location);
            if (!resource.exists()) continue;
            try (InputStream istream = resource.getInputStream();){
                String content = IOUtils.toString(istream, StandardCharsets.UTF_8);
                log.info("Got template {} with content length {}", (Object)location, (Object)content.length());
                log.trace("Template {} content: {}", (Object)location, (Object)content);
                Optional<Template> optional = Optional.of(new Template(location, content));
                return optional;
            }
            catch (IOException e) {
                log.error("Failed to load template {}:", (Object)location, (Object)e);
            }
        }
        return Optional.empty();
    }

Самый оптимальный код получается декомпиляция с обычным CFR с параметром --aexagg, запущенный с командной строки. Код декомпилировался без единого ошибка. Версия CFR 0.152. Вот результат декомпиляции:

    @Cacheable(value={"templates"}, key="{#profile, #range, #template}", unless="#result == null")
    public Optional<Template> load(String profile, String range, String template) {
        Set<String> locations = this.calculateAllLocations(profile, range, template);
        for (String location : locations) {
            Resource resource = this.resourceLoader.getResource(this.templatesPath + File.separator + location);
            if (!resource.exists()) continue;
            try (InputStream istream = resource.getInputStream();){
                String content = IOUtils.toString((InputStream)istream, (Charset)StandardCharsets.UTF_8);
                log.info("Got template {} with content length {}", (Object)location, (Object)content.length());
                log.trace("Template {} content: {}", (Object)location, (Object)content);
                Optional<Template> optional = Optional.of(new Template(location, content));
                return optional;
            }
            catch (IOException e) {
                log.error("Failed to load template {}:", (Object)location, (Object)e);
            }
        }
        return Optional.empty();
    }

обычный cfr без параметра --aexagg запущенный с командной строки декомпилировал так:

    /*
     * Enabled force condition propagation
     * Lifted jumps to return sites
     */
    @Cacheable(value={"templates"}, key="{#profile, #range, #template}", unless="#result == null")
    public Optional<Template> load(String profile, String range, String template) {
        Set<String> locations = this.calculateAllLocations(profile, range, template);
        for (String location : locations) {
            Optional<Template> optional;
            Resource resource = this.resourceLoader.getResource(this.templatesPath + File.separator + location);
            if (!resource.exists()) continue;
            InputStream istream = resource.getInputStream();
            try {
                String content = IOUtils.toString((InputStream)istream, (Charset)StandardCharsets.UTF_8);
                log.info("Got template {} with content length {}", (Object)location, (Object)content.length());
                log.trace("Template {} content: {}", (Object)location, (Object)content);
                optional = Optional.of(new Template(location, content));
                if (istream == null) return optional;
            } catch (Throwable throwable) {
                try {
                    if (istream == null) throw throwable;
                    try {
                        istream.close();
                        throw throwable;
                    } catch (Throwable throwable2) {
                        throwable.addSuppressed(throwable2);
                    }
                    throw throwable;
                } catch (IOException e) {
                    log.error("Failed to load template {}:", (Object)location, (Object)e);
                }
            }
            istream.close();
            return optional;
        }
        return Optional.empty();
    }

Думаю, по последнему результату комментарии излишны, так как клас не возможно компилировать, из-за ошибок декомпиляции.

0
Subscribe to my newsletter

Read articles from Unison directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Unison
Unison