diff --git a/data/shellcode/block_api.x64.graphml b/data/shellcode/block_api.x64.graphml
index f7f15da89e..7721dd7217 100644
--- a/data/shellcode/block_api.x64.graphml
+++ b/data/shellcode/block_api.x64.graphml
@@ -642,23 +642,16 @@
-
-
-
-
-
-
-
+
-
diff --git a/data/shellcode/block_api.x86.graphml b/data/shellcode/block_api.x86.graphml
index 4779c0c569..356016d5d0 100644
--- a/data/shellcode/block_api.x86.graphml
+++ b/data/shellcode/block_api.x86.graphml
@@ -595,21 +595,15 @@
-
-
-
-
-
-
+
-
diff --git a/lib/rex/parser/graphml.rb b/lib/rex/parser/graphml.rb
index 6872b15c2e..dc640f900f 100644
--- a/lib/rex/parser/graphml.rb
+++ b/lib/rex/parser/graphml.rb
@@ -362,6 +362,7 @@ module Rex
def initialize(id)
@id = id
@edges = []
+ @subgraph = nil
super()
end
@@ -390,6 +391,9 @@ module Rex
# @!attribute edges
# @return [Array] An array of all edges for which this node is either the source or the target.
attr_reader :edges
+ # @!attribute subgraph
+ # @return [Graph,nil] A subgraph contained within this node.
+ attr_accessor :subgraph
end
end
@@ -461,6 +465,7 @@ module Rex
when 'graph'
element = Element::Graph.from_xml_attributes(attrs)
+ @stack[-1].subgraph = element if @stack[-1].is_a? Element::Node
@graphml.graphs << element
when 'graphml'
diff --git a/lib/rex/payloads/shuffle.rb b/lib/rex/payloads/shuffle.rb
index 480a88fa6e..ade9acfac7 100644
--- a/lib/rex/payloads/shuffle.rb
+++ b/lib/rex/payloads/shuffle.rb
@@ -23,7 +23,7 @@ module Rex
# @param name [String] An optional symbol name to apply to the assembly source.
def self.from_graphml_file(file_path, arch: nil, name: nil)
graphml = Rex::Parser::GraphML.from_file(file_path)
- blocks = graphml.graphs.select { |graph| graph.attributes['type'] == 'block' }.sort_by { |graph| graph.attributes['address'] }
+ blocks = create_path(graphml.nodes.select { |_id,node| node.attributes['type'] == 'block' }, graphml.graphs[0].edges)
blocks.map! { |block| { node: block, instructions: process_block(block) } }
label_prefix = Rex::Text.rand_text_alpha_lower(4)
@@ -76,22 +76,27 @@ module Rex
# contains nodes representing each of its instructions.
#
def process_block(block)
+ subgraph = block.subgraph
+ instructions = subgraph.nodes.select { |_id, node| node.attributes['type'] == 'instruction' }
+ create_path(instructions, subgraph.edges)
+ end
+
+ def create_path(nodes, edges)
path = []
- instructions = block.nodes.select { |_id, node| node.attributes['type'] == 'instruction' }
# the initial choices are any node without a predecessor (dependency)
- targets = block.edges.map(&:target)
- choices = instructions.values.select { |node| !targets.include? node.id }
+ targets = edges.map(&:target)
+ choices = nodes.values.select { |node| !targets.include? node.id }
until choices.empty?
selection = choices.sample
choices.delete(selection)
path << selection
# check each node for which the selection is a dependency
- successors = selection.target_edges.map { |edge| instructions[edge.target] }
+ successors = selection.target_edges.map { |edge| nodes[edge.target] }
successors.each do |successor|
next if path.include? successor
- next if !successor.source_edges.map { |edge| path.include? instructions[edge.source] }.all?
+ next if !successor.source_edges.map { |edge| path.include? nodes[edge.source] }.all?
choices << successor
end