All examples in this tutorial interact with the GraphQL API hosted at https://fmd.localhost/graphql/. The interactive GraphQL explorer allows you to inspect the schema, browse documentation, and build queries and mutations directly in your browser.
The API is only accessible when the FirmwareDroid stack is up and running. Before executing these queries, ensure your containers are running via
docker compose up -d(ordocker compose -f docker-compose-release.yml up -d).
Authentication
Most API endpoints require superuser authentication. If you are already logged in to Django administration or the web interface at https://fmd.localhost/, your browser session cookie authenticates your requests in the GraphQL explorer automatically.
Alternatively, you can authenticate programmatically using tokenAuth:
1
2
3
4
5
6
query AuthenticateUser {
tokenAuth(username: "YOUR_DJANGO_SUPERUSER_USERNAME", password: "YOUR_DJANGO_SUPERUSER_PASSWORD") {
token
payload
}
}
Include the returned token in the HTTP Authorization header for subsequent requests:
1
Authorization: JWT <YOUR_TOKEN>
Generated administrator credentials can be retrieved from
docker compose logs initor copied from the container viadocker compose cp init:/config/secrets/generated-secrets.txt ..
Importing Android Firmware
After starting FMD, you can import Android firmware archives (.zip, .tar, .tgz, .7z, etc.) for extraction and inventorying.
1. Place firmware archives in the import directory
Persistent data is stored in the blob_storage hierarchy. The initial storage pool is located in 00_file_storage:
1
blob_storage/00_file_storage/<storage_uuid>/firmware_import/
Copy your firmware archive(s) into this firmware_import directory.
2. Trigger the extraction job
Open https://fmd.localhost/graphql/ and execute the createFirmwareExtractorJob mutation:
1
2
3
4
5
6
7
8
9
mutation StartFirmwareImport {
createFirmwareExtractorJob(
createFuzzyHashes: false
queueName: "extractor"
storageIndex: 0
) {
jobId
}
}
createFuzzyHashes: Set totrueto compute SSDeep/TLSH fuzzy hashes for all extracted files.queueName: The target queue (defaults to"extractor").storageIndex: Index of the storage partition to use (defaults to0).
This triggers the extractor-worker-1 container to unpack the archive, extract filesystem images (such as system, vendor, product, apex), parse build.prop, and inventory all contained APKs.
3. Monitor extraction progress
Firmware extraction can take several minutes depending on the archive size and archive compression. Monitor the worker status using any of the following methods:
- RQ Job Monitor: View live queue activity at https://fmd.localhost/django-rq/.
- Container Logs: Stream logs from the extractor worker:
1 2 3
docker compose logs -f extractor-worker-1 # or when using release images: docker compose -f docker-compose-release.yml logs -f extractor-worker-1
- GraphQL Job Query: Inspect the specific job using its returned
jobId:1 2 3 4 5 6 7 8 9 10 11
query CheckExtractorJob { rqJob(jobId: "YOUR_JOB_ID", queueName: "extractor") { id status startedAt endedAt isFinished isFailed excInfo } }
4. Direct database inspection (optional)
You can connect directly to MongoDB using any GUI client (such as Studio 3T, Compass, or mongosh).
Retrieve the generated MongoDB credentials:
1
2
docker compose cp init:/config/secrets/generated-secrets.txt .
cat generated-secrets.txt
Use the following connection settings:
- Host / Port:
127.0.0.1:27017 - Database:
FirmwareDroid - Authentication Database:
admin - Authentication Mechanism:
SCRAM-SHA-256 - Username / Password: Use the
Mongo app usernameorMongo root usernamefromgenerated-secrets.txt.
Successfully imported firmware records are stored in the android_firmware collection, and extracted applications are recorded in android_app.
5. Storage output layout
Extracted files and processed archives are organized within the blob store:
- Extracted APKs:
blob_storage/00_file_storage/<storage_uuid>/android_app_store/<firmware_hash>/<partition_name>/ - Stored Firmware:
blob_storage/00_file_storage/<storage_uuid>/firmware_store/<android_version>/<firmware_hash>/ - Failed Imports:
blob_storage/00_file_storage/<storage_uuid>/firmware_import_failed/
If an extraction fails, check the logs of extractor-worker-1 for details.
6. Query imported firmware data
Once extraction completes, list all available firmware record IDs:
1
2
3
query GetAndroidFirmwareIds {
android_firmware_id_list
}
Retrieve detailed metadata for specific firmware samples using their IDs:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
query GetAndroidFirmwareDetails {
android_firmware_list(objectIdList: ["YOUR_FIRMWARE_ID"]) {
id
filename
originalFilename
md5
sha1
sha256
fileSizeBytes
versionDetected
osVendor
relativeStorePath
absoluteStorePath
indexedDate
hasFileIndex
hasFuzzyHashIndex
}
}
Fetch the list of application IDs discovered inside the firmware:
1
2
3
query GetAppIdsForFirmware {
android_app_id_list(objectIdList: ["YOUR_FIRMWARE_ID"])
}
Query comprehensive details for the extracted apps:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
query GetAndroidApps {
android_app_list(objectIdList: ["YOUR_APP_ID"]) {
id
pk
filename
packagename
md5
sha1
sha256
fileSizeBytes
relativeFirmwarePath
relativeStorePath
absoluteStorePath
indexedDate
}
}
Static Analysis on Android Apps
Once firmware has been extracted and APKs are cataloged, you can schedule static analysis jobs across individual apps or batches of applications.
1. Check available static analyzers
Query the backend for all currently supported static analysis modules:
1
2
3
query GetAvailableScanners {
scanner_module_name_list
}
Supported modules include:
ANDROGUARDANDROWARNAPKIDAPKLEAKSAPKSCANEXODUSFLOWDROIDMANIFESTMOBSFQARKQUARKENGINESUPERTRUESEEINGTRUFFLEHOGVIRUSTOTAL
2. Schedule a static analysis job
Dispatch a scan job using the createApkScanJob mutation. Provide the analyzer module name and the list of application IDs to analyze:
1
2
3
4
5
6
7
8
9
mutation RunAndroguardAnalysis {
createApkScanJob(
moduleName: "ANDROGUARD"
objectIdList: ["YOUR_APP_ID_1", "YOUR_APP_ID_2"]
queueName: "scanner"
) {
jobIdList
}
}
moduleName: The analyzer to run (e.g."ANDROGUARD").objectIdList: Array ofAndroidAppobject IDs to analyze.queueName: The target queue (defaults to"scanner").
3. Monitor scanner workers
The apk_scanner-worker-1 container picks up tasks from the "scanner" queue. Follow its logs in real time:
1
2
3
docker compose logs -f apk_scanner-worker-1
# or when using release images:
docker compose -f docker-compose-release.yml logs -f apk_scanner-worker-1
You can also monitor active and finished scanner jobs at https://fmd.localhost/django-rq/.
4. Retrieve analysis reports
Scan results are stored in scanner-specific MongoDB collections (e.g. androguard_report) and linked to the corresponding AndroidApp record.
To fetch AndroGuard reports for scanned apps:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
query GetAndroGuardReports {
androguard_report_list(objectIdList: ["YOUR_REPORT_ID"]) {
id
appName
packagename
androidVersionCode
androidVersionName
minSdkVersion
targetSdkVersion
maxSdkVersion
effectiveTargetVersion
mainActivity
isValidApk
isMultidex
isSignedV1
isSignedV2
isSignedV3
permissionDetails
permissionsDeclaredDetails
reportDate
scannerName
scannerVersion
}
}