nmconew General Packet Format and Encryption
All listed entries are in network byte order, otherwise known as big endian.
// Primary header
WORD: Packet Length (Inclusive)
WORD: Unknown (Packet ID?)
// Secondary header
BYTE: Constant (0x18)
3 bytes: Packet Length - Primary Header Length
BYTE: Unknown
3 bytes: Packet Length Without Headers
DWORD: Encryption Seed
DWORD: Unknown
// Packet Body (Encrypted)
BUFFER: Packet Body
Sample Packet:
Code:
// Primary Header
[00 44] [00 0B]
// Secondary Header
[18] [00 00 40] [02] [00 00 34] [C6 7D 2A 54] [C2 B0 B4 35]
// Packet Body
[84 68 2D 2C 93 11 8B 7D F2 B7 20 EF 20 11 B4 8E 73 69 3B 18 F5 68 07 26 33 6F 23 17 3B 82 B1 6C A8 0D 05 A0 E6 F1 FC 17 6D C5 DD C6 95 C5 E3 B0 51 E1]
Encryption Scheme
Code:
unsigned int xor_table[] = { 0x040FC1578, 0x0113B6C1F, 0x08389CA19, 0x0E2196CD8,
0x074901489, 0x04AAB1566, 0x07B8C12A0, 0x00018FFCD,
0x0CCAB704B, 0x07B5A8C0F, 0x0AA13B891, 0x0DE419807,
0x012FFBCAE, 0x05F5FBA34, 0x010F5AC99, 0x0B1C1DD01 };
void encrypt(unsigned long* buffer, unsigned int len, int seed)
{
int temp, temp2 = 0;
for (int i = 0; i < len / 4; i++
{
temp = temp2 ^ xor_table[i & 15] ^ seed;
temp2 = (int)buffer[i];
buffer[i] = temp ^ temp2;
}
}
void decrypt(unsigned long* buffer, unsigned int len, int seed)
{
int temp = 0;
for (int i = 0; i < len / 4; i++)
{
buffer[i] ^= (temp ^ xor_table[i & 15] ^ seed);
temp = buffer[i];
}
}
Notes:
- Handling for packets constructed and sent from other DLLs may be formatted and encrypted differently.
- Handling for packets routed through sendto() rather than send() may be formatted differently.
- Packet headers may be different for inbound packets (recv).