Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
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
Tags
more
Archives
Today
Total
관리 메뉴

개발슝이의 블로그

유니티 암호화 2편, 외부 DLL 암호화 본문

Unity3D

유니티 암호화 2편, 외부 DLL 암호화

개발슝이 2017. 3. 1. 00:25

개발 이유


유니티로 컴파일 하여 배포한 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