“난독화”란 용어가 보안 업계에 들불처럼 퍼지고 있습니다. 이 단어를 누가 처음 꺼냈는지는 모르겠지만 요즘은 마치 이 녀석을 빼고는 보안을 말할 수 없다는 분위기가 돼 가는 것 같아서 안타깝기 그지 없는 실정입니다. 그 가운데는 너무 많은 약장수들이 있는 것도 한 몫 하는 것 같습니다. 할머니들을 모아놓고 약을 파는 약장수나 컴퓨터를 사용하는 업계 전반의 공포심을 상대로 장난치는 그들이나 본질적으로 다른 점은 없지 않나라는 생각이 듭니다.
약장수들은 항상 그렇습니다. 애꾸눈이예요. 무슨 이야기냐구요? 한쪽만 본다는 것이죠. 문제의 본질을 총체적으로 보지 않고 지엽적인 부분만 집중해서 봅니다. 그리곤 그 지엽적인 부분을 전체 문제와 동일시 하는 과정을 거치죠. 결국 그 지엽적인 문제만 해결하는 방법을 가지고 와서 원래 문제를 다 해결할 수 있다고 광고를 합니다. 잘 아시겠지만 보안에서는 말이죠. 완벽이란 없습니다. 그러니 만병통치약도 없지요. 여러분에게 누군가 찾아와서 다 막습니다, 완벽합니다, 이거 하나로 모든 걸 차단할 수 있는 완벽한 솔루션입니다, 그런 이야기를 한다면 일단 의심하고 보는게 맞습니다.
#0
난독화란 기술은 크게 폴리모픽과 메타모픽이라는 테크닉에 기반해서 구현 됩니다. 두 가지 기술의 차이는 아래 글에 상세하게 나와 있습니다. 여러분이 일단 난독화의 진실을 제대로 이해하려면 이 두가지 기술의 차이를 정확하게 하는 게 중요합니다.
변이(mutation)는 바이러스 제작자에게는 참 오래된 화두다. 바이러스 제작자들은 백신을 피하기 위해서 바이러스의 다양한 부분들이 변형되도록 연구했다. 이름을 바꾸었고, 내부에서 사용하는 문자열을 변경했다. 그리고 최근에는 백신의 감시를 피하기 위해서 바이러스 코드를 직접 변형하는 기법들을 사용한다. 변이는 바이러스의 출발점부터 지금까지 존재하는 가장 근본적이면서도 가장 강력한 기술이다. 이렇게 음지에서 연구된 ‘변이’라는 기법이 요즘은 난독화라는 이름으로 속속 바이러스가 아닌 일반 프로그램을 보호하는 용도로도 사용되고 있다. 이런 현상을 보면 정말 극과 극은 통한다는 말이 실감나기도 한다.
프로그램 변형 기법을 설명할 때 흔히 등장하는 용어로 메타모픽(metamorphic)과 폴리모픽(polymorphic)이 있다. 이 둘은 모두 morphic이란 어미에서 볼 수 있듯이 원본 프로그램을 변형시켜 새로운 ‘변이’를 만들어내는 방법을 의미한다. 용어 자체가 워낙 비슷하게 생긴 까닭에 용어의 비슷함만큼이나 그 차이가 불분명하게 여기저기 많이 사용되는 경향이 있다. 잠깐 둘의 차이점을 살펴보고 넘어가도록 하자.
이 두 변형 기법의 가장 근본적인 차이는 원본 회귀 가능성에 있다. 변형 함수를 M, 원본 바이너리를 S, 변형된 바이너리를 D라고 할 때, 이 사이에서는 D = M(S)라는 관계가 성립한다. 여기까지는 메타모픽과 폴리모픽 모두 동일하다. 둘의 차이는 생성된 D에 있다. 만약에 생성된 D로부터 원본 S로 돌아갈 수 있는 역함수 M-1가 존재한다면 이 변형함수 M은 폴리모픽 함수라 하고, 역함수가 존재하지 않는 변형함수라면 메타모픽 함수라 부른다. 즉, 변형된 바이너리에서 원본을 추출하는 것이 가능하다면 폴리모픽, 불가능하다면 메타모픽이란 이야기다. 메타모픽이 폴리모픽보다는 좀 더 상위의 변형 기법임을 알 수 있다.
– 메타모픽 엔진의 핵심, 코드 교환의 원리, 신영진
글에도 나와 있는 것처럼 메타모픽이 변형으로써는 좀 더 상위의 개념입니다. 그런데 시중에 나와 있는 거의 대부분의 난독화 솔루션이라 불리는 것들은 대부분 폴리모픽이란 메커니즘에 기반하고 있는 경우가 많습니다. 이 경우에는 사실 upx와 크게 차이가 없습니다. 패커죠. 메모리 상에서 원본이 드러나기 때문입니다. 물론 그보다 더 조악한 수준의 심벌을 숨겨주는 프로그램을 난독화라고 파는 경우도 많이 있습니다.
반면 메타모픽 쯤 되면 사실 해커들이 말하는 어레이 몇 개 찾아가지고서는 공략하기 힘든 수준이 됩니다. 하지만 PC 기반의 시중에 출시되어 있는 난독화 솔루션 중에서도 메타모픽이란 기술에 근간을 둔 제품은 거의 없습니다. 제품엔 메타모픽이라고 그럴싸하게 적어놓고 있지만 그렇지 않은 경우가 많습니다. 물론 거기에도 속깊은 사정이 있답니다. 그건 조금 있다가 살펴보기로 합시다.
#1
역사를 아는 것이 중요합니다. 과거를 알아야 미래를 예측할 수 있기 때문이지요. PC 기반 플랫폼에서는 난독화라는 기술은 바이러스 제작자들 사이에서 연구가 됐지만 나중에는 일반 프로그램에도 상당수 차용됐습니다. 이렇게 일반 프로그램에서 사용하게 된 계기는 바로 크랙을 막기 위함이었습니다. 크랙이란 건 주로 실행 파일을 리버싱해서 주요 코드를 바꾼 다음 실행하는 방법을 말합니다. 이런 행위를 막기 위해서 난독화가 도입된 것이죠. 실행 파일 단계에서의 정적 분석을 어렵게 만들기 위한 장치였습니다. 여기까지 들으면 요즘 다른 분야에서 벌어지는 시츄에이션과 얼추 비슷하죠?
네. 그렇게 초기 수준의 난독화를 도입하자 크랙이 사라졌을까요? 천만의 말씀. 만만의 콩떡이죠 ㅋ~ 크랙하는 사람들은 금방 방법을 찾았습니다. 굳이 실행 파일을 패치하지 않고, 메모리 상의 코드를 직접 패치해도 똑같은 결과가 나온다는 걸 알아내 버린것이죠. 그 전 세대에 개발된 난독화라는 기법이 폴리모픽이란 메커니즘에 기반해서 메모리 상에는 원본이 그대로 드러나는 문제점이 있었기 때문이죠. 이게 이제 다음에 벌어질 일입니다. 어레이라고 불리는 것들이 몇 개 돌아다닐 겁니다. 그런 어레이 몇 개만 입수하면 부산시에 사는 초등학생도 크랙을 할 수 있게 되는 것이죠.
메모리 패칭에 난독화가 속수 무책이자 보안 업계 사람들은 크게 세 가지 길로 나뉘게 됐습니다. 첫번째 사람들은 난독화를 독자적으로 더 깊게 연구한 사람들입니다. 메타모픽 수준으로 진화한 것이죠. 메모리 상에도 원본 코드가 드러나지 않을 뿐더러 실행할 때마다 바뀌기 때문에 해커 입장에서 패치하기가 곤란하게 만든 것입니다. 그 다음으로는 정적 체크를 선택한 사람들이 있습니다. 파일 뿐만 아니라 메모리 상의 코드가 변경됐는지를 체크하는 코드를 삽입한 겁니다. 끝으로는 동적 방어 메커니즘을 무장한 사람들이 나오게 됐습니다. 메모리 보안이라 불리는 기술이죠. 운영체제를 패칭해서 우리 프로그램이 디버깅 당하거나 메모리가 불법적으로 조작되는 행위를 하지 못하도록 방어하는 것을 말합니다.
어떻게 됐을까요? 누가 가장 성공했을까요? 물론 여기엔 완벽한 방법도 없고, 또 어떤 한가지가 가장 뛰어나지도 않습니다. 모든 방법을 적절하게 잘 버무려 써야겠지요. 그래도 어쨌든 오늘은 난독화 이야기를 하기로 했으니 메타모픽 쪽으로 선회한 사람들에 대해서만 알아보도록 합시다.
#2
메타모픽으로 선회한 사람들은 어떻게 됐을까요? 과연 그들의 생각처럼 어떤 해커도 그들의 코드를 해독하지 못했을까요? 당연히 아니겠지요. 안타깝게도 그들은 해커의 공격을 받기도 전에 스스로 붕괴할 수 밖에 없었습니다. 너무 큰 문제에 봉착해 버렸거든요. 우리의 튜링옹께서 1936년에 증명을 끝내버린 정지 문제였습니다. 정지 문제란 간단히 말하면 프로그램 P가 주어졌을 때 그 프로그램이 정지할지 하지 않을지 판단하는 프로그램은 작성할 수 없다는 것을 의미합니다.
계산 복잡도 이론에서 정지문제(停止問題, halting problem)는 판정 문제의 일종으로 다음과 같이 요약할 수 있다.
프로그램을 설명한 것과 처음 입력값이 주어졌을 때, 이 프로그램에 입력값을 넣고 실행한다면 이 프로그램이 계산을 끝내고 멈출지 아니면 영원히 계속 계산할지 판정하라.
1936년에 앨런 튜링이 모든 가능한 입력값에 대해 정지문제를 풀 수 있는 일반적인 알고리즘 은 존재하지 않는다는 것을 증명했다. 그러므로 ‘정지문제는 튜링 기계에서 판정할 수 없다’고 한다.
– http://ko.wikipedia.org/wiki/%EC%A0%95%EC%A7%80_%EB%AC%B8%EC%A0%9C
이게 왜 메타모픽이랑 연관이 될지 궁금할 겁니다. 바로 메타모픽의 얼굴이 너무 많다는 겁니다. 실제로 진짜 메타모픽 엔진은 실행할 때마다 모든 코드가 예측할 수 없는 순서로 재배열, 재구조화되는 과정을 거칩니다. 그런 모든 변종이 정상적으로 동작한다는 것을 보장할 수가 없습니다. 즉, 메타모픽을 적용한 프로그램이 어떤 고객의 PC에서 멈추더라도 그건 전혀 이상한 현상이 아니라는 것이지요. 왜냐하면 그 변종에 대해서는 누구도 검증을 하지 못했거든요. 메타모픽 엔진은 본질적으로 안전성을 검증할 수가 없습니다.
이쯤에서 JIT 컴파일을 반론으로 들고 나오는 사람들이 있습니다. JIT 컴파일은 메타모픽이랑은 완전 다른 기술입니다. JIT 컴파일은 서로 다른 CPU의 종류에 대해서만 한정적으로 서로 다른 컴파일 결과를 만들어내는 기술이지 동일한 CPU에서 매번 다른 코드를 만들어내는 기술이 아닙니다. 어쨌든, 최고의 메타모픽 엔진은 튜링옹께서 증명하셨던 것처럼 누구도 그것의 안정성에 대해서는 검증할 방법이 없습니다.
물론 정지 문제만 있었던 것이 아닙니다. 다른 문제도 있었습니다. 바로 자신의 얼굴이 너무 많아서 자신 조차도 이게 정상인지 아닌지를 판단할 방법이 없어진다는 겁니다. 코드가 매번 바뀌기 때문에 진짜 메타모픽 엔진은 변형된 코드에 대해서 예측할 수 없습니다. 따라서 현재 실행되는 코드만 보고 나 스스로 이 코드가 원래 나의 코드인지 아니면 해커가 변형한 코드인지를 분간해 낼 방법이 없어진다는 점입니다. 최고의 메타모픽 엔진으로 보호된 프로그램은 아주 사소한 프로그램 변조도 본질적으로 그 공격을 판단할 방법이 없어지는 묘한 현상이 발생합니다. 자가당착적인 구조죠. 성형에 중독된 여성들이 진짜 자기 얼굴이 어땠는지 까먹는 것과 비슷한 문제라고 보셔도 되겠습니다.
#3
HTML5를 기점으로 이제 자바스크립트로 둠을 만드는 세상이 도래했습니다. 요즘 자바스크립트는 더 이상 예전의 자바스크립트가 아니지요. 하지만 잘 알겠지만 자바스크립트는 소스 코드가 브라우저에 그대로 다운로드 됩니다. 게임 입장에서는 쥐약입니다. 핵심 코드들이 모두 날 것 그대로 노출된다는 것이기 때문이지요. 그래서 브라우저 게임 대부분은 지금까지는 서버에서 모든 연산이 가능한 방식의 게임 밖에는 출시되고 있지 않습니다. 클라이언트 연산이 들어가는 게임이 나온다면 정말 쉽게 해킹이 가능할 것이기 때문입니다.
How do I protect my content from pirates?
The “modern” open-source-based answer to this is, of course, that you shouldn’t: instead, you should architect your application or business so that the value is generated by the service you offer, not in the content delivered to the browser. However, in some cases that may well be unduly idealistic. Your best bet for under those circumstances is to look into JavaScript obfuscators.
WebGL FAQ 페이지에서 발췌한 내용입니다. 컨텐츠를 어떻게 보호할 수 있느냐는 질문입니다. 답은 아이러니하게도 난독화를 적용하는게 현실적인 수준이라는 대답입니다. 요즘 난독화가 자주 등장하는 가장 극적인 이유를 보여주는 한 장면입니다. 개발을 더 빠르고, 더 쉽게 할 수 있는 생산성이 높아지는 도구들을 잔뜩 만들었는데, 결국 사람들이 쉽게 만든다는 건 해커도 쉽게 리버싱 할 수 있는 환경을 만들어 버린 겁니다. 리플렉션 우왕 굳. 이랬는데 그 리플렉션에 사용되는 메타 데이터로 해커도 같이 꿀빨고 있었던 셈이죠.
어쨌든 계속 이야기 했지만 이 싸움의 끝에는 안타깝게도 난독화가 위치할 수는 없습니다. 폴리모픽은 결국은 원본을 구할 수 있다는 말이고, 메타모픽은 여러가지 문제가 있기 때문입니다. 자바스크립트 난독화 도구도 당연히 난독화 이전 상태로 돌려놓을 수 있습니다. 변수명/함수명은 보기 힘들어지지 않냐구요? 어셈블리 코드도 C 코드 보듯이 보는 친구들입니다. 그런 문자열 몇 개 뭉개졌다고 해독하기 힘들다고 생각하는 건 너무 순진한 생각입니다.
어떻게 해야 할까요? 네. 맞습니다. 사람이 이해하기 쉽도록 만든 장치를 사용해서 다시 이해하기 어렵게 만드는 우스꽝스러운 일을 해야 합니다. 이해하기 쉽게 만든 장치들을 사용해서 이해하기 어렵게 만든 내용을 해석하는 해석기를 만들어야 한다는 것이다. 자바스크립트 위에 새로운 해석기 레이어를 올려야 한다는 겁니다. 당연한 이야기겠지만 그 해석기가 해석하는 코드는 해커가 이해하기 어려운 수준으로 만들어야 겠지요. 결국은 VM 같은 구조가 되는 겁니다. 그러면 그 해석기 코드는 해커가 이해하기는 힘들기 때문에 기존과 동일한 수준, 내지는 만들기에 따라서는 더 높은 수준으로 분석하기가 힘들게 만들 수 있습니다. 그리고 자바스크립트 상에서 구동되는 코드 체계는 그 해석기가 해석하는 코드가 반드시 있어야 동작하도록 만들어 놓아야 하는 겁니다.
얘가 도대체 무슨 소리를 하는 거냐고 의아해 하실 거예요. 또 좀 아는 사람들은 그게 말이냐 돼냐? 가능한 소리를 해야지, 라고들 합니다. 그럼 이제 작품 감상을 하러갈 시간이 된 것 같습니다. 직접 보면 웃음 밖에는 안 나오는 프랑스 컴퓨터 사이언스계의 우주 신, Fabrice Bellard옹의 작품입니다. 이제 약을 팔아도 이정도는 만들어 놓고 약을 팔도록 합시다.