R!SC's Solution to Duelist's Crackme #3 (14千字)
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
=========================================================
; R!SC 191198
; asm stylee!!!
; <_risc> well, your a good bloke.. thx for the second opinion (can i have it in writing please..)
; <josephCo> haha
; <_risc> got it..
; <_risc> <josephCo> the total combinations are 2^18
; <_risc> <josephCo> which is 262144
; * josephCo writes "it's 2^18 possible combinations"
; * josephCo writes "which is 262144"
; <josephCo> :)
; <josephCo> there you go
; 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...
; R!SC's Matrix Brute Forcer for duelist's cm#3
; compile to a com file, tasm boo, tlink /t boo
; bpint 03 in sice.
; run the com..
; it breaks when it has found the pattern (about 1 second :)
; eax==duelist's magic number, ebx==my magic number...
; magic number it created is : 647E -- 110010001111110 in binary
; which means bit pattern : 0111111000100110000000 (yeah, reversed...)
; which means each bit thats a 1 is a checked box.. or something
; 0 1 1 1 1 1 1 0 0 0 1 0 0 1 1 0 0 0
;db 16h,49h,5Eh,15h,27h,26h,21h,25h,1Dh,59h,53h,37h,31h,48h,5Dh,0Ch,61h,52h,4Dh
; boxes 2,3,6,7,9,10,13,14,17 checked...
; buttons on screen
; id 61 49 5e 16 25 26 21 59 53
;bit was 0 1 1 0 0 1 1 0 1
; id 15 37 31 48 5d 0c 52 27 1d
; 1 0 0 1 1 0 0 1 0
.MODEL TINY
.CODE
.386
ORG 100h
start:
lea si, data
xor ecx,ecx
xor edx,edx
xor eax,eax
xor ebx,ebx
mov ebx, 01 ; we gonna inc ebx, which will add 1 bit to it each time
; 040000h=all 18 bits set, cant go no futher
jmp tryme@ ; try bit 1, before entering the loop which goes through all the other
; possible combinations
nextbits:
lea si, data ; data is the button iD array, in the mixed up order...
mov eax, dword ptr [temp] ; get our calculated number
cmp eax, 328feh ; and check it..
je gotit@@
xor eax,eax
mov dword ptr [temp], eax ; it wasnt right, so we reset it to 0 :)
inc ebx ; our 18bit value, inc ebx will make it go through every possible combination
cmp ebx, 040000h ; check if we have reached our limit.
je shit_fuck_damn ; shit fuck damn.. means that we have checked all possible
; combinations and not found our answer, we never want to jump here
tryme@:
mov eax, 01 ; gonna be our single bit , for checking which bit is set in EBX
xor edx,edx ; our iD counter
inc edx
loopy@:
test ebx, eax ; TEST MAGIC NUMBER, X
jnz callit ; JNZ CHECKED
still:
shl eax, 1 ; shift our bit to the left :)
inc edx ; increase the iD counter
inc si ; point data to next iD
cmp edx, 19 ; see if we have checked all 18 bits
je nextbits ; je next bit pattern, i.e. inc EBX
jmp loopy@ ; loop until finished
callit: ; bit X in EBX==1
pushad
call @1 ; do maths
popad
jmp still
@1:
mov al, byte ptr [si] ; current iD
mov cl, byte ptr [si+1] ; next iD
movsx eax, al ; clear rest of register
movsx ecx, cl ; " "
imul eax, ecx ; EAX==Current box iD * Next box iD
imul eax, edx ; EAX*=Button counter
add dword ptr [temp],eax ; MAGIC NUMBER = MAGIC NUMBER + EAX
ret
shit_fuck_damn:
mov eax, dword ptr [temp] ; bad news, either my code is wrong, or???
int 03
gotit@@:
mov eax, dword ptr [temp] ; temp==duelist's magic number
int 03 ; so EBX==our bit pattern
mov ax, 4C00h
int 21h
;_______________________________________________________________
temp dd 0
data db 16h,49h,5Eh,15h,27h,26h,21h,25h,1Dh,59h,53h,37h,31h,48h,5Dh,0Ch,61h,52h,4Dh
end start;
