• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.formats.ContainsVRegs;
25 
26 import java.util.ArrayList;
27 import java.util.List;
28 import java.util.Random;
29 
30 public class VRegChanger extends CodeMutator {
31   /**
32    * Every CodeMutator has an AssociatedMutation, representing the
33    * mutation that this CodeMutator can perform, to allow separate
34    * generateMutation() and applyMutation() phases, allowing serialization.
35    */
36   public static class AssociatedMutation extends Mutation {
37     public int vregInsnIdx;
38     public int mutatingVreg;
39     public int newVregValue;
40 
41     @Override
getString()42     public String getString() {
43       StringBuilder builder = new StringBuilder();
44       builder.append(vregInsnIdx).append(" ");
45       builder.append(mutatingVreg).append(" ");
46       builder.append(newVregValue);
47       return builder.toString();
48     }
49 
50     @Override
parseString(String[] elements)51     public void parseString(String[] elements) {
52       vregInsnIdx = Integer.parseInt(elements[2]);
53       mutatingVreg = Integer.parseInt(elements[3]);
54       newVregValue = Integer.parseInt(elements[4]);
55     }
56   }
57 
58   // The following two methods are here for the benefit of MutationSerializer,
59   // so it can create a CodeMutator and get the correct associated Mutation, as it
60   // reads in mutations from a dump of mutations.
61   @Override
getNewMutation()62   public Mutation getNewMutation() {
63     return new AssociatedMutation();
64   }
65 
VRegChanger()66   public VRegChanger() { }
67 
VRegChanger(Random rng, MutationStats stats, List<Mutation> mutations)68   public VRegChanger(Random rng, MutationStats stats, List<Mutation> mutations) {
69     super(rng, stats, mutations);
70     likelihood = 60;
71   }
72 
73   // A cache that should only exist between generateMutation() and applyMutation(),
74   // or be created at the start of applyMutation(), if we're reading in mutations from
75   // a file.
76   private List<MInsn> vregInsns = null;
77 
generateCachedVRegInsns(MutatableCode mutatableCode)78   private void generateCachedVRegInsns(MutatableCode mutatableCode) {
79     if (vregInsns != null) {
80       return;
81     }
82 
83     vregInsns = new ArrayList<MInsn>();
84     for (MInsn mInsn : mutatableCode.getInstructions()) {
85       if (mInsn.insn.info.format instanceof ContainsVRegs) {
86         vregInsns.add(mInsn);
87       }
88     }
89   }
90 
91   @Override
canMutate(MutatableCode mutatableCode)92   protected boolean canMutate(MutatableCode mutatableCode) {
93     if (mutatableCode.registersSize < 2) {
94       Log.debug("Impossible to change vregs in a method with fewer than 2 registers.");
95       return false;
96     }
97 
98     for (MInsn mInsn : mutatableCode.getInstructions()) {
99       if (mInsn.insn.info.format instanceof ContainsVRegs) {
100         return true;
101       }
102     }
103 
104     return false;
105   }
106 
107   @Override
generateMutation(MutatableCode mutatableCode)108   protected Mutation generateMutation(MutatableCode mutatableCode) {
109     generateCachedVRegInsns(mutatableCode);
110 
111     // Pick a random vreg instruction.
112     int vregInsnIdx = rng.nextInt(vregInsns.size());
113     MInsn vregInsn = vregInsns.get(vregInsnIdx);
114 
115     // Get the number of VRegs this instruction uses.
116     int numVregs = ((ContainsVRegs)vregInsn.insn.info.format).getVRegCount();
117 
118     // Pick which vreg to mutate.
119     int mutatingVreg = rng.nextInt(numVregs);
120 
121     // Find the old index.
122     int oldVregValue = 0;
123 
124     switch (mutatingVreg) {
125       case 0:
126         oldVregValue = (int) vregInsn.insn.vregA;
127         break;
128       case 1:
129         oldVregValue = (int) vregInsn.insn.vregB;
130         break;
131       case 2:
132         oldVregValue = (int) vregInsn.insn.vregC;
133         break;
134       default:
135         Log.errorAndQuit("Invalid number of vregs reported by a Format.");
136     }
137 
138     // Search for a new vreg value.
139     int newVregValue = oldVregValue;
140     while (newVregValue == oldVregValue) {
141       newVregValue = rng.nextInt(mutatableCode.registersSize);
142     }
143 
144     AssociatedMutation mutation = new AssociatedMutation();
145     mutation.setup(this.getClass(), mutatableCode);
146     mutation.vregInsnIdx = vregInsnIdx;
147     mutation.mutatingVreg = mutatingVreg;
148     mutation.newVregValue = newVregValue;
149     return mutation;
150   }
151 
152   @Override
applyMutation(Mutation uncastMutation)153   protected void applyMutation(Mutation uncastMutation) {
154     // Cast the Mutation to our AssociatedMutation, so we can access its fields.
155     AssociatedMutation mutation = (AssociatedMutation) uncastMutation;
156     MutatableCode mutatableCode = mutation.mutatableCode;
157 
158     generateCachedVRegInsns(mutatableCode);
159 
160     MInsn vregInsn = vregInsns.get(mutation.vregInsnIdx);
161 
162     // Remember what the instruction used to look like.
163     String oldInsnString = vregInsn.toString();
164 
165     int oldVregValue = 0;
166 
167     String vregId = "A";
168     switch (mutation.mutatingVreg) {
169       case 0:
170         oldVregValue = (int) vregInsn.insn.vregA;
171         vregInsn.insn.vregA = (long) mutation.newVregValue;
172         break;
173       case 1:
174         oldVregValue = (int) vregInsn.insn.vregB;
175         vregInsn.insn.vregB = (long) mutation.newVregValue;
176         vregId = "B";
177         break;
178       case 2:
179         oldVregValue = (int) vregInsn.insn.vregC;
180         vregInsn.insn.vregC = (long) mutation.newVregValue;
181         vregId = "C";
182         break;
183       default:
184         Log.errorAndQuit("Invalid number of vregs specified in a VRegChanger mutation.");
185     }
186 
187     Log.info("In " + oldInsnString + " changed v" + vregId + ": v" + oldVregValue
188         + " to v" + mutation.newVregValue);
189 
190     stats.incrementStat("Changed a virtual register");
191 
192     // Clear cache.
193     vregInsns = null;
194   }
195 }
196