x86-64 register shortcut
우리가 흔히 gdb에서 i r 명령어를 쳐보면
Shell
pwndbg> i r
rax 0x0 0
rbx 0x138d0 80080
rcx 0x0 0
rdx 0x0 0
rsi 0xffff888000020800 -131391639386112
rdi 0x138d0 80080
rbp 0xffffffff81c03f30 0xffffffff81c03f30
rsp 0xffffffff81c03f28 0xffffffff81c03f28
r8 0xffffffff81da3000 -2116407296
r9 0xffffffffffff 281474976710655
r10 0xffffffff81c03ef0 -2118107408
r11 0xffffffff0000ffff -4294901761
r12 0x0 0
r13 0x0 0
r14 0x0 0
r15 0x0 0
rip 0xffffffff81cf9ec6 0xffffffff81cf9ec6 <start_kernel>
eflags 0x46 [ IOPL=0 ZF PF ]
cs 0x10 16
ss 0x0 0
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
fs_base 0x0 0
gs_base 0xffffffff81cd7000 -2117242880
k_gs_base 0x0 0
cr0 0x80050033 [ PG AM WP NE ET MP PE ]
cr2 0xffff8880000138d0 -131391639439152
cr3 0x1d2e000 [ PDBR=7470 PCID=0 ]
cr4 0xa0 [ PGE PAE ]
cr8 0x0 0
efer 0xd01 [ NXE LMA LME SCE ]
다음과 같이 수많은 레지스터가 존재한다. r15까지는 흔히 아니깐 pass를 하고 나머지 특수 레지스터에 대해 분석하는 글들을 위한 shortcut글이다.
| 항목 | 이게 “무엇” | Linux x86-64에서 보통 의미 | 값이 꼬이면 자주 나는 증상 | shortcut( 추가적으로 분석한 글) |
|---|---|---|---|---|
| eflags (rflags) | CPU 상태 플래그(조건/제어 비트 묶음) | IF(인터럽트 허용), ZF/PF/CF/SF/OF(연산 결과 플래그), IOPL(I/O 권한 레벨) 등 | IF=0이면 인터럽트가 막혀서 시스템이 멈춘 듯 보이거나 타이밍이 달라짐. iretq 복귀 시 “이상한 RFLAGS”면 fault 유발 가능 | |
| cs | 코드 세그먼트 선택자(현재 CPL=권한레벨도 여기로 결정) | 보통 커널=0x10, 유저=0x33 같은 식(GDT 구성에 따라) | CPL/세그 선택자가 부적절하면 #GP/#SS/#PF 등 | |
| ss | 스택 세그먼트 선택자 | 롱모드에선 베이스는 무시되지만 권한/검증에는 여전히 관여 | iretq로 CPL 바꾸며 복귀할 때 스택 관련이 틀리면 #SS/#GP | |
| ds, es | 데이터 세그 선택자 | 롱모드에선 거의 의미 없음(베이스/리밋 무시). 보통 0으로 둬도 크게 상관 없는 경우 많음 | 대개 문제 원인 아닐 때가 많음 | |
| fs, gs | 세그 선택자(“selector”) 그 자체 | selector 값 자체보다 fs_base/gs_base가 핵심 | selector보다 base가 중요 | |
| fs_base | FS 세그먼트 베이스 주소 | **유저 TLS(Thread-Local Storage)**에 거의 항상 사용됨. glibc는 fs_base를 TCB(스레드 제어블록) 시작점으로 둬서 fs:[offset]로 errno, thread pointer, canary 등 접근 | TLS 깨지면 유저랜드에서 이상한 segfault/스택카나리 문제/스레드 관련 크래시 | |
| gs_base | GS 세그먼트 베이스 주소 | 리눅스 커널은 흔히 gs_base를 per-CPU 영역(CPU별 데이터)이나 현재 태스크 포인터 등에 쓰는 패턴이 많음(설정/커널버전에 따라 다름) | 잘못된 값이면 커널 진입/복귀 흐름에서 즉시 폭발(#GP/#PF)하기 쉬움 | |
| k_gs_base | “커널용 GS 베이스”로 쓰이는 값(디버거가 별도로 보여주는 경우) | 개념적으로는 “커널이 쓰고 싶어하는 GS base”가 따로 있고, 유저/커널 전환 때 SWAPGS로 서로 바꿔 쓰는 모델과 연결됨 | swapgs 타이밍이 틀리거나 엇갈리면 per-CPU 참조가 틀어져 바로 fault | |
| cr0 | 시스템 제어 레지스터 0 | PG(페이징 on), WP(커널도 read-only 페이지에 write 금지), PE(보호모드) 등 핵심 제어비트 | PG 등 핵심 비트가 이상하면 아예 시스템이 제대로 실행 불가 | |
| cr2 | 페이지 폴트가 난 선형 주소 | #PF 발생 시 “어느 주소 접근하다가” 터졌는지 여기에 남음 | 크래시 분석에서 제일 먼저 보는 값 | |
| cr3 | 페이지 테이블 기준 주소(PML4) + PCID 등 | 프로세스/주소공간이 바뀔 때 CR3가 바뀜. “유저 주소공간이 context switch마다 바뀌나?”의 핵심이 이거 | CR3/페이지테이블이 틀리면 즉시 #PF 연쇄 | what is CR3 register |
| cr4 | 시스템 제어 레지스터 4 | PAE, PGE, SMEP/SMAP(설정 시) 등 메모리 보호/페이징 확장 기능 | SMEP/SMAP 같은 보호기능이 켜져 있으면 특정 종류의 잘못된 접근이 곧바로 fault | |
| cr8 | Task Priority Register(TPR) | APIC 인터럽트 우선순위/마스킹에 관여(주로 커널이 인터럽트 제어에 사용) | 보통 유저가 직접 신경쓸 일은 적지만 커널 디버깅 땐 의미 있음 | |
| efer | Extended Feature Enable Register(MSR) | LME/LMA(64비트 모드), NXE(NX 비트), SCE(SYSCALL/SYSRET) 등 | NXE/LMA 등 핵심이 꺼져 있으면 64비트 운영 자체가 불가/불안정 |