反汇编 scanf 存储寄存器

逆向工程 部件 x86
2021-07-11 20:00:40

我想了解 scanf 函数有 3 个关于它的问题。这是c文件:

#include <stdio.h>
#include <stdlib.h>

int main(){
    int x;
    printf("Enter X:\n");
    scanf("%i",&x);
    printf("You entered %d...\n",x);
    return  0;
}

这是气体:

.text
    .section    .rodata
.LC0:
    .string "Enter X:"
.LC1:
    .string "%i"
.LC2:
    .string "You entered %d...\n"
    .text
    .globl  main
    .type   main, @function
main:
    pushq   %rbp    #
    movq    %rsp, %rbp  #,
    subq    $16, %rsp   #,
# a.c:5:    printf("Enter X:\n");
    leaq    .LC0(%rip), %rdi    #,
    call    puts@PLT    #
# a.c:6:    scanf("%i",&x);
    leaq    -4(%rbp), %rax  #, tmp90
    movq    %rax, %rsi  # tmp90,
    leaq    .LC1(%rip), %rdi    #,
    movl    $0, %eax    #,
    call    __isoc99_scanf@PLT  #
# a.c:7:    printf("You entered %d...\n",x);
    movl    -4(%rbp), %eax  # x, x.0_1
    movl    %eax, %esi  # x.0_1,
    leaq    .LC2(%rip), %rdi    #,
    movl    $0, %eax    #,
    call    printf@PLT  #
# a.c:8:    return  0;
    movl    $0, %eax    #, _6
# a.c:9: }
    leave   
    ret 
    .size   main, .-main
    .ident  "GCC: (Debian 8.3.0-6) 8.3.0"
    .section    .note.GNU-stack,"",@progbits

1)rsi应该取xint 的地址,但它在执行时从-4(%rbp)没有任何东西的地方取地址因为x变量的初始化来自stdinas scanf等待输入来初始化变量。但是在-4(%rbp)指令的时候是leaq -4(%rbp), %rax什么?它看起来像是垃圾,而不是 的地址x,应该从 初始化哪个值stdin

2)根据这个https://stackoverflow.com/questions/54165346/integer-describing-number-of-floating-point-arguments-in-xmm-registers-not-passe,这movl $0, %eax是零FP寄存器al,但是这是相同的约定printf所以我的问题是,来自 glibc 或其他库的哪些函数应用了这种对流?(所以我必须%al在 printf、scanf、.... 中归零?)。我假设每个都有va_list或可变参数?

3) 气源中的堆栈金丝雀在哪里应该保护 scanf 缓冲区免于溢出?根据这个:scanf 如何与我的汇编代码交互,这应该设置金丝雀(在 masm 中):

0x080484c5 <+6>: mov    eax,gs:0x14
   0x080484cb <+12>:    mov    DWORD PTR [ebp-0xc],eax
   0x080484ce <+15>:    xor    eax,eax

但是我在我的气体源中没有看到与此类似的东西,它也是从 gcc 输出的,它应该自己设置它(除非在我的源中不可见的 scanf 函数本身中有一些检查)。那么它在哪里呢?

1个回答
  1. rbp-4 编译器为变量分配的位置x您可以看到稍后它正在被调用mov指令读取printf
  2. al必须在每次调用可变参数函数之前设置(...)
  3. 这取决于 GCC 版本/构建选项,但默认情况下,堆栈保护仅用于缓冲区(数组)超过 8 字节大的函数因为您只有一个整数,所以它不可能被溢出,因此没有添加堆栈保护。如果您无论如何都想启用它,请使用-fstack-protector-all. 请注意,堆栈保护器不能对整数溢出做任何事情。