• Welcome to Valhalla Legends Archive.
 

[Python] Battle.net Login

Started by topaz, July 06, 2006, 08:01 PM

Previous topic - Next topic

topaz

Quote from: warz on July 10, 2006, 01:41 PM
Who says?

I should at least receive the header, anyway. I got a blank chunk of data.
RLY...?

topaz

#16
Alright, I've gotten as far as to send SID_AUTH_CHECK, but it fails - the error is 'wrong product'. The cdkey is valid for the product, so I _think_ it's something I did wrong in getting the public/private values:


main.py

import socket
import struct
import bncs

#connect
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('useast.battle.net', 6112))
sock.send(chr(1))

#initialize parser and packetbuilder
pbuilder = bncs.builder(sock)
pbuilder.Send0x50()
handler = bncs.handler(sock)

#loop that checks for data
strBuffer = ''
buflen = 0

while 1:
    strTemp = sock.recv(1024)
    recvlen = len(strTemp)

    strBuffer += strTemp
    buflen += recvlen

    while (buflen >= 4):
        lngLen, = struct.unpack('<b', strBuffer[2:3])
        if (buflen < lngLen): break
        handler.parsePacket(strBuffer[:lngLen])
        print strBuffer[:lngLen]
        strBuffer = strBuffer[lngLen:]
        buflen -= lngLen



pybncsutil

from ctypes import *
from struct import *

platformDict = { 'NIX':0x01, 'WIN32':0x01, 'PMAC':0x02, 'XMAC':0x03 }
#checkrevision functions

bncsutil = windll.LoadLibrary('./bncsutil.dll')

def extractMPQNumber(mpqName):
    return bncsutil.extractMPQNumber(mpqName)

def checkRevision(formula, hashFiles, mpqNumber):
    #Make sure hashFiles is a list - if it isn't, fail.
    if len(hashFiles) <> 3: return 0

    checkSum = create_string_buffer('\000' * 10) #mutable memory block
       
    if (bncsutil.checkRevisionFlat(formula, hashFiles[0],
            hashFiles[1], hashFiles[2], mpqNumber, checkSum) == True):
        #unpack the checksum, return first value of tuple
        return unpack('L', checkSum.value)[0]
    else:
        #failed
        return 0
       
def getExeInfo(exe):
    size = 256
    infoString = create_string_buffer(256)
    version = create_string_buffer('\000' * 10)
       
    result = bncsutil.getExeInfo(exe, infoString,
                            size, version, platformDict['WIN32'])

    while result > size:
        if size > 1024:
            return 0
        else:
            size = size + 256
            infoString = create_string_buffer(size)
           
            result = bncsutil.getExeInfo(exe, infoString,
                            size, version, platformDict['WIN32'])

    version = unpack('L', version.value)[0] #unpack version
       
    return [version, infoString.value] #return version and info as a list

#ols functions

def doubleHashPassword( password, cToken, sToken):
    dHash = create_string_buffer(20)
    bncsutil.doubleHashPassword(password, cToken, sToken, dHash)

    return dHash.value

def hashPassword(password):
    pHash = create_string_buffer(20)
    bncsutil.hashPassword(password, pHash)

    return pHash.value

#sha1 function

def calcHashBuf(data):
        dataLen = len(data)
        dHash = create_string_buffer(20)

        bncsutil.calcHashBuf(data, dataLen, dHash)

        return dHash.value

#key decoding

def decodeCDKey(cdkey):
    cdkey = create_string_buffer(cdkey)
    #decoder = self.bncsutil.kd_create(byref(cdkey), 13)
       
    #return decoder
    return cdkey

def quickDecode(cdkey, cToken, sToken):
    pdtValue = create_string_buffer('\000' * 20)
    pbValue = create_string_buffer('\000' * 20)
    keyHash = create_string_buffer(20)

    if bncsutil.kd_quick(cdkey, cToken, sToken,
                          pbValue, pdtValue, keyHash, 20) == 0:
        return 0 #failed to decode cdkey
    else:
        #returns the product value, private value, and key hash
        return [pbValue.value, pdtValue.value, keyHash.value]



bncs.py

import struct
import random
import pybncsutil

pidDict = { 0x00:'SID_NULL', 0x05:'SID_CLIENTID', 0x0A:'SID_ENTERCHAT',
            0x0B:'SID_GETCHANNEL', 0x0C:'SID_JOINCHANNEL', 0x0F:'SID_CHATCOMMAND',
            0x10:'SID_LEAVECHAT', 0x19:'SID_MESSAGEBOX', 0x1E:'SID_CLIENTID2',
            0x25:'SID_PING' }

class sendbuffer:
   
    def __init__(self, sock):
        self.buffer = []
        self.sock = sock
       
    def insertData(self, data):
        self.buffer.append(data)

    def insertString(self, data):
        self.buffer.append(data)

    def insertNTString(self, data):
        self.buffer.append(data + chr(0))

    def insertDWORD(self, data):
        data = self.makeDWORD(data)
        self.buffer.append(data)

    def makeDWORD(self, data):
        return struct.pack('I', data)

    def makeWORD(self, data):
        return struct.pack('H', data)
   
    def sendPacket(self, packetID):
        tmp = ''
        for i in self.buffer: tmp = tmp + i
       
        packetlen = self.makeWORD(len(tmp) + 4)
        header = chr(0xff) + chr(packetID) + packetlen

        self.sock.send(header + tmp)
        self.clear()
       
    def clear(self):
        del self.buffer[:]
        self.buffer[:] = []

class recvbuffer:
    def __init__(self, rawbuffer):
        self.rawbuffer = rawbuffer
        self.position = 0

    def resetPosition(self):
        self.position = 0
       
    def getDWORD(self, data):
        return struct.unpack('<I', data)

    def getWORD(self, data):
        return struct.unpack('<H', data)

    def increment(self):
        self.position = self.position + 1

    def jump(self, bytes):
        self.position += bytes

    def back(self, bytes):
        self.position -= bytes

    def setpos(self, position):
        self.position = position

    def nextBYTE(self):
        param = self.rawbuffer[self.position:self.position + 1]
        byte = struct.unpack('b', param)[0]

        self.increment()
        return byte

    def nextString(self):
        pos = self.rawbuffer.find(chr(0), self.position)
        string = self.rawbuffer[self.position:pos]
       
        self.setpos(pos + 1)
       
        return string
   
    def nextDWORD(self):
        param = self.rawbuffer[self.position:self.position + 4]
        dword = struct.unpack('I', param)[0]
       
        self.jump(4)

        return dword

    def nextWORD(self):
        param = self.rawbuffer[self.position:self.position + 2]
       
        word = struct.unpack('H', param)[0]
        self.jump(2)

        return word

class builder:

    def __init__(self, sock):
        self.sock = sock
        self.pbuffer = sendbuffer(self.sock)
       
    def Send0x50(self):
        self.pbuffer.insertDWORD(0x00)
        self.pbuffer.insertString('68XIPXES')
        self.pbuffer.insertDWORD(0xCD)
        self.pbuffer.insertDWORD(0x00)
        self.pbuffer.insertDWORD(0x00)
        self.pbuffer.insertDWORD(0x00)
        self.pbuffer.insertDWORD(0x00)
        self.pbuffer.insertDWORD(0x00)
        self.pbuffer.insertNTString('USA')
        self.pbuffer.insertNTString('United States')
        self.pbuffer.sendPacket(0x50)

    def Send0x51(self, sToken, mpqName, formula):
        #checkrevision stuff
        cToken = random.randint(10000000, 99999999)
        exeInfo = pybncsutil.getExeInfo('./STAR/starcraft.exe')
        mpqNumber = pybncsutil.extractMPQNumber(mpqName)
        hashFiles = ['./STAR/starcraft.exe', './STAR/storm.dll', './STAR/battle.snp']
        checksum = pybncsutil.checkRevision(formula, hashFiles, mpqNumber)
        #key stuff
        keyData = pybncsutil.quickDecode('############', cToken, sToken)

        print keyData
               
        self.pbuffer.insertDWORD(cToken)        # client token
        self.pbuffer.insertDWORD(exeInfo[0])    # exe version
        self.pbuffer.insertDWORD(checksum)      # exe hash

        self.pbuffer.insertDWORD(1)             # number of keys
        self.pbuffer.insertDWORD(0)             # 0/1 using spawn (false/true)

        self.pbuffer.insertDWORD(13)            # key length
        self.pbuffer.insertData(keyData[0])     # public value
        self.pbuffer.insertData(keyData[1])     # product value
        self.pbuffer.insertDWORD(0)             # unknown value
        self.pbuffer.insertString(keyData[2])   # key hash

        self.pbuffer.insertNTString(exeInfo[1]) # exe info
        self.pbuffer.insertNTString('piebot')   # cdkey owner name

        self.pbuffer.sendPacket(0x51)           # finally done!

class handler:
    def __init__(self, sock):
        self.sock = sock

    def parsePacket(self, data):
        self.rbuffer = recvbuffer(data)

        if self.rbuffer.nextBYTE() <> -1: return
       
        packetID = self.rbuffer.nextBYTE()

        print 'Packet received: %s' %hex(packetID)

        if packetID == 0x50:
            self.parse0x50(data)
        elif packetID == 0x25:
            self.parse0x25(data)
        elif packetID == 0x51:
            self.parse0x51(data)

    def parse0x25(self, data):
        pbuilder = builder(self.sock)
   
    def parse0x50(self, data):
        pbuilder = builder(self.sock)
       
        logonType = self.rbuffer.nextDWORD()
        sToken = self.rbuffer.nextDWORD()
        self.rbuffer.jump(14)
        mpqName = self.rbuffer.nextString()
        formula = self.rbuffer.nextString()

        pbuilder.Send0x51(sToken, mpqName, formula)

    def parse0x51(self, data):
        result = self.rbuffer.nextDWORD()

        print 'result: %s' %hex(result)
RLY...?