diff options
6 files changed, 307 insertions, 1 deletions
diff --git a/tools/dexfuzz/README b/tools/dexfuzz/README index 78f73f5c11..3c0c65e7e2 100644 --- a/tools/dexfuzz/README +++ b/tools/dexfuzz/README @@ -139,7 +139,9 @@ InstructionDuplicator 80 InstructionSwapper 80 NewMethodCaller 10 NonsenseStringPrinter 10 +OppositeBranchChanger 40 PoolIndexChanger 30 +RandomBranchChanger 30 RandomInstructionGenerator 30 SwitchBranchShifter 30 TryBlockShifter 40 diff --git a/tools/dexfuzz/src/dexfuzz/DexFuzz.java b/tools/dexfuzz/src/dexfuzz/DexFuzz.java index 3b2875482e..41ce7b2706 100644 --- a/tools/dexfuzz/src/dexfuzz/DexFuzz.java +++ b/tools/dexfuzz/src/dexfuzz/DexFuzz.java @@ -34,7 +34,7 @@ import dexfuzz.listeners.UpdatingConsoleListener; */ public class DexFuzz { private static int majorVersion = 1; - private static int minorVersion = 1; + private static int minorVersion = 2; private static int seedChangeVersion = 0; /** diff --git a/tools/dexfuzz/src/dexfuzz/program/Program.java b/tools/dexfuzz/src/dexfuzz/program/Program.java index 286fe5221e..e550d30308 100644 --- a/tools/dexfuzz/src/dexfuzz/program/Program.java +++ b/tools/dexfuzz/src/dexfuzz/program/Program.java @@ -32,7 +32,9 @@ import dexfuzz.program.mutators.InstructionDuplicator; import dexfuzz.program.mutators.InstructionSwapper; import dexfuzz.program.mutators.NewMethodCaller; import dexfuzz.program.mutators.NonsenseStringPrinter; +import dexfuzz.program.mutators.OppositeBranchChanger; import dexfuzz.program.mutators.PoolIndexChanger; +import dexfuzz.program.mutators.RandomBranchChanger; import dexfuzz.program.mutators.RandomInstructionGenerator; import dexfuzz.program.mutators.SwitchBranchShifter; import dexfuzz.program.mutators.TryBlockShifter; @@ -199,7 +201,9 @@ public class Program { registerMutator(new InstructionSwapper(rng, mutationStats, mutations)); registerMutator(new NewMethodCaller(rng, mutationStats, mutations)); registerMutator(new NonsenseStringPrinter(rng, mutationStats, mutations)); + registerMutator(new OppositeBranchChanger(rng, mutationStats, mutations)); registerMutator(new PoolIndexChanger(rng, mutationStats, mutations)); + registerMutator(new RandomBranchChanger(rng, mutationStats, mutations)); registerMutator(new RandomInstructionGenerator(rng, mutationStats, mutations)); registerMutator(new SwitchBranchShifter(rng, mutationStats, mutations)); registerMutator(new TryBlockShifter(rng, mutationStats, mutations)); diff --git a/tools/dexfuzz/src/dexfuzz/program/mutators/IfBranchChanger.java b/tools/dexfuzz/src/dexfuzz/program/mutators/IfBranchChanger.java new file mode 100644 index 0000000000..872b29730c --- /dev/null +++ b/tools/dexfuzz/src/dexfuzz/program/mutators/IfBranchChanger.java @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 dexfuzz.program.mutators; + +import dexfuzz.Log; +import dexfuzz.MutationStats; +import dexfuzz.program.MInsn; +import dexfuzz.program.MutatableCode; +import dexfuzz.program.Mutation; +import dexfuzz.rawdex.Instruction; +import dexfuzz.rawdex.Opcode; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + * This class mutates the comparison operator of the if + * statements by taking in a random instruction, checking whether + * it is an if statement and, if so, changing the comparison + * operator. The inheriting classes implement the way comparison + * operator changes. For example, by choosing the opposite + * comparison operator or by choosing a random comparison operator. + */ +public abstract class IfBranchChanger extends CodeMutator { + /** + * Every CodeMutator has an AssociatedMutation, representing the + * mutation that this CodeMutator can perform, to allow separate + * generateMutation() and applyMutation() phases, allowing serialization. + */ + public static class AssociatedMutation extends Mutation { + public int ifBranchInsnIdx; + + @Override + public String getString() { + return Integer.toString(ifBranchInsnIdx); + } + + @Override + public void parseString(String[] elements) { + ifBranchInsnIdx = Integer.parseInt(elements[2]); + } + } + + // The following two methods are here for the benefit of MutationSerializer, + // so it can create a CodeMutator and get the correct associated Mutation, as it + // reads in mutations from a dump of mutations. + @Override + public Mutation getNewMutation() { + return new AssociatedMutation(); + } + + public IfBranchChanger() { } + + public IfBranchChanger(Random rng, MutationStats stats, List<Mutation> mutations) { + super(rng, stats, mutations); + } + + // A cache that should only exist between generateMutation() and applyMutation(), + // or be created at the start of applyMutation(), if we're reading in mutations from + // a file. + private List<MInsn> ifBranchInsns = null; + + private void generateCachedifBranchInsns(MutatableCode mutatableCode) { + if (ifBranchInsns != null) { + return; + } + + ifBranchInsns = new ArrayList<MInsn>(); + + for (MInsn mInsn : mutatableCode.getInstructions()) { + if (isIfBranchOperation(mInsn)) { + ifBranchInsns.add(mInsn); + } + } + } + + @Override + protected boolean canMutate(MutatableCode mutatableCode) { + for (MInsn mInsn : mutatableCode.getInstructions()) { + if (isIfBranchOperation(mInsn)) { + return true; + } + } + + Log.debug("No if branch operation, skipping..."); + return false; + } + + @Override + protected Mutation generateMutation(MutatableCode mutatableCode) { + generateCachedifBranchInsns(mutatableCode); + + int ifBranchInsnIdx = rng.nextInt(ifBranchInsns.size()); + + AssociatedMutation mutation = new AssociatedMutation(); + mutation.setup(this.getClass(), mutatableCode); + mutation.ifBranchInsnIdx = ifBranchInsnIdx; + return mutation; + } + + @Override + protected void applyMutation(Mutation uncastMutation) { + AssociatedMutation mutation = (AssociatedMutation) uncastMutation; + MutatableCode mutatableCode = mutation.mutatableCode; + + generateCachedifBranchInsns(mutatableCode); + + MInsn ifBranchInsn = ifBranchInsns.get(mutation.ifBranchInsnIdx); + + String oldInsnString = ifBranchInsn.toString(); + + Opcode newOpcode = getModifiedOpcode(ifBranchInsn); + + ifBranchInsn.insn.info = Instruction.getOpcodeInfo(newOpcode); + + Log.info("Changed " + oldInsnString + " to " + ifBranchInsn); + + stats.incrementStat("Changed if branch operator to " + getMutationTag() + " operator"); + + // Clear cache. + ifBranchInsns = null; + } + + /** + * Get a different if branch instruction. + * @return opcode of the new comparison operator. + */ + protected abstract Opcode getModifiedOpcode(MInsn mInsn); + + /** + * Get the tag of the mutation that fired. + * @return string tag of the type of mutation used + */ + protected abstract String getMutationTag(); + + private boolean isIfBranchOperation(MInsn mInsn) { + Opcode opcode = mInsn.insn.info.opcode; + if (Opcode.isBetween(opcode, Opcode.IF_EQ, Opcode.IF_LEZ)) { + return true; + } + return false; + } +}
\ No newline at end of file diff --git a/tools/dexfuzz/src/dexfuzz/program/mutators/OppositeBranchChanger.java b/tools/dexfuzz/src/dexfuzz/program/mutators/OppositeBranchChanger.java new file mode 100644 index 0000000000..cb25b641cc --- /dev/null +++ b/tools/dexfuzz/src/dexfuzz/program/mutators/OppositeBranchChanger.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 dexfuzz.program.mutators; + +import dexfuzz.Log; +import dexfuzz.MutationStats; +import dexfuzz.program.MInsn; +import dexfuzz.program.Mutation; +import dexfuzz.rawdex.Opcode; +import java.util.List; +import java.util.Random; + +public class OppositeBranchChanger extends IfBranchChanger { + + public OppositeBranchChanger(Random rng, MutationStats stats, List<Mutation> mutations) { + super(rng, stats, mutations); + likelihood = 40; + } + + @Override + protected Opcode getModifiedOpcode(MInsn mInsn) { + Opcode opcode = mInsn.insn.info.opcode; + switch (opcode) { + case IF_EQ: + return Opcode.IF_NE; + case IF_NE: + return Opcode.IF_EQ; + case IF_LT: + return Opcode.IF_GE; + case IF_GT: + return Opcode.IF_LE; + case IF_GE: + return Opcode.IF_LT; + case IF_LE: + return Opcode.IF_GT; + case IF_EQZ: + return Opcode.IF_NEZ; + case IF_NEZ: + return Opcode.IF_EQZ; + case IF_LTZ: + return Opcode.IF_GEZ; + case IF_GTZ: + return Opcode.IF_LEZ; + case IF_GEZ: + return Opcode.IF_LTZ; + case IF_LEZ: + return Opcode.IF_GTZ; + default: + Log.errorAndQuit("Could not find if branch."); + return opcode; + } + } + + @Override + protected String getMutationTag() { + return "opposite"; + } +}
\ No newline at end of file diff --git a/tools/dexfuzz/src/dexfuzz/program/mutators/RandomBranchChanger.java b/tools/dexfuzz/src/dexfuzz/program/mutators/RandomBranchChanger.java new file mode 100644 index 0000000000..fc42c2ed6f --- /dev/null +++ b/tools/dexfuzz/src/dexfuzz/program/mutators/RandomBranchChanger.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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 dexfuzz.program.mutators; + +import dexfuzz.MutationStats; +import dexfuzz.program.MInsn; +import dexfuzz.program.Mutation; +import dexfuzz.rawdex.Opcode; +import java.util.List; +import java.util.Random; + +public class RandomBranchChanger extends IfBranchChanger { + + private static final Opcode[] EQUALITY_CMP_OP_LIST = { + Opcode.IF_EQ, + Opcode.IF_NE, + Opcode.IF_LT, + Opcode.IF_GE, + Opcode.IF_GT, + Opcode.IF_LE + }; + + private static final Opcode[] ZERO_CMP_OP_LIST = { + Opcode.IF_EQZ, + Opcode.IF_NEZ, + Opcode.IF_LTZ, + Opcode.IF_GEZ, + Opcode.IF_GTZ, + Opcode.IF_LEZ + }; + + public RandomBranchChanger(Random rng, MutationStats stats, List<Mutation> mutations) { + super(rng, stats, mutations); + likelihood = 30; + } + + @Override + protected Opcode getModifiedOpcode(MInsn mInsn) { + Opcode opcode = mInsn.insn.info.opcode; + if (Opcode.isBetween(opcode, Opcode.IF_EQ, Opcode.IF_LE)) { + int index = opcode.ordinal() - Opcode.IF_EQ.ordinal(); + int length = EQUALITY_CMP_OP_LIST.length; + return EQUALITY_CMP_OP_LIST[(index + 1 + rng.nextInt(length - 1)) % length]; + } else if (Opcode.isBetween(opcode, Opcode.IF_EQZ, Opcode.IF_LEZ)) { + int index = opcode.ordinal() - Opcode.IF_EQZ.ordinal(); + int length = ZERO_CMP_OP_LIST.length; + return ZERO_CMP_OP_LIST[(index + 1 + rng.nextInt(length - 1)) % length]; + } + return opcode; + } + + @Override + protected String getMutationTag() { + return "random"; + } +}
\ No newline at end of file |