最近在看ios下的arm汇编代码的时候看到有个stack_chkguard 和stack_chk_fail,记录下,以下代码均来自linux64下gcc编译器编译的二进制文件,代码已经备注的很详细了。
gcc中的编译器选项可以设置是否开启栈保护:-fstack-protector -fstack-protector -fno-stack-protector gcc 4版本中默认已经启用的stack-protector
c源代码如下:
#include <stdio.h>
int main(int argc, char* argv[]){
int i;
char a[64];
i = 0;
a[0] = 'a';
return 0;
}
1_nosp 为强制关掉stack_protector的反汇编代码。
(gdb) file 1_nosp
Reading symbols from 1_nosp...(no debugging symbols found)...done.
(gdb) disas main
Dump of assembler code for function main:
0x00000000004004d6 <+0>: push %rbp // 保存栈基址
0x00000000004004d7 <+1>: mov %rsp,%rbp // 设置新的栈指针
0x00000000004004da <+4>: mov %edi,-0x54(%rbp) // argc
0x00000000004004dd <+7>: mov %rsi,-0x60(%rbp) // argv
0x00000000004004e1 <+11>: movl $0x0,-0x4(%rbp) // 设置i的值
0x00000000004004e8 <+18>: movb $0x61,-0x50(%rbp) // 设置a[0] = 'a'
0x00000000004004ec <+22>: mov $0x0,%eax // 设置返回值
0x00000000004004f1 <+27>: pop %rbp // 弹出栈基址
0x00000000004004f2 <+28>: retq
End of assembler dump.
1_sp 为默认开启stack_protector的反汇编代码。
(gdb) file 1_sp
Reading symbols from 1_sp...(no debugging symbols found)...done.
(gdb) disas main
Dump of assembler code for function main:
0x0000000000400546 <+0>: push %rbp // 保存栈基址
0x0000000000400547 <+1>: mov %rsp,%rbp // 设置新的栈指针
0x000000000040054a <+4>: sub $0x70,%rsp // 开辟新的栈空间
0x000000000040054e <+8>: mov %edi,-0x64(%rbp) // argc
0x0000000000400551 <+11>: mov %rsi,-0x70(%rbp) // argv
0x0000000000400555 <+15>: mov %fs:0x28,%rax // canary 值
0x000000000040055e <+24>: mov %rax,-0x8(%rbp) // 这里是canary
0x0000000000400562 <+28>: xor %eax,%eax // 清空eax
0x0000000000400564 <+30>: movl $0x0,-0x54(%rbp) // 设置i的值
0x000000000040056b <+37>: movb $0x61,-0x50(%rbp) // 设置a[0] = 'a'
0x000000000040056f <+41>: mov $0x0,%eax // 设置返回值
0x0000000000400574 <+46>: mov -0x8(%rbp),%rdx //
0x0000000000400578 <+50>: xor %fs:0x28,%rdx // 检测canary值
0x0000000000400581 <+59>: je 0x400588 <main+66> // 如果为0则直接返回 否则调到保护代码区。
0x0000000000400583 <+61>: callq 0x400420 <__stack_chk_fail@plt>
0x0000000000400588 <+66>: leaveq
0x0000000000400589 <+67>: retq
End of assembler dump.
(gdb) disas __stack_chk_fail
Dump of assembler code for function __stack_chk_fail@plt:
0x0000000000400420 <+0>: jmpq *0x200bf2(%rip) # 0x601018
0x0000000000400426 <+6>: pushq $0x0
0x000000000040042b <+11>: jmpq 0x400410
End of assembler dump.
等于保存了两份一份在%fs:0x28处,另外一份在-0x8(%rbp)处,最终检测canary值是否被修改
当参数少于7个时, 参数从左到右放入寄存器: rdi, rsi, rdx, rcx, r8, r9。当参数为7个以上时, 前 6 个与前面一样, 但后面的依次从 “右向左” 放入栈中,即和32位汇编一样。xor %fs:0x28,%rdx,如果没有被修改直接返回,如果被修改了就跳到_stack_chk_fail中去。
linux64位汇编参数传递方式:参数个数大于 7 个的时候 H(a, b, c, d, e, f, g, h); a->%rdi, b->%rsi, c->%rdx, d->%rcx, e->%r8, f->%r9 h->8(%esp) g->(%esp) call H
最后的最后,欢迎大家与我多多交流,vx号:nicholas_mcc