proxy.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. ##
  2. #
  3. # Copyright (C) 2002-2022 MlgmXyysd All Rights Reserved.
  4. #
  5. ##
  6. ##
  7. #
  8. # Animation Company script for mitmproxy
  9. #
  10. # https://github.com/MlgmXyysd/
  11. #
  12. # *Original fiddler script from https://github.lunatic.moe/fiddlerscript
  13. #
  14. # Environment requirement:
  15. # - mitmdump from mitmproxy
  16. #
  17. # @author MlgmXyysd
  18. # @version 1.1
  19. #
  20. ##
  21. import collections
  22. import random
  23. from mitmproxy import http, connection, ctx, tls
  24. from abc import ABC, abstractmethod
  25. from enum import Enum
  26. from mitmproxy.utils import human
  27. from proxy_config import USE_SSL
  28. from proxy_config import REMOTE_HOST
  29. from proxy_config import REMOTE_PORT
  30. class MlgmXyysd_Animation_Company_Proxy:
  31. LIST_DOMAINS = [
  32. "api-os-takumi.mihoyo.com",
  33. "hk4e-api-os-static.mihoyo.com",
  34. "hk4e-sdk-os.mihoyo.com",
  35. "dispatchosglobal.yuanshen.com",
  36. "osusadispatch.yuanshen.com",
  37. "account.mihoyo.com",
  38. "log-upload-os.mihoyo.com",
  39. "dispatchcntest.yuanshen.com",
  40. "devlog-upload.mihoyo.com",
  41. "webstatic.mihoyo.com",
  42. "log-upload.mihoyo.com",
  43. "hk4e-sdk.mihoyo.com",
  44. "api-beta-sdk.mihoyo.com",
  45. "api-beta-sdk-os.mihoyo.com",
  46. "cnbeta01dispatch.yuanshen.com",
  47. "dispatchcnglobal.yuanshen.com",
  48. "cnbeta02dispatch.yuanshen.com",
  49. "sdk-os-static.mihoyo.com",
  50. "webstatic-sea.mihoyo.com",
  51. "webstatic-sea.hoyoverse.com",
  52. "hk4e-sdk-os-static.hoyoverse.com",
  53. "sdk-os-static.hoyoverse.com",
  54. "api-account-os.hoyoverse.com",
  55. "hk4e-sdk-os.hoyoverse.com",
  56. "overseauspider.yuanshen.com",
  57. "gameapi-account.mihoyo.com",
  58. "minor-api.mihoyo.com",
  59. "public-data-api.mihoyo.com",
  60. "uspider.yuanshen.com",
  61. "sdk-static.mihoyo.com",
  62. "abtest-api-data-sg.hoyoverse.com",
  63. "log-upload-os.hoyoverse.com"
  64. ]
  65. def request(self, flow: http.HTTPFlow) -> None:
  66. if flow.request.pretty_host in self.LIST_DOMAINS:
  67. if USE_SSL:
  68. flow.request.scheme = "https"
  69. else:
  70. flow.request.scheme = "http"
  71. flow.request.host = REMOTE_HOST
  72. flow.request.port = REMOTE_PORT
  73. class InterceptionResult(Enum):
  74. SUCCESS = 1
  75. FAILURE = 2
  76. SKIPPED = 3
  77. class TlsStrategy(ABC):
  78. def __init__(self):
  79. self.history = collections.defaultdict(lambda: collections.deque(maxlen=200))
  80. @abstractmethod
  81. def should_intercept(self, server_address: connection.Address) -> bool:
  82. raise NotImplementedError()
  83. def record_success(self, server_address):
  84. self.history[server_address].append(InterceptionResult.SUCCESS)
  85. def record_failure(self, server_address):
  86. self.history[server_address].append(InterceptionResult.FAILURE)
  87. def record_skipped(self, server_address):
  88. self.history[server_address].append(InterceptionResult.SKIPPED)
  89. class ConservativeStrategy(TlsStrategy):
  90. def should_intercept(self, server_address: connection.Address) -> bool:
  91. return InterceptionResult.FAILURE not in self.history[server_address]
  92. class ProbabilisticStrategy(TlsStrategy):
  93. def __init__(self, p: float):
  94. self.p = p
  95. super().__init__()
  96. def should_intercept(self, server_address: connection.Address) -> bool:
  97. return random.uniform(0, 1) < self.p
  98. class MaybeTls:
  99. strategy: TlsStrategy
  100. def load(self, l):
  101. l.add_option(
  102. "tls_strategy", int, 0,
  103. "TLS passthrough strategy. If set to 0, connections will be passed through after the first unsuccessful "
  104. "handshake. If set to 0 < p <= 100, connections with be passed through with probability p.",
  105. )
  106. def configure(self, updated):
  107. if "tls_strategy" not in updated:
  108. return
  109. if ctx.options.tls_strategy > 0:
  110. self.strategy = ProbabilisticStrategy(ctx.options.tls_strategy / 100)
  111. else:
  112. self.strategy = ConservativeStrategy()
  113. def tls_clienthello(self, data: tls.ClientHelloData):
  114. server_address = data.context.server.peername
  115. if not self.strategy.should_intercept(server_address):
  116. ctx.log(f"TLS passthrough: {human.format_address(server_address)}.")
  117. data.ignore_connection = True
  118. self.strategy.record_skipped(server_address)
  119. def tls_established_client(self, data: tls.TlsData):
  120. server_address = data.context.server.peername
  121. ctx.log(f"TLS handshake successful: {human.format_address(server_address)}")
  122. self.strategy.record_success(server_address)
  123. def tls_failed_client(self, data: tls.TlsData):
  124. server_address = data.context.server.peername
  125. ctx.log(f"TLS handshake failed: {human.format_address(server_address)}")
  126. self.strategy.record_failure(server_address)
  127. addons = [
  128. MlgmXyysd_Animation_Company_Proxy(),
  129. MaybeTls()
  130. ]