2010-12-14 91 views
2

后,我有一种奇怪的jar文件,它包含了一些类,当我使用JD反编译,它表现出这样的一段:的Java:奇怪的结果反编译

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; 
} 

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

+0

您已经显示了5种方法 - 哪种方法签名会打扰您? – 2010-12-14 08:25:44

+2

你是否问过重载类型(最后三个)? – 2010-12-14 08:26:23

+0

我的意思是最后三个'return'类型不包含在方法签名中,所以这些方法都是重复的,对吗? – secmask 2010-12-14 08:30:50

回答

6

As @Joachim Sauer correctly points out:与JLS在Java程序中相比,JVM规范对字节码中方法重载的限制较少。

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知道在调用点调用哪个方法?

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

1

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

6

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

+0

你能命名为java-obfuscator软件吗? – secmask 2010-12-14 08:36:16

+0

@secmask,ProGuard会这样做。看到我的答案。 – aioobe 2010-12-14 08:47:08

1

该类已编译时没有调试信息(至少缺少局部变量信息)并在稍后进行混淆。

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

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

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