Skip to content

Commit 0378757

Browse files
committed
improve ClassHunter
1 parent 614af47 commit 0378757

File tree

2 files changed

+87
-10
lines changed

2 files changed

+87
-10
lines changed

ClassHunter/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ android {
1414
if (!file.exists()) {
1515
file.createNewFile()
1616
}
17-
val classes = file.readLines().filterNot { it.startsWith("#") }
17+
val classes = file.readLines().filterNot { it.startsWith("#") || it.isBlank() }
1818
buildConfigField("String[]", "targetClass", classes.joinToString("\", \"", "{\"", "\"}"))
1919
versionNameSuffix = classes.joinToString(", ", " (", ")")
2020
}

ClassHunter/src/main/java/de/binarynoise/classHunter/Hook.kt

Lines changed: 86 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
11
package de.binarynoise.classHunter
22

3+
import java.security.SecureClassLoader
4+
import android.os.Build
35
import android.util.Log
6+
import dalvik.system.BaseDexClassLoader
7+
import dalvik.system.DelegateLastClassLoader
8+
import dalvik.system.PathClassLoader
49
import de.binarynoise.ClassHunter.BuildConfig
510
import de.robv.android.xposed.IXposedHookLoadPackage
11+
import de.robv.android.xposed.IXposedHookZygoteInit
12+
import de.robv.android.xposed.XposedBridge
613
import de.robv.android.xposed.callbacks.XC_LoadPackage
14+
import de.robv.android.xposed.XC_MethodHook as MethodHook
715

816
const val TAG = "Hook"
917

10-
class Hook : IXposedHookLoadPackage {
18+
class Hook : IXposedHookLoadPackage, IXposedHookZygoteInit {
1119
override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) {
1220
Log.i(TAG, "*".repeat(50))
1321
Log.i(TAG, "loading package: ${lpparam.packageName}")
@@ -34,16 +42,25 @@ class Hook : IXposedHookLoadPackage {
3442
BuildConfig.targetClass.forEach { className ->
3543
try {
3644
val cls = Class.forName(className, false, it)
37-
Log.i(TAG, " - found class: ${cls.name} in package ${lpparam.packageName} by $it")
45+
Log.i(TAG, " - found class: ${cls.name} in package ${lpparam.packageName} by ${it.toObjectString()}")
46+
47+
Log.i(TAG, " - constructors:")
48+
cls.declaredConstructors.map { c -> "${c.name}(${c.parameters.joinToString(", ") { p -> p.name + " " + p.type.name }})" }
49+
.sorted()
50+
.forEach { c ->
51+
Log.v(TAG, " - $it")
52+
}
3853

3954
Log.i(TAG, " - methods:")
40-
cls.declaredMethods.forEach { m ->
41-
Log.v(TAG, " - ${m.returnType.name} ${m.name}(${m.parameters.joinToString(", ") { p -> p.name + " " + p.type.name }})")
42-
}
55+
cls.declaredMethods.map { m -> "${m.returnType.name} ${m.name}(${m.parameters.joinToString(", ") { p -> p.name + " " + p.type.name }})" }
56+
.sorted()
57+
.forEach { m ->
58+
Log.v(TAG, " - $it")
59+
}
4360

4461
Log.i(TAG, " - fields:")
45-
cls.declaredFields.forEach { f ->
46-
Log.v(TAG, " - ${f.type.name} ${f.name}")
62+
cls.declaredFields.map { f -> "${f.type.name} ${f.name}" }.sorted().forEach { f ->
63+
Log.v(TAG, " - $it")
4764
}
4865
} catch (_: Throwable) {
4966
}
@@ -52,9 +69,69 @@ class Hook : IXposedHookLoadPackage {
5269
}
5370

5471
private fun collectParents(classLoader: ClassLoader, name: String, classLoaders: MutableSet<ClassLoader>) {
55-
generateSequence(classLoader) { it.parent }.forEach {
72+
classLoaders.addAll(generateSequence(classLoader) { it.parent }.onEach {
5673
Log.v(TAG, name + " - ${it.toObjectString()}")
57-
classLoaders.add(it)
74+
})
75+
}
76+
77+
override fun initZygote(startupParam: IXposedHookZygoteInit.StartupParam) {
78+
val classLoaderClasses = mutableSetOf<Class<*>>(
79+
ClassLoader::class.java,
80+
SecureClassLoader::class.java,
81+
// URLClassLoader::class.java,
82+
BaseDexClassLoader::class.java,
83+
// PathClassLoader::class.java,
84+
// InMemoryDexClassLoader::class.java,
85+
// DexClassLoader::class.java,
86+
ClassLoader.getSystemClassLoader()::class.java, // BootClassLoader
87+
)
88+
89+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
90+
classLoaderClasses.add(DelegateLastClassLoader::class.java)
91+
}
92+
93+
try {
94+
classLoaderClasses.add(Class.forName("android.app.LoadedApk\$WarningContextClassLoader", false, null))
95+
} catch (_: Throwable) {
96+
}
97+
98+
val targetClassesShortName = BuildConfig.targetClass.map { it.substringAfterLast(".") }.toSet()
99+
100+
classLoaderClasses.forEach {
101+
val loadClassHook = object : MethodHook() {
102+
override fun afterHookedMethod(param: MethodHookParam) {
103+
val cls = param.result as? Class<*> ?: return
104+
105+
if (cls.name.substringAfterLast(".") in targetClassesShortName) {
106+
Log.i(TAG, "Maybe found class: ${cls.name} by ${param.thisObject.toObjectString()}")
107+
}
108+
}
109+
}
110+
var loadNewClassloaderHook: MethodHook? = null
111+
loadNewClassloaderHook = object : MethodHook() {
112+
override fun afterHookedMethod(param: MethodHookParam) {
113+
if (param.thisObject !is PathClassLoader) {
114+
Log.v(TAG, "Created a new ClassLoader: ${param.thisObject.toObjectString()} ${param.thisObject}")
115+
}
116+
117+
val cls: Class<*> = param.thisObject::class.java
118+
if (cls !in classLoaderClasses) {
119+
Log.i(TAG, "Found a new ClassLoader class: ${cls}, created by ${cls.classLoader}")
120+
}
121+
try {
122+
123+
XposedBridge.hookAllConstructors(it, loadNewClassloaderHook)
124+
XposedBridge.hookAllMethods(it, "loadClass", loadClassHook)
125+
} catch (_: Throwable) {
126+
}
127+
}
128+
}
129+
130+
try {
131+
XposedBridge.hookAllConstructors(it, loadNewClassloaderHook)
132+
XposedBridge.hookAllMethods(it, "loadClass", loadClassHook)
133+
} catch (_: Throwable) {
134+
}
58135
}
59136
}
60137
}

0 commit comments

Comments
 (0)