public void BwIndexInMemoryAddress() { // samples of switch statement emitted // by the Microsoft VC compiler var ebp = m.Frame.EnsureRegister(Registers.ebp); var eax = m.Frame.EnsureRegister(Registers.eax); var edx = m.Frame.EnsureRegister(Registers.edx); // cmp [ebp-66],1D m.Assign(SCZO, m.Cond(m.ISub(m.Mem32(m.ISub(ebp, 0xC4)), 0x1D))); var block0 = m.CurrentBlock; m.BranchIf(new TestCondition(ConditionCode.UGT, SCZO), "default"); // mov edx,[ebp-66] // movzx eax,byte ptr [edx + 0x10000] // jmp [eax + 0x12000] m.Assign(edx, m.Mem32(m.ISub(ebp, 0xC4))); m.Assign(eax, m.Convert(m.Mem8(m.IAdd(edx, 0x10000)), PrimitiveType.Byte, PrimitiveType.Word32)); var xfer = new RtlGoto(m.Mem32(m.IAdd(eax, 0x12000)), InstrClass.Transfer); var block1 = m.CurrentBlock; var bw = new Backwalker <Block, Instruction>(host, xfer, expSimp); var ret = bw.BackwalkInstructions(Registers.eax, block1); Assert.AreEqual("None", bw.Index.ToString()); Assert.AreEqual("Mem0[ebp - 0xC4<32>:word32]", bw.IndexExpression.ToString()); Assert.AreEqual(4, bw.JumpSize); Assert.IsTrue(ret); ret = bw.BackwalkInstructions(null, block0); }
public void BwInvertedCondition() { var ebx = m.Reg32("ebx", 3); var eax = m.Reg32("eax", 0); var CZ = m.Flags("CZ"); m.Assign(CZ, m.Cond(m.ISub(ebx, 0x30))); m.BranchIf(m.Test(ConditionCode.ULE, CZ), "do_switch"); m.Goto("default_case"); m.Label("do_switch"); m.Assign(eax, 0); var block = m.CurrentBlock; var xfer = new RtlGoto(m.Mem32(m.IAdd(Constant.Word32(0x00123400), m.IMul(ebx, 4))), RtlClass.Transfer); m.Label("default_case"); m.Return(); var bw = new Backwalker <Block, Instruction>(host, xfer, expSimp); Assert.IsTrue(bw.CanBackwalk()); var ops = bw.BackWalk(block); Assert.AreEqual(3, ops.Count); Assert.AreEqual("cmp 48", ops[0].ToString()); Assert.AreEqual("branch UGT", ops[1].ToString()); Assert.AreEqual("* 4", ops[2].ToString()); }
/// <summary> /// RtlGoto transfers control to either a constant destination or /// a variable destination computed at run-time. /// </summary> /// <param name="g"></param> /// <returns></returns> public bool VisitGoto(RtlGoto g) { scanner.TerminateBlock(blockCur, ric.Address + ric.Length); var addrTarget = g.Target as Address; if (addrTarget != null) { var blockTarget = BlockFromAddress(ric.Address, addrTarget, blockCur.Procedure, state); var blockSource = scanner.FindContainingBlock(ric.Address); EnsureEdge(blockSource.Procedure, blockSource, blockTarget); return(false); } var mem = g.Target as MemoryAccess; if (mem != null) { if (mem.EffectiveAddress is Constant) { // jmp [address] var site = state.OnBeforeCall(this.stackReg, 4); //$BUGBUG: hard coded. Emit(new CallInstruction(g.Target, site)); Emit(new ReturnInstruction()); blockCur.Procedure.ControlGraph.AddEdge(blockCur, blockCur.Procedure.ExitBlock); return(false); } } ProcessIndirectControlTransfer(ric.Address, g); return(false); }
public void BwDetectIndexRegister() { var edx = m.Frame.EnsureRegister(Registers.edx); var xfer = new RtlGoto(m.Mem32(m.IAdd(m.Word32(0x10001234), m.IMul(edx, 4))), InstrClass.Transfer); var bw = new Backwalker <Block, Instruction>(host, xfer, expSimp); Assert.AreSame(Registers.edx, bw.Index); }
public SlicerResult VisitGoto(RtlGoto go) { var sr = go.Target.Accept(this, BackwardSlicerContext.Cond(RangeOf(go.Target))); if (JumpTableFormat == null) { JumpTableFormat = go.Target; } return(sr); }
public void BwLoadDirect() { var r1 = m.Reg32("r1", 1); m.Assign(r1, m.Mem32(Constant.Word32(0x00123400))); var xfer = new RtlGoto(m.Mem32(m.IAdd(Constant.Word32(0x00113300), m.IMul(r1, 8))), InstrClass.Transfer); var bw = new Backwalker<Block, Instruction>(host, xfer, expSimp); Assert.IsTrue(bw.CanBackwalk()); var ops = bw.BackWalk(m.Block); Assert.IsNull(ops, "Should have reported missing guard."); }
/// <summary> /// RtlGoto transfers control to either a constant destination or /// a variable destination computed at run-time. /// </summary> /// <param name="g"></param> /// <returns></returns> public bool VisitGoto(RtlGoto g) { var blockFrom = blockCur; if ((g.Class & RtlClass.Delay) != 0) { // Get next instruction cluster. rtlStream.MoveNext(); ProcessRtlCluster(rtlStream.Current); } scanner.TerminateBlock(blockCur, rtlStream.Current.Address + ric.Length); var addrTarget = g.Target as Address; if (addrTarget != null) { var blockTarget = BlockFromAddress(ric.Address, addrTarget, blockCur.Procedure, state); var blockSource = blockCur.IsSynthesized ? blockCur : scanner.FindContainingBlock(ric.Address); EnsureEdge(blockSource.Procedure, blockSource, blockTarget); if (ric.Address == addrTarget) { var bt = BlockFromAddress(ric.Address, addrTarget, blockCur.Procedure, state); EnsureEdge(blockSource.Procedure, blockFrom, bt); } return(false); } CallSite site; var mem = g.Target as MemoryAccess; if (mem != null) { if (mem.EffectiveAddress is Constant) { // jmp [address] site = state.OnBeforeCall(this.stackReg, 4); //$BUGBUG: hard coded. Emit(new CallInstruction(g.Target, site)); Emit(new ReturnInstruction()); blockCur.Procedure.ControlGraph.AddEdge(blockCur, blockCur.Procedure.ExitBlock); return(false); } } if (ProcessIndirectControlTransfer(ric.Address, g)) { return(false); } site = state.OnBeforeCall(this.stackReg, 4); //$BUGBUG: hard coded Emit(new CallInstruction(g.Target, site)); Emit(new ReturnInstruction()); blockCur.Procedure.ControlGraph.AddEdge(blockCur, blockCur.Procedure.ExitBlock); return(false); }
public void BwZeroExtend() { var rax = m.Reg64("rax", 0); var eax = m.Reg32("eax", 0); var al = m.Reg8("al", 0); var ecx = m.Reg32("ecx", 1); var CZ = m.Flags("CZ"); m.Assign(eax, m.Mem8(rax)); m.Assign(CZ, m.Cond(m.ISub(al, 0x78))); m.BranchIf(m.Test(ConditionCode.UGT, CZ), "ldefault"); m.Assign(ecx, m.Cast(PrimitiveType.Word32, al)); var xfer = new RtlGoto(m.Mem32(m.IAdd(Constant.Word32(0x00411F40), m.IMul(ecx, 8))), InstrClass.Transfer); var bw = new Backwalker<Block, Instruction>(host, xfer, expSimp); Assert.IsTrue(bw.CanBackwalk()); var ops = bw.BackWalk(m.Block); Assert.AreEqual(3, ops.Count); Assert.AreEqual("cmp 120", ops[0].ToString()); Assert.AreEqual("branch UGT", ops[1].ToString()); Assert.AreEqual("* 8", ops[2].ToString()); }
public void BwSignExtension() { var CVZNX = m.Flags("CVZNS"); var CVZN = m.Flags("CVZN"); var VZN = m.Flags("VZN"); var d1 = m.Reg32("d1", 1); var v80 = m.Temp(PrimitiveType.Word32, "v80"); var v82 = m.Temp(PrimitiveType.Word16, "v82"); m.Assign(v80, m.ISub(d1, 0x28)); m.Assign(CVZN, m.Cond(v80)); m.BranchIf(m.Test(ConditionCode.GT, VZN), "default_label"); m.Assign(d1, m.IAdd(d1, d1)); m.Assign(CVZNX, m.Cond(d1)); m.Assign(v82, m.Mem16(m.IAdd(m.Word32(0x001066A4), d1))); m.Assign(d1, m.Dpb(d1, v82, 0)); m.Assign(CVZN, m.Cond(v82)); var block = m.CurrentBlock; var xfer = new RtlGoto( m.IAdd( m.Word32(0x001066A2), m.Cast(PrimitiveType.Int32, m.Cast(PrimitiveType.Int16, d1))), RtlClass.Transfer); m.Label("default_case"); m.Return(); var bw = new Backwalker <Block, Instruction>(host, xfer, expSimp); Assert.IsTrue(bw.CanBackwalk()); var ops = bw.BackWalk(block); Assert.AreEqual(3, ops.Count); Assert.AreEqual("cmp 48", ops[0].ToString()); Assert.AreEqual("branch UGT", ops[1].ToString()); Assert.AreEqual("* 4", ops[2].ToString()); }
public RtlInstruction Goto(uint target) { var g = new RtlGoto(Address.Ptr32(target), RtlClass.Transfer); return(Emit(g)); }
public RtlInstruction Goto(uint target) { var g = new RtlGoto(Address.Ptr32(target), RtlClass.Transfer); return Emit(g); }
public void BwIndexInMemoryAddress() { // samples of switch statement emitted // by the Microsoft VC compiler var ebp = m.Frame.EnsureRegister(Registers.ebp); var eax = m.Frame.EnsureRegister(Registers.eax); var edx = m.Frame.EnsureRegister(Registers.edx); // cmp [ebp-66],1D m.Assign(SCZO, m.Cond(m.ISub(m.LoadDw(m.ISub(ebp, 0xC4)), 0x1D))); var block0 = m.CurrentBlock; m.BranchIf(new TestCondition(ConditionCode.UGT, SCZO), "default"); // mov edx,[ebp-66] // movzx eax,byte ptr [edx + 0x10000] // jmp [eax + 0x12000] m.Assign(edx, m.LoadDw(m.ISub(ebp, 0xC4))); m.Assign(eax, m.Cast(PrimitiveType.Word32, m.LoadB(m.IAdd(edx, 0x10000)))); var xfer = new RtlGoto(m.LoadDw(m.IAdd(eax, 0x12000)), RtlClass.Transfer); var block1 = m.CurrentBlock; var bw = new Backwalker(host, xfer, expSimp); var ret = bw.BackwalkInstructions(Registers.eax, block1); Assert.AreEqual("None", bw.Index.ToString()); Assert.AreEqual("Mem0[ebp - 0x000000C4:word32]", bw.IndexExpression.ToString()); Assert.AreEqual(4, bw.JumpSize); Assert.IsTrue(ret); ret = bw.BackwalkInstructions(null, block0); }
public void BwDetectIndexRegister() { var edx = m.Frame.EnsureRegister(Registers.edx); var xfer = new RtlGoto(m.LoadDw(m.IAdd(m.Word32(0x10001234), m.IMul(edx, 4))), RtlClass.Transfer); var bw = new Backwalker(host, xfer, expSimp); Assert.AreSame(Registers.edx, bw.Index); }
/// <summary> /// RtlGoto transfers control to either a constant destination or /// a variable destination computed at run-time. /// </summary> /// <param name="g"></param> /// <returns></returns> public bool VisitGoto(RtlGoto g) { var blockFrom = blockCur; if ((g.Class & RtlClass.Delay) != 0) { // Get next instruction cluster. rtlStream.MoveNext(); ProcessRtlCluster(rtlStream.Current); } CallSite site; scanner.TerminateBlock(blockCur, rtlStream.Current.Address + ric.Length); var addrTarget = g.Target as Address; if (addrTarget != null) { var impProc = scanner.GetImportedProcedure(addrTarget, this.ric.Address); if (impProc != null) { site = state.OnBeforeCall(stackReg, arch.PointerType.Size); var sig = impProc.Signature; var chr = impProc.Characteristics; if (chr != null && chr.IsAlloca) { return(ProcessAlloca(site, impProc)); } EmitCall(CreateProcedureConstant(impProc), sig, chr, site); Emit(new ReturnInstruction()); blockCur.Procedure.ControlGraph.AddEdge(blockCur, blockCur.Procedure.ExitBlock); return(false); } if (!program.SegmentMap.IsValidAddress(addrTarget)) { var jmpSite = state.OnBeforeCall(stackReg, arch.PointerType.Size); GenerateCallToOutsideProcedure(jmpSite, addrTarget); Emit(new ReturnInstruction()); blockCur.Procedure.ControlGraph.AddEdge(blockCur, blockCur.Procedure.ExitBlock); return(false); } var blockTarget = BlockFromAddress(ric.Address, addrTarget, blockCur.Procedure, state); var blockSource = blockCur.IsSynthesized ? blockCur : scanner.FindContainingBlock(ric.Address); EnsureEdge(blockSource.Procedure, blockSource, blockTarget); if (ric.Address == addrTarget) { var bt = BlockFromAddress(ric.Address, addrTarget, blockCur.Procedure, state); EnsureEdge(blockSource.Procedure, blockFrom, bt); } if (blockCur.Statements.Count == 0) { //$REVIEW: we insert a statement into empty blocks to satisfy the BlockHasBeenScanned // predicate. This should be done in a better way; perhaps by keeping track // of scanned blocks in the Scanner class? // The recursive scanning of basic blocks does need improvement; // consider using a similar technique to Shingle scanner, where reachable // statements are collected first, and basic blocks reconstructed afterwards. Emit(new GotoInstruction(addrTarget)); } return(false); } var mem = g.Target as MemoryAccess; if (mem != null) { if (mem.EffectiveAddress is Constant) { // jmp [address] site = state.OnBeforeCall(this.stackReg, 4); //$BUGBUG: hard coded. Emit(new CallInstruction(g.Target, site)); Emit(new ReturnInstruction()); blockCur.Procedure.ControlGraph.AddEdge(blockCur, blockCur.Procedure.ExitBlock); return(false); } } if (ProcessIndirectControlTransfer(ric.Address, g)) { return(false); } site = state.OnBeforeCall(this.stackReg, 4); //$BUGBUG: hard coded Emit(new CallInstruction(g.Target, site)); Emit(new ReturnInstruction()); blockCur.Procedure.ControlGraph.AddEdge(blockCur, blockCur.Procedure.ExitBlock); return(false); }
/// <summary> /// RtlGoto transfers control to either a constant destination or /// a variable destination computed at run-time. /// </summary> /// <param name="g"></param> /// <returns></returns> public bool VisitGoto(RtlGoto g) { var blockFrom = blockCur; if ((g.Class & RtlClass.Delay) != 0) { // Get next instruction cluster. rtlStream.MoveNext(); ProcessRtlCluster(rtlStream.Current); } CallSite site; scanner.TerminateBlock(blockCur, rtlStream.Current.Address + ric.Length); var addrTarget = g.Target as Address; if (addrTarget != null) { var impProc = scanner.GetImportedProcedure(addrTarget, this.ric.Address); if (impProc != null) { site = state.OnBeforeCall(stackReg, arch.PointerType.Size); var sig = impProc.Signature; var chr = impProc.Characteristics; if (chr != null && chr.IsAlloca) { return(ProcessAlloca(site, impProc)); } EmitCall(CreateProcedureConstant(impProc), sig, chr, site); Emit(new ReturnInstruction()); blockCur.Procedure.ControlGraph.AddEdge(blockCur, blockCur.Procedure.ExitBlock); return(false); } if (!program.SegmentMap.IsValidAddress(addrTarget)) { var jmpSite = state.OnBeforeCall(stackReg, arch.PointerType.Size); GenerateCallToOutsideProcedure(jmpSite, addrTarget); Emit(new ReturnInstruction()); blockCur.Procedure.ControlGraph.AddEdge(blockCur, blockCur.Procedure.ExitBlock); return(false); } var trampoline = scanner.GetTrampoline(addrTarget); if (trampoline != null) { var jmpSite = state.OnBeforeCall(stackReg, arch.PointerType.Size); var sig = trampoline.Signature; var chr = trampoline.Characteristics; // Adjust stack to "hide" any pushed return value since // currently Reko treats the return value as an implicit detail // of the calling convention. Had the x86 rewriter explicity // generated code to predecrement the stack pointer // when encountering CALL instructions this would // not be necessary. if (sig.ReturnAddressOnStack != 0) { Emit(new Assignment(stackReg, new BinaryExpression( Operator.IAdd, stackReg.DataType, stackReg, Constant.Word(stackReg.DataType.Size, sig.ReturnAddressOnStack)))); } EmitCall(CreateProcedureConstant(trampoline), sig, chr, jmpSite); if (sig.ReturnAddressOnStack != 0) { //$TODO: make x86 calls' implicit storage explicit // to avoid this hacky dance, Emit(new Assignment(stackReg, new BinaryExpression( Operator.ISub, stackReg.DataType, stackReg, Constant.Word(stackReg.DataType.Size, sig.ReturnAddressOnStack)))); } Emit(new ReturnInstruction()); blockCur.Procedure.ControlGraph.AddEdge(blockCur, blockCur.Procedure.ExitBlock); return(false); } var blockTarget = BlockFromAddress(ric.Address, addrTarget, blockCur.Procedure, state); var blockSource = blockCur.IsSynthesized ? blockCur : scanner.FindContainingBlock(ric.Address); EnsureEdge(blockSource.Procedure, blockSource, blockTarget); if (ric.Address == addrTarget) { var bt = BlockFromAddress(ric.Address, addrTarget, blockCur.Procedure, state); EnsureEdge(blockSource.Procedure, blockFrom, bt); } if (blockCur.Statements.Count == 0) { //$REVIEW: we insert a statement into empty blocks to satisfy the BlockHasBeenScanned // predicate. This should be done in a better way; perhaps by keeping track // of scanned blocks in the Scanner class? // The recursive scanning of basic blocks does need improvement; // consider using a similar technique to Shingle scanner, where reachable // statements are collected first, and basic blocks reconstructed afterwards. Emit(new GotoInstruction(addrTarget)); } return(false); } if (g.Target is MemoryAccess mem) { if (mem.EffectiveAddress is Constant) { // jmp [address] site = state.OnBeforeCall(this.stackReg, 4); //$BUGBUG: hard coded. Emit(new CallInstruction(g.Target, site)); Emit(new ReturnInstruction()); blockCur.Procedure.ControlGraph.AddEdge(blockCur, blockCur.Procedure.ExitBlock); return(false); } } if (ProcessIndirectControlTransfer(ric.Address, g)) { return(false); } site = state.OnBeforeCall(this.stackReg, 4); //$BUGBUG: hard coded Emit(new CallInstruction(g.Target, site)); Emit(new ReturnInstruction()); blockCur.Procedure.ControlGraph.AddEdge(blockCur, blockCur.Procedure.ExitBlock); return(false); }