|
@@ -3,14 +3,20 @@ package winter.com.ideaaedi.classwinter.executor;
|
|
|
import javassist.CannotCompileException;
|
|
import javassist.CannotCompileException;
|
|
|
import javassist.ClassPool;
|
|
import javassist.ClassPool;
|
|
|
import javassist.NotFoundException;
|
|
import javassist.NotFoundException;
|
|
|
|
|
+import org.dom4j.Document;
|
|
|
|
|
+import org.dom4j.Element;
|
|
|
|
|
+import org.dom4j.io.SAXReader;
|
|
|
|
|
+import org.dom4j.io.XMLWriter;
|
|
|
import winter.com.ideaaedi.classwinter.Reverses;
|
|
import winter.com.ideaaedi.classwinter.Reverses;
|
|
|
import winter.com.ideaaedi.classwinter.author.JustryDeng;
|
|
import winter.com.ideaaedi.classwinter.author.JustryDeng;
|
|
|
import winter.com.ideaaedi.classwinter.exception.ClassWinterException;
|
|
import winter.com.ideaaedi.classwinter.exception.ClassWinterException;
|
|
|
import winter.com.ideaaedi.classwinter.util.Cache;
|
|
import winter.com.ideaaedi.classwinter.util.Cache;
|
|
|
import winter.com.ideaaedi.classwinter.util.Constant;
|
|
import winter.com.ideaaedi.classwinter.util.Constant;
|
|
|
import winter.com.ideaaedi.classwinter.util.EncryptUtil;
|
|
import winter.com.ideaaedi.classwinter.util.EncryptUtil;
|
|
|
|
|
+import winter.com.ideaaedi.classwinter.util.ExceptionUtil;
|
|
|
import winter.com.ideaaedi.classwinter.util.IOUtil;
|
|
import winter.com.ideaaedi.classwinter.util.IOUtil;
|
|
|
import winter.com.ideaaedi.classwinter.util.JarUtil;
|
|
import winter.com.ideaaedi.classwinter.util.JarUtil;
|
|
|
|
|
+import winter.com.ideaaedi.classwinter.util.JavaagentCmdArgs;
|
|
|
import winter.com.ideaaedi.classwinter.util.JavassistUtil;
|
|
import winter.com.ideaaedi.classwinter.util.JavassistUtil;
|
|
|
import winter.com.ideaaedi.classwinter.util.Logger;
|
|
import winter.com.ideaaedi.classwinter.util.Logger;
|
|
|
import winter.com.ideaaedi.classwinter.util.Pair;
|
|
import winter.com.ideaaedi.classwinter.util.Pair;
|
|
@@ -18,12 +24,14 @@ import winter.com.ideaaedi.classwinter.util.PathUtil;
|
|
|
import winter.com.ideaaedi.classwinter.util.StrUtil;
|
|
import winter.com.ideaaedi.classwinter.util.StrUtil;
|
|
|
|
|
|
|
|
import java.io.File;
|
|
import java.io.File;
|
|
|
|
|
+import java.io.FileOutputStream;
|
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.nio.charset.StandardCharsets;
|
|
|
import java.security.SecureRandom;
|
|
import java.security.SecureRandom;
|
|
|
import java.util.ArrayList;
|
|
import java.util.ArrayList;
|
|
|
import java.util.Arrays;
|
|
import java.util.Arrays;
|
|
|
import java.util.HashMap;
|
|
import java.util.HashMap;
|
|
|
import java.util.HashSet;
|
|
import java.util.HashSet;
|
|
|
|
|
+import java.util.Iterator;
|
|
|
import java.util.List;
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
import java.util.Map;
|
|
|
import java.util.Set;
|
|
import java.util.Set;
|
|
@@ -37,27 +45,32 @@ import java.util.stream.Collectors;
|
|
|
*/
|
|
*/
|
|
|
public class EncryptExecutor {
|
|
public class EncryptExecutor {
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 调用EncryptExecutor进行加密的“人”是否是maven插件
|
|
|
|
|
+ */
|
|
|
|
|
+ public static boolean invokerIsPlugin = false;
|
|
|
|
|
+
|
|
|
/** 本项目(class-winter)需要打包的代码 */
|
|
/** 本项目(class-winter)需要打包的代码 */
|
|
|
public static final Set<String> CLASS_WINTER_FILES = new HashSet<>();
|
|
public static final Set<String> CLASS_WINTER_FILES = new HashSet<>();
|
|
|
|
|
|
|
|
static {
|
|
static {
|
|
|
- CLASS_WINTER_FILES.add("Cache.class");
|
|
|
|
|
- CLASS_WINTER_FILES.add("JustryDeng.class");
|
|
|
|
|
- CLASS_WINTER_FILES.add("ClassWinterException.class");
|
|
|
|
|
- CLASS_WINTER_FILES.add("DecryptExecutor.class");
|
|
|
|
|
- CLASS_WINTER_FILES.add("Constant.class");
|
|
|
|
|
- CLASS_WINTER_FILES.add("EncryptUtil.class");
|
|
|
|
|
- CLASS_WINTER_FILES.add("ExceptionUtil.class");
|
|
|
|
|
- CLASS_WINTER_FILES.add("IOUtil.class");
|
|
|
|
|
- CLASS_WINTER_FILES.add("JarUtil.class");
|
|
|
|
|
- CLASS_WINTER_FILES.add("JavaagentCmdArgs.class");
|
|
|
|
|
- CLASS_WINTER_FILES.add("JavassistUtil.class");
|
|
|
|
|
- CLASS_WINTER_FILES.add("Logger.class");
|
|
|
|
|
- CLASS_WINTER_FILES.add("Pair.class");
|
|
|
|
|
- CLASS_WINTER_FILES.add("PathUtil.class");
|
|
|
|
|
- CLASS_WINTER_FILES.add("StrUtil.class");
|
|
|
|
|
- CLASS_WINTER_FILES.add("Reverses.class");
|
|
|
|
|
- CLASS_WINTER_FILES.add("Reverses$1.class");
|
|
|
|
|
|
|
+ CLASS_WINTER_FILES.add(Cache.class.getName().replace(".", "/"));
|
|
|
|
|
+ CLASS_WINTER_FILES.add(JustryDeng.class.getName().replace(".", "/"));
|
|
|
|
|
+ CLASS_WINTER_FILES.add(ClassWinterException.class.getName().replace(".", "/"));
|
|
|
|
|
+ CLASS_WINTER_FILES.add(DecryptExecutor.class.getName().replace(".", "/"));
|
|
|
|
|
+ CLASS_WINTER_FILES.add(Constant.class.getName().replace(".", "/"));
|
|
|
|
|
+ CLASS_WINTER_FILES.add(EncryptUtil.class.getName().replace(".", "/"));
|
|
|
|
|
+ CLASS_WINTER_FILES.add(ExceptionUtil.class.getName().replace(".", "/"));
|
|
|
|
|
+ CLASS_WINTER_FILES.add(IOUtil.class.getName().replace(".", "/"));
|
|
|
|
|
+ CLASS_WINTER_FILES.add(JarUtil.class.getName().replace(".", "/"));
|
|
|
|
|
+ CLASS_WINTER_FILES.add(JavaagentCmdArgs.class.getName().replace(".", "/"));
|
|
|
|
|
+ CLASS_WINTER_FILES.add(JavassistUtil.class.getName().replace(".", "/"));
|
|
|
|
|
+ CLASS_WINTER_FILES.add(Logger.class.getName().replace(".", "/"));
|
|
|
|
|
+ CLASS_WINTER_FILES.add(Pair.class.getName().replace(".", "/"));
|
|
|
|
|
+ CLASS_WINTER_FILES.add(PathUtil.class.getName().replace(".", "/"));
|
|
|
|
|
+ CLASS_WINTER_FILES.add(StrUtil.class.getName().replace(".", "/"));
|
|
|
|
|
+ CLASS_WINTER_FILES.add(Reverses.class.getName().replace(".", "/"));
|
|
|
|
|
+ CLASS_WINTER_FILES.add(Cache.class.getName().replace(".", "/").replace("Reverses.class", "Reverses$1.class"));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/** 待加密的的jar/war包路径(如" /tmp/abc.jar) */
|
|
/** 待加密的的jar/war包路径(如" /tmp/abc.jar) */
|
|
@@ -188,7 +201,7 @@ public class EncryptExecutor {
|
|
|
List<File> allNeedEncryptedClassFileList = filterClasses(allFiles);
|
|
List<File> allNeedEncryptedClassFileList = filterClasses(allFiles);
|
|
|
// step3.1. 根据原.class文件,生成加密后的.class文件,并存至Constant.ENCRYPTED_CLASSES_SAVE_DIR
|
|
// step3.1. 根据原.class文件,生成加密后的.class文件,并存至Constant.ENCRYPTED_CLASSES_SAVE_DIR
|
|
|
List<String> allAlreadyEncryptedClassFileList = encryptClasses(allNeedEncryptedClassFileList, new File(targetRootDir,
|
|
List<String> allAlreadyEncryptedClassFileList = encryptClasses(allNeedEncryptedClassFileList, new File(targetRootDir,
|
|
|
- Constant.DEFAULT_ENCRYPTED_CLASSES_SAVE_DIR));
|
|
|
|
|
|
|
+ Constant.MANIFEST_FILE));
|
|
|
// step3.2. 生成记录已加密class的全类名的清单文件
|
|
// step3.2. 生成记录已加密class的全类名的清单文件
|
|
|
generateChecklistFile(allAlreadyEncryptedClassFileList);
|
|
generateChecklistFile(allAlreadyEncryptedClassFileList);
|
|
|
|
|
|
|
@@ -197,26 +210,109 @@ public class EncryptExecutor {
|
|
|
|
|
|
|
|
// step5. 混淆原.class文件(即:清空方法体)
|
|
// step5. 混淆原.class文件(即:清空方法体)
|
|
|
clearClassMethod(allNeedEncryptedClassFileList);
|
|
clearClassMethod(allNeedEncryptedClassFileList);
|
|
|
|
|
+
|
|
|
|
|
+ // step6. 清除META-INF/maven下pom.xml中关于class-winter-plugin的相关信息
|
|
|
|
|
+ clearWinterPluginInfo();
|
|
|
|
|
|
|
|
- // step6. 添加class-winter的用于javaagent解密的代码
|
|
|
|
|
|
|
+ // step7. 添加class-winter的用于javaagent解密的代码
|
|
|
addClassWinterAgent();
|
|
addClassWinterAgent();
|
|
|
-
|
|
|
|
|
- // step7. 汇总那些在本次加密前本身就已经是被class-winter混淆的lib的相关信息到当前项目中
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // step8. 汇总那些在本次加密前本身就已经是被class-winter混淆的lib的相关信息到当前项目中
|
|
|
collectAlreadyProtectedLibInfo();
|
|
collectAlreadyProtectedLibInfo();
|
|
|
|
|
|
|
|
- // step8. 与step1项对应,将临时目录还原为原来的lib(此时得到的lib是加密后的)
|
|
|
|
|
|
|
+ // step9. 与step1项对应,将临时目录还原为原来的lib(此时得到的lib是加密后的)
|
|
|
doLibJar();
|
|
doLibJar();
|
|
|
|
|
|
|
|
- // step9. 压缩targetRootDir目录为绝对文件路径名为generatedJarWar的jar(or war)包
|
|
|
|
|
|
|
+ // step10. 压缩targetRootDir目录为绝对文件路径名为generatedJarWar的jar(or war)包
|
|
|
String generatedJarWar = generateJarWarPath(this.originIsJar);
|
|
String generatedJarWar = generateJarWarPath(this.originIsJar);
|
|
|
JarUtil.doJarWar(targetRootDir, generatedJarWar);
|
|
JarUtil.doJarWar(targetRootDir, generatedJarWar);
|
|
|
|
|
|
|
|
- // step10. 删除临时目录
|
|
|
|
|
|
|
+ // step11. 删除临时目录
|
|
|
IOUtil.delete(targetRootDirFile);
|
|
IOUtil.delete(targetRootDirFile);
|
|
|
-
|
|
|
|
|
return generatedJarWar;
|
|
return generatedJarWar;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 清除META-INF/maven下pom.xml中关于class-winter-plugin的相关信息
|
|
|
|
|
+ *
|
|
|
|
|
+ * <p>
|
|
|
|
|
+ *
|
|
|
|
|
+ * <?xml version="1.0" encoding="UTF-8"?>
|
|
|
|
|
+ * <project ...>
|
|
|
|
|
+ *
|
|
|
|
|
+ * ......
|
|
|
|
|
+ *
|
|
|
|
|
+ * <build>
|
|
|
|
|
+ * <plugins>
|
|
|
|
|
+ * // 要把这部分清除 start
|
|
|
|
|
+ * <plugin >
|
|
|
|
|
+ * <groupId>com.idea-aedi</groupId>
|
|
|
|
|
+ * <artifactId>class-winter-maven-plugin</artifactId>
|
|
|
|
|
+ * ...
|
|
|
|
|
+ * </plugin>
|
|
|
|
|
+ * // 要把这部分清除 end
|
|
|
|
|
+ * </plugins>
|
|
|
|
|
+ * </build>
|
|
|
|
|
+ *
|
|
|
|
|
+ * </project>
|
|
|
|
|
+ */
|
|
|
|
|
+ private void clearWinterPluginInfo() {
|
|
|
|
|
+ // 只有调用者是插件时,才去清除pom.xml中的class_winter-plugin插件信息
|
|
|
|
|
+ if (!invokerIsPlugin) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ // 清除META-INF/maven下pom.xml中关于class-winter-plugin的相关信息
|
|
|
|
|
+ IOUtil.listFileOnly(new File(this.targetRootDir, Constant.POM_XML_ROOT), "pom.xml").stream()
|
|
|
|
|
+ .filter(x -> "pom.xml".equals(x.getName())).forEach(pomFile -> {
|
|
|
|
|
+ SAXReader saxReader = new SAXReader();
|
|
|
|
|
+ FileOutputStream fileOutputStream = null;
|
|
|
|
|
+ try {
|
|
|
|
|
+ Document document = saxReader.read(pomFile);
|
|
|
|
|
+ // rootElement就是上面的<project></project>
|
|
|
|
|
+ Element projectElement = document.getRootElement();
|
|
|
|
|
+ if (projectElement == null) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ Element buildElement = projectElement.element("build");
|
|
|
|
|
+ if (buildElement == null) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ Element pluginsElement = buildElement.element("plugins");
|
|
|
|
|
+ if (pluginsElement == null) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
|
|
+ Iterator<Element> iterator = (Iterator<Element>)pluginsElement.elementIterator();
|
|
|
|
|
+ while (iterator.hasNext()) {
|
|
|
|
|
+ Element pluginElement = iterator.next();
|
|
|
|
|
+ Element groupIdElement = pluginElement.element("groupId");
|
|
|
|
|
+ if (groupIdElement == null || groupIdElement.getStringValue() == null
|
|
|
|
|
+ || !Constant.GROUP_ID.equals(groupIdElement.getStringValue().trim())) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ Element artifactIdElement = pluginElement.element("artifactId");
|
|
|
|
|
+ if (artifactIdElement == null || artifactIdElement.getStringValue() == null
|
|
|
|
|
+ || !Constant.ARTIFACT_ID.equals(artifactIdElement.getStringValue().trim())) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ pluginsElement.remove(pluginElement);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 删除原文件
|
|
|
|
|
+ IOUtil.delete(pomFile);
|
|
|
|
|
+ // 再生成
|
|
|
|
|
+ fileOutputStream = new FileOutputStream(pomFile);
|
|
|
|
|
+ XMLWriter xmlwriter = new XMLWriter(fileOutputStream);
|
|
|
|
|
+ xmlwriter.write(document);
|
|
|
|
|
+ xmlwriter.flush();
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ throw new ClassWinterException("Delete class-winter-plugin info at pom.xml fail.", e);
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ IOUtil.close(fileOutputStream);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 采集本来就已经被class-winter混淆了的lib的信息
|
|
* 采集本来就已经被class-winter混淆了的lib的信息
|
|
|
*/
|
|
*/
|
|
@@ -238,8 +334,9 @@ public class EncryptExecutor {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
// 形如: META-INF/winter/abc-1.0.0_jar/
|
|
// 形如: META-INF/winter/abc-1.0.0_jar/
|
|
|
- String dirRelativePathForLib = Constant.DEFAULT_ENCRYPTED_CLASSES_SAVE_DIR + libJarName.substring(0, libJarName.length() - 4) + "_jar" + Constant.LINUX_FILE_SEPARATOR;
|
|
|
|
|
- String dirAbsolutePathForLib = this.targetRootDir + File.separator + Constant.DEFAULT_ENCRYPTED_CLASSES_SAVE_DIR + libJarName.substring(0, libJarName.length() - 4) + "_jar" + File.separator;
|
|
|
|
|
|
|
+ String nonSuffixLibName = libJarName.substring(0, libJarName.length() - 4);
|
|
|
|
|
+ String dirRelativePathForLib = Constant.MANIFEST_FILE + nonSuffixLibName + "_jar" + Constant.LINUX_FILE_SEPARATOR;
|
|
|
|
|
+ String dirAbsolutePathForLib = this.targetRootDir + File.separator + Constant.MANIFEST_FILE + nonSuffixLibName + "_jar" + File.separator;
|
|
|
|
|
|
|
|
/*
|
|
/*
|
|
|
* my-project依赖的lib包本身可以是被class-winter混淆后的,但是这个lib包依赖的lib包不能是被class-winter混淆后
|
|
* my-project依赖的lib包本身可以是被class-winter混淆后的,但是这个lib包依赖的lib包不能是被class-winter混淆后
|
|
@@ -269,7 +366,7 @@ public class EncryptExecutor {
|
|
|
String[] libClassesArr = libChecklist.split(",");
|
|
String[] libClassesArr = libChecklist.split(",");
|
|
|
byte[] libClazzByte;
|
|
byte[] libClazzByte;
|
|
|
for (String nonSuffixClassLongName : libClassesArr) {
|
|
for (String nonSuffixClassLongName : libClassesArr) {
|
|
|
- libClazzByte = IOUtil.readFileFromWorkbenchRoot(lib, Constant.DEFAULT_ENCRYPTED_CLASSES_SAVE_DIR + nonSuffixClassLongName);
|
|
|
|
|
|
|
+ libClazzByte = IOUtil.readFileFromWorkbenchRoot(lib, Constant.MANIFEST_FILE + nonSuffixClassLongName);
|
|
|
IOUtil.toFile(libClazzByte, new File(dirAbsolutePathForLib, nonSuffixClassLongName), true);
|
|
IOUtil.toFile(libClazzByte, new File(dirAbsolutePathForLib, nonSuffixClassLongName), true);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -305,7 +402,7 @@ public class EncryptExecutor {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
// 存时,加密存进去
|
|
// 存时,加密存进去
|
|
|
- String encryptedPassword =EncryptUtil.encrypt(password, Cache.sealCache.toCharArray());
|
|
|
|
|
|
|
+ String encryptedPassword =EncryptUtil.encrypt(password, Constant.SEAL.toCharArray());
|
|
|
IOUtil.writeContentToFile(encryptedPassword, new File(dirAbsolutePathForLib, Constant.PWD_WINTER_SIMPLE_NAME));
|
|
IOUtil.writeContentToFile(encryptedPassword, new File(dirAbsolutePathForLib, Constant.PWD_WINTER_SIMPLE_NAME));
|
|
|
// 由于这里已经处理了,将所有lib的密码(不论当初加密lib时密码是用户主动输入的还是系统自动产生的),都当做系统自动产生的进行录入,所以这里写死为false
|
|
// 由于这里已经处理了,将所有lib的密码(不论当初加密lib时密码是用户主动输入的还是系统自动产生的),都当做系统自动产生的进行录入,所以这里写死为false
|
|
|
IOUtil.writeContentToFile("false", new File(dirAbsolutePathForLib, Constant.USER_IF_INPUT_PWD_SIMPLE_NAME));
|
|
IOUtil.writeContentToFile("false", new File(dirAbsolutePathForLib, Constant.USER_IF_INPUT_PWD_SIMPLE_NAME));
|
|
@@ -358,6 +455,13 @@ public class EncryptExecutor {
|
|
|
libJarAndTmpDirMap.put(jarAbsolutePath, temDir);
|
|
libJarAndTmpDirMap.put(jarAbsolutePath, temDir);
|
|
|
// 删除原来的lib包
|
|
// 删除原来的lib包
|
|
|
IOUtil.delete(new File(jarAbsolutePath));
|
|
IOUtil.delete(new File(jarAbsolutePath));
|
|
|
|
|
+ // 擦除MANIFEST.MF中的Premain-Class信息, 如果有的话
|
|
|
|
|
+ File jarManifestFile = new File(temDir, Constant.MANIFEST_FILE);
|
|
|
|
|
+ if (jarManifestFile.exists()) {
|
|
|
|
|
+ String content = IOUtil.readContentFromFile(jarManifestFile);
|
|
|
|
|
+ content = content.replace("Premain-Class: " + Reverses.class.getName(), "");
|
|
|
|
|
+ IOUtil.writeContentToFile(content, jarManifestFile);
|
|
|
|
|
+ }
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -673,7 +777,6 @@ public class EncryptExecutor {
|
|
|
return this;
|
|
return this;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-
|
|
|
|
|
public Builder supportFile(String supportFile) {
|
|
public Builder supportFile(String supportFile) {
|
|
|
this.supportFile = supportFile;
|
|
this.supportFile = supportFile;
|
|
|
return this;
|
|
return this;
|