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-