Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

Spellborn reCreation / Remaking server Emulator?

Status
Not open for further replies.
Initiate Mage
Joined
Apr 18, 2006
Messages
2
Reaction score
0
Client used to Reverse:
http://www.gamershell.com/download_36174.shtml

Working on trying to get something going for this, loved the game and atmosphere so much and really miss it.. I am not too sure at what point to start with.. seeing how everything about this game was shut down / non existant for over 5 years now basically.. I found an earlier Beta Client which I presume is going to be easier to alter / change with the GameGuard Version.

Im kind of wondering where it is best to start with... done a bit of Wiresharking and seeing packets / IP's its looking for.. and a quick dabble into the d_mmos.dll and other d_ files seems to reveal something.. just not smart enough to see what that is.. But I severely want to learn.. and being a n00b.. and picking up things as I go.. just wondering if someone can link some good information for this.. not asking for someone to do this for me.. I mean that would be great.. but I prefer to learn myself :).. / empowering myself.. U can bypass the Patch Server by running sb_client.exe. if someone can Msg me / give some guidance forever in your debt :).
 
Initiate Mage
Joined
Sep 23, 2013
Messages
4
Reaction score
0
I'm keeping an eye on this. I miss this beautiful game
 
Initiate Mage
Joined
Aug 5, 2014
Messages
2
Reaction score
0
hope the best for you that you may find more people to help you :)
 
Initiate Mage
Joined
Aug 15, 2014
Messages
3
Reaction score
1
World is small. I was looking for information about d_mmos.dll and I found this.
Well, I am a noob in reverse enigneering but I do programming for a few years now (computer science student for 5 years) and I am an old fan of The Chronicles of Spellborn (discovered the game in 2005 and immediatly fell in love with its visual and music! Saltiel is not the pseudo I used on the game forums).
I don't know why but two weeks ago I suddenly had the envy to reverse it, at least to be able to explore a map, even empty (without npc, mobs etc).
So I started to learn. I can recommend you to read:
http://reversewithme.blogspot.fr/2013/12/sensepost-crash-course-in-x86-assembly.html <= introduction to assembly
http://beginners.re/ <= MUST READ, ~700 pages book, I am far of the end and already learning a lot
http://reversewithme.blogspot.fr/2013/02/reading-instructions-to-learn-x86.html

And a bunch of resources and tutorials here:
http://thelegendofrandom.com/blog/ <= very good tutorials, aimed at cracking but very useful to understand how to navigate through assembly with Olly etc, I recommend to start with that
http://www.rohitab.com/discuss/topic/35537-cc-reverse-engineering-tutorial-for-newbies/
http://nagareshwar.securityxploded.com/2014/03/20/code-injection-and-api-hooking-techniques/ => also bunch of articles
http://resources.infosecinstitute.com/ => bunch of articles
http://www.bubblews.com/news/1210350-mmorpg-server-development-educational-ebooks <= MMO oriented

Well I think there is enough stuff here! I don't want to engage myself in anything because I have a lot of projects, but currently it's something I am working hard on. I have to say that digging through assembly is pretty hard, and a big programm like a MMO is not an easy one to start with.
I started to spot some interesting places in the code, but reverse engineering them is not easy.

What did you achieved to do right know ? I'm using beta client 0.9 because my release client does not work on my computer it says "Protection error 196", it's an error I had back in the days when TCoS was still alive and never succeeded in solve it...
The advantage of this client is that it does not have protections.
I don't know if you know the site spellborn.org/forums, there is people who achieved to extract the maps (without all the infos but the geometry and textures) in order to open them in UT2k4 (Spellborn use an heavily modified version of Unreal Engine 2.5).
The only thing I actually did for now is changing the server IP to localhost (easy its in a config file in plain text) and start a very simple server in Java to "stimulate" and answer to the client... The login and mdp are in clear (not encrypted) but I don't know what to answer to the client. I think I will have to reverse some procedures in d_mmos.dll but that's the hard part. A good starting point, I think, is the Winsock32.recv () function, to break on it and then finding who calls it and how it analyses the packet...
Anyway I am currently learning as fast as I can but it's hard. What I do when I don't know what to do is exploring the dlls with IDA or OllyDBG and try to find interesting strings or functions... It's not very optimised but at least I'm starting to have a (very small) vision of the whole thing.

I am wondering if DLL injection / DLL proxy could be useful in our case to understand what is going on under the hood... Still searching, and trying. I also found a tool I still have to try because did not have the time: http://jacquelin.potier.free.fr/winapioverride32/

Don't know if this helps a lot, sorry for my bad english spoken :/
Would be great if we could share our discoveries :)
 
Last edited:
Initiate Mage
Joined
Aug 15, 2014
Messages
3
Reaction score
1
Hi everybody,

I don't know if anyone is reading this thread, but I will try to make updates on my progression in reversing packets in The Chronicles of Spellborn.
What I reversed so far:

  • connect/disconnect packet
  • login packet (client/server) : can validate login or send error (bad login/password or wrong client version)
  • universes list packet (client/server) (send universe list with name, population etc)
  • a good part of the universe selected packet (sending ip/port etc of the game server)
  • How to get packet ID
  • What is the header of every packets
  • Low level packet writing / reading in d_mmos.dll
  • Some parts of the write/read functions of the packets mentionned previously in SBPacket.dll
  • I also start to have an understanding of the packet management architecture that allows me to find quickly basics information and place to investigate when starting to reverse a packet.

The process is still very slow and "hand crafted". I will try to document what I did when I have the time.
I will edit this post with much details later.

Edit: Beginning of a doc

General

Sb_client.exe arguments

--show_console: show the console displaying the log (you can also take control of the console and use some functions/load packages)
--packet_log: enable logging of the packets sended et received
--world: not really sure what this option means... seems like bypassing universe selection but does not seem to work
--uc_debugger: (check syntax) attach unreal engine debugger to the process. Sadly scripts files are not accessible.
--unreal_log: seems to do nothing. Test

Encoding

TCoS client encodes its strings in UTF16-LE.

Network

d_mmos.dll

Contains low level functions for sending packets.
Interesting places:

  • d_message class with read (void* dataOut, uint dataSize) and write (const void* dataIn, uint dataSize)
  • d_address class: represent IP+Port
d_message class

d_message::read (void* dataOut, uint dataSize)

void* dataOut is a pointer to a memory location where the value read will be stored. Sometimes this memory is in stack, sometime in heap. It totally depends of the caller. For instance if the client tries to read a string, dataOut will be a pointer to the std::string::data () (or equivalent).
uint dataSize is the size in bytes of the value you want to read. For instance if you want to read a DWORD (double word = 4 bytes) its value will be 4.

The d_message object keeps track of the data you've read in it. So each time you call its read method, it updates an internal value with the size of data already read (it simply adds dataSize to its current value). This is also an offset allowing it to know where to begin the reading of the data in the message. Each time you call read, you actually ask to read the next data in the d_message object.
If there is no more data, or not enough (there is still 2 bytes and you ask to read 4 bytes), the method will raise an exception.

d_message::write (const void* dataIn, uint dataSize)

Work the same way than read but write dataSize bytes of data pointed by dataIn inside the d_message. Same mechanism checking that not too much data is written.

SBPacket.dll

Contains packet high level stuff. Use templates a lot, which means that the window 'Names' in IDA won't show you all the methods because the same actual method can be exported with multiples names (not apparing in 'Names' but only in 'Exports'). So, look in 'Exports' instead.
The interesting class is d_serializable<struct PACKET> where 'struct PACKET' is the template parameter. Interesting methods of d_serializable for now:

  • GetID ()
  • GetName () (but actually the name is exactly the same as the template parameter name)
  • ReadMessage (const struct d_message&)
  • WriteMessage (struct d_message&)
/!\ /!\ /!\ ==>WriteMessage and ReadMessage are very interesting to study for each message because it's there you can understand what is put inside the packet.<== /!\ /!\ /!\
This is how I try to reverse packets, by studying these two methods and their context (who calls them, what structure do they fill etc).

To find quickly which message has a specific ID, in OllyDBG use "find command" and type move ax, ID where ID is a short number. It will point you the good GetID () method. The template parameter gives you the message name.

Note: packet's names follow a simple convention. They have a prefix specifying if its a packet sended by the client to the server or by the server to the client.

C2L: Client to Login server
L2C: Login server to Client
C2S: Client to Server
S2C: Server to Client

There are other prefix but currently I did not find what they mean.

Packets layout

Every packet I have seen in the login process (login+ select universe) have this header:

struct PacketHeader (32 bits)
{
WORD PacketID;
WORD PacketSize;
}

If the PacketSize attribute does not match the actual packet size, the client will not trigger the ReadMessage or will trigger an error. If the client wants to read more data than you give to him, it will sayin the logs: "PACKET_NAME READ BUFFER OVERFLOW".
Note: For what I've seen so far, the client does not check the size in its read algorithm to verify if its is consistent with the type of packet you send.
The client will just try to read everything it has to read and if you send not enough data, triggers the BUFFER OVERFLOW error seen above. This behavior is due to the d_mmos.dll::d_message::read (const void* outData, uint dataSize) method which check the message size everytime you ask it to read a value in the packet. If the size alreday read + the size of the data you ask to read is greater than the message size: error.

Note: The following sizes does not take the packet's header into account, because the size contained in the packet's header do the same.

struct C2L_USER_LOGIN_PACKET (various size)
{
struct PacketHeader header;
DWORD zeroDword;//unknown data, = 0
DWORD clientVersion;//not sure but can't be anything else
DWORD loginNumCharacters;
char[loginNumCharacters*2] loginString;//in UTF-16LE
DWORD passwordNumCharacters;
char[passwordNumCharacters * 2] passwordString;//in UTF16-LE
};

struct L2C_USER_LOGIN_ACK_PACKET (2 DWORDS = 8 bytes)
{
struct PacketHeader header;
DWORD zeroDword;//unknown data, its value does nothing
DWORD statusCode;
};

statusCode possible values:

  • 0: Login OK
  • 1: Wrong client version
  • 2: Bad login or password
  • 3: Bad login or password (yes, the same)
  • above 3: unknown error during login process


struct C2L_QUERY_UNIVERSE_LIST_PACKET (empty)
{
struct PacketHeader header;
};

struct Universe (various size)
{
DWORD universeID;
DWORD universeNameNumChars;
char[universeNameNumChars*2] universeName; //UTF16-LE
DWORD universeLanguageNumChars;
char[universeLanguageNumChars*2] universeLanguage; //UTF16-LE
DWORD universeTypeNumChars;
char[universeTypeNumChars*2] universeType; //UTF16-LE
DWORD universePopulationNumChars;
char[universePopulationNumChars*2] universePopulation; //UTF16-LE
};

struct L2C_QUERY_UNIVERSE_LIST_ACK (various size)
{
struct PacketHeader header;
DWORD unknownDWORD; // MUST BE 0 to work, integrity check?
DWORD universesNumber; //number of universes available
struct Universe[universesNumber] universesList; // universesNumber times the attributes in the struct Universe
};

struct C2L_UNIVERSE_SELECTED_PACKET (size = 1 DWORD)
{
struct PacketHeader header;
DWORD universeID; //id of the selected universe
};


Protocol

Here is the dialog between client and server, don't know if it's very useful. For detailed info about the packets structure, see the section above.
Client send CONNECT (no data)
Client send C2L_USER_LOGIN (login + password)
Server answer L2C_USER_LOGIN_ACK (status code)
Client send C2L_QUERY_UNIVERSE_LIST (no data)
Server answer L2C_QUERY_UNIVERSE_LIST_ACK (status code?, universes list with infos)
Client send C2L_UNIVERSE_SELECTED (universe selected id)
Server answer L2C_UNIVERSE_SELECTED_ACK (universe package's name, universe IP + port, and unknown data)

List of Packets ID

CONNECT = 0xFFFD;
DISCONNECT = 0xFFFE;

Client packets ID

C2L_USER_LOGIN = 0;
C2S_WORLD_PRE_LOGIN_ACK = 2;
C2L_QUERY_UNIVERSE_LIST = 2;
C2S_WORLD_LOGIN_ACK = 4;
C2L_UNIVERSE_SELECTED = 4;

Server packets ID

L2C_USER_LOGIN_ACK = 1;
S2C_WORLD_LOGIN = 3;
L2C_QUERY_UNIVERSE_LIST_ACK = 3;
L2C_UNIVERSE_SELECTED_ACK = 5;

To be continued
 
Last edited:
Initiate Mage
Joined
Aug 15, 2014
Messages
3
Reaction score
1
For those interested, as spellborn.org is the only remaining site with a spellborn community, I continue the documentation and discussion about reversing spellborn there.
There is already an updated doc!
 
Status
Not open for further replies.
Back
Top