rex-text/lib/rex/text.rb

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