Xia Yin

147 papers A* 15A 4B 30C 16Journal 58Unranked 24
YearRankTypeTitle / Venue / Authors
2026 A* conf
WWW
Yunze Wei, Xingang Shi, Han Zhang, Tianyu Zhang, Yahui Li, Xia Yin
2026 J jnl
IEEE Trans. Inf. Forensics Secur.
Kaiyang Zhao, Han Zhang, Yahui Li, Xingang Shi, Zhiliang Wang, Xia Yin, Jiankun Hu, Jianping Wu
2026 J jnl
IEEE Trans. Inf. Forensics Secur.
Haoran Jiao, Cong Dong, Chenglong Li, Jiahai Yang, Leyao Nie, Yuling Liu, Jing Wang, Changzhi Zhao, Xia Yin
2026 J jnl
CoRR
Renrui Tian, Yahui Li, Xia Yin, Han Zhang, Xingang Shi, Zhiliang Wang
2026 J jnl
IEEE Trans. Netw.
Zitong Jin, Xingang Shi, Zhaozhen Wang, Kaiyang Zhao, Zhiliang Wang, Xia Yin
2025 J jnl
Comput. Networks
Jiangyuan Yao, Weiyang Xin, Xia Yin, Xingang Shi, Zhiliang Wang, Li Zhou, Ting Jin
2025 A* conf
WWW
Tianyu Zhang, Han Zhang, Yunze Wei, Yahui Li, Xingang Shi, Jilong Wang, Xia Yin
2025 A* conf
SIGCOMM
Han Zhang, Guyue Liu, Xingang Shi, Yahui Li, Dongbiao He, Jilong Wang, Zhiliang Wang, Yongqing Zhu, Ke Ruan, Weihua Cao, Xia Yin
2025 J jnl
Comput. Networks
Ying Tian, Zhiliang Wang, Xia Yin, Xingang Shi, Jiahai Yang, Han Zhang
2025 A* conf
INFOCOM
Zitong Jin, Xingang Shi, Ying Tian, Zhiliang Wang, Xia Yin, Jianping Wu
2025 J jnl
IEEE Trans. Netw.
Ying Tian, Zhiliang Wang, Xia Yin, Xingang Shi, Jiahai Yang, Han Zhang
2025 J jnl
Cybersecur.
Cong Dong, Jiahai Yang, Yun Li, Haoran Jiao, Chenglong Li, Xia Yin, Yuling Liu
2025 J jnl
IEEE Trans. Inf. Forensics Secur.
Su Wang, Hongbin Sun, Zhiliang Wang, Tao Zhou, Xia Yin, Dongqi Han, Han Zhang, Xingang Shi, Jiahai Yang
2025 J jnl
IEEE Trans. Netw.
Xingang Shi, Zitong Jin, Bin Xiong, Xinyao Huang, Xiaotian Xi, Dan Li, Han Zhang, Zhiliang Wang, Xia Yin
2025 A* conf
SIGCOMM
Yantao Geng, Han Zhang, Zhiheng Wu, Yahui Li, Jilong Wang, Xia Yin
2025 A* conf
INFOCOM
Zhaozhen Wang, Xingang Shi, Haijun Geng, Zitong Jin, Han Zhang, Xia Yin, Zhiliang Wang
2025 B conf
ICNP
Wei Zhang, Gang Ren, Xia Yin, Lin He
2025 A* conf
CCS
Renrui Tian, Yahui Li, Han Zhang, Xinzhe Liu, Xia Yin, Xingang Shi, Zhiliang Wang, Jilong Wang
2025 conf
CoNEXT (Short Papers)
Yanbo Yin, Yahui Li, Han Zhang, Xia Yin, Shibo Cui, Xingang Shi, Qiang Ma, Zhiliang Wang
2025 B conf
IWQoS
Zhiyun Tang, Yahui Li, Ke Ruan, Yongqing Zhu, Yingjun Ye, Jilong Wang, Xia Yin, Xingang Shi, Han Zhang
2025 conf
SIGMETRICS (Abstracts)
Zhaozhen Wang, Xingang Shi, Zhengfeng Ji, Xia Yin
2025 J jnl
Proc. ACM Meas. Anal. Comput. Syst.
Zhaozhen Wang, Xingang Shi, Zhengfeng Ji, Xia Yin
2025 B conf
IWQoS
Wei Zhang, Gang Ren, Xia Yin, Lin He
2025 B conf
ICNP
Kaiyang Zhao, Han Zhang, Yao Tong, Yahui Li, Xingang Shi, Zhiliang Wang, Xia Yin, Jianping Wu
2025 J jnl
Proc. ACM Netw.
Xinzhe Liu, Yahui Li, Han Zhang, Xia Yin, Xingang Shi, Zhiliang Wang, Gang Ren, Jilong Wang, Jiangyuan Yao
2025 A* conf
INFOCOM
Zitong Jin, Xingang Shi, Qiang Ma, Letong Sun, Zhiliang Wang, Xia Yin, Jianping Wu
2024 J jnl
CoRR
Ying Tian, Zhiliang Wang, Xia Yin, Xingang Shi, Jiahai Yang, Han Zhang
2024 J jnl
Comput. Networks
Weihan Chen, Zhiliang Wang, Han Zhang, Xia Yin, Xingang Shi
2024 J jnl
CoRR
Cong Dong, Jiahai Yang, Yun Li, Yue Wu, Yufan Chen, Chenglong Li, Haoran Jiao, Xia Yin, Yuling Liu
2024 J jnl
CoRR
Letong Sun, Xingang Shi, Fengyan Han, Xia Yin, Zhiliang Wang, Han Zhang
2024 J jnl
Comput. Networks
Wenqi Chen, Zhiliang Wang, Liyuan Chang, Kai Wang, Ying Zhong, Dongqi Han, Chenxin Duan, Xia Yin, Jiahai Yang, Xingang Shi
2024 conf
SIGCOMM (Posters and Demos)
Xinzhe Liu, Yahui Li, Han Zhang, Xia Yin, Xingang Shi, Zhiliang Wang, Gang Ren, Jiangyuan Yao
2024 J jnl
IEEE Trans. Inf. Forensics Secur.
Yahui Li, Han Zhang, Jilong Wang, Xingang Shi, Xia Yin, Zhiliang Wang, Jiankun Hu, Congcong Miao, Jianping Wu
2024 A* conf
CCS
Dongqi Han, Zhiliang Wang, Ruitao Feng, Minghui Jin, Wenqi Chen, Kai Wang, Su Wang, Jiahai Yang, Xingang Shi, Xia Yin, Yang Liu
2023 J jnl
IEEE Trans. Parallel Distributed Syst.
Yahui Li, Han Zhang, Jilong Wang, Zhiliang Wang, Xia Yin, Xingang Shi, Jianping Wu
2023 J jnl
IEEE/ACM Trans. Netw.
Han Zhang, Xia Yin, Xingang Shi, Jilong Wang, Zhiliang Wang, Yingya Guo, Tian Lan, Yahui Li, Yongqing Zhu, Ke Ruan, Haijun Geng
2023 A* conf
NDSS
Dongqi Han, Zhiliang Wang, Wenqi Chen, Kai Wang, Rui Yu, Su Wang, Han Zhang, Zhihua Wang, Minghui Jin, Jiahai Yang, Xingang Shi, Xia Yin
2023 A* conf
NDSS
Kai Wang, Zhiliang Wang, Dongqi Han, Wenqi Chen, Jiahai Yang, Xingang Shi, Xia Yin
2023 B conf
IFIP Networking
Dongqi Han, Shangdong Wang, Zhize He, Zhiliang Wang, Wenqi Chen, Chenglong Li, Jiahai Yang, Xingang Shi, Xia Yin
2023 B conf
IWQoS
Yantao Geng, Han Zhang, Xingang Shi, Jilong Wang, Xia Yin, Dongbiao He, Yahui Li
2023 A* conf
SIGCOMM
Junxian Shen, Han Zhang, Yang Xiang, Xingang Shi, Xinrui Li, Yunxi Shen, Zijian Zhang, Yongxiang Wu, Xia Yin, Jilong Wang, Mingwei Xu, Yahui Li, Jiping Yin, Jianchang Song, Zhuofeng Li, Runjie Nie
2023 J jnl
IEEE Trans. Inf. Forensics Secur.
Pei Zhang, Fangzhou He, Han Zhang, Jiankun Hu, Xiaohong Huang, Jilong Wang, Xia Yin, Huahong Zhu, Yahui Li
2022 B conf
ICNP
Ying Tian, Zhiliang Wang, Xia Yin, Xingang Shi, Jiahai Yang, Han Zhang
2022 J jnl
IEEE Trans. Parallel Distributed Syst.
Zongyi Zhao, Xingang Shi, Zhiliang Wang, Qing Li, Han Zhang, Xia Yin
2022 J jnl
Comput. Networks
Yan Yang, Xingang Shi, Qiang Ma, Yahui Li, Xia Yin, Zhiliang Wang
2022 A* conf
NDSS
Wenqi Chen, Zhiliang Wang, Dongqi Han, Chenxin Duan, Xia Yin, Jiahai Yang, Xingang Shi
2022 J jnl
IEEE Trans. Inf. Forensics Secur.
Su Wang, Zhiliang Wang, Tao Zhou, Hongbin Sun, Xia Yin, Dongqi Han, Han Zhang, Xingang Shi, Jiahai Yang
2021 B conf
IM
Wenqi Chen, Zhiliang Wang, Ying Zhong, Dongqi Han, Chenxin Duan, Xia Yin, Jiahai Yang, Xingang Shi
2021 A conf
CoNEXT
Han Zhang, Xingang Shi, Xia Yin, Jilong Wang, Zhiliang Wang, Yingya Guo, Tian Lan
2021 B conf
IWQoS
Zongyi Zhao, Xingang Shi, Arpit Gupta, Qing Li, Zhiliang Wang, Bin Xiong, Xia Yin
2021 B conf
CNSM
Weihan Chen, Zhiliang Wang, Han Zhang, Xia Yin, Xingang Shi
2021 A* conf
CCS
Dongqi Han, Zhiliang Wang, Wenqi Chen, Ying Zhong, Su Wang, Han Zhang, Jiahai Yang, Xingang Shi, Xia Yin
2021 J jnl
CoRR
Dongqi Han, Zhiliang Wang, Wenqi Chen, Ying Zhong, Su Wang, Han Zhang, Jiahai Yang, Xingang Shi, Xia Yin
2021 J jnl
IEEE J. Sel. Areas Commun.
Dongqi Han, Zhiliang Wang, Ying Zhong, Wenqi Chen, Jiahai Yang, Shuqiang Lu, Xingang Shi, Xia Yin
2021 J jnl
IEEE Trans. Inf. Forensics Secur.
Shangbin Han, Qianhong Wu, Han Zhang, Bo Qin, Jiankun Hu, Xingang Shi, Linfeng Liu, Xia Yin
2021 J jnl
Comput. Commun.
Yingya Guo, Huan Luo, Zhiliang Wang, Xia Yin, Jianping Wu
2021 C conf
ISCC
Ying Zhong, Ziqi Gao, Rui Li, Citong Que, Xinjie Yang, Zhiliang Wang, Jiahai Yang, Xia Yin, Xingang Shi, Keqin Li
2021 J jnl
J. Netw. Comput. Appl.
Yingya Guo, Weipeng Wang, Han Zhang, Wenzhong Guo, Zhiliang Wang, Ying Tian, Xia Yin, Jianping Wu
2021 B conf
CNSM
Ying Tian, Zhiliang Wang, Xia Yin, Xingang Shi, Jiahai Yang, Han Zhang, Yingya Guo, Haijun Geng
2021 J jnl
CoRR
Su Wang, Zhiliang Wang, Tao Zhou, Xia Yin, Dongqi Han, Han Zhang, Hongbin Sun, Xingang Shi, Jiahai Yang
2020 J jnl
J. Commun. Networks
Haijun Geng, Han Zhang, Xingang Shi, Zhiliang Wang, Xia Yin, Ju Zhang, Zhiguo Hu, Yong Wu
2020 conf
WASA (1)
Ying Zhong, Yiran Zhu, Zhiliang Wang, Xia Yin, Xingang Shi, Keqin Li
2020 J jnl
Comput. Networks
Yahui Li, Zhiliang Wang, Xia Yin, Xingang Shi, Jianping Wu, Fangdan Ye, Jiangyuan Yao, Han Zhang
2020 J jnl
J. Netw. Comput. Appl.
Haijun Geng, Han Zhang, Xingang Shi, Zhiliang Wang, Xia Yin
2020 J jnl
Comput. Networks
Ying Zhong, Wenqi Chen, Zhiliang Wang, Yifan Chen, Kai Wang, Yahui Li, Xia Yin, Xingang Shi, Jiahai Yang, Keqin Li
2020 conf
INFOCOM Workshops
Su Wang, Zhiliang Wang, Xia Yin, Xingang Shi
2020 conf
INFOCOM Workshops
Weihan Chen, Zhiliang Wang, Han Zhang, Xia Yin, Xingang Shi, Lei Sun
2020 J jnl
CoRR
Dongqi Han, Zhiliang Wang, Ying Zhong, Wenqi Chen, Jiahai Yang, Shuqiang Lu, Xingang Shi, Xia Yin
2020 C conf
ISCC
Yan Yang, Xingang Shi, Xia Yin, Zhiliang Wang, Xingyu Zhou
2020 A conf
Internet Measurement Conference
Zitong Jin, Xingang Shi, Yan Yang, Xia Yin, Zhiliang Wang, Jianping Wu
2020 J jnl
IEEE/ACM Trans. Netw.
Ying Tian, Zhiliang Wang, Xia Yin, Xingang Shi, Yingya Guo, Haijun Geng, Jiahai Yang
2019 J jnl
IEEE Commun. Surv. Tutorials
Yahui Li, Xia Yin, Zhiliang Wang, Jiangyuan Yao, Xingang Shi, Jianping Wu, Han Zhang, Qing Wang
2019 J jnl
IEEE/ACM Trans. Netw.
Han Zhang, Haijun Geng, Yahui Li, Xia Yin, Xingang Shi, Zhiliang Wang, Qianhong Wu, Jianwei Liu
2019 J jnl
IEEE Trans. Parallel Distributed Syst.
Zhiliang Wang, Han Zhang, Xingang Shi, Xia Yin, Yahui Li, Haijun Geng, Qianhong Wu, Jianwei Liu
2019 A conf
ICDCS
Zongyi Zhao, Xingang Shi, Xia Yin, Zhiliang Wang, Qing Li
2019 J jnl
Comput. Networks
Yan Yang, Xia Yin, Xingang Shi, Zhiliang Wang, Jiong He, Tom Z. J. Fu, Marianne Winslett
2019 J jnl
J. Netw. Comput. Appl.
Yingya Guo, Zhiliang Wang, Han Zhang, Xia Yin, Xingang Shi, Jianping Wu
2019 J jnl
Comput. Networks
Yahui Li, Zhiliang Wang, Jiangyuan Yao, Xia Yin, Xingang Shi, Jianping Wu, Han Zhang
2019 J jnl
CoRR
Weihan Chen, Xia Yin, Zhiliang Wang, Xingang Shi
2019 J jnl
Comput. Networks
Yingya Guo, Zhiliang Wang, Zhifeng Liu, Xia Yin, Xingang Shi, Jianping Wu, Yang Xu, H. Jonathan Chao
2019 C conf
ISCC
Zhifeng Liu, Zhiliang Wang, Xia Yin, Xingang Shi, Yingya Guo, Ying Tian
2018 J jnl
Comput. Commun.
Haijun Geng, Xingang Shi, Zhiliang Wang, Xia Yin
2018 conf
INFOCOM Workshops
Yahui Li, Zhiliang Wang, Xia Yin, Xingang Shi, Jianping Wu, Jiangyuan Yao, Yingya Guo
2018 conf
ICCCS (3)
Zhiliang Wang, Changping Zhou, Yang Yu, Xingang Shi, Xia Yin, Jiangyuan Yao
2018 J jnl
CoRR
Zongyi Zhao, Xingang Shi, Xia Yin, Zhiliang Wang
2018 J jnl
CoRR
Zongyi Zhao, Xingang Shi, Xia Yin, Zhiliang Wang
2018 J jnl
计算机科学
Haijun Geng, Xingang Shi, Zhiliang Wang, Xia Yin, Shaoping Yin
2017 J jnl
J. Commun. Networks
Haijun Geng, Xingang Shi, Xia Yin, Zhiliang Wang, Shaoping Yin
2017 C conf
ISCC
Geng Tian, Zhiliang Wang, Xia Yin, Jun Chen, Xingang Shi, Chao Zhou, Zimu Li, Yingya Guo
2017 B conf
ICCCN
Yingya Guo, Zhiliang Wang, Xia Yin, Xingang Shi, Jianping Wu
2017 C conf
IPCCC
Han Zhang, Xingang Shi, Yingya Guo, Haijun Geng, Zhiliang Wang, Xia Yin
2017 B conf
ICNP
Yahui Li, Zhiliang Wang, Jiangyuan Yao, Xia Yin, Xingang Shi, Jianping Wu
2017 J jnl
Comput. Networks
Han Zhang, Xingang Shi, Yingya Guo, Zhiliang Wang, Xia Yin
2017 B conf
ICCCN
Yingya Guo, Zhiliang Wang, Xia Yin, Xingang Shi, Jianping Wu
2017 B conf
MASCOTS
Jiangyuan Yao, Zhiliang Wang, Xia Yin, Xingang Shi, Yahui Li, Chongrong Li
2017 J jnl
Comput. Networks
Yingya Guo, Zhiliang Wang, Xia Yin, Xingang Shi, Jianping Wu
2017 B conf
ICNP
Han Zhang, Xingang Shi, Xia Yin, Zhiliang Wang
2017 J jnl
计算机科学
Haijun Geng, Xingang Shi, Zhiliang Wang, Xia Yin, Shaoping Yin
2016 B conf
IWQoS
Han Zhang, Xingang Shi, Xia Yin, Zhiliang Wang, Yingya Guo
2016 conf
Trustcom/BigDataSE/ISPA
Yan Yang, Xingang Shi, Xia Yin, Zhiliang Wang
2015 conf
INFOCOM Workshops
Geng Tian, Zhiliang Wang, Xia Yin, Zimu Li, Xingang Shi, Ziyi Lu, Chao Zhou, Yingya Guo
2015 B conf
IWQoS
Haijun Geng, Xingang Shi, Xia Yin, Zhiliang Wang, Han Zhang
2015 conf
ICC
Haijun Geng, Xingang Shi, Xia Yin, Zhiliang Wang, Han Zhang
2015 J jnl
Comput. Networks
Xia Yin, Dan Wu, Zhiliang Wang, Xingang Shi, Jianping Wu
2015 C conf
IPCCC
Yingya Guo, Zhiliang Wang, Xia Yin, Xingang Shi, Jianping Wu, Han Zhang
2015 C conf
IPCCC
Dan Wu, Zhiliang Wang, Xia Yin, Xingang Shi, Jianping Wu
2015 B conf
IWQoS
Geng Tian, Zhiliang Wang, Xia Yin, Zimu Li, Xingang Shi, Ziyi Lu, Chao Zhou, Yang Yu, Yingya Guo
2015 J jnl
IEICE Trans. Inf. Syst.
Xia Yin, Jiangyuan Yao, Zhiliang Wang, Xingang Shi, Jun Bi, Jianping Wu
2015 A* conf
INFOCOM
Han Zhang, Xingang Shi, Xia Yin, Fengyuan Ren, Zhiliang Wang
2015 C conf
SecureComm
Geng Tian, Zhiliang Wang, Xia Yin, Zimu Li, Xingang Shi, Ziyi Lu, Chao Zhou, Yang Yu, Dan Wu
2014 C conf
IPCCC
Haijun Geng, Xingang Shi, Xia Yin, Zhiliang Wang, Han Zhang, Jiangyuan Yao
2014 B conf
ICNP
Jiangyuan Yao, Zhiliang Wang, Xia Yin, Xingang Shi, Jianping Wu
2014 B conf
ICCCN
Dan Wu, Zhiliang Wang, Xia Yin, Xingang Shi, Jianping Wu, Wenlong Chen
2014 C conf
IPCCC
Haijun Geng, Xingang Shi, Xia Yin, Zhiliang Wang, Han Zhang, Jiangyuan Yao
2014 conf
CoNEXT Student Workshop
Jiangyuan Yao, Zhiliang Wang, Xia Yin, Xingang Shi, Jianping Wu, Yahui Li
2014 C conf
IPCCC
Jiangyuan Yao, Zhiliang Wang, Xia Yin, Xingang Shi, Jianping Wu, Yahui Li
2014 B conf
ICNP
Yingya Guo, Zhiliang Wang, Xia Yin, Xingang Shi, Jianping Wu
2013 conf
HPCC/EUC
Dan Wu, Zhiliang Wang, Xia Yin, Xingang Shi, Jianping Wu, Min Huang
2013 B conf
ICNP
Haijun Geng, Xingang Shi, Xia Yin, Zhiliang Wang
2013 C conf
ISCC
Haijun Geng, Xia Yin, Xingang Shi, Zhiliang Wang
2013 C conf
ISCC
Xiangxin Kong, Zhiliang Wang, Xingang Shi, Xia Yin, Dan Li
2013 B conf
ICCCN
Jiangyuan Yao, Zhiliang Wang, Xia Yin, Xingang Shi, Jianping Wu
2013 B conf
ICNP
Dan Wu, Zhiliang Wang, Xia Yin, Xingang Shi, Jianping Wu, Min Huang
2013 J jnl
Comput. Networks
Yang Xiang, Xingang Shi, Jianping Wu, Zhiliang Wang, Xia Yin
2012 A conf
Internet Measurement Conference
Xingang Shi, Yang Xiang, Zhiliang Wang, Xia Yin, Jianping Wu
2012 conf
BCFIC
Jigeon Lee, Zhiliang Wang, Xia Yin, Xingang Shi, Dan Wu, Suogang Li
2012 B conf
Networking (1)
Yang Xiang, Zhiliang Wang, Jianping Wu, Xingang Shi, Xia Yin
2011 J jnl
Secur. Commun. Networks
Xia Yin, Zhiliang Wang, Chuanming Jing, Jianping Wu
2011 B conf
ICNP
Yang Xiang, Zhiliang Wang, Xia Yin, Jianping Wu
2011 conf
ICC
Yang Xiang, Xia Yin, Zhiliang Wang, Jianping Wu
2011 conf
ICST Workshops
Li Zhou, Xia Yin, Zhiliang Wang
2011 conf
AINTEC
Jiangyuan Yao, Zhiliang Wang, Xia Yin, Jianping Wu
2010 B conf
CNSM
Letong Sun, Xia Yin, Zhiliang Wang, Yang Xiang, Jianping Wu
2009 C conf
ISADS
Xin Wu, Xia Yin, Zhiliang Wang, Min Tang
2009 conf
Infoscale
Xia Yin, Xin Wu, Zhiliang Wang
2009 conf
AINA Workshops
Yang Xiang, Zhiliang Wang, Xia Yin
2009 conf
TestCom/FATES
Zhiliang Wang, Xia Yin, Yang Xiang, Ruiping Zhu, Shirui Gao, Xin Wu, Shijian Liu, Song Gao, Li Zhou, Peng Li
2009 conf
ICOIN
Hwan Hwang, Xia Yin, Zhiliang Wang, Huiming Wang
2008 conf
ICYCS
Chuanming Jing, Xia Yin, Zhiliang Wang, Jianping Wu
2008 C conf
NPC
Chuanming Jing, Zhiliang Wang, Xia Yin, Jianping Wu
2008 J jnl
Sci. China Ser. F Inf. Sci.
Xia Yin, Zhiliang Wang, Chuanming Jing, Xingang Shi
2008 J jnl
Sci. China Ser. F Inf. Sci.
Zhiliang Wang, Xia Yin, Chuanming Jing
2008 B conf
AINA
Chuanming Jing, Zhiliang Wang, Xingang Shi, Xia Yin, Jianping Wu
2008 C conf
ISCC
Huiming Wang, Xingang Shi, Zhiliang Wang, Xia Yin, Jianping Wu
2007 conf
ICON
Li Ji, Xia Yin, Xingang Shi, Zhiliang Wang
2006 conf
TestCom
Zhiliang Wang, Jianping Wu, Xia Yin, Xingang Shi, Beihang Tian
2004 B conf
GLOBECOM
Zhiliang Wang, Jianping Wu, Xia Yin
APK_FEATURES_PDD-Tech_Annex.md
← Index APK_FEATURES_PDD-Tech_Annex.md markdown
# APK Extractor — Technical Annex

**Companion to:** APK_FEATURES_PDD.md
**Audience:** Engineers implementing the APK extractors
**Date:** 2026-02-21

---

## Table of Contents

1. [File Structure](#1-file-structure)
2. [Dependencies Setup](#2-dependencies-setup)
3. [Base Class: APKExtractor](#3-base-class-apkextractor)
4. [Dataclass Definitions](#4-dataclass-definitions)
5. [Tag Enum Updates](#5-tag-enum-updates)
6. [Extractor Implementation Details](#6-extractor-implementation-details)
7. [Ingestor Integration](#7-ingestor-integration)
8. [Hashes Dataclass Update](#8-hashes-dataclass-update)
9. [ClickHouse Schema](#9-clickhouse-schema)
10. [Androguard API Reference](#10-androguard-api-reference)
11. [Known Packer/Protector Signatures](#11-known-packerprotector-signatures)
12. [Sensitive API Categorization Reference](#12-sensitive-api-categorization-reference)

---

## 1. File Structure

Create the following files:

```
redb/extractors/
├── apk_extractor.py                          # APKExtractor base class
├── apk_extractors/
│   ├── __init__.py
│   ├── apk_features.py                       # APKFeaturesExtractor
│   ├── apk_manifest.py                       # APKManifestExtractor
│   ├── apk_permissions.py                    # APKPermissionsExtractor
│   ├── apk_signature.py                      # APKSignatureExtractor
│   ├── apk_dex.py                            # APKDexExtractor
│   ├── apk_resources.py                      # APKResourceExtractor
│   ├── apk_native_libs.py                    # APKNativeLibExtractor
│   └── apk_inconsistency_tests.py            # APKInconsistencyTestsExtractor
```

Modified files:

```
redb/extractors/enum.py                       # Add APK tags
redb/models/dataclasses.py                    # Add APK dataclasses + permhash field in Hashes
redb/ingestor.py                              # Wire up APK dispatch
requirements.txt                              # Add androguard, permhash
```

---

## 2. Dependencies Setup

Add to `requirements.txt`:

```
androguard>=4.1
permhash
```

Install and verify:

```bash
pip install androguard permhash
python -c "from androguard.core.apk import APK; print('androguard OK')"
python -c "import permhash; print('permhash OK')"
```

---

## 3. Base Class: APKExtractor

**File:** `redb/extractors/apk_extractor.py`

Follow the exact pattern of `PEExtractor` (`redb/extractors/pe_extractor.py`) and `MachOExtractor` (`redb/extractors/macho_extractor.py`).

```python
import logging
from abc import ABCMeta, abstractmethod
import zipfile

from androguard.core.apk import APK

from redb.extractors.extractor import Extractor

logger = logging.getLogger(__name__)


@abstractmethod
class APKExtractor(Extractor, metaclass=ABCMeta):

    def __init__(
        self,
        filepath,
        log,
        exporters=None,
        index_prefix=None,
        elastic_index=None,
        known_benign=False,
        known_malicious=False,
        apk=None,
    ):
        super().__init__(
            filepath,
            log,
            exporters,
            index_prefix,
            elastic_index,
            known_benign,
            known_malicious
        )
        self.apk = apk if apk else self._generate_apk_object()

    def _generate_apk_object(self):
        """Parse APK using androguard."""
        apk = None
        try:
            apk = APK(self.filepath)
            if not apk.is_valid_APK():
                self.log.warning(
                    f"APK validation warning for {self.hash.sha256}"
                )
                # Still return the object — partial parsing may still work
        except Exception as e:
            self.log.error(
                f"Format error parsing APK {self.hash.sha256}: {e}"
            )
        return apk

    def _is_valid_apk(self):
        """Check if the APK object was parsed successfully."""
        return self.apk is not None

    def _get_zip_file(self):
        """Get a zipfile.ZipFile handle for direct archive inspection."""
        try:
            return zipfile.ZipFile(self.filepath, 'r')
        except (zipfile.BadZipFile, Exception) as e:
            self.log.error(f"Failed to open APK as ZIP: {e}")
            return None

    def _list_files(self):
        """List all files in the APK archive."""
        if not self._is_valid_apk():
            return []
        try:
            return self.apk.get_files()
        except Exception as e:
            self.log.error(f"Error listing APK files: {e}")
            return []
```

**Key design decisions:**
- The `apk=` parameter allows the ingestor to parse once and share across all APK extractors (same pattern as `pe=` in PEExtractor, `macho=` in MachOExtractor, `elf=` in ELFExtractor)
- `_get_zip_file()` provides direct ZIP access for extractors that need it (resources, native libs, inconsistency tests)
- The androguard `APK` object is the primary parsing interface; `zipfile` is secondary for archive-level inspection

---

## 4. Dataclass Definitions

**File:** `redb/models/dataclasses.py`

Add after the Mach-O dataclasses section. Follow the exact style of existing dataclasses (type annotations, `Optional` for nullable fields, `field(default_factory=list)` for list defaults).

```python
# ============================================================================
# APK Dataclasses
# ============================================================================

@dataclass
class APKFeatures:
    """Core APK metadata and properties."""
    package_name: str
    app_name: str
    version_code: int
    version_name: str
    min_sdk_version: Optional[int] = None
    target_sdk_version: Optional[int] = None
    compile_sdk_version: Optional[int] = None
    main_activity: Optional[str] = None
    is_debuggable: bool = False
    allow_backup: bool = True
    uses_cleartext_traffic: bool = False
    supported_abis: List[str] = field(default_factory=list)
    dex_count: int = 0
    total_dex_size: int = 0
    total_file_count: int = 0
    has_native_code: bool = False
    has_assets: bool = False
    uses_libraries: List[str] = field(default_factory=list)
    earliest_content_modification: Optional[str] = None  # ISO 8601
    latest_content_modification: Optional[str] = None    # ISO 8601
    contains_embedded_apk: bool = False


@dataclass
class APKManifestComponent:
    """Single Android component (activity, service, receiver, provider)."""
    component_type: str      # "activity", "service", "receiver", "provider"
    class_name: str
    is_exported: bool
    intent_actions: List[str] = field(default_factory=list)
    intent_categories: List[str] = field(default_factory=list)


@dataclass
class APKManifest:
    """Full AndroidManifest.xml analysis."""
    activity_count: int
    service_count: int
    receiver_count: int
    provider_count: int
    activities: List[str] = field(default_factory=list)
    services: List[str] = field(default_factory=list)
    receivers: List[str] = field(default_factory=list)
    providers: List[str] = field(default_factory=list)
    exported_components: List[str] = field(default_factory=list)
    intent_filters_by_action: List[str] = field(default_factory=list)
    intent_filters_by_category: List[str] = field(default_factory=list)
    uses_features: List[str] = field(default_factory=list)
    meta_data: Optional[Dict] = None
    manifest_xml: Optional[str] = None  # Full decompiled XML text


@dataclass
class APKPermission:
    """Single permission entry for ClickHouse export."""
    permission_name: str
    protection_level: str    # "normal", "dangerous", "signature", "signatureOrSystem", "unknown"
    is_custom: bool = False  # True if declared by the app itself


@dataclass
class APKPermissions:
    """APK permission summary."""
    total_permission_count: int
    dangerous_permission_count: int
    permissions: List[str] = field(default_factory=list)
    dangerous_permissions: List[str] = field(default_factory=list)
    custom_permissions: List[str] = field(default_factory=list)
    permission_details: List[APKPermission] = field(default_factory=list)
    permhash: Optional[str] = None


@dataclass
class APKCertificate:
    """X.509 certificate from APK signature."""
    subject: str
    issuer: str
    serial_number: str
    valid_from: str
    valid_to: str
    thumbprint_sha1: str
    thumbprint_sha256: str
    algorithm: Optional[str] = None
    key_size: Optional[int] = None
    is_self_signed: bool = False


@dataclass
class APKCodeSigningInfo:
    """Complete APK signing information."""
    _id: str  # sha256
    is_signed: bool
    signature_scheme_versions: List[int] = field(default_factory=list)  # [1], [1,2], [1,2,3], etc.
    number_of_certificates: int = 0
    x509_certificates: Optional[List[APKCertificate]] = None
    signer_subject: Optional[str] = None
    signer_issuer: Optional[str] = None


@dataclass
class APKDexFile:
    """Analysis of a single DEX file."""
    filename: str
    sha256: str
    class_count: int
    method_count: int
    string_count: int
    top_packages: Optional[List[Dict]] = None  # [{"package": str, "class_count": int}]
    api_usage: Optional[Dict[str, List[str]]] = None  # {"reflection": [...], "crypto": [...], ...}
    obfuscation_indicators: Optional[Dict] = None


@dataclass
class APKResource:
    """Embedded resource file entry."""
    path: str
    size: int
    sha256: str
    filetype_magika: str
    is_suspicious: bool = False  # True for executable types


@dataclass
class APKNativeLib:
    """Native .so library entry."""
    abi: str          # e.g., "arm64-v8a"
    filename: str     # e.g., "libfoo.so"
    size: int
    sha256: str
    is_known_packer: bool = False  # True if matches known packer lib name


@dataclass
class APKInconsistencyTests:
    """APK anomaly and anti-analysis detection results."""
    test_zip_bomb: Optional[bool] = None
    test_zip_duplicate_entries: Optional[bool] = None
    test_zip_path_traversal: Optional[bool] = None
    test_zip_suspicious_timestamps: Optional[bool] = None
    test_hidden_dex_files: Optional[bool] = None
    test_manifest_component_mismatch: Optional[bool] = None
    test_debuggable_release: Optional[bool] = None
    test_emulator_detection_strings: Optional[bool] = None
    test_debugger_detection: Optional[bool] = None
    test_root_detection: Optional[bool] = None
```

---

## 5. Tag Enum Updates

**File:** `redb/extractors/enum.py`

Add at the end of the `Tag` class, after the ELF section:

```python
    # APK
    APK_FEATURES = "apk_features"
    APK_MANIFEST = "apk_manifest"
    APK_PERMISSIONS = "apk_permissions"
    APK_SIGNATURE = "apk_signature"
    APK_DEX = "apk_dex"
    APK_RESOURCES = "apk_resources"
    APK_NATIVE_LIBS = "apk_native_libs"
    APK_INCONSISTENCY_TESTS = "apk_inconsistency_tests"
```

---

## 6. Extractor Implementation Details

### 6.1 APKFeaturesExtractor

**File:** `redb/extractors/apk_extractors/apk_features.py`

```python
import inspect
import zipfile
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 APKFeatures


class APKFeaturesExtractor(APKExtractor):

    def __init__(
        self, filepath, log, exporters=None, index_prefix=None,
        elastic_index=None, known_benign=False, known_malicious=False,
        apk=None,
    ):
        super().__init__(
            filepath, log, exporters, index_prefix,
            elastic_index, known_benign, known_malicious, apk,
        )
        self.apk_features = None
        self.elastic_index = self.index_prefix + "-apk_features"

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

    def _extract_zip_timestamps(self):
        """Extract earliest and latest content modification from ZIP entries."""
        # Use zipfile directly for this — androguard doesn't expose ZIP metadata
        earliest = None
        latest = None
        try:
            zf = self._get_zip_file()
            if zf:
                with zf:
                    for info in zf.infolist():
                        try:
                            # date_time is (year, month, day, hour, minute, second)
                            dt = datetime(*info.date_time)
                            if earliest is None or dt < earliest:
                                earliest = dt
                            if latest is None or dt > latest:
                                latest = dt
                        except (ValueError, TypeError):
                            continue
        except Exception as e:
            self.log.warning(f"Error extracting ZIP timestamps: {e}")
        return (
            earliest.isoformat() if earliest else None,
            latest.isoformat() if latest else None,
        )

    def _extract_supported_abis(self):
        """Determine supported ABIs from lib/ directory."""
        abis = set()
        for f in self._list_files():
            if f.startswith("lib/") and f.endswith(".so"):
                parts = f.split("/")
                if len(parts) >= 3:
                    abis.add(parts[1])
        return sorted(abis)

    def _count_dex_files(self):
        """Count DEX files and compute total size."""
        dex_count = 0
        total_size = 0
        try:
            zf = self._get_zip_file()
            if zf:
                with zf:
                    for info in zf.infolist():
                        if info.filename.endswith(".dex"):
                            dex_count += 1
                            total_size += info.file_size
        except Exception as e:
            self.log.warning(f"Error counting DEX files: {e}")
        return dex_count, total_size

    def _check_embedded_apk(self):
        """Check if the archive contains nested APK files."""
        for f in self._list_files():
            if f.lower().endswith(".apk"):
                return True
        return False

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

            # Core metadata from androguard
            package_name = self.apk.get_package() or ""
            app_name = self.apk.get_app_name() or ""

            # version_code may be string or int
            try:
                version_code = int(self.apk.get_androidversion_code() or 0)
            except (ValueError, TypeError):
                version_code = 0

            version_name = self.apk.get_androidversion_name() or ""

            # SDK versions
            min_sdk = self.apk.get_min_sdk_version()
            target_sdk = self.apk.get_target_sdk_version()
            # NOTE: compile_sdk may not be available in all androguard versions
            compile_sdk = None
            try:
                compile_sdk = self.apk.get_effective_target_sdk_version()
            except AttributeError:
                pass

            min_sdk = int(min_sdk) if min_sdk else None
            target_sdk = int(target_sdk) if target_sdk else None
            compile_sdk = int(compile_sdk) if compile_sdk else None

            # Main activity
            main_activity = self.apk.get_main_activity()

            # Flags from manifest
            # androguard provides get_attribute_value for manifest attributes
            is_debuggable = self.apk.get_attribute_value(
                "application", "debuggable"
            ) == "true"
            allow_backup = self.apk.get_attribute_value(
                "application", "allowBackup"
            ) != "false"  # default is true
            uses_cleartext = self.apk.get_attribute_value(
                "application", "usesCleartextTraffic"
            ) == "true"

            # Archive-level analysis
            supported_abis = self._extract_supported_abis()
            dex_count, total_dex_size = self._count_dex_files()
            all_files = self._list_files()
            total_file_count = len(all_files)
            has_native_code = any(
                f.startswith("lib/") and f.endswith(".so") for f in all_files
            )
            has_assets = any(f.startswith("assets/") for f in all_files)
            contains_embedded_apk = self._check_embedded_apk()

            # Uses-library
            uses_libraries = []
            try:
                libs = self.apk.get_libraries()
                uses_libraries = list(libs) if libs else []
            except Exception:
                pass

            # ZIP timestamps
            earliest_mod, latest_mod = self._extract_zip_timestamps()

            self.apk_features = APKFeatures(
                package_name=package_name,
                app_name=app_name,
                version_code=version_code,
                version_name=version_name,
                min_sdk_version=min_sdk,
                target_sdk_version=target_sdk,
                compile_sdk_version=compile_sdk,
                main_activity=main_activity,
                is_debuggable=is_debuggable,
                allow_backup=allow_backup,
                uses_cleartext_traffic=uses_cleartext,
                supported_abis=supported_abis,
                dex_count=dex_count,
                total_dex_size=total_dex_size,
                total_file_count=total_file_count,
                has_native_code=has_native_code,
                has_assets=has_assets,
                uses_libraries=uses_libraries,
                earliest_content_modification=earliest_mod,
                latest_content_modification=latest_mod,
                contains_embedded_apk=contains_embedded_apk,
            )
            return self.apk_features

        except Exception as e:
            self.log.error(
                f"Error extracting APK features {self.hash.sha256}: {e}"
            )
            return None

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

            f = self.apk_features
            data = [[
                self.sha256, self.md5, self.sha1,
                f.package_name,
                f.app_name,
                f.version_code,
                f.version_name,
                f.min_sdk_version,
                f.target_sdk_version,
                f.compile_sdk_version,
                f.main_activity,
                int(f.is_debuggable),
                int(f.allow_backup),
                int(f.uses_cleartext_traffic),
                f.supported_abis,
                f.dex_count,
                f.total_dex_size,
                f.total_file_count,
                int(f.has_native_code),
                int(f.has_assets),
                f.uses_libraries,
                f.earliest_content_modification,
                f.latest_content_modification,
                int(f.contains_embedded_apk),
                datetime.now(timezone.utc),
            ]]

            column_names = [
                "sha256", "md5", "sha1",
                "package_name", "app_name", "version_code", "version_name",
                "min_sdk_version", "target_sdk_version", "compile_sdk_version",
                "main_activity",
                "is_debuggable", "allow_backup", "uses_cleartext_traffic",
                "supported_abis",
                "dex_count", "total_dex_size", "total_file_count",
                "has_native_code", "has_assets",
                "uses_libraries",
                "earliest_content_modification", "latest_content_modification",
                "contains_embedded_apk",
                "analysis_date",
            ]

            column_type_names = [
                "FixedString(64)", "FixedString(32)", "FixedString(40)",
                "String", "String", "UInt32", "String",
                "Nullable(UInt16)", "Nullable(UInt16)", "Nullable(UInt16)",
                "Nullable(String)",
                "UInt8", "UInt8", "UInt8",
                "Array(String)",
                "UInt16", "UInt64", "UInt32",
                "UInt8", "UInt8",
                "Array(String)",
                "Nullable(String)", "Nullable(String)",
                "UInt8",
                "DateTime64(3, 'UTC')",
            ]

            return (data, column_names, column_type_names)

    def get_clickhouse_table(self) -> str:
        return "redb_apk_features"
```

### 6.2 APKManifestExtractor

**File:** `redb/extractors/apk_extractors/apk_manifest.py`

**Key androguard API calls:**
```python
# Activities, services, receivers, providers
self.apk.get_activities()       # Returns list of activity class names
self.apk.get_services()         # Returns list of service class names
self.apk.get_receivers()        # Returns list of receiver class names
self.apk.get_providers()        # Returns list of provider class names

# Exported check (per component)
self.apk.get_intent_filters(component_type, component_name)
# Returns dict: {"action": [...], "category": [...]}

# Uses-features
self.apk.get_features()         # Returns list of feature strings

# Full XML
self.apk.get_android_manifest_xml().toxml()
# OR
self.apk.get_android_manifest_axml().get_xml()
```

**Implementation notes:**
- For ClickHouse export of components, use a **one-row-per-component** table (`redb_apk_components`) with columns: `sha256`, `component_type`, `class_name`, `is_exported`, `intent_actions` (Array), `intent_categories` (Array), `analysis_date`
- For the aggregated manifest data (counts, feature list, full XML), use a **one-row-per-APK** table (`redb_apk_manifest`)
- To determine if a component is exported: check `android:exported` attribute. If not explicitly set, it's implicitly exported if the component has intent filters (Android default behavior pre-API 31). From API 31+, `android:exported` must be explicit

### 6.3 APKPermissionsExtractor

**File:** `redb/extractors/apk_extractors/apk_permissions.py`

**Key androguard API calls:**
```python
# Requested permissions
self.apk.get_permissions()              # Returns list of permission strings
self.apk.get_declared_permissions()     # Custom permissions defined by the app

# For protection level, use androguard's permission mapping:
from androguard.core.api_specific_resources import load_permission_mappings
permission_map = load_permission_mappings(target_sdk)
# permission_map[perm_name] -> {"protectionLevel": "dangerous", ...}
```

**Permhash computation:**
```python
import permhash
ph = permhash.permhash_apk(self.filepath)
# Returns SHA-256 hex string
```

**Known dangerous permissions** (reference list for classification fallback):
```python
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",
}
```

**ClickHouse export:** One row per permission per APK in `redb_apk_permissions`:
- `sha256`, `permission_name`, `protection_level`, `is_custom`, `analysis_date`

The `permhash` value is also stored separately — see Section 8 for integration with `HashExtractor`.

### 6.4 APKSignatureExtractor

**File:** `redb/extractors/apk_extractors/apk_signature.py`

**Key androguard API calls:**
```python
# Get certificate objects
certs = self.apk.get_certificates()     # Returns list of asn1crypto Certificate objects

# For each certificate:
cert.subject.human_friendly              # Subject DN
cert.issuer.human_friendly               # Issuer DN
cert.serial_number                       # Serial
cert.not_valid_before                    # datetime
cert.not_valid_after                     # datetime
cert.hash_algo                           # e.g., "sha256"
cert.signature_algo                      # e.g., "rsassa_pkcs1v15"

# SHA-1 thumbprint
import hashlib
hashlib.sha1(cert.dump()).hexdigest()

# SHA-256 thumbprint
hashlib.sha256(cert.dump()).hexdigest()

# Self-signed check
cert.subject == cert.issuer

# Signature scheme detection:
# v1: Check META-INF/*.SF and META-INF/*.RSA/DSA/EC files exist
# v2/v3: androguard >= 4.x has is_signed_v2() / is_signed_v3()
self.apk.is_signed_v1()
self.apk.is_signed_v2()
self.apk.is_signed_v3()
```

**Implementation notes:**
- Mirror the structure of `PECodeSigningInfo` / `MachOCodeSigningInfo`
- The `_id` field should be `self.sha256` (same as PE/Mach-O signature extractors)

### 6.5 APKDexExtractor

**File:** `redb/extractors/apk_extractors/apk_dex.py`

This is the most complex extractor. Use `androguard.core.dex` for DEX parsing.

**Key androguard API calls:**
```python
from androguard.core.dex import DEX

# Get raw DEX data from APK
dex_files = self.apk.get_all_dex()  # Returns list of raw DEX bytes

for dex_name, dex_data in zip(self.apk.get_dex_names(), dex_files):
    d = DEX(dex_data)

    # Class enumeration
    classes = d.get_classes()
    for cls in classes:
        cls.get_name()          # e.g., "Lcom/example/MainActivity;"

    # Method enumeration
    methods = d.get_methods()
    for method in methods:
        method.get_class_name()  # e.g., "Lcom/example/MainActivity;"
        method.get_name()        # e.g., "onCreate"
        method.get_descriptor()  # e.g., "(Landroid/os/Bundle;)V"

    # String constants
    strings = d.get_strings()    # Returns list of string constants
```

**Computing `top_packages`:**
```python
from collections import Counter

package_counter = Counter()
for cls in classes:
    name = cls.get_name()  # "Lcom/example/foo/Bar;"
    # Convert to package: "com.example.foo"
    parts = name[1:].replace("/", ".").rsplit(".", 1)
    if len(parts) > 1:
        package = parts[0]
    else:
        package = "(default)"
    package_counter[package] += 1

top_packages = [
    {"package": pkg, "class_count": count}
    for pkg, count in package_counter.most_common(20)
]
```

**Computing `api_usage`:**
Iterate over all method cross-references (xrefs) or method invocations. For each invoked method, check if it matches any sensitive API pattern. See Section 12 for the full categorization reference.

```python
api_usage = {cat: [] for cat in SENSITIVE_API_CATEGORIES}

for method in d.get_methods():
    # Get the bytecode and look for invoke-* instructions
    code = method.get_code()
    if not code:
        continue
    # Use androguard's analysis or instruction iteration
    # to find method references that match sensitive patterns
```

**Computing `obfuscation_indicators`:**
```python
class_names = [cls.get_name() for cls in classes]
method_names = [m.get_name() for m in methods if m.get_name() not in ("<init>", "<clinit>")]

short_class = sum(1 for n in class_names if len(n.split("/")[-1].rstrip(";")) <= 2)
short_method = sum(1 for n in method_names if len(n) <= 2)

obfuscation_indicators = {
    "short_class_names_pct": round(short_class / max(len(class_names), 1), 4),
    "short_method_names_pct": round(short_method / max(len(method_names), 1), 4),
    "non_ascii_identifiers": sum(1 for n in class_names if not n.isascii()),
    "avg_class_name_length": round(
        sum(len(n) for n in class_names) / max(len(class_names), 1), 2
    ),
}
```

**ClickHouse export:**
- `redb_apk_dex`: One row per DEX file — `sha256`, `dex_sha256`, `dex_filename`, `class_count`, `method_count`, `string_count`, `top_packages` (JSON string), `obfuscation_indicators` (JSON string), `analysis_date`
- `redb_apk_dex_api_usage`: One row per API category per DEX — `sha256`, `dex_sha256`, `category`, `api_calls` (Array(String)), `analysis_date`

### 6.6 APKResourceExtractor

**File:** `redb/extractors/apk_extractors/apk_resources.py`

**Implementation approach:**
```python
import hashlib
from magika import Magika

magika = Magika()

resources = []
suspicious_files = []

zf = self._get_zip_file()
if zf:
    with zf:
        for info in zf.infolist():
            if info.is_dir():
                continue
            # Only scan res/ and assets/ directories
            if not (info.filename.startswith("res/") or
                    info.filename.startswith("assets/")):
                continue

            data = zf.read(info.filename)
            file_sha256 = hashlib.sha256(data).hexdigest()
            filetype = magika.identify_bytes(data).output.label

            resource = APKResource(
                path=info.filename,
                size=info.file_size,
                sha256=file_sha256,
                filetype_magika=filetype,
            )

            # Flag suspicious file types
            SUSPICIOUS_TYPES = {
                "elf", "pebin", "dex", "apk", "zip", "shell",
                "javascript", "python", "powershell", "batch",
            }
            if filetype in SUSPICIOUS_TYPES:
                resource.is_suspicious = True
                suspicious_files.append(resource)

            resources.append(resource)
```

**ClickHouse export:** One row per resource in `redb_apk_resources`:
- `sha256`, `resource_path`, `resource_size`, `resource_sha256`, `filetype_magika`, `is_suspicious`, `analysis_date`

**Performance note:** For APKs with very large resource directories (some apps have 10K+ files in `res/`), consider limiting to the top N resources by size or only scanning `assets/` fully while sampling `res/`. Document any limits applied.

### 6.7 APKNativeLibExtractor

**File:** `redb/extractors/apk_extractors/apk_native_libs.py`

**Implementation approach:**
```python
native_libs = []
abis = set()

zf = self._get_zip_file()
if zf:
    with zf:
        for info in zf.infolist():
            if info.filename.startswith("lib/") and info.filename.endswith(".so"):
                parts = info.filename.split("/")
                if len(parts) >= 3:
                    abi = parts[1]
                    filename = parts[-1]
                    abis.add(abi)

                    data = zf.read(info.filename)
                    lib_sha256 = hashlib.sha256(data).hexdigest()

                    native_libs.append(APKNativeLib(
                        abi=abi,
                        filename=filename,
                        size=info.file_size,
                        sha256=lib_sha256,
                        is_known_packer=filename in KNOWN_PACKER_LIBS,
                    ))
```

See Section 11 for the `KNOWN_PACKER_LIBS` reference list.

### 6.8 APKInconsistencyTestsExtractor

**File:** `redb/extractors/apk_extractors/apk_inconsistency_tests.py`

Each test is a private method returning `bool`:

```python
def _test_zip_bomb(self):
    """Check if any ZIP entry has compression ratio > 100:1."""
    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

def _test_zip_duplicate_entries(self):
    """Check for duplicate filenames in ZIP directory."""
    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))

def _test_zip_path_traversal(self):
    """Check for path traversal (../) in ZIP entry names."""
    for f in self._list_files():
        if ".." in f or f.startswith("/"):
            return True
    return False

def _test_zip_suspicious_timestamps(self):
    """Check for timestamps at epoch (1980) or in the future."""
    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

def _test_hidden_dex_files(self):
    """Check for DEX files not matching classes*.dex pattern."""
    import re
    standard_pattern = re.compile(r"^classes\d*\.dex$")
    for f in self._list_files():
        if f.endswith(".dex") and not standard_pattern.match(f.split("/")[-1]):
            return True
    return False

def _test_emulator_detection_strings(self):
    """Check for emulator detection patterns in DEX strings."""
    # Inspect DEX strings for known emulator detection indicators
    EMULATOR_INDICATORS = {
        "generic", "sdk", "google_sdk", "Emulator",
        "goldfish", "ranchu", "Andy", "Genymotion",
        "BlueStacks", "nox", "ttVM_Hdragon",
    }
    # Use androguard to extract strings from DEX, then check
    ...

def _test_debugger_detection(self):
    """Check for debugger detection API calls in DEX."""
    # Look for: Debug.isDebuggerConnected, Debug.waitingForDebugger
    ...

def _test_root_detection(self):
    """Check for root detection patterns in DEX."""
    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",
    }
    ...
```

---

## 7. Ingestor Integration

**File:** `redb/ingestor.py`

Replace the stub at line 1668:

```python
elif filetype == "apk":
    logger.debug("APK file detected")
```

With the full dispatch block:

```python
elif filetype == "apk":
    logger.debug("APK file detected")

    # Import APK extractors
    from redb.extractors.apk_extractor import APKExtractor
    from redb.extractors.apk_extractors.apk_features import APKFeaturesExtractor
    from redb.extractors.apk_extractors.apk_manifest import APKManifestExtractor
    from redb.extractors.apk_extractors.apk_permissions import APKPermissionsExtractor
    from redb.extractors.apk_extractors.apk_signature import APKSignatureExtractor
    from redb.extractors.apk_extractors.apk_dex import APKDexExtractor
    from redb.extractors.apk_extractors.apk_resources import APKResourceExtractor
    from redb.extractors.apk_extractors.apk_native_libs import APKNativeLibExtractor
    from redb.extractors.apk_extractors.apk_inconsistency_tests import APKInconsistencyTestsExtractor

    apk_modules = [
        APKFeaturesExtractor,
        APKManifestExtractor,
        APKPermissionsExtractor,
        APKSignatureExtractor,
        APKDexExtractor,
        APKResourceExtractor,
        APKNativeLibExtractor,
        APKInconsistencyTestsExtractor,
    ]

    # Parse APK once with androguard, share across all extractors
    try:
        from androguard.core.apk import APK
        apk = APK(filepath)
    except Exception as e:
        logger.error(f"Failed to parse APK {filepath}: {e}")
        apk = None

    # Run format-agnostic extractors first (same as PE/ELF/MachO)
    # DIE
    if 'all' in selected_modules or 'DIEExtractor' in selected_modules:
        try:
            extractor = DIEExtractor(
                filepath, logger, exporters=exporters,
                index_prefix=index_prefix
            )
            result = extractor.export_data()
            is_packed = bool(result) if result is not None else None
            if result:
                results[ImportResult.CORRECTLY] += 1
            elif result is False:
                results[ImportResult.FAILED] += 1
        except Exception as e:
            logger.error(f"Error in DIEExtractor: {str(e)}")
            results[ImportResult.FAILED] += 1

    # BasicProperties
    if 'all' in selected_modules or 'BasicPropertiesExtractor' in selected_modules:
        try:
            extractor = BasicPropertiesExtractor(
                filepath, logger, exporters=exporters,
                index_prefix=index_prefix
            )
            if is_packed is not None:
                extractor.is_packed = is_packed
            result = extractor.export_data()
            if result:
                results[ImportResult.CORRECTLY] += 1
            elif result is False:
                results[ImportResult.FAILED] += 1
        except Exception as e:
            logger.error(f"Error in BasicPropertiesExtractor: {str(e)}")
            results[ImportResult.FAILED] += 1

    # Hashes
    if 'all' in selected_modules or 'HashExtractor' in selected_modules:
        try:
            extractor = HashExtractor(
                filepath, logger, exporters=exporters,
                index_prefix=index_prefix
            )
            result = extractor.export_data()
            if result:
                results[ImportResult.CORRECTLY] += 1
            elif result is False:
                results[ImportResult.FAILED] += 1
        except Exception as e:
            logger.error(f"Error in HashExtractor: {str(e)}")
            results[ImportResult.FAILED] += 1

    # YARA
    if 'all' in selected_modules or 'YaraExtractor' in selected_modules:
        try:
            extractor = YaraExtractor(
                filepath, logger, exporters=exporters,
                index_prefix=index_prefix
            )
            result = extractor.export_data()
            if result:
                results[ImportResult.CORRECTLY] += 1
            elif result is False:
                results[ImportResult.FAILED] += 1
        except Exception as e:
            logger.error(f"Error in YaraExtractor: {str(e)}")
            results[ImportResult.FAILED] += 1

    # APK-specific extractors
    for module in apk_modules:
        if 'all' in selected_modules or module.__name__ in selected_modules:
            try:
                logger.debug(f"Running {module.__name__}")
                extractor = module(
                    filepath,
                    logger,
                    exporters=exporters,
                    index_prefix=index_prefix,
                    apk=apk
                )
                result = extractor.export_data()
                if result:
                    results[ImportResult.CORRECTLY] += 1
                elif result is False:
                    results[ImportResult.FAILED] += 1
            except Exception as e:
                logger.error(f"Error in {module.__name__}: {str(e)}")
                results[ImportResult.FAILED] += 1
```

**Note:** Follow the exact error-handling and `selected_modules` check pattern used by the existing PE/ELF/Mach-O dispatch blocks. The code above mirrors the pattern from `ingestor.py:1540-1666`.

---

## 8. Hashes Dataclass Update

**File:** `redb/models/dataclasses.py`

Add to the `Hashes` dataclass after the existing Mach-O hashes:

```python
@dataclass
class Hashes:
    md5: str
    sha1: str
    sha256: str
    ssdeep_hash: str
    tlsh_hash: str
    authentihash: Optional[str] = None  # PE
    imphash: Optional[str] = None  # PE
    impfuzzy: Optional[str] = None  # PE TODO: implement
    typerefhash: Optional[str] = None  # DotNet
    richhash: Optional[str] = None  # PE
    richpe_hash: Optional[str] = None  # PE
    richpv_hash: Optional[str] = None  # PE
    richpv_hash_sorted: Optional[str] = None  # PE
    import_hash: Optional[str] = None  # ELF
    export_hash: Optional[str] = None  # ELF
    section_hash: Optional[str] = None  # ELF
    symbol_hash: Optional[str] = None  # ELF (symhash)
    dynamic_hash: Optional[str] = None  # ELF
    # Mach-O similarity hashes
    macho_dylib_hash: Optional[str] = None
    macho_import_hash: Optional[str] = None
    macho_export_hash: Optional[str] = None
    macho_entitlement_hash: Optional[str] = None
    macho_symhash: Optional[str] = None
    # APK similarity hashes
    permhash: Optional[str] = None  # APK: SHA-256 of sorted permissions (Mandiant/Google)
```

The `permhash` should be computed in `HashExtractor` when the filetype is APK, using the `permhash` library:

```python
# In HashExtractor, when filetype == "apk":
import permhash as permhash_lib
self.hashes.permhash = permhash_lib.permhash_apk(self.filepath)
```

The `permhash` column must be added to the existing `redb_hashes` table:

```sql
ALTER TABLE redb_hashes
    ADD COLUMN IF NOT EXISTS permhash Nullable(FixedString(64));
```

---

## 9. ClickHouse Schema

Create the following tables. Naming convention follows existing tables (`redb_pe_features`, `redb_elf_features`, etc.):

```sql
-- Core metadata (one row per APK)
CREATE TABLE redb_apk_features (
    sha256              FixedString(64),
    md5                 FixedString(32),
    sha1                FixedString(40),
    package_name        String,
    app_name            String,
    version_code        UInt32,
    version_name        String,
    min_sdk_version     Nullable(UInt16),
    target_sdk_version  Nullable(UInt16),
    compile_sdk_version Nullable(UInt16),
    main_activity       Nullable(String),
    is_debuggable       UInt8,
    allow_backup        UInt8,
    uses_cleartext_traffic UInt8,
    supported_abis      Array(String),
    dex_count           UInt16,
    total_dex_size      UInt64,
    total_file_count    UInt32,
    has_native_code     UInt8,
    has_assets          UInt8,
    uses_libraries      Array(String),
    earliest_content_modification Nullable(String),
    latest_content_modification   Nullable(String),
    contains_embedded_apk UInt8,
    analysis_date       DateTime64(3, 'UTC')
) ENGINE = ReplacingMergeTree()
ORDER BY sha256;

-- Manifest components (one row per component)
CREATE TABLE redb_apk_components (
    sha256              FixedString(64),
    component_type      LowCardinality(String),  -- "activity", "service", "receiver", "provider"
    class_name          String,
    is_exported         UInt8,
    intent_actions      Array(String),
    intent_categories   Array(String),
    analysis_date       DateTime64(3, 'UTC')
) ENGINE = ReplacingMergeTree()
ORDER BY (sha256, component_type, class_name);

-- Manifest summary (one row per APK)
CREATE TABLE redb_apk_manifest (
    sha256              FixedString(64),
    md5                 FixedString(32),
    sha1                FixedString(40),
    activity_count      UInt16,
    service_count       UInt16,
    receiver_count      UInt16,
    provider_count      UInt16,
    intent_filters_by_action   Array(String),
    intent_filters_by_category Array(String),
    uses_features       Array(String),
    manifest_xml        Nullable(String),
    analysis_date       DateTime64(3, 'UTC')
) ENGINE = ReplacingMergeTree()
ORDER BY sha256;

-- Permissions (one row per permission per APK)
CREATE TABLE redb_apk_permissions (
    sha256              FixedString(64),
    permission_name     String,
    protection_level    LowCardinality(String),
    is_custom           UInt8,
    analysis_date       DateTime64(3, 'UTC')
) ENGINE = ReplacingMergeTree()
ORDER BY (sha256, permission_name);

-- Signing info (one row per APK)
CREATE TABLE redb_apk_signature (
    sha256              FixedString(64),
    md5                 FixedString(32),
    sha1                FixedString(40),
    is_signed           UInt8,
    signature_scheme_versions Array(UInt8),
    number_of_certificates UInt8,
    signer_subject      Nullable(String),
    signer_issuer       Nullable(String),
    analysis_date       DateTime64(3, 'UTC')
) ENGINE = ReplacingMergeTree()
ORDER BY sha256;

-- Certificate details (one row per certificate per APK)
CREATE TABLE redb_apk_certificates (
    sha256              FixedString(64),
    subject             String,
    issuer              String,
    serial_number       String,
    valid_from          String,
    valid_to            String,
    thumbprint_sha1     FixedString(40),
    thumbprint_sha256   FixedString(64),
    algorithm           Nullable(String),
    key_size            Nullable(UInt16),
    is_self_signed      UInt8,
    analysis_date       DateTime64(3, 'UTC')
) ENGINE = ReplacingMergeTree()
ORDER BY (sha256, thumbprint_sha256);

-- DEX file analysis (one row per DEX file)
CREATE TABLE redb_apk_dex (
    sha256              FixedString(64),
    dex_sha256          FixedString(64),
    dex_filename        String,
    dex_tlsh            Nullable(String),
    class_count         UInt32,
    method_count        UInt32,
    string_count        UInt32,
    top_packages        String,       -- JSON
    obfuscation_indicators String,    -- JSON
    analysis_date       DateTime64(3, 'UTC')
) ENGINE = ReplacingMergeTree()
ORDER BY (sha256, dex_sha256);

-- DEX API usage (one row per category per DEX)
CREATE TABLE redb_apk_dex_api_usage (
    sha256              FixedString(64),
    dex_sha256          FixedString(64),
    category            LowCardinality(String),
    api_calls           Array(String),
    analysis_date       DateTime64(3, 'UTC')
) ENGINE = ReplacingMergeTree()
ORDER BY (sha256, dex_sha256, category);

-- Resource inventory (one row per resource)
CREATE TABLE redb_apk_resources (
    sha256              FixedString(64),
    resource_path       String,
    resource_size       UInt64,
    resource_sha256     FixedString(64),
    filetype_magika     LowCardinality(String),
    is_suspicious       UInt8,
    analysis_date       DateTime64(3, 'UTC')
) ENGINE = ReplacingMergeTree()
ORDER BY (sha256, resource_path);

-- Native libraries (one row per .so file)
CREATE TABLE redb_apk_native_libs (
    sha256              FixedString(64),
    abi                 LowCardinality(String),
    filename            String,
    size                UInt64,
    lib_sha256          FixedString(64),
    is_known_packer     UInt8,
    analysis_date       DateTime64(3, 'UTC')
) ENGINE = ReplacingMergeTree()
ORDER BY (sha256, abi, filename);

-- Inconsistency tests (one row per APK)
CREATE TABLE redb_apk_inconsistency_tests (
    sha256              FixedString(64),
    md5                 FixedString(32),
    sha1                FixedString(40),
    test_zip_bomb                    Nullable(UInt8),
    test_zip_duplicate_entries       Nullable(UInt8),
    test_zip_path_traversal          Nullable(UInt8),
    test_zip_suspicious_timestamps   Nullable(UInt8),
    test_hidden_dex_files            Nullable(UInt8),
    test_manifest_component_mismatch Nullable(UInt8),
    test_debuggable_release          Nullable(UInt8),
    test_emulator_detection_strings  Nullable(UInt8),
    test_debugger_detection          Nullable(UInt8),
    test_root_detection              Nullable(UInt8),
    analysis_date       DateTime64(3, 'UTC')
) ENGINE = ReplacingMergeTree()
ORDER BY sha256;
```

---

## 10. Androguard API Reference

Quick reference for the most commonly used androguard APIs. Full docs: https://androguard.readthedocs.io/

### APK class (`androguard.core.apk.APK`)

| Method | Returns | Description |
|--------|---------|-------------|
| `APK(filepath)` | `APK` | Parse an APK file |
| `.is_valid_APK()` | `bool` | Check if parsing succeeded |
| `.get_package()` | `str` | Package name |
| `.get_app_name()` | `str` | Application display name |
| `.get_androidversion_code()` | `str` | Version code |
| `.get_androidversion_name()` | `str` | Version name |
| `.get_min_sdk_version()` | `str` | Minimum SDK |
| `.get_target_sdk_version()` | `str` | Target SDK |
| `.get_main_activity()` | `str` | Main/launcher activity |
| `.get_activities()` | `list[str]` | All activity class names |
| `.get_services()` | `list[str]` | All service class names |
| `.get_receivers()` | `list[str]` | All receiver class names |
| `.get_providers()` | `list[str]` | All provider class names |
| `.get_permissions()` | `list[str]` | Requested permissions |
| `.get_declared_permissions()` | `list[str]` | Custom-defined permissions |
| `.get_features()` | `list[str]` | Uses-feature declarations |
| `.get_libraries()` | `list[str]` | Uses-library declarations |
| `.get_files()` | `list[str]` | All files in the APK |
| `.get_certificates()` | `list[Certificate]` | X.509 certificate objects |
| `.get_all_dex()` | `list[bytes]` | Raw DEX file contents |
| `.get_dex_names()` | `list[str]` | DEX filenames |
| `.is_signed_v1()` | `bool` | JAR signature present |
| `.is_signed_v2()` | `bool` | v2 signature present |
| `.is_signed_v3()` | `bool` | v3 signature present |
| `.get_attribute_value(tag, attr)` | `str` | Get manifest attribute |
| `.get_android_manifest_xml()` | `minidom` | Parsed manifest XML |
| `.get_intent_filters(type, name)` | `dict` | Intent filters for component |

### DEX class (`androguard.core.dex.DEX`)

| Method | Returns | Description |
|--------|---------|-------------|
| `DEX(raw_bytes)` | `DEX` | Parse raw DEX data |
| `.get_classes()` | `list[ClassDefItem]` | All class definitions |
| `.get_methods()` | `list[EncodedMethod]` | All methods |
| `.get_strings()` | `list[str]` | All string constants |

---

## 11. Known Packer/Protector Signatures

Native library names commonly associated with packers and protectors. Used by `APKNativeLibExtractor` to flag `is_known_packer`:

```python
KNOWN_PACKER_LIBS = {
    # Jiagu (360/Qihoo)
    "libjiagu.so", "libjiagu_a64.so", "libjiagu_x86.so", "libjiagu_x64.so",
    # Bangcle/SecNeo
    "libsecexe.so", "libsecmain.so", "libSecShell.so",
    # Baidu
    "libbaiduprotect.so",
    # Tencent (Legu)
    "libshell-super.2019.so", "libshella-*.so", "libtxAppProtect.so",
    "libBugly.so", "mix.dex",
    # iJiami
    "libexec.so", "libexecmain.so",
    # Alibaba
    "libmobisec.so", "libaliprotect.so",
    # APKProtect
    "libAPKProtect.so",
    # Pangxie (Pangolin)
    "libdexjni.so",
    # DexProtector
    "libdexprotector.so",
    # AppSolid
    "libAppSolid.so",
    # Kiwisec
    "libkwscmm.so",
    # DingXiang
    "libx3g.so",
    # NQ Shield
    "libnqshield.so",
    # Generic / other
    "libprotectClass.so",
    "libDexHelper.so",
    "libdexloader.so",
    "libfdog.so",
}
```

**Note:** This list should be maintained and expanded over time. For glob-style matching (e.g., `libshella-*.so`), use `fnmatch` instead of exact set lookup.

---

## 12. Sensitive API Categorization Reference

Used by `APKDexExtractor` to categorize API calls. Each category maps to a list of class/method patterns:

```python
SENSITIVE_API_CATEGORIES = {
    "reflection": [
        "Ljava/lang/reflect/Method;->invoke",
        "Ljava/lang/reflect/Field;->get",
        "Ljava/lang/reflect/Field;->set",
        "Ljava/lang/reflect/Constructor;->newInstance",
        "Ljava/lang/Class;->forName",
        "Ljava/lang/Class;->getMethod",
        "Ljava/lang/Class;->getDeclaredMethod",
        "Ljava/lang/Class;->getDeclaredField",
        "Ljava/lang/ClassLoader;->loadClass",
    ],
    "crypto": [
        "Ljavax/crypto/Cipher;->getInstance",
        "Ljavax/crypto/Cipher;->init",
        "Ljavax/crypto/spec/SecretKeySpec;-><init>",
        "Ljavax/crypto/spec/IvParameterSpec;-><init>",
        "Ljava/security/MessageDigest;->getInstance",
        "Ljava/security/KeyStore;->getInstance",
        "Ljavax/crypto/Mac;->getInstance",
    ],
    "dynamic_loading": [
        "Ldalvik/system/DexClassLoader;-><init>",
        "Ldalvik/system/PathClassLoader;-><init>",
        "Ldalvik/system/InMemoryDexClassLoader;-><init>",
        "Ldalvik/system/BaseDexClassLoader;-><init>",
        "Ljava/lang/Runtime;->exec",
        "Ljava/lang/ProcessBuilder;->start",
    ],
    "telephony": [
        "Landroid/telephony/TelephonyManager;->getDeviceId",
        "Landroid/telephony/TelephonyManager;->getSubscriberId",
        "Landroid/telephony/TelephonyManager;->getLine1Number",
        "Landroid/telephony/TelephonyManager;->getSimSerialNumber",
        "Landroid/telephony/TelephonyManager;->getNetworkOperator",
        "Landroid/telephony/TelephonyManager;->getSimOperator",
    ],
    "sms": [
        "Landroid/telephony/SmsManager;->sendTextMessage",
        "Landroid/telephony/SmsManager;->sendMultipartTextMessage",
        "Landroid/telephony/SmsManager;->sendDataMessage",
    ],
    "network": [
        "Ljava/net/HttpURLConnection;->connect",
        "Ljava/net/URL;->openConnection",
        "Lokhttp3/OkHttpClient;-><init>",
        "Lokhttp3/Request$Builder;->build",
        "Lorg/apache/http/client/HttpClient;->execute",
        "Landroid/webkit/WebView;->loadUrl",
        "Landroid/webkit/WebView;->setWebViewClient",
    ],
    "native": [
        "Ljava/lang/System;->loadLibrary",
        "Ljava/lang/System;->load",
        "Ljava/lang/Runtime;->loadLibrary",
    ],
    "device_info": [
        "Landroid/os/Build;->FINGERPRINT",
        "Landroid/os/Build;->MODEL",
        "Landroid/os/Build;->MANUFACTURER",
        "Landroid/os/Build;->PRODUCT",
        "Landroid/os/Build;->BRAND",
        "Landroid/os/Build;->DEVICE",
        "Landroid/os/Build;->HARDWARE",
        "Landroid/os/Build;->SERIAL",
        "Landroid/os/Build$VERSION;->SDK_INT",
        "Landroid/provider/Settings$Secure;->getString",  # ANDROID_ID
    ],
    "file_io": [
        "Ljava/io/FileOutputStream;-><init>",
        "Ljava/io/FileInputStream;-><init>",
        "Landroid/content/SharedPreferences;->edit",
        "Landroid/database/sqlite/SQLiteDatabase;->execSQL",
        "Landroid/database/sqlite/SQLiteDatabase;->rawQuery",
    ],
    "ipc": [
        "Landroid/content/ContentResolver;->query",
        "Landroid/content/ContentResolver;->insert",
        "Landroid/content/ContentResolver;->delete",
        "Landroid/content/Intent;-><init>",
        "Landroid/content/Context;->sendBroadcast",
        "Landroid/content/Context;->startService",
        "Landroid/content/Context;->bindService",
    ],
}
```

**Matching approach:** For each method invocation found in DEX bytecode, check if its full signature (class + method) starts with any of the patterns above. Store only the first match per unique API call (avoid duplicates from multiple call sites).

---

## Implementation Checklist

- [ ] Add `androguard` and `permhash` to `requirements.txt`
- [ ] Create `redb/extractors/apk_extractor.py` (base class)
- [ ] Create `redb/extractors/apk_extractors/__init__.py`
- [ ] Implement `APKFeaturesExtractor`
- [ ] Implement `APKManifestExtractor`
- [ ] Implement `APKPermissionsExtractor`
- [ ] Implement `APKSignatureExtractor`
- [ ] Implement `APKDexExtractor`
- [ ] Implement `APKResourceExtractor`
- [ ] Implement `APKNativeLibExtractor`
- [ ] Implement `APKInconsistencyTestsExtractor`
- [ ] Add APK tags to `redb/extractors/enum.py`
- [ ] Add APK dataclasses to `redb/models/dataclasses.py`
- [ ] Add `permhash` field to `Hashes` dataclass
- [ ] Wire up APK dispatch in `redb/ingestor.py`
- [ ] Integrate `permhash` computation in `HashExtractor`
- [ ] Create ClickHouse migration scripts for new tables
- [ ] Unit tests per extractor
- [ ] Integration test: full APK ingestion pipeline
- [ ] Cross-validate output against VirusTotal for reference samples