• 검색 결과가 없습니다.

-dypar- 게임 취약점 및 방어 솔루션 Unity 엔진으로 만들어진 모바일

N/A
N/A
Protected

Academic year: 2022

Share "-dypar- 게임 취약점 및 방어 솔루션 Unity 엔진으로 만들어진 모바일"

Copied!
17
0
0

로드 중.... (전체 텍스트 보기)

전체 글

(1)

Unity엔진으로 만들어진 모바일 게임 취약점 및 방어 솔루션

-dypar-

(2)

시작 전

이 문서에서는 게임을 악의적 목적으로 공격하는 사람을 흔히 잘 알려진 해커가 아닌 크래커라고 부른다. 해커와 크래커의 차이는 해커는 컴퓨터에 능숙한 전문가를 뜻하는 말이고 법을 준수한다.

크래커란 해커와 다르게 배운 지식으로 불법적인 행위를 하는 사람을 뜻하는 말이다. 따라서 이 문서에서는 공격자를 크래커라고 칭하며 공격자가 게임을 해킹하는 행위를 크랙 혹은 크랙킹이라 고 부른다.

이 문서에 적은 내용들은 필자가 직접 테스트 해보고 생각해낸 솔루션을 바탕으로 적었으며 100%

확실하지 않을 수도 있다. 그러기에 이 문서를 완전히 믿고 따르기 보다는 참고만 하거나 솔루션 들을 독자들 자신 만의 방법으로 보완, 보강해서 사용한다면 더 강한 보안을 솔루션이 만들어질 것이다.

또한 이 문서에 적은 방어 솔루션들은 전문적인 코딩 방식으로 안티치트를 만드는 것이 아닌 보 다 쉬운 방법으로 크래커들이 크랙을 포기하게 만들거나 크래커를 색출하기 위한 목적으로 만들 어진 솔루션들이다. 전문적인 크래커들을 상대할 계획이라면 이 문서의 솔루션들로는 부족할 것 이다. 다시 한번 강조하지만 이 솔루션들은 크래커를 100% 막을 수 있다 장담할 수 없다. 하지만 적은 솔루션들을 잘 응용한다면 왠만한 툴키디나 초,중급 크래커들은 막을 수 있을 것이라 생각 한다.

(3)

Unity Mono 빌드와 il2cpp 빌드

해킹을 방지하기위해 Unity 게임에서 맨 처음 확인해야하는 것은 바로 Mono 빌드인지 il2cpp 빌 드인지 확인해야하는 것이다. 요즘 게임은 구글 플레이 스토어 정책 때문에 대부분 il2cpp로 빌드 된 게임을 출시하지만 간혹 예전에 만들어진 게임이나 빌드 시간이 오래 걸린다는 이유 그리고 디버깅이 힘들다는 단점 때문에 Mono 빌드로 개발하는 개발자도 있다.

그림 1 소스코드

그림 2 좌) mono빌드 우) il2cpp 빌드

그림 2는 예시로 만든 그림 1의 소스 코드를 Unity에서 각각 mono와 il2cpp로 빌드 후 dnspy라 하는 .net 디컴파일러로 디컴파일 해본 모습이다. 보다시피 좌) 같은 경우는 코드가 거의 그대로 디컴파일 되어있다. 전문 해커가 아니라도 프로그래밍 언어를 조금이라도 안다면 충분히 코드를 수정해서 원하는 바를 이룰 수 있다.

예시로 그림 2 좌)의 Buy 함수를 보면 구매 전 CanPurchase 함수를 통해 가진 돈이 구매 가격보 다 많은지 검사하고 많다면 가진 돈에서 구매 가격을 차감하고 true로 리턴을 한다. 리턴 값을 바

(4)

탕으로 Buy에서는 return 값이 true면 구매완료 로그를 띄우고 false면 돈이 모자르다는 로그를 띄운다. 즉 return 값을 true로만 해주면 돈이 많든 적든 무료로 구매 처리가 되는 것이다.

또한 getLevel 같은 경우는 PlayerPrefs라는 유니티 내장 함수를 통해서 저장된 레벨을 가져오고 그 값을 리턴하는 함수다. 이거 같은 경우도 저장된 레벨과 상관없이 앞에 return 99;를 넣는다면 99레벨이 단숨에 될 수 있고 임의의 값을 넣으면 임의의 값으로 레벨이 변하는 것이다.

반면 그림 2 우)를 본다면 노출된 코드가 아예 없다. 그림 2 우)도 해킹할 수 있는 방법이 없는 것은 아니지만 어셈블리어, 리버싱을 해야 하므로 대부분의 초보 크래커들은 메모리 치팅 기법을 사용해보고 안된다면 포기 할 수도 있다.

그림 3 il2cpp와 mono

Mono 빌드 방식은 c# 코드를 IL코드로 변환하고, 이 코드를 mono 가상 머신이 읽게 되는 방식 이다. 반면 il2cpp는 IL 코드를 c++ 소스코드로 변환하게 되고 c++ 컴파일러에서 네이티브 라이 브러리(il2cpp.so 파일 같은)가 생성되는 구조다. 리버싱 경험이 있다면 알다시피 c,c++ 같은 언어 를 디컴파일 시 어셈블리어로 리버싱을 하게 된다. 마찬가지로 il2cpp는 c++ 소스코드로 변환을 하기 때문에 mono처럼 코드가 그대로 노출되지 않는 것이다.

결론적으로 il2cpp는 크랙이 불가능하나? 답은 아니다. 리버싱이나 어셈블리어를 조금이라도 할 줄 안다면 충분히 가능하다. 그래도 메모리 치팅이나 소스코드만 수정 할 줄 아는 초보 크래커들 은 충분히 막을 수 있다. 또한 어셈블리 상태를 디버깅 그리고 패치를 해야 하기 때문에 정교한 패치(단순 변수 수정이 아닌 메크로, 에임핵)는 전문적인 크래커가 아니면 힘들다.

또한 무조건적으로 il2cpp로 빌드를 할 필요는 없다. Mono는 빠른 빌드와 버그가 잘 생기지 않는 다는 장점이 있다. Mono 빌드를 원한다면 코드를 난독화를 하면 된다. 초보든 고수든 난독화가 걸려있으면 크랙까지의 시간이 오래 걸리며 중간에 포기 할 수도 있다. 또한 애써 크랙을 했는데 안티 치트 기법에 걸린다면 아예 포기해 버릴지도 모른다.

(5)

그림 4 Unity il2cpp 빌드 방법

il2cpp 빌드 방법은 Build Setting – PlayerSetting – Cinfiguration의 Scripting Backend에서 Mono를 il2cpp로 바꾸면 된다.

(6)

메모리 치팅

메모리 치팅은 프로그래밍 언어를 접해보지 않은 사람도 쉽게 변수들을 조작할 수 있다. 대표적 인 툴로는 게임 가디언(모바일 전용), 치트 엔진(pc 전용)등이 있는데 난이도도 매우 쉽고, 시간도 별로 걸리지 않는다. 하지만 제대로 된 방어책이 없다면 애써 만든 게임은 mono, il2cpp 상관없이 게임에서 사용되는 모든 변수는 크래커들의 손에 좌지우지 될 것이다.

이 메모리 치팅 공격의 가장 큰 장점은 앞에 언급했듯이 난이도가 쉽다는 것이다. 프로그래밍 능 력이 필요 없기 때문에 이 공격으로 게임을 크랙 하는 일반인들도 많다.(단지 몇 분 구글링을 해 본다면 툴도 구할 수 있고 사용법 또한 알 수 있다.)

단점은 단순 변수 조작만 가능하고 메모리 치팅 공격의 방지 기법이 쉬운 편이다.

방지 기법을 알기 전 메모리 치팅 원리를 설명하겠다..

먼저 메모리 치팅을 하기 위해서는 타겟 프로그램을 실행하고 메모리 치팅 툴을 타겟 프로그램에 Attach하게 해야 한다.

그림 5 메모리 치팅 공격의 원리

Attach를 성공했다면 이제는 메모리에서 원하는 변수를 찾으면 된다. 그림 5는 치트 엔진의 원리 를 그림판에서 만들어 본 것이다. 변수 A란 값을 찾는다 가정 하겠다.

1. 먼저 A의 값에 해당하는 50을 치트 엔진을 통해 메모리에서 검색한다. 그러면 현재 값이 50인 모든 변수가 치트 엔진에서 출력해 준다(이를 A~Z라고 가정한다.).

(7)

2. 변수 A의 값을 의도적으로 감소 혹은 증가시킨 후 이 과정을 통해 만들어진 값인 40을 검색한다. 그러면 처음에 검색된 A~Z 중 값이 50에서 40으로 바뀐 변수만을 출력해 준 다.

3. 2번 과정을 반복해서 변수 후보를 하나만 남게 하거나 적게 남도록 불필요한 변수들을 소거 시킨다.

위와 같은 과정을 통해 변수 후보들을 제거 시킨 후 찾은 변수를 원하는 값으로 변조한다면 메모 리 치팅을 성공한 것이다. 만약 만들 게임 혹은 만들어진 게임의 중요 변수들이 서버를 베이스로 하고 있다면 메모리 치팅이 매우 힘들고 또한 치팅에 성공한다 해도 서버에 비정상적인 값을 캐 치하는 알고리즘 하나만 짜둔다면 색출하기 쉬울 것이다.

하지만 소규모 게임들은 보통 서버 베이스가 아니다. 그런 게임 같은 경우는 어떻게 방어 할 수 있는지 적어보겠다.

1. Anti-Cheat Toolkit

그림 6 Anti-Cheat Toolkit

그림 6은 유니티 에셋 스토어에서 판매하고 있는 안티치트 에셋이다. 가격은 한화로 약 5만원으 로 비교적 저렴하다.

메모리 치팅 방지가 주 기능이며 Obscured 라는 데이터 타입을 지원하기 때문에 일반 데이터보 다 좀더 안전하게 변수를 관리할 수 있다..(예) int -> ObsecuredInt) 또한 스피드핵 탐지, 월핵 시 스템 시간을 조작해 데일리 보상 같은 걸 얻는 행위도 방지하고, 그리고 게임이 실행 중일 때 코 드를 인젝션하는 행위 또한 감지할 수 있다.

장점은 사용이 간단해서 누구나 쉽게 안티치트를 적용시킬 수 있고 치트 엔진, 게임 가디언 같은 메모리 치팅 툴들을 이용한 해킹에 강하다.

(8)

단점은 오래전에 출시된 에셋이기 때문에 해체 및 우회 법은 잘 알려져 있다. 또한 런타임에서만 작동하기 때문에 코드 수정을 통한 크래킹은 막을 수 없다.(코드 수정을 통한 크랙은 제작자가 만 든 또 다른 에셋, Obfuscator로 코드를 난독화해서 방지할 수 있다.)

비록 코드 변조 공격은 방어가 불가능하지만 한번 사둔다면 평생 사용 가능하고 또한 왠만한 메 모리 치팅 공격은 막을 수 있다. 그리고 안티치트 내부 코드 수정 또한 가능하기 때문에 능력이 된다면 보안을 보강할 수 있다.(개인적으로 유니티 개발자라면 살만 하다고 생각한다.)

2. 메모리 치팅 방지 솔루션

이 솔루션은 필자가 직접 연구해서 만든 것이다.

이 솔루션 기법을 간단하게 설명하자면 이렇다.(보호 하려는 변수 : a)

a보다 일정한 차이의 값을 할당하는 변수를 하나 더 생성한다(이를 b라 칭한다.). 그리고 a의 값 이 증가 혹은 감소 할 때마다 b도 똑같은 값을 증가 혹은 감소해준다.(a에 10을 더할 때 b의 값 에도 10 더해준다) 그러면 항상 a와 b의 차이는 항상 일정할 것이다.

a가 게임내에서 돈 역할을 한다 가정할 때 크래커는 메모리 치팅 툴로 돈이 50이면 50, 40이면 40을 돈에 해당하는 값을 검색해서 돈의 값을 담고있는 변수 a를 찾아낼 수 있을 것이다. 하지만 a의 값과 일정한 차이가 나는 값이 할당된 b는 크래커가 찾는 변수 a와 다른 값을 갖고 있기 때 문에 알고 찾는게 아닌 이상 찾기 매우 힘들다. 이를 이용한 솔루션이다.

a와 b의 차이가 10이라 생각해 보자. 변수a의 값을 크래커가 메모리 치팅 기법으로 변조한다면 변조 후에는 더 이상 a와 b의 차이가 10이 아닐 것이다.(예로 초기 a 값이 100, b 값이 110일 때 a 변수의 값을 200으로 변조해 버리면 a와 b의 차이는 -90이 된다.) 이 차이를 활용한 조건식 if (b-a != 10) 같은 것을 만든 후 update 함수에 넣어 매순간 체크하고 만약 값의 변조가 감지되면 강제 종료, 세이브 데이터 삭제 등 변수 변조를 무효화 시킬 수도 있다.

설명이 이해가 안될 수도 있으므로 간단하게 예시를 준비해 봤다.

(9)

그림 7 예시 코드

그림 7은 그림 3에서 예시로 보여줬던 코드에 메모리 치팅 감지 코드를 추가한 것이다.

함수 설명

LoadMoney() 게임 시작시 저장된 돈을 로드하는 함수다.

Buy() 물건을 사려할 때 CanPurchase 함수를 호출해 구매 가능 여부를 리턴 받고 그에 따라 구매 유무를 결정하는 함수다.

CanPurchase(int price) 보유 돈이 구매 가격보다 많다면 true를 리턴하고 아니라면 false를 리 턴한다.

표 1 설명

먼저 LoadMoney에는 securityMoney라는 변수를 추가했다. securityMoney 변수는 money 변수보 다 10 높도록 값 할당을 한다. CanPurchase 함수에서는 securityMoney-=price 코드를 추가하여 항상 securityMoney 보다 money가 10 작도록 유지한다. 그러면 money 변수가 크래커에 의해 값 이 변조되지만 않는다면 항상 securityMoney와 money의 차이는 10일 것이다. Buy() 함수에 if (securityMoney – 10 != money)라는 조건문을 추가해서 구매하는 함수가 호출될 때 securityMoney 와 money의 차이가 10인지 검사한다. 만약 차이가 10이 아니라면 “해킹이 감지 됐습니다”라는 로그를 남기고 앱을 종료해 버린다.

이 솔루션의 장점으로는 간단한 코드 몇 개 추가로도 중요한 변수들을 메모리 치팅 공격으로부터 방어할 수 있다는 것이고 무료라는 것이다.

단점은 코드 변조 공격 과정에서 쉽게 우회가 가능하고 코드 변조를 통해 변수들의 값을 바꾼다 면 막을 수 없다.

(10)

코드 변조 공격

코드 변조 공격은 필자가 생각했을 때 가장 강력한 공격인 것 같다. 게임에 사용되는 코드들을 크래커 마음대로 수정할 수 있다. 광고를 제거할 수도 있고 메크로,봇 제작 등 크래커의 목적에 맞게 만들어 버릴 수 있다. 특히 mono 빌드 게임 같은 경우는 c# 코드 그대로 디컴파일 되기 때 문에 리버싱을 할 줄 모르는 크래커라도 코딩을 할 줄 안다면 정교하게 수정 할 수 있다. 반면에 il2cpp 빌드 게임은 빌드 과정에서 c++ 코드로 변환 후 .so파일로 만들어지기 때문에 hex와 어셈 블리어를 다룰 줄 알아야지 코드 변조가 가능하다.

1. 소스 코드 난독화

난독화란 암호화와 비슷한 의미지만 암호화는 암호화 과정만 있는 경우를 말하고 난독화는 프로 그램 상에 암호화 과정과 복호화 과정이 모두 있는 것을 뜻한다.

소스 코드 난독화의 장점은 소스코드를 알아보기 힘들게 바꿔 버릴 수 있다는 것이다. 난독화는 mono 빌드의 단점인 보안에 취약하다는 점을 보완할 수 있다. 난독화를 한다면 암호화된 코드를 실행 시 복호화 과정을 통해서 소스코드를 복구할 수 있다. 따라서 dnspy 같은 c# 디컴파일러를 사용해서 코드 변조 시도 시 크래커를 혼란스럽게 만들 수도 있고 군데 군데 페이크 코드를 넣는 다면 크래커가 변조 공격을 포기해 버릴지도 모른다.

난독화의 단점은 난독화를 해도 어느 정도는 알아 볼 수 있는 수준으로 난독화가 되기 때문에 끈 기가 있는 크래커라면 오랜 시간에 걸쳐 시도 함으로써 변조에 성공 할지도 모른다. 이를 막기위 해 너무 높은 수준의 난독화를 한다면 시스템에 무리가 갈 수 있고 성능이 저하될 수 있다. 따라 서 큰 규모의 게임이나 크랙 발생 시 피해가 큰 게임만 난독화를 하는 것을 추천한다.

그림 8 Obfuscator 에셋

(11)

에셋으로는 가장 좋은 것은 Obfuscator인 것 같다. 난독화에 깊은 지식이 없어도 간단하게 난독 화를 시킬 수 있고 메소드 이름 변경, 매개 변수 이름 변경, 필드 이름 변경, 클래스 이름 변경, 가짜 메소드 추가 같은 기능들도 제공되어 크래커를 훨씬 힘들게 만들 수 있다. 또한 il2cpp 빌드 방식 같은 경우는 global-metadata.dat 파일에 문자열 및 메소드, 클래스 이름 등이 노출되는데 이 파일에도 난독화가 적용되어 보안이 강화 된다.

난독화 방법으로는 그 밖에도 Dotfuscator 등 여러가지 있지만 개인적으로는 난독화는 성능이 저 하되기 때문에 비추천한다.

2. il2cpp 빌드

맨 앞에서 설명했듯이 mono 빌드는 보안에 많이 취약하다. il2cpp로 빌드 한 게임을 변조하기 위 해서는 리버싱 기술이 필요하기 때문에 il2cpp 빌드 또한 코드 변조 공격 방어책의 한 방법이 될 수 있다.

3. 함수 이름

정말 간단한 게임이 아닌 이상 대부분의 게임의 코드의 양은 엄청날 것이다. 그 엄청난 양의 코 드를 크래커들은 하나하나 살펴보지 않는다. 시간이 오래 걸린다는 이유도 있고 크래커들 입장에 서는 단지 자신의 목적에 맞는 함수만 수정하면 되기 때문에 하나하나 살펴보기 보다는 디컴파일 내의 검색 기능을 사용해 함수를 찾는다.

그림 9 dnspy 검색 기능

그림 10은 dnspy의 검색 기능을 사용해서 찾고자 하는 함수를 검색한 모습이다(테스트 앱이다).

크래커가 현재 보유한 돈을 관리하는 함수를 찾고 싶다 가정했을 때 크래커는 수많은 코드를 하 나하나 뒤져서 찾기 보다는 그림 11처럼 검색 창에서 돈과 관련된 영어단어 coin, money, cash 등 을 검색해서 원하는 함수를 찾을 수 있을 것이다. 보면 Money라는 단어를 검색했을 때 테스트용 앱에서 돈을 관리하는 함수인 PresentMoney라는 함수가 노출됐다.

대부분의 개발자들은 이처럼 함수이름을 함수가 하는 기능에 관련되어 짓는다. 이는 나쁜 것은 아니다. 기능에 관련되어 짓는다면 다른 개발자들과의 협업에도 도움이 되고 다른 스크립트에서 함수를 호출할 때 그 함수의 정확한 코드는 몰라도 함수 이름만 보고서 대강 기능을 짐작할 수

(12)

있기 때문이다.

특히 il2cpp 빌드 게임일 경우 크래커에게는 소스코드가 노출되지 않는다. 그래서 크래커는 함수 이름에 의존해서 크랙 할 함수를 찾아 낼 수 밖에 없다. 만약 광고를 호출하는 함수가 크래커의 눈에 들어왔다고 생각해보자. 어셈블리어를 모르는 크래커도 간단한 서핑을 통해서 return에 해당 하는 어셈블리어를 찾을 수 있을 것이다. 그러면 크래커는 단순히 함수의 맨 윗줄에 return에 해 당하는 어셈블리어를 넣는다면 광고가 노출되지 않아 수익이 줄 수 있다.

함수 이름이 노출 될 수 있는 위험이 있다고 해서 대부분의 함수의 이름을 알아볼 수 없게(이건 암 호화와 다름없다.) 짓는 것은 비효율적이다. 소규모 게임은 그렇다 쳐도 대규모 게임은 개발 단계 혹은 업데이트, 버그수정단계에서 함수 하나 호출할 때도 그 함수가 무슨 코드를 담고 있는지 살펴봐 야할 지도 모른다.(실제로 필자는 이 방법을 시도를 해봤다가 알아볼 수가 없어서 포기했다.) 방법이 없는 건 아니다.

그림 10 소스 코드

그림 11은 CanPurchase라는 이름이었던 함수를 SystemWork(해커가 관심을 끌지 않을만한 이름) 로 바꾼 모습이다. 함수 옆쪽에 주석을 표시해서 이 함수가 구매 여부를 알려주는 기능이라는 것 을 적어 두었다. 이 방법은 주석이 디컴파일시 노출되지 않는다는 점을 이용한건데 만약 Il2cpp 빌드면 크래커 입장에서는 이게 구매 여부를 알려 준다는 코드라는 것은 꿈에도 생각 못할 것이 다.

하지만 이 방법을 개발 단계 혹은 버그 수정, 업데이트 단계에서 사용한다면 혼동 및 혼선을 줄 수 있고 개발 효율 또한 떨어진다. 또한 주석으로 표기했다 보니 다른 스크립트에서 이 함수를 호출하는 코드를 볼 때 도대체 뭔 함수를 호출한 건지 기능을 짐작하기 어려울 것이다.

(13)

그림 11 ///주석

이를 보완하기 위한 방법이 /// 주석이다(이 주석은 협업에도 굉장히 유용하다). 이 주석을 사용한 다면 //주석과 다르게 함수 호출 코드에 커서를 올린다면 그 함수에 적은 주석을 보여준다. 이 주 석 역시 디컴파일 했을 때 노출되지 않는다.

이렇게 함수 이름을 기능과 관련 없는 이름으로 짓고 주석으로 함수가 무슨 기능인지 표현하는 방법도 좋지만 대부분의 함수를 이렇게 표현한다면 굉장히 혼란스럽다. 함수 호출을 해야 하는데 필요한 기능을 가진 함수의 이름이 뭔지 생각이 안나는 경우도 생기고 협업 과정에서도 마찰이 있을 수 있다.

필자는 이 방법을 개발을 마친 후 출시 과정에서 사용하는 것이(출시 후에는 버그 수정, 업데이트 말고는 코드 수정을 안 하기 때문에 비교적 수월하다) 좋다 생각하고 대부분의 함수에 적용하기 보다는 매우 중요한 함수(광고 노출 함수, 변조 감지 함수, 실제 돈과 직결되는 결제 함수 등)에만 사용하는 것을 추천한다. 또한 mono 빌드 보다는 il2cpp 빌드에서 사용하는 것이 훨씬 효과적이 다.

4. 페이크 함수(미끼 함수)

페이크 함수는 말 그대로 크래커를 속이기 위해서 만드는 함수다. 특히 il2cpp 같은 경우는 크랙 할 함수를 찾을려면 함수 이름에 의존해야 하는데 이걸 이용하는 것이다. 중요한 변수의 이름은 어렵게 바꾸고 일부러 크래커가 찾을 만한 이름을 가진 페이크 함수를 만들어서 만약 페이크 함 수 리턴 값 또는 정상적인 앱이라면 변경될 수 없는 변수가 변경된다면 변조된 앱으로 판단하고 앱을 종료 시키거나 패널티, 계정 정지 등 불이익을 줄 수도 있다.

(14)

그림 12 예시 코드

그림 13의 코드는 LoadMoney라는 페이크 함수를 만들고 변조 여부를 검사하는 abc라는 함수를 만들어 LoadMoney라는 함수의 리턴값이 크래커에 의해 변조된다면 감지할 수 있다.

페이크 함수 방법은 크래커를 막기 보다는 크래커의 시간을 끌고 귀찮음을 느끼게 하는 방법이다.

크래커가 맘 먹고 독하게 모든 함수의 어셈블리어를 보면서 크랙을 시도한다면 결국 뚫리고 말 방법이지만 대부분의 크래커는 특히 어셈블리어를 볼 줄 모르는 초보 크래커는 페이크 함수 몇 개만 만들어 놔도 포기할 수 있다고 생각한다.

5. 페이크 스크립트

이번에 설명할 방법 역시 크래커를 막기 보다는 시간을 끌고 귀찮게 하는 방법이다.

그림 13 dnspy

디컴파일러에서는 게임을 빌드할 때 게임에 사용되는 모든 스크립트도 보여주지만 단순 만들기만 하고 게임 내 적용되지 않은 스크립트도 노출된다. 그림 14는 테스트를 위해서 만든 앱을 디컴파 일러로 열어본 것인데, 실제 사용된 스크립트는 GameManager이다. 나머지 두개의 스크립트는 만 들기만 하고 유니티 하이러키 뷰 내 오브젝트에 적용시키지 않았다. 이번에 사용할 방법은 사용 하지 않는 스크립트도 크래커에게 노출된다는 점을 이용하는 것이다.

방법은 간단하다. 만들기만하고 실제로 사용되지 않는 스크립트를 몇 개 만든다. 이 페이크 스크

(15)

립트의 이름은 크래커가 관심 가질 만한 이름(MoneyManager, BuyManager, Admob 등)으로 짓고 그 안의 함수도 페이크 스크립트의 모티브가 된 스크립트와 비슷하게 채운다. 그러면 크래커는 사용되지 않는 스크립트의 함수들을 열심히 크랙 할 것이고 테스트 할 때 “왜 크랙이 적용이 안 되지?”라는 의문을 가지고 페이크 스크립트를 열심히 연구할 지도 모른다.

아니면 이를 4번 페이크 함수 방법을 응용해서 페이크 스크립트 내 변수 리턴 값 조작이나 변조 등을 감지하는 함수를 하나 만들어서 불이익을 주는 방법도 있다. 응용하기 나름이다.

6. 구글 로그인

6번째 방법은 구글 로그인을 필수로 하는 것이다. 의문을 가질지도 모른다. 어째서 구글 로그인으 로 코드 변조를 막을 수 있는 걸까? 답은 2가지다.

첫째, 코드 변조 후 서명 작업이란 것을 거쳐야지만 노루팅 디바이스에서 설치가 가능하다.

구글 로그인 같은 경우는 서명 값이 오리지널 앱과 다르다면 구글 로그인이 실패하는데 이를 이 용한 것이다. 서명을 안한다면 루팅 된 폰에서만 사용이 가능하고 서명을 한다면 구글 로그인을 못하는데 만약 구글 로그인을 필수로 해 둔다면 루팅이 안된 휴대폰에서는 필자가 알기론 실행이 불가능하다. 또한 크래커 중에서는 자기 자신의 욕심을 만족하기 위해서 크랙을 하는 크래커들도 있지만 크랙한 앱을 재배포 해서 돈을 벌기 위한 목적을 가진 크래커도 있다. 대부분의 사람들은 노루팅 폰을 사용하기 때문에 크래커 입장에서는 노루팅 폰에서도 실행가능한 앱을 배포하는 것 이 돈벌기 쉬울 것이다. 따라서 이렇게 구글 로그인을 필수로 해둔다면 코드 변조 후 루팅 폰에 서만 사용 가능해서 크랙 앱 사용자 수를 줄일 수 있다.

둘째, 정지 같은 제제를 받는다면 지웠다 깔면 그만이지만 구글 로그인이 필수면 새 계정을 만들 어야 한다.

이 방법도 역시 크래커들의 귀찮음을 이용한 방법이다. 기껏 크랙을 성공했지만 잘못하다 치트 감지 함수에 걸린다면 제제를 받는다. 로그인 필수가 아닌 게임이라면 게스트 계정을 사용해서 테스트를 지속할 수 있지만 구글 로그인 혹은 다른 로그인을 필수로 해둔다면 실패할 때마다 새 계정을 만들어서 테스트를 해야하기 때문에 매우 번거롭게 할 수 있다.

여기까지가 코드 변조를 막기위해 필자가 생각해본 방법이다. 부족할지 몰라도 융합해서 쓰거나 보완해서 쓴다면 크래커의 코드 변조 공격을 방어할 수 있을 것이다.

(16)

그 외

Root Check

위 방법은 앱이 작동되는 휴대폰이 루팅됐는지를 확인하는 방법이다.

보통 간단한 저장에 많이 사용되는 unity 내장 함수 PlayerPrefs는 /data/data/pkg- name/shared_prefs/pkg-name.xml 경로에 저장이 되는데 이 경로는 루팅이 안된 폰에서는 접근이 불가능 하지만 루팅 된 폰에서는 쉽게 접근을 해 저장된 데이터 변조가 가능하다. 만약 루팅 된 폰일시 앱 실행을 불가하게 한다면 크랙을 막는데 도움이 될 것이다.

또한 코드 변조 방어 솔루션 중 서명 작업을 안한다면 루팅 된 폰에서만 게임이 사용 가능하다 했는데 루팅 된 폰에서의 앱 실행을 제한한다면 서명 작업을 필수로 해야하고 또한 구글 로그인 또한 필수라면 루팅을 체크하는 함수를 건들지 않는 한 변조 앱을 실행할 수 있는 방법은 없을 것이다.

보안 업체

지금까지 설명한 솔루션들은 크래커를 막을 수는 있지만 정말 끈기 있고 시간을 많이 투자하는 크래커라면 언젠가는 뚫리고 말 것이다. 만약 개발한 게임 혹은 개발하고 있는 게임이 정말 대규 모 작품이고 크랙 당한다면 손해가 크다면 위에 적은 방법 + 보안 전문 업체에 맡기는 것도 좋 은 방법이다. 이런 전문 업체에 맡긴다면 어느정도 수준의 보안은 보장될 것이다. 하지만 안티치 트 툴킷 에셋과 마찬가지로 언젠가는 우회법이 잘 알려질지도 모른다. 그것을 대비해서 앞서 설 명한 솔루션들을 활용한다면 더 탄탄한 보안을 가진 게임이 되지 않을까 생각한다.

(17)

마치며

이 문서는 힘들게 만들어진 게임을 크랙하는 행위를 막고자 생각해낸 솔루션을 바탕으로 적었다.

아무래도 크랙을 막기위한 솔루션이다 보니 불가피하게 크랙의 원리나 방법도 적은 것 같은데 이 를 악용하지 않았으면 좋겠다.(필자는 취약한 앱을 직접 제작해서 테스트했다). 아무리 공부나 테 스트가 목적이라도 실제 출시된 게임을 크랙한다면 엄연히 범죄가 될 수 있다(특히 크랙 후 재배 포 관련해서는 법적 처벌을 받을 수 있다). 독자들은 이 솔루션들을 잘 활용, 보완해서 더 탄탄한 보안을 가진 게임을 만들기를 바란다.

참고 사이트

주소 참고 내용

https://assetstore.unity.com/packages/tools/utilities/anti-

cheat-toolkit-152334 Asset : AntiCheatToolKit https://devdic.tistory.com/8

코드 난독화 기법 http://jiniya.net/tt/590

암호화 관련 표 2 참고 사이트

참조

관련 문서

그래서 정치실패가

만약 이러한 행위를 한 사실이 확인될 경우에는 행위자 및 이를 이용한 수험생은 모두 부정행위자로 간주하며, 부 정행위자는 성적사정대상에서

만약 이러한 행위를 한 사실이 확인될 경우에는 행위자 및 이를 이용한 수험생은 모두 부정행위자로 간주하며, 부 정행위자는 성적사정대상에서 제외하여 불합격처리

- 셧다운제가 내수시장에 미친 영향을 분석하기 위해 셧다운제 규제가 없다는 가정에 서의 내수시장 규모를 셧다운제 실시 이전의 게임 내수시장 규모 데이터를

산업용 산업용 이더넷

이때 두번째 해를 찾는 방법이 있으며 두번째 해는 로그항을 포함하게 된다.. 그러면 두번째 해를

만약 이러한 행위를 한 사실이 확인될 경우에는 행위자 및 이를 이용한 수험생은 모두 부정행위자로 간주하며, 부 정행위자는 성적사정대상에서 제외하여 불합격처리

만약 이러한 행위를 한 사실이 확인될 경우에는 행위자 및 이를 이용한 수험생은 모두 부정행위자로 간주하며, 부 정행위자는 성적사정대상에서 제외하여 불합격처리