Search code examples
cassemblyx86reverse-engineeringdecompiling

What is the decompiled (C) code construct of this assembly x86 code?


This code compares every char of a string (located at ebp+arg_0) with different constants (ASCII chars) like 'I', 'o' and 'S'. I guess, based on other code parts, this code is originally written in C.

assembly

This compare-code-part looks very inefficient to. My question, how do you think this code will look in C? What code construct was used originally? my thoughts so far

  • It's not a for loop. Because i don't see any upward jump and stop-condition.

  • It's not a while/case/switch code construct

  • My best guess is that this are a lot of consecutive if/else statements. Can you help?

Yes it's part of a challenge, i already have the flag/solution, no worries about that. Just trying to better understand the code.


Solution

  • It's not a for loop. Because i don't see any upward jump and stop-condition.

    Correct.

    It's not a while/case/switch code constuct

    It can't be, it compares different indicies of the array.

    My best guess is that this are a lot of consecutive if/elses. Can you help?

    Looks like it could be this code:

    void f(const char* arg_0) {
        if(arg_0[4] == 'I' && arg_0[5] == 'o' && arg_0[6] == 'S') {
            printf("Gratz man :)");
            exit(0); //noreturn, hence your control flow ends here in the assembly
        }
        puts("Wrong password"); // Or `printf("Wrong password\n");` which gets optimized to `puts`
        // leave, retn
    }
    

    This is how gcc compiles it without optimizations:

    .LC0:
            .string "Gratz man :)"
    .LC1:
            .string "Wrong password"
    f(char const*):
            push    ebp
            mov     ebp, esp
            sub     esp, 8
            mov     eax, DWORD PTR [ebp+8]
            add     eax, 4
            movzx   eax, BYTE PTR [eax]
            cmp     al, 73
            jne     .L2
            mov     eax, DWORD PTR [ebp+8]
            add     eax, 5
            movzx   eax, BYTE PTR [eax]
            cmp     al, 111
            jne     .L2
            mov     eax, DWORD PTR [ebp+8]
            add     eax, 6
            movzx   eax, BYTE PTR [eax]
            cmp     al, 83
            jne     .L2
            sub     esp, 12
            push    OFFSET FLAT:.LC0
            call    printf
            add     esp, 16
            sub     esp, 12
            push    0
            call    exit
    .L2:
            sub     esp, 12
            push    OFFSET FLAT:.LC1
            call    puts
            add     esp, 16
            nop
            leave
            ret
    

    Looks very similar to your disassembled code.

    This compare-code-part looks very inefficient

    Looks like it was compiled without optimizations. With optimizations enabled, gcc compiled the code to:

    .LC0:
            .string "Gratz man :)"
    .LC1:
            .string "Wrong password"
    f(char const*):
            sub     esp, 12
            mov     eax, DWORD PTR [esp+16]
            cmp     BYTE PTR [eax+4], 73
            jne     .L2
            cmp     BYTE PTR [eax+5], 111
            je      .L5
    .L2:
            mov     DWORD PTR [esp+16], OFFSET FLAT:.LC1
            add     esp, 12
            jmp     puts
    .L5:
            cmp     BYTE PTR [eax+6], 83
            jne     .L2
            sub     esp, 12
            push    OFFSET FLAT:.LC0
            call    printf
            mov     DWORD PTR [esp], 0
            call    exit
    

    Not sure why gcc decided to jump down and back up again instead of a straight line of jnes. Also, the ret is gone, your printf got tail-call-optimized, i.e. a jmp printf istead of a call printf followed by a ret.