{"id":19290368,"url":"https://github.com/fergarrui/custom-bytecode-analyzer","last_synced_at":"2025-08-26T19:24:32.411Z","repository":{"id":107343897,"uuid":"78369404","full_name":"fergarrui/custom-bytecode-analyzer","owner":"fergarrui","description":"Java bytecode analyzer customizable via JSON rules","archived":false,"fork":false,"pushed_at":"2018-03-27T08:21:50.000Z","size":8801,"stargazers_count":74,"open_issues_count":0,"forks_count":13,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-04-22T06:18:57.173Z","etag":null,"topics":["analysis","analyzer","bughunting","bytecode","callgraph","java","json","security","static-analysis"],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fergarrui.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-01-08T20:44:04.000Z","updated_at":"2024-07-27T09:30:35.000Z","dependencies_parsed_at":"2023-05-17T03:45:37.655Z","dependency_job_id":null,"html_url":"https://github.com/fergarrui/custom-bytecode-analyzer","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/fergarrui/custom-bytecode-analyzer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fergarrui%2Fcustom-bytecode-analyzer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fergarrui%2Fcustom-bytecode-analyzer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fergarrui%2Fcustom-bytecode-analyzer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fergarrui%2Fcustom-bytecode-analyzer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fergarrui","download_url":"https://codeload.github.com/fergarrui/custom-bytecode-analyzer/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fergarrui%2Fcustom-bytecode-analyzer/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272248836,"owners_count":24899866,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-26T02:00:07.904Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["analysis","analyzer","bughunting","bytecode","callgraph","java","json","security","static-analysis"],"created_at":"2024-11-09T22:18:59.969Z","updated_at":"2025-08-26T19:24:32.366Z","avatar_url":"https://github.com/fergarrui.png","language":"Java","readme":"# custom-bytecode-analyzer\n\nJava bytecode analyzer customizable via JSON rules. It is a command-line tool that receives a path containing one or more [Jar](https://en.wikipedia.org/wiki/JAR_(file_format)) or [War](https://en.wikipedia.org/wiki/WAR_(file_format)) files, analyzes them using the provided rules and generates HTML reports with the results.\n\n[![Build Status](https://travis-ci.org/fergarrui/custom-bytecode-analyzer.svg?branch=master)](https://travis-ci.org/fergarrui/custom-bytecode-analyzer)\n\n## Usage\n\n```\nusage: java -jar cba-cli.jar [OPTIONS] -a DIRECTORY_TO_ANALYZE\n -a,--analyze \u003cpathToAnalyze\u003e    Path of the directory to run the\n                                 analysis.\n-c,--checks \u003cchecks...\u003e          Space separated list of custom checks\n\t\t\t\t\t\t\t\t that are going to be run in the analysis.\n -f,--custom-file \u003ccustomFile\u003e   Specify a file in JSON format to run\n                                 custom rules. Read more in\n                                 https://github.com/fergarrui/custom-bytecode-analyzer.\n -h,--help                       Print this message.\n -i,--items-report \u003cmaxItems\u003e    Max number of items per report. If the\n                                 number of issues found exceeds this\n                                 value, the report will be split into\n                                 different files. Useful if expecting too\n                                 many issues in the report. Default: 50.\n -o,--output \u003coutputDir\u003e         Directory to save the report. Warning -\n                                 if there are already saved reports in\n                                 this directory they will be overwritten.\n                                 Default is \"report\".\n -v,--verbose-debug              Increase verbosity to debug mode.\n -vv,--verbose-trace             Increase verbosity to trace mode - makes it slower, use it only when you need.\n```\n\n## Custom JSON rules\n\nRules file can be specified using ```-f,--custom-file``` argument . The file is in JSON format and has the following structure:\n\n* rules : array(rule)\n    * name : string\n    * fields : array(field)\n        * visibility : (public|protected|private)\n        * type : string\n        * valueRegex : string (java regular expression) - only supported if the field is ```final```\n        * nameRegex : string (java regular expression)\n        * report : boolean (default: true)\n    * interfaces : array(string)\n    * superClass : string\n    * annotations : array(annotation)\n        * type : string\n        * report : boolean (default: true)\n    * methods :  array(method)\n        * name : string\n        * visibility : (public|protected|private)\n        * parameters : array(parameter)\n            * type : string\n            * report : boolean (default: true)\n            * annotations : array(annotation)\n                * type : string\n                * report : boolean (default: true)\n        * variables : array(variable)\n            * type : string\n            * nameRegex : string (java regular expression)\n            * annotations : array(annotation)\n                * type : string\n                * report : boolean (default: true)\n            * report (default: true)\n        * annotations : array(annotation)\n            * type : string\n            * report : boolean (default: true)\n        * report : boolean (default: true)\n    * invocations : array(invocation)\n        * owner : string\n        * method : method\n            * name : string\n            * visibility : (public|protected|private)\n        * from : method\n            * name : string\n            * visibility : (public|protected|private)\n        * notFrom : method\n            * name : string\n            * visibility : (public|protected|private)\n        * report : boolean (default:true)\n\nYou can also check ```net.nandgr.cba.custom.model.Rules.java``` to see the structure in Java code.\n\n### Examples\n\nThere are already several rules under the directory [examples](https://github.com/fergarrui/custom-bytecode-analyzer/tree/master/examples) .\nAnyway, below are listed examples for every rule.\n\n#### Find custom deserialization\nIf we need to find classes with custom deserialization, we can do it quite easily. A class defines custom deserialization by implementing ```private void readObject(ObjectInputStream in)```. So we only need to find all classes where that method is defined. It would be enough just to define a rule as:\n\n```json\n{\n\t\"rules\": [{\n\t\t\"name\": \"Custom deserialization\",\n\t\t\"methods\": [{\n\t\t\t\"name\": \"readObject\",\n\t\t\t\"visibility\": \"private\",\n\t\t\t\"parameters\" : [{\n         \"type\" : \"java.io.ObjectInputStream\"\n      }]\n\t\t}]\n\t}]\n}\n```\n\nIt will report methods with ```private``` visibility, ```readObject``` as name and a parameter of type ```java.io.ObjectOutputStream```. Parameters are an array, if more than one is specified, all of them have to match to be reported. Since we only have one rule, a report named: custom-deserialization-0.html will be created.\n\n#### Find custom serialization and deserialization\n\nIn this case, one rule with two methods have to be defined. The same one than in the previous example for deserialization, and a new one to match ```private void writeObject(ObjectOutputStream out)```. As shown in the JSON structure above, the property rules.rule.methods is an array of methods, so a rule like this can be written:\n\n```json\n{\n  \"rules\": [{\n    \"name\": \"Custom serialization and deserialization\",\n    \"methods\": [{\n      \"name\": \"readObject\",\n      \"visibility\": \"private\",\n      \"parameters\" : [{\n       \"type\" : \"java.io.ObjectInputStream\"\n      }]\n    },{\n      \"name\": \"writeObject\",\n      \"report\": \"false\",\n      \"visibility\": \"private\",\n      \"parameters\" : [{\n        \"type\" : \"java.io.ObjectOutputStream\"\n      }]\n    }]\n  }]\n}\n```\n\nThe property ```report``` was set to false to avoid reporting twice for the same rule. We are using the second method just as a condition, but reporting only ```readObject``` methods should be enough for the purpose of this rule.\n\n#### Find all method definitions\nIf a property is not defined, it will always match as true. For example, this rule would return all methods definitions:\n```json\n{\n\t\"rules\": [{\n\t\t\"name\": \"Method definitions\",\n\t\t\"methods\": [{\n\t\t}]\n\t}]\n}\n```\n\n#### Find String.equals method invocations\n\nMethod invocations can also be found. The JSON in this case would be:\n```json\n{\n\t\"rules\": [{\n\t\t\"name\": \"String equals\",\n\t\t\"invocations\": [{\n\t\t\t\"owner\": \"java.lang.String\",\n\t\t\t\"method\": {\n\t\t\t\t\"name\": \"equals\"\n\t\t\t}\n\t\t}]\n\t}]\n}\n```\nThe property ```owner``` specifies the class containing the method.\n\n#### Reflection method invoke\n\nAnother method invocation example a bit more useful than the previous one:\n```json\n{\n\t\"rules\": [{\n\t\t\"name\": \"Method invocation by reflection\",\n\t\t\"invocations\": [{\n\t\t\t\"owner\": \"java.lang.reflect.Method\",\n\t\t\t\"method\": {\n\t\t\t\t\"name\": \"invoke\"\n\t\t\t}\n\t\t}]\n\t}]\n}\n```\n\n#### Find String instantiations\n\nIt is the same than any method invocation, but the name of the method in this case, should be ```\u003cinit\u003e```.\n\n```json\n{\n  \"rules\": [{\n    \"name\" : \"String instantiation\",\n    \"invocations\" : [{\n        \"owner\" : \"java.lang.String\",\n        \"method\" : {\n          \"name\" : \"\u003cinit\u003e\"\n        }\n    }]\n  }]\n}\n```\nThis rule will find occurrences of:\n```java\n[...]\nString s = new String(\"foo\");\n[...]\n```\n\n#### Deserialization usage\nIn this example, we want to find deserialization usages (not classes defining serialization behaviors like in the previous examples). Deserialization happens when ```ObjectInputStream.readObject()``` is invoked. for example in this code snippet:\n\n```java\nObjectInputStream in = new ObjectInputStream(fileInputStream);\nObject o = in.readObject();\n```\n\nSo we need to find method invocations from ```ObjectInputStream``` named ```readObject```. But it will find a lot of false positives in a researching context, because when a class defines custom deserialization, they make an invocation to this method inside a ```private void readObject(ObjectInputStream in)``` method, and that would pollute the report too much. If we want to exclude those cases and keep only genuine deserialization, ```notFrom``` property can be used:\n\n```json\n{\n\t\"rules\": [{\n\t\t\"name\": \"Deserialization usage\",\n\t\t\"invocations\": [{\n\t\t\t\"owner\": \"java.io.ObjectInputStream\",\n\t\t\t\"method\": {\n\t\t\t\t\"name\": \"readObject\"\n\t\t\t},\n\t\t\t\"notFrom\": {\n\t\t\t\t\"name\": \"readObject\",\n\t\t\t\t\"visibility\": \"private\"\n\t\t\t}\n\t\t}]\n\t}]\n}\n```\nThis file will find ```java.io.ObjectInputStream.readObject()``` invocations if the invocation is not done inside ```private void readObject(ObjectInputStream in)``` method.\n\nA class compiled with this code will not be reported:\n\n```java\nprivate void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {\n      Object o = in.readObject();\n}\n```\nBut this one will be reported:\n\n```java\npublic Object deserializeObject(ObjectInputStream in) throws IOException, ClassNotFoundException {\n      Object o = in.readObject();\n      return o;\n}\n```\n\nThe property ```from``` can be set in invocations in exactly the same way than ```notFrom```, but the result will be the opposite: it will only match if the invocation is made from the defined method.\n\n#### Java servlets\n\nThe property ```superClass```  can be used in this case. If we want to find all classes extending ```javax.servlet.http.HttpServlet```, a rule can be:\n\n```json\n{\n  \"rules\": [{\n    \"name\": \"Java servlets\",\n    \"superClass\" : \"javax.servlet.http.HttpServlet\"\n  }]\n}\n\n```\n\n#### Interface implementations\n\nA rule can be written to find classes implementing an array of interfaces. if more than one interface is defined in the rule, the class has to implement all of them to be reported. If we want to find classes implementing ```javax.net.ssl.X509TrustManager```, the rule would be:\n\n```json\n{\n  \"rules\": [{\n    \"name\": \"X509TrustManager implementations\",\n    \"interfaces\" : [\"javax.net.ssl.X509TrustManager\"]\n  }]\n}\n```\n\nPlease note that ```interfaces``` is an *array*, so make sure you add the strings between square brackets, e.g: ```[\"interface1\", \"interface2\", ...]```.\n\n#### Find Spring endpoints\n\nAnnotations are also supported. Multiple annotations properties can be defined in a rule (finding class annotations), in methods o variables (parameters or local variables). If all of them are found in the analyzed class, it will be reported.\nFor example, if we want to find Spring endpoints, we would search for classes or methods annotated with ```org.springframework.web.bind.annotation.RequestMapping```. So, the rule can be:\n\n```json\n{\n  \"rules\": [{\n    \"name\": \"Spring endpoint - class annotation\",\n    \"annotations\" : [{\n      \"type\" : \"org.springframework.web.bind.annotation.RequestMapping\"\n    }]\n  },\n  {\n     \"name\": \"Spring endpoint - method annotation\",\n     \"methods\" : [{\n        \"annotations\" : [{\n          \"type\" : \"org.springframework.web.bind.annotation.RequestMapping\"\n        }]\n      }]\n  }]\n}\n```\n\n#### Find fields\n\nThe property ```rule.fields``` can be used to find class fields. If we want to find private String fields with password names, a rule like this one could be used:\n\n```json\n{\n  \"rules\": [{\n    \"name\" : \"Password fields\",\n    \"fields\" : [\n      {\n        \"visibility\" : \"private\",\n        \"type\" : \"java.lang.String\",\n        \"nameRegex\" : \"(password|pass|psswd|passwd)\"\n      }\n    ]\n  }]\n}\n```\n\n#### Find variables\n\nTo find variables, ```rule.variables``` can be used. This property will report local variables and method arguments variables.\nIf we want to find all variables of type ```javax.servlet.http.Part```, a rule could be:\n\n```json\n{\n  \"rules\": [{\n    \"name\" : \"Servlet upload file\",\n    \"methods\" : [{\n      \"variables\" : [{\n          \"type\" : \"javax.servlet.http.Part\"\n      }]\n    }]\n  }]\n}\n```\n\n#### Define multiple rules\nMultiple rules can be defined in the same JSON file. They will be processed and reported separately and they will not affect each other. We can combine some of the previous examples rules:\n\n```json\n{\n\t\"rules\": [{\n\t\t\"name\": \"Custom deserialization\",\n\t\t\"methods\": [{\n\t\t\t\"name\": \"readObject\",\n\t\t\t\"visibility\": \"private\",\n\t\t\t\"parameters\": [{\n        \"type\" : \"java.io.ObjectInputStream\"\n      }]\n\t\t}]\n\t},{\n\t\t\"name\": \"Method invocation by reflection\",\n\t\t\"invocations\": [{\n\t\t\t\"owner\": \"java.lang.reflect.Method\",\n\t\t\t\"method\": {\n\t\t\t\t\"name\": \"invoke\"\n\t\t\t}\n\t\t}]\n\t}]\n}\n```\n\nHere, we have two rules (\"Custom deserialization\" and \"Method invocation by reflection\"). They will be processed as if you do it in two separated executions. And a report per rule will be generated. If the rules have the same name, they will be reported in the same file.\n\n## Custom Java rules\n\nThe project can be downloaded and built to add more complex custom rules in Java code that are not covered by the JSON format. There are already three examples under the package ```net.nandgr.cba.visitor.checks```. Those are ```CustomDeserializationCheck, DeserializationCheck and InvokeMethodCheck```. You can create your own rules by extending ```net.nandgr.cba.custom.visitor.base.CustomAbstractClassVisitor```.\n\n## Reports\n\nAs mentioned above, the reports are created by default under ```report``` folder. Every rule will have a separate file unless they have the same name.\nIf the report is too big, you can split it using the ```-i,--items-report \u003cmaxItems\u003e``` parameter, each of them will hold the argument specified or less (if it is the last one).\nEvery reported item, specifies the jar where it is found, the class name and the method name (if it is relevant). It also shows the decompiled version of the class to ease a quick visual check.\nExample of how the items are shown for a rule to find ```java.io.File``` instantiations:\n\n![Report example](images/report_image.png)\n\n### Call graph\n\nWhen searching for security bugs it is very useful to have a call graph. At the moment, a simple [DOT](https://en.wikipedia.org/wiki/DOT_(graph_description_language)) compatible file is created under the ```report``` directory.\nThe graph contains all the possible flows where the found issues can be invoked from. For example, if a rule to find deserialization is used,\na graph containing all possible paths leading to the method that calls the deserialization will be generated.\n\nThe file is ```call-graph.dot``` and it would look like this (this is an extremely simple example):\n\n```\ngraph callGraph {\n\"demo.callgraph.Class1:method1\" -- \"demo.callgraph.Class2:method2\"\n\"demo.callgraph.Class3:method3\" -- \"demo.callgraph.Class2:method2\"\n}\n```\n\nTo display it in a visual way, ```DOT``` can be used (or any compatible software). For example, to convert the file to ```svg```:\n\n```\ndot -Tsvg call-graph.dot -o call-graph.svg\n```\n\nThis is done automatically by default if DOT is found in the system PATH. If not, ```DOT``` can be installed in Debian based systems using ```sudo apt-get install graphviz```.\n\nIt will create a SVG file named ```call-graph.svg``` that can be converted into PNG or visualized using programs like ```inkscape``` or just ```firefox```.\n\nA very simple example of the above file call-graph.dot, would be:\n\n![Graph example](images/graph.png)\n\nThere are some limitations, like for example, if the searched item is in a ```java.lang.Runnable.run()``` or similar method, it will not find where the thread is executed from.\nAlso, the graph is cleaning cycles to avoid ```StackOverflowError```s, it is made in a bit of conservative way so the memory of the system is not drained during an analysis of a large directory.\n\nMore options will be added in future versions.\n\n## Command line examples\n\n#### Run an analysis using a JSON file\n```\njava -jar cba-cli-\u003cversion\u003e.jar -a /path/with/jars -f /path/with/json/file/rules.json\n```\n#### Run an analysis using a Java custom rule\nTo use custom java rules, class names have to be specified as arguments of ```-c```.\n```\njava -jar cba-cli-\u003cversion\u003e.jar -a /path/with/jars -c DeserializationCheck\n```\nAccepts a space separated list, so multiple custom rules can be defined (each of the rules will create a separate report):\n```\njava -jar cba-cli-\u003cversion\u003e.jar -a /path/with/jars -c DeserializationCheck InvokeMethodCheck CustomDeserializationCheck YourCustomRule\n```\n#### Combine JSON and custom Java rules\n```\njava -jar cba-cli-\u003cversion\u003e.jar -a /path/with/jars -f /path/with/json/file/rules.json -c YourCustomRule1 YourCustomRule2\n```\n\n#### Increase verbosity\n\nTo find errors, verbosity can be increased.\nDebug level:\n```\njava -jar cba-cli-\u003cversion\u003e.jar -a /path/with/jars -c YourCustomRule1 -v\n```\nTrace level:\n```\njava -jar cba-cli-\u003cversion\u003e.jar -a /path/with/jars -c YourCustomRule1 -vv\n```\n\n## Analyze Android APKs\n\nAt the moment, the APK has to be converted to JAR first to be analyzed.\n\n* Download dex2jar : https://github.com/pxb1988/dex2jar\n* Convert DEX to JAR\n    * ```d2j-dex2jar.sh -f -o app_to_analyze.jar app_to_analyze.apk```\n* Run cba-cli.jar as usual passing as ```-a``` parameter the directory containing the converted jar file.\n\n## Build and run the project\n\nThere is already an executable jar file under ```bin``` directory at: [https://github.com/fergarrui/custom-bytecode-analyzer/blob/master/bin/cba-cli-0.1-SNAPSHOT.jar](https://github.com/fergarrui/custom-bytecode-analyzer/blob/master/bin/cba-cli-0.1-SNAPSHOT.jar) . If you want to do modifications or add custom rules, the project can be built doing:\n\n```\ngit clone https://github.com/fergarrui/custom-bytecode-analyzer.git\ncd custom-bytecode-analyzer\nmvn clean package\n```\nTwo jars will be generated under ```target``` folder. ```cba-cli-\u003cversion\u003e.jar``` contains all dependencies and is executable. Can be run using ```java -jar cba-cli-\u003cversion\u003e.jar```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffergarrui%2Fcustom-bytecode-analyzer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffergarrui%2Fcustom-bytecode-analyzer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffergarrui%2Fcustom-bytecode-analyzer/lists"}