如何在不反编译的情况下更改已编译的 .class 文件?
Posted
技术标签:
【中文标题】如何在不反编译的情况下更改已编译的 .class 文件?【英文标题】:How to change already compiled .class file without decompile? 【发布时间】:2012-12-13 16:38:46 【问题描述】:我想更改 .class 文件的方法。我安装了 JD Eclipse Decompiler 并打开了 .class 文件。我添加了一些代码并保存 .class 文件。但是,.class 文件没有改变。
我不知道如何使用反编译器。如果可能的话,如何在不使用反编译器的情况下更改 .class 文件。
我正在使用 Ubuntu。
问候
编辑:
这是我的反编译代码:
/* */ package org.hibernate.id;
/* */
/* */ import java.io.Serializable;
/* */ import java.sql.ResultSet;
/* */ import java.sql.SQLException;
/* */ import java.util.HashMap;
/* */ import java.util.Properties;
/* */ import org.apache.commons.logging.Log;
/* */ import org.apache.commons.logging.LogFactory;
/* */ import org.hibernate.HibernateException;
/* */ import org.hibernate.MappingException;
/* */ import org.hibernate.dialect.Dialect;
/* */ import org.hibernate.type.Type;
/* */ import org.hibernate.util.ReflectHelper;
/* */
/* */ public final class IdentifierGeneratorFactory
/* */
/* 25 */ private static final Log log = LogFactory.getLog(IdentifierGeneratorFactory.class);
/* */
/* 64 */ private static final HashMap GENERATORS = new HashMap();
/* */
/* 66 */ public static final Serializable SHORT_CIRCUIT_INDICATOR = new Serializable()
/* */ public String toString() return "SHORT_CIRCUIT_INDICATOR";
/* */
/* 66 */ ;
/* */
/* 70 */ public static final Serializable POST_INSERT_INDICATOR = new Serializable()
/* */ public String toString() return "POST_INSERT_INDICATOR";
/* */
/* 70 */ ;
/* */
/* */ public static Serializable getGeneratedIdentity(ResultSet rs, Type type)
/* */ throws SQLException, HibernateException, IdentifierGenerationException
/* */
/* 32 */ if (!(rs.next()))
/* 33 */ throw new HibernateException("The database returned no natively generated identity value");
/* */
/* 35 */ Serializable id = get(rs, type);
/* */
/* 37 */ if (log.isDebugEnabled()) log.debug("Natively generated identity: " + id);
/* 38 */ return id;
/* */
/* */
/* */ public static Serializable get(ResultSet rs, Type type)
/* */ throws SQLException, IdentifierGenerationException
/* */
/* 45 */ Class clazz = type.getReturnedClass();
/* 46 */ if (clazz == Long.class)
/* 47 */ return new Long(rs.getLong(1));
/* */
/* 49 */ if (clazz == Integer.class)
/* 50 */ return new Integer(rs.getInt(1));
/* */
/* 52 */ if (clazz == Short.class)
/* 53 */ return new Short(rs.getShort(1));
/* */
/* 55 */ if (clazz == String.class)
/* 56 */ return rs.getString(1);
/* */
if(clazz == java.math.BigDecimal.class)
return rs.getBigDecimal(1);
/* */
/* 59 */ throw new IdentifierGenerationException("this id generator generates long, integer, short or string78");
/* */
/* */
/* */ public static IdentifierGenerator create(String strategy, Type type, Properties params, Dialect dialect)
/* */ throws MappingException
/* */
/* */ try
/* */
/* 92 */ Class clazz = getIdentifierGeneratorClass(strategy, dialect);
/* 93 */ IdentifierGenerator idgen = (IdentifierGenerator)clazz.newInstance();
/* 94 */ if (idgen instanceof Configurable) ((Configurable)idgen).configure(type, params, dialect);
/* 95 */ return idgen;
/* */
/* */ catch (Exception e)
/* 98 */ throw new MappingException("could not instantiate id generator", e);
/* */
/* */
/* */
/* */ public static Class getIdentifierGeneratorClass(String strategy, Dialect dialect)
/* 103 */ Class clazz = (Class)GENERATORS.get(strategy);
/* 104 */ if ("native".equals(strategy)) clazz = dialect.getNativeIdentifierGeneratorClass();
/* */ try
/* 106 */ if (clazz == null) clazz = ReflectHelper.classForName(strategy);
/* */
/* */ catch (ClassNotFoundException e)
/* 109 */ throw new MappingException("could not interpret id generator strategy: " + strategy);
/* */
/* 111 */ return clazz;
/* */
/* */
/* */ public static Number createNumber(long value, Class clazz) throws IdentifierGenerationException
/* 115 */ if (clazz == Long.class)
/* 116 */ return new Long(value);
/* */
/* 118 */ if (clazz == Integer.class)
/* 119 */ return new Integer((int)value);
/* */
/* 121 */ if (clazz == Short.class)
/* 122 */ return new Short((short)(int)value);
/* */
/* */
/* 125 */ throw new IdentifierGenerationException("this id generator generates long, integer, short");
/* */
/* */
/* */ static
/* */
/* 75 */ GENERATORS.put("uuid", UUIDHexGenerator.class);
GENERATORS.put("hilo", TableHiLoGenerator.class);
GENERATORS.put("assigned", Assigned.class);
GENERATORS.put("identity", IdentityGenerator.class);
GENERATORS.put("select", SelectGenerator.class);
GENERATORS.put("sequence", SequenceGenerator.class);
GENERATORS.put("seqhilo", SequenceHiLoGenerator.class);
GENERATORS.put("increment", IncrementGenerator.class);
GENERATORS.put("foreign", ForeignGenerator.class);
GENERATORS.put("guid", GUIDGenerator.class);
GENERATORS.put("uuid.hex", UUIDHexGenerator.class);
GENERATORS.put("sequence-identity", SequenceIdentityGenerator.class);
【问题讨论】:
你为什么要这样做? 因为 idgenerator 类不支持 BigDecimal。我使用 Hibernate 和 PostgreSQL,我得到这个错误:这个 id 生成器生成 long、integer、short 或 string 使用反编译器比其他方法容易 100 倍。如果您发现使用反编译器的想法有点多,我会尝试另一种不涉及更改类的方法。 当然,我会很高兴的。 【参考方案1】:您可以按照以下步骤修改您的 java 类:
-
反编译.class文件,保存为.java
在 Eclipse 中使用该 java 文件创建一个项目,即原始 JAR
作为库,以及它的所有依赖项
更改 .java 并编译
获取修改后的 .class 文件并再次将其放入原始文件中
罐子。
【讨论】:
我无法保存 .java 文件。实际上,我无论如何也无法保存。我保存了 .class 文件,但是当我关闭并重新打开时,我的更改消失了。 下载要修改的文件的源代码(因为它是 Hibernate 的一部分)、更改并重新编译不是更好吗?您可以使用我的方法重新编译或尝试重新编译整个 Hibernate(尽管这可能更难)。 那么,你有它。只需将其保存为 Java 文件,在论坛中添加修改,然后按照我的建议进行操作即可。 我无法保存。当我关闭 .class 文件时,更改消失了。因为我无法重新编译。 您忘记了另一个选项。拆卸、修改和重新组装。它适用于任何类文件,但它需要您理解字节码,我非常怀疑 OP 是否这样做。【参考方案2】:使用字节码编辑器,例如:
http://set.ee/jbe/
要小心,因为您需要非常了解 Java 字节码。
您还可以在运行时使用字节码编织(如 AspectJ)更改类。
【讨论】:
感谢回复,但我对 java 字节码一无所知。 我不认为你可以在运行时用反射改变任何类。你需要一个库来动态创建类来做类似的事情。 有时更改 java 字节码比获得正确的依赖关系更容易......尤其是如果您只需要进行一些小的更改。 JBE 在我的情况下抛出了错误,但 Recaf 运行良好。【参考方案3】:我添加了一些代码并保存了 .class 文件。
您在 JD EClipse Decompiler 中看到的是 .class 文件中字节码的反编译表示。即使更改文本也不会影响字节码。
【讨论】:
这是我的问题。我改变了,但没有效果。 @BreedHansen,为什么不生成 String 而不是 BigDecimal?所以你的问题的答案是:这几乎是不可能的。或者您必须将源代码提取到 eclipse 并尝试使用您的修改生成另一个类文件。 感谢详细回复。我想做这个。真的不可能吗? forum.hibernate.org/viewtopic.php?t=964410【参考方案4】:当您反编译和更改代码时,您必须进入 Eclipse 项目的根文件夹并检查 bin 文件夹中的类,该文件夹与 src 处于同一级别。然后用 zip 工具打开你的原始 jar(7zip 很好)并将修改后的类放在 jar 内的同一个包中。
【讨论】:
【参考方案5】:使用 java 辅助 Java 库来操作应用程序的 Java 字节码(.class 文件)。
-> Spring , Hibernate , EJB 使用它来实现代理
->我们可以通过字节码操作来做一些程序分析
-> 我们可以使用 Javassist 实现方法返回值的透明缓存,方法是拦截所有方法调用并仅在第一次调用时委托给超级实现。
【讨论】:
【参考方案6】:您可以使用任何反编译器先对文件进行反编译。
我曾经遇到过一个类似的问题,我没有应用程序的源代码,不得不对文件进行非常小的更改。
以下是我所做的:
从 jar 中提取类文件
在反编译器中打开它(我使用的是 JD GUI,你可以从互联网上的许多资源中轻松获取它) 你可以从here下载它
您实际上可以使用 JD GUI 查看 jar 中的所有文件。
对我想要的文件进行了更改并复制了该文件中的所有代码 在eclipse中创建了一个新项目,只有这个类(与jar中的包结构相同),提供原始jar作为库和所有其他依赖项。 编译类,将 .class 文件从我工作区的 bin 文件夹注入回 jar 中 测试了我的零钱,喝了一杯咖啡来庆祝一下 :)【讨论】:
【参考方案7】:Recaf 是一个反编译器 GUI,允许您编辑和重新编译文件。 Here 是手册的相关部分:
编辑字节码的最简单方法是将其作为反编译源进行编辑。这不适用于高度复杂的案例和混淆,但对于大多数简单的编辑,您只需要这样做。只需打开类,以纯 Java 代码的形式进行更改,然后保存。
【讨论】:
非常有用且最新的答案!谢谢【参考方案8】:你可以在反编译时更改代码,但必须重新编译成class
文件,反编译器输出java
代码,这必须使用与原始jar
/相同的类路径重新编译class
文件
【讨论】:
谢谢,我明白了。但我不知道我是怎么做到的? 将反编译后的代码拉入eclipse,解析依赖,修复错误,用eclipse重新编译。将生成的类文件放入旧 jar 中。或者获取原始源代码。 我只能在 Eclipse 中访问 .class 文件的 .java 文件。所以,我不明白“class file into the old jar”是怎么回事?【参考方案9】:有时我们需要从数千个文件中编译一个文件来解决问题。在这种情况下,可以创建与类路径相同的文件夹结构,将文件反编译为 java 或从源代码复制 java 文件。进行必要的更改,将一个特定文件编译成所有依赖项/类就位的类,最后替换类文件。最后重启容器。一旦战争爆发,文件将不会被替换。
【讨论】:
【参考方案10】:据我所知,没有简单的方法可以做到这一点。最简单的方法是不实际将类文件转换为可执行文件,而是在类文件周围包装一个可执行启动器。也就是说,创建一个可执行文件(可能是一个基于操作系统的可执行脚本文件),它只是通过命令行调用 Java 类。
如果你真的想有一个程序来做这件事,你应该看看那里的一些自动安装程序。
这是我找到的一种方法:
[code]
import java.io.*;
import java.util.jar.*;
class OnlyExt implements FilenameFilter
String ext;
public OnlyExt(String ext)
this.ext="." + ext;
@Override
public boolean accept(File dir,String name)
return name.endsWith(ext);
public class ExeCreator
public static int buffer = 10240;
protected void create(File exefile, File[] listFiles)
try
byte b[] = new byte[buffer];
FileOutputStream fout = new FileOutputStream(exefile);
JarOutputStream out = new JarOutputStream(fout, new Manifest());
for (int i = 0; i < listFiles.length; i++)
if (listFiles[i] == null || !listFiles[i].exists()|| listFiles[i].isDirectory())
System.out.println("Adding " + listFiles[i].getName());
JarEntry addFiles = new JarEntry(listFiles[i].getName());
addFiles.setTime(listFiles[i].lastModified());
out.putNextEntry(addFiles);
FileInputStream fin = new FileInputStream(listFiles[i]);
while (true)
int len = fin.read(b, 0, b.length);
if (len <= 0)
break;
out.write(b, 0, len);
fin.close();
out.close();
fout.close();
System.out.println("Jar File is created successfully.");
catch (Exception ex)
public static void main(String[]args)
ExeCreator exe=new ExeCreator();
FilenameFilter ff = new OnlyExt("class");
File folder = new File("./examples");
File[] files = folder.listFiles(ff);
File file=new File("examples.exe");
exe.create(file, files);
[/code]`
【讨论】:
以上是关于如何在不反编译的情况下更改已编译的 .class 文件?的主要内容,如果未能解决你的问题,请参考以下文章
如何在不编译更改的文件的情况下运行`iex -S mix`?
Eclipse“Enhanced Class Decompiler”插件在调试时不反编译
在没有 Xcode 项目和其他应用程序的情况下,如何修改已编译 macOS 应用程序的样式?