public Backwalker(IBackWalkHost host, RtlTransfer xfer, ExpressionSimplifier eval) { if (xfer is RtlGoto) //$DEBUG { xfer.ToString(); } this.host = host; this.eval = eval; var target = xfer.Target; var seq = xfer.Target as MkSequence; if (seq != null) { target = seq.Tail; } var mem = target as MemoryAccess; if (mem == null) { Index = RegisterOf(target as Identifier); } else { Index = DetermineIndexRegister(mem); } Operations = new List <BackwalkOperation>(); }
private void RunTest(IntelArchitecture arch, RtlTransfer rtlTransfer, string outputFile) { using (var fut = new FileUnitTester(outputFile)) { m.Procedure.Write(false, fut.TextWriter); fut.TextWriter.Flush(); var ibw = new Backwalker <Block, Instruction>(host, rtlTransfer, expSimp); var bwoList = ibw.BackWalk(m.CurrentBlock); Assert.IsNotNull(bwoList); foreach (BackwalkOperation bwo in bwoList) { fut.TextWriter.WriteLine(bwo); } fut.TextWriter.WriteLine("Index register: {0}", ibw.Index); fut.AssertFilesEqual(); } }
public Backwalker(IBackWalkHost <TBlock, TInstr> host, RtlTransfer xfer, ExpressionSimplifier eval) { this.host = host; this.eval = eval; var target = xfer.Target; if (xfer.Target is MkSequence seq && seq.Expressions.Length == 2) { target = seq.Expressions[1]; } if (target is MemoryAccess mem) { Index = DetermineIndexRegister(mem); } else { Index = RegisterOf(target as Identifier); } Operations = new List <BackwalkOperation>(); JumpSize = target.DataType.Size; }
public Backwalker(IBackWalkHost host, RtlTransfer xfer, ExpressionSimplifier eval) { if (xfer is RtlGoto) //$DEBUG xfer.ToString(); this.host = host; this.eval = eval; var target = xfer.Target; var seq = xfer.Target as MkSequence; if (seq != null) { target = seq.Tail; } var mem = target as MemoryAccess; if (mem == null) { Index = RegisterOf(target as Identifier); } else { Index = DetermineIndexRegister(mem); } Operations = new List<BackwalkOperation>(); }
public Backwalker(IBackWalkHost <TBlock, TInstr> host, RtlTransfer xfer, ExpressionSimplifier eval) { this.host = host; this.eval = eval; var target = xfer.Target; var seq = xfer.Target as MkSequence; if (seq != null) { target = seq.Tail; } var mem = target as MemoryAccess; if (mem == null) { Index = RegisterOf(target as Identifier); } else { Index = DetermineIndexRegister(mem); } Operations = new List <BackwalkOperation>(); JumpSize = target.DataType.Size; }
private void ScanVectorTargets(RtlTransfer xfer, List <Address> vector) { foreach (Address addr in vector) { var st = state.Clone(); if (xfer is RtlCall) { var pbase = scanner.ScanProcedure(addr, null, st); var pcallee = pbase as Procedure; if (pcallee != null) { program.CallGraph.AddEdge(blockCur.Statements.Last, pcallee); } } else { if (!program.SegmentMap.IsValidAddress(addr)) { break; } BlockFromAddress(ric.Address, addr, blockCur.Procedure, state); } } }
public TableExtent DiscoverTableExtent(Address addrSwitch, RtlTransfer xfer, DecompilerEventListener listener) { if (!Start(rtlBlock, host.BlockInstructionCount(rtlBlock) - 1, xfer.Target)) { // No registers were found, so we can't trace back. return(null); } while (Step()) { ; } var jumpExpr = this.JumpTableFormat; var interval = this.JumpTableIndexInterval; var index = this.JumpTableIndexToUse; var ctx = new Dictionary <Expression, ValueSet>(new ExpressionValueComparer()); if (index == null) { // Weren't able to find the index register, // try finding it by blind pattern matching. index = this.FindIndexWithPatternMatch(this.JumpTableFormat); if (index == null) { // This is likely an indirect call like a C++ // vtable dispatch. Since these are common, we don't // spam the user with warnings. return(null); } // We have a jump table, and we've guessed the index expression. // At this point we've given up on knowing the exact size // of the table, but we do know that it must be at least // more than one entry. The safest assumption is that it // has two entries. listener.Warn( listener.CreateAddressNavigator(host.Program, addrSwitch), "Unable to determine size of call or jump table; there may be more than 2 entries."); ctx.Add(index, new IntervalValueSet(index.DataType, StridedInterval.Create(1, 0, 1))); } else if (interval.IsEmpty) { return(null); } else if (interval.High == Int64.MaxValue) { // We have no reasonable upper bound. We make the arbitrary // assumption that the jump table has 2 items; it wouldn't // make sense to be indexing otherwise. listener.Warn( listener.CreateAddressNavigator(host.Program, addrSwitch), "Unable to determine the upper bound of an indirect call or jump; there may be more than 2 entries."); var vs = new IntervalValueSet( this.JumpTableIndex.DataType, StridedInterval.Create(1, interval.Low, interval.Low + 1)); ctx.Add(this.JumpTableIndexToUse, vs); } else { ctx.Add(this.JumpTableIndex, new IntervalValueSet(this.JumpTableIndex.DataType, interval)); } var vse = new ValueSetEvaluator(host.Architecture, host.SegmentMap, ctx, this.processorState); var(values, accesses) = vse.Evaluate(jumpExpr); var vector = values.Values .TakeWhile(c => c != Constant.Invalid) .Take(2000) // Arbitrary limit .Select(ForceToAddress) .TakeWhile(a => a != null) .ToList(); if (vector.Count == 0) { return(null); } return(new TableExtent { Targets = vector, Accesses = accesses, Index = index, }); }
public bool ProcessIndirectControlTransfer(Address addrSwitch, RtlTransfer xfer) { List <Address> vector; ImageMapVectorTable imgVector; Expression swExp; UserIndirectJump indJump; var listener = scanner.Services.RequireService <DecompilerEventListener>(); if (program.User.IndirectJumps.TryGetValue(addrSwitch, out indJump)) { vector = indJump.Table.Addresses; swExp = this.frame.EnsureIdentifier(indJump.IndexRegister); imgVector = indJump.Table; } else { var bw = new Backwalker <Block, Instruction>(new BackwalkerHost(this), xfer, eval); if (!bw.CanBackwalk()) { return(false); } var bwops = bw.BackWalk(blockCur); if (bwops == null || bwops.Count == 0) { return(false); //$REVIEW: warn? } Identifier idIndex = bw.Index != null ? blockCur.Procedure.Frame.EnsureRegister(bw.Index) : null; VectorBuilder builder = new VectorBuilder(scanner.Services, program, new DirectedGraphImpl <object>()); if (bw.VectorAddress == null) { return(false); } vector = builder.BuildAux(bw, addrSwitch, state); if (vector.Count == 0) { var rdr = program.CreateImageReader(bw.VectorAddress); if (!rdr.IsValid) { return(false); } // Can't determine the size of the table, but surely it has one entry? var addrEntry = arch.ReadCodeAddress(bw.Stride, rdr, state); string msg; if (this.program.SegmentMap.IsValidAddress(addrEntry)) { vector.Add(addrEntry); msg = "Can't determine size of jump vector; probing only one entry."; } else { // Nope, not even that. msg = "No valid entries could be found in jump vector."; } var nav = listener.CreateJumpTableNavigator(program, addrSwitch, bw.VectorAddress, bw.Stride); listener.Warn(nav, msg); if (vector.Count == 0) { return(false); } } imgVector = new ImageMapVectorTable( bw.VectorAddress, vector.ToArray(), builder.TableByteSize); swExp = idIndex; if (idIndex == null || idIndex.Name == "None") { swExp = bw.IndexExpression; } } ScanVectorTargets(xfer, vector); if (xfer is RtlGoto) { var blockSource = scanner.FindContainingBlock(ric.Address); blockCur = blockSource; foreach (Address addr in vector) { var dest = scanner.FindContainingBlock(addr); Debug.Assert(dest != null, "The block at address " + addr + "should have been enqueued."); blockSource.Procedure.ControlGraph.AddEdge(blockSource, dest); } if (swExp == null) { scanner.Warn(addrSwitch, "Unable to determine index variable for indirect jump."); Emit(new ReturnInstruction()); blockSource.Procedure.ControlGraph.AddEdge( blockSource, blockSource.Procedure.ExitBlock); } else { Emit(new SwitchInstruction(swExp, blockCur.Procedure.ControlGraph.Successors(blockCur).ToArray())); } } if (imgVector.Size > 0) { program.ImageMap.AddItemWithSize(imgVector.Address, imgVector); } else { program.ImageMap.AddItem(imgVector.Address, imgVector); } return(true); }
public bool ProcessIndirectControlTransfer(Address addrSwitch, RtlTransfer xfer) { var bw = new Backwalker(new BackwalkerHost(this), xfer, eval); if (!bw.CanBackwalk()) { return(false); } var bwops = bw.BackWalk(blockCur); if (bwops == null || bwops.Count == 0) { return(false); //$REVIEW: warn? } var idIndex = blockCur.Procedure.Frame.EnsureRegister(bw.Index); VectorBuilder builder = new VectorBuilder(scanner, program, new DirectedGraphImpl <object>()); if (bw.VectorAddress == null) { return(false); } List <Address> vector = builder.BuildAux(bw, addrSwitch, state); if (vector.Count == 0) { var addrNext = bw.VectorAddress + bw.Stride; var rdr = scanner.CreateReader(bw.VectorAddress); if (!rdr.IsValid) { return(false); } // Can't determine the size of the table, but surely it has one entry? var addrEntry = arch.ReadCodeAddress(bw.Stride, rdr, state); if (this.program.Image.IsValidAddress(addrEntry)) { vector.Add(addrEntry); scanner.Warn(addrSwitch, "Can't determine size of jump vector; probing only one entry."); } else { // Nope, not even that. scanner.Warn(addrSwitch, "No valid entries could be found in jump vector."); } } //$TODO: mark the vector ScanVectorTargets(xfer, vector); if (xfer is RtlGoto) { var blockSource = scanner.FindContainingBlock(ric.Address); blockCur = blockSource; foreach (Address addr in vector) { var dest = scanner.FindContainingBlock(addr); Debug.Assert(dest != null, "The block at address " + addr + "should have been enqueued."); blockSource.Procedure.ControlGraph.AddEdge(blockSource, dest); } Expression swExp = idIndex; if (idIndex.Name == "None") { swExp = bw.IndexExpression; } if (swExp == null) { throw new NotImplementedException(); } Emit(new SwitchInstruction(swExp, blockCur.Procedure.ControlGraph.Successors(blockCur).ToArray())); } //vectorUses[wi.addrFrom] = new VectorUse(wi.Address, builder.IndexRegister); program.ImageMap.AddItem(bw.VectorAddress, new ImageMapVectorTable(xfer is RtlCall, vector.ToArray(), builder.TableByteSize)); return(true); }
private void RunTest(IntelArchitecture arch, RtlTransfer rtlTransfer, string outputFile) { using (var fut = new FileUnitTester(outputFile)) { m.Procedure.Write(false, fut.TextWriter); fut.TextWriter.Flush(); var ibw = new Backwalker(host, rtlTransfer, expSimp); var bwoList = ibw.BackWalk(m.CurrentBlock); Assert.IsNotNull(bwoList); foreach (BackwalkOperation bwo in bwoList) { fut.TextWriter.WriteLine(bwo); } fut.TextWriter.WriteLine("Index register: {0}", ibw.Index); fut.AssertFilesEqual(); } }