개발슝이의 블로그
유니티 암호화 2편, 외부 DLL 암호화 본문
개발 이유
유니티로 컴파일 하여 배포한 APK 를 루팅한 기기(스마트폰 등)에서 APK 를 뽑아와 해체하면, 손쉽게 외부 DLL 에 접근이 가능합니다. 이렇게 접근 한 뒤 후킹 가능한 DLL 로 바꿔치기 하여, 다시 APK 로 묶으면, 손쉽게 해킹이 가능합니다. 또한 ILSpy 로 코드를 디스어샘블하여 볼 수 있습니다.
그래서 외부 컴파일된 DLL 을 암호화 하여, 동적 로드 하여, 사용한다면, 조금이라도 해커를 귀찮게 할 수 있습니다. 이 내용은 다음 링크에서 확인 할 수 있습니다.
링크
http://unitystudy.net/bbs/board.php?bo_table=newwriting&wr_id=356
http://www.slideshare.net/williamyang3910/unitekorea2013-protecting-your-android-content-21713675 - 32 page
DLL 암호화 절차
1. 외부에서 컴파일된 DLL 을 open ssl 을 이용해 암호화 한다.
- 디스어샘블을 막고 무결성을 검증하기 위해
2. 암호화된 DLL 을 base64 인코딩 한다.
- 암호화 되면, text 형태로 파일을 읽어오기 힘들기 때문에. (이 과정 없이 바로 바이너리로 로딩해도 됩니다)
3. 유니티에 인코딩된 파일을 알맞는 자리에 위치 시킨다.
4. 유니티로 base64로 인코딩된 파일을 읽고, byte[] 로 변환시킨다.
5. 변환 후 복호화 한다.
6. 복호화된 대상을 동적 로드 한다.
7. 쉽게 사용하기 위해 래퍼를 만들어 인터페이스를 추가하여 사용한다.
DLL 암호화 방법 및 사용법
1. oepnSSL 을 다운로드 받는다. 자신의 OS 에 맞는 버전을 받아 사용 하세요.
- 윈도우 사용자의 경우, 바이너리로 받으면 편합니다.
- https://www.openssl.org/related/binaries.html
2. openssl 명령어를 통해 aes-256-cbc 로 암호화 한다. 이때 암호를 입력 하라 나오는데 입력하고 key 와 iv 를 복사해 둔다.
1 2 3 4 5 | openssl aes-256-cbc -nosalt -p - in HOTween.dll -out HOTween.bin enter aes-256-cbc encryption password: cb13ad3fe5c9 Verifying - enter aes-256-cbc encryption password: cb13ad3fe5c9 key=B3457F4440802957414149DF2640A18D1CF9BFEFABDB69D3075B6DF7F879D88D iv =F48D97C3CE4CAB228A9946464E6D9065 |
3. openssl 명령어를 통해 base64 인코딩 한다.
예) openssl base64 -in HOTween.bin -out HOTween.txt
4. HOTween.txt 를 유니티 Resource 폴더에 위치 시킨다.
5. 로더를 만든다. SecurityDLLLoader.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | using System.Security.Cryptography; public class SecuirtyDLLLoader { private const string key = "B3457F4440802957414149DF2640A18D1CF9BFEFABDB69D3075B6DF7F879D88D" ; private const string iv = "F48D97C3CE4CAB228A9946464E6D9065" ; public static byte [] HexStringToByteArray( string hex) { byte [] bytes = new byte [hex.Length / 2]; for ( int i = 0; i < hex.Length; i += 2) { bytes[i / 2] = System.Convert.ToByte(hex.Substring(i, 2), 16); } return bytes; } public static System.Reflection.Assembly LoadSecurityDLL( byte [] bytes) { using (RijndaelManaged aes256 = new RijndaelManaged()) { aes256.KeySize = 256; aes256.BlockSize = 128; aes256.Key = HexStringToByteArray(key); aes256.IV = HexStringToByteArray(iv); aes256.Mode = CipherMode.CBC; aes256.Padding = PaddingMode.PKCS7; using (ICryptoTransform ct = aes256.CreateDecryptor()) { byte [] descrypted = ct.TransformFinalBlock(bytes, 0, bytes.Length); return System.Reflection.Assembly.Load(descrypted); } } } }
|
6. 손쉽게 사용할 레퍼를 만든다. SecurityHOTween.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | using UnityEngine; using System.Collections; public class SecurityHOTween { private static System.Reflection.Assembly _asm; private static System.Type _typeHOTween; private static System.Type _typeTweenParams; private static System.Reflection.MethodInfo _mtdInit; private static System.Reflection.MethodInfo _mtdTo; private static System.Reflection.MethodInfo _mtdProp2; public static void Init() { // load dll TextAsset hotweenText = Resources.Load<TextAsset>( "Lib/HOTween" ); byte [] binaryDLL = System.Convert.FromBase64String(hotweenText.text); _asm = SecuirtyDLLLoader.LoadSecurityDLL(binaryDLL); // get types _typeHOTween = _asm.GetType( "Holoville.HOTween.HOTween" ); _typeTweenParams = _asm.GetType( "Holoville.HOTween.TweenParms" ); // get method _mtdInit = _typeHOTween.GetMethod( "Init" , new System.Type[] { }); _mtdTo = _typeHOTween.GetMethod( "To" , new System.Type[] { typeof ( object ), typeof ( float ), _typeTweenParams }); _mtdProp2 = _typeTweenParams.GetMethod( "Prop" , new System.Type[] { typeof ( string ), typeof ( object ) }); // init _mtdInit.Invoke(_typeHOTween, null ); } public static void To( object p_target, float p_duration, object [] p_parms) { object instanceTweenParms = System.Activator.CreateInstance(_typeTweenParams); object propResult = _mtdProp2.Invoke(instanceTweenParms, p_parms); _mtdTo.Invoke(_typeHOTween, new object [] { p_target, p_duration, propResult }); } } |
7. 테스트!!!
1 2 3 4 5 6 7 8 9 10 11 12 | using UnityEngine; using System.Collections; public class CommonEditor : MonoBehaviour { void Start() { SecurityHOTween.Init(); SecurityHOTween.To(transform, 5.0f, new object [] { "position" , Vector3.one * 20.0f }); } } |
여담
ㆍ openssl 을 이용한 암호화 전략은 여러가지 이유로 편하다.
- 다양한 툴과 여러 라이브러리가 존재하기 때문이다.
ㆍ 동적 DLL 로드의 경우, 성능상의 이슈가 있으므로, 꼭 간단히 만들어 테스트 해보고진행 해야 한다.
- 애초에 동적 DLL 로 쓸꺼다라는 개념으로 프로그래밍 했다면 좀 더 편했을 수 있겠다.
ㆍ 위의 것을 조금 바꾸면, 스크립트 암호화가 되는데, 이는 다음 편에서....
'Unity3D' 카테고리의 다른 글
유니티 암호화 1편, PlayerPrefs 암호화 (0) | 2017.03.01 |
---|