public void HPSC_ResolveBlockConflicts_RemoveDirectlyCalledAddress() { var calledAddr = Address.Ptr32(0x5678); var wrongBlock = Given_Block(0x1234); Given_Instrs(wrongBlock, m => { m.Call(calledAddr, 4); }); var firstBlock = Given_Block(0x1235); Given_Instrs(firstBlock, m => { m.Assign(m.Mem32(m.Word32(0x2222)), 0); }); var lastBlock = Given_Block(0x1240); Given_Instrs(lastBlock, m => { m.Return(4, 0); }); var cfg = new DiGraph <RtlBlock>(); cfg.AddNode(wrongBlock); cfg.AddNode(firstBlock); cfg.AddNode(lastBlock); cfg.AddEdge(firstBlock, lastBlock); var sr = CreateScanResults(cfg); sr.DirectlyCalledAddresses.Add(calledAddr, 1); ResolveBlockConflicts(sr); Assert.AreEqual(0, sr.DirectlyCalledAddresses.Count); }
private void RemoveInvalidBlocks(ScanResults sr) { var revGraph = new DiGraph <RtlBlock>(); var invalid = new RtlBlock(null !, "<invalid>"); revGraph.AddNode(invalid); foreach (var b in sr.ICFG.Nodes) { revGraph.AddNode(b); } foreach (var b in sr.ICFG.Nodes) { foreach (var s in sr.ICFG.Successors(b)) { revGraph.AddEdge(s, b); } if (!b.IsValid) { revGraph.AddEdge(invalid, b); } } // Find the transitive closure of invalid nodes. var invalidNodes = new DfsIterator <RtlBlock>(revGraph) .PreOrder(invalid) .ToList(); foreach (var n in invalidNodes.Where(nn => nn != invalid)) { sr.ICFG.RemoveNode(n); sr.DirectlyCalledAddresses.Remove(n.Address); // Debug.Print("Removed invalid node {0}", n.Address); // commented out as this becomes very verbose. } }
public DiGraph <RtlBlock> BuildIcfg(Dictionary <Address, block> blocks) { var icfg = new DiGraph <RtlBlock>(); var map = new Dictionary <Address, RtlBlock>(); var rtlBlocks = from b in blocks.Values join i in sr.FlatInstructions.Values on b.id equals i.block_id into instrs orderby b.id select new RtlBlock(b.id, b.id.GenerateName("l", "")) { Instructions = instrs.Select(x => x.rtl).ToList() }; foreach (var rtlBlock in rtlBlocks) { map[rtlBlock.Address] = rtlBlock; icfg.AddNode(rtlBlock); } foreach (var edge in sr.FlatEdges) { if (!map.TryGetValue(edge.first, out RtlBlock from) || !map.TryGetValue(edge.second, out RtlBlock to)) { continue; } icfg.AddEdge(from, to); } return(icfg); }
public void AddEdge(DiGraph <Address> g, Address from, Address to) { #if !not_LinQ if (from == Bad) { return; } sr.FlatEdges.Add(new ScanResults.link { first = to, second = from, }); #else g.AddNode(from); g.AddNode(to); g.AddEdge(from, to); #endif }
public (DirectedGraph <Region>, Region) Build() { foreach (var b in proc.ControlGraph.Blocks) { if (b.Pred.Count == 0 && b != proc.EntryBlock || b == proc.ExitBlock) { continue; } var reg = regionFactory.Create(b); btor.Add(b, reg); graph.AddNode(reg); } foreach (var b in proc.ControlGraph.Blocks) { if (btor.TryGetValue(b, out var reg) && reg.Type == RegionType.IncSwitch) { MakeSwitchPads(b); } } foreach (var b in proc.ControlGraph.Blocks) { if (b.Pred.Count == 0 && b != proc.EntryBlock) { continue; } btor.TryGetValue(b, out var from); foreach (var s in b.Succ) { if (s == proc.ExitBlock) { continue; } var to = Destination(b, s); graph.AddEdge(from, to); } if (from != null) { if (graph.Successors(from).Count == 0) { from.Type = RegionType.Tail; } } } foreach (var reg in graph.Nodes.ToList()) { if (graph.Predecessors(reg).Count == 0 && reg != btor[proc.EntryBlock]) { graph.Nodes.Remove(reg); } } return(graph, btor[proc.EntryBlock]);
/// <summary> /// Disassemble every byte of the image, marking those addresses that likely /// are code as MaybeCode, everything else as data. /// </summary> /// <param name="segment"></param> /// <returns>An array of bytes classifying each byte as code or data. /// </returns> public byte[] ScanSegment(ImageMapSegment segment) { var G = new DiGraph<Address>(); G.AddNode(bad); var y = new byte[segment.ContentSize]; var step = program.Architecture.InstructionBitSize / 8; bool inDelaySlot = false; for (var a = 0; a < y.Length; a += step) { y[a] = MaybeCode; var i = Dasm(segment, a); if (i == null || i.InstructionClass == InstructionClass.Invalid) { AddEdge(G, bad, i.Address); inDelaySlot = false; } else { if (MayFallThrough(i)) { if (!inDelaySlot) { if (a + i.Length < y.Length) AddEdge(G, i.Address + i.Length, i.Address); else AddEdge(G, bad, i.Address); } } if ((i.InstructionClass & InstructionClass.Transfer) != 0) { var dest = Destination(i); if (dest != null) { if (IsExecutable(dest)) AddEdge(G, dest, i.Address); else AddEdge(G, bad, i.Address); } } // If this is a delayed unconditional branch... inDelaySlot = i.InstructionClass == DT; } } foreach (var a in new DfsIterator<Address>(G).PreOrder(bad)) { if (a != bad) { y[a - segment.Address] = Data; } } return y; }
public ShingledScanner(Program program, IRewriterHost host, IStorageBinder storageBinder, ScanResults sr, DecompilerEventListener eventListener) { this.program = program; this.host = host; this.storageBinder = storageBinder; this.sr = sr; this.eventListener = eventListener; this.sr.TransferTargets = new HashSet <Address>(); this.sr.DirectlyCalledAddresses = new Dictionary <Address, int>(); this.sr.Instructions = new SortedList <Address, RtlInstructionCluster>(); this.sr.FlatInstructions = new SortedList <Address, ScanResults.instr>(); this.sr.FlatEdges = new List <ScanResults.link>(); this.G = new DiGraph <Address>(); this.Bad = program.Platform.MakeAddressFromLinear(~0ul); G.AddNode(Bad); }
/// <summary> /// Builds a graph of regions based on the basic blocks of the code. /// </summary> /// <param name="proc"></param> /// <returns></returns> public Tuple<DirectedGraph<Region>, Region> BuildRegionGraph(Procedure proc) { var btor = new Dictionary<Block, Region>(); var regs = new DiGraph<Region>(); var regionFactory = new RegionFactory(); foreach (var b in proc.ControlGraph.Blocks) { if (b.Pred.Count == 0 && b != proc.EntryBlock || b == proc.ExitBlock) continue; var reg = regionFactory.Create(b); btor.Add(b, reg); regs.AddNode(reg); } foreach (var b in proc.ControlGraph.Blocks) { if (b.Pred.Count == 0 && b != proc.EntryBlock) continue; Region from; btor.TryGetValue(b, out from); foreach (var s in b.Succ) { if (s == proc.ExitBlock) continue; var to = btor[s]; regs.AddEdge(from, to); } if (from != null) { if (regs.Successors(from).Count == 0) from.Type = RegionType.Tail; } } foreach (var reg in regs.Nodes.ToList()) { if (regs.Predecessors(reg).Count == 0 && reg != btor[proc.EntryBlock]) { regs.Nodes.Remove(reg); } } return new Tuple<DirectedGraph<Region>, Region>(regs, btor[proc.EntryBlock]); }
/// <summary> /// Builds a graph of regions based on the basic blocks of the code. /// </summary> /// <param name="proc"></param> /// <returns></returns> public Tuple<DirectedGraph<Region>, Region> BuildRegionGraph(Procedure proc) { var btor = new Dictionary<Block, Region>(); var regs = new DiGraph<Region>(); var regionFactory = new RegionFactory(); foreach (var b in proc.ControlGraph.Blocks) { var reg = regionFactory.Create(b); btor.Add(b, reg); regs.AddNode(reg); } foreach (var b in proc.ControlGraph.Blocks) { foreach (var s in b.Succ) { var from = btor[b]; var to = btor[s]; regs.AddEdge(from, to); } } return new Tuple<DirectedGraph<Region>, Region>(regs, btor[proc.EntryBlock]); }
/// <summary> /// Disassemble every byte of the segment, marking those addresses /// that likely are code as MaybeCode, everything else as data. /// </summary> /// <remarks> /// The plan is to disassemble every location of the segment, building /// a reverse control graph. Any jump to an illegal address or any /// invalid instruction will result in an edge from "bad" to that /// instruction. /// </remarks> /// <param name="segment"></param> /// <returns>An array of bytes classifying each byte as code or data. /// </returns> public byte[] ScanSegment(ImageSegment segment) { var G = new DiGraph <Address>(); G.AddNode(bad); var cbAlloc = Math.Min( segment.Size, segment.MemoryArea.EndAddress - segment.Address); var y = new byte[cbAlloc]; // Advance by the instruction granularity. var step = program.Architecture.InstructionBitSize / 8; bool inDelaySlot = false; for (var a = 0; a < y.Length; a += step) { y[a] = MaybeCode; var i = Dasm(segment, a); if (i == null) { AddEdge(G, bad, segment.Address + a); inDelaySlot = false; break; } if (i.InstructionClass == InstructionClass.Invalid) { AddEdge(G, bad, i.Address); inDelaySlot = false; } else { if (MayFallThrough(i)) { if (!inDelaySlot) { if (a + i.Length < y.Length) { // Still inside the segment. AddEdge(G, i.Address + i.Length, i.Address); } else { // Fell off segment, i must be a bad instruction. AddEdge(G, bad, i.Address); } } } if ((i.InstructionClass & InstructionClass.Transfer) != 0) { var addrDest = DestinationAddress(i); if (addrDest != null) { if (IsExecutable(addrDest)) { // call / jump destination is executable AddEdge(G, addrDest, i.Address); if ((i.InstructionClass & InstructionClass.Call) != 0) { int callTally; if (!this.possibleCallDestinationTallies.TryGetValue(addrDest, out callTally)) { callTally = 0; } this.possibleCallDestinationTallies[addrDest] = callTally + 1; } } else { // Jump to data / hyperspace. AddEdge(G, bad, i.Address); } } } // If this is a delayed unconditional branch... inDelaySlot = i.InstructionClass == DT; } } // Find all places that are reachable from "bad" addresses. // By transitivity, they must also be be bad. foreach (var a in new DfsIterator <Address>(G).PreOrder(bad)) { if (a != bad) { y[a - segment.Address] = Data; } } return(y); }
private void AddEdge(DiGraph <Address> g, Address from, Address to) { g.AddNode(from); g.AddNode(to); g.AddEdge(from, to); }
/// <summary> /// Build Shingle blocks from the graph. An instruction can only be /// in one block at a time, so at each point in the graph where the /// successors > 1 or the predecessors > 1, we create a new node. /// </summary> /// <param name="instructions"></param> /// <returns></returns> public IcfgBuilder BuildBlocks(DiGraph <Address> graph) { // Remember, the graph is backwards! var activeBlocks = new List <RtlBlock>(); var allBlocks = new DiGraph <RtlBlock>(); var edges = new List <Tuple <RtlBlock, Address> >(); var mpBlocks = new Dictionary <Address, RtlBlock>(); var wl = sr.Instructions.Keys.ToSortedSet(); while (wl.Count > 0) { var addr = wl.First(); wl.Remove(addr); var instr = sr.Instructions[addr]; var label = program.NamingPolicy.BlockName(addr); var block = new RtlBlock(addr, label); block.Instructions.Add(instr); allBlocks.AddNode(block); mpBlocks.Add(addr, block); bool endBlockNow = false; bool terminateDeferred = false; bool addFallthroughEdge = false; bool addFallthroughEdgeDeferred = false; for (;;) { var addrInstrEnd = instr.Address + instr.Length; if ((instr.Class & DT) != 0) { if (MayFallThrough(instr)) { addFallthroughEdge = (instr.Class & DT) == T; addFallthroughEdgeDeferred = (instr.Class & DT) == DT; } var addrDst = DestinationAddress(instr); if (addrDst != null && (instr.Class & InstrClass.Call) == 0) { edges.Add(Tuple.Create(block, addrDst)); } if ((instr.Class & DT) == DT) { terminateDeferred = true; } else { endBlockNow = true; } } else if (instr.Class == InstrClass.Terminates) { endBlockNow = true; addFallthroughEdge = false; addFallthroughEdge = false; } else { endBlockNow = terminateDeferred; addFallthroughEdge = addFallthroughEdgeDeferred; addFallthroughEdgeDeferred = false; } if (sr.DirectlyCalledAddresses.Keys.Contains(addrInstrEnd) || sr.KnownProcedures.Contains(addrInstrEnd)) { // If control falls into what looks like a procedure, don't // add an edge. addFallthroughEdge = false; endBlockNow = true; } if (addFallthroughEdge) { edges.Add(Tuple.Create(block, addrInstrEnd)); } if (endBlockNow || !wl.Contains(addrInstrEnd) || !graph.Nodes.Contains(addrInstrEnd) || graph.Successors(addrInstrEnd).Count != 1) { //Debug.Print("addr: {0}, end {1}, term: {2}, wl: {3}, nodes: {4}, succ: {5}", // addr, // addrInstrEnd, // endBlockNow, // !wl.Contains(addrInstrEnd), // !graph.Nodes.Contains(addrInstrEnd), // graph.Nodes.Contains(addrInstrEnd) // ? graph.Successors(addrInstrEnd).Count // : 0); if (!endBlockNow && !addFallthroughEdge) { edges.Add(Tuple.Create(block, addrInstrEnd)); } break; } wl.Remove(addrInstrEnd); instr = sr.Instructions[addrInstrEnd]; block.Instructions.Add(instr); endBlockNow = terminateDeferred; } } return(new IcfgBuilder { Edges = edges, AddrToBlock = mpBlocks, Blocks = allBlocks, }); }
private void AddEdge(DiGraph<Address> g, Address from, Address to) { g.AddNode(from); g.AddNode(to); g.AddEdge(from, to); }
/// <summary> /// Disassemble every byte of the segment, marking those addresses /// that likely are code as MaybeCode, everything else as data. /// </summary> /// <remarks> /// The plan is to disassemble every location of the segment, building /// a reverse control graph. Any jump to an illegal address or any /// invalid instruction will result in an edge from "bad" to that /// instruction. /// </remarks> /// <param name="segment"></param> /// <returns>An array of bytes classifying each byte as code or data. /// </returns> public ScannedSegment ScanSegment(ImageSegment segment, ulong workToDo) { var G = new DiGraph<Address>(); G.AddNode(bad); var cbAlloc = Math.Min( segment.Size, segment.MemoryArea.EndAddress - segment.Address); var y = new byte[cbAlloc]; // Advance by the instruction granularity. var step = program.Architecture.InstructionBitSize / 8; var delaySlot = InstructionClass.None; for (var a = 0; a < y.Length; a += step) { y[a] = MaybeCode; var i = Dasm(segment, a); if (i == null) { AddEdge(G, bad, segment.Address + a); break; } if (IsInvalid(segment.MemoryArea, i)) { AddEdge(G, bad, i.Address); delaySlot = InstructionClass.None; y[a] = Data; } else { if (MayFallThrough(i)) { if (delaySlot != DT) { if (a + i.Length < y.Length) { // Still inside the segment. AddEdge(G, i.Address + i.Length, i.Address); } else { // Fell off segment, i must be a bad instruction. AddEdge(G, bad, i.Address); y[a] = Data; } } } if ((i.InstructionClass & InstructionClass.Transfer) != 0) { var addrDest = DestinationAddress(i); if (addrDest != null) { if (IsExecutable(addrDest)) { // call / jump destination is executable AddEdge(G, addrDest, i.Address); if ((i.InstructionClass & InstructionClass.Call) != 0) { int callTally; if (!this.possibleCallDestinationTallies.TryGetValue(addrDest, out callTally)) callTally = 0; this.possibleCallDestinationTallies[addrDest] = callTally + 1; } } else { // Jump to data / hyperspace. AddEdge(G, bad, i.Address); y[a] = Data; } } } // If this is a delayed unconditional branch... delaySlot = i.InstructionClass; } if (y[a] == MaybeCode) instructions.Add(i.Address, i); eventListener.ShowProgress("Shingle scanning", instructions.Count, (int)workToDo); } // Find all places that are reachable from "bad" addresses. // By transitivity, they must also be be bad. foreach (var a in new DfsIterator<Address>(G).PreOrder(bad)) { if (a != bad) { y[a - segment.Address] = Data; instructions.Remove(a); // Destination can't be a call destination. possibleCallDestinationTallies.Remove(a); } } // Build blocks out of sequences of instructions. var blocks = BuildBlocks(G, instructions); return new ScannedSegment { Blocks = blocks, CodeFlags = y, }; }
/// <summary> /// Disassemble every byte of the segment, marking those addresses /// that likely are code as MaybeCode, everything else as data. /// </summary> /// <remarks> /// The plan is to disassemble every location of the segment, building /// a reverse control graph. Any jump to an illegal address or any /// invalid instruction will result in an edge from "bad" to that /// instruction. /// </remarks> /// <param name="segment"></param> /// <returns>An array of bytes classifying each byte as code or data. /// </returns> public ScannedSegment ScanSegment(ImageSegment segment, ulong workToDo) { var G = new DiGraph <Address>(); G.AddNode(bad); var cbAlloc = Math.Min( segment.Size, segment.MemoryArea.EndAddress - segment.Address); var y = new byte[cbAlloc]; // Advance by the instruction granularity. var step = program.Architecture.InstructionBitSize / 8; var delaySlot = InstructionClass.None; for (var a = 0; a < y.Length; a += step) { y[a] = MaybeCode; var i = Dasm(segment, a); if (i == null) { AddEdge(G, bad, segment.Address + a); break; } if (IsInvalid(segment.MemoryArea, i)) { AddEdge(G, bad, i.Address); delaySlot = InstructionClass.None; y[a] = Data; } else { if (MayFallThrough(i)) { if (delaySlot != DT) { if (a + i.Length < y.Length) { // Still inside the segment. AddEdge(G, i.Address + i.Length, i.Address); } else { // Fell off segment, i must be a bad instruction. AddEdge(G, bad, i.Address); y[a] = Data; } } } if ((i.InstructionClass & InstructionClass.Transfer) != 0) { var addrDest = DestinationAddress(i); if (addrDest != null) { if (IsExecutable(addrDest)) { // call / jump destination is executable AddEdge(G, addrDest, i.Address); if ((i.InstructionClass & InstructionClass.Call) != 0) { int callTally; if (!this.possibleCallDestinationTallies.TryGetValue(addrDest, out callTally)) { callTally = 0; } this.possibleCallDestinationTallies[addrDest] = callTally + 1; } } else { // Jump to data / hyperspace. AddEdge(G, bad, i.Address); y[a] = Data; } } } // If this is a delayed unconditional branch... delaySlot = i.InstructionClass; } if (y[a] == MaybeCode) { instructions.Add(i.Address, i); } eventListener.ShowProgress("Shingle scanning", instructions.Count, (int)workToDo); } // Find all places that are reachable from "bad" addresses. // By transitivity, they must also be be bad. foreach (var a in new DfsIterator <Address>(G).PreOrder(bad)) { if (a != bad) { y[a - segment.Address] = Data; instructions.Remove(a); // Destination can't be a call destination. possibleCallDestinationTallies.Remove(a); } } // Build blocks out of sequences of instructions. var blocks = BuildBlocks(G, instructions); return(new ScannedSegment { Blocks = blocks, CodeFlags = y, }); }