Skip to content

Commit e6b6b6d

Browse files
committed
migrate to libxposed API 101
1 parent 258891d commit e6b6b6d

19 files changed

Lines changed: 1202 additions & 160 deletions

File tree

app/build.gradle.kts

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
1+
import com.android.build.api.instrumentation.AsmClassVisitorFactory
2+
import com.android.build.api.instrumentation.ClassContext
3+
import com.android.build.api.instrumentation.ClassData
4+
import com.android.build.api.instrumentation.InstrumentationParameters
5+
import com.android.build.api.instrumentation.InstrumentationScope
16
import com.android.build.gradle.tasks.PackageAndroidArtifact
27
import com.google.protobuf.gradle.id
8+
import org.objectweb.asm.ClassVisitor
9+
import org.objectweb.asm.commons.ClassRemapper
10+
import org.objectweb.asm.commons.Remapper
311
import java.io.FileInputStream
412
import java.nio.charset.StandardCharsets
513
import java.util.Properties
@@ -95,6 +103,7 @@ android {
95103
namespace = "io.github.a13e300.myinjector"
96104
packaging {
97105
resources {
106+
merges += "META-INF/xposed/*"
98107
excludes += "**"
99108
}
100109
}
@@ -127,12 +136,39 @@ protobuf {
127136
}
128137
}
129138

139+
abstract class ClassVisitorFactory : AsmClassVisitorFactory<InstrumentationParameters.None> {
140+
override fun createClassVisitor(
141+
classContext: ClassContext,
142+
nextClassVisitor: ClassVisitor
143+
): ClassVisitor {
144+
return ClassRemapper(nextClassVisitor, object : Remapper() {
145+
override fun map(name: String): String {
146+
if (name.startsWith("hidden/")) {
147+
return name.substring(name.indexOf('/') + 1)
148+
}
149+
return name
150+
}
151+
})
152+
}
153+
154+
override fun isInstrumentable(classData: ClassData): Boolean {
155+
return true
156+
}
157+
}
158+
159+
androidComponents.onVariants { variant ->
160+
variant.instrumentation.transformClassesWith(
161+
ClassVisitorFactory::class.java, InstrumentationScope.PROJECT
162+
) {}
163+
}
164+
130165
dependencies {
131-
compileOnly(libs.xposed.api)
132166
implementation(libs.dexkit)
133167
compileOnly(libs.androidx.annotation)
134168
compileOnly(project(":hidden-api"))
135169
implementation(libs.protobuf.kotlin)
136170
implementation(libs.protobuf.java)
137171
compileOnly(libs.protobuf.protoc)
172+
compileOnly(libs.libxposed.api)
173+
// implementation(libs.libxposed.service)
138174
}

app/src/main/AndroidManifest.xml

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,6 @@
3333
<category android:name="de.robv.android.xposed.category.MODULE_SETTINGS" />
3434
</intent-filter>
3535
</activity>
36-
37-
<meta-data
38-
android:name="xposedmodule"
39-
android:value="true" />
40-
<meta-data
41-
android:name="xposeddescription"
42-
android:value="test" />
43-
<meta-data
44-
android:name="xposedminversion"
45-
android:value="82" />
46-
<meta-data
47-
android:name="xposedscope"
48-
android:resource="@array/xposed_scope" />
4936
</application>
5037

5138
</manifest>

app/src/main/assets/xposed_init

Lines changed: 0 additions & 1 deletion
This file was deleted.

app/src/main/java/io/github/a13e300/myinjector/Entry.kt

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,33 @@
11
package io.github.a13e300.myinjector
22

3-
import android.content.res.XModuleResources
4-
import de.robv.android.xposed.IXposedHookLoadPackage
5-
import de.robv.android.xposed.IXposedHookZygoteInit
6-
import de.robv.android.xposed.callbacks.XC_LoadPackage
3+
import android.content.res.Resources
4+
import io.github.a13e300.myinjector.arch.newModuleResource
75
import io.github.a13e300.myinjector.bridge.LoadPackageParam
86
import io.github.a13e300.myinjector.system_server.SystemServerHookLoader
97
import io.github.a13e300.myinjector.telegram.TelegramHandler
8+
import io.github.libxposed.api.XposedModule
9+
import io.github.libxposed.api.XposedModuleInterface
1010

11-
class Entry : IXposedHookLoadPackage, IXposedHookZygoteInit {
11+
class Entry : XposedModule() {
1212
companion object {
1313
lateinit var modulePath: String
14-
val moduleRes: XModuleResources by lazy {
15-
XModuleResources.createInstance(
16-
modulePath,
17-
null
18-
)
14+
val moduleRes: Resources by lazy {
15+
newModuleResource(modulePath)
1916
}
17+
lateinit var instance: Entry
2018
}
2119

22-
override fun initZygote(startupParam: IXposedHookZygoteInit.StartupParam) {
23-
modulePath = startupParam.modulePath
20+
private lateinit var processName: String
21+
22+
override fun onModuleLoaded(param: XposedModuleInterface.ModuleLoadedParam) {
23+
instance = this
24+
modulePath = moduleApplicationInfo.sourceDir
25+
processName = param.processName
2426
}
2527

26-
override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) {
27-
logI("MyInjector: ${lpparam.packageName} ${lpparam.processName}")
28-
val handler = when (lpparam.packageName) {
28+
override fun onPackageReady(param: XposedModuleInterface.PackageReadyParam) {
29+
logI("MyInjector: ${param.packageName} ${processName}")
30+
val handler = when (param.packageName) {
2931
"com.fooview.android.fooview" -> FvXposedHandler()
3032
"com.lbe.security.miui" -> LbeHandler()
3133
"com.miui.securitycenter" -> MIUISecurityCenterHandler()
@@ -49,10 +51,6 @@ class Entry : IXposedHookLoadPackage, IXposedHookZygoteInit {
4951
"com.android.chrome", "com.kiwibrowser.browser" -> ChromeHandler
5052
"com.baidu.input" -> BaiduIMEHandler()
5153
"com.miui.home" -> MiuiHomeHandler()
52-
"android" -> {
53-
if (lpparam.processName == "android") SystemServerHookLoader
54-
else return
55-
}
5654
"com.android.settings" -> SettingsHandler()
5755
"app.landrop.landrop_flutter" -> LanDropHandler()
5856
"com.android.intentresolver" -> IntentResolverHandler()
@@ -66,6 +64,27 @@ class Entry : IXposedHookLoadPackage, IXposedHookZygoteInit {
6664
else -> return
6765
}
6866
logPrefix = "[${handler.javaClass.simpleName}] "
69-
handler.hook(LoadPackageParam(lpparam))
67+
handler.hook(
68+
LoadPackageParam(
69+
param.packageName,
70+
processName,
71+
param.classLoader,
72+
param.applicationInfo,
73+
param.isFirstPackage
74+
)
75+
)
76+
}
77+
78+
override fun onSystemServerStarting(param: XposedModuleInterface.SystemServerStartingParam) {
79+
logPrefix = "[${SystemServerHookLoader.javaClass.simpleName}] "
80+
SystemServerHookLoader.hook(
81+
LoadPackageParam(
82+
"android",
83+
"android",
84+
param.classLoader,
85+
null,
86+
true
87+
)
88+
)
7089
}
7190
}

app/src/main/java/io/github/a13e300/myinjector/XhsHandler.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package io.github.a13e300.myinjector
33
import android.annotation.SuppressLint
44
import android.app.Activity
55
import android.app.AlertDialog
6-
import android.app.AndroidAppHelper
76
import android.content.ClipData
87
import android.content.ClipboardManager
98
import android.content.Context
@@ -39,6 +38,7 @@ import io.github.a13e300.myinjector.arch.IHook
3938
import io.github.a13e300.myinjector.arch.ObfsTableCreator
4039
import io.github.a13e300.myinjector.arch.call
4140
import io.github.a13e300.myinjector.arch.callS
41+
import io.github.a13e300.myinjector.arch.currentApplication
4242
import io.github.a13e300.myinjector.arch.dp2px
4343
import io.github.a13e300.myinjector.arch.extraField
4444
import io.github.a13e300.myinjector.arch.findBaseActivity
@@ -528,7 +528,7 @@ class BetterShare : MyDynHook("betterShare") {
528528
else text += "\n" + newUri
529529
// logD("html=$html")
530530

531-
AndroidAppHelper.currentApplication()
531+
currentApplication()
532532
.getSystemService(ClipboardManager::class.java)
533533
.setPrimaryClip(ClipData.newHtmlText("", text, html))
534534

app/src/main/java/io/github/a13e300/myinjector/arch/Utils.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package io.github.a13e300.myinjector.arch
22

33
import android.app.Activity
4+
import android.app.ActivityThread
5+
import android.app.Application
46
import android.content.Context
57
import android.content.ContextWrapper
68
import android.content.Intent
@@ -95,3 +97,13 @@ fun ViewGroup.containsClass(clazz: Class<*>): Boolean {
9597
}
9698
return false
9799
}
100+
101+
fun currentApplication(): Application =
102+
ActivityThread.currentActivityThread().application
103+
104+
@Suppress("DEPRECATION")
105+
fun newModuleResource(path: String): Resources {
106+
val assetManager = hidden.android.content.res.AssetManager()
107+
assetManager.addAssetPath(path)
108+
return Resources(assetManager as AssetManager, null, null)
109+
}

app/src/main/java/io/github/a13e300/myinjector/bridge/HookParam.java

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,52 +2,58 @@
22

33
import java.lang.reflect.Member;
44

5-
import de.robv.android.xposed.XC_MethodHook;
6-
75
public class HookParam {
8-
final XC_MethodHook.MethodHookParam methodHookParam;
6+
Object[] args;
7+
Object thisObject;
8+
Member member;
9+
Object result;
10+
Throwable throwable;
11+
boolean invoked = false;
912

10-
public HookParam(XC_MethodHook.MethodHookParam param) {
11-
methodHookParam = param;
13+
public HookParam() {
1214
}
1315

1416
public Member getMethod() {
15-
return methodHookParam.method;
17+
return member;
1618
}
1719

1820
public void setMethod(Member m) {
19-
methodHookParam.method = m;
21+
member = m;
2022
}
2123

2224
public Object getThisObject() {
23-
return methodHookParam.thisObject;
25+
return thisObject;
2426
}
2527

2628
public void setThisObject(Object t) {
27-
methodHookParam.thisObject = t;
29+
thisObject = t;
2830
}
2931

3032
public Object[] getArgs() {
31-
return methodHookParam.args;
33+
return args;
3234
}
3335

3436
public void setArgs(Object[] a) {
35-
methodHookParam.args = a;
37+
args = a;
3638
}
3739

3840
public Object getResult() {
39-
return methodHookParam.getResult();
41+
return result;
4042
}
4143

4244
public void setResult(Object r) {
43-
methodHookParam.setResult(r);
45+
result = r;
46+
throwable = null;
47+
invoked = true;
4448
}
4549

4650
public Throwable getThrowable() {
47-
return methodHookParam.getThrowable();
51+
return throwable;
4852
}
4953

5054
public void setThrowable(Throwable t) {
51-
methodHookParam.setThrowable(t);
55+
throwable = t;
56+
result = null;
57+
invoked = true;
5258
}
5359
}

app/src/main/java/io/github/a13e300/myinjector/bridge/LoadPackageParam.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ public class LoadPackageParam {
88
public final ClassLoader classLoader;
99
public final ApplicationInfo appInfo;
1010
public final boolean isFirstApplication;
11-
public LoadPackageParam(de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam p) {
12-
packageName = p.packageName;
13-
processName = p.processName;
14-
classLoader = p.classLoader;
15-
appInfo = p.appInfo;
16-
isFirstApplication = p.isFirstApplication;
11+
12+
public LoadPackageParam(String packageName, String processName, ClassLoader classLoader, ApplicationInfo info, boolean isFirst) {
13+
this.packageName = packageName;
14+
this.processName = processName;
15+
this.classLoader = classLoader;
16+
appInfo = info;
17+
isFirstApplication = isFirst;
1718
}
1819
}

app/src/main/java/io/github/a13e300/myinjector/bridge/MethodHookCallback.java

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,43 @@
22

33
import androidx.annotation.NonNull;
44

5-
import de.robv.android.xposed.XC_MethodHook;
5+
import java.lang.reflect.Modifier;
66

7-
public abstract class MethodHookCallback extends XC_MethodHook {
8-
@Override
9-
protected final void beforeHookedMethod(MethodHookParam param) {
10-
beforeHook(new HookParam(param));
11-
}
7+
import io.github.a13e300.myinjector.LogKt;
8+
import io.github.libxposed.api.XposedInterface;
129

10+
public abstract class MethodHookCallback implements XposedInterface.Hooker {
1311
@Override
14-
protected final void afterHookedMethod(MethodHookParam param) {
15-
afterHook(new HookParam(param));
12+
public Object intercept(@NonNull XposedInterface.Chain chain) throws Throwable {
13+
var param = new HookParam();
14+
param.args = chain.getArgs().toArray(new Object[0]);
15+
param.thisObject = chain.getThisObject();
16+
param.member = chain.getExecutable();
17+
try {
18+
beforeHook(param);
19+
} catch (Throwable t) {
20+
LogKt.logE("beforeHook: ", t);
21+
}
22+
if (!param.invoked) {
23+
try {
24+
if ((param.member.getModifiers() & Modifier.STATIC) != 0) {
25+
param.result = chain.proceed(param.args);
26+
} else {
27+
param.result = chain.proceedWith(param.thisObject, param.args);
28+
}
29+
} catch (Throwable t) {
30+
param.throwable = t;
31+
}
32+
}
33+
try {
34+
afterHook(param);
35+
} catch (Throwable t) {
36+
LogKt.logE("afterHook: ", t);
37+
}
38+
if (param.throwable != null) {
39+
throw param.throwable;
40+
}
41+
return param.result;
1642
}
1743

1844
protected void beforeHook(@NonNull HookParam param) {

app/src/main/java/io/github/a13e300/myinjector/bridge/Unhook.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package io.github.a13e300.myinjector.bridge
22

3-
import de.robv.android.xposed.XC_MethodHook
3+
import io.github.libxposed.api.XposedInterface
44
import java.lang.reflect.Member
55

6-
class Unhook(private val inner: XC_MethodHook.Unhook) {
6+
class Unhook(private val inner: XposedInterface.HookHandle) {
77
val hookedMethod: Member
8-
get() = inner.hookedMethod
8+
get() = inner.executable
99

1010
fun unhook() {
1111
inner.unhook()

0 commit comments

Comments
 (0)