• Unfortunately, we have experienced significant hard drive damage that requires urgent maintenance and rebuilding. The forum will be a state of read only until we install our new drives and rebuild all the configurations needed. Please follow our Facebook page for updates, we will be back up shortly! (The forum could go offline at any given time due to the nature of the failed drives whilst awaiting the upgrades.) When you see an Incapsula error, you know we are in the process of migration.

Flyff packet breakdown

Joined
Sep 3, 2008
Messages
977
Reaction score
31
Packets and FlyFF - Introduction to packets with FlyFF

In this thread I will tell you all you need to know about FlyFF packets and how they work - including some tips that will make it easier for you to create a server.

First of all, you must know that FlyFF packets are NOT encrypted, which makes it really easy to read the data.

Now, lets start with the basics.

]The following objects are used in FlyFF packets:

Integer - 4 bytes. Little endian, meaning a normal 0x11223344 integer would be parsed as 44 33 22 11 instead of 11 22 33 44.
String - 4+X bytes. The first 4 bytes indicate an integer which tells the client/server how long the string is, and right after those 4 bytes, comes the string itself, every character represented with it's ASCII code.
Short - 2 bytes. Also little endian, so a normal 0x1122 short would be parsed as 22 11 instead of 11 22.
Byte - A simple byte, which can mean a lot. Known to be used with gender.
Long - 8 bytes. Once again, little endian, so a normal 0x1122334455667788 (no wonder they called that "long") would be parsed as 88 77 66 55 44 33 22 11 instead of 11 22 33 44 55 66 77 88.
Floats - 4 bytes. I have no idea how these work, and if you know how, feel free to tell me. :)
[/SIZE]

Please note that every FlyFF packet starts with byte 0x5E (ASCII: ^).

]Basic client packet structure]
There are 2 forms of client packets: Form #1 which is used for login server only and form #2 which is used for cluster and world servers.

Form #1
Code:
5E          
[int] Length hash
[int] Packet length
[int] Data hash
[int] Command
Rest of the packet data

Form #2
Code:
5E
[int] Length hash
[int] Packet length
[int] Data hash
[int] -1 (0xFFFFFFFF)(FF FF FF FF)
[int] Command
Rest of the packet data

The only difference is the addition of -1 after data hash and before command. Remember, form #2 goes to cluster and world client2server packets while form #1 is ONLY login server.

Basic server packet structure
There is only one form of the server2client packet.

Form #3
Code:
5E
[int] Length
Rest of the packet data

The length of the packet should be the length of the whole thing - 5 bytes. So if the whole packet is, for example:
5E 08 00 00 00 04 00 00 00 12 34 56 78
As you can see, the whole packet has 13 bytes, but we only calculate the bytes that come AFTER the length integer, so, as you can see, there are two integers after the length integer, so we then calculate the total amount of bytes in the packet (after the length integer) and set the length integer to that.

Note that everytime a client connects to your server, your server should first send a packet containing the session ID.
This is the form of the session ID packet, which is valid for all 3 servers:

Code:
5E
08 00 00 00
00 00 00 00
[int] Session ID

Some tips about reversing
As you already saw, we need to reverse numbers before we add them to the packet.
This is how I reverse numbers. The following is for integers only:
I take a number to reverse (for example: 560). I convert it to an hexadecimal string (would result in 230) then I left-pad the string with 0's to total size of 8: 00000230. Then, I split it into 4 substrings, each one containing 2 characters which together represent a byte, so this would split it into 4 bytes (as strings, of course), so set #1=00, set #2=00, set #3=02 and set #4=30.
I then convert the 4 substrings into real byte values, and add them to the packet in this order:
set #4 then set #3 then set #2 then set #1
This will successfully add an integer to the packet.

You can do the same for int16 (short) and int64 (long) variables.

This is all for now.

I might have spelling errors or whatever, I am writing this guide at 6:50am after staying up the whole night.
 
Last edited:
Joined
Sep 3, 2008
Messages
977
Reaction score
31
Login server packets
In this thread I will explain the login server packets.
You must know the basics of FlyFF packets. If you don't,

The first packet we need to send when the client connects is the session ID packet, but I assume you already read my first thread about the introduction, so you already know that.

The client connects to our server after we enter username and password and click the login button. It will then connect to your server on port 23000, wait for the session ID packet to be sent and then it will send you a packet containing the following strings:
- Client build date
- The MD5 hash of the contents inside Flyff.a file
- Account username
- Account password

The packet command is 0xFC, so whenever you receive this packet, you know theres a login request being made.

An example for the packet would be:
Code:
5E
[int] Length hash
[int] Length
[int] Data hash
FC 00 00 00
08 00 00 00 32 30 30 37 30 37 31 32
20 00 00 00 11 22 33 44 55 66 77 88 99 00 11 22 33 44 55 66 77 88 99 00 11 22 33 44 55 66 77 88 99 00 11 22
04 00 00 00 74 74 74 74
20 00 00 00 11 22 33 44 55 66 77 88 99 00 11 22 33 44 55 66 77 88 99 00 11 22 33 44 55 66 77 88 99 00 11 22

After the command, there is the client build date, right after it is the flyff.a hash, then username and password.

The password will always be 32 characters long since it is already hashed. To make a password hash, you add the salt "kikugalanet" to before the password itself then MD5 it, so 1234 would be kikugalanet1234, now you just have to hash it using MD5.

What does the server return?
Alright, so we got all the datas from the client, now we need to reply with something, that is either an error message or the server list packet in case of a successful login.

I'll start with error message:
Code:
5E
[int] Length
FE 00 00 00
[int] Error code

The following was taken from my source:
Code:
        public static int ACCOUNT_BANNED = 0x77;
        public static int INVALID_PASSWORD = 0x78;
        public static int INVALID_USERNAME = 0x79;
        public static int VERIFICATION_REQUIRED = 0x7A;
        public static int ACCOUNT_UNDER_MAINTENANCE = 0x85;
        public static int WRONGPW_15SECONDS = 0x86;
        public static int WRONGPW_15MINUTES = 0x87;
        public static int SERVER_ERROR = 0x88;
        public static int SERVICE_DOWN = 0x6D;
        public static int ACCOUNT_CONNECTED = 0x67;
        public static int BAD_CLIENT = 0x8A;
Those are the error codes my server uses. There's a whole lot more, but the others are useless. Would you really stop people from playing your server after 10PM?

After you send this, the client will display an error message depending on the error code, and then it will send a packet with command of 0xFF (correct me if I'm wrong). My client always sends it when my server sends the error message packet, so I use it close the client socket.

Now, moving to something more advanced, the server list packet. You should send it on a successful login.

Code:
5E
[int] Length
FE 00 00 00
E6 A8 3E 7B 01
[string] Username, must be lowercase to prevent crashes
25 00 00 00
<For each cluster>
FF FF FF FF
[int] Cluster ID
[string] Cluster name
[string] Cluster IP*
00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00
<For each server in the cluster>
[int] Cluster ID
[int] Server ID
[int] Server name
00 00 00 00 00 00 00 00
[int] Online players
01 00 00 00
[int] Max capacity
<End for each server in the clusters>
<End for each cluster>

The above packet ONLY works for version 11 neuz, like fame's.
To make it work for older versions, you need to remove the username string.

This is all.
The last packet we will be talking about is the ping packet sent by the client every once in a while.
I don't have the structure of it because I don't reply to it, and the client doesn't disconnect.

This is all for login packets.
 
Experienced Elementalist
Joined
Dec 9, 2007
Messages
210
Reaction score
9
i'd guess the v11 packet works with v12 too,

<offtopic> lol sorry about messing up 120 lines of code
 
Experienced Elementalist
Joined
Aug 21, 2005
Messages
297
Reaction score
107
btw your talking about little endian values also note flyff uses unsigned values.
 
Experienced Elementalist
Joined
Aug 30, 2008
Messages
272
Reaction score
5
Wow, really interesting, thank you for these informations dude :]
Btw, which packet sniffer do you use if you don't mind my asking?
 
Custom Title Activated
Loyal Member
Joined
Sep 9, 2008
Messages
1,949
Reaction score
390
Two well known packet sniffers are useable for sniffing flyff packets. If you want to sniff official packets and sift through hundreds of packets a second, then get wireshark. Its self explanitory and setting up is a breeze.

The other one is WPE Pro. This IMO is used for sniffing packets off of Caali servers by attaching it to the 3 servers but only one at a time. Click play and it will sniff all the packets go to and from the client as well as the mysql data base. you can see this by looking at the designation and soure ports.

BTW, I am not sure if I should release packets pertaining to the world server until people start getting in game with it.
 
Newbie Spellweaver
Joined
Aug 20, 2008
Messages
7
Reaction score
0
To lazy to type it down:
 
Experienced Elementalist
Joined
Aug 21, 2005
Messages
297
Reaction score
107
yes the encryption is a standard crc32 of the size or data, then xored by the seed sent on initial connection. depending on how you do your crc32 some people have reported having to xor it by -1 to get the correct value.
 
Newbie Spellweaver
Joined
Oct 16, 2008
Messages
35
Reaction score
2
The following piece of C++ code is the begin of a packet class to read and write packets. (For my own emulator I'm using a more complex one.)
Code:
#include <vector.h>

using namespace std;

class Packet
{
private:

	vector<char> Content;
	unsigned int ReadingPos;
	
public:

	Packet()
	{
		ReadingPos = 0;
	}

	void addBuffer(const char *_buffer, const unsigned int _buffer_size)
	{
		unsigned int oldsize = Content.size();
		Content.resize(oldsize + buffer_size);
		memcpy(&Content[oldsize], _buffer_size, _buffer);
	}

	void addByte(const char _byte)
	{
		Content.push_back(_byte);
	}

	void addShort(const short _short)
	{
		addByte(((char*)(&_short))[0]);
		addByte(((char*)(&_short))[1]);
	}

	void addInt(const int _int)
	{
		addByte(((char*)(&_int))[0]);
		addByte(((char*)(&_int))[1]);
		addByte(((char*)(&_int))[2]);
		addByte(((char*)(&_int))[3]);
	}

	char getByte()
	{
		return Content[ReadingPos++];
	}

	int getInt()
	{
		int r = 0;
		((char*)&r)[0] = getByte();
		((char*)&r)[1] = getByte();
		((char*)&r)[2] = getByte();
		((char*)&r)[3] = getByte();
		return r;
	}
	
	unsigned int getSize()
	{
		return Content.size();
	}

	char *getData()
	{
		return &Contend[0];
	}
	
	void clear()
	{
		Content.clear();
		ReadingPos = 0;
	}
};

//use with winsock2:
//send
Packet packet;
packet.addByte(0x5e);
packet.addInt(4);
packet.addInt(123456);
send(s, packet.getData(), packet.getSize());

//receive
packet.clear();
char buffer[1024];
unsigned int receivedbytes = recv(s, buffer, 1024, 0);
packet.addBuffer(buffer, receivedbytes);

cout << "First byte of the packet: " << packet.getByte() << endl;
cout << "Size checksum: " << packet.getInt() << endl;
 
Experienced Elementalist
Joined
Aug 30, 2008
Messages
272
Reaction score
5
Two well known packet sniffers are useable for sniffing flyff packets. If you want to sniff official packets and sift through hundreds of packets a second, then get wireshark. Its self explanitory and setting up is a breeze.

The other one is WPE Pro. This IMO is used for sniffing packets off of Caali servers by attaching it to the 3 servers but only one at a time. Click play and it will sniff all the packets go to and from the client as well as the mysql data base. you can see this by looking at the designation and soure ports.

BTW, I am not sure if I should release packets pertaining to the world server until people start getting in game with it.

Wow, thank you dude, I'll do some experiments with wireshark <3 :p
Thanks again for these informations!
 
Experienced Elementalist
Joined
Dec 9, 2007
Messages
210
Reaction score
9
oh stop bitching, this explination is not the most important thing in the flyff section and not even half of the people here would know what to do with it, wait till something vital of urs gets leaked like caali, then you get the right to throw a bf. he put credits at the top now anyway
 
Initiate Mage
Joined
Oct 24, 2008
Messages
2
Reaction score
0
I was wondering if it was possible to actually inject packets into Eflyff or even copy official packets and resend it continously into the game
 
Newbie Spellweaver
Joined
Aug 20, 2008
Messages
7
Reaction score
0
@keemo1321 yes this is possible, you would need to hook into the communication, read nForce and my posts on gamerzplanet and you should get a idea on what you need to do.
 
Custom Title Activated
Loyal Member
Joined
Sep 9, 2008
Messages
1,949
Reaction score
390
damn i miss the days of aug, and term. nForce laid the smackdown on eFlyff. good times. good times.
 
Experienced Elementalist
Joined
Sep 1, 2008
Messages
268
Reaction score
0
damn i miss the days of aug, and term. nForce laid the smackdown on eFlyff. good times. good times.

Lmao its still quite easy to put the smack down on flyff ^^



(not a message to glaphan)

no nubs im not telling you how >.> its not that hard when you put your mind to it ....... if you have one xD




ah skrew it mabe il post how soem other time but in a leacher proof way
 
Back
Top