C# 배포시 난독화를 해야 할까? - ConfuserEx 사용법
다양한 CPU, 다양한 운영체제의 홍수 속에서 자바와 .Net과 같은 플랫폼 독립성을 가진 체계가 점점 더 힘을 얻어가고 있는 형국이다. 운영체제나 CPU의 종류에 제한받지 않는 응용 프로그램의 개발 및 배포는 생산성뿐만 아니라 여러 가지 장점을 제공한다. 더구나 끊임없는 하드웨어 성능의 발전은 플랫폼 독립성 때문에 희생해야 하는 성능적인 단점조차도 문제가 되지 않게 해주고 있다.
C언어로 작성한 프로그램을 C/C++ 컴파일러로 빌드하게 되면 윈도나 리눅스와 같은 특정 운영체제에서만 수행할 수 있는 기계어 코드가 만들어 진다. 이 기계어 코드는 특정 운영체제에서만 사용할 수 있을 뿐만 아니라 CPU의 제약도 받을 수밖에 없다. 그만큼 개발자의 입장에서는 다양한 플랫폼 환경을 감안해야만 한다. 그렇지만 자바나 C#과 같은 언어로 개발한 프로그램의 경우에는 프로그램을 빌드하면 플랫폼과 무관한 중간 코드 형태로 만들어 지기 때문에 가상 머신이 동작하는 플랫폼이라면 어느 곳에서 동일한 프로그램으로 수행할 수 있다. 개발자가 플랫폼 환경에 대한 별다른 조처를 하지 않더라도 프로그램의 활용성이나 확장성이 상당히 넓어지고 개발 과정의 생산성 향상과 효율성이 높아질 수 있다.
문제는 소스 코드의 보안성이다. 소스 코드를 내 금고에 잘 보관한다고 될 문제가 아니라는 점이다. 자바나 .Net 프로그램들은 중간 코드에 대한 스펙이 개방되어 있기 때문에 실행 프로그램만 배포하더라도 해당 프로그램으로 소스코드를 어렵지 않게 만들어 낼 수 있다. 별다른 준비를 하지 않는다면 실행 프로그램만 배포하더라도 소스 코드를 같이 배포하는 것과 같은 의도하지 않은 결과를 초래할 수 있다. C#의 개발된 응용 프로그램을 무료로 배포하는 dotPeek와 같은 도구로 디컴파일을 해보면 혀를 내두를 수밖에 없을 것이다. 소스코드와 UI가 거의 그대로 복원된다.
역공학(Reverse Engineering)의 일환으로 소스코드가 없어진 프로젝트를 수정할 일이 있다던가 하는 경우에는 이런 작업이 큰 도움이 되겠지만 어렵게 제작한 내 소스코드가 내 의도와 관계 없이 개방되는 것은 정말 안타까운 일이 아닐 수 없다.
디컴파일을 통해서 소스코드를 복원할 수 있다는 것은 굳이 디컴파일 과정을 직접 거치지 않더라도 간접적으로 확인할 수 있다. 위의 그림은 소스 코드에 있는 특정 변수명을 검색할 것으로 실행 프로그램과 DLL 라이브러리에서 모두 검색되는 것을 볼 수 있다. 즉, 디컴파일 도구가 거의 원본 소스 코드 수준으로 복원할 수 도 있다는 것을 간접적으로도 확인할 수 있는 것이다. 물론 주석이나 코딩 스타일과 같은 부분까지 복원되지는 않는다. 이런 정보는 컴파일 과정에서 모든 제외되기 때문이다. 그러나, 프로그램의 가독성을 위해서 변수명, 클래스명, 오브젝트명 등을 의미 있는 것으로 붙이기 때문에 주석이 없더라도 코드는 충분히 참고할만하고 읽고, 수정이 가능한 것이다.
물론 C언어를 직접 특정 플랫폼에 맞는 기계어로 생성하는 과정도 디컴파일 또는 디스어셈블이 가능하기는 했다. 그렇지만 빌드 과정에서 디버깅 정보를 담지 않는 릴리즈(Release) 버전으로 빌드해서 배포하면 디컴파일이나 디스어셈블한 결과는 거의 암호나 다름이 없었다. 특히 최적화 레벨을 높이면 높일수록 원본 코드와는 전혀 다른 기계어가 산출되기 때문에 역공학을 통해서 원본 소스를 확보하는 것은 거의 불가능에 가까웠다. 그러나 C#으로 제작한 프로젝트의 경우에는 릴리즈(Release) 버전으로 빌드해서 배포하더라도 디컴파일러를 사용하면 거의 원본 수준의 소스 코드를 얻을 수 있는 문제가 있는 것이다. 예전 개발 방법에 익숙한 개발자라면 이 현실을 직시해야만 한다.
그래서 등장한 것이 코드 난독화(Code Obfuscation)이다. 앞서 C언어 소스 코드를 릴리즈 버전으로 빌드한 것을 디컴파일하면 거의 암호 수준이라고 언급했는데 C#으로 빌드한 결과물을 난독화 과정을 한번 더 거치도록 해서 디컴파일을 하더라도 읽기가 힘든 결과물이 되도록 하는 것입니다. 난독화 과정은 비주얼스튜디오 자체에서 지원하는 기능은 아니고 난독화 도구(오퍼스티케이터, Obfusticator)를 이용해야 한다.
필자의 경우에는 무료이고 오픈소스인 ConfuserEx를 사용하기로 했다. 라이선스는 MIT 라이선스로 기업에서도 무료로 사용할 수 있다. 아래의 주소에서 다운로드 받을 수 있다.
https://github.com/yck1509/ConfuserEx/releases
ConfuserEx_bin.zip 를 다운로드해서 압축을 해제하면 바로 사용할 수 있다.
압축을 해제한 결과는 위의 그림과 같다.
Confuser.CLI.exe /?
ConfuserEx.CLI: No output directory specified.
Usage:
Confuser.CLI -n|noPause <project configuration>
Confuser.CLI -n|noPause -o|out=<output directory> <modules>
위의 내용은 명령 창에서 수행할 수 있는 CLI 도구인 Confuser.CLI.exe의 도움말이다. 아래의 UI에서 프로젝트를 만들어 놓으면 이 CLI 도구를 통해서 난독화 과정을 자동화할 수도 있다.
ConfuserEx.exe를 실행시키면 위의 그림과 같은 창을 통해서 난독화 과정을 위한 프로젝트를 만들어서 수행까지 시킬 수 있다. 실행할때 주의할 점은 반드시 "관리자 권한으로 실행"시켜야 정상적인 결과를 얻을 수 있다. 새 프로젝트에서는 일단 빌드한 결과물이 있는 폴더와 결과가 저장될 폴더를 Base/Output 폴더로 선택한다. 그다음에는 어떤 파일들을 난독화 할지 탐색기에서 끌어다 놓기로 하단 공간에 두면 작업 준비가 끝나는데 나중에 이 작업을 단순화하려면 프로젝트를 저장할 필요가 있다.
설정은 각 개별 파일에 할 수도 있지만 <Global settings>를 선택하고 [+]클릭하여 true를 설정한 다음에 [-] 아래에 있는 규칙 수정 버튼을 클릭해서 상세한 난독화 규칙을 적용한다. 필자의 경우에는 Preset을 Maximum으로 설정해서 최대한 난독화 하도록 설정했다. 전체 규칙을 적용하면 물론 속도는 상당히 떨어질 것이다.(필자의 경우 압축을 적용했더니 바이러스가 검출되어서 압축은 사용하지 않았다)
모든 준비가 끝나면 Protect! 탭으로 이동하여 [Protect!] 버튼을 클릭하여 난독화 작업을 진행한다. 좌측의 그림을 보면 각 모듈 단위로 지정한 규칙들이 모두 적용되고 있음을 확인할 수 있다.
위의 그림에서 좌측은 난독화 과정을 거치지 않은 프로그램을 dotPeek로 디컴파일한 결과이고 우측은 난독화 과정을 거친 다음의 디컴파일한 결과이다. 난독화 과정을 거치지 않으면 거의 원본 수준으로 소스코드가 복원되지만 난독화 과정을 거치면 프로그램은 정상 수행되지만 디컴파일한 결과는 거의 알아보기 힘들게 되고 재사용도 어렵게 되는 것이다.
끝으로 이 난독화 과정을 프로젝트에 포함시키려면 프로젝트 빌드 시점에 수행하도록 빌드후 이벤트로 등록하는 방법이 있고, 위의 그림과 같이 비주얼스튜디오>도구>외부도구에서 난독화 과정을 수행하는 메뉴를 추가해서 사용하는 방법이 있다. 필자의 경우에는 후자로 수행했다. 내가 오랜 시간 공들여서 제작한 프로그램을 오픈 소스 프로젝트로 만들고 싶다면 빌드한 상태로 배포하면 되고 그렇지 않다면 난독화 과정을 거치는 것을 추천한다.