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/
This commit is contained in:
Aleos
2015-03-14 12:25:27 -04:00
7 changed files with 159 additions and 9 deletions

View File

@@ -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

View File

@@ -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_ */

View File

@@ -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
**/

View File

@@ -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();

View File

@@ -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 ) {

View File

@@ -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);

View File

@@ -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