MUnique / OpenMU

This project aims to create an easy to use, extendable and customizable server for a MMORPG called "MU Online".
https://munique.net
MIT License
728 stars 312 forks source link

client-server CheckSum #26

Closed Tocher closed 6 years ago

Tocher commented 6 years ago

Hi, i'v emulate client login and select character, then join into world and in some seconds get disconnect from server. i start investigate and see this packets: c3 08 03 00 5b cf d2 11 c3 08 03 00 30 31 1f ae maybe this is checksum? do you know how to get this/create? this code capture checksum and return to client?

also next packet after is: c1 05 18 16 5f and it's always the same

thanks.

sven-n commented 6 years ago

Hi, that's the client checksum, which I didn't implement in the game server yet - and don't plan to. The server sends a request to the client to calculate the checksum with a specific "challenge" value (16 bit).

There are several ways to get a valid checksum:

To load it by using the servers checksums.dat, I have some pseudo-code for you:

// returns an index between 0 and 1024:
        ushort GetIndex(ushort challenge)
        {
            ulong x = challenge;
            ulong y = 0;
            y ^= x;

            x ^= 0x0B479;
            x &= 0x0FFFF;
            y = x;
            y >>= 6;
            y ^= x;
            y &= 0x0F;
            x >>= 6;
            y ^= x;
            return (ushort)y;
        }

        uint GetChecksum(ushort challenge)
        {
                var index = this.GetIndex(challenge);
                using (var fileStream = File.Open("checksums.dat", FileMode.Open))
                {
                        byte[] buffer = new byte[4];
                        fileStream.Position = index * 4; // just a rough estimate, may be off by one ;)
                        fileStream.Read(buffer, 0, 4);
                        return buffer.MakeDWord();
                }
        }

The request packet which comes from the server looks like this: C3 06 03 00 08 15 The last two bytes is the challenge and is handed to GetChecksum... and the result is put into the result packet which look like the ones you mentioned: C3 08 03 00 12 34 56 78

I hope it's understandable, because I didn't put every detail in ;) As you can see, this is pretty bad security and doesn't protect from cheats at all :D

Tocher commented 6 years ago

wow, this is great! thx!

I'm interested, how you know about checksum and about packets structure? i dig in ragezone, but can't find much about this. maybe exist some method to investigate what means packet c1 52 or c1 fb, and etc...

sven-n commented 6 years ago

Well, when I played this game about 8 years ago, I researched a lot about the mu online protocol and game mechanics. The "mu helper" wasn't there yet, so I developed some packet based bots ;)

You can find some informations about the client checksum here: http://forum.ragezone.com/f197/main-checksum-dat-generator-422560/ http://forum.ragezone.com/f197/multicore-checksum-dat-generator-662748/

GetIndex reverse function: https://github.com/kessiler/muOnline-season6/blob/1e331e5765e102f44c7af29b6834a6bda96fcc2b/gameServer/gameServer/protocol.cpp#L1402

Tocher commented 6 years ago

hm, i generate checksum.dat file, then capture "challenge" from server c1 06 03 00 2cbf ok, challenge is 2cbf then i getIndex -> 0x266 or 614 int

after this i open checksum.dat, find index 614*4 and get 4 bytes. send them with c3 08 03 00 xx xx xx xx and... have disconnect :(

then i open original client, capture server and client checksum. client send c3 08 03 00 3a 9c ec 89 so i try to find '3a 9c ec 89' in my .dat file... and nothing found, even ec 98 or 9c ec.

can it be, they have packed main.exe? or some other .dat file? :(

Tocher commented 6 years ago

server not mine :) so i can't get checksum and generate from main.exe not working (maybe my mistake some where) third way was brute force? can you explain how, please? for now i imagine this like: create some "server" that send on client indexes and save answer to new.dat file

sven-n commented 6 years ago

Yes, to brute force either connect the original Client to a Fake Server or try to use the Original Server with a Proxy Tool... then try to iterate through the 1024 possible values ;)

However, did you try to use the Challenge 0xbf2c, index 37 yet?

Tocher commented 6 years ago

nope, index 37 not help :( maybe i'm have some bug in code, but i tried on c# or nodejs, and go through all indexes compare values with value that original client send back to server.

i'm trying create some proxy server, but i'm not good enough. so i have client which connect to 173.212.240.106:55901/44405 i can't change ip in main.exe because it's packed (i guess)

so i try find some solution to forward all packets with destination 55901 to another port (example 55800) but how to send back from 55800 to 55901 ;)

lunching fake server is complicated, because i have mac os :D so i'm stuck, i hope i will find solution ;)

sven-n commented 6 years ago

Can't you use a launcher to connect to a specific Ip and Port? There is one included in this project ;)

Tocher commented 6 years ago

launcher saved me, and i connect to my proxy. and now i have interesting things.

GetIndex from 0x1d28 and 0x1d18 is 673 so Checksum 4 bytes must be similar (or i mistake) but sending this two challenge to client from my proxy give me this:

0x1d18 c3 08 03 0c c0 c7 66 98 (decrypted)

0x1d28 c3 08 03 0c a1 ee 74 47 (decrypted)

i think this server have more complicated secure, so i try get full table from 0x0001 to 0xffff and search for algorithm or so)

thx very much for your help! ❤️