修改jar:ClassFormatError:未知的常量标记

时间:2017-03-06 23:53:20

标签: java jar jvm

我正在尝试修改现有的jar来更改用户凭据,因为我丢失了一些代码。

当我运行jar时,我得到一个sql异常,因为它由于凭据错误和服务器URL不正确而无法连接。

我尝试提取负责数据库连接的类文件,更改其中的字符串(它们是硬编码的字符串常量),然后将修改后的类文件放回jar中并执行它。

当我将密码更改为正确的密码(恰好与原始密码长度相同)时,我仍然会收到sql异常。但是,当我更改数据库URL时,通过将其替换为更大长度的字符串,我得到

Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:58)
Caused by: java.lang.ClassFormatError: Unknown constant tag 51 in class file

我不明白这里发生了什么。据我所知,类文件大小不存储在类文件中。此外,从搜索特定的异常,似乎其他人得到它已损坏类文件,这是一个很好的答案,但在我的情况下,我希望在更改密码时得到异常,它不应该依赖在字符串长度。

有谁知道为什么会这样? 另外,有没有办法可以有效地实现我在类文件中更改硬编码字符串并让jar运行正常的目标?

修改

public class TestEdit {
public static final String OUTPUT = "TEST";

public static void main(String[] args) {
    System.out.println(OUTPUT);
}

}

所以我在一个jar中编译了这个类,并打开了类文件,并改变了#34; TEST"到" newTest"。我把类文件放回到jar中并运行它,并获得异常。现在我再次编辑了类文件,并更改了#34; TEST"到"成长",把它放回去运行它。这次它奏效了。我认为如果我通过编辑它来破坏类文件,那么第二次更改也会抛出异常,但它不会。它似乎与字符串长度

有关

1 个答案:

答案 0 :(得分:3)

“Java®虚拟机规范”的相关部分是§4.4.7, The CONSTANT_Utf8_info Structure

  

CONSTANT_Utf8_info结构用于表示常量字符串值:

CONSTANT_Utf8_info {
  u1 tag;
  u2 length;
  u1 bytes[length];
}
     

CONSTANT_Utf8_info结构的项目如下:

     标签      

tag结构的CONSTANT_Utf8_info项的值为CONSTANT_Utf8(1)。

     长度      

length项的值给出bytes数组中的字节数(不是结果字符串的长度)。

     字节[]      

bytes数组包含字符串的字节。

因此,如果您在没有专用类文件解析器的情况下查看它并识别字符串内容,则在第一个字符之前的两个字节确定字符串的长度(解释为大端无符号短路)。

如果用相同长度的字符串覆盖字符串内容(假设全ASCII字符),它可以工作,但是如果你将它改为不同长度的字符串而不调整length信息,类文件解析器将尝试在旧位置查找下一个常量池项。在您第一次尝试将其更改为更长的字符串时,它会在原始字符串结束后的位置找到字节51,换句话说字符'3'

如果您正确调整长度,类文件中确实没有其他信息,具体取决于这些项目的长度/位置。