Guest User

Untitled

a guest
Jan 2nd, 2014
210
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 14.63 KB | None | 0 0
  1. package modify;
  2.  
  3. import java.io.ByteArrayInputStream;
  4. import java.io.ByteArrayOutputStream;
  5. import java.io.DataInputStream;
  6. import java.io.DataOutputStream;
  7. import java.io.FileInputStream;
  8. import java.io.FileOutputStream;
  9. import java.io.IOException;
  10. import java.util.Vector;
  11.  
  12. /**
  13.  *
  14.  * @author kiriman
  15.  */
  16. public class Main {
  17.  
  18.     private static final int MAGIC = 0xCAFEBABE; // О_о
  19.     public static final int CLASS = 7;
  20.     public static final int FIELDREF = 9;
  21.     public static final int METHODREF = 10;
  22.     public static final int INTERFACEMETHODREF = 11;
  23.     public static final int STRING = 8;
  24.     public static final int INTEGER = 3;
  25.     public static final int FLOAT = 4;
  26.     public static final int LONG = 5;
  27.     public static final int DOUBLE = 6;
  28.     public static final int NAMEANDTYPE = 12;
  29.     public static final int UTF8 = 1;
  30.     private static int class_version, // Версия класса
  31.             count_constants_cp, // Количество констант
  32.             max_stack; // Максимальный размер стека
  33.     private static byte[] tag_cp, // Тэги записей в пуле
  34.             code; // Основной код
  35.     private static Vector cpool, // Сами записи
  36.             indexC;
  37.  
  38.     public static void main(String[] args) {
  39.         if (!isModifyClass()) {
  40.             System.out.println("Not need to change");
  41.         } else {
  42.             System.out.println("Successfully!");
  43.         }
  44.     }
  45.  
  46.     private static int getIndex(int p, int l) {
  47.         int a1, a2;
  48.         a1 = (p >> l) & 0xff;
  49.         a2 = (p >> (l - 8)) & 0xff;
  50.         return ((a1 << 8) | (a2)) - 1;
  51.     }
  52.  
  53.     private static boolean isModifyClass() {
  54.         try {
  55.             FileInputStream fis = new FileInputStream("Main.class");
  56.             DataInputStream dis = new DataInputStream(fis);
  57.  
  58.             dis.readInt(); // MAGIC
  59.             class_version = dis.readInt();
  60.             count_constants_cp = dis.readUnsignedShort();
  61.             tag_cp = new byte[count_constants_cp];
  62.             cpool = new Vector();
  63.             Vector mref = new Vector(); // Для METHODREF записей
  64.             Vector temp_i = new Vector();
  65.             int skip = 10; // Кол-во прочтенных байт(int + int + short)
  66.             boolean z = false;
  67.  
  68.             for (int i = 0; i < count_constants_cp; i++) {
  69.                 tag_cp[i] = dis.readByte();
  70.                 skip++;
  71.                 switch (tag_cp[i]) {
  72.                     case METHODREF:
  73.                         int lol = dis.readInt();
  74.                         temp_i.addElement(new Integer(i + 1));
  75.                         cpool.addElement(new Integer(lol));
  76.                         mref.addElement(new Integer(lol));
  77.                         skip += 4;
  78.                         break;
  79.                     case UTF8:
  80.                         String s = dis.readUTF();
  81.                         skip += s.length() + 2;
  82.                         cpool.addElement(s);
  83.                         if (s.contains("getResourceAsStream")) {
  84.                             z = true; // Шоу продолжается!
  85.                         }
  86.                         break;
  87.                     case NAMEANDTYPE:
  88.                     case INTERFACEMETHODREF:
  89.                     case FIELDREF:
  90.                     case INTEGER:
  91.                     case FLOAT:
  92.                         cpool.addElement(new Integer(dis.readInt()));
  93.                         skip += 4;
  94.                         break;
  95.                     case DOUBLE:
  96.                     case LONG:
  97.                         cpool.addElement(new Long(dis.readLong()));
  98.                         skip += 8;
  99.                         break;
  100.                     case CLASS:
  101.                     case STRING:
  102.                         cpool.addElement(new Short(dis.readShort()));
  103.                         skip += 2;
  104.                         break;
  105.                 }
  106.             }
  107.  
  108.             if (!z) { // Класс годится для эмуляции
  109.                 return false;
  110.             }
  111.  
  112.             /*
  113.              * Разбор METHODREF записей на составляющие(индекс класса и имя метода с типом возвращаемых значений)
  114.              * проверяем, есть ли нужный нам метод - InputStream getResourceAsStream(String)
  115.              * и изменяем класс, ведь его индекс у нас найдется
  116.              */
  117.             indexC = new Vector();
  118.             int i = 0;
  119.             for (Object e : mref) {
  120.                 int m = ((Integer) e).intValue();
  121.                 int index_class = getClassIndex(getIndex(m, 24));
  122.                 if (getNameAndType(getIndex(m, 8)).equals("name=getResourceAsStream, type=(Ljava/lang/String;)Ljava/io/InputStream;")) {
  123.                     indexC.addElement(temp_i.elementAt(i));
  124.                     cpool.setElementAt("NewClass", index_class); // Аллилуйя!!!
  125.                 }
  126.                 i++;
  127.             }
  128.             code = new byte[(int) fis.getChannel().size() - skip];
  129.             dis.read(code);
  130.             dis.close();
  131.             fis.close();
  132.  
  133.             rebuildClassFile();
  134.  
  135.             return true;
  136.  
  137.         } catch (IOException ex) {
  138.             ex.printStackTrace();
  139.         }
  140.         return false;
  141.     }
  142.  
  143.     private static int getClassIndex(int index) {
  144.         if (tag_cp[index] == CLASS || tag_cp[index] == STRING) {
  145.             Object element = cpool.elementAt(index);
  146.             return ((Short) element).shortValue() - 1;
  147.         } else {
  148.             return index;
  149.         }
  150.     }
  151.  
  152.     private static String getNameAndType(int index) {
  153.         int nat = ((Integer) (cpool.elementAt(index))).intValue();
  154.         String name = (String) cpool.elementAt(getIndex(nat, 24));
  155.         String type = (String) cpool.elementAt(getIndex(nat, 8));
  156.         return "name=" + name + ", type=" + type;
  157.     }
  158.  
  159.     private static void rebuildClassFile() {
  160.         try {
  161.             // Собираем класс заново!
  162.             FileOutputStream fos = new FileOutputStream("Main_edit.class");
  163.             DataOutputStream dos = new DataOutputStream(fos);
  164.             // Constant Pool
  165.             dos.writeInt(MAGIC);
  166.             dos.writeInt(class_version);
  167.             dos.writeShort(count_constants_cp);
  168.             for (int i = 0; i < count_constants_cp; i++) {
  169.                 dos.writeByte(tag_cp[i]);
  170.                 switch (tag_cp[i]) {
  171.                     case UTF8:
  172.                         dos.writeUTF((String) cpool.elementAt(i));
  173.                         break;
  174.                     case NAMEANDTYPE:
  175.                     case INTERFACEMETHODREF:
  176.                     case METHODREF:
  177.                     case FIELDREF:
  178.                     case INTEGER:
  179.                     case FLOAT:
  180.                         dos.writeInt(((Integer) (cpool.elementAt(i))).intValue());
  181.                         break;
  182.                     case DOUBLE:
  183.                     case LONG:
  184.                         dos.writeLong(((Long) (cpool.elementAt(i))).longValue());
  185.                         break;
  186.                     case CLASS:
  187.                     case STRING:
  188.                         dos.writeShort(((Short) (cpool.elementAt(i))).shortValue());
  189.                         break;
  190.                 }
  191.             }
  192.             ByteArrayInputStream bais = new ByteArrayInputStream(code);
  193.             DataInputStream dis = new DataInputStream(bais);
  194.             dos.write(dis.read()); // Флаги доступа класса dos.writeShort(dis.readUnsignedShort());
  195.             dos.writeShort(dis.readUnsignedShort()); // this и super
  196.             dos.writeShort(dis.readUnsignedShort());
  197.             // Интерфейсы
  198.             int count_interfaces = dis.readUnsignedShort(); // Кол-во задействованных интерфейсов
  199.             System.out.println("count_interfaces = " + count_interfaces);
  200.             dos.writeShort(count_interfaces);
  201.             for (int i = 0; i < count_interfaces; i++) {
  202.                 dos.writeShort(dis.readUnsignedShort()); // Запись интерфейса(ссылка на запись в пуле)
  203.             }
  204.             // Переменные
  205.             int count_vars = dis.readUnsignedShort(); // Кол-во переменных
  206.             System.out.println("count_vars = " + count_vars);
  207.             dos.writeShort(count_vars);
  208.             for (int i = 0; i < count_vars; i++) {
  209.                 dos.writeShort(dis.readUnsignedShort()); // Флаг доступа
  210.                 dos.writeShort(dis.readUnsignedShort()); // Ссылка на запись в пуле(имя переменной)
  211.                 dos.writeShort(dis.readUnsignedShort()); // Дескриптор
  212.                 readAttr(dis, dos);
  213.             }
  214.             // Методы
  215.             int count_methods;
  216.             dos.writeShort(count_methods = dis.readUnsignedShort()); // Кол-во методов
  217.             for (int i = 0; i < count_methods; i++) {
  218.                 dos.writeShort(dis.readShort()); // Флаг доступа
  219.                 int name_index = dis.readShort();
  220.                 System.out.println("Loading method: " + cpool.elementAt(name_index - 1));
  221.                 dos.writeShort(name_index);
  222.                 dos.writeShort(dis.readShort()); // Дескриптор
  223.                 int count_attr = dis.readShort();
  224.                 dos.writeShort(count_attr);
  225.                 /*
  226.                  * Тут нас интересует аттрибут "Code" и размер стека
  227.                  * Здесь же ищем все опкоды 0xB6 и исправляем
  228.                  */
  229.                 for (int j = 0; j < count_attr; j++) {
  230.                     int attr_name_index = dis.readUnsignedShort();
  231.                     dos.writeShort(attr_name_index);
  232.                     int len = dis.readInt();
  233.                     //System.out.println("len = " + len);
  234.                     dos.writeInt(len);
  235.                     String name = (String) cpool.elementAt(attr_name_index - 1);
  236.                     System.out.println(name);
  237.                     if (name.equals("Code")) {
  238.                         max_stack = dis.readUnsignedShort();
  239.                         int max_locals = dis.readUnsignedShort();
  240.                         int code_length = dis.readInt();
  241.                         byte[] data = new byte[code_length];
  242.                         dis.read(data);
  243.                         byte[] b = editOpcode(data);
  244.                         dos.writeShort(max_stack);
  245.                         dos.writeShort(max_locals);
  246.                         dos.writeInt(code_length);
  247.                         dos.write(b);
  248.                         int exceptions_table_length = dis.readUnsignedShort();
  249.                         dos.writeShort(exceptions_table_length);
  250.                         for (int k = 0; k < exceptions_table_length; k++) {
  251.                             int start_pc = dis.readUnsignedShort();
  252.                             dos.writeShort(start_pc);
  253.                             int end_pc = dis.readUnsignedShort();
  254.                             dos.writeShort(end_pc);
  255.                             int handler_pc = dis.readUnsignedShort();
  256.                             dos.writeShort(handler_pc);
  257.                             int catch_type = dis.readUnsignedShort();
  258.                             dos.writeShort(catch_type);
  259.                         }
  260.                         readAttr(dis, dos);
  261.                     } else {
  262.                         // По идее здесь надо по-человечески написать чтение и запись остальных аттрибутов метода
  263.                         // Но даже в преверефицированном классе у меня находит лишь один аттрибут Code..
  264.                         System.out.println("Fuck!!!");
  265.                     }
  266.                 }
  267.             }
  268.             readAttr(dis, dos);
  269.             code = null;
  270.             dis.close();
  271.             bais.close();
  272.             dos.close();
  273.             fos.close();
  274.         } catch (IOException ex) {
  275.             ex.printStackTrace();
  276.         }
  277.     }
  278.  
  279.     private static void readAttr(DataInputStream dis, DataOutputStream dos) {
  280.         try {
  281.             int count_attr = dis.readUnsignedShort(); // Кол-во аттрибутов
  282.             dos.writeShort(count_attr);
  283.             for (int j = 0; j < count_attr; j++) {
  284.                 dos.writeShort(dis.readUnsignedShort()); // Ссылка на запись в пуле(имя аттрибута)
  285.                 int len = dis.readInt(); // Длина аттрибута
  286.                 dos.writeInt(len);
  287.                 byte[] data = new byte[len];
  288.                 dis.read(data);
  289.                 dos.write(data);
  290.             }
  291.         } catch (IOException ex) {
  292.             ex.printStackTrace();
  293.         }
  294.     }
  295.  
  296.     /*
  297.      *
  298.      * Изменяем опкоды B6 - invokevirtuals на B8 - invokestatic в основном коде!
  299.      * Чтоб получить из этого:
  300.      * getClass().getResourceAs..
  301.      * вот это:
  302.      * NewClass.getResourceAs..
  303.      */
  304.     private static byte[] editOpcode(byte[] code) {
  305.         ByteArrayInputStream bais = new ByteArrayInputStream(code);
  306.         DataInputStream dis = new DataInputStream(bais);
  307.         ByteArrayOutputStream bois = new ByteArrayOutputStream();
  308.         DataOutputStream dos = new DataOutputStream(bois);
  309.         try {
  310.             int b = 0;
  311.             boolean z = false;
  312.             while ((b = dis.read()) != -1) {
  313.                 z = false;
  314.                 if (b == 0xb6) {
  315.                     int index = dis.readShort();
  316.                     for (Object e : indexC) {
  317.                         if (index == ((Integer) e).intValue()) {
  318.                             max_stack++;
  319.                             dos.write(0xb8);
  320.                             dos.writeShort(index);
  321.                             z = true;
  322.                             break;
  323.                         }
  324.                     }
  325.                     if (!z) {
  326.                         dos.write(b);
  327.                         dos.writeShort(index);
  328.                     }
  329.                 } else {
  330.                     dos.write(b);
  331.                 }
  332.             }
  333.             dis.close();
  334.             bais.close();
  335.             byte[] data = bois.toByteArray();
  336.             dos.close();
  337.             bois.close();
  338.             return data;
  339.         } catch (IOException ex) {
  340.             ex.printStackTrace();
  341.         }
  342.         return null;
  343.     }
  344. }
Advertisement
Add Comment
Please, Sign In to add comment