数组访问与金丝雀值,长度为0数组的使用情景

写了一个简单的code,gcc -S test.c

int test_1()
{

}

int test_2()
{
    int a[0];
}
test_1:
    pushl    %ebp
    movl    %esp, %ebp
    nop
    popl    %ebp
    ret

test_2:
    pushl    %ebp
    movl    %esp, %ebp
    subl    $24, %esp
    movl    %gs:20, %eax
    movl    %eax, -12(%ebp)
    xorl    %eax, %eax
    nop
    movl    -12(%ebp), %edx
    xorl    %gs:20, %edx
    je    .L3
    call    __stack_chk_fail
.L3:
    leave
    ret

因为C不会对数组长度进行检测,所采取的方法就是插入一个金丝雀值,数组操作结束之后,看这个金丝雀值是否变化,变化了则调用

__stack_chk_fail,abort这个进程。

数组越界写入,导致 canary值被修改。在函数退出时检查canary,发现canary被修改,函数不能安全返回,call到__stack_chk_fail函数,abort当前

进程,使当前进程不能正常返回。

函数调用栈布局中canary位置

ESP:堆栈(Stack)指针寄存器,指向堆栈顶部
EBP:基址指针寄存器,指向当前堆栈底部

局部变量往低位地址增长,调用栈也是往位地址增长

canary位置:高于局部变量,低于EBP

所以诱发金丝雀的原因可能是:函数比局部变量更高的地址被修改

栈分配是从上到下分配,但是用的时候,是从下到上用的。

int main()
{
    int aa[10] = {0};

    printf("%p\n", &(aa[0]));
    printf("%p\n", &(aa[1]));
    printf("%p\n", &(aa[2]));
}

$ ./test
0xbf94c2b4
0xbf94c2b8
0xbf94c2bc

长度为0的数组正确用法应该是如下所示的情况:

struct TEST {
    int aa;
    int bb[0];
};

#define ARR_SIZE XXX

int main()
{
    struct TEST test = malloc(sizeof(struct TEST) + ARR_SIZE);

    /*然后通过bb访问后边的数据*/
  /*...*/

    return 0;
}

猜你喜欢

转载自www.cnblogs.com/rivsidn/p/9300539.html