Makoto Okabe

47 papers A* 2A 1B 3C 1Misc 2Journal 14Unranked 22
YearRankTypeTitle / Venue / Authors
2022 J jnl
IEEE Access
Yudai Watanabe, Makoto Okabe, Yasunori Harada, Naoji Kashima
2022 B conf
ICIP
Yudai Watanabe, Makoto Okabe, Yasunori Harada, Naoji Kashima
2022 J jnl
CoRR
Yudai Watanabe, Makoto Okabe, Yasunori Harada, Naoji Kashima
2021 ed.
PG (Short Papers, Posters, and Work-in-Progress Papers)
Sung-Hee Lee, Stefanie Zollmann, Makoto Okabe, Burkhard Wünsche
2020 ed.
PG (Short Papers, Posters, and Work-in-Progress Papers)
Sung-Hee Lee, Stefanie Zollmann, Makoto Okabe, Burkhard Wünsche
2020 conf
PG (Short Papers, Posters, and Work-in-Progress Papers)
Satsuki Tsubota, Makoto Okabe
2020 J jnl
IEEE Computer Graphics and Applications
Makoto Okabe, Keita Noda, Yoshinori Dobashi, Ken Anjyo
2019 J jnl
Vis. Comput.
Yoshinori Dobashi, Kei Iwasaki, Makoto Okabe, Takashi Ijiri, Hideki Todo
2018 J jnl
Vis. Comput.
Makoto Okabe, Yoshinori Dobashi, Ken Anjyo
2017 conf
SCCG
Takuya Yamakawa, Yoshinori Dobashi, Makoto Okabe, Kei Iwasaki, Tsuyoshi Yamamoto
2017 C conf
CGI
Kei Iwasaki, Yoshinori Dobashi, Makoto Okabe
2016 conf
BigMM
Takao Kakimori, Makoto Okabe, Keiji Yanai, Rikio Onai
2016 conf
SIGGRAPH Posters
Yoshinori Dobashi, Takashi Ijiri, Hideki Todo, Kei Iwasaki, Makoto Okabe, Satoshi Nishimura
2015 conf
SIGGRAPH Asia Mobile Graphics and Interactive Applications
Takao Kakimori, Makoto Okabe, Keiji Yanai, Rikio Onai
2015 J jnl
ACM Trans. Graph.
Makoto Okabe, Yoshinori Dobashi, Ken Anjyo, Rikio Onai
2014 conf
SIGGRAPH Posters
Morgane Rivière, Makoto Okabe
2013 conf
MMM (1)
Kenta Mizui, Makoto Okabe, Rikio Onai
2013 conf
UIST (Adjunct Volume)
Tatsuya Kurihara, Makoto Okabe, Rikio Onai
2013 Misc conf
WSCG
Tomohiro Yamamoto, Makoto Okabe, Yusuke Hijikata, Rikio Onai
2013 conf
MMM (2)
Makoto Okabe, Yuta Kawate, Ken Anjyo, Rikio Onai
2012 conf
DigiPro
Makoto Okabe, Ken Anjyo, Rikio Onai
2012 B conf
VL/HCC
Hikaru Nagasaka, Makoto Okabe, Rikio Onai
2012 conf
Web Intelligence
Masanao Ochi, Yutaka Matsuo, Makoto Okabe, Rikio Onai
2012 conf
SIGGRAPH Posters
Tomohiro Yamamoto, Makoto Okabe, Rikio Onai
2012 conf
SIGGRAPH Posters
Yuta Kawate, Makoto Okabe, Rikio Onai, Hiromi Hirano, Masahiro Sanjo
2011 conf
SIGGRAPH Asia Posters
Kenta Mizui, Makoto Okabe, Rikio Onai
2011 J jnl
Comput. Graph. Forum
Makoto Okabe, Ken Anjyo, Rikio Onai
2011 A conf
CIKM
Kazufumi Watanabe, Masanao Ochi, Makoto Okabe, Rikio Onai
2011 A* conf
SIGIR
Masanao Ochi, Makoto Okabe, Rikio Onai
2010 J jnl
Vis. Comput.
Dawid Pajak, Martin Cadík, Tunç Ozan Aydin, Makoto Okabe, Karol Myszkowski, Hans-Peter Seidel
2009 J jnl
Comput. Graph. Forum
Makoto Okabe, Ken-ichi Anjyo, Takeo Igarashi, Hans-Peter Seidel
2009 J jnl
ACM Trans. Graph.
Tobias Ritschel, Makoto Okabe, Thorsten Thormählen, Hans-Peter Seidel
2008 J jnl
ACM Trans. Graph.
Kenshi Takayama, Makoto Okabe, Takashi Ijiri, Takeo Igarashi
2007 B conf
TEI
Ivan Poupyrev, Tatsushi Nashida, Makoto Okabe
2007 conf
Smart Graphics
Shigeru Owada, Makoto Okabe, Takeo Igarashi, Frank Nielsen, Norimichi Tsumura
2007 conf
SIGGRAPH Courses
Takashi Ijiri, Shigeru Owada, Makoto Okabe, Takeo Igarashi
2007 Misc conf
PG
Makoto Okabe, Yasuyuki Matsushita, Li Shen, Takeo Igarashi
2007 conf
SIGGRAPH Courses
Makoto Okabe, Shigeru Owada, Takeo Igarashi
2007 conf
SIGGRAPH Sketches
Makoto Okabe, Kenshi Takayama, Takashi Ijiri, Takeo Igarashi
2006 conf
SIGGRAPH Courses
Takashi Ijiri, Shigeru Owada, Makoto Okabe, Takeo Igarashi
2006 conf
SIGGRAPH Research Posters
Makoto Okabe, Yasuyuki Matsushita, Takeo Igarashi, Heung-Yeung Shum
2006 conf
SIGGRAPH Courses
Makoto Okabe, Shigeru Owada, Takeo Igarashi
2005 J jnl
ACM Trans. Graph.
Takashi Ijiri, Shigeru Owada, Makoto Okabe, Takeo Igarashi
2005 J jnl
Comput. Graph. Forum
Makoto Okabe, Shigeru Owada, Takeo Igarashi
2004 conf
CHI Extended Abstracts
Ivan Poupyrev, Makoto Okabe, Shigeaki Maruyama
2004 J jnl
ACM Trans. Graph.
Shigeru Owada, Frank Nielsen, Makoto Okabe, Takeo Igarashi
2003 A* conf
SIGGRAPH
Makoto Okabe, Takeo Igarashi
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"