调查 jar 差异
Investigate jar differences
我目前正在尝试从标签重建旧应用程序,不幸的是我得到包含 "non binary equals" .class 文件的 jar 文件。
我试图比较这些 .class 文件的反编译版本,它们似乎是相等的,但是有没有一种安全和自动化的方法来诊断这种 .class 相等?
知道我生成的 jar 是否与旧的相同对我来说很重要,即使里面的 .class 文件不是二进制相等,而是功能上相等(当然是由于不同的 javac 版本) .
感谢
PS。
- 两者都使用相同的主要版本编译 (
Major: 52
)
- 如果我使用
javap -c
命令比较 "old" 和 "new" 的输出,我没有区别
- 如果我使用
javap -v
命令比较输出,我发现有几行偏移(例如:对于同一指令,旧的 #480 变成新的 #478)和一些缺失的错误声明(例如:365 = Utf8 Lorg/eclipse/ui/PartInitException;
仅旧)
这取决于你"equals"的意思。
如果你的意思是字节相等,那么只需使用 cmp
实用程序。
你似乎另有所指。但这就是问题所在:“.class”文件中存在足够的可变性,因此可能难以进行准确比较:
.class 文件的内容取决于所使用的编译器;例如Oracle 编译器、Eclipse 编译器和 Jikes 等其他编译器很可能会发出不同的字节码。
内容取决于编译器选项;例如-source 和 -target、-g 设置等。
.class 文件的内容可能取决于准确的编译器主要/次要/补丁版本号。并搭建平台。
添加/删除源代码空行或注释等细微更改可能会改变源代码行号,从而导致不同的 .class 文件
一些 Java 编译器将编译器版本 and/or 时间戳存储为 .class 文件中的非标准属性。
库中的差异可能会导致针对它们编译的代码存在差异。
我建议两种方法:
比较javap
输出,忽略不影响常量池中的代码、签名和常量的东西
确定用于编译预先存在的 JAR 的编译器、版本和选项,并在重新编译时使用完全相同的。
我终于找到了一个在我看来可以接受的方法
- 使用
zipcmp
比较 "generated" 和 "old" 等效的 jar 文件
- 如果在“.class”文件中发现差异,比较 "generated" 和 "old" 的反编译。class 并打印此差异
- 如果没有发现反编译差异,请考虑 .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
我目前正在尝试从标签重建旧应用程序,不幸的是我得到包含 "non binary equals" .class 文件的 jar 文件。
我试图比较这些 .class 文件的反编译版本,它们似乎是相等的,但是有没有一种安全和自动化的方法来诊断这种 .class 相等?
知道我生成的 jar 是否与旧的相同对我来说很重要,即使里面的 .class 文件不是二进制相等,而是功能上相等(当然是由于不同的 javac 版本) .
感谢
PS。
- 两者都使用相同的主要版本编译 (
Major: 52
) - 如果我使用
javap -c
命令比较 "old" 和 "new" 的输出,我没有区别 - 如果我使用
javap -v
命令比较输出,我发现有几行偏移(例如:对于同一指令,旧的 #480 变成新的 #478)和一些缺失的错误声明(例如:365 = Utf8 Lorg/eclipse/ui/PartInitException;
仅旧)
这取决于你"equals"的意思。
如果你的意思是字节相等,那么只需使用 cmp
实用程序。
你似乎另有所指。但这就是问题所在:“.class”文件中存在足够的可变性,因此可能难以进行准确比较:
.class 文件的内容取决于所使用的编译器;例如Oracle 编译器、Eclipse 编译器和 Jikes 等其他编译器很可能会发出不同的字节码。
内容取决于编译器选项;例如-source 和 -target、-g 设置等。
.class 文件的内容可能取决于准确的编译器主要/次要/补丁版本号。并搭建平台。
添加/删除源代码空行或注释等细微更改可能会改变源代码行号,从而导致不同的 .class 文件
一些 Java 编译器将编译器版本 and/or 时间戳存储为 .class 文件中的非标准属性。
库中的差异可能会导致针对它们编译的代码存在差异。
我建议两种方法:
比较
javap
输出,忽略不影响常量池中的代码、签名和常量的东西确定用于编译预先存在的 JAR 的编译器、版本和选项,并在重新编译时使用完全相同的。
我终于找到了一个在我看来可以接受的方法
- 使用
zipcmp
比较 "generated" 和 "old" 等效的 jar 文件
- 如果在“.class”文件中发现差异,比较 "generated" 和 "old" 的反编译。class 并打印此差异
- 如果没有发现反编译差异,请考虑 .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