可以修改类结构的java HostSwap实现思想

前段时间做动态无侵入拦截的工作,对于“即时加载”新类有了一些较深入的理解,已经写出两篇文章在这里。

我们已经解决了“如何修改”的问题,但是另一个问题是“能修改成什么样子”。

利用Instrumentation来动态redefine的类,只能修改方法,即在原有的方法代码插入代码来实现我们需要的逻辑。

却无法增加,删除方法和字段,即修改类定义的结构。

 

目前真正能做到“即时”加载结构已经被修改的新的class的工具就是javarebel.但这个工具是一个收费的(免费的功能有限)

工具,其它还没见到有相同功能的工具,其实这种需求是很强烈的,特别是在开发阶段,新修改一个类的实现,特别是类的结构。

希望能在不重启的情况下能即时看到效果。而实际上只javarebel能做到,说明这个技术还是有些小难度的。

 

经过非人的折磨(看混淆过的反编译码还不如直接看字节码更明白),基本弄懂了某个工具的实现原理(传说为了研究目的进行

某些工作可以原谅的,也正是因为这个原因可能会引起不必要的麻烦,所以不写具体的代码,只做原理性的记录在这里)。

当然,对于从class读懂了它的字节码,crack是相当简单滴了。

 

首先,把JDK中几个基本类的源码拿过来修改。

ClassLoader,Class,Enum,Constructor,Field,Method,Proxy.这几个类,其实还有其它几个ObjectStreamClass,URLClassLoader,PropertyResourceBundle,ResourceBundle$Control这几个类都需要修改。但是

从原理上讲对于最小模型我们先动ClassLoader,Class,Enum,Constructor,Field,Method,Proxy.

 

 现在假设有一个class:

class A{

   int x = 0;

}

要加载这个类,一定不能被JRE的默认ClassLoader加载,因为类一旦在JVM中露头,你在redefin时只能修改它的方法体而不能

修改它的结构了。所以我们要修改ClassLoader,当加载类A的时候,我们利用字节码生成器生成一个A$$ver1.class,其中A的

所有方法都在A$$ver1中实现,并反回这个A$$ver1的Class引用。

 

这里我们就需要修改Class,Constructor,Field,Method这几个基础类了。比如Class的getName(),当A$$ver1.class.getName()时

在return name前需要

int index = name.indexOf("$$ver");

if(index != -1) name = name.subString(0,index);

 

而Class.forName(String name)时我们则需要

修改成name = name + "$$verx";//这个x可以用一个全局的map保存原始类和当前版本的对应表。

 

还有Constructor,Method,Field这些反射方法,都要修改,即load A时,我实际是动态生成了A$$ver1.class,所以这些类中对应的方法中

要修改成实际上找A$$ver1来对应A的逻辑。

 

 

这时如果我们修改了A:

class A{

   int x = 0;

   int y = 0;

}

 

当扫描发现类结构被修改后,被crack过的ClassLoader又动态生成一个A$$ver2.class,当然修改后的方法和字段都生成在A$$ver2.class中,这里映射表中把A的对应类换成A$$ver2,所以Class类,Constructor,Field,Method,Proxy这些基础类访问A.class时都知道直接去访问A$$ver2.class,原来的A$$ver1.class就放弃了。

 

这样实际上每次修改A时底层实际上是生成了不同版本的它的替身,然后通过被crack过的基础类ClassLoader,Class,Enum,Constructor,Field,Method,Proxy就能达到动态“加载”目的。

 

前提是这几个被crack过的基础类一定要在Boot-Classpath中,先于JRE的原始的基础类工作。

 

 

你可能感兴趣的:(可以修改类结构的java HostSwap实现思想)