前言 Java是一种语言,JDK是Java这门语言的开发工具包,JDK= JRE + java  需要注意的是,Java 的版本号命名规则在 JDK 9 之后发生了变化。在 JDK 9 之前,版本号采用 “1.x.x” 的格式(如 1.8.0),而从 JDK 9 开始,版本号不再带有前缀的 “1”,而是直接使用主版本号作为前缀(如 9.0.4)。  
jar包操作 1 2 jar -xf 你的jar包名称  jar cf  D:\jar包\temp\temp.jar .  
 
Java本地命令执行 Runtime对象可以调用exec()方法执行命令,同时他也是java命令执行编写最简单的方法,属于最外层
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import  java.io.BufferedReader;import  java.io.InputStreamReader;public  class  JavaVersionExample   {    public  static  void  main (String[] args)   {         try  {                          String[] command = { "net" , "user"  };                          Process process = Runtime.getRuntime().exec(command);                          BufferedReader reader = new  BufferedReader(new  InputStreamReader(process.getInputStream()));             String line;             while  ((line = reader.readLine()) != null ) {                 System.out.println(line);             }                          process.waitFor();         } catch  (Exception e) {             e.printStackTrace();         }     } } 
 
底层分析 Runtime 1 2 3 4 5 6 7 8 9 10 11    public  Process exec (String cmdarray[])  throws  IOException  {         return  exec(cmdarray, null , null );     } ......  public  Process exec (String[] cmdarray, String[] envp, File dir)          throws  IOException  {        return  new  ProcessBuilder(cmdarray)              .environment(envp)             .directory(dir)              .start();     } 
 
ProcessBuilder 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public  Process start ()  throws  IOException  {        String[] cmdarray = command.toArray(new  String[command.size()]);          cmdarray = cmdarray.clone();         for  (String arg : cmdarray)             if  (arg == null )                 throw  new  NullPointerException();         String prog = cmdarray[0 ];         SecurityManager security = System.getSecurityManager();         if  (security != null )             security.checkExec(prog);         String dir = directory == null  ? null  : directory.toString();         for  (int  i = 1 ; i < cmdarray.length; i++) {             if  (cmdarray[i].indexOf('\u0000' ) >= 0 ) {                 throw  new  IOException("invalid null character in command" );             }         }          try  {             return  ProcessImpl.start(cmdarray,                                      environment,                                      dir,                                      redirects,                                      redirectErrorStream);         } 
 
ProcessImpl 1 2 3 4 5 6 7 8 9 10 11 12 13 final  class  ProcessImpl  extends  Process   {    static  Process start (String cmdarray[],                           java.util.Map<String,String> environment,                          String dir,                          ProcessBuilder.Redirect[] redirects,                          boolean  redirectErrorStream)         throws  IOException      {.................             return  new  ProcessImpl(cmdarray, envblock, dir,                                    stdHandles, redirectErrorStream); 
 
java 反射 Java反射操作的是java.lang.Class对象,在java反序列化中常用反射 反射Runtime执行本地命令代码片段:System.out.println(org.apache.commons.io.IOUtils.toString(Runtime.getRuntime().exec("whoami").getInputStream(), "UTF-8"));
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 Class runtimeClass1 = Class.forName("java.lang.Runtime" ); Constructor constructor = runtimeClass1.getDeclaredConstructor(); constructor.setAccessible(true ); Object runtimeInstance = constructor.newInstance(); Method runtimeMethod = runtimeClass1.getMethod("exec" , String.class); Process process = (Process) runtimeMethod.invoke(runtimeInstance, cmd); InputStream in = process.getInputStream(); System.out.println(org.apache.commons.io.IOUtils.toString(in, "UTF-8" )); public  class  test   {    public  static  void  main (String[] args)  throws  Exception {         Class<?> stu = Class.forName("com.testforclass.Student" );         Constructor<?> con2 = stu.getConstructor(String.class,int .class,String.class);         Object obj = con2.newInstance("aaa" ,18 ,"中国" );         System.out.println(obj);         Field field = stu.getDeclaredField("name" );         field.setAccessible(true );         String value = field.get(obj);         field.set(obj,"Arsene.Tang" );              } } Field modifiers = field.getClass().getDeclaredField("modifiers" ); modifiers.setAccessible(true ); modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL); field.set(类实例对象, 修改后的值); 
 
Java内省机制 内省(Introspection) 通常是指使用反射机制 来检测一个对象的属性和方法。内省主要用于JavaBeans ,它允许开发者在运行时检查一个JavaBean的属性和方法。在Java中,内省机制通常与设计模式,如MVC,结合使用,以便动态获取对象信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import  java.beans.Introspector;import  java.beans.PropertyDescriptor;public  class  User   {    private  String name;     public  String getName ()   {         return  name;     }     public  void  setName (String name)   {         this .name = name;     } } 
 
内省提供了操作 JavaBean 的 API。 Introspector 类:这是Java内省机制的核心类,提供了获取BeanInfo的静态方法。 BeanInfo 类:该类包含了关于Java Bean的元数据信息,如属性、事件和方法等。 PropertyDescriptor 类:该类描述了Java Bean的一个属性,包括其getter和setter方法。
1 2 3 4 5 6 7 BeanInfo info= Introspector.getBeanInfo(User.class); BeanDescriptor beanDescriptor = beanInfo.getBeanDescriptor(); PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); MethodDescriptor[] methodDescriptors = beanInfo.getMethodDescriptors(); 
 
Java 动态代理 Java 动态代理是一种在运行时动态生成代理对象的机制。通过使用 Java 提供的相关 API,可以在不修改原始类的情况下 创建一个代理类,该代理类可以拦截原始类的方法调用 ,并在方法执行前后插入额外的逻辑 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 import  java.lang.reflect.InvocationHandler;import  java.lang.reflect.Method;public  interface  flag   {    void  getflag (String flag)  ; } public  interface  flag1   {    void  getflag1 ()  ; } public  class  realproxy  implements  InvocationHandler   {    @Override      public  Object invoke (Object proxy, Method method, Object[] args)  throws  Throwable  {         if (method.toString().contains("java.lang.String" )){             System.out.println("方法名为: " +method);             System.out.println("参数为: " +args[0 ]);             Object result = method.invoke(proxy, args);             System.out.println("函数调用后" );         }         else {             System.out.println("方法名为: " +method);             System.out.println("没有传入参数" );         }         return  null ;     } } public  class  test   {    public  static  void  main (String[] args)   {         InvocationHandler handler = new  realproxy();         flag flag = (flag) Proxy.newProxyInstance(test.class.getClassLoader(),         new  Class[]{flag.class},         handler);         flag1 flag1 = (flag1) Proxy.newProxyInstance(test.class.getClassLoader(),new  Class[]{flag1.class},handler);         flag.getflag("flag" );         flag1.getflag1();     } } 
 
设计模式 因为java是大二的时候学的,所以在写这篇博客时没有关注太基础的内容,由于后面代码审计过程经常遇到了这种设计思路,就详细写写
java 工厂类与实例 使用工厂类(Factory Class)相比传统的直接实例化(直接使用 new 关键字),就是将创建对象时需要初始化数据、调用其他服务的方法封装在一个类中,便于 集中管理和代码修改,实例就是工程类创造的对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 interface  Animal   {    void  makeSound ()  ; } class  Dog  implements  Animal   {    @Override      public  void  makeSound ()   {         System.out.println("Woof! Woof!" );     } } class  Cat  implements  Animal   {    @Override      public  void  makeSound ()   {         System.out.println("Meow! Meow!" );     } } class  AnimalFactory   {    public  static  Animal createAnimal (String type)   {         if  ("dog" .equalsIgnoreCase(type)) {             return  new  Dog();           } else  if  ("cat" .equalsIgnoreCase(type)) {             return  new  Cat();           } else  {             return  null ;           }     } } public  class  Main   {    public  static  void  main (String[] args)   {                  Animal dog = AnimalFactory.createAnimal("dog" );         dog.makeSound();                    Animal cat = AnimalFactory.createAnimal("cat" );         cat.makeSound();       } } 
 
当然也可以将工厂抽象成两层,AbsFactory(抽象工厂)和具体实现的工厂子类dogFactory和catFactory,这种模式叫做抽象工厂模式 
Java Agent机制 在 jdk 1.5 之后引入了 java.lang.instrument 包,允许JVM在加载某个class文件之前对其字节码进行修改,同时也支持对已加载的class(类字节码)进行重新加载(Retransform),通过 java.lang.instrument 实现的工具我们称之为 Java Agent  ,Java Agent 能够在不影响正常编译的情况下来修改字节码,即动态修改已加载或者未加载的类,包括类的属性、方法
两种加载方式 1 2 3 4 5 6 7 public  static  void  premain (String args, Instrumentation inst)   {}public  static  void  agentmain (String args, Instrumentation inst)   {}
 
使用jar命令打包应用程序 Java Agent限制了我们必须以jar包的形式运行或加载
1 2 3 4 5 6 7 8 9 10 11 Manifest-Version:  1.0 Main-Class:  Hello Premain-Class:  com.anbai.sec.agent.CrackLicenseAgent Agent-Class:  com.anbai.sec.agent.CrackLicenseAgent Can-Retransform-Classes:  true 
 
然后就可以利用 编写的mf文件 编译jar包了
jar cvfm hello.jar hello.mf Hello.class
动态修改字节码 Instrumentation 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public  interface  Instrumentation   {                   void  addTransformer (ClassFileTransformer transformer)  ;          boolean  removeTransformer (ClassFileTransformer transformer)  ;          void  retransformClasses (Class<?>... classes)  throws  UnmodifiableClassException ;          boolean  isModifiableClass (Class<?> theClass)  ;          @SuppressWarnings("rawtypes")      Class[] getAllLoadedClasses();          boolean  isRetransformClassesSupported ()   ; } 
 
InstrumentationImpl 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 private  final  TransformerManager mTransformerManager = new  TransformerManager(false );..... public  void  addTransformer (ClassFileTransformer var1)   {        this .addTransformer(var1, false );     }     public  synchronized  void  addTransformer (ClassFileTransformer var1, boolean  var2)   {         if  (var1 == null ) {             throw  new  NullPointerException("null passed as 'transformer' in addTransformer" );         } else  {             if  (var2) {                 if  (!this .isRetransformClassesSupported()) {                     throw  new  UnsupportedOperationException("adding retransformable transformers is not supported in this environment" );                 }                 if  (this .mRetransfomableTransformerManager == null ) {                     this .mRetransfomableTransformerManager = new  TransformerManager(true );                 }                 this .mRetransfomableTransformerManager.addTransformer(var1);                 if  (this .mRetransfomableTransformerManager.getTransformerCount() == 1 ) {                     this .setHasRetransformableTransformers(this .mNativeAgent, true );                 }             } else  {                 this .mTransformerManager.addTransformer(var1);             }         }     } 
 
当有新的类被JVM加载时JVM会自动回调用我们自定义的Transformer类的transform方法 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public  interface  ClassFileTransformer   {       byte [] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,                             ProtectionDomain protectionDomain, byte [] classfileBuffer); } 
 
启动后加载 agent 要上传的jar包内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import  java.lang.instrument.Instrumentation;public  class  AgentMain   {    public  static  final  String ClassName = "org.apache.catalina.core.ApplicationFilterChain" ;      public  static  void  agentmain (String agentArgs, Instrumentation ins)   {         ins.addTransformer(new  DefineTransformer(),true );                  Class[] classes = ins.getAllLoadedClasses();         for  (Class clas:classes){             if  (clas.getName().equals(ClassName)){                 try {                                          ins.retransformClasses(new  Class[]{clas});                 } catch  (Exception e){                     e.printStackTrace();                 }             }         }     } } public  class  DefineTransformer  implements  ClassFileTransformer   { }
 
命令执行内容
1 2 3 4 5 6 7 8 9 10 11 String path = "AgentMain.jar的路径" ;         List<VirtualMachineDescriptor> list = VirtualMachine.list();         for  (VirtualMachineDescriptor v:list){             System.out.println(v.displayName());             if  (v.displayName().contains("AgentMainDemo" )){                                  VirtualMachine vm = VirtualMachine.attach(v.id());                                  vm.loadAgent(path);                 vm.detach();             }