1

For background, I am currently playing through Untrusted, a JavaScript-based programming game whose core mechanic is editing code to modify the game world to progress forward. I have solved most levels the "intended" way by modifying the variables I am given in the local scope using the documented in-game API. However, I am wondering if there are also some "unintended" ways to modify the game state/game definition by fishing around.

A lot of the game has code as follows (evaluated in window scope):

function foo() {
    var bar = 1234;
}

I understand that I can access foo from any scope by referring to window.foo. Is there a way I can access bar inside foo even though it is not explicitly exposed?

To clarify, the above code is already evaluated for me (in window scope, I believe, so I can at least get a reference to the foo). I can not change what is evaluated. (I suppose I could redefine foo if I really wanted, and that would bypass a lot of restrictions, but that's tangential to the current direction of questioning.) Rather, my goal is, given this has already been evaluated, modify it in place (such as setting a new value for bar).

Thanks in advance!

Ming
  • 1,613
  • 12
  • 27
  • I don't understand, you say you can't control the definition of `foo`, yet you can redefine `foo`. – MinusFour Aug 03 '15 at 04:44
  • The format of the game (assuming I want to play it as presented) is that I am shown some amount of JS source, some smaller subset of which I am allowed to modify. It may be, for example, that the definition of `foo` is within the portion I am *not* allowed to modify. Also, the `self.bar = ...` example is an example of something I am specifically *not* allowed to do. – Ming Aug 03 '15 at 04:46
  • No, you cannot access the variable `bar` of `foo` function from outside the `foo` function. The `bar` is basically a private variable of `foo`. Thus you can't – Ruchan Aug 03 '15 at 04:48
  • I'm aware that, typically, one should respect encapsulation and avoid this type of behavior. However, is there some sort of introspection mechanism (perhaps analogous to Python's `__dict__` or Ruby's `instance_variable_get`) which would allow me to do so under special circumstances? – Ming Aug 03 '15 at 04:50
  • To clarify, the premise of the game is that the `function foo() ...` snippet has already been evaluated in window scope. I cannot change the past. However, I can potentially change the future, and I may be able to evaluate something else in the future? (Not sure which introspection mechanisms are available in JS, or if any of them would allow this sort of change.) – Ming Aug 03 '15 at 04:53
  • It's not really an encapsulation thing (in the sense of private variables). It's just running on a different context to which the caller is oblivious. Had the declaration been different, it might have been possible to access it. – MinusFour Aug 03 '15 at 04:54
  • To add on, I admit that the situation is a bit contrived. In real world usage, of course I would be free to redefine the original `foo` in a more convenient fashion. The only reason that I'm looking for some sort of appropriate introspection mechanism, which may or may not exist, is to push the limits of what is possible in this game. – Ming Aug 03 '15 at 04:57

2 Answers2

4

The short answer is no.

It's not possible to access a local variable outside of it's scopes/closures (note that due to closures, there may be more than one scope that can access a single local variable).


For the long answer, see this answer for a description of how scopes work: javascript can't access private properties.

Community
  • 1
  • 1
slebetman
  • 109,858
  • 19
  • 140
  • 171
0

Without modifying foo, you cannot access bar from outside foo.

However, it is not hard to modify foo:

//Original code
function foo ( ) {
  var bar = 1234;
}

//Modify foo:
(function(){
  var fooMatches = foo.toString().replace(/var\s+bar/g, "window.bar").match(/^\s*function\s+foo\s*\(([^()]*)\)\s*{([^\0]*)}\s*$/);
  var args = fooMatches[1].split(/\s*,\s*/);
  args.push( fooMatches[2] );
  foo = Function.apply( window, args );
})();

//Access bar
foo();
alert( bar );
Inkbug
  • 1,682
  • 1
  • 10
  • 26