rex-exploitation 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.
Files changed (69) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +1 -0
  4. data/.gitignore +9 -0
  5. data/.rspec +2 -0
  6. data/.travis.yml +5 -0
  7. data/CODE_OF_CONDUCT.md +74 -0
  8. data/Gemfile +4 -0
  9. data/README.md +33 -0
  10. data/Rakefile +6 -0
  11. data/bin/console +14 -0
  12. data/bin/setup +8 -0
  13. data/data/exploits/cmdstager/debug_asm +91 -0
  14. data/data/exploits/cmdstager/debug_write +819 -0
  15. data/data/exploits/cmdstager/vbs_b64 +40 -0
  16. data/data/exploits/cmdstager/vbs_b64_adodb +50 -0
  17. data/data/exploits/cmdstager/vbs_b64_noquot +49 -0
  18. data/data/exploits/cmdstager/vbs_b64_sleep +41 -0
  19. data/data/js/detect/ie_addons.js +89 -0
  20. data/data/js/detect/misc_addons.js +157 -0
  21. data/data/js/detect/os.js +831 -0
  22. data/data/js/memory/explib2/lib/explib2.js +426 -0
  23. data/data/js/memory/explib2/payload/drop_exec.js +33 -0
  24. data/data/js/memory/explib2/payload/exec.js +10 -0
  25. data/data/js/memory/heap_spray.js +17 -0
  26. data/data/js/memory/heaplib2.js +192 -0
  27. data/data/js/memory/mstime_malloc.js +31 -0
  28. data/data/js/memory/property_spray.js +38 -0
  29. data/data/js/network/ajax_download.js +18 -0
  30. data/data/js/network/ajax_post.js +18 -0
  31. data/data/js/network/xhr_shim.js +15 -0
  32. data/data/js/utils/base64.js +126 -0
  33. data/data/ropdb/flash.xml +80 -0
  34. data/data/ropdb/hxds.xml +66 -0
  35. data/data/ropdb/java.xml +33 -0
  36. data/data/ropdb/msvcrt.xml +71 -0
  37. data/data/ropdb/reader.xml +132 -0
  38. data/data/ropdb/samba.xml +436 -0
  39. data/data/ropdb/stagefright.xml +225 -0
  40. data/lib/rex/exploitation.rb +7 -0
  41. data/lib/rex/exploitation/cmdstager.rb +11 -0
  42. data/lib/rex/exploitation/cmdstager/base.rb +189 -0
  43. data/lib/rex/exploitation/cmdstager/bourne.rb +118 -0
  44. data/lib/rex/exploitation/cmdstager/certutil.rb +114 -0
  45. data/lib/rex/exploitation/cmdstager/debug_asm.rb +139 -0
  46. data/lib/rex/exploitation/cmdstager/debug_write.rb +133 -0
  47. data/lib/rex/exploitation/cmdstager/echo.rb +166 -0
  48. data/lib/rex/exploitation/cmdstager/printf.rb +121 -0
  49. data/lib/rex/exploitation/cmdstager/tftp.rb +70 -0
  50. data/lib/rex/exploitation/cmdstager/vbs.rb +125 -0
  51. data/lib/rex/exploitation/egghunter.rb +423 -0
  52. data/lib/rex/exploitation/encryptjs.rb +79 -0
  53. data/lib/rex/exploitation/heaplib.js.b64 +331 -0
  54. data/lib/rex/exploitation/heaplib.rb +107 -0
  55. data/lib/rex/exploitation/js.rb +6 -0
  56. data/lib/rex/exploitation/js/detect.rb +70 -0
  57. data/lib/rex/exploitation/js/memory.rb +80 -0
  58. data/lib/rex/exploitation/js/network.rb +83 -0
  59. data/lib/rex/exploitation/js/utils.rb +32 -0
  60. data/lib/rex/exploitation/jsobfu.rb +17 -0
  61. data/lib/rex/exploitation/obfuscatejs.rb +336 -0
  62. data/lib/rex/exploitation/omelet.rb +321 -0
  63. data/lib/rex/exploitation/opcodedb.rb +819 -0
  64. data/lib/rex/exploitation/ropdb.rb +190 -0
  65. data/lib/rex/exploitation/seh.rb +93 -0
  66. data/lib/rex/exploitation/version.rb +5 -0
  67. data/rex-exploitation.gemspec +35 -0
  68. metadata +298 -0
  69. metadata.gz.sig +0 -0
@@ -0,0 +1,6 @@
1
+ # -*- coding: binary -*-
2
+
3
+ require 'rex/exploitation/js/memory'
4
+ require 'rex/exploitation/js/network'
5
+ require 'rex/exploitation/js/utils'
6
+ require 'rex/exploitation/js/detect'
@@ -0,0 +1,70 @@
1
+ # -*- coding: binary -*-
2
+
3
+ require 'rex/text'
4
+ require 'rex/exploitation/jsobfu'
5
+
6
+ module Rex
7
+ module Exploitation
8
+ module Js
9
+
10
+
11
+ class Detect
12
+
13
+ #
14
+ # Provides several javascript functions for determining the OS and browser versions of a client.
15
+ #
16
+ # getVersion(): returns an object with the following properties
17
+ # os_name - OS name such as "Windows 8", "Linux", "Mac OS X"
18
+ # os_flavor - OS flavor as a string such as "Home", "Enterprise", etc
19
+ # os_sp - OS service pack (e.g.: "SP2", will be empty on non-Windows)
20
+ # os_lang - OS language (e.g.: "en-us")
21
+ # os_vendor - A company or organization name such as Microsoft, Ubuntu, Apple, etc
22
+ # os_device - A specific piece of hardware such as iPad, iPhone, etc
23
+ # ua_name - Client name, one of the Msf::HttpClients constants
24
+ # ua_version - Client version as a string (e.g.: "3.5.1", "6.0;SP2")
25
+ # arch - Architecture, one of the ARCH_* constants
26
+ #
27
+ # The following functions work on the version returned in obj.ua_version
28
+ #
29
+ # ua_ver_cmp(a, b): returns -1, 0, or 1 based on whether a < b, a == b, or a > b respectively
30
+ # ua_ver_lt(a, b): returns true if a < b
31
+ # ua_ver_gt(a, b): returns true if a > b
32
+ # ua_ver_eq(a, b): returns true if a == b
33
+ #
34
+ def self.os(custom_js = '')
35
+ js = custom_js
36
+ js << ::File.read(::File.join(Rex::Exploitation::DATA_DIR, "js", "detect", "os.js"))
37
+
38
+ Rex::Exploitation::JSObfu.new(js)
39
+ end
40
+
41
+
42
+ #
43
+ # Provides javascript functions to determine IE addon information.
44
+ #
45
+ # getMsOfficeVersion(): Returns the version for Microsoft Office
46
+ #
47
+ def self.ie_addons(custom_js = '')
48
+ js = custom_js
49
+ js << ::File.read(::File.join(Rex::Exploitation::DATA_DIR, "js", "detect", "ie_addons.js"))
50
+
51
+ Rex::Exploitation::JSObfu.new(js)
52
+ end
53
+
54
+ #
55
+ # Provides javascript functions that work for all browsers to determine addon information
56
+ #
57
+ # getJavaVersion(): Returns the Java version
58
+ # hasSilverlight(): Returns whether Silverlight is enabled or not
59
+ #
60
+ def self.misc_addons(custom_js = '')
61
+ js = custom_js
62
+ js << ::File.read(::File.join(Rex::Exploitation::DATA_DIR, "js", "detect", "misc_addons.js"))
63
+
64
+ Rex::Exploitation::JSObfu.new(js)
65
+ end
66
+
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,80 @@
1
+ # -*- coding: binary -*-
2
+
3
+
4
+ module Rex
5
+ module Exploitation
6
+ module Js
7
+
8
+ #
9
+ # Provides meomry manipulative functions in JavaScript
10
+ #
11
+ class Memory
12
+
13
+ def self.mstime_malloc
14
+ js = ::File.read(::File.join(Rex::Exploitation::DATA_DIR, "js", "memory", "mstime_malloc.js"))
15
+ js = js.gsub(/W00TA/, Rex::Text.rand_text_hex(6))
16
+ js = js.gsub(/W00TB/, Rex::Text.rand_text_hex(5))
17
+
18
+ ::Rex::Exploitation::ObfuscateJS.new(js,
19
+ {
20
+ 'Symbols' => {
21
+ 'Variables' => %w{ buf eleId acTag }
22
+ }
23
+ }).obfuscate
24
+ end
25
+
26
+ def self.heaplib2(custom_js='', opts={})
27
+ js = ::File.read(::File.join(Rex::Exploitation::DATA_DIR, "js", "memory", "heaplib2.js"))
28
+
29
+ unless custom_js.to_s.strip.empty?
30
+ js << custom_js
31
+ end
32
+
33
+ js = ::Rex::Exploitation::JSObfu.new js
34
+ js.obfuscate
35
+ return js
36
+ end
37
+
38
+ def self.property_spray
39
+ js = ::File.read(::File.join(Rex::Exploitation::DATA_DIR, "js", "memory", "property_spray.js"))
40
+
41
+ ::Rex::Exploitation::ObfuscateJS.new(js,
42
+ {
43
+ 'Symbols' => {
44
+ 'Variables' => %w{ sym_div_container data junk obj }
45
+ }
46
+ }).obfuscate
47
+ end
48
+
49
+ def self.heap_spray
50
+ js = ::File.read(::File.join(Rex::Exploitation::DATA_DIR, "js", "memory", "heap_spray.js"))
51
+
52
+ ::Rex::Exploitation::ObfuscateJS.new(js,
53
+ {
54
+ 'Symbols' => {
55
+ 'Variables' => %w{ index heapSprayAddr_hi heapSprayAddr_lo retSlide heapBlockCnt }
56
+ }
57
+ }).obfuscate
58
+ end
59
+
60
+ def self.explib2
61
+ js = ::File.read(::File.join(Rex::Exploitation::DATA_DIR, "js", "memory", "explib2", "lib", "explib2.js"))
62
+
63
+ ::Rex::Exploitation::ObfuscateJS.obfuscate(js)
64
+ end
65
+
66
+ def self.explib2_payload(payload="exec")
67
+ case payload
68
+ when "drop_exec"
69
+ js = ::File.read(::File.join(Rex::Exploitation::DATA_DIR, "js", "memory", "explib2", "payload", "drop_exec.js"))
70
+ else # "exec"
71
+ js = ::File.read(::File.join(Rex::Exploitation::DATA_DIR, "js", "memory", "explib2", "payload", "exec.js"))
72
+ end
73
+
74
+ ::Rex::Exploitation::ObfuscateJS.obfuscate(js)
75
+ end
76
+
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,83 @@
1
+ # -*- coding: binary -*-
2
+
3
+
4
+ module Rex
5
+ module Exploitation
6
+ module Js
7
+
8
+ #
9
+ # Provides networking functions in JavaScript
10
+ #
11
+ class Network
12
+
13
+ # @param [Hash] opts the options hash
14
+ # @option opts [Boolean] :obfuscate toggles js obfuscation. defaults to true.
15
+ # @option opts [Boolean] :inject_xhr_shim automatically stubs XHR to use ActiveXObject when needed.
16
+ # defaults to true.
17
+ # @return [String] javascript code to perform a synchronous ajax request to the remote
18
+ # and returns the response
19
+ def self.ajax_download(opts={})
20
+ should_obfuscate = opts.fetch(:obfuscate, true)
21
+ js = ::File.read(::File.join(Rex::Exploitation::DATA_DIR, "js", "network", "ajax_download.js"))
22
+
23
+ if should_obfuscate
24
+ js = ::Rex::Exploitation::ObfuscateJS.new(js,
25
+ {
26
+ 'Symbols' => {
27
+ 'Variables' => %w{ xmlHttp oArg }
28
+ }
29
+ }).obfuscate
30
+ end
31
+
32
+ xhr_shim(opts) + js
33
+ end
34
+
35
+ # @param [Hash] opts the options hash
36
+ # @option opts [Boolean] :obfuscate toggles js obfuscation. defaults to true.
37
+ # @option opts [Boolean] :inject_xhr_shim automatically stubs XHR to use ActiveXObject when needed.
38
+ # defaults to true.
39
+ # @return [String] javascript code to perform a synchronous or asynchronous ajax request to
40
+ # the remote with the data specified.
41
+ def self.ajax_post(opts={})
42
+ should_obfuscate = opts.fetch(:obfuscate, true)
43
+ js = ::File.read(::File.join(Rex::Exploitation::DATA_DIR, "js", "network", "ajax_post.js"))
44
+
45
+ if should_obfuscate
46
+ js = ::Rex::Exploitation::ObfuscateJS.new(js,
47
+ {
48
+ 'Symbols' => {
49
+ 'Variables' => %w{ xmlHttp cb path data }
50
+ }
51
+ }).obfuscate
52
+ end
53
+
54
+ xhr_shim(opts) + js
55
+ end
56
+
57
+ # @param [Hash] opts the options hash
58
+ # @option opts [Boolean] :obfuscate toggles js obfuscation. defaults to true.
59
+ # @option opts [Boolean] :inject_xhr_shim false causes this method to return ''. defaults to true.
60
+ # @return [String] javascript code that adds XMLHttpRequest to the global scope if it
61
+ # does not exist (e.g. on IE6, where you have to use the ActiveXObject constructor)
62
+ def self.xhr_shim(opts={})
63
+ return '' unless opts.fetch(:inject_xhr_shim, true)
64
+
65
+ should_obfuscate = opts.fetch(:obfuscate, true)
66
+ js = ::File.read(::File.join(Rex::Exploitation::DATA_DIR, "js", "network", "xhr_shim.js"))
67
+
68
+ if should_obfuscate
69
+ js = ::Rex::Exploitation::ObfuscateJS.new(js,
70
+ {
71
+ 'Symbols' => {
72
+ 'Variables' => %w{ activeObjs idx }
73
+ }
74
+ }
75
+ ).obfuscate
76
+ end
77
+ js
78
+ end
79
+
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,32 @@
1
+ # -*- coding: binary -*-
2
+
3
+ require 'rex/text'
4
+ require 'rex/exploitation/jsobfu'
5
+
6
+ module Rex
7
+ module Exploitation
8
+ module Js
9
+
10
+ #
11
+ # Javascript utilities
12
+ #
13
+ class Utils
14
+
15
+ def self.base64
16
+ js = ::File.read(::File.join(Rex::Exploitation::DATA_DIR, "js", "utils", "base64.js"))
17
+
18
+ opts = {
19
+ 'Symbols' => {
20
+ 'Variables' => %w{ Base64 encoding result _keyStr encoded_data utftext input_idx
21
+ input output chr chr1 chr2 chr3 enc1 enc2 enc3 enc4 },
22
+ 'Methods' => %w{ _utf8_encode _utf8_decode encode decode }
23
+ }
24
+ }
25
+
26
+ ::Rex::Exploitation::ObfuscateJS.new(js, opts).to_s
27
+ end
28
+
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,17 @@
1
+ # -*- coding: binary -*-
2
+
3
+ require 'jsobfu'
4
+
5
+ module Rex
6
+ module Exploitation
7
+
8
+ #
9
+ # Simple wrapper class that makes the JSObfu functionality
10
+ # from the gem available under the Rex namespace.
11
+ #
12
+ class JSObfu < ::JSObfu
13
+
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,336 @@
1
+ # -*- coding: binary -*-
2
+ require 'rex/text'
3
+ module Rex
4
+ module Exploitation
5
+
6
+ #
7
+ # Obfuscates javascript in various ways
8
+ #
9
+ class ObfuscateJS
10
+ attr_reader :opts
11
+
12
+ #
13
+ # Obfuscates a javascript string.
14
+ #
15
+ # Options are 'Symbols', described below, and 'Strings', a boolean
16
+ # which specifies whether strings within the javascript should be
17
+ # mucked with (defaults to false).
18
+ #
19
+ # The 'Symbols' argument should have the following format:
20
+ #
21
+ # {
22
+ # 'Variables' => [ 'var1', ... ],
23
+ # 'Methods' => [ 'method1', ... ],
24
+ # 'Namespaces' => [ 'n', ... ],
25
+ # 'Classes' => [ { 'Namespace' => 'n', 'Class' => 'y'}, ... ]
26
+ # }
27
+ #
28
+ # Make sure you order your methods, classes, and namespaces by most
29
+ # specific to least specific to prevent partial substitution. For
30
+ # instance, if you have two methods (joe and joeBob), you should place
31
+ # joeBob before joe because it is more specific and will be globally
32
+ # replaced before joe is replaced.
33
+ #
34
+ # A simple example follows:
35
+ #
36
+ # <code>
37
+ # js = ObfuscateJS.new <<ENDJS
38
+ # function say_hi() {
39
+ # var foo = "Hello, world";
40
+ # document.writeln(foo);
41
+ # }
42
+ # ENDJS
43
+ # js.obfuscate(
44
+ # 'Symbols' => {
45
+ # 'Variables' => [ 'foo' ],
46
+ # 'Methods' => [ 'say_hi' ]
47
+ # }
48
+ # 'Strings' => true
49
+ # )
50
+ # </code>
51
+ #
52
+ # which should generate something like the following:
53
+ #
54
+ # <code>
55
+ # function oJaDYRzFOyJVQCOHk() { var cLprVG = "\x48\x65\x6c\x6c\x6f\x2c\x20\x77\x6f\x72\x6c\x64"; document.writeln(cLprVG); }
56
+ # </code>
57
+ #
58
+ # String obfuscation tries to deal with escaped quotes within strings but
59
+ # won't catch things like
60
+ # "\\"
61
+ # so be careful.
62
+ #
63
+ def self.obfuscate(js, opts = {})
64
+ ObfuscateJS.new(js).obfuscate(opts)
65
+ end
66
+
67
+ #
68
+ # Initialize an instance of the obfuscator
69
+ #
70
+ def initialize(js = "", opts = {})
71
+ @js = js
72
+ @dynsym = {}
73
+ @opts = {
74
+ 'Symbols' => {
75
+ 'Variables'=>[],
76
+ 'Methods'=>[],
77
+ 'Namespaces'=>[],
78
+ 'Classes'=>[]
79
+ },
80
+ 'Strings'=>false
81
+ }
82
+ @done = false
83
+ update_opts(opts) if (opts.length > 0)
84
+ end
85
+
86
+ def update_opts(opts)
87
+ if (opts.nil? or opts.length < 1)
88
+ return
89
+ end
90
+ if (@opts['Symbols'] && opts['Symbols'])
91
+ ['Variables', 'Methods', 'Namespaces', 'Classes'].each { |k|
92
+ if (@opts['Symbols'][k] && opts['Symbols'][k])
93
+ opts['Symbols'][k].each { |s|
94
+ if (not @opts['Symbols'][k].include? s)
95
+ @opts['Symbols'][k].push(s)
96
+ end
97
+ }
98
+ elsif (opts['Symbols'][k])
99
+ @opts['Symbols'][k] = opts['Symbols'][k]
100
+ end
101
+ }
102
+ elsif opts['Symbols']
103
+ @opts['Symbols'] = opts['Symbols']
104
+ end
105
+ @opts['Strings'] ||= opts['Strings']
106
+ end
107
+
108
+ #
109
+ # Returns the dynamic symbol associated with the supplied symbol name
110
+ #
111
+ # If obfuscation has not yet been performed (i.e. obfuscate() has not been
112
+ # called), then this method simply returns its argument
113
+ #
114
+ def sym(name)
115
+ @dynsym[name] || name
116
+ end
117
+
118
+ #
119
+ # Obfuscates the javascript string passed to the constructor
120
+ #
121
+ def obfuscate(opts = {})
122
+ #return @js if (@done)
123
+ @done = true
124
+
125
+ update_opts(opts)
126
+
127
+ if (@opts['Strings'])
128
+ obfuscate_strings()
129
+
130
+ # Full space randomization does not work for javascript -- despite
131
+ # claims that space is irrelavent, newlines break things. Instead,
132
+ # use only space (0x20) and tab (0x09).
133
+
134
+ #@js.gsub!(/[\x09\x20]+/) { |s|
135
+ # len = rand(50)+2
136
+ # set = "\x09\x20"
137
+ # buf = ''
138
+ # while (buf.length < len)
139
+ # buf << set[rand(set.length)].chr
140
+ # end
141
+ #
142
+ # buf
143
+ #}
144
+ end
145
+
146
+ # Remove our comments
147
+ remove_comments
148
+
149
+ # Globally replace symbols
150
+ replace_symbols(@opts['Symbols']) if @opts['Symbols']
151
+
152
+ return @js
153
+ end
154
+
155
+ #
156
+ # Returns the replaced javascript string
157
+ #
158
+ def to_s
159
+ @js
160
+ end
161
+ alias :to_str :to_s
162
+
163
+ def <<(str)
164
+ @js << str
165
+ end
166
+ def +(str)
167
+ @js + str
168
+ end
169
+
170
+ protected
171
+ attr_accessor :done
172
+
173
+ #
174
+ # Get rid of both single-line C++ style comments and multiline C style comments.
175
+ #
176
+ # Note: embedded comments (e.g.: "/*/**/*/") will break this,
177
+ # but they also break real javascript engines so I don't care.
178
+ #
179
+ def remove_comments
180
+ @js.gsub!(%r{\s+//.*$}, '')
181
+ @js.gsub!(%r{/\*.*?\*/}m, '')
182
+ end
183
+
184
+ # Replace method, class, and namespace symbols found in the javascript
185
+ # string
186
+ def replace_symbols(symbols)
187
+ taken = { }
188
+
189
+ # Generate random symbol names
190
+ [ 'Variables', 'Methods', 'Classes', 'Namespaces' ].each { |symtype|
191
+ next if symbols[symtype].nil?
192
+ symbols[symtype].each { |sym|
193
+ dyn = Rex::Text.rand_text_alpha(rand(32)+1) until dyn and not taken.key?(dyn)
194
+
195
+ taken[dyn] = true
196
+
197
+ if symtype == 'Classes'
198
+ full_sym = sym['Namespace'] + "." + sym['Class']
199
+ @dynsym[full_sym] = dyn
200
+
201
+ @js.gsub!(/#{full_sym}/) { |m|
202
+ sym['Namespace'] + "." + dyn
203
+ }
204
+ else
205
+ @dynsym[sym] = dyn
206
+
207
+ @js.gsub!(/#{sym}/, dyn)
208
+ end
209
+ }
210
+ }
211
+ end
212
+
213
+ #
214
+ # Change each string into some javascript that will generate that string
215
+ #
216
+ # There are a couple of caveats to using string obfuscation:
217
+ # * it tries to deal with escaped quotes within strings but won't catch
218
+ # things like: "\\"
219
+ # * depending on the random choices, this can easily balloon a short
220
+ # string up to hundreds of kilobytes if called multiple times.
221
+ # so be careful.
222
+ #
223
+ def obfuscate_strings()
224
+ @js.gsub!(/".*?[^\\]"|'.*?[^\\]'/) { |str|
225
+ buf = ''
226
+ quote = str[0,1]
227
+ # Pull the quotes off either end
228
+ str = str[1, str.length-2]
229
+ case (rand(2))
230
+ # Disable hex encoding for now. It's just too big a hassle.
231
+ #when 0
232
+ # # This is where we can run into trouble with generating
233
+ # # incorrect code. If we hex encode a string twice, the second
234
+ # # encoding will generate the first instead of the original
235
+ # # string.
236
+ # if str =~ /\\x/
237
+ # # Always have to remove spaces from strings so the space
238
+ # # randomization doesn't mess with them.
239
+ # buf = quote + str.gsub(/ /, '\x20') + quote
240
+ # else
241
+ # buf = '"' + Rex::Text.to_hex(str) + '"'
242
+ # end
243
+ when 0
244
+ #
245
+ # Escape sequences when naively encoded for unescape become a
246
+ # literal backslash instead of the intended meaning. To avoid
247
+ # that problem, we scan the string for escapes and leave them
248
+ # unmolested.
249
+ #
250
+ buf << 'unescape("'
251
+ bytes = str.unpack("C*")
252
+ c = 0
253
+ while bytes[c]
254
+ if bytes[c].chr == "\\"
255
+ # XXX This is pretty slow.
256
+ esc_len = parse_escape(bytes, c)
257
+ buf << bytes[c, esc_len].map{|a| a.chr}.join
258
+ c += esc_len
259
+ next
260
+ end
261
+ buf << "%%%0.2x"%(bytes[c])
262
+ # Break the string into smaller strings
263
+ if bytes[c+1] and rand(10) == 0
264
+ buf << '" + "'
265
+ end
266
+ c += 1
267
+ end
268
+ buf << '")'
269
+ when 1
270
+ buf = "String.fromCharCode( "
271
+ bytes = str.unpack("C*")
272
+ c = 0
273
+ while bytes[c]
274
+ if bytes[c].chr == "\\"
275
+ case bytes[c+1].chr
276
+ # For chars that contain their non-escaped selves, step
277
+ # past the backslash and let the rand() below decide
278
+ # how to represent the character.
279
+ when '"'; c += 1
280
+ when "'"; c += 1
281
+ when "\\"; c += 1
282
+ # For others, just take the hex representation out of
283
+ # laziness.
284
+ when "n"; buf << "0x0a"; c += 2; next
285
+ when "t"; buf << "0x09"; c += 2; next
286
+ # Lastly, if it's a hex, unicode, or octal escape,
287
+ # leave it, and anything after it, alone. At some
288
+ # point we may want to parse up to the end of the
289
+ # escapes and encode subsequent non-escape characters.
290
+ # Since this is the lazy way to do it, spaces after an
291
+ # escape sequence will get away unmodified. To prevent
292
+ # the space randomizer from hosing the string, convert
293
+ # spaces specifically.
294
+ else
295
+ buf = buf[0,buf.length-1] + " )"
296
+ buf << ' + ("' + bytes[c, bytes.length].map{|a| a==0x20 ? '\x20' : a.chr}.join + '" '
297
+ break
298
+ end
299
+ end
300
+ case (rand(3))
301
+ when 0
302
+ buf << " %i,"%(bytes[c])
303
+ when 1
304
+ buf << " 0%o,"%(bytes[c])
305
+ when 2
306
+ buf << " 0x%0.2x,"%(bytes[c])
307
+ end
308
+ c += 1
309
+ end
310
+ # Strip off the last comma
311
+ buf = buf[0,buf.length-1] + " )"
312
+ end
313
+ buf
314
+ }
315
+ @js
316
+ end
317
+
318
+ def parse_escape(bytes, offset)
319
+ esc_len = 0
320
+ if bytes[offset].chr == "\\"
321
+ case bytes[offset+1].chr
322
+ when "u"; esc_len = 6 # unicode \u1234
323
+ when "x"; esc_len = 4 # hex, \x41
324
+ when /[0-9]/ # octal, \123, \0
325
+ oct = bytes[offset+1, 4].map{|a|a.chr}.join
326
+ oct =~ /([0-9]+)/
327
+ esc_len = 1 + $1.length
328
+ else; esc_len = 2 # \" \n, etc.
329
+ end
330
+ end
331
+ esc_len
332
+ end
333
+ end
334
+
335
+ end
336
+ end