• 注册
  • Android博客 Android博客 关注:0 内容:1372

    教你如何高效的检查APK中使用敏感权限的地方以及检查某系统方法被调用的地方

  • 查看作者
  • 打赏作者
  • 当前位置: 职业司 > Android开发 > Android博客 > 正文
    • Android博客
    • 前言

      相信最近在App上架应用商店的同学都感受到了,国内对用户的隐私越来越重视,如MAC地址,设备ID,IMEI信息等,要么就干脆不用,要么就必须很明显的告诉用户想要获取这些信息,相关法律及规定,参考《网络安全法》及《关于开展APP侵害用户权益专项整治工作的通知》

      开门见山

      废话不多说,找了几个反编译工具,并简单看了下使用方法,最终锁定androguard,官方解释:对Android应用程序的逆向工程、恶意软件和恶意软件分析,它提供了一系列的Apk以及dex、odex、arsc等文件的分析处理功能,可以轻松的帮助我们找到调用系统权限的地方。且python脚本执行,简直不能再好用了

      环境

      • python
       链接
      复制代码
      • pycharm
       链接
      复制代码
      • androguard
       链接
      复制代码

      安装

      pip install -U androguard
      复制代码

      如果想在命令行直接操作,请在安装完后执行如下:

      androguard analyze
      复制代码

      执行后如图:
      教你如何高效的检查APK中使用敏感权限的地方以及检查某系统方法被调用的地方
      然后再加载apk,在上面执行后,输入如下:

      a, d, dx = AnalyzeAPK("examples/android/abcore/app-prod-debug.apk")
      复制代码

      apk加载完成后就可以调用相关api来获取信息

      获取权限

      In [2]: a.get_permissions()
      Out[2]:
      ['android.permission.INTERNET',
      'android.permission.WRITE_EXTERNAL_STORAGE',
      'android.permission.ACCESS_WIFI_STATE',
      'android.permission.ACCESS_NETWORK_STATE']
      复制代码

      获取Activity

      In [3]: a.get_activities()
      Out[3]:
      ['com.greenaddress.abcore.MainActivity',
      'com.greenaddress.abcore.BitcoinConfEditActivity',
      'com.greenaddress.abcore.AboutActivity',
      'com.greenaddress.abcore.SettingsActivity',
      'com.greenaddress.abcore.DownloadSettingsActivity',
      'com.greenaddress.abcore.PeerActivity',
      'com.greenaddress.abcore.ProgressActivity',
      'com.greenaddress.abcore.LogActivity',
      'com.greenaddress.abcore.ConsoleActivity',
      'com.greenaddress.abcore.DownloadActivity']
      复制代码

      其他

      # 包名
      In [4]: a.get_package()
      Out[4]: 'com.greenaddress.abcore'
      # app名字
      In [5]: a.get_app_name()
      Out[5]: u'ABCore'
      # logo
      In [6]: a.get_app_icon()
      Out[6]: u'res/mipmap-xxxhdpi-v4/ic_launcher.png'
      # 版本号
      In [7]: a.get_androidversion_code()
      Out[7]: '2162'
      # 版本名
      In [8]: a.get_androidversion_name()
      Out[8]: '0.62'
      # 最低sdk支持
      In [9]: a.get_min_sdk_version()
      Out[9]: '21'
      # 最高
      In [10]: a.get_max_sdk_version()
      # 目标版本
      In [11]: a.get_target_sdk_version()
      Out[11]: '27'
      # 获取有效目标版本
      In [12]: a.get_effective_target_sdk_version()
      Out[12]: 27
      # manifest文件
      In [13]: a.get_android_manifest_xml()
      Out[13]: <Element manifest at 0x7f9d01587b00>
      复制代码

      等等吧,Api实在是太多了,还是关注官方文档吧,只有你想不到,没有它没有的,如下链接:

       链接
      复制代码

      更多demo

       链接
      复制代码

      下面直接开始实践。

      检索使用敏感权限的地方并输出文件

      下面就是检查APK中使用敏感权限的实现,请看:

      import os
      import sys
      # 引入androguard的路径,根据个人存放的位置而定
      androguard_module_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'androguard')
      if not androguard_module_path in sys.path:
      sys.path.append(androguard_module_path)
      from androguard.misc import AnalyzeAPK
      from androguard.core.androconf import load_api_specific_resource_module
      path = r"/apk"
      out_path = r"/out"
      files = []
      path_list = os.listdir(path)
      path_list.sort()
      for name in path_list:
      if os.path.isfile(os.path.join(path, name)):
      files.append(name)
      def main():
      for apkFile in files:
      file_name = os.path.splitext(apkFile)[0]
      print(apkFile)
      out = AnalyzeAPK(path + '/' + apkFile)
      # apk object 抽象apk对象,可以获取apk的一些信息,如版本号、包名、Activity等
      a = out[0]
      # DalvikVMFormat 数组,一个元素其实对应的是class.dex,可以从DEX文件中获取类、方法或字符串。
      d = out[1]
      # Analysis 分析对象,因为它包含特殊的类,这些类链接有关classes.dex的信息,甚至可以一次处理许多dex文件,所以下面我们从这里面来分析整个apk
      dx = out[2]
      # api和权限映射
      # 输出文件路径
      api_perm_filename = os.path.join(out_path, file_name + "_api-perm.txt")
      api_perm_file = open(api_perm_filename, 'w', encoding='utf-8')
      # 权限映射map
      permissionMap = load_api_specific_resource_module('api_permission_mappings')
      # 遍历apk所有方法
      for meth_analysis in dx.get_methods():
      meth = meth_analysis.get_method()
      # 获取类名、方法名
      name = meth.get_class_name() + "-" + meth.get_name() + "-" + str(
      meth.get_descriptor())
      for k, v in permissionMap.items():
      # 匹配系统权限方法,匹配上就输出到文件中
      if name == k:
      result = str(meth) + ' : ' + str(v)
      api_perm_file.write(result + '\n')
      api_perm_file.close()
      if __name__ == '__main__':
      main()
      复制代码

      输出结果

      Landroid/app/Activity;->navigateUpTo(Landroid/content/Intent;)Z : ['android.permission.BROADCAST_STICKY']
      Landroid/app/Activity;->onMenuItemSelected(I Landroid/view/MenuItem;)Z : ['android.permission.BROADCAST_STICKY']
      Landroid/app/Activity;->setRequestedOrientation(I)V : ['android.permission.BROADCAST_STICKY']
      Landroid/app/Activity;->unregisterReceiver(Landroid/content/BroadcastReceiver;)V : ['android.permission.BROADCAST_STICKY']
      Landroid/os/PowerManager$WakeLock;->acquire(J)V : ['android.permission.WAKE_LOCK']
      Landroid/os/PowerManager$WakeLock;->release()V : ['android.permission.WAKE_LOCK']
      Landroid/location/LocationManager;->isProviderEnabled(Ljava/lang/String;)Z : ['android.permission.ACCESS_COARSE_LOCATION', 'android.permission.ACCESS_FINE_LOCATION']
      Landroid/location/LocationManager;->getLastKnownLocation(Ljava/lang/String;)Landroid/location/Location; : ['android.permission.ACCESS_COARSE_LOCATION', 'android.permission.ACCESS_FINE_LOCATION']
      Landroid/app/ActivityManager;->getRunningTasks(I)Ljava/util/List; : ['android.permission.GET_TASKS']
      Landroid/accounts/AccountManager;->invalidateAuthToken(Ljava/lang/String; Ljava/lang/String;)V : ['android.permission.MANAGE_ACCOUNTS', 'android.permission.USE_CREDENTIALS']
      Landroid/net/ConnectivityManager;->getNetworkInfo(I)Landroid/net/NetworkInfo; : ['android.permission.ACCESS_NETWORK_STATE']
      Landroid/net/ConnectivityManager;->isActiveNetworkMetered()Z : ['android.permission.ACCESS_NETWORK_STATE']
      Landroid/net/ConnectivityManager;->getActiveNetworkInfo()Landroid/net/NetworkInfo; : ['android.permission.ACCESS_NETWORK_STATE']
      Landroid/telephony/TelephonyManager;->getDeviceId()Ljava/lang/String; : ['android.permission.READ_PHONE_STATE']
      Landroid/telephony/TelephonyManager;->getSubscriberId()Ljava/lang/String; : ['android.permission.READ_PHONE_STATE']
      Landroid/telephony/TelephonyManager;->getSimSerialNumber()Ljava/lang/String; : ['android.permission.READ_PHONE_STATE']
      复制代码

      输出的系统类、调用方法、需要的权限。

      检索某系统方法被调用的地方并打印

      import os
      import sys
      # 引入androguard的路径,根据个人存放的位置而定
      androguard_module_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'androguard')
      if not androguard_module_path in sys.path:
      sys.path.append(androguard_module_path)
      from androguard.misc import AnalyzeAPK
      from androguard.core.androconf import load_api_specific_resource_module
      path = r"/apk"
      out_path = r"/out"
      files = []
      path_list = os.listdir(path)
      path_list.sort()
      for name in path_list:
      if os.path.isfile(os.path.join(path, name)):
      files.append(name)
      def main():
      for apkFile in files:
      file_name = os.path.splitext(apkFile)[0]
      print(apkFile)
      out = AnalyzeAPK(path + '/' + apkFile)
      a = out[0]
      d = out[1]
      dx = out[2]
      for meth in dx.classes['Ljava/io/File;'].get_methods():
      print("usage of method {}".format(meth.name))
      # 拿到改函数的引用函数
      for _, call, _ in meth.get_xref_from():
      print("  called by -> {} -- {}".format(call.class_name, call.name))
      if __name__ == '__main__':
      main()
      复制代码

      输出结果

      usage of method getPath
      called by -> Landroid/support/v4/util/AtomicFile; -- <init>
      usage of method <init>
      called by -> Landroid/support/v4/util/AtomicFile; -- <init>
      usage of method delete
      called by -> Landroid/support/v4/util/AtomicFile; -- failWrite
      called by -> Landroid/support/v4/util/AtomicFile; -- delete
      called by -> Landroid/support/v4/util/AtomicFile; -- delete
      called by -> Landroid/support/v4/util/AtomicFile; -- startWrite
      called by -> Landroid/support/v4/util/AtomicFile; -- openRead
      called by -> Landroid/support/v4/util/AtomicFile; -- finishWrite
      usage of method renameTo
      called by -> Landroid/support/v4/util/AtomicFile; -- openRead
      called by -> Landroid/support/v4/util/AtomicFile; -- failWrite
      called by -> Landroid/support/v4/util/AtomicFile; -- startWrite
      usage of method exists
      called by -> Landroid/support/v4/util/AtomicFile; -- startWrite
      called by -> Landroid/support/v4/util/AtomicFile; -- openRead
      called by -> Landroid/support/v4/util/AtomicFile; -- startWrite
      usage of method getParentFile
      called by -> Landroid/support/v4/util/AtomicFile; -- startWrite
      usage of method mkdir
      called by -> Landroid/support/v4/util/AtomicFile; -- startWrite
      复制代码
      • ‘Ljava/io/File;’ 需要检测的类
      • meth.get_xref_from() 那该类中函数被引用的地方
      • 你也可以自己搞个数组,配置好要检查的相关函数,然后在上面代码中加入if过滤即可

      如果你想找Android系统定位,被应用哪些方法调用,你就可以这样做:

      dx.classes['Landroid/location/LocationManager;']
      复制代码

      再运行一遍脚本就可以看到结果了。

      结束

      写这篇博客,主要目的是为了让更多人知道这个东西吧,我自己去搜索文章的时候发现并没有多少可以参考的,导致很多人无从下手,但其实官方文档也很详细,但是英文的,看起来也不方便,也希望这篇简短的文章给你提供帮助,如果有问题请再联系我或留言评论

      欢迎关注新网站

      jetpack.net.cn

      请登录之后再进行评论

      登录

      手机阅读天地(APP)

      • 微信公众号
      • 微信小程序
      • 安卓APP
      手机浏览,惊喜多多
      匿名树洞,说我想说!
      问答悬赏,VIP可见!
      密码可见,回复可见!
      即时聊天、群聊互动!
      宠物孵化,赠送礼物!
      动态像框,专属头衔!
      挑战/抽奖,金币送不停!
      赶紧体会下,不会让你失望!
    • 实时动态
    • 签到
    • 做任务
    • 发表内容
    • 偏好设置
    • 到底部
    • 帖子间隔 侧栏位置:
    • 还没有账号?点这里立即注册