### Setup Handshake Arguments and Generate Private Key Source: https://github.com/jellybitz/srodevs-docs/blob/master/client/a-guide-to-silkroads-security.md Configures arguments based on packet seeds, calculates intermediate values using Func_X_4, and generates the private Blowfish key using Func_X_2. ```c // Store the seeds into the arguments dwArgs[10] = packet->seedSecurity[3]; dwArgs[11] = packet->seedSecurity[2]; dwArgs[12] = packet->seedSecurity[4]; dwArgs[15] = packet->seedSecurity[0]; dwArgs[16] = packet->seedSecurity[1]; // Setup more arguments as best ordered in the client dwArgs[0] = dwArgs[11]; dwArgs[1] = dwArgs[10]; dwArgs[3] = dwRand; dwArgs[5] = Func_X_4(dwArgs[1], dwArgs[3], dwArgs[0]); dwArgs[13] = dwArgs[5]; dwArgs[4] = dwArgs[12]; dwArgs[6] = Func_X_4(dwArgs[1], dwArgs[3], dwArgs[4]); dwArgs[14] = dwArgs[6]; //------------------------------------------- // Generate the private blowfish key keyByte = LOBYTE(LOWORD(dwArgs[14])) & 0x03; keyArray[0] = dwArgs[12]; keyArray[1] = dwArgs[13]; Func_X_2((LPBYTE)keyArray, dwArgs[14], keyByte); // Initialize the blowfish blowfish.Initialize((LPBYTE)keyArray, 8); ``` -------------------------------- ### Initialize Random Value and Blowfish Source: https://github.com/jellybitz/srodevs-docs/blob/master/client/a-guide-to-silkroads-security.md Generates a random value using CoCreateGuid and initializes the Blowfish algorithm with initial packet data. Note: This initial Blowfish setup is not used for the 'E' flag packet. ```c CoCreateGuid(&guid); dwRand = guid.Data1 & 0x7FFFFFFF; // Initialize the initial blowfish (not used for the E flag at first) blowfish.Initialize((LPBYTE)packet->blowfish, 8); ``` -------------------------------- ### Initialize Handshake Key Variables Source: https://github.com/jellybitz/srodevs-docs/blob/master/client/a-guide-to-silkroads-security.md Declares and initializes variables used for processing Blowfish key data and performing calculations during the handshake. ```cpp // Packet pointer tPacket_5000_10 * packet = 0; // This holds the private blowfish data DWORD keyArray[2] = {0}; // Key byte variable used for a few operations BYTE keyByte = 0; ``` -------------------------------- ### Calculate Final Blowfish Key and Initialize Source: https://github.com/jellybitz/srodevs-docs/blob/master/client/a-guide-to-silkroads-security.md Calculates the final Blowfish key using provided arguments and initializes the Blowfish cipher for subsequent encryption. ```cpp // Calculate the final blowfish key keyArray[0] = dwArgs[15]; keyArray[1] = dwArgs[16]; Func_X_2((LPBYTE)keyArray, dwArgs[6], 0x3); // Initialize the blowfish blowfish.Initialize((LPBYTE)keyArray, 8); ``` -------------------------------- ### Build and Send Connection Accepted Packet Source: https://github.com/jellybitz/srodevs-docs/blob/master/client/a-guide-to-silkroads-security.md Constructs a 'connection accepted' packet with appropriate opcode, size, count, and CRC bytes, then sends it to the server. ```cpp // build the packet BYTE packetBuffer[32] = { 0 }; *(LPWORD)(packetBuffer + 0) = 0x0; *(LPWORD)(packetBuffer + 2) = 0x9000; // Set the count byte packetBuffer[4] = GenerateCountByte(); // Set the crc byte packetBuffer[5] = GenerateCheckByte((char*)packetBuffer, 6, firstPacket.seedCRC); // Send the packet send(s, (char *)packetBuffer, 6, 0); ``` -------------------------------- ### GLOBAL_MODULE_KEEP_ALIVE C# Example Source: https://github.com/jellybitz/srodevs-docs/blob/master/packets/global/global_module_keep_alive.md A placeholder C# code snippet related to the GLOBAL_MODULE_KEEP_ALIVE module. This example is minimal and serves as a structural representation. ```csharp // Empty ``` -------------------------------- ### Verify Handshake Signature Source: https://github.com/jellybitz/srodevs-docs/blob/master/client/a-guide-to-silkroads-security.md Compares the calculated handshake data against the expected server signature to validate the handshake process. ```cpp // Simple check to see if the handshake is good if (keyArray[0] != packet->challenge[0] || keyArray[1] != packet->challenge[1]) { MessageBox(0, "ACTIVE_SESSION::_OnMsgReceivedBeforeHandshake() - Handshake ServerSignature Error.", "Fatal Error", MB_ICONERROR); exit(-1); } ``` -------------------------------- ### HandShakeApi Class Methods Source: https://github.com/jellybitz/srodevs-docs/blob/master/client/a-guide-to-silkroads-security.md Detailed documentation for the public and private methods of the `cHandShakeApi` class, covering packet reception, decryption, encryption, and security byte generation. ```APIDOC cHandShakeApi Class Documentation --------------------------------- This class provides functionalities for handling network packet security, including handshake, encryption, and decryption for Silkroad. Private Members: - cBlowFish blowfish: Blowfish object for encryption/decryption. - unsigned char byte1seeds[3]: Count byte seeds. - tPacket_5000_E firstPacket: Structure for the 1st packet (0x5000). - tPacket_5000_10 secondPacket: Structure for the 2nd packet (0x5000_10). - DWORD dwArgs[18]: Array for function arguments. - DWORD dwRand: Client-generated random value. Private Methods: - unsigned long GenerateValue(unsigned long * Ptr) - Description: Generates a value, likely for security byte calculation. Written by jMerlin. - Parameters: - Ptr: Pointer to an unsigned long value. - Returns: Generated unsigned long value. - void SetupCountByte(unsigned long seed) - Description: Sets up the count bytes for packet security. Written by jMerlin. - Parameters: - seed: The seed value to use for setting up count bytes. Public Methods: - cHandShakeApi() - Description: Default constructor for the cHandShakeApi class. - unsigned char GenerateCountByte(void) - Description: Generates a count byte for packet security. Written by jMerlin. - Returns: The generated count byte. - unsigned char GenerateCheckByte(char* packet, int length, unsigned long seed) - Description: Generates the CRC check byte for a given packet. Written by jMerlin. - Parameters: - packet: Pointer to the packet data. - length: The length of the packet data. - seed: The seed value for CRC calculation. - Returns: The generated CRC check byte. - void OnPacketRecv(SOCKET s, LPBYTE stream) - Description: Processes incoming packet streams, typically for 0x5000 packets. - Parameters: - s: The socket descriptor. - stream: Pointer to the incoming packet byte stream. - void DecryptPacket(LPBYTE stream, LPBYTE & outPtr, DWORD & dwTotal) - Description: Decrypts a given packet stream. - Parameters: - stream: Pointer to the encrypted packet byte stream. - outPtr: Reference to a pointer where the decrypted data will be stored. - dwTotal: Reference to a DWORD where the total length of the decrypted data will be stored. - void EncryptPacket(LPBYTE rawpacket, LPBYTE & outPtr, DWORD & dwTotal) - Description: Encrypts a raw packet and stores the result. - Parameters: - rawpacket: Pointer to the raw packet data to encrypt. - outPtr: Reference to a pointer where the encrypted data will be stored. - dwTotal: Reference to a DWORD where the total length of the encrypted data will be stored. - void SetRandomNumber(DWORD value) - Description: Sets the client-generated random value used in security operations. - Parameters: - value: The DWORD value to set as the random number. - DWORD GetCRCSeed() - Description: Returns the CRC seed, which can be used in the GenerateCheckByte function. - Returns: The CRC seed value. ``` -------------------------------- ### Handshake Variable Declarations Source: https://github.com/jellybitz/srodevs-docs/blob/master/client/a-guide-to-silkroads-security.md Declares essential variables for the security handshake, including GUID for random value generation, Blowfish keys, and packet arguments. ```c // This is the client generated random value. If you are NOT doing a clientless, you will have to // figure out how to take this value from the client itself, or modify the client to use your value // Finding the location is easy, just search for: // // Push EAX // Call CoCreateGui // MOV ECX, DWORD PTR SS:[ESP+4] // AND ECX, 7FFFFFFF // // There might be a few, so break point on them all to see which one triggers. GUID guid = { 0 }; // This holds the private blowfish key DWORD keyArray[2] = { 0 }; // This holds the private blowfish data DWORD keyArray2[2] = { 0 }; // Key byte variable used for a few operations BYTE keyByte = 0; // The current packet tPacket_5000_E * packet = 0; // Args used for the functions DWORD dwArgs[18]; ``` -------------------------------- ### Construct and Send First Response Packet Source: https://github.com/jellybitz/srodevs-docs/blob/master/client/a-guide-to-silkroads-security.md Builds the initial response packet buffer, setting size, opcode, seeds, encoded data, count byte, and CRC byte before sending it over the network socket. ```c // build the packet BYTE packetBuffer[32] = {0}; *(LPWORD)(packetBuffer + 0) = 0xC; *(LPWORD)(packetBuffer + 2) = 0x5000; *(LPDWORD)(packetBuffer + 6) = dwArgs[13]; *(LPDWORD)(packetBuffer + 10) = *(keyArray2 + 0); *(LPDWORD)(packetBuffer + 14) = *(keyArray2 + 1); // Set the count byte packetBuffer[4] = GenerateCountByte(); // Set the crc byte packetBuffer[5] = GenerateCheckByte((char*)packetBuffer, 18,firstPacket.seedCRC); //------------------------------------------- // Send the packet send(s, (char *)packetBuffer, 18, 0); ``` -------------------------------- ### Handle Server Packets by Flag Source: https://github.com/jellybitz/srodevs-docs/blob/master/client/a-guide-to-silkroads-security.md Demonstrates using pointer casting to access packet data and switching based on the 'flag' member to handle different encryption types. It specifically shows handling the case for full encryption (flag 0xE). ```c // Handle the packets switch(packet->opcode) { case 0x5000: { Server_Packet_5000_Base * basePacket = (Server_Packet_5000_Base*)packet->dataPointer; switch(basePacket->flag) { // Full encryption packet case 0xE: { } break; } } } ``` -------------------------------- ### Silkroad Packet Encryption Protocol Steps Source: https://github.com/jellybitz/srodevs-docs/blob/master/client/a-guide-to-silkroads-security.md Defines the sequence of operations required to encrypt a packet for transmission within the Silkroad Online protocol. This includes setting packet size, security bytes, and the encryption process itself. ```APIDOC Packet Encryption Protocol: 1. **Packet Creation**: Prepare the packet data. 2. **Security Bytes**: Ensure the two security bytes in the header are set to 0. 3. **Size Field**: Set the high word of the packet size field to 0x80 if the packet is to be encrypted. 4. **Count Byte**: Fill in the count byte. 5. **CRC Byte**: Fill in the CRC byte. 6. **Encryption**: Encrypt the packet's contents. The encryption starts 2 bytes into the header and continues up to the end of the data payload. - The Blowfish algorithm requires buffer sizes divisible by 8 due to padding. The resulting encrypted packet may be larger than the original. 7. **Transmission**: Send the encrypted packet to the server. 8. **Logging**: Log status messages to track packets that might cause disconnections during testing. ``` -------------------------------- ### HandShakeApi Class Definition Source: https://github.com/jellybitz/srodevs-docs/blob/master/client/a-guide-to-silkroads-security.md The C++ class definition for HandShakeApi, outlining its private members and public methods for packet security operations. ```c++ // This is the handshake API class class cHandShakeApi { private: // Blowfish object cBlowFish blowfish; // Count byte seeds unsigned char byte1seeds[3]; // 1st packet tPacket_5000_E firstPacket; // 2nd packet tPacket_5000_10 secondPacket; // Args used for the functions DWORD dwArgs[18]; // The client generated random value DWORD dwRand; private: // This function was written by jMerlin as part of the article "How to generate the security bytes for SRO" unsigned long GenerateValue(unsigned long * Ptr); // Sets up the count bytes // This function was written by jMerlin as part of the article "How to generate the security bytes for SRO" void SetupCountByte(unsigned long seed); public: // Default ctor cHandShakeApi(); // Function called to generate a count byte // This function was written by jMerlin as part of the article "How to generate the security bytes for SRO" unsigned char GenerateCountByte(void); // Function called to generate the crc byte // This function was written by jMerlin as part of the article "How to generate the security bytes for SRO" unsigned char GenerateCheckByte(char* packet, int length, unsigned long seed); // Invoke this function with the packet stream of the 0x5000 packets void OnPacketRecv(SOCKET s, LPBYTE stream); // Decrypts a packet void DecryptPacket(LPBYTE stream, LPBYTE & outPtr, DWORD & dwTotal); // Encrypts a packet and stores the new data and length in the parameter void EncryptPacket(LPBYTE rawpacket, LPBYTE & outPtr, DWORD & dwTotal); // Set the client generated random value void SetRandomNumber(DWORD value); // Returns the CRC seed for use in the GenerateCheckByte function DWORD GetCRCSeed(); }; ``` -------------------------------- ### Generate and Encode Blowfish Key Data Source: https://github.com/jellybitz/srodevs-docs/blob/master/client/a-guide-to-silkroads-security.md Processes received data to generate the new private Blowfish key by encoding it with a derived key byte. ```cpp // Generate the new private bf key data keyArray[0] = dwArgs[4]; keyArray[1] = dwArgs[5]; // Generate the key byte keyByte = LOBYTE(LOWORD(dwArgs[4])) & 0x07; // Modify the data Func_X_2((LPBYTE)keyArray, dwArgs[14], keyByte); // Encode the data blowfish.Encode((LPBYTE)keyArray, (LPBYTE)keyArray, 8); ``` -------------------------------- ### C++ Clientless Packet Handler (0xA101) Source: https://github.com/jellybitz/srodevs-docs/blob/master/client/a-guide-to-silkroads-security.md Handles a specific network packet opcode (0xA101) for clientless connections. It parses an ID, a string, and then iterates through a list of servers, extracting their names, current players, and maximum players. ```cpp else if (packet->opcode == 0xA101) { // We've made it :) printf("***** Clientless Success! *****\n\n"); // This is a messy way to parse this, but remember, proof of concept code;) LPBYTE stream = (LPBYTE)data + 6; printf("ID: %X\n", *((LPWORD)stream)); stream += 2; WORD len = *((LPWORD)stream); stream += 2; for (int x = 0; x < len; ++x) { printf("%c", *((char*)stream)); stream++; } printf("\n"); stream++; while (*stream == 1) { stream++; WORD id = *((LPWORD)stream); stream += 2; len = *((LPWORD)stream); stream += 2; char name[256] = { 0 }; for (int x = 0; x < len; ++x) { name[x] = *((char*)stream); stream++; } WORD curPlayers = *((LPWORD)stream); stream += 2; WORD maxPlayers = *((LPWORD)stream); stream += 2; BYTE state = *stream; stream++; printf("%s - [%i / %i]\n", name, curPlayers, maxPlayers); } } ``` -------------------------------- ### Handle Server Packet Opcode 0x5000 Source: https://github.com/jellybitz/srodevs-docs/blob/master/client/a-guide-to-silkroads-security.md This C++ code snippet demonstrates how to process incoming server packets, specifically focusing on opcode 0x5000. It further categorizes packets based on a 'flag' field, detailing the structure and printing information for a specific handshake packet (flag 0xE), including seeds and Blowfish key components. ```cpp // Handle the packets switch(packet->opcode) { case 0x5000: { Server_Packet_5000_Base * basePacket = (Server_Packet_5000_Base*)packet->dataPointer; switch(basePacket->flag) { // Full encryption packet case 0xE: { Server_Packet_5000_25 * packet = (Server_Packet_5000_25*)packet->dataPointer; printf("1st Handshake Packet:\n"); printf(" Flag: %X\n", packet->flag); printf(" Count Seed: %X\n", packet->seedCount); printf(" CRC Seed: %X\n", packet->seedCRC); printf(" Blowfish: %.2X %.2X %.2X %.2X %.2X %.2X%.2X %.2X\n", packet->blowfish[0], packet->blowfish[1], packet->blowfish[2], packet->blowfish[3], packet->blowfish[4], packet->blowfish[5], packet->blowfish[6], packet->blowfish[7]); printf(" Handshake Seeds: %X %X %X %X %X\n", packet->seedSecurity1, packet->seedSecurity2, packet->seedSecurity3, packet->seedSecurity4, packet->seedSecurity5); printf("\n"); } break; } } } ``` -------------------------------- ### Generate Silkroad Packet Count Byte (C++) Source: https://github.com/jellybitz/srodevs-docs/blob/master/client/a-guide-to-silkroads-security.md Provides functions to generate the count byte for Silkroad packets. `SetupCountByte` initializes internal seeds based on an initial seed value, and `GenerateCountByte` uses these seeds to produce the actual count byte, updating the seeds for subsequent calls. The `byte1seeds` array stores the state between calls. ```c++ unsigned char byte1seeds[3]; void SetupCountByte(unsigned long seed) { if (seed == 0) seed = 0x9ABFB3B6; unsigned long mut = seed; unsigned long mut1 = GenerateValue(&mut); unsigned long mut2 = GenerateValue(&mut); unsigned long mut3 = GenerateValue(&mut); GenerateValue(&mut); unsigned char byte1 = (mut & 0xFF) ^ (mut3 & 0xFF); unsigned char byte2 = (mut1 & 0xFF) ^ (mut2 & 0xFF); if (!byte1) byte1 = 1; if (!byte2) byte2 = 1; byte1seeds[0] = byte1^byte2; byte1seeds[1] = byte2; byte1seeds[2] = byte1; } unsigned char GenerateCountByte(void) { unsigned char result = (byte1seeds[2] * (~byte1seeds[0] + byte1seeds[1])); result = result ^ (result >> 4); byte1seeds[0] = result; return result; } ``` -------------------------------- ### Server Packet Structure for Blowfish Handshake Source: https://github.com/jellybitz/srodevs-docs/blob/master/client/a-guide-to-silkroads-security.md Defines the structure of a server packet used during the Blowfish handshake, containing an internal flag and the next Blowfish key base. ```cpp // Blowfish handshake accept challenge packet struct Server_Packet_5000_9 { // Internal flag (0x10) BYTE flag; // Next blowfish key base BYTE blowfish[8]; }; ``` -------------------------------- ### Generate Security Byte Seed Value (C++) Source: https://github.com/jellybitz/srodevs-docs/blob/master/client/a-guide-to-silkroads-security.md Implements the `GenerateValue` function, a core component for seeding security byte calculations in Silkroad packets. It takes a pointer to an `unsigned long` and modifies it based on a specific bit manipulation algorithm. This function is crucial for initializing the state used by `SetupCountByte`. ```c++ unsigned long GenerateValue(unsigned long* Ptr) { unsigned long val = *Ptr; for (int i = 0; i < 32; i++) val = (((((((((((val >> 2) ^ val) >> 2) ^ val) >> 1) ^ val) >> 1) ^ val) >> 1) ^ val) & 1) | ((((val & 1) << 31) | (val >> 1)) & 0xFFFFFFFE); return (*Ptr = val); } ``` -------------------------------- ### C++ Packet Encryption Function Source: https://github.com/jellybitz/srodevs-docs/blob/master/client/a-guide-to-silkroads-security.md A C++ function demonstrating how to encrypt a game packet using Blowfish. It copies the packet, encrypts the relevant data section, and returns a pointer to the encrypted output. Note that the static buffer is reused on subsequent calls. ```c++ // Encrypts a packet void EncryptPacket(LPBYTE rawpacket, LPBYTE & outPtr, DWORD & dwTotal) { static BYTE output[8192]; WORD size = (*(WORD*)(rawpacket)) & 0x7FF; dwTotal = 0; memset(output, 0, 8192); memcpy(output, rawpacket, size + 6); dwTotal = blowfish.Encode(output + 2, output + 2, size + 4); dwTotal += 2; outPtr = output; } ``` -------------------------------- ### OnSocketRead Packet Handling for Silkroad Server Source: https://github.com/jellybitz/srodevs-docs/blob/master/client/a-guide-to-silkroads-security.md This C++ function handles incoming packets from a Silkroad server. It processes handshake requests (0x5000), version information (0x2001), and triggers server stats retrieval (0x600D) using Win32 Winsock. It relies on a `HandShakeApi` for encryption and CRC generation. ```C++ void OnSocketRead(SOCKET s) { static char data[8192] = { 0 }; static int size = 0; // Read the data available on the socket size = recv(s, data, 8192, 0); // Loop through and show the data for (int x = 0; x < size; ++x) { BYTE b = data[x]; printf("%.2X ", b); if ((x + 1) % 26 == 0) printf("\n"); } printf("\n\n"); // Now handle the packets tPacket * packet = (tPacket *)data; // Handshake if (packet->opcode == 0x5000) { HandShakeApi.OnPacketRecv(s, (LPBYTE)data); if (packet->size == 9) { // Response for 1.142 client BYTE response[18] = { 0x0C, 0x80, 0x01, 0x20, 0x00, 0x00, 0x09, 0x00, 0x53, 0x52, 0x5F, 0x43, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x00 }; // Set the count byte response[4] = HandShakeApi.GenerateCountByte(); // Set the crc byte response[5] = HandShakeApi.GenerateCheckByte((char*)response, 18, HandShakeApi.GetCRCSeed()); // Encrypt the packet LPBYTE sendPtr = 0; DWORD sendSize = 0; HandShakeApi.EncryptPacket(response, sendPtr, sendSize); // Send the packet send(s, (char*)sendPtr, sendSize, 0); } } // Version information else if (packet->opcode == 0x2001) { // Response for 1.142 client check what 0x8E is in decimal ;) BYTE response[22] = { 0x10, 0x80, 0x00, 0x61, 0x00, 0x00, 0x12, 0x09, 0x00, 0x53, 0x52, 0x5F, 0x43, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x8E, 0x00, 0x00, 0x00 }; // Set the count byte response[4] = HandShakeApi.GenerateCountByte(); // Set the crc byte response[5] = HandShakeApi.GenerateCheckByte((char*)response, 22, HandShakeApi.GetCRCSeed()); // Encrypt the packet LPBYTE sendPtr = 0; DWORD sendSize = 0; HandShakeApi.EncryptPacket(response, sendPtr, sendSize); // Send the packet send(s, (char*)sendPtr, sendSize, 0); } // Trigger a server stats packet when we recv this one else if (packet->opcode == 0x600D) { // Response for 1.142 client - ping the server to let it know we are alive BYTE ping[6] = { 0x00, 0x00, 0x02, 0x20, 0x00, 0x00 }; // Set the count byte ping[4] = HandShakeApi.GenerateCountByte(); // Set the crc byte ping[5] = HandShakeApi.GenerateCheckByte((char*)ping, 6, HandShakeApi.GetCRCSeed()); // Send the packet send(s, (char*)ping, 6, 0); // Response for 1.142 client - request server stats BYTE response[6] = { 0x00, 0x80, 0x01, 0x61, 0x00, 0x00 }; // Set the count byte response[4] = HandShakeApi.GenerateCountByte(); // Set the crc byte response[5] = HandShakeApi.GenerateCheckByte((char*)response, 6, HandShakeApi.GetCRCSeed()); // Encrypt the packet LPBYTE sendPtr = 0; DWORD sendSize = 0; HandShakeApi.EncryptPacket(response, sendPtr, sendSize); // Send the packet send(s, (char*)sendPtr, sendSize, 0); } // Server status } ``` -------------------------------- ### Silkroad Packet Structure (C++) Source: https://github.com/jellybitz/srodevs-docs/blob/master/client/a-guide-to-silkroads-security.md Defines the generic structure of packets used in Silkroad Online. It includes fields for packet size, opcode, security count, security CRC, and the data payload. This structure is fundamental for understanding network communication within the game. ```C++ // This is the generic packet structure struct tPacket { // Size of this packet WORD size; // Opcode of this packet WORD opcode; // Security count byte (0 from server to client packets) BYTE securityCount; // Security CRC byte (0 from server to client packets) BYTE securityCRC; // Pointer to the remaining data and other packets BYTE dataPointer[8186]; }; ``` -------------------------------- ### C++ Helper Function for Stream Obfuscation (Func_X_2) Source: https://github.com/jellybitz/srodevs-docs/blob/master/client/a-guide-to-silkroads-security.md This C++ helper function, named Func_X_2, performs XOR obfuscation on an 8-byte stream. It modifies each byte of the stream based on a provided key and a key byte, utilizing bitwise operations to extract parts of the key. This function is crucial for the handshake process, likely for encrypting or decrypting data. ```cpp // Helper function used in the handshake void Func_X_2(LPBYTE stream, DWORD key, BYTE keyByte) { stream[0] ^= (stream[0] + LOBYTE(LOWORD(key)) + keyByte); stream[1] ^= (stream[1] + HIBYTE(LOWORD(key)) + keyByte); stream[2] ^= (stream[2] + LOBYTE(HIWORD(key)) + keyByte); stream[3] ^= (stream[3] + HIBYTE(HIWORD(key)) + keyByte); stream[4] ^= (stream[4] + LOBYTE(LOWORD(key)) + keyByte); stream[5] ^= (stream[5] + HIBYTE(LOWORD(key)) + keyByte); stream[6] ^= (stream[6] + LOBYTE(HIWORD(key)) + keyByte); stream[7] ^= (stream[7] + HIBYTE(HIWORD(key)) + keyByte); } ``` -------------------------------- ### C++ Helper Function for Seed Calculation (Func_X_4) Source: https://github.com/jellybitz/srodevs-docs/blob/master/client/a-guide-to-silkroads-security.md This C++ helper function, Func_X_4, performs complex numerical operations involving modulo and multiplication, likely to derive encryption keys or seeds. It iterates 32 times, conditionally updating a result based on input arguments and using `LARGE_INTEGER` for 64-bit arithmetic, indicating operations that might exceed standard 32-bit integer limits. ```cpp // Helper function used in the handshake DWORD Func_X_4(DWORD arg1, DWORD arg2, DWORD arg3) { LARGE_INTEGER result = { 1, 0 }; LARGE_INTEGER temp1 = { 0 }; LARGE_INTEGER temp2 = { 0 }; LARGE_INTEGER temp3 = { 0 }; LARGE_INTEGER temp4 = { 0 }; for (int x = 0; x < 32; ++x) { if (arg2 & 1) { temp1.LowPart = arg3; temp1.HighPart = 0; temp2.QuadPart = temp1.QuadPart * result.QuadPart; temp3.LowPart = arg1; temp3.HighPart = 0; temp4.QuadPart = temp2.QuadPart % temp3.QuadPart; result.QuadPart = temp4.QuadPart; } arg2 >>= 1; temp1.LowPart = arg3; temp1.HighPart = 0; temp1.QuadPart *= temp1.QuadPart; temp2.LowPart = arg1; temp2.HighPart = 0; temp3.QuadPart = temp1.QuadPart % temp2.QuadPart; arg3 = temp3.LowPart; if (!arg2) break; } return result.LowPart; } ``` -------------------------------- ### Encrypted Packet Examples (Hex) Source: https://github.com/jellybitz/srodevs-docs/blob/master/client/a-guide-to-silkroads-security.md Illustrative examples of network packets where the high byte of the size field indicates encryption. These sequences show raw byte data as observed in network traffic. ```hex 21 80 63 3C 03 C5 E5 CE 37 9D 6A B7 0F 49 30 EE 4D 45 FB 96 1B 66 BA 41 37 1A 55 16 F0 E8 B5 6E 23 FF EC 38 D9 5F A7 19 BE 06 ``` ```hex 0C 80 B0 6A F0 53 3B E6 05 AC 64 F3 8B F1 D3 30 F6 89 ``` ```hex 01 00 FF FE F2 F1 A1 ``` -------------------------------- ### C Code: Calculate Real Packet Size Source: https://github.com/jellybitz/srodevs-docs/blob/master/client/a-guide-to-silkroads-security.md Demonstrates how to extract the actual data size from a packet's size field. It checks if the high bit (0x8000) is set, indicating encryption, and masks the size to get the correct length. ```c #include int main(int argc, char * argv[]) { unsigned short size = 0; size = 0x8021; printf("Original size: %.4X\n", size); if (size & 0x8000) { size = size & 0x7FF; } printf("New size: %.4X\n\n ", size); size = 0x800C; printf("Original size: %.4X\n", size); if (size & 0x8000) { size = size & 0x7FF; } printf("New size: %.4X\n\n ", size); size = 0x0001; printf("Original size: %.4X\n", size); if (size & 0x8000) { size = size & 0x7FF; } printf("New size: %.4X\n\n", size); return 0; } ``` -------------------------------- ### Check Packet Type for Handshake Source: https://github.com/jellybitz/srodevs-docs/blob/master/client/a-guide-to-silkroads-security.md Verifies if the received packet is the second packet in the handshake process, checking its size and flag. ```cpp // Check to see if this packet is the second packet of the handshake process else if(basePacket->size == 9 && basePacket->flag == 0x10) ``` -------------------------------- ### GATEWAY_SHARD_LIST_REQ C# Placeholder Source: https://github.com/jellybitz/srodevs-docs/blob/master/packets/gateway/gateway_shard_list_req.md An empty C# code snippet, potentially serving as a placeholder for implementing the GATEWAY_SHARD_LIST_REQ functionality. ```csharp // Empty ``` -------------------------------- ### Packet Type Check Source: https://github.com/jellybitz/srodevs-docs/blob/master/client/a-guide-to-silkroads-security.md Checks if the incoming stream points to a specific packet type (tPacket_5000) and verifies its size and flag for the handshake process. ```c // Pointer conversion tPacket_5000 * basePacket = (tPacket_5000 *)stream; // Check to see if this packet is the first packet of the handshake process if(basePacket->size == 0x25 && basePacket->flag == 0xE) ``` -------------------------------- ### Encode Data with Blowfish Source: https://github.com/jellybitz/srodevs-docs/blob/master/client/a-guide-to-silkroads-security.md Prepares data for Blowfish encoding using calculated values and then performs the encoding operation. The packet data itself is not encrypted at this stage. ```c // Generate the private blowfish data keyArray2[0] = dwArgs[5]; keyArray2[1] = dwArgs[4]; keyByte = LOBYTE(LOWORD(dwArgs[5])) & 0x07; Func_X_2((LPBYTE)keyArray2, dwArgs[14], keyByte); // Blowfish Encode on data to send it (note the packet itself is not encrypted!) blowfish.Encode((LPBYTE)keyArray2, (LPBYTE)keyArray2, 8); ``` -------------------------------- ### C# SILKCFG File Structure Source: https://github.com/jellybitz/srodevs-docs/blob/master/file-formats/silkcfg.md Describes the byte layout and data types for the SILKCFG configuration file using C# syntax. It details version-specific fields for window resolution, graphics, and sound settings. ```csharp 4 uint Version //3 if (Version < 4) { 4 uint unkUInt01 //1 4 uint WindowResolution.Width 4 uint WindowResolution.Height 1 byte GraphicType1 // 0 = Low, 1 = Middle, 2 = High, 3 = Large, 4 = Unchanged 1 byte Brightness // 0 = Very Dark, 1 = Dark, 2 = Normal, 3 = Bright, 4 = Very Bright 1 byte unkByte01 1 bool IsSoundEnabled 1 byte unkByte02 // Language tab index? if (Version == 3) { 1 byte GraphicType2 1 byte GraphicTypeIndex //1 or 2 } } ``` -------------------------------- ### File Structure Source: https://github.com/jellybitz/srodevs-docs/blob/master/file-formats/jmxvmfo.md Describes the file structure of JMXVMFO using C# syntax, detailing fields like Signature, MapWidth, MapHeight, and RegionData, along with their types and sizes. ```csharp 12 char[] Signature // "JMXVMFO 1000" 2 short MapWidth // 256 at max. (8 bits from RegionID) 2 short MapHeight // 128 at max. (7 bits from RegionID, 1 bit is used as dungeon indicator) 2 short unkShort0 2 short unkShort1 2 short unkShort2 2 short unkShort3 8192 byte[] RegionData // 256 * 256 = 65536 bits / 8 = 8192 bytes (1 byte has 8 region indicators) // Sorted at the same direction from world map. ``` -------------------------------- ### Server Packet Base Structure Source: https://github.com/jellybitz/srodevs-docs/blob/master/client/a-guide-to-silkroads-security.md Defines a base structure for server packets to identify encryption type via a flag. This structure is used for initial packet inspection before casting to a more specific type. ```c // Base packet to figure out which one we have struct Server_Packet_5000_Base { // Internal flag BYTE flag; }; ``` -------------------------------- ### C# JMXVMAPM File Structure Definition Source: https://github.com/jellybitz/srodevs-docs/blob/master/file-formats/jmxvmapm.md Defines the byte-level structure of the JMXVMAPM file format using C# data types. It outlines the layout of region blocks, vertices, and tiles, detailing data types and sizes for each component. ```csharp 12 char[] Signature //JMXVMAPM1000 // Each region has 6 x 6 blocks for (int yBlock = 0; yBlock < 6; yBlock++) { for (int xBlock = 0; xBlock < 6; xBlock++) { 4 uint Block.Flag // 0 = None, 1 = Culled 2 ushort Block.EnvironmentID // See "environment.ifo" // Each block has 17 x 17 MapMeshVertices for (int z = 0; z < 17; z++) { for (int x = 0; x < 17; x++) { 4 float Vertex.Height // (MSB) (LSB) // | 15 | 14 | 13 | 12 | 11 | 10 | 09 | 08 | 07 | 06 | 05 | 04 | 03 | 02 | 01 | 00 | // | Scale | ID (tile2d.ifo) | 2 ushort Vertex.TextureInfo 1 byte Vertex.Brightness // Lighting direction indicator? } } 1 byte Block.WaterType // 0xFF = None, 0 = Water, 1 = Ice 1 byte Block.WaterWaveID // See "map/water/wave?.ddj" 4 float Block.WaterHeight // Each block has 16 x 16 MapMeshTiles for (int z = 0; z < 16; z++) { for (int x = 0; x < 16; x++) { 2 ushort Tile.Flag // 0x01 = Blocked manually } } 4 float Block.HeightMax // Highest point including objects 4 float Block.HeightMin // Lowest point including objects 20 byte[] Block.Reserved // Reserved[0] = 1 in some blocks } } ``` -------------------------------- ### Full Security Packet Structure Source: https://github.com/jellybitz/srodevs-docs/blob/master/client/a-guide-to-silkroads-security.md Defines the complete structure for a server packet with full encryption (flag 0xE). This includes the Blowfish key, security count seed, CRC seed, and additional security-related seeds. ```c // Full security packet struct Server_Packet_5000_25 { // Internal flag (0xE) BYTE flag; // Initial blowfish key BYTE blowfish[8]; // security count seed DWORD seedCount; // security crc seed DWORD seedCRC; // Additional seeds used DWORD seedSecurity1; DWORD seedSecurity2; DWORD seedSecurity3; DWORD seedSecurity4; DWORD seedSecurity5; }; ``` -------------------------------- ### DIVISIONINFO File Structure Description Source: https://github.com/jellybitz/srodevs-docs/blob/master/file-formats/divisioninfo.md Describes the binary file format for DIVISIONINFO, detailing the layout of server division names and gateway addresses. It outlines the byte order and string lengths for parsing the data. ```csharp 1 byte ContentID // Locale 1 byte ServerDivisionCount foreach(ServerDivisionCount) { // ServerDivision 4 uint Name.Length * string Name 1 byte unkByte0 //0 1 byte GatewayCount foreach(GatewayCount) { // Gateway 4 uint Address.Length // IP or hostname * string Address 1 byte unkByte1 //0 } } ``` -------------------------------- ### LuaInsertNpc API Function Source: https://github.com/jellybitz/srodevs-docs/blob/master/lua.md Links NPCs to execute a specific Lua function. It takes the total count of NPCs and their codenames as arguments, allowing for batch linking. ```APIDOC LuaInsertNpc(Count: int, Codenames: *args as string) Links the NPC to execute the current function. Parameters: Count: int - The number of NPCs to be linked. Codenames: *args as string - A variable number of NPC codenames to link. Example: LuaInsertNpc(3,"NPC_CH_EVENT_KISAENG1","NPC_CH_EVENT_KISAENG2","NPC_CH_EVENT_KISAENG3") ``` -------------------------------- ### DIVISIONINFO ImHex Struct Definition Source: https://github.com/jellybitz/srodevs-docs/blob/master/file-formats/divisioninfo.md Provides a C-like struct definition for parsing the DIVISIONINFO binary file format using ImHex. It defines the structure of Gateway and ServerDivision, and the main DIVISIONINFO structure. ```c struct Gateway { u32 AddressLength; char Address[AddressLength]; u8 unkByte1; }; struct ServerDivision { u32 NameLength; char Name[NameLength]; u8 unkByte0; u8 GatewayCount; Gateway Gateways[GatewayCount]; }; struct DIVISIONINFO { u8 ContentID; u8 ServerDivisionCount; ServerDivision ServerDivisions[ServerDivisionCount]; }; DIVISIONINFO file @ 0; ``` -------------------------------- ### GATEWAY_LOGIN_IBUV_CHALLENGE Opcode Structure Source: https://github.com/jellybitz/srodevs-docs/blob/master/packets/gateway/gateway_login_ibuv_challenge.md Details the data structure for the GATEWAY_LOGIN_IBUV_CHALLENGE opcode, specifying the byte layout for image data transmission. This format is used for client-server communication. ```csharp byte Image.Flags ushort Image.Remaining //in bytes ushort Image.CompressedLength ushort Image.UncompressedLength ushort Image.Width //200 ushort Image.Height //64 byte[] Image.CompressedData ``` -------------------------------- ### C Function: Decrypt Silkroad Packet Source: https://github.com/jellybitz/srodevs-docs/blob/master/client/a-guide-to-silkroads-security.md A C function to decrypt a Silkroad packet using Blowfish. It takes the raw packet stream, calculates the correct data size, and decrypts the payload, including header bytes. The function returns a pointer to a static buffer containing the decrypted data. ```c // Decrypts a packet void DecryptPacket(LPBYTE stream, LPBYTE & outPtr, DWORD & dwTotal) { static BYTE output[8192]; WORD size = (*(WORD*)(stream)) & 0x7FF; memset(output, 0, 8192); (*(LPWORD)(output)) = size; blowfish.Decode(stream + 2, output + 2, size + 4); dwTotal = size + 4; outPtr = output; } ``` -------------------------------- ### GATEWAY_SHARD_LIST_PING_REQ Structure Source: https://github.com/jellybitz/srodevs-docs/blob/master/packets/gateway/gateway_shard_list_ping_req.md Represents the structure for the GATEWAY_SHARD_LIST_PING_REQ message. This snippet shows the basic definition, which is currently marked as empty. ```csharp // GATEWAY_SHARD_LIST_PING_REQ // Opcode: 0x6106 // Direction: C > S // Encrypted // The following C# code is a placeholder as the actual implementation is empty. public class GatewayShardListPingReq { // Placeholder for message content } ```