#------------------------------------------------------------------------------#
#                             - Challenge #3 -                                 #
#                                 by JaZZ                                      #
#------------------------------------------------------------------------------#

The program has several levels of protection:
1- integrity check.
2- no trivial access to registration menu.
3- no trivial comparison between serials.
4- "vital" strings are encrypted.
5- "Hidden" protection features.

This is, apart from the game itself which is imo very well designed (good
windoze progs are not so frequent !), quite a good protection, for a high level
language program. Hope that having included it in the strainer won't do any harm
to that guy as he's capable. Back to the topic. The 5th category is quite
unfair: for example you can't load a puzzle that's been created in another PC
with the program unregistered on it. May be there are several tricks of that
kind, i discovered this only one when showing the game a colleague at work, as
he tried to send me a puzzle by the network. As I said, cracking it is all the
more interesting as there ain't ANY "wide open doors" where you can get through.
Disassembling it with wdasm is ok, but the strings references lead to nothing
vital: the "Demo" references only the background of the image. You can disable
it, it won't reg the program. Furthermore this nasty author made a great "pied
de nez" to all crackers as he managed (i may be wrong, but i've never seen that
before ;-) to associate his name & copyright to every 00000001 that appears in
the listing. Well done Mr Trujillos, 1 to 0, we'll see your damned name at least
a thousand times, but we're not dead though. Of course you can remove them with
your editor, but dont try to use wdasm after as it'll be fooled. Anyway it's
only a detail. Our tools will be Softice and Wdasm, as usual.

			     -------------------

1) At first let's access the registration process. It can be a box, or a file
that you are emailed with for example. Checking the file accesses with filemon
doesn't show anything suspicious, it must be a box triggered by a special
keystroke. Let's call it zen or anything else (non academic approach...), I
tried every function key combined with alt,ctrl etc...and CTRL F8 triggered it.
Pack, name, id, key, nothing less than 4 fields to fill. At this point i
recalled that the challenge was to explain the scheme, NOT to make a keygen so i
didn't delve into "serial" manipulation and tracking at this moment, supposing
this guy clever enough to have used a heavy encryption process. So where to
start then? A very uncommon idea: let's type in some bogus stuff. We get a very
common messagebox "Seems that the data etc....". Ok. With Sice you discover the
main "registration box" routine (i dump just the end):

:0046B455 E89BB6FEFF              call 00456AF5 ---> check what you entered
:0046B45A 8BF8                    mov edi, eax
:0046B45C 85FF                    test edi, edi
:0046B45E 0F8585000000            jne 0046B4E9  ----> if eax!=0 you get out of
the loop
:0046B464 837DFC00                cmp dword ptr [ebp-04], 00000000
:0046B468 752D                    jne 0046B497   ---> it was bogus, go to
messagebox
:0046B46A C745FC01000000          mov [ebp-04], 00000001
:0046B471 6A02                    push 00000002
:0046B473 8D45C4                  lea eax, dword ptr [ebp-3C]
:0046B476 50                      push eax
:0046B477 E88F9CFAFF              call 0041510B
:0046B47C 6A02                    push 00000002
:0046B47E 8D55DC                  lea edx, dword ptr [ebp-24]
:0046B481 52                      push edx
:0046B482 E8849CFAFF              call 0041510B
:0046B487 6A02                    push 00000002
:0046B489 8D4DF0                  lea ecx, dword ptr [ebp-10]
:0046B48C 51                      push ecx
:0046B48D E8799CFAFF              call 0041510B
:0046B492 E968FDFFFF              jmp 0046B1FF  ---> give it a try again!

; error: messagebox
:0046B497 83C4FC                  add esp, FFFFFFFC
:0046B49A 66C704242E02            mov word ptr [esp], 022E -> index for
"Seems that the data..."
:0046B4A0 E803E8FCFF              call 00439CA8
:0046B4A5 50                      push eax
:0046B4A6 FF35D4974800            push dword ptr [004897D4]
:0046B4AC 6810200000              push 00002010
:0046B4B1 53                      push ebx
:0046B4B2 E8676CFBFF              call 0042211E  -> call messageboxa
:0046B4B7 837DF800                cmp dword ptr [ebp-08], 00000000
:0046B4BB 7507                    jne 0046B4C4
:0046B4BD BF7C150000              mov edi, 0000157C
:0046B4C2 EB05                    jmp 0046B4C9

			     -------------------

2) Up to this point you can either enter the 456AF5 routine, i didn't do it at
first as i was believing a lot of calls were involved. Infortunately it wasn't
true, and sure it would have been easier to look closer at this snippet, BUT
things always look easy once you've understand. That's why I tried another
direction. I just wanted to follow this idea to proof that with just a little
weakness the prog could be cracked. Look at the process that leads to the
messagebox. We notice that the adress of the string is calculated, with some
kind of "index". here it is 22E that through 439CA8 leads to the correct adress
in memory. In return of this call, eax holds the adress of the string that'll
be pushed for messagebox. for 22E the adress calculated is: 4A11F3. Then just
look around this area with sice: it's simply the whole array of every
interesting string used by bbrk, in addition they're fully decrypted. First
error from the author, he should have dispatched them, or better, decrypted
only if necessary. Sniffin' around only TWO strings appealed to me:
		 "Thank you!" "Registration code detected"
Lets choose the first. Its adress is 4A1301. My aim is to search the index
that'll give this adress through the call 439CA8. A good old bruteforce attack:
assemble this little routine "live" with sice:

	xor eax,eax
adr:	inc eax
	push eax
	add esp,-4
	mov word ptr[esp],ax
	call 439CA8
	cmp eax,4A1301
	pop eax
	jnz adr
ok:	; just bpx here!
It'll break instantly with 0231 in eax (unique solution). So back to the dead
listing. Let's search for the ", 0231" pattern in it: Only one match at 45CA36,
a very stimulating result! The corresponding routine obviously starts in 45C9AD.
Very disapointing that wdasm doesn't reference it though. Must be indirectly
called (call [ebx+nn] or similar). It is neither hardcoded (with a push) so it's
in a table and this will charge us with some extra work. With Sice again and
bbrk loaded, let's search the above table with s 30:0 l ffffffff AD C9 45 00.
Once again just one hit: 4852D4. Then same process again, search ", 004852D4"
with the editor. Two hits this time:
this is the first one:
* Referenced by a CALL at Address:
|:00456E04 -----> ****** THIS IS IMPORTANT ******
|
:0045C755 55                      push ebp
:0045C756 8BEC                    mov ebp, esp
:0045C758 83C488                  add esp, FFFFFF88
:0045C75B 53                      push ebx
:0045C75C 56                      push esi
:0045C75D 57                      push edi
:0045C75E 8B5D08                  mov ebx, dword ptr [ebp+08]
:0045C761 6A00                    push 00000000
:0045C763 53                      push ebx
:0045C764 E8DC2BFBFF              call 0040F345
:0045C769 C703D4524800            mov dword ptr [ebx], 004852D4  --> HERE !
etc.....
No matter what the second hit could be, Have you seen that it's referenced by a
call in 456E04 ? This is deep into the 456AF5 "password checking" routine. So
now it's time to have a look at it, and it'll be easier as we are SURE that to
register, the processor must reach 456E04.

Let's go then. At first sight all the: jmp 00457055 are EVIL, as they get (too
quickly...) out of it with eax=0 (remember eax mustn't be 0 when returning).
tracing with sice while entering bogus, you'll be kicked but not at the
beginning though. Summary of the strategic jumps:

:00456BA9 751B                    jne 00456BC6  ---> jump (ok)
:00456BF8 7526                    jne 00456C20  ---> jump (ok)
:00456C4F 7531                    jne 00456C82  ---> jump (ok)
:00456D31 E8363D0100              call 0046AA6C
:00456D36 85C0                    test eax, eax
:00456D38 741B                    je 00456D55   ---> jump (bad for us...)
after this jmp, eax will be set to 0 and this will kick us out in 456DC9. So
this 46AA6C routine is undoubtly the faulty one. Here's what it does:

:0046AA6C 55                      push ebp
:0046AA6D 8BEC                    mov ebp, esp
:0046AA6F 8B4508                  mov eax, dword ptr [ebp+08]
:0046AA72 8B00                    mov eax, dword ptr [eax]
:0046AA74 3B0590994800            cmp eax, dword ptr [00489990]
:0046AA7A 0F94C2                  sete dl
:0046AA7D 83E201                  and edx, 00000001
:0046AA80 8BC2                    mov eax, edx
:0046AA82 5D                      pop ebp
:0046AA83 C20400                  ret 0004
In short it returns 1 (the good_boy value) if [adress_pushed]=[489990].

Looking closer near this interesting call, we see that in fact there are two:

:00456D23 8D55C0                  lea edx, dword ptr [ebp-40]
:00456D26 52                      push edx
:00456D27 53                      push ebx
:00456D28 8B0B                    mov ecx, dword ptr [ebx]
:00456D2A FF5108                  call [ecx+08]
:00456D2D 8D45C0                  lea eax, dword ptr [ebp-40]
:00456D30 50                      push eax
:00456D31 E8363D0100              call 0046AA6C  ----> FIRST NICE_BUYER TEST
:00456D36 85C0                    test eax, eax
:00456D38 741B                    je 00456D55    ----> get out!
:00456D3A 8D55BC                  lea edx, dword ptr [ebp-44]
:00456D3D 52                      push edx
:00456D3E 6A00                    push 00000000
:00456D40 6A00                    push 00000000
:00456D42 53                      push ebx
:00456D43 8B0B                    mov ecx, dword ptr [ebx]
:00456D45 FF5110                  call [ecx+10]
:00456D48 8D45BC                  lea eax, dword ptr [ebp-44]
:00456D4B 50                      push eax
:00456D4C E81B3D0100              call 0046AA6C  ----> SECOND ONE.
:00456D51 85C0                    test eax, eax
:00456D53 7504                    jne 00456D59   ----> nice buyer!

So we just want eax to be non zero when returning 46AA6C. We'll change then:
:0046AA7D 83E201                  and edx, 00000001
to:
	  6A 01 		  push 01
	  5A			  pop edx
At first with a "live" patch, while bpx-ing on 46AA6C. A nice box pops up with
our "Thank you!" string in it (no field should be empty though) and it seems
regged... Try a puzzle, the "demo" background has disapeared, no more reminder
box anymore. Ok, now we try to hard patch, and we're stuck with a CRC check :
"content seems to be altered...." This shouldn't be too hard, with the
messagebox you'll easily find the dedicated
routine:
:00442CC2 E870DBFFFF              call 00440837  ---> checksum routine
:00442CC7 3D22334455              cmp eax, 55443322 ---> good boy value
:00442CCC 7472                    je 00442D40   ----> exe not altered
				  ;messagebox("sucker!")
				
Having a look at 440837, we quickly find that the good boy test is here: (yes we
could have set the je to jmp in 442CCC, but who knows, may be it's called
elsewhere, even if wdasm doesn't reference it)

:00440DAE E8B504FCFF              call 00401268
:00440DB3 83C40C                  add esp, 0000000C
:00440DB6 85C0                    test eax, eax
:00440DB8 752E                    jne 00440DE8   ---> this is the faulty one!                             
:00440DBA A1803B4800              mov eax, dword ptr [00483B80]
:00440DBF 8B10                    mov edx, dword ptr [eax]
:00440DC1 8B0D243B4800            mov ecx, dword ptr [00483B24]
:00440DC7 8911                    mov dword ptr [ecx], edx
:00440DC9 B822334455              mov eax, 55443322  ----> nice value...

Just change a single byte:
:00440DB6 85C0                    test eax, eax	
to:
	  33C0			  xor eax,eax

When you try to register, the program will write an entry in the bbrk.ini file,
where sections are defined according to the pack field. You can see then that
the guy is always checking if you're a nice buyer or not. Just bpx 46AA6C...
The release is now 2.3 (09/98), and the protection in this one is less simple.
He doesn't check a simple flag anymore. This decided me to look deeper at the
encryption scheme. But by now this is almost the deadline, only 2 days left, i
couldn't manage to break it totally. Please have a look at braincrypt.txt for a
little discussion of the encryption system.

				------------------

3) Finally let's enable the possibility to play every puzzle, even those created
with an "unregged" computer. (when creating a puzzle, a header holding your
"registration info" will be included in the file, program has just to check it
when loading). With a little research we find the"loading" call:
:00445CA4 E8B9E1FFFF              call 00443E62	
the routine begins at 445ABC. tracing through it with sice, comparing between a
good and a bad puzzle, you'll see that the evil jump is:

:00445C1E E8ED390200              call 00469610
:00445C23 3B45E8                  cmp eax, dword ptr [ebp-18]
:00445C26 743B                    je 00445C63 ---> regged user.
:00445C28 68EE030000              push 000003EE
:00445C2D 6A00                    push 00000000
:00445C2F 6A00                    push 00000000
:00445C31 8D4DFC                  lea ecx, dword ptr [ebp-04]
:00445C34 51                      push ecx
:00445C35 E86243FDFF              call 00419F9C
:00445C3A 8D45FC                  lea eax, dword ptr [ebp-04]
:00445C3D 50                      push eax
:00445C3E 56                      push esi
:00445C3F E8DD40FDFF              call 00419D21
:00445C44 8BC6                    mov eax, esi
:00445C46 50                      push eax
:00445C47 6A02                    push 00000002
:00445C49 8D55EC                  lea edx, dword ptr [ebp-14]
:00445C4C 52                      push edx
:00445C4D E8B9F4FCFF              call 0041510B
:00445C52 6A02                    push 00000002
:00445C54 8D4DFC                  lea ecx, dword ptr [ebp-04]
:00445C57 51                      push ecx
:00445C58 E83441FDFF              call 00419D91
:00445C5D 58                      pop eax
:00445C5E E98A000000              jmp 00445CED ---> exit

so we'll change one byte:
:00445C26 743B                    je 00445C63
to 	  EB3B			  jmp  445C63

Frow now on, every puzzle will be loaded.

The patcher has been designed to be tested on bbrk.(nb: whenever patched you 
must go through the CTRL F8 process and enter bogus (no empty fields).

#------------------------------------------------------------------------------#
