freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

APK文件隐私合规检测-静态分析篇(1)
2024-07-31 19:04:39

本系列主要从隐私权限、第三方sdk、个人信息,三个方面展开对APP的隐私问题静态分析,主要探讨在没有成熟工具的情况下,如何使用androguard对一个APK文件进行分析。
本文主要涉及androguard介绍、APK文件基本信息和隐私权限的静态检查
阅读本文需要对python和Android有基础了解

androguard工具介绍

Androguard是一个开源的Android应用程序分析工具,主要用于对APK文件进行静态和动态分析。它提供了多种功能,可以帮助安全研究人员、逆向工程师和开发人员分析Android应用程序的内部结构和行为。
主要功能包括:

  1. 反编译与分析
    • Androguard可以将APK文件反编译成可读的Smali代码,这是Android应用程序的汇编语言表示形式。
    • 它还能够将Smali代码转换回Java代码,使得代码审查更加容易。
  2. 静态分析
    • Androguard允许用户检查APK的文件结构、资源、权限请求和Android清单文件中声明的组件。
    • 可以分析APK中使用的第三方库和依赖。
  3. 动态分析
    • 尽管Androguard主要用于静态分析,但它也能辅助动态分析。例如,可以提取APK的DEX文件并在Dalvik虚拟机或ART运行时中执行。
  4. 自动化分析
    • 提供了Python API,允许用户编写脚本来自动化和批量处理APK的分析。

APK解析过程:
Androguard通过以下步骤对APK进行解析:

  1. 加载APK文件
    • Androguard会加载APK文件,包含了应用程序的所有资源、代码和配置信息
    • Androguard会解析APK中的AndroidManifest.xml文件,这是Android应用程序的配置文件,其中包含了应用程序的组件、权限请求和其他重要信息。
  2. 提取DEX文件
    • Androguard能够提取APK中的DEX(Dalvik Executable)文件,这是Android应用程序的核心代码文件,它包含了应用程序的字节码和相关的数据。
    • 对提取的DEX文件进行分析,包括查找和识别类、方法和字段等信息。
  3. 反编译Smali代码
    • Androguard可以将DEX文件中的字节码反编译成Smali代码,这使得逆向工程师可以查看和理解应用程序的工作原理。
    • Smali是一种文本格式的汇编语言,用于表示Android应用程序的字节码指令序列。Smali代码可以反编译自APK中的DEX文件,用于分析和理解应用程序的具体实现。

AnalyzeAPK解析APK示例:
AnalyzeAPK函数通常返回三个主要对象,即 a, d, dx。它们分别代表以下内容:

  1. a 是一个表示整个APK文件的对象。它通常包含了APK的各种元数据信息,比如应用程序的名称、版本号、包名、权限请求、清单文件内容等。在Androguard中,通常可以通过 a.get_app_name()、a.get_package() 等方法来获取这些信息。
  2. d 是一个表示APK中的Dex文件的对象。Dex文件包含了应用程序的字节码和相关的数据。通过 d.classes,可以访问到Dex文件中反编译后的类信息,包括类的方法、字段等。
  3. dx检测包体基本信息(隐私合规相关)。

d = DalvikVMFormat(a.get_dex())
dx = VMAnalysis(d)

---------以上由AI辅助生成------
参考材料如下
https://github.com/androguard/androguard
https://androguard.readthedocs.io/en/latest/

检测包体基本信息(隐私合规相关)

#解析包体,解析获得a、d、dx。
androguard analyze XX.apk
#获取包名、名称、版本号、图标
a.get_package()
a.get_app_name()
a.get_androidversion_name()
a.get_app_icon()
#获取sdk版本信息
a.get_min_sdk_version()
a.get_max_sdk_version()
a.get_target_sdk_version()  # 版本不得小于28,部分渠道要求不得低于30
#获取应用声明的系统权限,manifest文件的
a.get_permissions()
#获取代码中动态请求的权限,requestpermission()函数
#获取第三方sdk。
#manifest中services name\activity name\provider name\receiver name.
#dex文件中的classes,遍历目录文件名
a.get_services()\get_activities()\get_providers()\get_receivers()
dexss=list(dx.classes.keys())
new_dess = [item[1:].replace("/", ".") for item in dexss]

检测隐私权限

静态检查可以从两方面进行,方法1为主,方法2仅作参考

1. menifest文件中的声明
通过androguard对apk文件进行解析,主要加载APK文件的manifest文件,使用a.get_permissions()获取已声明的文件,并对比最新的隐私权限列表(可以看我之前的文章),找出目标内容

2. requestPermission函数
因为Android6之后危险权限需要动态申请、检查等,通过androguard对apk的dex进行解析,使用dx.get_methods()获取各个方法,并查找是否含有requestPermission以及权限特征“android.permisson.XXX",并输出权限代码和源代码

注:这个方法缺陷明显,External类型无法解析,且可能是第三方引入但应用无法使用,且因混淆等原因可能查不到对应代码。故该方法只能作为方法1的对比检查。(可以进一步优化,使用d来解析methods)
参考https://developer.aliyun.com/article/1129350 参考了此文,但检查结果和APP实际不太一样,这个方法我还没深刻领会
参考https://blog.csdn.net/ybdesire/article/details/52629142

import sys
import os
import androguard
import pandas as pd
from androguard.misc import AnalyzeAPK
from loguru import logger
logger.remove(handler_id=None)

def check_level(apkPerDict):
    perLevel_file = r"危险权限表地址"
    level_data = pd.read_csv(perLevel_file)
    dangerous_list = level_data['permission'].values.tolist()
    dangerous_name = level_data['name'].values.tolist()
    dangerous_level = level_data['level'].values.tolist()
    for apk_per in apkPerDict.keys():
        for dangerous in dangerous_list:
            i = dangerous_list.index(dangerous)
            if apk_per == ('android.permission.') + dangerous:
                apkPerDict[apk_per] = str(dangerous_name[i] + dangerous_level[i])

    return apkPerDict

def check_permission(apk):
    permissions_list = apk.get_permissions()
    apk_permissions = dict.fromkeys(permissions_list)
    apkperLevels = check_level(apk_permissions)
    print("权限列表:")
    for key, value in apkperLevels.items():
        if value != None:
             print(key + '----------------------------' + str(value))

# 只能静态解析apk自己的方法,来自外部库或系统的方法无法静态分析
# 混淆、源码不可用等,均可能影响结果
# 危险权限均需要使用requestpermission进行动态申请
def check_permissionmathod(dx):

    ExternalMethod_num = 0
    reslut_detail = []
    reslut = []

    for method in dx.get_methods():
        meth = method.get_method()
        try:
            c = meth.get_code()
            code = c.get_bc()
            n = code.get_instructions() 
            for idx, instruction in enumerate(n):
                method_c = instruction.get_output()

                if "requestPermissions" in method_c:
                    n = meth.get_class_name() + "-" + meth.get_name() + "-" + str(meth.get_descriptor())
                    #print("字节码类名方法名参数" + n)
                   # print("完整指令" + instruction.get_name() + " " + method_c)
                    try:
                        s = meth.get_source()
                        #print("源代码" + s)
                        pattern = r'android\.permission\.[^\s,;]*'
                        matches = re.findall(pattern, s)
                        if matches:
                            w = str("FIND::" + n + "-" + s)
                            reslut_detail.append(w)
                            for match in matches:
                                match = match.replace('"', '').replace(')', '')
                                reslut.append(match)
                    except TypeError as e:
                        print("Error:", e)
                    #print("\n")
                ExternalMethod_num = ExternalMethod_num + 1

        except AttributeError as e:
            ExternalMethod_num = ExternalMethod_num + 1
    print("外库与系统方法数" + str(ExternalMethod_num))
    print("敏感权限信息如下(仅参考):")
    reslutA = list(set(reslut))
    for e in reslutA:
        print(e)
    print("源代码")
    for a in reslut_detail:
        print(a)
if __name__ == '__main__':
    file_path = sys.argv[1]
    file_path = file_path.replace("\\", "/") + "/"
    apks = [f for f in os.listdir(file_path) if f.endswith(".apk")]
    print("开始分析")
    for apk in apks:
        print(f"应用程序名称: {apk}")
        apk, dex, dx = AnalyzeAPK(os.path.join(file_path, apk))
        # 从manifest文件中发现危险权限
        check_permission(apk)
        # 从dex文件的方法中发现危险权限的申请行为
        check_permissionmathod(dx)
    pass

以上代码及涉及的辅助库表,后续均会维护在集中地址,欢迎持续关注本系列

# App合规 # App安全合规检测
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者