-----------------------------------------------------------------------------------------------
출처: http://huewu.blog.me/110099143870
-----------------------------------------------------------------------------------------------
프로가드는 널리 사용되고 있는 코드 난독화 툴로, 여러분의 어플리케이션을 크래커의 공격으로
부터 보다 안전하게 보호하고 동시에, 코드 사이즈를 줄여주며, 그리고 약간의 최적화도 곁들여 주는 아주 아주 훌륭한 오프소스 툴입니다. 프로가드는 GPL 라이센스를 갖는 도구로 해당 코드를 수정하거나 툴 자체를 재배포할 수는 없지만, 공개된 프로가드를 이용하여 여러분의 어플리케이션을 난독화 하는데에는 어떠 제약 조건 없이 사용하실 수 있습니다.
간단하게 그 사용법을 정리해 보았습니다.
부터 보다 안전하게 보호하고 동시에, 코드 사이즈를 줄여주며, 그리고 약간의 최적화도 곁들여 주는 아주 아주 훌륭한 오프소스 툴입니다. 프로가드는 GPL 라이센스를 갖는 도구로 해당 코드를 수정하거나 툴 자체를 재배포할 수는 없지만, 공개된 프로가드를 이용하여 여러분의 어플리케이션을 난독화 하는데에는 어떠 제약 조건 없이 사용하실 수 있습니다.
구글 팀은 LVL 라이브러리를 공개 하고, 라인센싱 서비스를 시작한 직 후 부터, 코드 난독화 툴 - 특히 프로가드 툴을 사용할 것을 권장했으며, 마침내 새롭게 등장한 진저브레드 버전 부터는 아예 ADT 단에서 프로가드 사용을 지원하고 있습니다. 따라서, 개발자분들은 새롭게 업데이트된 ADT 를 사용하는 한, 꼭 2.3 타겟의 어플리케이션을 만드는 경우가 아니더라도 정말로 손쉽게 프로가드 툴을 사용하실 수 있습니다. 그 방법에 관하여, 구글 개발자 가이드 문서에 나온 내용을 기반으로
간단하게 그 사용법을 정리해 보았습니다.
더보기
출처: http://huewu.blog.me/110093424752
Securing Android LVL Applications
이 포스트는 안드로이드 개발자 프로그램을 위해 일하고 있는 Trevor Johns 에 의해 작성되었습니다.
— Tim Bray —
구글이 예고한대로, 어플리케이션을 불법복제자들로 부터 방어하기 위한 여러가지 노하우에 관한 내용이 안드로이드 개발자 블로그에 올라왔습니다. 소프트웨어 역공학이나 어플리케이션 크랙이 어떤식으로 구현되는지 잘 몰랐었는데, 내용을 읽어보니 꽤 재미있네요. 관련 포스트를 번역해 보았는데, 한 번쯤 읽어보셔도 좋을거 같습니다.
안드로이드 마켓 라이센스 서비스는 불법적인 사용자들로부터 자신의 어플리케이션을 보호할 수 있는 좋은 방법입니다. 그리고 License Verification Library(LVL)은 이를 위한 핵심 컴포넌트입니다. 따라서, 여러분의 어플리케이션을 크랙하고자 하는 공격자들은 LVL 을 이용하여 라이센스 서비스를 사용하는 부분을 제거하고자 할 것입니다.
기본적으로 LVL 은 여러분의 어플리케이션을 한 디바이스에서 다른 디바이스로 불법 복제하는 가벼운 종류의 공격을 방어해줍니다. (주> 불법 복제하더라도 해당 계정에 어플리케이션 구매 정보가 없으면 실행할 수 없음으로) 거기에 더해 여러분은 숙달된 크래커가 어플리케이션 내에서 LVL 관련된 코드를 제거하려는 시도를 보다 어렵게 만들기위해 다음과 같은 기법들을 활용할 수 있습니다.
- 어플리케이션을 난독화 하여 리버스 엔지리어링을 어렵게 하기
- 라이센스 라이브러리 자체를 수정하여, 일반적인 크래킹 기술을 적용하기 어렵게 하기
- 어플리케이션을 수정하기 어렵게 하기
- 신뢰할 수 있는 서버에서 라이센스를 추가로 체크하기
그리고 한가지, 이러한 기법을 적용할 때, 어플리케이션 개발자들은 자신만의 고유한 방법을 사용해야 합니다. (주>Copy&Paste 를 남발해서는 안됩니다.) 클라이언트 쪽의 코드를 100% 안전하게 작성하는 방법은 없으며, 클라이언트 어플리케이션은 어떠한 식으로든 크래킹의 위협에 노출되어 있습니다. 따라서, 라이센스 서비스를 디자인할 때 가장 핵심적인 원칙 중 하나는, 공격자들이 개별 어플리케이션을 하나 하나 개별적으로 크랙해야만 하도록 강제하는 것 입니다. 그러므로, 우리는 어플리케이션 개발자들에게 라이센스를 체크하는 코드를 보다 복잡하고 어렵게 만들 수 있는 방법들을 소개하고, 어플리케이션 개발자들이 이러한 방법들을 자신의 어플리케이션에 다양하게 적용하여, 공격자들이 어플리케이션에 관해 매우 상세한 정보를 알아야지만 해당 코드를 제거할 수 있도록 하고자 합니다.
테크닉: 코드 난독화(Code Obfuscation)
어플리케이션을 보호하기 위해서는 우선적으로 코드 난독화 기법을 적용하는 것이 좋습니다. 이 기술은 자동화된 공격으로 부터 여러분의 어플리케이션을 보호하지 못하며, 어플리케이션 플로우를 수정하지도 않습니다. 하지만 컴파일된 어플리케이션에 사용된 각종 심볼들의 의미를 이해하기 어렵게 만듬으로서, 최초의 공격자가 어플리케이션을 크래킹하기 어렵게 만들어줍니다. 따라서 우리는 LVL 을 사용하는 모든 어플리케이션이 코드 난독화 기법을 사용할 것을 강력하게 추천합니다.
코드 난독화가 어떤일을 하는지 이해하기위해서는, 여러분의 어플리케이션의 빌드 과정을 한번 떠올려보면 좋습니다. 어플리케이션은 컴파일된 후, DEX 파일로 변경되고 이 후 APK 파일로 패키징 됩니다. 컴파일된 바이트코드는 원본 소스 코드에 대하여, 패키지, 클래스, 메서드, 필드 변수들에 대한 참조를 담고 있습니다. 그리고 이러한 참조에는 어플리케이션 개발자가 사용한 이해하기 쉬운 이름이 그대로 남아있습니다. 공격자들은 이 정보를 이용하여 손쉽게 여러분의 어플리케이션에 역공학(reverse-engineering) 작업을 수행할 수 있으며, 라이센스 체크 루틴을 무력화 시킬 수 있습니다.
코드 난독화는 코드에서 사용된 각종 심볼들의 이름을 기계가 생성한 짤막한 대체 이름을 변경합니다. 따라서, 공격자는 dontAllow() 라는 메서드가 사용된다는 정보 대신 a() 라는 메서드가 사용된다는 정보만을 얻게 됩니다. 따라서 공격자는 원본 소스코드를 참조하지 않으면 각각의 메서드들이 어떤 일을 수행하는지 직감적으로 알아채기 어렵게 됩니다.
안드로이드 어플리케이션에 사용가능한 다양한 코드 난독화 툴들이 있습니다. 특히 우리는 ProGuard 를 사용하여 쏠쏠한 재미를 보았습니다. 물론 여러분은 여러분에게 가장 적합한 툴을 사용하시면 됩니다. 우리는 곧 ProGuard 를 사용하는 방법에 관하여 상세한 내용을 담은 문서를 제공할 예정입니다. (주>따라서, 제가 개인적으로 준비하던 포스트는 역사의 저편으로...) 그전에는 ProGuard 에서 제공하는 문서를 참고하시기 바랍니다.
테크닉: 라이센스 라이브러리 수정
두 번째로 고려해야할 보안책은, LVL 을 수정하여 공격자들이 디어셈블된 코드를 수정하여 라이센스 체크의 결과가 항상 True 값으로 반환되도록 만드는 것을 어렵게하는 것 입니다. 이런 방법으로 여러분의 어플리케이션을 공격하려는 크래커 뿐만 아니라, 별개의 어플리케이션을 공격하기 위한 방법이 여러분의 어플리케이션에도 손쉽게 적용되는 사태를 방어할 수 있습니다.
라이센스 라이브러리는 어플리케이션 바이트 코드의 복잡성을 증가시키고 동시에 LVL 구현 방식이 최대한 유니크하도록 만드는 방향으로 수정되어야합니다. 이를 위해 여러분은 다음의 세 가지를 주의깊게 살펴보셔야 합니다.
- 라이센스 라이브러리의 핵심 로직
- 라이센스 라이브러리의 진입/탈출 지점. (Entry Point / Exit Point)
- 어플리케이션이 라이브러리를 호출하고 결과 값을 처리하는 방법
라이센스 라이브러리의 핵심 로직은 LicenseChecker 와 LicenseValidator 두 개의 클래스로 이루어져있습니다. 아주 단순하게 말하자면, 여러분은 이 두 클래스가 정상적으로 동작하는 한도에서 최대한 클래스의 내용을 수정해야 합니다. 예를 들어 여기 몇 가지 예시가 있습니다.
- switch 문을 if 문으로 수정하기
- 사용되는 상수값을 생성할 때, XOR 이나 해쉬 펑션으로 이용하하기.
- 사용되지 않는 코드는 제거하기. 예를들어 여러분이 라이센스 정책을 교체할 수 있도록 작성할 필요가 없다고 확신한다면, Policy Interface 를 제거하고, LicenseValidator 내부에 인라인 형태로 Policy 를 구현할 것.
- LVL 전체를 여러분의 어플리케이션 패키지로 옮기기
- 라이센스 체크를 위한 각각의 과정을 처리하기 위한 추가적인 스레드를 생성하여,
- 가능한 경우 함수를 인라인 코드로 대체하기
예를 들어, LicenseValidator 의 다음 함수를 생각해 보면,
public void verify(PublicKey publicKey, int responseCode, String signedData,
String signature)
{
// ... Response validation code omitted for brevity ...
switch (responseCode) {
// In Java bytecode, LICENSED will be converted to the constant 0x0
case LICENSED:
case LICENSED_OLD_KEY:
LicenseResponse limiterResponse =
mDeviceLimiter.isDeviceAllowed(userId);
handleResponse(limiterResponse, data);
break;
// NOT_LICENSED will be converted to the constant 0x1
case NOT_LICENSED:
handleResponse(LicenseResponse.NOT_LICENSED, data);
break;
// ... Extra response codes also removed for brevity ...
}
이 예제에서, 공격자는 LICENSED 와 NOT_LICENSED 에 해당하는 코드를 교체하려고 시도할 수도 있습니다. LVL 소스 코드를 살펴보면, LICENSED (0x0) 과 NOT_LICENSED (0x1) 의 상수값을 알 수 있음으로, 만일 이러한 코드가 그대로 사용된다면, 여러분이 코드 난독화를 수행했다 하더라도 공격자는 바이트 코드 내에서 라이센스를 체크하는 코드를 손쉽게 찾아낼 수 있습니다.
이러한 작업을 어렵게 하기 위하여, 다음과 같이 코드를 수정할 수 있습니다.
public void verify(PublicKey publicKey, int responseCode, String signedData,
String signature)
{
// ... Response validation code omitted for brevity …
// Compute a derivative version of the response code
// Ideally, this should be placed as far from the responseCode switch
// as possible,
// to prevent attackers from noticing the call to the CRC32 library, which
// would be a strong hint as to what we're done here.
// If you can add additional transformations
// elsewhere in before this value is used, that's even better.
java.util.zip.CRC32 crc32 = new java.util.zip.CRC32();
crc32.update(responseCode);
int transformedResponseCode = crc32.getValue();
// ... put unrelated application code here ...
// crc32(LICENSED) == 3523407757
if (transformedResponse == 3523407757) {
LicenseResponse limiterResponse =
mDeviceLimiter.isDeviceAllowed(userId);
handleResponse(limiterResponse, data);
}
// ... put unrelated application code here ...
// crc32(LICENSED_OLD_KEY) == 1007455905
if (transformedResponseCode == 1007455905) {
LicenseResponse limiterResponse = mDeviceLimiter.isDeviceAllowed
(userId);
handleResponse(limiterResponse, data);
}
// ... put unrelated application code here ...
// crc32(NOT_LICENSED) == 2768625435
if (transformedResponseCode == 2768625435):
userIsntLicensed();
}
}
우리는 라이센스 응답 코드를 다른 값으로 변환하는 코드를 추가하였습니다. 그리고 switch 문을 제거하고, 라이센스 체크와 관련된 코드 사이에 임의의 어플리케이션 코드를 추가할 수 있도록 수정하였습니다. (기억하십시요. 여러분의 목표는 LVL 구현을 최대한 유니크하게 하는 것 임으로, 위의 코드를 그대로 카피하여 사용하거나 하셔서는 안됩니다.)
진입/탈출 점에 관해서는, 공겨자들이 여러분이 구현한 Public Interface 와 일치하는 Interface 를 갖는 위조 LVL 을 구현하여 관련된 클래스를 통채로 교체하려고
시도할 수도 있다는 점을 유의하셔야 합니다. 이를 방지하기 위하여, LicenseChecker 클래스 생성자나 메서드에 입력 파라매터를 추가할 수도 있습니다. 예를 들어, 여러분은 유니크한 값을 LicenseChecker 생성자에 넘겨주고,
allow() 메서드를 호출할 때 해당 값이 있는지 확인하도록 구현 할 수도 있습니다.
시도할 수도 있다는 점을 유의하셔야 합니다. 이를 방지하기 위하여, LicenseChecker 클래스 생성자나 메서드에 입력 파라매터를 추가할 수도 있습니다. 예를 들어, 여러분은 유니크한 값을 LicenseChecker 생성자에 넘겨주고,
allow() 메서드를 호출할 때 해당 값이 있는지 확인하도록 구현 할 수도 있습니다.
노트: allow() 와 dontAllow() 메서드의 이름을 변경하는 것은 별다른 효과가 없습니다. 여러분이 코드 난독화툴을 이용한다면 해당 툴이 자동으로 이러한 메서드 이름을 교체해 줄 것입니다.
또한, 공격자들은 여러분의 어플리케이션에서 LVL 을 호출하는 부분을 수정하려고 시도할 수도 있습니다. 예를 들어, 라이센스 체크가 실패했을 경우, '종료' 버튼이 달린 다이얼로그를 표시하도록 구현된 어플리케이션에서, 공격자가 윈도우를 디스플레이 하는 부분을 제거하면 어떠한 일이 일어나게 될까요? 사용자가 '종료' 버튼을 누르지 않아도 어플리케이션이 종료될까요? 이러한 일을 방지하기 위하여, 라이센스 체크가 실패한 경우 메인 Activity 는 바로 종료하고, 사용자에게는 별도의 Activity 를 이용하여 라이센스 체크 여부를 묻도록 구현하는 편이 좋습니다. 또한, 메인 Activity 를 종료하기 위한 finish() 문에도 주의를 기울여야 합니다. 기본적인 finish() 문이 제거될 경우에도 Activity 가 종료될 수 있도록, 어플리케이션 코드의 다른 부분에 예비의 finish() 문을 추가해 두거나, 타이머를 이용하여 일정 시간 후에 어플리케이션이 종료되도록 구현하면 좋습니다. 또한, 어플리케이션이 실행 된 후, 몇 분 후에 라이센스 체크를 수행하도록 구현해도 좋습니다. 공격자들은 일반적으로 라이센스 체크가 어플리케이션 실행 시점에 일어난다고 생각하기 때문입니다.
마지막으로, 몇몇 메서드들은 난독화 될 수 없다는 점에 주의하십시요. 예를 들어, onCreate() 와 같은 메서드는 이름을 변경할 수가 없는데, 안드로이드 시스템에 의하여 호출될 필요가 있기 때문입니다. 따라서, 라이센스 체크 구문을 이러한 메서드내에 추가해서는 안됩니다. 공격자들이 해당 메서드 내에서 LVL 관련 코드를 찾고자 시도할 수 있기 때문입니다.
테크닉: 어플리케이션을 수정하기 어렵게 하기
공격자들이 LVL 관련 코드를 어플리케이션에서 제거하기 위해서는, 여러분의 코드를 수정해야 합니다. 이 작업이 정교하게 이루어지지 않는다면, 여러분은 여러분의 코드가 수정되었다는 것을 눈치챌 수 있습니다. 여기 몇 가지 방법이 있습니다.
가장 확실한 방법은 CRC32 와 같은 가벼운 해쉬 함수를 사용하여 여러분의 어플리케이션 코드에 대한 해쉬 값을 생성하는 것 입니다. 이 값을 미리 저장해 둔 후, 런타임 시에 해당 값을 비교해볼 수 있습니다. 어플리케이션 파일은 Context.GetApplicationInfo() 메서드를 이용하여 얻어올 수 있습니다. 한 가지 주의할 점은, 파일의 체크섬을 비교할 때, 해당 파일이 체크섬 값을 담고있어서는 않됩니다. (공격자가 해당 값을 확인 할 수 있음으로) 해당 정보를 별도의 서버에 저장하는 것도 좋은 방법입니다.
[이 문서가 쓰인 시점에는 GetInstallerPackageName 메서드를 사용하는 방법에 관한 내용도 포함되어 있었습니다만, 우리의 시니어 엔지니어는 해당 메서드는 공식적인 메서드가 아님으로 항상 적용될 수 없다고 지적해 주었습니다. 따라서 관련된 내용은 제거되었습니다. –Tim]
또한, 여러분은 여러분의 어플리케이션이 현재 Debuggable 인지 체크해 볼 수도 있습니다. 만일 여러분의 어플리케이션이 디버깅 모드에서는 비정상적으로 작동하도록 구현되어 있다면, 공격자들이 어플리케이션을 크래킹하는 것이 좀 더 어려워질 것 입니다.
boolean isDebuggable = ( 0 != ( getApplcationInfo().flags &= ApplicationInfo.FLAG_DEBUGGABLE ) );
테크닉: 신뢰할 수 있는 서버에서 라이센스를 체크하기
만일 어플리케이션이 온라인상의 구성요소를 필요로 한다면, 보안을 위해서 라이센스 서버의 응답을 복사하여 서버에 전송하도록 구현할 수 있습니다. 여러분의 온라인 서버에 ResponseData 클래스와 서명 값을 전달 하고, 온라인 서버는 해당 유저가 정말로 라이센스를 갖고 있는지 체크한 후, 그렇지 않은 경우 온라인 컨텐츠를 제공하지 않도록 구현할 수 있습니다.
라이센스 서버의 응답은 키를 이용하여 암호화 되어 있기 때문에, 안드로이드 마켓 퍼블리셔 콘솔에서 제공하는 공개된 RSA 키 값을 이용하여 해당 응답이 올바른지 체크할 수 있습니다. 서버 측에서 이러한 작업을 수행할 때, 여러분은 다음과 같은 값들을 체크할 수 있습니다.
- Response Signature 가 올바른지.
- 라이센스 서비스가 LICENSED 를 응답했는지.
- 패키지 이름과 버전 코드가 올바른지.
- 라이센스 응답의 유효기간이 지나지 않았는지. (VT 값을 체크)
- 여러분은 또한 userid 필드 값을 기록하여, 크랙된 어플리케이션이 다른 라이센스 유저의 정보를 이용하는지 확인 할 필요가 있습니다. (이러한 상황은 하나의 유저아이디로 비정상적일 만큼 빈번한 라이센스 체크 요청이 있는 경우를 체크하여 확인 할 수 있습니다.)
라이센스 응답을 체크하기 위해 어떻게 해야하는지 알고 싶다면, LicenseValidator.verify() 메서드를 살펴보시기 바랍니다.
라이센스 체크가 서버 측에서 처리된다면, 여러분의 서버가 안전한 이상 이러한 메카니즘을 돌파할 수 없습니다. 왜냐하면 여러분의 서버는 신뢰할수 있는 컴퓨팅 환경 하에 위치하고 있기 때문입니다. (크래커들이 수정할 수 없는) 사용자의 제어하에 작동하는 클라이언트 사이드의 어떠한 코드도 신뢰할 수 없습니다. 만일 서버 측 라이센스 체크가 실패했다면, 사용자에게 간단하게 그 사실을 알리고, 어떠한 컨텐츠도 제공해서는 않됩니다.
결론
요약 하자면, 여러분은 여러분의 어플리케이션이 LVL 을 유니크하게 구현하여, 어플리케이션을 디컴파일 할 시에, 관련된 부분을 추적하기 어렵게 만들고 또한 어플리케이션을 수정하려는 시도에 견고하게 버틸 수 있도록 구현해야함을 명심해야 합니다. 함수를 숨기거나 라이센스 체크와 관련된 코드를 숨기는 등의 일은 전통적인 소프트웨어 공학의 관점과는 서로 상반될 수 있음을 기억해야 합니다. (일반적으로는 읽기 편하고 이해하기 쉽게 짜도록 권장함으로)
또한 보다 확실한 보안을 위해서는 라이센스 체크 구문을 신뢰할 수 있는 서버로 옮기는 것도 고려해 보아야 합니다. 이는 공격자가 라이센스를 체크하는 구문을 수정하는 행위를 불가능하게 만들어 줍니다. 클라이언트 상에서 100% 안전한 코드를 작성하는 것은 불가능하지만, 여러분의 관리하에 있는 기계 위에서 작동하는 코드에 관해서는 이는 달성 가능한 목표입니다.
그리고 여러분은 창조적이 될 필요가 있습니다. 여러분은 어플리케이션을 분석하기 위해 공격자가 주석도 없는 바이트 코드를 살펴봐야 하는 동안, 주석이 잘 달린 코드 전체를 열람할 수 있다는 이점이 있습니다. 이 장점을 적극 활용하시기 바랍니다.
또 한가지 기억해야할 점은, 여러분이 여기에 제시된 가이드라인을 따른다고 할 경우 때, 공격자들은 여러분이 새롭게 배포하는 어플리케이션 각각을 크래킹 해야 함을 기억하십시요. 그리고, 여러분이 새로운 기능을 자주 추가하면서, 매번 LVL 구현 방법을 수정하고자 한다면, 각각의 릴리즈마다 공격자들 역시 추가적인 작업을 수행햐야 함을 기억하시기 바랍니다.
이러한 모든 일들에 앞서, 어플리케이션 사용자들의 의견에 귀를 기울이고 그들을 행복하게 만드는데 힘쓰시기 바랍니다. 공격자들에 대한 최선의 방어는 기술적인 부분에 달린 것이 아니라 감정적인 부분 - 즉, 고객이 여러분의 어플리케이션을 기꺼이 구매하게 만드는 점에 달려있습니다.
[출처] [번역] 안드로이드 어플리케이션을 크래커들로부터 보호하는 방법|작성자 휴우
프로가드 사용하기
우선 당연히 현재 사용하고 계신 ADT 를 최신 버전(8.0.1 이 후 버전)을 설치 하셔야합니다.
기존에 설치된 ADT 가 있으시면 최신 버전으로 업데이트 하시면 됩니다. ADT 를 업데이트 하는 것과, 어플리케이션 타겟 플랫폼을 결정하는 것은 별다른 상관이 없으니 호환성에 대하여 큰 걱정
하지 않고 과감하게 업데이트 하셔도 좋습니다.
기존에 설치된 ADT 가 있으시면 최신 버전으로 업데이트 하시면 됩니다. ADT 를 업데이트 하는 것과, 어플리케이션 타겟 플랫폼을 결정하는 것은 별다른 상관이 없으니 호환성에 대하여 큰 걱정
하지 않고 과감하게 업데이트 하셔도 좋습니다.
ADT 업데이트를 마친 후에, 새로운 안드로이드 프로젝트를 만드시면, 프로젝트 루트 폴더에 기존과 다른 proguard.cfg 라는 파일이 생성되는 것을 확인 하실 수 있습니다. 프로가드 환경 설정 파일이라고 생각하시면 되며, 기본적으로 안드로이드에 알맞은 설정 값(메니페스트에서 이름으로 참조하는 클래스는 난독화 하지 않는 등,...)을 갖고 있음으로, 개인 개발자 분들이라면 별다른 수정 없이
해당 설정 파일을 사용하시면 될 듯 합니다.
해당 설정 파일을 사용하시면 될 듯 합니다.
그리고 마지막으로, 프로젝트 루트 폴더의 default.properties (프로젝트 설정 파일이조) 파일을
열어서 아래와 같이 프로가드를 사용하겠다고 설정 값을 추가하시면 됩니다.
열어서 아래와 같이 프로가드를 사용하겠다고 설정 값을 추가하시면 됩니다.
proguard.config=proguard.cfg
네...이게 전부입니다. 이 상황에서 여러분이 릴리즈 버전으로 어플리케이션을 익스포트 하시면,
빌드과정에서 자동으로 프로가드 툴이 동작합니다. 정말 쉬어졌습니다. 만세~!
하위 폴더가 새롭게 생성되며 해당 폴더 내에, 다음의 네 가지 파일이 생성됩니다.
빌드과정에서 자동으로 프로가드 툴이 동작합니다. 정말 쉬어졌습니다. 만세~!
그리고, 프로가드 툴이 정상적으로 동작하고 나면, 여러분의 프로젝트 폴더에 proguard 라는
하위 폴더가 새롭게 생성되며 해당 폴더 내에, 다음의 네 가지 파일이 생성됩니다.
- dump.txt : 여러분의 어플리케이션에서 사용중인 클래스들의 내부 구조에 대한 대략적인 정보를 나타냅니다. 말그대로 난독화 하기 위해 소스를 분석하는 과정에서 나오는 덤프값들이겠조. 뭐.
- mapping.txt : 이 파일은 중요합니다. 난독화 과정에서 기존 클래스 혹은 메서드가 어떤 새로운 난독화된 이름으로 매핑되었는지 그 목록을 표시해 줍니다. 난독화 된 어플리케이션에 발생하는 로그나, 스택 트레이스 들을 분석하기 위해서 꼭 챙겨 두셔야 합니다.
- seeds.txt : 난독화 되지 않은 클래스와 멤버들의 목록입니다.
- usage.txt : 사용되지 않기 때문에, apk 파일에서 제거된 코드들의 목록입니다. 혹시 제거되서는 안되는 메서드나 클래스가 제거되었는지 꼭 확인해 봐야 합니다.
프로가드 설정 하기
왠만한 경우에는 구글에서 기본적으로 설정한 proguard.cfg 가 잘 동작하겠지만, 몇몇 경우 프로가드 툴이 난독화 과정에서 잘못된 클래스나 멤버를 난독화 하거나 실재로는 사용되는 메서드를 제거하는 등의 오류를 일으킬 수 도 있습니다. 예를 들자면,
- 실제 코드가 아니라 AndroidManifest.xml 파일 내에서만 참조되는 클래스
- JNI 형식으로만 호출되는 메서드
- 동적으로 참조되는 필드 값이나 메스드들
프로가드 툴을 적용한 후 어플리케이션을 실행시켰을 때, ClassNotFoundException 등의 예외가 발생한다면 위의 경우를 의심해 봐야 합니다. 이처럼 프로가드 툴이 건들지 말아야할 코드를 건들여서 문제가 발생하는 것을 방지하기 위해, proguard.cfg 파일을 열어, -keep 항목을 추가로 선언할 수 있습니다.
-keep public class <MyClass>
난독화된 어플리케이션을 디버깅 하기
난독화된 어플리케이션의 스택 트레이스 정보는 엉망 진창이 되기 쉽상입니다.
온갖 메서드 이름과 클래스 이름이 전부 난독화되었을테니 말입니다.
난독화 과정에서 생성되는 mapping.txt 파일에 원본 이름이 어떻게 변경되었는지에 관한 내용이
저장됩니다. 프로가드 툴과 함께 제공되는 retrace.bat 혹은 retrace.sh 스크립트는 바로 이 mapping.txt 파일의 내용을 기반으로 난독화된 스택 트레이스 정보를 자동으로 변환시켜 줍니다.
온갖 메서드 이름과 클래스 이름이 전부 난독화되었을테니 말입니다.
디버깅이 불가능한 것은 아니지만, 결코 쉬운 일은 아닐테조. 하지만 앞서 이야기 한 것 처럼,
난독화 과정에서 생성되는 mapping.txt 파일에 원본 이름이 어떻게 변경되었는지에 관한 내용이
저장됩니다. 프로가드 툴과 함께 제공되는 retrace.bat 혹은 retrace.sh 스크립트는 바로 이 mapping.txt 파일의 내용을 기반으로 난독화된 스택 트레이스 정보를 자동으로 변환시켜 줍니다.
<sdk_root>/tools/proguard/ 디렉토리에 위치하며 다음과 같이 사용하시면 됩니다.
retrace.bat|retrace.sh [-verbose] mapping.txt [<stacktrace_file>]For example:retrace.bat -verbose mapping.txt obfuscated_trace.txt
출시한 어플리케이션 디버깅 하기
한가지 주의 점이 있습니다. 난독화 과정에서 생성되는 mapping.txt 파일은 기존 파일을 덮어 쓰게되어있습니다. 따라서, 개발자분들은 릴리즈 버전에 해당하는 mapping.txt 파일을 주의깊게 보존하셔야 합니다. 만일 그렇지 않을경우, 사용자들이 어플리케이션 사용주에 발생하는 크래쉬나 ANR 문제들에 관한 귀중한 정보를 보내온다 하더라도, 해당 내용을 해석할 수 없어서 발을 동동 구르게 될지도 모릅니다.
'IT_Programming > Dev Tools' 카테고리의 다른 글
Android Project SVN에 연결하기 (0) | 2012.03.07 |
---|---|
[Tip] Eclipse Android Service 에서 BreakPoint 걸기 & BreakPoint 조건 걸기 (0) | 2011.11.18 |
[Tip] MyProject/gen already exists but is not a source folder. Convert to a source folder or rename it. (0) | 2011.08.17 |
[cygwin_repo_shell script] Windows에서 Android 소스받기 (0) | 2011.08.11 |
[Eclipse] 원격 프로젝트 관리하는 RSE (Remote System Explorer ) Plugin (0) | 2011.06.15 |