Software Reverse Engineering - Finding Correct Serial Numbers Using The HMEMCPY Function
Copyright (c) 1998 Volatility
Document Courtesy of The Immortal Descendants - http://pages.prodigy.net/volatility

---------------------------------------------------------------------------------------------
TABLE OF CONTENTS
---------------------------------------------------------------------------------------------
I.    Tools You'll Need For This Tutorial

II.   Understanding The HMEMCPY Function
      A.  What Is HMEMCPY?
      B.  Which Applications Use HMEMCPY?

III.  Software Reverse Engineering Using HMEMCPY

      A.  When Will HMEMCPY Work?
      B.  Setting Up Your Debugger To Break On HMEMCPY
      C.  Common Things To Look For

IV.   Finding A Correct Serial Number Using HMEMCPY
      A.  Prepare To Crack
      B.  Making The Crack

V.    Final Thoughts

---------------------------------------------------------------------------------------------
I.  Tools You'll Need For This Tutorial
---------------------------------------------------------------------------------------------
Target:  Page 'O Labels For Mailing Labels v2.8 - (polml32.exe) 437,872 bytes.  Download this at:

	                  http://members.aol.com/rksftp5/polml32.exe

	NOTE: This method will work for ALL software at http://www.rks-software.com

Tools Needed:  	Soft-Ice (any version)

---------------------------------------------------------------------------------------------
II.  Understanding The HMEMCPY Function
---------------------------------------------------------------------------------------------

A.  What Is HMEMCPY?

	HMEMCPY is a Windows API call, which uses memory (RAM) to read, manipulate, compare
and store strings (text you've entered into a program).  The function takes the information
you've entered (such as name and serial number in a registration screen) and puts them into
memory.  The function then proceeds to manipulate these strings, by moving and comparing
them (for example, comparing the serial number you entered to the correct one), and then 
decides wether your string is correct or incorrect.  The function then sends this information
back to the application, and you proceed as good guy, or bad guy.

B.  Which Applications Use HMEMCPY?

	Many programs use HMEMCPY for many different reasons.  For our purposes in this 
tutorial, we're mainly interested in shareware programs.  The registration screens in
shareware programs often utilize the HMEMCPY function to compare the information you entered
with the correct information.  If incorrect, you're still unregistered.. if correct, you're
registered.

---------------------------------------------------------------------------------------------
III.  Software Reverse Engineering Using HMEMCPY
---------------------------------------------------------------------------------------------

A.  When Will HMEMCPY Work?

	HMEMCPY can be used to "trap" valid serial numbers for shareware programs.  Using a
debugger such as Soft-Ice, you can set a "breakpoint" on HMEMCPY, so that the debugger pops
up when HMEMCPY is called.  Now that your serial number, and most likely the correct one are
stored in RAM, you can proceed to "fish" for your valid serial number.

	Many shareware programs utilize HMEMCPY for comparisons of serial numbers, and this
method is extremely effective on applications written in Delphi or Visual Basic.

B.  Setting Up Your Debugger To Break On HMEMCPY

	In order to "break" into the routine where your serial number is compared with the
correct one, you'll need to set up a "breakpoint" to "pop" your debugger up when the function
is called.

	Using Soft-Ice, this couldn't be more simple.  Run your program, go to the registration
screen and enter in some "test" data.  Press Cntrl+D to enter Soft-Ice, and type BPX HMEMCPY.
BPX means Breakpoint on Execution, and you're telling Soft-Ice to break when HMEMCPY is called.
After setting the breakpoint, press Cntrl+D again to exit back out to the program.  Press the
"Ok", "Register", or whichever button, and Soft-Ice will pop up.  To get into the routine, you
need to press F11.

	Now that you're inside the routine, you'll most likely see a string such as "USER(0A)"
or (USER(01) on the line right above the command window.  This isn't where you need to be.  You
need to be inside the program routine.  If, for example, your program is called "Crack Me", 
you'll need to press F10 to step through the code, until you see a string such as "CRACKME!CODE"
on the line above the command window.

	You'll need to press F10 to step through the code many times before you get to the place
you need to be (I've found that a common number of times you need to press F10 is 79).  You'll 
see different strings such as "USER(01)", "USER(1C)", "KERNEL32!_FREQASM", etc., as you step 
through the code.  Normally, the program code is found  right after "KERNEL32!_FREQASM".

	If you had to enter just a serial number, you can normally stop at the first instance
of your program's code, but if you had to enter a user name AND a serial number, you'll need to
continue stepping through all the functions again, until you get back to your program's code
again.  The first instance just manipulates the user name you entered, while the second instance
manipulates your serial number.

C.  Common Things To Look For

	Once you get into your program's code, you'll need to start looking for a compare function
(CMP, TEST) and/or a jump function (JZ, JNZ, JE, JNE, etc).  When you find a compare, followed by
a jump, this is usually right where you can find your valid serial number.  A VERY common routine
you'll see is as follows:

---------------------------------------------------------------------------------------------
CALL     0041EF84
MOV      EAX,[EBP-14]     <the serial we entered stored in EAX
MOV      EDX,[004738D4]   <the correct serial stored in EDX
CALL     00403D8C         <call the routine to compare the serials
JNZ      00466E39         <jump to registered if good (not zero)
MOV      EAX,00466F34     -------.
CALL     0043C650                |
JMP      00466EA2                |-- if no good, get a zero, and proceed to
MOV      EAX,004738D4            |   unregistered.
MOV      EDX,00466F7C            |
CALL     00403A54         -------'
---------------------------------------------------------------------------------------------

	The numbers will no doubt be different, but the routine will be very similar.  To find
the serial number we entered in the above example, you need to step through the line 
"MOV      EAX,[EBP-14]" so that the line "MOV      EDX,[004738D4]" is highlighted.  You can now
display the EAX register by typing: d EAX.  You should now see the serial number you entered
in the display window.  To find the correct serial number, step through the line
"MOV      EDX,[004738D4]" so that the line "CALL     00403D8C" is highlighted.  You can now 
display the EDX register by typing: d EDX.  And, voila!  Your correct serial number!

	NOTE:  You often have to scroll up or down a little bit using the Alt key plus your up/
               down arrows to find your correct serial number.

	This example will not work in all programs, and the registers will be different, but
the above routine is a very common one, and will be very similar.

	Another very common routine is as follows:

---------------------------------------------------------------------------------------------
PUSH     EAX                        <various functions to put the correct
CALL     004067CC                   <serial and our serial in memory
ADD      ESP,04                     <
TEST     EAX,EAX                    <compare our serial with the correct one
JNZ      00402B68                   <jump to registered if not zero
PUSH     0040B61B                   <hmm....what is this? :)
PUSH     64
PUSH     EBX
CALL     00402133
---------------------------------------------------------------------------------------------

	Again, the numbers and registers will be different, but the routine will be very
similar.  This example "PUSHes" our correct serial into memory.  So, to find our correct
serial in the above example, we need to step through the jump "JNZ      00402B68" so that
the line "PUSH     0040B61B" is highlighted.  Now we can find our correct serial number by
displaying the memory location like so: d 0040B61B.

---------------------------------------------------------------------------------------------
IV.  Finding A Correct Serial Number Using HMEMCPY
---------------------------------------------------------------------------------------------

A.  Prepare To Crack

	Fire Up The Program Page 'O Labels For Mailing Labels (polml.exe) and go to the
registration screen - "Help", "Enter Serial Number".  We know from the registration screen
that we'll need to step through the first function, to get to it a second time.

	Enter some test data (Cracked By Volatility [ID] and 272727 for mine) and press
Cntrl+D to get into Soft-Ice.  Set a breakpoint on HMEMCPY (BPX HMEMCPY) and press Cntrl+D
to exit back out to the program.  Press the "Ok" button, and Soft-Ice Will pop up.  Press 
F11 to get into the routine, and you should be here:

---------------------------------------------------------------------------------------------
CALL     KERNEL!HMEMCPY
PUSH     WORD PTR [DI]
CALL     KERNEL!LOCALUNLOCK
MOV      AX,SI
POP      SI
POP      DI
LEAVE
RET      000A
ENTER    0006,00
PUSH     SI
MOV      SI,[BP+0A]
---------------------------------------------------------------------------------------------

B.  Making The Crack

	You'll see the string "USER(0A)" on the line above the command window, and this isn't
where you need to be, so step through the code by pressing F10 (exactly 79 times) until you
see the string "POLML!CODE" on the line.  You should now be here:

---------------------------------------------------------------------------------------------
CALL     USER32!CallWindowProcA
MOV      [ESI+0C],EAX
JMP      00416533
MOV      EDX,ESI
MOV      EAX,EBX
CALL     00414C5C
POP      EBP
POP      EDI
POP      ESI
POP      EBX
RET
---------------------------------------------------------------------------------------------

	Now you could step through the code, find a compare or jump, and display some registers,
but all you'll find in this routine is the user name you entered being manipulated.  We need
to be in the routine where our serial number is being manipulated.  So, step through the code
by pressing F10 MANY more times until you see "POLML!CODE" on the line above the command window.

	This is the routine we need to be in.  Now you must look for a compare and/or jump, for 
this is where we will find our correct serial number.  To save you time, if you press F10 exactly
28 times, you'll land here:

---------------------------------------------------------------------------------------------
CALL     00414428
MOV      ECX,[EBX+000001CC]
MOV      EDX,[EBP-08]                        <serial number you entered
MOV      EAX,[EBP-04]                        <correct serial number
CALL     0043D024                            <call the function to compare the serials
TEST     AL,AL                               <compare the serials
JZ       0043D85C                            <jump to "registered" if zero (0=good flag)
MOV      DWORD PTR [EBX+00000128],00000001   <otherwise, get a one (1=bad flag)
JMP      0043D883                            <and jump to "unregistered">
PUSH     00
CALL     USER32!MessageBeep
---------------------------------------------------------------------------------------------

	To display the serial number you entered, step through the line "MOV      EDX,[EBP-08]"
so that the line "MOV      EAX,[EBP-04]" is highlighted.  Now display the EDX register by 
typing: d EDX.  To display the correct serial number, press F10 twice so that the line
"TEST     AL,AL" is highlighted, and display the EDX register again.  Press Alt plus your down
arrow key a few times, and there's your correct serial number!  Mine was "RKS-4059199".

---------------------------------------------------------------------------------------------
V.  Final Thoughts
---------------------------------------------------------------------------------------------

	I hope that this tutorial has given you some insight on finding correct serial numbers
using the HMEMCPY function.  If not, trash it!  I won't be offended.

	If you feel I should add anything, or didn't clarify enough, feel free to let me know.
You can contact me at: volatility@prodigy.net.

	Shout-Outs! - The Sandman (for his excellent website, tutorials and forums.  Without
them I'd be lost), Razzia (for his excellent tutorials on cracking Visual Basic programs),
+Fravia (for the most comprehensive knowledge base on software reverse engineering available),
and all fellow newbie crackers - don't give up!  Failure is just the opportunity to start over
again more intelligently!

-Volatility-