I don't use very often MMX instructions. It is why, i've choosen to solve this crackme. It's written strangly (badly!) (Visual C++ i think) but it's funny.
You can change the mmx section characteristics to C0000020. Now have a look with Soft-ICE. The crackme checks if you have some mmx registers (see ismmx.asm). A funny thing, all Win32 API calls are made like that :
push argN ... push arg1 push (offset retaddress) push dword ptr [XXX32!TheWin32ApiA] ret retaddress:
The author declares two atoms (see API : GlobalAddAtom and GlobalGetAtomName).
"Good boy :)" in XXXX:004014B9 "Bad boy :(" in XXXX:004014C0
A part of the crackme is decrypted with a encrytion routine (CALL 0040158A). The rest is very classical, a wndproc ... Let's find some serials..
Here is the beginning :
XXXX:004012CB CMP EAX, 04 ; fours chars min for our serial
XXXX:004012CE JB 004014BF ; "Bad boy :("
XXXX:004012D4 EMMS ; empties the MMX state
XXXX:004012D6 MOVD MM0, EAX
XXXX:004012D9 BTS EAX, 1F ; change CF
XXXX:004012DD CDQ
XXXX:004012DE MOVD MM1, EDX
XXXX:004012E1 DEC EDX
XXXX:004012E2 NOT EDX
XXXX:004012E4 MOVD MM2, EDX
XXXX:004012E7 PSLLQ MM2, 05 ;MM2*32d
XXXX:004012EB PAND MM2, MM1
XXXX:004012EE PXOR MM2, MM0
XXXX:004012F1 PSUBD MM3, MM3 ;MM3=0 (doubleword)
XXXX:004012F4 PCMPEQD MM3, MM2 ; if (MM3==MM2) then MM3=-1 else MM3=0
XXXX:004012F7 MOVD EAX, MM3
XXXX:004012FA INC EAX
XXXX:004012FB JNZ 004014BF ; "Bad boy :("
So our serial will be 32 chars long. Then, the serial rewritten. Example:
the entered dummy serial is : "3615780015985347156456361736ABC8".
-----CRACKME!bss----------------------------------byte--------------PROT---(0)--
XXXX:00402000 36 15 78 00 15 98 53 47-15 64 56 36 17 36 15 78 6.x...SG.dV6.6.x
--------------------------------------------------------------------------------
(let's assume that our 128 bit serial is divided in 4 parts : p1, p2, p3, p4)
Remark: You should also enter letters..
We are in XXXX:00401353. After lots of garbage code.. this the following first check :
XXXX:004013BB MOVD EAX, MM1
XXXX:004013BE NEG EAX ; the only acceptable value is 0
XXXX:004013C0 SBB EAX, EAX ; Carry flag must be cleared
XXXX:004013C2 INC EAX
XXXX:004013C3 PUSH DWORD PTR [EAX*4+00401500] ; [004014BF ; 004013CB]
XXXX:004013CA RET
I have (just before XXXX:4013B5):
MM0 = 00000000 506E7F42 ;cpuid eax=0 : mm0=xor(eax,ebx,ecx,edx) MM1 = 00000000 15985347 ;p2 MM2 = 00000000 ADFFFFCE MM3 = 00000000 24FF6D46
So the second part of my serial (p2) is : MM0 XOR ADFFFFCE = FD91808C.
The second check is even more simple : the first dword of my serial should not be XX XX XX XX (i mean: p1 XOR (BSWAP p1) != 0).
The third check, primary like the second check (it's a SUB not a XOR), but there are aften another condition : (p1 SHR 8) = p3.
XXXX:00401441 MOVD EAX, MM1
XXXX:00401444 CMPXCHG EDX, EDX ;make eax=edx
XXXX:00401447 LAHF ;load flags in AX
XXXX:00401448 AND EAX, 00004000
XXXX:0040144D SHR EAX, 0E
XXXX:00401450 JMP [EAX*4+00401508] ; [004014BF ; 0040145A]
The last part (p4) is the most interesting :
XXXX:00401480 MOV EDI, 00402100 ;little 8 bytes buffer
XXXX:00401485 MOVQ [EDI], MM1 ;MM1=FFxxFFyy FFzzFFtt (where xxyyzztt = p4)
XXXX:00401488 PUSH EDI
XXXX:00401489 PUSH 0040171C ;"[[ master&slave proj"
XXXX:0040148E CALL 0040151E ;nice routine !
XXXX:00401493 MOVQ MM0, [EDI] ;we should obtain one of these values :
;2DFFC7DC A26A64C2
;2DFFC7DD A26A64C1
;2DFFC7DD A26A64C2
See brute/mmx.asm for more details. I don't know which (known) algo is used in the CALL 0040151E.. Finally p4 equals 6D6D7821 (unique solution).
Even if using MMX instructions is a good idea. This final product is not very good. All this garbage code is boring (PAND MM0, MM0, ...) and MMX instructions are here used as extra 32 bits registers only; the saturation operations are not used. It could have been a very good crackme, however the operations are limited to XOR, OR, AND, ADD, SUB. It's too linear. I'd like to watch the source by curiosity.
Greetings: Only youuuu ;).