2008년 07월 20일
How to MFC Reverse Engineering
비도오고 그냥 즉흥적으로 쓴글이므로 양해를 바랍니다...
물론 오덕후급의 리버서들에게는 이미 100년전에 알고 있거나 지루한 애기입니다.
그냥 그런 애기 입니다.
MFC 프로그램에 대한 리버싱
mfc 를 리버싱 하기란 어떻게 보면 간단하면서 어려운 것이다.
일단 왜냐면 첫째로 mfc함수가 wrapper함수 라는 것이다.
API와는 다른것이다. API경우 특정 함수 콜부분에 콜을 하거나..(절차지향적 프로그래밍 기법을 말한다)
물론 윈도우프로그래밍은 항상 메시지에 의존한 프로그래밍 기법을 이용하여서
절자지향적인 리버스와는 그 본질 부터가 다르다.
하지만 정확한 지점의 부분 가령 사용자로 부터 어떤 요청이 이루어지면
그요청이 이루어지는 부분은 한 부분씩 이루어 진다. 하지만 이 한부분을 찾기가 애매하다.
기본적으로 디버거로 mfc류의 프로그램을 열면 대체로 pdb(심볼을 의미)를 이용하여 기본적인 함수 오버라이드에 대한
함수 이름을 출력해준다. 하지만 프로그래머가 기존의 오버라이드 함수를 쓰는 경우도 있지만
대부분 새롭게 정의한 클래스에서 오버라이드를 한다 .이는 디버거가 제대로 함수 네임을 들고 오지 못한다.
여기서 간단한 센스로 리버싱을 진행해야한다.
가령 지금 생각나는 간단한 프로그램을 생각해보자
프로그램에서 어떤 트레이의 메뉴중 사용자 정보를 클릭했다고 가정해보자.
그리고 그 보여주는 부분에는 사용자의 정보라던지가 출력된다.여기서 리버서는
간단히 출력되는 부분을 바꿔보고 싶다고 생각해보자.
먼저 어떤 함수를 breakpoint를 걸며 추적을 할것인가이다..
물론 메뉴에서 클릭을 한 행위는 윈도우에서 OnCommand라는 함수로써 오버라이드 함으로써 제공 되고있다.
하지만 수많은 클래스중 특히 프로그래머가 정의해놓은 클래스의 OnCommand의 이벤트를 찾기란 불가능하다
여기서 한가지 팁이 있다. C++의 상속성의 특징을 이용하는 것이다.
즉 여기서 팝업되는 화면의 기능은 CWnd(윈도우에 관련된 기능) 등을 정의한 클래스인데 주로 여기서의 함수를
오버라이딩을 하여 프로그래머의 자신의 클래스에서 함수를 오버라이딩해서 땡겨 쓴다.
그렇다면 결국 프로그래머가 정의한 함수를 찾지 못하더라도 디어셈블러에서 보여주는 CWnd의 OnCommand의 함수를
먼저 호출한다는 애기이고 이 말 즉슨 CWnd OnCommand의 함수 호출은 프로그래머가 오버라이딩한 함수를 호출한다는
애기가 된다.
기본적으로 mfc가 정의하는 클래스들은 이렇다.(상속순으로 나열...)
CObject //거의 모든 MFC 클래스의 기반 클래스
CCmdType //이벤트를 받는 기능
CWinAPP //프로그램을 구동시키는 기능
CDocument // 데이터를 저장하고 처리하는 기능
CWnd //윈도우에 관련된 기능(눈에 보이는 오브젝트)
CFrameWnd //윈도우 프레임(외곽)을 관리하는 기능
CView //데이터를 보여주는 기능
물론 OnCommand를 브레이크 포인트 걸어봤자 결국에는 윈도우 함수들이 주루륵 호출 될것이다 이것은 역시 C++의
특징이다. 즉 그 이벤트에 대한 처리루틴들만이 우리는 trace하게 될것이다. 이것은 우리가 의도한 바는 아니다.
결국 거기서 데이터를 조작하건 사용자의 컨트롤을 제한하던 그 특정 처리를 위한 호출을 찾아야 한다.
그건 결국 경험에 의해서 이루어 지는데 다음과 같은 프로그램이 있다고 보자.
화면에서 보듯이 특정 기준점에 의해서 edit박스의 컨트롤을 활성화 하거나 비활성하는 기능이다.
우린 그쪽 위치에서 trace를 하기를 원한다.

위의 그림에서 기혼을 체크하면 밑의 배우자 정보의 오브젝트들이 활성화 되며 해제하면 비활성화 된다.

위의 그림에서 어떤 함수를 브레이크를 걸지를 알 수 있겠는가?

void CProfileDlg::OnCheck1()
{
// TODO: Add your control notification handler code here
UpdateData(TRUE); //UpdateData 의 인자값을 TRUE로 주면 사용자 컨트롤로 값이 멤버변수로
//UpdateData 의 인자값을 FALSE로 주면 Value형 멤버 변수에 설정 되어 있는 값이 컨트롤 전송
m_ctrName.EnableWindow(m_bMarried);
m_ctrlAge.EnableWindow(m_bMarried);
}
위의 코드는 디어셈블에서 찾기는 사막에서 바늘정도의 수준입니다.(조금 덩치큰 프로그램에서 혹은 그렇지 않더라도
mfc가 기본적으로 함수를 정의하는 코드를 비교 해봤을때..)
물론 엄청난 시력의 눈을 가진 리버서에게는 소용 없는 일인가요 ? :(
이는 어떻게 보면 CWnd함수중 어떤 기능을(함수)를 쓰는가에 초점을 맞춰진다.물론 정통한 C++프로그래머는
분명 바로 눈치를 채게된다. EnableWindow함수를 썻다는 것에 대하여...물론 다른 함수들도 있을수 도 있다
하지만 이부분은 분명 리버서의 재량이거나 혹은 경험에 의해서 컨트롤 되어짐을 명심해야한다.
이 함수주소를 찾아서 breakpoint를 걸게 된다면 우린 우리가 원하는 루틴속에 빨려 들어갈수 있다.
PS.좀더 Row한 흐름속에 명백히 그것을 찾을려면 API를 줄줄 익히고 있으면 된다.
혹은 윈도우의 콜체인을 안다면 그것은 더이상 문제거리가 되지 않는다. mfc의 수많은 콜 처리 중에
결국 호출되는 함수는 같은것이니깐...하지만 이것은 별로인걸라 생각이 든다.
다만 하나의 진실을 보는 방법은 수만가지일 뿐이라고 생각하네요.


Sysenter를 이용하여 커널과 통신을 하게 됩니다..
이상 비오는날 잡설이였습니다....~_~(글의내용은 다소 두서가 없지만 c++에 관한 디어셈 코드 복원 시도중이라 할까요 -_-)
좀더 다른 방법이나 괜찬은 방법있으시면 저한테 가르침을 주소서~
# by | 2008/07/20 16:43 | Reverse | 트랙백 | 핑백(1) | 덧글(2)





☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
... tp://binoopang.tistory.com Hong10 - http://hongten.egloos.com/1882971 ... more