fun with bytecode weaving

22
Fun with bytecode 1 / 21

Upload: mjgp2

Post on 18-Jul-2015

44 views

Category:

Technology


1 download

TRANSCRIPT

Fun with bytecode

1 / 21

Who the hell are you?ProgrammerEntrepeneurCTO of import.ioGeekEx-mathematicianLong-suffering Java user (yay, lambdas!)Proud father of two :)

2 / 21

So what's the plan?1. What?2. Why?3. How?4. Codez5. Q&A6. Beer!

3 / 21

Some JVM internalsDo you know how the JVM does its magic?

4 / 21

Per JVM

Heap for objectsPermGen/Metaspace

Per Thread

PC (Program Counter) tracks instruction position in a registerStack (as in trace) of Frames (method invocations)Native stack

Per frame

Local variable 32bit array ([0]=this)Operand 32bit stackConstant pool reference for the class

5 / 21

Operand stackThe Java stack is a last-in, first-out stack of 32-bit slots. Because each slot in thestack occupies 32 bits, all stack variables occupy at least 32 bits - even a byte.Longs/Doubles take 2 slots.

"We chose a stack organization so that it would be easy to emulate themachine efficiently on machines with few or irregular registers suchas the Intel 486."

Local variable arrayZero-indexed, 32 bit slots.

6 / 21

Bytecode"Understanding bytecode and what bytecode is likely to be generatedby a Java compiler helps the Java programmer in the same way thatknowledge of assembly helps the C or C++ programmer."

When a JVM loads a class file, it gets a stream of bytecodes that represent thelogic for each method that are interpreted or JIT compiled.

One byte opcode (mnemonics, action) and its operands.

7 / 21

Disassembling bytecodepublic static int factorial(int x) { int y = 1; for ( int z=2; z<=x; z++) y*=z; return y;}

PC keeps track of current position...

0 iconst_1 [1] [x] 1 istore_1 [] [x,1] 2 iconst_2 [2] [x,1] 3 istore_2 [] [x,1,2] 4 iload_2 [2] [x,1,2] 5 iload_0 [x,2][x,1,2] 6 if_icmpgt 19 (+13) [] [x,1,2] 9 iload_1 [1] [x,1,2] 10 iload_2 [2,1]11 imul [2] [x,1,2]12 istore_1 [] [x,2,2]13 iinc 2 by 1 [] [x,2,3]16 goto 4 (-12) [] [x,2,3]19 iload_1 [y] [x,y,z]20 ireturn [] [x,y,z]

8 / 21

Method signaturesV - voidB – byteC – charD – doubleF – floatI – intJ – longS – shortV – voidZ – boolean[ – array of the thing following the bracketL [class name] ; – instance of this class, with dots becoming slashes( [args] ) [return type] – method signature

For example:

public int foo(String bar, long[][] baz)

becomes

(Ljava/lang/String;[[J)I

9 / 21

What is bytecode weaving?Changing byte code for a class either up front or dynamically at run-time.

10 / 21

Why should I want to weave bytecode?Proxy creationAspect-orientated programmingLoggingSandboxingCode coverageAdding in features like co-routinesAnything else you can dream up :)

11 / 21

How to weaveWTF is a Java agent?

An agent is just an interceptor in front of your main method,executed in the same JVM and loaded by the same system classloader,and governed by the same security policy and context.

Need a class with a premain method:

public static void premain(String agentArgs, Instrumentation inst);

... and some special MANIFEST.MF lines:

Manifest-Version: 1.0Premain-Class: my.package.MyJavaAgentBoot-Class-Path: some-dependency.jar

... a command line option:

-javaagent:<jarpath>[=<options>]load Java programming language agent, see java.lang.instrument

... to hook into the Instrumentation class

12 / 21

Getting funky with InstrumentationLets you hook in ClassFileTransformer instances - which are what they soundlike.

byte[] transform( ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException;

But what's in the byte arrays?

13 / 21

Class structure

14 / 21

How do you modify the bytes?Manually (Super scary)JavassistASMOther libraries may be available... :)

15 / 21

Javassist: a quick asideIt'll parse Java source strings - no bytecode required.

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

pool.insertClassPath(new ByteArrayClassPath(className, classfileBuffer)); CtClass cclass = pool.get(className.replaceAll("/", ".")); if (cclass.isFrozen()) { return null; // use uninstrumented class, already processed } for (CtMethod currentMethod : cclass.getDeclaredMethods()) { currentMethod.insertBefore("System.err.println('foo');"); } return cclass.toBytecode();}

Easy, but not the quickest.

Not so good as a learning exercise either :)

16 / 21

ASM: total control, but like writingassembler.Event model, similar to SAX.

Extend abstract class:

class ClassVisitor { void visit(int version, int access, String name, String signature, String superName, String[] interfaces) void visitSource(String source, String debug) void visitOuterClass(String owner, String name, String desc) AnnotationVisitor visitAnnotation(String desc, boolean visible) AnnotationVisitor visitTypeAnnotation(int typeRef,TypePath typePath, String desc, boolean visible) void visitAttribute(Attribute attr) void visitInnerClass(String name, String outerName, String innerName, int access) FieldVisitor visitField(int access, String name, String desc, String signature, Object value) MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) void visitEnd()}

17 / 21

and hook into your ClassFileTransformer

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();}

Easy!

18 / 21

sio2boxA memory sandbox that counts allocations.

Add annotations to classes (SiO2Class) and methods (SiO2Method) to limit thetotal amount of memory allocated by untrusted code.

Don't take GC into account, interested in memory churn - could useReferenceQueue if we were.

Tracks:

Array.newInstancetype[].cloneObject instantiationnew type[] - ANEWARRAY, NEWARRAY, MULTIANEWARRAYObject.cloneArrayList.clone (TODO)

19 / 21

Quick examplePass through a MemoryStore object as the first argument (this is a convention).

MemoryStore memoryStore = new MemoryStore(maxMemory);myMethod(memoryStore, arg0, arg1);

Annotate the class and method:

@SiO2Classpublic class MyClass {

@SiO2Method public void myMethod(MemoryStore m, String arg0, Object arg1) { ... }}

If more memory is allocated than you specify, a MemoryExceededExceptionexception is thrown.

20 / 21

Code!Let's checkout github...

21 / 21