2. About me
CTO at WindySoft
● 9 years of online pc / unity game
Lecturer at Gachon Univ.
● 3 years of cryptography in game
Speaker
● 3rd times at KGC since 2010
Used to make games
● Katamari Damacy Online PC game
Forcus on Game Security
● PC / Android
3. Agenda
Unity on Android - what does it mean?
Code Obfuscation
Encryption of
● PlayerPrefs
● Scripts
● AssetBundles
Conclusion
Q&A
12. Mono
● Mono is a free and open source project led by Xamarin
(formerly by Novell and originally by Ximian) to create an
Ecma standard-compliant, .NET Framework-compatible set
of tools including, among others, a C# compiler and a
Common Language Runtime.
● The stated purpose of Mono is not only to be able to run
Microsoft .NET applications cross-platform, but also to bring
better development tools to Linux developers. Mono can be
run on many software systems including Android, most Linux
distributions, BSD, OS X, Windows, Solaris, and even some
game consoles such as PlayStation 3, Wii, and Xbox 360.
13. Dalvik
● Dalvik is the process virtual machine (VM) in Google's
Android operating system. It is the software that runs the
apps on Android devices. Dalvik is thus an integral part of
Android, which is typically used on mobile devices such as
mobile phones and tablet computers as well as more
recently on embedded devices such as smart TVs and media
streamers.
● Programs are commonly written in Java and compiled to
bytecode. They are then converted from Java Virtual
Machine-compatible .class files to Dalvik-compatible .dex
(Dalvik Executable) files before installation on a device.
The compact Dalvik Executable format is designed to be
suitable for systems that are constrained in terms of
memory and processor speed.
14. Java SE Performance Versus Android
● Java VM uses a stack machines.
● Dalvik VM uses a register-based architecute.
The relative merits stack machines versus register-based
approaches are a subject of ongoing debate.
15. Java SE Performance Versus Android
The results show that Java SE Embedded can execute Java
bytecodes from 2 to 3 times faster than Android 2.
18. Bartholomew IU
When I just finished my first mobile game in Unity3D,
I found that a C# decompiler like
decompile my game.
ILSpy can easily
There are a lot of obfuscators available for .Net,
but no one is specialized for Unity3D Android.
19. Bartholomew IU
I have to test them one by one. I tried some free
obfuscators, however, the result is not good enough.
Then I tried some other paid obfuscators. Some paid
obfuscators have no fine tuning of the obfuscation
process, they keep the name of all public methods and
fields unchanged.
Although this behavior is correct, it exposes too much
coding information.
20. Bartholomew IU
It would be better if an obfuscator can keep the public
methods used by Unity engine, such as Awake(),
Update(), OnGUI()... unchanged, while rename other
public methods.
The obfuscator also need to have a way to exclude
those public variables which have their value set
by Unity editor.
21. Bartholomew IU
After tried several obfuscators,
I found
Crypto obfuscator is quite good
(in terms of price and functionality),
although I haven't test all other paid obfuscators found
in the Google search.
I guess other obfuscators should work for Unity3D too,
provided that the obfuscator has the similar settings
described above.
22. Bartholomew IU
When I try the obfuscators, I find that I can test the
obfuscated code using PC build instead of installing the
result apk file into my phone in order to save time.
Comparing the re-build time using my game, PC version
takes around 20 seconds to build while Android version
takes around 4 minutes.
23. Bartholomew IU
It seems that PC build and Android build using the same
mono to interpret the IL bytecode, what obfuscation
setting works in PC build works in Android build too.
In PC build, there is a log file named output_log.txt
inside the data folder. If you run the game and find that
there are any errors after obfuscation, you can look into
the log file and check what's going wrong.
The common errors are class not found and instance is
null if the obfuscation setting is wrong.
28. Location inside the "Managed" folder
Target is to obfuscate the Assembly-CSharp.dll.
We don't need to obfuscate
the Assembly-UnityScript-firstpass.dll as non of our code is
inside this dll.
29.
30. Symbol Renaming Schemes:
I tested all different schemes, all scheme works (Although
Test Mode works too, don't use it for production. It is for
testing only). I prefer using "Unprintable", because it can
reduce the file size a bit.
I also checked the options inside "Use Advanced Overload
Renaming".
31. Assembly Specific Settings 1:
Advanced Protections:
● "Encrypt String" may not be too useful as the iOS build
keeps the string in the stripped bytecode. If you won't
publish to iOS platform, you can choose this option.
● "Protect Against Reflection-Based Examination" may break
the code as Unity3D engine uses the reflection feature.
● "Enable Tamper Detection" is not useful in my case.
32. Assembly Specific Settings 2:
Symbol Renaming:
● "Public and Non-Public..." option. This option will rename
all the public things inside the dll.
● Unity3d needs to call the public method (Awake(),
Update(), OnGUI()...) of the MonoBehaviour subclass and
these method must be excluded from renaming by setting
the "Obfuscation Rules".
33. Assembly Specific Settings 3:
Optimizations:
● "Mark Classes As Final..." option, as it will increase the
performance a bit.
Control Flow Obfuscation:
● Max level. Max level will boat the final dll. If you want to
reduce file size, choose Medium level.
34.
35. Obfuscation Rules 1:
CO process the rules from top to bottom. If the rules order
is different, some classes may be wrongly obfuscated.
● All the class name should not be renamed.
I tried that some non MonoBehaviour subclass does not
get referenced by reflection, it just fail to work if
renamed. If your game can have all the non
MonoBehaviour subclass renamed and run correctly,
remove this rule.
36.
37. Obfuscation Rules 2:
● All the class name of MonoBehaviour subclass
should not be renamed, otherwise Unity engine
cannot find your class at runtime. The exception is the
class added by AddComponent.<T>() instead of adding
the class by Unity editor.
38.
39. Obfuscation Rules 3:
● All the public fields and properties of
MonoBehaviour subclass should not be
renamed, since the value set in Unity editor is
applied to them.
40.
41. Obfuscation Rules 4:
● Some classes contain methods called by reflection
needs to be excluded from renaming. Those classes
should extend the interface KeepPublicMethod, which
is an empty interfaces with nothing inside it.
42.
43. Obfuscation Rules 5:
● Some third party code, such as iTween and MiniJSON,
is better not to rename. Because they may use the
reflection or other dynamic features of C#.
44.
45. Obfuscation Rules 6:
● All the callback method of MonoBehaviour
should be excluded from renaming, such as
Update(), Awake()...
46. How to use the command line instead of GUI
The command lines are:
● take out the dll file from the apk file
● obfuscate the dll
● put the dll back to the apk
● sign it with your signature
● finally optimize the apk file
48. Command line
Create a directory for the files, for example, c:temp. Then:
1. Copy the obfuscator setting file "ofuscator_setting.obproj" to
"c:temp".
2. Copy your key store, for example, to "c:
tempAndroidSpecificHeyZombie.keystore".
3. Create this directory: "c:
tempAndroidSpecificObfuscatedassetsbinDataManaged"
.
4. Build the apk and save it to "d:temptest.apk"
5. Go to c:temp
6. Open a command prompt and type these:
49. Open a command prompt 1
move test.apk working.zip
del AndroidSpecificOriginal*.dll /q
rem 7z is the 7-zip command line
7z e -y -r -oAndroidSpecificOriginal working.zip
assetsbinDataManaged*.dll
rem Run Obfuscator:
del AndroidSpecificObfuscatedassetsbinDataManaged*.dll /q
"C:Program Files (x86)LogicNP SoftwareCrypto Obfuscator
For .Net 2013 R2co.exe" projectfile=ofuscator_setting.obproj
50. Open a command prompt 2
rem Don't forget to remove the old signature information.
7z d working.zip "META-INF*"
cd AndroidSpecific/Obfuscated
7z u ../../working.zip assetsbinDataManagedAssemblyCSharp.dll
cd ../../
move working.zip working.apk
rem Should see the apk is not signed.
jarsigner -verify working.apk
51. Open a command prompt 3
rem This step need password:
jarsigner -verbose -sigalg MD5withRSA -digestalg SHA1 keystore AndroidSpecific/HeyZombie.keystore working.apk
HeyZombie
YourPassword
rem optimize the apk file.
zipalign -f -v 4 working.apk HeyZombie.apk
del working.apk
rem Verify and should see it signed.
jarsigner -verify HeyZombie.apk
54. Here is my coding guidelines:
● The above obfuscator setting can be that simple
because I use very few of the reflection or dynamic
feature of C#.
55. Here is my coding guidelines:
● Use this AddComponent.<T>() instead of
AddComponent(String className) if you want to
obfuscate the class name.
● Use the virtual method / interface to act as callback
instead of using SendMessage(). If SendMessage() is
used, then the target method name of SendMessage()
cannot be renamed. iTween class uses a lot of
SendMessage(), so I need to exclude the whole iTween
class from renaming.
56. Here is my coding guidelines:
● Use StartCoroutine(IEnumerator routine) instead of
StartCoroutine(String methodName, object value),
although I cannot use StopCoroutine(). The technique
I used to code the coroutine is similar to multithread program. Every coroutine has code to
determine when to stop execution itself instead of
relying on the parent object to stop it. In case you
really need to use the string version of
StartCoroutine(), set the coroutine to public and
implements KeepPublicMethod interface.
57. Here is my coding guidelines:
● Concentrate all the animation event code to a single
class, and don't obfuscate the public method of this
class by implementing the KeepPublicMethod
interface. If the method name for the animation event
code is renamed, your game won't run correctly.
62. Kerckhoffs's principle
In cryptography, Kerckhoffs's principle (also called
Kerckhoffs's desiderata, Kerckhoffs's assumption,
axiom, or law) was stated by Auguste Kerckhoffs in the
19th century:
“A cryptosystem should be secure
even if everything about the system,
except the key, is public knowledge.”
63. PlayerPrefs Encryption
Why?
● Prevent simple cheating
● Prevent cracking IAB purchases (if you cache anything
locally)
● In general good practice for sensitive data (like game
progress)
How?
● Encrypt key / values before inserting them in the
PlayerPrefs
● Use a user-specific encryption so prefs cannot be copied,
but still shared in a cloud
66. Block Encryption modes
● Block ciphers encrypt only fixed-size blocks. If you
want to encrypt something that isn’t exactly one block
long, you have to use a block cipher mode.
● Currently, NIST has approved nine modes of the
approved block ciphers in a series of special
publications.
● There are six confidentiality modes (ECB, CBC, OFB,
CFB, CTR, and XTS-AES), one authentication mode
(CMAC), and two combined modes for confidentiality
and authentication (CCM and GCM).
71. PaddingMode Enumeration
● ANSIX923
○
○
○
○
The ANSIX923 padding string consists of a sequence of bytes filled
with zeros before the length.
The following example shows how this mode works. Given a
blocklength of 8, a data length of 9, the number of padding octets
equal to 7, and the data equal to FF FF FF FF FF FF FF FF FF:
Data: FF FF FF FF FF FF FF FF FF
X923 padding: FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 07
● ISO10126
○
○
○
○
The ISO10126 padding string consists of random data before the
length.
The following example shows how this mode works. Given a
blocklength of 8, a data length of 9, the number of padding octets
equal to 7, and the data equal to FF FF FF FF FF FF FF FF FF:
Data: FF FF FF FF FF FF FF FF FF
ISO10126 padding: FF FF FF FF FF FF FF FF FF 7D 2A 75 EF F8 EF 07
72. PaddingMode Enumeration
● PKCS #7
○
○
○
○
The PKCS #7 padding string consists of a sequence of bytes, each
of which is equal to the total number of padding bytes added.
The following example shows how these modes work. Given a
blocklength of 8, a data length of 9, the number of padding octets
equal to 7, and the data equal to FF FF FF FF FF FF FF FF FF:
Data: FF FF FF FF FF FF FF FF FF
PKCS7 padding: FF FF FF FF FF FF FF FF FF 07 07 07 07 07 07 07
● None
○
No padding is done.
● Zeros
○
The padding string consists of bytes set to zero.
87. Encryption of Scripts
Why?
●
●
●
●
Scrips are generally insecure
Gameplay could be altered
Security checks could be disabled
Code needs to be “hidden” for some reason (i.e.
IAB logic)
88. Encryption of Scripts
How?
● Compile scripts outside Unity
● Run a sysmmetric / asymmetric encryption on the
Script.dll
● Choose a delivery mechanism
○ Embed in the application, or
○ Download it from a trusted server
● Decrypt the Script.dll in memory
● Load it through Assembly.Load(byte[])
89. Compile scripts outside Unity
● Compile the script (Plugin.cs) with ‘gmcs’
● Reference the UnityEngine.dll assembly to access to
Unity
$ gmcs
-target:library
-out:Script.dll
-r:AndroidPlayer/Managed/UnityEngine.dll
Plugin.cs
90. Encrypt the assembly
● Using OpenSSL
● Converted to ‘text’ using Base64 encoding
● Result can be embedded in Unity as a TextAsset
$ openssl rc2 - nosalt -p -in Script.dll -out Encrypted.bin
key = …
iv = …
$ base64 Encrypted.bin > ~/UnityProject/Assets/Encrypted.txt
91. Example: Plugin.cs
public class Plugin : MonoBehaviour
{
void Start()
{
StartCoroutine(Log());
}
IEnumerator Log()
{
Debug.Log("Script Loaded");
yield return new WaitForSeconds(1f);
StartCoroutine(Log());
}
}
92. Command line
C:UsersjooDocumentsCrypto_ScriptAssets>gmcs
-target:library
-out:Plugin.dll
-r:"C:Program Files (x86)UnityEditorDataManagedUnityEngine.dll"
Plugin.cs
C:UsersjooDocumentsCrypto_ScriptAssets>openssl
rc2 -nosalt -p -in Plugin.dll
-out Plugin.bin
enter rc2-cbc encryption password:
Verifying - enter rc2-cbc encryption password:
key=409C1892B68CB394799262AC57F6D4F1
iv =7AC77EFF3F65E62D
C:UsersjooDocumentsCrypto_ScriptAssets>openssl
Plugin.txt
base64 -in Plugin.bin -out
98. About RC2,
http://en.wikipedia.org/wiki/RC2
Designers
First published
Ron Rivest
leaked in 1996, designed in 1987
Key sizes
8–1024 bits, in steps of 8 bits;
default 64 bits
64 bits
Source-heavy Feistel network
16 of type MIXING, 2 of type
MASHING
Block sizes
Structure
Rounds
Best public
cryptanalysis
A related-key attack is possible
requiring 234 chosen plaintexts
(Kelsey et al., 1997).
99. Command line
C:UsersjooDocumentsCrypto_ScriptAssets>gmcs
-target:library
-out:Plugin.dll
-r:"C:Program Files (x86)UnityEditorDataManagedUnityEngine.dll"
Plugin.cs
C:TempPlugin>openssl aes-128-cbc -nosalt -p -in Plugin.dll -out Plugin.bin
enter aes-128-cbc encryption password:
Verifying - enter aes-128-cbc encryption password:
key=409C1892B68CB394799262AC57F6D4F1
iv =7AC77EFF3F65E62D9D3438FB5031C27F
C:UsersjooDocumentsCrypto_ScriptAssets>openssl
Plugin.txt
base64 -in Plugin.bin -out
101. Openssl,
http://www.openssl.org/docs/apps/enc.html
● enc - symmetric cipher routines
○ All the block ciphers normally use PKCS#5 padding
also known as standard block padding: this allows a
rudimentary integrity or password check to be
performed. However since the chance of random
data passing the test is better than 1 in 256 it isn't
a very good test.
102. PKCS#5 vs PKCS#7,
●
http://goo.gl/k11EB3
PKCS#5 padding is identical to PKCS#7
padding, except that it has only been
defined for block ciphers that use a 64 bit
(8 byte) block size. In practice the two can
be used interchangeably.
107. Encryption of Assets
Why?
● Some assets might need to be protected from
tampering
● “Assets” doesn’t necessarily mean just “textures”;
could be
○
○
○
○
○
Game logic
Dalvik bytecode
Script code
Native code
… “anything”
108. Encryption of Assets
How?
● Create an AssetBundle from the “secret” assets
● Run a symmetric / asymmetric encryption on the
AssetBundle.unity3d
● Choose a delivery mechanism
○ Embed in the application, or
○ Download it from a trusted server
● Decrypt the AssetBundle.unity3d in memory
● Load it through AssetBundle.CreateFromMemory
(Byte[])
109. Command line
C:Temp>openssl rc2 -nosalt -p -in gstar.unity3d -out gstar.bin
enter rc2-cbc encryption password:
Verifying - enter rc2-cbc encryption password:
key=EDD8F85DA1A1E7EEC271266DBD684452
iv =68F7497BECA087F2
C:Temp>openssl
base64 -in gstar.bin -out gstar.txt
113. Key save in trust server
Why?
● Local are generally insecure
● Gameplayer exchange save data each other
114. Key save in trust server
How?
● Make a key server
● Gameplayers download different keys from a key
server
● Every time get a new key
● Choose a encryption mechanism
○ Using Unity script encryption & decryption
● Decrypt save data in memory
● Load it through Assembly.Load(byte[])
120. RAM problem
● RAM search programs look for a specific set of
conditions, like numbers that have increased,
decreased, not changed, equal to, greater
than, less than, not equal to and other logical
comparison operations. To make this method
pretty much unusable, all you need to do is
make your score (which is visually a number)
not to be a number inside memory.
121. Conclusion
● Sensitive code must be protected
● Combine the different approaches, and create new
ones
● Finally: Do spend too much time on this
○ Also update the logic for each new release