Permissions and components¶
Permissions¶
An app can request permissions in two tags and define its own in a third:
| Tag | Method | Meaning |
|---|---|---|
<uses-permission> |
get_permissions() |
requested on every Android version |
<uses-permission-sdk-23> |
get_permissions_sdk23() |
requested only on Android 6.0+ |
<permission> |
get_declared_permissions() |
defined by this app for others to request |
for permission in sorted(apk.get_permissions()):
print(f"uses-permission {permission}")
for permission in apk.get_permissions_sdk23():
print(f"uses-permission-sdk-23 {permission}")
# permissions the app defines for others to request
for permission in apk.get_declared_permissions():
print(f"permission {permission.name} [{permission.protection_level}]")
for permission in apk.get_permissions() {
println!("uses-permission {permission}");
}
for permission in apk.get_permissions_sdk23() {
println!("uses-permission-sdk-23 {permission}");
}
for permission in apk.get_declared_permissions() {
println!(
"permission {:?} [{:?}]",
permission.name, permission.protection_level
);
}
uses-permission android.permission.FOREGROUND_SERVICE_DATA_SYNC
uses-permission android.permission.INTERNET
uses-permission android.permission.RECEIVE_BOOT_COMPLETED
uses-permission-sdk-23 android.permission.POST_NOTIFICATIONS
permission io.github.delvinru.apkstest.READ [signature]
Exported components¶
Other apps can start exported activities, services and receivers, and query exported providers. Start with them when you assess an app's attack surface.
target_sdk = apk.get_target_sdk_version()
def is_exported(component) -> bool:
# before Android 12 (target SDK 31), a component with an intent filter
# was exported unless it said otherwise
if component.exported is None:
return bool(component.intent_filters) and target_sdk < 31
return component.exported == "true"
for kind, components in [
("activity", apk.get_activities()),
("service", apk.get_services()),
("receiver", apk.get_receivers()),
]:
for component in components:
if is_exported(component):
print(f"{kind:9} {component.name} permission={component.permission}")
for provider in apk.get_providers():
if provider.exported == "true":
print(f"provider {provider.name} authorities={provider.authorities}")
let target_sdk = apk.get_target_sdk_version();
// before Android 12 (target SDK 31), a component with an intent filter
// was exported unless it said otherwise
let is_exported = |exported: Option<&str>, has_filters: bool| match exported {
Some(value) => value == "true",
None => has_filters && target_sdk < 31,
};
for activity in apk.get_activities() {
if is_exported(activity.exported, !activity.intent_filters.is_empty()) {
println!("activity {:?}", activity.name);
}
}
for service in apk.get_services() {
if is_exported(service.exported, !service.intent_filters.is_empty()) {
println!("service {:?}", service.name);
}
}
for receiver in apk.get_receivers() {
if is_exported(receiver.exported, !receiver.intent_filters.is_empty()) {
println!("receiver {:?}", receiver.name);
}
}
for provider in apk.get_providers() {
if provider.exported == Some("true") {
println!("provider {:?} {:?}", provider.name, provider.authorities);
}
}
exported is the raw attribute value: "true", "false" or None. When it's None, Android decides:
- Activities, services, receivers. Before Android 12 (target SDK 31), a component with an
<intent-filter>is exported by default. Since target SDK 31, a component with an intent filter must setandroid:exported, or the app won't install. - Providers. Exported by default only when
minSdkVersionortargetSdkVersionis 16 or lower.
If a component requires a permission with the signature protection level, only apps signed with the same key can reach it.
Intent filters¶
Activities, activity aliases, services and receivers carry their intent filters as lists of actions and categories:
for activity in apk.get_activities():
for intent_filter in activity.intent_filters:
if "android.intent.action.VIEW" in intent_filter.actions:
print(f"{activity.name} handles VIEW: {intent_filter.categories}")
.MainActivity handles VIEW: ['android.intent.category.DEFAULT', 'android.intent.category.BROWSABLE']
All component fields¶
get_activities(), get_activity_aliases(), get_services(), get_receivers() and get_providers() return objects with the raw manifest attributes: name, exported, enabled, permission, process and so on, plus type-specific ones such as authorities and grant_uri_permissions for providers or foreground_service_type for services.
See the Python API for the full list.