lib/ronin/formatting/extensions/binary/string.rb in ronin-0.2.1 vs lib/ronin/formatting/extensions/binary/string.rb in ronin-0.2.2
- old
+ new
@@ -19,10 +19,11 @@
# 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'
@@ -66,10 +67,65 @@
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 = ''
@@ -87,8 +143,118 @@
#
# 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:
+ # <tt>:format</tt>:: The expected format of the hexdump. Must be either
+ # <tt>:od</tt> or <tt>:hexdump</tt>.
+ # <tt>:encoding</tt>:: Denotes the encoding used for the bytes within the
+ # hexdump. Must be one of the following:
+ # <tt>:binary</tt>:: Binary encoded bytes.
+ # <tt>:octal</tt>:: Octal encoding.
+ # <tt>:octal_bytes</tt>:: Octal encoded bytes.
+ # <tt>:octal_shorts</tt>:: Octal encoded shorts.
+ # <tt>:octal_ints</tt>:: Octal encoded integers.
+ # <tt>:octal_quads</tt>:: Octal encoded quads.
+ # <tt>:decimal</tt>:: Unsigned decimal encoding.
+ # <tt>:decimal_bytes</tt>:: Unsigned decimal bytes.
+ # <tt>:decimal_shorts</tt>:: Unsigned decimal shorts.
+ # <tt>:decimal_ints</tt>:: Unsigned decimal ints.
+ # <tt>:decimal_quads</tt>:: Unsigned decimal quads.
+ # <tt>:hex</tt>:: Hexadecimal encoding.
+ # <tt>:hex_bytes</tt>:: Hexadecimal bytes.
+ # <tt>:hex_shorts</tt>:: Hexadecimal shorts.
+ # <tt>:hex_ints</tt>:: Hexadecimal ints.
+ # <tt>:hex_quads</tt>:: Hexadecimal quads.
+ # <tt>:segment</tt>:: 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