调查 jar 差异

Investigate jar differences

我目前正在尝试从标签重建旧应用程序,不幸的是我得到包含 "non binary equals" .class 文件的 jar 文件。

我试图比较这些 .class 文件的反编译版本,它们似乎是相等的,但是有没有一种安全和自动化的方法来诊断这种 .class 相等?

知道我生成的 jar 是否与旧的相同对我来说很重要,即使里面的 .class 文件不是二进制相等,而是功能上相等(当然是由于不同的 javac 版本) .

感谢

PS。

这取决于你"equals"的意思。

如果你的意思是字节相等,那么只需使用 cmp 实用程序。

你似乎另有所指。但这就是问题所在:“.class”文件中存在足够的可变性,因此可能难以进行准确比较:

  • .class 文件的内容取决于所使用的编译器;例如Oracle 编译器、Eclipse 编译器和 Jikes 等其他编译器很可能会发出不同的字节码。

  • 内容取决于编译器选项;例如-source 和 -target、-g 设置等。

  • .class 文件的内容可能取决于准确的编译器主要/次要/补丁版本号。并搭建平台。

  • 添加/删除源代码空行或注释等细微更改可能会改变源代码行号,从而导致不同的 .class 文件

  • 一些 Java 编译器将编译器版本 and/or 时间戳存储为 .class 文件中的非标准属性。

  • 库中的差异可能会导致针对它们编译的代码存在差异。


我建议两种方法:

  • 比较javap输出,忽略不影响常量池中的代码、签名和常量的东西

  • 确定用于编译预先存在的 JAR 的编译器、版本和选项,并在重新编译时使用完全相同的。

我终于找到了一个在我看来可以接受的方法

  1. 使用 zipcmp
  2. 比较 "generated" 和 "old" 等效的 jar 文件
  3. 如果在“.class”文件中发现差异,比较 "generated" 和 "old" 的反编译。class 并打印此差异
  4. 如果没有发现反编译差异,请考虑 .class 是等效的

我写了这个脚本来帮助完成工作

#!/bin/bash

GENERATED="<changeme>/application_5.2.0_generated"
OLD="<changeme>/application_5.2.0_old"
#DECOMPILER="javap -c"
DECOMPILER="java -jar <changeme>/procyon-decompiler-0.5.30.jar"

for plugin in $GENERATED/plugins/*; do
    echo "$plugin"
    base=$(basename "$plugin")
    old_plugin="$OLD/plugins/$base"

    zipcmp $plugin $old_plugin

    if [ $? -ne 0 ]; then
        mkdir -p "$GENERATED/unzip/$base" && cd "$GENERATED/unzip/$base" && jar xf $plugin
        mkdir -p "$OLD/unzip/$base" && cd "$OLD/unzip/$base" && jar xf $old_plugin

        for class in $(zipcmp $plugin $old_plugin | grep ".class" | awk '{print ;}' | uniq); do
            diff <($DECOMPILER "$GENERATED/unzip/$base/$class") <($DECOMPILER "$OLD/unzip/$base/$class") > /tmp/output
            if [ $? -ne 0 ]; then
                echo "diff <($DECOMPILER $GENERATED/unzip/$base/$class) <($DECOMPILER $OLD/unzip/$base/$class)"
                cat /tmp/output
            fi
        done
    fi
done