# 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 .
#
require 'ronin/cli/command'
require 'ronin/cli/binary_template'
module Ronin
class CLI
module Commands
#
# Unpacks binary data.
#
# ## Usage
#
# ronin unpack [options] TYPE [...]
#
# ## Options
#
# -E, --endian little|big|net Sets the endianness
# -A x86|x86_64|ppc|ppc64|mips|mips_le|mips_be|mips64|mips64_le|mips64_be|arm|arm_le|arm_be|arm64|arm64_le|arm64_be,
# --arch Sets the architecture
# -O linux|macos|windows|android|apple_ios|bsd|freebsd|openbsd|netbsd,
# --os Sets the OS
# -S, --string $'\xXX\x..' The raw binary string to unpack
# -f, --file FILE The binary file to unpack
# -h, --help Print help information
#
# ## Arguments
#
# TYPE:VALUE A value and it's type.
#
# ### Types
#
# Native Little-endian Big-endian Network-endian
# ------ ------------- ---------- --------------
#
# char
# uchar
# byte
# string
# int int_le int_be int_net
# int8
# int16 int16_le int16_be int16_net
# int32 int32_le int32_be int32_net
# int64 int64_le int64_be int64_net
# short short_le short_be short_net
# long long_le long_be long_net
# long_long long_long_le long_long_be long_long_net
# uint uint_le uint_be uint_net
# uint8
# uint1616 uint16_le uint16_be uint16_net
# uint3232 uint32_le uint32_be uint32_net
# uint6464 uint64_le uint64_be uint64_net
# ushort ushort_le ushort_be ushort_net
# ulong ulong_le ulong_be ulong_net
# ulong_long ulong_long_le ulong_long_be ulong_long_net
# float float_le float_be float_net
# float32 float32_le float32_be float32_net
# float64 float64_le float64_be float64_net
# double double_le double_be double_net
# pointer pointer_le pointer_be pointer_net
#
# ## Examples
#
# ronin unpack int32 uint32 char string
# ronin unpack int32[4] string[3]
# ronin unpack uint32_le
# ronin unpack uint32_be
# ronin unpack --endian big int uint
# ronin unpack --arch arm_le int long
# ronin unpack --arch x86_64 --os windows uint
# ronin unpack --string $'\x44\x33\x22\x11' int32
# ronin unpack --file int32.dat int32
# ronin pack int32:0x11223344 | ronin unpack int32
#
# @since 2.1.0
#
class Unpack < Command
include BinaryTemplate
option :string, short: '-S',
value: {
type: String,
usage: "$'\\xXX\\x..'"
},
desc: 'The raw binary string to unpack'
option :file, short: '-f',
value: {
type: String,
usage: 'FILE'
},
desc: 'The binary file to unpack'
argument :type, required: true,
repeats: true,
desc: 'A C type to unpack'
examples [
'int32 uint32 char string',
'int32[4] string[3]',
'uint32_le',
'uint32_be',
'--endian big int uint',
'--arch arm_le int long',
'--arch x86_64 --os windows uint',
'--string $\'\x44\x33\x22\x11\' int32',
'--file int32.dat int32',
'int32'
]
description 'Unpacks binary data'
man_page 'ronin-unpack.1'
#
# Runs the `ronin unpack` command.
#
# @param [Array] args
# The `TYPE` arguments to parse.
#
def run(*args)
types = args.map(&method(:parse_type))
template = build_template(types)
data = if options[:string]
options[:string]
elsif options[:file]
File.binread(options[:file])
else
stdin.read
end
values = template.unpack(data)
# remove the outer-most square brackets
print_array_value(values)
puts
end
#
# Prints an Array of values.
#
# @param [Array] value
# The array value to print.
#
def print_array_value(value)
# convert Ronin::Support::Binary::Array objects to plain Arrays
value = value.to_a
print '['
value.each_with_index do |element,index|
print_value(element)
print(', ') unless (index == (value.length - 1))
end
print ']'
end
#
# Prints an individual value.
#
# @param [Integer, Float, String, Ronin::Support::Binary::Array] value
# The value to print.
#
def print_value(value)
case value
when Array, Support::Binary::Array
print_array_value(value)
else
print(value.inspect)
end
end
end
end
end
end