关于asp.net:如何解码viewstate

关于asp.net:如何解码viewstate

How to decode viewstate

我需要查看一个asp.net页面的viewstate的内容。 我寻找了一个视图状态解码器,找到了弗里兹·洋葱(Fridz Onion)的视图状态解码器,但它请求页面的URL来获取其视图状态。 由于我的viewstate是在回发之后形成的,并且是由于更新面板中的操作而产生的,因此我无法提供url。 我需要复制并粘贴viewstate字符串,然后查看其中的内容。 是否存在可以帮助查看viewstate内容的工具或网站?


这是一个在线ViewState解码器:

http://ignatu.co.uk/ViewStateDecoder.aspx

编辑:不幸的是,以上链接已死-这是另一个ViewState解码器(来自注释):

http://viewstatedecoder.azurewebsites.net/


使用Fiddler并在响应中获取视图状态,然后将其粘贴到左下方的文本框中,然后进行解码。


这是Scott Mitchell在ViewState上的文章(共25页)中ViewView可视化工具的源代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
using System;
using System.Collections;
using System.Text;
using System.IO;
using System.Web.UI;


namespace ViewStateArticle.ExtendedPageClasses
{
    /// <summary>
    /// Parses the view state, constructing a viaully-accessible object graph.
    /// </summary>
    public class ViewStateParser
    {
        // private member variables
        private TextWriter tw;
        private string indentString ="  ";

        #region Constructor
        /// <summary>
        /// Creates a new ViewStateParser instance, specifying the TextWriter to emit the output to.
        /// </summary>
        public ViewStateParser(TextWriter writer)
        {
            tw = writer;
        }
        #endregion

        #region Methods
        #region ParseViewStateGraph Methods
        /// <summary>
        /// Emits a readable version of the view state to the TextWriter passed into the object's constructor.
        /// </summary>
        /// <param name="viewState">The view state object to start parsing at.</param>
        public virtual void ParseViewStateGraph(object viewState)
        {
            ParseViewStateGraph(viewState, 0, string.Empty);    
        }

        /// <summary>
        /// Emits a readable version of the view state to the TextWriter passed into the object's constructor.
        /// </summary>
        /// <param name="viewStateAsString">A base-64 encoded representation of the view state to parse.</param>
        public virtual void ParseViewStateGraph(string viewStateAsString)
        {
            // First, deserialize the string into a Triplet
            LosFormatter los = new LosFormatter();
            object viewState = los.Deserialize(viewStateAsString);

            ParseViewStateGraph(viewState, 0, string.Empty);    
        }

        /// <summary>
        /// Recursively parses the view state.
        /// </summary>
        /// <param name="node">The current view state node.</param>
        /// <param name="depth">The"depth" of the view state tree.</param>
        /// <param name="label">A label to display in the emitted output next to the current node.</param>
        protected virtual void ParseViewStateGraph(object node, int depth, string label)
        {
            tw.Write(System.Environment.NewLine);

            if (node == null)
            {
                tw.Write(String.Concat(Indent(depth), label,"NODE IS NULL"));
            }
            else if (node is Triplet)
            {
                tw.Write(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)
            {
                tw.Write(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)
            {
                tw.Write(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)
            {
                tw.Write(String.Concat(Indent(depth), label,"ARRAY"));
                tw.Write(String.Concat("(", 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)
            {
                tw.Write(String.Concat(Indent(depth), label));
                tw.Write(node.ToString() +" (" + node.GetType().ToString() +")");
            }
            else
            {
                tw.Write(String.Concat(Indent(depth), label,"OTHER -"));
                tw.Write(node.GetType().ToString());
            }
        }
        #endregion

        /// <summary>
        /// Returns a string containing the <see cref="IndentString"/> property value a specified number of times.
        /// </summary>
        /// <param name="depth">The number of times to repeat the <see cref="IndentString"/> property.</param>
        /// <returns>A string containing the <see cref="IndentString"/> property value a specified number of times.</returns>
        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();
        }
        #endregion

        #region Properties
        /// <summary>
        /// Specifies the indentation to use for each level when displaying the object graph.
        /// </summary>
        /// <value>A string value; the default is three blank spaces.</value>
        public string IndentString
        {
            get
            {
                return indentString;
            }
            set
            {
                indentString = value;
            }
        }
        #endregion
    }
}

这是一个简单的页面,用于从文本框中读取视图状态并使用上面的代码对其进行图形处理

1
2
3
4
5
6
7
8
9
private void btnParse_Click(object sender, System.EventArgs e)
        {
            // parse the viewState
            StringWriter writer = new StringWriter();
            ViewStateParser p = new ViewStateParser(writer);

            p.ParseViewStateGraph(txtViewState.Text);
            ltlViewState.Text = writer.ToString();
        }

正如另一个人提到的那样,它是base64编码的字符串。过去,我曾使用此网站对其进行解码:

http://www.motobit.com/util/base64-decoder-encoder.asp


这是从2014年开始运作良好的另一种解码器:http://viewstatedecoder.azurewebsites.net/

这在Ignatu解码器因"序列化数据无效"而失败的输入上起作用(尽管它使BinaryFormatter序列化的数据未解码,仅显示了其长度)。


JavaScript-ViewState-Parser:

  • http://mutantzombie.github.com/JavaScript-ViewState-Parser/
  • https://github.com/mutantzombie/JavaScript-ViewState-Parser/

The parser should work with most non-encrypted ViewStates. It doesn’t
handle the serialization format used by .NET version 1 because that
version is sorely outdated and therefore too unlikely to be
encountered in any real situation.

JavaScript ViewState Parser

解析.NET ViewState

  • 深入了解ViewState,第一部分:

    A Spirited Peek into ViewState, Part I

  • 深入了解ViewState,第二部分:

    A Spirited Peek into ViewState, Part II


这是将ViewState从字符串转换为StateBag的某种"本机" .NET方法
代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
public static StateBag LoadViewState(string viewState)
    {
        System.Web.UI.Page converterPage = new System.Web.UI.Page();
        HiddenFieldPageStatePersister persister = new HiddenFieldPageStatePersister(new Page());
        Type utilClass = typeof(System.Web.UI.BaseParser).Assembly.GetType("System.Web.UI.Util");
        if (utilClass != null && persister != null)
        {
            MethodInfo method = utilClass.GetMethod("DeserializeWithAssert", BindingFlags.NonPublic | BindingFlags.Static);
            if (method != null)
            {
                PropertyInfo formatterProperty = persister.GetType().GetProperty("StateFormatter", BindingFlags.NonPublic | BindingFlags.Instance);
                if (formatterProperty != null)
                {
                    IStateFormatter formatter = (IStateFormatter)formatterProperty.GetValue(persister, null);
                    if (formatter != null)
                    {
                        FieldInfo pageField = formatter.GetType().GetField("_page", BindingFlags.NonPublic | BindingFlags.Instance);
                        if (pageField != null)
                        {
                            pageField.SetValue(formatter, null);
                            try
                            {
                                Pair pair = (Pair)method.Invoke(null, new object[] { formatter, viewState });
                                if (pair != null)
                                {
                                    MethodInfo loadViewState = converterPage.GetType().GetMethod("LoadViewStateRecursive", BindingFlags.Instance | BindingFlags.NonPublic);
                                    if (loadViewState != null)
                                    {
                                        FieldInfo postback = converterPage.GetType().GetField("_isCrossPagePostBack", BindingFlags.NonPublic | BindingFlags.Instance);
                                        if (postback != null)
                                        {
                                            postback.SetValue(converterPage, true);
                                        }
                                        FieldInfo namevalue = converterPage.GetType().GetField("_requestValueCollection", BindingFlags.NonPublic | BindingFlags.Instance);
                                        if (namevalue != null)
                                        {
                                            namevalue.SetValue(converterPage, new NameValueCollection());
                                        }
                                        loadViewState.Invoke(converterPage, new object[] { ((Pair)((Pair)pair.First).Second) });
                                        FieldInfo viewStateField = typeof(Control).GetField("_viewState", BindingFlags.NonPublic | BindingFlags.Instance);
                                        if (viewStateField != null)
                                        {
                                            return (StateBag)viewStateField.GetValue(converterPage);
                                        }
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                if (ex != null)
                                {

                                }
                            }
                        }
                    }
                }
            }
        }
        return null;
    }

您可以忽略URL字段,而只需将viewstate粘贴到Viewstate字符串框中。

看起来您的版本确实很旧; ASP.NET 2.0中的序列化方法已更改,因此请获取2.0版本


Lachlan Keown制作的在线Viewstate Viewer:

http://lachlankeown.blogspot.com/2008/05/online-viewstate-viewer-decoder.html


通常,如果您拥有计算机密钥,ViewState应该可以解密,对吗?毕竟,ASP.net需要对其解密,这当然不是黑匣子。


推荐阅读