Ran Yi

182 papers A* 47A 3B 3Misc 3Journal 112Unranked 14
YearRankTypeTitle / Venue / Authors
2026 J jnl
Pattern Recognit.
Qijian Tian, Sen Wang, Ran Yi, Zufeng Zhang, Bin Sheng, Xin Tan, Lizhuang Ma
2026 J jnl
IEEE Trans. Emerg. Top. Comput. Intell.
Chaojie Chen, Xingcai Wu, Jinxiang Lai, Ran Yi, Minjing Yu, Yongbin Qin, Yongjin Liu, Qi Wang
2026 J jnl
CoRR
Yating Wang, Yuan Sun, Xuan Wang, Ran Yi, Boyao Zhou, Yipengjing Sun, Hongyu Liu, Yinuo Wang, Lizhuang Ma
2026 J jnl
CoRR
Yuze He, Yanning Zhou, Wang Zhao, Jingwen Ye, Zhongkai Wu, Ran Yi, Yong-Jin Liu
2026 A* conf
AAAI
Yiwen Wang, Ran Yi, Lizhuang Ma
2026 A* conf
AAAI
Teng Hu, Jiangning Zhang, Zihan Su, Ran Yi
2026 J jnl
CoRR
Yicheng Xu, Jiangning Zhang, Zhucun Xue, Teng Hu, Ran Yi, Xiaobin Hu, Yong Li, Dacheng Tao
2025 A* conf
CVPR
Yating Wang, Xuan Wang, Ran Yi, Yanbo Fan, Jichen Hu, Jingcheng Zhu, Lizhuang Ma
2025 J jnl
CoRR
Yating Wang, Xuan Wang, Ran Yi, Yanbo Fan, Jichen Hu, Jingcheng Zhu, Lizhuang Ma
2025 J jnl
CoRR
Yizhe Tang, Zhimin Sun, Yuzhen Du, Ran Yi, Guangben Lu, Teng Hu, Luying Li, Lizhuang Ma, Fangyuan Zou
2025 J jnl
CoRR
Mengfei Xia, Yu Zhou, Ran Yi, Yong-Jin Liu, Wenping Wang
2025 J jnl
Comput. Graph.
Zijing Ma, Zhi Yang, Aihua Mao, Shuyi Wen, Ran Yi, Yong-Jin Liu
2025 A* conf
CVPR
Yizhe Tang, Zhimin Sun, Yuzhen Du, Ran Yi, Guangben Lu, Teng Hu, Luying Li, Lizhuang Ma, Fangyuan Zou
2025 J jnl
IEEE Trans. Vis. Comput. Graph.
Yizhe Tang, Yue Wang, Teng Hu, Ran Yi, Xin Tan, Lizhuang Ma, Yu-Kun Lai, Paul L. Rosin
2025 J jnl
IEEE Trans. Vis. Comput. Graph.
Fengqi Liu, Jingyu Gong, Qianyu Zhou, Xuequan Lu, Ran Yi, Yuan Xie, Lizhuang Ma
2025 J jnl
IEEE Trans. Emerg. Top. Comput.
Aihua Mao, Qing Liu, Yuxuan Tang, Sheng Ye, Ran Yi, Minjing Yu, Yong-Jin Liu
2025 Misc conf
ICASSP
Miaomiao Dai, Qianyu Zhou, Ran Yi, Lizhuang Ma
2025 J jnl
Vis. Comput.
Hao Yin, Ran Yi, Bin Sheng
2025 J jnl
CoRR
Yuji Wang, Moran Li, Xiaobin Hu, Ran Yi, Jiangning Zhang, Chengming Xu, Weijian Cao, Yabiao Wang, Chengjie Wang, Lizhuang Ma
2025 A conf
ICME
Lijie Geng, Junli Zhao, Lin Gao, Ran Yi, Fuqing Duan, Zhenkuan Pan, Yong-Jin Liu
2025 J jnl
CoRR
Teng Hu, Zhentao Yu, Guozhen Zhang, Zihan Su, Zhengguang Zhou, Youliang Zhang, Yuan Zhou, Qinglin Lu, Ran Yi
2025 J jnl
CoRR
Ran Yi, Teng Hu, Zihan Su, Lizhuang Ma
2025 A* conf
AAAI
Jinkun Hao, Junshu Tang, Jiangning Zhang, Ran Yi, Yijia Hong, Moran Li, Weijian Cao, Yating Wang, Chengjie Wang, Lizhuang Ma
2025 A* conf
ACM Multimedia
Yuji Wang, Moran Li, Xiaobin Hu, Ran Yi, Jiangning Zhang, Han Feng, Weijian Cao, Yabiao Wang, Chengjie Wang, Lizhuang Ma
2025 J jnl
CoRR
Yuji Wang, Moran Li, Xiaobin Hu, Ran Yi, Jiangning Zhang, Han Feng, Weijian Cao, Yabiao Wang, Chengjie Wang, Lizhuang Ma
2025 J jnl
CoRR
Yinan Chen, Jiangning Zhang, Yali Bi, Xiaobin Hu, Teng Hu, Zhucun Xue, Ran Yi, Yong Li, Ying Tai
2025 J jnl
CoRR
Yuhang Dong, Haizhou Ge, Yupei Zeng, Jiangning Zhang, Beiwen Tian, Guanzhong Tian, Hongrui Zhu, Yufei Jia, Ruixiang Wang, Ran Yi, Guyue Zhou, Longhua Ma
2025 A* conf
CVPR
Teng Hu, Jiangning Zhang, Ran Yi, Jieyu Weng, Yabiao Wang, Xianfang Zeng, Zhucun Xue, Lizhuang Ma
2025 J jnl
CoRR
Teng Hu, Jiangning Zhang, Ran Yi, Jieyu Weng, Yabiao Wang, Xianfang Zeng, Zhucun Xue, Lizhuang Ma
2025 J jnl
CoRR
Yuheng Chen, Teng Hu, Jiangning Zhang, Zhucun Xue, Ran Yi, Lizhuang Ma
2025 J jnl
IEEE Trans. Pattern Anal. Mach. Intell.
Chengjie Wang, Haokun Zhu, Jinlong Peng, Yue Wang, Ran Yi, Yunsheng Wu, Lizhuang Ma, Jiangning Zhang
2025 J jnl
Vis. Comput.
Canlin Li, Xinyue Wang, Ran Yi, Wenjiao Zhang, Lihua Bi, Lizhuang Ma
2025 A* conf
CVPR
Zhengyuan Peng, Jinpeng Ma, Zhimin Sun, Ran Yi, Haichuan Song, Xin Tan, Lizhuang Ma
2025 J jnl
CoRR
Zhengyuan Peng, Jinpeng Ma, Zhimin Sun, Ran Yi, Haichuan Song, Xin Tan, Lizhuang Ma
2025 J jnl
CoRR
Jinkun Hao, Naifu Liang, Zhen Luo, Xudong Xu, Weipeng Zhong, Ran Yi, Yichen Jin, Zhaoyang Lyu, Feng Zheng, Lizhuang Ma, Jiangmiao Pang
2025 J jnl
Vis. Comput.
Feihu Bian, Suya Xiong, Ran Yi, Lizhuang Ma
2025 J jnl
IEEE Trans. Vis. Comput. Graph.
Yiheng Han, Irvin Haozhe Zhan, Long Zeng, Yu-Ping Wang, Ran Yi, Minjing Yu, Matthieu Gaetan Lin, Jenny Sheng, Yong-Jin Liu
2025 J jnl
CoRR
Teng Hu, Zhentao Yu, Zhengguang Zhou, Jiangning Zhang, Yuan Zhou, Qinglin Lu, Ran Yi
2025 J jnl
CoRR
Ruiyan Wang, Teng Hu, Kaihui Huang, Zihan Su, Ran Yi, Lizhuang Ma
2025 A* conf
CVPR
Mengfei Xia, Nan Xue, Yujun Shen, Ran Yi, Tieliang Gong, Yong-Jin Liu
2025 J jnl
Int. J. Comput. Vis.
Zhimin Sun, Shen Chen, Taiping Yao, Ran Yi, Shouhong Ding, Lizhuang Ma
2025 J jnl
IEEE Trans. Circuits Syst. Video Technol.
Aihua Mao, Shuyi Wen, Feng Chen, Ran Yi, Yong-Jin Liu
2025 J jnl
CoRR
Yuhang Yang, Fengqi Liu, Yixing Lu, Qin Zhao, Pingyu Wu, Wei Zhai, Ran Yi, Yang Cao, Lizhuang Ma, Zheng-Jun Zha, Junting Dong
2025 A* conf
ICLR
Teng Hu, Jiangning Zhang, Ran Yi, Hongrui Huang, Yabiao Wang, Lizhuang Ma
2025 J jnl
CoRR
Yijia Hong, Jiangning Zhang, Ran Yi, Yuji Wang, Weijian Cao, Xiaobin Hu, Zhucun Xue, Yabiao Wang, Chengjie Wang, Lizhuang Ma
2025 J jnl
CoRR
Teng Hu, Jiangning Zhang, Zihan Su, Ran Yi
2025 A* conf
AAAI
Xianhe Jiao, Chenlei Lv, Junli Zhao, Ran Yi, Yu-Hui Wen, Zhenkuan Pan, Zhongke Wu, Yong-Jin Liu
2024 J jnl
IEEE Trans. Pattern Anal. Mach. Intell.
Mengfei Xia, Yu Zhou, Ran Yi, Yong-Jin Liu, Wenping Wang
2024 A* conf
SIGGRAPH Asia
Xinzhe Wang, Ran Yi, Lizhuang Ma
2024 J jnl
CoRR
Xinzhe Wang, Ran Yi, Lizhuang Ma
2024 J jnl
Commun. Inf. Syst.
Chengyang Hu, Yuduo Chen, Ran Yi, Song-Yang Zhang, Lizhuang Ma
2024 A* conf
ACM Multimedia
Ran Yi, Haokun Zhu, Teng Hu, Yu-Kun Lai, Paul L. Rosin
2024 A* conf
AAAI
Teng Hu, Jiangning Zhang, Ran Yi, Yuzhen Du, Xu Chen, Liang Liu, Yabiao Wang, Chengjie Wang
2024 J jnl
CoRR
Yizhe Tang, Yue Wang, Teng Hu, Ran Yi, Xin Tan, Lizhuang Ma, Yu-Kun Lai, Paul L. Rosin
2024 J jnl
Comput. Aided Geom. Des.
Changsong Lei, Mengfei Xia, Shaofeng Wang, Yaqian Liang, Ran Yi, Yu-Hui Wen, Yong-Jin Liu
2024 A* conf
ACM Multimedia
Teng Hu, Jiangning Zhang, Ran Yi, Yating Wang, Jieyu Weng, Hongrui Huang, Yabiao Wang, Lizhuang Ma
2024 J jnl
IEEE Trans. Vis. Comput. Graph.
Aihua Mao, Zhi Yang, Wanxin Chen, Ran Yi, Yong-Jin Liu
2024 A* conf
AAAI
Hexiang Wang, Fengqi Liu, Qianyu Zhou, Ran Yi, Xin Tan, Lizhuang Ma
2024 J jnl
CoRR
Hexiang Wang, Fengqi Liu, Qianyu Zhou, Ran Yi, Xin Tan, Lizhuang Ma
2024 conf
ECCV (7)
Zhengyi Fang, Yue Wang, Ran Yi, Lizhuang Ma
2024 A* conf
ACM Multimedia
Minjing Yu, Delong Pang, Ziwen Kang, Zhiyao Sun, Tian Lv, Jenny Sheng, Ran Yi, Yu-Hui Wen, Yong-Jin Liu
2024 A* conf
ACM Multimedia
Fengqi Liu, Hexiang Wang, Jingyu Gong, Ran Yi, Qianyu Zhou, Xuequan Lu, Jiangbo Lu, Lizhuang Ma
2024 J jnl
CoRR
Fengqi Liu, Hexiang Wang, Jingyu Gong, Ran Yi, Qianyu Zhou, Xuequan Lu, Jiangbo Lu, Lizhuang Ma
2024 J jnl
CoRR
Yuzhen Du, Teng Hu, Jiangning Zhang, Ran Yi, Chengming Xu, Xiaobin Hu, Kai Wu, Donghao Luo, Yabiao Wang, Lizhuang Ma
2024 J jnl
IEEE Trans. Pattern Anal. Mach. Intell.
Ran Yi, Teng Hu, Mengfei Xia, Yizhe Tang, Yong-Jin Liu
2024 conf
ECCV (8)
Ke Fan, Junshu Tang, Weijian Cao, Ran Yi, Moran Li, Jingyu Gong, Jiangning Zhang, Yabiao Wang, Chengjie Wang, Lizhuang Ma
2024 J jnl
CoRR
Ke Fan, Junshu Tang, Weijian Cao, Ran Yi, Moran Li, Jingyu Gong, Jiangning Zhang, Yabiao Wang, Chengjie Wang, Lizhuang Ma
2024 conf
SIGGRAPH Asia Technical Communications
Junli Zhao, Chengyuan Wang, Yu-Hui Wen, Fuqing Duan, Ran Yi, Yong-Jin Liu, Qingdong Long, Zhenkuan Pan, Xianfeng Gu
2024 A* conf
ACM Multimedia
Yuzhen Du, Teng Hu, Ran Yi, Lizhuang Ma
2024 J jnl
CoRR
Yating Wang, Ran Yi, Ke Fan, Jinkun Hao, Jiangbo Lu, Lizhuang Ma
2024 J jnl
CoRR
Chengjie Wang, Haokun Zhu, Jinlong Peng, Yue Wang, Ran Yi, Yunsheng Wu, Lizhuang Ma, Jiangning Zhang
2024 J jnl
IEEE Trans. Circuits Syst. Video Technol.
Wenhao Cai, Junli Zhao, Ran Yi, Minjing Yu, Fuqing Duan, Zhenkuan Pan, Yong-Jin Liu
2024 A* conf
ICRA
Yuze He, Peng Wang, Yubin Hu, Wang Zhao, Ran Yi, Yong-Jin Liu, Wenping Wang
2024 J jnl
IEEE Trans. Vis. Comput. Graph.
Xianhe Jiao, Chenlei Lv, Ran Yi, Junli Zhao, Zhenkuan Pan, Zhongke Wu, Yong-Jin Liu
2024 J jnl
CoRR
Zehuan Huang, Yuan-Chen Guo, Haoran Wang, Ran Yi, Lizhuang Ma, Yan-Pei Cao, Lu Sheng
2024 J jnl
CoRR
Teng Hu, Jiangning Zhang, Ran Yi, Yating Wang, Hongrui Huang, Jieyu Weng, Yabiao Wang, Lizhuang Ma
2024 J jnl
CoRR
Sheng Ye, Yuze He, Matthieu Lin, Jenny Sheng, Ruoyu Fan, Yiheng Han, Yubin Hu, Ran Yi, Yu-Hui Wen, Yong-Jin Liu, Wenping Wang
2024 J jnl
ACM Trans. Graph.
Sheng Ye, Yuze He, Matthieu Lin, Jenny Sheng, Ruoyu Fan, Yiheng Han, Yubin Hu, Ran Yi, Yu-Hui Wen, Yong-Jin Liu, Wenping Wang
2024 J jnl
CoRR
Guangben Lu, Yuzhen Du, Zhimin Sun, Ran Yi, Yifan Qi, Yizhe Tang, Tianyi Wang, Lizhuang Ma, Fangyuan Zou
2024 J jnl
CoRR
Jinkun Hao, Junshu Tang, Jiangning Zhang, Ran Yi, Yijia Hong, Moran Li, Weijian Cao, Yating Wang, Lizhuang Ma
2024 A* conf
CVPR
Bin Fang, Bo Li, Shuang Wu, Shouhong Ding, Ran Yi, Lizhuang Ma
2024 J jnl
CoRR
Mengfei Xia, Nan Xue, Yujun Shen, Ran Yi, Tieliang Gong, Yong-Jin Liu
2024 Misc conf
ICASSP
Haokun Zhu, Juang Ian Chong, Teng Hu, Ran Yi, Yu-Kun Lai, Paul L. Rosin
2024 A* conf
CVPR
Sichen Chen, Yingyi Zhang, Siming Huang, Ran Yi, Ke Fan, Ruixin Zhang, Peixian Chen, Jun Wang, Shouhong Ding, Lizhuang Ma
2024 J jnl
CoRR
Sichen Chen, Yingyi Zhang, Siming Huang, Ran Yi, Ke Fan, Ruixin Zhang, Peixian Chen, Jun Wang, Shouhong Ding, Lizhuang Ma
2024 A* conf
ICML
Mengfei Xia, Yujun Shen, Ceyuan Yang, Ran Yi, Wenping Wang, Yongjin Liu
2024 J jnl
CoRR
Teng Hu, Jiangning Zhang, Ran Yi, Hongrui Huang, Yabiao Wang, Lizhuang Ma
2024 J jnl
CoRR
Yijia Hong, Yuan-Chen Guo, Ran Yi, Yulong Chen, Yan-Pei Cao, Lizhuang Ma
2024 A* conf
CVPR
Teng Hu, Ran Yi, Baihong Qian, Jiangning Zhang, Paul L. Rosin, Yu-Kun Lai
2024 J jnl
CoRR
Teng Hu, Ran Yi, Baihong Qian, Jiangning Zhang, Paul L. Rosin, Yu-Kun Lai
2024 J jnl
CoRR
Ke Fan, Jiangning Zhang, Ran Yi, Jingyu Gong, Yabiao Wang, Yating Wang, Xin Tan, Chengjie Wang, Lizhuang Ma
2024 A* conf
CVPR
Mengfei Xia, Yujun Shen, Changsong Lei, Yu Zhou, Deli Zhao, Ran Yi, Wenping Wang, Yong-Jin Liu
2024 J jnl
CoRR
Xianhe Jiao, Chenlei Lv, Junli Zhao, Ran Yi, Yu-Hui Wen, Zhenkuan Pan, Zhongke Wu, Yong-Jin Liu
2023 J jnl
IEEE Trans. Vis. Comput. Graph.
Zipeng Ye, Mengfei Xia, Yanan Sun, Ran Yi, Minjing Yu, Juyong Zhang, Yu-Kun Lai, Yong-Jin Liu
2023 J jnl
Comput. Graph.
Yong-Jin Liu, Baodong Wang, Lin Gao, Junli Zhao, Ran Yi, Minjing Yu, Zhenkuan Pan, Xianfeng Gu
2023 J jnl
CoRR
Teng Hu, Jiangning Zhang, Ran Yi, Yuzhen Du, Xu Chen, Liang Liu, Yabiao Wang, Chengjie Wang
2023 J jnl
IEEE Trans. Multim.
Zipeng Ye, Mengfei Xia, Ran Yi, Juyong Zhang, Yu-Kun Lai, Xuwei Huang, Guo-Xin Zhang, Yong-Jin Liu
2023 J jnl
CoRR
Changsong Lei, Mengfei Xia, Shaofeng Wang, Yaqian Liang, Ran Yi, Yu-Hui Wen, Yong-Jin Liu
2023 A* conf
ICCV
Zhimin Sun, Shen Chen, Taiping Yao, Bangjie Yin, Ran Yi, Shouhong Ding, Lizhuang Ma
2023 J jnl
CoRR
Zhimin Sun, Shen Chen, Taiping Yao, Bangjie Yin, Ran Yi, Shouhong Ding, Lizhuang Ma
2023 Misc conf
ICASSP
Meng Liu, Ran Yi, Lizhuang Ma
2023 J jnl
Comput. Graph.
Yanan Sun, Zhiyao Sun, Yu-Hui Wen, Sheng Ye, Tian Lv, Minjing Yu, Ran Yi, Lin Gao, Yong-Jin Liu
2023 conf
MMAsia
Miaomiao Dai, Hao Yin, Ran Yi, Lizhuang Ma
2023 conf
CAD/Graphics
Bin Fang, Ran Yi, Lizhuang Ma
2023 A* conf
CVPR
Qianyu Zhou, Ke-Yue Zhang, Taiping Yao, Xuequan Lu, Ran Yi, Shouhong Ding, Lizhuang Ma
2023 J jnl
CoRR
Qianyu Zhou, Ke-Yue Zhang, Taiping Yao, Xuequan Lu, Ran Yi, Shouhong Ding, Lizhuang Ma
2023 B conf
ICIP
Hexiang Wang, Fengqi Liu, Ran Yi, Lizhuang Ma
2023 A* conf
ICCV
Zhiwei Zhang, Zhizhong Zhang, Qian Yu, Ran Yi, Yuan Xie, Lizhuang Ma
2023 J jnl
CoRR
Zhiwei Zhang, Zhizhong Zhang, Qian Yu, Ran Yi, Yuan Xie, Lizhuang Ma
2023 J jnl
CoRR
Yuze He, Peng Wang, Yubin Hu, Wang Zhao, Ran Yi, Yong-Jin Liu, Wenping Wang
2023 A* conf
ICCV
Junshu Tang, Tengfei Wang, Bo Zhang, Ting Zhang, Ran Yi, Lizhuang Ma, Dong Chen
2023 J jnl
CoRR
Junshu Tang, Tengfei Wang, Bo Zhang, Ting Zhang, Ran Yi, Lizhuang Ma, Dong Chen
2023 A* conf
CVPR
Yue Wang, Jinlong Peng, Jiangning Zhang, Ran Yi, Yabiao Wang, Chengjie Wang
2023 J jnl
CoRR
Yue Wang, Jinlong Peng, Jiangning Zhang, Ran Yi, Yabiao Wang, Chengjie Wang
2023 J jnl
Comput. Graph.
Ruizhao Chen, Ran Yi, Tuanfeng Yang Wang, Lizhuang Ma
2023 A* conf
ICCV
Teng Hu, Jiangning Zhang, Liang Liu, Ran Yi, Siqi Kou, Haokun Zhu, Xu Chen, Yabiao Wang, Chengjie Wang, Lizhuang Ma
2023 J jnl
CoRR
Teng Hu, Jiangning Zhang, Liang Liu, Ran Yi, Siqi Kou, Haokun Zhu, Xu Chen, Yabiao Wang, Chengjie Wang, Lizhuang Ma
2023 J jnl
IEEE Trans. Multim.
Ran Yi, Zipeng Ye, Zhiyao Sun, Juyong Zhang, Guo-Xin Zhang, Pengfei Wan, Hujun Bao, Yong-Jin Liu
2023 J jnl
IEEE Trans. Pattern Anal. Mach. Intell.
Ran Yi, Yong-Jin Liu, Yu-Kun Lai, Paul L. Rosin
2023 A* conf
IJCAI
Ke Fan, Changan Wang, Yabiao Wang, Chengjie Wang, Ran Yi, Lizhuang Ma
2023 J jnl
CoRR
Ke Fan, Changan Wang, Yabiao Wang, Chengjie Wang, Ran Yi, Lizhuang Ma
2023 A* conf
SIGGRAPH Asia
Zixi Shu, Ran Yi, Yuqi Meng, Yutong Wu, Lizhuang Ma
2023 J jnl
CoRR
Bin Fang, Bo Li, Shuang Wu, Ran Yi, Shouhong Ding, Lizhuang Ma
2023 A* conf
ICCV
Zhihao Gu, Liang Liu, Xu Chen, Ran Yi, Jiangning Zhang, Yabiao Wang, Chengjie Wang, Annan Shu, Guannan Jiang, Lizhuang Ma
2023 J jnl
CoRR
Haokun Zhu, Juang Ian Chong, Teng Hu, Ran Yi, Yu-Kun Lai, Paul L. Rosin
2023 J jnl
CoRR
Mengfei Xia, Yujun Shen, Ceyuan Yang, Ran Yi, Wenping Wang, Yong-Jin Liu
2023 A* conf
ACM Multimedia
Teng Hu, Ran Yi, Haokun Zhu, Liang Liu, Jinlong Peng, Yabiao Wang, Chengjie Wang, Lizhuang Ma
2023 J jnl
CoRR
Teng Hu, Ran Yi, Haokun Zhu, Liang Liu, Jinlong Peng, Yabiao Wang, Chengjie Wang, Lizhuang Ma
2023 J jnl
CoRR
Yuze He, Yushi Bai, Matthieu Lin, Wang Zhao, Yubin Hu, Jenny Sheng, Ran Yi, Juanzi Li, Yong-Jin Liu
2023 conf
CISP-BMEI
Ang Chen, Ran Yi, Lizhuang Ma
2023 A* conf
ACM Multimedia
Yue Wang, Jinlong Peng, Jiangning Zhang, Ran Yi, Liang Liu, Yabiao Wang, Chengjie Wang
2023 J jnl
CoRR
Yue Wang, Jinlong Peng, Jiangning Zhang, Ran Yi, Liang Liu, Yabiao Wang, Chengjie Wang
2023 A* conf
CVPR
Ran Yi, Haoyuan Tian, Zhihao Gu, Yu-Kun Lai, Paul L. Rosin
2023 J jnl
CoRR
Ran Yi, Haoyuan Tian, Zhihao Gu, Yu-Kun Lai, Paul L. Rosin
2023 J jnl
CoRR
Bin Fang, Bo Li, Shuang Wu, Tianyi Zheng, Shouhong Ding, Ran Yi, Lizhuang Ma
2023 J jnl
CoRR
Mengfei Xia, Yujun Shen, Changsong Lei, Yu Zhou, Ran Yi, Deli Zhao, Wenping Wang, Yong-Jin Liu
2023 conf
CAD/Graphics
Hao Yang, Haijia Sun, Qianyu Zhou, Ran Yi, Lizhuang Ma
2022 A* conf
ACM Multimedia
Qianyu Zhou, Ke-Yue Zhang, Taiping Yao, Ran Yi, Shouhong Ding, Lizhuang Ma
2022 J jnl
CoRR
Qianyu Zhou, Ke-Yue Zhang, Taiping Yao, Ran Yi, Shouhong Ding, Lizhuang Ma
2022 conf
SIGGRAPH (Conference Paper Track)
Ran Yi, Zipeng Ye, Ruoyu Fan, Yezhi Shu, Yong-Jin Liu, Yu-Kun Lai, Paul L. Rosin
2022 J jnl
CoRR
Zipeng Ye, Mengfei Xia, Ran Yi, Juyong Zhang, Yu-Kun Lai, Xuwei Huang, Guo-Xin Zhang, Yong-Jin Liu
2022 J jnl
CoRR
Yifeng Chen, Wenqing Chu, Fangfang Wang, Ying Tai, Ran Yi, Zhenye Gan, Liang Yao, Chengjie Wang, Xi Li
2022 J jnl
CoRR
Yue Wang, Ran Yi, Ying Tai, Chengjie Wang, Lizhuang Ma
2022 A conf
ICME
Qianyu Zhou, Chuyun Zhuang, Ran Yi, Xuequan Lu, Lizhuang Ma
2022 J jnl
CoRR
Zipeng Ye, Zhiyao Sun, Yu-Hui Wen, Yanan Sun, Tian Lv, Ran Yi, Yong-Jin Liu
2022 A* conf
AAAI
Qiqi Gu, Shen Chen, Taiping Yao, Yang Chen, Shouhong Ding, Ran Yi
2022 J jnl
IEEE Trans. Vis. Comput. Graph.
Yezhi Shu, Ran Yi, Mengfei Xia, Zipeng Ye, Wang Zhao, Yang Chen, Yu-Kun Lai, Yong-Jin Liu
2022 conf
ECCV (5)
Qianyu Zhou, Ke-Yue Zhang, Taiping Yao, Ran Yi, Kekai Sheng, Shouhong Ding, Lizhuang Ma
2022 J jnl
CoRR
Qianyu Zhou, Ke-Yue Zhang, Taiping Yao, Ran Yi, Kekai Sheng, Shouhong Ding, Lizhuang Ma
2022 A* conf
CVPR
Shaohua Guo, Liang Liu, Zhenye Gan, Yabiao Wang, Wuhao Zhang, Chengjie Wang, Guannan Jiang, Wei Zhang, Ran Yi, Lizhuang Ma, Ke Xu
2022 A* conf
CVPR
Junshu Tang, Zhijun Gong, Ran Yi, Yuan Xie, Lizhuang Ma
2022 J jnl
CoRR
Junshu Tang, Zhijun Gong, Ran Yi, Yuan Xie, Lizhuang Ma
2022 J jnl
Quant. Biol.
Ran Yi, Rui Zeng, Yang Weng, Minjing Yu, Yu-Kun Lai, Yong-Jin Liu
2022 J jnl
Comput. Vis. Media
Paul L. Rosin, Yu-Kun Lai, David Mould, Ran Yi, Itamar Berger, Lars Doyle, Seungyong Lee, Chuan Li, Yong-Jin Liu, Amir Semmo, Ariel Shamir, Minjung Son, Holger Winnemöller
2022 conf
ECCV (2)
Jingyu Gong, Fengqi Liu, Jiachen Xu, Min Wang, Xin Tan, Zhizhong Zhang, Ran Yi, Haichuan Song, Yuan Xie, Lizhuang Ma
2022 J jnl
CoRR
Ran Yi, Yong-Jin Liu, Yu-Kun Lai, Paul L. Rosin
2022 J jnl
Virtual Real. Intell. Hardw.
Chuxuan Li, Ran Yi, Saba Ghazanfar Ali, Lizhuang Ma, Enhua Wu, Jihong Wang, Lijuan Mao, Bin Sheng
2022 A* conf
IJCAI
Zhihao Gu, Taiping Yao, Yang Chen, Ran Yi, Shouhong Ding, Lizhuang Ma
2022 A* conf
ACM Multimedia
Qi Liu, Nianjuan Jiang, Jiangbo Lu, Mingang Chen, Ran Yi, Lizhuang Ma
2021 conf
ICME Workshops
Yezhi Shu, Ran Yi, Yong-Jin Liu
2021 J jnl
CoRR
Qiqi Gu, Shen Chen, Taiping Yao, Yang Chen, Shouhong Ding, Ran Yi
2021 J jnl
IEEE Trans. Pattern Anal. Mach. Intell.
Ran Yi, Zipeng Ye, Wang Zhao, Minjing Yu, Yu-Kun Lai, Yong-Jin Liu
2021 J jnl
IEEE Trans. Pattern Anal. Mach. Intell.
Ran Yi, Mengfei Xia, Yong-Jin Liu, Yu-Kun Lai, Paul L. Rosin
2021 conf
ICME Workshops
Ran Yi, Yong-Jin Liu
2020 J jnl
CoRR
Zipeng Ye, Ran Yi, Minjing Yu, Juyong Zhang, Yu-Kun Lai, Yong-Jin Liu
2020 J jnl
CoRR
Ran Yi, Zipeng Ye, Juyong Zhang, Hujun Bao, Yong-Jin Liu
2020 J jnl
Comput. Aided Des.
Zipeng Ye, Ran Yi, Wen-Yong Gong, Ying He, Yong-Jin Liu
2020 J jnl
CoRR
Paul L. Rosin, Yu-Kun Lai, David Mould, Ran Yi, Itamar Berger, Lars Doyle, Seungyong Lee, Chuan Li, Yong-Jin Liu, Amir Semmo, Ariel Shamir, Minjung Son, Holger Winnemöller
2020 A* conf
CVPR
Ran Yi, Yong-Jin Liu, Yu-Kun Lai, Paul L. Rosin
2019 J jnl
CoRR
Yiheng Han, Wang Zhao, Jia Pan, Zipeng Ye, Ran Yi, Yong-Jin Liu
2019 A* conf
CVPR
Ran Yi, Yong-Jin Liu, Yu-Kun Lai, Paul L. Rosin
2019 B conf
ICIP
Wang Zhao, Ran Yi, Yong-Jin Liu
2019 A* conf
ICCV
Zipeng Ye, Ran Yi, Minjing Yu, Yong-Jin Liu, Ying He
2019 J jnl
CoRR
Zipeng Ye, Ran Yi, Minjing Yu, Yong-Jin Liu, Ying He
2019 conf
ICAAI
Xu Yan, Yuntao Wang, Ran Yi, Zhiyu Sun, Yong-Jin Liu
2018 A* conf
CVPR
Ran Yi, Yong-Jin Liu, Yu-Kun Lai
2018 J jnl
ACM Trans. Graph.
Ran Yi, Yong-Jin Liu, Ying He
2018 J jnl
IEEE Trans Autom. Sci. Eng.
Ran Yi, Chenming Wu, Yong-Jin Liu, Ying He, Charlie C. L. Wang
2018 B conf
ICIP
Ran Yi, Yong-Jin Liu, Yu-Kun Lai
2016 A conf
IROS
Chenming Wu, Ran Yi, Yong-Jin Liu, Ying He, Charlie C. L. Wang
2016 J jnl
ACM Trans. Graph.
Yong-Jin Liu, Chunxu Xu, Ran Yi, Dian Fan, Ying He
2016 conf
SIGGRAPH Asia Posters
Ran Yi, Chenming Wu, Yong-Jin Liu, Charlie C. L. Wang
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