8월호에 기고한 "실행 파일 속으로"란 기사의 필자 메모와 도입부 부분이 수정되기 전 내용으로 그대로 나갔더군요. 뭐 수정된 것과 전과 별 차이는 없지만 수정한게 아쉬워서 수정한 내용을 올려 봅니다. 그리고 소 제목 중 IAT라고 된 부분은 "임포트 정보"입니다. 수정 원고가 너무 늦게 보내서 이런 일이 발생한 것 같습니다.
필자 메모
얼마 전 모 방송사의 게임리그의 결승전이 있었다. 5전 3선승제의 결승전은 접전을 거듭하며 5경기까지 갔고, 5경기도 매우 오랜 시간 싸움 끝에 결말이 났다. 게임을 끝내고 나온 두 선수는 각각 인터뷰를 했고, 패전 선수의 인터뷰 첫 마디는 if였다. 자신이 큰 실수를 하지 않았으면 이길 수 있었다는 요지의 말이었다. 필자가 응원했던 선수라 실망감이 더 클 수 밖에 없었다.
A라는 사건의 결과가 잘못됐을 때 우리가 그 결과에 접근하는 시각은 크게 변명과 반성으로 압축된다. 변명은 결과 이전의 과거 상태에 집착하는 것이고, 반성은 결과 이후의 미래에 대해서 생각하는 것이다. “시간은 과거에서 미래로 흐르고, 지나간 시간은 절대로 다시 돌아오지 않는다.”라는 지극히 평범한 상식에 비추어 보아도 변명보다는 반성이 훨씬 더 생산적인 접근 방법이라는 것을 알 수 있다. 이와 관련해서 이외수님 플레이톡(http://playtalk.net/oisoo)에 재미있는 글이 있어서 소개해 본다.
다른 나라와의 축구경기에서 우리 선수들이 부진한 모습을 보이면 해설자들이 그라운드 상태가 엉망이기 때문이라는 둥, 비가 와서 잔디가 미끄럽기 때문이라는 둥 하는 따위의 변명을 상투적으로 늘어 놓는다. 아놔, 상대편 선수들은 명왕성에 가서 따로 경기하고 있냐, 그리고 비는 우리 선수들만 쫓아 다니면서 쏟아지고 있냐. 변명을 많이 할수록 발전은 느려지고 반성을 많이 할수록 발전은 빨라진다. 이것은 개인에게도 적용되는 일종의 법칙이다.
도입부
Windows 프로그램을 만들다 보면 누구나 한번쯤은 실행 파일에 관련된 궁금증을 가진다. 운영 체제는 어떻게 프로그램을 실행하는 것일까? 실행 파일에 사용된 DLL들은 어떻게 로드되는 것일 까? DLL의 함수는 어떤 방식으로 호출되는 것일까? 리버싱에 관심이 있는 독자라면 다음과 같은 궁금증을 가져본 적도 있을 것이다. 패커나 언패커는 어떤 식으로 동작하는 것일까? 바이러스는 어떻게 실행 파일을 감염 시키는 것일까? 다른 실행 파일에 임의의 코드를 추가할 순 없을까? 조금 거리가 있지만 이런 것들을 궁금해 하시는 분들도 있다. 자동 풀림 압축 파일은 어떻게 만드는 것일까? 이미지 파일을 입력하면 그것을 보여주는 실행 파일을 생성해내는 프로그램의 원리는 무엇일까?
이 모든 궁금증, 이 모든 질문에 대한 해답은 PE 포맷에 있다. PE는 Portable Executable의 약자로 Windows 운영체제에서 사용하는 표준 실행 파일 포맷이다. 이 포맷은 Windows 95에서 Windows Server 2003까지, 32비트에서 64비트에 이르기까지 전 Windows 운영체제에서 공통적으로 사용된다.
Windows 95때부터 사용된 파일 포맷인 만큼 이 포맷을 분석한 자료는 정말 많다. 구글에서 “PE format”이란 키워드로 검색해 보면 얼마나 많은지 알 수 있다. 대표적인 것으로 참고 자료에 있는 Matt Pietrek의 “Peering Inside the PE: A Tour of the Win32 Portable Executable File Format“와, 이호동님의 “Windows 시스템 실행 파일의 구조와 원리”가 있다. 바이블과 같은 자료이기 때문에 보다 깊이 있는 이해를 하고 싶다면 반드시 읽어 보도록 하자.
우리는 PE 포맷에 대해서 간단하게 분석하고 앞서 열거한 질문에 대한 해답을 하나씩 찾아 볼 것이다. 이번 시간은 그 시작으로 PE 포맷의 개략적인 구조와 임포트, 익스포트 테이블에 관해 다룬다. 이 글을 통해서 실행 파일에서 어떻게 다른 DLL의 함수를 참조하는지, DLL에서는 어떻게 자신의 함수를 외부로 노출시키는지에 대해서 배울 수 있다.