FiddlerCoreを使ってブラウザアプリをトラップする(前哨戦)

まあ、端的に言えば「艦これ」 http://www.dmm.com/netgame/feature/kancolle.html なのですが、先日「艦これのAPIがLTに」ってのを見つけて、そのあと自前で IE を使って調べてみました。で、単純な JSON と Flash の圧縮 SWF ファイルになっているので、解析は楽そう。実際公開当時(6月頃)から色々解析はやられているみたいで、マクロとか諸々あるのですが、まぁ、それはさておき。

艦これ 司令部室
http://nozomi.arege.jp/KanHQ/

20130827_01

というので、FiddlerCore というのを知りました。Fiddler 自体、Network monitor の後継なのかな?程度の知識しかなくて、昔は winsock をトラップするには特殊なDLLを入れないといけなくて(それでも DLL を入れて組めばなんとかなったわけですが)、かなり躊躇していたのですが、どうやら Fiddler にはコア部分だけをアプリで使えるように FiddlerCore ってのがあるんですね。なるほど。

# F# で JSON のパーサーが作ってあるのはまた後日に。

Fiddler – The Free Web Debugging Proxy by Telerik
http://fiddler2.com/
FiddlerCore – Fiddler Proxy Engine for your .NET Applications
http://fiddler2.com/fiddlercore

ネットワークモニタとして使う場合は、Fiddler をアプリとしてインストールします。詳細は、↓なんかを参考いすると色々でてきます。

実はFiddlerがすごすぎたので、機能まとめ紹介 – digital matter
http://blog.loadlimits.info/2009/09/%E5%AE%9F%E3%81%AFfiddler%E3%81%8C%E3%81%99%E3%81%94%E3%81%99%E3%81%8E%E3%81%9F%E3%81%AE%E3%81%A7%E3%80%81%E6%A9%9F%E8%83%BD%E3%81%BE%E3%81%A8%E3%82%81%E7%B4%B9%E4%BB%8B/

それはそれでWEB開発のテストには便利なのですが、もうちょっと突っ込んでアプリに組み込んでみたいと思っていたわけです。普通にプロキシを使えばそれでいいのですが、他アプリのネットワークも覗いてみたいですね、という感じで。

Fiddlercore Demo – Fiddler
http://fiddler.wikidot.com/fiddlercore-demo

に組み込んだときのテストコードがあります。これだとちと、ややこしいのでコメントやらイベントの位置を直したのが以下です。

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
    private void Form1_Load(object sender, EventArgs e)
    {
        Fiddler.FiddlerApplication.OnNotification += FiddlerApplication_OnNotification;
        Fiddler.FiddlerApplication.Log.OnLogString += Log_OnLogString;
        Fiddler.FiddlerApplication.BeforeRequest += FiddlerApplication_BeforeRequest;
        Fiddler.FiddlerApplication.BeforeResponse += FiddlerApplication_BeforeResponse;
        Fiddler.FiddlerApplication.AfterSessionComplete += FiddlerApplication_AfterSessionComplete;
        Fiddler.CONFIG.IgnoreServerCertErrors = false;
    }

    void FiddlerApplication_AfterSessionComplete(Fiddler.Session oSession)
    {
        Console.WriteLine("Finished session:t" + oSession.fullUrl);
    }

    void FiddlerApplication_BeforeResponse(Fiddler.Session oSession)
    {
        Debug.WriteLine("{0}:HTTP {1} for {2}", oSession.id, oSession.responseCode, oSession.fullUrl);
    }

    void FiddlerApplication_BeforeRequest(Fiddler.Session oSession)
    {
        Debug.WriteLine("Before request for:t" + oSession.fullUrl);
        oSession.bBufferResponse = true;
    }

    void FiddlerApplication_OnNotification(object sender, Fiddler.NotificationEventArgs e)
    {
        Debug.WriteLine("** NotifyUser: " + e.NotifyString);
    }
    void Log_OnLogString(object sender, Fiddler.LogEventArgs e)
    {
        Debug.WriteLine("** LogString: " + e.LogString);
    }

    /// <summary>
    /// キャプチャ開始
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void button1_Click(object sender, EventArgs e)
    {
        Fiddler.FiddlerApplication.Startup(8877, true, true);

    }

    /// <summary>
    /// キャプチャ終了
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void button2_Click(object sender, EventArgs e)
    {
        Debug.WriteLine("Shutting down...");
        Fiddler.FiddlerApplication.Shutdown();
    }
}

実行するとこんな感じになります。

Before request for:	http://t.jp.msn.com/
** LogString: Fiddler.Network.AutoProxy> AutoProxy Detection failed.
** LogString: AutoProxy failed. Disabling for this network.
1:HTTP 200 for http://t.jp.msn.com/
Finished session:	http://t.jp.msn.com/
Before request for:	http://udc.msn.com/c.gif?evt=impr&js=1&rid=FE68A2FD2C6040C69F537FF40F542212&cts=1377519905144&clid=13849A992C36614418429E192836616E&rf=&cu=http%3A%2F%2Ft.jp.msn.com%2F&bh=776&bw=1264&scr=1920x1080&sd=24&dv.Title1=MSN+Japan&di=258&mk=ja-jp&pn=JP_Homepage&su=http%253A%252F%252Ft.jp.msn.com%252F&pid=250048820&pageid=250048820&mv=15&cv.product=tmx&dv.ContnTp=HomePage&cv.partner=&cv.publcat=
Before request for:	http://c.msn.com/c.gif?udc=true&rid=FE68A2FD2C6040C69F537FF40F542212&rnd=1377519905169&rf=&tp=http%3A%2F%2Ft.jp.msn.com%2F&scr=1920x1080&di=258&pi=9961&ps=26623&lng=ja-jp
Before request for:	http://b.scorecardresearch.com/b?c1=2&c2=3000001&rn=1377519905169&c7=http%3A%2F%2Ft.jp.msn.com%2F&c8=MSN+Japan&c9=
2:HTTP 200 for http://udc.msn.com/c.gif?evt=impr&js=1&rid=FE68A2FD2C6040C69F537FF40F542212&cts=1377519905144&clid=13849A992C36614418429E192836616E&rf=&cu=http%3A%2F%2Ft.jp.msn.com%2F&bh=776&bw=1264&scr=1920x1080&sd=24&dv.Title1=MSN+Japan&di=258&mk=ja-jp&pn=JP_Homepage&su=http%253A%252F%252Ft.jp.msn.com%252F&pid=250048820&pageid=250048820&mv=15&cv.product=tmx&dv.ContnTp=HomePage&cv.partner=&cv.publcat=
4:HTTP 204 for http://b.scorecardresearch.com/b?c1=2&c2=3000001&rn=1377519905169&c7=http%3A%2F%2Ft.jp.msn.com%2F&c8=MSN+Japan&c9=
Finished session:	http://udc.msn.com/c.gif?evt=impr&js=1&rid=FE68A2FD2C6040C69F537FF40F542212&cts=1377519905144&clid=13849A992C36614418429E192836616E&rf=&cu=http%3A%2F%2Ft.jp.msn.com%2F&bh=776&bw=1264&scr=1920x1080&sd=24&dv.Title1=MSN+Japan&di=258&mk=ja-jp&pn=JP_Homepage&su=http%253A%252F%252Ft.jp.msn.com%252F&pid=250048820&pageid=250048820&mv=15&cv.product=tmx&dv.ContnTp=HomePage&cv.partner=&cv.publcat=
Finished session:	http://b.scorecardresearch.com/b?c1=2&c2=3000001&rn=1377519905169&c7=http%3A%2F%2Ft.jp.msn.com%2F&c8=MSN+Japan&c9=
Before request for:	http://kaw.stb01.s-msn.com/i/50/1918772e1d6c3e65af249dfb71f252/_h145_w300_m6_utrue_otrue_lfalse.jpg
Before request for:	http://kaw.stb01.s-msn.com/i/43/b1db42c168f3442eea6c660e454/_h145_w145_m6_utrue_otrue_lfalse.jpg
Before request for:	http://kaw.stb01.s-msn.com/i/53/cadac0dbcd456cef11aec35e1bbe17/_h145_w145_m6_utrue_otrue_lfalse.jpg

手順としては、

  1. トラップするイベントを割り付けておく。
  2. Startup メソッドでプロキシ開始。
  3. データ自体は、AfterSessionComplete イベントの Session オブジェクトで取得。
  4. 終わりは Shutdown を呼び出す。

という流れです。
コードを見るとわかるのですが、Fiddler.FiddlerApplication クラスの static メソッドになっています。つまりは、OS にひとつしかない訳ですね。どうやら、wininet をトラップしているらしく、os 上で動くネットワークを完全にプロキシ

…はしていませんね。wiinet 経由のみ。自前 winsock やっていると駄目? 一応、うちのブラウザIE10でもFirefoxの最新では大丈夫でした。それで十分用途は足りるので。

■フィルタをどうするのか?

ブラウザを複数開いていると(タブでも同じ)、あちこちでアクセスするデータを拾ってきてしまいます。なので、目的のサイトへのアクセスだけをトラップしたい場合は、、AfterSessionComplete イベントの oSession.fullUrl プロパティで判別すると思います。このあたり、いま起動している艦これだけを対象にしたい場合は、横須賀サーバーのIPだけフィルタリングするとか、そういう工夫が必要です。いや、ブラウザのトラップしたいだけなれば、WebBrowser を貼り付けてプロキシ経由にしてしまえば良いのですが。ええ、プロキシに関してはそのうち試してみましょう。

■データをどうやって取得するのか?

レスポンス自体は、oSession.ResponseBody で byte[] で取得するか、oSession.GetResponseBodyAsString() で文字列として取得します。テキストなのかバイナリなのかは、oSession.oResponse.MIMEType でチェックすれば OK ですね。

具体的に動かすのは、横須賀サーバーの復旧待ちということで。

カテゴリー: C# パーマリンク