diff --git a/db/packet_db.txt b/db/packet_db.txt index 117ca5e0c8..4c6db531ed 100644 --- a/db/packet_db.txt +++ b/db/packet_db.txt @@ -33,8 +33,16 @@ // Main packet version of the DB to use (default = max available version) // Client detection is faster when all clients use this version. // Version 23 is the latest Sakexe (above versions are for Renewal clients) +// +// packet_keys values are default value for each packet version, if no value +// or value is 'default' in packet_keys_use, server will uses default keys +// according to used packet_db_ver. packet_keys_use is user-defined keys. +// Maximum key value is 0x7FFFFFFF. +// NOTE: Keys won't be reloaded, initialized on first load only. +// //packet_db_ver: 46 packet_db_ver: default +packet_keys_use: default packet_ver: 5 0x0064,55 @@ -1635,6 +1643,7 @@ packet_ver: 26 //2011-10-05aRagexeRE packet_ver: 27 +packet_keys: 0x291E6762,0x77CD391A,0x60AC2F16 // [Shakto] 0x0364,5,walktoxy,2 0x0817,6,ticksend,2 0x0366,5,changedir,2:4 @@ -1653,6 +1662,7 @@ packet_ver: 27 // 2011-11-02aRagexe packet_ver: 28 +packet_keys: 0x5324329D,0x5D545D52,0x06137269 // [Shakto] 0x0436,26,friendslistadd,2 0x0898,5,hommenu,2:4 0x0281,36,storagepassword,2:4:20 @@ -1674,6 +1684,7 @@ packet_ver: 28 //2012-03-07fRagexeRE packet_ver:29 +packet_keys: 0x382A6DEF,0x5CBE7202,0x61F46637 // [Shakto] 0x086A,19,wanttoconnection,2:6:10:14:18 0x0437,5,walktoxy,2 0x0887,6,ticksend,2 @@ -1706,6 +1717,7 @@ packet_ver:29 //2012-04-10aRagexeRE packet_ver: 30 +packet_keys: 0x01581359,0x452D6FFA,0x6AFB6E2E // [Shakto] 0x01fd,15,repairitem,2:4:6:7:9:11:13 0x089c,26,friendslistadd,2 0x0885,5,hommenu,2:4 @@ -1767,6 +1779,7 @@ packet_ver: 30 //2012-04-18aRagexeRE [Special Thanks to Judas!] packet_ver: 31 +packet_keys: 0x01540E48,0x13041224,0x31247924 // [Shakto] 0x023B,26,friendslistadd,2 0x0361,5,hommenu,2:4 0x08A8,36,storagepassword,2:4:20 @@ -1786,11 +1799,13 @@ packet_ver: 31 //2012-06-18 packet_ver: 32 +packet_keys: 0x261F261F,0x261F261F,0x261F261F // [Shakto] 0x0983,29 // ZC_MSG_STATE_CHANGE3 0x0861,41,bookingregreq,2:4:6 //actually 12-05-03 //2012-07-02aRagexeRE (unstable) packet_ver: 33 +packet_keys: 0x25733B31,0x53486CFD,0x398649BD // [Shakto] 0x0363,19,wanttoconnection,2:6:10:14:18 0x0364,6,ticksend,2 0x085a,7,actionrequest,2:6 @@ -1809,6 +1824,7 @@ packet_ver: 33 //2013-03-20Ragexe (Judas) packet_ver: 34 +packet_keys: 0x3F094C49,0x55F86C1E,0x58AA359A // [Shakto] 0x014f,6,guildrequestinfo,2 0x01fd,15,repairitem,2:4:6:7:9:11:13 //0x0281,-1,itemlistwindowselected,2:4:8:12 @@ -1880,6 +1896,7 @@ packet_ver: 34 //2013-05-15aRagexe (Yommy) packet_ver: 35 +packet_keys: 0x75794A38,0x58A96BC1,0x296E6FB8 // [Shakto] 0x0369,7,actionrequest,2:6 0x083C,10,useskilltoid,2:4:6 0x0437,5,walktoxy,2 @@ -1912,6 +1929,7 @@ packet_ver: 35 //2013-05-22Ragexe (Yommy) packet_ver: 36 +packet_keys: 0x6948050B,0x06511D9D,0x725D4DF1 // [Shakto] 0x08A2,7,actionrequest,2:6 0x095C,10,useskilltoid,2:4:6 0x0360,5,walktoxy,2 @@ -1944,6 +1962,7 @@ packet_ver: 36 //2013-05-29Ragexe (Shakto) packet_ver: 37 +packet_keys: 0x023A6C87,0x14BF1F1E,0x5CC70CC9 // [Shakto] 0x0890,7,actionrequest,2:6 0x0438,10,useskilltoid,2:4:6 0x0876,5,walktoxy,2 @@ -1976,6 +1995,7 @@ packet_ver: 37 //2013-06-05Ragexe (Shakto) packet_ver: 38 +packet_keys: 0x646E08D9,0x5F153AB5,0x61B509B5 // [Shakto] 0x0369,7,actionrequest,2:6 0x083C,10,useskilltoid,2:4:6 0x0437,5,walktoxy,2 @@ -2009,6 +2029,7 @@ packet_ver: 38 //2013-06-12Ragexe (Shakto) packet_ver: 39 +packet_keys: 0x6D166F66,0x3C000FCF,0x295B0FCB // [Shakto] 0x0369,7,actionrequest,2:6 0x083C,10,useskilltoid,2:4:6 0x0437,5,walktoxy,2 @@ -2041,6 +2062,7 @@ packet_ver: 39 //2013-06-18Ragexe (Shakto) packet_ver: 40 +packet_keys: 0x434115DE,0x34A10FE9,0x6791428E // [Shakto] 0x0889,7,actionrequest,2:6 0x0951,10,useskilltoid,2:4:6 0x088E,5,walktoxy,2 @@ -2073,6 +2095,7 @@ packet_ver: 40 //2013-06-26Ragexe packet_ver: 41 +packet_keys: 0x38F453EF,0x6A040FD8,0X65BD6668 // [Shakto] 0x0369,7,actionrequest,2:6 0x083C,10,useskilltoid,2:4:6 0x0437,5,walktoxy,2 @@ -2105,6 +2128,7 @@ packet_ver: 41 //2013-07-03Ragexe packet_ver: 42 +packet_keys: 0x4FF90E23,0x0F1432F2,0x4CFA1EDA // [Shakto] 0x0369,7,actionrequest,2:6 0x083C,10,useskilltoid,2:4:6 0x0437,5,walktoxy,2 @@ -2137,6 +2161,7 @@ packet_ver: 42 //2013-07-10Ragexe packet_ver: 43 +packet_keys: 0x458F758F,0x4CCF3F8F,0x4A9C4237 0x0369,7,actionrequest,2:6 0x083C,10,useskilltoid,2:4:6 0x0437,5,walktoxy,2 @@ -2171,6 +2196,7 @@ packet_ver: 43 //2013-07-17Ragexe packet_ver: 44 +packet_keys: 0x2BED4F91,0x5F9E00CF,0x5EE5520C 0x0918,7,actionrequest,2:6 0x091E,10,useskilltoid,2:4:6 0x083C,5,walktoxy,2 @@ -2216,6 +2242,7 @@ packet_ver: 44 //2013-08-07Ragexe packet_ver: 45 +packet_keys: 0x7E241DE0,0x5E805580,0x3D807D80 // [Shakto] 0x0369,7,actionrequest,2:6 0x083C,10,useskilltoid,2:4:6 0x0437,5,walktoxy,2 @@ -2249,6 +2276,7 @@ packet_ver: 45 //2013-12-23Ragexe packet_ver: 46 +packet_keys: 0x631C511C,0x111C111C,0x111C111C // [Shakto] 0x0369,7,actionrequest,2:6 0x083C,10,useskilltoid,2:4:6 0x0437,5,walktoxy,2 diff --git a/src/common/mmo.h b/src/common/mmo.h index 39503a2653..cb206587f4 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -821,8 +821,15 @@ enum bound_type { #if (MIN_CHARS + MAX_CHAR_VIP + MAX_CHAR_BILLING) > MAX_CHARS #error Config of MAX_CHARS is invalid #endif + #if MIN_STORAGE > MAX_STORAGE #error Config of MIN_STORAGE is invalid #endif +#ifdef PACKET_OBFUSCATION + #if PACKETVER < 20110817 + #error core.h::PACKET_OBFUSCATION is enabled, it requires PACKETVER 20110817 or newer + #endif +#endif + #endif /* _MMO_H_ */ diff --git a/src/config/core.h b/src/config/core.h index 04033cadb5..24d730cbc3 100644 --- a/src/config/core.h +++ b/src/config/core.h @@ -93,6 +93,11 @@ #define MAX_CHAR_VIP 0 #endif +/// Comment to disable the official packet obfuscation support. +/// When enabled, make sure there is value for 'packet_keys' of used packet version or +/// defined 'packet_keys_use' in db/[import/]packet_db.txt. +#define PACKET_OBFUSCATION + /** * No settings past this point **/ diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 4000cf3374..91d8c81c1b 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -3831,7 +3831,7 @@ ACMD_FUNC(reload) { do_reload_quest(); clif_displaymessage(fd, msg_txt(sd,1377)); // Quest database has been reloaded. } else if (strstr(command, "packetdb") || strncmp(message, "packetdb", 4) == 0) { - packetdb_readdb(); + packetdb_readdb(true); clif_displaymessage(fd, msg_txt(sd,1477)); // Packet database has been reloaded. } else if (strstr(command, "instancedb") || strncmp(message, "instancedb", 4) == 0) { instance_readdb(); diff --git a/src/map/clif.c b/src/map/clif.c index e67352dda9..f4446179dd 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -65,6 +65,11 @@ struct Clif_Config { struct s_packet_db packet_db[MAX_PACKET_VER + 1][MAX_PACKET_DB + 1]; int packet_db_ack[MAX_PACKET_VER + 1][MAX_ACK_FUNC + 1]; +#ifdef PACKET_OBFUSCATION +static struct s_packet_keys *packet_keys[MAX_PACKET_VER + 1]; +static unsigned int clif_cryptKey[3]; // Used keys +#endif +static unsigned short clif_parse_cmd(int fd, struct map_session_data *sd); /** Converts item type to display it on client if necessary. * @param nameid: Item ID @@ -9430,7 +9435,8 @@ static int clif_guess_PacketVer(int fd, int get_previous, int *error) { static int err = 1; static int packet_ver = -1; - int cmd, packet_len, value; //Value is used to temporarily store account/char_id/sex + int packet_len, value; //Value is used to temporarily store account/char_id/sex + unsigned short cmd; if (get_previous) {//For quick reruns, since the normal code flow is to fetch this once to identify the packet version, then again in the wanttoconnect function. [Skotlex] @@ -9442,7 +9448,7 @@ static int clif_guess_PacketVer(int fd, int get_previous, int *error) //By default, start searching on the default one. err = 1; packet_ver = clif_config.packet_db_ver; - cmd = RFIFOW(fd,0); + cmd = clif_parse_cmd(fd, NULL); packet_len = RFIFOREST(fd); #define SET_ERROR(n) \ @@ -9562,6 +9568,9 @@ void clif_parse_WantToConnection(int fd, struct map_session_data* sd) CREATE(sd, TBL_PC, 1); sd->fd = fd; sd->packet_ver = packet_ver; +#ifdef PACKET_OBFUSCATION + sd->cryptKey = (((((clif_cryptKey[0] * clif_cryptKey[1]) + clif_cryptKey[2]) & 0xFFFFFFFF) * clif_cryptKey[1]) + clif_cryptKey[2]) & 0xFFFFFFFF; +#endif session[fd]->session_data = sd; pc_setnewpc(sd, account_id, char_id, login_id1, client_tick, sex, fd); @@ -17526,6 +17535,26 @@ void clif_party_leaderchanged(struct map_session_data *sd, int prev_leader_aid, clif_send(buf,packet_len(0x7fc),&sd->bl,PARTY); } +/** + * Decrypt packet identifier for player + * @param fd + * @param sd + * @param packet_ver + * Orig author [Ind/Hercules] + **/ +static unsigned short clif_parse_cmd(int fd, struct map_session_data *sd) { +#ifndef PACKET_OBFUSCATION + return RFIFOW(fd, 0); +#else + unsigned short cmd = RFIFOW(fd,0); // Check if it is a player that tries to connect to the map server. + if (sd) + cmd = (cmd ^ ((sd->cryptKey >> 16) & 0x7FFF)); // Decrypt the current packet ID with the last key stored in the session. + else + cmd = (cmd ^ ((((clif_cryptKey[0] * clif_cryptKey[1]) + clif_cryptKey[2]) >> 16) & 0x7FFF)); // A player tries to connect - use the initial keys for the decryption of the packet ID. + return cmd; // Return the decrypted packet ID. +#endif +} + /** * !TODO: Special item that obtained, must be broadcasted by this packet * 07fd ?? (ZC_BROADCASTING_SPECIAL_ITEM_OBTAIN) @@ -17586,6 +17615,7 @@ static int clif_parse(int fd) { // begin main client packet processing loop sd = (TBL_PC *)session[fd]->session_data; + if (session[fd]->flag.eof) { if (sd) { if (sd->state.autotrade) { @@ -17613,7 +17643,7 @@ static int clif_parse(int fd) if (RFIFOREST(fd) < 2) return 0; - cmd = RFIFOW(fd,0); + cmd = clif_parse_cmd(fd, sd); // identify client's packet version if (sd) { @@ -17648,7 +17678,7 @@ static int clif_parse(int fd) } // filter out invalid / unsupported packets - if (cmd > MAX_PACKET_DB || packet_db[packet_ver][cmd].len == 0) { + if (cmd > MAX_PACKET_DB || cmd < MIN_PACKET_DB || packet_db[packet_ver][cmd].len == 0) { ShowWarning("clif_parse: Received unsupported packet (packet 0x%04x, %d bytes received), disconnecting session #%d.\n", cmd, RFIFOREST(fd), fd); #ifdef DUMP_INVALID_PACKET ShowDump(RFIFOP(fd,0), RFIFOREST(fd)); @@ -17676,6 +17706,12 @@ static int clif_parse(int fd) if ((int)RFIFOREST(fd) < packet_len) return 0; // not enough data received to form the packet +#ifdef PACKET_OBFUSCATION + RFIFOW(fd, 0) = cmd; + if (sd) + sd->cryptKey = ((sd->cryptKey * clif_cryptKey[1]) + clif_cryptKey[2]) & 0xFFFFFFFF; // Update key for the next packet +#endif + if( packet_db[packet_ver][cmd].func == clif_parse_debug ) packet_db[packet_ver][cmd].func(fd, sd); else if( packet_db[packet_ver][cmd].func != NULL ) { @@ -17699,7 +17735,7 @@ static int clif_parse(int fd) /*========================================== * Reads packet_db.txt and setups its array reference *------------------------------------------*/ -void packetdb_readdb(void) +void packetdb_readdb(bool reload) { char line[1024]; int cmd,i,j; @@ -17707,6 +17743,11 @@ void packetdb_readdb(void) bool skip_ver = false; int warned = 0; int packet_ver = MAX_PACKET_VER; // read into packet_db's version by default +#ifdef PACKET_OBFUSCATION + bool key_defined = false; + int last_key_defined = -1; +#endif + int packet_len_table[MAX_PACKET_DB] = { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -18194,8 +18235,10 @@ void packetdb_readdb(void) const char *filename[] = { "packet_db.txt", DBIMPORT"/packet_db.txt"}; int f; - // initialize packet_db[SERVER] from hardcoded packet_len_table[] values memset(packet_db,0,sizeof(packet_db)); + memset(packet_db_ack,0,sizeof(packet_db_ack)); + + // initialize packet_db[SERVER] from hardcoded packet_len_table[] values for( i = 0; i < ARRAYLENGTH(packet_len_table); ++i ) packet_len(i) = packet_len_table[i]; @@ -18265,6 +18308,36 @@ void packetdb_readdb(void) clif_config.packet_db_ver = cap_value(atoi(w2), 0, MAX_PACKET_VER); continue; } +#ifdef PACKET_OBFUSCATION + else if (!reload && strcmpi(w1,"packet_keys") == 0) { + char key1[12] = { 0 }, key2[12] = { 0 }, key3[12] = { 0 }; + trim(w2); + if (sscanf(w2, "%11[^,],%11[^,],%11[^ \r\n/]", key1, key2, key3) == 3) { + CREATE(packet_keys[packet_ver], struct s_packet_keys, 1); + packet_keys[packet_ver]->keys[0] = strtol(key1, NULL, 0); + packet_keys[packet_ver]->keys[1] = strtol(key2, NULL, 0); + packet_keys[packet_ver]->keys[2] = strtol(key3, NULL, 0); + last_key_defined = packet_ver; + if (battle_config.etc_log) + ShowInfo("Packet Ver:%d -> Keys: 0x%08X, 0x%08X, 0x%08X\n", packet_ver, packet_keys[packet_ver]->keys[0], packet_keys[packet_ver]->keys[1], packet_keys[packet_ver]->keys[2]); + } + continue; + } else if (!reload && strcmpi(w1,"packet_keys_use") == 0) { + char key1[12] = { 0 }, key2[12] = { 0 }, key3[12] = { 0 }; + trim(w2); + if (strcmpi(w2,"default") == 0) + continue; + if (sscanf(w2, "%11[^,],%11[^,],%11[^ \r\n/]", key1, key2, key3) == 3) { + clif_cryptKey[0] = strtol(key1, NULL, 0); + clif_cryptKey[1] = strtol(key2, NULL, 0); + clif_cryptKey[2] = strtol(key3, NULL, 0); + key_defined = true; + if (battle_config.etc_log) + ShowInfo("Defined keys: 0x%08X, 0x%08X, 0x%08X\n", clif_cryptKey[0], clif_cryptKey[1], clif_cryptKey[2]); + } + continue; + } +#endif } if( skip_ver ) @@ -18353,6 +18426,28 @@ void packetdb_readdb(void) ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", entries, line); } ShowStatus("Using default packet version: "CL_WHITE"%d"CL_RESET".\n", clif_config.packet_db_ver); + +#ifdef PACKET_OBFUSCATION + if (!key_defined && !clif_cryptKey[0] && !clif_cryptKey[1] && !clif_cryptKey[2]) { // Not defined + int use_key = last_key_defined; + + if (last_key_defined == -1) + ShowError("Can't find packet obfuscation keys!\n"); + else { + if (packet_keys[clif_config.packet_db_ver]) + use_key = clif_config.packet_db_ver; + + ShowInfo("Using default packet obfuscation keys for packet_db_ver: %d\n", use_key); + memcpy(&clif_cryptKey, &packet_keys[use_key]->keys, sizeof(packet_keys[use_key]->keys)); + } + } + ShowStatus("Packet Obfuscation: "CL_GREEN"Enabled"CL_RESET". Keys: "CL_WHITE"0x%08X, 0x%08X, 0x%08X"CL_RESET"\n", clif_cryptKey[0], clif_cryptKey[1], clif_cryptKey[2]); + + for (i = 0; i < ARRAYLENGTH(packet_keys); i++) { + if (packet_keys[i]) + aFree(packet_keys[i]); + } +#endif } /*========================================== @@ -18375,9 +18470,12 @@ void do_init_clif(void) { clif_config.packet_db_ver = -1; // the main packet version of the DB memset(clif_config.connect_cmd, 0, sizeof(clif_config.connect_cmd)); //The default connect command will be determined after reading the packet_db [Skotlex] +#ifdef PACKET_OBFUSCATION + memset(clif_cryptKey, 0, sizeof(clif_cryptKey)); +#endif //Using the packet_db file is the only way to set up packets now [Skotlex] - packetdb_readdb(); + packetdb_readdb(false); set_defaultparse(clif_parse); if( make_listen_bind(bind_ip,map_port) == -1 ) { diff --git a/src/map/clif.h b/src/map/clif.h index 4a578b13fb..8e4f97e3aa 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -33,6 +33,7 @@ struct party_booking_ad_info; #include enum { // packet DB + MIN_PACKET_DB = 0x0064, MAX_PACKET_DB = 0xf00, MAX_PACKET_VER = 46, MAX_PACKET_POS = 20, @@ -59,6 +60,13 @@ struct s_packet_db { short pos[MAX_PACKET_POS]; }; +#ifdef PACKET_OBFUSCATION +/// Keys based on packet versions +struct s_packet_keys { + unsigned int keys[3]; ///< 3-Keys +}; +#endif + enum e_BANKING_DEPOSIT_ACK { BDA_SUCCESS = 0x0, BDA_ERROR = 0x1, @@ -424,7 +432,7 @@ void clif_setport(uint16 port); uint32 clif_getip(void); uint32 clif_refresh_ip(void); uint16 clif_getport(void); -void packetdb_readdb(void); +void packetdb_readdb(bool reload); void clif_authok(struct map_session_data *sd); void clif_authrefuse(int fd, uint8 error_code); diff --git a/src/map/pc.h b/src/map/pc.h index d11c267c70..88fc0c45bf 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -626,6 +626,10 @@ struct map_session_data { short last_addeditem_index; /// Index of latest item added int autotrade_tid; + +#ifdef PACKET_OBFUSCATION + unsigned int cryptKey; ///< Packet obfuscation key to be used for the next received packet +#endif }; struct eri *pc_sc_display_ers; /// Player's SC display table