Solution-vik3790-little-fish
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