理解汇编中的 if 语句

逆向工程 拆卸 部件 C 数据库
2021-07-03 08:04:57

我写了两个简单的 C 程序(一个有一个if,一个没有)。查看装配差异,有几行我无法解释,希望得到一些帮助。if基于C的代码是:

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

int main(int argc, char *argv[]) {
        char buffer[256];
        if(sizeof(buffer) >= sizeof(argv[1])) {
                strcpy(buffer, argv[1]);
                printf("%s\n", buffer);
       }
       return 0;
}

大会是这样的:

#   0x4005d6 <main>         push   rbp
#   0x4005d7 <main+1>       mov    rbp,rsp
#   0x4005da <main+4>       sub    rsp,0x120
#   0x4005e1 <main+11>      mov    DWORD PTR [rbp-0x114],edi
#   0x4005e7 <main+17>      mov    QWORD PTR [rbp-0x120],rsi
#   0x4005ee <main+24>      mov    rax,QWORD PTR fs:0x28

    0x4005f7 <main+33>      mov    QWORD PTR [rbp-0x8],rax
    0x4005fb <main+37>      xor    eax,eax
    0x4005fd <main+39>      mov    rax,QWORD PTR [rbp-0x120]

#   0x400604 <main+46>      add    rax,0x8
#   0x400608 <main+50>      mov    rdx,QWORD PTR [rax]
#   0x40060b <main+53>      lea    rax,[rbp-0x110]
#   0x400612 <main+60>      mov    rsi,rdx
#   0x400615 <main+63>      mov    rdi,rax
#   0x400618 <main+66>      call   0x400490 <strcpy@plt>
#   0x40061d <main+71>      lea    rax,[rbp-0x110]
#   0x400624 <main+78>      mov    rdi,rax
#   0x400627 <main+81>      call   0x4004a0 <puts@plt>
#   0x40062c <main+86>      mov    eax,0x0

    0x400631 <main+91>       mov    rcx,QWORD PTR [rbp-0x8]
    0x400635 <main+95>       xor    rcx,QWORD PTR fs:0x28
    0x40063e <main+104>      je     0x400645 <main+111>
    0x400640 <main+106>      call   0x4004b0 <__stack_chk_fail@plt>

#   0x400645 <main+111>     leave
#   0x400646 <main+112>     ret

程序集的部分与#没有 if 语句的代码完全相同(为了方便和可读性,我包含了它)。让我感到困惑的线条是 line main+91through main+106

我不明白为什么 if 语句会以某种方式添加这些位,并希望获得一点洞察力。

2个回答

您所指的代码是argv[1]最有可能被初始化的检查

这里的主要问题是您实际上是在比较两个静态数字,即sizeof(argv[1])无论是什么都将始终相同(并且小于 256)argv[1]编译器知道这一点,因此省略了整个“if”语句。如果没有argv[1]. 不用说,你可以很容易地在这里缓冲溢出..

你真正想做的是:

...   
if(sizeof(buffer) > strlen(argv[1])){    
... 
}
...   

' >' 而不是 ' >=' 的原因是空终止字符串需要空终止符,这在计算strlen()(或加一个)时没有考虑在内

只是为了补充 Sigtran 的答案,您指出的部分汇编代码来自堆栈粉碎保护。您的系统似乎默认启用了它。

尝试使用选项重新编译您的代码:-fno-stack-protector并再次查看程序集。它应该清除大多数您不理解的行(如果不是全部)。

PS:如果您想更详细地了解此代码的作用,请随时在我的答案中添加评论,我将在我的答案中详细说明这些行。