內存對象搜索原理剖析

聲明

出品|先知社區(ID:LeeH)

以下內容,來自先知社區的LeeH作者原創,由于傳播,利用此文所提供的信息而造成的任何直接或間接的后果和損失,均由使用者本人負責,長白山攻防實驗室以及文章作者不承擔任何責任。

前言

java-object-searcher作為一款java內存對象搜索工具,能夠快速定位在內存中關鍵變量在內存中的具體位置

不僅能夠快速找到特定的中間的回顯方法,更能夠定位到我們自定義的任何關鍵詞路徑,我們這篇就詳細的看看這個工具的具體實現原理

使用方法

根據readme的描述,可以直接在github下載源碼,之后使用maven打包成jar包

可以選擇將其添加在目標項目中的classpath中

又或者是直接將該jar包添加在JDK的ext目錄下,在加載JDK包的同時加載這個jar到classpath

? ? 我們直接對readme中的案例進行調試分析

//設置搜索類型包含Request關鍵字的對象List<Keyword> keys = new ArrayList<>();keys.add(new Keyword.Builder().setField_type("Request").build());//定義黑名單List<Blacklist> blacklists = new ArrayList<>();blacklists.add(new Blacklist.Builder().setField_type("java.io.File").build());//新建一個廣度優先搜索Thread.currentThread()的搜索器SearchRequstByBFS searcher = new SearchRequstByBFS(Thread.currentThread(),keys);// 設置黑名單searcher.setBlacklists(blacklists);//打開調試模式,會生成log日志searcher.setIs_debug(true);//挖掘深度為20searcher.setMax_search_depth(20);//設置報告保存位置searcher.setReport_save_path("D:\\apache-tomcat-7.0.94\\bin");searcher.searchObject();

實現原理

首先我們看看項目結構

entity

在entity包下定義了三個類Blacklist / Keyword / NodeT

Blacklist

其中Blacklist類,顧名思義,就是一個黑名單類

我們可以注意到他的構造方法傳入的是一個內部靜態類對象

作者建立這個黑名單的目的就是減少搜索的對象數量,憑借著經驗,可以將完全不可能存在有目標對象的對象添加進入黑名單中,大大的減少對象搜索的數量,加快尋找的速度

比如

- java.lang.Byte- java.lang.Short- java.lang.Integer- java.lang.Long- java.lang.Float- java.lang.Boolean- java.lang.String- java.lang.Class- java.lang.Character- java.io.File....

這些基本的數據類型,可以果斷的添加進入黑名單加快速度

Keyword

而對于Keyword類,和Blacklist類具有類似的結構

設置該類的目的,主要是設置我們需要尋找的對象的信息,什么名稱?什么值?什么樣的類型?

NodeT

對于這個類同樣具有相同的數據結構

其中chain屬性記錄的是這個利用鏈,而field_name記錄的是當前的節點的名稱, 而field_object記錄的就是當前節點的類對象

而最重要的就是Interger類型的屬性current_dep-th,這個用來記錄當前節點相比較于入口的深度,用來和之后在搜索器中會提到的最大搜索深度進行比較

searcher

在這個包下,定義的是三個搜索器

普通的版本:JavaObjectSearcher

采用廣度優先算法進行搜索:SearchRequest-ByBFS

采用深度優先算法進行搜索:SearchRequest-ByDFS

SearchRequestByBFS

我們首先看看常用的采用廣度優先算法的搜索器,在創建一個搜索器的時候,傳入的是一個target目標對象和一個List<Keyword>列表

在進行賦值之后

設置黑名單

首先是判斷搜索深度,之后就是搜索對象是否為null,再然后就是調用CheckUtil.isSysType判斷該對象是不是系統類型

如果沒有匹配過,在將目標對象添加進入該屬性中之后調用了MatchUtil.matchObject方法進行匹配

通過獲取對應的Keyword類對象的信息,如果存在有對應的field_name / field_value / field_type描述,將會調用對應的isIn方法進行匹配

如果沒有匹配到,將會返回false

以至于在最后的while判斷語句中返回了true,繼續進行下一個Keyword對象的匹配

當然,如果這里能夠匹配成功的話,返回的是true,將會進入if語句中

而如果目標對應是一個Class類對象,且其不是Object類

如果是,將會將其深度加一,之后獲取所有的元素生成對應的NodeT對象之后添加進入q這個隊列的末尾

后面同樣也有著是否是Map對象的判斷和處理

在這樣的處理之后,就能夠將該層的所有屬性生成對應的NodeT對象放置在q這個隊列中等待進行匹配

最后進入了最外層的while死循環

他這里主要是處理匹配每次都只是取出頭部第一個來進行首先匹配來達到廣度優先算法的實現

SearchRequestByDFS

這個搜索器和上面搜索器在實現方面沒有很大的區別,主要就是算法的實現

在上個搜索器中主要是定義了一個隊列q,其中存放了一個個NodeT對象來存儲節點信息,每次在進行目標匹配的時候總是取出隊列中的首部結點,通過這樣的設計思路,達到了廣度優先算法的實現

而對于SearchRequestByDFS這種基于深度優先算法的實現,并沒有定義一個隊列來進行存儲,而是采用,即時匹配的原則進行實現

具體點來看看,主要是在searchObject方法的實現上有所不同,在這個搜索器中有兩個重載方法

主要看看有參方法的實現

直接獲取其中的所有values,依次調用searchObject方法進行匹配,這里就會一直向內嵌套,直到將一個value對象匹配到底,或者是到達最大搜索深度才會截至繼續匹配下一個value值

如果目標對象是數組對象

嘗試搜索

//設置搜索類型包含Request關鍵字的對象List<Keyword> keys = new ArrayList<>();keys.add(new Keyword.Builder().setField_type("Request").build());List<Blacklist> blacklists = new ArrayList<>();blacklists.add(new Blacklist.Builder().setField_type("java.io.File").build());SearchRequstByBFS searcher = new SearchRequstByBFS(Thread.currentThread(),keys);searcher.setBlacklists(blacklists);searcher.setIs_debug(true);searcher.setMax_search_depth(10);searcher.setReport_save_path("xx");searcher.searchObject();

我這里的環境是springboot 2.5.0的環境

在運行搜索器之后得到結果

參考

https://github.com/c0ny1/java-object-searcher

歡迎關注長白山攻防實驗室公眾號

定期更新優質文章分享

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容