-
Notifications
You must be signed in to change notification settings - Fork 21
Skype's UDP Format
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.
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
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
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
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
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
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.
- 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
- 4 bytes original sender's external IP
- 4 bytes unknown
- see also 0x7
- 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
- a stream of data
- data is encrypted, see also Encryption
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