Programming - cpueblo.com

함수 포인터와 EIP


글쓴이 : 스네이… 날짜 : 2004-08-19 (목) 23:58 조회 : 8764

/*
        제목: 함수를 바이트 배열(OPCODE)로 관리하자..!!
        작성자: 박성완
        작성일: 2004.08.16
        목적:   1) 재미있을 거 같아서..
                2) 사고의 전환을 가져오기 위해서..
                3) 인라인 어셈블리를 사용하고 싶어서..
                4) 이를 이용해 암호화 패키지를 만들고 싶어서..
                5) 함수를 파일(OPCODE)로 관리하고 싶어서.

      * 방법 *
      -함수에 브레이크 포인트를 건다.
      -ALT+8을 눌러 어셈블리 모드로 진입한다.
      -코드의 어셈블리 코드를 참고한다.
      -코드의 스택내용을 참고한다.
      -어드레싱에 민감하게 주의를 기울인다.
      -메모리 보기로 함수시작 주소로 간 후, 함수 크기만큼 복사한다.
       (함수크기는 ret까지 이므로 VC++에서 알 수 있다.)

*/
#include 
#include 

//-----------------------------------------------------------------------------------------------
//
/*
    00401030   push        ebp
    00401031   mov         ebp,esp
    00401033   sub         esp,40h
    00401036   push        ebx
    00401037   push        esi
    00401038   push        edi
    00401039   lea         edi,[ebp-40h]
    0040103C   mov         ecx,10h
    00401041   mov         eax,0CCCCCCCCh
    00401046   rep stos    dword ptr [edi]
    16:       printf("OPCODE array");
    00401048   push        offset string "OPCODE array" (0042001c)
    0040104D   call        printf (004011e0)
    00401052   add         esp,4
    17:   }
    00401055   pop         edi
    00401056   pop         esi
    00401057   pop         ebx
    00401058   add         esp,40h
    0040105B   cmp         ebp,esp
    0040105D   call        __chkesp (00401260)
    00401062   mov         esp,ebp
    00401064   pop         ebp
    00401065   ret

*/

/*
    코드내에서 스택 외의 주소값(전역변수, 함수, 힙관련 포인터)을 사용할 경우,
    그 주소 값에 문제가 생긴다.
    프로세스 로딩시 리로케이션이 될 것이니까..
    단, API일 경우 정적 주소값(BASE + RVA)을 얻어 낼 수 있다.
    그러므로 모든 값들은 파라메터로 Stack으로 전달해야 사용이 가능하다.
*/
BYTE CODE_BYTE1[] =
{
    0x55, 0x8B, 0xEC, 0x83, 0xEC, 0x40, 0x53, 0x56, 0x57, 0x8D, 0x7D, 0xC0, 0xB9, 0x10, 0x00,
    0x00, 0x00, 0xB8, 0xCC, 0xCC, 0xCC, 0xCC, 0xF3, 0xAB, 0x68, 0x74, 0x0F, 0x42, 0x00, 0xE8,
    0x8E, 0x00, 0x00, 0x00, 0x83, 0xC4, 0x04, 0x5F, 0x5E, 0x5B, 0x83, 0xC4, 0x40, 0x3B, 0xEC,
    0xE8, 0xFE, 0x00, 0x00, 0x00, 0x8B, 0xE5, 0x5D, 0xC3
};

void func()
{
    printf("일반 함수 호출 void func() \\r\\n");
}

//-----------------------------------------------------------------------------------------------
/*

/*
    00401070   push        ebp
    00401071   mov         ebp,esp
    00401073   sub         esp,44h
    00401076   push        ebx
    00401077   push        esi
    00401078   push        edi
    00401079   lea         edi,[ebp-44h]
    0040107C   mov         ecx,11h
    00401081   mov         eax,0CCCCCCCCh
    00401086   rep stos    dword ptr [edi]
    32:       for(int i = 0; i < size; i++)
    00401088   mov         dword ptr [ebp-4],0
    0040108F   jmp         func3+2Ah (0040109a)
    00401091   mov         eax,dword ptr [ebp-4]
    00401094   add         eax,1
    00401097   mov         dword ptr [ebp-4],eax
    0040109A   mov         ecx,dword ptr [ebp-4]
    0040109D   cmp         ecx,dword ptr [ebp+10h]
    004010A0   jge         func3+44h (004010b4)
    33:           dest[i] = org[i];
    004010A2   mov         edx,dword ptr [ebp+0Ch]
    004010A5   add         edx,dword ptr [ebp-4]
    004010A8   mov         eax,dword ptr [ebp+8]
    004010AB   add         eax,dword ptr [ebp-4]
    004010AE   mov         cl,byte ptr [eax]
    004010B0   mov         byte ptr [edx],cl
    004010B2   jmp         func3+21h (00401091)
    34:   }
    004010B4   pop         edi
    004010B5   pop         esi
    004010B6   pop         ebx
    004010B7   mov         esp,ebp
    004010B9   pop         ebp
    004010BA   ret

*/
<FONT COLOR=#000000>BYTE CODE_BYTE2[] =
{
    0x55, 0x8B, 0xEC, 0x83, 0xEC, 0x44, 0x53, 0x56, 0x57, 0x8D, 0x7D, 0xBC, 0xB9, 0x11, 0x00,
    0x00, 0x00, 0xB8, 0xCC, 0xCC, 0xCC, 0xCC, 0xF3, 0xAB, 0xC7, 0x45, 0xFC, 0x00, 0x00, 0x00,
    0x00, 0xEB, 0x09, 0x8B, 0x45, 0xFC, 0x83, 0xC0, 0x01, 0x89, 0x45, 0xFC, 0x8B, 0x4D, 0xFC,
    0x3B, 0x4D, 0x10, 0x7D, 0x12, 0x8B, 0x55, 0x0C, 0x03, 0x55, 0xFC, 0x8B, 0x45, 0x08, 0x03,
    0x45, 0xFC, 0x8A, 0x08, 0x88, 0x0A, 0xEB, 0xDD, 0x5F, 0x5E, 0x5B, 0x8B, 0xE5, 0x5D, 0xC3
};

void func2(char* org, char* dest, int size)
{
    for(int i = 0; i < size; i++)
        dest[i] = org[i];
}

<FONT COLOR=#008000>//-----------------------------------------------------------------------------------------------
//

void test1(char* str)
{
    printf(str);
}

void func3(DWORD fn, DWORD param)
{
    //아래 코드의 inline Assembly
    /*
    void (*f)(char*);
    f= ( void (*)(char*) )fn;
    f((char*) param);
    */

    __asm{
        mov         eax,dword ptr [ebp+8]
        mov         dword ptr [ebp-4],eax

        mov         esi,esp
        mov         ecx,dword ptr [ebp+0Ch]

        push        ecx
        call        dword ptr [ebp-4]

        //************************************************
        // stack frame에 대해서 관리를 잘해야 함.!!!
        //************************************************
        add         esp, 4
   }
}


// 0xE8, 0x29, 0x01, 0x00, 0x00 --> 00401132 E8 29 01 00 00  call __chkesp (00401260)
// 호출관한 채크함수.. 당돌 함수니까 삭제해버려야 한다.
BYTE CODE_BYTE3[] =
{
    0x55, 0x8B, 0xEC, 0x83, 0xEC, 0x40, 0x53, 0x56, 0x57, 0x8D, 0x7D, 0xC0, 0xB9, 0x10, 0x00,
    0x00, 0x00, 0xB8, 0xCC, 0xCC, 0xCC, 0xCC, 0xF3, 0xAB, 0x8B, 0x45, 0x08, 0x89, 0x45, 0xFC,
    0x8B, 0xF4, 0x8B, 0x4D, 0x0C, 0x51, 0xFF, 0x55, 0xFC, 0x83, 0xC4, 0x04, 0x5F, 0x5E, 0x5B,
    0x83, 0xC4, 0x40, 0x3B, 0xEC, 0x8B, 0xE5, 0x5D, 0xC3
};


//-----------------------------------------------------------------------------------------------
//
/* 문자열 같은 경우도 포인터이므로 어드레싱 문제가 발생한다.
   그러므로 문자열을 STACK에 위치하기 위해서는 초기화시 배열 인덱스로 처리해야 한다.
*/

/*
004011A0 55                   push        ebp
004011A1 8B EC                mov         ebp,esp
004011A3 83 EC 58             sub         esp,58h
004011A6 53                   push        ebx
004011A7 56                   push        esi
004011A8 57                   push        edi
004011A9 8D 7D A8             lea         edi,[ebp-58h]
004011AC B9 16 00 00 00       mov         ecx,16h
004011B1 B8 CC CC CC CC       mov         eax,0CCCCCCCCh
004011B6 F3 AB                rep stos    dword ptr [edi]
171:      char MSG[] = {'A', 'P', 'I', ' ', 'T', 'E', 'S', 'T', '\\0'};
004011B8 C6 45 F4 41          mov         byte ptr [ebp-0Ch],41h
004011BC C6 45 F5 50          mov         byte ptr [ebp-0Bh],50h
004011C0 C6 45 F6 49          mov         byte ptr [ebp-0Ah],49h
004011C4 C6 45 F7 20          mov         byte ptr [ebp-9],20h
004011C8 C6 45 F8 54          mov         byte ptr [ebp-8],54h
004011CC C6 45 F9 45          mov         byte ptr [ebp-7],45h
004011D0 C6 45 FA 53          mov         byte ptr [ebp-6],53h
004011D4 C6 45 FB 54          mov         byte ptr [ebp-5],54h
004011D8 C6 45 FC 00          mov         byte ptr [ebp-4],0
172:      char CAP[] = {'C', 'A', 'P', 'T', 'I', 'O', 'N', '\\0'};
004011DC C6 45 EC 43          mov         byte ptr [ebp-14h],43h
004011E0 C6 45 ED 41          mov         byte ptr [ebp-13h],41h
004011E4 C6 45 EE 50          mov         byte ptr [ebp-12h],50h
004011E8 C6 45 EF 54          mov         byte ptr [ebp-11h],54h
004011EC C6 45 F0 49          mov         byte ptr [ebp-10h],49h
004011F0 C6 45 F1 4F          mov         byte ptr [ebp-0Fh],4Fh
004011F4 C6 45 F2 4E          mov         byte ptr [ebp-0Eh],4Eh
004011F8 C6 45 F3 00          mov         byte ptr [ebp-0Dh],0
173:      typedef int (WINAPI *APIFUNC)(HWND, LPCSTR, LPCSTR, UINT);
174:
175:      APIFUNC api = (APIFUNC)pAPIAdress;
004011FC 8B 45 08             mov         eax,dword ptr [ebp+8]
004011FF 89 45 E8             mov         dword ptr [ebp-18h],eax
176:      api(NULL, MSG, CAP, MB_OK);
00401202 8B F4                mov         esi,esp
00401204 6A 00                push        0
00401206 8D 4D EC             lea         ecx,[ebp-14h]
00401209 51                   push        ecx
0040120A 8D 55 F4             lea         edx,[ebp-0Ch]
0040120D 52                   push        edx
0040120E 6A 00                push        0
00401210 FF 55 E8             call        dword ptr [ebp-18h]
00401213 3B F4                cmp         esi,esp
00401215 E8 36 02 00 00       call        __chkesp (00401450)
177:  }
0040121A 5F                   pop         edi
0040121B 5E                   pop         esi
0040121C 5B                   pop         ebx
0040121D 83 C4 58             add         esp,58h
00401220 3B EC                cmp         ebp,esp
00401222 E8 29 02 00 00       call        __chkesp (00401450)
00401227 8B E5                mov         esp,ebp
00401229 5D                   pop         ebp
0040122A C3                   ret

*/
void func4(DWORD pAPIAdress)
{
    char MSG[] = {'A', 'P', 'I', ' ', 'T', 'E', 'S', 'T', '\\0'};
    char CAP[] = {'C', 'A', 'P', 'T', 'I', 'O', 'N', '\\0'};
    typedef int (WINAPI *APIFUNC)(HWND, LPCSTR, LPCSTR, UINT);

    APIFUNC api = (APIFUNC)pAPIAdress;
    api(NULL, MSG, CAP, MB_OK);
}

// 0xE8, 0x29, 0x01, 0x00, 0x00 --> 00401132 E8 29 01 00 00  call __chkesp (00401260)
// 호출관한 채크함수.. 당돌 함수니까 삭제해버려야 한다.
BYTE CODE_BYTE4[] =
{
    0x55, 0x8B, 0xEC, 0x83, 0xEC, 0x58, 0x53, 0x56, 0x57, 0x8D, 0x7D, 0xA8, 0xB9, 0x16, 0x00,
    0x00, 0x00, 0xB8, 0xCC, 0xCC, 0xCC, 0xCC, 0xF3, 0xAB, 0xC6, 0x45, 0xF4, 0x41, 0xC6, 0x45,
    0xF5, 0x50, 0xC6, 0x45, 0xF6, 0x49, 0xC6, 0x45, 0xF7, 0x20, 0xC6, 0x45, 0xF8, 0x54, 0xC6,
    0x45, 0xF9, 0x45, 0xC6, 0x45, 0xFA, 0x53, 0xC6, 0x45, 0xFB, 0x54, 0xC6, 0x45, 0xFC, 0x00,
    0xC6, 0x45, 0xEC, 0x43, 0xC6, 0x45, 0xED, 0x41, 0xC6, 0x45, 0xEE, 0x50, 0xC6, 0x45, 0xEF,
    0x54, 0xC6, 0x45, 0xF0, 0x49, 0xC6, 0x45, 0xF1, 0x4F, 0xC6, 0x45, 0xF2, 0x4E, 0xC6, 0x45,
    0xF3, 0x00, 0x8B, 0x45, 0x08, 0x89, 0x45, 0xE8, 0x8B, 0xF4, 0x6A, 0x00, 0x8D, 0x4D, 0xEC,
    0x51, 0x8D, 0x55, 0xF4, 0x52, 0x6A, 0x00, 0xFF, 0x55, 0xE8, 0x3B, 0xF4, //0xE8, 0x36, 0x02,
     0x5F, 0x5E, 0x5B, 0x83, 0xC4, 0x58, 0x3B, 0xEC, //0xE8, 0x29, 0x02, 0x00, 0x00,
    0x8B, 0xE5, 0x5D, 0xC3
};


//-----------------------------------------------------------------------------------------------
/*

int main()
{
    char  dest[100] ={0,};
    char* src       = "일반 함수 호출 void func2(char* org, char* dest, int size)\\r\\n";
    char* src1      = "void func2(char* org, char* dest, int size)의 OPCODE 배열\\r\\n";

    func();
    func2(src, dest, strlen(src) );
    printf ("%s", dest);

    func3((DWORD)test1, (DWORD)"일반 함수 호출 func3()\\r\\n" );
    func4((DWORD)MessageBox);

    printf("--------------------------------------------\\r\\n");
    printf("함수 OPCODE Memory 복사 & EIP Jump >>>> \\r\\n");
    printf("--------------------------------------------\\r\\n");

    // 에러날 것임.
    //void (*func_array_err)();
    //func_array_err = ( void (__cdecl*)(void) ) &CODE_BYTE2;
    //func_array_err();

    void (*func_array)(char*, char*, int);
    func_array = ( void (__cdecl*)(char*, char*, int) ) &CODE_BYTE2;
    func_array(src1, dest, strlen(src1) );
    printf("%s", dest);

    void (*func_array2)(DWORD, DWORD);
    func_array2 = ( void (__cdecl*)(DWORD, DWORD) ) &CODE_BYTE3;
    func_array2((DWORD)test1, (DWORD)"using func pointer and parameter");

    void (*func_array3)(DWORD);
    func_array3 = ( void (__cdecl*)(DWORD) ) &CODE_BYTE4;
    func_array3((DWORD)MessageBox);

    return 0;
}