Warden Modules

From SkullSecurity
Revision as of 16:15, 27 February 2008 by Ron (Talk | contribs) (Preperation)

Jump to: navigation, search

Warden modules are received in a series of 0x01 packets, and processed in a variety of different steps.

Initial Validation

After the entire module has been received up to the length specified in the 0x00 packet, a standard MD5 is calculated. The result is compared to the name of the module, which was also sent in 0x00. If they match, the module is processed and a response of 1 (encrypted) is sent back to the server. If the module doesn't match, a response of 0 (encrypted) is sent back to the server. The server then tries to send the module again (series of 0x01 packets).

Decryption

After verifying the MD5, the packet is decrypted using the simple xor encryption algorithm defined here: Crypto_and_Hashing#Xor_Encryption. The key used for decryption was sent in the 0x00 packet.

Second Validation

After decryption, the module is in this form: [4 bytes] -- length of uncompressed data [size - 0x108 bytes] -- data [0x04 bytes] -- An integer representing "SIGN" (or the string "NGIS") [0x100 bytes] -- A cryptographic signature

The "SIGN" string is checked first, and is a simple string match.

The signature is checked next.

RSA Signature

The signature is checked using RSA with the algorithm defined in Crypto_and_Hashing#RSA with the following variables:

  • c => the 0x100 byte signature
  • d => a constant 4-byte value (00 01 00 01) [TODO: VERIFY!!]
  • n => a constant 128-byte value [TODO: FIND!!]

The output is the result of an SHA1, hashing the module and a static string, padded with 0xBB values to the proper length:

  • checksum = SHA1(data [including length] without signature, "MAIEV.MOD")

TODO: Code example

Decompression

The "data" part of that decrypted data is then run through zlib's "inflate" function, as I mentioned here: Crypto_and_Hashing#Inflate.

Preperation

The final way in which the data is modified is when it's prepared for being loaded. I have reversed this code, although I haven't spent time to figure out how it actually works. What essentially happens is that the uncompressed code is copied to a new buffer, absolute addresses are updated, required modules are loaded (kernel32.dll and user.dll, for example), and function calls to those modules are mapped properly.

The decompressed code is in what seem to be a standard form these days:

  • [4 bytes] size of final code
  • [array] data

I will demonstrate how to prepare this through Java code (I haven't written C code for it yet):

TODO: Code example

Initialization Function

Once the module is loaded, an initialization function within it is called. To find that function, ... [TODO: Code]