I used to use local hashing for my bot, until Blizzard implemented lockdown.
So now I'm switching to BNLS. What's the most optimal procedure? I did a search on the forums, and so far the most optimal one I found was by Hdx:
BNCS C->S Protocol Byte: 0x01
BNCS C->S 0x50
BNCS S->C 0x50
If Client.protocol == NLS
BNLS C->S 0x0D
BNLS S->C 0x0D
End If
BNCS S->C 0x25
BNCS C->S 0x25
BNLS C->S 0x1A
BNLS S->C 0x1A
BNLS C->S 0x0C
BNLS C->S 0x51
If Client.protocol != NLS
BNLS C->S 0x0B
BNLS S->C 0x0B
BNCS C->S 0x3A
BNCS S->C 0x3A
Else
BNLS C->S 0x02
BNLS S->C 0x02
BNCS C->S 0x53
BNCS S->C 0x53
BNLS C->S 0x03
BNLS S->C 0x03
BNCS C->S 0x53
BNCS S->C 0x53
BNCS S->C 0x45
End If
If Client.UDPGames == True
BNCS C->S UDP 0x09
BNCS S->C UDP 0x09
BNCS C->S 0x14
End If
BNCS C->S 0x0A
BNCS C->S 0x0B
BNCS C->S 0x0C
What do you think? Is that the most optimal way to go? I apologize for being new to using BNLS. Thanks in advance for any assistance/tips given.
you are not allowed to be new at anything.
For use with BNLS, that is a good method to take.
Which is why I posted it.
Now take note: Thats for games that actually use the SID_AUTH system. For the legacy client's you have to do a little more work.
~Hdx
BNLS_CHOOSENLSREVISION is obsolete. You should implement a client-side cache and retry system based on the data given to you in BNLS_VERSIONCHECKEX2.
Seince when is ChooseNLSRevision Obsolete?
As far sI hae seen, it still defaults to NLSv1 if its no sent.
And notice how I didnt put REQUESTVERSIONBYE in there.
~~(HDX)~-~
In my experimenting with BNLS, it seems to be failing. I've been mainly just focusing on getting the bot to partially use BNLS to see if I can get the bot to work, and if it's successful, I'll rewrite the entire connection code so the bot uses BNLS.
The way my bot works is:
Send 0x01 (Protocol byte)
Send 0x50 (SID_AUTH_INFO)
Recieve 0x50 (SID_AUTH_INFO)
At this point, BNET returns an error saying invalid game version. So I figured it was because of the verbyte, in which case my bot does this:
BNLS.Connect "bnls.valhallalegends.com", "9367"
Then when BNLS accepts the connection, this sub fires:
Private Sub BNLS_Connect()
'BNLS_REQUESTVERSIONBYTE (0x10)
If DebugDisplay = True Then AddC "Sending BNLS_REQUESTVERSIONBYTE (0x10)..."
With PB
.Clear
.InsertDWORD PRODUCT_BROODWAR&
.SendPacket DMBot.BNET, &H10
.Clear
End With
If DebugDisplay = True Then AddC "BNLS_REQUESTVERSIONBYTE (0x10) packet sent."
DoEvents
End Sub
Half-assed code, I know. Then sole intention was to mainly to get the bot working albeit in a half-assed way. Once I was sure it worked, I was going to overhaul the entire connection method to BNLS and eliminate hashing.
The code used to process incoming data from BNLS is:
Private Sub BNLS_DataArrival(ByVal bytesTotal As Long)
Static PktBuff As String 'Packet Buffer
Dim Incoming As String
BNLS.GetData Incoming, vbString, bytesTotal
PktBuff = PktBuff & Incoming
Dim Pkt As BNCSPKT
While Len(PktBuff) > 3
Pkt.intPktLen = GetWord(Mid$(PktBuff, 3, 2))
If Len(PktBuff) < Pkt.intPktLen Then Exit Sub
ParseBNLSPacket (Left(PktBuff, Pkt.intPktLen))
PktBuff = Mid(PktBuff, Pkt.intPktLen + 1)
Wend
End Sub
And the ParseBNLSPacket sub:
Public Sub ParseBNLSPacket(ByVal PacketData As String)
Dim PacketID As Byte
'PacketID = Asc(Mid(PacketData, 2, 1))
PktDeBuf.SetData (PacketData)
PacketID = PktDeBuf.StripHeader
Select Case PacketID
Case &H10 'BNLS_REQUESTVERSIONBYTE
If DebugDisplay = True Then AddC "BNLS: Here's the new version byte."
Dim Trash As Long
Trash = PktDeBuf.rDWORD 'Product ID
VerByte = PktDeBuf.rDWORD
frmOptions.WriteConfig 'Update config.ini with new VerByte
If DebugDisplay = True Then AddC "DMBot: Thanks!"
'Now retry the bnet connection
Call DMBot.BNET.Connect(BNETServer, BNETPort)
Case Else
AddC "Unrecognized Packet ID: 0x" & IIf(Len(Hex(PacketID)) = 1, "0" & Hex(PacketID), Hex(PacketID)) & " (" & GetPacketName(PacketID) & ")"
DumpPacket (PacketData)
End Select
PktDeBuf.ClearData
End Sub
This entire connection method makes use of DarkMinion's PacketBuffer class.
Now, the problem here is; I'm not getting a response from BNLS. I'm sure I just did something stupid and missed something of paramount importance -- is anyone willing to enlighten me?
DMBot.BNET ? maybe use DMBot.BNLS ?
D'oh.
[edit]
Thanks for pointing that out, replaced that part. Still no response:
Quote[4:47:49 PM] DMBot activated.
[4:47:49 PM] Config.ini loaded.
[4:47:49 PM] Ready.
[4:47:54 PM] Debugging enabled.
[4:47:54 PM] You're not connected to BNET!
[4:48:00 PM] Connecting to port 6112 at the uswest.battle.net server...
[4:48:00 PM] Connected!
[4:48:00 PM] Initating packetage...
[4:48:00 PM] Notifying server of emulation...
[4:48:00 PM] 0x01 protocol packet sent.
[4:48:00 PM] Server notification done.
[4:48:00 PM] Assembling 0x50 Protocol packet...
[4:48:00 PM] 0x50 SID_AUTH_INFO packet sent.
[4:48:00 PM] BNET: Ping?
[4:48:00 PM] Assembling 0x25 SID_PING Packet...
[4:48:00 PM] 0x25 SID_PING packet sent.
[4:48:00 PM] DMBot: Pong!
[4:48:00 PM] BNET: Gimme your cdkey.
[4:48:00 PM] Assembling 0x51 SID_AUTH_CHECK Packet...
[4:48:00 PM] 0x51 SID_AUTH_CHECK packet sent.
[4:48:00 PM] DMBot: Blah blah. There ya go. Happy?
[4:48:00 PM] BNET: Well...
[4:48:00 PM] BNET: Nope. Invalid game version. Bye.
[4:48:00 PM] Server aborted connection!
[4:48:00 PM] Sending BNLS_REQUESTVERSIONBYTE (0x10)...
[4:48:00 PM] BNLS_REQUESTVERSIONBYTE (0x10) packet sent.
Hrmmm... I'm going to do some more research, see what I'm doing wrong or what needs to be updated.
[edit]
I just read up on the 0x51 packet (C->S) at BNetDocs (http://"http://bnetdocs.valhallalegends.com/content.php?Section=m&Code=4") and from IIRC, the lockdown affected the 0x51 since it no longer uses the files for hashing. I'm going to read up on the BNLS specs and see if there's an alternative to local hashing.
For now, any idea why BNLS isn't responding? Is there an appropriate connection procedure I have to perform prior to making any requests from BNLS?
[edit]
Yes, I know. Alot of edits. Anyway, I'm such an idiot. I just realized that the VerByte hasn't changed -- and that the game version has absolutely nothing to do with the VerByte (if the problem was the VerByte, bnet'd have said so IE (game needs to be upgraded, or invalid verbyte). Sooo.... Back to researching.
For one thing, you're not sending BNLS_VERSIONCHECKEX2 like you should, and once again REQUESTVERSIONBYTE is not needed, you get it in VERIONCHECKEX2
Why don't you try following the protocol that you quoted in the 1st post?
Also, BNLS headers != BNET Headers. So you will need to change the SendPacket function.
~-~(HDX)~-~
What the- they aren't the same? Damn, I need to do alot of research. Okay, I just looked over the bnetdocs, and found the header information for BNLS:
QuoteBNLS Headers
BNLS is the Battle.Net Logon Server, and can be used by bot authors to perform some of the computational tasks required during a Battle.net logon. It also allows bot authors to obtain useful information such as the current version byte for a game client, and has provisions for BNCS server emulator authors. It has the following headers:
(WORD) Message Length, including this header
(BYTE) Message ID
(VOID) Message Data
By message length, does it start from the message length all the way to the end of the message data? Is the BNLS protocol same for both sending and receiving?
[Edit]
Instead of asking like a newbie, I'll just do it and find out if it works or not. Quick question though, will BNLS ban me for malformed packets, or requesting packets out of order?
They aren't the same, no. The message length is the whole message length, just like the length in a BNCS packet. An easy way to do it is the Length of the data + 3 (2 for the word, 1 for the byte). Same protocol both ways, always.
Edit: BNLS will just disconnect you.
Good to hear. Thanks.
Okay, I'm still getting stuck. I've re-coded it to be compatiable with BNLS, and yet it keeps failing. This is the console output:
QuoteReady.
Username set.
Password set.
GameCode set to SEXP.
CDKey set.
Missing VerByte, now accquiring new VerByte.
Connecting to BNLS...
Connected to BNLS.
0x10 BNLS_REQUESTVERSIONBYTE packet sent.
Sockets closed.
Disconnected.
This is my On BNLS Connect sub:
Private Sub sckBNLS_Connect()
RaiseEvent DebugOutput("Connected to BNLS.")
If m_VerByte = "" Then
'missing verbyte
BNLS_REQUESTVERSIONBYTE
End If
End Sub
This is the BNLS_REQUESTVERSIONBYTE sub:
Public Sub BNLS_REQUESTVERSIONBYTE() '0x10
Dim ProductID As Long
Select Case UCase(GameCode)
Case "SEXP"
ProductID = PRODUCT_BROODWAR&
Case "STAR"
ProductID = PRODUCT_STARCRAFT&
Case "D2DV"
ProductID = PRODUCT_DIABLO2&
Case "D2XP"
ProductID = PRODUCT_LORDOFDESTRUCTION&
Case "WAR3"
ProductID = PRODUCT_WARCRAFT3&
Case "W3XP"
ProductID = PRODUCT_FROZENTHRONE&
Case Else
RaiseEvent sError("Unsupported game type.")
Disconnect
Exit Sub
End Select
With PacketBuf
.Clear
.InsertDWORD ProductID 'Product ID
.SendBNLSPacket sckBNET, &H10 'Send 0x10 packet
.Clear
End With
RaiseEvent DebugOutput("0x10 BNLS_REQUESTVERSIONBYTE packet sent.")
End Sub
This is my BNLS DataArrival sub:
Private Sub sckBNLS_DataArrival(ByVal bytesTotal As Long)
Static PktBuff As String 'Packet Buffer
Dim Incoming As String
sckBNLS.GetData Incoming, vbString, bytesTotal
PktBuff = PktBuff & Incoming
Dim Pkt As BNCSPKT
While Len(PktBuff) > 3
Pkt.intPktLen = GetWord(Mid$(PktBuff, 0, 2))
If Len(PktBuff) < Pkt.intPktLen Then Exit Sub
ParseBNLSPacket (Left(PktBuff, Pkt.intPktLen))
PktBuff = Mid(PktBuff, Pkt.intPktLen + 1)
Wend
End Sub
This is my BNLS parser sub:
Public Sub ParseBNLSPacket(ByVal PacketData As String)
Dim PacketID As Byte
Dim PacketLen As Long
PktDeBuf.SetData (PacketData)
PacketLen = PktDeBuf.rWORD()
PacketID = PktDeBuf.rBYTE()
Select Case PacketID
Case &H10 'BNLS_REQUESTVERSIONBYTE
RaiseEvent DebugOutput("Recieved new VerByte from BNLS.")
Dim Trash As Long
Trash = PktDeBuf.rDWORD 'Product ID
VerByte = PktDeBuf.rDWORD
RaiseEvent DebugOutput(HexToString(VerByte))
'Now retry the bnet connection
'Call DMBot.BNET.Connect(BNETServer, BNETPort)
Case Else
AddC "Unrecognized Packet ID: 0x" & IIf(Len(Hex(PacketID)) = 1, "0" & Hex(PacketID), Hex(PacketID)) & " (" & GetPacketName(PacketID) & ")"
DumpPacket (PacketData)
End Select
PktDeBuf.ClearData
End Sub
The intended goal was to get the program to raise the Event DebugOutput while passing along the verbyte as a string. For example, if CD was the verbyte, it'd change that from hex to string, so it'd display as "CD". But from what it looks like, it sends the 0x10 packet, then fails after that point. I think I screwed up somewhere, but I can't find the problem. Any ideas?
Pkt.intPktLen = GetWord(Mid$(PktBuff, 0, 2))
Mid$() starts at 1, not 0, consider using:
Pkt.intPktLen = GetWord(Left$(PktBuff, 2))
Thanks for the tip. Tried it. I still don't see any incoming data...
I did some debugging, and from what it appears, the BNLS data arrival sub isn't even being run. I'd say that seems to indicate that I'm not getting a response from the BNLS server.
Maybe my 0x10 packet is malformed?
Or maybe BNLS requires a specific sequence of packets before I can send any other packets? Or is it possible to just connect to BNLS and immediately request verbyte without doing any other packets?
BNLS has absolutely no packet order requirements. post a packet log of your send to bnls?
Quote from: Kyro on February 10, 2007, 04:01 PM
Okay, I'm still getting stuck. I've re-coded it to be compatiable with BNLS, and yet it keeps failing. This is the console output:
This is my On BNLS Connect sub:
Private Sub sckBNLS_Connect()
RaiseEvent DebugOutput("Connected to BNLS.")
If m_VerByte = "" Then
'missing verbyte
BNLS_REQUESTVERSIONBYTE
End If
End Sub
Just wondering why Verbyte is treated as a string and not a long?
Quote from: Mystical on February 10, 2007, 09:04 PM
Quote from: Kyro on February 10, 2007, 04:01 PM
Okay, I'm still getting stuck. I've re-coded it to be compatiable with BNLS, and yet it keeps failing. This is the console output:
This is my On BNLS Connect sub:
Private Sub sckBNLS_Connect()
RaiseEvent DebugOutput("Connected to BNLS.")
If m_VerByte = "" Then
'missing verbyte
BNLS_REQUESTVERSIONBYTE
End If
End Sub
Just wondering why Verbyte is treated as a string and not a long?
why would it be a long... it's a verBYTE. a byte value.
Kinda stupid but what do your constants looks like?
My bot allows the user to give a string value, which in turn will be converted into a long value. See below. It should answer your question.
Public Sub SID_AUTH_INFO() '0x50
If Ready = False Then
RaiseEvent sError("Error! Missing data!")
RaiseEvent sError("Connection aborted locally.")
Disconnect
Else
With PacketBuf
.Clear
.InsertDWORD &H0 'BNET Protocol ID (Currently zero.)
.InsertDWORD CLng("&H" & Replace(StrToHex("IX86"), " ", vbNullString)) 'IX86
.InsertDWORD CLng("&H" & Replace(StrToHex(m_GameCode), " ", vbNullString)) 'SEXP
[b][i].InsertDWORD CLng("&H" & m_VerByte) 'Verbyte, changes with product upgrade.[/b][/i]
.InsertDWORD CLng("&H" & Replace(StrToHex("enUS"), " ", vbNullString)) 'Product Language
.InsertDWORD CLng("&H" & Replace(StrToHex(IP2NBO(sckBNET.LocalIP)), " ", vbNullString)) 'Local IP for NAT compatibility
.InsertDWORD GetTimeZoneBias 'Time Zone bias
.InsertDWORD GetUserDefaultLCID() 'Locale ID
.InsertDWORD GetUserDefaultLangID 'Language ID
.InsertNTString GetInfo(LOCALE_SABBREVCTRYNAME) 'Abbrev. of country
.InsertNTString GetInfo(LOCALE_SENGCOUNTRY) 'Name of country
.SendPacket sckBNET, &H50 'Send 0x50 packet
.Clear
.InsertDWORD &H0 '0ms ping.
.SendPacket DMBot.BNET, &H25 'Send 0x25 packet
.Clear
End With
RaiseEvent DebugOutput("0x50 SID_AUTH_INFO packet sent.")
End If
End Sub
Edit:
As for the constants, here...
' PacketID Constants for Visual Basic
' Generated by BnetDocs on 10/02/07 02:13:14
' BnetDocs software written by Arta
' Content compiled by Arta & Skywing
' Visit us on Battle.net in channel Op [vL]
Public Const PRODUCT_STARCRAFT& = &H1
Public Const PRODUCT_BROODWAR& = &H2
Public Const PRODUCT_WAR2BNE& = &H3
Public Const PRODUCT_DIABLO2& = &H4
Public Const PRODUCT_LORDOFDESTRUCTION& = &H5
Public Const PRODUCT_JAPANSTARCRAFT& = &H6
Public Const PRODUCT_WARCRAFT3& = &H7
Public Const PRODUCT_FROZENTHRONE& = &H8
post a packet log..
I will as soon as I can figure out how to get WireShark to packet log. I'm a newbie to packet logging. I just installed it, and haven't the foggest idea as to how to configure it to only display BNLS and BNET packets...
Tried searching for a tutorial for specificially BNLS/BNET packet logging pertaining to WireShark/Etheral, no such luck...
why not just use WPE...? it makes quick things like that a lot easier...
linky if ya need it (http://realityripple.com/Uploads/WPE.zip) (note that some anti-viruses think the dll is a trojan, since it sniffs packets... it's not a trojan, nor really a false positive, since it does sniff packets. you just happen to be the one that sees the packets.)
Hrmmmm... I'm having the same problems as Etheral/Wireshark, and Commview.
Which is: it seems to be logging nothing. Let me compile it as an exe, and try again.
Hmm... That's strange, nothing.
So that seems to imply there is nothing being sent... wtf... I'm going to look at my code and see why this innate drivel isn't working.
--------
Edit:
I just looked at my code. This is the 0x10 sub:
Public Sub BNLS_REQUESTVERSIONBYTE() '0x10
Dim ProductID As Long
Select Case UCase(GameCode)
Case "SEXP"
ProductID = PRODUCT_BROODWAR&
Case "STAR"
ProductID = PRODUCT_STARCRAFT&
Case "D2DV"
ProductID = PRODUCT_DIABLO2&
Case "D2XP"
ProductID = PRODUCT_LORDOFDESTRUCTION&
Case "WAR3"
ProductID = PRODUCT_WARCRAFT3&
Case "W3XP"
ProductID = PRODUCT_FROZENTHRONE&
Case Else
RaiseEvent sError("Unsupported game type.")
Disconnect
Exit Sub
End Select
With PacketBuf
.Clear
.InsertDWORD ProductID 'Product ID
.SendBNLSPacket sckBNET, &H10 'Send 0x10 packet
.Clear
End With
RaiseEvent DebugOutput("0x10 BNLS_REQUESTVERSIONBYTE packet sent.")
End Sub
And this is the SendBNLSPacket sub in the PacketBuffer class:
Public Function SendBNLSPacket(sck As Winsock, Optional PacketID As Long) As Boolean
If sck.State = sckConnected Then
sck.SendData MakeWORD(Len(Buffer) + 4) & Chr(PacketID) & Buffer
End If
Clear
End Function
And the name of the socket for BNLS is sckBNLS...
erm... the length is +3, not +4. A word is 2 bytes, plus 1 byte for the ID.
Oops, thanks for pointing that out. Corrected that one.
But that still doesn't solve the fact the program isn't transmitting data. I mean, consider:
In order for BNLS to be sending me data, it must first recieve data. I've been able to confirm that the program successfully connects to BNLS, but beyond that, the program seems to fail in transmitting data to BNLS. I don't understand why it's not sending -- all of the code seems intact...
second problem
.SendBNLSPacket sckBNET, &H10 'Send 0x10 packet
shouldn't you be using sckBNLS? you really need to keep track of things like this better.
Finally. It works. Thanks RealityRipple, and everyone else who helped. I appreciate it.
Jeez. I'm blind. I could've swore I typed BNLS, not BNET. You're right, I really need to pay attention to what I'm typing and where it goes...
Any idea how I can take a byte variable and display it as a string? For instance, if I get 0x10 from BNLS, it comes in vb as &H10. Is there a way I can take this hex and convert it directly into a string ("0x10")?
I tried this:
RaiseEvent DebugOutput("Identified as: " & CStr(PacketID))
But it came out as 16, not 10. Any tips?
"Identified as 0x" & Hex$(PacketID)
Ah, simple. Works like a charm:
QuoteReady.
Username set.
Password set.
GameCode set to SEXP.
CDKey set.
Missing VerByte, now accquiring new VerByte.
Connecting to BNLS...
Connected to BNLS.
0x10 BNLS_REQUESTVERSIONBYTE packet sent.
Receiving incoming data...
Parsing BNLS packet...
Identified as 0x10
Recieved new VerByte from BNLS.
VerByte set: CF
Sockets closed.
Disconnected.
Many thanks. :-)
Quote from: [RealityRipple] on February 10, 2007, 09:37 PM
why would it be a long... it's a verBYTE. a byte value.
Because the Battle.net protocol sends it as a 32-bit value, not an 8-bit value.
This is most likely due to greater efficiency in reading and writing data that is aligned to the native word size of the processor.
That's why you do CLng(Config.VerByte). You define the variable as a byte because it's more efficient to have a byte variable than a long variable. Then when you need to send it, you send it as a long.
Quote from: [RealityRipple] on February 11, 2007, 12:37 AM
That's why you do CLng(Config.VerByte). You define the variable as a byte because it's more efficient to have a byte variable than a long variable. Then when you need to send it, you send it as a long.
Until a version byte exceeds 0xFF, and your program hits a problem ;)
oh noes, i'll have to set it to an int and release an update. how terrible. everyone else will also have to stop calling them verbytes then, too.
I think you just like to argue with people, but wouldn't you mean CByte(Config.Verbyte) if you want it to be a byte? CLong() would be converting it to a long?
CLng Function:
CLng(expression)
Converts the value of expression to a Long data type. The argument expression must be a numeric value from -2,147,483,648 to 2,147,483,647. Fractions are rounded.
Cbyte Function:
CByte(expression)
Converts the value of expression to a Byte data type. The argument expression must be a numeric value between 0 and 255.
that's the point... Config.VerByte is defined as a byte for less memory usage. the InsertDWORD requires a long, so you do CLng(Config.VerByte). and yes, I have a VERY argumentative nature.
Or if you're using an even half-decent packet buffer you call your uint_32 insertion on the Config.VerByte and the procedure automatically converts it.