TS2A
Work in progress
This article is currently under construction! This might be moved to http://imfreedom.org/wiki/ once its done.
General
I (JayFoxRox) give up this project and open it for other developers so they can continue to work on it. I wrote multiple version of a teamspeak client. One was written in VB6 and is almost fully functional. Another one was written in C++ but it never got out of the testing phase. This article will feature some bits of the dirty source code of the VB6 version! The full VB6 version won't be released because it depends on C code which will be used in commercial Projects in the near future.
Rules
Some rules apply if you use this information:
- If you use this information I would like to be informed about it by! You can do this by contacting me through this wiki or at gp32x.
- You must include my name in the credits of your software (let it be the manual or readme or an about dialog in your program), more information about this when you contact me.
- You are not allowed to create flooders, virus or anything else malicious with the information provided in the article.
- You should, but you are not forced to, make the source of your project available.
- These rules are subject to change and you should check them again before releasing your project!
- This is a loose contract and you are not bound to it except for rule 1, 2 and 3 which can be found above.
Constants
There are some constants which you will come accross in the packets, I will define them here for easier reading.
Codec constants
- CELP_5_1 = 0x0
- CELP_6_3 = 0x1
- SPEEX_12_3 = 0x9
- SPEEX_19_5 = 0xB
- SPEEX_25_9 = 0xC
Packet identifiers
- PACKET_IN_UNKNOWN = 0x0
- PACKET_OUT_UNKNOWN = 0x0
Packet format
More information coming soon
The checksum field
The checksum field in the packet header is a simple CRC32 checksum. The polynom is 0xEDB88320. To generate the checksum field you have to create the complete packet with 0x00000000 in the checksum field, generate the checksum and move it to the checksum field.
Splitting packets
Packet confirmations
Packets: Server to Client
Join Confirmation
Case &HF4BE0400: Dim by_X() As Byte ReDim by_X(&H1B4 - 17) ReadData by_X CopyMemory ln_Challenge, by_X(&HAC - 16), 4 CopyMemory ln_Player, by_X(&HB0 - 16), 4 fr_Main.Debug_Print "INFORMATION"
Pong
| ID | 0xF4BE0200 |
|---|---|
| Description | Response to an incoming Ping signal to keep the connection alive |
| Parameters |
| Size | Field |
|---|---|
| 16 Byte | Default packet header |
Packet arrival confirmation
| ID | 0xF1BE0000 |
|---|---|
| Description | This package is send when a Packet arrived successfully |
| Parameters |
| Size | Field |
|---|---|
| 16 Byte | Default packet header |
Text messages forbidden
Case &HF0BE0FFC: ReDim by_Copy(&HE - 1) ReadData by_Copy fr_Main.Debug_Print "CHAT FORBIDDEN" ProcessConfirmation Client, ln_Server
Unknown
Case &HF1BE0100: fr_Main.Debug_Print "YYY?"
Unable to switch channel
Case &HF0BE91FF: ReDim by_Copy(&H12 - 1) ReadData by_Copy Debug.Print "Couldn't switch channel!" ProcessConfirmation Client, ln_Server
Channellist
Case &HF0BE0600: ReDim by_Copy(4 - 1) ReadData by_Copy Dim ln_Count As Long ln_Count = ReadInteger(1) Debug.Print (ln_Count - 1) & " packets left" ln_Count = ReadInteger(1) Debug.Print "Channels: " & ln_Count Dim in_X As Integer For in_X = 0 To ln_Count - 1 Dim ln_ChannelID As Long Dim ln_Order As Long Dim ln_Parent As Long ln_ChannelID = ReadInteger(1) ln_Order = ReadInteger(1) ln_Parent = ReadInteger(1) ReDim by_Copy(4 - 1) ReadData by_Copy Dim st_Title As String Dim st_Topic As String Dim st_Description As String 'ls_Channel.AddItem ln_ChannelID & ") " & st_Channel 'Add channel to channellist - TODO! st_Title = ReadText(0) st_Topic = ReadText(0) st_Description = ReadText(0) AddChannel Client, ln_ChannelID, ln_Parent, st_Title, st_Topic, st_Description, ln_Order, by_Copy(2), 0, 0 fr_Main.Debug_Print "" Debug.Print "Channel: " & st_Title & " (" & Hex(by_Copy(3)) & " - " & Hex(ln_Parent) & ", " & Hex(ln_ChannelID) & ")" Next in_X fr_Main.Debug_Print "CHANNELS" ProcessConfirmation Client, ln_Server
Client was moved or kicked (Local client)
Case &HF0BE6500: ReDim by_Copy(&H30 - 1) ReadData by_Copy ' 'Channel switch = 0x30 Bytes -> 00 00 00 00 93 F6 7E BF 0B 00 00 00 06 00 00 00 00 00 00 1F F1 B7 78 F1 1F A1 01 00 00 00 30 F1 1F A1 59 2D E5 B7 6C F1 1F A1 00 00 00 00 07 FF 'Bot got kicked = 0x30 Bytes -> 00 00 00 00 C3 CA 89 AC 17 00 00 00 02 00 02 00 00 00 00 00 00 00 00 00 F0 BE 08 00 00 00 00 00 00 00 00 00 00 00 00 00 07 FF FF 0F FE FF FE FF ' 'MsgBox "Kicked?" fr_Main.Debug_Print "Kicked" ProcessConfirmation Client, ln_Server
Kicked (Remote client)
Case &HF0BE6600: ReDim by_Copy(&H34 - 1) ReadData by_Copy fr_Main.Debug_Print "KICKED FROM CHANNEL" ProcessConfirmation Client, ln_Server
Unknown
Case &HF0BE6700: ReDim by_Copy(&H16 - 1) ReadData by_Copy fr_Main.Debug_Print "ZOMFG?!" ProcessConfirmation Client, ln_Server
Unknown
Case &HF0BE0700: ReDim by_X(&H1D4 - 17) ReadData by_X fr_Main.Debug_Print "FUCKED! - Sub channel switch?" ProcessConfirmation Client, ln_Server ln_Client = 2 ln_Counter = 2 fr_Main.tm_Poll.Enabled = True 'Call tm_Poll_Timer
Server homepage address
Case &HF0BE0800: ReDim by_X(&H12E - 17) ReadData by_X fr_Main.Debug_Print "WEB SERVER" ProcessConfirmation Client, ln_Server
Client join
Case &HF0BE6400: ReDim by_Copy(4 * 5 - 1) ReadData by_Copy ReDim by_Copy(2 - 1) ReadData by_Copy ReDim by_Copy(1 - 1) ReadData by_Copy fr_Main.Debug_Print "Name: " & ReadText(by_Copy(0)) ReDim by_Copy(27 - by_Copy(0)) ReadData by_Copy fr_Main.Debug_Print "JOIN" ProcessConfirmation Client, ln_Server
Client list (?)
Case &HF0BE6C00: ReDim by_Copy(&H8 - 1) ReadData by_Copy Dim in_Count As Integer in_Count = ReadInteger(1) ReDim by_Copy(&HE - 1) ReadData by_Copy Dim in_Index As Integer For in_Index = 0 To in_Count - 1 Dim in_Channel As Integer Dim in_Sub As Integer ReDim by_Copy(1 - 1) ReadData by_Copy st_String = ReadText(by_Copy(0)) Debug.Print "User in channel: " & st_String ReDim by_Copy(28 - Len(st_String)) ReadData by_Copy in_Channel = ReadInteger(0) in_Sub = ReadInteger(0) ReDim by_Copy(&H5 - 1) ReadData by_Copy Next in_Index ReDim by_Copy(&H1C4 - &H2C * in_Count - &H1A - 1) ReadData by_Copy ProcessConfirmation Client, ln_Server
Channel order index changed
Case &HF0BE7500: ReDim by_Copy(&H12 - 1) ReadData by_Copy Debug.Print "Channel order modified" ProcessConfirmation Client, ln_Server
Channel name changed
Case &HF0BE6F00: ReDim by_Copy(&H10 - 1) ReadData by_Copy st_String = ReadText(0) Debug.Print "Channel name modified (" & st_String & ")" ProcessConfirmation Client, ln_Server
Channel description changed
Case &HF0BE7200: ReDim by_Copy(&H10 - 1) ReadData by_Copy st_String = ReadText(0) Debug.Print "Channel description modified (" & st_String & ")" ProcessConfirmation Client, ln_Server
Channel topic changed
Case &HF0BE7000: ReDim by_Copy(&H10 - 1) ReadData by_Copy st_String = ReadText(0) Debug.Print "Channel topic modified (" & st_String & ")" ProcessConfirmation Client, ln_Server
Player attributes changed
Case &HF0BE6800: ReDim by_Copy(8 - 1) ReadData by_Copy Dim by_Attributes As Byte Dim ln_Index As Long ln_Index = ReadInteger(1) ReDim by_Copy(2 - 1) ReadData by_Copy Dim in_Attributes As Integer CopyMemory in_Attributes, by_Copy(0), 2 fr_Main.Debug_Print "PLAYER ATTRIBUTES" ProcessConfirmation Client, ln_Server
Speech data (CELP 5.1)
Case &HF3BE0000 ReDim by_Copy(&HA6 - 1) ReadData by_Copy fr_Main.Debug_Print "PLAYER SPEECH (CELP 5.1)"
Speech data (CELP 6.3)
Case &HF3BE0001 ReDim by_Copy(&H40 - 1) ReadData by_Copy fr_Main.Debug_Print "PLAYER SPEECH (CELP 6.3)"
Speech data (Speex 12.3)
Case &HF3BE0009 ReDim by_Copy(&H91 - 1) ReadData by_Copy fr_Main.Debug_Print "PLAYER SPEECH (Speex 12.3)"
Speech data (Speex 19.5)
Case &HF3BE000B ReDim by_Copy(&H7 - 1) ReadData by_Copy ReDim by_Copy(&HE4 - 1) ReadData by_Copy fr_Main.Debug_Print "PLAYER SPEECH (Speex 19.5)"
Speech data (Speex 25.9)
Case &HF3BE000C ReDim by_Copy(&H7 - 1) ReadData by_Copy ReDim by_Copy(&H134 - 1) ReadData by_Copy 'Put #5, , by_Copy fr_Main.Debug_Print "PLAYER SPEECH (Speex 25.9)"
Channel removed
Case &HF0BE7300: ln_ChannelID = ReadInteger(1) ln_ChannelID = ReadInteger(1) ReDim by_Copy(&H2 - 1) ReadData by_Copy ln_ChannelID = ReadInteger(1) fr_Main.Debug_Print "Remove Channel" ProcessConfirmation Client, ln_Server Client.Channel(FindChannel(Client, ln_ChannelID)).Used = False Client.ChannelCount = Client.ChannelCount - 1 '00 00 00 00 1F 1B AB 12 1F 00 02 00 00 00
New channel created
Case &HF0BE6E00: ReDim by_Copy(&H8 - 1) ReadData by_Copy ReDim by_Copy(4 - 1) ReadData by_Copy ln_ChannelID = ReadInteger(1) ln_Order = ReadInteger(1) ln_Parent = ReadInteger(1) ReDim by_Copy(4 - 1) ReadData by_Copy st_Title = ReadText(0) fr_Main.Debug_Print "CHANNEL CREATED (" & st_Title & ")" st_Topic = ReadText(0) st_Description = ReadText(0) AddChannel Client, ln_ChannelID, ln_Parent, st_Title, st_Topic, st_Description, ln_Order, by_Copy(2), 0, 0 ProcessConfirmation Client, ln_Server
Channel flags changed
Case &HF0BE7100: ReDim by_Copy(&H14 - 1) ReadData by_Copy Debug.Print "Channel flags modified" 'Channel Created -> 00 00 00 00 50 27 21 CB 02 00 00 00 1E 00 00 00 00 00 0A 00 FF FF FF FF 80 0C 19 00 4F 4D 47 00 00 00 'Channel Changed -> 00 00 00 00 25 D3 01 AA 1F 00 00 00 01 00 0B 00 02 00 00 00 ProcessConfirmation Client, ln_Server
Channel client limit changed
Case &HF0BE7400: ReDim by_Copy(&H12 - 1) ReadData by_Copy Debug.Print "Channel limit modified" ProcessConfirmation Client, ln_Server
Text message received
Case &HF0BE8200: ReDim by_X(8 - 1) ReadData by_X Dim ln_Color As Long ln_Color = ReadInteger(1) fr_Main.Label1.ForeColor = IIf(ln_Color = (ln_Color And &HFFFFFF), ln_Color And &HFFFFFF, GetSysColor(ln_Color And &HFFFFFF)) ReDim by_X(1 - 1) ReadData by_X 'Message type? fr_Main.Label1.Caption = by_X(0) & " " ReadData by_X fr_Main.Label1.Caption = fr_Main.Label1.Caption & ReadText(by_X(0)) & ": " ReDim by_X(27 - by_X(0)) ReadData by_X fr_Main.Label1.Caption = fr_Main.Label1.Caption & ReadText(0) ProcessConfirmation Client, ln_Server
Packets: Client to Server
Join details
WriteInteger &HF0BE0500, 0 WriteInteger ln_Challenge, 1 WriteInteger ln_Player, 1 WriteInteger &H1000000, 0 WriteInteger &H0, 0 ln_Address = WriteInteger(0, 0) Dim st_String As String ReDim by_Copy(2 - 1) WriteData by_Copy st_String = "Cosy Corner" '"Default" '"Dungeon" ReDim by_Copy(1 - 1) by_Copy(0) = Len(st_String) WriteData by_Copy WriteText st_String ReDim by_Copy(29 - Len(st_String) - 1) WriteData by_Copy st_String = "" ReDim by_Copy(1 - 1) by_Copy(0) = Len(st_String) WriteData by_Copy WriteText st_String ReDim by_Copy(29 - Len(st_String) - 1) WriteData by_Copy st_String = "" ReDim by_Copy(1 - 1) by_Copy(0) = Len(st_String) WriteData by_Copy WriteText st_String ReDim by_Copy(29 - Len(st_String) - 1) WriteData by_Copy WriteInteger &H0, 0 Dim ln_Key As Long by_Copy = GetKey(by_Send, 0, UBound(by_Send) - 1) CopyMemory by_Send(ln_Address), by_Copy(0), 4 SendData
Ping
WriteInteger &HF4BE0100, 0 WriteInteger ln_Challenge, 1 WriteInteger ln_Player, 1 WriteInteger ln_Client, 1 'client[0x0C],4 = read[0x0C] ln_Address = WriteInteger(0, 0) by_Copy = GetKey(by_Send, 0, UBound(by_Send) - 1) CopyMemory by_Send(ln_Address), by_Copy(0), 4 ln_Client = ln_Client + 1 SendData
Speech data (Speex 25.9)
WriteInteger &HF2BE000C, 0 WriteInteger ln_Challenge, 1 WriteInteger ln_Player, 1 ln_pcount = ln_pcount + 1 WriteInteger ln_pcount, 1 ReDim by_Copy(&H1 - 1) by_Copy(0) = 5 WriteData by_Copy ReDim by_Copy(&H134 - 1) Get #4, , by_Copy WriteData by_Copy SendData
Packet arrival confirmation
Public Function ProcessConfirmation(Client As TeamspeakClient, Packet As Long) WriteInteger &HF1BE0000, 0 WriteInteger ln_Challenge, 1 WriteInteger ln_Player, 1 WriteInteger Packet, 1 SendData End Function
Player attributes
Public Function ProcessAttribute(Client As TeamspeakClient, Away As Boolean, Microphone As Boolean, Speakers As Boolean, Commander As Boolean, Whisper As Boolean, Record As Boolean) WriteInteger &HF0BE3001, 0 WriteInteger ln_Challenge, 1 WriteInteger ln_Player, 1 WriteInteger ln_Counter, 1 ln_Counter = ln_Counter + 1 WriteInteger 0, 0 ln_Address = WriteInteger(0, 0) Dim by_Attribute(2 - 1) As Byte If Whisper = False Then by_Attribute(0) = by_Attribute(0) + &H4 If Microphone = False Then by_Attribute(0) = by_Attribute(0) + &H10 If Speakers = False Then by_Attribute(0) = by_Attribute(0) + &H20 If Commander = True Then by_Attribute(0) = by_Attribute(0) + &H1 If Away = True Then by_Attribute(0) = by_Attribute(0) + &H8 If Record = True Then by_Attribute(0) = by_Attribute(0) + &H40 by_Attribute(1) = 0 WriteData by_Attribute by_Copy = GetKey(by_Send, 0, UBound(by_Send) - 1) CopyMemory by_Send(ln_Address), by_Copy(0), 4 SendData End Function
Login / Connect packet
Public Function ProcessLogin(Host As String, Display As String, Login As String, Password As String, Assign As Boolean) As TeamspeakClient fr_Main.Debug_Print "LOGIN" Dim st_Split() As String st_Split() = Split(Host, ":") fr_Main.ws_Client.RemoteHost = st_Split(0) fr_Main.ws_Client.RemotePort = IIf(UBound(st_Split) = 0, 8767, st_Split(1)) fr_Main.ws_Client.Bind WriteInteger &HF4BE0300, 0 Dim st_String As String ReDim by_Copy(8 - 1) WriteData by_Copy WriteInteger &H1000000, 0 ln_Address = WriteInteger(0, 0) st_String = "TeamSpeak" ReDim by_Copy(1 - 1) by_Copy(0) = Len(st_String) WriteData by_Copy WriteText st_String ReDim by_Copy(28 - Len(st_String)) WriteData by_Copy st_String = "Shitface Express" ReDim by_Copy(1 - 1) by_Copy(0) = Len(st_String) WriteData by_Copy WriteText st_String ReDim by_Copy(28 - Len(st_String)) WriteData by_Copy WriteText (Chr(2) & Chr(&H0)) 'Major.Major WriteText (Chr(0) & Chr(&H0)) 'Major.Minor WriteText (Chr(32) & Chr(&H0)) 'Minor.Major WriteText (Chr(60) & Chr(&H0)) 'Minor.Minor WriteText (Chr(IIf(Assign, 1, 0)) & Chr(IIf(Login = "", 1, 2))) 'Allow assigned nick / [1 = Anonymous; 2 = Registered] st_String = Login 'Loginname ReDim by_Copy(1 - 1) by_Copy(0) = Len(st_String) WriteData by_Copy WriteText st_String ReDim by_Copy(28 - Len(st_String)) WriteData by_Copy st_String = Password 'Server Password ReDim by_Copy(1 - 1) by_Copy(0) = Len(st_String) WriteData by_Copy WriteText st_String ReDim by_Copy(28 - Len(st_String)) WriteData by_Copy st_String = Display ReDim by_Copy(1 - 1) by_Copy(0) = Len(st_String) WriteData by_Copy WriteText (st_String) ReDim by_Copy(28 - Len(st_String)) WriteData by_Copy by_Copy = GetKey(by_Send, 0, UBound(by_Send) - 1) CopyMemory by_Send(ln_Address), by_Copy(0), 4 SendData ReDim ProcessLogin.Channel(1 - 1) ReDim ProcessLogin.Remote(1 - 1) ReDim ProcessLogin.Packet(1 - 1) ProcessLogin.Used = True End Function
Channel switch
Public Function ProcessSwitch(Client As TeamspeakClient, ByVal Index As Long, Password As String) WriteInteger &HF0BE2F01, 0 WriteInteger ln_Challenge, 1 WriteInteger ln_Player, 1 WriteInteger ln_Counter, 1 ln_Counter = ln_Counter + 1 WriteInteger &H0, 0 ln_Address = WriteInteger(0, 0) WriteInteger Client.Channel(FindChannel(Client, Index)).Index, 1 Dim st_String As String st_String = Password ReDim by_Copy(1 - 1) by_Copy(0) = Len(st_String) WriteData by_Copy WriteText (st_String) ReDim by_Copy(28 - Len(st_String)) WriteData by_Copy by_Copy = GetKey(by_Send, 0, UBound(by_Send) - 1) CopyMemory by_Send(ln_Address), by_Copy(0), 4 SendData End Function
Text message
Public Function ProcessMessage(Client As TeamspeakClient, Receiver As Byte, Color As Long, Text As String) If Receiver = 0 Then End If WriteInteger &HF0BEAE01, 0 WriteInteger ln_Challenge, 1 WriteInteger ln_Player, 1 WriteInteger ln_Counter, 1 ln_Counter = ln_Counter + 1 WriteInteger &H0, 0 ln_Address = WriteInteger(0, 0) WriteInteger Color, 1 WriteInteger &H0, 0 ReDim by_Copy(1 - 1) WriteData by_Copy Dim st_String As String st_String = Text WriteText st_String ReDim by_Copy(1 - 1) WriteData by_Copy by_Copy = GetKey(by_Send, 0, UBound(by_Send) - 1) CopyMemory by_Send(ln_Address), by_Copy(0), 4 SendData End Function
Leave packet
Public Function ProcessExit(Client As TeamspeakClient) WriteInteger &HF0BE6500, 0 WriteInteger ln_Challenge, 1 WriteInteger ln_Player, 1 WriteInteger ln_Counter, 1 ln_Counter = ln_Counter + 1 WriteInteger &H0, 0 ln_Address = WriteInteger(0, 0) WriteInteger &H20, 1 WriteInteger 1, 1 WriteInteger 0, 0 ReDim by_Copy(&H1C - 1) by_Copy(0) = &H90 by_Copy(1) = &HFB by_Copy(2) = &H1F by_Copy(3) = &HA1 by_Copy(4) = &H0 by_Copy(5) = &H0 by_Copy(6) = &H0 by_Copy(7) = &H0 by_Copy(8) = &H40 by_Copy(9) = &HAA by_Copy(10) = &H16 by_Copy(11) = &H6C by_Copy(12) = &HC5 by_Copy(13) = &HEB by_Copy(14) = &HD3 by_Copy(15) = &H3F by_Copy(16) = &H25 by_Copy(17) = &H2D by_Copy(18) = &HE1 by_Copy(19) = &H3F by_Copy(20) = &HD8 by_Copy(21) = &HF2 by_Copy(22) = &H1F by_Copy(23) = &HA1 by_Copy(24) = &H25 by_Copy(25) = &H6F by_Copy(26) = &H5 by_Copy(27) = &H8 WriteData by_Copy by_Copy = GetKey(by_Send, 0, UBound(by_Send) - 1) CopyMemory by_Send(ln_Address), by_Copy(0), 4 SendData End Function
More information coming soon
Sample traffic
Limitiations and Trivia
- The channels codec is not forced, it should be taken as an recommendation
- You can even speak while you are muted
- The version field of a login packet is checked, the OS field is not
More information coming soon
Further reading
A similar project is called TeamBlibbityBlabbity but the documentation is not too good. It might be good as a reference anyway: It can be found at SourceForge