読者です 読者をやめる 読者になる 読者になる

clock-up-blog

go-mi-tech

JavaScript で window 配下に紐づく全オブジェクトを再帰的に列挙する

JavaScript Advent Calendar 2016 14日目の記事です。

任意サイトにおいて window 配下に紐づいている全オブジェクト (つまりグローバル変数と、それにぶらさがっている全変数) を再帰的に列挙してみようと思います。

これはウェブサイトの内部構造(のとっかかり)を外部の人間が解析したいときに役立つであろうテクニックです。

スクリプト

Chrome Developer Tools Console にて以下を実行します。

(function(){
  var f = document.body.appendChild(document.createElement('iframe'));
  f.style.display = 'none';
  window.console = f.contentWindow.console;
})();

(function(){
  var g_objs = {};
  var ACCESS_MARK = 4;
  function join(left, right){
    if(!isNaN(right)){
      return left + '[' + right + ']';
    }
    else if(right.match(/[\/\-]/)){
      return left + "['" + right + "']";
    }
    else{
      return left + '.' + right;
    }
  }
  function enumObj(parent, name, depth){
    if(depth > 30){
      debugger;
    }
    // 子オブジェクト取得
    for(var key in parent){
      if(key === '__accessed__')continue;
      if(key === '$'){
        // debugger;
      }
      
      // オブジェクト取得
      var obj = null; 
      var type = 'error';
      try{
        obj = parent[key];
        type = typeof obj;
      }
      catch(e){
      }

      // 既にアクセスしたオブジェクトは無視
      try{
        if(obj !== null){
          if(obj.__accessed__ === ACCESS_MARK)continue;
          obj.__accessed__ = ACCESS_MARK;

          var unique = obj + JSON.stringify(obj);
          if(g_objs[unique])continue;
          g_objs[unique] = ACCESS_MARK;
        }
      }
      catch(e){
      }

      // オブジェクト情報出力
      console.log(join(name, key) + ' : ' + type);
      
      // さらに掘る
      if(obj === null)continue;
      if(typeof obj === 'string')continue;
      if(typeof obj === 'number')continue;
      enumObj(obj, join(name, key), depth + 1);
    }
  }
  enumObj(window, 'window', 0);
})();

結果

たとえば twitter.com で上記スクリプトを実行してみた例です。
twitter.com からひっぱってきたオブジェクト群 · GitHub

window.speechSynthesis : object
window.speechSynthesis.pending : boolean
window.speechSynthesis.onvoiceschanged : object
....
window.$.Tween : function
window.$.Tween.propHooks : object
....
window.loadrunner.Module.exports['bower_components/flight/lib/registry'].components[0].attachedTo[0]['tweet-post-iframe'] : object
window.loadrunner.Module.exports['bower_components/flight/lib/registry'].components[0].attachedTo[0]['tweet-post-iframe'].ondeviceorientationabsolute : object
window.loadrunner.Module.exports['bower_components/flight/lib/registry'].components[0].attachedTo[0]['tweet-post-iframe'].ondeviceorientation : object
window.loadrunner.Module.exports['bower_components/flight/lib/registry'].components[0].attachedTo[0]['tweet-post-iframe'].ondevicemotion : object
window.loadrunner.Module.exports['bower_components/flight/lib/registry'].components[0].attachedTo[0]['tweet-post-iframe'].ontouchstart : object
....
window.loadrunner.Module.exports['bower_components/flight/lib/registry'].components[0].attachedTo[0].jQuery22401681574395691191.events.dataDidUserUnpinTweet : object
window.loadrunner.Module.exports['bower_components/flight/lib/registry'].components[0].attachedTo[0].jQuery22401681574395691191.events.dataDidUserUnpinTweet[0] : object
....

おしまい

あくまでもグローバルなツリーに乗っている変数しか検出できない(スコープに隠れてしまっている変数や関数等は検出できない)のですが、解析のとっかかりの一つにはなるかと思います。

});