So I have an android game. Its Assembly-CSharp.dll causes .NET Reflector to show

File is not a portable executable. DOS header does not contain 'MZ' signature

It's encrypted. The app seems to decrypt that assembly at app launch time.

So I used UltraCompare to point out what is changed from previous version(It wasn't encrypted).

classes.dex was identical, so no java code was changed.
libmain.so and libunity.so was identical, but libmono.so had a big change.

There was some new added symbols which seem to be related with encryption such as TEAEncrypt, TEADecrypt, TEAEncryptString, TEADecryptString, and some mono library's C# internal call routine like ves_icall_System_Security_SecureString_EncryptInternal.

If it's the means of the encryption, I wander where are those functions called.

There was some changes to Assembly-CSharp-firstpass.dll, Assembly-UnityScript.dll, Assembly-UnityStript-firstpass.dll with a same change pattern. I can't figure out what does this means.

So where can be the Assembly-CSharp.dll decrypted at runtime? Or is there another way without decrypting that at runtime?

1 Answer 1


Mono is, basically, open source. So anyone can create a Mono implementation that, whenever it reads a chunk of a CIL DLL file, applies encryption to it. Maybe Unity delivers a libmono.so that does encryption with its newest version; maybe the vendor of the game implemented something themselves. You could start checking patch notes of Unity to learn if this is an official new feature; if not, it's likely that the game vendor created their own encrypting libmono.so.

Your TEA functions are, most likely, called within the libmono.so itself. If i had to implement something like that, i'd write wrapper functions TEAopen, TEAread, TEAclose for fopen, fread, fclose that decrypt on reading the file, then replace the f-* functions in the mono-code that reads a DLL with the TEA-* functions.

TEA encryption works with 8-byte chunks, which may be one of the reasons it was used here; if you want to read just a part of the file, you don't need to read everything before your part, except a few bytes to fill the 8-byte-block. But this also means the same 8 input bytes will always result in the same 8 output bytes, if your original DLL has areas with a lot of '\0' bytes, they will result in the same 8 bytes repeated over and over in the encrypted DLL.

While TEA has a weakness that turns a 128 bit key into 126 effective bits, there seems to be no known plaintext attack on it. This means, your observed same change pattern won't help you. So you need to extract the key from the mono implementation yourself. Disassemble that file, especially the TEAEncrypt and TEADecrypt functions. They should look somewhat like the code from the Wikipedia article. Their second parameter is the key; either try to find out where that key is stored/generated, or do some dynamic analysis, put a breakpoint on those functions, and check what the parameter they get actually is. Also, check if it's really a standard TEA implementation, or maybe XTEA or a different key schedule constant or something. Once you have the key, find a program that takes a file and a TEA key and decrypts it, or roll your own; this shouldn't be too difficult as there are lots of open source TEA implementations in any language of your choice.

  • So that same change pattern is not related to encryption. Only Assembly-CSharp.dll was encrypted. Anyway, those functions seems to be almost same with the wikipedia source. I have another question here, what routine is managing the assembly loading?
    – Ris
    Commented May 25, 2016 at 11:56
  • What routine is managing the assembly loading? Best check the mono source code (github.com/mono). Comparing that source with your libmono.so is probably the fastest way to find out what's different/where the encryption happens. Commented May 25, 2016 at 12:05
  • yep, I found it. I used IDA Proximity Browser. I didn't know the purpose of that browser and I finally got it. I searched TEADecryptString's function calls and found the key.
    – Ris
    Commented May 27, 2016 at 9:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.