FTP File Search: wpatch11.*
Greetings key generator aficionados and welcome once again to another tutorial. Before I start let me just say what a really great program WinPatch actually is, if you can live with a minimum of 100k patch files then this is one of the best patchers out there. You should also peruse the authors web site, there's an apparent multitude of clues on it. v1.1 isn't the current version hence my reason for choosing it, the protection in v1.2 just differs enough to make this tutorial lamer unfriendly.
The scheme is based on a Registration ID which uses both the User Name and Organization to generate a default prefixed ID. There is an easy echo of the good code at the very end so finding the good code isn't really the challenge. Its always helpful to have a disassembly listing available, use GetWindowTextA to commence examination. This scheme is really rather interesting because of its use of the EBP register for the maths loops, seemingly in preference to EDI or EBX, all the parameters for the various functions are passed through the stack indicating a high level language. By using the stack to such an extent, a bpr on the user input has no chance.
Enough talk, now to the first part of the protection, before we reach this code note that elementary length checks are performed (both User Name & Organization must be 6 or greater in length). I apologise for the length of this code.
:004113AC MOV EAX, DWORD PTR [ESI+00000110] <-- User
:004113B2 MOV EDX, DWORD PTR [ESI+00000118] <-- Organization.
:004113BC MOV CL, BYTE PTR [EAX+02] <-- 3rd position (User Name).
:004113BF MOVSX EBP, CL <-- Store in EBP.
:004113C2 PUSH EBP <-- Stack it.
:004113C3 MOVSX EBP, BYTE PTR [EAX+04] <-- 5th position (User Name).
:004113C7 PUSH EBP <-- Stack again.
:004113C8 MOVSX EBP, BYTE PTR [EAX+01] <-- 2nd position (User Name).
:004113CC MOVSX EAX, BYTE PTR [EAX+05] <-- 6th position (User Name).
:004113D0 PUSH EBP <-- Push 2nd User Name.
:004113D1 PUSH EAX <-- Push 6th User Name.
:004113D2 MOV EAX, DWORD PTR [EDX-08] <-- Length of Organization.
:004113D5 MOVSX ECX, CL <-- 3rd of User Name is still stored here.
:004113D8 PUSH ECX <-- Saved on stack.
:004113D9 MOVSX ECX, BYTE PTR [EAX+EDX-01] <-- Last of Organization.
:004113DE PUSH ECX <-- Saved on stack.
I'll just pause here, this code is critical to your understanding of the scheme, we have 6 significant pushes to the stack here, all of which will be used in the scheme, remember that Intel architecture stipulates a LIFO (last in, first off) stack (recall the stack of plates analogy). So the last push will be at the very top of the stack and hence the first off.
:004113E3 CALL 004062C0 <-- This has to be understood.
:004113E8 MOV ECX,EAX
:004113EA CALL 004062C0 <-- called again.
:004113EF MOV ECX,EAX
:004113F1 CALL 004062C0 <-- yet again.
:004113F6 MOV ECX,EAX
:004113F8 CALL 004062C0 <-- yet again.
:004113FD MOV ECX,EAX
:004113FF CALL 004062C0 <-- yet again.
:00411404 MOV ECX,EAX
:00411406 CALL 004062C0 <-- and finally.
:0041140B LEA ECX, DWORD PTR [ESP+10]
:0041140F CALL 00405FC0 <-- Use result to generate suffix.
:00411414 PUSH 0044F89C <-- "L&D-0626" <-- the default prefix.
You see, 6 pushes and 6 calls of the same function, you guessed also that each call takes the parameter popped from the previous section. The good thing here is that once you understand 004062C0 you've eliminated a significant proportion of the protection. Sadly understanding 004062C0 is tricky, you'll need to trace down its tentacles to find where the magic's at, I've saved you that work so trace the following path (0041A52C is where everything starts).
004062C0 --> 00406200 --> 0041A4D0 --> 0041A510
The algorithm isn't particularly tricky (in fact there might be a way to shorten it), but here's the very rough notes I made on the first iteration.
Popped value in EDI, EBP = 0Ah, Popped value moved into EAX, clear EDX, Divide by EBP, Discard EAX by moving popped value back, Store EDX value in ECX, clear EDX, Divide by EBP, Compare ECX,9h, Store EAX result in EDI, Jump Below (add 30h to CL), if above (add 57h), Store CL & AL which are then reversed (this isn't an intended feature of the algorithm its just how the compiler chose to do things).
This is essentially the first part of the key generator in words, some real reverse engineers would recommend you use a pictorial notation. Obviously we'll make this into a function as its called 6 times. The result of all 6 iterations is a value - in my case 69979011410797. Lets stop though, what does the algorithm actually do :). Take a little look at the values from the stack and the "code" we appear to generate.
3rd of name: a (61h) = 97 dec. 5th of name: k (6Bh) = 107 dec. 2nd of name: r (72h) = 114 dec. 6th of name: Z (5Ah) = 90 dec. 3rd of name: a (61h) = 97 dec. last of Org: E (45h) = 69 dec.
Just read 'up' the decimal values and the magic isn't quite so magic after all, all we have here is a very standard hex-->dec conversion routine. The algorithm I used to do this in the key generator isn't identical to this one, in fact I think mine is easier to understand although it does have one notable limitation (anything above C8h isn't going to work), this is an acceptable problem seeing as most people are unlikely to use anything that high in the ASCII table.
The next stage of the calculation uses CALL's beneath 00405FC0, you are welcome to analyse the scheme proper which starts at 0040606B, the loop uses basic multiplication with ESI acting as a counter to decrement sequentially backwards through the decimal string (take note of the routine beneath 0041A2D0 which in all truth shouldn't have any effect). The decimal result in EDX at 004060D6 will be the suffix, however there's a possible snag, if this value turns out to be a negative number the (-) sign will be included. In addition the program polishes the result so that only the first 9 chars. are added to the prefix, this means that some codes appear L&D-0626- & others L&D-0626.
You'll find below my key generator source code, its fairly substantial and in hindsight I rather wish I'd used C, you'll see at the end how I determine in a rather elegant fashion whether or not the result is indeed negative, you should of course realise that strange things occur if the last digit is a 0 (you might need to add to this). This is a pretty good scheme for a very good patching program, debugging and coding the key generator took me over 1hr and the cost of the program is only $50, put simply, if you use this program then purchase it.