我有个奇怪的罐子文件,它包含一些类,当我使用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源等效物,但只需付出巨大的努力。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top