今天看到一道题,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){}
实现效果