mirror of
https://github.com/PaiGramTeam/GetToken.git
synced 2024-11-24 16:59:18 +00:00
fix #5
This commit is contained in:
parent
3723f39bd7
commit
2e52b58f98
20989
app/proguard-dict.txt
Normal file
20989
app/proguard-dict.txt
Normal file
File diff suppressed because it is too large
Load Diff
4
app/proguard-rules.pro
vendored
4
app/proguard-rules.pro
vendored
@ -15,6 +15,10 @@
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
|
||||
-obfuscationdictionary proguard-dict.txt
|
||||
-classobfuscationdictionary proguard-dict.txt
|
||||
-packageobfuscationdictionary proguard-dict.txt
|
||||
|
||||
-keep class hat.holo.**{*;}
|
||||
|
||||
-keepattributes SourceFile,LineNumberTable
|
||||
|
@ -6,7 +6,9 @@ import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.util.ArrayMap
|
||||
import dalvik.system.DexClassLoader
|
||||
import hat.holo.token.utils.setAccess
|
||||
import hat.holo.token.utils.visitAndSetField
|
||||
import hat.holo.token.utils.visitField
|
||||
import hat.holo.token.utils.visitParentField
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
class LoaderActivity : Activity() {
|
||||
@ -30,14 +32,10 @@ class LoaderActivity : Activity() {
|
||||
// platform/frameworks/base/+/master/core/java/android/app/ActivityThread.java
|
||||
@SuppressLint("DiscouragedPrivateApi")
|
||||
private fun setClassLoader(classLoader: ClassLoader): ClassLoader {
|
||||
val mainThread = Activity::class.java.getDeclaredField("mMainThread").setAccess().get(this)
|
||||
val apks = mainThread.javaClass.getDeclaredField("mPackages").setAccess().get(mainThread) as ArrayMap<*, *>
|
||||
val apkRef = apks[packageName] as WeakReference<*>
|
||||
val loadedApk = apkRef.get() ?: throw IllegalStateException("WeakRef<LoadedApk> is null!")
|
||||
val fClassLoader = loadedApk.javaClass.getDeclaredField("mClassLoader").setAccess()
|
||||
val oClassLoader = fClassLoader.get(loadedApk)
|
||||
fClassLoader.set(loadedApk, classLoader)
|
||||
return oClassLoader as ClassLoader
|
||||
val actThread = this.visitParentField<Activity, Any>("mMainThread")
|
||||
val pkgs = actThread.visitField<ArrayMap<String, WeakReference<*>>>("mPackages")
|
||||
val pkg = pkgs[packageName]?.get() ?: throw IllegalStateException("WeakRef<LoadedApk> is null!")
|
||||
return pkg.visitAndSetField<ClassLoader>("mClassLoader", classLoader)
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
|
@ -1,84 +0,0 @@
|
||||
package hat.holo.token.utils
|
||||
|
||||
import android.content.Context
|
||||
import de.robv.android.xposed.XC_MethodHook
|
||||
import de.robv.android.xposed.XposedBridge
|
||||
import de.robv.android.xposed.XposedHelpers
|
||||
import java.lang.reflect.Method
|
||||
import kotlin.time.DurationUnit
|
||||
import kotlin.time.ExperimentalTime
|
||||
import kotlin.time.measureTimedValue
|
||||
|
||||
class ConstraintSetWrapper(
|
||||
clazz: Class<*>,
|
||||
private val clone: Method,
|
||||
private val apply: Method,
|
||||
private val connect: Method,
|
||||
private val connectWithMargin: Method
|
||||
) {
|
||||
|
||||
private val instance = clazz.newInstance()
|
||||
|
||||
fun clone(constraintLayout: Any) {
|
||||
clone.invoke(instance, constraintLayout)
|
||||
}
|
||||
|
||||
fun connect(startID: Int, startSide: Int, endID: Int, endSide: Int) {
|
||||
connect.invoke(instance, startID, startSide, endID, endSide)
|
||||
}
|
||||
|
||||
fun connect(startID: Int, startSide: Int, endID: Int, endSide: Int, margin: Int) {
|
||||
connectWithMargin.invoke(instance, startID, startSide, endID, endSide, margin)
|
||||
}
|
||||
|
||||
fun applyTo(constraintLayout: Any) {
|
||||
apply.invoke(instance, constraintLayout)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalTime::class)
|
||||
fun ClassLoader.createConstraintSet(ctx: Context) = measureTimedValue {
|
||||
runCatching {
|
||||
val calledMethods = arrayListOf<Method>()
|
||||
val zRadialViewGroup = loadClass("com.google.android.material.timepicker.RadialViewGroup")
|
||||
val zConstraints = loadClass("androidx.constraintlayout.widget.Constraints")
|
||||
val zConstraintLayout = loadClass("androidx.constraintlayout.widget.ConstraintLayout")
|
||||
val zConstraintSet = zConstraints.getDeclaredMethod("getConstraintSet").returnType
|
||||
val hooks = zConstraintSet.declaredMethods.filter { method ->
|
||||
method.parameterCount == 1 && method.parameterTypes[0] == zConstraintLayout
|
||||
}.map { method ->
|
||||
XposedHelpers.findAndHookMethod(
|
||||
zConstraintSet,
|
||||
method.name,
|
||||
zConstraintLayout,
|
||||
object : XC_MethodHook() {
|
||||
override fun afterHookedMethod(param: MethodHookParam) {
|
||||
calledMethods += param.method as Method
|
||||
}
|
||||
})
|
||||
}
|
||||
val oRadialViewGroup = zRadialViewGroup.getDeclaredConstructor(Context::class.java).apply {
|
||||
isAccessible = true
|
||||
}.newInstance(ctx)
|
||||
zRadialViewGroup.getDeclaredMethod("updateLayoutParams").invoke(oRadialViewGroup)
|
||||
hooks.forEach { hook -> hook.unhook() }
|
||||
if (calledMethods.size == 2) {
|
||||
ConstraintSetWrapper(
|
||||
clazz = zConstraintSet,
|
||||
clone = calledMethods[0],
|
||||
apply = calledMethods[1],
|
||||
connect = zConstraintSet.declaredMethods.first { method ->
|
||||
method.parameterCount == 4 && method.parameterTypes.all { p -> p == Int::class.java }
|
||||
},
|
||||
connectWithMargin = zConstraintSet.declaredMethods.first { method ->
|
||||
method.parameterCount == 5 && method.parameterTypes.all { p -> p == Int::class.java }
|
||||
}
|
||||
)
|
||||
} else null
|
||||
}.onFailure { ex ->
|
||||
XposedBridge.log(ex)
|
||||
}.getOrNull()
|
||||
}.let { (result, duration) ->
|
||||
XposedBridge.log("createConstraintSet cost ${duration.toString(DurationUnit.MILLISECONDS, 2)}")
|
||||
result
|
||||
}
|
@ -13,9 +13,22 @@ fun <R> Any.invokeMethod(methodName: String, vararg args: Any?) : R {
|
||||
return method.invoke(this, *args) as R
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T> Any.visitField(fieldName: String) : T {
|
||||
inline fun <reified T> Any.visitField(fieldName: String) : T {
|
||||
val field = this.javaClass.getDeclaredField(fieldName)
|
||||
field.isAccessible = true
|
||||
return field.get(this) as T
|
||||
}
|
||||
|
||||
inline fun <reified T, reified R> T.visitParentField(fieldName: String) : R {
|
||||
val field = T::class.java.getDeclaredField(fieldName)
|
||||
field.isAccessible = true
|
||||
return field.get(this) as R
|
||||
}
|
||||
|
||||
inline fun <reified T> Any.visitAndSetField(fieldName: String, value: Any) : T {
|
||||
val field = this.javaClass.getDeclaredField(fieldName)
|
||||
field.isAccessible = true
|
||||
val old = field.get(this) as T
|
||||
field.set(this, value)
|
||||
return old
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user