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 zActivity = loader.loadClass("hat.holo.token.TokenActivity")
val actIntent = Intent(this, zActivity) val actIntent = Intent(this, zActivity)
actIntent.putExtra("accountInfo", intent.getSerializableExtra("accountInfo")) actIntent.putExtra("accountInfo", intent.getSerializableExtra("accountInfo"))
actIntent.putExtra("deviceInfo", intent.getSerializableExtra("deviceInfo"))
startActivityForResult(actIntent, 1234) startActivityForResult(actIntent, 1234)
} }

View File

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

View File

@ -31,6 +31,7 @@ import androidx.constraintlayout.compose.ConstraintLayout
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import com.google.accompanist.systemuicontroller.rememberSystemUiController import com.google.accompanist.systemuicontroller.rememberSystemUiController
import hat.holo.token.models.AccountInfo import hat.holo.token.models.AccountInfo
import hat.holo.token.models.DeviceInfo
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
val textColor = Color(0xFF424242) val textColor = Color(0xFF424242)
@ -44,6 +45,7 @@ class TokenActivity : ComponentActivity() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
setTheme(androidx.appcompat.R.style.Theme_AppCompat_Light_NoActionBar) setTheme(androidx.appcompat.R.style.Theme_AppCompat_Light_NoActionBar)
val deviceInfo = intent.getSerializableExtra("deviceInfo") as DeviceInfo
val accountInfo = intent.getSerializableExtra("accountInfo") as AccountInfo val accountInfo = intent.getSerializableExtra("accountInfo") as AccountInfo
setContent { setContent {
rememberSystemUiController().setStatusBarColor(Color.White) rememberSystemUiController().setStatusBarColor(Color.White)
@ -53,7 +55,7 @@ class TokenActivity : ComponentActivity() {
), ),
content = { content = {
Surface { Surface {
Content(accountInfo) Content(deviceInfo, accountInfo)
} }
} }
) )
@ -70,7 +72,7 @@ private fun TokenActivity.showDialog(msg: String) = runOnUiThread {
} }
@Composable @Composable
private fun TokenActivity.Content(accountInfo: AccountInfo) = Column( private fun TokenActivity.Content(deviceInfo: DeviceInfo, accountInfo: AccountInfo) = Column(
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize()
) { ) {
TopAppBar() TopAppBar()
@ -79,6 +81,14 @@ private fun TokenActivity.Content(accountInfo: AccountInfo) = Column(
) { ) {
var grantSToken by remember { mutableStateOf(false) } var grantSToken by remember { mutableStateOf(false) }
var showDoneIcon by remember { mutableStateOf(false) } var showDoneIcon by remember { mutableStateOf(false) }
CustomCheckBox(
checked = true,
onCheckedChange = {},
name = "DeviceInfo",
permissions = buildAnnotatedString {
appendLine("绕过米游社风控所需的设备ID与指纹")
}
)
CustomCheckBox( CustomCheckBox(
checked = true, checked = true,
onCheckedChange = {}, onCheckedChange = {},
@ -116,6 +126,8 @@ private fun TokenActivity.Content(accountInfo: AccountInfo) = Column(
put("mid", accountInfo.mid) put("mid", accountInfo.mid)
put("stoken", accountInfo.sToken) put("stoken", accountInfo.sToken)
} }
put("device_id", deviceInfo.id)
put("device_fp", deviceInfo.fingerprint)
}.map { (k, v) -> "$k=$v" }.joinToString(";") }.map { (k, v) -> "$k=$v" }.joinToString(";")
val clip = ClipData.newPlainText(null, authStr) val clip = ClipData.newPlainText(null, authStr)
getSystemService<ClipboardManager>()!!.setPrimaryClip(clip) getSystemService<ClipboardManager>()!!.setPrimaryClip(clip)
@ -133,7 +145,7 @@ private fun TokenActivity.Content(accountInfo: AccountInfo) = Column(
colorFilter = ColorFilter.tint(Color(0xFF4CAF50)) colorFilter = ColorFilter.tint(Color(0xFF4CAF50))
) )
} }
Text("复制登录信息") Text("复制到剪贴板")
} }
} }
LaunchedEffect(showDoneIcon) { 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 package hat.holo.token.utils
import java.lang.reflect.Method
object AppUtils { object AppUtils {
private lateinit var instance: Any private lateinit var inst: Any
private val methodTable = arrayListOf<Method>()
fun init(cl: ClassLoader) { fun init(cl: ClassLoader) {
val clz = cl.loadClass("com.mihoyo.hyperion.utils.AppUtils") inst = cl.loadClass("com.mihoyo.hyperion.utils.AppUtils").visitStaticField<Any>("INSTANCE")
instance = clz.getDeclaredField("INSTANCE").get(null)!!
methodTable.add(clz.getDeclaredMethod("showToast", String::class.java))
} }
fun showToast(str: String) { fun showToast(str: String) = inst.invokeMethod<String, Unit?>("showToast", str)
methodTable[0].invoke(instance, 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 isAccessible = true
} }
@Suppress("UNCHECKED_CAST") inline fun <reified R> Any.invokeMethod(methodName: String) : R {
fun <R> Any.invokeMethod(methodName: String, vararg args: Any?) : R {
val method = this.javaClass.getDeclaredMethod(methodName) val method = this.javaClass.getDeclaredMethod(methodName)
method.isAccessible = true 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 { 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 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 { inline fun <reified T, reified R> T.visitParentField(fieldName: String) : R {
val field = T::class.java.getDeclaredField(fieldName) val field = T::class.java.getDeclaredField(fieldName)
field.isAccessible = true field.isAccessible = true