extract_strings.py 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. # -*- coding: utf-8 -*-
  2. import os, re, sys, collections
  3. DEX_DIR = r"D:\IdeaProjects\mes-ahdy\mescloud\_apk_work\unzipped"
  4. OUT = r"D:\IdeaProjects\mes-ahdy\mescloud\_apk_work\extracted"
  5. os.makedirs(OUT, exist_ok=True)
  6. CN = re.compile(r"[\u4e00-\u9fff]{2,}")
  7. # printable ascii strings
  8. ASCII = re.compile(rb"[\x20-\x7e]{6,}")
  9. UTF16 = re.compile(rb"(?:[\x20-\x7e]\x00){4,}")
  10. keywords = (
  11. "Activity", "Fragment", "menu", "Menu", "pda", "PDA", "http", "mes",
  12. "scan", "Scan", "login", "Login", "com.", "/a/", "api"
  13. )
  14. all_cn = collections.Counter()
  15. ascii_hits = collections.Counter()
  16. utf16_cn = collections.Counter()
  17. urls = set()
  18. classes = set()
  19. def walk_files():
  20. for root, dirs, files in os.walk(DEX_DIR):
  21. for f in files:
  22. p = os.path.join(root, f)
  23. if f.endswith((".dex", ".xml", ".lst", ".txt", ".properties")) or "classes" in f:
  24. yield p
  25. elif f.endswith(".arsc"):
  26. yield p
  27. for path in walk_files():
  28. data = open(path, "rb").read()
  29. # utf-8 / latin
  30. try:
  31. text = data.decode("utf-8", "ignore")
  32. except Exception:
  33. text = ""
  34. for m in CN.findall(text):
  35. if 2 <= len(m) <= 40:
  36. all_cn[m] += 1
  37. for m in ASCII.findall(data):
  38. s = m.decode("ascii", "ignore")
  39. if any(k in s for k in keywords):
  40. ascii_hits[s] += 1
  41. if s.startswith("http") or s.startswith("/a/") or "mes/" in s:
  42. urls.add(s)
  43. if "Activity" in s or "Fragment" in s:
  44. classes.add(s)
  45. for m in UTF16.findall(data):
  46. try:
  47. s = m.decode("utf-16le", "ignore")
  48. except Exception:
  49. continue
  50. for c in CN.findall(s):
  51. if 2 <= len(c) <= 40:
  52. utf16_cn[c] += 1
  53. if s.startswith("http") or "/a/" in s:
  54. urls.add(s)
  55. def dump(name, items, n=None):
  56. path = os.path.join(OUT, name)
  57. with open(path, "w", encoding="utf-8") as f:
  58. for i, item in enumerate(items):
  59. if n is not None and i >= n:
  60. break
  61. if isinstance(item, tuple):
  62. f.write("%s\t%s\n" % (item[0], item[1]))
  63. else:
  64. f.write("%s\n" % item)
  65. print("wrote", path, "count", min(len(items), n or len(items)))
  66. dump("cn_strings.txt", all_cn.most_common())
  67. dump("utf16_cn.txt", utf16_cn.most_common())
  68. dump("ascii_hits.txt", ascii_hits.most_common(3000))
  69. dump("urls.txt", sorted(urls))
  70. dump("classes.txt", sorted(classes))
  71. print("cn unique", len(all_cn), "utf16 unique", len(utf16_cn), "urls", len(urls), "classes", len(classes))