About this tutorialI've thrown this together because when I started out programming a bot, I had almost no idea where to start. Sure, there are places such as
BNET Docs that tell you what packets and stuff to send, but getting past the initial phase of "WTF is that and why the hell are we doing it" was hard.
This tutorial was written for mostly anybody, but code examples are in VB, and data that involves Visual Basic is in
orange text.
Introduction to bot programmingA bot such as
StealthBot is actually imitating the starcraft client when it connects to battle.net. It sends data in exactly (more or less) the same way that the actual Starcraft client does.
Once connected to battle.net, the client sends and recieves packets.
A packet is simply information send to and from a server (in this case battle.net). Since battle.net uses TCP protocol, there is actually a server to connect to.
All packets are made up of bytes. Lets take a look at a packet we might send to battle.net.
CODE
FF 0C 19 00 02 00 00 00 4F 70 20 4D 69 6E 64 41 ΓΏ....Op MindA
72 63 68 6F 6E 28 55 29 00 rchon(U)........
(this is packet 0x0C, used to join channels)
On the left is the data we are sending in
hexadecimal, while the data on the right is what the packet would look like in string format.
For instance, in that apcket FF would be a byte, 0C would be a byte, 19 would be a byte.. etc. The data is in hex format (FF) but converted to decimal it is 255 (you can use windows calculator for this).
A byte is made up of 8 bits (bit = 0 or 1 [binary]). 2 bytes make up a
word (integer). So FF 0C would make up a
word (3327 in decimal). A
dword is 4 bytes. So FF 0C 19 00 would be a
dword (1641727 in decimal).
All BNCS (
Battle.
Net
Chat
Server) servers have a specific kind of packet format. This format is
QUOTE(bnetdocs.valhallalegends.com)
(BYTE) Always 0xFF
(BYTE) Message ID
(WORD) Message length, including this header
... Message Data
In Visual Basic 0x means the same as &H which indentifies the value as hexadecimalSo lets analyze the packet above.
FF = every packet starts with this, so thats one byte.
0C = The packet ID (every packet has its own individual ID, so battle.net can figure out what your trying to do)
19 00 = A word (2 bytes). Converts to 25. The entire packet is 25 bytes long
Next is the data inside the packet.
In this particular packet, the data is:
DWORD = [channel flags]
String = channel to join.
Channel flags are either hexadecimal 00 (only will join if the channel isn't empty), hexadecimal 01 (will join a channel with your country code in it, such as Brood War USA-1), or hexadecimal 02 (will join a channel regardless of if its empty or not).
In this example my flag is 02. I dont care if Op MindArchon(U) is empty or not, I just want to join it.
Since the flag is 4 bytes (its a dword) i send
02 00 00 00. Next is the string name I want to join, which always ends in a null character. This tells the server where a string ends.
Congratulations, you just analyzed your first BNCS packet!
Of course you probably wondered how I knew what the packet contained and stuff. There is a free database online that tells you almost every battle.net packet you would ever need to know. Check it out at
http://bnetdocs.valhallalegends.comConnecting to battle.netIf you using VB, you can connect to battle.net with a winsock controlThere are four battle.net servers supported to blizzard.
useast.battle.net
uswest.battle.net
asia.battle.net
europe.battle.net
Those are all on port 6112.
Once connected to battle.net, the first thing you must send is what you want to do. You send this first. In this case we will send one byte (0x01) because that indicates we want to connect as a client. For instance, sending 0x02 would indicate we want to connect to FTP and so on.
After sending 0x01, you must start sending your packets. A complete login sequence can be found at
http://bnetdocs.valhallalegends.com/sequence.phpIn just about any language, it is simple and a lot less confusing to use a packet buffer. Basically you build the packet as you go, then send it when it is complete.
Here is the packet buffer I use in VB, originally done by DarkMinion, modifed by me. Make sure you figure out what this does before you use it. This is a class moduleCODE
Private buffer As String
Public Function InsertDWORD(data As Long)
buffer = buffer & MakeDWORD(data)
End Function
Public Function InsertWORD(data As Integer)
buffer = buffer & MakeWORD(data)
End Function
Public Function InsertBYTE(data As Integer)
buffer = buffer & Chr(data)
End Function
Public Function InsertNTString(data As String)
buffer = buffer & data & Chr(0)
End Function
Public Function InsertNonNTString(data As String)
buffer = buffer & data
End Function
Public Function Clear()
buffer = ""
End Function
Public Function SendPacket(PacketID As Byte)
If MainFRM.bnet.State <> sckConnected Then Exit Function
MainFRM.bnet.SendData Chr(&HFF)
MainFRM.bnet.SendData Chr(PacketID)
MainFRM.bnet.SendData MakeWORD(Len(buffer) + 4)
MainFRM.bnet.SendData buffer
Dim outputb As String
outputb = Chr(&HFF) & Chr(PacketID) & MakeWORD(Len(buffer) + 4) & buffer
'AddC_SCColors MainFRM.channeltext, "BNETSEND:", vbYellow, DebugOutput(outputb), vbRed, True
Clear
End Function
Public Function SendPacketBNLS(PacketID As Byte)
If MainFRM.bnls.State <> sckConnected Then Exit Function
MainFRM.bnls.SendData MakeWORD(Len(buffer) + 3)
MainFRM.bnls.SendData Chr(PacketID)
MainFRM.bnls.SendData buffer
Dim outputb As String
outputb = MakeWORD(Len(buffer) + 3) & Chr(PacketID) & buffer
'AddC_SCColors MainFRM.channeltext, "BNLSSEND:", vbGreen, DebugOutput(outputb), vbRed, True
Clear
End Function
Public Function SendPacketRealm(PacketID As Byte)
If MainFRM.realm.State <> sckConnected Then Exit Function
MainFRM.realm.SendData MakeWORD(Len(buffer) + 3)
MainFRM.realm.SendData Chr(PacketID)
MainFRM.realm.SendData buffer
Dim outputb As String
outputb = MakeWORD(Len(buffer) + 3) & Chr(PacketID) & buffer
'AddC_SCColors MainFRM.channeltext, "BNLSSEND:", vbYellow, DebugOutput(outputb), vbRed, True
Clear
End Function
Then put these functions inside a module somewhere.
CODE
Public Function GetWord(data As String) As Long
Dim lReturn As Long
Call CopyMemory(lReturn, ByVal data, 2)
GetWord = lReturn
End Function
Public Function MakeLong(X As String) As Long
If Len(X) < 4 Then
Exit Function
End If
CopyMemory MakeLong, ByVal X, 4
End Function
Public Function KillNull(ByVal Text As String) As String
Dim i As Integer
i = InStr(1, Text, Chr(0))
If i = 0 Then
KillNull = Text
Exit Function
End If
KillNull = Left(Text, i - 1)
End Function
Public Function StrtoHex(ByVal data As String, Optional addspace As Byte = 0) As String
Dim buffer As String
Dim tmphex As String
Dim i As Integer
For i = 1 To Len(data)
tmphex = Hex(Asc(Mid$(data, i, 1)))
If Val("&H" & tmphex) < 16 Then tmphex = "0" & tmphex
buffer = IIf(addspace = 0, buffer & tmphex & " ", buffer & tmphex)
Next i
StrtoHex = Left$(buffer, Len(buffer) - 1)
End Function
Public Function HexToStr(ByVal Hex1 As String) As String
Dim strTemp As String, strReturn As String, i As Long
Hex1 = Replace(Hex1, " ", "")
If Len(Hex1) Mod 2 <> 0 Then Exit Function
For i = 1 To Len(Hex1) Step 2
strReturn = strReturn & Chr(Val("&H" & Mid(Hex1, i, 2)))
Next i
HexToStr = strReturn
End Function
Public Function MakeDWORD(Value As Long) As String
Dim Result As String * 4
CopyMemory ByVal Result, Value, 4
MakeDWORD = Result
End Function
Public Function MakeWORD(Value As Integer) As String
Dim Result As String * 2
CopyMemory ByVal Result, Value, 2
MakeWORD = Result
End Function
Public Function GetDWORD(data As String) As Long
Dim lReturn As Long
Call CopyMemory(lReturn, ByVal data, 4)
GetDWORD = lReturn
End Function
MAKE SURE YOU UNDERSTAND WHAT THIS CODE IS DOING!!!
Now, when you usually send packets to battle.net, they respond with the exact same packet ID. According to
http://bnetdocs.valhallalegends.com/sequence.php, after sending 0x01, you send 0x50. 0x50 echos back with what I call
hashing data. Hashing data is battle.nets attempt at trying to stop people from creating bots.
Basically, battle.net sends you a bunch of data. In the next packet (0x51), you must send the data back, and battle.net expects it to be passed through a complicated algorithm. There are two main ways to do this.
Use hashes. Hashes are the game files originally used by the actual clients to pass the data through the algorithm. Check out the free hashing library at
http://bncsutil.ionws.com/Or, use BNLS. BNLS is a 3rd party server located at bnls.valhallalegends.com on port 9367. You send the data to them, and they send the "mathimized" data back to you. A packet listing for BNLS is at
http://bnetdocs.valhallalegends.comParsing recieved data in packetsWhen I first started bot programming this is the part I had the most trouble with.
The trick is to only get the parts you need. I dont know anything about doing this in other language than Visual Basic, so that's all I can tell you for non-VB'ers.
In Visual Basic, using the Mid function is the key. For instance lets say the BNCS packet contained one dword. You would use this
CODE
Dim GetData as Long
GetData = GetDword(Mid(PacketData, 5, 4))
The Mid function only takes data starting from the 5th byte 4 bytes over. Using the getdword function we can convert the raw string to a long (dword).Hope this small tutorial gets you on your feet on the world of bot programming.
If you have any questions, dont hesitate to post in this thread!----------------------------------
Good Links:
http://forum.valhallalegends.com [use good grammar here!]
http://bnetdocs.valhallalegends.com [contains login sequence, and all the packets you send]