Bulk APK Dangerous Permission Check

Oct. 9, 2020 // echel0n

Analyzing Dangerous Permissions

Small Python Script to Get Dangerous Permissions

Hello guys!
I would like to share with you my last script to get dangerous permissions that you would like to analyze in second.

  1. #!/usr/bin/env python
  2. import logging
  3. import mimetypes
  4. import argparse
  5. import os
  6. import json
  7. from contextlib import suppress
  8. from typing import Tuple, List, Optional, Union, Dict
  9. from androguard.misc import AnalyzeAPK
  10. from androguard.core.bytecodes.apk import BrokenAPKError
  11. logger = logging.getLogger(__file__)
  12. DANGEROUS_TYPES = frozenset(
  13. {
  14. "android.permission.READ_CALENDAR",
  15. "android.permission.WRITE_CALENDAR",
  16. "android.permission.CAMERA",
  17. "android.permission.READ_CONTACTS",
  18. "android.permission.WRITE_CONTACTS",
  19. "android.permission.GET_ACCOUNTS",
  20. "android.permission.ACCESS_FINE_LOCATION",
  21. "android.permission.ACCESS_COARSE_LOCATION",
  22. "android.permission.RECORD_AUDIO",
  23. "android.permission.READ_PHONE_STATE",
  24. "android.permission.READ_PHONE_NUMBERS",
  25. "android.permission.CALL_PHONE",
  26. "android.permission.ANSWER_PHONE_CALLS",
  27. "android.permission.READ_CALL_LOG",
  28. "android.permission.WRITE_CALL_LOG",
  29. "android.permission.ADD_VOICEMAIL",
  30. "android.permission.USE_SIP",
  31. "android.permission.PROCESS_OUTGOING_CALLS",
  32. "android.permission.BODY_SENSORS",
  33. "android.permission.SEND_SMS",
  34. "android.permission.RECEIVE_SMS",
  35. "android.permission.READ_SMS",
  36. "android.permission.RECEIVE_WAP_PUSH",
  37. "android.permission.RECEIVE_MMS",
  38. "android.permission.READ_EXTERNAL_STORAGE",
  39. "android.permission.WRITE_EXTERNAL_STORAGE",
  40. "android.permission.MOUNT_UNMOUNT_FILESYSTEMS",
  41. "android.permission.READ_HISTORY_BOOKMARKS",
  42. "android.permission.WRITE_HISTORY_BOOKMARKS",
  43. "android.permission.INSTALL_PACKAGES",
  44. "android.permission.RECEIVE_BOOT_COMPLETED",
  45. "android.permission.READ_LOGS",
  46. "android.permission.CHANGE_WIFI_STATE",
  47. "android.permission.DISABLE_KEYGUARD",
  48. "android.permission.GET_TASKS",
  49. "android.permission.BLUETOOTH",
  50. "android.permission.CHANGE_NETWORK_STATE",
  51. "android.permission.ACCESS_WIFI_STATE",
  52. }
  53. )
  54. APK_MIMETYPE = "application/vnd.android.package-archive"
  55. def valid_mimetype(filename: str) -> bool:
  56. m_type = mimetypes.guess_type(filename)
  57. logger.debug(f"{filename} mimetype is {m_type[0]}")
  58. return APK_MIMETYPE == m_type[0]
  59. def extract_filenames(directory: str) -> Optional[List[str]]:
  60. logger.info("Getting files from the given directory.")
  61. with suppress(FileNotFoundError):
  62. files = os.listdir(directory)
  63. logger.debug(f"The given directory has this files {', '.join(files)}")
  64. return files
  65. logger.error("Error at getting files from the given directory.")
  66. return None
  67. def get_permissions(apk_file: AnalyzeAPK) -> List[str]:
  68. return apk_file.get_permissions()
  69. def analyze_file(filepath: str) -> List[str]:
  70. print(filepath)
  71. logger.info("Analyzing this file -> " + filepath)
  72. with suppress(BrokenAPKError):
  73. a, _, _ = AnalyzeAPK(filepath)
  74. perms = get_permissions(a)
  75. dangerous_perms = list(DANGEROUS_TYPES.intersection(perms))
  76. return dangerous_perms
  77. logger.error("Error at creating APK Object")
  78. return ["CORRUPTED"]
  79. def parser() -> Tuple[str, str]:
  80. arg_parser = argparse.ArgumentParser() # our wise arg_parser
  81. arg_parser.add_argument(
  82. "file_or_directory", help="Chosen apk file", nargs=1, type=str
  83. )
  84. arg_parser.add_argument(
  85. "--verbose", help="Verbose Output", dest="verbose", action="store_true"
  86. )
  87. arg_parser.add_argument("--out", help="Save output to a file", type=str)
  88. parsed = arg_parser.parse_args()
  89. if parsed.verbose:
  90. logging.basicConfig(level=logging.INFO)
  91. return parsed.file_or_directory[0], parsed.out
  92. def analyze_directory(directory: str) -> Dict[str, List[str]]:
  93. filenames = extract_filenames(directory)
  94. assert isinstance(filenames, list), "aloooo admini yok mu buranin"
  95. return dict(
  96. (filename, analyze_file(f"{directory}/{filename}"))
  97. for filename in (
  98. filename
  99. for filename in filenames
  100. if valid_mimetype(f"{directory}/{filename}")
  101. )
  102. )
  103. def analyze(filename: str) -> Optional[Union[Dict[str, List[str]], List[str]]]:
  104. if os.path.isdir(filename):
  105. return analyze_directory(filename)
  106. if os.path.isfile(filename):
  107. return analyze_file(filename)
  108. return None
  109. def save(data: str, output_fname: str):
  110. output_file = open(output_fname, "w")
  111. output_file.write(data)
  112. output_file.close()
  113. logger.info("Output file created at --> " + output_fname)
  114. def main():
  115. filename, output_name = parser()
  116. rep = json.dumps(analyze(filename), indent=4)
  117. if output_name:
  118. return save(rep, os.path.realpath(output_name))
  119. print(rep)
  120. if __name__ == "__main__":
  121. main()
  1. usage: main.py [-h] [--verbose] [--out OUT] file_or_directory
  2. positional arguments:
  3. file_or_directory Chosen apk file or directory of APKs
  4. optional arguments:
  5. -h, --help show this help message and exit
  6. --verbose Verbose Output
  7. --out OUT Save output to a file
Have a nice day!