diff --git a/Readme-ja.md b/Readme-ja.md index d4561cf..9415077 100644 --- a/Readme-ja.md +++ b/Readme-ja.md @@ -30,6 +30,16 @@ __VIEWSTATE のパラメータが存在する場合、History の Message Tabに ![ViewState Tab](/image/ViewState.png) +### ViewStateDecoder タブ + +![ViewStateDecoder Tab](/image/ViewStateDecoder.png) + +- [Decode] ボタン +入力したViewState値をデコードします。 + +- [Clear] ボタン +デコードした値をクリアします。 + ## コマンドラインオプション コマンドラインから ViewState の値をデコードすることが可能です。 diff --git a/Readme.md b/Readme.md index 43d0f9f..78a2d38 100644 --- a/Readme.md +++ b/Readme.md @@ -12,7 +12,6 @@ Supports Burp suite Professional/Community. This extension is a tool that allows you to display ViewState of ASP.NET. Note that it is also possible to decode using the command line. - ViewState has been hidden in Burp suite since v2020.3. It is intended for use with Burp suite v2020.x or later. @@ -32,6 +31,16 @@ If the __VIEWSTATE parameter exists, you can select the ViewState from the "sele ![ViewState Tab](/image/ViewState.png) +### ViewStateDecoder Tab + +![ViewStateDecoder Tab](/image/ViewStateDecoder.png) + +- [Decode] Button +Decode the ViewState value. + +- [Clear] Button +Clear the decoded value. + ## Command line option It is possible to decode the value of ViewState from the command line. diff --git a/image/ViewState.png b/image/ViewState.png index 3e3a536..ede6128 100644 Binary files a/image/ViewState.png and b/image/ViewState.png differ diff --git a/image/ViewStateDecoder.png b/image/ViewStateDecoder.png new file mode 100644 index 0000000..932fc3a Binary files /dev/null and b/image/ViewStateDecoder.png differ diff --git a/pom.xml b/pom.xml index a8643bd..babbf44 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 burp ViewStateDecoder - 0.2 + 0.3 jar ${project.version}.0.0 @@ -35,9 +35,10 @@ maven-assembly-plugin - 3.2.0 + 3.3.0 - ${project.basedir}/release + ${project.artifactId}-v${project.version} + ${project.basedir}/release false jar-with-dependencies diff --git a/release/ViewStateDecoder.jar b/release/ViewStateDecoder-v0.3.jar similarity index 93% rename from release/ViewStateDecoder.jar rename to release/ViewStateDecoder-v0.3.jar index 89f5965..97b7ffc 100644 Binary files a/release/ViewStateDecoder.jar and b/release/ViewStateDecoder-v0.3.jar differ diff --git a/src/main/java/aspx/viewstate/ViewStateParser.java b/src/main/java/aspx/viewstate/ViewStateParser.java index 5fc7680..43fd27f 100644 --- a/src/main/java/aspx/viewstate/ViewStateParser.java +++ b/src/main/java/aspx/viewstate/ViewStateParser.java @@ -1,587 +1,594 @@ -package aspx.viewstate; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonNull; -import com.google.gson.JsonObject; -import extend.util.ConvertUtil; -import extend.util.Util; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Base64; -import java.util.logging.Logger; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * @author isayan - * Base Code - * @see https://github.com/mono/mono/blob/da11592cbea4269971f4b1f9624769a85cc10660/mcs/class/referencesource/System.Web/UI/ObjectStateFormatter.cs - * @licenses MIT license - */ -public class ViewStateParser { - private final static Logger logger = Logger.getLogger(ViewStateParser.class.getName()); - - private final static boolean DEBUG_MODE = false; - - // Optimized type tokens - private final static byte Token_Int16 = 0x01; - private final static byte Token_Int32 = 0x02; - private final static byte Token_Byte = 0x03; - private final static byte Token_Char = 0x04; - private final static byte Token_String = 0x05; - private final static byte Token_DateTime = 0x06; - private final static byte Token_Double = 0x07; - private final static byte Token_Single = 0x08; - private final static byte Token_Color = 0x09; - private final static byte Token_KnownColor = 0x0a; - private final static byte Token_IntEnum = 0x0b; - private final static byte Token_EmptyColor = 0x0c; - private final static byte Token_Pair = 0x0f; - private final static byte Token_Triplet = 0x10; - private final static byte Token_Array = 0x14; - private final static byte Token_StringArray = 0x15; - private final static byte Token_ArrayList = 0x16; - private final static byte Token_Hashtable = 0x17; - private final static byte Token_HybridDictionary = 0x18; - private final static byte Token_Type = 0x19; - - private final static byte Token_Unit = 0x1b; - private final static byte Token_EmptyUnit = 0x1c; - private final static byte Token_EventValidationStore = 0x1d; - - // String-table optimized strings - private final static byte Token_IndexedStringAdd = 0x1e; - private final static byte Token_IndexedString = 0x1f; - - // Semi-optimized (TypeConverter-based) - private final static byte Token_StringFormatted = 0x28; - - // Semi-optimized (Types) - private final static byte Token_TypeRefAdd = 0x29; - private final static byte Token_TypeRefAddLocal = 0x2a; - private final static byte Token_TypeRef = 0x2b; - - // Un-optimized (Binary serialized) types - private final static byte Token_BinarySerialized = 0x32; - - // Optimized for sparse arrays - private final static byte Token_SparseArray = 0x3c; - - // Constant values - private final static byte Token_Null = 0x64; - private final static byte Token_EmptyString = 0x65; - private final static byte Token_ZeroInt32 = 0x66; - private final static byte Token_True = 0x67; - private final static byte Token_False = 0x68; - - // Format and Version - private final static byte Marker_Format = (byte) 0xFF; - private final static byte Marker_Version_1 = 0x01; - - private final int HASH_SIZE_IN_BYTES = 128 / 8; - - private boolean detail = false; - - public boolean getDetailMode() { - return detail; - } - - public void setDetailMode(boolean detail) { - this.detail = detail; - } - - public ViewState parse(String viewStateEncode) { - ByteBuffer decodeBuffer = ByteBuffer.wrap(Base64.getDecoder().decode(viewStateEncode)); - decodeBuffer.order(ByteOrder.LITTLE_ENDIAN); // Change Endian - byte formatMarker = decodeBuffer.get(); - byte versionMarker = decodeBuffer.get(); - if (formatMarker == Marker_Format && versionMarker == Marker_Version_1) { - JsonElement jsonRoot = decodeJsonObject(decodeBuffer); - // hmac - int hmac_len = decodeBuffer.remaining(); - if (hmac_len > 0) { - byte[] hmac = new byte[hmac_len]; - decodeBuffer.get(hmac); - ViewState viewState = new ViewState(jsonRoot, hmac); - return viewState; - } else { - ViewState viewState = new ViewState(jsonRoot); - return viewState; - } - } - else { - // Encrypted - ViewState viewState = new ViewState(); - return viewState; - } - } - - public JsonElement decodeJsonObject(ByteBuffer bbf) { - JsonElement decodeNode = JsonNull.INSTANCE; - byte token = bbf.get(); -if (DEBUG_MODE) System.out.println(String.format("Type:0x%02x", token)); - try { - switch (token) { - case Token_Int16: { //? -if (DEBUG_MODE) System.out.println("Token_Int16"); - short value = bbf.getShort(); - JsonObject jsonNode = new JsonObject(); - jsonNode.addProperty("Int16", value); - decodeNode = jsonNode; - break; - } - case Token_Int32: { //? -if (DEBUG_MODE) System.out.println("Token_Int32"); - int value = readEncodedInt32(bbf); - JsonObject jsonNode = new JsonObject(); - jsonNode.addProperty("Int32", value); - decodeNode = jsonNode; - break; - } - case Token_Byte: { // - byte value = bbf.get(); - JsonObject jsonNode = new JsonObject(); - jsonNode.addProperty("byte", value); - decodeNode = jsonNode; - break; - } - case Token_Char: { //?? -if (DEBUG_MODE) System.out.println("Token_Char"); - // 2byteのケースが存在 - //char value = bbf.getChar(); - byte value = bbf.get(); -if (DEBUG_MODE) System.out.println(String.format("\tchar:%c, \\u%04x", value, (int)value)); - JsonObject jsonNode = new JsonObject(); - jsonNode.addProperty("char", value); - decodeNode = jsonNode; - break; - } - case Token_String: { //? - String value = readString(bbf); -if (DEBUG_MODE) System.out.println("string:" + value); - JsonObject jsonNode = new JsonObject(); - jsonNode.addProperty("string", value); - decodeNode = jsonNode; - break; - } - case Token_DateTime: { //? - long date_binary = bbf.getLong(); -if (DEBUG_MODE) System.out.println("DateTime:" + date_binary); -// LocalDateTime value = LocalDateTime.ofInstant(Instant.ofEpochSecond(date_binary), ZoneOffset.UTC); - JsonObject jsonNode = new JsonObject(); - jsonNode.addProperty("DateTime", date_binary); -// jsonNode.addProperty("DateTime", DateTimeFormatter.RFC_1123_DATE_TIME.format(value)); - decodeNode = jsonNode; - break; - } - case Token_Double: { //? - double value = bbf.getDouble(); - JsonObject jsonNode = new JsonObject(); - jsonNode.addProperty("Double", value); - decodeNode = jsonNode; - break; - } - case Token_Single: { //? - float value = bbf.getFloat(); - JsonObject jsonNode = new JsonObject(); - jsonNode.addProperty("Single", value); - decodeNode = jsonNode; - break; - } - case Token_Color: { //? - int value = bbf.getInt() & 0xffffffff; - JsonObject jsonNode = new JsonObject(); - jsonNode.addProperty("Color", value); - decodeNode = jsonNode; - break; - } - case Token_KnownColor: { //? - int value = readEncodedInt32(bbf) & 0xffffffff; - JsonObject jsonNode = new JsonObject(); - jsonNode.addProperty("KnownColor", value); - decodeNode = jsonNode; - break; - } - case Token_IntEnum: { //? - String enumType = readTypeIdent(bbf); - int enumValue = readEncodedInt32(bbf); - JsonObject jsonNode = new JsonObject(); - jsonNode.addProperty("Type", enumType); - jsonNode.addProperty("Value", enumValue); - JsonObject jsonEnum = new JsonObject(); - jsonEnum.add("IntEnum", jsonNode); - decodeNode = jsonEnum; - break; - } - case Token_EmptyColor: { // - JsonObject jsonNode = new JsonObject(); - jsonNode.add("Color", JsonNull.INSTANCE); - decodeNode = jsonNode; - break; - } - case Token_Pair: { //? -if (DEBUG_MODE) System.out.println("Token_Pair"); - JsonElement jsonNode = JsonNull.INSTANCE; - if (detail) { - JsonObject jsonPairObject = new JsonObject(); - JsonElement jsonPairFirst = decodeJsonObject(bbf); - if (!JsonNull.INSTANCE.equals(jsonPairFirst)) { - jsonPairObject.add("First", jsonPairFirst); - - } - JsonElement jsonPairSecond = decodeJsonObject(bbf); - if (!JsonNull.INSTANCE.equals(jsonPairSecond)) { - jsonPairObject.add("Second", jsonPairSecond); - } - JsonObject jsonPair = new JsonObject(); - jsonPair.add("Pair", jsonPairObject); - jsonNode = jsonPair; - } else { - JsonArray jsonPairArray = new JsonArray(); - jsonPairArray.add(decodeJsonObject(bbf)); - jsonPairArray.add(decodeJsonObject(bbf)); - JsonObject jsonPair = new JsonObject(); - jsonPair.add("Pair", jsonPairArray); - jsonNode = jsonPair; - } - decodeNode = jsonNode; - break; - } - case Token_Triplet: { //? -if (DEBUG_MODE) System.out.println("Token_Triplet"); - JsonElement jsonNode = JsonNull.INSTANCE; - if (detail) { - JsonObject jsonTripletObject = new JsonObject(); - JsonElement jsonTripletFirst = decodeJsonObject(bbf); - if (!JsonNull.INSTANCE.equals(jsonTripletFirst)) { - jsonTripletObject.add("First", jsonTripletFirst); - } - JsonElement jsonTripletSecond = decodeJsonObject(bbf); - if (!JsonNull.INSTANCE.equals(jsonTripletSecond)) { - jsonTripletObject.add("Second", jsonTripletSecond); - } - JsonElement jsonTripletThird = decodeJsonObject(bbf); - if (!JsonNull.INSTANCE.equals(jsonTripletThird)) { - jsonTripletObject.add("Third", jsonTripletThird); - } - JsonObject jsonTriplet = new JsonObject(); - jsonTriplet.add("Triplet", jsonTripletObject); - jsonNode = jsonTriplet; - } else { - JsonArray jsonTripletArray = new JsonArray(); - JsonElement jsonTripletFirst = decodeJsonObject(bbf); - jsonTripletArray.add(jsonTripletFirst); - JsonElement jsonTripletSecond = decodeJsonObject(bbf); - jsonTripletArray.add(jsonTripletSecond); - JsonElement jsonTripletThird = decodeJsonObject(bbf); - jsonTripletArray.add(jsonTripletThird); - JsonObject jsonTriplet = new JsonObject(); - jsonTriplet.add("Triplet", jsonTripletArray); - jsonNode = jsonTriplet; - } - decodeNode = jsonNode; - break; - } - case Token_Array: { - String enumType = readTypeIdent(bbf); - int count = readEncodedInt32(bbf); -if (DEBUG_MODE) System.out.println("Token_Array.type:" + enumType); -if (DEBUG_MODE) System.out.println("Token_Array.count:" + count); - JsonArray jsonArray = new JsonArray(); - for (int i = 0; i < count; i++) { - jsonArray.add(decodeJsonObject(bbf)); - } - JsonObject jsonList = new JsonObject(); - jsonList.add("Array" + " " + enumType, jsonArray); - decodeNode = jsonList; - break; - } - case Token_StringArray: { - int count = readEncodedInt32(bbf); -if (DEBUG_MODE) System.out.println("Token_StringArray.count:" + count); - JsonArray jsonArray = new JsonArray(); - String[] array = new String[count]; - for (int i = 0; i < count; i++) { - jsonArray.add(readString(bbf)); - } - JsonObject jsonList = new JsonObject(); - jsonList.add("StringArray", jsonArray); - decodeNode = jsonList; - break; - } - case Token_ArrayList: { //? - int count = readEncodedInt32(bbf); -if (DEBUG_MODE) System.out.println("Token_ArrayList.count:" + count); - JsonArray jsonArray = new JsonArray(); - for (int i = 0; i < count; i++) { - jsonArray.add(decodeJsonObject(bbf)); - } - JsonObject jsonList = new JsonObject(); - jsonList.add("ArrayList", jsonArray); - decodeNode = jsonList; - break; - } - case Token_Hashtable: - case Token_HybridDictionary: { - int count = readEncodedInt32(bbf); -if (DEBUG_MODE) System.out.println("Token_Hashtable.count:" + count); - JsonArray jsonArray = new JsonArray(); - for (int i = 0; i < count; i++) { - JsonObject jsonMap = new JsonObject(); - jsonMap.add("Key", decodeJsonObject(bbf)); - jsonMap.add("Value", decodeJsonObject(bbf)); - jsonArray.add(jsonMap); - } - JsonObject jsonNode = new JsonObject(); - jsonNode.add("Hashtable", jsonArray); - decodeNode = jsonNode; - break; - } - case Token_Type: { - String elementType = readTypeIdent(bbf); - JsonObject jsonNode = new JsonObject(); - jsonNode.addProperty("Type", elementType); - decodeNode = jsonNode; - break; - } - case Token_Unit: { -if (DEBUG_MODE) System.out.println("Token_Unit"); - JsonObject jsonUnit = new JsonObject(); - int b = bbf.remaining(); - double value = bbf.getDouble(); - int type = bbf.getInt(); -// jsonUnit.addProperty("UnitType", type); -// jsonUnit.addProperty("Value", value); - JsonObject jsonNode = new JsonObject(); - jsonNode.addProperty("Unit", String.format("%.2f %s", value, ViewState.getUnitType(type))); - decodeNode = jsonNode; - break; - } - case Token_EmptyUnit: { - JsonObject jsonNode = new JsonObject(); - jsonNode.add("Unit", JsonNull.INSTANCE); - decodeNode = jsonNode; - break; - } - case Token_EventValidationStore: { - byte versionHeader = bbf.get(); - if (versionHeader != 0) { - throw new IllegalArgumentException("Invalid Serialized Data"); - } - JsonArray jsonEvent = new JsonArray(); - int count = readEncodedInt32(bbf); - for (int i = 0; i < count; i++) { - byte[] entry = new byte[HASH_SIZE_IN_BYTES]; - if (bbf.remaining() >= HASH_SIZE_IN_BYTES) { - bbf.get(entry); - jsonEvent.add(ConvertUtil.toHexString(entry)); - } - else { // EOF - throw new IllegalArgumentException("Invalid Serialized Data"); - } - } - JsonObject jsonNode = new JsonObject(); - jsonNode.add("EventValidationStore", jsonEvent); - decodeNode = jsonNode; - break; - } - case Token_IndexedStringAdd: // - case Token_IndexedString: { //? - String value = readIndexedString(bbf, token); -if (DEBUG_MODE) System.out.println("\tindexString:" + value); - JsonObject jsonNode = new JsonObject(); - jsonNode.addProperty("IndexedString", value); - decodeNode = jsonNode; - break; - } - case Token_StringFormatted: { - String elementType = readTypeIdent(bbf); - String formattedValue = readString(bbf); - JsonObject jsonNode = new JsonObject(); - jsonNode.addProperty("Type", elementType); - jsonNode.addProperty("Formatted", formattedValue); - JsonObject jsonFormat = new JsonObject(); - jsonFormat.add("StringFormatted", jsonNode); - decodeNode = jsonFormat; - break; - } - case Token_BinarySerialized: { //? - int count = readEncodedInt32(bbf); -if (DEBUG_MODE) System.out.println("Token_BinarySerialized.count:" + count); - byte[] array = new byte[count]; - bbf.get(array); - JsonObject jsonNode = new JsonObject(); - jsonNode.addProperty("object", new String(array, StandardCharsets.UTF_8)); - decodeNode = jsonNode; - break; - } - case Token_SparseArray: { //? - String elementType = readTypeIdent(bbf); - int count = readEncodedInt32(bbf); - int itemCount = readEncodedInt32(bbf); - if (itemCount > count) { - throw new IllegalArgumentException("Invalid Serialized Data"); - } -if (DEBUG_MODE) System.out.println("Token_SparseArray.type:" + elementType); -if (DEBUG_MODE) System.out.println("Token_SparseArray.count:" + count); -if (DEBUG_MODE) System.out.println("Token_SparseArray.itemCount:" + itemCount); - ArrayList list = new ArrayList<>(); - for (int i = 0; i < count; i++) { - list.add(JsonNull.INSTANCE); - } - for (int i = 0; i < itemCount; i++) { - int nextPos = readEncodedInt32(bbf); - if (nextPos >= count || nextPos < 0) { - throw new IllegalArgumentException("Invalid Serialized Data:" + nextPos); - } - list.set(nextPos, decodeJsonObject(bbf)); - } - JsonArray jsonArray = new JsonArray(); - for (int i = 0; i < list.size(); i++) { - jsonArray.add(list.get(i)); - } - JsonObject jsonNode = new JsonObject(); - jsonNode.add("SparseArray" + " " + elementType + "[]", jsonArray); - decodeNode = jsonNode; - break; - } - case Token_Null: { // - JsonElement jsonNode = JsonNull.INSTANCE; - decodeNode = jsonNode; - break; - } - case Token_EmptyString: { // - JsonObject jsonNode = new JsonObject(); - jsonNode.addProperty("String", ""); - decodeNode = jsonNode; - break; - } - case Token_ZeroInt32: { // - JsonObject jsonNode = new JsonObject(); - jsonNode.addProperty("Int32", 0); - decodeNode = jsonNode; - break; - } - case Token_True: { // - JsonObject jsonNode = new JsonObject(); - jsonNode.addProperty("bool", true); - decodeNode = jsonNode; - break; - } - case Token_False: { // - JsonObject jsonNode = new JsonObject(); - jsonNode.addProperty("bool", false); - decodeNode = jsonNode; - break; - } - default: { -if (DEBUG_MODE) System.out.println("Mismatch token:" + String.format("0x%02x len=%d", token, bbf.remaining())); - JsonObject jsonNode = new JsonObject(); - jsonNode.addProperty("Unknown token", String.format("0x%02x", token)); - decodeNode = jsonNode; - break; - } - } - return decodeNode; - } catch (RuntimeException ex) { -if (DEBUG_MODE) System.out.println(ex.getMessage() + ":" + Util.getStackTrace(ex)); - } - return decodeNode; - } - - private int readEncodedInt32(ByteBuffer bbf) { - int value = 0; - int shift = 0; - byte readByte = 0; - do { - readByte = bbf.get(); - value |= (readByte & 0x7F) << shift; - shift += 7; - } while ((readByte & 0x80) != 0); - return value; - } - - public String readString(ByteBuffer bbf) { - StringBuilder sb = new StringBuilder(); - int stringLength = readEncodedInt32(bbf); - if (stringLength < 0) { - throw new IllegalArgumentException("Invalid String Length"); - } - // isEmpty - if (stringLength == 0) { - return ""; - } - byte[] byteBuff = new byte[stringLength]; - ByteBuffer b = bbf.get(byteBuff, 0, stringLength); - sb.append(new String(byteBuff, 0, stringLength, StandardCharsets.UTF_8)); - return sb.toString(); - } - - private String readIndexedString(ByteBuffer bbf, byte token) { - String value = ""; - switch (token) { - case Token_IndexedString: { - byte tableIndex = bbf.get(); - value = new String("stringReference:" + tableIndex); - break; - } - default: { - value = readString(bbf); - break; - } - } - return value; - } - - private JsonObject readType(ByteBuffer bbf) { - final String[] KnownTypes = new String[]{"Object", "int", "string", "bool"}; - JsonObject decodeNode = new JsonObject(); - byte token = bbf.get(); - switch (token) { - case Token_TypeRef: { - int typeID = readEncodedInt32(bbf); - JsonObject jsonType = new JsonObject(); - if (typeID < KnownTypes.length) { - jsonType.addProperty("Type", KnownTypes[typeID]); - } else { - jsonType.addProperty("Type", "Enum"); - } - decodeNode = jsonType; - break; - } - case Token_TypeRefAddLocal: - case Token_TypeRefAdd: { - String typeName = readString(bbf); - JsonObject jsonType = new JsonObject(); - jsonType.addProperty("TypeRef", typeName); - decodeNode = jsonType; - break; - } - default: { - break; - } - } - return decodeNode; - } - - private String readTypeIdent(ByteBuffer bbf) { - JsonObject ident = readType(bbf); - if (ident.has("Type")) { - return ident.get("Type").getAsString(); - } else if (ident.has("TypeRef")) { - return ident.get("TypeRef").getAsString(); - } - return "Unknown"; - } - - private final static Pattern PTN_URL = Pattern.compile("%([0-9a-fA-F]{2})"); - - public static boolean isUrlencoded(String value) { - Matcher m = PTN_URL.matcher(value); - return m.find(); - } - -} +package aspx.viewstate; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; +import com.google.gson.JsonObject; +import extend.util.ConvertUtil; +import extend.util.Util; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Base64; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author isayan + * Base Code + * @see https://github.com/mono/mono/blob/da11592cbea4269971f4b1f9624769a85cc10660/mcs/class/referencesource/System.Web/UI/ObjectStateFormatter.cs + * @licenses MIT license + */ +public class ViewStateParser { + private final static Logger logger = Logger.getLogger(ViewStateParser.class.getName()); + + private final static boolean DEBUG_MODE = false; + + private Charset encoding = StandardCharsets.UTF_8; + + // Optimized type tokens + private final static byte Token_Int16 = 0x01; + private final static byte Token_Int32 = 0x02; + private final static byte Token_Byte = 0x03; + private final static byte Token_Char = 0x04; + private final static byte Token_String = 0x05; + private final static byte Token_DateTime = 0x06; + private final static byte Token_Double = 0x07; + private final static byte Token_Single = 0x08; + private final static byte Token_Color = 0x09; + private final static byte Token_KnownColor = 0x0a; + private final static byte Token_IntEnum = 0x0b; + private final static byte Token_EmptyColor = 0x0c; + private final static byte Token_Pair = 0x0f; + private final static byte Token_Triplet = 0x10; + private final static byte Token_Array = 0x14; + private final static byte Token_StringArray = 0x15; + private final static byte Token_ArrayList = 0x16; + private final static byte Token_Hashtable = 0x17; + private final static byte Token_HybridDictionary = 0x18; + private final static byte Token_Type = 0x19; + + private final static byte Token_Unit = 0x1b; + private final static byte Token_EmptyUnit = 0x1c; + private final static byte Token_EventValidationStore = 0x1d; + + // String-table optimized strings + private final static byte Token_IndexedStringAdd = 0x1e; + private final static byte Token_IndexedString = 0x1f; + + // Semi-optimized (TypeConverter-based) + private final static byte Token_StringFormatted = 0x28; + + // Semi-optimized (Types) + private final static byte Token_TypeRefAdd = 0x29; + private final static byte Token_TypeRefAddLocal = 0x2a; + private final static byte Token_TypeRef = 0x2b; + + // Un-optimized (Binary serialized) types + private final static byte Token_BinarySerialized = 0x32; + + // Optimized for sparse arrays + private final static byte Token_SparseArray = 0x3c; + + // Constant values + private final static byte Token_Null = 0x64; + private final static byte Token_EmptyString = 0x65; + private final static byte Token_ZeroInt32 = 0x66; + private final static byte Token_True = 0x67; + private final static byte Token_False = 0x68; + + // Format and Version + private final static byte Marker_Format = (byte) 0xFF; + private final static byte Marker_Version_1 = 0x01; + + private final int HASH_SIZE_IN_BYTES = 128 / 8; + + private boolean detail = false; + + public boolean getDetailMode() { + return detail; + } + + public void setDetailMode(boolean detail) { + this.detail = detail; + } + + public ViewState parse(String viewStateEncode) { + ByteBuffer decodeBuffer = ByteBuffer.wrap(Base64.getDecoder().decode(viewStateEncode)); + decodeBuffer.order(ByteOrder.LITTLE_ENDIAN); // Change Endian + byte formatMarker = decodeBuffer.get(); + byte versionMarker = decodeBuffer.get(); + if (formatMarker == Marker_Format && versionMarker == Marker_Version_1) { + JsonElement jsonRoot = decodeJsonObject(decodeBuffer); + // hmac + int hmac_len = decodeBuffer.remaining(); + if (hmac_len > 0) { + byte[] hmac = new byte[hmac_len]; + decodeBuffer.get(hmac); + ViewState viewState = new ViewState(jsonRoot, hmac); + return viewState; + } else { + ViewState viewState = new ViewState(jsonRoot); + return viewState; + } + } + else { + // Encrypted + ViewState viewState = new ViewState(); + return viewState; + } + } + + public JsonElement decodeJsonObject(ByteBuffer bbf) { + JsonElement decodeNode = JsonNull.INSTANCE; + byte token = bbf.get(); +if (DEBUG_MODE) System.out.println(String.format("Type:0x%02x", token)); + try { + switch (token) { + case Token_Int16: { //? +if (DEBUG_MODE) System.out.println("Token_Int16"); + short value = bbf.getShort(); + JsonObject jsonNode = new JsonObject(); + jsonNode.addProperty("Int16", value); + decodeNode = jsonNode; + break; + } + case Token_Int32: { //? +if (DEBUG_MODE) System.out.println("Token_Int32"); + int value = readEncodedInt32(bbf); + JsonObject jsonNode = new JsonObject(); + jsonNode.addProperty("Int32", value); + decodeNode = jsonNode; + break; + } + case Token_Byte: { // + byte value = bbf.get(); + JsonObject jsonNode = new JsonObject(); + jsonNode.addProperty("byte", value); + decodeNode = jsonNode; + break; + } + case Token_Char: { //?? +if (DEBUG_MODE) System.out.println("Token_Char"); + // 2byteのケースが存在 + //char value = bbf.getChar(); + byte value = bbf.get(); +if (DEBUG_MODE) System.out.println(String.format("\tchar:%c, \\u%04x", value, (int)value)); + JsonObject jsonNode = new JsonObject(); + jsonNode.addProperty("char", value); + decodeNode = jsonNode; + break; + } + case Token_String: { //? + String value = readString(bbf); +if (DEBUG_MODE) System.out.println("string:" + value); + JsonObject jsonNode = new JsonObject(); + jsonNode.addProperty("string", value); + decodeNode = jsonNode; + break; + } + case Token_DateTime: { //? + long date_binary = bbf.getLong(); +if (DEBUG_MODE) System.out.println("DateTime:" + date_binary); +// LocalDateTime value = LocalDateTime.ofInstant(Instant.ofEpochSecond(date_binary), ZoneOffset.UTC); + JsonObject jsonNode = new JsonObject(); + jsonNode.addProperty("DateTime", date_binary); +// jsonNode.addProperty("DateTime", DateTimeFormatter.RFC_1123_DATE_TIME.format(value)); + decodeNode = jsonNode; + break; + } + case Token_Double: { //? + double value = bbf.getDouble(); + JsonObject jsonNode = new JsonObject(); + jsonNode.addProperty("Double", value); + decodeNode = jsonNode; + break; + } + case Token_Single: { //? + float value = bbf.getFloat(); + JsonObject jsonNode = new JsonObject(); + jsonNode.addProperty("Single", value); + decodeNode = jsonNode; + break; + } + case Token_Color: { //? + int value = bbf.getInt() & 0xffffffff; + JsonObject jsonNode = new JsonObject(); + jsonNode.addProperty("Color", value); + decodeNode = jsonNode; + break; + } + case Token_KnownColor: { //? + int value = readEncodedInt32(bbf) & 0xffffffff; + JsonObject jsonNode = new JsonObject(); + jsonNode.addProperty("KnownColor", value); + decodeNode = jsonNode; + break; + } + case Token_IntEnum: { //? + String enumType = readTypeIdent(bbf); + int enumValue = readEncodedInt32(bbf); + JsonObject jsonNode = new JsonObject(); + jsonNode.addProperty("Type", enumType); + jsonNode.addProperty("Value", enumValue); + JsonObject jsonEnum = new JsonObject(); + jsonEnum.add("IntEnum", jsonNode); + decodeNode = jsonEnum; + break; + } + case Token_EmptyColor: { // + JsonObject jsonNode = new JsonObject(); + jsonNode.add("Color", JsonNull.INSTANCE); + decodeNode = jsonNode; + break; + } + case Token_Pair: { //? +if (DEBUG_MODE) System.out.println("Token_Pair"); + JsonElement jsonNode = JsonNull.INSTANCE; + if (detail) { + JsonObject jsonPairObject = new JsonObject(); + JsonElement jsonPairFirst = decodeJsonObject(bbf); + if (!JsonNull.INSTANCE.equals(jsonPairFirst)) { + jsonPairObject.add("First", jsonPairFirst); + + } + JsonElement jsonPairSecond = decodeJsonObject(bbf); + if (!JsonNull.INSTANCE.equals(jsonPairSecond)) { + jsonPairObject.add("Second", jsonPairSecond); + } + JsonObject jsonPair = new JsonObject(); + jsonPair.add("Pair", jsonPairObject); + jsonNode = jsonPair; + } else { + JsonArray jsonPairArray = new JsonArray(); + jsonPairArray.add(decodeJsonObject(bbf)); + jsonPairArray.add(decodeJsonObject(bbf)); + JsonObject jsonPair = new JsonObject(); + jsonPair.add("Pair", jsonPairArray); + jsonNode = jsonPair; + } + decodeNode = jsonNode; + break; + } + case Token_Triplet: { //? +if (DEBUG_MODE) System.out.println("Token_Triplet"); + JsonElement jsonNode = JsonNull.INSTANCE; + if (detail) { + JsonObject jsonTripletObject = new JsonObject(); + JsonElement jsonTripletFirst = decodeJsonObject(bbf); + if (!JsonNull.INSTANCE.equals(jsonTripletFirst)) { + jsonTripletObject.add("First", jsonTripletFirst); + } + JsonElement jsonTripletSecond = decodeJsonObject(bbf); + if (!JsonNull.INSTANCE.equals(jsonTripletSecond)) { + jsonTripletObject.add("Second", jsonTripletSecond); + } + JsonElement jsonTripletThird = decodeJsonObject(bbf); + if (!JsonNull.INSTANCE.equals(jsonTripletThird)) { + jsonTripletObject.add("Third", jsonTripletThird); + } + JsonObject jsonTriplet = new JsonObject(); + jsonTriplet.add("Triplet", jsonTripletObject); + jsonNode = jsonTriplet; + } else { + JsonArray jsonTripletArray = new JsonArray(); + JsonElement jsonTripletFirst = decodeJsonObject(bbf); + jsonTripletArray.add(jsonTripletFirst); + JsonElement jsonTripletSecond = decodeJsonObject(bbf); + jsonTripletArray.add(jsonTripletSecond); + JsonElement jsonTripletThird = decodeJsonObject(bbf); + jsonTripletArray.add(jsonTripletThird); + JsonObject jsonTriplet = new JsonObject(); + jsonTriplet.add("Triplet", jsonTripletArray); + jsonNode = jsonTriplet; + } + decodeNode = jsonNode; + break; + } + case Token_Array: { + String enumType = readTypeIdent(bbf); + int count = readEncodedInt32(bbf); +if (DEBUG_MODE) System.out.println("Token_Array.type:" + enumType); +if (DEBUG_MODE) System.out.println("Token_Array.count:" + count); + JsonArray jsonArray = new JsonArray(); + for (int i = 0; i < count; i++) { + jsonArray.add(decodeJsonObject(bbf)); + } + JsonObject jsonList = new JsonObject(); + jsonList.add("Array" + " " + enumType, jsonArray); + decodeNode = jsonList; + break; + } + case Token_StringArray: { + int count = readEncodedInt32(bbf); +if (DEBUG_MODE) System.out.println("Token_StringArray.count:" + count); + JsonArray jsonArray = new JsonArray(); + String[] array = new String[count]; + for (int i = 0; i < count; i++) { + jsonArray.add(readString(bbf)); + } + JsonObject jsonList = new JsonObject(); + jsonList.add("StringArray", jsonArray); + decodeNode = jsonList; + break; + } + case Token_ArrayList: { //? + int count = readEncodedInt32(bbf); +if (DEBUG_MODE) System.out.println("Token_ArrayList.count:" + count); + JsonArray jsonArray = new JsonArray(); + for (int i = 0; i < count; i++) { + jsonArray.add(decodeJsonObject(bbf)); + } + JsonObject jsonList = new JsonObject(); + jsonList.add("ArrayList", jsonArray); + decodeNode = jsonList; + break; + } + case Token_Hashtable: + case Token_HybridDictionary: { + int count = readEncodedInt32(bbf); +if (DEBUG_MODE) System.out.println("Token_Hashtable.count:" + count); + JsonArray jsonArray = new JsonArray(); + for (int i = 0; i < count; i++) { + JsonObject jsonMap = new JsonObject(); + jsonMap.add("Key", decodeJsonObject(bbf)); + jsonMap.add("Value", decodeJsonObject(bbf)); + jsonArray.add(jsonMap); + } + JsonObject jsonNode = new JsonObject(); + jsonNode.add("Hashtable", jsonArray); + decodeNode = jsonNode; + break; + } + case Token_Type: { + String elementType = readTypeIdent(bbf); + JsonObject jsonNode = new JsonObject(); + jsonNode.addProperty("Type", elementType); + decodeNode = jsonNode; + break; + } + case Token_Unit: { +if (DEBUG_MODE) System.out.println("Token_Unit"); + JsonObject jsonUnit = new JsonObject(); + int b = bbf.remaining(); + double value = bbf.getDouble(); + int type = bbf.getInt(); +// jsonUnit.addProperty("UnitType", type); +// jsonUnit.addProperty("Value", value); + JsonObject jsonNode = new JsonObject(); + jsonNode.addProperty("Unit", String.format("%.2f %s", value, ViewState.getUnitType(type))); + decodeNode = jsonNode; + break; + } + case Token_EmptyUnit: { + JsonObject jsonNode = new JsonObject(); + jsonNode.add("Unit", JsonNull.INSTANCE); + decodeNode = jsonNode; + break; + } + case Token_EventValidationStore: { + byte versionHeader = bbf.get(); + if (versionHeader != 0) { + throw new IllegalArgumentException("Invalid Serialized Data"); + } + JsonArray jsonEvent = new JsonArray(); + int count = readEncodedInt32(bbf); + for (int i = 0; i < count; i++) { + byte[] entry = new byte[HASH_SIZE_IN_BYTES]; + if (bbf.remaining() >= HASH_SIZE_IN_BYTES) { + bbf.get(entry); + jsonEvent.add(ConvertUtil.toHexString(entry)); + } + else { // EOF + throw new IllegalArgumentException("Invalid Serialized Data"); + } + } + JsonObject jsonNode = new JsonObject(); + jsonNode.add("EventValidationStore", jsonEvent); + decodeNode = jsonNode; + break; + } + case Token_IndexedStringAdd: // + case Token_IndexedString: { //? + String value = readIndexedString(bbf, token); +if (DEBUG_MODE) System.out.println("\tindexString:" + value); + JsonObject jsonNode = new JsonObject(); + jsonNode.addProperty("IndexedString", value); + decodeNode = jsonNode; + break; + } + case Token_StringFormatted: { + String elementType = readTypeIdent(bbf); + String formattedValue = readString(bbf); + JsonObject jsonNode = new JsonObject(); + jsonNode.addProperty("Type", elementType); + jsonNode.addProperty("Formatted", formattedValue); + JsonObject jsonFormat = new JsonObject(); + jsonFormat.add("StringFormatted", jsonNode); + decodeNode = jsonFormat; + break; + } + case Token_BinarySerialized: { //? + int count = readEncodedInt32(bbf); +if (DEBUG_MODE) System.out.println("Token_BinarySerialized.count:" + count); + byte[] array = new byte[count]; + bbf.get(array); + JsonObject jsonNode = new JsonObject(); + jsonNode.addProperty("object", new String(array, encoding)); + decodeNode = jsonNode; + break; + } + case Token_SparseArray: { //? + String elementType = readTypeIdent(bbf); + int count = readEncodedInt32(bbf); + int itemCount = readEncodedInt32(bbf); + if (itemCount > count) { + throw new IllegalArgumentException("Invalid Serialized Data"); + } +if (DEBUG_MODE) System.out.println("Token_SparseArray.type:" + elementType); +if (DEBUG_MODE) System.out.println("Token_SparseArray.count:" + count); +if (DEBUG_MODE) System.out.println("Token_SparseArray.itemCount:" + itemCount); + ArrayList list = new ArrayList<>(); + for (int i = 0; i < count; i++) { + list.add(JsonNull.INSTANCE); + } + for (int i = 0; i < itemCount; i++) { + int nextPos = readEncodedInt32(bbf); + if (nextPos >= count || nextPos < 0) { + throw new IllegalArgumentException("Invalid Serialized Data:" + nextPos); + } + list.set(nextPos, decodeJsonObject(bbf)); + } + JsonArray jsonArray = new JsonArray(); + for (int i = 0; i < list.size(); i++) { + jsonArray.add(list.get(i)); + } + JsonObject jsonNode = new JsonObject(); + jsonNode.add("SparseArray" + " " + elementType + "[]", jsonArray); + decodeNode = jsonNode; + break; + } + case Token_Null: { // + JsonElement jsonNode = JsonNull.INSTANCE; + decodeNode = jsonNode; + break; + } + case Token_EmptyString: { // + JsonObject jsonNode = new JsonObject(); + jsonNode.addProperty("String", ""); + decodeNode = jsonNode; + break; + } + case Token_ZeroInt32: { // + JsonObject jsonNode = new JsonObject(); + jsonNode.addProperty("Int32", 0); + decodeNode = jsonNode; + break; + } + case Token_True: { // + JsonObject jsonNode = new JsonObject(); + jsonNode.addProperty("bool", true); + decodeNode = jsonNode; + break; + } + case Token_False: { // + JsonObject jsonNode = new JsonObject(); + jsonNode.addProperty("bool", false); + decodeNode = jsonNode; + break; + } + default: { +if (DEBUG_MODE) System.out.println("Mismatch token:" + String.format("0x%02x len=%d", token, bbf.remaining())); + JsonObject jsonNode = new JsonObject(); + jsonNode.addProperty("Unknown token", String.format("0x%02x", token)); + decodeNode = jsonNode; + break; + } + } + return decodeNode; + } catch (RuntimeException ex) { +if (DEBUG_MODE) System.out.println(ex.getMessage() + ":" + Util.getStackTrace(ex)); + } + return decodeNode; + } + + private int readEncodedInt32(ByteBuffer bbf) { + int value = 0; + int shift = 0; + byte readByte = 0; + do { + readByte = bbf.get(); + value |= (readByte & 0x7F) << shift; + shift += 7; + } while ((readByte & 0x80) != 0); + return value; + } + + public String readString(ByteBuffer bbf) { + return readString(bbf, StandardCharsets.UTF_8); + } + + public String readString(ByteBuffer bbf, Charset charset) { + StringBuilder sb = new StringBuilder(); + int stringLength = readEncodedInt32(bbf); + if (stringLength < 0) { + throw new IllegalArgumentException("Invalid String Length"); + } + // isEmpty + if (stringLength == 0) { + return ""; + } + byte[] byteBuff = new byte[stringLength]; + ByteBuffer b = bbf.get(byteBuff, 0, stringLength); + sb.append(new String(byteBuff, 0, stringLength, charset)); + return sb.toString(); + } + + private String readIndexedString(ByteBuffer bbf, byte token) { + String value = ""; + switch (token) { + case Token_IndexedString: { + byte tableIndex = bbf.get(); + value = new String("stringReference:" + tableIndex); + break; + } + default: { + value = readString(bbf); + break; + } + } + return value; + } + + private JsonObject readType(ByteBuffer bbf) { + final String[] KnownTypes = new String[]{"Object", "int", "string", "bool"}; + JsonObject decodeNode = new JsonObject(); + byte token = bbf.get(); + switch (token) { + case Token_TypeRef: { + int typeID = readEncodedInt32(bbf); + JsonObject jsonType = new JsonObject(); + if (typeID < KnownTypes.length) { + jsonType.addProperty("Type", KnownTypes[typeID]); + } else { + jsonType.addProperty("Type", "Enum"); + } + decodeNode = jsonType; + break; + } + case Token_TypeRefAddLocal: + case Token_TypeRefAdd: { + String typeName = readString(bbf); + JsonObject jsonType = new JsonObject(); + jsonType.addProperty("TypeRef", typeName); + decodeNode = jsonType; + break; + } + default: { + break; + } + } + return decodeNode; + } + + private String readTypeIdent(ByteBuffer bbf) { + JsonObject ident = readType(bbf); + if (ident.has("Type")) { + return ident.get("Type").getAsString(); + } else if (ident.has("TypeRef")) { + return ident.get("TypeRef").getAsString(); + } + return "Unknown"; + } + + private final static Pattern PTN_URL = Pattern.compile("%([0-9a-fA-F]{2})"); + + public static boolean isUrlencoded(String value) { + Matcher m = PTN_URL.matcher(value); + return m.find(); + } + +} diff --git a/src/main/java/burp/BurpExtender.java b/src/main/java/burp/BurpExtender.java index 949e2da..adb2460 100644 --- a/src/main/java/burp/BurpExtender.java +++ b/src/main/java/burp/BurpExtender.java @@ -5,6 +5,7 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.logging.Logger; +import yagura.view.ViewStateDecoderTab; import yagura.view.ViewStateTab; /** @@ -25,11 +26,13 @@ public static BurpExtender getInstance() { } private final ViewStateTab viewStateTab = new ViewStateTab(); + private final ViewStateDecoderTab viewStateDecoderTab = new ViewStateDecoderTab(); @Override public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) { super.registerExtenderCallbacks(callbacks); callbacks.setExtensionName(String.format("%s v%s", BUNDLE.getString("projname"), BUNDLE.getString("version"))); + callbacks.addSuiteTab(this.viewStateDecoderTab); callbacks.registerMessageEditorTabFactory(this.viewStateTab); } diff --git a/src/main/java/extend/util/external/JsonUtil.java b/src/main/java/extend/util/external/JsonUtil.java index 9f68fb0..46d7730 100644 --- a/src/main/java/extend/util/external/JsonUtil.java +++ b/src/main/java/extend/util/external/JsonUtil.java @@ -61,6 +61,12 @@ public static String prettyJson(JsonElement jsonElement, boolean pretty) { } } + public static DefaultTreeModel toTreeNodeModel(String rootName) { + DefaultMutableTreeNode rootJson = new DefaultMutableTreeNode(rootName); + DefaultTreeModel model = new DefaultTreeModel(rootJson); + return model; + } + public static DefaultTreeModel toJsonTreeModel(JsonElement jsonElement) { return toJsonTreeModel(jsonElement, "JSON"); } diff --git a/src/main/java/yagura/view/ViewStateDecoderTab.form b/src/main/java/yagura/view/ViewStateDecoderTab.form new file mode 100644 index 0000000..22be5d5 --- /dev/null +++ b/src/main/java/yagura/view/ViewStateDecoderTab.form @@ -0,0 +1,102 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/yagura/view/ViewStateDecoderTab.java b/src/main/java/yagura/view/ViewStateDecoderTab.java new file mode 100644 index 0000000..3eef63d --- /dev/null +++ b/src/main/java/yagura/view/ViewStateDecoderTab.java @@ -0,0 +1,129 @@ +package yagura.view; + +import burp.ITab; +import java.awt.Component; + +/** + * + * @author isayan + */ +public class ViewStateDecoderTab extends javax.swing.JPanel implements ITab { + + /** + * Creates new form ViewStateView + */ + public ViewStateDecoderTab() { + initComponents(); + customizeComponents(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + pnlViewStateDecoder = new javax.swing.JPanel(); + jScrollPane1 = new javax.swing.JScrollPane(); + txtViewState = new javax.swing.JTextArea(); + btnDecode = new javax.swing.JButton(); + btnClear = new javax.swing.JButton(); + tabViewStateDecoder = new javax.swing.JTabbedPane(); + + setLayout(new java.awt.BorderLayout()); + + txtViewState.setColumns(20); + txtViewState.setRows(5); + jScrollPane1.setViewportView(txtViewState); + + btnDecode.setText("Decode"); + btnDecode.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnDecodeActionPerformed(evt); + } + }); + + btnClear.setText("Clear"); + btnClear.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnClearActionPerformed(evt); + } + }); + + javax.swing.GroupLayout pnlViewStateDecoderLayout = new javax.swing.GroupLayout(pnlViewStateDecoder); + pnlViewStateDecoder.setLayout(pnlViewStateDecoderLayout); + pnlViewStateDecoderLayout.setHorizontalGroup( + pnlViewStateDecoderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(pnlViewStateDecoderLayout.createSequentialGroup() + .addGap(5, 5, 5) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 549, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(pnlViewStateDecoderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(btnDecode, javax.swing.GroupLayout.PREFERRED_SIZE, 115, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(btnClear, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 115, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap()) + ); + pnlViewStateDecoderLayout.setVerticalGroup( + pnlViewStateDecoderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(pnlViewStateDecoderLayout.createSequentialGroup() + .addContainerGap() + .addGroup(pnlViewStateDecoderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(pnlViewStateDecoderLayout.createSequentialGroup() + .addComponent(btnDecode) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnClear)) + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + add(pnlViewStateDecoder, java.awt.BorderLayout.NORTH); + add(tabViewStateDecoder, java.awt.BorderLayout.CENTER); + }// //GEN-END:initComponents + + public String getViewStateValue() { + String viewState = this.txtViewState.getText().trim(); + return viewState; + } + + + private void btnDecodeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnDecodeActionPerformed + String viewStateValue = getViewStateValue(); + if (viewStateValue.length() > 0) { + this.viewStateTab.setViewState(viewStateValue); + } + }//GEN-LAST:event_btnDecodeActionPerformed + + private void btnClearActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnClearActionPerformed + this.viewStateTab.clearViewState(); + }//GEN-LAST:event_btnClearActionPerformed + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton btnClear; + private javax.swing.JButton btnDecode; + private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JPanel pnlViewStateDecoder; + private javax.swing.JTabbedPane tabViewStateDecoder; + private javax.swing.JTextArea txtViewState; + // End of variables declaration//GEN-END:variables + + + private ViewStateTab viewStateTab = new ViewStateTab(); + + private void customizeComponents() { + this.tabViewStateDecoder.addTab(viewStateTab.getTabCaption(), viewStateTab); + } + + @Override + public String getTabCaption() { + return "ViewStateDecoder"; + } + + @Override + public Component getUiComponent() { + return this; + } +} diff --git a/src/main/java/yagura/view/ViewStateTab.java b/src/main/java/yagura/view/ViewStateTab.java index 08ef6b8..0ea07b2 100644 --- a/src/main/java/yagura/view/ViewStateTab.java +++ b/src/main/java/yagura/view/ViewStateTab.java @@ -14,7 +14,6 @@ import java.awt.Component; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; -import java.util.EnumSet; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.logging.Level; @@ -100,6 +99,7 @@ private void customizeComponents() { renderer.setClosedIcon(emptyIcon); renderer.setLeafIcon(emptyIcon); this.modelJSON = (DefaultTreeModel) this.treeJSON.getModel(); + this.clearViewState(); } private void btnExpandActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnExpandActionPerformed @@ -163,52 +163,7 @@ public void setMessage(byte[] content, boolean isMessageRequest) { } } } - if (viewStateValue == null) { - return ; - } - if (ViewStateParser.isUrlencoded(viewStateValue)) { - viewStateValue = URLDecoder.decode(viewStateValue, StandardCharsets.ISO_8859_1); - } - final ViewStateParser vs = new ViewStateParser(); - final String viewStateDecode = viewStateValue; - try { - // Tree View - SwingWorker swTree = new SwingWorker() { - @Override - protected DefaultTreeModel doInBackground() throws Exception { - publish("..."); - final ViewState viewState = vs.parse(viewStateDecode); - publish("......"); - if (viewState.isEncrypted()) { - return JsonUtil.toJsonTreeModel(ViewState.ENCRYPTED_JSON, "viewState"); - } - else { - String enabled = viewState.isMacEnabled() ? "[MAC enabled]" : "[MAC disnabled]"; - return (DefaultTreeModel)JsonUtil.toJsonTreeModel(viewState.toJson(), "viewState" + " - " + enabled); - } - } - - protected void process(List chunks) { - modelJSON.setRoot(new DefaultMutableTreeNode("Heavy Processing" + ConvertUtil.repeat("...", chunks.size()))); - } - - protected void done() { - try { - modelJSON = get(); - SwingUtil.allNodesChanged(treeJSON); - treeJSON.setModel(modelJSON); - expandJsonTree(); - } catch (InterruptedException ex) { - Logger.getLogger(ViewStateTab.class.getName()).log(Level.SEVERE, null, ex); - } catch (ExecutionException ex) { - Logger.getLogger(ViewStateTab.class.getName()).log(Level.SEVERE, null, ex); - } - } - }; - swTree.execute(); - } catch (IllegalArgumentException ex) { - Logger.getLogger(ViewStateTab.class.getName()).log(Level.WARNING, null, ex); - } + setViewState(viewStateValue); } } @@ -221,6 +176,59 @@ public byte[] getMessage() { } } + public void setViewState(String viewStateValue) { + if (viewStateValue == null) { + return ; + } + if (ViewStateParser.isUrlencoded(viewStateValue)) { + viewStateValue = URLDecoder.decode(viewStateValue, StandardCharsets.ISO_8859_1); + } + final ViewStateParser vs = new ViewStateParser(); + final String viewStateDecode = viewStateValue; + try { + // Tree View + SwingWorker swTree = new SwingWorker() { + @Override + protected DefaultTreeModel doInBackground() throws Exception { + publish("..."); + final ViewState viewState = vs.parse(viewStateDecode); + publish("...", "..."); + if (viewState.isEncrypted()) { + return JsonUtil.toJsonTreeModel(ViewState.ENCRYPTED_JSON, "viewState"); + } + else { + String enabled = viewState.isMacEnabled() ? "[MAC enabled]" : "[MAC disnabled]"; + return (DefaultTreeModel)JsonUtil.toJsonTreeModel(viewState.toJson(), "viewState" + " - " + enabled); + } + } + + protected void process(List chunks) { + modelJSON.setRoot(new DefaultMutableTreeNode("Heavy Processing" + ConvertUtil.repeat("...", chunks.size()))); + } + + protected void done() { + try { + modelJSON = get(); + SwingUtil.allNodesChanged(treeJSON); + treeJSON.setModel(modelJSON); + expandJsonTree(); + } catch (InterruptedException ex) { + Logger.getLogger(ViewStateTab.class.getName()).log(Level.SEVERE, null, ex); + } catch (ExecutionException ex) { + Logger.getLogger(ViewStateTab.class.getName()).log(Level.SEVERE, null, ex); + } + } + }; + swTree.execute(); + } catch (IllegalArgumentException ex) { + Logger.getLogger(ViewStateTab.class.getName()).log(Level.WARNING, null, ex); + } + } + + public void clearViewState() { + this.treeJSON.setModel(JsonUtil.toTreeNodeModel("viewState")); + } + @Override public boolean isModified() { return false; @@ -230,6 +238,7 @@ public boolean isModified() { public byte[] getSelectedData() { return null; } + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton btnCollapse; private javax.swing.JButton btnExpand;