219 lines
5.7 KiB
Ruby
219 lines
5.7 KiB
Ruby
# -*- coding: binary -*-
|
|
require 'rex/text/version'
|
|
require 'digest/md5'
|
|
require 'digest/sha1'
|
|
require 'stringio'
|
|
require 'cgi'
|
|
require 'zlib'
|
|
require 'openssl'
|
|
|
|
require 'rex/text/illegal_sequence'
|
|
require 'rex/text/rand'
|
|
require 'rex/text/checksum'
|
|
require 'rex/text/hash'
|
|
require 'rex/text/lang'
|
|
require 'rex/text/hex'
|
|
require 'rex/text/base32'
|
|
require 'rex/text/base64'
|
|
require 'rex/text/unicode'
|
|
require 'rex/text/binary_manipulation'
|
|
require 'rex/text/randomize'
|
|
require 'rex/text/compress'
|
|
require 'rex/text/silly'
|
|
require 'rex/text/encode'
|
|
require 'rex/text/block_api'
|
|
require 'rex/text/ebcdic'
|
|
require 'rex/text/pattern'
|
|
require 'rex/text/badchars'
|
|
require 'rex/text/xor'
|
|
|
|
require 'rex/text/color'
|
|
require 'rex/text/table'
|
|
require 'rex/text/wrapped_table'
|
|
|
|
module Rex
|
|
|
|
###
|
|
#
|
|
# This class formats text in various fashions and also provides
|
|
# a mechanism for wrapping text at a given column.
|
|
#
|
|
###
|
|
module Text
|
|
@@codepage_map_cache = nil
|
|
|
|
##
|
|
#
|
|
# Constants
|
|
#
|
|
##
|
|
|
|
UpperAlpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
LowerAlpha = "abcdefghijklmnopqrstuvwxyz"
|
|
Numerals = "0123456789"
|
|
Base32 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
|
|
Base64 = UpperAlpha + LowerAlpha + Numerals + '+/'
|
|
Base64Url = UpperAlpha + LowerAlpha + Numerals + '-_'
|
|
Alpha = UpperAlpha + LowerAlpha
|
|
AlphaNumeric = Alpha + Numerals
|
|
HighAscii = [*(0x80 .. 0xff)].pack("C*")
|
|
LowAscii = [*(0x00 .. 0x1f)].pack("C*")
|
|
DefaultWrap = 60
|
|
AllChars = [*(0x00 .. 0xff)].pack("C*")
|
|
Punctuation = ( [*(0x21 .. 0x2f)] + [*(0x3a .. 0x3F)] + [*(0x5b .. 0x60)] + [*(0x7b .. 0x7e)] ).flatten.pack("C*")
|
|
|
|
DefaultPatternSets = [ Rex::Text::UpperAlpha, Rex::Text::LowerAlpha, Rex::Text::Numerals ]
|
|
|
|
#
|
|
# Returns the raw string
|
|
#
|
|
def self.to_raw(str)
|
|
return str
|
|
end
|
|
|
|
#
|
|
# Returns the escaped octal version of the supplied string
|
|
#
|
|
# @example
|
|
# Rex::Text.to_octal("asdf") # => "\\141\\163\\144\\146"
|
|
#
|
|
# @param str [String] The string to be converted
|
|
# @param prefix [String]
|
|
# @return [String] The escaped octal version of +str+
|
|
def self.to_octal(str, prefix = "\\")
|
|
octal = ""
|
|
str.each_byte { |b|
|
|
octal << "#{prefix}#{b.to_s 8}"
|
|
}
|
|
|
|
return octal
|
|
end
|
|
|
|
#
|
|
# Wraps text at a given column using a supplied indention
|
|
#
|
|
def self.wordwrap(str, indent = 0, col = DefaultWrap, append = '', prepend = '')
|
|
return str.gsub(/.{1,#{col - indent}}(?:\s|\Z)/){
|
|
( (" " * indent) + prepend + $& + append + 5.chr).gsub(/\n\005/,"\n").gsub(/\005/,"\n")}
|
|
end
|
|
|
|
|
|
# @return [Regexp] Matches a valid color code, i.e. "%blu,%yel,...etc"
|
|
COLOR_CODES_REGEX = /#{Regexp.union(Rex::Text::Color::SUPPORTED_FORMAT_CODES.compact).source}/
|
|
private_constant :COLOR_CODES_REGEX
|
|
|
|
#
|
|
# Function that aims to calculate the display width of the given string.
|
|
# In the future this will be aware of East Asian characters having different display
|
|
# widths. For now it simply returns the string's length ignoring color codes.
|
|
#
|
|
# @param [String] str
|
|
# @return [Integer]
|
|
def self.display_width(str)
|
|
return 0 if str.nil?
|
|
|
|
str.gsub(COLOR_CODES_REGEX, '').length
|
|
end
|
|
|
|
#
|
|
# Convert 16-byte string to a GUID string
|
|
#
|
|
# @example
|
|
# str = "ABCDEFGHIJKLMNOP"
|
|
# Rex::Text.to_guid(str) #=> "{44434241-4645-4847-494a-4b4c4d4e4f50}"
|
|
#
|
|
# @param bytes [String] 16 bytes which represent a GUID in the proper
|
|
# order.
|
|
#
|
|
# @return [String]
|
|
def self.to_guid(bytes)
|
|
return nil unless bytes
|
|
s = bytes.unpack('H*')[0]
|
|
parts = [
|
|
s[6, 2] + s[4, 2] + s[2, 2] + s[0, 2],
|
|
s[10, 2] + s[8, 2],
|
|
s[14, 2] + s[12, 2],
|
|
s[16, 4],
|
|
s[20, 12]
|
|
]
|
|
"{#{parts.join('-')}}"
|
|
end
|
|
|
|
#
|
|
# Split a string by n character into an array
|
|
#
|
|
def self.split_to_a(str, n)
|
|
if n > 0
|
|
s = str.dup
|
|
until s.empty?
|
|
(ret ||= []).push s.slice!(0, n)
|
|
end
|
|
else
|
|
ret = str
|
|
end
|
|
ret
|
|
end
|
|
|
|
protected
|
|
|
|
def self.converge_sets(sets, idx, offsets, length) # :nodoc:
|
|
buf = sets[idx][offsets[idx]].chr
|
|
|
|
# If there are more sets after use, converge with them.
|
|
if (sets[idx + 1])
|
|
buf << converge_sets(sets, idx + 1, offsets, length)
|
|
else
|
|
# Increment the current set offset as well as previous ones if we
|
|
# wrap back to zero.
|
|
while (idx >= 0 and ((offsets[idx] = (offsets[idx] + 1) % sets[idx].length)) == 0)
|
|
idx -= 1
|
|
end
|
|
|
|
# If we reached the point where the idx fell below zero, then that
|
|
# means we've reached the maximum threshold for permutations.
|
|
if (idx < 0)
|
|
return buf
|
|
end
|
|
|
|
end
|
|
|
|
buf
|
|
end
|
|
|
|
def self.load_codepage()
|
|
return if (!@@codepage_map_cache.nil?)
|
|
file = File.join(File.dirname(__FILE__),'codepage.map')
|
|
page = ''
|
|
name = ''
|
|
map = {}
|
|
File.open(file).each { |line|
|
|
next if line =~ /^#/
|
|
next if line =~ /^\s*$/
|
|
data = line.split
|
|
if data[1] =~ /^\(/
|
|
page = data.shift.to_i
|
|
name = data.join(' ').sub(/^\(/,'').sub(/\)$/,'')
|
|
map[page] = {}
|
|
map[page]['name'] = name
|
|
map[page]['data'] = {}
|
|
else
|
|
data.each { |entry|
|
|
wide, char = entry.split(':')
|
|
char = [char].pack('H*')
|
|
wide = [wide].pack('H*')
|
|
if map[page]['data'][char].nil?
|
|
map[page]['data'][char] = [wide]
|
|
else
|
|
map[page]['data'][char].push(wide)
|
|
end
|
|
}
|
|
end
|
|
}
|
|
@@codepage_map_cache = map
|
|
end
|
|
|
|
|
|
|
|
end
|
|
end
|