C#」カテゴリーアーカイブ

Fiddler の Inspector プラグインを作ろう

どうもみむらです。

お仕事の関係上、アプリケーションの通信を見ることがありまして。
一般には “Burp” を使うことが多いのですが、
やっぱりサクッと見たいときには Fiddler 先生を使いたくなることがあります。[要出典]

Burp のプラグインを作る話はよくあるのですが Fiddler の話はあまりないのと、
作ってみたらサクッと出来たので記事に纏めてみようかと。


1.プロジェクトを作る

下記のようにまず、 “.NET Framework” の クラスライブラリを作成します。

Fiddler は .NET Framework の 4.6.1 を使用していますので、
バージョンは 4系を選択します。 (4.6.1 か それ以降を選択しておけば OK です)


2.Fiddler を参照に加える

Fiddler.exe を参照に加えます。

通常下記のパスに Fiddler がありますので、こちらを追加します。
%LOCALAPPDATA%\Programs\Fiddler\Fiddler.exe

また、Fiddler の Inspector プラグインはUI に Windows Forms を使用しますので System.Windows.Forms も忘れずに参照に加えます。


3.デバッグの設定をする

プラグインの開発時に F5 でデバッグ出来た方が良いですよね。

プロジェクトの設定の「デバッグ」から
Fiddler.exe (%LOCALAPPDATA%\Programs\Fiddler\Fiddler.exe) を
デバッグプログラムとして指定します。

同様に「ビルド」から、出力先のパスを
お使いのユーザのドキュメントフォルダの “Fiddler2\Inspectors” に出力するようにします。
(%USERPROFILE%\Documents\Fiddler2\Inspectors を展開したパスに保存すれば OK です)


4.Request 側と Response 側のビューのひな形を作る

それでは本題となるビューを作ってみましょう

ビューを作る際は下記のように、レスポンス用とリクエスト用を2つ定義する必要があります。

リクエスト用のビュー

基本的に Inspector2, IRequestInspector2 を継承して作ります。
上記の画像に当該するコードは下記の通りです

using Fiddler;
using System.Windows.Forms;

public class RequestView : Inspector2, IRequestInspector2
{
    /// <summary>
    /// Inspector ビューへの項目の追加やウィンドウの初期化等を行う
    /// </summary>
    /// <param name="o"></param>
    public override void AddToTab(TabPage o)
    {
        o.Text = "さんぷる!";
        o.Controls.Add(new TextBox() {Text = "リクエストヘッダ用!", Dock = DockStyle.Fill, Multiline = true, ReadOnly = true});
    }

    /// <summary>
    /// 項目が必要なくなった場合のクリーンアップ処理を書く (IDisposable の Dispose みたいな)
    /// </summary>
    public void Clear()
    {

    }

    /// <summary>
    /// POST リクエストとして送信されたメッセージ本文
    /// </summary>
    public byte[] body { get; set; }

    /// <summary>
    /// テキストが編集されたかどうかを返す
    /// </summary>
    public bool bDirty { get; }

    /// <summary>
    /// 読み取り専用項目かを取得・設定する
    /// </summary>
    public bool bReadOnly { get; set; }

    /// <summary>
    /// HTTP のリクエストヘッダ
    /// </summary>
    public HTTPRequestHeaders headers { get; set; }

    /// <summary>
    /// Inspector ビュー内の項目の順番(昇順でソートされるため、値が大きければ項目の最後に追加される)
    /// </summary>
    /// <returns>表示順番</returns>
    public override int GetOrder() => 1000;
}

レスポンス用のビュー

レスポンス用の場合は Inspector2, IResponseInspector2 を継承して作ります。
上記の画像に当該するコードは下記の通りです

using Fiddler;
using System.Windows.Forms;

public class ResponseView : Inspector2, IResponseInspector2
{
    /// <summary>
    /// Inspector ビューへの項目の追加やウィンドウの初期化等を行う
    /// </summary>
    /// <param name="o"></param>
    public override void AddToTab(TabPage o)
    {
        o.Text = "さんぷる!";
        o.Controls.Add(new TextBox()
            {Text = "レスポンスヘッダのびゅー!", Dock = DockStyle.Fill, Multiline = true, ReadOnly = true});
    }

    /// <summary>
    /// 項目が必要なくなった場合のクリーンアップ処理を書く (IDisposable の Dispose みたいな)
    /// </summary>
    public void Clear()
    {

    }

    /// <summary>
    /// 受信されたメッセージ本文
    /// </summary>
    public byte[] body { get; set; }

    /// <summary>
    /// テキストが編集されたかどうかを返す
    /// </summary>
    public bool bDirty { get; }

    /// <summary>
    /// 読み取り専用項目かを取得・設定する
    /// </summary>
    public bool bReadOnly { get; set; }

    /// <summary>
    /// HTTP のレスポンスヘッダ
    /// </summary>
    public HTTPResponseHeaders headers { get; set; }

    /// <summary>
    /// Inspector ビュー内の項目の順番(昇順でソートされるため、値が大きければ項目の最後に追加される)
    /// </summary>
    /// <returns>表示順番</returns>
    public override int GetOrder() => 1000;
}

5.Fiddler の RequiredVersion を宣言する

上記の2クラスだけではダメで、必要な Fiddler のバージョンを宣言する必要があります。

どこか1つのソースコードで問題ありませんので、
下記のようにバージョンを宣言するだけのソースコードを作成しましょう。

[assembly: Fiddler.RequiredVersion("2.3.0.0")]

6.実行してみよう

上手くいけば下記のように、「さんぷる!」という名前の項目が追加されて
作成したプラグインが読み込まれるはずです。

画像を編集

7.目的に合わせて拡張しよう

今回の例は Inspector プラグインとして任意のビューを表示するところまでを紹介しました。
ただこれだけではBody の処理や その他のパラメータの処理がかなりおざなりになっています。

そこで下記のような、Request / Response Body のテキストを編集できるサンプルを
下記の GitHub に公開しました。
https://github.com/mimura1133/sample_fiddlerInspector

コードも極力短く、また各パラメータに関しても極力コメントを入れてありますので、
これを踏み台にして独自の Inspector プラグインを作成頂けたら幸いです。


それでは、楽しい Fiddler ライフを!

Visual Studio 2015 で独自言語に対応させてみる。

みむらです。
新年初めての記事ですかね。明けましておめでとうございます。

一年の計は元旦にありということで、元旦から大幅に過ぎてしまいましたが
書き初めを。


何をするか、ということですが
タイトルにあるとおり「独自言語に対応させてみよう」ということで。

2016-01-16 (1)

たとえばこういう感じのが30分ほどで作成できます。


とはいえ、こんなことをしようとする人は、
たぶん放っておいても大丈夫そうな皆さんしかいなさそうな気もしますので、さくっとポイントのみ。

 

まず、作るためには “MPF for Projects” というのを使用するのが楽ちんなのですが、
Visual Studio 2015 用が出ていないようでしたので適当に作って公開しました。

https://github.com/mimura1133/uo_mpfproj14

この中にある “Samples/UsagiProject” の中身を見ると、大体の作り方が見えてくるかと思います。


1. とりあえず、新しい言語プロジェクトを作る:

CustomProjectPackage.cs を開くと、
このようにプロジェクト名とプロジェクトファイルの拡張子を指定できますので、
ここを適当にごにょごにょ。

image

次に上記でごにょごにょした形に合うように、 Templates フォルダ内を設定します。

Projects の中に作ったプロジェクトファイルとアイコンが、
新規作成時のプロジェクト一覧に並びます。

image

デフォルトのままですと、こんな感じですね。

image

 

重要な点として、このとき “Template” フォルダの中身について
ビルドアクションを “コンテンツ” そして “Include in VSIX” を “True” にする
必要があります。

これを忘れると、プロジェクト一覧に出てこなくなります。

image

 


2. 作ったはいいけれど、コンポーネントが読み込めないとかのエラーが出る。

主に、 “Microsoft.VisualStudio.Project” が読み込めないエラーだと思います。

デバッグ中に例外が出て、読み込みが無視されている場合は再ビルドで治る事がありますが、
それでも治らない場合。

extension.vsixmanifest および source.extension.vsixmanifest の “資産” のところに、
”MefComponent” として自身が登録されているか
どうかを確認してみてください。

image

私もこれで2時間潰しました orz.

 


あともう一つ。

ソリューションのファイル群が置いてある場所までのパスに日本語が
入っていないかどうか。

vsix に閉じ込めるファイルやソースのファイルは日本語でも問題なさそうなのですが、
そのソリューション一式のファイルまでのパス中に日本語が入っていると、
インストールしても何も出てこない vsix ファイルが生まれます。

たぶん vsixmanifest の処理あたりで問題が起きていそうな気がしますが、
詳しい所はよく分かりません。。


3.F5 でデバッグしたい!

まず、自身の参照のところに

Microsoft.VisualStudio.Modeling.SDK.Integration.14.0

を入れておきます。
次に、プロジェクトのプロパティより、「デバッグ」の「外部プログラムの開始」に

C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\devenv.exe

と記述し、コマンドライン引数に

/rootsuffix Exp

と書くといい感じに F5 でデバッグできるようになります。

 


そんなこんなで、色々と楽しい事が出来そうな Visual Studio さん。

image

Visual Studio 2015 の vsixmanifest を見ると、
このように Express 版に対してもインストール設定ができるようなので
私のようなフリーソフト作者にとっては、わざわざお高いソフトを導入してもらわなくても試してもらえるってことで、とてもわくてかです。

 

そんなこんなで、私の書き初めは今年も C# から。
それではみなさん Happy Visual Studio Life を。

No Visual Studio, No…. いや、 VS なくても頑張れるかな・・

C# で ini ファイルの内容を任意のクラスに格納するコードを書いてみた。

どうもみむらです。

C# で ini ファイルを操作するとなると、
よくあるのが GetPrivateProfileString あたりを叩いて取得することになります。

でもその場合、いちいち要素を指定して取得しなければならず、
特に複数のキー(フィールド)がある場合に複数回コードを書くのも面倒です。

特に ini ファイルの項目が多くて、こんな状態になった日には・・。

image

 

・・ということで、 Reflection を使用して
この辺をすごく楽に出来るような感じでコードを書いてみました。

 

コード:

using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;

public static class Ini
{
    [DllImport("KERNEL32.DLL")]
    public static extern uint GetPrivateProfileString(string lpAppName, string lpKeyName, string lpDefault, StringBuilder lpReturnedString, uint nSize, string lpFileName);

    [DllImport("KERNEL32.DLL")]
    public static extern uint GetPrivateProfileInt(string lpAppName, string lpKeyName, int nDefault, string lpFileName);

    [DllImport("KERNEL32.DLL")]
    public static extern uint WritePrivateProfileString(string lpAppName, string lpKeyName, string lpString, string lpFileName);

    public static T Read<T>(string section, string filepath)
    {
        T ret = (T)Activator.CreateInstance(typeof(T));

        foreach (var n in typeof(T).GetFields())
        {
            if (n.FieldType == typeof(int))
            {
                n.SetValue(ret, (int)GetPrivateProfileInt(section, n.Name, 0, Path.GetFullPath(filepath)));
            }
            else if (n.FieldType == typeof(uint))
            {
                n.SetValue(ret, GetPrivateProfileInt(section, n.Name, 0, Path.GetFullPath(filepath)));
            }
            else
            {
                var sb = new StringBuilder(1024);
                GetPrivateProfileString(section, n.Name, "", sb, (uint)sb.Capacity, Path.GetFullPath(filepath));
                n.SetValue(ret, sb.ToString());
            }
        };

        return ret;
    }

    public static void Write<T>(string secion, T data, string filepath)
    {
        foreach (var n in typeof(T).GetFields())
        {
            WritePrivateProfileString(secion, n.Name, n.GetValue(data).ToString(), Path.GetFullPath(filepath));
        };
    }
}

 

使い方:

ini ファイルの読み取りたいセクションに合わせたクラスを用意します。

    public class Human
    {
        public string name;
        public int age;
    }

でもって次のような ini ファイルを用意して

[01]
name=TARO
age=20

あとはこんな風に呼び出します。

        static void Main(string[] args)
        {
            var h = Ini.Read<Human>("01", "DATA.INI");

            h.age = 15;
            h.name = "JIRO";
            Ini.Write("02", h, "DATA.INI");
        }

 

実行しますと、

image

こんな感じでデータが読み出されます。

でもって、 ini ファイルは

[01]
name=TARO
age=20
[02]
name=JIRO
age=15

こんな感じに、ちゃんとセクション 02 が書き込まれます。


躓きそうなところ:

データを格納するクラスが、こういう感じに {get; set;} な状態になっている場合:

    public class Human
    {
        public string name { get; set; }
        public int age { get; set; }
    }

上記コード内の GetFields を GetProperties に換え、 FieldType を PropertyType に変えれば動作します。


・・そんなわけで、もし良ければ自己責任でご利用ください-。

Visual Studio 2010 から 2012 のヘルプを見に行くようにする。

新年明けましておめでとうございます。みむらです。

・・あけおめ関連の記事は後で書くとしまして、
大掃除中に見つけたことで一つ。

 

現在私の環境には、Visual Studio 2010 と 2012 がインストールされており、
それぞれを使い分けています。

ただヘルプに関しては、両方インストールしておいても特に幸せなことはありませんので
ディスクを圧迫する関係から、いつか一つにまとめたいと思っていました。

今回、
Visual Studio 2010 から Visual Studio 2012 のヘルプを参照するようにして、
問題解決(?)しましたので紹介します。

 

環境:

Windows 8 Pro
Visual Studio 2010 Ultimate
Visual Studio 2012 Ultimate


1. Visual Studio 2010 をインストール。

2. Visual Studio 2012 をインストール。

3. Visual Studio 2012 のヘルプビューアにコンテンツをインストールする。

image

 

4. Microsoft Help Viewer 1.1 とその Language Pack をアンインストール

image

消す際には、 Language Pack から消すとよさそうです。

 

5.  ms-xhelp:// を Help Viewer 2.0 で処理するように関連づける。

http://mimumimu.net/software/blogup/vs2010_hv2.zip

ftype や assoc でできないかとやってみたのですがどうもうまくいきませんでしたので、
レジストリファイルを用意しました。

このファイルを展開して結合します。


手順は以上のようになります。

当方の環境で試しましたところ、ソースコード上の命令に対する F1 ヘルプも動作しました。
(挙動がわからない命令にキャレットを合わせて F1 を押す)

 

複数環境を入れてある方は、このような方法で統合して、
リアル空間だけではなく、バーチャル空間の掃除も済ませてみてはいかがでしょうか。

Launcher.LaunchUriAsync でブラウザが立ち上がらない。

みむらです。
填まりましたのでメモ。

 

現象:

Launcher.LaunchUriAsync(
	new Uri("http://mimumimu.net")
	);

こういうコード書いてもブラウザが立ち上がらない。

 

確認ポイント:

マニフェストの「機能」のうち、

「プライベートネットワーク(クライアントとサーバ)」が有効になっているかどうか。

 

どうもこいつが有効じゃないと、立ち上がらないようで。