1、功能类

   功能类共有五,分别是:

package org.jvm;

import java.io.*;

/**
* 对字节数组操作的工具类
*/
public class ByteUtils {
public static int byte2Int(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[] origialBytes,int offset,int len,byte[] replaceBytes){
byte[] newBytes=new byte[origialBytes.length+(replaceBytes.length-len)];
System.arraycopy(origialBytes,0,newBytes,0,offset);
System.arraycopy(replaceBytes,0,newBytes,offset,replaceBytes.length);
System.arraycopy(origialBytes,offset+len,newBytes,offset+replaceBytes.length,origialBytes.length-offset-len);
return newBytes;
}
}
 
package org.jvm;

import java.io.*;

/**
* 对测试类class文件的字节数组执行替换,将oldStr替换成newStr
*/
public class ClassModifier {
private static final int CONSTANT_POOL_COUNT_INDEX=8;
private static final int CONSTANT_UTF8_info=1;
private static final int[] CONSTANT_ITEM_LENGTH={-1,-1,5,-1,5,9,9,3,3,5,5,5,5};
private final int u1=1;
private final int u2=2;
private byte[] classByte;
public ClassModifier(byte[] classByte){
this.classByte=classByte;
}
public byte[] modiftyUTF8Constant(String oldStr,String newStr){
int cpc=getConstantPoolCount();
int offset=CONSTANT_POOL_COUNT_INDEX+u2;
for(int i =0;i<cpc;i++){
//取出CONSTANT_UTF8_info中标志部分
int tag= ByteUtils.byte2Int(classByte, offset, u1);
//判断是否为CONSTANT_UTF8_info数据类型
if(tag==CONSTANT_UTF8_info){
//取出CONSTANT_UTF8_info中字符串的长度
int len=ByteUtils.byte2Int(classByte,offset+u1,u2);
offset+=(u1+u2);
//取出CONSTANT_UTF8_info中的字符串部分
String str=ByteUtils.bytes2String(classByte,offset,len);
//通过字符串部分比较是否为需要修改的CONSTANT_UTF8_info
if(str.equalsIgnoreCase(oldStr)){
//将新字符串的值打散成字节数组
byte[] strBytes=ByteUtils.string2Bytes(newStr);
//将表示字符串长度值的两个字节分别以16进制的形式装在字节数组中
byte[] strLen=ByteUtils.int2Bytes(newStr.length(),u2);
//将CONSTANT_UTF8_info中表示length部分进行替换
classByte=ByteUtils.bytesReplace(classByte,offset-u2,u2,strLen);
//将CONSTANT_UTF8_info中字符串部分进行替换
classByte=ByteUtils.bytesReplace(classByte,offset,len,strBytes);
return classByte;
//如不是需要修改的CONSTANT_UTF8_info,则跳过这个类型,接着循环
}else {
offset+=len;
}
//如果不是CONSTANT_UTF8_info数据类型,根据tag跳转CONSTANT_ITEM_LENGTH中定义的字节数
}else {
offset+=CONSTANT_ITEM_LENGTH[tag];
}
}
return classByte;
}
public int getConstantPoolCount(){
package org.jvm;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.PrintStream; /**
* 用于替换System的输出,将测试类中每次System.out的内容输出到字节数组流中,最后一次性输出到页面
*/
public class HackSystem {
public final static InputStream in=System.in;
private static ByteArrayOutputStream buffer=new ByteArrayOutputStream();
public static final PrintStream out=new PrintStream(buffer);
public static final PrintStream err=out;
public static String getBuffer(){
return buffer.toString();
}
public static void clearBuffer(){
buffer.reset();
}
}
package org.jvm;

/**
* 测试类的类加载器,通过字节数组的方式进行加载
*/
public class HotSwapClassloader extends ClassLoader{
public HotSwapClassloader(){
super(HotSwapClassloader.class.getClassLoader());
}
public Class loadByte(byte[] classByte){
return defineClass(null,classByte,0,classByte.length);
} }
package org.jvm;

import java.lang.reflect.Method;

/**
* 执行类,通过反射调用测试类中的main方法,最后取出HackSystem中字节数组流中的数据进行返回
*/
public class JavaClassExecuter {
public static String executer(byte[] classByte) throws NoSuchMethodException {
     HackSystem.clearBuffer();
ClassModifier classModifier=new ClassModifier(classByte);
byte[] modiByte=classModifier.modiftyUTF8Constant("java/lang/System","org/jvm/HackSystem");
HotSwapClassloader loader=new HotSwapClassloader();
Class cs=loader.loadByte(modiByte);
try {
Method method=cs.getMethod("main", new Class[]{String[].class});
method.invoke(null,new String []{null});
}catch (Throwable throwable){
throwable.printStackTrace(HackSystem.out);
}
return HackSystem.getBuffer();
}
}

2、测试类

  

package org.jvm;

/**
* 测试类,在此类中打印想要在页面看到的内容,System.out输出的内容会存在HackSystem的字节数组输出流中
*/
public class TestClass {
public static void main(String[] args) {
System.out.println("-----this is test class out println----");
}
}

3、jsp页面

  test.jsp

<%@ page import="java.lang.*" %>
<%@ page import="java.io.*" %>
<%@ page import="org.jvm.*" %>
<%
InputStream inputStream=new FileInputStream("/opt/TestClass.class");
byte[] b=new byte[inputStream.available()];
inputStream.read(b);
inputStream.close();
out.println(JavaClassExecuter.executer(b));
%>

使用方法:

  1、将 ByteUtils ClassModifier HackSystem HotSwapClassloader JavaClassExecuter TestClass 这六个.java文件上传到服务器通过javac进行编译成.class 文件

  2、将编译好的TestClass放在/opt目录中

  3、在tomcat的项目位置的WEB-INF/classes/中新建org/jvm文件夹,再将编译好的 ByteUtils ClassModifier HackSystem HotSwapClassloader JavaClassExecuter 放在WEB-INF/classes/org/jvm中

  4、将test.jsp放在项目中能访问到的位置,如项目的根路径中

  5、在浏览器中访问jsp页面即可,如http://192.168.3.235:8080/test.jsp即可看到页面中会输出

  -----this is test class out println----

  

java 手动实现远程执行功能(深入理解java虚拟机)的更多相关文章

  1. Java实践 — SSH远程执行Shell脚本(转)

    原文地址:http://www.open-open.com/lib/view/open1384351384024.html 1. SSH简介         SSH是Secure Shell的缩写,一 ...

  2. Java实践 — SSH远程执行Shell脚本

    1. SSH简介         SSH是Secure Shell的缩写,一种建立在应用层和传输层基础上的安全协议.SSH在连接和传送过程中会加密所有数据,可以用来在不同系统或者服务器之间进行安全连接 ...

  3. CentOS下利用sshpass不用手动输入密码远程执行命令

       在测试的时候要同时操作多台机器,每次都要挨个去执行几乎相同的命令或者修改一些设置,这样很影响工作效率也很烦,所以就想写一个脚本,远程自动去做这些操作.远程执行命令很简单,但是不能在执行命令加上命 ...

  4. 利用java实现可远程执行linux命令的小工具

    在linux的脚本中,如果不对机器做其他的处理,不能实现在linux的机器上执行命令.为了解决这个问题,写了个小工具来解决这个问题. 后面的代码是利用java实现的可远程执行linux命令的小工具,代 ...

  5. java内存模型(二)深入理解java内存模型的系列好文

    深入理解java内存模型(一)--基础 深入理解java内存模型(二)--重排序 深入理解java内存模型(三)--顺序一致性 深入理解java内存模型(四)--volatile 深入理解java内存 ...

  6. Java内存区域之程序计数器--《深入理解Java虚拟机》学习笔记及个人理解(一)

    Java虚拟机程序计数器 在书上的P39页 程序计数器干嘛的? 有了它,字节码解释器才可以知道下一条要执行的字节码指令是哪个. 无论是取下一条指令还是分支.循环.跳转.中断.线程恢复,都需要这个程序计 ...

  7. Java内存模型知识点小结---《深入理解Java内存模型》(程晓明)读书总结

    一.Java内存模型介绍 内存模型的作用范围: 在Java中,所有实例域.静态域和数组元素存放在堆内存中,线程之间共享,下文称之为“共享变量”.局部变量.方法参数.异常处理器等不会在线程之间共享,不存 ...

  8. Java中设置方法执行的超时时间java.util.concurrent.Future

    java.util.concurrent.Future Future代表一个异步计算的结果.它提供了方法来检查是否计算已经完成,还是正在计算而处于等待状态,并且也提供了获取计算结果 方法.当计算完成后 ...

  9. 《深入理解Java虚拟机》-----第9章 类加载及执行子系统的案例与实战

    概述 在Class文件格式与执行引擎这部分中,用户的程序能直接影响的内容并不太多, Class文件以何种格式存储,类型何时加载.如何连接,以及虚拟机如何执行字节码指令等都是由虚拟机直接控制的行为,用户 ...

随机推荐

  1. E0264 Unable to execute '"/usr/bin/codesign" ...'

    E0264 Unable to execute '"/usr/bin/codesign" ...' http://docwiki.embarcadero.com/RADStudio ...

  2. source tree使用经验

    FeatureXXX具体功能开发分支,从develop分支拉,功能开发自测完后合并到develop分支.来不及上线的feature分支不要合并到develop. develop开发分支,上面代码都是已 ...

  3. matlab中变量问题——readonly 索引超出矩阵维度 workspacefunc 215

    matlab程序运行过程中会出现如上提示,在网上检索未果,键入dbstop if error语句也无法定错误之处,就想这个错误不是一般的错误. 通过间隔打断点的方式最后定位错误为一句exist = f ...

  4. cdn贝四层协议配置端口映射TCP端口转发

    端口映射就是将外网主机的IP地址的一个端口映射到内网中一台机器,提供相应的服务.当用户访问该IP的这个端口时,服务器自动将请求映射到对应局域网内部的机器上.端口映射有动态和静态之分 1.安装好节点后初 ...

  5. 关于.gitignore无法过滤某些文件

    .gitignore文件用于忽略那些无需添加到版本管理的文件.但最近发现有些文件即使被加入到了.gitignore文件中,push时仍会被上传. 原因:如果某些文件已经被纳入了版本管理中,就算是在.g ...

  6. python--第十天总结(Select/Poll/Epoll使用 )

    首先列一下,sellect.poll.epoll三者的区别 select select最早于1983年出现在4.2BSD中,它通过一个select()系统调用来监视多个文件描述符的数组,当select ...

  7. Python设计模式 - UML - 组件图(Component Diagram)

    简介 组件图又称构建图,用于显示系统各组件及各组件关系的物理视图. 组件图通常包括组件.接口.关系.端口和连接器,用来显示程序代码中相应的模块.源文件或源文件集合之间的依赖和泛化关系. 组件图中的组件 ...

  8. 使用 Composer 安装Laravel扩展包的几种方法

    使用 Composer 安装Laravel扩展包的几种方法 以下的三种方法都是需要你在项目的根目录运行 第一种:composer install 如有 composer.lock 文件,直接安装,否则 ...

  9. E. Segment Sum(数位dp)

    题意:求一个区间内满足所有数位不同数字个数小于K的数字总和.比如:k=2   1,2,3所有数位的不同数字的个数为1满足,但是123数位上有三个不同的数字,即123不满足. 我们可以使用一个二进制的数 ...

  10. sqlserver2017 重装过程中出现“无法找到数据库引擎启动句柄”错误的解决办法

    sqlserver数据库引擎修改账号名,详情参考:http://blog.51cto.com/djclouds/2089047?utm_source=oschina-app 在SQL Server安装 ...