def trigger_fuzz(rate_limit=1.0): for trigger in range(0x100): time_ = parser.predict_client_time() x = parser.LAST_X y = parser.LAST_Y z = parser.LAST_Z pospkt = parser.position_packet(CLIENT_SECRET, time_, x, y, z, 0, 0, 0, trigger, 0, 0) print 'Trigger: 0x%02x' % (trigger) encrypted = encrypt_data(pospkt) add_server_queue(encrypted) time.sleep(1)
def stuffed_position(coords): stuffed = '' time_ = parser.predict_client_time() for x, y, z in coords: pospkt = parser.position_packet(CLIENT_SECRET, time_, x, y, z, 0, 0, 0, 0, 0, 0) stuffed += pospkt time_ += 1 stuffed = encrypt_data(stuffed) print 'Sending stuff pos pkt (%u bytes)' % (len(stuffed)) add_server_queue(stuffed)
def run(self): global BLOCK_POSITION global VERBOSITY while True: # pop injected packets with CQR_LOCK: while len(CLIENT_QUEUE_RAW) > 0: pkt = CLIENT_QUEUE_RAW.pop(0) self.game.forward(pkt) try: data, addr = self.server.recvfrom(4096) except socket.timeout: continue if data: data_pt = decrypt_data(data) if VERBOSITY > 0: print "[{}] <- {}".format(self.port, data_pt[:100].encode('hex')) hexdump.hexdump(data_pt) if BLOCK_POSITION and data_pt[2] in ['X', 'T']: print 'Block teleport/logout' continue elif data_pt[2] == 'X': print 'Blocked logout' continue elif data_pt[2] == 'Y': print 'Blocked freeze' continue #elif data_pt[2] in ['E', 'I', 'P']: # # Pass through for latency # self.game.forward(data) # continue try: parser.parse(data_pt[2:], self.port, 'server') while len(parser.CLIENT_QUEUE) > 0: pkt = parser.CLIENT_QUEUE.pop() #print "got queue client: {}".format(pkt.encode('hex')) self.game.forward(encrypt_data(pkt)) except Exception as e: print 'server[{}]'.format(self.port), e
def spray_coords(coords): socks = [(socket.socket(socket.AF_INET, socket.SOCK_DGRAM), p) for p in range(1338, 1358)] for sock in socks: sock[0].setblocking(0) if len(coords) > len(socks): raise Exception("too many to spray") time_ = parser.predict_client_time() for i, (x, y, z) in enumerate(coords): pospkt = parser.position_packet(CLIENT_SECRET, time_, x, y, z, 0, 0, 0, 0, 0, 0) pospkt = encrypt_data(pospkt) sock, port = socks[i] sock.sendto(pospkt, (DEFAULT_SERVER, port))
def run(self): global BLOCK_POSITION_OUT global VERBOSITY while True: # pop even if nothing received from proxy (injected packets) with SQR_LOCK: while len(SERVER_QUEUE_RAW) > 0: pkt = SERVER_QUEUE_RAW.pop(0) self.server.forward(pkt) try: data, self.reply_addr = self.game.recvfrom(4096) except socket.timeout: continue if data: data = decrypt_data(data) if BLOCK_POSITION_OUT and data[2] in ['P']: #print 'block c->s position' continue if VERBOSITY > 0: print "[{}] -> {}".format(self.port, data.encode('hex')) hexdump.hexdump(data) update_client_secret(data) try: parser.parse(data[2:], self.port, 'client') if len(parser.SERVER_QUEUE) > 0: pkt = parser.SERVER_QUEUE.pop() #print "got queue server: {}".format(pkt.encode('hex')) self.server.forward(encrypt_data(pkt)) except Exception as e: print 'client[{}]'.format(self.port), e
def main(): global BLOCK_POSITION, BLOCK_POSITION_OUT global CLIENT_SECRET global VERBOSITY BLOCK_POSITION = False argparser = argparse.ArgumentParser() argparser.add_argument('--port', type=int, default=1337) argparser.add_argument('--bindip', type=str, default=DEFAULT_BIND_IP) argparser.add_argument('--server', type=str, default=DEFAULT_SERVER) args = argparser.parse_args() _game_server = Proxy(args.bindip, args.server, args.port) _game_server.start() while True: try: cmd = raw_input('$ ') if cmd[:4] == 'quit': os._exit(0) elif cmd == 'v': if VERBOSITY == 0: VERBOSITY = 1 else: VERBOSITY = 0 elif cmd == 'bp': BLOCK_POSITION = not BLOCK_POSITION print 'Block position:', BLOCK_POSITION elif cmd == 'bpo': BLOCK_POSITION_OUT = not BLOCK_POSITION_OUT print 'Block pos out:', BLOCK_POSITION_OUT elif cmd == 'ft': parser.FREEZE_TIME = not parser.FREEZE_TIME print 'Freeze time:', parser.FREEZE_TIME elif cmd[0:2] == 'S ': # send to server add_server_queue(cmd[2:].decode('hex')) elif cmd[0:2] == 'C ': # send to client add_client_queue(cmd[2:].decode('hex')) elif cmd.startswith('chat_l '): msg = cmd[len('chat_l'):] data = ' ' + msg print data add_client_queue(encrypt_data(data)) elif cmd.startswith('chat_r '): msg = cmd[len('chat_r'):] data = ' ' + CLIENT_SECRET + msg add_server_queue(encrypt_data(data)) elif cmd[0:2] == 'T ': x, y, z = (float(x) for x in cmd[2:].split(' ')) telpkt = parser.teleport_packet(x, y, z, flag=1) add_client_queue(encrypt_data(telpkt)) elif cmd[0:2] == 'Z ': x, y, z = (float(x) for x in cmd[2:].split(' ')) #BLOCK_POSITION = True cur_x = parser.LAST_X cur_y = parser.LAST_Y cur_z = parser.LAST_Z smooth_teleport((cur_x, cur_y, cur_z), (x, y, z), send_server=True, send_client=False, rate_limit=0.1) #BLOCK_POSITION = False elif cmd == 'startrec' and not parser.RECORD_PLAYER_POS: print 'started recording' parser.RECORD_PLAYER_POS = True if parser.PLAYER_POS_HIST is not None: parser.PLAYER_POS_HIST = None elif cmd == 'stoprec' and parser.RECORD_PLAYER_POS: print 'stopped recording' parser.RECORD_PLAYER_POS = False print 'Recorded %u positions' % (len(parser.PLAYER_POS_HIST)) elif cmd.startswith('playrec'): if parser.PLAYER_POS_HIST is not None: coords = parser.PLAYER_POS_HIST[:] cmd = cmd.split(' ') rate = 0.14 if len(cmd) > 1: try: rate = float(cmd[-1]) except ValueError: pass if 'rev' in cmd: coords = coords[::-1] if 'stuf' in cmd: stuffed_position(coords) elif 'spray' in cmd: spray_coords(coords) elif 'speed' in cmd: last_pos = (parser.LAST_X, parser.LAST_Y, parser.LAST_Z) if None not in last_pos: print 'injecting last position:', last_pos coords.insert(0, last_pos) dr = ReplayThread(coords, send_client=True, send_server=True, dist_time=rate) dr.start() dr.join() else: last_pos = (parser.LAST_X, parser.LAST_Y, parser.LAST_Z) if None not in last_pos: print 'injecting last position:', last_pos coords.insert(0, last_pos) dr = ReplayThread(coords, send_client=True, send_server=False, rate_limit=rate) dr.start() dr.join() elif cmd.startswith('saverec '): if parser.PLAYER_POS_HIST is not None: filename = cmd[len('saverec '):] with open(filename, 'w') as posfile: posfile.write(json.dumps(parser.PLAYER_POS_HIST)) print 'Wrote recording to file %s' % (filename) elif cmd.startswith('loadrec '): filename = cmd[len('saverec '):] with open(filename, 'r') as posfile: positions = json.loads(posfile.read()) parser.PLAYER_POS_HIST = positions print 'Loaded file' elif cmd.startswith('emoji'): cmd = cmd.split(' ') emoji_id = int(cmd[-1], 0) pkt = parser.emoji_packet(emoji_id, CLIENT_SECRET) add_server_queue(encrypt_data(pkt)) elif cmd == 'tfuzz': BLOCK_POSITION_OUT = True tf = TriggerFuzzThread(1.0) tf.start() tf.join() BLOCK_POSITION_OUT = False elif cmd == 'reload': reload(parser) else: pass except KeyboardInterrupt: print 'abort' continue except Exception as e: print e
def discrete_replay(coords, skip=0, send_client=True, send_server=False, dist_time=None, rate_limit=0.2): print '# coords:', len(coords) if dist_time is not None: # Scaling up time for target units per second # Get current game time and track how much we artificially increase it start_time = parser.predict_client_time() accrued_time = 0.0 print 'start time:', start_time for i, (x, y, z) in enumerate(coords): print i, x, y, z # Only play every nth coordinate if skip > 1 and i % skip != 0: continue if send_client: telpkt = parser.teleport_packet(x, y, z) add_client_queue(encrypt_data(telpkt)) if send_server: if dist_time is not None: if i > 0: distance = dist(coords[i - 1], coords[i]) # decreased it a bit lower than normal 5.0 speed to avoid getting kicked normal_speed = 2.0 # 5.0 units per second, lower in case of round errors normal_time = distance / normal_speed new_time = (dist_time / normal_speed) * normal_time accrued_time += new_time #accrued_time += parser.LAST_SRV_ROUNDTRIP accrued_time += 0.04 time_ = start_time + accrued_time print 'normal time: %f -> scaled time: %f' % (normal_time, new_time) else: start_time += 1.0 time_ = start_time # sync injected hearbeat time parser.set_client_time(time_) else: time_ = parser.predict_client_time() pospkt = parser.position_packet( CLIENT_SECRET, time_, x, y, z, 0, 0, 0, # euler angles 0xff, # trigger 0x7fff, 0x7fff, # ground, notground raw_time=False) add_server_queue(encrypt_data(pospkt)) if dist_time is not None and i < len(coords) - 1: units_per_second = dist_time # default 5.0 distance = dist(coords[i], coords[i + 1]) duration = distance / units_per_second print '%f seconds to next checkpoint (%f units away)' % (duration, distance) if duration > 0.0: time.sleep(duration) elif rate_limit > 0.0: time.sleep(rate_limit) print 'discrete replay finished'