【我的ASM學習進階之旅】 01開篇介紹ASM

0x00、簡介

ASM名稱不代表任何含義:它只是對C語言中__asm__關鍵字的引用,它允許使用匯編語言實現某些功能

ASM是一個通用的Java字節碼操作和分析框架。它可以直接以二進制形式用於修改現有類或動態生成類。

ASM提供了一些常見的字節碼轉換和分析算法,可以從中構建定製的複雜轉換和代碼分析工具。

ASM提供與其他Java字節碼框架類似的功能,但側重於性能。
因爲它的設計和實現是儘可能的小和儘可能快,所以它非常適合在動態系統中使用(但當然也可以以靜態方式使用,例如在編譯器中使用)。

在許多項目中都使用ASM,包括:

  • OpenJDK,用於生成lambda調用站點;在Nashorn編譯器,
  • Groovy編譯器和Kotlin編譯器,
  • Cobertura和Jacoco中,ASM還用於檢測類,以測量代碼覆蓋率
  • CGLIB,動態生成代理類(在Mockito和EasyMock等其他項目中使用的代理類)
  • Gradle,以便在運行時生成一些類。

最近的版本: 2020年9月22日:發佈ASM 9.0

0x01、動機

程序分析,程序生成和程序轉換是可以在許多情況下使用的有用技術:

  • 程序分析
    程序分析的範圍從簡單的語法分析到完整的語義分析,都可用於查找應用程序中的潛在錯誤,檢測未使用的代碼,反向工程代碼等。

  • 程序生成
    程序生成在編譯器中使用。其中包括傳統的編譯器,還包括用於分佈式編程的stub或者skeleton編譯器,即時編譯器等。

  • 程序轉換
    程序轉換可用於優化或混淆程序,將調試或性能監視代碼插入應用程序,面向切面(aspect oriented programming)的編程等。

所有上面的這些技術都可以用於任何編程語言,但這或多或少容易實現,具體取決於語言。

對於Java,它們可以在Java源代碼或已編譯的Java classes上使用。處理已編譯的classes的優點之一,很明顯就是不需要源代碼。因此,程序轉換可用於任何應用程序,包括封閉源代碼和商業應用程序。

處理已編譯代碼的另一個優點是,可以在將類加載到Java虛擬機中之前在運行時分析,生成或轉換類(可以在運行時生成和編譯源代碼,但這確實很慢,並且需要完整的Java編譯器)。優點是stub編譯器或Aspect Weaver等工具對用戶透明。

由於程序分析,生成和轉換技術的許多可能用法,因此已經爲許多語言(包括Java)實現了許多分析,生成和轉換程序的工具。

ASM是Java語言的其中一種工具,旨在用於運行時(但也可以脫機)類生成和轉換。因此,ASM庫被設計爲在編譯的Java classes上工作。
它還被設計爲儘可能快和儘可能小。

  • 爲了不減慢在運行時使用ASM的應用程序進行動態類生成或轉換的速度,儘可能快是很重要的。
  • 爲了在受內存限制的環境中使用,並避免使用ASM減小小型應用程序或庫的大小,儘可能小是很重要的。

ASM不是生成和轉換已編譯Java類的唯一工具,而是最新,最有效的工具之一。
可以從http://asm.objectweb.org下載。
其主要優點如下:

  • 它具有簡單易用,設計良好的模塊化API。
  • 有據可查,並且具有關聯的Eclipse插件。
  • 它提供對最新Java版本Java 7的支持。
  • 它體積小,速度快且功能強大。
  • 其龐大的用戶社區可以爲新用戶提供支持。
  • 其開源許可證允許您以幾乎任何所需的方式使用它。

0x02 概述

2.1 範圍

ASM庫的目標是生成,轉換和分析已編譯的Java類,它們表示爲字節數組(因爲它們存儲在磁盤上並加載在Java虛擬機中)。

爲此,ASM提供了使用比字節更高級別的概念來讀取,寫入和轉換此類字節數組的工具,例如數字常量,字符串,Java標識符,Java類型,Java類結構元素等。

請注意,ASM庫的範圍嚴格限於讀取classes,寫classes,轉換classes和分析classes。特別是,類加載過程超出了範圍。

2.2 模型

ASM庫提供了兩個用於生成和轉換已編譯類的API:

  • core API提供基於事件的classes表示,
  • tree API提供基於對象的表示。
  • 基於事件的模型
    在基於事件的模型中,一個類由一系列事件表示,每個事件代表該類的元素,例如其標題,字段,方法聲明,指令等。基於事件的API定義了一組可能的事件事件及其發生的順序,並提供了一個類解析器,該解析器爲每個被解析的元素生成一個事件,以及一個類編寫器,該類編寫器根據此類事件的序列生成已編譯的類。

  • 基於對象的模型
    在基於對象的模型中,用對象樹表示一個類,每個對象代表該類的一部分,例如類本身,字段,方法,指令等,每個對象都具有對這些對象的引用。代表其成分。
    基於對象的API提供了一種將表示一個類的事件序列轉換爲表示相同類的對象樹的方法,反之亦然,是一種將對象樹轉換爲等效事件序列的方法。
    換句話說,基於對象的API建立在基於事件的API之上


這兩個API可以與XML文檔的簡單API(SAX)和XML文檔的文檔對象模型(DOM)API進行比較:

基於事件的API與SAX類似,而基於對象的API與DOM類似。

基於對象的API建立在基於事件的API之上,就像可以在SAX之上提供DOM一樣。

ASM提供這兩種API,因爲沒有最好的API。實際上,每個API都有自己的優點和缺點:

  • 與基於對象的API相比,基於事件的API更快並且需要的內存更少,因爲不需要創建並在內存中存儲代表該類的對象樹(SAX和DOM之間也存在相同的區別)
  • 但是,使用基於事件的API實現類轉換可能會更加困難,因爲在任何給定時間只有該類的一個元素(與當前事件相對應的元素)纔可用,而整個類都可以在基於對象的API內存中使用

請注意,這兩個API一次僅管理一個類,而與其他API無關:不維護有關類層次結構的信息,並且如果類轉換影響其他類,則由用戶來修改這些其他類。

2.3 架構

ASM應用程序具有強大的體系結構方面。

實際上,基於事件的API是圍繞事件生成器(類解析器),事件使用者(類編寫器)和各種預定義的事件過濾器組織的,可以向其中添加用戶定義的生產者,使用者和過濾器。因此,使用此API分爲兩個步驟:

  1. 將事件產生器,過濾器和使用者組件組裝到可能複雜的架構中
  2. 然後啓動事件生產者以運行生成或轉換過程。

基於對象的API也具有體系結構方面:實際上,可以構成對對象樹進行操作的類生成器或轉換器組件,它們之間的鏈接表示轉換的順序。

儘管典型ASM應用程序中的大多數組件體系結構都非常簡單,但是可以想象如下複雜的體系結構,其中箭頭表示類解析器,編寫器或轉換器之間的基於事件或基於對象的通信,並且可能在基於事件和基於對象之間進行轉換 鏈中任何地方的表示形式:

在這裏插入圖片描述

0x03 組織

ASM庫組織在幾個包中,這些包分佈在幾個jar文件中:

  • org.objectweb.asm和org.objectweb.asm.signature包
    定義基於事件的API,並提供類解析器和編寫器組件。 它們包含在asm.jar存檔中。

  • 在asm-util.jar檔案中的org.objectweb.asm.util包中,
    提供了基於核心API的各種工具,這些工具可以在
    ASM應用程序的開發和調試中使用。

  • org.objectweb.asm.commons包提供了幾個有用的預定義類轉換器,這些轉換器主要基於核心API。 它包含在asm-commons.jar存檔中。

  • org.objectweb.asm.tree包,在asm-tree.jar存檔中,
    定義基於對象的API,並提供在基於事件的表示和基於對象的表示之間進行轉換的工具。

  • org.objectweb.asm.tree.analysis包提供了一個基於樹API的類分析框架和幾個預定義的類分析器。 它包含在asm-analysis.jar存檔中。

接下來的數篇博客分爲兩部分介紹ASM。
第一部分介紹了核心API,即 asm,asm-util和asm-commons檔案。
第二部分介紹了樹API,即asm-tree和asm-analysis存檔。

這種組織結構使逐步引入類文件功能變得更加容易,但有時需要將單個ASM類的表示形式分散在幾個部分中。 因此,建議按順序閱讀本文檔。 有關ASM API的參考指南,請使用Javadoc

0x04 版本

ASM發佈的相關版本,查看鏈接Versions

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章