Owen Lo

30 papers B 1C 2Misc 1Journal 18Unranked 7
YearRankTypeTitle / Venue / Authors
2026 J jnl
CoRR
Callum Turino, William J. Buchanan, Owen Lo, Christoph Thuummler
2025 J jnl
CoRR
Nilupulee Anuradha Gunathilake, Owen Lo, William J. Buchanan, Ahmed Al-Dubai
2025 J jnl
IACR Cryptol. ePrint Arch.
Nilupulee Anuradha Gunathilake, Owen Lo, William J. Buchanan, Ahmed Yassin Al-Dubai
2025 conf
TPS-ISA
Callum Turino, William J. Buchanan, Owen Lo, Christoph Thümmler
2024 Misc conf
SEC
Dimitrios Kasimatis, William J. Buchanan, Mwrwan Abubakar, Owen Lo, Christos Chrysoulas, Nikolaos Pitropakis, Pavlos Papadopoulos, Sarwar Sayeed, Marc Sel
2022 conf
CSP
Nilupulee Anuradha Gunathilake, Ahmed Al-Dubai, William J. Buchanan, Owen Lo
2022 J jnl
CoRR
Owen Lo, William J. Buchanan, Sarwar Sayeed, Pavlos Papadopoulos, Nikolaos Pitropakis, Christos Chrysoulas
2022 J jnl
Sensors
Owen Lo, William J. Buchanan, Sarwar Sayeed, Pavlos Papadopoulos, Nikolaos Pitropakis, Christos Chrysoulas
2022 J jnl
CoRR
William J. Buchanan, Mwrwan Abubakar, Owen Lo, Christos Chrysoulas, Nikolaos Pitropakis, Pavlos Papadopoulos, Sarwar Sayeed, Marc Sel
2022 J jnl
Entropy
Hisham Ali, Jawad Ahmad, Zakwan Jaroucheh, Pavlos Papadopoulos, Nikolaos Pitropakis, Owen Lo, Will Abramson, William J. Buchanan
2021 J jnl
CoRR
Masoud Barati, William J. Buchanan, Owen Lo, Omer F. Rana
2021 conf
UCC Companion
Masoud Barati, William J. Buchanan, Owen Lo, Omer F. Rana
2021 J jnl
CoRR
Nilupulee Anuradha Gunathilake, Ahmed Al-Dubai, William J. Buchanan, Owen Lo
2021 J jnl
CoRR
Nilupulee Anuradha Gunathilake, Ahmed Al-Dubai, William J. Buchanan, Owen Lo
2021 conf
CyberICPS/SECPRE/ADIoT/SPOSE/CPS4CIP/CDT&SECOMANE@ESORICS
Christos Chrysoulas, Amanda Thomson, Nikolaos Pitropakis, Pavlos Papadopoulos, Owen Lo, William J. Buchanan, George Domalis, Nikos I. Karacapilidis, Dimitris Tsakalidis, Dimitrios Tsolis
2021 J jnl
CoRR
Christos Chrysoulas, Amanda Thomson, Nikolaos Pitropakis, Pavlos Papadopoulos, Owen Lo, William J. Buchanan, George Domalis, Nikos I. Karacapilidis, Dimitris Tsakalidis, Dimitrios Tsolis
2021 C conf
SIN
Will Abramson, William J. Buchanan, Sarwar Sayeed, Nikolaos Pitropakis, Owen Lo
2021 J jnl
CoRR
William Abramson, William J. Buchanan, Sarwar Sayeed, Nikolaos Pitropakis, Owen Lo
2020 J jnl
CoRR
Pavlos Papadopoulos, Nikolaos Pitropakis, William J. Buchanan, Owen Lo, Sokratis K. Katsikas
2020 J jnl
Comput.
Pavlos Papadopoulos, Nikolaos Pitropakis, William J. Buchanan, Owen Lo, Sokratis K. Katsikas
2020 J jnl
CoRR
Ian Low, William J. Buchanan, Richard J. Macfarlane, Owen Lo
2019 conf
ICGS3
Jamie O'Hare, Rich Macfarlane, Owen Lo
2018 B conf
ARES
Owen Lo, William J. Buchanan, Douglas Carson
2018 J jnl
Secur. Commun. Networks
Owen Lo, William J. Buchanan, Paul Griffiths, Richard Macfarlane
2015
Owen Lo
2015 conf
TrustCom/BigDataSE/ISPA (1)
Elochukwu Ukwandu, William J. Buchanan, Lu Fan, Gordon Russell, Owen Lo
2015 C conf
HealthCom
William J. Buchanan, Elochukwu Ukwandu, Nicole van Deursen, Lu Fan, Gordon Russell, Owen Lo, Christoph Thuemmler
2012 J jnl
J. Cyber Secur. Mobil.
Christoph Thuemmler, Lu Fan, William J. Buchanan, Owen Lo, Elias Ekonomou, Abou Sofyane Khedim
2012 J jnl
Comput. Secur.
Richard Macfarlane, William J. Buchanan, Elias Ekonomou, Omair Uthmani, Lu Fan, Owen Lo
2011 conf
IEEE CLOUD
Lu Fan, William J. Buchanan, Christoph Thümmler, Owen Lo, Abou Sofyane Khedim, Omair Uthmani, Alistair Lawson, Derek Bell
redb/extractors/apk_extractors/apk_permissions.py
← Index redb/extractors/apk_extractors/apk_permissions.py python
import inspect
from datetime import datetime, timezone
from typing import Any

from redb.extractors.enum import Tag
from redb.extractors.apk_extractor import APKExtractor
from redb.models.dataclasses import APKPermissions, APKPermission

# Known dangerous permissions (Android runtime permissions)
DANGEROUS_PERMISSIONS = {
    "android.permission.READ_CALENDAR",
    "android.permission.WRITE_CALENDAR",
    "android.permission.CAMERA",
    "android.permission.READ_CONTACTS",
    "android.permission.WRITE_CONTACTS",
    "android.permission.GET_ACCOUNTS",
    "android.permission.ACCESS_FINE_LOCATION",
    "android.permission.ACCESS_COARSE_LOCATION",
    "android.permission.ACCESS_BACKGROUND_LOCATION",
    "android.permission.RECORD_AUDIO",
    "android.permission.READ_PHONE_STATE",
    "android.permission.READ_PHONE_NUMBERS",
    "android.permission.CALL_PHONE",
    "android.permission.ANSWER_PHONE_CALLS",
    "android.permission.ADD_VOICEMAIL",
    "android.permission.USE_SIP",
    "android.permission.BODY_SENSORS",
    "android.permission.SEND_SMS",
    "android.permission.RECEIVE_SMS",
    "android.permission.READ_SMS",
    "android.permission.RECEIVE_WAP_PUSH",
    "android.permission.RECEIVE_MMS",
    "android.permission.READ_EXTERNAL_STORAGE",
    "android.permission.WRITE_EXTERNAL_STORAGE",
    "android.permission.READ_MEDIA_IMAGES",
    "android.permission.READ_MEDIA_VIDEO",
    "android.permission.READ_MEDIA_AUDIO",
    "android.permission.POST_NOTIFICATIONS",
    "android.permission.NEARBY_WIFI_DEVICES",
    "android.permission.ACTIVITY_RECOGNITION",
    "android.permission.BLUETOOTH_SCAN",
    "android.permission.BLUETOOTH_ADVERTISE",
    "android.permission.BLUETOOTH_CONNECT",
}


class APKPermissionsExtractor(APKExtractor):

    def __init__(
        self, filepath, log, exporters=None, index_prefix=None,
        known_benign=False, known_malicious=False,
        apk=None,
    ):
        super().__init__(
            filepath, log, exporters, index_prefix,
            known_benign, known_malicious, apk,
        )
        self.permissions_data = None
        self.log.debug(inspect.currentframe().f_code.co_name)

    def tag(self):
        return Tag.APK_PERMISSIONS.value

    def _get_protection_level(self, perm_name):
        """Determine the protection level of a permission.

        Uses androguard's permission mappings first, falls back to the
        known dangerous list.
        """
        try:
            from androguard.core.api_specific_resources import load_permission_mappings
            target_sdk = self.apk.get_target_sdk_version()
            sdk = int(target_sdk) if target_sdk else 30
            permission_map = load_permission_mappings(sdk)
            if perm_name in permission_map:
                info = permission_map[perm_name]
                if isinstance(info, dict):
                    return info.get("protectionLevel", "unknown")
                return "unknown"
        except Exception:
            pass

        # Fallback to known dangerous set
        if perm_name in DANGEROUS_PERMISSIONS:
            return "dangerous"
        if perm_name.startswith("android.permission."):
            return "normal"
        return "unknown"

    def _compute_permhash(self):
        """Compute permhash using the permhash library."""
        try:
            from permhash.functions import permhash_apk
            return permhash_apk(self.filepath)
        except Exception as e:
            self.log.warning(f"Failed to compute permhash: {e}")
            return None

    def _safe_extract(self, field_name, func, default=None):
        """Extract a single field, logging and returning default on failure."""
        try:
            return func()
        except Exception as e:
            self.log.warning(
                f"Error extracting APK permissions field '{field_name}' for "
                f"{self.hash.sha256}: {e}"
            )
            return default

    def extract(self):
        if not self._is_valid_apk():
            self.log.error(f"Invalid APK for {self.hash.sha256}")
            return None

        requested_perms = self._safe_extract(
            "requested_permissions",
            lambda: list(self.apk.get_permissions() or []), []
        )
        custom_perms = self._safe_extract(
            "custom_permissions",
            lambda: list(self.apk.get_declared_permissions() or []), []
        )
        custom_perm_set = set(custom_perms)

        permission_details = []
        dangerous_permissions = []

        for perm in requested_perms:
            try:
                protection_level = self._get_protection_level(perm)
                is_custom = perm in custom_perm_set

                permission_details.append(APKPermission(
                    permission_name=perm,
                    protection_level=protection_level,
                    is_custom=is_custom,
                ))

                if protection_level == "dangerous":
                    dangerous_permissions.append(perm)
            except Exception as e:
                self.log.warning(
                    f"Error processing permission '{perm}' for "
                    f"{self.hash.sha256}: {e}"
                )
                permission_details.append(APKPermission(
                    permission_name=perm,
                    protection_level="unknown",
                    is_custom=perm in custom_perm_set,
                ))

        permhash_value = self._compute_permhash()

        self.permissions_data = APKPermissions(
            total_permission_count=len(requested_perms),
            dangerous_permission_count=len(dangerous_permissions),
            permissions=requested_perms,
            dangerous_permissions=dangerous_permissions,
            custom_permissions=custom_perms,
            permission_details=permission_details,
            permhash=permhash_value,
        )
        return self.permissions_data

    def prepare_export_data(self, exporter_type: str) -> Any:
        if exporter_type == "ClickHouseExporter":
            if not self.permissions_data:
                return None

            current_time = datetime.now(timezone.utc)

            # One row per permission
            data = []
            for detail in self.permissions_data.permission_details:
                data.append([
                    self.sha256,
                    detail.permission_name,
                    detail.protection_level,
                    int(detail.is_custom),
                    current_time,
                ])

            if not data:
                return None

            column_names = [
                'sha256', 'permission_name', 'protection_level',
                'is_custom', 'analysis_date',
            ]

            column_type_names = [
                'FixedString(64)', 'String', 'LowCardinality(String)',
                'UInt8', "DateTime64(3, 'UTC')",
            ]

            return (data, column_names, column_type_names)

    def get_clickhouse_table(self) -> str:
        return "redb_apk_permissions"