A lightweight Java gadget chain detector based on SootUp.
Disclaimer: This software (androChain) is provided for educational, research, and authorized security testing purposes only.
@misc{kreyssig2025deserializationgadgetchainspathological,
title={Deserialization Gadget Chains are not a Pathological Problem in Android:an In-Depth Study of Java Gadget Chains in AOSP},
author={Bruno Kreyssig and Timothée Riom and Sabine Houy and Alexandre Bartel and Patrick McDaniel},
year={2025},
eprint={2502.08447},
archivePrefix={arXiv},
primaryClass={cs.CR},
url={https://arxiv.org/abs/2502.08447},
}# build
mvn clean package
# run
java -jar androChain.jar --serializableCheck --from all_serializable --jar <target> --sinkList mysinkList.txt --output result.txtWhen using the --android flag make sure to have a directory named android_sdk containing a built libcore.jar and framework.jar next to the androChain.jar.
We package a bunch of ready to use sink lists in the resources directory
usage: Main [-h]
[-f {readObject,readResolve,parcelable,toString,hashCode,equals,compareTo,invoke,readNoData,finalize,clinit,all,all_serializable}]
[-d DEPTH] [-c CONCURRENCY] [-t TO] [-j [JAR [JAR ...]]]
[--dir DIR] [--sinkList [SINKLIST [SINKLIST ...]]]
[-i IGNORELIST] [--android] [--parcelableCheck]
[--serializableCheck] [-o OUTPUT]
Find arbitrary chains from source to sink
named arguments:
-h, --help show this help message and exit
-f {readObject,readResolve,parcelable,toString,hashCode,equals,compareTo,invoke,readNoData,finalize,clinit,all,all_serializable}, --from {readObject,readResolve,parcelable,toString,hashCode,equals,compareTo,invoke,readNoData,finalize,clinit,all,all_serializable}
entrypoint (default: all)
-d DEPTH, --depth DEPTH
Depth at which to quit searching for gadget
chains. (default: 20)
-c CONCURRENCY, --concurrency CONCURRENCY
Amount of cores to use in Java's ForkJoin Pool.
If not supplied, runs sequentially (default: 0)
-t TO, --to TO single sink gadget to search for. Contains
prefactored options: methodInvoke, forName,
toString, hashCode, equals, compareTo, mapSize,
mapPut, mapGet
-j [JAR [JAR ...]], --jar [JAR [JAR ...]]
A single jar file to add to the analysis domain.
(default: [])
--dir DIR Adds all Jar files in the selected directory to
the analysis domain. (default: )
--sinkList [SINKLIST [SINKLIST ...]]
List of sink methods. We have precompiled sink
lists in the tool ([android, io, critical, gi,
tabby, crystallizer, jdd, serde, serianalyzer,
susi]). Else you can add any number of paths
seperated by space (default: [])
-i IGNORELIST, --ignoreList IGNORELIST
List of method signatures to ignore during gadget
chain search (default: )
--android Use this flag to load the android sdk (libcore
and framework) instead of the java class library
into the analysis domain. (default: false)
--parcelableCheck Require gadgets in virtual call sites to
implement the parcelable interface (default:
false)
--serializableCheck Require gadgets in virtual call sites to
implement the serializable interface (default:
false)
-o OUTPUT, --output OUTPUT
(default: )
For a custom sinkList with the --sinkList option, create a txt file and add method signatures according to the following template:
[Partial]
<packageName>.<className>.<methodName>
[Partial_SubClasses]
<packageName>.<className>.<methodName>
[Full]
<packageName>.<className>.<methodName> <arg1>,<arg2>
[Full_SubClasses]
<packageName>.<className>.<methodName> <arg1>,<arg2>
Using the four categories [Partial], [Partial_SubClasses], [Full], [Full_SubClasses] is optional. By default if no header [] is present in the file by default the [Full] category is assumed. Below are the purposes of the categories:
- Partial: considers all methods with the same method name in this specific class. E.g., the definition:
java.lang.Class.forNamewill result in the two sink method signatures:java.lang.Class.forName java.lang.Stringandjava.lang.Class.forName java.lang.String,boolean,java.lang.ClassLoader - Full: in contrast uses precise method signature definitions with specified args (using no args means there are no method parameters in the signature. E.g., the two sink method lists below are equivalent:
[Partial]
java.lang.Class.forName
[Full]
java.lang.Class.forName java.lang.String
java.lang.Class.forName java.lang.String,boolean,java.lang.ClassLoader
Then, the SubClasses option states that both the defined signature aswell as any implementations in subclasses shall be considered sink methods. E.g., [Partial_SubClasses] and java.io.OutputStream.write will in adding java.io.FileOutputStream.write byte[], java.io.FileOutputStream.write byte[],int,int, ObjectOutputStream.write byte[], etc.
An ignoreList ensures that certain gadgets will not be further analyzed in a run (i.e., because they are known to be false positives). Use an ignoreList with the --ignoreList option and a corresponding txt file. There are three ways to define ignoreList entries:
- By Method Signature:
<packageName>.<className>.<methodName> <arg1>,<arg2>- independent of the caller method this signature will never be visited - By Call Edge:
<packageName>.<className>.<methodName> <arg1>,<arg2> -> <packageName>.<className>.<methodName> <arg1>,<arg2>- does not visit the second method signature if the caller is the first method signature
