Valhalla Legends Forums Archive | Battle.net Bot Development | What is a packet buffer for?

AuthorMessageTime
para
Can my bot work without a packet buffer?
I'm not very experienced programmer so less complicated code is better ;P

I also don't understand the function of the pb

Thanks alot
August 17, 2008, 3:19 PM
iago
Yes, it can work fine without a packet buffer.

Do I recommend it? No.

A packetbuffer is an easy and clean way of "marshaling" the data for the packets, so to speak. In other words, it's an easy way to build a packet out of its components (dwords, strings, etc.). Rather than manually allocating space in a buffer, then sticking in all the variables, you just put the variables into a packetbuffer and it takes care of it.

So basically, if you have a packet that requires two DWORDs and a NTSRING, you'd do this:
buffer.insertDWORD(123);
buffer.insertDWORD(456);
buffer.insertNTSTRING("hello1");

It cleans things up a lot.

If you want to see a couple examples of packetbuffers I wrote, check them out:
(java) http://svn.skullsecurity.org:81/javaop/javaop2/javaop2_pub/src/util/Buffer.java
(C) http://svn.skullsecurity.org:81/ron/security/nbtool/buffer.h (and .c)

There are other implementations floating around there, too. My friend is working on one in Ruby.
August 17, 2008, 3:40 PM
dlStevens
*This is NOT for battle.net by maybe this will give you an idea on how a visual basic packet buffer works.

[code]
'   Specific Apryl Server Toolkit
'       Written by Dale Stevens
Private Buffer      As String
Private Position    As Integer

Public Sub Initialize()
On Error Resume Next
    Position = 1
End Sub

Private Sub Clear()
    Buffer = ""
    Position = 1
End Sub

Public Sub SendPacket(Socket As Winsock, OpCode As Long)
On Error Resume Next
    Socket.SendData OpCode & "||" & Buffer
    Clear
End Sub

Public Sub InsertString(strString As String)
On Error Resume Next
    Buffer = Buffer & strString & "||"
End Sub

Public Sub InsertInt(intInteger As Integer)
On Error Resume Next
    Buffer = Buffer & intInteger & "||"
End Sub

Public Sub InsertLong(lngLong As Long)
On Error Resume Next
    Buffer = Buffer & lngLong & "||"
End Sub

Public Sub SetBufferPosition(ByVal Pos As Long)
On Error Resume Next
    Position = Pos
End Sub

Public Function GetBuffer() As String
    GetBuffer = Buffer
End Function

Public Function BufferLength() As Long
On Error Resume Next
    BufferLength = Len(Buffer)
End Function

Public Sub Skip(ByVal Bytes As Long)
On Error Resume Next
    Position = Position + Bytes
End Sub

Private Function IsAlphaNumeric(TestString As String) As Boolean     'http://www.freevbcode.com/ShowCode.Asp?ID=1086
Dim sTemp As String
Dim iLen As Integer
Dim iCtr As Integer
Dim sChar As String
    sTemp = TestString
    iLen = Len(sTemp)
    If iLen > 0 Then
        For iCtr = 1 To iLen
            sChar = Mid(sTemp, iCtr, 1)
            If Not sChar Like "[0-9A-Za-z]" Then Exit Function
        Next
    IsAlphaNumeric = True
    End If
End Function

Public Function AtProperLength(Name As String, Username As String, Password As String) As Boolean
If Len(Username) >= 4 And Len(Username) <= 12 And Len(Password) >= 4 And Len(Password) <= 15 And Len(Name) >= 3 Then
    fntReturn = True
Else
    fntReturn = False
End If
End Function

Public Function UserValidation(ByRef FullName As String, ByRef UName As String, ByRef PW As String) As Boolean
Dim tmpSplt() As String
If InStr(FullName, " ") Then
    tmpSplt() = Split(FullName, " ")
        If tmpSplt(1) = "" Then
            UserValidation = False
        ElseIf tmpSplt(1) <> vbNullChar Then
            UserValidation = True
        End If
Else
   
        If IsAlphaNumeric(UName) = True Then
            If Len(UName) >= 4 And Len(UName) <= 12 Then
                UserValidation = True
            Else
                UserValidation = False
            End If
        Else
            UserValidation = Flase
        End If
        'Password Check
        If IsAlphaNumeric(PW) = True Then
            If Len(PW) >= 4 And Len(PW) <= 15 Then
                UserValidation = True
            Else
                UserValidation = False
            End If
        End If
End Function
[/code]

Example as iago said:
[code]
Dim Toolkit As New clsToolkit
With Toolkit
    .Initalize
    .InsertString "whatever"
    .SendPacket Winsock1, 1012
End with
[/code]
August 17, 2008, 6:34 PM
para
Thanks Iago, and Dale, I'll take a look at your sources and see if I can't get an idea of how these function. Although I'm attempting it in Python.

Hey I'm a Fedora Core-ist as well ! Long live Fedora, down with Ubuntu!
August 17, 2008, 7:30 PM
Ringo
if Python can use the rtlmovememory api, or alike, this might be easy to follow/port:
[code]
Private m_Buf(1023)         As Byte
Private m_BufPos            As Long
Private m_Header(3)         As Byte

Public Enum PacketHeaders
    BNCS_HEADER = 4
    BNRS_HEADER = 3
    D2GS_HEADER = 1
End Enum

Public Sub iClear()
    m_BufPos = 0
End Sub
Public Sub iBYTE(ByRef bValue As Byte)
    m_Buf(m_BufPos) = bValue
    m_BufPos = m_BufPos + 1
End Sub
Public Sub iWORD(ByRef intValue As Integer)
    Call CopyMemory(m_Buf(m_BufPos), intValue, 2)
    m_BufPos = m_BufPos + 2
End Sub
Public Sub iDWORD(ByRef lngValue As Long)
    Call CopyMemory(m_Buf(m_BufPos), lngValue, 4)
    m_BufPos = m_BufPos + 4
End Sub
Public Sub iSTRING(ByRef strValue As String)
    Dim strLen      As Integer
    strLen = Len(strValue)
    If strLen = 0 Then Exit Sub
    Call CopyMemory(m_Buf(m_BufPos), ByVal strValue, strLen)
    m_BufPos = m_BufPos + strLen
End Sub
Public Sub iNTSTRING(ByRef strValue As String)
    Dim strLen      As Integer
    strLen = Len(strValue)
    If (Not strLen = 0) Then
        Call CopyMemory(m_Buf(m_BufPos), ByVal strValue, strLen)
        m_BufPos = m_BufPos + strLen
    End If
    Call iBYTE(0)
End Sub
Public Sub iHEADER(ByVal PacketID As Byte, Optional ByVal Header As PacketHeaders = BNCS_HEADER)
    Dim strLen      As Integer
    strLen = CInt(Header)
    If (Header = BNCS_HEADER) Then
        m_Header(0) = &HFF
        m_Header(1) = PacketID
        Call CopyMemory(m_Header(2), CInt(m_BufPos + 4), 2)
    ElseIf (Header = BNRS_HEADER) Then
        Call CopyMemory(m_Header(0), CInt(m_BufPos + 3), 2)
        m_Header(2) = PacketID
    ElseIf (Header = D2GS_HEADER) Then
        m_Header(0) = PacketID
    End If
    Call CopyMemory(m_Buf(strLen), m_Buf(0), m_BufPos)
    Call CopyMemory(m_Buf(0), m_Header(0), strLen)
    m_BufPos = m_BufPos + strLen
End Sub
Public Sub iPacket(ByRef sckHdl As Long)
    If (m_BufPos = 0) Then Exit Sub 'empty buffer
    If send(sckHdl, m_Buf(0), m_BufPos, 0&) = -1 Then
        '//Failed to send any data
    End If
    Call iClear
End Sub
[/code]
Just don't build packets bigger than 1024 bytes with it, with out useing a bigger buffer size.
August 17, 2008, 7:54 PM
Yegg
Ringo, why did you mention Python? Is he using that as his language of choice?

There is an equivalent to RtlMoveMemory for Python. pack() and unpack() from Python's struct module.

First, here are the docs to this module: http://docs.python.org/lib/module-struct.html

I think this is a lot easier to use than the built-in methods in VB. I'm not going to create a whole list of examples, but here is how you would convert the number 100 into an unsigned int.

[code]>>> from struct import *
>>> pack('I', 100)
'd\x00\x00\x00'[/code]

This is done from the Python interpreter. the first argument of pack() takes a format string (more or less). 'I' represents unsigned int, 'i' represents signed int, the rest are listed on the URL I provided. Of course if I try to turn any number larger than 4294967295 (largest number unsigned int will hold) into an unsigned int, I'll either get invalid results or the program will error out.

unpack() does the opposite of pack().

[code]>>> unpack('I', 'd\x00\x00\x00')
(100,)[/code]

It returns its results as a tuple because you can use unpack() to return as many values as you like. For example,
[code]>>> unpack('IQc', '\x10\x50\x50\x12\x50\x00\x23\x44\x01\x00\x00\x00h')
(307253264, 5438111824L, 'h')[/code]

'IQc' says to first extract an unsigned int from the string provided in the second argument to unpack(), then get an unsigned long long (qword - 8 bytes), then a character. It gets all three things and stores their values into the tuple provided. Tuples work very similarly to lists in Python:
[code]>>> (307253264, 5438111824L, 'h')[1]
5438111824L[/code]

This should clear things up for someone out there.


Update: I just noticed iago's mention of Ruby. So I'll add this: Ruby has the same pack() and unpack() methods as Python and they work the same exact way. I prefer my Ruby implementation instead of Python as Ruby is a much nicer, clearer language to work with.

In Ruby I actually use pack() and unpack() as a method of the data I want to work with. So in Python where I did, pack('I', 100), I would actually do [100].pack('I') in Ruby. Not much different, but still incredibly simple.
August 18, 2008, 2:44 AM
para
Thanks alot guys, this is all moderatly confusing but I'm sure I'll get it if I keep at it.
August 18, 2008, 2:57 AM

Search