def _handle_start_versioning(self, pid, pak): pak.get_dword() self.product = pak.get_dword(True) if self.product not in products: self.disconnect("Unsupported product (%s)" % self.product) return # Send SID_CLIENTID pak = buffer.DataBuffer() pak.insert_dword(0) pak.insert_dword(0) pak.insert_dword(0) pak.insert_dword(0) self.send(SID_CLIENTID, pak) # Send SID_LOGONCHALLENGEEX2 pak = buffer.DataBuffer() pak.insert_dword(0) # UDP Value pak.insert_dword(self._server_token) # Server token self.send(SID_LOGONCHALLENGEEX, pak) pak = buffer.DataBuffer() if self.parent.server.do_version_check: # Send SID_STARTVERSIONING pi = check_revision_data pak.insert_long(pi[0]) # MPQ filetime pak.insert_string(pi[1]) # MPQ filename pak.insert_string(pi[2]) # Value string self.send(SID_STARTVERSIONING, pak) else: # Skip the version check pak.insert_dword(0x02) # Result: success pak.insert_string('') self.send(SID_REPORTVERSION, pak)
def send_logon_response(self, status=0, proof=None): # Status can be a number (0 = success, 2 = fail) or custom error message string. is_str = isinstance(status, str) pak = buffer.DataBuffer() if self.logon_type == -1: # Legacy login # The result for this packet is flipped. 0 = failure, 1 = success pak.insert_dword(0x01 if status == 0x00 else 0x00) self.send(SID_LOGONRESPONSE, pak) if self.logon_type == 0: # Old login (OLS) pak.insert_dword(0x06 if is_str else status) if is_str: pak.insert_string(status) self.send(SID_LOGONRESPONSE2, pak) elif self.logon_type in [1, 2]: # New login (NLS) pak.insert_dword(0x0F if is_str else status) pak.insert_raw(proof or (b'\0' * 20)) pak.insert_string(status if is_str else '') self.send(SID_AUTH_ACCOUNTLOGONPROOF, pak) if status == 0x00: self.parent.print( "BNCS login complete - authenticated to chat API") self.logged_on = True
def _handle_cd_key2(self, pid, pak): pak.get_raw(20) # Key properties and server token self._client_token = pak.get_dword() pak = buffer.DataBuffer() pak.insert_dword(0x01) # Result: OK pak.insert_string('') self.send(SID_CDKEY2, pak)
def _handle_auth_check(self, pid, pak): self._client_token = pak.get_dword() # Send auth check response pak = buffer.DataBuffer() pak.insert_dword(0x00) # Success pak.insert_string('') self.send(SID_AUTH_CHECK, pak)
def send_chat(self, eid, username, text, flags=0, ping=0): pak = buffer.DataBuffer() pak.insert_dword(eid) pak.insert_dword(flags) pak.insert_dword(ping) pak.insert_dword(0) # IP Address pak.insert_dword(0xbaadf00d) # Account number pak.insert_dword(0xbaadf00d) # Registration authority pak.insert_string(username) pak.insert_string(text) self.send(SID_CHATEVENT, pak)
def _handle_report_version(self, pid, pak): pak.get_dword() self.product = pak.get_dword(True) if self.product not in products: self.disconnect("Unsupported product (%s)" % self.product) return # Send version response pak = buffer.DataBuffer() pak.insert_dword(0x02) # Result: success pak.insert_string('') # Patch path self.send(SID_REPORTVERSION, pak)
def _handle_get_filetime(self, pid, pak): req_id = pak.get_dword() unknown = pak.get_dword() filename = pak.get_string() # No files ever exist. pak = buffer.DataBuffer() pak.insert_dword(req_id) pak.insert_dword(unknown) pak.insert_long(0) pak.insert_string(filename) self.send(SID_GETFILETIME, pak)
def enter_chat(self, username, stats, account=None): self.username = username if account is None: account = username if username.startswith("[B]"): account = username[3:] pak = buffer.DataBuffer() pak.insert_string(username) pak.insert_string(stats) pak.insert_string(account) self.send(SID_ENTERCHAT, pak)
def _handle_auth_info(self, pid, pak): if self.product: self.disconnect("Sent repeat client auth.") return pak.get_raw(8) # First 8 bytes not needed self.product = pak.get_dword(True) if self.product not in products: self.disconnect("Unsupported product (%s)" % self.product) return # Send ping packet pak = buffer.DataBuffer() pak.insert_dword(random.getrandbits(32)) self.send(SID_PING, pak) pak = buffer.DataBuffer() if self.parent.server.do_version_check: # Send version check request pi = check_revision_data pak.insert_dword(self.logon_type) # Logon type pak.insert_dword(self._server_token) # Server token pak.insert_dword(0) # UDP value pak.insert_long(pi[0]) # CRev archive filetime pak.insert_string(pi[1]) # CRev archive filename pak.insert_string(pi[2]) # CRev formula if self.product in ["WAR3", "W3XP"]: pak.insert_raw(b'\0' * 128) # W3 server signature self.send(SID_AUTH_INFO, pak) else: # Skip sending the request and immediately send the result. pak.insert_dword(0x00) # Success pak.insert_string('') self.send(SID_AUTH_CHECK, pak)
def _handle_auth_accountlogon(self, pid, pak): if self.logged_on: self.disconnect("Attempt to login again") return pak.get_raw(32) # Client key self.logon_type = 2 # Start the CAPI login process self.parent.capi.authenticate(pak.get_string()) # Send login response pak = buffer.DataBuffer() pak.insert_dword(0) # Logon accepted pak.insert_raw(b'\0' * 32) # Account salt pak.insert_raw(b'\0' * 32) # Server key self.send(SID_AUTH_ACCOUNTLOGON, pak)
def send(self, pid, payload=None): if not self.connected: return pak = buffer.DataBuffer() pak.insert_byte(0xFF) pak.insert_byte(pid) if payload: pak.insert_word(len(payload) + 4) pak.insert_raw(payload.data if isinstance(payload, buffer. DataBuffer) else payload) else: pak.insert_word(4) self.socket.sendall(pak.data) self.parent.debug("Sent BNCS packet 0x%02x (len: %i)" % (pid, len(pak)))
def _handle_get_icon_data(self, pid, pak): # Packet has no contents pak = buffer.DataBuffer() pak.insert_long(0) pak.insert_string('icons.bni') self.send(SID_GETICONDATA, pak)
def _handle_query_realms2(self, pid, pak): pak = buffer.DataBuffer() pak.insert_dword(0) pak.insert_dword(0) self.send(SID_QUERYREALMS2, pak)