SandHook: fix thread synchronization

This commit is contained in:
swift_gan 2019-03-30 14:42:12 +08:00
parent a956dd2a47
commit 184734b4b6
5 changed files with 33 additions and 29 deletions

View File

@ -24,7 +24,7 @@ dependencies {
compileOnly files("libs/framework-stub.jar") compileOnly files("libs/framework-stub.jar")
implementation project(':edxp-common') implementation project(':edxp-common')
implementation project(':xposed-bridge') implementation project(':xposed-bridge')
implementation 'com.swift.sandhook:hooklib:3.3.4' implementation 'com.swift.sandhook:hooklib:3.3.8'
compileOnly project(':dexmaker') compileOnly project(':dexmaker')
} }

View File

@ -13,15 +13,12 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.Member; import java.lang.reflect.Member;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import de.robv.android.xposed.XC_MethodHook; import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge; import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers; import de.robv.android.xposed.XposedHelpers;
import static de.robv.android.xposed.XposedBridge.sHookedMethodCallbacks;
public class HookStubManager { public class HookStubManager {
public static volatile boolean is64Bit; public static volatile boolean is64Bit;
@ -40,9 +37,7 @@ public class HookStubManager {
public static Member[] originMethods; public static Member[] originMethods;
public static HookMethodEntity[] hookMethodEntities; public static HookMethodEntity[] hookMethodEntities;
public static XposedBridge.AdditionalHookInfo[] additionalHookInfos;
private static final Map<Member, XposedBridge.CopyOnWriteSortedSet<XC_MethodHook>> hookCallbacks
= sHookedMethodCallbacks;
static { static {
is64Bit = SandHook.is64Bit(); is64Bit = SandHook.is64Bit();
@ -59,11 +54,12 @@ public class HookStubManager {
} }
originMethods = new Member[ALL_STUB]; originMethods = new Member[ALL_STUB];
hookMethodEntities = new HookMethodEntity[ALL_STUB]; hookMethodEntities = new HookMethodEntity[ALL_STUB];
additionalHookInfos = new XposedBridge.AdditionalHookInfo[ALL_STUB];
} }
} }
public static HookMethodEntity getHookMethodEntity(Member origin) { public static HookMethodEntity getHookMethodEntity(Member origin, XposedBridge.AdditionalHookInfo additionalHookInfo) {
if (!support()) { if (!support()) {
return null; return null;
@ -111,13 +107,14 @@ public class HookStubManager {
HookMethodEntity entity = new HookMethodEntity(origin, stubMethodInfo.hook, stubMethodInfo.backup); HookMethodEntity entity = new HookMethodEntity(origin, stubMethodInfo.hook, stubMethodInfo.backup);
entity.retType = retType; entity.retType = retType;
entity.parType = parType; entity.parType = parType;
int id = getMethodId(stubMethodInfo.args, stubMethodInfo.index);
originMethods[id] = origin;
hookMethodEntities[id] = entity;
if (hasStubBackup && !tryCompileAndResolveCallOriginMethod(entity.backup, stubMethodInfo.args, stubMethodInfo.index)) { if (hasStubBackup && !tryCompileAndResolveCallOriginMethod(entity.backup, stubMethodInfo.args, stubMethodInfo.index)) {
DexLog.w("internal stub <" + entity.hook.getName() + "> call origin compile failure, skip use internal stub"); DexLog.w("internal stub <" + entity.hook.getName() + "> call origin compile failure, skip use internal stub");
return null; return null;
} else { } else {
int id = getMethodId(stubMethodInfo.args, stubMethodInfo.index);
originMethods[id] = origin;
hookMethodEntities[id] = entity;
additionalHookInfos[id] = additionalHookInfo;
return entity; return entity;
} }
} }
@ -257,7 +254,8 @@ public class HookStubManager {
DexLog.printMethodHookIn(originMethod); DexLog.printMethodHookIn(originMethod);
Object[] snapshot = hookCallbacks.get(originMethod).getSnapshot(); Object[] snapshot = additionalHookInfos[id].callbacks.getSnapshot();
if (snapshot == null || snapshot.length == 0) { if (snapshot == null || snapshot.length == 0) {
if (hasStubBackup) { if (hasStubBackup) {
return callOrigin.call(stubArgs); return callOrigin.call(stubArgs);
@ -314,6 +312,7 @@ public class HookStubManager {
try { try {
((XC_MethodHook) snapshot[afterIdx]).callAfterHookedMethod(param); ((XC_MethodHook) snapshot[afterIdx]).callAfterHookedMethod(param);
} catch (Throwable t) { } catch (Throwable t) {
XposedBridge.log(t);
if (lastThrowable == null) if (lastThrowable == null)
param.setResult(lastResult); param.setResult(lastResult);
else else
@ -327,16 +326,17 @@ public class HookStubManager {
} }
} }
public static Object hookBridge(Member origin, Object thiz, Object... args) throws Throwable { public static Object hookBridge(Member origin, Method backup, XposedBridge.AdditionalHookInfo additionalHookInfo, Object thiz, Object... args) throws Throwable {
if (XposedBridge.disableHooks) { if (XposedBridge.disableHooks) {
return SandHook.callOriginMethod(origin, thiz, args); return SandHook.callOriginMethod(true, origin, backup, thiz, args);
} }
DexLog.printMethodHookIn(origin); DexLog.printMethodHookIn(origin);
Object[] snapshot = hookCallbacks.get(origin).getSnapshot(); Object[] snapshot = additionalHookInfo.callbacks.getSnapshot();
if (snapshot == null || snapshot.length == 0) { if (snapshot == null || snapshot.length == 0) {
return SandHook.callOriginMethod(origin, thiz, args); return SandHook.callOriginMethod(origin, thiz, args);
} }
@ -368,7 +368,7 @@ public class HookStubManager {
// call original method if not requested otherwise // call original method if not requested otherwise
if (!param.returnEarly) { if (!param.returnEarly) {
try { try {
param.setResult(SandHook.callOriginMethod(origin, thiz, param.args)); param.setResult(SandHook.callOriginMethod(true, origin, backup, thiz, param.args));
} catch (Throwable e) { } catch (Throwable e) {
param.setThrowable(e); param.setThrowable(e);
} }
@ -383,6 +383,7 @@ public class HookStubManager {
try { try {
((XC_MethodHook) snapshot[afterIdx]).callAfterHookedMethod(param); ((XC_MethodHook) snapshot[afterIdx]).callAfterHookedMethod(param);
} catch (Throwable t) { } catch (Throwable t) {
XposedBridge.log(t);
if (lastThrowable == null) if (lastThrowable == null)
param.setResult(lastResult); param.setResult(lastResult);
else else
@ -396,8 +397,8 @@ public class HookStubManager {
} }
} }
public static long callOrigin(HookMethodEntity entity, Member origin, Object thiz, Object[] args) throws Throwable { public final static long callOrigin(HookMethodEntity entity, Member origin, Object thiz, Object[] args) throws Throwable {
Object res = SandHook.callOriginMethod(origin, thiz, args); Object res = SandHook.callOriginMethod(true, origin, entity.backup, thiz, args);
return entity.getResultAddress(res); return entity.getResultAddress(res);
} }

View File

@ -37,7 +37,7 @@ public class HookerDexMakerNew implements HookMaker {
public static final String METHOD_NAME_HOOK = "hook"; public static final String METHOD_NAME_HOOK = "hook";
public static final TypeId<Object[]> objArrayTypeId = TypeId.get(Object[].class); public static final TypeId<Object[]> objArrayTypeId = TypeId.get(Object[].class);
private static final String CLASS_DESC_PREFIX = "L"; private static final String CLASS_DESC_PREFIX = "L";
private static final String CLASS_NAME_PREFIX = "SandHookerN"; private static final String CLASS_NAME_PREFIX = "SandHookerNew";
private static final String FIELD_NAME_HOOK_INFO = "additionalHookInfo"; private static final String FIELD_NAME_HOOK_INFO = "additionalHookInfo";
private static final String FIELD_NAME_METHOD = "method"; private static final String FIELD_NAME_METHOD = "method";
private static final String FIELD_NAME_BACKUP_METHOD = "backupMethod"; private static final String FIELD_NAME_BACKUP_METHOD = "backupMethod";
@ -237,12 +237,13 @@ public class HookerDexMakerNew implements HookMaker {
private void generateHookMethod() { private void generateHookMethod() {
mHookMethodId = mHookerTypeId.getMethod(mReturnTypeId, METHOD_NAME_HOOK, mParameterTypeIds); mHookMethodId = mHookerTypeId.getMethod(mReturnTypeId, METHOD_NAME_HOOK, mParameterTypeIds);
mSandHookBridgeMethodId = TypeId.get(HookStubManager.class).getMethod(TypeId.get(Object.class), "hookBridge", memberTypeId, TypeId.get(Object.class), TypeId.get(Object[].class)); mSandHookBridgeMethodId = TypeId.get(HookStubManager.class).getMethod(TypeId.get(Object.class), "hookBridge", memberTypeId, methodTypeId, hookInfoTypeId, TypeId.get(Object.class), TypeId.get(Object[].class));
Code code = mDexMaker.declare(mHookMethodId, Modifier.PUBLIC | Modifier.STATIC); Code code = mDexMaker.declare(mHookMethodId, Modifier.PUBLIC | Modifier.STATIC);
Local<Member> method = code.newLocal(memberTypeId); Local<Member> originMethod = code.newLocal(memberTypeId);
// Local<Method> backupMethod = code.newLocal(methodTypeId); Local<Method> backupMethod = code.newLocal(methodTypeId);
Local<XposedBridge.AdditionalHookInfo> hookInfo = code.newLocal(hookInfoTypeId);
Local<Object> thisObject = code.newLocal(TypeId.OBJECT); Local<Object> thisObject = code.newLocal(TypeId.OBJECT);
Local<Object[]> args = code.newLocal(objArrayTypeId); Local<Object[]> args = code.newLocal(objArrayTypeId);
Local<Integer> actualParamSize = code.newLocal(TypeId.INT); Local<Integer> actualParamSize = code.newLocal(TypeId.INT);
@ -253,10 +254,12 @@ public class HookerDexMakerNew implements HookMaker {
Map<TypeId, Local> resultLocals = createResultLocals(code); Map<TypeId, Local> resultLocals = createResultLocals(code);
code.sget(mMethodFieldId, method);
code.loadConstant(args, null); code.loadConstant(args, null);
code.loadConstant(argIndex, 0); code.loadConstant(argIndex, 0);
// code.sget(mBackupMethodFieldId, backupMethod); code.sget(mMethodFieldId, originMethod);
code.sget(mBackupMethodFieldId, backupMethod);
code.sget(mHookInfoFieldId, hookInfo);
int paramsSize = mParameterTypeIds.length; int paramsSize = mParameterTypeIds.length;
int offset = 0; int offset = 0;
// thisObject // thisObject
@ -282,10 +285,10 @@ public class HookerDexMakerNew implements HookMaker {
} }
if (mReturnTypeId.equals(TypeId.VOID)) { if (mReturnTypeId.equals(TypeId.VOID)) {
code.invokeStatic(mSandHookBridgeMethodId, null, method, thisObject, args); code.invokeStatic(mSandHookBridgeMethodId, null, originMethod, backupMethod, hookInfo, thisObject, args);
code.returnVoid(); code.returnVoid();
} else { } else {
code.invokeStatic(mSandHookBridgeMethodId, resultObj, method, thisObject, args); code.invokeStatic(mSandHookBridgeMethodId, resultObj, originMethod, backupMethod, hookInfo, thisObject, args);
TypeId objTypeId = getObjTypeIdIfPrimitive(mReturnTypeId); TypeId objTypeId = getObjTypeIdIfPrimitive(mReturnTypeId);
Local matchObjLocal = resultLocals.get(objTypeId); Local matchObjLocal = resultLocals.get(objTypeId);
code.cast(matchObjLocal, resultObj); code.cast(matchObjLocal, resultObj);

View File

@ -64,7 +64,7 @@ public final class SandHookXposedBridge {
long timeStart = System.currentTimeMillis(); long timeStart = System.currentTimeMillis();
HookMethodEntity stub = null; HookMethodEntity stub = null;
if (XposedCompat.useInternalStub) { if (XposedCompat.useInternalStub) {
stub = HookStubManager.getHookMethodEntity(hookMethod); stub = HookStubManager.getHookMethodEntity(hookMethod, additionalHookInfo);
} }
if (stub != null) { if (stub != null) {
SandHook.hook(new HookWrapper.HookEntity(hookMethod, stub.hook, stub.backup, false)); SandHook.hook(new HookWrapper.HookEntity(hookMethod, stub.hook, stub.backup, false));

View File

@ -14,10 +14,10 @@ import java.lang.reflect.Member;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import de.robv.android.xposed.XC_MethodHook.MethodHookParam; import de.robv.android.xposed.XC_MethodHook.MethodHookParam;
import de.robv.android.xposed.callbacks.XC_InitPackageResources; import de.robv.android.xposed.callbacks.XC_InitPackageResources;
@ -60,7 +60,7 @@ public final class XposedBridge {
private static final Object[] EMPTY_ARRAY = new Object[0]; private static final Object[] EMPTY_ARRAY = new Object[0];
// built-in handlers // built-in handlers
public static final Map<Member, CopyOnWriteSortedSet<XC_MethodHook>> sHookedMethodCallbacks = new ConcurrentHashMap<>(); public static final Map<Member, CopyOnWriteSortedSet<XC_MethodHook>> sHookedMethodCallbacks = new HashMap<>();
public static final CopyOnWriteSortedSet<XC_LoadPackage> sLoadedPackageCallbacks = new CopyOnWriteSortedSet<>(); public static final CopyOnWriteSortedSet<XC_LoadPackage> sLoadedPackageCallbacks = new CopyOnWriteSortedSet<>();
/*package*/ static final CopyOnWriteSortedSet<XC_InitPackageResources> sInitPackageResourcesCallbacks = new CopyOnWriteSortedSet<>(); /*package*/ static final CopyOnWriteSortedSet<XC_InitPackageResources> sInitPackageResourcesCallbacks = new CopyOnWriteSortedSet<>();