117 lines
4.2 KiB
Python
117 lines
4.2 KiB
Python
import struct
|
|
|
|
def calculate_c2_checksum(payload_bytes: bytes) -> int:
|
|
"""
|
|
Calculates the 8-bit checksum for the C2 packet payload based on the
|
|
decompiled Rust/C logic (main_packet_building).
|
|
|
|
The algorithm is a custom XOR reduction over the payload data, primarily
|
|
using 4-byte (DWORD) and 1-byte chunks, mimicking the final reduction
|
|
of the SSE logic.
|
|
|
|
The original logic is complex (32-byte blocks with SSE, then 4-byte,
|
|
then 1-byte), but the core of the final reduction is based on
|
|
accumulating XORs in 32-bit blocks and then folding the result.
|
|
|
|
For simplicity and focusing on the non-SSE reduction path (which handles
|
|
most sizes and remainders), we use a DWORD-based XOR sum and then a
|
|
byte-based XOR sum for the remainder.
|
|
"""
|
|
|
|
payload_len = len(payload_bytes)
|
|
checksum_v16 = 0
|
|
|
|
# --- 1. Process data in 4-byte (DWORD) chunks (Handles up to N & 0xFFFC) ---
|
|
# This section mimics the logic for sizes < 32 and the 4-byte remainder loop.
|
|
|
|
# v26 = a5 & 0x3FFC (The largest multiple of 4 less than a5)
|
|
processed_4byte_len = payload_len & 0xFFFC
|
|
|
|
# Iterate through the payload 4 bytes at a time
|
|
for i in range(0, processed_4byte_len, 4):
|
|
# Read 4 bytes as a little-endian integer (DWORD)
|
|
dword_value = struct.unpack('<I', payload_bytes[i:i+4])[0]
|
|
|
|
# Accumulate the XOR sum of the DWORDs
|
|
# In the original code, this happens in an SSE register, but we simplify
|
|
# it to an integer XOR sum for the final 8-bit result.
|
|
checksum_v16 ^= dword_value
|
|
|
|
# --- 2. Final Reduction/Folding (Mimics SSE reduction) ---
|
|
# The original SSE reduction folds a 128-bit XOR sum down to an 8-bit value.
|
|
# We perform a similar reduction on the 32-bit (dword) XOR sum.
|
|
|
|
# Fold 32-bit result to 16-bit: v28 = _mm_xor_si128(_mm_srli_epi32(v27, 0x10u), v27)
|
|
# This means XORing the upper 16 bits with the lower 16 bits.
|
|
checksum_v16 = (checksum_v16 & 0xFFFF) ^ (checksum_v16 >> 16)
|
|
|
|
# Fold 16-bit result to 8-bit: _mm_xor_si128(_mm_srli_epi16(v28, 8u), v28)
|
|
# This means XORing the upper 8 bits with the lower 8 bits.
|
|
checksum_v16 = (checksum_v16 & 0xFF) ^ (checksum_v16 >> 8)
|
|
|
|
# The checksum is now a single 8-bit value (0-255)
|
|
checksum_v16 &= 0xFF
|
|
|
|
# --- 3. Process the final 1-3 byte remainder (The byte loop LABEL_21) ---
|
|
# The remainder starts at the end of the 4-byte processed section.
|
|
|
|
# The XOR accumulation continues with the remaining 1-3 bytes.
|
|
for i in range(processed_4byte_len, payload_len):
|
|
checksum_v16 ^= payload_bytes[i]
|
|
|
|
# Ensure the final result is 8 bits
|
|
return checksum_v16 & 0xFF
|
|
|
|
def build_packet(command_id: int, payload: bytes) -> bytes:
|
|
"""
|
|
Constructs the complete C2 packet ready for transmission.
|
|
"""
|
|
magic_bytes = b'\x43\x42' # 0x4342 Big-Endian
|
|
cmd_id = command_id.to_bytes(1, 'big')
|
|
reserved_byte = b'\x00'
|
|
|
|
payload_len = len(payload)
|
|
# Payload length is Big-Endian (BYTE1(a5) then a5)
|
|
len_bytes = payload_len.to_bytes(2, 'big')
|
|
|
|
# Calculate the 8-bit checksum over the payload data
|
|
checksum_v16 = calculate_c2_checksum(payload)
|
|
|
|
# Checksum field is 2 bytes (Big-Endian), where MSB is 0x00 and LSB is the 8-bit checksum.
|
|
checksum_bytes = b'\x00' + checksum_v16.to_bytes(1, 'big')
|
|
|
|
# Combine all parts
|
|
packet = (
|
|
magic_bytes +
|
|
cmd_id +
|
|
reserved_byte +
|
|
len_bytes +
|
|
payload +
|
|
checksum_bytes
|
|
)
|
|
|
|
return packet
|
|
|
|
# --- Example Usage ---
|
|
# 1. Define inputs
|
|
COMMAND_OPCODE = 0x01 # Example command ID
|
|
PAYLOAD_DATA = b"cato@unknown" # N = 43 bytes
|
|
|
|
# 2. Calculate checksum and build the packet
|
|
final_packet = build_packet(COMMAND_OPCODE, PAYLOAD_DATA)
|
|
final_checksum_byte = final_packet[-1]
|
|
|
|
print(f"--- Packet Construction ---")
|
|
print(f"Payload Length (N): {len(PAYLOAD_DATA)} bytes")
|
|
print(f"Calculated Checksum (v16): {hex(final_checksum_byte)}")
|
|
print(f"Total Packet Size: {len(final_packet)} bytes (N + 8)")
|
|
print(f"Final Packet (Hex): {final_packet.hex()}")
|
|
|
|
# Verify structure:
|
|
# Magic Bytes: 0x4342 ('CB')
|
|
# CMD ID: 0x01
|
|
# Reserved: 0x00
|
|
# Length: 0x002B (43 decimal)
|
|
# Payload: 43 bytes of "This is..."
|
|
# Checksum: 0x00{v16}
|