Java逆向基礎之動態生成類
阿新 • • 發佈:2018-04-23
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逆向基礎之動態生成類