Author | Message | Time |
---|---|---|
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 |