c – CFI指令是什么意思? (还有一些问题)

好的,这将是一个很长的问题.我试图理解“缓冲区溢出”是如何工作的.我正在阅读aleph1的Smashing the stack for fun and profit,并且刚刚得到了以下代码的反汇编:

void function(int a, int b, int c) {
   char buffer1[5];
   char buffer2[10];
}

void main() {
  function(1,2,3);
}

使用GCC的-S标志的disameembly给了我:

    .file   "example1.c"
    .text
    .globl  function
    .type   function, @function
function:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    $48, %rsp
    movl    %edi, -36(%rbp)
    movl    %esi, -40(%rbp)
    movl    %edx, -44(%rbp)
    movq    %fs:40, %rax
    movq    %rax, -8(%rbp)
    xorl    %eax, %eax
    movq    -8(%rbp), %rax
    xorq    %fs:40, %rax
    je  .L2
    call    __stack_chk_fail
.L2:
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   function, .-function
    .globl  main
    .type   main, @function
main:
.LFB1:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    $3, %edx
    movl    $2, %esi
    movl    $1, %edi
    call    function
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE1:
    .size   main, .-main
    .ident  "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
    .section    .note.GNU-stack,"",@progbits

Aleph1的文章中没有.cfi指令,我猜他们当时没有使用过.我已经阅读了this question on SO,我得知它们被GCC用于异常处理.我也阅读了another question on SO,我得到了.LFB0,.LFE0,.LFE1和.LFB1是标签,但我有以下疑问:

>我得到了.cfi指令用于异常处理,但我不明白它们的含义.我一直在here,我看到一些定义,如:

.cfi_def_cfa register, offset

.cfi_def_cfa defines a rule for computing CFA as: take address from
register and add offset to it.

但是,如果你看一下我上面的反汇编,你找不到任何注册名称(比如EAX,EBX等),而是在那里找到一个数字(我一般都找到’6′)而且我不喜欢我不知道那应该是一个寄存器.特别是,任何人都能解释一下.cfi_def_cfa_offset 16,.cfi_offset 6,-16,.cfi_def_cfa_register 6和.cfi_def_cfa 7,8是什么意思?此外,CFA是什么意思?我问这个是因为主要是在书籍/论文中,程序序言如下:

 pushl %ebp
 movl %esp,%ebp
 subl $20,%esp

但是,现在我认为现代计算机中的程序序列如下:

    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    $48, %rsp

最初我认为使用CFI指令代替子助记符来设置偏移量但事实并非如此;尽管使用了CFI指令,仍然使用sub命令.

>我明白每个程序都有标签.但是,为什么程序中有多个嵌套标签?在我的情况下,main有.LFB1和.LFE2标签.多个标签需要什么?类似地,函数过程具有标签.LFB0,.L2和.LFE0
>这两个程序的最后3行似乎用于一些内务处理功能(告诉程序的大小,可能?)但我不确定它们是什么意思.任何人都可以解释他们的意思和用途是什么?

编辑:

(再添一个问题)

> CFI指令是否占用任何空间?因为在过程“函数”中,每个int参数占用4个字节而且它的数量是3,所以所有参数在内存中占用12个字节.接下来,第一个char数组占用8个字节(向上舍入为5个字节到8个字节),下一个char数组占用12个字节(向上舍入为10bytes到12bytes),因此整个char数组占用20个字节.总结这些全部,参数和局部变量只需要12 20 = 32个字节.

但是在过程“function”中,编译器减去48个字节来存储值.为什么?

解决方法:

根据你在逆向工程中的要求,我在这里把我的评论内容作为答案(我不知道这是否会继续,因为我看到一个激烈的竞争,在那里向下投票和向上投票)

Lindy Dancer回答了cfi和cfa的含义(呼叫帧信息)和(呼叫帧地址)

.L&LT NUM&GT表示根据Google中x64 GCC名称中各种花絮的标签,以下格式的所有标签都以.L开头,并以数字结尾.L1,.L2,.L …. infinity是标签

根据Google和一些早期的SO回答BF< num>表示Function-Begin和EF< num>表示功能结束

所以.LBF0,.LBF1. LBF …..无穷大和.LFE0,…….,.LFE ……无限

表示函数开始,函数在每个函数中结束,编译器可能需要这些函数来处理一些内部需求,所以你应该忘记它们,除非非常需要深入研究编译器内部

另一个标签.L2用于解决函数中的分支指令je

je  .L2

此外,每个编译器都将对参数和本地的访问权限对齐并填充到某个边界

我不能确定,但​​对于GCC,x64默认对齐是16个字节
所以,如果您要求奇怪的预订,如

char foo [5]或
BYTE blah [10]

即使对于x86,索引5和10也不对齐

对于5 x86编译器将分配8个字节和10个16字节

像明智的x64 gcc可能会为每个请求分配16个字节

你实际上不应该担心为什么编译器会做它的功能

当你试图理解汇编逻辑时,只关注地址

如果编译器决定将x放在rbp / – X,那么它也会在该变量的范围或生命周期内在同一位置访问它

上一篇:ideal几个插件-让你的工作效率爆表


下一篇:2020年最新 C# .net 面试题,月薪20K+中高级/架构师必看(2)