From 8f753de854a08308f2c27dd7d7d83f3f7f4712d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=B9=E5=9D=97=E5=90=9B?= Date: Sat, 14 May 2022 18:04:21 +0800 Subject: [PATCH] Optimize code --- app/build.gradle | 22 +- app/genshinproxy-dic.txt | 692 +++++++++++++++++ app/proguard-log.pro | 40 + app/proguard-rules.pro | 25 +- app/src/main/java/xfk233/genshinproxy/Hook.kt | 713 ++++++++++++++++++ .../main/java/xfk233/genshinproxy/MainHook.kt | 662 +--------------- .../xfk233/genshinproxy/TrustMeAlready.java | 5 +- .../main/java/xfk233/genshinproxy/Utils.kt | 14 + build.gradle | 6 +- gradle/wrapper/gradle-wrapper.properties | 4 +- 10 files changed, 1514 insertions(+), 669 deletions(-) create mode 100644 app/genshinproxy-dic.txt create mode 100644 app/proguard-log.pro create mode 100644 app/src/main/java/xfk233/genshinproxy/Hook.kt diff --git a/app/build.gradle b/app/build.gradle index e3f362f..4c4e20b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,8 @@ plugins { id 'com.android.application' id 'kotlin-android' + id 'top.niunaijun.blackobfuscator' + id 'icu.nullptr.stringfuck' } android { @@ -8,7 +10,7 @@ android { defaultConfig { applicationId "xfk233.genshinproxy" - minSdk 27 + minSdk 28 targetSdk 32 versionCode 5 versionName "1.5" @@ -16,8 +18,9 @@ android { buildTypes { release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + minifyEnabled true + shrinkResources true + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro', 'proguard-log.pro' } } compileOptions { @@ -29,10 +32,23 @@ android { } } +BlackObfuscator { + enabled true + depth 3 + obfClass = ["xfk233.genshinproxy"] +} + +stringFuck { + setKey "xfk2333" + obfuscationList ["xfk233.genshinproxy"] + workOnDebug true +} + dependencies { //API compileOnly 'de.robv.android.xposed:api:82' //带源码Api compileOnly 'de.robv.android.xposed:api:82:sources' implementation 'com.github.kyuubiran:EzXHelper:0.9.2' + implementation 'icu.nullptr.stringfuck:library:0.1.4' } \ No newline at end of file diff --git a/app/genshinproxy-dic.txt b/app/genshinproxy-dic.txt new file mode 100644 index 0000000..504fa3a --- /dev/null +++ b/app/genshinproxy-dic.txt @@ -0,0 +1,692 @@ +倒卖的丢你老母个嗨 +倒卖的丢你老母个臭嗨 +倒卖的你个逆子早晚懒趴掉下来 +倒卖的你妈有逼吗 +倒卖的你老母个烂ham +倒卖的你这个逆子 +倒卖的你逆你妈的臭烂逼 +倒卖的信不信骨灰都给你扬咯 +倒卖的去你妈个臭逼 +倒卖的去你妈的 +倒卖的去你妈的烂逼 +倒卖的含家产 +倒卖的夭寿鬼 +倒卖的憨憨 +倒卖的扬你妈的骨灰 +倒卖的操你妈的臭头鸡仔 +林北一拳打爆你妈的狗头 +林北一拳打爆你妈的脑袋 +林北一拳打穿你妈的血逼 +倒卖的瓜娃子 +还逆向 +逆 +逆向 +逆向你妈个逼 +逆向你妈的死人头 +逆向工程师 +倒卖的食屎啦 +倒卖的骨灰都给你妈扬咯 +倒卖的骨灰都给你扬咯 +倒卖的扑街仔 +富强 +民主 +文明 +和谐 +自由 +平等 +公正 +法制 +爱国 +敬业 +诚信 +友善 +ʻ +ʼ +ʽ +ʾ +ʿ +ˆ +ˈ +ˉ +ˊ +ˋ +ˎ +ˏ +ˑ +י +ـ +ٴ +ᐧ +ᴵ +ᵎ +ᵔ +ᵢ +ⁱ +ﹳ +ﹶ +゙ +゙゙ +ᐧᐧ +ᴵᴵ +ʻʻ +ʽʽ +ʼʼ +ʿʿ +ʾʾ +ــ +ˆˆ +ˉˉ +ˈˈ +ˋˋ +ˊˊ +ˏˏ +ˎˎ +ˑˑ +ᵔᵔ +יי +ᵎᵎ +ᵢᵢ +ⁱⁱ +ﹳﹳ +ٴٴ +ﹶﹶ +ʻʼ +ʻʽ +ʻʾ +ʻʿ +ʻˆ +ʻˈ +ʻˉ +ʻˊ +ʻˋ +ʻˎ +ʻˏ +ʻˑ +ʻי +ʻـ +ʻٴ +ʻᐧ +ʻᴵ +ʻᵎ +ʻᵔ +ʻᵢ +ʻⁱ +ʻﹳ +ʻﹶ +ʻ゙ +ʼʻ +ʼʽ +ʼʾ +ʼʿ +ʼˆ +ʼˈ +ʼˉ +ʼˊ +ʼˋ +ʼˎ +ʼˏ +ʼˑ +ʼי +ʼـ +ʼٴ +ʼᐧ +ʼᴵ +ʼᵎ +ʼᵔ +ʼᵢ +ʼⁱ +ʼﹳ +ʼﹶ +ʼ゙ +ʽʻ +ʽʼ +ʽʾ +ʽʿ +ʽˆ +ʽˈ +ʽˉ +ʽˊ +ʽˋ +ʽˎ +ʽˏ +ʽˑ +ʽי +ʽـ +ʽٴ +ʽᐧ +ʽᴵ +ʽᵎ +ʽᵔ +ʽᵢ +ʽⁱ +ʽﹳ +ʽﹶ +ʽ゙ +ʾʻ +ʾʼ +ʾʽ +ʾʿ +ʾˆ +ʾˈ +ʾˉ +ʾˊ +ʾˋ +ʾˎ +ʾˏ +ʾˑ +ʾי +ʾـ +ʾٴ +ʾᐧ +ʾᴵ +ʾᵎ +ʾᵔ +ʾᵢ +ʾⁱ +ʾﹳ +ʾﹶ +ʾ゙ +ʿʻ +ʿʼ +ʿʽ +ʿʾ +ʿˆ +ʿˈ +ʿˉ +ʿˊ +ʿˋ +ʿˎ +ʿˏ +ʿˑ +ʿי +ʿـ +ʿٴ +ʿᐧ +ʿᴵ +ʿᵎ +ʿᵔ +ʿᵢ +ʿⁱ +ʿﹳ +ʿﹶ +ʿ゙ +ˆʻ +ˆʼ +ˆʽ +ˆʾ +ˆʿ +ˆˈ +ˆˉ +ˆˊ +ˆˋ +ˆˎ +ˆˏ +ˆˑ +ˆי +ˆـ +ˆٴ +ˆᐧ +ˆᴵ +ˆᵎ +ˆᵔ +ˆᵢ +ˆⁱ +ˆﹳ +ˆﹶ +ˆ゙ +ˈʻ +ˈʼ +ˈʽ +ˈʾ +ˈʿ +ˈˆ +ˈˉ +ˈˊ +ˈˋ +ˈˎ +ˈˏ +ˈˑ +ˈי +ˈـ +ˈٴ +ˈᐧ +ˈᴵ +ˈᵎ +ˈᵔ +ˈᵢ +ˈⁱ +ˈﹳ +ˈﹶ +ˈ゙ +ˉʻ +ˉʼ +ˉʽ +ˉʾ +ˉʿ +ˉˆ +ˉˈ +ˉˊ +ˉˋ +ˉˎ +ˉˏ +ˉˑ +ˉי +ˉـ +ˉٴ +ˉᐧ +ˉᴵ +ˉᵎ +ˉᵔ +ˉᵢ +ˉⁱ +ˉﹳ +ˉﹶ +ˉ゙ +ˊʻ +ˊʼ +ˊʽ +ˊʾ +ˊʿ +ˊˆ +ˊˈ +ˊˉ +ˊˋ +ˊˎ +ˊˏ +ˊˑ +ˊי +ˊـ +ˊٴ +ˊᐧ +ˊᴵ +ˊᵎ +ˊᵔ +ˊᵢ +ˊⁱ +ˊﹳ +ˊﹶ +ˊ゙ +ˋʻ +ˋʼ +ˋʽ +ˋʾ +ˋʿ +ˋˆ +ˋˈ +ˋˉ +ˋˊ +ˋˎ +ˋˏ +ˋˑ +ˋי +ˋـ +ˋٴ +ˋᐧ +ˋᴵ +ˋᵎ +ˋᵔ +ˋᵢ +ˋⁱ +ˋﹳ +ˋﹶ +ˋ゙ +ˎʻ +ˎʼ +ˎʽ +ˎʾ +ˎʿ +ˎˆ +ˎˈ +ˎˉ +ˎˊ +ˎˋ +ˎˏ +ˎˑ +ˎי +ˎـ +ˎٴ +ˎᐧ +ˎᴵ +ˎᵎ +ˎᵔ +ˎᵢ +ˎⁱ +ˎﹳ +ˎﹶ +ˎ゙ +ˏʻ +ˏʼ +ˏʽ +ˏʾ +ˏʿ +ˏˆ +ˏˈ +ˏˉ +ˏˊ +ˏˋ +ˏˎ +ˏˑ +ˏי +ˏـ +ˏٴ +ˏᐧ +ˏᴵ +ˏᵎ +ˏᵔ +ˏᵢ +ˏⁱ +ˏﹳ +ˏﹶ +ˏ゙ +ˑʻ +ˑʼ +ˑʽ +ˑʾ +ˑʿ +ˑˆ +ˑˈ +ˑˉ +ˑˊ +ˑˋ +ˑˎ +ˑˏ +ˑי +ˑـ +ˑٴ +ˑᐧ +ˑᴵ +ˑᵎ +ˑᵔ +ˑᵢ +ˑⁱ +ˑﹳ +ˑﹶ +ˑ゙ +יʻ +יʼ +יʽ +יʾ +יʿ +יˆ +יˈ +יˉ +יˊ +יˋ +יˎ +יˏ +יˑ +יـ +יٴ +יᐧ +יᴵ +יᵎ +יᵔ +יᵢ +יⁱ +יﹳ +יﹶ +י゙ +ـʻ +ـʼ +ـʽ +ـʾ +ـʿ +ـˆ +ـˈ +ـˉ +ـˊ +ـˋ +ـˎ +ـˏ +ـˑ +ـי +ـٴ +ـᐧ +ـᴵ +ـᵎ +ـᵔ +ـᵢ +ـⁱ +ـﹳ +ـﹶ +ـ゙ +ٴʻ +ٴʼ +ٴʽ +ٴʾ +ٴʿ +ٴˆ +ٴˈ +ٴˉ +ٴˊ +ٴˋ +ٴˎ +ٴˏ +ٴˑ +ٴי +ٴـ +ٴᐧ +ٴᴵ +ٴᵎ +ٴᵔ +ٴᵢ +ٴⁱ +ٴﹳ +ٴﹶ +ٴ゙ +ᐧʻ +ᐧʼ +ᐧʽ +ᐧʾ +ᐧʿ +ᐧˆ +ᐧˈ +ᐧˉ +ᐧˊ +ᐧˋ +ᐧˎ +ᐧˏ +ᐧˑ +ᐧי +ᐧـ +ᐧٴ +ᐧᴵ +ᐧᵎ +ᐧᵔ +ᐧᵢ +ᐧⁱ +ᐧﹳ +ᐧﹶ +ᐧ゙ +ᴵʻ +ᴵʼ +ᴵʽ +ᴵʾ +ᴵʿ +ᴵˆ +ᴵˈ +ᴵˉ +ᴵˊ +ᴵˋ +ᴵˎ +ᴵˏ +ᴵˑ +ᴵי +ᴵـ +ᴵٴ +ᴵᐧ +ᴵᵎ +ᴵᵔ +ᴵᵢ +ᴵⁱ +ᴵﹳ +ᴵﹶ +ᴵ゙ +ᵎʻ +ᵎʼ +ᵎʽ +ᵎʾ +ᵎʿ +ᵎˆ +ᵎˈ +ᵎˉ +ᵎˊ +ᵎˋ +ᵎˎ +ᵎˏ +ᵎˑ +ᵎי +ᵎـ +ᵎٴ +ᵎᐧ +ᵎᴵ +ᵎᵔ +ᵎᵢ +ᵎⁱ +ᵎﹳ +ᵎﹶ +ᵎ゙ +ᵔʻ +ᵔʼ +ᵔʽ +ᵔʾ +ᵔʿ +ᵔˆ +ᵔˈ +ᵔˉ +ᵔˊ +ᵔˋ +ᵔˎ +ᵔˏ +ᵔˑ +ᵔי +ᵔـ +ᵔٴ +ᵔᐧ +ᵔᴵ +ᵔᵎ +ᵔᵢ +ᵔⁱ +ᵔﹳ +ᵔﹶ +ᵔ゙ +ᵢʻ +ᵢʼ +ᵢʽ +ᵢʾ +ᵢʿ +ᵢˆ +ᵢˈ +ᵢˉ +ᵢˊ +ᵢˋ +ᵢˎ +ᵢˏ +ᵢˑ +ᵢי +ᵢـ +ᵢٴ +ᵢᐧ +ᵢᴵ +ᵢᵎ +ᵢᵔ +ᵢⁱ +ᵢﹳ +ᵢﹶ +ᵢ゙ +ⁱʻ +ⁱʼ +ⁱʽ +ⁱʾ +ⁱʿ +ⁱˆ +ⁱˈ +ⁱˉ +ⁱˊ +ⁱˋ +ⁱˎ +ⁱˏ +ⁱˑ +ⁱי +ⁱـ +ⁱٴ +ⁱᐧ +ⁱᴵ +ⁱᵎ +ⁱᵔ +ⁱᵢ +ⁱﹳ +ⁱﹶ +ⁱ゙ +ﹳʻ +ﹳʼ +ﹳʽ +ﹳʾ +ﹳʿ +ﹳˆ +ﹳˈ +ﹳˉ +ﹳˊ +ﹳˋ +ﹳˎ +ﹳˏ +ﹳˑ +ﹳי +ﹳـ +ﹳٴ +ﹳᐧ +ﹳᴵ +ﹳᵎ +ﹳᵔ +ﹳᵢ +ﹳⁱ +ﹳﹶ +ﹳ゙ +ﹶʻ +ﹶʼ +ﹶʽ +ﹶʾ +ﹶʿ +ﹶˆ +ﹶˈ +ﹶˉ +ﹶˊ +ﹶˋ +ﹶˎ +ﹶˏ +ﹶˑ +ﹶי +ﹶـ +ﹶٴ +ﹶᐧ +ﹶᴵ +ﹶᵎ +ﹶᵔ +ﹶᵢ +ﹶⁱ +ﹶﹳ +ﹶ゙ +゙ʻ +゙ʼ +゙ʽ +゙ʾ +゙ʿ +゙ˆ +゙ˈ +゙ˉ +゙ˊ +゙ˋ +゙ˎ +゙ˏ +゙ˑ +゙י +゙ـ +゙ٴ +゙ᐧ +゙ᴵ +゙ᵎ +゙ᵔ +゙ᵢ +゙ⁱ +゙ﹳ +゙ﹶ \ No newline at end of file diff --git a/app/proguard-log.pro b/app/proguard-log.pro new file mode 100644 index 0000000..4a2c5fe --- /dev/null +++ b/app/proguard-log.pro @@ -0,0 +1,40 @@ +########################################################################################################## +# 作者:Sollyu +# 日期:2020-11-02 +# 内容:发布版本移除日志,kotlin编译时带的而外信息,增强反调试难度 +# 使用:proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro', 'proguard-log.pro' +########################################################################################################## + +########################################################################################################## +# 删除安卓日志 +-assumenosideeffects class android.util.Log { + public static *** d(...); + public static *** v(...); + public static *** w(...); + public static *** e(...); +} + +########################################################################################################## +# 删除Kotlin编译时可能生成显示变量的方法 +-assumenosideeffects class kotlin.jvm.internal.Intrinsics { + public static void checkExpressionValueIsNotNull(java.lang.Object, java.lang.String); + public static void checkFieldIsNotNull(java.lang.Object, java.lang.String); + public static void checkFieldIsNotNull(java.lang.Object, java.lang.String, java.lang.String); + public static void checkNotNull(java.lang.Object); + public static void checkNotNull(java.lang.Object, java.lang.String); + public static void checkNotNullExpressionValue(java.lang.Object, java.lang.String); + public static void checkNotNullParameter(java.lang.Object, java.lang.String); + public static void checkParameterIsNotNull(java.lang.Object, java.lang.String); + public static void checkReturnedValueIsNotNull(java.lang.Object, java.lang.String); + public static void throwUninitializedPropertyAccessException(java.lang.String); +} + +########################################################################################################## +# 会暴露变量名称 +-assumenosideeffects class java.util.Objects { + public static java.lang.Object requireNonNull(java.lang.Object, java.lang.String); +} + +-assumenosideeffects class de.robv.android.xposed.XposedBridge { + public synchronized static void log(...); +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 481bb43..a04f79f 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -18,4 +18,27 @@ # If you keep the line number information, uncomment this to # hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file +#-renamesourcefileattribute SourceFile + +-keep class * implements de.robv.android.xposed.IXposedHookLoadPackage { + public void *(de.robv.android.xposed.callbacks.XC_LoadPackage$LoadPackageParam); +} + +-keep class * implements de.robv.android.xposed.IXposedHookInitPackageResources { + public void *(de.robv.android.xposed.callbacks.XC_InitPackageResources$InitPackageResourcesParam); +} + +-keep class * implements de.robv.android.xposed.IXposedHookZygoteInit { + public void *(de.robv.android.xposed.IXposedHookZygoteInit$StartupParam); +} + +-assumenosideeffects class kotlin.jvm.internal.Intrinsics { + public static void check*(...); + public static void throw*(...); +} + +-obfuscationdictionary genshinproxy-dic.txt +-classobfuscationdictionary genshinproxy-dic.txt +-packageobfuscationdictionary genshinproxy-dic.txt + +-repackageclasses "xfk233.genshinproxy" \ No newline at end of file diff --git a/app/src/main/java/xfk233/genshinproxy/Hook.kt b/app/src/main/java/xfk233/genshinproxy/Hook.kt new file mode 100644 index 0000000..0775def --- /dev/null +++ b/app/src/main/java/xfk233/genshinproxy/Hook.kt @@ -0,0 +1,713 @@ +package xfk233.genshinproxy + + +import android.annotation.SuppressLint +import android.app.Activity +import android.app.AlertDialog +import android.content.ClipboardManager +import android.content.Context +import android.content.SharedPreferences +import android.content.pm.PackageManager +import android.content.res.XModuleResources +import android.graphics.Color +import android.graphics.PixelFormat +import android.graphics.drawable.ShapeDrawable +import android.graphics.drawable.shapes.RoundRectShape +import android.os.Build +import android.text.Editable +import android.text.InputType +import android.text.TextWatcher +import android.util.Base64 +import android.util.TypedValue +import android.view.Gravity +import android.view.MotionEvent +import android.view.View +import android.view.WindowManager +import android.webkit.SslErrorHandler +import android.widget.* +import com.github.kyuubiran.ezxhelper.init.EzXHelperInit +import com.github.kyuubiran.ezxhelper.utils.* +import de.robv.android.xposed.IXposedHookZygoteInit +import de.robv.android.xposed.XC_MethodHook +import de.robv.android.xposed.XposedBridge +import de.robv.android.xposed.callbacks.XC_LoadPackage +import icu.nullptr.stringfuck.StringFuck +import org.json.JSONObject +import xfk233.genshinproxy.Utils.dp2px +import xfk233.genshinproxy.Utils.isInit +import java.io.BufferedReader +import java.io.ByteArrayOutputStream +import java.io.File +import java.io.InputStreamReader +import java.net.HttpURLConnection +import java.net.URL +import java.security.SecureRandom +import java.security.cert.X509Certificate +import java.util.regex.Pattern +import javax.net.ssl.* +import kotlin.system.exitProcess + +class Hook { + private val regex = Pattern.compile("http(s|)://.*?\\.(hoyoverse|mihoyo|yuanshen|mob)\\.com") + private lateinit var server: String + private var forceUrl = false + private lateinit var modulePath: String + private lateinit var moduleRes: XModuleResources + private lateinit var windowManager: WindowManager + private var proxyList = false + private lateinit var sp: SharedPreferences + private val proxyListRegex = arrayListOf( + "api-os-takumi.mihoyo.com", + "hk4e-api-os-static.mihoyo.com", + "hk4e-sdk-os.mihoyo.com", + "dispatchosglobal.yuanshen.com", + "osusadispatch.yuanshen.com", + "account.mihoyo.com", + "log-upload-os.mihoyo.com", + "dispatchcntest.yuanshen.com", + "devlog-upload.mihoyo.com", + "webstatic.mihoyo.com", + "log-upload.mihoyo.com", + "hk4e-sdk.mihoyo.com", + "api-beta-sdk.mihoyo.com", + "api-beta-sdk-os.mihoyo.com", + "cnbeta01dispatch.yuanshen.com", + "dispatchcnglobal.yuanshen.com", + "cnbeta02dispatch.yuanshen.com", + "sdk-os-static.mihoyo.com", + "webstatic-sea.mihoyo.com", + "webstatic-sea.hoyoverse.com", + "hk4e-sdk-os-static.hoyoverse.com", + "sdk-os-static.hoyoverse.com", + "api-account-os.hoyoverse.com", + "hk4e-sdk-os.hoyoverse.com", + "overseauspider.yuanshen.com", + "gameapi-account.mihoyo.com", + "minor-api.mihoyo.com", + "public-data-api.mihoyo.com", + "uspider.yuanshen.com", + "sdk-static.mihoyo.com", + "minor-api-os.hoyoverse.com", + "log-upload-os.hoyoverse.com" + ) + + private val activityList: ArrayList = arrayListOf() + private var activity: Activity + get() { + for (mActivity in activityList) { + if (mActivity.isFinishing) { + activityList.remove(mActivity) + } else { + return mActivity + } + } + throw Throwable("Activity not found.") + } + set(value) { + activityList.add(value) + } + + private fun getDefaultSSLSocketFactory(): SSLSocketFactory { + return SSLContext.getInstance("TLS").apply { + init(arrayOf(), arrayOf(DefaultTrustManager()), SecureRandom()) + }.socketFactory + } + + private fun getDefaultHostnameVerifier(): HostnameVerifier { + return DefaultHostnameVerifier() + } + + class DefaultHostnameVerifier : HostnameVerifier { + @SuppressLint("BadHostnameVerifier") + override fun verify(p0: String?, p1: SSLSession?): Boolean { + return true + } + + } + + @SuppressLint("CustomX509TrustManager") + private class DefaultTrustManager : X509TrustManager { + + @SuppressLint("TrustAllX509TrustManager") + override fun checkClientTrusted(chain: Array?, authType: String?) { + } + + @SuppressLint("TrustAllX509TrustManager") + override fun checkServerTrusted(chain: Array?, authType: String?) { + } + + override fun getAcceptedIssuers(): Array { + return arrayOf() + } + } + + fun initZygote(startupParam: IXposedHookZygoteInit.StartupParam) { + StringFuck.init() + modulePath = startupParam.modulePath + moduleRes = XModuleResources.createInstance(modulePath, null) + TrustMeAlready().initZygote() + } + + private var startForceUrl = false + private var startProxyList = false + private lateinit var dialog: LinearLayout + + @SuppressLint("WrongConstant", "ClickableViewAccessibility") + fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) { + if (lpparam.packageName != "com.miHoYo.GenshinImpact") return + EzXHelperInit.initHandleLoadPackage(lpparam) + findMethod("com.combosdk.openapi.ComboApplication") { name == "attachBaseContext" }.hookBefore { + val context = it.args[0] as Context + Utils.check(context, modulePath) + sp = context.getSharedPreferences("serverConfig", 0) + forceUrl = sp.getBoolean("forceUrl", false) + startForceUrl = forceUrl + server = sp.getString("serverip", "") ?: "" + proxyList = sp.getBoolean("ProxyList", false) + startProxyList = proxyList + if (sp.getBoolean("KeepSSL", false)) sslHook() + } + hook() + findMethod(Activity::class.java, true) { name == "onCreate" }.hookBefore { param -> + activity = param.thisObject as Activity + } + findMethod("com.miHoYo.GetMobileInfo.MainActivity") { name == "onCreate" }.hookBefore { param -> + activity = param.thisObject as Activity + showDialog() + activity.windowManager.addView(LinearLayout(activity).apply { + dialog = this + visibility = View.GONE + background = ShapeDrawable().apply { + shape = RoundRectShape(floatArrayOf(18f, 18f, 18f, 18f, 18f, 18f, 18f, 18f), null, null) + paint.color = Color.parseColor("#FFEFEDF5") + } + addView(TextView(activity).apply { + layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT).also { + it.gravity = Gravity.CENTER_VERTICAL + } + gravity = Gravity.CENTER + text = String(Base64.decode("5pys5qih5Z2X5piv5YWN6LS55bm25byA5rqQ55qELCDlpoLmnpzkvaDmmK/otK3kubDnmoTmraTmqKHlnZfmiJbova/ku7bjgIJcbumCo+S5iOS9oOiiq+mql+S6hu+8jOivt+mAgOasvivlt67or4TvvIFcblRoaXMgbW9kdWxlIGlzIGZyZWUgYW5kIG9wZW4gc291cmNlLCBpZiB5b3UgcHVyY2hhc2VkIHRoaXMgbW9kdWxlIG9yIHNvZnR3YXJlLlxuVGhlbiB5b3UgaGF2ZSBiZWVuIGNoZWF0ZWQsIHBsZWFzZSByZWZ1bmQh", Base64.DEFAULT)).replace("\\n", "\n") + }) + }, WindowManager.LayoutParams(dp2px(activity, 200f), dp2px(activity, 150f), WindowManager.LayoutParams.TYPE_APPLICATION, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, PixelFormat.TRANSLUCENT).apply { + gravity = Gravity.CENTER_VERTICAL + x = 0 + y = 0 + }) + } + } + + private fun showDialog() { + AlertDialog.Builder(activity).apply { + setCancelable(false) + setTitle(moduleRes.getString(R.string.SelectServer)) + setMessage(moduleRes.getString(R.string.Tips)) + setNegativeButton(moduleRes.getString(R.string.Settings)) { _, _ -> + AlertDialog.Builder(activity).apply { + setMessage(moduleRes.getString(R.string.Tips2)) + setCancelable(false) + setView(ScrollView(context).apply { + setPadding(25, 0, 25, 0) + addView(LinearLayout(activity).apply { + orientation = LinearLayout.VERTICAL + addView(EditText(activity).apply { + hint = "http(s)://server.com:1234" + val str = sp.getString("serverip", "") ?: "" + setText(str.toCharArray(), 0, str.length) + addTextChangedListener(object : TextWatcher { + override fun beforeTextChanged(p0: CharSequence, p1: Int, p2: Int, p3: Int) {} + override fun onTextChanged(p0: CharSequence, p1: Int, p2: Int, p3: Int) {} + + @SuppressLint("CommitPrefEdits") + override fun afterTextChanged(p0: Editable) { + sp.edit().run { + putString("serverip", p0.toString()) + apply() + } + } + }) + }) + addView(Switch(activity).apply { + text = moduleRes.getString(R.string.ForcedMode) + isChecked = sp.getBoolean("forceUrl", false) + setOnCheckedChangeListener { _, b -> + sp.edit().run { + putBoolean("forceUrl", b) + apply() + } + forceUrl = b + } + }) + addView(Switch(activity).apply { + text = moduleRes.getString(R.string.ProxyList) + isChecked = sp.getBoolean("ProxyList", false) + setOnCheckedChangeListener { _, b -> + sp.edit().run { + putBoolean("ProxyList", b) + apply() + } + proxyList = b + } + }) + addView(Switch(activity).apply { + text = moduleRes.getString(R.string.HookConfig) + isChecked = sp.getBoolean("HookConfig", false) + setOnCheckedChangeListener { _, b -> + sp.edit().run { + putBoolean("HookConfig", b) + apply() + } + proxyList = b + } + }) + addView(Switch(activity).apply { + text = moduleRes.getString(R.string.EnableTools) + isChecked = sp.getBoolean("EnableTools", false) + setOnCheckedChangeListener { _, b -> + sp.edit().run { + putBoolean("EnableTools", b) + apply() + } + proxyList = b + } + }) + addView(Switch(activity).apply { + text = moduleRes.getString(R.string.KeepSSL) + isChecked = sp.getBoolean("KeepSSL", false) + setOnCheckedChangeListener { _, b -> + sp.edit().run { + putBoolean("KeepSSL", b) + apply() + } + } + }) + }) + }) + setPositiveButton(moduleRes.getString(R.string.Back)) { _, _ -> + showDialog() + } + setNeutralButton(moduleRes.getString(R.string.ExitGames)) { _, _ -> + exitProcess(0) + } + }.show() + } + setPositiveButton(moduleRes.getString(R.string.CustomServer)) { _, _ -> + val ip = sp.getString("serverip", "") ?: "" + if (ip == "") { + Toast.makeText(activity, moduleRes.getString(R.string.ServerAddressError), Toast.LENGTH_LONG).show() + activity.finish() + } else { + server = ip + forceUrl = true + if (sp.getBoolean("EnableTools", false)) gmTool() + Thread { + runOnMainThread { + dialog.visibility = View.VISIBLE + } + Thread.sleep(10 * 1000) + runOnMainThread { + dialog.visibility = View.GONE + activity.windowManager.removeView(dialog) + } + }.start() + } + } + setNeutralButton(moduleRes.getString(R.string.OfficialServer)) { _, _ -> + forceUrl = false + server = "" + if (startForceUrl || startProxyList) { + Toast.makeText(activity, moduleRes.getString(R.string.JoinServerError), Toast.LENGTH_LONG).show() + showDialog() + } + } + }.show() + } + + inner class MoveOnTouchListener : View.OnTouchListener { + private var originalXPos = 0 + private var originalYPos = 0 + + private var offsetX = 0f + private var offsetY = 0f + + @SuppressLint("ClickableViewAccessibility") + override fun onTouch(v: View, event: MotionEvent): Boolean { + when (event.action) { + MotionEvent.ACTION_DOWN -> { + val x = event.rawX + val y = event.rawY + + val location = IntArray(2) + v.getLocationOnScreen(location) + + originalXPos = location[0] + originalYPos = location[1] + + offsetX = x - originalXPos + offsetY = y - originalYPos + } + MotionEvent.ACTION_MOVE -> { + val onScreen = IntArray(2) + v.getLocationOnScreen(onScreen) + + val x = event.rawX + val y = event.rawY + + val params: WindowManager.LayoutParams = v.layoutParams as WindowManager.LayoutParams + + val newX = (x - offsetX).toInt() + val newY = (y - offsetY).toInt() + + if (newX == originalXPos && newY == originalYPos) { + return false + } + + params.x = newX + params.y = newY + + windowManager.updateViewLayout(v, params) + } + } + return false + } + } + + private lateinit var imageView: ImageView + private lateinit var mainView: ScrollView + private fun gmTool() { + if (this::mainView.isInitialized) return + if (this::imageView.isInitialized) return + if (isInit) return + isInit = true + mainView = ScrollView(activity).apply { + visibility = View.GONE + addView(LinearLayout(activity).apply { + orientation = LinearLayout.VERTICAL + layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT) + setBackgroundColor(Color.parseColor("#5F000000")) + addView(LinearLayout(activity).apply { + layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) + setBackgroundColor(Color.parseColor("#8F000000")) + addView(TextView(activity).apply { + layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT, 1f) + setTextColor(Color.BLUE) + setTextSize(TypedValue.COMPLEX_UNIT_SP, 18f) + text = moduleRes.getString(R.string.Tools) + }) + addView(TextView(activity).apply { + layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT).also { + it.setMargins(0, 0, 5, 0) + } + setTextColor(Color.BLUE) + setTextSize(TypedValue.COMPLEX_UNIT_SP, 18f) + text = "X" + setOnClickListener { + mainView.visibility = View.GONE + imageView.visibility = View.VISIBLE + } + }) + }) + addView(LinearLayout(activity).apply { + orientation = LinearLayout.VERTICAL + layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT) + var userEdit: EditText + var passEdit: EditText + addView(LinearLayout(activity).apply { + layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) + addView(TextView(activity).apply { + setTextColor(Color.BLUE) + text = moduleRes.getString(R.string.CheckServerStatus) + setOnClickListener { + Thread { + try { + XposedBridge.log("$server/authentication/type") + URL("$server/authentication/type").apply { + val conn = if (server.startsWith("https")) { + (openConnection() as HttpsURLConnection).apply { + sslSocketFactory = getDefaultSSLSocketFactory() + hostnameVerifier = getDefaultHostnameVerifier() + } + } else { + openConnection() as HttpURLConnection + } + conn.requestMethod = "GET" + conn.readTimeout = 8000 + conn.connectTimeout = 8000 + + val reader = BufferedReader(InputStreamReader(conn.inputStream)) + if (conn.responseCode == 200) { + val response = StringBuilder() + var line = "" + while (reader.readLine()?.also { line = it } != null) { + response.append(line) + } + runOnMainThread { + text = if (response.toString() == "me.exzork.gcauth.handler.GCAuthAuthenticationHandler") moduleRes.getString(R.string.ServerStatus) + "GcAuth" else moduleRes.getString(R.string.ServerStatus) + "GcAuth" + moduleRes.getString(R.string.NotInstall) + } + } else { + runOnMainThread { + text = moduleRes.getString(R.string.ServerStatus) + moduleRes.getString(R.string.GetServerStatusError) + } + } + } + } catch (e: Throwable) { + runOnMainThread { + text = moduleRes.getString(R.string.ServerStatus) + moduleRes.getString(R.string.GetServerStatusError) + e + } + } + }.start() + } + }) + }) + addView(LinearLayout(activity).apply { + layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) + addView(Switch(activity).apply { + text = moduleRes.getString(R.string.InputSwitch) + setOnCheckedChangeListener { _, b -> + if (b) { + val params = mainView.layoutParams as WindowManager.LayoutParams + params.flags = params.flags and (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE.inv()) + windowManager.updateViewLayout(mainView, params) + } else { + val params = mainView.layoutParams as WindowManager.LayoutParams + params.flags = params.flags or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + windowManager.updateViewLayout(mainView, params) + } + } + }) + }) + addView(LinearLayout(activity).apply { + layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) + addView(TextView(activity).apply { + setTextColor(Color.BLUE) + text = moduleRes.getString(R.string.User) + }) + addView(EditText(activity).apply { + userEdit = this + layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) + val user = sp.getString("user", "") ?: "" + setText(user.toCharArray(), 0, user.length) + }) + }) + addView(LinearLayout(activity).apply { + layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) + addView(TextView(activity).apply { + setTextColor(Color.BLUE) + text = moduleRes.getString(R.string.Password) + }) + addView(EditText(activity).apply { + passEdit = this + layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) + inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD + val user = sp.getString("pass", "") ?: "" + setText(user.toCharArray(), 0, user.length) + }) + }) + addView(LinearLayout(activity).apply { + layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) + addView(Button(activity).apply { + text = moduleRes.getString(R.string.Login) + layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) + setOnClickListener { + Thread { + try { + URL("$server/authentication/type").apply { + val conn = if (server.startsWith("https")) { + (openConnection() as HttpsURLConnection).apply { + sslSocketFactory = getDefaultSSLSocketFactory() + hostnameVerifier = getDefaultHostnameVerifier() + } + } else { + openConnection() as HttpURLConnection + } + conn.requestMethod = "POST" + conn.readTimeout = 8000 + conn.connectTimeout = 8000 + conn.doOutput = true + conn.doInput = true + conn.useCaches = false + + conn.outputStream.apply { + write("{\"username\":\"${userEdit.text}\",\"password\":\"${passEdit.text}\"}".toByteArray()) + flush() + } + if (conn.responseCode == 200) { + val input = conn.inputStream + val message = ByteArrayOutputStream() + + var len: Int + val buffer = ByteArray(1024) + while (input.read(buffer).also { len = it } != -1) { + message.write(buffer, 0, len) + } + input.close() + message.close() + + val json = JSONObject(String(message.toByteArray())) + if (json.optBoolean("success", false)) { + val token = json.optString("jwt", "") + runOnMainThread { + Toast.makeText(activity, "${moduleRes.getString(R.string.LoginSuccess)}\n${token}", Toast.LENGTH_LONG).show() + @Suppress("DEPRECATION") + (activity.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager).text = token + sp.edit().run { + putString("user", userEdit.text.toString()) + putString("pass", passEdit.text.toString()) + apply() + } + } + } else { + runOnMainThread { + Toast.makeText(activity, moduleRes.getString(R.string.LoginFailed) + json.optString("message", ""), Toast.LENGTH_LONG).show() + } + } + } + } + } catch (e: Throwable) { + runOnMainThread { + Toast.makeText(activity, moduleRes.getString(R.string.LoginError) + e, Toast.LENGTH_LONG).show() + } + } + }.start() + } + }) + }) + addView(LinearLayout(activity).apply { + layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) + addView(Button(activity).apply { + text = "Open WebView" + layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) + setOnClickListener { + val webview = loadClass("com.miHoYo.sdk.webview.MiHoYoWebview") + webview.invokeStaticMethod("init", args(activity, "test_webview"), argTypes(Activity::class.java, String::class.java)) + webview.invokeStaticMethod("show", args("test_webview"), argTypes(String::class.java)) + webview.invokeStaticMethod("load", args("test_webview", "https://www.fkj233.cn/gourl/"), argTypes(String::class.java, String::class.java)) + } + }) + }) + }) + }) + } + + windowManager = activity.windowManager + windowManager.addView(mainView, WindowManager.LayoutParams(dp2px(activity, 200f), WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.TYPE_APPLICATION, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, PixelFormat.TRANSLUCENT).apply { + gravity = Gravity.START or Gravity.TOP + x = 0 + y = 0 + }) + + val layoutParams = WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_APPLICATION, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, PixelFormat.TRANSLUCENT).apply { + gravity = Gravity.START or Gravity.TOP + x = 0 + y = 0 + } + imageView = ImageView(activity).apply { + @Suppress("DEPRECATION") + background = moduleRes.getDrawable(R.drawable.ic_android_black_24dp).also { it.alpha = 50 } + this.layoutParams = layoutParams + setOnTouchListener(MoveOnTouchListener()) + setOnClickListener { + mainView.visibility = View.VISIBLE + it.visibility = View.GONE + } + } + windowManager.addView(imageView, layoutParams) + } + + private fun sslHook() { + // OkHttp3 Hook + findMethodOrNull("com.combosdk.lib.third.okhttp3.OkHttpClient\$Builder") { name == "build" }?.hookBefore { + it.thisObject.invokeMethod("sslSocketFactory", args(getDefaultSSLSocketFactory()), argTypes(SSLSocketFactory::class.java)) + it.thisObject.invokeMethod("hostnameVerifier", args(getDefaultHostnameVerifier()), argTypes(HostnameVerifier::class.java)) + } + findMethodOrNull("okhttp3.OkHttpClient\$Builder") { name == "build" }?.hookBefore { + it.thisObject.invokeMethod("sslSocketFactory", args(getDefaultSSLSocketFactory(), DefaultTrustManager()), argTypes(SSLSocketFactory::class.java, X509TrustManager::class.java)) + it.thisObject.invokeMethod("hostnameVerifier", args(getDefaultHostnameVerifier()), argTypes(HostnameVerifier::class.java)) + } + // WebView Hook + arrayListOf( + "android.webkit.WebViewClient", + "cn.sharesdk.framework.g", + "com.facebook.internal.WebDialog\$DialogWebViewClient", + "com.geetest.sdk.dialog.views.GtWebView\$c", + "com.miHoYo.sdk.webview.common.view.ContentWebView\$6" + ).forEach { + findMethodOrNull(it) { name == "onReceivedSslError" && parameterTypes[1] == SslErrorHandler::class.java }?.hookBefore { param -> + (param.args[1] as SslErrorHandler).proceed() + } + } + // Android HttpsURLConnection Hook + findMethodOrNull("javax.net.ssl.HttpsURLConnection") { name == "getDefaultSSLSocketFactory" }?.hookBefore { + it.result = getDefaultSSLSocketFactory() + } + findMethodOrNull("javax.net.ssl.HttpsURLConnection") { name == "setSSLSocketFactory" }?.hookBefore { + it.result = null + } + findMethodOrNull("javax.net.ssl.HttpsURLConnection") { name == "setDefaultSSLSocketFactory" }?.hookBefore { + it.result = null + } + findMethodOrNull("javax.net.ssl.HttpsURLConnection") { name == "setHostnameVerifier" }?.hookBefore { + it.result = null + } + findMethodOrNull("javax.net.ssl.HttpsURLConnection") { name == "setDefaultHostnameVerifier" }?.hookBefore { + it.result = null + } + findMethodOrNull("javax.net.ssl.HttpsURLConnection") { name == "getDefaultHostnameVerifier" }?.hookBefore { + it.result = getDefaultHostnameVerifier() + } + } + + private fun hook() { + findMethod("com.miHoYo.sdk.webview.MiHoYoWebview") { name == "load" && parameterTypes[0] == String::class.java && parameterTypes[1] == String::class.java }.hookBefore { + replaceUrl(it, 1) + } + findAllMethods("android.webkit.WebView") { name == "loadUrl" }.hookBefore { + replaceUrl(it, 0) + } + findAllMethods("android.webkit.WebView") { name == "postUrl" }.hookBefore { + replaceUrl(it, 0) + } + + findMethod("okhttp3.HttpUrl") { name == "parse" && parameterTypes[0] == String::class.java }.hookBefore { + replaceUrl(it, 0) + } + findMethod("com.combosdk.lib.third.okhttp3.HttpUrl") { name == "parse" && parameterTypes[0] == String::class.java }.hookBefore { + replaceUrl(it, 0) + } + + findMethod("com.google.gson.Gson") { name == "fromJson" && parameterTypes[0] == String::class.java && parameterTypes[1] == java.lang.reflect.Type::class.java }.hookBefore { + replaceUrl(it, 0) + } + findConstructor("java.net.URL") { parameterTypes[0] == String::class.java }.hookBefore { + replaceUrl(it, 0) + } + findMethod("com.combosdk.lib.third.okhttp3.Request\$Builder") { name == "url" && parameterTypes[0] == String::class.java }.hookBefore { + replaceUrl(it, 0) + } + findMethod("okhttp3.Request\$Builder") { name == "url" && parameterTypes[0] == String::class.java }.hookBefore { + replaceUrl(it, 0) + } + } + + private fun replaceUrl(method: XC_MethodHook.MethodHookParam, args: Int) { + if (!forceUrl && !proxyList) return + if (!this::server.isInitialized) return + if (server == "") return + if (method.args[args].toString() == "") return + + XposedBridge.log("old: " + method.args[args].toString()) + if (!sp.getBoolean("HookConfig", false) && method.args[args].toString().startsWith("[{\"area\":")) return + if (proxyList) { + for (list in proxyListRegex) { + for (head in arrayListOf("http://", "https://")) { + method.args[args] = method.args[args].toString().replace(head + list, server) + } + } + } else { + val m = regex.matcher(method.args[args].toString()) + if (m.find()) { + method.args[args] = m.replaceAll(server) + } + } + XposedBridge.log("new: " + method.args[args].toString()) + } +} \ No newline at end of file diff --git a/app/src/main/java/xfk233/genshinproxy/MainHook.kt b/app/src/main/java/xfk233/genshinproxy/MainHook.kt index b051453..54b59a9 100644 --- a/app/src/main/java/xfk233/genshinproxy/MainHook.kt +++ b/app/src/main/java/xfk233/genshinproxy/MainHook.kt @@ -1,673 +1,19 @@ package xfk233.genshinproxy -import android.annotation.SuppressLint -import android.app.Activity -import android.app.AlertDialog -import android.content.ClipboardManager -import android.content.Context -import android.content.SharedPreferences -import android.content.res.XModuleResources -import android.graphics.Color -import android.graphics.PixelFormat -import android.text.Editable -import android.text.InputType -import android.text.TextWatcher -import android.util.TypedValue -import android.view.Gravity -import android.view.MotionEvent -import android.view.View -import android.view.WindowManager -import android.webkit.SslErrorHandler -import android.widget.* -import com.github.kyuubiran.ezxhelper.init.EzXHelperInit -import com.github.kyuubiran.ezxhelper.utils.* import de.robv.android.xposed.IXposedHookLoadPackage import de.robv.android.xposed.IXposedHookZygoteInit -import de.robv.android.xposed.XC_MethodHook -import de.robv.android.xposed.XposedBridge import de.robv.android.xposed.callbacks.XC_LoadPackage -import org.json.JSONObject -import xfk233.genshinproxy.Utils.dp2px -import xfk233.genshinproxy.Utils.isInit -import java.io.BufferedReader -import java.io.ByteArrayOutputStream -import java.io.InputStreamReader -import java.net.HttpURLConnection -import java.net.URL -import java.security.SecureRandom -import java.security.cert.X509Certificate -import java.util.regex.Pattern -import javax.net.ssl.* -import kotlin.system.exitProcess class MainHook : IXposedHookLoadPackage, IXposedHookZygoteInit { - private val regex = Pattern.compile("http(s|)://.*?\\.(hoyoverse|mihoyo|yuanshen|mob)\\.com") - private lateinit var server: String - private var forceUrl = false - private lateinit var modulePath: String - private lateinit var moduleRes: XModuleResources - private lateinit var windowManager: WindowManager - private var proxyList = false - private lateinit var sp: SharedPreferences - private val proxyListRegex = arrayListOf( - "api-os-takumi.mihoyo.com", - "hk4e-api-os-static.mihoyo.com", - "hk4e-sdk-os.mihoyo.com", - "dispatchosglobal.yuanshen.com", - "osusadispatch.yuanshen.com", - "account.mihoyo.com", - "log-upload-os.mihoyo.com", - "dispatchcntest.yuanshen.com", - "devlog-upload.mihoyo.com", - "webstatic.mihoyo.com", - "log-upload.mihoyo.com", - "hk4e-sdk.mihoyo.com", - "api-beta-sdk.mihoyo.com", - "api-beta-sdk-os.mihoyo.com", - "cnbeta01dispatch.yuanshen.com", - "dispatchcnglobal.yuanshen.com", - "cnbeta02dispatch.yuanshen.com", - "sdk-os-static.mihoyo.com", - "webstatic-sea.mihoyo.com", - "webstatic-sea.hoyoverse.com", - "hk4e-sdk-os-static.hoyoverse.com", - "sdk-os-static.hoyoverse.com", - "api-account-os.hoyoverse.com", - "hk4e-sdk-os.hoyoverse.com", - "overseauspider.yuanshen.com", - "gameapi-account.mihoyo.com", - "minor-api.mihoyo.com", - "public-data-api.mihoyo.com", - "uspider.yuanshen.com", - "sdk-static.mihoyo.com", - "minor-api-os.hoyoverse.com", - "log-upload-os.hoyoverse.com" - ) + private val hook = Hook() - private val activityList: ArrayList = arrayListOf() - private var activity: Activity - get() { - for (mActivity in activityList) { - if (mActivity.isFinishing) { - activityList.remove(mActivity) - } else { - return mActivity - } - } - throw Throwable("Activity not found.") - } - set(value) { - activityList.add(value) - } - - private fun getDefaultSSLSocketFactory(): SSLSocketFactory { - return SSLContext.getInstance("TLS").apply { - init(arrayOf(), arrayOf(DefaultTrustManager()), SecureRandom()) - }.socketFactory - } - - private fun getDefaultHostnameVerifier(): HostnameVerifier { - return DefaultHostnameVerifier() - } - - class DefaultHostnameVerifier : HostnameVerifier { - @SuppressLint("BadHostnameVerifier") - override fun verify(p0: String?, p1: SSLSession?): Boolean { - return true - } - - } - - @SuppressLint("CustomX509TrustManager") - private class DefaultTrustManager : X509TrustManager { - - @SuppressLint("TrustAllX509TrustManager") - override fun checkClientTrusted(chain: Array?, authType: String?) { - } - - @SuppressLint("TrustAllX509TrustManager") - override fun checkServerTrusted(chain: Array?, authType: String?) { - } - - override fun getAcceptedIssuers(): Array { - return arrayOf() - } + override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) { + hook.handleLoadPackage(lpparam) } override fun initZygote(startupParam: IXposedHookZygoteInit.StartupParam) { - modulePath = startupParam.modulePath - moduleRes = XModuleResources.createInstance(modulePath, null) - TrustMeAlready().initZygote(startupParam) + hook.initZygote(startupParam) } - private var startForceUrl = false - private var startProxyList = false - - @SuppressLint("WrongConstant", "ClickableViewAccessibility") - override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) { - if (lpparam.packageName != "com.miHoYo.GenshinImpact") return - EzXHelperInit.initHandleLoadPackage(lpparam) - findMethod("com.combosdk.openapi.ComboApplication") { name == "attachBaseContext" }.hookBefore { - val context = it.args[0] as Context - sp = context.getSharedPreferences("serverConfig", 0) - forceUrl = sp.getBoolean("forceUrl", false) - startForceUrl = forceUrl - server = sp.getString("serverip", "") ?: "" - proxyList = sp.getBoolean("ProxyList", false) - startProxyList = proxyList - if (sp.getBoolean("KeepSSL", false)) sslHook() - } - hook() - findMethod(Activity::class.java, true) { name == "onCreate" }.hookBefore { param -> - activity = param.thisObject as Activity - } - findMethod("com.miHoYo.GetMobileInfo.MainActivity") { name == "onCreate" }.hookBefore { param -> - activity = param.thisObject as Activity - showDialog() - } - } - - private fun showDialog() { - AlertDialog.Builder(activity).apply { - setCancelable(false) - setTitle(moduleRes.getString(R.string.SelectServer)) - setMessage(moduleRes.getString(R.string.Tips)) - setNegativeButton(moduleRes.getString(R.string.Settings)) { _, _ -> - AlertDialog.Builder(activity).apply { - setMessage(moduleRes.getString(R.string.Tips2)) - setCancelable(false) - setView(ScrollView(context).apply { - setPadding(25, 0, 25, 0) - addView(LinearLayout(activity).apply { - orientation = LinearLayout.VERTICAL - addView(EditText(activity).apply { - hint = "http(s)://server.com:1234" - val str = sp.getString("serverip", "") ?: "" - setText(str.toCharArray(), 0, str.length) - addTextChangedListener(object : TextWatcher { - override fun beforeTextChanged(p0: CharSequence, p1: Int, p2: Int, p3: Int) {} - override fun onTextChanged(p0: CharSequence, p1: Int, p2: Int, p3: Int) {} - - @SuppressLint("CommitPrefEdits") - override fun afterTextChanged(p0: Editable) { - sp.edit().run { - putString("serverip", p0.toString()) - apply() - } - } - }) - }) - addView(Switch(activity).apply { - text = moduleRes.getString(R.string.ForcedMode) - isChecked = sp.getBoolean("forceUrl", false) - setOnCheckedChangeListener { _, b -> - sp.edit().run { - putBoolean("forceUrl", b) - apply() - } - forceUrl = b - } - }) - addView(Switch(activity).apply { - text = moduleRes.getString(R.string.ProxyList) - isChecked = sp.getBoolean("ProxyList", false) - setOnCheckedChangeListener { _, b -> - sp.edit().run { - putBoolean("ProxyList", b) - apply() - } - proxyList = b - } - }) - addView(Switch(activity).apply { - text = moduleRes.getString(R.string.HookConfig) - isChecked = sp.getBoolean("HookConfig", false) - setOnCheckedChangeListener { _, b -> - sp.edit().run { - putBoolean("HookConfig", b) - apply() - } - proxyList = b - } - }) - addView(Switch(activity).apply { - text = moduleRes.getString(R.string.EnableTools) - isChecked = sp.getBoolean("EnableTools", false) - setOnCheckedChangeListener { _, b -> - sp.edit().run { - putBoolean("EnableTools", b) - apply() - } - proxyList = b - } - }) - addView(Switch(activity).apply { - text = moduleRes.getString(R.string.KeepSSL) - isChecked = sp.getBoolean("KeepSSL", false) - setOnCheckedChangeListener { _, b -> - sp.edit().run { - putBoolean("KeepSSL", b) - apply() - } - } - }) - }) - }) - setPositiveButton(moduleRes.getString(R.string.Back)) { _, _ -> - showDialog() - } - setNeutralButton(moduleRes.getString(R.string.ExitGames)) { _, _ -> - exitProcess(0) - } - }.show() - } - setPositiveButton(moduleRes.getString(R.string.CustomServer)) { _, _ -> - val ip = sp.getString("serverip", "") ?: "" - if (ip == "") { - Toast.makeText(activity, moduleRes.getString(R.string.ServerAddressError), Toast.LENGTH_LONG).show() - activity.finish() - } else { - server = ip - forceUrl = true - if (sp.getBoolean("EnableTools", false)) gmTool() - } - } - setNeutralButton(moduleRes.getString(R.string.OfficialServer)) { _, _ -> - forceUrl = false - server = "" - if (startForceUrl || startProxyList) { - Toast.makeText(activity, moduleRes.getString(R.string.JoinServerError), Toast.LENGTH_LONG).show() - showDialog() - } - } - }.show() - } - - inner class MoveOnTouchListener : View.OnTouchListener { - private var originalXPos = 0 - private var originalYPos = 0 - - private var offsetX = 0f - private var offsetY = 0f - - @SuppressLint("ClickableViewAccessibility") - override fun onTouch(v: View, event: MotionEvent): Boolean { - when (event.action) { - MotionEvent.ACTION_DOWN -> { - val x = event.rawX - val y = event.rawY - - val location = IntArray(2) - v.getLocationOnScreen(location) - - originalXPos = location[0] - originalYPos = location[1] - - offsetX = x - originalXPos - offsetY = y - originalYPos - } - MotionEvent.ACTION_MOVE -> { - val onScreen = IntArray(2) - v.getLocationOnScreen(onScreen) - - val x = event.rawX - val y = event.rawY - - val params: WindowManager.LayoutParams = v.layoutParams as WindowManager.LayoutParams - - val newX = (x - offsetX).toInt() - val newY = (y - offsetY).toInt() - - if (newX == originalXPos && newY == originalYPos) { - return false - } - - params.x = newX - params.y = newY - - windowManager.updateViewLayout(v, params) - } - } - return false - } - } - - private lateinit var imageView: ImageView - private lateinit var mainView: ScrollView - private fun gmTool() { - if (this::mainView.isInitialized) return - if (this::imageView.isInitialized) return - if (isInit) return - isInit = true - mainView = ScrollView(activity).apply { - visibility = View.GONE - addView(LinearLayout(activity).apply { - orientation = LinearLayout.VERTICAL - layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT) - setBackgroundColor(Color.parseColor("#5F000000")) - addView(LinearLayout(activity).apply { - layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) - setBackgroundColor(Color.parseColor("#8F000000")) - addView(TextView(activity).apply { - layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT, 1f) - setTextColor(Color.BLUE) - setTextSize(TypedValue.COMPLEX_UNIT_SP, 18f) - text = moduleRes.getString(R.string.Tools) - }) - addView(TextView(activity).apply { - layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT).also { - it.setMargins(0, 0, 5, 0) - } - setTextColor(Color.BLUE) - setTextSize(TypedValue.COMPLEX_UNIT_SP, 18f) - text = "X" - setOnClickListener { - mainView.visibility = View.GONE - imageView.visibility = View.VISIBLE - } - }) - }) - addView(LinearLayout(activity).apply { - orientation = LinearLayout.VERTICAL - layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT) - var userEdit: EditText - var passEdit: EditText - addView(LinearLayout(activity).apply { - layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) - addView(TextView(activity).apply { - setTextColor(Color.BLUE) - text = moduleRes.getString(R.string.CheckServerStatus) - setOnClickListener { - Thread() { - try { - XposedBridge.log("$server/authentication/type") - URL("$server/authentication/type").apply { - val conn = if (server.startsWith("https")) { - (openConnection() as HttpsURLConnection).apply { - sslSocketFactory = getDefaultSSLSocketFactory() - hostnameVerifier = getDefaultHostnameVerifier() - } - } else { - openConnection() as HttpURLConnection - } - conn.requestMethod = "GET" - conn.readTimeout = 8000 - conn.connectTimeout = 8000 - - val reader = BufferedReader(InputStreamReader(conn.inputStream)) - if (conn.responseCode == 200) { - val response = StringBuilder() - var line = "" - while (reader.readLine()?.also { line = it } != null) { - response.append(line) - } - runOnMainThread { - text = if (response.toString() == "me.exzork.gcauth.handler.GCAuthAuthenticationHandler") moduleRes.getString(R.string.ServerStatus) + "GcAuth" else moduleRes.getString(R.string.ServerStatus) + "GcAuth" + moduleRes.getString(R.string.NotInstall) - } - } else { - runOnMainThread { - text = moduleRes.getString(R.string.ServerStatus) + moduleRes.getString(R.string.GetServerStatusError) - } - } - } - } catch (e: Throwable) { - runOnMainThread { - text = moduleRes.getString(R.string.ServerStatus) + moduleRes.getString(R.string.GetServerStatusError) + e - } - } - }.start() - } - }) - }) - addView(LinearLayout(activity).apply { - layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) - addView(Switch(activity).apply { - text = moduleRes.getString(R.string.InputSwitch) - setOnCheckedChangeListener { _, b -> - if (b) { - val params = mainView.layoutParams as WindowManager.LayoutParams - params.flags = params.flags and (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE.inv()) - windowManager.updateViewLayout(mainView, params) - } else { - val params = mainView.layoutParams as WindowManager.LayoutParams - params.flags = params.flags or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - windowManager.updateViewLayout(mainView, params) - } - } - }) - }) - addView(LinearLayout(activity).apply { - layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) - addView(TextView(activity).apply { - setTextColor(Color.BLUE) - text = moduleRes.getString(R.string.User) - }) - addView(EditText(activity).apply { - userEdit = this - layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) - val user = sp.getString("user", "") ?: "" - setText(user.toCharArray(), 0, user.length) - }) - }) - addView(LinearLayout(activity).apply { - layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) - addView(TextView(activity).apply { - setTextColor(Color.BLUE) - text = moduleRes.getString(R.string.Password) - }) - addView(EditText(activity).apply { - passEdit = this - layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) - inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD - val user = sp.getString("pass", "") ?: "" - setText(user.toCharArray(), 0, user.length) - }) - }) - addView(LinearLayout(activity).apply { - layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) - addView(Button(activity).apply { - text = moduleRes.getString(R.string.Login) - layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) - setOnClickListener { - Thread() { - try { - URL("$server/authentication/type").apply { - val conn = if (server.startsWith("https")) { - (openConnection() as HttpsURLConnection).apply { - sslSocketFactory = getDefaultSSLSocketFactory() - hostnameVerifier = getDefaultHostnameVerifier() - } - } else { - openConnection() as HttpURLConnection - } - conn.requestMethod = "POST" - conn.readTimeout = 8000 - conn.connectTimeout = 8000 - conn.doOutput = true - conn.doInput = true - conn.useCaches = false - - conn.outputStream.apply { - write("{\"username\":\"${userEdit.text}\",\"password\":\"${passEdit.text}\"}".toByteArray()) - flush() - } - if (conn.responseCode == 200) { - val input = conn.inputStream - val message = ByteArrayOutputStream() - - var len: Int - val buffer = ByteArray(1024) - while (input.read(buffer).also { len = it } != -1) { - message.write(buffer, 0, len) - } - input.close() - message.close() - - val json = JSONObject(String(message.toByteArray())) - if (json.optBoolean("success", false)) { - val token = json.optString("jwt", "") - runOnMainThread { - Toast.makeText(activity, "${moduleRes.getString(R.string.LoginSuccess)}\n${token}", Toast.LENGTH_LONG).show() - (activity.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager).text = token - sp.edit().run { - putString("user", userEdit.text.toString()) - putString("pass", passEdit.text.toString()) - apply() - } - } - } else { - runOnMainThread { - Toast.makeText(activity, moduleRes.getString(R.string.LoginFailed) + json.optString("message", ""), Toast.LENGTH_LONG).show() - } - } - } - } - } catch (e: Throwable) { - runOnMainThread { - Toast.makeText(activity, moduleRes.getString(R.string.LoginError) + e, Toast.LENGTH_LONG).show() - } - } - }.start() - } - }) - }) - addView(LinearLayout(activity).apply { - layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) - addView(Button(activity).apply { - text = "Open WebView" - layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) - setOnClickListener { - val webview = loadClass("com.miHoYo.sdk.webview.MiHoYoWebview") - webview.invokeStaticMethod("init", args(activity, "test_webview"), argTypes(Activity::class.java, String::class.java)) - webview.invokeStaticMethod("show", args("test_webview"), argTypes(String::class.java)) - webview.invokeStaticMethod("load", args("test_webview", "https://www.fkj233.cn/gourl/"), argTypes(String::class.java, String::class.java)) - } - }) - }) - }) - }) - } - - windowManager = activity.windowManager - windowManager.addView(mainView, WindowManager.LayoutParams(dp2px(activity, 200f), WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.TYPE_APPLICATION, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, PixelFormat.TRANSLUCENT).apply { - gravity = Gravity.START or Gravity.TOP - x = 0 - y = 0 - }) - - val layoutParams = WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_APPLICATION, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, PixelFormat.TRANSLUCENT).apply { - gravity = Gravity.START or Gravity.TOP - x = 0 - y = 0 - } - imageView = ImageView(activity).apply { - @Suppress("DEPRECATION") - background = moduleRes.getDrawable(R.drawable.ic_android_black_24dp).also { it.alpha = 50 } - this.layoutParams = layoutParams - setOnTouchListener(MoveOnTouchListener()) - setOnClickListener { - mainView.visibility = View.VISIBLE - it.visibility = View.GONE - } - } - windowManager.addView(imageView, layoutParams) - } - - private fun sslHook() { - // OkHttp3 Hook - findMethodOrNull("com.combosdk.lib.third.okhttp3.OkHttpClient\$Builder") { name == "build" }?.hookBefore { - it.thisObject.invokeMethod("sslSocketFactory", args(getDefaultSSLSocketFactory()), argTypes(SSLSocketFactory::class.java)) - it.thisObject.invokeMethod("hostnameVerifier", args(getDefaultHostnameVerifier()), argTypes(HostnameVerifier::class.java)) - } - findMethodOrNull("okhttp3.OkHttpClient\$Builder") { name == "build" }?.hookBefore { - it.thisObject.invokeMethod("sslSocketFactory", args(getDefaultSSLSocketFactory(), DefaultTrustManager()), argTypes(SSLSocketFactory::class.java, X509TrustManager::class.java)) - it.thisObject.invokeMethod("hostnameVerifier", args(getDefaultHostnameVerifier()), argTypes(HostnameVerifier::class.java)) - } - // WebView Hook - arrayListOf( - "android.webkit.WebViewClient", - "cn.sharesdk.framework.g", - "com.facebook.internal.WebDialog\$DialogWebViewClient", - "com.geetest.sdk.dialog.views.GtWebView\$c", - "com.miHoYo.sdk.webview.common.view.ContentWebView\$6" - ).forEach { - findMethodOrNull(it) { name == "onReceivedSslError" && parameterTypes[1] == SslErrorHandler::class.java }?.hookBefore { param -> - (param.args[1] as SslErrorHandler).proceed() - } - } - // Android HttpsURLConnection Hook - findMethodOrNull("javax.net.ssl.HttpsURLConnection") { name == "getDefaultSSLSocketFactory" }?.hookBefore { - it.result = getDefaultSSLSocketFactory() - } - findMethodOrNull("javax.net.ssl.HttpsURLConnection") { name == "setSSLSocketFactory" }?.hookBefore { - it.result = null - } - findMethodOrNull("javax.net.ssl.HttpsURLConnection") { name == "setDefaultSSLSocketFactory" }?.hookBefore { - it.result = null - } - findMethodOrNull("javax.net.ssl.HttpsURLConnection") { name == "setHostnameVerifier" }?.hookBefore { - it.result = null - } - findMethodOrNull("javax.net.ssl.HttpsURLConnection") { name == "setDefaultHostnameVerifier" }?.hookBefore { - it.result = null - } - findMethodOrNull("javax.net.ssl.HttpsURLConnection") { name == "getDefaultHostnameVerifier" }?.hookBefore { - it.result = getDefaultHostnameVerifier() - } - } - - private fun hook() { - findMethod("com.miHoYo.sdk.webview.MiHoYoWebview") { name == "load" && parameterTypes[0] == String::class.java && parameterTypes[1] == String::class.java }.hookBefore { - replaceUrl(it, 1) - } - findAllMethods("android.webkit.WebView") { name == "loadUrl" }.hookBefore { - replaceUrl(it, 0) - } - findAllMethods("android.webkit.WebView") { name == "postUrl" }.hookBefore { - replaceUrl(it, 0) - } - - findMethod("okhttp3.HttpUrl") { name == "parse" && parameterTypes[0] == String::class.java }.hookBefore { - replaceUrl(it, 0) - } - findMethod("com.combosdk.lib.third.okhttp3.HttpUrl") { name == "parse" && parameterTypes[0] == String::class.java }.hookBefore { - replaceUrl(it, 0) - } - - findMethod("com.google.gson.Gson") { name == "fromJson" && parameterTypes[0] == String::class.java && parameterTypes[1] == java.lang.reflect.Type::class.java }.hookBefore { - replaceUrl(it, 0) - } - findConstructor("java.net.URL") { parameterTypes[0] == String::class.java }.hookBefore { - replaceUrl(it, 0) - } - findMethod("com.combosdk.lib.third.okhttp3.Request\$Builder") { name == "url" && parameterTypes[0] == String::class.java }.hookBefore { - replaceUrl(it, 0) - } - findMethod("okhttp3.Request\$Builder") { name == "url" && parameterTypes[0] == String::class.java }.hookBefore { - replaceUrl(it, 0) - } - } - - private fun replaceUrl(method: XC_MethodHook.MethodHookParam, args: Int) { - if (!forceUrl && !proxyList) return - if (!this::server.isInitialized) return - if (server == "") return - - if (BuildConfig.DEBUG) XposedBridge.log("old: " + method.args[args].toString()) - if (!sp.getBoolean("HookConfig", false) && method.args[args].toString().startsWith("[{\"area\":")) return - if (proxyList) { - for (list in proxyListRegex) { - for (head in arrayListOf("http://", "https://")) { - method.args[args] = method.args[args].toString().replace(head + list, server) - } - } - } else { - val m = regex.matcher(method.args[args].toString()) - if (m.find()) { - method.args[args] = m.replaceAll(server) - } - } - if (BuildConfig.DEBUG) XposedBridge.log("new: " + method.args[args].toString()) - } } diff --git a/app/src/main/java/xfk233/genshinproxy/TrustMeAlready.java b/app/src/main/java/xfk233/genshinproxy/TrustMeAlready.java index b96f3a6..905f80f 100644 --- a/app/src/main/java/xfk233/genshinproxy/TrustMeAlready.java +++ b/app/src/main/java/xfk233/genshinproxy/TrustMeAlready.java @@ -15,15 +15,14 @@ import de.robv.android.xposed.XposedBridge; import static de.robv.android.xposed.XposedHelpers.*; -public class TrustMeAlready implements IXposedHookZygoteInit { +public class TrustMeAlready { private static final String SSL_CLASS_NAME = "com.android.org.conscrypt.TrustManagerImpl"; private static final String SSL_METHOD_NAME = "checkTrustedRecursive"; private static final Class SSL_RETURN_TYPE = List.class; private static final Class SSL_RETURN_PARAM_TYPE = X509Certificate.class; - @Override - public void initZygote(StartupParam startupParam) throws Throwable { + public void initZygote() { XposedBridge.log("TrustMeAlready loading..."); int hookedMethods = 0; diff --git a/app/src/main/java/xfk233/genshinproxy/Utils.kt b/app/src/main/java/xfk233/genshinproxy/Utils.kt index 33d0452..bbaa64e 100644 --- a/app/src/main/java/xfk233/genshinproxy/Utils.kt +++ b/app/src/main/java/xfk233/genshinproxy/Utils.kt @@ -1,6 +1,10 @@ package xfk233.genshinproxy import android.content.Context +import android.content.pm.PackageManager +import android.util.Base64 +import android.widget.Toast +import kotlin.system.exitProcess object Utils { var isInit = false @@ -9,4 +13,14 @@ object Utils { val scale: Float = context.resources.displayMetrics.density return (dpValue * scale + 0.5f).toInt() } + + inline fun check(context: Context, modulePath: String) { + context.packageManager.getPackageArchiveInfo(modulePath, PackageManager.GET_SIGNING_CERTIFICATES).apply { + this ?: exitProcess(0) + if (signingInfo.apkContentsSigners[0].toCharsString() !in arrayOf(String(Base64.decode("MzA4MjAyZTQzMDgyMDFjYzAyMDEwMTMwMGQwNjA5MmE4NjQ4ODZmNzBkMDEwMTA1MDUwMDMwMzczMTE2MzAxNDA2MDM1NTA0MDMwYzBkNDE2ZTY0NzI2ZjY5NjQyMDQ0NjU2Mjc1NjczMTEwMzAwZTA2MDM1NTA0MGEwYzA3NDE2ZTY0NzI2ZjY5NjQzMTBiMzAwOTA2MDM1NTA0MDYxMzAyNTU1MzMwMjAxNzBkMzIzMjMwMzEzMDM4MzEzMzMxMzEzMjMwNWExODBmMzIzMDM1MzIzMDMxMzAzMTMxMzMzMTMxMzIzMDVhMzAzNzMxMTYzMDE0MDYwMzU1MDQwMzBjMGQ0MTZlNjQ3MjZmNjk2NDIwNDQ2NTYyNzU2NzMxMTAzMDBlMDYwMzU1MDQwYTBjMDc0MTZlNjQ3MjZmNjk2NDMxMGIzMDA5MDYwMzU1MDQwNjEzMDI1NTUzMzA4MjAxMjIzMDBkMDYwOTJhODY0ODg2ZjcwZDAxMDEwMTA1MDAwMzgyMDEwZjAwMzA4MjAxMGEwMjgyMDEwMTAwYTJjNmYyZGEzMTY4NmZhNzMwNTYyODE5NDYyOTFlYWE1M2U1ZTgzYmZkZTliNDgyMGMzNWNiY2ZlN2I2NGNlODhiYWViYjE5ZWNjMjM2YzI2MzczMWE1Mzg4NzJlZTU1MzQxNGYyOTY3ODAyM2JlNGIyYTlkY2QyMzkyMTUzNDY3OGEyOWEwOTkzNTljNDk1YzIwNjgxZjMzYTJmMzU5ZTEzNGY0OGM1N2I5Y2MzOTU0YjZlNzllYjMxMzM5MWMxYjZmYjgwYzM3ZjIyOGZmMjgyOTQxZjRkYTgwNDUwZDYwYzc3ZGRmOGFjYmNiYzA2OTY2MTVlNjRiMjA1YjYyMWRjMTcyMzMzZTBkZTQzOWYyMmI4YTE4M2MzYWMyMWFjZGEyNDcwODI0MjM5MDVkYTRjMjIzM2I2YzY4ODEyMGJjNDdkMWRiMGYwYTlhMGQzZjA3MTI4ZDAwNjE4NzE3OWRjOWY4OWE2YWRjZTY2YjkzNzgwZGQ5YmZlYzE2MjFjMWVjYzYwMzY0YzkzMGM0MDNhY2UyMjEzOTM2ZjQ1ZThlZWI0YjRmZmIxZWJkZDU5NjYxZjU4NmFjZWVmMGUzOWM1YWVkYzI3NDc1M2Q4ZTU3ZjJhZmJlOGRkMGVhYjJmMDA3N2NjOTQyNDc3MGY5ODdlMmQzYmExOTRhZjNlNjMwMjAzMDEwMDAxMzAwZDA2MDkyYTg2NDg4NmY3MGQwMTAxMDUwNTAwMDM4MjAxMDEwMDEzMzA2NjNmMWZjNjhiNjFmZTYwY2JiOWQ4NGZkNWViMjU0ZjliMDUxZmYzODY1ZTUxZjZiMjkzOTFlOGNiNWE4OGUyNjhmNmI5NTI3MTQ3YTIzZTM3YTg2N2JhYWFjMDczNjhjZjA1Mzg0MTI3MWJiOTFlNTE0M2FiMDIzY2ExZmZiY2RhOWYyMmQ2Y2NjZjI2YjQ4MjVkMTEyM2RiZmJkMDI4ZjFlOGViMDc4ZDEyYzkwMGQ3OWEyZmNmYTJiMTliZWY1YzU1ZmNlOTcwMGQ3Yjc1OWRhNThlN2U0OGQwOTJmMTRhZGFkODFjZGE4YTljYjM3NDY5NjFmNzk0NzY5NWU3ZjU3ZWE3Njk3MWUwOTNhMmI5NjdiMzJjZTY1OTE4ZTcxOWYyOWJhMDUxOGI2ZTdhMWFlYzAxZGY4ZDU0YjZiNzU5YmVmNTRkYjYxMjAxMjE3NTcyNmUxOTNmNmVkNTgyZjViYTA2MjMxYzQ5NDM5NmY5NDE3ODgwNWExNWIzM2RhZTg5ZmNiYjc4OTRhMzY0NzdlNjA3YWRmOWU2MGU1NzdjMDBiYzc4ZGQ5OTYyODY2MWU4NmNlZmQwZmQ1ZmRmMzc0Y2NkMjNmZmQwYzBkOTlkNzY1NTMzOGJmZGNjYTE4MTE5ZWYwOTI5ZWJmZTU1NTdmNTEyYTFiOTE4", Base64.DEFAULT)), String(Base64.decode("MzA4MjAyOTAzMDgyMDE3ODAyMDEwMTMwMGQwNjA5MmE4NjQ4ODZmNzBkMDEwMTA1MDUwMDMwMGUzMTBjMzAwYTA2MDM1NTA0MDMwYzAzNzg2NjZiMzAxZTE3MGQzMjMyMzAzNTMxMzEzMDMzMzEzOTMyMzU1YTE3MGQzNDM3MzAzNTMwMzUzMDMzMzEzOTMyMzU1YTMwMGUzMTBjMzAwYTA2MDM1NTA0MDMwYzAzNzg2NjZiMzA4MjAxMjIzMDBkMDYwOTJhODY0ODg2ZjcwZDAxMDEwMTA1MDAwMzgyMDEwZjAwMzA4MjAxMGEwMjgyMDEwMTAwODFmODY5MDljOTQ0YTIzMTNjMmQwZDNkNWM0NjhmN2FkYjk0M2IxMmZiZjUwMmEyNzgwNTQwZDgxODVhOTlmN2Y2NjJlMDA3ZjgwODExZDNiNWFlNzUxNGVkMjYyZDI5ZTMyMzFjYjNmMGFkNTAxZTFiZmEyNWMyOWE2OWE2ZjQ4YTQ1NWVlM2E4NzM5MDcyYzJmMzFkZWU5ZjA0ZTZlZDY1YTVlMDMwODEyYmI5NzE5OTczZTc3OTFmZTQ4MTk3ZWU4OWQ5NjVlMTE4MGRkOTNhZTcyM2EyNzIyNzg4MDgzZWU5MGIwMzNhMzA0MDBkNTI1NWUzMWZmZDJiNDI5MDhhZjE3NTc5M2UyZDk0ZjViODI0ZDY3OTBiZjVmNWQ2MDFlMTg3ODk1MWFlMGY5YmQ5OTJhMjc5MmIyMDcwYzIyYmRkNmNlNmY1ZWU5MmFhYzVmMDEzZjJiYzM2ZjIxMDllYzE1YzE3N2RlYzQwMmNhNmNkNjczZmU5NDUyN2E1OTNiOWE1NTM2ZmNkMjIyNTJmMDFkNmRlZWJmODk2M2U3NDBhMDZiYTNjZjVjM2U2MDRhODRhNjQxYWY1MzhkNjAxZDQ2NjVhNGJlMmJlMWRmYTAxZDc1Y2QyOTZiZjc2YzIwYWM2NTY4MTEyYzQ2NGRjY2Q4MDFlODJhZmM3NmQwMjAzMDEwMDAxMzAwZDA2MDkyYTg2NDg4NmY3MGQwMTAxMDUwNTAwMDM4MjAxMDEwMDUwN2Y1OWNiZDZkNmNmYWQ0OWIxOTZjZDAxY2UyYjA2NTk0ZGZmOTU3OWIyYTkwMWUxODk3YjdkNGMwNWRjYmM4ZWJjYmNhZjA2ZjNlMzViMWI5NTM0MDg2OGE5MTFiOTQ5NzBkYTYyNTE2YmYwN2Q0MmE4NDk1YjNmZDc5NThkNjc4MDMzMmJmYzA2NjM4NTQ5NWM1YmI0NDNmNDE2MzQ5MjdiZTFkMmJkYjMyYzU1ZmRkZmI0NTQ1MDE5OGUzZWU4OWE2MmM3NGI3NzIyYTk0ZjE3ZDZhMmVjZTI5YTI3MmQ1NTU3MmY1OGQ3MmZhNmU0ZDJjNjc3MmFjMTYxMDU4ZjBiZTQ5NWEzNGVmMzZmZjU2NTQ1YWIwMDM0YmJiYjgwY2QwNmY4NzZhNWUzOGExYjc0ZmEyYTYyNGIyNjA1MjUyZjI2NzMwZTAwNWE3YjkwN2ZkZTQ4NzkyZmRhODc5ZDdhMDI3NzY3ZWQyZWI5NzI5MjNkMjJlOGJhZTc5Mjg0OTFlODk5MWFiZDRhNmY1YmM3NmYzZWI3NTM2YmVjNzYzYjcwNmQzNmUwMjkwNDVmN2UyODkxOWU5MmZjN2M0NTk5YWIwOTU5MGQ5ZDM2YjU0MjE4NjZjYTk5MWRhN2E4NDRjOGZhYjZmZmQwOWM1ZDIyMTc5ZjhjODY0Y2Yz", Base64.DEFAULT)))) { + Toast.makeText(context, String(Base64.decode("UGxlYXNlIGRvIG5vdCBtb2RpZnkgdGhpcyBtb2R1bGUhISEgLyDor7fkuI3opoHkv67mlLnmraTmqKHlnZfvvIHvvIHvvIE=", Base64.DEFAULT)), Toast.LENGTH_LONG).show() + exitProcess(0) + } + } + } } \ No newline at end of file diff --git a/build.gradle b/build.gradle index 53b0d6b..cfd36d2 100644 --- a/build.gradle +++ b/build.gradle @@ -3,11 +3,13 @@ buildscript { repositories { google() mavenCentral() + maven { url 'https://jitpack.io' } } dependencies { - classpath "com.android.tools.build:gradle:7.0.4" + classpath "com.android.tools.build:gradle:7.2.0" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21" - + classpath "com.github.CodingGay:BlackObfuscator-ASPlugin:3.7" + classpath "icu.nullptr.stringfuck:gradle-plugin:0.1.4" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c3b8f0e..36d11f1 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Fri Apr 29 17:30:47 CST 2022 +#Sat May 14 18:02:35 CST 2022 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME