Java字節碼分析儀可通過JSON規則自定義。它是一個命令行工具,它接收包含一個或多個JAR或戰爭文件的路徑,使用提供的規則對其進行分析,並生成帶有結果的HTML報告。
usage: java -jar cba-cli.jar [OPTIONS] -a DIRECTORY_TO_ANALYZE
-a,--analyze <pathToAnalyze> Path of the directory to run the
analysis.
-c,--checks <checks...> Space separated list of custom checks
that are going to be run in the analysis.
-f,--custom-file <customFile> Specify a file in JSON format to run
custom rules. Read more in
https://github.com/fergarrui/custom-bytecode-analyzer.
-h,--help Print this message.
-i,--items-report <maxItems> Max number of items per report. If the
number of issues found exceeds this
value, the report will be split into
different files. Useful if expecting too
many issues in the report. Default: 50.
-o,--output <outputDir> Directory to save the report. Warning -
if there are already saved reports in
this directory they will be overwritten.
Default is "report".
-v,--verbose-debug Increase verbosity to debug mode.
-vv,--verbose-trace Increase verbosity to trace mode - makes it slower, use it only when you need.
可以使用-f,--custom-file參數指定規則文件。該文件為JSON格式,具有以下結構:
final時才支持您還可以檢查net.nandgr.cba.custom.model.Rules.java以查看Java代碼中的結構。
目錄示例中已經有幾個規則。無論如何,以下是每個規則的列出的示例。
如果我們需要找到具有自定義挑選化的課程,我們可以很容易地做到這一點。一類通過實現private void readObject(ObjectInputStream in)來定義自定義的挑選化。因此,我們只需要找到定義該方法的所有類。僅將規則定義為:
{
"rules" : [{
"name" : " Custom deserialization " ,
"methods" : [{
"name" : " readObject " ,
"visibility" : " private " ,
"parameters" : [{
"type" : " java.io.ObjectInputStream "
}]
}]
}]
}它將報告具有private可見性的方法, readObject作為名稱和類型java.io.ObjectOutputStream的參數。參數是一個數組,如果指定了多個,則所有這些數組都必須匹配以進行報告。由於我們只有一個規則,因此將創建一個名為:Custom-DeSerialization-0.html的報告。
在這種情況下,必須定義一種具有兩種方法的規則。與上一個典型化的示例相同,以及一個新的,可以匹配private void writeObject(ObjectOutputStream out) 。如上上面的JSON結構所示,屬性規則rule.Methods是一系列方法,因此可以寫入這樣的規則:
{
"rules" : [{
"name" : " Custom serialization and deserialization " ,
"methods" : [{
"name" : " readObject " ,
"visibility" : " private " ,
"parameters" : [{
"type" : " java.io.ObjectInputStream "
}]
},{
"name" : " writeObject " ,
"report" : " false " ,
"visibility" : " private " ,
"parameters" : [{
"type" : " java.io.ObjectOutputStream "
}]
}]
}]
}屬性report設置為False,以避免針對同一規則進行兩次報告。我們將第二種方法只是作為條件,但是僅報告readObject方法就足以滿足此規則的目的。
如果未定義屬性,它將始終匹配為true。例如,此規則將返回所有方法定義:
{
"rules" : [{
"name" : " Method definitions " ,
"methods" : [{
}]
}]
}也可以找到方法調用。在這種情況下,JSON將是:
{
"rules" : [{
"name" : " String equals " ,
"invocations" : [{
"owner" : " java.lang.String " ,
"method" : {
"name" : " equals "
}
}]
}]
}屬性owner指定包含該方法的類。
另一個方法調用示例比上一個更有用:
{
"rules" : [{
"name" : " Method invocation by reflection " ,
"invocations" : [{
"owner" : " java.lang.reflect.Method " ,
"method" : {
"name" : " invoke "
}
}]
}]
}它與任何方法調用相同,但是在這種情況下,該方法的名稱應為<init> 。
{
"rules" : [{
"name" : " String instantiation " ,
"invocations" : [{
"owner" : " java.lang.String " ,
"method" : {
"name" : " <init> "
}
}]
}]
}該規則將發現:
[...]
String s = new String ( "foo" );
[...]在此示例中,我們希望找到必不可少的用法(不是像以前的示例中那樣定義序列化行為的類)。當ObjectInputStream.readObject()調用時,應進行挑戰。例如,在此代碼段中:
ObjectInputStream in = new ObjectInputStream ( fileInputStream );
Object o = in . readObject ();因此,我們需要從名為readObject的ObjectInputStream中找到方法調用。但是,它會在研究環境中找到很多誤報,因為當一類定義自定義避免化時,它們在private void readObject(ObjectInputStream in)方法中對此方法進行調用,這會造成過多污染報告。如果我們要排除這些案例並僅保留真正的避難所,則可以使用notFrom屬性:
{
"rules" : [{
"name" : " Deserialization usage " ,
"invocations" : [{
"owner" : " java.io.ObjectInputStream " ,
"method" : {
"name" : " readObject "
},
"notFrom" : {
"name" : " readObject " ,
"visibility" : " private "
}
}]
}]
}如果在private void readObject(ObjectInputStream in)方法中,此文件將找到java.io.ObjectInputStream.readObject()調用。
與此代碼編譯的類不會報告:
private void readObject ( ObjectInputStream in ) throws IOException , ClassNotFoundException {
Object o = in . readObject ();
}但這將報告:
public Object deserializeObject ( ObjectInputStream in ) throws IOException , ClassNotFoundException {
Object o = in . readObject ();
return o ;
}可以以與notFrom完全相同的方式設置from屬性,但結果將相反:僅當從定義的方法中進行調用時,它才會匹配。
在這種情況下,可以使用屬性superClass 。如果我們想找到擴展javax.servlet.http.HttpServlet所有類,則可以是:
{
"rules" : [{
"name" : " Java servlets " ,
"superClass" : " javax.servlet.http.HttpServlet "
}]
}
可以編寫規則以查找實現一系列接口的類。如果規則中定義了多個接口,則類必須實現所有接口以進行報告。如果我們想找到實現javax.net.ssl.X509TrustManager類,則該規則將是:
{
"rules" : [{
"name" : " X509TrustManager implementations " ,
"interfaces" : [ " javax.net.ssl.X509TrustManager " ]
}]
}請注意, interfaces是一個數組,因此請確保在方括號之間添加字符串,例如: ["interface1", "interface2", ...] 。
還支持註釋。可以在規則(查找類註釋),方法o變量(參數或本地變量)中定義多個註釋屬性。如果所有這些都在分析的類中找到,則將報告。例如,如果我們想找到彈簧端點,我們將搜索使用org.springframework.web.bind.annotation.RequestMapping註釋的類或方法。因此,規則可以是:
{
"rules" : [{
"name" : " Spring endpoint - class annotation " ,
"annotations" : [{
"type" : " org.springframework.web.bind.annotation.RequestMapping "
}]
},
{
"name" : " Spring endpoint - method annotation " ,
"methods" : [{
"annotations" : [{
"type" : " org.springframework.web.bind.annotation.RequestMapping "
}]
}]
}]
}屬性rule.fields可用於查找類字段。如果我們想找到帶有密碼名稱的私有字符串字段,則可以使用這樣的規則:
{
"rules" : [{
"name" : " Password fields " ,
"fields" : [
{
"visibility" : " private " ,
"type" : " java.lang.String " ,
"nameRegex" : " (password|pass|psswd|passwd) "
}
]
}]
}要查找變量,可以使用rule.variables 。該屬性將報告局部變量和方法參數變量。如果我們想找到javax.servlet.http.Part類型的所有變量,則可以是:
{
"rules" : [{
"name" : " Servlet upload file " ,
"methods" : [{
"variables" : [{
"type" : " javax.servlet.http.Part "
}]
}]
}]
}可以在同一JSON文件中定義多個規則。它們將被分開處理和報告,不會互相影響。我們可以結合一些以前的示例規則:
{
"rules" : [{
"name" : " Custom deserialization " ,
"methods" : [{
"name" : " readObject " ,
"visibility" : " private " ,
"parameters" : [{
"type" : " java.io.ObjectInputStream "
}]
}]
},{
"name" : " Method invocation by reflection " ,
"invocations" : [{
"owner" : " java.lang.reflect.Method " ,
"method" : {
"name" : " invoke "
}
}]
}]
}在這裡,我們有兩個規則(“自定義避免”和“通過反射調用”)。它們將被處理好,就好像您在兩個分開的執行中進行處理一樣。並將生成規則的報告。如果規則具有相同的名稱,則將在同一文件中報告。
可以下載和構建該項目,以在JSON格式未涵蓋的Java代碼中添加更複雜的自定義規則。軟件包net.nandgr.cba.visitor.checks下的示例已經有三個示例。這些是CustomDeserializationCheck, DeserializationCheck and InvokeMethodCheck 。您可以通過擴展net.nandgr.cba.custom.visitor.base.CustomAbstractClassVisitor來創建自己的規則。
如上所述,默認情況下報告了report文件夾下的報告。除非它們具有相同的名稱,否則每個規則都會有一個單獨的文件。如果報告太大,則可以使用-i,--items-report <maxItems>參數將其拆分,它們每個都會持有指定的參數或更少的參數(如果是最後一個)。每個報告的項目都指定找到它的jar,類名稱和方法名稱(如果相關)。它還顯示了班級的分解版本,以簡化視覺檢查。如何顯示項目以查找java.io.File實例的示例:

在搜索安全錯誤時,擁有呼叫圖非常有用。目前,在report目錄下創建了一個簡單的DOT兼容文件。該圖包含可以從中調用發現問題的所有可能流。例如,如果使用了尋找挑選性化的規則,則將生成通往呼叫次序列化的方法的所有可能路徑的圖。
該文件是call-graph.dot ,看起來像這樣(這是一個非常簡單的示例):
graph callGraph {
"demo.callgraph.Class1:method1" -- "demo.callgraph.Class2:method2"
"demo.callgraph.Class3:method3" -- "demo.callgraph.Class2:method2"
}
要以視覺方式顯示它,可以使用DOT (或任何兼容軟件)。例如,將文件轉換為svg :
dot -Tsvg call-graph.dot -o call-graph.svg
如果在系統路徑中找到點,則默認情況下會自動完成。如果不是,則可以使用sudo apt-get install graphviz將DOT安裝在基於Debian的系統中。
它將創建一個名為call-graph.svg的SVG文件,可以使用inkscape或firefox之類的程序轉換為PNG或可視化。
上述文件呼叫graph.dot的一個非常簡單的示例是:

有一些限制,例如,如果搜索項目在java.lang.Runnable.run()或類似方法中,則將找不到從何處從何處執行該線程。此外,該圖正在清潔週期以避免使用StackOverflowError s,它是以保守的方式製成的,因此在大型目錄的分析過程中不會排干係統的記憶。
將來的版本將添加更多選項。
java -jar cba-cli-<version>.jar -a /path/with/jars -f /path/with/json/file/rules.json
要使用自定義Java規則,必須將類名指定為-c的參數。
java -jar cba-cli-<version>.jar -a /path/with/jars -c DeserializationCheck
接受一個分開的列表,因此可以定義多個自定義規則(每個規則將創建一個單獨的報告):
java -jar cba-cli-<version>.jar -a /path/with/jars -c DeserializationCheck InvokeMethodCheck CustomDeserializationCheck YourCustomRule
java -jar cba-cli-<version>.jar -a /path/with/jars -f /path/with/json/file/rules.json -c YourCustomRule1 YourCustomRule2
為了找到錯誤,可以提高冗長。調試級別:
java -jar cba-cli-<version>.jar -a /path/with/jars -c YourCustomRule1 -v
跟踪級別:
java -jar cba-cli-<version>.jar -a /path/with/jars -c YourCustomRule1 -vv
目前,必須先將APK轉換為JAR才能進行分析。
d2j-dex2jar.sh -f -o app_to_analyze.jar app_to_analyze.apk-a參數運行cba -cli.jar,其中包含轉換後的JAR文件的目錄。 bin Directory下已經有一個可執行的JAR文件:如果要進行修改或添加自定義規則,則可以構建項目:
git clone https://github.com/fergarrui/custom-bytecode-analyzer.git
cd custom-bytecode-analyzer
mvn clean package
target文件夾將生成兩個罐子。 cba-cli-<version>.jar包含所有依賴項,並且是可執行的。可以使用java -jar cba-cli-<version>.jar運行