Solution-vik3790-little-fish

From aldeid
Jump to navigation Jump to search

Challenge

The objective of this challenge is to find a valid combination of username and password and then develop a keygen.

The executable has the following properties:

MD5 fc530bf50dd540084f08b7c66548ab0f
SHA1 1f0ecfa05146fb822c6d169fac1f841ed7af21d4
SHA256 6856d40d366a4e2e56214b66d2a71e16bf03a24ff79193c62c7e0d9dc2df2e83
Type PE32 executable (GUI) Intel 80386, for MS Windows

When started, the program shows a window as follows but not login/password form is displayed:

The main window

WinMain

At the end of the main function, we can see a call to WinMain at offset 0x402016:

.text:00401FF4 loc_401FF4:             ; lpModuleName
.text:00401FF4 mov     [esp+74h+lpStartupInfo], 0
.text:00401FFB call    _GetModuleHandleA@4 ; GetModuleHandleA(x)
.text:00402000 sub     esp, 4
.text:00402003 mov     [esp+74h+nShowCmd], esi ; nShowCmd
.text:00402007 mov     [esp+74h+lpCmdLine], ebx ; lpCmdLine
.text:0040200B mov     [esp+74h+hPrevInstance], 0 ; hPrevInstance
.text:00402013 mov     [esp+74h+lpStartupInfo], eax ; hInstance
.text:00402016 call    _WinMain@16     ; WinMain(x,x,x,x)

The WinMain function is actually creating a dialog box with DlgMain:

.text:0040151D push    ebp
.text:0040151E mov     ebp, esp
.text:00401520 sub     esp, 28h
.text:00401523 mov     eax, [ebp+hInstance]
.text:00401526 mov     ds:_hInst, eax
.text:0040152B call    _InitCommonControls@0 ; InitCommonControls()
.text:00401530 mov     eax, ds:_hInst
.text:00401535 mov     [esp+28h+dwInitParam], 0 ; dwInitParam
.text:0040153D mov     [esp+28h+lpDialogFunc], offset __Z7DlgMainP6HWND__jjl@16 ; lpDialogFunc
.text:00401545 mov     [esp+28h+hWndParent], 0 ; hWndParent
.text:0040154D mov     [esp+28h+lpTemplateName], 64h ; lpTemplateName
.text:00401555 mov     [esp+28h+var_28], eax ; hInstance
.text:00401558 call    _DialogBoxParamA@20 ; DialogBoxParamA(x,x,x,x,x)
.text:0040155D sub     esp, 14h
.text:00401560 leave
.text:00401561 retn    10h

DlgMain

In this function, we can see that the left and right click on the mouse have counters associated. Each time one of these buttons are clicked, the function __Z6Clicksv is called.

.text:004014AB loc_4014AB:                             ; CODE XREF: _Z7DlgMainP6HWND__jjl(x,x,x,x)+15�j
.text:004014AB                 cmp     eax, WM_LBUTTONUP ; left click
.text:004014B0                 jz      short loc_4014BB
.text:004014B2                 cmp     eax, WM_RBUTTONUP ; right click
.text:004014B7                 jz      short loc_4014D2
.text:004014B9                 jmp     short loc_401514
.text:004014BB ; ---------------------------------------------------------------------------
.text:004014BB
.text:004014BB loc_4014BB:                             ; CODE XREF: _Z7DlgMainP6HWND__jjl(x,x,x,x)+2A�j
.text:004014BB                 mov     eax, ds:_CounterL
.text:004014C0                 inc     eax             ; increments counter left
.text:004014C1                 mov     ds:_CounterL, eax
.text:004014C6                 call    __Z6Clicksv     ; Clicks(void)
.text:004014CB                 mov     eax, 1
.text:004014D0                 jmp     short locret_401519
.text:004014D2 ; ---------------------------------------------------------------------------
.text:004014D2
.text:004014D2 loc_4014D2:                             ; CODE XREF: _Z7DlgMainP6HWND__jjl(x,x,x,x)+31�j
.text:004014D2                 mov     eax, ds:_CounterR
.text:004014D7                 inc     eax             ; increments counter right
.text:004014D8                 mov     ds:_CounterR, eax
.text:004014DD                 call    __Z6Clicksv     ; Clicks(void)
.text:004014E2                 mov     eax, 1
.text:004014E7                 jmp     short locret_401519

__Z6Clicksv

In this function, we can see that another window (RegisterDlg) will be displayed if the left button on the mouse is clicked 3 times and the right button is clicked 2 times:

.text:00401564                 push    ebp
.text:00401565                 mov     ebp, esp
.text:00401567                 sub     esp, 28h
.text:0040156A                 mov     eax, ds:_CounterL
.text:0040156F                 cmp     eax, 3          ; left button clicked 3 times
.text:00401572                 jnz     short locret_4015C2
.text:00401574                 mov     eax, ds:_CounterR
.text:00401579                 cmp     eax, 2          ; right button clicked 2 times
.text:0040157C                 jnz     short locret_4015C2
.text:0040157E                 mov     eax, ds:_hInst
.text:00401583                 mov     [esp+28h+dwInitParam], 0 ; dwInitParam
.text:0040158B                 mov     [esp+28h+lpDialogFunc], offset __Z11RegisterDlgP6HWND__jjl@16 ; lpDialogFunc
.text:00401593                 mov     [esp+28h+hWndParent], 0 ; hWndParent
.text:0040159B                 mov     [esp+28h+lpTemplateName], 66h ; lpTemplateName
.text:004015A3                 mov     [esp+28h+hInstance], eax ; hInstance
.text:004015A6                 call    _DialogBoxParamA@20 ; DialogBoxParamA(x,x,x,x,x)
.text:004015AB                 sub     esp, 14h
.text:004015AE                 mov     ds:_CounterL, 0
.text:004015B8                 mov     ds:_CounterR, 0
.text:004015C2
.text:004015C2 locret_4015C2:                          ; CODE XREF: Clicks(void)+E�j
.text:004015C2                                         ; Clicks(void)+18�j
.text:004015C2                 leave
.text:004015C3                 retn

The authentication form

Appearance

Let's click 3 times on the left button of the mouse in the main window and 2 times on the right button. As expected, here is the new window that appears:

RegisterDlg

As shown below, the __Z8CheckingPcS_ should return 1 to jump to the "good boy".

__Z8CheckingPcS_

Function Layout

Below is the function layout:

Initialization

Nothing special here; counters are set to 0:

.text:004015C4 push    ebp
.text:004015C5 mov     ebp, esp
.text:004015C7 sub     esp, 28h
.text:004015CA mov     [ebp+var_C], 0
.text:004015D1 mov     [ebp+counter_i], 0
.text:004015D8 jmp     short loc_401603

Main loop

We can see the below transformations in the main loop, applied to the first 4 characters of the username provided by the user:

.text:004015DA loc_4015DA:
.text:004015DA                 mov     edx, [ebp+counter_i] ;   \
.text:004015DD                 mov     eax, [ebp+my_username] ; |
.text:004015E0                 add     eax, edx        ;        |
.text:004015E2                 mov     al, [eax]       ;        |
.text:004015E4                 movsx   eax, al         ;        |
.text:004015E7                 mov     [ebp+var_14], eax ;      / var_14 = my_username[i]
.text:004015EA                 mov     eax, 3          ; eax = 3
.text:004015EF                 sub     eax, [ebp+counter_i] ; eax = 3 - i
.text:004015F2                 shl     eax, 3          ; eax = eax << 3 (equivalent to eax *= 8)
.text:004015F5                 mov     cl, al          ; cl = al
.text:004015F7                 shl     [ebp+var_14], cl ; var_14 = var_14 << cl
.text:004015FA                 mov     eax, [ebp+var_14] ; eax = var_14
.text:004015FD                 or      [ebp+var_C], eax ; var_C |= eax
.text:00401600                 inc     [ebp+counter_i] ; i += 1
.text:00401603
.text:00401603 loc_401603:
.text:00401603                 cmp     [ebp+counter_i], 3 ; repeat until i > 3
.text:00401603                                         ; (first 4 characters of username)
.text:00401607                 setle   al
.text:0040160A                 test    al, al
.text:0040160C                 jnz     short loc_4015DA

We can simplify these transformations as follows:

var_C |= ord(my_username[i]) << (3 - i) * 8

Final transformation

The final transformation code is as follows:

.text:0040160E                 mov     edx, [ebp+var_C] ; edx = var_C
.text:00401611                 mov     eax, edx        ; eax = var_C
.text:00401613                 shl     eax, 1          ; eax = eax << 1 (equivalent to eax *= 2)
.text:00401615                 add     eax, edx        ; eax += edx
.text:00401617                 lea     edx, ds:0[eax*4] ; edx = eax * 4
.text:0040161E                 add     eax, edx        ; eax += edx
.text:00401620                 mov     [ebp+var_C], eax ; var_C = eax
.text:00401623                 add     [ebp+var_C], 0FFh ; var_C += 0xFF
.text:0040162A                 mov     eax, [ebp+var_C]
.text:0040162D                 mov     [esp+28h+var_20], eax ; var_20 = var_C
.text:00401631                 mov     [esp+28h+var_24], offset aIx ; '%IX': Long unsigned hexadecimal
.text:00401631                                         ; integer in uppercase
.text:00401639                 mov     eax, [ebp+my_username]
.text:0040163C                 mov     [esp+28h+Str1], eax ; LPSTR
.text:0040163F                 call    _wsprintfA      ; hexadecimal value
.text:00401644                 mov     eax, [ebp+password]
.text:00401647                 mov     [esp+28h+var_24], eax ; Str2
.text:0040164B                 mov     eax, [ebp+my_username]
.text:0040164E                 mov     [esp+28h+Str1], eax ; Str1
.text:00401651                 call    _strcmp         ; compare password with hex value based
.text:00401651                                         ; on first 4 characters of my_username
.text:00401656                 test    eax, eax
.text:00401658                 jnz     short loc_401661

Here are the transformations and simplifications:

Code eax edx
edx = eax = var_C var_C var_C
eax *= 2 var_C * 2 var_C
eax += edx (var_C * 2) + var_C var_C
edx = eax * 4 var_C * 3 var_C * 3 * 4
eax += edx var_C * 3 + var_C * 12 var_C * 12
var_C = eax var_C * 15 var_C * 12
var_C += 0xFF var_C * 15 + 0xFF var_C * 12

Solution

Below is the code of my keygen:

#!/usr/bin/env python
import sys

def keygen(my_username):
    var_C = 0

    for (i, c) in enumerate(my_username[:4]):
        var_C |= ord(c) << (3 - i) * 8

    var_C = var_C * 15 + 0xFF & 0xFFFFFFFF

    return var_C

if __name__ == '__main__':
    if len(sys.argv) < 2:
        print "Usage: %s <username>" % sys.argv[0]
        sys.exit(1)
    
    print "USERNAME: %s" % sys.argv[1]
    print "PASSWORD: %X" % keygen(sys.argv[1])

Here below is the solution for the username "aldeid":

$ ./keygen.py aldeid
USERNAME: aldeid
PASSWORD: B559E2EA

Comments

Keywords: assembly x86 reverse-engineering crackme vik3790 littlefish