本申請涉及軟件開發技術領域,尤其涉及一種Java代碼檢測方法及裝置。
背景技術:
在軟件開發過程中,對于編寫好的Java代碼通常可以使用代碼混淆工具(如proguard工具)對代碼進行混淆。
混淆后的Java代碼相對于混淆前的Java代碼可以具有減少代碼量、增加代碼被破譯的難度等優點。
然而,使用代碼混淆工具后,經常會發送混淆后的Java代碼功能與混淆前的Java代碼功能不一致,甚至混淆后代碼功能不可用的情況。
現有技術中,針對混淆后代碼功能不一致的情況,通常會對混淆后的代碼進行測試。測試過程中需要用到測試用例。由于導致混淆后代碼功能不一致的原因多種多樣,一般一個測試用例只能發現一種原因,所以需要編寫盡可能多的測試用例。然而,編寫測試用例需要很高的成本,基于成本考慮無法無限制地增加測試用例,因此基于測試用例的測試無法覆蓋所有混淆后代碼功能不一致的情況,導致存在不能及時發現混淆后java代碼功能不一致的問題。
技術實現要素:
本申請提供的一種Java代碼檢測方法及裝置,以解決現有技術中存在不能及時發現混淆后Java代碼功能不一致的問題。
根據本申請實施例提供的一種Java代碼檢測方法,所述方法包括:
接收待檢測的源代碼;
分析源代碼的函數調用關系,得出所述源代碼的所有子結構代碼;
獲取所述源代碼以及每一個子結構代碼調用的jar包集合;
判斷所獲取的各個jar包集合是否存在沖突jar包;
在所述獲取的各個jar包集合存在沖突jar包的情況下,輸出Java代碼存在混淆后功能不一致的檢測結果。
可選的,所述獲取所述源代碼以及每一個子結構代碼調用的jar包集合,具體包括:
讀取所述源代碼的配置文件中記錄的所述源代碼調用的jar包;
讀取所述子結構代碼的配置文件中記錄的所述子結構代碼調用的jar包;
將所述源代碼調用的jar包以及所述每一個子結構代碼調用的jar包,存入對應的jar包集合。
可選的,所述讀取所述源代碼的配置文件中記錄的所述源代碼調用的jar包,具體包括:
讀取所述源代碼的配置文件中記錄的所述源代碼調用的jar包的名稱以及版本號;
所述讀取所述子結構代碼的配置文件中記錄的所述子結構代碼調用的jar包,具體包括:
讀取所述子結構代碼的配置文件中記錄的所述子結構代碼調用的jar包的名稱以及版本號。
可選的,所述配置文件包括pom文件或者build.gradle文件。
可選的,所述判斷所獲取的各個jar包集合是否存在沖突jar包,具體包括:
獲取所獲取的各個jar包集合中jar包的名稱以及版本號;
判斷是否存在相同名稱、不同版本號的jar包;
相應地,所述在所述獲取的各個jar包集合存在沖突jar包的情況下,輸出Java代碼存在混淆后功能不一致的檢測結果,具體包括:
在存在相同名稱、不同版本號的jar包的情況下,將其加入到沖突jar包集合;
輸出所述沖突jar包集合以及Java代碼存在混淆后功能不一致的檢測結果。
根據本申請實施例提供的一種Java代碼檢測裝置,所述裝置包括:
接收單元,接收待檢測的源代碼;
分析單元,分析源代碼的函數調用關系,得出所述源代碼的所有子結構代碼;
獲取單元,獲取所述源代碼以及每一個子結構代碼調用的jar包集合;
判斷單元,判斷所獲取的各個jar包集合是否存在沖突jar包;
輸出單元,在所述獲取的各個jar包集合存在沖突jar包的情況下,輸出Java代碼存在混淆后功能不一致的檢測結果。
可選的,所述獲取單元,具體包括:
第一讀取子單元,讀取所述源代碼的配置文件中記錄的所述源代碼調用的jar包;
第二讀取子單元,讀取所述子結構代碼的配置文件中記錄的所述子結構代碼調用的jar包;
存儲子單元,將所述源代碼調用的jar包以及所述每一個子結構代碼調用的jar包,存入對應的jar包集合。
可選的,所述第一讀取子單元,具體包括:
讀取所述源代碼的配置文件中記錄的所述源代碼調用的jar包的名稱以及版本號;
所述第二讀取子單元,具體包括:
讀取所述子結構代碼的配置文件中記錄的所述子結構代碼調用的jar包的名稱以及版本號。
可選的,所述配置文件包括pom文件或者build.gradle文件。
可選的,所述判斷單元,具體包括:
獲取子單元,獲取所獲取的各個jar包集合中jar包的名稱以及版本號;
判斷子單元,判斷是否存在相同名稱、不同版本號的jar包;
相應地,所述輸出單元,具體包括:
存儲子單元,在存在相同名稱、不同版本號的jar包的情況下,將其加入到沖突jar包集合;
輸出子單元,輸出所述沖突jar包集合以及Java代碼存在混淆后功能不一致的檢測結果。
本申請實施例中,java代碼混淆后不一致的原因是由于調用相同jar包的版本號存在不一致;所以通過分析源代碼的所有子結構代碼,從而獲取所述源代碼和所有子結構代碼調用的jar包集合;在所述獲取的各個jar包集合存在沖突jar包的情況下,可以得出Java代碼存在混淆后功能不一致的檢測結果。如此,無需通過編寫測試用例,僅通過掃描混淆前的源代碼既可以提前發現使用混淆工具后出現的功能不一致的情況。
附圖說明
圖1是本申請提供的代碼結構的示意圖;
圖2是本申請一實施例提供的Java代碼檢測方法的流程圖;
圖3是圖2中步驟130的具體步驟的流程圖;
圖4是本申請提供的Java代碼檢測裝置所在設備的一種硬件結構圖;
圖5是本申請一實施例提供的Java代碼檢測裝置的模塊示意圖。
具體實施方式
這里將詳細地對示例性實施例進行說明,其示例表示在附圖中。下面的描述涉及附圖時,除非另有表示,不同附圖中的相同數字表示相同或相似的要素。以下示例性實施例中所描述的實施方式并不代表與本申請相一致的所有實施方式。相反,它們僅是與如所附權利要求書中所詳述的、本申請的一些方面相一致的裝置和方法的例子。
在本申請使用的術語是僅僅出于描述特定實施例的目的,而非旨在限制本申請。在本申請和所附權利要求書中所使用的單數形式的“一種”、“所述”和“該”也旨在包括多數形式,除非上下文清楚地表示其他含義。還應當理解,本文中使用的術語“和/或”是指并包含一個或多個相關聯的列出項目的任何或所有可能組合。
應當理解,盡管在本申請可能采用術語第一、第二、第三等來描述各種信息,但這些信息不應限于這些術語。這些術語僅用來將同一類型的信息彼此區分開。例如,在不脫離本申請范圍的情況下,第一信息也可以被稱為第二信息,類似地,第二信息也可以被稱為第一信息。取決于語境,如在此所使用的詞語“如果”可以被解釋成為“在……時”或“當……時”或“響應于確定”。
本申請實施例可以應用在對Java代碼進行測試的測試客戶端。所述測試客戶端可以是軟件上的測試程序。
所述測試客戶端也可以是指軟硬結合的客戶端,例如安裝了測試程序的設備。
如今隨著應用功能的越來越多,越來越全,滿足了用戶需求的同時,對于編程人員來說,則意味著越來越多的代碼,為了方便區分不同的代碼所實現的功能,如今普遍采用的是分層架構也稱為多層架構(例如三層架構)的方式來編寫代碼。分層架構可以將大量代碼按照不同功能進行區分,不同層的代碼各司其職,不會相互影響;便于后期進行維護、擴展功能。
如此,對于一個完整的Java代碼來說,其是由多個實現不同功能的子結構代碼組成的。所述子結構代碼一般會被封裝為一個函數例如addA();不同子結構代碼之間可以通過調用函數來傳遞數據。對于函數在業內還可以稱之為類、方法等。
如前所述,代碼混淆工具可以對Java代碼進行混淆,并且混淆后的Java代碼可以具備減少代碼量、優化代碼結構、增加代碼被破譯的難度等優點。
舉例說明,如圖1所示的一個購物應用的代碼結構示意圖,該應用的可以具有6大功能:
登錄功能、顯示商品列表功能、外賣點餐功能、購物車功能、訂單功能以及支付功能。
對應的,該購物應用的Java代碼可以分為如下5個子結構代碼:
1、用于實現登錄功能的登錄子結構代碼,封裝為函數Login();
2、用于實現顯示商品列表功能的商品子結構代碼,封裝為函數Shop();
3、用于實現購物車功能的購物車子結構代碼,封裝為函數ShoppingCart();
4、用于實現訂單功能的訂單子結構代碼,封裝為函數Order();
5、用于實現支付功能的支付子結構代碼,封裝為函數Pay()。
在用戶使用該購物應用直到完成支付的整個過程如下:
用戶打開應用,首先調用函數Login(),用于登錄用戶賬戶。具體地,需要輸入賬戶名和密碼,所述賬戶名、密碼可以是用戶手動輸入的,也可以是直接獲取保存在本地的賬戶名、密碼。
在登錄成功后,則調用函數Shop(),來顯示商品列表;用戶瀏覽商品可以將想要購買的商品加入購物車;
用戶點擊購物車,則調用函數ShoppingCart(),顯示購物車內添加的商品;
用戶點擊提交訂單,則調用函數Order(),生成待支付的訂單;
用戶點擊支付,則調用函數Pay(),用于供用戶進行支付操作。
如此,在支付成功后,一次購物過程完成。
代碼混淆工具在混淆代碼時,可以通過分析Java代碼中函數調用關系,對于沒有被調用的函數,通常意味著該函數對應的子結構代碼實現的功能并沒有被用到。例如老功能被新功能取代后,則老功能對應的子結構代碼封裝的函數就不會被調用了,可以將沒有被調用的代碼刪除,從而實現減少代碼量。在圖1中,還存在有一個函數Food(),所述Food()為用于實現外賣點餐的功能,由于以前該功能推出后,用戶反映不好,所以后來又取消了該功能,所以該函數Food()沒有被調用。假設該購物應用的Java代碼經過代碼混淆工具進行代碼混淆后,會將函數Food()的子結構代碼去除,從而減少代碼量。
代碼混淆工具在混淆代碼時,還可以混淆函數名和變量名,從而起到增加代碼被破譯的難度。例如,將圖1中用于實現支付功能的函數Pay()和用于登錄功能的函數Login()的函數名互換;則代碼混淆后,用于實現支付功能的函數名變為Login(),用于實現登錄功能的函數名變為Pay(),這樣對于想要破譯代碼的人來說,閱讀代碼的難度就會增加很多,從而增加了代碼被破譯的難度。
然而,使用代碼混淆工具后,經常會發送混淆后的Java代碼功能與混淆前的Java代碼功能不一致,甚至混淆后代碼功能不可用的情況。
在Java中,可以允許用戶使用別人已經編寫好的函數,這些外部的函數就是以jar(Java ARchive)包的形式導入的。在調用jar包后,就可以使用該jar包所提供的函數。
一般的,導致混淆后代碼功能不一致的原因是由于不同代碼調用了相同名稱,但版本號不同的jar包,而不同版本號可能實現的功能不完全相同。
代碼混淆工具主要是根據不同代碼調用的jar包做代碼分析,進而進行代碼混淆,而代碼混淆工具無法識別相同名詞版本號不同的情況下,這樣就容易發生混淆后代碼功能不一致的情況。例如,存在兩個子結構代碼分別調用名稱相同、版本號不同(存在功能差異)的兩個jar包,對應代碼混淆工具來說,這兩個jar包是相同的,從而會刪除其中一個jar包,將原本的兩個子結構代碼同時調用剩下的一個jar包,如此會導致其中一個子結構代碼的功能發送改變。
如前所述,針對混淆后代碼功能不一致的情況,通常會對混淆后的代碼進行測試。測試過程中需要用到測試用例。由于相同名稱、版本號不同的jar包多種多樣,因此導致混淆后代碼功能不一致的情況也多種多樣。一般的,一個測試用例只能覆蓋一種情況,所以需要編寫盡可能多的測試用例。然而,編寫測試用例需要很高的成本,基于成本考慮無法無限制地增加測試用例,因此基于測試用例的測試無法覆蓋所有混淆后代碼功能不一致的情況,導致存在不能及時發現混淆后java代碼功能不一致的問題。
為了解決上述問題,請參見圖2,為本申請一實施例提供的Java代碼檢測方法的流程圖,所述方法包括以下步驟:
步驟110:接收待檢測的源代碼。
本實施例中,所述源代碼可以是未經過代碼混淆的Java代碼。
步驟120:分析源代碼的函數調用關系,得出所述源代碼的所有子結構代碼。
本實施例中,測試客戶端在接收到待測試的源代碼后,可以分析所述源代碼的函數調用關系,從而得出所述源代碼的子結構代碼。
一般的,分析函數調用關系都是從最后一層開始分析的。依舊如圖1所示,通過分析源代碼中的函數調用關系:
函數Pay()調用了函數Order();
而函數Order()調用了函數ShoppingCart();
函數ShoppingCart()調用了函數Shop();
函數Shop()調用了函數Login()。
因此,存在有5個子結構代碼,分別為:
函數Pay()對應的子結構代碼;以下簡稱為A代碼;
函數Order()對應的子結構代碼;以下簡稱為B代碼;
函數ShoppingCart()對應的子結構代碼;以下簡稱為C代碼;
函數Shop()對應的子結構代碼;以下簡稱為D代碼;
函數Login()對應的子結構代碼;以下簡稱為E代碼。
步驟130:獲取所述源代碼以及每一個子結構代碼調用的jar包集合。
本實施例中,測試客戶端在根據源代碼的函數調用關系,得出所述源代碼的所有子結構代碼之后,可以獲取所述源代碼以及每一個子結構代碼調用的jar包集合。
具體地,所述步驟130,如圖3所示可以包括如下步驟:
步驟131:讀取所述源代碼的配置文件中記錄的所述源代碼調用的jar包;
具體地,讀取所述源代碼的配置文件中記錄的所述源代碼調用的jar包的名稱以及版本號。
步驟132:讀取所述子結構代碼的配置文件中記錄的所述子結構代碼調用的jar包;
具體地,讀取所述子結構代碼的配置文件中記錄的所述子結構代碼調用的jar包的名稱以及版本號。
步驟133:將所述源代碼調用的jar包以及所述每一個子結構代碼調用的jar包,存入對應的jar包集合。
在Java開發中,通常可以將需要調用的jar包統一配置到配置文件中。
在實際應用中,為了方便管理不同的配置文件,通常需要應用例如maven工具、gradle工具等服務于Java的項目構建工具。
使用不同的工具生成的配置文件一般存在差異,使用maven工具生成的配置文件為pom文件;使用gradle工具生成的配置文件為build.gradle文件。
以下以pom文件為例介紹獲取代碼調用的jar包的過程:
如上所示為pom文件中配置的一個jar包。在pom文件中,jar包名稱對應的字段為“groupId”以及“artifactId”;jar包版本號對應的字段為“version”。因此,該jar包的名稱為:group.a-artifact.b;
該jar包的版本號為:1.0。
依然沿用上一步驟中的例子:
假設讀取源代碼的配置文件中記錄的所述源代碼調用的jar包為:
名稱:group.1-artifact.1;版本號:1.0;
名稱:group.2-artifact.2;版本號:1.0;
名稱:group.3-artifact.3;版本號:1.0;
名稱:group.4-artifact.4;版本號:1.0;
名稱:group.5-artifact.5;版本號:1.0;
讀取A代碼的配置文件中記錄的所述源代碼調用的jar包為:
名稱:group.1-artifact.1;版本號:1.0;
讀取B代碼的配置文件中記錄的所述源代碼調用的jar包為:
名稱:group.2-artifact.2;版本號:2.0;
讀取C代碼的配置文件中記錄的所述源代碼調用的jar包為:
名稱:group.3-artifact.3;版本號:1.0;
讀取D代碼的配置文件中記錄的所述源代碼調用的jar包為:
名稱:group.4-artifact.4;版本號:2.0;
讀取E代碼的配置文件中記錄的所述源代碼調用的jar包為:
名稱:group.5-artifact.5;版本號:1.0;
步驟140:判斷所獲取的各個jar包集合是否存在沖突jar包。
本實施例中,所述沖突可以是指不同jar包集合中存在相同名稱、不同版本號的jar包。
如此,所述步驟130,具體可以包括:
獲取所獲取的各個jar包集合中jar包的名稱以及版本號;
判斷是否存在相同名稱、不同版本號的jar包。
沿用上一步驟中的例子,即:
源代碼調用的jar包集合為Y{名稱:group.1-artifact.1;版本號:1.0;
名稱:group.2-artifact.2;版本號:1.0;
名稱:group.3-artifact.3;版本號:1.0;
名稱:group.4-artifact.4;版本號:1.0;
名稱:group.5-artifact.5;版本號:1.0}
A代碼調用的jar包集合為X1{名稱:group.1-artifact.1;版本號:1.0}
B代碼調用的jar包集合為X2{名稱:group.2-artifact.2;版本號:2.0}
C代碼調用的jar包集合為X3{名稱:group.3-artifact.3;版本號:1.0}
D代碼調用的jar包集合為X4{名稱:group.4-artifact.4;版本號:2.0}
E代碼調用的jar包集合為X5{名稱:group.5-artifact.5;版本號:1.0}
判斷jar包集合Y和jar包集合X1,由于存在名稱group.1-artifact.1相同的jar包,并且版本號1.0也相同,因此這兩個jar包集合不存在沖突jar包。
判斷jar包集合Y和jar包集合X2,由于存在名稱group.2-artifact.2相同的jar包,并且版本號不同(一個是1.0一個是2.0),因此這兩個jar包集合存在沖突jar包。
判斷jar包集合Y和jar包集合X3,由于存在名稱group.3-artifact.3相同的jar包,并且版本號1.0也相同,因此這兩個jar包集合不存在沖突jar包。
判斷jar包集合Y和jar包集合X4,由于存在名稱group.4-artifact.4相同的jar包,并且版本號不同(一個是1.0一個是2.0),因此這兩個jar包集合存在沖突jar包。
判斷jar包集合Y和jar包集合X5,由于存在名稱group.5-artifact.5相同的jar包,并且版本號1.0也相同,因此這兩個jar包集合不存在沖突jar包。
在jar包集合X1到X5之間,由于沒有存在名稱相同的jar包,因此都不存在沖突jar包。
步驟150:在所述獲取的各個jar包集合存在沖突jar包的情況下,輸出Java代碼存在混淆后功能不一致的檢測結果。
本實施例中,繼續沿用上一步驟中的例子,由于jar包集合Y和jar包集合X2存在沖突jar包,以及jar包集合Y和jar包集合X4存在沖突jar包;因此,可以輸出Java代碼存在混淆后功能不一致的檢測結果。
在另一個實施例中,所述步驟140,具體可以包括如下步驟:
在存在相同名稱、不同版本號的jar包的情況下,將其加入到沖突jar包集合;
輸出所述沖突jar包集合以及Java代碼存在混淆后功能不一致的檢測結果。
本實施例中,可以將jar包集合Y和jar包集合X2存在的沖突jar包:
名稱:group.1-artifact.1;版本號:1.0和名稱:group.1-artifact.1;版本號:2.0;
以及jar包集合Y和jar包集合X4存在的沖突jar包:
名稱:group.4-artifact.4;版本號:1.0和名稱:group.4-artifact.4;版本號:2.0;
寫入到沖突jar包集合中{名稱:group.1-artifact.1;版本號:1.0;
名稱:group.1-artifact.1;版本號:2.0;
名稱:group.4-artifact.4;版本號:1.0;
名稱:group.4-artifact.4;版本號:2.0}
最后,輸出該沖突jar包集合,以及Java代碼存在混淆后功能不一致的檢測結果。
通過本實施例,java代碼混淆后不一致的原因是由于調用相同jar包的版本號存在不一致;所以通過分析源代碼的所有子結構代碼,從而獲取所述源代碼和所有子結構代碼調用的jar包集合;在所述獲取的各個jar包集合存在沖突jar包的情況下,可以得出Java代碼存在混淆后功能不一致的檢測結果。如此,無需通過編寫測試用例,僅通過掃描混淆前的源代碼既可以發現使用混淆工具后出現的功能不一致的情況。
與前述Java代碼檢測方法實施例相對應,本申請還提供了一種Java代碼檢測裝置的實施例。
本申請Java代碼檢測裝置的實施例可以應用在測試客戶端。裝置實施例可以通過軟件實現,也可以通過硬件或者軟硬件結合的方式實現。以軟件實現為例,作為一個邏輯意義上的裝置,是通過其所在設備的處理器將非易失性存儲器中對應的計算機程序指令讀取到內存中運行形成的。從硬件層面而言,如圖4所示,為本申請Java代碼檢測裝置所在設備的一種硬件結構圖,除了圖4所示的處理器、網絡接口、內存以及非易失性存儲器之外,實施例中裝置所在的設備通常根據該Java代碼檢測實際功能,還可以包括其他硬件,對此不再贅述。
參見圖5,為本申請一實施例提供的Java代碼檢測裝置的模塊圖,所述裝置包括:接收單元310、分析單元320、獲取單元330、判斷單元340以及輸出單元350。
其中,接收單元310,接收待檢測的源代碼;
分析單元320,分析源代碼的函數調用關系,得出所述源代碼的所有子結構代碼;
獲取單元330,獲取所述源代碼以及每一個子結構代碼調用的jar包集合;
判斷單元340,判斷所獲取的各個jar包集合是否存在沖突jar包;
輸出單元350,在所述獲取的各個jar包集合存在沖突jar包的情況下,輸出Java代碼存在混淆后功能不一致的檢測結果。
在一個可選的實施方式中:
所述獲取單元330,具體包括:
第一讀取子單元,讀取所述源代碼的配置文件中記錄的所述源代碼調用的jar包;
第二讀取子單元,讀取所述子結構代碼的配置文件中記錄的所述子結構代碼調用的jar包;
存儲子單元,將所述源代碼調用的jar包以及所述每一個子結構代碼調用的jar包,存入對應的jar包集合。
在一個可選的實施方式中:
所述第一讀取子單元,具體包括:
讀取所述源代碼的配置文件中記錄的所述源代碼調用的jar包的名稱以及版本號;
所述第二讀取子單元,具體包括:
讀取所述子結構代碼的配置文件中記錄的所述子結構代碼調用的jar包的名稱以及版本號。
在一個可選的實施方式中:
所述配置文件包括pom文件或者build.gradle文件。
在一個可選的實施方式中:
所述判斷單元340,具體包括:
獲取子單元,獲取所獲取的各個jar包集合中jar包的名稱以及版本號;
判斷子單元,判斷是否存在相同名稱、不同版本號的jar包;
相應地,所述輸出單元350,具體包括:
存儲子單元,在存在相同名稱、不同版本號的jar包的情況下,將其加入到沖突jar包集合;
輸出子單元,輸出所述沖突jar包集合以及Java代碼存在混淆后功能不一致的檢測結果。
上述實施例闡明的系統、裝置、模塊或單元,具體可以由計算機芯片或實體實現,或者由具有某種功能的產品來實現。一種典型的實現設備為計算機,計算機的具體形式可以是個人計算機、膝上型計算機、蜂窩電話、相機電話、智能電話、個人數字助理、媒體播放器、導航設備、電子郵件收發設備、游戲控制臺、平板計算機、可穿戴設備或者這些設備中的任意幾種設備的組合。
上述裝置中各個單元的功能和作用的實現過程具體詳見上述方法中對應步驟的實現過程,在此不再贅述。
對于裝置實施例而言,由于其基本對應于方法實施例,所以相關之處參見方法實施例的部分說明即可。以上所描述的裝置實施例僅僅是示意性的,其中所述作為分離部件說明的單元可以是或者也可以不是物理上分開的,作為單元顯示的部件可以是或者也可以不是物理單元,即可以位于一個地方,或者也可以分布到多個網絡單元上。可以根據實際的需要選擇其中的部分或者全部模塊來實現本申請方案的目的。本領域普通技術人員在不付出創造性勞動的情況下,即可以理解并實施。
本領域技術人員在考慮說明書及實踐這里公開的發明后,將容易想到本申請的其它實施方案。本申請旨在涵蓋本申請的任何變型、用途或者適應性變化,這些變型、用途或者適應性變化遵循本申請的一般性原理并包括本申請未公開的本技術領域中的公知常識或慣用技術手段。說明書和實施例僅被視為示例性的,本申請的真正范圍和精神由下面的權利要求指出。
應當理解的是,本申請并不局限于上面已經描述并在附圖中示出的精確結構,并且可以在不脫離其范圍進行各種修改和改變。本申請的范圍僅由所附的權利要求來限制。