ronin-rb/ronin

View on GitHub
lib/ronin/cli/commands/unhexdump.rb

Summary

Maintainability
A
25 mins
Test Coverage
# frozen_string_literal: true
#
# Copyright (c) 2006-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
#
# Ronin 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 3 of the License, or
# (at your option) any later version.
#
# Ronin 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 Ronin.  If not, see <https://www.gnu.org/licenses/>.
#

require 'ronin/cli/command'
require 'ronin/support/binary/unhexdump/parser'

module Ronin
  class CLI
    module Commands
      #
      # Hexdumps data in a variety of encodings and formats.
      #
      # ## Usage
      #
      #     ronin unhexdump [options] [FILE]
      #
      # ## Options
      #
      #    -o, --output FILE                Optional output file
      #    -f, --format hexdump|od          Format of the hexdump input (Default: hexdump)
      #    -t int8|uint8|char|uchar|byte|int16|int16_le|int16_be|int16_ne|uint16|uint16_le|uint16_be|uint16_ne|short|short_le|short_be|short_ne|ushort|ushort_le|ushort_be|ushort_ne|int32|int32_le|int32_be|int32_ne|uint32|uint32_le|uint32_be|uint32_ne|int|long|long_le|long_be|long_ne|uint|ulong|ulong_le|ulong_be|ulong_ne|int64|int64_le|int64_be|int64_ne|uint64|uint64_le|uint64_be|uint64_ne|long_long|long_long_le|long_long_be|long_long_ne|ulong_long|ulong_long_le|ulong_long_be|ulong_long_ne|float|float_le|float_be|float_ne|double|double_le|double_be|double_ne,
      #        --type                       The binary data type to decode the data as
      #    -b, --base 2|8|10|16             Numerical base of the hexdumped numbers
      #    -A, --address-base 2|8|10|16     Numerical base of the address column
      #        --[no-]named-chars           Enables parsing of od-style named charactters
      #    -h, --help                       Print help information
      #
      # ## Arguments
      #
      #    [FILE]                           Optional file to unhexdump
      #
      class Unhexdump < Command

        # Supported types for the `-t,--type` option.
        TYPES = [
          :int8,
          :uint8,
          :char,
          :uchar,
          :byte, # default for --format hexdump
          :int16,
          :int16_le,
          :int16_be,
          :int16_ne,
          :uint16,
          :uint16_le, # default for --format od
          :uint16_be,
          :uint16_ne,
          :short,
          :short_le,
          :short_be,
          :short_ne,
          :ushort,
          :ushort_le,
          :ushort_be,
          :ushort_ne,
          :int32,
          :int32_le,
          :int32_be,
          :int32_ne,
          :uint32,
          :uint32_le,
          :uint32_be,
          :uint32_ne,
          :int,
          :long,
          :long_le,
          :long_be,
          :long_ne,
          :uint,
          :ulong,
          :ulong_le,
          :ulong_be,
          :ulong_ne,
          :int64,
          :int64_le,
          :int64_be,
          :int64_ne,
          :uint64,
          :uint64_le,
          :uint64_be,
          :uint64_ne,
          :long_long,
          :long_long_le,
          :long_long_be,
          :long_long_ne,
          :ulong_long,
          :ulong_long_le,
          :ulong_long_be,
          :ulong_long_ne,
          :float,
          :float_le,
          :float_be,
          :float_ne,
          :double,
          :double_le,
          :double_be,
          :double_ne
        ]

        usage '[options] [FILE]'

        option :output, short: '-o',
                        value: {
                          type:  String,
                          usage: 'FILE'
                        },
                        desc: 'Optional output file'

        option :format, short: '-f',
                        value: {
                          type: [:hexdump, :od],
                          default: :hexdump
                        },
                        desc: 'Format of the hexdump input'

        option :type, short: '-t',
                      value: {type: TYPES},
                      desc:  'The binary data type to decode the data as'

        BASES = {'2' => 2, '8' => 8, '10' => 10, '16' => 16}

        option :base, short: '-b',
                      value: {type: BASES},
                      desc: 'Numerical base of the hexdumped numbers'

        option :address_base, short: '-A',
                              value: {type: BASES},
                              desc: 'Numerical base of the address column'

        option :named_chars, long: '--[no-]named-chars',
                             desc: 'Enables parsing of od-style named charactters'

        argument :file, required: false,
                        desc: 'Optional file to unhexdump'

        man_page 'ronin-unhexdump.1'

        #
        # Runs the `unhexdump` command.
        #
        # @param [String, nil] file
        #   Optional input file.
        #
        def run(file=nil)
          parser = Support::Binary::Unhexdump::Parser.new(
                     **hexdump_parser_options
                   )

          input = if file
                    begin
                      File.open(file)
                    rescue Errno::ENOENT
                      print_error "no such file or directory: #{file}"
                      exit(1)
                    end
                  else
                    stdin
                  end

          data = parser.unhexdump(input)

          if options[:output]
            File.binwrite(options[:output],data)
          else
            stdout.write(data)
          end
        end

        # Maps command-line options to
        # `Ronin::Support::Binary::Unhexdump::Parser#initialize` keyword
        # arguments.
        HEXDUMP_PARSER_OPTIONS = [
          :format,
          :type,
          :address_base,
          :base,
          :named_chars
        ]

        #
        # Builds a keyword arguments `Hash` of all command `options` that will
        # be directly passed to
        # `Ronin::Support::Binary::Unhexdump::Parser#initialize`.
        #
        # @return [Hash{Symbol => Object}]
        #
        def hexdump_parser_options
          kwargs = {}

          HEXDUMP_PARSER_OPTIONS.each do |key|
            kwargs[key] = options[key] if options.has_key?(key)
          end

          return kwargs
        end

      end
    end
  end
end