Thursday, September 07, 2006

Decode ViewState with PowerShell

We have been screwing around with ViewState lately, trying to resolve some issues and shrink down the size. In the process, we've downloaded several utilities to decode the viewstate. However, even these were failing to decode if the Viewstate was over a certain size or if it had non-native datatypes. Since we didn't have access to the source code, we couldn't fix the problems with the utilities. So yesterday, at approximately 3:57 pm, I thought to myself, "Gee, how hard could it be to write my own decoder?" But who wants to create a new VS project for a dinky little utility that you may never use again. Time for a PowerShell Script. It's one file with no compiling necessary.

This script reads the contents of a text file containing the viewstate in question. Then it decodes it, replaces the non-printable characters with pipe symbols and writes the results to another text file. You could easily rewrite this to pass in the viewstate string as a parameter to the script, if you wanted to. You're the kind of person who isn't afraid to paste a +50kb string into your command line of choice. Get down with your bad self!

A note on the non-printable characters: As of .NET 2.0, the viewstate is now delimited with non-printable characters. To learn more read Fritz Onion's blog on the subject.

Now, onto the script:

# Get the file from the arguments and read it into the x
$x = Get-Content $Args[0]

# Parse the string into a byte array
$byteArray = [System.Convert]::FromBase64String($x)

# Create a new encoding object
$enc = New-Object System.Text.ASCIIEncoding

# We need a charArray with the same length as the byteArray. I am having a
# hard time finding out how to create an strongly typed empty array of a given
# length in powershell. If you know how, please let me know. For now I just
# make charArray a copy of byteArray that will be overwritten later.
[System.Char[]]$charArray = $byteArray

# Do the decoding.
$enc.GetDecoder().GetChars($byteArray, 0, $byteArray.Length, $charArray, 0)

# Build the result string.
$charArray | ForEach-Object { $result += $_ }

# This is a neat regex to replace all the non-printing characters with something else.
# Then the result is written out to ViewStateDecoded.txt.
$result -replace "[\x01-\x1F]+", "|" | Out-File ViewStateDecoded.txt

I could probably get this down to 5 lines of code or less, but it more readable this way.

No comments: