Fix modification of args array being ignored when calling "backup" method

This commit is contained in:
solohsu 2019-01-21 23:55:52 +08:00
parent f1c9b21ca7
commit af4feada27
2 changed files with 47 additions and 19 deletions

View File

@ -44,44 +44,63 @@ public class DexMakerUtils {
} }
} }
public static void autoUnboxIfNecessary(Code code, Local target, Local source) { public static void autoUnboxIfNecessary(Code code, Local target, Local source,
Map<TypeId, Local> tmpLocals, boolean castObj) {
String unboxMethod; String unboxMethod;
TypeId typeId = target.getType(); TypeId typeId = target.getType();
TypeId<?> boxTypeId; TypeId<?> boxTypeId;
if (typeId.equals(TypeId.BOOLEAN)) { if (typeId.equals(TypeId.BOOLEAN)) {
unboxMethod = "booleanValue"; unboxMethod = "booleanValue";
boxTypeId = TypeId.get(Boolean.class); boxTypeId = TypeId.get("Ljava/lang/Boolean;");
code.invokeVirtual(boxTypeId.getMethod(TypeId.BOOLEAN, unboxMethod), target, source); Local boxTypedLocal = tmpLocals.get(boxTypeId);
code.cast(boxTypedLocal, source);
code.invokeVirtual(boxTypeId.getMethod(TypeId.BOOLEAN, unboxMethod), target, boxTypedLocal);
} else if (typeId.equals(TypeId.BYTE)) { } else if (typeId.equals(TypeId.BYTE)) {
unboxMethod = "byteValue"; unboxMethod = "byteValue";
boxTypeId = TypeId.get(Byte.class); boxTypeId = TypeId.get("Ljava/lang/Byte;");
code.invokeVirtual(boxTypeId.getMethod(TypeId.BYTE, unboxMethod), target, source); Local boxTypedLocal = tmpLocals.get(boxTypeId);
code.cast(boxTypedLocal, source);
code.invokeVirtual(boxTypeId.getMethod(TypeId.BYTE, unboxMethod), target, boxTypedLocal);
} else if (typeId.equals(TypeId.CHAR)) { } else if (typeId.equals(TypeId.CHAR)) {
unboxMethod = "charValue"; unboxMethod = "charValue";
boxTypeId = TypeId.get(Character.class); boxTypeId = TypeId.get("Ljava/lang/Character;");
code.invokeVirtual(boxTypeId.getMethod(TypeId.CHAR, unboxMethod), target, source); Local boxTypedLocal = tmpLocals.get(boxTypeId);
code.cast(boxTypedLocal, source);
code.invokeVirtual(boxTypeId.getMethod(TypeId.CHAR, unboxMethod), target, boxTypedLocal);
} else if (typeId.equals(TypeId.DOUBLE)) { } else if (typeId.equals(TypeId.DOUBLE)) {
unboxMethod = "doubleValue"; unboxMethod = "doubleValue";
boxTypeId = TypeId.get(Double.class); boxTypeId = TypeId.get("Ljava/lang/Double;");
code.invokeVirtual(boxTypeId.getMethod(TypeId.DOUBLE, unboxMethod), target, source); Local boxTypedLocal = tmpLocals.get(boxTypeId);
code.cast(boxTypedLocal, source);
code.invokeVirtual(boxTypeId.getMethod(TypeId.DOUBLE, unboxMethod), target, boxTypedLocal);
} else if (typeId.equals(TypeId.FLOAT)) { } else if (typeId.equals(TypeId.FLOAT)) {
unboxMethod = "floatValue"; unboxMethod = "floatValue";
boxTypeId = TypeId.get(Float.class); boxTypeId = TypeId.get("Ljava/lang/Float;");
code.invokeVirtual(boxTypeId.getMethod(TypeId.FLOAT, unboxMethod), target, source); Local boxTypedLocal = tmpLocals.get(boxTypeId);
code.cast(boxTypedLocal, source);
code.invokeVirtual(boxTypeId.getMethod(TypeId.FLOAT, unboxMethod), target, boxTypedLocal);
} else if (typeId.equals(TypeId.INT)) { } else if (typeId.equals(TypeId.INT)) {
unboxMethod = "intValue"; unboxMethod = "intValue";
boxTypeId = TypeId.get(Integer.class); boxTypeId = TypeId.get("Ljava/lang/Integer;");
code.invokeVirtual(boxTypeId.getMethod(TypeId.INT, unboxMethod), target, source); Local boxTypedLocal = tmpLocals.get(boxTypeId);
code.cast(boxTypedLocal, source);
code.invokeVirtual(boxTypeId.getMethod(TypeId.INT, unboxMethod), target, boxTypedLocal);
} else if (typeId.equals(TypeId.LONG)) { } else if (typeId.equals(TypeId.LONG)) {
unboxMethod = "longValue"; unboxMethod = "longValue";
boxTypeId = TypeId.get(Long.class); boxTypeId = TypeId.get("Ljava/lang/Long;");
code.invokeVirtual(boxTypeId.getMethod(TypeId.LONG, unboxMethod), target, source); Local boxTypedLocal = tmpLocals.get(boxTypeId);
code.cast(boxTypedLocal, source);
code.invokeVirtual(boxTypeId.getMethod(TypeId.LONG, unboxMethod), target, boxTypedLocal);
} else if (typeId.equals(TypeId.SHORT)) { } else if (typeId.equals(TypeId.SHORT)) {
unboxMethod = "shortValue"; unboxMethod = "shortValue";
boxTypeId = TypeId.get(Short.class); boxTypeId = TypeId.get("Ljava/lang/Short;");
code.invokeVirtual(boxTypeId.getMethod(TypeId.SHORT, unboxMethod), target, source); Local boxTypedLocal = tmpLocals.get(boxTypeId);
code.cast(boxTypedLocal, source);
code.invokeVirtual(boxTypeId.getMethod(TypeId.SHORT, unboxMethod), target, boxTypedLocal);
} else if (typeId.equals(TypeId.VOID)) { } else if (typeId.equals(TypeId.VOID)) {
code.loadConstant(target, null); code.loadConstant(target, null);
} else if (castObj){
code.cast(target, source);
} else { } else {
code.move(target, source); code.move(target, source);
} }

View File

@ -311,7 +311,7 @@ public class HookerDexMaker {
Local<Object> callbackObj = code.newLocal(TypeId.OBJECT); Local<Object> callbackObj = code.newLocal(TypeId.OBJECT);
Local<XC_MethodHook> callback = code.newLocal(callbackTypeId); Local<XC_MethodHook> callback = code.newLocal(callbackTypeId);
Local<Object> resultObj = code.newLocal(TypeId.OBJECT); Local<Object> resultObj = code.newLocal(TypeId.OBJECT); // as a temp Local
Local<Integer> one = code.newLocal(TypeId.INT); Local<Integer> one = code.newLocal(TypeId.INT);
Local<Object> nullObj = code.newLocal(TypeId.OBJECT); Local<Object> nullObj = code.newLocal(TypeId.OBJECT);
Local<Throwable> throwable = code.newLocal(throwableTypeId); Local<Throwable> throwable = code.newLocal(throwableTypeId);
@ -435,6 +435,15 @@ public class HookerDexMaker {
// try to call backup // try to call backup
// try start // try start
code.addCatchClause(throwableTypeId, tryOrigCatch); code.addCatchClause(throwableTypeId, tryOrigCatch);
// we have to load args[] to paramLocals
// because args[] may be changed in beforeHookedMethod
// should consider first param is thisObj if hooked method is not static
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);
}
// get pre-created Local with a matching typeId // get pre-created Local with a matching typeId
if (mReturnTypeId.equals(TypeId.VOID)) { if (mReturnTypeId.equals(TypeId.VOID)) {
code.invokeStatic(mBackupMethodId, null, allArgsLocals); code.invokeStatic(mBackupMethodId, null, allArgsLocals);
@ -511,7 +520,7 @@ public class HookerDexMaker {
code.cast(matchObjLocal, resultObj); code.cast(matchObjLocal, resultObj);
// have to use matching typed Object(Integer, Double ...) to do unboxing // have to use matching typed Object(Integer, Double ...) to do unboxing
Local toReturn = resultLocals.get(mReturnTypeId); Local toReturn = resultLocals.get(mReturnTypeId);
autoUnboxIfNecessary(code, toReturn, matchObjLocal); autoUnboxIfNecessary(code, toReturn, matchObjLocal, resultLocals, true);
// return // return
code.returnValue(toReturn); code.returnValue(toReturn);
} }