|| Date: 18-06-14 || Back to index ||
|| Tag: write-up ||

ASM Primer - Part 2

Conditional Statements

Here’s an example of an if-elseif-else conditional statement.

sub_checker:
    push ebp
    mov ebp, esp
    test [ebp+0x8], [ebp+0x8]
    jnz loc_block2
    push off_you_win
    call foo
    jmp end

    loc_block2:
        cmp -1, [ebp+0x8]
        jne loc_block3
        push off_you_lose
        call foo
        jmp end

    loc_block3:
        push off_error_check_machine
        call foo

    end:
        mov -1, [ebp+0x8]

    mov esp, ebp
    pop ebp
    ret

// Pseudocode
void checker(int *arg) {
    if (*arg == 0){
        foo("You win!")
    } else if (*arg == -1) {
        foo("You lose...");
    } else {
        foo("Error. Check machine");
    }

    // End
    *arg = -1;
}

The main thing to note about simple conditional statements (not multiple conditions like AND, OR, NOT, etc.) is that the comparison is inverted. We’ll take a look at complex conditionals later on in this article.

Loops

A great example of a loop is below

lea edx, [eax+1]

loc_12345:
    mov cl, [eax]
    add eax, 1

    test cl, cl
    jnz loc_12345

sub eax, edx

// Pseudocode
int strlen(const char *eax) {
    const char* edx = eax+1;

    char c = eax[0];
    while (c != NULL) {
        eax += 1;
        c = *eax;
    }

    return edx - eax;
}

An example of a for loop

mov eax, 0
loc_12345:
    cmp eax, 10
    jnl end

    call foo
    add eax, 1
    jmp loc_12345
end:
    // Whatever...

// Pseudocode
for (i = 0; i < 10; i++) {
    foo();
}
// whatever...

Another great live example

xor esi, esi # control variable
loc_123456:             | <- Start of loop body
    push off_494949[esi]  |
    lea eax, [ebp-2c0h]   |
    push eax              | function call: 
    call sub_323232       | - push 2 arguments to stack
    pop ecx               | - call
    pop ecx               | - pop two local variables (cdecl style)
    test eax, eax    | <- test condition (is eax null)
    jz loc_end       
    add esi, 4       | increment and compare the control variable
    cmp esi, 38h     |
    jb short loc_123456 # end of loop body
end:

Clustering

Usually, you should always rely on IDA Pro or your disassembler of choice since they have good heuristics to identify a loop body, but this is an ASM primer so we’ll do stuff manually.

Assembly is just like any programming language: when one looks at it long enough, your eye starts to cluster the letters in patterns that it can identify later. A good example of this is:

lea eax, [ebp-2c0h]

There’s a lot going on here. I got taken back when I first saw this operation. I had to slow down and break it down. Now, my eye can catch what’s happening and has clustered it into patterns:

How to quickly identify a loop (without IDA)

Complex Conditional statements

We’ll take the same example of simple conditional statements from above and modify it to include multiple cases

sub_checker:
    push ebp
    mov ebp, esp
    cmp 1, [ebp+0x8]
    jmp loc_block1

    cmp 0, [ebp+0xc]
    jge loc_block2

    loc_block1:
        push off_machine_broken
        call foo
        mov esp, ebp
        pop ebp
        ret

    loc_block2:
        cmp 0, [ebp+0x8]
        jl loc_block3
        cmp 10, [ebp+0x8]
        jge loc_block3
        push off_you_lose
        call foo

    loc_block3:
        cmp 10, [ebp+0x8]
        jl loc_block4
        cmp 100, [ebp+0x8]
        jge loc_block4
        push off_you_win_big
        call foo

    loc_block4:
        mov -1, [ebp+0x8]

    mov esp, ebp
    pop ebp
    ret

// Pseudocode
void slot_machine(int isBroken, int *score) {
    if (isBroken || *score < 0) {
        foo("Machine is broken...")
        return
    }

    if (*score >= 0 && *score < 10){
        foo("You lose...")
    } else if (*score >= 10 && *score < 100) {
        foo("You win BIG!!!!");
    } 

    // End
    *score = -1;
}