Android 安全——Java環境動態加載Jar之Jar包的加密和解密

編寫測試Jar包

1.類結構

這裏寫圖片描述

2.類代碼

Parent.class

package com.wind.test;

abstract class Parent {
    public String name() {
        return "Piter";
    }
}

Jim.class

package com.wind.test;

class Jim extends Parent {

    public String name() {
        return "My father is " + super.name() + " and my name is Jim";
    }
}

Tom.class

package com.wind.test;

class Tom extends Parent{

    public String name() {
        return "My father is " + super.name() + " and my name is Tom";
    }
}

Test.class

package com.wind.test;

public class Test {
    public void print() {
        Jim son1 = new Jim();
        System.out.println(son1.name());
        Tom son2 = new Tom();
        System.out.println(son2.name());
    }
}

Main.class

package com.wind.main;

import com.wind.test.Test;

public class Main {

    public static void main(String[] args) {
        new Test().print();
    }
}

3.運行結果

這裏寫圖片描述

4.打包

打包過程在上一篇文章有,這裏就不贅述了。

Jar包的加密類

package com.wind.load.enjar;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;

import com.wind.load.Base64;

public class JarEncoder {
    private JarInputStream jis;

    public JarEncoder(String src) throws FileNotFoundException, IOException {
        this(new FileInputStream(src));
    }

    public JarEncoder(File file) throws FileNotFoundException, IOException {
        this(new FileInputStream(file));
    }

    public JarEncoder(InputStream is) throws IOException {
        jis = new JarInputStream(is);
    }

    /**
     * 通過指定的路徑輸出加密後的jar
     * @param target
     * @throws FileNotFoundException
     * @throws IOException
     */
    public void write(String target) throws FileNotFoundException, IOException {
        write(new FileOutputStream(target));
    }

    /**
     * 通過指定的文件輸出加密後的jar
     * @param file
     * @throws FileNotFoundException
     * @throws IOException
     */
    public void write(File file) throws FileNotFoundException, IOException {
        write(new FileOutputStream(file));
    }

    /**
     * 通過指定的輸出流輸出加密後的jar
     * @param os
     * @throws FileNotFoundException
     * @throws IOException
     */
    public void write(OutputStream os) throws FileNotFoundException, IOException {
        Manifest menifest = jis.getManifest(); //獲取jar的Manifest信息
        JarOutputStream jos = null;
        if(menifest == null) {
            jos = new JarOutputStream(os);
        } else {
            //JarInputStream的getNextJarEntry()方法無法獲取Manifest信息,所以只能通過這種方式寫入Manifest信息
            jos = new JarOutputStream(os, menifest);
        }

        JarEntry entry = null;
        while((entry = jis.getNextJarEntry()) != null) {
            jos.putNextEntry(entry);
            if(entry.getName().endsWith(".class")) { //只加密class文件
                byte[] bytes = getBytes(jis); //讀取class文件內容
                byte[] enbytes = Base64.encode(bytes); //加密後的信息
                jos.write(enbytes, 0, enbytes.length); //把加密後的信息寫入流
            } else { //其他類型的文件直接寫入流
                byte[] bytes = getBytes(jis);
                jos.write(bytes, 0, bytes.length);
            }
            jos.flush();
        }
        jos.close();
        jis.close();
    }

    /**
     * 從jar輸入流中讀取信息
     * @param jis
     * @return
     * @throws IOException
     */
    private byte[] getBytes(JarInputStream jis) throws IOException {
        int len = 0;
        byte[] bytes = new byte[8192];
        ByteArrayOutputStream baos = new ByteArrayOutputStream(2048);
        while((len = jis.read(bytes, 0, bytes.length)) != -1) {
            baos.write(bytes, 0, len);
        }
        return baos.toByteArray();
    }
}

Jar包的解密類

package com.wind.load.dejar;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;

import com.wind.load.Base64;

public class JarDecoder extends ClassLoader {
    private JarInputStream jis;
    private Map<String, ByteBuffer> entryMap;

    public JarDecoder(String src) throws FileNotFoundException, IOException {
        this(new FileInputStream(src));
    }

    public JarDecoder(File file) throws FileNotFoundException, IOException {
        this(new FileInputStream(file));
    }

    public JarDecoder(InputStream is) throws IOException {
        jis = new JarInputStream(is);
        entryMap = new HashMap<String, ByteBuffer>();
        JarEntry entry = null;
        while((entry = jis.getNextJarEntry()) != null) {
            String name = entry.getName();
            if(name.endsWith(".class")) { //class文件解密後再緩存
                byte[] bytes = getBytes(jis); //讀取class文件內容
                byte[] debytes = Base64.decode(bytes); //解密class文件內容
                ByteBuffer buffer = ByteBuffer.wrap(debytes); //把數據複製到ByteBuffer對象中
                entryMap.put(name, buffer); //緩存數據
            } else { //其他文件直接緩存
                byte[] bytes = getBytes(jis);
                ByteBuffer buffer = ByteBuffer.wrap(bytes);
                entryMap.put(name, buffer);
            }
        }
        jis.close();
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        String path = name.replace('.', '/').concat(".class");
        ByteBuffer buffer = entryMap.get(path);
        if(buffer == null) {
            return super.findClass(name);
        } else {
            byte[] bytes = buffer.array();
            return defineClass(name, bytes, 0, bytes.length);
        }
    }

    /**
     * 從jar輸入流中讀取信息
     * @param jis
     * @return
     * @throws IOException
     */
    private byte[] getBytes(JarInputStream jis) throws IOException {
        int len = 0;
        byte[] bytes = new byte[8192];
        ByteArrayOutputStream baos = new ByteArrayOutputStream(2048);
        while((len = jis.read(bytes, 0, bytes.length)) != -1) {
            baos.write(bytes, 0, len);
        }
        return baos.toByteArray();
    }

    /**
     * 關閉Decoder
     * @throws IOException
     */
    public void close() throws IOException {
        Iterator<ByteBuffer> iterator = entryMap.values().iterator();
        while(iterator.hasNext()) {
            ByteBuffer buffer = iterator.next();
            buffer.clear(); //清空ByteBuffer對象緩存
        }
        entryMap.clear(); //清空HashMap
    }
}

測試類

package com.wind.load;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import com.wind.load.dejar.JarDecoder;
import com.wind.load.enjar.JarEncoder;

public class Main {

    public static void main(String[] args) {
        encode();
        decode();
    }

    private static void encode() {
        try {
            JarEncoder encoder = new JarEncoder("E:/test.jar");
            encoder.write("E:/test_encode.jar");
            System.out.println("encode success");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void decode() {
        try {
            JarDecoder decoder = new JarDecoder("E:/test_encode.jar");
            Class<?> cls = decoder.loadClass("com.wind.test.Test");
            Method method = cls.getMethod("print", null);
            method.invoke(cls.newInstance(), null);
            decoder.close();
            System.out.println("decode success");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }
}

運行結果

這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章