1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package dexfuzz.program.mutators; 18 19 import dexfuzz.Log; 20 import dexfuzz.MutationStats; 21 import dexfuzz.program.MInsn; 22 import dexfuzz.program.MutatableCode; 23 import dexfuzz.program.Mutation; 24 import dexfuzz.rawdex.Instruction; 25 import dexfuzz.rawdex.Opcode; 26 import dexfuzz.rawdex.OpcodeInfo; 27 28 import java.util.ArrayList; 29 import java.util.List; 30 import java.util.Random; 31 32 public class ArithOpChanger extends CodeMutator { 33 /** 34 * Every CodeMutator has an AssociatedMutation, representing the 35 * mutation that this CodeMutator can perform, to allow separate 36 * generateMutation() and applyMutation() phases, allowing serialization. 37 */ 38 public static class AssociatedMutation extends Mutation { 39 public int arithmeticInsnIdx; 40 public int newOpcode; 41 42 @Override 43 public String getString() { 44 StringBuilder builder = new StringBuilder(); 45 builder.append(arithmeticInsnIdx).append(" "); 46 builder.append(newOpcode); 47 return builder.toString(); 48 } 49 50 @Override 51 public void parseString(String[] elements) { 52 arithmeticInsnIdx = Integer.parseInt(elements[2]); 53 newOpcode = Integer.parseInt(elements[3]); 54 } 55 } 56 57 // The following two methods are here for the benefit of MutationSerializer, 58 // so it can create a CodeMutator and get the correct associated Mutation, as it 59 // reads in mutations from a dump of mutations. 60 @Override 61 public Mutation getNewMutation() { 62 return new AssociatedMutation(); 63 } 64 65 public ArithOpChanger() { } 66 67 public ArithOpChanger(Random rng, MutationStats stats, List<Mutation> mutations) { 68 super(rng, stats, mutations); 69 likelihood = 75; 70 } 71 72 // A cache that should only exist between generateMutation() and applyMutation(), 73 // or be created at the start of applyMutation(), if we're reading in mutations from 74 // a file. 75 private List<MInsn> arithmeticInsns = null; 76 77 private void generateCachedArithmeticInsns(MutatableCode mutatableCode) { 78 if (arithmeticInsns != null) { 79 return; 80 } 81 82 arithmeticInsns = new ArrayList<MInsn>(); 83 84 for (MInsn mInsn : mutatableCode.getInstructions()) { 85 if (isArithmeticOperation(mInsn)) { 86 arithmeticInsns.add(mInsn); 87 } 88 } 89 } 90 91 @Override 92 protected boolean canMutate(MutatableCode mutatableCode) { 93 for (MInsn mInsn : mutatableCode.getInstructions()) { 94 if (isArithmeticOperation(mInsn)) { 95 return true; 96 } 97 } 98 99 Log.debug("No arithmetic operations in method, skipping..."); 100 return false; 101 } 102 103 @Override 104 protected Mutation generateMutation(MutatableCode mutatableCode) { 105 generateCachedArithmeticInsns(mutatableCode); 106 107 int arithmeticInsnIdx = rng.nextInt(arithmeticInsns.size()); 108 109 MInsn randomInsn = arithmeticInsns.get(arithmeticInsnIdx); 110 111 OpcodeInfo oldOpcodeInfo = randomInsn.insn.info; 112 113 OpcodeInfo newOpcodeInfo = oldOpcodeInfo; 114 115 while (newOpcodeInfo.value == oldOpcodeInfo.value) { 116 newOpcodeInfo = Instruction.getOpcodeInfo(getLegalDifferentOpcode(randomInsn)); 117 } 118 119 AssociatedMutation mutation = new AssociatedMutation(); 120 mutation.setup(this.getClass(), mutatableCode); 121 mutation.arithmeticInsnIdx = arithmeticInsnIdx; 122 mutation.newOpcode = newOpcodeInfo.value; 123 return mutation; 124 } 125 126 @Override 127 protected void applyMutation(Mutation uncastMutation) { 128 // Cast the Mutation to our AssociatedMutation, so we can access its fields. 129 AssociatedMutation mutation = (AssociatedMutation) uncastMutation; 130 MutatableCode mutatableCode = mutation.mutatableCode; 131 132 generateCachedArithmeticInsns(mutatableCode); 133 134 MInsn randomInsn = arithmeticInsns.get(mutation.arithmeticInsnIdx); 135 136 String oldInsnString = randomInsn.toString(); 137 138 OpcodeInfo newOpcodeInfo = Instruction.getOpcodeInfo(mutation.newOpcode); 139 140 randomInsn.insn.info = newOpcodeInfo; 141 142 Log.info("Changed " + oldInsnString + " to " + randomInsn); 143 144 stats.incrementStat("Changed arithmetic opcode"); 145 146 // Clear the cache. 147 arithmeticInsns = null; 148 } 149 150 private boolean isArithmeticOperation(MInsn mInsn) { 151 Opcode opcode = mInsn.insn.info.opcode; 152 if (Opcode.isBetween(opcode, Opcode.ADD_INT, Opcode.USHR_INT_LIT8)) { 153 return true; 154 } 155 return false; 156 } 157 158 private Opcode getLegalDifferentOpcode(MInsn mInsn) { 159 Opcode opcode = mInsn.insn.info.opcode; 160 161 for (List<Opcode> opcodeList : opcodeLists) { 162 Opcode first = opcodeList.get(0); 163 Opcode last = opcodeList.get(opcodeList.size() - 1); 164 if (Opcode.isBetween(opcode, first, last)) { 165 int newOpcodeIdx = rng.nextInt(opcodeList.size()); 166 return opcodeList.get(newOpcodeIdx); 167 } 168 } 169 170 return opcode; 171 } 172 173 private static List<Opcode> intOpcodes = new ArrayList<Opcode>(); 174 private static List<Opcode> int2addrOpcodes = new ArrayList<Opcode>(); 175 private static List<Opcode> longOpcodes = new ArrayList<Opcode>(); 176 private static List<Opcode> long2addrOpcodes = new ArrayList<Opcode>(); 177 private static List<Opcode> floatOpcodes = new ArrayList<Opcode>(); 178 private static List<Opcode> float2addrOpcodes = new ArrayList<Opcode>(); 179 private static List<Opcode> doubleOpcodes = new ArrayList<Opcode>(); 180 private static List<Opcode> double2addrOpcodes = new ArrayList<Opcode>(); 181 private static List<Opcode> intLit8Opcodes = new ArrayList<Opcode>(); 182 private static List<Opcode> intLit16Opcodes = new ArrayList<Opcode>(); 183 private static List<List<Opcode>> opcodeLists = new ArrayList<List<Opcode>>(); 184 185 static { 186 intOpcodes.add(Opcode.ADD_INT); 187 intOpcodes.add(Opcode.SUB_INT); 188 intOpcodes.add(Opcode.MUL_INT); 189 intOpcodes.add(Opcode.DIV_INT); 190 intOpcodes.add(Opcode.REM_INT); 191 intOpcodes.add(Opcode.AND_INT); 192 intOpcodes.add(Opcode.OR_INT); 193 intOpcodes.add(Opcode.XOR_INT); 194 intOpcodes.add(Opcode.SHL_INT); 195 intOpcodes.add(Opcode.SHR_INT); 196 intOpcodes.add(Opcode.USHR_INT); 197 198 int2addrOpcodes.add(Opcode.ADD_INT_2ADDR); 199 int2addrOpcodes.add(Opcode.SUB_INT_2ADDR); 200 int2addrOpcodes.add(Opcode.MUL_INT_2ADDR); 201 int2addrOpcodes.add(Opcode.DIV_INT_2ADDR); 202 int2addrOpcodes.add(Opcode.REM_INT_2ADDR); 203 int2addrOpcodes.add(Opcode.AND_INT_2ADDR); 204 int2addrOpcodes.add(Opcode.OR_INT_2ADDR); 205 int2addrOpcodes.add(Opcode.XOR_INT_2ADDR); 206 int2addrOpcodes.add(Opcode.SHL_INT_2ADDR); 207 int2addrOpcodes.add(Opcode.SHR_INT_2ADDR); 208 int2addrOpcodes.add(Opcode.USHR_INT_2ADDR); 209 210 longOpcodes.add(Opcode.ADD_LONG); 211 longOpcodes.add(Opcode.SUB_LONG); 212 longOpcodes.add(Opcode.MUL_LONG); 213 longOpcodes.add(Opcode.DIV_LONG); 214 longOpcodes.add(Opcode.REM_LONG); 215 longOpcodes.add(Opcode.AND_LONG); 216 longOpcodes.add(Opcode.OR_LONG); 217 longOpcodes.add(Opcode.XOR_LONG); 218 longOpcodes.add(Opcode.SHL_LONG); 219 longOpcodes.add(Opcode.SHR_LONG); 220 longOpcodes.add(Opcode.USHR_LONG); 221 222 long2addrOpcodes.add(Opcode.ADD_LONG_2ADDR); 223 long2addrOpcodes.add(Opcode.SUB_LONG_2ADDR); 224 long2addrOpcodes.add(Opcode.MUL_LONG_2ADDR); 225 long2addrOpcodes.add(Opcode.DIV_LONG_2ADDR); 226 long2addrOpcodes.add(Opcode.REM_LONG_2ADDR); 227 long2addrOpcodes.add(Opcode.AND_LONG_2ADDR); 228 long2addrOpcodes.add(Opcode.OR_LONG_2ADDR); 229 long2addrOpcodes.add(Opcode.XOR_LONG_2ADDR); 230 long2addrOpcodes.add(Opcode.SHL_LONG_2ADDR); 231 long2addrOpcodes.add(Opcode.SHR_LONG_2ADDR); 232 long2addrOpcodes.add(Opcode.USHR_LONG_2ADDR); 233 234 floatOpcodes.add(Opcode.ADD_FLOAT); 235 floatOpcodes.add(Opcode.SUB_FLOAT); 236 floatOpcodes.add(Opcode.MUL_FLOAT); 237 floatOpcodes.add(Opcode.DIV_FLOAT); 238 floatOpcodes.add(Opcode.REM_FLOAT); 239 240 float2addrOpcodes.add(Opcode.ADD_FLOAT_2ADDR); 241 float2addrOpcodes.add(Opcode.SUB_FLOAT_2ADDR); 242 float2addrOpcodes.add(Opcode.MUL_FLOAT_2ADDR); 243 float2addrOpcodes.add(Opcode.DIV_FLOAT_2ADDR); 244 float2addrOpcodes.add(Opcode.REM_FLOAT_2ADDR); 245 246 doubleOpcodes.add(Opcode.ADD_DOUBLE); 247 doubleOpcodes.add(Opcode.SUB_DOUBLE); 248 doubleOpcodes.add(Opcode.MUL_DOUBLE); 249 doubleOpcodes.add(Opcode.DIV_DOUBLE); 250 doubleOpcodes.add(Opcode.REM_DOUBLE); 251 252 double2addrOpcodes.add(Opcode.ADD_DOUBLE_2ADDR); 253 double2addrOpcodes.add(Opcode.SUB_DOUBLE_2ADDR); 254 double2addrOpcodes.add(Opcode.MUL_DOUBLE_2ADDR); 255 double2addrOpcodes.add(Opcode.DIV_DOUBLE_2ADDR); 256 double2addrOpcodes.add(Opcode.REM_DOUBLE_2ADDR); 257 258 intLit8Opcodes.add(Opcode.ADD_INT_LIT8); 259 intLit8Opcodes.add(Opcode.RSUB_INT_LIT8); 260 intLit8Opcodes.add(Opcode.MUL_INT_LIT8); 261 intLit8Opcodes.add(Opcode.DIV_INT_LIT8); 262 intLit8Opcodes.add(Opcode.REM_INT_LIT8); 263 intLit8Opcodes.add(Opcode.AND_INT_LIT8); 264 intLit8Opcodes.add(Opcode.OR_INT_LIT8); 265 intLit8Opcodes.add(Opcode.XOR_INT_LIT8); 266 intLit8Opcodes.add(Opcode.SHL_INT_LIT8); 267 intLit8Opcodes.add(Opcode.SHR_INT_LIT8); 268 intLit8Opcodes.add(Opcode.USHR_INT_LIT8); 269 270 intLit16Opcodes.add(Opcode.ADD_INT_LIT16); 271 intLit16Opcodes.add(Opcode.RSUB_INT); 272 intLit16Opcodes.add(Opcode.MUL_INT_LIT16); 273 intLit16Opcodes.add(Opcode.DIV_INT_LIT16); 274 intLit16Opcodes.add(Opcode.REM_INT_LIT16); 275 intLit16Opcodes.add(Opcode.AND_INT_LIT16); 276 intLit16Opcodes.add(Opcode.OR_INT_LIT16); 277 intLit16Opcodes.add(Opcode.XOR_INT_LIT16); 278 279 opcodeLists.add(intOpcodes); 280 opcodeLists.add(longOpcodes); 281 opcodeLists.add(floatOpcodes); 282 opcodeLists.add(doubleOpcodes); 283 opcodeLists.add(int2addrOpcodes); 284 opcodeLists.add(long2addrOpcodes); 285 opcodeLists.add(float2addrOpcodes); 286 opcodeLists.add(double2addrOpcodes); 287 opcodeLists.add(intLit8Opcodes); 288 opcodeLists.add(intLit16Opcodes); 289 } 290 } 291