# -*- coding: binary -*- require 'rexml/rexml' require 'rexml/source' require 'rexml/document' require 'rexml/parsers/treeparser' require 'rex/proto/http' require 'uri' module Rex module Exploitation module OpcodeDb module OpcodeResult # :nodoc: def initialize(hash) @hash = hash end attr_reader :hash end ### # # A cachable entry. # ### module Cachable def create(hash) # :nodoc: @Cache = {} unless (@Cache) if (hash_key(hash) and @Cache[hash_key(hash)]) @Cache[hash_key(hash)] else @Cache[hash_key(hash)] = self.new(hash) end end def hash_key(hash) # :nodoc: hash['id'] || nil end def flush_cache # :nodoc: @Cache.clear end end ### # # This class provides a general interface to items that come from that opcode # database that have a symbolic entry identifier and name. # ### module DbEntry include OpcodeResult def initialize(hash) super @id = hash['id'].to_i @name = hash['name'] end # # Fields that could possibly be filtered on for this database entry. # def filter_hash { "id" => id, "name" => name } end # # The unique server identifier. # attr_reader :id # # The unique name for this entry. # attr_reader :name end ### # # This class represents a particular image module including its name, # segments, imports, exports, base address, and so on. # ### class ImageModule include DbEntry ### # # This class contains information about a module-associated segment. # ### class Segment def initialize(hash) @type = hash['type'] @base_address = hash['base_address'].to_i @size = hash['segment_size'].to_i @writable = hash['writable'] == "true" ? true : false @readable = hash['readable'] == "true" ? true : false @executable = hash['executable'] == "true" ? true : false end # # The type of the segment, such as ".text". # attr_reader :type # # The base address of the segment. # attr_reader :base_address # # The size of the segment in bytes. # attr_reader :size # # Boolean that indicates whether or not the segment is writable. # attr_reader :writable # # Boolean that indicates whether or not the segment is readable. # attr_reader :readable # # Boolean that indicates whether or not the segment is executable. # attr_reader :executable end ### # # This class contains information about a module-associated import. # ### class Import def initialize(hash) @name = hash['name'] @address = hash['address'].to_i @ordinal = hash['ordinal'].to_i end # # The name of the imported function. # attr_reader :name # # The address of the function pointer in the IAT. # attr_reader :address # # The ordinal of the imported symbol. # attr_reader :ordinal end ### # # This class contains information about a module-associated export. # ### class Export def initialize(hash) @name = hash['name'] @address = hash['address'].to_i @ordinal = hash['ordinal'].to_i end # # The name of the exported function. # attr_reader :name # # The address of the exported function. # attr_reader :address # # The ordinal of the exported symbol. # attr_reader :ordinal end class < eip). # ### class Group include DbEntry class < method } opts.each_pair do |k, v| vars[k] = xlate_param(v) end client.set_config('uri_encode_mode' => 'none') # Initialize the request with the POST body. request = client.request_cgi( 'method' => 'POST', 'uri' => server_uri, 'vars_post' => vars ) # Send the request and grab the response. response = client.send_recv(request, 300) # Non-200 return code? if (response.code != 200) raise RuntimeError, "Invalid response received from server." end # Convert the return value to the native type. parse_response(response.body) rescue ::SocketError raise RuntimeError, "Could not communicate with the opcode service: #{$!.class} #{$!}" ensure client.close end end # # Translates a parameter into a flat CGI parameter string. # def xlate_param(v) if (v.kind_of?(Array)) v.map { |ent| xlate_param(ent) }.join(',,') elsif (v.kind_of?(Hash)) v.map { |k,v| "#{URI.escape(k)}:#{xlate_param(v)}" if (v) }.join(',,') else URI.escape(v.to_s) end end # # Translate the data type from a flat string to a ruby native type. # def parse_response(xml) @last_xml = xml if (!@disable_parse) source = REXML::Source.new(xml) doc = REXML::Document.new REXML::Parsers::TreeParser.new(source, doc).parse translate_element(doc.root) end end # # Translate elements conveyed as data types. # def translate_element(element) case element.name when "Array" return element.elements.map { |child| translate_element(child) } when "Hash" hsh = {} element.each_element { |child| if (e = child.elements[1]) v = translate_element(e) else v = child.text end hsh[child.attributes['name']] = v } return hsh else return element.text end end end end end end