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) ⇒ 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) ⇒ 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).
24 25 26 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 |
# File 'lib/rex/payloads/shuffle.rb', line 24 def self.from_graphml_file(file_path, arch: nil, name: nil) graphml = Rex::Parser::GraphML.from_file(file_path) 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) 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'] # 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(', ') } else instructions = block[:instructions].map { |node| node.attributes['instruction.source'] } end unless arch.nil? raise ArgumentError, 'Unsupported architecture' if FLOW_INSTRUCTIONS[arch].nil? # 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 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 |