自分のclassloaderを作成して暗号化されたclassをロードします
4287 ワード
1 Dateクラスを継承するクラスを作成します.
package erica.classloader;
import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.Date;
public class ClassLoaderAttachment extends Date {
@Override public String toString() { return "hello erica"; }
}
2ロードしたclassファイルを作成し、生成したclassファイルをD:itunesに置くことができるクラスを作成します.
package erica.classloader;
import java.io.*;
public class MyClassLoader {
public static void cypher(InputStream in,OutputStream out) throws IOException{ int b=-1; while((b=in.read())!=-1){ out.write(b^0xff); } }
}
3暗号化生成後のclassの実行
public static void main(String[] args) throws Exception { String srcPath="D:/workspace/WorkSpaceSpring/ReflectTest/bin/erica/classloader/ClassLoaderAttachment.class"; String descPath="D:\\itunes\\ClassLoaderAttachment.class"; FileInputStream fis=new FileInputStream(srcPath); FileOutputStream fos=new FileOutputStream(descPath); cypher(fis,fos); System.out.println("success"); }
4生成したclassを元のクラスのclassファイルに上書きし、java仮想マシン特定のclassloaderでファイルをロードするとエラーが発生します.
package erica.classloader;
import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.Date;
public class ClassLoaderAttachment extends Date {
@Override public String toString() { return "hello erica"; } public static void main(String[] args) throws Exception {
ClassLoaderAttachment ca=new ClassLoaderAttachment(); System.out.println(ca); } }
エラーは図のように表示されます.
5それでは、暗号化されたclassをロードするために、私たち自身の書いたクラスローダです.
1:ClassLoaderクラスの継承
2:protected Classを上書きfindClass(String name)throws ClassNotFoundExceptionメソッド
3:defineClassを呼び出し、byte配列をClassクラスのインスタンスに変換します.このインスタンスは、バイナリバイトコードの列をロードしたClassのオブジェクトです.
public class MyClassLoader extends ClassLoader{
private String dir; public MyClassLoader(){ } public MyClassLoader(String dir){ this.dir=dir; }
@Override protected ClassfindClass(String name)throws ClassNotFoundException{ System.out.println("findClass"); String classname=dir+"/"+name+".class"; FileInputStream fis; try { fis = new FileInputStream(classname); ByteArrayOutputStream out=new ByteArrayOutputStream(); cypher(fis,out); fis.close(); byte[]bytes=out.toByteArray(); return defineClass(null,bytes,0,bytes.length); } catch (Exception e) { e.printStackTrace(); } return null; }
}
6:自分のクラスローダで自分のバイトコードをロードする
public static void main(String[] args) throws Exception { MyClassLoader loader=new MyClassLoader("erica"); Date d=(Date)loader.loadClass("ClassLoaderAttachment").newInstance(); //Date d=(Date)loader.loadClass("erica.classloader.ClassLoaderAttachment").newInstance();//パッケージ名+クラス名Systemが指定されているため、元のclassがロードされます.out.println(d); }
印刷結果:
findClass hello erica
findClass文字列が印刷され、独自のクラスローダが実行されていることを示します.
jdkドキュメントの自己作成クラスローダの例を次に示します.
たとえば、アプリケーションは、サーバからクラスファイルをダウンロードするネットワーククラスローダを作成できます.サンプルコードは次のとおりです.
ネットワーククラスローダサブクラスは、ネットワークからクラスをロードする方法
package erica.classloader;
import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.Date;
public class ClassLoaderAttachment extends Date {
@Override public String toString() { return "hello erica"; }
}
2ロードしたclassファイルを作成し、生成したclassファイルをD:itunesに置くことができるクラスを作成します.
package erica.classloader;
import java.io.*;
public class MyClassLoader {
public static void cypher(InputStream in,OutputStream out) throws IOException{ int b=-1; while((b=in.read())!=-1){ out.write(b^0xff); } }
}
3暗号化生成後のclassの実行
public static void main(String[] args) throws Exception { String srcPath="D:/workspace/WorkSpaceSpring/ReflectTest/bin/erica/classloader/ClassLoaderAttachment.class"; String descPath="D:\\itunes\\ClassLoaderAttachment.class"; FileInputStream fis=new FileInputStream(srcPath); FileOutputStream fos=new FileOutputStream(descPath); cypher(fis,fos); System.out.println("success"); }
4生成したclassを元のクラスのclassファイルに上書きし、java仮想マシン特定のclassloaderでファイルをロードするとエラーが発生します.
package erica.classloader;
import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.Date;
public class ClassLoaderAttachment extends Date {
@Override public String toString() { return "hello erica"; } public static void main(String[] args) throws Exception {
ClassLoaderAttachment ca=new ClassLoaderAttachment(); System.out.println(ca); } }
エラーは図のように表示されます.
5それでは、暗号化されたclassをロードするために、私たち自身の書いたクラスローダです.
1:ClassLoaderクラスの継承
2:protected Classを上書きfindClass(String name)throws ClassNotFoundExceptionメソッド
3:defineClassを呼び出し、byte配列をClassクラスのインスタンスに変換します.このインスタンスは、バイナリバイトコードの列をロードしたClassのオブジェクトです.
public class MyClassLoader extends ClassLoader{
private String dir; public MyClassLoader(){ } public MyClassLoader(String dir){ this.dir=dir; }
@Override protected ClassfindClass(String name)throws ClassNotFoundException{ System.out.println("findClass"); String classname=dir+"/"+name+".class"; FileInputStream fis; try { fis = new FileInputStream(classname); ByteArrayOutputStream out=new ByteArrayOutputStream(); cypher(fis,out); fis.close(); byte[]bytes=out.toByteArray(); return defineClass(null,bytes,0,bytes.length); } catch (Exception e) { e.printStackTrace(); } return null; }
}
6:自分のクラスローダで自分のバイトコードをロードする
public static void main(String[] args) throws Exception { MyClassLoader loader=new MyClassLoader("erica"); Date d=(Date)loader.loadClass("ClassLoaderAttachment").newInstance(); //Date d=(Date)loader.loadClass("erica.classloader.ClassLoaderAttachment").newInstance();//パッケージ名+クラス名Systemが指定されているため、元のclassがロードされます.out.println(d); }
印刷結果:
findClass hello erica
findClass文字列が印刷され、独自のクラスローダが実行されていることを示します.
jdkドキュメントの自己作成クラスローダの例を次に示します.
たとえば、アプリケーションは、サーバからクラスファイルをダウンロードするネットワーククラスローダを作成できます.サンプルコードは次のとおりです.
ClassLoader loader = new NetworkClassLoader(host, port);
Object main = loader.loadClass("Main", true).newInstance();
. . .
ネットワーククラスローダサブクラスは、ネットワークからクラスをロードする方法
findClass
およびloadClassDataを定義する必要があります.クラスを構成するバイトをダウンロードした後、メソッドdefineClass
を使用してクラスインスタンスを作成する必要があります.例は次のようになります. class NetworkClassLoader extends ClassLoader {
String host;
int port;
public Class findClass(String name) {
byte[] b = loadClassData(name);
return defineClass(name, b, 0, b.length);
}
private byte[] loadClassData(String name) {
// load the class data from the connection
. . .
}
}