This commit is contained in:
HolographicHat 2024-08-12 23:12:11 +08:00
parent 2e52b58f98
commit 40717efbf5
No known key found for this signature in database
GPG Key ID: 12C8B5B85E5CE5C3
7 changed files with 82 additions and 18 deletions

View File

@ -24,6 +24,7 @@ class LoaderActivity : Activity() {
val zActivity = loader.loadClass("hat.holo.token.TokenActivity")
val actIntent = Intent(this, zActivity)
actIntent.putExtra("accountInfo", intent.getSerializableExtra("accountInfo"))
actIntent.putExtra("deviceInfo", intent.getSerializableExtra("deviceInfo"))
startActivityForResult(actIntent, 1234)
}

View File

@ -46,9 +46,10 @@ class ModuleMain : IXposedHookLoadPackage, IXposedHookZygoteInit {
val c0 = loadClass("com.mihoyo.hyperion.app.HyperionApplicationHelper")
findAndHookMethod(c0, "initOnMainProcess", Application::class.java, object : XC_MethodHook() {
override fun afterHookedMethod(p: MethodHookParam) {
AppUtils.init(classLoader)
AccountManager.init(classLoader)
val app = p.args[0] as Application
AppUtils.init(classLoader)
DeviceManager.init(classLoader, app.applicationContext)
AccountManager.init(classLoader)
appendToClassPath(app.applicationContext)
}
})
@ -70,12 +71,14 @@ class ModuleMain : IXposedHookLoadPackage, IXposedHookZygoteInit {
if (isPatch) {
val intent = Intent(ctx, LoaderActivity::class.java)
intent.putExtra("accountInfo", AccountManager.accountInfo)
intent.putExtra("deviceInfo", DeviceManager.deviceInfo)
intent.putExtra("dexPath", modulePath)
ctx.startActivity(intent)
} else {
val intent = Intent()
intent.setClassName("hat.holo.token", "hat.holo.token.TokenActivity")
intent.putExtra("accountInfo", AccountManager.accountInfo)
intent.putExtra("deviceInfo", DeviceManager.deviceInfo)
ctx.startActivity(intent)
}
} else {

View File

@ -31,6 +31,7 @@ import androidx.constraintlayout.compose.ConstraintLayout
import androidx.core.content.getSystemService
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import hat.holo.token.models.AccountInfo
import hat.holo.token.models.DeviceInfo
import kotlinx.coroutines.delay
val textColor = Color(0xFF424242)
@ -44,6 +45,7 @@ class TokenActivity : ComponentActivity() {
super.onCreate(savedInstanceState)
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
setTheme(androidx.appcompat.R.style.Theme_AppCompat_Light_NoActionBar)
val deviceInfo = intent.getSerializableExtra("deviceInfo") as DeviceInfo
val accountInfo = intent.getSerializableExtra("accountInfo") as AccountInfo
setContent {
rememberSystemUiController().setStatusBarColor(Color.White)
@ -53,7 +55,7 @@ class TokenActivity : ComponentActivity() {
),
content = {
Surface {
Content(accountInfo)
Content(deviceInfo, accountInfo)
}
}
)
@ -70,7 +72,7 @@ private fun TokenActivity.showDialog(msg: String) = runOnUiThread {
}
@Composable
private fun TokenActivity.Content(accountInfo: AccountInfo) = Column(
private fun TokenActivity.Content(deviceInfo: DeviceInfo, accountInfo: AccountInfo) = Column(
modifier = Modifier.fillMaxSize()
) {
TopAppBar()
@ -79,6 +81,14 @@ private fun TokenActivity.Content(accountInfo: AccountInfo) = Column(
) {
var grantSToken by remember { mutableStateOf(false) }
var showDoneIcon by remember { mutableStateOf(false) }
CustomCheckBox(
checked = true,
onCheckedChange = {},
name = "DeviceInfo",
permissions = buildAnnotatedString {
appendLine("绕过米游社风控所需的设备ID与指纹")
}
)
CustomCheckBox(
checked = true,
onCheckedChange = {},
@ -116,6 +126,8 @@ private fun TokenActivity.Content(accountInfo: AccountInfo) = Column(
put("mid", accountInfo.mid)
put("stoken", accountInfo.sToken)
}
put("device_id", deviceInfo.id)
put("device_fp", deviceInfo.fingerprint)
}.map { (k, v) -> "$k=$v" }.joinToString(";")
val clip = ClipData.newPlainText(null, authStr)
getSystemService<ClipboardManager>()!!.setPrimaryClip(clip)
@ -133,7 +145,7 @@ private fun TokenActivity.Content(accountInfo: AccountInfo) = Column(
colorFilter = ColorFilter.tint(Color(0xFF4CAF50))
)
}
Text("复制登录信息")
Text("复制到剪贴板")
}
}
LaunchedEffect(showDoneIcon) {

View File

@ -0,0 +1,6 @@
package hat.holo.token.models
data class DeviceInfo(
val id: String,
val fingerprint: String,
) : java.io.Serializable

View File

@ -1,19 +1,13 @@
package hat.holo.token.utils
import java.lang.reflect.Method
object AppUtils {
private lateinit var instance: Any
private val methodTable = arrayListOf<Method>()
private lateinit var inst: Any
fun init(cl: ClassLoader) {
val clz = cl.loadClass("com.mihoyo.hyperion.utils.AppUtils")
instance = clz.getDeclaredField("INSTANCE").get(null)!!
methodTable.add(clz.getDeclaredMethod("showToast", String::class.java))
inst = cl.loadClass("com.mihoyo.hyperion.utils.AppUtils").visitStaticField<Any>("INSTANCE")
}
fun showToast(str: String) {
methodTable[0].invoke(instance, str)
}
fun showToast(str: String) = inst.invokeMethod<String, Unit?>("showToast", str)
}

View File

@ -0,0 +1,31 @@
package hat.holo.token.utils
import android.annotation.SuppressLint
import android.content.Context
import hat.holo.token.models.DeviceInfo
@Suppress("MemberVisibilityCanBePrivate")
@SuppressLint("StaticFieldLeak")
object DeviceManager {
private lateinit var context: Context
private lateinit var riskManager: Any
private lateinit var deviceUtils: Any
fun init(cl: ClassLoader, ctx: Context) {
context = ctx
riskManager = cl
.loadClass("com.mihoyo.platform.account.sdk.risk.RiskManager")
.visitStaticField<Any>("INSTANCE")
deviceUtils = cl
.loadClass("com.mihoyo.platform.account.sdk.utils.DeviceUtils")
.visitStaticField<Any>("INSTANCE")
}
val deviceFp get() = riskManager.invokeMethod<String>("getDeviceFp")
val deviceId get() = deviceUtils.invokeMethod<Context, String>("getDeviceID", context)
val deviceInfo get() = DeviceInfo(deviceId, deviceFp)
}

View File

@ -6,11 +6,22 @@ fun <T : AccessibleObject> T.setAccess() = apply {
isAccessible = true
}
@Suppress("UNCHECKED_CAST")
fun <R> Any.invokeMethod(methodName: String, vararg args: Any?) : R {
inline fun <reified R> Any.invokeMethod(methodName: String) : R {
val method = this.javaClass.getDeclaredMethod(methodName)
method.isAccessible = true
return method.invoke(this, *args) as R
return method.invoke(this) as R
}
inline fun <reified T, reified R> Any.invokeMethod(methodName: String, a1: T) : R {
val method = this.javaClass.getDeclaredMethod(methodName, T::class.java)
method.isAccessible = true
return method.invoke(this, a1) as R
}
inline fun <reified T1, reified T2, reified R> Any.invokeMethod(methodName: String, a1: T1, a2: T2) : R {
val method = this.javaClass.getDeclaredMethod(methodName, T1::class.java, T2::class.java)
method.isAccessible = true
return method.invoke(this, a1, a2) as R
}
inline fun <reified T> Any.visitField(fieldName: String) : T {
@ -19,6 +30,12 @@ inline fun <reified T> Any.visitField(fieldName: String) : T {
return field.get(this) as T
}
inline fun <reified T> Class<*>.visitStaticField(fieldName: String) : T {
val field = getDeclaredField(fieldName)
field.isAccessible = true
return field.get(null) as T
}
inline fun <reified T, reified R> T.visitParentField(fieldName: String) : R {
val field = T::class.java.getDeclaredField(fieldName)
field.isAccessible = true