Noodles KeyGen

by Harlequin

  February 2000

 
Target: Noodles-Crackme5.exe
Size: 20kb
Location: crackmes.cjb.net

 

  

Tools Used:

 W32Dasm V 8.93
Softice
 Text/Hex Editor
ExeScope

 

Introduction

Noodles crackme #5 is a serial number crackme with a lot of garbage code to distract from the real serial routine. We will determine a real serial number and then convert the target to display the real serial every time an incorrect serial is entered.

 

The Essay

First of all as always we run the target and enter a serial to see what happens. Whoaa some weird little mouse movements and then 5 messageboxes informing us that we entered the wrong serial.
So first of I opened the target in W32Dasm. Checked out the GetDlgItemTextA calls and scrolled down a little and it all looks a little to easy (apart from the calculation algo that is :-). Seeing all the 'Registered' strings and the 'GetWindowTextA' string I immediately decide that there has been some confusion thrown into this little program. So not to mess about I opened the target in ExeScope checked out the value for the 'test' button ID (3002d) converted it to hex (BBAh) then did a text search in W32Dasm for BBAh. There is only the one occurrence at:

:700011E1 817D10BA0B0000          cmp dword ptr [ebp+10], 00000BBA

This must be the button check. So follow the je and scroll down we see the mouse_event calls which make our mouse do that little dance, scroll past all of them to the jump at 700012E7 and take the jump. Take the next jump and we end up here:

:700012F3 68E8030000              push 000003E8
:700012F8 FF35B8210070 push dword ptr [700021B8]

* Reference To: USER32.GetDlgItem, Ord:0105h
|
:700012FE E8470B0000 Call 70001E4A
:70001303 6A64 push 00000064
:70001305 6887230070 push 70002387
:7000130A 50 push eax
:7000130B FF1583230070 call dword ptr [70002383]
:70001311 8BF8 mov edi, eax

 There are two of these calls and after each the retrieved handle is used in another indirect call. This looks like as good a place as any to start. So in softice place a call on GetDlgItem and run the target.
Softice breaks but unfortunatly not where we want it to, not to worry place a breakpoint on 700012FE, clear the GetDlgItem breakpoint and ctrl+D.
Enter your name and serial and click test, we dance about a little then softice breaks and would you look at that we have our two GetDlgItem calls and each is now followed by a GetWindowTextA call. The API handles for these calls were loaded using the GetProcAddress ;-).

So if we F10 past all the calls we can see our name and serial retrieved, so we place two breakpoints:

bpm 70002387 and bpm 700023EB so that we will break when the memory containing our info is accessed.
Ctrl+D and we break here:

:70001B29 F3            repz                             --- copy our name and # into 
:70001B2A A4 movsb --- address at edi
:70001B2B BEEB230070 mov esi, 700023EB
:70001B30 B900010000 mov ecx, 00000100
:70001B35 F3 repz
:70001B36 A4 movsb
:70001B37 33D2 xor edx, edx
:70001B39 8B3D7F230070 mov edi, dword ptr [7000237F]
:70001B3F 81C700050000 add edi, 00000500 --- point edi to some memory
:70001B45 B887230070 mov eax, 70002387 --- our name into eax
:70001B4A 42 inc edx --- function1
:70001B4B 33DB xor ebx, ebx --- operates on each character of our
:70001B4D 8A18 mov bl, byte ptr [eax] --- name
:70001B4F 03DA add ebx, edx
:70001B51 81F31F020000 xor ebx, 0000021F
:70001B57 C0C314 rol bl, 14
:70001B5A 83E30F and ebx, 0000000F
:70001B5D 80C330 add bl, 30
:70001B60 881F mov byte ptr [edi], bl --- placing result in address at edi
:70001B62 47 inc edi
:70001B63 40 inc eax --- end of function1
:70001B64 83FA04 cmp edx, 00000004 --- if we are on our fourth character
:70001B67 751A jne 70001B83 --- then enter function2
:70001B69 C6072D mov byte ptr [edi], 2D --- place a '-' character at position
:70001B6C 55 push ebp --- 5 of our edi string
:70001B6D 8B6FFC mov ebp, dword ptr [edi-04]
:70001B70 0FCD bswap ebp
:70001B72 C1C504 rol ebp, 04
:70001B75 81F501D10400 xor ebp, 0004D101
:70001B7B C1CD05 ror ebp, 05
:70001B7E 896FFC mov dword ptr [edi-04], ebp --- do some calcs place result back in
:70001B81 5D pop ebp --- edi. End function2
:70001B82 47 inc edi --- if we are on char 8 of our name
:70001B83 83FA08 cmp edx, 00000008 --- note:name length is not important
:70001B86 751D jne 70001BA5 --- enter function3
:70001B88 C6072D mov byte ptr [edi], 2D --- this is nearly identical to
:70001B8B 55 push ebp --- function 3
:70001B8C 8B6FFC mov ebp, dword ptr [edi-04]
:70001B8F 0FCD bswap ebp
:70001B91 C1C504 rol ebp, 04
:70001B94 81F501D10400 xor ebp, 0004D101
:70001B9A C1CD05 ror ebp, 05
:70001B9D 896FFC mov dword ptr [edi-04], ebp --- result into edi
:70001BA0 5D pop ebp
:70001BA1 47 inc edi
:70001BA2 83E806 sub eax, 00000006 --- go back 6 in name
:70001BA5 83FA0C cmp edx, 0000000C --- check if we have done 12 chars
:70001BA8 75A0 jne 70001B4A --- if not goto function 1
:70001BAA 55 push ebp --- function4 same as 2 and 3
:70001BAB 8B6FFC mov ebp, dword ptr [edi-04]
:70001BAE 0FCD bswap ebp
:70001BB0 C1C504 rol ebp, 04
:70001BB3 81F501D10400 xor ebp, 0004D101
:70001BB9 C1CD05 ror ebp, 05
:70001BBC 896FFC mov dword ptr [edi-04], ebp --- save result again
:70001BBF 5D pop ebp --- end function4
:70001BC0 8B3D7F230070 mov edi, dword ptr [7000237F] --- point edi to begining of our new
:70001BC6 81C700050000 add edi, 00000500 --- string
:70001BCC 55 push ebp
:70001BCD BEEB230070 mov esi, 700023EB --- our serial number
:70001BD2 8B2E mov ebp, dword ptr [esi] --- function 5
:70001BD4 0FCD bswap ebp --- same as 2/3/4 only all in one
:70001BD6 C1C504 rol ebp, 04 --- ie each set of 4 chars of our ser#
:70001BD9 81F501D10400 xor ebp, 0004D101 --- are manipulated
:70001BDF C1CD05 ror ebp, 05
:70001BE2 892E mov dword ptr [esi], ebp
:70001BE4 83C605 add esi, 00000005
:70001BE7 8B2E mov ebp, dword ptr [esi]
:70001BE9 0FCD bswap ebp
:70001BEB C1C504 rol ebp, 04
:70001BEE 81F501D10400 xor ebp, 0004D101
:70001BF4 C1CD05 ror ebp, 05
:70001BF7 892E mov dword ptr [esi], ebp
:70001BF9 83C605 add esi, 00000005
:70001BFC 8B2E mov ebp, dword ptr [esi]
:70001BFE 0FCD bswap ebp
:70001C00 C1C504 rol ebp, 04
:70001C03 81F501D10400 xor ebp, 0004D101
:70001C09 C1CD05 ror ebp, 05
:70001C0C 892E mov dword ptr [esi], ebp --- end of function5
:70001C0E 83EE0A sub esi, 0000000A --- esi to begining of converted ser#
:70001C11 B90C000000 mov ecx, 0000000C
:70001C16 F3 repz
:70001C17 A6 cmpsb --- cmp converted ser# to converted
:70001C18 5D pop ebp --- name. I don't have to tell you
:70001C19 85C9 test ecx, ecx --- they should be equal :-)
:70001C1B 7505 jne 70001C22

The above is all there is to the protection, and as you can see it is pretty simple if you ignore all the red herrings ;-)
From reading the above even if you are not an expert in assembler you should be able to divine your real serial number. Lets now make noodles crackme into it's own keygen.

We want to make a copy of the real serial before it is converted via functions 2/3/4 so probably the best place to do this is immediately after each character has been calculated at line 70001B60h. First we need to find some empty space to place our new code so ctrl+end in W32Dasm and we can see a few extra bytes at the end of the code section starting at : 70001E7Ah. However I am going to use 70001E80h because it is a round number and because of the number of bytes involved in jumping to this new location I am going to jump from 70001B5Dh.

So load the target into w32dasm and in the small window click 'goto address', type 70001B5Dh. Click 'patch code' and then enter:

:70001B5D E91E030000                    jmp 70001E80

to jump to our new location. If you have my patch installed click 'make permanent if not copy the bytes and go and edit them into the target with your hex editor. (you can get my patch at protools, look under w32dasm)

Next goto address 70001E80h and patch in the following:

:70001E80 80C330          add bl, 30                --- the two line we are replacing
:70001E83 881F mov byte ptr [edi], bl --- with our jump
:70001E85 50 push eax --- save eax
:70001E86 89F8 mov eax, edi --- copy edi to eax
:70001E88 2B057F230070 sub eax, dword ptr [7000237F] --- subtract the base address to find
:70001E8E 2D00050000 sub eax, 00000500 --- the current char position
:70001E93 0591210070 add eax, 70002191 --- messagebox text+character position
:70001E98 8818 mov byte ptr [eax], bl --- our serial char into message text
:70001E9A B895210070 mov eax, 70002195 --- location of first '-' char
:70001E9F 66C6002D mov byte ptr [eax], 2D --- place a '-' in it
:70001EA3 66C640052D mov [eax+05], 2D --- second '-' char
:70001EA8 66C6400A00 mov [eax+0A], 00 --- terminate the string
:70001EAD 58 pop eax --- restore eax
:70001EAE E9AFFCFFFF jmp 70001B62 --- carry on as normal

I appreciate that the above is not very efficient as the '-' chars are inserted every time a new character is processed, but hey it's just a quick solution and the original code was hardly efficient to begin with.
As the messagebox text is in the code section we will have to change the section attributes so that we can write to it. Open it in procdump and change the .CODE section from 60000020 to E0000020 to make it write enabled.

That's all there is to it, click 'make permanent' and run the new target and every time you enter an incorrect serial number the message box will give you the real serial number. Simple!!!

 

Final Notes

If you had tried tracing through the code in softice immediatly after the GetWindowTextA calls you would have found yourself buried within the system dll's. This is because noodle very cleverly uses the CreateThread call before he retrieves the edit box values. If you wanted to trace further with softice you would need to place a breakpoint on the code of this new thread at 70001337.

You should also note that you will (as I have left it) have to shut down the target and restart it to enter the new serial number. This is because the serial entry is a one shot deal due to the program self patching a hard jump after the checks. I have left this for you to find and change ;-)
Should you be wondering how the program managed to change the byte in the code section whilst we had to change the section attributes to do the same thing, you should check out VirtualProtect with an attribute of 40h in your API ref. Unfortuantly our patch was made before this call :-(

I doubt that patching is allowed on this target due to it being a serial protection but you could register the whole thing without touching a single byte by simply placing the hex value '12345678' in the registry.

Thanks go to:

 Muad'Dib for maintaining the crackmes site. I do not get as much time as I would like to spend on the many crackmes.

Noodle, for writing this very interesting little program. I have never seen the use of CreateThread to take the execution of program code outside of the normal flow, fascinating. I have some reading to do.

Everyone else who takes the time to write crackmes and solutions.

 

 mail AT Harlequin00 DOT cjb DOT net

Essay by:       Harlequin
Page Created: 13th February 2000