본문 바로가기

보안라이프/IT트렌드

내 소스코드를 보호하자! 코드 가상화 기법

 1. 역공학
프로그램을 정적으로 조사하고 검증하는 방법에는 두 가지가 있습니다. 첫 번째는 소스코드를 살펴보는 것이고, 두 번째는 컴파일된 프로그램(바이너리 파일)을 거꾸로 살펴보는 것이죠. 소스코드를 살펴보는 것은 이해할 수 있겠는데.. 컴파일 된 프로그램은 어떻게 볼 수 있냐구요? 바로 역공학 기법을 이용하면 됩니다.

역공학(Reverse Engineering, 리버싱)이란 컴파일 된 바이너리를 어셈블리 코드로 살펴보는 것을 뜻합니다. 가령, 윈도우에 기본적으로 내장되어 있는 계산기(calc.exe)를 역공학 도구를 이용하여 보면 아래와 같은 코드들을 볼 수 있습니다.

<그림 1 - 어셈블리 코드>


혹은 좀 더 좋은 역공학 도구를 이용한다면, 실행파일로부터 소스코드를 알아낼 수도 있습니다.  <그림 2>는 위에서 본 calc.exe의 소스코드를 복원한 것인데요, 이는 우리가 알고 있는 "코드"라는 것과 가깝죠.


<그림 2 - C 코드>


이러한 역공학 기술은 악성코드 분석가에게는 매우 좋은 조사 방법입니다. 왜냐하면, 악성코드 제작자는 악성코드를 오픈소스로 공개하지 않기(?)때문입니다. 분석가에게는 역공학만이 유일한 정적 분석 방법입니다. 

그러나 프로그램 제작자의 입장에서 역공학은 그다지 반갑지 않습니다. 역공학 기법을 이용하면 자신의 프로그램의 동작 원리가 밝혀지는 것은 물론, 더 나아가 코드까지도 공개될 수 있기 때문이지요. 그렇다면 내가 만든 프로그램의 코드를 안전히 보호하는 방법은 무엇일까요? 역공학 기술로도 안전하게 내 코드를 보호하는 방법은 없을까요?

있습니다! 이를 안티 리버싱 기법이라고 말합니다. Anti-Reversing, 말 그대로 리버싱이 안 되도록 하는 것이죠. 안티 리버싱 기법은 많은 종류가 있는데요. 실행 압축, 프로그램 난독화, 안티 디버깅 코드 삽입, 코드 가상화... 등 다양한 방법이 있습니다. 이번 포스트에서는 이 중에서도 코드 가상화에 대해 살펴보려고 합니다. 



▶ 2. 코드 가상화

코드 가상화 기법은, 위에서 말했다시피 안티 리버싱 기술 중 하나입니다. 코드 가상화를 프로그램에 적용할 경우, 역공학으로부터 안전하게 프로그램과 코드를 보호할 수 있는 것이죠. 그렇다면 어떻게 보호하는 것일까요? 비밀은 바로 가상 CPU에 있습니다. 

프로그램은 많은 바이너리 코드들로 이루어집니다. 컴퓨터 내의 CPU라는 놈이 이 명령어들을 한땀 한땀... 아니, 한줄 한줄 실행합니다. 그렇게 함으로써 우리가 <그림 3>과 같이 calc.exe를 실행할 수 있게 되는 것이죠.

<그림 3 - 실행된 프로그램>



코드 가상화 기법의 경우는 좀 다릅니다. 프로그램을 만든 후, 이를 컴파일하여 실행파일을 만드는데, 코드 가상화 기법은 컴파일 과정에서 어셈블리 코드를 살짝 바꿉니다. intel CPU용 어셈블리가 아니라, 가상화 CPU용 어셈블리로요. 이것은 기존의 역공학 도구로 코드복원이 불가능합니다. 따라서 작성한 코드를 안전하게 보호할 수 있게 되는 것입니다. 또한 이렇게 가상화된 코드는 원래의 CPU에서 실행할 수 없습니다. 가상 CPU에서 실행합니다. 가상 CPU는, 프로그램 내에 소프트웨어적으로 구현되어 있죠.

한 마디로 정리하면, 실제 CPU가 실행하는 것은 가상화된 어셈블리 코드를 실행하는 가상화된 CPU인 것이죠. 이를 그림으로 표현하면 <그림 4>와 같습니다. 

<그림 4 - 코드 가상화의 원리>



즉, 코드 가상화 기법을 간단히 정리하면 이렇습니다. 

1.  원래의 코드를 가상화 CPU용 코드로 변환합니다. 
2.  가상화 CPU는 그 코드를 실제 CPU가 이해할 수 있도록 해석합니다. 
3. 해석된 코드는 실제 CPU에게 읽히며, 프로그램이 실행됩니다.

이해하기 어렵다구요? 그렇다면 자바를 떠올려보세요! 컴파일된 자바 코드가 JVM(Java Virtual Machine)에서 실행되고, JVM이 실제 CPU에서 실행되는 방식으로 자바 어플리케이션이 실행되죠? 바로 코드 가상화도 이와 같은 원리입니다. 


▶ 3. 코드 가상화 도구 : Code Virtualizer
그렇다면, 우리의 프로그램에 코드 가상화 기법을 적용하려면  어떻게 해야 할까요? 먼저 가상화 CPU 를 만들고, 이 가상화 CPU용 코드를 만들면 됩니다. 이러한 작업을 수행해 주는 코드 가상화 도구로는 대표적으로 Code Virtualizer가 있습니다. Code Virtualizer는 Oreans사에서 개발한 의 코드 가상화 시스템입니다. 


<그림 5 - Code Virtualizer (출처 http://oreans.com/)>

<그림 5>에서 볼수 있듯이, 원본 어셈블리 코드가 Code Visualizer를 거쳐 변환되면, 쉽게 알아볼 수 없는 가상화 코드가 됩니다. 이런 코드들은 그리고 이는 코드 내에 있는 가상 에뮬레이터로 실행됩니다. 그러면, 실제 프로그램에 이를 적용해 보도록 합시다.  여기 Ahnlab.exe이라는 프로그램이 있습니다. 실행되면 아래와 같은 알림 창을 띄우는 단순한 프로그램입니다. 


<그림 6 - Ahnlab.exe>


이 프로그램의 코드는 <그림 7>과 같습니다. VirtualizerSDK.h는 Code Virtualizer에서 제공하는 헤더파일로써, 매크로를 사용하여 가상화할 코드 블록을 지정할 수 있게 해 줍니다.  가상화 할 코드 블록은 VIRTUALIZER_START,  VIRTUALIZER_END로 지정할 수 있습니다.

<그림 7 - Ahnlab.exe의 소스코드>


이제 이 프로그램을 가상화하게 되면, 매크로로 지정된 부분만이 가상화됩니다. Code Virtualizer에서는, <그림 8>과 같이 많은 에뮬레이터와 가상 CPU를 지원합니다. 사용자는 복잡도와 실행시간을 보고, 사용할  CPU를 선택할 수 있습니다. 복잡도가 높을수록 코드를 안전하게 보호할 수 있지만, 실행 시간이 느려진다는 단점이 있습니다. 또한, 2개 이상의 가상CPU를 선택하여, <그림 9>와 같이 다중 코드 가상화를 할 수도 있습니다.


<그림 8 - Code Virtualizer>


<그림 9 - 다중 코드 가상화 (출처 http://oreans.com/) > 


▶ 3. 마무리하며
코드 가상화가 완료되면 가상화된 코드, 더미코드 등이 생기며 파일의 크기가 늘어납니다. 또한 공격자가 가상화된 코드 블록을 디컴파일하고자 하면, x86 명령어 대신 가상화 CPU에 대한 명령어 셋이 보여집니다. 더욱 해석하기 어려워지는 것이죠. 따라서 이는 안티 리버싱 및 난독화 기법으로도 볼 수 있습니다. 이렇듯 코드 가상화 기법은, 소중한 코드를 보호할 수 있게 하는 유용한 기법입니다. 그러나, 이 기술은 마냥 좋은 것은 아닙니다. 적어도 악성코드 분석가들에게는요. 생각해 봅시다. 만약 코드 가상화 기법이 악성코드에 적용된다면 어떨까요? 그것도 다중 코드 가상화 기법이 적용된 악성코드라면? 

그 악성코드를 분석하는 분석가는.. 며칠 밤 야근을 하게 될지도 모르겠군요...


<그림 10 - 코드 가상화가 적용된 실행파일>