Java:反编译后的奇怪结果

时间:2010-12-14 08:22:30

标签: java obfuscation decompiler

我有一个奇怪的jar文件,它包含一些类,当我使用JD Decompiler时,它会显示一个这样的段:

public final void a(ak aa) {
    this.jdField_a_of_type_Ak = aa;
}

public final void a(cn ccn) {
  this.jdField_a_of_type_Cn = ccn;
}

public final cN a() {
  return this.jdField_a_of_type_CN;
}

public final void a() {
  super.b();
}

public final boolean a() {
    return this.jdField_a_of_type_Boolean;
}

我只是想知道为什么编译器/混淆器可以产生类似的类字节代码,我的意思是方法签名。有没有人知道混淆器可以做到这一点吗?

4 个答案:

答案 0 :(得分:6)

Java字节码支持在Java源代码中无效的构造。混淆器通过修改字节码来使用这些结构来利用这一事实(同时仍然提供与未混淆的字节码相同的结果)。

答案 1 :(得分:6)

As @Joachim Sauer correctly points out:JVM规范对字节码中方法重载的约束比JLS对Java程序的约束要少。

来自JVM Specification (Section 4.6, Methods)

  

一个类文件中没有两个方法可能具有相同的名称和描述符(§4.3.3)。

方法描述符包括返回类型:(4.3.3 Method Descriptors

  

MethodDescriptor:
  ( ParameterDescriptor* ) ReturnDescriptor

你在问题​​中提到的方法都有不同的描述符,所以它们没问题:

public final void a(ak aa)     ->     (Lsomepkg1/ak;)V
public final void a(cn ccn)    ->     (Lsomepkg2/ccn;)V
public final cN a()            ->     ()Lsomepkg3/cN;
public final void a()          ->     ()V
public final boolean a()       ->     ()Z

混淆器巧妙地利用了这一点。有效的字节码程序不再具有“直接对应”的Java程序。 ProGuard就是这样做的。以下是手册中的摘录:

  

-overloadaggressively

  指定在混淆时应用积极的重载。然后,多个字段和方法可以获得相同的名称,只要它们的参数和返回类型不同(不仅仅是它们的参数)

还有其他类似的技术使用例如jsr字节码指令或使用Java语言中保留字的变量标识符。 Here是一个列出一些技巧的网页。


回答明显的后续问题:JVM如何知道在呼叫站点调用哪种方法?

invoke-instructions要求您指定对要调用的完整方法签名(包括方法的返回类型)的引用。

答案 2 :(得分:1)

......混淆器会生成这样的方法名称/签名,因为这是它的工作。任何混淆器都应该为此目的而工作。

答案 3 :(得分:1)

该类已编译时没有调试信息(至少缺少局部变量信息)并在以后进行模糊处理。

一个基本的混淆策略是用新的,无意义的名称替换(几乎)所有包,类和方法名,这样就无法理解反编译代码。

其他策略是混淆字符串并添加无法反编译为java代码的字节码构造。

您仍然可以为混淆的类文件创建等效的java源代码,但只需付出很大的努力。