mirror of
https://github.com/GravitLauncher/Launcher
synced 2025-04-04 15:31:53 +03:00
ClassWriter hierarchy...
This commit is contained in:
parent
d6049e71c0
commit
ed00a3778f
9 changed files with 279 additions and 63 deletions
|
@ -40,8 +40,8 @@ public ProguardConf(LaunchServer srv) {
|
||||||
prepare(false);
|
prepare(false);
|
||||||
if (srv.config.genMappings) confStrs.add("-printmapping \'" + mappings.toFile().getName() + "\'");
|
if (srv.config.genMappings) confStrs.add("-printmapping \'" + mappings.toFile().getName() + "\'");
|
||||||
confStrs.add("-obfuscationdictionary \'" + words.toFile().getName() + "\'");
|
confStrs.add("-obfuscationdictionary \'" + words.toFile().getName() + "\'");
|
||||||
confStrs.add("-injar \'" + srv.dir.toAbsolutePath() + IOHelper.PLATFORM_SEPARATOR + srv.config.binaryName + ".jar\'");
|
confStrs.add("-injar \'" + srv.dir.toAbsolutePath() + IOHelper.PLATFORM_SEPARATOR + srv.config.binaryName + "-nonObf.jar\'");
|
||||||
confStrs.add("-outjar \'" + srv.dir.toAbsolutePath() + IOHelper.PLATFORM_SEPARATOR + srv.config.binaryName + "-obf.jar\'");
|
confStrs.add("-outjar \'" + srv.dir.toAbsolutePath() + IOHelper.PLATFORM_SEPARATOR + srv.config.binaryName + "-obfed.jar\'");
|
||||||
confStrs.add("-classobfuscationdictionary \'" + words.toFile().getName() + "\'");
|
confStrs.add("-classobfuscationdictionary \'" + words.toFile().getName() + "\'");
|
||||||
confStrs.add(readConf());
|
confStrs.add(readConf());
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
package ru.gravit.launchserver.asm;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.jar.JarFile;
|
||||||
|
|
||||||
|
import org.objectweb.asm.ClassReader;
|
||||||
|
import org.objectweb.asm.ClassVisitor;
|
||||||
|
import org.objectweb.asm.Opcodes;
|
||||||
|
|
||||||
|
import ru.gravit.utils.helper.IOHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Позволяет искать методы внутри незагруженных классов и общие суперклассы для
|
||||||
|
* чего угодно. Работает через поиск class-файлов в classpath.
|
||||||
|
*/
|
||||||
|
public class ClassMetadataReader {
|
||||||
|
private class CheckSuperClassVisitor extends ClassVisitor {
|
||||||
|
|
||||||
|
String superClassName;
|
||||||
|
|
||||||
|
public CheckSuperClassVisitor() {
|
||||||
|
super(Opcodes.ASM5);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(int version, int access, String name, String signature, String superName,
|
||||||
|
String[] interfaces) {
|
||||||
|
superClassName = superName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final List<JarFile> cp;
|
||||||
|
|
||||||
|
public ClassMetadataReader(List<JarFile> cp) {
|
||||||
|
this.cp = cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<JarFile> getCp() {
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassMetadataReader() {
|
||||||
|
this.cp = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void acceptVisitor(byte[] classData, ClassVisitor visitor) {
|
||||||
|
new ClassReader(classData).accept(visitor, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void acceptVisitor(String className, ClassVisitor visitor) throws IOException {
|
||||||
|
acceptVisitor(getClassData(className), visitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getClassData(String className) throws IOException {
|
||||||
|
for (JarFile f : cp) {
|
||||||
|
if (f.getEntry(className + ".class") != null) try (InputStream in = f.getInputStream(f.getEntry(className + ".class"))) { return IOHelper.read(in); }
|
||||||
|
}
|
||||||
|
return IOHelper.read(IOHelper.getResourceURL(className + ".class"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSuperClass(String type) {
|
||||||
|
if (type.equals("java/lang/Object")) return null;
|
||||||
|
try {
|
||||||
|
return getSuperClassASM(type);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return "java/lang/Object";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getSuperClassASM(String type) throws IOException {
|
||||||
|
CheckSuperClassVisitor cv = new CheckSuperClassVisitor();
|
||||||
|
acceptVisitor(type, cv);
|
||||||
|
return cv.superClassName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает суперклассы в порядке возрастающей конкретности (начиная с
|
||||||
|
* java/lang/Object и заканчивая данным типом)
|
||||||
|
*/
|
||||||
|
public ArrayList<String> getSuperClasses(String type) {
|
||||||
|
ArrayList<String> superclasses = new ArrayList<>(1);
|
||||||
|
superclasses.add(type);
|
||||||
|
while ((type = getSuperClass(type)) != null)
|
||||||
|
superclasses.add(type);
|
||||||
|
Collections.reverse(superclasses);
|
||||||
|
return superclasses;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package ru.gravit.launchserver.asm;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import org.objectweb.asm.ClassReader;
|
||||||
|
import org.objectweb.asm.ClassWriter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClassWriter с другой реализацией метода getCommonSuperClass: при его
|
||||||
|
* использовании не происходит загрузки классов.
|
||||||
|
*/
|
||||||
|
public class SafeClassWriter extends ClassWriter {
|
||||||
|
|
||||||
|
private final ClassMetadataReader classMetadataReader;
|
||||||
|
|
||||||
|
public SafeClassWriter(ClassMetadataReader classMetadataReader, int flags) {
|
||||||
|
super(flags);
|
||||||
|
this.classMetadataReader = classMetadataReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SafeClassWriter(ClassReader classReader, ClassMetadataReader classMetadataReader, int flags) {
|
||||||
|
super(classReader, flags);
|
||||||
|
this.classMetadataReader = classMetadataReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getCommonSuperClass(String type1, String type2) {
|
||||||
|
ArrayList<String> superClasses1 = classMetadataReader.getSuperClasses(type1);
|
||||||
|
ArrayList<String> superClasses2 = classMetadataReader.getSuperClasses(type2);
|
||||||
|
int size = Math.min(superClasses1.size(), superClasses2.size());
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < size && superClasses1.get(i).equals(superClasses2.get(i)); i++)
|
||||||
|
;
|
||||||
|
if (i == 0)
|
||||||
|
return "java/lang/Object";
|
||||||
|
else
|
||||||
|
return superClasses1.get(i - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
package ru.gravit.launchserver.auth.hwid;
|
package ru.gravit.launchserver.auth.hwid;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import ru.gravit.launcher.HWID;
|
import ru.gravit.launcher.HWID;
|
||||||
|
|
|
@ -5,17 +5,19 @@
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.jar.JarInputStream;
|
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipInputStream;
|
||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
public class BuildContext {
|
public class BuildContext {
|
||||||
public final ZipOutputStream output;
|
public final ZipOutputStream output;
|
||||||
public final JAConfigurator config;
|
public final JAConfigurator config;
|
||||||
|
public final JARLauncherBinary data;
|
||||||
|
|
||||||
public BuildContext(ZipOutputStream output, JAConfigurator config) {
|
public BuildContext(ZipOutputStream output, JAConfigurator config, JARLauncherBinary data) {
|
||||||
this.output = output;
|
this.output = output;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void pushFile(String filename, InputStream inputStream) throws IOException {
|
public void pushFile(String filename, InputStream inputStream) throws IOException {
|
||||||
|
@ -24,7 +26,7 @@ public void pushFile(String filename, InputStream inputStream) throws IOExceptio
|
||||||
IOHelper.transfer(inputStream, output);
|
IOHelper.transfer(inputStream, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void pushJarFile(JarInputStream input) throws IOException {
|
public void pushJarFile(ZipInputStream input) throws IOException {
|
||||||
ZipEntry e = input.getNextEntry();
|
ZipEntry e = input.getNextEntry();
|
||||||
while (e != null) {
|
while (e != null) {
|
||||||
output.putNextEntry(e);
|
output.putNextEntry(e);
|
||||||
|
@ -33,7 +35,7 @@ public void pushJarFile(JarInputStream input) throws IOException {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void pushJarFile(JarInputStream input, Set<String> blacklist) throws IOException {
|
public void pushJarFile(ZipInputStream input, Set<String> blacklist) throws IOException {
|
||||||
ZipEntry e = input.getNextEntry();
|
ZipEntry e = input.getNextEntry();
|
||||||
while (e != null) {
|
while (e != null) {
|
||||||
if (blacklist.contains(e.getName())) {
|
if (blacklist.contains(e.getName())) {
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
import java.util.jar.JarFile;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipException;
|
import java.util.zip.ZipException;
|
||||||
|
@ -22,13 +23,15 @@
|
||||||
import ru.gravit.launcher.Launcher;
|
import ru.gravit.launcher.Launcher;
|
||||||
import ru.gravit.launcher.LauncherConfig;
|
import ru.gravit.launcher.LauncherConfig;
|
||||||
import ru.gravit.utils.helper.CommonHelper;
|
import ru.gravit.utils.helper.CommonHelper;
|
||||||
import ru.gravit.utils.helper.EnvHelper;
|
|
||||||
import ru.gravit.utils.helper.IOHelper;
|
import ru.gravit.utils.helper.IOHelper;
|
||||||
import ru.gravit.utils.helper.LogHelper;
|
import ru.gravit.utils.helper.LogHelper;
|
||||||
import ru.gravit.utils.helper.SecurityHelper;
|
import ru.gravit.utils.helper.SecurityHelper;
|
||||||
import ru.gravit.utils.helper.SecurityHelper.DigestAlgorithm;
|
import ru.gravit.utils.helper.SecurityHelper.DigestAlgorithm;
|
||||||
|
import ru.gravit.utils.helper.UnpackHelper;
|
||||||
import ru.gravit.launcher.serialize.HOutput;
|
import ru.gravit.launcher.serialize.HOutput;
|
||||||
import ru.gravit.launchserver.LaunchServer;
|
import ru.gravit.launchserver.LaunchServer;
|
||||||
|
import ru.gravit.launchserver.asm.ClassMetadataReader;
|
||||||
|
import ru.gravit.launchserver.manangers.BuildHookManager.ZipBuildHook;
|
||||||
import proguard.Configuration;
|
import proguard.Configuration;
|
||||||
import proguard.ConfigurationParser;
|
import proguard.ConfigurationParser;
|
||||||
import proguard.ParseException;
|
import proguard.ParseException;
|
||||||
|
@ -36,8 +39,6 @@
|
||||||
|
|
||||||
public final class JARLauncherBinary extends LauncherBinary {
|
public final class JARLauncherBinary extends LauncherBinary {
|
||||||
|
|
||||||
public static final String[] guardFileList = {"Avanguard64.dll", "Avanguard32.dll", "wrapper64.exe", "wrapper32.exe"};
|
|
||||||
|
|
||||||
private final class RuntimeDirVisitor extends SimpleFileVisitor<Path> {
|
private final class RuntimeDirVisitor extends SimpleFileVisitor<Path> {
|
||||||
private final ZipOutputStream output;
|
private final ZipOutputStream output;
|
||||||
private final Map<String, byte[]> runtime;
|
private final Map<String, byte[]> runtime;
|
||||||
|
@ -68,7 +69,8 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class GuardDirVisitor extends SimpleFileVisitor<Path> {
|
@SuppressWarnings("unused")
|
||||||
|
private final class GuardDirVisitor extends SimpleFileVisitor<Path> {
|
||||||
private final ZipOutputStream output;
|
private final ZipOutputStream output;
|
||||||
private final Map<String, byte[]> guard;
|
private final Map<String, byte[]> guard;
|
||||||
|
|
||||||
|
@ -106,25 +108,28 @@ private static ZipEntry newGuardEntry(String fileName) {
|
||||||
return newZipEntry(Launcher.GUARD_DIR + IOHelper.CROSS_SEPARATOR + fileName);
|
return newZipEntry(Launcher.GUARD_DIR + IOHelper.CROSS_SEPARATOR + fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final Path cleanJar;
|
||||||
public final Path runtimeDir;
|
public final Path runtimeDir;
|
||||||
public final Path guardDir;
|
public final Path guardDir;
|
||||||
|
|
||||||
|
|
||||||
public final Path initScriptFile;
|
public final Path initScriptFile;
|
||||||
|
|
||||||
|
|
||||||
public final Path obfJar;
|
public final Path obfJar;
|
||||||
|
public final Path obfOutJar;
|
||||||
|
public ClassMetadataReader reader;
|
||||||
|
|
||||||
public JARLauncherBinary(LaunchServer server) throws IOException {
|
public JARLauncherBinary(LaunchServer server) throws IOException {
|
||||||
super(server, server.dir.resolve(server.config.binaryName + ".jar"),
|
super(server, server.dir.resolve(server.config.binaryName + "-nonObf.jar"),
|
||||||
server.dir.resolve(server.config.binaryName + "-obf.jar"));
|
server.dir.resolve(server.config.binaryName + ".jar"));
|
||||||
runtimeDir = server.dir.resolve(Launcher.RUNTIME_DIR);
|
runtimeDir = server.dir.resolve(Launcher.RUNTIME_DIR);
|
||||||
guardDir = server.dir.resolve("guard");
|
guardDir = server.dir.resolve(Launcher.GUARD_DIR);
|
||||||
initScriptFile = runtimeDir.resolve(Launcher.INIT_SCRIPT_FILE);
|
initScriptFile = runtimeDir.resolve(Launcher.INIT_SCRIPT_FILE);
|
||||||
obfJar = syncBinaryFile;
|
obfJar = server.dir.resolve(server.config.binaryName + "-obfed.jar");
|
||||||
|
obfOutJar = server.config.buildPostTransform.enabled ? server.dir.resolve(server.config.binaryName + "-obf.jar") : syncBinaryFile;
|
||||||
|
cleanJar = server.dir.resolve(server.config.binaryName + "-clean.jar");
|
||||||
|
reader = new ClassMetadataReader();
|
||||||
|
UnpackHelper.unpack(IOHelper.getResourceURL("Launcher.jar"), cleanJar);
|
||||||
|
reader.getCp().add(new JarFile(cleanJar.toFile()));
|
||||||
tryUnpackRuntime();
|
tryUnpackRuntime();
|
||||||
|
tryUnpackGuard();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -148,13 +153,10 @@ public void build() throws IOException {
|
||||||
} catch (ParseException e1) {
|
} catch (ParseException e1) {
|
||||||
e1.printStackTrace();
|
e1.printStackTrace();
|
||||||
}
|
}
|
||||||
|
for (Runnable r : server.buildHookManager.getPostProguardRunHooks()) r.run();
|
||||||
if (server.buildHookManager.isNeedPostProguardHook()) {
|
if (server.buildHookManager.isNeedPostProguardHook()) {
|
||||||
Path obfPath = Paths.get(server.config.binaryName + "-obf.jar");
|
try (ZipInputStream input = new ZipInputStream(
|
||||||
Path tmpPath = Paths.get(server.config.binaryName + "-tmp.jar");
|
IOHelper.newInput(obfJar)); ZipOutputStream output = new ZipOutputStream(IOHelper.newOutput(obfOutJar))) {
|
||||||
IOHelper.move(obfPath, tmpPath);
|
|
||||||
try (ZipOutputStream output = new ZipOutputStream(IOHelper.newOutput(obfPath))) {
|
|
||||||
try (ZipInputStream input = new ZipInputStream(
|
|
||||||
IOHelper.newInput(tmpPath))) {
|
|
||||||
ZipEntry e = input.getNextEntry();
|
ZipEntry e = input.getNextEntry();
|
||||||
while (e != null) {
|
while (e != null) {
|
||||||
String filename = e.getName();
|
String filename = e.getName();
|
||||||
|
@ -167,23 +169,25 @@ public void build() throws IOException {
|
||||||
IOHelper.transfer(input, outputStream);
|
IOHelper.transfer(input, outputStream);
|
||||||
bytes = outputStream.toByteArray();
|
bytes = outputStream.toByteArray();
|
||||||
}
|
}
|
||||||
bytes = server.buildHookManager.proGuardClassTransform(bytes, classname);
|
bytes = server.buildHookManager.proGuardClassTransform(bytes, classname, this);
|
||||||
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes)) {
|
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes)) {
|
||||||
IOHelper.transfer(inputStream, output);
|
IOHelper.transfer(inputStream, output);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
IOHelper.transfer(input, output);
|
IOHelper.transfer(input, output);
|
||||||
e = input.getNextEntry();
|
e = input.getNextEntry();
|
||||||
}
|
}
|
||||||
}
|
for (ZipBuildHook h : server.buildHookManager.getProguardBuildHooks()) h.build(output);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
IOHelper.move(obfJar, obfOutJar);
|
||||||
}
|
}
|
||||||
//if (server.config.buildPostTransform.enabled)
|
if (server.config.buildPostTransform.enabled)
|
||||||
// transformedBuild();
|
transformedBuild();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void transformedBuild() throws IOException {
|
private void transformedBuild() throws IOException {
|
||||||
String cmd = CommonHelper.replace(server.config.buildPostTransform.script, "launcher-output", IOHelper.toAbsPathString(syncBinaryFile), "launcher-obf", IOHelper.toAbsPathString(obfJar), "launcher-nonObf", IOHelper.toAbsPathString(binaryFile));
|
String cmd = CommonHelper.replace(server.config.buildPostTransform.script, "launcher-output", IOHelper.toAbsPathString(syncBinaryFile), "launcher-obf", IOHelper.toAbsPathString(obfOutJar), "launcher-nonObf", IOHelper.toAbsPathString(binaryFile));
|
||||||
ProcessBuilder builder = new ProcessBuilder();
|
ProcessBuilder builder = new ProcessBuilder();
|
||||||
builder.directory(IOHelper.toAbsPath(server.dir).toFile());
|
builder.directory(IOHelper.toAbsPath(server.dir).toFile());
|
||||||
builder.inheritIO();
|
builder.inheritIO();
|
||||||
|
@ -203,7 +207,7 @@ private void transformedBuild() throws IOException {
|
||||||
private void stdBuild() throws IOException {
|
private void stdBuild() throws IOException {
|
||||||
try (ZipOutputStream output = new ZipOutputStream(IOHelper.newOutput(binaryFile));
|
try (ZipOutputStream output = new ZipOutputStream(IOHelper.newOutput(binaryFile));
|
||||||
JAConfigurator jaConfigurator = new JAConfigurator(AutogenConfig.class)) {
|
JAConfigurator jaConfigurator = new JAConfigurator(AutogenConfig.class)) {
|
||||||
BuildContext context = new BuildContext(output, jaConfigurator);
|
BuildContext context = new BuildContext(output, jaConfigurator, this);
|
||||||
server.buildHookManager.preHook(context);
|
server.buildHookManager.preHook(context);
|
||||||
jaConfigurator.setAddress(server.config.getAddress());
|
jaConfigurator.setAddress(server.config.getAddress());
|
||||||
jaConfigurator.setPort(server.config.port);
|
jaConfigurator.setPort(server.config.port);
|
||||||
|
@ -214,7 +218,7 @@ private void stdBuild() throws IOException {
|
||||||
jaConfigurator.setDownloadJava(server.config.isDownloadJava);
|
jaConfigurator.setDownloadJava(server.config.isDownloadJava);
|
||||||
server.buildHookManager.registerAllClientModuleClass(jaConfigurator);
|
server.buildHookManager.registerAllClientModuleClass(jaConfigurator);
|
||||||
try (ZipInputStream input = new ZipInputStream(
|
try (ZipInputStream input = new ZipInputStream(
|
||||||
IOHelper.newInput(IOHelper.getResourceURL("Launcher.jar")))) {
|
IOHelper.newInput(cleanJar))) {
|
||||||
ZipEntry e = input.getNextEntry();
|
ZipEntry e = input.getNextEntry();
|
||||||
while (e != null) {
|
while (e != null) {
|
||||||
String filename = e.getName();
|
String filename = e.getName();
|
||||||
|
@ -237,20 +241,19 @@ private void stdBuild() throws IOException {
|
||||||
IOHelper.transfer(input, outputStream);
|
IOHelper.transfer(input, outputStream);
|
||||||
bytes = outputStream.toByteArray();
|
bytes = outputStream.toByteArray();
|
||||||
}
|
}
|
||||||
bytes = server.buildHookManager.classTransform(bytes, classname);
|
bytes = server.buildHookManager.classTransform(bytes, classname, this);
|
||||||
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes)) {
|
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes)) {
|
||||||
IOHelper.transfer(inputStream, output);
|
IOHelper.transfer(inputStream, output);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
IOHelper.transfer(input, output);
|
IOHelper.transfer(input, output);
|
||||||
// }
|
|
||||||
e = input.getNextEntry();
|
e = input.getNextEntry();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// write additional classes
|
// write additional classes
|
||||||
for (Entry<String, byte[]> ent : server.buildHookManager.getIncludeClass().entrySet()) {
|
for (Entry<String, byte[]> ent : server.buildHookManager.getIncludeClass().entrySet()) {
|
||||||
output.putNextEntry(newZipEntry(ent.getKey().replace('.', '/').concat(".class")));
|
output.putNextEntry(newZipEntry(ent.getKey().replace('.', '/').concat(".class")));
|
||||||
output.write(server.buildHookManager.classTransform(ent.getValue(), ent.getKey()));
|
output.write(server.buildHookManager.classTransform(ent.getValue(), ent.getKey(), this));
|
||||||
}
|
}
|
||||||
// map for guard
|
// map for guard
|
||||||
Map<String, byte[]> runtime = new HashMap<>(256);
|
Map<String, byte[]> runtime = new HashMap<>(256);
|
||||||
|
|
|
@ -10,10 +10,10 @@
|
||||||
|
|
||||||
public abstract class LauncherBinary {
|
public abstract class LauncherBinary {
|
||||||
|
|
||||||
protected final LaunchServer server;
|
public final LaunchServer server;
|
||||||
|
|
||||||
protected final Path binaryFile;
|
public final Path binaryFile;
|
||||||
protected final Path syncBinaryFile;
|
public final Path syncBinaryFile;
|
||||||
private volatile DigestBytesHolder binary;
|
private volatile DigestBytesHolder binary;
|
||||||
private volatile byte[] sign;
|
private volatile byte[] sign;
|
||||||
|
|
||||||
|
|
|
@ -4,41 +4,49 @@
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
import ru.gravit.launcher.AutogenConfig;
|
import ru.gravit.launcher.AutogenConfig;
|
||||||
import ru.gravit.launcher.modules.TestClientModule;
|
import ru.gravit.launcher.modules.TestClientModule;
|
||||||
import ru.gravit.launchserver.binary.BuildContext;
|
import ru.gravit.launchserver.binary.BuildContext;
|
||||||
import ru.gravit.launchserver.binary.JAConfigurator;
|
import ru.gravit.launchserver.binary.JAConfigurator;
|
||||||
|
import ru.gravit.launchserver.binary.JARLauncherBinary;
|
||||||
|
|
||||||
public class BuildHookManager {
|
public class BuildHookManager {
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface PostBuildHook {
|
public static interface ZipBuildHook {
|
||||||
|
void build(ZipOutputStream context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public static interface BuildHook {
|
||||||
void build(BuildContext context);
|
void build(BuildContext context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface PreBuildHook {
|
public static interface Transformer {
|
||||||
void build(BuildContext context);
|
byte[] transform(byte[] input, CharSequence classname, JARLauncherBinary data);
|
||||||
}
|
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
public interface Transformer {
|
|
||||||
byte[] transform(byte[] input, CharSequence classname);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean BUILDRUNTIME;
|
private boolean BUILDRUNTIME;
|
||||||
private final Set<PostBuildHook> POST_HOOKS;
|
private final Set<BuildHook> POST_HOOKS;
|
||||||
|
private final Set<Runnable> POST_PROGUARDRUN_HOOKS;
|
||||||
private final Set<Transformer> POST_PROGUARD_HOOKS;
|
private final Set<Transformer> POST_PROGUARD_HOOKS;
|
||||||
private final Set<PreBuildHook> PRE_HOOKS;
|
private final Set<BuildHook> PRE_HOOKS;
|
||||||
|
private final Set<ZipBuildHook> POST_PROGUARD_BUILDHOOKS;
|
||||||
private final Set<Transformer> CLASS_TRANSFORMER;
|
private final Set<Transformer> CLASS_TRANSFORMER;
|
||||||
private final Set<String> CLASS_BLACKLIST;
|
private final Set<String> CLASS_BLACKLIST;
|
||||||
private final Set<String> MODULE_CLASS;
|
private final Set<String> MODULE_CLASS;
|
||||||
private final Map<String, byte[]> INCLUDE_CLASS;
|
private final Map<String, byte[]> INCLUDE_CLASS;
|
||||||
|
private final NodeTransformer noder;
|
||||||
|
private final NodeTransformer proguardNoder;
|
||||||
|
|
||||||
public BuildHookManager() {
|
public BuildHookManager() {
|
||||||
POST_HOOKS = new HashSet<>(4);
|
POST_HOOKS = new HashSet<>(4);
|
||||||
|
POST_PROGUARDRUN_HOOKS = new HashSet<>(4);
|
||||||
POST_PROGUARD_HOOKS = new HashSet<>(4);
|
POST_PROGUARD_HOOKS = new HashSet<>(4);
|
||||||
PRE_HOOKS = new HashSet<>(4);
|
PRE_HOOKS = new HashSet<>(4);
|
||||||
|
POST_PROGUARD_BUILDHOOKS = new HashSet<>(4);
|
||||||
CLASS_BLACKLIST = new HashSet<>(4);
|
CLASS_BLACKLIST = new HashSet<>(4);
|
||||||
MODULE_CLASS = new HashSet<>(4);
|
MODULE_CLASS = new HashSet<>(4);
|
||||||
INCLUDE_CLASS = new HashMap<>(4);
|
INCLUDE_CLASS = new HashMap<>(4);
|
||||||
|
@ -49,9 +57,37 @@ public BuildHookManager() {
|
||||||
registerIgnoredClass("META-INF/LICENSE");
|
registerIgnoredClass("META-INF/LICENSE");
|
||||||
registerIgnoredClass("META-INF/NOTICE");
|
registerIgnoredClass("META-INF/NOTICE");
|
||||||
registerClientModuleClass(TestClientModule.class.getName());
|
registerClientModuleClass(TestClientModule.class.getName());
|
||||||
|
noder = new NodeTransformer();
|
||||||
|
registerClassTransformer(noder);
|
||||||
|
proguardNoder = new NodeTransformer();
|
||||||
|
registerProGuardHook(proguardNoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void autoRegisterIgnoredClass(String clazz) {
|
public NodeTransformer getProguardNoder() {
|
||||||
|
return proguardNoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NodeTransformer getNoder() {
|
||||||
|
return noder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<ZipBuildHook> getProguardBuildHooks() {
|
||||||
|
return POST_PROGUARD_BUILDHOOKS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Runnable> getPostProguardRunHooks() {
|
||||||
|
return POST_PROGUARDRUN_HOOKS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addPostProguardRunHook(Runnable hook) {
|
||||||
|
POST_PROGUARDRUN_HOOKS.add(hook);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addPostProguardRunHook(ZipBuildHook hook) {
|
||||||
|
POST_PROGUARD_BUILDHOOKS.add(hook);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void autoRegisterIgnoredClass(String clazz) {
|
||||||
CLASS_BLACKLIST.add(clazz.replace('.', '/').concat(".class"));
|
CLASS_BLACKLIST.add(clazz.replace('.', '/').concat(".class"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,15 +95,15 @@ public boolean buildRuntime() {
|
||||||
return BUILDRUNTIME;
|
return BUILDRUNTIME;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] classTransform(byte[] clazz, CharSequence classname) {
|
public byte[] classTransform(byte[] clazz, CharSequence classname, JARLauncherBinary reader) {
|
||||||
byte[] result = clazz;
|
byte[] result = clazz;
|
||||||
for (Transformer transformer : CLASS_TRANSFORMER) result = transformer.transform(result, classname);
|
for (Transformer transformer : CLASS_TRANSFORMER) result = transformer.transform(result, classname, reader);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] proGuardClassTransform(byte[] clazz, CharSequence classname) {
|
public byte[] proGuardClassTransform(byte[] clazz, CharSequence classname, JARLauncherBinary reader) {
|
||||||
byte[] result = clazz;
|
byte[] result = clazz;
|
||||||
for (Transformer transformer : POST_PROGUARD_HOOKS) result = transformer.transform(result, classname);
|
for (Transformer transformer : POST_PROGUARD_HOOKS) result = transformer.transform(result, classname, reader);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,15 +116,18 @@ public Map<String, byte[]> getIncludeClass() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isContainsBlacklist(String clazz) {
|
public boolean isContainsBlacklist(String clazz) {
|
||||||
return CLASS_BLACKLIST.contains(clazz);
|
for (String classB : CLASS_BLACKLIST) {
|
||||||
|
if (clazz.startsWith(classB)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void postHook(BuildContext context) {
|
public void postHook(BuildContext context) {
|
||||||
for (PostBuildHook hook : POST_HOOKS) hook.build(context);
|
for (BuildHook hook : POST_HOOKS) hook.build(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void preHook(BuildContext context) {
|
public void preHook(BuildContext context) {
|
||||||
for (PreBuildHook hook : PRE_HOOKS) hook.build(context);
|
for (BuildHook hook : PRE_HOOKS) hook.build(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerAllClientModuleClass(JAConfigurator cfg) {
|
public void registerAllClientModuleClass(JAConfigurator cfg) {
|
||||||
|
@ -107,7 +146,7 @@ public void registerIgnoredClass(String clazz) {
|
||||||
CLASS_BLACKLIST.add(clazz);
|
CLASS_BLACKLIST.add(clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerPostHook(PostBuildHook hook) {
|
public void registerPostHook(BuildHook hook) {
|
||||||
POST_HOOKS.add(hook);
|
POST_HOOKS.add(hook);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,10 +155,10 @@ public void registerProGuardHook(Transformer hook) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isNeedPostProguardHook() {
|
public boolean isNeedPostProguardHook() {
|
||||||
return !POST_PROGUARD_HOOKS.isEmpty();
|
return POST_PROGUARD_HOOKS.size() > 1 || !POST_PROGUARDRUN_HOOKS.isEmpty() || !POST_PROGUARD_BUILDHOOKS.isEmpty() || !proguardNoder.getTransLst().isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerPreHook(PreBuildHook hook) {
|
public void registerPreHook(BuildHook hook) {
|
||||||
PRE_HOOKS.add(hook);
|
PRE_HOOKS.add(hook);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
package ru.gravit.launchserver.manangers;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.objectweb.asm.ClassReader;
|
||||||
|
import org.objectweb.asm.ClassWriter;
|
||||||
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
|
||||||
|
import ru.gravit.launchserver.asm.SafeClassWriter;
|
||||||
|
import ru.gravit.launchserver.binary.JARLauncherBinary;
|
||||||
|
import ru.gravit.launchserver.manangers.BuildHookManager.Transformer;
|
||||||
|
|
||||||
|
public class NodeTransformer implements Transformer {
|
||||||
|
@FunctionalInterface
|
||||||
|
public static interface ClassNodeTransformer {
|
||||||
|
void transform(ClassNode node, CharSequence classname, JARLauncherBinary data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final List<ClassNodeTransformer> transLst;
|
||||||
|
|
||||||
|
public List<ClassNodeTransformer> getTransLst() {
|
||||||
|
return transLst;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NodeTransformer() {
|
||||||
|
transLst = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] transform(byte[] input, CharSequence classname, JARLauncherBinary data) {
|
||||||
|
ClassReader cr = new ClassReader(input);
|
||||||
|
ClassNode cn = new ClassNode();
|
||||||
|
cr.accept(cn, ClassReader.EXPAND_FRAMES);
|
||||||
|
for (ClassNodeTransformer tr : transLst) tr.transform(cn, classname, data);
|
||||||
|
ClassWriter cw = new SafeClassWriter(data.reader, ClassWriter.COMPUTE_MAXS);
|
||||||
|
cn.accept(cw);
|
||||||
|
return cw.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue