Search code examples
cgccclangzshcracking

C program compiled file with clang leads to zsh: segmentation fault error when i try to change the assembly code


I want to crack a simple C program password file by changing the assembly code with objdump .

I want to crack this C program by changing "jne" operation to "NOP" in objdump:


int is_valid(const char* password)
    {
        if (strcmp(password, "") == 0) {
            return 1;
        }   else {
            return 0;
        }
    }

    int main()
    {
        char* input = malloc(256);

        printf("What is the password? " );
        scanf("%s" , input);

        if (is_valid(input)){
            printf("Correct! Go inside\n");
        } else {
            printf("Wrong.. you shall not enter!\n");
        }

        free(input);
        return 0;
    }


when i compile it with gcc and i try to change the "jne" to "nop" it works fine and when i type random characters as password it says:"Correct! Go inside" but when i compile it with clang and then i change the "jne" to "nop" , and when i run it and when i type some words as password it gives "zsh: segmentation fault" error.


I modify the file when i compiled it with gcc with

"printf "\x90\x90"  | dd of=pass bs=1 seek=4525 count=2 conv=notrunc" 

and when i compiled it with clang i modify it with

"printf "\x90\x90"  | dd of=pass bs=1 seek=4511 count=2 conv=notrunc"

i compile it with this command in my terminal

clang Pass.c -o pass

and jne is available in both gcc and clang compiled file in "is_valid" function.


this is is the assembly code that i get on clang compiled file:

0000000000001180 <is_valid>:
is_valid():
    1180:       55                      push   %rbp
    1181:       48 89 e5                mov    %rsp,%rbp
    1184:       48 83 ec 10             sub    $0x10,%rsp
    1188:       48 89 7d f0             mov    %rdi,-0x10(%rbp)
    118c:       48 8b 7d f0             mov    -0x10(%rbp),%rdi
    1190:       48 8d 35 6d 0e 00 00    lea    0xe6d(%rip),%rsi        # 2004 <_IO_stdin_used+0x4>
    1197:       e8 b4 fe ff ff          call   1050 <strcmp@plt>
    119c:       83 f8 00                cmp    $0x0,%eax
    119f:       0f 85 0c 00 00 00       jne    11b1 <is_valid+0x31>
    11a5:       c7 45 fc 01 00 00 00    movl   $0x1,-0x4(%rbp)
    11ac:       e9 07 00 00 00          jmp    11b8 <is_valid+0x38>
    11b1:       c7 45 fc 00 00 00 00    movl   $0x0,-0x4(%rbp)
    11b8:       8b 45 fc                mov    -0x4(%rbp),%eax
    11bb:       48 83 c4 10             add    $0x10,%rsp
    11bf:       5d                      pop    %rbp
    11c0:       c3                      ret
    11c1:       66 2e 0f 1f 84 00 00 00 00 00   cs nopw 0x0(%rax,%rax,1)
    11cb:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)

and this is the assembly code from gcc complier:

0000000000001189 <is_valid>:
is_valid():
    1189:       55                      push   %rbp
    118a:       48 89 e5                mov    %rsp,%rbp
    118d:       48 83 ec 10             sub    $0x10,%rsp
    1191:       48 89 7d f8             mov    %rdi,-0x8(%rbp)
    1195:       48 8b 45 f8             mov    -0x8(%rbp),%rax
    1199:       48 8d 15 64 0e 00 00    lea    0xe64(%rip),%rdx        # 2004 <_IO_stdin_used+0x4>
    11a0:       48 89 d6                mov    %rdx,%rsi
    11a3:       48 89 c7                mov    %rax,%rdi
    11a6:       e8 b5 fe ff ff          call   1060 <strcmp@plt>
    11ab:       85 c0                   test   %eax,%eax
    11ad:       75 07                   jne    11b6 <is_valid+0x2d>
    11af:       b8 01 00 00 00          mov    $0x1,%eax
    11b4:       eb 05                   jmp    11bb <is_valid+0x32>
    11b6:       b8 00 00 00 00          mov    $0x0,%eax
    11bb:       c9                      leave
    11bc:       c3                      ret

Solution

  • There are two different encodings of jne. See https://www.felixcloutier.com/x86/jcc. gcc is using the "short" jump JNE rel8, opcode 0x75 plus a one-byte displacement. clang is using the "near" encoding, opcode 0x0f 0x85 plus a four-byte displacement. So for the clang version, you need to overwrite 6 bytes with 0x90, instead of just 2. You can see this directly by counting the number of bytes appearing in the second field of the objdump output for the instruction.

    Since the displacement is less than 128 bytes, clang could also be using the short encoding, which would be more efficient in terms of code size. It looks like this code was compiled without optimizations; if it were compiled with optimizations, the short encoding would probably be used instead.