Class: JSObfu::Scope
- Inherits:
-
Hash
- Object
- Hash
- JSObfu::Scope
- Defined in:
- lib/jsobfu/scope.rb
Overview
A single Javascript scope, used as a key-value store to maintain uniqueness of members in generated closures. For speed this class is implemented as a subclass of Hash.
Constant Summary collapse
- RESERVED_KEYWORDS =
these keywords should never be used as a random var name source: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Reserved_Words
%w( break case catch continue debugger default delete do else finally for function if in instanceof new return switch this throw try typeof var void while with class enum export extends import super implements interface let package private protected public static yield const let )
- BUILTIN_VARS =
these vars should not be shadowed as they in the exploit code, and generating them would cause problems.
%w( String window unescape location chrome document navigator location frames ActiveXObject XMLHttpRequest Function eval Object Math CSS parent opener event frameElement Error TypeError setTimeout setInterval top arguments Array Date )
Instance Attribute Summary collapse
-
#depth ⇒ Number
The 0-indexed depth of the scope stack.
-
#parent ⇒ JSObfu::Scope
Parent that spawned this scope.
-
#renames ⇒ Hash
Mapping old var names to random ones.
Instance Method Summary collapse
-
#empty? ⇒ Boolean
Scope has members.
-
#has_key?(key) ⇒ Boolean
Check if we’ve used this var before.
-
#initialize(opts = {}) ⇒ Scope
constructor
A new instance of Scope.
-
#pop!(opts = {}) ⇒ Object
“Consumes” the parent and replaces self with it.
-
#push! ⇒ Object
replaces this Scope in the “parent” chain with a copy, empties current scope, and returns.
-
#random_string(len) ⇒ String
A random string that can be used as a var.
-
#random_var_name ⇒ String
Generates a unique, “safe” random variable.
-
#rename_var(var_name, opts = {}) ⇒ String
Re-maps your
var_name
to a unique, random names in the current scope. - #top ⇒ Object
-
#top? ⇒ Boolean
Scope has no parent.
Constructor Details
#initialize(opts = {}) ⇒ Scope
Returns a new instance of Scope.
41 42 43 44 45 46 47 48 |
# File 'lib/jsobfu/scope.rb', line 41 def initialize(opts={}) @parent = opts[:parent] @first_char_set = opts[:first_char_set] || [*'A'..'Z']+[*'a'..'z']+['_', '$'] @char_set = opts[:first_char_set] || @first_char_set + [*'0'..'9'] @min_len = opts[:min_len] || 1 @renames = {} @depth = -1 end |
Instance Attribute Details
#depth ⇒ Number
Returns the 0-indexed depth of the scope stack.
35 36 37 |
# File 'lib/jsobfu/scope.rb', line 35 def depth @depth end |
#parent ⇒ JSObfu::Scope
Returns parent that spawned this scope.
29 30 31 |
# File 'lib/jsobfu/scope.rb', line 29 def parent @parent end |
#renames ⇒ Hash
Returns mapping old var names to random ones.
32 33 34 |
# File 'lib/jsobfu/scope.rb', line 32 def renames @renames end |
Instance Method Details
#empty? ⇒ Boolean
Returns scope has members.
101 102 103 |
# File 'lib/jsobfu/scope.rb', line 101 def empty? self.keys.empty? and (parent.nil? or parent.empty?) end |
#has_key?(key) ⇒ Boolean
Check if we’ve used this var before. This will also check any attached parent scopes (and their parents, recursively)
120 121 122 |
# File 'lib/jsobfu/scope.rb', line 120 def has_key?(key) super or (parent and parent.has_key?(key)) end |
#pop!(opts = {}) ⇒ Object
“Consumes” the parent and replaces self with it
138 139 140 141 142 143 144 145 146 147 |
# File 'lib/jsobfu/scope.rb', line 138 def pop!(opts={}) retain = opts.fetch(:retain, false) @depth -= 1 clear unless retain if @parent merge! @parent @renames = @parent.renames @parent = @parent.parent end end |
#push! ⇒ Object
replaces this Scope in the “parent” chain with a copy, empties current scope, and returns. Essentially an in-place push operation
127 128 129 130 131 132 133 134 135 |
# File 'lib/jsobfu/scope.rb', line 127 def push! @depth += 1 replacement = dup replacement.parent = @parent replacement.renames = @renames @renames = {} @parent = replacement clear end |
#random_string(len) ⇒ String
Returns a random string that can be used as a var.
150 151 152 |
# File 'lib/jsobfu/scope.rb', line 150 def random_string(len) @first_char_set.sample + (len-1).times.map { @char_set.sample }.join end |
#random_var_name ⇒ String
Generates a unique, “safe” random variable
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/jsobfu/scope.rb', line 52 def random_var_name len = @min_len loop do text = random_string(len) unless has_key?(text) or RESERVED_KEYWORDS.include?(text) or BUILTIN_VARS.include?(text) self[text] = nil return text end len += 1 end end |
#rename_var(var_name, opts = {}) ⇒ String
Re-maps your var_name
to a unique, random names in the current scope
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/jsobfu/scope.rb', line 79 def rename_var(var_name, opts={}) return var_name if BUILTIN_VARS.include?(var_name) generate = opts.fetch(:generate, true) unresolved = opts.fetch(:unresolved, []) renamed = @renames[var_name] if renamed.nil? and parent renamed = parent.rename_var(var_name, :generate => false) end if renamed.nil? and generate @renames[var_name] = random_var_name renamed = @renames[var_name] end #puts "Mapped #{var_name} => #{renamed}" if renamed renamed end |
#top ⇒ Object
110 111 112 113 114 |
# File 'lib/jsobfu/scope.rb', line 110 def top p = self p = p.parent until p.parent.nil? p end |
#top? ⇒ Boolean
Returns scope has no parent.
106 107 108 |
# File 'lib/jsobfu/scope.rb', line 106 def top? parent.nil? end |