import java.util.*; import java.util.jar.*; import java.io.*; import java.net.*; import java.text.SimpleDateFormat; import org.apache.bcel.Constants; import org.apache.bcel.classfile.*; import org.apache.bcel.generic.*; import org.apache.bcel.util.InstructionFinder; public class ClientScanner implements Constants { private ClassGen accessorMethods; private JavaClass mouseListenerClass = null; private JavaClass stringWrapperClass = null; private int version = -1; File jar; File jar2; private int scan = 0; InstructionFactory factory; public void update(String server) { jar = new File("in/runescape.jar"); try { if(!jar.exists()) { log("Downloading \"runescape.jar\" from " + server + "..."); InputStream in = new URL("http://" + server + "/runescape.jar").openStream(); FileOutputStream out = new FileOutputStream(jar); byte[] buf = new byte[700]; int i; while ((i = in.read(buf)) != -1) { out.write(buf, 0, i); } try { in.close(); out.close(); } catch (Exception oh_) {} } log("Getting current .jar version and creating the accessor methods..."); JarFile jarFile = new JarFile(jar); if (new File(jarFile.getName()).exists()) { accessorMethods = new ClassGen("PrimaryAccessorMethods", "java.lang.Object", "PrimaryAccessorMethods.class", ACC_PUBLIC, new String[] {}); InstructionList list = new InstructionList(); ConstantPoolGen poolgen = accessorMethods.getConstantPool(); factory = new InstructionFactory(accessorMethods); MethodGen construct = new MethodGen(ACC_PUBLIC, Type.VOID, Type.NO_ARGS, new String[] {}, "", accessorMethods.getClassName(), list, poolgen); list.append(new ALOAD(0)); list.append(factory.createInvoke(accessorMethods.getSuperclassName(), "", Type.VOID, Type.NO_ARGS, INVOKESPECIAL)); list.append(factory.createReturn(Type.VOID)); construct.setMaxStack(); accessorMethods.addMethod(construct.getMethod()); InstructionFactory factory = new InstructionFactory(accessorMethods); for (; scan < 3; scan++) { Enumeration entries = jarFile.entries(); while (entries.hasMoreElements()) { JarEntry ent = (JarEntry) entries.nextElement(); if(ent.getName().endsWith(".class")) { if (version == -1) { ClassParser clazzp = new ClassParser(jarFile.getInputStream(ent), ent.getName()); scanClass(clazzp.parse()); } } } } accessorMethods.getJavaClass().dump(new File("bot/" + accessorMethods.getFileName())); log("Finished!"); } else { log("[ERROR]: .jar missing!"); } } catch (IOException ioe) { log("o man der be ioexception"); ioe.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } public void scanClass(JavaClass clazz) throws Exception { ClassGen gen = new ClassGen(clazz); if (mouseListenerClass == null) { for (String interfaceName: gen.getInterfaceNames()) { for (String mouseInterfaceName : new String[] { "MouseListener", "MouseMotionListener" }) { if (interfaceName.endsWith(mouseInterfaceName)) { mouseListenerClass = gen.getJavaClass(); log(mouseInterfaceName + " class is " + mouseListenerClass.getClassName() + "."); break; } } } } for(Field field : gen.getFields()) { if(mouseListenerClass != null && field.getType().toString().equals(mouseListenerClass.getClassName())) { ObjectType returnT = new ObjectType(mouseListenerClass.getClassName()); Instruction[] inst = new Instruction[] { factory.createGetStatic(gen.getClassName(), field.getName(), returnT), factory.createReturn(returnT) }; addAccessMethod("getMouseWrapperObject", inst, returnT, null); break; } } if (scan == 0) { for (Method meth : gen.getMethods()) { if (meth.getName().equals("toString") && gen.getInterfaceNames().length > 0) { stringWrapperClass = gen.getJavaClass(); log("String wrapper class is " + stringWrapperClass.getClassName() + "."); } ConstantPoolGen poolGen = gen.getConstantPool(); MethodGen methodGen = new MethodGen(meth, gen.getClassName(), poolGen); InstructionList list = methodGen.getInstructionList(); InstructionFinder finder = null; if (list != null) { finder = new InstructionFinder(list); } if(finder != null) { String pat1 = "getstatic getstatic iload iastore " + "getstatic getstatic iload iastore " + "getstatic getstatic iload iastore " + "getstatic getstatic iload iastore"; for(Iterator i = finder.search(pat1); i.hasNext();) { InstructionHandle matchHandle[] = (InstructionHandle[]) i.next(); GETSTATIC row = (GETSTATIC) matchHandle[1].getInstruction(); Instruction[] inst = new Instruction[] { factory.createGetStatic(gen.getClassName(), row.getFieldName(poolGen), row.getFieldType(poolGen)), factory.createReturn(row.getFieldType(poolGen)) }; addAccessMethod("getCurrentActionDataRow", inst, row.getFieldType(poolGen), null); for (int handle = 0; handle < 4; handle++) { GETSTATIC array = (GETSTATIC) matchHandle[handle * 4].getInstruction(); Instruction[] inst2 = new Instruction[] { factory.createGetStatic(gen.getClassName(), array.getFieldName(poolGen), array.getFieldType(poolGen)), factory.createReturn(array.getFieldType(poolGen)) }; addAccessMethod("getActionDataArray" + (handle + 1), inst2, array.getFieldType(poolGen), null); } } String pat2 = "aconst_null putfield getstatic iload aconst_null aastore iinc"; for (Iterator i = finder.search(pat2); i.hasNext();) { InstructionHandle match[] = (InstructionHandle[]) i.next(); GETSTATIC getStatic = (GETSTATIC) match[2].getInstruction(); if(getStatic.getType(poolGen).toString().endsWith("[]")) { Instruction[] inst3 = new Instruction[] { factory.createGetStatic(gen.getClassName(), getStatic.getFieldName(poolGen), getStatic.getType(poolGen)), factory.createReturn(getStatic.getType(poolGen)) }; addAccessMethod("getNPCArray", inst3, getStatic.getType(poolGen), null); } break; } } } } if (scan == 1) { ConstantPoolGen cpg = gen.getConstantPool(); for (Method m : clazz.getMethods()) { if (m.isStatic()) { MethodGen mg = new MethodGen(m, clazz.getClassName(), cpg); String pat3 = "getstatic istore getstatic iconst iadd putstatic " + "iload iconst ixor iconst if_icmple return"; InstructionList list = mg.getInstructionList(); InstructionFinder finder = new InstructionFinder(list); Iterator iterator = finder.search(pat3); while (iterator.hasNext()) { InstructionHandle handle[] = (InstructionHandle[]) iterator.next(); Instruction[] inst = new Instruction[] { //factory.createGetStatic(gen.getClassName(), m.getName(), Constants.METHOD, null), //factory.createReturn(m.getReturnType()) }; //addAccessMethod("actionMethod", inst, , null); //for (InstructionHandle h : handle) // System.out.println(">>>>" + (Object)m); } } } } if (scan == 2) { for (Method meth : gen.getMethods()) { if (meth.getName().equals("main")) { ConstantPoolGen poolGen = gen.getConstantPool(); MethodGen methGen = new MethodGen(meth, gen.getClassName(), poolGen); InstructionList list = methGen.getInstructionList(); InstructionFinder finder = new InstructionFinder(list); if (finder != null) { for (Iterator i = finder.search("SIPUSH"); i.hasNext();) { InstructionHandle[] match = (InstructionHandle[]) i.next(); SIPUSH sp = (SIPUSH) match[0].getInstruction(); int val = sp.getValue().intValue(); switch (val) { case 503: break; case 765: break; default: if (val >= 400 && val <= 1000) { version = val; log("This client's revision is " + version + "..."); } break; } } } if (version == -1) log("Revision number could not be obtained"); } } } } public void addAccessMethod(String name, final Instruction instructions[], Type returnType, Type[] args) { log("Adding access method (" + returnType.toString() + ")" + name + "..."); InstructionList list = new InstructionList(); ConstantPoolGen poolGen = accessorMethods.getConstantPool(); MethodGen methGen; if (returnType == null) methGen = new MethodGen((ACC_PUBLIC | ACC_STATIC), Type.VOID, Type.NO_ARGS, new String[] {}, name, accessorMethods.getClassName(), list, poolGen); else methGen = new MethodGen((ACC_PUBLIC | ACC_STATIC), returnType, Type.NO_ARGS, new String[] {}, name, accessorMethods.getClassName(), list, poolGen); for(Instruction instruction : instructions) { list.append(instruction); } methGen.setMaxStack(); accessorMethods.addMethod(methGen.getMethod()); } public static final void log(String message) { message = new SimpleDateFormat("[hh:mm:ss]").format(new Date()) + " " + message; System.out.println(message); } public static void main(String[] ammagods) { long time = System.currentTimeMillis(); if (ammagods.length == 1) new ClientScanner().update(ammagods[0]); else new ClientScanner().update("se4.runescape.com"); long time2 = System.currentTimeMillis(); System.out.println("It took " + (time2 - time) + " shameful milliseconds."); } }