Author | Message | Time |
---|---|---|
Topaz | I haven't been able to get the below to properly login. I am ipbanned immediately - I have compared packetlogs, and it should have worked. If you know or see what I did wrong, please post. main.py [code]iimport socket import struct import bncs #connect sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(('europe.battle.net', 6112)) sock.send(chr(1)) #initialize parser and packetbuilder pbuilder = bncs.builder(sock) pbuilder.Send0x50() parser = bncs.parser(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 parser.parsePacket(strBuffer[:lngLen]) strBuffer = strBuffer[lngLen:] buflen -= lngLen [/code] bncs.py [code]import struct import socket class packetbuffer: 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 getDWORD(self, data): return struct.unpack('<I', data) def getWORD(self, data): return struct.unpack('<H', data) def sendPacket(self, packetID): tmp = '' for i in self.buffer: tmp += i packetlen = self.makeWORD(len(tmp) + 4) header = chr(0xff) + chr(packetID) + packetlen self.sock.send(header + tmp) self.clear() def clear(self): self.buffer = list() class builder: def __init__(self, sock): self.sock = sock def Send0x50(self): pbuffer = packetbuffer(self.sock) pbuffer.insertDWORD(0x00) pbuffer.insertString('68XIRATS') pbuffer.insertDWORD(0xCB) pbuffer.insertDWORD(0x00) pbuffer.insertDWORD(0x00) pbuffer.insertDWORD(0x00) pbuffer.insertDWORD(0x00) pbuffer.insertDWORD(0x00) pbuffer.insertNTString('USA') pbuffer.insertNTString('United States') pbuffer.sendPacket(0x50) class parser: def __init__(self, sock): self.sock = sock def parsePacket(self, data): packetID = ord(data[1:2]) print 'data: ' + data print 'Packet received: %s' %hex(packetID)[/code] | July 7, 2006, 1:01 AM |
UserLoser | [quote] self.buffer.append(data + '.') [/quote] I don't know python, but that looks like it's putting a period there instead of a null character? | July 7, 2006, 6:14 AM |
Topaz | [quote author=UserLoser link=topic=15351.msg155426#msg155426 date=1152252856] [quote] self.buffer.append(data + '.') [/quote] I don't know python, but that looks like it's putting a period there instead of a null character? [/quote] They amount to the same thing. EDIT: You're right! Thanks a lot, UserLoser. Note to self: never listen to Yegg when he gives Python advice. | July 7, 2006, 6:14 AM |
Yegg | [quote author=Topaz link=topic=15351.msg155427#msg155427 date=1152252887] [quote author=UserLoser link=topic=15351.msg155426#msg155426 date=1152252856] [quote] self.buffer.append(data + '.') [/quote] I don't know python, but that looks like it's putting a period there instead of a null character? [/quote] They amount to the same thing. EDIT: You're right! Thanks a lot, UserLoser. Note to self: never listen to Yegg when he gives Python advice. [/quote] ;D That's not Python specific, the issue with the period. I figured it would work just fine. I decided to test it in Scheme by creating a binary file and reading it with a hex editor. I wrote "hello world" + "." to one file, and "hello world" + a null character (Python would display as '\x00'). The first file, using the period, shows a 0x2E representing the hex of the period. The second file shows the hex as 0x00 which is what we want. I guess period and null character do have their differences :). Btw, did you do a faulty job comparing packet logs? I would have observed each byte in each packet. | July 7, 2006, 11:45 AM |
K | Most hex editors use periods to display non-printable characters or characters that would screw up the formatting, since printing a tab, newline, or null in the middle of a string you are trying to align nicely will cause problems. you can use isprint() in C/C++ to determine whether or not a character is printable, though it might not catch all of them. | July 7, 2006, 4:49 PM |
Topaz | Got another weird issue After unpacking the packet length ('lngLen, = struct.unpack('H', strBuffer[2:4])') and comparing it to the length of the buffer, I get two wildly different numbers that make parsing data impossible: lngLen = 25168 strBuffer.Length = 99 Does anyone know why it would do this? | July 8, 2006, 12:15 AM |
Yegg | Well, what was the value of strBuffer[2:4]? | July 8, 2006, 1:51 AM |
K | Shouldn't it be 2:3, not 2:4? Edit: perhaps that what you meant, as it is written as such in your first post. | July 8, 2006, 2:02 AM |
Topaz | [quote author=K link=topic=15351.msg155467#msg155467 date=1152324122] Shouldn't it be 2:3, not 2:4? Edit: perhaps that what you meant, as it is written as such in your first post. [/quote] Thanks, I was experimenting since I had a problem with ord(). | July 8, 2006, 2:06 AM |
St0rm.iD | Looks like you are using the default endian setting of the struct module, big. Try prefixing your unpack strings with '<' | July 8, 2006, 4:15 AM |
Topaz | Packet received: Packet received: 5Š‡ÿPc Packet received: ÙrD%ÅIX86ver6.mpq A=699062515 B=955808502 C=857775189 4 A=A-S B=B Not sure why the parser passed a blank string, can anyone see why? | July 9, 2006, 5:13 AM |
Topaz | After mulling over it for a bit, I looked at how warz did it with his moderation client. The new way of handling socket data is more or less the same way he did it, but oh well. The alpha post has been updated with the revised code. | July 10, 2006, 8:11 AM |
UserLoser | [quote author=Topaz link=topic=15351.msg155511#msg155511 date=1152422009] Packet received: Packet received: 5Š‡ÿPc Packet received: ÙrD%ÅIX86ver6.mpq A=699062515 B=955808502 C=857775189 4 A=A-S B=B Not sure why the parser passed a blank string, can anyone see why? [/quote] Perhaps you received SID_NULL? | July 10, 2006, 4:45 PM |
Topaz | [quote author=Topaz link=topic=15351.msg155511#msg155511 date=1152422009] Packet received: Packet received: 5Š‡ÿPc Packet received: ÙrD%ÅIX86ver6.mpq A=699062515 B=955808502 C=857775189 4 A=A-S B=B Not sure why the parser passed a blank string, can anyone see why? [/quote] [quote]Perhaps you received SID_NULL? [/quote] It shouldn't be the first packet I receive, though. | July 10, 2006, 6:34 PM |
warz | Who says? | July 10, 2006, 6:41 PM |
Topaz | [quote author=warz link=topic=15351.msg155570#msg155570 date=1152556905] Who says? [/quote] I should at least receive the header, anyway. I got a blank chunk of data. | July 10, 2006, 7:11 PM |
Topaz | 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: [code] 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[/code] [code] 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][/code] [code] 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)[/code] | July 16, 2006, 6:45 AM |