Пофиксил ASM. Требуется тест! (#216)

* [FIX] ASM bundling.

* Revert "[FIX] Agent работает."

This reverts commit 76a9c07a48.

* Revert "[FIX] Удалена sm часть LauncherAgent"

This reverts commit 54c7526a66.

* [FIX] Закрываем ресурсы в LauncherAgent.

* [FIX] Не загруженный java.awt.Robot.

* [FIX] getRAM работает на OpenJDK 11+

* [FIX] Жуткий RequestAuthHandler.

* [FIX] Грамматика английского языка в RequestAuthHandler.

* [ANY] Опять RequestAuthHandler ошибки в грамматике.
This commit is contained in:
Zaxar163 2019-04-12 23:22:24 +03:00 committed by Gravit
parent 2180bd989e
commit 75e781d08e
7 changed files with 184 additions and 72 deletions

View file

@ -30,7 +30,8 @@
jar { jar {
dependsOn parent.childProjects.Launcher.tasks.build dependsOn parent.childProjects.Launcher.tasks.build
from { configurations.pack.collect { it.isDirectory() ? it : zipTree(it) } } from { configurations.pack.collect { it.isDirectory() ? it : zipTree(it) } }
from(parent.childProjects.Launcher.tasks.jar.archivePath, parent.childProjects.Launcher.tasks.genRuntimeJS.archivePath) from(parent.childProjects.Launcher.tasks.shadowJar.archivePath)
from(parent.childProjects.Launcher.tasks.genRuntimeJS.archivePath)
manifest.attributes("Main-Class": mainClassName, manifest.attributes("Main-Class": mainClassName,
"Premain-Class": mainAgentName, "Premain-Class": mainAgentName,
"Can-Redefine-Classes": "true", "Can-Redefine-Classes": "true",

View file

@ -1,5 +1,6 @@
package ru.gravit.launchserver.auth.handler; package ru.gravit.launchserver.auth.handler;
import ru.gravit.utils.helper.CommonHelper;
import ru.gravit.utils.helper.IOHelper; import ru.gravit.utils.helper.IOHelper;
import ru.gravit.utils.helper.LogHelper; import ru.gravit.utils.helper.LogHelper;
@ -8,100 +9,78 @@
import java.util.UUID; import java.util.UUID;
public final class RequestAuthHandler extends CachedAuthHandler { public final class RequestAuthHandler extends CachedAuthHandler {
private String url; private String usernameFetch;
private String secretKey; private String uuidFetch;
private String typeLine; private String updateAuth;
private String uuidLine; private String updateServerID;
private String usernameLine;
private String accessTokenLine;
private String serverIDLine;
private String secretKeyLine;
private String TypeFetchByUUID; private String splitSymbol = ":";
private String TypeFetchByUsername; private String goodResponse = "OK";
private String TypeSetAccessTokenAndUUID;
private String TypeSetServerID;
private String splitSymbol;
@Override @Override
public void init() { public void init() {
if (url == null) if (usernameFetch == null)
LogHelper.error("[Verify][AuthHandler] url cannot be null"); LogHelper.error("[Verify][AuthHandler] usernameFetch cannot be null");
if (secretKey == null) if (uuidFetch == null)
LogHelper.error("[Verify][AuthHandler] secretKey cannot be null"); LogHelper.error("[Verify][AuthHandler] uuidFetch cannot be null");
// Default if (updateAuth == null)
if (typeLine == null) LogHelper.error("[Verify][AuthHandler] updateAuth cannot be null");
typeLine = "type"; if (updateServerID == null)
if (uuidLine == null) LogHelper.error("[Verify][AuthHandler] updateServerID cannot be null");
uuidLine = "uuid";
if (usernameLine == null)
usernameLine = "username";
if (accessTokenLine == null)
accessTokenLine = "accessToken";
if (serverIDLine == null)
serverIDLine = "serverID";
if (secretKeyLine == null)
secretKeyLine = "secretKey";
if (TypeFetchByUUID == null)
TypeFetchByUUID = "FetchByUUID";
if (TypeFetchByUsername == null)
TypeFetchByUsername = "FetchByUsername";
if (TypeSetAccessTokenAndUUID == null)
TypeSetAccessTokenAndUUID = "SetAccessTokenAndUUID";
if (TypeSetServerID == null)
TypeSetServerID = "SetServerID";
if (splitSymbol == null)
splitSymbol = ":";
} }
@Override @Override
protected Entry fetchEntry(UUID uuid) throws IOException { protected Entry fetchEntry(UUID uuid) throws IOException {
String response = IOHelper.request(new URL(url + "?" + IOHelper.urlEncode(typeLine) + "=" + TypeFetchByUUID + "&" + secretKeyLine + "=" + IOHelper.urlEncode(secretKey) + "&" + IOHelper.urlEncode(uuidLine) + "=" + IOHelper.urlEncode(uuid.toString()))); String response = IOHelper.request(new URL(CommonHelper.replace(uuidFetch, "uuid", IOHelper.urlEncode(uuid.toString()))));
String[] parts = response.split(splitSymbol); String[] parts = response.split(splitSymbol);
String username = parts[0]; String username = parts[0];
String accessToken = parts[1]; String accessToken = parts[1];
String serverID = parts[2]; String serverID = parts[2];
LogHelper.debug("[AuthHandler] Getted username: " + username); if (LogHelper.isDebugEnabled()) {
LogHelper.debug("[AuthHandler] Getted accessToken: " + accessToken); LogHelper.debug("[AuthHandler] Got username: " + username);
LogHelper.debug("[AuthHandler] Getted serverID: " + serverID); LogHelper.debug("[AuthHandler] Got accessToken: " + accessToken);
LogHelper.debug("[AuthHandler] Getted UUID: " + uuid); LogHelper.debug("[AuthHandler] Got serverID: " + serverID);
return query(uuid, username, accessToken, serverID); LogHelper.debug("[AuthHandler] Got UUID: " + uuid);
}
return new Entry(uuid, username, accessToken, serverID);
} }
@Override @Override
protected Entry fetchEntry(String username) throws IOException { protected Entry fetchEntry(String username) throws IOException {
String response = IOHelper.request(new URL(url + "?" + IOHelper.urlEncode(typeLine) + "=" + TypeFetchByUsername + "&" + secretKeyLine + "=" + IOHelper.urlEncode(secretKey) + "&" + IOHelper.urlEncode(usernameLine) + "=" + IOHelper.urlEncode(username))); String response = IOHelper.request(new URL(CommonHelper.replace(usernameFetch, "user", IOHelper.urlEncode(username))));
String[] parts = response.split(splitSymbol); String[] parts = response.split(splitSymbol);
UUID uuid = UUID.fromString(parts[0]); UUID uuid = UUID.fromString(parts[0]);
String accessToken = parts[1]; String accessToken = parts[1];
String serverID = parts[2]; String serverID = parts[2];
LogHelper.debug("[AuthHandler] Getted username: " + username); if (LogHelper.isDebugEnabled()) {
LogHelper.debug("[AuthHandler] Getted accessToken: " + accessToken); LogHelper.debug("[AuthHandler] Got username: " + username);
LogHelper.debug("[AuthHandler] Getted serverID: " + serverID); LogHelper.debug("[AuthHandler] Got accessToken: " + accessToken);
LogHelper.debug("[AuthHandler] Getted UUID: " + uuid); LogHelper.debug("[AuthHandler] Got serverID: " + serverID);
return query(uuid, username, accessToken, serverID); LogHelper.debug("[AuthHandler] Got UUID: " + uuid);
} }
private Entry query(UUID uuid, String username, String accessToken, String serverID) {
return new Entry(uuid, username, accessToken, serverID); return new Entry(uuid, username, accessToken, serverID);
} }
@Override @Override
protected boolean updateAuth(UUID uuid, String username, String accessToken) throws IOException { protected boolean updateAuth(UUID uuid, String username, String accessToken) throws IOException {
String response = IOHelper.request(new URL(url + "?" + IOHelper.urlEncode(typeLine) + "=" + TypeSetAccessTokenAndUUID + "&" + secretKeyLine + "=" + IOHelper.urlEncode(secretKey) + "&" + IOHelper.urlEncode(uuidLine) + "=" + IOHelper.urlEncode(uuid.toString()) + "&" + IOHelper.urlEncode(accessTokenLine) + "=" + IOHelper.urlEncode(accessToken) + "&" + IOHelper.urlEncode(usernameLine) + "=" + IOHelper.urlEncode(username))); String response = IOHelper.request(new URL(CommonHelper.replace(updateAuth, "user", IOHelper.urlEncode(username), "uuid", IOHelper.urlEncode(uuid.toString()), "token", IOHelper.urlEncode(accessToken))));
if (LogHelper.isDebugEnabled()) {
LogHelper.debug("[AuthHandler] Set accessToken: " + accessToken); LogHelper.debug("[AuthHandler] Set accessToken: " + accessToken);
LogHelper.debug("[AuthHandler] Set UUID: " + uuid); LogHelper.debug("[AuthHandler] Set UUID: " + uuid);
LogHelper.debug("[AuthHandler] For this username: " + username); LogHelper.debug("[AuthHandler] For this username: " + username);
return response.equals("OK"); }
return goodResponse.equals(response);
} }
@Override @Override
protected boolean updateServerID(UUID uuid, String serverID) throws IOException { protected boolean updateServerID(UUID uuid, String serverID) throws IOException {
String response = IOHelper.request(new URL(url + "?" + IOHelper.urlEncode(typeLine) + "=" + TypeSetServerID + "&" + secretKeyLine + "=" + IOHelper.urlEncode(secretKey) + "&" + IOHelper.urlEncode(uuidLine) + "=" + IOHelper.urlEncode(uuid.toString()) + "&" + IOHelper.urlEncode(serverIDLine) + "=" + IOHelper.urlEncode(serverID))); String response = IOHelper.request(new URL(CommonHelper.replace(updateAuth, "serverid", IOHelper.urlEncode(serverID), "uuid", IOHelper.urlEncode(uuid.toString()))));
if (LogHelper.isDebugEnabled()) {
LogHelper.debug("[AuthHandler] Set serverID: " + serverID); LogHelper.debug("[AuthHandler] Set serverID: " + serverID);
LogHelper.debug("[AuthHandler] For this UUID: " + uuid); LogHelper.debug("[AuthHandler] For this UUID: " + uuid);
return response.equals("OK"); }
return goodResponse.equals(response);
} }
@Override @Override

View file

@ -1,3 +1,5 @@
apply plugin: 'com.github.johnrengelman.shadow'
String mainClassName = "ru.gravit.launcher.ClientLauncherWrapper" String mainClassName = "ru.gravit.launcher.ClientLauncherWrapper"
String mainAgentName = "ru.gravit.launcher.LauncherAgent" String mainAgentName = "ru.gravit.launcher.LauncherAgent"
@ -17,7 +19,7 @@
} }
jar { jar {
from { configurations.pack.collect { it.isDirectory() ? it : zipTree(it) } } classifier = 'clean'
manifest.attributes("Main-Class": mainClassName, manifest.attributes("Main-Class": mainClassName,
"Premain-Class": mainAgentName, "Premain-Class": mainAgentName,
"Can-Redefine-Classes": "true", "Can-Redefine-Classes": "true",
@ -25,11 +27,18 @@
"Can-Set-Native-Method-Prefix": "true") "Can-Set-Native-Method-Prefix": "true")
} }
shadowJar {
classifier = null
relocate 'org.objectweb.asm', 'ru.gravit.repackage.org.objectweb.asm'
configurations = [project.configurations.pack]
exclude 'module-info.class'
}
dependencies { dependencies {
pack project(':LauncherAPI') // Not error on obf. pack project(':LauncherAPI') // Not error on obf.
bundle 'com.github.oshi:oshi-core:3.13.0' bundle 'com.github.oshi:oshi-core:3.13.0'
compileOnly 'org.ow2.asm:asm-all:5.0.3'
bundle 'com.jfoenix:jfoenix:8.0.8' bundle 'com.jfoenix:jfoenix:8.0.8'
pack 'org.ow2.asm:asm-tree:7.1'
} }
task genRuntimeJS(type: Zip) { task genRuntimeJS(type: Zip) {
@ -44,4 +53,4 @@ task dumpLibs(type: Copy) {
} }
build.dependsOn tasks.genRuntimeJS, tasks.dumpLibs build.dependsOn tasks.genRuntimeJS, tasks.dumpLibs, tasks.shadowJar

View file

@ -43,9 +43,119 @@ public static void premain(String agentArgument, Instrumentation instrumentation
if (trimmedArg.contains("r")) rt = false; if (trimmedArg.contains("r")) rt = false;
} }
} }
if (rt || pb) replaceClasses(pb, rt);
} }
public static boolean isStarted() { public static boolean isStarted() {
return isAgentStarted; return isAgentStarted;
} }
/**
* @author https://github.com/Konloch/JVM-Sandbox
* Replaces the Runtime class via instrumentation, transforms the class via ASM
*/
private static void replaceClasses(boolean pb, boolean rt) {
java.awt.Robot.class.getName();
for(Class<?> c : inst.getAllLoadedClasses()) {
if(rt && c.getName().equals("java.lang.Runtime")) {
try {
inst.redefineClasses(new java.lang.instrument.ClassDefinition(java.lang.Runtime.class, transformClass(c.getName(), getClassFile(c))));
} catch(Exception e) {
e.printStackTrace();
}
}
if(pb && c.getName().equals("java.lang.ProcessBuilder")) {
try {
inst.redefineClasses(new java.lang.instrument.ClassDefinition(java.lang.ProcessBuilder.class, transformClass(c.getName(), getClassFile(c))));
} catch(Exception e) {
e.printStackTrace();
}
}
if(c.getName().equals("java.awt.Robot")) {
try {
inst.redefineClasses(new java.lang.instrument.ClassDefinition(java.lang.ProcessBuilder.class, transformClass(c.getName(), getClassFile(c))));
} catch(Exception e) {
e.printStackTrace();
}
}
}
}
/**
* @author https://github.com/Konloch/JVM-Sandbox
* Use ASM to modify the byte array
*/
private static byte[] transformClass(String className, byte[] classBytes) {
if (className.equals("java.lang.Runtime")) {
ClassReader cr=new ClassReader(classBytes);
ClassNode cn=new ClassNode();
cr.accept(cn,ClassReader.EXPAND_FRAMES);
for (Object o : cn.methods.toArray()) {
MethodNode m = (MethodNode) o;
if(m.name.equals("exec")) {
m.instructions.insert(new InsnNode(ARETURN));
m.instructions.insert(new InsnNode(ACONST_NULL));
}
}
ClassWriter cw=new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
cn.accept(cw);
return cw.toByteArray();
} else if (className.equals("java.lang.ProcessBuilder")) {
ClassReader cr=new ClassReader(classBytes);
ClassNode cn=new ClassNode();
cr.accept(cn,ClassReader.EXPAND_FRAMES);
for (Object o : cn.methods.toArray()) {
MethodNode m = (MethodNode) o;
if(m.name.equals("start")) {
m.instructions.insert(new InsnNode(ARETURN));
m.instructions.insert(new InsnNode(ACONST_NULL));
}
}
ClassWriter cw=new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
cn.accept(cw);
return cw.toByteArray();
} else if (className.equals("java.awt.Robot")) {
ClassReader cr=new ClassReader(classBytes);
ClassNode cn=new ClassNode();
cr.accept(cn,ClassReader.EXPAND_FRAMES);
for (Object o : cn.methods.toArray()) {
MethodNode m = (MethodNode) o;
if( m.name.equals("createScreenCapture") || m.name.equals("getPixelColor") ||
m.name.equals("keyPress") || m.name.equals("keyRelease") ||
m.name.equals("mouseMove") || m.name.equals("mousePress") ||
m.name.equals("mouseWheel"))
{
m.instructions.insert(new InsnNode(ARETURN));
m.instructions.insert(new InsnNode(ACONST_NULL));
}
}
ClassWriter cw=new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
cn.accept(cw);
return cw.toByteArray();
}
return classBytes;
}
/**
* @author https://github.com/Konloch/JVM-Sandbox
* Do not remove this method. Do not to cause classloading!
* Grab the byte array from the loaded Class object
* @param clazz
* @return array, respending this class in bytecode.
* @throws IOException
*/
private static byte[] getClassFile(Class<?> clazz) throws IOException {
try (InputStream is = clazz.getResourceAsStream( "/" + clazz.getName().replace('.', '/') + ".class");
ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
int r = 0;
byte[] buffer = new byte[8192];
while((r=is.read(buffer))>=0) {
baos.write(buffer, 0, r);
}
return baos.toByteArray();
}
}
} }

View file

@ -355,7 +355,7 @@ public static Process launch(
Collections.addAll(context.args, profile.getJvmArgs()); Collections.addAll(context.args, profile.getJvmArgs());
profile.pushOptionalJvmArgs(context.args); profile.pushOptionalJvmArgs(context.args);
Collections.addAll(context.args, "-Djava.library.path=".concat(params.clientDir.resolve(NATIVES_DIR).toString())); // Add Native Path Collections.addAll(context.args, "-Djava.library.path=".concat(params.clientDir.resolve(NATIVES_DIR).toString())); // Add Native Path
Collections.addAll(context.args, "-javaagent:".concat(pathLauncher).concat("=pr")); Collections.addAll(context.args, "-javaagent:".concat(pathLauncher));
LauncherGuardManager.guard.addCustomParams(context); LauncherGuardManager.guard.addCustomParams(context);
Collections.addAll(context.args, ClientLauncher.class.getName()); Collections.addAll(context.args, ClientLauncher.class.getName());

View file

@ -1,3 +1,7 @@
plugins {
id 'com.github.johnrengelman.shadow' version '5.0.0' apply false
}
configure(subprojects.findAll { it.name != 'modules' && it.name != 'Radon' }) { configure(subprojects.findAll { it.name != 'modules' && it.name != 'Radon' }) {
apply plugin: 'idea' apply plugin: 'idea'
apply plugin: 'eclipse' apply plugin: 'eclipse'

View file

@ -7,6 +7,8 @@
import java.lang.management.ManagementFactory; import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean; import java.lang.management.OperatingSystemMXBean;
import java.lang.management.RuntimeMXBean; import java.lang.management.RuntimeMXBean;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.util.Arrays; import java.util.Arrays;
@ -136,8 +138,15 @@ public static String getEnvPropertyCaseSensitive(String name) {
} }
private static int getRAMAmount() { private static int getRAMAmount() {
// TODO Normal fix. int physicalRam = 1024;
int physicalRam = (int) (((com.sun.management.OperatingSystemMXBean) OPERATING_SYSTEM_MXBEAN).getTotalPhysicalMemorySize() >> 20); try {
final Method getTotalPhysicalMemorySize = OPERATING_SYSTEM_MXBEAN.getClass().getDeclaredMethod("getTotalPhysicalMemorySize");
getTotalPhysicalMemorySize.setAccessible(true);
physicalRam = (int) ((long)getTotalPhysicalMemorySize.invoke(OPERATING_SYSTEM_MXBEAN) >> 20);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException
| SecurityException e) {
throw new Error(e);
}
return Math.min(physicalRam, OS_BITS == 32 ? 1536 : 32768); // Limit 32-bit OS to 1536 MiB, and 64-bit OS to 32768 MiB (because it's enough) return Math.min(physicalRam, OS_BITS == 32 ? 1536 : 32768); // Limit 32-bit OS to 1536 MiB, and 64-bit OS to 32768 MiB (because it's enough)
} }