
Analyseur de bytecode Java personnalisable via des règles JSON
Analyseur de bytecode Java personnalisable via des règles JSON. C'est un outil en ligne de commande qui reçoit un chemin contenant un ou plusieurs fichiers Jar ou War, les analyse en utilisant les règles fournies et génère des rapports HTML avec les résultats.
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.
Le fichier de règles peut être spécifié en utilisant l'argument -f,--custom-file. Le fichier est au format JSON et a la structure suivante :
finalVous pouvez également consulter net.nandgr.cba.custom.model.Rules.java pour voir la structure en code Java.
Il existe déjà plusieurs règles dans le répertoire examples. Quoi qu'il en soit, voici des exemples pour chaque règle.
Si nous avons besoin de trouver des classes avec désérialisation personnalisée, nous pouvons le faire assez facilement. Une classe définit une désérialisation personnalisée en implémentant private void readObject(ObjectInputStream in). Nous avons donc seulement besoin de trouver toutes les classes où cette méthode est définie. Il suffirait de définir une règle comme :
{
"rules": [{
"name": "Custom deserialization",
"methods": [{
"name": "readObject",
"visibility": "private",
"parameters" : [{
"type" : "java.io.ObjectInputStream"
}]
}]
}]
}
Il rapportera les méthodes avec la visibilité private, readObject comme nom et un paramètre de type java.io.ObjectOutputStream. Les paramètres sont un tableau ; si plus d'un est spécifié, tous doivent correspondre pour être signalés. Comme nous n'avons qu'une seule règle, un rapport nommé custom-deserialization-0.html sera créé.
Dans ce cas, une règle avec deux méthodes doit être définie. La même que dans l'exemple précédent pour la désérialisation, et une nouvelle pour correspondre à private void writeObject(ObjectOutputStream out). Comme indiqué dans la structure JSON ci-dessus, la propriété rules.rule.methods est un tableau de méthodes, donc une règle comme celle-ci peut être écrite :
{
"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"
}]
}]
}]
}
La propriété report a été définie à false pour éviter de signaler deux fois la même règle. Nous utilisons la deuxième méthode juste comme condition, mais signaler uniquement les méthodes readObject devrait suffire pour l'objectif de cette règle.
Si une propriété n'est pas définie, elle correspondra toujours à vrai. Par exemple, cette règle retournerait toutes les définitions de méthodes :
{
"rules": [{
"name": "Method definitions",
"methods": [{
}]
}]
}
Les invocations de méthodes peuvent également être trouvées. Le JSON dans ce cas serait :
{
"rules": [{
"name": "String equals",
"invocations": [{
"owner": "java.lang.String",
"method": {
"name": "equals"
}
}]
}]
}
La propriété owner spécifie la classe contenant la méthode.
Un autre exemple d'invocation de méthode un peu plus utile que le précédent :
{
"rules": [{
"name": "Method invocation by reflection",
"invocations": [{
"owner": "java.lang.reflect.Method",
"method": {
"name": "invoke"
}
}]
}]
}
C'est la même chose que n'importe quelle invocation de méthode, mais le nom de la méthode dans ce cas doit être <init>.
{
"rules": [{
"name" : "String instantiation",
"invocations" : [{
"owner" : "java.lang.String",
"method" : {
"name" : "<init>"
}
}]
}]
}
Cette règle trouvera les occurrences de :
[...]
String s = new String("foo");
[...]