
Analizzatore di bytecode Java personalizzabile tramite regole JSON
Analizzatore di bytecode Java personalizzabile tramite regole JSON. È uno strumento da riga di comando che riceve un percorso contenente uno o più file Jar o War, li analizza utilizzando le regole fornite e genera report HTML con i risultati.
usage: java -jar cba-cli.jar [OPTIONS] -a DIRECTORY_TO_ANALYZE
-a,--analyze <pathToAnalyze> Percorso della directory su cui eseguire
l'analisi.
-c,--checks <checks...> Elenco separato da spazi di controlli personalizzati
che verranno eseguiti nell'analisi.
-f,--custom-file <customFile> Specifica un file in formato JSON per eseguire
regole personalizzate. Leggi di più su
https://github.com/fergarrui/custom-bytecode-analyzer.
-h,--help Stampa questo messaggio.
-i,--items-report <maxItems> Numero massimo di elementi per report. Se il
numero di problemi trovati supera questo
valore, il report verrà suddiviso in file
diversi. Utile se ci si aspetta troppi
problemi nel report. Predefinito: 50.
-o,--output <outputDir> Directory in cui salvare il report. Attenzione -
se in questa directory sono già presenti report
salvati, verranno sovrascritti.
Predefinita è "report".
-v,--verbose-debug Aumenta la verbosità in modalità debug.
-vv,--verbose-trace Aumenta la verbosità in modalità trace - rallenta, usala solo quando necessario.
Il file delle regole può essere specificato usando l'argomento -f,--custom-file. Il file è in formato JSON e ha la seguente struttura:
finalPuoi anche controllare net.nandgr.cba.custom.model.Rules.java per vedere la struttura nel codice Java.
Ci sono già diverse regole nella directory examples. Comunque, di seguito sono elencati esempi per ogni regola.
Se dobbiamo trovare classi con deserializzazione personalizzata, possiamo farlo abbastanza facilmente. Una classe definisce deserializzazione personalizzata implementando private void readObject(ObjectInputStream in). Quindi dobbiamo solo trovare tutte le classi in cui quel metodo è definito. Sarebbe sufficiente definire una regola come:
{
"rules": [{
"name": "Deserializzazione personalizzata",
"methods": [{
"name": "readObject",
"visibility": "private",
"parameters" : [{
"type" : "java.io.ObjectInputStream"
}]
}]
}]
}
Segnalerà metodi con visibilità private, nome readObject e un parametro di tipo java.io.ObjectOutputStream. I parametri sono un array; se ne viene specificato più di uno, devono corrispondere tutti per essere segnalati. Poiché abbiamo una sola regola, verrà creato un report denominato: custom-deserialization-0.html.
In questo caso, deve essere definita una regola con due metodi. Lo stesso dell'esempio precedente per la deserializzazione, e uno nuovo per corrispondere a private void writeObject(ObjectOutputStream out). Come mostrato nella struttura JSON sopra, la proprietà rules.rule.methods è un array di metodi, quindi si può scrivere una regola come questa:
{
"rules": [{
"name": "Serializzazione e deserializzazione personalizzate",
"methods": [{
"name": "readObject",
"visibility": "private",
"parameters" : [{
"type" : "java.io.ObjectInputStream"
}]
},{
"name": "writeObject",
"report": "false",
"visibility": "private",
"parameters" : [{
"type" : "java.io.ObjectOutputStream"
}]
}]
}]
}
La proprietà report è stata impostata su false per evitare di segnalare due volte per la stessa regola. Stiamo usando il secondo metodo solo come condizione, ma segnalare solo i metodi readObject dovrebbe essere sufficiente per lo scopo di questa regola.
Se una proprietà non è definita, corrisponderà sempre come true. Ad esempio, questa regola restituirebbe tutte le definizioni di metodo:
{
"rules": [{
"name": "Definizioni di metodo",
"methods": [{
}]
}]
}
È possibile trovare anche le invocazioni di metodo. Il JSON in questo caso sarebbe:
{
"rules": [{
"name": "String equals",
"invocations": [{
"owner": "java.lang.String",
"method": {
"name": "equals"
}
}]
}]
}
La proprietà owner specifica la classe contenente il metodo.
Un altro esempio di invocazione di metodo un po' più utile del precedente:
{
"rules": [{
"name": "Invocazione di metodo per riflessione",
"invocations": [{
"owner": "java.lang.reflect.Method",
"method": {
"name": "invoke"
}
}]
}]
}
È uguale a qualsiasi invocazione di metodo, ma il nome del metodo in questo caso dovrebbe essere <init>.
{
"rules": [{
"name" : "Istanziazione di String",
"invocations" : [{
"owner" : "java.lang.String",
"method" : {
"name" : "<init>"
}
}]
}]
}
Questa regola troverà occorrenze di:
[...]
String s = new String("foo");
[...]