Notice that the line that accesses this address is only using a single byte, and
not whole DWORDs, so in reality the program is only accessing the first (which
is 0x25) and the fourth byte (which is 0x65).
In looking at the first algorithm from Listing 11.1, it is quite obvious that this
is some kind of key-generation algorithm that converts a username into a 32-
bit number (that ends up in ESI). What about the second algorithm from List-
ing 11.2? A quick observation shows that the code doesn’t have any complex
processing. All it does is go over each digit in the serial number, subtract it
from 0x30(which happens to be the digit ‘0’ in ASCII), and repeatedly multi-
ply the result by 10 until ECXgets to zero. This multiplication happens in an
inner loop for each digit in the source string. The number of multiplications is
determined by the digit’s position in the source string.
Stepping through this code in the debugger will show what experienced
reversers can detect by just looking at this function. It converts the string that
was passed in the parameter to a binary DWORD. This is equivalent to the atoi
function from the C runtime library, but it appears to be a private implemen-
tation (atoiis somewhat more complicated, and while OllyDbg is capable of
identifying library functions if it is given a library to work with, it didn’t seem
to find anything in KeygenMe-3).
So, it seems that the first algorithm (from Listing 11.1) converts the user-
name into a 32-bit DWORDusing a special algorithm, and that the second algo-
rithm simply converts digits from the lower text box. The lower text box
should contain the number produced by the first algorithm. In light of this, it
would seem that all you need to do is just rip the first algorithm into the key-
gen program and have it generate a serial number for us. Let’s try that out.
Listing 11.3 shows the ported routine I created for the keygen program. It is
essentially a C function (compiled using the Microsoft C/C++ compiler), with
an inline assembler sequence that was copied from the OllyDbg disassembler.
The instructions written in lowercase were all manually added, as was the
name LoopStart.
ULONG ComputeSerial(LPSTR pszString)
{
DWORD dwLen = lstrlen(pszString);
_asm
{
mov ecx, [dwLen]
mov edx, 0x25
mov eax, 1
LoopStart:
MOV EBX, DWORD PTR [pszString]
mov ebx, dword ptr [ebx]
//MOVSX EDX, BYTE PTR DS:[EAX+40351F]
Listing 11.3 Ported conversion algorithm for first input field from KeygenMe-3.
368 Chapter 11