当前位置: 首页 > 工具软件 > JD-Core > 使用案例 >

java反编译工具jd-core

顾泰平
2023-12-01

java的反编译工具有那么几款,使用最广泛的当属jd-gui,速度快,功能强大。网上介绍反编译工具的文章也不少,但几乎没有介绍如何与程序对接的。

jd-gui的设计相当精妙,核心就是jd-core,但核心几乎没有人提到,开源的jd-gui也没有找到core的踪影。

我是这么获的jd-core的,在官网下载jd-gui-1.4.0.jar,删除其他只保留jd文件夹,里面就是core了。

反编译jd-core之后发现api使用也相当简单:

jd.core.Decompiler----反编译接口

jd.core.process.DecompilerImpl--反编译接口实现

 只有一个方法:

public void <strong>decompile</strong>(jd.core.preferences.Preferences preferences, jd.core.loader.Loader loader, jd.core.printer.Printer printer, java.lang.String internalClassPath) throws jd.core.loader.LoaderException;


Preferences 为配置,构造方法只有两个参数:
<h5><div style="padding-top: 2px; margin-left: 20px; position: relative; -ms-word-wrap: break-word;"><a target=_blank href="eclipse-open:%E2%98%82=boss/jd-core-1.4.0.jar%3Cjd.core.preferences(Preferences.class%E2%98%83Preferences~Preferences~Z~Z"></a><a target=_blank class="header" href="eclipse-javadoc:%E2%98%82=boss/jd-core-1.4.0.jar%3Cjd">jd</a>.<a target=_blank class="header" href="eclipse-javadoc:%E2%98%82=boss/jd-core-1.4.0.jar%3Cjd.core">core</a>.<a target=_blank class="header" href="eclipse-javadoc:%E2%98%82=boss/jd-core-1.4.0.jar%3Cjd.core.preferences">preferences</a>.<a target=_blank class="header" href="eclipse-javadoc:%E2%98%82=boss/jd-core-1.4.0.jar%3Cjd.core.preferences(Preferences.class%E2%98%83Preferences">Preferences</a>.Preferences(<span style="font-weight: normal;"></span>boolean showDefaultConstructor, <span style="font-weight: normal;"></span>boolean realignmentLineNumber) 参数含义不言自明</div></h5>

loader为加载文件(.class或.jar)的接口,自己实现也很简单

internalClassPath 参数是内部路径,这个会作为参数传给load接口

稍微复杂点的就是Printer了 (再次赞叹jd灵活的设计)

我这里实现一个简单的动态代理,仅为了减少一些方法实现而已,因为printer接口的方法比较多。

final StringBuilder javaFileBuilder = new StringBuilder();// 将反编译后源码输出到StringBuilder
		// jd.core.printer.Printer接口代理的简单实现
		InvocationHandler h = new java.lang.reflect.InvocationHandler() {
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				String name = method.getName();
				System.out.println("Printer:: " + name + "(" + Arrays.toString(args) + ")");
				if (name.equals("print")) {
					javaFileBuilder.append(args[0]);
				} else if (name.equals("endOfLine")) {
					javaFileBuilder.append("\n");
				} else if (name.equals("printKeyword")) {
					javaFileBuilder.append(args[0]);
				} else if (name.equals("printTypeImport")) {
					javaFileBuilder.append(args[1]);
				} else if (name.equals("printMethodDeclaration")) {
					javaFileBuilder.append(args[1]);
				} else if (name.equals("printStaticMethodDeclaration")) {
					javaFileBuilder.append(args[1]);
				} else if (name.equals("printType")) {
					javaFileBuilder.append(args[0].toString().replace('/', '.'));
				} else if (name.equals("printString")) {
					javaFileBuilder.append(args[0]);
				} else if (name.equals("printStaticMethod")) {
					javaFileBuilder.append(args[1]);
				} else if (name.equals("printMethod")) {
					javaFileBuilder.append(args[1]);
				} else if (name.equals("printField")) {
					javaFileBuilder.append(args[1]);
				} else if (name.equals("printConstructor")) {
					javaFileBuilder.append(args[0].toString().replace('/', '.'));
				} else if (name.equals("printNumeric")) {
					javaFileBuilder.append(args[0]);
				} else if (name.equals("printTypeDeclaration")) {
					javaFileBuilder.append(args[1]);
				}
				return null;
			}
		};
		Printer printer = (Printer) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { Printer.class },
				h);
loader接口的实现比较简单,就不贴了,读者自己解决吧,下面是最终的反编译的调用:

		DecompilerImpl de = new DecompilerImpl();
		de.decompile(preferences, loader, printer, internalClassPath);




 类似资料: