# #-- # Ronin - A Ruby platform designed for information security and data # exploration tasks. # # Copyright (c) 2006-2009 Hal Brodigan (postmodern.mod3 at gmail.com) # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #++ # require 'ronin/formatting/extensions/binary/integer' require 'ronin/formatting/extensions/text' require 'ronin/arch' require 'base64' class String # # Packs the integer using the specified _arch_ and the given # _address_length_. The _address_length_ will default to the address # length of the _arch_. # # 0x41.pack(Arch('i686')) # => "A\000\000\000" # # 0x41.pack(Arch('ppc'),2) # => "\000A" # def depack(arch,address_length=arch.address_length) integer = 0x0 if arch.endian=='little' address_length.times do |i| if self[i] integer = (integer | (self[i] << (i*8))) end end elsif arch.endian=='big' address_length.times do |i| if self[i] integer = (integer | (self[i] << ((address_length-i-1)*8))) end end end return integer end # # Returns the hex escaped form of the string. # # "hello".hex_escape # # => "\\x68\\x65\\x6c\\x6c\\x6f" # def hex_escape(options={}) format_bytes(options) { |b| "\\x%.2x" % b } end # # Returns an unescaped version of the hex escaped string. # # "\\x68\\x65\\x6c\\x6c\\x6f".hex_unescape # # => "hello" # def hex_unescape buffer = '' hex_index = 0 hex_length = length while (hex_index < hex_length) hex_substring = self[hex_index..-1] if hex_substring =~ /^\\[0-7]{3}/ buffer << hex_substring[0..3].to_i(8) hex_index += 3 elsif hex_substring =~ /^\\x[0-9a-fA-F]{1,2}/ hex_substring[2..-1].scan(/^[0-9a-fA-F]{1,2}/) do |hex_byte| buffer << hex_byte.to_i(16) hex_index += (2 + hex_byte.length) end elsif hex_substring =~ /^\\./ escaped_char = hex_substring[1..1] buffer << case escaped_char when '0' "\0" when 'a' "\a" when 'b' "\b" when 't' "\t" when 'n' "\n" when 'v' "\v" when 'f' "\f" when 'r' "\r" else escaped_char end hex_index += 2 else buffer << hex_substring[0] hex_index += 1 end end return buffer end # # XOR encodes the string using the specified _key_. # def xor(key) encoded = '' each_byte { |b| encoded << (b ^ key).chr } return encoded end # # Returns the base64 encoded form of the string. # def base64_encode Base64.encode64(self) end # # Returns the base64 decoded form of the string. # def base64_decode Base64.decode64(self) end # # Converts a multitude of hexdump formats back into the original # raw-data using the given _options_. # # _options_ may contain the following keys: # :format:: The expected format of the hexdump. Must be either # :od or :hexdump. # :encoding:: Denotes the encoding used for the bytes within the # hexdump. Must be one of the following: # :binary:: Binary encoded bytes. # :octal:: Octal encoding. # :octal_bytes:: Octal encoded bytes. # :octal_shorts:: Octal encoded shorts. # :octal_ints:: Octal encoded integers. # :octal_quads:: Octal encoded quads. # :decimal:: Unsigned decimal encoding. # :decimal_bytes:: Unsigned decimal bytes. # :decimal_shorts:: Unsigned decimal shorts. # :decimal_ints:: Unsigned decimal ints. # :decimal_quads:: Unsigned decimal quads. # :hex:: Hexadecimal encoding. # :hex_bytes:: Hexadecimal bytes. # :hex_shorts:: Hexadecimal shorts. # :hex_ints:: Hexadecimal ints. # :hex_quads:: Hexadecimal quads. # :segment:: The length in bytes of each segment in the hexdump. # Defaults to 16, if not specified. # def unhexdump(options={}) case (format = options[:format]) when :od address_base = base = 8 word_size = 2 when :hexdump address_base = base = 16 word_size = 2 else address_base = base = 16 word_size = 1 end case options[:encoding] when :binary base = 2 when :octal, :octal_bytes, :octal_shorts, :octal_ints, :octal_quads base = 8 when :decimal, :decimal_bytes, :decimal_shorts, :decimal_ints, :decimal_quads base = 10 when :hex, :hex_bytes, :hex_shorts, :hex_ints, :hex_quads base = 16 end case options[:encoding] when :binary, :octal_bytes, :decimal_bytes, :hex_bytes word_size = 1 when :octal_shorts, :decimal_shorts, :hex_shorts word_size = 2 when :octal_ints, :decimal_ints, :hex_ints word_size = 4 when :octal_quads, :decimal_quads, :hex_quads word_size = 8 end current_addr = last_addr = first_addr = nil repeated = false segment_length = (options[:segment] || 16) segment = [] buffer = [] each_line do |line| if format == :hexdump line = line.gsub(/\s+\|.+\|\s*$/,'') end words = line.split if words.first == '*' repeated = true elsif words.length > 0 current_addr = words.shift.to_i(address_base) first_addr ||= current_addr if repeated (((current_addr - last_addr) / segment.length) - 1).times do buffer += segment end repeated = false end segment.clear words.each do |word| if (base != 10 && word =~ /^(\\[0abtnvfr\\]|.)$/) word.hex_unescape.each_byte { |b| segment << b } else segment += word.to_i(base).bytes(word_size) end end segment = segment[0...segment_length] buffer += segment last_addr = current_addr end end return buffer[0...(last_addr - first_addr)] end end