ASM是一个JAVA字节码分析、创建和修改的开源应用框架。
它可以动态生成二进制格式的stub类或其它代理类,或者在类被JAVA虚拟机装入内存之前,动态修改类。
一般情况下,Class文件是通过javac编译器产生的,然后通过类加载器加载到虚拟机内,再通过执行引擎去执行。
现在我们可以通过ASM的API直接生成符合Java虚拟机规范的Class字节流,
从这个角度来看,ASM承担的工作与javac解释器的工作相似。
ASM可以从字节码的角度,分析、创建一个类,同时也可以修改一个已经被编译过的类文件。
因此,我们可以通过ASM来实现诸如代码生成、代码混淆、代码转换等等以字节码为操作目标的工作。
本篇博客就记录一下利用ASM来加密Jar中字符串的方法。
这么做的初衷是:
Proguard只能混淆代码,无法混淆代码中使用的字符串。
想要混淆字符串,可能要借助收费的DexGuard。
于是,可以利用ASM来直接加密Jar包。
P.S.:
我目前的公司,产品以SDK为主,输出为Jar包。
因此这里以加密Jar包为例。
关于ASM框架的详细内容就不再赘述了,直接上加密Jar的代码。
这里依赖的lib为asm-all-5.2.jar和commons-lang3-3.5.jar。
1、定义加密字符的方法
package com.encrypt.util;
/**
* Created by zhangjian on 18-3-29
*/
public class Transform {
/**
* 将字符串编码成16进制数字,适用于所有字符(包括中文)
*/
public static byte[] encode(byte[] bytes, String key) {
int len = bytes.length;
int keyLen = key.length();
for (int i = 0; i < len; i++) {
bytes[i] = (byte) (bytes[i] ^ key.charAt(i % keyLen));
}
return bytes;
}
/**
* 将16进制数字解码成字符串,适用于所有字符(包括中文)
*/
public static String decode(byte[] bytes, String key) {
int len = bytes.length;
int keyLen = key.length();
for (int i = 0; i < len; i++) {
bytes[i] = (byte) (bytes[i] ^ key.charAt(i % keyLen));
}
return new String(bytes);
}
}
2、定义Main Class
/**
* Created by zhangjian on 18-3-29
*/
public class Encrypt {
//Transform.java对应class文件路径
private static final String TRANSFORM_FILE = Transform.class.getName().replace(".", "/") + ".class";
public static void main(String[] args) throws IOException {
if (args == null || args.length < 1) {
return;
}
//读取传入的待加密的Jar包路径
String path = args[0];
if (!path.endsWith(".jar")) {
return;
}
//读取Transform.java对应的Java字节码
byte b[] = readClass();
//指定输入和输出文件
int index = path.lastIndexOf(".jar");
File jarIn = new File(path);
File jarOut = new File(path.substring(0, index) + "obfused.jar");
try {
//开始处理Jar包
processJar(jarIn, jarOut, Charset.forName("UTF-8"), Charset.forName("UTF-8"), b);
} catch (IllegalArgumentException e) {
if ("MALFORMED".equals(e.getMessage())) {
processJar(jarIn, jarOut, Charset.forName("GBK"), Charset.forName("UTF-8"), b);
} else {
throw e;
}
}
}
private static byte[] readClass() {
InputStream in;
try {
in = Transform.class.getClassL