역컴파일러
역컴파일러(영어: decompiler)는 컴파일러와 반대의 역할을 하는 컴퓨터 프로그램이다. 즉, 이것은 상대적으로 저수준의 추상에 있는 프로그램의 코드를 고수준의 추상으로 변형한다. 역컴파일러는 보통 원본 소스코드로 완벽하게 재구성될 수 없으며, 결과가 매우 다양할 수 있다. 그럼에도 불구하고 이것은 소프트웨어 리버스 엔지니어링에서 매우 중요한 도구이다. 역컴파일러는 실행 파일을 입력으로 갖고, 같은 기능을 하는 소스 코드 파일 즉, 고급 언어로 만든다.
도입
역컴파일링은 잃어버린 소스 코드를 되찾거나, 컴퓨터 보안 그리고 오류 검출 정정 등의 과정에서 유용하게 사용된다.[1] 역컴파일링의 성공은 현재 코드에 존재하는 정보와 얼마나 세련된 분석을 했는지에 달려 있다. 바이트코드 형식은 종종 확장된 메타데이터와 높은 수준의 특징들을 포함하기 때문에 역컴파일의 성공이 가능할 수 있다. 디버그 데이터의 존재는 원본 변수와 구조체 이름들 그리고 줄 번호까지도 재생산 하는 것을 가능케 할 수 있다. 이런 메타데이터나 디버그 데이터 없이 기계어를 역컴파일링하는 것은 훨씬 어렵다.[2]
몇몇 컴파일러들은 난독화 코드를 만드는데 이걸로 인해서 실행 파일을 리버스 엔지니어링하는 것은 매우 어려워 진다.
디자인
역컴파일러는 역컴파일 과정에서 각각의 특별한 과정을 수행하는 것들의 집합으로 생각될 수 있다.
로더
첫 번째 역컴파일 단계는 입력된 기계어나 중간 언어 프로그램의 바이너리 형식을 로드하고 분석하는 것이다. 이것은 펜티엄, 파워PC 같은 아키텍처와 엔트리 포인트 같은 입력된 프로그램의 기본 사실들을 발견하는 것이 가능해야 한다. 많은 경우에 C의 main 함수(유저가 쓴 코드의 시작점) 같은 것을 찾는 것이 가능해야 한다. 이것은 런타임 초기화 코드를 역컴파일하지 않고 배제해야 한다. 만약 심볼 테이블과 디버그 데이터가 사용 가능하다면 이것들 또한 로드되어야 한다. 프론트엔드는 코드와 링크된 라이브러리들을 식별할 수 있다. 이것은 라이브러리 인터페이스를 제공할 수 있다. 만약 사용된 컴파일러를 결정할 수 있다면 코드 관용구들을 식별하는데 유용한 정보가 될 것이다.[3]
디스어셈블리
다음 단계는 기계어 명령어들의 디스어셈블리를 기계와 독립적인 중간 표현 형식 (IR: intermediate representation)으로 변환하는 것이다.
mov eax, [ebx+0x04]
은 IR로 변환될 수 있다.
eax := m[ebx+4];
관용구
관용적 기계어 코드 결과들은 결합된 의미들이 명령어들의 개별 의미로 봤을 때 명백하지 않은 코드의 결과물들이다. 디스어셈블리 과정 또는 다음의 분석 과정에서 이러한 관용적인 결과물들은 알려진 IR과 동등한 것으로 번역될 필요가 있다. 다음은 x86 기계어 코드이다.
cdq eax ; edx is set to the sign-extension of eax
xor eax, edx
sub eax, edx
이것은 다음과 같이 변환될 수 있다.
eax := abs(eax);
몇몇 관용적 결과들은 머신에 독립적이다. 즉 오직 하나의 명령어에 관련된다. 예를 들면, xor eax, eax는 eax 레지스터를 비우는 명령이다. 이것은 a xor a = 0 같은 머신에 독립적인 간단한 규칙으로 간소화될 수 있다.
일반적으로 다음 단계에서 명령어 순서에 영향을 덜 미치게 하기 위해서 가능한 한 관용적 결과들에 대한 탐지는 늦추는게 좋다. 예를 들면, 컴파일러의 명령어 스케줄 단계에서는 다른 명령어를 관용적 결과에 삽입하거나 순서를 바꾸는 경우가 있다. 디스어셈블리 단계의 패턴 매칭 과정에서 바뀐 패턴을 인식하지 못할 수도 있다. 다음 단계에서 명령어 집합 표현들은 더 더 복잡한 표현들로 바뀌고 고전적인 형태로 수정하며 바뀐 관용구는 고급 패턴에 맞게 된다.
컴파일러 관용구를 서브루틴 호출, 예외 처리 그리고 Switch 문으로 인식하는 것은 특히 중요하다. 또한 몇몇 언어들은 문자열이나 정수형에 대한 광범위한 지원을 가진다.
프로그램 분석
다양한 프로그램 분석이 IR에 적용될 수 있다. 특히, 표현 전달은 여러 명령어들의 의미들을 더 복잡한 표현으로 통합한다. 예를 들면,
mov eax,[ebx+0x04]
add eax,[ebx+0x08]
sub [ebx+0x0C],eax
은 표현 전달 이후로 아래와 같은 IR로 바뀔 수 있다.
m[ebx+12] := m[ebx+12] - (m[ebx+4] + m[ebx+8]);
결과를 표현한 것은 더 고급 언어와 닮았으며 기계어 레지스터 eax의 사용을 제거하였다. 분석 이후 ebx 레지스터도 제거될 것이다.
데이터 흐름 분석
레지스터 내용들이 정의되고 사용되는 곳은 데이터 흐름 분석을 통해 추적될 수 있어야 한다. 같은 분석은 임시 변수 그리고 로컬 데이터가 사용하는 위치에도 적용될 수 있다. 그 후 다른 이름은 값 정의 집합과 사용에 연결되어 구성된다. 같은 지역 변수의 위치는 원본 프로그램의 다른 부분의 변수들과 함께 사용될 수 있다. 더 심한 경우는, 실제로 절대 일어나지 않거나 현실에서는 중요하지 않지만, 데이터 흐름 분석 시에 값이 이러한 두 사용 사이에서 흐르는 경로를 인식하는 것이 가능할 수 있다. 좋지 않은 경우, 이것은 타입들의 결합으로서 위치에 대한 정의의 필요성으로 이어질 수 있다. 역컴파일러는 사용자에게 명백히 이러한 비자연스러운 의존성을 깨게 허용함으로써 더 깨끗한 코드로 만들 수 있다. 이것은 물론 변수가 잠재적으로 초기화 없이 사용됐다는 것이고, 원본 프로그램에서 문제가 나타나게 된다.
타입 분석
좋은 기계어 코드 역컴파일러는 타입 분석을 수행한다. 레지스터나 메모리 위치들이 사용되는 방식은 위치의 가능한 타입에 대한 제약으로 귀결된다. 예를 들면, and 명령어는 피연산자가 정수라는 것을 의미한다. 즉, 프로그램은 부동소수점 값이나 포인터에서 동작하는 명령을 사용하지 않는다. add 명령어는 3가지 제약으로 귀결되는데, 피연산자가 정수거나 아닐 수 있기 때문이다. 나머지 하나는 두 피연산자가 다를 경우에 생기는 제한이다.[4]
다양한 고급 표현들은 구조체나 배열들의 인식을 촉발하는 것으로 인식될 수 있다. 그러나 기계어나 C 같은 고급 언어들의 포인터 연산을 허용하는 자유 때문에 많은 가능성을 구별하는 것은 어려운 일이다.
앞의 섹션에서의 예는 다음과 같은 급 언어로 귀결될 수 있다.
struct T1 *ebx;
struct T1 {
int v0004;
int v0008;
int v000C;
};
ebx->v000C -= ebx->v0004 + ebx->v0008;
구조화
역컴파일링의 끝에서 두 번째 단계는 IR을 구조화하여 while 루프와 if/then/else 조건부 선언 같은 고급 구조체로 만드는 것이다. 예를 들면 기계어는 아래와 같다.
xor eax, eax
l0002:
or ebx, ebx
jge l0003
add eax,[ebx]
mov ebx,[ebx+0x4]
jmp l0002
l0003:
mov [0x10040000],eax
이것은 다음과 같이 변환될 수 있다.
eax = 0;
while (ebx < 0) {
eax += ebx->v0000;
ebx = ebx->v0004;
}
v10040000 = eax;
구조화되지 않은 코드를 구조화된 코드로 변환하는 것은 이미 구조화된 코드를 변환하는 것보다 훨씬 어렵다. 해결법으로는 몇몇 코드를 자기복제하거나 불리언 변수들을 추가하는 것이 있다.[5]
코드 생성
마지막 단계는 역컴파일러의 백엔드에서 고급 언어를 생성하는 것이다. 컴파일러가 여러 다른 아키텍처에 따른 여러 다른 기계어를 생성하는 백엔드를 가지듯이 역컴파일러도 여러 고급 언어 별로 생성할 수 있는 백엔드를 갖는다.
코드 생성 바로 직전에 GUI 형태를 사용하여 IR의 상호적인 수정을 허용하는 것이 바람직하다. 이것은 사용자에게 주석을 달거나 포괄적이지 않은 변수와 함수 이름들을 집어넣게 할 수 있다. 그러나 이것들은 역컴파일링 후에 하는 것처럼 쉽게 할 수 있다. 사용자는 구조적인 면을 바꾸고 싶어할 수도 있다(while 루프를 for 루프로 바꾼다든지). 이것들은 간단한 텍스트 에디터로는 쉽게 수정될 수 없다. 비록 소스 코드 리팩토링 도구들이 이 과정에서 도와준다고 하더라도 말이다. 마지막으로 결과 코드를 더욱 읽기 쉽게 하기 위하여, 부정확한 IR은 고쳐지거나 바뀌어야 한다.
합법성
대부분의 컴퓨터 프로그램들은 저작권 법들에 포함된다. 비록 지역마다 어느 정도가 저작권에 포함되는지는 다 다르지만, 일반적으로 개발자에게 프로그램에 대한 배타적인 권한을 준다.[6] 이러한 권리들은 복사본에 대한 권리를 포함한다. (심지어 RAM으로 만들어지는 복사도 포함한다.[7]) 역컴파일 과정이 여러 복사본을 만드는 것과 관련되어 있기 때문에 역컴파일은 허가 없이는 법적으로 금지되어 있다. 그러나 소프트웨어 상호운용성을 달성하는데 이것이 꼭 필요한 단계이므로 저작권 법(미국과 유럽 모두)은 한정된 범위 까지는 허가한다.
같이 보기
각주
- ↑ “Why Decompilation”. Program-transformation.org. 2005년 4월 11일. 2016년 2월 11일에 확인함.
- ↑ Miecznikowski, Jerome; Hendren, Laurie (2002). 〈Decompiling Java Bytecode: Problems, Traps and Pitfalls〉. R Nigel Horspool (편집). 《Compiler Construction: 11th International Conference, proceedings / CC 2002》. Springer-Verlag. 111–127쪽. ISBN 3-540-43369-4.
- ↑ Cifuentes, Cristina; Gough, K. John (July 1995). “Decompilation of Binary Programs”. 《Software Practice and Experience》 25 (7): 811–829. doi:10.1002/spe.4380250706. CiteSeerX: 10.1.1.14.8073.
- ↑ Mycroft, Alan (1999). 〈Type-Based Decompilation〉. S. Doaitse Swierstra (편집). 《Programming languages and systems: 8th European Symposium on Programming Languages and Systems》. Springer-Verlag. 208–223쪽. ISBN 3-540-65699-5.
- ↑ C. Cifuentes.
- ↑ Rowland, Diane (2005). 《Information technology law》 3판. Cavendish. ISBN 1-85941-756-6.
- ↑ http://www.copyright.gov/title17/92chap1.html#106
외부 링크
모듈:Authority_control 159번째 줄에서 Lua 오류: attempt to index field 'wikibase' (a nil value).
- 스크립트 오류가 있는 문서
- 영어 표기를 포함한 문서
- 위키데이터 속성 P18을 사용하는 문서
- 위키데이터 속성 P41을 사용하는 문서
- 위키데이터 속성 P94를 사용하는 문서
- 위키데이터 속성 P117을 사용하는 문서
- 위키데이터 속성 P154를 사용하는 문서
- 위키데이터 속성 P213을 사용하는 문서
- 위키데이터 속성 P227을 사용하는 문서
- 위키데이터 속성 P242를 사용하는 문서
- 위키데이터 속성 P244를 사용하는 문서
- 위키데이터 속성 P245를 사용하는 문서
- 위키데이터 속성 P268을 사용하는 문서
- 위키데이터 속성 P269를 사용하는 문서
- 위키데이터 속성 P271을 사용하는 문서
- 위키데이터 속성 P347을 사용하는 문서
- 위키데이터 속성 P349를 사용하는 문서
- 위키데이터 속성 P350을 사용하는 문서
- 위키데이터 속성 P373을 사용하는 문서
- 위키데이터 속성 P380을 사용하는 문서
- 위키데이터 속성 P396을 사용하는 문서
- 위키데이터 속성 P409를 사용하는 문서
- 위키데이터 속성 P428을 사용하는 문서
- 위키데이터 속성 P434를 사용하는 문서
- 위키데이터 속성 P435를 사용하는 문서
- 위키데이터 속성 P436을 사용하는 문서
- 위키데이터 속성 P454를 사용하는 문서
- 위키데이터 속성 P496을 사용하는 문서
- 위키데이터 속성 P549를 사용하는 문서
- 위키데이터 속성 P650을 사용하는 문서
- 위키데이터 속성 P651을 사용하는 문서
- 위키데이터 속성 P691을 사용하는 문서
- 위키데이터 속성 P716을 사용하는 문서
- 위키데이터 속성 P781을 사용하는 문서
- 위키데이터 속성 P791을 사용하는 문서
- 위키데이터 속성 P864를 사용하는 문서
- 위키데이터 속성 P865를 사용하는 문서
- 위키데이터 속성 P886을 사용하는 문서
- 위키데이터 속성 P902를 사용하는 문서
- 위키데이터 속성 P906을 사용하는 문서
- 위키데이터 속성 P947을 사용하는 문서
- 위키데이터 속성 P950을 사용하는 문서
- 위키데이터 속성 P966을 사용하는 문서
- 위키데이터 속성 P982를 사용하는 문서
- 위키데이터 속성 P1003을 사용하는 문서
- 위키데이터 속성 P1004를 사용하는 문서
- 위키데이터 속성 P1005를 사용하는 문서
- 위키데이터 속성 P1006을 사용하는 문서
- 위키데이터 속성 P1015를 사용하는 문서
- 위키데이터 속성 P1045를 사용하는 문서
- 위키데이터 속성 P1048을 사용하는 문서
- 위키데이터 속성 P1053을 사용하는 문서
- 위키데이터 속성 P1146을 사용하는 문서
- 위키데이터 속성 P1153을 사용하는 문서
- 위키데이터 속성 P1157을 사용하는 문서
- 위키데이터 속성 P1186을 사용하는 문서
- 위키데이터 속성 P1225를 사용하는 문서
- 위키데이터 속성 P1248을 사용하는 문서
- 위키데이터 속성 P1273을 사용하는 문서
- 위키데이터 속성 P1315를 사용하는 문서
- 위키데이터 속성 P1323을 사용하는 문서
- 위키데이터 속성 P1330을 사용하는 문서
- 위키데이터 속성 P1362를 사용하는 문서
- 위키데이터 속성 P1368을 사용하는 문서
- 위키데이터 속성 P1375를 사용하는 문서
- 위키데이터 속성 P1407을 사용하는 문서
- 위키데이터 속성 P1556을 사용하는 문서
- 위키데이터 속성 P1584를 사용하는 문서
- 위키데이터 속성 P1695를 사용하는 문서
- 위키데이터 속성 P1707을 사용하는 문서
- 위키데이터 속성 P1736을 사용하는 문서
- 위키데이터 속성 P1886을 사용하는 문서
- 위키데이터 속성 P1890을 사용하는 문서
- 위키데이터 속성 P1907을 사용하는 문서
- 위키데이터 속성 P1908을 사용하는 문서
- 위키데이터 속성 P1960을 사용하는 문서
- 위키데이터 속성 P1986을 사용하는 문서
- 위키데이터 속성 P2041을 사용하는 문서
- 위키데이터 속성 P2163을 사용하는 문서
- 위키데이터 속성 P2174를 사용하는 문서
- 위키데이터 속성 P2268을 사용하는 문서
- 위키데이터 속성 P2349를 사용하는 문서
- 위키데이터 속성 P2418을 사용하는 문서
- 위키데이터 속성 P2456을 사용하는 문서
- 위키데이터 속성 P2484를 사용하는 문서
- 위키데이터 속성 P2558을 사용하는 문서
- 위키데이터 속성 P2750을 사용하는 문서
- 위키데이터 속성 P2980을 사용하는 문서
- 위키데이터 속성 P3223을 사용하는 문서
- 위키데이터 속성 P3233을 사용하는 문서
- 위키데이터 속성 P3348을 사용하는 문서
- 위키데이터 속성 P3372를 사용하는 문서
- 위키데이터 속성 P3407을 사용하는 문서
- 위키데이터 속성 P3430을 사용하는 문서
- 위키데이터 속성 P3544를 사용하는 문서
- 위키데이터 속성 P3562를 사용하는 문서
- 위키데이터 속성 P3563을 사용하는 문서
- 위키데이터 속성 P3601을 사용하는 문서
- 위키데이터 속성 P3723을 사용하는 문서
- 위키데이터 속성 P3788을 사용하는 문서
- 위키데이터 속성 P3829를 사용하는 문서
- 위키데이터 속성 P3863을 사용하는 문서
- 위키데이터 속성 P3920을 사용하는 문서
- 위키데이터 속성 P3993을 사용하는 문서
- 위키데이터 속성 P4038을 사용하는 문서
- 위키데이터 속성 P4055를 사용하는 문서
- 위키데이터 속성 P4114를 사용하는 문서
- 위키데이터 속성 P4143을 사용하는 문서
- 위키데이터 속성 P4186을 사용하는 문서
- 위키데이터 속성 P4423을 사용하는 문서
- 위키데이터 속성 P4457을 사용하는 문서
- 위키데이터 속성 P4534를 사용하는 문서
- 위키데이터 속성 P4535를 사용하는 문서
- 위키데이터 속성 P4581을 사용하는 문서
- 위키데이터 속성 P4613을 사용하는 문서
- 위키데이터 속성 P4955를 사용하는 문서
- 위키데이터 속성 P5034를 사용하는 문서
- 위키데이터 속성 P5226을 사용하는 문서
- 위키데이터 속성 P5288을 사용하는 문서
- 위키데이터 속성 P5302를 사용하는 문서
- 위키데이터 속성 P5321을 사용하는 문서
- 위키데이터 속성 P5368을 사용하는 문서
- 위키데이터 속성 P5504를 사용하는 문서
- 위키데이터 속성 P5587을 사용하는 문서
- 위키데이터 속성 P5736을 사용하는 문서
- 위키데이터 속성 P5818을 사용하는 문서
- 위키데이터 속성 P6213을 사용하는 문서
- 위키데이터 속성 P6734를 사용하는 문서
- 위키데이터 속성 P6792를 사용하는 문서
- 위키데이터 속성 P6804를 사용하는 문서
- 위키데이터 속성 P6829를 사용하는 문서
- 위키데이터 속성 P7293을 사용하는 문서
- 위키데이터 속성 P7303을 사용하는 문서
- 위키데이터 속성 P7314를 사용하는 문서
- 위키데이터 속성 P7902를 사용하는 문서
- 위키데이터 속성 P8034를 사용하는 문서
- 위키데이터 속성 P8189를 사용하는 문서
- 위키데이터 속성 P8381을 사용하는 문서
- 위키데이터 속성 P8671을 사용하는 문서
- 위키데이터 속성 P8980을 사용하는 문서
- 위키데이터 속성 P9070을 사용하는 문서
- 위키데이터 속성 P9692를 사용하는 문서
- 위키데이터 속성 P9725를 사용하는 문서
- 위키데이터 속성 P9984를 사용하는 문서
- 위키데이터 속성 P10020을 사용하는 문서
- 위키데이터 속성 P10299를 사용하는 문서
- 위키데이터 속성 P10608을 사용하는 문서
- 위키데이터 속성 P10832를 사용하는 문서
- 위키데이터 속성 P11249를 사용하는 문서
- 위키데이터 속성 P11646을 사용하는 문서
- 위키데이터 속성 P11729를 사용하는 문서
- 위키데이터 속성 P12204를 사용하는 문서
- 위키데이터 속성 P12362를 사용하는 문서
- 위키데이터 속성 P12754를 사용하는 문서
- 위키데이터 속성 P13049를 사용하는 문서
- 컴파일러
- 유틸리티 소프트웨어 종류
- 역공학