DRMLab Project

This commit is contained in:
Mike 2026-02-08 17:42:32 +02:00
parent 4a0f3c9275
commit 7ba5bce8a9
2 changed files with 325 additions and 0 deletions

56
tools/decrypt.py Normal file
View File

@ -0,0 +1,56 @@
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import sys
import os
def decrypt_file(input_file, key_hex):
try:
key = bytes.fromhex(key_hex)
except ValueError:
print("[-] Invalid AES key")
return
with open(input_file, "rb") as f:
encrypted_data = f.read()
cipher = AES.new(key, AES.MODE_ECB)
dec_data = cipher.decrypt(pad(encrypted_data, 16))
if b"INNER_MSTAR" not in dec_data:
print("[-] AES key not working")
return
payload = None
for offset in (64, 96):
candidate = dec_data[offset:]
if b"CHAI" in candidate or b"kbox" in candidate:
payload = candidate
break
if payload is None:
payload = dec_data[64:]
if b"CHAI" in payload:
out_data = payload
elif b"kbox" in payload:
out_data = payload[:128]
else:
out_data = payload[:32]
base, _ = os.path.splitext(input_file)
out_file = f"{base}_encrypted.dat"
with open(out_file, "wb") as f:
f.write(out_data)
print(f"[+] Saved {out_file}")
if __name__ == "__main__":
if len(sys.argv) != 2:
print(f"Usage: python3 {sys.argv[0]} <file.dat>")
sys.exit(1)
aes_key = input("AES key (hex): ").strip()
decrypt_file(sys.argv[1], aes_key)

269
tools/dump_buildprop.py Normal file
View File

@ -0,0 +1,269 @@
#!/usr/bin/env python3
import argparse, os, re, sys
from typing import Dict, List, Tuple
RE_BLOCK = re.compile(
br'(?mi)^(#\s*begin[^\n]*build\s+properties[^\n]*\n)(.*?)(^#\s*end[^\n]*build\s+properties[^\n]*$)',
re.DOTALL,
)
BASE_CANONICAL: List[Tuple[str, bool]] = [
("# begin build properties", True),
("# autogenerated by buildinfo.sh", True),
("ro.build.id", False),
("ro.build.display.id", False),
("ro.build.version.incremental", False),
("ro.build.version.sdk", False),
("ro.build.version.preview_sdk", False),
("ro.build.version.codename", False),
("ro.build.version.all_codenames", False),
("ro.build.version.release", False),
("ro.build.version.security_patch", False),
("ro.build.version.base_os", False),
("ro.build.date", False),
("ro.build.date.utc", False),
("ro.build.type", False),
("ro.build.user", False),
("ro.build.host", False),
("ro.build.tags", False),
("ro.build.flavor", False),
("ro.build.system_root_image", False),
("ro.build.ab_update", False),
("ro.product.model", False),
("ro.product.brand", False),
("ro.product.name", False),
("ro.product.device", False),
("ro.product.board", False),
("# ro.product.cpu.abi and ro.product.cpu.abi2 are obsolete,", True),
("# use ro.product.cpu.abilist instead.", True),
("ro.product.cpu.abi", False),
("ro.product.cpu.abi2", False),
("ro.product.cpu.abilist", False),
("ro.product.cpu.abilist32", False),
("ro.product.cpu.abilist64", False),
("ro.product.manufacturer", False),
("ro.product.locale", False),
("ro.wifi.channels", False),
("ro.board.platform", False),
("# ro.build.product is obsolete; use ro.product.device", True),
("ro.build.product", False),
("# Do not try to parse description, fingerprint, or thumbprint", True),
("ro.build.description", False),
("ro.build.fingerprint", False),
("ro.build.thumbprint", False),
("ro.build.characteristics", False),
("# end build properties", True),
]
GENERIC_TOKENS = {"", "unknown", "generic", "aosp", "android", "android_device"}
def is_generic(v: str) -> bool:
s = (v or "").strip().lower()
return s in GENERIC_TOKENS or s.startswith("generic-") or s == "test-keys"
def parse_props(text: str) -> Dict[str, str]:
d: Dict[str, str] = {}
for raw in text.splitlines():
line = raw.strip()
if not line or line.startswith("#") or "=" not in line:
continue
k, v = line.split("=", 1)
d[k.strip()] = v.strip()
return d
def block_kind(header: str, body: str) -> str:
h = (header + body).lower()
return "common" if "common build properties" in h or "buildinfo_common.sh" in h else "base"
def find_blocks(data: bytes):
blocks = []
for m in RE_BLOCK.finditer(data):
header = m.group(1).decode(errors="ignore")
body = m.group(2).decode(errors="ignore")
footer = m.group(3).decode(errors="ignore")
text = (header + body + footer).replace("\r\n","\n")
props = parse_props(text)
blocks.append({"text": text, "props": props, "kind": block_kind(header, body)})
return blocks
SOC_VENDOR_PATTERNS = {
"mstar": ["mstar", "cv6a", "msd6a", "mst", "cva"],
"mediatek":["mediatek", "mtk", "mt5", "mt6", "mt8"],
"amlogic": ["amlogic", "s905", "s912", "s922", "a113", "g12"],
"qualcomm":["qcom", "qualcomm", "msm", "sdm", "sm"],
"hisilicon":["hisilicon", "kirin", "hi37", "hi38", "hi35"],
"rockchip":["rockchip", "rk3", "rk33", "rk35", "px3", "px5"],
}
def detect_soc_vendor(props: Dict[str,str]) -> str:
hay = " ".join([
props.get("ro.board.platform",""),
props.get("ro.hardware",""),
props.get("ro.soc.manufacturer",""),
props.get("ro.soc.model",""),
props.get("ro.product.board",""),
]).lower()
for vendor, pats in SOC_VENDOR_PATTERNS.items():
if any(p in hay for p in pats):
return vendor.capitalize()
return props.get("ro.soc.manufacturer","").strip()
FINGERPRINT_KEYS = [
"ro.build.fingerprint",
"ro.system.build.fingerprint",
"ro.product.build.fingerprint",
"ro.vendor.build.fingerprint",
"ro.odm.build.fingerprint",
"ro.oem.build.fingerprint",
"ro.bootimage.build.fingerprint",
]
def first_non_generic(*vals: str) -> str:
for v in vals:
if v and not is_generic(v):
return v
return vals[0] if vals else ""
def derive_company_from_fp(fp: str) -> str:
if not fp or "/" not in fp:
return ""
head = fp.split("/", 1)[0].strip()
return head[:1].upper() + head[1:] if head else ""
def detect_form_factor(all_props: Dict[str,str]) -> str:
text = " ".join([
all_props.get("ro.build.characteristics",""),
all_props.get("ro.build.flavor",""),
all_props.get("ro.build.fingerprint",""),
all_props.get("ro.product.model",""),
all_props.get("ro.product.name",""),
all_props.get("ro.product.device",""),
all_props.get("ro.product.system.model",""),
all_props.get("ro.product.system.name",""),
]).lower()
if any(t in text for t in [" tv", "/tv", "mitv", "atv", "dvb", "android-tv", "google/atv"]):
return "tv"
if "tablet" in text or "pad" in text or "tab" in text:
return "tablet"
if "watch" in text or "wear" in text:
return "watch"
if "automotive" in text or "car" in text or "ivi" in text:
return "automotive"
return ""
def compose_props(base: Dict[str,str], commons: Dict[str,str], prefer_soc: bool,
prefer_board_device: bool, force_ff: str|None) -> Dict[str,str]:
merged = dict(commons)
merged.update(base)
out = dict(base)
fp = base.get("ro.build.fingerprint","")
if not fp or is_generic(fp) or "/" not in fp:
out["ro.build.fingerprint"] = first_non_generic(*(commons.get(k,"") for k in FINGERPRINT_KEYS[1:])) or fp
for tail in ["brand","manufacturer","model","device","name","board"]:
dst = f"ro.product.{tail}"
cur = base.get(dst, "")
cand = first_non_generic(
commons.get(f"ro.product.system.{tail}",""),
commons.get(f"ro.product.product.{tail}",""),
commons.get(f"ro.product.vendor.{tail}",""),
commons.get(f"ro.product.odm.{tail}",""),
commons.get(f"ro.product.oem.{tail}",""),
merged.get(dst,""),
cur,
)
out[dst] = cand or cur
if prefer_board_device:
dev = out.get("ro.product.device","")
if is_generic(dev) or dev in {"croods","android"}:
repl = first_non_generic(
merged.get("ro.product.board",""),
merged.get("ro.soc.model",""),
merged.get("ro.hardware",""),
dev,
)
out["ro.product.device"] = repl or dev
fp_final = out.get("ro.build.fingerprint","")
fp_brand = derive_company_from_fp(fp_final)
soc_vendor = detect_soc_vendor(merged)
if prefer_soc and soc_vendor:
out["ro.product.brand"] = soc_vendor
out["ro.product.manufacturer"] = soc_vendor
else:
if is_generic(out.get("ro.product.brand","")) and fp_brand:
out["ro.product.brand"] = fp_brand
if is_generic(out.get("ro.product.manufacturer","")) and fp_brand:
out["ro.product.manufacturer"] = fp_brand
if is_generic(out.get("ro.product.board","")):
out["ro.product.board"] = first_non_generic(
merged.get("ro.product.board",""),
merged.get("ro.soc.model",""),
merged.get("ro.board.platform",""),
out.get("ro.product.device",""),
)
if not out.get("ro.board.platform",""):
out["ro.board.platform"] = first_non_generic(
merged.get("ro.board.platform",""),
merged.get("ro.hardware",""),
merged.get("ro.soc.model",""),
)
if force_ff:
out["ro.build.characteristics"] = force_ff
else:
cur_ff = out.get("ro.build.characteristics","").strip().lower()
if cur_ff in {"", "default", "nosdcard"}:
auto = detect_form_factor({**merged, **out})
if auto:
out["ro.build.characteristics"] = auto
return out
def render_canonical(props: Dict[str,str]) -> str:
lines: List[str] = []
for token, is_comment in BASE_CANONICAL:
lines.append(token if is_comment else f"{token}={props.get(token,'')}")
return "\n".join(lines).strip() + "\n"
def main():
ap = argparse.ArgumentParser(description="Compose canonical build.prop (fills brand/device/fingerprint/form-factor).")
ap.add_argument("file")
ap.add_argument("--outdir", default="out")
ap.add_argument("--prefer-soc", action="store_true")
ap.add_argument("--prefer-board-device", action="store_true")
ap.add_argument("--form-factor", choices=["auto","tv","tablet","phone","watch","automotive"], default="auto")
args = ap.parse_args()
with open(args.file, "rb") as f:
data = f.read()
blocks = find_blocks(data)
if not blocks:
print("No build properties blocks found.")
sys.exit(1)
base = next((b for b in blocks if b["kind"]=="base"), blocks[0])
commons: Dict[str,str] = {}
for b in blocks:
if b["kind"] == "common":
commons.update(b["props"])
force_ff = None if args.form_factor == "auto" else args.form_factor
composed = compose_props(base["props"], commons, args.prefer_soc, args.prefer_board_device, force_ff)
txt = render_canonical(composed)
os.makedirs(args.outdir, exist_ok=True)
outp = os.path.join(args.outdir, "best_build_composed.prop")
with open(outp, "w", encoding="utf-8") as fo:
fo.write(txt)
print("Done:", outp)
if __name__ == "__main__":
main()