Remove debug class writing. Add class signing

This commit is contained in:
Lassebq 2023-01-08 21:03:32 +02:00
parent 89f25af378
commit 4f5da66edc
No known key found for this signature in database
GPG key ID: DE0866BB0C980B6E
19 changed files with 1129 additions and 322 deletions

View file

@ -4,11 +4,10 @@ apply plugin: 'eclipse'
repositories {
maven {
url "https://libraries.minecraft.net/"
// Needs .poms in order to function
// url "https://mcphackers.github.io/libraries/"
}
mavenCentral()
flatDir {
dirs "lib"
}
}
group = 'org.mcphackers'
@ -17,8 +16,8 @@ version = '1.0'
sourceCompatibility = 1.6
dependencies {
implementation name: 'lwjgl-2.9.4'
implementation name: 'lwjgl_util-2.9.4'
// implementation 'org.lwjgl:lwjgl:2.9.4'
// implementation 'org.lwjgl:lwjgl_util:2.9.4'
implementation 'org.ow2.asm:asm:9.3'
implementation 'org.ow2.asm:asm-tree:9.3'
implementation 'org.json:json:20220924'

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -42,7 +42,4 @@ public class AppletLaunchTarget extends LaunchTarget {
}
AppletWrapper.startApplet(appletClass, width, height, title, icon);
}
}

View file

@ -4,6 +4,7 @@ import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
@ -36,16 +37,21 @@ public class LaunchConfig {
public LaunchParameter<String> versionType = new LaunchParameter<String>("versionType", String.class);
public LaunchParameter<Boolean> applet = new LaunchParameter<Boolean>("applet", Boolean.class, false);
public LaunchParameter<Boolean> haspaid = new LaunchParameter<Boolean>("haspaid", Boolean.class, true);
public LaunchParameter<String> loadmap_user = new LaunchParameter<String>("loadmap_user", String.class);
public LaunchParameter<Integer> loadmap_id = new LaunchParameter<Integer>("loadmap_id", Integer.class);
public LaunchParameter<String> mppass = new LaunchParameter<String>("mppass", String.class, "");
public LaunchParameter<Boolean> lwjglFrame = new LaunchParameter<Boolean>("lwjglFrame", Boolean.class, true, true);
public LaunchParameter<Boolean> isom = new LaunchParameter<Boolean>("isom", Boolean.class, false, true);
public LaunchParameter<Boolean> forceVsync = new LaunchParameter<Boolean>("forceVsync", Boolean.class, false, true);
public LaunchParameter<String> skinProxy = new LaunchParameter<String>("skinProxy", String.class, null, true);
public LaunchParameter<Integer> resourcesProxyPort = new LaunchParameter<Integer>("resourcesProxyPort", Integer.class, null, true);
public LaunchConfig(String[] args) {
int i = 0;
while(i < args.length) {
if(args[i].startsWith("--")) {
String paramName = args[i].substring(2);
LaunchParameter<Object> param = parameters.get(paramName);
LaunchParameter<Object> param = parameters.get(paramName.toLowerCase(Locale.ROOT));
if(param != null && param.type == Boolean.class) {
param.set(true);
}
@ -54,16 +60,15 @@ public class LaunchConfig {
}
else if(i + 1 < args.length) {
try {
LaunchParameter<Object> param2 = parameters.get(paramName);
if(param2 != null) {
if(param != null) {
if(param.type == String.class) {
param2.set(args[i + 1]);
param.set(args[i + 1]);
}
else if(param.type == File.class) {
param2.set(new File(args[i + 1]));
param.set(new File(args[i + 1]));
}
else if(param.type == Integer.class) {
param2.set(Integer.valueOf(args[i + 1]));
param.set(Integer.valueOf(args[i + 1]));
}
i++;
}
@ -119,7 +124,7 @@ public class LaunchConfig {
public LaunchParameter(String name, Class<?> type, T defaultValue) {
this.type = type;
this.value = defaultValue;
parameters.put(name, (LaunchParameter<Object>) this);
parameters.put(name.toLowerCase(Locale.ROOT), (LaunchParameter<Object>) this);
}
public String getString() {

View file

@ -24,10 +24,16 @@ public class Inject {
return new AppletWrapper(LAUNCH.config.getArgsAsMap());
}
/**
* Indev load level injection
*/
public static File getLevelFile(int index) {
return new File(LAUNCH.config.gameDir.get(), "levels/level" + index + ".dat");
}
/**
* Indev save level injection
*/
public static File saveLevel(int index, String levelName) {
final int maxLevels = 5;
File levels = new File(LAUNCH.config.gameDir.get(), "levels");

View file

@ -9,6 +9,10 @@ import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.security.CodeSigner;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
@ -23,7 +27,7 @@ import org.objectweb.asm.tree.FieldNode;
import org.objectweb.asm.tree.MethodNode;
public class LaunchClassLoader extends ClassLoader implements ClassNodeSource {
private static LaunchClassLoader INSTANCE;
private ClassLoader parent;
@ -84,28 +88,29 @@ public class LaunchClassLoader extends ClassLoader implements ClassNodeSource {
protected Class<?> redefineClass(String name) {
byte[] classData = getClassAsBytes(name);
if(classData == null) return null;
Class<?> definedClass = defineClass(name, classData, 0, classData.length);
Class<?> definedClass = defineClass(name, classData, 0, classData.length, getProtectionDomain(name));
classes.put(name, definedClass);
return definedClass;
}
private ProtectionDomain getProtectionDomain(String name) {
final URL resource = parent.getResource(classResourceName(name));
if (resource == null) {
return null;
}
URLConnection urlConnection;
try {
urlConnection = resource.openConnection();
} catch (IOException e) {
e.printStackTrace();
return null;
}
CodeSource codeSource = urlConnection == null ? null : new CodeSource(urlConnection.getURL(), new CodeSigner[0]);
return new ProtectionDomain(codeSource, null);
}
public void overrideClass(ClassNode node) {
if(node == null) return;
// if(true) {
// File saveFolder = new File("C:/Users/User/Desktop/debug");
// ClassWriter writer = new SafeClassWriter(parent, COMPUTE_MAXS);
// node.accept(writer);
// byte[] classData = writer.toByteArray();
// File cls = new File(saveFolder, node.name + ".class");
// cls.getParentFile().mkdirs();
// try {
// FileOutputStream fos = new FileOutputStream(cls);
// fos.write(classData);
// fos.close();
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
overridenClasses.put(className(node.name), node);
classNodeCache.put(node.name, node);
}

View file

@ -6,11 +6,13 @@ import java.net.URLConnection;
public class LegacyURLStreamHandler extends URLStreamHandlerProxy {
// private LegacyProxyData data;
//
// public LegacyURLStreamHandler(LegacyProxyData proxyData) {
// data = proxyData;
// }
private SkinType skins;
private int port;
public LegacyURLStreamHandler(SkinType skins, int port) {
this.skins = skins;
this.port = port;
}
@Override
protected URLConnection openConnection(URL url) throws IOException {
@ -33,14 +35,11 @@ public class LegacyURLStreamHandler extends URLStreamHandlerProxy {
return new LoadLevelURLConnection(url);
else if (path.equals("/listmaps.jsp"))
return new ListLevelsURLConnection(url);
else if (path.startsWith("/MinecraftResources/"))
return new ResourceIndexURLConnection(url, true);
else if (path.startsWith("/resources/"))
return new ResourceIndexURLConnection(url, false);
else if (path.startsWith("/MinecraftSkins/") || path.startsWith("/skin/"))
return new SkinURLConnection(url);
else if (path.startsWith("/MinecraftCloaks/") || path.startsWith("/cloak/"))
return new SkinURLConnection(url);
else if (path.startsWith("/MinecraftResources/") || path.startsWith("/resources/"))
return new ResourceIndexURLConnection(url, port);
else if (path.startsWith("/MinecraftSkins/") || path.startsWith("/skin/")
|| path.startsWith("/MinecraftCloaks/") || path.startsWith("/cloak/"))
return new SkinURLConnection(url, skins);
else if(host.equals("assets.minecraft.net") && path.equals("/1_6_has_been_released.flag")) {
return new BasicResponseURLConnection(url, "");
//return new BasicResponseURLConnection(url, "https://web.archive.org/web/20130702232237if_/https://mojang.com/2013/07/minecraft-the-horse-update/");
@ -48,4 +47,30 @@ public class LegacyURLStreamHandler extends URLStreamHandlerProxy {
}
return super.openConnection(url);
}
public enum SkinType {
CLASSIC("classic"),
PRE_B1_9("pre-b1.9"),
PRE_1_7("pre-1.7"),
PRE_1_8("pre-1.8"),
DEFAULT("default");
private String name;
private SkinType(String name) {
this.name = name;
}
public static SkinType get(String name) {
for(SkinType skinType : values()) {
if(skinType.name.equals(name)) {
return skinType;
}
}
return null;
}
}
public enum ResourceIndex {
}
}

View file

@ -1,23 +1,22 @@
package org.mcphackers.launchwrapper.protocol;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import org.mcphackers.launchwrapper.Launch;
import org.mcphackers.launchwrapper.protocol.LegacyURLStreamHandler.ResourceIndex;
import org.mcphackers.launchwrapper.util.Util;
public class ResourceIndexURLConnection extends URLConnection {
private static final String[] RESOURCES = new String[] {"/resources/", "/MinecraftResources/"};
private boolean xmlMode;
public ResourceIndexURLConnection(URL u, boolean xmlMode) {
super(u);
this.xmlMode = xmlMode;
ResourceIndex index = null;
int port = -1;
public ResourceIndexURLConnection(URL url, int port) {
super(url);
this.port = port;
}
@Override
@ -25,35 +24,16 @@ public class ResourceIndexURLConnection extends URLConnection {
@Override
public InputStream getInputStream() throws IOException {
File assetsDir = new File(Launch.INSTANCE.config.gameDir.get(), "resources");
String path = url.getPath();
for(String template : RESOURCES) {
if(path.startsWith(template)) {
String assetName = path.substring(template.length());
if(assetName.isEmpty()) {
File indexFile;
if (xmlMode) {
indexFile = new File(assetsDir, "index.xml");
} else {
indexFile = new File(assetsDir, "index.txt");
}
if(indexFile.exists()) {
return new FileInputStream(indexFile);
} else {
//TODO download from another host if missing locally
throw new FileNotFoundException("Missing resource index");
}
}
//TODO download from another host at all times
// it only requests it if (file.length() != resourceIndexFileLength || !file.exists())
File asset = new File(assetsDir, assetName);
if(asset.exists()) {
return new FileInputStream(asset);
} else {
throw new FileNotFoundException(assetName);
}
return Util.replaceHost(url, "betacraft.uk", getPort()).openStream();
}
}
throw new MalformedURLException(url.toExternalForm() + " is not a resource index");
return url.openStream();
}
protected int getPort() {
return port;
}
}

View file

@ -7,6 +7,7 @@ import java.net.URL;
import java.util.HashMap;
import org.json.JSONObject;
import org.mcphackers.launchwrapper.protocol.LegacyURLStreamHandler.SkinType;
import org.mcphackers.launchwrapper.util.Base64;
import org.mcphackers.launchwrapper.util.ImageUtils;
import org.mcphackers.launchwrapper.util.Util;
@ -38,7 +39,7 @@ public class SkinRequests {
int attemptCount = 0;
while(attemptCount < 2) {
attemptCount++;
URL nametouuidURL = new URL("https://api.mojang.com/users/profiles/minecraft/" + name);
URL nametouuidURL = new URL("https://api.mojang.com/users/profiles/minecraft/" + name);
HttpURLConnection connection = (HttpURLConnection)nametouuidURL.openConnection();
if(connection.getResponseCode() == 429) {
// wait for the block to pass
@ -129,7 +130,7 @@ public class SkinRequests {
cape = imgu.getInByteForm();
break;
default:
case DEFAULT:
return skindata.cape;
}
}
@ -154,18 +155,18 @@ public class SkinRequests {
switch(skinType) {
case CLASSIC:
imgu = overlayHeadLayer(imgu);
overlayHeadLayer(imgu);
case PRE_B1_9:
rotateBottomTX(imgu);
case PRE_1_7:
useLeftArm(imgu);
useLeftLeg(imgu);
case PRE_1_8:
imgu = overlay64to32(imgu);
overlay64to32(imgu);
if(skindata.slim)
alexToSteve(imgu);
imgu = imgu.crop(0, 0, 64, 32);
default:
case DEFAULT:
break;
}
@ -191,13 +192,13 @@ public class SkinRequests {
imgu.setArea(28, 16, imgu.crop(28, 16, 8, 4).flip(false, true).getImage());
}
public static ImageUtils overlay64to32(ImageUtils imgu) {
public static void overlay64to32(ImageUtils imgu) {
// 32-64 body
return imgu.setArea(0, 16, imgu.crop(0, 32, 56, 16).getImage(), false);
imgu.setArea(0, 16, imgu.crop(0, 32, 56, 16).getImage(), false);
}
public static ImageUtils overlayHeadLayer(ImageUtils imgu) {
return imgu.setArea(0, 0, imgu.crop(32, 0, 32, 16).getImage(), false);
public static void overlayHeadLayer(ImageUtils imgu) {
imgu.setArea(0, 0, imgu.crop(32, 0, 32, 16).getImage(), false);
}
public static void useLeftLeg(ImageUtils imgu) {
@ -229,11 +230,4 @@ public class SkinRequests {
// fill the 1px space on the right
imgu.setArea(51, 16, imgu.crop(50, 16, 1, 4).getImage());
}
public enum SkinType {
CLASSIC,
PRE_B1_9,
PRE_1_7,
PRE_1_8
}
}

View file

@ -1,29 +1,27 @@
package org.mcphackers.launchwrapper.protocol;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import org.mcphackers.launchwrapper.Launch;
import org.mcphackers.launchwrapper.protocol.SkinRequests.SkinType;
import org.mcphackers.launchwrapper.protocol.LegacyURLStreamHandler.SkinType;
import org.mcphackers.launchwrapper.util.Util;
public class SkinURLConnection extends HttpURLConnection {
private static final String[] CLOAKS = new String[] {"/cloak/", "/MinecraftCloaks/"};
private static final String[] SKINS = new String[] {"/skin/", "/MinecraftSkins/"};
private static final String[] CLOAKS = {"/cloak/", "/MinecraftCloaks/"};
private static final String[] SKINS = {"/skin/", "/MinecraftSkins/"};
protected SkinType skinType = SkinType.PRE_1_8;
protected SkinType skinType;
protected InputStream inputStream;
public SkinURLConnection(URL url) {
public SkinURLConnection(URL url, SkinType skin) {
super(url);
responseCode = 200;
skinType = skin;
}
@Override
@ -36,7 +34,7 @@ public class SkinURLConnection extends HttpURLConnection {
@Override
public void connect() throws IOException {
File skinDir = new File(Launch.INSTANCE.config.gameDir.get(), "skins");
// File skinDir = new File(Launch.INSTANCE.config.gameDir.get(), "skins");
Map<String, String> queryMap = Util.queryMap(url);
String username = queryMap.get("user");
String path = url.getPath();
@ -57,11 +55,11 @@ public class SkinURLConnection extends HttpURLConnection {
if (path.startsWith(template)) {
if(username == null)
username = path.substring(template.length()).replace(".png", "");
File cached = new File(skinDir, username + ".png");
if(cached.exists()) {
inputStream = new FileInputStream(cached);
return;
}
// File cached = new File(skinDir, username + ".png");
// if(cached.exists()) {
// inputStream = new FileInputStream(cached);
// return;
// }
byte[] skinData = SkinRequests.getSkin(username, skinType);
if(skinData != null) {
inputStream = new ByteArrayInputStream(skinData);

View file

@ -6,11 +6,15 @@ import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import org.mcphackers.launchwrapper.util.Util;
public abstract class URLStreamHandlerProxy extends URLStreamHandler {
private static final Map<String, URLStreamHandler> DEFAULT_HANDLERS = new HashMap<String, URLStreamHandler>();
protected URLStreamHandler parent;
@Override
@ -22,7 +26,7 @@ public abstract class URLStreamHandlerProxy extends URLStreamHandler {
if(parent == null) {
return null;
}
return new URL(null, url.toString(), parent).openConnection();
return new URL(null, url.toExternalForm(), parent).openConnection();
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@ -38,10 +42,16 @@ public abstract class URLStreamHandlerProxy extends URLStreamHandler {
}
public static URLStreamHandler getURLStreamHandler(String protocol) {
URLStreamHandler handler = DEFAULT_HANDLERS.get(protocol);
if(handler != null) {
return handler;
}
try {
URL url = new URL(protocol + ":");
Field handlerField = URL.class.getDeclaredField("handler");
return (URLStreamHandler)Util.getObjectUnsafe(url, handlerField);
handler = (URLStreamHandler)Util.getObjectUnsafe(url, handlerField);
DEFAULT_HANDLERS.put(protocol, handler);
return handler;
} catch (Exception e) {
e.printStackTrace();
return null;

View file

@ -13,9 +13,10 @@ import org.mcphackers.launchwrapper.inject.InjectUtils;
import org.mcphackers.launchwrapper.inject.InjectUtils.Access;
import org.mcphackers.launchwrapper.loader.LaunchClassLoader;
import org.mcphackers.launchwrapper.protocol.LegacyURLStreamHandler;
import org.mcphackers.launchwrapper.protocol.SkinRequests.SkinType;
import org.mcphackers.launchwrapper.protocol.LegacyURLStreamHandler.SkinType;
import org.mcphackers.launchwrapper.protocol.URLStreamHandlerProxy;
import org.mcphackers.launchwrapper.util.Util;
import org.mcphackers.rdi.util.IdentifyCall;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
@ -24,7 +25,6 @@ import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.FieldNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.IntInsnNode;
import org.objectweb.asm.tree.JumpInsnNode;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.LdcInsnNode;
@ -48,13 +48,11 @@ public class LegacyTweak extends Tweak {
"net/minecraft/client/MinecraftApplet",
"com/mojang/minecraft/MinecraftApplet"
};
public static final boolean experimentalIndevSaving = true;
protected ClassNode minecraft;
protected ClassNode minecraftApplet;
/** Class containing username and sessionId */
protected ClassNode user;
/** Field of user class */
protected FieldNode userField;
/** Field that determines if Minecraft should exit */
protected FieldNode running;
/** Frame width */
@ -64,11 +62,7 @@ public class LegacyTweak extends Tweak {
/** Working game directory */
protected FieldNode mcDir;
/** Whenever the game runs in an applet */
protected FieldNode appletMode;
private FieldInsnNode hasPaid;
protected FieldNode minecraftUri;
protected MethodNode setDemo;
protected MethodNode setServer;
private FieldNode appletMode;
private FieldInsnNode defaultWidth;
private FieldInsnNode defaultHeight;
private FieldInsnNode fullscreenField;
@ -76,9 +70,8 @@ public class LegacyTweak extends Tweak {
private boolean supportsResizing;
/** public static main(String[]) */
protected MethodNode main;
/** Class used to instantiate a Minecraft instance */
protected ClassNode minecraftImpl;
protected SkinType skinFormat = null; //TODO analyze and choose which format the skin should be in
protected SkinType skinType = SkinType.DEFAULT;
protected int port = -1;
public LegacyTweak(ClassNodeSource source, LaunchConfig launch) {
super(source);
@ -87,6 +80,12 @@ public class LegacyTweak extends Tweak {
public boolean transform() {
init();
if(launch.skinProxy.get() != null) {
skinType = SkinType.get(launch.skinProxy.get());
}
if(launch.resourcesProxyPort.get() != null) {
port = launch.resourcesProxyPort.get();
}
if(minecraft == null) {
return false;
}
@ -95,19 +94,16 @@ public class LegacyTweak extends Tweak {
return false;
}
MethodNode runTick = getTickMethod(run);
replaceGameDirectory(mcDir);
//fixSkinURL();
fixSplash();
fixPaulscode();
fixIndevLaunch();
addIndevSaving();
fixA111GrayScreen();
fixShutdown(run);
//setOnePointSixReleased(runTick, false);
removeCanvas(runTick);
MethodNode init = getInit(run);
replaceGameDirectory(init, mcDir);
optionsLoadFix(init);
//assetsURLFix(init);
displayPatch(init, supportsResizing);
fixMouseHelper(mouseHelperName);
patchMinecraftInit();
@ -126,7 +122,7 @@ public class LegacyTweak extends Tweak {
public LaunchTarget getLaunchTarget(LaunchClassLoader loader) {
if(main != null) {
enableLegacyMergeSort();
URLStreamHandlerProxy.setURLStreamHandler("http", new LegacyURLStreamHandler());
URLStreamHandlerProxy.setURLStreamHandler("http", new LegacyURLStreamHandler(skinType, port));
MainLaunchTarget target = new MainLaunchTarget(loader, minecraft.name);
target.args = new String[] {launch.username.get(), launch.sessionid.get()};
return target;
@ -135,7 +131,6 @@ public class LegacyTweak extends Tweak {
}
private void addIndevSaving() {
final boolean experimentalIndevSaving = true;
if(!experimentalIndevSaving) {
return;
}
@ -170,7 +165,7 @@ public class LegacyTweak extends Tweak {
if(compareInsn(insns2[0], ALOAD, 1)
&& compareInsn(insns2[1], GETFIELD, idField.owner, idField.name, idField.desc)
&& compareInsn(insns2[3], IF_ICMPNE)) {
AbstractInsnNode[] insns3 = fill(insns2[3].getNext(), 3);
AbstractInsnNode[] insns3 = fill(nextInsn(insns2[3]), 3);
if(compareInsn(insns3[2], NEW)) {
if(compareInsn(insns2[2], ICONST_2)) {
saveLevelMenu = source.getClass(((TypeInsnNode)insns3[2]).desc);
@ -239,7 +234,7 @@ public class LegacyTweak extends Tweak {
insn = getField;
}
}
insn = insn.getNext();
insn = nextInsn(insn);
}
break;
}
@ -375,14 +370,6 @@ public class LegacyTweak extends Tweak {
AbstractInsnNode insn = insnList.getFirst();
while(insn != null) {
AbstractInsnNode[] insns = fill(insn, 6);
if(mcDir != null && launch.gameDir.get() != null
&& compareInsn(insns[1], PUTFIELD, minecraft.name, mcDir.name, mcDir.desc)
&& compareInsn(insns[0], ALOAD)) {
insnList.remove(insns[0]);
insnList.insertBefore(insns[1], getGameDirectory());
insn = insns[1];
}
if(iLabel == null
&& compareInsn(insns[0], ALOAD)
&& compareInsn(insns[1], GETFIELD, minecraft.name, null, "Ljava/awt/Canvas;")
@ -505,7 +492,7 @@ public class LegacyTweak extends Tweak {
mouseHelperName = found ? ((MethodInsnNode)insns[2]).owner : ((MethodInsnNode)insns[4]).owner;
}
}
insn = insn.getNext();
insn = nextInsn(insn);
}
if(afterLabel != null
@ -637,70 +624,39 @@ public class LegacyTweak extends Tweak {
debugInfo("Replaced height");
}
}
insn = insn.getNext();
insn = nextInsn(insn);
}
int thisIndex = 0;
if(width != null && height != null) {
if(!widthReplaced) {
insert.add(new VarInsnNode(ALOAD, 0));
insert.add(new VarInsnNode(ALOAD, thisIndex));
insert.add(intInsn(launch.width.get()));
insert.add(new FieldInsnNode(PUTFIELD, minecraft.name, width.name, width.desc));
debugInfo("Set initial width");
}
if(!heightReplaced) {
insert.add(new VarInsnNode(ALOAD, 0));
insert.add(new VarInsnNode(ALOAD, thisIndex));
insert.add(intInsn(launch.height.get()));
insert.add(new FieldInsnNode(PUTFIELD, minecraft.name, height.name, height.desc));
debugInfo("Set initial height");
}
}
if(!fullscreenReplaced) {
insert.add(new VarInsnNode(ALOAD, 0));
if(!fullscreenReplaced && fullscreenField != null) {
insert.add(new VarInsnNode(ALOAD, thisIndex));
insert.add(booleanInsn(launch.fullscreen.get()));
insert.add(new FieldInsnNode(PUTFIELD, minecraft.name, fullscreenField.name, fullscreenField.desc));
debugInfo("Set fullscreen");
}
if(defaultWidth != null && defaultHeight != null) {
debugInfo("Set default width and height");
insert.add(new VarInsnNode(ALOAD, 0));
insert.add(new VarInsnNode(ALOAD, thisIndex));
insert.add(intInsn(launch.width.get()));
insert.add(new FieldInsnNode(PUTFIELD, minecraft.name, defaultWidth.name, defaultWidth.desc));
insert.add(new VarInsnNode(ALOAD, 0));
insert.add(new VarInsnNode(ALOAD, thisIndex));
insert.add(intInsn(launch.height.get()));
insert.add(new FieldInsnNode(PUTFIELD, minecraft.name, defaultHeight.name, defaultHeight.desc));
}
if(appletMode != null) {
insert.add(new VarInsnNode(ALOAD, 0));
insert.add(booleanInsn(launch.applet.get()));
insert.add(new FieldInsnNode(PUTFIELD, minecraft.name, appletMode.name, appletMode.desc));
}
if(minecraftUri != null) {
insert.add(new VarInsnNode(ALOAD, 0));
insert.add(new LdcInsnNode("www.minecraft.net"));
insert.add(new FieldInsnNode(PUTFIELD, minecraft.name, minecraftUri.name, minecraftUri.desc));
}
if(user != null) {
insert.add(new VarInsnNode(ALOAD, 0));
insert.add(new TypeInsnNode(NEW, user.name));
insert.add(new InsnNode(DUP));
insert.add(new LdcInsnNode(launch.username.get()));
insert.add(new LdcInsnNode(launch.sessionid.get()));
insert.add(new MethodInsnNode(INVOKESPECIAL, user.name, "<init>", "(Ljava/lang/String;Ljava/lang/String;)V"));
insert.add(new FieldInsnNode(PUTFIELD, minecraft.name, userField.name, userField.desc));
}
if(hasPaid != null) {
insert.add(new VarInsnNode(ALOAD, 0));
insert.add(new FieldInsnNode(GETFIELD, minecraft.name, userField.name, userField.desc));
insert.add(booleanInsn(launch.haspaid.get()));
insert.add(new FieldInsnNode(PUTFIELD, hasPaid.owner, hasPaid.name, hasPaid.desc));
}
if(setDemo != null) {
insert.add(new VarInsnNode(ALOAD, 0));
insert.add(booleanInsn(launch.demo.get()));
insert.add(new MethodInsnNode(INVOKEVIRTUAL, minecraft.name, setDemo.name, setDemo.desc));
}
insert.add(new InsnNode(ICONST_0));
insert.add(new MethodInsnNode(INVOKESTATIC, "javax/imageio/ImageIO", "setUseCache", "(Z)V"));
m.instructions.insertBefore(getLastReturn(m.instructions.getLast()), insert);
m.instructions.insert(getSuper(m.instructions.getFirst()), insert);
}
}
}
@ -755,7 +711,7 @@ public class LegacyTweak extends Tweak {
dy = putfield.name;
}
}
insn = insn.getNext();
insn = nextInsn(insn);
}
continue method;
}
@ -764,7 +720,7 @@ public class LegacyTweak extends Tweak {
setGrabbed = m;
continue method;
}
insn = insn.getNext();
insn = nextInsn(insn);
}
}
if(setDelta != null && setGrabbed != null && dx != null && dy != null) {
@ -855,7 +811,7 @@ public class LegacyTweak extends Tweak {
break method;
}
}
insn = insn.getNext();
insn = nextInsn(insn);
}
}
if(success) {
@ -915,7 +871,7 @@ public class LegacyTweak extends Tweak {
m.instructions.remove(insns[1]);
m.instructions.remove(insns[2]);
}
insn = insn.getNext();
insn = nextInsn(insn);
}
}
}
@ -942,7 +898,7 @@ public class LegacyTweak extends Tweak {
if(insn.getOpcode() == INVOKESTATIC) {
return;
}
insn = insn.getNext();
insn = nextInsn(insn);
}
}
}
@ -1118,11 +1074,11 @@ public class LegacyTweak extends Tweak {
}
}
}
insn = insn.getNext();
insn = nextInsn(insn);
}
break;
}
insn = insn.getNext();
insn = nextInsn(insn);
}
return run;
}
@ -1149,7 +1105,14 @@ public class LegacyTweak extends Tweak {
final String listenerClass = "org/mcphackers/launchwrapper/inject/WindowListener";
String mcField = null;
String mcDesc = "L" + minecraft.name + ";";
if(minecraftApplet != null) {
for(FieldNode field : minecraftApplet.fields) {
if(mcDesc.equals(field.desc)) {
mcField = field.name;
}
}
insns.add(new TypeInsnNode(NEW, minecraftApplet.name));
insns.add(new InsnNode(DUP));
insns.add(new MethodInsnNode(INVOKESPECIAL, minecraftApplet.name, "<init>", "()V"));
@ -1157,6 +1120,9 @@ public class LegacyTweak extends Tweak {
insns.add(new VarInsnNode(ALOAD, appletIndex));
insns.add(new MethodInsnNode(INVOKESTATIC, "org/mcphackers/launchwrapper/inject/Inject", "getApplet", "()Lorg/mcphackers/launchwrapper/tweak/AppletWrapper;"));
insns.add(new MethodInsnNode(INVOKEVIRTUAL, "java/applet/Applet", "setStub", "(Ljava/applet/AppletStub;)V"));
insns.add(new VarInsnNode(ALOAD, appletIndex));
insns.add(new MethodInsnNode(INVOKEVIRTUAL, minecraftApplet.name, "init", "()V"));
patchAppletInit();
}
if(!launch.lwjglFrame.get()) {
insns.add(new TypeInsnNode(NEW, "java/awt/Frame"));
@ -1193,17 +1159,79 @@ public class LegacyTweak extends Tweak {
insns.add(new InsnNode(ACONST_NULL));
insns.add(new MethodInsnNode(INVOKEVIRTUAL, "java/awt/Frame", "setLocationRelativeTo", "(Ljava/awt/Component;)V"));
}
insns.add(getMinecraftImpl());
if(minecraftApplet != null) {
insns.add(new VarInsnNode(ALOAD, appletIndex));
insns.add(new FieldInsnNode(GETFIELD, minecraftApplet.name, mcField, mcDesc));
} else {
insns.add(getNewMinecraftImpl(minecraft, null));
}
insns.add(new VarInsnNode(ASTORE, mcIndex));
if(width != null && height != null) {
insns.add(new VarInsnNode(ALOAD, mcIndex));
insns.add(intInsn(launch.width.get()));
insns.add(new FieldInsnNode(PUTFIELD, minecraft.name, width.name, width.desc));
insns.add(new VarInsnNode(ALOAD, mcIndex));
insns.add(intInsn(launch.height.get()));
insns.add(new FieldInsnNode(PUTFIELD, minecraft.name, height.name, height.desc));
}
if(fullscreenField != null) {
insns.add(new VarInsnNode(ALOAD, mcIndex));
insns.add(booleanInsn(launch.fullscreen.get()));
insns.add(new FieldInsnNode(PUTFIELD, minecraft.name, fullscreenField.name, fullscreenField.desc));
}
if(defaultWidth != null && defaultHeight != null) {
insns.add(new VarInsnNode(ALOAD, mcIndex));
insns.add(intInsn(launch.width.get()));
insns.add(new FieldInsnNode(PUTFIELD, minecraft.name, defaultWidth.name, defaultWidth.desc));
insns.add(new VarInsnNode(ALOAD, mcIndex));
insns.add(intInsn(launch.height.get()));
insns.add(new FieldInsnNode(PUTFIELD, minecraft.name, defaultHeight.name, defaultHeight.desc));
}
if(appletMode != null) {
insns.add(new VarInsnNode(ALOAD, mcIndex));
insns.add(booleanInsn(launch.applet.get()));
insns.add(new FieldInsnNode(PUTFIELD, minecraft.name, appletMode.name, appletMode.desc));
}
// if(minecraftUri != null) {
// insns.add(new VarInsnNode(ALOAD, mcIndex));
// insns.add(new LdcInsnNode("www.minecraft.net"));
// insns.add(new FieldInsnNode(PUTFIELD, minecraft.name, minecraftUri.name, minecraftUri.desc));
// }
// if(user != null) {
// insns.add(new VarInsnNode(ALOAD, mcIndex));
// insns.add(new TypeInsnNode(NEW, user.name));
// insns.add(new InsnNode(DUP));
// insns.add(new LdcInsnNode(launch.username.get()));
// insns.add(new LdcInsnNode(launch.sessionid.get()));
// insns.add(new MethodInsnNode(INVOKESPECIAL, user.name, "<init>", "(Ljava/lang/String;Ljava/lang/String;)V"));
// insns.add(new FieldInsnNode(PUTFIELD, minecraft.name, userField.name, userField.desc));
// }
// if(hasPaid != null) {
// insns.add(new VarInsnNode(ALOAD, mcIndex));
// insns.add(new FieldInsnNode(GETFIELD, minecraft.name, userField.name, userField.desc));
// insns.add(booleanInsn(launch.haspaid.get()));
// insns.add(new FieldInsnNode(PUTFIELD, hasPaid.owner, hasPaid.name, hasPaid.desc));
// }
// if(setDemo != null) {
// insns.add(new VarInsnNode(ALOAD, mcIndex));
// insns.add(booleanInsn(launch.demo.get()));
// insns.add(new MethodInsnNode(INVOKEVIRTUAL, minecraft.name, setDemo.name, setDemo.desc));
// }
// if(setServer != null && launch.server.get() != null) {
// insns.add(new VarInsnNode(ALOAD, mcIndex));
// insns.add(new LdcInsnNode(launch.server.get()));
// insns.add(intInsn(launch.port.get()));
// insns.add(new MethodInsnNode(INVOKEVIRTUAL, minecraft.name, setServer.name, setServer.desc));
// }
insns.add(new TypeInsnNode(NEW, "java/lang/Thread"));
insns.add(new InsnNode(DUP));
insns.add(new VarInsnNode(ALOAD, mcIndex));
insns.add(new LdcInsnNode("Minecraft main thread"));
insns.add(new MethodInsnNode(INVOKESPECIAL, "java/lang/Thread", "<init>", "(Ljava/lang/Runnable;Ljava/lang/String;)V"));
insns.add(new VarInsnNode(ASTORE, threadIndex));
insns.add(new VarInsnNode(ALOAD, threadIndex));
insns.add(new IntInsnNode(BIPUSH, 10));
insns.add(new MethodInsnNode(INVOKEVIRTUAL, "java/lang/Thread", "setPriority", "(I)V"));
// insns.add(new VarInsnNode(ALOAD, threadIndex));
// insns.add(new IntInsnNode(BIPUSH, 10));
// insns.add(new MethodInsnNode(INVOKEVIRTUAL, "java/lang/Thread", "setPriority", "(I)V"));
if(!launch.lwjglFrame.get()) {
insns.add(new VarInsnNode(ALOAD, frameIndex));
insns.add(new InsnNode(ICONST_1));
@ -1224,6 +1252,75 @@ public class LegacyTweak extends Tweak {
return node;
}
private void patchAppletInit() {
String mcField = null;
String canvasField = null;
String mcDesc = "L" + minecraft.name + ";";
MethodNode init = InjectUtils.getMethod(minecraftApplet, "init", "()V");
if(init == null) {
throw new IllegalStateException("Missing applet init");
}
for(FieldNode field : minecraftApplet.fields) {
if(mcDesc.equals(field.desc)) {
field.access = Access.PUBLIC.setAccess(field.access);
mcField = field.name;
}
if("Ljava/awt/Canvas;".equals(field.desc)) {
canvasField = field.name;
}
}
AbstractInsnNode insn = init.instructions.getFirst();
while(insn != null) {
AbstractInsnNode[] insns2 = fill(insn, 5);
if(compareInsn(insns2[1], PUTFIELD, minecraftApplet.name, mcField, mcDesc)
&& compareInsn(insns2[0], INVOKESPECIAL, null, "<init>")) {
MethodInsnNode invoke = (MethodInsnNode)insns2[0];
init.instructions.insertBefore(insns2[1], getNewMinecraftImpl(source.getClass(invoke.owner), canvasField));
IdentifyCall call = new IdentifyCall(invoke);
AbstractInsnNode newInsn = call.getArgument(0)[0].getPrevious();
if(newInsn.getOpcode() == NEW) {
init.instructions.remove(newInsn);
}
for(AbstractInsnNode[] arg : call.getArguments()) {
remove(init.instructions, arg);
}
init.instructions.remove(invoke);
insn = insns2[1];
}
if(compareInsn(insns2[0], ALOAD, 0)
&& compareInsn(insns2[1], GETFIELD, minecraftApplet.name, mcField, mcDesc)
&& compareInsn(insns2[2], LDC, "79.136.77.240")
&& compareInsn(insns2[3], SIPUSH)
&& compareInsn(insns2[4], INVOKEVIRTUAL, minecraft.name, null, "(Ljava/lang/String;I)V")) {
LabelNode label = new LabelNode();
init.instructions.remove(insns2[2]);
init.instructions.remove(insns2[3]);
InsnList insert = new InsnList();
insert.add(new VarInsnNode(ALOAD, 0));
insert.add(new LdcInsnNode("server"));
insert.add(new MethodInsnNode(INVOKEVIRTUAL, minecraftApplet.name, "getParameter", "(Ljava/lang/String;)Ljava/lang/String;"));
insert.add(new VarInsnNode(ALOAD, 0));
insert.add(new LdcInsnNode("port"));
insert.add(new MethodInsnNode(INVOKEVIRTUAL, minecraftApplet.name, "getParameter", "(Ljava/lang/String;)Ljava/lang/String;"));
insert.add(new MethodInsnNode(INVOKESTATIC, "java/lang/Integer", "parseInt", "(Ljava/lang/String;)I"));
init.instructions.insertBefore(insns2[4], insert);
insert = new InsnList();
insert.add(new VarInsnNode(ALOAD, 0));
insert.add(new LdcInsnNode("server"));
insert.add(new MethodInsnNode(INVOKEVIRTUAL, minecraftApplet.name, "getParameter", "(Ljava/lang/String;)Ljava/lang/String;"));
insert.add(new JumpInsnNode(IFNULL, label));
insert.add(new VarInsnNode(ALOAD, 0));
insert.add(new LdcInsnNode("port"));
insert.add(new MethodInsnNode(INVOKEVIRTUAL, minecraftApplet.name, "getParameter", "(Ljava/lang/String;)Ljava/lang/String;"));
insert.add(new JumpInsnNode(IFNULL, label));
init.instructions.insertBefore(insns2[0], insert);
init.instructions.insert(insns2[4], label);
}
insn = nextInsn(insn);
}
source.overrideClass(minecraftApplet);
}
private void createWindowListener(String listenerClass) {
running.access = Access.PUBLIC.setAccess(running.access);
@ -1275,7 +1372,7 @@ public class LegacyTweak extends Tweak {
source.overrideClass(node);
}
private InsnList getMinecraftImpl() {
private InsnList getNewMinecraftImpl(ClassNode minecraftImpl, String canvasField) {
MethodNode init = null;
for(MethodNode m : minecraftImpl.methods) {
if(m.name.equals("<init>")) {
@ -1286,9 +1383,9 @@ public class LegacyTweak extends Tweak {
throw new NullPointerException();
}
final int appletIndex = 1;
final int frameIndex = 2;
final int canvasIndex = 3;
// final int appletIndex = 1;
// final int frameIndex = 2;
// final int canvasIndex = 3;
InsnList insns = new InsnList();
insns.add(new TypeInsnNode(NEW, minecraftImpl.name));
@ -1303,16 +1400,19 @@ public class LegacyTweak extends Tweak {
if(launch.lwjglFrame.get()) {
insns.add(new InsnNode(ACONST_NULL));
} else {
insns.add(new VarInsnNode(ALOAD, canvasIndex));
//insns.add(new VarInsnNode(ALOAD, canvasIndex));
insns.add(new VarInsnNode(ALOAD, 0));
insns.add(new FieldInsnNode(GETFIELD, minecraftApplet.name, canvasField, "Ljava/awt/Canvas;"));
}
} else if(desc.equals("Ljava/awt/Component;")) {
if(launch.lwjglFrame.get()) {
insns.add(new InsnNode(ACONST_NULL));
} else {
insns.add(new VarInsnNode(ALOAD, frameIndex));
//insns.add(new VarInsnNode(ALOAD, frameIndex));
}
} else if(minecraftApplet != null && desc.equals("L" + minecraftApplet.name + ";")) {
insns.add(new VarInsnNode(ALOAD, appletIndex));
//insns.add(new VarInsnNode(ALOAD, appletIndex));
insns.add(new VarInsnNode(ALOAD, 0));
}
else if(desc.equals("I")) {
if(i == 0) {
@ -1333,16 +1433,25 @@ public class LegacyTweak extends Tweak {
return insns;
}
public void fixSplash() {
private void fixSplash() {
for(MethodNode m : minecraft.methods) {
for(AbstractInsnNode insn : m.instructions) {
if(insn.getOpcode() == LDC) {
LdcInsnNode ldc = (LdcInsnNode)insn;
if(ldc.cst.equals("/title/mojang.png")) {
AbstractInsnNode insn3 = ldc.getNext();
boolean store2 = false;
boolean store3 = false;
while(insn3 != null) {
AbstractInsnNode[] insns2 = fill(insn3, 15);
if(compareInsn(insns2[0], ALOAD)
if(compareInsn(insns2[0], ISTORE, 2)) {
store2 = true;
}
if(compareInsn(insns2[0], ISTORE, 3)) {
store3 = true;
}
if(store2 && store3
&& compareInsn(insns2[0], ALOAD)
&& compareInsn(insns2[1], GETFIELD, null, null, "I")
&& compareInsn(insns2[2], ICONST_2)
&& compareInsn(insns2[3], IDIV)
@ -1477,10 +1586,11 @@ public class LegacyTweak extends Tweak {
}
break;
}
insn = insn.getNext();
insn = nextInsn(insn);
}
}
@Deprecated
private void fixPaulscode() {
ClassNode libraryOpenAL = source.getClass("paulscode/sound/libraries/LibraryLWJGLOpenAL");
ClassNode libraryChannel = source.getClass("paulscode/sound/libraries/ChannelLWJGLOpenAL");
@ -1543,7 +1653,7 @@ public class LegacyTweak extends Tweak {
success |= true;
break;
}
insn = insn.getNext();
insn = nextInsn(insn);
}
boolean bufferBufferField = false;
insn = queueBuffer.instructions.getFirst();
@ -1580,7 +1690,7 @@ public class LegacyTweak extends Tweak {
success |= true;
break;
}
insn = insn.getNext();
insn = nextInsn(insn);
}
insn = preLoadBuffers.instructions.getFirst();
while(insn != null) {
@ -1622,7 +1732,7 @@ public class LegacyTweak extends Tweak {
success |= true;
break;
}
insn = insn.getNext();
insn = nextInsn(insn);
}
if(bufferBufferField) {
if(InjectUtils.getField(libraryChannel, "bufferBuffer", "Ljava/nio/ByteBuffer;") == null) {
@ -1639,7 +1749,7 @@ public class LegacyTweak extends Tweak {
success |= true;
break;
}
insn = insn.getNext();
insn = nextInsn(insn);
}
}
}
@ -1670,7 +1780,7 @@ public class LegacyTweak extends Tweak {
}
break;
}
insn = insn.getNext();
insn = nextInsn(insn);
}
}
}
@ -1699,120 +1809,38 @@ public class LegacyTweak extends Tweak {
}
}
for(MethodNode method : minecraftApplet.methods) {
if("init".equals(method.name) && "()V".equals(method.desc)) {
AbstractInsnNode insn = method.instructions.getFirst();
while(insn != null) {
AbstractInsnNode[] insns = fillBackwards(insn, 9);
if(compareInsn(insns[0], ALOAD)
&& compareInsn(insns[1], GETFIELD, minecraftApplet.name, mcField, mcDesc)
&& compareInsn(insns[2], ALOAD)
&& compareInsn(insns[3], INVOKEVIRTUAL, minecraftApplet.name, "getDocumentBase", "()Ljava/net/URL;")
&& compareInsn(insns[4], INVOKEVIRTUAL, "java/net/URL", "getHost", "()Ljava/lang/String;")
&& compareInsn(insns[5], PUTFIELD, minecraft.name, null, "Ljava/lang/String;")) {
FieldInsnNode field = (FieldInsnNode)insns[5];
minecraftUri = InjectUtils.getField(minecraft, field.name, field.desc);
}
if(compareInsn(insns[1], PUTFIELD, minecraftApplet.name, mcField, mcDesc)
&& compareInsn(insns[0], INVOKESPECIAL, null, "<init>")) {
MethodInsnNode invoke = (MethodInsnNode)insns[0];
minecraftImpl = source.getClass(invoke.owner);
}
if(compareInsn(insns[0], ALOAD)
&& compareInsn(insns[1], GETFIELD, minecraftApplet.name, mcField, mcDesc)
&& compareInsn(insns[2], ICONST_1)
&& compareInsn(insns[3], PUTFIELD, minecraft.name, null, "Z")) {
FieldInsnNode field = (FieldInsnNode)insns[3];
MethodNode init = InjectUtils.getMethod(minecraftApplet, "init", "()V");
if(init != null) {
AbstractInsnNode insn = init.instructions.getFirst();
while(insn != null) {
AbstractInsnNode[] insns = fillBackwards(insn, 8);
if(compareInsn(insns[0], ALOAD)
&& compareInsn(insns[1], GETFIELD, minecraftApplet.name, mcField, mcDesc)
&& compareInsn(insns[2], ICONST_1)
&& compareInsn(insns[3], PUTFIELD, minecraft.name, null, "Z")) {
FieldInsnNode field = (FieldInsnNode)insns[3];
appletMode = InjectUtils.getField(minecraft, field.name, field.desc);
}
if(compareInsn(insns[0], ALOAD)
&& compareInsn(insns[1], GETFIELD, minecraftApplet.name, mcField, mcDesc)
&& compareInsn(insns[2], LDC, "true")
&& compareInsn(insns[3], ALOAD)
&& compareInsn(insns[4], LDC, "stand-alone")
&& compareInsn(insns[5], INVOKEVIRTUAL, minecraftApplet.name, "getParameter", "(Ljava/lang/String;)Ljava/lang/String;")
&& compareInsn(insns[6], INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z")) {
AbstractInsnNode[] insns2 = fill(insns[7], 7);
if(compareInsn(insns2[0], IFNE)
&& compareInsn(insns2[1], ICONST_1)
&& compareInsn(insns2[2], GOTO)
&& compareInsn(insns2[3], ICONST_0)
&& compareInsn(insns2[4], PUTFIELD, minecraft.name, null, "Z")) {
FieldInsnNode field = (FieldInsnNode)insns2[4];
appletMode = InjectUtils.getField(minecraft, field.name, field.desc);
}
if(compareInsn(insns[0], ALOAD)
&& compareInsn(insns[1], GETFIELD, minecraftApplet.name, mcField, mcDesc)
&& compareInsn(insns[2], LDC, "true")
&& compareInsn(insns[3], ALOAD)
&& compareInsn(insns[4], LDC, "stand-alone")
&& compareInsn(insns[5], INVOKEVIRTUAL, minecraftApplet.name, "getParameter", "(Ljava/lang/String;)Ljava/lang/String;")
&& compareInsn(insns[6], INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z")) {
AbstractInsnNode[] insns2 = fill(insns[7], 7);
if(compareInsn(insns2[0], IFNE)
&& compareInsn(insns2[1], ICONST_1)
&& compareInsn(insns2[2], GOTO)
&& compareInsn(insns2[3], ICONST_0)
&& compareInsn(insns2[4], PUTFIELD, minecraft.name, null, "Z")) {
FieldInsnNode field = (FieldInsnNode)insns2[4];
appletMode = InjectUtils.getField(minecraft, field.name, field.desc);
}
}
if(compareInsn(insns[0], ALOAD)
&& compareInsn(insns[1], GETFIELD, minecraftApplet.name, mcField, mcDesc)
&& compareInsn(insns[2], GETFIELD, minecraft.name)
&& compareInsn(insns[3], LDC, "true")
&& compareInsn(insns[4], ALOAD)
&& compareInsn(insns[5], LDC, "haspaid")
&& compareInsn(insns[6], INVOKEVIRTUAL, minecraftApplet.name, "getParameter", "(Ljava/lang/String;)Ljava/lang/String;")
&& compareInsn(insns[7], INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z")
&& compareInsn(insns[8], PUTFIELD, null, null, "Z")) {
hasPaid = (FieldInsnNode)insns[8];
}
if(compareInsn(insns[0], ALOAD)
&& compareInsn(insns[1], GETFIELD, minecraftApplet.name, mcField, mcDesc)
&& compareInsn(insns[2], LDC, "true")
&& compareInsn(insns[3], ALOAD)
&& compareInsn(insns[4], LDC, "demo")
&& compareInsn(insns[5], INVOKEVIRTUAL, minecraftApplet.name, "getParameter", "(Ljava/lang/String;)Ljava/lang/String;")
&& compareInsn(insns[6], INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z")
&& compareInsn(insns[7], INVOKEVIRTUAL, minecraft.name, null, "(Z)V")) {
MethodInsnNode call = (MethodInsnNode)insns[7];
setDemo = InjectUtils.getMethod(minecraft, call.name, call.desc);
}
if(compareInsn(insns[0], ALOAD)
&& compareInsn(insns[1], LDC, "username")
&& compareInsn(insns[2], INVOKEVIRTUAL, minecraftApplet.name, "getParameter", "(Ljava/lang/String;)Ljava/lang/String;")
&& compareInsn(insns[3], ALOAD)
&& compareInsn(insns[4], LDC, "sessionid")
&& compareInsn(insns[5], INVOKEVIRTUAL, minecraftApplet.name, "getParameter", "(Ljava/lang/String;)Ljava/lang/String;")
&& compareInsn(insns[6], INVOKESPECIAL, null, "<init>", "(Ljava/lang/String;Ljava/lang/String;)V")
&& compareInsn(insns[7], PUTFIELD, minecraft.name)) {
debugInfo("Found user field");
MethodInsnNode invokespecial = (MethodInsnNode)insns[6];
user = source.getClass(invokespecial.owner);
FieldInsnNode field = (FieldInsnNode)insns[7];
userField = InjectUtils.getField(minecraft, field.name, field.desc);
}
else
if(compareInsn(insns[0], ALOAD)
&& compareInsn(insns[1], LDC, "username")
&& compareInsn(insns[2], INVOKEVIRTUAL, minecraftApplet.name, "getParameter", "(Ljava/lang/String;)Ljava/lang/String;")
&& compareInsn(insns[3], LDC)
&& compareInsn(insns[4], INVOKESPECIAL, null, "<init>", "(Ljava/lang/String;Ljava/lang/String;)V")
&& compareInsn(insns[5], PUTFIELD, minecraft.name)) {
debugInfo("Found user field");
MethodInsnNode invokespecial = (MethodInsnNode)insns[6];
user = source.getClass(invokespecial.owner);
FieldInsnNode field = (FieldInsnNode)insns[7];
userField = InjectUtils.getField(minecraft, field.name, field.desc);
}
else
if(compareInsn(insns[0], GETFIELD, minecraftApplet.name, mcField, mcDesc)
&& compareInsn(insns[1], NEW)
&& compareInsn(insns[2], DUP)
&& compareInsn(insns[3], INVOKESPECIAL, null, "<init>")) {
if(compareInsn(insns[4], PUTFIELD, minecraft.name)) {
FieldInsnNode field = (FieldInsnNode)insns[4];
if(field.desc.startsWith("L") && field.desc.endsWith(";")) {
debugInfo("Found user field");
user = source.getClass(field.desc.substring(1, field.desc.length() - 1));
userField = InjectUtils.getField(minecraft, field.name, field.desc);
}
}
}
insn = insn.getNext();
}
}
}
}
if(minecraftImpl == null) {
minecraftImpl = minecraft;
}
insn = nextInsn(insn);
}
}
}
}
@ -1879,7 +1907,46 @@ public class LegacyTweak extends Tweak {
return insns;
}
public void replaceGameDirectory(FieldNode mcDir) {
public void replaceGameDirectory(MethodNode init, FieldNode mcDir) {
InsnList insnList = init.instructions;
AbstractInsnNode insn = insnList.getFirst();
while(insn != null) {
AbstractInsnNode[] insns = fill(insn, 6);
// Indev game dir patch
if(mcDir != null && launch.gameDir.get() != null
&& compareInsn(insns[1], PUTFIELD, minecraft.name, mcDir.name, mcDir.desc)
&& compareInsn(insns[0], ALOAD)) {
insnList.remove(insns[0]);
insnList.insertBefore(insns[1], getGameDirectory());
insn = insns[1];
debugInfo("Replaced gameDir");
}
// Classic game dir patch
if(mcDir == null
&& compareInsn(insns[0], ALOAD)
&& compareInsn(insns[1], INVOKEVIRTUAL, "java/io/File", "exists", "()Z")
&& compareInsn(insns[2], IFNE)
&& compareInsn(insns[3], ALOAD)
&& compareInsn(insns[4], INVOKEVIRTUAL, "java/io/File", "mkdirs", "()Z")
&& compareInsn(insns[5], IFNE)) {
LabelNode lbl = ((JumpInsnNode)insns[2]).label;
int index = ((VarInsnNode)insns[0]).var;
if(lbl == ((JumpInsnNode)insns[5]).label
&& index == ((VarInsnNode)insns[3]).var) {
AbstractInsnNode[] insns2 = fill(nextInsn(lbl), 2);
if(compareInsn(insns2[0], ALOAD)
&& compareInsn(insns2[1], ASTORE)) {
if(index == ((VarInsnNode)insns2[0]).var) {
insnList.remove(insns2[0]);
insnList.insertBefore(insns2[1], getGameDirectory());
debugInfo("Replaced gameDir");
}
}
}
}
insn = nextInsn(insn);
}
if(mcDir != null && launch.gameDir.get() != null) {
if(InjectUtils.isStatic(mcDir)) {
MethodNode clinit = InjectUtils.getMethod(minecraft, "<clinit>", "()V");

View file

@ -6,6 +6,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.HashMap;
@ -75,6 +76,15 @@ public final class Util {
return buffer.toByteArray();
}
public static URL replaceHost(URL url, String hostName, int port) {
try {
return new URL(url.getProtocol(), hostName, port, url.getFile());
} catch (MalformedURLException e) {
e.printStackTrace();
return null;
}
}
public static Map<String, String> queryMap(URL url) throws UnsupportedEncodingException {
Map<String, String> queryMap = new HashMap<String, String>();
String query = url.getQuery();

View file

@ -0,0 +1,91 @@
package org.mcphackers.rdi.util;
import static org.mcphackers.rdi.util.InsnHelper.range;
import static org.mcphackers.rdi.util.InsnHelper.remove;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.MethodInsnNode;
public class IdentifyCall {
protected MethodInsnNode invokeInsn;
protected List<AbstractInsnNode[]> arguments;
public IdentifyCall(MethodInsnNode invoke) {
invokeInsn = invoke;
arguments = initArguments();
}
private List<AbstractInsnNode[]> initArguments() {
boolean isStatic = invokeInsn.getOpcode() == Opcodes.INVOKESTATIC;
Type[] argTypes = Type.getArgumentTypes(invokeInsn.desc);
List<AbstractInsnNode[]> args = new ArrayList<AbstractInsnNode[]>(argTypes.length);
if(argTypes.length == 0) {
return Collections.emptyList();
}
AbstractInsnNode insn = invokeInsn.getPrevious();
AbstractInsnNode start = null;
AbstractInsnNode end = insn;
for(int currentArg = argTypes.length - 1; currentArg >= 0; currentArg--) {
int stack = argTypes[currentArg].getSize();
end = insn;
while(stack > 0) {
stack -= OPHelper.getStackSizeDelta(insn);
if(stack == 0) {
start = insn;
}
insn = insn.getPrevious();
}
if(start != null) {
while(args.size() <= currentArg) {
args.add(null);
}
args.set(currentArg, range(start, end));
}
}
if(!isStatic) {
int stack = 1;
end = insn;
while(stack > 0) {
stack -= OPHelper.getStackSizeDelta(insn);
if(stack == 0) {
start = insn;
}
insn = insn.getPrevious();
}
args.add(0, range(start, end));
}
return args;
}
/**
* Returns a collection of insn node arrays with each argument
* Non-static methods include the owner of a call at index 0
* @return
*/
public List<AbstractInsnNode[]> getArguments() {
return Collections.unmodifiableList(arguments);
}
/**
* Returns an array of insn nodes belonging to the argument at that index
* Non-static methods include the owner of a call at index 0
* @return
*/
public AbstractInsnNode[] getArgument(int index) {
return arguments.get(index);
}
public static void removeCall(InsnList insns, MethodInsnNode invoke) {
for(AbstractInsnNode[] arg : new IdentifyCall(invoke).getArguments()) {
remove(insns, arg);
}
insns.remove(invoke);
}
}

View file

@ -0,0 +1,236 @@
package org.mcphackers.rdi.util;
import static org.objectweb.asm.Opcodes.*;
import static org.objectweb.asm.tree.AbstractInsnNode.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.IntInsnNode;
import org.objectweb.asm.tree.JumpInsnNode;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.TryCatchBlockNode;
import org.objectweb.asm.tree.VarInsnNode;
public class InsnHelper {
public static AbstractInsnNode[] fill(AbstractInsnNode insn, int size) {
AbstractInsnNode[] arr = new AbstractInsnNode[size];
int i = 0;
while(insn != null && i < size) {
arr[i] = insn;
insn = insn.getNext();
i++;
}
return arr;
}
public static void removeRange(InsnList insns, AbstractInsnNode first, AbstractInsnNode last) {
if(first == null || last == null) {
return;
}
AbstractInsnNode next = first;
while(next != null && next != last) {
AbstractInsnNode forRemoval = next;
next = next.getNext();
insns.remove(forRemoval);
}
insns.remove(last);
}
public static void remove(InsnList insns, AbstractInsnNode... toRemove) {
for(AbstractInsnNode insn : toRemove) {
insns.remove(insn);
}
}
public static AbstractInsnNode[] range(AbstractInsnNode start, AbstractInsnNode end) {
List<AbstractInsnNode> list = new LinkedList<AbstractInsnNode>();
AbstractInsnNode insn = start;
while(insn != end) {
list.add(insn);
insn = insn.getNext();
}
list.add(end);
AbstractInsnNode[] arr = new AbstractInsnNode[list.size()];
return list.toArray(arr);
}
public static InsnList clone(Iterable<AbstractInsnNode> insnList) {
Map<LabelNode, LabelNode> labels = new HashMap<LabelNode, LabelNode>();
for (AbstractInsnNode insn : insnList) {
if (insn.getType() == LABEL) {
LabelNode label = (LabelNode) insn;
labels.put(label, new LabelNode());
}
}
InsnList destList = new InsnList();
for (AbstractInsnNode insn : insnList) {
AbstractInsnNode insnCopy = insn.clone(labels);
destList.add(insnCopy);
}
return destList;
}
public static InsnList clone(AbstractInsnNode[] insnList) {
return clone(Arrays.asList(insnList));
}
public static LabelNode labelBefore(AbstractInsnNode current) {
current = current.getPrevious();
while(current.getType() == LINE) { // Skip line number nodes
current = current.getPrevious();
}
if(current.getType() == LABEL) {
return (LabelNode)current;
}
return null;
}
public static AbstractInsnNode nextInsn(AbstractInsnNode current) {
while((current = current.getNext()) != null && current.getOpcode() == -1);
return current;
}
public static AbstractInsnNode previousInsn(AbstractInsnNode current) {
while((current = current.getPrevious()) != null && current.getOpcode() == -1);
return current;
}
public static boolean containsInvoke(InsnList insns, MethodInsnNode invoke) {
for(AbstractInsnNode insn : insns) {
if(insn.getType() == METHOD_INSN) {
MethodInsnNode invoke2 = (MethodInsnNode)insn;
if(invoke2.getOpcode() == invoke.getOpcode() && invoke2.owner.equals(invoke.owner) && invoke2.name.equals(invoke.name) && invoke2.desc.equals(invoke.desc)) {
return true;
}
}
}
return false;
}
public static void addTryCatch(MethodNode method, AbstractInsnNode startInsn, AbstractInsnNode endInsn, String exception) {
addTryCatch(method, startInsn, endInsn, null, exception);
}
public static void addTryCatch(MethodNode method, AbstractInsnNode startInsn, AbstractInsnNode endInsn, InsnList handle, String exception) {
InsnList instructions = method.instructions;
if(!instructions.contains(startInsn) || !instructions.contains(endInsn)) {
throw new IllegalArgumentException("Instruction does not belong to the list");
}
LabelNode start = new LabelNode();
LabelNode end = new LabelNode();
LabelNode handler = new LabelNode();
LabelNode after = new LabelNode();
instructions.insertBefore(startInsn, start);
InsnList insert = new InsnList();
insert.add(end);
insert.add(new JumpInsnNode(GOTO, after));
insert.add(handler);
if(handle == null) {
insert.add(new InsnNode(POP));
} else {
insert.add(handle);
}
insert.add(after);
instructions.insert(endInsn, insert);
int index = 0; // FIXME Shouldn't be 0 if there are try/catch blocks within the range
method.tryCatchBlocks.add(index, new TryCatchBlockNode(start, end, handler, exception));
}
public static int getFreeIndex(InsnList instructions) {
int lastFree = 1;
AbstractInsnNode insn = instructions.getFirst();
while(insn != null) {
if(insn.getType() == VAR_INSN) {
VarInsnNode var = (VarInsnNode)insn;
lastFree = Math.max(lastFree, var.var + 1); //FIXME 2 if it's a double or long?
}
insn = insn.getNext();
}
return lastFree;
}
public static AbstractInsnNode intInsn(int value) {
switch(value) {
case -1:
return new InsnNode(ICONST_M1);
case 0:
return new InsnNode(ICONST_0);
case 1:
return new InsnNode(ICONST_1);
case 2:
return new InsnNode(ICONST_2);
case 3:
return new InsnNode(ICONST_3);
case 4:
return new InsnNode(ICONST_4);
case 5:
return new InsnNode(ICONST_5);
default:
if(value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
return new IntInsnNode(BIPUSH, value);
}
else if(value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
return new IntInsnNode(SIPUSH, value);
}
else {
return new LdcInsnNode(value);
}
}
}
public static AbstractInsnNode longInsn(long value) {
if(value == 0L) {
return new InsnNode(LCONST_0);
}
else if(value == 1L) {
return new InsnNode(LCONST_1);
}
else {
return new LdcInsnNode(value);
}
}
public static AbstractInsnNode booleanInsn(boolean value) {
return new InsnNode(value ? ICONST_1 : ICONST_0);
}
public static AbstractInsnNode floatInsn(float value) {
if(value == 0F) {
return new InsnNode(FCONST_0);
}
else if(value == 1F) {
return new InsnNode(FCONST_1);
}
else if(value == 2F) {
return new InsnNode(FCONST_2);
}
else {
return new LdcInsnNode(value);
}
}
public static AbstractInsnNode doubleInsn(double value) {
if(value == 0D) {
return new InsnNode(DCONST_0);
}
else if(value == 1D) {
return new InsnNode(DCONST_1);
}
else {
return new LdcInsnNode(value);
}
}
}

View file

@ -0,0 +1,384 @@
package org.mcphackers.rdi.util;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import static org.objectweb.asm.Opcodes.*;
import org.objectweb.asm.Type;
public final class OPHelper {
private static final int[] STACK_SIZE_DELTA = new int[0xFF];
static {
STACK_SIZE_DELTA[NOP] = 0;
STACK_SIZE_DELTA[ACONST_NULL] = 1;
STACK_SIZE_DELTA[ICONST_M1] = 1;
STACK_SIZE_DELTA[ICONST_0] = 1;
STACK_SIZE_DELTA[ICONST_1] = 1;
STACK_SIZE_DELTA[ICONST_2] = 1;
STACK_SIZE_DELTA[ICONST_3] = 1;
STACK_SIZE_DELTA[ICONST_4] = 1;
STACK_SIZE_DELTA[ICONST_5] = 1;
STACK_SIZE_DELTA[LCONST_0] = 2;
STACK_SIZE_DELTA[LCONST_1] = 1;
STACK_SIZE_DELTA[FCONST_0] = 1;
STACK_SIZE_DELTA[FCONST_1] = 1;
STACK_SIZE_DELTA[FCONST_2] = 1;
STACK_SIZE_DELTA[DCONST_0] = 2;
STACK_SIZE_DELTA[DCONST_1] = 2;
STACK_SIZE_DELTA[BIPUSH] = 1;
STACK_SIZE_DELTA[SIPUSH] = 1;
STACK_SIZE_DELTA[LDC] = 1; // special case
STACK_SIZE_DELTA[ILOAD] = 1;
STACK_SIZE_DELTA[LLOAD] = 2;
STACK_SIZE_DELTA[FLOAD] = 1;
STACK_SIZE_DELTA[DLOAD] = 2;
STACK_SIZE_DELTA[ALOAD] = 1;
STACK_SIZE_DELTA[IALOAD] = -1;
STACK_SIZE_DELTA[LALOAD] = 0;
STACK_SIZE_DELTA[FALOAD] = -1;
STACK_SIZE_DELTA[DALOAD] = 0;
STACK_SIZE_DELTA[AALOAD] = -1;
STACK_SIZE_DELTA[BALOAD] = -1;
STACK_SIZE_DELTA[CALOAD] = -1;
STACK_SIZE_DELTA[SALOAD] = -1;
STACK_SIZE_DELTA[ISTORE] = -1;
STACK_SIZE_DELTA[LSTORE] = -2;
STACK_SIZE_DELTA[FSTORE] = -1;
STACK_SIZE_DELTA[DSTORE] = -2;
STACK_SIZE_DELTA[ASTORE] = -1;
STACK_SIZE_DELTA[IASTORE] = -3;
STACK_SIZE_DELTA[LASTORE] = -4;
STACK_SIZE_DELTA[FASTORE] = -3;
STACK_SIZE_DELTA[DASTORE] = -4;
STACK_SIZE_DELTA[AASTORE] = -3;
STACK_SIZE_DELTA[BASTORE] = -3;
STACK_SIZE_DELTA[CASTORE] = -3;
STACK_SIZE_DELTA[SASTORE] = -3;
STACK_SIZE_DELTA[POP] = -1;
STACK_SIZE_DELTA[POP2] = -2;
STACK_SIZE_DELTA[DUP] = 1;
STACK_SIZE_DELTA[DUP_X1] = 1;
STACK_SIZE_DELTA[DUP_X2] = 1;
STACK_SIZE_DELTA[DUP2] = 2;
STACK_SIZE_DELTA[DUP2_X1] = 2;
STACK_SIZE_DELTA[DUP2_X2] = 2;
STACK_SIZE_DELTA[SWAP] = 0;
STACK_SIZE_DELTA[IADD] = -1;
STACK_SIZE_DELTA[LADD] = -2;
STACK_SIZE_DELTA[FADD] = -1;
STACK_SIZE_DELTA[DADD] = -2;
STACK_SIZE_DELTA[ISUB] = -1;
STACK_SIZE_DELTA[LSUB] = -2;
STACK_SIZE_DELTA[FSUB] = -1;
STACK_SIZE_DELTA[DSUB] = -2;
STACK_SIZE_DELTA[IMUL] = -1;
STACK_SIZE_DELTA[LMUL] = -2;
STACK_SIZE_DELTA[FMUL] = -1;
STACK_SIZE_DELTA[DMUL] = -2;
STACK_SIZE_DELTA[IDIV] = -1;
STACK_SIZE_DELTA[LDIV] = -2;
STACK_SIZE_DELTA[FDIV] = -1;
STACK_SIZE_DELTA[DDIV] = -2;
STACK_SIZE_DELTA[IREM] = -1;
STACK_SIZE_DELTA[LREM] = -2;
STACK_SIZE_DELTA[FREM] = -1;
STACK_SIZE_DELTA[DREM] = -2;
STACK_SIZE_DELTA[INEG] = 0;
STACK_SIZE_DELTA[LNEG] = 0;
STACK_SIZE_DELTA[FNEG] = 0;
STACK_SIZE_DELTA[DNEG] = 0;
STACK_SIZE_DELTA[ISHL] = -1;
STACK_SIZE_DELTA[LSHL] = -1;
STACK_SIZE_DELTA[ISHR] = -1;
STACK_SIZE_DELTA[LSHR] = -1;
STACK_SIZE_DELTA[IUSHR] = -1;
STACK_SIZE_DELTA[LUSHR] = -1;
STACK_SIZE_DELTA[IAND] = -1;
STACK_SIZE_DELTA[LAND] = -2;
STACK_SIZE_DELTA[IOR] = -1;
STACK_SIZE_DELTA[LOR] = -2;
STACK_SIZE_DELTA[IXOR] = -1;
STACK_SIZE_DELTA[LXOR] = -2;
STACK_SIZE_DELTA[IINC] = 0;
STACK_SIZE_DELTA[I2L] = 1;
STACK_SIZE_DELTA[I2F] = 0;
STACK_SIZE_DELTA[I2D] = 1;
STACK_SIZE_DELTA[L2I] = -1;
STACK_SIZE_DELTA[L2F] = -1;
STACK_SIZE_DELTA[L2D] = 0;
STACK_SIZE_DELTA[F2I] = 0;
STACK_SIZE_DELTA[F2L] = 1;
STACK_SIZE_DELTA[F2D] = 1;
STACK_SIZE_DELTA[D2I] = -1;
STACK_SIZE_DELTA[D2L] = 0;
STACK_SIZE_DELTA[D2F] = -1;
STACK_SIZE_DELTA[I2B] = 0;
STACK_SIZE_DELTA[I2C] = 0;
STACK_SIZE_DELTA[I2S] = 0;
STACK_SIZE_DELTA[LCMP] = -3;
STACK_SIZE_DELTA[FCMPL] = -1;
STACK_SIZE_DELTA[FCMPG] = -1;
STACK_SIZE_DELTA[DCMPL] = -3;
STACK_SIZE_DELTA[DCMPG] = -3;
STACK_SIZE_DELTA[IFEQ] = -1;
STACK_SIZE_DELTA[IFNE] = -1;
STACK_SIZE_DELTA[IFLT] = -1;
STACK_SIZE_DELTA[IFGE] = -1;
STACK_SIZE_DELTA[IFGT] = -1;
STACK_SIZE_DELTA[IFLE] = -1;
STACK_SIZE_DELTA[IF_ICMPEQ] = -2;
STACK_SIZE_DELTA[IF_ICMPNE] = -2;
STACK_SIZE_DELTA[IF_ICMPLT] = -2;
STACK_SIZE_DELTA[IF_ICMPGE] = -2;
STACK_SIZE_DELTA[IF_ICMPGT] = -2;
STACK_SIZE_DELTA[IF_ICMPLE] = -2;
STACK_SIZE_DELTA[IF_ACMPEQ] = -2;
STACK_SIZE_DELTA[IF_ACMPNE] = -2;
STACK_SIZE_DELTA[GOTO] = 0;
STACK_SIZE_DELTA[JSR] = 1;
STACK_SIZE_DELTA[RET] = 0;
STACK_SIZE_DELTA[TABLESWITCH] = -1;
STACK_SIZE_DELTA[LOOKUPSWITCH] = -1;
STACK_SIZE_DELTA[IRETURN] = -1;
STACK_SIZE_DELTA[LRETURN] = -2;
STACK_SIZE_DELTA[FRETURN] = -1;
STACK_SIZE_DELTA[DRETURN] = -2;
STACK_SIZE_DELTA[ARETURN] = -1;
STACK_SIZE_DELTA[RETURN] = 0;
STACK_SIZE_DELTA[GETSTATIC] = 0; // special case
STACK_SIZE_DELTA[PUTSTATIC] = 0; // special case
STACK_SIZE_DELTA[GETFIELD] = 0; // special case
STACK_SIZE_DELTA[PUTFIELD] = 0; // special case
STACK_SIZE_DELTA[INVOKEVIRTUAL] = 0; // special case
STACK_SIZE_DELTA[INVOKESPECIAL] = 0; // special case
STACK_SIZE_DELTA[INVOKESTATIC] = 0; // special case
STACK_SIZE_DELTA[INVOKEINTERFACE] = 0; // special case
STACK_SIZE_DELTA[INVOKEDYNAMIC] = 0; // special case
STACK_SIZE_DELTA[NEW] = 1;
STACK_SIZE_DELTA[NEWARRAY] = 0;
STACK_SIZE_DELTA[ANEWARRAY] = 0;
STACK_SIZE_DELTA[ARRAYLENGTH] = 0;
STACK_SIZE_DELTA[ATHROW] = 0; // special case
STACK_SIZE_DELTA[CHECKCAST] = 0;
STACK_SIZE_DELTA[INSTANCEOF] = 0;
STACK_SIZE_DELTA[MONITORENTER] = -1;
STACK_SIZE_DELTA[MONITOREXIT] = -1;
STACK_SIZE_DELTA[MULTIANEWARRAY] = 0; // special case
STACK_SIZE_DELTA[IFNULL] = -1;
STACK_SIZE_DELTA[IFNONNULL] = -1;
}
public static final int getStackSizeDelta(AbstractInsnNode insn) {
int opcode = insn.getOpcode();
if(opcode == -1) {
return 0;
}
if(insn.getType() == AbstractInsnNode.LDC_INSN) {
LdcInsnNode ldc = (LdcInsnNode)insn;
if(ldc.cst instanceof Double || ldc.cst instanceof Long) {
return 2;
}
return 1;
}
if(insn.getType() == AbstractInsnNode.METHOD_INSN) {
MethodInsnNode invoke = (MethodInsnNode)insn;
int sizes = Type.getArgumentsAndReturnSizes(invoke.desc);
int argumentSizes = sizes >> 2;
if(opcode == INVOKESTATIC) {
argumentSizes--;
}
int returnSize = sizes & 3;
return returnSize - argumentSizes;
}
if(insn.getType() == AbstractInsnNode.FIELD_INSN) {
FieldInsnNode field = (FieldInsnNode)insn;
int returnSize = Type.getType(field.desc).getSize();
if(opcode == GETSTATIC) {
return returnSize;
}
return returnSize - 1;
}
else if(opcode != ATHROW && opcode != MULTIANEWARRAY && opcode != INVOKEDYNAMIC) {
return STACK_SIZE_DELTA[opcode];
}
throw new IllegalArgumentException("Could not get stack size delta for " + opcode);
}
public static boolean isReturn(int opcode) {
return
opcode == RETURN ||
opcode == IRETURN ||
opcode == LRETURN ||
opcode == FRETURN ||
opcode == DRETURN ||
opcode == ARETURN;
}
public static final boolean isArrayLoad(int opcode) {
switch (opcode) {
case AALOAD:
case BALOAD: // for booleans and bytes
case CALOAD:
case DALOAD:
case FALOAD:
case IALOAD:
case LALOAD:
case SALOAD:
return true;
default:
return false;
}
}
public static final boolean isVarLoad(int opcode) {
switch (opcode) {
case ALOAD:
//case BLOAD: // bytes & booleans are also regular integers
//case CLOAD: // characters are regular integers (?) under the hood
case DLOAD:
case FLOAD:
case ILOAD:
case LLOAD:
//case SLOAD: // and so are shorts
return true;
default:
return false;
}
}
public static final int reverseVarOpcode(int opcode) {
switch (opcode) {
case AALOAD:
return AASTORE;
case BALOAD:
return BASTORE;
case CALOAD:
return CASTORE;
case IALOAD:
return IASTORE;
case SALOAD:
return IASTORE;
case DALOAD:
return IASTORE;
case FALOAD:
return IASTORE;
case LALOAD:
return IASTORE;
case ALOAD:
return IASTORE;
case DLOAD:
return IASTORE;
case FLOAD:
return IASTORE;
case ILOAD:
return IASTORE;
case LLOAD:
return IASTORE;
case AASTORE:
return AALOAD;
case BASTORE:
return BALOAD;
case CASTORE:
return CALOAD;
case IASTORE:
return IALOAD;
case SASTORE:
return SALOAD;
case DASTORE:
return DALOAD;
case FASTORE:
return FALOAD;
case LASTORE:
return LALOAD;
case ASTORE:
return ALOAD;
case DSTORE:
return DLOAD;
case FSTORE:
return FLOAD;
case ISTORE:
return ILOAD;
case LSTORE:
return LLOAD;
default:
throw new IllegalArgumentException("Opcode not valid.");
}
}
public static final boolean isVarSimilarType(int opcode1, int opcode2) {
switch (opcode1) {
case AALOAD:
return opcode2 == ALOAD;
case BALOAD:
case CALOAD:
case IALOAD:
case SALOAD:
return opcode2 == ILOAD;
case DALOAD:
return opcode2 == DLOAD;
case FALOAD:
return opcode2 == FLOAD;
case LALOAD:
return opcode2 == LLOAD;
case ALOAD:
return opcode2 == AALOAD;
case DLOAD:
return opcode2 == DALOAD;
case FLOAD:
return opcode2 == FALOAD;
case ILOAD:
return opcode2 == IALOAD || opcode2 == SALOAD
|| opcode2 == BALOAD || opcode2 == CALOAD;
case LLOAD:
return opcode2 == LALOAD;
// -- The same story for the store operation family --
case AASTORE:
return opcode2 == ASTORE;
case BASTORE:
case CASTORE:
case IASTORE:
case SASTORE:
return opcode2 == ISTORE;
case DASTORE:
return opcode2 == DSTORE;
case FASTORE:
return opcode2 == FSTORE;
case LASTORE:
return opcode2 == LSTORE;
case ASTORE:
return opcode2 == ASTORE;
case DSTORE:
return opcode2 == DSTORE;
case FSTORE:
return opcode2 == FSTORE;
case ISTORE:
return opcode2 == IASTORE || opcode2 == SASTORE
|| opcode2 == BASTORE || opcode2 == CASTORE;
case LSTORE:
return opcode2 == LSTORE;
default:
throw new IllegalArgumentException("Opcode1 not valid.");
}
}
public static final boolean isVarStore(int opcode) {
switch (opcode) {
case ASTORE:
//case BSTORE: // bytes & booleans are also regular integers
//case CSTORE: // characters are regular integers (?) under the hood
case DSTORE:
case FSTORE:
case ISTORE:
case LSTORE:
//case SSTORE: // and so are shorts
return true;
default:
return false;
}
}
}