Reverse Engineering challenge #11.

Tags: ARM MIPS ARM64 X64 ASM L1 .

This is a somewhat large function (in contrast to the other exercises in this blog), but heavily used nowadays in various software. As it can be clearly seen, it uses standard C/C++ functions including strlen() and sscanf(). Some other helper function is also used. I intentionally gave it this name to conceal its real function. So what does the whole code snippet do?

GCC 4.8.2 with -Os option (generate smallest possible code):


helper:
        lea     edx, [rdi-48]
        mov     eax, 1
        cmp     edx, 9
        jbe     .L2
        and     edi, -33
        xor     eax, eax
        sub     edi, 65
        cmp     edi, 5
        setbe   al
.L2:
        ret
.LC0:
        .string "%2x"
f:
        push    r15
        xor     eax, eax
        or      rcx, -1
        push    r14
        push    r13
        push    r12
        mov     r12, rsi
        push    rbp
        mov     rbp, rsi
        push    rbx
        mov     rbx, rdi
        sub     rsp, 24
        repnz scasb
        not     rcx
        lea     r14, [rbx-1+rcx]
.L6:
        cmp     rbx, r14
        ja      .L24
        movsx   eax, BYTE PTR [rbx]
        lea     r13, [rbx+1]
        mov     r15, r13
        cmp     eax, 43
        mov     DWORD PTR [rsp+12], eax
        jne     .L7
        mov     DWORD PTR [rsp+12], 32
        jmp     .L8
.L7:
        cmp     eax, 37
        jne     .L8
        movsx   edi, BYTE PTR [rbx+1]
        call    helper
        test    eax, eax
        jne     .L9
.L11:
        or      eax, -1
        jmp     .L10
.L9:
        movsx   edi, BYTE PTR [rbx+2]
        lea     r13, [rbx+3]
        call    helper
        test    eax, eax
        je      .L11
        lea     rdx, [rsp+12]
        xor     eax, eax
        mov     esi, OFFSET FLAT:.LC0
        mov     rdi, r15
        call    __isoc99_sscanf
        test    eax, eax
        je      .L11
.L8:
        test    r12, r12
        je      .L12
        mov     eax, DWORD PTR [rsp+12]
        mov     BYTE PTR [rbp+0], al
.L12:
        inc     rbp
        mov     rbx, r13
        jmp     .L6
.L24:
        mov     eax, ebp
        sub     eax, r12d
.L10:
        add     rsp, 24
        pop     rbx
        pop     rbp
        pop     r12
        pop     r13
        pop     r14
        pop     r15
        ret

GCC 4.9.3 for ARM64 with -Os option (generate smallest possible code):


helper:
        sub     w2, w0, #48
        mov     w1, 1
        cmp     w2, 9
        bls     .L2
        and     w0, w0, -33
        sub     w0, w0, #65
        cmp     w0, 5
        cset    w1, ls
.L2:
        mov     w0, w1
        ret
f:
        stp     x29, x30, [sp, -96]!
        add     x29, sp, 0
        stp     x19, x20, [sp, 16]
        stp     x21, x22, [sp, 32]
        mov     x19, x0
        mov     x21, x1
        adrp    x22, .LC0
        mov     x20, x21
        stp     x23, x24, [sp, 48]
        stp     x25, x26, [sp, 64]
        add     x22, x22, :lo12:.LC0
        bl      strlen
        mov     w25, 32
        add     x24, x19, x0
.L6:
        cmp     x19, x24
        bhi     .L23
        ldrb    w1, [x19]
        add     x23, x19, 1
        str     w1, [x29, 92]
        mov     x26, x23
        cmp     w1, 43
        bne     .L7
        str     w25, [x29, 92]
        b       .L8
.L7:
        cmp     w1, 37
        bne     .L8
        ldrb    w0, [x19, 1]
        bl      helper
        cbnz    w0, .L9
.L11:
        mov     w0, -1
        b       .L10
.L9:
        ldrb    w0, [x19, 2]
        add     x23, x19, 3
        bl      helper
        cbz     w0, .L11
        add     x2, x29, 92
        mov     x1, x22
        mov     x0, x26
        bl      __isoc99_sscanf
        cbz     w0, .L11
.L8:
        cbz     x21, .L12
        ldr     w0, [x29, 92]
        strb    w0, [x20]
.L12:
        add     x20, x20, 1
        mov     x19, x23
        b       .L6
.L23:
        sub     w0, w20, w21
.L10:
        ldp     x19, x20, [sp, 16]
        ldp     x21, x22, [sp, 32]
        ldp     x23, x24, [sp, 48]
        ldp     x25, x26, [sp, 64]
        ldp     x29, x30, [sp], 96
        ret
.LC0:
        .string "%2x"

(ARM) Optimizing Keil 5.05 (Thumb mode):


helper PROC
        MOVS     r1,r0
        SUBS     r1,r1,#0x30
        CMP      r1,#9
        BLS      |L0.20|
        SUBS     r1,r1,#0x31
        CMP      r1,#5
        BLS      |L0.20|
        SUBS     r0,r0,#0x41
        CMP      r0,#5
        BHI      |L0.24|
|L0.20|
        MOVS     r0,#1
        BX       lr
|L0.24|
        MOVS     r0,#0
        BX       lr
        ENDP

f PROC
        PUSH     {r3-r7,lr}
        MOVS     r6,r1
        MOVS     r4,r0
        BL       strlen
        ADDS     r7,r0,r4
        MOVS     r5,r6
        B        |L0.114|
|L0.44|
        LDRB     r0,[r4,#0]
        ADDS     r4,r4,#1
        CMP      r0,#0x2b
        STR      r0,[sp,#0]
        BEQ      |L0.60|
        CMP      r0,#0x25
        BEQ      |L0.66|
        B        |L0.104|
|L0.60|
        MOVS     r0,#0x20
        STR      r0,[sp,#0]
        B        |L0.104|
|L0.66|
        LDRB     r0,[r4,#0]
        ADDS     r4,r4,#1
        BL       helper
        CMP      r0,#0
        BEQ      |L0.122|
        LDRB     r0,[r4,#0]
        ADDS     r4,r4,#1
        BL       helper
        CMP      r0,#0
        BEQ      |L0.122|
        SUBS     r0,r4,#2
        MOV      r2,sp
        ADR      r1,|L0.128|
        BL       __0sscanf
        CMP      r0,#0
        BEQ      |L0.122|
|L0.104|
        CMP      r6,#0
        BEQ      |L0.112|
        LDR      r0,[sp,#0]
        STRB     r0,[r5,#0]
|L0.112|
        ADDS     r5,r5,#1
|L0.114|
        CMP      r4,r7
        BLS      |L0.44|
        SUBS     r0,r5,r6
        POP      {r3-r7,pc}
|L0.122|
        MOVS     r0,#0
        MVNS     r0,r0
        POP      {r3-r7,pc}
        ENDP

|L0.128|
        DCB      "%2x",0

(ARM) Optimizing Keil 5.05 (ARM mode):


helper PROC
        SUB      r1,r0,#0x30
        CMP      r1,#9
        SUBHI    r1,r0,#0x61
        CMPHI    r1,#5
        BLS      |L0.36|
        SUB      r0,r0,#0x41
        CMP      r0,#5
        MOVHI    r0,#0
        BXHI     lr
|L0.36|
        MOV      r0,#1
        BX       lr
        ENDP

f PROC
        PUSH     {r3-r7,lr}
        MOV      r6,r1
        MOV      r4,r0
        BL       strlen
        ADD      r7,r0,r4
        MOV      r5,r6
|L0.68|
        CMP      r4,r7
        SUBHI    r0,r5,r6
        BHI      |L0.192|
        LDRB     r0,[r4],#1
        CMP      r0,#0x2b
        STR      r0,[sp,#0]
        MOVEQ    r0,#0x20
        STREQ    r0,[sp,#0]
        BEQ      |L0.168|
        CMP      r0,#0x25
        BNE      |L0.168|
        LDRB     r0,[r4],#1
        BL       helper
        CMP      r0,#0
        BEQ      |L0.188|
        LDRB     r0,[r4],#1
        BL       helper
        CMP      r0,#0
        BEQ      |L0.188|
        MOV      r2,sp
        ADR      r1,|L0.196|
        SUB      r0,r4,#2
        BL       __0sscanf
        CMP      r0,#0
        BEQ      |L0.188|
|L0.168|
        CMP      r6,#0
        LDRNE    r0,[sp,#0]
        STRBNE   r0,[r5,#0]
        ADD      r5,r5,#1
        B        |L0.68|
|L0.188|
        MVN      r0,#0
|L0.192|
        POP      {r3-r7,pc}
        ENDP

|L0.196|
        DCB      "%2x",0

GCC 4.4.5 for MIPS with -Os option (generate smallest possible code):


helper:
        addiu   $2,$4,-48
        sltu    $2,$2,10
        bne     $2,$0,$L7
        li      $2,1                    # 0x1

        addiu   $2,$4,-97
        sltu    $2,$2,6
        bne     $2,$0,$L2
        addiu   $4,$4,-65

        j       $31
        sltu    $2,$4,6
$L2:
        li      $2,1                    # 0x1
$L7:
        j       $31
        nop

$LC0:
        .ascii  "%2x\000"
f:
        lui     $28,%hi(__gnu_local_gp)
        addiu   $sp,$sp,-72
        addiu   $28,$28,%lo(__gnu_local_gp)
        sw      $31,68($sp)
        sw      $fp,64($sp)
        sw      $23,60($sp)
        sw      $22,56($sp)
        sw      $21,52($sp)
        sw      $20,48($sp)
        sw      $19,44($sp)
        sw      $18,40($sp)
        sw      $17,36($sp)
        sw      $16,32($sp)
        lw      $25,%call16(strlen)($28)
        move    $18,$5
        move    $16,$4
        jalr    $25
        lui     $23,%hi($LC0)

        addu    $fp,$16,$2
        addiu   $23,$23,%lo($LC0)
        move    $17,$18
        li      $22,43                  # 0x2b
        li      $21,37                  # 0x25
        addiu   $20,$sp,24
        b       $L9
        li      $19,32                  # 0x20

$L14:
        lb      $2,0($16)
        addiu   $16,$16,1
        bne     $2,$22,$L10
        sw      $2,24($sp)

        b       $L11
        sw      $19,24($sp)

$L10:
        bne     $2,$21,$L11
        nop

        lb      $4,0($16)
        jal     helper
        nop
        beq     $2,$0,$L15
        li      $2,-1                   # 0xffffffffffffffff
        lb      $4,1($16)
        jal     helper
        addiu   $16,$16,2

        lw      $28,16($sp)
        addiu   $4,$16,-2
        lw      $25,%call16(__isoc99_sscanf)($28)
        move    $5,$23
        beq     $2,$0,$L12
        move    $6,$20

        jalr    $25
        nop

        beq     $2,$0,$L15
        li      $2,-1                   # 0xffffffffffffffff

$L11:
        beq     $18,$0,$L13
        nop

        lw      $2,24($sp)
        nop
        sb      $2,0($17)
$L13:
        addiu   $17,$17,1
$L9:
        sltu    $2,$fp,$16
        beq     $2,$0,$L14
        subu    $2,$17,$18

        b       $L15
        nop

$L12:
        li      $2,-1                   # 0xffffffffffffffff
$L15:
        lw      $31,68($sp)
        lw      $fp,64($sp)
        lw      $23,60($sp)
        lw      $22,56($sp)
        lw      $21,52($sp)
        lw      $20,48($sp)
        lw      $19,44($sp)
        lw      $18,40($sp)
        lw      $17,36($sp)
        lw      $16,32($sp)
        j       $31
        addiu   $sp,$sp,72

More challenges: challenges.re; about solutions: challenges.re/#Solutions.