
완전 동적 호출 스택 스푸퍼의 PoC 구현
완전 동적 콜 스택 스푸퍼의 PoC 구현
SilentMoonwalk는 완전 동적 콜 스택 스푸퍼의 PoC 구현으로, ROP를 사용하여 언와인딩을 제어 흐름과 비동기화함으로써 콜 스택에서 원래 호출자를 제거하는 기법을 구현합니다.
이 PoC는 스택 스푸핑 주제에 대한 공동 연구의 결과물입니다. 연구의 저자는 다음과 같습니다:
이 작업은 초기 PoC 단계와 PoC 뒤에 있는 연구에 모두 기여한 Waldo-IRC와 Trickster0의 작업 없이는 불가능했을 것임을 강조하고 싶습니다.
이 저장소는 임의의 Windows API를 호출할 때 콜 스택을 스푸핑하는 PoC 구현을 보여줍니다.
이 시도는 이 Twitter 스레드와 이 Twitter 스레드에서 영감을 받았으며, 여기서 sensei namazso가 ROP 체인을 사용하여 스택 언와인딩을 실제 제어 흐름과 비동기화하고 이후 원래 스택을 복원하는 접근 방식을 보여주고 확장할 것을 제안했습니다.
이 PoC는 위와 유사한 작업을 시도하며, 비동기 스택을 사용하여 원래 콜 스택을 완전히 숨기고 EXE 이미지 베이스도 제거합니다. 반환 시 ROP 가젯이 호출되어 원래 스택을 복원합니다. 코드에서는 이 과정이 루프에서 10번 반복되며, 각 반복마다 다른 프레임을 사용하여 안정성을 입증합니다.
현재 도구는 2가지 모드를 지원합니다. 그중 하나는 현재 RSP를 이동시키고 콜 스택에 두 개의 가짜 프레임을 추가하여 작동하는, 잘못된 POP RBP 프레임에 대한 잘못된 패치입니다. 합성 프레임을 사용하여 작동하므로 이 모드를 "SYNTHETIC"이라고 부릅니다.
스택에서 RBP 레지스터를 POP하여 언와인드되는 프레임을 선택할 때, 도구가 부적합한 프레임을 선택하여 아래에서 볼 수 있듯이 갑자기 잘린 콜 스택이 발생할 수 있습니다.

이 문제에 대한 어리석은 해결책은 두 개의 가짜 프레임을 만들고 이를 잘린 콜 스택에 다시 연결하는 것입니다. 이는 POP RBP를 호출하여 언와인드되는 적합한 프레임이 없더라도 일종의 겉보기에는 합법적인 콜 스택을 생성하지만:
_합성 스푸핑의 결과는 아래 이미지에서 볼 수 있습니다:

그림 1: Windows 10 - EXE 모듈이 완전히 제거된(매개변수 없는 함수 getchar 호출) 겉보기에는 합법적이지만 언와인딩 불가능한 콜 스택
참고: 이 작동 모드는 기본적으로 비활성화되어 있습니다. 활성화하려면 CALLSTACK_TYPE을 1로 변경하십시오.
이 모드는 위 문제에 대한 올바른 솔루션으로, 부적합한 프레임을 적합한 프레임으로 간단히 교체합니다.

그림 2: Windows 10 - EXE 모듈이 완전히 제거된(4개 매개변수 함수 MessageBoxA 호출) 합법적이고 언와인딩 가능한 콜 스택
저장소에는 런타임 함수를 검사하는 작은 유틸리티도 있으며, 이는 런타임 함수 엔트리를 분석하는 데 유용할 수 있습니다.
UnwindInspector.exe -h
Unwind Inspector v0.100000
필수 인자:
-m <모듈>: 대상 DLL
-f <함수>: 대상 함수
-a <함수-주소>: 대상 함수 주소
샘플 출력:
UnwindInspector.exe -m kernelbase -a 0x7FFAAE12182C
[*] 함수 주소 0x7ffaae12182c 사용 중
Runtime Function (0x000000000000182C, 0x00000000000019ED)
Unwind Info Address: 0x000000000026AA88
Version: 0
Ver + Flags: 00000000
SizeOfProlog: 0x1f
CountOfCodes: 0xc
FrameRegister: 0x0
FrameOffset: 0x0
UnwindCodes:
[00h] Frame: 0x741f - 0x04 - UWOP_SAVE_NONVOL (RDI, 0x001f)
[01h] Frame: 0x0015 - 0x00 - UWOP_PUSH_NONVOL (RAX, 0x0015)
[02h] Frame: 0x641f - 0x04 - UWOP_SAVE_NONVOL (RSI, 0x001f)
[03h] Frame: 0x0014 - 0x00 - UWOP_PUSH_NONVOL (RAX, 0x0014)
[04h] Frame: 0x341f - 0x04 - UWOP_SAVE_NONVOL (RBX, 0x001f)
[05h] Frame: 0x0012 - 0x00 - UWOP_PUSH_NONVOL (RAX, 0x0012)
[06h] Frame: 0xb21f - 0x02 - UWOP_ALLOC_SMALL (R11, 0x001f)
[07h] Frame: 0xf018 - 0x00 - UWOP_PUSH_NONVOL (R15, 0x0018)
[08h] Frame: 0xe016 - 0x00 - UWOP_PUSH_NONVOL (R14, 0x0016)
[09h] Frame: 0xd014 - 0x00 - UWOP_PUSH_NONVOL (R13, 0x0014)
[0ah] Frame: 0xc012 - 0x00 - UWOP_PUSH_NONVOL (R12, 0x0012)
[0bh] Frame: 0x5010 - 0x00 - UWOP_PUSH_NONVOL (RBP, 0x0010)
PoC를 빌드하고 그림과 유사한 동작을 관찰하려면 다음을 확인하십시오:
/GS-)/Od)/GL 제거)/Os, /Ot 제거)/Oi)이 주제에 대한 이전 작업을 언급할 가치가 있으며, 이 작업의 기초를 마련했습니다.