Fake Canary

1k words

今天看到一道题,checksec的时候会检测出Canary,但是实际上栈上并没有canary的值,故还是可以栈溢,好奇怎么实现的

起初我是采用__attribute__((noreturn)),这个是GCC的一个属性,用于告诉编译器该函数不会返回到调用者,可以帮助编译器进行优化,并消除用于函数缺少返回语句而可能产生的警告

void __attribute__((noreturn)) __stack_chk_fail_local(void) {
    
}

我想着将__stack_chk_fail_local函数重定义为空,但是这样编译时会出错

(.text+0x0): multiple definition of `__stack_chk_fail_local'; /tmp/ccZi1uB3.o:test.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status

于是我想着编译时--wrap来对__stack_chk_fail_local函数进行替换

gcc -static -Wl,--wrap=__stack_chk_fail_local test.c -o test

-Wl,--wrap=__stack_chk_fail_local这个选项是传递给链接器的,用来包装一个特定的函数,-Wl允许传递选项到链接器。

--wrap=__stack_chk_fail_local告诉链接器使用一个特定的包装函数替换__stack_chk_fail_local函数的所有调用。链接器会把所有对__stack_chk_fail_local的调用替换为对__wrap__stack_chk_fail_local的调用,同时也提供一个__real__stack_chk_fail_local符号来允许调用原始的__stack_chk_fail_local

同时编写一个wrap.s

    .global __wrap___stack_chk_fail_local
__wrap___stack_chk_fail_local:
    jmp my_stack_chk_fail_local

但是仍然编译后存在

*** stack smashing detected ***: terminated
Aborted

最后发现其实只需要写一个__Stack_chk_failed函数即可…

void __stack_chk_failed(void){}

实现效果