From f9eacc2a2a695a43ae8d1b0e2e3d2b6d827b4a03 Mon Sep 17 00:00:00 2001 From: ghidorahrex Date: Wed, 23 Nov 2022 20:11:27 +0000 Subject: [PATCH 1/3] GP-2872: Added instruction variants for ARM v4/5t bl[x] lr instruction. --- .../data/languages/ARMTHUMBinstructions.sinc | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/Ghidra/Processors/ARM/data/languages/ARMTHUMBinstructions.sinc b/Ghidra/Processors/ARM/data/languages/ARMTHUMBinstructions.sinc index 85dad7d02b..d45e55eee3 100644 --- a/Ghidra/Processors/ARM/data/languages/ARMTHUMBinstructions.sinc +++ b/Ghidra/Processors/ARM/data/languages/ARMTHUMBinstructions.sinc @@ -1443,22 +1443,31 @@ macro th_set_carry_for_asr(op1,shift_count) { @ifndef VERSION_6T2 -:bl^ItCond "#"^off is TMode=1 & ItCond & op11=0x1e & soffset11 [ off = inst_start + 4 + (soffset11 << 12); ] +:bl^ItCond "#"^off is TMode=1 & ItCond & op11=0x1e & soffset11 [ off = inst_start + 4 + (soffset11 << 12); ] { build ItCond; lr = off:4; } -:bl^ItCond "#"^off is TMode=1 & ItCond & op11=0x1f & offset11 [ off = offset11 << 1; ] +:bl^ItCond "#"^off is TMode=1 & ItCond & op11=0x1f & offset11 [ off = offset11 << 1; ] { build ItCond; local dest = lr + off:4; lr = inst_next|1; SetThumbMode(1); - goto [dest]; + call [dest]; } -:blx^ItCond "#"^off is TMode=1 & ItCond & op11=0x1d & offset11 & thc0000=0 [ off = offset11 << 1; ] +:bl^ItCond lr is TMode=1 & ItCond & op11=0x1f & offset11=0 & lr +{ + build ItCond; + local dest = lr; + lr = inst_next|1; + SetThumbMode(1); + call [dest]; +} + +:blx^ItCond "#"^off is TMode=1 & ItCond & op11=0x1d & offset11 & thc0000=0 [ off = offset11 << 1; ] { build ItCond; local dest = (lr & (~0x3)) + off:4; @@ -1466,6 +1475,16 @@ macro th_set_carry_for_asr(op1,shift_count) { SetThumbMode(0); call [dest]; } + +:blx^ItCond lr is TMode=1 & ItCond & op11=0x1d & offset11=0 & thc0000=0 & lr +{ + build ItCond; + local dest = (lr & (~0x3)); + lr = inst_next|1; + SetThumbMode(0); + call [dest]; +} + @endif :bl^ItCond ThAddr24 is TMode=1 & CALLoverride=1 & ItCond & (op11=0x1e; part2c1415=3 & part2c1212=1) & ThAddr24 From 5bf82b8af14df371f32642383451fcb99a17c3d5 Mon Sep 17 00:00:00 2001 From: emteere <47253321+emteere@users.noreply.github.com> Date: Mon, 20 Mar 2023 20:44:59 +0000 Subject: [PATCH 2/3] GP-3217 RISCV JAL/JALR goto/call fix for T0 register --- .../RISCV/data/languages/riscv.ldefs | 22 +++++++++---------- .../RISCV/data/languages/riscv.rv32i.sinc | 20 ++++++++--------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Ghidra/Processors/RISCV/data/languages/riscv.ldefs b/Ghidra/Processors/RISCV/data/languages/riscv.ldefs index d242f70dcd..ab3fbedb3c 100644 --- a/Ghidra/Processors/RISCV/data/languages/riscv.ldefs +++ b/Ghidra/Processors/RISCV/data/languages/riscv.ldefs @@ -6,7 +6,7 @@ endian="little" size="64" variant="RV64I" - version="1.2" + version="1.3" slafile="riscv.lp64d.sla" processorspec="RV64I.pspec" id="RISCV:LE:64:RV64I"> @@ -19,7 +19,7 @@ endian="little" size="64" variant="RV64IC" - version="1.2" + version="1.3" slafile="riscv.lp64d.sla" processorspec="RV64IC.pspec" id="RISCV:LE:64:RV64IC"> @@ -32,7 +32,7 @@ endian="little" size="64" variant="RV64G" - version="1.2" + version="1.3" slafile="riscv.lp64d.sla" processorspec="RV64G.pspec" id="RISCV:LE:64:RV64G"> @@ -45,7 +45,7 @@ endian="little" size="64" variant="RV64GC" - version="1.2" + version="1.3" slafile="riscv.lp64d.sla" processorspec="RV64GC.pspec" id="RISCV:LE:64:RV64GC"> @@ -58,7 +58,7 @@ endian="little" size="64" variant="default" - version="1.2" + version="1.3" slafile="riscv.lp64d.sla" processorspec="RV64GC.pspec" id="RISCV:LE:64:default"> @@ -71,7 +71,7 @@ endian="little" size="32" variant="RV32I" - version="1.2" + version="1.3" slafile="riscv.ilp32d.sla" processorspec="RV32I.pspec" id="RISCV:LE:32:RV32I"> @@ -84,7 +84,7 @@ endian="little" size="32" variant="RV32IC" - version="1.2" + version="1.3" slafile="riscv.ilp32d.sla" processorspec="RV32IC.pspec" id="RISCV:LE:32:RV32IC"> @@ -97,7 +97,7 @@ endian="little" size="32" variant="RV32IMC" - version="1.2" + version="1.3" slafile="riscv.ilp32d.sla" processorspec="RV32IMC.pspec" id="RISCV:LE:32:RV32IMC"> @@ -110,7 +110,7 @@ endian="little" size="32" variant="RV32G" - version="1.2" + version="1.3" slafile="riscv.ilp32d.sla" processorspec="RV32G.pspec" id="RISCV:LE:32:RV32G"> @@ -123,7 +123,7 @@ endian="little" size="32" variant="RV32GC" - version="1.2" + version="1.3" slafile="riscv.ilp32d.sla" processorspec="RV32GC.pspec" id="RISCV:LE:32:RV32GC"> @@ -136,7 +136,7 @@ endian="little" size="32" variant="default" - version="1.2" + version="1.3" slafile="riscv.ilp32d.sla" processorspec="RV32GC.pspec" id="RISCV:LE:32:default"> diff --git a/Ghidra/Processors/RISCV/data/languages/riscv.rv32i.sinc b/Ghidra/Processors/RISCV/data/languages/riscv.rv32i.sinc index c93efef488..0fbdfac2e1 100644 --- a/Ghidra/Processors/RISCV/data/languages/riscv.rv32i.sinc +++ b/Ghidra/Processors/RISCV/data/languages/riscv.rv32i.sinc @@ -123,15 +123,15 @@ } # jal d,a 0000006f 0000007f JSR (0, 0) -# call if RA set, destreg == RA -:jal ra,immUJ is immUJ & ra & r0711=1 & op0001=0x3 & op0204=0x3 & op0506=0x3 +# call for rd = RA|T0 set to inst_next +:jal rd,immUJ is immUJ & rd & (r0711=1 | r0711=5) & op0001=0x3 & op0204=0x3 & op0506=0x3 { - ra = inst_next; + rd = inst_next; call immUJ; } -# goto if RA not set, destreg != RA -:jal rd,immUJ is immUJ & rd & op0001=0x3 & op0204=0x3 & op0506=0x3 +# goto for all other rd set to inst_next +:jal rd,immUJ is immUJ & rd & r0711 & op0001=0x3 & op0204=0x3 & op0506=0x3 { rd = inst_next; goto immUJ; @@ -144,16 +144,16 @@ } # jalr d,s,j 00000067 0000707f JSR (0, 0) -# call if RA set, destreg == RA -:jalr ra,rs1,immI is rs1 & immI & ra & r0711=1 & op0001=0x3 & op0204=0x1 & op0506=0x3 & funct3=0x0 +# call for rd = RA|T0 set to inst_next +:jalr rd,rs1,immI is rs1 & immI & rd & (r0711=1 | r0711=5) & op0001=0x3 & op0204=0x1 & op0506=0x3 & funct3=0x0 { local ea:$(XLEN) = (rs1 + immI) & ~1; - ra = inst_next; + rd = inst_next; call [ea]; } -# goto if RA not set, destreg != RA -:jalr rd,rs1,immI is rs1 & immI & rd & op0001=0x3 & op0204=0x1 & op0506=0x3 & funct3=0x0 +# goto for all other rd set to inst_next +:jalr rd,rs1,immI is rs1 & immI & rd & r0711 & op0001=0x3 & op0204=0x1 & op0506=0x3 & funct3=0x0 { local ea:$(XLEN) = (rs1 + immI) & ~1; rd = inst_next; From 3fca50a7a894f0402da9c6bc632582de463d289b Mon Sep 17 00:00:00 2001 From: emteere <47253321+emteere@users.noreply.github.com> Date: Tue, 21 Mar 2023 17:52:34 -0400 Subject: [PATCH 3/3] GP-3214 Fix duplicate operand references from constant propagation and scalar analyzer --- .../program/util/SymbolicPropogator.java | 30 ++- .../ConstantPropogationReferenceTest.java | 174 ++++++++++++++++-- 2 files changed, 175 insertions(+), 29 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java index 6c892ef9fb..66117e5afa 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java @@ -2486,7 +2486,7 @@ public class SymbolicPropogator { int numOperands = instruction.getNumOperands(); - for (int i = 0; opIndex == Reference.MNEMONIC && i < numOperands; i++) { + for (int i = 0; i < numOperands; i++) { int opType = instruction.getOperandType(i); if ((opType & OperandType.ADDRESS) != 0) { @@ -2496,6 +2496,24 @@ public class SymbolicPropogator { break; } } + if ((opType & OperandType.SCALAR) != 0) { + Scalar s = instruction.getScalar(i); + if (s != null) { + long val = s.getUnsignedValue(); + // sort of a hack, for memory that is not byte addressable + if (val == wordOffset || val == (wordOffset >> 1)) { + opIndex = i; + break; + } + } + } + + // Don't check more complicated operands if already found an operand that matches + // only continue checking for an exact scalar/address operand + if (opIndex != Reference.MNEMONIC) { + continue; + } + // markup the program counter for any flow if ((opType & OperandType.REGISTER) != 0) { Register reg = instruction.getRegister(i); @@ -2519,15 +2537,7 @@ public class SymbolicPropogator { } } } - Scalar s = instruction.getScalar(i); - if (s != null) { - long val = s.getUnsignedValue(); - // sort of a hack, for memory that is not byte addressable - if (val == wordOffset || val == (wordOffset >> 1)) { - opIndex = i; - break; - } - } + if ((opType & OperandType.DYNAMIC) != 0) { List list = instruction.getDefaultOperandRepresentationList(i); int len = list.size(); diff --git a/Ghidra/Features/Base/src/test/java/ghidra/program/util/ConstantPropogationReferenceTest.java b/Ghidra/Features/Base/src/test/java/ghidra/program/util/ConstantPropogationReferenceTest.java index 5cf81f8b33..5641f65d45 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/program/util/ConstantPropogationReferenceTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/program/util/ConstantPropogationReferenceTest.java @@ -17,6 +17,7 @@ package ghidra.program.util; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import java.math.BigInteger; @@ -24,13 +25,17 @@ import org.junit.*; import generic.test.AbstractGenericTest; import ghidra.app.plugin.core.analysis.ConstantPropagationAnalyzer; +import ghidra.app.plugin.core.analysis.ConstantPropagationContextEvaluator; import ghidra.program.database.ProgramBuilder; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSet; import ghidra.program.model.lang.Register; import ghidra.program.model.lang.RegisterValue; import ghidra.program.model.listing.*; +import ghidra.program.model.pcode.Varnode; import ghidra.program.model.symbol.Reference; +import ghidra.program.util.SymbolicPropogator.Value; +import ghidra.util.exception.NotFoundException; import ghidra.util.task.TaskMonitor; /** @@ -44,17 +49,18 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest { private ProgramBuilder builder; private Program program; - private int txID; private ConstantPropagationAnalyzer analyzer; public ConstantPropogationReferenceTest() { super(); } - - @Before - public void setUp() throws Exception { + + @Test + public void testOperandRef_MIPS6432() throws Exception { + builder = new ProgramBuilder("MIPS_6432", "MIPS:BE:64:64-32addr"); + // lui v0, 0x80a8 // addiu v0, v0, -0xdf0 // sw v0, -0x46e8(gp) @@ -66,17 +72,8 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest { analyzer = new ConstantPropagationAnalyzer(); program = builder.getProgram(); - txID = program.startTransaction("Test"); - } - - @After - public void tearDown() throws Exception { - program.endTransaction(txID, true); - } - - @Test - public void testOperandRef_MIPS6432() throws Exception { - + program.startTransaction("Test"); + Address codeStart = addr("0x80a7f214"); Listing listing = program.getListing(); assertNotNull("Bad instruction disassembly", listing.getInstructionAt(codeStart)); @@ -88,15 +85,154 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest { assertOperandReferenceTo(0, instr, addr("0x80a7f210")); assertNoOperandReference(1, instr); - setRegister(codeStart, 0x90000000L); + setRegister(codeStart, "gp", 0x90000000L); analyze(addressSet); assertOperandReferenceTo(1, instr, addr("0x8fffb918")); } + + @Test + public void testBadAddressOffsetTracking() throws Exception { + + builder = new ProgramBuilder("thunk", ProgramBuilder._MIPS); + + builder.setBytes("0x1000", "3c 1c 00 14 27 9c b3 34 03 99 e0 21 27 bd ff e0" + + "af bc 00 10 3c 07 12 34 24 e7 45 67" + + "ac a7 00 10 3c 06 0a 0b 24 c6 0c 0d" + + "ae 06 00 10 8e 11 00 10 8c b1 00 10" + + "8f b1 00 10 8e 51 00 10 ae 53 00 10" + + "8e 51 00 10" + + "36 92 00 00" + + "8e 51 00 10" + + "8e 92 00 10" + + "3c 11 00 53" + + "8e 51 00 10" + + "03 e0 00 08" + + "27 bd 00 20"); + + //00001000 lui gp,0x14 + //00001004 addiu gp,gp,-0x4ccc + //00001008 addu gp,gp,t9 + //0000100c addiu sp,sp,-0x20 + //00001010 sw gp,0x10(sp) + //00001014 lui a3,0x1234 + //00001018 addiu a3,a3,0x4567 + //0000101c sw a3,0x10(a1) + //00001020 lui a2,0xa0b + //00001024 addiu a2,a2,0xc0d + //00001028 sw a2=>DAT_0a0b0c0d,0x10(s0) + //0000102c lw s1,0x10(s0) + //00001030 lw s1,0x10(a1) + //00001034 lw s1,0x10(sp) + //00001038 lw s1,0x10(s2) + //0000103c sw s3,0x10(s2) + //00001040 lw s1,0x10(s2) + //00001044 ori s2,s4,0x0 + //00001048 lw s1,0x10(s2) + //0000104c lw s2,0x10(s4) + //00001050 lui s1=>DAT_00530000,0x53 + //00001054 lw s1,0x10(s2) + //00001058 jr ra + //0000105c _addiu sp,sp,0x20 + + builder.disassemble("0x1000", 88, false); + + builder.createFunction("0x1000"); + + analyzer = new ConstantPropagationAnalyzer(); + + program = builder.getProgram(); + program.startTransaction("Test"); + + Address codeStart = addr("0x1000"); + Listing listing = program.getListing(); + assertNotNull("Bad instruction disassembly", listing.getInstructionAt(codeStart)); + + setRegister(addr("0x1000"), "gp", 0x11200000); + + // follow all flows building up context + // use context to fill out addresses on certain instructions + ContextEvaluator eval = new ConstantPropagationContextEvaluator(true) { + @Override + public boolean evaluateContextBefore(VarnodeContext context, Instruction instr) { + + // TODO Auto-generated method stub + return super.evaluateContextBefore(context, instr); + } + + private Varnode regValue(VarnodeContext context, String regName) { + return context.getRegisterVarnodeValue(context.getRegister(regName)); + } + + @Override + public boolean evaluateContext(VarnodeContext context, Instruction instr) { + String loc = instr.getMinAddress().toString(); + Varnode registerVarnode; + + switch(loc) { + case "00001010": + // gp should be 0x14 + t9 offset space + registerVarnode = regValue(context,"gp"); + assertTrue("symbolic value", context.isSymbol(registerVarnode)); + assertEquals("(t9, 0x13b334, 4)", registerVarnode.toString()); + break; + // TODO: more tests + } + return super.evaluateContext(context, instr); + } + }; + + setRegister(addr("0x1000"), "s1", 0); + SymbolicPropogator symEval = new SymbolicPropogator(program); + + Function func = program.getFunctionManager().getFunctionAt(builder.addr(0x1000)); + + symEval.flowConstants(codeStart, func.getBody(), eval, true, TaskMonitor.DUMMY); + + Value registerValue = symEval.getRegisterValue(addr("0x1010"), null); + } + + @Test + public void testCorrectOperandConstantParam_X86_64() throws Exception { + + builder = new ProgramBuilder("thunk", ProgramBuilder._X64, "gcc", this); + + // PUSH RBP + // MOV RBP,RSP + // MOV EDI,s_STRING_%s_%s_00040100 + // MOV EAX,0x0 + // CALL FUN_0004003d + // LEAVE + // RET + + builder.setBytes("0x00040000", + "55 48 89 e5 bf 00 01 04 00 b8 00 00 00 00 66 67 e8 2a 00 c9 c3"); + + builder.setBytes("0x00040100", + "53 54 52 49 4e 47 20 25 73 20 25 73 0a 00 00"); + + builder.disassemble("0x00040000", 21); + + analyzer = new ConstantPropagationAnalyzer(); + + program = builder.getProgram(); + program.startTransaction("Test"); + + Address codeStart = addr("0x00040000"); + Listing listing = program.getListing(); + assertNotNull("Bad instruction disassembly", listing.getInstructionAt(codeStart)); + + AddressSet addressSet = new AddressSet(codeStart, codeStart.add(21)); + analyze(addressSet); + + Instruction instr = listing.getInstructionAt(addr("0x00040004")); + assertNoOperandReference(0, instr); + assertOperandReferenceTo(1, instr, addr("0x00040100")); + } private void assertNoOperandReference(int opIndex, Instruction instr) { - Reference[] refs = instr.getOperandReferences(1); + Reference[] refs = instr.getOperandReferences(opIndex); assertEquals("No reference on operand " + opIndex, 0, refs.length); } @@ -110,9 +246,9 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest { analyzer.added(program, addrs, TaskMonitor.DUMMY, null); } - private void setRegister(Address a, long value) throws Exception { + private void setRegister(Address a, String regname, long value) throws Exception { ProgramContext context = program.getProgramContext(); - Register gp = context.getRegister("gp"); + Register gp = context.getRegister(regname); context.setRegisterValue(a, a.add(12), new RegisterValue(gp, BigInteger.valueOf(value))); }