rex-exploitation 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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