Bytecodemanipulation Bytecodemanipulation Vortrag im Rahmen des Seminars Generatives Computing 16.06.2004 Ronald Kutschke Daniel Haag Mirko Bleyh Markus Block 1 Bytecodemanipulation [ Einleitung ] Übersicht • • • • • • • • • Motivation Classfile Format Java Virtual Machine Möglichkeiten Vor- / Nachteile Beispiel: Framework BCEL Weitere Anwendungsgebiete Fazit Quellen 2 Bytecodemanipulation [ Einleitung ] Motivation Warum Bytecodemanipulation? • • Kein Sourcecode vorhanden Änderung am Bytecode einfacher, als am Sourcecode 3 Bytecodemanipulation [ Classfile Format ] Classfile Format Public class Person{} Person.java Person.class Person.java Person.class Public class Person{ class Adresse{} } Person$Adresse.class 4 Bytecodemanipulation [ Classfile Format ] Aufbau CLASSFILE magic_number 4 version_numbers 4 constant_pool_count 2 constant_pool n access_flags 2 this_class 2 super_class 2 interfaces_count 2 interfaces n fields_count 2 fields n methods_count 2 methods n attributes_count 2 attributes n 5 Bytecodemanipulation [ Classfile Format ] Beispiel (1) public class HelloWorld { public static void main(String[] args) { System.out.println("HELLO WORLD"); } } “javac HelloWorld.java“ HelloWorld.java HelloWorld.class 6 Bytecodemanipulation [ Classfile Format ] Beispiel (2) 7 Bytecodemanipulation [ Classfile Format ] Beispiel (3) 8 Bytecodemanipulation [ Classfile Format ] Constantpool (1) Constantpooleintrag Typ Angabe 1 Typ spezifisch n Constantpool Typ UTF8 String 01 Class 07 Methodref 0A NameAndType 0C ... 9 Bytecodemanipulation [ Classfile Format ] Constantpool (2) 10 Bytecodemanipulation [ Classfile Format ] Constantpool (3) 11 Bytecodemanipulation [ Classfile Format ] Inhalt Constantpool 1: UTF8: HelloWorld 2: CLASS: name=#1 3: UTF8: java/lang/Object 4: CLASS: name=#3 5: UTF8: <init> 6: UTF8: ()V 7: UTF8: Code 8: NAMEANDTYPE: name=#5, descriptor=#6 9: METHODREF: class=#4, nameAndType=#8 10: UTF8: LineNumberTable 11: UTF8: LocalVariableTable 12: UTF8: this 13: UTF8: LHelloWorld; 14: UTF8: main 15: UTF8: ([Ljava/lang/String;)V 16: UTF8: java/lang/System 17: CLASS: name=#16 18: UTF8: out 19: UTF8: Ljava/io/PrintStream; 20: NAMEANDTYPE: name=#18, descriptor=#19 21: FIELDREF: class=#17, nameAndType=#20 22: UTF8: HELLO WORLD 23: STRING: string=#22 24: UTF8: java/io/PrintStream 25: CLASS: name=#24 26: UTF8: println 27: UTF8: (Ljava/lang/String;)V 28: NAMEANDTYPE: name=#26, descriptor=#27 29: METHODREF: class=#25, nameAndType=#28 30: UTF8: args 31: UTF8: [Ljava/lang/String; 32: UTF8: SourceFile 33: UTF8: HelloWorld.java BaseType Character Type Interpretation B byte signed byte C char Unicode character D double double-precision floating-point value F float single-precision floating-point value I int integer J long long integer L<classname>; reference an instance of class <classname> S short signed short V void Return type void Z boolean true or false [ reference one array dimension 12 Bytecodemanipulation [ Classfile Format ] Methodendefinition [#24/UTF8] java/io/PrintStream [#25/Class] name=#24 [#26/UTF8] println [#27/UTF8] (Ljava/lang/String;)V [#28/NameAndType] name=#26, desc=#27 [#29/Methodref] class=25 nameAndType=#28 13 Bytecodemanipulation [ Classfile Format ] Security class Login{ private String passwort = “xyz“; ... public void login(String eingabe){ if(passwort.equals(eingabe)) { //login durchführen } } ... } 14 Bytecodemanipulation [ Classfile Format ] Optimierung (1) 15 Bytecodemanipulation [ Classfile Format ] Optimierung (2) Constantpool: 62% Methods: 33% 1% 2% 33% 2% 62% header class constant field method Analysis of the Java class file Denis N. Antoniolli, Markus Pilz 16 Bytecodemanipulation [ JVM ] Java Virtual Machine • Zentrales Element der Java Technologie • Verantwortlich für Plattform-Unabhängigkeit • Abstrakte Rechenmaschine mit fester Anzahl an Instruktionen (Opcodes), die auf verschiedenen Speicherbereichen operiert • Kennt keine Java Programmiersprache, lediglich das Bytecode-Format • Kann in Hardware oder in Software realisiert werden 17 Bytecodemanipulation [ JVM ] JVM Details Spezifizierte Aufgaben einer JVM: – Lesen von Bytecode – Ausführen der definierten Operationen Alles weitere ist dem Entwickler überlassen, also z.B. – Speicheranordnung der Runtime Data Areas – Algorithmus der Garbage-Collection – Ausführungsart der Operationen (Interpretieren oder in nativen Code kompilieren und dann ausführen) 18 Bytecodemanipulation [ JVM ] JVM-Architektur 19 Bytecodemanipulation [ Class Loader ] Motivation – Speicherort der Klassen kann sehr unterschiedlich sein: • • • • Lokales Dateisystem Entferntes Dateisystem Datenbank Internet – Zentraler Punkt zum Laden von Klassen Erhöhte Sicherheit 20 Bytecodemanipulation [ Class Loader ] Aufgaben Um eine Klasse verwenden zu können, muss Folgendes von der VM bzw. dem Class Loader erledigt werden: – Dynamisches Laden der Klasse: • Finden der binären Repräsentation der Klasse (Bytecode) und erzeugen einer Klasse aus diesem – Linken der Klasse: • Verifizieren • Reservieren und Initialisieren von Speicher für Klassenvariablen • Transformieren von symbolischen Referenzen in direkte Referenzen – Initialisieren der Klasse: • Ausführen der <clinit> Methode der Klasse, Initialisieren der Klassenvariablen 21 Bytecodemanipulation [ Class Loader ] Bootstrap Class Loader Problem: Der Class Loader selber ist auch eine Java Klasse! Wer lädt diesen? Antwort: Der Bootstrap Class Loader: – – – – – Er ist Teil der JVM Er ist zumeist in der selben Sprache wie die VM geschrieben Wird beim Hochfahren der VM geladen Lädt alle weiteren Class Loader und die Klassen des Java API Nur vom ihm geladene Klassen werden als vertrauenswürdig eingestuft – JDK1.1: Benötigt unter Windows die CLASSPATH Umgebungsvariable – JDK1.2: System Class Loader durchsucht den CLASSPATH selber 22 Bytecodemanipulation [ Class Loader ] public class SimpleClassLoader extends ClassLoader { public synchronized Class loadClass(String name, boolean resolve) { Class c = findLoadedClass(name); if (c != null) return c; try { c = findSystemClass(name); if (c != null) return c; } catch (ClassNotFoundException e) {} try { RandomAccessFile file = new RandomAccessFile("test/" + name + ".class", "r"); byte data[] = new byte[(int)file.length()]; file.readFully(data); c = defineClass(name, data, 0, data.length); } catch (IOException e) {} if (resolve) resolveClass(c); return c; } } 23 Bytecodemanipulation [ Class Loader ] Parent Delegation Model Bezeichnet die Arbeitsteilung der verschiedenen Class Loader innerhalb einer JVM: – Seit JDK 1.2 vorgeschlagen, bereits in java.lang.ClassLoader realisisert – Jeder Class Loader besitzt Referenz auf Parent (ausser BCL) – Anfrage zum Laden einer Klasse wird immer erst an den Parent weitergegeben – Wenn Parent Klasse nicht finden, versucht es der CL selber 24 Bytecodemanipulation [ JVM ] JVM-Architektur 25 Bytecodemanipulation [ Runtime Data Areas ] • Method Area: – Enthält alle Klassen-Informationen (Name, Superklasse, Constant Pool, Methoden-Informationen und –Bytecode, Exception-Table, Klassenvariablen, etc.) – Gehört logisch zum Heap • Heap: – Hier werden alle Objekt-Instanzen und Array gespeichert (d.h. Objekt-Referenzen zeigen auf Speicherbereiche im Heap): • Instanzvariablen der Klasse des Objekts und aller Superklassen • Zeiger auf den Speicherbereich der Klassendaten in der Method Area – Für alle Threads gemeinsam 26 Bytecodemanipulation [ Runtime Data Areas ] • PC Register: – Jeder Thread hat eigenen PC Register – PC Register ist ein Wort groß – Enthält „Adresse“ (nativer Pointer oder Offset des Bytecodes) der aktuell ausführenden Instruktion bzw. ist undefiniert beim Ausführen von nativem Code • Native Method Stack: – Führt Programm-Code aus, der nicht in Java geschrieben ist – Optional 27 Bytecodemanipulation [ Runtime Data Areas ] • Java Stack: – Jeder Thread hat eigenen Stack – Nur zwei mögliche Operationen: PUSH und POP – Stack besteht aus einzelnen Stack Frames: • zu jeder Methode gibt es einen Frame • immer genau ein Frame ist aktuell (aktuelle Methode) • bei Methodenaufruf wird ein Frame erzeugt und zum neuen aktuelle Frame am Stack (push) • bei Methodenende (return oder Exception) wird der aktuelle Frame verworfen und der vorherige Frame wird zum aktuellen Frame (pop) – ein Thread kann nur auf seinen Stack zugreifen ! 28 Bytecodemanipulation [ Runtime Data Areas ] • Stack Frame – Lokale Variablen: • Als 0-basiertes Array aus Wörtern organisiert • Enthält Parameter und lokale Variablen der jeweiligen Methode – Operanden-Stack: • Als 0-basiertes Array aus Wörtern organisiert • Lediglich PUSH und POP erlaubt (keine Indizierung möglich!) • Hauptspeicherort von Operanden für Instruktionen – Frame Daten: • Referenz auf Constant Pool der Klasse der Methode • Daten zur Wiederherstellen des vorherigen Frames bei normalem Methodenende • Exception Behandlung (Referenz auf Exception-Table der Methode) • Weitere Daten... 29 Bytecodemanipulation [ JVM ] JVM-Architektur 30 Bytecodemanipulation [ Execution Engine ] 3 unterschiedliche Bedeutungen: – Abstrakte Spezifikation: • für jede Bytecode Instruktion wird spezifiziert, was gemacht werden soll, aber nicht wie! – Konkrete Implementierung: • Interpretation, JIT-Kompilierung, etc. – Laufzeit-Instanz: • Jeder Thread ist eine Instanz einer Execution Engine 31 Bytecodemanipulation [ Execution Engine ] Implementierungen • Interpretation – sehr einfach (1. Generation der VMs) • Just-in-Time Kompilierung – 1. Ausführung einer Methode → nativer Code • Adaptive Optimierung – – – – Mischung aus Interpretation und JIT Kompilierung Code-Ausführung wird beobachtet 80 - 90 % der CPU Zeit → 10 - 20 % des Codes wird z.B. in Suns HotSpot VM verwendet 32 Bytecodemanipulation [ JVM ] Funktionsweise der JVM Applet Demo... 33 Bytecodemanipulation [ Möglichkeiten ] Möglichkeiten • • • • Einfügen von Debuginformationen Einfügen von Tracinginformationen Besseres Handling von NullPointerExceptions Umbenennen von Variablen- und Methodennamen um Bytecode unleserlich zu machen (Obfuskator) • Einfügen von Code zur Serialisierung (JDO) • Bytecodeoptimierung 34 Bytecodemanipulation [ Vor- / Nachteile ] Vorteile • Sourcecode muss nicht vorliegen • Code kann dynamisch zur Ladezeit verändert werden • Einfügen von fest vorgegebenem Code, der von Programmierern nicht verändert werden kann 35 Bytecodemanipulation [ Vor- / Nachteile ] Nachteile • Aufwändig – Genaue Kenntnis des Classfile-Formats, der Opcodes und der VM sind Voraussetzung – Fehlen von Kommentaren • Fehler erscheinen erst zur Laufzeit 36 Bytecodemanipulation [ BCEL ] Byte Code Engineering Library (BCEL) • Objektorientierte Bearbeitung des prozeduralen Bytecodes – Mappen sämtlicher Opcodes in Java Klassen • Getrennte Packages zum – Analysieren und Inspizieren – Modifizieren und Erzeugen • Manipulation nach der Compile- oder zur Ladezeit • Bytecode Verifier • Disassembler 37 Bytecodemanipulation [ BCEL ] Verwendung von BCEL • Einlesen und parsen des Classfiles -> JavaClass • Auslesen der Klassenparameter (Methoden, Constant Pool, Felder, …) • Generatoren der Klassenparameter erzeugen • Manipulation über die Generator Objekte • Ersetzen der alten Parameter durch die neuen aus den Generatorobjekten • Zurückschreiben des Classfiles auf Festplatte 38 Bytecodemanipulation [ BCEL ] Aufruf von statischen Methoden • • • • • Hinzufügen der Methode zum Constant Pool Sichern der Referenz zur Methode Parameter auf den Stack legen Die Methode mit INVOKESTATIC(Methodenref) aufrufen Rückgabewert liegt nach dem Aufruf auf dem Stack 39 Bytecodemanipulation [ BCEL ] Aufruf von nicht-statischen Methoden • • • • • • Hinzufügen der Methode zum Constant Pool Sichern der Referenz zur Methode Referenz des Methodenobjektes auf den Stack legen Parameter auf den Stack legen Die Methode mit INVOKEVIRUTAL(Methodenref) aufrufen Rückgabewert liegt nach dem Aufruf auf dem Stack 40 Bytecodemanipulation [ BCEL ] Einfügen der Methodenaufrufe • • • • Gewünschte Methode finden Generator Objekt davon erstellen Codestelle innerhalb der Methode zum Einfügen finden Gewünschte Aufrufe einfügen 41 Bytecodemanipulation [ BCEL ] Beispiel • Einfügen von „Hello from „ + Methodensignatur beim Aufruf jeder Methode einer Klasse (nach Compile Time) • Einfügen von Tracing und Logging Informationen beim Aufruf und Verlassen jeder Methode einer Klasse (zur Loading Time) 42 Bytecodemanipulation [ Frameworks ] Weitere Frameworks • BCEL • Jikes Bytecode Toolkit (JikesBT) • Javassist – Ermöglicht abstraktere Bytecode Manipulation über Method.append("System.out.println(\"Test\");"); 43 Bytecodemanipulation [ Fazit ] Fazit • Bytecodemanipulation ermöglicht die Erweiterung, Optimierung und Anpassung von Classfiles • Es ersetzt jedoch nicht das herkömmliche Programmieren in Java, da die Komplexität bedeutend höher ist 44 Bytecodemanipulation [ Quellen ] Quellen (1) • Analysis Of The Java Class File (Denis N. Antonioli, Markus Pilz) ftp://ftp.ifi.unizh.ch/pub/techreports/TR-98/ifi-98.04.ps.gz • The JavaTM Virtual Machine Specification Second Edition (Tim Lindholm, Frank Yellin) http://java.sun.com/docs/books/vmspec/2nd-edition/html/VMSpecTOC.doc.html • Inside the Java 2 Virtual Machine (Bill Venners) + Applets http://www.artima.com/insidejvm/applets http://www.artima.com/insidejvm/ed2/jvm.html 45 Bytecodemanipulation [ Quellen ] Quellen (2) • Java Programming Dynamics (Dennis M. Sosnoski) http://www-106.ibm.com/developerworks/java/library/j-dyn0429 • BCEL Homepage http://jakarta.apache.org/bcel • Beispiele für BCEL http://bcel.sourceforge.net • Javassist Homepage http://www.jboss.org/developers/projects/javassist.html • JikesBT Homepage http://www.alphaworks.ibm.com/tech/jikesbt 46 Bytecodemanipulation Fragen zum Thema? 47 Bytecodemanipulation Kontakt • Ronald Kutschke [email protected] • Daniel Haag [email protected] • Mirko Bleyh [email protected] • Markus Block [email protected] 48