我将一些[相对复杂的] Java代码编译成.class文件,然后使用jad将其反编译回Java。当然,代码被混淆了,这是可以预料的。但是,考虑到我拥有原始代码,我认为我可以很容易地浏览反编译的代码。但是,我注意到代码中的差异,例如定义了某些变量的位置(包括范围的差异)。
有什么主要原因吗?我想这只是代码反编译中发生的事情之一,但我对引起更改的因素(例如代码的复杂性,是否引用其他文件等)感到更加好奇。为我很好地解释了哪些因素导致代码前后的差异?
编辑
从技术上讲,.class文件是从jar中提取的。我提取了内容并在其中使用了.class文件。
就我使用的混淆器而言,我使用了具有以下选项的Retroguard混淆器(我目前只是在探索混淆并找出每件事对最终结果):
.option Application
.option Applet
.option Repackage
.option Annotations
.option MapClassString
.attribute LineNumberTable
.attribute EnclosingMethod
.attribute Deprecated

脚本的文档可以在其网站上找到。有点杂乱无章,但您应该能够在其中找到足够的解释。同样值得注意的是,我剥离了泛型和局部变量表。
我现在还设置了一种方法(受Minecraft Coder Pack的创建者启发),使用文件中的数据重命名源。 ,然后将其传递到包,类,方法和字段的列表的字典。
# snippet from the MCP version (mine's slightly different) (all in Python):
srg_types = {'PK:': ['obf_name', 'deobf_name'],
            'CL:': ['obf_name', 'deobf_name'],
            'FD:': ['obf_name', 'deobf_name'],
            'MD:': ['obf_name', 'obf_desc', 'deobf_name', 'deobf_desc']}
parsed_dict = {'PK': [],
               'CL': [],
               'FD': [],
               'MD': []}

然后从文件中解析一行,并将其传递到parsed_dict中,然后用于重命名所有内容(来来回回)。在编译之后而不是在第一次编译之后实现(我注意到了差异)。

评论

顺便问一下,您使用了哪种混淆器?听起来不像是一个很好的混淆器。而且,贾德(Jad)很老。我建议使用Procyon代替完整的代码。

@Antimony编辑了问题及其答案。附带说明一下,我现在不打算完全混淆所有内容。我把东西扔在墙上,看看有什么东西粘住(是的,非常混乱,但也很有趣)。

如果要反编译混淆的类,则应使用Krakatau。它是专门为处理混淆类而设计的,通常可以处理其他反编译器无法处理的东西。 github.com/Storyyeller/Krakatau

@锑甜。谢谢你的建议。我会调查的。

#1 楼

Java编译为在JVM中运行并存储在.class文件中的字节码。该字节码不是原始代码的1:1表示,而是包括一些编译器实现的优化。当执行这些优化时,信息会丢失,并且由于丢失信息,反编译器无法将代码重新构建回原来的状态。

#2 楼

除了Ditmar所说的,最大的问题可能是您的困惑。至少从C或C ++(甚至Scala)的角度来看,普通的Java字节码实际上令人惊讶地接近原始源。您总是会丢失一些信息,但是未混淆的Java可以反编译为接近原始信息的东西,特别是如果您使用调试信息进行编译。尝试操纵代码的结构。反编译混淆的代码时,如果发现完全相似,应该会感到惊讶。

评论


是的,根据发布者的编辑,这肯定是混淆引起的问题。好预测这一点。读者应注意,对于混淆/它们接近1:1的字节码,这些答案以非常相似的方式适用于.NET MSIL语言(如C#)。

– Ditmar Wendt
13年7月26日在21:01

@Ditmar Java比CIL更接近字节码,因为字节码仅设计用于一种语言。但是您说得很对,它们非常相似。

–锑
13年7月27日在1:57

#3 楼

您选择的反编译器会极大地影响结果。您应该尝试JODE或Fernflower(我相信是Androchef)。

在反编译之前,最好自己进行一些简单的去混淆处理。例如,您可以尝试


将已经用作类/方法/变量名称的Java关键字重新映射到合法Java标识符。使用ASM库提供的Remapping适配器(http://asm.ow2.org/asm40/javadoc/user/org/objectweb/asm/commons/RemappingClassAdapter.html
一些)可以很容易地完成此任务。块的简单重组。许多混淆器会将goto贴在Java源代码中“在单个表达式内”的尴尬位置,例如将某些东西推入堆栈,然后跳转,然后将其存储到目标位置的本地变量中,在字节码中是完全可行的,但是了解字节码只是在执行var = value可能会使一些反编译器很难。 />

评论


Fernflower并不是很好,而且我认为它甚至不再是公开可用的。同样,Krakatau将自动处理您提到的第二个模糊处理,以及许多其他模糊处理,但是如果代码没有被模糊处理,结果将不那么理想。

–锑
13年8月30日在5:34