浏览代码

Merge pull request #312 from rathena/feature/official_packet_obfuscation

Added Packet Obfuscation support
* More info: https://rathena.org/board/topic/101092-packet-obfuscation-support/
Aleos 10 年之前
父节点
当前提交
9d247d88c1
共有 7 个文件被更改,包括 159 次插入9 次删除
  1. 28 0
      db/packet_db.txt
  2. 7 0
      src/common/mmo.h
  3. 5 0
      src/config/core.h
  4. 1 1
      src/map/atcommand.c
  5. 105 7
      src/map/clif.c
  6. 9 1
      src/map/clif.h
  7. 4 0
      src/map/pc.h

+ 28 - 0
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

+ 7 - 0
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_ */

+ 5 - 0
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
  **/

+ 1 - 1
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();

+ 105 - 7
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 ) {

+ 9 - 1
src/map/clif.h

@@ -33,6 +33,7 @@ struct party_booking_ad_info;
 #include <stdarg.h>
 
 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);

+ 4 - 0
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