Spaces:
Paused
Paused
Download src/manifest_parser.py from Skydata001/Apkk: direct link, hf CLI and curl.
- Browser
- Download file 11.9 kB
-
https://huggingface.co/spaces/Skydata001/Apkk/resolve/main/src/manifest_parser.py
- Command line
-
hf download hf://spaces/Skydata001/Apkk/src/manifest_parser.py
-
curl -L -o manifest_parser.py https://huggingface.co/spaces/Skydata001/Apkk/resolve/main/src/manifest_parser.py
11.9 kB
| """ | |
| APK Deep Diff Analyzer - AndroidManifest.xml Parser | |
| """ | |
| import xml.etree.ElementTree as ET | |
| from typing import Dict, List, Any, Optional | |
| import os | |
| class ManifestAnalyzer: | |
| """Analyze AndroidManifest.xml content.""" | |
| def __init__(self, manifest_path: str): | |
| self.manifest_path = manifest_path | |
| self.tree = None | |
| self.root = None | |
| self._parse() | |
| def _parse(self): | |
| """Parse the manifest XML.""" | |
| try: | |
| self.tree = ET.parse(self.manifest_path) | |
| self.root = self.tree.getroot() | |
| except Exception: | |
| self.tree = None | |
| self.root = None | |
| def _get_attr(self, element: ET.Element, attr: str, namespace: str = "android") -> Optional[str]: | |
| """Get attribute value with namespace handling.""" | |
| ns = "http://schemas.android.com/apk/res/android" | |
| val = element.get(f"{{{ns}}}{attr}") | |
| if val is None: | |
| val = element.get(attr) | |
| return val | |
| def get_package_info(self) -> Dict[str, Any]: | |
| """Get package and application info.""" | |
| if self.root is None: | |
| return {} | |
| info = { | |
| "package": self.root.get("package", ""), | |
| "versionCode": self._get_attr(self.root, "versionCode"), | |
| "versionName": self._get_attr(self.root, "versionName"), | |
| } | |
| app = self.root.find("application") | |
| if app is not None: | |
| info["application"] = { | |
| "label": self._get_attr(app, "label"), | |
| "icon": self._get_attr(app, "icon"), | |
| "theme": self._get_attr(app, "theme"), | |
| "debuggable": self._get_attr(app, "debuggable"), | |
| "networkSecurityConfig": self._get_attr(app, "networkSecurityConfig"), | |
| "usesCleartextTraffic": self._get_attr(app, "usesCleartextTraffic"), | |
| "allowBackup": self._get_attr(app, "allowBackup"), | |
| "extractNativeLibs": self._get_attr(app, "extractNativeLibs"), | |
| } | |
| # SDK info | |
| uses_sdk = self.root.find("uses-sdk") | |
| if uses_sdk is not None: | |
| info["minSdkVersion"] = self._get_attr(uses_sdk, "minSdkVersion") | |
| info["targetSdkVersion"] = self._get_attr(uses_sdk, "targetSdkVersion") | |
| info["maxSdkVersion"] = self._get_attr(uses_sdk, "maxSdkVersion") | |
| return info | |
| def get_permissions(self) -> List[str]: | |
| """Get all permissions.""" | |
| if self.root is None: | |
| return [] | |
| permissions = [] | |
| for perm in self.root.findall("uses-permission"): | |
| name = self._get_attr(perm, "name") | |
| if name: | |
| permissions.append(name) | |
| return sorted(set(permissions)) | |
| def get_activities(self) -> List[Dict[str, Any]]: | |
| """Get all activities.""" | |
| if self.root is None: | |
| return [] | |
| activities = [] | |
| app = self.root.find("application") | |
| if app is not None: | |
| for activity in app.findall("activity"): | |
| name = self._get_attr(activity, "name") | |
| if name: | |
| acts = { | |
| "name": name, | |
| "exported": self._get_attr(activity, "exported"), | |
| "permission": self._get_attr(activity, "permission"), | |
| "intent_filters": [], | |
| } | |
| for intent in activity.findall("intent-filter"): | |
| actions = [a.get("name", "") for a in intent.findall("action")] | |
| categories = [c.get("name", "") for c in intent.findall("category")] | |
| acts["intent_filters"].append({ | |
| "actions": actions, | |
| "categories": categories, | |
| }) | |
| activities.append(acts) | |
| return activities | |
| def get_services(self) -> List[Dict[str, Any]]: | |
| """Get all services.""" | |
| if self.root is None: | |
| return [] | |
| services = [] | |
| app = self.root.find("application") | |
| if app is not None: | |
| for service in app.findall("service"): | |
| name = self._get_attr(service, "name") | |
| if name: | |
| services.append({ | |
| "name": name, | |
| "exported": self._get_attr(service, "exported"), | |
| "permission": self._get_attr(service, "permission"), | |
| }) | |
| return services | |
| def get_receivers(self) -> List[Dict[str, Any]]: | |
| """Get all broadcast receivers.""" | |
| if self.root is None: | |
| return [] | |
| receivers = [] | |
| app = self.root.find("application") | |
| if app is not None: | |
| for receiver in app.findall("receiver"): | |
| name = self._get_attr(receiver, "name") | |
| if name: | |
| receivers.append({ | |
| "name": name, | |
| "exported": self._get_attr(receiver, "exported"), | |
| "permission": self._get_attr(receiver, "permission"), | |
| }) | |
| return receivers | |
| def get_providers(self) -> List[Dict[str, Any]]: | |
| """Get all content providers.""" | |
| if self.root is None: | |
| return [] | |
| providers = [] | |
| app = self.root.find("application") | |
| if app is not None: | |
| for provider in app.findall("provider"): | |
| name = self._get_attr(provider, "name") | |
| if name: | |
| providers.append({ | |
| "name": name, | |
| "authorities": self._get_attr(provider, "authorities"), | |
| "exported": self._get_attr(provider, "exported"), | |
| }) | |
| return providers | |
| def get_metadata(self) -> List[Dict[str, str]]: | |
| """Get application metadata.""" | |
| if self.root is None: | |
| return [] | |
| metadata = [] | |
| app = self.root.find("application") | |
| if app is not None: | |
| for meta in app.findall("meta-data"): | |
| name = self._get_attr(meta, "name") | |
| value = self._get_attr(meta, "value") | |
| if name: | |
| metadata.append({"name": name, "value": value or ""}) | |
| return metadata | |
| def get_full_analysis(self) -> Dict[str, Any]: | |
| """Get complete manifest analysis.""" | |
| return { | |
| "package_info": self.get_package_info(), | |
| "permissions": self.get_permissions(), | |
| "activities": self.get_activities(), | |
| "services": self.get_services(), | |
| "receivers": self.get_receivers(), | |
| "providers": self.get_providers(), | |
| "metadata": self.get_metadata(), | |
| } | |
| def compare_manifests(orig_manifest: str, mod_manifest: str) -> Dict[str, Any]: | |
| """Compare two AndroidManifest.xml files.""" | |
| orig = ManifestAnalyzer(orig_manifest) | |
| mod = ManifestAnalyzer(mod_manifest) | |
| orig_data = orig.get_full_analysis() | |
| mod_data = mod.get_full_analysis() | |
| result = { | |
| "original": orig_data, | |
| "modified": mod_data, | |
| "changes": {}, | |
| } | |
| # Package info comparison | |
| orig_pkg = orig_data.get("package_info", {}) | |
| mod_pkg = mod_data.get("package_info", {}) | |
| pkg_changes = {} | |
| for key in set(list(orig_pkg.keys()) + list(mod_pkg.keys())): | |
| if key == "application": | |
| continue | |
| o_val = orig_pkg.get(key) | |
| m_val = mod_pkg.get(key) | |
| if o_val != m_val: | |
| pkg_changes[key] = {"original": o_val, "modified": m_val} | |
| # Application attributes | |
| orig_app = orig_pkg.get("application", {}) | |
| mod_app = mod_pkg.get("application", {}) | |
| app_changes = {} | |
| for key in set(list(orig_app.keys()) + list(mod_app.keys())): | |
| o_val = orig_app.get(key) | |
| m_val = mod_app.get(key) | |
| if o_val != m_val: | |
| app_changes[key] = {"original": o_val, "modified": m_val} | |
| if pkg_changes or app_changes: | |
| result["changes"]["package_info"] = {**pkg_changes, **app_changes} | |
| # Permissions | |
| orig_perms = set(orig_data.get("permissions", [])) | |
| mod_perms = set(mod_data.get("permissions", [])) | |
| result["changes"]["permissions"] = { | |
| "added": sorted(list(mod_perms - orig_perms)), | |
| "removed": sorted(list(orig_perms - mod_perms)), | |
| "unchanged": sorted(list(orig_perms & mod_perms)), | |
| } | |
| # Activities | |
| orig_acts = {a["name"]: a for a in orig_data.get("activities", [])} | |
| mod_acts = {a["name"]: a for a in mod_data.get("activities", [])} | |
| act_changes = { | |
| "added": [], | |
| "removed": [], | |
| "modified": [], | |
| } | |
| for name, data in mod_acts.items(): | |
| if name not in orig_acts: | |
| act_changes["added"].append(data) | |
| elif data != orig_acts[name]: | |
| act_changes["modified"].append({ | |
| "name": name, | |
| "original": orig_acts[name], | |
| "modified": data, | |
| }) | |
| for name, data in orig_acts.items(): | |
| if name not in mod_acts: | |
| act_changes["removed"].append(data) | |
| result["changes"]["activities"] = act_changes | |
| # Services | |
| orig_svcs = {s["name"]: s for s in orig_data.get("services", [])} | |
| mod_svcs = {s["name"]: s for s in mod_data.get("services", [])} | |
| svc_changes = {"added": [], "removed": [], "modified": []} | |
| for name, data in mod_svcs.items(): | |
| if name not in orig_svcs: | |
| svc_changes["added"].append(data) | |
| elif data != orig_svcs[name]: | |
| svc_changes["modified"].append({"name": name, "original": orig_svcs[name], "modified": data}) | |
| for name, data in orig_svcs.items(): | |
| if name not in mod_svcs: | |
| svc_changes["removed"].append(data) | |
| result["changes"]["services"] = svc_changes | |
| # Receivers | |
| orig_recs = {r["name"]: r for r in orig_data.get("receivers", [])} | |
| mod_recs = {r["name"]: r for r in mod_data.get("receivers", [])} | |
| rec_changes = {"added": [], "removed": [], "modified": []} | |
| for name, data in mod_recs.items(): | |
| if name not in orig_recs: | |
| rec_changes["added"].append(data) | |
| elif data != orig_recs[name]: | |
| rec_changes["modified"].append({"name": name, "original": orig_recs[name], "modified": data}) | |
| for name, data in orig_recs.items(): | |
| if name not in mod_recs: | |
| rec_changes["removed"].append(data) | |
| result["changes"]["receivers"] = rec_changes | |
| # Providers | |
| orig_provs = {p["name"]: p for p in orig_data.get("providers", [])} | |
| mod_provs = {p["name"]: p for p in mod_data.get("providers", [])} | |
| prov_changes = {"added": [], "removed": [], "modified": []} | |
| for name, data in mod_provs.items(): | |
| if name not in orig_provs: | |
| prov_changes["added"].append(data) | |
| elif data != orig_provs[name]: | |
| prov_changes["modified"].append({"name": name, "original": orig_provs[name], "modified": data}) | |
| for name, data in orig_provs.items(): | |
| if name not in mod_provs: | |
| prov_changes["removed"].append(data) | |
| result["changes"]["providers"] = prov_changes | |
| # Metadata | |
| orig_meta = {m["name"]: m["value"] for m in orig_data.get("metadata", [])} | |
| mod_meta = {m["name"]: m["value"] for m in mod_data.get("metadata", [])} | |
| meta_changes = { | |
| "added": [{"name": k, "value": v} for k, v in mod_meta.items() if k not in orig_meta], | |
| "removed": [{"name": k, "value": v} for k, v in orig_meta.items() if k not in mod_meta], | |
| "modified": [{"name": k, "original": orig_meta[k], "modified": mod_meta[k]} | |
| for k in orig_meta if k in mod_meta and orig_meta[k] != mod_meta[k]], | |
| } | |
| result["changes"]["metadata"] = meta_changes | |
| return result | |