Search code examples
c#c++serializationbinaryfilesbond

Microsoft Bond deserialization without knowing underlying schema


I am looking at some network requests that are happening on my machine, and I recognize some as using the Microsoft Bond data serialization format. I want to deserialize the content of the request, but I do not have the schema that was used to create its content.

I know that with the ProtoBuf compiler, there is a way to output the content of a ProtoBuf-based binary file without the schema with something like:

protoc --decode_raw < data.proto

Is something similar available for Microsoft Bond? I am happy to write C#/C++ code to get that done, but curious if that is even possible.

For reference, the protocol is Compact Binary.


Solution

  • Thanks to some insights from Christopher Warrington, I was able to piece together the methodology through which a Bond-encoded Compact Binary content piece can be "unpacked" into its component pieces:

    var ib = new Bond.IO.Unsafe.InputBuffer(File.ReadAllBytes("response_data.bin"));
    var cbr = new CompactBinaryReader<Bond.IO.Unsafe.InputBuffer>(ib, 2);
    
    cbr.ReadStructBegin();
    
    BondDataType dt = BondDataType.BT_BOOL;
    ushort id = 0;
    
    while (dt != BondDataType.BT_STOP)
    {
        cbr.ReadFieldBegin(out dt, out id);
        Console.WriteLine(dt + " " + id);
        if (dt == BondDataType.BT_STRING)
        {
            var stringValue = cbr.ReadString();
            Console.WriteLine(stringValue);
        }
        else if (dt == BondDataType.BT_LIST)
        {
            BondDataType listContent = BondDataType.BT_BOOL;
            int counter = 0;
            cbr.ReadContainerBegin(out counter, out listContent);
            Console.WriteLine("Inside container: " + listContent);
            if (listContent == BondDataType.BT_STRUCT)
            {
                BondDataType structDt = BondDataType.BT_BOOL;
    
                cbr.ReadStructBegin();
                while(structDt != BondDataType.BT_STOP)
                {
                    cbr.ReadFieldBegin(out structDt, out id);
                    Console.WriteLine(structDt + " " + id);
                    if (structDt == BondDataType.BT_STRING)
                    {
                        var stringValue = cbr.ReadString();
                        Console.WriteLine(stringValue);
                    }
                    else
                    {
                        if (structDt != BondDataType.BT_STOP)
                        {
                            cbr.Skip(structDt);
                        }
                    }
                }
                cbr.ReadStructEnd();
            }
            cbr.ReadContainerEnd();
        }
        else
        {
            if (dt != BondDataType.BT_STOP)
            {
                cbr.Skip(dt);
            }
        }
        cbr.ReadFieldEnd();
    }
    

    This is non-production code (you can spot many issues and lack of nested parsing) but it shows the approach through which one can get the contents.