Guest User

Untitled

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