C++ 클래스와 디스어셈블링
[실전강의실|Reverse Engineering의 정석]
C++ 클래스와 디스어셈블링
월간 마이크로소프트웨어 2008년 5월호
지난회는 C 코드가 어셈블리 코드로 변환되었을 때를 살펴보았다. 이번회는 C++ 문법과 클래스는 디스어셈블링을 할 때 어떤 식으로 해석할 수 있는지 알아본다. call, 조건문은 점프 구문 등으로 어느 정도 직관적인 예측을 할 수 있었던 C 문법에 비하여 C++는 멤버 함수, private 함수, 생성자, 소멸자, 상속 등 분석이 어려운 다양한 개념이 많은 편이다. 리버스 엔지니어링을 할 때 이러한 내용들은 어떻게 확인할 수 있는지 확인해 보자.
------------------------------------------------------
강병탁 window31@empal.com, http://www.window31.com | 바이너리 취약점 분석 업무를 하고 있다. 안티 크래킹/안티 디버깅 엔진 개발을 다년간 해왔으며 시스템 프로그래밍과 리버스 엔지니어링에 관심이 많다. 악성 코드나 해킹툴이 내부에 담고 있는 천재적인 알고리즘에 감탄하며 오늘도 IDA를 돌린다.
------------------------------------------------------
------------------------------------------------------
연재 순서
1회 | 2008. 4 | C 문법과 디스어셈블링
2회 | 2008. 5 | C++ 클래스와 디스어셈블링
3회 | 2008. 6 | DLL, MFC 실전 모듈 리버싱
4회 | 2008. 7 | 4GL 고급 언어 역분석
5회 | 2008. 8 | 안티 디버깅과 리버스 엔지니어링
------------------------------------------------------
연재 가이드
운영체제| 윈도우 2K/XP/2003
사용도구| Visual Studio, IDA, WinDBG
기초지식| C, ASM, Win32 API
응용분야| 리버스 엔지니어링/시스템 프로그래밍/해킹/보안
------------------------------------------------------
C++ 분석의 난해함
객체 지향 프로그래밍은 바이너리 코드로 바뀌었을 때 어떻게 접근해야 할까? 사실 C 코드의 경우는 함수, 조건문, 반복문 이라는 일정한 규칙이 있고, 이것은 어셈블리에서 CALL문, Jmp문 등으로 쉽게 대입이 된다. 하지만 C++로 넘어오게 되면 클래스가 등장하고, 멤버 변수와 멤버 함수가 필요하게 되며, 캡슐화나 상속 등의 개념까지도 요구된다. 이러한 것들이 개발자 입장에서는 좀더 쉽고 간편한 코딩을 위해 이러한 기반이 마련된 것이지만, 리버스 엔지니어링 할 때의 입장은 전혀 다르다. 현재 보고 있는 함수가 그냥 함수인지 특정 클래스의 멤버 함수인지, 그리고 이 변수는 전역 변수인지 생성자는 어떤 식으로 구성되어 있는지 등 파악하기 어려운 부분이 많기 때문이다. 즉 구조적 뼈대가 C++과 어셈은 1:1로 매칭되지 않으므로 직관적인 파악이 쉽지 않은 편이라는 것이다.
클래스 뼈대
C++ 바이너리를 디스어셈블링 했을 때 해당 어셈 코드는 이것이 멤버 변수이며 저것은 클래스 선언부라고 친절하게 가르쳐 주지는 않는다. 메모리 사용량과 함수의 구조적인 부분을 살펴보면서 클래스라는 것을 리버서 스스로 판단해야만 한다. 물론 그것은 절대로 쉬운 작업이 아니다. C 코드 때처럼 눈에 확 들어오는 정형화된 모습이 없기 때문이다. 또 오히려 어떤 부분은 클래스 멤버 함수인지 그냥 함수인지 상당히 파악하기 힘든 경우도 있다. 하지만 분석가의 풍부한 코딩 경험과 디스어셈블링 상에서의 "감"을 익힌다면, 현재 코드는 클래스의 어떤 부분이며 어느 역할을 하고 있다는 것 정도는 파악할 수 있다. <리스트 1> 을 보자.
http://www.imaso.co,kr
