Xiaole Shirley Liu

29 papers Journal 27Unranked 2
YearRankTypeTitle / Venue / Authors
2020 J jnl
Genom. Proteom. Bioinform.
Ziyi Li, Binbin Wang, Shengqing Gu, Peng Jiang, Avinash Das Sahu, Chen-Hao Chen, Tong Han, Sailing Shi, Xiaoqing Wang, Nicole Traugh, Hailing Liu, Yin Liu, Qiu Wu, Myles Brown, Tengfei Xiao, Genevieve M. Boland, Xiaole Shirley Liu
2020 J jnl
Nucleic Acids Res.
Taiwen Li, Jingxin Fu, Zexian Zeng, David Cohen, Jing Li, Qianming Chen, Bo Li, Xiaole Shirley Liu
2019 J jnl
Bioinform.
Johannes Köster, Myles Brown, Xiaole Shirley Liu
2019 J jnl
Bioinform.
Johannes Köster, Myles Brown, Xiaole Shirley Liu
2019 J jnl
Nucleic Acids Res.
Rongbin Zheng, Changxin Wan, Shenglin Mei, Qian Qin, Qiu Wu, Hanfei Sun, Chen-Hao Chen, Myles Brown, Xiaoyan Zhang, Clifford A. Meyer, Xiaole Shirley Liu
2019 J jnl
Nucleic Acids Res.
Shaojuan Li, Changxin Wan, Rongbin Zheng, Jingyu Fan, Xin Dong, Clifford A. Meyer, Xiaole Shirley Liu
2018 J jnl
Bioinform.
Chen-Hao Chen, Tengfei Xiao, Han Xu, Peng Jiang, Clifford A. Meyer, Wei Li, Myles Brown, Xiaole Shirley Liu
2018 J jnl
BMC Bioinform.
MacIntosh Cornwell, Mahesh Vangala, Len Taing, Zachary Herbert, Johannes Köster, Bo Li, Hanfei Sun, Taiwen Li, Jian Zhang, Xintao Qiu, Matthew Pun, Rinath Jeselsohn, Myles Brown, Xiaole Shirley Liu, Henry W. Long
2017 J jnl
Nucleic Acids Res.
Shenglin Mei, Qian Qin, Qiu Wu, Hanfei Sun, Rongbin Zheng, Chongzhi Zang, Muyuan Zhu, Jiaxin Wu, Xiaohui Shi, Len Taing, Tao Liu, Myles Brown, Clifford A. Meyer, Xiaole Shirley Liu
2016 J jnl
Bioinform.
Jian Ma, Johannes Köster, Qian Qin, Shengen Hu, Wei Li, Chenhao Chen, Qingyi Cao, Jinzeng Wang, Shenglin Mei, Qi Liu, Han Xu, Xiaole Shirley Liu
2015 J jnl
PLoS Comput. Biol.
Naiqian Zhang, Haiyun Wang, Yun Fang, Jun Wang, Xiaoqi Zheng, Xiaole Shirley Liu
2014 J jnl
Nucleic Acids Res.
Qixuan Wang, Jinyan Huang, Hanfei Sun, Jing Liu, Juan Wang, Qian Wang, Qian Qin, Shenglin Mei, Chengchen Zhao, Xiaoqin Yang, Xiaole Shirley Liu, Yong Zhang
2014 J jnl
Nat.
Joshua Wing Kei Ho, Youngsook L. Jung, Tao Liu, Burak Han Alver, Soohyun Lee, Kohta Ikegami, Kyung-Ah Sohn, Aki Minoda, Michael Y. Tolstorukov, Alex Appert, Stephen C. J. Parker, Tingting Gu, Anshul Kundaje, Nicole C. Riddle, Eric Bishop, Thea A. Egelhofer, Sheng'en Shawn Hu, Artyom A. Alekseyenko, Andreas Rechtsteiner, Dalal Asker, Jason A. Belsky, Sarah K. Bowman, Q. Brent Chen, Ron A.-J. Chen, Daniel S. Day, Yan Dong, Andrea C. Dose, Xikun Duan, Charles B. Epstein, Sevinc Ercan, Elise A. Feingold, Francesco Ferrari, Jacob M. Garrigues, Nils Gehlenborg, Peter J. Good, Psalm Haseley, Daniel He, Moritz Herrmann, Michael M. Hoffman, Tess E. Jeffers, Peter V. Kharchenko, Paulina Kolasinska-Zwierz, Chitra V. Kotwaliwale, Nischay Kumar, Sasha A. Langley, Erica Larschan, Isabel Latorre, Maxwell W. Libbrecht, Xueqiu Lin, Richard Park, Michael J. Pazin, Hoang N. Pham, Annette Plachetka, Bo Qin, Yuri B. Schwartz, Noam Shoresh, Przemyslaw Stempor, Anne Vielle, Chengyang Wang, Christina M. Whittle, Huiling Xue, Robert E. Kingston, Ju Han Kim, Bradley E. Bernstein, Abby F. Dernburg, Vincenzo Pirrotta, Mitzi I. Kuroda, William S. Noble, Thomas D. Tullius, Manolis Kellis, David M. MacAlpine, Susan Strome, Sarah C. R. Elgin, Xiaole Shirley Liu, Jason D. Lieb, Julie Ahringer, Gary H. Karpen, Peter J. Park
2014 J jnl
Quant. Biol.
Mengyi Sun, Bingyu Yan, Chengkun Wu, Xiaole Shirley Liu
2013 J jnl
Bioinform.
Hanfei Sun, Bo Qin, Tao Liu, Qixuan Wang, Jing Liu, Juan Wang, Xueqiu Lin, Yulin Yang, Len Taing, Prakash K. Rao, Myles Brown, Yong Zhang, Henry Long, Xiaole Shirley Liu
2013 J jnl
Quant. Biol.
Hyunjin Shin, Tao Liu, Xikun Duan, Yong Zhang, Xiaole Shirley Liu
2012 J jnl
Bioinform.
Bo Qin, Meng Zhou, Ying Ge, Len Taing, Tao Liu, Qian Wang, Su Wang, Junsheng Chen, Lingling Shen, Xikun Duan, Sheng'en Hu, Wei Li, Henry Long, Yong Zhang, Xiaole Shirley Liu
2012 J jnl
Bioinform.
Kai Fu, Qianzi Tang, Jianxing Feng, Xiaole Shirley Liu, Yong Zhang
2012 J jnl
Bioinform.
Jianxing Feng, Clifford A. Meyer, Qian Wang, Jun S. Liu, Xiaole Shirley Liu, Yong Zhang
2011 J jnl
Bioinform.
Clifford A. Meyer, Housheng H. He, Myles Brown, Xiaole Shirley Liu
2011 J jnl
Nucleic Acids Res.
Qingyi Cao, Meng Zhou, Xujun Wang, Clifford A. Meyer, Yong Zhang, Zhi Chen, Cheng Li, Xiaole Shirley Liu
2009 J jnl
Bioinform.
Hyunjin Shin, Tao Liu, Arjun K. Manrai, Xiaole Shirley Liu
2007 J jnl
PLoS Comput. Biol.
Xiaole Shirley Liu
2007 J jnl
Bioinform.
Jun S. Song, Kaveh Maghsoudi, Wei Li, Edward Fox, John Quackenbush, Xiaole Shirley Liu
2007 conf
BIOCOMP
Wei Li, Jason S. Carroll, Myles Brown, Xiaole Shirley Liu
2006 J jnl
Nucleic Acids Res.
Xuwo Ji, Wei Li, Jun Song, Liping Wei, Xiaole Shirley Liu
2005 J jnl
Bioinform.
Pengyu Hong, Xiaole Shirley Liu, Qing Zhou, Xin Lu, Jun S. Liu, Wing Hung Wong
2005 conf
ISMB (Supplement of Bioinformatics)
Wei Li, Clifford A. Meyer, Xiaole Shirley Liu
2004 J jnl
Nucleic Acids Res.
Yueyi Liu, Liping Wei, Serafim Batzoglou, Douglas L. Brutlag, Jun S. Liu, Xiaole Shirley Liu
redb/extractors/apk_extractors/apk_resources.py
← Index redb/extractors/apk_extractors/apk_resources.py python
import hashlib
import inspect
import os
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 APKResource


# ─── Suspicious file types ──────────────────────────────────────────────
# File types that are suspicious when found inside res/ or assets/.
# Excludes javascript/html (extremely common in legitimate hybrid apps)
# and common media/font types that are normal APK content.
SUSPICIOUS_TYPES = {
    # Executables — no legitimate reason in assets/res
    "elf", "pebin", "macho", "dex", "apk",
    # Java containers — DexClassLoader target
    "jar",
    # Archives — rare in legitimate assets (~135:1 malware-to-benign ratio)
    "zip", "gzip", "7z", "xz", "tar", "bzip2", "rar", "7zip", "lzma",
    # Scripts with system execution capability
    "shell", "python", "powershell", "batch",
}

# ─── Entropy thresholds ─────────────────────────────────────────────────
# For unrecognized/unknown types: encrypted payloads typically land > 7.0
ENTROPY_HIGH_UNKNOWN = 7.0
# For recognized-but-non-image types: stricter threshold
ENTROPY_EXTREME = 7.85

# ─── Android-specific binary format magic bytes ─────────────────────────
# These formats are common in legitimate APKs but unknown to Magika,
# causing misclassification (e.g., AXML → "gzip", profm → "unknown").
AXML_MAGIC = b'\x03\x00\x08\x00'       # Android Binary XML (compiled res/*.xml)
ARSC_MAGIC = b'\x02\x00\x0c\x00'       # Android compiled resource table
ART_PROF_MAGIC = b'pro\x00'            # ART baseline profile
ART_PROFM_MAGIC = b'prm\x00'           # ART baseline profile metadata

# ─── Allowlisted paths ──────────────────────────────────────────────────
# Fixed, hardcoded paths in the Android build system that are always benign.
# ART profiles at these exact paths are shipped by Jetpack ProfileInstaller.
ALLOWLISTED_PATHS = {
    "assets/dexopt/baseline.prof",
    "assets/dexopt/baseline.profm",
}

# ─── Image handling ─────────────────────────────────────────────────────
# Magika-confirmed image types: high entropy is expected (lossy codecs
# like VP8/JPEG arithmetic-code toward entropy ~7.95-8.0 by design).
IMAGE_MAGIKA_TYPES = {"png", "webp", "jpeg", "gif", "bmp", "tiff", "ico"}
IMAGE_EXTENSIONS = {".png", ".webp", ".jpg", ".jpeg", ".gif", ".bmp", ".tiff", ".ico"}

# ─── Types Magika assigns when it can't identify the content ────────────
UNRECOGNIZED_MAGIKA_TYPES = {"unknown", "empty"}

# ─── Resource scan limits ───────────────────────────────────────────────
MAX_RESOURCE_FILES = 5000


class APKResourceExtractor(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.resources = []
        self.suspicious_files = []
        self.log.debug(inspect.currentframe().f_code.co_name)

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

    # ─── Core classification logic ──────────────────────────────────────

    def _identify_android_format(self, header: bytes) -> str | None:
        """
        Identify Android-specific binary formats that Magika doesn't know.
        Returns a corrected type label, or None to fall through to Magika.
        """
        if len(header) < 4:
            return None

        magic4 = header[:4]

        # Android Binary XML — all res/*.xml in a compiled APK.
        # Magika often misclassifies this as "gzip".
        if magic4 == AXML_MAGIC:
            return "android_binary_xml"

        # Android compiled resource table (resources.arsc chunks)
        if magic4 == ARSC_MAGIC:
            return "android_resource_table"

        # ART baseline profiles — high entropy (zlib inside) but benign.
        # The format is inert (method reference bitmaps/metadata, not
        # executable code) and some build configs place them at varying paths.
        if magic4 == ART_PROF_MAGIC:
            return "android_art_profile"
        if magic4 == ART_PROFM_MAGIC:
            return "android_art_profile_metadata"

        return None

    def _is_suspicious_resource(
        self, path: str, magika_type: str, entropy: float,
        android_type: str | None,
    ) -> bool:
        """
        Determine if a resource file is suspicious.

        Detection layers:
        1. Allowlisted paths → always benign
        2. Android-specific format override → reclassify Magika mislabels
        3. Image extension vs Magika type mismatch → encrypted blob detection
        4. Magika-confirmed images → benign regardless of entropy
        5. Suspicious type match → flag known-dangerous types
        6. High-entropy unknown blobs → likely encrypted payloads
        """

        # ── Layer 1: Allowlisted paths (hardcoded Android build artifacts) ──
        if path in ALLOWLISTED_PATHS:
            return False

        # ── Layer 2: Android-specific format detection ──────────────────────
        # Override Magika's label for formats it doesn't recognize.
        # All Android-specific formats (AXML, ARSC, ART profiles) are
        # legitimate build artifacts — never suspicious.
        if android_type is not None:
            return False

        # ── Layer 3: Image extension / Magika type mismatch ─────────────────
        # If the file extension claims "image" but Magika's content analysis
        # disagrees, this is a strong signal for an encrypted payload with
        # a fake image extension (e.g., ErrorFather's "rbyypivsnw.png").
        ext = os.path.splitext(path)[1].lower()
        if ext in IMAGE_EXTENSIONS and magika_type not in IMAGE_MAGIKA_TYPES:
            # Exception: Magika might label a valid image as "unknown" if
            # the file is very small (< ~16 bytes). Don't flag tiny files.
            if entropy > 5.0:
                return True

        # ── Layer 4: Magika-confirmed images → benign ───────────────────────
        # Lossy codecs (VP8, JPEG) produce entropy up to ~8.0 by design.
        # If Magika confirms image structure, high entropy is expected.
        if magika_type in IMAGE_MAGIKA_TYPES:
            return False

        # ── Layer 5: Known suspicious file types ────────────────────────────
        if magika_type in SUSPICIOUS_TYPES:
            return True

        # ── Layer 6: High-entropy unrecognized blobs ────────────────────────
        # Files Magika can't identify with high entropy are likely encrypted
        # payloads. Most Android malware packers store encrypted DEX/SO
        # payloads as opaque blobs with random names and no valid magic.
        if magika_type in UNRECOGNIZED_MAGIKA_TYPES and entropy > ENTROPY_HIGH_UNKNOWN:
            return True

        # ── Layer 7: Extreme entropy on any non-image recognized type ───────
        # Catches edge cases where Magika assigns a benign label (e.g.,
        # "xml", "txt") but the entropy is impossibly high for that format.
        if magika_type not in IMAGE_MAGIKA_TYPES and entropy > ENTROPY_EXTREME:
            return True

        return False

    # ─── Extraction pipeline ────────────────────────────────────────────

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

        try:
            from magika import Magika
            magika = Magika()
        except Exception as e:
            self.log.error(f"Failed to initialize Magika for {self.hash.sha256}: {e}")
            magika = None

        self.resources = []
        self.suspicious_files = []
        scanned = 0

        zf = self._get_zip_file()
        if not zf:
            return None

        with zf:
            for info in zf.infolist():
                if info.is_dir():
                    continue
                if not (info.filename.startswith("res/") or
                        info.filename.startswith("assets/")):
                    continue

                if scanned >= MAX_RESOURCE_FILES:
                    self.log.warning(
                        f"Resource scan limit reached ({MAX_RESOURCE_FILES}), "
                        f"stopping resource enumeration"
                    )
                    break
                scanned += 1

                try:
                    data = zf.read(info.filename)
                except Exception as e:
                    self.log.warning(
                        f"Error reading resource {info.filename}: {e}"
                    )
                    continue

                try:
                    file_sha256 = hashlib.sha256(data).hexdigest()
                    file_entropy = round(self.calculate_entropy(data), 3)

                    # Read first bytes for Android-specific format detection
                    header = data[:16] if len(data) >= 16 else data

                    if magika:
                        try:
                            filetype = magika.identify_bytes(data).output.label
                        except Exception:
                            filetype = "unknown"
                    else:
                        filetype = "unknown"

                    # Identify Android-specific formats once, reuse for
                    # both stored type and suspicion classification
                    android_type = self._identify_android_format(header)
                    stored_type = android_type if android_type else filetype

                    suspicious = self._is_suspicious_resource(
                        path=info.filename,
                        magika_type=filetype,
                        entropy=file_entropy,
                        android_type=android_type,
                    )

                    resource = APKResource(
                        path=info.filename,
                        size=info.file_size,
                        sha256=file_sha256,
                        filetype_magika=stored_type,
                        entropy=file_entropy,
                    )

                    if suspicious:
                        resource.is_suspicious = True
                        self.suspicious_files.append(resource)

                    self.resources.append(resource)
                except Exception as e:
                    self.log.warning(
                        f"Error processing resource {info.filename}: {e}"
                    )
                    continue

        if not self.resources:
            return None

        return {
            "total_resource_count": len(self.resources),
            "total_resource_size": sum(r.size for r in self.resources),
            "suspicious_file_count": len(self.suspicious_files),
            "resources": self.resources,
            "suspicious_files": self.suspicious_files,
        }

    # ─── Export ──────────────────────────────────────────────────────────

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

            current_time = datetime.now(timezone.utc)
            data = []
            for res in self.resources:
                data.append([
                    self.sha256,
                    res.path,
                    res.size,
                    res.sha256,
                    res.filetype_magika,
                    res.entropy,
                    int(res.is_suspicious),
                    current_time,
                ])

            column_names = [
                'sha256', 'resource_path', 'resource_size',
                'resource_sha256', 'resource_magika', 'resource_entropy',
                'is_suspicious', 'analysis_date',
            ]

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

            return (data, column_names, column_type_names)

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