Presentation is loading. Please wait.

Presentation is loading. Please wait.

Ivan Kinash, Mikhail Dudarev Licel Corporation JavaOne 2015

Similar presentations


Presentation on theme: "Ivan Kinash, Mikhail Dudarev Licel Corporation JavaOne 2015"— Presentation transcript:

1 Ivan Kinash, Mikhail Dudarev Licel Corporation JavaOne 2015
Protecting Java Bytecode from Hackers with the InvokeDynamic Instruction Ivan Kinash, Mikhail Dudarev Licel Corporation JavaOne 2015

2 About us Licel Corporation Web:

3 Java Bytecode High level JVM instruction set Stack oriented
Instruction format Example: opcode operand 1 operand 2 invokevirtual (0xb6) index1 index2

4 Native Code vs Java Bytecode
C-code: main(){ printf("Hello JavaOne 2015\n"); } Java-code: public class Test { public static void main(String[] args) { System.out.println("Hello JavaOne 2015"); }

5 Native Code Dump vs ByteCode Dump _main pushq %rbp movq %rsp, %rbp
subq $0x10, %rsp ## "Hello JavaOne'2015\n" leaq x37(%rip), %rdi movb $0x0, %al ## symbol stub for: _printf callq x100000f66 movl $0x0, %ecx movl %eax, -0x4(%rbp) movl %ecx, %eax addq $0x10, %rsp popq %rbp retq public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V Flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=1, args_size=1 // Field java/lang/System.out:Ljava/io/PrintStream; 0: getstatic #2 // String Hello JavaOne 2015 3: ldc #3 // Method // java/io/PrintStream.println:(Ljava/lang/String;)V 5: invokevirtual #4 8: return

6 Java Bytecode Dump (structured)
0: getstatic # // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc # // String Hello JavaOne 2015 5: invokevirtual # // Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: return opcode operands constant pool values getstatic Field#2 java/lang/System.out:Ljava/io/PrintStream; 3 ldc String#3 Hello JavaOne 2015 5 invokevirtual Method#4 java/io/PrintStream.println:(Ljava/lang/String;)V 8 return

7 Java Bytecode Decompiler
Original code with lamdas: public static void main(String[] args) { Runnable r = () -> System.out.println("Hello JavaOne 2015"); r.run(); } Bytecode dump 0: invokedynamic #2,0 // InvokeDynamic #0:run:()Ljava/lang/Runnable; 5: astore_1 6: aload_1 7: invokeinterface #3, 1 // InterfaceMethod java/lang/Runnable.run:()V 12: return

8 Java Bytecode Decompiler
Launching Procyon: $ java –jar procyon.jar HelloJavaOneWithLamdas.class Procyon output: public static void main(String[] args) { Runnable r = () -> System.out.println("Hello JavaOne 2015"); r.run(); }

9 Java Bytecode Attacks Reverse engineering Bypassing critical routines
Easy decompilation and modification

10 Popular Java Decompilers
Rating Java 8 support Anti-obfuscation techniques GUI Procyon + Luyten 8/10 Yes CFR 7/10 - JD 6/10 Fernflower 5/10 Yes (Minecraft support) Krakatau Candle 4/10

11 Java Bytecode Protection
Codeflow obfuscation Name obfuscation Call hiding

12 Obfuscator/Decompiler Demo
TECHNIQUES SHOWN HERE ARE FOR EDUCATIONAL PURPOSES ONLY. WE DO NOT ASSUME ANY RESPONSIBILITY FOR ANY UNLAWFUL ACTIONS AND/OR DAMAGES RESULTING FROM THE USE OF THESE TECHNIQUES.

13 Constant Pool & Bytecode
#1 = Methodref #6.# // java/lang/Object."<init>":()V #2 = Fieldref #16.# // java/lang/System.out:Ljava/io/PrintStream; #3 = String # // Hello JavaOne 2015 #4 = Methodref #19.# // java/io/PrintStream.println:(Ljava/lang/String;)V public static void main(java.lang.String[]); Code: 0: getstatic # // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc # // String Hello JavaOne 2015 5: invokevirtual # // Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: return

14 Bytecode Execution stack java/lang/System.out 1 Current instruction:
java/lang/System.out 1 Current instruction: 0: getstatic #2 Console: opcode operands constant pool values getstatic Field#2 java/lang/System.out:Ljava/io/PrintStream; 3 ldc String#3 Hello JavaOne 2015 5 invokevirtual Method#4 java/io/PrintStream.println:(Ljava/lang/String;)V 8 return

15 Bytecode Execution stack “Hello JavaOne 2015” 1 java/lang/System.out
“Hello JavaOne 2015” 1 java/lang/System.out Current instruction: 3: ldc #3 Console: opcode operands constant pool values getstatic Field#2 java/lang/System.out:Ljava/io/PrintStream; 3 ldc String#3 Hello JavaOne 2015 5 invokevirtual Method#4 java/io/PrintStream.println:(Ljava/lang/String;)V 8 return

16 Bytecode Execution stack “Hello JavaOne 2015” 1 java/lang/System.out
“Hello JavaOne 2015” 1 java/lang/System.out Current instruction: 5: invokevirtual #4 Console: Hello JavaOne 2015 opcode operands constant pool values getstatic Field#2 java/lang/System.out:Ljava/io/PrintStream; 3 ldc String#3 Hello JavaOne 2015 5 invokevirtual Method#4 java/io/PrintStream.println:(Ljava/lang/String;)V 8 return

17 Notes #1 Constant pool contains all the symbolic information
invoke* instruction is used to call a method JVM requires the stack to be consistent before method execution

18 Call Hiding via Reflection
// Hide Fieldref #2 Object out = Class.forName("java.lang.System").getField("out").get(null); // Hide Methodref #4 Class.forName("java.io.PrintStream"). getMethod("println",new Class[]{String.class}). invoke(System.out, new Object[]{"Hello JavaOne 2015"})

19 Call Hiding via Reflection
$ javac HelloJavaOneWithReflection.java $ javap -c -v HelloJavaOne.class | grep 'Methodref\|Fieldref’ | grep ’System.out\|println’ >#2 = Fieldref #16.#17 // java/lang/System.out:Ljava/io/PrintStream; #4 = Methodref #19.#20 // java/io/PrintStream.println:(Ljava/lang/String;)V $ javap -c –v HelloJavaOneWithReflection.class | grep 'Methodref\|Fieldref’ | grep ’System.out\|println’ >

20 Call Hiding via Reflection
Constant pool: #1 = Methodref #6.# // java/lang/Object."<init>":()V #2 = Fieldref #16.# // java/lang/System.out:Ljava/io/PrintStream; #3 = String # // Hello JavaOne 2015 #4 = Methodref #19.# // java/io/PrintStream.println:(Ljava/lang/String;)V

21 Call Hiding via Reflection
Pros MethodRef and FieldRef are removed from ConstantPool Cons Performance Bytecode size overhead The need for boxing/unboxing args and return value Call super.superMethod(…) is not possible Security breach when calling/accessing private methods/fields

22 Classic invoke* Instructions
Math.random(); // Call static method No dispatch invokestatic java/lang/Math.random:()D System.out.println("Hello JavaOne 2015"); // Call virtual method Single dispatch via table invokevirtual java/io/PrintStream.println:(Ljava/lang/String;)V it.hasNext(); // Call interface method Single dispatch via search invokeinterface java/util/Iterator.hasNext:()Z new StringBuilder(); // Call special method No dispatch invokespecial java/lang/StringBuilder."<init>":()V

23 InvokeDynamic (JSR-292) Features of dynamic languages in Java Platform
Shipped in Java 7 The basic building block for a lot of new Java features, such as Lambdas Invokedynamic: Deep Dive. Vladimir Ivanov Hot Spot JVM Compiler, Oracle

24 bytecode + bootsrap method method handles invoke dynamic

25 InvokeDynamic Execution
Bytecode ConstantPool ….. 2 invokedynamic #0:#22 18 BoostrapSection 19 CallSite LambdaMetafactory.metafactory(..) 20 1 MethodHandle 21 MethodType 1.Resolving the bootstrap method 0: invokedynamic #2,0 3.Linking 2.Executing Bootstrap method with arguments CallSite

26 bootstrap method CallSite CallSite1 MutableCallSite ConstantCallSite
MethodHandles.Lookup String callerName CallSite1 MethodType callerType bootstrap method arg4 MutableCallSite arg255 ConstantCallSite MutableCallSite1

27 Call Hiding via InvokeDynamic
Plan Generate bootstrap method Replace invokevirtual/invokeinterface/invokestatic instructions with invokedynamic

28 Bootstrap Method - Signature
private static Object bootstrap$0( MethodHandles.Lookup lookup, String callerName, MethodType callerType, int originalOpcode, String originalClassName, String originalMethodName, String originalMethodSignature) User-defined params

29 Bootstrap Method - Structure
MethodHandle mh = null; try { // variables initialization Class clazz = Class.forName(originalClassName); ClassLoader currentClassLoader = BootstrapMethodTemplate.class.getClassLoader(); MethodType originalMethodType = MethodType.fromMethodDescriptorString(originalMethodSignature, currentClassLoader); // lookup method handle …… mh = mh.asType(callerType); } catch (Exception ex) { throw new BootstrapMethodError(); } return new ConstantCallSite(mh);

30 Lookup MethodHandle switch (originalOpcode) {
case 0xB8: // invokestatic opcode mh = lookup.findStatic(clazz, originalMethodName, originalMethodType); break; case 0xB6: // invokevirtual opcode case 0xB9: // invokeinterface opcode mh = lookup.findVirtual(clazz, originalMethodName, originalMethodType); default: throw new BootstrapMethodError(); }

31 org.objectweb.asm Library for low-level bytecode manipulation
Visitor API (same as SAX) Tree API (same as DOM)

32 Visitor API ClassVisitor MethodVisitor FieldVisitor visitMethod
visitField MethodVisitor FieldVisitor visitAnnotation visitEnd visitCode visit*Insn visitEnd visitAttribute

33 HelloWorld in ASM mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null); mv.visitCode(); mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); mv.visitLdcInsn("Hello JavaOne 2015"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V"); mv.visitInsn(RETURN); mv.visitMaxs(2, 1); mv.visitEnd();

34 ASMifier in Action Source code: Bytecode: javac
public class Test { public static void main(String[] args) { System.out.println("Hello JavaOne 2015"); } 0: getstatic #2 3: ldc #3 5: invokevirtual #4 8: return javac org.objectweb.asm.util.ASMifier compile & run ASMifier output: mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null); mv.visitCode(); mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); mv.visitLdcInsn("Hello JavaOne 2015"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V"); mv.visitInsn(RETURN); mv.visitMaxs(2, 1); mv.visitEnd();

35 BootstrapMethodGenerator.java String bootstrapMethodName = "bootstrap$0"; String bootstrapMethodSignature = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;"; MethodVisitor mv = cv.visitMethod(ACC_PRIVATE + ACC_STATIC, bootstrapMethodName, bootstrapSignature, null, null, true, true); mv.visitCode(); Label l0 = new Label(); Label l1 = new Label(); mv.visitTryCatchBlock(l0, l1, l0, "java/lang/Exception"); mv.visitInsn(ICONST_0); mv.visitVarInsn(ISTORE, 13); mv.visitInsn(ACONST_NULL); …..

36 Call Hiding via InvokeDynamic
Plan ✔ Generate bootstrap method Replace invokevirtual/invokeinterface/invokestatic instructions with invokedynamic

37 MethodVisitor class MethodIndyProtector extends MethodVisitor implements Opcodes { Handle bootsrapMethodHandle = null; public MethodIndyProtector(MethodVisitor mv, String className) { super(ASM4, mv); bootsrapMethodHandle = new Handle(Opcodes.H_INVOKESTATIC, className, bootstrapMethodName, bootstrapMethodSignature); } @Override public void visitMethodInsn(int opcode, String owner, String name, String desc) { // replace invokestatice/invokevirtual, invokeinterface instructions

38 Replace invoke* Instructions
@Override public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf ) { // generate a newName and a generic newSig (String.class->Object.class, ..) // … switch(opcode){ case INVOKESTATIC: case INVOKEVIRTUAL: case INVOKESINTERFACE: mv.visitInvokeDynamicInsn(newName, newSig, bootsrapMethodHandle, opcode, owner, name, desc); default: mv.visitMethodInsn(opcode, owner, name, desc, itf); }

39 Result – Call Hiding via InvokeDynamic
JD-GUI:

40 Result – Call Hiding via InvokeDynamic
$ java -jar procyon.jar indyp/HelloJavaOne.class public static void main(final String[] array) { } // invokedynamic( :(Ljava/lang/Object;Ljava/lang/Object;)V, System.out, "Hello JavaOne 2015")

41 Result – Call Hiding via InvokeDynamic
$ java -jar cfr.jar indyp/HelloJavaOne.class public static void main(String[] arrstring) { LHelloWorld;.bootstrap$0(182, "java.io.PrintStream", "println", "(Ljava/lang/String;)V", System.out, "Hello JavaOne 2015"); }

42 Result – Call Hiding via InvokeDynamic
Procyon output after Stringer Java Obfuscator: public static void main(final String[] array) { } // invokedynamic(qBtSrvLX:(Ljava/lang/Object;Ljava/lang/Object;)V, o, HelloJavaOne$1.F("\u21cc\u2058\u1a61\u351e\uff1d\u30d4\u34c0\u3539\ua8c3\uaf0d\ub61a\ua5f7\uecc2\ub638\ue7fb\uf02c\u56df\u5333"))

43 Conclusion Protection for all classic invoke* instructions
No performance impact (excellent JVM optimization for InvokeDynamic) Battle tested in our products

44 Our Products Stringer Java Obfuscator (java bytecode)
Used for large scale Java EE production systems financial institutions, payment systems End user thin Java clients - 3M+ users JavaFX support DexProtector (dalvik bytecode) Several Thousand licenses sold Thousands of protected applications Millions of end users using DexProtected apps

45 Contact Demo project: Licel Corporation Web:


Download ppt "Ivan Kinash, Mikhail Dudarev Licel Corporation JavaOne 2015"

Similar presentations


Ads by Google