Living in the Matrix with Bytecode Manipulation QCon NY 2014 - - PowerPoint PPT Presentation

living in the matrix with bytecode manipulation
SMART_READER_LITE
LIVE PREVIEW

Living in the Matrix with Bytecode Manipulation QCon NY 2014 - - PowerPoint PPT Presentation

Living in the Matrix with Bytecode Manipulation QCon NY 2014 Wednesday, June 11, 14 Ashley Puls Senior Software Engineer New Relic, Inc. Wednesday, June 11, 14 Follow Along http://slidesha.re/1kZwCXr Wednesday, June 11, 14 Outline


slide-1
SLIDE 1

QCon NY 2014

Living in the Matrix with Bytecode Manipulation

Wednesday, June 11, 14

slide-2
SLIDE 2

Ashley Puls

Senior Software Engineer New Relic, Inc.

Wednesday, June 11, 14

slide-3
SLIDE 3

Follow Along

http://slidesha.re/1kZwCXr

Wednesday, June 11, 14

slide-4
SLIDE 4

Outline

  • What is bytecode?
  • Why manipulate bytecode?
  • What frameworks can be used to

manipulate bytecode?

  • Examine two frameworks in depth

Wednesday, June 11, 14

slide-5
SLIDE 5

What is Java bytecode?

.java file .class file Java compiler (javac) Class Loader Bytecode Verifier Java Runtime System Native OS

Java Virtual Machine

Source: http://www.techlila.com/write-programs-linux/ Wednesday, June 11, 14

slide-6
SLIDE 6

What is Java bytecode?

.java file .class file Java compiler (javac) Class Loader Bytecode Verifier Java Runtime System Native OS

Java Virtual Machine

Source: http://www.techlila.com/write-programs-linux/ Wednesday, June 11, 14

slide-7
SLIDE 7

What is Java bytecode?

.java file .class file Java compiler (javac) Class Loader Bytecode Verifier Java Runtime System Native OS

Java Virtual Machine

Source: http://www.techlila.com/write-programs-linux/

Instruction set of the Java Virtual Machine

Wednesday, June 11, 14

slide-8
SLIDE 8

Why learn about Java bytecode manipulation frameworks ?

Wednesday, June 11, 14

slide-9
SLIDE 9

Why learn about Java bytecode manipulation frameworks ?

  • A bytecode manipulation framework is likely already
  • n your stack
  • Spring
  • Hibernate
  • Groovy
  • Clojure
  • Eclipse
  • JRuby

Wednesday, June 11, 14

slide-10
SLIDE 10
  • A bytecode manipulation framework is likely already
  • n your stack
  • Spring
  • Hibernate
  • Groovy
  • Clojure
  • Eclipse
  • JRuby
  • Its really fun!!!

Why learn about Java bytecode manipulation frameworks ?

Wednesday, June 11, 14

slide-11
SLIDE 11

Why learn about Java bytecode manipulation frameworks ?

  • program analysis
  • find bugs in code
  • examine code complexity
  • generate classes
  • proxies
  • remove access to certain APIs
  • compiler for another language like Scala
  • transform classes without Java source code
  • profilers
  • ptimization and obfuscation
  • additional logging

Wednesday, June 11, 14

slide-12
SLIDE 12

Why learn about Java bytecode manipulation frameworks ?

  • program analysis
  • find bugs in code
  • examine code complexity
  • generate classes
  • proxies
  • remove access to certain APIs
  • compiler for another language like Scala
  • transform classes without Java source code
  • profilers
  • ptimization and obfuscation
  • additional logging

Wednesday, June 11, 14

slide-13
SLIDE 13

Logging

Source: http://www.vforteachers.com/About_NetSupport.htm

Wednesday, June 11, 14

slide-14
SLIDE 14

Logging

Source: http://www.vforteachers.com/About_NetSupport.htm, http://inzolo.com/blog/tutorials/bank-accounts

Wednesday, June 11, 14

slide-15
SLIDE 15

Logging

Source: http://www.vforteachers.com/About_NetSupport.htm, http://upload.wikimedia.org/wikipedia/commons/d/d3/49024-SOS-ATM.JPG

Wednesday, June 11, 14

slide-16
SLIDE 16

Logging

Audit Log: a message should be logged every time an important method is called

Source: http://www.vforteachers.com/About_NetSupport.htm

Wednesday, June 11, 14

slide-17
SLIDE 17

Logging

Source: http://www.vforteachers.com/About_NetSupport.htm

log important input parameters to the method Audit Log: a message should be logged every time an important method is called

Wednesday, June 11, 14

slide-18
SLIDE 18

Logging

public class BankTransactions { public static void main(String[] args) { BankTransactions bank = new BankTransactions(); // login and add i dollars to account for (int i = 0; i < 100; i++) { String accountId = "account" + i; bank.login("password", accountId, "Ashley"); bank.unimportantProcessing(accountId); bank.finalizeTransaction(accountId, Double.valueOf(i)); } System.out.println(“Transactions completed”); } }

Wednesday, June 11, 14

slide-19
SLIDE 19

Logging

public class BankTransactions { public static void main(String[] args) { BankTransactions bank = new BankTransactions(); // login and add i dollars to each account for (int i = 0; i < 100; i++) { String accountId = "account" + i; bank.login("password", accountId, "Ashley"); bank.unimportantProcessing(accountId); bank.finalizeTransaction(accountId, Double.valueOf(i)); } System.out.println(“Transactions completed”); } }

Wednesday, June 11, 14

slide-20
SLIDE 20

Logging

/** * A method annotation which should be used to indicate important methods whose * invocations should be logged. * */ public @interface ImportantLog { /** * The method parameter indexes whose values should be logged. For example, * if we have the method hello(int paramA, int paramB, int paramC), and we * wanted to log the values of paramA and paramC, then fields would be ["0", * "2"]. If we only want to log the value of paramB, then fields would be * ["1"]. */ String[] fields(); }

Wednesday, June 11, 14

slide-21
SLIDE 21

Logging

public void login(String password, String accountId, String userName) { // login logic } public void finalizeTransaction(String accountId, Double moneyToAdd) { // transaction logic }

Wednesday, June 11, 14

slide-22
SLIDE 22

Logging

@ImportantLog(fields = { "1", "2" }) public void login(String password, String accountId, String userName) { // login logic } @ImportantLog(fields = { "0", "1" }) public void finalizeTransaction(String accountId, Double moneyToAdd) { // transaction logic }

Wednesday, June 11, 14

slide-23
SLIDE 23

Logging

@ImportantLog(fields = { "1", "2" }) public void login(String password, String accountId, String userName) { // login logic } @ImportantLog(fields = { "0", "1" }) public void finalizeTransaction(String accountId, Double moneyToAdd) { // transaction logic }

A call was made to method "login" on class "com/example/qcon/mains/BankTransactions". Important params: Index 1 value: ${accountId} Index 2 value: ${userName}

Wednesday, June 11, 14

slide-24
SLIDE 24

Logging

@ImportantLog(fields = { "1", "2" }) public void login(String password, String accountId, String userName) { // login logic } @ImportantLog(fields = { "0", "1" }) public void finalizeTransaction(String accountId, Double moneyToAdd) { // transaction logic }

A call was made to method "finalizeTransaction" on class "com/example/qcon/ mains/BankTransactions". Important params: Index 0 value: ${accountId} Index 1 value: ${moneyToAdd} A call was made to method "login" on class "com/example/qcon/mains/BankTransactions". Important params: Index 1 value: ${accountId} Index 2 value: ${userName}

Wednesday, June 11, 14

slide-25
SLIDE 25

Java Agent

  • Ability to modify the bytecode without modifying the

application source code

  • Added in Java 1.5
  • Docs: http://docs.oracle.com/javase/8/docs/api/

java/lang/instrument/package-summary.html

Wednesday, June 11, 14

slide-26
SLIDE 26

Typical Java Process

JVM

public static void main(String[] args) BankTransactions.class Classloader

java com/example/qcon/mains/BankTransactions Transactions completed

Wednesday, June 11, 14

slide-27
SLIDE 27

Java Agent

JVM

Agent java -javaagent:/path/to/agent.jar com/example/qcon/mains/ BankTransactions

Wednesday, June 11, 14

slide-28
SLIDE 28

Java Agent

JVM

java -javaagent:/path/to/agent.jar com/example/qcon/mains/ BankTransactions

Wednesday, June 11, 14

slide-29
SLIDE 29

Java Agent

JVM

Agent java -javaagent:/path/to/agent.jar com/example/qcon/mains/ BankTransactions

Wednesday, June 11, 14

slide-30
SLIDE 30

Java Agent

JVM

void premain(String agentArgs, Instrumentation inst) Agent.class MyTransformer.class byte[] transform( . . . , byte[] bankTransBytes)

Agent

  • 1. call Agent premain in manifest
  • 2. JVM registers my transformer

java -javaagent:/path/to/agent.jar com/example/qcon/mains/ BankTransactions

Wednesday, June 11, 14

slide-31
SLIDE 31

Java Agent

JVM

void premain(String agentArgs, Instrumentation inst) Agent.class MyTransformer.class byte[] transform( . . . , byte[] bankTransBytes)

Agent

  • 1. call Agent premain in manifest
  • 2. JVM registers my transformer
  • 3. Give BankTransactions bytes to

MyTransformer

  • 4. MyTransformer provides

bytes to load

java -javaagent:/path/to/agent.jar com/example/qcon/mains/ BankTransactions

Wednesday, June 11, 14

slide-32
SLIDE 32

Java Agent

JVM

void main(String[] args) BankTransactions.class void premain(String agentArgs, Instrumentation inst) Agent.class MyTransformer.class byte[] transform( . . . , byte[] bankTransBytes)

Agent

  • 1. call Agent premain in manifest
  • 2. JVM registers my transformer
  • 3. Give BankTransactions bytes to

MyTransformer

  • 4. MyTransformer provides

bytes to load

  • 5. BankTransactions loaded and main

runs

java -javaagent:/path/to/agent.jar com/example/qcon/mains/ BankTransactions Transactions completed

Wednesday, June 11, 14

slide-33
SLIDE 33

lets code

Manifest: Premain-Class: com.example.qcon.agent.Agent

Wednesday, June 11, 14

slide-34
SLIDE 34

lets code

package com.example.qcon.agent; public class Agent { public static void premain(String agentArgs, Instrumentation inst) { System.out.println("Starting the agent"); inst.addTransformer(new ImportantLogClassTransformer()); } } Manifest: Premain-Class: com.example.qcon.agent.Agent

Wednesday, June 11, 14

slide-35
SLIDE 35

lets code

package com.example.qcon.agent; public class Agent { public static void premain(String agentArgs, Instrumentation inst) { System.out.println("Starting the agent"); inst.addTransformer(new ImportantLogClassTransformer()); } } Manifest: Premain-Class: com.example.qcon.agent.Agent

Wednesday, June 11, 14

slide-36
SLIDE 36

lets code

package com.example.qcon.agent; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; public class ImportantLogClassTransformer implements ClassFileTransformer { public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { //TODO return null; } }

Wednesday, June 11, 14

slide-37
SLIDE 37

lets code

package com.example.qcon.agent; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; public class ImportantLogClassTransformer implements ClassFileTransformer { public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { //TODO return null; } }

Wednesday, June 11, 14

slide-38
SLIDE 38

lets code

package com.example.qcon.agent; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; public class ImportantLogClassTransformer implements ClassFileTransformer { public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { System.out.println(" Loading class: " + className); return null; } }

Wednesday, June 11, 14

slide-39
SLIDE 39

lets code

Starting the agent Loading class: java/lang/invoke/MethodHandleImpl Loading class: java/lang/invoke/MemberName$Factory Loading class: java/lang/invoke/LambdaForm$NamedFunction Loading class: java/lang/invoke/MethodType$ConcurrentWeakInternSet Loading class: java/lang/invoke/MethodHandleStatics Loading class: java/lang/invoke/MethodHandleStatics$1 Loading class: java/lang/invoke/MethodTypeForm Loading class: java/lang/invoke/Invokers Loading class: java/lang/invoke/MethodType$ConcurrentWeakInternSet$WeakEntry Loading class: java/lang/Void Loading class: java/lang/IllegalAccessException Loading class: sun/misc/PostVMInitHook Loading class: sun/launcher/LauncherHelper Loading class: java/util/concurrent/ConcurrentHashMap$ForwardingNode Loading class: sun/misc/URLClassPath$FileLoader$1 Loading class: com/example/qcon/mains/BankTransactions Loading class: sun/launcher/LauncherHelper$FXHelper

Wednesday, June 11, 14

slide-40
SLIDE 40

lets code

package com.example.qcon.agent; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; public class ImportantLogClassTransformer implements ClassFileTransformer { public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { System.out.println(" Loading class: " + className); return null; } }

Wednesday, June 11, 14

slide-41
SLIDE 41

lets code

package com.example.qcon.agent; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; public class ImportantLogClassTransformer implements ClassFileTransformer { public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { // manipulate the bytes here and then return them return null; } }

Wednesday, June 11, 14

slide-42
SLIDE 42

Bytecode Manipulation Frameworks

  • ASM: http://asm.ow2.org/
  • BCEL: http://commons.apache.org/proper/commons-bcel/
  • CGLib: https://github.com/cglib/cglib
  • Javassist: http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/
  • Serp: http://serp.sourceforge.net/
  • Cojen: https://github.com/cojen/Cojen/wiki
  • Soot: http://www.sable.mcgill.ca/soot/

Wednesday, June 11, 14

slide-43
SLIDE 43

Bytecode Manipulation Frameworks

  • ASM: http://asm.ow2.org/
  • BCEL: http://commons.apache.org/proper/commons-bcel/
  • CGLib: https://github.com/cglib/cglib
  • Javassist: http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/
  • Serp: http://serp.sourceforge.net/
  • Cojen: https://github.com/cojen/Cojen/wiki
  • Soot: http://www.sable.mcgill.ca/soot/

Wednesday, June 11, 14

slide-44
SLIDE 44

Javassist

  • Java Programming Assistant
  • Subproject of JBoss
  • Actively updated
  • Version 3.18.2 released May 2014
  • Source code: https://github.com/jboss-javassist/

javassist

  • Documentation: http://www.csg.ci.i.u-tokyo.ac.jp/

~chiba/javassist/tutorial/tutorial.html

Wednesday, June 11, 14

slide-45
SLIDE 45

Javassist

ArrayList HashMap

CtClass: represents a compile time class

Wednesday, June 11, 14

slide-46
SLIDE 46

Javassist

ClassPool: container of CtClass objects

ArrayList HashMap

CtClass: represents a compile time class

Wednesday, June 11, 14

slide-47
SLIDE 47

Javassist

ClassPool: container of CtClass objects

ArrayList HashMap

ArrayList HashMap

CtClass: represents a compile time class

Wednesday, June 11, 14

slide-48
SLIDE 48

Javassist

ClassPool: container of CtClass objects

ArrayList HashMap BankTrans

ArrayList HashMap

CtClass: represents a compile time class

Wednesday, June 11, 14

slide-49
SLIDE 49

Javassist

CtClass: represents a compile time class ClassPool: container of CtClass objects

ArrayList HashMap BankTrans

ArrayList HashMap

ByteArrayClassPath: converts a byte[] to a CtClass

Wednesday, June 11, 14

slide-50
SLIDE 50

Javassist

ClassPool: container of CtClass objects

ArrayList HashMap BankTrans

ArrayList HashMap

Classpool.getDefault().insertClassPath(new ByteArrayClassPath(“BankTrans”, classBytes);

ByteArrayClassPath: converts a byte[] to a CtClass CtClass: represents a compile time class

Wednesday, June 11, 14

slide-51
SLIDE 51

Javassist

ClassPool: container of CtClass objects

ArrayList HashMap BankTrans

ArrayList HashMap BankTrans

Classpool.getDefault().insertClassPath(new ByteArrayClassPath(“BankTrans”, classBytes);

ByteArrayClassPath: converts a byte[] to a CtClass CtClass: represents a compile time class

Wednesday, June 11, 14

slide-52
SLIDE 52

Javassist

ClassPool: container of CtClass objects

ArrayList HashMap BankTrans

ArrayList HashMap BankTrans

Classpool.getDefault().insertClassPath(new ByteArrayClassPath(“BankTrans”, classBytes);

ByteArrayClassPath: converts a byte[] to a CtClass CtClass: represents a compile time class

CtClass bank = Classpool.getDefault().get(“BankTrans”);

Wednesday, June 11, 14

slide-53
SLIDE 53

Javassist

ClassPool: container of CtClass objects

ArrayList HashMap BankTrans

ArrayList HashMap BankTrans

ByteArrayClassPath: converts a byte[] to a CtClass CtClass: represents a compile time class

BankTrans

Classpool.getDefault().insertClassPath(new ByteArrayClassPath(“BankTrans”, classBytes); CtClass bank = Classpool.getDefault().get(“BankTrans”);

Wednesday, June 11, 14

slide-54
SLIDE 54

Javassist

BankTrans

CtClass: represents a compile time class

Wednesday, June 11, 14

slide-55
SLIDE 55

Javassist

CtConstructor: represents a compile time constructor

init

BankTrans

CtClass: represents a compile time class

Wednesday, June 11, 14

slide-56
SLIDE 56

Javassist

CtConstructor: represents a compile time constructor

init

BankTrans

CtClass: represents a compile time class CtMethod: represents a compile time class

login process

Wednesday, June 11, 14

slide-57
SLIDE 57

Javassist

CtConstructor: represents a compile time constructor

init

CtClass: represents a compile time class CtMethod: represents a compile time method

CtMethod loginMethod = loginCtClass.getDeclaredMethod(“login”);

BankTrans

login process

Wednesday, June 11, 14

slide-58
SLIDE 58

Javassist

CtConstructor: represents a compile time constructor

init

CtClass: represents a compile time class CtMethod: represents a compile time method

CtMethod loginMethod = loginCtClass.getDeclaredMethod(“login”);

login

BankTrans

login process

Wednesday, June 11, 14

slide-59
SLIDE 59

Javassist

login

CtMethod: represents a compile time method

Wednesday, June 11, 14

slide-60
SLIDE 60

Javassist

Modifications:

login

CtMethod: represents a compile time method

Wednesday, June 11, 14

slide-61
SLIDE 61

Javassist

Modifications:

login

CtMethod: represents a compile time method

putMethod.insertAfter(“System.out.println(\”after method\”);”); putMethod.insertBefore(“System.out.println(\“before method\”);”);

Wednesday, June 11, 14

slide-62
SLIDE 62

Javassist

Modifications:

System.out.println(“before method”);

CtMethod: represents a compile time method

putMethod.insertAfter(“System.out.println(\”after method\”);”); putMethod.insertBefore(“System.out.println(\“before method\”);”); System.out.println(“after method”);

login

Wednesday, June 11, 14

slide-63
SLIDE 63

Javassist

Modifications: CtMethod: represents a compile time method

CtClass exceptionType = classpool.get(“java.io.IOException”); putMethod.addCatch(“{System.out.println($e); throw $e}”, exceptionType);

login

Wednesday, June 11, 14

slide-64
SLIDE 64

Javassist

Modifications: CtMethod: represents a compile time method

CtClass exceptionType = classpool.get(“java.io.IOException”); System.out.println(“exception”); throw exception; putMethod.addCatch(“{System.out.println($e); throw $e}”, exceptionType);

login

Wednesday, June 11, 14

slide-65
SLIDE 65

Javassist

Modifications: CtMethod: represents a compile time method

putMethod.insertAt(5, true, “System.out.println(\“hello\”);”);

login

Wednesday, June 11, 14

slide-66
SLIDE 66

Javassist

Modifications: CtMethod: represents a compile time method

putMethod.insertAt(5, true, “System.out.println(\“hello\”);”); System.out.println(“hello”);

login

Wednesday, June 11, 14

slide-67
SLIDE 67

Javassist

Modifications: CtMethod: represents a compile time method

insertBefore insertAfter insertAt addCatch System.out.println(“before method”); System.out.println(“after method”); System.out.println(“hello”); System.out.println(“exception”); throw exception;

login

Wednesday, June 11, 14

slide-68
SLIDE 68

Javassist

Modifications: CtMethod: represents a compile time method

insertBefore insertAfter insertAt addCatch

Freeze Class:

System.out.println(“before method”); System.out.println(“after method”); System.out.println(“hello”); System.out.println(“exception”); throw exception;

login

Wednesday, June 11, 14

slide-69
SLIDE 69

Javassist

Modifications: CtMethod: represents a compile time method

insertBefore insertAfter insertAt addCatch

Freeze Class:

System.out.println(“before method”); System.out.println(“after method”); System.out.println(“hello”); System.out.println(“exception”); throw exception; writeFile() toClass() toBytecode()

login

Wednesday, June 11, 14

slide-70
SLIDE 70

lets code

Wednesday, June 11, 14

slide-71
SLIDE 71

lets code

package com.example.qcon.agent; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; public class ImportantLogClassTransformer implements ClassFileTransformer { public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { //TODO return null; } }

Wednesday, June 11, 14

slide-72
SLIDE 72

lets code

package com.example.qcon.agent; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; public class ImportantLogClassTransformer implements ClassFileTransformer { public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { //TODO return null; } }

Wednesday, June 11, 14

slide-73
SLIDE 73

lets code

public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] cfbuffer) throws IllegalClassFormatException {

  • 1. convert byte array to a ct class object
  • 2. check each method of ct class for annotation @ImportantLog
  • 3. if @ImportantLog annotation present on method, then
  • a. get important method parameter indexes
  • b. add logging statement to beginning of the method

return null; }

Wednesday, June 11, 14

slide-74
SLIDE 74

lets code

public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] cfbuffer) throws IllegalClassFormatException { pool.insertClassPath(new ByteArrayClassPath(className, classfileBuffer)); CtClass cclass = pool.get(className.replaceAll("/", "."));

  • 2. check each method of ct class for annotation @ImportantLog
  • 3. if @ImportantLog annotation present on method, then
  • a. get important method parameter indexes
  • b. add logging statement to beginning of the method

return null; }

Wednesday, June 11, 14

slide-75
SLIDE 75

lets code

public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] cfbuffer) throws IllegalClassFormatException { pool.insertClassPath(new ByteArrayClassPath(className, classfileBuffer)); CtClass cclass = pool.get(className.replaceAll("/", ".")); if (!cclass.isFrozen()) { for (CtMethod currentMethod : cclass.getDeclaredMethods()) { Annotation annotation = getAnnotation(currentMethod);

  • 3. if @ImportantLog annotation present on method, then
  • a. get important method parameter indexes
  • b. add logging statement to beginning of the method

} } return null; }

Wednesday, June 11, 14

slide-76
SLIDE 76

lets code

public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] cfbuffer) throws IllegalClassFormatException { pool.insertClassPath(new ByteArrayClassPath(className, classfileBuffer)); CtClass cclass = pool.get(className.replaceAll("/", ".")); if (!cclass.isFrozen()) { for (CtMethod currentMethod : cclass.getDeclaredMethods()) { Annotation annotation = getAnnotation(currentMethod); if (annotation != null) { List<String> parameterIndexes = getParamIndexes(annotation);

  • b. add logging statement to beginning of the method

} } } return null; }

Wednesday, June 11, 14

slide-77
SLIDE 77

lets code

public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] cfbuffer) throws IllegalClassFormatException { pool.insertClassPath(new ByteArrayClassPath(className, classfileBuffer)); CtClass cclass = pool.get(className.replaceAll("/", ".")); if (!cclass.isFrozen()) { for (CtMethod currentMethod : cclass.getDeclaredMethods()) { Annotation annotation = getAnnotation(currentMethod); if (annotation != null) { List<String> parameterIndexes = getParamIndexes(annotation); currentMethod.insertBefore(createJavaString( currentMethod, className, parameterIndexes)); } } return cclass.toBytecode(); } return null; }

Wednesday, June 11, 14

slide-78
SLIDE 78

lets code

public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] cfbuffer) throws IllegalClassFormatException { pool.insertClassPath(new ByteArrayClassPath(className, classfileBuffer)); CtClass cclass = pool.get(className.replaceAll("/", ".")); if (!cclass.isFrozen()) { for (CtMethod currentMethod : cclass.getDeclaredMethods()) { Annotation annotation = getAnnotation(currentMethod); if (annotation != null) { List<String> parameterIndexes = getParamIndexes(annotation); currentMethod.insertBefore(createJavaString( currentMethod, className, parameterIndexes)); } } return cclass.toBytecode(); } return null; }

Wednesday, June 11, 14

slide-79
SLIDE 79

lets code

private Annotation getAnnotation(CtMethod method) { MethodInfo mInfo = method.getMethodInfo(); // the attribute we are looking for is a runtime invisible attribute // use Retention(RetentionPolicy.RUNTIME) on the annotation to make it // visible at runtime AnnotationsAttribute attInfo = (AnnotationsAttribute) mInfo .getAttribute(AnnotationsAttribute.invisibleTag); if (attInfo != null) { // this is the type name meaning use dots instead of slashes return attInfo.getAnnotation("com.example.qcon.mains.ImportantLog"); } return null; }

Wednesday, June 11, 14

slide-80
SLIDE 80

lets code

public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] cfbuffer) throws IllegalClassFormatException { pool.insertClassPath(new ByteArrayClassPath(className, classfileBuffer)); CtClass cclass = pool.get(className.replaceAll("/", ".")); if (!cclass.isFrozen()) { for (CtMethod currentMethod : cclass.getDeclaredMethods()) { Annotation annotation = getAnnotation(currentMethod); if (annotation != null) { List<String> parameterIndexes = getParamIndexes(annotation); currentMethod.insertBefore(createJavaString( currentMethod, className, parameterIndexes)); } } return cclass.toBytecode(); } return null; }

Wednesday, June 11, 14

slide-81
SLIDE 81

lets code

private List<String> getParamIndexes(Annotation annotation) { ArrayMemberValue fields = (ArrayMemberValue) annotation .getMemberValue(“fields”); if (fields != null) { MemberValue[] values = (MemberValue[]) fields.getValue(); List<String> parameterIndexes = new ArrayList<String>(); for (MemberValue val : values) { parameterIndexes.add(((StringMemberValue) val).getValue()); } return parameterIndexes; } return Collections.emptyList(); }

Wednesday, June 11, 14

slide-82
SLIDE 82

lets code

public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] cfbuffer) throws IllegalClassFormatException { pool.insertClassPath(new ByteArrayClassPath(className, classfileBuffer)); CtClass cclass = pool.get(className.replaceAll("/", ".")); if (!cclass.isFrozen()) { for (CtMethod currentMethod : cclass.getDeclaredMethods()) { Annotation annotation = getAnnotation(currentMethod); if (annotation != null) { List<String> parameterIndexes = getParamIndexes(annotation); currentMethod.insertBefore(createJavaString( currentMethod, className, parameterIndexes)); } } return cclass.toBytecode(); } return null; }

Wednesday, June 11, 14

slide-83
SLIDE 83

lets code

private String createJavaString(CtMethod currentMethod, String className, List<String> indexParameters) { StringBuilder sb = new StringBuilder(); sb.append("{StringBuilder sb = new StringBuilder"); sb.append("(\"A call was made to method '\");"); sb.append("sb.append(\""); sb.append(currentMethod.getName()); sb.append("\");sb.append(\"' on class '\");"); sb.append("sb.append(\""); sb.append(className); sb.append("\");sb.append(\"'.\");"); sb.append("sb.append(\"\\n Important params:\");"); . . .

Wednesday, June 11, 14

slide-84
SLIDE 84

lets code

private String createJavaString(CtMethod currentMethod, String className, List<String> indexParameters) { StringBuilder sb = new StringBuilder(); sb.append("{StringBuilder sb = new StringBuilder"); sb.append("(\"A call was made to method '\");"); sb.append("sb.append(\""); sb.append(currentMethod.getName()); sb.append("\");sb.append(\"' on class '\");"); sb.append("sb.append(\""); sb.append(className); sb.append("\");sb.append(\"'.\");"); sb.append("sb.append(\"\\n Important params:\");"); . . .

Put multiple statements inside brackets {}

Wednesday, June 11, 14

slide-85
SLIDE 85

lets code

private String createJavaString(CtMethod currentMethod, String className, List<String> indexParameters) { . . . for (String index : indexParameters) { try { int localVar = Integer.parseInt(index) + 1; sb.append("sb.append(\"\\n Index: \");"); sb.append("sb.append(\""); sb.append(index); sb.append("\");sb.append(\" value: \");"); sb.append("sb.append($" + localVar + ");"); } catch (NumberFormatException e) { e.printStackTrace(); } } sb.append("System.out.println(sb.toString());}"); return sb.toString(); }

Wednesday, June 11, 14

slide-86
SLIDE 86

lets code

private String createJavaString(CtMethod currentMethod, String className, List<String> indexParameters) { . . . for (String index : indexParameters) { try { int localVar = Integer.parseInt(index) + 1; sb.append("sb.append(\"\\n Index: \");"); sb.append("sb.append(\""); sb.append(index); sb.append("\");sb.append(\" value: \");"); sb.append("sb.append($" + localVar + ");"); } catch (NumberFormatException e) { e.printStackTrace(); } } sb.append("System.out.println(sb.toString());}"); return sb.toString(); }

$0, $1, $2, ... can be used to access “this” and the actual method parameters

Wednesday, June 11, 14

slide-87
SLIDE 87

lets code

public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] cfbuffer) throws IllegalClassFormatException { pool.insertClassPath(new ByteArrayClassPath(className, classfileBuffer)); CtClass cclass = pool.get(className.replaceAll("/", ".")); if (!cclass.isFrozen()) { for (CtMethod currentMethod : cclass.getDeclaredMethods()) { Annotation annotation = getAnnotation(currentMethod); if (annotation != null) { List<String> parameterIndexes = getParamIndexes(annotation); currentMethod.insertBefore(createJavaString( currentMethod, className, parameterIndexes)); } } return cclass.toBytecode(); } return null; }

Wednesday, June 11, 14

slide-88
SLIDE 88

Javassist

  • Positives
  • Simplicity
  • Do not have to write actual bytecode
  • Decent documentation
  • Negatives
  • Generally slower than ASM
  • Less functionality

Wednesday, June 11, 14

slide-89
SLIDE 89

ASM

  • Released in Open Source in 2002
  • Actively updated
  • Version 5.0.3 released May 2014
  • Two ASM libraries
  • Event based (SAX like)
  • Visitor design pattern
  • Object based (DOM like)
  • Documentation: http://download.forge.objectweb.org/

asm/asm4-guide.pdf

Wednesday, June 11, 14

slide-90
SLIDE 90

ASM

Source: http://download.forge.objectweb.org/asm/asm4-guide.pdf Wednesday, June 11, 14

slide-91
SLIDE 91

ASM

Source: http://download.forge.objectweb.org/asm/asm4-guide.pdf Wednesday, June 11, 14

slide-92
SLIDE 92

ASM

Source: http://download.forge.objectweb.org/asm/asm4-guide.pdf Wednesday, June 11, 14

slide-93
SLIDE 93

ASM

ClassReader: given a byte[], parses a compiled class

ClassReader: event producer BankTrans ClassWriter: event consumer ClassVisitor: event filter

Wednesday, June 11, 14

slide-94
SLIDE 94

ASM

ClassReader: given a byte[], parses a compiled class

ClassReader: event producer BankTrans ClassWriter: event consumer visitField visitMethod ClassVisitor: event filter

Wednesday, June 11, 14

slide-95
SLIDE 95

ASM

ClassVisitor: delegates class events, event filter

visitAttribute visitField visitMethod visitInnerClass visitEnd

ClassReader: given a byte[], parses a compiled class

ClassReader: event producer BankTrans ClassWriter: event consumer visitField visitMethod ClassVisitor: event filter

Wednesday, June 11, 14

slide-96
SLIDE 96

ASM

ClassVisitor: delegates class events, event filter

visitAttribute visitField visitMethod visitInnerClass visitEnd

ClassWriter: produces output byte[] ClassReader: given a byte[], parses a compiled class

ClassReader: event producer BankTrans ClassWriter: event consumer visitField visitMethod BankTrans ClassVisitor: event filter

Wednesday, June 11, 14

slide-97
SLIDE 97

lets code

package com.example.qcon.agent; import java.lang.instrument.Instrumentation; public class Agent { public static void premain(String agentArgs, Instrumentation inst) { System.out.println("Starting the agent"); inst.addTransformer(new ImportantLogClassTransformer()); } }

Wednesday, June 11, 14

slide-98
SLIDE 98

lets code

package com.example.qcon.agent; import java.lang.instrument.Instrumentation; public class Agent { public static void premain(String agentArgs, Instrumentation inst) { System.out.println("Starting the agent"); inst.addTransformer(new ImportantLogClassTransformer()); } }

Wednesday, June 11, 14

slide-99
SLIDE 99

lets code

package com.example.qcon.agent; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; public class ImportantLogClassTransformer implements ClassFileTransformer { public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { //TODO return null; } }

Wednesday, June 11, 14

slide-100
SLIDE 100

lets code

package com.example.qcon.agent; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; public class ImportantLogClassTransformer implements ClassFileTransformer { public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { //TODO return null; } }

Wednesday, June 11, 14

slide-101
SLIDE 101

lets code

public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { ClassReader cr = new ClassReader(classfileBuffer); ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES); cr.accept(cw, 0); return cw.toByteArray(); }

Wednesday, June 11, 14

slide-102
SLIDE 102

lets code

public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { ClassReader cr = new ClassReader(classfileBuffer); ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES); ClassVisitor cv = new LogMethodClassVisitor(cw, className); cr.accept(cv, 0); return cw.toByteArray(); }

Wednesday, June 11, 14

slide-103
SLIDE 103

ASM

ClassVisitor: delegates class events, event filter

visitAttribute visitField visitMethod visitInnerClass visitEnd

ClassWriter: produces output byte[] ClassReader: given a byte[], parses a compiled class

ClassReader: event producer BankTrans ClassWriter: event consumer visitMethod BankTrans LogMethod ClassVisitor: event filter

Wednesday, June 11, 14

slide-104
SLIDE 104

ASM

Source: http://download.forge.objectweb.org/asm/asm4-guide.pdf Wednesday, June 11, 14

slide-105
SLIDE 105

lets code

public class LogMethodClassVisitor extends ClassVisitor { private String className; public LogMethodIfAnnotationVisitor(ClassVisitor cv, String pClassName) { super(Opcodes.ASM5, cv); className = pClassName; } @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {

// put our logic in here

} }

Wednesday, June 11, 14

slide-106
SLIDE 106

lets code

public class LogMethodClassVisitor extends ClassVisitor { private String className; public LogMethodIfAnnotationVisitor(ClassVisitor cv, String pClassName) { super(Opcodes.ASM5, cv); className = pClassName; } @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {

// put our logic in here

} }

Wednesday, June 11, 14

slide-107
SLIDE 107

ASM

Source: http://download.forge.objectweb.org/asm/asm4-guide.pdf Wednesday, June 11, 14

slide-108
SLIDE 108

ASM

Source: http://download.forge.objectweb.org/asm/asm4-guide.pdf Wednesday, June 11, 14

slide-109
SLIDE 109

ASM

Source: http://download.forge.objectweb.org/asm/asm4-guide.pdf Wednesday, June 11, 14

slide-110
SLIDE 110

ASM

MethodVisitor: method event filter

MethodVisitor MethodVisitor visitCode login method visitor login method visitor visitAnnotation visitEnd visitCode visitTryCatchBlock visitEnd visitAttribute

Wednesday, June 11, 14

slide-111
SLIDE 111

ASM

Source: http://download.forge.objectweb.org/asm/asm4-guide.pdf Wednesday, June 11, 14

slide-112
SLIDE 112

lets code

public class LogMethodClassVisitor extends ClassVisitor { private String className; public LogMethodIfAnnotationVisitor(ClassVisitor cv, String pClassName) { super(Opcodes.ASM5, cv); className = pClassName; } @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); return new PrintMessageMethodVisitor(mv, name, className); } }

Wednesday, June 11, 14

slide-113
SLIDE 113

lets code

public class PrintMessageMethodVisitor extends MethodVisitor { private String methodName; private String className; private boolean isAnnotationPresent; private List<String> parameterIndexes; public PrintMessageMethodVisitor(MethodVisitor mv, String methodName, String className) { } @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) { } @Override public void visitCode() { } }

Wednesday, June 11, 14

slide-114
SLIDE 114

lets code

public class PrintMessageMethodVisitor extends MethodVisitor { private String methodName; private String className; private boolean isAnnotationPresent; private List<String> parameterIndexes; public PrintMessageMethodVisitor(MethodVisitor mv, String methodName, String className) { // initialize instance variables } @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) {

  • 1. check method for annotation @ImportantLog
  • 2. if annotation present, then get important method param indexes

} @Override public void visitCode() {

  • 3. if annotation present, add logging to beginning of the method

} }

Wednesday, June 11, 14

slide-115
SLIDE 115

lets code

public AnnotationVisitor visitAnnotation(String desc, boolean visible) { if ("Lcom/example/qcon/mains/ImportantLog;".equals(desc)) {

isAnnotationPresent = true;

return new AnnotationVisitor(Opcodes.ASM5, super.visitAnnotation(desc, visible)) { public AnnotationVisitor visitArray(String name) { if (“fields”.equals(name)) { return new AnnotationVisitor(Opcodes.ASM5, super.visitArray(name)) { public void visit(String name, Object value) { parameterIndexes.add((String) value); super.visit(name, value); } }; } else { return super.visitArray(name); } } }; } return super.visitAnnotation(desc, visible); }

Wednesday, June 11, 14

slide-116
SLIDE 116

lets code

public class PrintMessageMethodVisitor extends MethodVisitor { private String methodName; private String className; private boolean isAnnotationPresent; private List<String> parameterIndexes; public PrintMessageMethodVisitor(MethodVisitor mv, String methodName, String className) { // initialize instance variables } @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) {

  • 1. check method for annotation @ImportantLog
  • 2. if annotation present, then get important method param indexes

} @Override public void visitCode() {

  • 3. if annotation present, add logging statement to beginning of the method

} }

Wednesday, June 11, 14

slide-117
SLIDE 117

lets code

public void visitCode() {

if (isAnnotationPresent) { // create string builder mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); mv.visitTypeInsn(Opcodes.NEW, "java/lang/StringBuilder"); mv.visitInsn(Opcodes.DUP); // add everything to the string builder mv.visitLdcInsn("A call was made to method \""); mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "(Ljava/lang/String;)V", false); mv.visitLdcInsn(methodName); mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false); . . .

Wednesday, June 11, 14

slide-118
SLIDE 118

What is Java bytecode?

use javap to examine the bytecode

Wednesday, June 11, 14

slide-119
SLIDE 119

What is Java bytecode?

public class PrintMessage { private String methodName; private String className; public PrintMessage(String mName, String cName) { methodName = mName; className = cName; } public void print() { StringBuilder sb = new StringBuilder(); sb.append("A call was made to method \""); sb.append(methodName); sb.append("\" on class \""); sb.append(className); sb.append("\"."); System.out.println(sb.toString()); }

Wednesday, June 11, 14

slide-120
SLIDE 120

What is Java bytecode?

javap -c bin/com/example/qcon/mains/PrintMessage

Wednesday, June 11, 14

slide-121
SLIDE 121

What is Java bytecode?

javap -c bin/com/example/qcon/mains/PrintMessage

public void print(); Code: 0: new #38 // class java/lang/StringBuilder 3: dup 4: invokespecial #40 // Method java/lang/ StringBuilder."<init>":()V 7: astore_1 8: aload_1 9: ldc #41 // String A call was made to method \" 11: invokevirtual #43 // Method java/lang/ StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 14: pop 15: aload_1 16: aload_0 17: getfield #14 // Field methodName:Ljava/lang/String; 20: invokevirtual #43 // Method java/lang/ StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; . . .

Wednesday, June 11, 14

slide-122
SLIDE 122

What is Java bytecode?

each line represents one JVM instruction

public void print(); Code: 0: new #38 // class java/lang/StringBuilder 3: dup 4: invokespecial #40 // Method java/lang/ StringBuilder."<init>":()V 7: astore_1 8: aload_1 9: ldc #41 // String A call was made to method \" 11: invokevirtual #43 // Method java/lang/ StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 14: pop 15: aload_1 16: aload_0 17: getfield #14 // Field methodName:Ljava/lang/String; 20: invokevirtual #43 // Method java/lang/ StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; . . .

Wednesday, June 11, 14

slide-123
SLIDE 123

What is Java bytecode?

JVM instruction = 1 opcode with 0 or more operands

public void print(); Code: 0: new #38 // class java/lang/StringBuilder 3: dup 4: invokespecial #40 // Method java/lang/ StringBuilder."<init>":()V 7: astore_1 8: aload_1 9: ldc #41 // String A call was made to method \" 11: invokevirtual #43 // Method java/lang/ StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 14: pop 15: aload_1 16: aload_0 17: getfield #14 // Field methodName:Ljava/lang/String; 20: invokevirtual #43 // Method java/lang/ StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; . . .

Wednesday, June 11, 14

slide-124
SLIDE 124

What is Java bytecode?

Opcode Description load

load a reference onto the stack from a local variable iload, lload, fload, dload, aload

store

stores a value from the stack into a local variable istore, lstore, fstore, dstore, astore

lcd

push a constant from a constant pool onto the stack

return

method return instruction ireturn, lreturn, freturn, dreturn, areturn, return

invokevirtual

invoke an instance method on an object

invokespecial

invokes an instance method requiring special handling such as an initialization method See the spec for more info: http://docs.oracle.com/javase/specs/jvms/se8/jvms8.pdf

Wednesday, June 11, 14

slide-125
SLIDE 125

What is Java bytecode?

Opcode Description invokestatic

invoke a class (static) method on a named class

athrow

throws an exception

new

create a new class

newarray

create a new array

if<cond>

branch if int comparison with 0 succeeds ifeq, ifne, iflt, ifge, ifgt, ifle

dup

duplicate the top operand stack value See the spec for more info: http://docs.oracle.com/javase/specs/jvms/se8/jvms8.pdf

Wednesday, June 11, 14

slide-126
SLIDE 126

What is Java bytecode?

Wednesday, June 11, 14

slide-127
SLIDE 127

What is Java bytecode?

Wednesday, June 11, 14

slide-128
SLIDE 128

What is Java bytecode?

Wednesday, June 11, 14

slide-129
SLIDE 129

lets code

public void visitCode() {

if (isAnnotationPresent) { // create string builder mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); mv.visitTypeInsn(Opcodes.NEW, "java/lang/StringBuilder"); mv.visitInsn(Opcodes.DUP); // add everything to the string builder mv.visitLdcInsn("A call was made to method \""); mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "(Ljava/lang/String;)V", false); mv.visitLdcInsn(methodName); mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false); . . .

Wednesday, June 11, 14

slide-130
SLIDE 130

ASM

  • Positives
  • Speed and Size
  • Decent documentation
  • Depth of Functionality
  • Number of people using framework
  • Negatives
  • Need to write actual byte code
  • longer developer ramp-up

Wednesday, June 11, 14

slide-131
SLIDE 131

Why learn about Java bytecode manipulation frameworks ?

  • program analysis
  • find bugs in code
  • examine code complexity
  • generate classes
  • proxies
  • remove access to certain APIs
  • compiler for another language like Scala
  • transform classes without Java source code
  • profilers
  • ptimization and obfuscation
  • additional logging

Wednesday, June 11, 14

slide-132
SLIDE 132

Bytecode Manipulation Frameworks

  • ASM: http://asm.ow2.org/
  • BCEL: http://commons.apache.org/proper/commons-bcel/
  • CGLib: https://github.com/cglib/cglib
  • Javassist: http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/
  • Serp: http://serp.sourceforge.net/
  • Cojen: https://github.com/cojen/Cojen/wiki
  • Soot: http://www.sable.mcgill.ca/soot/

Wednesday, June 11, 14

slide-133
SLIDE 133

Source: http://www.kulfoto.com/dog-pictures/15799/mans-best-friend

Make bytecode manipulation frameworks your friend. They might save your job one day.

Wednesday, June 11, 14

slide-134
SLIDE 134

Wednesday, June 11, 14

slide-135
SLIDE 135

Source: http://alangregerman.typepad.com/.a/6a00d83516c0ad53ef017c3329aba8970b-800wi

Questions?

Wednesday, June 11, 14