http://www.cict.co.uk/software/markin/ - Webpage (markin3213.exe - (1Mb)).
Welcome to a slightly longer tutorial than usual. I'm going to use Markin to demonstrate all of the work involved in producing a key generator, ultimately resulting in the production of relevant source code. Without further ado lets launch Markin and access the register option. There are a lot of ways of proceeding here (as highlighted in other tutorials), however lets use the bad guy message box text "Incorrect key or user name" as a basis for our intrusions.
Tracing up the disassembly one level from the bad key reference you should easily locate this code.
:004495DE CALL 004492B4
:004495E3 MOV EDX, [EBP-3C] <-- From your bogus code.
:004495E6 MOV EAX, [EBP-14] <-- Generated code.
:004495E9 CALL 004036E8 <-- Compare.
:004495EE JNZ 00449694 <-- Jump_away_bad.
Well we can learn several things from just this code and the surrounding snippets. Obviously JNZ *jumping* is not desirable, note a few lines lower we have the good code message and what looks like the desired registry keys being added. Our next stage is to get into SoftICE and start tracing through CALL 004036E8.
You'll find that bpx Hmemcpy works well, allowing 2 breaks of course, then pressing F12 11 times or so will get you an entry point at address 00449496. I advise you now to use a 14 digit bogus code and then you'll understand the significance of EBP-3C above. Below you'll find highlighted the key code snippets.
:004494A8 TEST ESI,ESI <-- ESI holds name length.
:004494AA JL 004494E3 <-- Name must exist but a inefficient check.
:004494AC INC ESI <-- Important for whats to follow but why?.
:004494AD XOR EDI,EDI <-- Clear EDI.
:004494B2 MOV BL, BYTE PTR [EAX+EDI-01] <-- Strange.
:004494B6 CMP BL,61 <-- Check for 'a'.
:004494B9 JB 004494C0
:004494BB CMP BL,7A <-- Check for 'z'.
:004494BE JBE 004494CA
:004494C0 CMP BL,41 <-- Check for 'A'.
:004494C3 JB 004494DF
:004494C5 CMP BL,5A <-- Check for 'Z'
:004494C8 JA 004494DF
:004494DF INC EDI <-- Next character.
:004494E0 DEC ESI <-- Loop count.
:004494E1 JNZ 004494AF <-- Loop name.
Well, I've omitted several of the functions that are called during this loop, you should of course find it fairly easy to work out what they do by simple tracing. I'd like you to examine this very carefully and see that both 004494A8 & 004494B2 are very strange instructions. 004494A8 checks that our name was not of length 0, but from the disassembly we can see that 0 length names are thrown out by the program at String Ref 00449476 so this check may well be due to the compiler. 004494B2 is also very strange because it seems to point to the location 1 before the start of our user name and that could be any character that happens to be in memory. You may like to improve this codes efficiency by patching.
For the next part I'm going to break with tradition and instead of showing you the precise code I'm going to describe how my name CrackZ is transformed into the mysterious 8 letter result. Firstly our program checks each character of the user name for letters using the code above, if your input is a letter then we copy it to a new location and all is well.
As the program generates 8 good characters from the user name the name CrackZ presents a problem (its too short), so if the name is short the program will add as many x (78h) characters as are necessary to make the result of length 8, so in my case CrackZ becomes CrackZxx.
For the key generator we also have other considerations here as well, the program dislikes anything that isn't a letter, such as numbers and space characters which users may like to include in their names, there is also need to consider what happens with names greater than 8 characters e.g. CrackZ The Cracker. Continuing onward, our program then reverses our result from the user name, so CrackZxx becomes xxZkcarC.
Each letter of this result is then passed through a loop which performs various manipulations depending on the letter. I've given part of this loop below.
:0044955A MOV EDX, DWORD PTR [EAX] <-- Reversed result
from user name.
:0044955C ADD EDX,EDI
:0044955E ADD EDX,06 <-- Add 6 to the character.
:00449565 CMP EDX,5A <-- 'Z'.
:00449568 JLE 00449572
:0044956A CMP EDX,61 <-- 'a'.
:0044956D JGE 00449572
:0044956F ADD DWORD PTR [EAX],0C <-- Important for key generator.
:00449572 CMP DWORD PTR [EAX],7A <-- 'z'
:00449575 JLE 0044957A
:00449577 SUB DWORD PTR [EAX],0C <-- Also important for key generator.
At the end of this loop our 8 good characters have been generated, although the letter case may be mixed, the program polishes these letters using a very simple upper casing routine, in my case the 8 letter result is RSBTMLRP. Each of these characters then corresponds to a location inside a code which must be at least 14 digits. If you took my advice earlier and used a 14 digit example you should easily see where each digit corresponds.
You can of course now attempt to code your own key generator, I strongly suspect using a high level language is easier, but I used ASM for didactic purposes. You can also read some feedback I received from Markin's author (Martin Holmes) on the Author Feedback page.