Java:奇怪的结果之后反编译
-
09-10-2019 - |
题
我有个奇怪的罐子文件,它包含一些类,当我使用JD反编译器,这显示一段是这样的:
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;
}
我只是想知道为什么a/一个编译器/混淆可以产品类字节的代码这样的,我的意思是该方法的签名。没有任何一个知道一个混淆可以这样做?
解决方案
作为 @joachim sauer正确指出: :与JAVA程序上的JLS相比,JVM规范对在字节码中的过载的约束更少。
来自 JVM规范(第4.6节,方法):
一个类文件中没有两种方法具有相同的名称 和描述符 (§4.3.3).
和方法描述符包括返回类型:((4.3.3方法描述符)
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程序。 前卫 这样做吗?这是他们手册中的片段:
-overloadaggressively
指定在混淆时施加积极的超载。然后,多个字段和方法可以获取相同的名称, 只要他们的论点和回报类型不同(不仅仅是他们的论点).
还有其他类似的技术使用 jsr
字节码指令或使用Java语言保留单词的变量标识符。 这里 是列出一些技术的网页。
要回答明显的后续问题:JVM如何知道在呼叫站点上打电话的方法?
Invoke-Instructions要求您指定要调用的完整方法签名(包括方法的返回类型)的引用。
其他提示
Java码支持结构,不是有效的Java源代码。Obfuscators利用这一事实通过修改码使用这些结构(同时仍给予同样的结果作为联合国的模糊字节).
...混淆器会产生这样的方法/签名,因为这是它的工作。任何混淆器都应为此目的工作。
该类是在没有调试信息的情况下进行编译的(至少缺少局部变量信息)并稍后混淆。
一种基本的混淆策略是(几乎)用新的,毫无意义的名称替换(几乎)所有软件包,类和方法名称,以便无法理解分解的代码。
其他策略是混淆字符串,并添加无法将其分配到Java代码的字节码结构。
您仍然能够为混淆的类文件创建Java源等效物,但只需付出巨大的努力。