4장. 프로시저와 스택 구조

 

  • 함수가 호출 될 때 스택의 변화

    • 함수가 호출 되기 직전에 함수의 인자 값을 먼저 스택에 쌓고, 함수의 복귀 주소이전의 EBP 를 push, ESP를 이동 시킨다. 그리고 그 함수 스코프 내에 있는 지역 변수( 먼저 선언 한 것이 먼저 스택에 쌓인다 )를 push 한다.
    • 함수의 인자 값 : 제일 뒤에 있는 인자 값이 스택에 먼저 PUSH 된다.(default 로... 컴파일 옵션에 따라 달라 질 수 있다.)
    • 인자 값 접근 : EBP를 기준[복귀주소]으로 + 0x4[첫 번째 지역변수] or 0x8[두 번째 지역변수]... ( 32 비트 환경 )

      • ESP를 return 되는 함수 복귀 주소 가 저장 되어 있는 곳 이전 데이터를 가리키고 있다.

      함수가 return 될 때 스택의 변화

    • 지역변수 접근EBP - 0x4[ 이전의 EBP ], EBP - 0x8[ 지역변수1 ]

 

  • 스택에서 ESP의 위치만 바꿀 뿐, 기존에 있는 데이터는 쓰래기 값 처럼 대우를 한다. 데이터를 PUSH 할 때는 그냥 덮어서 쓴다.

 

  • 스택 프레임

    • 스택 프레임은 스택에서 PUSH 로 인한 ESP 의 변화로 인한 지역변수 접근 문제 때문에 만들어졌다. 이 때 EBP가 등장.

 

  • 파라미터 전달의 방법 : Calling Convention - 스택에 파라미터를 어떤 순서로 넣을지, 전달되어진 파라미터를 어느 곳에서 해제할 건인지 방식을 정하는 것

    • 이러한 Calling Convention은 컴파일러에 의해 코드가 자동으로 만들어 진다.
    •  __cdecl :  C/C++ 에서 default 로 사용하는 콜링 컨벤션 방식     ex ) int sum( int a, int b )

      • 파라미터 전달 : 오른쪽에서 왼쪽으로
      • 파라미터 해제 : 프로시저를 호출한 쪽에서 해제
    • __stdcall : Windows API 의 프로시저에서 사용하는 콜링 컨벤션 방식   ex ) int __stdcall sum( int a, int b )

      • 파라미터 전달 : __cdecl 과 같음
      • 파라미터 해제 : 프로시저가 복귀되기 전에 이루어진다.
      • 장점

        • 함수의 독립성이 뛰어나다 : 함수가 리턴되어진 후에 그 프로시저의 SP가 이전 상태로 복원되어 있어서, 복귀후에 호출 프로시저에 대하여 더 이상 신경 안써도 된다.
        • 스택 해제 코드가 호출한 프로시저 안에 있어서, 프로시저가 여러 곳에서 호출 되더라도 스택을 해제하는 코든느 프로시저 내에 하나만 존재하여 __cdecl 방식보다 코드크기가 줄어 든다.
    • __fastcall

      • 파라미터 전달 : 처음 두 개까지의 파라미터는 스택을 사용하지 않고, ecx, edx 레지스터를 사용하고 그 이상의 파라미터에 대해서만 오른쪽에서 왼쪽 방향으로 스택에 저장
      • 스택 제거는 __stdcall과 동일
  • 리턴 값 전달 방법

    • 32비트 보다 작거나 같은 값 일 경우 : 프로시저 리턴 전에 EAX에 리턴 값을 저장
    • 32비트 보다 큰 경우 : 낮은 주소 영역의 32비트 -> EAX , 상위 32비트 -> EDX 에 저장

 

  • Naked Function

    • Interrupt Handler 나 Hooking 루틴을 만들다 보면 프로그래머가 직접 스택 프레임을 구성하고, 원하는 형태로 함수의 구조를 만들어야 하는 경우 사용을 한다.
    • 모든 스택 프레임에 대한 구성과 해제를 프로그래ㄴ머가 직접 신경 써 줘야 한다.
    1. __declspec(naked)NamedFunc()
      {
    2. int i;  int j;
    3. __asm {
    4. push ebp
    5. mov ebp, esp
    6. sub esp, __LOCAL_SIZE }
    7. i = 1; j = 2;
    8. __asm {
    9. mov esp, ebp
    10. pop ebp
    11. ret }
    12. }

 

  • Windows 에서의 스택 구조

    • 쓰레드 생성 시 디폴트로 1MByte의 메모리를 예약하여 놓고 이 중 1개의 페이지인 4byte 만을 실제 메모리와 매핑, 다른 1개는 가드 페이지( Guard Page ) 형태로 만들어 놓는다. 나머지 메모리 들에 대해서는 예약만 해 놓고 실제 메모리와 매핑은 시켜놓지 않은 상태로 둔다.
    • 가드 페이지로 페이지 보호를 수행 한다. 최초 4Kbyte의 스택을 초과 하여 사용할 시에 가드 페이지 영역을 새로운 Committed Page로 바꿔주고 그 아래 페이지 영역의 부분을 새로운 가드 페이지로 바꾸어 준다.
    • 이런식으로 계속 페이지를 Committed Page로 바꾸지만, 마지막 페이지 직전까지 할당 했을때, 마지막 페이지는 Guard Page로 바꾸지 않고 Reserved Page로 그냥 둔다. 왜냐하면, 전체 영역에 대해 Commit 되게 하면, 쓰레드가 자신의 스택 영역을 초과하여 사용하더라도 이를 알아차리지 못하기 때문에, 다른 데이터 영역을 손상 시키고, 스택에 대한 오버플로우 문제를 발생 시킬수 있기 때문이다.
    • 나머지 페이지는 예약만 해놓아서 이 프로세스 공간에 대한 메모리 할당을 스택 용도 이외로 사용하지 못하게 한다. ???

 

 

 

설정

트랙백

댓글