sfs2x-py
Pure Python implementation of the SmartFoxServer 2X binary protocol.
What is SmartFoxServer 2X?
SmartFoxServer 2X (SFS2X) is a real-time multiplayer game server used by many mobile and web games. It communicates over TCP using a custom binary protocol with its own type system (SFSObject/SFSArray), XOR obfuscation on client-to-server packets, optional zlib/zstd compression, and AES session encryption.
This library provides a complete encode/decode implementation of the SFS2X wire protocol in pure Python — useful for protocol analysis, reverse engineering, MITM proxying, and building game bots.
Features
- Full type system: All 19 SFS2X data types (NULL, BOOL, BYTE, SHORT, INT, LONG, FLOAT, DOUBLE, UTF_STRING, arrays, SFS_ARRAY, SFS_OBJECT)
- C2S/S2C packet framing: Encode and decode client-to-server and server-to-client packets
- XOR obfuscation: Rotating 4-byte XOR key derived from packet size
- Compression: zlib and zstd support for large packets
- AES session encryption: Key exchange via
/BlueBox/CryptoManager - Type-preserving decode:
decode_typed()wraps values inTypedValueto preserve wire types (BYTE vs INT) for MITM proxies - Packet builders:
make_extension_request(),make_keepalive(),parse_s2c_command()
Install
pip install sfs2x-py
Or from source:
git clone https://github.com/KeepALifeUS/sfs2x-py.git
cd sfs2x-py
pip install -e ".[dev]"
Quick Start
Encode/decode SFSObject
from sfs2x import SFSCodec, TypedValue, INT
# Encode
obj = {"username": "player1", "level": TypedValue(INT, 42)}
data = SFSCodec.encode(obj)
# Decode
decoded, consumed = SFSCodec.decode(data)
print(decoded) # {'username': 'player1', 'level': 42}
Build an extension request
from sfs2x import make_extension_request, decode_c2s_packet, TypedValue, INT
# Create a C2S packet
packet = make_extension_request(
cmd="chat.send",
params={"msg": "Hello!", "channel": TypedValue(INT, 1)},
server_id=1234,
)
# Decode it back
obj, _ = decode_c2s_packet(packet)
Decode a captured S2C packet
from sfs2x import decode_s2c_packet, parse_s2c_command
raw = bytes.fromhex("80001f...") # paste captured hex
obj, _ = decode_s2c_packet(raw)
cmd, params = parse_s2c_command(obj)
print(f"Command: {cmd}, Params: {params}")
Type-preserving decode for MITM
from sfs2x import decode_c2s_packet_typed
obj, _ = decode_c2s_packet_typed(packet)
# Values are TypedValue instances — re-encoding preserves wire types
Protocol Overview
Wire Format
S2C (server → client):
[0x80] [size: 2B BE] [SFSObject payload]
C2S (client → server):
[0xC4] [server_id: 2B BE] [size: 2B BE] [XOR-obfuscated payload]
[0xE4] [server_id: 2B BE] [size: 2B BE] [XOR(zlib(payload))] (compressed)
SFSObject Structure
The payload is always a root SFSObject with:
"c"→ controller ID (BYTE: 0=system, 1=extension)"a"→ action ID (SHORT)"p"→ parameters (SFS_OBJECT)
Extension commands (c=1, a=13) nest further:
"p"."c"→ command name (UTF_STRING)"p"."r"→ room ID (INT)"p"."p"→ command parameters (SFS_OBJECT)
API Reference
sfs2x.objects
SFSCodec.encode(obj)→bytes— Encode a dict as SFSObjectSFSCodec.decode(data)→(dict, int)— Decode SFSObject, return (dict, bytes_consumed)SFSCodec.decode_typed(data)→(dict, int)— Decode preserving wire types asTypedValueTypedValue(type_id, value)— Force a specific wire type
sfs2x.protocol
encode_c2s_packet(controller, action, params, server_id, compress)→bytesdecode_c2s_packet(data)→(dict, int)decode_c2s_packet_typed(data)→(dict, int)encode_s2c_packet(obj, compress)→bytesdecode_s2c_packet(data)→(dict, int)make_extension_request(cmd, params, room_id, server_id)→bytesmake_keepalive(client_time, server_id)→bytesparse_s2c_command(obj)→(str | None, dict)iter_s2c_packets(data)→ iterator of(dict, offset)
sfs2x.crypto
AESCipher(key, iv)— AES-128-CBC with fixed IVKeyExchange()— Manages key exchange via CryptoManager endpointmake_password_hash(session_token, password)→str— MD5 password hash
License
MIT
Metadata
Release files for sfs2x-py 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sfs2x_py-0.1.1.tar.gz | 18.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sfs2x_py-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 32.3 kB
Release files / sfs2x_py-0.1.1.tar.gz
| Download URL | sfs2x_py-0.1.1.tar.gz |
|---|---|
| Size | 18.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9876566130803c69344804a5c2e63a6c215a9bccac11c7196e0969b40fe3d30d
|
|
BLAKE2b-256 checksum How to use checksums |
7ca60ec93d5610349355ea5375917ca44b432e6716600648a7ed3020ad33b68f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 13, 2026.
Transparency logRelease files / sfs2x_py-0.1.1-py3-none-any.whl
| Download URL | sfs2x_py-0.1.1-py3-none-any.whl |
|---|---|
| Size | 13.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ee0856eabd0f9444b71db40f731fbf64a6483c104800b2ac1765f7a3e6bf1b4a
|
|
BLAKE2b-256 checksum How to use checksums |
24e37a211ffb0678a5d3169a191b08418eac4d521fa81f89c19c748dea6f5b73
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 13, 2026.
Transparency log