package com.swift.sandhook; import com.swift.sandhook.annotation.HookMode; import com.swift.sandhook.blacklist.HookBlackList; import com.swift.sandhook.utils.ClassStatusUtils; import com.swift.sandhook.utils.FileUtils; import com.swift.sandhook.utils.ReflectionUtils; import com.swift.sandhook.utils.Unsafe; import com.swift.sandhook.wrapper.HookErrorException; import com.swift.sandhook.wrapper.HookWrapper; import i.am.jaggu; import java.io.File; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class SandHook { public static Class artMethodClass; static Map<Method, HookWrapper.HookEntity> globalBackupMap = new ConcurrentHashMap(); static Map<Member, HookWrapper.HookEntity> globalHookEntityMap = new ConcurrentHashMap(); private static HookModeCallBack hookModeCallBack; private static HookResultCallBack hookResultCallBack; public static Field nativePeerField; public static int testAccessFlag; public static Object testOffsetArtMethod1; public static Object testOffsetArtMethod2; public static Method testOffsetMethod1; public static Method testOffsetMethod2; @FunctionalInterface public interface HookModeCallBack { int hookMode(Member member); } @FunctionalInterface public interface HookResultCallBack { void hookResult(boolean z, HookWrapper.HookEntity hookEntity); } static { SandHookConfig.libLoader.loadLib(); init(); } public static native void MakeInitializedClassVisibilyInitialized(long j); public static void addHookClass(ClassLoader classLoader, Class... clsArr) throws HookErrorException { HookWrapper.addHookClass(classLoader, clsArr); } public static void addHookClass(Class... clsArr) throws HookErrorException { HookWrapper.addHookClass(clsArr); } public static final Object callOriginByBackup(Method method, Object obj, Object... objArr) throws Throwable { HookWrapper.HookEntity hookEntity = globalBackupMap.get(method); if (hookEntity == null) { return null; } return callOriginMethod(hookEntity.backupIsStub, hookEntity.target, method, obj, objArr); } public static final Object callOriginMethod(Member member, Object obj, Object... objArr) throws Throwable { HookWrapper.HookEntity hookEntity = globalHookEntityMap.get(member); if (hookEntity == null || hookEntity.backup == null) { return null; } return callOriginMethod(hookEntity.backupIsStub, member, hookEntity.backup, obj, objArr); } public static final Object callOriginMethod(Member member, Method method, Object obj, Object[] objArr) throws Throwable { return callOriginMethod(true, member, method, obj, objArr); } public static final Object callOriginMethod(boolean z, Member member, Method method, Object obj, Object[] objArr) throws Throwable { if (!z && SandHookConfig.SDK_INT >= 24) { member.getDeclaringClass(); ensureDeclareClass(member, method); } if (Modifier.isStatic(member.getModifiers())) { try { return method.invoke(null, objArr); } catch (InvocationTargetException e) { if (e.getCause() != null) { throw e.getCause(); } throw e; } } else { try { return method.invoke(obj, objArr); } catch (InvocationTargetException e2) { if (e2.getCause() != null) { throw e2.getCause(); } throw e2; } } } public static native boolean canGetObject(); public static boolean canGetObjectAddress() { return Unsafe.support(); } public static native boolean compileMethod(Member member); public static native boolean deCompileMethod(Member member, boolean z); public static native boolean disableDex2oatInline(boolean z); public static native boolean disableVMInline(); public static final void ensureBackupMethod(Method method) { HookWrapper.HookEntity hookEntity; if (SandHookConfig.SDK_INT >= 24 && (hookEntity = globalBackupMap.get(method)) != null) { ensureDeclareClass(hookEntity.target, method); } } public static native void ensureDeclareClass(Member member, Method method); public static native void ensureMethodCached(Method method, Method method2); public static long getArtMethod(Member member) { return SandHookMethodResolver.getArtMethod(member); } private static Object[] getFakeArgs(Method method) { return new Object[method.getParameterTypes().length]; } public static Field getField(Class cls, String str) throws NoSuchFieldException { while (cls != null && cls != Object.class) { try { Field declaredField = cls.getDeclaredField(str); declaredField.setAccessible(true); return declaredField; } catch (Exception unused) { cls = cls.getSuperclass(); } } throw new NoSuchFieldException(str); } public static Object getJavaMethod(String str, String str2) { if (str == null) { return null; } try { return Class.forName(str).getDeclaredMethod(str2, new Class[0]); } catch (ClassNotFoundException unused) { return null; } } public static Object getObject(long j) { if (j == 0) { return null; } return getObjectNative(getThreadId(), j); } public static long getObjectAddress(Object obj) { return Unsafe.getObjectAddress(obj); } public static native Object getObjectNative(long j, long j2); public static long getThreadId() { Field field = nativePeerField; if (field == null) { return 0; } try { return field.getType() == Integer.TYPE ? (long) nativePeerField.getInt(Thread.currentThread()) : nativePeerField.getLong(Thread.currentThread()); } catch (IllegalAccessException unused) { return 0; } } public static boolean hasJavaArtMethod() { if (SandHookConfig.SDK_INT >= 26) { return false; } if (artMethodClass != null) { return true; } try { ClassLoader classLoader = SandHookConfig.initClassLoader; String decode = jaggu.base.decode("090713571908025E5F1E105707095105471A2045157B01115B5F07"); if (classLoader == null) { artMethodClass = Class.forName(decode); } else { artMethodClass = Class.forName(decode, true, SandHookConfig.initClassLoader); } return true; } catch (ClassNotFoundException unused) { return false; } } public static synchronized void hook(HookWrapper.HookEntity hookEntity) throws HookErrorException { int i2; synchronized (SandHook.class) { if (hookEntity != null) { Member member = hookEntity.target; Method method = hookEntity.hook; Method method2 = hookEntity.backup; if (member == null || method == null) { throw new HookErrorException(jaggu.base.decode("0D13095A170D0D404D44")); } else if (globalHookEntityMap.containsKey(hookEntity.target)) { throw new HookErrorException(jaggu.base.decode("0E03115E5800430C") + hookEntity.target.toString() + jaggu.base.decode("5D460D57444401555D5E425A0E0A5F035715")); } else if (HookBlackList.canNotHook(member)) { throw new HookErrorException(jaggu.base.decode("0E03115E5800430C") + hookEntity.target.toString() + jaggu.base.decode("5D46065759440D5F4C100A5D0E0E184651510256144501455C56435B58135B5C02050E5A5E171711")); } else if (!SandHookConfig.delayHook || !PendingHookHandler.canWork() || !ClassStatusUtils.isStaticAndNoInited(hookEntity.target)) { if (hookEntity.initClass) { resolveStaticMethod(member); MakeInitializedClassVisibilyInitialized(getThreadId()); } resolveStaticMethod(method2); if (method2 != null && hookEntity.resolveDexCache) { SandHookMethodResolver.resolveMethod(method, method2); } if (member instanceof Method) { ((Method) member).setAccessible(true); } boolean z = false; int hookMode = hookModeCallBack != null ? hookModeCallBack.hookMode(member) : 0; globalHookEntityMap.put(hookEntity.target, hookEntity); if (hookMode != 0) { i2 = hookMethod(member, method, method2, hookMode); } else { HookMode hookMode2 = (HookMode) method.getAnnotation(HookMode.class); i2 = hookMethod(member, method, method2, hookMode2 == null ? 0 : hookMode2.value()); } if (i2 > 0 && method2 != null) { method2.setAccessible(true); } hookEntity.hookMode = i2; if (hookResultCallBack != null) { HookResultCallBack hookResultCallBack2 = hookResultCallBack; if (i2 > 0) { z = true; } hookResultCallBack2.hookResult(z, hookEntity); } if (i2 >= 0) { if (hookEntity.backup != null) { globalBackupMap.put(hookEntity.backup, hookEntity); } StringBuilder sb = new StringBuilder(); sb.append(jaggu.base.decode("0E03115E5800430C")); sb.append(hookEntity.target.toString()); sb.append(jaggu.base.decode("5D460D59580F430C")); sb.append(i2 == 1 ? jaggu.base.decode("0A08095F5901") : jaggu.base.decode("1103155A5607065D5D5E16")); sb.append(jaggu.base.decode("5D461643540706434B11")); HookLog.d(sb.toString()); return; } globalHookEntityMap.remove(hookEntity.target); throw new HookErrorException(jaggu.base.decode("0B090A5D17090644505F06125D") + hookEntity.target.toString() + jaggu.base.decode("5D460044450B1110515E425C00115D105615")); } else { PendingHookHandler.addPendingHook(hookEntity); } } else { throw new HookErrorException(jaggu.base.decode("0D13095A170C0C5F5310075C150C401F")); } } } private static native int hookMethod(Member member, Method method, Method method2, int i2); private static boolean init() { initTestOffset(); initThreadPeer(); SandHookMethodResolver.init(); return initNative(SandHookConfig.SDK_INT, SandHookConfig.DEBUG); } public static native boolean initForPendingHook(); private static native boolean initNative(int i2, boolean z); private static void initTestAccessFlag() { boolean hasJavaArtMethod = hasJavaArtMethod(); String decode = jaggu.base.decode("020506534417255C595711"); if (hasJavaArtMethod) { try { loadArtMethod(); testAccessFlag = ((Integer) getField(artMethodClass, decode).get(testOffsetArtMethod1)).intValue(); } catch (Exception unused) { } } else { testAccessFlag = ((Integer) getField(Method.class, decode).get(testOffsetMethod1)).intValue(); } } private static void initTestOffset() { ArtMethodSizeTest.method1(); ArtMethodSizeTest.method2(); try { testOffsetMethod1 = ArtMethodSizeTest.class.getDeclaredMethod(jaggu.base.decode("0E03115E580052"), new Class[0]); testOffsetMethod2 = ArtMethodSizeTest.class.getDeclaredMethod(jaggu.base.decode("0E03115E580051"), new Class[0]); initTestAccessFlag(); } catch (NoSuchMethodException e) { throw new RuntimeException(jaggu.base.decode("30070B527F0B0C5B18590C5B15455114415B13"), e); } } private static void initThreadPeer() { try { nativePeerField = getField(Thread.class, jaggu.base.decode("0D07115F410133555D42")); } catch (NoSuchFieldException unused) { } } public static native boolean is64Bit(); private static void loadArtMethod() { try { Field field = getField(Method.class, jaggu.base.decode("0214117B52100B5F5C")); testOffsetArtMethod1 = field.get(testOffsetMethod1); testOffsetArtMethod2 = field.get(testOffsetMethod2); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (NoSuchFieldException e2) { e2.printStackTrace(); } } public static boolean passApiCheck() { return ReflectionUtils.passApiCheck(); } public static boolean resolveStaticMethod(Member member) { if (member == null) { return true; } try { if ((member instanceof Method) && Modifier.isStatic(member.getModifiers())) { ((Method) member).setAccessible(true); ((Method) member).invoke(null, getFakeArgs((Method) member)); } } catch (ExceptionInInitializerError unused) { return false; } catch (Throwable unused2) { } return true; } public static native void setHookMode(int i2); public static void setHookModeCallBack(HookModeCallBack hookModeCallBack2) { hookModeCallBack = hookModeCallBack2; } public static void setHookResultCallBack(HookResultCallBack hookResultCallBack2) { hookResultCallBack = hookResultCallBack2; } public static native void setInlineSafeCheck(boolean z); public static native boolean setNativeEntry(Member member, Member member2, long j); public static native void skipAllSafeCheck(boolean z); public static boolean tryDisableProfile(String str) { if (SandHookConfig.SDK_INT < 24) { return false; } try { File file = new File(jaggu.base.decode("4C020442564B0E594B534D42130A520F5F5112180243164A") + SandHookConfig.curUser + jaggu.base.decode("4C") + str + jaggu.base.decode("4C16175F5A0511491640105D07")); if (!file.getParentFile().exists()) { return false; } try { file.delete(); file.createNewFile(); } catch (Throwable unused) { } FileUtils.chmod(file.getAbsolutePath(), 256); return true; } catch (Throwable unused2) { return false; } } }