http://www.goldwave.com - Webpage (gwave401.zip - (618k)).
Welcome once again to another fairly long key generator tutorial. GoldWave is a fairly interesting scheme performing a lot of manipulations upon the user name. For those "I must register it now" readers just set a >bpx lstrcmp and snatch the good code from EDI. However, if you are interested in building a key generator and improving your assembly knowledge then read on.
Firstly locate the register option, (Options Menu), note the 3 dialog boxes, I'm using First Name: CRACKZ, Last Name: ZENCRACK and any password (its not important), note that the program upper cases everything. Now you can set a breakpoint on >bpx GetWindowTextA but you'll need to do some pretty heavy F12 work to reach an entry point at address 0042D16A.
The interesting code can be reached from there with F10.
:0042D21F CALL 0042CA60 <-- Builds good Password.
:0042D224 POP ECX
:0042D225 TEST AL,AL <-- Test AX-low for 0.
:0042D227 JNZ 0042D2CE <-- Jump_good_password.
So lets trace into 0042CA60 and examine how the program builds the good password for the program. Note that I've only commented significant parts of the code (also note that this function is called from 3 addresses and hence why patching this function as opposed to the callers is the best approach) You'll soon find that you'll need to trace lower functions, the most interesting of which is 0042C960.
:0042C98C MOVSX ECX, BYTE PTR [EDX] <-- Last letter
of first name.
:0042C98F ADD ECX,EAX
:0042C991 ADD EBX,ECX <-- EBX used as store.
:0042C993 DEC EDX
:0042C994 MOV ECX,EAX
:0042C996 ADD EAX,-01
:0042C999 TEST ECX,ECX <-- Test for end of first name reached.
:0042C99B JNZ 0042C98C <-- Loop_first_name.
Well there's nothing complex here, the first name's ASCII values will be added together in reverse order, the result is placed in EBX and kept for later use (CRACKZ=1CD), the function call 004A86D4 is used through out this function (its a string length checker). Similarly addresses 0042C9BE-0042C9CB will loop through the last name and save that result (ZENCRACK=26D) storing that result in ESI for later use as well. We continue at this next piece of code:
:0042C9E7 ADD EDI,EAX <-- EDI = combined length of
first name + last name (0E).
:0042C9EA MOV EAX,EDI <-- EAX has length also.
:0042C9EC MOV EDX,EAX <-- EDX also.
:0042C9F1 SHL EDX,04 <-- Shift left combined name length 0000000E = 000000E0.
:0042C9F4 LEA EDX,[EDX+2*EDX]
:0042C9F7 LEA EDX,[EDX+4*EDX]
:0042C9FA LEA EDX,[EDX+4*EDX]
:0042C9FD LEA EDX,[EDX+4*EDX] <-- Multiplication of shifted result (*375).
:0042CA00 ADD EBX,EDX <-- Add result to sum of first name in EBX.
The program next combines the length of the 2 names entered, in this case CRACKZ+ZENCRACK=14. Then we shift left before performing multiplications equivalent to *375, the result is 149ED. This value is then utilised in the following code.
:0042CA05 MOV ECX,EBX <-- Move result into ECX.
:0042CA07 SHL ECX,04 <-- Shift left (00149ED0).
..... <-- Multiplication of shifted result as above.
:0042CA16 ADD ESI,ECX <-- Add result to sum of last name.
:0042CA18 MOV EBX,ESI <-- Place result in EBX.
So now the program has calculated this value it saves it to EBX (in my case the result is 1E34A51D). The next piece of code converts this value into a valid user password.
:0042CA22 MOV EAX,EBX <-- Place result in EAX.
:0042CA24 XOR EDX,EDX <-- Clean-up EDX.
:0042CA26 MOV ECX,0000001A <-- ECX=26 decimal.
:0042CA2B DIV ECX <-- Maths.
:0042CA2D ADD DL,41 <-- Now convert result into a letter.
:0042CA30 MOV EAX,EBX <-- Restore result in EAX temporarily.
:0042CA32 MOV BYTE PTR [ESI],DL <-- Pointer.
:0042CA36 MOV ECX,0000001A <-- Restore value of ECX.
:0042CA3B INC ESI <-- Next character.
:0042CA3C DIV ECX <-- Critical divide of original result ready for next pass of loop.
:0042CA43 TEST EBX,EBX <-- End of loop check, can we DIV anymore.
:0042CA45 JNZ 0042CA22 <-- Jump_continue_loop.
Now we can how the correct password is built on each pass of the loop, the divide instruction determining how many times the loop will continue, a few instructions on you'll be able to see the result as its popped from the stack ready to be compared with the code you entered. In terms of patching its obviously advisable to patch the result of the lstrcmp function, however a key generator is also a possibility. This scheme isn't particularly weak in operations but is let down by the use of lstrcmp to compare the passwords, note the use of the ini file for the registration information.