Coding Range

Decoded: Steam In-Home Streaming Control Protocol

January 26th, 2014

With the Discovery protocol done, the control protocol’s format has proven to be quite elusive. Looking at a packet capture, the format seemed to be, repeated:

  • 3 bytes of unknown contents
  • 2 bytes big-endian, which is the payload size
  • N bytes, which is the payload

What eventually gave it away was that the string “steam” appeared in one of the packets, and following that in a disassembler pointed me to SSL PSK methods.

Finding clues from the string "steam"

Of course, once I found that I noticed that it had been staring me in the face the whole time.

Steam's CSSLPSKContextContainer saying hi from CRemoteClientManager::BInitialize

The next question then is, from where does the Pre-Shared Key (PSK) come from? That also turned out to have been staring me in the face for a while, as I found it quite quickly when looking at an old dump of Steam’s traffic from NetHook:

Steam's servers sending the Account Secret to a local Steam client

(Update: If you want to find your own key, Steam caches it in userdata/your Steam account ID/config/localconfig.vdf - look for ‘AuthData’ in the ‘SharedAuth’ section.)

A quick test of that key showed that I was right.

Connecting to Steam In-Home Streaming with OpenSSL's s_client

A few things are instantly recognisable - VT01 is Valve’s “Magic” value for the TCP protocol that the Steam client uses to communicate with the Steam servers. The other recognisable string in there is “Yavin”, which is my computer’s machine name.

Most likely then, this follows the standard “CM Client” protocol which is:

  • Length: uint32, little-endian - length of the payload
  • Magic: uint32, little-endian - “VT01”
  • Payload: number of bytes specified in Length. The payload starts with a little-endiant uint32 EMsg value.

The relevant EMsg values for the Remote Control protocol are:

  • Auth: 0x251C (9500)
  • AuthResponse: 0x251D (9501)
  • AppStatus: 0x251E (9502)
  • StartStream: 0x251F (9503)
  • StartStreamResponse: 0x2520 (9504)
  • Ping: 0x2521 (9505)
  • PingResponse: 0x2522 (9506)

Unfortunately I can’t feasibly progress any further as I can’t find any decent libraries that support TLS-PSK. The only one I can find is OpenSSL (which is what Valve uses), but it’s so low-level that there’s an enormous amount of overhead before I can even send or recieve any data that it might just not be worth it.

Any third-party client would need to connect to Steam to obtain the Pre-Shared Key, which while doable, also adds a lot more work before I can even launch a game to stream.

If anyone knows of any high-level TLS-PSK client libraries, please let me know.