站長資訊網
        最全最豐富的資訊網站

        實例詳解Java反序列化之反射機制

        本篇文章給大家帶來了關于java的相關知識,其中主要介紹了java反射機制的相關問題,動態獲取程序信息以及動態調用對象的功能稱為Java語言的反射機制,希望對大家有幫助。

        實例詳解Java反序列化之反射機制

        推薦學習:《java教程》

        每次聽到大佬在講或者看論壇等一些方式學java反序列化漏洞時,都會有一個詞叫做反射機制,大佬順勢借著這個詞,就給你造出一個payload,對于剛學java反序列化的我們,可能有點會懵圈,反正我是懵了,所以就趕緊學了一波,不然和大佬差距越來越大。所以這篇文章主要講述java反射機制

        Java反射機制

        Java的反射(reflection)機制是指在程序的運行狀態中,可以構造任意一個類的對象,可以了解任意一個對象所屬的類,可以了解任意一個類的成員變量和方法,可以調用任意一個對象的屬性和方法。這種動態獲取程序信息以及動態調用對象的功能稱為Java語言的反射機制。反射被視為動態語言的關鍵。

        我不太擅長文字表達,還是上圖操作把

        不用反射機制的例子

        //定義一個animals接口interface animals {     public abstract void print();}//定義類來實現animals接口的抽象方法class Dog implements animals {     public void print() {         System.out.println("Dog");     }}class Cat implements animals {     public void print() {         System.out.println("Cat");     }}// 構造一個zoo類// 之后如果我們在添加其他的實例的時候只需要修改zoo類class zoo {      public static animals getInstance(String animalsName) {         animals a = null;         if ("Dog".equals(animalsName)) {             a = new Dog();         }         if ("Cat".equals(animalsName)) {             a = new Cat();         }         return a;     }}public class reflection {     public static void main(String[] args) {         //借助zoo類尋找對應的類來實現接口         animals a=zoo.getInstance("Cat");         if(a!=null)             a.print();     }}

        這時候添加動物,只需要

        • 添加類
        • 修改zoo
        • 修改main函數的動物類

        把上面修改為反射機制

        //定義一個animals接口interface animals {     public abstract void print();}//定義類來實現animals接口的抽象方法class Dog implements animals {     public void print() {         System.out.println("Dog");     }}class Cat implements animals {     public void print() {         System.out.println("Cat");     }}// 構造一個zoo類// 之后如果我們在添加其他的實例的時候只需要修改zoo類class zoo {      public static animals getInstance(String className) {         animals a = null;         try {             //借助Class.forName尋找類名,并用newInstance實例化類似于new             a = (animals) Class.forName(className).newInstance();         } catch (Exception e) {             e.printStackTrace();         }         return a;     }}public class reflection {     public static void main(String[] args) {         //借助zoo類尋找對應的類來實現接口(classname為當前包名加類名)         animals a = zoo.getInstance("com.cc1.Dog");         if (a != null)             a.print();     }}

        這時候添加動物只需要

        • 添加類
        • 修改main函數的動物類

        省了一步,傳入類名可控,發現好像是存在的類都可以調

        反射機制方法

        我們用的最多的可能是

        • forName(調用類)
        • getMethod(調用類下方法)
        • invoke(執行)
        • newInstance(實例化對象)
        Class.forName(className).getMethod(methodName).invoke(Class.forName(className).newInstance());

        下面我們用反射機制來彈出計算機(calc)或者記事本(notepad)

        由于彈出計算機有點多這次我就彈記事本把,總而言之,能彈出來就很美妙

        Runtime.getRuntime().exec("notepad");

        實例詳解Java反序列化之反射機制
        我們看下getRuntime函數
        實例詳解Java反序列化之反射機制
        得知,該函數是Runtime類獲取對象的方式,個人感覺是每用一次就調一次比較麻煩,為了不調用一次建立一個對象所以封裝成了函數

        類對象獲取方式

        • Class.forName(類名獲取)
        • zoo.class(已經加載過的類)
        • obj.class(實例)
          實例詳解Java反序列化之反射機制

        類初始化

        修改zoo類,增加初始塊、靜態初始塊、和構造函數

        class zoo {     //初始塊     {         System.out.println("1  " + this.getClass());     }      //靜態初始塊     static {         System.out.println("2  " + zoo.class);     }      public zoo() {         System.out.println("3  " + this.getClass());     }      public static animals getInstance(String className) {         animals a = null;         try {             //借助Class.forName尋找類名,并用newInstance實例化類似于new             a = (animals) Class.forName(className).newInstance();         } catch (Exception e) {             e.printStackTrace();         }         return a;     }}

        類初始化執行順序:靜態初始塊
        實例詳解Java反序列化之反射機制
        類實例化執行順序:靜態初始塊 – > 初始塊 – > 構造函數
        實例詳解Java反序列化之反射機制
        由此得知,類初始化和類實例化不一樣

        接下來增加zoo1類繼承zoo類

        class zoo1 extends zoo{     //初始塊     {         System.out.println("11  " + this.getClass());     }      //靜態初始塊     static {         System.out.println("12  " + zoo.class);     }      public zoo1() {         System.out.println("13  " + this.getClass());     }}

        子類初始化順序:父類靜態初始化塊 – > 子類靜態初始化塊
        實例詳解Java反序列化之反射機制
        子類實例化順序:父類靜態初始化塊 – > 子類靜態初始化塊 – > 父類初始化塊 – > 父類構造函數 – > 子類初始化塊 – >子類構造函數
        實例詳解Java反序列化之反射機制
        以上可以得知,當使用Class.forName時,且類靜態初始化塊可控,可以執行任意代碼

        調用內部類

        Class.forName(“java.lang.Runtime”)來獲取類(java.lang.Runtime是Runtime類的完整路徑)

        getMethod

        getMethod 的作用是通過反射獲取類的某個特定的公有方法。
        java支持類重載,但不能僅通過一個函數名確定一個函數,所以在調用getMethod時,需要傳給它方法的參數類型列表
        Class.forName(“java.lang.Runtime”).getMethod(“exec”, String.class)

        invoke

        靜態和動態方法的區別
        實例詳解Java反序列化之反射機制

        invoke方法在getMethod類下,作用時傳遞參數,執行方法
        public Object invoke(Object obj, Object… args)
        第一個參數是getMethod獲取的方法的類對象(如果方法是靜態方法則傳類)
        獲取exec函數的類對象
        Class.forName(“java.lang.Runtime”).getMethod(“getRuntime”).invoke(Class.forName(“java.lang.Runtime”))
        由于getRuntime是靜態方法,所以傳類
        invoke(Class.forName(“java.lang.Runtime”).getMethod(“getRuntime”).invoke(Class.forName(“java.lang.Runtime”)),“calc.exe”)

        最后我們合并一下

        Class.forName("java.lang.Runtime").                 getMethod("exec", String.class).                 invoke(Class.forName("java.lang.Runtime").getMethod("getRuntime").invoke(Class.forName("java.lang.Runtime")), "notepad");

        實例詳解Java反序列化之反射機制

        指定構造方法生成實例

        String str="notepad";ProcessBuilder pb = new ProcessBuilder(str);pb.start();

        getConsturctor(函數可以選定指定接口格式的構造函數(由于構造函數也可以根據參數來進行重載)
        選定后我們可以通過newInstance(),并傳入構造函數的參數執行構造函數

        ProcessBuilder類有兩個構造函數

        • public ProcessBuilder(String… command)(String…變長的字符串數組String[].class)
        • public ProcessBuilder(List command)

        分別使用構造方法

        • Class.forName(“java.lang.ProcessBuilder”).getConstructor(String[].class).newInstance(new String[][]{{“notepad”}})
        • Class.forName(“java.lang.ProcessBuilder”).getConstructor(List.class).newInstance(Arrays.asList(“notepad”))

        執行完構造方法實例后,在進行強制轉化使用start函數即可

        ( (ProcessBuilder) Class.forName(“java.lang.ProcessBuilder”).getConstructor(List.class).newInstance(Arrays.asList(“notepad”))).start();

        實際中,肯定用不了,哪有這么好的事,還是接著反射把

        Class.forName(“java.lang.ProcessBuilder”).getMethod(“start”).invoke(clazz.getConstructor(List.class).newInstance(Arrays.asList(“notepad”)));
        實例詳解Java反序列化之反射機制
        這里可能有人會好奇我寫的里那的另一個構造函數,String…command這個傳參為什么用new String[][]{{“notepad”}},不應該是new String[]{“notepad”},現在用應該的

        ((ProcessBuilder) Class.forName(“java.lang.ProcessBuilder”).getConstructor(String[].class).newInstance(new String[]{“notepad”})).start();

        在這行打斷點調試
        實例詳解Java反序列化之反射機制
        我們傳的是一個字符串數組到了實例化的時候變成了一個字符串,再看看另一個構造函數(List)

        ( (ProcessBuilder) Class.forName(“java.lang.ProcessBuilder”).getConstructor(List.class).newInstance(Arrays.asList(“notepad”))).start();

        依舊還是這行打斷點

        實例詳解Java反序列化之反射機制
        由此可知,List傳入時會被當作Object的第一項,而String[]會被當做Object,所以多加一層[]{}

        執行私有方法

        通過函數getDeclaredConstructor獲取私有方法,再利用setAccessible(true)打破私有方法限制

        Class cls = Class.forName("java.lang.Runtime");  Constructor m = cls.getDeclaredConstructor();  m.setAccessible(true);   cls.getMethod("exec", String.class).invoke(m.newInstance(), "notepad");

        推薦學習:《java視頻教程》

        贊(0)
        分享到: 更多 (0)
        網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
        主站蜘蛛池模板: 无码人妻精品一区二区三区东京热 | 国产精品极品| 无码国内精品人妻少妇蜜桃视频| 久久久久99精品成人片| 国内精品久久久久久久coent| 国产精品久久久久jk制服| 2020国产精品| 91精品国产91久久久久久青草| 国产精品毛片一区二区| 国产精品夜色视频一级区| 老司机精品影院91| 精品无码一区二区三区爱欲| 91精品在线看| 亚洲欧洲国产精品你懂的| 久久人搡人人玩人妻精品首页| 久久亚洲国产精品123区| 精品国产VA久久久久久久冰| 91精品国产91久久久久久蜜臀| 亚洲av午夜精品一区二区三区| 久久精品国产久精国产思思| 精品亚洲一区二区| 合区精品久久久中文字幕一区| 一本色道久久88—综合亚洲精品| 丰满人妻熟妇乱又仑精品| 久久久91人妻无码精品蜜桃HD| 久久亚洲精品中文字幕| 国产亚洲福利精品一区| 精品国产不卡一区二区三区| 2020国产精品永久在线| 一本色道久久88综合日韩精品| 91精品国产色综合久久| 久久99热这里只有精品国产| 国产亚洲精品va在线| 欧产日产国产精品精品| 日韩欧美亚洲国产精品字幕久久久 | 精品免费久久久久久久| 国产区精品高清在线观看| 97久久久久人妻精品专区| 亚洲中文字幕无码久久精品1 | 国产精品99久久不卡| 国产99视频精品免视看7|