IT_Programming/Dev Tools

[펌] ProGuard - Java Code 난독화 프로그램

JJun ™ 2011. 2. 14. 11:20

-----------------------------------------------------------------------------------------------

                                                   출처: http://jcjeon.tistory.com/entry/ProGuard

-----------------------------------------------------------------------------------------------


Proguard Tool은 사용하지 않는 코드를 제거하고 클래스, 멤버 필드, Methods의 이름을 잘 알려져 있지 

않은 이름들로 변경하는 방법으로 코드를 줄이고 최적화시키며 해독이 불가하도록(obfuscate) 만들어준다. 


결과적으로 더 작아진 크기의 .apk 파일이 만들어지게 되며 역으로 코드를 알아내는 것(reverse engineer)을 힘들게 해준다. ProGuard가 개발자의 코드가 역으로 해석되는 것을 어렵게 만들어주기 때문에 라이센스 관련 사항과 같은 보안에 민감한 features을 사용하는 Application이 사용할 때 ProGuard를 사용하는게 

중요하다.


ProGuard는 Android Build System에 통합되어 있어서 손수 그것을 실행시킬 필요는 없다. 

ProGuard는 Release Mode에서 Application을 빌드할 때에만 실행되므로 Debug Mode에서 Application을 빌드할 때 난독화되어 있는 코드를 다룰 필요는 없다. ProGuard를 실행시키는 것은 선택적이지만 매우 추천되는 방식이다. 

이번 문서는 ProGuard를 설정하고 활성화시키는 방법외에 난독화되어 있는 Stack Traces를 Decode할 수 있는 "retrace" Tool을 사용하는 방법을 기술하고 있다.


Enabling ProGuard

Android Project를 생성할 때, "proguard.cfg" 파일이 Project의 root directory에 자동으로 생성된다.

이러한 파일은 ProGuard가 어떻게 최적화하고 코드를 해독이 불가하도록 하는지를 정의하므로 필요에 따라 

그것을 Customize하는 방법을 이해하는 것은 아주 중요한 일이다. 기본적인 Configuration 파일은 단지 

일반적인 경우들만 커버하기 때문에 자신의 필요에 의해 변경해야만하는 것이 대부분이다. "Configuring ProGuard"에 대한 다음 Section을 보면 ProGuard Configuration 파일을 Customize하는 것에 대한 정보를 얻을 수 있다.

Ant나 Eclipse의 일부로 ProGuard를 동작하도록 활성화시키려면 <project_root>/default.properties 파일에 "proguard.config" Property를 설정해야 한다. 경로는 절대 경로가 되거나 Projects의 Root에 상대적인 경로가 될 수 있다.

만일 "proguard.cfg" 파일을 기본 위치인 Project의 root 디렉토리에 둔다면 다음과 같이 해당 파일의 위치를 설정할 수 있다.

proguard.config=proguard.cfg


또한 원하는 어느 곳으로든 파일을 이동시킬수 있고 그에 따른 절대 경로를 설정할 수 있다.

proguard.config=/path/to/proguard.cfg


Release Mode에서 Application을 빌드할 때 "ant release"를 실행에 의해서거나 Eclipse의 "Export Wizard"를 사용하는 것에 의해 빌드 System은 자동으로 "proguard.config" Property가 설정되어 있는 지를

체크한다. 만약 체크되어 있다면 ProGuard는 해당 .apk 파일로 모든 것이 패키징되기 전에 자동으로 Application의 ByteCode를 처리하게 된다. Debug Mode에서의 빌드과정은 ProGuard를 실행시키지 않는데 이는 더 힘들게 Debugging을 해야 하기 때문이다.

ProGuard는 실행 이후 다음과 같은 Outputs을 내놓는다. 
dump.txt: .apk 파일에 있는 모든 클래스 파일들의 내부 구조를 기술한다. 
mapping.txt: 원래의 클래스, Method, 필드 멤버들과 난독화된 것들 사이의 매핑을 리스트화 시킨 것이다. 이러한 파일은 Release 빌드로부터 버그를 받았을 때 중요해진다. 왜냐햐면 난독화된 Stack Trace를 원래의 것으로 변화시킬 수 있기 때문이다. 더 많은 정보를 원한다면 "Decoding Obfuscated Stack Traces"를 참고하면 된다.


seeds.txt: 난독화되지 않은 클래스들과 멤버들의 리스트
usage.txt: .apk 파일로부터 벗겨져 얻어진 코드의 리스트


이러한 파일들은 다음의 디렉토리에 위치하게 된다.
  <project_root>/bin/proguard if you are using Ant. 
  <project_root>/proguard if you are using Eclipse. 

[주의] Release Mode에서 빌드할 때마다 이러한 파일들은 ProGuard에 의해 생성된 최근 파일로 

          덮어 써진다. Release 빌드로부터 받는 버그를 해독이 가능하게 만들기 위해서는 Application을 

          Release할 때 마다 복사본을 저장해두어야 한다. 이러한 파일을 저장하는 것이 왜 중요한지에 대한

          더 많은 정보를 원한다면 "Debugging considerations for published applications"을 참고하면 된다.



Configuring ProGuard

몇몇 경우에서는 proguard.cfg 파일에서의 기본 설정들이면 충분하다. 하지만 많은 경우에서 ProGuard는 정확한 분석을 어렵게 하며 사용되지는 않지만 실제적으로 필요한 코드를 삭제시킬 수 있다. 

몇 개의 예제들은 다음을 포함한다.


 - AndroidManifest.xml 파일에서만 참조되는 클래스
 - JNI로부터 호출되는 Method
 - 동적으로 참조되는 필드들과 멤버들

기본적인 proguard.cfg 파일은 일반적인 경우를 커버하고자 하지만 "ClassNotFoundException"과 같은 

예외를 마주치게 된다. 그리고 이러한 예외는 ProGuard가 Application이 호출하는 전체 클래스들에 대해 

불필요한 것들을 없앨(strip away) 때 발생하게 된다. 

ProGuard가 코드에서 불필요한 부분을 없애려 할 때, proguard.cfg 파일에 "-keep" line을 추가함으로써 

이러한 문제를 수정할 수 있다. 

-keep public class <MyClass>
"-keep" option을 사용하는데에는 아주 많은 Options과 Considerations이 존재하기 때문에 Configuration 파일을 Customizing하는 것에 대한 더 많은 정보를 얻고자 한다면 "ProGuardManual"을 읽어볼 것을 

강하게 추천하는 바이다.


"Overview of Keep Options"와 "Examples Section"은 특히 도움이 될 것이다. ProGuard Manual의 "Troubleshooting" Section 코드에서 불필요한 부분을 제거할 때 마주치게 될 수 있는 다른 일반적인 문제들을 보여준다.


Decoding Obfuscated Stack Traces

난독화과정이 일어난 코드는 Stack trace를 생성할 때 Method 이름들이 난독화되는데, 이러한 난독화된 

이름들은 debugging이 가능할 수는 있지만 어렵게 만든다. 다행스럽게도 ProGuard가 실행될 때마다 <project_root>/bin/proguard/mapping.txt 파일이 생성되는데 이러한 파일은 난독화된 이름들에 매핑되어 있는 원래의 클래스, Method, 그리고 필드 이름들을 보여주게 된다. 

Windows에서는 retrace.bat 스크립트 파일이, Linux나 MacOS X에서는 retrace.sh 스크립트가 난독화 된 Stack trace를 읽기 가능한 것들로 변경이 가능하다. <sdk_root>/tools/proguard/ directory에 이러한 파일이 존재하며 retrace tool의 실행을 위한 Syntax는 다음과 같다.

retrace.bat|retrace.sh [-verbose] mapping.txt [<stacktrace_file>]


예를 들어,

retrace.bat -verbose mapping.txt obfuscated_trace.txt


<stacktrace_file>을 따로 지정하지 않으면 retrace tool은 기본 입력으로부터 읽어들이게 된다.


Debugging considerations for published applications

사용자에게 제공하기 위한 매번의 릴리즈때마다 mapping.txt파일을 저장해둬야 한다. 

각각의 빌드에 대해 mapping.txt의 복사본을 유지함으로써, 사용자가 버그를 보고 난독화되어 있는 

starc trace를 보내주면 문제를 디버깅할 수 있게 된다. 


하나의 Project에 대한 mapping.txt 파일은 릴리즈 빌드시마다 덮어써지게 되므로 필요한 버전의 저장에 

주의를 해야만 한다. 

예를 들어, Appliction을 배포하고 새로운 버전에 대한 Appliction의 신규 기능들의 개발을 계속하는 것을 

가정하여 말해보자. 그런 다음 ProGuard를 사용하여 하나의 릴리즈 빌드를 하게 된다. 


빌드 과정에서 이전의 mapping.txt파일이 덮어써지게 된다. 사용자는 최근에 배포된 Appliction으로부터 stack trace를 포함하는 버그 리포트를 제출한다. 개발자는 사용자가 보내준 stack trace를 디버깅 할 수 

있는 방법이 더이상 없게 된다. 왜냐하면 사용자의 Device에 있는 버전과 연관된 mapping.txt 파일이 

사라지기 때문이다. 


mapping.txt 파일이 덮어써질 수 있는 또 다른 상황이 존재하고 있어서 디버깅이 필요하다고 예견하는 

모든 릴리즈에 대해 복사본을 저장해야만 한다. 

mapping.txt 파일을 어떻게 저장하는지는 개발자의 결정에 달려있다. 

예를 들어, 버전이나 빌드 번호를 포함하도록 그것들의 이름을 재지정한다거나 소스 코드에 따라 

버전 제어를 할 수 있다.