研究罐子差异

时间:2018-05-17 09:53:06

标签: java decompiling

我目前正在尝试从标签重建旧应用程序,不幸的是我得到包含“非二进制等于”.class文件的jar文件。

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

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

THX

PS。

  • 两者都使用相同的主要版本(Major: 52
  • 进行编译
  • 如果我使用javap -c命令比较“旧”和“新”的输出我没有差异
  • 如果我使用javap -v命令比较输出,我发现有几行移位(例如:旧的#480在同一指令的新变为#478)和一些缺失的错误声明(例如:{{1}只在旧)

2 个答案:

答案 0 :(得分:0)

这取决于你所说的“等于”。

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

你似乎意味着别的东西。但问题在于:“。class”文件中存在足够的可变性,因此准确比较可能很困难:

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

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

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

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

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

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

我建议采用两种方法:

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

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

答案 1 :(得分:0)

我终于找到了一种从我的观点来看可以接受的方法

  1. 比较"生成"和#34;老"使用zipcmp
  2. 的等效jar文件
  3. 如果在" .class"中找到差异文件,差异"生成"的反编译和#34;老" .class并打印此差异
  4. 如果没有找到反编译差异,请考虑.class是等效的
  5. 我写了这个脚本来帮助完成工作

    #!/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 $4;}' | 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