Jump to content

Warden - I now have MaNGOS managing it


Guest Neo2003
 Share

Recommended Posts

Hello,

I post here for a simple raison: I would like that we all discuss what to do.

I have a working patch.

About the patch

In game project I added WardenMgr.cpp and WardenMgr.h. This Warden Manager is doing everything for client<->mangosd communication, including encrypting/decrypting packets.

I store the two 2048bits rc4 keys in the WorldSession + a shortTimer to manage the timings between cheat checks and to be able to timeout a not responding client and kick it.

That is mostly what this manager does for client, it does not manage any module nor have any storage requirement. however, it has a communication part to exchange information with a Warden Daemon.

Warden Daemon is a Win32 VC project only because it will load modules that are Win32 code.

This Daemon waits for mangosd connection and then is using his own protocol to discuss with mangosd.

This daemon loads the modules and checks information from the realm DB; it loads modules code, generates the keys, build cheat checks and validate them.

This Daemon is loading each module only for about 1 second in order to have the keys and seed then unload it. I did set it arbitrary to handle a maximum of 20 modules at the same time, meaning client connection rate at 20 clients/second. if 20 modules are already loaded and if it gets a new request, it will simply delay it by 5 seconds.

Warden

Each client is assigned a module randomly (from the 71 I have), then it will keep the same module for the full day. If the client is disconnecting and come back the same day, the same module is reused. If he come back another day, he will get a new one. A module is never changed during a session, whatever the length of the session is. Each time the same user connect the same day, keys will change each time.

For the cheat checks, the daemon build the list based on what I did put in the DB and this is sniffed data I know nothing about.

All checks are working: timing, page, drivers, memory, mpq and lua. Checks are done a the rate 6 to 9 checks every 1 minutes approximately. A new cheat check set is sent 12 to 15 seconds after the last reply from client, and the client can take up to 1 minute to reply.

Timing are not validated because I don't know how to compute the client tick count from the server. I simply accept any value.

Memory check are not validated too (so I accept anything) because I don't know what the client returns.

We need to get the offset in wow.exe memory for the values we want to check. For example ask the client for the memory chunk that is containing player speed, and then we could check the results. I did not code anything around this yet.

Client is kicked if it did not load the module after the module has been sent.

The client is banned for 24H if it failed a cheat check (I only kick it for the moment).

Now let's raise the problems:

- Do we apply such a patch on git? It adds a unique anti-cheat system MaNGOS miss a lot, but what about Blizz?

My feeling: Noone will care. Blizz is not chasing after emulator for a long time

- Can I post such a patch in the public section of the forum?

My feeling: same

- How can I share the modules with their keys and their cheat check table?

My feeling: For this I will have to use IRC I think, it's a bit dangerous to post modules here .

- If this patch is added, do you think someone will use the code to build a cheating proxy on official and then expose mangos to problems?

My Feeling: One wanting to do it would have done it without the patch, many information are present on Internet

Since I am at work I cannot post the patch. I will post it this evening. I will give you the patch for [11260], 71 modules with their full Check table and a set of cheat check I did capture from Official.

To make it work you have to:

- Apply the patch and compile mangos as always, I tested Win32, Winx64 and Linux 32.

- Compile wardend with your favorite VC, I added the 3 solutions in /win for the 3 VCs.

- Configure wardend.conf to have DB information and path to the folder containing the warden folder I put in the archive.

- Apply the update sql on realm db and apply the content sql

- Start wardend on a windows machine and mangos anywhere, you will have to update mangosd.conf and to setup the IP address and port information for wardend.

Neo2003

Link to comment
Share on other sites

Memory check are not validated too (so I accept anything) because I don't know what the client returns.

Client returns n bytes from memory address specified in cheat check packet. So you can just query your client with all mem checks and store results. If you receive some different result, something is wrong, as it's mostly used for checking read only code segment. Ofc there's some checks for data segment as well (like wall climb angle, gravity etc...)

Timing are not validated because I don't know how to compute the client tick count from the server. I simply accept any value.

Client returns it's tickcount in CMSG_TIME_SYNC_RESP packet.

Link to comment
Share on other sites

New Version : http://trunk.dyndns.org/Warden110318_11263.zip

WardenMgr::SendWardenData() changed to use BuildChecksum() and opcode and added content description

Coded transformed seed sent back by client is now checked for validity

The order of things done with timer was not proper and we were lucky that client was fast enough or we would have a problem of packet order. Fixed

I also share the flow of the functions so that you can trace what the code is doing easier:

http://trunk.dyndns.org/Flow.txt

Link to comment
Share on other sites

New version (just the patch, the rest does not change): http://trunk.dyndns.org/Warden110319b.diff

Lua reply parsed properly and written clearly on wardend console

Added message BASIC_LOG on wardend console for all reasons of kicking

All other messages are DEBUG_LOG now, loading/unloading module messages are DEBUG_DETAIL

Really change the module every day, last_login was already updated by realmd, so I cannot use it, I added a mediumit containing the year_day to be able to track day change.

Link to comment
Share on other sites

About MPQ file check, how to check it fully?

I don't want to extract the MPQ to check all the files and this check is only for people that change the textures, do we care?

But hes I will test the result, not the SHA1, or I can put some SHA1 of files in the DB but I doubt it is useful.

Do you have other idea for the SHA1?

For grammar, I will check. When I am tired, my English is horrible ;)

Link to comment
Share on other sites

About MPQ file check, how to check it fully?

I don't want to extract the MPQ to check all the files and this check is only for people that change the textures, do we care?

But hes I will test the result, not the SHA1, or I can put some SHA1 of files in the DB but I doubt it is useful.

Do you have other idea for the SHA1?

For grammar, I will check. When I am tired, my English is horrible ;)

Cheaters can change whole game world, not just textures. It's not that hard to put SHA1 of the files in DB in addition to file names. This can be useful for someone.

Link to comment
Share on other sites

Cheaters can change whole game world, not just textures. It's not that hard to put SHA1 of the files in DB in addition to file names. This can be useful for someone.

Ah ok, I thought only .adt and .m2 files were checked. Btw, It's coded (SHA1 added to the DB and used) already.

I will do an English pass and also try to homogenize the variable names. Then I will post a new version the evening.

Link to comment
Share on other sites

May be it's time to move it to public section? I've done limited testing and it seems to work :)

                   if (memContent[i]!=checkList[i].mem->Result[pos])
                       valid = false; // It returns false because I need to have proper result stored for 3.3.5

I changed it to "false" and haven't got kicked, I guess you already have proper data in DB.

Also your MEM_CHECK and FILE_CHECK client structs probably wrong for cases where "memory can't be read" or "file doesn't exist".

Link to comment
Share on other sites

Last version of the diff: http://trunk.dyndns.org/Warden110326b.diff

Changes:

- Proper structure in MEM_CHECK and FILE_CHECK is case memory not read or file not found

- If wardend crashes, the client are not disconnected and an error message is displayed in mangos console

- Use PAGE1 and PAGE2 checks instead of just PAGE1

Since I will post on public part, I uploaded the files to filebeam.

In case of problem, here is the delete link, don't use it if not required

http://filebeam.com/97478ef0a0133a493ad164fe05f76e43&del=910477
[url]http://filebeam.com/6bf78f32b0beb3dced13cb8be2cdf82d&del=185390[/url]
[url]http://filebeam.com/16eb3e969b151b74cda28581ad9f8531&del=913252[/url]
[url]http://filebeam.com/4ff191aca8c8405612b6f922b19d7648&del=442842[/url]
[url]http://filebeam.com/26a8fff342b2b7d77a6194d4dd646a0e&del=876343[/url]
[url]http://filebeam.com/fe266bbfeae7f7b2799a7fab4767e47b&del=868927[/url]
[url]http://filebeam.com/fddc1f2246bc16bc443d6b4ed82c4c05&del=615408[/url]
one missed
[url]http://filebeam.com/f7e5f956f718991dd371a6007b2c0359&del=764441[/url]
[url]http://filebeam.com/97dd974c4da5d17513c54ab9a8946f68&del=448608[/url]

Link to comment
Share on other sites

  • 1 month later...

Hello,

Just for your information, I try to break some RC4 keys of modules for which I did not get it via sniffing. In fact I did get them from wdb.

But even if I manage to brute force 700 000 key test per second on a single process/single thread, it's not possible to get the 128bits key in a reasonable time.

If you know any shortcut to brute force a RC4 key, I would be happy to hear it.

I already only recrypt the 1st 6 bytes of the module to check the uint32 module_deflated_size in a proper range and the uint16 zlib signature. Then if this pass, I decrypt the module until the RSA signature to check the "SIGN" at offset size-0x104 (I never came to that point yet on an unknown module, so my first check with 6 bytes is pretty well).

I also changed a bit the rc4 function to write the result in another buffer to prevent the memory copy each loop. Here is the code, if you see any big optimization, tell me ;)

#include <windows.h>
#include <stdio.h>
#include <time.h>
#include <stdint.h>
#include "BigNumber.h"

// rc4 part
inline void SWAP(uint8_t *a, uint8_t *b);
inline void rc4_init(uint8_t *key_buffer, uint8_t *base, uint32_t base_length);
inline void rc4_crypt(uint8_t *key, uint8_t *data, uint32_t length, uint8_t *destdata);

int main(int argc, char *argv[])
{
   uint32_t mod_length = 18754;
   char *name = "1D811DBA8199D4CF0633CE36C7557E3D.bin";

   FILE *fp = fopen(name, "rb");
   if(!fp)
   {
       printf("Module file missing!!!\\n");
       return 0;
   }

   uint8_t *m_cryptedModule, *m_workCopy;
   m_cryptedModule = (uint8_t*)malloc(sizeof(uint8_t)*mod_length);
   m_workCopy      = (uint8_t*)malloc(sizeof(uint8_t)*(mod_length - 0x100));
   uint8_t m_testKey[0x102];

   fread(m_cryptedModule, sizeof(uint8_t)*mod_length, 1, fp);
   fclose(fp);

   BigNumber bn;
   bn.SetDword(0);
   bool found = false;

   time_t start = time(0);
   uint32_t a = -1;
   while (!found)
   {
       if (0x007FFFFF == a++)
       {
           a = 0;
           printf("%u: ", time(0) - start);
           printf("%s\\n", bn.AsHexStr());
       }
       // fast check
       rc4_init(m_testKey, bn.AsByteArray(16, false), 16);
       rc4_crypt(m_testKey, m_cryptedModule, 6, m_workCopy); // no need to decrypt until the end
       uint32_t m_inflatedSize = *(uint32_t*)m_workCopy;
       uint16_t m_sign = *(uint16_t*)(m_workCopy+4);
       if (m_sign == 0xDA78 && m_inflatedSize > 25500 && m_inflatedSize < 34500)  // 78 DA
       {
           printf("%s: slib signature check pass.\\n    Inflated size would be %u\\n", bn.AsHexStr(), *(uint32_t*)m_workCopy);
           rc4_init(m_testKey, bn.AsByteArray(16, false), 16);
           rc4_crypt(m_testKey, m_cryptedModule, mod_length - 0x100, m_workCopy); // no need to decrypt until the end
           uint32_t m_signature = *(uint32_t*)(m_workCopy + mod_length - 0x104);
           if (m_signature == 0x5349474E)
           {
               printf("Found !!!!!!\\n");
               fp = fopen("module.key", "wb");
               fwrite(&mod_length, sizeof(uint32_t), 1, fp);
               fwrite(bn.AsByteArray(16, false), sizeof(uint8_t)*16, 1, fp);
               fclose(fp);
               found = true;
               printf("\\n%s - 0x%08X\\n", bn.AsHexStr(), m_signature);
           }
       }
       ++bn;
   }
   return 0;
}

// rc4 part
inline void SWAP(uint8_t *a, uint8_t *b)
{
   uint8_t t;
   t = *a;
   *a = *b;
   *b = t;
}

inline void rc4_init(uint8_t *key_buffer, uint8_t *base, uint32_t base_length)
{
   uint8_t val = 0;
   uint32_t position = 0;
   uint32_t i;

   for(i = 0; i < 0x100; i++)
       key_buffer[i] = (uint8_t)i;

   key_buffer[0x100] = 0;
   key_buffer[0x101] = 0;

   for(i = 1; i <= 0x40; i++)
   {
       val += key_buffer[(i * 4) - 4] + base[position++ % base_length];
       SWAP(&key_buffer[(i * 4) - 4], &key_buffer[val & 0x0FF]);

       val += key_buffer[(i * 4) - 3] + base[position++ % base_length];
       SWAP(&key_buffer[(i * 4) - 3], &key_buffer[val & 0x0FF]);

       val += key_buffer[(i * 4) - 2] + base[position++ % base_length];
       SWAP(&key_buffer[(i * 4) - 2], &key_buffer[val & 0x0FF]);

       val += key_buffer[(i * 4) - 1] + base[position++ % base_length];
       SWAP(&key_buffer[(i * 4) - 1], &key_buffer[val & 0x0FF]);
   }
}

inline void rc4_crypt(uint8_t *key, uint8_t *data, uint32_t length, uint8_t *destdata)
{
   for(uint32_t i = 0; i < length; i++)
   {
       key[0x100]++;
       key[0x101] += key[key[0x100]];
       SWAP(&key[key[0x101]], &key[key[0x100]]);
       //data[i] ^= key[(key[key[0x101]] + key[key[0x100]]) & 0x0FF];
       destdata[i] = data[i] ^ (key[(key[key[0x101]] + key[key[0x100]]) & 0x0FF]);
   }
}

I did add ++ and -- operators to BigNumber class like this:

BigNumber BigNumber::operator++()
{
   BN_add_word(_bn, 1);
   return *this;
}

Link to comment
Share on other sites

 Share

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. Privacy Policy Terms of Use