Much code, many rewrite
This commit is contained in:
parent
3bdd78b61c
commit
2166a30aa9
8
.vscode/settings.json
vendored
8
.vscode/settings.json
vendored
|
@ -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
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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"
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
53
handlers/old_mainHandler.py
Normal file
53
handlers/old_mainHandler.py
Normal 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"
|
||||||
|
"""
|
|
@ -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
|
||||||
}
|
}
|
16
handlers/unknownHandler.py
Normal file
16
handlers/unknownHandler.py
Normal 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(" ")])
|
||||||
|
]
|
58
helpers/TEABlockEncryptor.py
Normal file
58
helpers/TEABlockEncryptor.py
Normal 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)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
from . import dataHelper
|
||||||
|
from . import TEABlockEncryptor
|
||||||
|
from . import checksumHelper
|
2
helpers/byteFormater.py
Normal file
2
helpers/byteFormater.py
Normal 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
25
helpers/checksumHelper.py
Normal 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
14
main.py
|
@ -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
3
network/__init__.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
from . import enums
|
||||||
|
|
||||||
|
from . import compression
|
50
network/compression.py
Normal file
50
network/compression.py
Normal 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
|
2
network/consts/datasize.py
Normal file
2
network/consts/datasize.py
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
MTU_SIZE = 576
|
||||||
|
UDP_HEADER_SIZE = 28
|
4
network/enums/__init__.py
Normal file
4
network/enums/__init__.py
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
from . import packetTypeRaknet
|
||||||
|
from . import packetTypeSamp
|
||||||
|
from . import packetRPC
|
||||||
|
from . import types
|
137
network/enums/packetRPC.py
Normal file
137
network/enums/packetRPC.py
Normal 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"
|
113
network/enums/packetTypeRaknet.py
Normal file
113
network/enums/packetTypeRaknet.py
Normal 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
|
0
network/enums/packetTypeSamp.py
Normal file
0
network/enums/packetTypeSamp.py
Normal file
20
network/enums/types.py
Normal file
20
network/enums/types.py
Normal 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
20
notes/1.txt
Normal 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
15
notes/1_1.txt
Normal 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
25
notes/2.txt
Normal 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
25
notes/2_1.txt
Normal 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
2
notes/const.md
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
UDP_HEADER_SIZE = 28
|
||||||
|
|
7
notes/notes.md
Normal file
7
notes/notes.md
Normal 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
21
notes/packet.md
Normal 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|
|
||||||
|
|---|---|
|
||||||
|
|---|---|
|
|
@ -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()
|
|
@ -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:])
|
||||||
|
|
|
@ -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
1
proxy_data.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"id": 14}
|
66
raknet/bitStream.py
Normal file
66
raknet/bitStream.py
Normal 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
1
requirements.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
#PyRakLib>=1.0.15b1
|
Reference in New Issue
Block a user