fs : [0x28] (스택 카나리아)는 무엇입니까?


13

에서 이 포스트 는 것을 알 수있다 FS:[0x28]스택 - 카나리아입니다. 이 함수에서 GCC를 사용하여 동일한 코드를 생성하고 있습니다.

void foo () {
    char a[500] = {};
    printf("%s", a);
}

구체적으로이 어셈블리를 얻습니다 ..

    0x000006b5      64488b042528.  mov rax, qword fs:[0x28]                ; [0x28:8]=0x1978 ; '(' ; "x\x19"
    0x000006be      488945f8       mov qword [local_8h], rax
...stuff...
    0x00000700      488b45f8       mov rax, qword [local_8h]
    0x00000704      644833042528.  xor rax, qword fs:[0x28]
    0x0000070d      7405           je 0x714
    0x0000070f      e85cfeffff     call sym.imp.__stack_chk_fail           ; void __stack_chk_fail(void)
    ; CODE XREF from 0x0000070d (sym.foo)
    0x00000714      c9             leave
    0x00000715      c3             ret

값을 설정하는 것은 무엇입니까 fs:[0x28]? 커널입니까, 아니면 GCC가 코드에서 발생합니까? 커널에 코드를 보여 주거나 설정하는 바이너리로 컴파일 할 수 fs:[0x28]있습니까? 부팅시 카나리아가 재생성됩니까? 이것은 어디에 문서화되어 있습니까?

답변:


18

(거의) 모든 프로세스 strace는 프로세스 실행 초기에 매우 의심스러운 syscall을 보여주기 때문에이 초기화를 쉽게 추적 할 수 있습니다.

arch_prctl(ARCH_SET_FS, 0x7fc189ed0740) = 0

그것이 man 2 arch_prctl말하는 것입니다 :

   ARCH_SET_FS
          Set the 64-bit base for the FS register to addr.

예, 우리가 필요한 것 같습니다. 를 호출하는 사람을 찾으려면 arch_prctl역 추적 을 찾으십시오 .

(gdb) catch syscall arch_prctl
Catchpoint 1 (syscall 'arch_prctl' [158])
(gdb) r
Starting program: <program path>

Catchpoint 1 (call to syscall arch_prctl), 0x00007ffff7dd9cad in init_tls () from /lib64/ld-linux-x86-64.so.2
(gdb) bt
#0  0x00007ffff7dd9cad in init_tls () from /lib64/ld-linux-x86-64.so.2
#1  0x00007ffff7ddd3e3 in dl_main () from /lib64/ld-linux-x86-64.so.2
#2  0x00007ffff7df04c0 in _dl_sysdep_start () from /lib64/ld-linux-x86-64.so.2
#3  0x00007ffff7dda028 in _dl_start () from /lib64/ld-linux-x86-64.so.2
#4  0x00007ffff7dd8fb8 in _start () from /lib64/ld-linux-x86-64.so.2
#5  0x0000000000000001 in ?? ()
#6  0x00007fffffffecef in ?? ()
#7  0x0000000000000000 in ?? ()

따라서 FS 세그먼트베이스는 프로그램 로딩 중의 ld-linux일부인에 의해 설정됩니다 glibc(프로그램이 정적으로 링크 된 경우이 코드는 이진에 포함됩니다). 이것이 모든 일이 일어나는 곳입니다.

시작하는 동안 로더는 TLS를 초기화 합니다. 여기에는 TLS 시작을 가리 키도록 메모리 할당 및 FS 기본 값 설정이 포함됩니다. 이것은 arch_prctl syscall을 통해 수행됩니다 . TLS 초기화 security_init 함수 가 호출 된 후 스택 가드의 값을 생성하고이를 메모리 위치에 fs:[0x28]기록합니다.

그리고 TLS 시작에 위치한 구조 0x28에서 stack_guard필드 의 오프셋입니다 .


zomfg, 정말 좋은 답변입니다. 나는 radare로 바이너리를 분해하려고했습니다. 이것은 내가 찾던 형태와 내용을 가지고 있습니다. 정말 감사합니다.
Evan Carroll

arch_prctl(ARCH_SET_FS..)실행 파일에서 볼 수없는 프로세스를 초기화하는 것은 무엇입니까 ? 커널 코드인가요?
Evan Carroll

게시물의 "syscall"링크를 참조하십시오. syscall이 실행되는 실제 호출 사이트 ( git.launchpad.net/glibc/tree/sysdeps/x86_64/nptl/tls.h#n153 )로 연결됩니다 . ld-linuxTLS 초기화 중에 실행됩니다 .
Danila Kiver

6

여러분이보고있는 것을 GCC에서 스택 스매싱 프로텍터 (SSP)라고 하며, 이는 컴파일러가 생성 한 버퍼 오버 플로우 방지 의 한 형태입니다 . 이 값은 시작시 프로그램에 의해 생성 된 난수이며 Wikipedia 기사에서 언급 한 것처럼 TLS (Thread Local Storage )에 배치됩니다 . 다른 컴파일러는 이러한 유형의 보호를 구현하기 위해 다른 전략을 사용할 수 있습니다.

왜 TLS에 값을 저장합니까? 값이 해당 위치에 있으므로 CS, DS 및 SS 레지스터에서 해당 주소에 액세스 할 수 없으므로 악의적 인 코드에서 스택을 변경하려고하면 저장된 값을 추측하기가 매우 어렵습니다.


이것은 내가 찾고있는 것이 아니므로 명확하게하기 위해 조금 명확하게 설명했습니다. "시작시 프로그램에 의해 생성 된 난수"실행 파일에서 생성 된 위치와 코드를 생성하는 코드는 무엇입니까?
Evan Carroll
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.