
	..Kydodai Mahjongg 16.00..
------------------------------------------
"a total disassembling story" by Boba Fett ;)
---------------------------------------------

1. (Introduction)
2. (The target)
3. (Tools)
4. (Unpack this nasty one)
	4.1. (Dumping the import section)
	4.2. (Dumping the unpacked exe)
	4.3. (Rebuilding the new exe)
5. (Disassembling)
	5.1. (Removing the anti SI trick)
	5.2. (Finding the registration routine)
	5.3. (How to patch it)
	5.4. (How to make it work like a keygen)
6. (Writing a keygen)
	6.1. (Further analyse of the registration routine)
	6.2. (Writing the keygen in VB)
7. (Last words)
8. (Special thanks)



1. Introduction
---------------

Today, we are gonna do something special, and very educational, cuz were gonna do a total disassembling of the game Kyodai Mahjongg ver. 16.00.
We will at first unpack it sucessfully since its packed with AsPack (whatta joke) then when the rebuilded exe works like it should we will make a simple patch for it (and I know that this seems alittle weird since were gonna make a keygen later, but I thinking about those who just learned how to crack, thats YOU, newbies.
As I said im closing up by making 2 keygens, one using Kyodai Mahjongg and the second using VB. ;)
There is not special requirements for this tut cuz I will make it as understandable as possible. This tut includes the .aspack section and the correct .idata section.

2. The target
-------------

Targets name: Kyodai Mahjongg
Version: 16.00
URL: http://kyodai.com
Size: 4442 kb
Packer: AsPack
Anti SI tricks: MeltIce

3. Tools
--------

Soft Ice version 4.05
Hiew version 6.55
WDasm version 8.93
Procdump version 1.62
IceDump version 6.017
HexWorkShop version 2.01 (Old and trusty ;)
The URL for these tools can be found at 
URL: http://www.lockless.com
or
URL: http://www.crackstore.com
Remember that the version numbers of the tools are only optional so if you have a earlier version the above, ignore and proceed.

4. Unpack this nasty one
------------------------

4.1. Dumping the import section
-------------------------------

So its time to finally start the baby up. Before we start, make sure that you have all the tools above and have loaded IceDump, so it can be used.
The first thing needed when we are to unpack a exe is some info about the exe. Thats why we have ProcDump, so execute procdump and press the "PE Editor" button to the right and choose kyodai.exe
The things we need are the Size of image which in this case is 003D9000 and we need the Image Base which is 00400000 (most programs have this Image Base).
Next press the "Sections" key and here is the sections a exe is made of. Here you can often see which packer it been packed with. In our case it was AsPack but the section we want some info about is the .idata section. We need the VS (Virtual Size), the VO (Virtual Offset).
The VO has to be added the imagebase to show its right offset but Ill tell you more later on. Now we have what we need so close ProcDump and start the Symbol Loader and choose the kydodai.exe
Load it and SI should break and if you aint familiar with unpacking just follow my instructions below and you should do just fine ;)
Press F8 to get into the first call that see, then switch to F10 and keep pressing that til you reach address XXXX:007D62E5, here you will type "dd 725000" (remember what I said earlier: "The VO has to be added the imagebase to show its right offset" and now you might understand why (the VO was 00325000 and if we add the image base that was 00400000 it will equal 00725000). This is where the .idata section begins.
For now there is just alot of ???? (means that it aint unpacked yet) in the window but not for long. Trace to address XXXX:007D6248 and the next time you pass the call above this address you will see alot of numbers instead of ???? and the value in the upper right corner was for me 624C31A5 (it doesnt matter if you dont have the same as I did).
But this aint the idata we want (later you will notice why) so trace again til you reach XXXX:007D62C4, and now the values changed and if you take the upper right corners value again and add the image base value, youll get:
00325874+004000000= 00725874 and iff you type "d 00725874" you will see that its says kernel32.dll in the data window, this means that we have the correct idata section but again trace til you reach XXXX:007D62EB. Here you will dump this baby and to do that, type the following:
/dump start_address size_to_dump name_of_the_file
in our case that would be from address 725000 + 3000 (you might reqognize these values):
/dump 725000 3000 idata.bin

4.2. Dumping the unpacked exe
-----------------------------

Now you have the .idata section done so all there is left is to dump the whole exe but to do that we need the OEP (Original Entry Point, this is where the packer jumps after it has unpacked the exe) so again trace til you reach XXXX:7D6503.
If you take a look at the line above you will see this:
Push 004E6BE4
And you guessed right, its our OEP, so write it down and press F10 one more time. This time you should be in the kyodai.code section (you should stand on a push ebp) and now its completely unpacked so type:
/dump 400000 3D9000 unpack.exe
to dump the exe.
Done! Press F5 to let it run.

4.3 Rebuilding the new exe
--------------------------

So now you have the exe and the idata section unpacked and all thats is left to merge them together and the PE header etc
So open up the unpacked exe and the idata section with HexWorkShop. With the exe window focused do a search for kernel32.dll and you will break at several place but the one you should choose is on offset 325870 (or actually at 325874 and that offset is a value that you seen before in this tut =)
And if you remember that you should also remember that the .idata section started at the offset 325000 so trace a bit up. From the offset 325000, hold down the shift button and trace down 3000 bytes. You can see how many bytes you have selected at the bottom of the program. When you have marked the 3000 bytes, press Ctrl-X to cut it out. The shift to the idata.bin file and mark the whole file, from top to end, and its selected value should also be 3000 bytes. Press Ctrl-C to copy the selection and shift again to the unpacked exe and here you will press Ctrl-V to paste your selection. When that is done save the file as a new one and then leave HexWorkShop.
Now fire up ProcDump and press the "PE Editor" button but this time choose the exe you created in HexWorkShop. 

Take a look in the "Entry Point" box, the value there is the address to the unpacker routin (as we dont need no more) so we need to replace it with a value and that value is the OEP as you wrote down from .aspack routine, but there is one thing to do with that value before you continue. The OEP was 004E6BE4 but to correct address is: OEP-Image Base ==> the correct value is: 004E6BE4-00400000 = 000E6BE4
So enter 000E6BE4 in the Entry Point box and then press the "Sections" button.
Since you dumped the exe from the start (4000000) you will have to change the VA (Virtual Size), the VO (Virtual Offset), the RS (Raw Size) and the RO (Raw Offset).
The VS should be equal to RS (VS=RS) and the VO should be equal to RO (VO=RO)
So right click one section at the time and click "Edit section" 
and while youre changing the offsets and the sizes, do also change the "Charateristics" to the value E0000020 (this is for all the sections). When you are done there is only of thing left to do and perhaps a very important thing, and that is to update the values for the Import Table. The Import Table is found of you click "Ok" in the "Sections" and press the "Directory" button. The RVA value for the Import Table should equal the VO and the Size should equal the VS. These were the values that you entered in the "Sections". So type them in and press "Ok" one last time then exit ProcDump.
You have now the complete unpacked exe in front of you but if you run it wont start.
One thing that wasnt removed was the MeltIce protection (MeltIce is used to find out if SI is loaded or not and it uses CreateFileA to find it out).
The kyodai2d.exe is packed in the same way as kyodai.exe so as training you could try to unpack that one to.

5. Disassembling
----------------

5.1. Removing the anti SI trick
-------------------------------

Disassemble the exe (this could take a while) and when its done open up the "Imports" and press kernel32.CreateFileA seven times and you should land at address :0048F60E

:0048F604 68000000C0              push C0000000

* Possible StringData Ref from Code Obj ->"\\.\SICE" ; The check
                                  |
:0048F609 6824F64800              push 0048F624

* Reference To: kernel32.CreateFileA, Ord:0000h
                                  |
:0048F60E E80172F7FF              Call 00406814 ; You will land here
:0048F613 83F8FF                  cmp eax, FFFFFFFF ; Was SI loaded?
:0048F616 7408                    je 0048F620 ; Jump if it wasnt
:0048F618 50                      push eax

As you can see that simple patch a adress :0048F616 would solve this problem.
Open up Hiew and choose a copy of the disassembled file and press "Enter" twice to enter decode mode and then press F5 and type in the offset for this address (it can be found in the bottom of WDasm and in this case its 8F616
Instead of letting it jump when it doesnt find that SI is loaded it should alwys jump so press F3 and write EB 08 (makes the jump whether SI was loaded or not)
Thats the first check, no press the kernel32.CreateFileA one more time and you will land at address :0048F64A, and the procedure is the same as said above.
Now is the SI check removed and the exe should run like its supposed to.

--Remark--
Instead of rewrite the code, you could load the exe in like HexWorkShop or Hiew and do a search for \NTICE or \SICE and just rename it to something else like:
\AAICE or whatever and it will work to
--End Remark--

5.2. Finding the registration routine
-------------------------------------

Its time! Time to make this baby run like a regged version WITHOUT the correct serial
Open up the String Data Section and look for the string that appears when you enter a bogus serial. I found it at address :004B0B83 and if I look a bit up I found another string saying: "Thanks again! Youre now registered."
So I guess we are at the right place ;)

5.3. How to patch it
--------------------

Above the "correct serial" string there is a jump that also leads to the "bad serial" string. So appearently we found the jump that makes us a registered user. So that jump should be changed from 74 26 to 90 90 (90 means nop, which in its turn stands for "No Operation" in Hiew.
Now go into the call at address :004B0B51 and it will look like this:

* Referenced by a CALL at Addresses:
|:004B0B51   , :004C1417   , :004C565A   , :004C645C   , :004C64B2   
|:004C6860   , :004C6DF1   , :004C8AD6   , :004CC4A0   , :004DF806   
|
:004B2410 55                      push ebp
:004B2411 8BEC                    mov ebp, esp
:004B2413 B90E000000              mov ecx, 0000000E

To make it as easy as possible I choosed to take the long way to register it but there are other ways, I know, but its harder for newbies to understand. So we came from address 
:004B0B51 and its this call that decideds if we are registered or not, so press shift and F12 together and type in the next address, like :004C1417 and press enter.
Some lines below the current address there is another jump thas has to be edited. The jump looks like this:
:004C141E 0F85A9020000            jne 004C16CD
But we want the code to always jump so load up Hiew and enter the offset and press F3 but this time press "Enter" once and a new window will appear. So manually do this:
instead of jne type jmp and then press enter once, then "Esc", and finally 90. One byte will not be included to this snippet so just nop it away..the jump should look like this when youre done:
:004C141E E9AA020000            jmp 004C16CD
:004C1423 90			nop
Hope you understood that..
Now do the same with the following calls and remember this:
the first time you nop because it was JZ jump
the seconde time you made it jmp cuz it was JNZ jump
Do you see the pattern? Whenever its JZ jmp below the call, nop it and when its a JNZ jmp below, make a jump.
(This is ONLY for this program that this works, other programs could have the reversed order, so if it was a JZ jump it had to be a jmp and so on).
"How do make a jnz to jmp of the opcode is like 7507?"
Change it from 7507 to EB07 (this is for every case)
When this is done, launch the exe and......
SUCESS!!
but wait whatta fuck??
The "Unregistered version - Please register!!!" string is still there with the title bar..
Well back to WDasm and the String Data References.
Found it? Its at address :004B2A72 and there is two conditional jumps to this address but the one we have to change is the last one so go to address :004B24A7 and enter Hiew
Nop this jmp away and youre have now cracked it sucessfully..
Congrats mate..

5.4. How to make it work like a keygen
--------------------------------------

This is really a great trick Ive learned myself as I want you also to learn. It simple to learn and very very useful if you cant understand the routine very well.
The idea is this, that instead of showing me the "wrong serial" string it will show me the serial (the correct) it compared with my fake one. Are you with me?
So we need the SI for this, and a good breakpoint (bpx)
Why not use the address that we had for the jmp to either god_serial or bad_serial?
Of course we will use that one  ;)
If you didnt remember its :004B0B58
So launch your "uncracked" version of kyodai and go to the registration box.
Enter your info, but before pressing "Ok", enter SI and set a bpx at Hmemcpy (bpx Hmemcpy).
Press "Ok" then F5 once, type "bc *" to clear all the bpxs now keep tracing til youll get into the kyodai code. When youve done that set a new bpx at 4B0B58 (bpx 4B0B58)
Now press F5 again to let it run, and when SI breaks again, check all the registers for anything similar a serial. Finding it? I hope not ;) cuz the call at address :004B0B51 clears the correct_serial from the memory so what we need is to set a new bpx at that address, so..
bc *
bpx 4B0B51
Try to register again and when you break again check every register again, but this time you should enter call since you know that its in this call the correct_serial is generated and also erased from the memory before leaving it. Keep tracing til you get to address :004B24A2
Below you can find a JNZ jump, so check all the register and this time you will find something cool in EAX, its your correct serial but that aint what we want, we wanted a keygen so if you set a bpx at address :004B24A2 (bpx 4B24A2) then press F12 to leave this call and you will land at address :004B0B56. Keep tracing to line :004B0B3. If you type "d 004B0C20" you will see the error msg. So think now..we now that somtime during the serial check EAX contains your correct_serial and later EDX will loaded with the "Wrong serial" string, so why not load EDX with EAX BEFORE Eax gets erased?? Sounds got to me =)
You remember our jmp at address 4B24A5?? Well anyway, thats jump could instead jump directly to address :004B0B80, then we will change the code at address :004B0B88 so that Edx gets loaded with Eax instead of 004B0C20. That should work, so lets try it. One more comment is the call at address :004B24A2 and that is that you will have to nop that call away since its in there it compares your fake code with the correct one and the clears the correct one from the memory! 
Before we open up Hiew we need the offest that the new jump is jumping to; the address is :004B0B80 and the offset is B0B80 so open Hiew and goto the jump at address 4B24A5 that were gonna edit. Press F3 and change the Jnz to Jmp and the 004B2A72 to 4B0b80 and after the editing the call and the jump it should look like this:
:004B24A2 90		nop
:004B24A3 90		nop
:004B24A4 90		nop
:004B24A5 90		nop
:004B24A6 90		nop
:004B24A7 E9D4E6FFFF	jmp 004B0B80
:004B24A8 90		nop
--Remark--
you dont enter 4B0B80 in Hiew, you just enter the offset, cuz the image base is added after you pressed Enter, so I would be have wanted to jump to address :004B24AD you would have typed this in Hiew
jmp B24AD
So after you pressed "Ok" it would look like this
jmp 4B24AD
--End remark--
Now to address :004B0B83, offset B0B83. Press F3, Enter, and type exaclty as mentioned below:
mov edx,eax
Press Enter once then
90 (nop three times)
F9 
Done! After this it should look like this:
:004B0B83 8BD0		mov edx, eax
:004B0B85 90		nop
:004B0B86 90		nop
:004B0B87 90		nop
Now try to run it and enter a random user name, and the serial that pops up is the correct serial for that username!
Good work, you just made a AutoKeyGenerator (AKG) ;)

6. Writing a keygen
-------------------

Its time to do it the really "right" way and thats to write a keygen but to do that we need to study the key_generatin routine one more time.
This is nothing for newbies, but for those who wants to learn anyway, go ahead, but this chapter will not be too "newbie written".

6.1. Further analyse of the registration routine
------------------------------------------------

As I wrote earlier about patching the JNZ at :004B24A2 to a JMP and that was cuz the correct serial had at that time been already generated and above the call at address :004B2494 it hasnt been generated so the registration routine starts at :004AF338
This is a snippet from WDasm of the reg routine

:004AF338 55                      push ebp		; Not important
:004AF339 8BEC                    mov ebp, esp		; Not important
:004AF33B 83C4F4                  add esp, FFFFFFF4	; Not important
:004AF33E 53                      push ebx		; Not important
:004AF33F 56                      push esi		; User Name
:004AF340 57                      push edi		; Not important
:004AF341 33DB                    xor ebx, ebx		; Ebx=0
:004AF343 895DF4                  mov dword ptr [ebp-0C], ebx	; Not important
:004AF346 8BF9                    mov edi, ecx			; Edi= Ecx
:004AF348 8955F8                  mov dword ptr [ebp-08], edx	; User Name is put in memory location Ebp-8
:004AF34B 8945FC                  mov dword ptr [ebp-04], eax	; Not important
:004AF34E 8B45F8                  mov eax, dword ptr [ebp-08]	; Eax=User Name
:004AF351 E8524FF5FF              call 004042A8			; Not important
:004AF356 33C0                    xor eax, eax			; Eax= 0
:004AF358 55                      push ebp			; Not important
:004AF359 6815F44A00              push 004AF415			; Not important
:004AF35E 64FF30                  push dword ptr fs:[eax]	; Not important
:004AF361 648920                  mov dword ptr fs:[eax], esp	; Not important
:004AF364 8B45F8                  mov eax, dword ptr [ebp-08]	; Eax= User Name
:004AF367 E8884DF5FF              call 004040F4			; Not important
:004AF36C 8B55F8                  mov edx, dword ptr [ebp-08]	; Edx= User Name
:004AF36F 0FB64402FF              movzx eax, byte ptr [edx+eax-01]	; Eax= Edx+Eax-1 (Eax=Lenght of User Name!)
:004AF374 8B55F8                  mov edx, dword ptr [ebp-08]		; Edx = User Name
:004AF377 0FB612                  movzx edx, byte ptr [edx]		; Edx= first letter in User Name
:004AF37A 03C2                    add eax, edx				; Eax= Eax+Edx
:004AF37C B90A000000              mov ecx, 0000000A		; Ecx= 0000000A
:004AF381 33D2                    xor edx, edx			; Edx= 0
:004AF383 F7F1                    div ecx			; Eax=Eax/Ecx (Eax contains the integer and Edx contains the rest, if Eax= ==> Eax= 1 and Edx = 0, if Eax = B ==> Eax = 1 and Edx= 1
:004AF385 83C230                  add edx, 00000030		; Edx= Edx+30 (Edx is the first number if the Ok_Serial
:004AF388 8BC7                    mov eax, edi			; Not important
:004AF38A E88D4CF5FF              call 0040401C			; Not important
:004AF38F 8B45F8                  mov eax, dword ptr [ebp-08]	; Eax = User Name
:004AF392 E85D4DF5FF              call 004040F4			; Not important
:004AF397 8BF0                    mov esi, eax			; Esi= Eax
:004AF399 83EE02                  sub esi, 00000002		; Esi= Esi-2
:004AF39C 7C3A                    jl 004AF3D8			; Jump if lower
:004AF39E 46                      inc esi			; Esi= Esi+1
:004AF39F BB02000000              mov ebx, 00000002		; Ebx= 00000002

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004AF3D6(C)
|
:004AF3A4 8B45F8                  mov eax, dword ptr [ebp-08]	; Eax= User Name
:004AF3A7 0FB64418FE              movzx eax, byte ptr [eax+ebx-02]	; Eax= n:th letter in User Name, where n is a integer
:004AF3AC 8B55F8                  mov edx, dword ptr [ebp-08]		; Edx= User Name
:004AF3AF 0FB6541AFF              movzx edx, byte ptr [edx+ebx-01]	; Edx= n:th letter in User Name, where n is a integer
:004AF3B4 03C2                    add eax, edx			; Eax= Eax+Edx
:004AF3B6 B90A000000              mov ecx, 0000000A		; Ecx= 0000000A
:004AF3BB 33D2                    xor edx, edx			; Edx= 0
:004AF3BD F7F1                    div ecx			; Eax=Eax/Ecx (Eax contains the integer and Edx contains the rest, if Eax= ==> Eax= 1 and Edx = 0, if Eax = B ==> Eax = 1 and Edx= 1
:004AF3BF 83C230                  add edx, 00000030		; Edx= Edx+30
:004AF3C2 8D45F4                  lea eax, dword ptr [ebp-0C]	; Not important
:004AF3C5 E8524CF5FF              call 0040401C			; Not important
:004AF3CA 8B55F4                  mov edx, dword ptr [ebp-0C]	; Not important
:004AF3CD 8BC7                    mov eax, edi			; Eax= Edi
:004AF3CF E8284DF5FF              call 004040FC			; Not important
:004AF3D4 43                      inc ebx			; Ebx = Ebx+1 (n=n+1)
:004AF3D5 4E                      dec esi			; Esi= Esi-1
:004AF3D6 75CC                    jne 004AF3A4			; Was Esi = 0? Then were done

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004AF39C(C)
|
:004AF3D8 8B45F8                  mov eax, dword ptr [ebp-08]	; Eax= User Name
:004AF3DB E8144DF5FF              call 004040F4			; Not important
:004AF3E0 83F808                  cmp eax, 00000008		; Wasnt User Name lenght less or equal 8 chars?
:004AF3E3 7D15                    jge 004AF3FA			; Jump if true
:004AF3E5 8BCF                    mov ecx, edi			; The rest in not important
:004AF3E7 8B45FC                  mov eax, dword ptr [ebp-04]
:004AF3EA 8B809C040000            mov eax, dword ptr [eax+0000049C]

* Possible StringData Ref from Code Obj ->"UNREGISTERED"
                                  |
:004AF3F0 BA2CF44A00              mov edx, 004AF42C
:004AF3F5 E85E02FBFF              call 0045F658

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004AF3E3(C)
|
:004AF3FA 33C0                    xor eax, eax
:004AF3FC 5A                      pop edx
:004AF3FD 59                      pop ecx
:004AF3FE 59                      pop ecx
:004AF3FF 648910                  mov dword ptr fs:[eax], edx

* Possible StringData Ref from Code Obj ->"_^["
                                  |
:004AF402 681CF44A00              push 004AF41C

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004AF41A(U)
|
:004AF407 8D45F4                  lea eax, dword ptr [ebp-0C]
:004AF40A BA02000000              mov edx, 00000002
:004AF40F E8844AF5FF              call 00403E98
:004AF414 C3                      ret			; Done!

Before we continue I can mention that the calls aint important for us and I didnt mention some code snippets but those doesnt either effect the keygenning.

6.3. Writing the keygen in VB
-----------------------------

So with the info from the chapter 6.2. its now possible to write a keygen in VB and for this time im just gonna show you the  source code from my keygen and if youre using my source in your keygen, please give me a thanks or something in return otherwise consider yourself a loser, a fucking lamer!!
Source code snippet:



















