利用sun.misc.Unsafe实现一次类混淆(Type Confusion)

   unsafe是jdk里面非常有意思的函数,不仅仅是名字。具体功能大家可以搜一下看看,简单来说就是,这个类提供了直接操作硬件的方法。
    我这边简单利用unsafe的putObject方法,实现一次类混淆,有点儿意思。
    代码如下:
    Dingo.java : (作用是跑一个计算器)
   
package ding.yang.controller;
 
import java.io.IOException;
import java.io.Serializable;
 
public class Dingo implements Serializable {
 
    /**
     *
     */
    private static final long serialVersionUID = 1L;
 
    public void fuck() {
        ProcessBuilder pb = new ProcessBuilder("calc");
        try {
            pb.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

     Yang.java: (作用是跑一个记事本)
    
package ding.yang.controller;
 
import java.io.IOException;
import java.io.Serializable;
 
public class Yang implements Serializable {
 
    /**
     *
     */
    private static final long serialVersionUID = 1L;
 
    public void fuck() {
        ProcessBuilder pb = new ProcessBuilder("notepad");
        try {
            pb.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
 

    Hello.java:
   
package ding.yang.controller;
 
public class Hello {
 
    public Dingo dingo;
     
    public Hello(Dingo dingo){
        this.dingo  = dingo;
    }
     
}

     接着利用putObject,将hello.java类中的dingo这个field,替换为yang.java
  
 package ding.yang.controller;
 
import java.io.IOException;
import java.lang.reflect.Field;
import java.security.AllPermission;
import java.security.ProtectionDomain;
 
import sun.misc.Unsafe;
 
public class TestUnsafe {
 
    public static void main(String[] avgs) throws NoSuchFieldException,
            SecurityException, IllegalArgumentException,
            IllegalAccessException, IOException {
 
        // 获取unsafe 的实例
        Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
        theUnsafe.setAccessible(true);
        Unsafe unsafe = (Unsafe) theUnsafe.get(null);
     
        Hello hello = new Hello(new Dingo());
        Yang yang = new Yang();
        Field f = hello.getClass().getDeclaredField("dingo");
        unsafe.putObject(hello, unsafe.objectFieldOffset(f), yang);
        hello.dingo.fuck();               // 这里是弹计算器呢还是记事本呢?
 
    }
}


    总结:
  1、上述代码最后是弹出了记事本,因为我们采用直接操作内存对象的方式,将hello类中的dingo对象,替换成了yang对象。
  2、还有一个需要注意的点是,unsafe实例并不能直接获取,因为在unsafe中,判断了当前的classloader如果不是null,也就是root的classloader,会抛出一个securityexception异常,所以我们利用反射的方式,将private置为public,然后获取
  3、上述代码当然只能在trust code环境里面运行了。

你可能感兴趣的:(java,安全,unsafe,类混淆)