1

I have written two simple C programs (one with an if and one without). Looking at the assembly differences there are a few lines that I can't manage to explain and was hoping to get some assistance. The if based C code is:

#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;
}

The assembly for this is:

#   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

The parts of the assembly with # are exactly the same as the code without the if statement (I included it for ease and readability). The lines that have me confused are line main+91 through main+106.

I don't get why an if statement would somehow add these bits and was hoping for a little insight.

3

The code you are referring to is a check for argv[1] being initialized most likely.

The main problem here is that you are actually comparing two static numbers, i.e. sizeof(argv[1]) is going to ALWAYS be the same (and also smaller than 256), no matter what the argv[1] is. The compiler knows this, thus omits the whole 'if' statement. It should also segfault / have undefined behavior if there is no argv[1]. Needless to say, you can easily buffer overflow here..

What you really wanted to do is this:

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

Reason for '>' and not '>=' is that the null terminated string needs the null terminator, which is not accounted for when calculating the strlen() (or add one).

3

Just to add on Sigtran answer, part of the assembly code you are pinpointing is coming from the stack-smashing protection. It seems that you have it enabled by default on your system.

Try to recompile your code with the option: -fno-stack-protector and look at the assembly again. It should clean out most of these lines that you do not understand (if not all).

PS: If you want a more detailed answer about what does this code, feel free to add a comment to my answer and I will detail these lines in my answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.