使用javassist处理字节码混淆过的class文件

java程序员,有时候为了某种特定目的比如调试或者增强代码,不得不反编译一下代码,然后把内容修改成自己想要的,再从新打包回jar文件里面。
当然,很多时候为了防止这种事情发生,于是代码混淆工具诞生了。一般代码级别的混淆,反编译之后基本无法获得原有的逻辑,不过仍然可以直接修改代码然后再编译打包回去;比较厉害的情况是字节码直接混淆,这种情况有可能反编译出来比较奇特的代码,我最近就遇到这样的问题,反编译出来竟然是这样的结构(忽略了函数体):
private static String a(String[] as);
public static void a();
private static String a();
private static String a(String as);
private static void a(Date paramDate1, Date paramDate2);


这样的代码没法修改,因为根本不可能编译通过,所以只能在字节码级别做文章,尽量简单的解决混淆带来的麻烦。
好在javassist就可以处理这样的问题,除了动态增强之外,javassist也可以把增强过的类,从新写入到文件中。
import java.io.File;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.Modifier;
import javassist.expr.ExprEditor;
import javassist.expr.MethodCall;

public class Pathcer {
	static String tempDir = "c:\\output1";
	static String className = "com.company.fQ";

	public static void main(String[] args) throws Exception {
		ClassPool pool = ClassPool.getDefault();
		CtClass cc = pool.get(className);

		File f = new File(tempDir);
		if (!f.exists())
			f.mkdirs();

		CtMethod targetM = null;

		CtMethod[] methos = cc.getDeclaredMethods();
//找到private staitc void a();
		for (CtMethod m : methos) {
			if (!m.getName().equals("a"))
				continue;
			if (m.getReturnType().getName().equals("void"))
				continue;
			CtClass arg[] = m.getParameterTypes();
			if (arg != null && arg.length > 0) 
				continue;
			
			targetM = m;
			break;
		}

		if (targetM == null) {
			System.out.println("not found the target mehtod!exit now.");
			System.exit(1);
		}
//直接写java代码,可以动态编译进去;好消息是setBody函数里面可以写任何东西。
		targetM.setBody("{return \"This is my code.\";}");

//注意因为class已经加载过了,所以必须从新加载一次。
		ClassPool.getDefault().get(className).writeFile(f.getAbsolutePath());
	}

}




javassist可以增强任何东西,比如给一个类添加接口,添加父类,添加函数,删除函数,总之几乎无所不能。

你可能感兴趣的:(F#)