Much code, many rewrite

This commit is contained in:
Emily 2019-12-14 20:08:34 +01:00
parent 3bdd78b61c
commit 2166a30aa9
34 changed files with 852 additions and 58 deletions

View File

@ -1,3 +1,9 @@
{ {
"python.pythonPath": "C:\\Users\\Emily\\AppData\\Local\\Programs\\Python\\Python36\\python.exe" "python.pythonPath": "C:\\Users\\Emily\\AppData\\Local\\Programs\\Python\\Python37\\python.exe",
"files.exclude": {
"**/__pycache__": true,
"**/__pycache__.*": true,
"**/*.pyc": true,
".vscode": true
}
} }

View File

@ -7,5 +7,11 @@
"max_players": 50, "max_players": 50,
"mode": "yay", "mode": "yay",
"language": "spoop" "language": "spoop"
} },
"logging": {
"filename": "",
"level": "DEBUG",
"format": "%(name)s - %(levelname)s - %(message)s",
"datefmt": "%d-%b-%y %H:%M:%S"
}
} }

View File

@ -1,4 +1,5 @@
from . import mainHandler from . import mainHandler
from . import serverPingHandler from . import serverQueryHandler
from . import handshakeHandler from . import handshakeHandler
from . import unknownHandler

View File

@ -1,3 +1,18 @@
def handle(client, data): import logging
print("![{}] -> Handshake".format(client.addr)) import struct
return
from network.enums import types as TYPE
from objects import glob
logger = logging.getLogger(__name__)
def handle(client: "Client", data: bytes) -> bytes:
challenge = (client.ip_uint ^ glob.challenge_short) & TYPE.MAX_USHORT
challenge_solution = challenge ^ 0x6969
challenge_answer = struct.unpack_from(b">H", data, 1)[0]
if challenge_answer != challenge_solution:
return struct.pack(b">BH", 0x1A, challenge)
client.state = 1 # CHALLENGE_PASSED
return b"\x19\x00" # 0x19: Valid_challenge; leading 0x00 byte due to some routers shitting itself if only 1 byte is sent/received

View File

@ -1,16 +1,29 @@
from importlib import reload
import random
import logging
import struct
from . import handshakeHandler from . import handshakeHandler
from . import unknownHandler
def handle(client, data): from helpers.byteFormater import readable_bytes
print("?[{}] -> {} / {}".format(client.addr, data, data.hex()))
if client.state == 0: # Perform handshake if possible logger = logging.getLogger(__name__)
client.state = 1
return b"\x1a\x1e\xd1\xd1"
if client.state == 1:
client.state = 2
return b"\x19\x00"
if client.state == 2:
client.state = 3
return b"\xe3\x00\x00", b"\x00\x00\x42\x98\x0c\x11\x33\x45\x30\x42\x33\x33\x35\x32\x37\x34\x46\x39\x31\x43\x39\x39\x00"
return b"WUT?" HANDLERS = {
0x18: handshakeHandler.handle,
0x00: unknownHandler.handle
}
def handle(client: "Client", data: bytes) -> bytes:
out: bytes = HANDLERS.get(data[0], unimplemented)(client, data)
return out
def unimplemented(client: "Client", data: bytes) -> bytes:
logger.debug("[%s] sent unhandled data: %s" % (client.addr, readable_bytes(data)))
return bytes([x for x in range(1,32,1)])
def restart():
reload(handshakeHandler)

View File

@ -0,0 +1,53 @@
"""
if client.state == 0: # Perform handshake if possible
client.state = 1
return b"\x1a\x1e\xd1\xd1"
if client.state == 1:
client.state = 2
return b"\x19\x00"
if client.state == 2:
client.state = 3
return b"\xe3\x00\x00", b"\x00\x00\x42\x98\x0c\x11\x33\x45\x30\x42\x33\x33\x35\x32\x37\x34\x46\x39\x31\x43\x39\x39\x00"
if client.state == 3:
client.state = 4
return
if client.state == 4:
client.state = 5
return b"\xe3\x01\x00", b"\x00\x80\x42\x68\x22\xc0\xa8\x02\x87\xfb\xaa\x00\x00\x04\x41\x00\x00"
if client.state <= 7:
client.state += 1
return
if client.state == 8:
client.state = 9
return b"\xe5\x02\x00\x02\x00\x02\x80\x00"
if client.state == 9:
client.state = 10
return b"\x01\x00\x32\x28\x06\xbf\xf9\xca\x0f\x03\x00\x87\x00\x29\x04\x00\x64\x90\x09\xaa\xf9\xca\x0f\xbf\xf9\xca\x0f\x05\x00\x87\x00\x17", b"\x03\x00\x32\x28\x06\xc5\xf9\xca\x0f"
if client.state == 10:
client.state = 11
return b"\x03\x80\x32\x48\x09\xb0\xf9\xca\x0f\xd1\xf9\xca\x0f"
if client.state == 11:
client.state = 12
return b"\xe3\x07\x00"
if client.state == 12:
client.state = 13
return b"\x04\x00\x48\x80\x00\x11\xe0\x14\x3c\xe2\x0e\x2f\x9c\xa0\xf0\x09\x00\x91\x00\x80\x0f\xc1\x00\x14\x8b\xcb\x61\x00\x00\x80\x38\x8d\x00\x00\x8c\x42\x40\x20\x00\x00\x00\x00\x10\x10\x00\x00\x00\xc0\x16\xf1\x20\x33\xc0\x00\x00\x00\x00\xa0\x00\x00\x00\xa0\x00\x00\x00\xa0\x00\x00\x00\x08\x00\x00\x00\x04\x00\x00\x00\x05\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
if client.state == 13:
client.state = 14
return
if client.state == 14:
client.state = 15
return b"\xe3\x0a\x00", b"\x05\x00\x48\x80\x80\x13\xe0\x14\x0c\xe6\x01\xbc\xcf\x44\x40\x8e\x5a\x74\x45\xdf\xe7\x54\x10\x0b\x00\x91\x01\x80\x27\xc0\x14\x9d\xe6\x01\xbc\xcf\x44\x40\x8e\x5a\x74\x45\xdf\xe7\x54\x10\x0c\x00\x91\x02\x00\x28\x40\x14\x9e\xe6\x81\xbc\xcf\x44\x40\x8e\x5a\x74\x45\xdf\xe7\x54\x10\x20\x0d\x00\x82\x6c\x04\x14\x80\xcf\x00\x20\x3f\xe0\x00\x00\x00\x00\x03\x79\x9e\x88\x81\x1c\xb4\xe8\x8b\xbf\xce\xa8\x27\xb2\x50\xc8\x60\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
if client.state == 15:
client.state = 16
return
if client.state == 16:
client.state = 17
return b"\xe3\x0b\x00", b"\x07\x00\x42\x20\x14\x81\xf8\x01"
if client.state == 17:
client.state = 18
return
if client.state == 18:
#client.state = 19
return b"\xe3\x0c\x00", b"\x07\x80\x38\x40\x00\x11\x40\xd0\x00\x00\x00\x00"
"""

View File

@ -1,16 +1,24 @@
import struct import struct
import logging
from objects import glob from objects import glob
from helpers import dataHelper from helpers import dataHelper
def handle(client, data): logger = logging.getLogger(__name__)
ping_ip = ".".join((str(x) for x in struct.unpack(b"<BBBB", data[4:8]))) logger.propagate = False # Disable console logging
print("![{}] -> Pinging to {}".format(client.addr, ping_ip)) def handle(client, data):
ping_ip = ".".join((str(x) for x in struct.unpack(b"<4B", data[4:8])))
ping_port = struct.unpack(b"<H", data[9:11])[0]
logger.debug("[%s] -> Pinging to %s:%d" % (client.addr, ping_ip, ping_port))
if len(data) == 11: # We should add our data ontop if len(data) == 11: # We should add our data ontop
if data[-1:] in RESPONSE: if data[-1:] in RESPONSE:
data += RESPONSE[data[-1:]]() data += RESPONSE[data[-1:]]()
logger.debug("[%s] <- %s" % (client.addr, data))
return data return data
def query_i(): def query_i():
@ -53,7 +61,7 @@ def query_r():
def query_c(): def query_c():
packet_data = [] packet_data = []
players_scores = get_players_scores() players_scores = get_players_scores()
packet_data.append(len(players_scores)) packet_data.append(len(players_scores))
@ -62,13 +70,13 @@ def query_c():
len(name), name, len(name), name,
value value
]) ])
flat_packet_data = dataHelper.flatten(packet_data) flat_packet_data = dataHelper.flatten(packet_data)
packet = struct.pack(b"<H" + b"B%dsI" * flat_packet_data[0] packet = struct.pack(b"<H" + b"B%dsI" * flat_packet_data[0]
% tuple(len(x) for x in players_scores.keys()), % tuple(len(x) for x in players_scores.keys()),
*flat_packet_data) *flat_packet_data)
return packet return packet
def query_d(): def query_d():
@ -109,4 +117,4 @@ RESPONSE = { #TODO?: p (https://wiki.sa-mp.com/wiki/Query_Mechanism) (We dont re
b"r": query_r, b"r": query_r,
b"c": query_c, b"c": query_c,
b"d": query_d b"d": query_d
} }

View File

@ -0,0 +1,16 @@
import struct
index = 0
def handle(client: "Client", data: bytes) -> bytes:
global index
data = LOOKUP[index]
client.send_immediate(data[:3])
index = (index + 1) % 2
return data[3:]
LOOKUP = [
bytes([int(x,16) for x in "e3 00 00 00 00 42 98 0c 11 33 30 45 39 33 39 33 33 36 39 42 35 36 38 43 32 00".split(" ")]),
bytes([int(x,16) for x in "e3 01 00 00 80 42 68 22 c0 a8 02 85 dc f8 01 00 e0 57 00 00".split(" ")])
]

View File

@ -0,0 +1,58 @@
import struct
from random import randint
from helpers.checksumHelper import CheckSum
from network.enums import types as TYPE
TEA_ROUNDS = 32
TEA_XOR_MASK = 0x5E94A3CF
KEY = []
def EncryptBlock(v0, v1):
sum = 0
for i in range(TEA_ROUNDS):
v0 += ((v1 << 4 ^ v1 >> 5) + v1) ^ (sum + key[sum & 3])
def Encrypt(var_input): # bytes
var_input_len = len(var_input) + TYPE.SIZEOF_CHAR * 2 # (checksum, encodedPad)
paddingBytes = 0
if var_input_len % 8 != 0:
paddingBytes = 8 - (var_input_len % 8)
finalLen = var_input_len + paddingBytes
# Randomize pad size for some reason
encodedPad = randint(0, TYPE.MAX_UCHAR)
encodedPad <<= 4
encodedPad &= 0xF0 # Remove bits lost from UCHAR size (C) [BYTE MAGIC]
encodedPad |= paddingBytes
var_output = [0] * finalLen #bytes(finalLen)
var_output[2 + paddingBytes:] = [b for b in var_input]
# Write the pad size variable
var_output[1] = encodedPad
# Write the padding
var_output[2:2+len(paddingBytes)] = bytes([randint(0, TYPE.MAX_UCHAR) for _ in range(len(paddingBytes))])
# Calculate checksum
checksum = CheckSum()
checksum.add(var_output[1:var_input_len + 1 + paddingBytes])
var_checksum = checksum.get()
var_checksum = (var_checksum << 4) ^ var_checksum
var_checksum &= TYPE.MAX_UCHAR # [BYTE MAGIC]
var_output[0] = var_checksum
# Encryption
for i in range(0, finalLen, 8):
v0 = var_output[i]
v1 = var_output[i + TYPE.SIZEOF_INT]
return bytes(var_output)

View File

@ -0,0 +1,3 @@
from . import dataHelper
from . import TEABlockEncryptor
from . import checksumHelper

2
helpers/byteFormater.py Normal file
View File

@ -0,0 +1,2 @@
def readable_bytes(byteStream: bytes) -> str:
return " ".join([(hex(b) if b >= 16 else hex(b).replace("x", "x0"))[2:] for b in byteStream])

25
helpers/checksumHelper.py Normal file
View File

@ -0,0 +1,25 @@
from network.enums import types as TYPE
# TODO: Single function if Object's state is not needed
class CheckSum:
def __init__(self):
self.clear()
def clear(self):
self.sum = 0
self.r = 55665
self.c1 = 52845
self.c2 = 22719
def add(self, byteArray):
[self._add(b) for b in byteArray]
def _add(self, byte):
cipher = byte ^ (self.r >> 8)
cipher &= TYPE.MAX_UCHAR # [BYTE MAGIC]
self.r = (cipher + self.r) * self.c1 + self.c2
self.r &= TYPE.MAX_USHORT # [BYTE MAGIC]
self.sum += cipher
def get(self):
return self.sum

14
main.py
View File

@ -1,32 +1,30 @@
from importlib import reload from importlib import reload
import sys import sys
import socket import socket
import json import json
import logging
from objects import glob from objects import glob
from objects.server import Server from objects.server import Server
from objects import client from objects import client
if __name__ == "__main__": logger = logging.getLogger(__name__)
print("> Loading config")
with open("config.json", "r") as f:
glob.config = json.load(f)
print("> Starting server") if __name__ == "__main__":
logger.info("> Starting server...")
glob.server = Server(glob.config["host"], glob.config["port"]) glob.server = Server(glob.config["host"], glob.config["port"])
glob.server.start() glob.server.start()
# Terminal loop # Terminal loop
while True: while True:
try: try:
cmd = input("> ") cmd = input()
if cmd == "quit" or cmd == "exit" or cmd == "stop": if cmd == "quit" or cmd == "exit" or cmd == "stop":
exit(0) exit(0)
else: else:
print("> Restarting...") logger.info("> Restarting...")
client.restart() client.restart()
"""for module in sys.modules.values(): """for module in sys.modules.values():
reload(module) reload(module)

3
network/__init__.py Normal file
View File

@ -0,0 +1,3 @@
from . import enums
from . import compression

50
network/compression.py Normal file
View File

@ -0,0 +1,50 @@
import logging
from objects import glob
# Found @ addr 0x004C88E0
LOOKUP_TABLE = b"\xb4b\x07\xe5\x9d\xafc\xdd\xe3\xd0\xcc\xfe\xdc\xdbk.j@\xabG\xc9\xd1S\xd5 \x91\xa5\x0eJ\xdf\x18\x89\xfdo%\x12\xb7\x13w\x00e6mI\xecW*\xa9\x11_\xfax\x95\xa4\xbd\x1e\xd9yD\xcd\xde\x81\xeb\t>\xf6\xee\xda\x7f\xa3\x1a\xa7-\xa6\xad\xc1F\x93\xd2\x1b\x9c\xaa\xd7NKML\xf3\xb84\xc0\xca\x88\xf4\x94\xcb\x0490\x82\xd6s\xb0\xbf\"\x01AnH,\xa8u\xb1\n\xae\x9f\'\x80\x10\xce\xf0)(\x85\r\x05\xf75\xbb\xbc\x15\x06\xf5`q\x03\x1f\xeaZ3\x92\x8d\xe7\x90[\xe9\xcf\x9e\xd3]\xed1\x1c\x0bR\x16Q\x0f\x86\xc5h\x9b!\x0c\x8bB\x87\xffO\xbe\xc8\xe8\xc7\xd4z\xe0U/\x8a\x8e\xba\x987\xe4\xb28\xa1\xb62\x83:{\x84<a\xfb\x8c\x14=C;\x1d\xc3\xa2\x96\xb3\xf8\xc4\xf2&+\xd8|\xfc#$f\xefidPTY\xf1\xa0t\xac\xc6}\xb5\xe6\xe2\xc2~g\x17^\xe1\xb9?lp\x08\x99EVv\xf9\x9a\x97\x19r\\\x02\x8fX"
logger = logging.getLogger(__name__)
def uncompress(byteStream: bytes) -> bytearray:
"""Uncompress client packet.
This is actually a deobfuscation as there is no compression involved anymore
as zlib was removed and just swapped with this implementation after the leak.
Arguments:
byteStream {bytes} -- Bytes sent by client
"""
checksum, data = byteStream[0], bytearray(byteStream[1:])
data = xor_every_other_byte(get_port_xor_key(), data)
data = run_though_lookup_table(data)
if checksum != calc_checksum(data):
logger.error("Checksum failed!\n\tExpected: %d\n\tGot: %d" % (checksum, calc_checksum(data)))
raise Exception("Checksum failed!")
return data
def xor_every_other_byte(xor, byteStream: bytearray):
# xor: (server_port ^ 0xCCCC) & 0xFF
for i in range(1, len(byteStream), 2):
byteStream[i] = byteStream[i] ^ xor
return byteStream
def run_though_lookup_table(byteStream: bytes):
return bytearray([LOOKUP_TABLE[b] for b in byteStream])
def calc_checksum(byteStream: bytes):
checksum = 0
for i in range(len(byteStream)):
checksum = checksum ^ byteStream[i] & 0xAA
return checksum
# It should be faster to call a function and do an if, then to read the property of a dict and do bit operations after
_port_xor_key = None
def get_port_xor_key():
global _port_xor_key
if _port_xor_key is None:
_port_xor_key = (glob.config["port"] ^ 0xCCCC) & 0xFF
return _port_xor_key

View File

@ -0,0 +1,2 @@
MTU_SIZE = 576
UDP_HEADER_SIZE = 28

View File

@ -0,0 +1,4 @@
from . import packetTypeRaknet
from . import packetTypeSamp
from . import packetRPC
from . import types

137
network/enums/packetRPC.py Normal file
View File

@ -0,0 +1,137 @@
# netrpc (client)
RPC_ServerJoin = "xy"
RPC_ServerQuit = "ab"
RPC_InitGame = "ac"
RPC_VehicleSpawn = "am"
RPC_VehicleDestroy = "an"
RPC_SetCheckpoint = "ao"
RPC_DisableCheckpoint = "ap"
RPC_SetRaceCheckpoint = "aq"
RPC_DisableRaceCheckpoint = "ar"
RPC_GameModeRestart = "at"
RPC_ConnectionRejected = "au"
RPC_ClientMessage = "av"
RPC_WorldTime = "aw"
RPC_Pickup = "ax"
RPC_DestroyPickup = "ay"
RPC_DestroyWeaponPickup = "az"
RPC_Weather = "bb"
RPC_Instagib = "bc"
RPC_SetTimeEx = "be"
RPC_ToggleClock = "bf"
# netrpc (both)
RPC_Chat = "ad"
RPC_Privmsg = "ae"
RPC_TeamPrivmsg = "af"
RPC_RequestClass = "ag"
RPC_RequestSpawn = "ah"
RPC_Spawn = "ai"
RPC_Death = "aj"
RPC_EnterVehicle = "ak"
RPC_ExitVehicle = "al"
RPC_UpdateScoresPingsIPs = "as"
RPC_SvrStats = "em"
RPC_ScmEvent = "ba"
# scriptrpc
RPC_ScrSetSpawnInfo = "bg"
RPC_ScrSetPlayerTeam = "bh"
RPC_ScrSetPlayerSkin = "bi"
RPC_ScrSetPlayerName = "bj"
RPC_ScrSetPlayerPos = "bk"
RPC_ScrSetPlayerPosFindZ = "bl"
RPC_ScrSetPlayerHealth = "bm"
RPC_ScrPutPlayerInVehicle = "bn"
RPC_ScrRemovePlayerFromVehicle = "bo"
RPC_ScrSetPlayerColor = "bp"
RPC_ScrDisplayGameText = "bq"
RPC_ScrSetInterior = "br"
RPC_ScrSetCameraPos = "bs"
RPC_ScrSetCameraLookAt = "bt"
RPC_ScrSetVehiclePos = "bu"
RPC_ScrSetVehicleZAngle = "bv"
RPC_ScrVehicleParams = "bw"
RPC_ScrSetCameraBehindPlayer = "bx"
RPC_ScrTogglePlayerControllable = "by"
RPC_ScrPlaySound = "bz"
RPC_ScrSetWorldBounds = "ca"
RPC_ScrHaveSomeMoney = "cb"
RPC_ScrSetPlayerFacingAngle = "cc"
RPC_ScrResetMoney = "cd"
RPC_ScrResetPlayerWeapons = "ce"
RPC_ScrGivePlayerWeapon = "cf"
RPC_ScrRespawnVehicle = "cg"
RPC_ScrLinkVehicle = "ch"
RPC_ScrSetPlayerArmour = "ci"
RPC_ScrDeathMessage = "cj"
RPC_ScrSetMapIcon = "ck"
RPC_ScrDisableMapIcon = "cl"
RPC_ScrSetWeaponAmmo = "cm"
RPC_ScrSetGravity = "cn"
RPC_ScrSetVehicleHealth = "co"
RPC_ScrAttachTrailerToVehicle = "cp"
RPC_ScrDetachTrailerFromVehicle = "cq"
RPC_ScrCreateObject = "cr"
RPC_ScrSetObjectPos = "cs"
RPC_ScrSetObjectRotation = "ct"
RPC_ScrDestroyObject = "cu"
RPC_ScrSetPlayerVirtualWorld = "cv"
RPC_ScrSetVehicleVirtualWorld = "cw"
RPC_ScrCreateExplosion = "cx"
RPC_ScrShowNameTag = "cy"
RPC_ScrMoveObject = "cz"
RPC_ScrStopObject = "da"
RPC_ScrNumberPlate = "db"
RPC_ScrTogglePlayerSpectating = "dc"
RPC_ScrSetPlayerSpectating = "dd"
RPC_ScrPlayerSpectatePlayer = "de"
RPC_ScrPlayerSpectateVehicle = "df"
RPC_ScrRemoveComponent = "dg"
RPC_ScrForceSpawnSelection = "dh"
RPC_ScrAttachObjectToPlayer = "dt"
RPC_ScrInitMenu = "du"
RPC_ScrShowMenu = "dv"
RPC_ScrHideMenu = "dw"
RPC_ScrSetPlayerWantedLevel = "dz"
RPC_ScrShowTextDraw = "ea"
RPC_ScrHideTextDraw = "eb"
RPC_ScrEditTextDraw = "ee"
RPC_ScrAddGangZone = "ef"
RPC_ScrRemoveGangZone = "eg"
RPC_ScrFlashGangZone = "eh"
RPC_ScrStopFlashGangZone = "ei"
RPC_ScrApplyAnimation = "eo"
RPC_ScrClearAnimations = "eq"
RPC_ScrSetSpecialAction = "ep"
RPC_ScrEnableStuntBonus = "ec"
RPC_ScrUsePlayerPedAnims = "a1"
RPC_ScrToggleVehicleMarker = "a4"
RPC_ScrMoveTextdraw = "a5"
RPC_ScrSetPlayerVisibleInScoreBoard = "a6"
# netrpc (server)
RPC_ClientJoin = "xx"
RPC_ServerCommand = "dj"
RPC_SetInteriorId = "dk"
RPC_ClickMap = "dl"
RPC_VehicleDestroyed = "dm"
RPC_PickedUpWeapon = "dn"
RPC_PickedUpPickup = "do"
RPC_MenuSelect = "dx"
RPC_MenuQuit = "dy"
RPC_UnderMapTeleport = "a2"
RPC_ResolutionChanged = "a3"
# rcon
RPC_RconConnect = "dp"
RPC_RconCommand = "dq"
RPC_RconEvent = "dr"
RPC_RconPlayerInfo = "ds"
# anticheat
RPC_ACAuthRequest = "ej"
RPC_ACAuthResponse = "ek"
RPC_ACAuthEngineLoaded = "el"
RPC_ACServerProtected = "bd"

View File

@ -0,0 +1,113 @@
INTERNAL_PING = 0x00
PING = 0x01
PING_OPEN_CONNECTIONS = 0x02
CONNECTED_PONG = 0x03
REQUEST_STATIC_DATA = 0x04
CONNECTION_REQUEST = 0x05
SECURED_CONNECTION_RESPONSE = 0x06
SECURED_CONNECTION_CONFIRMATION = 0x07
RPC_MAPPING = 0x08
DETECT_LOST_CONNECTIONS = 0x09
OPEN_CONNECTION_REQUEST = 0x0a
OPEN_CONNECTION_REPLY = 0x0b
RPC = 0x0c
RPC_REPLY = 0x0d
BROADCAST_PINGS = 0x0e
SET_RANDOM_NUMBER_SEED = 0x0f
CONNECTION_REQUEST_ACCEPTED = 0x10
CONNECTION_ATTEMPT_FAILED = 0x11
NEW_INCOMING_CONNECTION = 0x18
NO_FREE_INCOMING_CONNECTIONS = 0x13
DISCONNECTION_NOTIFICATION = 0x14
CONNECTION_LOST = 0x15
RSA_PUBLIC_KEY_MISMATCH = 0x16
CONNECTION_BANNED = 0x17
INVALID_PASSWORD = 0x18
MODIFIED_PACKET = 0x19
TIMESTAMP = 0x1a
PONG = 0x1b
RECEIVED_STATIC_DATA = 0x1c
REMOTE_DISCONNECTION_NOTIFICATION = 0x1d
REMOTE_CONNECTION_LOST = 0x1e
REMOTE_NEW_INCOMING_CONNECTION = 0x1f
REMOTE_EXISTING_CONNECTION = 0x20
REMOTE_STATIC_DATA = 0x21
FILE_LIST_TRANSFER_HEADER = 0x22
FILE_LIST_TRANSFER_FILE = 0x23
DDT_DOWNLOAD_REQUEST = 0x24
QUERY_MASTER_SERVER = 0x25
MASTER_SERVER_DELIST_SERVER = 0x26
MASTER_SERVER_UPDATE_SERVER = 0x27
MASTER_SERVER_SET_SERVER = 0x28
RELAYED_CONNECTION_NOTIFICATION = 0x29
ADVERTISE_SYSTEM = 0x2a
TRANSPORT_STRING = 0x2b
REPLICA_MANAGER_CONSTRUCTION = 0x2c
REPLICA_MANAGER_DESTRUCTION = 0x2d
REPLICA_MANAGER_SCOPE_CHANGE = 0x2e
REPLICA_MANAGER_SERIALIZE = 0x2f
REPLICA_MANAGER_DOWNLOAD_COMPLETE = 0x30
CONNECTION_GRAPH_REQUEST = 0x31
CONNECTION_GRAPH_REPLY = 0x32
CONNECTION_GRAPH_UPDATE = 0x33
CONNECTION_GRAPH_NEW_CONNECTION = 0x34
CONNECTION_GRAPH_CONNECTION_LOST = 0x35
CONNECTION_GRAPH_DISCONNECTION_NOTIFICATION = 0x36
ROUTE_AND_MULTICAST = 0x37
RAKVOICE_OPEN_CHANNEL_REQUEST = 0x38
RAKVOICE_OPEN_CHANNEL_REPLY = 0x39
RAKVOICE_CLOSE_CHANNEL = 0x3a
RAKVOICE_DATA = 0x3b
AUTOPATCHER_GET_CHANGELIST_SINCE_DATE = 0x3c
AUTOPATCHER_CREATION_LIST = 0x3d
AUTOPATCHER_DELETION_LIST = 0x3e
AUTOPATCHER_GET_PATCH = 0x3f
AUTOPATCHER_PATCH_LIST = 0x40
AUTOPATCHER_REPOSITORY_FATAL_ERROR = 0x41
AUTOPATCHER_FINISHED = 0x42
AUTOPATCHER_RESTART_APPLICATION = 0x43
NAT_PUNCHTHROUGH_REQUEST = 0x44
NAT_TARGET_NOT_CONNECTED = 0x45
NAT_TARGET_CONNECTION_LOST = 0x46
NAT_CONNECT_AT_TIME = 0x47
NAT_SEND_OFFLINE_MESSAGE_AT_TIME = 0x48
DATABASE_QUERY_REQUEST = 0x49
DATABASE_UPDATE_ROW = 0x4a
DATABASE_REMOVE_ROW = 0x4b
DATABASE_QUERY_REPLY = 0x4c
DATABASE_UNKNOWN_TABLE = 0x4d
DATABASE_INCORRECT_PASSWORD = 0x4e

View File

20
network/enums/types.py Normal file
View File

@ -0,0 +1,20 @@
SIZEOF_CHAR = 1
SIZEOF_SHORT = 2
SIZEOF_INT = 4
SIZEOF_LONG = 4
SIZEOF_LONG_LONG = 8
SIZEOF_FLOAT = 4
SIZEOF_DOUBLE = 8
MAX_CHAR = 0x7F
MAX_UCHAR = 0xFF
MAX_SHORT = 0x7FFF
MAX_USHORT = 0xFFFF
MAX_INT = 0x7FFFFFFF
MAX_UINT = 0xFFFFFFFF # 1 << SIZEOF_INT * 8 - 1 (I had a dream of doing it this way.. but Robin said no >.>)
MAX_LONG = 0x7FFFFFFF
MAX_ULONG = 0xFFFFFFFF
MAX_LONG_LONG = 0x7FFFFFFFFFFFFFFF
MAX_ULONG_LONG = 0xFFFFFFFFFFFFFFFF

20
notes/1.txt Normal file
View File

@ -0,0 +1,20 @@
---Packet---
17 7f 00 00 01 1c fb 00 00 df 2f 00 00
xx xx xx ?? ?? ?? ?? xx xx xx xx xx xx
---RTC---
ID: xx
BitStream: 87 15 00 00 01 05 53 75 6e 70 79 00 00 00 00 00 ee dd 60 3d 00 01 00 80 01 01 00 00 00 00 00 05 12 00 00 00 00 00 00 00 e3 dd 63 3d 00 02 00 88 58 0b b4 00 58 19 b4 00 e8 0d b4 00 08 18 b4 00 e4 dd 66 3d 00 03 00 88 e0 0d b4 00 a8 13 b4 00 90 0b b4 00 20 19 b4 00
---Packet---
26
---Packet---
15 7f 00 00 01 1c fb ff ff
xx xx xx ?? ?? ?? ?? xx xx
^ Same pattern as earlier
Seem to increment over time?
C:\Users\Emily\Downloads\samp-1-master\samp-1-master\testbot\.\Debug\bot.exe (process 8620) exited with code 1.
To automatically close the console when debugging stops, enable Tools->Options->Debugging->Automatically close the console when debugging stops.
Press any key to close this window . . .

15
notes/1_1.txt Normal file
View File

@ -0,0 +1,15 @@
---Packet---
17 7f 00 00 01 7e eb 00 00 df 2f 00 00
---RTC---
ID: xx
BitStream: 87 15 00 00 01 05 53 75 6e 70 79 00 00 00 00 00 f7 94 49 05 00 10 00 8c 01 01 00 00 00 00 00 05 14 00 00 00 00 00 00 00 fa 94 44 05 00 11 00 8c 38 18 55 00 08 6f 88 00 00 00 00 00 00 00 00 00 fd 94 47 05 00 12 00 8c c8 17 55 00 4b 5e 88 00 00 00 00 00 00 00 00 00
---Packet---
26
---Packet---
15 7f 00 00 01 7e eb ff ff
C:\Users\Emily\Downloads\samp-1-master\samp-1-master\testbot\.\Debug\bot.exe (process 16152) exited with code 1.
Press any key to close this window . . .

25
notes/2.txt Normal file
View File

@ -0,0 +1,25 @@
---RTC SEND---
BitStream: 60 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 17 44 5a 5c 00 05 00 8c 53 00 45 00 52 00 4e 00 41 00 4d 00 45 00 3d 00 1a 44 59 5c 69 06 00 80 79 00 00 00 55 00 53 00 45 00 52 00 50 00 52 00 4f 00 46 00 49 00 4c 00 60 05 d3 00 43 00 3a 00 1f 44 42 5c 73 06 00 88 80 39 2c 6f a8 c3 2c 6f 00 00 00 00 00 00 00 00 78 59 ad eb 72 c1 d7 4a a2 fb 1d bd 77 96 84 a5 00 00 00 00 d4 5e 00 00 78 59 ad eb 72 c1 d7 4a a2 fb 1d bd 77 96 84 a5 e7 45 4a 5c 3d 07 00 88 80 6e 2a 6f 30 05 2b 6f 00 00 00 00 00 00 00 00 37 7f 1f f3 e0 ed ce 44 ab 10 eb 1d 44 e7 81 bf 00 00 00 00 d4 5e 00 00 37 7f 1f f3 e0 ed ce 44 ab 10 eb 1d 44 e7 81 bf ef 45 32 5c 42 08 00 88 80 6e 2a 6f f0 03 2b 6f 00 00 00 00 00 00 00 00 cf 81 bc bb 19 e2 9c 46 a4 05 f8 20 ee 49 61 94 00 00 00 00 d4 5e 00 00 cf 81 bc bb 19 e2 9c 46 a4 05 f8 20 ee 49 61 94 f7 45 3a 5c 6f 09 00 88 80 6e 2a 6f 80 05 2b 6f 00 00 00 00 00 00 00 00 73 6c 8d 0f d5 6b af 45 8f 1f 19 07 0a 40 43 9c 00 00 00 00 d4 5e 00 00 73 6c 8d 0f d5 6b af 45 8f 1f 19 07 0a 40 43 9c ff 45 22 5c 00 0a 00 88 4e 00 54 00 20 00 41 00 75 00 74 00 68 00 6f 00 72 00 69 00 74 00 79 00 5c 00 4e 00 65 00 74 00 77 00 6f 00 72 00 6b 00
---Packet---
17 7f 00 00 01 00 fd 00 00 78 38 00 00
---RTC---
ID: xx
BitStream: 87 15 00 00 01 05 53 75 6e 70 79 00 00 00 00 00 5e 01 4d 5c 00 12 00 88 10 0e d6 00 70 15 d6 00 38 0f d6 00 10 18 d6 00 21 01 48 5c 00 13 00 88 f8 0d d6 00 c0 16 d6 00 f0 0e d6 00 11 18 d6 00 24 01 37 5c 00 14 00 8c f0 11 d6 00 e6 45 ad 00 00 00 00 00 00 00 00 00
---RTC SEND---
BitStream: 60 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 b6 33 d3 5d 00 34 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 be 33 db 5d 00 35 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 86 33 c3 5d 00 36 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 8e 33 cb 5d 00 37 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 96 33 b3 5d 00 38 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 9e 33 bb 5d 00 39 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
---Packet---
26
---Packet---
15 7f 00 00 01 00 fd ff ff
---RTC SEND---
BitStream: 60 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 5e 32 7b 5d 00 21 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 26 32 63 5d 00 22 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 2e 32 6b 5d 00 23 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 36 32 53 5d 00 24 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3e 32 5b 5d 00 25 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 06 32 43 5d 00 26 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
C:\Users\Emily\Downloads\samp-1-master\samp-1-master\testbot\.\Debug\bot.exe (process 24276) exited with code 1.
To automatically close the console when debugging stops, enable Tools->Options->Debugging->Automatically close the console when debugging stops.
Press any key to close this window . . .

25
notes/2_1.txt Normal file
View File

@ -0,0 +1,25 @@
---RTC SEND---
BitStream: 60 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 82 52 16 af 6f 10 00 88 c0 c9 ee 77 ff ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00 d0 07 00 0a f8 01 00 00 00 00 00 00 fc 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 a0 c9 ee 77 9a 52 1e af 5c 11 00 88 80 6e 2a 6f d0 05 2b 6f 00 00 00 00 00 00 00 00 65 69 e6 53 fd fc da 4c a5 20 34 fa 34 59 9a 7f 00 00 00 00 7c 2d 00 00 65 69 e6 53 fd fc da 4c a5 20 34 fa 34 59 9a 7f 92 52 06 af 50 12 00 88 c0 a9 45 71 00 87 48 71 00 00 00 00 00 00 00 00 d2 00 16 5a e5 68 e7 4d bc f4 1c 2d 21 5f e0 fe 00 00 00 00 7c 2d 00 00 d2 00 16 5a e5 68 e7 4d bc f4 1c 2d 21 5f e0 fe aa 52 0e af 56 13 00 88 80 6e 2a 6f 40 04 2b 6f 00 00 00 00 00 00 00 00 f6 89 84 88 de 5d b8 47 85 06 e5 bb c4 0e 81 d1 00 00 00 00 7c 2d 00 00 f6 89 84 88 de 5d b8 47 85 06 e5 bb c4 0e 81 d1 a2 52 36 af 6b 14 00 8c 74 00 73 00 00 00 6f 00 bc 52 34 af 00 17 00 80 4e 00 4f 00 5f 00 44 00 45 00 42 00 55 00 47 00 5f 00 48 00 45 00 41 00 50 00 3d 00 31 00 00 00 60 05 ef 00 00 00 00 00 ba 52 3e af db 15 00 88 90 bd 11 74 40 b7 12 74 00 00 00 00 00 00 00 00 05 4a 00 eb 1a 9b d4 11 91 23 00 50 04 77 59 bc 00 00 00 00 7c 2d 00 00
---Packet---
17 7f 00 00 01 fc f7 00 00 78 38 00 00
---RTC---
ID: xx
BitStream: 87 15 00 00 01 05 53 75 6e 70 79 00 48 28 f3 00 75 16 a7 af 00 10 00 80 01 01 00 00 00 00 00 05 13 00 00 00 00 00 00 00 76 16 aa af 00 11 00 88 e0 0d f2 00 20 1b f2 00 f8 0c f2 00 e8 1a f2 00 73 16 a9 af 00 12 00 8c 80 04 f2 00 b0 62 ad 00 00 00 00 00 00 00 00 00
---RTC SEND---
BitStream: 60 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 27 af ae 00 27 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 28 27 d7 ae 00 28 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 27 df ae 00 29 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 38 27 c7 ae 00 2a 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 30 27 cf ae 00 2b 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 c8 26 f7 ae 00 2c 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
---Packet---
26
---Packet---
15 7f 00 00 01 fc f7 ff ff
---RTC SEND---
BitStream: 60 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 a0 26 5f ae 00 39 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 b8 26 47 ae 00 3a 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 b0 26 4f ae 00 3b 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 48 26 77 ae 00 3c 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 26 7f ae 00 3d 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 58 26 67 ae 00 3e 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
C:\Users\Emily\Downloads\samp-1-master\samp-1-master\testbot\.\Debug\bot.exe (process 11644) exited with code 1.
To automatically close the console when debugging stops, enable Tools->Options->Debugging->Automatically close the console when debugging stops.
Press any key to close this window . . .

2
notes/const.md Normal file
View File

@ -0,0 +1,2 @@
UDP_HEADER_SIZE = 28

7
notes/notes.md Normal file
View File

@ -0,0 +1,7 @@
availableBandwidth -= updateBitStream.GetNumberOfBitsUsed() + UDP_HEADER_SIZE * 8 # -224
GenerateDatagram( &updateBitStream, MTUSize, &reliableDataSent, time, playerId, messageHandlerList )
updateBitStream:

21
notes/packet.md Normal file
View File

@ -0,0 +1,21 @@
|Key|Value|
|---|---|
|---|---|
|Name|ID_OPEN_CONNECTION_REQUEST|
|id|10|
|0|packetID|
|1|0|
|---|---|
|---|---|
|Name|ID_OPEN_CONNECTION_REPLY|
|id|11|
|0|packetID|
|1|0|
|---|---|
|---|---|
|Name|ID_NO_FREE_INCOMING_CONNECTIONS|
|id|1B|
|0|packetID|
|1|0|
|---|---|
|---|---|

View File

@ -1,49 +1,78 @@
from importlib import reload from importlib import reload
import socket import socket
from handlers import serverPingHandler, mainHandler import logging
import struct
from network.compression import uncompress
from handlers import serverQueryHandler, mainHandler
from helpers.byteFormater import readable_bytes
logger = logging.getLogger(__name__)
class Client: class Client:
BUFF_SIZE = 65535 BUFF_SIZE = 65535
HANDLERS = { HANDLERS = {
b"SAMP": serverPingHandler b"SAMP": serverQueryHandler.handle
} }
def __init__(self, server, addr): def __init__(self, server: "Server", addr: "Address"):
self.server = server self.server = server
self.ip_uint = struct.unpack(b"<I", bytes(int(x) for x in addr[0].split(".")))[0]
self.addr = addr self.addr = addr
self.state = 0 self.state = 0
self.__writebuffer = [] self.__writebuffer = bytearray()
def handle_data(self, data): def handle_data(self, data: bytes):
found = False found = False
for pattern, handler in self.HANDLERS.items(): for pattern, handle in self.HANDLERS.items(): # SAMP query
if data.startswith(pattern): if data.startswith(pattern):
queue = handler.handle(self, data) queue = handle(self, data)
if queue: if queue:
self.write_to_buffer(queue) self.write_to_buffer(queue)
found = True found = True
if not found: if not found:
queue = mainHandler.handle(self, data) # deobfuscate
if queue: try:
data: bytearray = uncompress(data)
logger.debug("[%s] -> %s" % (self.addr, readable_bytes(data)))
queue = mainHandler.handle(self, data)
except Exception as err:
logger.error(err)
finally:
if queue:
self.write_to_buffer(queue) self.write_to_buffer(queue)
#print("?[{}] -> {} / {}".format(self.addr, data, data.hex()))
def write_to_buffer(self, data): def write_to_buffer(self, data: bytes):
if type(data) == bytes: if type(data) == int:
self.__writebuffer.append(data) self.__writebuffer.append(data)
elif type(data) == list:
for item in data:
self.write_to_buffer(item)
else: else:
self.__writebuffer += data self.__writebuffer += data
def write_buffer_size(self): def get_buffer_size(self) -> int:
return len(self.__writebuffer) return len(self.__writebuffer)
def write_socket(self): def write_socket(self):
if len(self.__writebuffer) > 0: if self.get_buffer_size() > 0:
write_chunk = self.__writebuffer.pop(0) #write_chunk = self.__writebuffer.pop(0)
print("[{}] <- {}".format(self.addr, write_chunk)) #logger.debug("[%s] <- %s" % (self.addr, write_chunk))
self.server.socket.sendto(write_chunk, self.addr) logger.debug("[%s] <- %s" % (self.addr, readable_bytes(self.__writebuffer)))
self.server.socket.sendto(self.__writebuffer, self.addr)
self.__writebuffer.clear()
def send_immediate(self, data: bytes):
logger.debug("[%s] <- %s" % (self.addr, readable_bytes(data)))
self.server.socket.sendto(data, self.addr)
def restart(): def restart():
reload(serverPingHandler) reload(serverQueryHandler)
reload(mainHandler)
mainHandler.restart()

View File

@ -1,2 +1,47 @@
import sys
import json
import logging
from random import randint
from network.enums import types as TYPE
# ---------------------------------------------------------------------------
# public
config = None config = None
server = None server = None
challenge_short = None
# ---------------------------------------------------------------------------
with open("config.json", "r") as f:
config = json.load(f)
# fix for logging level
default_logging_fallback = False
if type(config["logging"]["level"]) is not int:
try:
config["logging"]["level"] = getattr(logging, config["logging"]["level"])
except:
config["logging"]["level"] = logging.INFO
default_logging_fallback = True
# Setup logging settings
logging_handlers = [logging.StreamHandler(sys.stdout)]
if len(config["logging"]["filename"]):
logging_handlers.append(logging.FileHandler(config["logging"]["filename"]))
del config["logging"]["filename"]
logging.basicConfig(**config["logging"], handlers = logging_handlers)
logger = logging.getLogger(__name__)
logger.debug("glob.configured logger")
if default_logging_fallback:
logger.warning("Invalid logging value in config! Defaulting to logging level INFO.")
logger.info("Logging level: %d" % config["logging"]["level"])
# ---------------------------------------------
challenge_short = randint(0, TYPE.MAX_USHORT)
logger.debug("Client challenge set to: %s" % ("0x" if challenge_short & 0x1000 else "0x0") + hex(challenge_short)[2:])

View File

@ -1,10 +1,13 @@
import socket import socket
import select import select
import logging
from threading import Thread from threading import Thread
from .client import Client from .client import Client
logger = logging.getLogger(__name__)
class Server(Thread): class Server(Thread):
BUFF_SIZE = 65535 BUFF_SIZE = 65535
@ -36,18 +39,19 @@ class Server(Thread):
else: else:
try: try:
self.clients[addr] = Client(self, addr) self.clients[addr] = Client(self, addr)
print("[Server] Accepted connection from {}:{}".format(addr[0], addr[1])) logger.info("Accepted connection from %s:%s" % (addr[0], addr[1]))
self.clients[addr].handle_data(data) self.clients[addr].handle_data(data)
except socket.error: except socket.error:
try: try:
self.socket.close() self.socket.close()
except: except:
pass pass
print("[Server] Something went very wrong...") logger.warn("Something went very wrong...")
exit() #exit()
return
clients = [x for x in self.clients.values() clients = [x for x in self.clients.values()
if x.write_buffer_size() > 0] if x.get_buffer_size() > 0]
for client in clients: for client in clients:
client.write_socket() client.write_socket()

1
proxy_data.json Normal file
View File

@ -0,0 +1 @@
{"id": 14}

66
raknet/bitStream.py Normal file
View File

@ -0,0 +1,66 @@
class BitStream:
def __init__(self, data: array = []):
self.bits_used = 0
self.read_offset = 0
self.data = data
def write(self, c_bytes): # ?bytes_to_write
bytes_to_write = len(c_bytes)
if not len(c_bytes):
return
self.write_bits(c_bytes, bytes_to_write << 3, True)
def read(self, bytes_to_read: int):
bits_to_read = bytes_to_read << 3
if self.read_offset & 7 == 0:
if self.read_offset + bits_to_read > self.bits_used:
return False
read_offset_bytes = self.read_offset >> 3
data = self.data[read_offset_bytes:read_offset_bytes + bytes_to_read]
self.read_offset += bits_to_read
return data
return self.read_bits(bits_to_read)
def read_bits(self, bits_to_read: int, align_right: bool = False):
if bits_to_read <= 0:
return False
if self.read_offset + bits_to_read > self.bits_used:
return False
offset = 0
bits_read_offset_mod8 = self.read_offset & 7
def write_bits(self, c_bytes, bits_to_write: int, align_right: bool = False):
if not bits_to_write:
return
offset = 0
bits_used_mod8 = self.bits_used & 7
while bits_to_write:
byte = c_bytes[offset]
if bits_to_write < 8 and align_right:
byte <<= 8 - bits_to_write
if bits_used_mod8 == 0:
self.data[self.bits_used >> 3] = byte
else:
self.data[self.bits_used >> 3] |= byte >> bits_used_mod8
if 8 - bits_used_mod8 < 8 and 8 - bits_used_mod8 < bits_to_write:
self.data[(self.bits_used >> 3) + 1] = byte << (8 - bits_used_mod8)
if bits_to_write >= 8:
self.bits_used += 8
else:
self.bits_used += bits_to_write
bits_to_write -= 8
offset += 1

1
requirements.txt Normal file
View File

@ -0,0 +1 @@
#PyRakLib>=1.0.15b1