Skip to content

Commit 93bddd9

Browse files
committed
Improved docs and partial specs for Rex::Text
Conflicts: lib/msf/core/modules/loader/base.rb lib/rex/poly/block.rb lib/rex/text.rb
1 parent 47097ec commit 93bddd9

File tree

3 files changed

+203
-19
lines changed

3 files changed

+203
-19
lines changed

lib/rex/poly/block.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ def once
124124
#
125125
# Increments the number of blocks that depend on this block.
126126
#
127+
# @see #deref
127128
def ref
128129
@references += 1
129130
end
@@ -133,6 +134,7 @@ def ref
133134
# pass on this block. This number should never become higher than the
134135
# `@references` attribute.
135136
#
137+
# @see #ref
136138
def deref
137139
@used_references += 1
138140
end

lib/rex/text.rb

Lines changed: 125 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,15 @@ def self.to_unescape(data, endian=ENDIAN_LITTLE)
276276
return buff
277277
end
278278

279+
#
280+
# Returns the escaped octal version of the supplied string
281+
#
282+
# @example
283+
# Rex::Text.to_octal("asdf") # => "\\141\\163\\144\\146"
284+
#
285+
# @param str [String] The string to be converted
286+
# @param prefix [String]
287+
# @return [String] The escaped octal version of +str+
279288
def self.to_octal(str, prefix = "\\")
280289
octal = ""
281290
str.each_byte { |b|
@@ -286,8 +295,15 @@ def self.to_octal(str, prefix = "\\")
286295
end
287296

288297
#
289-
# Returns the hex version of the supplied string
298+
# Returns the escaped hex version of the supplied string
299+
#
300+
# @example
301+
# Rex::Text.to_hex("asdf") # => "\\x61\\x73\\x64\\x66"
290302
#
303+
# @param str (see to_octal)
304+
# @param prefix (see to_octal)
305+
# @param count [Fixnum] Number of bytes to put in each escape chunk
306+
# @return [String] The escaped hex version of +str+
291307
def self.to_hex(str, prefix = "\\x", count = 1)
292308
raise ::RuntimeError, "unable to chunk into #{count} byte chunks" if ((str.length % count) > 0)
293309

@@ -299,9 +315,18 @@ def self.to_hex(str, prefix = "\\x", count = 1)
299315
end
300316

301317
#
302-
# Returns the string with nonprintable hex characters sanitized to ascii. Similiar to to_hex,
303-
# but regular ASCII is not translated if count is 1.
318+
# Returns the string with nonprintable hex characters sanitized to ascii.
319+
# Similiar to {.to_hex}, but regular ASCII is not translated if +count+ is 1.
304320
#
321+
# @example
322+
# Rex::Text.to_hex_ascii("\x7fABC\0") # => "\\x7fABC\\x00"
323+
#
324+
# @param str (see to_hex)
325+
# @param prefix (see to_hex)
326+
# @param count (see to_hex)
327+
# @param suffix [String,nil] A string to append to the converted bytes
328+
# @return [String] The original string with non-printables converted to
329+
# their escaped hex representation
305330
def self.to_hex_ascii(str, prefix = "\\x", count = 1, suffix=nil)
306331
raise ::RuntimeError, "unable to chunk into #{count} byte chunks" if ((str.length % count) > 0)
307332
return str.unpack('H*')[0].gsub(Regexp.new(".{#{count * 2}}", nil, 'n')) { |s|
@@ -557,6 +582,10 @@ def self.uri_encode(str, mode = 'hex-normal')
557582
#
558583
# Encode a string in a manner useful for HTTP URIs and URI Parameters.
559584
#
585+
# @param str [String] The string to be encoded
586+
# @param mode ["hex","int","int-wide"]
587+
# @return [String]
588+
# @raise [TypeError] if +mode+ is not one of the three available modes
560589
def self.html_encode(str, mode = 'hex')
561590
case mode
562591
when 'hex'
@@ -595,6 +624,13 @@ def self.uri_decode(str)
595624
#
596625
# Converts a string to random case
597626
#
627+
# @example
628+
# Rex::Text.to_rand_case("asdf") # => "asDf"
629+
#
630+
# @param str [String] The string to randomize
631+
# @return [String]
632+
# @see permute_case
633+
# @see to_mixed_case_array
598634
def self.to_rand_case(str)
599635
buf = str.dup
600636
0.upto(str.length) do |i|
@@ -606,11 +642,13 @@ def self.to_rand_case(str)
606642
#
607643
# Takes a string, and returns an array of all mixed case versions.
608644
#
609-
# Example:
610-
#
611-
# >> Rex::Text.to_mixed_case_array "abc1"
612-
# => ["abc1", "abC1", "aBc1", "aBC1", "Abc1", "AbC1", "ABc1", "ABC1"]
645+
# @example
646+
# >> Rex::Text.to_mixed_case_array "abc1"
647+
# => ["abc1", "abC1", "aBc1", "aBC1", "Abc1", "AbC1", "ABc1", "ABC1"]
613648
#
649+
# @param str [String] The string to randomize
650+
# @return [Array<String>]
651+
# @see permute_case
614652
def self.to_mixed_case_array(str)
615653
letters = []
616654
str.scan(/./).each { |l| letters << [l.downcase, l.upcase] }
@@ -627,8 +665,10 @@ def self.to_mixed_case_array(str)
627665
end
628666

629667
#
630-
# Converts a string a nicely formatted hex dump
668+
# Converts a string to a nicely formatted hex dump
631669
#
670+
# @param str [String] The string to convert
671+
# @param width [Fixnum] Number of bytes to convert before adding a newline
632672
def self.to_hex_dump(str, width=16)
633673
buf = ''
634674
idx = 0
@@ -711,6 +751,9 @@ def self.to_addr_hex_dump(str, start_addr=0, width=16)
711751
#
712752
# Converts a hex string to a raw string
713753
#
754+
# @example
755+
# Rex::Text.hex_to_raw("\\x41\\x7f\\x42") # => "A\x7fB"
756+
#
714757
def self.hex_to_raw(str)
715758
[ str.downcase.gsub(/'/,'').gsub(/\\?x([a-f0-9][a-f0-9])/, '\1') ].pack("H*")
716759
end
@@ -721,6 +764,9 @@ def self.hex_to_raw(str)
721764
# If +whitespace+ is true, converts whitespace (0x20, 0x09, etc) to hex as
722765
# well.
723766
#
767+
# @see hexify
768+
# @see to_hex Converts all the chars
769+
#
724770
def self.ascii_safe_hex(str, whitespace=false)
725771
if whitespace
726772
str.gsub(/([\x00-\x20\x80-\xFF])/){ |x| "\\x%.2x" % x.unpack("C*")[0] }
@@ -915,8 +961,12 @@ def self.sha1(str)
915961

916962
#
917963
# Convert hex-encoded characters to literals.
918-
# Example: "AA\\x42CC" becomes "AABCC"
919964
#
965+
# @example
966+
# Rex::Text.dehex("AA\\x42CC") # => "AABCC"
967+
#
968+
# @see hex_to_raw
969+
# @param str [String]
920970
def self.dehex(str)
921971
return str unless str.respond_to? :match
922972
return str unless str.respond_to? :gsub
@@ -931,6 +981,7 @@ def self.dehex(str)
931981
#
932982
# Convert and replace hex-encoded characters to literals.
933983
#
984+
# @param (see dehex)
934985
def self.dehex!(str)
935986
return str unless str.respond_to? :match
936987
return str unless str.respond_to? :gsub
@@ -1020,7 +1071,12 @@ def self.rand_text_highascii(len, bad='')
10201071
rand_base(len, bad, *foo )
10211072
end
10221073

1023-
# Generate a random GUID, of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
1074+
# Generate a random GUID
1075+
#
1076+
# @example
1077+
# Rex::Text.rand_guid # => "{ca776ced-4ab8-2ed6-6510-aa71e5e2508e}"
1078+
#
1079+
# @return [String]
10241080
def self.rand_guid
10251081
"{#{[8,4,4,4,12].map {|a| rand_text_hex(a) }.join("-")}}"
10261082
end
@@ -1031,9 +1087,15 @@ def self.rand_guid
10311087
# supplied number of identifiable characters (slots). The supplied sets
10321088
# should not contain any duplicate characters or the logic will fail.
10331089
#
1090+
# @param length [Fixnum]
1091+
# @param sets [Array<(String,String,String)>] The character sets to choose
1092+
# from. Should have 3 elements, each of which must be a string containing
1093+
# no characters contained in the other sets.
1094+
# @return [String] A pattern of +length+ bytes, in which any 4-byte chunk is
1095+
# unique
1096+
# @see pattern_offset
10341097
def self.pattern_create(length, sets = nil)
10351098
buf = ''
1036-
idx = 0
10371099
offsets = []
10381100

10391101
# Make sure there's something in sets even if we were given an explicit nil
@@ -1084,6 +1146,12 @@ def self.patt2(len, sets = nil)
10841146
#
10851147
# Calculate the offset to a pattern
10861148
#
1149+
# @param pattern [String] The pattern to search. Usually the return value
1150+
# from {.pattern_create}
1151+
# @param value [String,Fixnum,Bignum]
1152+
# @return [Fixnum] Index of the given +value+ within +pattern+, if it exists
1153+
# @return [nil] if +pattern+ does not contain +value+
1154+
# @see pattern_create
10871155
def self.pattern_offset(pattern, value, start=0)
10881156
if (value.kind_of?(String))
10891157
pattern.index(value, start)
@@ -1098,6 +1166,9 @@ def self.pattern_offset(pattern, value, start=0)
10981166
# Compresses a string, eliminating all superfluous whitespace before and
10991167
# after lines and eliminating all lines.
11001168
#
1169+
# @param str [String] The string in which to crunch whitespace
1170+
# @return [String] Just like +str+, but with repeated whitespace characters
1171+
# trimmed down to a single space
11011172
def self.compress(str)
11021173
str.gsub(/\n/m, ' ').gsub(/\s+/, ' ').gsub(/^\s+/, '').gsub(/\s+$/, '')
11031174
end
@@ -1136,6 +1207,9 @@ def self.gzip_present?
11361207
#
11371208
# Compresses a string using zlib
11381209
#
1210+
# @param str [String] The string to be compressed
1211+
# @param level [Fixnum] One of the Zlib compression level constants
1212+
# @return [String] The compressed version of +str+
11391213
def self.zlib_deflate(str, level = Zlib::BEST_COMPRESSION)
11401214
if self.zlib_present?
11411215
z = Zlib::Deflate.new(level)
@@ -1150,6 +1224,8 @@ def self.zlib_deflate(str, level = Zlib::BEST_COMPRESSION)
11501224
#
11511225
# Uncompresses a string using zlib
11521226
#
1227+
# @param str [String] Compressed string to inflate
1228+
# @return [String] The uncompressed version of +str+
11531229
def self.zlib_inflate(str)
11541230
if(self.zlib_present?)
11551231
zstream = Zlib::Inflate.new
@@ -1165,6 +1241,9 @@ def self.zlib_inflate(str)
11651241
#
11661242
# Compresses a string using gzip
11671243
#
1244+
# @param str (see zlib_deflate)
1245+
# @param level [Fixnum] Compression level, 1 (fast) to 9 (best)
1246+
# @return (see zlib_deflate)
11681247
def self.gzip(str, level = 9)
11691248
raise RuntimeError, "Gzip support is not present." if (!zlib_present?)
11701249
raise RuntimeError, "Invalid gzip compression level" if (level < 1 or level > 9)
@@ -1180,6 +1259,8 @@ def self.gzip(str, level = 9)
11801259
#
11811260
# Uncompresses a string using gzip
11821261
#
1262+
# @param str (see zlib_inflate)
1263+
# @return (see zlib_inflate)
11831264
def self.ungzip(str)
11841265
raise RuntimeError, "Gzip support is not present." if (!zlib_present?)
11851266

@@ -1192,9 +1273,13 @@ def self.ungzip(str)
11921273
end
11931274

11941275
#
1195-
# Return the index of the first badchar in data, otherwise return
1276+
# Return the index of the first badchar in +data+, otherwise return
11961277
# nil if there wasn't any badchar occurences.
11971278
#
1279+
# @param data [String] The string to check for bad characters
1280+
# @param badchars [String] A list of characters considered to be bad
1281+
# @return [Fixnum] Index of the first bad character if any exist in +data+
1282+
# @return [nil] If +data+ contains no bad characters
11981283
def self.badchar_index(data, badchars = '')
11991284
badchars.unpack("C*").each { |badchar|
12001285
pos = data.index(badchar.chr)
@@ -1204,29 +1289,42 @@ def self.badchar_index(data, badchars = '')
12041289
end
12051290

12061291
#
1207-
# This method removes bad characters from a string.
1292+
# Removes bad characters from a string.
1293+
#
1294+
# Modifies +data+ in place
12081295
#
1296+
# @param data [#delete]
1297+
# @param badchars [String] A list of characters considered to be bad
12091298
def self.remove_badchars(data, badchars = '')
12101299
data.delete(badchars)
12111300
end
12121301

12131302
#
1214-
# This method returns all chars but the supplied set
1303+
# Returns all chars that are not in the supplied set
12151304
#
1305+
# @param keepers [String]
1306+
# @return [String] All characters not contained in +keepers+
12161307
def self.charset_exclude(keepers)
12171308
[*(0..255)].pack('C*').delete(keepers)
12181309
end
12191310

12201311
#
1221-
# Shuffles a byte stream
1312+
# Shuffles a byte stream
12221313
#
1314+
# @param str [String]
1315+
# @return [String] The shuffled result
1316+
# @see shuffle_a
12231317
def self.shuffle_s(str)
12241318
shuffle_a(str.unpack("C*")).pack("C*")
12251319
end
12261320

12271321
#
12281322
# Performs a Fisher-Yates shuffle on an array
12291323
#
1324+
# Modifies +arr+ in place
1325+
#
1326+
# @param arr [Array] The array to be shuffled
1327+
# @return [Array]
12301328
def self.shuffle_a(arr)
12311329
len = arr.length
12321330
max = len - 1
@@ -1268,6 +1366,8 @@ def self.permute_case(word, idx=0)
12681366
end
12691367

12701368
# Generate a random hostname
1369+
#
1370+
# @return [String] A random string conforming to the rules of FQDNs
12711371
def self.rand_hostname
12721372
host = []
12731373
(rand(5) + 1).times {
@@ -1287,15 +1387,18 @@ def self.rand_state()
12871387
#
12881388
# Calculate the ROR13 hash of a given string
12891389
#
1390+
# @return [Fixnum]
12901391
def self.ror13_hash(name)
12911392
hash = 0
12921393
name.unpack("C*").each {|c| hash = ror(hash, 13); hash += c }
12931394
hash
12941395
end
12951396

12961397
#
1297-
# Rotate a 32-bit value to the right by cnt bits
1398+
# Rotate a 32-bit value to the right by +cnt+ bits
12981399
#
1400+
# @param val [Fixnum] The value to rotate
1401+
# @param cnt [Fixnum] Number of bits to rotate by
12991402
def self.ror(val, cnt)
13001403
bits = [val].pack("N").unpack("B32")[0].split(//)
13011404
1.upto(cnt) do |c|
@@ -1305,8 +1408,11 @@ def self.ror(val, cnt)
13051408
end
13061409

13071410
#
1308-
# Rotate a 32-bit value to the left by cnt bits
1411+
# Rotate a 32-bit value to the left by +cnt+ bits
13091412
#
1413+
# @param val (see ror)
1414+
# @param cnt (see ror)
1415+
# @return (see ror)
13101416
def self.rol(val, cnt)
13111417
bits = [val].pack("N").unpack("B32")[0].split(//)
13121418
1.upto(cnt) do |c|
@@ -1316,7 +1422,7 @@ def self.rol(val, cnt)
13161422
end
13171423

13181424
#
1319-
# Split a string by n charachter into an array
1425+
# Split a string by n character into an array
13201426
#
13211427
def self.split_to_a(str, n)
13221428
if n > 0
@@ -1331,7 +1437,7 @@ def self.split_to_a(str, n)
13311437
end
13321438

13331439
#
1334-
#Pack a value as 64 bit litle endian; does not exist for Array.pack
1440+
# Pack a value as 64 bit litle endian; does not exist for Array.pack
13351441
#
13361442
def self.pack_int64le(val)
13371443
[val & 0x00000000ffffffff, val >> 32].pack("V2")

0 commit comments

Comments
 (0)