1. 程式人生 > >Java逆向基礎之動態生成類

Java逆向基礎之動態生成類

Java動態生成類

為什麽有這個東西,一方面時AOP框架的需要,另一方面是增加軟件逆向的難度

動態生成類的技術目前大體上分為兩類,一類是通過操作字節碼框架如cglib/Javassist去實現,另一類就是JNI方式,調用dll/so庫,內存中動態還原。這兩種方式都能實現隱藏類

看一個Javassist動態生成類的例子

package com.vvvtimes;

import java.lang.reflect.Modifier;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;
import javassist.CtNewMethod;

public class DynamicGenerateClass {

	public static void main(String[] args) throws Exception {

		// ClassPool:CtClass對象的容器
		ClassPool pool = ClassPool.getDefault();

		// 通過ClassPool生成一個public新類Employee.java
		CtClass ctClass = pool.makeClass("com.vvvtimes.bean.Employee");

		// 添加字段
		// 首先添加字段private String ename
		CtField enameField = new CtField(pool.getCtClass("java.lang.String"), "ename", ctClass);
		enameField.setModifiers(Modifier.PRIVATE);
		ctClass.addField(enameField);

		// 其次添加字段privtae int eage
		CtField eageField = new CtField(pool.getCtClass("int"), "eage", ctClass);
		eageField.setModifiers(Modifier.PRIVATE);
		ctClass.addField(eageField);

		// 其次添加字段privtae int eage
		CtField esexField = new CtField(pool.getCtClass("int"), "esex", ctClass);
		esexField.setModifiers(Modifier.PRIVATE);
		ctClass.addField(esexField);

		// 為字段ename和eno添加getter和setter方法
		ctClass.addMethod(CtNewMethod.getter("getEname", enameField));
		ctClass.addMethod(CtNewMethod.setter("setEname", enameField));
		ctClass.addMethod(CtNewMethod.getter("getEage", eageField));
		ctClass.addMethod(CtNewMethod.setter("setEage", eageField));
		ctClass.addMethod(CtNewMethod.getter("getSex", esexField));
		ctClass.addMethod(CtNewMethod.setter("setSex", esexField));

		// 添加構造函數
		CtConstructor ctConstructor = new CtConstructor(new CtClass[] {}, ctClass);
		// 為構造函數設置函數體
		StringBuffer buffer = new StringBuffer();
		buffer.append("{\n").append("ename=\"gsls200808\";\n").append("eage=25;\n").append("esex=1;\n}");
		ctConstructor.setBody(buffer.toString());
		// 把構造函數添加到新的類中
		ctClass.addConstructor(ctConstructor);

		// 添加自定義方法
		CtMethod ctMethod = new CtMethod(CtClass.voidType, "printInfo", new CtClass[] {}, ctClass);
		// 為自定義方法設置修飾符
		ctMethod.setModifiers(Modifier.PUBLIC);
		// 為自定義方法設置函數體
		StringBuffer buffer2 = new StringBuffer();
		buffer2.append("{\n").append("System.out.println(\"begin!\");\n")
				.append("System.out.println(\"name=\"+ename);\n").append("System.out.println(\"age=\"+eage);\n")
				.append("System.out.println(\"sex=\"+esex);\n").append("System.out.println(\"end!\");\n").append("}");
		ctMethod.setBody(buffer2.toString());
		ctClass.addMethod(ctMethod);

		// 為了驗證效果,下面使用反射執行方法printInfo
		Class<?> clazz = ctClass.toClass();
		Object obj = clazz.newInstance();
		obj.getClass().getMethod("printInfo", new Class[] {}).invoke(obj, new Object[] {});

	}
}

需要引用的第三方jar:javassist-3.20.0-GA.jar

運行結果

begin!
name=gsls200808
age=25
sex=1
end!

代碼的意思相當於在內存中創建了一個名為com.vvvtimes.bean.Employee的類,並通過反射方式調用了printInfo方法進行輸出。


這個類的內容大致如下,只不過我們在上面是動態生成的

package com.vvvtimes.bean;

import java.io.PrintStream;

public class Employee
{
  private String ename = "gsls200808";
  private int eage = 25;
  private int esex = 1;
  
  public String getEname()
  {
    return this.ename;
  }
  
  public void setEname(String paramString)
  {
    this.ename = paramString;
  }
  
  public int getEage()
  {
    return this.eage;
  }
  
  public void setEage(int paramInt)
  {
    this.eage = paramInt;
  }
  
  public int getSex()
  {
    return this.esex;
  }
  
  public void setSex(int paramInt)
  {
    this.esex = paramInt;
  }
  
  public void printInfo()
  {
    System.out.println("begin!");
    System.out.println("name=" + this.ename);
    System.out.println("age=" + this.eage);
    System.out.println("sex=" + this.esex);
    System.out.println("end!");
  }
}

在後續文章中我們會講如何獲取內存中的類

Java逆向基礎之動態生成類