C언어/C언어 자료실

함수 호출 스택 프레임에서 메모리 보호를 위한 카나리(Canary)

Chipmunks 2024. 5. 14. 02:03
728x90

지난 3월 26일에 운영체제 스터디 중 함수 호출 스택 프레임을 살펴보는 발표가 있었습니다.

당시에 이해가 되지 않고 넘어간 질문이 있었는데, 유투브를 우연히 보다가 해답을 알게 되었네요..!

 

발표 사진 및 대화

 

스택 프레임에서 변수 메모리 값 앞 뒤에 cc cc cc cc 4바이트로 넣어져 있는 걸 확인할 수 있습니다.
어셈블리어 코드에서도 MOV eax, CCCCCC , mov eax, dword ptr ss:[ebp+8] , mov eax, dword ptr ss:[ebp-8] 으로 넣어주는 걸 확인할 수 있습니다.

이를 '카나리(Canary)', '카나리 비트' 라고 합니다.
메모리 보호를 위한 값이라고 하는데요,
해당 값이 '오버 플로우' 또는 '언더 플로우'로 수정이 되면 손상되었다고 판단한다고 합니다.
이를 판단하는 (어셈블리어)코드가 컴파일 단계에서 추가합니다.

 

$ gcc -S -fverbose-asm -O2 main.c -fstack-protector-all

	.section	__TEXT,__text,regular,pure_instructions
	.build_version macos, 14, 0	sdk_version 14, 2
	.globl	_main                           ; -- Begin function main
	.p2align	2
_main:                                  ; @main
	.cfi_startproc
; %bb.0:
	sub	sp, sp, #32
	.cfi_def_cfa_offset 32
	stp	x29, x30, [sp, #16]             ; 16-byte Folded Spill
	add	x29, sp, #16
	.cfi_def_cfa w29, 16
	.cfi_offset w30, -8
	.cfi_offset w29, -16
Lloh0:
	adrp	x8, ___stack_chk_guard@GOTPAGE
Lloh1:
	ldr	x8, [x8, ___stack_chk_guard@GOTPAGEOFF]
Lloh2:
	ldr	x8, [x8]
	str	x8, [sp, #8]
	mov	w8, #8265
	movk	w8, #28001, lsl #16
	str	w8, [sp, #4]
	add	x0, sp, #4
	bl	_puts
	ldr	x8, [sp, #8]
Lloh3:
	adrp	x9, ___stack_chk_guard@GOTPAGE
Lloh4:
	ldr	x9, [x9, ___stack_chk_guard@GOTPAGEOFF]
Lloh5:
	ldr	x9, [x9]
	cmp	x9, x8
	b.ne	LBB0_2
; %bb.1:
	mov	w0, #0
	ldp	x29, x30, [sp, #16]             ; 16-byte Folded Reload
	add	sp, sp, #32
	ret
LBB0_2:
	bl	___stack_chk_fail
	.loh AdrpLdrGotLdr	Lloh3, Lloh4, Lloh5
	.loh AdrpLdrGotLdr	Lloh0, Lloh1, Lloh2
	.cfi_endproc
                                        ; -- End function
.subsections_via_symbols

 

Visual Studio 에서 기본 런타임 검사 옵션을, 기본값(사용 안함) 으로 설정하거나

gcc 옵션으로 -fno-stack-protector 옵션을 주면 기능을 끌 수 있습니다.

( -fstack-protector-all 은 메모리 보호 기법 사용 )

 

< 출처 >

1. (Youtube) 널널한개발자 C언어 예제 실행결과 맞히기 문제 해설 : https://www.youtube.com/watch?v=nr5IZDg1fXY&ab_channel=널널한개발자TV
-> 시간 11분 50초 부터 설명 시작

  • 스택 프레임 동작 원리
  • 메모리 값과 자료형의 관계
  • 문자열을 읽는 방식 (아스키)
  • 카나리와 기본 런타임 검사(SSP, Stack Smashing Protector)
  • 디버그 모드와 릴리즈 모드의 차이 (컴파일러 최적화로 인한 사용하지 않는 메모리 할당 제거)

 

2. (Wiki) Buffer overflow protection : https://en.wikipedia.org/wiki/Buffer_overflow_protection

3. (Blog) 메모리 보호기법 - SSP(Stack Smashing Protector) : https://pmandocom.tistory.com/82