ViewStateの値の文字列をデコードして解析する - ASP.NET

ASP.NETのViewStateの値の文字列をデコードして解析するコードを紹介します。

概要

ASP.NETでは画面の状態を記憶するしくみとしてViewStateが用いられます。ViewStateは画面の状態や値を表す変数やオブジェクトをエンコードしてHiddenフィールドに設定しています。ここではHiddenフィールドに設定されているエンコード済みのViewStateの文字列をデコードして解析するコードを紹介します。

ViewStateの文字列をデコードするWebアプリをお探しの場合

ViewStateの文字列をデコード、解析するWebアプリはこちらへどうぞ。

事前準備

ASP.NET 2.0以降ではViewStateはデフォルトでは暗号化された状態になっています。解析前に解析対象のページのViewStateの値の暗号化をしない設定にする必要があります。
暗号化解除のためにpageディレクティブに
  • EnableViewStateMac="False"
  • ViewStateEncryptionMode="Never"
を追記します。詳しくはこちらの記事を参照してください。
Pageディレクティブの例
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm_DisabledCrypt.aspx.cs"
  Inherits="ViewStateEncrypt.WebForm_DisabledCrypt"
  EnableViewStateMac="False" ViewStateEncryptionMode="Never"%>

デコード解析プログラム

ASP.NETでViewState解析プログラムを作成します。ASP.NETプロジェクトを新規作成します。

UI

以下のUIを作成します。TextModeプロパティを"MultiLine"に設定したTextBoxを2つ、Buttonを1つ配置します。

aspxファイルのコード
aspxファイルのコードは以下になります。
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="default.aspx.cs" Inherits="ViewStateDecode._default" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
      <div><asp:TextBox ID="TextBox1" runat="server" TextMode="MultiLine" Height="150px" Width="600px"></asp:TextBox></div>
      <div><asp:Button ID="Button1" runat="server" Text="デコード" OnClick="Button1_Click" /></div>
      <div><asp:TextBox ID="TextBox2" runat="server" TextMode="MultiLine" Height="150px" Width="600px"></asp:TextBox></div>
    </div>
    </form>
</body>
</html>

コード

以下のコードを記述します。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Text;
using System.Collections;

namespace ViewStateDecode
{
  public partial class _default : System.Web.UI.Page
  {
    private string IndentString = "   ";
    private List<string> DecodeText;

    protected void Page_Load(object sender, EventArgs e)
    {

    }

    protected void Button1_Click(object sender, EventArgs e)
    {
      LosFormatter los = new LosFormatter();
      object viewState = los.Deserialize(TextBox1.Text);

      DecodeText = new List<string>();
      ParseViewStateGraph(viewState, 0, string.Empty);

      StringBuilder str = new StringBuilder();
      for (int i = 0; i < DecodeText.Count; i++) {
        str.Append(DecodeText[i]);
        str.Append("\r\n");
      }
      TextBox2.Text = str.ToString();
    }

    protected virtual void ParseViewStateGraph(object node, int depth, string label)
    {
      if (node == null) {
        DecodeText.Add(String.Concat(Indent(depth), label, "NODE IS NULL"));
      }
      else if (node is Triplet) {
        DecodeText.Add(String.Concat(Indent(depth), label, "TRIPLET"));
        ParseViewStateGraph(((Triplet)node).First, depth + 1, "First: ");
        ParseViewStateGraph(((Triplet)node).Second, depth + 1, "Second: ");
        ParseViewStateGraph(((Triplet)node).Third, depth + 1, "Third: ");
      }
      else if (node is Pair) {
        DecodeText.Add(String.Concat(Indent(depth), label, "PAIR"));
        ParseViewStateGraph(((Pair)node).First, depth + 1, "First: ");
        ParseViewStateGraph(((Pair)node).Second, depth + 1, "Second: ");
      }
      else if (node is ArrayList) {
        DecodeText.Add(String.Concat(Indent(depth), label, "ARRAYLIST"));

        // display array values
        for (int i = 0; i < ((ArrayList)node).Count; i++)
          ParseViewStateGraph(((ArrayList)node)[i], depth + 1, String.Format("({0}) ", i));
      }
      else if (node.GetType().IsArray) {
        DecodeText.Add(String.Concat(Indent(depth), label, "ARRAY ", "(", node.GetType().ToString(), ")"));
        IEnumerator e = ((Array)node).GetEnumerator();
        int count = 0;
        while (e.MoveNext())
          ParseViewStateGraph(e.Current, depth + 1, String.Format("({0}) ", count++));
      }
      else if (node.GetType().IsPrimitive || node is string) {
        DecodeText.Add(String.Concat(Indent(depth), label, node.ToString() , " (", node.GetType().ToString(), ")"));
      }
      else {
        DecodeText.Add(String.Concat(Indent(depth), label, "OTHER - ", node.GetType().ToString() ));
      }
    }

    protected virtual string Indent(int depth)
    {
      StringBuilder sb = new StringBuilder(IndentString.Length * depth);
      for (int i = 0; i < depth; i++)
        sb.Append(IndentString);

      return sb.ToString();
    }
  }
}

解説

ViewStateをデコードするクラスとしてLosFormatterが用意されています。LosFormatterクラスのDeserializeメソッドを呼び出すことでViewStateの文字列をViewStateオブジェクトに変換できます。
ViewStateオブジェクトはPair, Triplet, ArrayList, またはその他のクラスで表現される木構造になっています。ViewStateオブジェクトの要素を末端までたどり、値をテキストボックスに表示します。

実行結果

プロジェクトを実行します。Webブラウザが起動し下図のwebフォームが表示されます。


上部のテキストボックスにViewStateの値の文字列を入力します。値はname="__VIEWSTATE" id="__VIEWSTATE" の名称のhiddenフィールドのvalueに設定されています。入力するViewStateの値の文字列は暗号化されていない状態のものである必要があります。


[デコード]ボタンをクリックします。ViewStateの文字列をデコードし解析した結果が下部のテキストボックスに表示されます。
今回の例では、最上位のViewStateオブジェクトはPairクラスであり、片方の要素はPairクラス、もう一方はnullとなっています。


著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
最終更新日: 2024-01-06
作成日: 2014-03-25
iPentec all rights reserverd.