check smali

This commit is contained in:
Jean-Marie Mineau 2024-11-05 16:01:34 +01:00
parent 3d7764d958
commit 4f197877ca
2 changed files with 107 additions and 1 deletions

View file

@ -2,12 +2,16 @@ import zipfile
import io
import hashlib
import json
import sqlite3
import tempfile
import subprocess
from argparse import ArgumentParser
from pathlib import Path
from getpass import getpass
from datetime import datetime
from .androzoo import download_apk
from .data import ApkData, load_from_directory
from .analysis import analyze
@ -130,7 +134,7 @@ def main():
print(entry.to_string())
else:
with (args.output_dir / sha256).open("w") as file:
file.write(entry)
file.write(entry.to_string())
if apks:
if args.json:
@ -231,3 +235,104 @@ def collect_to_db():
)
args = parser.parse_args()
load_from_directory(args.dir, args.db, args.androzoo_list)
def check_smali():
parser = ArgumentParser(
prog="Smalli Check",
description="Check if duplicated classes have distinct smali",
)
parser.add_argument(
"--db",
help="Path to the database storing the results",
type=Path,
required=True,
)
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
SECRET_STORAGE_IMPORTED = True
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()
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()
with sqlite3.connect(args.db) as conn:
apks = list(
map(
lambda t: t[0],
conn.execute("SELECT sha256 FROM data WHERE nb_duplicate_classes >= 1"),
)
)
data = {}
for sha256 in apks:
with tempfile.TemporaryDirectory() as tmpdirname:
d = Path(tmpdirname)
apk_bin = download_apk(sha256, api_key, logfile=None)
if apk_bin is None:
continue
with (d / "app.apk").open("wb") as fp:
fp.write(apk_bin)
with zipfile.ZipFile(io.BytesIO(apk_bin)) as apk:
json_data[sha256] = {}
entry = analyze(apk, sha256, json_out=json_data[sha256])
subprocess.run(["apktool", "d", "app.apk", "-o", "apktool_out"], cwd=d)
smalli_dirs = []
for dex in json_data[sha256]["class_dex"]:
if dex == "classes.dex":
smalli_dirs.append(out / "apktool_out" / "smali")
else:
smalli_dirs.append(
out / "apktool_out" / "smali_" + dex.removesuffix(".dex")
)
dist_dup_classes = set()
for cl in json_data[sha256]["duplicated_classes"]:
cl_f = cl.removesuffix(";").removeprefix("L") + ".smali"
smali = None
for cdir in smalli_dirs:
if (cdir / cl_f).exists():
with (cdir / cl_f).open() as file:
smali_new = file.read()
if smali is None:
smali = smali_new
elif smali != smali_new:
dist_dup_classes.add(cl)
json_data[sha256]["redef_classes"] = list(dist_dup_classes)
print(json.dumps(json_data))

View file

@ -21,3 +21,4 @@ build-backend = "poetry.core.masonry.api"
[tool.poetry.scripts]
scan = 'android_class_shadowing_scanner.__init__:main'
collect-scan = 'android_class_shadowing_scanner.__init__:collect_to_db'
check-class-redef = 'android_class_shadowing_scanner.__init__:check_smali'