rex-text 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,219 @@
1
+ # -*- coding: binary -*-
2
+ module Rex
3
+ module Text
4
+ # We are re-opening the module to add these module methods.
5
+ # Breaking them up this way allows us to maintain a little higher
6
+ # degree of organisation and make it easier to find what you're looking for
7
+ # without hanging the underlying calls that we historically rely upon.
8
+
9
+
10
+ # The Iconv translation table for IBM's mainframe / System Z
11
+ # (z/os, s390, mvs, etc) - This is a different implementation
12
+ # of EBCDIC than the Iconv_EBCDIC below.
13
+ # It is technically referred to as Code Page IBM1047.
14
+ # This will be net new (until Ruby supports 1047 code page)
15
+ # for all Mainframe / SystemZ based modules
16
+ # that need to convert ASCII to EBCDIC
17
+ #
18
+ # The bytes are indexed by ASCII conversion number
19
+ # e.g. Iconv_IBM1047[0x41] == \xc1 for letter "A"
20
+ #
21
+ # Note the characters CANNOT be assumed to be in any logical
22
+ # order. Nor are the tables reversible. Lookups must be for each byte
23
+ # https://gist.github.com/bigendiansmalls/b08483ecedff52cc8fa3
24
+ #
25
+ Iconv_IBM1047 = [
26
+ "\x00","\x01","\x02","\x03","\x37","\x2d","\x2e","\x2f",
27
+ "\x16","\x05","\x15","\x0b","\x0c","\x0d","\x0e","\x0f","\x10",
28
+ "\x11","\x12","\x13","\x3c","\x3d","\x32","\x26","\x18","\x19",
29
+ "\x3f","\x27","\x1c","\x1d","\x1e","\x1f","\x40","\x5a","\x7f",
30
+ "\x7b","\x5b","\x6c","\x50","\x7d","\x4d","\x5d","\x5c","\x4e",
31
+ "\x6b","\x60","\x4b","\x61","\xf0","\xf1","\xf2","\xf3","\xf4",
32
+ "\xf5","\xf6","\xf7","\xf8","\xf9","\x7a","\x5e","\x4c","\x7e",
33
+ "\x6e","\x6f","\x7c","\xc1","\xc2","\xc3","\xc4","\xc5","\xc6",
34
+ "\xc7","\xc8","\xc9","\xd1","\xd2","\xd3","\xd4","\xd5","\xd6",
35
+ "\xd7","\xd8","\xd9","\xe2","\xe3","\xe4","\xe5","\xe6","\xe7",
36
+ "\xe8","\xe9","\xad","\xe0","\xbd","\x5f","\x6d","\x79","\x81",
37
+ "\x82","\x83","\x84","\x85","\x86","\x87","\x88","\x89","\x91",
38
+ "\x92","\x93","\x94","\x95","\x96","\x97","\x98","\x99","\xa2",
39
+ "\xa3","\xa4","\xa5","\xa6","\xa7","\xa8","\xa9","\xc0","\x4f",
40
+ "\xd0","\xa1","\x07","\x20","\x21","\x22","\x23","\x24","\x25",
41
+ "\x06","\x17","\x28","\x29","\x2a","\x2b","\x2c","\x09","\x0a",
42
+ "\x1b","\x30","\x31","\x1a","\x33","\x34","\x35","\x36","\x08",
43
+ "\x38","\x39","\x3a","\x3b","\x04","\x14","\x3e","\xff","\x41",
44
+ "\xaa","\x4a","\xb1","\x9f","\xb2","\x6a","\xb5","\xbb","\xb4",
45
+ "\x9a","\x8a","\xb0","\xca","\xaf","\xbc","\x90","\x8f","\xea",
46
+ "\xfa","\xbe","\xa0","\xb6","\xb3","\x9d","\xda","\x9b","\x8b",
47
+ "\xb7","\xb8","\xb9","\xab","\x64","\x65","\x62","\x66","\x63",
48
+ "\x67","\x9e","\x68","\x74","\x71","\x72","\x73","\x78","\x75",
49
+ "\x76","\x77","\xac","\x69","\xed","\xee","\xeb","\xef","\xec",
50
+ "\xbf","\x80","\xfd","\xfe","\xfb","\xfc","\xba","\xae","\x59",
51
+ "\x44","\x45","\x42","\x46","\x43","\x47","\x9c","\x48","\x54",
52
+ "\x51","\x52","\x53","\x58","\x55","\x56","\x57","\x8c","\x49",
53
+ "\xcd","\xce","\xcb","\xcf","\xcc","\xe1","\x70","\xdd","\xde",
54
+ "\xdb","\xdc","\x8d","\x8e","\xdf"
55
+ ]
56
+
57
+ #
58
+ # This is the reverse of the above, converts EBCDIC -> ASCII
59
+ # The bytes are indexed by IBM1047(EBCDIC) conversion number
60
+ # e.g. Iconv_ISO8859_1[0xc1] = \x41 for letter "A"
61
+ #
62
+ # Note the characters CANNOT be assumed to be in any logical (e.g. sequential)
63
+ # order. Nor are the tables reversible. Lookups must be done byte by byte
64
+ #
65
+ Iconv_ISO8859_1 = [
66
+ "\x00","\x01","\x02","\x03","\x9c","\x09","\x86","\x7f",
67
+ "\x97","\x8d","\x8e","\x0b","\x0c","\x0d","\x0e","\x0f","\x10",
68
+ "\x11","\x12","\x13","\x9d","\x0a","\x08","\x87","\x18","\x19",
69
+ "\x92","\x8f","\x1c","\x1d","\x1e","\x1f","\x80","\x81","\x82",
70
+ "\x83","\x84","\x85","\x17","\x1b","\x88","\x89","\x8a","\x8b",
71
+ "\x8c","\x05","\x06","\x07","\x90","\x91","\x16","\x93","\x94",
72
+ "\x95","\x96","\x04","\x98","\x99","\x9a","\x9b","\x14","\x15",
73
+ "\x9e","\x1a","\x20","\xa0","\xe2","\xe4","\xe0","\xe1","\xe3",
74
+ "\xe5","\xe7","\xf1","\xa2","\x2e","\x3c","\x28","\x2b","\x7c",
75
+ "\x26","\xe9","\xea","\xeb","\xe8","\xed","\xee","\xef","\xec",
76
+ "\xdf","\x21","\x24","\x2a","\x29","\x3b","\x5e","\x2d","\x2f",
77
+ "\xc2","\xc4","\xc0","\xc1","\xc3","\xc5","\xc7","\xd1","\xa6",
78
+ "\x2c","\x25","\x5f","\x3e","\x3f","\xf8","\xc9","\xca","\xcb",
79
+ "\xc8","\xcd","\xce","\xcf","\xcc","\x60","\x3a","\x23","\x40",
80
+ "\x27","\x3d","\x22","\xd8","\x61","\x62","\x63","\x64","\x65",
81
+ "\x66","\x67","\x68","\x69","\xab","\xbb","\xf0","\xfd","\xfe",
82
+ "\xb1","\xb0","\x6a","\x6b","\x6c","\x6d","\x6e","\x6f","\x70",
83
+ "\x71","\x72","\xaa","\xba","\xe6","\xb8","\xc6","\xa4","\xb5",
84
+ "\x7e","\x73","\x74","\x75","\x76","\x77","\x78","\x79","\x7a",
85
+ "\xa1","\xbf","\xd0","\x5b","\xde","\xae","\xac","\xa3","\xa5",
86
+ "\xb7","\xa9","\xa7","\xb6","\xbc","\xbd","\xbe","\xdd","\xa8",
87
+ "\xaf","\x5d","\xb4","\xd7","\x7b","\x41","\x42","\x43","\x44",
88
+ "\x45","\x46","\x47","\x48","\x49","\xad","\xf4","\xf6","\xf2",
89
+ "\xf3","\xf5","\x7d","\x4a","\x4b","\x4c","\x4d","\x4e","\x4f",
90
+ "\x50","\x51","\x52","\xb9","\xfb","\xfc","\xf9","\xfa","\xff",
91
+ "\x5c","\xf7","\x53","\x54","\x55","\x56","\x57","\x58","\x59",
92
+ "\x5a","\xb2","\xd4","\xd6","\xd2","\xd3","\xd5","\x30","\x31",
93
+ "\x32","\x33","\x34","\x35","\x36","\x37","\x38","\x39","\xb3",
94
+ "\xdb","\xdc","\xd9","\xda","\x9f"
95
+ ]
96
+
97
+ # The Iconv translation table. The Iconv gem is deprecated in favor of
98
+ # String#encode, yet there is no encoding for EBCDIC. See #4525
99
+ Iconv_EBCDIC = [
100
+ "\x00", "\x01", "\x02", "\x03", "7", "-", ".", "/", "\x16", "\x05",
101
+ "%", "\v", "\f", "\r", "\x0E", "\x0F", "\x10", "\x11", "\x12", "\x13",
102
+ "<", "=", "2", "&", "\x18", "\x19", "?", "'", "\x1C", "\x1D", "\x1E",
103
+ "\x1F", "@", "Z", "\x7F", "{", "[", "l", "P", "}", "M", "]", "\\",
104
+ "N", "k", "`", "K", "a", "\xF0", "\xF1", "\xF2", "\xF3", "\xF4",
105
+ "\xF5", "\xF6", "\xF7", "\xF8", "\xF9", "z", "^", "L", "~", "n", "o",
106
+ "|", "\xC1", "\xC2", "\xC3", "\xC4", "\xC5", "\xC6", "\xC7", "\xC8",
107
+ "\xC9", "\xD1", "\xD2", "\xD3", "\xD4", "\xD5", "\xD6", "\xD7",
108
+ "\xD8", "\xD9", "\xE2", "\xE3", "\xE4", "\xE5", "\xE6", "\xE7",
109
+ "\xE8", "\xE9", nil, "\xE0", nil, nil, "m", "y", "\x81", "\x82",
110
+ "\x83", "\x84", "\x85", "\x86", "\x87", "\x88", "\x89", "\x91",
111
+ "\x92", "\x93", "\x94", "\x95", "\x96", "\x97", "\x98", "\x99",
112
+ "\xA2", "\xA3", "\xA4", "\xA5", "\xA6", "\xA7", "\xA8", "\xA9",
113
+ "\xC0", "O", "\xD0", "\xA1", "\a", nil, nil, nil, nil, nil, nil,
114
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
115
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
116
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
117
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
118
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
119
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
120
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
121
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
122
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
123
+ nil, nil, nil, nil, nil
124
+ ]
125
+
126
+ Iconv_ASCII = [
127
+ "\x00", "\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\a", "\b",
128
+ "\t", "\n", "\v", "\f", "\r", "\x0E", "\x0F", "\x10", "\x11", "\x12",
129
+ "\x13", "\x14", "\x15", "\x16", "\x17", "\x18", "\x19", "\x1A", "\e",
130
+ "\x1C", "\x1D", "\x1E", "\x1F", " ", "!", "\"", "#", "$", "%", "&",
131
+ "'", "(", ")", "*", "+", ",", "-", ".", "/", "0", "1", "2", "3", "4",
132
+ "5", "6", "7", "8", "9", ":", ";", "<", "=", ">", "?", "@", "A", "B",
133
+ "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P",
134
+ "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", nil, "\\", nil,
135
+ nil, "_", "`", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
136
+ "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y",
137
+ "z", "{", "|", "}", "~", "\x7F", nil, nil, nil, nil, nil, nil, nil,
138
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
139
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
140
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
141
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
142
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
143
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
144
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
145
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
146
+ nil, nil, nil, nil, nil, nil, nil, nil, nil
147
+ ]
148
+
149
+ # A native implementation of the ASCII to EBCDIC conversion table, since
150
+ # EBCDIC isn't available to String#encode as of Ruby 2.1
151
+ #
152
+ # @param str [String] An encodable ASCII string
153
+ # @return [String] an EBCDIC encoded string
154
+ # @note This method will raise in the event of invalid characters
155
+ def self.to_ebcdic(str)
156
+ new_str = []
157
+ str.each_byte do |x|
158
+ if Iconv_ASCII.index(x.chr)
159
+ new_str << Iconv_EBCDIC[Iconv_ASCII.index(x.chr)]
160
+ else
161
+ raise Rex::Text::IllegalSequence, ("\\x%x" % x)
162
+ end
163
+ end
164
+ new_str.join
165
+ end
166
+
167
+ # A native implementation of the EBCDIC to ASCII conversion table, since
168
+ # EBCDIC isn't available to String#encode as of Ruby 2.1
169
+ #
170
+ # @param str [String] an EBCDIC encoded string
171
+ # @return [String] An encodable ASCII string
172
+ # @note This method will raise in the event of invalid characters
173
+ def self.from_ebcdic(str)
174
+ new_str = []
175
+ str.each_byte do |x|
176
+ if Iconv_EBCDIC.index(x.chr)
177
+ new_str << Iconv_ASCII[Iconv_EBCDIC.index(x.chr)]
178
+ else
179
+ raise Rex::Text::IllegalSequence, ("\\x%x" % x)
180
+ end
181
+ end
182
+ new_str.join
183
+ end
184
+
185
+ #
186
+ # The next two are the same as the above, except strictly for z/os
187
+ # conversions
188
+ # strictly for IBM1047 -> ISO8859-1
189
+ # A native implementation of the IBM1047(EBCDIC) -> ISO8859-1(ASCII)
190
+ # conversion table, since EBCDIC isn't available to String#encode as of Ruby 2.1
191
+ # all 256 bytes are defined
192
+ #
193
+ def self.to_ibm1047(str)
194
+ return str if str.nil?
195
+ new_str = []
196
+ str.each_byte do |x|
197
+ new_str << Iconv_IBM1047[x.ord]
198
+ end
199
+ new_str.join
200
+ end
201
+
202
+ #
203
+ # The next two are the same as the above, except strictly for z/os
204
+ # conversions
205
+ # strictly for ISO8859-1 -> IBM1047
206
+ # A native implementation of the ISO8859-1(ASCII) -> IBM1047(EBCDIC)
207
+ # conversion table, since EBCDIC isn't available to String#encode as of Ruby 2.1
208
+ #
209
+ def self.from_ibm1047(str)
210
+ return str if str.nil?
211
+ new_str = []
212
+ str.each_byte do |x|
213
+ new_str << Iconv_ISO8859_1[x.ord]
214
+ end
215
+ new_str.join
216
+ end
217
+
218
+ end
219
+ end
@@ -0,0 +1,104 @@
1
+ # -*- coding: binary -*-
2
+ module Rex
3
+ module Text
4
+ # We are re-opening the module to add these module methods.
5
+ # Breaking them up this way allows us to maintain a little higher
6
+ # degree of organisation and make it easier to find what you're looking for
7
+ # without hanging the underlying calls that we historically rely upon.
8
+
9
+
10
+
11
+ #
12
+ # Encode a string in a manor useful for HTTP URIs and URI Parameters.
13
+ #
14
+ def self.uri_encode(str, mode = 'hex-normal')
15
+ return "" if str == nil
16
+
17
+ return str if mode == 'none' # fast track no encoding
18
+
19
+ all = /./
20
+ noslashes = /[^\/\\]+/
21
+ # http://tools.ietf.org/html/rfc3986#section-2.3
22
+ normal = /[^a-zA-Z0-9\/\\\.\-_~]+/
23
+
24
+ case mode
25
+ when 'hex-all'
26
+ return str.gsub(all) { |s| Rex::Text.to_hex(s, '%') }
27
+ when 'hex-normal'
28
+ return str.gsub(normal) { |s| Rex::Text.to_hex(s, '%') }
29
+ when 'hex-noslashes'
30
+ return str.gsub(noslashes) { |s| Rex::Text.to_hex(s, '%') }
31
+ when 'hex-random'
32
+ res = ''
33
+ str.each_byte do |c|
34
+ b = c.chr
35
+ res << ((rand(2) == 0) ?
36
+ b.gsub(all) { |s| Rex::Text.to_hex(s, '%') } :
37
+ b.gsub(normal){ |s| Rex::Text.to_hex(s, '%') } )
38
+ end
39
+ return res
40
+ when 'u-all'
41
+ return str.gsub(all) { |s| Rex::Text.to_hex(Rex::Text.to_unicode(s, 'uhwtfms'), '%u', 2) }
42
+ when 'u-normal'
43
+ return str.gsub(normal) { |s| Rex::Text.to_hex(Rex::Text.to_unicode(s, 'uhwtfms'), '%u', 2) }
44
+ when 'u-noslashes'
45
+ return str.gsub(noslashes) { |s| Rex::Text.to_hex(Rex::Text.to_unicode(s, 'uhwtfms'), '%u', 2) }
46
+ when 'u-random'
47
+ res = ''
48
+ str.each_byte do |c|
49
+ b = c.chr
50
+ res << ((rand(2) == 0) ?
51
+ b.gsub(all) { |s| Rex::Text.to_hex(Rex::Text.to_unicode(s, 'uhwtfms'), '%u', 2) } :
52
+ b.gsub(normal){ |s| Rex::Text.to_hex(Rex::Text.to_unicode(s, 'uhwtfms'), '%u', 2) } )
53
+ end
54
+ return res
55
+ when 'u-half'
56
+ return str.gsub(all) { |s| Rex::Text.to_hex(Rex::Text.to_unicode(s, 'uhwtfms-half'), '%u', 2) }
57
+ else
58
+ raise TypeError, "invalid mode #{mode.inspect}"
59
+ end
60
+ end
61
+
62
+ #
63
+ # Encode a string in a manner useful for HTTP URIs and URI Parameters.
64
+ #
65
+ # @param str [String] The string to be encoded
66
+ # @param mode ["hex","int","int-wide"]
67
+ # @return [String]
68
+ # @raise [TypeError] if +mode+ is not one of the three available modes
69
+ def self.html_encode(str, mode = 'hex')
70
+ case mode
71
+ when 'hex'
72
+ return str.unpack('C*').collect{ |i| "&#x" + ("%.2x" % i) + ";"}.join
73
+ when 'int'
74
+ return str.unpack('C*').collect{ |i| "&#" + i.to_s + ";"}.join
75
+ when 'int-wide'
76
+ return str.unpack('C*').collect{ |i| "&#" + ("0" * (7 - i.to_s.length)) + i.to_s + ";" }.join
77
+ else
78
+ raise TypeError, 'invalid mode'
79
+ end
80
+ end
81
+
82
+ #
83
+ # Decode a string that's html encoded
84
+ #
85
+ def self.html_decode(str)
86
+ decoded_str = CGI.unescapeHTML(str)
87
+ return decoded_str
88
+ end
89
+
90
+ #
91
+ # Encode an ASCII string so it's safe for XML. It's a wrapper for to_hex_ascii.
92
+ #
93
+ def self.xml_char_encode(str)
94
+ self.to_hex_ascii(str, "&#x", 1, ";")
95
+ end
96
+
97
+ #
98
+ # Decode a URI encoded string
99
+ #
100
+ def self.uri_decode(str)
101
+ str.gsub(/(%[a-z0-9]{2})/i){ |c| [c[1,2]].pack("H*") }
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,37 @@
1
+ # -*- coding: binary -*-
2
+ module Rex
3
+ module Text
4
+ # We are re-opening the module to add these module methods.
5
+ # Breaking them up this way allows us to maintain a little higher
6
+ # degree of organisation and make it easier to find what you're looking for
7
+ # without hanging the underlying calls that we historically rely upon.
8
+
9
+ #
10
+ # Raw MD5 digest of the supplied string
11
+ #
12
+ def self.md5_raw(str)
13
+ Digest::MD5.digest(str)
14
+ end
15
+
16
+ #
17
+ # Hexidecimal MD5 digest of the supplied string
18
+ #
19
+ def self.md5(str)
20
+ Digest::MD5.hexdigest(str)
21
+ end
22
+
23
+ #
24
+ # Raw SHA1 digest of the supplied string
25
+ #
26
+ def self.sha1_raw(str)
27
+ Digest::SHA1.digest(str)
28
+ end
29
+
30
+ #
31
+ # Hexidecimal SHA1 digest of the supplied string
32
+ #
33
+ def self.sha1(str)
34
+ Digest::SHA1.hexdigest(str)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,204 @@
1
+ # -*- coding: binary -*-
2
+ module Rex
3
+ module Text
4
+ # We are re-opening the module to add these module methods.
5
+ # Breaking them up this way allows us to maintain a little higher
6
+ # degree of organisation and make it easier to find what you're looking for
7
+ # without hanging the underlying calls that we historically rely upon.
8
+
9
+ #
10
+ # Returns the escaped hex version of the supplied string
11
+ #
12
+ # @example
13
+ # Rex::Text.to_hex("asdf") # => "\\x61\\x73\\x64\\x66"
14
+ #
15
+ # @param str (see to_octal)
16
+ # @param prefix (see to_octal)
17
+ # @param count [Fixnum] Number of bytes to put in each escape chunk
18
+ # @return [String] The escaped hex version of +str+
19
+ def self.to_hex(str, prefix = "\\x", count = 1)
20
+ raise ::RuntimeError, "unable to chunk into #{count} byte chunks" if ((str.length % count) > 0)
21
+
22
+ # XXX: Regexp.new is used here since using /.{#{count}}/o would compile
23
+ # the regex the first time it is used and never check again. Since we
24
+ # want to know how many to capture on every instance, we do it this
25
+ # way.
26
+ return str.unpack('H*')[0].gsub(Regexp.new(".{#{count * 2}}", nil, 'n')) { |s| prefix + s }
27
+ end
28
+
29
+ #
30
+ # Returns the string with nonprintable hex characters sanitized to ascii.
31
+ # Similiar to {.to_hex}, but regular ASCII is not translated if +count+ is 1.
32
+ #
33
+ # @example
34
+ # Rex::Text.to_hex_ascii("\x7fABC\0") # => "\\x7fABC\\x00"
35
+ #
36
+ # @param str (see to_hex)
37
+ # @param prefix (see to_hex)
38
+ # @param count (see to_hex)
39
+ # @param suffix [String,nil] A string to append to the converted bytes
40
+ # @return [String] The original string with non-printables converted to
41
+ # their escaped hex representation
42
+ def self.to_hex_ascii(str, prefix = "\\x", count = 1, suffix=nil)
43
+ raise ::RuntimeError, "unable to chunk into #{count} byte chunks" if ((str.length % count) > 0)
44
+ return str.unpack('H*')[0].gsub(Regexp.new(".{#{count * 2}}", nil, 'n')) { |s|
45
+ (0x20..0x7e) === s.to_i(16) ? s.to_i(16).chr : prefix + s + suffix.to_s
46
+ }
47
+ end
48
+
49
+ #
50
+ # Converts a string to a nicely formatted hex dump
51
+ #
52
+ # @param str [String] The string to convert
53
+ # @param width [Fixnum] Number of bytes to convert before adding a newline
54
+ # @param base [Fixnum] The base address of the dump
55
+ def self.to_hex_dump(str, width=16, base=nil)
56
+ buf = ''
57
+ idx = 0
58
+ cnt = 0
59
+ snl = false
60
+ lst = 0
61
+ lft_col_len = (base.to_i+str.length).to_s(16).length
62
+ lft_col_len = 8 if lft_col_len < 8
63
+
64
+ while (idx < str.length)
65
+ chunk = str[idx, width]
66
+ addr = base ? "%0#{lft_col_len}x " %(base.to_i + idx) : ''
67
+ line = chunk.unpack("H*")[0].scan(/../).join(" ")
68
+ buf << addr + line
69
+
70
+ if (lst == 0)
71
+ lst = line.length
72
+ buf << " " * 4
73
+ else
74
+ buf << " " * ((lst - line.length) + 4).abs
75
+ end
76
+
77
+ buf << "|"
78
+
79
+ chunk.unpack("C*").each do |c|
80
+ if (c > 0x1f and c < 0x7f)
81
+ buf << c.chr
82
+ else
83
+ buf << "."
84
+ end
85
+ end
86
+
87
+ buf << "|\n"
88
+
89
+ idx += width
90
+ end
91
+
92
+ buf << "\n"
93
+ end
94
+
95
+ #
96
+ # Converts a hex string to a raw string
97
+ #
98
+ # @example
99
+ # Rex::Text.hex_to_raw("\\x41\\x7f\\x42") # => "A\x7fB"
100
+ #
101
+ def self.hex_to_raw(str)
102
+ [ str.downcase.gsub(/'/,'').gsub(/\\?x([a-f0-9][a-f0-9])/, '\1') ].pack("H*")
103
+ end
104
+
105
+ #
106
+ # Turn non-printable chars into hex representations, leaving others alone
107
+ #
108
+ # If +whitespace+ is true, converts whitespace (0x20, 0x09, etc) to hex as
109
+ # well.
110
+ #
111
+ # @see hexify
112
+ # @see to_hex Converts all the chars
113
+ #
114
+ def self.ascii_safe_hex(str, whitespace=false)
115
+ if whitespace
116
+ str.gsub(/([\x00-\x20\x80-\xFF])/n){ |x| "\\x%.2x" % x.unpack("C*")[0] }
117
+ else
118
+ str.gsub(/([\x00-\x08\x0b\x0c\x0e-\x1f\x80-\xFF])/n){ |x| "\\x%.2x" % x.unpack("C*")[0]}
119
+ end
120
+ end
121
+
122
+ #
123
+ # Converts a string to a hex version with wrapping support
124
+ #
125
+ def self.hexify(str, col = DefaultWrap, line_start = '', line_end = '', buf_start = '', buf_end = '')
126
+ output = buf_start
127
+ cur = 0
128
+ count = 0
129
+ new_line = true
130
+
131
+ # Go through each byte in the string
132
+ str.each_byte { |byte|
133
+ count += 1
134
+ append = ''
135
+
136
+ # If this is a new line, prepend with the
137
+ # line start text
138
+ if (new_line == true)
139
+ append << line_start
140
+ new_line = false
141
+ end
142
+
143
+ # Append the hexified version of the byte
144
+ append << sprintf("\\x%.2x", byte)
145
+ cur += append.length
146
+
147
+ # If we're about to hit the column or have gone past it,
148
+ # time to finish up this line
149
+ if ((cur + line_end.length >= col) or (cur + buf_end.length >= col))
150
+ new_line = true
151
+ cur = 0
152
+
153
+ # If this is the last byte, use the buf_end instead of
154
+ # line_end
155
+ if (count == str.length)
156
+ append << buf_end + "\n"
157
+ else
158
+ append << line_end + "\n"
159
+ end
160
+ end
161
+
162
+ output << append
163
+ }
164
+
165
+ # If we were in the middle of a line, finish the buffer at this point
166
+ if (new_line == false)
167
+ output << buf_end + "\n"
168
+ end
169
+
170
+ return output
171
+ end
172
+
173
+ #
174
+ # Convert hex-encoded characters to literals.
175
+ #
176
+ # @example
177
+ # Rex::Text.dehex("AA\\x42CC") # => "AABCC"
178
+ #
179
+ # @see hex_to_raw
180
+ # @param str [String]
181
+ def self.dehex(str)
182
+ return str unless str.respond_to? :match
183
+ return str unless str.respond_to? :gsub
184
+ regex = /\x5cx[0-9a-f]{2}/nmi
185
+ if str.match(regex)
186
+ str.gsub(regex) { |x| x[2,2].to_i(16).chr }
187
+ else
188
+ str
189
+ end
190
+ end
191
+
192
+ #
193
+ # Convert and replace hex-encoded characters to literals.
194
+ #
195
+ # @param (see dehex)
196
+ def self.dehex!(str)
197
+ return str unless str.respond_to? :match
198
+ return str unless str.respond_to? :gsub
199
+ regex = /\x5cx[0-9a-f]{2}/nmi
200
+ str.gsub!(regex) { |x| x[2,2].to_i(16).chr }
201
+ end
202
+
203
+ end
204
+ end