java远程执行调试类
2015-12-07 13:49
573 查看
package com.dfb.dong.loader; /** * 為了多次載入執行類而加入的加载器 * 把defineClass方法开放出来,只有外部显式调用的时候才会使用到loadByte方法 * 由虚拟机调用时,仍然按照原有的双亲委派规则使用loadClass方法进行类加载 * @author zhoudong * */ public class HotSwapClassLoader extends ClassLoader{ public HotSwapClassLoader() { super(HotSwapClassLoader.class.getClassLoader()); } @SuppressWarnings("rawtypes") public Class loadByte(byte [] classByte) { return defineClass(null, classByte,0,classByte.length); } }
package com.dfb.dong.modifier; import com.dfb.dong.util.ByteUtils; /** * 修改Class文件,暂时只提供修改常量池常量的功能 * @author zhoudong * */ public class ClassModifier { /** * Class文件中常量池的起始偏移 */ private static final int CONSTANT_POOL_COUNT_INDEX = 8; /** * CONSTANT_Uff8_info常量的tag标志 */ private static final int CONSTANT_Utf8_info = 1; /** * 常量池中11中常量所占的长度,CONSTATN_UTF8_INFO型常量除外,因为它不是定长的 */ private static final int [] CONSTANT_ITEM_LENGTH={-1,-1,-1,5,5,9,9,3,3,5,5,5,5}; private static final int u1 = 1; private static final int u2 = 2; private byte[] classByte; public ClassModifier(byte []classByte) { this.classByte = classByte; } /** * 修改常量池中CONSTANT_Uft8_info常量的内容 * @param oldStr 修改前的字符串 * @param newStr 修改后的字符串 * @return 修改结果 */ public byte[] modifyUTF8Constant(String oldStr,String newStr) { int cpc = getConstantPoolCount();//获取常量值 int offset = CONSTANT_POOL_COUNT_INDEX + u2;//常量值开始位置,常量表示符占两个字节 for(int i=0;i<cpc;i++) { int tag = ByteUtils.bytes2Int(classByte, offset, u1);//常量值占一个字节 if(tag == CONSTANT_Utf8_info)//常量标志 { int len = ByteUtils.bytes2Int(classByte, offset+u1, u2);//一个常量占两个字节 offset += (u1+u2); String str = ByteUtils.bytes2String(classByte, offset, len); if(str.equalsIgnoreCase(oldStr)) { byte[] strBytes = ByteUtils.string2Bytes(newStr); byte[] strLen = ByteUtils.int2Bytes(newStr.length(), u2); classByte = ByteUtils.bytesReplace(classByte, offset-u2, u2, strLen); classByte = ByteUtils.bytesReplace(classByte, offset, len, strBytes); return classByte; }else{ offset += len; } }else{ offset += CONSTANT_ITEM_LENGTH[tag]; } } return classByte; } /** * 获取常量池中常量的数量 * @return 常量池数量 */ private int getConstantPoolCount() { return ByteUtils.bytes2Int(classByte, CONSTANT_POOL_COUNT_INDEX, u2);//常量池数量值占两个字节,从class文件的第八位到第十位为常量池数量位置 } }
package com.dfb.dong.system; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.PrintStream; /** * 为JavaClass劫持java.lang.System提供支持 * 除了out和err外,其余的都直接转发给System处理 * @author zhoudong * */ public class HackSystem { public final static InputStream in = System.in; private static ByteArrayOutputStream buffer = new ByteArrayOutputStream(); public final static PrintStream out = new PrintStream(buffer); public final static PrintStream err = out; public static String getBufferString() { return buffer.toString(); } public static void clearBuffer() { buffer.reset(); } public static void setSecurityManager(final SecurityManager s) { System.setSecurityManager(s); } public static SecurityManager getSecurityManager() { return System.getSecurityManager(); } public static long currentTimeMillis() { return System.currentTimeMillis(); } public static void arraycopy(Object src,int srcPos,Object dest,int destPos, int length) { System.arraycopy(src, srcPos, dest, destPos, length); } public static int identityHashCode(Object x) { return System.identityHashCode(x); } /** * 下面所有的方法都与java.lang.System的名称一样 * 实现都是字节转调System的对应方法 */ }
package com.dfb.dong.util; /** * Bytes 数组处理工具 * @author zhoudong * */ public class ByteUtils { public static int bytes2Int(byte[] b,int start,int len) { int sum = 0; int end = start + len; for(int i=start;i<end;i++) { int n = ((int)b[i]) & 0xff; n<<=(--len)*8; sum = n + sum; } return sum; } public static byte[] int2Bytes(int value,int len) { byte[] b = new byte[len]; for(int i=0;i<len;i++) { b[len-i-1] = (byte) ((value>>8*i)&0xff); } return b; } public static String bytes2String(byte[]b,int start,int len) { return new String(b,start,len); } public static byte[] string2Bytes(String str) { return str.getBytes(); } public static byte[] bytesReplace(byte[] originalBytes,int offset,int len,byte[] replaceBytes) { byte[] newBytes = new byte[originalBytes.length+(replaceBytes.length-len)]; System.arraycopy(originalBytes, 0, newBytes, 0, offset); System.arraycopy(replaceBytes, 0, newBytes, offset, replaceBytes.length); System.arraycopy(originalBytes, offset+len,newBytes ,offset+replaceBytes.length, originalBytes.length-offset-len); return newBytes; } }
package com.dfb.dong.executer; import java.lang.reflect.Method; import com.dfb.dong.loader.HotSwapClassLoader; import com.dfb.dong.modifier.ClassModifier; import com.dfb.dong.system.HackSystem; /** * JavaClass执行工具 * @author zhoudong * */ public class JavaClassExecuter { /** * 执行外部传过来的代表一个Java类的byte数组 * 将输入类的byte数组中代表java.lang.System的CONSTANT_Uft8_info常量修改为劫持后的HackSystem类 * 执行方法为该类的static main(String [] atgs)方法,输出结果为该类向System.out/err输出的信息 * * @param classByte 代表一个java类的byte数组 * @return 执行结果 */ public static String excute(byte [] classByte) { HackSystem.clearBuffer(); ClassModifier cm = new ClassModifier(classByte); byte[] modiBytes = cm.modifyUTF8Constant("java/lang/System", "com/dfb/dong/system/HackSystem"); HotSwapClassLoader loader = new HotSwapClassLoader(); Class clazz = loader.loadByte(modiBytes); try { Method method = clazz.getMethod("main", new Class[]{String[].class}); method.invoke(null, new String[]{null}); } catch (Throwable e) { e.printStackTrace(HackSystem.out); } return HackSystem.getBufferString(); } }
相关文章推荐
- struts2文件下载及文件名中文问题
- spring mvc 使用session
- Java 学习历程(一)程序执行过程
- 详解Java GC的工作原理+Minor GC、FullGC
- Java数据库连接(JDBC)【整理】
- 使用JAVA爬取网页图片
- java中split的坑,用的时候一定要小心
- java中不同循环的系能比较
- 第二章 Spring Security起步
- java int与byte【】之间的转换
- SpringMVC_RESTful简易笔记
- Java 8十个lambda表达式案例
- mysq连接 mysql-connector-java-5.1.34.jar
- SpringMVC整合Swagger框架
- 在Eclipse 中,选择一个变量名,其他相同变量名都高亮阴影显示 的设置
- java中while的用法
- 简单谈谈Java中String类型的参数传递问题
- java实现图片与base64字符串之间的转换
- Java关键字final、static使用总结 - 熔 岩 - 51CTO技术博客
- java socket编程之聊天室(一)