Skip to content

Commit

Permalink
use dexkit
Browse files Browse the repository at this point in the history
  • Loading branch information
5ec1cff committed Jun 6, 2024
1 parent 302b200 commit f7912cd
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 12 deletions.
4 changes: 4 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ android {
targetSdk = 33
versionCode = 1
versionName = "1.0"
ndk {
abiFilters += "arm64-v8a"
}
}
buildFeatures {
buildConfig = true
Expand Down Expand Up @@ -41,5 +44,6 @@ dependencies {
implementation(libs.constraintlayout)
compileOnly(libs.xposed.api)
implementation(libs.ezxhelper)
implementation(libs.dexkit)
compileOnly(project(":hidden-api"))
}
88 changes: 76 additions & 12 deletions app/src/main/java/five/ec1cff/myinjector/ZhihuXposedHandler.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,36 +7,99 @@ import de.robv.android.xposed.IXposedHookLoadPackage
import de.robv.android.xposed.XC_MethodHook
import de.robv.android.xposed.XposedBridge
import de.robv.android.xposed.XposedHelpers
import de.robv.android.xposed.callbacks.XC_LoadPackage
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam
import org.luckypray.dexkit.DexKitBridge
import org.luckypray.dexkit.query.matchers.ClassMatcher
import java.io.File

class ZhihuXposedHandler : IXposedHookLoadPackage {
companion object {
private const val TAG = "MyInjector-zhihu"
}

override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) {
// Zhihu 10.2.0 (20214) sha256=0774c8c812232dd1d1c0a75e32f791f7171686a8c68ce280c6b3d9b82cdde5eb
// class f$r implements com.zhihu.android.app.feed.ui2.feed.a.a<FeedList>
// io.reactivex.subjects.ReplaySubject b
// public void a(com.zhihu.android.api.model.FeedList)
// use strings: "FeedRepository" "use cache"
private var localSourceClass = "com.zhihu.android.app.feed.ui2.feed.a.f\$r"
private var localSourceMethod = "a"
private var localSourceField = "b"

private var cacheFile: File? = null

private fun prepare(lpparam: LoadPackageParam) = kotlin.runCatching {
val f = File(lpparam.appInfo.dataDir, "dexkit.tmp")
cacheFile = f
if (f.isFile) {
try {
val lines = f.inputStream().use { f.readLines() }
val apkPath = lines[0]
if (apkPath == lpparam.appInfo.sourceDir) {
localSourceClass = lines[1]
localSourceMethod = lines[2]
localSourceField = lines[3]
Log.d(TAG, "prepare: use cached result")
return@runCatching
} else {
Log.d(TAG, "prepare: need invalidate cache!")
f.delete()
}
} catch (t: Throwable) {
Log.e(TAG, "prepare: failed to read", t)
f.delete()
}
}
Log.d(TAG, "prepare: start deobf")
System.loadLibrary("dexkit")
val bridge = DexKitBridge.create(lpparam.classLoader, true)
val method = bridge.findMethod {
searchPackages("com.zhihu.android.app.feed.ui2.feed")
matcher {
usingStrings("FeedRepository", "use cache")
}
}[0]
Log.d(TAG, "prepare: found method: $method")
val field = method.declaredClass!!.findField {
matcher {
type(ClassMatcher().className("io.reactivex.subjects.ReplaySubject"))
}
}[0]
Log.d(TAG, "prepare: found field: $field")
localSourceClass = method.className
localSourceMethod = method.methodName
localSourceField = field.fieldName
f.bufferedWriter().use {
it.write("${lpparam.appInfo.sourceDir}\n")
it.write("$localSourceClass\n")
it.write("$localSourceMethod\n")
it.write("$localSourceField\n")
}
}.onFailure {
Log.e(TAG, "prepare: failed", it)
}

override fun handleLoadPackage(lpparam: LoadPackageParam) {
if (lpparam.packageName != "com.zhihu.android") return
prepare(lpparam)
hookDisableFeedAutoRefresh(lpparam)
hookClipboard()
}

private fun hookDisableFeedAutoRefresh(lpparam: XC_LoadPackage.LoadPackageParam) =
private fun hookDisableFeedAutoRefresh(lpparam: LoadPackageParam) =
kotlin.runCatching {
// TODO: use dexkit
// Zhihu 10.2.0 (20214) sha256=0774c8c812232dd1d1c0a75e32f791f7171686a8c68ce280c6b3d9b82cdde5eb
// class f$r implements com.zhihu.android.app.feed.ui2.feed.a.a<FeedList>
// io.reactivex.subjects.ReplaySubject b
// public void a(com.zhihu.android.api.model.FeedList)
// use strings: "FeedRepository" "use cache"
XposedBridge.hookAllMethods(
XposedHelpers.findClass(
"com.zhihu.android.app.feed.ui2.feed.a.f\$r",
localSourceClass,
lpparam.classLoader
),
"a",
localSourceMethod,
object : XC_MethodHook() {
override fun afterHookedMethod(param: MethodHookParam) {
val b = XposedHelpers.getObjectField(param.thisObject, "b") // ReplaySubject
val b = XposedHelpers.getObjectField(
param.thisObject,
localSourceField
) // ReplaySubject
XposedHelpers.callMethod(
b,
"onComplete"
Expand All @@ -46,6 +109,7 @@ class ZhihuXposedHandler : IXposedHookLoadPackage {
)
}.onFailure {
Log.e(TAG, "hookDisableAutoRefresh: failed", it)
cacheFile?.delete()
}

private fun hookClipboard() = kotlin.runCatching {
Expand Down
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[versions]
dexkit = "2.0.1"
ezxhelper = "1.0.3"
kotlin = "1.9.0"
agp = "8.1.3"
Expand All @@ -8,6 +9,7 @@ material = "1.9.0"
constraintlayout = "2.1.4"

[libraries]
dexkit = { module = "org.luckypray:dexkit", version.ref = "dexkit" }
ezxhelper = { module = "com.github.kyuubiran:EzXHelper", version.ref = "ezxhelper" }
xposed-api = { module = "de.robv.android.xposed:api", version.ref = "xposed" }
appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
Expand Down

0 comments on commit f7912cd

Please sign in to comment.