Skip to content

Commit

Permalink
use java 21
Browse files Browse the repository at this point in the history
  • Loading branch information
vvb2060 committed Feb 9, 2025
1 parent 0df64f2 commit cd3dc4c
Show file tree
Hide file tree
Showing 10 changed files with 219 additions and 159 deletions.
38 changes: 36 additions & 2 deletions library/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import com.android.build.api.artifact.SingleArtifact
import com.android.build.api.instrumentation.AsmClassVisitorFactory
import com.android.build.api.instrumentation.ClassContext
import com.android.build.api.instrumentation.ClassData
import com.android.build.api.instrumentation.InstrumentationParameters
import com.android.build.api.instrumentation.InstrumentationScope
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.commons.ClassRemapper
import org.objectweb.asm.commons.Remapper

plugins {
alias(libs.plugins.agp.lib)
Expand Down Expand Up @@ -30,8 +38,8 @@ android {
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
packaging {
resources {
Expand All @@ -55,6 +63,32 @@ dependencies {
androidTestCompileOnly(projects.stub)
}

androidComponents.onVariants { variant ->
variant.instrumentation.transformClassesWith(
ClassVisitorFactory::class.java, InstrumentationScope.PROJECT
) {}
}

abstract class ClassVisitorFactory : AsmClassVisitorFactory<InstrumentationParameters.None> {
override fun createClassVisitor(
classContext: ClassContext,
nextClassVisitor: ClassVisitor
): ClassVisitor {
return ClassRemapper(nextClassVisitor, object : Remapper() {
override fun map(name: String): String {
if (name.startsWith("stub/")) {
return name.substring(name.indexOf('/') + 1)
}
return name
}
})
}

override fun isInstrumentable(classData: ClassData): Boolean {
return classData.className.endsWith("ass")
}
}

@CacheableTask
abstract class ManifestUpdater : DefaultTask() {
@get:InputFile
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,23 @@
import java.util.List;
import java.util.Optional;

import dalvik.system.VMRuntime;

@SuppressWarnings("JavaReflectionMemberAccess")
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.P)
@RunWith(AndroidJUnit4.class)
public class HiddenApiBypassTest {

private final Class<?> runtime = Class.forName("dalvik.system.VMRuntime");

@Rule
public ExpectedException exception = ExpectedException.none();

public HiddenApiBypassTest() throws ClassNotFoundException {
}

@Test
public void AgetDeclaredMethods() {
List<Executable> methods = HiddenApiBypass.getDeclaredMethods(VMRuntime.class);
List<Executable> methods = HiddenApiBypass.getDeclaredMethods(runtime);
Optional<Executable> getRuntime = methods.stream().filter(it -> it.getName().equals("getRuntime")).findFirst();
assertTrue(getRuntime.isPresent());
Optional<Executable> setHiddenApiExemptions = methods.stream().filter(it -> it.getName().equals("setHiddenApiExemptions")).findFirst();
Expand All @@ -52,7 +55,7 @@ public void BusesNonSdkApiIsHiddenApi() throws NoSuchMethodException {

@Test(expected = NoSuchMethodException.class)
public void CsetHiddenApiExemptionsIsHiddenApi() throws NoSuchMethodException {
VMRuntime.class.getMethod("setHiddenApiExemptions", String[].class);
runtime.getMethod("setHiddenApiExemptions", String[].class);
}

@Test(expected = NoSuchMethodException.class)
Expand All @@ -69,6 +72,7 @@ public void ElongVersionCodeIsHiddenApi() throws NoSuchFieldException {
public void FHiddenApiEnforcementDefaultIsHiddenApi() throws NoSuchFieldException {
ApplicationInfo.class.getDeclaredField("HIDDEN_API_ENFORCEMENT_DEFAULT");
}

@Test
public void GtestGetInstanceFields() {
assertTrue(HiddenApiBypass.getInstanceFields(ApplicationInfo.class).stream().anyMatch(i -> i.getName().equals("longVersionCode")));
Expand Down Expand Up @@ -112,30 +116,30 @@ public void MclearHiddenApiExemptions() throws NoSuchMethodException {
assertTrue(HiddenApiBypass.setHiddenApiExemptions("L"));
ApplicationInfo.class.getMethod("getHiddenApiEnforcementPolicy");
assertTrue(HiddenApiBypass.clearHiddenApiExemptions());
VMRuntime.class.getMethod("setHiddenApiExemptions", String[].class);
runtime.getMethod("setHiddenApiExemptions", String[].class);
}

@Test
public void NaddHiddenApiExemptionsTest() throws NoSuchMethodException {
assertTrue(HiddenApiBypass.addHiddenApiExemptions("Landroid/content/pm/ApplicationInfo;"));
ApplicationInfo.class.getMethod("getHiddenApiEnforcementPolicy");
assertTrue(HiddenApiBypass.addHiddenApiExemptions("Ldalvik/system/VMRuntime;"));
VMRuntime.class.getMethod("setHiddenApiExemptions", String[].class);
runtime.getMethod("setHiddenApiExemptions", String[].class);
}

@Test
public void OtestCheckArgsForInvokeMethod() {
class X {
}
assertFalse(HiddenApiBypass.checkArgsForInvokeMethod(new Class[]{}, new Object[]{new Object()}));
assertTrue(HiddenApiBypass.checkArgsForInvokeMethod(new Class[]{int.class}, new Object[]{1}));
assertFalse(HiddenApiBypass.checkArgsForInvokeMethod(new Class[]{int.class}, new Object[]{1.0}));
assertFalse(HiddenApiBypass.checkArgsForInvokeMethod(new Class[]{int.class}, new Object[]{null}));
assertTrue(HiddenApiBypass.checkArgsForInvokeMethod(new Class[]{Integer.class}, new Object[]{1}));
assertTrue(HiddenApiBypass.checkArgsForInvokeMethod(new Class[]{Integer.class}, new Object[]{null}));
assertTrue(HiddenApiBypass.checkArgsForInvokeMethod(new Class[]{Object.class}, new Object[]{new X()}));
assertFalse(HiddenApiBypass.checkArgsForInvokeMethod(new Class[]{X.class}, new Object[]{new Object()}));
assertTrue(HiddenApiBypass.checkArgsForInvokeMethod(new Class[]{Object.class, int.class, byte.class, short.class, char.class, double.class, float.class, boolean.class, long.class}, new Object[]{new X(), 1, (byte) 0, (short) 2, 'c', 1.1, 1.2f, false, 114514L}));
assertFalse(Helper.checkArgsForInvokeMethod(new Class[]{}, new Object[]{new Object()}));
assertTrue(Helper.checkArgsForInvokeMethod(new Class[]{int.class}, new Object[]{1}));
assertFalse(Helper.checkArgsForInvokeMethod(new Class[]{int.class}, new Object[]{1.0}));
assertFalse(Helper.checkArgsForInvokeMethod(new Class[]{int.class}, new Object[]{null}));
assertTrue(Helper.checkArgsForInvokeMethod(new Class[]{Integer.class}, new Object[]{1}));
assertTrue(Helper.checkArgsForInvokeMethod(new Class[]{Integer.class}, new Object[]{null}));
assertTrue(Helper.checkArgsForInvokeMethod(new Class[]{Object.class}, new Object[]{new X()}));
assertFalse(Helper.checkArgsForInvokeMethod(new Class[]{X.class}, new Object[]{new Object()}));
assertTrue(Helper.checkArgsForInvokeMethod(new Class[]{Object.class, int.class, byte.class, short.class, char.class, double.class, float.class, boolean.class, long.class}, new Object[]{new X(), 1, (byte) 0, (short) 2, 'c', 1.1, 1.2f, false, 114514L}));
}

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.lsposed.lspass;
package org.lsposed.hiddenapibypass;

import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
Expand All @@ -17,7 +17,6 @@
import org.junit.runners.MethodSorters;

import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;

@SuppressWarnings("JavaReflectionMemberAccess")
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
Expand All @@ -42,7 +41,7 @@ public void CmHeightIsHiddenApi() throws NoSuchFieldException {

@Test
public void DtestgetDeclaredFields() {
assertTrue(Arrays.stream(LSPass.getDeclaredFields(ActivityOptions.class)).anyMatch(i -> i.getName().equals("mHeight")));
assertTrue(LSPass.getDeclaredFields(ActivityOptions.class).stream().anyMatch(i -> i.getName().equals("mHeight")));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package org.lsposed.hiddenapibypass;

import android.os.Build;

import androidx.annotation.RequiresApi;

import java.lang.invoke.MethodHandle;
import java.lang.reflect.Executable;

import dalvik.system.PathClassLoader;

@RequiresApi(Build.VERSION_CODES.P)
final class CoreOjClassLoader extends PathClassLoader {
private static String getCoreOjPath() {
String bootClassPath = System.getProperty("java.boot.class.path", "");
assert bootClassPath != null;
return bootClassPath.split(":", 2)[0];
}

CoreOjClassLoader() {
super(getCoreOjPath(), null);
}

@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (Object.class.getName().equals(name)) {
return Object.class;
}
try {
return findClass(name);
} catch (ClassNotFoundException ignored) {
// no class file in jar before art moved to apex.
}
if (Executable.class.getName().equals(name)) {
return Helper.Executable.class;
} else if (MethodHandle.class.getName().equals(name)) {
return Helper.MethodHandle.class;
} else if (Class.class.getName().equals(name)) {
return Helper.Class.class;
}
return super.loadClass(name);
}
}
21 changes: 21 additions & 0 deletions library/src/main/java/org/lsposed/hiddenapibypass/Helper.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,30 @@
package org.lsposed.hiddenapibypass;

import java.lang.invoke.MethodType;
import java.util.HashSet;
import java.util.Set;

@SuppressWarnings("unused")
public class Helper {
static final Set<String> signaturePrefixes = new HashSet<>();

static boolean checkArgsForInvokeMethod(java.lang.Class<?>[] params, Object[] args) {
if (params.length != args.length) return false;
for (int i = 0; i < params.length; ++i) {
if (params[i].isPrimitive()) {
if (params[i] == int.class && !(args[i] instanceof Integer)) return false;
else if (params[i] == byte.class && !(args[i] instanceof Byte)) return false;
else if (params[i] == char.class && !(args[i] instanceof Character)) return false;
else if (params[i] == boolean.class && !(args[i] instanceof Boolean)) return false;
else if (params[i] == double.class && !(args[i] instanceof Double)) return false;
else if (params[i] == float.class && !(args[i] instanceof Float)) return false;
else if (params[i] == long.class && !(args[i] instanceof Long)) return false;
else if (params[i] == short.class && !(args[i] instanceof Short)) return false;
} else if (args[i] != null && !params[i].isInstance(args[i])) return false;
}
return true;
}

static public class MethodHandle {
private final MethodType type = null;
private MethodType nominalType;
Expand Down
Loading

0 comments on commit cd3dc4c

Please sign in to comment.