Apkk / src /manifest_parser.py
Skydata001's picture
Upload 7 files
e092c28 verified
Raw History Blame Contribute Delete
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