http://www.fruityloops.com - Webpage (fruity1212.exe - (850k) - no samples).
Well, here's an updated and requested tutorial. FruityLoops is a good example of why live SoftICE reversing is better than just the disassembler. I disassembled the fruity.exe first and found the failure message at address 0048188E but then when I traced quickly to that address in SoftICE I couldn't see how to quickly avoid it.
Well, lets start. Launch the program, close all the setup screens and get to the register dialog box. Now, enter some details in the boxes, I used CrackZ & 123456. In SoftICE set a breakpoint >bpx Hmemcpy and then perform the necessary actions. You'll be returned inside User.
Now lets do a search for our name in memory:
>s 0 l ffffffff 'CrackZ'
I find that my string gets found at location 009BB06C (yours will almost certainly be different), remember that most of the time you can ignore anything found at Cxxxxxxx & 8xxxxxxx as these tend to be mirror or OS areas. So take a note of the address of your name and disable the breakpoint on Hmemcpy, now set a bpm on the address of your string. In my case.
Now, when you push Ctrl+D the first 2 times you may or may not break in vmm.vxd, obviously ring 0 code won't be responsible for checking your name and serial number so just continue using Ctrl+D until you hit this code inside fruity.exe.
:00406EA9 MOV AL, BYTE PTR [EDX] <-- Character pointer
to name entered.
:00406EAB CMP AL,61 <-- Compare it with 'a'.
:00406EAD JB 00406EB5 <-- Jump_if_below.
:00406EAD CMP AL,7A <-- Compare it with 'z'.
:00406EB1 JA 00406EB5 <-- Jump_if_above.
:00406EB3 SUB AL,20 <-- Uppercase it if necessary.
:00406EB5 MOV BYTE PTR [ESI], AL
:00406EB7 INC EDX <-- Point to next character.
:00406EB8 INC ESI
:00406EB9 DEC EBX <-- Decrement_name_counter.
:00406EBA TEST EBX,EBX <-- Test_for_end_of_name.
:00406EBC JNZ 00406EA9 <-- Loop.
So the first thing the program does is uppercase the user name, in my case that gives the result CRACKZ, we then return from the function at this code.
:00485DF8 MOV EDX,[EBP-0C] <-- Upper case name.
:00485DFB LEA EAX,[EBP-04]
:00485DFE CALL 00403A58 <-- Tests both lower and upper case names for 0.
:00485E03 MOV EAX,[EBP-04] <-- Restore upper case name.
:00485E06 CALL 00403C3C <-- Get length of name, result in EAX.
:00485E0B MOV ESI,EAX <-- Length in ESI.
:00485EOD TEST ESI,ESI <-- Check_for_0.
:00485E0F JLE 00485E45 <-- No_jump_name_was_entered.
Another fairly routine test, was a user name entered. Now, I'm not going to continue with commenting the next portion of code, but it works something like this, firstly the value that EBX is initialised to is critical, a loop then proceeds through the upper cased name, its quite complex but fairly simple, watch very carefully the SHL and IDIV instructions, at the end of that loop I snatched the value F54 from EBX, this will actually be the 4 digits in the middle of the good code (x3924x in my case).
After generating this value the program will then individually determine the 1st and last digits of the code, before eventually finishing up at this code.
:0048607D MOV EDX,[EBP-08] <-- Good_code.
:00486080 MOV EAX,[004942FC]
:00486085 CALL 00403D4C <-- Compare user input with good code.
:0048608A SETE BYTE PTR [EBX] <-- Flag.
:0048608D CMP BYTE PTR [EBX],00 <-- Test flag.
:00486090 JZ 00486103 <-- Jump_bad_code.
Well, I hope you can now see how you might patch this code or just snatch your good code from EDX, the patch is quite tricky because this routine controls the registry check so it needs registry values present, trace the CALL 00403D4C if you want to patch. Should you wish to examine this any further then the code information is written out to the registry (HKEY_USERS/.Default/FLRg/FL SETTINGS).