Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package com.Joedobo27.WUmod;
- import javassist.ClassPool;
- import javassist.CtClass;
- import javassist.NotFoundException;
- import javassist.bytecode.*;
- import org.gotti.wurmunlimited.modloader.classhooks.HookManager;
- import org.gotti.wurmunlimited.modloader.interfaces.Initable;
- import org.gotti.wurmunlimited.modloader.interfaces.WurmServerMod;
- import java.util.*;
- import java.util.logging.Level;
- import java.util.logging.Logger;
- public class Test implements WurmServerMod, Initable {
- private static ClassPool pool;
- private static CtClass ctcItem;
- private static ClassFile cfItem;
- private static ConstPool cpItem;
- private static CodeAttribute moveToItemAttribute;
- private static CodeIterator moveToItemIterator;
- private static MethodInfo moveToItemMInfo;
- private static final Logger logger = Logger.getLogger(Test.class.getName());
- private static final String EMPTY_STRING = "";
- private static final int EMPTY_INT = Integer.MAX_VALUE;
- @Override
- public void init() {
- try {
- pool = HookManager.getInstance().getClassPool();
- setJSItem();
- moveItemsIntoBinWithinContainerBytecode();
- }catch (NotFoundException | BadBytecode e){
- logger.log(Level.WARNING, e.getMessage(), e);
- }
- }
- private void moveItemsIntoBinWithinContainerBytecode() throws BadBytecode {
- //<editor-fold desc="moveToItem() of Item.class changes">
- /*
- Lines 3990 to 4046 in moveToItem of Javap.exe dump.
- Removed-
- if (target.getTopParent() != target.getWurmId() && !target.isCrate()) {
- if (mover != null) {
- final String message = StringUtil.format("The %s needs to be on the ground.", target.getName());
- mover.getCommunicator().sendNormalServerMessage(message);
- }
- return false;
- }
- */
- //</editor-fold>
- ArrayList<Integer> findPoolResult;
- setMoveToItem(cfItem, "(Lcom/wurmonline/server/creatures/Creature;JZ)Z", "moveToItem");
- Bytecode find = new Bytecode(cpItem);
- find.addAload(8);//2
- find.addOpcode(Opcode.INVOKEVIRTUAL);
- findPoolResult = findConstantPoolReference(cpItem, "// Method getTopParent:()J");
- find.add(findPoolResult.get(0), findPoolResult.get(1));
- find.addAload(8);//2 7
- find.addOpcode(Opcode.INVOKEVIRTUAL);
- findPoolResult = findConstantPoolReference(cpItem, "// Method getWurmId:()J");
- find.add(findPoolResult.get(0), findPoolResult.get(1));
- find.addOpcode(Opcode.LCMP);//1 11
- find.addOpcode(Opcode.IFEQ); find.add(0,46);//3 14 jump forward 46 lines
- find.addAload(8);//2 16
- find.addOpcode(Opcode.INVOKEVIRTUAL);
- findPoolResult = findConstantPoolReference(cpItem, "// Method isCrate:()Z");
- find.add(findPoolResult.get(0), findPoolResult.get(1));
- find.addOpcode(Opcode.IFNE); find.add(0,38);//3 22 jump forward 38 lines
- find.addOpcode(Opcode.ALOAD_1);//1 23
- find.addOpcode(Opcode.IFNULL); find.add(0, 32);//3 26 jump forward 20 lines
- find.addOpcode(Opcode.LDC_W);
- findPoolResult = findConstantPoolReference(cpItem, "// String The %s needs to be on the ground.");
- find.add(findPoolResult.get(0), findPoolResult.get(1));
- find.addOpcode(Opcode.ICONST_1);//1 30
- find.addOpcode(Opcode.ANEWARRAY);
- findPoolResult = findConstantPoolReference(cpItem, "// class java/lang/Object");
- find.add(findPoolResult.get(0), findPoolResult.get(1));
- find.addOpcode(Opcode.DUP);//1 34
- find.addOpcode(Opcode.ICONST_0);//1 35
- find.addAload(8);//2 37
- find.addOpcode(Opcode.INVOKEVIRTUAL);
- findPoolResult = findConstantPoolReference(cpItem, "// Method getName:()Ljava/lang/String;");
- find.add(findPoolResult.get(0), findPoolResult.get(1));
- find.addOpcode(Opcode.AASTORE);//1 41
- find.addOpcode(Opcode.INVOKESTATIC);
- findPoolResult = findConstantPoolReference(cpItem, "// Method com/wurmonline/server/utils/StringUtil.format:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;");
- find.add(findPoolResult.get(0), findPoolResult.get(1));
- find.addAstore(19);//2 46
- find.addOpcode(Opcode.ALOAD_1);//1 47
- find.addOpcode(Opcode.INVOKEVIRTUAL);
- findPoolResult = findConstantPoolReference(cpItem, "// Method com/wurmonline/server/creatures/Creature.getCommunicator:()Lcom/wurmonline/server/creatures/Communicator;");
- find.add(findPoolResult.get(0), findPoolResult.get(1));
- find.addAload(19);//2 52
- find.addOpcode(Opcode.INVOKEVIRTUAL);
- findPoolResult = findConstantPoolReference(cpItem, "// Method com/wurmonline/server/creatures/Communicator.sendNormalServerMessage:(Ljava/lang/String;)V");
- find.add(findPoolResult.get(0), findPoolResult.get(1));
- find.addOpcode(Opcode.ICONST_0);//1 56
- find.addReturn(CtClass.intType);//1 57
- Bytecode replace = new Bytecode(cpItem);
- int nopLength = 57;
- for (int i=0;i<nopLength;i++){
- replace.addOpcode(Opcode.NOP);
- }
- findReplaceCodeIterator(moveToItemIterator, find, replace);
- }
- private void setJSItem() throws NotFoundException {
- ctcItem = pool.get("com.wurmonline.server.items.Item");
- cfItem = ctcItem.getClassFile();
- cpItem = cfItem.getConstPool();
- }
- private static void setMoveToItem(ClassFile cf, String desc, String name) {
- if (moveToItemMInfo == null || moveToItemIterator == null || moveToItemAttribute == null) {
- for (List a : new List[]{cf.getMethods()}){
- for(Object b : a){
- MethodInfo MInfo = (MethodInfo) b;
- if (Objects.equals(MInfo.getDescriptor(), desc) && Objects.equals(MInfo.getName(), name)){
- moveToItemMInfo = MInfo;
- break;
- }
- }
- }
- if (moveToItemMInfo == null){
- throw new NullPointerException();
- }
- moveToItemAttribute = moveToItemMInfo.getCodeAttribute();
- moveToItemIterator = moveToItemAttribute.iterator();
- }
- }
- //*****************************************************************************************
- //*****************************************************************************************
- //*****************************************************************************************
- public static void findReplaceCodeIterator(CodeIterator ci, Bytecode find, Bytecode replace) throws BadBytecode {
- byte[] findSimpleB = find.get();
- LinkedList<Integer> findSimpleI = new LinkedList<>();
- for (byte aFindSimpleB : findSimpleB) {
- findSimpleI.add(Byte.toUnsignedInt(aFindSimpleB));
- }
- findSimpleB = null; // void out unused.
- int index;
- int bitLine;
- int bitLine2;
- int findSize = findSimpleI.size();
- CIStack ciStack = new CIStack(findSize);
- ci.begin();
- while (ci.hasNext()) {
- index = ci.next();
- ciStack.indexPush(index);
- switch (ci.lookAhead() - index){
- case 1:
- ciStack.stackPush(ci.byteAt(index));
- break;
- case 2:
- bitLine = ci.s16bitAt(index);
- ciStack.stackPush((bitLine & 0xff00) >>> 8);
- ciStack.stackPush(bitLine & 0x00ff);
- break;
- case 3:
- bitLine = ci.s32bitAt(index);
- ciStack.stackPush((bitLine & 0xff000000) >>> 24);
- ciStack.stackPush((bitLine & 0x00ff0000) >>> 16);
- ciStack.stackPush((bitLine & 0x0000ff00) >>> 8);
- // not using the last byte
- break;
- case 4:
- bitLine = ci.s32bitAt(index);
- ciStack.stackPush((bitLine & 0xff000000) >>> 24);
- ciStack.stackPush((bitLine & 0x00ff0000) >>> 16);
- ciStack.stackPush((bitLine & 0x0000ff00) >>> 8);
- ciStack.stackPush((bitLine & 0x000000ff));
- break;
- case 5:
- bitLine = ci.s32bitAt(index);
- ciStack.stackPush((bitLine & 0xff000000) >>> 24);
- ciStack.stackPush((bitLine & 0x00ff0000) >>> 16);
- ciStack.stackPush((bitLine & 0x0000ff00) >>> 8);
- ciStack.stackPush((bitLine & 0x000000ff));
- bitLine2 = ci.byteAt(index + 4);
- ciStack.stackPush(bitLine2);
- break;
- case 6:
- bitLine = ci.s32bitAt(index);
- ciStack.stackPush((bitLine & 0xff000000) >>> 24);
- ciStack.stackPush((bitLine & 0x00ff0000) >>> 16);
- ciStack.stackPush((bitLine & 0x0000ff00) >>> 8);
- ciStack.stackPush((bitLine & 0x000000ff));
- bitLine2 = ci.s16bitAt(index + 4);
- ciStack.stackPush((bitLine2 & 0xff00) >>> 8);
- ciStack.stackPush((bitLine2 & 0x00ff));
- break;
- case 7:
- bitLine = ci.s32bitAt(index);
- ciStack.stackPush((bitLine & 0xff000000) >>> 24);
- ciStack.stackPush((bitLine & 0x00ff0000) >>> 16);
- ciStack.stackPush((bitLine & 0x0000ff00) >>> 8);
- ciStack.stackPush((bitLine & 0x000000ff));
- bitLine2 = ci.s32bitAt(index + 4);
- ciStack.stackPush((bitLine2 & 0xff000000) >>> 24);
- ciStack.stackPush((bitLine2 & 0x00ff0000) >>> 16);
- ciStack.stackPush((bitLine2 & 0x0000ff00) >>> 8);
- break;
- case 8:
- bitLine = ci.s32bitAt(index);
- ciStack.stackPush((bitLine & 0xff000000) >>> 24);
- ciStack.stackPush((bitLine & 0x00ff0000) >>> 16);
- ciStack.stackPush((bitLine & 0x0000ff00) >>> 8);
- ciStack.stackPush((bitLine & 0x000000ff));
- bitLine2 = ci.s32bitAt(index + 4);
- ciStack.stackPush((bitLine2 & 0xff000000) >>> 24);
- ciStack.stackPush((bitLine2 & 0x00ff0000) >>> 16);
- ciStack.stackPush((bitLine2 & 0x0000ff00) >>> 8);
- ciStack.stackPush((bitLine2 & 0x000000ff));
- break;
- }
- if (ciStack.getStackSize()<findSize) {
- continue;
- }
- while (ciStack.getStackSize() > findSize) {
- int[] removed = ciStack.stackPop();
- }
- if (4100 > index && index > 4000 ) {
- printArrayToHex(ciStack.getStack().toArray(), "ciStack");
- printArrayToHex(findSimpleI.toArray(), "findSimpleI");
- logger.log(Level.INFO, "ArrayPos: " + Arrays.toString(ciStack.getListPositions().toArray()));
- logger.log(Level.INFO, "Indexes: " + Arrays.toString(ciStack.getByteIndexes().toArray()));
- logger.log(Level.INFO, "stackSize: " + ciStack.getStackSize());
- logger.log(Level.INFO, "findSize: " + findSize);
- }
- if (ciStack.getStackSize() != findSize || !Arrays.equals(ciStack.getStack().toArray(), findSimpleI.toArray())){
- //logger.log(Level.INFO,"ciQueue: " + ciQueue.toString());
- continue;
- }
- logger.log(Level.INFO, "Insert index: " + ciStack.getInsertPoint());
- // Match found and insert the replace array at index
- ci.write(replace.get(), ciStack.getInsertPoint());
- break;
- }
- logger.log(Level.INFO, "DONE");
- }
- public static String addConstantPoolReference(ConstPool cp, String javapDesc) {
- String[] splitDesc1;
- String[] splitDesc2;
- //String refType = "";
- //String classInfo = "";
- String name = "";
- String descriptor = "";
- int classConstPoolIndex = Integer.MAX_VALUE;
- int poolIndex = Integer.MAX_VALUE;
- splitDesc1 = javapDesc.split("[ .:]");
- if (Objects.equals(splitDesc1[1], "String")) {
- splitDesc2 = javapDesc.split("String ");
- splitDesc1 = new String[]{"//", "String", splitDesc2[1]};
- }
- if (splitDesc1.length < 3 || splitDesc1.length > 5)
- throw new UnsupportedOperationException();
- if ( (Objects.equals(splitDesc1[1], "Method") || Objects.equals(splitDesc1[1], "Field")) && splitDesc1.length == 3) {
- throw new UnsupportedOperationException();
- }
- if ( (Objects.equals(splitDesc1[1], "Method") || Objects.equals(splitDesc1[1], "Field")) && splitDesc1.length == 4) {
- // The class reference is missing. This happens when a field or method is defined in the same class and javap
- // assumes the reader is aware. addFieldrefInfo and addMethodrefInfo need specifics not assumptions.
- try {
- //classConstPoolIndex = Integer.valueOf(findConstantPoolReference(cp, "// class " + cp.getClassName().replaceAll("\\.", "/")), 16);
- }catch (UnsupportedOperationException e) {
- classConstPoolIndex = cp.addClassInfo(cp.getClassName().replaceAll("/", "."));
- }
- name = splitDesc1[2];
- name = name.replaceAll("\"", "");
- descriptor = splitDesc1[3];
- }
- if ( (Objects.equals(splitDesc1[1], "Method") || Objects.equals(splitDesc1[1], "Field")) && splitDesc1.length == 5) {
- try {
- //classConstPoolIndex = Integer.valueOf(findConstantPoolReference(cp, "// class " + splitDesc1[2].replaceAll("\\.", "/")), 16);
- }catch (UnsupportedOperationException e) {
- classConstPoolIndex = cp.addClassInfo(splitDesc1[2].replaceAll("/", "."));
- }
- name = splitDesc1[3];
- name = name.replaceAll("\"", "");
- descriptor = splitDesc1[4];
- }
- switch (splitDesc1[1]){
- case "Method":
- poolIndex = cp.addMethodrefInfo(classConstPoolIndex, name, descriptor);
- break;
- case "Field":
- poolIndex = cp.addFieldrefInfo(classConstPoolIndex, name, descriptor);
- break;
- case "class":
- try {
- //poolIndex = Integer.valueOf(findConstantPoolReference(cp, "// class " + splitDesc1[2].replaceAll("\\.", "/")), 16);
- }catch (UnsupportedOperationException e) {
- poolIndex = cp.addClassInfo(splitDesc1[2].replaceAll("/", "."));
- }
- break;
- case "String":
- poolIndex = cp.addStringInfo(splitDesc1[2]);
- }
- if (Objects.equals(poolIndex, EMPTY_INT))
- throw new UnsupportedOperationException();
- return String.format("%04X", poolIndex & 0xffff);
- }
- /**
- * This method looks for matches in the constantPool and returns found addresses.
- *
- * @param cp is type ConstPool. This object is for accessing a specific ConstPool.
- * @param javapDesc is a string. This string data is copied directly from javap.exe data dump and represents a description
- * of its explanatory value in the constantPool.
- * @return is a string of 4 digits. These 4 numbers(in string form) are the address in the ConstantPool
- */
- public static ArrayList<Integer> findConstantPoolReference(ConstPool cp, String javapDesc) {
- String[] splitDesc1;
- String[] splitDesc2;
- String refClass = "";
- String cpClass;
- String name = "";
- String eqResult;
- String descriptor = "";
- int classConstPoolIndex = Integer.MAX_VALUE;
- int poolIndex = Integer.MAX_VALUE;
- byte[] byteAddress = null;
- splitDesc1 = javapDesc.split("[ .:]");
- if (Objects.equals(splitDesc1[1], "String")) {
- splitDesc2 = javapDesc.split("String ");
- splitDesc1 = new String[]{"//", "String", splitDesc2[1]};
- }
- if (Objects.equals(splitDesc1[1], "float")) {
- splitDesc2 = javapDesc.split("float ");
- splitDesc1 = new String[]{"//", "float", splitDesc2[1]};
- }
- if (splitDesc1.length < 3 || splitDesc1.length > 5)
- throw new UnsupportedOperationException();
- if ( (Objects.equals(splitDesc1[1], "Method") || Objects.equals(splitDesc1[1], "Field")) && splitDesc1.length == 3) {
- throw new UnsupportedOperationException();
- }
- if ( (Objects.equals(splitDesc1[1], "Method") || Objects.equals(splitDesc1[1], "Field") || Objects.equals(splitDesc1[1], "InterfaceMethod"))
- && splitDesc1.length == 4) {
- // The class reference is missing. This happens when a field or method is defined in the same class and javap
- // assumes the reader is aware. ConstPool references still show the class reference even if the lines in methods don't.
- //classConstPoolIndex = cp.addClassInfo(cp.getClassName().replaceAll("/", "."));
- refClass = cp.getClassName();
- refClass = refClass.replace("/", ".");
- name = splitDesc1[2];
- name = name.replaceAll("\"", "");
- descriptor = splitDesc1[3];
- }
- if ( (Objects.equals(splitDesc1[1], "Method") || Objects.equals(splitDesc1[1], "Field") || Objects.equals(splitDesc1[1], "InterfaceMethod"))
- && splitDesc1.length == 5) {
- //classConstPoolIndex = cp.addClassInfo(splitDesc1[2]);
- refClass = splitDesc1[2];
- refClass = refClass.replace("/", ".");
- name = splitDesc1[3];
- name = name.replaceAll("\"", "");
- descriptor = splitDesc1[4];
- }
- for (int i = 1; i < cp.getSize(); i++) {
- try {
- switch (splitDesc1[1]) {
- case "Method":
- eqResult = cp.eqMember(name, descriptor, i);
- cpClass = cp.getMethodrefClassName(i);
- if (eqResult != null && Objects.equals(refClass, cpClass)) {
- byteAddress = intToByteArray(i);
- }
- break;
- case "String":
- String cpStr = cp.getStringInfo(i);
- String refStr = splitDesc1[2];
- if (cpStr != null && Objects.equals(cpStr, refStr))
- byteAddress = intToByteArray(i);
- break;
- case "Field":
- eqResult = cp.eqMember(name, descriptor, i);
- cpClass = cp.getMethodrefClassName(i);
- if (eqResult != null && Objects.equals(refClass, cpClass))
- byteAddress = intToByteArray(i);
- break;
- case "class":
- refClass = splitDesc1[2];
- refClass = refClass.replace("/", ".");
- cpClass = cp.getClassInfo(i);
- if (cpClass != null && Objects.equals(cpClass, refClass))
- byteAddress = intToByteArray(i);
- break;
- case "long":
- long cpLong = cp.getLongInfo(i);
- long refLong = Long.parseLong(splitDesc1[2].replace("l", ""), 10);
- if (Objects.equals(cpLong, refLong))
- byteAddress = intToByteArray(i);
- break;
- case "float":
- float cpFloat = cp.getFloatInfo(i);
- float refFloat = Float.parseFloat(splitDesc1[2].replace("f", ""));
- if (Objects.equals(cpFloat, refFloat))
- byteAddress = intToByteArray(i);
- break;
- case "InterfaceMethod":
- eqResult = cp.eqMember(name, descriptor, i);
- cpClass = cp.getInterfaceMethodrefClassName(i);
- if (eqResult != null && Objects.equals(refClass, cpClass))
- byteAddress = intToByteArray(i);
- break;
- }
- } catch (ClassCastException ignored) {
- // This method does ConstPool information fetching that throws this exception often, ignore it.
- }
- if (byteAddress != null) {
- break;
- }
- }
- if (byteAddress == null) {
- throw new UnsupportedOperationException();
- }
- ArrayList<Integer> toReturn = new ArrayList<>(byteAddress.length);
- for (byte b : byteAddress){
- toReturn.add(Byte.toUnsignedInt(b));
- }
- return toReturn;
- }
- public static byte[] intToByteArray(int value) {
- //(byte)(value >>> 24),
- //(byte)(value >>> 16),
- return new byte[] {
- (byte)(value >>> 8),
- (byte)value};
- }
- public static void printArrayToHex(Object[] obj, String name){
- int length = obj.length;
- int[] c = new int[length];
- for (int i=0;i<length;i++){
- c[i]=(int)obj[i];
- }
- String[] a = new String[length];
- for (int i=0;i<length;i++){
- a[i]=String.format("%02X", c[i] & 0xff);
- }
- logger.log(Level.INFO,name + " : " + Arrays.toString(a));
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement