Class: Rex::Payloads::Shuffle
- Inherits:
-
Object
- Object
- Rex::Payloads::Shuffle
- Defined in:
- lib/rex/payloads/shuffle.rb
Class Method Summary collapse
-
.from_graphml_file(file_path, arch: nil, name: nil, random: nil) ⇒ Object
Shuffle instructions from a GraphML data file and return the assembly source.
Class Method Details
.from_graphml_file(file_path, arch: nil, name: nil, random: nil) ⇒ Object
Shuffle instructions from a GraphML data file and return the assembly source. If an architecture is specified and supported, labels will be added for control flow instructions such as jumps and calls. Labels are necessary if any post processing is performed on the source (such as for obfuscation).
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/rex/payloads/shuffle.rb', line 27 def self.from_graphml_file(file_path, arch: nil, name: nil, random: nil) graphml = Rex::Parser::GraphML.from_file(file_path) blocks = create_path(graphml.nodes.select { |_id,node| %w[ data instructions-graph block ].include?(node.attributes['type']) }, graphml.graphs[0].edges, random: random) blocks.map! do |block| hash = { node: block } if %w[ instructions-graph block ].include?(block.attributes['type']) hash[:instructions] = process_instructions_graph_block(block, random: random) end hash end label_prefix = random ? Array.new(4) { ('a'.ord + random.rand(26)).chr }.join : Rex::Text.rand_text_alpha_lower(4) labeler = lambda { |address| "loc_#{label_prefix}#{address.to_s(16).rjust(4, '0')}" } source_lines = [] labeled = [] label_refs = [] blocks.each do |block| if [ Rex::Arch::ARCH_X86, Rex::Arch::ARCH_X64 ].include? arch source_lines << labeler.call(block[:node].attributes['address']) + ':' labeled << block[:node].attributes['address'] case block[:node].attributes['type'] when 'data' instructions = data_block_instructions(block[:node]) when 'instructions-graph', 'block' # by default use the raw binary instruction to avoid syntax compatibility issues with metasm instructions = block[:instructions].map { |node| 'db ' + node.attributes['instruction.hex'].strip.chars.each_slice(2).map { |hex| '0x' + hex.join }.join(', ') } end else case block[:node].attributes['type'] when 'data' instructions = data_block_instructions(block[:node]) when 'instructions-graph', 'block' instructions = block[:instructions].map { |node| node.attributes['instruction.source'] } end end unless arch.nil? raise ArgumentError, 'Unsupported architecture' if FLOW_INSTRUCTIONS[arch].nil? if %w[ instructions-graph block ].include?(block[:node].attributes['type']) # if a supported architecture was specified, use the original source and apply the necessary labels block[:instructions].each_with_index do |node, index| next unless match = /^(?<mnemonic>\S+)\s+(?<address>0x[a-f0-9]+)$/.match(node.attributes['instruction.source']) next unless FLOW_INSTRUCTIONS[arch].include? match[:mnemonic] address = Integer(match[:address]) instructions[index] = "#{match[:mnemonic]} #{labeler.call(address)}" label_refs << address end end end source_lines += instructions end unless label_refs.all? { |address| labeled.include? address } # raise this here so it's closer to the source of the problem :( raise StandardError, 'Missing label reference' end source_lines = ([name + ':'] + source_lines.map { |source_line| ' ' + source_line}) unless name.nil? source_lines.join("\n") + "\n" end |