Neil Walkinshaw

87 papers A* 1A 14B 6C 9Journal 29Unranked 26
YearRankTypeTitle / Venue / Authors
2026 J jnl
CoRR
Beomsu Koh, Neil Walkinshaw, Donghwan Shin
2025 J jnl
Softw. Test. Verification Reliab.
Richard J. Somers, Neil Walkinshaw, Robert M. Hierons, Jackie Elliott, Ahmed Iqbal, Emma Walkinshaw
2025 B conf
XP
Giulia Neri, Rob Marchand, Neil Walkinshaw
2025 J jnl
J. Open Source Softw.
Michael Foster, Andrew G. Clark, Christopher Wild, Farhad Allian, Robert D. Turner, Richard J. Somers, Nicholas Latimer, Neil Walkinshaw, Robert M. Hierons
2025 A conf
EASE
Michael Foster, Robert M. Hierons, Donghwan Shin, Neil Walkinshaw, Christopher Wild
2025 J jnl
CoRR
Michael Foster, Robert M. Hierons, Donghwan Shin, Neil Walkinshaw, Christopher Wild
2024 C conf
ICTSS
Guannan Lou, Donghwan Shin, Neil Walkinshaw, Robert M. Hierons
2024 J jnl
CoRR
Neil Walkinshaw, Michael Foster, José Miguel Rojas, Robert M. Hierons
2024 J jnl
Proc. ACM Softw. Eng.
Neil Walkinshaw, Michael Foster, José Miguel Rojas, Robert M. Hierons
2024 A conf
ICST
Michael Foster, Christopher Wild, Robert M. Hierons, Neil Walkinshaw
2024 J jnl
CoRR
Germán Vega, Roland Groz, Catherine Oriat, Michael Foster, Neil Walkinshaw, Adenilso Simão
2024 J jnl
ACM Trans. Softw. Eng. Methodol.
Andrew G. Clark, Michael Foster, Benedikt Prifling, Neil Walkinshaw, Robert M. Hierons, Volker Schmidt, Robert D. Turner
2023 C conf
ICFEM
Michael Foster, Roland Groz, Catherine Oriat, Adenilso da Silva Simão, Germán Vega, Neil Walkinshaw
2023 conf
ICGI
Roland Groz, Catherine Oriat, Germán Vega, Adenilso da Silva Simão, Michael Foster, Neil Walkinshaw
2023 J jnl
Inf. Softw. Technol.
Richard J. Somers, James A. Douthwaite, David James Wagg, Neil Walkinshaw, Robert M. Hierons
2023 A conf
ICST
Andrew G. Clark, Michael Foster, Neil Walkinshaw, Robert M. Hierons
2023 J jnl
IEEE Trans. Software Eng.
Neil Walkinshaw, Robert M. Hierons
2022 J jnl
IEEE Trans. Software Eng.
Foozhan Ataiefard, Mohammad Jafar Mashhadi, Hadi Hemmati, Neil Walkinshaw
2022 conf
MoDELS (Companion)
Richard J. Somers, Andrew G. Clark, Neil Walkinshaw, Robert M. Hierons
2022 J jnl
CoRR
Andrew G. Clark, Michael Foster, Benedikt Prifling, Neil Walkinshaw, Robert M. Hierons, Volker Schmidt, Robert D. Turner
2021 J jnl
CoRR
Mohammad Jafar Mashhadi, Foozhan Ataiefard, Hadi Hemmati, Neil Walkinshaw
2021 C conf
ICTSS
Michael Foster, John Derrick, Neil Walkinshaw
2021 J jnl
CoRR
Andrew G. Clark, Neil Walkinshaw, Robert M. Hierons
2021 J jnl
Inf. Softw. Technol.
Andrew G. Clark, Neil Walkinshaw, Robert M. Hierons
2020 conf
AITest
Neil Walkinshaw
2020 conf
ECSEE
Maren Krafft, Gordon Fraser, Neil Walkinshaw
2020 A conf
EASE
Neil Walkinshaw, Martin J. Shepperd
2019 conf
WiPSCE
Sebastian Keller, Maren Krafft, Gordon Fraser, Neil Walkinshaw, Korbinian Otto, Barbara Sabitzer
2018 A conf
ESEM
Neil Walkinshaw, Leandro L. Minku
2018 B conf
SSBSE
Basil Eljuse, Neil Walkinshaw
2018 J jnl
IEEE Trans. Software Eng.
Mathew Hall, Neil Walkinshaw, Phil McMinn
2018 A conf
ICST
Sina Shamshiri, José Miguel Rojas, Juan Pablo Galeotti, Neil Walkinshaw, Gordon Fraser
2018 conf
Machine Learning for Dynamic Software Analysis
Neil Walkinshaw
2017 book
Neil Walkinshaw
2017 A conf
ICST
Neil Walkinshaw, Gordon Fraser
2017 C conf
QRS
Othman Esoul, Neil Walkinshaw
2016 B conf
SSBSE
Basil Eljuse, Neil Walkinshaw
2016 C conf
PDP
Ramsay Taylor, Emilio Tuosto, Neil Walkinshaw, John Derrick
2016 A conf
ICSME
Mathew Hall, Neil Walkinshaw
2016 J jnl
CoRR
Othman Esoul, Neil Walkinshaw
2016 A conf
ICSME
Neil Walkinshaw, Mathew Hall
2016 J jnl
Empir. Softw. Eng.
Neil Walkinshaw, Ramsay Taylor, John Derrick
2016 J jnl
CoRR
Neil Walkinshaw, Gordon Fraser
2015 A conf
ISSRE
Sunil Nair, Neil Walkinshaw, Tim Kelly, Jose Luis de la Vara
2015 J jnl
Softw. Test. Verification Reliab.
Gordon Fraser, Neil Walkinshaw
2015 conf
RAISE@ICSE
Petros Papadopoulos, Neil Walkinshaw
2015 A conf
CADE
Thomas Gransden, Neil Walkinshaw, Rajeev Raman
2015 J jnl
CoRR
Thomas Gransden, Neil Walkinshaw, Rajeev Raman
2015 B conf
VISSOFT
Simon Scarle, Neil Walkinshaw
2014 A conf
ICSME
Mathew Hall, Muhammad Ali Khojaye, Neil Walkinshaw, Phil McMinn
2014 C conf
CICM
Thomas Gransden, Neil Walkinshaw, Rajeev Raman
2014 J jnl
CoRR
Thomas Gransden, Neil Walkinshaw, Rajeev Raman
2014 conf
SAFECOMP Workshops
Sunil Nair, Neil Walkinshaw, Tim Kelly
2013 J jnl
ACM Trans. Softw. Eng. Methodol.
Neil Walkinshaw, Kirill Bogdanov
2013 conf
WCRE
Neil Walkinshaw, Ramsay Taylor, John Derrick
2013 J jnl
Adv. Comput.
Neil Walkinshaw
2013 J jnl
Empir. Softw. Eng.
Neil Walkinshaw, Bernard Lambeau, Christophe Damas, Kirill Bogdanov, Pierre Dupont
2013 conf
PROMISE
Neil Walkinshaw
2012 A conf
ICST
Gordon Fraser, Neil Walkinshaw
2012 conf
ISoLA (1)
Karl Meinke, Neil Walkinshaw
2012 conf
ICSM
Mathew Hall, Neil Walkinshaw, Phil McMinn
2011 B conf
IEEE Congress on Evolutionary Computation
Salem Fawaz Adra, Mariam Kiran, Phil McMinn, Neil Walkinshaw
2011 C conf
ICTSS
Neil Walkinshaw
2010 C conf
ICTSS
Neil Walkinshaw, Kirill Bogdanov, John Derrick, Javier París
2010 A conf
GECCO
Mathew Hall, Phil McMinn, Neil Walkinshaw
2010 J jnl
J. Syst. Softw.
Leonardo Bottaci, Gregory M. Kapfhammer, Neil Walkinshaw
2010 conf
TAIC PART
Neil Walkinshaw
2010 conf
WODA
Neil Walkinshaw, Sheeva Afshan, Phil McMinn
2009 conf
TestCom/FATES
Qiang Guo, John Derrick, Neil Walkinshaw
2009 conf
WCRE
Kirill Bogdanov, Neil Walkinshaw
2009 conf
FMCO
Neil Walkinshaw, John Derrick
2009 B conf
FM
Neil Walkinshaw, John Derrick, Qiang Guo
2009 conf
FMCO
John Derrick, Neil Walkinshaw, Thomas Arts, Clara Benac Earle, Francesco Cesarini, Lars-Åke Fredlund, Víctor M. Gulías, John Hughes, Simon J. Thompson
2008 J jnl
Softw. Test. Verification Reliab.
Neil Walkinshaw, Kirill Bogdanov, Shaukat Ali, Mike Holcombe
2008 conf
ICST Workshops
Sarah Salahuddin, Kirill Bogdanov, Neil Walkinshaw
2008 conf
ICGI
Neil Walkinshaw, Kirill Bogdanov, Ken Johnson
2008 J jnl
J. Softw. Maintenance Res. Pract.
Neil Walkinshaw, Kirill Bogdanov, Mike Holcombe, Sarah Salahuddin
2008 A* conf
ASE
Neil Walkinshaw, Kirill Bogdanov
2008 J jnl
Biosyst.
Mariam Kiran, Simon Coakley, Neil Walkinshaw, Phil McMinn, Mike Holcombe
2007 conf
Workshop on Membrane Computing
Francesco Bernardini, Marian Gheorghe, Francisco José Romero-Campero, Neil Walkinshaw
2007 conf
ICSM
Neil Walkinshaw, Marc Roper, Murray Wood
2007
Neil Walkinshaw
2007 conf
WCRE
Neil Walkinshaw, Kirill Bogdanov, Mike Holcombe, Sarah Salahuddin
2006 conf
TAIC PART
Neil Walkinshaw, Kirill Bogdanov, Mike Holcombe
2005 conf
IWPC
Neil Walkinshaw, Marc Roper, Murray Wood
2005 conf
Beyond Program Slicing
Douglas Samuel Kirk, Marc Roper, Neil Walkinshaw
2003 C conf
SCAM
Neil Walkinshaw, Marc Roper, Murray Wood
redb/extractors/apk_extractors/apk_inconsistency_tests.py
← Index redb/extractors/apk_extractors/apk_inconsistency_tests.py python
import inspect
import re
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 APKInconsistencyTests

# Emulator detection indicator strings
EMULATOR_INDICATORS = {
    "generic", "sdk", "google_sdk", "Emulator",
    "goldfish", "ranchu", "Andy", "Genymotion",
    "BlueStacks", "nox", "ttVM_Hdragon",
}

# Root detection indicator strings
ROOT_INDICATORS = {
    "/system/app/Superuser.apk",
    "/system/xbin/su",
    "/system/bin/su",
    "com.noshufou.android.su",
    "com.thirdparty.superuser",
    "eu.chainfire.supersu",
    "com.koushikdutta.superuser",
    "com.topjohnwu.magisk",
}

# Standard DEX filename pattern
STANDARD_DEX_PATTERN = re.compile(r"^classes\d*\.dex$")


class APKInconsistencyTestsExtractor(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.test_results = None
        self.log.debug(inspect.currentframe().f_code.co_name)

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

    def _test_zip_bomb(self):
        """Check if any ZIP entry has compression ratio > 100:1."""
        try:
            zf = self._get_zip_file()
            if not zf:
                return None
            with zf:
                for info in zf.infolist():
                    if info.compress_size > 0:
                        ratio = info.file_size / info.compress_size
                        if ratio > 100:
                            return True
            return False
        except Exception as e:
            self.log.warning(f"Error in zip bomb test: {e}")
            return None

    def _test_zip_duplicate_entries(self):
        """Check for duplicate filenames in ZIP directory."""
        try:
            zf = self._get_zip_file()
            if not zf:
                return None
            with zf:
                names = [info.filename for info in zf.infolist()]
                return len(names) != len(set(names))
        except Exception as e:
            self.log.warning(f"Error in duplicate entries test: {e}")
            return None

    def _test_zip_path_traversal(self):
        """Check for path traversal (../) in ZIP entry names."""
        try:
            for f in self._list_files():
                if ".." in f or f.startswith("/"):
                    return True
            return False
        except Exception as e:
            self.log.warning(f"Error in path traversal test: {e}")
            return None

    def _test_zip_suspicious_timestamps(self):
        """Check for timestamps at epoch (1980) or in the future."""
        try:
            zf = self._get_zip_file()
            if not zf:
                return None
            now = datetime.now()
            with zf:
                for info in zf.infolist():
                    try:
                        dt = datetime(*info.date_time)
                        if dt.year <= 1980 or dt > now:
                            return True
                    except (ValueError, TypeError):
                        continue
            return False
        except Exception as e:
            self.log.warning(f"Error in suspicious timestamps test: {e}")
            return None

    def _test_hidden_dex_files(self):
        """Check for DEX files not matching classes*.dex pattern."""
        try:
            for f in self._list_files():
                if f.endswith(".dex"):
                    basename = f.split("/")[-1]
                    if not STANDARD_DEX_PATTERN.match(basename):
                        return True
            return False
        except Exception as e:
            self.log.warning(f"Error in hidden DEX files test: {e}")
            return None

    def _test_manifest_component_mismatch(self):
        """Check for declared components that don't exist in DEX."""
        try:
            if not self._is_valid_apk():
                return None

            # Get all class names from DEX
            dex_classes = set()
            try:
                from androguard.core.dex import DEX
                for dex_data in (self.apk.get_all_dex() or []):
                    try:
                        d = DEX(dex_data)
                        for cls in d.get_classes():
                            name = cls.get_name()
                            if name:
                                # Convert "Lcom/example/Foo;" to "com.example.Foo"
                                dex_classes.add(
                                    name[1:-1].replace("/", ".") if name.startswith("L") else name
                                )
                    except Exception:
                        continue
            except Exception:
                return None

            if not dex_classes:
                return None

            # Check manifest components against DEX classes
            components = []
            try:
                components.extend(self.apk.get_activities() or [])
                components.extend(self.apk.get_services() or [])
                components.extend(self.apk.get_receivers() or [])
                components.extend(self.apk.get_providers() or [])
            except Exception:
                return None

            for comp in components:
                if comp and comp not in dex_classes:
                    # Component might use a shorthand; check with package prefix
                    package = self.apk.get_package() or ""
                    full_name = package + comp if comp.startswith(".") else comp
                    if full_name not in dex_classes:
                        return True

            return False
        except Exception as e:
            self.log.warning(f"Error in manifest component mismatch test: {e}")
            return None

    def _test_debuggable_release(self):
        """Check android:debuggable=true combined with a release signature."""
        try:
            if not self._is_valid_apk():
                return None

            is_debuggable = self.apk.get_attribute_value(
                "application", "debuggable"
            ) == "true"

            if not is_debuggable:
                return False

            # Check if it has a signing certificate (release builds have certs)
            try:
                certs = self.apk.get_certificates()
                if certs and len(certs) > 0:
                    return True
            except Exception:
                pass

            return False
        except Exception as e:
            self.log.warning(f"Error in debuggable release test: {e}")
            return None

    def _get_dex_strings(self):
        """Get all string constants from DEX files."""
        all_strings = set()
        try:
            from androguard.core.dex import DEX
            for dex_data in (self.apk.get_all_dex() or []):
                try:
                    d = DEX(dex_data)
                    for s in d.get_strings():
                        if s:
                            all_strings.add(s)
                except Exception:
                    continue
        except Exception:
            pass
        return all_strings

    def _test_emulator_detection_strings(self):
        """Check for emulator detection patterns in DEX strings."""
        try:
            if not self._is_valid_apk():
                return None

            dex_strings = self._get_dex_strings()
            for indicator in EMULATOR_INDICATORS:
                for s in dex_strings:
                    if indicator in s:
                        return True
            return False
        except Exception as e:
            self.log.warning(f"Error in emulator detection test: {e}")
            return None

    def _test_debugger_detection(self):
        """Check for debugger detection API calls in DEX."""
        try:
            if not self._is_valid_apk():
                return None

            dex_strings = self._get_dex_strings()
            debugger_patterns = {
                "isDebuggerConnected",
                "waitingForDebugger",
                "Debug.isDebuggerConnected",
            }
            for pattern in debugger_patterns:
                for s in dex_strings:
                    if pattern in s:
                        return True
            return False
        except Exception as e:
            self.log.warning(f"Error in debugger detection test: {e}")
            return None

    def _test_root_detection(self):
        """Check for root detection patterns in DEX."""
        try:
            if not self._is_valid_apk():
                return None

            dex_strings = self._get_dex_strings()
            for indicator in ROOT_INDICATORS:
                for s in dex_strings:
                    if indicator in s:
                        return True
            return False
        except Exception as e:
            self.log.warning(f"Error in root detection test: {e}")
            return None

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

        self.test_results = APKInconsistencyTests(
            test_zip_bomb=self._test_zip_bomb(),
            test_zip_duplicate_entries=self._test_zip_duplicate_entries(),
            test_zip_path_traversal=self._test_zip_path_traversal(),
            test_zip_suspicious_timestamps=self._test_zip_suspicious_timestamps(),
            test_hidden_dex_files=self._test_hidden_dex_files(),
            test_manifest_component_mismatch=self._test_manifest_component_mismatch(),
            test_debuggable_release=self._test_debuggable_release(),
            test_emulator_detection_strings=self._test_emulator_detection_strings(),
            test_debugger_detection=self._test_debugger_detection(),
            test_root_detection=self._test_root_detection(),
        )
        return self.test_results

    def _bool_to_nullable(self, val):
        """Convert bool/None to ClickHouse Nullable(UInt8)."""
        if val is None:
            return None
        return int(val)

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

            current_time = datetime.now(timezone.utc)
            t = self.test_results

            data = [[
                self.sha256,
                self._bool_to_nullable(t.test_zip_bomb),
                self._bool_to_nullable(t.test_zip_duplicate_entries),
                self._bool_to_nullable(t.test_zip_path_traversal),
                self._bool_to_nullable(t.test_zip_suspicious_timestamps),
                self._bool_to_nullable(t.test_hidden_dex_files),
                self._bool_to_nullable(t.test_manifest_component_mismatch),
                self._bool_to_nullable(t.test_debuggable_release),
                self._bool_to_nullable(t.test_emulator_detection_strings),
                self._bool_to_nullable(t.test_debugger_detection),
                self._bool_to_nullable(t.test_root_detection),
                current_time,
            ]]

            column_names = [
                'sha256',
                'test_zip_bomb', 'test_zip_duplicate_entries',
                'test_zip_path_traversal', 'test_zip_suspicious_timestamps',
                'test_hidden_dex_files', 'test_manifest_component_mismatch',
                'test_debuggable_release', 'test_emulator_detection_strings',
                'test_debugger_detection', 'test_root_detection',
                'analysis_date',
            ]

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

            return (data, column_names, column_type_names)

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