Fixed encryption, implemented more QR server stuff

- Fixed the RC4/Base64 encryption method (seems to be more commonly
known as "gsmsalg").
- Implemented more of the query and reporting server.
This commit is contained in:
polaris
2014-03-31 07:07:10 -04:00
parent 5de4dae622
commit 3df984eb0d
3 changed files with 122 additions and 12 deletions

View File

@@ -42,11 +42,12 @@ def rc4_encrypt(_key, _data):
return data
# Tetris DS overlay 10 @ 0216E9B8
# Used by the master server to send some data between the client and server
# Used by the master server to send some data between the client and server.
# This seems to be what Luigi Auriemma calls "Gsmsalg".
def prepare_rc4_base64(_key, _data):
data = rc4_encrypt(_key, _data)
data.append(0)
return base64_encode(buffer(data))
return base64.b64encode(buffer(data))
# Parse my custom authtoken generated by the emulated nas.nintendowifi.net/ac
def parse_authtoken(authtoken):

View File

@@ -1,4 +1,8 @@
# Server emulator for *.available.gs.nintendowifi.net and *.master.gs.nintendowifi.net
# Query and Reporting: http://docs.poweredbygamespy.com/wiki/Query_and_Reporting_Overview
# TODO: Refactor into a class
import socket
import gamespy.gs_utility as gs_utils
import other.utils as utils
@@ -15,6 +19,11 @@ s.bind(address)
utils.print_log("Server is now listening on %s:%s..." % (address[0], address[1]))
# Temporarily make these global until everything is made into a client class.
server_challenge = ""
secretkey = "JJlSi8" # Parse gslist.cfg later
sent_challenge = False
while 1:
recv_data, addr = s.recvfrom(2048)
@@ -22,7 +31,7 @@ while 1:
# Tetris DS overlay 10 @ 02144184 - Handle responses back to server
#
# After some more packet inspection, it seems the format goes something like this:
# - All server messages seem to always start with \xfe\xfe.
# - All server messages seem to always start with \xfe\xfd.
# - The first byte from the client (or third byte from the server) is a command.
# - Bytes 2 - 5 from the client is some kind of ID. This will have to be inspected later. I believe it's a
# session-like ID because the number changes between connections. Copying the client's ID might be enough.
@@ -37,7 +46,7 @@ while 1:
#
# CLIENT:
# 0x01 - Response (Tetris DS overlay 10 @ 216DCA4)
# Sends back base64 of RC4 encrypted string that was gotten from the server's 0x01. Server doesn't respond?
# Sends back base64 of RC4 encrypted string that was gotten from the server's 0x01.
#
# 0x03 - Send client state? (Tetris DS overlay 10 @ 216DA30)
# Data sent:
@@ -96,21 +105,87 @@ while 1:
#
# - \xfd\xfc commands get passed directly between the other player(s)?
#
#
# Open source version of GameSpy found here: https://github.com/sfcspanky/Openspy-Core/tree/master/qr
# Use as reference.
if recv_data[0] == '\x01':
utils.print_log("Response received from %s:%s... %s" % (addr[0], addr[1], recv_data[5:]))
elif recv_data[0] == '\x03':
utils.print_log("Received client state from %s:%s... %s" % (addr[0], addr[1], recv_data[5:]))
elif recv_data[0] == '\x07':
utils.print_log("Received unknown data from %s:%s... %s" % (addr[0], addr[1], recv_data[5:]))
elif recv_data[0] == '\x08':
if recv_data[0] == '\x00': # Query
utils.print_log("NOT IMPLEMENTED! Received query from %s:%s... %s" % (addr[0], addr[1], recv_data[5:]))
elif recv_data[0] == '\x01': # Challenge
utils.print_log("Received challenge from %s:%s... %s" % (addr[0], addr[1], recv_data[5:]))
# Prepare the challenge sent from the server to be compared
challenge = gs_utils.prepare_rc4_base64(secretkey, server_challenge)
# Compare challenge
client_challenge = recv_data[5:-1]
if client_challenge == challenge:
# Challenge succeeded
sent_challenge = True
# Handle successful challenge stuff here
packet = bytearray([0xfe, 0xfd, 0x0a]) # Send client registered command
packet.extend(recv_data[1:5]) # Get the ID
s.sendto(packet, addr)
utils.print_log("Sent client registered to %s:%s..." % (addr[0], addr[1]))
elif recv_data[0] == '\x02': # Echo
utils.print_log("NOT IMPLEMENTED! Received echo from %s:%s... %s" % (addr[0], addr[1], recv_data[5:]))
elif recv_data[0] == '\x03': # Heartbeat
data = recv_data[5:]
utils.print_log("Received heartbeat from %s:%s... %s" % (addr[0], addr[1], data))
# Parse information from heartbeat here
d = data.rstrip('\0').split('\0')
# It may be safe to ignore "unknown" keys because the proper key names get filled in later...
k = {}
for i in range(len(d) / 2):
k[d[i]] = d[i+1]
# Store k per client
if sent_challenge == False:
addr_hex = ''.join(["%02X" % int(x) for x in addr[0].split('.')])
port_hex = "%04X" % int(addr[1])
server_challenge = utils.generate_random_str(8) + addr_hex + port_hex
packet = bytearray([0xfe, 0xfd, 0x01]) # Send challenge command
packet.extend(recv_data[1:5]) # Get the ID
packet.extend(server_challenge)
packet.extend('\x00')
s.sendto(packet, addr)
utils.print_log("Sent challenge to %s:%s..." % (addr[0], addr[1]))
elif recv_data[0] == '\x04': # Add Error
utils.print_log("NOT IMPLEMENTED! Received add error from %s:%s... %s" % (addr[0], addr[1], recv_data[5:]))
elif recv_data[0] == '\x05': # Echo Response
utils.print_log("NOT IMPLEMENTED! Received echo response from %s:%s... %s" % (addr[0], addr[1], recv_data[5:]))
elif recv_data[0] == '\x06': # Client Message
utils.print_log("NOT IMPLEMENTED! Received echo from %s:%s... %s" % (addr[0], addr[1], recv_data[5:]))
elif recv_data[0] == '\x07': # Client Message Ack
utils.print_log("NOT IMPLEMENTED! Received client message ack from %s:%s... %s" % (addr[0], addr[1], recv_data[5:]))
elif recv_data[0] == '\x08': # Keep Alive
utils.print_log("Received keep alive from %s:%s..." % (addr[0], addr[1]))
elif recv_data[0] == '\x09':
elif recv_data[0] == '\x09': # Available
# Availability check only sent to *.available.gs.nintendowifi.net
utils.print_log("Received availability request for '%s' from %s:%s... %s" % (
get_game_id(recv_data), addr[0], addr[1], [elem.encode("hex") for elem in recv_data]))
s.sendto(bytearray([0xfe, 0xfd, recv_data[0], recv_data[1], recv_data[2], recv_data[3], recv_data[4]]), addr)
elif recv_data[0] == '\x0a': # Client Registered
# Only sent to client, never received?
utils.print_log("NOT IMPLEMENTED! Received client registered from %s:%s... %s" % (addr[0], addr[1], recv_data[5:]))
else:
utils.print_log(
"Unknown request from %s:%s: %s" % (addr[0], addr[1], [elem.encode("hex") for elem in recv_data]))

34
server_browser.py Normal file
View File

@@ -0,0 +1,34 @@
# I found an open source implemention of this exact server I'm trying to emulate here: https://github.com/sfcspanky/Openspy-Core/blob/master/serverbrowsing/
# Use as reference later.
# Tetris DS won't let you search for a match unless this server exists, so just create an empty server for now.
import socket
import gamespy.gs_utility as gs_utils
import other.utils as utils
import time
def get_game_id(data):
game_id = data[5: -1]
return game_id
#address = ('127.0.0.1', 28910) # accessible to only the local computer
address = ('0.0.0.0', 28910) # accessible to outside connections (use this if you don't know what you're doing)
backlog = 10
size = 2048
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(address)
s.listen(backlog)
utils.print_log("Server is now listening on %s:%s..." % (address[0], address[1]))
while 1:
client, address = s.accept()
utils.print_log("Received connection from %s:%s" % (address[0], address[1]))
while 1:
accept_connection = True
data = client.recv(size).rstrip()
utils.print_log("RESPONSE: %s" % data)