Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Binary patching for fun and profit

Binary patching for fun and profit

Anton Arhipov

February 26, 2012
Tweet

More Decks by Anton Arhipov

Other Decks in Technology

Transcript

  1. Binary  Patching   10101010101 11000101010 10101010001 00010001110 11011101011 10101010101 11100001010

    10101010001 00010001110 11011101110 Ninja.class   Ninja.class’   a.k.a  instrumenta9on  
  2. Why?   •  Programming  model  (AOP,  ORM)   •  Tooling

     (profilers,  coverage)   •  Legacy  integraFon   … or maybe you’re just bored? J
  3. How?   •  Add  –javaagent  to  hook  into  class  loading

      process   •  Implement  ClassFileTransformer   •  Use  bytecode  manipulaFon  libraries  (Javassist,   cglib,  asm)  to  add  any  custom  logic   java.lang.instrument  
  4. java.lang.instrument   import  java.lang.instrument.ClassFileTransformer;   import  java.lang.instrument.Instrumenta9on;     public

     class  Agent  {      public  sta9c  void  premain(String  args,  Instrumenta9on  inst)                    throws  Excep9on  {                inst.addTransformer(new  ClassFileTransformer  {  …  });        }   }  
  5. java.lang.instrument   import  java.lang.instrument.ClassFileTransformer;   import  java.lang.instrument.Instrumenta9on;     public

     class  Agent  {      public  sta9c  void  premain(String  args,  Instrumenta9on  inst)                    throws  Excep9on  {                inst.addTransformer(new  ClassFileTransformer  {  …  });        }   }  
  6. java.lang.instrument   import  java.lang.instrument.ClassFileTransformer;   import  java.lang.instrument.Instrumenta9on;     public

     class  Agent  {      public  sta9c  void  premain(String  args,  Instrumenta9on  inst)                    throws  Excep9on  {                inst.addTransformer(new  ClassFileTransformer  {  …  });        }   }   META-INF/MANIFEST.MF Premain-Class: Agent java  –javaagent:agent.jar  …  
  7. j.l.instrument.ClassFileTransformer   new ClassFileTransformer() { public byte[] transform(ClassLoader loader, String

    className, Class<?>classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer){ ClassPool cp = ClassPool.getDefault(); CtClass ct = cp.makeClass(new ByteArrayInputStream(classfileBuffer)); transformClass(ct, cp); return ct.toBytecode(); } }
  8. j.l.instrument.ClassFileTransformer   new ClassFileTransformer() { public byte[] transform(ClassLoader loader, String

    className, Class<?>classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer){ ClassPool cp = ClassPool.getDefault(); CtClass ct = cp.makeClass(new ByteArrayInputStream(classfileBuffer)); transformClass(ct, cp); return ct.toBytecode(); } }
  9. j.l.instrument.ClassFileTransformer   new ClassFileTransformer() { public byte[] transform(ClassLoader loader, String

    className, Class<?>classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer){ ClassPool cp = ClassPool.getDefault(); CtClass ct = cp.makeClass(new ByteArrayInputStream(classfileBuffer)); transformClass(ct, cp); return ct.toBytecode(); } }
  10. j.l.instrument.ClassFileTransformer   new ClassFileTransformer() { public byte[] transform(ClassLoader loader, String

    className, Class<?>classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer){ ClassPool cp = ClassPool.getDefault(); CtClass ct = cp.makeClass(new ByteArrayInputStream(classfileBuffer)); transformClass(ct, cp); return ct.toBytecode(); } }
  11. Javassist   •  Bytecode  manipulaFon  made  easy   •  Source-­‐level

     and  bytecode-­‐level  API   •  Uses  the  vocabulary  of  Java  language   •  On-­‐the-­‐fly  compilaFon  of  the  injected  code   •  hVp://www.jboss.org/javassist  
  12. Adding  Interfaces   ClassPool  cp  =  ClassPool.getDefault();     CtClass

     ct  =  cp.get("org.geecon.Alarm");     ct.addInterface(cp.get(Listener.class.getName()));     ct.addMethod(CtNewMethod.make("public  void  fire(){  alert();  }",  ct));   public  interface  Listener  {        void  fire();     }   public  class  Alarm  {        void  alert()  {}     }  
  13. Adding  Interfaces   ClassPool  cp  =  ClassPool.getDefault();     CtClass

     ct  =  cp.get("org.geecon.Alarm");     ct.addInterface(cp.get(Listener.class.getName()));     ct.addMethod(CtNewMethod.make("public  void  fire(){  alert();  }",  ct));   public  interface  Listener  {        void  fire();     }   public  class  Alarm  {        void  alert()  {}     }  
  14. Adding  Interfaces   ClassPool  cp  =  ClassPool.getDefault();     CtClass

     ct  =  cp.get("org.geecon.Alarm");     ct.addInterface(cp.get(Listener.class.getName()));     ct.addMethod(CtNewMethod.make("public  void  fire(){  alert();  }",  ct));   public  interface  Listener  {        void  fire();     }   public  class  Alarm  {        void  alert()  {}     }  
  15. Adding  Interfaces   ClassPool  cp  =  ClassPool.getDefault();     CtClass

     ct  =  cp.get("org.geecon.Alarm");     ct.addInterface(cp.get(Listener.class.getName()));     ct.addMethod(CtNewMethod.make("public  void  fire(){  alert();  }",  ct));   public  interface  Listener  {        void  fire();     }   public  class  Alarm  {        void  alert()  {}     }  
  16. Simple  AOP   ProxyFactory  pf  =  new  ProxyFactory();    

    pf.setSuperclass(No9fier.class);     pf.setFilter(new  MethodFilter()  {  …  });   No9fier  no9fier  =  (No9fier)  pf.createClass().newInstance();     ((ProxyObject)  no9fier).setHandler(new  MethodHandler()  {  …  });     System.out.println("calling  on()");   no9fier.on();     System.out.println("calling  off()");   no9fier.off();     public  class  No9fier  {        public  void  on(){  }        @Pointcut      public  void  off(){}   }  
  17. Intercept  Statements          ClassPool  pool  =  ClassPool.getDefault();

               CtClass  ct  =  pool.get("org.geecon.PaymentMachine");            ct.getDeclaredMethod("process")                .instrument(new  ExprEditor()  {                        public  void  edit(NewExpr  e)                                    throws  CannotCompileExcep9on  {                                  e.replace("$_  =  $proceed($$);");                        }          });