R!SC's Solution to Duelist's Crackme #3 -- http://csir.cjb.net -- risc@notme.com :)

Difficulty level : 5/10 (probably the toughest crack i have done)

Tools Needed : Symantec Resource Workshop 1.0
             : W32Dasm
		     : Hex WorkShop
		     : Tasm
		     : Softice
		     : Efnet :) (optional)
			 

First off (well, after running the crackme, and trying a few random combinations), i loaded
due-cm3.exe into W32Dasm, scrolling through the code, i soon found this bit...

the important code...ESI points to button check order array thingy

:00401127 0FBE8EFE204000          movsx ecx, byte ptr [esi+004020FE]
:0040112E 83F94D                  cmp ecx, 0000004D	<-- 4D is like a NULL terminator, also used
:00401131 742F                    je 00401162		  - for the last bit of maths
:00401133 890D5E214000            mov dword ptr [0040215E], ecx	<-- save the current button iD
:00401139 51                      push ecx			<-- button iD
:0040113A FF7508                  push [ebp+08]		<-- dialog box handle

* Reference To: USER32.IsDlgButtonChecked, Ord:0000h
                                  |
:0040113D E8D0010000              Call 00401312
:00401142 46                      inc esi			<-- Counter, points to next button,
:00401143 83F800                  cmp eax, 00000000	  - and used in the maths
:00401146 74DF                    je 00401127		<-- Loop until one is found checked...
:00401148 A15E214000              mov eax, dword ptr [0040215E]		 <-- Our checked box iD
:0040114D 0FBE8EFE204000          movsx ecx, byte ptr [esi+004020FE] <-- Next button iD
:00401154 0FAFC1                  imul eax, ecx		<-- Multiply next button iD with current one
:00401157 0FAFC6                  imul eax, esi		<-- Multiply count with answer
:0040115A 010562214000            add dword ptr [00402162], eax	<-- Add it to our magic number
:00401160 EBC5                    jmp 00401127

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401131(C)
|
:00401162 A162214000              mov eax, dword ptr [00402162]	<-- Our final magic number..
:00401167 6BC04D                  imul eax, 0000004D
:0040116A 3D6654F300              cmp eax, 00F35466		<-- Magic number we have to get...


So, from this, we know we can bpx IsDlgButtonChecked, to make softice break at the routine
which does the checking. After returning from USER32.IsDlgButtonChecked, if eax is NULL, the
button wasnt checked, and it loops back to get the next iD, if eax != 0, the button is
checked, and it does some maths on it

MAGIC NUMBER = MAGIC NUMBER + (Current box iD * Next box iD * Button counter)

After the last button, it puts our MAGIC NUMBER into eax, multiplys it by 4D, then compares
it against the predifined number we have to get, F35466.. for the sake of it, to save some 
maths, F35466 / 4D = 328FE (the number i finally use to figure out the correct order of ticks)

At the start of the routine, it loads ESI with the check order of the buttons, displaying the
memory at [esi+004020FE] (when ESI==0) we get this information

---button iD check order---

004020FE 16 49 5E 15 27 26 21 25 1D 59 53 37 31 48 5D 0C 61 52 4D
    ESI== 0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f 10 11 --
    my id 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18   (9*2)

This means bugger all to us, because we dont know which number represents which check box on
the screen. We have to use a resource editor, to look at the dialog box resources, and find out
which box uses which iD..

I used Symantec Resource Editor 1.0, availble from http:\\protools.cjb.net (couldnt get BRW to 
load the exe) . So load due-cm3.exe into your resource editor, and click to edit the dialog...
After clicking on each button, starting from the top left, converting the iD into hex, then
writing them down, i got this information from it..

Buttons on screen
61 49 5E 16 25 26 21 59 53	; top row of check boxes

15 37 31 48 5D 0C 52 27 1D	; bottom row of check boxes 10-18

Okay, with all this information, we know what button gets checked when, and we still cant figure
out the correct order (can you do the maths in your head?)

My theory, to write a brute forcer, which will go through every possible combination you can
have, do the maths on them, and compare the result with 328FE (the correct MAGIC NUMBER / 4D)

90 minutes of coding later (i am real bad at this :) i got a result!!

Picture this in your head, 18 boxes, can be checked or unchecked, 0 or 1, imagine a binary
value, using 18 bits, to represent these boxes, we test each bit in the binary value, if its
0 it represents an unchecked box, if its 1, it represents a tick ;) we use a 1 bit binary value,
scrolling this to the left, bit by bit, and increase a counter, so we know which bit we are
checking (bit 0 through to 17), test a with b, if the bit is set, do the maths..

(see the comments i added to the source for the brute forcer..)

theory behind R!SC's Matrix Brute Forcer (r)

we have 18 check boxes, can be either 'checked' or 'unchecked' (1 or 0) 
apparantly, the amount of diff combo's is square of 18, 324???
so where i come up with 262,144 :)

we also have a way of testing single 'bits' in a value, by using 'TEST dest, src'
i use a 18bit binary value (well, 32bit binary value, but only use the TEST on the first
18 bits of it...) (i'll refer to this as my MAGIC NUMBER)

i start the MAGIC NUMBER with the first bit set, (01h) then do the maths, check the result,
if it doesnt find the correct answer, we increase the MAGIC NUMBER by 1, and check again....

examples of the MAGIC NUMBER, and how it represents the matrix of check boxes....

000000000000000001 = 01h = box 1 checked, 2-18 unckecked, simulate the maths, check the results
000000000000000010 = 02h = box 2 checked, 1,3-18 unchecked
000000000000000011 = 03h = box 1,2 checked, 3-18 unckecked
000000000000000100 = 04h = box 3 checked, 1,2,4-18 unchecked
000000000000000101
000000000000000110
000000000000000111 = 07h = box 1-3 checked, 4-18 unchecked...
000000000000001000
000000000000001001

101000110101000110 = 028d46h = box 2,3,7,9,11,12,16,18 checked
                               box 1,4,5,6,8,10,13,14,15,17 unchecked
111111111111111111 = 03ffffh = box 1-18 checked...

to find out if a bit is set or not, i use another 18bit (32bit :) value, with only one bit
set in it (i'll call this X)

TEST MAGIC NUMBER, X	; see if bit 'X' is set in the magic number
JNZ CHECKED				; if bit 'X' is not '0' jump to calculation routine

which will check bit X in the MAGIC NUMBER, and alter the ZERO flag accordingly
i.e, bit X is 0, zero flag is set, bit X is 1, zero flag is cleared...

X gets shifted to the left by 1 bit, the counter increased, check the counter, if its equal
to 18, we have checked every bit in the MAGIC NUMBER, and have to loop back to check our result
erm... still with me??

examples of X

000000000000000001 = bit 1 set = 01h, counter = 0
000000000000000010 = bit 2 set = 02h, counter = 1
000000000000000100 = bit 3 set = 04h, counter = 2
000000000000001000 = bit 4 set = 08h, counter = 3
000000000000010000 = bit 5 set = 10h, counter = 4
000000000000100000 = bit 6 set = 20h, counter = 5
000000000001000000 = bit 7 set = 40h, counter = 6
..................
001000000000000000 = bit 16 set = 08000h, counter = 15
010000000000000000 = bit 17 set = 10000h, counter = 16
100000000000000000 = bit 18 set = 20000h, counter = 17
bit gets shifted one more time, counter increased to 18,
counter gets checked, weve done, so loop back and check the answer...

okay, go study the source code
...
...
heh, you back already? try changing this line

:0040116A 3D6654F300              cmp eax, 00F35466	 

to read 

:0040116A 3D6E8BC000              cmp eax, 00C08B6E	; file offset 76A

and figure out the correct sequence :) 

(CHANGE ALREADY MADE IN 28026-DUE-CM3.EXE)
(SOLUTION IN TEST.ZIP)

R!SC 31st May 1999


