class JSObfu::Scope

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.

Constants

BUILTIN_VARS

these vars should not be shadowed as they in the exploit code, and generating them would cause problems.

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

Attributes

parent[RW]

@return [JSObfu::Scope] parent that spawned this scope

renames[RW]

@return [Hash] mapping old var names to random ones

Public Class Methods

new(opts={}) click to toggle source

@param [Hash] opts the options hash @option opts [Rex::Exploitation::JSObfu::Scope] :parent an optional parent scope,

sometimes necessary to prevent needless var shadowing

@option opts [Integer] :min_len minimum length of the var names

# File lib/jsobfu/scope.rb, line 38
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        = {}
end

Public Instance Methods

empty?() click to toggle source

@return [Boolean] scope has members

# File lib/jsobfu/scope.rb, line 98
def empty?
  self.keys.empty? and (parent.nil? or parent.empty?)
end
has_key?(key) click to toggle source

Check if we've used this var before. This will also check any attached parent scopes (and their parents, recursively)

@return [Boolean] whether var is in scope

Calls superclass method
# File lib/jsobfu/scope.rb, line 117
def has_key?(key)
  super or (parent and parent.has_key?(key))
end
pop!() click to toggle source

“Consumes” the parent and replaces self with it

# File lib/jsobfu/scope.rb, line 134
def pop!
  clear
  if @parent
    merge! @parent
    @renames = @parent.renames
    @parent = @parent.parent
  end
end
push!() click to toggle source

replaces this Scope in the “parent” chain with a copy, empties current scope, and returns. Essentially an in-place push operation

# File lib/jsobfu/scope.rb, line 124
def push!
  replacement = dup
  replacement.parent = @parent
  replacement.renames = @renames
  @renames = {}
  @parent = replacement
  clear
end
random_string(len) click to toggle source

@return [String] a random string that can be used as a var

# File lib/jsobfu/scope.rb, line 144
def random_string(len)
  @first_char_set.sample + (len-1).times.map { @char_set.sample }.join
end
random_var_name() click to toggle source

Generates a unique, “safe” random variable @return [String] a unique random var name that is not a reserved keyword

# File lib/jsobfu/scope.rb, line 48
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={}) click to toggle source

Re-maps your var_name to a unique, random names in the current scope

@param var_name [String] the name you want to replace. This

name will be remembered in the #renames hash

@param opts [Hash] the options hash @option opts [Boolean] :generate if the variable was not

explicitly renamed before, in this scope or any parent
scope, generate a new random name

@return [String] the randomly generated replacement name @return nil if generate=false and var_name was not already replaced

# File lib/jsobfu/scope.rb, line 76
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() click to toggle source
# File lib/jsobfu/scope.rb, line 107
def top
  p = self
  p = p.parent until p.parent.nil?
  p
end
top?() click to toggle source

@return [Boolean] scope has no parent

# File lib/jsobfu/scope.rb, line 103
def top?
  parent.nil?
end