Commit 3e4cf9aa authored by swift_gan's avatar swift_gan

add call origin error detect

parent 955fa990
...@@ -118,10 +118,12 @@ public class SandHook { ...@@ -118,10 +118,12 @@ public class SandHook {
hookResultCallBack.hookResult(res > 0, entity); hookResultCallBack.hookResult(res > 0, entity);
} }
if (res <= 0) if (res < 0) {
throw new HookErrorException("hook method <" + entity.target.toString() + "> error in native!"); throw new HookErrorException("hook method <" + entity.target.toString() + "> error in native!");
}
globalHookEntityMap.put(entity.target, entity); globalHookEntityMap.put(entity.target, entity);
if (entity.backup != null) { if (entity.backup != null) {
globalBackupMap.put(entity.backup, entity); globalBackupMap.put(entity.backup, entity);
} }
...@@ -129,6 +131,33 @@ public class SandHook { ...@@ -129,6 +131,33 @@ public class SandHook {
Log.d("SandHook", "method <" + entity.target.toString() + "> hook <" + (res == HookMode.INLINE ? "inline" : "replacement") + "> success!"); Log.d("SandHook", "method <" + entity.target.toString() + "> hook <" + (res == HookMode.INLINE ? "inline" : "replacement") + "> success!");
} }
public static Object callOriginMethod(Member originMethod, Object thiz, Object[] args) throws Throwable {
HookWrapper.HookEntity hookEntity = globalHookEntityMap.get(originMethod);
if (hookEntity == null || hookEntity.backup == null)
return null;
return callOriginMethod(originMethod, hookEntity.backup, thiz, args);
}
public static Object callOriginMethod(Member originMethod, Method backupMethod, Object thiz, Object[] args) throws Throwable {
backupMethod.setAccessible(true);
if (args == null) {
args = new Object[0];
}
final int argsSize = args.length;
if (Modifier.isStatic(originMethod.getModifiers())) {
ensureMethodDeclaringClass(originMethod, backupMethod);
return backupMethod.invoke(null, args);
} else {
Object[] newArgs = new Object[argsSize + 1];
newArgs[0] = thiz;
for (int i = 1; i < newArgs.length; i++) {
newArgs[i] = args[i - 1];
}
ensureMethodDeclaringClass(originMethod, backupMethod);
return backupMethod.invoke(null, newArgs);
}
}
public static void ensureBackupDeclaringClass(Method backupMethod) { public static void ensureBackupDeclaringClass(Method backupMethod) {
if (backupMethod == null) if (backupMethod == null)
return; return;
...@@ -138,13 +167,13 @@ public class SandHook { ...@@ -138,13 +167,13 @@ public class SandHook {
ensureMethodDeclaringClass(hookEntity.target, backupMethod); ensureMethodDeclaringClass(hookEntity.target, backupMethod);
} }
public static void ensureBackupDelaringClassByOrigin(Member originMethod) { public static boolean ensureBackupDelaringClassByOrigin(Member originMethod) {
if (originMethod == null) if (originMethod == null)
return; return false;
HookWrapper.HookEntity hookEntity = globalHookEntityMap.get(originMethod); HookWrapper.HookEntity hookEntity = globalHookEntityMap.get(originMethod);
if (hookEntity == null || hookEntity.backup == null) if (hookEntity == null || hookEntity.backup == null)
return; return false;
ensureMethodDeclaringClass(originMethod, hookEntity.backup); return ensureMethodDeclaringClass(originMethod, hookEntity.backup);
} }
private static void resolveStaticMethod(Member method) { private static void resolveStaticMethod(Member method) {
...@@ -248,7 +277,7 @@ public class SandHook { ...@@ -248,7 +277,7 @@ public class SandHook {
public static native void ensureMethodCached(Method hook, Method backup); public static native void ensureMethodCached(Method hook, Method backup);
public static native void ensureMethodDeclaringClass(Member originMethod, Method backupMethod); public static native boolean ensureMethodDeclaringClass(Member originMethod, Method backupMethod);
@FunctionalInterface @FunctionalInterface
public interface HookModeCallBack { public interface HookModeCallBack {
......
...@@ -20,11 +20,13 @@ public class XposedCompat { ...@@ -20,11 +20,13 @@ public class XposedCompat {
public static File cacheDir; public static File cacheDir;
public static Context context; public static Context context;
public static ClassLoader classLoader; public static volatile ClassLoader classLoader;
public static String packageName; public static String packageName;
public static String processName; public static String processName;
public static boolean isFirstApplication; public static boolean isFirstApplication;
public static volatile boolean retryWhenCallOriginError = false;
private static ClassLoader sandHookXposedClassLoader; private static ClassLoader sandHookXposedClassLoader;
......
package com.swift.sandhook.xposedcompat.methodgen;
import android.util.Log;
import com.swift.sandhook.SandHook;
import com.swift.sandhook.xposedcompat.XposedCompat;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
public class ErrorCatch {
public static Object callOriginError(Member originMethod, Method backupMethod, Object thiz, Object[] args) throws Throwable {
if (XposedCompat.retryWhenCallOriginError) {
Log.w("SandHook", "method <" + originMethod.toString() + "> use invoke to call origin!");
return SandHook.callOriginMethod(originMethod, backupMethod, thiz, args);
} else {
return null;
}
}
}
package com.swift.sandhook.xposedcompat.methodgen; package com.swift.sandhook.xposedcompat.methodgen;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log;
import com.android.dx.BinaryOp; import com.android.dx.BinaryOp;
import com.android.dx.Code; import com.android.dx.Code;
...@@ -43,6 +44,7 @@ public class HookerDexMaker { ...@@ -43,6 +44,7 @@ public class HookerDexMaker {
private static final String CLASS_NAME_PREFIX = "SandHooker"; private static final String CLASS_NAME_PREFIX = "SandHooker";
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 PARAMS_FIELD_NAME_METHOD = "method"; private static final String PARAMS_FIELD_NAME_METHOD = "method";
private static final String PARAMS_FIELD_NAME_THIS_OBJECT = "thisObject"; private static final String PARAMS_FIELD_NAME_THIS_OBJECT = "thisObject";
private static final String PARAMS_FIELD_NAME_ARGS = "args"; private static final String PARAMS_FIELD_NAME_ARGS = "args";
...@@ -50,6 +52,7 @@ public class HookerDexMaker { ...@@ -50,6 +52,7 @@ public class HookerDexMaker {
private static final String CALLBACK_METHOD_NAME_AFTER = "callAfterHookedMethod"; private static final String CALLBACK_METHOD_NAME_AFTER = "callAfterHookedMethod";
private static final TypeId<Throwable> throwableTypeId = TypeId.get(Throwable.class); private static final TypeId<Throwable> throwableTypeId = TypeId.get(Throwable.class);
private static final TypeId<Member> memberTypeId = TypeId.get(Member.class); private static final TypeId<Member> memberTypeId = TypeId.get(Member.class);
private static final TypeId<Method> methodTypeId = TypeId.get(Method.class);
private static final TypeId<XC_MethodHook> callbackTypeId = TypeId.get(XC_MethodHook.class); private static final TypeId<XC_MethodHook> callbackTypeId = TypeId.get(XC_MethodHook.class);
private static final TypeId<XposedBridge.AdditionalHookInfo> hookInfoTypeId private static final TypeId<XposedBridge.AdditionalHookInfo> hookInfoTypeId
= TypeId.get(XposedBridge.AdditionalHookInfo.class); = TypeId.get(XposedBridge.AdditionalHookInfo.class);
...@@ -79,10 +82,12 @@ public class HookerDexMaker { ...@@ -79,10 +82,12 @@ public class HookerDexMaker {
private FieldId<?, XposedBridge.AdditionalHookInfo> mHookInfoFieldId; private FieldId<?, XposedBridge.AdditionalHookInfo> mHookInfoFieldId;
private FieldId<?, Member> mMethodFieldId; private FieldId<?, Member> mMethodFieldId;
private FieldId<?, Method> mBackupMethodFieldId;
private MethodId<?, ?> mBackupMethodId; private MethodId<?, ?> mBackupMethodId;
private MethodId<?, ?> mCallBackupMethodId; private MethodId<?, ?> mCallBackupMethodId;
private MethodId<?, ?> mHookMethodId; private MethodId<?, ?> mHookMethodId;
private MethodId<?, ?> mPrintLogMethodId; private MethodId<?, ?> mPrintLogMethodId;
private MethodId<?, ?> mSandHookCallOriginMethodId;
private TypeId<?> mHookerTypeId; private TypeId<?> mHookerTypeId;
private TypeId<?>[] mParameterTypeIds; private TypeId<?>[] mParameterTypeIds;
...@@ -215,11 +220,10 @@ public class HookerDexMaker { ...@@ -215,11 +220,10 @@ public class HookerDexMaker {
private HookWrapper.HookEntity loadHookerClass(ClassLoader loader, String className) throws Exception { private HookWrapper.HookEntity loadHookerClass(ClassLoader loader, String className) throws Exception {
mHookClass = loader.loadClass(className); mHookClass = loader.loadClass(className);
// Execute our newly-generated code in-process. // Execute our newly-generated code in-process.
mHookClass.getMethod(METHOD_NAME_SETUP, Member.class, XposedBridge.AdditionalHookInfo.class)
.invoke(null, mMember, mHookInfo);
mHookMethod = mHookClass.getMethod(METHOD_NAME_HOOK, mActualParameterTypes); mHookMethod = mHookClass.getMethod(METHOD_NAME_HOOK, mActualParameterTypes);
mBackupMethod = mHookClass.getMethod(METHOD_NAME_BACKUP, mActualParameterTypes); mBackupMethod = mHookClass.getMethod(METHOD_NAME_BACKUP, mActualParameterTypes);
mCallBackupMethod = mHookClass.getMethod(METHOD_NAME_CALL_BACKUP, mActualParameterTypes); mCallBackupMethod = mHookClass.getMethod(METHOD_NAME_CALL_BACKUP, mActualParameterTypes);
mHookClass.getMethod(METHOD_NAME_SETUP, Member.class, Method.class, XposedBridge.AdditionalHookInfo.class).invoke(null, mMember, mBackupMethod, mHookInfo);
return new HookWrapper.HookEntity(mMember, mHookMethod, mBackupMethod); return new HookWrapper.HookEntity(mMember, mHookMethod, mBackupMethod);
} }
...@@ -246,42 +250,107 @@ public class HookerDexMaker { ...@@ -246,42 +250,107 @@ public class HookerDexMaker {
private void generateFields() { private void generateFields() {
mHookInfoFieldId = mHookerTypeId.getField(hookInfoTypeId, FIELD_NAME_HOOK_INFO); mHookInfoFieldId = mHookerTypeId.getField(hookInfoTypeId, FIELD_NAME_HOOK_INFO);
mMethodFieldId = mHookerTypeId.getField(memberTypeId, FIELD_NAME_METHOD); mMethodFieldId = mHookerTypeId.getField(memberTypeId, FIELD_NAME_METHOD);
mBackupMethodFieldId = mHookerTypeId.getField(methodTypeId, FIELD_NAME_BACKUP_METHOD);
mDexMaker.declare(mHookInfoFieldId, Modifier.STATIC, null); mDexMaker.declare(mHookInfoFieldId, Modifier.STATIC, null);
mDexMaker.declare(mMethodFieldId, Modifier.STATIC, null); mDexMaker.declare(mMethodFieldId, Modifier.STATIC, null);
mDexMaker.declare(mBackupMethodFieldId, Modifier.STATIC, null);
} }
private void generateSetupMethod() { private void generateSetupMethod() {
MethodId<?, Void> setupMethodId = mHookerTypeId.getMethod( MethodId<?, Void> setupMethodId = mHookerTypeId.getMethod(
TypeId.VOID, METHOD_NAME_SETUP, memberTypeId, hookInfoTypeId); TypeId.VOID, METHOD_NAME_SETUP, memberTypeId, methodTypeId, hookInfoTypeId);
Code code = mDexMaker.declare(setupMethodId, Modifier.PUBLIC | Modifier.STATIC); Code code = mDexMaker.declare(setupMethodId, Modifier.PUBLIC | Modifier.STATIC);
// init logic // init logic
// get parameters // get parameters
Local<Member> method = code.getParameter(0, memberTypeId); Local<Member> method = code.getParameter(0, memberTypeId);
Local<XposedBridge.AdditionalHookInfo> hookInfo = code.getParameter(1, hookInfoTypeId); Local<Method> backupMethod = code.getParameter(1, methodTypeId);
Local<XposedBridge.AdditionalHookInfo> hookInfo = code.getParameter(2, hookInfoTypeId);
// save params to static // save params to static
code.sput(mMethodFieldId, method); code.sput(mMethodFieldId, method);
code.sput(mBackupMethodFieldId, backupMethod);
code.sput(mHookInfoFieldId, hookInfo); code.sput(mHookInfoFieldId, hookInfo);
code.returnVoid(); code.returnVoid();
} }
private void generateBackupMethod() { private void generateBackupMethod() {
mBackupMethodId = mHookerTypeId.getMethod(mReturnTypeId, METHOD_NAME_BACKUP, mParameterTypeIds); mBackupMethodId = mHookerTypeId.getMethod(mReturnTypeId, METHOD_NAME_BACKUP, mParameterTypeIds);
mSandHookCallOriginMethodId = TypeId.get(ErrorCatch.class).getMethod(TypeId.get(Object.class), "callOriginError", memberTypeId, methodTypeId, TypeId.get(Object.class), TypeId.get(Object[].class));
MethodId<?, ?> errLogMethod = TypeId.get(DexLog.class).getMethod(TypeId.get(Void.TYPE), "printCallOriginError", TypeId.get(Member.class));
Code code = mDexMaker.declare(mBackupMethodId, Modifier.PUBLIC | Modifier.STATIC); Code code = mDexMaker.declare(mBackupMethodId, Modifier.PUBLIC | Modifier.STATIC);
Local<Member> method = code.newLocal(memberTypeId); Local<Member> method = code.newLocal(memberTypeId);
Local<Method> backupMethod = code.newLocal(methodTypeId);
Local<Object> thisObject = code.newLocal(TypeId.OBJECT);
Local<Object[]> args = code.newLocal(objArrayTypeId);
Local<Integer> actualParamSize = code.newLocal(TypeId.INT);
Local<Integer> argIndex = code.newLocal(TypeId.INT);
Local<Object> resultObj = code.newLocal(TypeId.OBJECT);
Label tryCatchBlock = new Label();
Local[] allArgsLocals = createParameterLocals(code);
Map<TypeId, Local> resultLocals = createResultLocals(code); Map<TypeId, Local> resultLocals = createResultLocals(code);
MethodId<?, ?> errLogMethod = TypeId.get(DexLog.class).getMethod(TypeId.get(Void.TYPE), "printCallOriginError", TypeId.get(Member.class));
//very very important!!!!!!!!!!! //very very important!!!!!!!!!!!
//add a try cache block avoid inline //add a try cache block avoid inline
Label tryCatchBlock = new Label();
code.sget(mMethodFieldId, method);
code.invokeStatic(errLogMethod, null, method);
// start of try // start of try
code.addCatchClause(throwableTypeId, tryCatchBlock); code.addCatchClause(throwableTypeId, tryCatchBlock);
code.sget(mMethodFieldId, method);
code.invokeStatic(errLogMethod, null, method);
//call origin by invoke
code.loadConstant(args, null);
code.loadConstant(argIndex, 0);
code.sget(mBackupMethodFieldId, backupMethod);
int paramsSize = mParameterTypeIds.length;
int offset = 0;
// thisObject
if (mIsStatic) {
// thisObject = null
code.loadConstant(thisObject, null);
} else {
// thisObject = args[0]
offset = 1;
code.move(thisObject, allArgsLocals[0]);
}
// offset = mIsStatic ? 0 : 1;
// for (int i = offset; i < allArgsLocals.length; i++) {
// code.loadConstant(argIndex, i - offset);
// code.aget(resultObj, args, argIndex);
// autoUnboxIfNecessary(code, allArgsLocals[i], resultObj, resultLocals, true);
// }
// actual args (exclude thisObject if this is not a static method)
code.loadConstant(actualParamSize, paramsSize - offset);
code.newArray(args, actualParamSize);
for (int i = offset; i < paramsSize; i++) {
Local parameter = allArgsLocals[i];
// save parameter to resultObj as Object
autoBoxIfNecessary(code, resultObj, parameter);
code.loadConstant(argIndex, i - offset);
// save Object to args
code.aput(args, argIndex, resultObj);
}
if (mReturnTypeId.equals(TypeId.VOID)) {
code.invokeStatic(mSandHookCallOriginMethodId, null, method, backupMethod, thisObject, args);
code.returnVoid();
} else {
code.invokeStatic(mSandHookCallOriginMethodId, resultObj, method, backupMethod, thisObject, args);
TypeId objTypeId = getObjTypeIdIfPrimitive(mReturnTypeId);
Local matchObjLocal = resultLocals.get(objTypeId);
code.cast(matchObjLocal, resultObj);
// have to use matching typed Object(Integer, Double ...) to do unboxing
Local toReturn = resultLocals.get(mReturnTypeId);
autoUnboxIfNecessary(code, toReturn, matchObjLocal, resultLocals, true);
code.returnValue(toReturn);
}
code.mark(tryCatchBlock);
// do nothing // do nothing
if (mReturnTypeId.equals(TypeId.VOID)) { if (mReturnTypeId.equals(TypeId.VOID)) {
code.returnVoid(); code.returnVoid();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment