Skip to content
Hugo Landau edited this page Jul 18, 2014 · 47 revisions

Communication between Skype clients may occur using SkypeUDP, which is an undisclosed proprietary network protocol carried over UDP.

Each SkypeUDP datagram is formed of a header followed by datagram type-specific data. Most content is obfuscated using RC4. Calls are encrypted.

All values are in network order unless otherwise specified.

Table of Contents

UDP Packet Format

    2  ui    Frame ID
    1  ui    Type/Flags
               Low 4 bits:  Message Type
               High 4 bits: Some kind of packet sub-id or message flag(s)
    ...      Type-specific data

UDP Packet Types

    0x2  Payload    (called "Ack" by other authors)
    0x3  Payload Forward/Payload Resend
    0x5  CRC Error
    0x7  CRC Error + Request to Resend (called "NAck" or "NAT Repeat" by other authors)
    0xD  Audio Stream
    0xF  Payload Fragment

Type 0x2: Payload

    4  ui  IV
    4  ui  CRC
    ...    Encrypted (Obfuscated) Object List

The encryption here is just an obfuscation layer providing no real security. The IV is randomly generated.

The CRC is the Skype-CRC32 value of the decrypted data.

The encryption key is derived as follows:

  Seed = Pack the following fields:
    ** Fields packed in little-endian format (which is the opposite of the usual).
    4  ui  (External) Source IP Address
    4  ui  (Final) Destination IP Address
    2  ui  Frame ID
    2  ui  0
  Hash = SkypeCRC(Seed)
  K'   = IV ^ Hash             # K' is  4 bytes long.
  K    = FluxCapacitor(K')     # K  is 80 bytes long.

The encrypted data is decrypted using RC4 using K.

The FluxCapacitor function (`Skype_RC4_Expand_IV`) is a needlessly complicated key derivation function used to frustrate reverse engineering. skype_rc4.c (courtesy of O'Neil) can be used to calculate this function. (The code is very messy as it has been adapted from a disassembly of Skype.)

    Seed = Hash ^ IV
    RC4 = RC4_Context ()
    Skype_RC4_Expand_IV (Seed, RC4)

A python binding for skype_rc4.c by Schlatterbeck is available: FluxCapacitor.py (This is just a binding, it still requires skype_rc4.c.)

Usage:

    # Build skype_rc4.c.
    make
    
    # Run.
    ./FluxCapacitor.py
expect CRC: fc95755e
04 da 01 7f 4d 42 15                              ....MB.         
got    CRC: fc95755e

expect CRC: f28624e6
04 da 01 7f 45 42 15                              ....EB.         
got    CRC: f28624e6

expect CRC: 67ceb123
04 da 01 15 f3 42 15                              .....B.         
got    CRC: 67ceb123

00 01 00 00 00 01 00 00 00 01                     ..........      
expect CRC: e5f3eb82
05 7b 16 3e 42 3c 25                              .{.>B<%         
got    CRC: e5f3eb82

SkypeCRC

This is a variant of "standard" CRC32. See http://blog.runtux.com/2010/10/06/176/. This is also implemented in Schlatterbeck's FluxCapacitor.py.

Standard CRC32 is modified by XORing the initial value with 0xFFFFFFFF before passing it to the CRC32 function, and then XORing the output of the resulting CRC32 value with 0xFFFFFFFF. The default initial seed value is changed to 0xFFFFFFFF (meaning that the default initial seed value to the unmodified CRC32 function remains zero).

In a line:

    def skype_crc(d, seed=0xFFFFFFFF):
      from zlib import crc32
      return crc32(d, seed ^ 0xFFFFFFFF) ^ 0xFFFFFFFF

Skype Commands

The encrypted contents of a Payload frame is a sequence of one or more Commands.

Request/Response correlation is handled using the Frame ID. If a client sends a frame and expects a response, it reserves the frame ID F+1, where F is the Frame ID of the outgoing packet for the response. A frame ID received with this ID is processed as the response.

The format of a Command is as follows:

    ...  uiv  Command Length
    ...  uiv  Command Type/Flags
                TTTT Tabc
                T: The command type is T+1.
                a: Unknown flag.
                b: Is Request?
                c: Unknown flag.
    if "Is Request?" flag set:
      2    ui   Request ID
    Object List

Skype Object List

The format of an Object List is as follows:

An Object List will usually begin with an encoding mode byte to indicate how it is encoded. There are two known encoding schemes:

  1  ui  Encoding Type
           0x41: Raw Encoding
           0x42: Ext Encoding
  ...    Encoded Data

The Raw encoding scheme is an uncompressed encoding scheme as follows:

  Encoded Data:
    ...  uiv  Number of Objects
    ...       Objects
  Object:
      1  ui   Object Type
    ...  uiv  Object "ID"
    ...       Object Data, as follows:
      Object Type == 0x00 (Number):
        ...  uiv  Number
      Object Type == 0x01 (Double):
        ...  double  Double
      Object Type == 0x02 (IP:Port):
        4    ui   IP
        2    ui   Port
      Object Type = 0x03 (String):
        (null-terminated string)
      Object Type == 0x04 (Blob):
        ...  uiv  Blob Length
        ...       Blob Data
      Object Type == 0x05 (Object List):
        Object List (including encoding mode byte)
      Object Type == 0x06 (Number List):
        ...  uiv  Number of Numbers
        For each number:
          ...  uiv  Number

The 'Ext' encoding scheme is an unpleasant compressed encoding scheme based on arithmetic compression. Implementations in C adapted from assembly are available. Search for C files with '4142' in the filename.

message type 0x3: RESEND

  • 1 byte probably resend number (usually 0x01)
  • 4 bytes initial value seed (as specified by the REQUEST TO RESEND 0x7)
  • 4 bytes unknown
  • 4 bytes Skype-CRC32 of the deobfuscated payload, CRC identical with the original PAYLOAD's CRC
    • a RESEND contains a payload that is identical to the original packet
  • variable payload

message type 0x5: CRC ERROR

  • 4 bytes original sender's external IP
  • 4 bytes unknown
    • see also 0x7

message type 0x7: CRC ERROR + REQUEST TO RESEND

  • 4 bytes original sender's external IP
  • 4 bytes initial value "seed"
    • these 4 bytes are always identical with 4 bytes in the following resend packet
    • not an IP address (Vanilla Skype is wrong there)
    • actually the first 2 bytes are the first 2 bytes of the RC4 seed, which decrypts the resend packet
    • the other 2 bytes are unknown

message type 0xD: AUDIO STREAM

  • a stream of data
  • data is encrypted, see also Encryption

message type 0xF: FRAGMENT

PAYLOADs > 1340 or so are split in fragments. Fragment payload is obfuscated (iv+crc, as in PAYLOADs). Each fragment must be deobfuscated individually (independent of the other fragment packets). Concatenation of deobfuscated fragments constitutes a SkypeObject (just like PAYLOADs do).

  • 2 bytes: in reply to your REQUEST PAYLOAD object id
  • 4 bits: flags: 0x00=more fragments to come, 0x80=this is the last fragment
  • 4 bits: fragment number: 0x00...until flags==0x80
  • 1 byte "magic", which is always 0x02
  • 4 bytes: initial value for deobfuscation of the current fragment packet's payload
  • 4 bytes: Skype-CRC32 of the deobfuscated current fragment packet's payload
  • payload