Difference between revisions of "Example 6"
m (Reverted edits by RacccDarli (Talk) to last version by Ron) |
|||
(6 intermediate revisions by 3 users not shown) | |||
Line 4: | Line 4: | ||
The previous example demonstrates how to crack a game. This example goes one step further and demonstrates how to write a keygen for that game. | The previous example demonstrates how to crack a game. This example goes one step further and demonstrates how to write a keygen for that game. | ||
As with the previous example, if you want the name of the game, please contact me privately -- if I know you, I'll let you know which game and where to find it. If I don't know you, I won't be able to tell you. I'm not sure what the legality of this is, but I don't want to piss anybody off | As with the previous example, if you want the name of the game, please contact me privately -- if I know you, I'll let you know which game and where to find it. If I don't know you, I won't be able to tell you. I'm not sure what the legality of this is, but I don't want to piss anybody off. | ||
== Unregistering the Game == | |||
To unregister the game, go into the "data" folder in the program's directory and delete the newest file. | |||
== The Next Step == | |||
Recall this code from the previous example: | |||
<pre> | |||
push ebp | |||
mov ebp, esp | |||
movsx eax, word_111111 | |||
push eax | |||
call sub_222222 | |||
pop ecx | |||
cmp word_333333, ax | |||
jnz short registerfail | |||
mov ds:IsRegistered, 1 ; <--------- You end up here | |||
jmp short endfunction | |||
registerfail: | |||
mov ds:IsRegistered, 0 | |||
endfunction: | |||
mov esp, ebp | |||
pop ebp | |||
retn | |||
</pre> | |||
We determined that "call sub_222222" likely converts the registration code to the key expected from the user. With this in mind, double-click on the function and have a look at the code. I'll post the exact code from the function here, and as usual I recommend you try and figure it out on your own. Can you write a keygen without peaking at my code? | |||
When looking over this, note that it's just a series of divisions and multiplications of the parameter. The divisions all use "edx", which means that they're modular divisions. Note that the multiplications use two parameters, which means that the result is stored in the first one, not in edx:eax (see the section on instructions if you don't remember this -- there's a good chance that you don't remember reading it because I just added it). | |||
Here's the code: | |||
<pre> | <pre> | ||
GenerateCode proc near | GenerateCode proc near | ||
arg_0= dword ptr 8 | arg_0= dword ptr 8 | ||
push ebx | push ebx | ||
mov edx, [esp+arg_0] ; edx gets the reg code | mov edx, [esp+arg_0] ; edx gets the reg code | ||
xor ebx, ebx | xor ebx, ebx | ||
mov ebx, edx | mov ebx, edx | ||
lea eax, [edx+7] | lea eax, [edx+7] | ||
imul ebx, eax | imul ebx, eax | ||
lea ebx, [ebx+33h] | lea ebx, [ebx+33h] | ||
mov ecx, 8085h | mov ecx, 8085h | ||
mov eax, ebx | mov eax, ebx | ||
cdq | cdq | ||
idiv ecx | idiv ecx | ||
mov ebx, edx | mov ebx, edx | ||
imul ebx, 4Fh | imul ebx, 4Fh | ||
mov ecx, 702Fh | mov ecx, 702Fh | ||
mov eax, ebx | mov eax, ebx | ||
cdq | cdq | ||
idiv ecx | idiv ecx | ||
mov ebx, edx | mov ebx, edx | ||
shl ebx, 5 | shl ebx, 5 | ||
lea eax, [edx+edx*2] | lea eax, [edx+edx*2] | ||
sub ebx, eax | sub ebx, eax | ||
mov ecx, 47A9h | mov ecx, 47A9h | ||
mov eax, ebx | mov eax, ebx | ||
cdq | cdq | ||
idiv ecx | idiv ecx | ||
mov ebx, edx | mov ebx, edx | ||
imul ebx, 2DBh | imul ebx, 2DBh | ||
mov ecx, 2710h | mov ecx, 2710h | ||
mov eax, ebx | mov eax, ebx | ||
cdq | cdq | ||
idiv ecx | idiv ecx | ||
mov ebx, edx | mov ebx, edx | ||
lea eax, [ebx+2710h] | lea eax, [ebx+2710h] | ||
pop ebx | pop ebx | ||
retn | retn | ||
GenerateCode endp | GenerateCode endp | ||
</pre> | </pre> | ||
== | == C Code == | ||
In previous examples, I documented every line. This code, however, is actually extremely simplistic, so I won't bother spending time going through every line. Instead, I'll go straight to C code: | |||
<pre> | |||
#include <stdio.h> | |||
int GenerateKey(int code) | |||
{ | |||
// push ebx | |||
// mov edx, [esp+arg_0] ; edx gets the reg code | |||
int edx = code; | |||
// xor ebx, ebx | |||
int ebx = 0; | |||
// mov ebx, edx | |||
ebx = edx; | |||
// lea eax, [edx+7] | |||
int eax = edx + 7; | |||
// imul ebx, eax | |||
ebx = ebx * eax; | |||
// lea ebx, [ebx+33h] | |||
ebx = ebx + 0x33; | |||
// mov ecx, 8085h | |||
int ecx = 0x8085; | |||
// mov eax, ebx | |||
eax = ebx; | |||
// cdq | |||
// idiv ecx | |||
edx = eax % ecx; | |||
// mov ebx, edx | |||
ebx = edx; | |||
// imul ebx, 4Fh | |||
ebx = ebx * 0x4f; | |||
// mov ecx, 702Fh | |||
ecx = 0x702f; | |||
// mov eax, ebx | |||
eax = ebx; | |||
// cdq | |||
// idiv ecx | |||
edx = eax % ecx; | |||
// mov ebx, edx | |||
ebx = edx; | |||
// shl ebx, 5 | |||
ebx = ebx << 5; | |||
// lea eax, [edx+edx*2] | |||
eax = edx + edx*2; | |||
// sub ebx, eax | |||
ebx = ebx - eax; | |||
// mov ecx, 47A9h | |||
ecx = 0x47a9; | |||
// mov eax, ebx | |||
eax = ebx; | |||
// cdq | |||
// idiv ecx | |||
edx = eax % ecx; | |||
// mov ebx, edx | |||
ebx = edx; | |||
// imul ebx, 2DBh | |||
ebx = ebx * 0x2db; | |||
// mov ecx, 2710h | |||
ecx = 0x2710; | |||
// mov eax, ebx | |||
eax = ebx; | |||
// cdq | |||
// idiv ecx | |||
edx = eax % ecx; | |||
// mov ebx, edx | |||
ebx = edx; | |||
// lea eax, [ebx+2710h] | |||
eax = ebx + 0x2710; | |||
// pop ebx | |||
// retn | |||
return eax; | |||
} | |||
= | int main(int argc, char *argv[]) | ||
{ | |||
int code; | |||
int key; | |||
printf("Please enter your code --> "); | |||
scanf("%d", &code); | |||
key = GenerateKey(code); | |||
printf("\nYour code: %d\n\n", key); | |||
} | |||
</pre> | |||
== Cleaned Up C Code == | == Cleaned Up C Code == | ||
<pre> | |||
int GenerateKey(int code) | |||
{ | |||
int edx = code; | |||
int ebx = 0; | |||
ebx = edx; | |||
int eax = edx + 7; | |||
ebx = ebx * eax; | |||
ebx = ebx + 0x33; | |||
int ecx = 0x8085; | |||
eax = ebx; | |||
edx = eax % ecx; | |||
ebx = edx; | |||
ebx = ebx * 0x4f; | |||
ecx = 0x702f; | |||
eax = ebx; | |||
edx = eax % ecx; | |||
ebx = edx; | |||
ebx = ebx << 5; | |||
eax = edx + edx*2; | |||
ebx = ebx - eax; | |||
ecx = 0x47a9; | |||
eax = ebx; | |||
edx = eax % ecx; | |||
ebx = edx; | |||
ebx = ebx * 0x2db; | |||
ecx = 0x2710; | |||
eax = ebx; | |||
edx = eax % ecx; | |||
ebx = edx; | |||
eax = ebx + 0x2710; | |||
return eax; | |||
} | |||
</pre> | |||
== Reduced C Code == | == Reduced C Code == | ||
Basically, to reduce this code, just go from top to bottom and combine the variables, which will easily go this far: | |||
<pre> | |||
int GenerateKey(int code) | |||
{ | |||
int edx = ((((code * (code + 7)) + 0x33) % 0x8085) * 0x4f) % 0x702f; | |||
int ebx = edx; | |||
int ecx, eax; | |||
ebx = ebx << 5; | |||
eax = edx + edx*2; | |||
ebx = ebx - eax; | |||
ecx = 0x47a9; | |||
eax = ebx; | |||
edx = eax % ecx; | |||
ebx = edx; | |||
ebx = ebx * 0x2db; | |||
ecx = 0x2710; | |||
eax = ebx; | |||
edx = eax % ecx; | |||
ebx = edx; | |||
eax = ebx + 0x2710; | |||
return eax; | |||
} | |||
</pre> | |||
== Finished Code == | == Finished Code == | ||
After reducing the code as far as possible, and using the "code" variable instead of registers, here is the final code: | |||
<pre> | |||
int GenerateKey(int code) | |||
{ | |||
code = ((((code * (code + 7)) + 0x33) % 0x8085) * 0x4f) % 0x702f; | |||
return (((((code << 5) - (code * 3)) % 0x47a9) * 0x2db) % 0x2710) + 0x2710; | |||
} | |||
</pre> | |||
I have verified that that code does indeed work. | |||
As I said before, this was for educational purposes only, if you actually want to play the game, please buy it! | |||
== Questions == | == Questions == | ||
Feel free to edit this section and post questions, I'll do my best to answer them. But you may need to contact me to let me know that a question exists. | Feel free to edit this section and post questions, I'll do my best to answer them. But you may need to contact me to let me know that a question exists. |
Latest revision as of 01:23, 21 December 2008
Assembly Language Tutorial | |
---|---|
Please choose a tutorial page:
|
The previous example demonstrates how to crack a game. This example goes one step further and demonstrates how to write a keygen for that game.
As with the previous example, if you want the name of the game, please contact me privately -- if I know you, I'll let you know which game and where to find it. If I don't know you, I won't be able to tell you. I'm not sure what the legality of this is, but I don't want to piss anybody off.
Unregistering the Game
To unregister the game, go into the "data" folder in the program's directory and delete the newest file.
The Next Step
Recall this code from the previous example:
push ebp mov ebp, esp movsx eax, word_111111 push eax call sub_222222 pop ecx cmp word_333333, ax jnz short registerfail mov ds:IsRegistered, 1 ; <--------- You end up here jmp short endfunction registerfail: mov ds:IsRegistered, 0 endfunction: mov esp, ebp pop ebp retn
We determined that "call sub_222222" likely converts the registration code to the key expected from the user. With this in mind, double-click on the function and have a look at the code. I'll post the exact code from the function here, and as usual I recommend you try and figure it out on your own. Can you write a keygen without peaking at my code?
When looking over this, note that it's just a series of divisions and multiplications of the parameter. The divisions all use "edx", which means that they're modular divisions. Note that the multiplications use two parameters, which means that the result is stored in the first one, not in edx:eax (see the section on instructions if you don't remember this -- there's a good chance that you don't remember reading it because I just added it).
Here's the code:
GenerateCode proc near arg_0= dword ptr 8 push ebx mov edx, [esp+arg_0] ; edx gets the reg code xor ebx, ebx mov ebx, edx lea eax, [edx+7] imul ebx, eax lea ebx, [ebx+33h] mov ecx, 8085h mov eax, ebx cdq idiv ecx mov ebx, edx imul ebx, 4Fh mov ecx, 702Fh mov eax, ebx cdq idiv ecx mov ebx, edx shl ebx, 5 lea eax, [edx+edx*2] sub ebx, eax mov ecx, 47A9h mov eax, ebx cdq idiv ecx mov ebx, edx imul ebx, 2DBh mov ecx, 2710h mov eax, ebx cdq idiv ecx mov ebx, edx lea eax, [ebx+2710h] pop ebx retn GenerateCode endp
C Code
In previous examples, I documented every line. This code, however, is actually extremely simplistic, so I won't bother spending time going through every line. Instead, I'll go straight to C code:
#include <stdio.h> int GenerateKey(int code) { // push ebx // mov edx, [esp+arg_0] ; edx gets the reg code int edx = code; // xor ebx, ebx int ebx = 0; // mov ebx, edx ebx = edx; // lea eax, [edx+7] int eax = edx + 7; // imul ebx, eax ebx = ebx * eax; // lea ebx, [ebx+33h] ebx = ebx + 0x33; // mov ecx, 8085h int ecx = 0x8085; // mov eax, ebx eax = ebx; // cdq // idiv ecx edx = eax % ecx; // mov ebx, edx ebx = edx; // imul ebx, 4Fh ebx = ebx * 0x4f; // mov ecx, 702Fh ecx = 0x702f; // mov eax, ebx eax = ebx; // cdq // idiv ecx edx = eax % ecx; // mov ebx, edx ebx = edx; // shl ebx, 5 ebx = ebx << 5; // lea eax, [edx+edx*2] eax = edx + edx*2; // sub ebx, eax ebx = ebx - eax; // mov ecx, 47A9h ecx = 0x47a9; // mov eax, ebx eax = ebx; // cdq // idiv ecx edx = eax % ecx; // mov ebx, edx ebx = edx; // imul ebx, 2DBh ebx = ebx * 0x2db; // mov ecx, 2710h ecx = 0x2710; // mov eax, ebx eax = ebx; // cdq // idiv ecx edx = eax % ecx; // mov ebx, edx ebx = edx; // lea eax, [ebx+2710h] eax = ebx + 0x2710; // pop ebx // retn return eax; } int main(int argc, char *argv[]) { int code; int key; printf("Please enter your code --> "); scanf("%d", &code); key = GenerateKey(code); printf("\nYour code: %d\n\n", key); }
Cleaned Up C Code
int GenerateKey(int code) { int edx = code; int ebx = 0; ebx = edx; int eax = edx + 7; ebx = ebx * eax; ebx = ebx + 0x33; int ecx = 0x8085; eax = ebx; edx = eax % ecx; ebx = edx; ebx = ebx * 0x4f; ecx = 0x702f; eax = ebx; edx = eax % ecx; ebx = edx; ebx = ebx << 5; eax = edx + edx*2; ebx = ebx - eax; ecx = 0x47a9; eax = ebx; edx = eax % ecx; ebx = edx; ebx = ebx * 0x2db; ecx = 0x2710; eax = ebx; edx = eax % ecx; ebx = edx; eax = ebx + 0x2710; return eax; }
Reduced C Code
Basically, to reduce this code, just go from top to bottom and combine the variables, which will easily go this far:
int GenerateKey(int code) { int edx = ((((code * (code + 7)) + 0x33) % 0x8085) * 0x4f) % 0x702f; int ebx = edx; int ecx, eax; ebx = ebx << 5; eax = edx + edx*2; ebx = ebx - eax; ecx = 0x47a9; eax = ebx; edx = eax % ecx; ebx = edx; ebx = ebx * 0x2db; ecx = 0x2710; eax = ebx; edx = eax % ecx; ebx = edx; eax = ebx + 0x2710; return eax; }
Finished Code
After reducing the code as far as possible, and using the "code" variable instead of registers, here is the final code:
int GenerateKey(int code) { code = ((((code * (code + 7)) + 0x33) % 0x8085) * 0x4f) % 0x702f; return (((((code << 5) - (code * 3)) % 0x47a9) * 0x2db) % 0x2710) + 0x2710; }
I have verified that that code does indeed work.
As I said before, this was for educational purposes only, if you actually want to play the game, please buy it!
Questions
Feel free to edit this section and post questions, I'll do my best to answer them. But you may need to contact me to let me know that a question exists.