> For the complete documentation index, see [llms.txt](https://www.pentestwiki.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://www.pentestwiki.com/etc/system-internals/stack-unwinding.md).

# Stack unwinding

스택 언와이딩은 프로그램에서 예외가 발생했을 때 예외를 처리하기 위해 호출 스택을 역방향으로 하나씩 정리하며 올라가는 과정입니다.&#x20;

이 과정은 예외가 발생한 곳까지 반복되며, 예외 처리 함수가 없을 경우 프로그램이 종료될 때까지 반복되며 결국 종료됩니다.

<figure><img src="/files/1D5XzzwmGAOixxcFs8GV" alt=""><figcaption><p><a href="https://juhyun167.github.io/2022/07/17/cpp-exception-handling/">https://juhyun167.github.io/2022/07/17/cpp-exception-handling/</a></p></figcaption></figure>

호출 스택을 역방향으로 올라가는 과정에서 try문과 catch문 사이에서 생성되었던 객체들은 메모리 낭비를 방지하기 위해 자동으로 소멸자를 호출하도록 되어있습니다.

## RUNTIME\_FUNCTION

{% code title="RUNTIME\_FUNCTION 구조체" %}

```cpp
typedef struct _IMAGE_RUNTIME_FUNCTION_ENTRY {
  DWORD BeginAddress;
  DWORD EndAddress;
  union {
    DWORD UnwindInfoAddress;
    DWORD UnwindData;
  } DUMMYUNIONNAME;
} RUNTIME_FUNCTION, *PRUNTIME_FUNCTION, _IMAGE_RUNTIME_FUNCTION_ENTRY, *_PIMAGE_RUNTIME_FUNCTION_ENTRY;
```

{% endcode %}

x64 실행파일은 .pdata라고 불리는 예외 디렉토리가 있으며, 이곳에는 실행 파일 내 스택 프레임을 생성하는 함수 대부분에 대해 RUNTIME\_FUNCTION 엔트리가 존재합니다.

해당 구조체에는 함수의 시작과 끝 주소, 그리고 해당 함수의 call stack을 어떻게 되돌릴 수 있는지 알려주는 UNWIND\_INFO 구조체를 가리키는 주소가 있습니다.

## UNWIND\_INFO

{% code title="UNWIND\_INFO 구조체" %}

```cpp
typedef struct _UNWIND_INFO {
    UCHAR Version       : 3;
    UCHAR Flags         : 5;
    UCHAR SizeOfProlog;
    UCHAR CountOfCodes;
    UCHAR FrameRegister : 4;
    UCHAR FrameOffset   : 4;
    UNWIND_CODE UnwindCode[1];
} UNWIND_INFO, *PUNWIND_INFO;
```

{% endcode %}

이 구조체에서는 함수의 프롤로그에서 어떤 레지스터를 스택에 저장했는지(spill), 그 위치를 기록한 unwide 코드들이 포함되어 있습니다.

또한 함수에 예외 처리 구문이 있을 경우, 해당 핸들러 루틴의 RVA(Relative Virtual Address)를 가리키는 포인터도 저장되어 있습니다.

## UNWIND\_CODE

{% code title="UNWIND\_CODE 구조체" %}

```cpp
typedef struct _UNWIND_CODE {
    UCHAR CodeOffset;
    UCHAR UnwindOp : 4;
    UCHAR OpInfo   : 4;
    // If size > 1, next words contain additional info
} UNWIND_CODE, *PUNWIND_CODE;
```

{% endcode %}

이 구조체는 함수의 프롤로그에서 수행되는 각 동작을 기술하는데 사용되며 주로 다음과 같은 정보들을 포함하고 있습니다.

* 프롤로그에서 스택 포인터를 조정한 크기 (sub rsp, 0x20)
* 어떤 레지스터가 스택에 스필되었는지 (mov \[rsp+8], rbx)
* 프레임 포인터의 설정 여부 (SET\_FPREG)
* 예외 핸들러 존재 여부
* 프롤로그 명령어가 적용되는 시점의 오프셋

## References

{% embed url="<https://m.blog.naver.com/nawoo/221727061390>" %}

{% embed url="<https://juhyun167.github.io/2022/07/17/cpp-exception-handling/>" %}
