ByteCodePatcher

Fix the bungle that was my last merge.
Refactored class/method names to adhere to ByteCodePatcher layout
Import all transformers
This commit is contained in:
zeruth
2019-04-18 19:02:21 -04:00
parent 0ddb7e1078
commit 227ae81082
4 changed files with 36 additions and 290 deletions

View File

@@ -86,245 +86,6 @@ public class ClientLoader
this.clientConfigLoader = clientConfigLoader; this.clientConfigLoader = clientConfigLoader;
} }
public Applet load()
{
if (updateCheckMode == NONE)
{
return null;
}
try
{
File injectedClientFile = ByteCodeUtils.injectedClientFile;
File hijackedClientFile = ByteCodeUtils.hijackedClientFile;
Manifest manifest = new Manifest();
manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
target = new JarOutputStream(new FileOutputStream(injectedClientFile), manifest);
RSConfig config = clientConfigLoader.fetch();
Map<String, byte[]> zipFile = new HashMap<>();
{
Certificate[] jagexCertificateChain = getJagexCertificateChain();
String codebase = config.getCodeBase();
String initialJar = config.getInitialJar();
URL url = new URL(codebase + initialJar);
Request request = new Request.Builder()
.url(url)
.build();
try (Response response = RuneLiteAPI.CLIENT.newCall(request).execute())
{
JarInputStream jis;
jis = new JarInputStream(response.body().byteStream());
byte[] tmp = new byte[4096];
ByteArrayOutputStream buffer = new ByteArrayOutputStream(756 * 1024);
for (; ; )
{
JarEntry metadata = jis.getNextJarEntry();
if (metadata == null)
{
break;
}
buffer.reset();
for (; ; )
{
int n = jis.read(tmp);
if (n <= -1)
{
break;
}
buffer.write(tmp, 0, n);
}
zipFile.put(metadata.getName(), buffer.toByteArray());
}
}
}
if (updateCheckMode == AUTO)
{
Map<String, String> hashes;
try (InputStream is = ClientLoader.class.getResourceAsStream("/patch/hashes.json"))
{
hashes = new Gson().fromJson(new InputStreamReader(is), new TypeToken<HashMap<String, String>>()
{
}.getType());
}
for (Map.Entry<String, String> file : hashes.entrySet())
{
byte[] bytes = zipFile.get(file.getKey());
String ourHash = null;
if (bytes != null)
{
ourHash = Hashing.sha512().hashBytes(bytes).toString();
}
if (!file.getValue().equals(ourHash))
{
if (hijackedClientFile.exists()) {
Logger.getAnonymousLogger().warning("[RuneLit] Hash checking / Client patching skipped due to hijacked client.");
updateCheckMode = VANILLA;
break;
} else {
log.info("{} had a hash mismatch; falling back to vanilla. {} != {}", file.getKey(), file.getValue(), ourHash);
log.info("Client is outdated!");
updateCheckMode = VANILLA;
break;
}
}
}
}
if (updateCheckMode == AUTO)
{
ByteArrayOutputStream patchOs = new ByteArrayOutputStream(756 * 1024);
int patchCount = 0;
for (Map.Entry<String, byte[]> file : zipFile.entrySet())
{
byte[] bytes;
try (InputStream is = ClientLoader.class.getResourceAsStream("/patch/" + file.getKey() + ".bs"))
{
if (is == null)
{
continue;
}
bytes = ByteStreams.toByteArray(is);
}
patchOs.reset();
Patch.patch(file.getValue(), bytes, patchOs);
file.setValue(patchOs.toByteArray());
++patchCount;
if (!file.getKey().startsWith("META")) {
add(file.getValue(), file.getKey(), target);
}
}
if (target!=null)
target.close();
log.info("Patched {} classes", patchCount);
}
if (hooksFile.exists()) {
ByteCodePatcher.classPool = new ClassPool(true);
ByteCodePatcher.classPool.appendClassPath(RuneLite.RUNELITE_DIR+"/injectedClient-"+ RuneLiteAPI.getVersion() +"-.jar");
Gson gson = new Gson();
Hooks hooks = gson.fromJson(new BufferedReader(new FileReader(hooksFile)), Hooks.class);
if (hooks == null && !scrapedHooks) {
System.out.println("[RuneLit] Bad hooks, re-scraping.");
ByteCodePatcher.clientInstance = initVanillaInjected(ByteCodeUtils.injectedClientFile.getPath());
ByteCodePatcher.findHooks(injectedClientFile.getPath());
scrapedHooks=true;
}
if ((hooks.clientInstance.equals("")||
hooks.projectileClass.equals("") ||
hooks.actorClass.equals("") ||
hooks.playerClass.equals("")) && !scrapedHooks) {
System.out.println("[RuneLit] Bad hooks, re-scraping.");
ByteCodePatcher.clientInstance = initVanillaInjected(ByteCodeUtils.injectedClientFile.getPath());
ByteCodePatcher.findHooks(injectedClientFile.getPath());
scrapedHooks=true;
} else if (!scrapedHooks) {
ByteCodePatcher.clientInstance = hooks.clientInstance;
ByteCodePatcher.applyHooks(ByteCodeUtils.injectedClientFile, hooks);
System.out.println("[RuneLit] Loaded hooks");
scrapedHooks=true;
}
} else {
System.out.println("[RuneLit] Hooks file not found, scraping hooks.");
ByteCodePatcher.clientInstance = initVanillaInjected(ByteCodeUtils.injectedClientFile.getPath());
ByteCodePatcher.findHooks(injectedClientFile.getPath());
}
Map<String, byte[]> zipFile2 = new HashMap<>();
JarInputStream jis = new JarInputStream(new FileInputStream(hijackedClientFile));
byte[] tmp = new byte[4096];
ByteArrayOutputStream buffer = new ByteArrayOutputStream(756 * 1024);
for (; ; ) {
JarEntry metadata = jis.getNextJarEntry();
if (metadata == null) {
break;
}
buffer.reset();
for (; ; ) {
int n = jis.read(tmp);
if (n <= -1) {
break;
}
buffer.write(tmp, 0, n);
}
zipFile2.put(metadata.getName(), buffer.toByteArray());
}
String initialClass = config.getInitialClass();
ClassLoader rsClassLoader = new ClassLoader(ClientLoader.class.getClassLoader())
{
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException
{
String path = name.replace('.', '/').concat(".class");
byte[] data = zipFile2.get(path);
if (data == null)
{
throw new ClassNotFoundException(name);
}
return defineClass(name, data, 0, data.length);
}
};
Class<?> clientClass = rsClassLoader.loadClass(initialClass);
Applet rs = (Applet) clientClass.newInstance();
rs.setStub(new RSAppletStub(config));
return rs;
}
catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException
| CompressorException | InvalidHeaderException | CertificateException | SecurityException e)
{
if (e instanceof ClassNotFoundException)
{
log.error("Unable to load client - class not found. This means you"
+ " are not running RuneLite with Maven as the client patch"
+ " is not in your classpath.");
}
log.error("Error loading RS!", e);
return null;
} catch (NotFoundException e) {
e.printStackTrace();
}
return null;
}
private void add(byte[] bytes, String entryName ,JarOutputStream target) throws IOException {
BufferedInputStream in = null;
try {
JarEntry entry = new JarEntry(entryName);
target.putNextEntry(entry);
target.write(bytes);
target.closeEntry();
} finally {
if (in != null)
in.close();
}
}
private static Certificate[] getJagexCertificateChain() throws CertificateException private static Certificate[] getJagexCertificateChain() throws CertificateException
{ {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
@@ -524,10 +285,10 @@ public class ClientLoader
if (hooks.clientInstance.equals("") || if (hooks.clientInstance.equals("") ||
hooks.projectileClass.equals("") || hooks.projectileClass.equals("") ||
hooks.actorClass.equals("") || hooks.actorClass.equals("") ||
hooks.mainClientInstance.equals("") || hooks.clientInstance.equals("") ||
hooks.playerClass.equals("")) { hooks.playerClass.equals("")) {
System.out.println("[RuneLit] Bad hooks, re-scraping."); System.out.println("[RuneLit] Bad hooks, re-scraping.");
ByteCodePatcher.clientInstance = getClientInstance(ByteCodeUtils.injectedClientFile.getPath()); ByteCodePatcher.clientInstance = ByteCodeUtils.injectedClientFile.getPath();
ByteCodePatcher.findHooks(injectedClientFile.getPath()); ByteCodePatcher.findHooks(injectedClientFile.getPath());
} else { } else {
ByteCodePatcher.clientInstance = hooks.clientInstance; ByteCodePatcher.clientInstance = hooks.clientInstance;
@@ -537,7 +298,7 @@ public class ClientLoader
} else { } else {
System.out.println("[RuneLit] Hooks file not found, scraping hooks."); System.out.println("[RuneLit] Hooks file not found, scraping hooks.");
ByteCodePatcher.clientInstance = getClientInstance(ByteCodeUtils.injectedClientFile.getPath()); ByteCodePatcher.clientInstance = initVanillaInjected(ByteCodeUtils.injectedClientFile.getPath());
ByteCodePatcher.findHooks(injectedClientFile.getPath()); ByteCodePatcher.findHooks(injectedClientFile.getPath());
} }

View File

@@ -7,10 +7,7 @@ import javassist.CtClass;
import javassist.NotFoundException; import javassist.NotFoundException;
import net.runelite.client.RuneLite; import net.runelite.client.RuneLite;
import net.runelite.client.rs.ClientLoader; import net.runelite.client.rs.ClientLoader;
import net.runelite.client.rs.bytecode.transformers.ActorTransform; import net.runelite.client.rs.bytecode.transformers.*;
import net.runelite.client.rs.bytecode.transformers.PlayerTransform;
import net.runelite.client.rs.bytecode.transformers.ProjectileTransform;
import net.runelite.client.rs.bytecode.transformers.getProjectileTransform;
import net.runelite.http.api.RuneLiteAPI; import net.runelite.http.api.RuneLiteAPI;
import org.xeustechnologies.jcl.JarClassLoader; import org.xeustechnologies.jcl.JarClassLoader;
@@ -45,6 +42,8 @@ public class ByteCodePatcher {
transformProjectile(projectileClass); transformProjectile(projectileClass);
Class playerClass = Class.forName(hooks.playerClass, false, child); Class playerClass = Class.forName(hooks.playerClass, false, child);
transformPlayer(playerClass); transformPlayer(playerClass);
Class clientClass = Class.forName(hooks.clientClass, false, child);
transformClient(clientClass);
ByteCodeUtils.updateHijackedJar(); ByteCodeUtils.updateHijackedJar();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
@@ -99,6 +98,7 @@ public class ByteCodePatcher {
checkActor(classToLoad); checkActor(classToLoad);
checkProjectile(classToLoad); checkProjectile(classToLoad);
checkPlayer(classToLoad); checkPlayer(classToLoad);
checkClient(classToLoad);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
@@ -153,42 +153,6 @@ public class ByteCodePatcher {
pt.modify(projectile); pt.modify(projectile);
} }
public static void checkPlayer(Class current) {
try {
Method method = current.getDeclaredMethod("getSkullIcon");
if (method!=null) {
hooks.playerClass = current.getName();
System.out.println("[RuneLit] Transforming Player at class: "+current.getName());
PlayerTransform pt = new PlayerTransform();
pt.modify(current);
public static void checkgetProjectiles(Class getprojectile) {
try {
Method method = getprojectile.getDeclaredMethod("getProjectiles");
if (method != null) {
hooks.mainClientInstance = getprojectile.getName();
System.out.println("[RuneLit] Transforming Projectile at class: " + getprojectile.getName());
getProjectileTransform gpt = new getProjectileTransform();
gpt.modify(getprojectile);
}
} catch (NoSuchMethodException e) {
//e.printStackTrace();
} catch (NoClassDefFoundError e) {
//e.printStackTrace();
}
}
public static void transformPlayer(Class player) {
System.out.println("[RuneLit] Transforming Player at class: "+player.getName());
PlayerTransform pt = new PlayerTransform();
pt.modify(player);
public static void transformGetProjectile(Class current) {
System.out.println("[RuneLit] Transforming getProjectile at class: " + current.getName());
getProjectileTransform gpt = new getProjectileTransform();
gpt.modify(current);
}
public static void checkPlayer(Class current) { public static void checkPlayer(Class current) {
try { try {
Method method = current.getDeclaredMethod("getSkullIcon"); Method method = current.getDeclaredMethod("getSkullIcon");
@@ -198,6 +162,20 @@ public class ByteCodePatcher {
PlayerTransform pt = new PlayerTransform(); PlayerTransform pt = new PlayerTransform();
pt.modify(current); pt.modify(current);
} }
} catch (Exception e) {
e.printStackTrace();
}
}
public static void checkClient(Class current) {
try {
Method method = current.getDeclaredMethod("getProjectiles");
if (method != null) {
hooks.clientInstance = current.getName();
System.out.println("[RuneLit] Transforming Projectile at class: " + current.getName());
ClientTransform ct = new ClientTransform();
ct.modify(current);
}
} catch (NoSuchMethodException e) { } catch (NoSuchMethodException e) {
//e.printStackTrace(); //e.printStackTrace();
} catch (NoClassDefFoundError e) { } catch (NoClassDefFoundError e) {
@@ -205,6 +183,12 @@ public class ByteCodePatcher {
} }
} }
public static void transformClient(Class client) {
System.out.println("[RuneLit] Transforming Client at class: " + client.getName());
ClientTransform ct = new ClientTransform();
ct.modify(client);
}
public static void transformPlayer(Class player) { public static void transformPlayer(Class player) {
System.out.println("[RuneLit] Transforming Player at class: " + player.getName()); System.out.println("[RuneLit] Transforming Player at class: " + player.getName());
PlayerTransform pt = new PlayerTransform(); PlayerTransform pt = new PlayerTransform();

View File

@@ -9,6 +9,7 @@ public class Hooks {
public String actorClass = ""; public String actorClass = "";
public String projectileClass = ""; public String projectileClass = "";
public String playerClass = ""; public String playerClass = "";
public String clientClass = "client"; //Always named client
public String[] protectedMethods; public String[] protectedMethods;
public Hooks() { public Hooks() {

View File

@@ -3,27 +3,26 @@ package net.runelite.client.rs.bytecode.transformers;
import javassist.CtClass; import javassist.CtClass;
import javassist.CtMethod; import javassist.CtMethod;
import javassist.CtNewMethod; import javassist.CtNewMethod;
import javassist.NotFoundException;
import javassist.bytecode.AnnotationsAttribute; import javassist.bytecode.AnnotationsAttribute;
import javassist.bytecode.ClassFile; import javassist.bytecode.ClassFile;
import javassist.bytecode.ConstPool; import javassist.bytecode.ConstPool;
import net.runelite.client.rs.bytecode.ByteCodePatcher; import net.runelite.client.rs.bytecode.ByteCodePatcher;
public class ClientTransform {
public class getProjectileTransform {
public CtClass ct = null; public CtClass ct = null;
public void modify(Class getprojectile) { public void modify(Class client) {
try { try {
ct = ByteCodePatcher.classPool.get(getprojectile.getName()); ct = ByteCodePatcher.classPool.get(client.getName());
transformGetProjectiles();
transformGetProjectile();
ByteCodePatcher.modifiedClasses.add(ct); ByteCodePatcher.modifiedClasses.add(ct);
} catch (Exception e) { } catch (NotFoundException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
public void transformGetProjectile() { public void transformGetProjectiles() {
CtMethod getProjectiles; CtMethod getProjectiles;
try { try {
@@ -53,4 +52,5 @@ public class getProjectileTransform {
e.printStackTrace(); e.printStackTrace();
} }
} }
} }