티스토리 뷰
mono & il2cpp 비교
앞서 Unity Obfuscator를 살펴보면서 유니티에서 빌드 시 Assembly-CSharp.dll이 생성되고 이는 .Net decompiler 프로그램을 사용하여 쉽게 소스코드를 확인할 수 있었다. 해당 빌드 방식은 mono인데 유니티에서 mono와 il2cpp의 2가지 형식으로 빌드가 가능하다.
mono와 il2cpp는 공통적으로 C#코드를 IL(Intermediate Language)코드로 변환한 후 빌드할 플렛폼에 맞는 Assembly로 변환하여 실행한 기기에서 동작하게 된다.
위 사진은 유니티로 방향키로 Object를 움직이는 간단한 코드를 빌드하여 ILdasm 프로그램으로 IL 코드가 어떻게 생성되는지를 확인한 모습이다. mono와 il2cpp의 차이점은 mono의 경우 해당 IL 코드를 JIT 컴파일(just-in-time compilation)형식 즉, 실행 시 마다 Assembly로 변환하는 반면 il2cpp의 경우 바로 Assembly로 변환하지 않고 C++ 코드로 변환 후 C++ 컴파일러를 통해 네이티브 라이브러리(.so)를 생성하게 된다. 이는 JIT 컴파일 방식과 다르게 미리 생성된 Assembly로 실행하기 때문에 빌드 시 오래걸리지만 실행 속도 면에서는 향상된 성능을 보여준다.
il2cpp 디컴파일 및 리패키징
이제 il2cpp로 빌드된 apk를 디컴파일한 후 il2cpp 코드를 수정하여 리패키징을 진행해보자.
테스트를 진행하기 위해 간단하게 Object를 움직이는 코드를 작성하여 유니티로 빌드하였다. 빌드를 진행하고 lib폴더에 libil2cpp.so파일이 생성된 것을 확인할 수 있다.
현 시점에서 so파일을 IDA로 열어보아도 수많은 함수들 속에서 내가 고치고 싶은 함수를 찾는 것은 쉽지 않다. 따라서 il2cppdumper라는 툴을 이용하여 il2cpp로 빌드된 바이너리에 대한 필드, 함수 정보와 위치를 알아내야 한다.
https://github.com/Perfare/Il2CppDumper << il2cppdumper 다운로드
il2cppdumper를 실행하면 두 파일을 선택해야 한다. 먼저 첫번째는 il2cpp 파일을 선택하는데 각 플렛폼 마다 상이하지만 apk의 경우 디컴파일 후 생성되는 libil2cpp.so파일을 선택하면 된다. 두번째는 global-metadata.dat을 선택한다. 해당 파일은 apk 내부에 "asset\bin\Data\Managed\Matadata 폴더 내에 존재한다. 두 파일을 선택한 후 유니티 버전을 입력하고(본인 경우 2019.1), Auto 모드를 선택하면 위 사진과 같이 dump가 진행된다. 결과적으로 il2cppdumper.exe 경로에 DummyDll 폴더가 생성되며 폴더 내 Assembly-CSharp.dll이 생성되어 mono 분석 때와 같이 dnspy같은 툴을 이용하여 코드를 살펴보면 된다.
처음 dll파일이 생성된 것을 보고 바로 코드를 수정할 수 있을 것이라 생각했지만 아쉽게도(?) 메소드들의 정보와 위치만 알수 있었다. 해당 정보를 통해서 IDA를 통해 libil2cpp.so파일을 열어 Move 함수의 코드를 수정한다.
il2cppdumper로 알아낸 Move함수의 주소로 이동하니 처음 작성하였던 Move 함수의 코드와 유사한 sub_5157B0 함수(Move함수의 주소는 0x5157B4이지만 Update함수 내에서 호출 하므로 해당 주소인 0x5157B0 내에 존재한다)를 찾을 수 있었다. GetKey함수를 통해 키보드의 방향키 값을 입력받으면 방향에 맞게 움직이는 코드이다. 0x111 값이 위 방향키를 나타내고, 0x112 값이 아래 방향키를 나타낸다. 코드를 수정하여 위를 누르면 아래로 가고 아래를 누르면 위로 가게끔 값들을 바꿔 위 사진과 같이 so파일 수정한 후 리패키징을 하였다. 참고로 디컴파일과 리패키징은 APK Easy Tool을 이용하였다.
리패키징 후 nox player를 통해 해당 apk를 실행하여 확인하니 방향키 위 아래가 바뀌어 작동하는 것을 확인할 수 있었다. 이를 통해 mono보다는 il2cpp가 보안적인 측면에서 좋을지 모르지만 간단한 프로그램이나 암호화(난독화)가 되지 않은 프로그램의 경우 il2cpp라 하더라도 쉽게 코드 수정이 가능하다는 것을 알 수 있다.
Output file 살펴보기
프로그램을 실행하고 나면 해당 폴더에 여러 Output 파일들이 생성된다. (위 사진 참고)
1. dump.cs
C# pseudocode이다. 간단한 코드 내용이나 전반적인 흐름을 알 수 있다. 해당 코드를 보는 것보다 script를 적용한 IDA나 디컴파일러를 통해 분석하는 것이 더 좋을 듯 하다.
2. script.py
libil2cpp.so파일을 IDA로 열어보면 앞서 분석한 것 처럼 dumper를 통해 주소를 알아내야 분석 범위를 좁힐 수 있다. 해당 스크립트를 IDA에 적용하면 dumper로 분석된 함수 이름 등의 정보를 파싱된 값으로 변환하여 보여준다.
이제 굳이 디컴파일러를 통해 주소를 확인하거나 IDA의 함수 이름을 일일히 바꾸지 않아도 Script.py를 IDA에 추가하면 함수 이름이 파싱되서 보여준다. 완전 좋다 ㅎㅎ
3. DummyDll
Mono.Cecil 라이브러리를 이용하여 바이너리에서 추출된 .Net 메타데이터를 포함한 DLL파일들이 모여있는 폴더이다. .Net 디컴파일 프로그램들을 통해 확인이 가능하다.
참고 사이트
'Project > Unity_Obfuscator' 카테고리의 다른 글
Unity Obfuscator #6 (0) | 2019.07.19 |
---|---|
Unity Obfuscator #5 (0) | 2019.07.05 |
Unity Obfuscator #4 - code Analysis (0) | 2019.06.28 |
Unity Obfuscator #3 - 난독화 적용 후 il2cpp 살펴보기 (0) | 2019.06.14 |
Unity Obfuscator 들여다보기 (0) | 2019.05.27 |