²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²
    ²²    ____                     __       __           ²²ßÛ
    ²²   /  _/_ _  __ _  ___  ____/ /____ _/ /           ²² ÛßÛ
    ²²  _/ //  ' \/  ' \/ _ \/ __/ __/ _ `/ /            ²² Û Û
    ²² /___/_/_/_/_/_/_/\___/_/  \__/\_,_/_/             ²² Û Û
    ²²   ____                          __          __    ²² Û Û     
    ²²  / __ \___ ___ _______ ___  ___/ /__ ____  / /____²² Û Û 
    ²² / /_/ / -_|_-</ __/ -_) _ \/ _  / _ `/ _ \/ __(_-<²² Û Û
    ²²/_____/\__/___/\__/\__/_//_/\_,_/\_,_/_//_/\__/___/²² Û Û
    ²²                                                   ²² Û Û
    ²²      Web: http://www.ImmortalDescendants.com      ²² Û Û
    ²²      Author: Lord Soth                            ²² Û Û
    ²²      Date: 09/09/99 (mm/dd/yy)                    ²² Û Û
    ²²      Topic: Cracking Jammer 1.95                  ²² Û Û
    ²²      Level: Intermediate                          ²² Û Û
    ²²                                                   ²² Û Û
    ²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²² Û Û
      ÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÛ Û
        ÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÛ

------------------------------------------------------------------------------
Don't be lame and distribute a keygen using this method.
------------------------------------------------------------------------------

Ok folks, I'm back again, but bringing a bit less of a knowledge load .. :)
In this essay I want to explore one of the most widespread protections in existence,
much to the programmer's regret, BTW. 
This protection is pretty straightforward. If you are not a registered user,
Jammer will disable a few inside features and will limit itself to a 30 day 
evaluation period. If this was all, this could have been a pain for us reversers,
because even if we can pretty easily defeat the time check, those remaining hidden
features might be a bitch to find. However, much to our advantage, this is a product
of commercial oriented programmers, who probably wanted it to go on the market ASAP,
so they made a silly protection and added a registration dialog for us to tamper with.
And they did this with guess what: MFC !!!
That makes things SO MUCH better for us, because MFC routines use several standard 
API calls, we can trap the protection more easily!
Ok enough ranting, I want to go on to the more important stuff. I will use this program
as an example of how to code a serial gen. I know probly most of you know but I wanna
show how simple it is to generate a serial gen that runs under winblows and has a nice
GUI.
The second section of this essay is devoted for that and explanation of my source code
which is actually pretty simple.
For now lets start the reversing part of this essay.

Cracking Jammer 1.95 build 0809
=================================

Ok, first swoop, lets launch Jammer and see whats going on inside it. When it gets
run, we can see several messages in its client window saying it is unregistered and
blah blah blah (first we go into some config dialog, but after we're done with it, 
the main app runs).
We can try to be smart and launch a disassembler and try to catch this strings and
maybe work our way backwards to the validation routine, but I really don't like that
approach much.
Instead, lets do this. Lets find out (using a disassembly if you want), what imports
this program is using. After we disassemble/Tdump the EXE file, we see that it does
NOT use any of the standard APIs to catch text from a dialog box or a window, i.e:

GetDlgItemTextA, GetWindowTextA and so on.....

But we know that if we click on the Register option in the about menu, a dialog will
pop up and let us input our user name and serial number. This is where M$ comes into
action, in the form of MFC.
Know this : when MFC ordinals are used to open a dialog box and manage its controls,
you can bet on it to use a standard API.
What do I mean ?

If you want, you can look in a disassebly. Find a string resource that appears in the
dialog box, and you will see several CALLs to MFC ordinals (routines).
In these the actual creation of the dialog happens, but this is of no concern to us.
All we need to do is break on the code getting the text from the dialog, and this
can be accomplished (pretty sure whenever they code in MFC) by the following BP:

bpx getwindowtexta

Now fill in the fields in whatever you like, I put : Lord Soth, and for the serial
I put 12345 - 67890.
That turned out as a mistake later on, but lemme get to that.
Now after we try to register, we break inside SI on GetWindowTextA. P RET (F12), 
and wham, we're back inside the caller routine which is if you notice, not in
the normal code area of normal programs. In fact its dwelling in 5XXXXXXX and above
which suggests a DLL code, and my guess would go to MFC42.DLL (mainly because the
program does not have any other DLLs hehe).

So we broke on the code and we see this:

:u 5f41423c l 20
023F:5F41423C  50                  PUSH    EAX
023F:5F41423D  E8FCE5FEFF          CALL    5F40283E
023F:5F414242  50                  PUSH    EAX			; push a pointer to where text would be...
023F:5F414243  56                  PUSH    ESI
023F:5F414244  FF1588B5495F        CALL    [USER32!GetWindowTextA]
023F:5F41424A  8B4D10              MOV     ECX,[EBP+10]				;<<< we land here!!!
023F:5F41424D  6AFF                PUSH    FF
023F:5F41424F  E8CFE4FEFF          CALL    5F402723
023F:5F414254  5F                  POP     EDI
023F:5F414255  5E                  POP     ESI
023F:5F414256  5D                  POP     EBP
023F:5F414257  C20C00              RET     000C
023F:5F41425A  8B4510              MOV     EAX,[EBP+10]

Ok, so we got back, and we see we're inside the MFC DLL, there won't be any interesting code in here,
so lets try to go back a little. Before we do that, in these situations (almost any reference to an API), 
I tend to put a BP on the PUSH instructions themselves. This is done so the next time the code will be
executed, I can watch the parameters the APIs are receiving.
If you'll do this who thing again, and watch what's passed to the CALL, you'll see some pointer values
and if you display those memory locations (do it before the CALL because afterwards they change), you'll
see the input you put appear there.

Anyways, back to business. I want to see what happens here, so after I display my name in the data window,
which I will do by redoing all this again, and doing a D EAX, I'll wanna put a BP on memory read where the
username I put dwells.
This would normally lead you straight to the calculation routine, but in this case it won't. When the 
registration information is invalid, the program opens up a MessageBox and yells at you that its invalid.
After I breaked 3 times on GetWindowTextA (3 fields of input), I noticed that it automatically popped the
MessageBox without breaking on memory read!
I asked myself how could this be, and the answer came a little while afterwards. I decided to continue
stepping through code and seeing what happened. I figured lets first return to the real program and out
of M$'s code.

I returned a few more times and then I saw I was back in the code area of Jammer. It looked pretty
odd, not what you would expect from a Win program. It was just PUSHs and CALLs.
It certainly looked liked the higher level of a VB program, or an MFC app!
Some of the CALLs were repetitive, so I decided to step over them, and in the repeating ones, SI broke
on the BPs I set earlier (remember the BP on 5F414242 , that PUSH EAX ? )..
SI breaks whenever you got a BP inside a CALL you step over because stepping over activates all
the sticky BPs as noted in the SI manual.

So, checking the programs view (F4), I saw the MessageBox wasn't there, it hasn't called it yet. That
was good, and I continued to step over code and then got to a RET, and that took me to a different 
area completely.
A bit of stepping and I found this snippet of code (almost right after I RET from the above mentioned code):

:u eip l 100
023F:0041BE3A  8B4664              MOV     EAX,[ESI+64]			; loading of address of username!
023F:0041BE3D  FF766C              PUSH    DWORD PTR [ESI+6C]
023F:0041BE40  8B40F8              MOV     EAX,[EAX-08]
023F:0041BE43  8945E4              MOV     [EBP-1C],EAX
023F:0041BE46  8B4668              MOV     EAX,[ESI+68]
023F:0041BE49  8B78F8              MOV     EDI,[EAX-08]
023F:0041BE4C  FF1550594200        CALL    [00425950]
023F:0041BE52  8D5E60              LEA     EBX,[ESI+60]
023F:0041BE55  8945E0              MOV     [EBP-20],EAX
023F:0041BE58  8BCB                MOV     ECX,EBX
023F:0041BE5A  C7042480134300      MOV     DWORD PTR [ESP],00431380
023F:0041BE61  E8EE480000          CALL    00420754
023F:0041BE66  33C9                XOR     ECX,ECX
023F:0041BE68  394DE0              CMP     [EBP-20],ECX
023F:0041BE6B  0F8452010000        JZ      0041BFC3
023F:0041BE71  837DE408            CMP     DWORD PTR [EBP-1C],08 ; compare length of name with 8 , has to be greater than
023F:0041BE75  0F8C48010000        JL      0041BFC3				;if not, go to bad cracker
023F:0041BE7B  83FF0A              CMP     EDI,0A				;compare length of serial entered, gotta be 10 or bigger
023F:0041BE7E  0F8C3F010000        JL      0041BFC3				;if not, go to bad cracker
023F:0041BE84  8B4664              MOV     EAX,[ESI+64]			; loading again, this time for real!
023F:0041BE87  8D7901              LEA     EDI,[ECX+01]			; put something in ECX (0,1,2,...)
023F:0041BE8A  8A1408              MOV     DL,[ECX+EAX]			; get char from start of name
023F:0041BE8D  2BC1                SUB     EAX,ECX				; reduce pointer to name by ECX
023F:0041BE8F  8855F3              MOV     [EBP-0D],DL			; store char on stack
023F:0041BE92  8B55E4              MOV     EDX,[EBP-1C]			
023F:0041BE95  8BCF                MOV     ECX,EDI				; restore ECX from before
023F:0041BE97  8A4410FF            MOV     AL,[EDX+EAX-01]		; get last char from name
023F:0041BE9B  0FAFCF              IMUL    ECX,EDI				; multiply ECX by itself
023F:0041BE9E  0FBED0              MOVSX   EDX,AL				; take char and zero everything else
023F:0041BEA1  0355E0              ADD     EDX,[EBP-20]			; add the first serial field to the last char
023F:0041BEA4  0FBE45F3            MOVSX   EAX,BYTE PTR [EBP-0D]; move into EAX and clear the rest
023F:0041BEA8  03D1                ADD     EDX,ECX				; now add ECX * ECX
023F:0041BEAA  B9FF000000          MOV     ECX,000000FF			; load 255
023F:0041BEAF  03C2                ADD     EAX,EDX				; now add first char to the whole thing
023F:0041BEB1  33D2                XOR     EDX,EDX				; zero EDX (remainder register)
023F:0041BEB3  F7F1                DIV     ECX					; divide result with 255
023F:0041BEB5  0FB6C2              MOVZX   EAX,DL				; get the remainder and zero everything else
023F:0041BEB8  50                  PUSH    EAX					; push on stack
023F:0041BEB9  8D45EC              LEA     EAX,[EBP-14]
023F:0041BEBC  68600B4300          PUSH    00430B60
023F:0041BEC1  50                  PUSH    EAX
023F:0041BEC2  E8FF4B0000          CALL    00420AC6				; turn the hex code into a string that looks the same
023F:0041BEC7  83C40C              ADD     ESP,0C
023F:0041BECA  8D45EC              LEA     EAX,[EBP-14]			; pointer of end of serial is here!
023F:0041BECD  8BCB                MOV     ECX,EBX
023F:0041BECF  50                  PUSH    EAX
023F:0041BED0  E8F74E0000          CALL    00420DCC				; append to pointer of end of serial!
023F:0041BED5  8BCF                MOV     ECX,EDI				; restore ECX
023F:0041BED7  83F905              CMP     ECX,05				; check if 5
023F:0041BEDA  7CA8                JL      0041BF84				; if not yet, go back for another run
023F:0041BEDC  FF7668              PUSH    DWORD PTR [ESI+68]
023F:0041BEDF  FF33                PUSH    DWORD PTR [EBX]
023F:0041BEE1  E894520000          CALL    0042117A				;compare actual serial to what we put in
023F:0041BEE6  59                  POP     ECX
023F:0041BEE7  85C0                TEST    EAX,EAX				;based on this branch to good/bad cracker..
023F:0041BEE9  59                  POP     ECX
023F:0041BEEA  7407                JZ      0041BEF3
023F:0041BEEC  6A00                PUSH    00
023F:0041BEEE  E9D1000000          JMP     0041BFC4
023F:0041BEF3  FF7664              PUSH    DWORD PTR [ESI+64]
023F:0041BEF6  8D85B0FEFFFF        LEA     EAX,[EBP-0150]
023F:0041BEFC  50                  PUSH    EAX
023F:0041BEFD  E88A520000          CALL    0042118C
023F:0041BF02  FF766C              PUSH    DWORD PTR [ESI+6C]
023F:0041BF05  8D857CFFFFFF        LEA     EAX,[EBP-0084]
023F:0041BF0B  50                  PUSH    EAX
023F:0041BF0C  E87B520000          CALL    0042118C
023F:0041BF11  8D857CFFFFFF        LEA     EAX,[EBP-0084]
023F:0041BF17  685C0B4300          PUSH    00430B5C
023F:0041BF1C  50                  PUSH    EAX
023F:0041BF1D  E852520000          CALL    00421174
023F:0041BF22  FF7668              PUSH    DWORD PTR [ESI+68]
023F:0041BF25  8D857CFFFFFF        LEA     EAX,[EBP-0084]
023F:0041BF2B  50                  PUSH    EAX
023F:0041BF2C  E843520000          CALL    00421174
023F:0041BF31  83C420              ADD     ESP,20
023F:0041BF34  8D857CFFFFFF        LEA     EAX,[EBP-0084]

Now I've found my problem. Look at address 0041BE71. The length of the serial I entered on the second field is compared with 10 decimal, and if its smaller, than we go to bad cracker routine, and without even picking one character !
This is why SI didn't break when I put a memory BP on my user name. The program never got to the calculation routine!

Ok so I fixed this, and put a 10 digit serial in the 2nd field, and now this check has passed as well and we're
off to some interesting stuff.
Notice, after we passed the inital length checks, the real calculation starts in address 0041BE84.
What is happening here ? only way to know for sure is to go with SI and reverse this part!
A disassembly will not help you to see the pattern here. Ok so in SI, we go from address 0041BE84 and we see what happens.
Everything is pretty normal right untill address 0041BE87.
That instruction puzzled me actually. It pointed to a weird area in memory and ECX took its address. I didn't figure it out untill I did the whole loop again. Everytime, ECX is loaded with 1 more than it used to be, and it used to be 0
because there's a XOR ECX,ECX somewhere in there.
Everytime we passed on this instruction, ECX would increase in 1 actually, nothing special to it.
Then we see some handling of the value in EAX, which holds the pointer for the beginning of the username.
This is very weird I thought in the beginning, only to realize what is happening in the next pass.
In the first pass ECX was 0, and we took the first char pointed to by EAX (natually).
Then the length of the username is added and stuff, and reduced by 1 and we end up with the last char in the name.
The whole trick is that when we do this loop again, ECX will be bigger, and walla, look how it automagically takes
the next char and with the same calculation takes the next char from the end!
pretty slick :)
Ok in each pass it takes the end and the beginning char and it moves inward to the center of the string.
Each time, you can pretty easily see whats going on : it takes the number we entered in the first field of the serial,
it adds to it our last char's value. Then it takes ECX which is basically a counter, it multiplies by itself (power of 2)
and added to the result. Then the first char is added again. We get a result which we divide by 255 and the remainder
is a number between 0 to FE in hex, and that gets turned into a string, exactly how it looks, and then added to the 
serial number string (yes, the good 1).
The the whole process repeats itself , to a total of 5 times. This gives us a serial number of 10 digits, and it has
to be uppercase as we will see when we try to enter it :)

I wanna note that the 1st field of the serial can be anything we want , the second gets calculated by the first.
Anyways, I included my serial gen along with its source and resource, I hope you find it useful...

Yet again, another silly protection was annihilated , mainly because being a good programmer does not mean
being a good protectionist, and as companies want money, they lack :)
Even this company's name is all about Jammer, suggesting it was created just for this project, another
company was created just for the quick buck.. Ah well....

On to the serial code!

Serial code coding :)
======================
In this zip (hopefully), you'll find Jammser.cpp, my serial generator. It runs under winblows and is pretty simple to
understand.
The main function (WinMain), starts and without even registering a window class or opening a window, it calls a dialog
box for the serial (dont need more than a dialog box). Notice that if you don't pass the owner window's handle to the
dialog box function (because there is none!), the desktop will be the owner window, so this is a way to make custom
windows without having to register your window classes :)
the CALLBACK function 'gen' is the message loop of the dialog box. It detects when the Generate button has been pressed
and acts accordingly. Look at the little loop there, its the whole serial calculation in short hehe
Then the serial is loaded back into the Dialog and we're done.
If the exit button is pressed we end the dialog there (notice that the switch is used to determine which message and which
button was clicked).
This is standard win programming, not too fancy , pretty short tho :)

This is the source with all the includes and resources , you could insert your calculation code and make yourself a keygen
if you don't really know about programming, but I suggest learning :)

Anyways folks, thats all for now, I hope you enjoyed this little dumb protection. Learn how to bash MFC !!! :)

For questions, comments and stuff: lordsoth8@hotmail.com

ICQ # 5178515

Lord Soth

PS Greetings to everyone I know! and those I don't :)