/* * Copyright (C) 2012 Sony Mobile Communications AB * * This file is part of ApkAnalyser. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package andreflect.injection; import java.util.ArrayList; import jerl.bcm.inj.Injection; import org.jf.dexlib.FieldIdItem; import org.jf.dexlib.Code.FiveRegisterInstruction; import org.jf.dexlib.Code.Instruction; import org.jf.dexlib.Code.InstructionWithReference; import org.jf.dexlib.Code.Opcode; import org.jf.dexlib.Code.RegisterRangeInstruction; import org.jf.dexlib.Code.SingleRegisterInstruction; import org.jf.dexlib.Code.ThreeRegisterInstruction; import org.jf.dexlib.Code.TwoRegisterInstruction; import andreflect.DexMethod; import andreflect.injection.abs.DalvikInjectionMethod; import andreflect.injection.abs.DalvikInjectionMethodField; import andreflect.injection.abs.DalvikInjectionMethodLocal; import andreflect.injection.abs.DalvikInjectionMethodOffset; public class DalvikCodeItemVisitor { public static void visit(DalvikInjectionMethod injection, DexMethod method, DalvikInjectCollection ic) { if (injection.performed == true) { return; } int type = injection.getInjectionType(); boolean isInRange = false; if (method.getEncodedMethod() != null && method.getEncodedMethod().codeItem != null) { Instruction[] instructions = method.getEncodedMethod().codeItem.getInstructions(); for (Instruction instruction : instructions) { if (instruction.isInject() == false) { if (type == Injection.METHOD_ENTRY_INJECTION) { ArrayList<Instruction> injectInstructions = injection.injectDalvik(ic, method, instruction); DalvikBytecodeModificationMediator.injectInsturctionsAtInstruction(method, instruction, injectInstructions); break; } else if (type == Injection.METHOD_OFFSET_INJECTION && (((DalvikInjectionMethodOffset) injection).getOffsetInstruction() == null || instruction == ((DalvikInjectionMethodOffset) injection).getOffsetInstruction())) { ArrayList<Instruction> injectInstructions = injection.injectDalvik(ic, method, instruction); DalvikBytecodeModificationMediator.injectInsturctionsAtInstruction(method, instruction, injectInstructions); break; } else if (type == Injection.METHOD_LOCAL_ACCESS_INJECTION) { DalvikInjectionMethodLocal localInjection = (DalvikInjectionMethodLocal) injection; if (instruction == (localInjection.beginIns)) { isInRange = true; } if (isInRange) { if (localInjection.isRead) { if (checkRegisterUsedForRead(instruction.deodexedInstruction, localInjection.reg)) { ArrayList<Instruction> injectInstructions = injection.injectDalvik(ic, method, instruction); DalvikBytecodeModificationMediator.injectInsturctionsAtInstruction(method, instruction, injectInstructions); } } else { if (instruction.opcode.setsRegister() && localInjection.reg == ((SingleRegisterInstruction) instruction).getRegisterA() && instruction.opcode != Opcode.NEW_INSTANCE) { ArrayList<Instruction> injectInstructions = injection.injectDalvik(ic, method, instruction); DalvikBytecodeModificationMediator.injectInsturctionsAtNextInstruction(method, instruction, injectInstructions); } } } if (instruction == (localInjection.endIns)) { isInRange = false; } } else { switch (instruction.deodexedInstruction.opcode) { case RETURN_VOID: case RETURN: case RETURN_WIDE: case RETURN_OBJECT: if (type == Injection.METHOD_EXIT_INJECTION) { ArrayList<Instruction> injectInstructions = injection.injectDalvik(ic, method, instruction); DalvikBytecodeModificationMediator.injectInsturctionsAtInstruction(method, instruction, injectInstructions); } break; case IGET: case IGET_WIDE: case IGET_OBJECT: case IGET_BOOLEAN: case IGET_BYTE: case IGET_CHAR: case IGET_SHORT: case SGET: case SGET_WIDE: case SGET_OBJECT: case SGET_BOOLEAN: case SGET_BYTE: case SGET_CHAR: case SGET_SHORT: /* case IGET_QUICK: case IGET_WIDE_QUICK: case IGET_OBJECT_QUICK: //for gingerbread case IGET_VOLATILE: case IGET_WIDE_VOLATILE: case IGET_OBJECT_VOLATILE: case SGET_VOLATILE: case SGET_WIDE_VOLATILE: case SGET_OBJECT_VOLATILE: */ if (type == Injection.METHOD_FIELD_ACCESS_INJECTION) { DalvikInjectionMethodField fieldInjection = (DalvikInjectionMethodField) injection; InstructionWithReference refIns = (InstructionWithReference) instruction.deodexedInstruction; FieldIdItem refFieldIdItem = (FieldIdItem) refIns.getReferencedItem(); if (fieldInjection.isRead == true && (fieldInjection.fieldIdItem == null || fieldInjection.fieldIdItem == refFieldIdItem)) { ArrayList<Instruction> injectInstructions = injection.injectDalvik(ic, method, instruction); DalvikBytecodeModificationMediator.injectInsturctionsAtNextInstruction(method, instruction, injectInstructions); } } break; case IPUT: case IPUT_WIDE: case IPUT_OBJECT: case IPUT_BOOLEAN: case IPUT_BYTE: case IPUT_CHAR: case IPUT_SHORT: case SPUT: case SPUT_WIDE: case SPUT_OBJECT: case SPUT_BOOLEAN: case SPUT_BYTE: case SPUT_CHAR: case SPUT_SHORT: /* case IPUT_QUICK: case IPUT_WIDE_QUICK: case IPUT_OBJECT_QUICK: //for gingerbread case IPUT_VOLATILE: case IPUT_WIDE_VOLATILE: case IPUT_OBJECT_VOLATILE: case SPUT_VOLATILE: case SPUT_WIDE_VOLATILE: case SPUT_OBJECT_VOLATILE: */ if (type == Injection.METHOD_FIELD_ACCESS_INJECTION) { DalvikInjectionMethodField fieldInjection = (DalvikInjectionMethodField) injection; InstructionWithReference refIns = (InstructionWithReference) instruction.deodexedInstruction; FieldIdItem refFieldIdItem = (FieldIdItem) refIns.getReferencedItem(); if (fieldInjection.isRead == false && (fieldInjection.fieldIdItem == null || fieldInjection.fieldIdItem == refFieldIdItem)) { ArrayList<Instruction> injectInstructions = injection.injectDalvik(ic, method, instruction); DalvikBytecodeModificationMediator.injectInsturctionsAtInstruction(method, instruction, injectInstructions); } } break; } } } } } injection.performed = true; } public static boolean checkRegisterUsedForRead(Instruction instruction, short register) { boolean ret = false; if (instruction.opcode.setsRegister() && register == ((SingleRegisterInstruction) instruction).getRegisterA()) { return false; } if (instruction.opcode.setsResult() == true) { return false; } if (instruction instanceof RegisterRangeInstruction) { RegisterRangeInstruction ins = (RegisterRangeInstruction) instruction; short count = (short) ins.getRegCount(); int startReg = ins.getStartRegister(); if (register >= startReg && register <= startReg + count) { ret = true; } } else if (instruction instanceof FiveRegisterInstruction) { FiveRegisterInstruction ins = (FiveRegisterInstruction) instruction; short regCount = (short) ins.getRegCount(); switch (regCount) { case 1: ret = (ins.getRegisterD() == register || ret) ? true : false; break; case 2: ret = (ins.getRegisterD() == register || ret) ? true : false; ret = (ins.getRegisterE() == register || ret) ? true : false; break; case 3: ret = (ins.getRegisterD() == register || ret) ? true : false; ret = (ins.getRegisterE() == register || ret) ? true : false; ret = (ins.getRegisterF() == register || ret) ? true : false; break; case 4: ret = (ins.getRegisterD() == register || ret) ? true : false; ret = (ins.getRegisterE() == register || ret) ? true : false; ret = (ins.getRegisterF() == register || ret) ? true : false; ret = (ins.getRegisterG() == register || ret) ? true : false; break; case 5: ret = (ins.getRegisterD() == register || ret) ? true : false; ret = (ins.getRegisterE() == register || ret) ? true : false; ret = (ins.getRegisterF() == register || ret) ? true : false; ret = (ins.getRegisterG() == register || ret) ? true : false; ret = (ins.getRegisterA() == register || ret) ? true : false; break; } } else if (instruction instanceof ThreeRegisterInstruction) { ThreeRegisterInstruction ins = (ThreeRegisterInstruction) instruction; ret = (ins.getRegisterA() == register || ret) ? true : false; ret = (ins.getRegisterB() == register || ret) ? true : false; ret = (ins.getRegisterC() == register || ret) ? true : false; } else if (instruction instanceof TwoRegisterInstruction) { TwoRegisterInstruction ins = (TwoRegisterInstruction) instruction; ret = (ins.getRegisterA() == register || ret) ? true : false; ret = (ins.getRegisterB() == register || ret) ? true : false; } else if (instruction instanceof SingleRegisterInstruction) { SingleRegisterInstruction ins = (SingleRegisterInstruction) instruction; ret = (ins.getRegisterA() == register || ret) ? true : false; } return ret; } }