├── .gitattributes
├── .gradle
├── 7.4.2
│ ├── checksums
│ │ ├── checksums.lock
│ │ ├── md5-checksums.bin
│ │ └── sha1-checksums.bin
│ ├── dependencies-accessors
│ │ ├── dependencies-accessors.lock
│ │ └── gc.properties
│ ├── executionHistory
│ │ ├── executionHistory.bin
│ │ └── executionHistory.lock
│ ├── fileChanges
│ │ └── last-build.bin
│ ├── fileHashes
│ │ ├── fileHashes.bin
│ │ ├── fileHashes.lock
│ │ └── resourceHashesCache.bin
│ └── gc.properties
├── buildOutputCleanup
│ ├── buildOutputCleanup.lock
│ ├── cache.properties
│ └── outputFiles.bin
└── vcs-1
│ └── gc.properties
├── README.md
├── app
├── build.gradle.kts
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── assets
│ └── xposed_init
│ ├── java
│ └── Xuoos
│ │ └── GenshinImpact
│ │ └── Proxy
│ │ ├── Hook.kt
│ │ ├── MainHook.kt
│ │ ├── ToastCustom.java
│ │ ├── TrustMeAlready.java
│ │ └── Utils.kt
│ └── res
│ ├── mipmap
│ └── xuoos.png
│ └── values
│ ├── arrays.xml
│ └── strings.xml
├── build.gradle.kts
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle.kts
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.gradle/7.4.2/checksums/checksums.lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xuoos/GenshinProxy/66d5acd9cf75042386f3b6d05ac8f9301d3644e0/.gradle/7.4.2/checksums/checksums.lock
--------------------------------------------------------------------------------
/.gradle/7.4.2/checksums/md5-checksums.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xuoos/GenshinProxy/66d5acd9cf75042386f3b6d05ac8f9301d3644e0/.gradle/7.4.2/checksums/md5-checksums.bin
--------------------------------------------------------------------------------
/.gradle/7.4.2/checksums/sha1-checksums.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xuoos/GenshinProxy/66d5acd9cf75042386f3b6d05ac8f9301d3644e0/.gradle/7.4.2/checksums/sha1-checksums.bin
--------------------------------------------------------------------------------
/.gradle/7.4.2/dependencies-accessors/dependencies-accessors.lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xuoos/GenshinProxy/66d5acd9cf75042386f3b6d05ac8f9301d3644e0/.gradle/7.4.2/dependencies-accessors/dependencies-accessors.lock
--------------------------------------------------------------------------------
/.gradle/7.4.2/dependencies-accessors/gc.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xuoos/GenshinProxy/66d5acd9cf75042386f3b6d05ac8f9301d3644e0/.gradle/7.4.2/dependencies-accessors/gc.properties
--------------------------------------------------------------------------------
/.gradle/7.4.2/executionHistory/executionHistory.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xuoos/GenshinProxy/66d5acd9cf75042386f3b6d05ac8f9301d3644e0/.gradle/7.4.2/executionHistory/executionHistory.bin
--------------------------------------------------------------------------------
/.gradle/7.4.2/executionHistory/executionHistory.lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xuoos/GenshinProxy/66d5acd9cf75042386f3b6d05ac8f9301d3644e0/.gradle/7.4.2/executionHistory/executionHistory.lock
--------------------------------------------------------------------------------
/.gradle/7.4.2/fileChanges/last-build.bin:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gradle/7.4.2/fileHashes/fileHashes.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xuoos/GenshinProxy/66d5acd9cf75042386f3b6d05ac8f9301d3644e0/.gradle/7.4.2/fileHashes/fileHashes.bin
--------------------------------------------------------------------------------
/.gradle/7.4.2/fileHashes/fileHashes.lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xuoos/GenshinProxy/66d5acd9cf75042386f3b6d05ac8f9301d3644e0/.gradle/7.4.2/fileHashes/fileHashes.lock
--------------------------------------------------------------------------------
/.gradle/7.4.2/fileHashes/resourceHashesCache.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xuoos/GenshinProxy/66d5acd9cf75042386f3b6d05ac8f9301d3644e0/.gradle/7.4.2/fileHashes/resourceHashesCache.bin
--------------------------------------------------------------------------------
/.gradle/7.4.2/gc.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xuoos/GenshinProxy/66d5acd9cf75042386f3b6d05ac8f9301d3644e0/.gradle/7.4.2/gc.properties
--------------------------------------------------------------------------------
/.gradle/buildOutputCleanup/buildOutputCleanup.lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xuoos/GenshinProxy/66d5acd9cf75042386f3b6d05ac8f9301d3644e0/.gradle/buildOutputCleanup/buildOutputCleanup.lock
--------------------------------------------------------------------------------
/.gradle/buildOutputCleanup/cache.properties:
--------------------------------------------------------------------------------
1 | #Tue Mar 28 13:01:37 GMT 2023
2 | gradle.version=7.4.2
3 |
--------------------------------------------------------------------------------
/.gradle/buildOutputCleanup/outputFiles.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xuoos/GenshinProxy/66d5acd9cf75042386f3b6d05ac8f9301d3644e0/.gradle/buildOutputCleanup/outputFiles.bin
--------------------------------------------------------------------------------
/.gradle/vcs-1/gc.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xuoos/GenshinProxy/66d5acd9cf75042386f3b6d05ac8f9301d3644e0/.gradle/vcs-1/gc.properties
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # GenshinProxy
2 |
3 | ###
4 | 本项目已不再更新,请查看我的另一个项目[AnimeGamesProxy]https://github.com/Xuoos/AnimeGamesProxy
5 |
6 | 基于方块君的GenshinProxy([577fkj](https://github.com/577fkj)) 修改
7 | 勿用于商业,否则我会直接删除本仓库
8 |
9 | qq group 782305852
10 |
11 | This is an xposed module that does not use a proxy to enter the grasscutter server
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/build.gradle.kts:
--------------------------------------------------------------------------------
1 |
2 | plugins {
3 | id("com.android.application")
4 | id("kotlin-android")
5 | }
6 |
7 | android {
8 | compileSdk = 32
9 |
10 | defaultConfig {
11 | applicationId = "Xuoos.GenshinImpact.Proxy"
12 | minSdk = 28
13 | targetSdk = 32
14 | versionCode = 3
15 | versionName = "1.0.5"
16 | }
17 |
18 |
19 |
20 | buildTypes {
21 | release {
22 | isMinifyEnabled = false
23 | isShrinkResources = false
24 | setProguardFiles(listOf(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro", "proguard-log.pro"))
25 | }
26 | }
27 |
28 | compileOptions {
29 | sourceCompatibility = JavaVersion.VERSION_11
30 | targetCompatibility = JavaVersion.VERSION_11
31 | }
32 |
33 | kotlinOptions {
34 | jvmTarget = JavaVersion.VERSION_11.majorVersion
35 | }
36 |
37 | packagingOptions {
38 | resources {
39 | excludes += "/META-INF/**"
40 | excludes += "/kotlin/**"
41 | excludes += "/*.txt"
42 | excludes += "/*.bin"
43 | }
44 | }
45 |
46 | applicationVariants.all {
47 | outputs.all {
48 | (this as com.android.build.gradle.internal.api.BaseVariantOutputImpl).outputFileName =
49 | "GI-Proxy-Xuoos-$name.apk"
50 | }
51 | }
52 | }
53 |
54 | dependencies {
55 | compileOnly("de.robv.android.xposed:api:82")
56 | compileOnly("de.robv.android.xposed:api:82:sources")
57 | implementation("com.github.kyuubiran:EzXHelper:0.9.2")
58 | implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0")
59 | }
60 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
13 |
16 |
19 |
22 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/assets/xposed_init:
--------------------------------------------------------------------------------
1 | Xuoos.GenshinImpact.Proxy.MainHook
--------------------------------------------------------------------------------
/app/src/main/java/Xuoos/GenshinImpact/Proxy/Hook.kt:
--------------------------------------------------------------------------------
1 | package Xuoos.GenshinImpact.Proxy
2 |
3 | import android.app.Activity
4 | import android.app.AlertDialog
5 | //====
6 | import android.content.ClipboardManager
7 | import android.content.Context
8 | import android.content.SharedPreferences
9 | import android.content.res.XModuleResources
10 | //====
11 | import android.graphics.Color
12 | import android.graphics.Paint
13 | import android.graphics.Typeface
14 | import android.graphics.PixelFormat
15 | import android.graphics.drawable.ShapeDrawable
16 | import android.graphics.drawable.shapes.RoundRectShape
17 | import android.graphics.drawable.ColorDrawable
18 | import android.graphics.drawable.Drawable
19 | import android.graphics.drawable.TransitionDrawable
20 | //====
21 | import android.text.style.StyleSpan
22 | import android.text.Spannable
23 | import android.text.SpannableString
24 | import android.text.style.ForegroundColorSpan
25 | import android.text.style.UnderlineSpan
26 | import android.text.Editable
27 | import android.text.InputType
28 | import android.text.TextWatcher
29 | //=====
30 | import android.view.Gravity
31 | import android.view.MotionEvent
32 | import android.view.View
33 | import android.view.WindowManager
34 | //=====
35 | import android.widget.LinearLayout
36 | import android.widget.TextView
37 | import android.widget.*
38 | //====
39 | import com.github.kyuubiran.ezxhelper.init.EzXHelperInit
40 | import com.github.kyuubiran.ezxhelper.utils.*
41 | //====
42 | import de.robv.android.xposed.IXposedHookZygoteInit
43 | import de.robv.android.xposed.XC_MethodHook
44 | import de.robv.android.xposed.XposedBridge
45 | import de.robv.android.xposed.XposedHelpers
46 | import de.robv.android.xposed.callbacks.XC_LoadPackage
47 | //====
48 | import Xuoos.GenshinImpact.Proxy.Utils.dp2px
49 | //====
50 | import java.io.BufferedReader
51 | import java.io.ByteArrayOutputStream
52 | import java.io.File
53 | import java.math.BigInteger
54 | import java.security.SecureRandom
55 | import java.security.cert.X509Certificate
56 | import java.util.regex.Pattern
57 | import java.io.IOException
58 | import java.util.*
59 | //====
60 | import javax.net.ssl.*
61 | import java.net.HttpURLConnection
62 | import java.net.URL
63 | //====
64 | import kotlinx.coroutines.Dispatchers
65 | import kotlinx.coroutines.GlobalScope
66 | import kotlinx.coroutines.launch
67 | import kotlinx.coroutines.withContext
68 | import kotlin.concurrent.thread
69 | import kotlin.system.exitProcess
70 | //====
71 | import android.webkit.SslErrorHandler
72 | import android.annotation.SuppressLint
73 |
74 | class Hook {
75 |
76 | private var SaveIP = ""
77 | private var SizeError = false
78 |
79 | private val red = Color.RED
80 | private val blue = Color.BLUE
81 | private val white = Color.WHITE
82 | private val black = Color.BLACK
83 | private val green = Color.GREEN
84 | private val yellow = Color.YELLOW
85 | private val Toast = ToastCustom.createToastConfig()
86 |
87 | private lateinit var server: String
88 | private lateinit var modulePath: String
89 | private lateinit var dialog: LinearLayout
90 | private lateinit var PackageName: String
91 | private lateinit var sp: SharedPreferences
92 | private lateinit var moduleRes: XModuleResources
93 | private lateinit var windowManager: WindowManager
94 |
95 | private val regex = Pattern.compile("http(s|)://.*?\\.(hk4e|hoyoverse|mihoyo|yuanshen|mob)\\.com")
96 |
97 | private val more_domain =
98 | arrayListOf(
99 | "overseauspider.yuanshen.com:8888",
100 | "uspider.yuanshen.com:8888"
101 | )
102 |
103 | private val activityList: ArrayList = arrayListOf()
104 | private var activity: Activity
105 | get() {
106 | for (mActivity in activityList) {
107 | if (mActivity.isFinishing) {
108 | activityList.remove(mActivity)
109 | } else {
110 | return mActivity
111 | }
112 | }
113 | throw Throwable("Activity not found.")
114 | }
115 | set(value) {
116 | activityList.add(value)
117 | }
118 |
119 | private fun getDefaultSSLSocketFactory(): SSLSocketFactory {
120 | return SSLContext.getInstance("TLS").apply {
121 | init(arrayOf(), arrayOf(DefaultTrustManager()), SecureRandom())
122 | }.socketFactory
123 | }
124 |
125 | private fun getDefaultHostnameVerifier(): HostnameVerifier {
126 | return DefaultHostnameVerifier()
127 | }
128 |
129 | class DefaultHostnameVerifier : HostnameVerifier {
130 | @SuppressLint("BadHostnameVerifier")
131 | override fun verify(p0: String?, p1: SSLSession?): Boolean {
132 | return true
133 | }
134 |
135 | }
136 |
137 | @SuppressLint("CustomX509TrustManager")
138 | private class DefaultTrustManager : X509TrustManager {
139 |
140 | @SuppressLint("TrustAllX509TrustManager")
141 | override fun checkClientTrusted(chain: Array?, authType: String?) {
142 | }
143 |
144 | @SuppressLint("TrustAllX509TrustManager")
145 | override fun checkServerTrusted(chain: Array?, authType: String?) {
146 | }
147 |
148 | override fun getAcceptedIssuers(): Array {
149 | return arrayOf()
150 | }
151 | }
152 |
153 | fun initZygote(startupParam: IXposedHookZygoteInit.StartupParam) {
154 | modulePath = startupParam.modulePath
155 | moduleRes = XModuleResources.createInstance(modulePath, null)
156 | TrustMeAlready().initZygote()
157 | }
158 |
159 | @SuppressLint("WrongConstant", "ClickableViewAccessibility")
160 | fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) {
161 |
162 | if (lpparam.packageName == "com.miHoYo.GenshinImpact" || lpparam.packageName == "com.miHoYo.Yuanshen" || lpparam.packageName == "com.miHoYo.YuanshenPS") {
163 | PackageName = lpparam.packageName
164 | EzXHelperInit.initHandleLoadPackage(lpparam)
165 |
166 | fun getFolderSize(folderPath: String): Long {
167 | val folder = File(folderPath)
168 | var totalSize: Long = 0
169 |
170 | if (folder.exists() && folder.isDirectory) {
171 | folder.listFiles()?.forEach { file ->
172 | totalSize += if (file.isFile) file.length() else getFolderSize(file.absolutePath)
173 | }
174 | }
175 | return totalSize
176 | }
177 |
178 | val folderPath = "/sdcard/Android/data/${PackageName}/files"
179 | val folderSize = getFolderSize(folderPath)
180 | var size = "无法获取"
181 | var unit = ""
182 |
183 | if (folderSize < 20L * 1024 * 1024 * 1024) {
184 |
185 | if (folderSize < 1024 * 1024) {
186 | size = (folderSize / 1024).toString()
187 | unit = "KB"
188 | } else if (folderSize < 1024 * 1024 * 1024) {
189 | size = String.format("%.2f", folderSize.toFloat() / (1024 * 1024))
190 | unit = "MB"
191 | } else {
192 | size = String.format("%.2f", folderSize.toFloat() / (1024 * 1024 * 1024))
193 | unit = "GB"
194 | }
195 | if (size == "0") {
196 | size = "无法获取"
197 | unit = ""
198 | }
199 | SizeError = true
200 | }
201 |
202 | SSLHook()
203 | HttpHook()
204 |
205 | findMethod("com.combosdk.openapi.ComboApplication") { name == "attachBaseContext" }.hookBefore {
206 | val context = it.args[0] as Context
207 | sp = context.getSharedPreferences("ProxyConfig", 0)
208 | if (!sp.contains("serverip")) {
209 | sp.edit().putString("serverip", "https://127.0.0.1:54321").apply()
210 | XposedBridge.log("W: serverip不存在,使用默认地址")
211 | }
212 |
213 | server = sp.getString("serverip", "") ?: ""
214 |
215 | if (!sp.contains("ResCheck")) {
216 | sp.edit().putBoolean("ResCheck", true).apply()
217 | XposedBridge.log("W: rescheck不存在,自动启用")
218 | }
219 |
220 | if (sp.getBoolean("ResCheck", true)) {
221 | if (SizeError == true) {
222 | server = ""
223 | }
224 | }
225 | }
226 |
227 | findMethod("com.miHoYo.GetMobileInfo.MainActivity") { name == "onCreate" }.hookBefore { param ->
228 | activity = param.thisObject as Activity
229 |
230 | if (sp.getBoolean("AutoDelCache", false)) AutoDelCache()
231 | if (sp.getBoolean("AtDelLl2cppFolder", false)) AutoDelLl2cppFolder()
232 |
233 | if (sp.getBoolean("ResCheck", true)) {
234 | if (SizeError == true) {
235 | Toast.show(activity, "客户端无数据/数据不完整,大小:\t${size}${unit}", 0, yellow, black)
236 | Toast.show(activity, "自动进入资源下载服务器...", 0, white, black)
237 | }
238 | }
239 |
240 | if (server.startsWith("https:") || server.startsWith("http:")) {
241 | GlobalScope.launch {
242 | val serverStatus = checkServerAvailability()
243 | var ToastColor: Int
244 | if (serverStatus.startsWith("目标服务器可")) {
245 | ToastColor = green
246 | } else {
247 | ToastColor = red
248 | }
249 |
250 | withContext(Dispatchers.Main) {
251 | Toast.show_ServerStatus(activity, serverStatus, 1, ToastColor, black)
252 | }
253 | }
254 | } else {
255 | Toast.show_ServerStatus(activity, "地址错误,无法获取服务器状态", 1, red, black)
256 | }
257 |
258 | activity.windowManager.addView(LinearLayout(activity).apply {
259 | dialog = this
260 | visibility = View.GONE
261 | setGravity(Gravity.CENTER)
262 | background = ShapeDrawable().apply {
263 | shape = RoundRectShape(floatArrayOf(20f, 20f, 20f, 20f, 20f, 20f, 20f, 20f), null, null)
264 | paint.color = Color.argb((255 * 0.90).toInt(), 0x80, 0x8E, 0xEA)
265 | }
266 |
267 | addView(TextView(activity).apply {
268 | layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT).also {
269 | }
270 | setTextColor(Color.RED)
271 | setGravity(Gravity.CENTER)
272 | setOnClickListener {
273 | showDialog()
274 | }
275 | })
276 | }, WindowManager.LayoutParams(dp2px(activity, 200f), dp2px(activity, 90f), WindowManager.LayoutParams.TYPE_APPLICATION, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, PixelFormat.TRANSLUCENT).apply {
277 | gravity = Gravity.CENTER_VERTICAL
278 | x = 0
279 | y = 0
280 | })
281 |
282 | // 随机颜色
283 | fun getRainbowColor(): Int {
284 | val rainbowColors = intArrayOf(
285 | Color.parseColor("#FF8C00"), // 橙色
286 | Color.parseColor("#FFFF00"), // 黄色
287 | Color.parseColor("#008000"), // 绿色
288 | Color.parseColor("#0000FF"), // 蓝色
289 | Color.parseColor("#4B0082"), // 靛蓝色
290 | Color.parseColor("#EE82EE"), // 紫罗兰色
291 | Color.parseColor("#800000"), // 栗色
292 | Color.parseColor("#808000"), // 橄榄色
293 | Color.parseColor("#00FFFF") // 青色
294 | )
295 | val random = Random()
296 | return rainbowColors[random.nextInt(rainbowColors.size)]
297 | }
298 |
299 | var ShowIP = server
300 | if (ShowIP == "") {
301 | ShowIP = "未设置地址(连接至官方服务器)"
302 | }
303 |
304 | val sb = StringBuilder()
305 | sb.append("→点我打开代理设置←\n")
306 | sb.append("目标服务器:\n")
307 | val startIndex = sb.length
308 | sb.append(ShowIP)
309 | val originalString = sb.toString()
310 |
311 | Thread {
312 | runOnMainThread {
313 | val textView = dialog.getChildAt(0) as? TextView
314 | textView?.let {
315 | it.text = originalString
316 | val span = SpannableString(originalString)
317 | span.setSpan(ForegroundColorSpan(Color.GREEN), 0, 10, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
318 | span.setSpan(ForegroundColorSpan(getRainbowColor()), startIndex, startIndex + ShowIP.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
319 | span.setSpan(UnderlineSpan(), startIndex, startIndex + ShowIP.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
320 | span.setSpan(StyleSpan(Typeface.BOLD), startIndex, startIndex + ShowIP.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
321 | it.text = span
322 | dialog.visibility = View.VISIBLE
323 | }
324 | }
325 | Thread.sleep(8000)
326 | runOnMainThread {
327 | dialog.visibility = View.GONE
328 | activity.windowManager.removeView(dialog)
329 | }
330 | }.start()
331 | }
332 | } else {
333 | XposedBridge.log("E: 被注入应用不是目标应用,包名:" + lpparam.packageName)
334 | }
335 | }
336 |
337 | private fun AutoDelCache() {
338 | try {
339 | val cachePath = File("/sdcard/Android/data/${PackageName}/cache")
340 | val cache1Path = File("/sdcard/Android/data/${PackageName}/files/gee_logger_cache")
341 | val cache2Path = File("/data/data/${PackageName}/code_cache")
342 | val cache3Path = File("/data/data/${PackageName}/cache/WebView")
343 | val cache4Path = File("/data/data/${PackageName}/app_webview/Default/GPUCache")
344 | if (cachePath.exists()) {
345 | cachePath.deleteRecursively()
346 | }
347 | if (cache1Path.exists()) {
348 | cache1Path.deleteRecursively()
349 | }
350 | if (cache2Path.exists()) {
351 | cache2Path.deleteRecursively()
352 | }
353 | if (cache3Path.exists()) {
354 | cache3Path.deleteRecursively()
355 | }
356 | if (cache4Path.exists()) {
357 | cache4Path.deleteRecursively()
358 | }
359 | } catch (e: IOException) {
360 | Toast.show(activity, "删除缓存时发生错误\n" + e.toString(), 1, red, white)
361 | XposedBridge.log("E: 删除缓存失败" + e.toString())
362 | }
363 | }
364 |
365 | private val cornerRadius = 25f
366 | private val dialogBg = ShapeDrawable().apply {
367 | paint.color = Color.parseColor("#E6E7F8FF")
368 | shape = RoundRectShape(floatArrayOf(cornerRadius, cornerRadius,cornerRadius, cornerRadius,cornerRadius, cornerRadius,cornerRadius, cornerRadius), null, null)
369 | }
370 |
371 | private fun IPDialog() {
372 | val subject = arrayOf(
373 | "自定义服务器",
374 | "本地服务器"
375 | )
376 | var selectedSubject = subject[0]
377 | AlertDialog.Builder(activity).apply {
378 | setTitle("请选择服务器:")
379 | setCancelable(false)
380 | setSingleChoiceItems(subject, 0) { _, which ->
381 | selectedSubject = subject[which]
382 | }
383 | setPositiveButton("确定") { _, _ ->
384 | when (selectedSubject) {
385 | "自定义服务器" -> {
386 | CustomIPDialog()
387 | }
388 | "本地服务器" -> {
389 | sp.edit().run {
390 | putString("serverip", "https://127.0.0.1:54321")
391 | apply()
392 | Toast.show(activity, "已保存地址设置,请重新打开客户端~", 0, green, black)
393 | thread {
394 | Thread.sleep(2100)
395 | exitProcess(0)
396 | }
397 | }
398 | }
399 | }
400 | }
401 | setNeutralButton("取消") { _, _ ->
402 | showDialog()
403 | }
404 | }.create().apply {
405 | window?.setBackgroundDrawable(dialogBg)
406 | window?.setGravity(Gravity.CENTER)
407 | show()
408 | }
409 | }
410 |
411 | private fun showDialog() {
412 | AlertDialog.Builder(activity).apply {
413 | setTitle("代理设置")
414 | setMessage("倒卖🐶骨灰都给你妈扬咯")
415 | setCancelable(false)
416 | setView(ScrollView(context).apply {
417 | setPadding(25, 0, 25, 0)
418 | addView(LinearLayout(activity).apply {
419 | orientation = LinearLayout.VERTICAL
420 | addView(Switch(activity).apply {
421 | text = "游戏数据检测 (需重启)"
422 | isChecked = sp.getBoolean("ResCheck", false)
423 | setOnCheckedChangeListener { _, b ->
424 | sp.edit().run {
425 | putBoolean("ResCheck", b)
426 | apply()
427 | }
428 | }
429 | })
430 | addView(Switch(activity).apply {
431 | text = "自动删除客户端缓存 (需重启)"
432 | isChecked = sp.getBoolean("AutoDelCache", false)
433 | setOnCheckedChangeListener { _, b ->
434 | sp.edit().run {
435 | putBoolean("AutoDelCache", b)
436 | apply()
437 | }
438 | }
439 | })
440 | addView(Switch(activity).apply {
441 | text = "自动删除“il2cpp”文件夹 (需重启)"
442 | isChecked = sp.getBoolean("AtDelLl2cppFolder", false)
443 | setOnCheckedChangeListener { _, b ->
444 | sp.edit().run {
445 | putBoolean("AtDelLl2cppFolder", b)
446 | apply()
447 | }
448 | }
449 | })
450 | })
451 | })
452 | setPositiveButton("关闭") { _, _ ->
453 | // 无
454 | }
455 | setNegativeButton("修改服务器地址") { _, _ ->
456 | IPDialog()
457 | }
458 | setNeutralButton("🚫退出游戏") { _, _ ->
459 | exitProcess(0)
460 | }
461 | }.create().apply {
462 | window?.setBackgroundDrawable(dialogBg)
463 | window?.setGravity(Gravity.CENTER)
464 | show()
465 | }
466 | }
467 |
468 | private fun CustomIPDialog() {
469 | AlertDialog.Builder(activity).apply {
470 | setTitle("请输入服务器地址:")
471 | setCancelable(false)
472 | setView(ScrollView(context).apply {
473 | setPadding(25, 0, 25, 0)
474 | addView(LinearLayout(activity).apply {
475 | orientation = LinearLayout.VERTICAL
476 | addView(EditText(activity).apply {
477 | //输入框提示
478 | hint = "http(s)://server.com:1234"
479 | //输入框显示内容
480 | val str = ""
481 | setText(str.toCharArray(), 0, str.length)
482 | addTextChangedListener(object : TextWatcher {
483 | override fun beforeTextChanged(p0: CharSequence, p1: Int, p2: Int, p3: Int) {}
484 | override fun onTextChanged(p0: CharSequence, p1: Int, p2: Int, p3: Int) {}
485 |
486 | @SuppressLint("CommitPrefEdits")
487 | override fun afterTextChanged(p0: Editable) {
488 | val import_ip = p0.toString()
489 | if (import_ip == "") {
490 | SaveIP = ""
491 | } else if (import_ip == "localhost" || import_ip == "127.0.0.1") {
492 | SaveIP = "https://127.0.0.1:54321"
493 | } else if (!import_ip.startsWith("https://") && !import_ip.startsWith("http://")) {
494 | SaveIP = "https://" + import_ip
495 | } else {
496 | SaveIP = import_ip
497 | }
498 | }
499 | })
500 | })
501 | })
502 | })
503 | setNeutralButton("返回") { _, _ ->
504 | showDialog()
505 | }
506 | setPositiveButton("保存地址") { _, _ ->
507 | if (SaveIP == "") {
508 | Toast.show(activity, "错误: 输入框未填写任何内容", 0, red, white)
509 | CustomIPDialog()
510 | } else if (SaveIP.endsWith("/")) {
511 | Toast.show(activity, "错误: 地址结尾不能有“/”!", 0, red, white)
512 | SaveIP = ""
513 | CustomIPDialog()
514 | } else {
515 | sp.edit().run {
516 | putString("serverip", SaveIP)
517 | apply()
518 | val ser_ip = sp.getString("serverip", "") ?: ""
519 | Toast.show(activity, "已保存地址:\t${ser_ip}", 0, green, black)
520 | Toast.show(activity, "请重新打开客户端~", 0, white, black)
521 | thread {
522 | Thread.sleep(4200)
523 | exitProcess(0)
524 | }
525 | }
526 | }
527 | }
528 | }.create().apply {
529 | window?.setBackgroundDrawable(dialogBg)
530 | window?.setGravity(Gravity.CENTER)
531 | show()
532 | }
533 | }
534 |
535 | private fun AutoDelLl2cppFolder() {
536 | try {
537 | val il2cppPath = File("/sdcard/Android/data/${PackageName}/files/il2cpp")
538 | if (il2cppPath.exists()) {
539 | il2cppPath.deleteRecursively()
540 | }
541 | } catch (e: IOException) {
542 | Toast.show(activity, "删除il2cpp文件夹时发生错误\n" + e.toString(), 1, red, white)
543 | XposedBridge.log("E: 删除il2cpp失败" + e.toString())
544 | }
545 | }
546 |
547 | private fun SSLHook() {
548 | // OkHttp3 Hook
549 | findMethodOrNull("com.combosdk.lib.third.okhttp3.OkHttpClient\$Builder") { name == "build" }
550 | ?.hookBefore {
551 | it.thisObject.invokeMethod(
552 | "sslSocketFactory",
553 | args(getDefaultSSLSocketFactory()),
554 | argTypes(SSLSocketFactory::class.java)
555 | )
556 | it.thisObject.invokeMethod(
557 | "hostnameVerifier",
558 | args(getDefaultHostnameVerifier()),
559 | argTypes(HostnameVerifier::class.java)
560 | )
561 | }
562 | findMethodOrNull("okhttp3.OkHttpClient\$Builder") { name == "build" }?.hookBefore {
563 | it.thisObject.invokeMethod(
564 | "sslSocketFactory",
565 | args(getDefaultSSLSocketFactory(), DefaultTrustManager()),
566 | argTypes(SSLSocketFactory::class.java, X509TrustManager::class.java)
567 | )
568 | it.thisObject.invokeMethod(
569 | "hostnameVerifier",
570 | args(getDefaultHostnameVerifier()),
571 | argTypes(HostnameVerifier::class.java)
572 | )
573 | }
574 | // WebView Hook
575 | arrayListOf(
576 | "android.webkit.WebViewClient",
577 | //"cn.sharesdk.framework.g",
578 | //"com.facebook.internal.WebDialog\$DialogWebViewClient",
579 | "com.geetest.sdk.dialog.views.GtWebView\$c",
580 | "com.miHoYo.sdk.webview.common.view.ContentWebView\$6"
581 | )
582 | .forEach {
583 | findMethodOrNull(it) {
584 | name == "onReceivedSslError" &&
585 | parameterTypes[1] == SslErrorHandler::class.java
586 | }
587 | ?.hookBefore { param -> (param.args[1] as SslErrorHandler).proceed() }
588 | }
589 | // Android HttpsURLConnection Hook
590 | findMethodOrNull("javax.net.ssl.HttpsURLConnection") {
591 | name == "getDefaultSSLSocketFactory"
592 | }
593 | ?.hookBefore { it.result = getDefaultSSLSocketFactory() }
594 | findMethodOrNull("javax.net.ssl.HttpsURLConnection") { name == "setSSLSocketFactory" }
595 | ?.hookBefore { it.result = null }
596 | findMethodOrNull("javax.net.ssl.HttpsURLConnection") {
597 | name == "setDefaultSSLSocketFactory"
598 | }
599 | ?.hookBefore { it.result = null }
600 | findMethodOrNull("javax.net.ssl.HttpsURLConnection") { name == "setHostnameVerifier" }
601 | ?.hookBefore { it.result = null }
602 | findMethodOrNull("javax.net.ssl.HttpsURLConnection") {
603 | name == "setDefaultHostnameVerifier"
604 | }
605 | ?.hookBefore { it.result = null }
606 | findMethodOrNull("javax.net.ssl.HttpsURLConnection") {
607 | name == "getDefaultHostnameVerifier"
608 | }
609 | ?.hookBefore { it.result = getDefaultHostnameVerifier() }
610 | }
611 |
612 | // Bypass HTTP
613 | private fun HttpHook() {
614 | findMethod("com.miHoYo.sdk.webview.MiHoYoWebview") {
615 | name == "load" &&
616 | parameterTypes[0] == String::class.java &&
617 | parameterTypes[1] == String::class.java
618 | }
619 | .hookBefore { replaceUrl(it, 1) }
620 | findAllMethods("android.webkit.WebView") { name == "loadUrl" }.hookBefore {
621 | replaceUrl(it, 0)
622 | }
623 | findAllMethods("android.webkit.WebView") { name == "postUrl" }.hookBefore {
624 | replaceUrl(it, 0)
625 | }
626 |
627 | findMethod("okhttp3.HttpUrl") { name == "parse" && parameterTypes[0] == String::class.java }
628 | .hookBefore { replaceUrl(it, 0) }
629 | findMethod("com.combosdk.lib.third.okhttp3.HttpUrl") {
630 | name == "parse" && parameterTypes[0] == String::class.java
631 | }
632 | .hookBefore { replaceUrl(it, 0) }
633 |
634 | findMethod("com.google.gson.Gson") {
635 | name == "fromJson" &&
636 | parameterTypes[0] == String::class.java &&
637 | parameterTypes[1] == java.lang.reflect.Type::class.java
638 | }
639 | .hookBefore { replaceUrl(it, 0) }
640 | findConstructor("java.net.URL") { parameterTypes[0] == String::class.java }.hookBefore {
641 | replaceUrl(it, 0)
642 | }
643 | findMethod("com.combosdk.lib.third.okhttp3.Request\$Builder") {
644 | name == "url" && parameterTypes[0] == String::class.java
645 | }
646 | .hookBefore { replaceUrl(it, 0) }
647 | findMethod("okhttp3.Request\$Builder") {
648 | name == "url" && parameterTypes[0] == String::class.java
649 | }
650 | .hookBefore { replaceUrl(it, 0) }
651 | }
652 |
653 | private suspend fun checkServerAvailability(): String = withContext(Dispatchers.IO) {
654 | val url = URL(server)
655 | val connection = url.openConnection() as HttpURLConnection
656 | connection.requestMethod = "GET"
657 |
658 | try {
659 | val startTime = System.currentTimeMillis()
660 | connection.connect()
661 | val responseCode = connection.responseCode
662 | if (responseCode == HttpURLConnection.HTTP_OK) {
663 | val endTime = System.currentTimeMillis()
664 | val delay = endTime - startTime
665 |
666 | "目标服务器可用\nSuccessfully connect to " + server + "\n请求耗时: ${delay}毫秒"
667 | } else if (responseCode in 400..499) {
668 | "目标服务器存在异常,服务器无法处理请求\nHTTP状态码:" + responseCode
669 | } else if (responseCode in 500..599) {
670 | "目标服务器存在异常,服务器处理请求时出错\nHTTP状态码:" + responseCode
671 | } else {
672 | "目标服务器存在异常,原因未知"
673 | }
674 | } catch (e: Exception) {
675 | "无法连接至目标服务器,错误:\n" + e.toString()
676 | } finally {
677 | connection.disconnect()
678 | }
679 | }
680 |
681 | private fun replaceUrl(method: XC_MethodHook.MethodHookParam, args: Int) {
682 | var Xuoos = method.args[args].toString()
683 | val m = regex.matcher(Xuoos)
684 |
685 | if (server == "" || Xuoos == "" || method.args[args] == null) return
686 | for (list in more_domain) {
687 | for (head in arrayListOf("http://", "https://")) {
688 | method.args[args] = method.args[args].toString().replace(head + list, server)
689 | }
690 | }
691 |
692 | if (m.find()) {
693 | method.args[args] = m.replaceAll(server)
694 | }
695 | }
696 | }
--------------------------------------------------------------------------------
/app/src/main/java/Xuoos/GenshinImpact/Proxy/MainHook.kt:
--------------------------------------------------------------------------------
1 | package Xuoos.GenshinImpact.Proxy
2 |
3 | import de.robv.android.xposed.IXposedHookLoadPackage
4 | import de.robv.android.xposed.IXposedHookZygoteInit
5 | import de.robv.android.xposed.callbacks.XC_LoadPackage
6 |
7 | class MainHook : IXposedHookLoadPackage, IXposedHookZygoteInit {
8 | private val hook: Hook = Hook()
9 |
10 | override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) {
11 | hook.handleLoadPackage(lpparam)
12 | }
13 |
14 | override fun initZygote(startupParam: IXposedHookZygoteInit.StartupParam) {
15 | hook.initZygote(startupParam)
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/java/Xuoos/GenshinImpact/Proxy/ToastCustom.java:
--------------------------------------------------------------------------------
1 | package Xuoos.GenshinImpact.Proxy;
2 |
3 | import android.app.Activity;
4 | import android.graphics.Color;
5 | import android.graphics.drawable.ShapeDrawable;
6 | import android.graphics.drawable.shapes.RoundRectShape;
7 | import android.view.Gravity;
8 | import android.view.View;
9 | import android.widget.TextView;
10 | import android.widget.Toast;
11 |
12 | public class ToastCustom {
13 | private Toast toast;
14 |
15 | private static ToastCustom toastCustom;
16 |
17 | public static ToastCustom createToastConfig() {
18 | if (toastCustom == null) {
19 | toastCustom = new ToastCustom();
20 | }
21 | return toastCustom;
22 | }
23 |
24 | public void show(Activity activity, String msg, int duration, int backgroundColor, int textColor) {
25 | TextView toastView = new TextView(activity);
26 | toastView.setText(msg);
27 | toastView.setTextColor(textColor);
28 | toastView.setGravity(Gravity.CENTER);
29 | toastView.setBackgroundColor(backgroundColor);
30 | toastView.setPadding(25, 30, 25, 30);
31 | float radius = 20f;
32 | ShapeDrawable shapeDrawable = new ShapeDrawable(new RoundRectShape(new float[]{radius, radius, radius, radius, radius, radius, radius, radius}, null, null));
33 | shapeDrawable.getPaint().setColor(backgroundColor);
34 | toastView.setBackground(shapeDrawable);
35 |
36 | toast = new Toast(activity);
37 | toast.setGravity(Gravity.BOTTOM, 0, 80);
38 | if (duration == 1) {
39 | toast.setDuration(Toast.LENGTH_LONG);
40 | } else {
41 | toast.setDuration(Toast.LENGTH_SHORT);
42 | }
43 | toast.setView(toastView);
44 |
45 | View view = toast.getView();
46 | if (view != null) {
47 | view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
48 | int width = view.getMeasuredWidth();
49 | int height = view.getMeasuredHeight();
50 | view.setPadding(0, 0, 0, 0);
51 | view.setMinimumWidth(width);
52 | view.setMinimumHeight(height);
53 | }
54 |
55 | toast.show();
56 | }
57 |
58 | public void show_ServerStatus(Activity activity, String msg, int duration, int backgroundColor, int textColor) {
59 | TextView toastView = new TextView(activity);
60 | toastView.setText(msg);
61 | toastView.setTextColor(textColor);
62 | toastView.setGravity(Gravity.CENTER);
63 | toastView.setBackgroundColor(backgroundColor);
64 | toastView.setPadding(25, 30, 25, 30);
65 | float radius = 20f;
66 | ShapeDrawable shapeDrawable = new ShapeDrawable(new RoundRectShape(new float[]{radius, radius, radius, radius, radius, radius, radius, radius}, null, null));
67 | shapeDrawable.getPaint().setColor(backgroundColor);
68 | toastView.setBackground(shapeDrawable);
69 |
70 | toast = new Toast(activity);
71 | toast.setGravity(Gravity.TOP, 0, 0);
72 | if (duration == 1) {
73 | toast.setDuration(Toast.LENGTH_LONG);
74 | } else {
75 | toast.setDuration(Toast.LENGTH_SHORT);
76 | }
77 | toast.setView(toastView);
78 |
79 | View view = toast.getView();
80 | if (view != null) {
81 | view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
82 | int width = view.getMeasuredWidth();
83 | int height = view.getMeasuredHeight();
84 | view.setPadding(0, 0, 0, 0);
85 | view.setMinimumWidth(width);
86 | view.setMinimumHeight(height);
87 | }
88 |
89 | toast.show();
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/app/src/main/java/Xuoos/GenshinImpact/Proxy/TrustMeAlready.java:
--------------------------------------------------------------------------------
1 | package Xuoos.GenshinImpact.Proxy;
2 |
3 | import java.lang.reflect.Method;
4 | import java.lang.reflect.ParameterizedType;
5 | import java.lang.reflect.Type;
6 | import java.security.cert.X509Certificate;
7 | import java.util.ArrayList;
8 | import java.util.Arrays;
9 | import java.util.List;
10 | import java.util.Locale;
11 |
12 | import de.robv.android.xposed.XC_MethodReplacement;
13 | import static de.robv.android.xposed.XposedHelpers.*;
14 |
15 | public class TrustMeAlready {
16 |
17 | private static final String SSL_CLASS_NAME = "com.android.org.conscrypt.TrustManagerImpl";
18 | private static final String SSL_METHOD_NAME = "checkTrustedRecursive";
19 | private static final Class> SSL_RETURN_TYPE = List.class;
20 | private static final Class> SSL_RETURN_PARAM_TYPE = X509Certificate.class;
21 |
22 | public void initZygote() {
23 | int hookedMethods = 0;
24 |
25 | for (Method method : findClass(SSL_CLASS_NAME, null).getDeclaredMethods()) {
26 | if (!checkSSLMethod(method)) {
27 | continue;
28 | }
29 |
30 | List