c / c + + 함수 깊이 탐색 (3) - 허 멤버 함수 호출 의 기본 과정

http://blog.csdn.net/demon__hunter/article/details/5447111
c + + 를 배 운 적 이 있 으 면 한동안 알 수 있 습 니 다. c + + 는 가상 함수 에 의 해 다 형 을 실현 합 니 다. 다음 코드 는 다음 과 같 습 니 다.
#include <iostream>
using namespace  std;
class Base
{
public:
	virtual void Print()
	{
		cout<<"^-^"<<endl;
	}
};
class Derive:public Base
{
public:
	virtual void Print()
	{
		cout<<"T-T"<<endl;
	}
};
int main()
{
	Base *p=new Derive();
	p->Print();
}

하하, T - T 출력 ~ ~ ~ ~ ~
가상 함수 의 실현 원 리 를 이해 하 는 데 있어 서 c + 초보 자가 중수 에 가 는 데 필수 적 인 길 중 하나 이다. 그 실현 원리 에 대해 개인 적 으로 라 는 책 을 추천 합 니 다.
원 리 는 매우 투철 하 게 말한다.현재 주류 컴 파일 러 의 구체 적 인 실현 방식 을 분석 하고 어 셈 블 리 의 측면 에서 컴 파일 러 의 가상 함수 의 실현 원 리 를 분석 합 니 다 (최근 c / c + 작업 을 찾 으 면 가상 함수 가 가능성 이 높 을 것 으로 예상 합 니 다 ~).
먼저 c + + 표준 은 가상 함수 의 행위 만 규정 하고 이러한 행위 의 구체 적 인 실현 을 규정 하지 않 았 으 나 현재 주류 의 컴 파일 러 (vc, g +) 는 실현 에 있어 어느 정도 호흡 을 이 루 었 다. 모두 대상 앞의 4 바이트 에 가상 시계 지침 을 삽입 하 는 것 이다.
이 가상 시계 바늘 은 대응 하 는 클래스 의 가상 시 계 를 가리 키 며, 가상 함 수 를 호출 할 때 가상 시계 바늘 을 통 해 가상 시 계 를 찾 아 최종 적 으로 호출 할 함 수 를 얻 는 것 이다. 이것 이 바로 동적 으로 연 결 된 바 텀 실현 방식 이다.
다음은 vc 10 기본 컴 파일 옵션 debug 아래 위의 프로그램의 어 셈 블 리 입 니 다.
   257: int main()  
   258: {  
01031500  push        ebp    
01031501  mov         ebp,esp    
01031503  sub         esp,0DCh    
01031509  push        ebx    
0103150A  push        esi    
0103150B  push        edi    
0103150C  lea         edi,[ebp-0DCh]    
01031512  mov         ecx,37h    
01031517  mov         eax,0CCCCCCCCh    
0103151C  rep stos    dword ptr es:[edi];     (/RTCs) ,        ,    
                                             ;             cc,  int 3    
                                             ;           int   ,   -858993460  
                                        ;         ,-858993460    0xcccccccc  
                                        ;              ,     debug ,  
                                             ;               。  
  
  
   259:     Base *p=new Derive();  
0103151E  push        4   ;operator new      ,   Derive           。  
01031520  call        operator new (1031208h) ;  operator new    
01031525  add         esp,4 ;__cdecl    ,     ,    ,   
01031528  mov         dword ptr [ebp-0D4h],eax; operator new         dword ptr[ebp-0D4h]  
                                              ;    ,operator new        ,        
                                                    ;    ,vc                   eax  
0103152E  cmp         dword ptr [ebp-0D4h],0  ;        0  
01031535  je          main+4Ah (103154Ah)  ; 0     
01031537  mov         ecx,dword ptr [ebp-0D4h]; operator new          ecx,vc       
                                                   ;   this    ecx 。   
0103153D  call        Derive::Derive (1031127h) ;      ,                ,  
                                                ;              ,               
01031542  mov         dword ptr [ebp-0DCh],eax  ;             ,               
                                                      ;    eax,             。        
                                                      ;              
01031548  jmp         main+54h (1031554h)       ;          。  
0103154A  mov         dword ptr [ebp-0DCh],0;          je main+4Ah (103154Ah)      
                                            ;     ,        ,          p   0,  
                                            ;   this   0,   this+             。  
01031554  mov         eax,dword ptr [ebp-0DCh] ;            ,  dword ptr [ebp-0DCh]  
                                               ;          。   
0103155A  mov         dword ptr [p],eax   ;         dword ptr [p]    ,         
                                                ;                  ,        
   260:     p->Print();  
0103155D  mov         eax,dword ptr [p]  ;         eax,  eax=p(p         )  
01031560  mov         edx,dword ptr [eax] ;  eax  ,       eax                
                                               ;  , 4   ,  4                 edx  
                                          ;   edx=*(int*)p,        4             
                                               ;    ,               。   
01031562  mov         esi,esp    
01031564  mov         ecx,dword ptr [p]  ;this    ecx  
01031567  mov         eax,dword ptr [edx];       ,        , edx       ,    
                                              ;    4      ,          ,    edx    
                                              ;        ,          ,          
                                              ;0x00100000,  0x00100000~0x00100003            
                                              ;  ,0x00100004~0x00100007            .....  
                                         ;                 ,eax=*(int*)*(int*)p  
                                         ;  eax                 
01031569  call        eax                ;        
0103156B  cmp         esi,esp    
0103156D  call        @ILT+435(__RTC_CheckEsp) (10311B8h)    
   261: }  
01031572  xor         eax,eax    
01031574  pop         edi    
01031575  pop         esi    
01031576  pop         ebx    
01031577  add         esp,0DCh    
0103157D  cmp         ebp,esp    
0103157F  call        @ILT+435(__RTC_CheckEsp) (10311B8h)    
01031584  mov         esp,ebp    
01031586  pop         ebp    
01031587  ret    

상기 분석 을 통 해 * (int *) * (int *) p 와 같은 표현 식 으로 가상 표 의 함수 방법 을 얻 을 수 있 습 니 다. 이 곳 은 포인터 응용 을 고찰 하 는 기본 적 인 기능 입 니 다.
void(*f)()=(void(*)())*(int*)*(int*)p;
f();
최종 호출 은 Derive:: Print () 입 니 다.분명히 * (int *) (* (int *) p + 4) 는 가상 표 의 두 번 째 함수 주소 값 입 니 다. 있 으 면 ~ ~ ~ ~ ~
컴 파일 러 가 만 든 구조 함수 에서 무엇 을 했 는 지 살 펴 보 자.
Derive::Derive: 01031127  jmp         Derive::Derive (10315B0h)
메모리 10315 B0h 에 있 는 어 셈 블 리 명령 을 찾 습 니 다:
Derive::Derive:  
010315B0  push        ebp    
010315B1  mov         ebp,esp    
010315B3  sub         esp,0CCh    
010315B9  push        ebx    
010315BA  push        esi    
010315BB  push        edi    
010315BC  push        ecx    
010315BD  lea         edi,[ebp-0CCh]    
010315C3  mov         ecx,33h    
010315C8  mov         eax,0CCCCCCCCh    
010315CD  rep stos    dword ptr es:[edi]    
010315CF  pop         ecx    
010315D0  mov         dword ptr [ebp-8],ecx; ecx    this     dword ptr [ebp-8]  
010315D3  mov         ecx,dword ptr [this] ;this    ecx,       ,      
                                                ;dword ptr [this] dword ptr [ebp-8]      
010315D6  call        Base::Base (1031131h);            
010315DB  mov         eax,dword ptr [this] ;dword ptr [this]       Base::Base   
                                           ;      ,                
010315DE  mov         dword ptr [eax],offset Derive::`vftable' (1037834h)   
                                           ; dword ptr [this]              
                                                ; Derive::`vftable' ,dword ptr [this]     
                                                ;      ,   p,       *(int*)p=  
                                           ;Derive::`vftable' .  
010315E4  mov         eax,dword ptr [this] ;            eax,           
010315E7  pop         edi    
010315E8  pop         esi    
010315E9  pop         ebx    
010315EA  add         esp,0CCh    
010315F0  cmp         ebp,esp    
010315F2  call        @ILT+435(__RTC_CheckEsp) (10311B8h)    
010315F7  mov         esp,ebp    
010315F9  pop         ebp    
010315FA  ret    

베이스 보기:: 베이스 (1031131 h);어 셈 블 리 코드
Base::Base:  
01031690  push        ebp    
01031691  mov         ebp,esp    
01031693  sub         esp,0CCh    
01031699  push        ebx    
0103169A  push        esi    
0103169B  push        edi    
0103169C  push        ecx    
0103169D  lea         edi,[ebp-0CCh]    
010316A3  mov         ecx,33h    
010316A8  mov         eax,0CCCCCCCCh    
010316AD  rep stos    dword ptr es:[edi]    
010316AF  pop         ecx    
010316B0  mov         dword ptr [ebp-8],ecx    
010316B3  mov         eax,dword ptr [this]    
010316B6  mov         dword ptr [eax],offset Base::`vftable' (1037844h)    
010316BC  mov         eax,dword ptr [this] ; Derive  ,               
010316BF  pop         edi    
010316C0  pop         esi    
010316C1  pop         ebx    
010316C2  mov         esp,ebp    
010316C4  pop         ebp    
010316C5  ret    

여기까지 분석 하면 여러분 들 이 가상 함수 호출 에 대해 기본 적 인 인식 을 가지 고 있다 고 믿 습 니 다. 컴 파일 러 는 가상 함 수 를 실현 할 때 주로 다음 과 같은 절차 가 있 습 니 다.
1. 컴 파일 할 때 클래스 의 성명 에 따라 가상 함수 표를 생 성 합 니 다.
2. 대상 을 만 들 때 컴 파일 러 는 클래스 의 구조 함수 에 일부 코드 를 삽입 하여 대상 의 가상 포인터 를 초기 화 합 니 다. 보통 (vc g +) 구조 함수 에 들 어 갑 니 다.
  시작 부분 에 코드 를 삽입 합 니 다.
3. 포인터 나 인용 으로 가상 함 수 를 호출 할 때 동적 바 인 딩 을 활성화 합 니 다. 실질 적 으로 가상 포인터 로 함 수 를 찾 는 과정 입 니 다.
 그래서 이와 같은 코드 Derive () {memset (this, 0, sizeof (Derive);} 은 재난 적 입 니 다 ~ ~ ~
가상 함수 의 실현 은 구조 함 수 를 빌려 야 하기 때문에 구조 함 수 는 가상 함수 가 될 수 없습니다 ~ ~ ~
 
마지막 으로 c + + 가상 함수 에 관 한 hack 의 간단 한 프로그램 두 개 를 소개 하여 번역기 에 대한 가상 함수 체제 에 대한 이 해 를 강화 합 니 다 ~ ~ ~
#include <iostream>  
#include <vector>  
using namespace  std;  
  
class Base  
{  
public:  
    virtual void PrintA()  
    {  
        cout<<"^-^"<<endl;  
    }  
    virtual void PrintB()  
    {  
        cout<<"T-T"<<endl;  
    }  
  
};  
class Derive:public Base  
{  
public:  
    virtual void PrintA()  
    {  
        cout<<":)"<<endl;  
    }  
    virtual void PrintB()  
    {  
        cout<<":("<<endl;  
    }  
};  
void Hack1()  
{  
    cout<<"Hack1"<<endl;  
}  
void Hack2()  
{  
    cout<<"Hack2"<<endl;  
}  
int main()  
{  
    Base *p=new Derive();  
    int *pVtable[2]={(int*)Hack1,(int*)Hack2};//        
    *(int*)p=(int)pVtable;//        
    p->PrintA();  
         p->PrintB();  
    system("pause");  
}  

허 표 지침 을 수정 하여 납치 절 차 를 진행 하 는 것 이 분명 합 니 다. 다음은 허 표를 수정 하여 납치 절 차 를 진행 하 겠 습 니 다 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
#include <iostream>  
#include <Windows.h>  
using namespace  std;  
  
class Base  
{  
public:  
    virtual void PrintA()  
    {  
        cout<<"^-^"<<endl;  
    }  
    virtual void PrintB()  
    {  
        cout<<"T-T"<<endl;  
    }  
  
};  
class Derive:public Base  
{  
public:  
    virtual void PrintA()  
    {  
        cout<<":)"<<endl;  
    }  
    virtual void PrintB()  
    {  
        cout<<":("<<endl;  
    }  
};  
void Hack1()  
{  
    cout<<"Hack1"<<endl;  
}  
int main()  
{  
    Base *p=new Derive();  
    int PrintAAdress=*(int*)*(int*)p;//  PrintA          
    int PrintBAdress=*(int*)(*(int*)p+4);//  PrintB          
    //vc debug                 ,     jmp    
    //      0xe9  
    if (*(unsigned char*)PrintAAdress==0xe9)  
    {  
        DWORD d;  
        int PrintBOffset=*(int*)(PrintBAdress+1);//  jmp          
        int Hack1Offset=*(int*)((int)Hack1+1);  
        //jmp           jmp     ,       PrintA     
        //  PrintB,          
        int diff=PrintBOffset-(PrintAAdress-PrintBAdress);  
        WriteProcessMemory(GetCurrentProcess(),(int*)(PrintAAdress+1), &diff, 4, &d);  
  
        diff=Hack1Offset-(PrintBAdress-(int)Hack1);  
        WriteProcessMemory(GetCurrentProcess(),(int*)(PrintBAdress+1), &diff, 4, &d);  
    //release                            
    }else{   
        DWORD dwIdOld;  
        HANDLE hProcess=OpenProcess(PROCESS_ALL_ACCESS,1,GetCurrentProcessId());   
        //              ,debug      ,          
        VirtualProtectEx(hProcess,(int*)*(int*)p,4,PAGE_READWRITE,&dwIdOld);  
        WriteProcessMemory(hProcess,(int*)*(int*)p, &PrintBAdress, 4, 0);  
        VirtualProtectEx(hProcess,(int*)*(int*)p,4,dwIdOld,&dwIdOld);  
  
        int Hack1Adress= (int)Hack1;  
        VirtualProtectEx(hProcess,(int*)(*(int*)p+4),4,PAGE_READWRITE,&dwIdOld);  
        WriteProcessMemory(hProcess,(int*)(*(int*)p+4), &Hack1Adress, 4, 0);  
        VirtualProtectEx(hProcess,(int*)(*(int*)p+4),4,dwIdOld,&dwIdOld);  
    }  
    //         ,  Derive      ,    PrintB Hack1   
    p->PrintA();  
    p->PrintB();  
  
}  

위의 프로그램 은 컴 파일 러 가 만 든 가상 표를 성공 적 으로 수정 한 것 입 니 다. 실제 hack 라 고 할 수 있 습 니 다 ~ ~, 위의 프로그램 vc9 / 10 + win 7 debug / release 기본 컴 파일 옵션 통과 ~ ~ ~ ~
만약 에 상기 두 프로그램 을 알 게 된다 면 가상 표 의 컴 파일 러 에 대한 인식 이 더욱 깊 어 질 것 이 라 고 믿 습 니 다 ~ ~ ~
원 리 는 바로 이 모양 입 니 다. 다 중 계승 상황 에서 좀 번 거 로 울 수 있 습 니 다. 대상 이 여러 개의 가상 포인터 가 생 길 수 있 기 때 문 입 니 다. 또한 가상 분석 함수 가 가상 표 에서 구 조 를 하고 각 컴 파일 러 의 차이 도 비교적 큽 니 다.
그 러 니까 왜 come 이 실 현 될 때 release 와 비슷 한 인터페이스 가 있어 야 하 는 지 ~ ~ ~
 
 
 
자, 여기까지 쓰 세 요. 시간 나 면 보충 할 게 요 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~

좋은 웹페이지 즐겨찾기