Be myself :: C++에서 VTable

달력

42024  이전 다음

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

C++에서 VTable

Exploit 2014. 7. 12. 00:29

1 c++ 가상함수

IE취약점을 분석하다(use after free) vtable에 관한 지식이 없어 찾다 보니, C++에서의 가상함수 개념과 비슷하여 알아볼 필요가 있을 것 같았다. 따라서 C++은 어떻게 어셈블리로 표현되는지 간단한 코드를 통해 알아 보겠다. 본 포스팅은 <리버스 엔지니어링 바이블>이라는 책의 예제를 사용하였다.

가상함수란, 상속된 객체의 함수가 있으면서 없는듯하게 행동하는 함수이다. 다시 말하면 A를 상속하는 B라는 클래스가 있고, 똑 같은 test()함수를 가지고 있다. 이 때, A클래스에서 test()함수가 가상함수로 선언되어 있다면, A객체포인터로 B객체를 가리키고 있고, test()함수를 호출한다면 원래 A의 test함수가 호출되어야 하지만, 가상함수로 선언되어 있어 B의 test함수가 호출되는 원리이다. 말로 하면 끝도 없이 어려우니 관련 문서나 책을 참고하기 바란다.

또 클래스에서 함수에 대해 더 설명하자면, 멤버 변수는 객체 내에 존재하지만 멤버 함수는 메모리의 한 공간에 존재하면서 모든 객체가 공유하는 형태이다.

컴파일러는 가상함수를 포함하는 클래스에 대해서, 가상함수 테이블(VTable)을 만들어 준다. 따라서 하나 이상의 가상 함수를 멤버로 지니는 클래서의 객체에는 VTable을 위한 포인터가 멤버로 추가된다.

이건 추측인데 다음과 같은 결론을 내렸다.(아는 사람이 있으면 좀 알려주시길 ㅠㅠ) 아래와 같은 코드가 있다고 해보자.

#include<iostream>
using std::endl;
using std::cout;

class
A
{
public:
    int a;
    int b;
    virtual void fct1(){ cout<<"fct1..."<<endl; }
    virtual void fct2(){ cout<<"fct2..."<<endl; }
};

class
B : public A
{
    int c;
    int d;
public:
    virtual void fct1(){ cout<<"fct1 over..."<<endl; }
    void fct3(){ cout<<"fct3..."<<endl; }
};

int
main()
{
    A* aaa = new B();
    aaa ->fct1();
 
    B* bbb = new B();
    bbb ->fct1();
    return 0;
}

이 때, A* aaa = new B(); 부분의 의미는 곧 A객체를 만들고, VTable에서 겹치는 함수 부분만(오버라이딩 된 부분) VTable에 함수 주소값을 넣어라. 라는 뜻인 것 같다.

 

2 c++ 코드 분석

직접 어셈블리어로 분석 해 보자.

기본 코드는 다음과 같다.

#include "windows.h"										

#include "stdio.h" #include "tchar.h" class Employee {     public :         int number;         char name[128];         long pay;         void ShowData();         void Test(); }; void Employee::ShowData() {    printf("number: %d\n", number);    printf("name: %s\n", name);    printf("pay: %d\n", pay);      Test();    return; }   void Employee::Test() {     printf("Test fuction\n");     return; }   //Employee kang; int main(int argc, char* argv[]) {     Employee kang;     printf("size: %X\n", sizeof(Employee));          kang.number = 0x1111;     _tcscpy(kang.name, _T("강병탁"));     kang.pay =0x100;     kang.ShowData();     return 0; }

아래는 위 코드를 컴파일 하고 IDA로 열어본 화면이다.

여기서 ecx가 클래스 멤버의 제일 첫 주소를 나타내고, 이 주소 값을 기준으로 클래스 멤버에 접근한다. Main 부분을 확인해 보면 확실해 진다.

결론은 Ebp-88부분부터 ebp-4까지 Employee클래스의 멤버 변수들의 공간이었다. 그리고 이 멤버 변수에 접근을 ecx(C++에서의 this포인터)가 담당하였다.

이제 가상함수가 선언된 클래스를 분석해 보자. VTable은 생성자가 실행될 때, 설정된다.

따라서 그림상으로 나타내면 다음과 같다.

'Exploit' 카테고리의 다른 글

유니코드 익스플로잇  (0) 2014.07.21
SEH overwrite 실습  (0) 2014.07.16
여러 보호기법  (0) 2014.07.11
SEH overwriting  (0) 2014.07.10
윈도우 BOF  (2) 2014.05.28
Posted by flack3r
|