Valhalla Legends Forums Archive | Battle.net Bot Development | BNet Chat bot?

AuthorMessageTime
Ozzapoo
Hi, is there any working tutorial on how to create a simple chat bot using VB.NET/VB6?

Also,

Warcraft III
SEND -> SID_AUTH_INFO (0x50)
RECV <- SID_PING (0x25)
RECV <- SID_AUTH_INFO (0x50)
SEND -> SID_PING (0x25) (Optional)
SEND -> SID_AUTH_CHECK (0x51)
RECV <- SID_AUTH_CHECK (0x51)
SEND -> SID_AUTH_ACCOUNTLOGON (0x53)
RECV <- SID_AUTH_ACCOUNTLOGON (0x53)
SEND -> SID_AUTH_ACCOUNTLOGONPROOF (0x54)
RECV <- SID_AUTH_ACCOUNTLOGONPROOF (0x54)
SEND -> SID_NETGAMEPORT (0x45)
SEND -> SID_ENTERCHAT (0x0A)

In order to send the 'SID_AUTH_INFO' packet, for example, do I simply send a buffer with the information? Or do I have to send something like 0x50 first?
November 5, 2008, 8:35 AM
Myndfyr
There's a packet header format described here for sending messages - yes, you need to send the packet ID as part of the header.

If you're using VB.NET and aren't married to doing the packet processing yourself, you can grab BN#, which is a library I've been working on (documentation's here, and tutorial).  It's not quite complete but it's very usable for .NET developers.  It's not supported for VB6.

November 5, 2008, 4:25 PM
Ozzapoo
Well if I wanted to send SID_AUTH_INFO, then which type of header would I use? 'BNCS', Realm, D2GS, Botnet, BNLS, WC3 Ingame or Storm?
November 5, 2008, 8:07 PM
HdxBmx27
Seince you're connecting to the Battle.Net Chat Server...... I don't know.
Anything SID_ is BNCS
November 5, 2008, 8:22 PM
Ozzapoo
How do I send 'IX86' as a DWORD? Isn't it a string?
November 10, 2008, 5:53 AM
BreW
[quote author=Ozzapoo link=topic=17704.msg180335#msg180335 date=1226296388]
How do I send 'IX86' as a DWORD? Isn't it a string?
[/quote]
no?
isn't it 'IX86' (single quote marks intended) for a reason?
insert it as you would any other 32 bit value: InsertDWORD('IX86');
November 10, 2008, 5:57 AM
Ozzapoo
InsertDword()?

I'm using VB.Net for this.. =/
I'm not sure what is meant by the single-quotes, so do you care to explain?
November 10, 2008, 6:21 AM
BreW
Yeah, i was just showing you some example usage.
Also, sorry about the single quotes thing, since you're using VB .NET i'm not sure if single quotes work for numerical constants. try converting the value IX86 to hexidecimal and insert it into your packet as you would a 32 bit number such as 1, or 40.
November 10, 2008, 6:25 AM
Barabajagal
&H49583836
November 10, 2008, 6:27 AM
Ozzapoo
Andy, is there a way I can get the using VB.NET?
November 10, 2008, 6:30 AM
Barabajagal
uh... 0x49583836? I don't know how .NET denotes hex.
November 10, 2008, 7:31 AM
Ozzapoo
Nevermind, I figured it out anyway. Uh...

(DWORD) Product language
(DWORD) Local IP for NAT compatibility*
(DWORD) Time zone bias*
(DWORD) Locale ID*
(DWORD) Language ID*


Can these fields really safely be set to zero? I tried send a packet and had all thse fields as 0, but I didn't get a response from Battle.Net. However, when I connected using Stealthbot and captured the packets, some of the fields weren't 0 and it DID receive a response from Battle.net. Here is the captured data for comparison between my packet and the one sent by StealthBot.

EDIT: I tried to match it even more, but Battle.Net still won't give me a response
My Packet
[code]0000  00 17 9a 1d e6 67 00 1d  e0 52 ca 73 08 00 45 00   .....g.. .R.s..E.
0010  00 62 6f 7c 40 00 80 06  ed 1c 0a 01 01 03 3f f1   .bo|@... ......?.
0020  53 08 ee 66 17 e0 22 1d  9b f4 5b a2 e3 82 50 18   S..f..". ..[...P.
0030  42 30 c3 a0 00 00 ff 50  3a 00 00 00 00 00 36 38   B0.....P :.....68
0040  58 49 33 52 41 57 16 00  00 00 00 00 00 00 00 00   XI3RAW.. ........
0050  00 00 6c fd ff ff 09 0c  00 00 09 0c 00 00 55 53   ..l..... ......US
0060  41 00 55 6e 69 74 65 64  20 53 74 61 74 65 73 00   A.United  States.[/code]
SB Packet
[code]
0000  00 17 9a 1d e6 67 00 1d  e0 52 ca 73 08 00 45 00   .....g.. .R.s..E.
0010  00 62 70 14 40 00 80 06  ec 84 0a 01 01 03 3f f1   .bp.@... ......?.
0020  53 08 ee 73 17 e0 87 b5  09 f4 a6 cf ec c8 50 18   S..s.... ......P.
0030  42 30 9b 88 00 00 ff 50  3a 00 00 00 00 00 36 38   B0.....P :.....68
0040  58 49 33 52 41 57 16 00  00 00 00 00 00 00 00 00   XI3RAW.. ........
0050  00 00 6c fd ff ff 09 0c  00 00 09 0c 00 00 55 53   ..l..... ......US
0060  41 00 55 6e 69 74 65 64  20 53 74 61 74 65 73 00   A.United  States.[/code]

EDIT: Here's the full info:

http://pastebin.com/f7431517d <-My packet
http://pastebin.com/f57167bd4 <-SB Packet
November 10, 2008, 8:20 AM
Myndfyr
Did you initiate the connection with a binary byte of 1?

[code]Dim protocolID() As New Byte(1)
protocolID(0) = 1
sck.Send(protocolID)[/code]

I'm going to throw this out there - and you can ignore it if you like, but it'll save you a lot of headache.  If you're going to push through writing your own binary connection, I'd highly suggest utilizing MBNCSUtil.  It's written in C#, so it's completely compatible with your VB.NET code, it uses the standards set within the .NET runtime, and it's going to save you headache (for example, for converting those strings/32-bit integer values such as 'IX86').  It's also highly optimized for memory and does all the authentication math, as you opt-in to its features.

At the very least, consider using or porting its DataBuffer and DataReader classes - these will let you create outgoing data and read incoming data packets much more easily than doing the binary operations by hand or by rolling your own.  And I guarantee they're a lot more correct than some of the other stuff you might find here (and yes, I'm aware that two of those were my own).  It's open-source under the BSD license (generally).

Do what you will, I'm not trying to advertise a product.  I'm just trying to avoid headache for you and for the rest of us. :)
November 10, 2008, 1:16 PM
Ozzapoo
Thanks! I completely forgot to send the first byte >.<
I'll try that. And I'll also try your library if I have any more headaches :P

EDIT: W00T! It worked!

EDIT: o.o The MBNCSUtil is pretty nice, I'm gonna use it :D

EDIT: Uh...How can I get the Client token? Do I have to use BNLS or can MBNCSUtil generate it for me? Oh wait...Can ClientToken be any random value?
November 10, 2008, 6:47 PM
Barabajagal
Client token is generated by the client.
November 11, 2008, 6:52 AM
Ozzapoo
But I don't get how I'm supposed to generate it =/

Also, in SID_AUTH_CHECK, when It refers to 'EXE Version' and 'EXE Hash', what file is EXE? The hash exe file?
November 11, 2008, 6:53 AM
Barabajagal
GetTickCount works... or 123456... or anything you want. When I say it's generated by the client, I mean it. It can be any value from 0x00000000 to 0xFFFFFFFF.

And yes. The EXE file. Doesn't MBNCSUtil do that for you?
November 11, 2008, 8:00 AM
Ozzapoo
Alright, I got it, but when I try to get the 'Key Private' using MBNCSUtils, it returns a 10-byte array, but it's supposed to fit in a DWORD?

Also, in SID_AUTH_CHECK, is '(DWORD) [5] Hashed Key Data' supposed to have the values hashed using the 'Broken SHA-1' thing?
November 11, 2008, 9:05 AM
BreW
Warcraft 3 style CDKeys have a 10 byte private value instead.
The array of 5 dwords in SID_AUTH_CHECK is the resulting 20-byte (suprise!) hash of the cdkey values and the tokens.
November 11, 2008, 4:50 PM
Myndfyr
[quote author=Ozzapoo link=topic=17704.msg180376#msg180376 date=1226394314]
Alright, I got it, but when I try to get the 'Key Private' using MBNCSUtils, it returns a 10-byte array, but it's supposed to fit in a DWORD?

Also, in SID_AUTH_CHECK, is '(DWORD) [5] Hashed Key Data' supposed to have the values hashed using the 'Broken SHA-1' thing?
[/quote]
You don't actually use the private for anything though.  You'd use .Product and .Value1 on the CdKey object.

Yes, hashed key data is the 20-byte hash returned by cdKey.GetHash(clientToken, serverToken).  It does not need to be converted to integers first; you can simply insert the byte array using .InsertByteArray() if you're using the DataBuffer/BncsPacket classes.
November 11, 2008, 5:27 PM
Ozzapoo
So I can just use CdKey.GetHash(ClientToken,ServerToken) and put that result as the [5] DWords?
November 11, 2008, 7:44 PM
Ribose
Yeah,
C#:
[code]CdKey key = new CdKey(variablecontainingkeyasstring);
byte[] hash = key.GetHash(clientToken, serverToken);
...
packet.InsertByteArray(hash);[/code]
VB.Net:
[code]Dim key As CdKey = New CdKey(variablecontainingkeyasstring)
Dim hash() As Byte = key.GetHash(clientToken, serverToken)
...
packet.InsertByteArray(hash)[/code]
November 11, 2008, 7:51 PM
Myndfyr
[quote author=Ribose link=topic=17704.msg180381#msg180381 date=1226433100]
Yeah,
C#:
[code]CdKey key = new CdKey(variablecontainingkeyasstring);
byte[] hash = key.GetHash(clientToken, serverToken);
...
packet.InsertByteArray(hash);[/code]
VB.Net:
[code]Dim key As CdKey = New CdKey(variablecontainingkeyasstring)
Dim hash As Byte() = key.GetHash(clientToken, serverToken)
...
packet.InsertByteArray(hash)[/code]
[/quote]
Actually for VB it'd be:
[code]
Dim hash() As Byte = ...
[/code]
November 11, 2008, 8:04 PM
Ribose
Edited, then.
November 11, 2008, 8:42 PM
Ozzapoo
Wait hold on...
(DWORD) [5] Hashed Key Data
Shouldn't that be 24 bytes? Or is the [5] the length?
November 12, 2008, 6:30 AM
Myndfyr
[quote author=Ozzapoo link=topic=17704.msg180387#msg180387 date=1226471440]
Wait hold on...
(DWORD) [5] Hashed Key Data
Shouldn't that be 24 bytes? Or is the [5] the length?
[/quote]
A DWORD is four bytes long.  5 is the length of the array.  5 time 4 is 20.  Therefore the correct number of bytes is 20.
November 12, 2008, 7:11 AM
Ozzapoo
[quote]The data that should be hashed for 'Hashed Key Data' is:
Client Token
Server Token
Key Product (from decoded CD key)
Key Public (from decoded CD key)
(DWORD) 0
Key Private (from decoded CD key)[/quote]
Then why are there six values to hash?
November 12, 2008, 7:18 AM
HdxBmx27
You shove all those into a xSHA-1, and the digest is the 5 dwords you send.
You can have unlimited ammounts of data in a SHA1 hash, and the digest will always be 20 bytes
November 12, 2008, 7:27 AM
Ozzapoo
Arlight....Well I think I got the basics right, but now when I connect it gives me the old product version error -.-

P.S. Hdx, congrats on 1000th post! :D
November 12, 2008, 7:31 AM
HdxBmx27
Logs. And you sure your performing the check revision correctly?
November 12, 2008, 7:33 AM
Myndfyr
[quote author=Ozzapoo link=topic=17704.msg180391#msg180391 date=1226475098]
Arlight....Well I think I got the basics right, but now when I connect it gives me the old product version error -.-
[/quote]
Um... update your game files and verbyte?  :P  Old version != invalid version!  Old version is very specific.

[quote author=Ozzapoo link=topic=17704.msg180389#msg180389 date=1226474310]
[quote]The data that should be hashed for 'Hashed Key Data' is:
Client Token
Server Token
Key Product (from decoded CD key)
Key Public (from decoded CD key)
(DWORD) 0
Key Private (from decoded CD key)[/quote]
Then why are there six values to hash?
[/quote]
These are the values that get fed into the hashing algorithm.  The hashing algorithm produces a 20-byte (5 DWORD) value that is inserted into the outgoing data buffer.

If you're using MBNCSUtil, the CdKey.GetHash(clientToken, serverToken) method handles doing all that legwork for you - you just need to provide the client and server tokens.
November 12, 2008, 8:09 AM
Ozzapoo
>.< I forgot to do all this stuff...Because I must have thought the GetHash() thing included it >.<

[quote]For Each Key:
(DWORD) Key Length
(DWORD) CD-key's product value
(DWORD) CD-key's public value
(DWORD) Unknown (0)[/quote]

But yeah....Then I thought I fixed it but I got Invalid Cd Key instead -.-"
I think it's because I stuffed up again and forgot t include the Unknown value... Well I'm going to try again.

EDIT: I think it's working now! (At least 'CD Key in use' is working...) I'm going to test it a bit more.
EDIT: Yeah, it definitely works. Time to go onto SID_AUTH_ACCOUNTLOGON! :D
EDIT: W00T!!!!!! It's entered chat! =D

EDIT: Uh oh...Problem.

Right now, I have it set up using a System.Net.Sockets.TcpListener object and a NetworkStream object. And it works like this:
Stream.Write(bnetpacket,0,bnetpacket.Length)
Stream.Read(<some variable>,0,<something>)

But in this, it expects a response to everything. However, I'm stuck on how I'm supposed to make my application respond to every packet that Bnet sends me... I'm not sure how I can detect a packet when Bnet sends it and respond to it. Is there something else that I need to do? Please help >.<
November 12, 2008, 8:21 AM
Myndfyr
The way that BN# does it is to have a single thread that simply sits on a Read() loop (the thread will block as long as Read() is waiting).  Writes are always done on-demand by another thread.
November 12, 2008, 4:58 PM
Ozzapoo
Alright...So will a BackgroundWorker Object do the job?
Aand...I don't quite understand what the 'padding' parameter is in ReadDwordString()..
November 12, 2008, 7:16 PM
Myndfyr
[quote author=Ozzapoo link=topic=17704.msg180406#msg180406 date=1226517375]
Alright...So will a BackgroundWorker Object do the job?
Aand...I don't quite understand what the 'padding' parameter is in ReadDwordString()..
[/quote]BackgroundWorker will work fine.

The Padding parameter is a character to strip out in the event that the value isn't four bytes long.  For example, clan tags are written as integers that might not have four characters.  There was another situation in the protocol, I don't remember where, that used 0x0d as a padding character.

Generally using 0 as the parameter is adequate.
November 12, 2008, 10:01 PM
Ozzapoo
Alright I've pretty much got it. Just a small problem now...The background worker doesn't work quick enough to detect all packets when you do something like '/f list'...Which can send up to 26 packets at once.

My current code for the Sub is as follows:
[code]    Sub DetectIncoming()
        Dim rec(bnetClient.ReceiveBufferSize) As Byte
        Dim bnetStream As NetworkStream = bnetClient.GetStream()
        Do
            ReDim rec(bnetClient.ReceiveBufferSize)
            bnetStream.Read(rec, 0, rec.Length)
            If rec(1) = &HF Then
                Dim packetreader As New BncsReader(rec)
                Dim eventid As Int32 = packetreader.ReadInt32()
                Dim userflags As Int32 = packetreader.ReadInt32()
                Dim ping As Int32 = packetreader.ReadInt32()
                packetreader.ReadInt32()
                packetreader.ReadInt32()
                packetreader.ReadInt32()
                Dim username As String = packetreader.ReadCString()
                Dim text As String = packetreader.ReadCString()
                Select Case eventid
                    Case &H2
                        Console.WriteLine("-INFO- User " + username + " has joined the channel.")
                    Case &H3
                        Console.WriteLine("-INFO- User " + username + " has left the channel.")
                    Case &H4
                        Console.WriteLine("<" + username + "> has whispered: " + text)
                    Case &H5
                        Console.WriteLine("<" + username + "> " + text)
                    Case &H6
                        Console.WriteLine("-BROADCAST- " + text)
                    Case &H7
                        Console.WriteLine("-JOINED CHANNEL- " + text)
                    Case &H9
                        Console.WriteLine("User Flags Update: " + text)
                    Case &HA
                        Console.WriteLine("-WHISPER SENT-")
                    Case &HD
                        Console.WriteLine("Error! Channel Full!")
                    Case &HE
                        Console.WriteLine("Error! Channel does not exist!")
                    Case &HF
                        Console.WriteLine("Error! Channel is restricted!")
                    Case &H12
                        Console.WriteLine("-INFORMATION- " + text)
                    Case &H13
                        Console.WriteLine("Error! " + text)
                    Case &H17
                        Console.WriteLine("-INFO- Emote Used by " + username)
                End Select
            ElseIf rec(1) = &H0 Then
                SendNull(bnetStream)
            End If
        Loop
    End Sub[/code]
What should I do to fix it?
November 13, 2008, 6:52 AM
HdxBmx27
Why are you not splitting the packets based on length? {Remember the BNCS Header 0xFF ID (word)Length}
The problem you're getting multiple packets at once when you do recv.
Also, switch ftw
November 13, 2008, 7:38 AM
Ozzapoo
[quote author=Hdx link=topic=17704.msg180414#msg180414 date=1226561889]
Why are you not splitting the packets based on length? {Remember the BNCS Header 0xFF ID (word)Length}
The problem you're getting multiple packets at once when you do recv.
Also, switch ftw
[/quote]
Is the length always static?
Any suggestions on how I can fix it :(?
What's "switch"?
November 13, 2008, 8:07 AM
HdxBmx27
err its select case in vb
No the length is not always static, hence why its part of the header....
{AE read the 1st byte if its not oxff its not a real bncs packet, read the next one, thats the id, read the next two, thats the length, read the next X where X was the previous word}
November 13, 2008, 8:10 AM
Ozzapoo
Wait, are you saying I should only use the stream to read the first 4 bytes (the header) and then read however much is left? Will it reduce the amount of time needed, as right now it's the ReceivedBufferSize property or something and there are LOTS of null bytes in the output.

[quote]The problem you're getting multiple packets at once when you do recv.[/quote]
Wait...You mean if I read too much at a time I might read two packets at once?

EDIT: Had a go at making some changes...But it still screws up and now I have no idea what's wrong.

[code]    Sub DetectIncoming()
        Dim rec1() As Byte
        Dim rec(bnetClient.ReceiveBufferSize) As Byte
        Dim header(3) As Byte
        Dim bnetStream As NetworkStream = bnetClient.GetStream()
        Do

            ReDim header(3)
            Dim packetsize As Integer
            bnetStream.Read(header, 0, 4)
            If header(0) = &HFF Then

                packetsize = BitConverter.ToInt16(header, 2)

            Else
                Continue Do
            End If
            ReDim rec1(packetsize - 4) 'Error: Arithmetic operation resulted in an overflow. <----------------------------ERROR!!
            bnetStream.Read(rec1, 0, rec1.Length)
            ReDim rec(packetsize)
            rec = ConcatenateByteArray(header, rec1)

            If rec(1) = &HF Then
                Dim packetreader As New BncsReader(rec)
                Dim eventid As Int32 = packetreader.ReadInt32()
                Dim userflags As Int32 = packetreader.ReadInt32()
                Dim ping As Int32 = packetreader.ReadInt32()
                packetreader.ReadInt32()
                packetreader.ReadInt32()
                packetreader.ReadInt32()
                Dim username As String = packetreader.ReadCString()
                Dim text As String = packetreader.ReadCString()
                Select Case eventid
                    Case &H2
                        Console.WriteLine("-INFO- User " + username + " has joined the channel.")
                    Case &H3
                        Console.WriteLine("-INFO- User " + username + " has left the channel.")
                    Case &H4
                        Console.WriteLine("<" + username + "> has whispered: " + text)
                    Case &H5
                        Console.WriteLine("<" + username + "> " + text)
                    Case &H6
                        Console.WriteLine("-BROADCAST- " + text)
                    Case &H7
                        Console.WriteLine("-JOINED CHANNEL- " + text)
                    Case &H9
                        Console.WriteLine("User Flags Update: " + text)
                    Case &HA
                        Console.WriteLine("-WHISPER SENT-")
                    Case &HD
                        Console.WriteLine("Error! Channel Full!")
                    Case &HE
                        Console.WriteLine("Error! Channel does not exist!")
                    Case &HF
                        Console.WriteLine("Error! Channel is restricted!")
                    Case &H12
                        Console.WriteLine("-INFORMATION- " + text)
                    Case &H13
                        Console.WriteLine("Error! " + text)
                    Case &H17
                        Console.WriteLine("-INFO- Emote Used by " + username)
                End Select
            ElseIf rec(1) = &H0 Then
                SendNull(bnetStream)
            End If
        Loop
    End Sub
[/code]
I made it:
1. Only read the first 4 bytes.
2. If the first byte is no &HFF, then skip the rest of the actions in the loop and go from the start. If it IS &HFF, then it will use BitConverter to get the header size.
3. It will ReDim the 'rec1' array to be PacketSize - 4.
4. It will receive the rest of the packet data.
5. It will concatenate the header and 'rec1', so it should become an entire packet, into 'rec'.
6. It will continue to do the rest, as it did before.

Pretty much, if what Hdx said is true, I should have eliminated those problems, but almost every time I try to do '/f list', I get an error saying 'Arithmetic operation resulted in an overflow.' at around the sixth packet (Refer to the comment in the code). And even when I don't (rarely), it starts off displaying the messages  in order, but then it just skips and finishes..... Any help?

The 'packetsize' variable is 0 when the error occurs, which leads me to believe that it isn't set, maybe because the packet header isn't 'read' properly...

EDIT: [code]    Sub DetectIncoming()
        Dim rec1() As Byte
        Dim rec(bnetClient.ReceiveBufferSize) As Byte
        Dim header(3) As Byte
        Dim bnetStream As NetworkStream = bnetClient.GetStream()
        Do

            ReDim header(3)
            Dim packetsize As Integer
            Dim startbyte As Byte = bnetStream.ReadByte()
            Dim header2(2) As Byte
            If startbyte = &HFF Then
                bnetStream.Read(header2, 0, 3)
                header(0) = startbyte
                header(1) = header2(0)
                header(2) = header2(1)
                header(3) = header2(2)
                packetsize = BitConverter.ToInt16(header, 2)

            Else
                Continue Do
            End If
            ReDim rec1(packetsize - 4)
            bnetStream.Read(rec1, 0, rec1.Length)
            ReDim rec(packetsize)
            rec = ConcatenateByteArray(header, rec1)

            If rec(1) = &HF Then
                Dim packetreader As New BncsReader(rec)
                Dim eventid As Int32 = packetreader.ReadInt32()
                Dim userflags As Int32 = packetreader.ReadInt32()
                Dim ping As Int32 = packetreader.ReadInt32()
                packetreader.ReadInt32()
                packetreader.ReadInt32()
                packetreader.ReadInt32()
                Dim username As String = packetreader.ReadCString()
                Dim text As String = packetreader.ReadCString()
                Select Case eventid
                    Case &H2
                        Console.WriteLine("-INFO- User " + username + " has joined the channel.")
                    Case &H3
                        Console.WriteLine("-INFO- User " + username + " has left the channel.")
                    Case &H4
                        Console.WriteLine("<" + username + "> has whispered: " + text)
                    Case &H5
                        Console.WriteLine("<" + username + "> " + text)
                    Case &H6
                        Console.WriteLine("-BROADCAST- " + text)
                    Case &H7
                        Console.WriteLine("-JOINED CHANNEL- " + text)
                    Case &H9
                        Console.WriteLine("User Flags Update: " + text)
                    Case &HA
                        Console.WriteLine("-WHISPER SENT-")
                    Case &HD
                        Console.WriteLine("Error! Channel Full!")
                    Case &HE
                        Console.WriteLine("Error! Channel does not exist!")
                    Case &HF
                        Console.WriteLine("Error! Channel is restricted!")
                    Case &H12
                        Console.WriteLine("-INFORMATION- " + text)
                    Case &H13
                        Console.WriteLine("Error! " + text)
                    Case &H17
                        Console.WriteLine("-INFO- Emote Used by " + username)
                End Select
            ElseIf rec(1) = &H0 Then
                SendNull(bnetStream)
            End If
        Loop
    End Sub
[/code]
That has the error too, except now the 'packetsize' value is -1.

EDIT: Just added 'If packetsize < 1 Then Continue Do'.....But it still skips some packets. All that and I didn't get anywhere in the end -.-

EDIT: OK WTF. I made it say 'w00t' whenever it ran the IF that checked for &HFF and I found some revealing stuff .. -.-"
[quote]
-JOINED CHANNEL- The Void
w00t
/f l
w00t
-INFORMATION- Your friends are:
w00t
-INFORMATION- 1: lfuzzyl, offline
w00t
-INFORMATION- 2: rts178, offline
w00t
-INFORMATION- 3: shamanno1, offline
w00t
-INFORMATION- 4: ace)of(clubs, offline
w00t
w00t
-INFORMATION- 6: water_knight, offline
w00t
w00t
-INFORMATION- 8: computer(hairy), offline
w00t
w00t
-INFORMATION- 10: carnifox, offline
w00t
w00t
-INFORMATION- 12: lordkintaro, using Warcraft III The Frozen Throne in a private
channel.
w00t
w00t
-INFORMATION- 14: caesio, offline
w00t
w00t
-INFORMATION- 16: tonton.vfr[1], offline
w00t
w00t
-INFORMATION- 18: tonton.vfr[3], offline
w00t
w00t
-INFORMATION- 20: tonton.vfr[5], offline
w00t
w00t
-INFORMATION- 22: FlipCirca, offline
w00t
w00t
-INFORMATION- 24: TonTonSNORT, offline[/quote]
Anyone have any ideas? =X
Bedtime for me now =D
November 13, 2008, 8:54 AM
Myndfyr
My listen loop follows the principle the others have discussed.  Here's some adapted code that more pseudocode-ish:

[code]
                while (IsConnected)
                {
                    // I wrote Receive().  It guarantees a buffer filled with as many bytes as you request and blocks until it comes in,
                    // or else returns null.
                    byte[] hdr = Receive(header, 0, 4);
                    if (hdr == null) return; // disconnected.
                    byte[] result = null;
                    ushort length = BitConverter.ToUInt16(hdr, 2);
                    if (length > 4)
                    {
                        byte[] data = AllocateIncomingBuffer(length);
                        result = Receive(data, 0, unchecked((ushort)(length - 4)));
                        if (result == null) return; // disconnected.
                        length = unchecked((ushort)(length - 4));
                    }
                    else if (length == 4)
                    {
                        // no data to parse; length is just for header.
                        length = unchecked((ushort)(length - 4));
                        result = new byte[0];
                    }
                    else
                    {
                        throw new ProtocolViolationException(Strings.InvalidPacketSizeFromBnet);
                    }
                    ParseData parseData = new ParseData(hdr[1], length, result);
                    Priority priority = DeterminePriority((BncsPacketId)parseData.PacketID);
                    ParsePacket(priority, parseData);
                }
[/code]

November 13, 2008, 4:36 PM
HdxBmx27
Two things:
[code]
                        // no data to parse; length is just for header.
                        length = unchecked((ushort)(length - 4));
                        result = new byte[0];

                        // no data to parse; length is just for header.
                        length = 0;
                        result = null;[/code] Neh?
And [code] Priority priority = DeterminePriority((BncsPacketId)parseData.PacketID);[/code] I'd like to see your DeterminePriority() function. {Just curious}
November 13, 2008, 6:10 PM
Ozzapoo
[quote author=MyndFyre[vL] link=topic=17704.msg180421#msg180421 date=1226594164]
My listen loop follows the principle the others have discussed.  Here's some adapted code that more pseudocode-ish:

[code]
                while (IsConnected)
                {
                    // I wrote Receive().  It guarantees a buffer filled with as many bytes as you request and blocks until it comes in,
                    // or else returns null.
                    byte[] hdr = Receive(header, 0, 4);
                    if (hdr == null) return; // disconnected.
                    byte[] result = null;
                    ushort length = BitConverter.ToUInt16(hdr, 2);
                    if (length > 4)
                    {
                        byte[] data = AllocateIncomingBuffer(length);
                        result = Receive(data, 0, unchecked((ushort)(length - 4)));
                        if (result == null) return; // disconnected.
                        length = unchecked((ushort)(length - 4));
                    }
                    else if (length == 4)
                    {
                        // no data to parse; length is just for header.
                        length = unchecked((ushort)(length - 4));
                        result = new byte[0];
                    }
                    else
                    {
                        throw new ProtocolViolationException(Strings.InvalidPacketSizeFromBnet);
                    }
                    ParseData parseData = new ParseData(hdr[1], length, result);
                    Priority priority = DeterminePriority((BncsPacketId)parseData.PacketID);
                    ParsePacket(priority, parseData);
                }
[/code]


[/quote]
I still don't really get it...(partially because of some of the functions used)
Could you please explain what the your code does?
November 13, 2008, 7:45 PM
HdxBmx27
[code]               while (IsConnected)
                {
                    byte[] hdr = Receive(header, 0, 4); //Reterives 4 bytes from the socket, garentees it's 4 bytes or null
                    if (hdr == null) return; // The socket was closed
                    byte[] result = null; //var for the actuall data
                    ushort length = BitConverter.ToUInt16(hdr, 2); //Gets the length of the packet from the header {hdr[2] | hdr[3] << 8}
                    if (length > 4){ //If it actually has data
                        byte[] data = AllocateIncomingBuffer(length); //Allocates 'length' amount of bytes for the data
                        result = Receive(data, 0, unchecked((ushort)(length - 4))); //Reads length - 4 bytes from the socket
                        if (result == null) return; // read failed, socket closed
                        length = unchecked((ushort)(length - 4)); //Data length = length - 4 {length - size of header}
                    }else if (length == 4){ // packet contains only header {AE: SID_NULL}
                        length = unchecked((ushort)(length - 4)); //length = 0
                        result = new byte[0]; //No data
                    }else{
                        throw new ProtocolViolationException(Strings.InvalidPacketSizeFromBnet); //OMFG THIS SHOULDNT HAPPEN DONT HAX ME!
                    }
                    ParseData parseData = new ParseData(hdr[1], length, result); //Creates a new Incoming packet buffer using the data from above.
                    Priority priority = DeterminePriority((BncsPacketId)parseData.PacketID); //Gets the priority {So the bot knows which packets to handle first, you don't need to do this}
                    ParsePacket(priority, parseData); //Passes it off to the handeling sub
                }[/code]

The main thing you need to do is this:
[code]               while (IsConnected)
                {
                    byte[] hdr = Receive(header, 0, 4); //receive 4 bytes
                    if (hdr == null) return; // disconnected.
                    byte[] data = null;
                    ushort length = hdr[2] | hdr[3] << 8;
                    if (length > 4){
                        data = Receive(data, 0, length - 4); //Read length - 4 bytes {The body of the packet}
                        if (data == null) return; // disconnected.
                    }
                    ParsePacket(hdr[1], data, length);
                }[/code]
An extreamly striped down version that should work {well, its psudo code cuz i havent tested but the base ideas are there}
November 13, 2008, 9:05 PM
Myndfyr
Note that the synax hdr[2] | hdr[3] << 8 might not work in C# or Visual Basic (it would require expansion from byte to a larger data type to do the shift, plus it's just not really clear in the intent: you need to specifically look up operator precedence to be sure that shift operator takes precedence over the bitwise or | operator).  Use BitConverter.ToInt16 or BitConverter.ToUInt16 as I did - it's built-in to the system.
November 13, 2008, 10:04 PM
Ozzapoo
Alright thanks, I'll try that.

EDIT: Where did Receive() come from?

EDIT: W00T! It works!!
May be crude, but works fine.
[code]    Sub DetectIncoming()


        Dim bnetStream As NetworkStream = bnetClient.GetStream()
        Do
            Dim header(3) As Byte
            bnetStream.Read(header, 0, 4)
            If header(0) = 0 Then
                Continue Do
            End If
            Dim packetsize As Int16
            If header(0) = &HFF Then
                packetsize = BitConverter.ToInt16(header, 2)
            End If
            Dim packet(packetsize - 5) As Byte
            If packetsize > 4 Then
                bnetStream.Read(packet, 0, packetsize - 4)
            End If
            Dim rec() As Byte = ConcatenateByteArray(header, packet)
            header = Nothing
            packet = Nothing
            If rec(1) = &HF Then
                Dim packetreader As New BncsReader(rec)
                Dim eventid As Int32 = packetreader.ReadInt32()
                Dim userflags As Int32 = packetreader.ReadInt32()
                Dim ping As Int32 = packetreader.ReadInt32()
                packetreader.ReadInt32()
                packetreader.ReadInt32()
                packetreader.ReadInt32()
                Dim username As String = packetreader.ReadCString()
                Dim text As String = packetreader.ReadCString()
                Select Case eventid
                    Case &H2
                        Console.WriteLine("-INFO- User " + username + " has joined the channel.")
                    Case &H3
                        Console.WriteLine("-INFO- User " + username + " has left the channel.")
                    Case &H4
                        Console.WriteLine("<" + username + "> has whispered: " + text)
                    Case &H5
                        Console.WriteLine("<" + username + "> " + text)
                    Case &H6
                        Console.WriteLine("-BROADCAST- " + text)
                    Case &H7
                        Console.WriteLine("-JOINED CHANNEL- " + text)
                    Case &H9
                        Console.WriteLine("User Flags Update: " + text)
                    Case &HA
                        Console.WriteLine("-WHISPER SENT-")
                    Case &HD
                        Console.WriteLine("Error! Channel Full!")
                    Case &HE
                        Console.WriteLine("Error! Channel does not exist!")
                    Case &HF
                        Console.WriteLine("Error! Channel is restricted!")
                    Case &H12
                        Console.WriteLine("-INFORMATION- " + text)
                    Case &H13
                        Console.WriteLine("Error! " + text)
                    Case &H17
                        Console.WriteLine("-INFO- Emote Used by " + username)
                End Select
            ElseIf rec(1) = &H0 Then
                SendNull(bnetStream)
            End If
        Loop
    End Sub
[/code]

And also, which packet returns all the people currently in the channel?
November 14, 2008, 5:20 AM
HdxBmx27
EID_SHOWUSER
Crude, but works i guess, think about it a little more and you can clean it up.
November 14, 2008, 7:50 AM
Ozzapoo
Alright Thanks! But can you give me any ideas on how I can clean it up?
November 14, 2008, 8:07 AM
Myndfyr
[quote author=Ozzapoo link=topic=17704.msg180436#msg180436 date=1226640021]
Alright thanks, I'll try that.

EDIT: Where did Receive() come from?
[/quote]
I commented about it:
[code]                    // I wrote Receive().  It guarantees a buffer filled with as many bytes as you request and blocks until it comes in,
                    // or else returns null.[/code]

It's inherited from ConnectionBase (source).
November 14, 2008, 6:47 PM
Ozzapoo
But does it really matter? Read() seems to work fine.
November 14, 2008, 9:28 PM
HdxBmx27
IIRC Read will read data from the socket, but does not guarantee that it is of the length you specify.
For example, if in some fluke the BNCS header comes in two tcp segments, {\xff\x51 in the 1st and \x10\x00 in the second}
Your Read() function will read 2 bytes and then return. So you'd have a header value of: \xff\x51\x00\x00
But, this is just speaking of C, I don't know if VB.net's Read() is diffrent.
November 14, 2008, 9:33 PM
Myndfyr
[quote author=Hdx link=topic=17704.msg180451#msg180451 date=1226698399]
IIRC Read will read data from the socket, but does not guarantee that it is of the length you specify.
For example, if in some fluke the BNCS header comes in two tcp segments, {\xff\x51 in the 1st and \x10\x00 in the second}
Your Read() function will read 2 bytes and then return. So you'd have a header value of: \xff\x51\x00\x00
But, this is just speaking of C, I don't know if VB.net's Read() is diffrent.
[/quote]
Nope.  That's exactly how Socket.Read() works.  That's why it modifies a buffer you pass it as a parameter, and its return value is the number of bytes read.
November 14, 2008, 9:35 PM
Ozzapoo
Uh..I've stumbled across a bit of an off-topic problem...

Is there any way I can modify the properties of a control on another thread (yes) from a piece of code on a different module (not sure)?
November 15, 2008, 2:29 AM
Myndfyr
You cannot modify a control's properties on a thread other than the one on which it was created - that's a Win32 rule.  You can use BeginInvoke[url=http://or just [url=http://msdn.microsoft.com/en-us/library/system.windows.forms.control.invoke.aspx]Invoke] or just [url=http://msdn.microsoft.com/en-us/library/system.windows.forms.control.invoke.aspx]Invoke to marshal it to the UI thread.
November 15, 2008, 7:08 PM
Ozzapoo
Alright. Thanks. I've pretty much got my bot set up now! :D
November 15, 2008, 9:21 PM
Ozzapoo
Just wondering, but how would I do an IP Ban, because the User IP thing is labeled DEFUNCT, so you can't exactly just grab someone's IP.
November 17, 2008, 6:56 AM
Barabajagal
Squelch is by IP. If you squelch an account, any other accounts that are squelched are on the same IP. Simply ban anyone who's squelched.
November 17, 2008, 7:39 AM
Ozzapoo
Wait, so if in Stealthbot, for example, you do /exile username

And it kicks, bans, and squelches 'username', does it just ban anyone who then attemps to join who is also squlched? If so, wouldn't it also ban other people who join your channel but are squelched? (Who are actually different people?)
November 17, 2008, 8:40 AM
l2k-Shadow
[quote author=Ozzapoo link=topic=17704.msg180478#msg180478 date=1226911208]
Wait, so if in Stealthbot, for example, you do /exile username

And it kicks, bans, and squelches 'username', does it just ban anyone who then attemps to join who is also squlched? If so, wouldn't it also ban other people who join your channel but are squelched? (Who are actually different people?)
[/quote]

yes. however, why would the bot squelch unless it was for the purpose of IP ban?
November 17, 2008, 2:42 PM
Barabajagal
That's why one doesn't typically chat via moderation bot...
November 17, 2008, 3:31 PM
LW-Falcon
[quote author=Ozzapoo link=topic=17704.msg180478#msg180478 date=1226911208]
Wait, so if in Stealthbot, for example, you do /exile username

And it kicks, bans, and squelches 'username', does it just ban anyone who then attemps to join who is also squlched? If so, wouldn't it also ban other people who join your channel but are squelched? (Who are actually different people?)
[/quote]
What difference does it make? If a user is squelched in the first place for whatever reason, you clearly don't care what happens to them.
November 18, 2008, 7:32 AM
Ozzapoo
Alright thanks for the info. And I'm just curious as to whether SID_GETADVLISTEX joins a game for you or lists them or both?
November 18, 2008, 7:47 AM
Barabajagal
GETADVLISTEX just gives you a game list.
November 18, 2008, 7:02 PM
Ozzapoo
Then what do you put for the string values?
November 19, 2008, 8:05 PM
HdxBmx27
If you jsut want to list them, leave them blank.
If you want to get the information for a specific game, you put the title/pw in.
November 19, 2008, 8:07 PM
Ozzapoo
For some reason I get "Too many server requests" (0x06) is response to SID_GETADVLISTEX
November 24, 2008, 3:14 AM
Barabajagal
You have to wait a few minutes between joining and sending that request, and about 30 seconds between every request... It's picky.
November 24, 2008, 3:43 AM
Ozzapoo
This CAN be used for Warcraft III custom games, right? If so, then howcome I am able to easily log on using WC3 and straight away go to the custom games list?
November 24, 2008, 9:12 AM
Barabajagal
Warcraft 3 has a built in anti-flood system... maybe that's why? I honestly have spent no time on any actual client, so I really only know the packets and what I've done with them, not the original use.
November 24, 2008, 10:22 AM

Search