add androzoo support

This commit is contained in:
Jean-Marie Mineau 2024-10-17 14:57:08 +02:00
parent 43eef100f1
commit 01abb1879d
6 changed files with 465 additions and 206 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
__pycache__

View file

@ -1,214 +1,84 @@
import zipfile import zipfile
import io import io
from dataclasses import dataclass, asdict from argparse import ArgumentParser
from enum import IntEnum from pathlib import Path
from getpass import getpass
import androguard.core.dex # type: ignore from .androzoo import download_apk
from androguard.core.dex import DEX # type: ignore from .analysis import analyze
# loguru -> logging framework used by androgard
from loguru import logger # type: ignore
from .platform_classes import (
PLATFORM_32_CLASSES,
SDK_32_CLASSES,
PLATFORM_33_CLASSES,
SDK_33_CLASSES,
PLATFORM_34_CLASSES,
SDK_34_CLASSES,
)
# Remove Androguard logs
logger.remove()
# Patch Androguard
class PatchedDomapiApiFlag(IntEnum):
NONE = 0
CORE_PLATFORM_API = 1
TEST_API = 2
UNKN_3 = 3
UNKN_4 = 4
UNKN_5 = 5
UNKN_6 = 6
UNKN_7 = 7
UNKN_8 = 8
UNKN_9 = 9
INKN_10 = 10
class PatchedRestrictionApiFlag(IntEnum):
WHITELIST = 0
GREYLIST = 1
BLACKLIST = 2
GREYLIST_MAX_O = 3
GREYLIST_MAX_P = 4
GREYLIST_MAX_Q = 5
GREYLIST_MAX_R = 6
GREYLIST_MAX_7 = 7
GREYLIST_MAX_8 = 8
GREYLIST_MAX_9 = 9
GREYLIST_MAX_10 = 10
androguard.core.dex.HiddenApiClassDataItem.DomapiApiFlag = PatchedDomapiApiFlag
androguard.core.dex.HiddenApiClassDataItem.RestrictionApiFlag = (
PatchedRestrictionApiFlag
)
@dataclass
class Entry:
# sha256: str
nb_duplicate_classes: int
nb_platform_32_classes: int
nb_platform_non_sdk_32_classes: int
nb_sdk_32_classes: int
nb_platform_33_classes: int
nb_platform_non_sdk_33_classes: int
nb_sdk_33_classes: int
nb_platform_34_classes: int
nb_platform_non_sdk_34_classes: int
nb_sdk_34_classes: int
has_classes0_dex: bool
has_classes1_dex: bool
has_classes0X_dex: bool
has_classes_dex_over_10: bool
has_non_numeric_classes_dex: bool
has_non_consecutive_classes_dex: bool
@dataclass
class PlatformClassesData:
nb_duplicate_classes: int
nb_platform_32_classes: int
nb_platform_non_sdk_32_classes: int
nb_sdk_32_classes: int
nb_platform_33_classes: int
nb_platform_non_sdk_33_classes: int
nb_sdk_33_classes: int
nb_platform_34_classes: int
nb_platform_non_sdk_34_classes: int
nb_sdk_34_classes: int
def scan_classes(apk: zipfile.ZipFile, file_names: set[str]) -> PlatformClassesData:
all_classes = set()
duplicated_classes = set()
platform_32_classes = set()
sdk_32_classes = set()
platform_non_sdk_32_classes = set()
platform_33_classes = set()
sdk_33_classes = set()
platform_non_sdk_33_classes = set()
platform_34_classes = set()
sdk_34_classes = set()
platform_non_sdk_34_classes = set()
for name in file_names:
with apk.open(name) as dex_f:
dex = DEX(dex_f.read())
for clazz in map(lambda c: c.name, dex.get_classes()):
if clazz in all_classes:
duplicated_classes.add(clazz)
if clazz in PLATFORM_32_CLASSES:
platform_32_classes.add(clazz)
if clazz in SDK_32_CLASSES:
sdk_32_classes.add(clazz)
if clazz in PLATFORM_32_CLASSES and clazz not in SDK_32_CLASSES:
platform_non_sdk_32_classes.add(clazz)
if clazz in PLATFORM_33_CLASSES:
platform_33_classes.add(clazz)
if clazz in SDK_33_CLASSES:
sdk_33_classes.add(clazz)
if clazz in PLATFORM_33_CLASSES and clazz not in SDK_33_CLASSES:
platform_non_sdk_33_classes.add(clazz)
if clazz in PLATFORM_34_CLASSES:
platform_34_classes.add(clazz)
if clazz in SDK_34_CLASSES:
sdk_34_classes.add(clazz)
if clazz in PLATFORM_34_CLASSES and clazz not in SDK_34_CLASSES:
platform_non_sdk_34_classes.add(clazz)
all_classes.add(clazz)
return PlatformClassesData(
nb_duplicate_classes=len(duplicated_classes),
nb_platform_32_classes=len(platform_32_classes),
nb_platform_non_sdk_32_classes=len(platform_non_sdk_32_classes),
nb_sdk_32_classes=len(sdk_32_classes),
nb_platform_33_classes=len(platform_33_classes),
nb_platform_non_sdk_33_classes=len(platform_non_sdk_33_classes),
nb_sdk_33_classes=len(sdk_33_classes),
nb_platform_34_classes=len(platform_34_classes),
nb_platform_non_sdk_34_classes=len(platform_non_sdk_34_classes),
nb_sdk_34_classes=len(sdk_34_classes),
)
def analyze(apk: zipfile.ZipFile) -> Entry:
classes_dex = set(
filter(
lambda name: name.startswith("classes") and name.endswith(".dex"),
apk.namelist(),
)
)
dex_numbers = list(
map(
int,
filter(
lambda string: string not in ("", "1")
and string.isnumeric()
and string[0] != "0",
map(
lambda name: name.removeprefix("classes").removesuffix(".dex"),
classes_dex,
),
),
)
)
dex_numbers.sort()
has_non_numeric_classes_dex = False
for name in classes_dex:
if name == "classes.dex":
continue
if not name.removeprefix("classes").removesuffix(".dex").isnumeric():
has_non_numeric_classes_dex = True
has_non_consecutive_classes_dex = False
if "classes.dex" in classes_dex and dex_numbers:
has_non_consecutive_classes_dex = True
last_number = 1
for i in range(len(dex_numbers)):
if dex_numbers[i] == 0 or dex_numbers[i] == 1:
continue
# the list is sorted
if dex_numbers[i] != last_number + 1:
has_non_consecutive_classes_dex = True
break
platform_classes_data = scan_classes(apk, classes_dex)
return Entry(
**asdict(platform_classes_data),
has_classes0_dex="classes0.dex" in classes_dex,
has_classes1_dex="classes1.dex" in classes_dex,
has_classes0X_dex=any(
map(lambda name: name.startswith("classes0"), classes_dex)
),
has_classes_dex_over_10=any(map(lambda x: x >= 10, dex_numbers)),
has_non_numeric_classes_dex=has_non_numeric_classes_dex,
has_non_consecutive_classes_dex=has_non_consecutive_classes_dex,
)
def main(): def main():
import sys
import pprint import pprint
with open(sys.argv[1], "rb") as file: parser = ArgumentParser(
apk = file.read() prog="Android Class Shadowing Scanner",
description="Scan application for patern that could be reveling of class shadowing obfuscation",
)
apk_parser = parser.add_mutually_exclusive_group(required=True)
apk_parser.add_argument(
"--sha256", help="The sha256 hash of the APK to download", type=str
)
apk_parser.add_argument("--apk", help="The APK to use", type=Path)
key_parser = parser.add_mutually_exclusive_group(required=False)
key_parser.add_argument(
"--api-key-file",
help="The path to a file containing the Androzoo API key",
type=Path,
)
key_parser.add_argument(
"--api-key", help="The Androzoo API key (Usage NOT recommanded)", type=str
)
SECRET_STORAGE_IMPORTED = False
try:
import secretstorage
with zipfile.ZipFile(io.BytesIO(apk)) as apk: SECRET_STORAGE_IMPORTED = True
entry = analyze(apk)
pprint.pprint(entry) key_parser.add_argument(
"--api-key-keyring-id",
help="The ID of the Androzoo API key in the secret service storage",
type=str,
)
except ModuleNotFoundError:
pass
args = parser.parse_args()
if args.apk:
with args.apk.open("rb") as file:
with zipfile.ZipFile(file) as apk:
entry = analyze(apk)
pprint.pprint(entry)
exit()
sha256s = []
if args.sha256:
sha256s.append(args.sha256)
api_key = ""
if args.api_key:
api_key = args.api_key
if args.api_key_file:
with args.api_key_file.open("r") as file:
api_key = file.read().strip()
if SECRET_STORAGE_IMPORTED and not api_key:
if args.api_key_keyring_id:
key_id = args.api_key_keyring_id
else:
key_id = "androzoo"
try:
with secretstorage.dbus_init() as connection:
collection = secretstorage.get_default_collection(connection)
item = next(collection.search_items({"Title": key_id}))
item.unlock()
api_key = item.get_secret().decode("utf-8").strip()
except:
pass
if not api_key:
api_key = getpass(prompt="Androzoo API key: ").strip()
for sha256 in sha256s:
with zipfile.ZipFile(io.BytesIO(download_apk(sha256, api_key))) as apk:
entry = analyze(apk, sha256)
pprint.pprint(entry)

View file

@ -0,0 +1,202 @@
import zipfile
import io
from dataclasses import dataclass, asdict
from enum import IntEnum
import androguard.core.dex # type: ignore
from androguard.core.dex import DEX # type: ignore
# loguru -> logging framework used by androgard
from loguru import logger # type: ignore
from .platform_classes import (
PLATFORM_32_CLASSES,
SDK_32_CLASSES,
PLATFORM_33_CLASSES,
SDK_33_CLASSES,
PLATFORM_34_CLASSES,
SDK_34_CLASSES,
)
# Remove Androguard logs
logger.remove()
# Patch Androguard
class PatchedDomapiApiFlag(IntEnum):
NONE = 0
CORE_PLATFORM_API = 1
TEST_API = 2
UNKN_3 = 3
UNKN_4 = 4
UNKN_5 = 5
UNKN_6 = 6
UNKN_7 = 7
UNKN_8 = 8
UNKN_9 = 9
INKN_10 = 10
class PatchedRestrictionApiFlag(IntEnum):
WHITELIST = 0
GREYLIST = 1
BLACKLIST = 2
GREYLIST_MAX_O = 3
GREYLIST_MAX_P = 4
GREYLIST_MAX_Q = 5
GREYLIST_MAX_R = 6
GREYLIST_MAX_7 = 7
GREYLIST_MAX_8 = 8
GREYLIST_MAX_9 = 9
GREYLIST_MAX_10 = 10
androguard.core.dex.HiddenApiClassDataItem.DomapiApiFlag = PatchedDomapiApiFlag
androguard.core.dex.HiddenApiClassDataItem.RestrictionApiFlag = (
PatchedRestrictionApiFlag
)
@dataclass
class ApkData:
sha256: str
nb_duplicate_classes: int
nb_platform_32_classes: int
nb_platform_non_sdk_32_classes: int
nb_sdk_32_classes: int
nb_platform_33_classes: int
nb_platform_non_sdk_33_classes: int
nb_sdk_33_classes: int
nb_platform_34_classes: int
nb_platform_non_sdk_34_classes: int
nb_sdk_34_classes: int
has_classes0_dex: bool
has_classes1_dex: bool
has_classes0X_dex: bool
has_classes_dex_over_10: bool
has_non_numeric_classes_dex: bool
has_non_consecutive_classes_dex: bool
@dataclass
class PlatformClassesData:
nb_duplicate_classes: int
nb_platform_32_classes: int
nb_platform_non_sdk_32_classes: int
nb_sdk_32_classes: int
nb_platform_33_classes: int
nb_platform_non_sdk_33_classes: int
nb_sdk_33_classes: int
nb_platform_34_classes: int
nb_platform_non_sdk_34_classes: int
nb_sdk_34_classes: int
def scan_classes(apk: zipfile.ZipFile, file_names: set[str]) -> PlatformClassesData:
all_classes = set()
duplicated_classes = set()
platform_32_classes = set()
sdk_32_classes = set()
platform_non_sdk_32_classes = set()
platform_33_classes = set()
sdk_33_classes = set()
platform_non_sdk_33_classes = set()
platform_34_classes = set()
sdk_34_classes = set()
platform_non_sdk_34_classes = set()
for name in file_names:
with apk.open(name) as dex_f:
dex = DEX(dex_f.read())
for clazz in map(lambda c: c.name, dex.get_classes()):
if clazz in all_classes:
duplicated_classes.add(clazz)
if clazz in PLATFORM_32_CLASSES:
platform_32_classes.add(clazz)
if clazz in SDK_32_CLASSES:
sdk_32_classes.add(clazz)
if clazz in PLATFORM_32_CLASSES and clazz not in SDK_32_CLASSES:
platform_non_sdk_32_classes.add(clazz)
if clazz in PLATFORM_33_CLASSES:
platform_33_classes.add(clazz)
if clazz in SDK_33_CLASSES:
sdk_33_classes.add(clazz)
if clazz in PLATFORM_33_CLASSES and clazz not in SDK_33_CLASSES:
platform_non_sdk_33_classes.add(clazz)
if clazz in PLATFORM_34_CLASSES:
platform_34_classes.add(clazz)
if clazz in SDK_34_CLASSES:
sdk_34_classes.add(clazz)
if clazz in PLATFORM_34_CLASSES and clazz not in SDK_34_CLASSES:
platform_non_sdk_34_classes.add(clazz)
all_classes.add(clazz)
return PlatformClassesData(
nb_duplicate_classes=len(duplicated_classes),
nb_platform_32_classes=len(platform_32_classes),
nb_platform_non_sdk_32_classes=len(platform_non_sdk_32_classes),
nb_sdk_32_classes=len(sdk_32_classes),
nb_platform_33_classes=len(platform_33_classes),
nb_platform_non_sdk_33_classes=len(platform_non_sdk_33_classes),
nb_sdk_33_classes=len(sdk_33_classes),
nb_platform_34_classes=len(platform_34_classes),
nb_platform_non_sdk_34_classes=len(platform_non_sdk_34_classes),
nb_sdk_34_classes=len(sdk_34_classes),
)
def analyze(apk: zipfile.ZipFile, sha256: str) -> ApkData:
classes_dex = set(
filter(
lambda name: name.startswith("classes") and name.endswith(".dex"),
apk.namelist(),
)
)
dex_numbers = list(
map(
int,
filter(
lambda string: string not in ("", "1")
and string.isnumeric()
and string[0] != "0",
map(
lambda name: name.removeprefix("classes").removesuffix(".dex"),
classes_dex,
),
),
)
)
dex_numbers.sort()
has_non_numeric_classes_dex = False
for name in classes_dex:
if name == "classes.dex":
continue
if not name.removeprefix("classes").removesuffix(".dex").isnumeric():
has_non_numeric_classes_dex = True
has_non_consecutive_classes_dex = False
if "classes.dex" in classes_dex and dex_numbers:
has_non_consecutive_classes_dex = True
last_number = 1
for i in range(len(dex_numbers)):
if dex_numbers[i] == 0 or dex_numbers[i] == 1:
continue
# the list is sorted
if dex_numbers[i] != last_number + 1:
has_non_consecutive_classes_dex = True
break
platform_classes_data = scan_classes(apk, classes_dex)
return ApkData(
sha256=sha256,
**asdict(platform_classes_data),
has_classes0_dex="classes0.dex" in classes_dex,
has_classes1_dex="classes1.dex" in classes_dex,
has_classes0X_dex=any(
map(lambda name: name.startswith("classes0"), classes_dex)
),
has_classes_dex_over_10=any(map(lambda x: x >= 10, dex_numbers)),
has_non_numeric_classes_dex=has_non_numeric_classes_dex,
has_non_consecutive_classes_dex=has_non_consecutive_classes_dex,
)

View file

@ -0,0 +1,10 @@
import http.client
def download_apk(sha256: str, api_key: str) -> bytes:
conn = http.client.HTTPSConnection("androzoo.uni.lu")
conn.request("GET", f"/api/download?apikey={api_key}&sha256={sha256}")
resp = conn.getresponse()
if resp.status != 200:
raise RuntimeError(f"Failled to download APK {sha256}: {resp.reason}")
return resp.read()

174
poetry.lock generated
View file

@ -102,6 +102,85 @@ files = [
[package.extras] [package.extras]
dev = ["mypy", "wheel"] dev = ["mypy", "wheel"]
[[package]]
name = "cffi"
version = "1.17.1"
description = "Foreign Function Interface for Python calling C code."
optional = true
python-versions = ">=3.8"
files = [
{file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"},
{file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"},
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"},
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"},
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"},
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"},
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"},
{file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"},
{file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"},
{file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"},
{file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"},
{file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"},
{file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"},
{file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"},
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"},
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"},
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"},
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"},
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"},
{file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"},
{file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"},
{file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"},
{file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"},
{file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"},
{file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"},
{file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"},
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"},
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"},
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"},
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"},
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"},
{file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"},
{file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"},
{file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"},
{file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"},
{file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"},
{file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"},
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"},
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"},
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"},
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"},
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"},
{file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"},
{file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"},
{file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"},
{file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"},
{file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"},
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"},
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"},
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"},
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"},
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"},
{file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"},
{file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"},
{file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"},
{file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"},
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"},
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"},
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"},
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"},
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"},
{file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"},
{file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"},
{file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"},
{file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"},
{file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"},
{file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"},
]
[package.dependencies]
pycparser = "*"
[[package]] [[package]]
name = "click" name = "click"
version = "8.1.7" version = "8.1.7"
@ -211,6 +290,55 @@ mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.11.1)", "types-Pil
test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] test = ["Pillow", "contourpy[test-no-images]", "matplotlib"]
test-no-images = ["pytest", "pytest-cov", "pytest-rerunfailures", "pytest-xdist", "wurlitzer"] test-no-images = ["pytest", "pytest-cov", "pytest-rerunfailures", "pytest-xdist", "wurlitzer"]
[[package]]
name = "cryptography"
version = "43.0.1"
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
optional = true
python-versions = ">=3.7"
files = [
{file = "cryptography-43.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d"},
{file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062"},
{file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962"},
{file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277"},
{file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a"},
{file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042"},
{file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494"},
{file = "cryptography-43.0.1-cp37-abi3-win32.whl", hash = "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2"},
{file = "cryptography-43.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d"},
{file = "cryptography-43.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d"},
{file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806"},
{file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85"},
{file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c"},
{file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1"},
{file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa"},
{file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4"},
{file = "cryptography-43.0.1-cp39-abi3-win32.whl", hash = "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47"},
{file = "cryptography-43.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb"},
{file = "cryptography-43.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034"},
{file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d"},
{file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289"},
{file = "cryptography-43.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84"},
{file = "cryptography-43.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365"},
{file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96"},
{file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172"},
{file = "cryptography-43.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2"},
{file = "cryptography-43.0.1.tar.gz", hash = "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d"},
]
[package.dependencies]
cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""}
[package.extras]
docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"]
docstest = ["pyenchant (>=1.6.11)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"]
nox = ["nox"]
pep8test = ["check-sdist", "click", "mypy", "ruff"]
sdist = ["build"]
ssh = ["bcrypt (>=3.1.5)"]
test = ["certifi", "cryptography-vectors (==43.0.1)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"]
test-randomorder = ["pytest-randomly"]
[[package]] [[package]]
name = "cycler" name = "cycler"
version = "0.12.1" version = "0.12.1"
@ -504,6 +632,21 @@ docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alab
qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"]
testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"]
[[package]]
name = "jeepney"
version = "0.8.0"
description = "Low-level, pure Python DBus protocol wrapper."
optional = true
python-versions = ">=3.7"
files = [
{file = "jeepney-0.8.0-py3-none-any.whl", hash = "sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755"},
{file = "jeepney-0.8.0.tar.gz", hash = "sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806"},
]
[package.extras]
test = ["async-timeout", "pytest", "pytest-asyncio (>=0.17)", "pytest-trio", "testpath", "trio"]
trio = ["async_generator", "trio"]
[[package]] [[package]]
name = "kiwisolver" name = "kiwisolver"
version = "1.4.7" version = "1.4.7"
@ -1256,6 +1399,17 @@ files = [
[package.extras] [package.extras]
tests = ["pytest"] tests = ["pytest"]
[[package]]
name = "pycparser"
version = "2.22"
description = "C parser in Python"
optional = true
python-versions = ">=3.8"
files = [
{file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"},
{file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"},
]
[[package]] [[package]]
name = "pydot" name = "pydot"
version = "3.0.2" version = "3.0.2"
@ -1379,6 +1533,21 @@ files = [
{file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"},
] ]
[[package]]
name = "secretstorage"
version = "3.3.3"
description = "Python bindings to FreeDesktop.org Secret Service API"
optional = true
python-versions = ">=3.6"
files = [
{file = "SecretStorage-3.3.3-py3-none-any.whl", hash = "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99"},
{file = "SecretStorage-3.3.3.tar.gz", hash = "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77"},
]
[package.dependencies]
cryptography = ">=2.0"
jeepney = ">=0.6"
[[package]] [[package]]
name = "six" name = "six"
version = "1.16.0" version = "1.16.0"
@ -1537,7 +1706,10 @@ files = [
[package.extras] [package.extras]
dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"]
[extras]
secretstorage = ["SecretStorage"]
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = "^3.12" python-versions = "^3.12"
content-hash = "b53b77f57e118a7dc8649764dff18035672596a44b2be1983d3cbe17e1d28bc2" content-hash = "17b8e803d4fecdffce0e19b557cedc226cc67d501c8f86b8228af513d9dfc3e3"

View file

@ -7,9 +7,13 @@ readme = "README.md"
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.12" python = "^3.12"
androguard = "^4.1.2" androguard = "^4.1.2"
SecretStorage = { version = "^3.3.3", optional = true }
[tool.poetry.extras]
secretstorage = ["SecretStorage"]
[build-system] [build-system]
requires = ["poetry-core"] requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api" build-backend = "poetry.core.masonry.api"